138fd1498Szrj /* Convert RTL to assembler code and output it, for GNU compiler.
238fd1498Szrj Copyright (C) 1987-2018 Free Software Foundation, Inc.
338fd1498Szrj
438fd1498Szrj This file is part of GCC.
538fd1498Szrj
638fd1498Szrj GCC is free software; you can redistribute it and/or modify it under
738fd1498Szrj the terms of the GNU General Public License as published by the Free
838fd1498Szrj Software Foundation; either version 3, or (at your option) any later
938fd1498Szrj version.
1038fd1498Szrj
1138fd1498Szrj GCC is distributed in the hope that it will be useful, but WITHOUT ANY
1238fd1498Szrj WARRANTY; without even the implied warranty of MERCHANTABILITY or
1338fd1498Szrj FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1438fd1498Szrj for more details.
1538fd1498Szrj
1638fd1498Szrj You should have received a copy of the GNU General Public License
1738fd1498Szrj along with GCC; see the file COPYING3. If not see
1838fd1498Szrj <http://www.gnu.org/licenses/>. */
1938fd1498Szrj
2038fd1498Szrj /* This is the final pass of the compiler.
2138fd1498Szrj It looks at the rtl code for a function and outputs assembler code.
2238fd1498Szrj
2338fd1498Szrj Call `final_start_function' to output the assembler code for function entry,
2438fd1498Szrj `final' to output assembler code for some RTL code,
2538fd1498Szrj `final_end_function' to output assembler code for function exit.
2638fd1498Szrj If a function is compiled in several pieces, each piece is
2738fd1498Szrj output separately with `final'.
2838fd1498Szrj
2938fd1498Szrj Some optimizations are also done at this level.
3038fd1498Szrj Move instructions that were made unnecessary by good register allocation
3138fd1498Szrj are detected and omitted from the output. (Though most of these
3238fd1498Szrj are removed by the last jump pass.)
3338fd1498Szrj
3438fd1498Szrj Instructions to set the condition codes are omitted when it can be
3538fd1498Szrj seen that the condition codes already had the desired values.
3638fd1498Szrj
3738fd1498Szrj In some cases it is sufficient if the inherited condition codes
3838fd1498Szrj have related values, but this may require the following insn
3938fd1498Szrj (the one that tests the condition codes) to be modified.
4038fd1498Szrj
4138fd1498Szrj The code for the function prologue and epilogue are generated
4238fd1498Szrj directly in assembler by the target functions function_prologue and
4338fd1498Szrj function_epilogue. Those instructions never exist as rtl. */
4438fd1498Szrj
4538fd1498Szrj #include "config.h"
4638fd1498Szrj #define INCLUDE_ALGORITHM /* reverse */
4738fd1498Szrj #include "system.h"
4838fd1498Szrj #include "coretypes.h"
4938fd1498Szrj #include "backend.h"
5038fd1498Szrj #include "target.h"
5138fd1498Szrj #include "rtl.h"
5238fd1498Szrj #include "tree.h"
5338fd1498Szrj #include "cfghooks.h"
5438fd1498Szrj #include "df.h"
5538fd1498Szrj #include "memmodel.h"
5638fd1498Szrj #include "tm_p.h"
5738fd1498Szrj #include "insn-config.h"
5838fd1498Szrj #include "regs.h"
5938fd1498Szrj #include "emit-rtl.h"
6038fd1498Szrj #include "recog.h"
6138fd1498Szrj #include "cgraph.h"
6238fd1498Szrj #include "tree-pretty-print.h" /* for dump_function_header */
6338fd1498Szrj #include "varasm.h"
6438fd1498Szrj #include "insn-attr.h"
6538fd1498Szrj #include "conditions.h"
6638fd1498Szrj #include "flags.h"
6738fd1498Szrj #include "output.h"
6838fd1498Szrj #include "except.h"
6938fd1498Szrj #include "rtl-error.h"
7038fd1498Szrj #include "toplev.h" /* exact_log2, floor_log2 */
7138fd1498Szrj #include "reload.h"
7238fd1498Szrj #include "intl.h"
7338fd1498Szrj #include "cfgrtl.h"
7438fd1498Szrj #include "debug.h"
7538fd1498Szrj #include "tree-pass.h"
7638fd1498Szrj #include "tree-ssa.h"
7738fd1498Szrj #include "cfgloop.h"
7838fd1498Szrj #include "params.h"
7938fd1498Szrj #include "stringpool.h"
8038fd1498Szrj #include "attribs.h"
8138fd1498Szrj #include "asan.h"
8238fd1498Szrj #include "rtl-iter.h"
8338fd1498Szrj #include "print-rtl.h"
8438fd1498Szrj
8538fd1498Szrj #ifdef XCOFF_DEBUGGING_INFO
8638fd1498Szrj #include "xcoffout.h" /* Needed for external data declarations. */
8738fd1498Szrj #endif
8838fd1498Szrj
8938fd1498Szrj #include "dwarf2out.h"
9038fd1498Szrj
9138fd1498Szrj #ifdef DBX_DEBUGGING_INFO
9238fd1498Szrj #include "dbxout.h"
9338fd1498Szrj #endif
9438fd1498Szrj
9538fd1498Szrj /* Most ports that aren't using cc0 don't need to define CC_STATUS_INIT.
9638fd1498Szrj So define a null default for it to save conditionalization later. */
9738fd1498Szrj #ifndef CC_STATUS_INIT
9838fd1498Szrj #define CC_STATUS_INIT
9938fd1498Szrj #endif
10038fd1498Szrj
10138fd1498Szrj /* Is the given character a logical line separator for the assembler? */
10238fd1498Szrj #ifndef IS_ASM_LOGICAL_LINE_SEPARATOR
10338fd1498Szrj #define IS_ASM_LOGICAL_LINE_SEPARATOR(C, STR) ((C) == ';')
10438fd1498Szrj #endif
10538fd1498Szrj
10638fd1498Szrj #ifndef JUMP_TABLES_IN_TEXT_SECTION
10738fd1498Szrj #define JUMP_TABLES_IN_TEXT_SECTION 0
10838fd1498Szrj #endif
10938fd1498Szrj
11038fd1498Szrj /* Bitflags used by final_scan_insn. */
11138fd1498Szrj #define SEEN_NOTE 1
11238fd1498Szrj #define SEEN_EMITTED 2
11338fd1498Szrj #define SEEN_NEXT_VIEW 4
11438fd1498Szrj
11538fd1498Szrj /* Last insn processed by final_scan_insn. */
11638fd1498Szrj static rtx_insn *debug_insn;
11738fd1498Szrj rtx_insn *current_output_insn;
11838fd1498Szrj
11938fd1498Szrj /* Line number of last NOTE. */
12038fd1498Szrj static int last_linenum;
12138fd1498Szrj
12238fd1498Szrj /* Column number of last NOTE. */
12338fd1498Szrj static int last_columnnum;
12438fd1498Szrj
12538fd1498Szrj /* Last discriminator written to assembly. */
12638fd1498Szrj static int last_discriminator;
12738fd1498Szrj
12838fd1498Szrj /* Discriminator of current block. */
12938fd1498Szrj static int discriminator;
13038fd1498Szrj
13138fd1498Szrj /* Highest line number in current block. */
13238fd1498Szrj static int high_block_linenum;
13338fd1498Szrj
13438fd1498Szrj /* Likewise for function. */
13538fd1498Szrj static int high_function_linenum;
13638fd1498Szrj
13738fd1498Szrj /* Filename of last NOTE. */
13838fd1498Szrj static const char *last_filename;
13938fd1498Szrj
14038fd1498Szrj /* Override filename, line and column number. */
14138fd1498Szrj static const char *override_filename;
14238fd1498Szrj static int override_linenum;
14338fd1498Szrj static int override_columnnum;
14438fd1498Szrj
14538fd1498Szrj /* Whether to force emission of a line note before the next insn. */
14638fd1498Szrj static bool force_source_line = false;
14738fd1498Szrj
14838fd1498Szrj extern const int length_unit_log; /* This is defined in insn-attrtab.c. */
14938fd1498Szrj
15038fd1498Szrj /* Nonzero while outputting an `asm' with operands.
15138fd1498Szrj This means that inconsistencies are the user's fault, so don't die.
15238fd1498Szrj The precise value is the insn being output, to pass to error_for_asm. */
15338fd1498Szrj const rtx_insn *this_is_asm_operands;
15438fd1498Szrj
15538fd1498Szrj /* Number of operands of this insn, for an `asm' with operands. */
15638fd1498Szrj static unsigned int insn_noperands;
15738fd1498Szrj
15838fd1498Szrj /* Compare optimization flag. */
15938fd1498Szrj
16038fd1498Szrj static rtx last_ignored_compare = 0;
16138fd1498Szrj
16238fd1498Szrj /* Assign a unique number to each insn that is output.
16338fd1498Szrj This can be used to generate unique local labels. */
16438fd1498Szrj
16538fd1498Szrj static int insn_counter = 0;
16638fd1498Szrj
16738fd1498Szrj /* This variable contains machine-dependent flags (defined in tm.h)
16838fd1498Szrj set and examined by output routines
16938fd1498Szrj that describe how to interpret the condition codes properly. */
17038fd1498Szrj
17138fd1498Szrj CC_STATUS cc_status;
17238fd1498Szrj
17338fd1498Szrj /* During output of an insn, this contains a copy of cc_status
17438fd1498Szrj from before the insn. */
17538fd1498Szrj
17638fd1498Szrj CC_STATUS cc_prev_status;
17738fd1498Szrj
17838fd1498Szrj /* Number of unmatched NOTE_INSN_BLOCK_BEG notes we have seen. */
17938fd1498Szrj
18038fd1498Szrj static int block_depth;
18138fd1498Szrj
18238fd1498Szrj /* Nonzero if have enabled APP processing of our assembler output. */
18338fd1498Szrj
18438fd1498Szrj static int app_on;
18538fd1498Szrj
18638fd1498Szrj /* If we are outputting an insn sequence, this contains the sequence rtx.
18738fd1498Szrj Zero otherwise. */
18838fd1498Szrj
18938fd1498Szrj rtx_sequence *final_sequence;
19038fd1498Szrj
19138fd1498Szrj #ifdef ASSEMBLER_DIALECT
19238fd1498Szrj
19338fd1498Szrj /* Number of the assembler dialect to use, starting at 0. */
19438fd1498Szrj static int dialect_number;
19538fd1498Szrj #endif
19638fd1498Szrj
19738fd1498Szrj /* Nonnull if the insn currently being emitted was a COND_EXEC pattern. */
19838fd1498Szrj rtx current_insn_predicate;
19938fd1498Szrj
20038fd1498Szrj /* True if printing into -fdump-final-insns= dump. */
20138fd1498Szrj bool final_insns_dump_p;
20238fd1498Szrj
20338fd1498Szrj /* True if profile_function should be called, but hasn't been called yet. */
20438fd1498Szrj static bool need_profile_function;
20538fd1498Szrj
20638fd1498Szrj static int asm_insn_count (rtx);
20738fd1498Szrj static void profile_function (FILE *);
20838fd1498Szrj static void profile_after_prologue (FILE *);
20938fd1498Szrj static bool notice_source_line (rtx_insn *, bool *);
21038fd1498Szrj static rtx walk_alter_subreg (rtx *, bool *);
21138fd1498Szrj static void output_asm_name (void);
21238fd1498Szrj static void output_alternate_entry_point (FILE *, rtx_insn *);
21338fd1498Szrj static tree get_mem_expr_from_op (rtx, int *);
21438fd1498Szrj static void output_asm_operand_names (rtx *, int *, int);
21538fd1498Szrj #ifdef LEAF_REGISTERS
21638fd1498Szrj static void leaf_renumber_regs (rtx_insn *);
21738fd1498Szrj #endif
21838fd1498Szrj #if HAVE_cc0
21938fd1498Szrj static int alter_cond (rtx);
22038fd1498Szrj #endif
22138fd1498Szrj static int align_fuzz (rtx, rtx, int, unsigned);
22238fd1498Szrj static void collect_fn_hard_reg_usage (void);
22338fd1498Szrj static tree get_call_fndecl (rtx_insn *);
22438fd1498Szrj
22538fd1498Szrj /* Initialize data in final at the beginning of a compilation. */
22638fd1498Szrj
22738fd1498Szrj void
init_final(const char * filename ATTRIBUTE_UNUSED)22838fd1498Szrj init_final (const char *filename ATTRIBUTE_UNUSED)
22938fd1498Szrj {
23038fd1498Szrj app_on = 0;
23138fd1498Szrj final_sequence = 0;
23238fd1498Szrj
23338fd1498Szrj #ifdef ASSEMBLER_DIALECT
23438fd1498Szrj dialect_number = ASSEMBLER_DIALECT;
23538fd1498Szrj #endif
23638fd1498Szrj }
23738fd1498Szrj
23838fd1498Szrj /* Default target function prologue and epilogue assembler output.
23938fd1498Szrj
24038fd1498Szrj If not overridden for epilogue code, then the function body itself
24138fd1498Szrj contains return instructions wherever needed. */
24238fd1498Szrj void
default_function_pro_epilogue(FILE *)24338fd1498Szrj default_function_pro_epilogue (FILE *)
24438fd1498Szrj {
24538fd1498Szrj }
24638fd1498Szrj
24738fd1498Szrj void
default_function_switched_text_sections(FILE * file ATTRIBUTE_UNUSED,tree decl ATTRIBUTE_UNUSED,bool new_is_cold ATTRIBUTE_UNUSED)24838fd1498Szrj default_function_switched_text_sections (FILE *file ATTRIBUTE_UNUSED,
24938fd1498Szrj tree decl ATTRIBUTE_UNUSED,
25038fd1498Szrj bool new_is_cold ATTRIBUTE_UNUSED)
25138fd1498Szrj {
25238fd1498Szrj }
25338fd1498Szrj
25438fd1498Szrj /* Default target hook that outputs nothing to a stream. */
25538fd1498Szrj void
no_asm_to_stream(FILE * file ATTRIBUTE_UNUSED)25638fd1498Szrj no_asm_to_stream (FILE *file ATTRIBUTE_UNUSED)
25738fd1498Szrj {
25838fd1498Szrj }
25938fd1498Szrj
26038fd1498Szrj /* Enable APP processing of subsequent output.
26138fd1498Szrj Used before the output from an `asm' statement. */
26238fd1498Szrj
26338fd1498Szrj void
app_enable(void)26438fd1498Szrj app_enable (void)
26538fd1498Szrj {
26638fd1498Szrj if (! app_on)
26738fd1498Szrj {
26838fd1498Szrj fputs (ASM_APP_ON, asm_out_file);
26938fd1498Szrj app_on = 1;
27038fd1498Szrj }
27138fd1498Szrj }
27238fd1498Szrj
27338fd1498Szrj /* Disable APP processing of subsequent output.
27438fd1498Szrj Called from varasm.c before most kinds of output. */
27538fd1498Szrj
27638fd1498Szrj void
app_disable(void)27738fd1498Szrj app_disable (void)
27838fd1498Szrj {
27938fd1498Szrj if (app_on)
28038fd1498Szrj {
28138fd1498Szrj fputs (ASM_APP_OFF, asm_out_file);
28238fd1498Szrj app_on = 0;
28338fd1498Szrj }
28438fd1498Szrj }
28538fd1498Szrj
28638fd1498Szrj /* Return the number of slots filled in the current
28738fd1498Szrj delayed branch sequence (we don't count the insn needing the
28838fd1498Szrj delay slot). Zero if not in a delayed branch sequence. */
28938fd1498Szrj
29038fd1498Szrj int
dbr_sequence_length(void)29138fd1498Szrj dbr_sequence_length (void)
29238fd1498Szrj {
29338fd1498Szrj if (final_sequence != 0)
29438fd1498Szrj return XVECLEN (final_sequence, 0) - 1;
29538fd1498Szrj else
29638fd1498Szrj return 0;
29738fd1498Szrj }
29838fd1498Szrj
29938fd1498Szrj /* The next two pages contain routines used to compute the length of an insn
30038fd1498Szrj and to shorten branches. */
30138fd1498Szrj
30238fd1498Szrj /* Arrays for insn lengths, and addresses. The latter is referenced by
30338fd1498Szrj `insn_current_length'. */
30438fd1498Szrj
30538fd1498Szrj static int *insn_lengths;
30638fd1498Szrj
30738fd1498Szrj vec<int> insn_addresses_;
30838fd1498Szrj
30938fd1498Szrj /* Max uid for which the above arrays are valid. */
31038fd1498Szrj static int insn_lengths_max_uid;
31138fd1498Szrj
31238fd1498Szrj /* Address of insn being processed. Used by `insn_current_length'. */
31338fd1498Szrj int insn_current_address;
31438fd1498Szrj
31538fd1498Szrj /* Address of insn being processed in previous iteration. */
31638fd1498Szrj int insn_last_address;
31738fd1498Szrj
31838fd1498Szrj /* known invariant alignment of insn being processed. */
31938fd1498Szrj int insn_current_align;
32038fd1498Szrj
32138fd1498Szrj /* After shorten_branches, for any insn, uid_align[INSN_UID (insn)]
32238fd1498Szrj gives the next following alignment insn that increases the known
32338fd1498Szrj alignment, or NULL_RTX if there is no such insn.
32438fd1498Szrj For any alignment obtained this way, we can again index uid_align with
32538fd1498Szrj its uid to obtain the next following align that in turn increases the
32638fd1498Szrj alignment, till we reach NULL_RTX; the sequence obtained this way
32738fd1498Szrj for each insn we'll call the alignment chain of this insn in the following
32838fd1498Szrj comments. */
32938fd1498Szrj
33038fd1498Szrj struct label_alignment
33138fd1498Szrj {
33238fd1498Szrj short alignment;
33338fd1498Szrj short max_skip;
33438fd1498Szrj };
33538fd1498Szrj
33638fd1498Szrj static rtx *uid_align;
33738fd1498Szrj static int *uid_shuid;
33838fd1498Szrj static struct label_alignment *label_align;
33938fd1498Szrj
34038fd1498Szrj /* Indicate that branch shortening hasn't yet been done. */
34138fd1498Szrj
34238fd1498Szrj void
init_insn_lengths(void)34338fd1498Szrj init_insn_lengths (void)
34438fd1498Szrj {
34538fd1498Szrj if (uid_shuid)
34638fd1498Szrj {
34738fd1498Szrj free (uid_shuid);
34838fd1498Szrj uid_shuid = 0;
34938fd1498Szrj }
35038fd1498Szrj if (insn_lengths)
35138fd1498Szrj {
35238fd1498Szrj free (insn_lengths);
35338fd1498Szrj insn_lengths = 0;
35438fd1498Szrj insn_lengths_max_uid = 0;
35538fd1498Szrj }
35638fd1498Szrj if (HAVE_ATTR_length)
35738fd1498Szrj INSN_ADDRESSES_FREE ();
35838fd1498Szrj if (uid_align)
35938fd1498Szrj {
36038fd1498Szrj free (uid_align);
36138fd1498Szrj uid_align = 0;
36238fd1498Szrj }
36338fd1498Szrj }
36438fd1498Szrj
36538fd1498Szrj /* Obtain the current length of an insn. If branch shortening has been done,
36638fd1498Szrj get its actual length. Otherwise, use FALLBACK_FN to calculate the
36738fd1498Szrj length. */
36838fd1498Szrj static int
get_attr_length_1(rtx_insn * insn,int (* fallback_fn)(rtx_insn *))36938fd1498Szrj get_attr_length_1 (rtx_insn *insn, int (*fallback_fn) (rtx_insn *))
37038fd1498Szrj {
37138fd1498Szrj rtx body;
37238fd1498Szrj int i;
37338fd1498Szrj int length = 0;
37438fd1498Szrj
37538fd1498Szrj if (!HAVE_ATTR_length)
37638fd1498Szrj return 0;
37738fd1498Szrj
37838fd1498Szrj if (insn_lengths_max_uid > INSN_UID (insn))
37938fd1498Szrj return insn_lengths[INSN_UID (insn)];
38038fd1498Szrj else
38138fd1498Szrj switch (GET_CODE (insn))
38238fd1498Szrj {
38338fd1498Szrj case NOTE:
38438fd1498Szrj case BARRIER:
38538fd1498Szrj case CODE_LABEL:
38638fd1498Szrj case DEBUG_INSN:
38738fd1498Szrj return 0;
38838fd1498Szrj
38938fd1498Szrj case CALL_INSN:
39038fd1498Szrj case JUMP_INSN:
39138fd1498Szrj length = fallback_fn (insn);
39238fd1498Szrj break;
39338fd1498Szrj
39438fd1498Szrj case INSN:
39538fd1498Szrj body = PATTERN (insn);
39638fd1498Szrj if (GET_CODE (body) == USE || GET_CODE (body) == CLOBBER)
39738fd1498Szrj return 0;
39838fd1498Szrj
39938fd1498Szrj else if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0)
40038fd1498Szrj length = asm_insn_count (body) * fallback_fn (insn);
40138fd1498Szrj else if (rtx_sequence *seq = dyn_cast <rtx_sequence *> (body))
40238fd1498Szrj for (i = 0; i < seq->len (); i++)
40338fd1498Szrj length += get_attr_length_1 (seq->insn (i), fallback_fn);
40438fd1498Szrj else
40538fd1498Szrj length = fallback_fn (insn);
40638fd1498Szrj break;
40738fd1498Szrj
40838fd1498Szrj default:
40938fd1498Szrj break;
41038fd1498Szrj }
41138fd1498Szrj
41238fd1498Szrj #ifdef ADJUST_INSN_LENGTH
41338fd1498Szrj ADJUST_INSN_LENGTH (insn, length);
41438fd1498Szrj #endif
41538fd1498Szrj return length;
41638fd1498Szrj }
41738fd1498Szrj
41838fd1498Szrj /* Obtain the current length of an insn. If branch shortening has been done,
41938fd1498Szrj get its actual length. Otherwise, get its maximum length. */
42038fd1498Szrj int
get_attr_length(rtx_insn * insn)42138fd1498Szrj get_attr_length (rtx_insn *insn)
42238fd1498Szrj {
42338fd1498Szrj return get_attr_length_1 (insn, insn_default_length);
42438fd1498Szrj }
42538fd1498Szrj
42638fd1498Szrj /* Obtain the current length of an insn. If branch shortening has been done,
42738fd1498Szrj get its actual length. Otherwise, get its minimum length. */
42838fd1498Szrj int
get_attr_min_length(rtx_insn * insn)42938fd1498Szrj get_attr_min_length (rtx_insn *insn)
43038fd1498Szrj {
43138fd1498Szrj return get_attr_length_1 (insn, insn_min_length);
43238fd1498Szrj }
43338fd1498Szrj
43438fd1498Szrj /* Code to handle alignment inside shorten_branches. */
43538fd1498Szrj
43638fd1498Szrj /* Here is an explanation how the algorithm in align_fuzz can give
43738fd1498Szrj proper results:
43838fd1498Szrj
43938fd1498Szrj Call a sequence of instructions beginning with alignment point X
44038fd1498Szrj and continuing until the next alignment point `block X'. When `X'
44138fd1498Szrj is used in an expression, it means the alignment value of the
44238fd1498Szrj alignment point.
44338fd1498Szrj
44438fd1498Szrj Call the distance between the start of the first insn of block X, and
44538fd1498Szrj the end of the last insn of block X `IX', for the `inner size of X'.
44638fd1498Szrj This is clearly the sum of the instruction lengths.
44738fd1498Szrj
44838fd1498Szrj Likewise with the next alignment-delimited block following X, which we
44938fd1498Szrj shall call block Y.
45038fd1498Szrj
45138fd1498Szrj Call the distance between the start of the first insn of block X, and
45238fd1498Szrj the start of the first insn of block Y `OX', for the `outer size of X'.
45338fd1498Szrj
45438fd1498Szrj The estimated padding is then OX - IX.
45538fd1498Szrj
45638fd1498Szrj OX can be safely estimated as
45738fd1498Szrj
45838fd1498Szrj if (X >= Y)
45938fd1498Szrj OX = round_up(IX, Y)
46038fd1498Szrj else
46138fd1498Szrj OX = round_up(IX, X) + Y - X
46238fd1498Szrj
46338fd1498Szrj Clearly est(IX) >= real(IX), because that only depends on the
46438fd1498Szrj instruction lengths, and those being overestimated is a given.
46538fd1498Szrj
46638fd1498Szrj Clearly round_up(foo, Z) >= round_up(bar, Z) if foo >= bar, so
46738fd1498Szrj we needn't worry about that when thinking about OX.
46838fd1498Szrj
46938fd1498Szrj When X >= Y, the alignment provided by Y adds no uncertainty factor
47038fd1498Szrj for branch ranges starting before X, so we can just round what we have.
47138fd1498Szrj But when X < Y, we don't know anything about the, so to speak,
47238fd1498Szrj `middle bits', so we have to assume the worst when aligning up from an
47338fd1498Szrj address mod X to one mod Y, which is Y - X. */
47438fd1498Szrj
47538fd1498Szrj #ifndef LABEL_ALIGN
47638fd1498Szrj #define LABEL_ALIGN(LABEL) align_labels_log
47738fd1498Szrj #endif
47838fd1498Szrj
47938fd1498Szrj #ifndef LOOP_ALIGN
48038fd1498Szrj #define LOOP_ALIGN(LABEL) align_loops_log
48138fd1498Szrj #endif
48238fd1498Szrj
48338fd1498Szrj #ifndef LABEL_ALIGN_AFTER_BARRIER
48438fd1498Szrj #define LABEL_ALIGN_AFTER_BARRIER(LABEL) 0
48538fd1498Szrj #endif
48638fd1498Szrj
48738fd1498Szrj #ifndef JUMP_ALIGN
48838fd1498Szrj #define JUMP_ALIGN(LABEL) align_jumps_log
48938fd1498Szrj #endif
49038fd1498Szrj
49138fd1498Szrj int
default_label_align_after_barrier_max_skip(rtx_insn * insn ATTRIBUTE_UNUSED)49238fd1498Szrj default_label_align_after_barrier_max_skip (rtx_insn *insn ATTRIBUTE_UNUSED)
49338fd1498Szrj {
49438fd1498Szrj return 0;
49538fd1498Szrj }
49638fd1498Szrj
49738fd1498Szrj int
default_loop_align_max_skip(rtx_insn * insn ATTRIBUTE_UNUSED)49838fd1498Szrj default_loop_align_max_skip (rtx_insn *insn ATTRIBUTE_UNUSED)
49938fd1498Szrj {
50038fd1498Szrj return align_loops_max_skip;
50138fd1498Szrj }
50238fd1498Szrj
50338fd1498Szrj int
default_label_align_max_skip(rtx_insn * insn ATTRIBUTE_UNUSED)50438fd1498Szrj default_label_align_max_skip (rtx_insn *insn ATTRIBUTE_UNUSED)
50538fd1498Szrj {
50638fd1498Szrj return align_labels_max_skip;
50738fd1498Szrj }
50838fd1498Szrj
50938fd1498Szrj int
default_jump_align_max_skip(rtx_insn * insn ATTRIBUTE_UNUSED)51038fd1498Szrj default_jump_align_max_skip (rtx_insn *insn ATTRIBUTE_UNUSED)
51138fd1498Szrj {
51238fd1498Szrj return align_jumps_max_skip;
51338fd1498Szrj }
51438fd1498Szrj
51538fd1498Szrj #ifndef ADDR_VEC_ALIGN
51638fd1498Szrj static int
final_addr_vec_align(rtx_jump_table_data * addr_vec)51738fd1498Szrj final_addr_vec_align (rtx_jump_table_data *addr_vec)
51838fd1498Szrj {
51938fd1498Szrj int align = GET_MODE_SIZE (addr_vec->get_data_mode ());
52038fd1498Szrj
52138fd1498Szrj if (align > BIGGEST_ALIGNMENT / BITS_PER_UNIT)
52238fd1498Szrj align = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
52338fd1498Szrj return exact_log2 (align);
52438fd1498Szrj
52538fd1498Szrj }
52638fd1498Szrj
52738fd1498Szrj #define ADDR_VEC_ALIGN(ADDR_VEC) final_addr_vec_align (ADDR_VEC)
52838fd1498Szrj #endif
52938fd1498Szrj
53038fd1498Szrj #ifndef INSN_LENGTH_ALIGNMENT
53138fd1498Szrj #define INSN_LENGTH_ALIGNMENT(INSN) length_unit_log
53238fd1498Szrj #endif
53338fd1498Szrj
53438fd1498Szrj #define INSN_SHUID(INSN) (uid_shuid[INSN_UID (INSN)])
53538fd1498Szrj
53638fd1498Szrj static int min_labelno, max_labelno;
53738fd1498Szrj
53838fd1498Szrj #define LABEL_TO_ALIGNMENT(LABEL) \
53938fd1498Szrj (label_align[CODE_LABEL_NUMBER (LABEL) - min_labelno].alignment)
54038fd1498Szrj
54138fd1498Szrj #define LABEL_TO_MAX_SKIP(LABEL) \
54238fd1498Szrj (label_align[CODE_LABEL_NUMBER (LABEL) - min_labelno].max_skip)
54338fd1498Szrj
54438fd1498Szrj /* For the benefit of port specific code do this also as a function. */
54538fd1498Szrj
54638fd1498Szrj int
label_to_alignment(rtx label)54738fd1498Szrj label_to_alignment (rtx label)
54838fd1498Szrj {
54938fd1498Szrj if (CODE_LABEL_NUMBER (label) <= max_labelno)
55038fd1498Szrj return LABEL_TO_ALIGNMENT (label);
55138fd1498Szrj return 0;
55238fd1498Szrj }
55338fd1498Szrj
55438fd1498Szrj int
label_to_max_skip(rtx label)55538fd1498Szrj label_to_max_skip (rtx label)
55638fd1498Szrj {
55738fd1498Szrj if (CODE_LABEL_NUMBER (label) <= max_labelno)
55838fd1498Szrj return LABEL_TO_MAX_SKIP (label);
55938fd1498Szrj return 0;
56038fd1498Szrj }
56138fd1498Szrj
56238fd1498Szrj /* The differences in addresses
56338fd1498Szrj between a branch and its target might grow or shrink depending on
56438fd1498Szrj the alignment the start insn of the range (the branch for a forward
56538fd1498Szrj branch or the label for a backward branch) starts out on; if these
56638fd1498Szrj differences are used naively, they can even oscillate infinitely.
56738fd1498Szrj We therefore want to compute a 'worst case' address difference that
56838fd1498Szrj is independent of the alignment the start insn of the range end
56938fd1498Szrj up on, and that is at least as large as the actual difference.
57038fd1498Szrj The function align_fuzz calculates the amount we have to add to the
57138fd1498Szrj naively computed difference, by traversing the part of the alignment
57238fd1498Szrj chain of the start insn of the range that is in front of the end insn
57338fd1498Szrj of the range, and considering for each alignment the maximum amount
57438fd1498Szrj that it might contribute to a size increase.
57538fd1498Szrj
57638fd1498Szrj For casesi tables, we also want to know worst case minimum amounts of
57738fd1498Szrj address difference, in case a machine description wants to introduce
57838fd1498Szrj some common offset that is added to all offsets in a table.
57938fd1498Szrj For this purpose, align_fuzz with a growth argument of 0 computes the
58038fd1498Szrj appropriate adjustment. */
58138fd1498Szrj
58238fd1498Szrj /* Compute the maximum delta by which the difference of the addresses of
58338fd1498Szrj START and END might grow / shrink due to a different address for start
58438fd1498Szrj which changes the size of alignment insns between START and END.
58538fd1498Szrj KNOWN_ALIGN_LOG is the alignment known for START.
58638fd1498Szrj GROWTH should be ~0 if the objective is to compute potential code size
58738fd1498Szrj increase, and 0 if the objective is to compute potential shrink.
58838fd1498Szrj The return value is undefined for any other value of GROWTH. */
58938fd1498Szrj
59038fd1498Szrj static int
align_fuzz(rtx start,rtx end,int known_align_log,unsigned int growth)59138fd1498Szrj align_fuzz (rtx start, rtx end, int known_align_log, unsigned int growth)
59238fd1498Szrj {
59338fd1498Szrj int uid = INSN_UID (start);
59438fd1498Szrj rtx align_label;
59538fd1498Szrj int known_align = 1 << known_align_log;
59638fd1498Szrj int end_shuid = INSN_SHUID (end);
59738fd1498Szrj int fuzz = 0;
59838fd1498Szrj
59938fd1498Szrj for (align_label = uid_align[uid]; align_label; align_label = uid_align[uid])
60038fd1498Szrj {
60138fd1498Szrj int align_addr, new_align;
60238fd1498Szrj
60338fd1498Szrj uid = INSN_UID (align_label);
60438fd1498Szrj align_addr = INSN_ADDRESSES (uid) - insn_lengths[uid];
60538fd1498Szrj if (uid_shuid[uid] > end_shuid)
60638fd1498Szrj break;
60738fd1498Szrj known_align_log = LABEL_TO_ALIGNMENT (align_label);
60838fd1498Szrj new_align = 1 << known_align_log;
60938fd1498Szrj if (new_align < known_align)
61038fd1498Szrj continue;
61138fd1498Szrj fuzz += (-align_addr ^ growth) & (new_align - known_align);
61238fd1498Szrj known_align = new_align;
61338fd1498Szrj }
61438fd1498Szrj return fuzz;
61538fd1498Szrj }
61638fd1498Szrj
61738fd1498Szrj /* Compute a worst-case reference address of a branch so that it
61838fd1498Szrj can be safely used in the presence of aligned labels. Since the
61938fd1498Szrj size of the branch itself is unknown, the size of the branch is
62038fd1498Szrj not included in the range. I.e. for a forward branch, the reference
62138fd1498Szrj address is the end address of the branch as known from the previous
62238fd1498Szrj branch shortening pass, minus a value to account for possible size
62338fd1498Szrj increase due to alignment. For a backward branch, it is the start
62438fd1498Szrj address of the branch as known from the current pass, plus a value
62538fd1498Szrj to account for possible size increase due to alignment.
62638fd1498Szrj NB.: Therefore, the maximum offset allowed for backward branches needs
62738fd1498Szrj to exclude the branch size. */
62838fd1498Szrj
62938fd1498Szrj int
insn_current_reference_address(rtx_insn * branch)63038fd1498Szrj insn_current_reference_address (rtx_insn *branch)
63138fd1498Szrj {
63238fd1498Szrj rtx dest;
63338fd1498Szrj int seq_uid;
63438fd1498Szrj
63538fd1498Szrj if (! INSN_ADDRESSES_SET_P ())
63638fd1498Szrj return 0;
63738fd1498Szrj
63838fd1498Szrj rtx_insn *seq = NEXT_INSN (PREV_INSN (branch));
63938fd1498Szrj seq_uid = INSN_UID (seq);
64038fd1498Szrj if (!JUMP_P (branch))
64138fd1498Szrj /* This can happen for example on the PA; the objective is to know the
64238fd1498Szrj offset to address something in front of the start of the function.
64338fd1498Szrj Thus, we can treat it like a backward branch.
64438fd1498Szrj We assume here that FUNCTION_BOUNDARY / BITS_PER_UNIT is larger than
64538fd1498Szrj any alignment we'd encounter, so we skip the call to align_fuzz. */
64638fd1498Szrj return insn_current_address;
64738fd1498Szrj dest = JUMP_LABEL (branch);
64838fd1498Szrj
64938fd1498Szrj /* BRANCH has no proper alignment chain set, so use SEQ.
65038fd1498Szrj BRANCH also has no INSN_SHUID. */
65138fd1498Szrj if (INSN_SHUID (seq) < INSN_SHUID (dest))
65238fd1498Szrj {
65338fd1498Szrj /* Forward branch. */
65438fd1498Szrj return (insn_last_address + insn_lengths[seq_uid]
65538fd1498Szrj - align_fuzz (seq, dest, length_unit_log, ~0));
65638fd1498Szrj }
65738fd1498Szrj else
65838fd1498Szrj {
65938fd1498Szrj /* Backward branch. */
66038fd1498Szrj return (insn_current_address
66138fd1498Szrj + align_fuzz (dest, seq, length_unit_log, ~0));
66238fd1498Szrj }
66338fd1498Szrj }
66438fd1498Szrj
66538fd1498Szrj /* Compute branch alignments based on CFG profile. */
66638fd1498Szrj
66738fd1498Szrj unsigned int
compute_alignments(void)66838fd1498Szrj compute_alignments (void)
66938fd1498Szrj {
67038fd1498Szrj int log, max_skip, max_log;
67138fd1498Szrj basic_block bb;
67238fd1498Szrj
67338fd1498Szrj if (label_align)
67438fd1498Szrj {
67538fd1498Szrj free (label_align);
67638fd1498Szrj label_align = 0;
67738fd1498Szrj }
67838fd1498Szrj
67938fd1498Szrj max_labelno = max_label_num ();
68038fd1498Szrj min_labelno = get_first_label_num ();
68138fd1498Szrj label_align = XCNEWVEC (struct label_alignment, max_labelno - min_labelno + 1);
68238fd1498Szrj
68338fd1498Szrj /* If not optimizing or optimizing for size, don't assign any alignments. */
68438fd1498Szrj if (! optimize || optimize_function_for_size_p (cfun))
68538fd1498Szrj return 0;
68638fd1498Szrj
68738fd1498Szrj if (dump_file)
68838fd1498Szrj {
68938fd1498Szrj dump_reg_info (dump_file);
69038fd1498Szrj dump_flow_info (dump_file, TDF_DETAILS);
69138fd1498Szrj flow_loops_dump (dump_file, NULL, 1);
69238fd1498Szrj }
69338fd1498Szrj loop_optimizer_init (AVOID_CFG_MODIFICATIONS);
69438fd1498Szrj profile_count count_threshold = cfun->cfg->count_max.apply_scale
69538fd1498Szrj (1, PARAM_VALUE (PARAM_ALIGN_THRESHOLD));
69638fd1498Szrj
69738fd1498Szrj if (dump_file)
69838fd1498Szrj {
69938fd1498Szrj fprintf (dump_file, "count_max: ");
70038fd1498Szrj cfun->cfg->count_max.dump (dump_file);
70138fd1498Szrj fprintf (dump_file, "\n");
70238fd1498Szrj }
70338fd1498Szrj FOR_EACH_BB_FN (bb, cfun)
70438fd1498Szrj {
70538fd1498Szrj rtx_insn *label = BB_HEAD (bb);
70638fd1498Szrj bool has_fallthru = 0;
70738fd1498Szrj edge e;
70838fd1498Szrj edge_iterator ei;
70938fd1498Szrj
71038fd1498Szrj if (!LABEL_P (label)
71138fd1498Szrj || optimize_bb_for_size_p (bb))
71238fd1498Szrj {
71338fd1498Szrj if (dump_file)
71438fd1498Szrj fprintf (dump_file,
71538fd1498Szrj "BB %4i loop %2i loop_depth %2i skipped.\n",
71638fd1498Szrj bb->index,
71738fd1498Szrj bb->loop_father->num,
71838fd1498Szrj bb_loop_depth (bb));
71938fd1498Szrj continue;
72038fd1498Szrj }
72138fd1498Szrj max_log = LABEL_ALIGN (label);
72238fd1498Szrj max_skip = targetm.asm_out.label_align_max_skip (label);
72338fd1498Szrj profile_count fallthru_count = profile_count::zero ();
72438fd1498Szrj profile_count branch_count = profile_count::zero ();
72538fd1498Szrj
72638fd1498Szrj FOR_EACH_EDGE (e, ei, bb->preds)
72738fd1498Szrj {
72838fd1498Szrj if (e->flags & EDGE_FALLTHRU)
72938fd1498Szrj has_fallthru = 1, fallthru_count += e->count ();
73038fd1498Szrj else
73138fd1498Szrj branch_count += e->count ();
73238fd1498Szrj }
73338fd1498Szrj if (dump_file)
73438fd1498Szrj {
73538fd1498Szrj fprintf (dump_file, "BB %4i loop %2i loop_depth"
73638fd1498Szrj " %2i fall ",
73738fd1498Szrj bb->index, bb->loop_father->num,
73838fd1498Szrj bb_loop_depth (bb));
73938fd1498Szrj fallthru_count.dump (dump_file);
74038fd1498Szrj fprintf (dump_file, " branch ");
74138fd1498Szrj branch_count.dump (dump_file);
74238fd1498Szrj if (!bb->loop_father->inner && bb->loop_father->num)
74338fd1498Szrj fprintf (dump_file, " inner_loop");
74438fd1498Szrj if (bb->loop_father->header == bb)
74538fd1498Szrj fprintf (dump_file, " loop_header");
74638fd1498Szrj fprintf (dump_file, "\n");
74738fd1498Szrj }
74838fd1498Szrj if (!fallthru_count.initialized_p () || !branch_count.initialized_p ())
74938fd1498Szrj continue;
75038fd1498Szrj
75138fd1498Szrj /* There are two purposes to align block with no fallthru incoming edge:
75238fd1498Szrj 1) to avoid fetch stalls when branch destination is near cache boundary
75338fd1498Szrj 2) to improve cache efficiency in case the previous block is not executed
75438fd1498Szrj (so it does not need to be in the cache).
75538fd1498Szrj
75638fd1498Szrj We to catch first case, we align frequently executed blocks.
75738fd1498Szrj To catch the second, we align blocks that are executed more frequently
75838fd1498Szrj than the predecessor and the predecessor is likely to not be executed
75938fd1498Szrj when function is called. */
76038fd1498Szrj
76138fd1498Szrj if (!has_fallthru
76238fd1498Szrj && (branch_count > count_threshold
76338fd1498Szrj || (bb->count > bb->prev_bb->count.apply_scale (10, 1)
76438fd1498Szrj && (bb->prev_bb->count
76538fd1498Szrj <= ENTRY_BLOCK_PTR_FOR_FN (cfun)
76638fd1498Szrj ->count.apply_scale (1, 2)))))
76738fd1498Szrj {
76838fd1498Szrj log = JUMP_ALIGN (label);
76938fd1498Szrj if (dump_file)
77038fd1498Szrj fprintf (dump_file, " jump alignment added.\n");
77138fd1498Szrj if (max_log < log)
77238fd1498Szrj {
77338fd1498Szrj max_log = log;
77438fd1498Szrj max_skip = targetm.asm_out.jump_align_max_skip (label);
77538fd1498Szrj }
77638fd1498Szrj }
77738fd1498Szrj /* In case block is frequent and reached mostly by non-fallthru edge,
77838fd1498Szrj align it. It is most likely a first block of loop. */
77938fd1498Szrj if (has_fallthru
78038fd1498Szrj && !(single_succ_p (bb)
78138fd1498Szrj && single_succ (bb) == EXIT_BLOCK_PTR_FOR_FN (cfun))
78238fd1498Szrj && optimize_bb_for_speed_p (bb)
78338fd1498Szrj && branch_count + fallthru_count > count_threshold
78438fd1498Szrj && (branch_count
78538fd1498Szrj > fallthru_count.apply_scale
78638fd1498Szrj (PARAM_VALUE (PARAM_ALIGN_LOOP_ITERATIONS), 1)))
78738fd1498Szrj {
78838fd1498Szrj log = LOOP_ALIGN (label);
78938fd1498Szrj if (dump_file)
79038fd1498Szrj fprintf (dump_file, " internal loop alignment added.\n");
79138fd1498Szrj if (max_log < log)
79238fd1498Szrj {
79338fd1498Szrj max_log = log;
79438fd1498Szrj max_skip = targetm.asm_out.loop_align_max_skip (label);
79538fd1498Szrj }
79638fd1498Szrj }
79738fd1498Szrj LABEL_TO_ALIGNMENT (label) = max_log;
79838fd1498Szrj LABEL_TO_MAX_SKIP (label) = max_skip;
79938fd1498Szrj }
80038fd1498Szrj
80138fd1498Szrj loop_optimizer_finalize ();
80238fd1498Szrj free_dominance_info (CDI_DOMINATORS);
80338fd1498Szrj return 0;
80438fd1498Szrj }
80538fd1498Szrj
80638fd1498Szrj /* Grow the LABEL_ALIGN array after new labels are created. */
80738fd1498Szrj
80838fd1498Szrj static void
grow_label_align(void)80938fd1498Szrj grow_label_align (void)
81038fd1498Szrj {
81138fd1498Szrj int old = max_labelno;
81238fd1498Szrj int n_labels;
81338fd1498Szrj int n_old_labels;
81438fd1498Szrj
81538fd1498Szrj max_labelno = max_label_num ();
81638fd1498Szrj
81738fd1498Szrj n_labels = max_labelno - min_labelno + 1;
81838fd1498Szrj n_old_labels = old - min_labelno + 1;
81938fd1498Szrj
82038fd1498Szrj label_align = XRESIZEVEC (struct label_alignment, label_align, n_labels);
82138fd1498Szrj
82238fd1498Szrj /* Range of labels grows monotonically in the function. Failing here
82338fd1498Szrj means that the initialization of array got lost. */
82438fd1498Szrj gcc_assert (n_old_labels <= n_labels);
82538fd1498Szrj
82638fd1498Szrj memset (label_align + n_old_labels, 0,
82738fd1498Szrj (n_labels - n_old_labels) * sizeof (struct label_alignment));
82838fd1498Szrj }
82938fd1498Szrj
83038fd1498Szrj /* Update the already computed alignment information. LABEL_PAIRS is a vector
83138fd1498Szrj made up of pairs of labels for which the alignment information of the first
83238fd1498Szrj element will be copied from that of the second element. */
83338fd1498Szrj
83438fd1498Szrj void
update_alignments(vec<rtx> & label_pairs)83538fd1498Szrj update_alignments (vec<rtx> &label_pairs)
83638fd1498Szrj {
83738fd1498Szrj unsigned int i = 0;
83838fd1498Szrj rtx iter, label = NULL_RTX;
83938fd1498Szrj
84038fd1498Szrj if (max_labelno != max_label_num ())
84138fd1498Szrj grow_label_align ();
84238fd1498Szrj
84338fd1498Szrj FOR_EACH_VEC_ELT (label_pairs, i, iter)
84438fd1498Szrj if (i & 1)
84538fd1498Szrj {
84638fd1498Szrj LABEL_TO_ALIGNMENT (label) = LABEL_TO_ALIGNMENT (iter);
84738fd1498Szrj LABEL_TO_MAX_SKIP (label) = LABEL_TO_MAX_SKIP (iter);
84838fd1498Szrj }
84938fd1498Szrj else
85038fd1498Szrj label = iter;
85138fd1498Szrj }
85238fd1498Szrj
85338fd1498Szrj namespace {
85438fd1498Szrj
85538fd1498Szrj const pass_data pass_data_compute_alignments =
85638fd1498Szrj {
85738fd1498Szrj RTL_PASS, /* type */
85838fd1498Szrj "alignments", /* name */
85938fd1498Szrj OPTGROUP_NONE, /* optinfo_flags */
86038fd1498Szrj TV_NONE, /* tv_id */
86138fd1498Szrj 0, /* properties_required */
86238fd1498Szrj 0, /* properties_provided */
86338fd1498Szrj 0, /* properties_destroyed */
86438fd1498Szrj 0, /* todo_flags_start */
86538fd1498Szrj 0, /* todo_flags_finish */
86638fd1498Szrj };
86738fd1498Szrj
86838fd1498Szrj class pass_compute_alignments : public rtl_opt_pass
86938fd1498Szrj {
87038fd1498Szrj public:
pass_compute_alignments(gcc::context * ctxt)87138fd1498Szrj pass_compute_alignments (gcc::context *ctxt)
87238fd1498Szrj : rtl_opt_pass (pass_data_compute_alignments, ctxt)
87338fd1498Szrj {}
87438fd1498Szrj
87538fd1498Szrj /* opt_pass methods: */
execute(function *)87638fd1498Szrj virtual unsigned int execute (function *) { return compute_alignments (); }
87738fd1498Szrj
87838fd1498Szrj }; // class pass_compute_alignments
87938fd1498Szrj
88038fd1498Szrj } // anon namespace
88138fd1498Szrj
88238fd1498Szrj rtl_opt_pass *
make_pass_compute_alignments(gcc::context * ctxt)88338fd1498Szrj make_pass_compute_alignments (gcc::context *ctxt)
88438fd1498Szrj {
88538fd1498Szrj return new pass_compute_alignments (ctxt);
88638fd1498Szrj }
88738fd1498Szrj
88838fd1498Szrj
88938fd1498Szrj /* Make a pass over all insns and compute their actual lengths by shortening
89038fd1498Szrj any branches of variable length if possible. */
89138fd1498Szrj
89238fd1498Szrj /* shorten_branches might be called multiple times: for example, the SH
89338fd1498Szrj port splits out-of-range conditional branches in MACHINE_DEPENDENT_REORG.
89438fd1498Szrj In order to do this, it needs proper length information, which it obtains
89538fd1498Szrj by calling shorten_branches. This cannot be collapsed with
89638fd1498Szrj shorten_branches itself into a single pass unless we also want to integrate
89738fd1498Szrj reorg.c, since the branch splitting exposes new instructions with delay
89838fd1498Szrj slots. */
89938fd1498Szrj
90038fd1498Szrj void
shorten_branches(rtx_insn * first)90138fd1498Szrj shorten_branches (rtx_insn *first)
90238fd1498Szrj {
90338fd1498Szrj rtx_insn *insn;
90438fd1498Szrj int max_uid;
90538fd1498Szrj int i;
90638fd1498Szrj int max_log;
90738fd1498Szrj int max_skip;
90838fd1498Szrj #define MAX_CODE_ALIGN 16
90938fd1498Szrj rtx_insn *seq;
91038fd1498Szrj int something_changed = 1;
91138fd1498Szrj char *varying_length;
91238fd1498Szrj rtx body;
91338fd1498Szrj int uid;
91438fd1498Szrj rtx align_tab[MAX_CODE_ALIGN + 1];
91538fd1498Szrj
91638fd1498Szrj /* Compute maximum UID and allocate label_align / uid_shuid. */
91738fd1498Szrj max_uid = get_max_uid ();
91838fd1498Szrj
91938fd1498Szrj /* Free uid_shuid before reallocating it. */
92038fd1498Szrj free (uid_shuid);
92138fd1498Szrj
92238fd1498Szrj uid_shuid = XNEWVEC (int, max_uid);
92338fd1498Szrj
92438fd1498Szrj if (max_labelno != max_label_num ())
92538fd1498Szrj grow_label_align ();
92638fd1498Szrj
92738fd1498Szrj /* Initialize label_align and set up uid_shuid to be strictly
92838fd1498Szrj monotonically rising with insn order. */
92938fd1498Szrj /* We use max_log here to keep track of the maximum alignment we want to
93038fd1498Szrj impose on the next CODE_LABEL (or the current one if we are processing
93138fd1498Szrj the CODE_LABEL itself). */
93238fd1498Szrj
93338fd1498Szrj max_log = 0;
93438fd1498Szrj max_skip = 0;
93538fd1498Szrj
93638fd1498Szrj for (insn = get_insns (), i = 1; insn; insn = NEXT_INSN (insn))
93738fd1498Szrj {
93838fd1498Szrj int log;
93938fd1498Szrj
94038fd1498Szrj INSN_SHUID (insn) = i++;
94138fd1498Szrj if (INSN_P (insn))
94238fd1498Szrj continue;
94338fd1498Szrj
94438fd1498Szrj if (rtx_code_label *label = dyn_cast <rtx_code_label *> (insn))
94538fd1498Szrj {
94638fd1498Szrj /* Merge in alignments computed by compute_alignments. */
94738fd1498Szrj log = LABEL_TO_ALIGNMENT (label);
94838fd1498Szrj if (max_log < log)
94938fd1498Szrj {
95038fd1498Szrj max_log = log;
95138fd1498Szrj max_skip = LABEL_TO_MAX_SKIP (label);
95238fd1498Szrj }
95338fd1498Szrj
95438fd1498Szrj rtx_jump_table_data *table = jump_table_for_label (label);
95538fd1498Szrj if (!table)
95638fd1498Szrj {
95738fd1498Szrj log = LABEL_ALIGN (label);
95838fd1498Szrj if (max_log < log)
95938fd1498Szrj {
96038fd1498Szrj max_log = log;
96138fd1498Szrj max_skip = targetm.asm_out.label_align_max_skip (label);
96238fd1498Szrj }
96338fd1498Szrj }
96438fd1498Szrj /* ADDR_VECs only take room if read-only data goes into the text
96538fd1498Szrj section. */
96638fd1498Szrj if ((JUMP_TABLES_IN_TEXT_SECTION
96738fd1498Szrj || readonly_data_section == text_section)
96838fd1498Szrj && table)
96938fd1498Szrj {
97038fd1498Szrj log = ADDR_VEC_ALIGN (table);
97138fd1498Szrj if (max_log < log)
97238fd1498Szrj {
97338fd1498Szrj max_log = log;
97438fd1498Szrj max_skip = targetm.asm_out.label_align_max_skip (label);
97538fd1498Szrj }
97638fd1498Szrj }
97738fd1498Szrj LABEL_TO_ALIGNMENT (label) = max_log;
97838fd1498Szrj LABEL_TO_MAX_SKIP (label) = max_skip;
97938fd1498Szrj max_log = 0;
98038fd1498Szrj max_skip = 0;
98138fd1498Szrj }
98238fd1498Szrj else if (BARRIER_P (insn))
98338fd1498Szrj {
98438fd1498Szrj rtx_insn *label;
98538fd1498Szrj
98638fd1498Szrj for (label = insn; label && ! INSN_P (label);
98738fd1498Szrj label = NEXT_INSN (label))
98838fd1498Szrj if (LABEL_P (label))
98938fd1498Szrj {
99038fd1498Szrj log = LABEL_ALIGN_AFTER_BARRIER (insn);
99138fd1498Szrj if (max_log < log)
99238fd1498Szrj {
99338fd1498Szrj max_log = log;
99438fd1498Szrj max_skip = targetm.asm_out.label_align_after_barrier_max_skip (label);
99538fd1498Szrj }
99638fd1498Szrj break;
99738fd1498Szrj }
99838fd1498Szrj }
99938fd1498Szrj }
100038fd1498Szrj if (!HAVE_ATTR_length)
100138fd1498Szrj return;
100238fd1498Szrj
100338fd1498Szrj /* Allocate the rest of the arrays. */
100438fd1498Szrj insn_lengths = XNEWVEC (int, max_uid);
100538fd1498Szrj insn_lengths_max_uid = max_uid;
100638fd1498Szrj /* Syntax errors can lead to labels being outside of the main insn stream.
100738fd1498Szrj Initialize insn_addresses, so that we get reproducible results. */
100838fd1498Szrj INSN_ADDRESSES_ALLOC (max_uid);
100938fd1498Szrj
101038fd1498Szrj varying_length = XCNEWVEC (char, max_uid);
101138fd1498Szrj
101238fd1498Szrj /* Initialize uid_align. We scan instructions
101338fd1498Szrj from end to start, and keep in align_tab[n] the last seen insn
101438fd1498Szrj that does an alignment of at least n+1, i.e. the successor
101538fd1498Szrj in the alignment chain for an insn that does / has a known
101638fd1498Szrj alignment of n. */
101738fd1498Szrj uid_align = XCNEWVEC (rtx, max_uid);
101838fd1498Szrj
101938fd1498Szrj for (i = MAX_CODE_ALIGN + 1; --i >= 0;)
102038fd1498Szrj align_tab[i] = NULL_RTX;
102138fd1498Szrj seq = get_last_insn ();
102238fd1498Szrj for (; seq; seq = PREV_INSN (seq))
102338fd1498Szrj {
102438fd1498Szrj int uid = INSN_UID (seq);
102538fd1498Szrj int log;
102638fd1498Szrj log = (LABEL_P (seq) ? LABEL_TO_ALIGNMENT (seq) : 0);
102738fd1498Szrj uid_align[uid] = align_tab[0];
102838fd1498Szrj if (log)
102938fd1498Szrj {
103038fd1498Szrj /* Found an alignment label. */
103138fd1498Szrj uid_align[uid] = align_tab[log];
103238fd1498Szrj for (i = log - 1; i >= 0; i--)
103338fd1498Szrj align_tab[i] = seq;
103438fd1498Szrj }
103538fd1498Szrj }
103638fd1498Szrj
103738fd1498Szrj /* When optimizing, we start assuming minimum length, and keep increasing
103838fd1498Szrj lengths as we find the need for this, till nothing changes.
103938fd1498Szrj When not optimizing, we start assuming maximum lengths, and
104038fd1498Szrj do a single pass to update the lengths. */
104138fd1498Szrj bool increasing = optimize != 0;
104238fd1498Szrj
104338fd1498Szrj #ifdef CASE_VECTOR_SHORTEN_MODE
104438fd1498Szrj if (optimize)
104538fd1498Szrj {
104638fd1498Szrj /* Look for ADDR_DIFF_VECs, and initialize their minimum and maximum
104738fd1498Szrj label fields. */
104838fd1498Szrj
104938fd1498Szrj int min_shuid = INSN_SHUID (get_insns ()) - 1;
105038fd1498Szrj int max_shuid = INSN_SHUID (get_last_insn ()) + 1;
105138fd1498Szrj int rel;
105238fd1498Szrj
105338fd1498Szrj for (insn = first; insn != 0; insn = NEXT_INSN (insn))
105438fd1498Szrj {
105538fd1498Szrj rtx min_lab = NULL_RTX, max_lab = NULL_RTX, pat;
105638fd1498Szrj int len, i, min, max, insn_shuid;
105738fd1498Szrj int min_align;
105838fd1498Szrj addr_diff_vec_flags flags;
105938fd1498Szrj
106038fd1498Szrj if (! JUMP_TABLE_DATA_P (insn)
106138fd1498Szrj || GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC)
106238fd1498Szrj continue;
106338fd1498Szrj pat = PATTERN (insn);
106438fd1498Szrj len = XVECLEN (pat, 1);
106538fd1498Szrj gcc_assert (len > 0);
106638fd1498Szrj min_align = MAX_CODE_ALIGN;
106738fd1498Szrj for (min = max_shuid, max = min_shuid, i = len - 1; i >= 0; i--)
106838fd1498Szrj {
106938fd1498Szrj rtx lab = XEXP (XVECEXP (pat, 1, i), 0);
107038fd1498Szrj int shuid = INSN_SHUID (lab);
107138fd1498Szrj if (shuid < min)
107238fd1498Szrj {
107338fd1498Szrj min = shuid;
107438fd1498Szrj min_lab = lab;
107538fd1498Szrj }
107638fd1498Szrj if (shuid > max)
107738fd1498Szrj {
107838fd1498Szrj max = shuid;
107938fd1498Szrj max_lab = lab;
108038fd1498Szrj }
108138fd1498Szrj if (min_align > LABEL_TO_ALIGNMENT (lab))
108238fd1498Szrj min_align = LABEL_TO_ALIGNMENT (lab);
108338fd1498Szrj }
108438fd1498Szrj XEXP (pat, 2) = gen_rtx_LABEL_REF (Pmode, min_lab);
108538fd1498Szrj XEXP (pat, 3) = gen_rtx_LABEL_REF (Pmode, max_lab);
108638fd1498Szrj insn_shuid = INSN_SHUID (insn);
108738fd1498Szrj rel = INSN_SHUID (XEXP (XEXP (pat, 0), 0));
108838fd1498Szrj memset (&flags, 0, sizeof (flags));
108938fd1498Szrj flags.min_align = min_align;
109038fd1498Szrj flags.base_after_vec = rel > insn_shuid;
109138fd1498Szrj flags.min_after_vec = min > insn_shuid;
109238fd1498Szrj flags.max_after_vec = max > insn_shuid;
109338fd1498Szrj flags.min_after_base = min > rel;
109438fd1498Szrj flags.max_after_base = max > rel;
109538fd1498Szrj ADDR_DIFF_VEC_FLAGS (pat) = flags;
109638fd1498Szrj
109738fd1498Szrj if (increasing)
109838fd1498Szrj PUT_MODE (pat, CASE_VECTOR_SHORTEN_MODE (0, 0, pat));
109938fd1498Szrj }
110038fd1498Szrj }
110138fd1498Szrj #endif /* CASE_VECTOR_SHORTEN_MODE */
110238fd1498Szrj
110338fd1498Szrj /* Compute initial lengths, addresses, and varying flags for each insn. */
110438fd1498Szrj int (*length_fun) (rtx_insn *) = increasing ? insn_min_length : insn_default_length;
110538fd1498Szrj
110638fd1498Szrj for (insn_current_address = 0, insn = first;
110738fd1498Szrj insn != 0;
110838fd1498Szrj insn_current_address += insn_lengths[uid], insn = NEXT_INSN (insn))
110938fd1498Szrj {
111038fd1498Szrj uid = INSN_UID (insn);
111138fd1498Szrj
111238fd1498Szrj insn_lengths[uid] = 0;
111338fd1498Szrj
111438fd1498Szrj if (LABEL_P (insn))
111538fd1498Szrj {
111638fd1498Szrj int log = LABEL_TO_ALIGNMENT (insn);
111738fd1498Szrj if (log)
111838fd1498Szrj {
111938fd1498Szrj int align = 1 << log;
112038fd1498Szrj int new_address = (insn_current_address + align - 1) & -align;
112138fd1498Szrj insn_lengths[uid] = new_address - insn_current_address;
112238fd1498Szrj }
112338fd1498Szrj }
112438fd1498Szrj
112538fd1498Szrj INSN_ADDRESSES (uid) = insn_current_address + insn_lengths[uid];
112638fd1498Szrj
112738fd1498Szrj if (NOTE_P (insn) || BARRIER_P (insn)
112838fd1498Szrj || LABEL_P (insn) || DEBUG_INSN_P (insn))
112938fd1498Szrj continue;
113038fd1498Szrj if (insn->deleted ())
113138fd1498Szrj continue;
113238fd1498Szrj
113338fd1498Szrj body = PATTERN (insn);
113438fd1498Szrj if (rtx_jump_table_data *table = dyn_cast <rtx_jump_table_data *> (insn))
113538fd1498Szrj {
113638fd1498Szrj /* This only takes room if read-only data goes into the text
113738fd1498Szrj section. */
113838fd1498Szrj if (JUMP_TABLES_IN_TEXT_SECTION
113938fd1498Szrj || readonly_data_section == text_section)
114038fd1498Szrj insn_lengths[uid] = (XVECLEN (body,
114138fd1498Szrj GET_CODE (body) == ADDR_DIFF_VEC)
114238fd1498Szrj * GET_MODE_SIZE (table->get_data_mode ()));
114338fd1498Szrj /* Alignment is handled by ADDR_VEC_ALIGN. */
114438fd1498Szrj }
114538fd1498Szrj else if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0)
114638fd1498Szrj insn_lengths[uid] = asm_insn_count (body) * insn_default_length (insn);
114738fd1498Szrj else if (rtx_sequence *body_seq = dyn_cast <rtx_sequence *> (body))
114838fd1498Szrj {
114938fd1498Szrj int i;
115038fd1498Szrj int const_delay_slots;
115138fd1498Szrj if (DELAY_SLOTS)
115238fd1498Szrj const_delay_slots = const_num_delay_slots (body_seq->insn (0));
115338fd1498Szrj else
115438fd1498Szrj const_delay_slots = 0;
115538fd1498Szrj
115638fd1498Szrj int (*inner_length_fun) (rtx_insn *)
115738fd1498Szrj = const_delay_slots ? length_fun : insn_default_length;
115838fd1498Szrj /* Inside a delay slot sequence, we do not do any branch shortening
115938fd1498Szrj if the shortening could change the number of delay slots
116038fd1498Szrj of the branch. */
116138fd1498Szrj for (i = 0; i < body_seq->len (); i++)
116238fd1498Szrj {
116338fd1498Szrj rtx_insn *inner_insn = body_seq->insn (i);
116438fd1498Szrj int inner_uid = INSN_UID (inner_insn);
116538fd1498Szrj int inner_length;
116638fd1498Szrj
116738fd1498Szrj if (GET_CODE (PATTERN (inner_insn)) == ASM_INPUT
116838fd1498Szrj || asm_noperands (PATTERN (inner_insn)) >= 0)
116938fd1498Szrj inner_length = (asm_insn_count (PATTERN (inner_insn))
117038fd1498Szrj * insn_default_length (inner_insn));
117138fd1498Szrj else
117238fd1498Szrj inner_length = inner_length_fun (inner_insn);
117338fd1498Szrj
117438fd1498Szrj insn_lengths[inner_uid] = inner_length;
117538fd1498Szrj if (const_delay_slots)
117638fd1498Szrj {
117738fd1498Szrj if ((varying_length[inner_uid]
117838fd1498Szrj = insn_variable_length_p (inner_insn)) != 0)
117938fd1498Szrj varying_length[uid] = 1;
118038fd1498Szrj INSN_ADDRESSES (inner_uid) = (insn_current_address
118138fd1498Szrj + insn_lengths[uid]);
118238fd1498Szrj }
118338fd1498Szrj else
118438fd1498Szrj varying_length[inner_uid] = 0;
118538fd1498Szrj insn_lengths[uid] += inner_length;
118638fd1498Szrj }
118738fd1498Szrj }
118838fd1498Szrj else if (GET_CODE (body) != USE && GET_CODE (body) != CLOBBER)
118938fd1498Szrj {
119038fd1498Szrj insn_lengths[uid] = length_fun (insn);
119138fd1498Szrj varying_length[uid] = insn_variable_length_p (insn);
119238fd1498Szrj }
119338fd1498Szrj
119438fd1498Szrj /* If needed, do any adjustment. */
119538fd1498Szrj #ifdef ADJUST_INSN_LENGTH
119638fd1498Szrj ADJUST_INSN_LENGTH (insn, insn_lengths[uid]);
119738fd1498Szrj if (insn_lengths[uid] < 0)
119838fd1498Szrj fatal_insn ("negative insn length", insn);
119938fd1498Szrj #endif
120038fd1498Szrj }
120138fd1498Szrj
120238fd1498Szrj /* Now loop over all the insns finding varying length insns. For each,
120338fd1498Szrj get the current insn length. If it has changed, reflect the change.
120438fd1498Szrj When nothing changes for a full pass, we are done. */
120538fd1498Szrj
120638fd1498Szrj while (something_changed)
120738fd1498Szrj {
120838fd1498Szrj something_changed = 0;
120938fd1498Szrj insn_current_align = MAX_CODE_ALIGN - 1;
121038fd1498Szrj for (insn_current_address = 0, insn = first;
121138fd1498Szrj insn != 0;
121238fd1498Szrj insn = NEXT_INSN (insn))
121338fd1498Szrj {
121438fd1498Szrj int new_length;
121538fd1498Szrj #ifdef ADJUST_INSN_LENGTH
121638fd1498Szrj int tmp_length;
121738fd1498Szrj #endif
121838fd1498Szrj int length_align;
121938fd1498Szrj
122038fd1498Szrj uid = INSN_UID (insn);
122138fd1498Szrj
122238fd1498Szrj if (rtx_code_label *label = dyn_cast <rtx_code_label *> (insn))
122338fd1498Szrj {
122438fd1498Szrj int log = LABEL_TO_ALIGNMENT (label);
122538fd1498Szrj
122638fd1498Szrj #ifdef CASE_VECTOR_SHORTEN_MODE
122738fd1498Szrj /* If the mode of a following jump table was changed, we
122838fd1498Szrj may need to update the alignment of this label. */
122938fd1498Szrj
123038fd1498Szrj if (JUMP_TABLES_IN_TEXT_SECTION
123138fd1498Szrj || readonly_data_section == text_section)
123238fd1498Szrj {
123338fd1498Szrj rtx_jump_table_data *table = jump_table_for_label (label);
123438fd1498Szrj if (table)
123538fd1498Szrj {
123638fd1498Szrj int newlog = ADDR_VEC_ALIGN (table);
123738fd1498Szrj if (newlog != log)
123838fd1498Szrj {
123938fd1498Szrj log = newlog;
124038fd1498Szrj LABEL_TO_ALIGNMENT (insn) = log;
124138fd1498Szrj something_changed = 1;
124238fd1498Szrj }
124338fd1498Szrj }
124438fd1498Szrj }
124538fd1498Szrj #endif
124638fd1498Szrj
124738fd1498Szrj if (log > insn_current_align)
124838fd1498Szrj {
124938fd1498Szrj int align = 1 << log;
125038fd1498Szrj int new_address= (insn_current_address + align - 1) & -align;
125138fd1498Szrj insn_lengths[uid] = new_address - insn_current_address;
125238fd1498Szrj insn_current_align = log;
125338fd1498Szrj insn_current_address = new_address;
125438fd1498Szrj }
125538fd1498Szrj else
125638fd1498Szrj insn_lengths[uid] = 0;
125738fd1498Szrj INSN_ADDRESSES (uid) = insn_current_address;
125838fd1498Szrj continue;
125938fd1498Szrj }
126038fd1498Szrj
126138fd1498Szrj length_align = INSN_LENGTH_ALIGNMENT (insn);
126238fd1498Szrj if (length_align < insn_current_align)
126338fd1498Szrj insn_current_align = length_align;
126438fd1498Szrj
126538fd1498Szrj insn_last_address = INSN_ADDRESSES (uid);
126638fd1498Szrj INSN_ADDRESSES (uid) = insn_current_address;
126738fd1498Szrj
126838fd1498Szrj #ifdef CASE_VECTOR_SHORTEN_MODE
126938fd1498Szrj if (optimize
127038fd1498Szrj && JUMP_TABLE_DATA_P (insn)
127138fd1498Szrj && GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)
127238fd1498Szrj {
127338fd1498Szrj rtx_jump_table_data *table = as_a <rtx_jump_table_data *> (insn);
127438fd1498Szrj rtx body = PATTERN (insn);
127538fd1498Szrj int old_length = insn_lengths[uid];
127638fd1498Szrj rtx_insn *rel_lab =
127738fd1498Szrj safe_as_a <rtx_insn *> (XEXP (XEXP (body, 0), 0));
127838fd1498Szrj rtx min_lab = XEXP (XEXP (body, 2), 0);
127938fd1498Szrj rtx max_lab = XEXP (XEXP (body, 3), 0);
128038fd1498Szrj int rel_addr = INSN_ADDRESSES (INSN_UID (rel_lab));
128138fd1498Szrj int min_addr = INSN_ADDRESSES (INSN_UID (min_lab));
128238fd1498Szrj int max_addr = INSN_ADDRESSES (INSN_UID (max_lab));
128338fd1498Szrj rtx_insn *prev;
128438fd1498Szrj int rel_align = 0;
128538fd1498Szrj addr_diff_vec_flags flags;
128638fd1498Szrj scalar_int_mode vec_mode;
128738fd1498Szrj
128838fd1498Szrj /* Avoid automatic aggregate initialization. */
128938fd1498Szrj flags = ADDR_DIFF_VEC_FLAGS (body);
129038fd1498Szrj
129138fd1498Szrj /* Try to find a known alignment for rel_lab. */
129238fd1498Szrj for (prev = rel_lab;
129338fd1498Szrj prev
129438fd1498Szrj && ! insn_lengths[INSN_UID (prev)]
129538fd1498Szrj && ! (varying_length[INSN_UID (prev)] & 1);
129638fd1498Szrj prev = PREV_INSN (prev))
129738fd1498Szrj if (varying_length[INSN_UID (prev)] & 2)
129838fd1498Szrj {
129938fd1498Szrj rel_align = LABEL_TO_ALIGNMENT (prev);
130038fd1498Szrj break;
130138fd1498Szrj }
130238fd1498Szrj
130338fd1498Szrj /* See the comment on addr_diff_vec_flags in rtl.h for the
130438fd1498Szrj meaning of the flags values. base: REL_LAB vec: INSN */
130538fd1498Szrj /* Anything after INSN has still addresses from the last
130638fd1498Szrj pass; adjust these so that they reflect our current
130738fd1498Szrj estimate for this pass. */
130838fd1498Szrj if (flags.base_after_vec)
130938fd1498Szrj rel_addr += insn_current_address - insn_last_address;
131038fd1498Szrj if (flags.min_after_vec)
131138fd1498Szrj min_addr += insn_current_address - insn_last_address;
131238fd1498Szrj if (flags.max_after_vec)
131338fd1498Szrj max_addr += insn_current_address - insn_last_address;
131438fd1498Szrj /* We want to know the worst case, i.e. lowest possible value
131538fd1498Szrj for the offset of MIN_LAB. If MIN_LAB is after REL_LAB,
131638fd1498Szrj its offset is positive, and we have to be wary of code shrink;
131738fd1498Szrj otherwise, it is negative, and we have to be vary of code
131838fd1498Szrj size increase. */
131938fd1498Szrj if (flags.min_after_base)
132038fd1498Szrj {
132138fd1498Szrj /* If INSN is between REL_LAB and MIN_LAB, the size
132238fd1498Szrj changes we are about to make can change the alignment
132338fd1498Szrj within the observed offset, therefore we have to break
132438fd1498Szrj it up into two parts that are independent. */
132538fd1498Szrj if (! flags.base_after_vec && flags.min_after_vec)
132638fd1498Szrj {
132738fd1498Szrj min_addr -= align_fuzz (rel_lab, insn, rel_align, 0);
132838fd1498Szrj min_addr -= align_fuzz (insn, min_lab, 0, 0);
132938fd1498Szrj }
133038fd1498Szrj else
133138fd1498Szrj min_addr -= align_fuzz (rel_lab, min_lab, rel_align, 0);
133238fd1498Szrj }
133338fd1498Szrj else
133438fd1498Szrj {
133538fd1498Szrj if (flags.base_after_vec && ! flags.min_after_vec)
133638fd1498Szrj {
133738fd1498Szrj min_addr -= align_fuzz (min_lab, insn, 0, ~0);
133838fd1498Szrj min_addr -= align_fuzz (insn, rel_lab, 0, ~0);
133938fd1498Szrj }
134038fd1498Szrj else
134138fd1498Szrj min_addr -= align_fuzz (min_lab, rel_lab, 0, ~0);
134238fd1498Szrj }
134338fd1498Szrj /* Likewise, determine the highest lowest possible value
134438fd1498Szrj for the offset of MAX_LAB. */
134538fd1498Szrj if (flags.max_after_base)
134638fd1498Szrj {
134738fd1498Szrj if (! flags.base_after_vec && flags.max_after_vec)
134838fd1498Szrj {
134938fd1498Szrj max_addr += align_fuzz (rel_lab, insn, rel_align, ~0);
135038fd1498Szrj max_addr += align_fuzz (insn, max_lab, 0, ~0);
135138fd1498Szrj }
135238fd1498Szrj else
135338fd1498Szrj max_addr += align_fuzz (rel_lab, max_lab, rel_align, ~0);
135438fd1498Szrj }
135538fd1498Szrj else
135638fd1498Szrj {
135738fd1498Szrj if (flags.base_after_vec && ! flags.max_after_vec)
135838fd1498Szrj {
135938fd1498Szrj max_addr += align_fuzz (max_lab, insn, 0, 0);
136038fd1498Szrj max_addr += align_fuzz (insn, rel_lab, 0, 0);
136138fd1498Szrj }
136238fd1498Szrj else
136338fd1498Szrj max_addr += align_fuzz (max_lab, rel_lab, 0, 0);
136438fd1498Szrj }
136538fd1498Szrj vec_mode = CASE_VECTOR_SHORTEN_MODE (min_addr - rel_addr,
136638fd1498Szrj max_addr - rel_addr, body);
136738fd1498Szrj if (!increasing
136838fd1498Szrj || (GET_MODE_SIZE (vec_mode)
136938fd1498Szrj >= GET_MODE_SIZE (table->get_data_mode ())))
137038fd1498Szrj PUT_MODE (body, vec_mode);
137138fd1498Szrj if (JUMP_TABLES_IN_TEXT_SECTION
137238fd1498Szrj || readonly_data_section == text_section)
137338fd1498Szrj {
137438fd1498Szrj insn_lengths[uid]
137538fd1498Szrj = (XVECLEN (body, 1)
137638fd1498Szrj * GET_MODE_SIZE (table->get_data_mode ()));
137738fd1498Szrj insn_current_address += insn_lengths[uid];
137838fd1498Szrj if (insn_lengths[uid] != old_length)
137938fd1498Szrj something_changed = 1;
138038fd1498Szrj }
138138fd1498Szrj
138238fd1498Szrj continue;
138338fd1498Szrj }
138438fd1498Szrj #endif /* CASE_VECTOR_SHORTEN_MODE */
138538fd1498Szrj
138638fd1498Szrj if (! (varying_length[uid]))
138738fd1498Szrj {
138838fd1498Szrj if (NONJUMP_INSN_P (insn)
138938fd1498Szrj && GET_CODE (PATTERN (insn)) == SEQUENCE)
139038fd1498Szrj {
139138fd1498Szrj int i;
139238fd1498Szrj
139338fd1498Szrj body = PATTERN (insn);
139438fd1498Szrj for (i = 0; i < XVECLEN (body, 0); i++)
139538fd1498Szrj {
139638fd1498Szrj rtx inner_insn = XVECEXP (body, 0, i);
139738fd1498Szrj int inner_uid = INSN_UID (inner_insn);
139838fd1498Szrj
139938fd1498Szrj INSN_ADDRESSES (inner_uid) = insn_current_address;
140038fd1498Szrj
140138fd1498Szrj insn_current_address += insn_lengths[inner_uid];
140238fd1498Szrj }
140338fd1498Szrj }
140438fd1498Szrj else
140538fd1498Szrj insn_current_address += insn_lengths[uid];
140638fd1498Szrj
140738fd1498Szrj continue;
140838fd1498Szrj }
140938fd1498Szrj
141038fd1498Szrj if (NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == SEQUENCE)
141138fd1498Szrj {
141238fd1498Szrj rtx_sequence *seqn = as_a <rtx_sequence *> (PATTERN (insn));
141338fd1498Szrj int i;
141438fd1498Szrj
141538fd1498Szrj body = PATTERN (insn);
141638fd1498Szrj new_length = 0;
141738fd1498Szrj for (i = 0; i < seqn->len (); i++)
141838fd1498Szrj {
141938fd1498Szrj rtx_insn *inner_insn = seqn->insn (i);
142038fd1498Szrj int inner_uid = INSN_UID (inner_insn);
142138fd1498Szrj int inner_length;
142238fd1498Szrj
142338fd1498Szrj INSN_ADDRESSES (inner_uid) = insn_current_address;
142438fd1498Szrj
142538fd1498Szrj /* insn_current_length returns 0 for insns with a
142638fd1498Szrj non-varying length. */
142738fd1498Szrj if (! varying_length[inner_uid])
142838fd1498Szrj inner_length = insn_lengths[inner_uid];
142938fd1498Szrj else
143038fd1498Szrj inner_length = insn_current_length (inner_insn);
143138fd1498Szrj
143238fd1498Szrj if (inner_length != insn_lengths[inner_uid])
143338fd1498Szrj {
143438fd1498Szrj if (!increasing || inner_length > insn_lengths[inner_uid])
143538fd1498Szrj {
143638fd1498Szrj insn_lengths[inner_uid] = inner_length;
143738fd1498Szrj something_changed = 1;
143838fd1498Szrj }
143938fd1498Szrj else
144038fd1498Szrj inner_length = insn_lengths[inner_uid];
144138fd1498Szrj }
144238fd1498Szrj insn_current_address += inner_length;
144338fd1498Szrj new_length += inner_length;
144438fd1498Szrj }
144538fd1498Szrj }
144638fd1498Szrj else
144738fd1498Szrj {
144838fd1498Szrj new_length = insn_current_length (insn);
144938fd1498Szrj insn_current_address += new_length;
145038fd1498Szrj }
145138fd1498Szrj
145238fd1498Szrj #ifdef ADJUST_INSN_LENGTH
145338fd1498Szrj /* If needed, do any adjustment. */
145438fd1498Szrj tmp_length = new_length;
145538fd1498Szrj ADJUST_INSN_LENGTH (insn, new_length);
145638fd1498Szrj insn_current_address += (new_length - tmp_length);
145738fd1498Szrj #endif
145838fd1498Szrj
145938fd1498Szrj if (new_length != insn_lengths[uid]
146038fd1498Szrj && (!increasing || new_length > insn_lengths[uid]))
146138fd1498Szrj {
146238fd1498Szrj insn_lengths[uid] = new_length;
146338fd1498Szrj something_changed = 1;
146438fd1498Szrj }
146538fd1498Szrj else
146638fd1498Szrj insn_current_address += insn_lengths[uid] - new_length;
146738fd1498Szrj }
146838fd1498Szrj /* For a non-optimizing compile, do only a single pass. */
146938fd1498Szrj if (!increasing)
147038fd1498Szrj break;
147138fd1498Szrj }
147238fd1498Szrj crtl->max_insn_address = insn_current_address;
147338fd1498Szrj free (varying_length);
147438fd1498Szrj }
147538fd1498Szrj
147638fd1498Szrj /* Given the body of an INSN known to be generated by an ASM statement, return
147738fd1498Szrj the number of machine instructions likely to be generated for this insn.
147838fd1498Szrj This is used to compute its length. */
147938fd1498Szrj
148038fd1498Szrj static int
asm_insn_count(rtx body)148138fd1498Szrj asm_insn_count (rtx body)
148238fd1498Szrj {
148338fd1498Szrj const char *templ;
148438fd1498Szrj
148538fd1498Szrj if (GET_CODE (body) == ASM_INPUT)
148638fd1498Szrj templ = XSTR (body, 0);
148738fd1498Szrj else
148838fd1498Szrj templ = decode_asm_operands (body, NULL, NULL, NULL, NULL, NULL);
148938fd1498Szrj
149038fd1498Szrj return asm_str_count (templ);
149138fd1498Szrj }
149238fd1498Szrj
149338fd1498Szrj /* Return the number of machine instructions likely to be generated for the
149438fd1498Szrj inline-asm template. */
149538fd1498Szrj int
asm_str_count(const char * templ)149638fd1498Szrj asm_str_count (const char *templ)
149738fd1498Szrj {
149838fd1498Szrj int count = 1;
149938fd1498Szrj
150038fd1498Szrj if (!*templ)
150138fd1498Szrj return 0;
150238fd1498Szrj
150338fd1498Szrj for (; *templ; templ++)
150438fd1498Szrj if (IS_ASM_LOGICAL_LINE_SEPARATOR (*templ, templ)
150538fd1498Szrj || *templ == '\n')
150638fd1498Szrj count++;
150738fd1498Szrj
150838fd1498Szrj return count;
150938fd1498Szrj }
151038fd1498Szrj
151138fd1498Szrj /* Return true if DWARF2 debug info can be emitted for DECL. */
151238fd1498Szrj
151338fd1498Szrj static bool
dwarf2_debug_info_emitted_p(tree decl)151438fd1498Szrj dwarf2_debug_info_emitted_p (tree decl)
151538fd1498Szrj {
151638fd1498Szrj if (write_symbols != DWARF2_DEBUG && write_symbols != VMS_AND_DWARF2_DEBUG)
151738fd1498Szrj return false;
151838fd1498Szrj
151938fd1498Szrj if (DECL_IGNORED_P (decl))
152038fd1498Szrj return false;
152138fd1498Szrj
152238fd1498Szrj return true;
152338fd1498Szrj }
152438fd1498Szrj
152538fd1498Szrj /* Return scope resulting from combination of S1 and S2. */
152638fd1498Szrj static tree
choose_inner_scope(tree s1,tree s2)152738fd1498Szrj choose_inner_scope (tree s1, tree s2)
152838fd1498Szrj {
152938fd1498Szrj if (!s1)
153038fd1498Szrj return s2;
153138fd1498Szrj if (!s2)
153238fd1498Szrj return s1;
153338fd1498Szrj if (BLOCK_NUMBER (s1) > BLOCK_NUMBER (s2))
153438fd1498Szrj return s1;
153538fd1498Szrj return s2;
153638fd1498Szrj }
153738fd1498Szrj
153838fd1498Szrj /* Emit lexical block notes needed to change scope from S1 to S2. */
153938fd1498Szrj
154038fd1498Szrj static void
change_scope(rtx_insn * orig_insn,tree s1,tree s2)154138fd1498Szrj change_scope (rtx_insn *orig_insn, tree s1, tree s2)
154238fd1498Szrj {
154338fd1498Szrj rtx_insn *insn = orig_insn;
154438fd1498Szrj tree com = NULL_TREE;
154538fd1498Szrj tree ts1 = s1, ts2 = s2;
154638fd1498Szrj tree s;
154738fd1498Szrj
154838fd1498Szrj while (ts1 != ts2)
154938fd1498Szrj {
155038fd1498Szrj gcc_assert (ts1 && ts2);
155138fd1498Szrj if (BLOCK_NUMBER (ts1) > BLOCK_NUMBER (ts2))
155238fd1498Szrj ts1 = BLOCK_SUPERCONTEXT (ts1);
155338fd1498Szrj else if (BLOCK_NUMBER (ts1) < BLOCK_NUMBER (ts2))
155438fd1498Szrj ts2 = BLOCK_SUPERCONTEXT (ts2);
155538fd1498Szrj else
155638fd1498Szrj {
155738fd1498Szrj ts1 = BLOCK_SUPERCONTEXT (ts1);
155838fd1498Szrj ts2 = BLOCK_SUPERCONTEXT (ts2);
155938fd1498Szrj }
156038fd1498Szrj }
156138fd1498Szrj com = ts1;
156238fd1498Szrj
156338fd1498Szrj /* Close scopes. */
156438fd1498Szrj s = s1;
156538fd1498Szrj while (s != com)
156638fd1498Szrj {
156738fd1498Szrj rtx_note *note = emit_note_before (NOTE_INSN_BLOCK_END, insn);
156838fd1498Szrj NOTE_BLOCK (note) = s;
156938fd1498Szrj s = BLOCK_SUPERCONTEXT (s);
157038fd1498Szrj }
157138fd1498Szrj
157238fd1498Szrj /* Open scopes. */
157338fd1498Szrj s = s2;
157438fd1498Szrj while (s != com)
157538fd1498Szrj {
157638fd1498Szrj insn = emit_note_before (NOTE_INSN_BLOCK_BEG, insn);
157738fd1498Szrj NOTE_BLOCK (insn) = s;
157838fd1498Szrj s = BLOCK_SUPERCONTEXT (s);
157938fd1498Szrj }
158038fd1498Szrj }
158138fd1498Szrj
158238fd1498Szrj /* Rebuild all the NOTE_INSN_BLOCK_BEG and NOTE_INSN_BLOCK_END notes based
158338fd1498Szrj on the scope tree and the newly reordered instructions. */
158438fd1498Szrj
158538fd1498Szrj static void
reemit_insn_block_notes(void)158638fd1498Szrj reemit_insn_block_notes (void)
158738fd1498Szrj {
158838fd1498Szrj tree cur_block = DECL_INITIAL (cfun->decl);
158938fd1498Szrj rtx_insn *insn;
159038fd1498Szrj
159138fd1498Szrj insn = get_insns ();
159238fd1498Szrj for (; insn; insn = NEXT_INSN (insn))
159338fd1498Szrj {
159438fd1498Szrj tree this_block;
159538fd1498Szrj
159638fd1498Szrj /* Prevent lexical blocks from straddling section boundaries. */
159738fd1498Szrj if (NOTE_P (insn))
159838fd1498Szrj switch (NOTE_KIND (insn))
159938fd1498Szrj {
160038fd1498Szrj case NOTE_INSN_SWITCH_TEXT_SECTIONS:
160138fd1498Szrj {
160238fd1498Szrj for (tree s = cur_block; s != DECL_INITIAL (cfun->decl);
160338fd1498Szrj s = BLOCK_SUPERCONTEXT (s))
160438fd1498Szrj {
160538fd1498Szrj rtx_note *note = emit_note_before (NOTE_INSN_BLOCK_END, insn);
160638fd1498Szrj NOTE_BLOCK (note) = s;
160738fd1498Szrj note = emit_note_after (NOTE_INSN_BLOCK_BEG, insn);
160838fd1498Szrj NOTE_BLOCK (note) = s;
160938fd1498Szrj }
161038fd1498Szrj }
161138fd1498Szrj break;
161238fd1498Szrj
161338fd1498Szrj case NOTE_INSN_BEGIN_STMT:
161438fd1498Szrj case NOTE_INSN_INLINE_ENTRY:
161538fd1498Szrj this_block = LOCATION_BLOCK (NOTE_MARKER_LOCATION (insn));
161638fd1498Szrj goto set_cur_block_to_this_block;
161738fd1498Szrj
161838fd1498Szrj default:
161938fd1498Szrj continue;
162038fd1498Szrj }
162138fd1498Szrj
162238fd1498Szrj if (!active_insn_p (insn))
162338fd1498Szrj continue;
162438fd1498Szrj
162538fd1498Szrj /* Avoid putting scope notes between jump table and its label. */
162638fd1498Szrj if (JUMP_TABLE_DATA_P (insn))
162738fd1498Szrj continue;
162838fd1498Szrj
162938fd1498Szrj this_block = insn_scope (insn);
163038fd1498Szrj /* For sequences compute scope resulting from merging all scopes
163138fd1498Szrj of instructions nested inside. */
163238fd1498Szrj if (rtx_sequence *body = dyn_cast <rtx_sequence *> (PATTERN (insn)))
163338fd1498Szrj {
163438fd1498Szrj int i;
163538fd1498Szrj
163638fd1498Szrj this_block = NULL;
163738fd1498Szrj for (i = 0; i < body->len (); i++)
163838fd1498Szrj this_block = choose_inner_scope (this_block,
163938fd1498Szrj insn_scope (body->insn (i)));
164038fd1498Szrj }
164138fd1498Szrj set_cur_block_to_this_block:
164238fd1498Szrj if (! this_block)
164338fd1498Szrj {
164438fd1498Szrj if (INSN_LOCATION (insn) == UNKNOWN_LOCATION)
164538fd1498Szrj continue;
164638fd1498Szrj else
164738fd1498Szrj this_block = DECL_INITIAL (cfun->decl);
164838fd1498Szrj }
164938fd1498Szrj
165038fd1498Szrj if (this_block != cur_block)
165138fd1498Szrj {
165238fd1498Szrj change_scope (insn, cur_block, this_block);
165338fd1498Szrj cur_block = this_block;
165438fd1498Szrj }
165538fd1498Szrj }
165638fd1498Szrj
165738fd1498Szrj /* change_scope emits before the insn, not after. */
165838fd1498Szrj rtx_note *note = emit_note (NOTE_INSN_DELETED);
165938fd1498Szrj change_scope (note, cur_block, DECL_INITIAL (cfun->decl));
166038fd1498Szrj delete_insn (note);
166138fd1498Szrj
166238fd1498Szrj reorder_blocks ();
166338fd1498Szrj }
166438fd1498Szrj
166538fd1498Szrj static const char *some_local_dynamic_name;
166638fd1498Szrj
166738fd1498Szrj /* Locate some local-dynamic symbol still in use by this function
166838fd1498Szrj so that we can print its name in local-dynamic base patterns.
166938fd1498Szrj Return null if there are no local-dynamic references. */
167038fd1498Szrj
167138fd1498Szrj const char *
get_some_local_dynamic_name()167238fd1498Szrj get_some_local_dynamic_name ()
167338fd1498Szrj {
167438fd1498Szrj subrtx_iterator::array_type array;
167538fd1498Szrj rtx_insn *insn;
167638fd1498Szrj
167738fd1498Szrj if (some_local_dynamic_name)
167838fd1498Szrj return some_local_dynamic_name;
167938fd1498Szrj
168038fd1498Szrj for (insn = get_insns (); insn ; insn = NEXT_INSN (insn))
168138fd1498Szrj if (NONDEBUG_INSN_P (insn))
168238fd1498Szrj FOR_EACH_SUBRTX (iter, array, PATTERN (insn), ALL)
168338fd1498Szrj {
168438fd1498Szrj const_rtx x = *iter;
168538fd1498Szrj if (GET_CODE (x) == SYMBOL_REF)
168638fd1498Szrj {
168738fd1498Szrj if (SYMBOL_REF_TLS_MODEL (x) == TLS_MODEL_LOCAL_DYNAMIC)
168838fd1498Szrj return some_local_dynamic_name = XSTR (x, 0);
168938fd1498Szrj if (CONSTANT_POOL_ADDRESS_P (x))
169038fd1498Szrj iter.substitute (get_pool_constant (x));
169138fd1498Szrj }
169238fd1498Szrj }
169338fd1498Szrj
169438fd1498Szrj return 0;
169538fd1498Szrj }
169638fd1498Szrj
169738fd1498Szrj /* Arrange for us to emit a source location note before any further
169838fd1498Szrj real insns or section changes, by setting the SEEN_NEXT_VIEW bit in
169938fd1498Szrj *SEEN, as long as we are keeping track of location views. The bit
170038fd1498Szrj indicates we have referenced the next view at the current PC, so we
170138fd1498Szrj have to emit it. This should be called next to the var_location
170238fd1498Szrj debug hook. */
170338fd1498Szrj
170438fd1498Szrj static inline void
set_next_view_needed(int * seen)170538fd1498Szrj set_next_view_needed (int *seen)
170638fd1498Szrj {
170738fd1498Szrj if (debug_variable_location_views)
170838fd1498Szrj *seen |= SEEN_NEXT_VIEW;
170938fd1498Szrj }
171038fd1498Szrj
171138fd1498Szrj /* Clear the flag in *SEEN indicating we need to emit the next view.
171238fd1498Szrj This should be called next to the source_line debug hook. */
171338fd1498Szrj
171438fd1498Szrj static inline void
clear_next_view_needed(int * seen)171538fd1498Szrj clear_next_view_needed (int *seen)
171638fd1498Szrj {
171738fd1498Szrj *seen &= ~SEEN_NEXT_VIEW;
171838fd1498Szrj }
171938fd1498Szrj
172038fd1498Szrj /* Test whether we have a pending request to emit the next view in
172138fd1498Szrj *SEEN, and emit it if needed, clearing the request bit. */
172238fd1498Szrj
172338fd1498Szrj static inline void
maybe_output_next_view(int * seen)172438fd1498Szrj maybe_output_next_view (int *seen)
172538fd1498Szrj {
172638fd1498Szrj if ((*seen & SEEN_NEXT_VIEW) != 0)
172738fd1498Szrj {
172838fd1498Szrj clear_next_view_needed (seen);
172938fd1498Szrj (*debug_hooks->source_line) (last_linenum, last_columnnum,
173038fd1498Szrj last_filename, last_discriminator,
173138fd1498Szrj false);
173238fd1498Szrj }
173338fd1498Szrj }
173438fd1498Szrj
173538fd1498Szrj /* We want to emit param bindings (before the first begin_stmt) in the
173638fd1498Szrj initial view, if we are emitting views. To that end, we may
173738fd1498Szrj consume initial notes in the function, processing them in
173838fd1498Szrj final_start_function, before signaling the beginning of the
173938fd1498Szrj prologue, rather than in final.
174038fd1498Szrj
174138fd1498Szrj We don't test whether the DECLs are PARM_DECLs: the assumption is
174238fd1498Szrj that there will be a NOTE_INSN_BEGIN_STMT marker before any
174338fd1498Szrj non-parameter NOTE_INSN_VAR_LOCATION. It's ok if the marker is not
174438fd1498Szrj there, we'll just have more variable locations bound in the initial
174538fd1498Szrj view, which is consistent with their being bound without any code
174638fd1498Szrj that would give them a value. */
174738fd1498Szrj
174838fd1498Szrj static inline bool
in_initial_view_p(rtx_insn * insn)174938fd1498Szrj in_initial_view_p (rtx_insn *insn)
175038fd1498Szrj {
175138fd1498Szrj return (!DECL_IGNORED_P (current_function_decl)
175238fd1498Szrj && debug_variable_location_views
175338fd1498Szrj && insn && GET_CODE (insn) == NOTE
175438fd1498Szrj && (NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION
175538fd1498Szrj || NOTE_KIND (insn) == NOTE_INSN_DELETED));
175638fd1498Szrj }
175738fd1498Szrj
175838fd1498Szrj /* Output assembler code for the start of a function,
175938fd1498Szrj and initialize some of the variables in this file
176038fd1498Szrj for the new function. The label for the function and associated
176138fd1498Szrj assembler pseudo-ops have already been output in `assemble_start_function'.
176238fd1498Szrj
176338fd1498Szrj FIRST is the first insn of the rtl for the function being compiled.
176438fd1498Szrj FILE is the file to write assembler code to.
176538fd1498Szrj SEEN should be initially set to zero, and it may be updated to
176638fd1498Szrj indicate we have references to the next location view, that would
176738fd1498Szrj require us to emit it at the current PC.
176838fd1498Szrj OPTIMIZE_P is nonzero if we should eliminate redundant
176938fd1498Szrj test and compare insns. */
177038fd1498Szrj
177138fd1498Szrj static void
final_start_function_1(rtx_insn ** firstp,FILE * file,int * seen,int optimize_p ATTRIBUTE_UNUSED)177238fd1498Szrj final_start_function_1 (rtx_insn **firstp, FILE *file, int *seen,
177338fd1498Szrj int optimize_p ATTRIBUTE_UNUSED)
177438fd1498Szrj {
177538fd1498Szrj block_depth = 0;
177638fd1498Szrj
177738fd1498Szrj this_is_asm_operands = 0;
177838fd1498Szrj
177938fd1498Szrj need_profile_function = false;
178038fd1498Szrj
178138fd1498Szrj last_filename = LOCATION_FILE (prologue_location);
178238fd1498Szrj last_linenum = LOCATION_LINE (prologue_location);
178338fd1498Szrj last_columnnum = LOCATION_COLUMN (prologue_location);
178438fd1498Szrj last_discriminator = discriminator = 0;
178538fd1498Szrj
178638fd1498Szrj high_block_linenum = high_function_linenum = last_linenum;
178738fd1498Szrj
178838fd1498Szrj if (flag_sanitize & SANITIZE_ADDRESS)
178938fd1498Szrj asan_function_start ();
179038fd1498Szrj
179138fd1498Szrj rtx_insn *first = *firstp;
179238fd1498Szrj if (in_initial_view_p (first))
179338fd1498Szrj {
179438fd1498Szrj do
179538fd1498Szrj {
179638fd1498Szrj final_scan_insn (first, file, 0, 0, seen);
179738fd1498Szrj first = NEXT_INSN (first);
179838fd1498Szrj }
179938fd1498Szrj while (in_initial_view_p (first));
180038fd1498Szrj *firstp = first;
180138fd1498Szrj }
180238fd1498Szrj
180338fd1498Szrj if (!DECL_IGNORED_P (current_function_decl))
180438fd1498Szrj debug_hooks->begin_prologue (last_linenum, last_columnnum,
180538fd1498Szrj last_filename);
180638fd1498Szrj
180738fd1498Szrj if (!dwarf2_debug_info_emitted_p (current_function_decl))
180838fd1498Szrj dwarf2out_begin_prologue (0, 0, NULL);
180938fd1498Szrj
181038fd1498Szrj #ifdef LEAF_REG_REMAP
181138fd1498Szrj if (crtl->uses_only_leaf_regs)
181238fd1498Szrj leaf_renumber_regs (first);
181338fd1498Szrj #endif
181438fd1498Szrj
181538fd1498Szrj /* The Sun386i and perhaps other machines don't work right
181638fd1498Szrj if the profiling code comes after the prologue. */
181738fd1498Szrj if (targetm.profile_before_prologue () && crtl->profile)
181838fd1498Szrj {
181938fd1498Szrj if (targetm.asm_out.function_prologue == default_function_pro_epilogue
182038fd1498Szrj && targetm.have_prologue ())
182138fd1498Szrj {
182238fd1498Szrj rtx_insn *insn;
182338fd1498Szrj for (insn = first; insn; insn = NEXT_INSN (insn))
182438fd1498Szrj if (!NOTE_P (insn))
182538fd1498Szrj {
182638fd1498Szrj insn = NULL;
182738fd1498Szrj break;
182838fd1498Szrj }
182938fd1498Szrj else if (NOTE_KIND (insn) == NOTE_INSN_BASIC_BLOCK
183038fd1498Szrj || NOTE_KIND (insn) == NOTE_INSN_FUNCTION_BEG)
183138fd1498Szrj break;
183238fd1498Szrj else if (NOTE_KIND (insn) == NOTE_INSN_DELETED
183338fd1498Szrj || NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION)
183438fd1498Szrj continue;
183538fd1498Szrj else
183638fd1498Szrj {
183738fd1498Szrj insn = NULL;
183838fd1498Szrj break;
183938fd1498Szrj }
184038fd1498Szrj
184138fd1498Szrj if (insn)
184238fd1498Szrj need_profile_function = true;
184338fd1498Szrj else
184438fd1498Szrj profile_function (file);
184538fd1498Szrj }
184638fd1498Szrj else
184738fd1498Szrj profile_function (file);
184838fd1498Szrj }
184938fd1498Szrj
185038fd1498Szrj /* If debugging, assign block numbers to all of the blocks in this
185138fd1498Szrj function. */
185238fd1498Szrj if (write_symbols)
185338fd1498Szrj {
185438fd1498Szrj reemit_insn_block_notes ();
185538fd1498Szrj number_blocks (current_function_decl);
185638fd1498Szrj /* We never actually put out begin/end notes for the top-level
185738fd1498Szrj block in the function. But, conceptually, that block is
185838fd1498Szrj always needed. */
185938fd1498Szrj TREE_ASM_WRITTEN (DECL_INITIAL (current_function_decl)) = 1;
186038fd1498Szrj }
186138fd1498Szrj
186238fd1498Szrj HOST_WIDE_INT min_frame_size = constant_lower_bound (get_frame_size ());
186338fd1498Szrj if (warn_frame_larger_than
186438fd1498Szrj && min_frame_size > frame_larger_than_size)
186538fd1498Szrj {
186638fd1498Szrj /* Issue a warning */
186738fd1498Szrj warning (OPT_Wframe_larger_than_,
186838fd1498Szrj "the frame size of %wd bytes is larger than %wd bytes",
186938fd1498Szrj min_frame_size, frame_larger_than_size);
187038fd1498Szrj }
187138fd1498Szrj
187238fd1498Szrj /* First output the function prologue: code to set up the stack frame. */
187338fd1498Szrj targetm.asm_out.function_prologue (file);
187438fd1498Szrj
187538fd1498Szrj /* If the machine represents the prologue as RTL, the profiling code must
187638fd1498Szrj be emitted when NOTE_INSN_PROLOGUE_END is scanned. */
187738fd1498Szrj if (! targetm.have_prologue ())
187838fd1498Szrj profile_after_prologue (file);
187938fd1498Szrj }
188038fd1498Szrj
188138fd1498Szrj /* This is an exported final_start_function_1, callable without SEEN. */
188238fd1498Szrj
188338fd1498Szrj void
final_start_function(rtx_insn * first,FILE * file,int optimize_p ATTRIBUTE_UNUSED)188438fd1498Szrj final_start_function (rtx_insn *first, FILE *file,
188538fd1498Szrj int optimize_p ATTRIBUTE_UNUSED)
188638fd1498Szrj {
188738fd1498Szrj int seen = 0;
188838fd1498Szrj final_start_function_1 (&first, file, &seen, optimize_p);
188938fd1498Szrj gcc_assert (seen == 0);
189038fd1498Szrj }
189138fd1498Szrj
189238fd1498Szrj static void
profile_after_prologue(FILE * file ATTRIBUTE_UNUSED)189338fd1498Szrj profile_after_prologue (FILE *file ATTRIBUTE_UNUSED)
189438fd1498Szrj {
189538fd1498Szrj if (!targetm.profile_before_prologue () && crtl->profile)
189638fd1498Szrj profile_function (file);
189738fd1498Szrj }
189838fd1498Szrj
189938fd1498Szrj static void
profile_function(FILE * file ATTRIBUTE_UNUSED)190038fd1498Szrj profile_function (FILE *file ATTRIBUTE_UNUSED)
190138fd1498Szrj {
190238fd1498Szrj #ifndef NO_PROFILE_COUNTERS
190338fd1498Szrj # define NO_PROFILE_COUNTERS 0
190438fd1498Szrj #endif
190538fd1498Szrj #ifdef ASM_OUTPUT_REG_PUSH
190638fd1498Szrj rtx sval = NULL, chain = NULL;
190738fd1498Szrj
190838fd1498Szrj if (cfun->returns_struct)
190938fd1498Szrj sval = targetm.calls.struct_value_rtx (TREE_TYPE (current_function_decl),
191038fd1498Szrj true);
191138fd1498Szrj if (cfun->static_chain_decl)
191238fd1498Szrj chain = targetm.calls.static_chain (current_function_decl, true);
191338fd1498Szrj #endif /* ASM_OUTPUT_REG_PUSH */
191438fd1498Szrj
191538fd1498Szrj if (! NO_PROFILE_COUNTERS)
191638fd1498Szrj {
191738fd1498Szrj int align = MIN (BIGGEST_ALIGNMENT, LONG_TYPE_SIZE);
191838fd1498Szrj switch_to_section (data_section);
191938fd1498Szrj ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));
192038fd1498Szrj targetm.asm_out.internal_label (file, "LP", current_function_funcdef_no);
192138fd1498Szrj assemble_integer (const0_rtx, LONG_TYPE_SIZE / BITS_PER_UNIT, align, 1);
192238fd1498Szrj }
192338fd1498Szrj
192438fd1498Szrj switch_to_section (current_function_section ());
192538fd1498Szrj
192638fd1498Szrj #ifdef ASM_OUTPUT_REG_PUSH
192738fd1498Szrj if (sval && REG_P (sval))
192838fd1498Szrj ASM_OUTPUT_REG_PUSH (file, REGNO (sval));
192938fd1498Szrj if (chain && REG_P (chain))
193038fd1498Szrj ASM_OUTPUT_REG_PUSH (file, REGNO (chain));
193138fd1498Szrj #endif
193238fd1498Szrj
193338fd1498Szrj FUNCTION_PROFILER (file, current_function_funcdef_no);
193438fd1498Szrj
193538fd1498Szrj #ifdef ASM_OUTPUT_REG_PUSH
193638fd1498Szrj if (chain && REG_P (chain))
193738fd1498Szrj ASM_OUTPUT_REG_POP (file, REGNO (chain));
193838fd1498Szrj if (sval && REG_P (sval))
193938fd1498Szrj ASM_OUTPUT_REG_POP (file, REGNO (sval));
194038fd1498Szrj #endif
194138fd1498Szrj }
194238fd1498Szrj
194338fd1498Szrj /* Output assembler code for the end of a function.
194438fd1498Szrj For clarity, args are same as those of `final_start_function'
194538fd1498Szrj even though not all of them are needed. */
194638fd1498Szrj
194738fd1498Szrj void
final_end_function(void)194838fd1498Szrj final_end_function (void)
194938fd1498Szrj {
195038fd1498Szrj app_disable ();
195138fd1498Szrj
195238fd1498Szrj if (!DECL_IGNORED_P (current_function_decl))
195338fd1498Szrj debug_hooks->end_function (high_function_linenum);
195438fd1498Szrj
195538fd1498Szrj /* Finally, output the function epilogue:
195638fd1498Szrj code to restore the stack frame and return to the caller. */
195738fd1498Szrj targetm.asm_out.function_epilogue (asm_out_file);
195838fd1498Szrj
195938fd1498Szrj /* And debug output. */
196038fd1498Szrj if (!DECL_IGNORED_P (current_function_decl))
196138fd1498Szrj debug_hooks->end_epilogue (last_linenum, last_filename);
196238fd1498Szrj
196338fd1498Szrj if (!dwarf2_debug_info_emitted_p (current_function_decl)
196438fd1498Szrj && dwarf2out_do_frame ())
196538fd1498Szrj dwarf2out_end_epilogue (last_linenum, last_filename);
196638fd1498Szrj
196738fd1498Szrj some_local_dynamic_name = 0;
196838fd1498Szrj }
196938fd1498Szrj
197038fd1498Szrj
197138fd1498Szrj /* Dumper helper for basic block information. FILE is the assembly
197238fd1498Szrj output file, and INSN is the instruction being emitted. */
197338fd1498Szrj
197438fd1498Szrj static void
dump_basic_block_info(FILE * file,rtx_insn * insn,basic_block * start_to_bb,basic_block * end_to_bb,int bb_map_size,int * bb_seqn)197538fd1498Szrj dump_basic_block_info (FILE *file, rtx_insn *insn, basic_block *start_to_bb,
197638fd1498Szrj basic_block *end_to_bb, int bb_map_size, int *bb_seqn)
197738fd1498Szrj {
197838fd1498Szrj basic_block bb;
197938fd1498Szrj
198038fd1498Szrj if (!flag_debug_asm)
198138fd1498Szrj return;
198238fd1498Szrj
198338fd1498Szrj if (INSN_UID (insn) < bb_map_size
198438fd1498Szrj && (bb = start_to_bb[INSN_UID (insn)]) != NULL)
198538fd1498Szrj {
198638fd1498Szrj edge e;
198738fd1498Szrj edge_iterator ei;
198838fd1498Szrj
198938fd1498Szrj fprintf (file, "%s BLOCK %d", ASM_COMMENT_START, bb->index);
199038fd1498Szrj if (bb->count.initialized_p ())
199138fd1498Szrj {
199238fd1498Szrj fprintf (file, ", count:");
199338fd1498Szrj bb->count.dump (file);
199438fd1498Szrj }
199538fd1498Szrj fprintf (file, " seq:%d", (*bb_seqn)++);
199638fd1498Szrj fprintf (file, "\n%s PRED:", ASM_COMMENT_START);
199738fd1498Szrj FOR_EACH_EDGE (e, ei, bb->preds)
199838fd1498Szrj {
199938fd1498Szrj dump_edge_info (file, e, TDF_DETAILS, 0);
200038fd1498Szrj }
200138fd1498Szrj fprintf (file, "\n");
200238fd1498Szrj }
200338fd1498Szrj if (INSN_UID (insn) < bb_map_size
200438fd1498Szrj && (bb = end_to_bb[INSN_UID (insn)]) != NULL)
200538fd1498Szrj {
200638fd1498Szrj edge e;
200738fd1498Szrj edge_iterator ei;
200838fd1498Szrj
200938fd1498Szrj fprintf (asm_out_file, "%s SUCC:", ASM_COMMENT_START);
201038fd1498Szrj FOR_EACH_EDGE (e, ei, bb->succs)
201138fd1498Szrj {
201238fd1498Szrj dump_edge_info (asm_out_file, e, TDF_DETAILS, 1);
201338fd1498Szrj }
201438fd1498Szrj fprintf (file, "\n");
201538fd1498Szrj }
201638fd1498Szrj }
201738fd1498Szrj
201838fd1498Szrj /* Output assembler code for some insns: all or part of a function.
201938fd1498Szrj For description of args, see `final_start_function', above. */
202038fd1498Szrj
202138fd1498Szrj static void
final_1(rtx_insn * first,FILE * file,int seen,int optimize_p)202238fd1498Szrj final_1 (rtx_insn *first, FILE *file, int seen, int optimize_p)
202338fd1498Szrj {
202438fd1498Szrj rtx_insn *insn, *next;
202538fd1498Szrj
202638fd1498Szrj /* Used for -dA dump. */
202738fd1498Szrj basic_block *start_to_bb = NULL;
202838fd1498Szrj basic_block *end_to_bb = NULL;
202938fd1498Szrj int bb_map_size = 0;
203038fd1498Szrj int bb_seqn = 0;
203138fd1498Szrj
203238fd1498Szrj last_ignored_compare = 0;
203338fd1498Szrj
203438fd1498Szrj if (HAVE_cc0)
203538fd1498Szrj for (insn = first; insn; insn = NEXT_INSN (insn))
203638fd1498Szrj {
203738fd1498Szrj /* If CC tracking across branches is enabled, record the insn which
203838fd1498Szrj jumps to each branch only reached from one place. */
203938fd1498Szrj if (optimize_p && JUMP_P (insn))
204038fd1498Szrj {
204138fd1498Szrj rtx lab = JUMP_LABEL (insn);
204238fd1498Szrj if (lab && LABEL_P (lab) && LABEL_NUSES (lab) == 1)
204338fd1498Szrj {
204438fd1498Szrj LABEL_REFS (lab) = insn;
204538fd1498Szrj }
204638fd1498Szrj }
204738fd1498Szrj }
204838fd1498Szrj
204938fd1498Szrj init_recog ();
205038fd1498Szrj
205138fd1498Szrj CC_STATUS_INIT;
205238fd1498Szrj
205338fd1498Szrj if (flag_debug_asm)
205438fd1498Szrj {
205538fd1498Szrj basic_block bb;
205638fd1498Szrj
205738fd1498Szrj bb_map_size = get_max_uid () + 1;
205838fd1498Szrj start_to_bb = XCNEWVEC (basic_block, bb_map_size);
205938fd1498Szrj end_to_bb = XCNEWVEC (basic_block, bb_map_size);
206038fd1498Szrj
206138fd1498Szrj /* There is no cfg for a thunk. */
206238fd1498Szrj if (!cfun->is_thunk)
206338fd1498Szrj FOR_EACH_BB_REVERSE_FN (bb, cfun)
206438fd1498Szrj {
206538fd1498Szrj start_to_bb[INSN_UID (BB_HEAD (bb))] = bb;
206638fd1498Szrj end_to_bb[INSN_UID (BB_END (bb))] = bb;
206738fd1498Szrj }
206838fd1498Szrj }
206938fd1498Szrj
207038fd1498Szrj /* Output the insns. */
207138fd1498Szrj for (insn = first; insn;)
207238fd1498Szrj {
207338fd1498Szrj if (HAVE_ATTR_length)
207438fd1498Szrj {
207538fd1498Szrj if ((unsigned) INSN_UID (insn) >= INSN_ADDRESSES_SIZE ())
207638fd1498Szrj {
207738fd1498Szrj /* This can be triggered by bugs elsewhere in the compiler if
207838fd1498Szrj new insns are created after init_insn_lengths is called. */
207938fd1498Szrj gcc_assert (NOTE_P (insn));
208038fd1498Szrj insn_current_address = -1;
208138fd1498Szrj }
208238fd1498Szrj else
208338fd1498Szrj insn_current_address = INSN_ADDRESSES (INSN_UID (insn));
208438fd1498Szrj /* final can be seen as an iteration of shorten_branches that
208538fd1498Szrj does nothing (since a fixed point has already been reached). */
208638fd1498Szrj insn_last_address = insn_current_address;
208738fd1498Szrj }
208838fd1498Szrj
208938fd1498Szrj dump_basic_block_info (file, insn, start_to_bb, end_to_bb,
209038fd1498Szrj bb_map_size, &bb_seqn);
209138fd1498Szrj insn = final_scan_insn (insn, file, optimize_p, 0, &seen);
209238fd1498Szrj }
209338fd1498Szrj
209438fd1498Szrj maybe_output_next_view (&seen);
209538fd1498Szrj
209638fd1498Szrj if (flag_debug_asm)
209738fd1498Szrj {
209838fd1498Szrj free (start_to_bb);
209938fd1498Szrj free (end_to_bb);
210038fd1498Szrj }
210138fd1498Szrj
210238fd1498Szrj /* Remove CFI notes, to avoid compare-debug failures. */
210338fd1498Szrj for (insn = first; insn; insn = next)
210438fd1498Szrj {
210538fd1498Szrj next = NEXT_INSN (insn);
210638fd1498Szrj if (NOTE_P (insn)
210738fd1498Szrj && (NOTE_KIND (insn) == NOTE_INSN_CFI
210838fd1498Szrj || NOTE_KIND (insn) == NOTE_INSN_CFI_LABEL))
210938fd1498Szrj delete_insn (insn);
211038fd1498Szrj }
211138fd1498Szrj }
211238fd1498Szrj
211338fd1498Szrj /* This is an exported final_1, callable without SEEN. */
211438fd1498Szrj
211538fd1498Szrj void
final(rtx_insn * first,FILE * file,int optimize_p)211638fd1498Szrj final (rtx_insn *first, FILE *file, int optimize_p)
211738fd1498Szrj {
211838fd1498Szrj /* Those that use the internal final_start_function_1/final_1 API
211938fd1498Szrj skip initial debug bind notes in final_start_function_1, and pass
212038fd1498Szrj the modified FIRST to final_1. But those that use the public
212138fd1498Szrj final_start_function/final APIs, final_start_function can't move
212238fd1498Szrj FIRST because it's not passed by reference, so if they were
212338fd1498Szrj skipped there, skip them again here. */
212438fd1498Szrj while (in_initial_view_p (first))
212538fd1498Szrj first = NEXT_INSN (first);
212638fd1498Szrj
212738fd1498Szrj final_1 (first, file, 0, optimize_p);
212838fd1498Szrj }
212938fd1498Szrj
213038fd1498Szrj const char *
get_insn_template(int code,rtx insn)213138fd1498Szrj get_insn_template (int code, rtx insn)
213238fd1498Szrj {
213338fd1498Szrj switch (insn_data[code].output_format)
213438fd1498Szrj {
213538fd1498Szrj case INSN_OUTPUT_FORMAT_SINGLE:
213638fd1498Szrj return insn_data[code].output.single;
213738fd1498Szrj case INSN_OUTPUT_FORMAT_MULTI:
213838fd1498Szrj return insn_data[code].output.multi[which_alternative];
213938fd1498Szrj case INSN_OUTPUT_FORMAT_FUNCTION:
214038fd1498Szrj gcc_assert (insn);
214138fd1498Szrj return (*insn_data[code].output.function) (recog_data.operand,
214238fd1498Szrj as_a <rtx_insn *> (insn));
214338fd1498Szrj
214438fd1498Szrj default:
214538fd1498Szrj gcc_unreachable ();
214638fd1498Szrj }
214738fd1498Szrj }
214838fd1498Szrj
214938fd1498Szrj /* Emit the appropriate declaration for an alternate-entry-point
215038fd1498Szrj symbol represented by INSN, to FILE. INSN is a CODE_LABEL with
215138fd1498Szrj LABEL_KIND != LABEL_NORMAL.
215238fd1498Szrj
215338fd1498Szrj The case fall-through in this function is intentional. */
215438fd1498Szrj static void
output_alternate_entry_point(FILE * file,rtx_insn * insn)215538fd1498Szrj output_alternate_entry_point (FILE *file, rtx_insn *insn)
215638fd1498Szrj {
215738fd1498Szrj const char *name = LABEL_NAME (insn);
215838fd1498Szrj
215938fd1498Szrj switch (LABEL_KIND (insn))
216038fd1498Szrj {
216138fd1498Szrj case LABEL_WEAK_ENTRY:
216238fd1498Szrj #ifdef ASM_WEAKEN_LABEL
216338fd1498Szrj ASM_WEAKEN_LABEL (file, name);
216438fd1498Szrj gcc_fallthrough ();
216538fd1498Szrj #endif
216638fd1498Szrj case LABEL_GLOBAL_ENTRY:
216738fd1498Szrj targetm.asm_out.globalize_label (file, name);
216838fd1498Szrj gcc_fallthrough ();
216938fd1498Szrj case LABEL_STATIC_ENTRY:
217038fd1498Szrj #ifdef ASM_OUTPUT_TYPE_DIRECTIVE
217138fd1498Szrj ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function");
217238fd1498Szrj #endif
217338fd1498Szrj ASM_OUTPUT_LABEL (file, name);
217438fd1498Szrj break;
217538fd1498Szrj
217638fd1498Szrj case LABEL_NORMAL:
217738fd1498Szrj default:
217838fd1498Szrj gcc_unreachable ();
217938fd1498Szrj }
218038fd1498Szrj }
218138fd1498Szrj
218238fd1498Szrj /* Given a CALL_INSN, find and return the nested CALL. */
218338fd1498Szrj static rtx
call_from_call_insn(rtx_call_insn * insn)218438fd1498Szrj call_from_call_insn (rtx_call_insn *insn)
218538fd1498Szrj {
218638fd1498Szrj rtx x;
218738fd1498Szrj gcc_assert (CALL_P (insn));
218838fd1498Szrj x = PATTERN (insn);
218938fd1498Szrj
219038fd1498Szrj while (GET_CODE (x) != CALL)
219138fd1498Szrj {
219238fd1498Szrj switch (GET_CODE (x))
219338fd1498Szrj {
219438fd1498Szrj default:
219538fd1498Szrj gcc_unreachable ();
219638fd1498Szrj case COND_EXEC:
219738fd1498Szrj x = COND_EXEC_CODE (x);
219838fd1498Szrj break;
219938fd1498Szrj case PARALLEL:
220038fd1498Szrj x = XVECEXP (x, 0, 0);
220138fd1498Szrj break;
220238fd1498Szrj case SET:
220338fd1498Szrj x = XEXP (x, 1);
220438fd1498Szrj break;
220538fd1498Szrj }
220638fd1498Szrj }
220738fd1498Szrj return x;
220838fd1498Szrj }
220938fd1498Szrj
221038fd1498Szrj /* Print a comment into the asm showing FILENAME, LINENUM, and the
221138fd1498Szrj corresponding source line, if available. */
221238fd1498Szrj
221338fd1498Szrj static void
asm_show_source(const char * filename,int linenum)221438fd1498Szrj asm_show_source (const char *filename, int linenum)
221538fd1498Szrj {
221638fd1498Szrj if (!filename)
221738fd1498Szrj return;
221838fd1498Szrj
221938fd1498Szrj int line_size;
222038fd1498Szrj const char *line = location_get_source_line (filename, linenum, &line_size);
222138fd1498Szrj if (!line)
222238fd1498Szrj return;
222338fd1498Szrj
222438fd1498Szrj fprintf (asm_out_file, "%s %s:%i: ", ASM_COMMENT_START, filename, linenum);
222538fd1498Szrj /* "line" is not 0-terminated, so we must use line_size. */
222638fd1498Szrj fwrite (line, 1, line_size, asm_out_file);
222738fd1498Szrj fputc ('\n', asm_out_file);
222838fd1498Szrj }
222938fd1498Szrj
223038fd1498Szrj /* The final scan for one insn, INSN.
223138fd1498Szrj Args are same as in `final', except that INSN
223238fd1498Szrj is the insn being scanned.
223338fd1498Szrj Value returned is the next insn to be scanned.
223438fd1498Szrj
223538fd1498Szrj NOPEEPHOLES is the flag to disallow peephole processing (currently
223638fd1498Szrj used for within delayed branch sequence output).
223738fd1498Szrj
223838fd1498Szrj SEEN is used to track the end of the prologue, for emitting
223938fd1498Szrj debug information. We force the emission of a line note after
224038fd1498Szrj both NOTE_INSN_PROLOGUE_END and NOTE_INSN_FUNCTION_BEG. */
224138fd1498Szrj
224238fd1498Szrj static rtx_insn *
final_scan_insn_1(rtx_insn * insn,FILE * file,int optimize_p ATTRIBUTE_UNUSED,int nopeepholes ATTRIBUTE_UNUSED,int * seen)224338fd1498Szrj final_scan_insn_1 (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
224438fd1498Szrj int nopeepholes ATTRIBUTE_UNUSED, int *seen)
224538fd1498Szrj {
224638fd1498Szrj #if HAVE_cc0
224738fd1498Szrj rtx set;
224838fd1498Szrj #endif
224938fd1498Szrj rtx_insn *next;
225038fd1498Szrj rtx_jump_table_data *table;
225138fd1498Szrj
225238fd1498Szrj insn_counter++;
225338fd1498Szrj
225438fd1498Szrj /* Ignore deleted insns. These can occur when we split insns (due to a
225538fd1498Szrj template of "#") while not optimizing. */
225638fd1498Szrj if (insn->deleted ())
225738fd1498Szrj return NEXT_INSN (insn);
225838fd1498Szrj
225938fd1498Szrj switch (GET_CODE (insn))
226038fd1498Szrj {
226138fd1498Szrj case NOTE:
226238fd1498Szrj switch (NOTE_KIND (insn))
226338fd1498Szrj {
226438fd1498Szrj case NOTE_INSN_DELETED:
226538fd1498Szrj case NOTE_INSN_UPDATE_SJLJ_CONTEXT:
226638fd1498Szrj break;
226738fd1498Szrj
226838fd1498Szrj case NOTE_INSN_SWITCH_TEXT_SECTIONS:
226938fd1498Szrj maybe_output_next_view (seen);
227038fd1498Szrj
227138fd1498Szrj output_function_exception_table (0);
227238fd1498Szrj
227338fd1498Szrj if (targetm.asm_out.unwind_emit)
227438fd1498Szrj targetm.asm_out.unwind_emit (asm_out_file, insn);
227538fd1498Szrj
227638fd1498Szrj in_cold_section_p = !in_cold_section_p;
227738fd1498Szrj
227838fd1498Szrj if (in_cold_section_p)
227938fd1498Szrj cold_function_name
228038fd1498Szrj = clone_function_name (current_function_decl, "cold");
228138fd1498Szrj
228238fd1498Szrj if (dwarf2out_do_frame ())
228338fd1498Szrj {
228438fd1498Szrj dwarf2out_switch_text_section ();
228538fd1498Szrj if (!dwarf2_debug_info_emitted_p (current_function_decl)
228638fd1498Szrj && !DECL_IGNORED_P (current_function_decl))
228738fd1498Szrj debug_hooks->switch_text_section ();
228838fd1498Szrj }
228938fd1498Szrj else if (!DECL_IGNORED_P (current_function_decl))
229038fd1498Szrj debug_hooks->switch_text_section ();
229138fd1498Szrj
229238fd1498Szrj switch_to_section (current_function_section ());
229338fd1498Szrj targetm.asm_out.function_switched_text_sections (asm_out_file,
229438fd1498Szrj current_function_decl,
229538fd1498Szrj in_cold_section_p);
229638fd1498Szrj /* Emit a label for the split cold section. Form label name by
229738fd1498Szrj suffixing "cold" to the original function's name. */
229838fd1498Szrj if (in_cold_section_p)
229938fd1498Szrj {
230038fd1498Szrj #ifdef ASM_DECLARE_COLD_FUNCTION_NAME
230138fd1498Szrj ASM_DECLARE_COLD_FUNCTION_NAME (asm_out_file,
230238fd1498Szrj IDENTIFIER_POINTER
230338fd1498Szrj (cold_function_name),
230438fd1498Szrj current_function_decl);
230538fd1498Szrj #else
230638fd1498Szrj ASM_OUTPUT_LABEL (asm_out_file,
230738fd1498Szrj IDENTIFIER_POINTER (cold_function_name));
230838fd1498Szrj #endif
2309*58e805e6Szrj if (dwarf2out_do_frame ()
2310*58e805e6Szrj && cfun->fde->dw_fde_second_begin != NULL)
2311*58e805e6Szrj ASM_OUTPUT_LABEL (asm_out_file, cfun->fde->dw_fde_second_begin);
231238fd1498Szrj }
231338fd1498Szrj break;
231438fd1498Szrj
231538fd1498Szrj case NOTE_INSN_BASIC_BLOCK:
231638fd1498Szrj if (need_profile_function)
231738fd1498Szrj {
231838fd1498Szrj profile_function (asm_out_file);
231938fd1498Szrj need_profile_function = false;
232038fd1498Szrj }
232138fd1498Szrj
232238fd1498Szrj if (targetm.asm_out.unwind_emit)
232338fd1498Szrj targetm.asm_out.unwind_emit (asm_out_file, insn);
232438fd1498Szrj
232538fd1498Szrj discriminator = NOTE_BASIC_BLOCK (insn)->discriminator;
232638fd1498Szrj
232738fd1498Szrj break;
232838fd1498Szrj
232938fd1498Szrj case NOTE_INSN_EH_REGION_BEG:
233038fd1498Szrj ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LEHB",
233138fd1498Szrj NOTE_EH_HANDLER (insn));
233238fd1498Szrj break;
233338fd1498Szrj
233438fd1498Szrj case NOTE_INSN_EH_REGION_END:
233538fd1498Szrj ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LEHE",
233638fd1498Szrj NOTE_EH_HANDLER (insn));
233738fd1498Szrj break;
233838fd1498Szrj
233938fd1498Szrj case NOTE_INSN_PROLOGUE_END:
234038fd1498Szrj targetm.asm_out.function_end_prologue (file);
234138fd1498Szrj profile_after_prologue (file);
234238fd1498Szrj
234338fd1498Szrj if ((*seen & (SEEN_EMITTED | SEEN_NOTE)) == SEEN_NOTE)
234438fd1498Szrj {
234538fd1498Szrj *seen |= SEEN_EMITTED;
234638fd1498Szrj force_source_line = true;
234738fd1498Szrj }
234838fd1498Szrj else
234938fd1498Szrj *seen |= SEEN_NOTE;
235038fd1498Szrj
235138fd1498Szrj break;
235238fd1498Szrj
235338fd1498Szrj case NOTE_INSN_EPILOGUE_BEG:
235438fd1498Szrj if (!DECL_IGNORED_P (current_function_decl))
235538fd1498Szrj (*debug_hooks->begin_epilogue) (last_linenum, last_filename);
235638fd1498Szrj targetm.asm_out.function_begin_epilogue (file);
235738fd1498Szrj break;
235838fd1498Szrj
235938fd1498Szrj case NOTE_INSN_CFI:
236038fd1498Szrj dwarf2out_emit_cfi (NOTE_CFI (insn));
236138fd1498Szrj break;
236238fd1498Szrj
236338fd1498Szrj case NOTE_INSN_CFI_LABEL:
236438fd1498Szrj ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LCFI",
236538fd1498Szrj NOTE_LABEL_NUMBER (insn));
236638fd1498Szrj break;
236738fd1498Szrj
236838fd1498Szrj case NOTE_INSN_FUNCTION_BEG:
236938fd1498Szrj if (need_profile_function)
237038fd1498Szrj {
237138fd1498Szrj profile_function (asm_out_file);
237238fd1498Szrj need_profile_function = false;
237338fd1498Szrj }
237438fd1498Szrj
237538fd1498Szrj app_disable ();
237638fd1498Szrj if (!DECL_IGNORED_P (current_function_decl))
237738fd1498Szrj debug_hooks->end_prologue (last_linenum, last_filename);
237838fd1498Szrj
237938fd1498Szrj if ((*seen & (SEEN_EMITTED | SEEN_NOTE)) == SEEN_NOTE)
238038fd1498Szrj {
238138fd1498Szrj *seen |= SEEN_EMITTED;
238238fd1498Szrj force_source_line = true;
238338fd1498Szrj }
238438fd1498Szrj else
238538fd1498Szrj *seen |= SEEN_NOTE;
238638fd1498Szrj
238738fd1498Szrj break;
238838fd1498Szrj
238938fd1498Szrj case NOTE_INSN_BLOCK_BEG:
239038fd1498Szrj if (debug_info_level == DINFO_LEVEL_NORMAL
239138fd1498Szrj || debug_info_level == DINFO_LEVEL_VERBOSE
239238fd1498Szrj || write_symbols == DWARF2_DEBUG
239338fd1498Szrj || write_symbols == VMS_AND_DWARF2_DEBUG
239438fd1498Szrj || write_symbols == VMS_DEBUG)
239538fd1498Szrj {
239638fd1498Szrj int n = BLOCK_NUMBER (NOTE_BLOCK (insn));
239738fd1498Szrj
239838fd1498Szrj app_disable ();
239938fd1498Szrj ++block_depth;
240038fd1498Szrj high_block_linenum = last_linenum;
240138fd1498Szrj
240238fd1498Szrj /* Output debugging info about the symbol-block beginning. */
240338fd1498Szrj if (!DECL_IGNORED_P (current_function_decl))
240438fd1498Szrj debug_hooks->begin_block (last_linenum, n);
240538fd1498Szrj
240638fd1498Szrj /* Mark this block as output. */
240738fd1498Szrj TREE_ASM_WRITTEN (NOTE_BLOCK (insn)) = 1;
240838fd1498Szrj BLOCK_IN_COLD_SECTION_P (NOTE_BLOCK (insn)) = in_cold_section_p;
240938fd1498Szrj }
241038fd1498Szrj if (write_symbols == DBX_DEBUG)
241138fd1498Szrj {
241238fd1498Szrj location_t *locus_ptr
241338fd1498Szrj = block_nonartificial_location (NOTE_BLOCK (insn));
241438fd1498Szrj
241538fd1498Szrj if (locus_ptr != NULL)
241638fd1498Szrj {
241738fd1498Szrj override_filename = LOCATION_FILE (*locus_ptr);
241838fd1498Szrj override_linenum = LOCATION_LINE (*locus_ptr);
241938fd1498Szrj override_columnnum = LOCATION_COLUMN (*locus_ptr);
242038fd1498Szrj }
242138fd1498Szrj }
242238fd1498Szrj break;
242338fd1498Szrj
242438fd1498Szrj case NOTE_INSN_BLOCK_END:
242538fd1498Szrj maybe_output_next_view (seen);
242638fd1498Szrj
242738fd1498Szrj if (debug_info_level == DINFO_LEVEL_NORMAL
242838fd1498Szrj || debug_info_level == DINFO_LEVEL_VERBOSE
242938fd1498Szrj || write_symbols == DWARF2_DEBUG
243038fd1498Szrj || write_symbols == VMS_AND_DWARF2_DEBUG
243138fd1498Szrj || write_symbols == VMS_DEBUG)
243238fd1498Szrj {
243338fd1498Szrj int n = BLOCK_NUMBER (NOTE_BLOCK (insn));
243438fd1498Szrj
243538fd1498Szrj app_disable ();
243638fd1498Szrj
243738fd1498Szrj /* End of a symbol-block. */
243838fd1498Szrj --block_depth;
243938fd1498Szrj gcc_assert (block_depth >= 0);
244038fd1498Szrj
244138fd1498Szrj if (!DECL_IGNORED_P (current_function_decl))
244238fd1498Szrj debug_hooks->end_block (high_block_linenum, n);
244338fd1498Szrj gcc_assert (BLOCK_IN_COLD_SECTION_P (NOTE_BLOCK (insn))
244438fd1498Szrj == in_cold_section_p);
244538fd1498Szrj }
244638fd1498Szrj if (write_symbols == DBX_DEBUG)
244738fd1498Szrj {
244838fd1498Szrj tree outer_block = BLOCK_SUPERCONTEXT (NOTE_BLOCK (insn));
244938fd1498Szrj location_t *locus_ptr
245038fd1498Szrj = block_nonartificial_location (outer_block);
245138fd1498Szrj
245238fd1498Szrj if (locus_ptr != NULL)
245338fd1498Szrj {
245438fd1498Szrj override_filename = LOCATION_FILE (*locus_ptr);
245538fd1498Szrj override_linenum = LOCATION_LINE (*locus_ptr);
245638fd1498Szrj override_columnnum = LOCATION_COLUMN (*locus_ptr);
245738fd1498Szrj }
245838fd1498Szrj else
245938fd1498Szrj {
246038fd1498Szrj override_filename = NULL;
246138fd1498Szrj override_linenum = 0;
246238fd1498Szrj override_columnnum = 0;
246338fd1498Szrj }
246438fd1498Szrj }
246538fd1498Szrj break;
246638fd1498Szrj
246738fd1498Szrj case NOTE_INSN_DELETED_LABEL:
246838fd1498Szrj /* Emit the label. We may have deleted the CODE_LABEL because
246938fd1498Szrj the label could be proved to be unreachable, though still
247038fd1498Szrj referenced (in the form of having its address taken. */
247138fd1498Szrj ASM_OUTPUT_DEBUG_LABEL (file, "L", CODE_LABEL_NUMBER (insn));
247238fd1498Szrj break;
247338fd1498Szrj
247438fd1498Szrj case NOTE_INSN_DELETED_DEBUG_LABEL:
247538fd1498Szrj /* Similarly, but need to use different namespace for it. */
247638fd1498Szrj if (CODE_LABEL_NUMBER (insn) != -1)
247738fd1498Szrj ASM_OUTPUT_DEBUG_LABEL (file, "LDL", CODE_LABEL_NUMBER (insn));
247838fd1498Szrj break;
247938fd1498Szrj
248038fd1498Szrj case NOTE_INSN_VAR_LOCATION:
248138fd1498Szrj if (!DECL_IGNORED_P (current_function_decl))
248238fd1498Szrj {
248338fd1498Szrj debug_hooks->var_location (insn);
248438fd1498Szrj set_next_view_needed (seen);
248538fd1498Szrj }
248638fd1498Szrj break;
248738fd1498Szrj
248838fd1498Szrj case NOTE_INSN_BEGIN_STMT:
248938fd1498Szrj gcc_checking_assert (cfun->debug_nonbind_markers);
249038fd1498Szrj if (!DECL_IGNORED_P (current_function_decl)
249138fd1498Szrj && notice_source_line (insn, NULL))
249238fd1498Szrj {
249338fd1498Szrj output_source_line:
249438fd1498Szrj (*debug_hooks->source_line) (last_linenum, last_columnnum,
249538fd1498Szrj last_filename, last_discriminator,
249638fd1498Szrj true);
249738fd1498Szrj clear_next_view_needed (seen);
249838fd1498Szrj }
249938fd1498Szrj break;
250038fd1498Szrj
250138fd1498Szrj case NOTE_INSN_INLINE_ENTRY:
250238fd1498Szrj gcc_checking_assert (cfun->debug_nonbind_markers);
250338fd1498Szrj if (!DECL_IGNORED_P (current_function_decl))
250438fd1498Szrj {
250538fd1498Szrj if (!notice_source_line (insn, NULL))
250638fd1498Szrj break;
250738fd1498Szrj (*debug_hooks->inline_entry) (LOCATION_BLOCK
250838fd1498Szrj (NOTE_MARKER_LOCATION (insn)));
250938fd1498Szrj goto output_source_line;
251038fd1498Szrj }
251138fd1498Szrj break;
251238fd1498Szrj
251338fd1498Szrj default:
251438fd1498Szrj gcc_unreachable ();
251538fd1498Szrj break;
251638fd1498Szrj }
251738fd1498Szrj break;
251838fd1498Szrj
251938fd1498Szrj case BARRIER:
252038fd1498Szrj break;
252138fd1498Szrj
252238fd1498Szrj case CODE_LABEL:
252338fd1498Szrj /* The target port might emit labels in the output function for
252438fd1498Szrj some insn, e.g. sh.c output_branchy_insn. */
252538fd1498Szrj if (CODE_LABEL_NUMBER (insn) <= max_labelno)
252638fd1498Szrj {
252738fd1498Szrj int align = LABEL_TO_ALIGNMENT (insn);
252838fd1498Szrj #ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
252938fd1498Szrj int max_skip = LABEL_TO_MAX_SKIP (insn);
253038fd1498Szrj #endif
253138fd1498Szrj
253238fd1498Szrj if (align && NEXT_INSN (insn))
253338fd1498Szrj {
253438fd1498Szrj #ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
253538fd1498Szrj ASM_OUTPUT_MAX_SKIP_ALIGN (file, align, max_skip);
253638fd1498Szrj #else
253738fd1498Szrj #ifdef ASM_OUTPUT_ALIGN_WITH_NOP
253838fd1498Szrj ASM_OUTPUT_ALIGN_WITH_NOP (file, align);
253938fd1498Szrj #else
254038fd1498Szrj ASM_OUTPUT_ALIGN (file, align);
254138fd1498Szrj #endif
254238fd1498Szrj #endif
254338fd1498Szrj }
254438fd1498Szrj }
254538fd1498Szrj CC_STATUS_INIT;
254638fd1498Szrj
254738fd1498Szrj if (!DECL_IGNORED_P (current_function_decl) && LABEL_NAME (insn))
254838fd1498Szrj debug_hooks->label (as_a <rtx_code_label *> (insn));
254938fd1498Szrj
255038fd1498Szrj app_disable ();
255138fd1498Szrj
255238fd1498Szrj /* If this label is followed by a jump-table, make sure we put
255338fd1498Szrj the label in the read-only section. Also possibly write the
255438fd1498Szrj label and jump table together. */
255538fd1498Szrj table = jump_table_for_label (as_a <rtx_code_label *> (insn));
255638fd1498Szrj if (table)
255738fd1498Szrj {
255838fd1498Szrj #if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC)
255938fd1498Szrj /* In this case, the case vector is being moved by the
256038fd1498Szrj target, so don't output the label at all. Leave that
256138fd1498Szrj to the back end macros. */
256238fd1498Szrj #else
256338fd1498Szrj if (! JUMP_TABLES_IN_TEXT_SECTION)
256438fd1498Szrj {
256538fd1498Szrj int log_align;
256638fd1498Szrj
256738fd1498Szrj switch_to_section (targetm.asm_out.function_rodata_section
256838fd1498Szrj (current_function_decl));
256938fd1498Szrj
257038fd1498Szrj #ifdef ADDR_VEC_ALIGN
257138fd1498Szrj log_align = ADDR_VEC_ALIGN (table);
257238fd1498Szrj #else
257338fd1498Szrj log_align = exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT);
257438fd1498Szrj #endif
257538fd1498Szrj ASM_OUTPUT_ALIGN (file, log_align);
257638fd1498Szrj }
257738fd1498Szrj else
257838fd1498Szrj switch_to_section (current_function_section ());
257938fd1498Szrj
258038fd1498Szrj #ifdef ASM_OUTPUT_CASE_LABEL
258138fd1498Szrj ASM_OUTPUT_CASE_LABEL (file, "L", CODE_LABEL_NUMBER (insn), table);
258238fd1498Szrj #else
258338fd1498Szrj targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (insn));
258438fd1498Szrj #endif
258538fd1498Szrj #endif
258638fd1498Szrj break;
258738fd1498Szrj }
258838fd1498Szrj if (LABEL_ALT_ENTRY_P (insn))
258938fd1498Szrj output_alternate_entry_point (file, insn);
259038fd1498Szrj else
259138fd1498Szrj targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (insn));
259238fd1498Szrj break;
259338fd1498Szrj
259438fd1498Szrj default:
259538fd1498Szrj {
259638fd1498Szrj rtx body = PATTERN (insn);
259738fd1498Szrj int insn_code_number;
259838fd1498Szrj const char *templ;
259938fd1498Szrj bool is_stmt, *is_stmt_p;
260038fd1498Szrj
260138fd1498Szrj if (MAY_HAVE_DEBUG_MARKER_INSNS && cfun->debug_nonbind_markers)
260238fd1498Szrj {
260338fd1498Szrj is_stmt = false;
260438fd1498Szrj is_stmt_p = NULL;
260538fd1498Szrj }
260638fd1498Szrj else
260738fd1498Szrj is_stmt_p = &is_stmt;
260838fd1498Szrj
260938fd1498Szrj /* Reset this early so it is correct for ASM statements. */
261038fd1498Szrj current_insn_predicate = NULL_RTX;
261138fd1498Szrj
261238fd1498Szrj /* An INSN, JUMP_INSN or CALL_INSN.
261338fd1498Szrj First check for special kinds that recog doesn't recognize. */
261438fd1498Szrj
261538fd1498Szrj if (GET_CODE (body) == USE /* These are just declarations. */
261638fd1498Szrj || GET_CODE (body) == CLOBBER)
261738fd1498Szrj break;
261838fd1498Szrj
261938fd1498Szrj #if HAVE_cc0
262038fd1498Szrj {
262138fd1498Szrj /* If there is a REG_CC_SETTER note on this insn, it means that
262238fd1498Szrj the setting of the condition code was done in the delay slot
262338fd1498Szrj of the insn that branched here. So recover the cc status
262438fd1498Szrj from the insn that set it. */
262538fd1498Szrj
262638fd1498Szrj rtx note = find_reg_note (insn, REG_CC_SETTER, NULL_RTX);
262738fd1498Szrj if (note)
262838fd1498Szrj {
262938fd1498Szrj rtx_insn *other = as_a <rtx_insn *> (XEXP (note, 0));
263038fd1498Szrj NOTICE_UPDATE_CC (PATTERN (other), other);
263138fd1498Szrj cc_prev_status = cc_status;
263238fd1498Szrj }
263338fd1498Szrj }
263438fd1498Szrj #endif
263538fd1498Szrj
263638fd1498Szrj /* Detect insns that are really jump-tables
263738fd1498Szrj and output them as such. */
263838fd1498Szrj
263938fd1498Szrj if (JUMP_TABLE_DATA_P (insn))
264038fd1498Szrj {
264138fd1498Szrj #if !(defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC))
264238fd1498Szrj int vlen, idx;
264338fd1498Szrj #endif
264438fd1498Szrj
264538fd1498Szrj if (! JUMP_TABLES_IN_TEXT_SECTION)
264638fd1498Szrj switch_to_section (targetm.asm_out.function_rodata_section
264738fd1498Szrj (current_function_decl));
264838fd1498Szrj else
264938fd1498Szrj switch_to_section (current_function_section ());
265038fd1498Szrj
265138fd1498Szrj app_disable ();
265238fd1498Szrj
265338fd1498Szrj #if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC)
265438fd1498Szrj if (GET_CODE (body) == ADDR_VEC)
265538fd1498Szrj {
265638fd1498Szrj #ifdef ASM_OUTPUT_ADDR_VEC
265738fd1498Szrj ASM_OUTPUT_ADDR_VEC (PREV_INSN (insn), body);
265838fd1498Szrj #else
265938fd1498Szrj gcc_unreachable ();
266038fd1498Szrj #endif
266138fd1498Szrj }
266238fd1498Szrj else
266338fd1498Szrj {
266438fd1498Szrj #ifdef ASM_OUTPUT_ADDR_DIFF_VEC
266538fd1498Szrj ASM_OUTPUT_ADDR_DIFF_VEC (PREV_INSN (insn), body);
266638fd1498Szrj #else
266738fd1498Szrj gcc_unreachable ();
266838fd1498Szrj #endif
266938fd1498Szrj }
267038fd1498Szrj #else
267138fd1498Szrj vlen = XVECLEN (body, GET_CODE (body) == ADDR_DIFF_VEC);
267238fd1498Szrj for (idx = 0; idx < vlen; idx++)
267338fd1498Szrj {
267438fd1498Szrj if (GET_CODE (body) == ADDR_VEC)
267538fd1498Szrj {
267638fd1498Szrj #ifdef ASM_OUTPUT_ADDR_VEC_ELT
267738fd1498Szrj ASM_OUTPUT_ADDR_VEC_ELT
267838fd1498Szrj (file, CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 0, idx), 0)));
267938fd1498Szrj #else
268038fd1498Szrj gcc_unreachable ();
268138fd1498Szrj #endif
268238fd1498Szrj }
268338fd1498Szrj else
268438fd1498Szrj {
268538fd1498Szrj #ifdef ASM_OUTPUT_ADDR_DIFF_ELT
268638fd1498Szrj ASM_OUTPUT_ADDR_DIFF_ELT
268738fd1498Szrj (file,
268838fd1498Szrj body,
268938fd1498Szrj CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 1, idx), 0)),
269038fd1498Szrj CODE_LABEL_NUMBER (XEXP (XEXP (body, 0), 0)));
269138fd1498Szrj #else
269238fd1498Szrj gcc_unreachable ();
269338fd1498Szrj #endif
269438fd1498Szrj }
269538fd1498Szrj }
269638fd1498Szrj #ifdef ASM_OUTPUT_CASE_END
269738fd1498Szrj ASM_OUTPUT_CASE_END (file,
269838fd1498Szrj CODE_LABEL_NUMBER (PREV_INSN (insn)),
269938fd1498Szrj insn);
270038fd1498Szrj #endif
270138fd1498Szrj #endif
270238fd1498Szrj
270338fd1498Szrj switch_to_section (current_function_section ());
270438fd1498Szrj
270538fd1498Szrj if (debug_variable_location_views
270638fd1498Szrj && !DECL_IGNORED_P (current_function_decl))
270738fd1498Szrj debug_hooks->var_location (insn);
270838fd1498Szrj
270938fd1498Szrj break;
271038fd1498Szrj }
271138fd1498Szrj /* Output this line note if it is the first or the last line
271238fd1498Szrj note in a row. */
271338fd1498Szrj if (!DECL_IGNORED_P (current_function_decl)
271438fd1498Szrj && notice_source_line (insn, is_stmt_p))
271538fd1498Szrj {
271638fd1498Szrj if (flag_verbose_asm)
271738fd1498Szrj asm_show_source (last_filename, last_linenum);
271838fd1498Szrj (*debug_hooks->source_line) (last_linenum, last_columnnum,
271938fd1498Szrj last_filename, last_discriminator,
272038fd1498Szrj is_stmt);
272138fd1498Szrj clear_next_view_needed (seen);
272238fd1498Szrj }
272338fd1498Szrj else
272438fd1498Szrj maybe_output_next_view (seen);
272538fd1498Szrj
272638fd1498Szrj gcc_checking_assert (!DEBUG_INSN_P (insn));
272738fd1498Szrj
272838fd1498Szrj if (GET_CODE (body) == PARALLEL
272938fd1498Szrj && GET_CODE (XVECEXP (body, 0, 0)) == ASM_INPUT)
273038fd1498Szrj body = XVECEXP (body, 0, 0);
273138fd1498Szrj
273238fd1498Szrj if (GET_CODE (body) == ASM_INPUT)
273338fd1498Szrj {
273438fd1498Szrj const char *string = XSTR (body, 0);
273538fd1498Szrj
273638fd1498Szrj /* There's no telling what that did to the condition codes. */
273738fd1498Szrj CC_STATUS_INIT;
273838fd1498Szrj
273938fd1498Szrj if (string[0])
274038fd1498Szrj {
274138fd1498Szrj expanded_location loc;
274238fd1498Szrj
274338fd1498Szrj app_enable ();
274438fd1498Szrj loc = expand_location (ASM_INPUT_SOURCE_LOCATION (body));
274538fd1498Szrj if (*loc.file && loc.line)
274638fd1498Szrj fprintf (asm_out_file, "%s %i \"%s\" 1\n",
274738fd1498Szrj ASM_COMMENT_START, loc.line, loc.file);
274838fd1498Szrj fprintf (asm_out_file, "\t%s\n", string);
274938fd1498Szrj #if HAVE_AS_LINE_ZERO
275038fd1498Szrj if (*loc.file && loc.line)
275138fd1498Szrj fprintf (asm_out_file, "%s 0 \"\" 2\n", ASM_COMMENT_START);
275238fd1498Szrj #endif
275338fd1498Szrj }
275438fd1498Szrj break;
275538fd1498Szrj }
275638fd1498Szrj
275738fd1498Szrj /* Detect `asm' construct with operands. */
275838fd1498Szrj if (asm_noperands (body) >= 0)
275938fd1498Szrj {
276038fd1498Szrj unsigned int noperands = asm_noperands (body);
276138fd1498Szrj rtx *ops = XALLOCAVEC (rtx, noperands);
276238fd1498Szrj const char *string;
276338fd1498Szrj location_t loc;
276438fd1498Szrj expanded_location expanded;
276538fd1498Szrj
276638fd1498Szrj /* There's no telling what that did to the condition codes. */
276738fd1498Szrj CC_STATUS_INIT;
276838fd1498Szrj
276938fd1498Szrj /* Get out the operand values. */
277038fd1498Szrj string = decode_asm_operands (body, ops, NULL, NULL, NULL, &loc);
277138fd1498Szrj /* Inhibit dying on what would otherwise be compiler bugs. */
277238fd1498Szrj insn_noperands = noperands;
277338fd1498Szrj this_is_asm_operands = insn;
277438fd1498Szrj expanded = expand_location (loc);
277538fd1498Szrj
277638fd1498Szrj #ifdef FINAL_PRESCAN_INSN
277738fd1498Szrj FINAL_PRESCAN_INSN (insn, ops, insn_noperands);
277838fd1498Szrj #endif
277938fd1498Szrj
278038fd1498Szrj /* Output the insn using them. */
278138fd1498Szrj if (string[0])
278238fd1498Szrj {
278338fd1498Szrj app_enable ();
278438fd1498Szrj if (expanded.file && expanded.line)
278538fd1498Szrj fprintf (asm_out_file, "%s %i \"%s\" 1\n",
278638fd1498Szrj ASM_COMMENT_START, expanded.line, expanded.file);
278738fd1498Szrj output_asm_insn (string, ops);
278838fd1498Szrj #if HAVE_AS_LINE_ZERO
278938fd1498Szrj if (expanded.file && expanded.line)
279038fd1498Szrj fprintf (asm_out_file, "%s 0 \"\" 2\n", ASM_COMMENT_START);
279138fd1498Szrj #endif
279238fd1498Szrj }
279338fd1498Szrj
279438fd1498Szrj if (targetm.asm_out.final_postscan_insn)
279538fd1498Szrj targetm.asm_out.final_postscan_insn (file, insn, ops,
279638fd1498Szrj insn_noperands);
279738fd1498Szrj
279838fd1498Szrj this_is_asm_operands = 0;
279938fd1498Szrj break;
280038fd1498Szrj }
280138fd1498Szrj
280238fd1498Szrj app_disable ();
280338fd1498Szrj
280438fd1498Szrj if (rtx_sequence *seq = dyn_cast <rtx_sequence *> (body))
280538fd1498Szrj {
280638fd1498Szrj /* A delayed-branch sequence */
280738fd1498Szrj int i;
280838fd1498Szrj
280938fd1498Szrj final_sequence = seq;
281038fd1498Szrj
281138fd1498Szrj /* The first insn in this SEQUENCE might be a JUMP_INSN that will
281238fd1498Szrj force the restoration of a comparison that was previously
281338fd1498Szrj thought unnecessary. If that happens, cancel this sequence
281438fd1498Szrj and cause that insn to be restored. */
281538fd1498Szrj
281638fd1498Szrj next = final_scan_insn (seq->insn (0), file, 0, 1, seen);
281738fd1498Szrj if (next != seq->insn (1))
281838fd1498Szrj {
281938fd1498Szrj final_sequence = 0;
282038fd1498Szrj return next;
282138fd1498Szrj }
282238fd1498Szrj
282338fd1498Szrj for (i = 1; i < seq->len (); i++)
282438fd1498Szrj {
282538fd1498Szrj rtx_insn *insn = seq->insn (i);
282638fd1498Szrj rtx_insn *next = NEXT_INSN (insn);
282738fd1498Szrj /* We loop in case any instruction in a delay slot gets
282838fd1498Szrj split. */
282938fd1498Szrj do
283038fd1498Szrj insn = final_scan_insn (insn, file, 0, 1, seen);
283138fd1498Szrj while (insn != next);
283238fd1498Szrj }
283338fd1498Szrj #ifdef DBR_OUTPUT_SEQEND
283438fd1498Szrj DBR_OUTPUT_SEQEND (file);
283538fd1498Szrj #endif
283638fd1498Szrj final_sequence = 0;
283738fd1498Szrj
283838fd1498Szrj /* If the insn requiring the delay slot was a CALL_INSN, the
283938fd1498Szrj insns in the delay slot are actually executed before the
284038fd1498Szrj called function. Hence we don't preserve any CC-setting
284138fd1498Szrj actions in these insns and the CC must be marked as being
284238fd1498Szrj clobbered by the function. */
284338fd1498Szrj if (CALL_P (seq->insn (0)))
284438fd1498Szrj {
284538fd1498Szrj CC_STATUS_INIT;
284638fd1498Szrj }
284738fd1498Szrj break;
284838fd1498Szrj }
284938fd1498Szrj
285038fd1498Szrj /* We have a real machine instruction as rtl. */
285138fd1498Szrj
285238fd1498Szrj body = PATTERN (insn);
285338fd1498Szrj
285438fd1498Szrj #if HAVE_cc0
285538fd1498Szrj set = single_set (insn);
285638fd1498Szrj
285738fd1498Szrj /* Check for redundant test and compare instructions
285838fd1498Szrj (when the condition codes are already set up as desired).
285938fd1498Szrj This is done only when optimizing; if not optimizing,
286038fd1498Szrj it should be possible for the user to alter a variable
286138fd1498Szrj with the debugger in between statements
286238fd1498Szrj and the next statement should reexamine the variable
286338fd1498Szrj to compute the condition codes. */
286438fd1498Szrj
286538fd1498Szrj if (optimize_p)
286638fd1498Szrj {
286738fd1498Szrj if (set
286838fd1498Szrj && GET_CODE (SET_DEST (set)) == CC0
286938fd1498Szrj && insn != last_ignored_compare)
287038fd1498Szrj {
287138fd1498Szrj rtx src1, src2;
287238fd1498Szrj if (GET_CODE (SET_SRC (set)) == SUBREG)
287338fd1498Szrj SET_SRC (set) = alter_subreg (&SET_SRC (set), true);
287438fd1498Szrj
287538fd1498Szrj src1 = SET_SRC (set);
287638fd1498Szrj src2 = NULL_RTX;
287738fd1498Szrj if (GET_CODE (SET_SRC (set)) == COMPARE)
287838fd1498Szrj {
287938fd1498Szrj if (GET_CODE (XEXP (SET_SRC (set), 0)) == SUBREG)
288038fd1498Szrj XEXP (SET_SRC (set), 0)
288138fd1498Szrj = alter_subreg (&XEXP (SET_SRC (set), 0), true);
288238fd1498Szrj if (GET_CODE (XEXP (SET_SRC (set), 1)) == SUBREG)
288338fd1498Szrj XEXP (SET_SRC (set), 1)
288438fd1498Szrj = alter_subreg (&XEXP (SET_SRC (set), 1), true);
288538fd1498Szrj if (XEXP (SET_SRC (set), 1)
288638fd1498Szrj == CONST0_RTX (GET_MODE (XEXP (SET_SRC (set), 0))))
288738fd1498Szrj src2 = XEXP (SET_SRC (set), 0);
288838fd1498Szrj }
288938fd1498Szrj if ((cc_status.value1 != 0
289038fd1498Szrj && rtx_equal_p (src1, cc_status.value1))
289138fd1498Szrj || (cc_status.value2 != 0
289238fd1498Szrj && rtx_equal_p (src1, cc_status.value2))
289338fd1498Szrj || (src2 != 0 && cc_status.value1 != 0
289438fd1498Szrj && rtx_equal_p (src2, cc_status.value1))
289538fd1498Szrj || (src2 != 0 && cc_status.value2 != 0
289638fd1498Szrj && rtx_equal_p (src2, cc_status.value2)))
289738fd1498Szrj {
289838fd1498Szrj /* Don't delete insn if it has an addressing side-effect. */
289938fd1498Szrj if (! FIND_REG_INC_NOTE (insn, NULL_RTX)
290038fd1498Szrj /* or if anything in it is volatile. */
290138fd1498Szrj && ! volatile_refs_p (PATTERN (insn)))
290238fd1498Szrj {
290338fd1498Szrj /* We don't really delete the insn; just ignore it. */
290438fd1498Szrj last_ignored_compare = insn;
290538fd1498Szrj break;
290638fd1498Szrj }
290738fd1498Szrj }
290838fd1498Szrj }
290938fd1498Szrj }
291038fd1498Szrj
291138fd1498Szrj /* If this is a conditional branch, maybe modify it
291238fd1498Szrj if the cc's are in a nonstandard state
291338fd1498Szrj so that it accomplishes the same thing that it would
291438fd1498Szrj do straightforwardly if the cc's were set up normally. */
291538fd1498Szrj
291638fd1498Szrj if (cc_status.flags != 0
291738fd1498Szrj && JUMP_P (insn)
291838fd1498Szrj && GET_CODE (body) == SET
291938fd1498Szrj && SET_DEST (body) == pc_rtx
292038fd1498Szrj && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE
292138fd1498Szrj && COMPARISON_P (XEXP (SET_SRC (body), 0))
292238fd1498Szrj && XEXP (XEXP (SET_SRC (body), 0), 0) == cc0_rtx)
292338fd1498Szrj {
292438fd1498Szrj /* This function may alter the contents of its argument
292538fd1498Szrj and clear some of the cc_status.flags bits.
292638fd1498Szrj It may also return 1 meaning condition now always true
292738fd1498Szrj or -1 meaning condition now always false
292838fd1498Szrj or 2 meaning condition nontrivial but altered. */
292938fd1498Szrj int result = alter_cond (XEXP (SET_SRC (body), 0));
293038fd1498Szrj /* If condition now has fixed value, replace the IF_THEN_ELSE
293138fd1498Szrj with its then-operand or its else-operand. */
293238fd1498Szrj if (result == 1)
293338fd1498Szrj SET_SRC (body) = XEXP (SET_SRC (body), 1);
293438fd1498Szrj if (result == -1)
293538fd1498Szrj SET_SRC (body) = XEXP (SET_SRC (body), 2);
293638fd1498Szrj
293738fd1498Szrj /* The jump is now either unconditional or a no-op.
293838fd1498Szrj If it has become a no-op, don't try to output it.
293938fd1498Szrj (It would not be recognized.) */
294038fd1498Szrj if (SET_SRC (body) == pc_rtx)
294138fd1498Szrj {
294238fd1498Szrj delete_insn (insn);
294338fd1498Szrj break;
294438fd1498Szrj }
294538fd1498Szrj else if (ANY_RETURN_P (SET_SRC (body)))
294638fd1498Szrj /* Replace (set (pc) (return)) with (return). */
294738fd1498Szrj PATTERN (insn) = body = SET_SRC (body);
294838fd1498Szrj
294938fd1498Szrj /* Rerecognize the instruction if it has changed. */
295038fd1498Szrj if (result != 0)
295138fd1498Szrj INSN_CODE (insn) = -1;
295238fd1498Szrj }
295338fd1498Szrj
295438fd1498Szrj /* If this is a conditional trap, maybe modify it if the cc's
295538fd1498Szrj are in a nonstandard state so that it accomplishes the same
295638fd1498Szrj thing that it would do straightforwardly if the cc's were
295738fd1498Szrj set up normally. */
295838fd1498Szrj if (cc_status.flags != 0
295938fd1498Szrj && NONJUMP_INSN_P (insn)
296038fd1498Szrj && GET_CODE (body) == TRAP_IF
296138fd1498Szrj && COMPARISON_P (TRAP_CONDITION (body))
296238fd1498Szrj && XEXP (TRAP_CONDITION (body), 0) == cc0_rtx)
296338fd1498Szrj {
296438fd1498Szrj /* This function may alter the contents of its argument
296538fd1498Szrj and clear some of the cc_status.flags bits.
296638fd1498Szrj It may also return 1 meaning condition now always true
296738fd1498Szrj or -1 meaning condition now always false
296838fd1498Szrj or 2 meaning condition nontrivial but altered. */
296938fd1498Szrj int result = alter_cond (TRAP_CONDITION (body));
297038fd1498Szrj
297138fd1498Szrj /* If TRAP_CONDITION has become always false, delete the
297238fd1498Szrj instruction. */
297338fd1498Szrj if (result == -1)
297438fd1498Szrj {
297538fd1498Szrj delete_insn (insn);
297638fd1498Szrj break;
297738fd1498Szrj }
297838fd1498Szrj
297938fd1498Szrj /* If TRAP_CONDITION has become always true, replace
298038fd1498Szrj TRAP_CONDITION with const_true_rtx. */
298138fd1498Szrj if (result == 1)
298238fd1498Szrj TRAP_CONDITION (body) = const_true_rtx;
298338fd1498Szrj
298438fd1498Szrj /* Rerecognize the instruction if it has changed. */
298538fd1498Szrj if (result != 0)
298638fd1498Szrj INSN_CODE (insn) = -1;
298738fd1498Szrj }
298838fd1498Szrj
298938fd1498Szrj /* Make same adjustments to instructions that examine the
299038fd1498Szrj condition codes without jumping and instructions that
299138fd1498Szrj handle conditional moves (if this machine has either one). */
299238fd1498Szrj
299338fd1498Szrj if (cc_status.flags != 0
299438fd1498Szrj && set != 0)
299538fd1498Szrj {
299638fd1498Szrj rtx cond_rtx, then_rtx, else_rtx;
299738fd1498Szrj
299838fd1498Szrj if (!JUMP_P (insn)
299938fd1498Szrj && GET_CODE (SET_SRC (set)) == IF_THEN_ELSE)
300038fd1498Szrj {
300138fd1498Szrj cond_rtx = XEXP (SET_SRC (set), 0);
300238fd1498Szrj then_rtx = XEXP (SET_SRC (set), 1);
300338fd1498Szrj else_rtx = XEXP (SET_SRC (set), 2);
300438fd1498Szrj }
300538fd1498Szrj else
300638fd1498Szrj {
300738fd1498Szrj cond_rtx = SET_SRC (set);
300838fd1498Szrj then_rtx = const_true_rtx;
300938fd1498Szrj else_rtx = const0_rtx;
301038fd1498Szrj }
301138fd1498Szrj
301238fd1498Szrj if (COMPARISON_P (cond_rtx)
301338fd1498Szrj && XEXP (cond_rtx, 0) == cc0_rtx)
301438fd1498Szrj {
301538fd1498Szrj int result;
301638fd1498Szrj result = alter_cond (cond_rtx);
301738fd1498Szrj if (result == 1)
301838fd1498Szrj validate_change (insn, &SET_SRC (set), then_rtx, 0);
301938fd1498Szrj else if (result == -1)
302038fd1498Szrj validate_change (insn, &SET_SRC (set), else_rtx, 0);
302138fd1498Szrj else if (result == 2)
302238fd1498Szrj INSN_CODE (insn) = -1;
302338fd1498Szrj if (SET_DEST (set) == SET_SRC (set))
302438fd1498Szrj delete_insn (insn);
302538fd1498Szrj }
302638fd1498Szrj }
302738fd1498Szrj
302838fd1498Szrj #endif
302938fd1498Szrj
303038fd1498Szrj /* Do machine-specific peephole optimizations if desired. */
303138fd1498Szrj
303238fd1498Szrj if (HAVE_peephole && optimize_p && !flag_no_peephole && !nopeepholes)
303338fd1498Szrj {
303438fd1498Szrj rtx_insn *next = peephole (insn);
303538fd1498Szrj /* When peepholing, if there were notes within the peephole,
303638fd1498Szrj emit them before the peephole. */
303738fd1498Szrj if (next != 0 && next != NEXT_INSN (insn))
303838fd1498Szrj {
303938fd1498Szrj rtx_insn *note, *prev = PREV_INSN (insn);
304038fd1498Szrj
304138fd1498Szrj for (note = NEXT_INSN (insn); note != next;
304238fd1498Szrj note = NEXT_INSN (note))
304338fd1498Szrj final_scan_insn (note, file, optimize_p, nopeepholes, seen);
304438fd1498Szrj
304538fd1498Szrj /* Put the notes in the proper position for a later
304638fd1498Szrj rescan. For example, the SH target can do this
304738fd1498Szrj when generating a far jump in a delayed branch
304838fd1498Szrj sequence. */
304938fd1498Szrj note = NEXT_INSN (insn);
305038fd1498Szrj SET_PREV_INSN (note) = prev;
305138fd1498Szrj SET_NEXT_INSN (prev) = note;
305238fd1498Szrj SET_NEXT_INSN (PREV_INSN (next)) = insn;
305338fd1498Szrj SET_PREV_INSN (insn) = PREV_INSN (next);
305438fd1498Szrj SET_NEXT_INSN (insn) = next;
305538fd1498Szrj SET_PREV_INSN (next) = insn;
305638fd1498Szrj }
305738fd1498Szrj
305838fd1498Szrj /* PEEPHOLE might have changed this. */
305938fd1498Szrj body = PATTERN (insn);
306038fd1498Szrj }
306138fd1498Szrj
306238fd1498Szrj /* Try to recognize the instruction.
306338fd1498Szrj If successful, verify that the operands satisfy the
306438fd1498Szrj constraints for the instruction. Crash if they don't,
306538fd1498Szrj since `reload' should have changed them so that they do. */
306638fd1498Szrj
306738fd1498Szrj insn_code_number = recog_memoized (insn);
306838fd1498Szrj cleanup_subreg_operands (insn);
306938fd1498Szrj
307038fd1498Szrj /* Dump the insn in the assembly for debugging (-dAP).
307138fd1498Szrj If the final dump is requested as slim RTL, dump slim
307238fd1498Szrj RTL to the assembly file also. */
307338fd1498Szrj if (flag_dump_rtl_in_asm)
307438fd1498Szrj {
307538fd1498Szrj print_rtx_head = ASM_COMMENT_START;
307638fd1498Szrj if (! (dump_flags & TDF_SLIM))
307738fd1498Szrj print_rtl_single (asm_out_file, insn);
307838fd1498Szrj else
307938fd1498Szrj dump_insn_slim (asm_out_file, insn);
308038fd1498Szrj print_rtx_head = "";
308138fd1498Szrj }
308238fd1498Szrj
308338fd1498Szrj if (! constrain_operands_cached (insn, 1))
308438fd1498Szrj fatal_insn_not_found (insn);
308538fd1498Szrj
308638fd1498Szrj /* Some target machines need to prescan each insn before
308738fd1498Szrj it is output. */
308838fd1498Szrj
308938fd1498Szrj #ifdef FINAL_PRESCAN_INSN
309038fd1498Szrj FINAL_PRESCAN_INSN (insn, recog_data.operand, recog_data.n_operands);
309138fd1498Szrj #endif
309238fd1498Szrj
309338fd1498Szrj if (targetm.have_conditional_execution ()
309438fd1498Szrj && GET_CODE (PATTERN (insn)) == COND_EXEC)
309538fd1498Szrj current_insn_predicate = COND_EXEC_TEST (PATTERN (insn));
309638fd1498Szrj
309738fd1498Szrj #if HAVE_cc0
309838fd1498Szrj cc_prev_status = cc_status;
309938fd1498Szrj
310038fd1498Szrj /* Update `cc_status' for this instruction.
310138fd1498Szrj The instruction's output routine may change it further.
310238fd1498Szrj If the output routine for a jump insn needs to depend
310338fd1498Szrj on the cc status, it should look at cc_prev_status. */
310438fd1498Szrj
310538fd1498Szrj NOTICE_UPDATE_CC (body, insn);
310638fd1498Szrj #endif
310738fd1498Szrj
310838fd1498Szrj current_output_insn = debug_insn = insn;
310938fd1498Szrj
311038fd1498Szrj /* Find the proper template for this insn. */
311138fd1498Szrj templ = get_insn_template (insn_code_number, insn);
311238fd1498Szrj
311338fd1498Szrj /* If the C code returns 0, it means that it is a jump insn
311438fd1498Szrj which follows a deleted test insn, and that test insn
311538fd1498Szrj needs to be reinserted. */
311638fd1498Szrj if (templ == 0)
311738fd1498Szrj {
311838fd1498Szrj rtx_insn *prev;
311938fd1498Szrj
312038fd1498Szrj gcc_assert (prev_nonnote_insn (insn) == last_ignored_compare);
312138fd1498Szrj
312238fd1498Szrj /* We have already processed the notes between the setter and
312338fd1498Szrj the user. Make sure we don't process them again, this is
312438fd1498Szrj particularly important if one of the notes is a block
312538fd1498Szrj scope note or an EH note. */
312638fd1498Szrj for (prev = insn;
312738fd1498Szrj prev != last_ignored_compare;
312838fd1498Szrj prev = PREV_INSN (prev))
312938fd1498Szrj {
313038fd1498Szrj if (NOTE_P (prev))
313138fd1498Szrj delete_insn (prev); /* Use delete_note. */
313238fd1498Szrj }
313338fd1498Szrj
313438fd1498Szrj return prev;
313538fd1498Szrj }
313638fd1498Szrj
313738fd1498Szrj /* If the template is the string "#", it means that this insn must
313838fd1498Szrj be split. */
313938fd1498Szrj if (templ[0] == '#' && templ[1] == '\0')
314038fd1498Szrj {
314138fd1498Szrj rtx_insn *new_rtx = try_split (body, insn, 0);
314238fd1498Szrj
314338fd1498Szrj /* If we didn't split the insn, go away. */
314438fd1498Szrj if (new_rtx == insn && PATTERN (new_rtx) == body)
314538fd1498Szrj fatal_insn ("could not split insn", insn);
314638fd1498Szrj
314738fd1498Szrj /* If we have a length attribute, this instruction should have
314838fd1498Szrj been split in shorten_branches, to ensure that we would have
314938fd1498Szrj valid length info for the splitees. */
315038fd1498Szrj gcc_assert (!HAVE_ATTR_length);
315138fd1498Szrj
315238fd1498Szrj return new_rtx;
315338fd1498Szrj }
315438fd1498Szrj
315538fd1498Szrj /* ??? This will put the directives in the wrong place if
315638fd1498Szrj get_insn_template outputs assembly directly. However calling it
315738fd1498Szrj before get_insn_template breaks if the insns is split. */
315838fd1498Szrj if (targetm.asm_out.unwind_emit_before_insn
315938fd1498Szrj && targetm.asm_out.unwind_emit)
316038fd1498Szrj targetm.asm_out.unwind_emit (asm_out_file, insn);
316138fd1498Szrj
316238fd1498Szrj rtx_call_insn *call_insn = dyn_cast <rtx_call_insn *> (insn);
316338fd1498Szrj if (call_insn != NULL)
316438fd1498Szrj {
316538fd1498Szrj rtx x = call_from_call_insn (call_insn);
316638fd1498Szrj x = XEXP (x, 0);
316738fd1498Szrj if (x && MEM_P (x) && GET_CODE (XEXP (x, 0)) == SYMBOL_REF)
316838fd1498Szrj {
316938fd1498Szrj tree t;
317038fd1498Szrj x = XEXP (x, 0);
317138fd1498Szrj t = SYMBOL_REF_DECL (x);
317238fd1498Szrj if (t)
317338fd1498Szrj assemble_external (t);
317438fd1498Szrj }
317538fd1498Szrj }
317638fd1498Szrj
317738fd1498Szrj /* Output assembler code from the template. */
317838fd1498Szrj output_asm_insn (templ, recog_data.operand);
317938fd1498Szrj
318038fd1498Szrj /* Some target machines need to postscan each insn after
318138fd1498Szrj it is output. */
318238fd1498Szrj if (targetm.asm_out.final_postscan_insn)
318338fd1498Szrj targetm.asm_out.final_postscan_insn (file, insn, recog_data.operand,
318438fd1498Szrj recog_data.n_operands);
318538fd1498Szrj
318638fd1498Szrj if (!targetm.asm_out.unwind_emit_before_insn
318738fd1498Szrj && targetm.asm_out.unwind_emit)
318838fd1498Szrj targetm.asm_out.unwind_emit (asm_out_file, insn);
318938fd1498Szrj
319038fd1498Szrj /* Let the debug info back-end know about this call. We do this only
319138fd1498Szrj after the instruction has been emitted because labels that may be
319238fd1498Szrj created to reference the call instruction must appear after it. */
319338fd1498Szrj if ((debug_variable_location_views || call_insn != NULL)
319438fd1498Szrj && !DECL_IGNORED_P (current_function_decl))
319538fd1498Szrj debug_hooks->var_location (insn);
319638fd1498Szrj
319738fd1498Szrj current_output_insn = debug_insn = 0;
319838fd1498Szrj }
319938fd1498Szrj }
320038fd1498Szrj return NEXT_INSN (insn);
320138fd1498Szrj }
320238fd1498Szrj
320338fd1498Szrj /* This is a wrapper around final_scan_insn_1 that allows ports to
320438fd1498Szrj call it recursively without a known value for SEEN. The value is
320538fd1498Szrj saved at the outermost call, and recovered for recursive calls.
320638fd1498Szrj Recursive calls MUST pass NULL, or the same pointer if they can
320738fd1498Szrj otherwise get to it. */
320838fd1498Szrj
320938fd1498Szrj rtx_insn *
final_scan_insn(rtx_insn * insn,FILE * file,int optimize_p,int nopeepholes,int * seen)321038fd1498Szrj final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p,
321138fd1498Szrj int nopeepholes, int *seen)
321238fd1498Szrj {
321338fd1498Szrj static int *enclosing_seen;
321438fd1498Szrj static int recursion_counter;
321538fd1498Szrj
321638fd1498Szrj gcc_assert (seen || recursion_counter);
321738fd1498Szrj gcc_assert (!recursion_counter || !seen || seen == enclosing_seen);
321838fd1498Szrj
321938fd1498Szrj if (!recursion_counter++)
322038fd1498Szrj enclosing_seen = seen;
322138fd1498Szrj else if (!seen)
322238fd1498Szrj seen = enclosing_seen;
322338fd1498Szrj
322438fd1498Szrj rtx_insn *ret = final_scan_insn_1 (insn, file, optimize_p, nopeepholes, seen);
322538fd1498Szrj
322638fd1498Szrj if (!--recursion_counter)
322738fd1498Szrj enclosing_seen = NULL;
322838fd1498Szrj
322938fd1498Szrj return ret;
323038fd1498Szrj }
323138fd1498Szrj
323238fd1498Szrj
323338fd1498Szrj /* Return whether a source line note needs to be emitted before INSN.
323438fd1498Szrj Sets IS_STMT to TRUE if the line should be marked as a possible
323538fd1498Szrj breakpoint location. */
323638fd1498Szrj
323738fd1498Szrj static bool
notice_source_line(rtx_insn * insn,bool * is_stmt)323838fd1498Szrj notice_source_line (rtx_insn *insn, bool *is_stmt)
323938fd1498Szrj {
324038fd1498Szrj const char *filename;
324138fd1498Szrj int linenum, columnnum;
324238fd1498Szrj
324338fd1498Szrj if (NOTE_MARKER_P (insn))
324438fd1498Szrj {
324538fd1498Szrj location_t loc = NOTE_MARKER_LOCATION (insn);
324638fd1498Szrj /* The inline entry markers (gimple, insn, note) carry the
324738fd1498Szrj location of the call, because that's what we want to carry
324838fd1498Szrj during compilation, but the location we want to output in
324938fd1498Szrj debug information for the inline entry point is the location
325038fd1498Szrj of the function itself. */
325138fd1498Szrj if (NOTE_KIND (insn) == NOTE_INSN_INLINE_ENTRY)
325238fd1498Szrj {
325338fd1498Szrj tree block = LOCATION_BLOCK (loc);
325438fd1498Szrj tree fn = block_ultimate_origin (block);
325538fd1498Szrj loc = DECL_SOURCE_LOCATION (fn);
325638fd1498Szrj }
325738fd1498Szrj expanded_location xloc = expand_location (loc);
325838fd1498Szrj if (xloc.line == 0)
325938fd1498Szrj {
326038fd1498Szrj gcc_checking_assert (LOCATION_LOCUS (loc) == UNKNOWN_LOCATION
326138fd1498Szrj || LOCATION_LOCUS (loc) == BUILTINS_LOCATION);
326238fd1498Szrj return false;
326338fd1498Szrj }
326438fd1498Szrj filename = xloc.file;
326538fd1498Szrj linenum = xloc.line;
326638fd1498Szrj columnnum = xloc.column;
326738fd1498Szrj force_source_line = true;
326838fd1498Szrj }
326938fd1498Szrj else if (override_filename)
327038fd1498Szrj {
327138fd1498Szrj filename = override_filename;
327238fd1498Szrj linenum = override_linenum;
327338fd1498Szrj columnnum = override_columnnum;
327438fd1498Szrj }
327538fd1498Szrj else if (INSN_HAS_LOCATION (insn))
327638fd1498Szrj {
327738fd1498Szrj expanded_location xloc = insn_location (insn);
327838fd1498Szrj filename = xloc.file;
327938fd1498Szrj linenum = xloc.line;
328038fd1498Szrj columnnum = xloc.column;
328138fd1498Szrj }
328238fd1498Szrj else
328338fd1498Szrj {
328438fd1498Szrj filename = NULL;
328538fd1498Szrj linenum = 0;
328638fd1498Szrj columnnum = 0;
328738fd1498Szrj }
328838fd1498Szrj
328938fd1498Szrj if (filename == NULL)
329038fd1498Szrj return false;
329138fd1498Szrj
329238fd1498Szrj if (force_source_line
329338fd1498Szrj || filename != last_filename
329438fd1498Szrj || last_linenum != linenum
329538fd1498Szrj || (debug_column_info && last_columnnum != columnnum))
329638fd1498Szrj {
329738fd1498Szrj force_source_line = false;
329838fd1498Szrj last_filename = filename;
329938fd1498Szrj last_linenum = linenum;
330038fd1498Szrj last_columnnum = columnnum;
330138fd1498Szrj last_discriminator = discriminator;
330238fd1498Szrj if (is_stmt)
330338fd1498Szrj *is_stmt = true;
330438fd1498Szrj high_block_linenum = MAX (last_linenum, high_block_linenum);
330538fd1498Szrj high_function_linenum = MAX (last_linenum, high_function_linenum);
330638fd1498Szrj return true;
330738fd1498Szrj }
330838fd1498Szrj
330938fd1498Szrj if (SUPPORTS_DISCRIMINATOR && last_discriminator != discriminator)
331038fd1498Szrj {
331138fd1498Szrj /* If the discriminator changed, but the line number did not,
331238fd1498Szrj output the line table entry with is_stmt false so the
331338fd1498Szrj debugger does not treat this as a breakpoint location. */
331438fd1498Szrj last_discriminator = discriminator;
331538fd1498Szrj if (is_stmt)
331638fd1498Szrj *is_stmt = false;
331738fd1498Szrj return true;
331838fd1498Szrj }
331938fd1498Szrj
332038fd1498Szrj return false;
332138fd1498Szrj }
332238fd1498Szrj
332338fd1498Szrj /* For each operand in INSN, simplify (subreg (reg)) so that it refers
332438fd1498Szrj directly to the desired hard register. */
332538fd1498Szrj
332638fd1498Szrj void
cleanup_subreg_operands(rtx_insn * insn)332738fd1498Szrj cleanup_subreg_operands (rtx_insn *insn)
332838fd1498Szrj {
332938fd1498Szrj int i;
333038fd1498Szrj bool changed = false;
333138fd1498Szrj extract_insn_cached (insn);
333238fd1498Szrj for (i = 0; i < recog_data.n_operands; i++)
333338fd1498Szrj {
333438fd1498Szrj /* The following test cannot use recog_data.operand when testing
333538fd1498Szrj for a SUBREG: the underlying object might have been changed
333638fd1498Szrj already if we are inside a match_operator expression that
333738fd1498Szrj matches the else clause. Instead we test the underlying
333838fd1498Szrj expression directly. */
333938fd1498Szrj if (GET_CODE (*recog_data.operand_loc[i]) == SUBREG)
334038fd1498Szrj {
334138fd1498Szrj recog_data.operand[i] = alter_subreg (recog_data.operand_loc[i], true);
334238fd1498Szrj changed = true;
334338fd1498Szrj }
334438fd1498Szrj else if (GET_CODE (recog_data.operand[i]) == PLUS
334538fd1498Szrj || GET_CODE (recog_data.operand[i]) == MULT
334638fd1498Szrj || MEM_P (recog_data.operand[i]))
334738fd1498Szrj recog_data.operand[i] = walk_alter_subreg (recog_data.operand_loc[i], &changed);
334838fd1498Szrj }
334938fd1498Szrj
335038fd1498Szrj for (i = 0; i < recog_data.n_dups; i++)
335138fd1498Szrj {
335238fd1498Szrj if (GET_CODE (*recog_data.dup_loc[i]) == SUBREG)
335338fd1498Szrj {
335438fd1498Szrj *recog_data.dup_loc[i] = alter_subreg (recog_data.dup_loc[i], true);
335538fd1498Szrj changed = true;
335638fd1498Szrj }
335738fd1498Szrj else if (GET_CODE (*recog_data.dup_loc[i]) == PLUS
335838fd1498Szrj || GET_CODE (*recog_data.dup_loc[i]) == MULT
335938fd1498Szrj || MEM_P (*recog_data.dup_loc[i]))
336038fd1498Szrj *recog_data.dup_loc[i] = walk_alter_subreg (recog_data.dup_loc[i], &changed);
336138fd1498Szrj }
336238fd1498Szrj if (changed)
336338fd1498Szrj df_insn_rescan (insn);
336438fd1498Szrj }
336538fd1498Szrj
336638fd1498Szrj /* If X is a SUBREG, try to replace it with a REG or a MEM, based on
336738fd1498Szrj the thing it is a subreg of. Do it anyway if FINAL_P. */
336838fd1498Szrj
336938fd1498Szrj rtx
alter_subreg(rtx * xp,bool final_p)337038fd1498Szrj alter_subreg (rtx *xp, bool final_p)
337138fd1498Szrj {
337238fd1498Szrj rtx x = *xp;
337338fd1498Szrj rtx y = SUBREG_REG (x);
337438fd1498Szrj
337538fd1498Szrj /* simplify_subreg does not remove subreg from volatile references.
337638fd1498Szrj We are required to. */
337738fd1498Szrj if (MEM_P (y))
337838fd1498Szrj {
337938fd1498Szrj poly_int64 offset = SUBREG_BYTE (x);
338038fd1498Szrj
338138fd1498Szrj /* For paradoxical subregs on big-endian machines, SUBREG_BYTE
338238fd1498Szrj contains 0 instead of the proper offset. See simplify_subreg. */
338338fd1498Szrj if (paradoxical_subreg_p (x))
338438fd1498Szrj offset = byte_lowpart_offset (GET_MODE (x), GET_MODE (y));
338538fd1498Szrj
338638fd1498Szrj if (final_p)
338738fd1498Szrj *xp = adjust_address (y, GET_MODE (x), offset);
338838fd1498Szrj else
338938fd1498Szrj *xp = adjust_address_nv (y, GET_MODE (x), offset);
339038fd1498Szrj }
339138fd1498Szrj else if (REG_P (y) && HARD_REGISTER_P (y))
339238fd1498Szrj {
339338fd1498Szrj rtx new_rtx = simplify_subreg (GET_MODE (x), y, GET_MODE (y),
339438fd1498Szrj SUBREG_BYTE (x));
339538fd1498Szrj
339638fd1498Szrj if (new_rtx != 0)
339738fd1498Szrj *xp = new_rtx;
339838fd1498Szrj else if (final_p && REG_P (y))
339938fd1498Szrj {
340038fd1498Szrj /* Simplify_subreg can't handle some REG cases, but we have to. */
340138fd1498Szrj unsigned int regno;
340238fd1498Szrj poly_int64 offset;
340338fd1498Szrj
340438fd1498Szrj regno = subreg_regno (x);
340538fd1498Szrj if (subreg_lowpart_p (x))
340638fd1498Szrj offset = byte_lowpart_offset (GET_MODE (x), GET_MODE (y));
340738fd1498Szrj else
340838fd1498Szrj offset = SUBREG_BYTE (x);
340938fd1498Szrj *xp = gen_rtx_REG_offset (y, GET_MODE (x), regno, offset);
341038fd1498Szrj }
341138fd1498Szrj }
341238fd1498Szrj
341338fd1498Szrj return *xp;
341438fd1498Szrj }
341538fd1498Szrj
341638fd1498Szrj /* Do alter_subreg on all the SUBREGs contained in X. */
341738fd1498Szrj
341838fd1498Szrj static rtx
walk_alter_subreg(rtx * xp,bool * changed)341938fd1498Szrj walk_alter_subreg (rtx *xp, bool *changed)
342038fd1498Szrj {
342138fd1498Szrj rtx x = *xp;
342238fd1498Szrj switch (GET_CODE (x))
342338fd1498Szrj {
342438fd1498Szrj case PLUS:
342538fd1498Szrj case MULT:
342638fd1498Szrj case AND:
342738fd1498Szrj XEXP (x, 0) = walk_alter_subreg (&XEXP (x, 0), changed);
342838fd1498Szrj XEXP (x, 1) = walk_alter_subreg (&XEXP (x, 1), changed);
342938fd1498Szrj break;
343038fd1498Szrj
343138fd1498Szrj case MEM:
343238fd1498Szrj case ZERO_EXTEND:
343338fd1498Szrj XEXP (x, 0) = walk_alter_subreg (&XEXP (x, 0), changed);
343438fd1498Szrj break;
343538fd1498Szrj
343638fd1498Szrj case SUBREG:
343738fd1498Szrj *changed = true;
343838fd1498Szrj return alter_subreg (xp, true);
343938fd1498Szrj
344038fd1498Szrj default:
344138fd1498Szrj break;
344238fd1498Szrj }
344338fd1498Szrj
344438fd1498Szrj return *xp;
344538fd1498Szrj }
344638fd1498Szrj
344738fd1498Szrj #if HAVE_cc0
344838fd1498Szrj
344938fd1498Szrj /* Given BODY, the body of a jump instruction, alter the jump condition
345038fd1498Szrj as required by the bits that are set in cc_status.flags.
345138fd1498Szrj Not all of the bits there can be handled at this level in all cases.
345238fd1498Szrj
345338fd1498Szrj The value is normally 0.
345438fd1498Szrj 1 means that the condition has become always true.
345538fd1498Szrj -1 means that the condition has become always false.
345638fd1498Szrj 2 means that COND has been altered. */
345738fd1498Szrj
345838fd1498Szrj static int
alter_cond(rtx cond)345938fd1498Szrj alter_cond (rtx cond)
346038fd1498Szrj {
346138fd1498Szrj int value = 0;
346238fd1498Szrj
346338fd1498Szrj if (cc_status.flags & CC_REVERSED)
346438fd1498Szrj {
346538fd1498Szrj value = 2;
346638fd1498Szrj PUT_CODE (cond, swap_condition (GET_CODE (cond)));
346738fd1498Szrj }
346838fd1498Szrj
346938fd1498Szrj if (cc_status.flags & CC_INVERTED)
347038fd1498Szrj {
347138fd1498Szrj value = 2;
347238fd1498Szrj PUT_CODE (cond, reverse_condition (GET_CODE (cond)));
347338fd1498Szrj }
347438fd1498Szrj
347538fd1498Szrj if (cc_status.flags & CC_NOT_POSITIVE)
347638fd1498Szrj switch (GET_CODE (cond))
347738fd1498Szrj {
347838fd1498Szrj case LE:
347938fd1498Szrj case LEU:
348038fd1498Szrj case GEU:
348138fd1498Szrj /* Jump becomes unconditional. */
348238fd1498Szrj return 1;
348338fd1498Szrj
348438fd1498Szrj case GT:
348538fd1498Szrj case GTU:
348638fd1498Szrj case LTU:
348738fd1498Szrj /* Jump becomes no-op. */
348838fd1498Szrj return -1;
348938fd1498Szrj
349038fd1498Szrj case GE:
349138fd1498Szrj PUT_CODE (cond, EQ);
349238fd1498Szrj value = 2;
349338fd1498Szrj break;
349438fd1498Szrj
349538fd1498Szrj case LT:
349638fd1498Szrj PUT_CODE (cond, NE);
349738fd1498Szrj value = 2;
349838fd1498Szrj break;
349938fd1498Szrj
350038fd1498Szrj default:
350138fd1498Szrj break;
350238fd1498Szrj }
350338fd1498Szrj
350438fd1498Szrj if (cc_status.flags & CC_NOT_NEGATIVE)
350538fd1498Szrj switch (GET_CODE (cond))
350638fd1498Szrj {
350738fd1498Szrj case GE:
350838fd1498Szrj case GEU:
350938fd1498Szrj /* Jump becomes unconditional. */
351038fd1498Szrj return 1;
351138fd1498Szrj
351238fd1498Szrj case LT:
351338fd1498Szrj case LTU:
351438fd1498Szrj /* Jump becomes no-op. */
351538fd1498Szrj return -1;
351638fd1498Szrj
351738fd1498Szrj case LE:
351838fd1498Szrj case LEU:
351938fd1498Szrj PUT_CODE (cond, EQ);
352038fd1498Szrj value = 2;
352138fd1498Szrj break;
352238fd1498Szrj
352338fd1498Szrj case GT:
352438fd1498Szrj case GTU:
352538fd1498Szrj PUT_CODE (cond, NE);
352638fd1498Szrj value = 2;
352738fd1498Szrj break;
352838fd1498Szrj
352938fd1498Szrj default:
353038fd1498Szrj break;
353138fd1498Szrj }
353238fd1498Szrj
353338fd1498Szrj if (cc_status.flags & CC_NO_OVERFLOW)
353438fd1498Szrj switch (GET_CODE (cond))
353538fd1498Szrj {
353638fd1498Szrj case GEU:
353738fd1498Szrj /* Jump becomes unconditional. */
353838fd1498Szrj return 1;
353938fd1498Szrj
354038fd1498Szrj case LEU:
354138fd1498Szrj PUT_CODE (cond, EQ);
354238fd1498Szrj value = 2;
354338fd1498Szrj break;
354438fd1498Szrj
354538fd1498Szrj case GTU:
354638fd1498Szrj PUT_CODE (cond, NE);
354738fd1498Szrj value = 2;
354838fd1498Szrj break;
354938fd1498Szrj
355038fd1498Szrj case LTU:
355138fd1498Szrj /* Jump becomes no-op. */
355238fd1498Szrj return -1;
355338fd1498Szrj
355438fd1498Szrj default:
355538fd1498Szrj break;
355638fd1498Szrj }
355738fd1498Szrj
355838fd1498Szrj if (cc_status.flags & (CC_Z_IN_NOT_N | CC_Z_IN_N))
355938fd1498Szrj switch (GET_CODE (cond))
356038fd1498Szrj {
356138fd1498Szrj default:
356238fd1498Szrj gcc_unreachable ();
356338fd1498Szrj
356438fd1498Szrj case NE:
356538fd1498Szrj PUT_CODE (cond, cc_status.flags & CC_Z_IN_N ? GE : LT);
356638fd1498Szrj value = 2;
356738fd1498Szrj break;
356838fd1498Szrj
356938fd1498Szrj case EQ:
357038fd1498Szrj PUT_CODE (cond, cc_status.flags & CC_Z_IN_N ? LT : GE);
357138fd1498Szrj value = 2;
357238fd1498Szrj break;
357338fd1498Szrj }
357438fd1498Szrj
357538fd1498Szrj if (cc_status.flags & CC_NOT_SIGNED)
357638fd1498Szrj /* The flags are valid if signed condition operators are converted
357738fd1498Szrj to unsigned. */
357838fd1498Szrj switch (GET_CODE (cond))
357938fd1498Szrj {
358038fd1498Szrj case LE:
358138fd1498Szrj PUT_CODE (cond, LEU);
358238fd1498Szrj value = 2;
358338fd1498Szrj break;
358438fd1498Szrj
358538fd1498Szrj case LT:
358638fd1498Szrj PUT_CODE (cond, LTU);
358738fd1498Szrj value = 2;
358838fd1498Szrj break;
358938fd1498Szrj
359038fd1498Szrj case GT:
359138fd1498Szrj PUT_CODE (cond, GTU);
359238fd1498Szrj value = 2;
359338fd1498Szrj break;
359438fd1498Szrj
359538fd1498Szrj case GE:
359638fd1498Szrj PUT_CODE (cond, GEU);
359738fd1498Szrj value = 2;
359838fd1498Szrj break;
359938fd1498Szrj
360038fd1498Szrj default:
360138fd1498Szrj break;
360238fd1498Szrj }
360338fd1498Szrj
360438fd1498Szrj return value;
360538fd1498Szrj }
360638fd1498Szrj #endif
360738fd1498Szrj
360838fd1498Szrj /* Report inconsistency between the assembler template and the operands.
360938fd1498Szrj In an `asm', it's the user's fault; otherwise, the compiler's fault. */
361038fd1498Szrj
361138fd1498Szrj void
output_operand_lossage(const char * cmsgid,...)361238fd1498Szrj output_operand_lossage (const char *cmsgid, ...)
361338fd1498Szrj {
361438fd1498Szrj char *fmt_string;
361538fd1498Szrj char *new_message;
361638fd1498Szrj const char *pfx_str;
361738fd1498Szrj va_list ap;
361838fd1498Szrj
361938fd1498Szrj va_start (ap, cmsgid);
362038fd1498Szrj
362138fd1498Szrj pfx_str = this_is_asm_operands ? _("invalid 'asm': ") : "output_operand: ";
362238fd1498Szrj fmt_string = xasprintf ("%s%s", pfx_str, _(cmsgid));
362338fd1498Szrj new_message = xvasprintf (fmt_string, ap);
362438fd1498Szrj
362538fd1498Szrj if (this_is_asm_operands)
362638fd1498Szrj error_for_asm (this_is_asm_operands, "%s", new_message);
362738fd1498Szrj else
362838fd1498Szrj internal_error ("%s", new_message);
362938fd1498Szrj
363038fd1498Szrj free (fmt_string);
363138fd1498Szrj free (new_message);
363238fd1498Szrj va_end (ap);
363338fd1498Szrj }
363438fd1498Szrj
363538fd1498Szrj /* Output of assembler code from a template, and its subroutines. */
363638fd1498Szrj
363738fd1498Szrj /* Annotate the assembly with a comment describing the pattern and
363838fd1498Szrj alternative used. */
363938fd1498Szrj
364038fd1498Szrj static void
output_asm_name(void)364138fd1498Szrj output_asm_name (void)
364238fd1498Szrj {
364338fd1498Szrj if (debug_insn)
364438fd1498Szrj {
364538fd1498Szrj fprintf (asm_out_file, "\t%s %d\t",
364638fd1498Szrj ASM_COMMENT_START, INSN_UID (debug_insn));
364738fd1498Szrj
364838fd1498Szrj fprintf (asm_out_file, "[c=%d",
364938fd1498Szrj insn_cost (debug_insn, optimize_insn_for_speed_p ()));
365038fd1498Szrj if (HAVE_ATTR_length)
365138fd1498Szrj fprintf (asm_out_file, " l=%d",
365238fd1498Szrj get_attr_length (debug_insn));
365338fd1498Szrj fprintf (asm_out_file, "] ");
365438fd1498Szrj
365538fd1498Szrj int num = INSN_CODE (debug_insn);
365638fd1498Szrj fprintf (asm_out_file, "%s", insn_data[num].name);
365738fd1498Szrj if (insn_data[num].n_alternatives > 1)
365838fd1498Szrj fprintf (asm_out_file, "/%d", which_alternative);
365938fd1498Szrj
366038fd1498Szrj /* Clear this so only the first assembler insn
366138fd1498Szrj of any rtl insn will get the special comment for -dp. */
366238fd1498Szrj debug_insn = 0;
366338fd1498Szrj }
366438fd1498Szrj }
366538fd1498Szrj
366638fd1498Szrj /* If OP is a REG or MEM and we can find a MEM_EXPR corresponding to it
366738fd1498Szrj or its address, return that expr . Set *PADDRESSP to 1 if the expr
366838fd1498Szrj corresponds to the address of the object and 0 if to the object. */
366938fd1498Szrj
367038fd1498Szrj static tree
get_mem_expr_from_op(rtx op,int * paddressp)367138fd1498Szrj get_mem_expr_from_op (rtx op, int *paddressp)
367238fd1498Szrj {
367338fd1498Szrj tree expr;
367438fd1498Szrj int inner_addressp;
367538fd1498Szrj
367638fd1498Szrj *paddressp = 0;
367738fd1498Szrj
367838fd1498Szrj if (REG_P (op))
367938fd1498Szrj return REG_EXPR (op);
368038fd1498Szrj else if (!MEM_P (op))
368138fd1498Szrj return 0;
368238fd1498Szrj
368338fd1498Szrj if (MEM_EXPR (op) != 0)
368438fd1498Szrj return MEM_EXPR (op);
368538fd1498Szrj
368638fd1498Szrj /* Otherwise we have an address, so indicate it and look at the address. */
368738fd1498Szrj *paddressp = 1;
368838fd1498Szrj op = XEXP (op, 0);
368938fd1498Szrj
369038fd1498Szrj /* First check if we have a decl for the address, then look at the right side
369138fd1498Szrj if it is a PLUS. Otherwise, strip off arithmetic and keep looking.
369238fd1498Szrj But don't allow the address to itself be indirect. */
369338fd1498Szrj if ((expr = get_mem_expr_from_op (op, &inner_addressp)) && ! inner_addressp)
369438fd1498Szrj return expr;
369538fd1498Szrj else if (GET_CODE (op) == PLUS
369638fd1498Szrj && (expr = get_mem_expr_from_op (XEXP (op, 1), &inner_addressp)))
369738fd1498Szrj return expr;
369838fd1498Szrj
369938fd1498Szrj while (UNARY_P (op)
370038fd1498Szrj || GET_RTX_CLASS (GET_CODE (op)) == RTX_BIN_ARITH)
370138fd1498Szrj op = XEXP (op, 0);
370238fd1498Szrj
370338fd1498Szrj expr = get_mem_expr_from_op (op, &inner_addressp);
370438fd1498Szrj return inner_addressp ? 0 : expr;
370538fd1498Szrj }
370638fd1498Szrj
370738fd1498Szrj /* Output operand names for assembler instructions. OPERANDS is the
370838fd1498Szrj operand vector, OPORDER is the order to write the operands, and NOPS
370938fd1498Szrj is the number of operands to write. */
371038fd1498Szrj
371138fd1498Szrj static void
output_asm_operand_names(rtx * operands,int * oporder,int nops)371238fd1498Szrj output_asm_operand_names (rtx *operands, int *oporder, int nops)
371338fd1498Szrj {
371438fd1498Szrj int wrote = 0;
371538fd1498Szrj int i;
371638fd1498Szrj
371738fd1498Szrj for (i = 0; i < nops; i++)
371838fd1498Szrj {
371938fd1498Szrj int addressp;
372038fd1498Szrj rtx op = operands[oporder[i]];
372138fd1498Szrj tree expr = get_mem_expr_from_op (op, &addressp);
372238fd1498Szrj
372338fd1498Szrj fprintf (asm_out_file, "%c%s",
372438fd1498Szrj wrote ? ',' : '\t', wrote ? "" : ASM_COMMENT_START);
372538fd1498Szrj wrote = 1;
372638fd1498Szrj if (expr)
372738fd1498Szrj {
372838fd1498Szrj fprintf (asm_out_file, "%s",
372938fd1498Szrj addressp ? "*" : "");
373038fd1498Szrj print_mem_expr (asm_out_file, expr);
373138fd1498Szrj wrote = 1;
373238fd1498Szrj }
373338fd1498Szrj else if (REG_P (op) && ORIGINAL_REGNO (op)
373438fd1498Szrj && ORIGINAL_REGNO (op) != REGNO (op))
373538fd1498Szrj fprintf (asm_out_file, " tmp%i", ORIGINAL_REGNO (op));
373638fd1498Szrj }
373738fd1498Szrj }
373838fd1498Szrj
373938fd1498Szrj #ifdef ASSEMBLER_DIALECT
374038fd1498Szrj /* Helper function to parse assembler dialects in the asm string.
374138fd1498Szrj This is called from output_asm_insn and asm_fprintf. */
374238fd1498Szrj static const char *
do_assembler_dialects(const char * p,int * dialect)374338fd1498Szrj do_assembler_dialects (const char *p, int *dialect)
374438fd1498Szrj {
374538fd1498Szrj char c = *(p - 1);
374638fd1498Szrj
374738fd1498Szrj switch (c)
374838fd1498Szrj {
374938fd1498Szrj case '{':
375038fd1498Szrj {
375138fd1498Szrj int i;
375238fd1498Szrj
375338fd1498Szrj if (*dialect)
375438fd1498Szrj output_operand_lossage ("nested assembly dialect alternatives");
375538fd1498Szrj else
375638fd1498Szrj *dialect = 1;
375738fd1498Szrj
375838fd1498Szrj /* If we want the first dialect, do nothing. Otherwise, skip
375938fd1498Szrj DIALECT_NUMBER of strings ending with '|'. */
376038fd1498Szrj for (i = 0; i < dialect_number; i++)
376138fd1498Szrj {
376238fd1498Szrj while (*p && *p != '}')
376338fd1498Szrj {
376438fd1498Szrj if (*p == '|')
376538fd1498Szrj {
376638fd1498Szrj p++;
376738fd1498Szrj break;
376838fd1498Szrj }
376938fd1498Szrj
377038fd1498Szrj /* Skip over any character after a percent sign. */
377138fd1498Szrj if (*p == '%')
377238fd1498Szrj p++;
377338fd1498Szrj if (*p)
377438fd1498Szrj p++;
377538fd1498Szrj }
377638fd1498Szrj
377738fd1498Szrj if (*p == '}')
377838fd1498Szrj break;
377938fd1498Szrj }
378038fd1498Szrj
378138fd1498Szrj if (*p == '\0')
378238fd1498Szrj output_operand_lossage ("unterminated assembly dialect alternative");
378338fd1498Szrj }
378438fd1498Szrj break;
378538fd1498Szrj
378638fd1498Szrj case '|':
378738fd1498Szrj if (*dialect)
378838fd1498Szrj {
378938fd1498Szrj /* Skip to close brace. */
379038fd1498Szrj do
379138fd1498Szrj {
379238fd1498Szrj if (*p == '\0')
379338fd1498Szrj {
379438fd1498Szrj output_operand_lossage ("unterminated assembly dialect alternative");
379538fd1498Szrj break;
379638fd1498Szrj }
379738fd1498Szrj
379838fd1498Szrj /* Skip over any character after a percent sign. */
379938fd1498Szrj if (*p == '%' && p[1])
380038fd1498Szrj {
380138fd1498Szrj p += 2;
380238fd1498Szrj continue;
380338fd1498Szrj }
380438fd1498Szrj
380538fd1498Szrj if (*p++ == '}')
380638fd1498Szrj break;
380738fd1498Szrj }
380838fd1498Szrj while (1);
380938fd1498Szrj
381038fd1498Szrj *dialect = 0;
381138fd1498Szrj }
381238fd1498Szrj else
381338fd1498Szrj putc (c, asm_out_file);
381438fd1498Szrj break;
381538fd1498Szrj
381638fd1498Szrj case '}':
381738fd1498Szrj if (! *dialect)
381838fd1498Szrj putc (c, asm_out_file);
381938fd1498Szrj *dialect = 0;
382038fd1498Szrj break;
382138fd1498Szrj default:
382238fd1498Szrj gcc_unreachable ();
382338fd1498Szrj }
382438fd1498Szrj
382538fd1498Szrj return p;
382638fd1498Szrj }
382738fd1498Szrj #endif
382838fd1498Szrj
382938fd1498Szrj /* Output text from TEMPLATE to the assembler output file,
383038fd1498Szrj obeying %-directions to substitute operands taken from
383138fd1498Szrj the vector OPERANDS.
383238fd1498Szrj
383338fd1498Szrj %N (for N a digit) means print operand N in usual manner.
383438fd1498Szrj %lN means require operand N to be a CODE_LABEL or LABEL_REF
383538fd1498Szrj and print the label name with no punctuation.
383638fd1498Szrj %cN means require operand N to be a constant
383738fd1498Szrj and print the constant expression with no punctuation.
383838fd1498Szrj %aN means expect operand N to be a memory address
383938fd1498Szrj (not a memory reference!) and print a reference
384038fd1498Szrj to that address.
384138fd1498Szrj %nN means expect operand N to be a constant
384238fd1498Szrj and print a constant expression for minus the value
384338fd1498Szrj of the operand, with no other punctuation. */
384438fd1498Szrj
384538fd1498Szrj void
output_asm_insn(const char * templ,rtx * operands)384638fd1498Szrj output_asm_insn (const char *templ, rtx *operands)
384738fd1498Szrj {
384838fd1498Szrj const char *p;
384938fd1498Szrj int c;
385038fd1498Szrj #ifdef ASSEMBLER_DIALECT
385138fd1498Szrj int dialect = 0;
385238fd1498Szrj #endif
385338fd1498Szrj int oporder[MAX_RECOG_OPERANDS];
385438fd1498Szrj char opoutput[MAX_RECOG_OPERANDS];
385538fd1498Szrj int ops = 0;
385638fd1498Szrj
385738fd1498Szrj /* An insn may return a null string template
385838fd1498Szrj in a case where no assembler code is needed. */
385938fd1498Szrj if (*templ == 0)
386038fd1498Szrj return;
386138fd1498Szrj
386238fd1498Szrj memset (opoutput, 0, sizeof opoutput);
386338fd1498Szrj p = templ;
386438fd1498Szrj putc ('\t', asm_out_file);
386538fd1498Szrj
386638fd1498Szrj #ifdef ASM_OUTPUT_OPCODE
386738fd1498Szrj ASM_OUTPUT_OPCODE (asm_out_file, p);
386838fd1498Szrj #endif
386938fd1498Szrj
387038fd1498Szrj while ((c = *p++))
387138fd1498Szrj switch (c)
387238fd1498Szrj {
387338fd1498Szrj case '\n':
387438fd1498Szrj if (flag_verbose_asm)
387538fd1498Szrj output_asm_operand_names (operands, oporder, ops);
387638fd1498Szrj if (flag_print_asm_name)
387738fd1498Szrj output_asm_name ();
387838fd1498Szrj
387938fd1498Szrj ops = 0;
388038fd1498Szrj memset (opoutput, 0, sizeof opoutput);
388138fd1498Szrj
388238fd1498Szrj putc (c, asm_out_file);
388338fd1498Szrj #ifdef ASM_OUTPUT_OPCODE
388438fd1498Szrj while ((c = *p) == '\t')
388538fd1498Szrj {
388638fd1498Szrj putc (c, asm_out_file);
388738fd1498Szrj p++;
388838fd1498Szrj }
388938fd1498Szrj ASM_OUTPUT_OPCODE (asm_out_file, p);
389038fd1498Szrj #endif
389138fd1498Szrj break;
389238fd1498Szrj
389338fd1498Szrj #ifdef ASSEMBLER_DIALECT
389438fd1498Szrj case '{':
389538fd1498Szrj case '}':
389638fd1498Szrj case '|':
389738fd1498Szrj p = do_assembler_dialects (p, &dialect);
389838fd1498Szrj break;
389938fd1498Szrj #endif
390038fd1498Szrj
390138fd1498Szrj case '%':
390238fd1498Szrj /* %% outputs a single %. %{, %} and %| print {, } and | respectively
390338fd1498Szrj if ASSEMBLER_DIALECT defined and these characters have a special
390438fd1498Szrj meaning as dialect delimiters.*/
390538fd1498Szrj if (*p == '%'
390638fd1498Szrj #ifdef ASSEMBLER_DIALECT
390738fd1498Szrj || *p == '{' || *p == '}' || *p == '|'
390838fd1498Szrj #endif
390938fd1498Szrj )
391038fd1498Szrj {
391138fd1498Szrj putc (*p, asm_out_file);
391238fd1498Szrj p++;
391338fd1498Szrj }
391438fd1498Szrj /* %= outputs a number which is unique to each insn in the entire
391538fd1498Szrj compilation. This is useful for making local labels that are
391638fd1498Szrj referred to more than once in a given insn. */
391738fd1498Szrj else if (*p == '=')
391838fd1498Szrj {
391938fd1498Szrj p++;
392038fd1498Szrj fprintf (asm_out_file, "%d", insn_counter);
392138fd1498Szrj }
392238fd1498Szrj /* % followed by a letter and some digits
392338fd1498Szrj outputs an operand in a special way depending on the letter.
392438fd1498Szrj Letters `acln' are implemented directly.
392538fd1498Szrj Other letters are passed to `output_operand' so that
392638fd1498Szrj the TARGET_PRINT_OPERAND hook can define them. */
392738fd1498Szrj else if (ISALPHA (*p))
392838fd1498Szrj {
392938fd1498Szrj int letter = *p++;
393038fd1498Szrj unsigned long opnum;
393138fd1498Szrj char *endptr;
393238fd1498Szrj
393338fd1498Szrj opnum = strtoul (p, &endptr, 10);
393438fd1498Szrj
393538fd1498Szrj if (endptr == p)
393638fd1498Szrj output_operand_lossage ("operand number missing "
393738fd1498Szrj "after %%-letter");
393838fd1498Szrj else if (this_is_asm_operands && opnum >= insn_noperands)
393938fd1498Szrj output_operand_lossage ("operand number out of range");
394038fd1498Szrj else if (letter == 'l')
394138fd1498Szrj output_asm_label (operands[opnum]);
394238fd1498Szrj else if (letter == 'a')
394338fd1498Szrj output_address (VOIDmode, operands[opnum]);
394438fd1498Szrj else if (letter == 'c')
394538fd1498Szrj {
394638fd1498Szrj if (CONSTANT_ADDRESS_P (operands[opnum]))
394738fd1498Szrj output_addr_const (asm_out_file, operands[opnum]);
394838fd1498Szrj else
394938fd1498Szrj output_operand (operands[opnum], 'c');
395038fd1498Szrj }
395138fd1498Szrj else if (letter == 'n')
395238fd1498Szrj {
395338fd1498Szrj if (CONST_INT_P (operands[opnum]))
395438fd1498Szrj fprintf (asm_out_file, HOST_WIDE_INT_PRINT_DEC,
395538fd1498Szrj - INTVAL (operands[opnum]));
395638fd1498Szrj else
395738fd1498Szrj {
395838fd1498Szrj putc ('-', asm_out_file);
395938fd1498Szrj output_addr_const (asm_out_file, operands[opnum]);
396038fd1498Szrj }
396138fd1498Szrj }
396238fd1498Szrj else
396338fd1498Szrj output_operand (operands[opnum], letter);
396438fd1498Szrj
396538fd1498Szrj if (!opoutput[opnum])
396638fd1498Szrj oporder[ops++] = opnum;
396738fd1498Szrj opoutput[opnum] = 1;
396838fd1498Szrj
396938fd1498Szrj p = endptr;
397038fd1498Szrj c = *p;
397138fd1498Szrj }
397238fd1498Szrj /* % followed by a digit outputs an operand the default way. */
397338fd1498Szrj else if (ISDIGIT (*p))
397438fd1498Szrj {
397538fd1498Szrj unsigned long opnum;
397638fd1498Szrj char *endptr;
397738fd1498Szrj
397838fd1498Szrj opnum = strtoul (p, &endptr, 10);
397938fd1498Szrj if (this_is_asm_operands && opnum >= insn_noperands)
398038fd1498Szrj output_operand_lossage ("operand number out of range");
398138fd1498Szrj else
398238fd1498Szrj output_operand (operands[opnum], 0);
398338fd1498Szrj
398438fd1498Szrj if (!opoutput[opnum])
398538fd1498Szrj oporder[ops++] = opnum;
398638fd1498Szrj opoutput[opnum] = 1;
398738fd1498Szrj
398838fd1498Szrj p = endptr;
398938fd1498Szrj c = *p;
399038fd1498Szrj }
399138fd1498Szrj /* % followed by punctuation: output something for that
399238fd1498Szrj punctuation character alone, with no operand. The
399338fd1498Szrj TARGET_PRINT_OPERAND hook decides what is actually done. */
399438fd1498Szrj else if (targetm.asm_out.print_operand_punct_valid_p ((unsigned char) *p))
399538fd1498Szrj output_operand (NULL_RTX, *p++);
399638fd1498Szrj else
399738fd1498Szrj output_operand_lossage ("invalid %%-code");
399838fd1498Szrj break;
399938fd1498Szrj
400038fd1498Szrj default:
400138fd1498Szrj putc (c, asm_out_file);
400238fd1498Szrj }
400338fd1498Szrj
400438fd1498Szrj /* Try to keep the asm a bit more readable. */
400538fd1498Szrj if ((flag_verbose_asm || flag_print_asm_name) && strlen (templ) < 9)
400638fd1498Szrj putc ('\t', asm_out_file);
400738fd1498Szrj
400838fd1498Szrj /* Write out the variable names for operands, if we know them. */
400938fd1498Szrj if (flag_verbose_asm)
401038fd1498Szrj output_asm_operand_names (operands, oporder, ops);
401138fd1498Szrj if (flag_print_asm_name)
401238fd1498Szrj output_asm_name ();
401338fd1498Szrj
401438fd1498Szrj putc ('\n', asm_out_file);
401538fd1498Szrj }
401638fd1498Szrj
401738fd1498Szrj /* Output a LABEL_REF, or a bare CODE_LABEL, as an assembler symbol. */
401838fd1498Szrj
401938fd1498Szrj void
output_asm_label(rtx x)402038fd1498Szrj output_asm_label (rtx x)
402138fd1498Szrj {
402238fd1498Szrj char buf[256];
402338fd1498Szrj
402438fd1498Szrj if (GET_CODE (x) == LABEL_REF)
402538fd1498Szrj x = label_ref_label (x);
402638fd1498Szrj if (LABEL_P (x)
402738fd1498Szrj || (NOTE_P (x)
402838fd1498Szrj && NOTE_KIND (x) == NOTE_INSN_DELETED_LABEL))
402938fd1498Szrj ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
403038fd1498Szrj else
403138fd1498Szrj output_operand_lossage ("'%%l' operand isn't a label");
403238fd1498Szrj
403338fd1498Szrj assemble_name (asm_out_file, buf);
403438fd1498Szrj }
403538fd1498Szrj
403638fd1498Szrj /* Marks SYMBOL_REFs in x as referenced through use of assemble_external. */
403738fd1498Szrj
403838fd1498Szrj void
mark_symbol_refs_as_used(rtx x)403938fd1498Szrj mark_symbol_refs_as_used (rtx x)
404038fd1498Szrj {
404138fd1498Szrj subrtx_iterator::array_type array;
404238fd1498Szrj FOR_EACH_SUBRTX (iter, array, x, ALL)
404338fd1498Szrj {
404438fd1498Szrj const_rtx x = *iter;
404538fd1498Szrj if (GET_CODE (x) == SYMBOL_REF)
404638fd1498Szrj if (tree t = SYMBOL_REF_DECL (x))
404738fd1498Szrj assemble_external (t);
404838fd1498Szrj }
404938fd1498Szrj }
405038fd1498Szrj
405138fd1498Szrj /* Print operand X using machine-dependent assembler syntax.
405238fd1498Szrj CODE is a non-digit that preceded the operand-number in the % spec,
405338fd1498Szrj such as 'z' if the spec was `%z3'. CODE is 0 if there was no char
405438fd1498Szrj between the % and the digits.
405538fd1498Szrj When CODE is a non-letter, X is 0.
405638fd1498Szrj
405738fd1498Szrj The meanings of the letters are machine-dependent and controlled
405838fd1498Szrj by TARGET_PRINT_OPERAND. */
405938fd1498Szrj
406038fd1498Szrj void
output_operand(rtx x,int code ATTRIBUTE_UNUSED)406138fd1498Szrj output_operand (rtx x, int code ATTRIBUTE_UNUSED)
406238fd1498Szrj {
406338fd1498Szrj if (x && GET_CODE (x) == SUBREG)
406438fd1498Szrj x = alter_subreg (&x, true);
406538fd1498Szrj
406638fd1498Szrj /* X must not be a pseudo reg. */
406738fd1498Szrj if (!targetm.no_register_allocation)
406838fd1498Szrj gcc_assert (!x || !REG_P (x) || REGNO (x) < FIRST_PSEUDO_REGISTER);
406938fd1498Szrj
407038fd1498Szrj targetm.asm_out.print_operand (asm_out_file, x, code);
407138fd1498Szrj
407238fd1498Szrj if (x == NULL_RTX)
407338fd1498Szrj return;
407438fd1498Szrj
407538fd1498Szrj mark_symbol_refs_as_used (x);
407638fd1498Szrj }
407738fd1498Szrj
407838fd1498Szrj /* Print a memory reference operand for address X using
407938fd1498Szrj machine-dependent assembler syntax. */
408038fd1498Szrj
408138fd1498Szrj void
output_address(machine_mode mode,rtx x)408238fd1498Szrj output_address (machine_mode mode, rtx x)
408338fd1498Szrj {
408438fd1498Szrj bool changed = false;
408538fd1498Szrj walk_alter_subreg (&x, &changed);
408638fd1498Szrj targetm.asm_out.print_operand_address (asm_out_file, mode, x);
408738fd1498Szrj }
408838fd1498Szrj
408938fd1498Szrj /* Print an integer constant expression in assembler syntax.
409038fd1498Szrj Addition and subtraction are the only arithmetic
409138fd1498Szrj that may appear in these expressions. */
409238fd1498Szrj
409338fd1498Szrj void
output_addr_const(FILE * file,rtx x)409438fd1498Szrj output_addr_const (FILE *file, rtx x)
409538fd1498Szrj {
409638fd1498Szrj char buf[256];
409738fd1498Szrj
409838fd1498Szrj restart:
409938fd1498Szrj switch (GET_CODE (x))
410038fd1498Szrj {
410138fd1498Szrj case PC:
410238fd1498Szrj putc ('.', file);
410338fd1498Szrj break;
410438fd1498Szrj
410538fd1498Szrj case SYMBOL_REF:
410638fd1498Szrj if (SYMBOL_REF_DECL (x))
410738fd1498Szrj assemble_external (SYMBOL_REF_DECL (x));
410838fd1498Szrj #ifdef ASM_OUTPUT_SYMBOL_REF
410938fd1498Szrj ASM_OUTPUT_SYMBOL_REF (file, x);
411038fd1498Szrj #else
411138fd1498Szrj assemble_name (file, XSTR (x, 0));
411238fd1498Szrj #endif
411338fd1498Szrj break;
411438fd1498Szrj
411538fd1498Szrj case LABEL_REF:
411638fd1498Szrj x = label_ref_label (x);
411738fd1498Szrj /* Fall through. */
411838fd1498Szrj case CODE_LABEL:
411938fd1498Szrj ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
412038fd1498Szrj #ifdef ASM_OUTPUT_LABEL_REF
412138fd1498Szrj ASM_OUTPUT_LABEL_REF (file, buf);
412238fd1498Szrj #else
412338fd1498Szrj assemble_name (file, buf);
412438fd1498Szrj #endif
412538fd1498Szrj break;
412638fd1498Szrj
412738fd1498Szrj case CONST_INT:
412838fd1498Szrj fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x));
412938fd1498Szrj break;
413038fd1498Szrj
413138fd1498Szrj case CONST:
413238fd1498Szrj /* This used to output parentheses around the expression,
413338fd1498Szrj but that does not work on the 386 (either ATT or BSD assembler). */
413438fd1498Szrj output_addr_const (file, XEXP (x, 0));
413538fd1498Szrj break;
413638fd1498Szrj
413738fd1498Szrj case CONST_WIDE_INT:
413838fd1498Szrj /* We do not know the mode here so we have to use a round about
413938fd1498Szrj way to build a wide-int to get it printed properly. */
414038fd1498Szrj {
414138fd1498Szrj wide_int w = wide_int::from_array (&CONST_WIDE_INT_ELT (x, 0),
414238fd1498Szrj CONST_WIDE_INT_NUNITS (x),
414338fd1498Szrj CONST_WIDE_INT_NUNITS (x)
414438fd1498Szrj * HOST_BITS_PER_WIDE_INT,
414538fd1498Szrj false);
414638fd1498Szrj print_decs (w, file);
414738fd1498Szrj }
414838fd1498Szrj break;
414938fd1498Szrj
415038fd1498Szrj case CONST_DOUBLE:
415138fd1498Szrj if (CONST_DOUBLE_AS_INT_P (x))
415238fd1498Szrj {
415338fd1498Szrj /* We can use %d if the number is one word and positive. */
415438fd1498Szrj if (CONST_DOUBLE_HIGH (x))
415538fd1498Szrj fprintf (file, HOST_WIDE_INT_PRINT_DOUBLE_HEX,
415638fd1498Szrj (unsigned HOST_WIDE_INT) CONST_DOUBLE_HIGH (x),
415738fd1498Szrj (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (x));
415838fd1498Szrj else if (CONST_DOUBLE_LOW (x) < 0)
415938fd1498Szrj fprintf (file, HOST_WIDE_INT_PRINT_HEX,
416038fd1498Szrj (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (x));
416138fd1498Szrj else
416238fd1498Szrj fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x));
416338fd1498Szrj }
416438fd1498Szrj else
416538fd1498Szrj /* We can't handle floating point constants;
416638fd1498Szrj PRINT_OPERAND must handle them. */
416738fd1498Szrj output_operand_lossage ("floating constant misused");
416838fd1498Szrj break;
416938fd1498Szrj
417038fd1498Szrj case CONST_FIXED:
417138fd1498Szrj fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_FIXED_VALUE_LOW (x));
417238fd1498Szrj break;
417338fd1498Szrj
417438fd1498Szrj case PLUS:
417538fd1498Szrj /* Some assemblers need integer constants to appear last (eg masm). */
417638fd1498Szrj if (CONST_INT_P (XEXP (x, 0)))
417738fd1498Szrj {
417838fd1498Szrj output_addr_const (file, XEXP (x, 1));
417938fd1498Szrj if (INTVAL (XEXP (x, 0)) >= 0)
418038fd1498Szrj fprintf (file, "+");
418138fd1498Szrj output_addr_const (file, XEXP (x, 0));
418238fd1498Szrj }
418338fd1498Szrj else
418438fd1498Szrj {
418538fd1498Szrj output_addr_const (file, XEXP (x, 0));
418638fd1498Szrj if (!CONST_INT_P (XEXP (x, 1))
418738fd1498Szrj || INTVAL (XEXP (x, 1)) >= 0)
418838fd1498Szrj fprintf (file, "+");
418938fd1498Szrj output_addr_const (file, XEXP (x, 1));
419038fd1498Szrj }
419138fd1498Szrj break;
419238fd1498Szrj
419338fd1498Szrj case MINUS:
419438fd1498Szrj /* Avoid outputting things like x-x or x+5-x,
419538fd1498Szrj since some assemblers can't handle that. */
419638fd1498Szrj x = simplify_subtraction (x);
419738fd1498Szrj if (GET_CODE (x) != MINUS)
419838fd1498Szrj goto restart;
419938fd1498Szrj
420038fd1498Szrj output_addr_const (file, XEXP (x, 0));
420138fd1498Szrj fprintf (file, "-");
420238fd1498Szrj if ((CONST_INT_P (XEXP (x, 1)) && INTVAL (XEXP (x, 1)) >= 0)
420338fd1498Szrj || GET_CODE (XEXP (x, 1)) == PC
420438fd1498Szrj || GET_CODE (XEXP (x, 1)) == SYMBOL_REF)
420538fd1498Szrj output_addr_const (file, XEXP (x, 1));
420638fd1498Szrj else
420738fd1498Szrj {
420838fd1498Szrj fputs (targetm.asm_out.open_paren, file);
420938fd1498Szrj output_addr_const (file, XEXP (x, 1));
421038fd1498Szrj fputs (targetm.asm_out.close_paren, file);
421138fd1498Szrj }
421238fd1498Szrj break;
421338fd1498Szrj
421438fd1498Szrj case ZERO_EXTEND:
421538fd1498Szrj case SIGN_EXTEND:
421638fd1498Szrj case SUBREG:
421738fd1498Szrj case TRUNCATE:
421838fd1498Szrj output_addr_const (file, XEXP (x, 0));
421938fd1498Szrj break;
422038fd1498Szrj
422138fd1498Szrj default:
422238fd1498Szrj if (targetm.asm_out.output_addr_const_extra (file, x))
422338fd1498Szrj break;
422438fd1498Szrj
422538fd1498Szrj output_operand_lossage ("invalid expression as operand");
422638fd1498Szrj }
422738fd1498Szrj }
422838fd1498Szrj
422938fd1498Szrj /* Output a quoted string. */
423038fd1498Szrj
423138fd1498Szrj void
output_quoted_string(FILE * asm_file,const char * string)423238fd1498Szrj output_quoted_string (FILE *asm_file, const char *string)
423338fd1498Szrj {
423438fd1498Szrj #ifdef OUTPUT_QUOTED_STRING
423538fd1498Szrj OUTPUT_QUOTED_STRING (asm_file, string);
423638fd1498Szrj #else
423738fd1498Szrj char c;
423838fd1498Szrj
423938fd1498Szrj putc ('\"', asm_file);
424038fd1498Szrj while ((c = *string++) != 0)
424138fd1498Szrj {
424238fd1498Szrj if (ISPRINT (c))
424338fd1498Szrj {
424438fd1498Szrj if (c == '\"' || c == '\\')
424538fd1498Szrj putc ('\\', asm_file);
424638fd1498Szrj putc (c, asm_file);
424738fd1498Szrj }
424838fd1498Szrj else
424938fd1498Szrj fprintf (asm_file, "\\%03o", (unsigned char) c);
425038fd1498Szrj }
425138fd1498Szrj putc ('\"', asm_file);
425238fd1498Szrj #endif
425338fd1498Szrj }
425438fd1498Szrj
425538fd1498Szrj /* Write a HOST_WIDE_INT number in hex form 0x1234, fast. */
425638fd1498Szrj
425738fd1498Szrj void
fprint_whex(FILE * f,unsigned HOST_WIDE_INT value)425838fd1498Szrj fprint_whex (FILE *f, unsigned HOST_WIDE_INT value)
425938fd1498Szrj {
426038fd1498Szrj char buf[2 + CHAR_BIT * sizeof (value) / 4];
426138fd1498Szrj if (value == 0)
426238fd1498Szrj putc ('0', f);
426338fd1498Szrj else
426438fd1498Szrj {
426538fd1498Szrj char *p = buf + sizeof (buf);
426638fd1498Szrj do
426738fd1498Szrj *--p = "0123456789abcdef"[value % 16];
426838fd1498Szrj while ((value /= 16) != 0);
426938fd1498Szrj *--p = 'x';
427038fd1498Szrj *--p = '0';
427138fd1498Szrj fwrite (p, 1, buf + sizeof (buf) - p, f);
427238fd1498Szrj }
427338fd1498Szrj }
427438fd1498Szrj
427538fd1498Szrj /* Internal function that prints an unsigned long in decimal in reverse.
427638fd1498Szrj The output string IS NOT null-terminated. */
427738fd1498Szrj
427838fd1498Szrj static int
sprint_ul_rev(char * s,unsigned long value)427938fd1498Szrj sprint_ul_rev (char *s, unsigned long value)
428038fd1498Szrj {
428138fd1498Szrj int i = 0;
428238fd1498Szrj do
428338fd1498Szrj {
428438fd1498Szrj s[i] = "0123456789"[value % 10];
428538fd1498Szrj value /= 10;
428638fd1498Szrj i++;
428738fd1498Szrj /* alternate version, without modulo */
428838fd1498Szrj /* oldval = value; */
428938fd1498Szrj /* value /= 10; */
429038fd1498Szrj /* s[i] = "0123456789" [oldval - 10*value]; */
429138fd1498Szrj /* i++ */
429238fd1498Szrj }
429338fd1498Szrj while (value != 0);
429438fd1498Szrj return i;
429538fd1498Szrj }
429638fd1498Szrj
429738fd1498Szrj /* Write an unsigned long as decimal to a file, fast. */
429838fd1498Szrj
429938fd1498Szrj void
fprint_ul(FILE * f,unsigned long value)430038fd1498Szrj fprint_ul (FILE *f, unsigned long value)
430138fd1498Szrj {
430238fd1498Szrj /* python says: len(str(2**64)) == 20 */
430338fd1498Szrj char s[20];
430438fd1498Szrj int i;
430538fd1498Szrj
430638fd1498Szrj i = sprint_ul_rev (s, value);
430738fd1498Szrj
430838fd1498Szrj /* It's probably too small to bother with string reversal and fputs. */
430938fd1498Szrj do
431038fd1498Szrj {
431138fd1498Szrj i--;
431238fd1498Szrj putc (s[i], f);
431338fd1498Szrj }
431438fd1498Szrj while (i != 0);
431538fd1498Szrj }
431638fd1498Szrj
431738fd1498Szrj /* Write an unsigned long as decimal to a string, fast.
431838fd1498Szrj s must be wide enough to not overflow, at least 21 chars.
431938fd1498Szrj Returns the length of the string (without terminating '\0'). */
432038fd1498Szrj
432138fd1498Szrj int
sprint_ul(char * s,unsigned long value)432238fd1498Szrj sprint_ul (char *s, unsigned long value)
432338fd1498Szrj {
432438fd1498Szrj int len = sprint_ul_rev (s, value);
432538fd1498Szrj s[len] = '\0';
432638fd1498Szrj
432738fd1498Szrj std::reverse (s, s + len);
432838fd1498Szrj return len;
432938fd1498Szrj }
433038fd1498Szrj
433138fd1498Szrj /* A poor man's fprintf, with the added features of %I, %R, %L, and %U.
433238fd1498Szrj %R prints the value of REGISTER_PREFIX.
433338fd1498Szrj %L prints the value of LOCAL_LABEL_PREFIX.
433438fd1498Szrj %U prints the value of USER_LABEL_PREFIX.
433538fd1498Szrj %I prints the value of IMMEDIATE_PREFIX.
433638fd1498Szrj %O runs ASM_OUTPUT_OPCODE to transform what follows in the string.
433738fd1498Szrj Also supported are %d, %i, %u, %x, %X, %o, %c, %s and %%.
433838fd1498Szrj
433938fd1498Szrj We handle alternate assembler dialects here, just like output_asm_insn. */
434038fd1498Szrj
434138fd1498Szrj void
asm_fprintf(FILE * file,const char * p,...)434238fd1498Szrj asm_fprintf (FILE *file, const char *p, ...)
434338fd1498Szrj {
434438fd1498Szrj char buf[10];
434538fd1498Szrj char *q, c;
434638fd1498Szrj #ifdef ASSEMBLER_DIALECT
434738fd1498Szrj int dialect = 0;
434838fd1498Szrj #endif
434938fd1498Szrj va_list argptr;
435038fd1498Szrj
435138fd1498Szrj va_start (argptr, p);
435238fd1498Szrj
435338fd1498Szrj buf[0] = '%';
435438fd1498Szrj
435538fd1498Szrj while ((c = *p++))
435638fd1498Szrj switch (c)
435738fd1498Szrj {
435838fd1498Szrj #ifdef ASSEMBLER_DIALECT
435938fd1498Szrj case '{':
436038fd1498Szrj case '}':
436138fd1498Szrj case '|':
436238fd1498Szrj p = do_assembler_dialects (p, &dialect);
436338fd1498Szrj break;
436438fd1498Szrj #endif
436538fd1498Szrj
436638fd1498Szrj case '%':
436738fd1498Szrj c = *p++;
436838fd1498Szrj q = &buf[1];
436938fd1498Szrj while (strchr ("-+ #0", c))
437038fd1498Szrj {
437138fd1498Szrj *q++ = c;
437238fd1498Szrj c = *p++;
437338fd1498Szrj }
437438fd1498Szrj while (ISDIGIT (c) || c == '.')
437538fd1498Szrj {
437638fd1498Szrj *q++ = c;
437738fd1498Szrj c = *p++;
437838fd1498Szrj }
437938fd1498Szrj switch (c)
438038fd1498Szrj {
438138fd1498Szrj case '%':
438238fd1498Szrj putc ('%', file);
438338fd1498Szrj break;
438438fd1498Szrj
438538fd1498Szrj case 'd': case 'i': case 'u':
438638fd1498Szrj case 'x': case 'X': case 'o':
438738fd1498Szrj case 'c':
438838fd1498Szrj *q++ = c;
438938fd1498Szrj *q = 0;
439038fd1498Szrj fprintf (file, buf, va_arg (argptr, int));
439138fd1498Szrj break;
439238fd1498Szrj
439338fd1498Szrj case 'w':
439438fd1498Szrj /* This is a prefix to the 'd', 'i', 'u', 'x', 'X', and
439538fd1498Szrj 'o' cases, but we do not check for those cases. It
439638fd1498Szrj means that the value is a HOST_WIDE_INT, which may be
439738fd1498Szrj either `long' or `long long'. */
439838fd1498Szrj memcpy (q, HOST_WIDE_INT_PRINT, strlen (HOST_WIDE_INT_PRINT));
439938fd1498Szrj q += strlen (HOST_WIDE_INT_PRINT);
440038fd1498Szrj *q++ = *p++;
440138fd1498Szrj *q = 0;
440238fd1498Szrj fprintf (file, buf, va_arg (argptr, HOST_WIDE_INT));
440338fd1498Szrj break;
440438fd1498Szrj
440538fd1498Szrj case 'l':
440638fd1498Szrj *q++ = c;
440738fd1498Szrj #ifdef HAVE_LONG_LONG
440838fd1498Szrj if (*p == 'l')
440938fd1498Szrj {
441038fd1498Szrj *q++ = *p++;
441138fd1498Szrj *q++ = *p++;
441238fd1498Szrj *q = 0;
441338fd1498Szrj fprintf (file, buf, va_arg (argptr, long long));
441438fd1498Szrj }
441538fd1498Szrj else
441638fd1498Szrj #endif
441738fd1498Szrj {
441838fd1498Szrj *q++ = *p++;
441938fd1498Szrj *q = 0;
442038fd1498Szrj fprintf (file, buf, va_arg (argptr, long));
442138fd1498Szrj }
442238fd1498Szrj
442338fd1498Szrj break;
442438fd1498Szrj
442538fd1498Szrj case 's':
442638fd1498Szrj *q++ = c;
442738fd1498Szrj *q = 0;
442838fd1498Szrj fprintf (file, buf, va_arg (argptr, char *));
442938fd1498Szrj break;
443038fd1498Szrj
443138fd1498Szrj case 'O':
443238fd1498Szrj #ifdef ASM_OUTPUT_OPCODE
443338fd1498Szrj ASM_OUTPUT_OPCODE (asm_out_file, p);
443438fd1498Szrj #endif
443538fd1498Szrj break;
443638fd1498Szrj
443738fd1498Szrj case 'R':
443838fd1498Szrj #ifdef REGISTER_PREFIX
443938fd1498Szrj fprintf (file, "%s", REGISTER_PREFIX);
444038fd1498Szrj #endif
444138fd1498Szrj break;
444238fd1498Szrj
444338fd1498Szrj case 'I':
444438fd1498Szrj #ifdef IMMEDIATE_PREFIX
444538fd1498Szrj fprintf (file, "%s", IMMEDIATE_PREFIX);
444638fd1498Szrj #endif
444738fd1498Szrj break;
444838fd1498Szrj
444938fd1498Szrj case 'L':
445038fd1498Szrj #ifdef LOCAL_LABEL_PREFIX
445138fd1498Szrj fprintf (file, "%s", LOCAL_LABEL_PREFIX);
445238fd1498Szrj #endif
445338fd1498Szrj break;
445438fd1498Szrj
445538fd1498Szrj case 'U':
445638fd1498Szrj fputs (user_label_prefix, file);
445738fd1498Szrj break;
445838fd1498Szrj
445938fd1498Szrj #ifdef ASM_FPRINTF_EXTENSIONS
446038fd1498Szrj /* Uppercase letters are reserved for general use by asm_fprintf
446138fd1498Szrj and so are not available to target specific code. In order to
446238fd1498Szrj prevent the ASM_FPRINTF_EXTENSIONS macro from using them then,
446338fd1498Szrj they are defined here. As they get turned into real extensions
446438fd1498Szrj to asm_fprintf they should be removed from this list. */
446538fd1498Szrj case 'A': case 'B': case 'C': case 'D': case 'E':
446638fd1498Szrj case 'F': case 'G': case 'H': case 'J': case 'K':
446738fd1498Szrj case 'M': case 'N': case 'P': case 'Q': case 'S':
446838fd1498Szrj case 'T': case 'V': case 'W': case 'Y': case 'Z':
446938fd1498Szrj break;
447038fd1498Szrj
447138fd1498Szrj ASM_FPRINTF_EXTENSIONS (file, argptr, p)
447238fd1498Szrj #endif
447338fd1498Szrj default:
447438fd1498Szrj gcc_unreachable ();
447538fd1498Szrj }
447638fd1498Szrj break;
447738fd1498Szrj
447838fd1498Szrj default:
447938fd1498Szrj putc (c, file);
448038fd1498Szrj }
448138fd1498Szrj va_end (argptr);
448238fd1498Szrj }
448338fd1498Szrj
448438fd1498Szrj /* Return nonzero if this function has no function calls. */
448538fd1498Szrj
448638fd1498Szrj int
leaf_function_p(void)448738fd1498Szrj leaf_function_p (void)
448838fd1498Szrj {
448938fd1498Szrj rtx_insn *insn;
449038fd1498Szrj
449138fd1498Szrj /* Ensure we walk the entire function body. */
449238fd1498Szrj gcc_assert (!in_sequence_p ());
449338fd1498Szrj
449438fd1498Szrj /* Some back-ends (e.g. s390) want leaf functions to stay leaf
449538fd1498Szrj functions even if they call mcount. */
449638fd1498Szrj if (crtl->profile && !targetm.keep_leaf_when_profiled ())
449738fd1498Szrj return 0;
449838fd1498Szrj
449938fd1498Szrj for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
450038fd1498Szrj {
450138fd1498Szrj if (CALL_P (insn)
450238fd1498Szrj && ! SIBLING_CALL_P (insn))
450338fd1498Szrj return 0;
450438fd1498Szrj if (NONJUMP_INSN_P (insn)
450538fd1498Szrj && GET_CODE (PATTERN (insn)) == SEQUENCE
450638fd1498Szrj && CALL_P (XVECEXP (PATTERN (insn), 0, 0))
450738fd1498Szrj && ! SIBLING_CALL_P (XVECEXP (PATTERN (insn), 0, 0)))
450838fd1498Szrj return 0;
450938fd1498Szrj }
451038fd1498Szrj
451138fd1498Szrj return 1;
451238fd1498Szrj }
451338fd1498Szrj
451438fd1498Szrj /* Return 1 if branch is a forward branch.
451538fd1498Szrj Uses insn_shuid array, so it works only in the final pass. May be used by
451638fd1498Szrj output templates to customary add branch prediction hints.
451738fd1498Szrj */
451838fd1498Szrj int
final_forward_branch_p(rtx_insn * insn)451938fd1498Szrj final_forward_branch_p (rtx_insn *insn)
452038fd1498Szrj {
452138fd1498Szrj int insn_id, label_id;
452238fd1498Szrj
452338fd1498Szrj gcc_assert (uid_shuid);
452438fd1498Szrj insn_id = INSN_SHUID (insn);
452538fd1498Szrj label_id = INSN_SHUID (JUMP_LABEL (insn));
452638fd1498Szrj /* We've hit some insns that does not have id information available. */
452738fd1498Szrj gcc_assert (insn_id && label_id);
452838fd1498Szrj return insn_id < label_id;
452938fd1498Szrj }
453038fd1498Szrj
453138fd1498Szrj /* On some machines, a function with no call insns
453238fd1498Szrj can run faster if it doesn't create its own register window.
453338fd1498Szrj When output, the leaf function should use only the "output"
453438fd1498Szrj registers. Ordinarily, the function would be compiled to use
453538fd1498Szrj the "input" registers to find its arguments; it is a candidate
453638fd1498Szrj for leaf treatment if it uses only the "input" registers.
453738fd1498Szrj Leaf function treatment means renumbering so the function
453838fd1498Szrj uses the "output" registers instead. */
453938fd1498Szrj
454038fd1498Szrj #ifdef LEAF_REGISTERS
454138fd1498Szrj
454238fd1498Szrj /* Return 1 if this function uses only the registers that can be
454338fd1498Szrj safely renumbered. */
454438fd1498Szrj
454538fd1498Szrj int
only_leaf_regs_used(void)454638fd1498Szrj only_leaf_regs_used (void)
454738fd1498Szrj {
454838fd1498Szrj int i;
454938fd1498Szrj const char *const permitted_reg_in_leaf_functions = LEAF_REGISTERS;
455038fd1498Szrj
455138fd1498Szrj for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
455238fd1498Szrj if ((df_regs_ever_live_p (i) || global_regs[i])
455338fd1498Szrj && ! permitted_reg_in_leaf_functions[i])
455438fd1498Szrj return 0;
455538fd1498Szrj
455638fd1498Szrj if (crtl->uses_pic_offset_table
455738fd1498Szrj && pic_offset_table_rtx != 0
455838fd1498Szrj && REG_P (pic_offset_table_rtx)
455938fd1498Szrj && ! permitted_reg_in_leaf_functions[REGNO (pic_offset_table_rtx)])
456038fd1498Szrj return 0;
456138fd1498Szrj
456238fd1498Szrj return 1;
456338fd1498Szrj }
456438fd1498Szrj
456538fd1498Szrj /* Scan all instructions and renumber all registers into those
456638fd1498Szrj available in leaf functions. */
456738fd1498Szrj
456838fd1498Szrj static void
leaf_renumber_regs(rtx_insn * first)456938fd1498Szrj leaf_renumber_regs (rtx_insn *first)
457038fd1498Szrj {
457138fd1498Szrj rtx_insn *insn;
457238fd1498Szrj
457338fd1498Szrj /* Renumber only the actual patterns.
457438fd1498Szrj The reg-notes can contain frame pointer refs,
457538fd1498Szrj and renumbering them could crash, and should not be needed. */
457638fd1498Szrj for (insn = first; insn; insn = NEXT_INSN (insn))
457738fd1498Szrj if (INSN_P (insn))
457838fd1498Szrj leaf_renumber_regs_insn (PATTERN (insn));
457938fd1498Szrj }
458038fd1498Szrj
458138fd1498Szrj /* Scan IN_RTX and its subexpressions, and renumber all regs into those
458238fd1498Szrj available in leaf functions. */
458338fd1498Szrj
458438fd1498Szrj void
leaf_renumber_regs_insn(rtx in_rtx)458538fd1498Szrj leaf_renumber_regs_insn (rtx in_rtx)
458638fd1498Szrj {
458738fd1498Szrj int i, j;
458838fd1498Szrj const char *format_ptr;
458938fd1498Szrj
459038fd1498Szrj if (in_rtx == 0)
459138fd1498Szrj return;
459238fd1498Szrj
459338fd1498Szrj /* Renumber all input-registers into output-registers.
459438fd1498Szrj renumbered_regs would be 1 for an output-register;
459538fd1498Szrj they */
459638fd1498Szrj
459738fd1498Szrj if (REG_P (in_rtx))
459838fd1498Szrj {
459938fd1498Szrj int newreg;
460038fd1498Szrj
460138fd1498Szrj /* Don't renumber the same reg twice. */
460238fd1498Szrj if (in_rtx->used)
460338fd1498Szrj return;
460438fd1498Szrj
460538fd1498Szrj newreg = REGNO (in_rtx);
460638fd1498Szrj /* Don't try to renumber pseudo regs. It is possible for a pseudo reg
460738fd1498Szrj to reach here as part of a REG_NOTE. */
460838fd1498Szrj if (newreg >= FIRST_PSEUDO_REGISTER)
460938fd1498Szrj {
461038fd1498Szrj in_rtx->used = 1;
461138fd1498Szrj return;
461238fd1498Szrj }
461338fd1498Szrj newreg = LEAF_REG_REMAP (newreg);
461438fd1498Szrj gcc_assert (newreg >= 0);
461538fd1498Szrj df_set_regs_ever_live (REGNO (in_rtx), false);
461638fd1498Szrj df_set_regs_ever_live (newreg, true);
461738fd1498Szrj SET_REGNO (in_rtx, newreg);
461838fd1498Szrj in_rtx->used = 1;
461938fd1498Szrj return;
462038fd1498Szrj }
462138fd1498Szrj
462238fd1498Szrj if (INSN_P (in_rtx))
462338fd1498Szrj {
462438fd1498Szrj /* Inside a SEQUENCE, we find insns.
462538fd1498Szrj Renumber just the patterns of these insns,
462638fd1498Szrj just as we do for the top-level insns. */
462738fd1498Szrj leaf_renumber_regs_insn (PATTERN (in_rtx));
462838fd1498Szrj return;
462938fd1498Szrj }
463038fd1498Szrj
463138fd1498Szrj format_ptr = GET_RTX_FORMAT (GET_CODE (in_rtx));
463238fd1498Szrj
463338fd1498Szrj for (i = 0; i < GET_RTX_LENGTH (GET_CODE (in_rtx)); i++)
463438fd1498Szrj switch (*format_ptr++)
463538fd1498Szrj {
463638fd1498Szrj case 'e':
463738fd1498Szrj leaf_renumber_regs_insn (XEXP (in_rtx, i));
463838fd1498Szrj break;
463938fd1498Szrj
464038fd1498Szrj case 'E':
464138fd1498Szrj if (XVEC (in_rtx, i) != NULL)
464238fd1498Szrj for (j = 0; j < XVECLEN (in_rtx, i); j++)
464338fd1498Szrj leaf_renumber_regs_insn (XVECEXP (in_rtx, i, j));
464438fd1498Szrj break;
464538fd1498Szrj
464638fd1498Szrj case 'S':
464738fd1498Szrj case 's':
464838fd1498Szrj case '0':
464938fd1498Szrj case 'i':
465038fd1498Szrj case 'w':
465138fd1498Szrj case 'p':
465238fd1498Szrj case 'n':
465338fd1498Szrj case 'u':
465438fd1498Szrj break;
465538fd1498Szrj
465638fd1498Szrj default:
465738fd1498Szrj gcc_unreachable ();
465838fd1498Szrj }
465938fd1498Szrj }
466038fd1498Szrj #endif
466138fd1498Szrj
466238fd1498Szrj /* Turn the RTL into assembly. */
466338fd1498Szrj static unsigned int
rest_of_handle_final(void)466438fd1498Szrj rest_of_handle_final (void)
466538fd1498Szrj {
466638fd1498Szrj const char *fnname = get_fnname_from_decl (current_function_decl);
466738fd1498Szrj
466838fd1498Szrj /* Turn debug markers into notes if the var-tracking pass has not
466938fd1498Szrj been invoked. */
467038fd1498Szrj if (!flag_var_tracking && MAY_HAVE_DEBUG_MARKER_INSNS)
467138fd1498Szrj delete_vta_debug_insns (false);
467238fd1498Szrj
467338fd1498Szrj assemble_start_function (current_function_decl, fnname);
467438fd1498Szrj rtx_insn *first = get_insns ();
467538fd1498Szrj int seen = 0;
467638fd1498Szrj final_start_function_1 (&first, asm_out_file, &seen, optimize);
467738fd1498Szrj final_1 (first, asm_out_file, seen, optimize);
467838fd1498Szrj if (flag_ipa_ra
4679*58e805e6Szrj && !lookup_attribute ("noipa", DECL_ATTRIBUTES (current_function_decl))
4680*58e805e6Szrj /* Functions with naked attributes are supported only with basic asm
4681*58e805e6Szrj statements in the body, thus for supported use cases the information
4682*58e805e6Szrj on clobbered registers is not available. */
4683*58e805e6Szrj && !lookup_attribute ("naked", DECL_ATTRIBUTES (current_function_decl)))
468438fd1498Szrj collect_fn_hard_reg_usage ();
468538fd1498Szrj final_end_function ();
468638fd1498Szrj
468738fd1498Szrj /* The IA-64 ".handlerdata" directive must be issued before the ".endp"
468838fd1498Szrj directive that closes the procedure descriptor. Similarly, for x64 SEH.
468938fd1498Szrj Otherwise it's not strictly necessary, but it doesn't hurt either. */
469038fd1498Szrj output_function_exception_table (crtl->has_bb_partition ? 1 : 0);
469138fd1498Szrj
469238fd1498Szrj assemble_end_function (current_function_decl, fnname);
469338fd1498Szrj
469438fd1498Szrj /* Free up reg info memory. */
469538fd1498Szrj free_reg_info ();
469638fd1498Szrj
469738fd1498Szrj if (! quiet_flag)
469838fd1498Szrj fflush (asm_out_file);
469938fd1498Szrj
470038fd1498Szrj /* Write DBX symbols if requested. */
470138fd1498Szrj
470238fd1498Szrj /* Note that for those inline functions where we don't initially
470338fd1498Szrj know for certain that we will be generating an out-of-line copy,
470438fd1498Szrj the first invocation of this routine (rest_of_compilation) will
470538fd1498Szrj skip over this code by doing a `goto exit_rest_of_compilation;'.
470638fd1498Szrj Later on, wrapup_global_declarations will (indirectly) call
470738fd1498Szrj rest_of_compilation again for those inline functions that need
470838fd1498Szrj to have out-of-line copies generated. During that call, we
470938fd1498Szrj *will* be routed past here. */
471038fd1498Szrj
471138fd1498Szrj timevar_push (TV_SYMOUT);
471238fd1498Szrj if (!DECL_IGNORED_P (current_function_decl))
471338fd1498Szrj debug_hooks->function_decl (current_function_decl);
471438fd1498Szrj timevar_pop (TV_SYMOUT);
471538fd1498Szrj
471638fd1498Szrj /* Release the blocks that are linked to DECL_INITIAL() to free the memory. */
471738fd1498Szrj DECL_INITIAL (current_function_decl) = error_mark_node;
471838fd1498Szrj
471938fd1498Szrj if (DECL_STATIC_CONSTRUCTOR (current_function_decl)
472038fd1498Szrj && targetm.have_ctors_dtors)
472138fd1498Szrj targetm.asm_out.constructor (XEXP (DECL_RTL (current_function_decl), 0),
472238fd1498Szrj decl_init_priority_lookup
472338fd1498Szrj (current_function_decl));
472438fd1498Szrj if (DECL_STATIC_DESTRUCTOR (current_function_decl)
472538fd1498Szrj && targetm.have_ctors_dtors)
472638fd1498Szrj targetm.asm_out.destructor (XEXP (DECL_RTL (current_function_decl), 0),
472738fd1498Szrj decl_fini_priority_lookup
472838fd1498Szrj (current_function_decl));
472938fd1498Szrj return 0;
473038fd1498Szrj }
473138fd1498Szrj
473238fd1498Szrj namespace {
473338fd1498Szrj
473438fd1498Szrj const pass_data pass_data_final =
473538fd1498Szrj {
473638fd1498Szrj RTL_PASS, /* type */
473738fd1498Szrj "final", /* name */
473838fd1498Szrj OPTGROUP_NONE, /* optinfo_flags */
473938fd1498Szrj TV_FINAL, /* tv_id */
474038fd1498Szrj 0, /* properties_required */
474138fd1498Szrj 0, /* properties_provided */
474238fd1498Szrj 0, /* properties_destroyed */
474338fd1498Szrj 0, /* todo_flags_start */
474438fd1498Szrj 0, /* todo_flags_finish */
474538fd1498Szrj };
474638fd1498Szrj
474738fd1498Szrj class pass_final : public rtl_opt_pass
474838fd1498Szrj {
474938fd1498Szrj public:
pass_final(gcc::context * ctxt)475038fd1498Szrj pass_final (gcc::context *ctxt)
475138fd1498Szrj : rtl_opt_pass (pass_data_final, ctxt)
475238fd1498Szrj {}
475338fd1498Szrj
475438fd1498Szrj /* opt_pass methods: */
execute(function *)475538fd1498Szrj virtual unsigned int execute (function *) { return rest_of_handle_final (); }
475638fd1498Szrj
475738fd1498Szrj }; // class pass_final
475838fd1498Szrj
475938fd1498Szrj } // anon namespace
476038fd1498Szrj
476138fd1498Szrj rtl_opt_pass *
make_pass_final(gcc::context * ctxt)476238fd1498Szrj make_pass_final (gcc::context *ctxt)
476338fd1498Szrj {
476438fd1498Szrj return new pass_final (ctxt);
476538fd1498Szrj }
476638fd1498Szrj
476738fd1498Szrj
476838fd1498Szrj static unsigned int
rest_of_handle_shorten_branches(void)476938fd1498Szrj rest_of_handle_shorten_branches (void)
477038fd1498Szrj {
477138fd1498Szrj /* Shorten branches. */
477238fd1498Szrj shorten_branches (get_insns ());
477338fd1498Szrj return 0;
477438fd1498Szrj }
477538fd1498Szrj
477638fd1498Szrj namespace {
477738fd1498Szrj
477838fd1498Szrj const pass_data pass_data_shorten_branches =
477938fd1498Szrj {
478038fd1498Szrj RTL_PASS, /* type */
478138fd1498Szrj "shorten", /* name */
478238fd1498Szrj OPTGROUP_NONE, /* optinfo_flags */
478338fd1498Szrj TV_SHORTEN_BRANCH, /* tv_id */
478438fd1498Szrj 0, /* properties_required */
478538fd1498Szrj 0, /* properties_provided */
478638fd1498Szrj 0, /* properties_destroyed */
478738fd1498Szrj 0, /* todo_flags_start */
478838fd1498Szrj 0, /* todo_flags_finish */
478938fd1498Szrj };
479038fd1498Szrj
479138fd1498Szrj class pass_shorten_branches : public rtl_opt_pass
479238fd1498Szrj {
479338fd1498Szrj public:
pass_shorten_branches(gcc::context * ctxt)479438fd1498Szrj pass_shorten_branches (gcc::context *ctxt)
479538fd1498Szrj : rtl_opt_pass (pass_data_shorten_branches, ctxt)
479638fd1498Szrj {}
479738fd1498Szrj
479838fd1498Szrj /* opt_pass methods: */
execute(function *)479938fd1498Szrj virtual unsigned int execute (function *)
480038fd1498Szrj {
480138fd1498Szrj return rest_of_handle_shorten_branches ();
480238fd1498Szrj }
480338fd1498Szrj
480438fd1498Szrj }; // class pass_shorten_branches
480538fd1498Szrj
480638fd1498Szrj } // anon namespace
480738fd1498Szrj
480838fd1498Szrj rtl_opt_pass *
make_pass_shorten_branches(gcc::context * ctxt)480938fd1498Szrj make_pass_shorten_branches (gcc::context *ctxt)
481038fd1498Szrj {
481138fd1498Szrj return new pass_shorten_branches (ctxt);
481238fd1498Szrj }
481338fd1498Szrj
481438fd1498Szrj
481538fd1498Szrj static unsigned int
rest_of_clean_state(void)481638fd1498Szrj rest_of_clean_state (void)
481738fd1498Szrj {
481838fd1498Szrj rtx_insn *insn, *next;
481938fd1498Szrj FILE *final_output = NULL;
482038fd1498Szrj int save_unnumbered = flag_dump_unnumbered;
482138fd1498Szrj int save_noaddr = flag_dump_noaddr;
482238fd1498Szrj
482338fd1498Szrj if (flag_dump_final_insns)
482438fd1498Szrj {
482538fd1498Szrj final_output = fopen (flag_dump_final_insns, "a");
482638fd1498Szrj if (!final_output)
482738fd1498Szrj {
482838fd1498Szrj error ("could not open final insn dump file %qs: %m",
482938fd1498Szrj flag_dump_final_insns);
483038fd1498Szrj flag_dump_final_insns = NULL;
483138fd1498Szrj }
483238fd1498Szrj else
483338fd1498Szrj {
483438fd1498Szrj flag_dump_noaddr = flag_dump_unnumbered = 1;
483538fd1498Szrj if (flag_compare_debug_opt || flag_compare_debug)
483638fd1498Szrj dump_flags |= TDF_NOUID | TDF_COMPARE_DEBUG;
483738fd1498Szrj dump_function_header (final_output, current_function_decl,
483838fd1498Szrj dump_flags);
483938fd1498Szrj final_insns_dump_p = true;
484038fd1498Szrj
484138fd1498Szrj for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
484238fd1498Szrj if (LABEL_P (insn))
484338fd1498Szrj INSN_UID (insn) = CODE_LABEL_NUMBER (insn);
484438fd1498Szrj else
484538fd1498Szrj {
484638fd1498Szrj if (NOTE_P (insn))
484738fd1498Szrj set_block_for_insn (insn, NULL);
484838fd1498Szrj INSN_UID (insn) = 0;
484938fd1498Szrj }
485038fd1498Szrj }
485138fd1498Szrj }
485238fd1498Szrj
485338fd1498Szrj /* It is very important to decompose the RTL instruction chain here:
485438fd1498Szrj debug information keeps pointing into CODE_LABEL insns inside the function
485538fd1498Szrj body. If these remain pointing to the other insns, we end up preserving
485638fd1498Szrj whole RTL chain and attached detailed debug info in memory. */
485738fd1498Szrj for (insn = get_insns (); insn; insn = next)
485838fd1498Szrj {
485938fd1498Szrj next = NEXT_INSN (insn);
486038fd1498Szrj SET_NEXT_INSN (insn) = NULL;
486138fd1498Szrj SET_PREV_INSN (insn) = NULL;
486238fd1498Szrj
486338fd1498Szrj rtx_insn *call_insn = insn;
486438fd1498Szrj if (NONJUMP_INSN_P (call_insn)
486538fd1498Szrj && GET_CODE (PATTERN (call_insn)) == SEQUENCE)
486638fd1498Szrj {
486738fd1498Szrj rtx_sequence *seq = as_a <rtx_sequence *> (PATTERN (call_insn));
486838fd1498Szrj call_insn = seq->insn (0);
486938fd1498Szrj }
487038fd1498Szrj if (CALL_P (call_insn))
487138fd1498Szrj {
487238fd1498Szrj rtx note
487338fd1498Szrj = find_reg_note (call_insn, REG_CALL_ARG_LOCATION, NULL_RTX);
487438fd1498Szrj if (note)
487538fd1498Szrj remove_note (call_insn, note);
487638fd1498Szrj }
487738fd1498Szrj
487838fd1498Szrj if (final_output
487938fd1498Szrj && (!NOTE_P (insn)
488038fd1498Szrj || (NOTE_KIND (insn) != NOTE_INSN_VAR_LOCATION
488138fd1498Szrj && NOTE_KIND (insn) != NOTE_INSN_BEGIN_STMT
488238fd1498Szrj && NOTE_KIND (insn) != NOTE_INSN_INLINE_ENTRY
488338fd1498Szrj && NOTE_KIND (insn) != NOTE_INSN_BLOCK_BEG
488438fd1498Szrj && NOTE_KIND (insn) != NOTE_INSN_BLOCK_END
488538fd1498Szrj && NOTE_KIND (insn) != NOTE_INSN_DELETED_DEBUG_LABEL)))
488638fd1498Szrj print_rtl_single (final_output, insn);
488738fd1498Szrj }
488838fd1498Szrj
488938fd1498Szrj if (final_output)
489038fd1498Szrj {
489138fd1498Szrj flag_dump_noaddr = save_noaddr;
489238fd1498Szrj flag_dump_unnumbered = save_unnumbered;
489338fd1498Szrj final_insns_dump_p = false;
489438fd1498Szrj
489538fd1498Szrj if (fclose (final_output))
489638fd1498Szrj {
489738fd1498Szrj error ("could not close final insn dump file %qs: %m",
489838fd1498Szrj flag_dump_final_insns);
489938fd1498Szrj flag_dump_final_insns = NULL;
490038fd1498Szrj }
490138fd1498Szrj }
490238fd1498Szrj
490338fd1498Szrj flag_rerun_cse_after_global_opts = 0;
490438fd1498Szrj reload_completed = 0;
490538fd1498Szrj epilogue_completed = 0;
490638fd1498Szrj #ifdef STACK_REGS
490738fd1498Szrj regstack_completed = 0;
490838fd1498Szrj #endif
490938fd1498Szrj
491038fd1498Szrj /* Clear out the insn_length contents now that they are no
491138fd1498Szrj longer valid. */
491238fd1498Szrj init_insn_lengths ();
491338fd1498Szrj
491438fd1498Szrj /* Show no temporary slots allocated. */
491538fd1498Szrj init_temp_slots ();
491638fd1498Szrj
491738fd1498Szrj free_bb_for_insn ();
491838fd1498Szrj
491938fd1498Szrj if (cfun->gimple_df)
492038fd1498Szrj delete_tree_ssa (cfun);
492138fd1498Szrj
492238fd1498Szrj /* We can reduce stack alignment on call site only when we are sure that
492338fd1498Szrj the function body just produced will be actually used in the final
492438fd1498Szrj executable. */
492538fd1498Szrj if (decl_binds_to_current_def_p (current_function_decl))
492638fd1498Szrj {
492738fd1498Szrj unsigned int pref = crtl->preferred_stack_boundary;
492838fd1498Szrj if (crtl->stack_alignment_needed > crtl->preferred_stack_boundary)
492938fd1498Szrj pref = crtl->stack_alignment_needed;
493038fd1498Szrj cgraph_node::rtl_info (current_function_decl)
493138fd1498Szrj ->preferred_incoming_stack_boundary = pref;
493238fd1498Szrj }
493338fd1498Szrj
493438fd1498Szrj /* Make sure volatile mem refs aren't considered valid operands for
493538fd1498Szrj arithmetic insns. We must call this here if this is a nested inline
493638fd1498Szrj function, since the above code leaves us in the init_recog state,
493738fd1498Szrj and the function context push/pop code does not save/restore volatile_ok.
493838fd1498Szrj
493938fd1498Szrj ??? Maybe it isn't necessary for expand_start_function to call this
494038fd1498Szrj anymore if we do it here? */
494138fd1498Szrj
494238fd1498Szrj init_recog_no_volatile ();
494338fd1498Szrj
494438fd1498Szrj /* We're done with this function. Free up memory if we can. */
494538fd1498Szrj free_after_parsing (cfun);
494638fd1498Szrj free_after_compilation (cfun);
494738fd1498Szrj return 0;
494838fd1498Szrj }
494938fd1498Szrj
495038fd1498Szrj namespace {
495138fd1498Szrj
495238fd1498Szrj const pass_data pass_data_clean_state =
495338fd1498Szrj {
495438fd1498Szrj RTL_PASS, /* type */
495538fd1498Szrj "*clean_state", /* name */
495638fd1498Szrj OPTGROUP_NONE, /* optinfo_flags */
495738fd1498Szrj TV_FINAL, /* tv_id */
495838fd1498Szrj 0, /* properties_required */
495938fd1498Szrj 0, /* properties_provided */
496038fd1498Szrj PROP_rtl, /* properties_destroyed */
496138fd1498Szrj 0, /* todo_flags_start */
496238fd1498Szrj 0, /* todo_flags_finish */
496338fd1498Szrj };
496438fd1498Szrj
496538fd1498Szrj class pass_clean_state : public rtl_opt_pass
496638fd1498Szrj {
496738fd1498Szrj public:
pass_clean_state(gcc::context * ctxt)496838fd1498Szrj pass_clean_state (gcc::context *ctxt)
496938fd1498Szrj : rtl_opt_pass (pass_data_clean_state, ctxt)
497038fd1498Szrj {}
497138fd1498Szrj
497238fd1498Szrj /* opt_pass methods: */
execute(function *)497338fd1498Szrj virtual unsigned int execute (function *)
497438fd1498Szrj {
497538fd1498Szrj return rest_of_clean_state ();
497638fd1498Szrj }
497738fd1498Szrj
497838fd1498Szrj }; // class pass_clean_state
497938fd1498Szrj
498038fd1498Szrj } // anon namespace
498138fd1498Szrj
498238fd1498Szrj rtl_opt_pass *
make_pass_clean_state(gcc::context * ctxt)498338fd1498Szrj make_pass_clean_state (gcc::context *ctxt)
498438fd1498Szrj {
498538fd1498Szrj return new pass_clean_state (ctxt);
498638fd1498Szrj }
498738fd1498Szrj
498838fd1498Szrj /* Return true if INSN is a call to the current function. */
498938fd1498Szrj
499038fd1498Szrj static bool
self_recursive_call_p(rtx_insn * insn)499138fd1498Szrj self_recursive_call_p (rtx_insn *insn)
499238fd1498Szrj {
499338fd1498Szrj tree fndecl = get_call_fndecl (insn);
499438fd1498Szrj return (fndecl == current_function_decl
499538fd1498Szrj && decl_binds_to_current_def_p (fndecl));
499638fd1498Szrj }
499738fd1498Szrj
499838fd1498Szrj /* Collect hard register usage for the current function. */
499938fd1498Szrj
500038fd1498Szrj static void
collect_fn_hard_reg_usage(void)500138fd1498Szrj collect_fn_hard_reg_usage (void)
500238fd1498Szrj {
500338fd1498Szrj rtx_insn *insn;
500438fd1498Szrj #ifdef STACK_REGS
500538fd1498Szrj int i;
500638fd1498Szrj #endif
500738fd1498Szrj struct cgraph_rtl_info *node;
500838fd1498Szrj HARD_REG_SET function_used_regs;
500938fd1498Szrj
501038fd1498Szrj /* ??? To be removed when all the ports have been fixed. */
501138fd1498Szrj if (!targetm.call_fusage_contains_non_callee_clobbers)
501238fd1498Szrj return;
501338fd1498Szrj
501438fd1498Szrj CLEAR_HARD_REG_SET (function_used_regs);
501538fd1498Szrj
501638fd1498Szrj for (insn = get_insns (); insn != NULL_RTX; insn = next_insn (insn))
501738fd1498Szrj {
501838fd1498Szrj HARD_REG_SET insn_used_regs;
501938fd1498Szrj
502038fd1498Szrj if (!NONDEBUG_INSN_P (insn))
502138fd1498Szrj continue;
502238fd1498Szrj
502338fd1498Szrj if (CALL_P (insn)
502438fd1498Szrj && !self_recursive_call_p (insn))
502538fd1498Szrj {
502638fd1498Szrj if (!get_call_reg_set_usage (insn, &insn_used_regs,
502738fd1498Szrj call_used_reg_set))
502838fd1498Szrj return;
502938fd1498Szrj
503038fd1498Szrj IOR_HARD_REG_SET (function_used_regs, insn_used_regs);
503138fd1498Szrj }
503238fd1498Szrj
503338fd1498Szrj find_all_hard_reg_sets (insn, &insn_used_regs, false);
503438fd1498Szrj IOR_HARD_REG_SET (function_used_regs, insn_used_regs);
503538fd1498Szrj }
503638fd1498Szrj
503738fd1498Szrj /* Be conservative - mark fixed and global registers as used. */
503838fd1498Szrj IOR_HARD_REG_SET (function_used_regs, fixed_reg_set);
503938fd1498Szrj
504038fd1498Szrj #ifdef STACK_REGS
504138fd1498Szrj /* Handle STACK_REGS conservatively, since the df-framework does not
504238fd1498Szrj provide accurate information for them. */
504338fd1498Szrj
504438fd1498Szrj for (i = FIRST_STACK_REG; i <= LAST_STACK_REG; i++)
504538fd1498Szrj SET_HARD_REG_BIT (function_used_regs, i);
504638fd1498Szrj #endif
504738fd1498Szrj
504838fd1498Szrj /* The information we have gathered is only interesting if it exposes a
504938fd1498Szrj register from the call_used_regs that is not used in this function. */
505038fd1498Szrj if (hard_reg_set_subset_p (call_used_reg_set, function_used_regs))
505138fd1498Szrj return;
505238fd1498Szrj
505338fd1498Szrj node = cgraph_node::rtl_info (current_function_decl);
505438fd1498Szrj gcc_assert (node != NULL);
505538fd1498Szrj
505638fd1498Szrj COPY_HARD_REG_SET (node->function_used_regs, function_used_regs);
505738fd1498Szrj node->function_used_regs_valid = 1;
505838fd1498Szrj }
505938fd1498Szrj
506038fd1498Szrj /* Get the declaration of the function called by INSN. */
506138fd1498Szrj
506238fd1498Szrj static tree
get_call_fndecl(rtx_insn * insn)506338fd1498Szrj get_call_fndecl (rtx_insn *insn)
506438fd1498Szrj {
506538fd1498Szrj rtx note, datum;
506638fd1498Szrj
506738fd1498Szrj note = find_reg_note (insn, REG_CALL_DECL, NULL_RTX);
506838fd1498Szrj if (note == NULL_RTX)
506938fd1498Szrj return NULL_TREE;
507038fd1498Szrj
507138fd1498Szrj datum = XEXP (note, 0);
507238fd1498Szrj if (datum != NULL_RTX)
507338fd1498Szrj return SYMBOL_REF_DECL (datum);
507438fd1498Szrj
507538fd1498Szrj return NULL_TREE;
507638fd1498Szrj }
507738fd1498Szrj
507838fd1498Szrj /* Return the cgraph_rtl_info of the function called by INSN. Returns NULL for
507938fd1498Szrj call targets that can be overwritten. */
508038fd1498Szrj
508138fd1498Szrj static struct cgraph_rtl_info *
get_call_cgraph_rtl_info(rtx_insn * insn)508238fd1498Szrj get_call_cgraph_rtl_info (rtx_insn *insn)
508338fd1498Szrj {
508438fd1498Szrj tree fndecl;
508538fd1498Szrj
508638fd1498Szrj if (insn == NULL_RTX)
508738fd1498Szrj return NULL;
508838fd1498Szrj
508938fd1498Szrj fndecl = get_call_fndecl (insn);
509038fd1498Szrj if (fndecl == NULL_TREE
509138fd1498Szrj || !decl_binds_to_current_def_p (fndecl))
509238fd1498Szrj return NULL;
509338fd1498Szrj
509438fd1498Szrj return cgraph_node::rtl_info (fndecl);
509538fd1498Szrj }
509638fd1498Szrj
509738fd1498Szrj /* Find hard registers used by function call instruction INSN, and return them
509838fd1498Szrj in REG_SET. Return DEFAULT_SET in REG_SET if not found. */
509938fd1498Szrj
510038fd1498Szrj bool
get_call_reg_set_usage(rtx_insn * insn,HARD_REG_SET * reg_set,HARD_REG_SET default_set)510138fd1498Szrj get_call_reg_set_usage (rtx_insn *insn, HARD_REG_SET *reg_set,
510238fd1498Szrj HARD_REG_SET default_set)
510338fd1498Szrj {
510438fd1498Szrj if (flag_ipa_ra)
510538fd1498Szrj {
510638fd1498Szrj struct cgraph_rtl_info *node = get_call_cgraph_rtl_info (insn);
510738fd1498Szrj if (node != NULL
510838fd1498Szrj && node->function_used_regs_valid)
510938fd1498Szrj {
511038fd1498Szrj COPY_HARD_REG_SET (*reg_set, node->function_used_regs);
511138fd1498Szrj AND_HARD_REG_SET (*reg_set, default_set);
511238fd1498Szrj return true;
511338fd1498Szrj }
511438fd1498Szrj }
511538fd1498Szrj
511638fd1498Szrj COPY_HARD_REG_SET (*reg_set, default_set);
511738fd1498Szrj return false;
511838fd1498Szrj }
5119