arm.c revision 117395
190075Sobrien/* Output routines for GCC for ARM.
290075Sobrien   Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
390075Sobrien   Free Software Foundation, Inc.
490075Sobrien   Contributed by Pieter `Tiggr' Schoenmakers (rcpieter@win.tue.nl)
590075Sobrien   and Martin Simmons (@harleqn.co.uk).
690075Sobrien   More major hacks by Richard Earnshaw (rearnsha@arm.com).
790075Sobrien
890075SobrienThis file is part of GNU CC.
990075Sobrien
1090075SobrienGNU CC is free software; you can redistribute it and/or modify
1190075Sobrienit under the terms of the GNU General Public License as published by
1290075Sobrienthe Free Software Foundation; either version 2, or (at your option)
1390075Sobrienany later version.
1490075Sobrien
1590075SobrienGNU CC is distributed in the hope that it will be useful,
1690075Sobrienbut WITHOUT ANY WARRANTY; without even the implied warranty of
1790075SobrienMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1890075SobrienGNU General Public License for more details.
1990075Sobrien
2090075SobrienYou should have received a copy of the GNU General Public License
2190075Sobrienalong with GNU CC; see the file COPYING.  If not, write to
2290075Sobrienthe Free Software Foundation, 59 Temple Place - Suite 330,
2390075SobrienBoston, MA 02111-1307, USA.  */
2490075Sobrien
2590075Sobrien#include "config.h"
2690075Sobrien#include "system.h"
2790075Sobrien#include "rtl.h"
2890075Sobrien#include "tree.h"
2990075Sobrien#include "obstack.h"
3090075Sobrien#include "regs.h"
3190075Sobrien#include "hard-reg-set.h"
3290075Sobrien#include "real.h"
3390075Sobrien#include "insn-config.h"
3490075Sobrien#include "conditions.h"
3590075Sobrien#include "output.h"
3690075Sobrien#include "insn-attr.h"
3790075Sobrien#include "flags.h"
3890075Sobrien#include "reload.h"
3990075Sobrien#include "function.h"
4090075Sobrien#include "expr.h"
4190075Sobrien#include "optabs.h"
4290075Sobrien#include "toplev.h"
4390075Sobrien#include "recog.h"
4490075Sobrien#include "ggc.h"
4590075Sobrien#include "except.h"
4690075Sobrien#include "c-pragma.h"
4790075Sobrien#include "integrate.h"
4890075Sobrien#include "tm_p.h"
4990075Sobrien#include "target.h"
5090075Sobrien#include "target-def.h"
5190075Sobrien
5290075Sobrien/* Forward definitions of types.  */
5390075Sobrientypedef struct minipool_node    Mnode;
5490075Sobrientypedef struct minipool_fixup   Mfix;
5590075Sobrien
5690075Sobrien/* In order to improve the layout of the prototypes below
5790075Sobrien   some short type abbreviations are defined here.  */
5890075Sobrien#define Hint     HOST_WIDE_INT
5990075Sobrien#define Mmode    enum machine_mode
6090075Sobrien#define Ulong    unsigned long
6190075Sobrien#define Ccstar   const char *
6290075Sobrien
6390075Sobrienconst struct attribute_spec arm_attribute_table[];
6490075Sobrien
6590075Sobrien/* Forward function declarations.  */
6690075Sobrienstatic void      arm_add_gc_roots 		PARAMS ((void));
6790075Sobrienstatic int       arm_gen_constant		PARAMS ((enum rtx_code, Mmode, Hint, rtx, rtx, int, int));
68117395Skanstatic unsigned  bit_count 			PARAMS ((Ulong));
6990075Sobrienstatic int       const_ok_for_op 		PARAMS ((Hint, enum rtx_code));
7090075Sobrienstatic rtx	 emit_multi_reg_push		PARAMS ((int));
7190075Sobrienstatic rtx	 emit_sfm			PARAMS ((int, int));
7290075Sobrien#ifndef AOF_ASSEMBLER
7390075Sobrienstatic bool	 arm_assemble_integer		PARAMS ((rtx, unsigned int, int));
7490075Sobrien#endif
7590075Sobrienstatic Ccstar    fp_const_from_val		PARAMS ((REAL_VALUE_TYPE *));
7690075Sobrienstatic arm_cc    get_arm_condition_code		PARAMS ((rtx));
7790075Sobrienstatic void      init_fpa_table			PARAMS ((void));
7890075Sobrienstatic Hint      int_log2			PARAMS ((Hint));
7990075Sobrienstatic rtx       is_jump_table 			PARAMS ((rtx));
8090075Sobrienstatic Ccstar    output_multi_immediate		PARAMS ((rtx *, Ccstar, Ccstar, int, Hint));
8190075Sobrienstatic void      print_multi_reg		PARAMS ((FILE *, Ccstar, int, int));
8290075Sobrienstatic Mmode     select_dominance_cc_mode	PARAMS ((rtx, rtx, Hint));
8390075Sobrienstatic Ccstar    shift_op			PARAMS ((rtx, Hint *));
84117395Skanstatic struct machine_function * arm_init_machine_status PARAMS ((void));
8590075Sobrienstatic int       number_of_first_bit_set        PARAMS ((int));
8690075Sobrienstatic void      replace_symbols_in_block       PARAMS ((tree, rtx, rtx));
8790075Sobrienstatic void      thumb_exit                     PARAMS ((FILE *, int, rtx));
8890075Sobrienstatic void      thumb_pushpop                  PARAMS ((FILE *, int, int));
8990075Sobrienstatic Ccstar    thumb_condition_code           PARAMS ((rtx, int));
9090075Sobrienstatic rtx	 is_jump_table		        PARAMS ((rtx));
9190075Sobrienstatic Hint	 get_jump_table_size	        PARAMS ((rtx));
9290075Sobrienstatic Mnode *   move_minipool_fix_forward_ref  PARAMS ((Mnode *, Mnode *, Hint));
9390075Sobrienstatic Mnode *   add_minipool_forward_ref	PARAMS ((Mfix *));
9490075Sobrienstatic Mnode *   move_minipool_fix_backward_ref PARAMS ((Mnode *, Mnode *, Hint));
9590075Sobrienstatic Mnode *   add_minipool_backward_ref      PARAMS ((Mfix *));
9690075Sobrienstatic void	 assign_minipool_offsets	PARAMS ((Mfix *));
9790075Sobrienstatic void	 arm_print_value		PARAMS ((FILE *, rtx));
9890075Sobrienstatic void	 dump_minipool		        PARAMS ((rtx));
9990075Sobrienstatic int	 arm_barrier_cost		PARAMS ((rtx));
10090075Sobrienstatic Mfix *    create_fix_barrier		PARAMS ((Mfix *, Hint));
10190075Sobrienstatic void	 push_minipool_barrier	        PARAMS ((rtx, Hint));
10290075Sobrienstatic void	 push_minipool_fix		PARAMS ((rtx, Hint, rtx *, Mmode, rtx));
10390075Sobrienstatic void	 note_invalid_constants	        PARAMS ((rtx, Hint));
10490075Sobrienstatic int       current_file_function_operand	PARAMS ((rtx));
10590075Sobrienstatic Ulong	 arm_compute_save_reg0_reg12_mask  PARAMS ((void));
10690075Sobrienstatic Ulong     arm_compute_save_reg_mask	PARAMS ((void));
10790075Sobrienstatic Ulong     arm_isr_value 			PARAMS ((tree));
10890075Sobrienstatic Ulong     arm_compute_func_type		PARAMS ((void));
10990075Sobrienstatic tree      arm_handle_fndecl_attribute    PARAMS ((tree *, tree, tree, int, bool *));
11090075Sobrienstatic tree      arm_handle_isr_attribute       PARAMS ((tree *, tree, tree, int, bool *));
11190075Sobrienstatic void	 arm_output_function_epilogue	PARAMS ((FILE *, Hint));
11290075Sobrienstatic void	 arm_output_function_prologue	PARAMS ((FILE *, Hint));
11390075Sobrienstatic void	 thumb_output_function_prologue PARAMS ((FILE *, Hint));
11490075Sobrienstatic int	 arm_comp_type_attributes	PARAMS ((tree, tree));
11590075Sobrienstatic void	 arm_set_default_type_attributes  PARAMS ((tree));
11690075Sobrienstatic int	 arm_adjust_cost		PARAMS ((rtx, rtx, rtx, int));
117117395Skanstatic int	 count_insns_for_constant	PARAMS ((HOST_WIDE_INT, int));
118117395Skanstatic int	 arm_get_strip_length		PARAMS ((int));
11990075Sobrien#ifdef OBJECT_FORMAT_ELF
12090075Sobrienstatic void	 arm_elf_asm_named_section	PARAMS ((const char *, unsigned int));
12190075Sobrien#endif
122117395Skan#ifndef ARM_PE
123117395Skanstatic void	 arm_encode_section_info	PARAMS ((tree, int));
124117395Skan#endif
125117395Skan#ifdef AOF_ASSEMBLER
126117395Skanstatic void	 aof_globalize_label		PARAMS ((FILE *, const char *));
127117395Skan#endif
128117395Skanstatic void arm_output_mi_thunk			PARAMS ((FILE *, tree,
129117395Skan							 HOST_WIDE_INT,
130117395Skan							 HOST_WIDE_INT, tree));
13190075Sobrien
13290075Sobrien#undef Hint
13390075Sobrien#undef Mmode
13490075Sobrien#undef Ulong
13590075Sobrien#undef Ccstar
13690075Sobrien
13790075Sobrien/* Initialize the GCC target structure.  */
13890075Sobrien#ifdef TARGET_DLLIMPORT_DECL_ATTRIBUTES
13990075Sobrien#undef  TARGET_MERGE_DECL_ATTRIBUTES
14090075Sobrien#define TARGET_MERGE_DECL_ATTRIBUTES merge_dllimport_decl_attributes
14190075Sobrien#endif
14290075Sobrien
14390075Sobrien#undef  TARGET_ATTRIBUTE_TABLE
14490075Sobrien#define TARGET_ATTRIBUTE_TABLE arm_attribute_table
14590075Sobrien
14690075Sobrien#ifdef AOF_ASSEMBLER
14790075Sobrien#undef  TARGET_ASM_BYTE_OP
14890075Sobrien#define TARGET_ASM_BYTE_OP "\tDCB\t"
14990075Sobrien#undef  TARGET_ASM_ALIGNED_HI_OP
15090075Sobrien#define TARGET_ASM_ALIGNED_HI_OP "\tDCW\t"
15190075Sobrien#undef  TARGET_ASM_ALIGNED_SI_OP
15290075Sobrien#define TARGET_ASM_ALIGNED_SI_OP "\tDCD\t"
153117395Skan#undef TARGET_ASM_GLOBALIZE_LABEL
154117395Skan#define TARGET_ASM_GLOBALIZE_LABEL aof_globalize_label
15590075Sobrien#else
15690075Sobrien#undef  TARGET_ASM_ALIGNED_SI_OP
15790075Sobrien#define TARGET_ASM_ALIGNED_SI_OP NULL
15890075Sobrien#undef  TARGET_ASM_INTEGER
15990075Sobrien#define TARGET_ASM_INTEGER arm_assemble_integer
16090075Sobrien#endif
16190075Sobrien
16290075Sobrien#undef  TARGET_ASM_FUNCTION_PROLOGUE
16390075Sobrien#define TARGET_ASM_FUNCTION_PROLOGUE arm_output_function_prologue
16490075Sobrien
16590075Sobrien#undef  TARGET_ASM_FUNCTION_EPILOGUE
16690075Sobrien#define TARGET_ASM_FUNCTION_EPILOGUE arm_output_function_epilogue
16790075Sobrien
16890075Sobrien#undef  TARGET_COMP_TYPE_ATTRIBUTES
16990075Sobrien#define TARGET_COMP_TYPE_ATTRIBUTES arm_comp_type_attributes
17090075Sobrien
17190075Sobrien#undef  TARGET_SET_DEFAULT_TYPE_ATTRIBUTES
17290075Sobrien#define TARGET_SET_DEFAULT_TYPE_ATTRIBUTES arm_set_default_type_attributes
17390075Sobrien
17490075Sobrien#undef  TARGET_INIT_BUILTINS
17590075Sobrien#define TARGET_INIT_BUILTINS arm_init_builtins
17690075Sobrien
17790075Sobrien#undef  TARGET_EXPAND_BUILTIN
17890075Sobrien#define TARGET_EXPAND_BUILTIN arm_expand_builtin
17990075Sobrien
18090075Sobrien#undef  TARGET_SCHED_ADJUST_COST
18190075Sobrien#define TARGET_SCHED_ADJUST_COST arm_adjust_cost
18290075Sobrien
183117395Skan#undef TARGET_ENCODE_SECTION_INFO
184117395Skan#ifdef ARM_PE
185117395Skan#define TARGET_ENCODE_SECTION_INFO  arm_pe_encode_section_info
186117395Skan#else
187117395Skan#define TARGET_ENCODE_SECTION_INFO  arm_encode_section_info
188117395Skan#endif
189117395Skan
190117395Skan#undef TARGET_STRIP_NAME_ENCODING
191117395Skan#define TARGET_STRIP_NAME_ENCODING arm_strip_name_encoding
192117395Skan
193117395Skan#undef TARGET_ASM_OUTPUT_MI_THUNK
194117395Skan#define TARGET_ASM_OUTPUT_MI_THUNK arm_output_mi_thunk
195117395Skan#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
196117395Skan#define TARGET_ASM_CAN_OUTPUT_MI_THUNK default_can_output_mi_thunk_no_vcall
197117395Skan
19890075Sobrienstruct gcc_target targetm = TARGET_INITIALIZER;
19990075Sobrien
20090075Sobrien/* Obstack for minipool constant handling.  */
20190075Sobrienstatic struct obstack minipool_obstack;
20290075Sobrienstatic char *         minipool_startobj;
20390075Sobrien
20490075Sobrien/* The maximum number of insns skipped which
20590075Sobrien   will be conditionalised if possible.  */
20690075Sobrienstatic int max_insns_skipped = 5;
20790075Sobrien
20890075Sobrienextern FILE * asm_out_file;
20990075Sobrien
21090075Sobrien/* True if we are currently building a constant table.  */
21190075Sobrienint making_const_table;
21290075Sobrien
21390075Sobrien/* Define the information needed to generate branch insns.  This is
21490075Sobrien   stored from the compare operation.  */
21590075Sobrienrtx arm_compare_op0, arm_compare_op1;
21690075Sobrien
21790075Sobrien/* What type of floating point are we tuning for?  */
21890075Sobrienenum floating_point_type arm_fpu;
21990075Sobrien
22090075Sobrien/* What type of floating point instructions are available?  */
22190075Sobrienenum floating_point_type arm_fpu_arch;
22290075Sobrien
22390075Sobrien/* What program mode is the cpu running in? 26-bit mode or 32-bit mode.  */
22490075Sobrienenum prog_mode_type arm_prgmode;
22590075Sobrien
22690075Sobrien/* Set by the -mfp=... option.  */
22790075Sobrienconst char * target_fp_name = NULL;
22890075Sobrien
22990075Sobrien/* Used to parse -mstructure_size_boundary command line option.  */
23090075Sobrienconst char * structure_size_string = NULL;
23190075Sobrienint    arm_structure_size_boundary = DEFAULT_STRUCTURE_SIZE_BOUNDARY;
23290075Sobrien
23390075Sobrien/* Bit values used to identify processor capabilities.  */
23490075Sobrien#define FL_CO_PROC    (1 << 0)        /* Has external co-processor bus */
23590075Sobrien#define FL_FAST_MULT  (1 << 1)        /* Fast multiply */
23690075Sobrien#define FL_MODE26     (1 << 2)        /* 26-bit mode support */
23790075Sobrien#define FL_MODE32     (1 << 3)        /* 32-bit mode support */
23890075Sobrien#define FL_ARCH4      (1 << 4)        /* Architecture rel 4 */
23990075Sobrien#define FL_ARCH5      (1 << 5)        /* Architecture rel 5 */
24090075Sobrien#define FL_THUMB      (1 << 6)        /* Thumb aware */
24190075Sobrien#define FL_LDSCHED    (1 << 7)	      /* Load scheduling necessary */
24290075Sobrien#define FL_STRONG     (1 << 8)	      /* StrongARM */
24390075Sobrien#define FL_ARCH5E     (1 << 9)        /* DSP extenstions to v5 */
24490075Sobrien#define FL_XSCALE     (1 << 10)	      /* XScale */
24590075Sobrien
24690075Sobrien/* The bits in this mask specify which
24790075Sobrien   instructions we are allowed to generate.  */
248117395Skanstatic unsigned long insn_flags = 0;
24990075Sobrien
25090075Sobrien/* The bits in this mask specify which instruction scheduling options should
25190075Sobrien   be used.  Note - there is an overlap with the FL_FAST_MULT.  For some
25290075Sobrien   hardware we want to be able to generate the multiply instructions, but to
25390075Sobrien   tune as if they were not present in the architecture.  */
254117395Skanstatic unsigned long tune_flags = 0;
25590075Sobrien
25690075Sobrien/* The following are used in the arm.md file as equivalents to bits
25790075Sobrien   in the above two flag variables.  */
25890075Sobrien
25990075Sobrien/* Nonzero if this is an "M" variant of the processor.  */
26090075Sobrienint arm_fast_multiply = 0;
26190075Sobrien
26290075Sobrien/* Nonzero if this chip supports the ARM Architecture 4 extensions.  */
26390075Sobrienint arm_arch4 = 0;
26490075Sobrien
26590075Sobrien/* Nonzero if this chip supports the ARM Architecture 5 extensions.  */
26690075Sobrienint arm_arch5 = 0;
26790075Sobrien
26890075Sobrien/* Nonzero if this chip supports the ARM Architecture 5E extensions.  */
26990075Sobrienint arm_arch5e = 0;
27090075Sobrien
27190075Sobrien/* Nonzero if this chip can benefit from load scheduling.  */
27290075Sobrienint arm_ld_sched = 0;
27390075Sobrien
27490075Sobrien/* Nonzero if this chip is a StrongARM.  */
27590075Sobrienint arm_is_strong = 0;
27690075Sobrien
27790075Sobrien/* Nonzero if this chip is an XScale.  */
27890075Sobrienint arm_is_xscale = 0;
27990075Sobrien
28090075Sobrien/* Nonzero if this chip is an ARM6 or an ARM7.  */
28190075Sobrienint arm_is_6_or_7 = 0;
28290075Sobrien
28390075Sobrien/* Nonzero if generating Thumb instructions.  */
28490075Sobrienint thumb_code = 0;
28590075Sobrien
28690075Sobrien/* In case of a PRE_INC, POST_INC, PRE_DEC, POST_DEC memory reference, we
28790075Sobrien   must report the mode of the memory reference from PRINT_OPERAND to
28890075Sobrien   PRINT_OPERAND_ADDRESS.  */
28990075Sobrienenum machine_mode output_memory_reference_mode;
29090075Sobrien
29190075Sobrien/* The register number to be used for the PIC offset register.  */
29290075Sobrienconst char * arm_pic_register_string = NULL;
29396263Sobrienint arm_pic_register = INVALID_REGNUM;
29490075Sobrien
29590075Sobrien/* Set to 1 when a return insn is output, this means that the epilogue
29690075Sobrien   is not needed.  */
29790075Sobrienint return_used_this_function;
29890075Sobrien
29990075Sobrien/* Set to 1 after arm_reorg has started.  Reset to start at the start of
30090075Sobrien   the next function.  */
30190075Sobrienstatic int after_arm_reorg = 0;
30290075Sobrien
30390075Sobrien/* The maximum number of insns to be used when loading a constant.  */
30490075Sobrienstatic int arm_constant_limit = 3;
30590075Sobrien
30690075Sobrien/* For an explanation of these variables, see final_prescan_insn below.  */
30790075Sobrienint arm_ccfsm_state;
30890075Sobrienenum arm_cond_code arm_current_cc;
30990075Sobrienrtx arm_target_insn;
31090075Sobrienint arm_target_label;
31190075Sobrien
31290075Sobrien/* The condition codes of the ARM, and the inverse function.  */
31390075Sobrienstatic const char * const arm_condition_codes[] =
31490075Sobrien{
31590075Sobrien  "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
31690075Sobrien  "hi", "ls", "ge", "lt", "gt", "le", "al", "nv"
31790075Sobrien};
31890075Sobrien
31990075Sobrien#define streq(string1, string2) (strcmp (string1, string2) == 0)
32090075Sobrien
32190075Sobrien/* Initialization code.  */
32290075Sobrien
32390075Sobrienstruct processors
32490075Sobrien{
32590075Sobrien  const char *const name;
326117395Skan  const unsigned long flags;
32790075Sobrien};
32890075Sobrien
32990075Sobrien/* Not all of these give usefully different compilation alternatives,
33090075Sobrien   but there is no simple way of generalizing them.  */
33190075Sobrienstatic const struct processors all_cores[] =
33290075Sobrien{
33390075Sobrien  /* ARM Cores */
33490075Sobrien
33590075Sobrien  {"arm2",	FL_CO_PROC | FL_MODE26 },
33690075Sobrien  {"arm250",	FL_CO_PROC | FL_MODE26 },
33790075Sobrien  {"arm3",	FL_CO_PROC | FL_MODE26 },
33890075Sobrien  {"arm6",	FL_CO_PROC | FL_MODE26 | FL_MODE32 },
33990075Sobrien  {"arm60",	FL_CO_PROC | FL_MODE26 | FL_MODE32 },
34090075Sobrien  {"arm600",	FL_CO_PROC | FL_MODE26 | FL_MODE32 },
34190075Sobrien  {"arm610",	             FL_MODE26 | FL_MODE32 },
34290075Sobrien  {"arm620",	FL_CO_PROC | FL_MODE26 | FL_MODE32 },
34390075Sobrien  {"arm7",	FL_CO_PROC | FL_MODE26 | FL_MODE32 },
34490075Sobrien  /* arm7m doesn't exist on its own, but only with D, (and I), but
34590075Sobrien     those don't alter the code, so arm7m is sometimes used.  */
34690075Sobrien  {"arm7m",	FL_CO_PROC | FL_MODE26 | FL_MODE32 | FL_FAST_MULT },
34790075Sobrien  {"arm7d",	FL_CO_PROC | FL_MODE26 | FL_MODE32 },
34890075Sobrien  {"arm7dm",	FL_CO_PROC | FL_MODE26 | FL_MODE32 | FL_FAST_MULT },
34990075Sobrien  {"arm7di",	FL_CO_PROC | FL_MODE26 | FL_MODE32 },
35090075Sobrien  {"arm7dmi",	FL_CO_PROC | FL_MODE26 | FL_MODE32 | FL_FAST_MULT },
35190075Sobrien  {"arm70",	FL_CO_PROC | FL_MODE26 | FL_MODE32 },
35290075Sobrien  {"arm700",	FL_CO_PROC | FL_MODE26 | FL_MODE32 },
35390075Sobrien  {"arm700i",	FL_CO_PROC | FL_MODE26 | FL_MODE32 },
35490075Sobrien  {"arm710",	             FL_MODE26 | FL_MODE32 },
35590075Sobrien  {"arm710t",	             FL_MODE26 | FL_MODE32                           | FL_THUMB },
35690075Sobrien  {"arm720",	             FL_MODE26 | FL_MODE32 },
35790075Sobrien  {"arm720t",	             FL_MODE26 | FL_MODE32                           | FL_THUMB },
35890075Sobrien  {"arm740t",	             FL_MODE26 | FL_MODE32                           | FL_THUMB },
35990075Sobrien  {"arm710c",	             FL_MODE26 | FL_MODE32 },
36090075Sobrien  {"arm7100",	             FL_MODE26 | FL_MODE32 },
36190075Sobrien  {"arm7500",	             FL_MODE26 | FL_MODE32 },
36290075Sobrien  /* Doesn't have an external co-proc, but does have embedded fpu.  */
36390075Sobrien  {"arm7500fe",	FL_CO_PROC | FL_MODE26 | FL_MODE32 },
36490075Sobrien  {"arm7tdmi",	FL_CO_PROC |             FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB },
36590075Sobrien  {"arm8",	             FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 |            FL_LDSCHED },
36690075Sobrien  {"arm810",	             FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 |            FL_LDSCHED },
36790075Sobrien  {"arm9",	                         FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED },
36890075Sobrien  {"arm920",	                         FL_MODE32 | FL_FAST_MULT | FL_ARCH4 |            FL_LDSCHED },
36990075Sobrien  {"arm920t",	                         FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED },
37090075Sobrien  {"arm940t",	                         FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED },
37190075Sobrien  {"arm9tdmi",	                         FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED },
37290075Sobrien  {"arm9e",	       	      		 FL_MODE32 | FL_FAST_MULT | FL_ARCH4 |            FL_LDSCHED },
37390075Sobrien  {"strongarm",	             FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 |            FL_LDSCHED | FL_STRONG },
37490075Sobrien  {"strongarm110",           FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 |            FL_LDSCHED | FL_STRONG },
37590075Sobrien  {"strongarm1100",          FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 |            FL_LDSCHED | FL_STRONG },
37690075Sobrien  {"strongarm1110",          FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 |            FL_LDSCHED | FL_STRONG },
37790075Sobrien  {"arm10tdmi",	                         FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED             | FL_ARCH5 },
37890075Sobrien  {"arm1020t",	                         FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED             | FL_ARCH5 },
37990075Sobrien  {"xscale",                             FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED | FL_STRONG | FL_ARCH5 | FL_ARCH5E | FL_XSCALE },
380117395Skan
38190075Sobrien  {NULL, 0}
38290075Sobrien};
38390075Sobrien
38490075Sobrienstatic const struct processors all_architectures[] =
38590075Sobrien{
38690075Sobrien  /* ARM Architectures */
38790075Sobrien
38890075Sobrien  { "armv2",     FL_CO_PROC | FL_MODE26 },
38990075Sobrien  { "armv2a",    FL_CO_PROC | FL_MODE26 },
39090075Sobrien  { "armv3",     FL_CO_PROC | FL_MODE26 | FL_MODE32 },
39190075Sobrien  { "armv3m",    FL_CO_PROC | FL_MODE26 | FL_MODE32 | FL_FAST_MULT },
39290075Sobrien  { "armv4",     FL_CO_PROC | FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 },
39390075Sobrien  /* Strictly, FL_MODE26 is a permitted option for v4t, but there are no
39490075Sobrien     implementations that support it, so we will leave it out for now.  */
39590075Sobrien  { "armv4t",    FL_CO_PROC |             FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB },
39690075Sobrien  { "armv5",     FL_CO_PROC |             FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_ARCH5 },
39790075Sobrien  { "armv5t",    FL_CO_PROC |             FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_ARCH5 },
39890075Sobrien  { "armv5te",   FL_CO_PROC |             FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_ARCH5 | FL_ARCH5E },
39990075Sobrien  { NULL, 0 }
40090075Sobrien};
40190075Sobrien
40290075Sobrien/* This is a magic stucture.  The 'string' field is magically filled in
40390075Sobrien   with a pointer to the value specified by the user on the command line
40490075Sobrien   assuming that the user has specified such a value.  */
40590075Sobrien
40690075Sobrienstruct arm_cpu_select arm_select[] =
40790075Sobrien{
40890075Sobrien  /* string	  name            processors  */
40990075Sobrien  { NULL,	"-mcpu=",	all_cores  },
41090075Sobrien  { NULL,	"-march=",	all_architectures },
41190075Sobrien  { NULL,	"-mtune=",	all_cores }
41290075Sobrien};
41390075Sobrien
414117395Skan/* Return the number of bits set in VALUE.  */
415117395Skanstatic unsigned
41690075Sobrienbit_count (value)
417117395Skan     unsigned long value;
41890075Sobrien{
41990075Sobrien  unsigned long count = 0;
42090075Sobrien
42190075Sobrien  while (value)
42290075Sobrien    {
423117395Skan      count++;
424117395Skan      value &= value - 1;  /* Clear the least-significant set bit.  */
42590075Sobrien    }
42690075Sobrien
42790075Sobrien  return count;
42890075Sobrien}
42990075Sobrien
43090075Sobrien/* Fix up any incompatible options that the user has specified.
43190075Sobrien   This has now turned into a maze.  */
43290075Sobrienvoid
43390075Sobrienarm_override_options ()
43490075Sobrien{
43590075Sobrien  unsigned i;
43690075Sobrien
43790075Sobrien  /* Set up the flags based on the cpu/architecture selected by the user.  */
43890075Sobrien  for (i = ARRAY_SIZE (arm_select); i--;)
43990075Sobrien    {
44090075Sobrien      struct arm_cpu_select * ptr = arm_select + i;
44190075Sobrien
44290075Sobrien      if (ptr->string != NULL && ptr->string[0] != '\0')
44390075Sobrien        {
44490075Sobrien	  const struct processors * sel;
44590075Sobrien
44690075Sobrien          for (sel = ptr->processors; sel->name != NULL; sel++)
44790075Sobrien            if (streq (ptr->string, sel->name))
44890075Sobrien              {
44990075Sobrien		if (i == 2)
45090075Sobrien		  tune_flags = sel->flags;
45190075Sobrien		else
45290075Sobrien		  {
45390075Sobrien		    /* If we have been given an architecture and a processor
45490075Sobrien		       make sure that they are compatible.  We only generate
45590075Sobrien		       a warning though, and we prefer the CPU over the
45690075Sobrien		       architecture.  */
45790075Sobrien		    if (insn_flags != 0 && (insn_flags ^ sel->flags))
45890075Sobrien		      warning ("switch -mcpu=%s conflicts with -march= switch",
45990075Sobrien			       ptr->string);
46090075Sobrien
46190075Sobrien		    insn_flags = sel->flags;
46290075Sobrien		  }
46390075Sobrien
46490075Sobrien                break;
46590075Sobrien              }
46690075Sobrien
46790075Sobrien          if (sel->name == NULL)
46890075Sobrien            error ("bad value (%s) for %s switch", ptr->string, ptr->name);
46990075Sobrien        }
47090075Sobrien    }
47190075Sobrien
47290075Sobrien  /* If the user did not specify a processor, choose one for them.  */
47390075Sobrien  if (insn_flags == 0)
47490075Sobrien    {
47590075Sobrien      const struct processors * sel;
47690075Sobrien      unsigned int        sought;
47790075Sobrien      static const struct cpu_default
47890075Sobrien      {
47990075Sobrien	const int cpu;
48090075Sobrien	const char *const name;
48190075Sobrien      }
48290075Sobrien      cpu_defaults[] =
48390075Sobrien      {
48490075Sobrien	{ TARGET_CPU_arm2,      "arm2" },
48590075Sobrien	{ TARGET_CPU_arm6,      "arm6" },
48690075Sobrien	{ TARGET_CPU_arm610,    "arm610" },
48790075Sobrien	{ TARGET_CPU_arm710,	"arm710" },
48890075Sobrien	{ TARGET_CPU_arm7m,     "arm7m" },
48990075Sobrien	{ TARGET_CPU_arm7500fe, "arm7500fe" },
49090075Sobrien	{ TARGET_CPU_arm7tdmi,  "arm7tdmi" },
49190075Sobrien	{ TARGET_CPU_arm8,      "arm8" },
49290075Sobrien	{ TARGET_CPU_arm810,    "arm810" },
49390075Sobrien	{ TARGET_CPU_arm9,      "arm9" },
49490075Sobrien	{ TARGET_CPU_strongarm, "strongarm" },
49590075Sobrien	{ TARGET_CPU_xscale,    "xscale" },
49690075Sobrien	{ TARGET_CPU_generic,   "arm" },
49790075Sobrien	{ 0, 0 }
49890075Sobrien      };
49990075Sobrien      const struct cpu_default * def;
50090075Sobrien
50190075Sobrien      /* Find the default.  */
50290075Sobrien      for (def = cpu_defaults; def->name; def++)
50390075Sobrien	if (def->cpu == TARGET_CPU_DEFAULT)
50490075Sobrien	  break;
50590075Sobrien
50690075Sobrien      /* Make sure we found the default CPU.  */
50790075Sobrien      if (def->name == NULL)
50890075Sobrien	abort ();
50990075Sobrien
51090075Sobrien      /* Find the default CPU's flags.  */
51190075Sobrien      for (sel = all_cores; sel->name != NULL; sel++)
51290075Sobrien	if (streq (def->name, sel->name))
51390075Sobrien	  break;
51490075Sobrien
51590075Sobrien      if (sel->name == NULL)
51690075Sobrien	abort ();
51790075Sobrien
51890075Sobrien      insn_flags = sel->flags;
51990075Sobrien
52090075Sobrien      /* Now check to see if the user has specified some command line
52190075Sobrien	 switch that require certain abilities from the cpu.  */
52290075Sobrien      sought = 0;
52390075Sobrien
52490075Sobrien      if (TARGET_INTERWORK || TARGET_THUMB)
52590075Sobrien	{
52690075Sobrien	  sought |= (FL_THUMB | FL_MODE32);
52790075Sobrien
52890075Sobrien	  /* Force apcs-32 to be used for interworking.  */
52990075Sobrien	  target_flags |= ARM_FLAG_APCS_32;
53090075Sobrien
53190075Sobrien	  /* There are no ARM processors that support both APCS-26 and
53290075Sobrien	     interworking.  Therefore we force FL_MODE26 to be removed
53390075Sobrien	     from insn_flags here (if it was set), so that the search
53490075Sobrien	     below will always be able to find a compatible processor.  */
53590075Sobrien	  insn_flags &= ~FL_MODE26;
53690075Sobrien	}
53790075Sobrien      else if (!TARGET_APCS_32)
53890075Sobrien	sought |= FL_MODE26;
53990075Sobrien
54090075Sobrien      if (sought != 0 && ((sought & insn_flags) != sought))
54190075Sobrien	{
54290075Sobrien	  /* Try to locate a CPU type that supports all of the abilities
54390075Sobrien	     of the default CPU, plus the extra abilities requested by
54490075Sobrien	     the user.  */
54590075Sobrien	  for (sel = all_cores; sel->name != NULL; sel++)
54690075Sobrien	    if ((sel->flags & sought) == (sought | insn_flags))
54790075Sobrien	      break;
54890075Sobrien
54990075Sobrien	  if (sel->name == NULL)
55090075Sobrien	    {
551117395Skan	      unsigned current_bit_count = 0;
55290075Sobrien	      const struct processors * best_fit = NULL;
55390075Sobrien
55490075Sobrien	      /* Ideally we would like to issue an error message here
55590075Sobrien		 saying that it was not possible to find a CPU compatible
55690075Sobrien		 with the default CPU, but which also supports the command
55790075Sobrien		 line options specified by the programmer, and so they
55890075Sobrien		 ought to use the -mcpu=<name> command line option to
55990075Sobrien		 override the default CPU type.
56090075Sobrien
56190075Sobrien		 Unfortunately this does not work with multilibing.  We
56290075Sobrien		 need to be able to support multilibs for -mapcs-26 and for
56390075Sobrien		 -mthumb-interwork and there is no CPU that can support both
56490075Sobrien		 options.  Instead if we cannot find a cpu that has both the
56590075Sobrien		 characteristics of the default cpu and the given command line
56690075Sobrien		 options we scan the array again looking for a best match.  */
56790075Sobrien	      for (sel = all_cores; sel->name != NULL; sel++)
56890075Sobrien		if ((sel->flags & sought) == sought)
56990075Sobrien		  {
570117395Skan		    unsigned count;
57190075Sobrien
57290075Sobrien		    count = bit_count (sel->flags & insn_flags);
57390075Sobrien
57490075Sobrien		    if (count >= current_bit_count)
57590075Sobrien		      {
57690075Sobrien			best_fit = sel;
57790075Sobrien			current_bit_count = count;
57890075Sobrien		      }
57990075Sobrien		  }
58090075Sobrien
58190075Sobrien	      if (best_fit == NULL)
58290075Sobrien		abort ();
58390075Sobrien	      else
58490075Sobrien		sel = best_fit;
58590075Sobrien	    }
58690075Sobrien
58790075Sobrien	  insn_flags = sel->flags;
58890075Sobrien	}
58990075Sobrien    }
59090075Sobrien
59190075Sobrien  /* If tuning has not been specified, tune for whichever processor or
59290075Sobrien     architecture has been selected.  */
59390075Sobrien  if (tune_flags == 0)
59490075Sobrien    tune_flags = insn_flags;
595117395Skan
59690075Sobrien  /* Make sure that the processor choice does not conflict with any of the
59790075Sobrien     other command line choices.  */
59890075Sobrien  if (TARGET_APCS_32 && !(insn_flags & FL_MODE32))
59990075Sobrien    {
60090075Sobrien      /* If APCS-32 was not the default then it must have been set by the
60190075Sobrien	 user, so issue a warning message.  If the user has specified
60290075Sobrien	 "-mapcs-32 -mcpu=arm2" then we loose here.  */
60390075Sobrien      if ((TARGET_DEFAULT & ARM_FLAG_APCS_32) == 0)
60490075Sobrien	warning ("target CPU does not support APCS-32" );
60590075Sobrien      target_flags &= ~ARM_FLAG_APCS_32;
60690075Sobrien    }
60790075Sobrien  else if (!TARGET_APCS_32 && !(insn_flags & FL_MODE26))
60890075Sobrien    {
60990075Sobrien      warning ("target CPU does not support APCS-26" );
61090075Sobrien      target_flags |= ARM_FLAG_APCS_32;
61190075Sobrien    }
61290075Sobrien
61390075Sobrien  if (TARGET_INTERWORK && !(insn_flags & FL_THUMB))
61490075Sobrien    {
61590075Sobrien      warning ("target CPU does not support interworking" );
61690075Sobrien      target_flags &= ~ARM_FLAG_INTERWORK;
61790075Sobrien    }
61890075Sobrien
61990075Sobrien  if (TARGET_THUMB && !(insn_flags & FL_THUMB))
62090075Sobrien    {
62190075Sobrien      warning ("target CPU does not support THUMB instructions");
62290075Sobrien      target_flags &= ~ARM_FLAG_THUMB;
62390075Sobrien    }
62490075Sobrien
62590075Sobrien  if (TARGET_APCS_FRAME && TARGET_THUMB)
62690075Sobrien    {
62790075Sobrien      /* warning ("ignoring -mapcs-frame because -mthumb was used"); */
62890075Sobrien      target_flags &= ~ARM_FLAG_APCS_FRAME;
62990075Sobrien    }
63090075Sobrien
63190075Sobrien  /* TARGET_BACKTRACE calls leaf_function_p, which causes a crash if done
63290075Sobrien     from here where no function is being compiled currently.  */
63390075Sobrien  if ((target_flags & (THUMB_FLAG_LEAF_BACKTRACE | THUMB_FLAG_BACKTRACE))
63490075Sobrien      && TARGET_ARM)
63590075Sobrien    warning ("enabling backtrace support is only meaningful when compiling for the Thumb");
63690075Sobrien
63790075Sobrien  if (TARGET_ARM && TARGET_CALLEE_INTERWORKING)
63890075Sobrien    warning ("enabling callee interworking support is only meaningful when compiling for the Thumb");
63990075Sobrien
64090075Sobrien  if (TARGET_ARM && TARGET_CALLER_INTERWORKING)
64190075Sobrien    warning ("enabling caller interworking support is only meaningful when compiling for the Thumb");
64290075Sobrien
64390075Sobrien  /* If interworking is enabled then APCS-32 must be selected as well.  */
64490075Sobrien  if (TARGET_INTERWORK)
64590075Sobrien    {
64690075Sobrien      if (!TARGET_APCS_32)
64790075Sobrien	warning ("interworking forces APCS-32 to be used" );
64890075Sobrien      target_flags |= ARM_FLAG_APCS_32;
64990075Sobrien    }
65090075Sobrien
65190075Sobrien  if (TARGET_APCS_STACK && !TARGET_APCS_FRAME)
65290075Sobrien    {
65390075Sobrien      warning ("-mapcs-stack-check incompatible with -mno-apcs-frame");
65490075Sobrien      target_flags |= ARM_FLAG_APCS_FRAME;
65590075Sobrien    }
65690075Sobrien
65790075Sobrien  if (TARGET_POKE_FUNCTION_NAME)
65890075Sobrien    target_flags |= ARM_FLAG_APCS_FRAME;
65990075Sobrien
66090075Sobrien  if (TARGET_APCS_REENT && flag_pic)
66190075Sobrien    error ("-fpic and -mapcs-reent are incompatible");
66290075Sobrien
66390075Sobrien  if (TARGET_APCS_REENT)
66490075Sobrien    warning ("APCS reentrant code not supported.  Ignored");
66590075Sobrien
66690075Sobrien  /* If this target is normally configured to use APCS frames, warn if they
66790075Sobrien     are turned off and debugging is turned on.  */
66890075Sobrien  if (TARGET_ARM
66990075Sobrien      && write_symbols != NO_DEBUG
67090075Sobrien      && !TARGET_APCS_FRAME
67190075Sobrien      && (TARGET_DEFAULT & ARM_FLAG_APCS_FRAME))
67290075Sobrien    warning ("-g with -mno-apcs-frame may not give sensible debugging");
67390075Sobrien
67490075Sobrien  /* If stack checking is disabled, we can use r10 as the PIC register,
67590075Sobrien     which keeps r9 available.  */
67696263Sobrien  if (flag_pic)
67796263Sobrien    arm_pic_register = TARGET_APCS_STACK ? 9 : 10;
67890075Sobrien
67990075Sobrien  if (TARGET_APCS_FLOAT)
68090075Sobrien    warning ("passing floating point arguments in fp regs not yet supported");
68190075Sobrien
682117395Skan  /* Initialize boolean versions of the flags, for use in the arm.md file.  */
68390075Sobrien  arm_fast_multiply = (insn_flags & FL_FAST_MULT) != 0;
68490075Sobrien  arm_arch4         = (insn_flags & FL_ARCH4) != 0;
68590075Sobrien  arm_arch5         = (insn_flags & FL_ARCH5) != 0;
68690075Sobrien  arm_arch5e        = (insn_flags & FL_ARCH5E) != 0;
68790075Sobrien  arm_is_xscale     = (insn_flags & FL_XSCALE) != 0;
68890075Sobrien
68990075Sobrien  arm_ld_sched      = (tune_flags & FL_LDSCHED) != 0;
69090075Sobrien  arm_is_strong     = (tune_flags & FL_STRONG) != 0;
69190075Sobrien  thumb_code	    = (TARGET_ARM == 0);
69290075Sobrien  arm_is_6_or_7     = (((tune_flags & (FL_MODE26 | FL_MODE32))
69390075Sobrien		       && !(tune_flags & FL_ARCH4))) != 0;
69490075Sobrien
69590075Sobrien  /* Default value for floating point code... if no co-processor
69690075Sobrien     bus, then schedule for emulated floating point.  Otherwise,
69790075Sobrien     assume the user has an FPA.
69890075Sobrien     Note: this does not prevent use of floating point instructions,
69990075Sobrien     -msoft-float does that.  */
70090075Sobrien  arm_fpu = (tune_flags & FL_CO_PROC) ? FP_HARD : FP_SOFT3;
70190075Sobrien
70290075Sobrien  if (target_fp_name)
70390075Sobrien    {
70490075Sobrien      if (streq (target_fp_name, "2"))
70590075Sobrien	arm_fpu_arch = FP_SOFT2;
70690075Sobrien      else if (streq (target_fp_name, "3"))
70790075Sobrien	arm_fpu_arch = FP_SOFT3;
70890075Sobrien      else
70990075Sobrien	error ("invalid floating point emulation option: -mfpe-%s",
71090075Sobrien	       target_fp_name);
71190075Sobrien    }
71290075Sobrien  else
71390075Sobrien    arm_fpu_arch = FP_DEFAULT;
71490075Sobrien
71590075Sobrien  if (TARGET_FPE && arm_fpu != FP_HARD)
71690075Sobrien    arm_fpu = FP_SOFT2;
71790075Sobrien
71890075Sobrien  /* For arm2/3 there is no need to do any scheduling if there is only
71990075Sobrien     a floating point emulator, or we are doing software floating-point.  */
72090075Sobrien  if ((TARGET_SOFT_FLOAT || arm_fpu != FP_HARD)
72190075Sobrien      && (tune_flags & FL_MODE32) == 0)
72290075Sobrien    flag_schedule_insns = flag_schedule_insns_after_reload = 0;
72390075Sobrien
72490075Sobrien  arm_prgmode = TARGET_APCS_32 ? PROG_MODE_PROG32 : PROG_MODE_PROG26;
72590075Sobrien
72690075Sobrien  if (structure_size_string != NULL)
72790075Sobrien    {
72890075Sobrien      int size = strtol (structure_size_string, NULL, 0);
72990075Sobrien
73090075Sobrien      if (size == 8 || size == 32)
73190075Sobrien	arm_structure_size_boundary = size;
73290075Sobrien      else
73390075Sobrien	warning ("structure size boundary can only be set to 8 or 32");
73490075Sobrien    }
73590075Sobrien
73690075Sobrien  if (arm_pic_register_string != NULL)
73790075Sobrien    {
73896263Sobrien      int pic_register = decode_reg_name (arm_pic_register_string);
739117395Skan
74090075Sobrien      if (!flag_pic)
74190075Sobrien	warning ("-mpic-register= is useless without -fpic");
74290075Sobrien
74390075Sobrien      /* Prevent the user from choosing an obviously stupid PIC register.  */
74496263Sobrien      else if (pic_register < 0 || call_used_regs[pic_register]
74596263Sobrien	       || pic_register == HARD_FRAME_POINTER_REGNUM
74696263Sobrien	       || pic_register == STACK_POINTER_REGNUM
74796263Sobrien	       || pic_register >= PC_REGNUM)
74890075Sobrien	error ("unable to use '%s' for PIC register", arm_pic_register_string);
74990075Sobrien      else
75090075Sobrien	arm_pic_register = pic_register;
75190075Sobrien    }
75290075Sobrien
75390075Sobrien  if (TARGET_THUMB && flag_schedule_insns)
75490075Sobrien    {
75590075Sobrien      /* Don't warn since it's on by default in -O2.  */
75690075Sobrien      flag_schedule_insns = 0;
75790075Sobrien    }
75890075Sobrien
75990075Sobrien  /* If optimizing for space, don't synthesize constants.
76090075Sobrien     For processors with load scheduling, it never costs more than 2 cycles
76190075Sobrien     to load a constant, and the load scheduler may well reduce that to 1.  */
76290075Sobrien  if (optimize_size || (tune_flags & FL_LDSCHED))
76390075Sobrien    arm_constant_limit = 1;
76490075Sobrien
76590075Sobrien  if (arm_is_xscale)
76690075Sobrien    arm_constant_limit = 2;
76790075Sobrien
76890075Sobrien  /* If optimizing for size, bump the number of instructions that we
76990075Sobrien     are prepared to conditionally execute (even on a StrongARM).
77090075Sobrien     Otherwise for the StrongARM, which has early execution of branches,
77190075Sobrien     a sequence that is worth skipping is shorter.  */
77290075Sobrien  if (optimize_size)
77390075Sobrien    max_insns_skipped = 6;
77490075Sobrien  else if (arm_is_strong)
77590075Sobrien    max_insns_skipped = 3;
77690075Sobrien
77790075Sobrien  /* Register global variables with the garbage collector.  */
77890075Sobrien  arm_add_gc_roots ();
77990075Sobrien}
78090075Sobrien
78190075Sobrienstatic void
78290075Sobrienarm_add_gc_roots ()
78390075Sobrien{
78490075Sobrien  gcc_obstack_init(&minipool_obstack);
78590075Sobrien  minipool_startobj = (char *) obstack_alloc (&minipool_obstack, 0);
78690075Sobrien}
78790075Sobrien
78890075Sobrien/* A table of known ARM exception types.
78990075Sobrien   For use with the interrupt function attribute.  */
79090075Sobrien
79190075Sobrientypedef struct
79290075Sobrien{
79390075Sobrien  const char *const arg;
79490075Sobrien  const unsigned long return_value;
79590075Sobrien}
79690075Sobrienisr_attribute_arg;
79790075Sobrien
79890075Sobrienstatic const isr_attribute_arg isr_attribute_args [] =
79990075Sobrien{
80090075Sobrien  { "IRQ",   ARM_FT_ISR },
80190075Sobrien  { "irq",   ARM_FT_ISR },
80290075Sobrien  { "FIQ",   ARM_FT_FIQ },
80390075Sobrien  { "fiq",   ARM_FT_FIQ },
80490075Sobrien  { "ABORT", ARM_FT_ISR },
80590075Sobrien  { "abort", ARM_FT_ISR },
80690075Sobrien  { "ABORT", ARM_FT_ISR },
80790075Sobrien  { "abort", ARM_FT_ISR },
80890075Sobrien  { "UNDEF", ARM_FT_EXCEPTION },
80990075Sobrien  { "undef", ARM_FT_EXCEPTION },
81090075Sobrien  { "SWI",   ARM_FT_EXCEPTION },
81190075Sobrien  { "swi",   ARM_FT_EXCEPTION },
81290075Sobrien  { NULL,    ARM_FT_NORMAL }
81390075Sobrien};
81490075Sobrien
81590075Sobrien/* Returns the (interrupt) function type of the current
81690075Sobrien   function, or ARM_FT_UNKNOWN if the type cannot be determined.  */
81790075Sobrien
81890075Sobrienstatic unsigned long
81990075Sobrienarm_isr_value (argument)
82090075Sobrien     tree argument;
82190075Sobrien{
82290075Sobrien  const isr_attribute_arg * ptr;
82390075Sobrien  const char *              arg;
82490075Sobrien
82590075Sobrien  /* No argument - default to IRQ.  */
82690075Sobrien  if (argument == NULL_TREE)
82790075Sobrien    return ARM_FT_ISR;
82890075Sobrien
82990075Sobrien  /* Get the value of the argument.  */
83090075Sobrien  if (TREE_VALUE (argument) == NULL_TREE
83190075Sobrien      || TREE_CODE (TREE_VALUE (argument)) != STRING_CST)
83290075Sobrien    return ARM_FT_UNKNOWN;
83390075Sobrien
83490075Sobrien  arg = TREE_STRING_POINTER (TREE_VALUE (argument));
83590075Sobrien
83690075Sobrien  /* Check it against the list of known arguments.  */
83790075Sobrien  for (ptr = isr_attribute_args; ptr->arg != NULL; ptr ++)
83890075Sobrien    if (streq (arg, ptr->arg))
83990075Sobrien      return ptr->return_value;
84090075Sobrien
841117395Skan  /* An unrecognized interrupt type.  */
84290075Sobrien  return ARM_FT_UNKNOWN;
84390075Sobrien}
84490075Sobrien
84590075Sobrien/* Computes the type of the current function.  */
84690075Sobrien
84790075Sobrienstatic unsigned long
84890075Sobrienarm_compute_func_type ()
84990075Sobrien{
85090075Sobrien  unsigned long type = ARM_FT_UNKNOWN;
85190075Sobrien  tree a;
85290075Sobrien  tree attr;
85390075Sobrien
85490075Sobrien  if (TREE_CODE (current_function_decl) != FUNCTION_DECL)
85590075Sobrien    abort ();
85690075Sobrien
85790075Sobrien  /* Decide if the current function is volatile.  Such functions
85890075Sobrien     never return, and many memory cycles can be saved by not storing
85990075Sobrien     register values that will never be needed again.  This optimization
86090075Sobrien     was added to speed up context switching in a kernel application.  */
86190075Sobrien  if (optimize > 0
86290075Sobrien      && current_function_nothrow
86390075Sobrien      && TREE_THIS_VOLATILE (current_function_decl))
86490075Sobrien    type |= ARM_FT_VOLATILE;
86590075Sobrien
86690075Sobrien  if (current_function_needs_context)
86790075Sobrien    type |= ARM_FT_NESTED;
86890075Sobrien
86990075Sobrien  attr = DECL_ATTRIBUTES (current_function_decl);
87090075Sobrien
87190075Sobrien  a = lookup_attribute ("naked", attr);
87290075Sobrien  if (a != NULL_TREE)
87390075Sobrien    type |= ARM_FT_NAKED;
87490075Sobrien
87590075Sobrien  if (cfun->machine->eh_epilogue_sp_ofs != NULL_RTX)
87690075Sobrien    type |= ARM_FT_EXCEPTION_HANDLER;
87790075Sobrien  else
87890075Sobrien    {
87990075Sobrien      a = lookup_attribute ("isr", attr);
88090075Sobrien      if (a == NULL_TREE)
88190075Sobrien	a = lookup_attribute ("interrupt", attr);
88290075Sobrien
88390075Sobrien      if (a == NULL_TREE)
88490075Sobrien	type |= TARGET_INTERWORK ? ARM_FT_INTERWORKED : ARM_FT_NORMAL;
88590075Sobrien      else
88690075Sobrien	type |= arm_isr_value (TREE_VALUE (a));
88790075Sobrien    }
88890075Sobrien
88990075Sobrien  return type;
89090075Sobrien}
89190075Sobrien
89290075Sobrien/* Returns the type of the current function.  */
89390075Sobrien
89490075Sobrienunsigned long
89590075Sobrienarm_current_func_type ()
89690075Sobrien{
89790075Sobrien  if (ARM_FUNC_TYPE (cfun->machine->func_type) == ARM_FT_UNKNOWN)
89890075Sobrien    cfun->machine->func_type = arm_compute_func_type ();
89990075Sobrien
90090075Sobrien  return cfun->machine->func_type;
90190075Sobrien}
90290075Sobrien
90390075Sobrien/* Return 1 if it is possible to return using a single instruction.  */
90490075Sobrien
90590075Sobrienint
90690075Sobrienuse_return_insn (iscond)
90790075Sobrien     int iscond;
90890075Sobrien{
90990075Sobrien  int regno;
91090075Sobrien  unsigned int func_type;
911107590Sobrien  unsigned long saved_int_regs;
91290075Sobrien
91390075Sobrien  /* Never use a return instruction before reload has run.  */
91490075Sobrien  if (!reload_completed)
91590075Sobrien    return 0;
91690075Sobrien
91790075Sobrien  func_type = arm_current_func_type ();
91890075Sobrien
91996263Sobrien  /* Naked functions and volatile functions need special
92096263Sobrien     consideration.  */
92196263Sobrien  if (func_type & (ARM_FT_VOLATILE | ARM_FT_NAKED))
92290075Sobrien    return 0;
923117395Skan
924117395Skan  /* So do interrupt functions that use the frame pointer.  */
925117395Skan  if (IS_INTERRUPT (func_type) && frame_pointer_needed)
926117395Skan    return 0;
92790075Sobrien
92890075Sobrien  /* As do variadic functions.  */
92990075Sobrien  if (current_function_pretend_args_size
93096263Sobrien      || cfun->machine->uses_anonymous_args
93190075Sobrien      /* Of if the function calls __builtin_eh_return () */
93290075Sobrien      || ARM_FUNC_TYPE (func_type) == ARM_FT_EXCEPTION_HANDLER
93390075Sobrien      /* Or if there is no frame pointer and there is a stack adjustment.  */
934117395Skan      || ((arm_get_frame_size () + current_function_outgoing_args_size != 0)
93590075Sobrien	  && !frame_pointer_needed))
93690075Sobrien    return 0;
93790075Sobrien
938107590Sobrien  saved_int_regs = arm_compute_save_reg_mask ();
939107590Sobrien
94090075Sobrien  /* Can't be done if interworking with Thumb, and any registers have been
941107590Sobrien     stacked.  */
942107590Sobrien  if (TARGET_INTERWORK && saved_int_regs != 0)
94390075Sobrien    return 0;
944107590Sobrien
945107590Sobrien  /* On StrongARM, conditional returns are expensive if they aren't
946107590Sobrien     taken and multiple registers have been stacked.  */
947107590Sobrien  if (iscond && arm_is_strong)
94890075Sobrien    {
949107590Sobrien      /* Conditional return when just the LR is stored is a simple
950107590Sobrien	 conditional-load instruction, that's not expensive.  */
951107590Sobrien      if (saved_int_regs != 0 && saved_int_regs != (1 << LR_REGNUM))
952107590Sobrien	return 0;
95390075Sobrien
95490075Sobrien      if (flag_pic && regs_ever_live[PIC_OFFSET_TABLE_REGNUM])
95590075Sobrien	return 0;
95690075Sobrien    }
957107590Sobrien
958107590Sobrien  /* If there are saved registers but the LR isn't saved, then we need
959107590Sobrien     two instructions for the return.  */
960107590Sobrien  if (saved_int_regs && !(saved_int_regs & (1 << LR_REGNUM)))
961107590Sobrien    return 0;
962107590Sobrien
96390075Sobrien  /* Can't be done if any of the FPU regs are pushed,
96490075Sobrien     since this also requires an insn.  */
96590075Sobrien  if (TARGET_HARD_FLOAT)
96690075Sobrien    for (regno = FIRST_ARM_FP_REGNUM; regno <= LAST_ARM_FP_REGNUM; regno++)
96790075Sobrien      if (regs_ever_live[regno] && !call_used_regs[regno])
96890075Sobrien	return 0;
96990075Sobrien
97090075Sobrien  return 1;
97190075Sobrien}
97290075Sobrien
97390075Sobrien/* Return TRUE if int I is a valid immediate ARM constant.  */
97490075Sobrien
97590075Sobrienint
97690075Sobrienconst_ok_for_arm (i)
97790075Sobrien     HOST_WIDE_INT i;
97890075Sobrien{
97990075Sobrien  unsigned HOST_WIDE_INT mask = ~(unsigned HOST_WIDE_INT)0xFF;
98090075Sobrien
98190075Sobrien  /* For machines with >32 bit HOST_WIDE_INT, the bits above bit 31 must
98290075Sobrien     be all zero, or all one.  */
98390075Sobrien  if ((i & ~(unsigned HOST_WIDE_INT) 0xffffffff) != 0
98490075Sobrien      && ((i & ~(unsigned HOST_WIDE_INT) 0xffffffff)
98590075Sobrien	  != ((~(unsigned HOST_WIDE_INT) 0)
98690075Sobrien	      & ~(unsigned HOST_WIDE_INT) 0xffffffff)))
98790075Sobrien    return FALSE;
98890075Sobrien
98990075Sobrien  /* Fast return for 0 and powers of 2 */
99090075Sobrien  if ((i & (i - 1)) == 0)
99190075Sobrien    return TRUE;
99290075Sobrien
99390075Sobrien  do
99490075Sobrien    {
99590075Sobrien      if ((i & mask & (unsigned HOST_WIDE_INT) 0xffffffff) == 0)
99690075Sobrien        return TRUE;
99790075Sobrien      mask =
99890075Sobrien	  (mask << 2) | ((mask & (unsigned HOST_WIDE_INT) 0xffffffff)
99990075Sobrien			  >> (32 - 2)) | ~(unsigned HOST_WIDE_INT) 0xffffffff;
100090075Sobrien    }
100190075Sobrien  while (mask != ~(unsigned HOST_WIDE_INT) 0xFF);
100290075Sobrien
100390075Sobrien  return FALSE;
100490075Sobrien}
100590075Sobrien
100690075Sobrien/* Return true if I is a valid constant for the operation CODE.  */
100790075Sobrienstatic int
100890075Sobrienconst_ok_for_op (i, code)
100990075Sobrien     HOST_WIDE_INT i;
101090075Sobrien     enum rtx_code code;
101190075Sobrien{
101290075Sobrien  if (const_ok_for_arm (i))
101390075Sobrien    return 1;
101490075Sobrien
101590075Sobrien  switch (code)
101690075Sobrien    {
101790075Sobrien    case PLUS:
101890075Sobrien      return const_ok_for_arm (ARM_SIGN_EXTEND (-i));
101990075Sobrien
102090075Sobrien    case MINUS:		/* Should only occur with (MINUS I reg) => rsb */
102190075Sobrien    case XOR:
102290075Sobrien    case IOR:
102390075Sobrien      return 0;
102490075Sobrien
102590075Sobrien    case AND:
102690075Sobrien      return const_ok_for_arm (ARM_SIGN_EXTEND (~i));
102790075Sobrien
102890075Sobrien    default:
102990075Sobrien      abort ();
103090075Sobrien    }
103190075Sobrien}
103290075Sobrien
103390075Sobrien/* Emit a sequence of insns to handle a large constant.
103490075Sobrien   CODE is the code of the operation required, it can be any of SET, PLUS,
103590075Sobrien   IOR, AND, XOR, MINUS;
103690075Sobrien   MODE is the mode in which the operation is being performed;
103790075Sobrien   VAL is the integer to operate on;
103890075Sobrien   SOURCE is the other operand (a register, or a null-pointer for SET);
103990075Sobrien   SUBTARGETS means it is safe to create scratch registers if that will
104090075Sobrien   either produce a simpler sequence, or we will want to cse the values.
104190075Sobrien   Return value is the number of insns emitted.  */
104290075Sobrien
104390075Sobrienint
104490075Sobrienarm_split_constant (code, mode, val, target, source, subtargets)
104590075Sobrien     enum rtx_code code;
104690075Sobrien     enum machine_mode mode;
104790075Sobrien     HOST_WIDE_INT val;
104890075Sobrien     rtx target;
104990075Sobrien     rtx source;
105090075Sobrien     int subtargets;
105190075Sobrien{
105290075Sobrien  if (subtargets || code == SET
105390075Sobrien      || (GET_CODE (target) == REG && GET_CODE (source) == REG
105490075Sobrien	  && REGNO (target) != REGNO (source)))
105590075Sobrien    {
105690075Sobrien      /* After arm_reorg has been called, we can't fix up expensive
1057117395Skan	 constants by pushing them into memory so we must synthesize
105890075Sobrien	 them in-line, regardless of the cost.  This is only likely to
105990075Sobrien	 be more costly on chips that have load delay slots and we are
106090075Sobrien	 compiling without running the scheduler (so no splitting
106190075Sobrien	 occurred before the final instruction emission).
106290075Sobrien
106390075Sobrien	 Ref: gcc -O1 -mcpu=strongarm gcc.c-torture/compile/980506-2.c
106490075Sobrien      */
106590075Sobrien      if (!after_arm_reorg
106690075Sobrien	  && (arm_gen_constant (code, mode, val, target, source, 1, 0)
106790075Sobrien	      > arm_constant_limit + (code != SET)))
106890075Sobrien	{
106990075Sobrien	  if (code == SET)
107090075Sobrien	    {
107190075Sobrien	      /* Currently SET is the only monadic value for CODE, all
107290075Sobrien		 the rest are diadic.  */
107390075Sobrien	      emit_insn (gen_rtx_SET (VOIDmode, target, GEN_INT (val)));
107490075Sobrien	      return 1;
107590075Sobrien	    }
107690075Sobrien	  else
107790075Sobrien	    {
107890075Sobrien	      rtx temp = subtargets ? gen_reg_rtx (mode) : target;
107990075Sobrien
108090075Sobrien	      emit_insn (gen_rtx_SET (VOIDmode, temp, GEN_INT (val)));
108190075Sobrien	      /* For MINUS, the value is subtracted from, since we never
108290075Sobrien		 have subtraction of a constant.  */
108390075Sobrien	      if (code == MINUS)
108490075Sobrien		emit_insn (gen_rtx_SET (VOIDmode, target,
108590075Sobrien					gen_rtx_MINUS (mode, temp, source)));
108690075Sobrien	      else
108790075Sobrien		emit_insn (gen_rtx_SET (VOIDmode, target,
108890075Sobrien					gen_rtx (code, mode, source, temp)));
108990075Sobrien	      return 2;
109090075Sobrien	    }
109190075Sobrien	}
109290075Sobrien    }
109390075Sobrien
109490075Sobrien  return arm_gen_constant (code, mode, val, target, source, subtargets, 1);
109590075Sobrien}
109690075Sobrien
109790075Sobrienstatic int
1098117395Skancount_insns_for_constant (remainder, i)
1099117395Skan     HOST_WIDE_INT remainder;
1100117395Skan     int i;
110190075Sobrien{
110290075Sobrien  HOST_WIDE_INT temp1;
110390075Sobrien  int num_insns = 0;
110490075Sobrien  do
110590075Sobrien    {
110690075Sobrien      int end;
110790075Sobrien
110890075Sobrien      if (i <= 0)
110990075Sobrien	i += 32;
111090075Sobrien      if (remainder & (3 << (i - 2)))
111190075Sobrien	{
111290075Sobrien	  end = i - 8;
111390075Sobrien	  if (end < 0)
111490075Sobrien	    end += 32;
111590075Sobrien	  temp1 = remainder & ((0x0ff << end)
111690075Sobrien				    | ((i < end) ? (0xff >> (32 - end)) : 0));
111790075Sobrien	  remainder &= ~temp1;
111890075Sobrien	  num_insns++;
111990075Sobrien	  i -= 6;
112090075Sobrien	}
112190075Sobrien      i -= 2;
112290075Sobrien    } while (remainder);
112390075Sobrien  return num_insns;
112490075Sobrien}
112590075Sobrien
112690075Sobrien/* As above, but extra parameter GENERATE which, if clear, suppresses
112790075Sobrien   RTL generation.  */
112890075Sobrien
112990075Sobrienstatic int
113090075Sobrienarm_gen_constant (code, mode, val, target, source, subtargets, generate)
113190075Sobrien     enum rtx_code code;
113290075Sobrien     enum machine_mode mode;
113390075Sobrien     HOST_WIDE_INT val;
113490075Sobrien     rtx target;
113590075Sobrien     rtx source;
113690075Sobrien     int subtargets;
113790075Sobrien     int generate;
113890075Sobrien{
113990075Sobrien  int can_invert = 0;
114090075Sobrien  int can_negate = 0;
114190075Sobrien  int can_negate_initial = 0;
114290075Sobrien  int can_shift = 0;
114390075Sobrien  int i;
114490075Sobrien  int num_bits_set = 0;
114590075Sobrien  int set_sign_bit_copies = 0;
114690075Sobrien  int clear_sign_bit_copies = 0;
114790075Sobrien  int clear_zero_bit_copies = 0;
114890075Sobrien  int set_zero_bit_copies = 0;
114990075Sobrien  int insns = 0;
115090075Sobrien  unsigned HOST_WIDE_INT temp1, temp2;
115190075Sobrien  unsigned HOST_WIDE_INT remainder = val & 0xffffffff;
115290075Sobrien
115390075Sobrien  /* Find out which operations are safe for a given CODE.  Also do a quick
115490075Sobrien     check for degenerate cases; these can occur when DImode operations
115590075Sobrien     are split.  */
115690075Sobrien  switch (code)
115790075Sobrien    {
115890075Sobrien    case SET:
115990075Sobrien      can_invert = 1;
116090075Sobrien      can_shift = 1;
116190075Sobrien      can_negate = 1;
116290075Sobrien      break;
116390075Sobrien
116490075Sobrien    case PLUS:
116590075Sobrien      can_negate = 1;
116690075Sobrien      can_negate_initial = 1;
116790075Sobrien      break;
116890075Sobrien
116990075Sobrien    case IOR:
117090075Sobrien      if (remainder == 0xffffffff)
117190075Sobrien	{
117290075Sobrien	  if (generate)
117390075Sobrien	    emit_insn (gen_rtx_SET (VOIDmode, target,
117490075Sobrien				    GEN_INT (ARM_SIGN_EXTEND (val))));
117590075Sobrien	  return 1;
117690075Sobrien	}
117790075Sobrien      if (remainder == 0)
117890075Sobrien	{
117990075Sobrien	  if (reload_completed && rtx_equal_p (target, source))
118090075Sobrien	    return 0;
118190075Sobrien	  if (generate)
118290075Sobrien	    emit_insn (gen_rtx_SET (VOIDmode, target, source));
118390075Sobrien	  return 1;
118490075Sobrien	}
118590075Sobrien      break;
118690075Sobrien
118790075Sobrien    case AND:
118890075Sobrien      if (remainder == 0)
118990075Sobrien	{
119090075Sobrien	  if (generate)
119190075Sobrien	    emit_insn (gen_rtx_SET (VOIDmode, target, const0_rtx));
119290075Sobrien	  return 1;
119390075Sobrien	}
119490075Sobrien      if (remainder == 0xffffffff)
119590075Sobrien	{
119690075Sobrien	  if (reload_completed && rtx_equal_p (target, source))
119790075Sobrien	    return 0;
119890075Sobrien	  if (generate)
119990075Sobrien	    emit_insn (gen_rtx_SET (VOIDmode, target, source));
120090075Sobrien	  return 1;
120190075Sobrien	}
120290075Sobrien      can_invert = 1;
120390075Sobrien      break;
120490075Sobrien
120590075Sobrien    case XOR:
120690075Sobrien      if (remainder == 0)
120790075Sobrien	{
120890075Sobrien	  if (reload_completed && rtx_equal_p (target, source))
120990075Sobrien	    return 0;
121090075Sobrien	  if (generate)
121190075Sobrien	    emit_insn (gen_rtx_SET (VOIDmode, target, source));
121290075Sobrien	  return 1;
121390075Sobrien	}
121490075Sobrien      if (remainder == 0xffffffff)
121590075Sobrien	{
121690075Sobrien	  if (generate)
121790075Sobrien	    emit_insn (gen_rtx_SET (VOIDmode, target,
121890075Sobrien				    gen_rtx_NOT (mode, source)));
121990075Sobrien	  return 1;
122090075Sobrien	}
122190075Sobrien
122290075Sobrien      /* We don't know how to handle this yet below.  */
122390075Sobrien      abort ();
122490075Sobrien
122590075Sobrien    case MINUS:
122690075Sobrien      /* We treat MINUS as (val - source), since (source - val) is always
122790075Sobrien	 passed as (source + (-val)).  */
122890075Sobrien      if (remainder == 0)
122990075Sobrien	{
123090075Sobrien	  if (generate)
123190075Sobrien	    emit_insn (gen_rtx_SET (VOIDmode, target,
123290075Sobrien				    gen_rtx_NEG (mode, source)));
123390075Sobrien	  return 1;
123490075Sobrien	}
123590075Sobrien      if (const_ok_for_arm (val))
123690075Sobrien	{
123790075Sobrien	  if (generate)
123890075Sobrien	    emit_insn (gen_rtx_SET (VOIDmode, target,
123990075Sobrien				    gen_rtx_MINUS (mode, GEN_INT (val),
124090075Sobrien						   source)));
124190075Sobrien	  return 1;
124290075Sobrien	}
124390075Sobrien      can_negate = 1;
124490075Sobrien
124590075Sobrien      break;
124690075Sobrien
124790075Sobrien    default:
124890075Sobrien      abort ();
124990075Sobrien    }
125090075Sobrien
125190075Sobrien  /* If we can do it in one insn get out quickly.  */
125290075Sobrien  if (const_ok_for_arm (val)
125390075Sobrien      || (can_negate_initial && const_ok_for_arm (-val))
125490075Sobrien      || (can_invert && const_ok_for_arm (~val)))
125590075Sobrien    {
125690075Sobrien      if (generate)
125790075Sobrien	emit_insn (gen_rtx_SET (VOIDmode, target,
125890075Sobrien				(source ? gen_rtx (code, mode, source,
125990075Sobrien						   GEN_INT (val))
126090075Sobrien				 : GEN_INT (val))));
126190075Sobrien      return 1;
126290075Sobrien    }
126390075Sobrien
126490075Sobrien  /* Calculate a few attributes that may be useful for specific
126590075Sobrien     optimizations.  */
126690075Sobrien  for (i = 31; i >= 0; i--)
126790075Sobrien    {
126890075Sobrien      if ((remainder & (1 << i)) == 0)
126990075Sobrien	clear_sign_bit_copies++;
127090075Sobrien      else
127190075Sobrien	break;
127290075Sobrien    }
127390075Sobrien
127490075Sobrien  for (i = 31; i >= 0; i--)
127590075Sobrien    {
127690075Sobrien      if ((remainder & (1 << i)) != 0)
127790075Sobrien	set_sign_bit_copies++;
127890075Sobrien      else
127990075Sobrien	break;
128090075Sobrien    }
128190075Sobrien
128290075Sobrien  for (i = 0; i <= 31; i++)
128390075Sobrien    {
128490075Sobrien      if ((remainder & (1 << i)) == 0)
128590075Sobrien	clear_zero_bit_copies++;
128690075Sobrien      else
128790075Sobrien	break;
128890075Sobrien    }
128990075Sobrien
129090075Sobrien  for (i = 0; i <= 31; i++)
129190075Sobrien    {
129290075Sobrien      if ((remainder & (1 << i)) != 0)
129390075Sobrien	set_zero_bit_copies++;
129490075Sobrien      else
129590075Sobrien	break;
129690075Sobrien    }
129790075Sobrien
129890075Sobrien  switch (code)
129990075Sobrien    {
130090075Sobrien    case SET:
130190075Sobrien      /* See if we can do this by sign_extending a constant that is known
130290075Sobrien	 to be negative.  This is a good, way of doing it, since the shift
130390075Sobrien	 may well merge into a subsequent insn.  */
130490075Sobrien      if (set_sign_bit_copies > 1)
130590075Sobrien	{
130690075Sobrien	  if (const_ok_for_arm
130790075Sobrien	      (temp1 = ARM_SIGN_EXTEND (remainder
130890075Sobrien					<< (set_sign_bit_copies - 1))))
130990075Sobrien	    {
131090075Sobrien	      if (generate)
131190075Sobrien		{
131290075Sobrien		  rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
131390075Sobrien		  emit_insn (gen_rtx_SET (VOIDmode, new_src,
131490075Sobrien					  GEN_INT (temp1)));
131590075Sobrien		  emit_insn (gen_ashrsi3 (target, new_src,
131690075Sobrien					  GEN_INT (set_sign_bit_copies - 1)));
131790075Sobrien		}
131890075Sobrien	      return 2;
131990075Sobrien	    }
132090075Sobrien	  /* For an inverted constant, we will need to set the low bits,
132190075Sobrien	     these will be shifted out of harm's way.  */
132290075Sobrien	  temp1 |= (1 << (set_sign_bit_copies - 1)) - 1;
132390075Sobrien	  if (const_ok_for_arm (~temp1))
132490075Sobrien	    {
132590075Sobrien	      if (generate)
132690075Sobrien		{
132790075Sobrien		  rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
132890075Sobrien		  emit_insn (gen_rtx_SET (VOIDmode, new_src,
132990075Sobrien					  GEN_INT (temp1)));
133090075Sobrien		  emit_insn (gen_ashrsi3 (target, new_src,
133190075Sobrien					  GEN_INT (set_sign_bit_copies - 1)));
133290075Sobrien		}
133390075Sobrien	      return 2;
133490075Sobrien	    }
133590075Sobrien	}
133690075Sobrien
133790075Sobrien      /* See if we can generate this by setting the bottom (or the top)
133890075Sobrien	 16 bits, and then shifting these into the other half of the
133990075Sobrien	 word.  We only look for the simplest cases, to do more would cost
134090075Sobrien	 too much.  Be careful, however, not to generate this when the
134190075Sobrien	 alternative would take fewer insns.  */
134290075Sobrien      if (val & 0xffff0000)
134390075Sobrien	{
134490075Sobrien	  temp1 = remainder & 0xffff0000;
134590075Sobrien	  temp2 = remainder & 0x0000ffff;
134690075Sobrien
134790075Sobrien	  /* Overlaps outside this range are best done using other methods.  */
134890075Sobrien	  for (i = 9; i < 24; i++)
134990075Sobrien	    {
135090075Sobrien	      if ((((temp2 | (temp2 << i)) & 0xffffffff) == remainder)
135190075Sobrien		  && !const_ok_for_arm (temp2))
135290075Sobrien		{
135390075Sobrien		  rtx new_src = (subtargets
135490075Sobrien				 ? (generate ? gen_reg_rtx (mode) : NULL_RTX)
135590075Sobrien				 : target);
135690075Sobrien		  insns = arm_gen_constant (code, mode, temp2, new_src,
135790075Sobrien					    source, subtargets, generate);
135890075Sobrien		  source = new_src;
135990075Sobrien		  if (generate)
136090075Sobrien		    emit_insn (gen_rtx_SET
136190075Sobrien			       (VOIDmode, target,
136290075Sobrien				gen_rtx_IOR (mode,
136390075Sobrien					     gen_rtx_ASHIFT (mode, source,
136490075Sobrien							     GEN_INT (i)),
136590075Sobrien					     source)));
136690075Sobrien		  return insns + 1;
136790075Sobrien		}
136890075Sobrien	    }
136990075Sobrien
137090075Sobrien	  /* Don't duplicate cases already considered.  */
137190075Sobrien	  for (i = 17; i < 24; i++)
137290075Sobrien	    {
137390075Sobrien	      if (((temp1 | (temp1 >> i)) == remainder)
137490075Sobrien		  && !const_ok_for_arm (temp1))
137590075Sobrien		{
137690075Sobrien		  rtx new_src = (subtargets
137790075Sobrien				 ? (generate ? gen_reg_rtx (mode) : NULL_RTX)
137890075Sobrien				 : target);
137990075Sobrien		  insns = arm_gen_constant (code, mode, temp1, new_src,
138090075Sobrien					    source, subtargets, generate);
138190075Sobrien		  source = new_src;
138290075Sobrien		  if (generate)
138390075Sobrien		    emit_insn
138490075Sobrien		      (gen_rtx_SET (VOIDmode, target,
138590075Sobrien				    gen_rtx_IOR
138690075Sobrien				    (mode,
138790075Sobrien				     gen_rtx_LSHIFTRT (mode, source,
138890075Sobrien						       GEN_INT (i)),
138990075Sobrien				     source)));
139090075Sobrien		  return insns + 1;
139190075Sobrien		}
139290075Sobrien	    }
139390075Sobrien	}
139490075Sobrien      break;
139590075Sobrien
139690075Sobrien    case IOR:
139790075Sobrien    case XOR:
139890075Sobrien      /* If we have IOR or XOR, and the constant can be loaded in a
139990075Sobrien	 single instruction, and we can find a temporary to put it in,
140090075Sobrien	 then this can be done in two instructions instead of 3-4.  */
140190075Sobrien      if (subtargets
140290075Sobrien	  /* TARGET can't be NULL if SUBTARGETS is 0 */
140390075Sobrien	  || (reload_completed && !reg_mentioned_p (target, source)))
140490075Sobrien	{
140590075Sobrien	  if (const_ok_for_arm (ARM_SIGN_EXTEND (~val)))
140690075Sobrien	    {
140790075Sobrien	      if (generate)
140890075Sobrien		{
140990075Sobrien		  rtx sub = subtargets ? gen_reg_rtx (mode) : target;
141090075Sobrien
141190075Sobrien		  emit_insn (gen_rtx_SET (VOIDmode, sub, GEN_INT (val)));
141290075Sobrien		  emit_insn (gen_rtx_SET (VOIDmode, target,
141390075Sobrien					  gen_rtx (code, mode, source, sub)));
141490075Sobrien		}
141590075Sobrien	      return 2;
141690075Sobrien	    }
141790075Sobrien	}
141890075Sobrien
141990075Sobrien      if (code == XOR)
142090075Sobrien	break;
142190075Sobrien
142290075Sobrien      if (set_sign_bit_copies > 8
142390075Sobrien	  && (val & (-1 << (32 - set_sign_bit_copies))) == val)
142490075Sobrien	{
142590075Sobrien	  if (generate)
142690075Sobrien	    {
142790075Sobrien	      rtx sub = subtargets ? gen_reg_rtx (mode) : target;
142890075Sobrien	      rtx shift = GEN_INT (set_sign_bit_copies);
142990075Sobrien
143090075Sobrien	      emit_insn (gen_rtx_SET (VOIDmode, sub,
143190075Sobrien				      gen_rtx_NOT (mode,
143290075Sobrien						   gen_rtx_ASHIFT (mode,
143390075Sobrien								   source,
143490075Sobrien								   shift))));
143590075Sobrien	      emit_insn (gen_rtx_SET (VOIDmode, target,
143690075Sobrien				      gen_rtx_NOT (mode,
143790075Sobrien						   gen_rtx_LSHIFTRT (mode, sub,
143890075Sobrien								     shift))));
143990075Sobrien	    }
144090075Sobrien	  return 2;
144190075Sobrien	}
144290075Sobrien
144390075Sobrien      if (set_zero_bit_copies > 8
144490075Sobrien	  && (remainder & ((1 << set_zero_bit_copies) - 1)) == remainder)
144590075Sobrien	{
144690075Sobrien	  if (generate)
144790075Sobrien	    {
144890075Sobrien	      rtx sub = subtargets ? gen_reg_rtx (mode) : target;
144990075Sobrien	      rtx shift = GEN_INT (set_zero_bit_copies);
145090075Sobrien
145190075Sobrien	      emit_insn (gen_rtx_SET (VOIDmode, sub,
145290075Sobrien				      gen_rtx_NOT (mode,
145390075Sobrien						   gen_rtx_LSHIFTRT (mode,
145490075Sobrien								     source,
145590075Sobrien								     shift))));
145690075Sobrien	      emit_insn (gen_rtx_SET (VOIDmode, target,
145790075Sobrien				      gen_rtx_NOT (mode,
145890075Sobrien						   gen_rtx_ASHIFT (mode, sub,
145990075Sobrien								   shift))));
146090075Sobrien	    }
146190075Sobrien	  return 2;
146290075Sobrien	}
146390075Sobrien
146490075Sobrien      if (const_ok_for_arm (temp1 = ARM_SIGN_EXTEND (~val)))
146590075Sobrien	{
146690075Sobrien	  if (generate)
146790075Sobrien	    {
146890075Sobrien	      rtx sub = subtargets ? gen_reg_rtx (mode) : target;
146990075Sobrien	      emit_insn (gen_rtx_SET (VOIDmode, sub,
147090075Sobrien				      gen_rtx_NOT (mode, source)));
147190075Sobrien	      source = sub;
147290075Sobrien	      if (subtargets)
147390075Sobrien		sub = gen_reg_rtx (mode);
147490075Sobrien	      emit_insn (gen_rtx_SET (VOIDmode, sub,
147590075Sobrien				      gen_rtx_AND (mode, source,
147690075Sobrien						   GEN_INT (temp1))));
147790075Sobrien	      emit_insn (gen_rtx_SET (VOIDmode, target,
147890075Sobrien				      gen_rtx_NOT (mode, sub)));
147990075Sobrien	    }
148090075Sobrien	  return 3;
148190075Sobrien	}
148290075Sobrien      break;
148390075Sobrien
148490075Sobrien    case AND:
148590075Sobrien      /* See if two shifts will do 2 or more insn's worth of work.  */
148690075Sobrien      if (clear_sign_bit_copies >= 16 && clear_sign_bit_copies < 24)
148790075Sobrien	{
148890075Sobrien	  HOST_WIDE_INT shift_mask = ((0xffffffff
148990075Sobrien				       << (32 - clear_sign_bit_copies))
149090075Sobrien				      & 0xffffffff);
149190075Sobrien
149290075Sobrien	  if ((remainder | shift_mask) != 0xffffffff)
149390075Sobrien	    {
149490075Sobrien	      if (generate)
149590075Sobrien		{
149690075Sobrien		  rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
149790075Sobrien		  insns = arm_gen_constant (AND, mode, remainder | shift_mask,
149890075Sobrien					    new_src, source, subtargets, 1);
149990075Sobrien		  source = new_src;
150090075Sobrien		}
150190075Sobrien	      else
150290075Sobrien		{
150390075Sobrien		  rtx targ = subtargets ? NULL_RTX : target;
150490075Sobrien		  insns = arm_gen_constant (AND, mode, remainder | shift_mask,
150590075Sobrien					    targ, source, subtargets, 0);
150690075Sobrien		}
150790075Sobrien	    }
150890075Sobrien
150990075Sobrien	  if (generate)
151090075Sobrien	    {
151190075Sobrien	      rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
151290075Sobrien	      rtx shift = GEN_INT (clear_sign_bit_copies);
151390075Sobrien
151490075Sobrien	      emit_insn (gen_ashlsi3 (new_src, source, shift));
151590075Sobrien	      emit_insn (gen_lshrsi3 (target, new_src, shift));
151690075Sobrien	    }
151790075Sobrien
151890075Sobrien	  return insns + 2;
151990075Sobrien	}
152090075Sobrien
152190075Sobrien      if (clear_zero_bit_copies >= 16 && clear_zero_bit_copies < 24)
152290075Sobrien	{
152390075Sobrien	  HOST_WIDE_INT shift_mask = (1 << clear_zero_bit_copies) - 1;
152490075Sobrien
152590075Sobrien	  if ((remainder | shift_mask) != 0xffffffff)
152690075Sobrien	    {
152790075Sobrien	      if (generate)
152890075Sobrien		{
152990075Sobrien		  rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
153090075Sobrien
153190075Sobrien		  insns = arm_gen_constant (AND, mode, remainder | shift_mask,
153290075Sobrien					    new_src, source, subtargets, 1);
153390075Sobrien		  source = new_src;
153490075Sobrien		}
153590075Sobrien	      else
153690075Sobrien		{
153790075Sobrien		  rtx targ = subtargets ? NULL_RTX : target;
153890075Sobrien
153990075Sobrien		  insns = arm_gen_constant (AND, mode, remainder | shift_mask,
154090075Sobrien					    targ, source, subtargets, 0);
154190075Sobrien		}
154290075Sobrien	    }
154390075Sobrien
154490075Sobrien	  if (generate)
154590075Sobrien	    {
154690075Sobrien	      rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
154790075Sobrien	      rtx shift = GEN_INT (clear_zero_bit_copies);
154890075Sobrien
154990075Sobrien	      emit_insn (gen_lshrsi3 (new_src, source, shift));
155090075Sobrien	      emit_insn (gen_ashlsi3 (target, new_src, shift));
155190075Sobrien	    }
155290075Sobrien
155390075Sobrien	  return insns + 2;
155490075Sobrien	}
155590075Sobrien
155690075Sobrien      break;
155790075Sobrien
155890075Sobrien    default:
155990075Sobrien      break;
156090075Sobrien    }
156190075Sobrien
156290075Sobrien  for (i = 0; i < 32; i++)
156390075Sobrien    if (remainder & (1 << i))
156490075Sobrien      num_bits_set++;
156590075Sobrien
156690075Sobrien  if (code == AND || (can_invert && num_bits_set > 16))
156790075Sobrien    remainder = (~remainder) & 0xffffffff;
156890075Sobrien  else if (code == PLUS && num_bits_set > 16)
156990075Sobrien    remainder = (-remainder) & 0xffffffff;
157090075Sobrien  else
157190075Sobrien    {
157290075Sobrien      can_invert = 0;
157390075Sobrien      can_negate = 0;
157490075Sobrien    }
157590075Sobrien
157690075Sobrien  /* Now try and find a way of doing the job in either two or three
157790075Sobrien     instructions.
157890075Sobrien     We start by looking for the largest block of zeros that are aligned on
157990075Sobrien     a 2-bit boundary, we then fill up the temps, wrapping around to the
158090075Sobrien     top of the word when we drop off the bottom.
158190075Sobrien     In the worst case this code should produce no more than four insns.  */
158290075Sobrien  {
158390075Sobrien    int best_start = 0;
158490075Sobrien    int best_consecutive_zeros = 0;
158590075Sobrien
158690075Sobrien    for (i = 0; i < 32; i += 2)
158790075Sobrien      {
158890075Sobrien	int consecutive_zeros = 0;
158990075Sobrien
159090075Sobrien	if (!(remainder & (3 << i)))
159190075Sobrien	  {
159290075Sobrien	    while ((i < 32) && !(remainder & (3 << i)))
159390075Sobrien	      {
159490075Sobrien		consecutive_zeros += 2;
159590075Sobrien		i += 2;
159690075Sobrien	      }
159790075Sobrien	    if (consecutive_zeros > best_consecutive_zeros)
159890075Sobrien	      {
159990075Sobrien		best_consecutive_zeros = consecutive_zeros;
160090075Sobrien		best_start = i - consecutive_zeros;
160190075Sobrien	      }
160290075Sobrien	    i -= 2;
160390075Sobrien	  }
160490075Sobrien      }
160590075Sobrien
160690075Sobrien    /* So long as it won't require any more insns to do so, it's
160790075Sobrien       desirable to emit a small constant (in bits 0...9) in the last
160890075Sobrien       insn.  This way there is more chance that it can be combined with
160990075Sobrien       a later addressing insn to form a pre-indexed load or store
161090075Sobrien       operation.  Consider:
161190075Sobrien
161290075Sobrien	       *((volatile int *)0xe0000100) = 1;
161390075Sobrien	       *((volatile int *)0xe0000110) = 2;
161490075Sobrien
161590075Sobrien       We want this to wind up as:
161690075Sobrien
161790075Sobrien		mov rA, #0xe0000000
161890075Sobrien		mov rB, #1
161990075Sobrien		str rB, [rA, #0x100]
162090075Sobrien		mov rB, #2
162190075Sobrien		str rB, [rA, #0x110]
162290075Sobrien
162390075Sobrien       rather than having to synthesize both large constants from scratch.
162490075Sobrien
162590075Sobrien       Therefore, we calculate how many insns would be required to emit
162690075Sobrien       the constant starting from `best_start', and also starting from
162790075Sobrien       zero (ie with bit 31 first to be output).  If `best_start' doesn't
162890075Sobrien       yield a shorter sequence, we may as well use zero.  */
162990075Sobrien    if (best_start != 0
163090075Sobrien	&& ((((unsigned HOST_WIDE_INT) 1) << best_start) < remainder)
163190075Sobrien	&& (count_insns_for_constant (remainder, 0) <=
163290075Sobrien	    count_insns_for_constant (remainder, best_start)))
163390075Sobrien      best_start = 0;
163490075Sobrien
163590075Sobrien    /* Now start emitting the insns.  */
163690075Sobrien    i = best_start;
163790075Sobrien    do
163890075Sobrien      {
163990075Sobrien	int end;
164090075Sobrien
164190075Sobrien	if (i <= 0)
164290075Sobrien	  i += 32;
164390075Sobrien	if (remainder & (3 << (i - 2)))
164490075Sobrien	  {
164590075Sobrien	    end = i - 8;
164690075Sobrien	    if (end < 0)
164790075Sobrien	      end += 32;
164890075Sobrien	    temp1 = remainder & ((0x0ff << end)
164990075Sobrien				 | ((i < end) ? (0xff >> (32 - end)) : 0));
165090075Sobrien	    remainder &= ~temp1;
165190075Sobrien
165290075Sobrien	    if (generate)
165390075Sobrien	      {
165490075Sobrien		rtx new_src, temp1_rtx;
165590075Sobrien
165690075Sobrien		if (code == SET || code == MINUS)
165790075Sobrien		  {
165890075Sobrien		    new_src = (subtargets ? gen_reg_rtx (mode) : target);
165990075Sobrien		    if (can_invert && code != MINUS)
166090075Sobrien		      temp1 = ~temp1;
166190075Sobrien		  }
166290075Sobrien		else
166390075Sobrien		  {
166490075Sobrien		    if (remainder && subtargets)
166590075Sobrien		      new_src = gen_reg_rtx (mode);
166690075Sobrien		    else
166790075Sobrien		      new_src = target;
166890075Sobrien		    if (can_invert)
166990075Sobrien		      temp1 = ~temp1;
167090075Sobrien		    else if (can_negate)
167190075Sobrien		      temp1 = -temp1;
167290075Sobrien		  }
167390075Sobrien
167490075Sobrien		temp1 = trunc_int_for_mode (temp1, mode);
167590075Sobrien		temp1_rtx = GEN_INT (temp1);
167690075Sobrien
167790075Sobrien		if (code == SET)
167890075Sobrien		  ;
167990075Sobrien		else if (code == MINUS)
168090075Sobrien		  temp1_rtx = gen_rtx_MINUS (mode, temp1_rtx, source);
168190075Sobrien		else
168290075Sobrien		  temp1_rtx = gen_rtx_fmt_ee (code, mode, source, temp1_rtx);
168390075Sobrien
168490075Sobrien		emit_insn (gen_rtx_SET (VOIDmode, new_src, temp1_rtx));
168590075Sobrien		source = new_src;
168690075Sobrien	      }
168790075Sobrien
168890075Sobrien	    if (code == SET)
168990075Sobrien	      {
169090075Sobrien		can_invert = 0;
169190075Sobrien		code = PLUS;
169290075Sobrien	      }
169390075Sobrien	    else if (code == MINUS)
169490075Sobrien	      code = PLUS;
169590075Sobrien
169690075Sobrien	    insns++;
169790075Sobrien	    i -= 6;
169890075Sobrien	  }
169990075Sobrien	i -= 2;
170090075Sobrien      }
170190075Sobrien    while (remainder);
170290075Sobrien  }
170390075Sobrien
170490075Sobrien  return insns;
170590075Sobrien}
170690075Sobrien
170790075Sobrien/* Canonicalize a comparison so that we are more likely to recognize it.
170890075Sobrien   This can be done for a few constant compares, where we can make the
170990075Sobrien   immediate value easier to load.  */
171090075Sobrien
171190075Sobrienenum rtx_code
171290075Sobrienarm_canonicalize_comparison (code, op1)
171390075Sobrien     enum rtx_code code;
171490075Sobrien     rtx * op1;
171590075Sobrien{
171690075Sobrien  unsigned HOST_WIDE_INT i = INTVAL (*op1);
171790075Sobrien
171890075Sobrien  switch (code)
171990075Sobrien    {
172090075Sobrien    case EQ:
172190075Sobrien    case NE:
172290075Sobrien      return code;
172390075Sobrien
172490075Sobrien    case GT:
172590075Sobrien    case LE:
172690075Sobrien      if (i != ((((unsigned HOST_WIDE_INT) 1) << (HOST_BITS_PER_WIDE_INT - 1)) - 1)
172790075Sobrien	  && (const_ok_for_arm (i + 1) || const_ok_for_arm (-(i + 1))))
172890075Sobrien	{
172990075Sobrien	  *op1 = GEN_INT (i + 1);
173090075Sobrien	  return code == GT ? GE : LT;
173190075Sobrien	}
173290075Sobrien      break;
173390075Sobrien
173490075Sobrien    case GE:
173590075Sobrien    case LT:
173690075Sobrien      if (i != (((unsigned HOST_WIDE_INT) 1) << (HOST_BITS_PER_WIDE_INT - 1))
173790075Sobrien	  && (const_ok_for_arm (i - 1) || const_ok_for_arm (-(i - 1))))
173890075Sobrien	{
173990075Sobrien	  *op1 = GEN_INT (i - 1);
174090075Sobrien	  return code == GE ? GT : LE;
174190075Sobrien	}
174290075Sobrien      break;
174390075Sobrien
174490075Sobrien    case GTU:
174590075Sobrien    case LEU:
174690075Sobrien      if (i != ~((unsigned HOST_WIDE_INT) 0)
174790075Sobrien	  && (const_ok_for_arm (i + 1) || const_ok_for_arm (-(i + 1))))
174890075Sobrien	{
174990075Sobrien	  *op1 = GEN_INT (i + 1);
175090075Sobrien	  return code == GTU ? GEU : LTU;
175190075Sobrien	}
175290075Sobrien      break;
175390075Sobrien
175490075Sobrien    case GEU:
175590075Sobrien    case LTU:
175690075Sobrien      if (i != 0
175790075Sobrien	  && (const_ok_for_arm (i - 1) || const_ok_for_arm (-(i - 1))))
175890075Sobrien	{
175990075Sobrien	  *op1 = GEN_INT (i - 1);
176090075Sobrien	  return code == GEU ? GTU : LEU;
176190075Sobrien	}
176290075Sobrien      break;
176390075Sobrien
176490075Sobrien    default:
176590075Sobrien      abort ();
176690075Sobrien    }
176790075Sobrien
176890075Sobrien  return code;
176990075Sobrien}
177090075Sobrien
177190075Sobrien/* Decide whether a type should be returned in memory (true)
177290075Sobrien   or in a register (false).  This is called by the macro
177390075Sobrien   RETURN_IN_MEMORY.  */
177490075Sobrien
177590075Sobrienint
177690075Sobrienarm_return_in_memory (type)
177790075Sobrien     tree type;
177890075Sobrien{
1779117395Skan  HOST_WIDE_INT size;
1780117395Skan
178190075Sobrien  if (!AGGREGATE_TYPE_P (type))
178290075Sobrien    /* All simple types are returned in registers.  */
178390075Sobrien    return 0;
1784117395Skan
1785117395Skan  size = int_size_in_bytes (type);
1786117395Skan
1787117395Skan  if (TARGET_ATPCS)
1788117395Skan    {
1789117395Skan      /* ATPCS returns aggregate types in memory only if they are
1790117395Skan	 larger than a word (or are variable size).  */
1791117395Skan      return (size < 0 || size > UNITS_PER_WORD);
1792117395Skan    }
179390075Sobrien
179490075Sobrien  /* For the arm-wince targets we choose to be compitable with Microsoft's
179590075Sobrien     ARM and Thumb compilers, which always return aggregates in memory.  */
179690075Sobrien#ifndef ARM_WINCE
179790075Sobrien  /* All structures/unions bigger than one word are returned in memory.
179890075Sobrien     Also catch the case where int_size_in_bytes returns -1.  In this case
179990075Sobrien     the aggregate is either huge or of varaible size, and in either case
180090075Sobrien     we will want to return it via memory and not in a register.  */
1801117395Skan  if (size < 0 || size > UNITS_PER_WORD)
180290075Sobrien    return 1;
180390075Sobrien
180490075Sobrien  if (TREE_CODE (type) == RECORD_TYPE)
180590075Sobrien    {
180690075Sobrien      tree field;
180790075Sobrien
180890075Sobrien      /* For a struct the APCS says that we only return in a register
180990075Sobrien	 if the type is 'integer like' and every addressable element
181090075Sobrien	 has an offset of zero.  For practical purposes this means
181190075Sobrien	 that the structure can have at most one non bit-field element
181290075Sobrien	 and that this element must be the first one in the structure.  */
181390075Sobrien
181490075Sobrien      /* Find the first field, ignoring non FIELD_DECL things which will
181590075Sobrien	 have been created by C++.  */
181690075Sobrien      for (field = TYPE_FIELDS (type);
181790075Sobrien	   field && TREE_CODE (field) != FIELD_DECL;
181890075Sobrien	   field = TREE_CHAIN (field))
181990075Sobrien	continue;
182090075Sobrien
182190075Sobrien      if (field == NULL)
182290075Sobrien	return 0; /* An empty structure.  Allowed by an extension to ANSI C.  */
182390075Sobrien
182490075Sobrien      /* Check that the first field is valid for returning in a register.  */
182590075Sobrien
182690075Sobrien      /* ... Floats are not allowed */
182790075Sobrien      if (FLOAT_TYPE_P (TREE_TYPE (field)))
182890075Sobrien	return 1;
182990075Sobrien
183090075Sobrien      /* ... Aggregates that are not themselves valid for returning in
183190075Sobrien	 a register are not allowed.  */
183290075Sobrien      if (RETURN_IN_MEMORY (TREE_TYPE (field)))
183390075Sobrien	return 1;
183490075Sobrien
183590075Sobrien      /* Now check the remaining fields, if any.  Only bitfields are allowed,
183690075Sobrien	 since they are not addressable.  */
183790075Sobrien      for (field = TREE_CHAIN (field);
183890075Sobrien	   field;
183990075Sobrien	   field = TREE_CHAIN (field))
184090075Sobrien	{
184190075Sobrien	  if (TREE_CODE (field) != FIELD_DECL)
184290075Sobrien	    continue;
184390075Sobrien
184490075Sobrien	  if (!DECL_BIT_FIELD_TYPE (field))
184590075Sobrien	    return 1;
184690075Sobrien	}
184790075Sobrien
184890075Sobrien      return 0;
184990075Sobrien    }
185090075Sobrien
185190075Sobrien  if (TREE_CODE (type) == UNION_TYPE)
185290075Sobrien    {
185390075Sobrien      tree field;
185490075Sobrien
185590075Sobrien      /* Unions can be returned in registers if every element is
185690075Sobrien	 integral, or can be returned in an integer register.  */
185790075Sobrien      for (field = TYPE_FIELDS (type);
185890075Sobrien	   field;
185990075Sobrien	   field = TREE_CHAIN (field))
186090075Sobrien	{
186190075Sobrien	  if (TREE_CODE (field) != FIELD_DECL)
186290075Sobrien	    continue;
186390075Sobrien
186490075Sobrien	  if (FLOAT_TYPE_P (TREE_TYPE (field)))
186590075Sobrien	    return 1;
186690075Sobrien
186790075Sobrien	  if (RETURN_IN_MEMORY (TREE_TYPE (field)))
186890075Sobrien	    return 1;
186990075Sobrien	}
187090075Sobrien
187190075Sobrien      return 0;
187290075Sobrien    }
187390075Sobrien#endif /* not ARM_WINCE */
187490075Sobrien
187590075Sobrien  /* Return all other types in memory.  */
187690075Sobrien  return 1;
187790075Sobrien}
187890075Sobrien
1879117395Skan/* Indicate whether or not words of a double are in big-endian order. */
1880117395Skan
1881117395Skanint
1882117395Skanarm_float_words_big_endian ()
1883117395Skan{
1884117395Skan
1885117395Skan  /* For FPA, float words are always big-endian.  For VFP, floats words
1886117395Skan     follow the memory system mode.  */
1887117395Skan
1888117395Skan  if (TARGET_HARD_FLOAT)
1889117395Skan    {
1890117395Skan      /* FIXME: TARGET_HARD_FLOAT currently implies FPA.  */
1891117395Skan      return 1;
1892117395Skan    }
1893117395Skan
1894117395Skan  if (TARGET_VFP)
1895117395Skan    return (TARGET_BIG_END ? 1 : 0);
1896117395Skan
1897117395Skan  return 1;
1898117395Skan}
1899117395Skan
190090075Sobrien/* Initialize a variable CUM of type CUMULATIVE_ARGS
190190075Sobrien   for a call to a function whose data type is FNTYPE.
190290075Sobrien   For a library call, FNTYPE is NULL.  */
190390075Sobrienvoid
190490075Sobrienarm_init_cumulative_args (pcum, fntype, libname, indirect)
190590075Sobrien     CUMULATIVE_ARGS * pcum;
190690075Sobrien     tree fntype;
190790075Sobrien     rtx libname  ATTRIBUTE_UNUSED;
190890075Sobrien     int indirect ATTRIBUTE_UNUSED;
190990075Sobrien{
191090075Sobrien  /* On the ARM, the offset starts at 0.  */
191190075Sobrien  pcum->nregs = ((fntype && aggregate_value_p (TREE_TYPE (fntype))) ? 1 : 0);
191290075Sobrien
191390075Sobrien  pcum->call_cookie = CALL_NORMAL;
191490075Sobrien
191590075Sobrien  if (TARGET_LONG_CALLS)
191690075Sobrien    pcum->call_cookie = CALL_LONG;
191790075Sobrien
191890075Sobrien  /* Check for long call/short call attributes.  The attributes
191990075Sobrien     override any command line option.  */
192090075Sobrien  if (fntype)
192190075Sobrien    {
192290075Sobrien      if (lookup_attribute ("short_call", TYPE_ATTRIBUTES (fntype)))
192390075Sobrien	pcum->call_cookie = CALL_SHORT;
192490075Sobrien      else if (lookup_attribute ("long_call", TYPE_ATTRIBUTES (fntype)))
192590075Sobrien	pcum->call_cookie = CALL_LONG;
192690075Sobrien    }
192790075Sobrien}
192890075Sobrien
192990075Sobrien/* Determine where to put an argument to a function.
193090075Sobrien   Value is zero to push the argument on the stack,
193190075Sobrien   or a hard register in which to store the argument.
193290075Sobrien
193390075Sobrien   MODE is the argument's machine mode.
193490075Sobrien   TYPE is the data type of the argument (as a tree).
193590075Sobrien    This is null for libcalls where that information may
193690075Sobrien    not be available.
193790075Sobrien   CUM is a variable of type CUMULATIVE_ARGS which gives info about
193890075Sobrien    the preceding args and about the function being called.
193990075Sobrien   NAMED is nonzero if this argument is a named parameter
194090075Sobrien    (otherwise it is an extra parameter matching an ellipsis).  */
194190075Sobrien
194290075Sobrienrtx
194390075Sobrienarm_function_arg (pcum, mode, type, named)
194490075Sobrien     CUMULATIVE_ARGS * pcum;
194590075Sobrien     enum machine_mode mode;
194690075Sobrien     tree type ATTRIBUTE_UNUSED;
194790075Sobrien     int named;
194890075Sobrien{
194990075Sobrien  if (mode == VOIDmode)
195090075Sobrien    /* Compute operand 2 of the call insn.  */
195190075Sobrien    return GEN_INT (pcum->call_cookie);
195290075Sobrien
195390075Sobrien  if (!named || pcum->nregs >= NUM_ARG_REGS)
195490075Sobrien    return NULL_RTX;
195590075Sobrien
195690075Sobrien  return gen_rtx_REG (mode, pcum->nregs);
195790075Sobrien}
1958117395Skan
1959117395Skan/* Variable sized types are passed by reference.  This is a GCC
1960117395Skan   extension to the ARM ABI.  */
1961117395Skan
1962117395Skanint
1963117395Skanarm_function_arg_pass_by_reference (cum, mode, type, named)
1964117395Skan     CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED;
1965117395Skan     enum machine_mode mode ATTRIBUTE_UNUSED;
1966117395Skan     tree type;
1967117395Skan     int named ATTRIBUTE_UNUSED;
1968117395Skan{
1969117395Skan  return type && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST;
1970117395Skan}
1971117395Skan
1972117395Skan/* Implement va_arg.  */
1973117395Skan
1974117395Skanrtx
1975117395Skanarm_va_arg (valist, type)
1976117395Skan     tree valist, type;
1977117395Skan{
1978117395Skan  /* Variable sized types are passed by reference.  */
1979117395Skan  if (TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
1980117395Skan    {
1981117395Skan      rtx addr = std_expand_builtin_va_arg (valist, build_pointer_type (type));
1982117395Skan      return gen_rtx_MEM (ptr_mode, force_reg (Pmode, addr));
1983117395Skan    }
1984117395Skan
1985117395Skan  return std_expand_builtin_va_arg (valist, type);
1986117395Skan}
198790075Sobrien
198890075Sobrien/* Encode the current state of the #pragma [no_]long_calls.  */
198990075Sobrientypedef enum
199090075Sobrien{
199190075Sobrien  OFF,		/* No #pramgma [no_]long_calls is in effect.  */
199290075Sobrien  LONG,		/* #pragma long_calls is in effect.  */
199390075Sobrien  SHORT		/* #pragma no_long_calls is in effect.  */
199490075Sobrien} arm_pragma_enum;
199590075Sobrien
199690075Sobrienstatic arm_pragma_enum arm_pragma_long_calls = OFF;
199790075Sobrien
199890075Sobrienvoid
199990075Sobrienarm_pr_long_calls (pfile)
200090075Sobrien     cpp_reader * pfile ATTRIBUTE_UNUSED;
200190075Sobrien{
200290075Sobrien  arm_pragma_long_calls = LONG;
200390075Sobrien}
200490075Sobrien
200590075Sobrienvoid
200690075Sobrienarm_pr_no_long_calls (pfile)
200790075Sobrien     cpp_reader * pfile ATTRIBUTE_UNUSED;
200890075Sobrien{
200990075Sobrien  arm_pragma_long_calls = SHORT;
201090075Sobrien}
201190075Sobrien
201290075Sobrienvoid
201390075Sobrienarm_pr_long_calls_off (pfile)
201490075Sobrien     cpp_reader * pfile ATTRIBUTE_UNUSED;
201590075Sobrien{
201690075Sobrien  arm_pragma_long_calls = OFF;
201790075Sobrien}
201890075Sobrien
201990075Sobrien/* Table of machine attributes.  */
202090075Sobrienconst struct attribute_spec arm_attribute_table[] =
202190075Sobrien{
202290075Sobrien  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
202390075Sobrien  /* Function calls made to this symbol must be done indirectly, because
202490075Sobrien     it may lie outside of the 26 bit addressing range of a normal function
202590075Sobrien     call.  */
202690075Sobrien  { "long_call",    0, 0, false, true,  true,  NULL },
202790075Sobrien  /* Whereas these functions are always known to reside within the 26 bit
202890075Sobrien     addressing range.  */
202990075Sobrien  { "short_call",   0, 0, false, true,  true,  NULL },
203090075Sobrien  /* Interrupt Service Routines have special prologue and epilogue requirements.  */
203190075Sobrien  { "isr",          0, 1, false, false, false, arm_handle_isr_attribute },
203290075Sobrien  { "interrupt",    0, 1, false, false, false, arm_handle_isr_attribute },
203390075Sobrien  { "naked",        0, 0, true,  false, false, arm_handle_fndecl_attribute },
203490075Sobrien#ifdef ARM_PE
203590075Sobrien  /* ARM/PE has three new attributes:
203690075Sobrien     interfacearm - ?
203790075Sobrien     dllexport - for exporting a function/variable that will live in a dll
203890075Sobrien     dllimport - for importing a function/variable from a dll
203990075Sobrien
204090075Sobrien     Microsoft allows multiple declspecs in one __declspec, separating
204190075Sobrien     them with spaces.  We do NOT support this.  Instead, use __declspec
204290075Sobrien     multiple times.
204390075Sobrien  */
204490075Sobrien  { "dllimport",    0, 0, true,  false, false, NULL },
204590075Sobrien  { "dllexport",    0, 0, true,  false, false, NULL },
204690075Sobrien  { "interfacearm", 0, 0, true,  false, false, arm_handle_fndecl_attribute },
204790075Sobrien#endif
204890075Sobrien  { NULL,           0, 0, false, false, false, NULL }
204990075Sobrien};
205090075Sobrien
205190075Sobrien/* Handle an attribute requiring a FUNCTION_DECL;
205290075Sobrien   arguments as in struct attribute_spec.handler.  */
205390075Sobrien
205490075Sobrienstatic tree
205590075Sobrienarm_handle_fndecl_attribute (node, name, args, flags, no_add_attrs)
205690075Sobrien     tree * node;
205790075Sobrien     tree   name;
205890075Sobrien     tree   args ATTRIBUTE_UNUSED;
205990075Sobrien     int    flags ATTRIBUTE_UNUSED;
206090075Sobrien     bool * no_add_attrs;
206190075Sobrien{
206290075Sobrien  if (TREE_CODE (*node) != FUNCTION_DECL)
206390075Sobrien    {
206490075Sobrien      warning ("`%s' attribute only applies to functions",
206590075Sobrien	       IDENTIFIER_POINTER (name));
206690075Sobrien      *no_add_attrs = true;
206790075Sobrien    }
206890075Sobrien
206990075Sobrien  return NULL_TREE;
207090075Sobrien}
207190075Sobrien
207290075Sobrien/* Handle an "interrupt" or "isr" attribute;
207390075Sobrien   arguments as in struct attribute_spec.handler.  */
207490075Sobrien
207590075Sobrienstatic tree
207690075Sobrienarm_handle_isr_attribute (node, name, args, flags, no_add_attrs)
207790075Sobrien     tree * node;
207890075Sobrien     tree   name;
207990075Sobrien     tree   args;
208090075Sobrien     int    flags;
208190075Sobrien     bool * no_add_attrs;
208290075Sobrien{
208390075Sobrien  if (DECL_P (*node))
208490075Sobrien    {
208590075Sobrien      if (TREE_CODE (*node) != FUNCTION_DECL)
208690075Sobrien	{
208790075Sobrien	  warning ("`%s' attribute only applies to functions",
208890075Sobrien		   IDENTIFIER_POINTER (name));
208990075Sobrien	  *no_add_attrs = true;
209090075Sobrien	}
209190075Sobrien      /* FIXME: the argument if any is checked for type attributes;
209290075Sobrien	 should it be checked for decl ones?  */
209390075Sobrien    }
209490075Sobrien  else
209590075Sobrien    {
209690075Sobrien      if (TREE_CODE (*node) == FUNCTION_TYPE
209790075Sobrien	  || TREE_CODE (*node) == METHOD_TYPE)
209890075Sobrien	{
209990075Sobrien	  if (arm_isr_value (args) == ARM_FT_UNKNOWN)
210090075Sobrien	    {
210190075Sobrien	      warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
210290075Sobrien	      *no_add_attrs = true;
210390075Sobrien	    }
210490075Sobrien	}
210590075Sobrien      else if (TREE_CODE (*node) == POINTER_TYPE
210690075Sobrien	       && (TREE_CODE (TREE_TYPE (*node)) == FUNCTION_TYPE
210790075Sobrien		   || TREE_CODE (TREE_TYPE (*node)) == METHOD_TYPE)
210890075Sobrien	       && arm_isr_value (args) != ARM_FT_UNKNOWN)
210990075Sobrien	{
211090075Sobrien	  *node = build_type_copy (*node);
211190075Sobrien	  TREE_TYPE (*node) = build_type_attribute_variant
211290075Sobrien	    (TREE_TYPE (*node),
211390075Sobrien	     tree_cons (name, args, TYPE_ATTRIBUTES (TREE_TYPE (*node))));
211490075Sobrien	  *no_add_attrs = true;
211590075Sobrien	}
211690075Sobrien      else
211790075Sobrien	{
211890075Sobrien	  /* Possibly pass this attribute on from the type to a decl.  */
211990075Sobrien	  if (flags & ((int) ATTR_FLAG_DECL_NEXT
212090075Sobrien		       | (int) ATTR_FLAG_FUNCTION_NEXT
212190075Sobrien		       | (int) ATTR_FLAG_ARRAY_NEXT))
212290075Sobrien	    {
212390075Sobrien	      *no_add_attrs = true;
212490075Sobrien	      return tree_cons (name, args, NULL_TREE);
212590075Sobrien	    }
212690075Sobrien	  else
212790075Sobrien	    {
212890075Sobrien	      warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
212990075Sobrien	    }
213090075Sobrien	}
213190075Sobrien    }
213290075Sobrien
213390075Sobrien  return NULL_TREE;
213490075Sobrien}
213590075Sobrien
213690075Sobrien/* Return 0 if the attributes for two types are incompatible, 1 if they
213790075Sobrien   are compatible, and 2 if they are nearly compatible (which causes a
213890075Sobrien   warning to be generated).  */
213990075Sobrien
214090075Sobrienstatic int
214190075Sobrienarm_comp_type_attributes (type1, type2)
214290075Sobrien     tree type1;
214390075Sobrien     tree type2;
214490075Sobrien{
214590075Sobrien  int l1, l2, s1, s2;
214690075Sobrien
214790075Sobrien  /* Check for mismatch of non-default calling convention.  */
214890075Sobrien  if (TREE_CODE (type1) != FUNCTION_TYPE)
214990075Sobrien    return 1;
215090075Sobrien
215190075Sobrien  /* Check for mismatched call attributes.  */
215290075Sobrien  l1 = lookup_attribute ("long_call", TYPE_ATTRIBUTES (type1)) != NULL;
215390075Sobrien  l2 = lookup_attribute ("long_call", TYPE_ATTRIBUTES (type2)) != NULL;
215490075Sobrien  s1 = lookup_attribute ("short_call", TYPE_ATTRIBUTES (type1)) != NULL;
215590075Sobrien  s2 = lookup_attribute ("short_call", TYPE_ATTRIBUTES (type2)) != NULL;
215690075Sobrien
215790075Sobrien  /* Only bother to check if an attribute is defined.  */
215890075Sobrien  if (l1 | l2 | s1 | s2)
215990075Sobrien    {
216090075Sobrien      /* If one type has an attribute, the other must have the same attribute.  */
216190075Sobrien      if ((l1 != l2) || (s1 != s2))
216290075Sobrien	return 0;
216390075Sobrien
216490075Sobrien      /* Disallow mixed attributes.  */
216590075Sobrien      if ((l1 & s2) || (l2 & s1))
216690075Sobrien	return 0;
216790075Sobrien    }
216890075Sobrien
216990075Sobrien  /* Check for mismatched ISR attribute.  */
217090075Sobrien  l1 = lookup_attribute ("isr", TYPE_ATTRIBUTES (type1)) != NULL;
217190075Sobrien  if (! l1)
217290075Sobrien    l1 = lookup_attribute ("interrupt", TYPE_ATTRIBUTES (type1)) != NULL;
217390075Sobrien  l2 = lookup_attribute ("isr", TYPE_ATTRIBUTES (type2)) != NULL;
217490075Sobrien  if (! l2)
217590075Sobrien    l1 = lookup_attribute ("interrupt", TYPE_ATTRIBUTES (type2)) != NULL;
217690075Sobrien  if (l1 != l2)
217790075Sobrien    return 0;
217890075Sobrien
217990075Sobrien  return 1;
218090075Sobrien}
218190075Sobrien
218290075Sobrien/*  Encode long_call or short_call attribute by prefixing
218390075Sobrien    symbol name in DECL with a special character FLAG.  */
218490075Sobrien
218590075Sobrienvoid
218690075Sobrienarm_encode_call_attribute (decl, flag)
218790075Sobrien  tree decl;
218890075Sobrien  int flag;
218990075Sobrien{
219090075Sobrien  const char * str = XSTR (XEXP (DECL_RTL (decl), 0), 0);
219190075Sobrien  int          len = strlen (str);
219290075Sobrien  char *       newstr;
219390075Sobrien
219490075Sobrien  /* Do not allow weak functions to be treated as short call.  */
219590075Sobrien  if (DECL_WEAK (decl) && flag == SHORT_CALL_FLAG_CHAR)
219690075Sobrien    return;
219790075Sobrien
219890075Sobrien  newstr = alloca (len + 2);
219990075Sobrien  newstr[0] = flag;
220090075Sobrien  strcpy (newstr + 1, str);
220190075Sobrien
220290075Sobrien  newstr = (char *) ggc_alloc_string (newstr, len + 1);
220390075Sobrien  XSTR (XEXP (DECL_RTL (decl), 0), 0) = newstr;
220490075Sobrien}
220590075Sobrien
220690075Sobrien/*  Assigns default attributes to newly defined type.  This is used to
220790075Sobrien    set short_call/long_call attributes for function types of
220890075Sobrien    functions defined inside corresponding #pragma scopes.  */
220990075Sobrien
221090075Sobrienstatic void
221190075Sobrienarm_set_default_type_attributes (type)
221290075Sobrien  tree type;
221390075Sobrien{
221490075Sobrien  /* Add __attribute__ ((long_call)) to all functions, when
221590075Sobrien     inside #pragma long_calls or __attribute__ ((short_call)),
221690075Sobrien     when inside #pragma no_long_calls.  */
221790075Sobrien  if (TREE_CODE (type) == FUNCTION_TYPE || TREE_CODE (type) == METHOD_TYPE)
221890075Sobrien    {
221990075Sobrien      tree type_attr_list, attr_name;
222090075Sobrien      type_attr_list = TYPE_ATTRIBUTES (type);
222190075Sobrien
222290075Sobrien      if (arm_pragma_long_calls == LONG)
222390075Sobrien 	attr_name = get_identifier ("long_call");
222490075Sobrien      else if (arm_pragma_long_calls == SHORT)
222590075Sobrien 	attr_name = get_identifier ("short_call");
222690075Sobrien      else
222790075Sobrien 	return;
222890075Sobrien
222990075Sobrien      type_attr_list = tree_cons (attr_name, NULL_TREE, type_attr_list);
223090075Sobrien      TYPE_ATTRIBUTES (type) = type_attr_list;
223190075Sobrien    }
223290075Sobrien}
223390075Sobrien
223490075Sobrien/* Return 1 if the operand is a SYMBOL_REF for a function known to be
223590075Sobrien   defined within the current compilation unit.  If this caanot be
223690075Sobrien   determined, then 0 is returned.  */
223790075Sobrien
223890075Sobrienstatic int
223990075Sobriencurrent_file_function_operand (sym_ref)
224090075Sobrien  rtx sym_ref;
224190075Sobrien{
224290075Sobrien  /* This is a bit of a fib.  A function will have a short call flag
224390075Sobrien     applied to its name if it has the short call attribute, or it has
224490075Sobrien     already been defined within the current compilation unit.  */
224590075Sobrien  if (ENCODED_SHORT_CALL_ATTR_P (XSTR (sym_ref, 0)))
224690075Sobrien    return 1;
224790075Sobrien
224890075Sobrien  /* The current function is always defined within the current compilation
224990075Sobrien     unit.  if it s a weak definition however, then this may not be the real
225090075Sobrien     definition of the function, and so we have to say no.  */
225190075Sobrien  if (sym_ref == XEXP (DECL_RTL (current_function_decl), 0)
225290075Sobrien      && !DECL_WEAK (current_function_decl))
225390075Sobrien    return 1;
225490075Sobrien
225590075Sobrien  /* We cannot make the determination - default to returning 0.  */
225690075Sobrien  return 0;
225790075Sobrien}
225890075Sobrien
2259117395Skan/* Return nonzero if a 32 bit "long_call" should be generated for
226090075Sobrien   this call.  We generate a long_call if the function:
226190075Sobrien
226290075Sobrien        a.  has an __attribute__((long call))
226390075Sobrien     or b.  is within the scope of a #pragma long_calls
226490075Sobrien     or c.  the -mlong-calls command line switch has been specified
226590075Sobrien
226690075Sobrien   However we do not generate a long call if the function:
226790075Sobrien
226890075Sobrien        d.  has an __attribute__ ((short_call))
226990075Sobrien     or e.  is inside the scope of a #pragma no_long_calls
227090075Sobrien     or f.  has an __attribute__ ((section))
227190075Sobrien     or g.  is defined within the current compilation unit.
227290075Sobrien
227390075Sobrien   This function will be called by C fragments contained in the machine
227490075Sobrien   description file.  CALL_REF and CALL_COOKIE correspond to the matched
227590075Sobrien   rtl operands.  CALL_SYMBOL is used to distinguish between
227690075Sobrien   two different callers of the function.  It is set to 1 in the
227790075Sobrien   "call_symbol" and "call_symbol_value" patterns and to 0 in the "call"
227890075Sobrien   and "call_value" patterns.  This is because of the difference in the
227990075Sobrien   SYM_REFs passed by these patterns.  */
228090075Sobrien
228190075Sobrienint
228290075Sobrienarm_is_longcall_p (sym_ref, call_cookie, call_symbol)
228390075Sobrien  rtx sym_ref;
228490075Sobrien  int call_cookie;
228590075Sobrien  int call_symbol;
228690075Sobrien{
228790075Sobrien  if (!call_symbol)
228890075Sobrien    {
228990075Sobrien      if (GET_CODE (sym_ref) != MEM)
229090075Sobrien	return 0;
229190075Sobrien
229290075Sobrien      sym_ref = XEXP (sym_ref, 0);
229390075Sobrien    }
229490075Sobrien
229590075Sobrien  if (GET_CODE (sym_ref) != SYMBOL_REF)
229690075Sobrien    return 0;
229790075Sobrien
229890075Sobrien  if (call_cookie & CALL_SHORT)
229990075Sobrien    return 0;
230090075Sobrien
230190075Sobrien  if (TARGET_LONG_CALLS && flag_function_sections)
230290075Sobrien    return 1;
230390075Sobrien
230490075Sobrien  if (current_file_function_operand (sym_ref))
230590075Sobrien    return 0;
230690075Sobrien
230790075Sobrien  return (call_cookie & CALL_LONG)
230890075Sobrien    || ENCODED_LONG_CALL_ATTR_P (XSTR (sym_ref, 0))
230990075Sobrien    || TARGET_LONG_CALLS;
231090075Sobrien}
231190075Sobrien
2312117395Skan/* Return nonzero if it is ok to make a tail-call to DECL.  */
231390075Sobrien
231490075Sobrienint
231590075Sobrienarm_function_ok_for_sibcall (decl)
231690075Sobrien     tree decl;
231790075Sobrien{
231890075Sobrien  int call_type = TARGET_LONG_CALLS ? CALL_LONG : CALL_NORMAL;
231990075Sobrien
232090075Sobrien  /* Never tailcall something for which we have no decl, or if we
232190075Sobrien     are in Thumb mode.  */
232290075Sobrien  if (decl == NULL || TARGET_THUMB)
232390075Sobrien    return 0;
232490075Sobrien
232590075Sobrien  /* Get the calling method.  */
232690075Sobrien  if (lookup_attribute ("short_call", TYPE_ATTRIBUTES (TREE_TYPE (decl))))
232790075Sobrien    call_type = CALL_SHORT;
232890075Sobrien  else if (lookup_attribute ("long_call", TYPE_ATTRIBUTES (TREE_TYPE (decl))))
232990075Sobrien    call_type = CALL_LONG;
233090075Sobrien
233190075Sobrien  /* Cannot tail-call to long calls, since these are out of range of
233290075Sobrien     a branch instruction.  However, if not compiling PIC, we know
233390075Sobrien     we can reach the symbol if it is in this compilation unit.  */
233490075Sobrien  if (call_type == CALL_LONG && (flag_pic || !TREE_ASM_WRITTEN (decl)))
233590075Sobrien    return 0;
233690075Sobrien
233790075Sobrien  /* If we are interworking and the function is not declared static
233890075Sobrien     then we can't tail-call it unless we know that it exists in this
233990075Sobrien     compilation unit (since it might be a Thumb routine).  */
234090075Sobrien  if (TARGET_INTERWORK && TREE_PUBLIC (decl) && !TREE_ASM_WRITTEN (decl))
234190075Sobrien    return 0;
234290075Sobrien
234390075Sobrien  /* Never tailcall from an ISR routine - it needs a special exit sequence.  */
234490075Sobrien  if (IS_INTERRUPT (arm_current_func_type ()))
234590075Sobrien    return 0;
234690075Sobrien
234790075Sobrien  /* Everything else is ok.  */
234890075Sobrien  return 1;
234990075Sobrien}
235090075Sobrien
235190075Sobrien
235290075Sobrienint
235390075Sobrienlegitimate_pic_operand_p (x)
235490075Sobrien     rtx x;
235590075Sobrien{
235690075Sobrien  if (CONSTANT_P (x)
235790075Sobrien      && flag_pic
235890075Sobrien      && (GET_CODE (x) == SYMBOL_REF
235990075Sobrien	  || (GET_CODE (x) == CONST
236090075Sobrien	      && GET_CODE (XEXP (x, 0)) == PLUS
236190075Sobrien	      && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF)))
236290075Sobrien    return 0;
236390075Sobrien
236490075Sobrien  return 1;
236590075Sobrien}
236690075Sobrien
236790075Sobrienrtx
236890075Sobrienlegitimize_pic_address (orig, mode, reg)
236990075Sobrien     rtx orig;
237090075Sobrien     enum machine_mode mode;
237190075Sobrien     rtx reg;
237290075Sobrien{
237390075Sobrien  if (GET_CODE (orig) == SYMBOL_REF
237490075Sobrien      || GET_CODE (orig) == LABEL_REF)
237590075Sobrien    {
237690075Sobrien#ifndef AOF_ASSEMBLER
237790075Sobrien      rtx pic_ref, address;
237890075Sobrien#endif
237990075Sobrien      rtx insn;
238090075Sobrien      int subregs = 0;
238190075Sobrien
238290075Sobrien      if (reg == 0)
238390075Sobrien	{
238490075Sobrien	  if (no_new_pseudos)
238590075Sobrien	    abort ();
238690075Sobrien	  else
238790075Sobrien	    reg = gen_reg_rtx (Pmode);
238890075Sobrien
238990075Sobrien	  subregs = 1;
239090075Sobrien	}
239190075Sobrien
239290075Sobrien#ifdef AOF_ASSEMBLER
239390075Sobrien      /* The AOF assembler can generate relocations for these directly, and
239490075Sobrien	 understands that the PIC register has to be added into the offset.  */
239590075Sobrien      insn = emit_insn (gen_pic_load_addr_based (reg, orig));
239690075Sobrien#else
239790075Sobrien      if (subregs)
239890075Sobrien	address = gen_reg_rtx (Pmode);
239990075Sobrien      else
240090075Sobrien	address = reg;
240190075Sobrien
240290075Sobrien      if (TARGET_ARM)
240390075Sobrien	emit_insn (gen_pic_load_addr_arm (address, orig));
240490075Sobrien      else
240590075Sobrien	emit_insn (gen_pic_load_addr_thumb (address, orig));
240690075Sobrien
240796263Sobrien      if ((GET_CODE (orig) == LABEL_REF
240896263Sobrien	   || (GET_CODE (orig) == SYMBOL_REF &&
240996263Sobrien	       ENCODED_SHORT_CALL_ATTR_P (XSTR (orig, 0))))
241096263Sobrien	  && NEED_GOT_RELOC)
241190075Sobrien	pic_ref = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, address);
241290075Sobrien      else
241390075Sobrien	{
241490075Sobrien	  pic_ref = gen_rtx_MEM (Pmode,
241590075Sobrien				 gen_rtx_PLUS (Pmode, pic_offset_table_rtx,
241690075Sobrien					       address));
241790075Sobrien	  RTX_UNCHANGING_P (pic_ref) = 1;
241890075Sobrien	}
241990075Sobrien
242090075Sobrien      insn = emit_move_insn (reg, pic_ref);
242190075Sobrien#endif
242290075Sobrien      current_function_uses_pic_offset_table = 1;
242390075Sobrien      /* Put a REG_EQUAL note on this insn, so that it can be optimized
242490075Sobrien	 by loop.  */
242590075Sobrien      REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, orig,
242690075Sobrien					    REG_NOTES (insn));
242790075Sobrien      return reg;
242890075Sobrien    }
242990075Sobrien  else if (GET_CODE (orig) == CONST)
243090075Sobrien    {
243190075Sobrien      rtx base, offset;
243290075Sobrien
243390075Sobrien      if (GET_CODE (XEXP (orig, 0)) == PLUS
243490075Sobrien	  && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx)
243590075Sobrien	return orig;
243690075Sobrien
243790075Sobrien      if (reg == 0)
243890075Sobrien	{
243990075Sobrien	  if (no_new_pseudos)
244090075Sobrien	    abort ();
244190075Sobrien	  else
244290075Sobrien	    reg = gen_reg_rtx (Pmode);
244390075Sobrien	}
244490075Sobrien
244590075Sobrien      if (GET_CODE (XEXP (orig, 0)) == PLUS)
244690075Sobrien	{
244790075Sobrien	  base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg);
244890075Sobrien	  offset = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode,
244990075Sobrien					   base == reg ? 0 : reg);
245090075Sobrien	}
245190075Sobrien      else
245290075Sobrien	abort ();
245390075Sobrien
245490075Sobrien      if (GET_CODE (offset) == CONST_INT)
245590075Sobrien	{
245690075Sobrien	  /* The base register doesn't really matter, we only want to
245790075Sobrien	     test the index for the appropriate mode.  */
245890075Sobrien	  ARM_GO_IF_LEGITIMATE_INDEX (mode, 0, offset, win);
245990075Sobrien
246090075Sobrien	  if (!no_new_pseudos)
246190075Sobrien	    offset = force_reg (Pmode, offset);
246290075Sobrien	  else
246390075Sobrien	    abort ();
246490075Sobrien
246590075Sobrien	win:
246690075Sobrien	  if (GET_CODE (offset) == CONST_INT)
246790075Sobrien	    return plus_constant (base, INTVAL (offset));
246890075Sobrien	}
246990075Sobrien
247090075Sobrien      if (GET_MODE_SIZE (mode) > 4
247190075Sobrien	  && (GET_MODE_CLASS (mode) == MODE_INT
247290075Sobrien	      || TARGET_SOFT_FLOAT))
247390075Sobrien	{
247490075Sobrien	  emit_insn (gen_addsi3 (reg, base, offset));
247590075Sobrien	  return reg;
247690075Sobrien	}
247790075Sobrien
247890075Sobrien      return gen_rtx_PLUS (Pmode, base, offset);
247990075Sobrien    }
248090075Sobrien
248190075Sobrien  return orig;
248290075Sobrien}
248390075Sobrien
248490075Sobrien/* Generate code to load the PIC register.  PROLOGUE is true if
248590075Sobrien   called from arm_expand_prologue (in which case we want the
248690075Sobrien   generated insns at the start of the function);  false if called
248790075Sobrien   by an exception receiver that needs the PIC register reloaded
248890075Sobrien   (in which case the insns are just dumped at the current location).  */
248990075Sobrien
249090075Sobrienvoid
249190075Sobrienarm_finalize_pic (prologue)
249290075Sobrien     int prologue ATTRIBUTE_UNUSED;
249390075Sobrien{
249490075Sobrien#ifndef AOF_ASSEMBLER
249590075Sobrien  rtx l1, pic_tmp, pic_tmp2, seq, pic_rtx;
249690075Sobrien  rtx global_offset_table;
249790075Sobrien
249890075Sobrien  if (current_function_uses_pic_offset_table == 0 || TARGET_SINGLE_PIC_BASE)
249990075Sobrien    return;
250090075Sobrien
250190075Sobrien  if (!flag_pic)
250290075Sobrien    abort ();
250390075Sobrien
250490075Sobrien  start_sequence ();
250590075Sobrien  l1 = gen_label_rtx ();
250690075Sobrien
250790075Sobrien  global_offset_table = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
250890075Sobrien  /* On the ARM the PC register contains 'dot + 8' at the time of the
250990075Sobrien     addition, on the Thumb it is 'dot + 4'.  */
251090075Sobrien  pic_tmp = plus_constant (gen_rtx_LABEL_REF (Pmode, l1), TARGET_ARM ? 8 : 4);
251190075Sobrien  if (GOT_PCREL)
251290075Sobrien    pic_tmp2 = gen_rtx_CONST (VOIDmode,
251390075Sobrien			    gen_rtx_PLUS (Pmode, global_offset_table, pc_rtx));
251490075Sobrien  else
251590075Sobrien    pic_tmp2 = gen_rtx_CONST (VOIDmode, global_offset_table);
251690075Sobrien
251790075Sobrien  pic_rtx = gen_rtx_CONST (Pmode, gen_rtx_MINUS (Pmode, pic_tmp2, pic_tmp));
251890075Sobrien
251990075Sobrien  if (TARGET_ARM)
252090075Sobrien    {
252190075Sobrien      emit_insn (gen_pic_load_addr_arm (pic_offset_table_rtx, pic_rtx));
252290075Sobrien      emit_insn (gen_pic_add_dot_plus_eight (pic_offset_table_rtx, l1));
252390075Sobrien    }
252490075Sobrien  else
252590075Sobrien    {
252690075Sobrien      emit_insn (gen_pic_load_addr_thumb (pic_offset_table_rtx, pic_rtx));
252790075Sobrien      emit_insn (gen_pic_add_dot_plus_four (pic_offset_table_rtx, l1));
252890075Sobrien    }
252990075Sobrien
2530117395Skan  seq = get_insns ();
253190075Sobrien  end_sequence ();
253290075Sobrien  if (prologue)
253390075Sobrien    emit_insn_after (seq, get_insns ());
253490075Sobrien  else
253590075Sobrien    emit_insn (seq);
253690075Sobrien
253790075Sobrien  /* Need to emit this whether or not we obey regdecls,
253890075Sobrien     since setjmp/longjmp can cause life info to screw up.  */
253990075Sobrien  emit_insn (gen_rtx_USE (VOIDmode, pic_offset_table_rtx));
254090075Sobrien#endif /* AOF_ASSEMBLER */
254190075Sobrien}
254290075Sobrien
254390075Sobrien#define REG_OR_SUBREG_REG(X)						\
254490075Sobrien  (GET_CODE (X) == REG							\
254590075Sobrien   || (GET_CODE (X) == SUBREG && GET_CODE (SUBREG_REG (X)) == REG))
254690075Sobrien
254790075Sobrien#define REG_OR_SUBREG_RTX(X)			\
254890075Sobrien   (GET_CODE (X) == REG ? (X) : SUBREG_REG (X))
254990075Sobrien
255090075Sobrien#ifndef COSTS_N_INSNS
255190075Sobrien#define COSTS_N_INSNS(N) ((N) * 4 - 2)
255290075Sobrien#endif
255390075Sobrien
255490075Sobrienint
255590075Sobrienarm_rtx_costs (x, code, outer)
255690075Sobrien     rtx x;
255790075Sobrien     enum rtx_code code;
255890075Sobrien     enum rtx_code outer;
255990075Sobrien{
256090075Sobrien  enum machine_mode mode = GET_MODE (x);
256190075Sobrien  enum rtx_code subcode;
256290075Sobrien  int extra_cost;
256390075Sobrien
256490075Sobrien  if (TARGET_THUMB)
256590075Sobrien    {
256690075Sobrien      switch (code)
256790075Sobrien	{
256890075Sobrien	case ASHIFT:
256990075Sobrien	case ASHIFTRT:
257090075Sobrien	case LSHIFTRT:
257190075Sobrien	case ROTATERT:
257290075Sobrien	case PLUS:
257390075Sobrien	case MINUS:
257490075Sobrien	case COMPARE:
257590075Sobrien	case NEG:
257690075Sobrien	case NOT:
257790075Sobrien	  return COSTS_N_INSNS (1);
257890075Sobrien
257990075Sobrien	case MULT:
258090075Sobrien	  if (GET_CODE (XEXP (x, 1)) == CONST_INT)
258190075Sobrien	    {
258290075Sobrien	      int cycles = 0;
258390075Sobrien	      unsigned HOST_WIDE_INT i = INTVAL (XEXP (x, 1));
258490075Sobrien
258590075Sobrien	      while (i)
258690075Sobrien		{
258790075Sobrien		  i >>= 2;
258890075Sobrien		  cycles++;
258990075Sobrien		}
259090075Sobrien	      return COSTS_N_INSNS (2) + cycles;
259190075Sobrien	    }
259290075Sobrien	  return COSTS_N_INSNS (1) + 16;
259390075Sobrien
259490075Sobrien	case SET:
259590075Sobrien	  return (COSTS_N_INSNS (1)
259690075Sobrien		  + 4 * ((GET_CODE (SET_SRC (x)) == MEM)
259790075Sobrien			 + GET_CODE (SET_DEST (x)) == MEM));
259890075Sobrien
259990075Sobrien	case CONST_INT:
260090075Sobrien	  if (outer == SET)
260190075Sobrien	    {
260290075Sobrien	      if ((unsigned HOST_WIDE_INT) INTVAL (x) < 256)
260390075Sobrien		return 0;
260490075Sobrien	      if (thumb_shiftable_const (INTVAL (x)))
260590075Sobrien		return COSTS_N_INSNS (2);
260690075Sobrien	      return COSTS_N_INSNS (3);
260790075Sobrien	    }
260890075Sobrien	  else if (outer == PLUS
260990075Sobrien		   && INTVAL (x) < 256 && INTVAL (x) > -256)
261090075Sobrien	    return 0;
261190075Sobrien	  else if (outer == COMPARE
261290075Sobrien		   && (unsigned HOST_WIDE_INT) INTVAL (x) < 256)
261390075Sobrien	    return 0;
261490075Sobrien	  else if (outer == ASHIFT || outer == ASHIFTRT
261590075Sobrien		   || outer == LSHIFTRT)
261690075Sobrien	    return 0;
261790075Sobrien	  return COSTS_N_INSNS (2);
261890075Sobrien
261990075Sobrien	case CONST:
262090075Sobrien	case CONST_DOUBLE:
262190075Sobrien	case LABEL_REF:
262290075Sobrien	case SYMBOL_REF:
262390075Sobrien	  return COSTS_N_INSNS (3);
262490075Sobrien
262590075Sobrien	case UDIV:
262690075Sobrien	case UMOD:
262790075Sobrien	case DIV:
262890075Sobrien	case MOD:
262990075Sobrien	  return 100;
263090075Sobrien
263190075Sobrien	case TRUNCATE:
263290075Sobrien	  return 99;
263390075Sobrien
263490075Sobrien	case AND:
263590075Sobrien	case XOR:
263690075Sobrien	case IOR:
263790075Sobrien	  /* XXX guess. */
263890075Sobrien	  return 8;
263990075Sobrien
264090075Sobrien	case ADDRESSOF:
264190075Sobrien	case MEM:
264290075Sobrien	  /* XXX another guess.  */
264390075Sobrien	  /* Memory costs quite a lot for the first word, but subsequent words
264490075Sobrien	     load at the equivalent of a single insn each.  */
264590075Sobrien	  return (10 + 4 * ((GET_MODE_SIZE (mode) - 1) / UNITS_PER_WORD)
2646117395Skan		  + ((GET_CODE (x) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (x))
2647117395Skan		     ? 4 : 0));
264890075Sobrien
264990075Sobrien	case IF_THEN_ELSE:
265090075Sobrien	  /* XXX a guess. */
265190075Sobrien	  if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC)
265290075Sobrien	    return 14;
265390075Sobrien	  return 2;
265490075Sobrien
265590075Sobrien	case ZERO_EXTEND:
265690075Sobrien	  /* XXX still guessing.  */
265790075Sobrien	  switch (GET_MODE (XEXP (x, 0)))
265890075Sobrien	    {
265990075Sobrien	    case QImode:
266090075Sobrien	      return (1 + (mode == DImode ? 4 : 0)
266190075Sobrien		      + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
266290075Sobrien
266390075Sobrien	    case HImode:
266490075Sobrien	      return (4 + (mode == DImode ? 4 : 0)
266590075Sobrien		      + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
266690075Sobrien
266790075Sobrien	    case SImode:
266890075Sobrien	      return (1 + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
266990075Sobrien
267090075Sobrien	    default:
267190075Sobrien	      return 99;
267290075Sobrien	    }
267390075Sobrien
267490075Sobrien	default:
267590075Sobrien	  return 99;
267690075Sobrien#if 0
267790075Sobrien	case FFS:
267890075Sobrien	case FLOAT:
267990075Sobrien	case FIX:
268090075Sobrien	case UNSIGNED_FIX:
268190075Sobrien	  /* XXX guess */
268290075Sobrien	  fprintf (stderr, "unexpected code for thumb in rtx_costs: %s\n",
268390075Sobrien		   rtx_name[code]);
268490075Sobrien	  abort ();
268590075Sobrien#endif
268690075Sobrien	}
268790075Sobrien    }
268890075Sobrien
268990075Sobrien  switch (code)
269090075Sobrien    {
269190075Sobrien    case MEM:
269290075Sobrien      /* Memory costs quite a lot for the first word, but subsequent words
269390075Sobrien	 load at the equivalent of a single insn each.  */
269490075Sobrien      return (10 + 4 * ((GET_MODE_SIZE (mode) - 1) / UNITS_PER_WORD)
2695117395Skan	      + (GET_CODE (x) == SYMBOL_REF
2696117395Skan		 && CONSTANT_POOL_ADDRESS_P (x) ? 4 : 0));
269790075Sobrien
269890075Sobrien    case DIV:
269990075Sobrien    case MOD:
270090075Sobrien      return 100;
270190075Sobrien
270290075Sobrien    case ROTATE:
270390075Sobrien      if (mode == SImode && GET_CODE (XEXP (x, 1)) == REG)
270490075Sobrien	return 4;
270590075Sobrien      /* Fall through */
270690075Sobrien    case ROTATERT:
270790075Sobrien      if (mode != SImode)
270890075Sobrien	return 8;
270990075Sobrien      /* Fall through */
271090075Sobrien    case ASHIFT: case LSHIFTRT: case ASHIFTRT:
271190075Sobrien      if (mode == DImode)
271290075Sobrien	return (8 + (GET_CODE (XEXP (x, 1)) == CONST_INT ? 0 : 8)
271390075Sobrien		+ ((GET_CODE (XEXP (x, 0)) == REG
271490075Sobrien		    || (GET_CODE (XEXP (x, 0)) == SUBREG
271590075Sobrien			&& GET_CODE (SUBREG_REG (XEXP (x, 0))) == REG))
271690075Sobrien		   ? 0 : 8));
271790075Sobrien      return (1 + ((GET_CODE (XEXP (x, 0)) == REG
271890075Sobrien		    || (GET_CODE (XEXP (x, 0)) == SUBREG
271990075Sobrien			&& GET_CODE (SUBREG_REG (XEXP (x, 0))) == REG))
272090075Sobrien		   ? 0 : 4)
272190075Sobrien	      + ((GET_CODE (XEXP (x, 1)) == REG
272290075Sobrien		  || (GET_CODE (XEXP (x, 1)) == SUBREG
272390075Sobrien		      && GET_CODE (SUBREG_REG (XEXP (x, 1))) == REG)
272490075Sobrien		  || (GET_CODE (XEXP (x, 1)) == CONST_INT))
272590075Sobrien		 ? 0 : 4));
272690075Sobrien
272790075Sobrien    case MINUS:
272890075Sobrien      if (mode == DImode)
272990075Sobrien	return (4 + (REG_OR_SUBREG_REG (XEXP (x, 1)) ? 0 : 8)
273090075Sobrien		+ ((REG_OR_SUBREG_REG (XEXP (x, 0))
273190075Sobrien		    || (GET_CODE (XEXP (x, 0)) == CONST_INT
273290075Sobrien		       && const_ok_for_arm (INTVAL (XEXP (x, 0)))))
273390075Sobrien		   ? 0 : 8));
273490075Sobrien
273590075Sobrien      if (GET_MODE_CLASS (mode) == MODE_FLOAT)
273690075Sobrien	return (2 + ((REG_OR_SUBREG_REG (XEXP (x, 1))
273790075Sobrien		      || (GET_CODE (XEXP (x, 1)) == CONST_DOUBLE
273890075Sobrien			  && const_double_rtx_ok_for_fpu (XEXP (x, 1))))
273990075Sobrien		     ? 0 : 8)
274090075Sobrien		+ ((REG_OR_SUBREG_REG (XEXP (x, 0))
274190075Sobrien		    || (GET_CODE (XEXP (x, 0)) == CONST_DOUBLE
274290075Sobrien			&& const_double_rtx_ok_for_fpu (XEXP (x, 0))))
274390075Sobrien		   ? 0 : 8));
274490075Sobrien
274590075Sobrien      if (((GET_CODE (XEXP (x, 0)) == CONST_INT
274690075Sobrien	    && const_ok_for_arm (INTVAL (XEXP (x, 0)))
274790075Sobrien	    && REG_OR_SUBREG_REG (XEXP (x, 1))))
274890075Sobrien	  || (((subcode = GET_CODE (XEXP (x, 1))) == ASHIFT
274990075Sobrien	       || subcode == ASHIFTRT || subcode == LSHIFTRT
275090075Sobrien	       || subcode == ROTATE || subcode == ROTATERT
275190075Sobrien	       || (subcode == MULT
275290075Sobrien		   && GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT
275390075Sobrien		   && ((INTVAL (XEXP (XEXP (x, 1), 1)) &
275490075Sobrien			(INTVAL (XEXP (XEXP (x, 1), 1)) - 1)) == 0)))
275590075Sobrien	      && REG_OR_SUBREG_REG (XEXP (XEXP (x, 1), 0))
275690075Sobrien	      && (REG_OR_SUBREG_REG (XEXP (XEXP (x, 1), 1))
275790075Sobrien		  || GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT)
275890075Sobrien	      && REG_OR_SUBREG_REG (XEXP (x, 0))))
275990075Sobrien	return 1;
276090075Sobrien      /* Fall through */
276190075Sobrien
276290075Sobrien    case PLUS:
276390075Sobrien      if (GET_MODE_CLASS (mode) == MODE_FLOAT)
276490075Sobrien	return (2 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 8)
276590075Sobrien		+ ((REG_OR_SUBREG_REG (XEXP (x, 1))
276690075Sobrien		    || (GET_CODE (XEXP (x, 1)) == CONST_DOUBLE
276790075Sobrien			&& const_double_rtx_ok_for_fpu (XEXP (x, 1))))
276890075Sobrien		   ? 0 : 8));
276990075Sobrien
277090075Sobrien      /* Fall through */
277190075Sobrien    case AND: case XOR: case IOR:
277290075Sobrien      extra_cost = 0;
277390075Sobrien
277490075Sobrien      /* Normally the frame registers will be spilt into reg+const during
277590075Sobrien	 reload, so it is a bad idea to combine them with other instructions,
277690075Sobrien	 since then they might not be moved outside of loops.  As a compromise
277790075Sobrien	 we allow integration with ops that have a constant as their second
277890075Sobrien	 operand.  */
277990075Sobrien      if ((REG_OR_SUBREG_REG (XEXP (x, 0))
278090075Sobrien	   && ARM_FRAME_RTX (REG_OR_SUBREG_RTX (XEXP (x, 0)))
278190075Sobrien	   && GET_CODE (XEXP (x, 1)) != CONST_INT)
278290075Sobrien	  || (REG_OR_SUBREG_REG (XEXP (x, 0))
278390075Sobrien	      && ARM_FRAME_RTX (REG_OR_SUBREG_RTX (XEXP (x, 0)))))
278490075Sobrien	extra_cost = 4;
278590075Sobrien
278690075Sobrien      if (mode == DImode)
278790075Sobrien	return (4 + extra_cost + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 8)
278890075Sobrien		+ ((REG_OR_SUBREG_REG (XEXP (x, 1))
278990075Sobrien		    || (GET_CODE (XEXP (x, 1)) == CONST_INT
279090075Sobrien			&& const_ok_for_op (INTVAL (XEXP (x, 1)), code)))
279190075Sobrien		   ? 0 : 8));
279290075Sobrien
279390075Sobrien      if (REG_OR_SUBREG_REG (XEXP (x, 0)))
279490075Sobrien	return (1 + (GET_CODE (XEXP (x, 1)) == CONST_INT ? 0 : extra_cost)
279590075Sobrien		+ ((REG_OR_SUBREG_REG (XEXP (x, 1))
279690075Sobrien		    || (GET_CODE (XEXP (x, 1)) == CONST_INT
279790075Sobrien			&& const_ok_for_op (INTVAL (XEXP (x, 1)), code)))
279890075Sobrien		   ? 0 : 4));
279990075Sobrien
280090075Sobrien      else if (REG_OR_SUBREG_REG (XEXP (x, 1)))
280190075Sobrien	return (1 + extra_cost
280290075Sobrien		+ ((((subcode = GET_CODE (XEXP (x, 0))) == ASHIFT
280390075Sobrien		     || subcode == LSHIFTRT || subcode == ASHIFTRT
280490075Sobrien		     || subcode == ROTATE || subcode == ROTATERT
280590075Sobrien		     || (subcode == MULT
280690075Sobrien			 && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
280790075Sobrien			 && ((INTVAL (XEXP (XEXP (x, 0), 1)) &
280890075Sobrien			      (INTVAL (XEXP (XEXP (x, 0), 1)) - 1)) == 0)))
280990075Sobrien		    && (REG_OR_SUBREG_REG (XEXP (XEXP (x, 0), 0)))
281090075Sobrien		    && ((REG_OR_SUBREG_REG (XEXP (XEXP (x, 0), 1)))
281190075Sobrien			|| GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT))
281290075Sobrien		   ? 0 : 4));
281390075Sobrien
281490075Sobrien      return 8;
281590075Sobrien
281690075Sobrien    case MULT:
281790075Sobrien      /* There is no point basing this on the tuning, since it is always the
281890075Sobrien	 fast variant if it exists at all.  */
281990075Sobrien      if (arm_fast_multiply && mode == DImode
282090075Sobrien	  && (GET_CODE (XEXP (x, 0)) == GET_CODE (XEXP (x, 1)))
282190075Sobrien	  && (GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
282290075Sobrien	      || GET_CODE (XEXP (x, 0)) == SIGN_EXTEND))
282390075Sobrien	return 8;
282490075Sobrien
282590075Sobrien      if (GET_MODE_CLASS (mode) == MODE_FLOAT
282690075Sobrien	  || mode == DImode)
282790075Sobrien	return 30;
282890075Sobrien
282990075Sobrien      if (GET_CODE (XEXP (x, 1)) == CONST_INT)
283090075Sobrien	{
283190075Sobrien	  unsigned HOST_WIDE_INT i = (INTVAL (XEXP (x, 1))
283290075Sobrien				      & (unsigned HOST_WIDE_INT) 0xffffffff);
283390075Sobrien	  int add_cost = const_ok_for_arm (i) ? 4 : 8;
283490075Sobrien	  int j;
283590075Sobrien
283690075Sobrien	  /* Tune as appropriate.  */
283790075Sobrien	  int booth_unit_size = ((tune_flags & FL_FAST_MULT) ? 8 : 2);
283890075Sobrien
283990075Sobrien	  for (j = 0; i && j < 32; j += booth_unit_size)
284090075Sobrien	    {
284190075Sobrien	      i >>= booth_unit_size;
284290075Sobrien	      add_cost += 2;
284390075Sobrien	    }
284490075Sobrien
284590075Sobrien	  return add_cost;
284690075Sobrien	}
284790075Sobrien
284890075Sobrien      return (((tune_flags & FL_FAST_MULT) ? 8 : 30)
284990075Sobrien	      + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4)
285090075Sobrien	      + (REG_OR_SUBREG_REG (XEXP (x, 1)) ? 0 : 4));
285190075Sobrien
285290075Sobrien    case TRUNCATE:
285390075Sobrien      if (arm_fast_multiply && mode == SImode
285490075Sobrien	  && GET_CODE (XEXP (x, 0)) == LSHIFTRT
285590075Sobrien	  && GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT
285690075Sobrien	  && (GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0))
285790075Sobrien	      == GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 1)))
285890075Sobrien	  && (GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == ZERO_EXTEND
285990075Sobrien	      || GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == SIGN_EXTEND))
286090075Sobrien	return 8;
286190075Sobrien      return 99;
286290075Sobrien
286390075Sobrien    case NEG:
286490075Sobrien      if (GET_MODE_CLASS (mode) == MODE_FLOAT)
286590075Sobrien	return 4 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 6);
286690075Sobrien      /* Fall through */
286790075Sobrien    case NOT:
286890075Sobrien      if (mode == DImode)
286990075Sobrien	return 4 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4);
287090075Sobrien
287190075Sobrien      return 1 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4);
287290075Sobrien
287390075Sobrien    case IF_THEN_ELSE:
287490075Sobrien      if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC)
287590075Sobrien	return 14;
287690075Sobrien      return 2;
287790075Sobrien
287890075Sobrien    case COMPARE:
287990075Sobrien      return 1;
288090075Sobrien
288190075Sobrien    case ABS:
288290075Sobrien      return 4 + (mode == DImode ? 4 : 0);
288390075Sobrien
288490075Sobrien    case SIGN_EXTEND:
288590075Sobrien      if (GET_MODE (XEXP (x, 0)) == QImode)
288690075Sobrien	return (4 + (mode == DImode ? 4 : 0)
288790075Sobrien		+ (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
288890075Sobrien      /* Fall through */
288990075Sobrien    case ZERO_EXTEND:
289090075Sobrien      switch (GET_MODE (XEXP (x, 0)))
289190075Sobrien	{
289290075Sobrien	case QImode:
289390075Sobrien	  return (1 + (mode == DImode ? 4 : 0)
289490075Sobrien		  + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
289590075Sobrien
289690075Sobrien	case HImode:
289790075Sobrien	  return (4 + (mode == DImode ? 4 : 0)
289890075Sobrien		  + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
289990075Sobrien
290090075Sobrien	case SImode:
290190075Sobrien	  return (1 + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
290290075Sobrien
290390075Sobrien	default:
290490075Sobrien	  break;
290590075Sobrien	}
290690075Sobrien      abort ();
290790075Sobrien
290890075Sobrien    case CONST_INT:
290990075Sobrien      if (const_ok_for_arm (INTVAL (x)))
291090075Sobrien	return outer == SET ? 2 : -1;
291190075Sobrien      else if (outer == AND
291290075Sobrien	       && const_ok_for_arm (~INTVAL (x)))
291390075Sobrien	return -1;
291490075Sobrien      else if ((outer == COMPARE
291590075Sobrien		|| outer == PLUS || outer == MINUS)
291690075Sobrien	       && const_ok_for_arm (-INTVAL (x)))
291790075Sobrien	return -1;
291890075Sobrien      else
291990075Sobrien	return 5;
292090075Sobrien
292190075Sobrien    case CONST:
292290075Sobrien    case LABEL_REF:
292390075Sobrien    case SYMBOL_REF:
292490075Sobrien      return 6;
292590075Sobrien
292690075Sobrien    case CONST_DOUBLE:
292790075Sobrien      if (const_double_rtx_ok_for_fpu (x))
292890075Sobrien	return outer == SET ? 2 : -1;
292990075Sobrien      else if ((outer == COMPARE || outer == PLUS)
293090075Sobrien	       && neg_const_double_rtx_ok_for_fpu (x))
293190075Sobrien	return -1;
293290075Sobrien      return 7;
293390075Sobrien
293490075Sobrien    default:
293590075Sobrien      return 99;
293690075Sobrien    }
293790075Sobrien}
293890075Sobrien
293990075Sobrienstatic int
294090075Sobrienarm_adjust_cost (insn, link, dep, cost)
294190075Sobrien     rtx insn;
294290075Sobrien     rtx link;
294390075Sobrien     rtx dep;
294490075Sobrien     int cost;
294590075Sobrien{
294690075Sobrien  rtx i_pat, d_pat;
294790075Sobrien
294890075Sobrien  /* Some true dependencies can have a higher cost depending
294990075Sobrien     on precisely how certain input operands are used.  */
295090075Sobrien  if (arm_is_xscale
295190075Sobrien      && REG_NOTE_KIND (link) == 0
295290075Sobrien      && recog_memoized (insn) < 0
295390075Sobrien      && recog_memoized (dep) < 0)
295490075Sobrien    {
295590075Sobrien      int shift_opnum = get_attr_shift (insn);
295690075Sobrien      enum attr_type attr_type = get_attr_type (dep);
295790075Sobrien
295890075Sobrien      /* If nonzero, SHIFT_OPNUM contains the operand number of a shifted
295990075Sobrien	 operand for INSN.  If we have a shifted input operand and the
296090075Sobrien	 instruction we depend on is another ALU instruction, then we may
296190075Sobrien	 have to account for an additional stall.  */
296290075Sobrien      if (shift_opnum != 0 && attr_type == TYPE_NORMAL)
296390075Sobrien	{
296490075Sobrien	  rtx shifted_operand;
296590075Sobrien	  int opno;
296690075Sobrien
296790075Sobrien	  /* Get the shifted operand.  */
296890075Sobrien	  extract_insn (insn);
296990075Sobrien	  shifted_operand = recog_data.operand[shift_opnum];
297090075Sobrien
297190075Sobrien	  /* Iterate over all the operands in DEP.  If we write an operand
297290075Sobrien	     that overlaps with SHIFTED_OPERAND, then we have increase the
297390075Sobrien	     cost of this dependency.  */
297490075Sobrien	  extract_insn (dep);
297590075Sobrien	  preprocess_constraints ();
297690075Sobrien	  for (opno = 0; opno < recog_data.n_operands; opno++)
297790075Sobrien	    {
297890075Sobrien	      /* We can ignore strict inputs.  */
297990075Sobrien	      if (recog_data.operand_type[opno] == OP_IN)
298090075Sobrien		continue;
298190075Sobrien
298290075Sobrien	      if (reg_overlap_mentioned_p (recog_data.operand[opno],
298390075Sobrien					   shifted_operand))
298490075Sobrien		return 2;
298590075Sobrien	    }
298690075Sobrien	}
298790075Sobrien    }
298890075Sobrien
298990075Sobrien  /* XXX This is not strictly true for the FPA.  */
299090075Sobrien  if (REG_NOTE_KIND (link) == REG_DEP_ANTI
299190075Sobrien      || REG_NOTE_KIND (link) == REG_DEP_OUTPUT)
299290075Sobrien    return 0;
299390075Sobrien
299490075Sobrien  /* Call insns don't incur a stall, even if they follow a load.  */
299590075Sobrien  if (REG_NOTE_KIND (link) == 0
299690075Sobrien      && GET_CODE (insn) == CALL_INSN)
299790075Sobrien    return 1;
299890075Sobrien
299990075Sobrien  if ((i_pat = single_set (insn)) != NULL
300090075Sobrien      && GET_CODE (SET_SRC (i_pat)) == MEM
300190075Sobrien      && (d_pat = single_set (dep)) != NULL
300290075Sobrien      && GET_CODE (SET_DEST (d_pat)) == MEM)
300390075Sobrien    {
3004117395Skan      rtx src_mem = XEXP (SET_SRC (i_pat), 0);
300590075Sobrien      /* This is a load after a store, there is no conflict if the load reads
300690075Sobrien	 from a cached area.  Assume that loads from the stack, and from the
300790075Sobrien	 constant pool are cached, and that others will miss.  This is a
300890075Sobrien	 hack.  */
300990075Sobrien
3010117395Skan      if ((GET_CODE (src_mem) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (src_mem))
3011117395Skan	  || reg_mentioned_p (stack_pointer_rtx, src_mem)
3012117395Skan	  || reg_mentioned_p (frame_pointer_rtx, src_mem)
3013117395Skan	  || reg_mentioned_p (hard_frame_pointer_rtx, src_mem))
301490075Sobrien	return 1;
301590075Sobrien    }
301690075Sobrien
301790075Sobrien  return cost;
301890075Sobrien}
301990075Sobrien
302090075Sobrien/* This code has been fixed for cross compilation.  */
302190075Sobrien
302290075Sobrienstatic int fpa_consts_inited = 0;
302390075Sobrien
302490075Sobrienstatic const char * const strings_fpa[8] =
302590075Sobrien{
302690075Sobrien  "0",   "1",   "2",   "3",
302790075Sobrien  "4",   "5",   "0.5", "10"
302890075Sobrien};
302990075Sobrien
303090075Sobrienstatic REAL_VALUE_TYPE values_fpa[8];
303190075Sobrien
303290075Sobrienstatic void
303390075Sobrieninit_fpa_table ()
303490075Sobrien{
303590075Sobrien  int i;
303690075Sobrien  REAL_VALUE_TYPE r;
303790075Sobrien
303890075Sobrien  for (i = 0; i < 8; i++)
303990075Sobrien    {
304090075Sobrien      r = REAL_VALUE_ATOF (strings_fpa[i], DFmode);
304190075Sobrien      values_fpa[i] = r;
304290075Sobrien    }
304390075Sobrien
304490075Sobrien  fpa_consts_inited = 1;
304590075Sobrien}
304690075Sobrien
304790075Sobrien/* Return TRUE if rtx X is a valid immediate FPU constant.  */
304890075Sobrien
304990075Sobrienint
305090075Sobrienconst_double_rtx_ok_for_fpu (x)
305190075Sobrien     rtx x;
305290075Sobrien{
305390075Sobrien  REAL_VALUE_TYPE r;
305490075Sobrien  int i;
305590075Sobrien
305690075Sobrien  if (!fpa_consts_inited)
305790075Sobrien    init_fpa_table ();
305890075Sobrien
305990075Sobrien  REAL_VALUE_FROM_CONST_DOUBLE (r, x);
306090075Sobrien  if (REAL_VALUE_MINUS_ZERO (r))
306190075Sobrien    return 0;
306290075Sobrien
306390075Sobrien  for (i = 0; i < 8; i++)
306490075Sobrien    if (REAL_VALUES_EQUAL (r, values_fpa[i]))
306590075Sobrien      return 1;
306690075Sobrien
306790075Sobrien  return 0;
306890075Sobrien}
306990075Sobrien
307090075Sobrien/* Return TRUE if rtx X is a valid immediate FPU constant.  */
307190075Sobrien
307290075Sobrienint
307390075Sobrienneg_const_double_rtx_ok_for_fpu (x)
307490075Sobrien     rtx x;
307590075Sobrien{
307690075Sobrien  REAL_VALUE_TYPE r;
307790075Sobrien  int i;
307890075Sobrien
307990075Sobrien  if (!fpa_consts_inited)
308090075Sobrien    init_fpa_table ();
308190075Sobrien
308290075Sobrien  REAL_VALUE_FROM_CONST_DOUBLE (r, x);
308390075Sobrien  r = REAL_VALUE_NEGATE (r);
308490075Sobrien  if (REAL_VALUE_MINUS_ZERO (r))
308590075Sobrien    return 0;
308690075Sobrien
308790075Sobrien  for (i = 0; i < 8; i++)
308890075Sobrien    if (REAL_VALUES_EQUAL (r, values_fpa[i]))
308990075Sobrien      return 1;
309090075Sobrien
309190075Sobrien  return 0;
309290075Sobrien}
309390075Sobrien
309490075Sobrien/* Predicates for `match_operand' and `match_operator'.  */
309590075Sobrien
309690075Sobrien/* s_register_operand is the same as register_operand, but it doesn't accept
309790075Sobrien   (SUBREG (MEM)...).
309890075Sobrien
309990075Sobrien   This function exists because at the time it was put in it led to better
310090075Sobrien   code.  SUBREG(MEM) always needs a reload in the places where
310190075Sobrien   s_register_operand is used, and this seemed to lead to excessive
310290075Sobrien   reloading.  */
310390075Sobrien
310490075Sobrienint
310590075Sobriens_register_operand (op, mode)
310690075Sobrien     rtx op;
310790075Sobrien     enum machine_mode mode;
310890075Sobrien{
310990075Sobrien  if (GET_MODE (op) != mode && mode != VOIDmode)
311090075Sobrien    return 0;
311190075Sobrien
311290075Sobrien  if (GET_CODE (op) == SUBREG)
311390075Sobrien    op = SUBREG_REG (op);
311490075Sobrien
311590075Sobrien  /* We don't consider registers whose class is NO_REGS
311690075Sobrien     to be a register operand.  */
311790075Sobrien  /* XXX might have to check for lo regs only for thumb ??? */
311890075Sobrien  return (GET_CODE (op) == REG
311990075Sobrien	  && (REGNO (op) >= FIRST_PSEUDO_REGISTER
312090075Sobrien	      || REGNO_REG_CLASS (REGNO (op)) != NO_REGS));
312190075Sobrien}
312290075Sobrien
312390075Sobrien/* A hard register operand (even before reload.  */
312490075Sobrien
312590075Sobrienint
312690075Sobrienarm_hard_register_operand (op, mode)
312790075Sobrien     rtx op;
312890075Sobrien     enum machine_mode mode;
312990075Sobrien{
313090075Sobrien  if (GET_MODE (op) != mode && mode != VOIDmode)
313190075Sobrien    return 0;
313290075Sobrien
313390075Sobrien  return (GET_CODE (op) == REG
313490075Sobrien	  && REGNO (op) < FIRST_PSEUDO_REGISTER);
313590075Sobrien}
313690075Sobrien
313790075Sobrien/* Only accept reg, subreg(reg), const_int.  */
313890075Sobrien
313990075Sobrienint
314090075Sobrienreg_or_int_operand (op, mode)
314190075Sobrien     rtx op;
314290075Sobrien     enum machine_mode mode;
314390075Sobrien{
314490075Sobrien  if (GET_CODE (op) == CONST_INT)
314590075Sobrien    return 1;
314690075Sobrien
314790075Sobrien  if (GET_MODE (op) != mode && mode != VOIDmode)
314890075Sobrien    return 0;
314990075Sobrien
315090075Sobrien  if (GET_CODE (op) == SUBREG)
315190075Sobrien    op = SUBREG_REG (op);
315290075Sobrien
315390075Sobrien  /* We don't consider registers whose class is NO_REGS
315490075Sobrien     to be a register operand.  */
315590075Sobrien  return (GET_CODE (op) == REG
315690075Sobrien	  && (REGNO (op) >= FIRST_PSEUDO_REGISTER
315790075Sobrien	      || REGNO_REG_CLASS (REGNO (op)) != NO_REGS));
315890075Sobrien}
315990075Sobrien
316090075Sobrien/* Return 1 if OP is an item in memory, given that we are in reload.  */
316190075Sobrien
316290075Sobrienint
316390075Sobrienarm_reload_memory_operand (op, mode)
316490075Sobrien     rtx op;
316590075Sobrien     enum machine_mode mode ATTRIBUTE_UNUSED;
316690075Sobrien{
316790075Sobrien  int regno = true_regnum (op);
316890075Sobrien
316990075Sobrien  return (!CONSTANT_P (op)
317090075Sobrien	  && (regno == -1
317190075Sobrien	      || (GET_CODE (op) == REG
317290075Sobrien		  && REGNO (op) >= FIRST_PSEUDO_REGISTER)));
317390075Sobrien}
317490075Sobrien
317590075Sobrien/* Return 1 if OP is a valid memory address, but not valid for a signed byte
317690075Sobrien   memory access (architecture V4).
317790075Sobrien   MODE is QImode if called when computing constraints, or VOIDmode when
317890075Sobrien   emitting patterns.  In this latter case we cannot use memory_operand()
317990075Sobrien   because it will fail on badly formed MEMs, which is precisly what we are
318090075Sobrien   trying to catch.  */
318190075Sobrien
318290075Sobrienint
318390075Sobrienbad_signed_byte_operand (op, mode)
318490075Sobrien     rtx op;
318590075Sobrien     enum machine_mode mode ATTRIBUTE_UNUSED;
318690075Sobrien{
318790075Sobrien#if 0
318890075Sobrien  if ((mode == QImode && !memory_operand (op, mode)) || GET_CODE (op) != MEM)
318990075Sobrien    return 0;
319090075Sobrien#endif
319190075Sobrien  if (GET_CODE (op) != MEM)
319290075Sobrien    return 0;
319390075Sobrien
319490075Sobrien  op = XEXP (op, 0);
319590075Sobrien
319690075Sobrien  /* A sum of anything more complex than reg + reg or reg + const is bad.  */
319790075Sobrien  if ((GET_CODE (op) == PLUS || GET_CODE (op) == MINUS)
319890075Sobrien      && (!s_register_operand (XEXP (op, 0), VOIDmode)
319990075Sobrien	  || (!s_register_operand (XEXP (op, 1), VOIDmode)
320090075Sobrien	      && GET_CODE (XEXP (op, 1)) != CONST_INT)))
320190075Sobrien    return 1;
320290075Sobrien
320390075Sobrien  /* Big constants are also bad.  */
320490075Sobrien  if (GET_CODE (op) == PLUS && GET_CODE (XEXP (op, 1)) == CONST_INT
320590075Sobrien      && (INTVAL (XEXP (op, 1)) > 0xff
320690075Sobrien	  || -INTVAL (XEXP (op, 1)) > 0xff))
320790075Sobrien    return 1;
320890075Sobrien
320990075Sobrien  /* Everything else is good, or can will automatically be made so.  */
321090075Sobrien  return 0;
321190075Sobrien}
321290075Sobrien
321390075Sobrien/* Return TRUE for valid operands for the rhs of an ARM instruction.  */
321490075Sobrien
321590075Sobrienint
321690075Sobrienarm_rhs_operand (op, mode)
321790075Sobrien     rtx op;
321890075Sobrien     enum machine_mode mode;
321990075Sobrien{
322090075Sobrien  return (s_register_operand (op, mode)
322190075Sobrien	  || (GET_CODE (op) == CONST_INT && const_ok_for_arm (INTVAL (op))));
322290075Sobrien}
322390075Sobrien
322490075Sobrien/* Return TRUE for valid operands for the
322590075Sobrien   rhs of an ARM instruction, or a load.  */
322690075Sobrien
322790075Sobrienint
322890075Sobrienarm_rhsm_operand (op, mode)
322990075Sobrien     rtx op;
323090075Sobrien     enum machine_mode mode;
323190075Sobrien{
323290075Sobrien  return (s_register_operand (op, mode)
323390075Sobrien	  || (GET_CODE (op) == CONST_INT && const_ok_for_arm (INTVAL (op)))
323490075Sobrien	  || memory_operand (op, mode));
323590075Sobrien}
323690075Sobrien
323790075Sobrien/* Return TRUE for valid operands for the rhs of an ARM instruction, or if a
323890075Sobrien   constant that is valid when negated.  */
323990075Sobrien
324090075Sobrienint
324190075Sobrienarm_add_operand (op, mode)
324290075Sobrien     rtx op;
324390075Sobrien     enum machine_mode mode;
324490075Sobrien{
324590075Sobrien  if (TARGET_THUMB)
324690075Sobrien    return thumb_cmp_operand (op, mode);
324790075Sobrien
324890075Sobrien  return (s_register_operand (op, mode)
324990075Sobrien	  || (GET_CODE (op) == CONST_INT
325090075Sobrien	      && (const_ok_for_arm (INTVAL (op))
325190075Sobrien		  || const_ok_for_arm (-INTVAL (op)))));
325290075Sobrien}
325390075Sobrien
325490075Sobrienint
325590075Sobrienarm_not_operand (op, mode)
325690075Sobrien     rtx op;
325790075Sobrien     enum machine_mode mode;
325890075Sobrien{
325990075Sobrien  return (s_register_operand (op, mode)
326090075Sobrien	  || (GET_CODE (op) == CONST_INT
326190075Sobrien	      && (const_ok_for_arm (INTVAL (op))
326290075Sobrien		  || const_ok_for_arm (~INTVAL (op)))));
326390075Sobrien}
326490075Sobrien
326590075Sobrien/* Return TRUE if the operand is a memory reference which contains an
326690075Sobrien   offsettable address.  */
326790075Sobrien
326890075Sobrienint
326990075Sobrienoffsettable_memory_operand (op, mode)
327090075Sobrien     rtx op;
327190075Sobrien     enum machine_mode mode;
327290075Sobrien{
327390075Sobrien  if (mode == VOIDmode)
327490075Sobrien    mode = GET_MODE (op);
327590075Sobrien
327690075Sobrien  return (mode == GET_MODE (op)
327790075Sobrien	  && GET_CODE (op) == MEM
327890075Sobrien	  && offsettable_address_p (reload_completed | reload_in_progress,
327990075Sobrien				    mode, XEXP (op, 0)));
328090075Sobrien}
328190075Sobrien
328290075Sobrien/* Return TRUE if the operand is a memory reference which is, or can be
328390075Sobrien   made word aligned by adjusting the offset.  */
328490075Sobrien
328590075Sobrienint
328690075Sobrienalignable_memory_operand (op, mode)
328790075Sobrien     rtx op;
328890075Sobrien     enum machine_mode mode;
328990075Sobrien{
329090075Sobrien  rtx reg;
329190075Sobrien
329290075Sobrien  if (mode == VOIDmode)
329390075Sobrien    mode = GET_MODE (op);
329490075Sobrien
329590075Sobrien  if (mode != GET_MODE (op) || GET_CODE (op) != MEM)
329690075Sobrien    return 0;
329790075Sobrien
329890075Sobrien  op = XEXP (op, 0);
329990075Sobrien
330090075Sobrien  return ((GET_CODE (reg = op) == REG
330190075Sobrien	   || (GET_CODE (op) == SUBREG
330290075Sobrien	       && GET_CODE (reg = SUBREG_REG (op)) == REG)
330390075Sobrien	   || (GET_CODE (op) == PLUS
330490075Sobrien	       && GET_CODE (XEXP (op, 1)) == CONST_INT
330590075Sobrien	       && (GET_CODE (reg = XEXP (op, 0)) == REG
330690075Sobrien		   || (GET_CODE (XEXP (op, 0)) == SUBREG
330790075Sobrien		       && GET_CODE (reg = SUBREG_REG (XEXP (op, 0))) == REG))))
330890075Sobrien	  && REGNO_POINTER_ALIGN (REGNO (reg)) >= 32);
330990075Sobrien}
331090075Sobrien
331190075Sobrien/* Similar to s_register_operand, but does not allow hard integer
331290075Sobrien   registers.  */
331390075Sobrien
331490075Sobrienint
331590075Sobrienf_register_operand (op, mode)
331690075Sobrien     rtx op;
331790075Sobrien     enum machine_mode mode;
331890075Sobrien{
331990075Sobrien  if (GET_MODE (op) != mode && mode != VOIDmode)
332090075Sobrien    return 0;
332190075Sobrien
332290075Sobrien  if (GET_CODE (op) == SUBREG)
332390075Sobrien    op = SUBREG_REG (op);
332490075Sobrien
332590075Sobrien  /* We don't consider registers whose class is NO_REGS
332690075Sobrien     to be a register operand.  */
332790075Sobrien  return (GET_CODE (op) == REG
332890075Sobrien	  && (REGNO (op) >= FIRST_PSEUDO_REGISTER
332990075Sobrien	      || REGNO_REG_CLASS (REGNO (op)) == FPU_REGS));
333090075Sobrien}
333190075Sobrien
333290075Sobrien/* Return TRUE for valid operands for the rhs of an FPU instruction.  */
333390075Sobrien
333490075Sobrienint
333590075Sobrienfpu_rhs_operand (op, mode)
333690075Sobrien     rtx op;
333790075Sobrien     enum machine_mode mode;
333890075Sobrien{
333990075Sobrien  if (s_register_operand (op, mode))
334090075Sobrien    return TRUE;
334190075Sobrien
334290075Sobrien  if (GET_MODE (op) != mode && mode != VOIDmode)
334390075Sobrien    return FALSE;
334490075Sobrien
334590075Sobrien  if (GET_CODE (op) == CONST_DOUBLE)
334690075Sobrien    return const_double_rtx_ok_for_fpu (op);
334790075Sobrien
334890075Sobrien  return FALSE;
334990075Sobrien}
335090075Sobrien
335190075Sobrienint
335290075Sobrienfpu_add_operand (op, mode)
335390075Sobrien     rtx op;
335490075Sobrien     enum machine_mode mode;
335590075Sobrien{
335690075Sobrien  if (s_register_operand (op, mode))
335790075Sobrien    return TRUE;
335890075Sobrien
335990075Sobrien  if (GET_MODE (op) != mode && mode != VOIDmode)
336090075Sobrien    return FALSE;
336190075Sobrien
336290075Sobrien  if (GET_CODE (op) == CONST_DOUBLE)
336390075Sobrien    return (const_double_rtx_ok_for_fpu (op)
336490075Sobrien	    || neg_const_double_rtx_ok_for_fpu (op));
336590075Sobrien
336690075Sobrien  return FALSE;
336790075Sobrien}
336890075Sobrien
336990075Sobrien/* Return nonzero if OP is a constant power of two.  */
337090075Sobrien
337190075Sobrienint
337290075Sobrienpower_of_two_operand (op, mode)
337390075Sobrien     rtx op;
337490075Sobrien     enum machine_mode mode ATTRIBUTE_UNUSED;
337590075Sobrien{
337690075Sobrien  if (GET_CODE (op) == CONST_INT)
337790075Sobrien    {
337890075Sobrien      HOST_WIDE_INT value = INTVAL (op);
337990075Sobrien
338090075Sobrien      return value != 0  &&  (value & (value - 1)) == 0;
338190075Sobrien    }
338290075Sobrien
338390075Sobrien  return FALSE;
338490075Sobrien}
338590075Sobrien
338690075Sobrien/* Return TRUE for a valid operand of a DImode operation.
338790075Sobrien   Either: REG, SUBREG, CONST_DOUBLE or MEM(DImode_address).
338890075Sobrien   Note that this disallows MEM(REG+REG), but allows
338990075Sobrien   MEM(PRE/POST_INC/DEC(REG)).  */
339090075Sobrien
339190075Sobrienint
339290075Sobriendi_operand (op, mode)
339390075Sobrien     rtx op;
339490075Sobrien     enum machine_mode mode;
339590075Sobrien{
339690075Sobrien  if (s_register_operand (op, mode))
339790075Sobrien    return TRUE;
339890075Sobrien
339990075Sobrien  if (mode != VOIDmode && GET_MODE (op) != VOIDmode && GET_MODE (op) != DImode)
340090075Sobrien    return FALSE;
340190075Sobrien
340290075Sobrien  if (GET_CODE (op) == SUBREG)
340390075Sobrien    op = SUBREG_REG (op);
340490075Sobrien
340590075Sobrien  switch (GET_CODE (op))
340690075Sobrien    {
340790075Sobrien    case CONST_DOUBLE:
340890075Sobrien    case CONST_INT:
340990075Sobrien      return TRUE;
341090075Sobrien
341190075Sobrien    case MEM:
341290075Sobrien      return memory_address_p (DImode, XEXP (op, 0));
341390075Sobrien
341490075Sobrien    default:
341590075Sobrien      return FALSE;
341690075Sobrien    }
341790075Sobrien}
341890075Sobrien
341990075Sobrien/* Like di_operand, but don't accept constants.  */
342090075Sobrien
342190075Sobrienint
342290075Sobriennonimmediate_di_operand (op, mode)
342390075Sobrien     rtx op;
342490075Sobrien     enum machine_mode mode;
342590075Sobrien{
342690075Sobrien  if (s_register_operand (op, mode))
342790075Sobrien    return TRUE;
342890075Sobrien
342990075Sobrien  if (mode != VOIDmode && GET_MODE (op) != VOIDmode && GET_MODE (op) != DImode)
343090075Sobrien    return FALSE;
343190075Sobrien
343290075Sobrien  if (GET_CODE (op) == SUBREG)
343390075Sobrien    op = SUBREG_REG (op);
343490075Sobrien
343590075Sobrien  if (GET_CODE (op) == MEM)
343690075Sobrien    return memory_address_p (DImode, XEXP (op, 0));
343790075Sobrien
343890075Sobrien  return FALSE;
343990075Sobrien}
344090075Sobrien
344190075Sobrien/* Return TRUE for a valid operand of a DFmode operation when -msoft-float.
344290075Sobrien   Either: REG, SUBREG, CONST_DOUBLE or MEM(DImode_address).
344390075Sobrien   Note that this disallows MEM(REG+REG), but allows
344490075Sobrien   MEM(PRE/POST_INC/DEC(REG)).  */
344590075Sobrien
344690075Sobrienint
344790075Sobriensoft_df_operand (op, mode)
344890075Sobrien     rtx op;
344990075Sobrien     enum machine_mode mode;
345090075Sobrien{
345190075Sobrien  if (s_register_operand (op, mode))
345290075Sobrien    return TRUE;
345390075Sobrien
345490075Sobrien  if (mode != VOIDmode && GET_MODE (op) != mode)
345590075Sobrien    return FALSE;
345690075Sobrien
345790075Sobrien  if (GET_CODE (op) == SUBREG && CONSTANT_P (SUBREG_REG (op)))
345890075Sobrien    return FALSE;
345990075Sobrien
346090075Sobrien  if (GET_CODE (op) == SUBREG)
346190075Sobrien    op = SUBREG_REG (op);
346290075Sobrien
346390075Sobrien  switch (GET_CODE (op))
346490075Sobrien    {
346590075Sobrien    case CONST_DOUBLE:
346690075Sobrien      return TRUE;
346790075Sobrien
346890075Sobrien    case MEM:
346990075Sobrien      return memory_address_p (DFmode, XEXP (op, 0));
347090075Sobrien
347190075Sobrien    default:
347290075Sobrien      return FALSE;
347390075Sobrien    }
347490075Sobrien}
347590075Sobrien
347690075Sobrien/* Like soft_df_operand, but don't accept constants.  */
347790075Sobrien
347890075Sobrienint
347990075Sobriennonimmediate_soft_df_operand (op, mode)
348090075Sobrien     rtx op;
348190075Sobrien     enum machine_mode mode;
348290075Sobrien{
348390075Sobrien  if (s_register_operand (op, mode))
348490075Sobrien    return TRUE;
348590075Sobrien
348690075Sobrien  if (mode != VOIDmode && GET_MODE (op) != mode)
348790075Sobrien    return FALSE;
348890075Sobrien
348990075Sobrien  if (GET_CODE (op) == SUBREG)
349090075Sobrien    op = SUBREG_REG (op);
349190075Sobrien
349290075Sobrien  if (GET_CODE (op) == MEM)
349390075Sobrien    return memory_address_p (DFmode, XEXP (op, 0));
349490075Sobrien  return FALSE;
349590075Sobrien}
349690075Sobrien
349790075Sobrien/* Return TRUE for valid index operands.  */
349890075Sobrien
349990075Sobrienint
350090075Sobrienindex_operand (op, mode)
350190075Sobrien     rtx op;
350290075Sobrien     enum machine_mode mode;
350390075Sobrien{
350490075Sobrien  return (s_register_operand (op, mode)
350590075Sobrien	  || (immediate_operand (op, mode)
350690075Sobrien	      && (GET_CODE (op) != CONST_INT
350790075Sobrien		  || (INTVAL (op) < 4096 && INTVAL (op) > -4096))));
350890075Sobrien}
350990075Sobrien
351090075Sobrien/* Return TRUE for valid shifts by a constant. This also accepts any
351190075Sobrien   power of two on the (somewhat overly relaxed) assumption that the
351290075Sobrien   shift operator in this case was a mult.  */
351390075Sobrien
351490075Sobrienint
351590075Sobrienconst_shift_operand (op, mode)
351690075Sobrien     rtx op;
351790075Sobrien     enum machine_mode mode;
351890075Sobrien{
351990075Sobrien  return (power_of_two_operand (op, mode)
352090075Sobrien	  || (immediate_operand (op, mode)
352190075Sobrien	      && (GET_CODE (op) != CONST_INT
352290075Sobrien		  || (INTVAL (op) < 32 && INTVAL (op) > 0))));
352390075Sobrien}
352490075Sobrien
352590075Sobrien/* Return TRUE for arithmetic operators which can be combined with a multiply
352690075Sobrien   (shift).  */
352790075Sobrien
352890075Sobrienint
352990075Sobrienshiftable_operator (x, mode)
353090075Sobrien     rtx x;
353190075Sobrien     enum machine_mode mode;
353290075Sobrien{
353390075Sobrien  enum rtx_code code;
353490075Sobrien
353590075Sobrien  if (GET_MODE (x) != mode)
353690075Sobrien    return FALSE;
353790075Sobrien
353890075Sobrien  code = GET_CODE (x);
353990075Sobrien
354090075Sobrien  return (code == PLUS || code == MINUS
354190075Sobrien	  || code == IOR || code == XOR || code == AND);
354290075Sobrien}
354390075Sobrien
354490075Sobrien/* Return TRUE for binary logical operators.  */
354590075Sobrien
354690075Sobrienint
354790075Sobrienlogical_binary_operator (x, mode)
354890075Sobrien     rtx x;
354990075Sobrien     enum machine_mode mode;
355090075Sobrien{
355190075Sobrien  enum rtx_code code;
355290075Sobrien
355390075Sobrien  if (GET_MODE (x) != mode)
355490075Sobrien    return FALSE;
355590075Sobrien
355690075Sobrien  code = GET_CODE (x);
355790075Sobrien
355890075Sobrien  return (code == IOR || code == XOR || code == AND);
355990075Sobrien}
356090075Sobrien
356190075Sobrien/* Return TRUE for shift operators.  */
356290075Sobrien
356390075Sobrienint
356490075Sobrienshift_operator (x, mode)
356590075Sobrien     rtx x;
356690075Sobrien     enum machine_mode mode;
356790075Sobrien{
356890075Sobrien  enum rtx_code code;
356990075Sobrien
357090075Sobrien  if (GET_MODE (x) != mode)
357190075Sobrien    return FALSE;
357290075Sobrien
357390075Sobrien  code = GET_CODE (x);
357490075Sobrien
357590075Sobrien  if (code == MULT)
357690075Sobrien    return power_of_two_operand (XEXP (x, 1), mode);
357790075Sobrien
357890075Sobrien  return (code == ASHIFT || code == ASHIFTRT || code == LSHIFTRT
357990075Sobrien	  || code == ROTATERT);
358090075Sobrien}
358190075Sobrien
358290075Sobrien/* Return TRUE if x is EQ or NE.  */
358390075Sobrien
358490075Sobrienint
358590075Sobrienequality_operator (x, mode)
358690075Sobrien     rtx x;
358790075Sobrien     enum machine_mode mode ATTRIBUTE_UNUSED;
358890075Sobrien{
358990075Sobrien  return GET_CODE (x) == EQ || GET_CODE (x) == NE;
359090075Sobrien}
359190075Sobrien
359290075Sobrien/* Return TRUE if x is a comparison operator other than LTGT or UNEQ.  */
359390075Sobrien
359490075Sobrienint
359590075Sobrienarm_comparison_operator (x, mode)
359690075Sobrien     rtx x;
359790075Sobrien     enum machine_mode mode;
359890075Sobrien{
359990075Sobrien  return (comparison_operator (x, mode)
360090075Sobrien	  && GET_CODE (x) != LTGT
360190075Sobrien	  && GET_CODE (x) != UNEQ);
360290075Sobrien}
360390075Sobrien
360490075Sobrien/* Return TRUE for SMIN SMAX UMIN UMAX operators.  */
360590075Sobrien
360690075Sobrienint
360790075Sobrienminmax_operator (x, mode)
360890075Sobrien     rtx x;
360990075Sobrien     enum machine_mode mode;
361090075Sobrien{
361190075Sobrien  enum rtx_code code = GET_CODE (x);
361290075Sobrien
361390075Sobrien  if (GET_MODE (x) != mode)
361490075Sobrien    return FALSE;
361590075Sobrien
361690075Sobrien  return code == SMIN || code == SMAX || code == UMIN || code == UMAX;
361790075Sobrien}
361890075Sobrien
361990075Sobrien/* Return TRUE if this is the condition code register, if we aren't given
362090075Sobrien   a mode, accept any class CCmode register.  */
362190075Sobrien
362290075Sobrienint
362390075Sobriencc_register (x, mode)
362490075Sobrien     rtx x;
362590075Sobrien     enum machine_mode mode;
362690075Sobrien{
362790075Sobrien  if (mode == VOIDmode)
362890075Sobrien    {
362990075Sobrien      mode = GET_MODE (x);
363090075Sobrien
363190075Sobrien      if (GET_MODE_CLASS (mode) != MODE_CC)
363290075Sobrien	return FALSE;
363390075Sobrien    }
363490075Sobrien
363590075Sobrien  if (   GET_MODE (x) == mode
363690075Sobrien      && GET_CODE (x) == REG
363790075Sobrien      && REGNO    (x) == CC_REGNUM)
363890075Sobrien    return TRUE;
363990075Sobrien
364090075Sobrien  return FALSE;
364190075Sobrien}
364290075Sobrien
364390075Sobrien/* Return TRUE if this is the condition code register, if we aren't given
364490075Sobrien   a mode, accept any class CCmode register which indicates a dominance
364590075Sobrien   expression.  */
364690075Sobrien
364790075Sobrienint
364890075Sobriendominant_cc_register (x, mode)
364990075Sobrien     rtx x;
365090075Sobrien     enum machine_mode mode;
365190075Sobrien{
365290075Sobrien  if (mode == VOIDmode)
365390075Sobrien    {
365490075Sobrien      mode = GET_MODE (x);
365590075Sobrien
365690075Sobrien      if (GET_MODE_CLASS (mode) != MODE_CC)
365790075Sobrien	return FALSE;
365890075Sobrien    }
365990075Sobrien
366090075Sobrien  if (   mode != CC_DNEmode && mode != CC_DEQmode
366190075Sobrien      && mode != CC_DLEmode && mode != CC_DLTmode
366290075Sobrien      && mode != CC_DGEmode && mode != CC_DGTmode
366390075Sobrien      && mode != CC_DLEUmode && mode != CC_DLTUmode
366490075Sobrien      && mode != CC_DGEUmode && mode != CC_DGTUmode)
366590075Sobrien    return FALSE;
366690075Sobrien
366790075Sobrien  return cc_register (x, mode);
366890075Sobrien}
366990075Sobrien
367090075Sobrien/* Return TRUE if X references a SYMBOL_REF.  */
367190075Sobrien
367290075Sobrienint
367390075Sobriensymbol_mentioned_p (x)
367490075Sobrien     rtx x;
367590075Sobrien{
367690075Sobrien  const char * fmt;
367790075Sobrien  int i;
367890075Sobrien
367990075Sobrien  if (GET_CODE (x) == SYMBOL_REF)
368090075Sobrien    return 1;
368190075Sobrien
368290075Sobrien  fmt = GET_RTX_FORMAT (GET_CODE (x));
368390075Sobrien
368490075Sobrien  for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
368590075Sobrien    {
368690075Sobrien      if (fmt[i] == 'E')
368790075Sobrien	{
368890075Sobrien	  int j;
368990075Sobrien
369090075Sobrien	  for (j = XVECLEN (x, i) - 1; j >= 0; j--)
369190075Sobrien	    if (symbol_mentioned_p (XVECEXP (x, i, j)))
369290075Sobrien	      return 1;
369390075Sobrien	}
369490075Sobrien      else if (fmt[i] == 'e' && symbol_mentioned_p (XEXP (x, i)))
369590075Sobrien	return 1;
369690075Sobrien    }
369790075Sobrien
369890075Sobrien  return 0;
369990075Sobrien}
370090075Sobrien
370190075Sobrien/* Return TRUE if X references a LABEL_REF.  */
370290075Sobrien
370390075Sobrienint
370490075Sobrienlabel_mentioned_p (x)
370590075Sobrien     rtx x;
370690075Sobrien{
370790075Sobrien  const char * fmt;
370890075Sobrien  int i;
370990075Sobrien
371090075Sobrien  if (GET_CODE (x) == LABEL_REF)
371190075Sobrien    return 1;
371290075Sobrien
371390075Sobrien  fmt = GET_RTX_FORMAT (GET_CODE (x));
371490075Sobrien  for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
371590075Sobrien    {
371690075Sobrien      if (fmt[i] == 'E')
371790075Sobrien	{
371890075Sobrien	  int j;
371990075Sobrien
372090075Sobrien	  for (j = XVECLEN (x, i) - 1; j >= 0; j--)
372190075Sobrien	    if (label_mentioned_p (XVECEXP (x, i, j)))
372290075Sobrien	      return 1;
372390075Sobrien	}
372490075Sobrien      else if (fmt[i] == 'e' && label_mentioned_p (XEXP (x, i)))
372590075Sobrien	return 1;
372690075Sobrien    }
372790075Sobrien
372890075Sobrien  return 0;
372990075Sobrien}
373090075Sobrien
373190075Sobrienenum rtx_code
373290075Sobrienminmax_code (x)
373390075Sobrien     rtx x;
373490075Sobrien{
373590075Sobrien  enum rtx_code code = GET_CODE (x);
373690075Sobrien
373790075Sobrien  if (code == SMAX)
373890075Sobrien    return GE;
373990075Sobrien  else if (code == SMIN)
374090075Sobrien    return LE;
374190075Sobrien  else if (code == UMIN)
374290075Sobrien    return LEU;
374390075Sobrien  else if (code == UMAX)
374490075Sobrien    return GEU;
374590075Sobrien
374690075Sobrien  abort ();
374790075Sobrien}
374890075Sobrien
374990075Sobrien/* Return 1 if memory locations are adjacent.  */
375090075Sobrien
375190075Sobrienint
375290075Sobrienadjacent_mem_locations (a, b)
375390075Sobrien     rtx a, b;
375490075Sobrien{
375590075Sobrien  if ((GET_CODE (XEXP (a, 0)) == REG
375690075Sobrien       || (GET_CODE (XEXP (a, 0)) == PLUS
375790075Sobrien	   && GET_CODE (XEXP (XEXP (a, 0), 1)) == CONST_INT))
375890075Sobrien      && (GET_CODE (XEXP (b, 0)) == REG
375990075Sobrien	  || (GET_CODE (XEXP (b, 0)) == PLUS
376090075Sobrien	      && GET_CODE (XEXP (XEXP (b, 0), 1)) == CONST_INT)))
376190075Sobrien    {
376290075Sobrien      int val0 = 0, val1 = 0;
376390075Sobrien      int reg0, reg1;
376490075Sobrien
376590075Sobrien      if (GET_CODE (XEXP (a, 0)) == PLUS)
376690075Sobrien        {
376790075Sobrien	  reg0 = REGNO  (XEXP (XEXP (a, 0), 0));
376890075Sobrien	  val0 = INTVAL (XEXP (XEXP (a, 0), 1));
376990075Sobrien        }
377090075Sobrien      else
377190075Sobrien	reg0 = REGNO (XEXP (a, 0));
377290075Sobrien
377390075Sobrien      if (GET_CODE (XEXP (b, 0)) == PLUS)
377490075Sobrien        {
377590075Sobrien	  reg1 = REGNO  (XEXP (XEXP (b, 0), 0));
377690075Sobrien	  val1 = INTVAL (XEXP (XEXP (b, 0), 1));
377790075Sobrien        }
377890075Sobrien      else
377990075Sobrien	reg1 = REGNO (XEXP (b, 0));
378090075Sobrien
378190075Sobrien      return (reg0 == reg1) && ((val1 - val0) == 4 || (val0 - val1) == 4);
378290075Sobrien    }
378390075Sobrien  return 0;
378490075Sobrien}
378590075Sobrien
378690075Sobrien/* Return 1 if OP is a load multiple operation.  It is known to be
378790075Sobrien   parallel and the first section will be tested.  */
378890075Sobrien
378990075Sobrienint
379090075Sobrienload_multiple_operation (op, mode)
379190075Sobrien     rtx op;
379290075Sobrien     enum machine_mode mode ATTRIBUTE_UNUSED;
379390075Sobrien{
379490075Sobrien  HOST_WIDE_INT count = XVECLEN (op, 0);
379590075Sobrien  int dest_regno;
379690075Sobrien  rtx src_addr;
379790075Sobrien  HOST_WIDE_INT i = 1, base = 0;
379890075Sobrien  rtx elt;
379990075Sobrien
380090075Sobrien  if (count <= 1
380190075Sobrien      || GET_CODE (XVECEXP (op, 0, 0)) != SET)
380290075Sobrien    return 0;
380390075Sobrien
380490075Sobrien  /* Check to see if this might be a write-back.  */
380590075Sobrien  if (GET_CODE (SET_SRC (elt = XVECEXP (op, 0, 0))) == PLUS)
380690075Sobrien    {
380790075Sobrien      i++;
380890075Sobrien      base = 1;
380990075Sobrien
381090075Sobrien      /* Now check it more carefully.  */
381190075Sobrien      if (GET_CODE (SET_DEST (elt)) != REG
381290075Sobrien          || GET_CODE (XEXP (SET_SRC (elt), 0)) != REG
381390075Sobrien          || REGNO (XEXP (SET_SRC (elt), 0)) != REGNO (SET_DEST (elt))
381490075Sobrien          || GET_CODE (XEXP (SET_SRC (elt), 1)) != CONST_INT
381590075Sobrien          || INTVAL (XEXP (SET_SRC (elt), 1)) != (count - 1) * 4)
381690075Sobrien        return 0;
381790075Sobrien    }
381890075Sobrien
381990075Sobrien  /* Perform a quick check so we don't blow up below.  */
382090075Sobrien  if (count <= i
382190075Sobrien      || GET_CODE (XVECEXP (op, 0, i - 1)) != SET
382290075Sobrien      || GET_CODE (SET_DEST (XVECEXP (op, 0, i - 1))) != REG
382390075Sobrien      || GET_CODE (SET_SRC (XVECEXP (op, 0, i - 1))) != MEM)
382490075Sobrien    return 0;
382590075Sobrien
382690075Sobrien  dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, i - 1)));
382790075Sobrien  src_addr = XEXP (SET_SRC (XVECEXP (op, 0, i - 1)), 0);
382890075Sobrien
382990075Sobrien  for (; i < count; i++)
383090075Sobrien    {
383190075Sobrien      elt = XVECEXP (op, 0, i);
383290075Sobrien
383390075Sobrien      if (GET_CODE (elt) != SET
383490075Sobrien          || GET_CODE (SET_DEST (elt)) != REG
383590075Sobrien          || GET_MODE (SET_DEST (elt)) != SImode
383690075Sobrien          || REGNO (SET_DEST (elt)) != (unsigned int)(dest_regno + i - base)
383790075Sobrien          || GET_CODE (SET_SRC (elt)) != MEM
383890075Sobrien          || GET_MODE (SET_SRC (elt)) != SImode
383990075Sobrien          || GET_CODE (XEXP (SET_SRC (elt), 0)) != PLUS
384090075Sobrien          || !rtx_equal_p (XEXP (XEXP (SET_SRC (elt), 0), 0), src_addr)
384190075Sobrien          || GET_CODE (XEXP (XEXP (SET_SRC (elt), 0), 1)) != CONST_INT
384290075Sobrien          || INTVAL (XEXP (XEXP (SET_SRC (elt), 0), 1)) != (i - base) * 4)
384390075Sobrien        return 0;
384490075Sobrien    }
384590075Sobrien
384690075Sobrien  return 1;
384790075Sobrien}
384890075Sobrien
384990075Sobrien/* Return 1 if OP is a store multiple operation.  It is known to be
385090075Sobrien   parallel and the first section will be tested.  */
385190075Sobrien
385290075Sobrienint
385390075Sobrienstore_multiple_operation (op, mode)
385490075Sobrien     rtx op;
385590075Sobrien     enum machine_mode mode ATTRIBUTE_UNUSED;
385690075Sobrien{
385790075Sobrien  HOST_WIDE_INT count = XVECLEN (op, 0);
385890075Sobrien  int src_regno;
385990075Sobrien  rtx dest_addr;
386090075Sobrien  HOST_WIDE_INT i = 1, base = 0;
386190075Sobrien  rtx elt;
386290075Sobrien
386390075Sobrien  if (count <= 1
386490075Sobrien      || GET_CODE (XVECEXP (op, 0, 0)) != SET)
386590075Sobrien    return 0;
386690075Sobrien
386790075Sobrien  /* Check to see if this might be a write-back.  */
386890075Sobrien  if (GET_CODE (SET_SRC (elt = XVECEXP (op, 0, 0))) == PLUS)
386990075Sobrien    {
387090075Sobrien      i++;
387190075Sobrien      base = 1;
387290075Sobrien
387390075Sobrien      /* Now check it more carefully.  */
387490075Sobrien      if (GET_CODE (SET_DEST (elt)) != REG
387590075Sobrien          || GET_CODE (XEXP (SET_SRC (elt), 0)) != REG
387690075Sobrien          || REGNO (XEXP (SET_SRC (elt), 0)) != REGNO (SET_DEST (elt))
387790075Sobrien          || GET_CODE (XEXP (SET_SRC (elt), 1)) != CONST_INT
387890075Sobrien          || INTVAL (XEXP (SET_SRC (elt), 1)) != (count - 1) * 4)
387990075Sobrien        return 0;
388090075Sobrien    }
388190075Sobrien
388290075Sobrien  /* Perform a quick check so we don't blow up below.  */
388390075Sobrien  if (count <= i
388490075Sobrien      || GET_CODE (XVECEXP (op, 0, i - 1)) != SET
388590075Sobrien      || GET_CODE (SET_DEST (XVECEXP (op, 0, i - 1))) != MEM
388690075Sobrien      || GET_CODE (SET_SRC (XVECEXP (op, 0, i - 1))) != REG)
388790075Sobrien    return 0;
388890075Sobrien
388990075Sobrien  src_regno = REGNO (SET_SRC (XVECEXP (op, 0, i - 1)));
389090075Sobrien  dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, i - 1)), 0);
389190075Sobrien
389290075Sobrien  for (; i < count; i++)
389390075Sobrien    {
389490075Sobrien      elt = XVECEXP (op, 0, i);
389590075Sobrien
389690075Sobrien      if (GET_CODE (elt) != SET
389790075Sobrien          || GET_CODE (SET_SRC (elt)) != REG
389890075Sobrien          || GET_MODE (SET_SRC (elt)) != SImode
389990075Sobrien          || REGNO (SET_SRC (elt)) != (unsigned int)(src_regno + i - base)
390090075Sobrien          || GET_CODE (SET_DEST (elt)) != MEM
390190075Sobrien          || GET_MODE (SET_DEST (elt)) != SImode
390290075Sobrien          || GET_CODE (XEXP (SET_DEST (elt), 0)) != PLUS
390390075Sobrien          || !rtx_equal_p (XEXP (XEXP (SET_DEST (elt), 0), 0), dest_addr)
390490075Sobrien          || GET_CODE (XEXP (XEXP (SET_DEST (elt), 0), 1)) != CONST_INT
390590075Sobrien          || INTVAL (XEXP (XEXP (SET_DEST (elt), 0), 1)) != (i - base) * 4)
390690075Sobrien        return 0;
390790075Sobrien    }
390890075Sobrien
390990075Sobrien  return 1;
391090075Sobrien}
391190075Sobrien
391290075Sobrienint
391390075Sobrienload_multiple_sequence (operands, nops, regs, base, load_offset)
391490075Sobrien     rtx * operands;
391590075Sobrien     int nops;
391690075Sobrien     int * regs;
391790075Sobrien     int * base;
391890075Sobrien     HOST_WIDE_INT * load_offset;
391990075Sobrien{
392090075Sobrien  int unsorted_regs[4];
392190075Sobrien  HOST_WIDE_INT unsorted_offsets[4];
392290075Sobrien  int order[4];
392390075Sobrien  int base_reg = -1;
392490075Sobrien  int i;
392590075Sobrien
392690075Sobrien  /* Can only handle 2, 3, or 4 insns at present,
392790075Sobrien     though could be easily extended if required.  */
392890075Sobrien  if (nops < 2 || nops > 4)
392990075Sobrien    abort ();
393090075Sobrien
393190075Sobrien  /* Loop over the operands and check that the memory references are
393290075Sobrien     suitable (ie immediate offsets from the same base register).  At
393390075Sobrien     the same time, extract the target register, and the memory
393490075Sobrien     offsets.  */
393590075Sobrien  for (i = 0; i < nops; i++)
393690075Sobrien    {
393790075Sobrien      rtx reg;
393890075Sobrien      rtx offset;
393990075Sobrien
394090075Sobrien      /* Convert a subreg of a mem into the mem itself.  */
394190075Sobrien      if (GET_CODE (operands[nops + i]) == SUBREG)
394290075Sobrien	operands[nops + i] = alter_subreg (operands + (nops + i));
394390075Sobrien
394490075Sobrien      if (GET_CODE (operands[nops + i]) != MEM)
394590075Sobrien	abort ();
394690075Sobrien
394790075Sobrien      /* Don't reorder volatile memory references; it doesn't seem worth
394890075Sobrien	 looking for the case where the order is ok anyway.  */
394990075Sobrien      if (MEM_VOLATILE_P (operands[nops + i]))
395090075Sobrien	return 0;
395190075Sobrien
395290075Sobrien      offset = const0_rtx;
395390075Sobrien
395490075Sobrien      if ((GET_CODE (reg = XEXP (operands[nops + i], 0)) == REG
395590075Sobrien	   || (GET_CODE (reg) == SUBREG
395690075Sobrien	       && GET_CODE (reg = SUBREG_REG (reg)) == REG))
395790075Sobrien	  || (GET_CODE (XEXP (operands[nops + i], 0)) == PLUS
395890075Sobrien	      && ((GET_CODE (reg = XEXP (XEXP (operands[nops + i], 0), 0))
395990075Sobrien		   == REG)
396090075Sobrien		  || (GET_CODE (reg) == SUBREG
396190075Sobrien		      && GET_CODE (reg = SUBREG_REG (reg)) == REG))
396290075Sobrien	      && (GET_CODE (offset = XEXP (XEXP (operands[nops + i], 0), 1))
396390075Sobrien		  == CONST_INT)))
396490075Sobrien	{
396590075Sobrien	  if (i == 0)
396690075Sobrien	    {
396790075Sobrien	      base_reg = REGNO (reg);
396890075Sobrien	      unsorted_regs[0] = (GET_CODE (operands[i]) == REG
396990075Sobrien				  ? REGNO (operands[i])
397090075Sobrien				  : REGNO (SUBREG_REG (operands[i])));
397190075Sobrien	      order[0] = 0;
397290075Sobrien	    }
397390075Sobrien	  else
397490075Sobrien	    {
397590075Sobrien	      if (base_reg != (int) REGNO (reg))
397690075Sobrien		/* Not addressed from the same base register.  */
397790075Sobrien		return 0;
397890075Sobrien
397990075Sobrien	      unsorted_regs[i] = (GET_CODE (operands[i]) == REG
398090075Sobrien				  ? REGNO (operands[i])
398190075Sobrien				  : REGNO (SUBREG_REG (operands[i])));
398290075Sobrien	      if (unsorted_regs[i] < unsorted_regs[order[0]])
398390075Sobrien		order[0] = i;
398490075Sobrien	    }
398590075Sobrien
398690075Sobrien	  /* If it isn't an integer register, or if it overwrites the
398790075Sobrien	     base register but isn't the last insn in the list, then
398890075Sobrien	     we can't do this.  */
398990075Sobrien	  if (unsorted_regs[i] < 0 || unsorted_regs[i] > 14
399090075Sobrien	      || (i != nops - 1 && unsorted_regs[i] == base_reg))
399190075Sobrien	    return 0;
399290075Sobrien
399390075Sobrien	  unsorted_offsets[i] = INTVAL (offset);
399490075Sobrien	}
399590075Sobrien      else
399690075Sobrien	/* Not a suitable memory address.  */
399790075Sobrien	return 0;
399890075Sobrien    }
399990075Sobrien
400090075Sobrien  /* All the useful information has now been extracted from the
400190075Sobrien     operands into unsorted_regs and unsorted_offsets; additionally,
400290075Sobrien     order[0] has been set to the lowest numbered register in the
400390075Sobrien     list.  Sort the registers into order, and check that the memory
400490075Sobrien     offsets are ascending and adjacent.  */
400590075Sobrien
400690075Sobrien  for (i = 1; i < nops; i++)
400790075Sobrien    {
400890075Sobrien      int j;
400990075Sobrien
401090075Sobrien      order[i] = order[i - 1];
401190075Sobrien      for (j = 0; j < nops; j++)
401290075Sobrien	if (unsorted_regs[j] > unsorted_regs[order[i - 1]]
401390075Sobrien	    && (order[i] == order[i - 1]
401490075Sobrien		|| unsorted_regs[j] < unsorted_regs[order[i]]))
401590075Sobrien	  order[i] = j;
401690075Sobrien
401790075Sobrien      /* Have we found a suitable register? if not, one must be used more
401890075Sobrien	 than once.  */
401990075Sobrien      if (order[i] == order[i - 1])
402090075Sobrien	return 0;
402190075Sobrien
402290075Sobrien      /* Is the memory address adjacent and ascending? */
402390075Sobrien      if (unsorted_offsets[order[i]] != unsorted_offsets[order[i - 1]] + 4)
402490075Sobrien	return 0;
402590075Sobrien    }
402690075Sobrien
402790075Sobrien  if (base)
402890075Sobrien    {
402990075Sobrien      *base = base_reg;
403090075Sobrien
403190075Sobrien      for (i = 0; i < nops; i++)
403290075Sobrien	regs[i] = unsorted_regs[order[i]];
403390075Sobrien
403490075Sobrien      *load_offset = unsorted_offsets[order[0]];
403590075Sobrien    }
403690075Sobrien
403790075Sobrien  if (unsorted_offsets[order[0]] == 0)
403890075Sobrien    return 1; /* ldmia */
403990075Sobrien
404090075Sobrien  if (unsorted_offsets[order[0]] == 4)
404190075Sobrien    return 2; /* ldmib */
404290075Sobrien
404390075Sobrien  if (unsorted_offsets[order[nops - 1]] == 0)
404490075Sobrien    return 3; /* ldmda */
404590075Sobrien
404690075Sobrien  if (unsorted_offsets[order[nops - 1]] == -4)
404790075Sobrien    return 4; /* ldmdb */
404890075Sobrien
404990075Sobrien  /* For ARM8,9 & StrongARM, 2 ldr instructions are faster than an ldm
405090075Sobrien     if the offset isn't small enough.  The reason 2 ldrs are faster
405190075Sobrien     is because these ARMs are able to do more than one cache access
405290075Sobrien     in a single cycle.  The ARM9 and StrongARM have Harvard caches,
405390075Sobrien     whilst the ARM8 has a double bandwidth cache.  This means that
405490075Sobrien     these cores can do both an instruction fetch and a data fetch in
405590075Sobrien     a single cycle, so the trick of calculating the address into a
405690075Sobrien     scratch register (one of the result regs) and then doing a load
405790075Sobrien     multiple actually becomes slower (and no smaller in code size).
405890075Sobrien     That is the transformation
405990075Sobrien
406090075Sobrien 	ldr	rd1, [rbase + offset]
406190075Sobrien 	ldr	rd2, [rbase + offset + 4]
406290075Sobrien
406390075Sobrien     to
406490075Sobrien
406590075Sobrien 	add	rd1, rbase, offset
406690075Sobrien 	ldmia	rd1, {rd1, rd2}
406790075Sobrien
406890075Sobrien     produces worse code -- '3 cycles + any stalls on rd2' instead of
406990075Sobrien     '2 cycles + any stalls on rd2'.  On ARMs with only one cache
407090075Sobrien     access per cycle, the first sequence could never complete in less
407190075Sobrien     than 6 cycles, whereas the ldm sequence would only take 5 and
407290075Sobrien     would make better use of sequential accesses if not hitting the
407390075Sobrien     cache.
407490075Sobrien
407590075Sobrien     We cheat here and test 'arm_ld_sched' which we currently know to
407690075Sobrien     only be true for the ARM8, ARM9 and StrongARM.  If this ever
407790075Sobrien     changes, then the test below needs to be reworked.  */
407890075Sobrien  if (nops == 2 && arm_ld_sched)
407990075Sobrien    return 0;
408090075Sobrien
408190075Sobrien  /* Can't do it without setting up the offset, only do this if it takes
408290075Sobrien     no more than one insn.  */
408390075Sobrien  return (const_ok_for_arm (unsorted_offsets[order[0]])
408490075Sobrien	  || const_ok_for_arm (-unsorted_offsets[order[0]])) ? 5 : 0;
408590075Sobrien}
408690075Sobrien
408790075Sobrienconst char *
408890075Sobrienemit_ldm_seq (operands, nops)
408990075Sobrien     rtx * operands;
409090075Sobrien     int nops;
409190075Sobrien{
409290075Sobrien  int regs[4];
409390075Sobrien  int base_reg;
409490075Sobrien  HOST_WIDE_INT offset;
409590075Sobrien  char buf[100];
409690075Sobrien  int i;
409790075Sobrien
409890075Sobrien  switch (load_multiple_sequence (operands, nops, regs, &base_reg, &offset))
409990075Sobrien    {
410090075Sobrien    case 1:
410190075Sobrien      strcpy (buf, "ldm%?ia\t");
410290075Sobrien      break;
410390075Sobrien
410490075Sobrien    case 2:
410590075Sobrien      strcpy (buf, "ldm%?ib\t");
410690075Sobrien      break;
410790075Sobrien
410890075Sobrien    case 3:
410990075Sobrien      strcpy (buf, "ldm%?da\t");
411090075Sobrien      break;
411190075Sobrien
411290075Sobrien    case 4:
411390075Sobrien      strcpy (buf, "ldm%?db\t");
411490075Sobrien      break;
411590075Sobrien
411690075Sobrien    case 5:
411790075Sobrien      if (offset >= 0)
411890075Sobrien	sprintf (buf, "add%%?\t%s%s, %s%s, #%ld", REGISTER_PREFIX,
411990075Sobrien		 reg_names[regs[0]], REGISTER_PREFIX, reg_names[base_reg],
412090075Sobrien		 (long) offset);
412190075Sobrien      else
412290075Sobrien	sprintf (buf, "sub%%?\t%s%s, %s%s, #%ld", REGISTER_PREFIX,
412390075Sobrien		 reg_names[regs[0]], REGISTER_PREFIX, reg_names[base_reg],
412490075Sobrien		 (long) -offset);
412590075Sobrien      output_asm_insn (buf, operands);
412690075Sobrien      base_reg = regs[0];
412790075Sobrien      strcpy (buf, "ldm%?ia\t");
412890075Sobrien      break;
412990075Sobrien
413090075Sobrien    default:
413190075Sobrien      abort ();
413290075Sobrien    }
413390075Sobrien
413490075Sobrien  sprintf (buf + strlen (buf), "%s%s, {%s%s", REGISTER_PREFIX,
413590075Sobrien	   reg_names[base_reg], REGISTER_PREFIX, reg_names[regs[0]]);
413690075Sobrien
413790075Sobrien  for (i = 1; i < nops; i++)
413890075Sobrien    sprintf (buf + strlen (buf), ", %s%s", REGISTER_PREFIX,
413990075Sobrien	     reg_names[regs[i]]);
414090075Sobrien
414190075Sobrien  strcat (buf, "}\t%@ phole ldm");
414290075Sobrien
414390075Sobrien  output_asm_insn (buf, operands);
414490075Sobrien  return "";
414590075Sobrien}
414690075Sobrien
414790075Sobrienint
414890075Sobrienstore_multiple_sequence (operands, nops, regs, base, load_offset)
414990075Sobrien     rtx * operands;
415090075Sobrien     int nops;
415190075Sobrien     int * regs;
415290075Sobrien     int * base;
415390075Sobrien     HOST_WIDE_INT * load_offset;
415490075Sobrien{
415590075Sobrien  int unsorted_regs[4];
415690075Sobrien  HOST_WIDE_INT unsorted_offsets[4];
415790075Sobrien  int order[4];
415890075Sobrien  int base_reg = -1;
415990075Sobrien  int i;
416090075Sobrien
416190075Sobrien  /* Can only handle 2, 3, or 4 insns at present, though could be easily
416290075Sobrien     extended if required.  */
416390075Sobrien  if (nops < 2 || nops > 4)
416490075Sobrien    abort ();
416590075Sobrien
416690075Sobrien  /* Loop over the operands and check that the memory references are
416790075Sobrien     suitable (ie immediate offsets from the same base register).  At
416890075Sobrien     the same time, extract the target register, and the memory
416990075Sobrien     offsets.  */
417090075Sobrien  for (i = 0; i < nops; i++)
417190075Sobrien    {
417290075Sobrien      rtx reg;
417390075Sobrien      rtx offset;
417490075Sobrien
417590075Sobrien      /* Convert a subreg of a mem into the mem itself.  */
417690075Sobrien      if (GET_CODE (operands[nops + i]) == SUBREG)
417790075Sobrien	operands[nops + i] = alter_subreg (operands + (nops + i));
417890075Sobrien
417990075Sobrien      if (GET_CODE (operands[nops + i]) != MEM)
418090075Sobrien	abort ();
418190075Sobrien
418290075Sobrien      /* Don't reorder volatile memory references; it doesn't seem worth
418390075Sobrien	 looking for the case where the order is ok anyway.  */
418490075Sobrien      if (MEM_VOLATILE_P (operands[nops + i]))
418590075Sobrien	return 0;
418690075Sobrien
418790075Sobrien      offset = const0_rtx;
418890075Sobrien
418990075Sobrien      if ((GET_CODE (reg = XEXP (operands[nops + i], 0)) == REG
419090075Sobrien	   || (GET_CODE (reg) == SUBREG
419190075Sobrien	       && GET_CODE (reg = SUBREG_REG (reg)) == REG))
419290075Sobrien	  || (GET_CODE (XEXP (operands[nops + i], 0)) == PLUS
419390075Sobrien	      && ((GET_CODE (reg = XEXP (XEXP (operands[nops + i], 0), 0))
419490075Sobrien		   == REG)
419590075Sobrien		  || (GET_CODE (reg) == SUBREG
419690075Sobrien		      && GET_CODE (reg = SUBREG_REG (reg)) == REG))
419790075Sobrien	      && (GET_CODE (offset = XEXP (XEXP (operands[nops + i], 0), 1))
419890075Sobrien		  == CONST_INT)))
419990075Sobrien	{
420090075Sobrien	  if (i == 0)
420190075Sobrien	    {
420290075Sobrien	      base_reg = REGNO (reg);
420390075Sobrien	      unsorted_regs[0] = (GET_CODE (operands[i]) == REG
420490075Sobrien				  ? REGNO (operands[i])
420590075Sobrien				  : REGNO (SUBREG_REG (operands[i])));
420690075Sobrien	      order[0] = 0;
420790075Sobrien	    }
420890075Sobrien	  else
420990075Sobrien	    {
421090075Sobrien	      if (base_reg != (int) REGNO (reg))
421190075Sobrien		/* Not addressed from the same base register.  */
421290075Sobrien		return 0;
421390075Sobrien
421490075Sobrien	      unsorted_regs[i] = (GET_CODE (operands[i]) == REG
421590075Sobrien				  ? REGNO (operands[i])
421690075Sobrien				  : REGNO (SUBREG_REG (operands[i])));
421790075Sobrien	      if (unsorted_regs[i] < unsorted_regs[order[0]])
421890075Sobrien		order[0] = i;
421990075Sobrien	    }
422090075Sobrien
422190075Sobrien	  /* If it isn't an integer register, then we can't do this.  */
422290075Sobrien	  if (unsorted_regs[i] < 0 || unsorted_regs[i] > 14)
422390075Sobrien	    return 0;
422490075Sobrien
422590075Sobrien	  unsorted_offsets[i] = INTVAL (offset);
422690075Sobrien	}
422790075Sobrien      else
422890075Sobrien	/* Not a suitable memory address.  */
422990075Sobrien	return 0;
423090075Sobrien    }
423190075Sobrien
423290075Sobrien  /* All the useful information has now been extracted from the
423390075Sobrien     operands into unsorted_regs and unsorted_offsets; additionally,
423490075Sobrien     order[0] has been set to the lowest numbered register in the
423590075Sobrien     list.  Sort the registers into order, and check that the memory
423690075Sobrien     offsets are ascending and adjacent.  */
423790075Sobrien
423890075Sobrien  for (i = 1; i < nops; i++)
423990075Sobrien    {
424090075Sobrien      int j;
424190075Sobrien
424290075Sobrien      order[i] = order[i - 1];
424390075Sobrien      for (j = 0; j < nops; j++)
424490075Sobrien	if (unsorted_regs[j] > unsorted_regs[order[i - 1]]
424590075Sobrien	    && (order[i] == order[i - 1]
424690075Sobrien		|| unsorted_regs[j] < unsorted_regs[order[i]]))
424790075Sobrien	  order[i] = j;
424890075Sobrien
424990075Sobrien      /* Have we found a suitable register? if not, one must be used more
425090075Sobrien	 than once.  */
425190075Sobrien      if (order[i] == order[i - 1])
425290075Sobrien	return 0;
425390075Sobrien
425490075Sobrien      /* Is the memory address adjacent and ascending? */
425590075Sobrien      if (unsorted_offsets[order[i]] != unsorted_offsets[order[i - 1]] + 4)
425690075Sobrien	return 0;
425790075Sobrien    }
425890075Sobrien
425990075Sobrien  if (base)
426090075Sobrien    {
426190075Sobrien      *base = base_reg;
426290075Sobrien
426390075Sobrien      for (i = 0; i < nops; i++)
426490075Sobrien	regs[i] = unsorted_regs[order[i]];
426590075Sobrien
426690075Sobrien      *load_offset = unsorted_offsets[order[0]];
426790075Sobrien    }
426890075Sobrien
426990075Sobrien  if (unsorted_offsets[order[0]] == 0)
427090075Sobrien    return 1; /* stmia */
427190075Sobrien
427290075Sobrien  if (unsorted_offsets[order[0]] == 4)
427390075Sobrien    return 2; /* stmib */
427490075Sobrien
427590075Sobrien  if (unsorted_offsets[order[nops - 1]] == 0)
427690075Sobrien    return 3; /* stmda */
427790075Sobrien
427890075Sobrien  if (unsorted_offsets[order[nops - 1]] == -4)
427990075Sobrien    return 4; /* stmdb */
428090075Sobrien
428190075Sobrien  return 0;
428290075Sobrien}
428390075Sobrien
428490075Sobrienconst char *
428590075Sobrienemit_stm_seq (operands, nops)
428690075Sobrien     rtx * operands;
428790075Sobrien     int nops;
428890075Sobrien{
428990075Sobrien  int regs[4];
429090075Sobrien  int base_reg;
429190075Sobrien  HOST_WIDE_INT offset;
429290075Sobrien  char buf[100];
429390075Sobrien  int i;
429490075Sobrien
429590075Sobrien  switch (store_multiple_sequence (operands, nops, regs, &base_reg, &offset))
429690075Sobrien    {
429790075Sobrien    case 1:
429890075Sobrien      strcpy (buf, "stm%?ia\t");
429990075Sobrien      break;
430090075Sobrien
430190075Sobrien    case 2:
430290075Sobrien      strcpy (buf, "stm%?ib\t");
430390075Sobrien      break;
430490075Sobrien
430590075Sobrien    case 3:
430690075Sobrien      strcpy (buf, "stm%?da\t");
430790075Sobrien      break;
430890075Sobrien
430990075Sobrien    case 4:
431090075Sobrien      strcpy (buf, "stm%?db\t");
431190075Sobrien      break;
431290075Sobrien
431390075Sobrien    default:
431490075Sobrien      abort ();
431590075Sobrien    }
431690075Sobrien
431790075Sobrien  sprintf (buf + strlen (buf), "%s%s, {%s%s", REGISTER_PREFIX,
431890075Sobrien	   reg_names[base_reg], REGISTER_PREFIX, reg_names[regs[0]]);
431990075Sobrien
432090075Sobrien  for (i = 1; i < nops; i++)
432190075Sobrien    sprintf (buf + strlen (buf), ", %s%s", REGISTER_PREFIX,
432290075Sobrien	     reg_names[regs[i]]);
432390075Sobrien
432490075Sobrien  strcat (buf, "}\t%@ phole stm");
432590075Sobrien
432690075Sobrien  output_asm_insn (buf, operands);
432790075Sobrien  return "";
432890075Sobrien}
432990075Sobrien
433090075Sobrienint
433190075Sobrienmulti_register_push (op, mode)
433290075Sobrien     rtx op;
433390075Sobrien     enum machine_mode mode ATTRIBUTE_UNUSED;
433490075Sobrien{
433590075Sobrien  if (GET_CODE (op) != PARALLEL
433690075Sobrien      || (GET_CODE (XVECEXP (op, 0, 0)) != SET)
433790075Sobrien      || (GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != UNSPEC)
433890075Sobrien      || (XINT (SET_SRC (XVECEXP (op, 0, 0)), 1) != UNSPEC_PUSH_MULT))
433990075Sobrien    return 0;
434090075Sobrien
434190075Sobrien  return 1;
434290075Sobrien}
434390075Sobrien
434490075Sobrien/* Routines for use in generating RTL.  */
434590075Sobrien
434690075Sobrienrtx
434790075Sobrienarm_gen_load_multiple (base_regno, count, from, up, write_back, unchanging_p,
434890075Sobrien		       in_struct_p, scalar_p)
434990075Sobrien     int base_regno;
435090075Sobrien     int count;
435190075Sobrien     rtx from;
435290075Sobrien     int up;
435390075Sobrien     int write_back;
435490075Sobrien     int unchanging_p;
435590075Sobrien     int in_struct_p;
435690075Sobrien     int scalar_p;
435790075Sobrien{
435890075Sobrien  int i = 0, j;
435990075Sobrien  rtx result;
436090075Sobrien  int sign = up ? 1 : -1;
436190075Sobrien  rtx mem;
436290075Sobrien
436390075Sobrien  /* XScale has load-store double instructions, but they have stricter
436490075Sobrien     alignment requirements than load-store multiple, so we can not
436590075Sobrien     use them.
436690075Sobrien
436790075Sobrien     For XScale ldm requires 2 + NREGS cycles to complete and blocks
436890075Sobrien     the pipeline until completion.
436990075Sobrien
437090075Sobrien	NREGS		CYCLES
437190075Sobrien	  1		  3
437290075Sobrien	  2		  4
437390075Sobrien	  3		  5
437490075Sobrien	  4		  6
437590075Sobrien
437690075Sobrien     An ldr instruction takes 1-3 cycles, but does not block the
437790075Sobrien     pipeline.
437890075Sobrien
437990075Sobrien	NREGS		CYCLES
438090075Sobrien	  1		 1-3
438190075Sobrien	  2		 2-6
438290075Sobrien	  3		 3-9
438390075Sobrien	  4		 4-12
438490075Sobrien
438590075Sobrien     Best case ldr will always win.  However, the more ldr instructions
438690075Sobrien     we issue, the less likely we are to be able to schedule them well.
438790075Sobrien     Using ldr instructions also increases code size.
438890075Sobrien
438990075Sobrien     As a compromise, we use ldr for counts of 1 or 2 regs, and ldm
439090075Sobrien     for counts of 3 or 4 regs.  */
439190075Sobrien  if (arm_is_xscale && count <= 2 && ! optimize_size)
439290075Sobrien    {
439390075Sobrien      rtx seq;
439490075Sobrien
439590075Sobrien      start_sequence ();
439690075Sobrien
439790075Sobrien      for (i = 0; i < count; i++)
439890075Sobrien	{
439990075Sobrien	  mem = gen_rtx_MEM (SImode, plus_constant (from, i * 4 * sign));
440090075Sobrien	  RTX_UNCHANGING_P (mem) = unchanging_p;
440190075Sobrien	  MEM_IN_STRUCT_P (mem) = in_struct_p;
440290075Sobrien	  MEM_SCALAR_P (mem) = scalar_p;
440390075Sobrien	  emit_move_insn (gen_rtx_REG (SImode, base_regno + i), mem);
440490075Sobrien	}
440590075Sobrien
440690075Sobrien      if (write_back)
440790075Sobrien	emit_move_insn (from, plus_constant (from, count * 4 * sign));
440890075Sobrien
4409117395Skan      seq = get_insns ();
441090075Sobrien      end_sequence ();
441190075Sobrien
441290075Sobrien      return seq;
441390075Sobrien    }
441490075Sobrien
441590075Sobrien  result = gen_rtx_PARALLEL (VOIDmode,
441690075Sobrien			     rtvec_alloc (count + (write_back ? 1 : 0)));
441790075Sobrien  if (write_back)
441890075Sobrien    {
441990075Sobrien      XVECEXP (result, 0, 0)
442090075Sobrien	= gen_rtx_SET (GET_MODE (from), from,
442190075Sobrien		       plus_constant (from, count * 4 * sign));
442290075Sobrien      i = 1;
442390075Sobrien      count++;
442490075Sobrien    }
442590075Sobrien
442690075Sobrien  for (j = 0; i < count; i++, j++)
442790075Sobrien    {
442890075Sobrien      mem = gen_rtx_MEM (SImode, plus_constant (from, j * 4 * sign));
442990075Sobrien      RTX_UNCHANGING_P (mem) = unchanging_p;
443090075Sobrien      MEM_IN_STRUCT_P (mem) = in_struct_p;
443190075Sobrien      MEM_SCALAR_P (mem) = scalar_p;
443290075Sobrien      XVECEXP (result, 0, i)
443390075Sobrien	= gen_rtx_SET (VOIDmode, gen_rtx_REG (SImode, base_regno + j), mem);
443490075Sobrien    }
443590075Sobrien
443690075Sobrien  return result;
443790075Sobrien}
443890075Sobrien
443990075Sobrienrtx
444090075Sobrienarm_gen_store_multiple (base_regno, count, to, up, write_back, unchanging_p,
444190075Sobrien			in_struct_p, scalar_p)
444290075Sobrien     int base_regno;
444390075Sobrien     int count;
444490075Sobrien     rtx to;
444590075Sobrien     int up;
444690075Sobrien     int write_back;
444790075Sobrien     int unchanging_p;
444890075Sobrien     int in_struct_p;
444990075Sobrien     int scalar_p;
445090075Sobrien{
445190075Sobrien  int i = 0, j;
445290075Sobrien  rtx result;
445390075Sobrien  int sign = up ? 1 : -1;
445490075Sobrien  rtx mem;
445590075Sobrien
445690075Sobrien  /* See arm_gen_load_multiple for discussion of
445790075Sobrien     the pros/cons of ldm/stm usage for XScale.  */
445890075Sobrien  if (arm_is_xscale && count <= 2 && ! optimize_size)
445990075Sobrien    {
446090075Sobrien      rtx seq;
446190075Sobrien
446290075Sobrien      start_sequence ();
446390075Sobrien
446490075Sobrien      for (i = 0; i < count; i++)
446590075Sobrien	{
446690075Sobrien	  mem = gen_rtx_MEM (SImode, plus_constant (to, i * 4 * sign));
446790075Sobrien	  RTX_UNCHANGING_P (mem) = unchanging_p;
446890075Sobrien	  MEM_IN_STRUCT_P (mem) = in_struct_p;
446990075Sobrien	  MEM_SCALAR_P (mem) = scalar_p;
447090075Sobrien	  emit_move_insn (mem, gen_rtx_REG (SImode, base_regno + i));
447190075Sobrien	}
447290075Sobrien
447390075Sobrien      if (write_back)
447490075Sobrien	emit_move_insn (to, plus_constant (to, count * 4 * sign));
447590075Sobrien
4476117395Skan      seq = get_insns ();
447790075Sobrien      end_sequence ();
447890075Sobrien
447990075Sobrien      return seq;
448090075Sobrien    }
448190075Sobrien
448290075Sobrien  result = gen_rtx_PARALLEL (VOIDmode,
448390075Sobrien			     rtvec_alloc (count + (write_back ? 1 : 0)));
448490075Sobrien  if (write_back)
448590075Sobrien    {
448690075Sobrien      XVECEXP (result, 0, 0)
448790075Sobrien	= gen_rtx_SET (GET_MODE (to), to,
448890075Sobrien		       plus_constant (to, count * 4 * sign));
448990075Sobrien      i = 1;
449090075Sobrien      count++;
449190075Sobrien    }
449290075Sobrien
449390075Sobrien  for (j = 0; i < count; i++, j++)
449490075Sobrien    {
449590075Sobrien      mem = gen_rtx_MEM (SImode, plus_constant (to, j * 4 * sign));
449690075Sobrien      RTX_UNCHANGING_P (mem) = unchanging_p;
449790075Sobrien      MEM_IN_STRUCT_P (mem) = in_struct_p;
449890075Sobrien      MEM_SCALAR_P (mem) = scalar_p;
449990075Sobrien
450090075Sobrien      XVECEXP (result, 0, i)
450190075Sobrien	= gen_rtx_SET (VOIDmode, mem, gen_rtx_REG (SImode, base_regno + j));
450290075Sobrien    }
450390075Sobrien
450490075Sobrien  return result;
450590075Sobrien}
450690075Sobrien
450790075Sobrienint
450890075Sobrienarm_gen_movstrqi (operands)
450990075Sobrien     rtx * operands;
451090075Sobrien{
451190075Sobrien  HOST_WIDE_INT in_words_to_go, out_words_to_go, last_bytes;
451290075Sobrien  int i;
451390075Sobrien  rtx src, dst;
451490075Sobrien  rtx st_src, st_dst, fin_src, fin_dst;
451590075Sobrien  rtx part_bytes_reg = NULL;
451690075Sobrien  rtx mem;
451790075Sobrien  int dst_unchanging_p, dst_in_struct_p, src_unchanging_p, src_in_struct_p;
451890075Sobrien  int dst_scalar_p, src_scalar_p;
451990075Sobrien
452090075Sobrien  if (GET_CODE (operands[2]) != CONST_INT
452190075Sobrien      || GET_CODE (operands[3]) != CONST_INT
452290075Sobrien      || INTVAL (operands[2]) > 64
452390075Sobrien      || INTVAL (operands[3]) & 3)
452490075Sobrien    return 0;
452590075Sobrien
452690075Sobrien  st_dst = XEXP (operands[0], 0);
452790075Sobrien  st_src = XEXP (operands[1], 0);
452890075Sobrien
452990075Sobrien  dst_unchanging_p = RTX_UNCHANGING_P (operands[0]);
453090075Sobrien  dst_in_struct_p = MEM_IN_STRUCT_P (operands[0]);
453190075Sobrien  dst_scalar_p = MEM_SCALAR_P (operands[0]);
453290075Sobrien  src_unchanging_p = RTX_UNCHANGING_P (operands[1]);
453390075Sobrien  src_in_struct_p = MEM_IN_STRUCT_P (operands[1]);
453490075Sobrien  src_scalar_p = MEM_SCALAR_P (operands[1]);
453590075Sobrien
453690075Sobrien  fin_dst = dst = copy_to_mode_reg (SImode, st_dst);
453790075Sobrien  fin_src = src = copy_to_mode_reg (SImode, st_src);
453890075Sobrien
4539117395Skan  in_words_to_go = ARM_NUM_INTS (INTVAL (operands[2]));
454090075Sobrien  out_words_to_go = INTVAL (operands[2]) / 4;
454190075Sobrien  last_bytes = INTVAL (operands[2]) & 3;
454290075Sobrien
454390075Sobrien  if (out_words_to_go != in_words_to_go && ((in_words_to_go - 1) & 3) != 0)
454490075Sobrien    part_bytes_reg = gen_rtx_REG (SImode, (in_words_to_go - 1) & 3);
454590075Sobrien
454690075Sobrien  for (i = 0; in_words_to_go >= 2; i+=4)
454790075Sobrien    {
454890075Sobrien      if (in_words_to_go > 4)
454990075Sobrien	emit_insn (arm_gen_load_multiple (0, 4, src, TRUE, TRUE,
455090075Sobrien					  src_unchanging_p,
455190075Sobrien					  src_in_struct_p,
455290075Sobrien					  src_scalar_p));
455390075Sobrien      else
455490075Sobrien	emit_insn (arm_gen_load_multiple (0, in_words_to_go, src, TRUE,
455590075Sobrien					  FALSE, src_unchanging_p,
455690075Sobrien					  src_in_struct_p, src_scalar_p));
455790075Sobrien
455890075Sobrien      if (out_words_to_go)
455990075Sobrien	{
456090075Sobrien	  if (out_words_to_go > 4)
456190075Sobrien	    emit_insn (arm_gen_store_multiple (0, 4, dst, TRUE, TRUE,
456290075Sobrien					       dst_unchanging_p,
456390075Sobrien					       dst_in_struct_p,
456490075Sobrien					       dst_scalar_p));
456590075Sobrien	  else if (out_words_to_go != 1)
456690075Sobrien	    emit_insn (arm_gen_store_multiple (0, out_words_to_go,
456790075Sobrien					       dst, TRUE,
456890075Sobrien					       (last_bytes == 0
456990075Sobrien						? FALSE : TRUE),
457090075Sobrien					       dst_unchanging_p,
457190075Sobrien					       dst_in_struct_p,
457290075Sobrien					       dst_scalar_p));
457390075Sobrien	  else
457490075Sobrien	    {
457590075Sobrien	      mem = gen_rtx_MEM (SImode, dst);
457690075Sobrien	      RTX_UNCHANGING_P (mem) = dst_unchanging_p;
457790075Sobrien	      MEM_IN_STRUCT_P (mem) = dst_in_struct_p;
457890075Sobrien	      MEM_SCALAR_P (mem) = dst_scalar_p;
457990075Sobrien	      emit_move_insn (mem, gen_rtx_REG (SImode, 0));
458090075Sobrien	      if (last_bytes != 0)
458190075Sobrien		emit_insn (gen_addsi3 (dst, dst, GEN_INT (4)));
458290075Sobrien	    }
458390075Sobrien	}
458490075Sobrien
458590075Sobrien      in_words_to_go -= in_words_to_go < 4 ? in_words_to_go : 4;
458690075Sobrien      out_words_to_go -= out_words_to_go < 4 ? out_words_to_go : 4;
458790075Sobrien    }
458890075Sobrien
458990075Sobrien  /* OUT_WORDS_TO_GO will be zero here if there are byte stores to do.  */
459090075Sobrien  if (out_words_to_go)
459190075Sobrien    {
459290075Sobrien      rtx sreg;
459390075Sobrien
459490075Sobrien      mem = gen_rtx_MEM (SImode, src);
459590075Sobrien      RTX_UNCHANGING_P (mem) = src_unchanging_p;
459690075Sobrien      MEM_IN_STRUCT_P (mem) = src_in_struct_p;
459790075Sobrien      MEM_SCALAR_P (mem) = src_scalar_p;
459890075Sobrien      emit_move_insn (sreg = gen_reg_rtx (SImode), mem);
459990075Sobrien      emit_move_insn (fin_src = gen_reg_rtx (SImode), plus_constant (src, 4));
460090075Sobrien
460190075Sobrien      mem = gen_rtx_MEM (SImode, dst);
460290075Sobrien      RTX_UNCHANGING_P (mem) = dst_unchanging_p;
460390075Sobrien      MEM_IN_STRUCT_P (mem) = dst_in_struct_p;
460490075Sobrien      MEM_SCALAR_P (mem) = dst_scalar_p;
460590075Sobrien      emit_move_insn (mem, sreg);
460690075Sobrien      emit_move_insn (fin_dst = gen_reg_rtx (SImode), plus_constant (dst, 4));
460790075Sobrien      in_words_to_go--;
460890075Sobrien
460990075Sobrien      if (in_words_to_go)	/* Sanity check */
461090075Sobrien	abort ();
461190075Sobrien    }
461290075Sobrien
461390075Sobrien  if (in_words_to_go)
461490075Sobrien    {
461590075Sobrien      if (in_words_to_go < 0)
461690075Sobrien	abort ();
461790075Sobrien
461890075Sobrien      mem = gen_rtx_MEM (SImode, src);
461990075Sobrien      RTX_UNCHANGING_P (mem) = src_unchanging_p;
462090075Sobrien      MEM_IN_STRUCT_P (mem) = src_in_struct_p;
462190075Sobrien      MEM_SCALAR_P (mem) = src_scalar_p;
462290075Sobrien      part_bytes_reg = copy_to_mode_reg (SImode, mem);
462390075Sobrien    }
462490075Sobrien
462590075Sobrien  if (last_bytes && part_bytes_reg == NULL)
462690075Sobrien    abort ();
462790075Sobrien
462890075Sobrien  if (BYTES_BIG_ENDIAN && last_bytes)
462990075Sobrien    {
463090075Sobrien      rtx tmp = gen_reg_rtx (SImode);
463190075Sobrien
463290075Sobrien      /* The bytes we want are in the top end of the word.  */
463390075Sobrien      emit_insn (gen_lshrsi3 (tmp, part_bytes_reg,
463490075Sobrien			      GEN_INT (8 * (4 - last_bytes))));
463590075Sobrien      part_bytes_reg = tmp;
463690075Sobrien
463790075Sobrien      while (last_bytes)
463890075Sobrien	{
463990075Sobrien	  mem = gen_rtx_MEM (QImode, plus_constant (dst, last_bytes - 1));
464090075Sobrien	  RTX_UNCHANGING_P (mem) = dst_unchanging_p;
464190075Sobrien	  MEM_IN_STRUCT_P (mem) = dst_in_struct_p;
464290075Sobrien	  MEM_SCALAR_P (mem) = dst_scalar_p;
4643102780Skan	  emit_move_insn (mem, gen_lowpart (QImode, part_bytes_reg));
4644102780Skan
464590075Sobrien	  if (--last_bytes)
464690075Sobrien	    {
464790075Sobrien	      tmp = gen_reg_rtx (SImode);
464890075Sobrien	      emit_insn (gen_lshrsi3 (tmp, part_bytes_reg, GEN_INT (8)));
464990075Sobrien	      part_bytes_reg = tmp;
465090075Sobrien	    }
465190075Sobrien	}
465290075Sobrien
465390075Sobrien    }
465490075Sobrien  else
465590075Sobrien    {
465690075Sobrien      if (last_bytes > 1)
465790075Sobrien	{
465890075Sobrien	  mem = gen_rtx_MEM (HImode, dst);
465990075Sobrien	  RTX_UNCHANGING_P (mem) = dst_unchanging_p;
466090075Sobrien	  MEM_IN_STRUCT_P (mem) = dst_in_struct_p;
466190075Sobrien	  MEM_SCALAR_P (mem) = dst_scalar_p;
4662102780Skan	  emit_move_insn (mem, gen_lowpart (HImode, part_bytes_reg));
466390075Sobrien	  last_bytes -= 2;
466490075Sobrien	  if (last_bytes)
466590075Sobrien	    {
466690075Sobrien	      rtx tmp = gen_reg_rtx (SImode);
466790075Sobrien
466890075Sobrien	      emit_insn (gen_addsi3 (dst, dst, GEN_INT (2)));
466990075Sobrien	      emit_insn (gen_lshrsi3 (tmp, part_bytes_reg, GEN_INT (16)));
467090075Sobrien	      part_bytes_reg = tmp;
467190075Sobrien	    }
467290075Sobrien	}
467390075Sobrien
467490075Sobrien      if (last_bytes)
467590075Sobrien	{
467690075Sobrien	  mem = gen_rtx_MEM (QImode, dst);
467790075Sobrien	  RTX_UNCHANGING_P (mem) = dst_unchanging_p;
467890075Sobrien	  MEM_IN_STRUCT_P (mem) = dst_in_struct_p;
467990075Sobrien	  MEM_SCALAR_P (mem) = dst_scalar_p;
4680102780Skan	  emit_move_insn (mem, gen_lowpart (QImode, part_bytes_reg));
468190075Sobrien	}
468290075Sobrien    }
468390075Sobrien
468490075Sobrien  return 1;
468590075Sobrien}
468690075Sobrien
468790075Sobrien/* Generate a memory reference for a half word, such that it will be loaded
468890075Sobrien   into the top 16 bits of the word.  We can assume that the address is
468990075Sobrien   known to be alignable and of the form reg, or plus (reg, const).  */
469090075Sobrien
469190075Sobrienrtx
469290075Sobrienarm_gen_rotated_half_load (memref)
469390075Sobrien     rtx memref;
469490075Sobrien{
469590075Sobrien  HOST_WIDE_INT offset = 0;
469690075Sobrien  rtx base = XEXP (memref, 0);
469790075Sobrien
469890075Sobrien  if (GET_CODE (base) == PLUS)
469990075Sobrien    {
470090075Sobrien      offset = INTVAL (XEXP (base, 1));
470190075Sobrien      base = XEXP (base, 0);
470290075Sobrien    }
470390075Sobrien
470490075Sobrien  /* If we aren't allowed to generate unaligned addresses, then fail.  */
470590075Sobrien  if (TARGET_MMU_TRAPS
470690075Sobrien      && ((BYTES_BIG_ENDIAN ? 1 : 0) ^ ((offset & 2) == 0)))
470790075Sobrien    return NULL;
470890075Sobrien
470990075Sobrien  base = gen_rtx_MEM (SImode, plus_constant (base, offset & ~2));
471090075Sobrien
471190075Sobrien  if ((BYTES_BIG_ENDIAN ? 1 : 0) ^ ((offset & 2) == 2))
471290075Sobrien    return base;
471390075Sobrien
471490075Sobrien  return gen_rtx_ROTATE (SImode, base, GEN_INT (16));
471590075Sobrien}
471690075Sobrien
471790075Sobrien/* Select a dominance comparison mode if possible.  We support three forms.
471890075Sobrien   COND_OR == 0 => (X && Y)
471990075Sobrien   COND_OR == 1 => ((! X( || Y)
472090075Sobrien   COND_OR == 2 => (X || Y)
472190075Sobrien   If we are unable to support a dominance comparsison we return CC mode.
472290075Sobrien   This will then fail to match for the RTL expressions that generate this
472390075Sobrien   call.  */
472490075Sobrien
472590075Sobrienstatic enum machine_mode
472690075Sobrienselect_dominance_cc_mode (x, y, cond_or)
472790075Sobrien     rtx x;
472890075Sobrien     rtx y;
472990075Sobrien     HOST_WIDE_INT cond_or;
473090075Sobrien{
473190075Sobrien  enum rtx_code cond1, cond2;
473290075Sobrien  int swapped = 0;
473390075Sobrien
473490075Sobrien  /* Currently we will probably get the wrong result if the individual
473590075Sobrien     comparisons are not simple.  This also ensures that it is safe to
473690075Sobrien     reverse a comparison if necessary.  */
473790075Sobrien  if ((arm_select_cc_mode (cond1 = GET_CODE (x), XEXP (x, 0), XEXP (x, 1))
473890075Sobrien       != CCmode)
473990075Sobrien      || (arm_select_cc_mode (cond2 = GET_CODE (y), XEXP (y, 0), XEXP (y, 1))
474090075Sobrien	  != CCmode))
474190075Sobrien    return CCmode;
474290075Sobrien
474390075Sobrien  /* The if_then_else variant of this tests the second condition if the
474490075Sobrien     first passes, but is true if the first fails.  Reverse the first
474590075Sobrien     condition to get a true "inclusive-or" expression.  */
474690075Sobrien  if (cond_or == 1)
474790075Sobrien    cond1 = reverse_condition (cond1);
474890075Sobrien
474990075Sobrien  /* If the comparisons are not equal, and one doesn't dominate the other,
475090075Sobrien     then we can't do this.  */
475190075Sobrien  if (cond1 != cond2
475290075Sobrien      && !comparison_dominates_p (cond1, cond2)
475390075Sobrien      && (swapped = 1, !comparison_dominates_p (cond2, cond1)))
475490075Sobrien    return CCmode;
475590075Sobrien
475690075Sobrien  if (swapped)
475790075Sobrien    {
475890075Sobrien      enum rtx_code temp = cond1;
475990075Sobrien      cond1 = cond2;
476090075Sobrien      cond2 = temp;
476190075Sobrien    }
476290075Sobrien
476390075Sobrien  switch (cond1)
476490075Sobrien    {
476590075Sobrien    case EQ:
476690075Sobrien      if (cond2 == EQ || !cond_or)
476790075Sobrien	return CC_DEQmode;
476890075Sobrien
476990075Sobrien      switch (cond2)
477090075Sobrien	{
477190075Sobrien	case LE: return CC_DLEmode;
477290075Sobrien	case LEU: return CC_DLEUmode;
477390075Sobrien	case GE: return CC_DGEmode;
477490075Sobrien	case GEU: return CC_DGEUmode;
477590075Sobrien	default: break;
477690075Sobrien	}
477790075Sobrien
477890075Sobrien      break;
477990075Sobrien
478090075Sobrien    case LT:
478190075Sobrien      if (cond2 == LT || !cond_or)
478290075Sobrien	return CC_DLTmode;
478390075Sobrien      if (cond2 == LE)
478490075Sobrien	return CC_DLEmode;
478590075Sobrien      if (cond2 == NE)
478690075Sobrien	return CC_DNEmode;
478790075Sobrien      break;
478890075Sobrien
478990075Sobrien    case GT:
479090075Sobrien      if (cond2 == GT || !cond_or)
479190075Sobrien	return CC_DGTmode;
479290075Sobrien      if (cond2 == GE)
479390075Sobrien	return CC_DGEmode;
479490075Sobrien      if (cond2 == NE)
479590075Sobrien	return CC_DNEmode;
479690075Sobrien      break;
479790075Sobrien
479890075Sobrien    case LTU:
479990075Sobrien      if (cond2 == LTU || !cond_or)
480090075Sobrien	return CC_DLTUmode;
480190075Sobrien      if (cond2 == LEU)
480290075Sobrien	return CC_DLEUmode;
480390075Sobrien      if (cond2 == NE)
480490075Sobrien	return CC_DNEmode;
480590075Sobrien      break;
480690075Sobrien
480790075Sobrien    case GTU:
480890075Sobrien      if (cond2 == GTU || !cond_or)
480990075Sobrien	return CC_DGTUmode;
481090075Sobrien      if (cond2 == GEU)
481190075Sobrien	return CC_DGEUmode;
481290075Sobrien      if (cond2 == NE)
481390075Sobrien	return CC_DNEmode;
481490075Sobrien      break;
481590075Sobrien
481690075Sobrien    /* The remaining cases only occur when both comparisons are the
481790075Sobrien       same.  */
481890075Sobrien    case NE:
481990075Sobrien      return CC_DNEmode;
482090075Sobrien
482190075Sobrien    case LE:
482290075Sobrien      return CC_DLEmode;
482390075Sobrien
482490075Sobrien    case GE:
482590075Sobrien      return CC_DGEmode;
482690075Sobrien
482790075Sobrien    case LEU:
482890075Sobrien      return CC_DLEUmode;
482990075Sobrien
483090075Sobrien    case GEU:
483190075Sobrien      return CC_DGEUmode;
483290075Sobrien
483390075Sobrien    default:
483490075Sobrien      break;
483590075Sobrien    }
483690075Sobrien
483790075Sobrien  abort ();
483890075Sobrien}
483990075Sobrien
484090075Sobrienenum machine_mode
484190075Sobrienarm_select_cc_mode (op, x, y)
484290075Sobrien     enum rtx_code op;
484390075Sobrien     rtx x;
484490075Sobrien     rtx y;
484590075Sobrien{
484690075Sobrien  /* All floating point compares return CCFP if it is an equality
484790075Sobrien     comparison, and CCFPE otherwise.  */
484890075Sobrien  if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
484990075Sobrien    {
485090075Sobrien      switch (op)
485190075Sobrien	{
485290075Sobrien	case EQ:
485390075Sobrien	case NE:
485490075Sobrien	case UNORDERED:
485590075Sobrien	case ORDERED:
485690075Sobrien	case UNLT:
485790075Sobrien	case UNLE:
485890075Sobrien	case UNGT:
485990075Sobrien	case UNGE:
486090075Sobrien	case UNEQ:
486190075Sobrien	case LTGT:
486290075Sobrien	  return CCFPmode;
486390075Sobrien
486490075Sobrien	case LT:
486590075Sobrien	case LE:
486690075Sobrien	case GT:
486790075Sobrien	case GE:
486890075Sobrien	  return CCFPEmode;
486990075Sobrien
487090075Sobrien	default:
487190075Sobrien	  abort ();
487290075Sobrien	}
487390075Sobrien    }
487490075Sobrien
487590075Sobrien  /* A compare with a shifted operand.  Because of canonicalization, the
487690075Sobrien     comparison will have to be swapped when we emit the assembler.  */
487790075Sobrien  if (GET_MODE (y) == SImode && GET_CODE (y) == REG
487890075Sobrien      && (GET_CODE (x) == ASHIFT || GET_CODE (x) == ASHIFTRT
487990075Sobrien	  || GET_CODE (x) == LSHIFTRT || GET_CODE (x) == ROTATE
488090075Sobrien	  || GET_CODE (x) == ROTATERT))
488190075Sobrien    return CC_SWPmode;
488290075Sobrien
488390075Sobrien  /* This is a special case that is used by combine to allow a
488490075Sobrien     comparison of a shifted byte load to be split into a zero-extend
488590075Sobrien     followed by a comparison of the shifted integer (only valid for
488690075Sobrien     equalities and unsigned inequalities).  */
488790075Sobrien  if (GET_MODE (x) == SImode
488890075Sobrien      && GET_CODE (x) == ASHIFT
488990075Sobrien      && GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) == 24
489090075Sobrien      && GET_CODE (XEXP (x, 0)) == SUBREG
489190075Sobrien      && GET_CODE (SUBREG_REG (XEXP (x, 0))) == MEM
489290075Sobrien      && GET_MODE (SUBREG_REG (XEXP (x, 0))) == QImode
489390075Sobrien      && (op == EQ || op == NE
489490075Sobrien	  || op == GEU || op == GTU || op == LTU || op == LEU)
489590075Sobrien      && GET_CODE (y) == CONST_INT)
489690075Sobrien    return CC_Zmode;
489790075Sobrien
489890075Sobrien  /* A construct for a conditional compare, if the false arm contains
489990075Sobrien     0, then both conditions must be true, otherwise either condition
490090075Sobrien     must be true.  Not all conditions are possible, so CCmode is
490190075Sobrien     returned if it can't be done.  */
490290075Sobrien  if (GET_CODE (x) == IF_THEN_ELSE
490390075Sobrien      && (XEXP (x, 2) == const0_rtx
490490075Sobrien	  || XEXP (x, 2) == const1_rtx)
490590075Sobrien      && GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
490690075Sobrien      && GET_RTX_CLASS (GET_CODE (XEXP (x, 1))) == '<')
490790075Sobrien    return select_dominance_cc_mode (XEXP (x, 0), XEXP (x, 1),
490890075Sobrien				     INTVAL (XEXP (x, 2)));
490990075Sobrien
491090075Sobrien  /* Alternate canonicalizations of the above.  These are somewhat cleaner.  */
491190075Sobrien  if (GET_CODE (x) == AND
491290075Sobrien      && GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
491390075Sobrien      && GET_RTX_CLASS (GET_CODE (XEXP (x, 1))) == '<')
491490075Sobrien    return select_dominance_cc_mode (XEXP (x, 0), XEXP (x, 1), 0);
491590075Sobrien
491690075Sobrien  if (GET_CODE (x) == IOR
491790075Sobrien      && GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
491890075Sobrien      && GET_RTX_CLASS (GET_CODE (XEXP (x, 1))) == '<')
491990075Sobrien    return select_dominance_cc_mode (XEXP (x, 0), XEXP (x, 1), 2);
492090075Sobrien
492190075Sobrien  /* An operation that sets the condition codes as a side-effect, the
492290075Sobrien     V flag is not set correctly, so we can only use comparisons where
492390075Sobrien     this doesn't matter.  (For LT and GE we can use "mi" and "pl"
492490075Sobrien     instead.  */
492590075Sobrien  if (GET_MODE (x) == SImode
492690075Sobrien      && y == const0_rtx
492790075Sobrien      && (op == EQ || op == NE || op == LT || op == GE)
492890075Sobrien      && (GET_CODE (x) == PLUS || GET_CODE (x) == MINUS
492990075Sobrien	  || GET_CODE (x) == AND || GET_CODE (x) == IOR
493090075Sobrien	  || GET_CODE (x) == XOR || GET_CODE (x) == MULT
493190075Sobrien	  || GET_CODE (x) == NOT || GET_CODE (x) == NEG
493290075Sobrien	  || GET_CODE (x) == LSHIFTRT
493390075Sobrien	  || GET_CODE (x) == ASHIFT || GET_CODE (x) == ASHIFTRT
493490075Sobrien	  || GET_CODE (x) == ROTATERT || GET_CODE (x) == ZERO_EXTRACT))
493590075Sobrien    return CC_NOOVmode;
493690075Sobrien
493790075Sobrien  if (GET_MODE (x) == QImode && (op == EQ || op == NE))
493890075Sobrien    return CC_Zmode;
493990075Sobrien
494090075Sobrien  if (GET_MODE (x) == SImode && (op == LTU || op == GEU)
494190075Sobrien      && GET_CODE (x) == PLUS
494290075Sobrien      && (rtx_equal_p (XEXP (x, 0), y) || rtx_equal_p (XEXP (x, 1), y)))
494390075Sobrien    return CC_Cmode;
494490075Sobrien
494590075Sobrien  return CCmode;
494690075Sobrien}
494790075Sobrien
494890075Sobrien/* X and Y are two things to compare using CODE.  Emit the compare insn and
494990075Sobrien   return the rtx for register 0 in the proper mode.  FP means this is a
495090075Sobrien   floating point compare: I don't think that it is needed on the arm.  */
495190075Sobrien
495290075Sobrienrtx
495390075Sobrienarm_gen_compare_reg (code, x, y)
495490075Sobrien     enum rtx_code code;
495590075Sobrien     rtx x, y;
495690075Sobrien{
495790075Sobrien  enum machine_mode mode = SELECT_CC_MODE (code, x, y);
495890075Sobrien  rtx cc_reg = gen_rtx_REG (mode, CC_REGNUM);
495990075Sobrien
496090075Sobrien  emit_insn (gen_rtx_SET (VOIDmode, cc_reg,
496190075Sobrien			  gen_rtx_COMPARE (mode, x, y)));
496290075Sobrien
496390075Sobrien  return cc_reg;
496490075Sobrien}
496590075Sobrien
4966117395Skan/* Generate a sequence of insns that will generate the correct return
4967117395Skan   address mask depending on the physical architecture that the program
4968117395Skan   is running on.  */
4969117395Skan
4970117395Skanrtx
4971117395Skanarm_gen_return_addr_mask ()
4972117395Skan{
4973117395Skan  rtx reg = gen_reg_rtx (Pmode);
4974117395Skan
4975117395Skan  emit_insn (gen_return_addr_mask (reg));
4976117395Skan  return reg;
4977117395Skan}
4978117395Skan
497990075Sobrienvoid
498090075Sobrienarm_reload_in_hi (operands)
498190075Sobrien     rtx * operands;
498290075Sobrien{
498390075Sobrien  rtx ref = operands[1];
498490075Sobrien  rtx base, scratch;
498590075Sobrien  HOST_WIDE_INT offset = 0;
498690075Sobrien
498790075Sobrien  if (GET_CODE (ref) == SUBREG)
498890075Sobrien    {
498990075Sobrien      offset = SUBREG_BYTE (ref);
499090075Sobrien      ref = SUBREG_REG (ref);
499190075Sobrien    }
499290075Sobrien
499390075Sobrien  if (GET_CODE (ref) == REG)
499490075Sobrien    {
499590075Sobrien      /* We have a pseudo which has been spilt onto the stack; there
499690075Sobrien	 are two cases here: the first where there is a simple
499790075Sobrien	 stack-slot replacement and a second where the stack-slot is
499890075Sobrien	 out of range, or is used as a subreg.  */
499990075Sobrien      if (reg_equiv_mem[REGNO (ref)])
500090075Sobrien	{
500190075Sobrien	  ref = reg_equiv_mem[REGNO (ref)];
500290075Sobrien	  base = find_replacement (&XEXP (ref, 0));
500390075Sobrien	}
500490075Sobrien      else
500590075Sobrien	/* The slot is out of range, or was dressed up in a SUBREG.  */
500690075Sobrien	base = reg_equiv_address[REGNO (ref)];
500790075Sobrien    }
500890075Sobrien  else
500990075Sobrien    base = find_replacement (&XEXP (ref, 0));
501090075Sobrien
501190075Sobrien  /* Handle the case where the address is too complex to be offset by 1.  */
501290075Sobrien  if (GET_CODE (base) == MINUS
501390075Sobrien      || (GET_CODE (base) == PLUS && GET_CODE (XEXP (base, 1)) != CONST_INT))
501490075Sobrien    {
501590075Sobrien      rtx base_plus = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
501690075Sobrien
501790075Sobrien      emit_insn (gen_rtx_SET (VOIDmode, base_plus, base));
501890075Sobrien      base = base_plus;
501990075Sobrien    }
502090075Sobrien  else if (GET_CODE (base) == PLUS)
502190075Sobrien    {
502290075Sobrien      /* The addend must be CONST_INT, or we would have dealt with it above.  */
502390075Sobrien      HOST_WIDE_INT hi, lo;
502490075Sobrien
502590075Sobrien      offset += INTVAL (XEXP (base, 1));
502690075Sobrien      base = XEXP (base, 0);
502790075Sobrien
502890075Sobrien      /* Rework the address into a legal sequence of insns.  */
502990075Sobrien      /* Valid range for lo is -4095 -> 4095 */
503090075Sobrien      lo = (offset >= 0
503190075Sobrien	    ? (offset & 0xfff)
503290075Sobrien	    : -((-offset) & 0xfff));
503390075Sobrien
503490075Sobrien      /* Corner case, if lo is the max offset then we would be out of range
503590075Sobrien	 once we have added the additional 1 below, so bump the msb into the
503690075Sobrien	 pre-loading insn(s).  */
503790075Sobrien      if (lo == 4095)
503890075Sobrien	lo &= 0x7ff;
503990075Sobrien
504090075Sobrien      hi = ((((offset - lo) & (HOST_WIDE_INT) 0xffffffff)
504190075Sobrien	     ^ (HOST_WIDE_INT) 0x80000000)
504290075Sobrien	    - (HOST_WIDE_INT) 0x80000000);
504390075Sobrien
504490075Sobrien      if (hi + lo != offset)
504590075Sobrien	abort ();
504690075Sobrien
504790075Sobrien      if (hi != 0)
504890075Sobrien	{
504990075Sobrien	  rtx base_plus = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
505090075Sobrien
505190075Sobrien	  /* Get the base address; addsi3 knows how to handle constants
505290075Sobrien	     that require more than one insn.  */
505390075Sobrien	  emit_insn (gen_addsi3 (base_plus, base, GEN_INT (hi)));
505490075Sobrien	  base = base_plus;
505590075Sobrien	  offset = lo;
505690075Sobrien	}
505790075Sobrien    }
505890075Sobrien
5059117395Skan  /* Operands[2] may overlap operands[0] (though it won't overlap
5060117395Skan     operands[1]), that's why we asked for a DImode reg -- so we can
5061117395Skan     use the bit that does not overlap.  */
5062117395Skan  if (REGNO (operands[2]) == REGNO (operands[0]))
5063117395Skan    scratch = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
5064117395Skan  else
5065117395Skan    scratch = gen_rtx_REG (SImode, REGNO (operands[2]));
5066117395Skan
506790075Sobrien  emit_insn (gen_zero_extendqisi2 (scratch,
506890075Sobrien				   gen_rtx_MEM (QImode,
506990075Sobrien						plus_constant (base,
507090075Sobrien							       offset))));
507190075Sobrien  emit_insn (gen_zero_extendqisi2 (gen_rtx_SUBREG (SImode, operands[0], 0),
507290075Sobrien				   gen_rtx_MEM (QImode,
507390075Sobrien						plus_constant (base,
507490075Sobrien							       offset + 1))));
507590075Sobrien  if (!BYTES_BIG_ENDIAN)
507690075Sobrien    emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_SUBREG (SImode, operands[0], 0),
507790075Sobrien			gen_rtx_IOR (SImode,
507890075Sobrien				     gen_rtx_ASHIFT
507990075Sobrien				     (SImode,
508090075Sobrien				      gen_rtx_SUBREG (SImode, operands[0], 0),
508190075Sobrien				      GEN_INT (8)),
508290075Sobrien				     scratch)));
508390075Sobrien  else
508490075Sobrien    emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_SUBREG (SImode, operands[0], 0),
508590075Sobrien			    gen_rtx_IOR (SImode,
508690075Sobrien					 gen_rtx_ASHIFT (SImode, scratch,
508790075Sobrien							 GEN_INT (8)),
508890075Sobrien					 gen_rtx_SUBREG (SImode, operands[0],
508990075Sobrien							 0))));
509090075Sobrien}
509190075Sobrien
509290075Sobrien/* Handle storing a half-word to memory during reload by synthesising as two
509390075Sobrien   byte stores.  Take care not to clobber the input values until after we
509490075Sobrien   have moved them somewhere safe.  This code assumes that if the DImode
509590075Sobrien   scratch in operands[2] overlaps either the input value or output address
509690075Sobrien   in some way, then that value must die in this insn (we absolutely need
509790075Sobrien   two scratch registers for some corner cases).  */
509890075Sobrien
509990075Sobrienvoid
510090075Sobrienarm_reload_out_hi (operands)
510190075Sobrien     rtx * operands;
510290075Sobrien{
510390075Sobrien  rtx ref = operands[0];
510490075Sobrien  rtx outval = operands[1];
510590075Sobrien  rtx base, scratch;
510690075Sobrien  HOST_WIDE_INT offset = 0;
510790075Sobrien
510890075Sobrien  if (GET_CODE (ref) == SUBREG)
510990075Sobrien    {
511090075Sobrien      offset = SUBREG_BYTE (ref);
511190075Sobrien      ref = SUBREG_REG (ref);
511290075Sobrien    }
511390075Sobrien
511490075Sobrien  if (GET_CODE (ref) == REG)
511590075Sobrien    {
511690075Sobrien      /* We have a pseudo which has been spilt onto the stack; there
511790075Sobrien	 are two cases here: the first where there is a simple
511890075Sobrien	 stack-slot replacement and a second where the stack-slot is
511990075Sobrien	 out of range, or is used as a subreg.  */
512090075Sobrien      if (reg_equiv_mem[REGNO (ref)])
512190075Sobrien	{
512290075Sobrien	  ref = reg_equiv_mem[REGNO (ref)];
512390075Sobrien	  base = find_replacement (&XEXP (ref, 0));
512490075Sobrien	}
512590075Sobrien      else
512690075Sobrien	/* The slot is out of range, or was dressed up in a SUBREG.  */
512790075Sobrien	base = reg_equiv_address[REGNO (ref)];
512890075Sobrien    }
512990075Sobrien  else
513090075Sobrien    base = find_replacement (&XEXP (ref, 0));
513190075Sobrien
513290075Sobrien  scratch = gen_rtx_REG (SImode, REGNO (operands[2]));
513390075Sobrien
513490075Sobrien  /* Handle the case where the address is too complex to be offset by 1.  */
513590075Sobrien  if (GET_CODE (base) == MINUS
513690075Sobrien      || (GET_CODE (base) == PLUS && GET_CODE (XEXP (base, 1)) != CONST_INT))
513790075Sobrien    {
513890075Sobrien      rtx base_plus = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
513990075Sobrien
514090075Sobrien      /* Be careful not to destroy OUTVAL.  */
514190075Sobrien      if (reg_overlap_mentioned_p (base_plus, outval))
514290075Sobrien	{
514390075Sobrien	  /* Updating base_plus might destroy outval, see if we can
514490075Sobrien	     swap the scratch and base_plus.  */
514590075Sobrien	  if (!reg_overlap_mentioned_p (scratch, outval))
514690075Sobrien	    {
514790075Sobrien	      rtx tmp = scratch;
514890075Sobrien	      scratch = base_plus;
514990075Sobrien	      base_plus = tmp;
515090075Sobrien	    }
515190075Sobrien	  else
515290075Sobrien	    {
515390075Sobrien	      rtx scratch_hi = gen_rtx_REG (HImode, REGNO (operands[2]));
515490075Sobrien
515590075Sobrien	      /* Be conservative and copy OUTVAL into the scratch now,
515690075Sobrien		 this should only be necessary if outval is a subreg
515790075Sobrien		 of something larger than a word.  */
515890075Sobrien	      /* XXX Might this clobber base?  I can't see how it can,
515990075Sobrien		 since scratch is known to overlap with OUTVAL, and
516090075Sobrien		 must be wider than a word.  */
516190075Sobrien	      emit_insn (gen_movhi (scratch_hi, outval));
516290075Sobrien	      outval = scratch_hi;
516390075Sobrien	    }
516490075Sobrien	}
516590075Sobrien
516690075Sobrien      emit_insn (gen_rtx_SET (VOIDmode, base_plus, base));
516790075Sobrien      base = base_plus;
516890075Sobrien    }
516990075Sobrien  else if (GET_CODE (base) == PLUS)
517090075Sobrien    {
517190075Sobrien      /* The addend must be CONST_INT, or we would have dealt with it above.  */
517290075Sobrien      HOST_WIDE_INT hi, lo;
517390075Sobrien
517490075Sobrien      offset += INTVAL (XEXP (base, 1));
517590075Sobrien      base = XEXP (base, 0);
517690075Sobrien
517790075Sobrien      /* Rework the address into a legal sequence of insns.  */
517890075Sobrien      /* Valid range for lo is -4095 -> 4095 */
517990075Sobrien      lo = (offset >= 0
518090075Sobrien	    ? (offset & 0xfff)
518190075Sobrien	    : -((-offset) & 0xfff));
518290075Sobrien
518390075Sobrien      /* Corner case, if lo is the max offset then we would be out of range
518490075Sobrien	 once we have added the additional 1 below, so bump the msb into the
518590075Sobrien	 pre-loading insn(s).  */
518690075Sobrien      if (lo == 4095)
518790075Sobrien	lo &= 0x7ff;
518890075Sobrien
518990075Sobrien      hi = ((((offset - lo) & (HOST_WIDE_INT) 0xffffffff)
519090075Sobrien	     ^ (HOST_WIDE_INT) 0x80000000)
519190075Sobrien	    - (HOST_WIDE_INT) 0x80000000);
519290075Sobrien
519390075Sobrien      if (hi + lo != offset)
519490075Sobrien	abort ();
519590075Sobrien
519690075Sobrien      if (hi != 0)
519790075Sobrien	{
519890075Sobrien	  rtx base_plus = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
519990075Sobrien
520090075Sobrien	  /* Be careful not to destroy OUTVAL.  */
520190075Sobrien	  if (reg_overlap_mentioned_p (base_plus, outval))
520290075Sobrien	    {
520390075Sobrien	      /* Updating base_plus might destroy outval, see if we
520490075Sobrien		 can swap the scratch and base_plus.  */
520590075Sobrien	      if (!reg_overlap_mentioned_p (scratch, outval))
520690075Sobrien		{
520790075Sobrien		  rtx tmp = scratch;
520890075Sobrien		  scratch = base_plus;
520990075Sobrien		  base_plus = tmp;
521090075Sobrien		}
521190075Sobrien	      else
521290075Sobrien		{
521390075Sobrien		  rtx scratch_hi = gen_rtx_REG (HImode, REGNO (operands[2]));
521490075Sobrien
521590075Sobrien		  /* Be conservative and copy outval into scratch now,
521690075Sobrien		     this should only be necessary if outval is a
521790075Sobrien		     subreg of something larger than a word.  */
521890075Sobrien		  /* XXX Might this clobber base?  I can't see how it
521990075Sobrien		     can, since scratch is known to overlap with
522090075Sobrien		     outval.  */
522190075Sobrien		  emit_insn (gen_movhi (scratch_hi, outval));
522290075Sobrien		  outval = scratch_hi;
522390075Sobrien		}
522490075Sobrien	    }
522590075Sobrien
522690075Sobrien	  /* Get the base address; addsi3 knows how to handle constants
522790075Sobrien	     that require more than one insn.  */
522890075Sobrien	  emit_insn (gen_addsi3 (base_plus, base, GEN_INT (hi)));
522990075Sobrien	  base = base_plus;
523090075Sobrien	  offset = lo;
523190075Sobrien	}
523290075Sobrien    }
523390075Sobrien
523490075Sobrien  if (BYTES_BIG_ENDIAN)
523590075Sobrien    {
523690075Sobrien      emit_insn (gen_movqi (gen_rtx_MEM (QImode,
523790075Sobrien					 plus_constant (base, offset + 1)),
5238102780Skan			    gen_lowpart (QImode, outval)));
523990075Sobrien      emit_insn (gen_lshrsi3 (scratch,
524090075Sobrien			      gen_rtx_SUBREG (SImode, outval, 0),
524190075Sobrien			      GEN_INT (8)));
524290075Sobrien      emit_insn (gen_movqi (gen_rtx_MEM (QImode, plus_constant (base, offset)),
5243102780Skan			    gen_lowpart (QImode, scratch)));
524490075Sobrien    }
524590075Sobrien  else
524690075Sobrien    {
524790075Sobrien      emit_insn (gen_movqi (gen_rtx_MEM (QImode, plus_constant (base, offset)),
5248102780Skan			    gen_lowpart (QImode, outval)));
524990075Sobrien      emit_insn (gen_lshrsi3 (scratch,
525090075Sobrien			      gen_rtx_SUBREG (SImode, outval, 0),
525190075Sobrien			      GEN_INT (8)));
525290075Sobrien      emit_insn (gen_movqi (gen_rtx_MEM (QImode,
525390075Sobrien					 plus_constant (base, offset + 1)),
5254102780Skan			    gen_lowpart (QImode, scratch)));
525590075Sobrien    }
525690075Sobrien}
525790075Sobrien
525890075Sobrien/* Print a symbolic form of X to the debug file, F.  */
525990075Sobrien
526090075Sobrienstatic void
526190075Sobrienarm_print_value (f, x)
526290075Sobrien     FILE * f;
526390075Sobrien     rtx x;
526490075Sobrien{
526590075Sobrien  switch (GET_CODE (x))
526690075Sobrien    {
526790075Sobrien    case CONST_INT:
526890075Sobrien      fprintf (f, HOST_WIDE_INT_PRINT_HEX, INTVAL (x));
526990075Sobrien      return;
527090075Sobrien
527190075Sobrien    case CONST_DOUBLE:
527290075Sobrien      fprintf (f, "<0x%lx,0x%lx>", (long)XWINT (x, 2), (long)XWINT (x, 3));
527390075Sobrien      return;
527490075Sobrien
527590075Sobrien    case CONST_STRING:
527690075Sobrien      fprintf (f, "\"%s\"", XSTR (x, 0));
527790075Sobrien      return;
527890075Sobrien
527990075Sobrien    case SYMBOL_REF:
528090075Sobrien      fprintf (f, "`%s'", XSTR (x, 0));
528190075Sobrien      return;
528290075Sobrien
528390075Sobrien    case LABEL_REF:
528490075Sobrien      fprintf (f, "L%d", INSN_UID (XEXP (x, 0)));
528590075Sobrien      return;
528690075Sobrien
528790075Sobrien    case CONST:
528890075Sobrien      arm_print_value (f, XEXP (x, 0));
528990075Sobrien      return;
529090075Sobrien
529190075Sobrien    case PLUS:
529290075Sobrien      arm_print_value (f, XEXP (x, 0));
529390075Sobrien      fprintf (f, "+");
529490075Sobrien      arm_print_value (f, XEXP (x, 1));
529590075Sobrien      return;
529690075Sobrien
529790075Sobrien    case PC:
529890075Sobrien      fprintf (f, "pc");
529990075Sobrien      return;
530090075Sobrien
530190075Sobrien    default:
530290075Sobrien      fprintf (f, "????");
530390075Sobrien      return;
530490075Sobrien    }
530590075Sobrien}
530690075Sobrien
530790075Sobrien/* Routines for manipulation of the constant pool.  */
530890075Sobrien
530990075Sobrien/* Arm instructions cannot load a large constant directly into a
531090075Sobrien   register; they have to come from a pc relative load.  The constant
531190075Sobrien   must therefore be placed in the addressable range of the pc
531290075Sobrien   relative load.  Depending on the precise pc relative load
531390075Sobrien   instruction the range is somewhere between 256 bytes and 4k.  This
531490075Sobrien   means that we often have to dump a constant inside a function, and
531590075Sobrien   generate code to branch around it.
531690075Sobrien
531790075Sobrien   It is important to minimize this, since the branches will slow
531890075Sobrien   things down and make the code larger.
531990075Sobrien
532090075Sobrien   Normally we can hide the table after an existing unconditional
532190075Sobrien   branch so that there is no interruption of the flow, but in the
532290075Sobrien   worst case the code looks like this:
532390075Sobrien
532490075Sobrien	ldr	rn, L1
532590075Sobrien	...
532690075Sobrien	b	L2
532790075Sobrien	align
532890075Sobrien	L1:	.long value
532990075Sobrien	L2:
533090075Sobrien	...
533190075Sobrien
533290075Sobrien	ldr	rn, L3
533390075Sobrien	...
533490075Sobrien	b	L4
533590075Sobrien	align
533690075Sobrien	L3:	.long value
533790075Sobrien	L4:
533890075Sobrien	...
533990075Sobrien
534090075Sobrien   We fix this by performing a scan after scheduling, which notices
534190075Sobrien   which instructions need to have their operands fetched from the
534290075Sobrien   constant table and builds the table.
534390075Sobrien
534490075Sobrien   The algorithm starts by building a table of all the constants that
534590075Sobrien   need fixing up and all the natural barriers in the function (places
534690075Sobrien   where a constant table can be dropped without breaking the flow).
534790075Sobrien   For each fixup we note how far the pc-relative replacement will be
534890075Sobrien   able to reach and the offset of the instruction into the function.
534990075Sobrien
535090075Sobrien   Having built the table we then group the fixes together to form
535190075Sobrien   tables that are as large as possible (subject to addressing
535290075Sobrien   constraints) and emit each table of constants after the last
535390075Sobrien   barrier that is within range of all the instructions in the group.
535490075Sobrien   If a group does not contain a barrier, then we forcibly create one
535590075Sobrien   by inserting a jump instruction into the flow.  Once the table has
535690075Sobrien   been inserted, the insns are then modified to reference the
535790075Sobrien   relevant entry in the pool.
535890075Sobrien
535990075Sobrien   Possible enhancements to the algorithm (not implemented) are:
536090075Sobrien
536190075Sobrien   1) For some processors and object formats, there may be benefit in
536290075Sobrien   aligning the pools to the start of cache lines; this alignment
536390075Sobrien   would need to be taken into account when calculating addressability
536490075Sobrien   of a pool.  */
536590075Sobrien
536690075Sobrien/* These typedefs are located at the start of this file, so that
536790075Sobrien   they can be used in the prototypes there.  This comment is to
536890075Sobrien   remind readers of that fact so that the following structures
536990075Sobrien   can be understood more easily.
537090075Sobrien
537190075Sobrien     typedef struct minipool_node    Mnode;
537290075Sobrien     typedef struct minipool_fixup   Mfix;  */
537390075Sobrien
537490075Sobrienstruct minipool_node
537590075Sobrien{
537690075Sobrien  /* Doubly linked chain of entries.  */
537790075Sobrien  Mnode * next;
537890075Sobrien  Mnode * prev;
537990075Sobrien  /* The maximum offset into the code that this entry can be placed.  While
538090075Sobrien     pushing fixes for forward references, all entries are sorted in order
538190075Sobrien     of increasing max_address.  */
538290075Sobrien  HOST_WIDE_INT max_address;
538390075Sobrien  /* Similarly for an entry inserted for a backwards ref.  */
538490075Sobrien  HOST_WIDE_INT min_address;
538590075Sobrien  /* The number of fixes referencing this entry.  This can become zero
538690075Sobrien     if we "unpush" an entry.  In this case we ignore the entry when we
538790075Sobrien     come to emit the code.  */
538890075Sobrien  int refcount;
538990075Sobrien  /* The offset from the start of the minipool.  */
539090075Sobrien  HOST_WIDE_INT offset;
539190075Sobrien  /* The value in table.  */
539290075Sobrien  rtx value;
539390075Sobrien  /* The mode of value.  */
539490075Sobrien  enum machine_mode mode;
539590075Sobrien  int fix_size;
539690075Sobrien};
539790075Sobrien
539890075Sobrienstruct minipool_fixup
539990075Sobrien{
540090075Sobrien  Mfix *            next;
540190075Sobrien  rtx               insn;
540290075Sobrien  HOST_WIDE_INT     address;
540390075Sobrien  rtx *             loc;
540490075Sobrien  enum machine_mode mode;
540590075Sobrien  int               fix_size;
540690075Sobrien  rtx               value;
540790075Sobrien  Mnode *           minipool;
540890075Sobrien  HOST_WIDE_INT     forwards;
540990075Sobrien  HOST_WIDE_INT     backwards;
541090075Sobrien};
541190075Sobrien
541290075Sobrien/* Fixes less than a word need padding out to a word boundary.  */
541390075Sobrien#define MINIPOOL_FIX_SIZE(mode) \
541490075Sobrien  (GET_MODE_SIZE ((mode)) >= 4 ? GET_MODE_SIZE ((mode)) : 4)
541590075Sobrien
541690075Sobrienstatic Mnode *	minipool_vector_head;
541790075Sobrienstatic Mnode *	minipool_vector_tail;
541890075Sobrienstatic rtx	minipool_vector_label;
541990075Sobrien
542090075Sobrien/* The linked list of all minipool fixes required for this function.  */
542190075SobrienMfix * 		minipool_fix_head;
542290075SobrienMfix * 		minipool_fix_tail;
542390075Sobrien/* The fix entry for the current minipool, once it has been placed.  */
542490075SobrienMfix *		minipool_barrier;
542590075Sobrien
542690075Sobrien/* Determines if INSN is the start of a jump table.  Returns the end
542790075Sobrien   of the TABLE or NULL_RTX.  */
542890075Sobrien
542990075Sobrienstatic rtx
543090075Sobrienis_jump_table (insn)
543190075Sobrien     rtx insn;
543290075Sobrien{
543390075Sobrien  rtx table;
543490075Sobrien
543590075Sobrien  if (GET_CODE (insn) == JUMP_INSN
543690075Sobrien      && JUMP_LABEL (insn) != NULL
543790075Sobrien      && ((table = next_real_insn (JUMP_LABEL (insn)))
543890075Sobrien	  == next_real_insn (insn))
543990075Sobrien      && table != NULL
544090075Sobrien      && GET_CODE (table) == JUMP_INSN
544190075Sobrien      && (GET_CODE (PATTERN (table)) == ADDR_VEC
544290075Sobrien	  || GET_CODE (PATTERN (table)) == ADDR_DIFF_VEC))
544390075Sobrien    return table;
544490075Sobrien
544590075Sobrien  return NULL_RTX;
544690075Sobrien}
544790075Sobrien
544896263Sobrien#ifndef JUMP_TABLES_IN_TEXT_SECTION
544996263Sobrien#define JUMP_TABLES_IN_TEXT_SECTION 0
545096263Sobrien#endif
545196263Sobrien
545290075Sobrienstatic HOST_WIDE_INT
545390075Sobrienget_jump_table_size (insn)
545490075Sobrien     rtx insn;
545590075Sobrien{
545696263Sobrien  /* ADDR_VECs only take room if read-only data does into the text
545796263Sobrien     section.  */
545896263Sobrien  if (JUMP_TABLES_IN_TEXT_SECTION
5459117395Skan#if !defined(READONLY_DATA_SECTION) && !defined(READONLY_DATA_SECTION_ASM_OP)
546096263Sobrien      || 1
546196263Sobrien#endif
546296263Sobrien      )
546396263Sobrien    {
546496263Sobrien      rtx body = PATTERN (insn);
546596263Sobrien      int elt = GET_CODE (body) == ADDR_DIFF_VEC ? 1 : 0;
546690075Sobrien
546796263Sobrien      return GET_MODE_SIZE (GET_MODE (body)) * XVECLEN (body, elt);
546896263Sobrien    }
546996263Sobrien
547096263Sobrien  return 0;
547190075Sobrien}
547290075Sobrien
547390075Sobrien/* Move a minipool fix MP from its current location to before MAX_MP.
547490075Sobrien   If MAX_MP is NULL, then MP doesn't need moving, but the addressing
547590075Sobrien   contrains may need updating.  */
547690075Sobrien
547790075Sobrienstatic Mnode *
547890075Sobrienmove_minipool_fix_forward_ref (mp, max_mp, max_address)
547990075Sobrien     Mnode *       mp;
548090075Sobrien     Mnode *       max_mp;
548190075Sobrien     HOST_WIDE_INT max_address;
548290075Sobrien{
548390075Sobrien  /* This should never be true and the code below assumes these are
548490075Sobrien     different.  */
548590075Sobrien  if (mp == max_mp)
548690075Sobrien    abort ();
548790075Sobrien
548890075Sobrien  if (max_mp == NULL)
548990075Sobrien    {
549090075Sobrien      if (max_address < mp->max_address)
549190075Sobrien	mp->max_address = max_address;
549290075Sobrien    }
549390075Sobrien  else
549490075Sobrien    {
549590075Sobrien      if (max_address > max_mp->max_address - mp->fix_size)
549690075Sobrien	mp->max_address = max_mp->max_address - mp->fix_size;
549790075Sobrien      else
549890075Sobrien	mp->max_address = max_address;
549990075Sobrien
550090075Sobrien      /* Unlink MP from its current position.  Since max_mp is non-null,
550190075Sobrien       mp->prev must be non-null.  */
550290075Sobrien      mp->prev->next = mp->next;
550390075Sobrien      if (mp->next != NULL)
550490075Sobrien	mp->next->prev = mp->prev;
550590075Sobrien      else
550690075Sobrien	minipool_vector_tail = mp->prev;
550790075Sobrien
550890075Sobrien      /* Re-insert it before MAX_MP.  */
550990075Sobrien      mp->next = max_mp;
551090075Sobrien      mp->prev = max_mp->prev;
551190075Sobrien      max_mp->prev = mp;
551290075Sobrien
551390075Sobrien      if (mp->prev != NULL)
551490075Sobrien	mp->prev->next = mp;
551590075Sobrien      else
551690075Sobrien	minipool_vector_head = mp;
551790075Sobrien    }
551890075Sobrien
551990075Sobrien  /* Save the new entry.  */
552090075Sobrien  max_mp = mp;
552190075Sobrien
552290075Sobrien  /* Scan over the preceding entries and adjust their addresses as
552390075Sobrien     required.  */
552490075Sobrien  while (mp->prev != NULL
552590075Sobrien	 && mp->prev->max_address > mp->max_address - mp->prev->fix_size)
552690075Sobrien    {
552790075Sobrien      mp->prev->max_address = mp->max_address - mp->prev->fix_size;
552890075Sobrien      mp = mp->prev;
552990075Sobrien    }
553090075Sobrien
553190075Sobrien  return max_mp;
553290075Sobrien}
553390075Sobrien
553490075Sobrien/* Add a constant to the minipool for a forward reference.  Returns the
553590075Sobrien   node added or NULL if the constant will not fit in this pool.  */
553690075Sobrien
553790075Sobrienstatic Mnode *
553890075Sobrienadd_minipool_forward_ref (fix)
553990075Sobrien     Mfix * fix;
554090075Sobrien{
554190075Sobrien  /* If set, max_mp is the first pool_entry that has a lower
554290075Sobrien     constraint than the one we are trying to add.  */
554390075Sobrien  Mnode *       max_mp = NULL;
554490075Sobrien  HOST_WIDE_INT max_address = fix->address + fix->forwards;
554590075Sobrien  Mnode *       mp;
554690075Sobrien
554790075Sobrien  /* If this fix's address is greater than the address of the first
554890075Sobrien     entry, then we can't put the fix in this pool.  We subtract the
554990075Sobrien     size of the current fix to ensure that if the table is fully
555090075Sobrien     packed we still have enough room to insert this value by suffling
555190075Sobrien     the other fixes forwards.  */
555290075Sobrien  if (minipool_vector_head &&
555390075Sobrien      fix->address >= minipool_vector_head->max_address - fix->fix_size)
555490075Sobrien    return NULL;
555590075Sobrien
555690075Sobrien  /* Scan the pool to see if a constant with the same value has
555790075Sobrien     already been added.  While we are doing this, also note the
555890075Sobrien     location where we must insert the constant if it doesn't already
555990075Sobrien     exist.  */
556090075Sobrien  for (mp = minipool_vector_head; mp != NULL; mp = mp->next)
556190075Sobrien    {
556290075Sobrien      if (GET_CODE (fix->value) == GET_CODE (mp->value)
556390075Sobrien	  && fix->mode == mp->mode
556490075Sobrien	  && (GET_CODE (fix->value) != CODE_LABEL
556590075Sobrien	      || (CODE_LABEL_NUMBER (fix->value)
556690075Sobrien		  == CODE_LABEL_NUMBER (mp->value)))
556790075Sobrien	  && rtx_equal_p (fix->value, mp->value))
556890075Sobrien	{
556990075Sobrien	  /* More than one fix references this entry.  */
557090075Sobrien	  mp->refcount++;
557190075Sobrien	  return move_minipool_fix_forward_ref (mp, max_mp, max_address);
557290075Sobrien	}
557390075Sobrien
557490075Sobrien      /* Note the insertion point if necessary.  */
557590075Sobrien      if (max_mp == NULL
557690075Sobrien	  && mp->max_address > max_address)
557790075Sobrien	max_mp = mp;
557890075Sobrien    }
557990075Sobrien
558090075Sobrien  /* The value is not currently in the minipool, so we need to create
558190075Sobrien     a new entry for it.  If MAX_MP is NULL, the entry will be put on
558290075Sobrien     the end of the list since the placement is less constrained than
558390075Sobrien     any existing entry.  Otherwise, we insert the new fix before
558490075Sobrien     MAX_MP and, if neceesary, adjust the constraints on the other
558590075Sobrien     entries.  */
558690075Sobrien  mp = xmalloc (sizeof (* mp));
558790075Sobrien  mp->fix_size = fix->fix_size;
558890075Sobrien  mp->mode = fix->mode;
558990075Sobrien  mp->value = fix->value;
559090075Sobrien  mp->refcount = 1;
559190075Sobrien  /* Not yet required for a backwards ref.  */
559290075Sobrien  mp->min_address = -65536;
559390075Sobrien
559490075Sobrien  if (max_mp == NULL)
559590075Sobrien    {
559690075Sobrien      mp->max_address = max_address;
559790075Sobrien      mp->next = NULL;
559890075Sobrien      mp->prev = minipool_vector_tail;
559990075Sobrien
560090075Sobrien      if (mp->prev == NULL)
560190075Sobrien	{
560290075Sobrien	  minipool_vector_head = mp;
560390075Sobrien	  minipool_vector_label = gen_label_rtx ();
560490075Sobrien	}
560590075Sobrien      else
560690075Sobrien	mp->prev->next = mp;
560790075Sobrien
560890075Sobrien      minipool_vector_tail = mp;
560990075Sobrien    }
561090075Sobrien  else
561190075Sobrien    {
561290075Sobrien      if (max_address > max_mp->max_address - mp->fix_size)
561390075Sobrien	mp->max_address = max_mp->max_address - mp->fix_size;
561490075Sobrien      else
561590075Sobrien	mp->max_address = max_address;
561690075Sobrien
561790075Sobrien      mp->next = max_mp;
561890075Sobrien      mp->prev = max_mp->prev;
561990075Sobrien      max_mp->prev = mp;
562090075Sobrien      if (mp->prev != NULL)
562190075Sobrien	mp->prev->next = mp;
562290075Sobrien      else
562390075Sobrien	minipool_vector_head = mp;
562490075Sobrien    }
562590075Sobrien
562690075Sobrien  /* Save the new entry.  */
562790075Sobrien  max_mp = mp;
562890075Sobrien
562990075Sobrien  /* Scan over the preceding entries and adjust their addresses as
563090075Sobrien     required.  */
563190075Sobrien  while (mp->prev != NULL
563290075Sobrien	 && mp->prev->max_address > mp->max_address - mp->prev->fix_size)
563390075Sobrien    {
563490075Sobrien      mp->prev->max_address = mp->max_address - mp->prev->fix_size;
563590075Sobrien      mp = mp->prev;
563690075Sobrien    }
563790075Sobrien
563890075Sobrien  return max_mp;
563990075Sobrien}
564090075Sobrien
564190075Sobrienstatic Mnode *
564290075Sobrienmove_minipool_fix_backward_ref (mp, min_mp, min_address)
564390075Sobrien     Mnode *        mp;
564490075Sobrien     Mnode *        min_mp;
564590075Sobrien     HOST_WIDE_INT  min_address;
564690075Sobrien{
564790075Sobrien  HOST_WIDE_INT offset;
564890075Sobrien
564990075Sobrien  /* This should never be true, and the code below assumes these are
565090075Sobrien     different.  */
565190075Sobrien  if (mp == min_mp)
565290075Sobrien    abort ();
565390075Sobrien
565490075Sobrien  if (min_mp == NULL)
565590075Sobrien    {
565690075Sobrien      if (min_address > mp->min_address)
565790075Sobrien	mp->min_address = min_address;
565890075Sobrien    }
565990075Sobrien  else
566090075Sobrien    {
566190075Sobrien      /* We will adjust this below if it is too loose.  */
566290075Sobrien      mp->min_address = min_address;
566390075Sobrien
566490075Sobrien      /* Unlink MP from its current position.  Since min_mp is non-null,
566590075Sobrien	 mp->next must be non-null.  */
566690075Sobrien      mp->next->prev = mp->prev;
566790075Sobrien      if (mp->prev != NULL)
566890075Sobrien	mp->prev->next = mp->next;
566990075Sobrien      else
567090075Sobrien	minipool_vector_head = mp->next;
567190075Sobrien
567290075Sobrien      /* Reinsert it after MIN_MP.  */
567390075Sobrien      mp->prev = min_mp;
567490075Sobrien      mp->next = min_mp->next;
567590075Sobrien      min_mp->next = mp;
567690075Sobrien      if (mp->next != NULL)
567790075Sobrien	mp->next->prev = mp;
567890075Sobrien      else
567990075Sobrien	minipool_vector_tail = mp;
568090075Sobrien    }
568190075Sobrien
568290075Sobrien  min_mp = mp;
568390075Sobrien
568490075Sobrien  offset = 0;
568590075Sobrien  for (mp = minipool_vector_head; mp != NULL; mp = mp->next)
568690075Sobrien    {
568790075Sobrien      mp->offset = offset;
568890075Sobrien      if (mp->refcount > 0)
568990075Sobrien	offset += mp->fix_size;
569090075Sobrien
569190075Sobrien      if (mp->next && mp->next->min_address < mp->min_address + mp->fix_size)
569290075Sobrien	mp->next->min_address = mp->min_address + mp->fix_size;
569390075Sobrien    }
569490075Sobrien
569590075Sobrien  return min_mp;
569690075Sobrien}
569790075Sobrien
569890075Sobrien/* Add a constant to the minipool for a backward reference.  Returns the
569990075Sobrien   node added or NULL if the constant will not fit in this pool.
570090075Sobrien
570190075Sobrien   Note that the code for insertion for a backwards reference can be
570290075Sobrien   somewhat confusing because the calculated offsets for each fix do
570390075Sobrien   not take into account the size of the pool (which is still under
570490075Sobrien   construction.  */
570590075Sobrien
570690075Sobrienstatic Mnode *
570790075Sobrienadd_minipool_backward_ref (fix)
570890075Sobrien     Mfix * fix;
570990075Sobrien{
571090075Sobrien  /* If set, min_mp is the last pool_entry that has a lower constraint
571190075Sobrien     than the one we are trying to add.  */
571290075Sobrien  Mnode *        min_mp = NULL;
571390075Sobrien  /* This can be negative, since it is only a constraint.  */
571490075Sobrien  HOST_WIDE_INT  min_address = fix->address - fix->backwards;
571590075Sobrien  Mnode *        mp;
571690075Sobrien
571790075Sobrien  /* If we can't reach the current pool from this insn, or if we can't
571890075Sobrien     insert this entry at the end of the pool without pushing other
571990075Sobrien     fixes out of range, then we don't try.  This ensures that we
572090075Sobrien     can't fail later on.  */
572190075Sobrien  if (min_address >= minipool_barrier->address
572290075Sobrien      || (minipool_vector_tail->min_address + fix->fix_size
572390075Sobrien	  >= minipool_barrier->address))
572490075Sobrien    return NULL;
572590075Sobrien
572690075Sobrien  /* Scan the pool to see if a constant with the same value has
572790075Sobrien     already been added.  While we are doing this, also note the
572890075Sobrien     location where we must insert the constant if it doesn't already
572990075Sobrien     exist.  */
573090075Sobrien  for (mp = minipool_vector_tail; mp != NULL; mp = mp->prev)
573190075Sobrien    {
573290075Sobrien      if (GET_CODE (fix->value) == GET_CODE (mp->value)
573390075Sobrien	  && fix->mode == mp->mode
573490075Sobrien	  && (GET_CODE (fix->value) != CODE_LABEL
573590075Sobrien	      || (CODE_LABEL_NUMBER (fix->value)
573690075Sobrien		  == CODE_LABEL_NUMBER (mp->value)))
573790075Sobrien	  && rtx_equal_p (fix->value, mp->value)
573890075Sobrien	  /* Check that there is enough slack to move this entry to the
573990075Sobrien	     end of the table (this is conservative).  */
574090075Sobrien	  && (mp->max_address
574190075Sobrien	      > (minipool_barrier->address
574290075Sobrien		 + minipool_vector_tail->offset
574390075Sobrien		 + minipool_vector_tail->fix_size)))
574490075Sobrien	{
574590075Sobrien	  mp->refcount++;
574690075Sobrien	  return move_minipool_fix_backward_ref (mp, min_mp, min_address);
574790075Sobrien	}
574890075Sobrien
574990075Sobrien      if (min_mp != NULL)
575090075Sobrien	mp->min_address += fix->fix_size;
575190075Sobrien      else
575290075Sobrien	{
575390075Sobrien	  /* Note the insertion point if necessary.  */
575490075Sobrien	  if (mp->min_address < min_address)
575590075Sobrien	    min_mp = mp;
575690075Sobrien	  else if (mp->max_address
575790075Sobrien		   < minipool_barrier->address + mp->offset + fix->fix_size)
575890075Sobrien	    {
575990075Sobrien	      /* Inserting before this entry would push the fix beyond
576090075Sobrien		 its maximum address (which can happen if we have
576190075Sobrien		 re-located a forwards fix); force the new fix to come
576290075Sobrien		 after it.  */
576390075Sobrien	      min_mp = mp;
576490075Sobrien	      min_address = mp->min_address + fix->fix_size;
576590075Sobrien	    }
576690075Sobrien	}
576790075Sobrien    }
576890075Sobrien
576990075Sobrien  /* We need to create a new entry.  */
577090075Sobrien  mp = xmalloc (sizeof (* mp));
577190075Sobrien  mp->fix_size = fix->fix_size;
577290075Sobrien  mp->mode = fix->mode;
577390075Sobrien  mp->value = fix->value;
577490075Sobrien  mp->refcount = 1;
577590075Sobrien  mp->max_address = minipool_barrier->address + 65536;
577690075Sobrien
577790075Sobrien  mp->min_address = min_address;
577890075Sobrien
577990075Sobrien  if (min_mp == NULL)
578090075Sobrien    {
578190075Sobrien      mp->prev = NULL;
578290075Sobrien      mp->next = minipool_vector_head;
578390075Sobrien
578490075Sobrien      if (mp->next == NULL)
578590075Sobrien	{
578690075Sobrien	  minipool_vector_tail = mp;
578790075Sobrien	  minipool_vector_label = gen_label_rtx ();
578890075Sobrien	}
578990075Sobrien      else
579090075Sobrien	mp->next->prev = mp;
579190075Sobrien
579290075Sobrien      minipool_vector_head = mp;
579390075Sobrien    }
579490075Sobrien  else
579590075Sobrien    {
579690075Sobrien      mp->next = min_mp->next;
579790075Sobrien      mp->prev = min_mp;
579890075Sobrien      min_mp->next = mp;
579990075Sobrien
580090075Sobrien      if (mp->next != NULL)
580190075Sobrien	mp->next->prev = mp;
580290075Sobrien      else
580390075Sobrien	minipool_vector_tail = mp;
580490075Sobrien    }
580590075Sobrien
580690075Sobrien  /* Save the new entry.  */
580790075Sobrien  min_mp = mp;
580890075Sobrien
580990075Sobrien  if (mp->prev)
581090075Sobrien    mp = mp->prev;
581190075Sobrien  else
581290075Sobrien    mp->offset = 0;
581390075Sobrien
581490075Sobrien  /* Scan over the following entries and adjust their offsets.  */
581590075Sobrien  while (mp->next != NULL)
581690075Sobrien    {
581790075Sobrien      if (mp->next->min_address < mp->min_address + mp->fix_size)
581890075Sobrien	mp->next->min_address = mp->min_address + mp->fix_size;
581990075Sobrien
582090075Sobrien      if (mp->refcount)
582190075Sobrien	mp->next->offset = mp->offset + mp->fix_size;
582290075Sobrien      else
582390075Sobrien	mp->next->offset = mp->offset;
582490075Sobrien
582590075Sobrien      mp = mp->next;
582690075Sobrien    }
582790075Sobrien
582890075Sobrien  return min_mp;
582990075Sobrien}
583090075Sobrien
583190075Sobrienstatic void
583290075Sobrienassign_minipool_offsets (barrier)
583390075Sobrien     Mfix * barrier;
583490075Sobrien{
583590075Sobrien  HOST_WIDE_INT offset = 0;
583690075Sobrien  Mnode * mp;
583790075Sobrien
583890075Sobrien  minipool_barrier = barrier;
583990075Sobrien
584090075Sobrien  for (mp = minipool_vector_head; mp != NULL; mp = mp->next)
584190075Sobrien    {
584290075Sobrien      mp->offset = offset;
584390075Sobrien
584490075Sobrien      if (mp->refcount > 0)
584590075Sobrien	offset += mp->fix_size;
584690075Sobrien    }
584790075Sobrien}
584890075Sobrien
584990075Sobrien/* Output the literal table */
585090075Sobrienstatic void
585190075Sobriendump_minipool (scan)
585290075Sobrien     rtx scan;
585390075Sobrien{
585490075Sobrien  Mnode * mp;
585590075Sobrien  Mnode * nmp;
585690075Sobrien
585790075Sobrien  if (rtl_dump_file)
585890075Sobrien    fprintf (rtl_dump_file,
585990075Sobrien	     ";; Emitting minipool after insn %u; address %ld\n",
586090075Sobrien	     INSN_UID (scan), (unsigned long) minipool_barrier->address);
586190075Sobrien
586290075Sobrien  scan = emit_label_after (gen_label_rtx (), scan);
586390075Sobrien  scan = emit_insn_after (gen_align_4 (), scan);
586490075Sobrien  scan = emit_label_after (minipool_vector_label, scan);
586590075Sobrien
586690075Sobrien  for (mp = minipool_vector_head; mp != NULL; mp = nmp)
586790075Sobrien    {
586890075Sobrien      if (mp->refcount > 0)
586990075Sobrien	{
587090075Sobrien	  if (rtl_dump_file)
587190075Sobrien	    {
587290075Sobrien	      fprintf (rtl_dump_file,
587390075Sobrien		       ";;  Offset %u, min %ld, max %ld ",
587490075Sobrien		       (unsigned) mp->offset, (unsigned long) mp->min_address,
587590075Sobrien		       (unsigned long) mp->max_address);
587690075Sobrien	      arm_print_value (rtl_dump_file, mp->value);
587790075Sobrien	      fputc ('\n', rtl_dump_file);
587890075Sobrien	    }
587990075Sobrien
588090075Sobrien	  switch (mp->fix_size)
588190075Sobrien	    {
588290075Sobrien#ifdef HAVE_consttable_1
588390075Sobrien	    case 1:
588490075Sobrien	      scan = emit_insn_after (gen_consttable_1 (mp->value), scan);
588590075Sobrien	      break;
588690075Sobrien
588790075Sobrien#endif
588890075Sobrien#ifdef HAVE_consttable_2
588990075Sobrien	    case 2:
589090075Sobrien	      scan = emit_insn_after (gen_consttable_2 (mp->value), scan);
589190075Sobrien	      break;
589290075Sobrien
589390075Sobrien#endif
589490075Sobrien#ifdef HAVE_consttable_4
589590075Sobrien	    case 4:
589690075Sobrien	      scan = emit_insn_after (gen_consttable_4 (mp->value), scan);
589790075Sobrien	      break;
589890075Sobrien
589990075Sobrien#endif
590090075Sobrien#ifdef HAVE_consttable_8
590190075Sobrien	    case 8:
590290075Sobrien	      scan = emit_insn_after (gen_consttable_8 (mp->value), scan);
590390075Sobrien	      break;
590490075Sobrien
590590075Sobrien#endif
590690075Sobrien	    default:
590790075Sobrien	      abort ();
590890075Sobrien	      break;
590990075Sobrien	    }
591090075Sobrien	}
591190075Sobrien
591290075Sobrien      nmp = mp->next;
591390075Sobrien      free (mp);
591490075Sobrien    }
591590075Sobrien
591690075Sobrien  minipool_vector_head = minipool_vector_tail = NULL;
591790075Sobrien  scan = emit_insn_after (gen_consttable_end (), scan);
591890075Sobrien  scan = emit_barrier_after (scan);
591990075Sobrien}
592090075Sobrien
592190075Sobrien/* Return the cost of forcibly inserting a barrier after INSN.  */
592290075Sobrien
592390075Sobrienstatic int
592490075Sobrienarm_barrier_cost (insn)
592590075Sobrien     rtx insn;
592690075Sobrien{
592790075Sobrien  /* Basing the location of the pool on the loop depth is preferable,
592890075Sobrien     but at the moment, the basic block information seems to be
592990075Sobrien     corrupt by this stage of the compilation.  */
593090075Sobrien  int base_cost = 50;
593190075Sobrien  rtx next = next_nonnote_insn (insn);
593290075Sobrien
593390075Sobrien  if (next != NULL && GET_CODE (next) == CODE_LABEL)
593490075Sobrien    base_cost -= 20;
593590075Sobrien
593690075Sobrien  switch (GET_CODE (insn))
593790075Sobrien    {
593890075Sobrien    case CODE_LABEL:
593990075Sobrien      /* It will always be better to place the table before the label, rather
594090075Sobrien	 than after it.  */
594190075Sobrien      return 50;
594290075Sobrien
594390075Sobrien    case INSN:
594490075Sobrien    case CALL_INSN:
594590075Sobrien      return base_cost;
594690075Sobrien
594790075Sobrien    case JUMP_INSN:
594890075Sobrien      return base_cost - 10;
594990075Sobrien
595090075Sobrien    default:
595190075Sobrien      return base_cost + 10;
595290075Sobrien    }
595390075Sobrien}
595490075Sobrien
595590075Sobrien/* Find the best place in the insn stream in the range
595690075Sobrien   (FIX->address,MAX_ADDRESS) to forcibly insert a minipool barrier.
595790075Sobrien   Create the barrier by inserting a jump and add a new fix entry for
595890075Sobrien   it.  */
595990075Sobrien
596090075Sobrienstatic Mfix *
596190075Sobriencreate_fix_barrier (fix, max_address)
596290075Sobrien     Mfix * fix;
596390075Sobrien     HOST_WIDE_INT max_address;
596490075Sobrien{
596590075Sobrien  HOST_WIDE_INT count = 0;
596690075Sobrien  rtx barrier;
596790075Sobrien  rtx from = fix->insn;
596890075Sobrien  rtx selected = from;
596990075Sobrien  int selected_cost;
597090075Sobrien  HOST_WIDE_INT selected_address;
597190075Sobrien  Mfix * new_fix;
597290075Sobrien  HOST_WIDE_INT max_count = max_address - fix->address;
597390075Sobrien  rtx label = gen_label_rtx ();
597490075Sobrien
597590075Sobrien  selected_cost = arm_barrier_cost (from);
597690075Sobrien  selected_address = fix->address;
597790075Sobrien
597890075Sobrien  while (from && count < max_count)
597990075Sobrien    {
598090075Sobrien      rtx tmp;
598190075Sobrien      int new_cost;
598290075Sobrien
598390075Sobrien      /* This code shouldn't have been called if there was a natural barrier
598490075Sobrien	 within range.  */
598590075Sobrien      if (GET_CODE (from) == BARRIER)
598690075Sobrien	abort ();
598790075Sobrien
598890075Sobrien      /* Count the length of this insn.  */
598990075Sobrien      count += get_attr_length (from);
599090075Sobrien
599190075Sobrien      /* If there is a jump table, add its length.  */
599290075Sobrien      tmp = is_jump_table (from);
599390075Sobrien      if (tmp != NULL)
599490075Sobrien	{
599590075Sobrien	  count += get_jump_table_size (tmp);
599690075Sobrien
599790075Sobrien	  /* Jump tables aren't in a basic block, so base the cost on
599890075Sobrien	     the dispatch insn.  If we select this location, we will
599990075Sobrien	     still put the pool after the table.  */
600090075Sobrien	  new_cost = arm_barrier_cost (from);
600190075Sobrien
600290075Sobrien	  if (count < max_count && new_cost <= selected_cost)
600390075Sobrien	    {
600490075Sobrien	      selected = tmp;
600590075Sobrien	      selected_cost = new_cost;
600690075Sobrien	      selected_address = fix->address + count;
600790075Sobrien	    }
600890075Sobrien
600990075Sobrien	  /* Continue after the dispatch table.  */
601090075Sobrien	  from = NEXT_INSN (tmp);
601190075Sobrien	  continue;
601290075Sobrien	}
601390075Sobrien
601490075Sobrien      new_cost = arm_barrier_cost (from);
601590075Sobrien
601690075Sobrien      if (count < max_count && new_cost <= selected_cost)
601790075Sobrien	{
601890075Sobrien	  selected = from;
601990075Sobrien	  selected_cost = new_cost;
602090075Sobrien	  selected_address = fix->address + count;
602190075Sobrien	}
602290075Sobrien
602390075Sobrien      from = NEXT_INSN (from);
602490075Sobrien    }
602590075Sobrien
602690075Sobrien  /* Create a new JUMP_INSN that branches around a barrier.  */
602790075Sobrien  from = emit_jump_insn_after (gen_jump (label), selected);
602890075Sobrien  JUMP_LABEL (from) = label;
602990075Sobrien  barrier = emit_barrier_after (from);
603090075Sobrien  emit_label_after (label, barrier);
603190075Sobrien
603290075Sobrien  /* Create a minipool barrier entry for the new barrier.  */
603390075Sobrien  new_fix = (Mfix *) obstack_alloc (&minipool_obstack, sizeof (* new_fix));
603490075Sobrien  new_fix->insn = barrier;
603590075Sobrien  new_fix->address = selected_address;
603690075Sobrien  new_fix->next = fix->next;
603790075Sobrien  fix->next = new_fix;
603890075Sobrien
603990075Sobrien  return new_fix;
604090075Sobrien}
604190075Sobrien
604290075Sobrien/* Record that there is a natural barrier in the insn stream at
604390075Sobrien   ADDRESS.  */
604490075Sobrienstatic void
604590075Sobrienpush_minipool_barrier (insn, address)
604690075Sobrien     rtx insn;
604790075Sobrien     HOST_WIDE_INT address;
604890075Sobrien{
604990075Sobrien  Mfix * fix = (Mfix *) obstack_alloc (&minipool_obstack, sizeof (* fix));
605090075Sobrien
605190075Sobrien  fix->insn = insn;
605290075Sobrien  fix->address = address;
605390075Sobrien
605490075Sobrien  fix->next = NULL;
605590075Sobrien  if (minipool_fix_head != NULL)
605690075Sobrien    minipool_fix_tail->next = fix;
605790075Sobrien  else
605890075Sobrien    minipool_fix_head = fix;
605990075Sobrien
606090075Sobrien  minipool_fix_tail = fix;
606190075Sobrien}
606290075Sobrien
606390075Sobrien/* Record INSN, which will need fixing up to load a value from the
606490075Sobrien   minipool.  ADDRESS is the offset of the insn since the start of the
606590075Sobrien   function; LOC is a pointer to the part of the insn which requires
606690075Sobrien   fixing; VALUE is the constant that must be loaded, which is of type
606790075Sobrien   MODE.  */
606890075Sobrienstatic void
606990075Sobrienpush_minipool_fix (insn, address, loc, mode, value)
607090075Sobrien     rtx insn;
607190075Sobrien     HOST_WIDE_INT address;
607290075Sobrien     rtx * loc;
607390075Sobrien     enum machine_mode mode;
607490075Sobrien     rtx value;
607590075Sobrien{
607690075Sobrien  Mfix * fix = (Mfix *) obstack_alloc (&minipool_obstack, sizeof (* fix));
607790075Sobrien
607890075Sobrien#ifdef AOF_ASSEMBLER
607990075Sobrien  /* PIC symbol refereneces need to be converted into offsets into the
608090075Sobrien     based area.  */
608190075Sobrien  /* XXX This shouldn't be done here.  */
608290075Sobrien  if (flag_pic && GET_CODE (value) == SYMBOL_REF)
608390075Sobrien    value = aof_pic_entry (value);
608490075Sobrien#endif /* AOF_ASSEMBLER */
608590075Sobrien
608690075Sobrien  fix->insn = insn;
608790075Sobrien  fix->address = address;
608890075Sobrien  fix->loc = loc;
608990075Sobrien  fix->mode = mode;
609090075Sobrien  fix->fix_size = MINIPOOL_FIX_SIZE (mode);
609190075Sobrien  fix->value = value;
609290075Sobrien  fix->forwards = get_attr_pool_range (insn);
609390075Sobrien  fix->backwards = get_attr_neg_pool_range (insn);
609490075Sobrien  fix->minipool = NULL;
609590075Sobrien
609690075Sobrien  /* If an insn doesn't have a range defined for it, then it isn't
609790075Sobrien     expecting to be reworked by this code.  Better to abort now than
609890075Sobrien     to generate duff assembly code.  */
609990075Sobrien  if (fix->forwards == 0 && fix->backwards == 0)
610090075Sobrien    abort ();
610190075Sobrien
610290075Sobrien  if (rtl_dump_file)
610390075Sobrien    {
610490075Sobrien      fprintf (rtl_dump_file,
610590075Sobrien	       ";; %smode fixup for i%d; addr %lu, range (%ld,%ld): ",
610690075Sobrien	       GET_MODE_NAME (mode),
610790075Sobrien	       INSN_UID (insn), (unsigned long) address,
610890075Sobrien	       -1 * (long)fix->backwards, (long)fix->forwards);
610990075Sobrien      arm_print_value (rtl_dump_file, fix->value);
611090075Sobrien      fprintf (rtl_dump_file, "\n");
611190075Sobrien    }
611290075Sobrien
611390075Sobrien  /* Add it to the chain of fixes.  */
611490075Sobrien  fix->next = NULL;
611590075Sobrien
611690075Sobrien  if (minipool_fix_head != NULL)
611790075Sobrien    minipool_fix_tail->next = fix;
611890075Sobrien  else
611990075Sobrien    minipool_fix_head = fix;
612090075Sobrien
612190075Sobrien  minipool_fix_tail = fix;
612290075Sobrien}
612390075Sobrien
612490075Sobrien/* Scan INSN and note any of its operands that need fixing.  */
612590075Sobrien
612690075Sobrienstatic void
612790075Sobriennote_invalid_constants (insn, address)
612890075Sobrien     rtx insn;
612990075Sobrien     HOST_WIDE_INT address;
613090075Sobrien{
613190075Sobrien  int opno;
613290075Sobrien
613390075Sobrien  extract_insn (insn);
613490075Sobrien
613590075Sobrien  if (!constrain_operands (1))
613690075Sobrien    fatal_insn_not_found (insn);
613790075Sobrien
613890075Sobrien  /* Fill in recog_op_alt with information about the constraints of this
613990075Sobrien     insn.  */
614090075Sobrien  preprocess_constraints ();
614190075Sobrien
614290075Sobrien  for (opno = 0; opno < recog_data.n_operands; opno++)
614390075Sobrien    {
614490075Sobrien      /* Things we need to fix can only occur in inputs.  */
614590075Sobrien      if (recog_data.operand_type[opno] != OP_IN)
614690075Sobrien	continue;
614790075Sobrien
614890075Sobrien      /* If this alternative is a memory reference, then any mention
614990075Sobrien	 of constants in this alternative is really to fool reload
615090075Sobrien	 into allowing us to accept one there.  We need to fix them up
615190075Sobrien	 now so that we output the right code.  */
615290075Sobrien      if (recog_op_alt[opno][which_alternative].memory_ok)
615390075Sobrien	{
615490075Sobrien	  rtx op = recog_data.operand[opno];
615590075Sobrien
615690075Sobrien	  if (CONSTANT_P (op))
615790075Sobrien	    push_minipool_fix (insn, address, recog_data.operand_loc[opno],
615890075Sobrien			       recog_data.operand_mode[opno], op);
615990075Sobrien#if 0
616090075Sobrien	  /* RWE: Now we look correctly at the operands for the insn,
616190075Sobrien	     this shouldn't be needed any more.  */
616290075Sobrien#ifndef AOF_ASSEMBLER
616390075Sobrien	  /* XXX Is this still needed?  */
616490075Sobrien	  else if (GET_CODE (op) == UNSPEC && XINT (op, 1) == UNSPEC_PIC_SYM)
616590075Sobrien	    push_minipool_fix (insn, address, recog_data.operand_loc[opno],
616690075Sobrien			       recog_data.operand_mode[opno],
616790075Sobrien			       XVECEXP (op, 0, 0));
616890075Sobrien#endif
616990075Sobrien#endif
617090075Sobrien	  else if (GET_CODE (op) == MEM
617190075Sobrien		   && GET_CODE (XEXP (op, 0)) == SYMBOL_REF
617290075Sobrien		   && CONSTANT_POOL_ADDRESS_P (XEXP (op, 0)))
617390075Sobrien	    push_minipool_fix (insn, address, recog_data.operand_loc[opno],
617490075Sobrien			       recog_data.operand_mode[opno],
617590075Sobrien			       get_pool_constant (XEXP (op, 0)));
617690075Sobrien	}
617790075Sobrien    }
617890075Sobrien}
617990075Sobrien
618090075Sobrienvoid
618190075Sobrienarm_reorg (first)
618290075Sobrien     rtx first;
618390075Sobrien{
618490075Sobrien  rtx insn;
618590075Sobrien  HOST_WIDE_INT address = 0;
618690075Sobrien  Mfix * fix;
618790075Sobrien
618890075Sobrien  minipool_fix_head = minipool_fix_tail = NULL;
618990075Sobrien
619090075Sobrien  /* The first insn must always be a note, or the code below won't
619190075Sobrien     scan it properly.  */
619290075Sobrien  if (GET_CODE (first) != NOTE)
619390075Sobrien    abort ();
619490075Sobrien
619590075Sobrien  /* Scan all the insns and record the operands that will need fixing.  */
619690075Sobrien  for (insn = next_nonnote_insn (first); insn; insn = next_nonnote_insn (insn))
619790075Sobrien    {
619890075Sobrien      if (GET_CODE (insn) == BARRIER)
619990075Sobrien	push_minipool_barrier (insn, address);
620090075Sobrien      else if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN
620190075Sobrien	       || GET_CODE (insn) == JUMP_INSN)
620290075Sobrien	{
620390075Sobrien	  rtx table;
620490075Sobrien
620590075Sobrien	  note_invalid_constants (insn, address);
620690075Sobrien	  address += get_attr_length (insn);
620790075Sobrien
620890075Sobrien	  /* If the insn is a vector jump, add the size of the table
620990075Sobrien	     and skip the table.  */
621090075Sobrien	  if ((table = is_jump_table (insn)) != NULL)
621190075Sobrien	    {
621290075Sobrien	      address += get_jump_table_size (table);
621390075Sobrien	      insn = table;
621490075Sobrien	    }
621590075Sobrien	}
621690075Sobrien    }
621790075Sobrien
621890075Sobrien  fix = minipool_fix_head;
621990075Sobrien
622090075Sobrien  /* Now scan the fixups and perform the required changes.  */
622190075Sobrien  while (fix)
622290075Sobrien    {
622390075Sobrien      Mfix * ftmp;
622490075Sobrien      Mfix * fdel;
622590075Sobrien      Mfix *  last_added_fix;
622690075Sobrien      Mfix * last_barrier = NULL;
622790075Sobrien      Mfix * this_fix;
622890075Sobrien
622990075Sobrien      /* Skip any further barriers before the next fix.  */
623090075Sobrien      while (fix && GET_CODE (fix->insn) == BARRIER)
623190075Sobrien	fix = fix->next;
623290075Sobrien
623390075Sobrien      /* No more fixes.  */
623490075Sobrien      if (fix == NULL)
623590075Sobrien	break;
623690075Sobrien
623790075Sobrien      last_added_fix = NULL;
623890075Sobrien
623990075Sobrien      for (ftmp = fix; ftmp; ftmp = ftmp->next)
624090075Sobrien	{
624190075Sobrien	  if (GET_CODE (ftmp->insn) == BARRIER)
624290075Sobrien	    {
624390075Sobrien	      if (ftmp->address >= minipool_vector_head->max_address)
624490075Sobrien		break;
624590075Sobrien
624690075Sobrien	      last_barrier = ftmp;
624790075Sobrien	    }
624890075Sobrien	  else if ((ftmp->minipool = add_minipool_forward_ref (ftmp)) == NULL)
624990075Sobrien	    break;
625090075Sobrien
625190075Sobrien	  last_added_fix = ftmp;  /* Keep track of the last fix added.  */
625290075Sobrien	}
625390075Sobrien
625490075Sobrien      /* If we found a barrier, drop back to that; any fixes that we
625590075Sobrien	 could have reached but come after the barrier will now go in
625690075Sobrien	 the next mini-pool.  */
625790075Sobrien      if (last_barrier != NULL)
625890075Sobrien	{
625990075Sobrien	  /* Reduce the refcount for those fixes that won't go into this
626090075Sobrien	     pool after all.  */
626190075Sobrien	  for (fdel = last_barrier->next;
626290075Sobrien	       fdel && fdel != ftmp;
626390075Sobrien	       fdel = fdel->next)
626490075Sobrien	    {
626590075Sobrien	      fdel->minipool->refcount--;
626690075Sobrien	      fdel->minipool = NULL;
626790075Sobrien	    }
626890075Sobrien
626990075Sobrien	  ftmp = last_barrier;
627090075Sobrien	}
627190075Sobrien      else
627290075Sobrien        {
627390075Sobrien	  /* ftmp is first fix that we can't fit into this pool and
627490075Sobrien	     there no natural barriers that we could use.  Insert a
627590075Sobrien	     new barrier in the code somewhere between the previous
627690075Sobrien	     fix and this one, and arrange to jump around it.  */
627790075Sobrien	  HOST_WIDE_INT max_address;
627890075Sobrien
627990075Sobrien	  /* The last item on the list of fixes must be a barrier, so
628090075Sobrien	     we can never run off the end of the list of fixes without
628190075Sobrien	     last_barrier being set.  */
628290075Sobrien	  if (ftmp == NULL)
628390075Sobrien	    abort ();
628490075Sobrien
628590075Sobrien	  max_address = minipool_vector_head->max_address;
628690075Sobrien	  /* Check that there isn't another fix that is in range that
628790075Sobrien	     we couldn't fit into this pool because the pool was
628890075Sobrien	     already too large: we need to put the pool before such an
628990075Sobrien	     instruction.  */
629090075Sobrien	  if (ftmp->address < max_address)
629190075Sobrien	    max_address = ftmp->address;
629290075Sobrien
629390075Sobrien	  last_barrier = create_fix_barrier (last_added_fix, max_address);
629490075Sobrien	}
629590075Sobrien
629690075Sobrien      assign_minipool_offsets (last_barrier);
629790075Sobrien
629890075Sobrien      while (ftmp)
629990075Sobrien	{
630090075Sobrien	  if (GET_CODE (ftmp->insn) != BARRIER
630190075Sobrien	      && ((ftmp->minipool = add_minipool_backward_ref (ftmp))
630290075Sobrien		  == NULL))
630390075Sobrien	    break;
630490075Sobrien
630590075Sobrien	  ftmp = ftmp->next;
630690075Sobrien	}
630790075Sobrien
630890075Sobrien      /* Scan over the fixes we have identified for this pool, fixing them
630990075Sobrien	 up and adding the constants to the pool itself.  */
631090075Sobrien      for (this_fix = fix; this_fix && ftmp != this_fix;
631190075Sobrien	   this_fix = this_fix->next)
631290075Sobrien	if (GET_CODE (this_fix->insn) != BARRIER)
631390075Sobrien	  {
631490075Sobrien	    rtx addr
631590075Sobrien	      = plus_constant (gen_rtx_LABEL_REF (VOIDmode,
631690075Sobrien						  minipool_vector_label),
631790075Sobrien			       this_fix->minipool->offset);
631890075Sobrien	    *this_fix->loc = gen_rtx_MEM (this_fix->mode, addr);
631990075Sobrien	  }
632090075Sobrien
632190075Sobrien      dump_minipool (last_barrier->insn);
632290075Sobrien      fix = ftmp;
632390075Sobrien    }
632490075Sobrien
632590075Sobrien  /* From now on we must synthesize any constants that we can't handle
632690075Sobrien     directly.  This can happen if the RTL gets split during final
632790075Sobrien     instruction generation.  */
632890075Sobrien  after_arm_reorg = 1;
632990075Sobrien
633090075Sobrien  /* Free the minipool memory.  */
633190075Sobrien  obstack_free (&minipool_obstack, minipool_startobj);
633290075Sobrien}
633390075Sobrien
633490075Sobrien/* Routines to output assembly language.  */
633590075Sobrien
633690075Sobrien/* If the rtx is the correct value then return the string of the number.
633790075Sobrien   In this way we can ensure that valid double constants are generated even
633890075Sobrien   when cross compiling.  */
633990075Sobrien
634090075Sobrienconst char *
634190075Sobrienfp_immediate_constant (x)
634290075Sobrien     rtx x;
634390075Sobrien{
634490075Sobrien  REAL_VALUE_TYPE r;
634590075Sobrien  int i;
634690075Sobrien
634790075Sobrien  if (!fpa_consts_inited)
634890075Sobrien    init_fpa_table ();
634990075Sobrien
635090075Sobrien  REAL_VALUE_FROM_CONST_DOUBLE (r, x);
635190075Sobrien  for (i = 0; i < 8; i++)
635290075Sobrien    if (REAL_VALUES_EQUAL (r, values_fpa[i]))
635390075Sobrien      return strings_fpa[i];
635490075Sobrien
635590075Sobrien  abort ();
635690075Sobrien}
635790075Sobrien
635890075Sobrien/* As for fp_immediate_constant, but value is passed directly, not in rtx.  */
635990075Sobrien
636090075Sobrienstatic const char *
636190075Sobrienfp_const_from_val (r)
636290075Sobrien     REAL_VALUE_TYPE * r;
636390075Sobrien{
636490075Sobrien  int i;
636590075Sobrien
636690075Sobrien  if (!fpa_consts_inited)
636790075Sobrien    init_fpa_table ();
636890075Sobrien
636990075Sobrien  for (i = 0; i < 8; i++)
637090075Sobrien    if (REAL_VALUES_EQUAL (*r, values_fpa[i]))
637190075Sobrien      return strings_fpa[i];
637290075Sobrien
637390075Sobrien  abort ();
637490075Sobrien}
637590075Sobrien
637690075Sobrien/* Output the operands of a LDM/STM instruction to STREAM.
637790075Sobrien   MASK is the ARM register set mask of which only bits 0-15 are important.
637890075Sobrien   REG is the base register, either the frame pointer or the stack pointer,
637990075Sobrien   INSTR is the possibly suffixed load or store instruction.  */
638090075Sobrien
638190075Sobrienstatic void
638290075Sobrienprint_multi_reg (stream, instr, reg, mask)
638390075Sobrien     FILE * stream;
638490075Sobrien     const char * instr;
638590075Sobrien     int reg;
638690075Sobrien     int mask;
638790075Sobrien{
638890075Sobrien  int i;
638990075Sobrien  int not_first = FALSE;
639090075Sobrien
639190075Sobrien  fputc ('\t', stream);
639290075Sobrien  asm_fprintf (stream, instr, reg);
639390075Sobrien  fputs (", {", stream);
639490075Sobrien
639590075Sobrien  for (i = 0; i <= LAST_ARM_REGNUM; i++)
639690075Sobrien    if (mask & (1 << i))
639790075Sobrien      {
639890075Sobrien	if (not_first)
639990075Sobrien	  fprintf (stream, ", ");
640090075Sobrien
640190075Sobrien	asm_fprintf (stream, "%r", i);
640290075Sobrien	not_first = TRUE;
640390075Sobrien      }
640490075Sobrien
640590075Sobrien  fprintf (stream, "}%s\n", TARGET_APCS_32 ? "" : "^");
640690075Sobrien}
640790075Sobrien
640890075Sobrien/* Output a 'call' insn.  */
640990075Sobrien
641090075Sobrienconst char *
641190075Sobrienoutput_call (operands)
641290075Sobrien     rtx * operands;
641390075Sobrien{
641490075Sobrien  /* Handle calls to lr using ip (which may be clobbered in subr anyway).  */
641590075Sobrien
641690075Sobrien  if (REGNO (operands[0]) == LR_REGNUM)
641790075Sobrien    {
641890075Sobrien      operands[0] = gen_rtx_REG (SImode, IP_REGNUM);
641990075Sobrien      output_asm_insn ("mov%?\t%0, %|lr", operands);
642090075Sobrien    }
642190075Sobrien
642290075Sobrien  output_asm_insn ("mov%?\t%|lr, %|pc", operands);
642390075Sobrien
642490075Sobrien  if (TARGET_INTERWORK)
642590075Sobrien    output_asm_insn ("bx%?\t%0", operands);
642690075Sobrien  else
642790075Sobrien    output_asm_insn ("mov%?\t%|pc, %0", operands);
642890075Sobrien
642990075Sobrien  return "";
643090075Sobrien}
643190075Sobrien
643290075Sobrien/* Output a 'call' insn that is a reference in memory.  */
643390075Sobrien
643490075Sobrienconst char *
643590075Sobrienoutput_call_mem (operands)
643690075Sobrien     rtx * operands;
643790075Sobrien{
643890075Sobrien  if (TARGET_INTERWORK)
643990075Sobrien    {
644090075Sobrien      output_asm_insn ("ldr%?\t%|ip, %0", operands);
644190075Sobrien      output_asm_insn ("mov%?\t%|lr, %|pc", operands);
644290075Sobrien      output_asm_insn ("bx%?\t%|ip", operands);
644390075Sobrien    }
6444117395Skan  else if (regno_use_in (LR_REGNUM, operands[0]))
6445117395Skan    {
6446117395Skan      /* LR is used in the memory address.  We load the address in the
6447117395Skan	 first instruction.  It's safe to use IP as the target of the
6448117395Skan	 load since the call will kill it anyway.  */
6449117395Skan      output_asm_insn ("ldr%?\t%|ip, %0", operands);
6450117395Skan      output_asm_insn ("mov%?\t%|lr, %|pc", operands);
6451117395Skan      output_asm_insn ("mov%?\t%|pc, %|ip", operands);
6452117395Skan    }
645390075Sobrien  else
645490075Sobrien    {
645590075Sobrien      output_asm_insn ("mov%?\t%|lr, %|pc", operands);
645690075Sobrien      output_asm_insn ("ldr%?\t%|pc, %0", operands);
645790075Sobrien    }
645890075Sobrien
645990075Sobrien  return "";
646090075Sobrien}
646190075Sobrien
646290075Sobrien
646390075Sobrien/* Output a move from arm registers to an fpu registers.
646490075Sobrien   OPERANDS[0] is an fpu register.
646590075Sobrien   OPERANDS[1] is the first registers of an arm register pair.  */
646690075Sobrien
646790075Sobrienconst char *
646890075Sobrienoutput_mov_long_double_fpu_from_arm (operands)
646990075Sobrien     rtx * operands;
647090075Sobrien{
647190075Sobrien  int arm_reg0 = REGNO (operands[1]);
647290075Sobrien  rtx ops[3];
647390075Sobrien
647490075Sobrien  if (arm_reg0 == IP_REGNUM)
647590075Sobrien    abort ();
647690075Sobrien
647790075Sobrien  ops[0] = gen_rtx_REG (SImode, arm_reg0);
647890075Sobrien  ops[1] = gen_rtx_REG (SImode, 1 + arm_reg0);
647990075Sobrien  ops[2] = gen_rtx_REG (SImode, 2 + arm_reg0);
648090075Sobrien
648190075Sobrien  output_asm_insn ("stm%?fd\t%|sp!, {%0, %1, %2}", ops);
648290075Sobrien  output_asm_insn ("ldf%?e\t%0, [%|sp], #12", operands);
648390075Sobrien
648490075Sobrien  return "";
648590075Sobrien}
648690075Sobrien
648790075Sobrien/* Output a move from an fpu register to arm registers.
648890075Sobrien   OPERANDS[0] is the first registers of an arm register pair.
648990075Sobrien   OPERANDS[1] is an fpu register.  */
649090075Sobrien
649190075Sobrienconst char *
649290075Sobrienoutput_mov_long_double_arm_from_fpu (operands)
649390075Sobrien     rtx * operands;
649490075Sobrien{
649590075Sobrien  int arm_reg0 = REGNO (operands[0]);
649690075Sobrien  rtx ops[3];
649790075Sobrien
649890075Sobrien  if (arm_reg0 == IP_REGNUM)
649990075Sobrien    abort ();
650090075Sobrien
650190075Sobrien  ops[0] = gen_rtx_REG (SImode, arm_reg0);
650290075Sobrien  ops[1] = gen_rtx_REG (SImode, 1 + arm_reg0);
650390075Sobrien  ops[2] = gen_rtx_REG (SImode, 2 + arm_reg0);
650490075Sobrien
650590075Sobrien  output_asm_insn ("stf%?e\t%1, [%|sp, #-12]!", operands);
650690075Sobrien  output_asm_insn ("ldm%?fd\t%|sp!, {%0, %1, %2}", ops);
650790075Sobrien  return "";
650890075Sobrien}
650990075Sobrien
651090075Sobrien/* Output a move from arm registers to arm registers of a long double
651190075Sobrien   OPERANDS[0] is the destination.
651290075Sobrien   OPERANDS[1] is the source.  */
651390075Sobrien
651490075Sobrienconst char *
651590075Sobrienoutput_mov_long_double_arm_from_arm (operands)
651690075Sobrien     rtx * operands;
651790075Sobrien{
651890075Sobrien  /* We have to be careful here because the two might overlap.  */
651990075Sobrien  int dest_start = REGNO (operands[0]);
652090075Sobrien  int src_start = REGNO (operands[1]);
652190075Sobrien  rtx ops[2];
652290075Sobrien  int i;
652390075Sobrien
652490075Sobrien  if (dest_start < src_start)
652590075Sobrien    {
652690075Sobrien      for (i = 0; i < 3; i++)
652790075Sobrien	{
652890075Sobrien	  ops[0] = gen_rtx_REG (SImode, dest_start + i);
652990075Sobrien	  ops[1] = gen_rtx_REG (SImode, src_start + i);
653090075Sobrien	  output_asm_insn ("mov%?\t%0, %1", ops);
653190075Sobrien	}
653290075Sobrien    }
653390075Sobrien  else
653490075Sobrien    {
653590075Sobrien      for (i = 2; i >= 0; i--)
653690075Sobrien	{
653790075Sobrien	  ops[0] = gen_rtx_REG (SImode, dest_start + i);
653890075Sobrien	  ops[1] = gen_rtx_REG (SImode, src_start + i);
653990075Sobrien	  output_asm_insn ("mov%?\t%0, %1", ops);
654090075Sobrien	}
654190075Sobrien    }
654290075Sobrien
654390075Sobrien  return "";
654490075Sobrien}
654590075Sobrien
654690075Sobrien
654790075Sobrien/* Output a move from arm registers to an fpu registers.
654890075Sobrien   OPERANDS[0] is an fpu register.
654990075Sobrien   OPERANDS[1] is the first registers of an arm register pair.  */
655090075Sobrien
655190075Sobrienconst char *
655290075Sobrienoutput_mov_double_fpu_from_arm (operands)
655390075Sobrien     rtx * operands;
655490075Sobrien{
655590075Sobrien  int arm_reg0 = REGNO (operands[1]);
655690075Sobrien  rtx ops[2];
655790075Sobrien
655890075Sobrien  if (arm_reg0 == IP_REGNUM)
655990075Sobrien    abort ();
656090075Sobrien
656190075Sobrien  ops[0] = gen_rtx_REG (SImode, arm_reg0);
656290075Sobrien  ops[1] = gen_rtx_REG (SImode, 1 + arm_reg0);
656390075Sobrien  output_asm_insn ("stm%?fd\t%|sp!, {%0, %1}", ops);
656490075Sobrien  output_asm_insn ("ldf%?d\t%0, [%|sp], #8", operands);
656590075Sobrien  return "";
656690075Sobrien}
656790075Sobrien
656890075Sobrien/* Output a move from an fpu register to arm registers.
656990075Sobrien   OPERANDS[0] is the first registers of an arm register pair.
657090075Sobrien   OPERANDS[1] is an fpu register.  */
657190075Sobrien
657290075Sobrienconst char *
657390075Sobrienoutput_mov_double_arm_from_fpu (operands)
657490075Sobrien     rtx * operands;
657590075Sobrien{
657690075Sobrien  int arm_reg0 = REGNO (operands[0]);
657790075Sobrien  rtx ops[2];
657890075Sobrien
657990075Sobrien  if (arm_reg0 == IP_REGNUM)
658090075Sobrien    abort ();
658190075Sobrien
658290075Sobrien  ops[0] = gen_rtx_REG (SImode, arm_reg0);
658390075Sobrien  ops[1] = gen_rtx_REG (SImode, 1 + arm_reg0);
658490075Sobrien  output_asm_insn ("stf%?d\t%1, [%|sp, #-8]!", operands);
658590075Sobrien  output_asm_insn ("ldm%?fd\t%|sp!, {%0, %1}", ops);
658690075Sobrien  return "";
658790075Sobrien}
658890075Sobrien
658990075Sobrien/* Output a move between double words.
659090075Sobrien   It must be REG<-REG, REG<-CONST_DOUBLE, REG<-CONST_INT, REG<-MEM
659190075Sobrien   or MEM<-REG and all MEMs must be offsettable addresses.  */
659290075Sobrien
659390075Sobrienconst char *
659490075Sobrienoutput_move_double (operands)
659590075Sobrien     rtx * operands;
659690075Sobrien{
659790075Sobrien  enum rtx_code code0 = GET_CODE (operands[0]);
659890075Sobrien  enum rtx_code code1 = GET_CODE (operands[1]);
659990075Sobrien  rtx otherops[3];
660090075Sobrien
660190075Sobrien  if (code0 == REG)
660290075Sobrien    {
660390075Sobrien      int reg0 = REGNO (operands[0]);
660490075Sobrien
660590075Sobrien      otherops[0] = gen_rtx_REG (SImode, 1 + reg0);
660690075Sobrien
660790075Sobrien      if (code1 == REG)
660890075Sobrien	{
660990075Sobrien	  int reg1 = REGNO (operands[1]);
661090075Sobrien	  if (reg1 == IP_REGNUM)
661190075Sobrien	    abort ();
661290075Sobrien
661390075Sobrien	  /* Ensure the second source is not overwritten.  */
661490075Sobrien	  if (reg1 == reg0 + (WORDS_BIG_ENDIAN ? -1 : 1))
661590075Sobrien	    output_asm_insn ("mov%?\t%Q0, %Q1\n\tmov%?\t%R0, %R1", operands);
661690075Sobrien	  else
661790075Sobrien	    output_asm_insn ("mov%?\t%R0, %R1\n\tmov%?\t%Q0, %Q1", operands);
661890075Sobrien	}
661990075Sobrien      else if (code1 == CONST_DOUBLE)
662090075Sobrien	{
662190075Sobrien	  if (GET_MODE (operands[1]) == DFmode)
662290075Sobrien	    {
6623117395Skan	      REAL_VALUE_TYPE r;
662490075Sobrien	      long l[2];
662590075Sobrien
6626117395Skan	      REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);
6627117395Skan	      REAL_VALUE_TO_TARGET_DOUBLE (r, l);
662890075Sobrien	      otherops[1] = GEN_INT (l[1]);
662990075Sobrien	      operands[1] = GEN_INT (l[0]);
663090075Sobrien	    }
663190075Sobrien	  else if (GET_MODE (operands[1]) != VOIDmode)
663290075Sobrien	    abort ();
663390075Sobrien	  else if (WORDS_BIG_ENDIAN)
663490075Sobrien	    {
663590075Sobrien	      otherops[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1]));
663690075Sobrien	      operands[1] = GEN_INT (CONST_DOUBLE_HIGH (operands[1]));
663790075Sobrien	    }
663890075Sobrien	  else
663990075Sobrien	    {
664090075Sobrien	      otherops[1] = GEN_INT (CONST_DOUBLE_HIGH (operands[1]));
664190075Sobrien	      operands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1]));
664290075Sobrien	    }
664390075Sobrien
664490075Sobrien	  output_mov_immediate (operands);
664590075Sobrien	  output_mov_immediate (otherops);
664690075Sobrien	}
664790075Sobrien      else if (code1 == CONST_INT)
664890075Sobrien	{
664990075Sobrien#if HOST_BITS_PER_WIDE_INT > 32
665090075Sobrien	  /* If HOST_WIDE_INT is more than 32 bits, the intval tells us
665190075Sobrien	     what the upper word is.  */
665290075Sobrien	  if (WORDS_BIG_ENDIAN)
665390075Sobrien	    {
665490075Sobrien	      otherops[1] = GEN_INT (ARM_SIGN_EXTEND (INTVAL (operands[1])));
665590075Sobrien	      operands[1] = GEN_INT (INTVAL (operands[1]) >> 32);
665690075Sobrien	    }
665790075Sobrien	  else
665890075Sobrien	    {
665990075Sobrien	      otherops[1] = GEN_INT (INTVAL (operands[1]) >> 32);
666090075Sobrien	      operands[1] = GEN_INT (ARM_SIGN_EXTEND (INTVAL (operands[1])));
666190075Sobrien	    }
666290075Sobrien#else
666390075Sobrien	  /* Sign extend the intval into the high-order word.  */
666490075Sobrien	  if (WORDS_BIG_ENDIAN)
666590075Sobrien	    {
666690075Sobrien	      otherops[1] = operands[1];
666790075Sobrien	      operands[1] = (INTVAL (operands[1]) < 0
666890075Sobrien			     ? constm1_rtx : const0_rtx);
666990075Sobrien	    }
667090075Sobrien	  else
667190075Sobrien	    otherops[1] = INTVAL (operands[1]) < 0 ? constm1_rtx : const0_rtx;
667290075Sobrien#endif
667390075Sobrien	  output_mov_immediate (otherops);
667490075Sobrien	  output_mov_immediate (operands);
667590075Sobrien	}
667690075Sobrien      else if (code1 == MEM)
667790075Sobrien	{
667890075Sobrien	  switch (GET_CODE (XEXP (operands[1], 0)))
667990075Sobrien	    {
668090075Sobrien	    case REG:
668190075Sobrien	      output_asm_insn ("ldm%?ia\t%m1, %M0", operands);
668290075Sobrien	      break;
668390075Sobrien
668490075Sobrien  	    case PRE_INC:
668590075Sobrien	      abort (); /* Should never happen now.  */
668690075Sobrien	      break;
668790075Sobrien
668890075Sobrien	    case PRE_DEC:
668990075Sobrien	      output_asm_insn ("ldm%?db\t%m1!, %M0", operands);
669090075Sobrien	      break;
669190075Sobrien
669290075Sobrien	    case POST_INC:
669390075Sobrien	      output_asm_insn ("ldm%?ia\t%m1!, %M0", operands);
669490075Sobrien	      break;
669590075Sobrien
669690075Sobrien	    case POST_DEC:
669790075Sobrien	      abort (); /* Should never happen now.  */
669890075Sobrien	      break;
669990075Sobrien
670090075Sobrien	    case LABEL_REF:
670190075Sobrien	    case CONST:
670290075Sobrien	      output_asm_insn ("adr%?\t%0, %1", operands);
670390075Sobrien	      output_asm_insn ("ldm%?ia\t%0, %M0", operands);
670490075Sobrien	      break;
670590075Sobrien
670690075Sobrien	    default:
670790075Sobrien	      if (arm_add_operand (XEXP (XEXP (operands[1], 0), 1),
670890075Sobrien				   GET_MODE (XEXP (XEXP (operands[1], 0), 1))))
670990075Sobrien		{
671090075Sobrien		  otherops[0] = operands[0];
671190075Sobrien		  otherops[1] = XEXP (XEXP (operands[1], 0), 0);
671290075Sobrien		  otherops[2] = XEXP (XEXP (operands[1], 0), 1);
671390075Sobrien
671490075Sobrien		  if (GET_CODE (XEXP (operands[1], 0)) == PLUS)
671590075Sobrien		    {
671690075Sobrien		      if (GET_CODE (otherops[2]) == CONST_INT)
671790075Sobrien			{
671890075Sobrien			  switch (INTVAL (otherops[2]))
671990075Sobrien			    {
672090075Sobrien			    case -8:
672190075Sobrien			      output_asm_insn ("ldm%?db\t%1, %M0", otherops);
672290075Sobrien			      return "";
672390075Sobrien			    case -4:
672490075Sobrien			      output_asm_insn ("ldm%?da\t%1, %M0", otherops);
672590075Sobrien			      return "";
672690075Sobrien			    case 4:
672790075Sobrien			      output_asm_insn ("ldm%?ib\t%1, %M0", otherops);
672890075Sobrien			      return "";
672990075Sobrien			    }
673090075Sobrien
673190075Sobrien			  if (!(const_ok_for_arm (INTVAL (otherops[2]))))
673290075Sobrien			    output_asm_insn ("sub%?\t%0, %1, #%n2", otherops);
673390075Sobrien			  else
673490075Sobrien			    output_asm_insn ("add%?\t%0, %1, %2", otherops);
673590075Sobrien			}
673690075Sobrien		      else
673790075Sobrien			output_asm_insn ("add%?\t%0, %1, %2", otherops);
673890075Sobrien		    }
673990075Sobrien		  else
674090075Sobrien		    output_asm_insn ("sub%?\t%0, %1, %2", otherops);
674190075Sobrien
674290075Sobrien		  return "ldm%?ia\t%0, %M0";
674390075Sobrien                }
674490075Sobrien              else
674590075Sobrien                {
6746117395Skan		  otherops[1] = adjust_address (operands[1], SImode, 4);
674790075Sobrien		  /* Take care of overlapping base/data reg.  */
674890075Sobrien		  if (reg_mentioned_p (operands[0], operands[1]))
674990075Sobrien		    {
675090075Sobrien		      output_asm_insn ("ldr%?\t%0, %1", otherops);
675190075Sobrien		      output_asm_insn ("ldr%?\t%0, %1", operands);
675290075Sobrien		    }
675390075Sobrien		  else
675490075Sobrien		    {
675590075Sobrien		      output_asm_insn ("ldr%?\t%0, %1", operands);
675690075Sobrien		      output_asm_insn ("ldr%?\t%0, %1", otherops);
675790075Sobrien		    }
675890075Sobrien		}
675990075Sobrien	    }
676090075Sobrien	}
676190075Sobrien      else
676290075Sobrien	abort ();  /* Constraints should prevent this.  */
676390075Sobrien    }
676490075Sobrien  else if (code0 == MEM && code1 == REG)
676590075Sobrien    {
676690075Sobrien      if (REGNO (operands[1]) == IP_REGNUM)
676790075Sobrien	abort ();
676890075Sobrien
676990075Sobrien      switch (GET_CODE (XEXP (operands[0], 0)))
677090075Sobrien        {
677190075Sobrien	case REG:
677290075Sobrien	  output_asm_insn ("stm%?ia\t%m0, %M1", operands);
677390075Sobrien	  break;
677490075Sobrien
677590075Sobrien        case PRE_INC:
677690075Sobrien	  abort (); /* Should never happen now.  */
677790075Sobrien	  break;
677890075Sobrien
677990075Sobrien        case PRE_DEC:
678090075Sobrien	  output_asm_insn ("stm%?db\t%m0!, %M1", operands);
678190075Sobrien	  break;
678290075Sobrien
678390075Sobrien        case POST_INC:
678490075Sobrien	  output_asm_insn ("stm%?ia\t%m0!, %M1", operands);
678590075Sobrien	  break;
678690075Sobrien
678790075Sobrien        case POST_DEC:
678890075Sobrien	  abort (); /* Should never happen now.  */
678990075Sobrien	  break;
679090075Sobrien
679190075Sobrien	case PLUS:
679290075Sobrien	  if (GET_CODE (XEXP (XEXP (operands[0], 0), 1)) == CONST_INT)
679390075Sobrien	    {
679490075Sobrien	      switch (INTVAL (XEXP (XEXP (operands[0], 0), 1)))
679590075Sobrien		{
679690075Sobrien		case -8:
679790075Sobrien		  output_asm_insn ("stm%?db\t%m0, %M1", operands);
679890075Sobrien		  return "";
679990075Sobrien
680090075Sobrien		case -4:
680190075Sobrien		  output_asm_insn ("stm%?da\t%m0, %M1", operands);
680290075Sobrien		  return "";
680390075Sobrien
680490075Sobrien		case 4:
680590075Sobrien		  output_asm_insn ("stm%?ib\t%m0, %M1", operands);
680690075Sobrien		  return "";
680790075Sobrien		}
680890075Sobrien	    }
680990075Sobrien	  /* Fall through */
681090075Sobrien
681190075Sobrien        default:
6812117395Skan	  otherops[0] = adjust_address (operands[0], SImode, 4);
681390075Sobrien	  otherops[1] = gen_rtx_REG (SImode, 1 + REGNO (operands[1]));
681490075Sobrien	  output_asm_insn ("str%?\t%1, %0", operands);
681590075Sobrien	  output_asm_insn ("str%?\t%1, %0", otherops);
681690075Sobrien	}
681790075Sobrien    }
681890075Sobrien  else
681990075Sobrien    /* Constraints should prevent this.  */
682090075Sobrien    abort ();
682190075Sobrien
682290075Sobrien  return "";
682390075Sobrien}
682490075Sobrien
682590075Sobrien
682690075Sobrien/* Output an arbitrary MOV reg, #n.
682790075Sobrien   OPERANDS[0] is a register.  OPERANDS[1] is a const_int.  */
682890075Sobrien
682990075Sobrienconst char *
683090075Sobrienoutput_mov_immediate (operands)
683190075Sobrien     rtx * operands;
683290075Sobrien{
683390075Sobrien  HOST_WIDE_INT n = INTVAL (operands[1]);
683490075Sobrien
683590075Sobrien  /* Try to use one MOV.  */
683690075Sobrien  if (const_ok_for_arm (n))
683790075Sobrien    output_asm_insn ("mov%?\t%0, %1", operands);
683890075Sobrien
683990075Sobrien  /* Try to use one MVN.  */
684090075Sobrien  else if (const_ok_for_arm (~n))
684190075Sobrien    {
684290075Sobrien      operands[1] = GEN_INT (~n);
684390075Sobrien      output_asm_insn ("mvn%?\t%0, %1", operands);
684490075Sobrien    }
684590075Sobrien  else
684690075Sobrien    {
684790075Sobrien      int n_ones = 0;
684890075Sobrien      int i;
684990075Sobrien
685090075Sobrien      /* If all else fails, make it out of ORRs or BICs as appropriate.  */
685190075Sobrien      for (i = 0; i < 32; i ++)
685290075Sobrien	if (n & 1 << i)
685390075Sobrien	  n_ones ++;
685490075Sobrien
685590075Sobrien      if (n_ones > 16)  /* Shorter to use MVN with BIC in this case.  */
685690075Sobrien	output_multi_immediate (operands, "mvn%?\t%0, %1", "bic%?\t%0, %0, %1", 1, ~ n);
685790075Sobrien      else
685890075Sobrien	output_multi_immediate (operands, "mov%?\t%0, %1", "orr%?\t%0, %0, %1", 1, n);
685990075Sobrien    }
686090075Sobrien
686190075Sobrien  return "";
686290075Sobrien}
686390075Sobrien
686490075Sobrien/* Output an ADD r, s, #n where n may be too big for one instruction.
686590075Sobrien   If adding zero to one register, output nothing.  */
686690075Sobrien
686790075Sobrienconst char *
686890075Sobrienoutput_add_immediate (operands)
686990075Sobrien     rtx * operands;
687090075Sobrien{
687190075Sobrien  HOST_WIDE_INT n = INTVAL (operands[2]);
687290075Sobrien
687390075Sobrien  if (n != 0 || REGNO (operands[0]) != REGNO (operands[1]))
687490075Sobrien    {
687590075Sobrien      if (n < 0)
687690075Sobrien	output_multi_immediate (operands,
687790075Sobrien				"sub%?\t%0, %1, %2", "sub%?\t%0, %0, %2", 2,
687890075Sobrien				-n);
687990075Sobrien      else
688090075Sobrien	output_multi_immediate (operands,
688190075Sobrien				"add%?\t%0, %1, %2", "add%?\t%0, %0, %2", 2,
688290075Sobrien				n);
688390075Sobrien    }
688490075Sobrien
688590075Sobrien  return "";
688690075Sobrien}
688790075Sobrien
688890075Sobrien/* Output a multiple immediate operation.
688990075Sobrien   OPERANDS is the vector of operands referred to in the output patterns.
689090075Sobrien   INSTR1 is the output pattern to use for the first constant.
689190075Sobrien   INSTR2 is the output pattern to use for subsequent constants.
689290075Sobrien   IMMED_OP is the index of the constant slot in OPERANDS.
689390075Sobrien   N is the constant value.  */
689490075Sobrien
689590075Sobrienstatic const char *
689690075Sobrienoutput_multi_immediate (operands, instr1, instr2, immed_op, n)
689790075Sobrien     rtx * operands;
689890075Sobrien     const char * instr1;
689990075Sobrien     const char * instr2;
690090075Sobrien     int immed_op;
690190075Sobrien     HOST_WIDE_INT n;
690290075Sobrien{
690390075Sobrien#if HOST_BITS_PER_WIDE_INT > 32
690490075Sobrien  n &= 0xffffffff;
690590075Sobrien#endif
690690075Sobrien
690790075Sobrien  if (n == 0)
690890075Sobrien    {
690990075Sobrien      /* Quick and easy output.  */
691090075Sobrien      operands[immed_op] = const0_rtx;
691190075Sobrien      output_asm_insn (instr1, operands);
691290075Sobrien    }
691390075Sobrien  else
691490075Sobrien    {
691590075Sobrien      int i;
691690075Sobrien      const char * instr = instr1;
691790075Sobrien
691890075Sobrien      /* Note that n is never zero here (which would give no output).  */
691990075Sobrien      for (i = 0; i < 32; i += 2)
692090075Sobrien	{
692190075Sobrien	  if (n & (3 << i))
692290075Sobrien	    {
692390075Sobrien	      operands[immed_op] = GEN_INT (n & (255 << i));
692490075Sobrien	      output_asm_insn (instr, operands);
692590075Sobrien	      instr = instr2;
692690075Sobrien	      i += 6;
692790075Sobrien	    }
692890075Sobrien	}
692990075Sobrien    }
693090075Sobrien
693190075Sobrien  return "";
693290075Sobrien}
693390075Sobrien
693490075Sobrien/* Return the appropriate ARM instruction for the operation code.
693590075Sobrien   The returned result should not be overwritten.  OP is the rtx of the
693690075Sobrien   operation.  SHIFT_FIRST_ARG is TRUE if the first argument of the operator
693790075Sobrien   was shifted.  */
693890075Sobrien
693990075Sobrienconst char *
694090075Sobrienarithmetic_instr (op, shift_first_arg)
694190075Sobrien     rtx op;
694290075Sobrien     int shift_first_arg;
694390075Sobrien{
694490075Sobrien  switch (GET_CODE (op))
694590075Sobrien    {
694690075Sobrien    case PLUS:
694790075Sobrien      return "add";
694890075Sobrien
694990075Sobrien    case MINUS:
695090075Sobrien      return shift_first_arg ? "rsb" : "sub";
695190075Sobrien
695290075Sobrien    case IOR:
695390075Sobrien      return "orr";
695490075Sobrien
695590075Sobrien    case XOR:
695690075Sobrien      return "eor";
695790075Sobrien
695890075Sobrien    case AND:
695990075Sobrien      return "and";
696090075Sobrien
696190075Sobrien    default:
696290075Sobrien      abort ();
696390075Sobrien    }
696490075Sobrien}
696590075Sobrien
696690075Sobrien/* Ensure valid constant shifts and return the appropriate shift mnemonic
696790075Sobrien   for the operation code.  The returned result should not be overwritten.
696890075Sobrien   OP is the rtx code of the shift.
696990075Sobrien   On exit, *AMOUNTP will be -1 if the shift is by a register, or a constant
697090075Sobrien   shift.  */
697190075Sobrien
697290075Sobrienstatic const char *
697390075Sobrienshift_op (op, amountp)
697490075Sobrien     rtx op;
697590075Sobrien     HOST_WIDE_INT *amountp;
697690075Sobrien{
697790075Sobrien  const char * mnem;
697890075Sobrien  enum rtx_code code = GET_CODE (op);
697990075Sobrien
698090075Sobrien  if (GET_CODE (XEXP (op, 1)) == REG || GET_CODE (XEXP (op, 1)) == SUBREG)
698190075Sobrien    *amountp = -1;
698290075Sobrien  else if (GET_CODE (XEXP (op, 1)) == CONST_INT)
698390075Sobrien    *amountp = INTVAL (XEXP (op, 1));
698490075Sobrien  else
698590075Sobrien    abort ();
698690075Sobrien
698790075Sobrien  switch (code)
698890075Sobrien    {
698990075Sobrien    case ASHIFT:
699090075Sobrien      mnem = "asl";
699190075Sobrien      break;
699290075Sobrien
699390075Sobrien    case ASHIFTRT:
699490075Sobrien      mnem = "asr";
699590075Sobrien      break;
699690075Sobrien
699790075Sobrien    case LSHIFTRT:
699890075Sobrien      mnem = "lsr";
699990075Sobrien      break;
700090075Sobrien
700190075Sobrien    case ROTATERT:
700290075Sobrien      mnem = "ror";
700390075Sobrien      break;
700490075Sobrien
700590075Sobrien    case MULT:
700690075Sobrien      /* We never have to worry about the amount being other than a
700790075Sobrien	 power of 2, since this case can never be reloaded from a reg.  */
700890075Sobrien      if (*amountp != -1)
700990075Sobrien	*amountp = int_log2 (*amountp);
701090075Sobrien      else
701190075Sobrien	abort ();
701290075Sobrien      return "asl";
701390075Sobrien
701490075Sobrien    default:
701590075Sobrien      abort ();
701690075Sobrien    }
701790075Sobrien
701890075Sobrien  if (*amountp != -1)
701990075Sobrien    {
702090075Sobrien      /* This is not 100% correct, but follows from the desire to merge
702190075Sobrien	 multiplication by a power of 2 with the recognizer for a
702290075Sobrien	 shift.  >=32 is not a valid shift for "asl", so we must try and
702390075Sobrien	 output a shift that produces the correct arithmetical result.
702490075Sobrien	 Using lsr #32 is identical except for the fact that the carry bit
702590075Sobrien	 is not set correctly if we set the flags; but we never use the
702690075Sobrien	 carry bit from such an operation, so we can ignore that.  */
702790075Sobrien      if (code == ROTATERT)
702890075Sobrien	/* Rotate is just modulo 32.  */
702990075Sobrien	*amountp &= 31;
703090075Sobrien      else if (*amountp != (*amountp & 31))
703190075Sobrien	{
703290075Sobrien	  if (code == ASHIFT)
703390075Sobrien	    mnem = "lsr";
703490075Sobrien	  *amountp = 32;
703590075Sobrien	}
703690075Sobrien
703790075Sobrien      /* Shifts of 0 are no-ops.  */
703890075Sobrien      if (*amountp == 0)
703990075Sobrien	return NULL;
704090075Sobrien    }
704190075Sobrien
704290075Sobrien  return mnem;
704390075Sobrien}
704490075Sobrien
704590075Sobrien/* Obtain the shift from the POWER of two.  */
704690075Sobrien
704790075Sobrienstatic HOST_WIDE_INT
704890075Sobrienint_log2 (power)
704990075Sobrien     HOST_WIDE_INT power;
705090075Sobrien{
705190075Sobrien  HOST_WIDE_INT shift = 0;
705290075Sobrien
705390075Sobrien  while ((((HOST_WIDE_INT) 1 << shift) & power) == 0)
705490075Sobrien    {
705590075Sobrien      if (shift > 31)
705690075Sobrien	abort ();
705790075Sobrien      shift ++;
705890075Sobrien    }
705990075Sobrien
706090075Sobrien  return shift;
706190075Sobrien}
706290075Sobrien
706390075Sobrien/* Output a .ascii pseudo-op, keeping track of lengths.  This is because
706490075Sobrien   /bin/as is horribly restrictive.  */
706590075Sobrien#define MAX_ASCII_LEN 51
706690075Sobrien
706790075Sobrienvoid
706890075Sobrienoutput_ascii_pseudo_op (stream, p, len)
706990075Sobrien     FILE * stream;
707090075Sobrien     const unsigned char * p;
707190075Sobrien     int len;
707290075Sobrien{
707390075Sobrien  int i;
707490075Sobrien  int len_so_far = 0;
707590075Sobrien
707690075Sobrien  fputs ("\t.ascii\t\"", stream);
707790075Sobrien
707890075Sobrien  for (i = 0; i < len; i++)
707990075Sobrien    {
708090075Sobrien      int c = p[i];
708190075Sobrien
708290075Sobrien      if (len_so_far >= MAX_ASCII_LEN)
708390075Sobrien	{
708490075Sobrien	  fputs ("\"\n\t.ascii\t\"", stream);
708590075Sobrien	  len_so_far = 0;
708690075Sobrien	}
708790075Sobrien
708890075Sobrien      switch (c)
708990075Sobrien	{
709090075Sobrien	case TARGET_TAB:
709190075Sobrien	  fputs ("\\t", stream);
709290075Sobrien	  len_so_far += 2;
709390075Sobrien	  break;
709490075Sobrien
709590075Sobrien	case TARGET_FF:
709690075Sobrien	  fputs ("\\f", stream);
709790075Sobrien	  len_so_far += 2;
709890075Sobrien	  break;
709990075Sobrien
710090075Sobrien	case TARGET_BS:
710190075Sobrien	  fputs ("\\b", stream);
710290075Sobrien	  len_so_far += 2;
710390075Sobrien	  break;
710490075Sobrien
710590075Sobrien	case TARGET_CR:
710690075Sobrien	  fputs ("\\r", stream);
710790075Sobrien	  len_so_far += 2;
710890075Sobrien	  break;
710990075Sobrien
711090075Sobrien	case TARGET_NEWLINE:
711190075Sobrien	  fputs ("\\n", stream);
711290075Sobrien	  c = p [i + 1];
711390075Sobrien	  if ((c >= ' ' && c <= '~')
711490075Sobrien	      || c == TARGET_TAB)
711590075Sobrien	    /* This is a good place for a line break.  */
711690075Sobrien	    len_so_far = MAX_ASCII_LEN;
711790075Sobrien	  else
711890075Sobrien	    len_so_far += 2;
711990075Sobrien	  break;
712090075Sobrien
712190075Sobrien	case '\"':
712290075Sobrien	case '\\':
712390075Sobrien	  putc ('\\', stream);
712490075Sobrien	  len_so_far++;
712590075Sobrien	  /* drop through.  */
712690075Sobrien
712790075Sobrien	default:
712890075Sobrien	  if (c >= ' ' && c <= '~')
712990075Sobrien	    {
713090075Sobrien	      putc (c, stream);
713190075Sobrien	      len_so_far++;
713290075Sobrien	    }
713390075Sobrien	  else
713490075Sobrien	    {
713590075Sobrien	      fprintf (stream, "\\%03o", c);
713690075Sobrien	      len_so_far += 4;
713790075Sobrien	    }
713890075Sobrien	  break;
713990075Sobrien	}
714090075Sobrien    }
714190075Sobrien
714290075Sobrien  fputs ("\"\n", stream);
714390075Sobrien}
714490075Sobrien
714590075Sobrien/* Compute the register sabe mask for registers 0 through 12
714690075Sobrien   inclusive.  This code is used by both arm_compute_save_reg_mask
714790075Sobrien   and arm_compute_initial_elimination_offset.  */
714890075Sobrien
714990075Sobrienstatic unsigned long
715090075Sobrienarm_compute_save_reg0_reg12_mask ()
715190075Sobrien{
715290075Sobrien  unsigned long func_type = arm_current_func_type ();
715390075Sobrien  unsigned int save_reg_mask = 0;
715490075Sobrien  unsigned int reg;
715590075Sobrien
715690075Sobrien  if (IS_INTERRUPT (func_type))
715790075Sobrien    {
715890075Sobrien      unsigned int max_reg;
715990075Sobrien      /* Interrupt functions must not corrupt any registers,
716090075Sobrien	 even call clobbered ones.  If this is a leaf function
716190075Sobrien	 we can just examine the registers used by the RTL, but
716290075Sobrien	 otherwise we have to assume that whatever function is
716390075Sobrien	 called might clobber anything, and so we have to save
716490075Sobrien	 all the call-clobbered registers as well.  */
716590075Sobrien      if (ARM_FUNC_TYPE (func_type) == ARM_FT_FIQ)
716690075Sobrien	/* FIQ handlers have registers r8 - r12 banked, so
716790075Sobrien	   we only need to check r0 - r7, Normal ISRs only
716890075Sobrien	   bank r14 and r15, so we must check up to r12.
716990075Sobrien	   r13 is the stack pointer which is always preserved,
717090075Sobrien	   so we do not need to consider it here.  */
717190075Sobrien	max_reg = 7;
717290075Sobrien      else
717390075Sobrien	max_reg = 12;
717490075Sobrien
717590075Sobrien      for (reg = 0; reg <= max_reg; reg++)
717690075Sobrien	if (regs_ever_live[reg]
717790075Sobrien	    || (! current_function_is_leaf && call_used_regs [reg]))
717890075Sobrien	  save_reg_mask |= (1 << reg);
717990075Sobrien    }
718090075Sobrien  else
718190075Sobrien    {
718290075Sobrien      /* In the normal case we only need to save those registers
718390075Sobrien	 which are call saved and which are used by this function.  */
718490075Sobrien      for (reg = 0; reg <= 10; reg++)
718590075Sobrien	if (regs_ever_live[reg] && ! call_used_regs [reg])
718690075Sobrien	  save_reg_mask |= (1 << reg);
718790075Sobrien
718890075Sobrien      /* Handle the frame pointer as a special case.  */
718990075Sobrien      if (! TARGET_APCS_FRAME
719090075Sobrien	  && ! frame_pointer_needed
719190075Sobrien	  && regs_ever_live[HARD_FRAME_POINTER_REGNUM]
719290075Sobrien	  && ! call_used_regs[HARD_FRAME_POINTER_REGNUM])
719390075Sobrien	save_reg_mask |= 1 << HARD_FRAME_POINTER_REGNUM;
719490075Sobrien
719590075Sobrien      /* If we aren't loading the PIC register,
719690075Sobrien	 don't stack it even though it may be live.  */
719790075Sobrien      if (flag_pic
719890075Sobrien	  && ! TARGET_SINGLE_PIC_BASE
719990075Sobrien	  && regs_ever_live[PIC_OFFSET_TABLE_REGNUM])
720090075Sobrien	save_reg_mask |= 1 << PIC_OFFSET_TABLE_REGNUM;
720190075Sobrien    }
720290075Sobrien
720390075Sobrien  return save_reg_mask;
720490075Sobrien}
720590075Sobrien
720690075Sobrien/* Compute a bit mask of which registers need to be
720790075Sobrien   saved on the stack for the current function.  */
720890075Sobrien
720990075Sobrienstatic unsigned long
721090075Sobrienarm_compute_save_reg_mask ()
721190075Sobrien{
721290075Sobrien  unsigned int save_reg_mask = 0;
721390075Sobrien  unsigned long func_type = arm_current_func_type ();
721490075Sobrien
721590075Sobrien  if (IS_NAKED (func_type))
721690075Sobrien    /* This should never really happen.  */
721790075Sobrien    return 0;
721890075Sobrien
721990075Sobrien  /* If we are creating a stack frame, then we must save the frame pointer,
722090075Sobrien     IP (which will hold the old stack pointer), LR and the PC.  */
722190075Sobrien  if (frame_pointer_needed)
722290075Sobrien    save_reg_mask |=
722390075Sobrien      (1 << ARM_HARD_FRAME_POINTER_REGNUM)
722490075Sobrien      | (1 << IP_REGNUM)
722590075Sobrien      | (1 << LR_REGNUM)
722690075Sobrien      | (1 << PC_REGNUM);
722790075Sobrien
722890075Sobrien  /* Volatile functions do not return, so there
722990075Sobrien     is no need to save any other registers.  */
723090075Sobrien  if (IS_VOLATILE (func_type))
723190075Sobrien    return save_reg_mask;
723290075Sobrien
723390075Sobrien  save_reg_mask |= arm_compute_save_reg0_reg12_mask ();
723490075Sobrien
723590075Sobrien  /* Decide if we need to save the link register.
723690075Sobrien     Interrupt routines have their own banked link register,
723790075Sobrien     so they never need to save it.
723896263Sobrien     Otherwise if we do not use the link register we do not need to save
723990075Sobrien     it.  If we are pushing other registers onto the stack however, we
724090075Sobrien     can save an instruction in the epilogue by pushing the link register
724190075Sobrien     now and then popping it back into the PC.  This incurs extra memory
724290075Sobrien     accesses though, so we only do it when optimising for size, and only
724390075Sobrien     if we know that we will not need a fancy return sequence.  */
724496263Sobrien  if (regs_ever_live [LR_REGNUM]
724590075Sobrien	  || (save_reg_mask
724690075Sobrien	      && optimize_size
724796263Sobrien	      && ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL))
724890075Sobrien    save_reg_mask |= 1 << LR_REGNUM;
724990075Sobrien
725090075Sobrien  if (cfun->machine->lr_save_eliminated)
725190075Sobrien    save_reg_mask &= ~ (1 << LR_REGNUM);
725290075Sobrien
725390075Sobrien  return save_reg_mask;
725490075Sobrien}
725590075Sobrien
725690075Sobrien/* Generate a function exit sequence.  If REALLY_RETURN is true, then do
725790075Sobrien   everything bar the final return instruction.  */
725890075Sobrien
725990075Sobrienconst char *
726090075Sobrienoutput_return_instruction (operand, really_return, reverse)
726190075Sobrien     rtx operand;
726290075Sobrien     int really_return;
726390075Sobrien     int reverse;
726490075Sobrien{
726590075Sobrien  char conditional[10];
726690075Sobrien  char instr[100];
726790075Sobrien  int reg;
726890075Sobrien  unsigned long live_regs_mask;
726990075Sobrien  unsigned long func_type;
7270117395Skan
727190075Sobrien  func_type = arm_current_func_type ();
727290075Sobrien
727390075Sobrien  if (IS_NAKED (func_type))
727490075Sobrien    return "";
727590075Sobrien
727690075Sobrien  if (IS_VOLATILE (func_type) && TARGET_ABORT_NORETURN)
727790075Sobrien    {
727890075Sobrien      /* If this function was declared non-returning, and we have found a tail
727990075Sobrien	 call, then we have to trust that the called function won't return.  */
728090075Sobrien      if (really_return)
728190075Sobrien	{
728290075Sobrien	  rtx ops[2];
728390075Sobrien
728490075Sobrien	  /* Otherwise, trap an attempted return by aborting.  */
728590075Sobrien	  ops[0] = operand;
728690075Sobrien	  ops[1] = gen_rtx_SYMBOL_REF (Pmode, NEED_PLT_RELOC ? "abort(PLT)"
728790075Sobrien				       : "abort");
728890075Sobrien	  assemble_external_libcall (ops[1]);
728990075Sobrien	  output_asm_insn (reverse ? "bl%D0\t%a1" : "bl%d0\t%a1", ops);
729090075Sobrien	}
729190075Sobrien
729290075Sobrien      return "";
729390075Sobrien    }
729490075Sobrien
729590075Sobrien  if (current_function_calls_alloca && !really_return)
729690075Sobrien    abort ();
729790075Sobrien
729890075Sobrien  sprintf (conditional, "%%?%%%c0", reverse ? 'D' : 'd');
729990075Sobrien
730090075Sobrien  return_used_this_function = 1;
730190075Sobrien
730290075Sobrien  live_regs_mask = arm_compute_save_reg_mask ();
730390075Sobrien
730496263Sobrien  if (live_regs_mask)
730590075Sobrien    {
730696263Sobrien      const char * return_reg;
730796263Sobrien
730896263Sobrien      /* If we do not have any special requirements for function exit
730996263Sobrien	 (eg interworking, or ISR) then we can load the return address
731096263Sobrien	 directly into the PC.  Otherwise we must load it into LR.  */
731196263Sobrien      if (really_return
731296263Sobrien	  && ! TARGET_INTERWORK)
731396263Sobrien	return_reg = reg_names[PC_REGNUM];
731490075Sobrien      else
731596263Sobrien	return_reg = reg_names[LR_REGNUM];
731696263Sobrien
731790075Sobrien      if ((live_regs_mask & (1 << IP_REGNUM)) == (1 << IP_REGNUM))
731890075Sobrien	/* There are two possible reasons for the IP register being saved.
731990075Sobrien	   Either a stack frame was created, in which case IP contains the
732090075Sobrien	   old stack pointer, or an ISR routine corrupted it.  If this in an
732190075Sobrien	   ISR routine then just restore IP, otherwise restore IP into SP.  */
732290075Sobrien	if (! IS_INTERRUPT (func_type))
732390075Sobrien	  {
732490075Sobrien	    live_regs_mask &= ~ (1 << IP_REGNUM);
732590075Sobrien	    live_regs_mask |=   (1 << SP_REGNUM);
732690075Sobrien	  }
732790075Sobrien
732896263Sobrien      /* On some ARM architectures it is faster to use LDR rather than
732996263Sobrien	 LDM to load a single register.  On other architectures, the
733096263Sobrien	 cost is the same.  In 26 bit mode, or for exception handlers,
733196263Sobrien	 we have to use LDM to load the PC so that the CPSR is also
733296263Sobrien	 restored.  */
733396263Sobrien      for (reg = 0; reg <= LAST_ARM_REGNUM; reg++)
733490075Sobrien	{
733596263Sobrien	  if (live_regs_mask == (unsigned int)(1 << reg))
733696263Sobrien	    break;
733790075Sobrien	}
733896263Sobrien      if (reg <= LAST_ARM_REGNUM
733996263Sobrien	  && (reg != LR_REGNUM
734096263Sobrien	      || ! really_return
734196263Sobrien	      || (TARGET_APCS_32 && ! IS_INTERRUPT (func_type))))
734296263Sobrien	{
734396263Sobrien	  sprintf (instr, "ldr%s\t%%|%s, [%%|sp], #4", conditional,
734496263Sobrien		   (reg == LR_REGNUM) ? return_reg : reg_names[reg]);
734596263Sobrien	}
734690075Sobrien      else
734790075Sobrien	{
734896263Sobrien	  char *p;
734996263Sobrien	  int first = 1;
735090075Sobrien
735196263Sobrien	  /* Generate the load multiple instruction to restore the registers.  */
735296263Sobrien	  if (frame_pointer_needed)
735396263Sobrien	    sprintf (instr, "ldm%sea\t%%|fp, {", conditional);
7354117395Skan	  else if (live_regs_mask & (1 << SP_REGNUM))
7355117395Skan	    sprintf (instr, "ldm%sfd\t%%|sp, {", conditional);
735690075Sobrien	  else
735796263Sobrien	    sprintf (instr, "ldm%sfd\t%%|sp!, {", conditional);
735890075Sobrien
735996263Sobrien	  p = instr + strlen (instr);
736090075Sobrien
736196263Sobrien	  for (reg = 0; reg <= SP_REGNUM; reg++)
736296263Sobrien	    if (live_regs_mask & (1 << reg))
736396263Sobrien	      {
736496263Sobrien		int l = strlen (reg_names[reg]);
736590075Sobrien
736696263Sobrien		if (first)
736796263Sobrien		  first = 0;
736896263Sobrien		else
736996263Sobrien		  {
737096263Sobrien		    memcpy (p, ", ", 2);
737196263Sobrien		    p += 2;
737296263Sobrien		  }
737390075Sobrien
737496263Sobrien		memcpy (p, "%|", 2);
737596263Sobrien		memcpy (p + 2, reg_names[reg], l);
737696263Sobrien		p += l + 2;
737796263Sobrien	      }
737896263Sobrien
737996263Sobrien	  if (live_regs_mask & (1 << LR_REGNUM))
738096263Sobrien	    {
738196263Sobrien	      int l = strlen (return_reg);
738290075Sobrien
738396263Sobrien	      if (! first)
738490075Sobrien		{
738596263Sobrien		  memcpy (p, ", ", 2);
738696263Sobrien		  p += 2;
738796263Sobrien		}
738890075Sobrien
738996263Sobrien	      memcpy (p, "%|", 2);
739096263Sobrien	      memcpy (p + 2, return_reg, l);
739196263Sobrien	      strcpy (p + 2 + l, ((TARGET_APCS_32
739296263Sobrien				   && !IS_INTERRUPT (func_type))
739396263Sobrien				  || !really_return)
739496263Sobrien		      ? "}" : "}^");
739590075Sobrien	    }
739696263Sobrien	  else
739796263Sobrien	    strcpy (p, "}");
739890075Sobrien	}
739996263Sobrien
740096263Sobrien      output_asm_insn (instr, & operand);
740196263Sobrien
740296263Sobrien      /* See if we need to generate an extra instruction to
740396263Sobrien	 perform the actual function return.  */
740496263Sobrien      if (really_return
740596263Sobrien	  && func_type != ARM_FT_INTERWORKED
740696263Sobrien	  && (live_regs_mask & (1 << LR_REGNUM)) != 0)
740796263Sobrien	{
740896263Sobrien	  /* The return has already been handled
740996263Sobrien	     by loading the LR into the PC.  */
741096263Sobrien	  really_return = 0;
741196263Sobrien	}
741290075Sobrien    }
7413117395Skan
741496263Sobrien  if (really_return)
741590075Sobrien    {
741690075Sobrien      switch ((int) ARM_FUNC_TYPE (func_type))
741790075Sobrien	{
741890075Sobrien	case ARM_FT_ISR:
741990075Sobrien	case ARM_FT_FIQ:
742090075Sobrien	  sprintf (instr, "sub%ss\t%%|pc, %%|lr, #4", conditional);
742190075Sobrien	  break;
742290075Sobrien
742390075Sobrien	case ARM_FT_INTERWORKED:
742490075Sobrien	  sprintf (instr, "bx%s\t%%|lr", conditional);
742590075Sobrien	  break;
742690075Sobrien
742790075Sobrien	case ARM_FT_EXCEPTION:
742890075Sobrien	  sprintf (instr, "mov%ss\t%%|pc, %%|lr", conditional);
742990075Sobrien	  break;
743090075Sobrien
743190075Sobrien	default:
743296263Sobrien	  /* ARMv5 implementations always provide BX, so interworking
743396263Sobrien	     is the default unless APCS-26 is in use.  */
743496263Sobrien	  if ((insn_flags & FL_ARCH5) != 0 && TARGET_APCS_32)
743596263Sobrien	    sprintf (instr, "bx%s\t%%|lr", conditional);
743696263Sobrien	  else
743796263Sobrien	    sprintf (instr, "mov%s%s\t%%|pc, %%|lr",
743896263Sobrien		     conditional, TARGET_APCS_32 ? "" : "s");
743990075Sobrien	  break;
744090075Sobrien	}
744196263Sobrien
744296263Sobrien      output_asm_insn (instr, & operand);
744390075Sobrien    }
744490075Sobrien
744590075Sobrien  return "";
744690075Sobrien}
744790075Sobrien
744890075Sobrien/* Write the function name into the code section, directly preceding
744990075Sobrien   the function prologue.
745090075Sobrien
745190075Sobrien   Code will be output similar to this:
745290075Sobrien     t0
745390075Sobrien	 .ascii "arm_poke_function_name", 0
745490075Sobrien	 .align
745590075Sobrien     t1
745690075Sobrien	 .word 0xff000000 + (t1 - t0)
745790075Sobrien     arm_poke_function_name
745890075Sobrien	 mov     ip, sp
745990075Sobrien	 stmfd   sp!, {fp, ip, lr, pc}
746090075Sobrien	 sub     fp, ip, #4
746190075Sobrien
746290075Sobrien   When performing a stack backtrace, code can inspect the value
746390075Sobrien   of 'pc' stored at 'fp' + 0.  If the trace function then looks
746490075Sobrien   at location pc - 12 and the top 8 bits are set, then we know
746590075Sobrien   that there is a function name embedded immediately preceding this
746690075Sobrien   location and has length ((pc[-3]) & 0xff000000).
746790075Sobrien
746890075Sobrien   We assume that pc is declared as a pointer to an unsigned long.
746990075Sobrien
747090075Sobrien   It is of no benefit to output the function name if we are assembling
747190075Sobrien   a leaf function.  These function types will not contain a stack
747290075Sobrien   backtrace structure, therefore it is not possible to determine the
747390075Sobrien   function name.  */
747490075Sobrien
747590075Sobrienvoid
747690075Sobrienarm_poke_function_name (stream, name)
747790075Sobrien   FILE * stream;
747890075Sobrien   const char * name;
747990075Sobrien{
748090075Sobrien  unsigned long alignlength;
748190075Sobrien  unsigned long length;
748290075Sobrien  rtx           x;
748390075Sobrien
748490075Sobrien  length      = strlen (name) + 1;
748590075Sobrien  alignlength = ROUND_UP (length);
748690075Sobrien
748790075Sobrien  ASM_OUTPUT_ASCII (stream, name, length);
748890075Sobrien  ASM_OUTPUT_ALIGN (stream, 2);
748990075Sobrien  x = GEN_INT ((unsigned HOST_WIDE_INT) 0xff000000 + alignlength);
749090075Sobrien  assemble_aligned_integer (UNITS_PER_WORD, x);
749190075Sobrien}
749290075Sobrien
749390075Sobrien/* Place some comments into the assembler stream
749490075Sobrien   describing the current function.  */
749590075Sobrien
749690075Sobrienstatic void
749790075Sobrienarm_output_function_prologue (f, frame_size)
749890075Sobrien     FILE * f;
749990075Sobrien     HOST_WIDE_INT frame_size;
750090075Sobrien{
750190075Sobrien  unsigned long func_type;
750290075Sobrien
750390075Sobrien  if (!TARGET_ARM)
750490075Sobrien    {
750590075Sobrien      thumb_output_function_prologue (f, frame_size);
750690075Sobrien      return;
750790075Sobrien    }
750890075Sobrien
750990075Sobrien  /* Sanity check.  */
751090075Sobrien  if (arm_ccfsm_state || arm_target_insn)
751190075Sobrien    abort ();
751290075Sobrien
751390075Sobrien  func_type = arm_current_func_type ();
751490075Sobrien
751590075Sobrien  switch ((int) ARM_FUNC_TYPE (func_type))
751690075Sobrien    {
751790075Sobrien    default:
751890075Sobrien    case ARM_FT_NORMAL:
751990075Sobrien      break;
752090075Sobrien    case ARM_FT_INTERWORKED:
752190075Sobrien      asm_fprintf (f, "\t%@ Function supports interworking.\n");
752290075Sobrien      break;
752390075Sobrien    case ARM_FT_EXCEPTION_HANDLER:
752490075Sobrien      asm_fprintf (f, "\t%@ C++ Exception Handler.\n");
752590075Sobrien      break;
752690075Sobrien    case ARM_FT_ISR:
752790075Sobrien      asm_fprintf (f, "\t%@ Interrupt Service Routine.\n");
752890075Sobrien      break;
752990075Sobrien    case ARM_FT_FIQ:
753090075Sobrien      asm_fprintf (f, "\t%@ Fast Interrupt Service Routine.\n");
753190075Sobrien      break;
753290075Sobrien    case ARM_FT_EXCEPTION:
753390075Sobrien      asm_fprintf (f, "\t%@ ARM Exception Handler.\n");
753490075Sobrien      break;
753590075Sobrien    }
753690075Sobrien
753790075Sobrien  if (IS_NAKED (func_type))
753890075Sobrien    asm_fprintf (f, "\t%@ Naked Function: prologue and epilogue provided by programmer.\n");
753990075Sobrien
754090075Sobrien  if (IS_VOLATILE (func_type))
754190075Sobrien    asm_fprintf (f, "\t%@ Volatile: function does not return.\n");
754290075Sobrien
754390075Sobrien  if (IS_NESTED (func_type))
754490075Sobrien    asm_fprintf (f, "\t%@ Nested: function declared inside another function.\n");
754590075Sobrien
754690075Sobrien  asm_fprintf (f, "\t%@ args = %d, pretend = %d, frame = %d\n",
754790075Sobrien	       current_function_args_size,
754890075Sobrien	       current_function_pretend_args_size, frame_size);
754990075Sobrien
755096263Sobrien  asm_fprintf (f, "\t%@ frame_needed = %d, uses_anonymous_args = %d\n",
755190075Sobrien	       frame_pointer_needed,
755296263Sobrien	       cfun->machine->uses_anonymous_args);
755390075Sobrien
755490075Sobrien  if (cfun->machine->lr_save_eliminated)
755590075Sobrien    asm_fprintf (f, "\t%@ link register save eliminated.\n");
755690075Sobrien
755790075Sobrien#ifdef AOF_ASSEMBLER
755890075Sobrien  if (flag_pic)
755990075Sobrien    asm_fprintf (f, "\tmov\t%r, %r\n", IP_REGNUM, PIC_OFFSET_TABLE_REGNUM);
756090075Sobrien#endif
756190075Sobrien
756290075Sobrien  return_used_this_function = 0;
756390075Sobrien}
756490075Sobrien
756590075Sobrienconst char *
756690075Sobrienarm_output_epilogue (really_return)
756790075Sobrien     int really_return;
756890075Sobrien{
756990075Sobrien  int reg;
757090075Sobrien  unsigned long saved_regs_mask;
757190075Sobrien  unsigned long func_type;
757296263Sobrien  /* Floats_offset is the offset from the "virtual" frame.  In an APCS
757396263Sobrien     frame that is $fp + 4 for a non-variadic function.  */
757496263Sobrien  int floats_offset = 0;
757590075Sobrien  rtx operands[3];
7576117395Skan  int frame_size = arm_get_frame_size ();
757790075Sobrien  FILE * f = asm_out_file;
757890075Sobrien  rtx eh_ofs = cfun->machine->eh_epilogue_sp_ofs;
757990075Sobrien
758090075Sobrien  /* If we have already generated the return instruction
758190075Sobrien     then it is futile to generate anything else.  */
758290075Sobrien  if (use_return_insn (FALSE) && return_used_this_function)
758390075Sobrien    return "";
758490075Sobrien
758590075Sobrien  func_type = arm_current_func_type ();
758690075Sobrien
758790075Sobrien  if (IS_NAKED (func_type))
758890075Sobrien    /* Naked functions don't have epilogues.  */
758990075Sobrien    return "";
759090075Sobrien
759190075Sobrien  if (IS_VOLATILE (func_type) && TARGET_ABORT_NORETURN)
759290075Sobrien    {
759390075Sobrien      rtx op;
759490075Sobrien
759590075Sobrien      /* A volatile function should never return.  Call abort.  */
759690075Sobrien      op = gen_rtx_SYMBOL_REF (Pmode, NEED_PLT_RELOC ? "abort(PLT)" : "abort");
759790075Sobrien      assemble_external_libcall (op);
759890075Sobrien      output_asm_insn ("bl\t%a0", &op);
759990075Sobrien
760090075Sobrien      return "";
760190075Sobrien    }
760290075Sobrien
760390075Sobrien  if (ARM_FUNC_TYPE (func_type) == ARM_FT_EXCEPTION_HANDLER
760490075Sobrien      && ! really_return)
760590075Sobrien    /* If we are throwing an exception, then we really must
760690075Sobrien       be doing a return,  so we can't tail-call.  */
760790075Sobrien    abort ();
760890075Sobrien
760990075Sobrien  saved_regs_mask = arm_compute_save_reg_mask ();
761090075Sobrien
761196263Sobrien  /* XXX We should adjust floats_offset for any anonymous args, and then
761296263Sobrien     re-adjust vfp_offset below to compensate.  */
761396263Sobrien
761490075Sobrien  /* Compute how far away the floats will be.  */
761590075Sobrien  for (reg = 0; reg <= LAST_ARM_REGNUM; reg ++)
761690075Sobrien    if (saved_regs_mask & (1 << reg))
761790075Sobrien      floats_offset += 4;
761890075Sobrien
761990075Sobrien  if (frame_pointer_needed)
762090075Sobrien    {
762196263Sobrien      int vfp_offset = 4;
762296263Sobrien
762390075Sobrien      if (arm_fpu_arch == FP_SOFT2)
762490075Sobrien	{
762590075Sobrien	  for (reg = LAST_ARM_FP_REGNUM; reg >= FIRST_ARM_FP_REGNUM; reg--)
762690075Sobrien	    if (regs_ever_live[reg] && !call_used_regs[reg])
762790075Sobrien	      {
762890075Sobrien		floats_offset += 12;
762990075Sobrien		asm_fprintf (f, "\tldfe\t%r, [%r, #-%d]\n",
763096263Sobrien			     reg, FP_REGNUM, floats_offset - vfp_offset);
763190075Sobrien	      }
763290075Sobrien	}
763390075Sobrien      else
763490075Sobrien	{
763590075Sobrien	  int start_reg = LAST_ARM_FP_REGNUM;
763690075Sobrien
763790075Sobrien	  for (reg = LAST_ARM_FP_REGNUM; reg >= FIRST_ARM_FP_REGNUM; reg--)
763890075Sobrien	    {
763990075Sobrien	      if (regs_ever_live[reg] && !call_used_regs[reg])
764090075Sobrien		{
764190075Sobrien		  floats_offset += 12;
764290075Sobrien
764390075Sobrien		  /* We can't unstack more than four registers at once.  */
764490075Sobrien		  if (start_reg - reg == 3)
764590075Sobrien		    {
764690075Sobrien		      asm_fprintf (f, "\tlfm\t%r, 4, [%r, #-%d]\n",
764796263Sobrien			           reg, FP_REGNUM, floats_offset - vfp_offset);
764890075Sobrien		      start_reg = reg - 1;
764990075Sobrien		    }
765090075Sobrien		}
765190075Sobrien	      else
765290075Sobrien		{
765390075Sobrien		  if (reg != start_reg)
765490075Sobrien		    asm_fprintf (f, "\tlfm\t%r, %d, [%r, #-%d]\n",
765590075Sobrien				 reg + 1, start_reg - reg,
765696263Sobrien				 FP_REGNUM, floats_offset - vfp_offset);
765790075Sobrien		  start_reg = reg - 1;
765890075Sobrien		}
765990075Sobrien	    }
766090075Sobrien
766190075Sobrien	  /* Just in case the last register checked also needs unstacking.  */
766290075Sobrien	  if (reg != start_reg)
766390075Sobrien	    asm_fprintf (f, "\tlfm\t%r, %d, [%r, #-%d]\n",
766490075Sobrien			 reg + 1, start_reg - reg,
766596263Sobrien			 FP_REGNUM, floats_offset - vfp_offset);
766690075Sobrien	}
766790075Sobrien
766890075Sobrien      /* saved_regs_mask should contain the IP, which at the time of stack
766990075Sobrien	 frame generation actually contains the old stack pointer.  So a
767090075Sobrien	 quick way to unwind the stack is just pop the IP register directly
767190075Sobrien	 into the stack pointer.  */
767290075Sobrien      if ((saved_regs_mask & (1 << IP_REGNUM)) == 0)
767390075Sobrien	abort ();
767490075Sobrien      saved_regs_mask &= ~ (1 << IP_REGNUM);
767590075Sobrien      saved_regs_mask |=   (1 << SP_REGNUM);
767690075Sobrien
767790075Sobrien      /* There are two registers left in saved_regs_mask - LR and PC.  We
767890075Sobrien	 only need to restore the LR register (the return address), but to
767990075Sobrien	 save time we can load it directly into the PC, unless we need a
768090075Sobrien	 special function exit sequence, or we are not really returning.  */
768190075Sobrien      if (really_return && ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL)
768290075Sobrien	/* Delete the LR from the register mask, so that the LR on
768390075Sobrien	   the stack is loaded into the PC in the register mask.  */
768490075Sobrien	saved_regs_mask &= ~ (1 << LR_REGNUM);
768590075Sobrien      else
768690075Sobrien	saved_regs_mask &= ~ (1 << PC_REGNUM);
768790075Sobrien
768890075Sobrien      print_multi_reg (f, "ldmea\t%r", FP_REGNUM, saved_regs_mask);
768990075Sobrien
769090075Sobrien      if (IS_INTERRUPT (func_type))
769190075Sobrien	/* Interrupt handlers will have pushed the
769290075Sobrien	   IP onto the stack, so restore it now.  */
7693117395Skan	print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM, 1 << IP_REGNUM);
769490075Sobrien    }
769590075Sobrien  else
769690075Sobrien    {
769790075Sobrien      /* Restore stack pointer if necessary.  */
769890075Sobrien      if (frame_size + current_function_outgoing_args_size != 0)
769990075Sobrien	{
770090075Sobrien	  operands[0] = operands[1] = stack_pointer_rtx;
770190075Sobrien	  operands[2] = GEN_INT (frame_size
770290075Sobrien				 + current_function_outgoing_args_size);
770390075Sobrien	  output_add_immediate (operands);
770490075Sobrien	}
770590075Sobrien
770690075Sobrien      if (arm_fpu_arch == FP_SOFT2)
770790075Sobrien	{
770890075Sobrien	  for (reg = FIRST_ARM_FP_REGNUM; reg <= LAST_ARM_FP_REGNUM; reg++)
770990075Sobrien	    if (regs_ever_live[reg] && !call_used_regs[reg])
771090075Sobrien	      asm_fprintf (f, "\tldfe\t%r, [%r], #12\n",
771190075Sobrien			   reg, SP_REGNUM);
771290075Sobrien	}
771390075Sobrien      else
771490075Sobrien	{
771590075Sobrien	  int start_reg = FIRST_ARM_FP_REGNUM;
771690075Sobrien
771790075Sobrien	  for (reg = FIRST_ARM_FP_REGNUM; reg <= LAST_ARM_FP_REGNUM; reg++)
771890075Sobrien	    {
771990075Sobrien	      if (regs_ever_live[reg] && !call_used_regs[reg])
772090075Sobrien		{
772190075Sobrien		  if (reg - start_reg == 3)
772290075Sobrien		    {
772390075Sobrien		      asm_fprintf (f, "\tlfmfd\t%r, 4, [%r]!\n",
772490075Sobrien				   start_reg, SP_REGNUM);
772590075Sobrien		      start_reg = reg + 1;
772690075Sobrien		    }
772790075Sobrien		}
772890075Sobrien	      else
772990075Sobrien		{
773090075Sobrien		  if (reg != start_reg)
773190075Sobrien		    asm_fprintf (f, "\tlfmfd\t%r, %d, [%r]!\n",
773290075Sobrien				 start_reg, reg - start_reg,
773390075Sobrien				 SP_REGNUM);
773490075Sobrien
773590075Sobrien		  start_reg = reg + 1;
773690075Sobrien		}
773790075Sobrien	    }
773890075Sobrien
773990075Sobrien	  /* Just in case the last register checked also needs unstacking.  */
774090075Sobrien	  if (reg != start_reg)
774190075Sobrien	    asm_fprintf (f, "\tlfmfd\t%r, %d, [%r]!\n",
774290075Sobrien			 start_reg, reg - start_reg, SP_REGNUM);
774390075Sobrien	}
774490075Sobrien
774590075Sobrien      /* If we can, restore the LR into the PC.  */
774690075Sobrien      if (ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL
774790075Sobrien	  && really_return
774890075Sobrien	  && current_function_pretend_args_size == 0
774990075Sobrien	  && saved_regs_mask & (1 << LR_REGNUM))
775090075Sobrien	{
775190075Sobrien	  saved_regs_mask &= ~ (1 << LR_REGNUM);
775290075Sobrien	  saved_regs_mask |=   (1 << PC_REGNUM);
775390075Sobrien	}
775490075Sobrien
775590075Sobrien      /* Load the registers off the stack.  If we only have one register
775690075Sobrien	 to load use the LDR instruction - it is faster.  */
775790075Sobrien      if (saved_regs_mask == (1 << LR_REGNUM))
775890075Sobrien	{
775996263Sobrien	  /* The exception handler ignores the LR, so we do
776090075Sobrien	     not really need to load it off the stack.  */
776190075Sobrien	  if (eh_ofs)
776290075Sobrien	    asm_fprintf (f, "\tadd\t%r, %r, #4\n", SP_REGNUM, SP_REGNUM);
776390075Sobrien	  else
776490075Sobrien	    asm_fprintf (f, "\tldr\t%r, [%r], #4\n", LR_REGNUM, SP_REGNUM);
776590075Sobrien	}
776690075Sobrien      else if (saved_regs_mask)
7767117395Skan	{
7768117395Skan	  if (saved_regs_mask & (1 << SP_REGNUM))
7769117395Skan	    /* Note - write back to the stack register is not enabled
7770117395Skan	       (ie "ldmfd sp!...").  We know that the stack pointer is
7771117395Skan	       in the list of registers and if we add writeback the
7772117395Skan	       instruction becomes UNPREDICTABLE.  */
7773117395Skan	    print_multi_reg (f, "ldmfd\t%r", SP_REGNUM, saved_regs_mask);
7774117395Skan	  else
7775117395Skan	    print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM, saved_regs_mask);
7776117395Skan	}
777790075Sobrien
777890075Sobrien      if (current_function_pretend_args_size)
777990075Sobrien	{
778090075Sobrien	  /* Unwind the pre-pushed regs.  */
778190075Sobrien	  operands[0] = operands[1] = stack_pointer_rtx;
778290075Sobrien	  operands[2] = GEN_INT (current_function_pretend_args_size);
778390075Sobrien	  output_add_immediate (operands);
778490075Sobrien	}
778590075Sobrien    }
778690075Sobrien
778790075Sobrien#if 0
778890075Sobrien  if (ARM_FUNC_TYPE (func_type) == ARM_FT_EXCEPTION_HANDLER)
778990075Sobrien    /* Adjust the stack to remove the exception handler stuff.  */
779090075Sobrien    asm_fprintf (f, "\tadd\t%r, %r, %r\n", SP_REGNUM, SP_REGNUM,
779190075Sobrien		 REGNO (eh_ofs));
779290075Sobrien#endif
779390075Sobrien
779496263Sobrien  if (! really_return
779596263Sobrien    || (ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL
779696263Sobrien	&& current_function_pretend_args_size == 0
779796263Sobrien	&& saved_regs_mask & (1 << PC_REGNUM)))
779890075Sobrien    return "";
779990075Sobrien
780090075Sobrien  /* Generate the return instruction.  */
780190075Sobrien  switch ((int) ARM_FUNC_TYPE (func_type))
780290075Sobrien    {
780390075Sobrien    case ARM_FT_EXCEPTION_HANDLER:
780490075Sobrien      /* Even in 26-bit mode we do a mov (rather than a movs)
780590075Sobrien	 because we don't have the PSR bits set in the address.  */
780690075Sobrien      asm_fprintf (f, "\tmov\t%r, %r\n", PC_REGNUM, EXCEPTION_LR_REGNUM);
780790075Sobrien      break;
780890075Sobrien
780990075Sobrien    case ARM_FT_ISR:
781090075Sobrien    case ARM_FT_FIQ:
781190075Sobrien      asm_fprintf (f, "\tsubs\t%r, %r, #4\n", PC_REGNUM, LR_REGNUM);
781290075Sobrien      break;
781390075Sobrien
781490075Sobrien    case ARM_FT_EXCEPTION:
781590075Sobrien      asm_fprintf (f, "\tmovs\t%r, %r\n", PC_REGNUM, LR_REGNUM);
781690075Sobrien      break;
781790075Sobrien
781890075Sobrien    case ARM_FT_INTERWORKED:
781990075Sobrien      asm_fprintf (f, "\tbx\t%r\n", LR_REGNUM);
782090075Sobrien      break;
782190075Sobrien
782290075Sobrien    default:
782390075Sobrien      if (frame_pointer_needed)
7824117395Skan	/* If we used the frame pointer then the return address
782590075Sobrien	   will have been loaded off the stack directly into the
782690075Sobrien	   PC, so there is no need to issue a MOV instruction
782790075Sobrien	   here.  */
782890075Sobrien	;
782990075Sobrien      else if (current_function_pretend_args_size == 0
783090075Sobrien	       && (saved_regs_mask & (1 << LR_REGNUM)))
783190075Sobrien	/* Similarly we may have been able to load LR into the PC
783290075Sobrien	   even if we did not create a stack frame.  */
783390075Sobrien	;
783490075Sobrien      else if (TARGET_APCS_32)
783590075Sobrien	asm_fprintf (f, "\tmov\t%r, %r\n", PC_REGNUM, LR_REGNUM);
783690075Sobrien      else
783790075Sobrien	asm_fprintf (f, "\tmovs\t%r, %r\n", PC_REGNUM, LR_REGNUM);
783890075Sobrien      break;
783990075Sobrien    }
784090075Sobrien
784190075Sobrien  return "";
784290075Sobrien}
784390075Sobrien
784490075Sobrienstatic void
784590075Sobrienarm_output_function_epilogue (file, frame_size)
784690075Sobrien     FILE *file ATTRIBUTE_UNUSED;
784790075Sobrien     HOST_WIDE_INT frame_size;
784890075Sobrien{
784990075Sobrien  if (TARGET_THUMB)
785090075Sobrien    {
785190075Sobrien      /* ??? Probably not safe to set this here, since it assumes that a
785290075Sobrien	 function will be emitted as assembly immediately after we generate
785390075Sobrien	 RTL for it.  This does not happen for inline functions.  */
785490075Sobrien      return_used_this_function = 0;
785590075Sobrien    }
785690075Sobrien  else
785790075Sobrien    {
7858117395Skan      /* We need to take into account any stack-frame rounding.  */
7859117395Skan      frame_size = arm_get_frame_size ();
7860117395Skan
786190075Sobrien      if (use_return_insn (FALSE)
786290075Sobrien	  && return_used_this_function
786390075Sobrien	  && (frame_size + current_function_outgoing_args_size) != 0
786490075Sobrien	  && !frame_pointer_needed)
786590075Sobrien	abort ();
786690075Sobrien
786790075Sobrien      /* Reset the ARM-specific per-function variables.  */
786890075Sobrien      after_arm_reorg = 0;
786990075Sobrien    }
787090075Sobrien}
787190075Sobrien
787290075Sobrien/* Generate and emit an insn that we will recognize as a push_multi.
787390075Sobrien   Unfortunately, since this insn does not reflect very well the actual
787490075Sobrien   semantics of the operation, we need to annotate the insn for the benefit
787590075Sobrien   of DWARF2 frame unwind information.  */
787690075Sobrien
787790075Sobrienstatic rtx
787890075Sobrienemit_multi_reg_push (mask)
787990075Sobrien     int mask;
788090075Sobrien{
788190075Sobrien  int num_regs = 0;
788290075Sobrien  int num_dwarf_regs;
788390075Sobrien  int i, j;
788490075Sobrien  rtx par;
788590075Sobrien  rtx dwarf;
788690075Sobrien  int dwarf_par_index;
788790075Sobrien  rtx tmp, reg;
788890075Sobrien
788990075Sobrien  for (i = 0; i <= LAST_ARM_REGNUM; i++)
789090075Sobrien    if (mask & (1 << i))
789190075Sobrien      num_regs++;
789290075Sobrien
789390075Sobrien  if (num_regs == 0 || num_regs > 16)
789490075Sobrien    abort ();
789590075Sobrien
789690075Sobrien  /* We don't record the PC in the dwarf frame information.  */
789790075Sobrien  num_dwarf_regs = num_regs;
789890075Sobrien  if (mask & (1 << PC_REGNUM))
789990075Sobrien    num_dwarf_regs--;
790090075Sobrien
790190075Sobrien  /* For the body of the insn we are going to generate an UNSPEC in
7902117395Skan     parallel with several USEs.  This allows the insn to be recognized
790390075Sobrien     by the push_multi pattern in the arm.md file.  The insn looks
790490075Sobrien     something like this:
790590075Sobrien
790690075Sobrien       (parallel [
790790075Sobrien           (set (mem:BLK (pre_dec:BLK (reg:SI sp)))
790890075Sobrien	        (unspec:BLK [(reg:SI r4)] UNSPEC_PUSH_MULT))
790990075Sobrien           (use (reg:SI 11 fp))
791090075Sobrien           (use (reg:SI 12 ip))
791190075Sobrien           (use (reg:SI 14 lr))
791290075Sobrien           (use (reg:SI 15 pc))
791390075Sobrien        ])
791490075Sobrien
791590075Sobrien     For the frame note however, we try to be more explicit and actually
791690075Sobrien     show each register being stored into the stack frame, plus a (single)
791790075Sobrien     decrement of the stack pointer.  We do it this way in order to be
791890075Sobrien     friendly to the stack unwinding code, which only wants to see a single
791990075Sobrien     stack decrement per instruction.  The RTL we generate for the note looks
792090075Sobrien     something like this:
792190075Sobrien
792290075Sobrien      (sequence [
792390075Sobrien           (set (reg:SI sp) (plus:SI (reg:SI sp) (const_int -20)))
792490075Sobrien           (set (mem:SI (reg:SI sp)) (reg:SI r4))
792590075Sobrien           (set (mem:SI (plus:SI (reg:SI sp) (const_int 4))) (reg:SI fp))
792690075Sobrien           (set (mem:SI (plus:SI (reg:SI sp) (const_int 8))) (reg:SI ip))
792790075Sobrien           (set (mem:SI (plus:SI (reg:SI sp) (const_int 12))) (reg:SI lr))
792890075Sobrien        ])
792990075Sobrien
793090075Sobrien      This sequence is used both by the code to support stack unwinding for
793190075Sobrien      exceptions handlers and the code to generate dwarf2 frame debugging.  */
793290075Sobrien
793390075Sobrien  par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (num_regs));
793490075Sobrien  dwarf = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (num_dwarf_regs + 1));
793590075Sobrien  dwarf_par_index = 1;
793690075Sobrien
793790075Sobrien  for (i = 0; i <= LAST_ARM_REGNUM; i++)
793890075Sobrien    {
793990075Sobrien      if (mask & (1 << i))
794090075Sobrien	{
794190075Sobrien	  reg = gen_rtx_REG (SImode, i);
794290075Sobrien
794390075Sobrien	  XVECEXP (par, 0, 0)
794490075Sobrien	    = gen_rtx_SET (VOIDmode,
794590075Sobrien			   gen_rtx_MEM (BLKmode,
794690075Sobrien					gen_rtx_PRE_DEC (BLKmode,
794790075Sobrien							 stack_pointer_rtx)),
794890075Sobrien			   gen_rtx_UNSPEC (BLKmode,
794990075Sobrien					   gen_rtvec (1, reg),
795090075Sobrien					   UNSPEC_PUSH_MULT));
795190075Sobrien
795290075Sobrien	  if (i != PC_REGNUM)
795390075Sobrien	    {
795490075Sobrien	      tmp = gen_rtx_SET (VOIDmode,
795590075Sobrien				 gen_rtx_MEM (SImode, stack_pointer_rtx),
795690075Sobrien				 reg);
795790075Sobrien	      RTX_FRAME_RELATED_P (tmp) = 1;
795890075Sobrien	      XVECEXP (dwarf, 0, dwarf_par_index) = tmp;
795990075Sobrien	      dwarf_par_index++;
796090075Sobrien	    }
796190075Sobrien
796290075Sobrien	  break;
796390075Sobrien	}
796490075Sobrien    }
796590075Sobrien
796690075Sobrien  for (j = 1, i++; j < num_regs; i++)
796790075Sobrien    {
796890075Sobrien      if (mask & (1 << i))
796990075Sobrien	{
797090075Sobrien	  reg = gen_rtx_REG (SImode, i);
797190075Sobrien
797290075Sobrien	  XVECEXP (par, 0, j) = gen_rtx_USE (VOIDmode, reg);
797390075Sobrien
797490075Sobrien	  if (i != PC_REGNUM)
797590075Sobrien	    {
797690075Sobrien	      tmp = gen_rtx_SET (VOIDmode,
797790075Sobrien				 gen_rtx_MEM (SImode,
797890075Sobrien					      plus_constant (stack_pointer_rtx,
797990075Sobrien							     4 * j)),
798090075Sobrien				 reg);
798190075Sobrien	      RTX_FRAME_RELATED_P (tmp) = 1;
798290075Sobrien	      XVECEXP (dwarf, 0, dwarf_par_index++) = tmp;
798390075Sobrien	    }
798490075Sobrien
798590075Sobrien	  j++;
798690075Sobrien	}
798790075Sobrien    }
798890075Sobrien
798990075Sobrien  par = emit_insn (par);
799090075Sobrien
799190075Sobrien  tmp = gen_rtx_SET (SImode,
799290075Sobrien		     stack_pointer_rtx,
799390075Sobrien		     gen_rtx_PLUS (SImode,
799490075Sobrien				   stack_pointer_rtx,
799590075Sobrien				   GEN_INT (-4 * num_regs)));
799690075Sobrien  RTX_FRAME_RELATED_P (tmp) = 1;
799790075Sobrien  XVECEXP (dwarf, 0, 0) = tmp;
799890075Sobrien
799990075Sobrien  REG_NOTES (par) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
800090075Sobrien				       REG_NOTES (par));
800190075Sobrien  return par;
800290075Sobrien}
800390075Sobrien
800490075Sobrienstatic rtx
800590075Sobrienemit_sfm (base_reg, count)
800690075Sobrien     int base_reg;
800790075Sobrien     int count;
800890075Sobrien{
800990075Sobrien  rtx par;
801090075Sobrien  rtx dwarf;
801190075Sobrien  rtx tmp, reg;
801290075Sobrien  int i;
801390075Sobrien
801490075Sobrien  par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count));
801590075Sobrien  dwarf = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count));
801690075Sobrien
801790075Sobrien  reg = gen_rtx_REG (XFmode, base_reg++);
801890075Sobrien
801990075Sobrien  XVECEXP (par, 0, 0)
802090075Sobrien    = gen_rtx_SET (VOIDmode,
802190075Sobrien		   gen_rtx_MEM (BLKmode,
802290075Sobrien				gen_rtx_PRE_DEC (BLKmode, stack_pointer_rtx)),
802390075Sobrien		   gen_rtx_UNSPEC (BLKmode,
802490075Sobrien				   gen_rtvec (1, reg),
802590075Sobrien				   UNSPEC_PUSH_MULT));
802690075Sobrien  tmp
802790075Sobrien    = gen_rtx_SET (VOIDmode,
802890075Sobrien		   gen_rtx_MEM (XFmode,
802990075Sobrien				gen_rtx_PRE_DEC (BLKmode, stack_pointer_rtx)),
803090075Sobrien		   reg);
803190075Sobrien  RTX_FRAME_RELATED_P (tmp) = 1;
803290075Sobrien  XVECEXP (dwarf, 0, count - 1) = tmp;
803390075Sobrien
803490075Sobrien  for (i = 1; i < count; i++)
803590075Sobrien    {
803690075Sobrien      reg = gen_rtx_REG (XFmode, base_reg++);
803790075Sobrien      XVECEXP (par, 0, i) = gen_rtx_USE (VOIDmode, reg);
803890075Sobrien
803990075Sobrien      tmp = gen_rtx_SET (VOIDmode,
804090075Sobrien			 gen_rtx_MEM (XFmode,
804190075Sobrien				      gen_rtx_PRE_DEC (BLKmode,
804290075Sobrien						       stack_pointer_rtx)),
804390075Sobrien			 reg);
804490075Sobrien      RTX_FRAME_RELATED_P (tmp) = 1;
804590075Sobrien      XVECEXP (dwarf, 0, count - i - 1) = tmp;
804690075Sobrien    }
804790075Sobrien
804890075Sobrien  par = emit_insn (par);
804990075Sobrien  REG_NOTES (par) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
805090075Sobrien				       REG_NOTES (par));
805190075Sobrien  return par;
805290075Sobrien}
805390075Sobrien
805490075Sobrien/* Compute the distance from register FROM to register TO.
805590075Sobrien   These can be the arg pointer (26), the soft frame pointer (25),
805690075Sobrien   the stack pointer (13) or the hard frame pointer (11).
805790075Sobrien   Typical stack layout looks like this:
805890075Sobrien
805990075Sobrien       old stack pointer -> |    |
806090075Sobrien                             ----
806190075Sobrien                            |    | \
806290075Sobrien                            |    |   saved arguments for
806390075Sobrien                            |    |   vararg functions
806490075Sobrien			    |    | /
806590075Sobrien                              --
806690075Sobrien   hard FP & arg pointer -> |    | \
806790075Sobrien                            |    |   stack
806890075Sobrien                            |    |   frame
806990075Sobrien                            |    | /
807090075Sobrien                              --
807190075Sobrien                            |    | \
807290075Sobrien                            |    |   call saved
807390075Sobrien                            |    |   registers
807490075Sobrien      soft frame pointer -> |    | /
807590075Sobrien                              --
807690075Sobrien                            |    | \
807790075Sobrien                            |    |   local
807890075Sobrien                            |    |   variables
807990075Sobrien                            |    | /
808090075Sobrien                              --
808190075Sobrien                            |    | \
808290075Sobrien                            |    |   outgoing
808390075Sobrien                            |    |   arguments
808490075Sobrien   current stack pointer -> |    | /
808590075Sobrien                              --
808690075Sobrien
8087117395Skan  For a given function some or all of these stack components
808890075Sobrien  may not be needed, giving rise to the possibility of
808990075Sobrien  eliminating some of the registers.
809090075Sobrien
8091117395Skan  The values returned by this function must reflect the behavior
809290075Sobrien  of arm_expand_prologue() and arm_compute_save_reg_mask().
809390075Sobrien
809490075Sobrien  The sign of the number returned reflects the direction of stack
809590075Sobrien  growth, so the values are positive for all eliminations except
809690075Sobrien  from the soft frame pointer to the hard frame pointer.  */
809790075Sobrien
809890075Sobrienunsigned int
809990075Sobrienarm_compute_initial_elimination_offset (from, to)
810090075Sobrien     unsigned int from;
810190075Sobrien     unsigned int to;
810290075Sobrien{
8103117395Skan  unsigned int local_vars    = arm_get_frame_size ();
810490075Sobrien  unsigned int outgoing_args = current_function_outgoing_args_size;
810590075Sobrien  unsigned int stack_frame;
810690075Sobrien  unsigned int call_saved_registers;
810790075Sobrien  unsigned long func_type;
810890075Sobrien
810990075Sobrien  func_type = arm_current_func_type ();
811090075Sobrien
811190075Sobrien  /* Volatile functions never return, so there is
811290075Sobrien     no need to save call saved registers.  */
811390075Sobrien  call_saved_registers = 0;
811490075Sobrien  if (! IS_VOLATILE (func_type))
811590075Sobrien    {
811690075Sobrien      unsigned int reg_mask;
811790075Sobrien      unsigned int reg;
811890075Sobrien
811990075Sobrien      /* Make sure that we compute which registers will be saved
812090075Sobrien	 on the stack using the same algorithm that is used by
812190075Sobrien	 arm_compute_save_reg_mask().  */
812290075Sobrien      reg_mask = arm_compute_save_reg0_reg12_mask ();
812390075Sobrien
812490075Sobrien      /* Now count the number of bits set in save_reg_mask.
812590075Sobrien	 For each set bit we need 4 bytes of stack space.  */
812690075Sobrien      while (reg_mask)
812790075Sobrien	{
812890075Sobrien	  call_saved_registers += 4;
812990075Sobrien	  reg_mask = reg_mask & ~ (reg_mask & - reg_mask);
813090075Sobrien	}
813190075Sobrien
8132117395Skan      if ((regs_ever_live[LR_REGNUM]
8133117395Skan	   /* If optimizing for size, then we save the link register if
8134117395Skan	      any other integer register is saved.  This gives a smaller
8135117395Skan	      return sequence.  */
8136117395Skan	   || (optimize_size && call_saved_registers > 0))
8137117395Skan	  /* But if a stack frame is going to be created, the LR will
8138117395Skan	     be saved as part of that, so we do not need to allow for
8139117395Skan	     it here.  */
814090075Sobrien	  && ! frame_pointer_needed)
814190075Sobrien	call_saved_registers += 4;
814290075Sobrien
814390075Sobrien      /* If the hard floating point registers are going to be
814490075Sobrien	 used then they must be saved on the stack as well.
814590075Sobrien         Each register occupies 12 bytes of stack space.  */
814690075Sobrien      for (reg = FIRST_ARM_FP_REGNUM; reg <= LAST_ARM_FP_REGNUM; reg ++)
814790075Sobrien	if (regs_ever_live[reg] && ! call_used_regs[reg])
814890075Sobrien	  call_saved_registers += 12;
814990075Sobrien    }
815090075Sobrien
815190075Sobrien  /* The stack frame contains 4 registers - the old frame pointer,
815290075Sobrien     the old stack pointer, the return address and PC of the start
815390075Sobrien     of the function.  */
815490075Sobrien  stack_frame = frame_pointer_needed ? 16 : 0;
815590075Sobrien
815690075Sobrien  /* OK, now we have enough information to compute the distances.
815790075Sobrien     There must be an entry in these switch tables for each pair
815890075Sobrien     of registers in ELIMINABLE_REGS, even if some of the entries
815990075Sobrien     seem to be redundant or useless.  */
816090075Sobrien  switch (from)
816190075Sobrien    {
816290075Sobrien    case ARG_POINTER_REGNUM:
816390075Sobrien      switch (to)
816490075Sobrien	{
816590075Sobrien	case THUMB_HARD_FRAME_POINTER_REGNUM:
816690075Sobrien	  return 0;
816790075Sobrien
816890075Sobrien	case FRAME_POINTER_REGNUM:
816990075Sobrien	  /* This is the reverse of the soft frame pointer
817090075Sobrien	     to hard frame pointer elimination below.  */
817190075Sobrien	  if (call_saved_registers == 0 && stack_frame == 0)
817290075Sobrien	    return 0;
817390075Sobrien	  return (call_saved_registers + stack_frame - 4);
817490075Sobrien
817590075Sobrien	case ARM_HARD_FRAME_POINTER_REGNUM:
817690075Sobrien	  /* If there is no stack frame then the hard
817790075Sobrien	     frame pointer and the arg pointer coincide.  */
817890075Sobrien	  if (stack_frame == 0 && call_saved_registers != 0)
817990075Sobrien	    return 0;
818090075Sobrien	  /* FIXME:  Not sure about this.  Maybe we should always return 0 ?  */
818190075Sobrien	  return (frame_pointer_needed
818290075Sobrien		  && current_function_needs_context
818396263Sobrien		  && ! cfun->machine->uses_anonymous_args) ? 4 : 0;
818490075Sobrien
818590075Sobrien	case STACK_POINTER_REGNUM:
818690075Sobrien	  /* If nothing has been pushed on the stack at all
818790075Sobrien	     then this will return -4.  This *is* correct!  */
818890075Sobrien	  return call_saved_registers + stack_frame + local_vars + outgoing_args - 4;
818990075Sobrien
819090075Sobrien	default:
819190075Sobrien	  abort ();
819290075Sobrien	}
819390075Sobrien      break;
819490075Sobrien
819590075Sobrien    case FRAME_POINTER_REGNUM:
819690075Sobrien      switch (to)
819790075Sobrien	{
819890075Sobrien	case THUMB_HARD_FRAME_POINTER_REGNUM:
819990075Sobrien	  return 0;
820090075Sobrien
820190075Sobrien	case ARM_HARD_FRAME_POINTER_REGNUM:
820290075Sobrien	  /* The hard frame pointer points to the top entry in the
820390075Sobrien	     stack frame.  The soft frame pointer to the bottom entry
820490075Sobrien	     in the stack frame.  If there is no stack frame at all,
820590075Sobrien	     then they are identical.  */
820690075Sobrien	  if (call_saved_registers == 0 && stack_frame == 0)
820790075Sobrien	    return 0;
820890075Sobrien	  return - (call_saved_registers + stack_frame - 4);
820990075Sobrien
821090075Sobrien	case STACK_POINTER_REGNUM:
821190075Sobrien	  return local_vars + outgoing_args;
821290075Sobrien
821390075Sobrien	default:
821490075Sobrien	  abort ();
821590075Sobrien	}
821690075Sobrien      break;
821790075Sobrien
821890075Sobrien    default:
821990075Sobrien      /* You cannot eliminate from the stack pointer.
822090075Sobrien	 In theory you could eliminate from the hard frame
822190075Sobrien	 pointer to the stack pointer, but this will never
822290075Sobrien	 happen, since if a stack frame is not needed the
822390075Sobrien	 hard frame pointer will never be used.  */
822490075Sobrien      abort ();
822590075Sobrien    }
822690075Sobrien}
822790075Sobrien
8228117395Skan/* Calculate the size of the stack frame, taking into account any
8229117395Skan   padding that is required to ensure stack-alignment.  */
8230117395Skan
8231117395SkanHOST_WIDE_INT
8232117395Skanarm_get_frame_size ()
8233117395Skan{
8234117395Skan  int regno;
8235117395Skan
8236117395Skan  int base_size = ROUND_UP (get_frame_size ());
8237117395Skan  int entry_size = 0;
8238117395Skan  unsigned long func_type = arm_current_func_type ();
8239117395Skan  int leaf;
8240117395Skan
8241117395Skan  if (! TARGET_ARM)
8242117395Skan    abort();
8243117395Skan
8244117395Skan  if (! TARGET_ATPCS)
8245117395Skan    return base_size;
8246117395Skan
8247117395Skan  /* We need to know if we are a leaf function.  Unfortunately, it
8248117395Skan     is possible to be called after start_sequence has been called,
8249117395Skan     which causes get_insns to return the insns for the sequence,
8250117395Skan     not the function, which will cause leaf_function_p to return
8251117395Skan     the incorrect result.
8252117395Skan
8253117395Skan     To work around this, we cache the computed frame size.  This
8254117395Skan     works because we will only be calling RTL expanders that need
8255117395Skan     to know about leaf functions once reload has completed, and the
8256117395Skan     frame size cannot be changed after that time, so we can safely
8257117395Skan     use the cached value.  */
8258117395Skan
8259117395Skan  if (reload_completed)
8260117395Skan    return cfun->machine->frame_size;
8261117395Skan
8262117395Skan  leaf = leaf_function_p ();
8263117395Skan
8264117395Skan  /* A leaf function does not need any stack alignment if it has nothing
8265117395Skan     on the stack.  */
8266117395Skan  if (leaf && base_size == 0)
8267117395Skan    {
8268117395Skan      cfun->machine->frame_size = 0;
8269117395Skan      return 0;
8270117395Skan    }
8271117395Skan
8272117395Skan  /* We know that SP will be word aligned on entry, and we must
8273117395Skan     preserve that condition at any subroutine call.  But those are
8274117395Skan     the only constraints.  */
8275117395Skan
8276117395Skan  /* Space for variadic functions.  */
8277117395Skan  if (current_function_pretend_args_size)
8278117395Skan    entry_size += current_function_pretend_args_size;
8279117395Skan
8280117395Skan  /* Space for saved registers.  */
8281117395Skan  entry_size += bit_count (arm_compute_save_reg_mask ()) * 4;
8282117395Skan
8283117395Skan  /* Space for saved FPA registers.  */
8284117395Skan  if (! IS_VOLATILE (func_type))
8285117395Skan    {
8286117395Skan      for (regno = FIRST_ARM_FP_REGNUM; regno <= LAST_ARM_FP_REGNUM; regno++)
8287117395Skan      if (regs_ever_live[regno] && ! call_used_regs[regno])
8288117395Skan	entry_size += 12;
8289117395Skan    }
8290117395Skan
8291117395Skan  if ((entry_size + base_size + current_function_outgoing_args_size) & 7)
8292117395Skan    base_size += 4;
8293117395Skan  if ((entry_size + base_size + current_function_outgoing_args_size) & 7)
8294117395Skan    abort ();
8295117395Skan
8296117395Skan  cfun->machine->frame_size = base_size;
8297117395Skan
8298117395Skan  return base_size;
8299117395Skan}
8300117395Skan
830190075Sobrien/* Generate the prologue instructions for entry into an ARM function.  */
830290075Sobrien
830390075Sobrienvoid
830490075Sobrienarm_expand_prologue ()
830590075Sobrien{
830690075Sobrien  int reg;
830790075Sobrien  rtx amount;
830890075Sobrien  rtx insn;
830990075Sobrien  rtx ip_rtx;
831090075Sobrien  unsigned long live_regs_mask;
831190075Sobrien  unsigned long func_type;
831290075Sobrien  int fp_offset = 0;
831390075Sobrien  int saved_pretend_args = 0;
831490075Sobrien  unsigned int args_to_push;
831590075Sobrien
831690075Sobrien  func_type = arm_current_func_type ();
831790075Sobrien
831890075Sobrien  /* Naked functions don't have prologues.  */
831990075Sobrien  if (IS_NAKED (func_type))
832090075Sobrien    return;
832190075Sobrien
832290075Sobrien  /* Make a copy of c_f_p_a_s as we may need to modify it locally.  */
832390075Sobrien  args_to_push = current_function_pretend_args_size;
832490075Sobrien
832590075Sobrien  /* Compute which register we will have to save onto the stack.  */
832690075Sobrien  live_regs_mask = arm_compute_save_reg_mask ();
832790075Sobrien
832890075Sobrien  ip_rtx = gen_rtx_REG (SImode, IP_REGNUM);
832990075Sobrien
833090075Sobrien  if (frame_pointer_needed)
833190075Sobrien    {
833290075Sobrien      if (IS_INTERRUPT (func_type))
833390075Sobrien	{
833490075Sobrien	  /* Interrupt functions must not corrupt any registers.
833590075Sobrien	     Creating a frame pointer however, corrupts the IP
833690075Sobrien	     register, so we must push it first.  */
833790075Sobrien	  insn = emit_multi_reg_push (1 << IP_REGNUM);
833890075Sobrien
833990075Sobrien	  /* Do not set RTX_FRAME_RELATED_P on this insn.
834090075Sobrien	     The dwarf stack unwinding code only wants to see one
834190075Sobrien	     stack decrement per function, and this is not it.  If
834290075Sobrien	     this instruction is labeled as being part of the frame
834390075Sobrien	     creation sequence then dwarf2out_frame_debug_expr will
834490075Sobrien	     abort when it encounters the assignment of IP to FP
834590075Sobrien	     later on, since the use of SP here establishes SP as
834690075Sobrien	     the CFA register and not IP.
834790075Sobrien
834890075Sobrien	     Anyway this instruction is not really part of the stack
834990075Sobrien	     frame creation although it is part of the prologue.  */
835090075Sobrien	}
835190075Sobrien      else if (IS_NESTED (func_type))
835290075Sobrien	{
835390075Sobrien	  /* The Static chain register is the same as the IP register
835490075Sobrien	     used as a scratch register during stack frame creation.
835590075Sobrien	     To get around this need to find somewhere to store IP
835690075Sobrien	     whilst the frame is being created.  We try the following
835790075Sobrien	     places in order:
835890075Sobrien
835990075Sobrien	       1. The last argument register.
836090075Sobrien	       2. A slot on the stack above the frame.  (This only
836190075Sobrien	          works if the function is not a varargs function).
836290075Sobrien	       3. Register r3, after pushing the argument registers
836390075Sobrien	          onto the stack.
836490075Sobrien
836590075Sobrien	     Note - we only need to tell the dwarf2 backend about the SP
836690075Sobrien	     adjustment in the second variant; the static chain register
836790075Sobrien	     doesn't need to be unwound, as it doesn't contain a value
836890075Sobrien	     inherited from the caller.  */
836990075Sobrien
837090075Sobrien	  if (regs_ever_live[3] == 0)
837190075Sobrien	    {
837290075Sobrien	      insn = gen_rtx_REG (SImode, 3);
837390075Sobrien	      insn = gen_rtx_SET (SImode, insn, ip_rtx);
837490075Sobrien	      insn = emit_insn (insn);
837590075Sobrien	    }
837690075Sobrien	  else if (args_to_push == 0)
837790075Sobrien	    {
837890075Sobrien	      rtx dwarf;
837990075Sobrien	      insn = gen_rtx_PRE_DEC (SImode, stack_pointer_rtx);
838090075Sobrien	      insn = gen_rtx_MEM (SImode, insn);
838190075Sobrien	      insn = gen_rtx_SET (VOIDmode, insn, ip_rtx);
838290075Sobrien	      insn = emit_insn (insn);
838390075Sobrien
838490075Sobrien	      fp_offset = 4;
838590075Sobrien
838690075Sobrien	      /* Just tell the dwarf backend that we adjusted SP.  */
838790075Sobrien	      dwarf = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
838890075Sobrien				   gen_rtx_PLUS (SImode, stack_pointer_rtx,
838990075Sobrien						 GEN_INT (-fp_offset)));
839090075Sobrien	      RTX_FRAME_RELATED_P (insn) = 1;
839190075Sobrien	      REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
839290075Sobrien						    dwarf, REG_NOTES (insn));
839390075Sobrien	    }
839490075Sobrien	  else
839590075Sobrien	    {
839690075Sobrien	      /* Store the args on the stack.  */
839796263Sobrien	      if (cfun->machine->uses_anonymous_args)
839890075Sobrien		insn = emit_multi_reg_push
839990075Sobrien		  ((0xf0 >> (args_to_push / 4)) & 0xf);
840090075Sobrien	      else
840190075Sobrien		insn = emit_insn
840290075Sobrien		  (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
840390075Sobrien			       GEN_INT (- args_to_push)));
840490075Sobrien
840590075Sobrien	      RTX_FRAME_RELATED_P (insn) = 1;
840690075Sobrien
840790075Sobrien	      saved_pretend_args = 1;
840890075Sobrien	      fp_offset = args_to_push;
840990075Sobrien	      args_to_push = 0;
841090075Sobrien
841190075Sobrien	      /* Now reuse r3 to preserve IP.  */
841290075Sobrien	      insn = gen_rtx_REG (SImode, 3);
841390075Sobrien	      insn = gen_rtx_SET (SImode, insn, ip_rtx);
841490075Sobrien	      (void) emit_insn (insn);
841590075Sobrien	    }
841690075Sobrien	}
841790075Sobrien
841890075Sobrien      if (fp_offset)
841990075Sobrien	{
842090075Sobrien	  insn = gen_rtx_PLUS (SImode, stack_pointer_rtx, GEN_INT (fp_offset));
842190075Sobrien	  insn = gen_rtx_SET  (SImode, ip_rtx, insn);
842290075Sobrien	}
842390075Sobrien      else
842490075Sobrien	insn = gen_movsi (ip_rtx, stack_pointer_rtx);
842590075Sobrien
842690075Sobrien      insn = emit_insn (insn);
842790075Sobrien      RTX_FRAME_RELATED_P (insn) = 1;
842890075Sobrien    }
842990075Sobrien
843090075Sobrien  if (args_to_push)
843190075Sobrien    {
843290075Sobrien      /* Push the argument registers, or reserve space for them.  */
843396263Sobrien      if (cfun->machine->uses_anonymous_args)
843490075Sobrien	insn = emit_multi_reg_push
843590075Sobrien	  ((0xf0 >> (args_to_push / 4)) & 0xf);
843690075Sobrien      else
843790075Sobrien	insn = emit_insn
843890075Sobrien	  (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
843990075Sobrien		       GEN_INT (- args_to_push)));
844090075Sobrien      RTX_FRAME_RELATED_P (insn) = 1;
844190075Sobrien    }
844290075Sobrien
8443117395Skan  /* If this is an interrupt service routine, and the link register
8444117395Skan     is going to be pushed, and we are not creating a stack frame,
8445117395Skan     (which would involve an extra push of IP and a pop in the epilogue)
8446117395Skan     subtracting four from LR now will mean that the function return
8447117395Skan     can be done with a single instruction.  */
844896263Sobrien  if ((func_type == ARM_FT_ISR || func_type == ARM_FT_FIQ)
8449117395Skan      && (live_regs_mask & (1 << LR_REGNUM)) != 0
8450117395Skan      && ! frame_pointer_needed)
8451117395Skan    emit_insn (gen_rtx_SET (SImode,
8452117395Skan			    gen_rtx_REG (SImode, LR_REGNUM),
8453117395Skan			    gen_rtx_PLUS (SImode,
8454117395Skan					  gen_rtx_REG (SImode, LR_REGNUM),
8455117395Skan					  GEN_INT (-4))));
845696263Sobrien
845790075Sobrien  if (live_regs_mask)
845890075Sobrien    {
845990075Sobrien      insn = emit_multi_reg_push (live_regs_mask);
846090075Sobrien      RTX_FRAME_RELATED_P (insn) = 1;
846190075Sobrien    }
846290075Sobrien
846390075Sobrien  if (! IS_VOLATILE (func_type))
846490075Sobrien    {
846590075Sobrien      /* Save any floating point call-saved registers used by this function.  */
846690075Sobrien      if (arm_fpu_arch == FP_SOFT2)
846790075Sobrien	{
846890075Sobrien	  for (reg = LAST_ARM_FP_REGNUM; reg >= FIRST_ARM_FP_REGNUM; reg --)
846990075Sobrien	    if (regs_ever_live[reg] && !call_used_regs[reg])
847090075Sobrien	      {
847190075Sobrien		insn = gen_rtx_PRE_DEC (XFmode, stack_pointer_rtx);
847290075Sobrien		insn = gen_rtx_MEM (XFmode, insn);
847390075Sobrien		insn = emit_insn (gen_rtx_SET (VOIDmode, insn,
847490075Sobrien					       gen_rtx_REG (XFmode, reg)));
847590075Sobrien		RTX_FRAME_RELATED_P (insn) = 1;
847690075Sobrien	      }
847790075Sobrien	}
847890075Sobrien      else
847990075Sobrien	{
848090075Sobrien	  int start_reg = LAST_ARM_FP_REGNUM;
848190075Sobrien
848290075Sobrien	  for (reg = LAST_ARM_FP_REGNUM; reg >= FIRST_ARM_FP_REGNUM; reg --)
848390075Sobrien	    {
848490075Sobrien	      if (regs_ever_live[reg] && !call_used_regs[reg])
848590075Sobrien		{
848690075Sobrien		  if (start_reg - reg == 3)
848790075Sobrien		    {
848890075Sobrien		      insn = emit_sfm (reg, 4);
848990075Sobrien		      RTX_FRAME_RELATED_P (insn) = 1;
849090075Sobrien		      start_reg = reg - 1;
849190075Sobrien		    }
849290075Sobrien		}
849390075Sobrien	      else
849490075Sobrien		{
849590075Sobrien		  if (start_reg != reg)
849690075Sobrien		    {
849790075Sobrien		      insn = emit_sfm (reg + 1, start_reg - reg);
849890075Sobrien		      RTX_FRAME_RELATED_P (insn) = 1;
849990075Sobrien		    }
850090075Sobrien		  start_reg = reg - 1;
850190075Sobrien		}
850290075Sobrien	    }
850390075Sobrien
850490075Sobrien	  if (start_reg != reg)
850590075Sobrien	    {
850690075Sobrien	      insn = emit_sfm (reg + 1, start_reg - reg);
850790075Sobrien	      RTX_FRAME_RELATED_P (insn) = 1;
850890075Sobrien	    }
850990075Sobrien	}
851090075Sobrien    }
851190075Sobrien
851290075Sobrien  if (frame_pointer_needed)
851390075Sobrien    {
851490075Sobrien      /* Create the new frame pointer.  */
851590075Sobrien      insn = GEN_INT (-(4 + args_to_push + fp_offset));
851690075Sobrien      insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx, ip_rtx, insn));
851790075Sobrien      RTX_FRAME_RELATED_P (insn) = 1;
851890075Sobrien
851990075Sobrien      if (IS_NESTED (func_type))
852090075Sobrien	{
852190075Sobrien	  /* Recover the static chain register.  */
852290075Sobrien	  if (regs_ever_live [3] == 0
852390075Sobrien	      || saved_pretend_args)
852490075Sobrien	    insn = gen_rtx_REG (SImode, 3);
852590075Sobrien	  else /* if (current_function_pretend_args_size == 0) */
852690075Sobrien	    {
852790075Sobrien	      insn = gen_rtx_PLUS (SImode, hard_frame_pointer_rtx, GEN_INT (4));
852890075Sobrien	      insn = gen_rtx_MEM (SImode, insn);
852990075Sobrien	    }
853090075Sobrien
853190075Sobrien	  emit_insn (gen_rtx_SET (SImode, ip_rtx, insn));
853290075Sobrien	  /* Add a USE to stop propagate_one_insn() from barfing.  */
853390075Sobrien	  emit_insn (gen_prologue_use (ip_rtx));
853490075Sobrien	}
853590075Sobrien    }
853690075Sobrien
8537117395Skan  amount = GEN_INT (-(arm_get_frame_size ()
853890075Sobrien		      + current_function_outgoing_args_size));
853990075Sobrien
854090075Sobrien  if (amount != const0_rtx)
854190075Sobrien    {
854290075Sobrien      /* This add can produce multiple insns for a large constant, so we
854390075Sobrien	 need to get tricky.  */
854490075Sobrien      rtx last = get_last_insn ();
854590075Sobrien      insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
854690075Sobrien				    amount));
854790075Sobrien      do
854890075Sobrien	{
854990075Sobrien	  last = last ? NEXT_INSN (last) : get_insns ();
855090075Sobrien	  RTX_FRAME_RELATED_P (last) = 1;
855190075Sobrien	}
855290075Sobrien      while (last != insn);
855390075Sobrien
855490075Sobrien      /* If the frame pointer is needed, emit a special barrier that
855590075Sobrien	 will prevent the scheduler from moving stores to the frame
855690075Sobrien	 before the stack adjustment.  */
855790075Sobrien      if (frame_pointer_needed)
8558117395Skan	insn = emit_insn (gen_stack_tie (stack_pointer_rtx,
8559117395Skan					 hard_frame_pointer_rtx));
856090075Sobrien    }
856190075Sobrien
856290075Sobrien  /* If we are profiling, make sure no instructions are scheduled before
856390075Sobrien     the call to mcount.  Similarly if the user has requested no
856490075Sobrien     scheduling in the prolog.  */
856590075Sobrien  if (current_function_profile || TARGET_NO_SCHED_PRO)
856690075Sobrien    emit_insn (gen_blockage ());
856790075Sobrien
856890075Sobrien  /* If the link register is being kept alive, with the return address in it,
856990075Sobrien     then make sure that it does not get reused by the ce2 pass.  */
857090075Sobrien  if ((live_regs_mask & (1 << LR_REGNUM)) == 0)
857190075Sobrien    {
857290075Sobrien      emit_insn (gen_prologue_use (gen_rtx_REG (SImode, LR_REGNUM)));
857390075Sobrien      cfun->machine->lr_save_eliminated = 1;
857490075Sobrien    }
857590075Sobrien}
857690075Sobrien
857790075Sobrien/* If CODE is 'd', then the X is a condition operand and the instruction
857890075Sobrien   should only be executed if the condition is true.
857990075Sobrien   if CODE is 'D', then the X is a condition operand and the instruction
858090075Sobrien   should only be executed if the condition is false: however, if the mode
858190075Sobrien   of the comparison is CCFPEmode, then always execute the instruction -- we
858290075Sobrien   do this because in these circumstances !GE does not necessarily imply LT;
858390075Sobrien   in these cases the instruction pattern will take care to make sure that
858490075Sobrien   an instruction containing %d will follow, thereby undoing the effects of
858590075Sobrien   doing this instruction unconditionally.
858690075Sobrien   If CODE is 'N' then X is a floating point operand that must be negated
858790075Sobrien   before output.
858890075Sobrien   If CODE is 'B' then output a bitwise inverted value of X (a const int).
858990075Sobrien   If X is a REG and CODE is `M', output a ldm/stm style multi-reg.  */
859090075Sobrien
859190075Sobrienvoid
859290075Sobrienarm_print_operand (stream, x, code)
859390075Sobrien     FILE * stream;
859490075Sobrien     rtx x;
859590075Sobrien     int code;
859690075Sobrien{
859790075Sobrien  switch (code)
859890075Sobrien    {
859990075Sobrien    case '@':
860090075Sobrien      fputs (ASM_COMMENT_START, stream);
860190075Sobrien      return;
860290075Sobrien
860390075Sobrien    case '_':
860490075Sobrien      fputs (user_label_prefix, stream);
860590075Sobrien      return;
860690075Sobrien
860790075Sobrien    case '|':
860890075Sobrien      fputs (REGISTER_PREFIX, stream);
860990075Sobrien      return;
861090075Sobrien
861190075Sobrien    case '?':
861290075Sobrien      if (arm_ccfsm_state == 3 || arm_ccfsm_state == 4)
861390075Sobrien	{
861490075Sobrien	  if (TARGET_THUMB || current_insn_predicate != NULL)
861590075Sobrien	    abort ();
861690075Sobrien
861790075Sobrien	  fputs (arm_condition_codes[arm_current_cc], stream);
861890075Sobrien	}
861990075Sobrien      else if (current_insn_predicate)
862090075Sobrien	{
862190075Sobrien	  enum arm_cond_code code;
862290075Sobrien
862390075Sobrien	  if (TARGET_THUMB)
862490075Sobrien	    abort ();
862590075Sobrien
862690075Sobrien	  code = get_arm_condition_code (current_insn_predicate);
862790075Sobrien	  fputs (arm_condition_codes[code], stream);
862890075Sobrien	}
862990075Sobrien      return;
863090075Sobrien
863190075Sobrien    case 'N':
863290075Sobrien      {
863390075Sobrien	REAL_VALUE_TYPE r;
863490075Sobrien	REAL_VALUE_FROM_CONST_DOUBLE (r, x);
863590075Sobrien	r = REAL_VALUE_NEGATE (r);
863690075Sobrien	fprintf (stream, "%s", fp_const_from_val (&r));
863790075Sobrien      }
863890075Sobrien      return;
863990075Sobrien
864090075Sobrien    case 'B':
864190075Sobrien      if (GET_CODE (x) == CONST_INT)
864290075Sobrien	{
864390075Sobrien	  HOST_WIDE_INT val;
864490075Sobrien	  val = ARM_SIGN_EXTEND (~INTVAL (x));
864590075Sobrien	  fprintf (stream, HOST_WIDE_INT_PRINT_DEC, val);
864690075Sobrien	}
864790075Sobrien      else
864890075Sobrien	{
864990075Sobrien	  putc ('~', stream);
865090075Sobrien	  output_addr_const (stream, x);
865190075Sobrien	}
865290075Sobrien      return;
865390075Sobrien
865490075Sobrien    case 'i':
865590075Sobrien      fprintf (stream, "%s", arithmetic_instr (x, 1));
865690075Sobrien      return;
865790075Sobrien
865890075Sobrien    case 'I':
865990075Sobrien      fprintf (stream, "%s", arithmetic_instr (x, 0));
866090075Sobrien      return;
866190075Sobrien
866290075Sobrien    case 'S':
866390075Sobrien      {
866490075Sobrien	HOST_WIDE_INT val;
866590075Sobrien	const char * shift = shift_op (x, &val);
866690075Sobrien
866790075Sobrien	if (shift)
866890075Sobrien	  {
866990075Sobrien	    fprintf (stream, ", %s ", shift_op (x, &val));
867090075Sobrien	    if (val == -1)
867190075Sobrien	      arm_print_operand (stream, XEXP (x, 1), 0);
867290075Sobrien	    else
867390075Sobrien	      {
867490075Sobrien		fputc ('#', stream);
867590075Sobrien		fprintf (stream, HOST_WIDE_INT_PRINT_DEC, val);
867690075Sobrien	      }
867790075Sobrien	  }
867890075Sobrien      }
867990075Sobrien      return;
868090075Sobrien
868190075Sobrien      /* An explanation of the 'Q', 'R' and 'H' register operands:
868290075Sobrien
868390075Sobrien	 In a pair of registers containing a DI or DF value the 'Q'
868490075Sobrien	 operand returns the register number of the register containing
868590075Sobrien	 the least signficant part of the value.  The 'R' operand returns
868690075Sobrien	 the register number of the register containing the most
868790075Sobrien	 significant part of the value.
868890075Sobrien
868990075Sobrien	 The 'H' operand returns the higher of the two register numbers.
869090075Sobrien	 On a run where WORDS_BIG_ENDIAN is true the 'H' operand is the
869190075Sobrien	 same as the 'Q' operand, since the most signficant part of the
869290075Sobrien	 value is held in the lower number register.  The reverse is true
869390075Sobrien	 on systems where WORDS_BIG_ENDIAN is false.
869490075Sobrien
869590075Sobrien	 The purpose of these operands is to distinguish between cases
869690075Sobrien	 where the endian-ness of the values is important (for example
869790075Sobrien	 when they are added together), and cases where the endian-ness
869890075Sobrien	 is irrelevant, but the order of register operations is important.
869990075Sobrien	 For example when loading a value from memory into a register
870090075Sobrien	 pair, the endian-ness does not matter.  Provided that the value
870190075Sobrien	 from the lower memory address is put into the lower numbered
870290075Sobrien	 register, and the value from the higher address is put into the
870390075Sobrien	 higher numbered register, the load will work regardless of whether
870490075Sobrien	 the value being loaded is big-wordian or little-wordian.  The
870590075Sobrien	 order of the two register loads can matter however, if the address
870690075Sobrien	 of the memory location is actually held in one of the registers
870790075Sobrien	 being overwritten by the load.  */
870890075Sobrien    case 'Q':
870990075Sobrien      if (REGNO (x) > LAST_ARM_REGNUM)
871090075Sobrien	abort ();
871190075Sobrien      asm_fprintf (stream, "%r", REGNO (x) + (WORDS_BIG_ENDIAN ? 1 : 0));
871290075Sobrien      return;
871390075Sobrien
871490075Sobrien    case 'R':
871590075Sobrien      if (REGNO (x) > LAST_ARM_REGNUM)
871690075Sobrien	abort ();
871790075Sobrien      asm_fprintf (stream, "%r", REGNO (x) + (WORDS_BIG_ENDIAN ? 0 : 1));
871890075Sobrien      return;
871990075Sobrien
872090075Sobrien    case 'H':
872190075Sobrien      if (REGNO (x) > LAST_ARM_REGNUM)
872290075Sobrien	abort ();
872390075Sobrien      asm_fprintf (stream, "%r", REGNO (x) + 1);
872490075Sobrien      return;
872590075Sobrien
872690075Sobrien    case 'm':
872790075Sobrien      asm_fprintf (stream, "%r",
872890075Sobrien		   GET_CODE (XEXP (x, 0)) == REG
872990075Sobrien		   ? REGNO (XEXP (x, 0)) : REGNO (XEXP (XEXP (x, 0), 0)));
873090075Sobrien      return;
873190075Sobrien
873290075Sobrien    case 'M':
873390075Sobrien      asm_fprintf (stream, "{%r-%r}",
873490075Sobrien		   REGNO (x),
8735117395Skan		   REGNO (x) + ARM_NUM_REGS (GET_MODE (x)) - 1);
873690075Sobrien      return;
873790075Sobrien
873890075Sobrien    case 'd':
8739117395Skan      /* CONST_TRUE_RTX means always -- that's the default.  */
8740117395Skan      if (x == const_true_rtx)
874190075Sobrien	return;
874290075Sobrien
874390075Sobrien      if (TARGET_ARM)
874490075Sobrien        fputs (arm_condition_codes[get_arm_condition_code (x)],
874590075Sobrien	       stream);
874690075Sobrien      else
874790075Sobrien	fputs (thumb_condition_code (x, 0), stream);
874890075Sobrien      return;
874990075Sobrien
875090075Sobrien    case 'D':
8751117395Skan      /* CONST_TRUE_RTX means not always -- ie never.  We shouldn't ever
8752117395Skan	 want to do that.  */
8753117395Skan      if (x == const_true_rtx)
8754117395Skan	abort ();
875590075Sobrien
875690075Sobrien      if (TARGET_ARM)
875790075Sobrien	fputs (arm_condition_codes[ARM_INVERSE_CONDITION_CODE
875890075Sobrien				  (get_arm_condition_code (x))],
875990075Sobrien	       stream);
876090075Sobrien      else
876190075Sobrien	fputs (thumb_condition_code (x, 1), stream);
876290075Sobrien      return;
876390075Sobrien
876490075Sobrien    default:
876590075Sobrien      if (x == 0)
876690075Sobrien	abort ();
876790075Sobrien
876890075Sobrien      if (GET_CODE (x) == REG)
876990075Sobrien	asm_fprintf (stream, "%r", REGNO (x));
877090075Sobrien      else if (GET_CODE (x) == MEM)
877190075Sobrien	{
877290075Sobrien	  output_memory_reference_mode = GET_MODE (x);
877390075Sobrien	  output_address (XEXP (x, 0));
877490075Sobrien	}
877590075Sobrien      else if (GET_CODE (x) == CONST_DOUBLE)
877690075Sobrien	fprintf (stream, "#%s", fp_immediate_constant (x));
877790075Sobrien      else if (GET_CODE (x) == NEG)
877890075Sobrien	abort (); /* This should never happen now.  */
877990075Sobrien      else
878090075Sobrien	{
878190075Sobrien	  fputc ('#', stream);
878290075Sobrien	  output_addr_const (stream, x);
878390075Sobrien	}
878490075Sobrien    }
878590075Sobrien}
878690075Sobrien
878790075Sobrien#ifndef AOF_ASSEMBLER
878890075Sobrien/* Target hook for assembling integer objects.  The ARM version needs to
878990075Sobrien   handle word-sized values specially.  */
879090075Sobrien
879190075Sobrienstatic bool
879290075Sobrienarm_assemble_integer (x, size, aligned_p)
879390075Sobrien     rtx x;
879490075Sobrien     unsigned int size;
879590075Sobrien     int aligned_p;
879690075Sobrien{
879790075Sobrien  if (size == UNITS_PER_WORD && aligned_p)
879890075Sobrien    {
879990075Sobrien      fputs ("\t.word\t", asm_out_file);
880090075Sobrien      output_addr_const (asm_out_file, x);
880190075Sobrien
880290075Sobrien      /* Mark symbols as position independent.  We only do this in the
880390075Sobrien	 .text segment, not in the .data segment. */
880490075Sobrien      if (NEED_GOT_RELOC && flag_pic && making_const_table &&
880590075Sobrien	  (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF))
880690075Sobrien	{
8807117395Skan	  if (GET_CODE (x) == SYMBOL_REF
880896263Sobrien	      && (CONSTANT_POOL_ADDRESS_P (x)
880996263Sobrien		  || ENCODED_SHORT_CALL_ATTR_P (XSTR (x, 0))))
881090075Sobrien	    fputs ("(GOTOFF)", asm_out_file);
881190075Sobrien	  else if (GET_CODE (x) == LABEL_REF)
881290075Sobrien	    fputs ("(GOTOFF)", asm_out_file);
881390075Sobrien	  else
881490075Sobrien	    fputs ("(GOT)", asm_out_file);
881590075Sobrien	}
881690075Sobrien      fputc ('\n', asm_out_file);
881790075Sobrien      return true;
881890075Sobrien    }
881990075Sobrien
882090075Sobrien  return default_assemble_integer (x, size, aligned_p);
882190075Sobrien}
882290075Sobrien#endif
882390075Sobrien
882490075Sobrien/* A finite state machine takes care of noticing whether or not instructions
882590075Sobrien   can be conditionally executed, and thus decrease execution time and code
882690075Sobrien   size by deleting branch instructions.  The fsm is controlled by
882790075Sobrien   final_prescan_insn, and controls the actions of ASM_OUTPUT_OPCODE.  */
882890075Sobrien
882990075Sobrien/* The state of the fsm controlling condition codes are:
883090075Sobrien   0: normal, do nothing special
883190075Sobrien   1: make ASM_OUTPUT_OPCODE not output this instruction
883290075Sobrien   2: make ASM_OUTPUT_OPCODE not output this instruction
883390075Sobrien   3: make instructions conditional
883490075Sobrien   4: make instructions conditional
883590075Sobrien
883690075Sobrien   State transitions (state->state by whom under condition):
883790075Sobrien   0 -> 1 final_prescan_insn if the `target' is a label
883890075Sobrien   0 -> 2 final_prescan_insn if the `target' is an unconditional branch
883990075Sobrien   1 -> 3 ASM_OUTPUT_OPCODE after not having output the conditional branch
884090075Sobrien   2 -> 4 ASM_OUTPUT_OPCODE after not having output the conditional branch
884190075Sobrien   3 -> 0 ASM_OUTPUT_INTERNAL_LABEL if the `target' label is reached
884290075Sobrien          (the target label has CODE_LABEL_NUMBER equal to arm_target_label).
884390075Sobrien   4 -> 0 final_prescan_insn if the `target' unconditional branch is reached
884490075Sobrien          (the target insn is arm_target_insn).
884590075Sobrien
884690075Sobrien   If the jump clobbers the conditions then we use states 2 and 4.
884790075Sobrien
884890075Sobrien   A similar thing can be done with conditional return insns.
884990075Sobrien
885090075Sobrien   XXX In case the `target' is an unconditional branch, this conditionalising
885190075Sobrien   of the instructions always reduces code size, but not always execution
885290075Sobrien   time.  But then, I want to reduce the code size to somewhere near what
885390075Sobrien   /bin/cc produces.  */
885490075Sobrien
885590075Sobrien/* Returns the index of the ARM condition code string in
885690075Sobrien   `arm_condition_codes'.  COMPARISON should be an rtx like
885790075Sobrien   `(eq (...) (...))'.  */
885890075Sobrien
885990075Sobrienstatic enum arm_cond_code
886090075Sobrienget_arm_condition_code (comparison)
886190075Sobrien     rtx comparison;
886290075Sobrien{
886390075Sobrien  enum machine_mode mode = GET_MODE (XEXP (comparison, 0));
886490075Sobrien  int code;
886590075Sobrien  enum rtx_code comp_code = GET_CODE (comparison);
886690075Sobrien
886790075Sobrien  if (GET_MODE_CLASS (mode) != MODE_CC)
886890075Sobrien    mode = SELECT_CC_MODE (comp_code, XEXP (comparison, 0),
886990075Sobrien			   XEXP (comparison, 1));
887090075Sobrien
887190075Sobrien  switch (mode)
887290075Sobrien    {
887390075Sobrien    case CC_DNEmode: code = ARM_NE; goto dominance;
887490075Sobrien    case CC_DEQmode: code = ARM_EQ; goto dominance;
887590075Sobrien    case CC_DGEmode: code = ARM_GE; goto dominance;
887690075Sobrien    case CC_DGTmode: code = ARM_GT; goto dominance;
887790075Sobrien    case CC_DLEmode: code = ARM_LE; goto dominance;
887890075Sobrien    case CC_DLTmode: code = ARM_LT; goto dominance;
887990075Sobrien    case CC_DGEUmode: code = ARM_CS; goto dominance;
888090075Sobrien    case CC_DGTUmode: code = ARM_HI; goto dominance;
888190075Sobrien    case CC_DLEUmode: code = ARM_LS; goto dominance;
888290075Sobrien    case CC_DLTUmode: code = ARM_CC;
888390075Sobrien
888490075Sobrien    dominance:
888590075Sobrien      if (comp_code != EQ && comp_code != NE)
888690075Sobrien	abort ();
888790075Sobrien
888890075Sobrien      if (comp_code == EQ)
888990075Sobrien	return ARM_INVERSE_CONDITION_CODE (code);
889090075Sobrien      return code;
889190075Sobrien
889290075Sobrien    case CC_NOOVmode:
889390075Sobrien      switch (comp_code)
889490075Sobrien	{
889590075Sobrien	case NE: return ARM_NE;
889690075Sobrien	case EQ: return ARM_EQ;
889790075Sobrien	case GE: return ARM_PL;
889890075Sobrien	case LT: return ARM_MI;
889990075Sobrien	default: abort ();
890090075Sobrien	}
890190075Sobrien
890290075Sobrien    case CC_Zmode:
890390075Sobrien      switch (comp_code)
890490075Sobrien	{
890590075Sobrien	case NE: return ARM_NE;
890690075Sobrien	case EQ: return ARM_EQ;
890790075Sobrien	default: abort ();
890890075Sobrien	}
890990075Sobrien
891090075Sobrien    case CCFPEmode:
891190075Sobrien    case CCFPmode:
891290075Sobrien      /* These encodings assume that AC=1 in the FPA system control
891390075Sobrien	 byte.  This allows us to handle all cases except UNEQ and
891490075Sobrien	 LTGT.  */
891590075Sobrien      switch (comp_code)
891690075Sobrien	{
891790075Sobrien	case GE: return ARM_GE;
891890075Sobrien	case GT: return ARM_GT;
891990075Sobrien	case LE: return ARM_LS;
892090075Sobrien	case LT: return ARM_MI;
892190075Sobrien	case NE: return ARM_NE;
892290075Sobrien	case EQ: return ARM_EQ;
892390075Sobrien	case ORDERED: return ARM_VC;
892490075Sobrien	case UNORDERED: return ARM_VS;
892590075Sobrien	case UNLT: return ARM_LT;
892690075Sobrien	case UNLE: return ARM_LE;
892790075Sobrien	case UNGT: return ARM_HI;
892890075Sobrien	case UNGE: return ARM_PL;
892990075Sobrien	  /* UNEQ and LTGT do not have a representation.  */
893090075Sobrien	case UNEQ: /* Fall through.  */
893190075Sobrien	case LTGT: /* Fall through.  */
893290075Sobrien	default: abort ();
893390075Sobrien	}
893490075Sobrien
893590075Sobrien    case CC_SWPmode:
893690075Sobrien      switch (comp_code)
893790075Sobrien	{
893890075Sobrien	case NE: return ARM_NE;
893990075Sobrien	case EQ: return ARM_EQ;
894090075Sobrien	case GE: return ARM_LE;
894190075Sobrien	case GT: return ARM_LT;
894290075Sobrien	case LE: return ARM_GE;
894390075Sobrien	case LT: return ARM_GT;
894490075Sobrien	case GEU: return ARM_LS;
894590075Sobrien	case GTU: return ARM_CC;
894690075Sobrien	case LEU: return ARM_CS;
894790075Sobrien	case LTU: return ARM_HI;
894890075Sobrien	default: abort ();
894990075Sobrien	}
895090075Sobrien
895190075Sobrien    case CC_Cmode:
895290075Sobrien      switch (comp_code)
895390075Sobrien      {
895490075Sobrien      case LTU: return ARM_CS;
895590075Sobrien      case GEU: return ARM_CC;
895690075Sobrien      default: abort ();
895790075Sobrien      }
895890075Sobrien
895990075Sobrien    case CCmode:
896090075Sobrien      switch (comp_code)
896190075Sobrien	{
896290075Sobrien	case NE: return ARM_NE;
896390075Sobrien	case EQ: return ARM_EQ;
896490075Sobrien	case GE: return ARM_GE;
896590075Sobrien	case GT: return ARM_GT;
896690075Sobrien	case LE: return ARM_LE;
896790075Sobrien	case LT: return ARM_LT;
896890075Sobrien	case GEU: return ARM_CS;
896990075Sobrien	case GTU: return ARM_HI;
897090075Sobrien	case LEU: return ARM_LS;
897190075Sobrien	case LTU: return ARM_CC;
897290075Sobrien	default: abort ();
897390075Sobrien	}
897490075Sobrien
897590075Sobrien    default: abort ();
897690075Sobrien    }
897790075Sobrien
897890075Sobrien  abort ();
897990075Sobrien}
898090075Sobrien
898190075Sobrien
898290075Sobrienvoid
898390075Sobrienarm_final_prescan_insn (insn)
898490075Sobrien     rtx insn;
898590075Sobrien{
898690075Sobrien  /* BODY will hold the body of INSN.  */
898790075Sobrien  rtx body = PATTERN (insn);
898890075Sobrien
898990075Sobrien  /* This will be 1 if trying to repeat the trick, and things need to be
899090075Sobrien     reversed if it appears to fail.  */
899190075Sobrien  int reverse = 0;
899290075Sobrien
899390075Sobrien  /* JUMP_CLOBBERS will be one implies that the conditions if a branch is
899490075Sobrien     taken are clobbered, even if the rtl suggests otherwise.  It also
899590075Sobrien     means that we have to grub around within the jump expression to find
899690075Sobrien     out what the conditions are when the jump isn't taken.  */
899790075Sobrien  int jump_clobbers = 0;
899890075Sobrien
899990075Sobrien  /* If we start with a return insn, we only succeed if we find another one.  */
900090075Sobrien  int seeking_return = 0;
900190075Sobrien
900290075Sobrien  /* START_INSN will hold the insn from where we start looking.  This is the
900390075Sobrien     first insn after the following code_label if REVERSE is true.  */
900490075Sobrien  rtx start_insn = insn;
900590075Sobrien
900690075Sobrien  /* If in state 4, check if the target branch is reached, in order to
900790075Sobrien     change back to state 0.  */
900890075Sobrien  if (arm_ccfsm_state == 4)
900990075Sobrien    {
901090075Sobrien      if (insn == arm_target_insn)
901190075Sobrien	{
901290075Sobrien	  arm_target_insn = NULL;
901390075Sobrien	  arm_ccfsm_state = 0;
901490075Sobrien	}
901590075Sobrien      return;
901690075Sobrien    }
901790075Sobrien
901890075Sobrien  /* If in state 3, it is possible to repeat the trick, if this insn is an
901990075Sobrien     unconditional branch to a label, and immediately following this branch
902090075Sobrien     is the previous target label which is only used once, and the label this
902190075Sobrien     branch jumps to is not too far off.  */
902290075Sobrien  if (arm_ccfsm_state == 3)
902390075Sobrien    {
902490075Sobrien      if (simplejump_p (insn))
902590075Sobrien	{
902690075Sobrien	  start_insn = next_nonnote_insn (start_insn);
902790075Sobrien	  if (GET_CODE (start_insn) == BARRIER)
902890075Sobrien	    {
902990075Sobrien	      /* XXX Isn't this always a barrier?  */
903090075Sobrien	      start_insn = next_nonnote_insn (start_insn);
903190075Sobrien	    }
903290075Sobrien	  if (GET_CODE (start_insn) == CODE_LABEL
903390075Sobrien	      && CODE_LABEL_NUMBER (start_insn) == arm_target_label
903490075Sobrien	      && LABEL_NUSES (start_insn) == 1)
903590075Sobrien	    reverse = TRUE;
903690075Sobrien	  else
903790075Sobrien	    return;
903890075Sobrien	}
903990075Sobrien      else if (GET_CODE (body) == RETURN)
904090075Sobrien        {
904190075Sobrien	  start_insn = next_nonnote_insn (start_insn);
904290075Sobrien	  if (GET_CODE (start_insn) == BARRIER)
904390075Sobrien	    start_insn = next_nonnote_insn (start_insn);
904490075Sobrien	  if (GET_CODE (start_insn) == CODE_LABEL
904590075Sobrien	      && CODE_LABEL_NUMBER (start_insn) == arm_target_label
904690075Sobrien	      && LABEL_NUSES (start_insn) == 1)
904790075Sobrien	    {
904890075Sobrien	      reverse = TRUE;
904990075Sobrien	      seeking_return = 1;
905090075Sobrien	    }
905190075Sobrien	  else
905290075Sobrien	    return;
905390075Sobrien        }
905490075Sobrien      else
905590075Sobrien	return;
905690075Sobrien    }
905790075Sobrien
905890075Sobrien  if (arm_ccfsm_state != 0 && !reverse)
905990075Sobrien    abort ();
906090075Sobrien  if (GET_CODE (insn) != JUMP_INSN)
906190075Sobrien    return;
906290075Sobrien
906390075Sobrien  /* This jump might be paralleled with a clobber of the condition codes
906490075Sobrien     the jump should always come first */
906590075Sobrien  if (GET_CODE (body) == PARALLEL && XVECLEN (body, 0) > 0)
906690075Sobrien    body = XVECEXP (body, 0, 0);
906790075Sobrien
906890075Sobrien#if 0
906990075Sobrien  /* If this is a conditional return then we don't want to know */
907090075Sobrien  if (GET_CODE (body) == SET && GET_CODE (SET_DEST (body)) == PC
907190075Sobrien      && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE
907290075Sobrien      && (GET_CODE (XEXP (SET_SRC (body), 1)) == RETURN
907390075Sobrien          || GET_CODE (XEXP (SET_SRC (body), 2)) == RETURN))
907490075Sobrien    return;
907590075Sobrien#endif
907690075Sobrien
907790075Sobrien  if (reverse
907890075Sobrien      || (GET_CODE (body) == SET && GET_CODE (SET_DEST (body)) == PC
907990075Sobrien	  && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE))
908090075Sobrien    {
908190075Sobrien      int insns_skipped;
908290075Sobrien      int fail = FALSE, succeed = FALSE;
908390075Sobrien      /* Flag which part of the IF_THEN_ELSE is the LABEL_REF.  */
908490075Sobrien      int then_not_else = TRUE;
908590075Sobrien      rtx this_insn = start_insn, label = 0;
908690075Sobrien
908790075Sobrien      /* If the jump cannot be done with one instruction, we cannot
908890075Sobrien	 conditionally execute the instruction in the inverse case.  */
908990075Sobrien      if (get_attr_conds (insn) == CONDS_JUMP_CLOB)
909090075Sobrien	{
909190075Sobrien	  jump_clobbers = 1;
909290075Sobrien	  return;
909390075Sobrien	}
909490075Sobrien
909590075Sobrien      /* Register the insn jumped to.  */
909690075Sobrien      if (reverse)
909790075Sobrien        {
909890075Sobrien	  if (!seeking_return)
909990075Sobrien	    label = XEXP (SET_SRC (body), 0);
910090075Sobrien        }
910190075Sobrien      else if (GET_CODE (XEXP (SET_SRC (body), 1)) == LABEL_REF)
910290075Sobrien	label = XEXP (XEXP (SET_SRC (body), 1), 0);
910390075Sobrien      else if (GET_CODE (XEXP (SET_SRC (body), 2)) == LABEL_REF)
910490075Sobrien	{
910590075Sobrien	  label = XEXP (XEXP (SET_SRC (body), 2), 0);
910690075Sobrien	  then_not_else = FALSE;
910790075Sobrien	}
910890075Sobrien      else if (GET_CODE (XEXP (SET_SRC (body), 1)) == RETURN)
910990075Sobrien	seeking_return = 1;
911090075Sobrien      else if (GET_CODE (XEXP (SET_SRC (body), 2)) == RETURN)
911190075Sobrien        {
911290075Sobrien	  seeking_return = 1;
911390075Sobrien	  then_not_else = FALSE;
911490075Sobrien        }
911590075Sobrien      else
911690075Sobrien	abort ();
911790075Sobrien
911890075Sobrien      /* See how many insns this branch skips, and what kind of insns.  If all
911990075Sobrien	 insns are okay, and the label or unconditional branch to the same
912090075Sobrien	 label is not too far away, succeed.  */
912190075Sobrien      for (insns_skipped = 0;
912290075Sobrien	   !fail && !succeed && insns_skipped++ < max_insns_skipped;)
912390075Sobrien	{
912490075Sobrien	  rtx scanbody;
912590075Sobrien
912690075Sobrien	  this_insn = next_nonnote_insn (this_insn);
912790075Sobrien	  if (!this_insn)
912890075Sobrien	    break;
912990075Sobrien
913090075Sobrien	  switch (GET_CODE (this_insn))
913190075Sobrien	    {
913290075Sobrien	    case CODE_LABEL:
913390075Sobrien	      /* Succeed if it is the target label, otherwise fail since
913490075Sobrien		 control falls in from somewhere else.  */
913590075Sobrien	      if (this_insn == label)
913690075Sobrien		{
913790075Sobrien		  if (jump_clobbers)
913890075Sobrien		    {
913990075Sobrien		      arm_ccfsm_state = 2;
914090075Sobrien		      this_insn = next_nonnote_insn (this_insn);
914190075Sobrien		    }
914290075Sobrien		  else
914390075Sobrien		    arm_ccfsm_state = 1;
914490075Sobrien		  succeed = TRUE;
914590075Sobrien		}
914690075Sobrien	      else
914790075Sobrien		fail = TRUE;
914890075Sobrien	      break;
914990075Sobrien
915090075Sobrien	    case BARRIER:
915190075Sobrien	      /* Succeed if the following insn is the target label.
915290075Sobrien		 Otherwise fail.
915390075Sobrien		 If return insns are used then the last insn in a function
915490075Sobrien		 will be a barrier.  */
915590075Sobrien	      this_insn = next_nonnote_insn (this_insn);
915690075Sobrien	      if (this_insn && this_insn == label)
915790075Sobrien		{
915890075Sobrien		  if (jump_clobbers)
915990075Sobrien		    {
916090075Sobrien		      arm_ccfsm_state = 2;
916190075Sobrien		      this_insn = next_nonnote_insn (this_insn);
916290075Sobrien		    }
916390075Sobrien		  else
916490075Sobrien		    arm_ccfsm_state = 1;
916590075Sobrien		  succeed = TRUE;
916690075Sobrien		}
916790075Sobrien	      else
916890075Sobrien		fail = TRUE;
916990075Sobrien	      break;
917090075Sobrien
917190075Sobrien	    case CALL_INSN:
917290075Sobrien	      /* If using 32-bit addresses the cc is not preserved over
917390075Sobrien		 calls.  */
917490075Sobrien	      if (TARGET_APCS_32)
917590075Sobrien		{
917690075Sobrien		  /* Succeed if the following insn is the target label,
917790075Sobrien		     or if the following two insns are a barrier and
917890075Sobrien		     the target label.  */
917990075Sobrien		  this_insn = next_nonnote_insn (this_insn);
918090075Sobrien		  if (this_insn && GET_CODE (this_insn) == BARRIER)
918190075Sobrien		    this_insn = next_nonnote_insn (this_insn);
918290075Sobrien
918390075Sobrien		  if (this_insn && this_insn == label
918490075Sobrien		      && insns_skipped < max_insns_skipped)
918590075Sobrien		    {
918690075Sobrien		      if (jump_clobbers)
918790075Sobrien			{
918890075Sobrien			  arm_ccfsm_state = 2;
918990075Sobrien			  this_insn = next_nonnote_insn (this_insn);
919090075Sobrien			}
919190075Sobrien		      else
919290075Sobrien			arm_ccfsm_state = 1;
919390075Sobrien		      succeed = TRUE;
919490075Sobrien		    }
919590075Sobrien		  else
919690075Sobrien		    fail = TRUE;
919790075Sobrien		}
919890075Sobrien	      break;
919990075Sobrien
920090075Sobrien	    case JUMP_INSN:
920190075Sobrien      	      /* If this is an unconditional branch to the same label, succeed.
920290075Sobrien		 If it is to another label, do nothing.  If it is conditional,
920390075Sobrien		 fail.  */
920490075Sobrien	      /* XXX Probably, the tests for SET and the PC are unnecessary.  */
920590075Sobrien
920690075Sobrien	      scanbody = PATTERN (this_insn);
920790075Sobrien	      if (GET_CODE (scanbody) == SET
920890075Sobrien		  && GET_CODE (SET_DEST (scanbody)) == PC)
920990075Sobrien		{
921090075Sobrien		  if (GET_CODE (SET_SRC (scanbody)) == LABEL_REF
921190075Sobrien		      && XEXP (SET_SRC (scanbody), 0) == label && !reverse)
921290075Sobrien		    {
921390075Sobrien		      arm_ccfsm_state = 2;
921490075Sobrien		      succeed = TRUE;
921590075Sobrien		    }
921690075Sobrien		  else if (GET_CODE (SET_SRC (scanbody)) == IF_THEN_ELSE)
921790075Sobrien		    fail = TRUE;
921890075Sobrien		}
921990075Sobrien	      /* Fail if a conditional return is undesirable (eg on a
922090075Sobrien		 StrongARM), but still allow this if optimizing for size.  */
922190075Sobrien	      else if (GET_CODE (scanbody) == RETURN
922290075Sobrien		       && !use_return_insn (TRUE)
922390075Sobrien		       && !optimize_size)
922490075Sobrien		fail = TRUE;
922590075Sobrien	      else if (GET_CODE (scanbody) == RETURN
922690075Sobrien		       && seeking_return)
922790075Sobrien	        {
922890075Sobrien		  arm_ccfsm_state = 2;
922990075Sobrien		  succeed = TRUE;
923090075Sobrien	        }
923190075Sobrien	      else if (GET_CODE (scanbody) == PARALLEL)
923290075Sobrien	        {
923390075Sobrien		  switch (get_attr_conds (this_insn))
923490075Sobrien		    {
923590075Sobrien		    case CONDS_NOCOND:
923690075Sobrien		      break;
923790075Sobrien		    default:
923890075Sobrien		      fail = TRUE;
923990075Sobrien		      break;
924090075Sobrien		    }
924190075Sobrien		}
924290075Sobrien	      else
924390075Sobrien		fail = TRUE;	/* Unrecognized jump (eg epilogue).  */
924490075Sobrien
924590075Sobrien	      break;
924690075Sobrien
924790075Sobrien	    case INSN:
924890075Sobrien	      /* Instructions using or affecting the condition codes make it
924990075Sobrien		 fail.  */
925090075Sobrien	      scanbody = PATTERN (this_insn);
925190075Sobrien	      if (!(GET_CODE (scanbody) == SET
925290075Sobrien		    || GET_CODE (scanbody) == PARALLEL)
925390075Sobrien		  || get_attr_conds (this_insn) != CONDS_NOCOND)
925490075Sobrien		fail = TRUE;
925590075Sobrien	      break;
925690075Sobrien
925790075Sobrien	    default:
925890075Sobrien	      break;
925990075Sobrien	    }
926090075Sobrien	}
926190075Sobrien      if (succeed)
926290075Sobrien	{
926390075Sobrien	  if ((!seeking_return) && (arm_ccfsm_state == 1 || reverse))
926490075Sobrien	    arm_target_label = CODE_LABEL_NUMBER (label);
926590075Sobrien	  else if (seeking_return || arm_ccfsm_state == 2)
926690075Sobrien	    {
926790075Sobrien	      while (this_insn && GET_CODE (PATTERN (this_insn)) == USE)
926890075Sobrien	        {
926990075Sobrien		  this_insn = next_nonnote_insn (this_insn);
927090075Sobrien		  if (this_insn && (GET_CODE (this_insn) == BARRIER
927190075Sobrien				    || GET_CODE (this_insn) == CODE_LABEL))
927290075Sobrien		    abort ();
927390075Sobrien	        }
927490075Sobrien	      if (!this_insn)
927590075Sobrien	        {
927690075Sobrien		  /* Oh, dear! we ran off the end.. give up */
927790075Sobrien		  recog (PATTERN (insn), insn, NULL);
927890075Sobrien		  arm_ccfsm_state = 0;
927990075Sobrien		  arm_target_insn = NULL;
928090075Sobrien		  return;
928190075Sobrien	        }
928290075Sobrien	      arm_target_insn = this_insn;
928390075Sobrien	    }
928490075Sobrien	  else
928590075Sobrien	    abort ();
928690075Sobrien	  if (jump_clobbers)
928790075Sobrien	    {
928890075Sobrien	      if (reverse)
928990075Sobrien		abort ();
929090075Sobrien	      arm_current_cc =
929190075Sobrien		  get_arm_condition_code (XEXP (XEXP (XEXP (SET_SRC (body),
929290075Sobrien							    0), 0), 1));
929390075Sobrien	      if (GET_CODE (XEXP (XEXP (SET_SRC (body), 0), 0)) == AND)
929490075Sobrien		arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc);
929590075Sobrien	      if (GET_CODE (XEXP (SET_SRC (body), 0)) == NE)
929690075Sobrien		arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc);
929790075Sobrien	    }
929890075Sobrien	  else
929990075Sobrien	    {
930090075Sobrien	      /* If REVERSE is true, ARM_CURRENT_CC needs to be inverted from
930190075Sobrien		 what it was.  */
930290075Sobrien	      if (!reverse)
930390075Sobrien		arm_current_cc = get_arm_condition_code (XEXP (SET_SRC (body),
930490075Sobrien							       0));
930590075Sobrien	    }
930690075Sobrien
930790075Sobrien	  if (reverse || then_not_else)
930890075Sobrien	    arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc);
930990075Sobrien	}
931090075Sobrien
931190075Sobrien      /* Restore recog_data (getting the attributes of other insns can
931290075Sobrien	 destroy this array, but final.c assumes that it remains intact
931390075Sobrien	 across this call; since the insn has been recognized already we
931490075Sobrien	 call recog direct).  */
931590075Sobrien      recog (PATTERN (insn), insn, NULL);
931690075Sobrien    }
931790075Sobrien}
931890075Sobrien
931990075Sobrien/* Returns true if REGNO is a valid register
932090075Sobrien   for holding a quantity of tyoe MODE.  */
932190075Sobrien
932290075Sobrienint
932390075Sobrienarm_hard_regno_mode_ok (regno, mode)
932490075Sobrien     unsigned int regno;
932590075Sobrien     enum machine_mode mode;
932690075Sobrien{
932790075Sobrien  if (GET_MODE_CLASS (mode) == MODE_CC)
932890075Sobrien    return regno == CC_REGNUM;
932990075Sobrien
933090075Sobrien  if (TARGET_THUMB)
933190075Sobrien    /* For the Thumb we only allow values bigger than SImode in
933290075Sobrien       registers 0 - 6, so that there is always a second low
933390075Sobrien       register available to hold the upper part of the value.
933490075Sobrien       We probably we ought to ensure that the register is the
933590075Sobrien       start of an even numbered register pair.  */
9336117395Skan    return (ARM_NUM_REGS (mode) < 2) || (regno < LAST_LO_REGNUM);
933790075Sobrien
933890075Sobrien  if (regno <= LAST_ARM_REGNUM)
933996263Sobrien    /* We allow any value to be stored in the general regisetrs.  */
934096263Sobrien    return 1;
934190075Sobrien
934290075Sobrien  if (   regno == FRAME_POINTER_REGNUM
934390075Sobrien      || regno == ARG_POINTER_REGNUM)
934490075Sobrien    /* We only allow integers in the fake hard registers.  */
934590075Sobrien    return GET_MODE_CLASS (mode) == MODE_INT;
934690075Sobrien
934790075Sobrien  /* The only registers left are the FPU registers
934890075Sobrien     which we only allow to hold FP values.  */
934990075Sobrien  return GET_MODE_CLASS (mode) == MODE_FLOAT
935090075Sobrien    && regno >= FIRST_ARM_FP_REGNUM
935190075Sobrien    && regno <= LAST_ARM_FP_REGNUM;
935290075Sobrien}
935390075Sobrien
935490075Sobrienint
935590075Sobrienarm_regno_class (regno)
935690075Sobrien     int regno;
935790075Sobrien{
935890075Sobrien  if (TARGET_THUMB)
935990075Sobrien    {
936090075Sobrien      if (regno == STACK_POINTER_REGNUM)
936190075Sobrien	return STACK_REG;
936290075Sobrien      if (regno == CC_REGNUM)
936390075Sobrien	return CC_REG;
936490075Sobrien      if (regno < 8)
936590075Sobrien	return LO_REGS;
936690075Sobrien      return HI_REGS;
936790075Sobrien    }
936890075Sobrien
936990075Sobrien  if (   regno <= LAST_ARM_REGNUM
937090075Sobrien      || regno == FRAME_POINTER_REGNUM
937190075Sobrien      || regno == ARG_POINTER_REGNUM)
937290075Sobrien    return GENERAL_REGS;
937390075Sobrien
937490075Sobrien  if (regno == CC_REGNUM)
937590075Sobrien    return NO_REGS;
937690075Sobrien
937790075Sobrien  return FPU_REGS;
937890075Sobrien}
937990075Sobrien
938090075Sobrien/* Handle a special case when computing the offset
938190075Sobrien   of an argument from the frame pointer.  */
938290075Sobrien
938390075Sobrienint
938490075Sobrienarm_debugger_arg_offset (value, addr)
938590075Sobrien     int value;
938690075Sobrien     rtx addr;
938790075Sobrien{
938890075Sobrien  rtx insn;
938990075Sobrien
939090075Sobrien  /* We are only interested if dbxout_parms() failed to compute the offset.  */
939190075Sobrien  if (value != 0)
939290075Sobrien    return 0;
939390075Sobrien
939490075Sobrien  /* We can only cope with the case where the address is held in a register.  */
939590075Sobrien  if (GET_CODE (addr) != REG)
939690075Sobrien    return 0;
939790075Sobrien
939890075Sobrien  /* If we are using the frame pointer to point at the argument, then
939990075Sobrien     an offset of 0 is correct.  */
940090075Sobrien  if (REGNO (addr) == (unsigned) HARD_FRAME_POINTER_REGNUM)
940190075Sobrien    return 0;
940290075Sobrien
940390075Sobrien  /* If we are using the stack pointer to point at the
940490075Sobrien     argument, then an offset of 0 is correct.  */
940590075Sobrien  if ((TARGET_THUMB || !frame_pointer_needed)
940690075Sobrien      && REGNO (addr) == SP_REGNUM)
940790075Sobrien    return 0;
940890075Sobrien
940990075Sobrien  /* Oh dear.  The argument is pointed to by a register rather
941090075Sobrien     than being held in a register, or being stored at a known
941190075Sobrien     offset from the frame pointer.  Since GDB only understands
941290075Sobrien     those two kinds of argument we must translate the address
941390075Sobrien     held in the register into an offset from the frame pointer.
941490075Sobrien     We do this by searching through the insns for the function
941590075Sobrien     looking to see where this register gets its value.  If the
9416117395Skan     register is initialized from the frame pointer plus an offset
941790075Sobrien     then we are in luck and we can continue, otherwise we give up.
941890075Sobrien
941990075Sobrien     This code is exercised by producing debugging information
942090075Sobrien     for a function with arguments like this:
942190075Sobrien
942290075Sobrien           double func (double a, double b, int c, double d) {return d;}
942390075Sobrien
942490075Sobrien     Without this code the stab for parameter 'd' will be set to
942590075Sobrien     an offset of 0 from the frame pointer, rather than 8.  */
942690075Sobrien
942790075Sobrien  /* The if() statement says:
942890075Sobrien
942990075Sobrien     If the insn is a normal instruction
943090075Sobrien     and if the insn is setting the value in a register
943190075Sobrien     and if the register being set is the register holding the address of the argument
943290075Sobrien     and if the address is computing by an addition
943390075Sobrien     that involves adding to a register
943490075Sobrien     which is the frame pointer
943590075Sobrien     a constant integer
943690075Sobrien
943790075Sobrien     then... */
943890075Sobrien
943990075Sobrien  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
944090075Sobrien    {
944190075Sobrien      if (   GET_CODE (insn) == INSN
944290075Sobrien	  && GET_CODE (PATTERN (insn)) == SET
944390075Sobrien	  && REGNO    (XEXP (PATTERN (insn), 0)) == REGNO (addr)
944490075Sobrien	  && GET_CODE (XEXP (PATTERN (insn), 1)) == PLUS
944590075Sobrien	  && GET_CODE (XEXP (XEXP (PATTERN (insn), 1), 0)) == REG
944690075Sobrien	  && REGNO    (XEXP (XEXP (PATTERN (insn), 1), 0)) == (unsigned) HARD_FRAME_POINTER_REGNUM
944790075Sobrien	  && GET_CODE (XEXP (XEXP (PATTERN (insn), 1), 1)) == CONST_INT
944890075Sobrien	     )
944990075Sobrien	{
945090075Sobrien	  value = INTVAL (XEXP (XEXP (PATTERN (insn), 1), 1));
945190075Sobrien
945290075Sobrien	  break;
945390075Sobrien	}
945490075Sobrien    }
945590075Sobrien
945690075Sobrien  if (value == 0)
945790075Sobrien    {
945890075Sobrien      debug_rtx (addr);
945990075Sobrien      warning ("unable to compute real location of stacked parameter");
946090075Sobrien      value = 8; /* XXX magic hack */
946190075Sobrien    }
946290075Sobrien
946390075Sobrien  return value;
946490075Sobrien}
946590075Sobrien
946690075Sobrien#define def_builtin(NAME, TYPE, CODE) \
9467117395Skan  builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, NULL, NULL_TREE)
946890075Sobrien
946990075Sobrienvoid
947090075Sobrienarm_init_builtins ()
947190075Sobrien{
947290075Sobrien  tree endlink = void_list_node;
947390075Sobrien  tree int_endlink = tree_cons (NULL_TREE, integer_type_node, endlink);
947490075Sobrien  tree pchar_type_node = build_pointer_type (char_type_node);
947590075Sobrien
947690075Sobrien  tree int_ftype_int, void_ftype_pchar;
947790075Sobrien
9478117395Skan  /* void func (char *) */
947990075Sobrien  void_ftype_pchar
9480117395Skan    = build_function_type_list (void_type_node, pchar_type_node, NULL_TREE);
948190075Sobrien
948290075Sobrien  /* int func (int) */
948390075Sobrien  int_ftype_int
948490075Sobrien    = build_function_type (integer_type_node, int_endlink);
948590075Sobrien
948690075Sobrien  /* Initialize arm V5 builtins.  */
948790075Sobrien  if (arm_arch5)
948890075Sobrien    def_builtin ("__builtin_clz", int_ftype_int, ARM_BUILTIN_CLZ);
948990075Sobrien}
949090075Sobrien
949190075Sobrien/* Expand an expression EXP that calls a built-in function,
949290075Sobrien   with result going to TARGET if that's convenient
949390075Sobrien   (and in mode MODE if that's convenient).
949490075Sobrien   SUBTARGET may be used as the target for computing one of EXP's operands.
949590075Sobrien   IGNORE is nonzero if the value is to be ignored.  */
949690075Sobrien
949790075Sobrienrtx
949890075Sobrienarm_expand_builtin (exp, target, subtarget, mode, ignore)
949990075Sobrien     tree exp;
950090075Sobrien     rtx target;
950190075Sobrien     rtx subtarget ATTRIBUTE_UNUSED;
950290075Sobrien     enum machine_mode mode ATTRIBUTE_UNUSED;
950390075Sobrien     int ignore ATTRIBUTE_UNUSED;
950490075Sobrien{
950590075Sobrien  enum insn_code icode;
950690075Sobrien  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
950790075Sobrien  tree arglist = TREE_OPERAND (exp, 1);
950890075Sobrien  tree arg0;
950990075Sobrien  rtx op0, pat;
951090075Sobrien  enum machine_mode tmode, mode0;
951190075Sobrien  int fcode = DECL_FUNCTION_CODE (fndecl);
951290075Sobrien
951390075Sobrien  switch (fcode)
951490075Sobrien    {
951590075Sobrien    default:
951690075Sobrien      break;
951790075Sobrien
951890075Sobrien    case ARM_BUILTIN_CLZ:
951990075Sobrien      icode = CODE_FOR_clz;
952090075Sobrien      arg0 = TREE_VALUE (arglist);
952190075Sobrien      op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
952290075Sobrien      tmode = insn_data[icode].operand[0].mode;
952390075Sobrien      mode0 = insn_data[icode].operand[1].mode;
952490075Sobrien
952590075Sobrien      if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
952690075Sobrien	op0 = copy_to_mode_reg (mode0, op0);
952790075Sobrien      if (target == 0
952890075Sobrien	  || GET_MODE (target) != tmode
952990075Sobrien	  || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
953090075Sobrien	target = gen_reg_rtx (tmode);
953190075Sobrien      pat = GEN_FCN (icode) (target, op0);
953290075Sobrien      if (! pat)
953390075Sobrien	return 0;
953490075Sobrien      emit_insn (pat);
953590075Sobrien      return target;
953690075Sobrien    }
9537117395Skan
953890075Sobrien  /* @@@ Should really do something sensible here.  */
953990075Sobrien  return NULL_RTX;
954090075Sobrien}
954190075Sobrien
954290075Sobrien/* Recursively search through all of the blocks in a function
954390075Sobrien   checking to see if any of the variables created in that
954490075Sobrien   function match the RTX called 'orig'.  If they do then
954590075Sobrien   replace them with the RTX called 'new'.  */
954690075Sobrien
954790075Sobrienstatic void
954890075Sobrienreplace_symbols_in_block (block, orig, new)
954990075Sobrien     tree block;
955090075Sobrien     rtx orig;
955190075Sobrien     rtx new;
955290075Sobrien{
955390075Sobrien  for (; block; block = BLOCK_CHAIN (block))
955490075Sobrien    {
955590075Sobrien      tree sym;
955690075Sobrien
955790075Sobrien      if (!TREE_USED (block))
955890075Sobrien	continue;
955990075Sobrien
956090075Sobrien      for (sym = BLOCK_VARS (block); sym; sym = TREE_CHAIN (sym))
956190075Sobrien	{
956290075Sobrien	  if (  (DECL_NAME (sym) == 0 && TREE_CODE (sym) != TYPE_DECL)
956390075Sobrien	      || DECL_IGNORED_P (sym)
956490075Sobrien	      || TREE_CODE (sym) != VAR_DECL
956590075Sobrien	      || DECL_EXTERNAL (sym)
956690075Sobrien	      || !rtx_equal_p (DECL_RTL (sym), orig)
956790075Sobrien	      )
956890075Sobrien	    continue;
956990075Sobrien
957090075Sobrien	  SET_DECL_RTL (sym, new);
957190075Sobrien	}
957290075Sobrien
957390075Sobrien      replace_symbols_in_block (BLOCK_SUBBLOCKS (block), orig, new);
957490075Sobrien    }
957590075Sobrien}
957690075Sobrien
957790075Sobrien/* Return the number (counting from 0) of
957890075Sobrien   the least significant set bit in MASK.  */
957990075Sobrien
958090075Sobrien#ifdef __GNUC__
958190075Sobrieninline
958290075Sobrien#endif
958390075Sobrienstatic int
958490075Sobriennumber_of_first_bit_set (mask)
958590075Sobrien     int mask;
958690075Sobrien{
958790075Sobrien  int bit;
958890075Sobrien
958990075Sobrien  for (bit = 0;
959090075Sobrien       (mask & (1 << bit)) == 0;
959190075Sobrien       ++bit)
959290075Sobrien    continue;
959390075Sobrien
959490075Sobrien  return bit;
959590075Sobrien}
959690075Sobrien
959790075Sobrien/* Generate code to return from a thumb function.
959890075Sobrien   If 'reg_containing_return_addr' is -1, then the return address is
959990075Sobrien   actually on the stack, at the stack pointer.  */
960090075Sobrienstatic void
960190075Sobrienthumb_exit (f, reg_containing_return_addr, eh_ofs)
960290075Sobrien     FILE * f;
960390075Sobrien     int    reg_containing_return_addr;
960490075Sobrien     rtx    eh_ofs;
960590075Sobrien{
960690075Sobrien  unsigned regs_available_for_popping;
960790075Sobrien  unsigned regs_to_pop;
960890075Sobrien  int pops_needed;
960990075Sobrien  unsigned available;
961090075Sobrien  unsigned required;
961190075Sobrien  int mode;
961290075Sobrien  int size;
961390075Sobrien  int restore_a4 = FALSE;
961490075Sobrien
961590075Sobrien  /* Compute the registers we need to pop.  */
961690075Sobrien  regs_to_pop = 0;
961790075Sobrien  pops_needed = 0;
961890075Sobrien
961990075Sobrien  /* There is an assumption here, that if eh_ofs is not NULL, the
962090075Sobrien     normal return address will have been pushed.  */
962190075Sobrien  if (reg_containing_return_addr == -1 || eh_ofs)
962290075Sobrien    {
962390075Sobrien      /* When we are generating a return for __builtin_eh_return,
962490075Sobrien	 reg_containing_return_addr must specify the return regno.  */
962590075Sobrien      if (eh_ofs && reg_containing_return_addr == -1)
962690075Sobrien	abort ();
962790075Sobrien
962890075Sobrien      regs_to_pop |= 1 << LR_REGNUM;
962990075Sobrien      ++pops_needed;
963090075Sobrien    }
963190075Sobrien
963290075Sobrien  if (TARGET_BACKTRACE)
963390075Sobrien    {
963490075Sobrien      /* Restore the (ARM) frame pointer and stack pointer.  */
963590075Sobrien      regs_to_pop |= (1 << ARM_HARD_FRAME_POINTER_REGNUM) | (1 << SP_REGNUM);
963690075Sobrien      pops_needed += 2;
963790075Sobrien    }
963890075Sobrien
963990075Sobrien  /* If there is nothing to pop then just emit the BX instruction and
964090075Sobrien     return.  */
964190075Sobrien  if (pops_needed == 0)
964290075Sobrien    {
964390075Sobrien      if (eh_ofs)
964490075Sobrien	asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, REGNO (eh_ofs));
964590075Sobrien
964690075Sobrien      asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
964790075Sobrien      return;
964890075Sobrien    }
964990075Sobrien  /* Otherwise if we are not supporting interworking and we have not created
965090075Sobrien     a backtrace structure and the function was not entered in ARM mode then
965190075Sobrien     just pop the return address straight into the PC.  */
965290075Sobrien  else if (!TARGET_INTERWORK
965390075Sobrien	   && !TARGET_BACKTRACE
965490075Sobrien	   && !is_called_in_ARM_mode (current_function_decl))
965590075Sobrien    {
965690075Sobrien      if (eh_ofs)
965790075Sobrien	{
965890075Sobrien	  asm_fprintf (f, "\tadd\t%r, #4\n", SP_REGNUM);
965990075Sobrien	  asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, REGNO (eh_ofs));
966090075Sobrien	  asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
966190075Sobrien	}
966290075Sobrien      else
966390075Sobrien	asm_fprintf (f, "\tpop\t{%r}\n", PC_REGNUM);
966490075Sobrien
966590075Sobrien      return;
966690075Sobrien    }
966790075Sobrien
966890075Sobrien  /* Find out how many of the (return) argument registers we can corrupt.  */
966990075Sobrien  regs_available_for_popping = 0;
967090075Sobrien
967190075Sobrien  /* If returning via __builtin_eh_return, the bottom three registers
967290075Sobrien     all contain information needed for the return.  */
967390075Sobrien  if (eh_ofs)
967490075Sobrien    size = 12;
967590075Sobrien  else
967690075Sobrien    {
967790075Sobrien#ifdef RTX_CODE
967890075Sobrien      /* If we can deduce the registers used from the function's
967990075Sobrien	 return value.  This is more reliable that examining
968090075Sobrien	 regs_ever_live[] because that will be set if the register is
968190075Sobrien	 ever used in the function, not just if the register is used
968290075Sobrien	 to hold a return value.  */
968390075Sobrien
968490075Sobrien      if (current_function_return_rtx != 0)
968590075Sobrien	mode = GET_MODE (current_function_return_rtx);
968690075Sobrien      else
968790075Sobrien#endif
968890075Sobrien	mode = DECL_MODE (DECL_RESULT (current_function_decl));
968990075Sobrien
969090075Sobrien      size = GET_MODE_SIZE (mode);
969190075Sobrien
969290075Sobrien      if (size == 0)
969390075Sobrien	{
969490075Sobrien	  /* In a void function we can use any argument register.
969590075Sobrien	     In a function that returns a structure on the stack
969690075Sobrien	     we can use the second and third argument registers.  */
969790075Sobrien	  if (mode == VOIDmode)
969890075Sobrien	    regs_available_for_popping =
969990075Sobrien	      (1 << ARG_REGISTER (1))
970090075Sobrien	      | (1 << ARG_REGISTER (2))
970190075Sobrien	      | (1 << ARG_REGISTER (3));
970290075Sobrien	  else
970390075Sobrien	    regs_available_for_popping =
970490075Sobrien	      (1 << ARG_REGISTER (2))
970590075Sobrien	      | (1 << ARG_REGISTER (3));
970690075Sobrien	}
970790075Sobrien      else if (size <= 4)
970890075Sobrien	regs_available_for_popping =
970990075Sobrien	  (1 << ARG_REGISTER (2))
971090075Sobrien	  | (1 << ARG_REGISTER (3));
971190075Sobrien      else if (size <= 8)
971290075Sobrien	regs_available_for_popping =
971390075Sobrien	  (1 << ARG_REGISTER (3));
971490075Sobrien    }
971590075Sobrien
971690075Sobrien  /* Match registers to be popped with registers into which we pop them.  */
971790075Sobrien  for (available = regs_available_for_popping,
971890075Sobrien       required  = regs_to_pop;
971990075Sobrien       required != 0 && available != 0;
972090075Sobrien       available &= ~(available & - available),
972190075Sobrien       required  &= ~(required  & - required))
972290075Sobrien    -- pops_needed;
972390075Sobrien
972490075Sobrien  /* If we have any popping registers left over, remove them.  */
972590075Sobrien  if (available > 0)
972690075Sobrien    regs_available_for_popping &= ~available;
972790075Sobrien
972890075Sobrien  /* Otherwise if we need another popping register we can use
972990075Sobrien     the fourth argument register.  */
973090075Sobrien  else if (pops_needed)
973190075Sobrien    {
973290075Sobrien      /* If we have not found any free argument registers and
973390075Sobrien	 reg a4 contains the return address, we must move it.  */
973490075Sobrien      if (regs_available_for_popping == 0
973590075Sobrien	  && reg_containing_return_addr == LAST_ARG_REGNUM)
973690075Sobrien	{
973790075Sobrien	  asm_fprintf (f, "\tmov\t%r, %r\n", LR_REGNUM, LAST_ARG_REGNUM);
973890075Sobrien	  reg_containing_return_addr = LR_REGNUM;
973990075Sobrien	}
974090075Sobrien      else if (size > 12)
974190075Sobrien	{
974290075Sobrien	  /* Register a4 is being used to hold part of the return value,
974390075Sobrien	     but we have dire need of a free, low register.  */
974490075Sobrien	  restore_a4 = TRUE;
974590075Sobrien
974690075Sobrien	  asm_fprintf (f, "\tmov\t%r, %r\n",IP_REGNUM, LAST_ARG_REGNUM);
974790075Sobrien	}
974890075Sobrien
974990075Sobrien      if (reg_containing_return_addr != LAST_ARG_REGNUM)
975090075Sobrien	{
975190075Sobrien	  /* The fourth argument register is available.  */
975290075Sobrien	  regs_available_for_popping |= 1 << LAST_ARG_REGNUM;
975390075Sobrien
975490075Sobrien	  --pops_needed;
975590075Sobrien	}
975690075Sobrien    }
975790075Sobrien
975890075Sobrien  /* Pop as many registers as we can.  */
975990075Sobrien  thumb_pushpop (f, regs_available_for_popping, FALSE);
976090075Sobrien
976190075Sobrien  /* Process the registers we popped.  */
976290075Sobrien  if (reg_containing_return_addr == -1)
976390075Sobrien    {
976490075Sobrien      /* The return address was popped into the lowest numbered register.  */
976590075Sobrien      regs_to_pop &= ~(1 << LR_REGNUM);
976690075Sobrien
976790075Sobrien      reg_containing_return_addr =
976890075Sobrien	number_of_first_bit_set (regs_available_for_popping);
976990075Sobrien
977090075Sobrien      /* Remove this register for the mask of available registers, so that
977190075Sobrien         the return address will not be corrupted by futher pops.  */
977290075Sobrien      regs_available_for_popping &= ~(1 << reg_containing_return_addr);
977390075Sobrien    }
977490075Sobrien
977590075Sobrien  /* If we popped other registers then handle them here.  */
977690075Sobrien  if (regs_available_for_popping)
977790075Sobrien    {
977890075Sobrien      int frame_pointer;
977990075Sobrien
978090075Sobrien      /* Work out which register currently contains the frame pointer.  */
978190075Sobrien      frame_pointer = number_of_first_bit_set (regs_available_for_popping);
978290075Sobrien
978390075Sobrien      /* Move it into the correct place.  */
978490075Sobrien      asm_fprintf (f, "\tmov\t%r, %r\n",
978590075Sobrien		   ARM_HARD_FRAME_POINTER_REGNUM, frame_pointer);
978690075Sobrien
978790075Sobrien      /* (Temporarily) remove it from the mask of popped registers.  */
978890075Sobrien      regs_available_for_popping &= ~(1 << frame_pointer);
978990075Sobrien      regs_to_pop &= ~(1 << ARM_HARD_FRAME_POINTER_REGNUM);
979090075Sobrien
979190075Sobrien      if (regs_available_for_popping)
979290075Sobrien	{
979390075Sobrien	  int stack_pointer;
979490075Sobrien
979590075Sobrien	  /* We popped the stack pointer as well,
979690075Sobrien	     find the register that contains it.  */
979790075Sobrien	  stack_pointer = number_of_first_bit_set (regs_available_for_popping);
979890075Sobrien
979990075Sobrien	  /* Move it into the stack register.  */
980090075Sobrien	  asm_fprintf (f, "\tmov\t%r, %r\n", SP_REGNUM, stack_pointer);
980190075Sobrien
980290075Sobrien	  /* At this point we have popped all necessary registers, so
980390075Sobrien	     do not worry about restoring regs_available_for_popping
980490075Sobrien	     to its correct value:
980590075Sobrien
980690075Sobrien	     assert (pops_needed == 0)
980790075Sobrien	     assert (regs_available_for_popping == (1 << frame_pointer))
980890075Sobrien	     assert (regs_to_pop == (1 << STACK_POINTER))  */
980990075Sobrien	}
981090075Sobrien      else
981190075Sobrien	{
981290075Sobrien	  /* Since we have just move the popped value into the frame
981390075Sobrien	     pointer, the popping register is available for reuse, and
981490075Sobrien	     we know that we still have the stack pointer left to pop.  */
981590075Sobrien	  regs_available_for_popping |= (1 << frame_pointer);
981690075Sobrien	}
981790075Sobrien    }
981890075Sobrien
981990075Sobrien  /* If we still have registers left on the stack, but we no longer have
982090075Sobrien     any registers into which we can pop them, then we must move the return
982190075Sobrien     address into the link register and make available the register that
982290075Sobrien     contained it.  */
982390075Sobrien  if (regs_available_for_popping == 0 && pops_needed > 0)
982490075Sobrien    {
982590075Sobrien      regs_available_for_popping |= 1 << reg_containing_return_addr;
982690075Sobrien
982790075Sobrien      asm_fprintf (f, "\tmov\t%r, %r\n", LR_REGNUM,
982890075Sobrien		   reg_containing_return_addr);
982990075Sobrien
983090075Sobrien      reg_containing_return_addr = LR_REGNUM;
983190075Sobrien    }
983290075Sobrien
983390075Sobrien  /* If we have registers left on the stack then pop some more.
983490075Sobrien     We know that at most we will want to pop FP and SP.  */
983590075Sobrien  if (pops_needed > 0)
983690075Sobrien    {
983790075Sobrien      int  popped_into;
983890075Sobrien      int  move_to;
983990075Sobrien
984090075Sobrien      thumb_pushpop (f, regs_available_for_popping, FALSE);
984190075Sobrien
984290075Sobrien      /* We have popped either FP or SP.
984390075Sobrien	 Move whichever one it is into the correct register.  */
984490075Sobrien      popped_into = number_of_first_bit_set (regs_available_for_popping);
984590075Sobrien      move_to     = number_of_first_bit_set (regs_to_pop);
984690075Sobrien
984790075Sobrien      asm_fprintf (f, "\tmov\t%r, %r\n", move_to, popped_into);
984890075Sobrien
984990075Sobrien      regs_to_pop &= ~(1 << move_to);
985090075Sobrien
985190075Sobrien      --pops_needed;
985290075Sobrien    }
985390075Sobrien
985490075Sobrien  /* If we still have not popped everything then we must have only
985590075Sobrien     had one register available to us and we are now popping the SP.  */
985690075Sobrien  if (pops_needed > 0)
985790075Sobrien    {
985890075Sobrien      int  popped_into;
985990075Sobrien
986090075Sobrien      thumb_pushpop (f, regs_available_for_popping, FALSE);
986190075Sobrien
986290075Sobrien      popped_into = number_of_first_bit_set (regs_available_for_popping);
986390075Sobrien
986490075Sobrien      asm_fprintf (f, "\tmov\t%r, %r\n", SP_REGNUM, popped_into);
986590075Sobrien      /*
986690075Sobrien	assert (regs_to_pop == (1 << STACK_POINTER))
986790075Sobrien	assert (pops_needed == 1)
986890075Sobrien      */
986990075Sobrien    }
987090075Sobrien
987190075Sobrien  /* If necessary restore the a4 register.  */
987290075Sobrien  if (restore_a4)
987390075Sobrien    {
987490075Sobrien      if (reg_containing_return_addr != LR_REGNUM)
987590075Sobrien	{
987690075Sobrien	  asm_fprintf (f, "\tmov\t%r, %r\n", LR_REGNUM, LAST_ARG_REGNUM);
987790075Sobrien	  reg_containing_return_addr = LR_REGNUM;
987890075Sobrien	}
987990075Sobrien
988090075Sobrien      asm_fprintf (f, "\tmov\t%r, %r\n", LAST_ARG_REGNUM, IP_REGNUM);
988190075Sobrien    }
988290075Sobrien
988390075Sobrien  if (eh_ofs)
988490075Sobrien    asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, REGNO (eh_ofs));
988590075Sobrien
988690075Sobrien  /* Return to caller.  */
988790075Sobrien  asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
988890075Sobrien}
988990075Sobrien
989090075Sobrien/* Emit code to push or pop registers to or from the stack.  */
989190075Sobrien
989290075Sobrienstatic void
989390075Sobrienthumb_pushpop (f, mask, push)
989490075Sobrien     FILE * f;
989590075Sobrien     int mask;
989690075Sobrien     int push;
989790075Sobrien{
989890075Sobrien  int regno;
989990075Sobrien  int lo_mask = mask & 0xFF;
990090075Sobrien
990190075Sobrien  if (lo_mask == 0 && !push && (mask & (1 << 15)))
990290075Sobrien    {
990390075Sobrien      /* Special case.  Do not generate a POP PC statement here, do it in
990490075Sobrien	 thumb_exit() */
990590075Sobrien      thumb_exit (f, -1, NULL_RTX);
990690075Sobrien      return;
990790075Sobrien    }
990890075Sobrien
990990075Sobrien  fprintf (f, "\t%s\t{", push ? "push" : "pop");
991090075Sobrien
991190075Sobrien  /* Look at the low registers first.  */
991290075Sobrien  for (regno = 0; regno <= LAST_LO_REGNUM; regno++, lo_mask >>= 1)
991390075Sobrien    {
991490075Sobrien      if (lo_mask & 1)
991590075Sobrien	{
991690075Sobrien	  asm_fprintf (f, "%r", regno);
991790075Sobrien
991890075Sobrien	  if ((lo_mask & ~1) != 0)
991990075Sobrien	    fprintf (f, ", ");
992090075Sobrien	}
992190075Sobrien    }
992290075Sobrien
992390075Sobrien  if (push && (mask & (1 << LR_REGNUM)))
992490075Sobrien    {
992590075Sobrien      /* Catch pushing the LR.  */
992690075Sobrien      if (mask & 0xFF)
992790075Sobrien	fprintf (f, ", ");
992890075Sobrien
992990075Sobrien      asm_fprintf (f, "%r", LR_REGNUM);
993090075Sobrien    }
993190075Sobrien  else if (!push && (mask & (1 << PC_REGNUM)))
993290075Sobrien    {
993390075Sobrien      /* Catch popping the PC.  */
993490075Sobrien      if (TARGET_INTERWORK || TARGET_BACKTRACE)
993590075Sobrien	{
993690075Sobrien	  /* The PC is never poped directly, instead
993790075Sobrien	     it is popped into r3 and then BX is used.  */
993890075Sobrien	  fprintf (f, "}\n");
993990075Sobrien
994090075Sobrien	  thumb_exit (f, -1, NULL_RTX);
994190075Sobrien
994290075Sobrien	  return;
994390075Sobrien	}
994490075Sobrien      else
994590075Sobrien	{
994690075Sobrien	  if (mask & 0xFF)
994790075Sobrien	    fprintf (f, ", ");
994890075Sobrien
994990075Sobrien	  asm_fprintf (f, "%r", PC_REGNUM);
995090075Sobrien	}
995190075Sobrien    }
995290075Sobrien
995390075Sobrien  fprintf (f, "}\n");
995490075Sobrien}
995590075Sobrien
995690075Sobrienvoid
995790075Sobrienthumb_final_prescan_insn (insn)
995890075Sobrien     rtx insn;
995990075Sobrien{
996090075Sobrien  if (flag_print_asm_name)
996190075Sobrien    asm_fprintf (asm_out_file, "%@ 0x%04x\n",
996290075Sobrien		 INSN_ADDRESSES (INSN_UID (insn)));
996390075Sobrien}
996490075Sobrien
996590075Sobrienint
996690075Sobrienthumb_shiftable_const (val)
996790075Sobrien     unsigned HOST_WIDE_INT val;
996890075Sobrien{
996990075Sobrien  unsigned HOST_WIDE_INT mask = 0xff;
997090075Sobrien  int i;
997190075Sobrien
997290075Sobrien  if (val == 0) /* XXX */
997390075Sobrien    return 0;
997490075Sobrien
997590075Sobrien  for (i = 0; i < 25; i++)
997690075Sobrien    if ((val & (mask << i)) == val)
997790075Sobrien      return 1;
997890075Sobrien
997990075Sobrien  return 0;
998090075Sobrien}
998190075Sobrien
9982117395Skan/* Returns nonzero if the current function contains,
998390075Sobrien   or might contain a far jump.  */
998490075Sobrien
998590075Sobrienint
9986117395Skanthumb_far_jump_used_p (in_prologue)
9987117395Skan     int in_prologue;
998890075Sobrien{
998990075Sobrien  rtx insn;
999090075Sobrien
999190075Sobrien  /* This test is only important for leaf functions.  */
999290075Sobrien  /* assert (!leaf_function_p ()); */
999390075Sobrien
999490075Sobrien  /* If we have already decided that far jumps may be used,
999590075Sobrien     do not bother checking again, and always return true even if
999690075Sobrien     it turns out that they are not being used.  Once we have made
999790075Sobrien     the decision that far jumps are present (and that hence the link
999890075Sobrien     register will be pushed onto the stack) we cannot go back on it.  */
999990075Sobrien  if (cfun->machine->far_jump_used)
1000090075Sobrien    return 1;
1000190075Sobrien
1000290075Sobrien  /* If this function is not being called from the prologue/epilogue
1000390075Sobrien     generation code then it must be being called from the
1000490075Sobrien     INITIAL_ELIMINATION_OFFSET macro.  */
1000590075Sobrien  if (!in_prologue)
1000690075Sobrien    {
1000790075Sobrien      /* In this case we know that we are being asked about the elimination
1000890075Sobrien	 of the arg pointer register.  If that register is not being used,
1000990075Sobrien	 then there are no arguments on the stack, and we do not have to
1001090075Sobrien	 worry that a far jump might force the prologue to push the link
1001190075Sobrien	 register, changing the stack offsets.  In this case we can just
1001290075Sobrien	 return false, since the presence of far jumps in the function will
1001390075Sobrien	 not affect stack offsets.
1001490075Sobrien
1001590075Sobrien	 If the arg pointer is live (or if it was live, but has now been
1001690075Sobrien	 eliminated and so set to dead) then we do have to test to see if
1001790075Sobrien	 the function might contain a far jump.  This test can lead to some
1001890075Sobrien	 false negatives, since before reload is completed, then length of
1001990075Sobrien	 branch instructions is not known, so gcc defaults to returning their
1002090075Sobrien	 longest length, which in turn sets the far jump attribute to true.
1002190075Sobrien
1002290075Sobrien	 A false negative will not result in bad code being generated, but it
1002390075Sobrien	 will result in a needless push and pop of the link register.  We
1002490075Sobrien	 hope that this does not occur too often.  */
1002590075Sobrien      if (regs_ever_live [ARG_POINTER_REGNUM])
1002690075Sobrien	cfun->machine->arg_pointer_live = 1;
1002790075Sobrien      else if (!cfun->machine->arg_pointer_live)
1002890075Sobrien	return 0;
1002990075Sobrien    }
1003090075Sobrien
1003190075Sobrien  /* Check to see if the function contains a branch
1003290075Sobrien     insn with the far jump attribute set.  */
1003390075Sobrien  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
1003490075Sobrien    {
1003590075Sobrien      if (GET_CODE (insn) == JUMP_INSN
1003690075Sobrien	  /* Ignore tablejump patterns.  */
1003790075Sobrien	  && GET_CODE (PATTERN (insn)) != ADDR_VEC
1003890075Sobrien	  && GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC
1003990075Sobrien	  && get_attr_far_jump (insn) == FAR_JUMP_YES
1004090075Sobrien	  )
1004190075Sobrien	{
1004290075Sobrien	  /* Record the fact that we have decied that
1004390075Sobrien	     the function does use far jumps.  */
1004490075Sobrien	  cfun->machine->far_jump_used = 1;
1004590075Sobrien	  return 1;
1004690075Sobrien	}
1004790075Sobrien    }
1004890075Sobrien
1004990075Sobrien  return 0;
1005090075Sobrien}
1005190075Sobrien
10052117395Skan/* Return nonzero if FUNC must be entered in ARM mode.  */
1005390075Sobrien
1005490075Sobrienint
1005590075Sobrienis_called_in_ARM_mode (func)
1005690075Sobrien     tree func;
1005790075Sobrien{
1005890075Sobrien  if (TREE_CODE (func) != FUNCTION_DECL)
1005990075Sobrien    abort ();
1006090075Sobrien
1006190075Sobrien  /* Ignore the problem about functions whoes address is taken.  */
1006290075Sobrien  if (TARGET_CALLEE_INTERWORKING && TREE_PUBLIC (func))
1006390075Sobrien    return TRUE;
1006490075Sobrien
1006590075Sobrien#ifdef ARM_PE
1006690075Sobrien  return lookup_attribute ("interfacearm", DECL_ATTRIBUTES (func)) != NULL_TREE;
1006790075Sobrien#else
1006890075Sobrien  return FALSE;
1006990075Sobrien#endif
1007090075Sobrien}
1007190075Sobrien
1007290075Sobrien/* The bits which aren't usefully expanded as rtl. */
1007390075Sobrien
1007490075Sobrienconst char *
1007590075Sobrienthumb_unexpanded_epilogue ()
1007690075Sobrien{
1007790075Sobrien  int regno;
1007890075Sobrien  int live_regs_mask = 0;
1007990075Sobrien  int high_regs_pushed = 0;
1008090075Sobrien  int leaf_function = leaf_function_p ();
1008190075Sobrien  int had_to_push_lr;
1008290075Sobrien  rtx eh_ofs = cfun->machine->eh_epilogue_sp_ofs;
1008390075Sobrien
1008490075Sobrien  if (return_used_this_function)
1008590075Sobrien    return "";
1008690075Sobrien
10087117395Skan  if (IS_NAKED (arm_current_func_type ()))
10088117395Skan    return "";
10089117395Skan
1009090075Sobrien  for (regno = 0; regno <= LAST_LO_REGNUM; regno++)
10091117395Skan    if (THUMB_REG_PUSHED_P (regno))
1009290075Sobrien      live_regs_mask |= 1 << regno;
1009390075Sobrien
1009490075Sobrien  for (regno = 8; regno < 13; regno++)
10095117395Skan    if (THUMB_REG_PUSHED_P (regno))
10096117395Skan      high_regs_pushed++;
1009790075Sobrien
1009890075Sobrien  /* The prolog may have pushed some high registers to use as
1009990075Sobrien     work registers.  eg the testuite file:
1010090075Sobrien     gcc/testsuite/gcc/gcc.c-torture/execute/complex-2.c
1010190075Sobrien     compiles to produce:
1010290075Sobrien	push	{r4, r5, r6, r7, lr}
1010390075Sobrien	mov	r7, r9
1010490075Sobrien	mov	r6, r8
1010590075Sobrien	push	{r6, r7}
1010690075Sobrien     as part of the prolog.  We have to undo that pushing here.  */
1010790075Sobrien
1010890075Sobrien  if (high_regs_pushed)
1010990075Sobrien    {
1011090075Sobrien      int mask = live_regs_mask;
1011190075Sobrien      int next_hi_reg;
1011290075Sobrien      int size;
1011390075Sobrien      int mode;
1011490075Sobrien
1011590075Sobrien#ifdef RTX_CODE
1011690075Sobrien      /* If we can deduce the registers used from the function's return value.
1011790075Sobrien	 This is more reliable that examining regs_ever_live[] because that
1011890075Sobrien	 will be set if the register is ever used in the function, not just if
1011990075Sobrien	 the register is used to hold a return value.  */
1012090075Sobrien
1012190075Sobrien      if (current_function_return_rtx != 0)
1012290075Sobrien	mode = GET_MODE (current_function_return_rtx);
1012390075Sobrien      else
1012490075Sobrien#endif
1012590075Sobrien	mode = DECL_MODE (DECL_RESULT (current_function_decl));
1012690075Sobrien
1012790075Sobrien      size = GET_MODE_SIZE (mode);
1012890075Sobrien
1012990075Sobrien      /* Unless we are returning a type of size > 12 register r3 is
1013090075Sobrien         available.  */
1013190075Sobrien      if (size < 13)
1013290075Sobrien	mask |=  1 << 3;
1013390075Sobrien
1013490075Sobrien      if (mask == 0)
1013590075Sobrien	/* Oh dear!  We have no low registers into which we can pop
1013690075Sobrien           high registers!  */
1013790075Sobrien	internal_error
1013890075Sobrien	  ("no low registers available for popping high registers");
1013990075Sobrien
1014090075Sobrien      for (next_hi_reg = 8; next_hi_reg < 13; next_hi_reg++)
10141117395Skan	if (THUMB_REG_PUSHED_P (next_hi_reg))
1014290075Sobrien	  break;
1014390075Sobrien
1014490075Sobrien      while (high_regs_pushed)
1014590075Sobrien	{
1014690075Sobrien	  /* Find lo register(s) into which the high register(s) can
1014790075Sobrien             be popped.  */
1014890075Sobrien	  for (regno = 0; regno <= LAST_LO_REGNUM; regno++)
1014990075Sobrien	    {
1015090075Sobrien	      if (mask & (1 << regno))
1015190075Sobrien		high_regs_pushed--;
1015290075Sobrien	      if (high_regs_pushed == 0)
1015390075Sobrien		break;
1015490075Sobrien	    }
1015590075Sobrien
1015690075Sobrien	  mask &= (2 << regno) - 1;	/* A noop if regno == 8 */
1015790075Sobrien
1015890075Sobrien	  /* Pop the values into the low register(s). */
1015990075Sobrien	  thumb_pushpop (asm_out_file, mask, 0);
1016090075Sobrien
1016190075Sobrien	  /* Move the value(s) into the high registers.  */
1016290075Sobrien	  for (regno = 0; regno <= LAST_LO_REGNUM; regno++)
1016390075Sobrien	    {
1016490075Sobrien	      if (mask & (1 << regno))
1016590075Sobrien		{
1016690075Sobrien		  asm_fprintf (asm_out_file, "\tmov\t%r, %r\n", next_hi_reg,
1016790075Sobrien			       regno);
1016890075Sobrien
1016990075Sobrien		  for (next_hi_reg++; next_hi_reg < 13; next_hi_reg++)
10170117395Skan		    if (THUMB_REG_PUSHED_P (next_hi_reg))
1017190075Sobrien		      break;
1017290075Sobrien		}
1017390075Sobrien	    }
1017490075Sobrien	}
1017590075Sobrien    }
1017690075Sobrien
1017790075Sobrien  had_to_push_lr = (live_regs_mask || !leaf_function
1017890075Sobrien		    || thumb_far_jump_used_p (1));
1017990075Sobrien
1018090075Sobrien  if (TARGET_BACKTRACE
1018190075Sobrien      && ((live_regs_mask & 0xFF) == 0)
1018290075Sobrien      && regs_ever_live [LAST_ARG_REGNUM] != 0)
1018390075Sobrien    {
1018490075Sobrien      /* The stack backtrace structure creation code had to
1018590075Sobrien	 push R7 in order to get a work register, so we pop
1018690075Sobrien	 it now.   */
1018790075Sobrien      live_regs_mask |= (1 << LAST_LO_REGNUM);
1018890075Sobrien    }
1018990075Sobrien
1019090075Sobrien  if (current_function_pretend_args_size == 0 || TARGET_BACKTRACE)
1019190075Sobrien    {
1019290075Sobrien      if (had_to_push_lr
1019390075Sobrien	  && !is_called_in_ARM_mode (current_function_decl)
1019490075Sobrien	  && !eh_ofs)
1019590075Sobrien	live_regs_mask |= 1 << PC_REGNUM;
1019690075Sobrien
1019790075Sobrien      /* Either no argument registers were pushed or a backtrace
1019890075Sobrien	 structure was created which includes an adjusted stack
1019990075Sobrien	 pointer, so just pop everything.  */
1020090075Sobrien      if (live_regs_mask)
1020190075Sobrien	thumb_pushpop (asm_out_file, live_regs_mask, FALSE);
1020290075Sobrien
1020390075Sobrien      if (eh_ofs)
1020490075Sobrien	thumb_exit (asm_out_file, 2, eh_ofs);
1020590075Sobrien      /* We have either just popped the return address into the
1020690075Sobrien	 PC or it is was kept in LR for the entire function or
1020790075Sobrien	 it is still on the stack because we do not want to
1020890075Sobrien	 return by doing a pop {pc}.  */
1020990075Sobrien      else if ((live_regs_mask & (1 << PC_REGNUM)) == 0)
1021090075Sobrien	thumb_exit (asm_out_file,
1021190075Sobrien		    (had_to_push_lr
1021290075Sobrien		     && is_called_in_ARM_mode (current_function_decl)) ?
1021390075Sobrien		    -1 : LR_REGNUM, NULL_RTX);
1021490075Sobrien    }
1021590075Sobrien  else
1021690075Sobrien    {
1021790075Sobrien      /* Pop everything but the return address.  */
1021890075Sobrien      live_regs_mask &= ~(1 << PC_REGNUM);
1021990075Sobrien
1022090075Sobrien      if (live_regs_mask)
1022190075Sobrien	thumb_pushpop (asm_out_file, live_regs_mask, FALSE);
1022290075Sobrien
1022390075Sobrien      if (had_to_push_lr)
1022490075Sobrien	/* Get the return address into a temporary register.  */
1022590075Sobrien	thumb_pushpop (asm_out_file, 1 << LAST_ARG_REGNUM, 0);
1022690075Sobrien
1022790075Sobrien      /* Remove the argument registers that were pushed onto the stack.  */
1022890075Sobrien      asm_fprintf (asm_out_file, "\tadd\t%r, %r, #%d\n",
1022990075Sobrien		   SP_REGNUM, SP_REGNUM,
1023090075Sobrien		   current_function_pretend_args_size);
1023190075Sobrien
1023290075Sobrien      if (eh_ofs)
1023390075Sobrien	thumb_exit (asm_out_file, 2, eh_ofs);
1023490075Sobrien      else
1023590075Sobrien	thumb_exit (asm_out_file,
1023690075Sobrien		    had_to_push_lr ? LAST_ARG_REGNUM : LR_REGNUM, NULL_RTX);
1023790075Sobrien    }
1023890075Sobrien
1023990075Sobrien  return "";
1024090075Sobrien}
1024190075Sobrien
1024290075Sobrien/* Functions to save and restore machine-specific function data.  */
1024390075Sobrien
10244117395Skanstatic struct machine_function *
10245117395Skanarm_init_machine_status ()
1024690075Sobrien{
10247117395Skan  struct machine_function *machine;
10248117395Skan  machine = (machine_function *) ggc_alloc_cleared (sizeof (machine_function));
1024990075Sobrien
10250117395Skan#if ARM_FT_UNKNOWN != 0
10251117395Skan  machine->func_type = ARM_FT_UNKNOWN;
1025290075Sobrien#endif
10253117395Skan  return machine;
1025490075Sobrien}
1025590075Sobrien
1025690075Sobrien/* Return an RTX indicating where the return address to the
1025790075Sobrien   calling function can be found.  */
1025890075Sobrien
1025990075Sobrienrtx
1026090075Sobrienarm_return_addr (count, frame)
1026190075Sobrien     int count;
1026290075Sobrien     rtx frame ATTRIBUTE_UNUSED;
1026390075Sobrien{
1026490075Sobrien  if (count != 0)
1026590075Sobrien    return NULL_RTX;
1026690075Sobrien
1026790075Sobrien  if (TARGET_APCS_32)
1026890075Sobrien    return get_hard_reg_initial_val (Pmode, LR_REGNUM);
1026990075Sobrien  else
1027090075Sobrien    {
1027190075Sobrien      rtx lr = gen_rtx_AND (Pmode, gen_rtx_REG (Pmode, LR_REGNUM),
1027290075Sobrien			    GEN_INT (RETURN_ADDR_MASK26));
1027390075Sobrien      return get_func_hard_reg_initial_val (cfun, lr);
1027490075Sobrien    }
1027590075Sobrien}
1027690075Sobrien
1027790075Sobrien/* Do anything needed before RTL is emitted for each function.  */
1027890075Sobrien
1027990075Sobrienvoid
1028090075Sobrienarm_init_expanders ()
1028190075Sobrien{
1028290075Sobrien  /* Arrange to initialize and mark the machine per-function status.  */
1028390075Sobrien  init_machine_status = arm_init_machine_status;
1028490075Sobrien}
1028590075Sobrien
10286117395SkanHOST_WIDE_INT
10287117395Skanthumb_get_frame_size ()
10288117395Skan{
10289117395Skan  int regno;
10290117395Skan
10291117395Skan  int base_size = ROUND_UP (get_frame_size ());
10292117395Skan  int count_regs = 0;
10293117395Skan  int entry_size = 0;
10294117395Skan  int leaf;
10295117395Skan
10296117395Skan  if (! TARGET_THUMB)
10297117395Skan    abort ();
10298117395Skan
10299117395Skan  if (! TARGET_ATPCS)
10300117395Skan    return base_size;
10301117395Skan
10302117395Skan  /* We need to know if we are a leaf function.  Unfortunately, it
10303117395Skan     is possible to be called after start_sequence has been called,
10304117395Skan     which causes get_insns to return the insns for the sequence,
10305117395Skan     not the function, which will cause leaf_function_p to return
10306117395Skan     the incorrect result.
10307117395Skan
10308117395Skan     To work around this, we cache the computed frame size.  This
10309117395Skan     works because we will only be calling RTL expanders that need
10310117395Skan     to know about leaf functions once reload has completed, and the
10311117395Skan     frame size cannot be changed after that time, so we can safely
10312117395Skan     use the cached value.  */
10313117395Skan
10314117395Skan  if (reload_completed)
10315117395Skan    return cfun->machine->frame_size;
10316117395Skan
10317117395Skan  leaf = leaf_function_p ();
10318117395Skan
10319117395Skan  /* A leaf function does not need any stack alignment if it has nothing
10320117395Skan     on the stack.  */
10321117395Skan  if (leaf && base_size == 0)
10322117395Skan    {
10323117395Skan      cfun->machine->frame_size = 0;
10324117395Skan      return 0;
10325117395Skan    }
10326117395Skan
10327117395Skan  /* We know that SP will be word aligned on entry, and we must
10328117395Skan     preserve that condition at any subroutine call.  But those are
10329117395Skan     the only constraints.  */
10330117395Skan
10331117395Skan  /* Space for variadic functions.  */
10332117395Skan  if (current_function_pretend_args_size)
10333117395Skan    entry_size += current_function_pretend_args_size;
10334117395Skan
10335117395Skan  /* Space for pushed lo registers.  */
10336117395Skan  for (regno = 0; regno <= LAST_LO_REGNUM; regno++)
10337117395Skan    if (THUMB_REG_PUSHED_P (regno))
10338117395Skan      count_regs++;
10339117395Skan
10340117395Skan  /* Space for backtrace structure.  */
10341117395Skan  if (TARGET_BACKTRACE)
10342117395Skan    {
10343117395Skan      if (count_regs == 0 && regs_ever_live[LAST_ARG_REGNUM] != 0)
10344117395Skan	entry_size += 20;
10345117395Skan      else
10346117395Skan	entry_size += 16;
10347117395Skan    }
10348117395Skan
10349117395Skan  if (count_regs || !leaf || thumb_far_jump_used_p (1))
10350117395Skan    count_regs++;	/* LR */
10351117395Skan
10352117395Skan  entry_size += count_regs * 4;
10353117395Skan  count_regs = 0;
10354117395Skan
10355117395Skan  /* Space for pushed hi regs.  */
10356117395Skan  for (regno = 8; regno < 13; regno++)
10357117395Skan    if (THUMB_REG_PUSHED_P (regno))
10358117395Skan      count_regs++;
10359117395Skan
10360117395Skan  entry_size += count_regs * 4;
10361117395Skan
10362117395Skan  if ((entry_size + base_size + current_function_outgoing_args_size) & 7)
10363117395Skan    base_size += 4;
10364117395Skan  if ((entry_size + base_size + current_function_outgoing_args_size) & 7)
10365117395Skan    abort ();
10366117395Skan
10367117395Skan  cfun->machine->frame_size = base_size;
10368117395Skan
10369117395Skan  return base_size;
10370117395Skan}
10371117395Skan
1037290075Sobrien/* Generate the rest of a function's prologue.  */
1037390075Sobrien
1037490075Sobrienvoid
1037590075Sobrienthumb_expand_prologue ()
1037690075Sobrien{
10377117395Skan  HOST_WIDE_INT amount = (thumb_get_frame_size ()
1037890075Sobrien			  + current_function_outgoing_args_size);
1037990075Sobrien  unsigned long func_type;
1038090075Sobrien
1038190075Sobrien  func_type = arm_current_func_type ();
1038290075Sobrien
1038390075Sobrien  /* Naked functions don't have prologues.  */
1038490075Sobrien  if (IS_NAKED (func_type))
1038590075Sobrien    return;
1038690075Sobrien
1038790075Sobrien  if (IS_INTERRUPT (func_type))
1038890075Sobrien    {
1038990075Sobrien      error ("interrupt Service Routines cannot be coded in Thumb mode");
1039090075Sobrien      return;
1039190075Sobrien    }
1039290075Sobrien
1039390075Sobrien  if (frame_pointer_needed)
1039490075Sobrien    emit_insn (gen_movsi (hard_frame_pointer_rtx, stack_pointer_rtx));
1039590075Sobrien
1039690075Sobrien  if (amount)
1039790075Sobrien    {
1039890075Sobrien      amount = ROUND_UP (amount);
1039990075Sobrien
1040090075Sobrien      if (amount < 512)
1040190075Sobrien	emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
1040290075Sobrien			       GEN_INT (- amount)));
1040390075Sobrien      else
1040490075Sobrien	{
1040590075Sobrien	  int regno;
1040690075Sobrien	  rtx reg;
1040790075Sobrien
1040890075Sobrien	  /* The stack decrement is too big for an immediate value in a single
1040990075Sobrien	     insn.  In theory we could issue multiple subtracts, but after
1041090075Sobrien	     three of them it becomes more space efficient to place the full
1041190075Sobrien	     value in the constant pool and load into a register.  (Also the
1041290075Sobrien	     ARM debugger really likes to see only one stack decrement per
1041390075Sobrien	     function).  So instead we look for a scratch register into which
1041490075Sobrien	     we can load the decrement, and then we subtract this from the
1041590075Sobrien	     stack pointer.  Unfortunately on the thumb the only available
1041690075Sobrien	     scratch registers are the argument registers, and we cannot use
1041790075Sobrien	     these as they may hold arguments to the function.  Instead we
1041890075Sobrien	     attempt to locate a call preserved register which is used by this
1041990075Sobrien	     function.  If we can find one, then we know that it will have
1042090075Sobrien	     been pushed at the start of the prologue and so we can corrupt
1042190075Sobrien	     it now.  */
1042290075Sobrien	  for (regno = LAST_ARG_REGNUM + 1; regno <= LAST_LO_REGNUM; regno++)
10423117395Skan	    if (THUMB_REG_PUSHED_P (regno)
1042490075Sobrien		&& !(frame_pointer_needed
1042590075Sobrien		     && (regno == THUMB_HARD_FRAME_POINTER_REGNUM)))
1042690075Sobrien	      break;
1042790075Sobrien
10428117395Skan	  if (regno > LAST_LO_REGNUM) /* Very unlikely.  */
1042990075Sobrien	    {
1043090075Sobrien	      rtx spare = gen_rtx (REG, SImode, IP_REGNUM);
1043190075Sobrien
1043290075Sobrien	      /* Choose an arbitary, non-argument low register.  */
1043390075Sobrien	      reg = gen_rtx (REG, SImode, LAST_LO_REGNUM);
1043490075Sobrien
1043590075Sobrien	      /* Save it by copying it into a high, scratch register.  */
1043690075Sobrien	      emit_insn (gen_movsi (spare, reg));
1043790075Sobrien	      /* Add a USE to stop propagate_one_insn() from barfing.  */
1043890075Sobrien	      emit_insn (gen_prologue_use (spare));
1043990075Sobrien
1044090075Sobrien	      /* Decrement the stack.  */
1044190075Sobrien	      emit_insn (gen_movsi (reg, GEN_INT (- amount)));
1044290075Sobrien	      emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
1044390075Sobrien				     reg));
1044490075Sobrien
1044590075Sobrien	      /* Restore the low register's original value.  */
1044690075Sobrien	      emit_insn (gen_movsi (reg, spare));
1044790075Sobrien
1044890075Sobrien	      /* Emit a USE of the restored scratch register, so that flow
1044990075Sobrien		 analysis will not consider the restore redundant.  The
1045090075Sobrien		 register won't be used again in this function and isn't
1045190075Sobrien		 restored by the epilogue.  */
1045290075Sobrien	      emit_insn (gen_prologue_use (reg));
1045390075Sobrien	    }
1045490075Sobrien	  else
1045590075Sobrien	    {
1045690075Sobrien	      reg = gen_rtx (REG, SImode, regno);
1045790075Sobrien
1045890075Sobrien	      emit_insn (gen_movsi (reg, GEN_INT (- amount)));
1045990075Sobrien	      emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
1046090075Sobrien				     reg));
1046190075Sobrien	    }
1046290075Sobrien	}
1046390075Sobrien    }
1046490075Sobrien
1046590075Sobrien  if (current_function_profile || TARGET_NO_SCHED_PRO)
1046690075Sobrien    emit_insn (gen_blockage ());
1046790075Sobrien}
1046890075Sobrien
1046990075Sobrienvoid
1047090075Sobrienthumb_expand_epilogue ()
1047190075Sobrien{
10472117395Skan  HOST_WIDE_INT amount = (thumb_get_frame_size ()
1047390075Sobrien			  + current_function_outgoing_args_size);
1047490075Sobrien
1047590075Sobrien  /* Naked functions don't have prologues.  */
1047690075Sobrien  if (IS_NAKED (arm_current_func_type ()))
1047790075Sobrien    return;
1047890075Sobrien
1047990075Sobrien  if (frame_pointer_needed)
1048090075Sobrien    emit_insn (gen_movsi (stack_pointer_rtx, hard_frame_pointer_rtx));
1048190075Sobrien  else if (amount)
1048290075Sobrien    {
1048390075Sobrien      amount = ROUND_UP (amount);
1048490075Sobrien
1048590075Sobrien      if (amount < 512)
1048690075Sobrien	emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
1048790075Sobrien			       GEN_INT (amount)));
1048890075Sobrien      else
1048990075Sobrien	{
1049090075Sobrien	  /* r3 is always free in the epilogue.  */
1049190075Sobrien	  rtx reg = gen_rtx (REG, SImode, LAST_ARG_REGNUM);
1049290075Sobrien
1049390075Sobrien	  emit_insn (gen_movsi (reg, GEN_INT (amount)));
1049490075Sobrien	  emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, reg));
1049590075Sobrien	}
1049690075Sobrien    }
1049790075Sobrien
1049890075Sobrien  /* Emit a USE (stack_pointer_rtx), so that
1049990075Sobrien     the stack adjustment will not be deleted.  */
1050090075Sobrien  emit_insn (gen_prologue_use (stack_pointer_rtx));
1050190075Sobrien
1050290075Sobrien  if (current_function_profile || TARGET_NO_SCHED_PRO)
1050390075Sobrien    emit_insn (gen_blockage ());
1050490075Sobrien}
1050590075Sobrien
1050690075Sobrienstatic void
1050790075Sobrienthumb_output_function_prologue (f, size)
1050890075Sobrien     FILE * f;
1050990075Sobrien     HOST_WIDE_INT size ATTRIBUTE_UNUSED;
1051090075Sobrien{
1051190075Sobrien  int live_regs_mask = 0;
1051290075Sobrien  int high_regs_pushed = 0;
1051390075Sobrien  int regno;
1051490075Sobrien
1051590075Sobrien  if (IS_NAKED (arm_current_func_type ()))
1051690075Sobrien    return;
1051790075Sobrien
1051890075Sobrien  if (is_called_in_ARM_mode (current_function_decl))
1051990075Sobrien    {
1052090075Sobrien      const char * name;
1052190075Sobrien
1052290075Sobrien      if (GET_CODE (DECL_RTL (current_function_decl)) != MEM)
1052390075Sobrien	abort ();
1052490075Sobrien      if (GET_CODE (XEXP (DECL_RTL (current_function_decl), 0)) != SYMBOL_REF)
1052590075Sobrien	abort ();
1052690075Sobrien      name = XSTR  (XEXP (DECL_RTL (current_function_decl), 0), 0);
1052790075Sobrien
1052890075Sobrien      /* Generate code sequence to switch us into Thumb mode.  */
1052990075Sobrien      /* The .code 32 directive has already been emitted by
1053090075Sobrien	 ASM_DECLARE_FUNCTION_NAME.  */
1053190075Sobrien      asm_fprintf (f, "\torr\t%r, %r, #1\n", IP_REGNUM, PC_REGNUM);
1053290075Sobrien      asm_fprintf (f, "\tbx\t%r\n", IP_REGNUM);
1053390075Sobrien
1053490075Sobrien      /* Generate a label, so that the debugger will notice the
1053590075Sobrien	 change in instruction sets.  This label is also used by
1053690075Sobrien	 the assembler to bypass the ARM code when this function
1053790075Sobrien	 is called from a Thumb encoded function elsewhere in the
1053890075Sobrien	 same file.  Hence the definition of STUB_NAME here must
1053990075Sobrien	 agree with the definition in gas/config/tc-arm.c  */
1054090075Sobrien
1054190075Sobrien#define STUB_NAME ".real_start_of"
1054290075Sobrien
10543117395Skan      fprintf (f, "\t.code\t16\n");
1054490075Sobrien#ifdef ARM_PE
1054590075Sobrien      if (arm_dllexport_name_p (name))
1054690075Sobrien        name = arm_strip_name_encoding (name);
1054790075Sobrien#endif
1054890075Sobrien      asm_fprintf (f, "\t.globl %s%U%s\n", STUB_NAME, name);
10549117395Skan      fprintf (f, "\t.thumb_func\n");
1055090075Sobrien      asm_fprintf (f, "%s%U%s:\n", STUB_NAME, name);
1055190075Sobrien    }
1055290075Sobrien
1055390075Sobrien  if (current_function_pretend_args_size)
1055490075Sobrien    {
1055596263Sobrien      if (cfun->machine->uses_anonymous_args)
1055690075Sobrien	{
1055790075Sobrien	  int num_pushes;
1055890075Sobrien
10559117395Skan	  fprintf (f, "\tpush\t{");
1056090075Sobrien
10561117395Skan	  num_pushes = ARM_NUM_INTS (current_function_pretend_args_size);
1056290075Sobrien
1056390075Sobrien	  for (regno = LAST_ARG_REGNUM + 1 - num_pushes;
1056490075Sobrien	       regno <= LAST_ARG_REGNUM;
1056590075Sobrien	       regno++)
1056690075Sobrien	    asm_fprintf (f, "%r%s", regno,
1056790075Sobrien			 regno == LAST_ARG_REGNUM ? "" : ", ");
1056890075Sobrien
10569117395Skan	  fprintf (f, "}\n");
1057090075Sobrien	}
1057190075Sobrien      else
1057290075Sobrien	asm_fprintf (f, "\tsub\t%r, %r, #%d\n",
1057390075Sobrien		     SP_REGNUM, SP_REGNUM,
1057490075Sobrien		     current_function_pretend_args_size);
1057590075Sobrien    }
1057690075Sobrien
1057790075Sobrien  for (regno = 0; regno <= LAST_LO_REGNUM; regno++)
10578117395Skan    if (THUMB_REG_PUSHED_P (regno))
1057990075Sobrien      live_regs_mask |= 1 << regno;
1058090075Sobrien
1058190075Sobrien  if (live_regs_mask || !leaf_function_p () || thumb_far_jump_used_p (1))
1058290075Sobrien    live_regs_mask |= 1 << LR_REGNUM;
1058390075Sobrien
1058490075Sobrien  if (TARGET_BACKTRACE)
1058590075Sobrien    {
1058690075Sobrien      int    offset;
1058790075Sobrien      int    work_register = 0;
1058890075Sobrien      int    wr;
1058990075Sobrien
1059090075Sobrien      /* We have been asked to create a stack backtrace structure.
1059190075Sobrien         The code looks like this:
1059290075Sobrien
1059390075Sobrien	 0   .align 2
1059490075Sobrien	 0   func:
1059590075Sobrien         0     sub   SP, #16         Reserve space for 4 registers.
1059690075Sobrien	 2     push  {R7}            Get a work register.
1059790075Sobrien         4     add   R7, SP, #20     Get the stack pointer before the push.
1059890075Sobrien         6     str   R7, [SP, #8]    Store the stack pointer (before reserving the space).
1059990075Sobrien         8     mov   R7, PC          Get hold of the start of this code plus 12.
1060090075Sobrien        10     str   R7, [SP, #16]   Store it.
1060190075Sobrien        12     mov   R7, FP          Get hold of the current frame pointer.
1060290075Sobrien        14     str   R7, [SP, #4]    Store it.
1060390075Sobrien        16     mov   R7, LR          Get hold of the current return address.
1060490075Sobrien        18     str   R7, [SP, #12]   Store it.
1060590075Sobrien        20     add   R7, SP, #16     Point at the start of the backtrace structure.
1060690075Sobrien        22     mov   FP, R7          Put this value into the frame pointer.  */
1060790075Sobrien
1060890075Sobrien      if ((live_regs_mask & 0xFF) == 0)
1060990075Sobrien	{
1061090075Sobrien	  /* See if the a4 register is free.  */
1061190075Sobrien
1061290075Sobrien	  if (regs_ever_live [LAST_ARG_REGNUM] == 0)
1061390075Sobrien	    work_register = LAST_ARG_REGNUM;
1061490075Sobrien	  else	  /* We must push a register of our own */
1061590075Sobrien	    live_regs_mask |= (1 << LAST_LO_REGNUM);
1061690075Sobrien	}
1061790075Sobrien
1061890075Sobrien      if (work_register == 0)
1061990075Sobrien	{
1062090075Sobrien	  /* Select a register from the list that will be pushed to
1062190075Sobrien             use as our work register.  */
1062290075Sobrien	  for (work_register = (LAST_LO_REGNUM + 1); work_register--;)
1062390075Sobrien	    if ((1 << work_register) & live_regs_mask)
1062490075Sobrien	      break;
1062590075Sobrien	}
1062690075Sobrien
1062790075Sobrien      asm_fprintf
1062890075Sobrien	(f, "\tsub\t%r, %r, #16\t%@ Create stack backtrace structure\n",
1062990075Sobrien	 SP_REGNUM, SP_REGNUM);
1063090075Sobrien
1063190075Sobrien      if (live_regs_mask)
1063290075Sobrien	thumb_pushpop (f, live_regs_mask, 1);
1063390075Sobrien
1063490075Sobrien      for (offset = 0, wr = 1 << 15; wr != 0; wr >>= 1)
1063590075Sobrien	if (wr & live_regs_mask)
1063690075Sobrien	  offset += 4;
1063790075Sobrien
1063890075Sobrien      asm_fprintf (f, "\tadd\t%r, %r, #%d\n", work_register, SP_REGNUM,
1063990075Sobrien		   offset + 16 + current_function_pretend_args_size);
1064090075Sobrien
1064190075Sobrien      asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
1064290075Sobrien		   offset + 4);
1064390075Sobrien
1064490075Sobrien      /* Make sure that the instruction fetching the PC is in the right place
1064590075Sobrien	 to calculate "start of backtrace creation code + 12".  */
1064690075Sobrien      if (live_regs_mask)
1064790075Sobrien	{
1064890075Sobrien	  asm_fprintf (f, "\tmov\t%r, %r\n", work_register, PC_REGNUM);
1064990075Sobrien	  asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
1065090075Sobrien		       offset + 12);
1065190075Sobrien	  asm_fprintf (f, "\tmov\t%r, %r\n", work_register,
1065290075Sobrien		       ARM_HARD_FRAME_POINTER_REGNUM);
1065390075Sobrien	  asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
1065490075Sobrien		       offset);
1065590075Sobrien	}
1065690075Sobrien      else
1065790075Sobrien	{
1065890075Sobrien	  asm_fprintf (f, "\tmov\t%r, %r\n", work_register,
1065990075Sobrien		       ARM_HARD_FRAME_POINTER_REGNUM);
1066090075Sobrien	  asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
1066190075Sobrien		       offset);
1066290075Sobrien	  asm_fprintf (f, "\tmov\t%r, %r\n", work_register, PC_REGNUM);
1066390075Sobrien	  asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
1066490075Sobrien		       offset + 12);
1066590075Sobrien	}
1066690075Sobrien
1066790075Sobrien      asm_fprintf (f, "\tmov\t%r, %r\n", work_register, LR_REGNUM);
1066890075Sobrien      asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
1066990075Sobrien		   offset + 8);
1067090075Sobrien      asm_fprintf (f, "\tadd\t%r, %r, #%d\n", work_register, SP_REGNUM,
1067190075Sobrien		   offset + 12);
1067290075Sobrien      asm_fprintf (f, "\tmov\t%r, %r\t\t%@ Backtrace structure created\n",
1067390075Sobrien		   ARM_HARD_FRAME_POINTER_REGNUM, work_register);
1067490075Sobrien    }
1067590075Sobrien  else if (live_regs_mask)
1067690075Sobrien    thumb_pushpop (f, live_regs_mask, 1);
1067790075Sobrien
1067890075Sobrien  for (regno = 8; regno < 13; regno++)
10679117395Skan    if (THUMB_REG_PUSHED_P (regno))
10680117395Skan      high_regs_pushed++;
1068190075Sobrien
1068290075Sobrien  if (high_regs_pushed)
1068390075Sobrien    {
1068490075Sobrien      int pushable_regs = 0;
1068590075Sobrien      int mask = live_regs_mask & 0xff;
1068690075Sobrien      int next_hi_reg;
1068790075Sobrien
1068890075Sobrien      for (next_hi_reg = 12; next_hi_reg > LAST_LO_REGNUM; next_hi_reg--)
10689117395Skan	if (THUMB_REG_PUSHED_P (next_hi_reg))
10690117395Skan	  break;
1069190075Sobrien
1069290075Sobrien      pushable_regs = mask;
1069390075Sobrien
1069490075Sobrien      if (pushable_regs == 0)
1069590075Sobrien	{
1069690075Sobrien	  /* Desperation time -- this probably will never happen.  */
10697117395Skan	  if (THUMB_REG_PUSHED_P (LAST_ARG_REGNUM))
1069890075Sobrien	    asm_fprintf (f, "\tmov\t%r, %r\n", IP_REGNUM, LAST_ARG_REGNUM);
1069990075Sobrien	  mask = 1 << LAST_ARG_REGNUM;
1070090075Sobrien	}
1070190075Sobrien
1070290075Sobrien      while (high_regs_pushed > 0)
1070390075Sobrien	{
1070490075Sobrien	  for (regno = LAST_LO_REGNUM; regno >= 0; regno--)
1070590075Sobrien	    {
1070690075Sobrien	      if (mask & (1 << regno))
1070790075Sobrien		{
1070890075Sobrien		  asm_fprintf (f, "\tmov\t%r, %r\n", regno, next_hi_reg);
1070990075Sobrien
1071090075Sobrien		  high_regs_pushed--;
1071190075Sobrien
1071290075Sobrien		  if (high_regs_pushed)
10713117395Skan		    {
10714117395Skan		      for (next_hi_reg--; next_hi_reg > LAST_LO_REGNUM;
10715117395Skan			   next_hi_reg--)
10716117395Skan			if (THUMB_REG_PUSHED_P (next_hi_reg))
1071790075Sobrien			  break;
10718117395Skan		    }
1071990075Sobrien		  else
1072090075Sobrien		    {
1072190075Sobrien		      mask &= ~((1 << regno) - 1);
1072290075Sobrien		      break;
1072390075Sobrien		    }
1072490075Sobrien		}
1072590075Sobrien	    }
1072690075Sobrien
1072790075Sobrien	  thumb_pushpop (f, mask, 1);
1072890075Sobrien	}
1072990075Sobrien
1073090075Sobrien      if (pushable_regs == 0
10731117395Skan	  && (THUMB_REG_PUSHED_P (LAST_ARG_REGNUM)))
1073290075Sobrien	asm_fprintf (f, "\tmov\t%r, %r\n", LAST_ARG_REGNUM, IP_REGNUM);
1073390075Sobrien    }
1073490075Sobrien}
1073590075Sobrien
1073690075Sobrien/* Handle the case of a double word load into a low register from
1073790075Sobrien   a computed memory address.  The computed address may involve a
1073890075Sobrien   register which is overwritten by the load.  */
1073990075Sobrien
1074090075Sobrienconst char *
1074190075Sobrienthumb_load_double_from_address (operands)
1074290075Sobrien     rtx *operands;
1074390075Sobrien{
1074490075Sobrien  rtx addr;
1074590075Sobrien  rtx base;
1074690075Sobrien  rtx offset;
1074790075Sobrien  rtx arg1;
1074890075Sobrien  rtx arg2;
1074990075Sobrien
1075090075Sobrien  if (GET_CODE (operands[0]) != REG)
1075190075Sobrien    abort ();
1075290075Sobrien
1075390075Sobrien  if (GET_CODE (operands[1]) != MEM)
1075490075Sobrien    abort ();
1075590075Sobrien
1075690075Sobrien  /* Get the memory address.  */
1075790075Sobrien  addr = XEXP (operands[1], 0);
1075890075Sobrien
1075990075Sobrien  /* Work out how the memory address is computed.  */
1076090075Sobrien  switch (GET_CODE (addr))
1076190075Sobrien    {
1076290075Sobrien    case REG:
1076390075Sobrien      operands[2] = gen_rtx (MEM, SImode,
1076490075Sobrien			     plus_constant (XEXP (operands[1], 0), 4));
1076590075Sobrien
1076690075Sobrien      if (REGNO (operands[0]) == REGNO (addr))
1076790075Sobrien	{
1076890075Sobrien	  output_asm_insn ("ldr\t%H0, %2", operands);
1076990075Sobrien	  output_asm_insn ("ldr\t%0, %1", operands);
1077090075Sobrien	}
1077190075Sobrien      else
1077290075Sobrien	{
1077390075Sobrien	  output_asm_insn ("ldr\t%0, %1", operands);
1077490075Sobrien	  output_asm_insn ("ldr\t%H0, %2", operands);
1077590075Sobrien	}
1077690075Sobrien      break;
1077790075Sobrien
1077890075Sobrien    case CONST:
1077990075Sobrien      /* Compute <address> + 4 for the high order load.  */
1078090075Sobrien      operands[2] = gen_rtx (MEM, SImode,
1078190075Sobrien			     plus_constant (XEXP (operands[1], 0), 4));
1078290075Sobrien
1078390075Sobrien      output_asm_insn ("ldr\t%0, %1", operands);
1078490075Sobrien      output_asm_insn ("ldr\t%H0, %2", operands);
1078590075Sobrien      break;
1078690075Sobrien
1078790075Sobrien    case PLUS:
1078890075Sobrien      arg1   = XEXP (addr, 0);
1078990075Sobrien      arg2   = XEXP (addr, 1);
1079090075Sobrien
1079190075Sobrien      if (CONSTANT_P (arg1))
1079290075Sobrien	base = arg2, offset = arg1;
1079390075Sobrien      else
1079490075Sobrien	base = arg1, offset = arg2;
1079590075Sobrien
1079690075Sobrien      if (GET_CODE (base) != REG)
1079790075Sobrien	abort ();
1079890075Sobrien
1079990075Sobrien      /* Catch the case of <address> = <reg> + <reg> */
1080090075Sobrien      if (GET_CODE (offset) == REG)
1080190075Sobrien	{
1080290075Sobrien	  int reg_offset = REGNO (offset);
1080390075Sobrien	  int reg_base   = REGNO (base);
1080490075Sobrien	  int reg_dest   = REGNO (operands[0]);
1080590075Sobrien
1080690075Sobrien	  /* Add the base and offset registers together into the
1080790075Sobrien             higher destination register.  */
1080890075Sobrien	  asm_fprintf (asm_out_file, "\tadd\t%r, %r, %r",
1080990075Sobrien		       reg_dest + 1, reg_base, reg_offset);
1081090075Sobrien
1081190075Sobrien	  /* Load the lower destination register from the address in
1081290075Sobrien             the higher destination register.  */
1081390075Sobrien	  asm_fprintf (asm_out_file, "\tldr\t%r, [%r, #0]",
1081490075Sobrien		       reg_dest, reg_dest + 1);
1081590075Sobrien
1081690075Sobrien	  /* Load the higher destination register from its own address
1081790075Sobrien             plus 4.  */
1081890075Sobrien	  asm_fprintf (asm_out_file, "\tldr\t%r, [%r, #4]",
1081990075Sobrien		       reg_dest + 1, reg_dest + 1);
1082090075Sobrien	}
1082190075Sobrien      else
1082290075Sobrien	{
1082390075Sobrien	  /* Compute <address> + 4 for the high order load.  */
1082490075Sobrien	  operands[2] = gen_rtx (MEM, SImode,
1082590075Sobrien				 plus_constant (XEXP (operands[1], 0), 4));
1082690075Sobrien
1082790075Sobrien	  /* If the computed address is held in the low order register
1082890075Sobrien	     then load the high order register first, otherwise always
1082990075Sobrien	     load the low order register first.  */
1083090075Sobrien	  if (REGNO (operands[0]) == REGNO (base))
1083190075Sobrien	    {
1083290075Sobrien	      output_asm_insn ("ldr\t%H0, %2", operands);
1083390075Sobrien	      output_asm_insn ("ldr\t%0, %1", operands);
1083490075Sobrien	    }
1083590075Sobrien	  else
1083690075Sobrien	    {
1083790075Sobrien	      output_asm_insn ("ldr\t%0, %1", operands);
1083890075Sobrien	      output_asm_insn ("ldr\t%H0, %2", operands);
1083990075Sobrien	    }
1084090075Sobrien	}
1084190075Sobrien      break;
1084290075Sobrien
1084390075Sobrien    case LABEL_REF:
1084490075Sobrien      /* With no registers to worry about we can just load the value
1084590075Sobrien         directly.  */
1084690075Sobrien      operands[2] = gen_rtx (MEM, SImode,
1084790075Sobrien			     plus_constant (XEXP (operands[1], 0), 4));
1084890075Sobrien
1084990075Sobrien      output_asm_insn ("ldr\t%H0, %2", operands);
1085090075Sobrien      output_asm_insn ("ldr\t%0, %1", operands);
1085190075Sobrien      break;
1085290075Sobrien
1085390075Sobrien    default:
1085490075Sobrien      abort ();
1085590075Sobrien      break;
1085690075Sobrien    }
1085790075Sobrien
1085890075Sobrien  return "";
1085990075Sobrien}
1086090075Sobrien
1086190075Sobrien
1086290075Sobrienconst char *
1086390075Sobrienthumb_output_move_mem_multiple (n, operands)
1086490075Sobrien     int n;
1086590075Sobrien     rtx * operands;
1086690075Sobrien{
1086790075Sobrien  rtx tmp;
1086890075Sobrien
1086990075Sobrien  switch (n)
1087090075Sobrien    {
1087190075Sobrien    case 2:
1087290075Sobrien      if (REGNO (operands[4]) > REGNO (operands[5]))
1087390075Sobrien	{
1087490075Sobrien	  tmp = operands[4];
1087590075Sobrien	  operands[4] = operands[5];
1087690075Sobrien	  operands[5] = tmp;
1087790075Sobrien	}
1087890075Sobrien      output_asm_insn ("ldmia\t%1!, {%4, %5}", operands);
1087990075Sobrien      output_asm_insn ("stmia\t%0!, {%4, %5}", operands);
1088090075Sobrien      break;
1088190075Sobrien
1088290075Sobrien    case 3:
1088390075Sobrien      if (REGNO (operands[4]) > REGNO (operands[5]))
1088490075Sobrien	{
1088590075Sobrien	  tmp = operands[4];
1088690075Sobrien	  operands[4] = operands[5];
1088790075Sobrien	  operands[5] = tmp;
1088890075Sobrien	}
1088990075Sobrien      if (REGNO (operands[5]) > REGNO (operands[6]))
1089090075Sobrien	{
1089190075Sobrien	  tmp = operands[5];
1089290075Sobrien	  operands[5] = operands[6];
1089390075Sobrien	  operands[6] = tmp;
1089490075Sobrien	}
1089590075Sobrien      if (REGNO (operands[4]) > REGNO (operands[5]))
1089690075Sobrien	{
1089790075Sobrien	  tmp = operands[4];
1089890075Sobrien	  operands[4] = operands[5];
1089990075Sobrien	  operands[5] = tmp;
1090090075Sobrien	}
1090190075Sobrien
1090290075Sobrien      output_asm_insn ("ldmia\t%1!, {%4, %5, %6}", operands);
1090390075Sobrien      output_asm_insn ("stmia\t%0!, {%4, %5, %6}", operands);
1090490075Sobrien      break;
1090590075Sobrien
1090690075Sobrien    default:
1090790075Sobrien      abort ();
1090890075Sobrien    }
1090990075Sobrien
1091090075Sobrien  return "";
1091190075Sobrien}
1091290075Sobrien
1091390075Sobrien/* Routines for generating rtl.  */
1091490075Sobrien
1091590075Sobrienvoid
1091690075Sobrienthumb_expand_movstrqi (operands)
1091790075Sobrien     rtx * operands;
1091890075Sobrien{
1091990075Sobrien  rtx out = copy_to_mode_reg (SImode, XEXP (operands[0], 0));
1092090075Sobrien  rtx in  = copy_to_mode_reg (SImode, XEXP (operands[1], 0));
1092190075Sobrien  HOST_WIDE_INT len = INTVAL (operands[2]);
1092290075Sobrien  HOST_WIDE_INT offset = 0;
1092390075Sobrien
1092490075Sobrien  while (len >= 12)
1092590075Sobrien    {
1092690075Sobrien      emit_insn (gen_movmem12b (out, in, out, in));
1092790075Sobrien      len -= 12;
1092890075Sobrien    }
1092990075Sobrien
1093090075Sobrien  if (len >= 8)
1093190075Sobrien    {
1093290075Sobrien      emit_insn (gen_movmem8b (out, in, out, in));
1093390075Sobrien      len -= 8;
1093490075Sobrien    }
1093590075Sobrien
1093690075Sobrien  if (len >= 4)
1093790075Sobrien    {
1093890075Sobrien      rtx reg = gen_reg_rtx (SImode);
1093990075Sobrien      emit_insn (gen_movsi (reg, gen_rtx (MEM, SImode, in)));
1094090075Sobrien      emit_insn (gen_movsi (gen_rtx (MEM, SImode, out), reg));
1094190075Sobrien      len -= 4;
1094290075Sobrien      offset += 4;
1094390075Sobrien    }
1094490075Sobrien
1094590075Sobrien  if (len >= 2)
1094690075Sobrien    {
1094790075Sobrien      rtx reg = gen_reg_rtx (HImode);
1094890075Sobrien      emit_insn (gen_movhi (reg, gen_rtx (MEM, HImode,
1094990075Sobrien					  plus_constant (in, offset))));
1095090075Sobrien      emit_insn (gen_movhi (gen_rtx (MEM, HImode, plus_constant (out, offset)),
1095190075Sobrien			    reg));
1095290075Sobrien      len -= 2;
1095390075Sobrien      offset += 2;
1095490075Sobrien    }
1095590075Sobrien
1095690075Sobrien  if (len)
1095790075Sobrien    {
1095890075Sobrien      rtx reg = gen_reg_rtx (QImode);
1095990075Sobrien      emit_insn (gen_movqi (reg, gen_rtx (MEM, QImode,
1096090075Sobrien					  plus_constant (in, offset))));
1096190075Sobrien      emit_insn (gen_movqi (gen_rtx (MEM, QImode, plus_constant (out, offset)),
1096290075Sobrien			    reg));
1096390075Sobrien    }
1096490075Sobrien}
1096590075Sobrien
1096690075Sobrienint
1096790075Sobrienthumb_cmp_operand (op, mode)
1096890075Sobrien     rtx op;
1096990075Sobrien     enum machine_mode mode;
1097090075Sobrien{
1097190075Sobrien  return ((GET_CODE (op) == CONST_INT
1097290075Sobrien	   && (unsigned HOST_WIDE_INT) (INTVAL (op)) < 256)
1097390075Sobrien	  || register_operand (op, mode));
1097490075Sobrien}
1097590075Sobrien
1097690075Sobrienstatic const char *
1097790075Sobrienthumb_condition_code (x, invert)
1097890075Sobrien     rtx x;
1097990075Sobrien     int invert;
1098090075Sobrien{
1098190075Sobrien  static const char * const conds[] =
1098290075Sobrien  {
1098390075Sobrien    "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
1098490075Sobrien    "hi", "ls", "ge", "lt", "gt", "le"
1098590075Sobrien  };
1098690075Sobrien  int val;
1098790075Sobrien
1098890075Sobrien  switch (GET_CODE (x))
1098990075Sobrien    {
1099090075Sobrien    case EQ: val = 0; break;
1099190075Sobrien    case NE: val = 1; break;
1099290075Sobrien    case GEU: val = 2; break;
1099390075Sobrien    case LTU: val = 3; break;
1099490075Sobrien    case GTU: val = 8; break;
1099590075Sobrien    case LEU: val = 9; break;
1099690075Sobrien    case GE: val = 10; break;
1099790075Sobrien    case LT: val = 11; break;
1099890075Sobrien    case GT: val = 12; break;
1099990075Sobrien    case LE: val = 13; break;
1100090075Sobrien    default:
1100190075Sobrien      abort ();
1100290075Sobrien    }
1100390075Sobrien
1100490075Sobrien  return conds[val ^ invert];
1100590075Sobrien}
1100690075Sobrien
1100790075Sobrien/* Handle storing a half-word to memory during reload.  */
1100890075Sobrien
1100990075Sobrienvoid
1101090075Sobrienthumb_reload_out_hi (operands)
1101190075Sobrien     rtx * operands;
1101290075Sobrien{
1101390075Sobrien  emit_insn (gen_thumb_movhi_clobber (operands[0], operands[1], operands[2]));
1101490075Sobrien}
1101590075Sobrien
1101690075Sobrien/* Handle storing a half-word to memory during reload.  */
1101790075Sobrien
1101890075Sobrienvoid
1101990075Sobrienthumb_reload_in_hi (operands)
1102090075Sobrien     rtx * operands ATTRIBUTE_UNUSED;
1102190075Sobrien{
1102290075Sobrien  abort ();
1102390075Sobrien}
1102490075Sobrien
1102590075Sobrien/* Return the length of a function name prefix
1102690075Sobrien    that starts with the character 'c'.  */
1102790075Sobrien
1102890075Sobrienstatic int
11029117395Skanarm_get_strip_length (c)
11030117395Skan     int c;
1103190075Sobrien{
1103290075Sobrien  switch (c)
1103390075Sobrien    {
1103490075Sobrien    ARM_NAME_ENCODING_LENGTHS
1103590075Sobrien      default: return 0;
1103690075Sobrien    }
1103790075Sobrien}
1103890075Sobrien
1103990075Sobrien/* Return a pointer to a function's name with any
1104090075Sobrien   and all prefix encodings stripped from it.  */
1104190075Sobrien
1104290075Sobrienconst char *
11043117395Skanarm_strip_name_encoding (name)
11044117395Skan     const char * name;
1104590075Sobrien{
1104690075Sobrien  int skip;
1104790075Sobrien
1104890075Sobrien  while ((skip = arm_get_strip_length (* name)))
1104990075Sobrien    name += skip;
1105090075Sobrien
1105190075Sobrien  return name;
1105290075Sobrien}
1105390075Sobrien
11054117395Skan/* If there is a '*' anywhere in the name's prefix, then
11055117395Skan   emit the stripped name verbatim, otherwise prepend an
11056117395Skan   underscore if leading underscores are being used.  */
11057117395Skan
11058117395Skanvoid
11059117395Skanarm_asm_output_labelref (stream, name)
11060117395Skan     FILE * stream;
11061117395Skan     const char * name;
11062117395Skan{
11063117395Skan  int skip;
11064117395Skan  int verbatim = 0;
11065117395Skan
11066117395Skan  while ((skip = arm_get_strip_length (* name)))
11067117395Skan    {
11068117395Skan      verbatim |= (*name == '*');
11069117395Skan      name += skip;
11070117395Skan    }
11071117395Skan
11072117395Skan  if (verbatim)
11073117395Skan    fputs (name, stream);
11074117395Skan  else
11075117395Skan    asm_fprintf (stream, "%U%s", name);
11076117395Skan}
11077117395Skan
11078117395Skanrtx aof_pic_label;
11079117395Skan
1108090075Sobrien#ifdef AOF_ASSEMBLER
1108190075Sobrien/* Special functions only needed when producing AOF syntax assembler.  */
1108290075Sobrien
1108390075Sobrienstruct pic_chain
1108490075Sobrien{
1108590075Sobrien  struct pic_chain * next;
1108690075Sobrien  const char * symname;
1108790075Sobrien};
1108890075Sobrien
1108990075Sobrienstatic struct pic_chain * aof_pic_chain = NULL;
1109090075Sobrien
1109190075Sobrienrtx
1109290075Sobrienaof_pic_entry (x)
1109390075Sobrien     rtx x;
1109490075Sobrien{
1109590075Sobrien  struct pic_chain ** chainp;
1109690075Sobrien  int offset;
1109790075Sobrien
1109890075Sobrien  if (aof_pic_label == NULL_RTX)
1109990075Sobrien    {
1110090075Sobrien      aof_pic_label = gen_rtx_SYMBOL_REF (Pmode, "x$adcons");
1110190075Sobrien    }
1110290075Sobrien
1110390075Sobrien  for (offset = 0, chainp = &aof_pic_chain; *chainp;
1110490075Sobrien       offset += 4, chainp = &(*chainp)->next)
1110590075Sobrien    if ((*chainp)->symname == XSTR (x, 0))
1110690075Sobrien      return plus_constant (aof_pic_label, offset);
1110790075Sobrien
1110890075Sobrien  *chainp = (struct pic_chain *) xmalloc (sizeof (struct pic_chain));
1110990075Sobrien  (*chainp)->next = NULL;
1111090075Sobrien  (*chainp)->symname = XSTR (x, 0);
1111190075Sobrien  return plus_constant (aof_pic_label, offset);
1111290075Sobrien}
1111390075Sobrien
1111490075Sobrienvoid
1111590075Sobrienaof_dump_pic_table (f)
1111690075Sobrien     FILE * f;
1111790075Sobrien{
1111890075Sobrien  struct pic_chain * chain;
1111990075Sobrien
1112090075Sobrien  if (aof_pic_chain == NULL)
1112190075Sobrien    return;
1112290075Sobrien
1112390075Sobrien  asm_fprintf (f, "\tAREA |%r$$adcons|, BASED %r\n",
1112490075Sobrien	       PIC_OFFSET_TABLE_REGNUM,
1112590075Sobrien	       PIC_OFFSET_TABLE_REGNUM);
1112690075Sobrien  fputs ("|x$adcons|\n", f);
1112790075Sobrien
1112890075Sobrien  for (chain = aof_pic_chain; chain; chain = chain->next)
1112990075Sobrien    {
1113090075Sobrien      fputs ("\tDCD\t", f);
1113190075Sobrien      assemble_name (f, chain->symname);
1113290075Sobrien      fputs ("\n", f);
1113390075Sobrien    }
1113490075Sobrien}
1113590075Sobrien
1113690075Sobrienint arm_text_section_count = 1;
1113790075Sobrien
1113890075Sobrienchar *
1113990075Sobrienaof_text_section ()
1114090075Sobrien{
1114190075Sobrien  static char buf[100];
1114290075Sobrien  sprintf (buf, "\tAREA |C$$code%d|, CODE, READONLY",
1114390075Sobrien	   arm_text_section_count++);
1114490075Sobrien  if (flag_pic)
1114590075Sobrien    strcat (buf, ", PIC, REENTRANT");
1114690075Sobrien  return buf;
1114790075Sobrien}
1114890075Sobrien
1114990075Sobrienstatic int arm_data_section_count = 1;
1115090075Sobrien
1115190075Sobrienchar *
1115290075Sobrienaof_data_section ()
1115390075Sobrien{
1115490075Sobrien  static char buf[100];
1115590075Sobrien  sprintf (buf, "\tAREA |C$$data%d|, DATA", arm_data_section_count++);
1115690075Sobrien  return buf;
1115790075Sobrien}
1115890075Sobrien
1115990075Sobrien/* The AOF assembler is religiously strict about declarations of
1116090075Sobrien   imported and exported symbols, so that it is impossible to declare
1116190075Sobrien   a function as imported near the beginning of the file, and then to
1116290075Sobrien   export it later on.  It is, however, possible to delay the decision
1116390075Sobrien   until all the functions in the file have been compiled.  To get
1116490075Sobrien   around this, we maintain a list of the imports and exports, and
1116590075Sobrien   delete from it any that are subsequently defined.  At the end of
1116690075Sobrien   compilation we spit the remainder of the list out before the END
1116790075Sobrien   directive.  */
1116890075Sobrien
1116990075Sobrienstruct import
1117090075Sobrien{
1117190075Sobrien  struct import * next;
1117290075Sobrien  const char * name;
1117390075Sobrien};
1117490075Sobrien
1117590075Sobrienstatic struct import * imports_list = NULL;
1117690075Sobrien
1117790075Sobrienvoid
1117890075Sobrienaof_add_import (name)
1117990075Sobrien     const char * name;
1118090075Sobrien{
1118190075Sobrien  struct import * new;
1118290075Sobrien
1118390075Sobrien  for (new = imports_list; new; new = new->next)
1118490075Sobrien    if (new->name == name)
1118590075Sobrien      return;
1118690075Sobrien
1118790075Sobrien  new = (struct import *) xmalloc (sizeof (struct import));
1118890075Sobrien  new->next = imports_list;
1118990075Sobrien  imports_list = new;
1119090075Sobrien  new->name = name;
1119190075Sobrien}
1119290075Sobrien
1119390075Sobrienvoid
1119490075Sobrienaof_delete_import (name)
1119590075Sobrien     const char * name;
1119690075Sobrien{
1119790075Sobrien  struct import ** old;
1119890075Sobrien
1119990075Sobrien  for (old = &imports_list; *old; old = & (*old)->next)
1120090075Sobrien    {
1120190075Sobrien      if ((*old)->name == name)
1120290075Sobrien	{
1120390075Sobrien	  *old = (*old)->next;
1120490075Sobrien	  return;
1120590075Sobrien	}
1120690075Sobrien    }
1120790075Sobrien}
1120890075Sobrien
1120990075Sobrienint arm_main_function = 0;
1121090075Sobrien
1121190075Sobrienvoid
1121290075Sobrienaof_dump_imports (f)
1121390075Sobrien     FILE * f;
1121490075Sobrien{
1121590075Sobrien  /* The AOF assembler needs this to cause the startup code to be extracted
1121690075Sobrien     from the library.  Brining in __main causes the whole thing to work
1121790075Sobrien     automagically.  */
1121890075Sobrien  if (arm_main_function)
1121990075Sobrien    {
1122090075Sobrien      text_section ();
1122190075Sobrien      fputs ("\tIMPORT __main\n", f);
1122290075Sobrien      fputs ("\tDCD __main\n", f);
1122390075Sobrien    }
1122490075Sobrien
1122590075Sobrien  /* Now dump the remaining imports.  */
1122690075Sobrien  while (imports_list)
1122790075Sobrien    {
1122890075Sobrien      fprintf (f, "\tIMPORT\t");
1122990075Sobrien      assemble_name (f, imports_list->name);
1123090075Sobrien      fputc ('\n', f);
1123190075Sobrien      imports_list = imports_list->next;
1123290075Sobrien    }
1123390075Sobrien}
11234117395Skan
11235117395Skanstatic void
11236117395Skanaof_globalize_label (stream, name)
11237117395Skan     FILE *stream;
11238117395Skan     const char *name;
11239117395Skan{
11240117395Skan  default_globalize_label (stream, name);
11241117395Skan  if (! strcmp (name, "main"))
11242117395Skan    arm_main_function = 1;
11243117395Skan}
1124490075Sobrien#endif /* AOF_ASSEMBLER */
1124590075Sobrien
1124690075Sobrien#ifdef OBJECT_FORMAT_ELF
1124790075Sobrien/* Switch to an arbitrary section NAME with attributes as specified
1124890075Sobrien   by FLAGS.  ALIGN specifies any known alignment requirements for
1124990075Sobrien   the section; 0 if the default should be used.
1125090075Sobrien
1125190075Sobrien   Differs from the default elf version only in the prefix character
1125290075Sobrien   used before the section type.  */
1125390075Sobrien
1125490075Sobrienstatic void
1125590075Sobrienarm_elf_asm_named_section (name, flags)
1125690075Sobrien     const char *name;
1125790075Sobrien     unsigned int flags;
1125890075Sobrien{
11259117395Skan  char flagchars[10], *f = flagchars;
1126090075Sobrien
11261117395Skan  if (! named_section_first_declaration (name))
11262117395Skan    {
11263117395Skan      fprintf (asm_out_file, "\t.section\t%s\n", name);
11264117395Skan      return;
11265117395Skan    }
11266117395Skan
1126790075Sobrien  if (!(flags & SECTION_DEBUG))
1126890075Sobrien    *f++ = 'a';
1126990075Sobrien  if (flags & SECTION_WRITE)
1127090075Sobrien    *f++ = 'w';
1127190075Sobrien  if (flags & SECTION_CODE)
1127290075Sobrien    *f++ = 'x';
1127390075Sobrien  if (flags & SECTION_SMALL)
1127490075Sobrien    *f++ = 's';
1127590075Sobrien  if (flags & SECTION_MERGE)
1127690075Sobrien    *f++ = 'M';
1127790075Sobrien  if (flags & SECTION_STRINGS)
1127890075Sobrien    *f++ = 'S';
11279117395Skan  if (flags & SECTION_TLS)
11280117395Skan    *f++ = 'T';
1128190075Sobrien  *f = '\0';
1128290075Sobrien
11283117395Skan  fprintf (asm_out_file, "\t.section\t%s,\"%s\"", name, flagchars);
1128490075Sobrien
11285117395Skan  if (!(flags & SECTION_NOTYPE))
11286117395Skan    {
11287117395Skan      const char *type;
11288117395Skan
11289117395Skan      if (flags & SECTION_BSS)
11290117395Skan	type = "nobits";
11291117395Skan      else
11292117395Skan	type = "progbits";
11293117395Skan
11294117395Skan      fprintf (asm_out_file, ",%%%s", type);
11295117395Skan
11296117395Skan      if (flags & SECTION_ENTSIZE)
11297117395Skan	fprintf (asm_out_file, ",%d", flags & SECTION_ENTSIZE);
11298117395Skan    }
11299117395Skan
11300117395Skan  putc ('\n', asm_out_file);
1130190075Sobrien}
1130290075Sobrien#endif
11303117395Skan
11304117395Skan#ifndef ARM_PE
11305117395Skan/* Symbols in the text segment can be accessed without indirecting via the
11306117395Skan   constant pool; it may take an extra binary operation, but this is still
11307117395Skan   faster than indirecting via memory.  Don't do this when not optimizing,
11308117395Skan   since we won't be calculating al of the offsets necessary to do this
11309117395Skan   simplification.  */
11310117395Skan
11311117395Skanstatic void
11312117395Skanarm_encode_section_info (decl, first)
11313117395Skan     tree decl;
11314117395Skan     int first;
11315117395Skan{
11316117395Skan  /* This doesn't work with AOF syntax, since the string table may be in
11317117395Skan     a different AREA.  */
11318117395Skan#ifndef AOF_ASSEMBLER
11319117395Skan  if (optimize > 0 && TREE_CONSTANT (decl)
11320117395Skan      && (!flag_writable_strings || TREE_CODE (decl) != STRING_CST))
11321117395Skan    {
11322117395Skan      rtx rtl = (TREE_CODE_CLASS (TREE_CODE (decl)) != 'd'
11323117395Skan                 ? TREE_CST_RTL (decl) : DECL_RTL (decl));
11324117395Skan      SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1;
11325117395Skan    }
11326117395Skan#endif
11327117395Skan
11328117395Skan  /* If we are referencing a function that is weak then encode a long call
11329117395Skan     flag in the function name, otherwise if the function is static or
11330117395Skan     or known to be defined in this file then encode a short call flag.  */
11331117395Skan  if (first && TREE_CODE_CLASS (TREE_CODE (decl)) == 'd')
11332117395Skan    {
11333117395Skan      if (TREE_CODE (decl) == FUNCTION_DECL && DECL_WEAK (decl))
11334117395Skan        arm_encode_call_attribute (decl, LONG_CALL_FLAG_CHAR);
11335117395Skan      else if (! TREE_PUBLIC (decl))
11336117395Skan        arm_encode_call_attribute (decl, SHORT_CALL_FLAG_CHAR);
11337117395Skan    }
11338117395Skan}
11339117395Skan#endif /* !ARM_PE */
11340117395Skan
11341117395Skan/* Output code to add DELTA to the first argument, and then jump
11342117395Skan   to FUNCTION.  Used for C++ multiple inheritance.  */
11343117395Skan
11344117395Skanstatic void
11345117395Skanarm_output_mi_thunk (file, thunk, delta, vcall_offset, function)
11346117395Skan     FILE *file;
11347117395Skan     tree thunk ATTRIBUTE_UNUSED;
11348117395Skan     HOST_WIDE_INT delta;
11349117395Skan     HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED;
11350117395Skan     tree function;
11351117395Skan{
11352117395Skan  int mi_delta = delta;
11353117395Skan  const char *const mi_op = mi_delta < 0 ? "sub" : "add";
11354117395Skan  int shift = 0;
11355117395Skan  int this_regno = (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)))
11356117395Skan                    ? 1 : 0);
11357117395Skan  if (mi_delta < 0)
11358117395Skan    mi_delta = - mi_delta;
11359117395Skan  while (mi_delta != 0)
11360117395Skan    {
11361117395Skan      if ((mi_delta & (3 << shift)) == 0)
11362117395Skan        shift += 2;
11363117395Skan      else
11364117395Skan        {
11365117395Skan          asm_fprintf (file, "\t%s\t%r, %r, #%d\n",
11366117395Skan                       mi_op, this_regno, this_regno,
11367117395Skan                       mi_delta & (0xff << shift));
11368117395Skan          mi_delta &= ~(0xff << shift);
11369117395Skan          shift += 8;
11370117395Skan        }
11371117395Skan    }
11372117395Skan  fputs ("\tb\t", file);
11373117395Skan  assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0));
11374117395Skan  if (NEED_PLT_RELOC)
11375117395Skan    fputs ("(PLT)", file);
11376117395Skan  fputc ('\n', file);
11377117395Skan}
11378117395Skan
11379