xref: /dflybsd-src/contrib/gcc-8.0/gcc/final.c (revision 95059079af47f9a66a175f374f2da1a5020e3255)
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