arm.c revision 161651
190075Sobrien/* Output routines for GCC for ARM.
2132718Skan   Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
3146895Skan   2002, 2003, 2004, 2005  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
8132718Skan   This file is part of GCC.
990075Sobrien
10132718Skan   GCC is free software; you can redistribute it and/or modify it
11132718Skan   under the terms of the GNU General Public License as published
12132718Skan   by the Free Software Foundation; either version 2, or (at your
13132718Skan   option) any later version.
1490075Sobrien
15132718Skan   GCC is distributed in the hope that it will be useful, but WITHOUT
16132718Skan   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17132718Skan   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
18132718Skan   License for more details.
1990075Sobrien
20132718Skan   You should have received a copy of the GNU General Public License
21132718Skan   along with GCC; see the file COPYING.  If not, write to
22132718Skan   the Free Software Foundation, 59 Temple Place - Suite 330,
23132718Skan   Boston, MA 02111-1307, USA.  */
2490075Sobrien
2590075Sobrien#include "config.h"
2690075Sobrien#include "system.h"
27132718Skan#include "coretypes.h"
28132718Skan#include "tm.h"
2990075Sobrien#include "rtl.h"
3090075Sobrien#include "tree.h"
3190075Sobrien#include "obstack.h"
3290075Sobrien#include "regs.h"
3390075Sobrien#include "hard-reg-set.h"
3490075Sobrien#include "real.h"
3590075Sobrien#include "insn-config.h"
3690075Sobrien#include "conditions.h"
3790075Sobrien#include "output.h"
3890075Sobrien#include "insn-attr.h"
3990075Sobrien#include "flags.h"
4090075Sobrien#include "reload.h"
4190075Sobrien#include "function.h"
4290075Sobrien#include "expr.h"
4390075Sobrien#include "optabs.h"
4490075Sobrien#include "toplev.h"
4590075Sobrien#include "recog.h"
4690075Sobrien#include "ggc.h"
4790075Sobrien#include "except.h"
4890075Sobrien#include "c-pragma.h"
4990075Sobrien#include "integrate.h"
5090075Sobrien#include "tm_p.h"
5190075Sobrien#include "target.h"
5290075Sobrien#include "target-def.h"
53132718Skan#include "debug.h"
5490075Sobrien
5590075Sobrien/* Forward definitions of types.  */
5690075Sobrientypedef struct minipool_node    Mnode;
5790075Sobrientypedef struct minipool_fixup   Mfix;
5890075Sobrien
5990075Sobrienconst struct attribute_spec arm_attribute_table[];
6090075Sobrien
6190075Sobrien/* Forward function declarations.  */
62132718Skanstatic void arm_add_gc_roots (void);
63132718Skanstatic int arm_gen_constant (enum rtx_code, enum machine_mode, HOST_WIDE_INT,
64132718Skan			     rtx, rtx, int, int);
65132718Skanstatic unsigned bit_count (unsigned long);
66132718Skanstatic int arm_address_register_rtx_p (rtx, int);
67132718Skanstatic int arm_legitimate_index_p (enum machine_mode, rtx, int);
68132718Skanstatic int thumb_base_register_rtx_p (rtx, enum machine_mode, int);
69132718Skaninline static int thumb_index_register_rtx_p (rtx, int);
70132718Skanstatic int const_ok_for_op (HOST_WIDE_INT, enum rtx_code);
71132718Skanstatic rtx emit_multi_reg_push (int);
72132718Skanstatic rtx emit_sfm (int, int);
7390075Sobrien#ifndef AOF_ASSEMBLER
74132718Skanstatic bool arm_assemble_integer (rtx, unsigned int, int);
7590075Sobrien#endif
76132718Skanstatic const char *fp_const_from_val (REAL_VALUE_TYPE *);
77132718Skanstatic arm_cc get_arm_condition_code (rtx);
78132718Skanstatic void init_fpa_table (void);
79132718Skanstatic HOST_WIDE_INT int_log2 (HOST_WIDE_INT);
80132718Skanstatic rtx is_jump_table (rtx);
81132718Skanstatic const char *output_multi_immediate (rtx *, const char *, const char *,
82132718Skan					   int, HOST_WIDE_INT);
83132718Skanstatic void print_multi_reg (FILE *, const char *, int, int);
84132718Skanstatic const char *shift_op (rtx, HOST_WIDE_INT *);
85132718Skanstatic struct machine_function *arm_init_machine_status (void);
86132718Skanstatic int number_of_first_bit_set (int);
87132718Skanstatic void replace_symbols_in_block (tree, rtx, rtx);
88132718Skanstatic void thumb_exit (FILE *, int, rtx);
89132718Skanstatic void thumb_pushpop (FILE *, int, int, int *, int);
90132718Skanstatic rtx is_jump_table (rtx);
91132718Skanstatic HOST_WIDE_INT get_jump_table_size (rtx);
92132718Skanstatic Mnode *move_minipool_fix_forward_ref (Mnode *, Mnode *, HOST_WIDE_INT);
93132718Skanstatic Mnode *add_minipool_forward_ref (Mfix *);
94132718Skanstatic Mnode *move_minipool_fix_backward_ref (Mnode *, Mnode *, HOST_WIDE_INT);
95132718Skanstatic Mnode *add_minipool_backward_ref (Mfix *);
96132718Skanstatic void assign_minipool_offsets (Mfix *);
97132718Skanstatic void arm_print_value (FILE *, rtx);
98132718Skanstatic void dump_minipool (rtx);
99132718Skanstatic int arm_barrier_cost (rtx);
100132718Skanstatic Mfix *create_fix_barrier (Mfix *, HOST_WIDE_INT);
101132718Skanstatic void push_minipool_barrier (rtx, HOST_WIDE_INT);
102132718Skanstatic void push_minipool_fix (rtx, HOST_WIDE_INT, rtx *, enum machine_mode,
103132718Skan			       rtx);
104132718Skanstatic void arm_reorg (void);
105132718Skanstatic bool note_invalid_constants (rtx, HOST_WIDE_INT, int);
106132718Skanstatic int current_file_function_operand (rtx);
107132718Skanstatic unsigned long arm_compute_save_reg0_reg12_mask (void);
108132718Skanstatic unsigned long arm_compute_save_reg_mask (void);
109132718Skanstatic unsigned long arm_isr_value (tree);
110132718Skanstatic unsigned long arm_compute_func_type (void);
111132718Skanstatic tree arm_handle_fndecl_attribute (tree *, tree, tree, int, bool *);
112132718Skanstatic tree arm_handle_isr_attribute (tree *, tree, tree, int, bool *);
113132718Skanstatic void arm_output_function_epilogue (FILE *, HOST_WIDE_INT);
114132718Skanstatic void arm_output_function_prologue (FILE *, HOST_WIDE_INT);
115132718Skanstatic void thumb_output_function_prologue (FILE *, HOST_WIDE_INT);
116132718Skanstatic int arm_comp_type_attributes (tree, tree);
117132718Skanstatic void arm_set_default_type_attributes (tree);
118132718Skanstatic int arm_adjust_cost (rtx, rtx, rtx, int);
119132718Skanstatic int arm_use_dfa_pipeline_interface (void);
120132718Skanstatic int count_insns_for_constant (HOST_WIDE_INT, int);
121132718Skanstatic int arm_get_strip_length (int);
122132718Skanstatic bool arm_function_ok_for_sibcall (tree, tree);
123132718Skanstatic void arm_internal_label (FILE *, const char *, unsigned long);
124132718Skanstatic void arm_output_mi_thunk (FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT,
125132718Skan				 tree);
126132718Skanstatic int arm_rtx_costs_1 (rtx, enum rtx_code, enum rtx_code);
127132718Skanstatic bool arm_rtx_costs (rtx, int, int, int *);
128132718Skanstatic int arm_address_cost (rtx);
129132718Skanstatic bool arm_memory_load_p (rtx);
130132718Skanstatic bool arm_cirrus_insn_p (rtx);
131132718Skanstatic void cirrus_reorg (rtx);
132132718Skanstatic void arm_init_builtins (void);
133132718Skanstatic rtx arm_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
134132718Skanstatic void arm_init_iwmmxt_builtins (void);
135132718Skanstatic rtx safe_vector_operand (rtx, enum machine_mode);
136132718Skanstatic rtx arm_expand_binop_builtin (enum insn_code, tree, rtx);
137132718Skanstatic rtx arm_expand_unop_builtin (enum insn_code, tree, rtx, int);
138132718Skanstatic rtx arm_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
139132718Skan
14090075Sobrien#ifdef OBJECT_FORMAT_ELF
141132718Skanstatic void arm_elf_asm_named_section (const char *, unsigned int);
14290075Sobrien#endif
143117395Skan#ifndef ARM_PE
144132718Skanstatic void arm_encode_section_info (tree, rtx, int);
145117395Skan#endif
146117395Skan#ifdef AOF_ASSEMBLER
147132718Skanstatic void aof_globalize_label (FILE *, const char *);
148132718Skanstatic void aof_dump_imports (FILE *);
149132718Skanstatic void aof_dump_pic_table (FILE *);
150132718Skanstatic void aof_file_start (void);
151132718Skanstatic void aof_file_end (void);
152117395Skan#endif
15390075Sobrien
15490075Sobrien
15590075Sobrien/* Initialize the GCC target structure.  */
15690075Sobrien#ifdef TARGET_DLLIMPORT_DECL_ATTRIBUTES
15790075Sobrien#undef  TARGET_MERGE_DECL_ATTRIBUTES
15890075Sobrien#define TARGET_MERGE_DECL_ATTRIBUTES merge_dllimport_decl_attributes
15990075Sobrien#endif
16090075Sobrien
16190075Sobrien#undef  TARGET_ATTRIBUTE_TABLE
16290075Sobrien#define TARGET_ATTRIBUTE_TABLE arm_attribute_table
16390075Sobrien
16490075Sobrien#ifdef AOF_ASSEMBLER
16590075Sobrien#undef  TARGET_ASM_BYTE_OP
16690075Sobrien#define TARGET_ASM_BYTE_OP "\tDCB\t"
16790075Sobrien#undef  TARGET_ASM_ALIGNED_HI_OP
16890075Sobrien#define TARGET_ASM_ALIGNED_HI_OP "\tDCW\t"
16990075Sobrien#undef  TARGET_ASM_ALIGNED_SI_OP
17090075Sobrien#define TARGET_ASM_ALIGNED_SI_OP "\tDCD\t"
171117395Skan#undef TARGET_ASM_GLOBALIZE_LABEL
172117395Skan#define TARGET_ASM_GLOBALIZE_LABEL aof_globalize_label
173132718Skan#undef TARGET_ASM_FILE_START
174132718Skan#define TARGET_ASM_FILE_START aof_file_start
175132718Skan#undef TARGET_ASM_FILE_END
176132718Skan#define TARGET_ASM_FILE_END aof_file_end
17790075Sobrien#else
17890075Sobrien#undef  TARGET_ASM_ALIGNED_SI_OP
17990075Sobrien#define TARGET_ASM_ALIGNED_SI_OP NULL
18090075Sobrien#undef  TARGET_ASM_INTEGER
18190075Sobrien#define TARGET_ASM_INTEGER arm_assemble_integer
18290075Sobrien#endif
18390075Sobrien
18490075Sobrien#undef  TARGET_ASM_FUNCTION_PROLOGUE
18590075Sobrien#define TARGET_ASM_FUNCTION_PROLOGUE arm_output_function_prologue
18690075Sobrien
18790075Sobrien#undef  TARGET_ASM_FUNCTION_EPILOGUE
18890075Sobrien#define TARGET_ASM_FUNCTION_EPILOGUE arm_output_function_epilogue
18990075Sobrien
19090075Sobrien#undef  TARGET_COMP_TYPE_ATTRIBUTES
19190075Sobrien#define TARGET_COMP_TYPE_ATTRIBUTES arm_comp_type_attributes
19290075Sobrien
19390075Sobrien#undef  TARGET_SET_DEFAULT_TYPE_ATTRIBUTES
19490075Sobrien#define TARGET_SET_DEFAULT_TYPE_ATTRIBUTES arm_set_default_type_attributes
19590075Sobrien
19690075Sobrien#undef  TARGET_SCHED_ADJUST_COST
19790075Sobrien#define TARGET_SCHED_ADJUST_COST arm_adjust_cost
19890075Sobrien
199132718Skan#undef  TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE
200132718Skan#define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE arm_use_dfa_pipeline_interface
201132718Skan
202117395Skan#undef TARGET_ENCODE_SECTION_INFO
203117395Skan#ifdef ARM_PE
204117395Skan#define TARGET_ENCODE_SECTION_INFO  arm_pe_encode_section_info
205117395Skan#else
206117395Skan#define TARGET_ENCODE_SECTION_INFO  arm_encode_section_info
207117395Skan#endif
208117395Skan
209132718Skan#undef  TARGET_STRIP_NAME_ENCODING
210117395Skan#define TARGET_STRIP_NAME_ENCODING arm_strip_name_encoding
211117395Skan
212132718Skan#undef  TARGET_ASM_INTERNAL_LABEL
213132718Skan#define TARGET_ASM_INTERNAL_LABEL arm_internal_label
214132718Skan
215132718Skan#undef  TARGET_FUNCTION_OK_FOR_SIBCALL
216132718Skan#define TARGET_FUNCTION_OK_FOR_SIBCALL arm_function_ok_for_sibcall
217132718Skan
218132718Skan#undef  TARGET_ASM_OUTPUT_MI_THUNK
219117395Skan#define TARGET_ASM_OUTPUT_MI_THUNK arm_output_mi_thunk
220132718Skan#undef  TARGET_ASM_CAN_OUTPUT_MI_THUNK
221117395Skan#define TARGET_ASM_CAN_OUTPUT_MI_THUNK default_can_output_mi_thunk_no_vcall
222117395Skan
223132718Skan#undef  TARGET_RTX_COSTS
224132718Skan#define TARGET_RTX_COSTS arm_rtx_costs
225132718Skan#undef  TARGET_ADDRESS_COST
226132718Skan#define TARGET_ADDRESS_COST arm_address_cost
227132718Skan
228132718Skan#undef  TARGET_MACHINE_DEPENDENT_REORG
229132718Skan#define TARGET_MACHINE_DEPENDENT_REORG arm_reorg
230132718Skan
231132718Skan#undef  TARGET_INIT_BUILTINS
232132718Skan#define TARGET_INIT_BUILTINS  arm_init_builtins
233132718Skan#undef  TARGET_EXPAND_BUILTIN
234132718Skan#define TARGET_EXPAND_BUILTIN arm_expand_builtin
235132718Skan
23690075Sobrienstruct gcc_target targetm = TARGET_INITIALIZER;
23790075Sobrien
23890075Sobrien/* Obstack for minipool constant handling.  */
23990075Sobrienstatic struct obstack minipool_obstack;
24090075Sobrienstatic char *         minipool_startobj;
24190075Sobrien
24290075Sobrien/* The maximum number of insns skipped which
24390075Sobrien   will be conditionalised if possible.  */
24490075Sobrienstatic int max_insns_skipped = 5;
24590075Sobrien
24690075Sobrienextern FILE * asm_out_file;
24790075Sobrien
24890075Sobrien/* True if we are currently building a constant table.  */
24990075Sobrienint making_const_table;
25090075Sobrien
25190075Sobrien/* Define the information needed to generate branch insns.  This is
25290075Sobrien   stored from the compare operation.  */
25390075Sobrienrtx arm_compare_op0, arm_compare_op1;
25490075Sobrien
25590075Sobrien/* What type of floating point are we tuning for?  */
256132718Skanenum fputype arm_fpu_tune;
25790075Sobrien
25890075Sobrien/* What type of floating point instructions are available?  */
259132718Skanenum fputype arm_fpu_arch;
26090075Sobrien
26190075Sobrien/* What program mode is the cpu running in? 26-bit mode or 32-bit mode.  */
26290075Sobrienenum prog_mode_type arm_prgmode;
26390075Sobrien
26490075Sobrien/* Set by the -mfp=... option.  */
26590075Sobrienconst char * target_fp_name = NULL;
26690075Sobrien
26790075Sobrien/* Used to parse -mstructure_size_boundary command line option.  */
26890075Sobrienconst char * structure_size_string = NULL;
26990075Sobrienint    arm_structure_size_boundary = DEFAULT_STRUCTURE_SIZE_BOUNDARY;
27090075Sobrien
27190075Sobrien/* Bit values used to identify processor capabilities.  */
27290075Sobrien#define FL_CO_PROC    (1 << 0)        /* Has external co-processor bus */
27390075Sobrien#define FL_FAST_MULT  (1 << 1)        /* Fast multiply */
27490075Sobrien#define FL_MODE26     (1 << 2)        /* 26-bit mode support */
27590075Sobrien#define FL_MODE32     (1 << 3)        /* 32-bit mode support */
27690075Sobrien#define FL_ARCH4      (1 << 4)        /* Architecture rel 4 */
27790075Sobrien#define FL_ARCH5      (1 << 5)        /* Architecture rel 5 */
27890075Sobrien#define FL_THUMB      (1 << 6)        /* Thumb aware */
27990075Sobrien#define FL_LDSCHED    (1 << 7)	      /* Load scheduling necessary */
28090075Sobrien#define FL_STRONG     (1 << 8)	      /* StrongARM */
281132718Skan#define FL_ARCH5E     (1 << 9)        /* DSP extensions to v5 */
28290075Sobrien#define FL_XSCALE     (1 << 10)	      /* XScale */
283132718Skan#define FL_CIRRUS     (1 << 11)	      /* Cirrus/DSP.  */
284132718Skan#define FL_IWMMXT     (1 << 29)	      /* XScale v2 or "Intel Wireless MMX technology".  */
285132718Skan#define FL_ARCH6J     (1 << 12)       /* Architecture rel 6.  Adds
286132718Skan					 media instructions.  */
287132718Skan#define FL_VFPV2      (1 << 13)       /* Vector Floating Point V2.  */
28890075Sobrien
28990075Sobrien/* The bits in this mask specify which
29090075Sobrien   instructions we are allowed to generate.  */
291117395Skanstatic unsigned long insn_flags = 0;
29290075Sobrien
29390075Sobrien/* The bits in this mask specify which instruction scheduling options should
29490075Sobrien   be used.  Note - there is an overlap with the FL_FAST_MULT.  For some
29590075Sobrien   hardware we want to be able to generate the multiply instructions, but to
29690075Sobrien   tune as if they were not present in the architecture.  */
297117395Skanstatic unsigned long tune_flags = 0;
29890075Sobrien
29990075Sobrien/* The following are used in the arm.md file as equivalents to bits
30090075Sobrien   in the above two flag variables.  */
30190075Sobrien
30290075Sobrien/* Nonzero if this is an "M" variant of the processor.  */
30390075Sobrienint arm_fast_multiply = 0;
30490075Sobrien
30590075Sobrien/* Nonzero if this chip supports the ARM Architecture 4 extensions.  */
30690075Sobrienint arm_arch4 = 0;
30790075Sobrien
30890075Sobrien/* Nonzero if this chip supports the ARM Architecture 5 extensions.  */
30990075Sobrienint arm_arch5 = 0;
31090075Sobrien
31190075Sobrien/* Nonzero if this chip supports the ARM Architecture 5E extensions.  */
31290075Sobrienint arm_arch5e = 0;
31390075Sobrien
31490075Sobrien/* Nonzero if this chip can benefit from load scheduling.  */
31590075Sobrienint arm_ld_sched = 0;
31690075Sobrien
31790075Sobrien/* Nonzero if this chip is a StrongARM.  */
31890075Sobrienint arm_is_strong = 0;
31990075Sobrien
320132718Skan/* Nonzero if this chip supports Intel Wireless MMX technology.  */
321132718Skanint arm_arch_iwmmxt = 0;
322132718Skan
32390075Sobrien/* Nonzero if this chip is an XScale.  */
324132718Skanint arm_arch_xscale = 0;
32590075Sobrien
326132718Skan/* Nonzero if tuning for XScale  */
327132718Skanint arm_tune_xscale = 0;
328132718Skan
32990075Sobrien/* Nonzero if this chip is an ARM6 or an ARM7.  */
33090075Sobrienint arm_is_6_or_7 = 0;
33190075Sobrien
332132718Skan/* Nonzero if this chip is a Cirrus/DSP.  */
333132718Skanint arm_is_cirrus = 0;
334132718Skan
33590075Sobrien/* Nonzero if generating Thumb instructions.  */
33690075Sobrienint thumb_code = 0;
33790075Sobrien
33890075Sobrien/* In case of a PRE_INC, POST_INC, PRE_DEC, POST_DEC memory reference, we
33990075Sobrien   must report the mode of the memory reference from PRINT_OPERAND to
34090075Sobrien   PRINT_OPERAND_ADDRESS.  */
34190075Sobrienenum machine_mode output_memory_reference_mode;
34290075Sobrien
34390075Sobrien/* The register number to be used for the PIC offset register.  */
34490075Sobrienconst char * arm_pic_register_string = NULL;
34596263Sobrienint arm_pic_register = INVALID_REGNUM;
34690075Sobrien
34790075Sobrien/* Set to 1 when a return insn is output, this means that the epilogue
34890075Sobrien   is not needed.  */
34990075Sobrienint return_used_this_function;
35090075Sobrien
35190075Sobrien/* Set to 1 after arm_reorg has started.  Reset to start at the start of
35290075Sobrien   the next function.  */
35390075Sobrienstatic int after_arm_reorg = 0;
35490075Sobrien
35590075Sobrien/* The maximum number of insns to be used when loading a constant.  */
35690075Sobrienstatic int arm_constant_limit = 3;
35790075Sobrien
35890075Sobrien/* For an explanation of these variables, see final_prescan_insn below.  */
35990075Sobrienint arm_ccfsm_state;
36090075Sobrienenum arm_cond_code arm_current_cc;
36190075Sobrienrtx arm_target_insn;
36290075Sobrienint arm_target_label;
36390075Sobrien
36490075Sobrien/* The condition codes of the ARM, and the inverse function.  */
36590075Sobrienstatic const char * const arm_condition_codes[] =
36690075Sobrien{
36790075Sobrien  "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
36890075Sobrien  "hi", "ls", "ge", "lt", "gt", "le", "al", "nv"
36990075Sobrien};
37090075Sobrien
37190075Sobrien#define streq(string1, string2) (strcmp (string1, string2) == 0)
37290075Sobrien
37390075Sobrien/* Initialization code.  */
37490075Sobrien
37590075Sobrienstruct processors
37690075Sobrien{
37790075Sobrien  const char *const name;
378117395Skan  const unsigned long flags;
37990075Sobrien};
38090075Sobrien
38190075Sobrien/* Not all of these give usefully different compilation alternatives,
38290075Sobrien   but there is no simple way of generalizing them.  */
38390075Sobrienstatic const struct processors all_cores[] =
38490075Sobrien{
38590075Sobrien  /* ARM Cores */
38690075Sobrien
38790075Sobrien  {"arm2",	FL_CO_PROC | FL_MODE26 },
38890075Sobrien  {"arm250",	FL_CO_PROC | FL_MODE26 },
38990075Sobrien  {"arm3",	FL_CO_PROC | FL_MODE26 },
39090075Sobrien  {"arm6",	FL_CO_PROC | FL_MODE26 | FL_MODE32 },
39190075Sobrien  {"arm60",	FL_CO_PROC | FL_MODE26 | FL_MODE32 },
39290075Sobrien  {"arm600",	FL_CO_PROC | FL_MODE26 | FL_MODE32 },
39390075Sobrien  {"arm610",	             FL_MODE26 | FL_MODE32 },
39490075Sobrien  {"arm620",	FL_CO_PROC | FL_MODE26 | FL_MODE32 },
39590075Sobrien  {"arm7",	FL_CO_PROC | FL_MODE26 | FL_MODE32 },
39690075Sobrien  /* arm7m doesn't exist on its own, but only with D, (and I), but
39790075Sobrien     those don't alter the code, so arm7m is sometimes used.  */
39890075Sobrien  {"arm7m",	FL_CO_PROC | FL_MODE26 | FL_MODE32 | FL_FAST_MULT },
39990075Sobrien  {"arm7d",	FL_CO_PROC | FL_MODE26 | FL_MODE32 },
40090075Sobrien  {"arm7dm",	FL_CO_PROC | FL_MODE26 | FL_MODE32 | FL_FAST_MULT },
40190075Sobrien  {"arm7di",	FL_CO_PROC | FL_MODE26 | FL_MODE32 },
40290075Sobrien  {"arm7dmi",	FL_CO_PROC | FL_MODE26 | FL_MODE32 | FL_FAST_MULT },
40390075Sobrien  {"arm70",	FL_CO_PROC | FL_MODE26 | FL_MODE32 },
40490075Sobrien  {"arm700",	FL_CO_PROC | FL_MODE26 | FL_MODE32 },
40590075Sobrien  {"arm700i",	FL_CO_PROC | FL_MODE26 | FL_MODE32 },
40690075Sobrien  {"arm710",	             FL_MODE26 | FL_MODE32 },
40790075Sobrien  {"arm720",	             FL_MODE26 | FL_MODE32 },
40890075Sobrien  {"arm710c",	             FL_MODE26 | FL_MODE32 },
40990075Sobrien  {"arm7100",	             FL_MODE26 | FL_MODE32 },
41090075Sobrien  {"arm7500",	             FL_MODE26 | FL_MODE32 },
411132718Skan  /* Doesn't have an external co-proc, but does have embedded fpa.  */
41290075Sobrien  {"arm7500fe",	FL_CO_PROC | FL_MODE26 | FL_MODE32 },
413132718Skan  /* V4 Architecture Processors */
41490075Sobrien  {"arm7tdmi",	FL_CO_PROC |             FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB },
415132718Skan  {"arm710t",	                         FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB },
416132718Skan  {"arm720t",	                         FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB },
417132718Skan  {"arm740t",	                         FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB },
41890075Sobrien  {"arm8",	             FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 |            FL_LDSCHED },
41990075Sobrien  {"arm810",	             FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 |            FL_LDSCHED },
42090075Sobrien  {"arm9",	                         FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED },
42190075Sobrien  {"arm920",	                         FL_MODE32 | FL_FAST_MULT | FL_ARCH4 |            FL_LDSCHED },
42290075Sobrien  {"arm920t",	                         FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED },
42390075Sobrien  {"arm940t",	                         FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED },
42490075Sobrien  {"arm9tdmi",	                         FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED },
42590075Sobrien  {"arm9e",	       	      		 FL_MODE32 | FL_FAST_MULT | FL_ARCH4 |            FL_LDSCHED },
426132718Skan  {"ep9312",	   			 FL_MODE32 | FL_FAST_MULT | FL_ARCH4 |            FL_LDSCHED |             FL_CIRRUS },
42790075Sobrien  {"strongarm",	             FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 |            FL_LDSCHED | FL_STRONG },
42890075Sobrien  {"strongarm110",           FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 |            FL_LDSCHED | FL_STRONG },
42990075Sobrien  {"strongarm1100",          FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 |            FL_LDSCHED | FL_STRONG },
43090075Sobrien  {"strongarm1110",          FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 |            FL_LDSCHED | FL_STRONG },
431132718Skan  /* V5 Architecture Processors */
43290075Sobrien  {"arm10tdmi",	                         FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED             | FL_ARCH5 },
43390075Sobrien  {"arm1020t",	                         FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED             | FL_ARCH5 },
434132718Skan  {"arm926ejs",                          FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB                          | FL_ARCH5 | FL_ARCH5E },
435132718Skan  {"arm1026ejs",                         FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB                          | FL_ARCH5 | FL_ARCH5E },
43690075Sobrien  {"xscale",                             FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED | FL_STRONG | FL_ARCH5 | FL_ARCH5E | FL_XSCALE },
437132718Skan  {"iwmmxt",                             FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED | FL_STRONG | FL_ARCH5 | FL_ARCH5E | FL_XSCALE | FL_IWMMXT },
438132718Skan  /* V6 Architecture Processors */
439132718Skan  {"arm1136js",                          FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB                          | FL_ARCH5 | FL_ARCH5E | FL_ARCH6J },
440132718Skan  {"arm1136jfs",                         FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB                          | FL_ARCH5 | FL_ARCH5E | FL_ARCH6J | FL_VFPV2 },
44190075Sobrien  {NULL, 0}
44290075Sobrien};
44390075Sobrien
44490075Sobrienstatic const struct processors all_architectures[] =
44590075Sobrien{
44690075Sobrien  /* ARM Architectures */
44790075Sobrien
44890075Sobrien  { "armv2",     FL_CO_PROC | FL_MODE26 },
44990075Sobrien  { "armv2a",    FL_CO_PROC | FL_MODE26 },
45090075Sobrien  { "armv3",     FL_CO_PROC | FL_MODE26 | FL_MODE32 },
45190075Sobrien  { "armv3m",    FL_CO_PROC | FL_MODE26 | FL_MODE32 | FL_FAST_MULT },
45290075Sobrien  { "armv4",     FL_CO_PROC | FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 },
45390075Sobrien  /* Strictly, FL_MODE26 is a permitted option for v4t, but there are no
45490075Sobrien     implementations that support it, so we will leave it out for now.  */
45590075Sobrien  { "armv4t",    FL_CO_PROC |             FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB },
45690075Sobrien  { "armv5",     FL_CO_PROC |             FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_ARCH5 },
45790075Sobrien  { "armv5t",    FL_CO_PROC |             FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_ARCH5 },
45890075Sobrien  { "armv5te",   FL_CO_PROC |             FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_ARCH5 | FL_ARCH5E },
459132718Skan  { "armv6j",    FL_CO_PROC |             FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_ARCH5 | FL_ARCH5E | FL_ARCH6J },
460132718Skan  { "ep9312",				  FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED | FL_CIRRUS },
461132718Skan  {"iwmmxt",                             FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED | FL_STRONG | FL_ARCH5 | FL_ARCH5E | FL_XSCALE | FL_IWMMXT },
46290075Sobrien  { NULL, 0 }
46390075Sobrien};
46490075Sobrien
465132718Skan/* This is a magic structure.  The 'string' field is magically filled in
46690075Sobrien   with a pointer to the value specified by the user on the command line
46790075Sobrien   assuming that the user has specified such a value.  */
46890075Sobrien
46990075Sobrienstruct arm_cpu_select arm_select[] =
47090075Sobrien{
47190075Sobrien  /* string	  name            processors  */
47290075Sobrien  { NULL,	"-mcpu=",	all_cores  },
47390075Sobrien  { NULL,	"-march=",	all_architectures },
47490075Sobrien  { NULL,	"-mtune=",	all_cores }
47590075Sobrien};
47690075Sobrien
477117395Skan/* Return the number of bits set in VALUE.  */
478117395Skanstatic unsigned
479132718Skanbit_count (unsigned long value)
48090075Sobrien{
48190075Sobrien  unsigned long count = 0;
48290075Sobrien
48390075Sobrien  while (value)
48490075Sobrien    {
485117395Skan      count++;
486117395Skan      value &= value - 1;  /* Clear the least-significant set bit.  */
48790075Sobrien    }
48890075Sobrien
48990075Sobrien  return count;
49090075Sobrien}
49190075Sobrien
49290075Sobrien/* Fix up any incompatible options that the user has specified.
49390075Sobrien   This has now turned into a maze.  */
49490075Sobrienvoid
495132718Skanarm_override_options (void)
49690075Sobrien{
49790075Sobrien  unsigned i;
49890075Sobrien
49990075Sobrien  /* Set up the flags based on the cpu/architecture selected by the user.  */
50090075Sobrien  for (i = ARRAY_SIZE (arm_select); i--;)
50190075Sobrien    {
50290075Sobrien      struct arm_cpu_select * ptr = arm_select + i;
50390075Sobrien
50490075Sobrien      if (ptr->string != NULL && ptr->string[0] != '\0')
50590075Sobrien        {
50690075Sobrien	  const struct processors * sel;
50790075Sobrien
50890075Sobrien          for (sel = ptr->processors; sel->name != NULL; sel++)
50990075Sobrien            if (streq (ptr->string, sel->name))
51090075Sobrien              {
51190075Sobrien		if (i == 2)
51290075Sobrien		  tune_flags = sel->flags;
51390075Sobrien		else
51490075Sobrien		  {
51590075Sobrien		    /* If we have been given an architecture and a processor
51690075Sobrien		       make sure that they are compatible.  We only generate
51790075Sobrien		       a warning though, and we prefer the CPU over the
51890075Sobrien		       architecture.  */
51990075Sobrien		    if (insn_flags != 0 && (insn_flags ^ sel->flags))
52090075Sobrien		      warning ("switch -mcpu=%s conflicts with -march= switch",
52190075Sobrien			       ptr->string);
52290075Sobrien
52390075Sobrien		    insn_flags = sel->flags;
52490075Sobrien		  }
52590075Sobrien
52690075Sobrien                break;
52790075Sobrien              }
52890075Sobrien
52990075Sobrien          if (sel->name == NULL)
53090075Sobrien            error ("bad value (%s) for %s switch", ptr->string, ptr->name);
53190075Sobrien        }
53290075Sobrien    }
53390075Sobrien
53490075Sobrien  /* If the user did not specify a processor, choose one for them.  */
53590075Sobrien  if (insn_flags == 0)
53690075Sobrien    {
53790075Sobrien      const struct processors * sel;
53890075Sobrien      unsigned int        sought;
53990075Sobrien      static const struct cpu_default
54090075Sobrien      {
54190075Sobrien	const int cpu;
54290075Sobrien	const char *const name;
54390075Sobrien      }
54490075Sobrien      cpu_defaults[] =
54590075Sobrien      {
54690075Sobrien	{ TARGET_CPU_arm2,      "arm2" },
54790075Sobrien	{ TARGET_CPU_arm6,      "arm6" },
54890075Sobrien	{ TARGET_CPU_arm610,    "arm610" },
54990075Sobrien	{ TARGET_CPU_arm710,	"arm710" },
55090075Sobrien	{ TARGET_CPU_arm7m,     "arm7m" },
55190075Sobrien	{ TARGET_CPU_arm7500fe, "arm7500fe" },
55290075Sobrien	{ TARGET_CPU_arm7tdmi,  "arm7tdmi" },
55390075Sobrien	{ TARGET_CPU_arm8,      "arm8" },
55490075Sobrien	{ TARGET_CPU_arm810,    "arm810" },
55590075Sobrien	{ TARGET_CPU_arm9,      "arm9" },
55690075Sobrien	{ TARGET_CPU_strongarm, "strongarm" },
55790075Sobrien	{ TARGET_CPU_xscale,    "xscale" },
558132718Skan	{ TARGET_CPU_ep9312,    "ep9312" },
559132718Skan	{ TARGET_CPU_iwmmxt,    "iwmmxt" },
560132718Skan	{ TARGET_CPU_arm926ej_s, "arm926ej-s" },
561132718Skan	{ TARGET_CPU_arm1026ej_s, "arm1026ej-s" },
562132718Skan	{ TARGET_CPU_arm1136j_s, "arm1136j_s" },
563132718Skan	{ TARGET_CPU_arm1136jf_s, "arm1136jf_s" },
56490075Sobrien	{ TARGET_CPU_generic,   "arm" },
56590075Sobrien	{ 0, 0 }
56690075Sobrien      };
56790075Sobrien      const struct cpu_default * def;
56890075Sobrien
56990075Sobrien      /* Find the default.  */
57090075Sobrien      for (def = cpu_defaults; def->name; def++)
57190075Sobrien	if (def->cpu == TARGET_CPU_DEFAULT)
57290075Sobrien	  break;
57390075Sobrien
57490075Sobrien      /* Make sure we found the default CPU.  */
57590075Sobrien      if (def->name == NULL)
57690075Sobrien	abort ();
57790075Sobrien
57890075Sobrien      /* Find the default CPU's flags.  */
57990075Sobrien      for (sel = all_cores; sel->name != NULL; sel++)
58090075Sobrien	if (streq (def->name, sel->name))
58190075Sobrien	  break;
58290075Sobrien
58390075Sobrien      if (sel->name == NULL)
58490075Sobrien	abort ();
58590075Sobrien
58690075Sobrien      insn_flags = sel->flags;
58790075Sobrien
58890075Sobrien      /* Now check to see if the user has specified some command line
58990075Sobrien	 switch that require certain abilities from the cpu.  */
59090075Sobrien      sought = 0;
59190075Sobrien
59290075Sobrien      if (TARGET_INTERWORK || TARGET_THUMB)
59390075Sobrien	{
59490075Sobrien	  sought |= (FL_THUMB | FL_MODE32);
59590075Sobrien
59690075Sobrien	  /* Force apcs-32 to be used for interworking.  */
59790075Sobrien	  target_flags |= ARM_FLAG_APCS_32;
59890075Sobrien
59990075Sobrien	  /* There are no ARM processors that support both APCS-26 and
60090075Sobrien	     interworking.  Therefore we force FL_MODE26 to be removed
60190075Sobrien	     from insn_flags here (if it was set), so that the search
60290075Sobrien	     below will always be able to find a compatible processor.  */
60390075Sobrien	  insn_flags &= ~FL_MODE26;
60490075Sobrien	}
60590075Sobrien      else if (!TARGET_APCS_32)
60690075Sobrien	sought |= FL_MODE26;
60790075Sobrien
60890075Sobrien      if (sought != 0 && ((sought & insn_flags) != sought))
60990075Sobrien	{
61090075Sobrien	  /* Try to locate a CPU type that supports all of the abilities
61190075Sobrien	     of the default CPU, plus the extra abilities requested by
61290075Sobrien	     the user.  */
61390075Sobrien	  for (sel = all_cores; sel->name != NULL; sel++)
61490075Sobrien	    if ((sel->flags & sought) == (sought | insn_flags))
61590075Sobrien	      break;
61690075Sobrien
61790075Sobrien	  if (sel->name == NULL)
61890075Sobrien	    {
619117395Skan	      unsigned current_bit_count = 0;
62090075Sobrien	      const struct processors * best_fit = NULL;
62190075Sobrien
62290075Sobrien	      /* Ideally we would like to issue an error message here
62390075Sobrien		 saying that it was not possible to find a CPU compatible
62490075Sobrien		 with the default CPU, but which also supports the command
62590075Sobrien		 line options specified by the programmer, and so they
62690075Sobrien		 ought to use the -mcpu=<name> command line option to
62790075Sobrien		 override the default CPU type.
62890075Sobrien
62990075Sobrien		 Unfortunately this does not work with multilibing.  We
63090075Sobrien		 need to be able to support multilibs for -mapcs-26 and for
63190075Sobrien		 -mthumb-interwork and there is no CPU that can support both
63290075Sobrien		 options.  Instead if we cannot find a cpu that has both the
63390075Sobrien		 characteristics of the default cpu and the given command line
63490075Sobrien		 options we scan the array again looking for a best match.  */
63590075Sobrien	      for (sel = all_cores; sel->name != NULL; sel++)
63690075Sobrien		if ((sel->flags & sought) == sought)
63790075Sobrien		  {
638117395Skan		    unsigned count;
63990075Sobrien
64090075Sobrien		    count = bit_count (sel->flags & insn_flags);
64190075Sobrien
64290075Sobrien		    if (count >= current_bit_count)
64390075Sobrien		      {
64490075Sobrien			best_fit = sel;
64590075Sobrien			current_bit_count = count;
64690075Sobrien		      }
64790075Sobrien		  }
64890075Sobrien
64990075Sobrien	      if (best_fit == NULL)
65090075Sobrien		abort ();
65190075Sobrien	      else
65290075Sobrien		sel = best_fit;
65390075Sobrien	    }
65490075Sobrien
65590075Sobrien	  insn_flags = sel->flags;
65690075Sobrien	}
65790075Sobrien    }
65890075Sobrien
65990075Sobrien  /* If tuning has not been specified, tune for whichever processor or
66090075Sobrien     architecture has been selected.  */
66190075Sobrien  if (tune_flags == 0)
66290075Sobrien    tune_flags = insn_flags;
663117395Skan
66490075Sobrien  /* Make sure that the processor choice does not conflict with any of the
66590075Sobrien     other command line choices.  */
66690075Sobrien  if (TARGET_APCS_32 && !(insn_flags & FL_MODE32))
66790075Sobrien    {
66890075Sobrien      /* If APCS-32 was not the default then it must have been set by the
66990075Sobrien	 user, so issue a warning message.  If the user has specified
67090075Sobrien	 "-mapcs-32 -mcpu=arm2" then we loose here.  */
67190075Sobrien      if ((TARGET_DEFAULT & ARM_FLAG_APCS_32) == 0)
67290075Sobrien	warning ("target CPU does not support APCS-32" );
67390075Sobrien      target_flags &= ~ARM_FLAG_APCS_32;
67490075Sobrien    }
67590075Sobrien  else if (!TARGET_APCS_32 && !(insn_flags & FL_MODE26))
67690075Sobrien    {
67790075Sobrien      warning ("target CPU does not support APCS-26" );
67890075Sobrien      target_flags |= ARM_FLAG_APCS_32;
67990075Sobrien    }
68090075Sobrien
68190075Sobrien  if (TARGET_INTERWORK && !(insn_flags & FL_THUMB))
68290075Sobrien    {
68390075Sobrien      warning ("target CPU does not support interworking" );
68490075Sobrien      target_flags &= ~ARM_FLAG_INTERWORK;
68590075Sobrien    }
68690075Sobrien
68790075Sobrien  if (TARGET_THUMB && !(insn_flags & FL_THUMB))
68890075Sobrien    {
68990075Sobrien      warning ("target CPU does not support THUMB instructions");
69090075Sobrien      target_flags &= ~ARM_FLAG_THUMB;
69190075Sobrien    }
69290075Sobrien
693132718Skan  if (!TARGET_APCS_32)
694132718Skan    inform ("future releases of GCC will not support -mapcs-26");
695132718Skan
69690075Sobrien  if (TARGET_APCS_FRAME && TARGET_THUMB)
69790075Sobrien    {
69890075Sobrien      /* warning ("ignoring -mapcs-frame because -mthumb was used"); */
69990075Sobrien      target_flags &= ~ARM_FLAG_APCS_FRAME;
70090075Sobrien    }
70190075Sobrien
70290075Sobrien  /* TARGET_BACKTRACE calls leaf_function_p, which causes a crash if done
70390075Sobrien     from here where no function is being compiled currently.  */
70490075Sobrien  if ((target_flags & (THUMB_FLAG_LEAF_BACKTRACE | THUMB_FLAG_BACKTRACE))
70590075Sobrien      && TARGET_ARM)
70690075Sobrien    warning ("enabling backtrace support is only meaningful when compiling for the Thumb");
70790075Sobrien
70890075Sobrien  if (TARGET_ARM && TARGET_CALLEE_INTERWORKING)
70990075Sobrien    warning ("enabling callee interworking support is only meaningful when compiling for the Thumb");
71090075Sobrien
71190075Sobrien  if (TARGET_ARM && TARGET_CALLER_INTERWORKING)
71290075Sobrien    warning ("enabling caller interworking support is only meaningful when compiling for the Thumb");
71390075Sobrien
71490075Sobrien  /* If interworking is enabled then APCS-32 must be selected as well.  */
71590075Sobrien  if (TARGET_INTERWORK)
71690075Sobrien    {
71790075Sobrien      if (!TARGET_APCS_32)
71890075Sobrien	warning ("interworking forces APCS-32 to be used" );
71990075Sobrien      target_flags |= ARM_FLAG_APCS_32;
72090075Sobrien    }
72190075Sobrien
72290075Sobrien  if (TARGET_APCS_STACK && !TARGET_APCS_FRAME)
72390075Sobrien    {
72490075Sobrien      warning ("-mapcs-stack-check incompatible with -mno-apcs-frame");
72590075Sobrien      target_flags |= ARM_FLAG_APCS_FRAME;
72690075Sobrien    }
72790075Sobrien
72890075Sobrien  if (TARGET_POKE_FUNCTION_NAME)
72990075Sobrien    target_flags |= ARM_FLAG_APCS_FRAME;
73090075Sobrien
73190075Sobrien  if (TARGET_APCS_REENT && flag_pic)
73290075Sobrien    error ("-fpic and -mapcs-reent are incompatible");
73390075Sobrien
73490075Sobrien  if (TARGET_APCS_REENT)
73590075Sobrien    warning ("APCS reentrant code not supported.  Ignored");
73690075Sobrien
73790075Sobrien  /* If this target is normally configured to use APCS frames, warn if they
73890075Sobrien     are turned off and debugging is turned on.  */
73990075Sobrien  if (TARGET_ARM
74090075Sobrien      && write_symbols != NO_DEBUG
74190075Sobrien      && !TARGET_APCS_FRAME
74290075Sobrien      && (TARGET_DEFAULT & ARM_FLAG_APCS_FRAME))
74390075Sobrien    warning ("-g with -mno-apcs-frame may not give sensible debugging");
74490075Sobrien
74590075Sobrien  /* If stack checking is disabled, we can use r10 as the PIC register,
74690075Sobrien     which keeps r9 available.  */
74796263Sobrien  if (flag_pic)
74896263Sobrien    arm_pic_register = TARGET_APCS_STACK ? 9 : 10;
74990075Sobrien
75090075Sobrien  if (TARGET_APCS_FLOAT)
75190075Sobrien    warning ("passing floating point arguments in fp regs not yet supported");
75290075Sobrien
753117395Skan  /* Initialize boolean versions of the flags, for use in the arm.md file.  */
75490075Sobrien  arm_fast_multiply = (insn_flags & FL_FAST_MULT) != 0;
75590075Sobrien  arm_arch4         = (insn_flags & FL_ARCH4) != 0;
75690075Sobrien  arm_arch5         = (insn_flags & FL_ARCH5) != 0;
75790075Sobrien  arm_arch5e        = (insn_flags & FL_ARCH5E) != 0;
758132718Skan  arm_arch_xscale     = (insn_flags & FL_XSCALE) != 0;
75990075Sobrien
76090075Sobrien  arm_ld_sched      = (tune_flags & FL_LDSCHED) != 0;
76190075Sobrien  arm_is_strong     = (tune_flags & FL_STRONG) != 0;
76290075Sobrien  thumb_code	    = (TARGET_ARM == 0);
76390075Sobrien  arm_is_6_or_7     = (((tune_flags & (FL_MODE26 | FL_MODE32))
76490075Sobrien		       && !(tune_flags & FL_ARCH4))) != 0;
765132718Skan  arm_tune_xscale       = (tune_flags & FL_XSCALE) != 0;
766132718Skan  arm_is_cirrus	    = (tune_flags & FL_CIRRUS) != 0;
767132718Skan  arm_arch_iwmmxt   = (insn_flags & FL_IWMMXT) != 0;
76890075Sobrien
769132718Skan  if (TARGET_IWMMXT && (! TARGET_ATPCS))
770132718Skan    target_flags |= ARM_FLAG_ATPCS;
771132718Skan
772132718Skan  if (arm_is_cirrus)
773132718Skan    {
774132718Skan      arm_fpu_tune = FPUTYPE_MAVERICK;
775132718Skan
776132718Skan      /* Ignore -mhard-float if -mcpu=ep9312.  */
777132718Skan      if (TARGET_HARD_FLOAT)
778132718Skan	target_flags ^= ARM_FLAG_SOFT_FLOAT;
779132718Skan    }
780132718Skan  else
781132718Skan    /* Default value for floating point code... if no co-processor
782132718Skan       bus, then schedule for emulated floating point.  Otherwise,
783132718Skan       assume the user has an FPA.
784132718Skan       Note: this does not prevent use of floating point instructions,
785132718Skan       -msoft-float does that.  */
786132718Skan    arm_fpu_tune = (tune_flags & FL_CO_PROC) ? FPUTYPE_FPA : FPUTYPE_FPA_EMU3;
78790075Sobrien
78890075Sobrien  if (target_fp_name)
78990075Sobrien    {
79090075Sobrien      if (streq (target_fp_name, "2"))
791132718Skan	arm_fpu_arch = FPUTYPE_FPA_EMU2;
79290075Sobrien      else if (streq (target_fp_name, "3"))
793132718Skan	arm_fpu_arch = FPUTYPE_FPA_EMU3;
79490075Sobrien      else
79590075Sobrien	error ("invalid floating point emulation option: -mfpe-%s",
79690075Sobrien	       target_fp_name);
79790075Sobrien    }
79890075Sobrien  else
799132718Skan    arm_fpu_arch = FPUTYPE_DEFAULT;
80090075Sobrien
801132718Skan  if (TARGET_FPE)
802132718Skan    {
803132718Skan      if (arm_fpu_tune == FPUTYPE_FPA_EMU3)
804132718Skan	arm_fpu_tune = FPUTYPE_FPA_EMU2;
805132718Skan      else if (arm_fpu_tune == FPUTYPE_MAVERICK)
806132718Skan	warning ("-mfpe switch not supported by ep9312 target cpu - ignored.");
807132718Skan      else if (arm_fpu_tune != FPUTYPE_FPA)
808132718Skan	arm_fpu_tune = FPUTYPE_FPA_EMU2;
809132718Skan    }
81090075Sobrien
81190075Sobrien  /* For arm2/3 there is no need to do any scheduling if there is only
81290075Sobrien     a floating point emulator, or we are doing software floating-point.  */
813132718Skan  if ((TARGET_SOFT_FLOAT || arm_fpu_tune != FPUTYPE_FPA)
81490075Sobrien      && (tune_flags & FL_MODE32) == 0)
81590075Sobrien    flag_schedule_insns = flag_schedule_insns_after_reload = 0;
81690075Sobrien
81790075Sobrien  arm_prgmode = TARGET_APCS_32 ? PROG_MODE_PROG32 : PROG_MODE_PROG26;
81890075Sobrien
81990075Sobrien  if (structure_size_string != NULL)
82090075Sobrien    {
82190075Sobrien      int size = strtol (structure_size_string, NULL, 0);
82290075Sobrien
82390075Sobrien      if (size == 8 || size == 32)
82490075Sobrien	arm_structure_size_boundary = size;
82590075Sobrien      else
82690075Sobrien	warning ("structure size boundary can only be set to 8 or 32");
82790075Sobrien    }
82890075Sobrien
82990075Sobrien  if (arm_pic_register_string != NULL)
83090075Sobrien    {
83196263Sobrien      int pic_register = decode_reg_name (arm_pic_register_string);
832117395Skan
83390075Sobrien      if (!flag_pic)
83490075Sobrien	warning ("-mpic-register= is useless without -fpic");
83590075Sobrien
83690075Sobrien      /* Prevent the user from choosing an obviously stupid PIC register.  */
83796263Sobrien      else if (pic_register < 0 || call_used_regs[pic_register]
83896263Sobrien	       || pic_register == HARD_FRAME_POINTER_REGNUM
83996263Sobrien	       || pic_register == STACK_POINTER_REGNUM
84096263Sobrien	       || pic_register >= PC_REGNUM)
84190075Sobrien	error ("unable to use '%s' for PIC register", arm_pic_register_string);
84290075Sobrien      else
84390075Sobrien	arm_pic_register = pic_register;
84490075Sobrien    }
84590075Sobrien
84690075Sobrien  if (TARGET_THUMB && flag_schedule_insns)
84790075Sobrien    {
84890075Sobrien      /* Don't warn since it's on by default in -O2.  */
84990075Sobrien      flag_schedule_insns = 0;
85090075Sobrien    }
85190075Sobrien
85290075Sobrien  if (optimize_size)
853132718Skan    {
854132718Skan      /* There's some dispute as to whether this should be 1 or 2.  However,
855132718Skan	 experiments seem to show that in pathological cases a setting of
856132718Skan	 1 degrades less severely than a setting of 2.  This could change if
857132718Skan	 other parts of the compiler change their behavior.  */
858132718Skan      arm_constant_limit = 1;
85990075Sobrien
860132718Skan      /* If optimizing for size, bump the number of instructions that we
861132718Skan         are prepared to conditionally execute (even on a StrongARM).  */
862132718Skan      max_insns_skipped = 6;
863132718Skan    }
864132718Skan  else
865132718Skan    {
866132718Skan      /* For processors with load scheduling, it never costs more than
867132718Skan         2 cycles to load a constant, and the load scheduler may well
868132718Skan	 reduce that to 1.  */
869132718Skan      if (tune_flags & FL_LDSCHED)
870132718Skan        arm_constant_limit = 1;
871132718Skan
872132718Skan      /* On XScale the longer latency of a load makes it more difficult
873132718Skan         to achieve a good schedule, so it's faster to synthesize
874132718Skan	 constants that can be done in two insns.  */
875132718Skan      if (arm_tune_xscale)
876132718Skan        arm_constant_limit = 2;
877132718Skan
878132718Skan      /* StrongARM has early execution of branches, so a sequence
879132718Skan         that is worth skipping is shorter.  */
880132718Skan      if (arm_is_strong)
881132718Skan        max_insns_skipped = 3;
882132718Skan    }
883132718Skan
88490075Sobrien  /* Register global variables with the garbage collector.  */
88590075Sobrien  arm_add_gc_roots ();
88690075Sobrien}
88790075Sobrien
88890075Sobrienstatic void
889132718Skanarm_add_gc_roots (void)
89090075Sobrien{
89190075Sobrien  gcc_obstack_init(&minipool_obstack);
89290075Sobrien  minipool_startobj = (char *) obstack_alloc (&minipool_obstack, 0);
89390075Sobrien}
89490075Sobrien
89590075Sobrien/* A table of known ARM exception types.
89690075Sobrien   For use with the interrupt function attribute.  */
89790075Sobrien
89890075Sobrientypedef struct
89990075Sobrien{
90090075Sobrien  const char *const arg;
90190075Sobrien  const unsigned long return_value;
90290075Sobrien}
90390075Sobrienisr_attribute_arg;
90490075Sobrien
90590075Sobrienstatic const isr_attribute_arg isr_attribute_args [] =
90690075Sobrien{
90790075Sobrien  { "IRQ",   ARM_FT_ISR },
90890075Sobrien  { "irq",   ARM_FT_ISR },
90990075Sobrien  { "FIQ",   ARM_FT_FIQ },
91090075Sobrien  { "fiq",   ARM_FT_FIQ },
91190075Sobrien  { "ABORT", ARM_FT_ISR },
91290075Sobrien  { "abort", ARM_FT_ISR },
91390075Sobrien  { "ABORT", ARM_FT_ISR },
91490075Sobrien  { "abort", ARM_FT_ISR },
91590075Sobrien  { "UNDEF", ARM_FT_EXCEPTION },
91690075Sobrien  { "undef", ARM_FT_EXCEPTION },
91790075Sobrien  { "SWI",   ARM_FT_EXCEPTION },
91890075Sobrien  { "swi",   ARM_FT_EXCEPTION },
91990075Sobrien  { NULL,    ARM_FT_NORMAL }
92090075Sobrien};
92190075Sobrien
92290075Sobrien/* Returns the (interrupt) function type of the current
92390075Sobrien   function, or ARM_FT_UNKNOWN if the type cannot be determined.  */
92490075Sobrien
92590075Sobrienstatic unsigned long
926132718Skanarm_isr_value (tree argument)
92790075Sobrien{
92890075Sobrien  const isr_attribute_arg * ptr;
92990075Sobrien  const char *              arg;
93090075Sobrien
93190075Sobrien  /* No argument - default to IRQ.  */
93290075Sobrien  if (argument == NULL_TREE)
93390075Sobrien    return ARM_FT_ISR;
93490075Sobrien
93590075Sobrien  /* Get the value of the argument.  */
93690075Sobrien  if (TREE_VALUE (argument) == NULL_TREE
93790075Sobrien      || TREE_CODE (TREE_VALUE (argument)) != STRING_CST)
93890075Sobrien    return ARM_FT_UNKNOWN;
93990075Sobrien
94090075Sobrien  arg = TREE_STRING_POINTER (TREE_VALUE (argument));
94190075Sobrien
94290075Sobrien  /* Check it against the list of known arguments.  */
943132718Skan  for (ptr = isr_attribute_args; ptr->arg != NULL; ptr++)
94490075Sobrien    if (streq (arg, ptr->arg))
94590075Sobrien      return ptr->return_value;
94690075Sobrien
947117395Skan  /* An unrecognized interrupt type.  */
94890075Sobrien  return ARM_FT_UNKNOWN;
94990075Sobrien}
95090075Sobrien
95190075Sobrien/* Computes the type of the current function.  */
95290075Sobrien
95390075Sobrienstatic unsigned long
954132718Skanarm_compute_func_type (void)
95590075Sobrien{
95690075Sobrien  unsigned long type = ARM_FT_UNKNOWN;
95790075Sobrien  tree a;
95890075Sobrien  tree attr;
95990075Sobrien
96090075Sobrien  if (TREE_CODE (current_function_decl) != FUNCTION_DECL)
96190075Sobrien    abort ();
96290075Sobrien
96390075Sobrien  /* Decide if the current function is volatile.  Such functions
96490075Sobrien     never return, and many memory cycles can be saved by not storing
96590075Sobrien     register values that will never be needed again.  This optimization
96690075Sobrien     was added to speed up context switching in a kernel application.  */
96790075Sobrien  if (optimize > 0
96890075Sobrien      && current_function_nothrow
96990075Sobrien      && TREE_THIS_VOLATILE (current_function_decl))
97090075Sobrien    type |= ARM_FT_VOLATILE;
97190075Sobrien
97290075Sobrien  if (current_function_needs_context)
97390075Sobrien    type |= ARM_FT_NESTED;
97490075Sobrien
97590075Sobrien  attr = DECL_ATTRIBUTES (current_function_decl);
97690075Sobrien
97790075Sobrien  a = lookup_attribute ("naked", attr);
97890075Sobrien  if (a != NULL_TREE)
97990075Sobrien    type |= ARM_FT_NAKED;
98090075Sobrien
98190075Sobrien  if (cfun->machine->eh_epilogue_sp_ofs != NULL_RTX)
98290075Sobrien    type |= ARM_FT_EXCEPTION_HANDLER;
98390075Sobrien  else
98490075Sobrien    {
98590075Sobrien      a = lookup_attribute ("isr", attr);
98690075Sobrien      if (a == NULL_TREE)
98790075Sobrien	a = lookup_attribute ("interrupt", attr);
98890075Sobrien
98990075Sobrien      if (a == NULL_TREE)
99090075Sobrien	type |= TARGET_INTERWORK ? ARM_FT_INTERWORKED : ARM_FT_NORMAL;
99190075Sobrien      else
99290075Sobrien	type |= arm_isr_value (TREE_VALUE (a));
99390075Sobrien    }
99490075Sobrien
99590075Sobrien  return type;
99690075Sobrien}
99790075Sobrien
99890075Sobrien/* Returns the type of the current function.  */
99990075Sobrien
100090075Sobrienunsigned long
1001132718Skanarm_current_func_type (void)
100290075Sobrien{
100390075Sobrien  if (ARM_FUNC_TYPE (cfun->machine->func_type) == ARM_FT_UNKNOWN)
100490075Sobrien    cfun->machine->func_type = arm_compute_func_type ();
100590075Sobrien
100690075Sobrien  return cfun->machine->func_type;
100790075Sobrien}
100890075Sobrien
1009132718Skan/* Return 1 if it is possible to return using a single instruction.
1010132718Skan   If SIBLING is non-null, this is a test for a return before a sibling
1011132718Skan   call.  SIBLING is the call insn, so we can examine its register usage.  */
101290075Sobrien
101390075Sobrienint
1014132718Skanuse_return_insn (int iscond, rtx sibling)
101590075Sobrien{
101690075Sobrien  int regno;
101790075Sobrien  unsigned int func_type;
1018107590Sobrien  unsigned long saved_int_regs;
1019132718Skan  unsigned HOST_WIDE_INT stack_adjust;
102090075Sobrien
102190075Sobrien  /* Never use a return instruction before reload has run.  */
102290075Sobrien  if (!reload_completed)
102390075Sobrien    return 0;
1024132718Skan
102590075Sobrien  func_type = arm_current_func_type ();
102690075Sobrien
102796263Sobrien  /* Naked functions and volatile functions need special
102896263Sobrien     consideration.  */
102996263Sobrien  if (func_type & (ARM_FT_VOLATILE | ARM_FT_NAKED))
103090075Sobrien    return 0;
1031117395Skan
1032117395Skan  /* So do interrupt functions that use the frame pointer.  */
1033117395Skan  if (IS_INTERRUPT (func_type) && frame_pointer_needed)
1034117395Skan    return 0;
1035132718Skan
1036132718Skan  stack_adjust = arm_get_frame_size () + current_function_outgoing_args_size;
1037132718Skan
103890075Sobrien  /* As do variadic functions.  */
103990075Sobrien  if (current_function_pretend_args_size
104096263Sobrien      || cfun->machine->uses_anonymous_args
1041132718Skan      /* Or if the function calls __builtin_eh_return () */
104290075Sobrien      || ARM_FUNC_TYPE (func_type) == ARM_FT_EXCEPTION_HANDLER
1043132718Skan      /* Or if the function calls alloca */
1044132718Skan      || current_function_calls_alloca
1045132718Skan      /* Or if there is a stack adjustment.  However, if the stack pointer
1046132718Skan	 is saved on the stack, we can use a pre-incrementing stack load.  */
1047132718Skan      || !(stack_adjust == 0 || (frame_pointer_needed && stack_adjust == 4)))
104890075Sobrien    return 0;
104990075Sobrien
1050107590Sobrien  saved_int_regs = arm_compute_save_reg_mask ();
1051107590Sobrien
1052132718Skan  /* Unfortunately, the insn
1053132718Skan
1054132718Skan       ldmib sp, {..., sp, ...}
1055132718Skan
1056132718Skan     triggers a bug on most SA-110 based devices, such that the stack
1057132718Skan     pointer won't be correctly restored if the instruction takes a
1058132718Skan     page fault.  We work around this problem by popping r3 along with
1059132718Skan     the other registers, since that is never slower than executing
1060132718Skan     another instruction.
1061132718Skan
1062132718Skan     We test for !arm_arch5 here, because code for any architecture
1063132718Skan     less than this could potentially be run on one of the buggy
1064132718Skan     chips.  */
1065132718Skan  if (stack_adjust == 4 && !arm_arch5)
1066132718Skan    {
1067132718Skan      /* Validate that r3 is a call-clobbered register (always true in
1068132718Skan	 the default abi) ...  */
1069132718Skan      if (!call_used_regs[3])
1070132718Skan	return 0;
1071132718Skan
1072132718Skan      /* ... that it isn't being used for a return value (always true
1073132718Skan	 until we implement return-in-regs), or for a tail-call
1074132718Skan	 argument ...  */
1075132718Skan      if (sibling)
1076132718Skan	{
1077132718Skan	  if (GET_CODE (sibling) != CALL_INSN)
1078132718Skan	    abort ();
1079132718Skan
1080132718Skan	  if (find_regno_fusage (sibling, USE, 3))
1081132718Skan	    return 0;
1082132718Skan	}
1083132718Skan
1084132718Skan      /* ... and that there are no call-saved registers in r0-r2
1085132718Skan	 (always true in the default ABI).  */
1086132718Skan      if (saved_int_regs & 0x7)
1087132718Skan	return 0;
1088132718Skan    }
1089132718Skan
109090075Sobrien  /* Can't be done if interworking with Thumb, and any registers have been
1091107590Sobrien     stacked.  */
1092107590Sobrien  if (TARGET_INTERWORK && saved_int_regs != 0)
109390075Sobrien    return 0;
1094107590Sobrien
1095107590Sobrien  /* On StrongARM, conditional returns are expensive if they aren't
1096107590Sobrien     taken and multiple registers have been stacked.  */
1097107590Sobrien  if (iscond && arm_is_strong)
109890075Sobrien    {
1099107590Sobrien      /* Conditional return when just the LR is stored is a simple
1100107590Sobrien	 conditional-load instruction, that's not expensive.  */
1101107590Sobrien      if (saved_int_regs != 0 && saved_int_regs != (1 << LR_REGNUM))
1102107590Sobrien	return 0;
110390075Sobrien
110490075Sobrien      if (flag_pic && regs_ever_live[PIC_OFFSET_TABLE_REGNUM])
110590075Sobrien	return 0;
110690075Sobrien    }
1107107590Sobrien
1108107590Sobrien  /* If there are saved registers but the LR isn't saved, then we need
1109107590Sobrien     two instructions for the return.  */
1110107590Sobrien  if (saved_int_regs && !(saved_int_regs & (1 << LR_REGNUM)))
1111107590Sobrien    return 0;
1112107590Sobrien
1113132718Skan  /* Can't be done if any of the FPA regs are pushed,
111490075Sobrien     since this also requires an insn.  */
111590075Sobrien  if (TARGET_HARD_FLOAT)
111690075Sobrien    for (regno = FIRST_ARM_FP_REGNUM; regno <= LAST_ARM_FP_REGNUM; regno++)
111790075Sobrien      if (regs_ever_live[regno] && !call_used_regs[regno])
111890075Sobrien	return 0;
111990075Sobrien
1120132718Skan  if (TARGET_REALLY_IWMMXT)
1121132718Skan    for (regno = FIRST_IWMMXT_REGNUM; regno <= LAST_IWMMXT_REGNUM; regno++)
1122132718Skan      if (regs_ever_live[regno] && ! call_used_regs [regno])
1123132718Skan	return 0;
1124132718Skan
112590075Sobrien  return 1;
112690075Sobrien}
112790075Sobrien
112890075Sobrien/* Return TRUE if int I is a valid immediate ARM constant.  */
112990075Sobrien
113090075Sobrienint
1131132718Skanconst_ok_for_arm (HOST_WIDE_INT i)
113290075Sobrien{
113390075Sobrien  unsigned HOST_WIDE_INT mask = ~(unsigned HOST_WIDE_INT)0xFF;
113490075Sobrien
113590075Sobrien  /* For machines with >32 bit HOST_WIDE_INT, the bits above bit 31 must
113690075Sobrien     be all zero, or all one.  */
113790075Sobrien  if ((i & ~(unsigned HOST_WIDE_INT) 0xffffffff) != 0
113890075Sobrien      && ((i & ~(unsigned HOST_WIDE_INT) 0xffffffff)
113990075Sobrien	  != ((~(unsigned HOST_WIDE_INT) 0)
114090075Sobrien	      & ~(unsigned HOST_WIDE_INT) 0xffffffff)))
114190075Sobrien    return FALSE;
114290075Sobrien
114390075Sobrien  /* Fast return for 0 and powers of 2 */
114490075Sobrien  if ((i & (i - 1)) == 0)
114590075Sobrien    return TRUE;
114690075Sobrien
114790075Sobrien  do
114890075Sobrien    {
114990075Sobrien      if ((i & mask & (unsigned HOST_WIDE_INT) 0xffffffff) == 0)
115090075Sobrien        return TRUE;
115190075Sobrien      mask =
115290075Sobrien	  (mask << 2) | ((mask & (unsigned HOST_WIDE_INT) 0xffffffff)
115390075Sobrien			  >> (32 - 2)) | ~(unsigned HOST_WIDE_INT) 0xffffffff;
115490075Sobrien    }
115590075Sobrien  while (mask != ~(unsigned HOST_WIDE_INT) 0xFF);
115690075Sobrien
115790075Sobrien  return FALSE;
115890075Sobrien}
115990075Sobrien
116090075Sobrien/* Return true if I is a valid constant for the operation CODE.  */
116190075Sobrienstatic int
1162132718Skanconst_ok_for_op (HOST_WIDE_INT i, enum rtx_code code)
116390075Sobrien{
116490075Sobrien  if (const_ok_for_arm (i))
116590075Sobrien    return 1;
116690075Sobrien
116790075Sobrien  switch (code)
116890075Sobrien    {
116990075Sobrien    case PLUS:
117090075Sobrien      return const_ok_for_arm (ARM_SIGN_EXTEND (-i));
117190075Sobrien
117290075Sobrien    case MINUS:		/* Should only occur with (MINUS I reg) => rsb */
117390075Sobrien    case XOR:
117490075Sobrien    case IOR:
117590075Sobrien      return 0;
117690075Sobrien
117790075Sobrien    case AND:
117890075Sobrien      return const_ok_for_arm (ARM_SIGN_EXTEND (~i));
117990075Sobrien
118090075Sobrien    default:
118190075Sobrien      abort ();
118290075Sobrien    }
118390075Sobrien}
118490075Sobrien
118590075Sobrien/* Emit a sequence of insns to handle a large constant.
118690075Sobrien   CODE is the code of the operation required, it can be any of SET, PLUS,
118790075Sobrien   IOR, AND, XOR, MINUS;
118890075Sobrien   MODE is the mode in which the operation is being performed;
118990075Sobrien   VAL is the integer to operate on;
119090075Sobrien   SOURCE is the other operand (a register, or a null-pointer for SET);
119190075Sobrien   SUBTARGETS means it is safe to create scratch registers if that will
119290075Sobrien   either produce a simpler sequence, or we will want to cse the values.
119390075Sobrien   Return value is the number of insns emitted.  */
119490075Sobrien
119590075Sobrienint
1196132718Skanarm_split_constant (enum rtx_code code, enum machine_mode mode,
1197132718Skan		    HOST_WIDE_INT val, rtx target, rtx source, int subtargets)
119890075Sobrien{
119990075Sobrien  if (subtargets || code == SET
120090075Sobrien      || (GET_CODE (target) == REG && GET_CODE (source) == REG
120190075Sobrien	  && REGNO (target) != REGNO (source)))
120290075Sobrien    {
120390075Sobrien      /* After arm_reorg has been called, we can't fix up expensive
1204117395Skan	 constants by pushing them into memory so we must synthesize
120590075Sobrien	 them in-line, regardless of the cost.  This is only likely to
120690075Sobrien	 be more costly on chips that have load delay slots and we are
120790075Sobrien	 compiling without running the scheduler (so no splitting
120890075Sobrien	 occurred before the final instruction emission).
120990075Sobrien
121090075Sobrien	 Ref: gcc -O1 -mcpu=strongarm gcc.c-torture/compile/980506-2.c
121190075Sobrien      */
121290075Sobrien      if (!after_arm_reorg
121390075Sobrien	  && (arm_gen_constant (code, mode, val, target, source, 1, 0)
121490075Sobrien	      > arm_constant_limit + (code != SET)))
121590075Sobrien	{
121690075Sobrien	  if (code == SET)
121790075Sobrien	    {
121890075Sobrien	      /* Currently SET is the only monadic value for CODE, all
121990075Sobrien		 the rest are diadic.  */
122090075Sobrien	      emit_insn (gen_rtx_SET (VOIDmode, target, GEN_INT (val)));
122190075Sobrien	      return 1;
122290075Sobrien	    }
122390075Sobrien	  else
122490075Sobrien	    {
122590075Sobrien	      rtx temp = subtargets ? gen_reg_rtx (mode) : target;
122690075Sobrien
122790075Sobrien	      emit_insn (gen_rtx_SET (VOIDmode, temp, GEN_INT (val)));
122890075Sobrien	      /* For MINUS, the value is subtracted from, since we never
122990075Sobrien		 have subtraction of a constant.  */
123090075Sobrien	      if (code == MINUS)
123190075Sobrien		emit_insn (gen_rtx_SET (VOIDmode, target,
123290075Sobrien					gen_rtx_MINUS (mode, temp, source)));
123390075Sobrien	      else
123490075Sobrien		emit_insn (gen_rtx_SET (VOIDmode, target,
123590075Sobrien					gen_rtx (code, mode, source, temp)));
123690075Sobrien	      return 2;
123790075Sobrien	    }
123890075Sobrien	}
123990075Sobrien    }
124090075Sobrien
124190075Sobrien  return arm_gen_constant (code, mode, val, target, source, subtargets, 1);
124290075Sobrien}
124390075Sobrien
124490075Sobrienstatic int
1245132718Skancount_insns_for_constant (HOST_WIDE_INT remainder, int i)
124690075Sobrien{
124790075Sobrien  HOST_WIDE_INT temp1;
124890075Sobrien  int num_insns = 0;
124990075Sobrien  do
125090075Sobrien    {
125190075Sobrien      int end;
125290075Sobrien
125390075Sobrien      if (i <= 0)
125490075Sobrien	i += 32;
125590075Sobrien      if (remainder & (3 << (i - 2)))
125690075Sobrien	{
125790075Sobrien	  end = i - 8;
125890075Sobrien	  if (end < 0)
125990075Sobrien	    end += 32;
126090075Sobrien	  temp1 = remainder & ((0x0ff << end)
126190075Sobrien				    | ((i < end) ? (0xff >> (32 - end)) : 0));
126290075Sobrien	  remainder &= ~temp1;
126390075Sobrien	  num_insns++;
126490075Sobrien	  i -= 6;
126590075Sobrien	}
126690075Sobrien      i -= 2;
126790075Sobrien    } while (remainder);
126890075Sobrien  return num_insns;
126990075Sobrien}
127090075Sobrien
127190075Sobrien/* As above, but extra parameter GENERATE which, if clear, suppresses
127290075Sobrien   RTL generation.  */
127390075Sobrien
127490075Sobrienstatic int
1275132718Skanarm_gen_constant (enum rtx_code code, enum machine_mode mode,
1276132718Skan		  HOST_WIDE_INT val, rtx target, rtx source, int subtargets,
1277132718Skan		  int generate)
127890075Sobrien{
127990075Sobrien  int can_invert = 0;
128090075Sobrien  int can_negate = 0;
128190075Sobrien  int can_negate_initial = 0;
128290075Sobrien  int can_shift = 0;
128390075Sobrien  int i;
128490075Sobrien  int num_bits_set = 0;
128590075Sobrien  int set_sign_bit_copies = 0;
128690075Sobrien  int clear_sign_bit_copies = 0;
128790075Sobrien  int clear_zero_bit_copies = 0;
128890075Sobrien  int set_zero_bit_copies = 0;
128990075Sobrien  int insns = 0;
129090075Sobrien  unsigned HOST_WIDE_INT temp1, temp2;
129190075Sobrien  unsigned HOST_WIDE_INT remainder = val & 0xffffffff;
129290075Sobrien
129390075Sobrien  /* Find out which operations are safe for a given CODE.  Also do a quick
129490075Sobrien     check for degenerate cases; these can occur when DImode operations
129590075Sobrien     are split.  */
129690075Sobrien  switch (code)
129790075Sobrien    {
129890075Sobrien    case SET:
129990075Sobrien      can_invert = 1;
130090075Sobrien      can_shift = 1;
130190075Sobrien      can_negate = 1;
130290075Sobrien      break;
130390075Sobrien
130490075Sobrien    case PLUS:
130590075Sobrien      can_negate = 1;
130690075Sobrien      can_negate_initial = 1;
130790075Sobrien      break;
130890075Sobrien
130990075Sobrien    case IOR:
131090075Sobrien      if (remainder == 0xffffffff)
131190075Sobrien	{
131290075Sobrien	  if (generate)
131390075Sobrien	    emit_insn (gen_rtx_SET (VOIDmode, target,
131490075Sobrien				    GEN_INT (ARM_SIGN_EXTEND (val))));
131590075Sobrien	  return 1;
131690075Sobrien	}
131790075Sobrien      if (remainder == 0)
131890075Sobrien	{
131990075Sobrien	  if (reload_completed && rtx_equal_p (target, source))
132090075Sobrien	    return 0;
132190075Sobrien	  if (generate)
132290075Sobrien	    emit_insn (gen_rtx_SET (VOIDmode, target, source));
132390075Sobrien	  return 1;
132490075Sobrien	}
132590075Sobrien      break;
132690075Sobrien
132790075Sobrien    case AND:
132890075Sobrien      if (remainder == 0)
132990075Sobrien	{
133090075Sobrien	  if (generate)
133190075Sobrien	    emit_insn (gen_rtx_SET (VOIDmode, target, const0_rtx));
133290075Sobrien	  return 1;
133390075Sobrien	}
133490075Sobrien      if (remainder == 0xffffffff)
133590075Sobrien	{
133690075Sobrien	  if (reload_completed && rtx_equal_p (target, source))
133790075Sobrien	    return 0;
133890075Sobrien	  if (generate)
133990075Sobrien	    emit_insn (gen_rtx_SET (VOIDmode, target, source));
134090075Sobrien	  return 1;
134190075Sobrien	}
134290075Sobrien      can_invert = 1;
134390075Sobrien      break;
134490075Sobrien
134590075Sobrien    case XOR:
134690075Sobrien      if (remainder == 0)
134790075Sobrien	{
134890075Sobrien	  if (reload_completed && rtx_equal_p (target, source))
134990075Sobrien	    return 0;
135090075Sobrien	  if (generate)
135190075Sobrien	    emit_insn (gen_rtx_SET (VOIDmode, target, source));
135290075Sobrien	  return 1;
135390075Sobrien	}
135490075Sobrien      if (remainder == 0xffffffff)
135590075Sobrien	{
135690075Sobrien	  if (generate)
135790075Sobrien	    emit_insn (gen_rtx_SET (VOIDmode, target,
135890075Sobrien				    gen_rtx_NOT (mode, source)));
135990075Sobrien	  return 1;
136090075Sobrien	}
136190075Sobrien
136290075Sobrien      /* We don't know how to handle this yet below.  */
136390075Sobrien      abort ();
136490075Sobrien
136590075Sobrien    case MINUS:
136690075Sobrien      /* We treat MINUS as (val - source), since (source - val) is always
136790075Sobrien	 passed as (source + (-val)).  */
136890075Sobrien      if (remainder == 0)
136990075Sobrien	{
137090075Sobrien	  if (generate)
137190075Sobrien	    emit_insn (gen_rtx_SET (VOIDmode, target,
137290075Sobrien				    gen_rtx_NEG (mode, source)));
137390075Sobrien	  return 1;
137490075Sobrien	}
137590075Sobrien      if (const_ok_for_arm (val))
137690075Sobrien	{
137790075Sobrien	  if (generate)
137890075Sobrien	    emit_insn (gen_rtx_SET (VOIDmode, target,
137990075Sobrien				    gen_rtx_MINUS (mode, GEN_INT (val),
138090075Sobrien						   source)));
138190075Sobrien	  return 1;
138290075Sobrien	}
138390075Sobrien      can_negate = 1;
138490075Sobrien
138590075Sobrien      break;
138690075Sobrien
138790075Sobrien    default:
138890075Sobrien      abort ();
138990075Sobrien    }
139090075Sobrien
139190075Sobrien  /* If we can do it in one insn get out quickly.  */
139290075Sobrien  if (const_ok_for_arm (val)
139390075Sobrien      || (can_negate_initial && const_ok_for_arm (-val))
139490075Sobrien      || (can_invert && const_ok_for_arm (~val)))
139590075Sobrien    {
139690075Sobrien      if (generate)
139790075Sobrien	emit_insn (gen_rtx_SET (VOIDmode, target,
139890075Sobrien				(source ? gen_rtx (code, mode, source,
139990075Sobrien						   GEN_INT (val))
140090075Sobrien				 : GEN_INT (val))));
140190075Sobrien      return 1;
140290075Sobrien    }
140390075Sobrien
140490075Sobrien  /* Calculate a few attributes that may be useful for specific
140590075Sobrien     optimizations.  */
140690075Sobrien  for (i = 31; i >= 0; i--)
140790075Sobrien    {
140890075Sobrien      if ((remainder & (1 << i)) == 0)
140990075Sobrien	clear_sign_bit_copies++;
141090075Sobrien      else
141190075Sobrien	break;
141290075Sobrien    }
141390075Sobrien
141490075Sobrien  for (i = 31; i >= 0; i--)
141590075Sobrien    {
141690075Sobrien      if ((remainder & (1 << i)) != 0)
141790075Sobrien	set_sign_bit_copies++;
141890075Sobrien      else
141990075Sobrien	break;
142090075Sobrien    }
142190075Sobrien
142290075Sobrien  for (i = 0; i <= 31; i++)
142390075Sobrien    {
142490075Sobrien      if ((remainder & (1 << i)) == 0)
142590075Sobrien	clear_zero_bit_copies++;
142690075Sobrien      else
142790075Sobrien	break;
142890075Sobrien    }
142990075Sobrien
143090075Sobrien  for (i = 0; i <= 31; i++)
143190075Sobrien    {
143290075Sobrien      if ((remainder & (1 << i)) != 0)
143390075Sobrien	set_zero_bit_copies++;
143490075Sobrien      else
143590075Sobrien	break;
143690075Sobrien    }
143790075Sobrien
143890075Sobrien  switch (code)
143990075Sobrien    {
144090075Sobrien    case SET:
144190075Sobrien      /* See if we can do this by sign_extending a constant that is known
144290075Sobrien	 to be negative.  This is a good, way of doing it, since the shift
144390075Sobrien	 may well merge into a subsequent insn.  */
144490075Sobrien      if (set_sign_bit_copies > 1)
144590075Sobrien	{
144690075Sobrien	  if (const_ok_for_arm
144790075Sobrien	      (temp1 = ARM_SIGN_EXTEND (remainder
144890075Sobrien					<< (set_sign_bit_copies - 1))))
144990075Sobrien	    {
145090075Sobrien	      if (generate)
145190075Sobrien		{
145290075Sobrien		  rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
145390075Sobrien		  emit_insn (gen_rtx_SET (VOIDmode, new_src,
145490075Sobrien					  GEN_INT (temp1)));
145590075Sobrien		  emit_insn (gen_ashrsi3 (target, new_src,
145690075Sobrien					  GEN_INT (set_sign_bit_copies - 1)));
145790075Sobrien		}
145890075Sobrien	      return 2;
145990075Sobrien	    }
146090075Sobrien	  /* For an inverted constant, we will need to set the low bits,
146190075Sobrien	     these will be shifted out of harm's way.  */
146290075Sobrien	  temp1 |= (1 << (set_sign_bit_copies - 1)) - 1;
146390075Sobrien	  if (const_ok_for_arm (~temp1))
146490075Sobrien	    {
146590075Sobrien	      if (generate)
146690075Sobrien		{
146790075Sobrien		  rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
146890075Sobrien		  emit_insn (gen_rtx_SET (VOIDmode, new_src,
146990075Sobrien					  GEN_INT (temp1)));
147090075Sobrien		  emit_insn (gen_ashrsi3 (target, new_src,
147190075Sobrien					  GEN_INT (set_sign_bit_copies - 1)));
147290075Sobrien		}
147390075Sobrien	      return 2;
147490075Sobrien	    }
147590075Sobrien	}
147690075Sobrien
147790075Sobrien      /* See if we can generate this by setting the bottom (or the top)
147890075Sobrien	 16 bits, and then shifting these into the other half of the
147990075Sobrien	 word.  We only look for the simplest cases, to do more would cost
148090075Sobrien	 too much.  Be careful, however, not to generate this when the
148190075Sobrien	 alternative would take fewer insns.  */
148290075Sobrien      if (val & 0xffff0000)
148390075Sobrien	{
148490075Sobrien	  temp1 = remainder & 0xffff0000;
148590075Sobrien	  temp2 = remainder & 0x0000ffff;
148690075Sobrien
148790075Sobrien	  /* Overlaps outside this range are best done using other methods.  */
148890075Sobrien	  for (i = 9; i < 24; i++)
148990075Sobrien	    {
149090075Sobrien	      if ((((temp2 | (temp2 << i)) & 0xffffffff) == remainder)
149190075Sobrien		  && !const_ok_for_arm (temp2))
149290075Sobrien		{
149390075Sobrien		  rtx new_src = (subtargets
149490075Sobrien				 ? (generate ? gen_reg_rtx (mode) : NULL_RTX)
149590075Sobrien				 : target);
149690075Sobrien		  insns = arm_gen_constant (code, mode, temp2, new_src,
149790075Sobrien					    source, subtargets, generate);
149890075Sobrien		  source = new_src;
149990075Sobrien		  if (generate)
150090075Sobrien		    emit_insn (gen_rtx_SET
150190075Sobrien			       (VOIDmode, target,
150290075Sobrien				gen_rtx_IOR (mode,
150390075Sobrien					     gen_rtx_ASHIFT (mode, source,
150490075Sobrien							     GEN_INT (i)),
150590075Sobrien					     source)));
150690075Sobrien		  return insns + 1;
150790075Sobrien		}
150890075Sobrien	    }
150990075Sobrien
151090075Sobrien	  /* Don't duplicate cases already considered.  */
151190075Sobrien	  for (i = 17; i < 24; i++)
151290075Sobrien	    {
151390075Sobrien	      if (((temp1 | (temp1 >> i)) == remainder)
151490075Sobrien		  && !const_ok_for_arm (temp1))
151590075Sobrien		{
151690075Sobrien		  rtx new_src = (subtargets
151790075Sobrien				 ? (generate ? gen_reg_rtx (mode) : NULL_RTX)
151890075Sobrien				 : target);
151990075Sobrien		  insns = arm_gen_constant (code, mode, temp1, new_src,
152090075Sobrien					    source, subtargets, generate);
152190075Sobrien		  source = new_src;
152290075Sobrien		  if (generate)
152390075Sobrien		    emit_insn
152490075Sobrien		      (gen_rtx_SET (VOIDmode, target,
152590075Sobrien				    gen_rtx_IOR
152690075Sobrien				    (mode,
152790075Sobrien				     gen_rtx_LSHIFTRT (mode, source,
152890075Sobrien						       GEN_INT (i)),
152990075Sobrien				     source)));
153090075Sobrien		  return insns + 1;
153190075Sobrien		}
153290075Sobrien	    }
153390075Sobrien	}
153490075Sobrien      break;
153590075Sobrien
153690075Sobrien    case IOR:
153790075Sobrien    case XOR:
153890075Sobrien      /* If we have IOR or XOR, and the constant can be loaded in a
153990075Sobrien	 single instruction, and we can find a temporary to put it in,
154090075Sobrien	 then this can be done in two instructions instead of 3-4.  */
154190075Sobrien      if (subtargets
154290075Sobrien	  /* TARGET can't be NULL if SUBTARGETS is 0 */
154390075Sobrien	  || (reload_completed && !reg_mentioned_p (target, source)))
154490075Sobrien	{
154590075Sobrien	  if (const_ok_for_arm (ARM_SIGN_EXTEND (~val)))
154690075Sobrien	    {
154790075Sobrien	      if (generate)
154890075Sobrien		{
154990075Sobrien		  rtx sub = subtargets ? gen_reg_rtx (mode) : target;
155090075Sobrien
155190075Sobrien		  emit_insn (gen_rtx_SET (VOIDmode, sub, GEN_INT (val)));
155290075Sobrien		  emit_insn (gen_rtx_SET (VOIDmode, target,
155390075Sobrien					  gen_rtx (code, mode, source, sub)));
155490075Sobrien		}
155590075Sobrien	      return 2;
155690075Sobrien	    }
155790075Sobrien	}
155890075Sobrien
155990075Sobrien      if (code == XOR)
156090075Sobrien	break;
156190075Sobrien
156290075Sobrien      if (set_sign_bit_copies > 8
156390075Sobrien	  && (val & (-1 << (32 - set_sign_bit_copies))) == val)
156490075Sobrien	{
156590075Sobrien	  if (generate)
156690075Sobrien	    {
156790075Sobrien	      rtx sub = subtargets ? gen_reg_rtx (mode) : target;
156890075Sobrien	      rtx shift = GEN_INT (set_sign_bit_copies);
156990075Sobrien
157090075Sobrien	      emit_insn (gen_rtx_SET (VOIDmode, sub,
157190075Sobrien				      gen_rtx_NOT (mode,
157290075Sobrien						   gen_rtx_ASHIFT (mode,
157390075Sobrien								   source,
157490075Sobrien								   shift))));
157590075Sobrien	      emit_insn (gen_rtx_SET (VOIDmode, target,
157690075Sobrien				      gen_rtx_NOT (mode,
157790075Sobrien						   gen_rtx_LSHIFTRT (mode, sub,
157890075Sobrien								     shift))));
157990075Sobrien	    }
158090075Sobrien	  return 2;
158190075Sobrien	}
158290075Sobrien
158390075Sobrien      if (set_zero_bit_copies > 8
158490075Sobrien	  && (remainder & ((1 << set_zero_bit_copies) - 1)) == remainder)
158590075Sobrien	{
158690075Sobrien	  if (generate)
158790075Sobrien	    {
158890075Sobrien	      rtx sub = subtargets ? gen_reg_rtx (mode) : target;
158990075Sobrien	      rtx shift = GEN_INT (set_zero_bit_copies);
159090075Sobrien
159190075Sobrien	      emit_insn (gen_rtx_SET (VOIDmode, sub,
159290075Sobrien				      gen_rtx_NOT (mode,
159390075Sobrien						   gen_rtx_LSHIFTRT (mode,
159490075Sobrien								     source,
159590075Sobrien								     shift))));
159690075Sobrien	      emit_insn (gen_rtx_SET (VOIDmode, target,
159790075Sobrien				      gen_rtx_NOT (mode,
159890075Sobrien						   gen_rtx_ASHIFT (mode, sub,
159990075Sobrien								   shift))));
160090075Sobrien	    }
160190075Sobrien	  return 2;
160290075Sobrien	}
160390075Sobrien
160490075Sobrien      if (const_ok_for_arm (temp1 = ARM_SIGN_EXTEND (~val)))
160590075Sobrien	{
160690075Sobrien	  if (generate)
160790075Sobrien	    {
160890075Sobrien	      rtx sub = subtargets ? gen_reg_rtx (mode) : target;
160990075Sobrien	      emit_insn (gen_rtx_SET (VOIDmode, sub,
161090075Sobrien				      gen_rtx_NOT (mode, source)));
161190075Sobrien	      source = sub;
161290075Sobrien	      if (subtargets)
161390075Sobrien		sub = gen_reg_rtx (mode);
161490075Sobrien	      emit_insn (gen_rtx_SET (VOIDmode, sub,
161590075Sobrien				      gen_rtx_AND (mode, source,
161690075Sobrien						   GEN_INT (temp1))));
161790075Sobrien	      emit_insn (gen_rtx_SET (VOIDmode, target,
161890075Sobrien				      gen_rtx_NOT (mode, sub)));
161990075Sobrien	    }
162090075Sobrien	  return 3;
162190075Sobrien	}
162290075Sobrien      break;
162390075Sobrien
162490075Sobrien    case AND:
162590075Sobrien      /* See if two shifts will do 2 or more insn's worth of work.  */
162690075Sobrien      if (clear_sign_bit_copies >= 16 && clear_sign_bit_copies < 24)
162790075Sobrien	{
162890075Sobrien	  HOST_WIDE_INT shift_mask = ((0xffffffff
162990075Sobrien				       << (32 - clear_sign_bit_copies))
163090075Sobrien				      & 0xffffffff);
163190075Sobrien
163290075Sobrien	  if ((remainder | shift_mask) != 0xffffffff)
163390075Sobrien	    {
163490075Sobrien	      if (generate)
163590075Sobrien		{
163690075Sobrien		  rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
163790075Sobrien		  insns = arm_gen_constant (AND, mode, remainder | shift_mask,
163890075Sobrien					    new_src, source, subtargets, 1);
163990075Sobrien		  source = new_src;
164090075Sobrien		}
164190075Sobrien	      else
164290075Sobrien		{
164390075Sobrien		  rtx targ = subtargets ? NULL_RTX : target;
164490075Sobrien		  insns = arm_gen_constant (AND, mode, remainder | shift_mask,
164590075Sobrien					    targ, source, subtargets, 0);
164690075Sobrien		}
164790075Sobrien	    }
164890075Sobrien
164990075Sobrien	  if (generate)
165090075Sobrien	    {
165190075Sobrien	      rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
165290075Sobrien	      rtx shift = GEN_INT (clear_sign_bit_copies);
165390075Sobrien
165490075Sobrien	      emit_insn (gen_ashlsi3 (new_src, source, shift));
165590075Sobrien	      emit_insn (gen_lshrsi3 (target, new_src, shift));
165690075Sobrien	    }
165790075Sobrien
165890075Sobrien	  return insns + 2;
165990075Sobrien	}
166090075Sobrien
166190075Sobrien      if (clear_zero_bit_copies >= 16 && clear_zero_bit_copies < 24)
166290075Sobrien	{
166390075Sobrien	  HOST_WIDE_INT shift_mask = (1 << clear_zero_bit_copies) - 1;
166490075Sobrien
166590075Sobrien	  if ((remainder | shift_mask) != 0xffffffff)
166690075Sobrien	    {
166790075Sobrien	      if (generate)
166890075Sobrien		{
166990075Sobrien		  rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
167090075Sobrien
167190075Sobrien		  insns = arm_gen_constant (AND, mode, remainder | shift_mask,
167290075Sobrien					    new_src, source, subtargets, 1);
167390075Sobrien		  source = new_src;
167490075Sobrien		}
167590075Sobrien	      else
167690075Sobrien		{
167790075Sobrien		  rtx targ = subtargets ? NULL_RTX : target;
167890075Sobrien
167990075Sobrien		  insns = arm_gen_constant (AND, mode, remainder | shift_mask,
168090075Sobrien					    targ, source, subtargets, 0);
168190075Sobrien		}
168290075Sobrien	    }
168390075Sobrien
168490075Sobrien	  if (generate)
168590075Sobrien	    {
168690075Sobrien	      rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
168790075Sobrien	      rtx shift = GEN_INT (clear_zero_bit_copies);
168890075Sobrien
168990075Sobrien	      emit_insn (gen_lshrsi3 (new_src, source, shift));
169090075Sobrien	      emit_insn (gen_ashlsi3 (target, new_src, shift));
169190075Sobrien	    }
169290075Sobrien
169390075Sobrien	  return insns + 2;
169490075Sobrien	}
169590075Sobrien
169690075Sobrien      break;
169790075Sobrien
169890075Sobrien    default:
169990075Sobrien      break;
170090075Sobrien    }
170190075Sobrien
170290075Sobrien  for (i = 0; i < 32; i++)
170390075Sobrien    if (remainder & (1 << i))
170490075Sobrien      num_bits_set++;
170590075Sobrien
170690075Sobrien  if (code == AND || (can_invert && num_bits_set > 16))
170790075Sobrien    remainder = (~remainder) & 0xffffffff;
170890075Sobrien  else if (code == PLUS && num_bits_set > 16)
170990075Sobrien    remainder = (-remainder) & 0xffffffff;
171090075Sobrien  else
171190075Sobrien    {
171290075Sobrien      can_invert = 0;
171390075Sobrien      can_negate = 0;
171490075Sobrien    }
171590075Sobrien
171690075Sobrien  /* Now try and find a way of doing the job in either two or three
171790075Sobrien     instructions.
171890075Sobrien     We start by looking for the largest block of zeros that are aligned on
171990075Sobrien     a 2-bit boundary, we then fill up the temps, wrapping around to the
172090075Sobrien     top of the word when we drop off the bottom.
172190075Sobrien     In the worst case this code should produce no more than four insns.  */
172290075Sobrien  {
172390075Sobrien    int best_start = 0;
172490075Sobrien    int best_consecutive_zeros = 0;
172590075Sobrien
172690075Sobrien    for (i = 0; i < 32; i += 2)
172790075Sobrien      {
172890075Sobrien	int consecutive_zeros = 0;
172990075Sobrien
173090075Sobrien	if (!(remainder & (3 << i)))
173190075Sobrien	  {
173290075Sobrien	    while ((i < 32) && !(remainder & (3 << i)))
173390075Sobrien	      {
173490075Sobrien		consecutive_zeros += 2;
173590075Sobrien		i += 2;
173690075Sobrien	      }
173790075Sobrien	    if (consecutive_zeros > best_consecutive_zeros)
173890075Sobrien	      {
173990075Sobrien		best_consecutive_zeros = consecutive_zeros;
174090075Sobrien		best_start = i - consecutive_zeros;
174190075Sobrien	      }
174290075Sobrien	    i -= 2;
174390075Sobrien	  }
174490075Sobrien      }
174590075Sobrien
174690075Sobrien    /* So long as it won't require any more insns to do so, it's
174790075Sobrien       desirable to emit a small constant (in bits 0...9) in the last
174890075Sobrien       insn.  This way there is more chance that it can be combined with
174990075Sobrien       a later addressing insn to form a pre-indexed load or store
175090075Sobrien       operation.  Consider:
175190075Sobrien
175290075Sobrien	       *((volatile int *)0xe0000100) = 1;
175390075Sobrien	       *((volatile int *)0xe0000110) = 2;
175490075Sobrien
175590075Sobrien       We want this to wind up as:
175690075Sobrien
175790075Sobrien		mov rA, #0xe0000000
175890075Sobrien		mov rB, #1
175990075Sobrien		str rB, [rA, #0x100]
176090075Sobrien		mov rB, #2
176190075Sobrien		str rB, [rA, #0x110]
176290075Sobrien
176390075Sobrien       rather than having to synthesize both large constants from scratch.
176490075Sobrien
176590075Sobrien       Therefore, we calculate how many insns would be required to emit
176690075Sobrien       the constant starting from `best_start', and also starting from
176790075Sobrien       zero (ie with bit 31 first to be output).  If `best_start' doesn't
176890075Sobrien       yield a shorter sequence, we may as well use zero.  */
176990075Sobrien    if (best_start != 0
177090075Sobrien	&& ((((unsigned HOST_WIDE_INT) 1) << best_start) < remainder)
177190075Sobrien	&& (count_insns_for_constant (remainder, 0) <=
177290075Sobrien	    count_insns_for_constant (remainder, best_start)))
177390075Sobrien      best_start = 0;
177490075Sobrien
177590075Sobrien    /* Now start emitting the insns.  */
177690075Sobrien    i = best_start;
177790075Sobrien    do
177890075Sobrien      {
177990075Sobrien	int end;
178090075Sobrien
178190075Sobrien	if (i <= 0)
178290075Sobrien	  i += 32;
178390075Sobrien	if (remainder & (3 << (i - 2)))
178490075Sobrien	  {
178590075Sobrien	    end = i - 8;
178690075Sobrien	    if (end < 0)
178790075Sobrien	      end += 32;
178890075Sobrien	    temp1 = remainder & ((0x0ff << end)
178990075Sobrien				 | ((i < end) ? (0xff >> (32 - end)) : 0));
179090075Sobrien	    remainder &= ~temp1;
179190075Sobrien
179290075Sobrien	    if (generate)
179390075Sobrien	      {
179490075Sobrien		rtx new_src, temp1_rtx;
179590075Sobrien
179690075Sobrien		if (code == SET || code == MINUS)
179790075Sobrien		  {
179890075Sobrien		    new_src = (subtargets ? gen_reg_rtx (mode) : target);
179990075Sobrien		    if (can_invert && code != MINUS)
180090075Sobrien		      temp1 = ~temp1;
180190075Sobrien		  }
180290075Sobrien		else
180390075Sobrien		  {
180490075Sobrien		    if (remainder && subtargets)
180590075Sobrien		      new_src = gen_reg_rtx (mode);
180690075Sobrien		    else
180790075Sobrien		      new_src = target;
180890075Sobrien		    if (can_invert)
180990075Sobrien		      temp1 = ~temp1;
181090075Sobrien		    else if (can_negate)
181190075Sobrien		      temp1 = -temp1;
181290075Sobrien		  }
181390075Sobrien
181490075Sobrien		temp1 = trunc_int_for_mode (temp1, mode);
181590075Sobrien		temp1_rtx = GEN_INT (temp1);
181690075Sobrien
181790075Sobrien		if (code == SET)
181890075Sobrien		  ;
181990075Sobrien		else if (code == MINUS)
182090075Sobrien		  temp1_rtx = gen_rtx_MINUS (mode, temp1_rtx, source);
182190075Sobrien		else
182290075Sobrien		  temp1_rtx = gen_rtx_fmt_ee (code, mode, source, temp1_rtx);
182390075Sobrien
182490075Sobrien		emit_insn (gen_rtx_SET (VOIDmode, new_src, temp1_rtx));
182590075Sobrien		source = new_src;
182690075Sobrien	      }
182790075Sobrien
182890075Sobrien	    if (code == SET)
182990075Sobrien	      {
183090075Sobrien		can_invert = 0;
183190075Sobrien		code = PLUS;
183290075Sobrien	      }
183390075Sobrien	    else if (code == MINUS)
183490075Sobrien	      code = PLUS;
183590075Sobrien
183690075Sobrien	    insns++;
183790075Sobrien	    i -= 6;
183890075Sobrien	  }
183990075Sobrien	i -= 2;
184090075Sobrien      }
184190075Sobrien    while (remainder);
184290075Sobrien  }
184390075Sobrien
184490075Sobrien  return insns;
184590075Sobrien}
184690075Sobrien
184790075Sobrien/* Canonicalize a comparison so that we are more likely to recognize it.
184890075Sobrien   This can be done for a few constant compares, where we can make the
184990075Sobrien   immediate value easier to load.  */
185090075Sobrien
185190075Sobrienenum rtx_code
1852132718Skanarm_canonicalize_comparison (enum rtx_code code, rtx * op1)
185390075Sobrien{
185490075Sobrien  unsigned HOST_WIDE_INT i = INTVAL (*op1);
185590075Sobrien
185690075Sobrien  switch (code)
185790075Sobrien    {
185890075Sobrien    case EQ:
185990075Sobrien    case NE:
186090075Sobrien      return code;
186190075Sobrien
186290075Sobrien    case GT:
186390075Sobrien    case LE:
186490075Sobrien      if (i != ((((unsigned HOST_WIDE_INT) 1) << (HOST_BITS_PER_WIDE_INT - 1)) - 1)
186590075Sobrien	  && (const_ok_for_arm (i + 1) || const_ok_for_arm (-(i + 1))))
186690075Sobrien	{
186790075Sobrien	  *op1 = GEN_INT (i + 1);
186890075Sobrien	  return code == GT ? GE : LT;
186990075Sobrien	}
187090075Sobrien      break;
187190075Sobrien
187290075Sobrien    case GE:
187390075Sobrien    case LT:
187490075Sobrien      if (i != (((unsigned HOST_WIDE_INT) 1) << (HOST_BITS_PER_WIDE_INT - 1))
187590075Sobrien	  && (const_ok_for_arm (i - 1) || const_ok_for_arm (-(i - 1))))
187690075Sobrien	{
187790075Sobrien	  *op1 = GEN_INT (i - 1);
187890075Sobrien	  return code == GE ? GT : LE;
187990075Sobrien	}
188090075Sobrien      break;
188190075Sobrien
188290075Sobrien    case GTU:
188390075Sobrien    case LEU:
188490075Sobrien      if (i != ~((unsigned HOST_WIDE_INT) 0)
188590075Sobrien	  && (const_ok_for_arm (i + 1) || const_ok_for_arm (-(i + 1))))
188690075Sobrien	{
188790075Sobrien	  *op1 = GEN_INT (i + 1);
188890075Sobrien	  return code == GTU ? GEU : LTU;
188990075Sobrien	}
189090075Sobrien      break;
189190075Sobrien
189290075Sobrien    case GEU:
189390075Sobrien    case LTU:
189490075Sobrien      if (i != 0
189590075Sobrien	  && (const_ok_for_arm (i - 1) || const_ok_for_arm (-(i - 1))))
189690075Sobrien	{
189790075Sobrien	  *op1 = GEN_INT (i - 1);
189890075Sobrien	  return code == GEU ? GTU : LEU;
189990075Sobrien	}
190090075Sobrien      break;
190190075Sobrien
190290075Sobrien    default:
190390075Sobrien      abort ();
190490075Sobrien    }
190590075Sobrien
190690075Sobrien  return code;
190790075Sobrien}
190890075Sobrien
190990075Sobrien/* Decide whether a type should be returned in memory (true)
191090075Sobrien   or in a register (false).  This is called by the macro
191190075Sobrien   RETURN_IN_MEMORY.  */
191290075Sobrienint
1913132718Skanarm_return_in_memory (tree type)
191490075Sobrien{
1915117395Skan  HOST_WIDE_INT size;
1916117395Skan
191790075Sobrien  if (!AGGREGATE_TYPE_P (type))
191890075Sobrien    /* All simple types are returned in registers.  */
191990075Sobrien    return 0;
1920117395Skan
1921117395Skan  size = int_size_in_bytes (type);
1922117395Skan
1923117395Skan  if (TARGET_ATPCS)
1924117395Skan    {
1925117395Skan      /* ATPCS returns aggregate types in memory only if they are
1926117395Skan	 larger than a word (or are variable size).  */
1927117395Skan      return (size < 0 || size > UNITS_PER_WORD);
1928117395Skan    }
192990075Sobrien
1930132718Skan  /* For the arm-wince targets we choose to be compatible with Microsoft's
193190075Sobrien     ARM and Thumb compilers, which always return aggregates in memory.  */
193290075Sobrien#ifndef ARM_WINCE
193390075Sobrien  /* All structures/unions bigger than one word are returned in memory.
193490075Sobrien     Also catch the case where int_size_in_bytes returns -1.  In this case
1935132718Skan     the aggregate is either huge or of variable size, and in either case
193690075Sobrien     we will want to return it via memory and not in a register.  */
1937117395Skan  if (size < 0 || size > UNITS_PER_WORD)
193890075Sobrien    return 1;
193990075Sobrien
194090075Sobrien  if (TREE_CODE (type) == RECORD_TYPE)
194190075Sobrien    {
194290075Sobrien      tree field;
194390075Sobrien
194490075Sobrien      /* For a struct the APCS says that we only return in a register
194590075Sobrien	 if the type is 'integer like' and every addressable element
194690075Sobrien	 has an offset of zero.  For practical purposes this means
194790075Sobrien	 that the structure can have at most one non bit-field element
194890075Sobrien	 and that this element must be the first one in the structure.  */
194990075Sobrien
195090075Sobrien      /* Find the first field, ignoring non FIELD_DECL things which will
195190075Sobrien	 have been created by C++.  */
195290075Sobrien      for (field = TYPE_FIELDS (type);
195390075Sobrien	   field && TREE_CODE (field) != FIELD_DECL;
195490075Sobrien	   field = TREE_CHAIN (field))
195590075Sobrien	continue;
195690075Sobrien
195790075Sobrien      if (field == NULL)
195890075Sobrien	return 0; /* An empty structure.  Allowed by an extension to ANSI C.  */
195990075Sobrien
196090075Sobrien      /* Check that the first field is valid for returning in a register.  */
196190075Sobrien
196290075Sobrien      /* ... Floats are not allowed */
196390075Sobrien      if (FLOAT_TYPE_P (TREE_TYPE (field)))
196490075Sobrien	return 1;
196590075Sobrien
196690075Sobrien      /* ... Aggregates that are not themselves valid for returning in
196790075Sobrien	 a register are not allowed.  */
196890075Sobrien      if (RETURN_IN_MEMORY (TREE_TYPE (field)))
196990075Sobrien	return 1;
197090075Sobrien
197190075Sobrien      /* Now check the remaining fields, if any.  Only bitfields are allowed,
197290075Sobrien	 since they are not addressable.  */
197390075Sobrien      for (field = TREE_CHAIN (field);
197490075Sobrien	   field;
197590075Sobrien	   field = TREE_CHAIN (field))
197690075Sobrien	{
197790075Sobrien	  if (TREE_CODE (field) != FIELD_DECL)
197890075Sobrien	    continue;
197990075Sobrien
198090075Sobrien	  if (!DECL_BIT_FIELD_TYPE (field))
198190075Sobrien	    return 1;
198290075Sobrien	}
198390075Sobrien
198490075Sobrien      return 0;
198590075Sobrien    }
198690075Sobrien
198790075Sobrien  if (TREE_CODE (type) == UNION_TYPE)
198890075Sobrien    {
198990075Sobrien      tree field;
199090075Sobrien
199190075Sobrien      /* Unions can be returned in registers if every element is
199290075Sobrien	 integral, or can be returned in an integer register.  */
199390075Sobrien      for (field = TYPE_FIELDS (type);
199490075Sobrien	   field;
199590075Sobrien	   field = TREE_CHAIN (field))
199690075Sobrien	{
199790075Sobrien	  if (TREE_CODE (field) != FIELD_DECL)
199890075Sobrien	    continue;
199990075Sobrien
200090075Sobrien	  if (FLOAT_TYPE_P (TREE_TYPE (field)))
200190075Sobrien	    return 1;
200290075Sobrien
200390075Sobrien	  if (RETURN_IN_MEMORY (TREE_TYPE (field)))
200490075Sobrien	    return 1;
200590075Sobrien	}
200690075Sobrien
200790075Sobrien      return 0;
200890075Sobrien    }
200990075Sobrien#endif /* not ARM_WINCE */
201090075Sobrien
201190075Sobrien  /* Return all other types in memory.  */
201290075Sobrien  return 1;
201390075Sobrien}
201490075Sobrien
2015132718Skan/* Indicate whether or not words of a double are in big-endian order.  */
2016117395Skan
2017117395Skanint
2018132718Skanarm_float_words_big_endian (void)
2019117395Skan{
2020132718Skan  if (TARGET_CIRRUS)
2021132718Skan    return 0;
2022117395Skan
2023117395Skan  /* For FPA, float words are always big-endian.  For VFP, floats words
2024117395Skan     follow the memory system mode.  */
2025117395Skan
2026117395Skan  if (TARGET_HARD_FLOAT)
2027117395Skan    {
2028117395Skan      /* FIXME: TARGET_HARD_FLOAT currently implies FPA.  */
2029117395Skan      return 1;
2030117395Skan    }
2031117395Skan
2032117395Skan  if (TARGET_VFP)
2033117395Skan    return (TARGET_BIG_END ? 1 : 0);
2034117395Skan
2035117395Skan  return 1;
2036117395Skan}
2037117395Skan
203890075Sobrien/* Initialize a variable CUM of type CUMULATIVE_ARGS
203990075Sobrien   for a call to a function whose data type is FNTYPE.
204090075Sobrien   For a library call, FNTYPE is NULL.  */
204190075Sobrienvoid
2042132718Skanarm_init_cumulative_args (CUMULATIVE_ARGS *pcum, tree fntype,
2043132718Skan			  rtx libname  ATTRIBUTE_UNUSED,
2044132718Skan			  tree fndecl ATTRIBUTE_UNUSED)
204590075Sobrien{
204690075Sobrien  /* On the ARM, the offset starts at 0.  */
2047132718Skan  pcum->nregs = ((fntype && aggregate_value_p (TREE_TYPE (fntype), fntype)) ? 1 : 0);
2048132718Skan  pcum->iwmmxt_nregs = 0;
204990075Sobrien
205090075Sobrien  pcum->call_cookie = CALL_NORMAL;
205190075Sobrien
205290075Sobrien  if (TARGET_LONG_CALLS)
205390075Sobrien    pcum->call_cookie = CALL_LONG;
205490075Sobrien
205590075Sobrien  /* Check for long call/short call attributes.  The attributes
205690075Sobrien     override any command line option.  */
205790075Sobrien  if (fntype)
205890075Sobrien    {
205990075Sobrien      if (lookup_attribute ("short_call", TYPE_ATTRIBUTES (fntype)))
206090075Sobrien	pcum->call_cookie = CALL_SHORT;
206190075Sobrien      else if (lookup_attribute ("long_call", TYPE_ATTRIBUTES (fntype)))
206290075Sobrien	pcum->call_cookie = CALL_LONG;
206390075Sobrien    }
2064132718Skan
2065132718Skan  /* Varargs vectors are treated the same as long long.
2066132718Skan     named_count avoids having to change the way arm handles 'named' */
2067132718Skan  pcum->named_count = 0;
2068132718Skan  pcum->nargs = 0;
2069132718Skan
2070132718Skan  if (TARGET_REALLY_IWMMXT && fntype)
2071132718Skan    {
2072132718Skan      tree fn_arg;
2073132718Skan
2074132718Skan      for (fn_arg = TYPE_ARG_TYPES (fntype);
2075132718Skan	   fn_arg;
2076132718Skan	   fn_arg = TREE_CHAIN (fn_arg))
2077132718Skan	pcum->named_count += 1;
2078132718Skan
2079132718Skan      if (! pcum->named_count)
2080132718Skan	pcum->named_count = INT_MAX;
2081132718Skan    }
208290075Sobrien}
208390075Sobrien
208490075Sobrien/* Determine where to put an argument to a function.
208590075Sobrien   Value is zero to push the argument on the stack,
208690075Sobrien   or a hard register in which to store the argument.
208790075Sobrien
208890075Sobrien   MODE is the argument's machine mode.
208990075Sobrien   TYPE is the data type of the argument (as a tree).
209090075Sobrien    This is null for libcalls where that information may
209190075Sobrien    not be available.
209290075Sobrien   CUM is a variable of type CUMULATIVE_ARGS which gives info about
209390075Sobrien    the preceding args and about the function being called.
209490075Sobrien   NAMED is nonzero if this argument is a named parameter
209590075Sobrien    (otherwise it is an extra parameter matching an ellipsis).  */
209690075Sobrien
209790075Sobrienrtx
2098132718Skanarm_function_arg (CUMULATIVE_ARGS *pcum, enum machine_mode mode,
2099132718Skan		  tree type ATTRIBUTE_UNUSED, int named)
210090075Sobrien{
2101132718Skan  if (TARGET_REALLY_IWMMXT)
2102132718Skan    {
2103132718Skan      if (VECTOR_MODE_SUPPORTED_P (mode))
2104132718Skan	{
2105132718Skan	  /* varargs vectors are treated the same as long long.
2106132718Skan	     named_count avoids having to change the way arm handles 'named' */
2107132718Skan	  if (pcum->named_count <= pcum->nargs + 1)
2108132718Skan	    {
2109132718Skan	      if (pcum->nregs == 1)
2110132718Skan		pcum->nregs += 1;
2111132718Skan	      if (pcum->nregs <= 2)
2112132718Skan		return gen_rtx_REG (mode, pcum->nregs);
2113132718Skan	      else
2114132718Skan		return NULL_RTX;
2115132718Skan	    }
2116132718Skan	  else if (pcum->iwmmxt_nregs <= 9)
2117132718Skan	    return gen_rtx_REG (mode, pcum->iwmmxt_nregs + FIRST_IWMMXT_REGNUM);
2118132718Skan	  else
2119132718Skan	    return NULL_RTX;
2120132718Skan	}
2121132718Skan      else if ((mode == DImode || mode == DFmode) && pcum->nregs & 1)
2122132718Skan	pcum->nregs += 1;
2123132718Skan    }
2124132718Skan
212590075Sobrien  if (mode == VOIDmode)
212690075Sobrien    /* Compute operand 2 of the call insn.  */
212790075Sobrien    return GEN_INT (pcum->call_cookie);
212890075Sobrien
212990075Sobrien  if (!named || pcum->nregs >= NUM_ARG_REGS)
213090075Sobrien    return NULL_RTX;
213190075Sobrien
213290075Sobrien  return gen_rtx_REG (mode, pcum->nregs);
213390075Sobrien}
2134117395Skan
2135117395Skan/* Variable sized types are passed by reference.  This is a GCC
2136117395Skan   extension to the ARM ABI.  */
2137117395Skan
2138117395Skanint
2139132718Skanarm_function_arg_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
2140132718Skan				    enum machine_mode mode ATTRIBUTE_UNUSED,
2141132718Skan				    tree type, int named ATTRIBUTE_UNUSED)
2142117395Skan{
2143117395Skan  return type && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST;
2144117395Skan}
2145117395Skan
2146117395Skan/* Implement va_arg.  */
2147117395Skan
2148117395Skanrtx
2149132718Skanarm_va_arg (tree valist, tree type)
2150117395Skan{
2151117395Skan  /* Variable sized types are passed by reference.  */
2152117395Skan  if (TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
2153117395Skan    {
2154117395Skan      rtx addr = std_expand_builtin_va_arg (valist, build_pointer_type (type));
2155117395Skan      return gen_rtx_MEM (ptr_mode, force_reg (Pmode, addr));
2156117395Skan    }
2157117395Skan
2158132718Skan  if (FUNCTION_ARG_BOUNDARY (TYPE_MODE (type), NULL) == IWMMXT_ALIGNMENT)
2159132718Skan    {
2160132718Skan      tree minus_eight;
2161132718Skan      tree t;
2162132718Skan
2163132718Skan      /* Maintain 64-bit alignment of the valist pointer by
2164132718Skan	 constructing:   valist = ((valist + (8 - 1)) & -8).  */
2165132718Skan      minus_eight = build_int_2 (- (IWMMXT_ALIGNMENT / BITS_PER_UNIT), -1);
2166132718Skan      t = build_int_2 ((IWMMXT_ALIGNMENT / BITS_PER_UNIT) - 1, 0);
2167132718Skan      t = build (PLUS_EXPR,    TREE_TYPE (valist), valist, t);
2168132718Skan      t = build (BIT_AND_EXPR, TREE_TYPE (t), t, minus_eight);
2169132718Skan      t = build (MODIFY_EXPR,  TREE_TYPE (valist), valist, t);
2170132718Skan      TREE_SIDE_EFFECTS (t) = 1;
2171132718Skan      expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
2172132718Skan
2173132718Skan      /* This is to stop the combine pass optimizing
2174132718Skan	 away the alignment adjustment.  */
2175132718Skan      mark_reg_pointer (arg_pointer_rtx, PARM_BOUNDARY);
2176132718Skan    }
2177132718Skan
2178117395Skan  return std_expand_builtin_va_arg (valist, type);
2179117395Skan}
218090075Sobrien
218190075Sobrien/* Encode the current state of the #pragma [no_]long_calls.  */
218290075Sobrientypedef enum
218390075Sobrien{
218490075Sobrien  OFF,		/* No #pramgma [no_]long_calls is in effect.  */
218590075Sobrien  LONG,		/* #pragma long_calls is in effect.  */
218690075Sobrien  SHORT		/* #pragma no_long_calls is in effect.  */
218790075Sobrien} arm_pragma_enum;
218890075Sobrien
218990075Sobrienstatic arm_pragma_enum arm_pragma_long_calls = OFF;
219090075Sobrien
219190075Sobrienvoid
2192132718Skanarm_pr_long_calls (struct cpp_reader * pfile ATTRIBUTE_UNUSED)
219390075Sobrien{
219490075Sobrien  arm_pragma_long_calls = LONG;
219590075Sobrien}
219690075Sobrien
219790075Sobrienvoid
2198132718Skanarm_pr_no_long_calls (struct cpp_reader * pfile ATTRIBUTE_UNUSED)
219990075Sobrien{
220090075Sobrien  arm_pragma_long_calls = SHORT;
220190075Sobrien}
220290075Sobrien
220390075Sobrienvoid
2204132718Skanarm_pr_long_calls_off (struct cpp_reader * pfile ATTRIBUTE_UNUSED)
220590075Sobrien{
220690075Sobrien  arm_pragma_long_calls = OFF;
220790075Sobrien}
220890075Sobrien
220990075Sobrien/* Table of machine attributes.  */
221090075Sobrienconst struct attribute_spec arm_attribute_table[] =
221190075Sobrien{
221290075Sobrien  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
221390075Sobrien  /* Function calls made to this symbol must be done indirectly, because
221490075Sobrien     it may lie outside of the 26 bit addressing range of a normal function
221590075Sobrien     call.  */
221690075Sobrien  { "long_call",    0, 0, false, true,  true,  NULL },
221790075Sobrien  /* Whereas these functions are always known to reside within the 26 bit
221890075Sobrien     addressing range.  */
221990075Sobrien  { "short_call",   0, 0, false, true,  true,  NULL },
222090075Sobrien  /* Interrupt Service Routines have special prologue and epilogue requirements.  */
222190075Sobrien  { "isr",          0, 1, false, false, false, arm_handle_isr_attribute },
222290075Sobrien  { "interrupt",    0, 1, false, false, false, arm_handle_isr_attribute },
222390075Sobrien  { "naked",        0, 0, true,  false, false, arm_handle_fndecl_attribute },
222490075Sobrien#ifdef ARM_PE
222590075Sobrien  /* ARM/PE has three new attributes:
222690075Sobrien     interfacearm - ?
222790075Sobrien     dllexport - for exporting a function/variable that will live in a dll
222890075Sobrien     dllimport - for importing a function/variable from a dll
222990075Sobrien
223090075Sobrien     Microsoft allows multiple declspecs in one __declspec, separating
223190075Sobrien     them with spaces.  We do NOT support this.  Instead, use __declspec
223290075Sobrien     multiple times.
223390075Sobrien  */
223490075Sobrien  { "dllimport",    0, 0, true,  false, false, NULL },
223590075Sobrien  { "dllexport",    0, 0, true,  false, false, NULL },
223690075Sobrien  { "interfacearm", 0, 0, true,  false, false, arm_handle_fndecl_attribute },
223790075Sobrien#endif
223890075Sobrien  { NULL,           0, 0, false, false, false, NULL }
223990075Sobrien};
224090075Sobrien
224190075Sobrien/* Handle an attribute requiring a FUNCTION_DECL;
224290075Sobrien   arguments as in struct attribute_spec.handler.  */
224390075Sobrienstatic tree
2244132718Skanarm_handle_fndecl_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
2245132718Skan			     int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
224690075Sobrien{
224790075Sobrien  if (TREE_CODE (*node) != FUNCTION_DECL)
224890075Sobrien    {
224990075Sobrien      warning ("`%s' attribute only applies to functions",
225090075Sobrien	       IDENTIFIER_POINTER (name));
225190075Sobrien      *no_add_attrs = true;
225290075Sobrien    }
225390075Sobrien
225490075Sobrien  return NULL_TREE;
225590075Sobrien}
225690075Sobrien
225790075Sobrien/* Handle an "interrupt" or "isr" attribute;
225890075Sobrien   arguments as in struct attribute_spec.handler.  */
225990075Sobrienstatic tree
2260132718Skanarm_handle_isr_attribute (tree *node, tree name, tree args, int flags,
2261132718Skan			  bool *no_add_attrs)
226290075Sobrien{
226390075Sobrien  if (DECL_P (*node))
226490075Sobrien    {
226590075Sobrien      if (TREE_CODE (*node) != FUNCTION_DECL)
226690075Sobrien	{
226790075Sobrien	  warning ("`%s' attribute only applies to functions",
226890075Sobrien		   IDENTIFIER_POINTER (name));
226990075Sobrien	  *no_add_attrs = true;
227090075Sobrien	}
227190075Sobrien      /* FIXME: the argument if any is checked for type attributes;
227290075Sobrien	 should it be checked for decl ones?  */
227390075Sobrien    }
227490075Sobrien  else
227590075Sobrien    {
227690075Sobrien      if (TREE_CODE (*node) == FUNCTION_TYPE
227790075Sobrien	  || TREE_CODE (*node) == METHOD_TYPE)
227890075Sobrien	{
227990075Sobrien	  if (arm_isr_value (args) == ARM_FT_UNKNOWN)
228090075Sobrien	    {
228190075Sobrien	      warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
228290075Sobrien	      *no_add_attrs = true;
228390075Sobrien	    }
228490075Sobrien	}
228590075Sobrien      else if (TREE_CODE (*node) == POINTER_TYPE
228690075Sobrien	       && (TREE_CODE (TREE_TYPE (*node)) == FUNCTION_TYPE
228790075Sobrien		   || TREE_CODE (TREE_TYPE (*node)) == METHOD_TYPE)
228890075Sobrien	       && arm_isr_value (args) != ARM_FT_UNKNOWN)
228990075Sobrien	{
229090075Sobrien	  *node = build_type_copy (*node);
229190075Sobrien	  TREE_TYPE (*node) = build_type_attribute_variant
229290075Sobrien	    (TREE_TYPE (*node),
229390075Sobrien	     tree_cons (name, args, TYPE_ATTRIBUTES (TREE_TYPE (*node))));
229490075Sobrien	  *no_add_attrs = true;
229590075Sobrien	}
229690075Sobrien      else
229790075Sobrien	{
229890075Sobrien	  /* Possibly pass this attribute on from the type to a decl.  */
229990075Sobrien	  if (flags & ((int) ATTR_FLAG_DECL_NEXT
230090075Sobrien		       | (int) ATTR_FLAG_FUNCTION_NEXT
230190075Sobrien		       | (int) ATTR_FLAG_ARRAY_NEXT))
230290075Sobrien	    {
230390075Sobrien	      *no_add_attrs = true;
230490075Sobrien	      return tree_cons (name, args, NULL_TREE);
230590075Sobrien	    }
230690075Sobrien	  else
230790075Sobrien	    {
230890075Sobrien	      warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
230990075Sobrien	    }
231090075Sobrien	}
231190075Sobrien    }
231290075Sobrien
231390075Sobrien  return NULL_TREE;
231490075Sobrien}
231590075Sobrien
231690075Sobrien/* Return 0 if the attributes for two types are incompatible, 1 if they
231790075Sobrien   are compatible, and 2 if they are nearly compatible (which causes a
231890075Sobrien   warning to be generated).  */
231990075Sobrienstatic int
2320132718Skanarm_comp_type_attributes (tree type1, tree type2)
232190075Sobrien{
232290075Sobrien  int l1, l2, s1, s2;
232390075Sobrien
232490075Sobrien  /* Check for mismatch of non-default calling convention.  */
232590075Sobrien  if (TREE_CODE (type1) != FUNCTION_TYPE)
232690075Sobrien    return 1;
232790075Sobrien
232890075Sobrien  /* Check for mismatched call attributes.  */
232990075Sobrien  l1 = lookup_attribute ("long_call", TYPE_ATTRIBUTES (type1)) != NULL;
233090075Sobrien  l2 = lookup_attribute ("long_call", TYPE_ATTRIBUTES (type2)) != NULL;
233190075Sobrien  s1 = lookup_attribute ("short_call", TYPE_ATTRIBUTES (type1)) != NULL;
233290075Sobrien  s2 = lookup_attribute ("short_call", TYPE_ATTRIBUTES (type2)) != NULL;
233390075Sobrien
233490075Sobrien  /* Only bother to check if an attribute is defined.  */
233590075Sobrien  if (l1 | l2 | s1 | s2)
233690075Sobrien    {
233790075Sobrien      /* If one type has an attribute, the other must have the same attribute.  */
233890075Sobrien      if ((l1 != l2) || (s1 != s2))
233990075Sobrien	return 0;
234090075Sobrien
234190075Sobrien      /* Disallow mixed attributes.  */
234290075Sobrien      if ((l1 & s2) || (l2 & s1))
234390075Sobrien	return 0;
234490075Sobrien    }
234590075Sobrien
234690075Sobrien  /* Check for mismatched ISR attribute.  */
234790075Sobrien  l1 = lookup_attribute ("isr", TYPE_ATTRIBUTES (type1)) != NULL;
234890075Sobrien  if (! l1)
234990075Sobrien    l1 = lookup_attribute ("interrupt", TYPE_ATTRIBUTES (type1)) != NULL;
235090075Sobrien  l2 = lookup_attribute ("isr", TYPE_ATTRIBUTES (type2)) != NULL;
235190075Sobrien  if (! l2)
235290075Sobrien    l1 = lookup_attribute ("interrupt", TYPE_ATTRIBUTES (type2)) != NULL;
235390075Sobrien  if (l1 != l2)
235490075Sobrien    return 0;
235590075Sobrien
235690075Sobrien  return 1;
235790075Sobrien}
235890075Sobrien
235990075Sobrien/*  Encode long_call or short_call attribute by prefixing
236090075Sobrien    symbol name in DECL with a special character FLAG.  */
236190075Sobrienvoid
2362132718Skanarm_encode_call_attribute (tree decl, int flag)
236390075Sobrien{
236490075Sobrien  const char * str = XSTR (XEXP (DECL_RTL (decl), 0), 0);
236590075Sobrien  int          len = strlen (str);
236690075Sobrien  char *       newstr;
236790075Sobrien
236890075Sobrien  /* Do not allow weak functions to be treated as short call.  */
236990075Sobrien  if (DECL_WEAK (decl) && flag == SHORT_CALL_FLAG_CHAR)
237090075Sobrien    return;
237190075Sobrien
237290075Sobrien  newstr = alloca (len + 2);
237390075Sobrien  newstr[0] = flag;
237490075Sobrien  strcpy (newstr + 1, str);
237590075Sobrien
237690075Sobrien  newstr = (char *) ggc_alloc_string (newstr, len + 1);
237790075Sobrien  XSTR (XEXP (DECL_RTL (decl), 0), 0) = newstr;
237890075Sobrien}
237990075Sobrien
238090075Sobrien/*  Assigns default attributes to newly defined type.  This is used to
238190075Sobrien    set short_call/long_call attributes for function types of
238290075Sobrien    functions defined inside corresponding #pragma scopes.  */
238390075Sobrienstatic void
2384132718Skanarm_set_default_type_attributes (tree type)
238590075Sobrien{
238690075Sobrien  /* Add __attribute__ ((long_call)) to all functions, when
238790075Sobrien     inside #pragma long_calls or __attribute__ ((short_call)),
238890075Sobrien     when inside #pragma no_long_calls.  */
238990075Sobrien  if (TREE_CODE (type) == FUNCTION_TYPE || TREE_CODE (type) == METHOD_TYPE)
239090075Sobrien    {
239190075Sobrien      tree type_attr_list, attr_name;
239290075Sobrien      type_attr_list = TYPE_ATTRIBUTES (type);
239390075Sobrien
239490075Sobrien      if (arm_pragma_long_calls == LONG)
239590075Sobrien 	attr_name = get_identifier ("long_call");
239690075Sobrien      else if (arm_pragma_long_calls == SHORT)
239790075Sobrien 	attr_name = get_identifier ("short_call");
239890075Sobrien      else
239990075Sobrien 	return;
240090075Sobrien
240190075Sobrien      type_attr_list = tree_cons (attr_name, NULL_TREE, type_attr_list);
240290075Sobrien      TYPE_ATTRIBUTES (type) = type_attr_list;
240390075Sobrien    }
240490075Sobrien}
240590075Sobrien
240690075Sobrien/* Return 1 if the operand is a SYMBOL_REF for a function known to be
2407132718Skan   defined within the current compilation unit.  If this cannot be
240890075Sobrien   determined, then 0 is returned.  */
240990075Sobrienstatic int
2410132718Skancurrent_file_function_operand (rtx sym_ref)
241190075Sobrien{
241290075Sobrien  /* This is a bit of a fib.  A function will have a short call flag
241390075Sobrien     applied to its name if it has the short call attribute, or it has
241490075Sobrien     already been defined within the current compilation unit.  */
241590075Sobrien  if (ENCODED_SHORT_CALL_ATTR_P (XSTR (sym_ref, 0)))
241690075Sobrien    return 1;
241790075Sobrien
241890075Sobrien  /* The current function is always defined within the current compilation
241990075Sobrien     unit.  if it s a weak definition however, then this may not be the real
242090075Sobrien     definition of the function, and so we have to say no.  */
242190075Sobrien  if (sym_ref == XEXP (DECL_RTL (current_function_decl), 0)
242290075Sobrien      && !DECL_WEAK (current_function_decl))
242390075Sobrien    return 1;
242490075Sobrien
242590075Sobrien  /* We cannot make the determination - default to returning 0.  */
242690075Sobrien  return 0;
242790075Sobrien}
242890075Sobrien
2429117395Skan/* Return nonzero if a 32 bit "long_call" should be generated for
243090075Sobrien   this call.  We generate a long_call if the function:
243190075Sobrien
243290075Sobrien        a.  has an __attribute__((long call))
243390075Sobrien     or b.  is within the scope of a #pragma long_calls
243490075Sobrien     or c.  the -mlong-calls command line switch has been specified
243590075Sobrien
243690075Sobrien   However we do not generate a long call if the function:
243790075Sobrien
243890075Sobrien        d.  has an __attribute__ ((short_call))
243990075Sobrien     or e.  is inside the scope of a #pragma no_long_calls
244090075Sobrien     or f.  has an __attribute__ ((section))
244190075Sobrien     or g.  is defined within the current compilation unit.
244290075Sobrien
244390075Sobrien   This function will be called by C fragments contained in the machine
244490075Sobrien   description file.  CALL_REF and CALL_COOKIE correspond to the matched
244590075Sobrien   rtl operands.  CALL_SYMBOL is used to distinguish between
244690075Sobrien   two different callers of the function.  It is set to 1 in the
244790075Sobrien   "call_symbol" and "call_symbol_value" patterns and to 0 in the "call"
244890075Sobrien   and "call_value" patterns.  This is because of the difference in the
244990075Sobrien   SYM_REFs passed by these patterns.  */
245090075Sobrienint
2451132718Skanarm_is_longcall_p (rtx sym_ref, int call_cookie, int call_symbol)
245290075Sobrien{
245390075Sobrien  if (!call_symbol)
245490075Sobrien    {
245590075Sobrien      if (GET_CODE (sym_ref) != MEM)
245690075Sobrien	return 0;
245790075Sobrien
245890075Sobrien      sym_ref = XEXP (sym_ref, 0);
245990075Sobrien    }
246090075Sobrien
246190075Sobrien  if (GET_CODE (sym_ref) != SYMBOL_REF)
246290075Sobrien    return 0;
246390075Sobrien
246490075Sobrien  if (call_cookie & CALL_SHORT)
246590075Sobrien    return 0;
246690075Sobrien
246790075Sobrien  if (TARGET_LONG_CALLS && flag_function_sections)
246890075Sobrien    return 1;
246990075Sobrien
247090075Sobrien  if (current_file_function_operand (sym_ref))
247190075Sobrien    return 0;
247290075Sobrien
247390075Sobrien  return (call_cookie & CALL_LONG)
247490075Sobrien    || ENCODED_LONG_CALL_ATTR_P (XSTR (sym_ref, 0))
247590075Sobrien    || TARGET_LONG_CALLS;
247690075Sobrien}
247790075Sobrien
2478117395Skan/* Return nonzero if it is ok to make a tail-call to DECL.  */
2479132718Skanstatic bool
2480132718Skanarm_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
248190075Sobrien{
248290075Sobrien  int call_type = TARGET_LONG_CALLS ? CALL_LONG : CALL_NORMAL;
248390075Sobrien
2484132718Skan  if (cfun->machine->sibcall_blocked)
2485132718Skan    return false;
2486132718Skan
248790075Sobrien  /* Never tailcall something for which we have no decl, or if we
248890075Sobrien     are in Thumb mode.  */
248990075Sobrien  if (decl == NULL || TARGET_THUMB)
2490132718Skan    return false;
249190075Sobrien
249290075Sobrien  /* Get the calling method.  */
249390075Sobrien  if (lookup_attribute ("short_call", TYPE_ATTRIBUTES (TREE_TYPE (decl))))
249490075Sobrien    call_type = CALL_SHORT;
249590075Sobrien  else if (lookup_attribute ("long_call", TYPE_ATTRIBUTES (TREE_TYPE (decl))))
249690075Sobrien    call_type = CALL_LONG;
249790075Sobrien
249890075Sobrien  /* Cannot tail-call to long calls, since these are out of range of
249990075Sobrien     a branch instruction.  However, if not compiling PIC, we know
250090075Sobrien     we can reach the symbol if it is in this compilation unit.  */
250190075Sobrien  if (call_type == CALL_LONG && (flag_pic || !TREE_ASM_WRITTEN (decl)))
2502132718Skan    return false;
250390075Sobrien
250490075Sobrien  /* If we are interworking and the function is not declared static
250590075Sobrien     then we can't tail-call it unless we know that it exists in this
250690075Sobrien     compilation unit (since it might be a Thumb routine).  */
250790075Sobrien  if (TARGET_INTERWORK && TREE_PUBLIC (decl) && !TREE_ASM_WRITTEN (decl))
2508132718Skan    return false;
250990075Sobrien
251090075Sobrien  /* Never tailcall from an ISR routine - it needs a special exit sequence.  */
251190075Sobrien  if (IS_INTERRUPT (arm_current_func_type ()))
2512132718Skan    return false;
251390075Sobrien
251490075Sobrien  /* Everything else is ok.  */
2515132718Skan  return true;
251690075Sobrien}
251790075Sobrien
251890075Sobrien
2519132718Skan/* Addressing mode support functions.  */
2520132718Skan
2521132718Skan/* Return nonzero if X is a legitimate immediate operand when compiling
2522132718Skan   for PIC.  */
252390075Sobrienint
2524132718Skanlegitimate_pic_operand_p (rtx x)
252590075Sobrien{
252690075Sobrien  if (CONSTANT_P (x)
252790075Sobrien      && flag_pic
252890075Sobrien      && (GET_CODE (x) == SYMBOL_REF
252990075Sobrien	  || (GET_CODE (x) == CONST
253090075Sobrien	      && GET_CODE (XEXP (x, 0)) == PLUS
253190075Sobrien	      && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF)))
253290075Sobrien    return 0;
253390075Sobrien
253490075Sobrien  return 1;
253590075Sobrien}
253690075Sobrien
253790075Sobrienrtx
2538132718Skanlegitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
253990075Sobrien{
254090075Sobrien  if (GET_CODE (orig) == SYMBOL_REF
254190075Sobrien      || GET_CODE (orig) == LABEL_REF)
254290075Sobrien    {
254390075Sobrien#ifndef AOF_ASSEMBLER
254490075Sobrien      rtx pic_ref, address;
254590075Sobrien#endif
254690075Sobrien      rtx insn;
254790075Sobrien      int subregs = 0;
254890075Sobrien
254990075Sobrien      if (reg == 0)
255090075Sobrien	{
255190075Sobrien	  if (no_new_pseudos)
255290075Sobrien	    abort ();
255390075Sobrien	  else
255490075Sobrien	    reg = gen_reg_rtx (Pmode);
255590075Sobrien
255690075Sobrien	  subregs = 1;
255790075Sobrien	}
255890075Sobrien
255990075Sobrien#ifdef AOF_ASSEMBLER
256090075Sobrien      /* The AOF assembler can generate relocations for these directly, and
256190075Sobrien	 understands that the PIC register has to be added into the offset.  */
256290075Sobrien      insn = emit_insn (gen_pic_load_addr_based (reg, orig));
256390075Sobrien#else
256490075Sobrien      if (subregs)
256590075Sobrien	address = gen_reg_rtx (Pmode);
256690075Sobrien      else
256790075Sobrien	address = reg;
256890075Sobrien
256990075Sobrien      if (TARGET_ARM)
257090075Sobrien	emit_insn (gen_pic_load_addr_arm (address, orig));
257190075Sobrien      else
257290075Sobrien	emit_insn (gen_pic_load_addr_thumb (address, orig));
257390075Sobrien
257496263Sobrien      if ((GET_CODE (orig) == LABEL_REF
257596263Sobrien	   || (GET_CODE (orig) == SYMBOL_REF &&
2576132718Skan	       SYMBOL_REF_LOCAL_P (orig)))
257796263Sobrien	  && NEED_GOT_RELOC)
257890075Sobrien	pic_ref = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, address);
257990075Sobrien      else
258090075Sobrien	{
258190075Sobrien	  pic_ref = gen_rtx_MEM (Pmode,
258290075Sobrien				 gen_rtx_PLUS (Pmode, pic_offset_table_rtx,
258390075Sobrien					       address));
258490075Sobrien	  RTX_UNCHANGING_P (pic_ref) = 1;
258590075Sobrien	}
258690075Sobrien
258790075Sobrien      insn = emit_move_insn (reg, pic_ref);
258890075Sobrien#endif
258990075Sobrien      current_function_uses_pic_offset_table = 1;
259090075Sobrien      /* Put a REG_EQUAL note on this insn, so that it can be optimized
259190075Sobrien	 by loop.  */
259290075Sobrien      REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, orig,
259390075Sobrien					    REG_NOTES (insn));
259490075Sobrien      return reg;
259590075Sobrien    }
259690075Sobrien  else if (GET_CODE (orig) == CONST)
259790075Sobrien    {
259890075Sobrien      rtx base, offset;
259990075Sobrien
260090075Sobrien      if (GET_CODE (XEXP (orig, 0)) == PLUS
260190075Sobrien	  && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx)
260290075Sobrien	return orig;
260390075Sobrien
260490075Sobrien      if (reg == 0)
260590075Sobrien	{
260690075Sobrien	  if (no_new_pseudos)
260790075Sobrien	    abort ();
260890075Sobrien	  else
260990075Sobrien	    reg = gen_reg_rtx (Pmode);
261090075Sobrien	}
261190075Sobrien
261290075Sobrien      if (GET_CODE (XEXP (orig, 0)) == PLUS)
261390075Sobrien	{
261490075Sobrien	  base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg);
261590075Sobrien	  offset = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode,
261690075Sobrien					   base == reg ? 0 : reg);
261790075Sobrien	}
261890075Sobrien      else
261990075Sobrien	abort ();
262090075Sobrien
262190075Sobrien      if (GET_CODE (offset) == CONST_INT)
262290075Sobrien	{
262390075Sobrien	  /* The base register doesn't really matter, we only want to
262490075Sobrien	     test the index for the appropriate mode.  */
2625132718Skan	  if (!arm_legitimate_index_p (mode, offset, 0))
2626132718Skan	    {
2627132718Skan	      if (!no_new_pseudos)
2628132718Skan		offset = force_reg (Pmode, offset);
2629132718Skan	      else
2630132718Skan		abort ();
2631132718Skan	    }
263290075Sobrien
263390075Sobrien	  if (GET_CODE (offset) == CONST_INT)
263490075Sobrien	    return plus_constant (base, INTVAL (offset));
263590075Sobrien	}
263690075Sobrien
263790075Sobrien      if (GET_MODE_SIZE (mode) > 4
263890075Sobrien	  && (GET_MODE_CLASS (mode) == MODE_INT
263990075Sobrien	      || TARGET_SOFT_FLOAT))
264090075Sobrien	{
264190075Sobrien	  emit_insn (gen_addsi3 (reg, base, offset));
264290075Sobrien	  return reg;
264390075Sobrien	}
264490075Sobrien
264590075Sobrien      return gen_rtx_PLUS (Pmode, base, offset);
264690075Sobrien    }
264790075Sobrien
264890075Sobrien  return orig;
264990075Sobrien}
265090075Sobrien
265190075Sobrien/* Generate code to load the PIC register.  PROLOGUE is true if
265290075Sobrien   called from arm_expand_prologue (in which case we want the
265390075Sobrien   generated insns at the start of the function);  false if called
265490075Sobrien   by an exception receiver that needs the PIC register reloaded
265590075Sobrien   (in which case the insns are just dumped at the current location).  */
265690075Sobrienvoid
2657132718Skanarm_finalize_pic (int prologue ATTRIBUTE_UNUSED)
265890075Sobrien{
265990075Sobrien#ifndef AOF_ASSEMBLER
266090075Sobrien  rtx l1, pic_tmp, pic_tmp2, seq, pic_rtx;
266190075Sobrien  rtx global_offset_table;
266290075Sobrien
266390075Sobrien  if (current_function_uses_pic_offset_table == 0 || TARGET_SINGLE_PIC_BASE)
266490075Sobrien    return;
266590075Sobrien
266690075Sobrien  if (!flag_pic)
266790075Sobrien    abort ();
266890075Sobrien
266990075Sobrien  start_sequence ();
267090075Sobrien  l1 = gen_label_rtx ();
267190075Sobrien
267290075Sobrien  global_offset_table = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
267390075Sobrien  /* On the ARM the PC register contains 'dot + 8' at the time of the
267490075Sobrien     addition, on the Thumb it is 'dot + 4'.  */
267590075Sobrien  pic_tmp = plus_constant (gen_rtx_LABEL_REF (Pmode, l1), TARGET_ARM ? 8 : 4);
267690075Sobrien  if (GOT_PCREL)
267790075Sobrien    pic_tmp2 = gen_rtx_CONST (VOIDmode,
267890075Sobrien			    gen_rtx_PLUS (Pmode, global_offset_table, pc_rtx));
267990075Sobrien  else
268090075Sobrien    pic_tmp2 = gen_rtx_CONST (VOIDmode, global_offset_table);
268190075Sobrien
268290075Sobrien  pic_rtx = gen_rtx_CONST (Pmode, gen_rtx_MINUS (Pmode, pic_tmp2, pic_tmp));
268390075Sobrien
268490075Sobrien  if (TARGET_ARM)
268590075Sobrien    {
268690075Sobrien      emit_insn (gen_pic_load_addr_arm (pic_offset_table_rtx, pic_rtx));
268790075Sobrien      emit_insn (gen_pic_add_dot_plus_eight (pic_offset_table_rtx, l1));
268890075Sobrien    }
268990075Sobrien  else
269090075Sobrien    {
269190075Sobrien      emit_insn (gen_pic_load_addr_thumb (pic_offset_table_rtx, pic_rtx));
269290075Sobrien      emit_insn (gen_pic_add_dot_plus_four (pic_offset_table_rtx, l1));
269390075Sobrien    }
269490075Sobrien
2695117395Skan  seq = get_insns ();
269690075Sobrien  end_sequence ();
269790075Sobrien  if (prologue)
269890075Sobrien    emit_insn_after (seq, get_insns ());
269990075Sobrien  else
270090075Sobrien    emit_insn (seq);
270190075Sobrien
270290075Sobrien  /* Need to emit this whether or not we obey regdecls,
270390075Sobrien     since setjmp/longjmp can cause life info to screw up.  */
270490075Sobrien  emit_insn (gen_rtx_USE (VOIDmode, pic_offset_table_rtx));
270590075Sobrien#endif /* AOF_ASSEMBLER */
270690075Sobrien}
270790075Sobrien
2708132718Skan/* Return nonzero if X is valid as an ARM state addressing register.  */
2709132718Skanstatic int
2710132718Skanarm_address_register_rtx_p (rtx x, int strict_p)
2711132718Skan{
2712132718Skan  int regno;
2713132718Skan
2714132718Skan  if (GET_CODE (x) != REG)
2715132718Skan    return 0;
2716132718Skan
2717132718Skan  regno = REGNO (x);
2718132718Skan
2719132718Skan  if (strict_p)
2720132718Skan    return ARM_REGNO_OK_FOR_BASE_P (regno);
2721132718Skan
2722132718Skan  return (regno <= LAST_ARM_REGNUM
2723132718Skan	  || regno >= FIRST_PSEUDO_REGISTER
2724132718Skan	  || regno == FRAME_POINTER_REGNUM
2725132718Skan	  || regno == ARG_POINTER_REGNUM);
2726132718Skan}
2727132718Skan
2728132718Skan/* Return nonzero if X is a valid ARM state address operand.  */
2729132718Skanint
2730132718Skanarm_legitimate_address_p (enum machine_mode mode, rtx x, int strict_p)
2731132718Skan{
2732132718Skan  if (arm_address_register_rtx_p (x, strict_p))
2733132718Skan    return 1;
2734132718Skan
2735132718Skan  else if (GET_CODE (x) == POST_INC || GET_CODE (x) == PRE_DEC)
2736132718Skan    return arm_address_register_rtx_p (XEXP (x, 0), strict_p);
2737132718Skan
2738132718Skan  else if ((GET_CODE (x) == POST_MODIFY || GET_CODE (x) == PRE_MODIFY)
2739132718Skan	   && GET_MODE_SIZE (mode) <= 4
2740132718Skan	   && arm_address_register_rtx_p (XEXP (x, 0), strict_p)
2741132718Skan	   && GET_CODE (XEXP (x, 1)) == PLUS
2742132718Skan	   && rtx_equal_p (XEXP (XEXP (x, 1), 0), XEXP (x, 0)))
2743132718Skan    return arm_legitimate_index_p (mode, XEXP (XEXP (x, 1), 1), strict_p);
2744132718Skan
2745132718Skan  /* After reload constants split into minipools will have addresses
2746132718Skan     from a LABEL_REF.  */
2747132718Skan  else if (reload_completed
2748132718Skan	   && (GET_CODE (x) == LABEL_REF
2749132718Skan	       || (GET_CODE (x) == CONST
2750132718Skan		   && GET_CODE (XEXP (x, 0)) == PLUS
2751132718Skan		   && GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF
2752132718Skan		   && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)))
2753132718Skan    return 1;
2754132718Skan
2755132718Skan  else if (mode == TImode)
2756132718Skan    return 0;
2757132718Skan
2758132718Skan  else if (mode == DImode || (TARGET_SOFT_FLOAT && mode == DFmode))
2759132718Skan    {
2760132718Skan      if (GET_CODE (x) == PLUS
2761132718Skan	  && arm_address_register_rtx_p (XEXP (x, 0), strict_p)
2762132718Skan	  && GET_CODE (XEXP (x, 1)) == CONST_INT)
2763132718Skan	{
2764132718Skan	  HOST_WIDE_INT val = INTVAL (XEXP (x, 1));
2765132718Skan
2766132718Skan          if (val == 4 || val == -4 || val == -8)
2767132718Skan	    return 1;
2768132718Skan	}
2769132718Skan    }
2770132718Skan
2771132718Skan  else if (GET_CODE (x) == PLUS)
2772132718Skan    {
2773132718Skan      rtx xop0 = XEXP (x, 0);
2774132718Skan      rtx xop1 = XEXP (x, 1);
2775132718Skan
2776132718Skan      return ((arm_address_register_rtx_p (xop0, strict_p)
2777132718Skan	       && arm_legitimate_index_p (mode, xop1, strict_p))
2778132718Skan	      || (arm_address_register_rtx_p (xop1, strict_p)
2779132718Skan		  && arm_legitimate_index_p (mode, xop0, strict_p)));
2780132718Skan    }
2781132718Skan
2782132718Skan#if 0
2783132718Skan  /* Reload currently can't handle MINUS, so disable this for now */
2784132718Skan  else if (GET_CODE (x) == MINUS)
2785132718Skan    {
2786132718Skan      rtx xop0 = XEXP (x, 0);
2787132718Skan      rtx xop1 = XEXP (x, 1);
2788132718Skan
2789132718Skan      return (arm_address_register_rtx_p (xop0, strict_p)
2790132718Skan	      && arm_legitimate_index_p (mode, xop1, strict_p));
2791132718Skan    }
2792132718Skan#endif
2793132718Skan
2794132718Skan  else if (GET_MODE_CLASS (mode) != MODE_FLOAT
2795132718Skan	   && GET_CODE (x) == SYMBOL_REF
2796132718Skan	   && CONSTANT_POOL_ADDRESS_P (x)
2797132718Skan	   && ! (flag_pic
2798132718Skan		 && symbol_mentioned_p (get_pool_constant (x))))
2799132718Skan    return 1;
2800132718Skan
2801132718Skan  else if ((GET_CODE (x) == PRE_INC || GET_CODE (x) == POST_DEC)
2802132718Skan	   && (GET_MODE_SIZE (mode) <= 4)
2803132718Skan	   && arm_address_register_rtx_p (XEXP (x, 0), strict_p))
2804132718Skan    return 1;
2805132718Skan
2806132718Skan  return 0;
2807132718Skan}
2808132718Skan
2809132718Skan/* Return nonzero if INDEX is valid for an address index operand in
2810132718Skan   ARM state.  */
2811132718Skanstatic int
2812132718Skanarm_legitimate_index_p (enum machine_mode mode, rtx index, int strict_p)
2813132718Skan{
2814132718Skan  HOST_WIDE_INT range;
2815132718Skan  enum rtx_code code = GET_CODE (index);
2816132718Skan
2817132718Skan  if (TARGET_HARD_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT)
2818132718Skan    return (code == CONST_INT && INTVAL (index) < 1024
2819132718Skan	    && INTVAL (index) > -1024
2820132718Skan	    && (INTVAL (index) & 3) == 0);
2821132718Skan
2822132718Skan  if (TARGET_CIRRUS
2823132718Skan      && (GET_MODE_CLASS (mode) == MODE_FLOAT || mode == DImode))
2824132718Skan    return (code == CONST_INT
2825132718Skan	    && INTVAL (index) < 255
2826132718Skan	    && INTVAL (index) > -255);
2827132718Skan
2828132718Skan  if (arm_address_register_rtx_p (index, strict_p)
2829132718Skan      && GET_MODE_SIZE (mode) <= 4)
2830132718Skan    return 1;
2831132718Skan
2832132718Skan  if (TARGET_REALLY_IWMMXT && VALID_IWMMXT_REG_MODE (mode))
2833132718Skan    return (code == CONST_INT
2834132718Skan	    && INTVAL (index) < 256
2835132718Skan	    && INTVAL (index) > -256);
2836132718Skan
2837132718Skan  /* XXX What about ldrsb?  */
2838132718Skan  if (GET_MODE_SIZE (mode) <= 4  && code == MULT
2839132718Skan      && (!arm_arch4 || (mode) != HImode))
2840132718Skan    {
2841132718Skan      rtx xiop0 = XEXP (index, 0);
2842132718Skan      rtx xiop1 = XEXP (index, 1);
2843132718Skan
2844132718Skan      return ((arm_address_register_rtx_p (xiop0, strict_p)
2845132718Skan	       && power_of_two_operand (xiop1, SImode))
2846132718Skan	      || (arm_address_register_rtx_p (xiop1, strict_p)
2847132718Skan		  && power_of_two_operand (xiop0, SImode)));
2848132718Skan    }
2849132718Skan
2850132718Skan  if (GET_MODE_SIZE (mode) <= 4
2851132718Skan      && (code == LSHIFTRT || code == ASHIFTRT
2852132718Skan	  || code == ASHIFT || code == ROTATERT)
2853132718Skan      && (!arm_arch4 || (mode) != HImode))
2854132718Skan    {
2855132718Skan      rtx op = XEXP (index, 1);
2856132718Skan
2857132718Skan      return (arm_address_register_rtx_p (XEXP (index, 0), strict_p)
2858132718Skan	      && GET_CODE (op) == CONST_INT
2859132718Skan	      && INTVAL (op) > 0
2860132718Skan	      && INTVAL (op) <= 31);
2861132718Skan    }
2862132718Skan
2863132718Skan  /* XXX For ARM v4 we may be doing a sign-extend operation during the
2864132718Skan     load, but that has a restricted addressing range and we are unable
2865132718Skan     to tell here whether that is the case.  To be safe we restrict all
2866132718Skan     loads to that range.  */
2867132718Skan  if (arm_arch4)
2868132718Skan    range = (mode == HImode || mode == QImode) ? 256 : 4096;
2869132718Skan  else
2870132718Skan    range = (mode == HImode) ? 4095 : 4096;
2871132718Skan
2872132718Skan  return (code == CONST_INT
2873132718Skan	  && INTVAL (index) < range
2874132718Skan	  && INTVAL (index) > -range);
2875132718Skan}
2876132718Skan
2877132718Skan/* Return nonzero if X is valid as a Thumb state base register.  */
2878132718Skanstatic int
2879132718Skanthumb_base_register_rtx_p (rtx x, enum machine_mode mode, int strict_p)
2880132718Skan{
2881132718Skan  int regno;
2882132718Skan
2883132718Skan  if (GET_CODE (x) != REG)
2884132718Skan    return 0;
2885132718Skan
2886132718Skan  regno = REGNO (x);
2887132718Skan
2888132718Skan  if (strict_p)
2889132718Skan    return THUMB_REGNO_MODE_OK_FOR_BASE_P (regno, mode);
2890132718Skan
2891132718Skan  return (regno <= LAST_LO_REGNUM
2892132718Skan	  || regno > LAST_VIRTUAL_REGISTER
2893132718Skan	  || regno == FRAME_POINTER_REGNUM
2894132718Skan	  || (GET_MODE_SIZE (mode) >= 4
2895132718Skan	      && (regno == STACK_POINTER_REGNUM
2896132718Skan		  || regno >= FIRST_PSEUDO_REGISTER
2897132718Skan		  || x == hard_frame_pointer_rtx
2898132718Skan		  || x == arg_pointer_rtx)));
2899132718Skan}
2900132718Skan
2901132718Skan/* Return nonzero if x is a legitimate index register.  This is the case
2902132718Skan   for any base register that can access a QImode object.  */
2903132718Skaninline static int
2904132718Skanthumb_index_register_rtx_p (rtx x, int strict_p)
2905132718Skan{
2906132718Skan  return thumb_base_register_rtx_p (x, QImode, strict_p);
2907132718Skan}
2908132718Skan
2909132718Skan/* Return nonzero if x is a legitimate Thumb-state address.
2910132718Skan
2911132718Skan   The AP may be eliminated to either the SP or the FP, so we use the
2912132718Skan   least common denominator, e.g. SImode, and offsets from 0 to 64.
2913132718Skan
2914132718Skan   ??? Verify whether the above is the right approach.
2915132718Skan
2916132718Skan   ??? Also, the FP may be eliminated to the SP, so perhaps that
2917132718Skan   needs special handling also.
2918132718Skan
2919132718Skan   ??? Look at how the mips16 port solves this problem.  It probably uses
2920132718Skan   better ways to solve some of these problems.
2921132718Skan
2922132718Skan   Although it is not incorrect, we don't accept QImode and HImode
2923132718Skan   addresses based on the frame pointer or arg pointer until the
2924132718Skan   reload pass starts.  This is so that eliminating such addresses
2925132718Skan   into stack based ones won't produce impossible code.  */
2926132718Skanint
2927132718Skanthumb_legitimate_address_p (enum machine_mode mode, rtx x, int strict_p)
2928132718Skan{
2929132718Skan  /* ??? Not clear if this is right.  Experiment.  */
2930132718Skan  if (GET_MODE_SIZE (mode) < 4
2931132718Skan      && !(reload_in_progress || reload_completed)
2932132718Skan      && (reg_mentioned_p (frame_pointer_rtx, x)
2933132718Skan	  || reg_mentioned_p (arg_pointer_rtx, x)
2934132718Skan	  || reg_mentioned_p (virtual_incoming_args_rtx, x)
2935132718Skan	  || reg_mentioned_p (virtual_outgoing_args_rtx, x)
2936132718Skan	  || reg_mentioned_p (virtual_stack_dynamic_rtx, x)
2937132718Skan	  || reg_mentioned_p (virtual_stack_vars_rtx, x)))
2938132718Skan    return 0;
2939132718Skan
2940132718Skan  /* Accept any base register.  SP only in SImode or larger.  */
2941132718Skan  else if (thumb_base_register_rtx_p (x, mode, strict_p))
2942132718Skan    return 1;
2943132718Skan
2944132718Skan  /* This is PC relative data before arm_reorg runs.  */
2945132718Skan  else if (GET_MODE_SIZE (mode) >= 4 && CONSTANT_P (x)
2946132718Skan	   && GET_CODE (x) == SYMBOL_REF
2947132718Skan           && CONSTANT_POOL_ADDRESS_P (x) && ! flag_pic)
2948132718Skan    return 1;
2949132718Skan
2950132718Skan  /* This is PC relative data after arm_reorg runs.  */
2951132718Skan  else if (GET_MODE_SIZE (mode) >= 4 && reload_completed
2952132718Skan	   && (GET_CODE (x) == LABEL_REF
2953132718Skan	       || (GET_CODE (x) == CONST
2954132718Skan		   && GET_CODE (XEXP (x, 0)) == PLUS
2955132718Skan		   && GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF
2956132718Skan		   && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)))
2957132718Skan    return 1;
2958132718Skan
2959132718Skan  /* Post-inc indexing only supported for SImode and larger.  */
2960132718Skan  else if (GET_CODE (x) == POST_INC && GET_MODE_SIZE (mode) >= 4
2961132718Skan	   && thumb_index_register_rtx_p (XEXP (x, 0), strict_p))
2962132718Skan    return 1;
2963132718Skan
2964132718Skan  else if (GET_CODE (x) == PLUS)
2965132718Skan    {
2966132718Skan      /* REG+REG address can be any two index registers.  */
2967132718Skan      /* We disallow FRAME+REG addressing since we know that FRAME
2968132718Skan	 will be replaced with STACK, and SP relative addressing only
2969132718Skan	 permits SP+OFFSET.  */
2970132718Skan      if (GET_MODE_SIZE (mode) <= 4
2971132718Skan	  && XEXP (x, 0) != frame_pointer_rtx
2972132718Skan	  && XEXP (x, 1) != frame_pointer_rtx
2973132718Skan	  && thumb_index_register_rtx_p (XEXP (x, 0), strict_p)
2974132718Skan	  && thumb_index_register_rtx_p (XEXP (x, 1), strict_p))
2975132718Skan	return 1;
2976132718Skan
2977132718Skan      /* REG+const has 5-7 bit offset for non-SP registers.  */
2978132718Skan      else if ((thumb_index_register_rtx_p (XEXP (x, 0), strict_p)
2979132718Skan		|| XEXP (x, 0) == arg_pointer_rtx)
2980132718Skan	       && GET_CODE (XEXP (x, 1)) == CONST_INT
2981132718Skan	       && thumb_legitimate_offset_p (mode, INTVAL (XEXP (x, 1))))
2982132718Skan	return 1;
2983132718Skan
2984132718Skan      /* REG+const has 10 bit offset for SP, but only SImode and
2985132718Skan	 larger is supported.  */
2986132718Skan      /* ??? Should probably check for DI/DFmode overflow here
2987132718Skan	 just like GO_IF_LEGITIMATE_OFFSET does.  */
2988132718Skan      else if (GET_CODE (XEXP (x, 0)) == REG
2989132718Skan	       && REGNO (XEXP (x, 0)) == STACK_POINTER_REGNUM
2990132718Skan	       && GET_MODE_SIZE (mode) >= 4
2991132718Skan	       && GET_CODE (XEXP (x, 1)) == CONST_INT
2992132718Skan	       && INTVAL (XEXP (x, 1)) >= 0
2993132718Skan	       && INTVAL (XEXP (x, 1)) + GET_MODE_SIZE (mode) <= 1024
2994132718Skan	       && (INTVAL (XEXP (x, 1)) & 3) == 0)
2995132718Skan	return 1;
2996132718Skan
2997132718Skan      else if (GET_CODE (XEXP (x, 0)) == REG
2998132718Skan	       && REGNO (XEXP (x, 0)) == FRAME_POINTER_REGNUM
2999132718Skan	       && GET_MODE_SIZE (mode) >= 4
3000132718Skan	       && GET_CODE (XEXP (x, 1)) == CONST_INT
3001132718Skan	       && (INTVAL (XEXP (x, 1)) & 3) == 0)
3002132718Skan	return 1;
3003132718Skan    }
3004132718Skan
3005132718Skan  else if (GET_MODE_CLASS (mode) != MODE_FLOAT
3006132718Skan	   && GET_MODE_SIZE (mode) == 4
3007132718Skan	   && GET_CODE (x) == SYMBOL_REF
3008132718Skan	   && CONSTANT_POOL_ADDRESS_P (x)
3009132718Skan	   && !(flag_pic
3010132718Skan		&& symbol_mentioned_p (get_pool_constant (x))))
3011132718Skan    return 1;
3012132718Skan
3013132718Skan  return 0;
3014132718Skan}
3015132718Skan
3016132718Skan/* Return nonzero if VAL can be used as an offset in a Thumb-state address
3017132718Skan   instruction of mode MODE.  */
3018132718Skanint
3019132718Skanthumb_legitimate_offset_p (enum machine_mode mode, HOST_WIDE_INT val)
3020132718Skan{
3021132718Skan  switch (GET_MODE_SIZE (mode))
3022132718Skan    {
3023132718Skan    case 1:
3024132718Skan      return val >= 0 && val < 32;
3025132718Skan
3026132718Skan    case 2:
3027132718Skan      return val >= 0 && val < 64 && (val & 1) == 0;
3028132718Skan
3029132718Skan    default:
3030132718Skan      return (val >= 0
3031132718Skan	      && (val + GET_MODE_SIZE (mode)) <= 128
3032132718Skan	      && (val & 3) == 0);
3033132718Skan    }
3034132718Skan}
3035132718Skan
3036132718Skan/* Try machine-dependent ways of modifying an illegitimate address
3037132718Skan   to be legitimate.  If we find one, return the new, valid address.  */
3038132718Skanrtx
3039132718Skanarm_legitimize_address (rtx x, rtx orig_x, enum machine_mode mode)
3040132718Skan{
3041132718Skan  if (GET_CODE (x) == PLUS)
3042132718Skan    {
3043132718Skan      rtx xop0 = XEXP (x, 0);
3044132718Skan      rtx xop1 = XEXP (x, 1);
3045132718Skan
3046132718Skan      if (CONSTANT_P (xop0) && !symbol_mentioned_p (xop0))
3047132718Skan	xop0 = force_reg (SImode, xop0);
3048132718Skan
3049132718Skan      if (CONSTANT_P (xop1) && !symbol_mentioned_p (xop1))
3050132718Skan	xop1 = force_reg (SImode, xop1);
3051132718Skan
3052132718Skan      if (ARM_BASE_REGISTER_RTX_P (xop0)
3053132718Skan	  && GET_CODE (xop1) == CONST_INT)
3054132718Skan	{
3055132718Skan	  HOST_WIDE_INT n, low_n;
3056132718Skan	  rtx base_reg, val;
3057132718Skan	  n = INTVAL (xop1);
3058132718Skan
3059132718Skan	  if (mode == DImode || (TARGET_SOFT_FLOAT && mode == DFmode))
3060132718Skan	    {
3061132718Skan	      low_n = n & 0x0f;
3062132718Skan	      n &= ~0x0f;
3063132718Skan	      if (low_n > 4)
3064132718Skan		{
3065132718Skan		  n += 16;
3066132718Skan		  low_n -= 16;
3067132718Skan		}
3068132718Skan	    }
3069132718Skan	  else
3070132718Skan	    {
3071132718Skan	      low_n = ((mode) == TImode ? 0
3072132718Skan		       : n >= 0 ? (n & 0xfff) : -((-n) & 0xfff));
3073132718Skan	      n -= low_n;
3074132718Skan	    }
3075132718Skan
3076132718Skan	  base_reg = gen_reg_rtx (SImode);
3077132718Skan	  val = force_operand (gen_rtx_PLUS (SImode, xop0,
3078132718Skan					     GEN_INT (n)), NULL_RTX);
3079132718Skan	  emit_move_insn (base_reg, val);
3080132718Skan	  x = (low_n == 0 ? base_reg
3081132718Skan	       : gen_rtx_PLUS (SImode, base_reg, GEN_INT (low_n)));
3082132718Skan	}
3083132718Skan      else if (xop0 != XEXP (x, 0) || xop1 != XEXP (x, 1))
3084132718Skan	x = gen_rtx_PLUS (SImode, xop0, xop1);
3085132718Skan    }
3086132718Skan
3087132718Skan  /* XXX We don't allow MINUS any more -- see comment in
3088132718Skan     arm_legitimate_address_p ().  */
3089132718Skan  else if (GET_CODE (x) == MINUS)
3090132718Skan    {
3091132718Skan      rtx xop0 = XEXP (x, 0);
3092132718Skan      rtx xop1 = XEXP (x, 1);
3093132718Skan
3094132718Skan      if (CONSTANT_P (xop0))
3095132718Skan	xop0 = force_reg (SImode, xop0);
3096132718Skan
3097132718Skan      if (CONSTANT_P (xop1) && ! symbol_mentioned_p (xop1))
3098132718Skan	xop1 = force_reg (SImode, xop1);
3099132718Skan
3100132718Skan      if (xop0 != XEXP (x, 0) || xop1 != XEXP (x, 1))
3101132718Skan	x = gen_rtx_MINUS (SImode, xop0, xop1);
3102132718Skan    }
3103132718Skan
3104132718Skan  if (flag_pic)
3105132718Skan    {
3106132718Skan      /* We need to find and carefully transform any SYMBOL and LABEL
3107132718Skan	 references; so go back to the original address expression.  */
3108132718Skan      rtx new_x = legitimize_pic_address (orig_x, mode, NULL_RTX);
3109132718Skan
3110132718Skan      if (new_x != orig_x)
3111132718Skan	x = new_x;
3112132718Skan    }
3113132718Skan
3114132718Skan  return x;
3115132718Skan}
3116132718Skan
3117132718Skan
3118132718Skan
311990075Sobrien#define REG_OR_SUBREG_REG(X)						\
312090075Sobrien  (GET_CODE (X) == REG							\
312190075Sobrien   || (GET_CODE (X) == SUBREG && GET_CODE (SUBREG_REG (X)) == REG))
312290075Sobrien
312390075Sobrien#define REG_OR_SUBREG_RTX(X)			\
312490075Sobrien   (GET_CODE (X) == REG ? (X) : SUBREG_REG (X))
312590075Sobrien
312690075Sobrien#ifndef COSTS_N_INSNS
312790075Sobrien#define COSTS_N_INSNS(N) ((N) * 4 - 2)
312890075Sobrien#endif
3129132718Skan/* Worker routine for arm_rtx_costs.  */
3130132718Skanstatic inline int
3131132718Skanarm_rtx_costs_1 (rtx x, enum rtx_code code, enum rtx_code outer)
313290075Sobrien{
313390075Sobrien  enum machine_mode mode = GET_MODE (x);
313490075Sobrien  enum rtx_code subcode;
313590075Sobrien  int extra_cost;
313690075Sobrien
313790075Sobrien  if (TARGET_THUMB)
313890075Sobrien    {
313990075Sobrien      switch (code)
314090075Sobrien	{
314190075Sobrien	case ASHIFT:
314290075Sobrien	case ASHIFTRT:
314390075Sobrien	case LSHIFTRT:
314490075Sobrien	case ROTATERT:
314590075Sobrien	case PLUS:
314690075Sobrien	case MINUS:
314790075Sobrien	case COMPARE:
314890075Sobrien	case NEG:
314990075Sobrien	case NOT:
315090075Sobrien	  return COSTS_N_INSNS (1);
315190075Sobrien
315290075Sobrien	case MULT:
315390075Sobrien	  if (GET_CODE (XEXP (x, 1)) == CONST_INT)
315490075Sobrien	    {
315590075Sobrien	      int cycles = 0;
315690075Sobrien	      unsigned HOST_WIDE_INT i = INTVAL (XEXP (x, 1));
315790075Sobrien
315890075Sobrien	      while (i)
315990075Sobrien		{
316090075Sobrien		  i >>= 2;
316190075Sobrien		  cycles++;
316290075Sobrien		}
316390075Sobrien	      return COSTS_N_INSNS (2) + cycles;
316490075Sobrien	    }
316590075Sobrien	  return COSTS_N_INSNS (1) + 16;
316690075Sobrien
316790075Sobrien	case SET:
316890075Sobrien	  return (COSTS_N_INSNS (1)
316990075Sobrien		  + 4 * ((GET_CODE (SET_SRC (x)) == MEM)
317090075Sobrien			 + GET_CODE (SET_DEST (x)) == MEM));
317190075Sobrien
317290075Sobrien	case CONST_INT:
317390075Sobrien	  if (outer == SET)
317490075Sobrien	    {
317590075Sobrien	      if ((unsigned HOST_WIDE_INT) INTVAL (x) < 256)
317690075Sobrien		return 0;
317790075Sobrien	      if (thumb_shiftable_const (INTVAL (x)))
317890075Sobrien		return COSTS_N_INSNS (2);
317990075Sobrien	      return COSTS_N_INSNS (3);
318090075Sobrien	    }
3181132718Skan	  else if ((outer == PLUS || outer == COMPARE)
318290075Sobrien		   && INTVAL (x) < 256 && INTVAL (x) > -256)
3183132718Skan	    return 0;
3184132718Skan	  else if (outer == AND
3185132718Skan		   && INTVAL (x) < 256 && INTVAL (x) >= -256)
3186132718Skan	    return COSTS_N_INSNS (1);
318790075Sobrien	  else if (outer == ASHIFT || outer == ASHIFTRT
318890075Sobrien		   || outer == LSHIFTRT)
318990075Sobrien	    return 0;
319090075Sobrien	  return COSTS_N_INSNS (2);
319190075Sobrien
319290075Sobrien	case CONST:
319390075Sobrien	case CONST_DOUBLE:
319490075Sobrien	case LABEL_REF:
319590075Sobrien	case SYMBOL_REF:
319690075Sobrien	  return COSTS_N_INSNS (3);
319790075Sobrien
319890075Sobrien	case UDIV:
319990075Sobrien	case UMOD:
320090075Sobrien	case DIV:
320190075Sobrien	case MOD:
320290075Sobrien	  return 100;
320390075Sobrien
320490075Sobrien	case TRUNCATE:
320590075Sobrien	  return 99;
320690075Sobrien
320790075Sobrien	case AND:
320890075Sobrien	case XOR:
320990075Sobrien	case IOR:
3210132718Skan	  /* XXX guess.  */
321190075Sobrien	  return 8;
321290075Sobrien
321390075Sobrien	case ADDRESSOF:
321490075Sobrien	case MEM:
321590075Sobrien	  /* XXX another guess.  */
321690075Sobrien	  /* Memory costs quite a lot for the first word, but subsequent words
321790075Sobrien	     load at the equivalent of a single insn each.  */
321890075Sobrien	  return (10 + 4 * ((GET_MODE_SIZE (mode) - 1) / UNITS_PER_WORD)
3219117395Skan		  + ((GET_CODE (x) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (x))
3220117395Skan		     ? 4 : 0));
322190075Sobrien
322290075Sobrien	case IF_THEN_ELSE:
3223132718Skan	  /* XXX a guess.  */
322490075Sobrien	  if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC)
322590075Sobrien	    return 14;
322690075Sobrien	  return 2;
322790075Sobrien
322890075Sobrien	case ZERO_EXTEND:
322990075Sobrien	  /* XXX still guessing.  */
323090075Sobrien	  switch (GET_MODE (XEXP (x, 0)))
323190075Sobrien	    {
323290075Sobrien	    case QImode:
323390075Sobrien	      return (1 + (mode == DImode ? 4 : 0)
323490075Sobrien		      + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
323590075Sobrien
323690075Sobrien	    case HImode:
323790075Sobrien	      return (4 + (mode == DImode ? 4 : 0)
323890075Sobrien		      + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
323990075Sobrien
324090075Sobrien	    case SImode:
324190075Sobrien	      return (1 + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
324290075Sobrien
324390075Sobrien	    default:
324490075Sobrien	      return 99;
324590075Sobrien	    }
324690075Sobrien
324790075Sobrien	default:
324890075Sobrien	  return 99;
324990075Sobrien	}
325090075Sobrien    }
325190075Sobrien
325290075Sobrien  switch (code)
325390075Sobrien    {
325490075Sobrien    case MEM:
325590075Sobrien      /* Memory costs quite a lot for the first word, but subsequent words
325690075Sobrien	 load at the equivalent of a single insn each.  */
325790075Sobrien      return (10 + 4 * ((GET_MODE_SIZE (mode) - 1) / UNITS_PER_WORD)
3258117395Skan	      + (GET_CODE (x) == SYMBOL_REF
3259117395Skan		 && CONSTANT_POOL_ADDRESS_P (x) ? 4 : 0));
326090075Sobrien
326190075Sobrien    case DIV:
326290075Sobrien    case MOD:
3263132718Skan    case UDIV:
3264132718Skan    case UMOD:
3265132718Skan      return optimize_size ? COSTS_N_INSNS (2) : 100;
326690075Sobrien
326790075Sobrien    case ROTATE:
326890075Sobrien      if (mode == SImode && GET_CODE (XEXP (x, 1)) == REG)
326990075Sobrien	return 4;
327090075Sobrien      /* Fall through */
327190075Sobrien    case ROTATERT:
327290075Sobrien      if (mode != SImode)
327390075Sobrien	return 8;
327490075Sobrien      /* Fall through */
327590075Sobrien    case ASHIFT: case LSHIFTRT: case ASHIFTRT:
327690075Sobrien      if (mode == DImode)
327790075Sobrien	return (8 + (GET_CODE (XEXP (x, 1)) == CONST_INT ? 0 : 8)
327890075Sobrien		+ ((GET_CODE (XEXP (x, 0)) == REG
327990075Sobrien		    || (GET_CODE (XEXP (x, 0)) == SUBREG
328090075Sobrien			&& GET_CODE (SUBREG_REG (XEXP (x, 0))) == REG))
328190075Sobrien		   ? 0 : 8));
328290075Sobrien      return (1 + ((GET_CODE (XEXP (x, 0)) == REG
328390075Sobrien		    || (GET_CODE (XEXP (x, 0)) == SUBREG
328490075Sobrien			&& GET_CODE (SUBREG_REG (XEXP (x, 0))) == REG))
328590075Sobrien		   ? 0 : 4)
328690075Sobrien	      + ((GET_CODE (XEXP (x, 1)) == REG
328790075Sobrien		  || (GET_CODE (XEXP (x, 1)) == SUBREG
328890075Sobrien		      && GET_CODE (SUBREG_REG (XEXP (x, 1))) == REG)
328990075Sobrien		  || (GET_CODE (XEXP (x, 1)) == CONST_INT))
329090075Sobrien		 ? 0 : 4));
329190075Sobrien
329290075Sobrien    case MINUS:
329390075Sobrien      if (mode == DImode)
329490075Sobrien	return (4 + (REG_OR_SUBREG_REG (XEXP (x, 1)) ? 0 : 8)
329590075Sobrien		+ ((REG_OR_SUBREG_REG (XEXP (x, 0))
329690075Sobrien		    || (GET_CODE (XEXP (x, 0)) == CONST_INT
329790075Sobrien		       && const_ok_for_arm (INTVAL (XEXP (x, 0)))))
329890075Sobrien		   ? 0 : 8));
329990075Sobrien
330090075Sobrien      if (GET_MODE_CLASS (mode) == MODE_FLOAT)
330190075Sobrien	return (2 + ((REG_OR_SUBREG_REG (XEXP (x, 1))
330290075Sobrien		      || (GET_CODE (XEXP (x, 1)) == CONST_DOUBLE
3303132718Skan			  && const_double_rtx_ok_for_fpa (XEXP (x, 1))))
330490075Sobrien		     ? 0 : 8)
330590075Sobrien		+ ((REG_OR_SUBREG_REG (XEXP (x, 0))
330690075Sobrien		    || (GET_CODE (XEXP (x, 0)) == CONST_DOUBLE
3307132718Skan			&& const_double_rtx_ok_for_fpa (XEXP (x, 0))))
330890075Sobrien		   ? 0 : 8));
330990075Sobrien
331090075Sobrien      if (((GET_CODE (XEXP (x, 0)) == CONST_INT
331190075Sobrien	    && const_ok_for_arm (INTVAL (XEXP (x, 0)))
331290075Sobrien	    && REG_OR_SUBREG_REG (XEXP (x, 1))))
331390075Sobrien	  || (((subcode = GET_CODE (XEXP (x, 1))) == ASHIFT
331490075Sobrien	       || subcode == ASHIFTRT || subcode == LSHIFTRT
331590075Sobrien	       || subcode == ROTATE || subcode == ROTATERT
331690075Sobrien	       || (subcode == MULT
331790075Sobrien		   && GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT
331890075Sobrien		   && ((INTVAL (XEXP (XEXP (x, 1), 1)) &
331990075Sobrien			(INTVAL (XEXP (XEXP (x, 1), 1)) - 1)) == 0)))
332090075Sobrien	      && REG_OR_SUBREG_REG (XEXP (XEXP (x, 1), 0))
332190075Sobrien	      && (REG_OR_SUBREG_REG (XEXP (XEXP (x, 1), 1))
332290075Sobrien		  || GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT)
332390075Sobrien	      && REG_OR_SUBREG_REG (XEXP (x, 0))))
332490075Sobrien	return 1;
332590075Sobrien      /* Fall through */
332690075Sobrien
332790075Sobrien    case PLUS:
332890075Sobrien      if (GET_MODE_CLASS (mode) == MODE_FLOAT)
332990075Sobrien	return (2 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 8)
333090075Sobrien		+ ((REG_OR_SUBREG_REG (XEXP (x, 1))
333190075Sobrien		    || (GET_CODE (XEXP (x, 1)) == CONST_DOUBLE
3332132718Skan			&& const_double_rtx_ok_for_fpa (XEXP (x, 1))))
333390075Sobrien		   ? 0 : 8));
333490075Sobrien
333590075Sobrien      /* Fall through */
333690075Sobrien    case AND: case XOR: case IOR:
333790075Sobrien      extra_cost = 0;
333890075Sobrien
333990075Sobrien      /* Normally the frame registers will be spilt into reg+const during
334090075Sobrien	 reload, so it is a bad idea to combine them with other instructions,
334190075Sobrien	 since then they might not be moved outside of loops.  As a compromise
334290075Sobrien	 we allow integration with ops that have a constant as their second
334390075Sobrien	 operand.  */
334490075Sobrien      if ((REG_OR_SUBREG_REG (XEXP (x, 0))
334590075Sobrien	   && ARM_FRAME_RTX (REG_OR_SUBREG_RTX (XEXP (x, 0)))
334690075Sobrien	   && GET_CODE (XEXP (x, 1)) != CONST_INT)
334790075Sobrien	  || (REG_OR_SUBREG_REG (XEXP (x, 0))
334890075Sobrien	      && ARM_FRAME_RTX (REG_OR_SUBREG_RTX (XEXP (x, 0)))))
334990075Sobrien	extra_cost = 4;
335090075Sobrien
335190075Sobrien      if (mode == DImode)
335290075Sobrien	return (4 + extra_cost + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 8)
335390075Sobrien		+ ((REG_OR_SUBREG_REG (XEXP (x, 1))
335490075Sobrien		    || (GET_CODE (XEXP (x, 1)) == CONST_INT
335590075Sobrien			&& const_ok_for_op (INTVAL (XEXP (x, 1)), code)))
335690075Sobrien		   ? 0 : 8));
335790075Sobrien
335890075Sobrien      if (REG_OR_SUBREG_REG (XEXP (x, 0)))
335990075Sobrien	return (1 + (GET_CODE (XEXP (x, 1)) == CONST_INT ? 0 : extra_cost)
336090075Sobrien		+ ((REG_OR_SUBREG_REG (XEXP (x, 1))
336190075Sobrien		    || (GET_CODE (XEXP (x, 1)) == CONST_INT
336290075Sobrien			&& const_ok_for_op (INTVAL (XEXP (x, 1)), code)))
336390075Sobrien		   ? 0 : 4));
336490075Sobrien
336590075Sobrien      else if (REG_OR_SUBREG_REG (XEXP (x, 1)))
336690075Sobrien	return (1 + extra_cost
336790075Sobrien		+ ((((subcode = GET_CODE (XEXP (x, 0))) == ASHIFT
336890075Sobrien		     || subcode == LSHIFTRT || subcode == ASHIFTRT
336990075Sobrien		     || subcode == ROTATE || subcode == ROTATERT
337090075Sobrien		     || (subcode == MULT
337190075Sobrien			 && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
337290075Sobrien			 && ((INTVAL (XEXP (XEXP (x, 0), 1)) &
337390075Sobrien			      (INTVAL (XEXP (XEXP (x, 0), 1)) - 1)) == 0)))
337490075Sobrien		    && (REG_OR_SUBREG_REG (XEXP (XEXP (x, 0), 0)))
337590075Sobrien		    && ((REG_OR_SUBREG_REG (XEXP (XEXP (x, 0), 1)))
337690075Sobrien			|| GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT))
337790075Sobrien		   ? 0 : 4));
337890075Sobrien
337990075Sobrien      return 8;
338090075Sobrien
338190075Sobrien    case MULT:
338290075Sobrien      /* There is no point basing this on the tuning, since it is always the
338390075Sobrien	 fast variant if it exists at all.  */
338490075Sobrien      if (arm_fast_multiply && mode == DImode
338590075Sobrien	  && (GET_CODE (XEXP (x, 0)) == GET_CODE (XEXP (x, 1)))
338690075Sobrien	  && (GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
338790075Sobrien	      || GET_CODE (XEXP (x, 0)) == SIGN_EXTEND))
338890075Sobrien	return 8;
338990075Sobrien
339090075Sobrien      if (GET_MODE_CLASS (mode) == MODE_FLOAT
339190075Sobrien	  || mode == DImode)
339290075Sobrien	return 30;
339390075Sobrien
339490075Sobrien      if (GET_CODE (XEXP (x, 1)) == CONST_INT)
339590075Sobrien	{
339690075Sobrien	  unsigned HOST_WIDE_INT i = (INTVAL (XEXP (x, 1))
339790075Sobrien				      & (unsigned HOST_WIDE_INT) 0xffffffff);
3398132718Skan	  int cost, const_ok = const_ok_for_arm (i);
3399132718Skan	  int j, booth_unit_size;
3400132718Skan
3401132718Skan	  if (arm_tune_xscale)
3402132718Skan	    {
3403132718Skan	      unsigned HOST_WIDE_INT masked_const;
3404132718Skan
3405132718Skan	      /* The cost will be related to two insns.
3406132718Skan		 First a load of the constant (MOV or LDR), then a multiply.  */
3407132718Skan	      cost = 2;
3408132718Skan	      if (! const_ok)
3409132718Skan		cost += 1;      /* LDR is probably more expensive because
3410132718Skan				   of longer result latency.  */
3411132718Skan	      masked_const = i & 0xffff8000;
3412132718Skan	      if (masked_const != 0 && masked_const != 0xffff8000)
3413132718Skan		{
3414132718Skan		  masked_const = i & 0xf8000000;
3415132718Skan		  if (masked_const == 0 || masked_const == 0xf8000000)
3416132718Skan		    cost += 1;
3417132718Skan		  else
3418132718Skan		    cost += 2;
3419132718Skan		}
3420132718Skan	      return cost;
3421132718Skan	    }
342290075Sobrien
342390075Sobrien	  /* Tune as appropriate.  */
3424132718Skan	  cost = const_ok ? 4 : 8;
3425132718Skan	  booth_unit_size = ((tune_flags & FL_FAST_MULT) ? 8 : 2);
342690075Sobrien	  for (j = 0; i && j < 32; j += booth_unit_size)
342790075Sobrien	    {
342890075Sobrien	      i >>= booth_unit_size;
3429132718Skan	      cost += 2;
343090075Sobrien	    }
343190075Sobrien
3432132718Skan	  return cost;
343390075Sobrien	}
343490075Sobrien
343590075Sobrien      return (((tune_flags & FL_FAST_MULT) ? 8 : 30)
343690075Sobrien	      + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4)
343790075Sobrien	      + (REG_OR_SUBREG_REG (XEXP (x, 1)) ? 0 : 4));
343890075Sobrien
343990075Sobrien    case TRUNCATE:
344090075Sobrien      if (arm_fast_multiply && mode == SImode
344190075Sobrien	  && GET_CODE (XEXP (x, 0)) == LSHIFTRT
344290075Sobrien	  && GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT
344390075Sobrien	  && (GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0))
344490075Sobrien	      == GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 1)))
344590075Sobrien	  && (GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == ZERO_EXTEND
344690075Sobrien	      || GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == SIGN_EXTEND))
344790075Sobrien	return 8;
344890075Sobrien      return 99;
344990075Sobrien
345090075Sobrien    case NEG:
345190075Sobrien      if (GET_MODE_CLASS (mode) == MODE_FLOAT)
345290075Sobrien	return 4 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 6);
345390075Sobrien      /* Fall through */
345490075Sobrien    case NOT:
345590075Sobrien      if (mode == DImode)
345690075Sobrien	return 4 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4);
345790075Sobrien
345890075Sobrien      return 1 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4);
345990075Sobrien
346090075Sobrien    case IF_THEN_ELSE:
346190075Sobrien      if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC)
346290075Sobrien	return 14;
346390075Sobrien      return 2;
346490075Sobrien
346590075Sobrien    case COMPARE:
346690075Sobrien      return 1;
346790075Sobrien
346890075Sobrien    case ABS:
346990075Sobrien      return 4 + (mode == DImode ? 4 : 0);
347090075Sobrien
347190075Sobrien    case SIGN_EXTEND:
347290075Sobrien      if (GET_MODE (XEXP (x, 0)) == QImode)
347390075Sobrien	return (4 + (mode == DImode ? 4 : 0)
347490075Sobrien		+ (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
347590075Sobrien      /* Fall through */
347690075Sobrien    case ZERO_EXTEND:
347790075Sobrien      switch (GET_MODE (XEXP (x, 0)))
347890075Sobrien	{
347990075Sobrien	case QImode:
348090075Sobrien	  return (1 + (mode == DImode ? 4 : 0)
348190075Sobrien		  + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
348290075Sobrien
348390075Sobrien	case HImode:
348490075Sobrien	  return (4 + (mode == DImode ? 4 : 0)
348590075Sobrien		  + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
348690075Sobrien
348790075Sobrien	case SImode:
348890075Sobrien	  return (1 + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
348990075Sobrien
3490132718Skan	case V8QImode:
3491132718Skan	case V4HImode:
3492132718Skan	case V2SImode:
3493132718Skan	case V4QImode:
3494132718Skan	case V2HImode:
3495132718Skan	    return 1;
3496132718Skan
349790075Sobrien	default:
349890075Sobrien	  break;
349990075Sobrien	}
350090075Sobrien      abort ();
350190075Sobrien
350290075Sobrien    case CONST_INT:
350390075Sobrien      if (const_ok_for_arm (INTVAL (x)))
350490075Sobrien	return outer == SET ? 2 : -1;
350590075Sobrien      else if (outer == AND
350690075Sobrien	       && const_ok_for_arm (~INTVAL (x)))
350790075Sobrien	return -1;
350890075Sobrien      else if ((outer == COMPARE
350990075Sobrien		|| outer == PLUS || outer == MINUS)
351090075Sobrien	       && const_ok_for_arm (-INTVAL (x)))
351190075Sobrien	return -1;
351290075Sobrien      else
351390075Sobrien	return 5;
351490075Sobrien
351590075Sobrien    case CONST:
351690075Sobrien    case LABEL_REF:
351790075Sobrien    case SYMBOL_REF:
351890075Sobrien      return 6;
351990075Sobrien
352090075Sobrien    case CONST_DOUBLE:
3521132718Skan      if (const_double_rtx_ok_for_fpa (x))
352290075Sobrien	return outer == SET ? 2 : -1;
352390075Sobrien      else if ((outer == COMPARE || outer == PLUS)
3524132718Skan	       && neg_const_double_rtx_ok_for_fpa (x))
352590075Sobrien	return -1;
352690075Sobrien      return 7;
352790075Sobrien
352890075Sobrien    default:
352990075Sobrien      return 99;
353090075Sobrien    }
353190075Sobrien}
353290075Sobrien
3533132718Skanstatic bool
3534132718Skanarm_rtx_costs (rtx x, int code, int outer_code, int *total)
3535132718Skan{
3536132718Skan  *total = arm_rtx_costs_1 (x, code, outer_code);
3537132718Skan  return true;
3538132718Skan}
3539132718Skan
3540132718Skan/* All address computations that can be done are free, but rtx cost returns
3541132718Skan   the same for practically all of them.  So we weight the different types
3542132718Skan   of address here in the order (most pref first):
3543132718Skan   PRE/POST_INC/DEC, SHIFT or NON-INT sum, INT sum, REG, MEM or LABEL.  */
3544132718Skanstatic inline int
3545132718Skanarm_arm_address_cost (rtx x)
3546132718Skan{
3547132718Skan  enum rtx_code c  = GET_CODE (x);
3548132718Skan
3549132718Skan  if (c == PRE_INC || c == PRE_DEC || c == POST_INC || c == POST_DEC)
3550132718Skan    return 0;
3551132718Skan  if (c == MEM || c == LABEL_REF || c == SYMBOL_REF)
3552132718Skan    return 10;
3553132718Skan
3554132718Skan  if (c == PLUS || c == MINUS)
3555132718Skan    {
3556132718Skan      char cl0 = GET_RTX_CLASS (GET_CODE (XEXP (x, 0)));
3557132718Skan      char cl1 = GET_RTX_CLASS (GET_CODE (XEXP (x, 1)));
3558132718Skan
3559132718Skan      if (GET_CODE (XEXP (x, 0)) == CONST_INT)
3560132718Skan	return 2;
3561132718Skan
3562132718Skan      if (cl0 == '2' || cl0 == 'c' || cl1 == '2' || cl1 == 'c')
3563132718Skan	return 3;
3564132718Skan
3565132718Skan      return 4;
3566132718Skan    }
3567132718Skan
3568132718Skan  return 6;
3569132718Skan}
3570132718Skan
3571132718Skanstatic inline int
3572132718Skanarm_thumb_address_cost (rtx x)
3573132718Skan{
3574132718Skan  enum rtx_code c  = GET_CODE (x);
3575132718Skan
3576132718Skan  if (c == REG)
3577132718Skan    return 1;
3578132718Skan  if (c == PLUS
3579132718Skan      && GET_CODE (XEXP (x, 0)) == REG
3580132718Skan      && GET_CODE (XEXP (x, 1)) == CONST_INT)
3581132718Skan    return 1;
3582132718Skan
3583132718Skan  return 2;
3584132718Skan}
3585132718Skan
358690075Sobrienstatic int
3587132718Skanarm_address_cost (rtx x)
358890075Sobrien{
3589132718Skan  return TARGET_ARM ? arm_arm_address_cost (x) : arm_thumb_address_cost (x);
3590132718Skan}
3591132718Skan
3592132718Skanstatic int
3593132718Skanarm_use_dfa_pipeline_interface (void)
3594132718Skan{
3595132718Skan  return true;
3596132718Skan}
3597132718Skan
3598132718Skanstatic int
3599132718Skanarm_adjust_cost (rtx insn, rtx link, rtx dep, int cost)
3600132718Skan{
360190075Sobrien  rtx i_pat, d_pat;
360290075Sobrien
360390075Sobrien  /* Some true dependencies can have a higher cost depending
360490075Sobrien     on precisely how certain input operands are used.  */
3605132718Skan  if (arm_tune_xscale
360690075Sobrien      && REG_NOTE_KIND (link) == 0
3607132718Skan      && recog_memoized (insn) >= 0
3608132718Skan      && recog_memoized (dep) >= 0)
360990075Sobrien    {
361090075Sobrien      int shift_opnum = get_attr_shift (insn);
361190075Sobrien      enum attr_type attr_type = get_attr_type (dep);
361290075Sobrien
361390075Sobrien      /* If nonzero, SHIFT_OPNUM contains the operand number of a shifted
361490075Sobrien	 operand for INSN.  If we have a shifted input operand and the
361590075Sobrien	 instruction we depend on is another ALU instruction, then we may
361690075Sobrien	 have to account for an additional stall.  */
361790075Sobrien      if (shift_opnum != 0 && attr_type == TYPE_NORMAL)
361890075Sobrien	{
361990075Sobrien	  rtx shifted_operand;
362090075Sobrien	  int opno;
362190075Sobrien
362290075Sobrien	  /* Get the shifted operand.  */
362390075Sobrien	  extract_insn (insn);
362490075Sobrien	  shifted_operand = recog_data.operand[shift_opnum];
362590075Sobrien
362690075Sobrien	  /* Iterate over all the operands in DEP.  If we write an operand
362790075Sobrien	     that overlaps with SHIFTED_OPERAND, then we have increase the
362890075Sobrien	     cost of this dependency.  */
362990075Sobrien	  extract_insn (dep);
363090075Sobrien	  preprocess_constraints ();
363190075Sobrien	  for (opno = 0; opno < recog_data.n_operands; opno++)
363290075Sobrien	    {
363390075Sobrien	      /* We can ignore strict inputs.  */
363490075Sobrien	      if (recog_data.operand_type[opno] == OP_IN)
363590075Sobrien		continue;
363690075Sobrien
363790075Sobrien	      if (reg_overlap_mentioned_p (recog_data.operand[opno],
363890075Sobrien					   shifted_operand))
363990075Sobrien		return 2;
364090075Sobrien	    }
364190075Sobrien	}
364290075Sobrien    }
364390075Sobrien
364490075Sobrien  /* XXX This is not strictly true for the FPA.  */
364590075Sobrien  if (REG_NOTE_KIND (link) == REG_DEP_ANTI
364690075Sobrien      || REG_NOTE_KIND (link) == REG_DEP_OUTPUT)
364790075Sobrien    return 0;
364890075Sobrien
364990075Sobrien  /* Call insns don't incur a stall, even if they follow a load.  */
365090075Sobrien  if (REG_NOTE_KIND (link) == 0
365190075Sobrien      && GET_CODE (insn) == CALL_INSN)
365290075Sobrien    return 1;
365390075Sobrien
365490075Sobrien  if ((i_pat = single_set (insn)) != NULL
365590075Sobrien      && GET_CODE (SET_SRC (i_pat)) == MEM
365690075Sobrien      && (d_pat = single_set (dep)) != NULL
365790075Sobrien      && GET_CODE (SET_DEST (d_pat)) == MEM)
365890075Sobrien    {
3659117395Skan      rtx src_mem = XEXP (SET_SRC (i_pat), 0);
366090075Sobrien      /* This is a load after a store, there is no conflict if the load reads
366190075Sobrien	 from a cached area.  Assume that loads from the stack, and from the
366290075Sobrien	 constant pool are cached, and that others will miss.  This is a
366390075Sobrien	 hack.  */
366490075Sobrien
3665117395Skan      if ((GET_CODE (src_mem) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (src_mem))
3666117395Skan	  || reg_mentioned_p (stack_pointer_rtx, src_mem)
3667117395Skan	  || reg_mentioned_p (frame_pointer_rtx, src_mem)
3668117395Skan	  || reg_mentioned_p (hard_frame_pointer_rtx, src_mem))
366990075Sobrien	return 1;
367090075Sobrien    }
367190075Sobrien
367290075Sobrien  return cost;
367390075Sobrien}
367490075Sobrien
367590075Sobrienstatic int fpa_consts_inited = 0;
367690075Sobrien
367790075Sobrienstatic const char * const strings_fpa[8] =
367890075Sobrien{
367990075Sobrien  "0",   "1",   "2",   "3",
368090075Sobrien  "4",   "5",   "0.5", "10"
368190075Sobrien};
368290075Sobrien
368390075Sobrienstatic REAL_VALUE_TYPE values_fpa[8];
368490075Sobrien
368590075Sobrienstatic void
3686132718Skaninit_fpa_table (void)
368790075Sobrien{
368890075Sobrien  int i;
368990075Sobrien  REAL_VALUE_TYPE r;
369090075Sobrien
369190075Sobrien  for (i = 0; i < 8; i++)
369290075Sobrien    {
369390075Sobrien      r = REAL_VALUE_ATOF (strings_fpa[i], DFmode);
369490075Sobrien      values_fpa[i] = r;
369590075Sobrien    }
369690075Sobrien
369790075Sobrien  fpa_consts_inited = 1;
369890075Sobrien}
369990075Sobrien
3700132718Skan/* Return TRUE if rtx X is a valid immediate FPA constant.  */
370190075Sobrienint
3702132718Skanconst_double_rtx_ok_for_fpa (rtx x)
370390075Sobrien{
370490075Sobrien  REAL_VALUE_TYPE r;
370590075Sobrien  int i;
370690075Sobrien
370790075Sobrien  if (!fpa_consts_inited)
370890075Sobrien    init_fpa_table ();
370990075Sobrien
371090075Sobrien  REAL_VALUE_FROM_CONST_DOUBLE (r, x);
371190075Sobrien  if (REAL_VALUE_MINUS_ZERO (r))
371290075Sobrien    return 0;
371390075Sobrien
371490075Sobrien  for (i = 0; i < 8; i++)
371590075Sobrien    if (REAL_VALUES_EQUAL (r, values_fpa[i]))
371690075Sobrien      return 1;
371790075Sobrien
371890075Sobrien  return 0;
371990075Sobrien}
372090075Sobrien
3721132718Skan/* Return TRUE if rtx X is a valid immediate FPA constant.  */
372290075Sobrienint
3723132718Skanneg_const_double_rtx_ok_for_fpa (rtx x)
372490075Sobrien{
372590075Sobrien  REAL_VALUE_TYPE r;
372690075Sobrien  int i;
372790075Sobrien
372890075Sobrien  if (!fpa_consts_inited)
372990075Sobrien    init_fpa_table ();
373090075Sobrien
373190075Sobrien  REAL_VALUE_FROM_CONST_DOUBLE (r, x);
373290075Sobrien  r = REAL_VALUE_NEGATE (r);
373390075Sobrien  if (REAL_VALUE_MINUS_ZERO (r))
373490075Sobrien    return 0;
373590075Sobrien
373690075Sobrien  for (i = 0; i < 8; i++)
373790075Sobrien    if (REAL_VALUES_EQUAL (r, values_fpa[i]))
373890075Sobrien      return 1;
373990075Sobrien
374090075Sobrien  return 0;
374190075Sobrien}
374290075Sobrien
374390075Sobrien/* Predicates for `match_operand' and `match_operator'.  */
374490075Sobrien
374590075Sobrien/* s_register_operand is the same as register_operand, but it doesn't accept
374690075Sobrien   (SUBREG (MEM)...).
374790075Sobrien
374890075Sobrien   This function exists because at the time it was put in it led to better
374990075Sobrien   code.  SUBREG(MEM) always needs a reload in the places where
375090075Sobrien   s_register_operand is used, and this seemed to lead to excessive
375190075Sobrien   reloading.  */
375290075Sobrienint
3753132718Skans_register_operand (rtx op, enum machine_mode mode)
375490075Sobrien{
375590075Sobrien  if (GET_MODE (op) != mode && mode != VOIDmode)
375690075Sobrien    return 0;
375790075Sobrien
375890075Sobrien  if (GET_CODE (op) == SUBREG)
375990075Sobrien    op = SUBREG_REG (op);
376090075Sobrien
376190075Sobrien  /* We don't consider registers whose class is NO_REGS
376290075Sobrien     to be a register operand.  */
376390075Sobrien  /* XXX might have to check for lo regs only for thumb ??? */
376490075Sobrien  return (GET_CODE (op) == REG
376590075Sobrien	  && (REGNO (op) >= FIRST_PSEUDO_REGISTER
376690075Sobrien	      || REGNO_REG_CLASS (REGNO (op)) != NO_REGS));
376790075Sobrien}
376890075Sobrien
376990075Sobrien/* A hard register operand (even before reload.  */
377090075Sobrienint
3771132718Skanarm_hard_register_operand (rtx op, enum machine_mode mode)
377290075Sobrien{
377390075Sobrien  if (GET_MODE (op) != mode && mode != VOIDmode)
377490075Sobrien    return 0;
377590075Sobrien
377690075Sobrien  return (GET_CODE (op) == REG
377790075Sobrien	  && REGNO (op) < FIRST_PSEUDO_REGISTER);
377890075Sobrien}
377990075Sobrien
378090075Sobrien/* Only accept reg, subreg(reg), const_int.  */
378190075Sobrienint
3782132718Skanreg_or_int_operand (rtx op, enum machine_mode mode)
378390075Sobrien{
378490075Sobrien  if (GET_CODE (op) == CONST_INT)
378590075Sobrien    return 1;
378690075Sobrien
378790075Sobrien  if (GET_MODE (op) != mode && mode != VOIDmode)
378890075Sobrien    return 0;
378990075Sobrien
379090075Sobrien  if (GET_CODE (op) == SUBREG)
379190075Sobrien    op = SUBREG_REG (op);
379290075Sobrien
379390075Sobrien  /* We don't consider registers whose class is NO_REGS
379490075Sobrien     to be a register operand.  */
379590075Sobrien  return (GET_CODE (op) == REG
379690075Sobrien	  && (REGNO (op) >= FIRST_PSEUDO_REGISTER
379790075Sobrien	      || REGNO_REG_CLASS (REGNO (op)) != NO_REGS));
379890075Sobrien}
379990075Sobrien
380090075Sobrien/* Return 1 if OP is an item in memory, given that we are in reload.  */
380190075Sobrienint
3802132718Skanarm_reload_memory_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
380390075Sobrien{
380490075Sobrien  int regno = true_regnum (op);
380590075Sobrien
380690075Sobrien  return (!CONSTANT_P (op)
380790075Sobrien	  && (regno == -1
380890075Sobrien	      || (GET_CODE (op) == REG
380990075Sobrien		  && REGNO (op) >= FIRST_PSEUDO_REGISTER)));
381090075Sobrien}
381190075Sobrien
381290075Sobrien/* Return 1 if OP is a valid memory address, but not valid for a signed byte
381390075Sobrien   memory access (architecture V4).
381490075Sobrien   MODE is QImode if called when computing constraints, or VOIDmode when
381590075Sobrien   emitting patterns.  In this latter case we cannot use memory_operand()
3816132718Skan   because it will fail on badly formed MEMs, which is precisely what we are
381790075Sobrien   trying to catch.  */
381890075Sobrienint
3819132718Skanbad_signed_byte_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
382090075Sobrien{
382190075Sobrien  if (GET_CODE (op) != MEM)
382290075Sobrien    return 0;
382390075Sobrien
382490075Sobrien  op = XEXP (op, 0);
382590075Sobrien
382690075Sobrien  /* A sum of anything more complex than reg + reg or reg + const is bad.  */
382790075Sobrien  if ((GET_CODE (op) == PLUS || GET_CODE (op) == MINUS)
382890075Sobrien      && (!s_register_operand (XEXP (op, 0), VOIDmode)
382990075Sobrien	  || (!s_register_operand (XEXP (op, 1), VOIDmode)
383090075Sobrien	      && GET_CODE (XEXP (op, 1)) != CONST_INT)))
383190075Sobrien    return 1;
383290075Sobrien
383390075Sobrien  /* Big constants are also bad.  */
383490075Sobrien  if (GET_CODE (op) == PLUS && GET_CODE (XEXP (op, 1)) == CONST_INT
383590075Sobrien      && (INTVAL (XEXP (op, 1)) > 0xff
383690075Sobrien	  || -INTVAL (XEXP (op, 1)) > 0xff))
383790075Sobrien    return 1;
383890075Sobrien
383990075Sobrien  /* Everything else is good, or can will automatically be made so.  */
384090075Sobrien  return 0;
384190075Sobrien}
384290075Sobrien
384390075Sobrien/* Return TRUE for valid operands for the rhs of an ARM instruction.  */
384490075Sobrienint
3845132718Skanarm_rhs_operand (rtx op, enum machine_mode mode)
384690075Sobrien{
384790075Sobrien  return (s_register_operand (op, mode)
384890075Sobrien	  || (GET_CODE (op) == CONST_INT && const_ok_for_arm (INTVAL (op))));
384990075Sobrien}
385090075Sobrien
385190075Sobrien/* Return TRUE for valid operands for the
385290075Sobrien   rhs of an ARM instruction, or a load.  */
385390075Sobrienint
3854132718Skanarm_rhsm_operand (rtx op, enum machine_mode mode)
385590075Sobrien{
385690075Sobrien  return (s_register_operand (op, mode)
385790075Sobrien	  || (GET_CODE (op) == CONST_INT && const_ok_for_arm (INTVAL (op)))
385890075Sobrien	  || memory_operand (op, mode));
385990075Sobrien}
386090075Sobrien
386190075Sobrien/* Return TRUE for valid operands for the rhs of an ARM instruction, or if a
386290075Sobrien   constant that is valid when negated.  */
386390075Sobrienint
3864132718Skanarm_add_operand (rtx op, enum machine_mode mode)
386590075Sobrien{
386690075Sobrien  if (TARGET_THUMB)
386790075Sobrien    return thumb_cmp_operand (op, mode);
386890075Sobrien
386990075Sobrien  return (s_register_operand (op, mode)
387090075Sobrien	  || (GET_CODE (op) == CONST_INT
387190075Sobrien	      && (const_ok_for_arm (INTVAL (op))
387290075Sobrien		  || const_ok_for_arm (-INTVAL (op)))));
387390075Sobrien}
387490075Sobrien
3875132718Skan/* Return TRUE for valid ARM constants (or when valid if negated).  */
387690075Sobrienint
3877132718Skanarm_addimm_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
387890075Sobrien{
3879132718Skan  return (GET_CODE (op) == CONST_INT
3880132718Skan	  && (const_ok_for_arm (INTVAL (op))
3881132718Skan	      || const_ok_for_arm (-INTVAL (op))));
3882132718Skan}
3883132718Skan
3884132718Skanint
3885132718Skanarm_not_operand (rtx op, enum machine_mode mode)
3886132718Skan{
388790075Sobrien  return (s_register_operand (op, mode)
388890075Sobrien	  || (GET_CODE (op) == CONST_INT
388990075Sobrien	      && (const_ok_for_arm (INTVAL (op))
389090075Sobrien		  || const_ok_for_arm (~INTVAL (op)))));
389190075Sobrien}
389290075Sobrien
389390075Sobrien/* Return TRUE if the operand is a memory reference which contains an
389490075Sobrien   offsettable address.  */
389590075Sobrienint
3896132718Skanoffsettable_memory_operand (rtx op, enum machine_mode mode)
389790075Sobrien{
389890075Sobrien  if (mode == VOIDmode)
389990075Sobrien    mode = GET_MODE (op);
390090075Sobrien
390190075Sobrien  return (mode == GET_MODE (op)
390290075Sobrien	  && GET_CODE (op) == MEM
390390075Sobrien	  && offsettable_address_p (reload_completed | reload_in_progress,
390490075Sobrien				    mode, XEXP (op, 0)));
390590075Sobrien}
390690075Sobrien
390790075Sobrien/* Return TRUE if the operand is a memory reference which is, or can be
390890075Sobrien   made word aligned by adjusting the offset.  */
390990075Sobrienint
3910132718Skanalignable_memory_operand (rtx op, enum machine_mode mode)
391190075Sobrien{
391290075Sobrien  rtx reg;
391390075Sobrien
391490075Sobrien  if (mode == VOIDmode)
391590075Sobrien    mode = GET_MODE (op);
391690075Sobrien
391790075Sobrien  if (mode != GET_MODE (op) || GET_CODE (op) != MEM)
391890075Sobrien    return 0;
391990075Sobrien
392090075Sobrien  op = XEXP (op, 0);
392190075Sobrien
392290075Sobrien  return ((GET_CODE (reg = op) == REG
392390075Sobrien	   || (GET_CODE (op) == SUBREG
392490075Sobrien	       && GET_CODE (reg = SUBREG_REG (op)) == REG)
392590075Sobrien	   || (GET_CODE (op) == PLUS
392690075Sobrien	       && GET_CODE (XEXP (op, 1)) == CONST_INT
392790075Sobrien	       && (GET_CODE (reg = XEXP (op, 0)) == REG
392890075Sobrien		   || (GET_CODE (XEXP (op, 0)) == SUBREG
392990075Sobrien		       && GET_CODE (reg = SUBREG_REG (XEXP (op, 0))) == REG))))
393090075Sobrien	  && REGNO_POINTER_ALIGN (REGNO (reg)) >= 32);
393190075Sobrien}
393290075Sobrien
393390075Sobrien/* Similar to s_register_operand, but does not allow hard integer
393490075Sobrien   registers.  */
393590075Sobrienint
3936132718Skanf_register_operand (rtx op, enum machine_mode mode)
393790075Sobrien{
393890075Sobrien  if (GET_MODE (op) != mode && mode != VOIDmode)
393990075Sobrien    return 0;
394090075Sobrien
394190075Sobrien  if (GET_CODE (op) == SUBREG)
394290075Sobrien    op = SUBREG_REG (op);
394390075Sobrien
394490075Sobrien  /* We don't consider registers whose class is NO_REGS
394590075Sobrien     to be a register operand.  */
394690075Sobrien  return (GET_CODE (op) == REG
394790075Sobrien	  && (REGNO (op) >= FIRST_PSEUDO_REGISTER
3948132718Skan	      || REGNO_REG_CLASS (REGNO (op)) == FPA_REGS));
394990075Sobrien}
395090075Sobrien
3951132718Skan/* Return TRUE for valid operands for the rhs of an FPA instruction.  */
395290075Sobrienint
3953132718Skanfpa_rhs_operand (rtx op, enum machine_mode mode)
395490075Sobrien{
395590075Sobrien  if (s_register_operand (op, mode))
395690075Sobrien    return TRUE;
395790075Sobrien
395890075Sobrien  if (GET_MODE (op) != mode && mode != VOIDmode)
395990075Sobrien    return FALSE;
396090075Sobrien
396190075Sobrien  if (GET_CODE (op) == CONST_DOUBLE)
3962132718Skan    return const_double_rtx_ok_for_fpa (op);
396390075Sobrien
396490075Sobrien  return FALSE;
396590075Sobrien}
396690075Sobrien
396790075Sobrienint
3968132718Skanfpa_add_operand (rtx op, enum machine_mode mode)
396990075Sobrien{
397090075Sobrien  if (s_register_operand (op, mode))
397190075Sobrien    return TRUE;
397290075Sobrien
397390075Sobrien  if (GET_MODE (op) != mode && mode != VOIDmode)
397490075Sobrien    return FALSE;
397590075Sobrien
397690075Sobrien  if (GET_CODE (op) == CONST_DOUBLE)
3977132718Skan    return (const_double_rtx_ok_for_fpa (op)
3978132718Skan	    || neg_const_double_rtx_ok_for_fpa (op));
397990075Sobrien
398090075Sobrien  return FALSE;
398190075Sobrien}
398290075Sobrien
3983132718Skan/* Return nonzero if OP is a valid Cirrus memory address pattern.  */
3984132718Skanint
3985132718Skancirrus_memory_offset (rtx op)
3986132718Skan{
3987132718Skan  /* Reject eliminable registers.  */
3988132718Skan  if (! (reload_in_progress || reload_completed)
3989132718Skan      && (   reg_mentioned_p (frame_pointer_rtx, op)
3990132718Skan	  || reg_mentioned_p (arg_pointer_rtx, op)
3991132718Skan	  || reg_mentioned_p (virtual_incoming_args_rtx, op)
3992132718Skan	  || reg_mentioned_p (virtual_outgoing_args_rtx, op)
3993132718Skan	  || reg_mentioned_p (virtual_stack_dynamic_rtx, op)
3994132718Skan	  || reg_mentioned_p (virtual_stack_vars_rtx, op)))
3995132718Skan    return 0;
399690075Sobrien
3997132718Skan  if (GET_CODE (op) == MEM)
3998132718Skan    {
3999132718Skan      rtx ind;
4000132718Skan
4001132718Skan      ind = XEXP (op, 0);
4002132718Skan
4003132718Skan      /* Match: (mem (reg)).  */
4004132718Skan      if (GET_CODE (ind) == REG)
4005132718Skan	return 1;
4006132718Skan
4007132718Skan      /* Match:
4008132718Skan	 (mem (plus (reg)
4009132718Skan	            (const))).  */
4010132718Skan      if (GET_CODE (ind) == PLUS
4011132718Skan	  && GET_CODE (XEXP (ind, 0)) == REG
4012132718Skan	  && REG_MODE_OK_FOR_BASE_P (XEXP (ind, 0), VOIDmode)
4013132718Skan	  && GET_CODE (XEXP (ind, 1)) == CONST_INT)
4014132718Skan	return 1;
4015132718Skan    }
4016132718Skan
4017132718Skan  return 0;
4018132718Skan}
4019132718Skan
4020132718Skan/* Return nonzero if OP is a Cirrus or general register.  */
402190075Sobrienint
4022132718Skancirrus_register_operand (rtx op, enum machine_mode mode)
402390075Sobrien{
4024132718Skan  if (GET_MODE (op) != mode && mode != VOIDmode)
4025132718Skan    return FALSE;
4026132718Skan
4027132718Skan  if (GET_CODE (op) == SUBREG)
4028132718Skan    op = SUBREG_REG (op);
4029132718Skan
4030132718Skan  return (GET_CODE (op) == REG
4031132718Skan	  && (REGNO_REG_CLASS (REGNO (op)) == CIRRUS_REGS
4032132718Skan	      || REGNO_REG_CLASS (REGNO (op)) == GENERAL_REGS));
4033132718Skan}
4034132718Skan
4035132718Skan/* Return nonzero if OP is a cirrus FP register.  */
4036132718Skanint
4037132718Skancirrus_fp_register (rtx op, enum machine_mode mode)
4038132718Skan{
4039132718Skan  if (GET_MODE (op) != mode && mode != VOIDmode)
4040132718Skan    return FALSE;
4041132718Skan
4042132718Skan  if (GET_CODE (op) == SUBREG)
4043132718Skan    op = SUBREG_REG (op);
4044132718Skan
4045132718Skan  return (GET_CODE (op) == REG
4046132718Skan	  && (REGNO (op) >= FIRST_PSEUDO_REGISTER
4047132718Skan	      || REGNO_REG_CLASS (REGNO (op)) == CIRRUS_REGS));
4048132718Skan}
4049132718Skan
4050132718Skan/* Return nonzero if OP is a 6bit constant (0..63).  */
4051132718Skanint
4052132718Skancirrus_shift_const (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
4053132718Skan{
4054132718Skan  return (GET_CODE (op) == CONST_INT
4055132718Skan	  && INTVAL (op) >= 0
4056132718Skan	  && INTVAL (op) < 64);
4057132718Skan}
4058132718Skan
4059146895Skan/* Return true if X is a register that will be eliminated later on.  */
4060146895Skanint
4061146895Skanarm_eliminable_register (rtx x)
4062146895Skan{
4063146895Skan  return REG_P (x) && (REGNO (x) == FRAME_POINTER_REGNUM
4064146895Skan		       || REGNO (x) == ARG_POINTER_REGNUM
4065146895Skan		       || (REGNO (x) >= FIRST_VIRTUAL_REGISTER
4066146895Skan			   && REGNO (x) <= LAST_VIRTUAL_REGISTER));
4067146895Skan}
4068146895Skan
4069132718Skan/* Returns TRUE if INSN is an "LDR REG, ADDR" instruction.
4070132718Skan   Use by the Cirrus Maverick code which has to workaround
4071132718Skan   a hardware bug triggered by such instructions.  */
4072132718Skanstatic bool
4073132718Skanarm_memory_load_p (rtx insn)
4074132718Skan{
4075132718Skan  rtx body, lhs, rhs;;
4076132718Skan
4077132718Skan  if (insn == NULL_RTX || GET_CODE (insn) != INSN)
4078132718Skan    return false;
4079132718Skan
4080132718Skan  body = PATTERN (insn);
4081132718Skan
4082132718Skan  if (GET_CODE (body) != SET)
4083132718Skan    return false;
4084132718Skan
4085132718Skan  lhs = XEXP (body, 0);
4086132718Skan  rhs = XEXP (body, 1);
4087132718Skan
4088132718Skan  lhs = REG_OR_SUBREG_RTX (lhs);
4089132718Skan
4090132718Skan  /* If the destination is not a general purpose
4091132718Skan     register we do not have to worry.  */
4092132718Skan  if (GET_CODE (lhs) != REG
4093132718Skan      || REGNO_REG_CLASS (REGNO (lhs)) != GENERAL_REGS)
4094132718Skan    return false;
4095132718Skan
4096132718Skan  /* As well as loads from memory we also have to react
4097132718Skan     to loads of invalid constants which will be turned
4098132718Skan     into loads from the minipool.  */
4099132718Skan  return (GET_CODE (rhs) == MEM
4100132718Skan	  || GET_CODE (rhs) == SYMBOL_REF
4101132718Skan	  || note_invalid_constants (insn, -1, false));
4102132718Skan}
4103132718Skan
4104132718Skan/* Return TRUE if INSN is a Cirrus instruction.  */
4105132718Skanstatic bool
4106132718Skanarm_cirrus_insn_p (rtx insn)
4107132718Skan{
4108132718Skan  enum attr_cirrus attr;
4109132718Skan
4110132718Skan  /* get_attr aborts on USE and CLOBBER.  */
4111132718Skan  if (!insn
4112132718Skan      || GET_CODE (insn) != INSN
4113132718Skan      || GET_CODE (PATTERN (insn)) == USE
4114132718Skan      || GET_CODE (PATTERN (insn)) == CLOBBER)
4115132718Skan    return 0;
4116132718Skan
4117132718Skan  attr = get_attr_cirrus (insn);
4118132718Skan
4119132718Skan  return attr != CIRRUS_NOT;
4120132718Skan}
4121132718Skan
4122132718Skan/* Cirrus reorg for invalid instruction combinations.  */
4123132718Skanstatic void
4124132718Skancirrus_reorg (rtx first)
4125132718Skan{
4126132718Skan  enum attr_cirrus attr;
4127132718Skan  rtx body = PATTERN (first);
4128132718Skan  rtx t;
4129132718Skan  int nops;
4130132718Skan
4131132718Skan  /* Any branch must be followed by 2 non Cirrus instructions.  */
4132132718Skan  if (GET_CODE (first) == JUMP_INSN && GET_CODE (body) != RETURN)
4133132718Skan    {
4134132718Skan      nops = 0;
4135132718Skan      t = next_nonnote_insn (first);
4136132718Skan
4137132718Skan      if (arm_cirrus_insn_p (t))
4138132718Skan	++ nops;
4139132718Skan
4140132718Skan      if (arm_cirrus_insn_p (next_nonnote_insn (t)))
4141132718Skan	++ nops;
4142132718Skan
4143132718Skan      while (nops --)
4144132718Skan	emit_insn_after (gen_nop (), first);
4145132718Skan
4146132718Skan      return;
4147132718Skan    }
4148132718Skan
4149132718Skan  /* (float (blah)) is in parallel with a clobber.  */
4150132718Skan  if (GET_CODE (body) == PARALLEL && XVECLEN (body, 0) > 0)
4151132718Skan    body = XVECEXP (body, 0, 0);
4152132718Skan
4153132718Skan  if (GET_CODE (body) == SET)
4154132718Skan    {
4155132718Skan      rtx lhs = XEXP (body, 0), rhs = XEXP (body, 1);
4156132718Skan
4157132718Skan      /* cfldrd, cfldr64, cfstrd, cfstr64 must
4158132718Skan	 be followed by a non Cirrus insn.  */
4159132718Skan      if (get_attr_cirrus (first) == CIRRUS_DOUBLE)
4160132718Skan	{
4161132718Skan	  if (arm_cirrus_insn_p (next_nonnote_insn (first)))
4162132718Skan	    emit_insn_after (gen_nop (), first);
4163132718Skan
4164132718Skan	  return;
4165132718Skan	}
4166132718Skan      else if (arm_memory_load_p (first))
4167132718Skan	{
4168132718Skan	  unsigned int arm_regno;
4169132718Skan
4170132718Skan	  /* Any ldr/cfmvdlr, ldr/cfmvdhr, ldr/cfmvsr, ldr/cfmv64lr,
4171132718Skan	     ldr/cfmv64hr combination where the Rd field is the same
4172132718Skan	     in both instructions must be split with a non Cirrus
4173132718Skan	     insn.  Example:
4174132718Skan
4175132718Skan	     ldr r0, blah
4176132718Skan	     nop
4177132718Skan	     cfmvsr mvf0, r0.  */
4178132718Skan
4179132718Skan	  /* Get Arm register number for ldr insn.  */
4180132718Skan	  if (GET_CODE (lhs) == REG)
4181132718Skan	    arm_regno = REGNO (lhs);
4182132718Skan	  else if (GET_CODE (rhs) == REG)
4183132718Skan	    arm_regno = REGNO (rhs);
4184132718Skan	  else
4185132718Skan	    abort ();
4186132718Skan
4187132718Skan	  /* Next insn.  */
4188132718Skan	  first = next_nonnote_insn (first);
4189132718Skan
4190132718Skan	  if (! arm_cirrus_insn_p (first))
4191132718Skan	    return;
4192132718Skan
4193132718Skan	  body = PATTERN (first);
4194132718Skan
4195132718Skan          /* (float (blah)) is in parallel with a clobber.  */
4196132718Skan          if (GET_CODE (body) == PARALLEL && XVECLEN (body, 0))
4197132718Skan	    body = XVECEXP (body, 0, 0);
4198132718Skan
4199132718Skan	  if (GET_CODE (body) == FLOAT)
4200132718Skan	    body = XEXP (body, 0);
4201132718Skan
4202132718Skan	  if (get_attr_cirrus (first) == CIRRUS_MOVE
4203132718Skan	      && GET_CODE (XEXP (body, 1)) == REG
4204132718Skan	      && arm_regno == REGNO (XEXP (body, 1)))
4205132718Skan	    emit_insn_after (gen_nop (), first);
4206132718Skan
4207132718Skan	  return;
4208132718Skan	}
4209132718Skan    }
4210132718Skan
4211132718Skan  /* get_attr aborts on USE and CLOBBER.  */
4212132718Skan  if (!first
4213132718Skan      || GET_CODE (first) != INSN
4214132718Skan      || GET_CODE (PATTERN (first)) == USE
4215132718Skan      || GET_CODE (PATTERN (first)) == CLOBBER)
4216132718Skan    return;
4217132718Skan
4218132718Skan  attr = get_attr_cirrus (first);
4219132718Skan
4220132718Skan  /* Any coprocessor compare instruction (cfcmps, cfcmpd, ...)
4221132718Skan     must be followed by a non-coprocessor instruction.  */
4222132718Skan  if (attr == CIRRUS_COMPARE)
4223132718Skan    {
4224132718Skan      nops = 0;
4225132718Skan
4226132718Skan      t = next_nonnote_insn (first);
4227132718Skan
4228132718Skan      if (arm_cirrus_insn_p (t))
4229132718Skan	++ nops;
4230132718Skan
4231132718Skan      if (arm_cirrus_insn_p (next_nonnote_insn (t)))
4232132718Skan	++ nops;
4233132718Skan
4234132718Skan      while (nops --)
4235132718Skan	emit_insn_after (gen_nop (), first);
4236132718Skan
4237132718Skan      return;
4238132718Skan    }
4239132718Skan}
4240132718Skan
4241132718Skan/* Return nonzero if OP is a constant power of two.  */
4242132718Skanint
4243132718Skanpower_of_two_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
4244132718Skan{
424590075Sobrien  if (GET_CODE (op) == CONST_INT)
424690075Sobrien    {
424790075Sobrien      HOST_WIDE_INT value = INTVAL (op);
424890075Sobrien
424990075Sobrien      return value != 0  &&  (value & (value - 1)) == 0;
425090075Sobrien    }
425190075Sobrien
425290075Sobrien  return FALSE;
425390075Sobrien}
425490075Sobrien
425590075Sobrien/* Return TRUE for a valid operand of a DImode operation.
425690075Sobrien   Either: REG, SUBREG, CONST_DOUBLE or MEM(DImode_address).
425790075Sobrien   Note that this disallows MEM(REG+REG), but allows
425890075Sobrien   MEM(PRE/POST_INC/DEC(REG)).  */
425990075Sobrienint
4260132718Skandi_operand (rtx op, enum machine_mode mode)
426190075Sobrien{
426290075Sobrien  if (s_register_operand (op, mode))
426390075Sobrien    return TRUE;
426490075Sobrien
426590075Sobrien  if (mode != VOIDmode && GET_MODE (op) != VOIDmode && GET_MODE (op) != DImode)
426690075Sobrien    return FALSE;
426790075Sobrien
426890075Sobrien  if (GET_CODE (op) == SUBREG)
426990075Sobrien    op = SUBREG_REG (op);
427090075Sobrien
427190075Sobrien  switch (GET_CODE (op))
427290075Sobrien    {
427390075Sobrien    case CONST_DOUBLE:
427490075Sobrien    case CONST_INT:
427590075Sobrien      return TRUE;
427690075Sobrien
427790075Sobrien    case MEM:
427890075Sobrien      return memory_address_p (DImode, XEXP (op, 0));
427990075Sobrien
428090075Sobrien    default:
428190075Sobrien      return FALSE;
428290075Sobrien    }
428390075Sobrien}
428490075Sobrien
428590075Sobrien/* Like di_operand, but don't accept constants.  */
428690075Sobrienint
4287132718Skannonimmediate_di_operand (rtx op, enum machine_mode mode)
428890075Sobrien{
428990075Sobrien  if (s_register_operand (op, mode))
429090075Sobrien    return TRUE;
429190075Sobrien
429290075Sobrien  if (mode != VOIDmode && GET_MODE (op) != VOIDmode && GET_MODE (op) != DImode)
429390075Sobrien    return FALSE;
429490075Sobrien
429590075Sobrien  if (GET_CODE (op) == SUBREG)
429690075Sobrien    op = SUBREG_REG (op);
429790075Sobrien
429890075Sobrien  if (GET_CODE (op) == MEM)
429990075Sobrien    return memory_address_p (DImode, XEXP (op, 0));
430090075Sobrien
430190075Sobrien  return FALSE;
430290075Sobrien}
430390075Sobrien
430490075Sobrien/* Return TRUE for a valid operand of a DFmode operation when -msoft-float.
430590075Sobrien   Either: REG, SUBREG, CONST_DOUBLE or MEM(DImode_address).
430690075Sobrien   Note that this disallows MEM(REG+REG), but allows
430790075Sobrien   MEM(PRE/POST_INC/DEC(REG)).  */
430890075Sobrienint
4309132718Skansoft_df_operand (rtx op, enum machine_mode mode)
431090075Sobrien{
431190075Sobrien  if (s_register_operand (op, mode))
431290075Sobrien    return TRUE;
431390075Sobrien
431490075Sobrien  if (mode != VOIDmode && GET_MODE (op) != mode)
431590075Sobrien    return FALSE;
431690075Sobrien
431790075Sobrien  if (GET_CODE (op) == SUBREG && CONSTANT_P (SUBREG_REG (op)))
431890075Sobrien    return FALSE;
431990075Sobrien
432090075Sobrien  if (GET_CODE (op) == SUBREG)
432190075Sobrien    op = SUBREG_REG (op);
432290075Sobrien
432390075Sobrien  switch (GET_CODE (op))
432490075Sobrien    {
432590075Sobrien    case CONST_DOUBLE:
432690075Sobrien      return TRUE;
432790075Sobrien
432890075Sobrien    case MEM:
432990075Sobrien      return memory_address_p (DFmode, XEXP (op, 0));
433090075Sobrien
433190075Sobrien    default:
433290075Sobrien      return FALSE;
433390075Sobrien    }
433490075Sobrien}
433590075Sobrien
433690075Sobrien/* Like soft_df_operand, but don't accept constants.  */
433790075Sobrienint
4338132718Skannonimmediate_soft_df_operand (rtx op, enum machine_mode mode)
433990075Sobrien{
434090075Sobrien  if (s_register_operand (op, mode))
434190075Sobrien    return TRUE;
434290075Sobrien
434390075Sobrien  if (mode != VOIDmode && GET_MODE (op) != mode)
434490075Sobrien    return FALSE;
434590075Sobrien
434690075Sobrien  if (GET_CODE (op) == SUBREG)
434790075Sobrien    op = SUBREG_REG (op);
434890075Sobrien
434990075Sobrien  if (GET_CODE (op) == MEM)
435090075Sobrien    return memory_address_p (DFmode, XEXP (op, 0));
435190075Sobrien  return FALSE;
435290075Sobrien}
435390075Sobrien
435490075Sobrien/* Return TRUE for valid index operands.  */
435590075Sobrienint
4356132718Skanindex_operand (rtx op, enum machine_mode mode)
435790075Sobrien{
435890075Sobrien  return (s_register_operand (op, mode)
435990075Sobrien	  || (immediate_operand (op, mode)
436090075Sobrien	      && (GET_CODE (op) != CONST_INT
436190075Sobrien		  || (INTVAL (op) < 4096 && INTVAL (op) > -4096))));
436290075Sobrien}
436390075Sobrien
436490075Sobrien/* Return TRUE for valid shifts by a constant. This also accepts any
436590075Sobrien   power of two on the (somewhat overly relaxed) assumption that the
436690075Sobrien   shift operator in this case was a mult.  */
436790075Sobrienint
4368132718Skanconst_shift_operand (rtx op, enum machine_mode mode)
436990075Sobrien{
437090075Sobrien  return (power_of_two_operand (op, mode)
437190075Sobrien	  || (immediate_operand (op, mode)
437290075Sobrien	      && (GET_CODE (op) != CONST_INT
437390075Sobrien		  || (INTVAL (op) < 32 && INTVAL (op) > 0))));
437490075Sobrien}
437590075Sobrien
437690075Sobrien/* Return TRUE for arithmetic operators which can be combined with a multiply
437790075Sobrien   (shift).  */
437890075Sobrienint
4379132718Skanshiftable_operator (rtx x, enum machine_mode mode)
438090075Sobrien{
438190075Sobrien  enum rtx_code code;
438290075Sobrien
438390075Sobrien  if (GET_MODE (x) != mode)
438490075Sobrien    return FALSE;
438590075Sobrien
438690075Sobrien  code = GET_CODE (x);
438790075Sobrien
438890075Sobrien  return (code == PLUS || code == MINUS
438990075Sobrien	  || code == IOR || code == XOR || code == AND);
439090075Sobrien}
439190075Sobrien
439290075Sobrien/* Return TRUE for binary logical operators.  */
439390075Sobrienint
4394132718Skanlogical_binary_operator (rtx x, enum machine_mode mode)
439590075Sobrien{
439690075Sobrien  enum rtx_code code;
439790075Sobrien
439890075Sobrien  if (GET_MODE (x) != mode)
439990075Sobrien    return FALSE;
440090075Sobrien
440190075Sobrien  code = GET_CODE (x);
440290075Sobrien
440390075Sobrien  return (code == IOR || code == XOR || code == AND);
440490075Sobrien}
440590075Sobrien
440690075Sobrien/* Return TRUE for shift operators.  */
440790075Sobrienint
4408132718Skanshift_operator (rtx x,enum machine_mode mode)
440990075Sobrien{
441090075Sobrien  enum rtx_code code;
441190075Sobrien
441290075Sobrien  if (GET_MODE (x) != mode)
441390075Sobrien    return FALSE;
441490075Sobrien
441590075Sobrien  code = GET_CODE (x);
441690075Sobrien
441790075Sobrien  if (code == MULT)
441890075Sobrien    return power_of_two_operand (XEXP (x, 1), mode);
441990075Sobrien
442090075Sobrien  return (code == ASHIFT || code == ASHIFTRT || code == LSHIFTRT
442190075Sobrien	  || code == ROTATERT);
442290075Sobrien}
442390075Sobrien
442490075Sobrien/* Return TRUE if x is EQ or NE.  */
442590075Sobrienint
4426132718Skanequality_operator (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
442790075Sobrien{
442890075Sobrien  return GET_CODE (x) == EQ || GET_CODE (x) == NE;
442990075Sobrien}
443090075Sobrien
443190075Sobrien/* Return TRUE if x is a comparison operator other than LTGT or UNEQ.  */
443290075Sobrienint
4433132718Skanarm_comparison_operator (rtx x, enum machine_mode mode)
443490075Sobrien{
443590075Sobrien  return (comparison_operator (x, mode)
443690075Sobrien	  && GET_CODE (x) != LTGT
443790075Sobrien	  && GET_CODE (x) != UNEQ);
443890075Sobrien}
443990075Sobrien
444090075Sobrien/* Return TRUE for SMIN SMAX UMIN UMAX operators.  */
444190075Sobrienint
4442132718Skanminmax_operator (rtx x, enum machine_mode mode)
444390075Sobrien{
444490075Sobrien  enum rtx_code code = GET_CODE (x);
444590075Sobrien
444690075Sobrien  if (GET_MODE (x) != mode)
444790075Sobrien    return FALSE;
444890075Sobrien
444990075Sobrien  return code == SMIN || code == SMAX || code == UMIN || code == UMAX;
445090075Sobrien}
445190075Sobrien
445290075Sobrien/* Return TRUE if this is the condition code register, if we aren't given
445390075Sobrien   a mode, accept any class CCmode register.  */
445490075Sobrienint
4455132718Skancc_register (rtx x, enum machine_mode mode)
445690075Sobrien{
445790075Sobrien  if (mode == VOIDmode)
445890075Sobrien    {
445990075Sobrien      mode = GET_MODE (x);
446090075Sobrien
446190075Sobrien      if (GET_MODE_CLASS (mode) != MODE_CC)
446290075Sobrien	return FALSE;
446390075Sobrien    }
446490075Sobrien
446590075Sobrien  if (   GET_MODE (x) == mode
446690075Sobrien      && GET_CODE (x) == REG
446790075Sobrien      && REGNO    (x) == CC_REGNUM)
446890075Sobrien    return TRUE;
446990075Sobrien
447090075Sobrien  return FALSE;
447190075Sobrien}
447290075Sobrien
447390075Sobrien/* Return TRUE if this is the condition code register, if we aren't given
447490075Sobrien   a mode, accept any class CCmode register which indicates a dominance
447590075Sobrien   expression.  */
447690075Sobrienint
4477132718Skandominant_cc_register (rtx x, enum machine_mode mode)
447890075Sobrien{
447990075Sobrien  if (mode == VOIDmode)
448090075Sobrien    {
448190075Sobrien      mode = GET_MODE (x);
448290075Sobrien
448390075Sobrien      if (GET_MODE_CLASS (mode) != MODE_CC)
448490075Sobrien	return FALSE;
448590075Sobrien    }
448690075Sobrien
4487132718Skan  if (mode != CC_DNEmode && mode != CC_DEQmode
448890075Sobrien      && mode != CC_DLEmode && mode != CC_DLTmode
448990075Sobrien      && mode != CC_DGEmode && mode != CC_DGTmode
449090075Sobrien      && mode != CC_DLEUmode && mode != CC_DLTUmode
449190075Sobrien      && mode != CC_DGEUmode && mode != CC_DGTUmode)
449290075Sobrien    return FALSE;
449390075Sobrien
449490075Sobrien  return cc_register (x, mode);
449590075Sobrien}
449690075Sobrien
449790075Sobrien/* Return TRUE if X references a SYMBOL_REF.  */
449890075Sobrienint
4499132718Skansymbol_mentioned_p (rtx x)
450090075Sobrien{
450190075Sobrien  const char * fmt;
450290075Sobrien  int i;
450390075Sobrien
450490075Sobrien  if (GET_CODE (x) == SYMBOL_REF)
450590075Sobrien    return 1;
450690075Sobrien
450790075Sobrien  fmt = GET_RTX_FORMAT (GET_CODE (x));
450890075Sobrien
450990075Sobrien  for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
451090075Sobrien    {
451190075Sobrien      if (fmt[i] == 'E')
451290075Sobrien	{
451390075Sobrien	  int j;
451490075Sobrien
451590075Sobrien	  for (j = XVECLEN (x, i) - 1; j >= 0; j--)
451690075Sobrien	    if (symbol_mentioned_p (XVECEXP (x, i, j)))
451790075Sobrien	      return 1;
451890075Sobrien	}
451990075Sobrien      else if (fmt[i] == 'e' && symbol_mentioned_p (XEXP (x, i)))
452090075Sobrien	return 1;
452190075Sobrien    }
452290075Sobrien
452390075Sobrien  return 0;
452490075Sobrien}
452590075Sobrien
452690075Sobrien/* Return TRUE if X references a LABEL_REF.  */
452790075Sobrienint
4528132718Skanlabel_mentioned_p (rtx x)
452990075Sobrien{
453090075Sobrien  const char * fmt;
453190075Sobrien  int i;
453290075Sobrien
453390075Sobrien  if (GET_CODE (x) == LABEL_REF)
453490075Sobrien    return 1;
453590075Sobrien
453690075Sobrien  fmt = GET_RTX_FORMAT (GET_CODE (x));
453790075Sobrien  for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
453890075Sobrien    {
453990075Sobrien      if (fmt[i] == 'E')
454090075Sobrien	{
454190075Sobrien	  int j;
454290075Sobrien
454390075Sobrien	  for (j = XVECLEN (x, i) - 1; j >= 0; j--)
454490075Sobrien	    if (label_mentioned_p (XVECEXP (x, i, j)))
454590075Sobrien	      return 1;
454690075Sobrien	}
454790075Sobrien      else if (fmt[i] == 'e' && label_mentioned_p (XEXP (x, i)))
454890075Sobrien	return 1;
454990075Sobrien    }
455090075Sobrien
455190075Sobrien  return 0;
455290075Sobrien}
455390075Sobrien
455490075Sobrienenum rtx_code
4555132718Skanminmax_code (rtx x)
455690075Sobrien{
455790075Sobrien  enum rtx_code code = GET_CODE (x);
455890075Sobrien
455990075Sobrien  if (code == SMAX)
456090075Sobrien    return GE;
456190075Sobrien  else if (code == SMIN)
456290075Sobrien    return LE;
456390075Sobrien  else if (code == UMIN)
456490075Sobrien    return LEU;
456590075Sobrien  else if (code == UMAX)
456690075Sobrien    return GEU;
456790075Sobrien
456890075Sobrien  abort ();
456990075Sobrien}
457090075Sobrien
457190075Sobrien/* Return 1 if memory locations are adjacent.  */
457290075Sobrienint
4573132718Skanadjacent_mem_locations (rtx a, rtx b)
457490075Sobrien{
457590075Sobrien  if ((GET_CODE (XEXP (a, 0)) == REG
457690075Sobrien       || (GET_CODE (XEXP (a, 0)) == PLUS
457790075Sobrien	   && GET_CODE (XEXP (XEXP (a, 0), 1)) == CONST_INT))
457890075Sobrien      && (GET_CODE (XEXP (b, 0)) == REG
457990075Sobrien	  || (GET_CODE (XEXP (b, 0)) == PLUS
458090075Sobrien	      && GET_CODE (XEXP (XEXP (b, 0), 1)) == CONST_INT)))
458190075Sobrien    {
4582146895Skan      HOST_WIDE_INT val0 = 0, val1 = 0;
4583146895Skan      rtx reg0, reg1;
4584146895Skan      int val_diff;
4585146895Skan
458690075Sobrien      if (GET_CODE (XEXP (a, 0)) == PLUS)
458790075Sobrien        {
4588146895Skan	  reg0 = XEXP (XEXP (a, 0), 0);
458990075Sobrien	  val0 = INTVAL (XEXP (XEXP (a, 0), 1));
459090075Sobrien        }
459190075Sobrien      else
4592146895Skan	reg0 = XEXP (a, 0);
459390075Sobrien
459490075Sobrien      if (GET_CODE (XEXP (b, 0)) == PLUS)
459590075Sobrien        {
4596146895Skan	  reg1 = XEXP (XEXP (b, 0), 0);
459790075Sobrien	  val1 = INTVAL (XEXP (XEXP (b, 0), 1));
459890075Sobrien        }
459990075Sobrien      else
4600146895Skan	reg1 = XEXP (b, 0);
460190075Sobrien
4602132718Skan      /* Don't accept any offset that will require multiple
4603132718Skan	 instructions to handle, since this would cause the
4604132718Skan	 arith_adjacentmem pattern to output an overlong sequence.  */
4605132718Skan      if (!const_ok_for_op (PLUS, val0) || !const_ok_for_op (PLUS, val1))
4606132718Skan	return 0;
4607146895Skan
4608146895Skan      /* Don't allow an eliminable register: register elimination can make
4609146895Skan	 the offset too large.  */
4610146895Skan      if (arm_eliminable_register (reg0))
4611146895Skan	return 0;
4612146895Skan
4613146895Skan      val_diff = val1 - val0;
4614146895Skan      return ((REGNO (reg0) == REGNO (reg1))
4615146895Skan	      && (val_diff == 4 || val_diff == -4));
461690075Sobrien    }
4617146895Skan
461890075Sobrien  return 0;
461990075Sobrien}
462090075Sobrien
462190075Sobrien/* Return 1 if OP is a load multiple operation.  It is known to be
462290075Sobrien   parallel and the first section will be tested.  */
462390075Sobrienint
4624132718Skanload_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
462590075Sobrien{
462690075Sobrien  HOST_WIDE_INT count = XVECLEN (op, 0);
462790075Sobrien  int dest_regno;
462890075Sobrien  rtx src_addr;
462990075Sobrien  HOST_WIDE_INT i = 1, base = 0;
463090075Sobrien  rtx elt;
463190075Sobrien
463290075Sobrien  if (count <= 1
463390075Sobrien      || GET_CODE (XVECEXP (op, 0, 0)) != SET)
463490075Sobrien    return 0;
463590075Sobrien
463690075Sobrien  /* Check to see if this might be a write-back.  */
463790075Sobrien  if (GET_CODE (SET_SRC (elt = XVECEXP (op, 0, 0))) == PLUS)
463890075Sobrien    {
463990075Sobrien      i++;
464090075Sobrien      base = 1;
464190075Sobrien
464290075Sobrien      /* Now check it more carefully.  */
464390075Sobrien      if (GET_CODE (SET_DEST (elt)) != REG
464490075Sobrien          || GET_CODE (XEXP (SET_SRC (elt), 0)) != REG
464590075Sobrien          || GET_CODE (XEXP (SET_SRC (elt), 1)) != CONST_INT
464690075Sobrien          || INTVAL (XEXP (SET_SRC (elt), 1)) != (count - 1) * 4)
464790075Sobrien        return 0;
464890075Sobrien    }
464990075Sobrien
465090075Sobrien  /* Perform a quick check so we don't blow up below.  */
465190075Sobrien  if (count <= i
465290075Sobrien      || GET_CODE (XVECEXP (op, 0, i - 1)) != SET
465390075Sobrien      || GET_CODE (SET_DEST (XVECEXP (op, 0, i - 1))) != REG
465490075Sobrien      || GET_CODE (SET_SRC (XVECEXP (op, 0, i - 1))) != MEM)
465590075Sobrien    return 0;
465690075Sobrien
465790075Sobrien  dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, i - 1)));
465890075Sobrien  src_addr = XEXP (SET_SRC (XVECEXP (op, 0, i - 1)), 0);
465990075Sobrien
466090075Sobrien  for (; i < count; i++)
466190075Sobrien    {
466290075Sobrien      elt = XVECEXP (op, 0, i);
466390075Sobrien
466490075Sobrien      if (GET_CODE (elt) != SET
466590075Sobrien          || GET_CODE (SET_DEST (elt)) != REG
466690075Sobrien          || GET_MODE (SET_DEST (elt)) != SImode
466790075Sobrien          || REGNO (SET_DEST (elt)) != (unsigned int)(dest_regno + i - base)
466890075Sobrien          || GET_CODE (SET_SRC (elt)) != MEM
466990075Sobrien          || GET_MODE (SET_SRC (elt)) != SImode
467090075Sobrien          || GET_CODE (XEXP (SET_SRC (elt), 0)) != PLUS
467190075Sobrien          || !rtx_equal_p (XEXP (XEXP (SET_SRC (elt), 0), 0), src_addr)
467290075Sobrien          || GET_CODE (XEXP (XEXP (SET_SRC (elt), 0), 1)) != CONST_INT
467390075Sobrien          || INTVAL (XEXP (XEXP (SET_SRC (elt), 0), 1)) != (i - base) * 4)
467490075Sobrien        return 0;
467590075Sobrien    }
467690075Sobrien
467790075Sobrien  return 1;
467890075Sobrien}
467990075Sobrien
468090075Sobrien/* Return 1 if OP is a store multiple operation.  It is known to be
468190075Sobrien   parallel and the first section will be tested.  */
468290075Sobrienint
4683132718Skanstore_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
468490075Sobrien{
468590075Sobrien  HOST_WIDE_INT count = XVECLEN (op, 0);
468690075Sobrien  int src_regno;
468790075Sobrien  rtx dest_addr;
468890075Sobrien  HOST_WIDE_INT i = 1, base = 0;
468990075Sobrien  rtx elt;
469090075Sobrien
469190075Sobrien  if (count <= 1
469290075Sobrien      || GET_CODE (XVECEXP (op, 0, 0)) != SET)
469390075Sobrien    return 0;
469490075Sobrien
469590075Sobrien  /* Check to see if this might be a write-back.  */
469690075Sobrien  if (GET_CODE (SET_SRC (elt = XVECEXP (op, 0, 0))) == PLUS)
469790075Sobrien    {
469890075Sobrien      i++;
469990075Sobrien      base = 1;
470090075Sobrien
470190075Sobrien      /* Now check it more carefully.  */
470290075Sobrien      if (GET_CODE (SET_DEST (elt)) != REG
470390075Sobrien          || GET_CODE (XEXP (SET_SRC (elt), 0)) != REG
470490075Sobrien          || GET_CODE (XEXP (SET_SRC (elt), 1)) != CONST_INT
470590075Sobrien          || INTVAL (XEXP (SET_SRC (elt), 1)) != (count - 1) * 4)
470690075Sobrien        return 0;
470790075Sobrien    }
470890075Sobrien
470990075Sobrien  /* Perform a quick check so we don't blow up below.  */
471090075Sobrien  if (count <= i
471190075Sobrien      || GET_CODE (XVECEXP (op, 0, i - 1)) != SET
471290075Sobrien      || GET_CODE (SET_DEST (XVECEXP (op, 0, i - 1))) != MEM
471390075Sobrien      || GET_CODE (SET_SRC (XVECEXP (op, 0, i - 1))) != REG)
471490075Sobrien    return 0;
471590075Sobrien
471690075Sobrien  src_regno = REGNO (SET_SRC (XVECEXP (op, 0, i - 1)));
471790075Sobrien  dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, i - 1)), 0);
471890075Sobrien
471990075Sobrien  for (; i < count; i++)
472090075Sobrien    {
472190075Sobrien      elt = XVECEXP (op, 0, i);
472290075Sobrien
472390075Sobrien      if (GET_CODE (elt) != SET
472490075Sobrien          || GET_CODE (SET_SRC (elt)) != REG
472590075Sobrien          || GET_MODE (SET_SRC (elt)) != SImode
472690075Sobrien          || REGNO (SET_SRC (elt)) != (unsigned int)(src_regno + i - base)
472790075Sobrien          || GET_CODE (SET_DEST (elt)) != MEM
472890075Sobrien          || GET_MODE (SET_DEST (elt)) != SImode
472990075Sobrien          || GET_CODE (XEXP (SET_DEST (elt), 0)) != PLUS
473090075Sobrien          || !rtx_equal_p (XEXP (XEXP (SET_DEST (elt), 0), 0), dest_addr)
473190075Sobrien          || GET_CODE (XEXP (XEXP (SET_DEST (elt), 0), 1)) != CONST_INT
473290075Sobrien          || INTVAL (XEXP (XEXP (SET_DEST (elt), 0), 1)) != (i - base) * 4)
473390075Sobrien        return 0;
473490075Sobrien    }
473590075Sobrien
473690075Sobrien  return 1;
473790075Sobrien}
473890075Sobrien
473990075Sobrienint
4740132718Skanload_multiple_sequence (rtx *operands, int nops, int *regs, int *base,
4741132718Skan			HOST_WIDE_INT *load_offset)
474290075Sobrien{
474390075Sobrien  int unsorted_regs[4];
474490075Sobrien  HOST_WIDE_INT unsorted_offsets[4];
474590075Sobrien  int order[4];
474690075Sobrien  int base_reg = -1;
474790075Sobrien  int i;
474890075Sobrien
474990075Sobrien  /* Can only handle 2, 3, or 4 insns at present,
475090075Sobrien     though could be easily extended if required.  */
475190075Sobrien  if (nops < 2 || nops > 4)
475290075Sobrien    abort ();
475390075Sobrien
475490075Sobrien  /* Loop over the operands and check that the memory references are
475590075Sobrien     suitable (ie immediate offsets from the same base register).  At
475690075Sobrien     the same time, extract the target register, and the memory
475790075Sobrien     offsets.  */
475890075Sobrien  for (i = 0; i < nops; i++)
475990075Sobrien    {
476090075Sobrien      rtx reg;
476190075Sobrien      rtx offset;
476290075Sobrien
476390075Sobrien      /* Convert a subreg of a mem into the mem itself.  */
476490075Sobrien      if (GET_CODE (operands[nops + i]) == SUBREG)
476590075Sobrien	operands[nops + i] = alter_subreg (operands + (nops + i));
476690075Sobrien
476790075Sobrien      if (GET_CODE (operands[nops + i]) != MEM)
476890075Sobrien	abort ();
476990075Sobrien
477090075Sobrien      /* Don't reorder volatile memory references; it doesn't seem worth
477190075Sobrien	 looking for the case where the order is ok anyway.  */
477290075Sobrien      if (MEM_VOLATILE_P (operands[nops + i]))
477390075Sobrien	return 0;
477490075Sobrien
477590075Sobrien      offset = const0_rtx;
477690075Sobrien
477790075Sobrien      if ((GET_CODE (reg = XEXP (operands[nops + i], 0)) == REG
477890075Sobrien	   || (GET_CODE (reg) == SUBREG
477990075Sobrien	       && GET_CODE (reg = SUBREG_REG (reg)) == REG))
478090075Sobrien	  || (GET_CODE (XEXP (operands[nops + i], 0)) == PLUS
478190075Sobrien	      && ((GET_CODE (reg = XEXP (XEXP (operands[nops + i], 0), 0))
478290075Sobrien		   == REG)
478390075Sobrien		  || (GET_CODE (reg) == SUBREG
478490075Sobrien		      && GET_CODE (reg = SUBREG_REG (reg)) == REG))
478590075Sobrien	      && (GET_CODE (offset = XEXP (XEXP (operands[nops + i], 0), 1))
478690075Sobrien		  == CONST_INT)))
478790075Sobrien	{
478890075Sobrien	  if (i == 0)
478990075Sobrien	    {
479090075Sobrien	      base_reg = REGNO (reg);
479190075Sobrien	      unsorted_regs[0] = (GET_CODE (operands[i]) == REG
479290075Sobrien				  ? REGNO (operands[i])
479390075Sobrien				  : REGNO (SUBREG_REG (operands[i])));
479490075Sobrien	      order[0] = 0;
479590075Sobrien	    }
479690075Sobrien	  else
479790075Sobrien	    {
479890075Sobrien	      if (base_reg != (int) REGNO (reg))
479990075Sobrien		/* Not addressed from the same base register.  */
480090075Sobrien		return 0;
480190075Sobrien
480290075Sobrien	      unsorted_regs[i] = (GET_CODE (operands[i]) == REG
480390075Sobrien				  ? REGNO (operands[i])
480490075Sobrien				  : REGNO (SUBREG_REG (operands[i])));
480590075Sobrien	      if (unsorted_regs[i] < unsorted_regs[order[0]])
480690075Sobrien		order[0] = i;
480790075Sobrien	    }
480890075Sobrien
480990075Sobrien	  /* If it isn't an integer register, or if it overwrites the
481090075Sobrien	     base register but isn't the last insn in the list, then
481190075Sobrien	     we can't do this.  */
481290075Sobrien	  if (unsorted_regs[i] < 0 || unsorted_regs[i] > 14
481390075Sobrien	      || (i != nops - 1 && unsorted_regs[i] == base_reg))
481490075Sobrien	    return 0;
481590075Sobrien
481690075Sobrien	  unsorted_offsets[i] = INTVAL (offset);
481790075Sobrien	}
481890075Sobrien      else
481990075Sobrien	/* Not a suitable memory address.  */
482090075Sobrien	return 0;
482190075Sobrien    }
482290075Sobrien
482390075Sobrien  /* All the useful information has now been extracted from the
482490075Sobrien     operands into unsorted_regs and unsorted_offsets; additionally,
482590075Sobrien     order[0] has been set to the lowest numbered register in the
482690075Sobrien     list.  Sort the registers into order, and check that the memory
482790075Sobrien     offsets are ascending and adjacent.  */
482890075Sobrien
482990075Sobrien  for (i = 1; i < nops; i++)
483090075Sobrien    {
483190075Sobrien      int j;
483290075Sobrien
483390075Sobrien      order[i] = order[i - 1];
483490075Sobrien      for (j = 0; j < nops; j++)
483590075Sobrien	if (unsorted_regs[j] > unsorted_regs[order[i - 1]]
483690075Sobrien	    && (order[i] == order[i - 1]
483790075Sobrien		|| unsorted_regs[j] < unsorted_regs[order[i]]))
483890075Sobrien	  order[i] = j;
483990075Sobrien
484090075Sobrien      /* Have we found a suitable register? if not, one must be used more
484190075Sobrien	 than once.  */
484290075Sobrien      if (order[i] == order[i - 1])
484390075Sobrien	return 0;
484490075Sobrien
484590075Sobrien      /* Is the memory address adjacent and ascending? */
484690075Sobrien      if (unsorted_offsets[order[i]] != unsorted_offsets[order[i - 1]] + 4)
484790075Sobrien	return 0;
484890075Sobrien    }
484990075Sobrien
485090075Sobrien  if (base)
485190075Sobrien    {
485290075Sobrien      *base = base_reg;
485390075Sobrien
485490075Sobrien      for (i = 0; i < nops; i++)
485590075Sobrien	regs[i] = unsorted_regs[order[i]];
485690075Sobrien
485790075Sobrien      *load_offset = unsorted_offsets[order[0]];
485890075Sobrien    }
485990075Sobrien
486090075Sobrien  if (unsorted_offsets[order[0]] == 0)
486190075Sobrien    return 1; /* ldmia */
486290075Sobrien
486390075Sobrien  if (unsorted_offsets[order[0]] == 4)
486490075Sobrien    return 2; /* ldmib */
486590075Sobrien
486690075Sobrien  if (unsorted_offsets[order[nops - 1]] == 0)
486790075Sobrien    return 3; /* ldmda */
486890075Sobrien
486990075Sobrien  if (unsorted_offsets[order[nops - 1]] == -4)
487090075Sobrien    return 4; /* ldmdb */
487190075Sobrien
487290075Sobrien  /* For ARM8,9 & StrongARM, 2 ldr instructions are faster than an ldm
487390075Sobrien     if the offset isn't small enough.  The reason 2 ldrs are faster
487490075Sobrien     is because these ARMs are able to do more than one cache access
487590075Sobrien     in a single cycle.  The ARM9 and StrongARM have Harvard caches,
487690075Sobrien     whilst the ARM8 has a double bandwidth cache.  This means that
487790075Sobrien     these cores can do both an instruction fetch and a data fetch in
487890075Sobrien     a single cycle, so the trick of calculating the address into a
487990075Sobrien     scratch register (one of the result regs) and then doing a load
488090075Sobrien     multiple actually becomes slower (and no smaller in code size).
488190075Sobrien     That is the transformation
488290075Sobrien
488390075Sobrien 	ldr	rd1, [rbase + offset]
488490075Sobrien 	ldr	rd2, [rbase + offset + 4]
488590075Sobrien
488690075Sobrien     to
488790075Sobrien
488890075Sobrien 	add	rd1, rbase, offset
488990075Sobrien 	ldmia	rd1, {rd1, rd2}
489090075Sobrien
489190075Sobrien     produces worse code -- '3 cycles + any stalls on rd2' instead of
489290075Sobrien     '2 cycles + any stalls on rd2'.  On ARMs with only one cache
489390075Sobrien     access per cycle, the first sequence could never complete in less
489490075Sobrien     than 6 cycles, whereas the ldm sequence would only take 5 and
489590075Sobrien     would make better use of sequential accesses if not hitting the
489690075Sobrien     cache.
489790075Sobrien
489890075Sobrien     We cheat here and test 'arm_ld_sched' which we currently know to
489990075Sobrien     only be true for the ARM8, ARM9 and StrongARM.  If this ever
490090075Sobrien     changes, then the test below needs to be reworked.  */
490190075Sobrien  if (nops == 2 && arm_ld_sched)
490290075Sobrien    return 0;
490390075Sobrien
490490075Sobrien  /* Can't do it without setting up the offset, only do this if it takes
490590075Sobrien     no more than one insn.  */
490690075Sobrien  return (const_ok_for_arm (unsorted_offsets[order[0]])
490790075Sobrien	  || const_ok_for_arm (-unsorted_offsets[order[0]])) ? 5 : 0;
490890075Sobrien}
490990075Sobrien
491090075Sobrienconst char *
4911132718Skanemit_ldm_seq (rtx *operands, int nops)
491290075Sobrien{
491390075Sobrien  int regs[4];
491490075Sobrien  int base_reg;
491590075Sobrien  HOST_WIDE_INT offset;
491690075Sobrien  char buf[100];
491790075Sobrien  int i;
491890075Sobrien
491990075Sobrien  switch (load_multiple_sequence (operands, nops, regs, &base_reg, &offset))
492090075Sobrien    {
492190075Sobrien    case 1:
492290075Sobrien      strcpy (buf, "ldm%?ia\t");
492390075Sobrien      break;
492490075Sobrien
492590075Sobrien    case 2:
492690075Sobrien      strcpy (buf, "ldm%?ib\t");
492790075Sobrien      break;
492890075Sobrien
492990075Sobrien    case 3:
493090075Sobrien      strcpy (buf, "ldm%?da\t");
493190075Sobrien      break;
493290075Sobrien
493390075Sobrien    case 4:
493490075Sobrien      strcpy (buf, "ldm%?db\t");
493590075Sobrien      break;
493690075Sobrien
493790075Sobrien    case 5:
493890075Sobrien      if (offset >= 0)
493990075Sobrien	sprintf (buf, "add%%?\t%s%s, %s%s, #%ld", REGISTER_PREFIX,
494090075Sobrien		 reg_names[regs[0]], REGISTER_PREFIX, reg_names[base_reg],
494190075Sobrien		 (long) offset);
494290075Sobrien      else
494390075Sobrien	sprintf (buf, "sub%%?\t%s%s, %s%s, #%ld", REGISTER_PREFIX,
494490075Sobrien		 reg_names[regs[0]], REGISTER_PREFIX, reg_names[base_reg],
494590075Sobrien		 (long) -offset);
494690075Sobrien      output_asm_insn (buf, operands);
494790075Sobrien      base_reg = regs[0];
494890075Sobrien      strcpy (buf, "ldm%?ia\t");
494990075Sobrien      break;
495090075Sobrien
495190075Sobrien    default:
495290075Sobrien      abort ();
495390075Sobrien    }
495490075Sobrien
495590075Sobrien  sprintf (buf + strlen (buf), "%s%s, {%s%s", REGISTER_PREFIX,
495690075Sobrien	   reg_names[base_reg], REGISTER_PREFIX, reg_names[regs[0]]);
495790075Sobrien
495890075Sobrien  for (i = 1; i < nops; i++)
495990075Sobrien    sprintf (buf + strlen (buf), ", %s%s", REGISTER_PREFIX,
496090075Sobrien	     reg_names[regs[i]]);
496190075Sobrien
496290075Sobrien  strcat (buf, "}\t%@ phole ldm");
496390075Sobrien
496490075Sobrien  output_asm_insn (buf, operands);
496590075Sobrien  return "";
496690075Sobrien}
496790075Sobrien
496890075Sobrienint
4969132718Skanstore_multiple_sequence (rtx *operands, int nops, int *regs, int *base,
4970132718Skan			 HOST_WIDE_INT * load_offset)
497190075Sobrien{
497290075Sobrien  int unsorted_regs[4];
497390075Sobrien  HOST_WIDE_INT unsorted_offsets[4];
497490075Sobrien  int order[4];
497590075Sobrien  int base_reg = -1;
497690075Sobrien  int i;
497790075Sobrien
497890075Sobrien  /* Can only handle 2, 3, or 4 insns at present, though could be easily
497990075Sobrien     extended if required.  */
498090075Sobrien  if (nops < 2 || nops > 4)
498190075Sobrien    abort ();
498290075Sobrien
498390075Sobrien  /* Loop over the operands and check that the memory references are
498490075Sobrien     suitable (ie immediate offsets from the same base register).  At
498590075Sobrien     the same time, extract the target register, and the memory
498690075Sobrien     offsets.  */
498790075Sobrien  for (i = 0; i < nops; i++)
498890075Sobrien    {
498990075Sobrien      rtx reg;
499090075Sobrien      rtx offset;
499190075Sobrien
499290075Sobrien      /* Convert a subreg of a mem into the mem itself.  */
499390075Sobrien      if (GET_CODE (operands[nops + i]) == SUBREG)
499490075Sobrien	operands[nops + i] = alter_subreg (operands + (nops + i));
499590075Sobrien
499690075Sobrien      if (GET_CODE (operands[nops + i]) != MEM)
499790075Sobrien	abort ();
499890075Sobrien
499990075Sobrien      /* Don't reorder volatile memory references; it doesn't seem worth
500090075Sobrien	 looking for the case where the order is ok anyway.  */
500190075Sobrien      if (MEM_VOLATILE_P (operands[nops + i]))
500290075Sobrien	return 0;
500390075Sobrien
500490075Sobrien      offset = const0_rtx;
500590075Sobrien
500690075Sobrien      if ((GET_CODE (reg = XEXP (operands[nops + i], 0)) == REG
500790075Sobrien	   || (GET_CODE (reg) == SUBREG
500890075Sobrien	       && GET_CODE (reg = SUBREG_REG (reg)) == REG))
500990075Sobrien	  || (GET_CODE (XEXP (operands[nops + i], 0)) == PLUS
501090075Sobrien	      && ((GET_CODE (reg = XEXP (XEXP (operands[nops + i], 0), 0))
501190075Sobrien		   == REG)
501290075Sobrien		  || (GET_CODE (reg) == SUBREG
501390075Sobrien		      && GET_CODE (reg = SUBREG_REG (reg)) == REG))
501490075Sobrien	      && (GET_CODE (offset = XEXP (XEXP (operands[nops + i], 0), 1))
501590075Sobrien		  == CONST_INT)))
501690075Sobrien	{
501790075Sobrien	  if (i == 0)
501890075Sobrien	    {
501990075Sobrien	      base_reg = REGNO (reg);
502090075Sobrien	      unsorted_regs[0] = (GET_CODE (operands[i]) == REG
502190075Sobrien				  ? REGNO (operands[i])
502290075Sobrien				  : REGNO (SUBREG_REG (operands[i])));
502390075Sobrien	      order[0] = 0;
502490075Sobrien	    }
502590075Sobrien	  else
502690075Sobrien	    {
502790075Sobrien	      if (base_reg != (int) REGNO (reg))
502890075Sobrien		/* Not addressed from the same base register.  */
502990075Sobrien		return 0;
503090075Sobrien
503190075Sobrien	      unsorted_regs[i] = (GET_CODE (operands[i]) == REG
503290075Sobrien				  ? REGNO (operands[i])
503390075Sobrien				  : REGNO (SUBREG_REG (operands[i])));
503490075Sobrien	      if (unsorted_regs[i] < unsorted_regs[order[0]])
503590075Sobrien		order[0] = i;
503690075Sobrien	    }
503790075Sobrien
503890075Sobrien	  /* If it isn't an integer register, then we can't do this.  */
503990075Sobrien	  if (unsorted_regs[i] < 0 || unsorted_regs[i] > 14)
504090075Sobrien	    return 0;
504190075Sobrien
504290075Sobrien	  unsorted_offsets[i] = INTVAL (offset);
504390075Sobrien	}
504490075Sobrien      else
504590075Sobrien	/* Not a suitable memory address.  */
504690075Sobrien	return 0;
504790075Sobrien    }
504890075Sobrien
504990075Sobrien  /* All the useful information has now been extracted from the
505090075Sobrien     operands into unsorted_regs and unsorted_offsets; additionally,
505190075Sobrien     order[0] has been set to the lowest numbered register in the
505290075Sobrien     list.  Sort the registers into order, and check that the memory
505390075Sobrien     offsets are ascending and adjacent.  */
505490075Sobrien
505590075Sobrien  for (i = 1; i < nops; i++)
505690075Sobrien    {
505790075Sobrien      int j;
505890075Sobrien
505990075Sobrien      order[i] = order[i - 1];
506090075Sobrien      for (j = 0; j < nops; j++)
506190075Sobrien	if (unsorted_regs[j] > unsorted_regs[order[i - 1]]
506290075Sobrien	    && (order[i] == order[i - 1]
506390075Sobrien		|| unsorted_regs[j] < unsorted_regs[order[i]]))
506490075Sobrien	  order[i] = j;
506590075Sobrien
506690075Sobrien      /* Have we found a suitable register? if not, one must be used more
506790075Sobrien	 than once.  */
506890075Sobrien      if (order[i] == order[i - 1])
506990075Sobrien	return 0;
507090075Sobrien
507190075Sobrien      /* Is the memory address adjacent and ascending? */
507290075Sobrien      if (unsorted_offsets[order[i]] != unsorted_offsets[order[i - 1]] + 4)
507390075Sobrien	return 0;
507490075Sobrien    }
507590075Sobrien
507690075Sobrien  if (base)
507790075Sobrien    {
507890075Sobrien      *base = base_reg;
507990075Sobrien
508090075Sobrien      for (i = 0; i < nops; i++)
508190075Sobrien	regs[i] = unsorted_regs[order[i]];
508290075Sobrien
508390075Sobrien      *load_offset = unsorted_offsets[order[0]];
508490075Sobrien    }
508590075Sobrien
508690075Sobrien  if (unsorted_offsets[order[0]] == 0)
508790075Sobrien    return 1; /* stmia */
508890075Sobrien
508990075Sobrien  if (unsorted_offsets[order[0]] == 4)
509090075Sobrien    return 2; /* stmib */
509190075Sobrien
509290075Sobrien  if (unsorted_offsets[order[nops - 1]] == 0)
509390075Sobrien    return 3; /* stmda */
509490075Sobrien
509590075Sobrien  if (unsorted_offsets[order[nops - 1]] == -4)
509690075Sobrien    return 4; /* stmdb */
509790075Sobrien
509890075Sobrien  return 0;
509990075Sobrien}
510090075Sobrien
510190075Sobrienconst char *
5102132718Skanemit_stm_seq (rtx *operands, int nops)
510390075Sobrien{
510490075Sobrien  int regs[4];
510590075Sobrien  int base_reg;
510690075Sobrien  HOST_WIDE_INT offset;
510790075Sobrien  char buf[100];
510890075Sobrien  int i;
510990075Sobrien
511090075Sobrien  switch (store_multiple_sequence (operands, nops, regs, &base_reg, &offset))
511190075Sobrien    {
511290075Sobrien    case 1:
511390075Sobrien      strcpy (buf, "stm%?ia\t");
511490075Sobrien      break;
511590075Sobrien
511690075Sobrien    case 2:
511790075Sobrien      strcpy (buf, "stm%?ib\t");
511890075Sobrien      break;
511990075Sobrien
512090075Sobrien    case 3:
512190075Sobrien      strcpy (buf, "stm%?da\t");
512290075Sobrien      break;
512390075Sobrien
512490075Sobrien    case 4:
512590075Sobrien      strcpy (buf, "stm%?db\t");
512690075Sobrien      break;
512790075Sobrien
512890075Sobrien    default:
512990075Sobrien      abort ();
513090075Sobrien    }
513190075Sobrien
513290075Sobrien  sprintf (buf + strlen (buf), "%s%s, {%s%s", REGISTER_PREFIX,
513390075Sobrien	   reg_names[base_reg], REGISTER_PREFIX, reg_names[regs[0]]);
513490075Sobrien
513590075Sobrien  for (i = 1; i < nops; i++)
513690075Sobrien    sprintf (buf + strlen (buf), ", %s%s", REGISTER_PREFIX,
513790075Sobrien	     reg_names[regs[i]]);
513890075Sobrien
513990075Sobrien  strcat (buf, "}\t%@ phole stm");
514090075Sobrien
514190075Sobrien  output_asm_insn (buf, operands);
514290075Sobrien  return "";
514390075Sobrien}
514490075Sobrien
514590075Sobrienint
5146132718Skanmulti_register_push (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
514790075Sobrien{
514890075Sobrien  if (GET_CODE (op) != PARALLEL
514990075Sobrien      || (GET_CODE (XVECEXP (op, 0, 0)) != SET)
515090075Sobrien      || (GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != UNSPEC)
515190075Sobrien      || (XINT (SET_SRC (XVECEXP (op, 0, 0)), 1) != UNSPEC_PUSH_MULT))
515290075Sobrien    return 0;
515390075Sobrien
515490075Sobrien  return 1;
515590075Sobrien}
515690075Sobrien
515790075Sobrien/* Routines for use in generating RTL.  */
515890075Sobrien
515990075Sobrienrtx
5160132718Skanarm_gen_load_multiple (int base_regno, int count, rtx from, int up,
5161161651Skan		       int write_back, rtx basemem, HOST_WIDE_INT *offsetp)
516290075Sobrien{
5163161651Skan  HOST_WIDE_INT offset = *offsetp;
516490075Sobrien  int i = 0, j;
516590075Sobrien  rtx result;
516690075Sobrien  int sign = up ? 1 : -1;
5167161651Skan  rtx mem, addr;
516890075Sobrien
516990075Sobrien  /* XScale has load-store double instructions, but they have stricter
517090075Sobrien     alignment requirements than load-store multiple, so we can not
517190075Sobrien     use them.
517290075Sobrien
517390075Sobrien     For XScale ldm requires 2 + NREGS cycles to complete and blocks
517490075Sobrien     the pipeline until completion.
517590075Sobrien
517690075Sobrien	NREGS		CYCLES
517790075Sobrien	  1		  3
517890075Sobrien	  2		  4
517990075Sobrien	  3		  5
518090075Sobrien	  4		  6
518190075Sobrien
518290075Sobrien     An ldr instruction takes 1-3 cycles, but does not block the
518390075Sobrien     pipeline.
518490075Sobrien
518590075Sobrien	NREGS		CYCLES
518690075Sobrien	  1		 1-3
518790075Sobrien	  2		 2-6
518890075Sobrien	  3		 3-9
518990075Sobrien	  4		 4-12
519090075Sobrien
519190075Sobrien     Best case ldr will always win.  However, the more ldr instructions
519290075Sobrien     we issue, the less likely we are to be able to schedule them well.
519390075Sobrien     Using ldr instructions also increases code size.
519490075Sobrien
519590075Sobrien     As a compromise, we use ldr for counts of 1 or 2 regs, and ldm
519690075Sobrien     for counts of 3 or 4 regs.  */
5197132718Skan  if (arm_tune_xscale && count <= 2 && ! optimize_size)
519890075Sobrien    {
519990075Sobrien      rtx seq;
520090075Sobrien
520190075Sobrien      start_sequence ();
520290075Sobrien
520390075Sobrien      for (i = 0; i < count; i++)
520490075Sobrien	{
5205161651Skan	  addr = plus_constant (from, i * 4 * sign);
5206161651Skan	  mem = adjust_automodify_address (basemem, SImode, addr, offset);
520790075Sobrien	  emit_move_insn (gen_rtx_REG (SImode, base_regno + i), mem);
5208161651Skan	  offset += 4 * sign;
520990075Sobrien	}
521090075Sobrien
521190075Sobrien      if (write_back)
5212161651Skan	{
5213161651Skan	  emit_move_insn (from, plus_constant (from, count * 4 * sign));
5214161651Skan	  *offsetp = offset;
5215161651Skan	}
521690075Sobrien
5217117395Skan      seq = get_insns ();
521890075Sobrien      end_sequence ();
521990075Sobrien
522090075Sobrien      return seq;
522190075Sobrien    }
522290075Sobrien
522390075Sobrien  result = gen_rtx_PARALLEL (VOIDmode,
522490075Sobrien			     rtvec_alloc (count + (write_back ? 1 : 0)));
522590075Sobrien  if (write_back)
522690075Sobrien    {
522790075Sobrien      XVECEXP (result, 0, 0)
522890075Sobrien	= gen_rtx_SET (GET_MODE (from), from,
522990075Sobrien		       plus_constant (from, count * 4 * sign));
523090075Sobrien      i = 1;
523190075Sobrien      count++;
523290075Sobrien    }
523390075Sobrien
523490075Sobrien  for (j = 0; i < count; i++, j++)
523590075Sobrien    {
5236161651Skan      addr = plus_constant (from, j * 4 * sign);
5237161651Skan      mem = adjust_automodify_address_nv (basemem, SImode, addr, offset);
523890075Sobrien      XVECEXP (result, 0, i)
523990075Sobrien	= gen_rtx_SET (VOIDmode, gen_rtx_REG (SImode, base_regno + j), mem);
5240161651Skan      offset += 4 * sign;
524190075Sobrien    }
524290075Sobrien
5243161651Skan  if (write_back)
5244161651Skan    *offsetp = offset;
5245161651Skan
524690075Sobrien  return result;
524790075Sobrien}
524890075Sobrien
524990075Sobrienrtx
5250132718Skanarm_gen_store_multiple (int base_regno, int count, rtx to, int up,
5251161651Skan			int write_back, rtx basemem, HOST_WIDE_INT *offsetp)
525290075Sobrien{
5253161651Skan  HOST_WIDE_INT offset = *offsetp;
525490075Sobrien  int i = 0, j;
525590075Sobrien  rtx result;
525690075Sobrien  int sign = up ? 1 : -1;
5257161651Skan  rtx mem, addr;
525890075Sobrien
525990075Sobrien  /* See arm_gen_load_multiple for discussion of
526090075Sobrien     the pros/cons of ldm/stm usage for XScale.  */
5261132718Skan  if (arm_tune_xscale && count <= 2 && ! optimize_size)
526290075Sobrien    {
526390075Sobrien      rtx seq;
526490075Sobrien
526590075Sobrien      start_sequence ();
526690075Sobrien
526790075Sobrien      for (i = 0; i < count; i++)
526890075Sobrien	{
5269161651Skan	  addr = plus_constant (to, i * 4 * sign);
5270161651Skan	  mem = adjust_automodify_address (basemem, SImode, addr, offset);
527190075Sobrien	  emit_move_insn (mem, gen_rtx_REG (SImode, base_regno + i));
5272161651Skan	  offset += 4 * sign;
527390075Sobrien	}
527490075Sobrien
527590075Sobrien      if (write_back)
5276161651Skan	{
5277161651Skan	  emit_move_insn (to, plus_constant (to, count * 4 * sign));
5278161651Skan	  *offsetp = offset;
5279161651Skan	}
528090075Sobrien
5281117395Skan      seq = get_insns ();
528290075Sobrien      end_sequence ();
528390075Sobrien
528490075Sobrien      return seq;
528590075Sobrien    }
528690075Sobrien
528790075Sobrien  result = gen_rtx_PARALLEL (VOIDmode,
528890075Sobrien			     rtvec_alloc (count + (write_back ? 1 : 0)));
528990075Sobrien  if (write_back)
529090075Sobrien    {
529190075Sobrien      XVECEXP (result, 0, 0)
529290075Sobrien	= gen_rtx_SET (GET_MODE (to), to,
529390075Sobrien		       plus_constant (to, count * 4 * sign));
529490075Sobrien      i = 1;
529590075Sobrien      count++;
529690075Sobrien    }
529790075Sobrien
529890075Sobrien  for (j = 0; i < count; i++, j++)
529990075Sobrien    {
5300161651Skan      addr = plus_constant (to, j * 4 * sign);
5301161651Skan      mem = adjust_automodify_address_nv (basemem, SImode, addr, offset);
530290075Sobrien      XVECEXP (result, 0, i)
530390075Sobrien	= gen_rtx_SET (VOIDmode, mem, gen_rtx_REG (SImode, base_regno + j));
5304161651Skan      offset += 4 * sign;
530590075Sobrien    }
530690075Sobrien
5307161651Skan  if (write_back)
5308161651Skan    *offsetp = offset;
5309161651Skan
531090075Sobrien  return result;
531190075Sobrien}
531290075Sobrien
531390075Sobrienint
5314132718Skanarm_gen_movstrqi (rtx *operands)
531590075Sobrien{
531690075Sobrien  HOST_WIDE_INT in_words_to_go, out_words_to_go, last_bytes;
5317161651Skan  HOST_WIDE_INT srcoffset, dstoffset;
531890075Sobrien  int i;
5319161651Skan  rtx src, dst, srcbase, dstbase;
532090075Sobrien  rtx part_bytes_reg = NULL;
532190075Sobrien  rtx mem;
532290075Sobrien
532390075Sobrien  if (GET_CODE (operands[2]) != CONST_INT
532490075Sobrien      || GET_CODE (operands[3]) != CONST_INT
532590075Sobrien      || INTVAL (operands[2]) > 64
532690075Sobrien      || INTVAL (operands[3]) & 3)
532790075Sobrien    return 0;
532890075Sobrien
5329161651Skan  dstbase = operands[0];
5330161651Skan  srcbase = operands[1];
5331161651Skan
5332161651Skan  dst = copy_to_mode_reg (SImode, XEXP (dstbase, 0));
5333161651Skan  src = copy_to_mode_reg (SImode, XEXP (srcbase, 0));
533490075Sobrien
5335117395Skan  in_words_to_go = ARM_NUM_INTS (INTVAL (operands[2]));
533690075Sobrien  out_words_to_go = INTVAL (operands[2]) / 4;
533790075Sobrien  last_bytes = INTVAL (operands[2]) & 3;
5338161651Skan  dstoffset = srcoffset = 0;
5339161651Skan
534090075Sobrien  if (out_words_to_go != in_words_to_go && ((in_words_to_go - 1) & 3) != 0)
534190075Sobrien    part_bytes_reg = gen_rtx_REG (SImode, (in_words_to_go - 1) & 3);
534290075Sobrien
534390075Sobrien  for (i = 0; in_words_to_go >= 2; i+=4)
534490075Sobrien    {
534590075Sobrien      if (in_words_to_go > 4)
534690075Sobrien	emit_insn (arm_gen_load_multiple (0, 4, src, TRUE, TRUE,
5347161651Skan					  srcbase, &srcoffset));
534890075Sobrien      else
534990075Sobrien	emit_insn (arm_gen_load_multiple (0, in_words_to_go, src, TRUE,
5350161651Skan					  FALSE, srcbase, &srcoffset));
535190075Sobrien
535290075Sobrien      if (out_words_to_go)
535390075Sobrien	{
535490075Sobrien	  if (out_words_to_go > 4)
535590075Sobrien	    emit_insn (arm_gen_store_multiple (0, 4, dst, TRUE, TRUE,
5356161651Skan					       dstbase, &dstoffset));
5357161651Skan
535890075Sobrien	  else if (out_words_to_go != 1)
535990075Sobrien	    emit_insn (arm_gen_store_multiple (0, out_words_to_go,
536090075Sobrien					       dst, TRUE,
536190075Sobrien					       (last_bytes == 0
536290075Sobrien						? FALSE : TRUE),
5363161651Skan					       dstbase, &dstoffset));
536490075Sobrien	  else
536590075Sobrien	    {
5366161651Skan	      mem = adjust_automodify_address (dstbase, SImode, dst, dstoffset);
536790075Sobrien	      emit_move_insn (mem, gen_rtx_REG (SImode, 0));
536890075Sobrien	      if (last_bytes != 0)
5369161651Skan		{
5370161651Skan		  emit_insn (gen_addsi3 (dst, dst, GEN_INT (4)));
5371161651Skan		  dstoffset += 4;
5372161651Skan		}
537390075Sobrien	    }
537490075Sobrien	}
537590075Sobrien
537690075Sobrien      in_words_to_go -= in_words_to_go < 4 ? in_words_to_go : 4;
537790075Sobrien      out_words_to_go -= out_words_to_go < 4 ? out_words_to_go : 4;
537890075Sobrien    }
537990075Sobrien
538090075Sobrien  /* OUT_WORDS_TO_GO will be zero here if there are byte stores to do.  */
538190075Sobrien  if (out_words_to_go)
538290075Sobrien    {
538390075Sobrien      rtx sreg;
5384161651Skan
5385161651Skan      mem = adjust_automodify_address (srcbase, SImode, src, srcoffset);
5386161651Skan      sreg = copy_to_reg (mem);
5387161651Skan
5388161651Skan      mem = adjust_automodify_address (dstbase, SImode, dst, dstoffset);
538990075Sobrien      emit_move_insn (mem, sreg);
539090075Sobrien      in_words_to_go--;
539190075Sobrien
539290075Sobrien      if (in_words_to_go)	/* Sanity check */
539390075Sobrien	abort ();
539490075Sobrien    }
539590075Sobrien
539690075Sobrien  if (in_words_to_go)
539790075Sobrien    {
539890075Sobrien      if (in_words_to_go < 0)
539990075Sobrien	abort ();
540090075Sobrien
5401161651Skan      mem = adjust_automodify_address (srcbase, SImode, src, srcoffset);
540290075Sobrien      part_bytes_reg = copy_to_mode_reg (SImode, mem);
540390075Sobrien    }
540490075Sobrien
540590075Sobrien  if (last_bytes && part_bytes_reg == NULL)
540690075Sobrien    abort ();
540790075Sobrien
540890075Sobrien  if (BYTES_BIG_ENDIAN && last_bytes)
540990075Sobrien    {
541090075Sobrien      rtx tmp = gen_reg_rtx (SImode);
541190075Sobrien
541290075Sobrien      /* The bytes we want are in the top end of the word.  */
541390075Sobrien      emit_insn (gen_lshrsi3 (tmp, part_bytes_reg,
541490075Sobrien			      GEN_INT (8 * (4 - last_bytes))));
541590075Sobrien      part_bytes_reg = tmp;
541690075Sobrien
541790075Sobrien      while (last_bytes)
541890075Sobrien	{
5419161651Skan	  mem = adjust_automodify_address (dstbase, QImode,
5420161651Skan					   plus_constant (dst, last_bytes - 1),
5421161651Skan					   dstoffset + last_bytes - 1);
5422102780Skan	  emit_move_insn (mem, gen_lowpart (QImode, part_bytes_reg));
5423102780Skan
542490075Sobrien	  if (--last_bytes)
542590075Sobrien	    {
542690075Sobrien	      tmp = gen_reg_rtx (SImode);
542790075Sobrien	      emit_insn (gen_lshrsi3 (tmp, part_bytes_reg, GEN_INT (8)));
542890075Sobrien	      part_bytes_reg = tmp;
542990075Sobrien	    }
543090075Sobrien	}
543190075Sobrien
543290075Sobrien    }
543390075Sobrien  else
543490075Sobrien    {
543590075Sobrien      if (last_bytes > 1)
543690075Sobrien	{
5437161651Skan	  mem = adjust_automodify_address (dstbase, HImode, dst, dstoffset);
5438102780Skan	  emit_move_insn (mem, gen_lowpart (HImode, part_bytes_reg));
543990075Sobrien	  last_bytes -= 2;
544090075Sobrien	  if (last_bytes)
544190075Sobrien	    {
544290075Sobrien	      rtx tmp = gen_reg_rtx (SImode);
544390075Sobrien
544490075Sobrien	      emit_insn (gen_addsi3 (dst, dst, GEN_INT (2)));
544590075Sobrien	      emit_insn (gen_lshrsi3 (tmp, part_bytes_reg, GEN_INT (16)));
544690075Sobrien	      part_bytes_reg = tmp;
5447161651Skan	      dstoffset += 2;
544890075Sobrien	    }
544990075Sobrien	}
545090075Sobrien
545190075Sobrien      if (last_bytes)
545290075Sobrien	{
5453161651Skan	  mem = adjust_automodify_address (dstbase, QImode, dst, dstoffset);
5454102780Skan	  emit_move_insn (mem, gen_lowpart (QImode, part_bytes_reg));
545590075Sobrien	}
545690075Sobrien    }
545790075Sobrien
545890075Sobrien  return 1;
545990075Sobrien}
546090075Sobrien
546190075Sobrien/* Generate a memory reference for a half word, such that it will be loaded
546290075Sobrien   into the top 16 bits of the word.  We can assume that the address is
546390075Sobrien   known to be alignable and of the form reg, or plus (reg, const).  */
546490075Sobrien
546590075Sobrienrtx
5466132718Skanarm_gen_rotated_half_load (rtx memref)
546790075Sobrien{
546890075Sobrien  HOST_WIDE_INT offset = 0;
546990075Sobrien  rtx base = XEXP (memref, 0);
547090075Sobrien
547190075Sobrien  if (GET_CODE (base) == PLUS)
547290075Sobrien    {
547390075Sobrien      offset = INTVAL (XEXP (base, 1));
547490075Sobrien      base = XEXP (base, 0);
547590075Sobrien    }
547690075Sobrien
547790075Sobrien  /* If we aren't allowed to generate unaligned addresses, then fail.  */
547890075Sobrien  if (TARGET_MMU_TRAPS
547990075Sobrien      && ((BYTES_BIG_ENDIAN ? 1 : 0) ^ ((offset & 2) == 0)))
548090075Sobrien    return NULL;
548190075Sobrien
548290075Sobrien  base = gen_rtx_MEM (SImode, plus_constant (base, offset & ~2));
548390075Sobrien
548490075Sobrien  if ((BYTES_BIG_ENDIAN ? 1 : 0) ^ ((offset & 2) == 2))
548590075Sobrien    return base;
548690075Sobrien
548790075Sobrien  return gen_rtx_ROTATE (SImode, base, GEN_INT (16));
548890075Sobrien}
548990075Sobrien
5490132718Skan/* Select a dominance comparison mode if possible for a test of the general
5491132718Skan   form (OP (COND_OR (X) (Y)) (const_int 0)).  We support three forms.
5492132718Skan   COND_OR == DOM_CC_X_AND_Y => (X && Y)
5493132718Skan   COND_OR == DOM_CC_NX_OR_Y => ((! X) || Y)
5494132718Skan   COND_OR == DOM_CC_X_OR_Y => (X || Y)
5495132718Skan   In all cases OP will be either EQ or NE, but we don't need to know which
5496132718Skan   here.  If we are unable to support a dominance comparison we return
5497132718Skan   CC mode.  This will then fail to match for the RTL expressions that
5498132718Skan   generate this call.  */
5499132718Skanenum machine_mode
5500132718Skanarm_select_dominance_cc_mode (rtx x, rtx y, HOST_WIDE_INT cond_or)
550190075Sobrien{
550290075Sobrien  enum rtx_code cond1, cond2;
550390075Sobrien  int swapped = 0;
550490075Sobrien
550590075Sobrien  /* Currently we will probably get the wrong result if the individual
550690075Sobrien     comparisons are not simple.  This also ensures that it is safe to
550790075Sobrien     reverse a comparison if necessary.  */
550890075Sobrien  if ((arm_select_cc_mode (cond1 = GET_CODE (x), XEXP (x, 0), XEXP (x, 1))
550990075Sobrien       != CCmode)
551090075Sobrien      || (arm_select_cc_mode (cond2 = GET_CODE (y), XEXP (y, 0), XEXP (y, 1))
551190075Sobrien	  != CCmode))
551290075Sobrien    return CCmode;
551390075Sobrien
551490075Sobrien  /* The if_then_else variant of this tests the second condition if the
551590075Sobrien     first passes, but is true if the first fails.  Reverse the first
551690075Sobrien     condition to get a true "inclusive-or" expression.  */
5517132718Skan  if (cond_or == DOM_CC_NX_OR_Y)
551890075Sobrien    cond1 = reverse_condition (cond1);
551990075Sobrien
552090075Sobrien  /* If the comparisons are not equal, and one doesn't dominate the other,
552190075Sobrien     then we can't do this.  */
552290075Sobrien  if (cond1 != cond2
552390075Sobrien      && !comparison_dominates_p (cond1, cond2)
552490075Sobrien      && (swapped = 1, !comparison_dominates_p (cond2, cond1)))
552590075Sobrien    return CCmode;
552690075Sobrien
552790075Sobrien  if (swapped)
552890075Sobrien    {
552990075Sobrien      enum rtx_code temp = cond1;
553090075Sobrien      cond1 = cond2;
553190075Sobrien      cond2 = temp;
553290075Sobrien    }
553390075Sobrien
553490075Sobrien  switch (cond1)
553590075Sobrien    {
553690075Sobrien    case EQ:
5537132718Skan      if (cond2 == EQ || cond_or == DOM_CC_X_AND_Y)
553890075Sobrien	return CC_DEQmode;
553990075Sobrien
554090075Sobrien      switch (cond2)
554190075Sobrien	{
554290075Sobrien	case LE: return CC_DLEmode;
554390075Sobrien	case LEU: return CC_DLEUmode;
554490075Sobrien	case GE: return CC_DGEmode;
554590075Sobrien	case GEU: return CC_DGEUmode;
554690075Sobrien	default: break;
554790075Sobrien	}
554890075Sobrien
554990075Sobrien      break;
555090075Sobrien
555190075Sobrien    case LT:
5552132718Skan      if (cond2 == LT || cond_or == DOM_CC_X_AND_Y)
555390075Sobrien	return CC_DLTmode;
555490075Sobrien      if (cond2 == LE)
555590075Sobrien	return CC_DLEmode;
555690075Sobrien      if (cond2 == NE)
555790075Sobrien	return CC_DNEmode;
555890075Sobrien      break;
555990075Sobrien
556090075Sobrien    case GT:
5561132718Skan      if (cond2 == GT || cond_or == DOM_CC_X_AND_Y)
556290075Sobrien	return CC_DGTmode;
556390075Sobrien      if (cond2 == GE)
556490075Sobrien	return CC_DGEmode;
556590075Sobrien      if (cond2 == NE)
556690075Sobrien	return CC_DNEmode;
556790075Sobrien      break;
556890075Sobrien
556990075Sobrien    case LTU:
5570132718Skan      if (cond2 == LTU || cond_or == DOM_CC_X_AND_Y)
557190075Sobrien	return CC_DLTUmode;
557290075Sobrien      if (cond2 == LEU)
557390075Sobrien	return CC_DLEUmode;
557490075Sobrien      if (cond2 == NE)
557590075Sobrien	return CC_DNEmode;
557690075Sobrien      break;
557790075Sobrien
557890075Sobrien    case GTU:
5579132718Skan      if (cond2 == GTU || cond_or == DOM_CC_X_AND_Y)
558090075Sobrien	return CC_DGTUmode;
558190075Sobrien      if (cond2 == GEU)
558290075Sobrien	return CC_DGEUmode;
558390075Sobrien      if (cond2 == NE)
558490075Sobrien	return CC_DNEmode;
558590075Sobrien      break;
558690075Sobrien
558790075Sobrien    /* The remaining cases only occur when both comparisons are the
558890075Sobrien       same.  */
558990075Sobrien    case NE:
559090075Sobrien      return CC_DNEmode;
559190075Sobrien
559290075Sobrien    case LE:
559390075Sobrien      return CC_DLEmode;
559490075Sobrien
559590075Sobrien    case GE:
559690075Sobrien      return CC_DGEmode;
559790075Sobrien
559890075Sobrien    case LEU:
559990075Sobrien      return CC_DLEUmode;
560090075Sobrien
560190075Sobrien    case GEU:
560290075Sobrien      return CC_DGEUmode;
560390075Sobrien
560490075Sobrien    default:
560590075Sobrien      break;
560690075Sobrien    }
560790075Sobrien
560890075Sobrien  abort ();
560990075Sobrien}
561090075Sobrien
561190075Sobrienenum machine_mode
5612132718Skanarm_select_cc_mode (enum rtx_code op, rtx x, rtx y)
561390075Sobrien{
561490075Sobrien  /* All floating point compares return CCFP if it is an equality
561590075Sobrien     comparison, and CCFPE otherwise.  */
561690075Sobrien  if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
561790075Sobrien    {
561890075Sobrien      switch (op)
561990075Sobrien	{
562090075Sobrien	case EQ:
562190075Sobrien	case NE:
562290075Sobrien	case UNORDERED:
562390075Sobrien	case ORDERED:
562490075Sobrien	case UNLT:
562590075Sobrien	case UNLE:
562690075Sobrien	case UNGT:
562790075Sobrien	case UNGE:
562890075Sobrien	case UNEQ:
562990075Sobrien	case LTGT:
563090075Sobrien	  return CCFPmode;
563190075Sobrien
563290075Sobrien	case LT:
563390075Sobrien	case LE:
563490075Sobrien	case GT:
563590075Sobrien	case GE:
5636132718Skan	  if (TARGET_CIRRUS)
5637132718Skan	    return CCFPmode;
563890075Sobrien	  return CCFPEmode;
563990075Sobrien
564090075Sobrien	default:
564190075Sobrien	  abort ();
564290075Sobrien	}
564390075Sobrien    }
564490075Sobrien
564590075Sobrien  /* A compare with a shifted operand.  Because of canonicalization, the
564690075Sobrien     comparison will have to be swapped when we emit the assembler.  */
564790075Sobrien  if (GET_MODE (y) == SImode && GET_CODE (y) == REG
564890075Sobrien      && (GET_CODE (x) == ASHIFT || GET_CODE (x) == ASHIFTRT
564990075Sobrien	  || GET_CODE (x) == LSHIFTRT || GET_CODE (x) == ROTATE
565090075Sobrien	  || GET_CODE (x) == ROTATERT))
565190075Sobrien    return CC_SWPmode;
565290075Sobrien
565390075Sobrien  /* This is a special case that is used by combine to allow a
565490075Sobrien     comparison of a shifted byte load to be split into a zero-extend
565590075Sobrien     followed by a comparison of the shifted integer (only valid for
565690075Sobrien     equalities and unsigned inequalities).  */
565790075Sobrien  if (GET_MODE (x) == SImode
565890075Sobrien      && GET_CODE (x) == ASHIFT
565990075Sobrien      && GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) == 24
566090075Sobrien      && GET_CODE (XEXP (x, 0)) == SUBREG
566190075Sobrien      && GET_CODE (SUBREG_REG (XEXP (x, 0))) == MEM
566290075Sobrien      && GET_MODE (SUBREG_REG (XEXP (x, 0))) == QImode
566390075Sobrien      && (op == EQ || op == NE
566490075Sobrien	  || op == GEU || op == GTU || op == LTU || op == LEU)
566590075Sobrien      && GET_CODE (y) == CONST_INT)
566690075Sobrien    return CC_Zmode;
566790075Sobrien
566890075Sobrien  /* A construct for a conditional compare, if the false arm contains
566990075Sobrien     0, then both conditions must be true, otherwise either condition
567090075Sobrien     must be true.  Not all conditions are possible, so CCmode is
567190075Sobrien     returned if it can't be done.  */
567290075Sobrien  if (GET_CODE (x) == IF_THEN_ELSE
567390075Sobrien      && (XEXP (x, 2) == const0_rtx
567490075Sobrien	  || XEXP (x, 2) == const1_rtx)
567590075Sobrien      && GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
567690075Sobrien      && GET_RTX_CLASS (GET_CODE (XEXP (x, 1))) == '<')
5677132718Skan    return arm_select_dominance_cc_mode (XEXP (x, 0), XEXP (x, 1),
5678132718Skan					 INTVAL (XEXP (x, 2)));
567990075Sobrien
568090075Sobrien  /* Alternate canonicalizations of the above.  These are somewhat cleaner.  */
568190075Sobrien  if (GET_CODE (x) == AND
568290075Sobrien      && GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
568390075Sobrien      && GET_RTX_CLASS (GET_CODE (XEXP (x, 1))) == '<')
5684132718Skan    return arm_select_dominance_cc_mode (XEXP (x, 0), XEXP (x, 1),
5685132718Skan					 DOM_CC_X_AND_Y);
568690075Sobrien
568790075Sobrien  if (GET_CODE (x) == IOR
568890075Sobrien      && GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
568990075Sobrien      && GET_RTX_CLASS (GET_CODE (XEXP (x, 1))) == '<')
5690132718Skan    return arm_select_dominance_cc_mode (XEXP (x, 0), XEXP (x, 1),
5691132718Skan					 DOM_CC_X_OR_Y);
569290075Sobrien
5693132718Skan  /* An operation (on Thumb) where we want to test for a single bit.
5694132718Skan     This is done by shifting that bit up into the top bit of a
5695132718Skan     scratch register; we can then branch on the sign bit.  */
5696132718Skan  if (TARGET_THUMB
5697132718Skan      && GET_MODE (x) == SImode
5698132718Skan      && (op == EQ || op == NE)
5699132718Skan      && (GET_CODE (x) == ZERO_EXTRACT))
5700132718Skan    return CC_Nmode;
5701132718Skan
570290075Sobrien  /* An operation that sets the condition codes as a side-effect, the
570390075Sobrien     V flag is not set correctly, so we can only use comparisons where
570490075Sobrien     this doesn't matter.  (For LT and GE we can use "mi" and "pl"
5705132718Skan     instead.)  */
570690075Sobrien  if (GET_MODE (x) == SImode
570790075Sobrien      && y == const0_rtx
570890075Sobrien      && (op == EQ || op == NE || op == LT || op == GE)
570990075Sobrien      && (GET_CODE (x) == PLUS || GET_CODE (x) == MINUS
571090075Sobrien	  || GET_CODE (x) == AND || GET_CODE (x) == IOR
571190075Sobrien	  || GET_CODE (x) == XOR || GET_CODE (x) == MULT
571290075Sobrien	  || GET_CODE (x) == NOT || GET_CODE (x) == NEG
571390075Sobrien	  || GET_CODE (x) == LSHIFTRT
571490075Sobrien	  || GET_CODE (x) == ASHIFT || GET_CODE (x) == ASHIFTRT
5715132718Skan	  || GET_CODE (x) == ROTATERT
5716132718Skan	  || (TARGET_ARM && GET_CODE (x) == ZERO_EXTRACT)))
571790075Sobrien    return CC_NOOVmode;
571890075Sobrien
571990075Sobrien  if (GET_MODE (x) == QImode && (op == EQ || op == NE))
572090075Sobrien    return CC_Zmode;
572190075Sobrien
572290075Sobrien  if (GET_MODE (x) == SImode && (op == LTU || op == GEU)
572390075Sobrien      && GET_CODE (x) == PLUS
572490075Sobrien      && (rtx_equal_p (XEXP (x, 0), y) || rtx_equal_p (XEXP (x, 1), y)))
572590075Sobrien    return CC_Cmode;
572690075Sobrien
572790075Sobrien  return CCmode;
572890075Sobrien}
572990075Sobrien
573090075Sobrien/* X and Y are two things to compare using CODE.  Emit the compare insn and
573190075Sobrien   return the rtx for register 0 in the proper mode.  FP means this is a
573290075Sobrien   floating point compare: I don't think that it is needed on the arm.  */
573390075Sobrienrtx
5734132718Skanarm_gen_compare_reg (enum rtx_code code, rtx x, rtx y)
573590075Sobrien{
573690075Sobrien  enum machine_mode mode = SELECT_CC_MODE (code, x, y);
573790075Sobrien  rtx cc_reg = gen_rtx_REG (mode, CC_REGNUM);
573890075Sobrien
573990075Sobrien  emit_insn (gen_rtx_SET (VOIDmode, cc_reg,
574090075Sobrien			  gen_rtx_COMPARE (mode, x, y)));
574190075Sobrien
574290075Sobrien  return cc_reg;
574390075Sobrien}
574490075Sobrien
5745117395Skan/* Generate a sequence of insns that will generate the correct return
5746117395Skan   address mask depending on the physical architecture that the program
5747117395Skan   is running on.  */
5748117395Skanrtx
5749132718Skanarm_gen_return_addr_mask (void)
5750117395Skan{
5751117395Skan  rtx reg = gen_reg_rtx (Pmode);
5752117395Skan
5753117395Skan  emit_insn (gen_return_addr_mask (reg));
5754117395Skan  return reg;
5755117395Skan}
5756117395Skan
575790075Sobrienvoid
5758132718Skanarm_reload_in_hi (rtx *operands)
575990075Sobrien{
576090075Sobrien  rtx ref = operands[1];
576190075Sobrien  rtx base, scratch;
576290075Sobrien  HOST_WIDE_INT offset = 0;
576390075Sobrien
576490075Sobrien  if (GET_CODE (ref) == SUBREG)
576590075Sobrien    {
576690075Sobrien      offset = SUBREG_BYTE (ref);
576790075Sobrien      ref = SUBREG_REG (ref);
576890075Sobrien    }
576990075Sobrien
577090075Sobrien  if (GET_CODE (ref) == REG)
577190075Sobrien    {
577290075Sobrien      /* We have a pseudo which has been spilt onto the stack; there
577390075Sobrien	 are two cases here: the first where there is a simple
577490075Sobrien	 stack-slot replacement and a second where the stack-slot is
577590075Sobrien	 out of range, or is used as a subreg.  */
577690075Sobrien      if (reg_equiv_mem[REGNO (ref)])
577790075Sobrien	{
577890075Sobrien	  ref = reg_equiv_mem[REGNO (ref)];
577990075Sobrien	  base = find_replacement (&XEXP (ref, 0));
578090075Sobrien	}
578190075Sobrien      else
578290075Sobrien	/* The slot is out of range, or was dressed up in a SUBREG.  */
578390075Sobrien	base = reg_equiv_address[REGNO (ref)];
578490075Sobrien    }
578590075Sobrien  else
578690075Sobrien    base = find_replacement (&XEXP (ref, 0));
578790075Sobrien
578890075Sobrien  /* Handle the case where the address is too complex to be offset by 1.  */
578990075Sobrien  if (GET_CODE (base) == MINUS
579090075Sobrien      || (GET_CODE (base) == PLUS && GET_CODE (XEXP (base, 1)) != CONST_INT))
579190075Sobrien    {
579290075Sobrien      rtx base_plus = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
579390075Sobrien
579490075Sobrien      emit_insn (gen_rtx_SET (VOIDmode, base_plus, base));
579590075Sobrien      base = base_plus;
579690075Sobrien    }
579790075Sobrien  else if (GET_CODE (base) == PLUS)
579890075Sobrien    {
579990075Sobrien      /* The addend must be CONST_INT, or we would have dealt with it above.  */
580090075Sobrien      HOST_WIDE_INT hi, lo;
580190075Sobrien
580290075Sobrien      offset += INTVAL (XEXP (base, 1));
580390075Sobrien      base = XEXP (base, 0);
580490075Sobrien
580590075Sobrien      /* Rework the address into a legal sequence of insns.  */
580690075Sobrien      /* Valid range for lo is -4095 -> 4095 */
580790075Sobrien      lo = (offset >= 0
580890075Sobrien	    ? (offset & 0xfff)
580990075Sobrien	    : -((-offset) & 0xfff));
581090075Sobrien
581190075Sobrien      /* Corner case, if lo is the max offset then we would be out of range
581290075Sobrien	 once we have added the additional 1 below, so bump the msb into the
581390075Sobrien	 pre-loading insn(s).  */
581490075Sobrien      if (lo == 4095)
581590075Sobrien	lo &= 0x7ff;
581690075Sobrien
581790075Sobrien      hi = ((((offset - lo) & (HOST_WIDE_INT) 0xffffffff)
581890075Sobrien	     ^ (HOST_WIDE_INT) 0x80000000)
581990075Sobrien	    - (HOST_WIDE_INT) 0x80000000);
582090075Sobrien
582190075Sobrien      if (hi + lo != offset)
582290075Sobrien	abort ();
582390075Sobrien
582490075Sobrien      if (hi != 0)
582590075Sobrien	{
582690075Sobrien	  rtx base_plus = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
582790075Sobrien
582890075Sobrien	  /* Get the base address; addsi3 knows how to handle constants
582990075Sobrien	     that require more than one insn.  */
583090075Sobrien	  emit_insn (gen_addsi3 (base_plus, base, GEN_INT (hi)));
583190075Sobrien	  base = base_plus;
583290075Sobrien	  offset = lo;
583390075Sobrien	}
583490075Sobrien    }
583590075Sobrien
5836117395Skan  /* Operands[2] may overlap operands[0] (though it won't overlap
5837117395Skan     operands[1]), that's why we asked for a DImode reg -- so we can
5838117395Skan     use the bit that does not overlap.  */
5839117395Skan  if (REGNO (operands[2]) == REGNO (operands[0]))
5840117395Skan    scratch = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
5841117395Skan  else
5842117395Skan    scratch = gen_rtx_REG (SImode, REGNO (operands[2]));
5843117395Skan
584490075Sobrien  emit_insn (gen_zero_extendqisi2 (scratch,
584590075Sobrien				   gen_rtx_MEM (QImode,
584690075Sobrien						plus_constant (base,
584790075Sobrien							       offset))));
584890075Sobrien  emit_insn (gen_zero_extendqisi2 (gen_rtx_SUBREG (SImode, operands[0], 0),
584990075Sobrien				   gen_rtx_MEM (QImode,
585090075Sobrien						plus_constant (base,
585190075Sobrien							       offset + 1))));
585290075Sobrien  if (!BYTES_BIG_ENDIAN)
585390075Sobrien    emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_SUBREG (SImode, operands[0], 0),
585490075Sobrien			gen_rtx_IOR (SImode,
585590075Sobrien				     gen_rtx_ASHIFT
585690075Sobrien				     (SImode,
585790075Sobrien				      gen_rtx_SUBREG (SImode, operands[0], 0),
585890075Sobrien				      GEN_INT (8)),
585990075Sobrien				     scratch)));
586090075Sobrien  else
586190075Sobrien    emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_SUBREG (SImode, operands[0], 0),
586290075Sobrien			    gen_rtx_IOR (SImode,
586390075Sobrien					 gen_rtx_ASHIFT (SImode, scratch,
586490075Sobrien							 GEN_INT (8)),
586590075Sobrien					 gen_rtx_SUBREG (SImode, operands[0],
586690075Sobrien							 0))));
586790075Sobrien}
586890075Sobrien
5869132718Skan/* Handle storing a half-word to memory during reload by synthesizing as two
587090075Sobrien   byte stores.  Take care not to clobber the input values until after we
587190075Sobrien   have moved them somewhere safe.  This code assumes that if the DImode
587290075Sobrien   scratch in operands[2] overlaps either the input value or output address
587390075Sobrien   in some way, then that value must die in this insn (we absolutely need
587490075Sobrien   two scratch registers for some corner cases).  */
587590075Sobrienvoid
5876132718Skanarm_reload_out_hi (rtx *operands)
587790075Sobrien{
587890075Sobrien  rtx ref = operands[0];
587990075Sobrien  rtx outval = operands[1];
588090075Sobrien  rtx base, scratch;
588190075Sobrien  HOST_WIDE_INT offset = 0;
588290075Sobrien
588390075Sobrien  if (GET_CODE (ref) == SUBREG)
588490075Sobrien    {
588590075Sobrien      offset = SUBREG_BYTE (ref);
588690075Sobrien      ref = SUBREG_REG (ref);
588790075Sobrien    }
588890075Sobrien
588990075Sobrien  if (GET_CODE (ref) == REG)
589090075Sobrien    {
589190075Sobrien      /* We have a pseudo which has been spilt onto the stack; there
589290075Sobrien	 are two cases here: the first where there is a simple
589390075Sobrien	 stack-slot replacement and a second where the stack-slot is
589490075Sobrien	 out of range, or is used as a subreg.  */
589590075Sobrien      if (reg_equiv_mem[REGNO (ref)])
589690075Sobrien	{
589790075Sobrien	  ref = reg_equiv_mem[REGNO (ref)];
589890075Sobrien	  base = find_replacement (&XEXP (ref, 0));
589990075Sobrien	}
590090075Sobrien      else
590190075Sobrien	/* The slot is out of range, or was dressed up in a SUBREG.  */
590290075Sobrien	base = reg_equiv_address[REGNO (ref)];
590390075Sobrien    }
590490075Sobrien  else
590590075Sobrien    base = find_replacement (&XEXP (ref, 0));
590690075Sobrien
590790075Sobrien  scratch = gen_rtx_REG (SImode, REGNO (operands[2]));
590890075Sobrien
590990075Sobrien  /* Handle the case where the address is too complex to be offset by 1.  */
591090075Sobrien  if (GET_CODE (base) == MINUS
591190075Sobrien      || (GET_CODE (base) == PLUS && GET_CODE (XEXP (base, 1)) != CONST_INT))
591290075Sobrien    {
591390075Sobrien      rtx base_plus = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
591490075Sobrien
591590075Sobrien      /* Be careful not to destroy OUTVAL.  */
591690075Sobrien      if (reg_overlap_mentioned_p (base_plus, outval))
591790075Sobrien	{
591890075Sobrien	  /* Updating base_plus might destroy outval, see if we can
591990075Sobrien	     swap the scratch and base_plus.  */
592090075Sobrien	  if (!reg_overlap_mentioned_p (scratch, outval))
592190075Sobrien	    {
592290075Sobrien	      rtx tmp = scratch;
592390075Sobrien	      scratch = base_plus;
592490075Sobrien	      base_plus = tmp;
592590075Sobrien	    }
592690075Sobrien	  else
592790075Sobrien	    {
592890075Sobrien	      rtx scratch_hi = gen_rtx_REG (HImode, REGNO (operands[2]));
592990075Sobrien
593090075Sobrien	      /* Be conservative and copy OUTVAL into the scratch now,
593190075Sobrien		 this should only be necessary if outval is a subreg
593290075Sobrien		 of something larger than a word.  */
593390075Sobrien	      /* XXX Might this clobber base?  I can't see how it can,
593490075Sobrien		 since scratch is known to overlap with OUTVAL, and
593590075Sobrien		 must be wider than a word.  */
593690075Sobrien	      emit_insn (gen_movhi (scratch_hi, outval));
593790075Sobrien	      outval = scratch_hi;
593890075Sobrien	    }
593990075Sobrien	}
594090075Sobrien
594190075Sobrien      emit_insn (gen_rtx_SET (VOIDmode, base_plus, base));
594290075Sobrien      base = base_plus;
594390075Sobrien    }
594490075Sobrien  else if (GET_CODE (base) == PLUS)
594590075Sobrien    {
594690075Sobrien      /* The addend must be CONST_INT, or we would have dealt with it above.  */
594790075Sobrien      HOST_WIDE_INT hi, lo;
594890075Sobrien
594990075Sobrien      offset += INTVAL (XEXP (base, 1));
595090075Sobrien      base = XEXP (base, 0);
595190075Sobrien
595290075Sobrien      /* Rework the address into a legal sequence of insns.  */
595390075Sobrien      /* Valid range for lo is -4095 -> 4095 */
595490075Sobrien      lo = (offset >= 0
595590075Sobrien	    ? (offset & 0xfff)
595690075Sobrien	    : -((-offset) & 0xfff));
595790075Sobrien
595890075Sobrien      /* Corner case, if lo is the max offset then we would be out of range
595990075Sobrien	 once we have added the additional 1 below, so bump the msb into the
596090075Sobrien	 pre-loading insn(s).  */
596190075Sobrien      if (lo == 4095)
596290075Sobrien	lo &= 0x7ff;
596390075Sobrien
596490075Sobrien      hi = ((((offset - lo) & (HOST_WIDE_INT) 0xffffffff)
596590075Sobrien	     ^ (HOST_WIDE_INT) 0x80000000)
596690075Sobrien	    - (HOST_WIDE_INT) 0x80000000);
596790075Sobrien
596890075Sobrien      if (hi + lo != offset)
596990075Sobrien	abort ();
597090075Sobrien
597190075Sobrien      if (hi != 0)
597290075Sobrien	{
597390075Sobrien	  rtx base_plus = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
597490075Sobrien
597590075Sobrien	  /* Be careful not to destroy OUTVAL.  */
597690075Sobrien	  if (reg_overlap_mentioned_p (base_plus, outval))
597790075Sobrien	    {
597890075Sobrien	      /* Updating base_plus might destroy outval, see if we
597990075Sobrien		 can swap the scratch and base_plus.  */
598090075Sobrien	      if (!reg_overlap_mentioned_p (scratch, outval))
598190075Sobrien		{
598290075Sobrien		  rtx tmp = scratch;
598390075Sobrien		  scratch = base_plus;
598490075Sobrien		  base_plus = tmp;
598590075Sobrien		}
598690075Sobrien	      else
598790075Sobrien		{
598890075Sobrien		  rtx scratch_hi = gen_rtx_REG (HImode, REGNO (operands[2]));
598990075Sobrien
599090075Sobrien		  /* Be conservative and copy outval into scratch now,
599190075Sobrien		     this should only be necessary if outval is a
599290075Sobrien		     subreg of something larger than a word.  */
599390075Sobrien		  /* XXX Might this clobber base?  I can't see how it
599490075Sobrien		     can, since scratch is known to overlap with
599590075Sobrien		     outval.  */
599690075Sobrien		  emit_insn (gen_movhi (scratch_hi, outval));
599790075Sobrien		  outval = scratch_hi;
599890075Sobrien		}
599990075Sobrien	    }
600090075Sobrien
600190075Sobrien	  /* Get the base address; addsi3 knows how to handle constants
600290075Sobrien	     that require more than one insn.  */
600390075Sobrien	  emit_insn (gen_addsi3 (base_plus, base, GEN_INT (hi)));
600490075Sobrien	  base = base_plus;
600590075Sobrien	  offset = lo;
600690075Sobrien	}
600790075Sobrien    }
600890075Sobrien
600990075Sobrien  if (BYTES_BIG_ENDIAN)
601090075Sobrien    {
601190075Sobrien      emit_insn (gen_movqi (gen_rtx_MEM (QImode,
601290075Sobrien					 plus_constant (base, offset + 1)),
6013102780Skan			    gen_lowpart (QImode, outval)));
601490075Sobrien      emit_insn (gen_lshrsi3 (scratch,
601590075Sobrien			      gen_rtx_SUBREG (SImode, outval, 0),
601690075Sobrien			      GEN_INT (8)));
601790075Sobrien      emit_insn (gen_movqi (gen_rtx_MEM (QImode, plus_constant (base, offset)),
6018102780Skan			    gen_lowpart (QImode, scratch)));
601990075Sobrien    }
602090075Sobrien  else
602190075Sobrien    {
602290075Sobrien      emit_insn (gen_movqi (gen_rtx_MEM (QImode, plus_constant (base, offset)),
6023102780Skan			    gen_lowpart (QImode, outval)));
602490075Sobrien      emit_insn (gen_lshrsi3 (scratch,
602590075Sobrien			      gen_rtx_SUBREG (SImode, outval, 0),
602690075Sobrien			      GEN_INT (8)));
602790075Sobrien      emit_insn (gen_movqi (gen_rtx_MEM (QImode,
602890075Sobrien					 plus_constant (base, offset + 1)),
6029102780Skan			    gen_lowpart (QImode, scratch)));
603090075Sobrien    }
603190075Sobrien}
603290075Sobrien
603390075Sobrien/* Print a symbolic form of X to the debug file, F.  */
603490075Sobrienstatic void
6035132718Skanarm_print_value (FILE *f, rtx x)
603690075Sobrien{
603790075Sobrien  switch (GET_CODE (x))
603890075Sobrien    {
603990075Sobrien    case CONST_INT:
604090075Sobrien      fprintf (f, HOST_WIDE_INT_PRINT_HEX, INTVAL (x));
604190075Sobrien      return;
604290075Sobrien
604390075Sobrien    case CONST_DOUBLE:
604490075Sobrien      fprintf (f, "<0x%lx,0x%lx>", (long)XWINT (x, 2), (long)XWINT (x, 3));
604590075Sobrien      return;
604690075Sobrien
6047132718Skan    case CONST_VECTOR:
6048132718Skan      {
6049132718Skan	int i;
6050132718Skan
6051132718Skan	fprintf (f, "<");
6052132718Skan	for (i = 0; i < CONST_VECTOR_NUNITS (x); i++)
6053132718Skan	  {
6054132718Skan	    fprintf (f, HOST_WIDE_INT_PRINT_HEX, INTVAL (CONST_VECTOR_ELT (x, i)));
6055132718Skan	    if (i < (CONST_VECTOR_NUNITS (x) - 1))
6056132718Skan	      fputc (',', f);
6057132718Skan	  }
6058132718Skan	fprintf (f, ">");
6059132718Skan      }
6060132718Skan      return;
6061132718Skan
606290075Sobrien    case CONST_STRING:
606390075Sobrien      fprintf (f, "\"%s\"", XSTR (x, 0));
606490075Sobrien      return;
606590075Sobrien
606690075Sobrien    case SYMBOL_REF:
606790075Sobrien      fprintf (f, "`%s'", XSTR (x, 0));
606890075Sobrien      return;
606990075Sobrien
607090075Sobrien    case LABEL_REF:
607190075Sobrien      fprintf (f, "L%d", INSN_UID (XEXP (x, 0)));
607290075Sobrien      return;
607390075Sobrien
607490075Sobrien    case CONST:
607590075Sobrien      arm_print_value (f, XEXP (x, 0));
607690075Sobrien      return;
607790075Sobrien
607890075Sobrien    case PLUS:
607990075Sobrien      arm_print_value (f, XEXP (x, 0));
608090075Sobrien      fprintf (f, "+");
608190075Sobrien      arm_print_value (f, XEXP (x, 1));
608290075Sobrien      return;
608390075Sobrien
608490075Sobrien    case PC:
608590075Sobrien      fprintf (f, "pc");
608690075Sobrien      return;
608790075Sobrien
608890075Sobrien    default:
608990075Sobrien      fprintf (f, "????");
609090075Sobrien      return;
609190075Sobrien    }
609290075Sobrien}
609390075Sobrien
609490075Sobrien/* Routines for manipulation of the constant pool.  */
609590075Sobrien
609690075Sobrien/* Arm instructions cannot load a large constant directly into a
609790075Sobrien   register; they have to come from a pc relative load.  The constant
609890075Sobrien   must therefore be placed in the addressable range of the pc
609990075Sobrien   relative load.  Depending on the precise pc relative load
610090075Sobrien   instruction the range is somewhere between 256 bytes and 4k.  This
610190075Sobrien   means that we often have to dump a constant inside a function, and
610290075Sobrien   generate code to branch around it.
610390075Sobrien
610490075Sobrien   It is important to minimize this, since the branches will slow
610590075Sobrien   things down and make the code larger.
610690075Sobrien
610790075Sobrien   Normally we can hide the table after an existing unconditional
610890075Sobrien   branch so that there is no interruption of the flow, but in the
610990075Sobrien   worst case the code looks like this:
611090075Sobrien
611190075Sobrien	ldr	rn, L1
611290075Sobrien	...
611390075Sobrien	b	L2
611490075Sobrien	align
611590075Sobrien	L1:	.long value
611690075Sobrien	L2:
611790075Sobrien	...
611890075Sobrien
611990075Sobrien	ldr	rn, L3
612090075Sobrien	...
612190075Sobrien	b	L4
612290075Sobrien	align
612390075Sobrien	L3:	.long value
612490075Sobrien	L4:
612590075Sobrien	...
612690075Sobrien
612790075Sobrien   We fix this by performing a scan after scheduling, which notices
612890075Sobrien   which instructions need to have their operands fetched from the
612990075Sobrien   constant table and builds the table.
613090075Sobrien
613190075Sobrien   The algorithm starts by building a table of all the constants that
613290075Sobrien   need fixing up and all the natural barriers in the function (places
613390075Sobrien   where a constant table can be dropped without breaking the flow).
613490075Sobrien   For each fixup we note how far the pc-relative replacement will be
613590075Sobrien   able to reach and the offset of the instruction into the function.
613690075Sobrien
613790075Sobrien   Having built the table we then group the fixes together to form
613890075Sobrien   tables that are as large as possible (subject to addressing
613990075Sobrien   constraints) and emit each table of constants after the last
614090075Sobrien   barrier that is within range of all the instructions in the group.
614190075Sobrien   If a group does not contain a barrier, then we forcibly create one
614290075Sobrien   by inserting a jump instruction into the flow.  Once the table has
614390075Sobrien   been inserted, the insns are then modified to reference the
614490075Sobrien   relevant entry in the pool.
614590075Sobrien
614690075Sobrien   Possible enhancements to the algorithm (not implemented) are:
614790075Sobrien
614890075Sobrien   1) For some processors and object formats, there may be benefit in
614990075Sobrien   aligning the pools to the start of cache lines; this alignment
615090075Sobrien   would need to be taken into account when calculating addressability
615190075Sobrien   of a pool.  */
615290075Sobrien
615390075Sobrien/* These typedefs are located at the start of this file, so that
615490075Sobrien   they can be used in the prototypes there.  This comment is to
615590075Sobrien   remind readers of that fact so that the following structures
615690075Sobrien   can be understood more easily.
615790075Sobrien
615890075Sobrien     typedef struct minipool_node    Mnode;
615990075Sobrien     typedef struct minipool_fixup   Mfix;  */
616090075Sobrien
616190075Sobrienstruct minipool_node
616290075Sobrien{
616390075Sobrien  /* Doubly linked chain of entries.  */
616490075Sobrien  Mnode * next;
616590075Sobrien  Mnode * prev;
616690075Sobrien  /* The maximum offset into the code that this entry can be placed.  While
616790075Sobrien     pushing fixes for forward references, all entries are sorted in order
616890075Sobrien     of increasing max_address.  */
616990075Sobrien  HOST_WIDE_INT max_address;
617090075Sobrien  /* Similarly for an entry inserted for a backwards ref.  */
617190075Sobrien  HOST_WIDE_INT min_address;
617290075Sobrien  /* The number of fixes referencing this entry.  This can become zero
617390075Sobrien     if we "unpush" an entry.  In this case we ignore the entry when we
617490075Sobrien     come to emit the code.  */
617590075Sobrien  int refcount;
617690075Sobrien  /* The offset from the start of the minipool.  */
617790075Sobrien  HOST_WIDE_INT offset;
617890075Sobrien  /* The value in table.  */
617990075Sobrien  rtx value;
618090075Sobrien  /* The mode of value.  */
618190075Sobrien  enum machine_mode mode;
6182132718Skan  /* The size of the value.  With iWMMXt enabled
6183132718Skan     sizes > 4 also imply an alignment of 8-bytes.  */
618490075Sobrien  int fix_size;
618590075Sobrien};
618690075Sobrien
618790075Sobrienstruct minipool_fixup
618890075Sobrien{
618990075Sobrien  Mfix *            next;
619090075Sobrien  rtx               insn;
619190075Sobrien  HOST_WIDE_INT     address;
619290075Sobrien  rtx *             loc;
619390075Sobrien  enum machine_mode mode;
619490075Sobrien  int               fix_size;
619590075Sobrien  rtx               value;
619690075Sobrien  Mnode *           minipool;
619790075Sobrien  HOST_WIDE_INT     forwards;
619890075Sobrien  HOST_WIDE_INT     backwards;
619990075Sobrien};
620090075Sobrien
620190075Sobrien/* Fixes less than a word need padding out to a word boundary.  */
620290075Sobrien#define MINIPOOL_FIX_SIZE(mode) \
620390075Sobrien  (GET_MODE_SIZE ((mode)) >= 4 ? GET_MODE_SIZE ((mode)) : 4)
620490075Sobrien
620590075Sobrienstatic Mnode *	minipool_vector_head;
620690075Sobrienstatic Mnode *	minipool_vector_tail;
620790075Sobrienstatic rtx	minipool_vector_label;
620890075Sobrien
620990075Sobrien/* The linked list of all minipool fixes required for this function.  */
621090075SobrienMfix * 		minipool_fix_head;
621190075SobrienMfix * 		minipool_fix_tail;
621290075Sobrien/* The fix entry for the current minipool, once it has been placed.  */
621390075SobrienMfix *		minipool_barrier;
621490075Sobrien
621590075Sobrien/* Determines if INSN is the start of a jump table.  Returns the end
621690075Sobrien   of the TABLE or NULL_RTX.  */
621790075Sobrienstatic rtx
6218132718Skanis_jump_table (rtx insn)
621990075Sobrien{
622090075Sobrien  rtx table;
622190075Sobrien
622290075Sobrien  if (GET_CODE (insn) == JUMP_INSN
622390075Sobrien      && JUMP_LABEL (insn) != NULL
622490075Sobrien      && ((table = next_real_insn (JUMP_LABEL (insn)))
622590075Sobrien	  == next_real_insn (insn))
622690075Sobrien      && table != NULL
622790075Sobrien      && GET_CODE (table) == JUMP_INSN
622890075Sobrien      && (GET_CODE (PATTERN (table)) == ADDR_VEC
622990075Sobrien	  || GET_CODE (PATTERN (table)) == ADDR_DIFF_VEC))
623090075Sobrien    return table;
623190075Sobrien
623290075Sobrien  return NULL_RTX;
623390075Sobrien}
623490075Sobrien
623596263Sobrien#ifndef JUMP_TABLES_IN_TEXT_SECTION
623696263Sobrien#define JUMP_TABLES_IN_TEXT_SECTION 0
623796263Sobrien#endif
623896263Sobrien
623990075Sobrienstatic HOST_WIDE_INT
6240132718Skanget_jump_table_size (rtx insn)
624190075Sobrien{
624296263Sobrien  /* ADDR_VECs only take room if read-only data does into the text
624396263Sobrien     section.  */
624496263Sobrien  if (JUMP_TABLES_IN_TEXT_SECTION
6245117395Skan#if !defined(READONLY_DATA_SECTION) && !defined(READONLY_DATA_SECTION_ASM_OP)
624696263Sobrien      || 1
624796263Sobrien#endif
624896263Sobrien      )
624996263Sobrien    {
625096263Sobrien      rtx body = PATTERN (insn);
625196263Sobrien      int elt = GET_CODE (body) == ADDR_DIFF_VEC ? 1 : 0;
625290075Sobrien
625396263Sobrien      return GET_MODE_SIZE (GET_MODE (body)) * XVECLEN (body, elt);
625496263Sobrien    }
625596263Sobrien
625696263Sobrien  return 0;
625790075Sobrien}
625890075Sobrien
625990075Sobrien/* Move a minipool fix MP from its current location to before MAX_MP.
626090075Sobrien   If MAX_MP is NULL, then MP doesn't need moving, but the addressing
6261132718Skan   constraints may need updating.  */
626290075Sobrienstatic Mnode *
6263132718Skanmove_minipool_fix_forward_ref (Mnode *mp, Mnode *max_mp,
6264132718Skan			       HOST_WIDE_INT max_address)
626590075Sobrien{
626690075Sobrien  /* This should never be true and the code below assumes these are
626790075Sobrien     different.  */
626890075Sobrien  if (mp == max_mp)
626990075Sobrien    abort ();
627090075Sobrien
627190075Sobrien  if (max_mp == NULL)
627290075Sobrien    {
627390075Sobrien      if (max_address < mp->max_address)
627490075Sobrien	mp->max_address = max_address;
627590075Sobrien    }
627690075Sobrien  else
627790075Sobrien    {
627890075Sobrien      if (max_address > max_mp->max_address - mp->fix_size)
627990075Sobrien	mp->max_address = max_mp->max_address - mp->fix_size;
628090075Sobrien      else
628190075Sobrien	mp->max_address = max_address;
628290075Sobrien
628390075Sobrien      /* Unlink MP from its current position.  Since max_mp is non-null,
628490075Sobrien       mp->prev must be non-null.  */
628590075Sobrien      mp->prev->next = mp->next;
628690075Sobrien      if (mp->next != NULL)
628790075Sobrien	mp->next->prev = mp->prev;
628890075Sobrien      else
628990075Sobrien	minipool_vector_tail = mp->prev;
629090075Sobrien
629190075Sobrien      /* Re-insert it before MAX_MP.  */
629290075Sobrien      mp->next = max_mp;
629390075Sobrien      mp->prev = max_mp->prev;
629490075Sobrien      max_mp->prev = mp;
629590075Sobrien
629690075Sobrien      if (mp->prev != NULL)
629790075Sobrien	mp->prev->next = mp;
629890075Sobrien      else
629990075Sobrien	minipool_vector_head = mp;
630090075Sobrien    }
630190075Sobrien
630290075Sobrien  /* Save the new entry.  */
630390075Sobrien  max_mp = mp;
630490075Sobrien
630590075Sobrien  /* Scan over the preceding entries and adjust their addresses as
630690075Sobrien     required.  */
630790075Sobrien  while (mp->prev != NULL
630890075Sobrien	 && mp->prev->max_address > mp->max_address - mp->prev->fix_size)
630990075Sobrien    {
631090075Sobrien      mp->prev->max_address = mp->max_address - mp->prev->fix_size;
631190075Sobrien      mp = mp->prev;
631290075Sobrien    }
631390075Sobrien
631490075Sobrien  return max_mp;
631590075Sobrien}
631690075Sobrien
631790075Sobrien/* Add a constant to the minipool for a forward reference.  Returns the
631890075Sobrien   node added or NULL if the constant will not fit in this pool.  */
631990075Sobrienstatic Mnode *
6320132718Skanadd_minipool_forward_ref (Mfix *fix)
632190075Sobrien{
632290075Sobrien  /* If set, max_mp is the first pool_entry that has a lower
632390075Sobrien     constraint than the one we are trying to add.  */
632490075Sobrien  Mnode *       max_mp = NULL;
632590075Sobrien  HOST_WIDE_INT max_address = fix->address + fix->forwards;
632690075Sobrien  Mnode *       mp;
632790075Sobrien
632890075Sobrien  /* If this fix's address is greater than the address of the first
632990075Sobrien     entry, then we can't put the fix in this pool.  We subtract the
633090075Sobrien     size of the current fix to ensure that if the table is fully
633190075Sobrien     packed we still have enough room to insert this value by suffling
633290075Sobrien     the other fixes forwards.  */
633390075Sobrien  if (minipool_vector_head &&
633490075Sobrien      fix->address >= minipool_vector_head->max_address - fix->fix_size)
633590075Sobrien    return NULL;
633690075Sobrien
633790075Sobrien  /* Scan the pool to see if a constant with the same value has
633890075Sobrien     already been added.  While we are doing this, also note the
633990075Sobrien     location where we must insert the constant if it doesn't already
634090075Sobrien     exist.  */
634190075Sobrien  for (mp = minipool_vector_head; mp != NULL; mp = mp->next)
634290075Sobrien    {
634390075Sobrien      if (GET_CODE (fix->value) == GET_CODE (mp->value)
634490075Sobrien	  && fix->mode == mp->mode
634590075Sobrien	  && (GET_CODE (fix->value) != CODE_LABEL
634690075Sobrien	      || (CODE_LABEL_NUMBER (fix->value)
634790075Sobrien		  == CODE_LABEL_NUMBER (mp->value)))
634890075Sobrien	  && rtx_equal_p (fix->value, mp->value))
634990075Sobrien	{
635090075Sobrien	  /* More than one fix references this entry.  */
635190075Sobrien	  mp->refcount++;
635290075Sobrien	  return move_minipool_fix_forward_ref (mp, max_mp, max_address);
635390075Sobrien	}
635490075Sobrien
635590075Sobrien      /* Note the insertion point if necessary.  */
635690075Sobrien      if (max_mp == NULL
635790075Sobrien	  && mp->max_address > max_address)
635890075Sobrien	max_mp = mp;
6359132718Skan
6360132718Skan      /* If we are inserting an 8-bytes aligned quantity and
6361132718Skan	 we have not already found an insertion point, then
6362132718Skan	 make sure that all such 8-byte aligned quantities are
6363132718Skan	 placed at the start of the pool.  */
6364132718Skan      if (TARGET_REALLY_IWMMXT
6365132718Skan	  && max_mp == NULL
6366132718Skan	  && fix->fix_size == 8
6367132718Skan	  && mp->fix_size != 8)
6368132718Skan	{
6369132718Skan	  max_mp = mp;
6370132718Skan	  max_address = mp->max_address;
6371132718Skan	}
637290075Sobrien    }
637390075Sobrien
637490075Sobrien  /* The value is not currently in the minipool, so we need to create
637590075Sobrien     a new entry for it.  If MAX_MP is NULL, the entry will be put on
637690075Sobrien     the end of the list since the placement is less constrained than
637790075Sobrien     any existing entry.  Otherwise, we insert the new fix before
6378132718Skan     MAX_MP and, if necessary, adjust the constraints on the other
637990075Sobrien     entries.  */
638090075Sobrien  mp = xmalloc (sizeof (* mp));
638190075Sobrien  mp->fix_size = fix->fix_size;
638290075Sobrien  mp->mode = fix->mode;
638390075Sobrien  mp->value = fix->value;
638490075Sobrien  mp->refcount = 1;
638590075Sobrien  /* Not yet required for a backwards ref.  */
638690075Sobrien  mp->min_address = -65536;
638790075Sobrien
638890075Sobrien  if (max_mp == NULL)
638990075Sobrien    {
639090075Sobrien      mp->max_address = max_address;
639190075Sobrien      mp->next = NULL;
639290075Sobrien      mp->prev = minipool_vector_tail;
639390075Sobrien
639490075Sobrien      if (mp->prev == NULL)
639590075Sobrien	{
639690075Sobrien	  minipool_vector_head = mp;
639790075Sobrien	  minipool_vector_label = gen_label_rtx ();
639890075Sobrien	}
639990075Sobrien      else
640090075Sobrien	mp->prev->next = mp;
640190075Sobrien
640290075Sobrien      minipool_vector_tail = mp;
640390075Sobrien    }
640490075Sobrien  else
640590075Sobrien    {
640690075Sobrien      if (max_address > max_mp->max_address - mp->fix_size)
640790075Sobrien	mp->max_address = max_mp->max_address - mp->fix_size;
640890075Sobrien      else
640990075Sobrien	mp->max_address = max_address;
641090075Sobrien
641190075Sobrien      mp->next = max_mp;
641290075Sobrien      mp->prev = max_mp->prev;
641390075Sobrien      max_mp->prev = mp;
641490075Sobrien      if (mp->prev != NULL)
641590075Sobrien	mp->prev->next = mp;
641690075Sobrien      else
641790075Sobrien	minipool_vector_head = mp;
641890075Sobrien    }
641990075Sobrien
642090075Sobrien  /* Save the new entry.  */
642190075Sobrien  max_mp = mp;
642290075Sobrien
642390075Sobrien  /* Scan over the preceding entries and adjust their addresses as
642490075Sobrien     required.  */
642590075Sobrien  while (mp->prev != NULL
642690075Sobrien	 && mp->prev->max_address > mp->max_address - mp->prev->fix_size)
642790075Sobrien    {
642890075Sobrien      mp->prev->max_address = mp->max_address - mp->prev->fix_size;
642990075Sobrien      mp = mp->prev;
643090075Sobrien    }
643190075Sobrien
643290075Sobrien  return max_mp;
643390075Sobrien}
643490075Sobrien
643590075Sobrienstatic Mnode *
6436132718Skanmove_minipool_fix_backward_ref (Mnode *mp, Mnode *min_mp,
6437132718Skan				HOST_WIDE_INT  min_address)
643890075Sobrien{
643990075Sobrien  HOST_WIDE_INT offset;
644090075Sobrien
644190075Sobrien  /* This should never be true, and the code below assumes these are
644290075Sobrien     different.  */
644390075Sobrien  if (mp == min_mp)
644490075Sobrien    abort ();
644590075Sobrien
644690075Sobrien  if (min_mp == NULL)
644790075Sobrien    {
644890075Sobrien      if (min_address > mp->min_address)
644990075Sobrien	mp->min_address = min_address;
645090075Sobrien    }
645190075Sobrien  else
645290075Sobrien    {
645390075Sobrien      /* We will adjust this below if it is too loose.  */
645490075Sobrien      mp->min_address = min_address;
645590075Sobrien
645690075Sobrien      /* Unlink MP from its current position.  Since min_mp is non-null,
645790075Sobrien	 mp->next must be non-null.  */
645890075Sobrien      mp->next->prev = mp->prev;
645990075Sobrien      if (mp->prev != NULL)
646090075Sobrien	mp->prev->next = mp->next;
646190075Sobrien      else
646290075Sobrien	minipool_vector_head = mp->next;
646390075Sobrien
646490075Sobrien      /* Reinsert it after MIN_MP.  */
646590075Sobrien      mp->prev = min_mp;
646690075Sobrien      mp->next = min_mp->next;
646790075Sobrien      min_mp->next = mp;
646890075Sobrien      if (mp->next != NULL)
646990075Sobrien	mp->next->prev = mp;
647090075Sobrien      else
647190075Sobrien	minipool_vector_tail = mp;
647290075Sobrien    }
647390075Sobrien
647490075Sobrien  min_mp = mp;
647590075Sobrien
647690075Sobrien  offset = 0;
647790075Sobrien  for (mp = minipool_vector_head; mp != NULL; mp = mp->next)
647890075Sobrien    {
647990075Sobrien      mp->offset = offset;
648090075Sobrien      if (mp->refcount > 0)
648190075Sobrien	offset += mp->fix_size;
648290075Sobrien
648390075Sobrien      if (mp->next && mp->next->min_address < mp->min_address + mp->fix_size)
648490075Sobrien	mp->next->min_address = mp->min_address + mp->fix_size;
648590075Sobrien    }
648690075Sobrien
648790075Sobrien  return min_mp;
648890075Sobrien}
648990075Sobrien
649090075Sobrien/* Add a constant to the minipool for a backward reference.  Returns the
649190075Sobrien   node added or NULL if the constant will not fit in this pool.
649290075Sobrien
649390075Sobrien   Note that the code for insertion for a backwards reference can be
649490075Sobrien   somewhat confusing because the calculated offsets for each fix do
649590075Sobrien   not take into account the size of the pool (which is still under
649690075Sobrien   construction.  */
649790075Sobrienstatic Mnode *
6498132718Skanadd_minipool_backward_ref (Mfix *fix)
649990075Sobrien{
650090075Sobrien  /* If set, min_mp is the last pool_entry that has a lower constraint
650190075Sobrien     than the one we are trying to add.  */
6502132718Skan  Mnode *min_mp = NULL;
650390075Sobrien  /* This can be negative, since it is only a constraint.  */
650490075Sobrien  HOST_WIDE_INT  min_address = fix->address - fix->backwards;
6505132718Skan  Mnode *mp;
650690075Sobrien
650790075Sobrien  /* If we can't reach the current pool from this insn, or if we can't
650890075Sobrien     insert this entry at the end of the pool without pushing other
650990075Sobrien     fixes out of range, then we don't try.  This ensures that we
651090075Sobrien     can't fail later on.  */
651190075Sobrien  if (min_address >= minipool_barrier->address
651290075Sobrien      || (minipool_vector_tail->min_address + fix->fix_size
651390075Sobrien	  >= minipool_barrier->address))
651490075Sobrien    return NULL;
651590075Sobrien
651690075Sobrien  /* Scan the pool to see if a constant with the same value has
651790075Sobrien     already been added.  While we are doing this, also note the
651890075Sobrien     location where we must insert the constant if it doesn't already
651990075Sobrien     exist.  */
652090075Sobrien  for (mp = minipool_vector_tail; mp != NULL; mp = mp->prev)
652190075Sobrien    {
652290075Sobrien      if (GET_CODE (fix->value) == GET_CODE (mp->value)
652390075Sobrien	  && fix->mode == mp->mode
652490075Sobrien	  && (GET_CODE (fix->value) != CODE_LABEL
652590075Sobrien	      || (CODE_LABEL_NUMBER (fix->value)
652690075Sobrien		  == CODE_LABEL_NUMBER (mp->value)))
652790075Sobrien	  && rtx_equal_p (fix->value, mp->value)
652890075Sobrien	  /* Check that there is enough slack to move this entry to the
652990075Sobrien	     end of the table (this is conservative).  */
653090075Sobrien	  && (mp->max_address
653190075Sobrien	      > (minipool_barrier->address
653290075Sobrien		 + minipool_vector_tail->offset
653390075Sobrien		 + minipool_vector_tail->fix_size)))
653490075Sobrien	{
653590075Sobrien	  mp->refcount++;
653690075Sobrien	  return move_minipool_fix_backward_ref (mp, min_mp, min_address);
653790075Sobrien	}
653890075Sobrien
653990075Sobrien      if (min_mp != NULL)
654090075Sobrien	mp->min_address += fix->fix_size;
654190075Sobrien      else
654290075Sobrien	{
654390075Sobrien	  /* Note the insertion point if necessary.  */
654490075Sobrien	  if (mp->min_address < min_address)
6545132718Skan	    {
6546132718Skan	      /* For now, we do not allow the insertion of 8-byte alignment
6547132718Skan		 requiring nodes anywhere but at the start of the pool.  */
6548132718Skan	      if (TARGET_REALLY_IWMMXT && fix->fix_size == 8 && mp->fix_size != 8)
6549132718Skan		return NULL;
6550132718Skan	      else
6551132718Skan		min_mp = mp;
6552132718Skan	    }
655390075Sobrien	  else if (mp->max_address
655490075Sobrien		   < minipool_barrier->address + mp->offset + fix->fix_size)
655590075Sobrien	    {
655690075Sobrien	      /* Inserting before this entry would push the fix beyond
655790075Sobrien		 its maximum address (which can happen if we have
655890075Sobrien		 re-located a forwards fix); force the new fix to come
655990075Sobrien		 after it.  */
656090075Sobrien	      min_mp = mp;
656190075Sobrien	      min_address = mp->min_address + fix->fix_size;
656290075Sobrien	    }
6563132718Skan	  /* If we are inserting an 8-bytes aligned quantity and
6564132718Skan	     we have not already found an insertion point, then
6565132718Skan	     make sure that all such 8-byte aligned quantities are
6566132718Skan	     placed at the start of the pool.  */
6567132718Skan	  else if (TARGET_REALLY_IWMMXT
6568132718Skan		   && min_mp == NULL
6569132718Skan		   && fix->fix_size == 8
6570132718Skan		   && mp->fix_size < 8)
6571132718Skan	    {
6572132718Skan	      min_mp = mp;
6573132718Skan	      min_address = mp->min_address + fix->fix_size;
6574132718Skan	    }
657590075Sobrien	}
657690075Sobrien    }
657790075Sobrien
657890075Sobrien  /* We need to create a new entry.  */
657990075Sobrien  mp = xmalloc (sizeof (* mp));
658090075Sobrien  mp->fix_size = fix->fix_size;
658190075Sobrien  mp->mode = fix->mode;
658290075Sobrien  mp->value = fix->value;
658390075Sobrien  mp->refcount = 1;
658490075Sobrien  mp->max_address = minipool_barrier->address + 65536;
658590075Sobrien
658690075Sobrien  mp->min_address = min_address;
658790075Sobrien
658890075Sobrien  if (min_mp == NULL)
658990075Sobrien    {
659090075Sobrien      mp->prev = NULL;
659190075Sobrien      mp->next = minipool_vector_head;
659290075Sobrien
659390075Sobrien      if (mp->next == NULL)
659490075Sobrien	{
659590075Sobrien	  minipool_vector_tail = mp;
659690075Sobrien	  minipool_vector_label = gen_label_rtx ();
659790075Sobrien	}
659890075Sobrien      else
659990075Sobrien	mp->next->prev = mp;
660090075Sobrien
660190075Sobrien      minipool_vector_head = mp;
660290075Sobrien    }
660390075Sobrien  else
660490075Sobrien    {
660590075Sobrien      mp->next = min_mp->next;
660690075Sobrien      mp->prev = min_mp;
660790075Sobrien      min_mp->next = mp;
660890075Sobrien
660990075Sobrien      if (mp->next != NULL)
661090075Sobrien	mp->next->prev = mp;
661190075Sobrien      else
661290075Sobrien	minipool_vector_tail = mp;
661390075Sobrien    }
661490075Sobrien
661590075Sobrien  /* Save the new entry.  */
661690075Sobrien  min_mp = mp;
661790075Sobrien
661890075Sobrien  if (mp->prev)
661990075Sobrien    mp = mp->prev;
662090075Sobrien  else
662190075Sobrien    mp->offset = 0;
662290075Sobrien
662390075Sobrien  /* Scan over the following entries and adjust their offsets.  */
662490075Sobrien  while (mp->next != NULL)
662590075Sobrien    {
662690075Sobrien      if (mp->next->min_address < mp->min_address + mp->fix_size)
662790075Sobrien	mp->next->min_address = mp->min_address + mp->fix_size;
662890075Sobrien
662990075Sobrien      if (mp->refcount)
663090075Sobrien	mp->next->offset = mp->offset + mp->fix_size;
663190075Sobrien      else
663290075Sobrien	mp->next->offset = mp->offset;
663390075Sobrien
663490075Sobrien      mp = mp->next;
663590075Sobrien    }
663690075Sobrien
663790075Sobrien  return min_mp;
663890075Sobrien}
663990075Sobrien
664090075Sobrienstatic void
6641132718Skanassign_minipool_offsets (Mfix *barrier)
664290075Sobrien{
664390075Sobrien  HOST_WIDE_INT offset = 0;
6644132718Skan  Mnode *mp;
664590075Sobrien
664690075Sobrien  minipool_barrier = barrier;
664790075Sobrien
664890075Sobrien  for (mp = minipool_vector_head; mp != NULL; mp = mp->next)
664990075Sobrien    {
665090075Sobrien      mp->offset = offset;
665190075Sobrien
665290075Sobrien      if (mp->refcount > 0)
665390075Sobrien	offset += mp->fix_size;
665490075Sobrien    }
665590075Sobrien}
665690075Sobrien
665790075Sobrien/* Output the literal table */
665890075Sobrienstatic void
6659132718Skandump_minipool (rtx scan)
666090075Sobrien{
666190075Sobrien  Mnode * mp;
666290075Sobrien  Mnode * nmp;
6663132718Skan  int align64 = 0;
666490075Sobrien
6665132718Skan  if (TARGET_REALLY_IWMMXT)
6666132718Skan    for (mp = minipool_vector_head; mp != NULL; mp = mp->next)
6667132718Skan      if (mp->refcount > 0 && mp->fix_size == 8)
6668132718Skan	{
6669132718Skan	  align64 = 1;
6670132718Skan	  break;
6671132718Skan	}
6672132718Skan
667390075Sobrien  if (rtl_dump_file)
667490075Sobrien    fprintf (rtl_dump_file,
6675132718Skan	     ";; Emitting minipool after insn %u; address %ld; align %d (bytes)\n",
6676132718Skan	     INSN_UID (scan), (unsigned long) minipool_barrier->address, align64 ? 8 : 4);
667790075Sobrien
667890075Sobrien  scan = emit_label_after (gen_label_rtx (), scan);
6679132718Skan  scan = emit_insn_after (align64 ? gen_align_8 () : gen_align_4 (), scan);
668090075Sobrien  scan = emit_label_after (minipool_vector_label, scan);
668190075Sobrien
668290075Sobrien  for (mp = minipool_vector_head; mp != NULL; mp = nmp)
668390075Sobrien    {
668490075Sobrien      if (mp->refcount > 0)
668590075Sobrien	{
668690075Sobrien	  if (rtl_dump_file)
668790075Sobrien	    {
668890075Sobrien	      fprintf (rtl_dump_file,
668990075Sobrien		       ";;  Offset %u, min %ld, max %ld ",
669090075Sobrien		       (unsigned) mp->offset, (unsigned long) mp->min_address,
669190075Sobrien		       (unsigned long) mp->max_address);
669290075Sobrien	      arm_print_value (rtl_dump_file, mp->value);
669390075Sobrien	      fputc ('\n', rtl_dump_file);
669490075Sobrien	    }
669590075Sobrien
669690075Sobrien	  switch (mp->fix_size)
669790075Sobrien	    {
669890075Sobrien#ifdef HAVE_consttable_1
669990075Sobrien	    case 1:
670090075Sobrien	      scan = emit_insn_after (gen_consttable_1 (mp->value), scan);
670190075Sobrien	      break;
670290075Sobrien
670390075Sobrien#endif
670490075Sobrien#ifdef HAVE_consttable_2
670590075Sobrien	    case 2:
670690075Sobrien	      scan = emit_insn_after (gen_consttable_2 (mp->value), scan);
670790075Sobrien	      break;
670890075Sobrien
670990075Sobrien#endif
671090075Sobrien#ifdef HAVE_consttable_4
671190075Sobrien	    case 4:
671290075Sobrien	      scan = emit_insn_after (gen_consttable_4 (mp->value), scan);
671390075Sobrien	      break;
671490075Sobrien
671590075Sobrien#endif
671690075Sobrien#ifdef HAVE_consttable_8
671790075Sobrien	    case 8:
671890075Sobrien	      scan = emit_insn_after (gen_consttable_8 (mp->value), scan);
671990075Sobrien	      break;
672090075Sobrien
672190075Sobrien#endif
672290075Sobrien	    default:
672390075Sobrien	      abort ();
672490075Sobrien	      break;
672590075Sobrien	    }
672690075Sobrien	}
672790075Sobrien
672890075Sobrien      nmp = mp->next;
672990075Sobrien      free (mp);
673090075Sobrien    }
673190075Sobrien
673290075Sobrien  minipool_vector_head = minipool_vector_tail = NULL;
673390075Sobrien  scan = emit_insn_after (gen_consttable_end (), scan);
673490075Sobrien  scan = emit_barrier_after (scan);
673590075Sobrien}
673690075Sobrien
673790075Sobrien/* Return the cost of forcibly inserting a barrier after INSN.  */
673890075Sobrienstatic int
6739132718Skanarm_barrier_cost (rtx insn)
674090075Sobrien{
674190075Sobrien  /* Basing the location of the pool on the loop depth is preferable,
674290075Sobrien     but at the moment, the basic block information seems to be
674390075Sobrien     corrupt by this stage of the compilation.  */
674490075Sobrien  int base_cost = 50;
674590075Sobrien  rtx next = next_nonnote_insn (insn);
674690075Sobrien
674790075Sobrien  if (next != NULL && GET_CODE (next) == CODE_LABEL)
674890075Sobrien    base_cost -= 20;
674990075Sobrien
675090075Sobrien  switch (GET_CODE (insn))
675190075Sobrien    {
675290075Sobrien    case CODE_LABEL:
675390075Sobrien      /* It will always be better to place the table before the label, rather
675490075Sobrien	 than after it.  */
675590075Sobrien      return 50;
675690075Sobrien
675790075Sobrien    case INSN:
675890075Sobrien    case CALL_INSN:
675990075Sobrien      return base_cost;
676090075Sobrien
676190075Sobrien    case JUMP_INSN:
676290075Sobrien      return base_cost - 10;
676390075Sobrien
676490075Sobrien    default:
676590075Sobrien      return base_cost + 10;
676690075Sobrien    }
676790075Sobrien}
676890075Sobrien
676990075Sobrien/* Find the best place in the insn stream in the range
677090075Sobrien   (FIX->address,MAX_ADDRESS) to forcibly insert a minipool barrier.
677190075Sobrien   Create the barrier by inserting a jump and add a new fix entry for
677290075Sobrien   it.  */
677390075Sobrienstatic Mfix *
6774132718Skancreate_fix_barrier (Mfix *fix, HOST_WIDE_INT max_address)
677590075Sobrien{
677690075Sobrien  HOST_WIDE_INT count = 0;
677790075Sobrien  rtx barrier;
677890075Sobrien  rtx from = fix->insn;
677990075Sobrien  rtx selected = from;
678090075Sobrien  int selected_cost;
678190075Sobrien  HOST_WIDE_INT selected_address;
678290075Sobrien  Mfix * new_fix;
678390075Sobrien  HOST_WIDE_INT max_count = max_address - fix->address;
678490075Sobrien  rtx label = gen_label_rtx ();
678590075Sobrien
678690075Sobrien  selected_cost = arm_barrier_cost (from);
678790075Sobrien  selected_address = fix->address;
678890075Sobrien
678990075Sobrien  while (from && count < max_count)
679090075Sobrien    {
679190075Sobrien      rtx tmp;
679290075Sobrien      int new_cost;
679390075Sobrien
679490075Sobrien      /* This code shouldn't have been called if there was a natural barrier
679590075Sobrien	 within range.  */
679690075Sobrien      if (GET_CODE (from) == BARRIER)
679790075Sobrien	abort ();
679890075Sobrien
679990075Sobrien      /* Count the length of this insn.  */
680090075Sobrien      count += get_attr_length (from);
680190075Sobrien
680290075Sobrien      /* If there is a jump table, add its length.  */
680390075Sobrien      tmp = is_jump_table (from);
680490075Sobrien      if (tmp != NULL)
680590075Sobrien	{
680690075Sobrien	  count += get_jump_table_size (tmp);
680790075Sobrien
680890075Sobrien	  /* Jump tables aren't in a basic block, so base the cost on
680990075Sobrien	     the dispatch insn.  If we select this location, we will
681090075Sobrien	     still put the pool after the table.  */
681190075Sobrien	  new_cost = arm_barrier_cost (from);
681290075Sobrien
681390075Sobrien	  if (count < max_count && new_cost <= selected_cost)
681490075Sobrien	    {
681590075Sobrien	      selected = tmp;
681690075Sobrien	      selected_cost = new_cost;
681790075Sobrien	      selected_address = fix->address + count;
681890075Sobrien	    }
681990075Sobrien
682090075Sobrien	  /* Continue after the dispatch table.  */
682190075Sobrien	  from = NEXT_INSN (tmp);
682290075Sobrien	  continue;
682390075Sobrien	}
682490075Sobrien
682590075Sobrien      new_cost = arm_barrier_cost (from);
682690075Sobrien
682790075Sobrien      if (count < max_count && new_cost <= selected_cost)
682890075Sobrien	{
682990075Sobrien	  selected = from;
683090075Sobrien	  selected_cost = new_cost;
683190075Sobrien	  selected_address = fix->address + count;
683290075Sobrien	}
683390075Sobrien
683490075Sobrien      from = NEXT_INSN (from);
683590075Sobrien    }
683690075Sobrien
683790075Sobrien  /* Create a new JUMP_INSN that branches around a barrier.  */
683890075Sobrien  from = emit_jump_insn_after (gen_jump (label), selected);
683990075Sobrien  JUMP_LABEL (from) = label;
684090075Sobrien  barrier = emit_barrier_after (from);
684190075Sobrien  emit_label_after (label, barrier);
684290075Sobrien
684390075Sobrien  /* Create a minipool barrier entry for the new barrier.  */
684490075Sobrien  new_fix = (Mfix *) obstack_alloc (&minipool_obstack, sizeof (* new_fix));
684590075Sobrien  new_fix->insn = barrier;
684690075Sobrien  new_fix->address = selected_address;
684790075Sobrien  new_fix->next = fix->next;
684890075Sobrien  fix->next = new_fix;
684990075Sobrien
685090075Sobrien  return new_fix;
685190075Sobrien}
685290075Sobrien
685390075Sobrien/* Record that there is a natural barrier in the insn stream at
685490075Sobrien   ADDRESS.  */
685590075Sobrienstatic void
6856132718Skanpush_minipool_barrier (rtx insn, HOST_WIDE_INT address)
685790075Sobrien{
685890075Sobrien  Mfix * fix = (Mfix *) obstack_alloc (&minipool_obstack, sizeof (* fix));
685990075Sobrien
686090075Sobrien  fix->insn = insn;
686190075Sobrien  fix->address = address;
686290075Sobrien
686390075Sobrien  fix->next = NULL;
686490075Sobrien  if (minipool_fix_head != NULL)
686590075Sobrien    minipool_fix_tail->next = fix;
686690075Sobrien  else
686790075Sobrien    minipool_fix_head = fix;
686890075Sobrien
686990075Sobrien  minipool_fix_tail = fix;
687090075Sobrien}
687190075Sobrien
687290075Sobrien/* Record INSN, which will need fixing up to load a value from the
687390075Sobrien   minipool.  ADDRESS is the offset of the insn since the start of the
687490075Sobrien   function; LOC is a pointer to the part of the insn which requires
687590075Sobrien   fixing; VALUE is the constant that must be loaded, which is of type
687690075Sobrien   MODE.  */
687790075Sobrienstatic void
6878132718Skanpush_minipool_fix (rtx insn, HOST_WIDE_INT address, rtx *loc,
6879132718Skan		   enum machine_mode mode, rtx value)
688090075Sobrien{
688190075Sobrien  Mfix * fix = (Mfix *) obstack_alloc (&minipool_obstack, sizeof (* fix));
688290075Sobrien
688390075Sobrien#ifdef AOF_ASSEMBLER
6884132718Skan  /* PIC symbol references need to be converted into offsets into the
688590075Sobrien     based area.  */
688690075Sobrien  /* XXX This shouldn't be done here.  */
688790075Sobrien  if (flag_pic && GET_CODE (value) == SYMBOL_REF)
688890075Sobrien    value = aof_pic_entry (value);
688990075Sobrien#endif /* AOF_ASSEMBLER */
689090075Sobrien
689190075Sobrien  fix->insn = insn;
689290075Sobrien  fix->address = address;
689390075Sobrien  fix->loc = loc;
689490075Sobrien  fix->mode = mode;
689590075Sobrien  fix->fix_size = MINIPOOL_FIX_SIZE (mode);
689690075Sobrien  fix->value = value;
689790075Sobrien  fix->forwards = get_attr_pool_range (insn);
689890075Sobrien  fix->backwards = get_attr_neg_pool_range (insn);
689990075Sobrien  fix->minipool = NULL;
690090075Sobrien
690190075Sobrien  /* If an insn doesn't have a range defined for it, then it isn't
690290075Sobrien     expecting to be reworked by this code.  Better to abort now than
690390075Sobrien     to generate duff assembly code.  */
690490075Sobrien  if (fix->forwards == 0 && fix->backwards == 0)
690590075Sobrien    abort ();
690690075Sobrien
6907132718Skan  /* With iWMMXt enabled, the pool is aligned to an 8-byte boundary.
6908132718Skan     So there might be an empty word before the start of the pool.
6909132718Skan     Hence we reduce the forward range by 4 to allow for this
6910132718Skan     possibility.  */
6911132718Skan  if (TARGET_REALLY_IWMMXT && fix->fix_size == 8)
6912132718Skan    fix->forwards -= 4;
6913132718Skan
691490075Sobrien  if (rtl_dump_file)
691590075Sobrien    {
691690075Sobrien      fprintf (rtl_dump_file,
691790075Sobrien	       ";; %smode fixup for i%d; addr %lu, range (%ld,%ld): ",
691890075Sobrien	       GET_MODE_NAME (mode),
691990075Sobrien	       INSN_UID (insn), (unsigned long) address,
692090075Sobrien	       -1 * (long)fix->backwards, (long)fix->forwards);
692190075Sobrien      arm_print_value (rtl_dump_file, fix->value);
692290075Sobrien      fprintf (rtl_dump_file, "\n");
692390075Sobrien    }
692490075Sobrien
692590075Sobrien  /* Add it to the chain of fixes.  */
692690075Sobrien  fix->next = NULL;
692790075Sobrien
692890075Sobrien  if (minipool_fix_head != NULL)
692990075Sobrien    minipool_fix_tail->next = fix;
693090075Sobrien  else
693190075Sobrien    minipool_fix_head = fix;
693290075Sobrien
693390075Sobrien  minipool_fix_tail = fix;
693490075Sobrien}
693590075Sobrien
6936132718Skan/* Scan INSN and note any of its operands that need fixing.
6937132718Skan   If DO_PUSHES is false we do not actually push any of the fixups
6938132718Skan   needed.  The function returns TRUE is any fixups were needed/pushed.
6939132718Skan   This is used by arm_memory_load_p() which needs to know about loads
6940132718Skan   of constants that will be converted into minipool loads.  */
6941132718Skanstatic bool
6942132718Skannote_invalid_constants (rtx insn, HOST_WIDE_INT address, int do_pushes)
694390075Sobrien{
6944132718Skan  bool result = false;
694590075Sobrien  int opno;
694690075Sobrien
694790075Sobrien  extract_insn (insn);
694890075Sobrien
694990075Sobrien  if (!constrain_operands (1))
695090075Sobrien    fatal_insn_not_found (insn);
695190075Sobrien
6952132718Skan  if (recog_data.n_alternatives == 0)
6953132718Skan    return false;
6954132718Skan
6955132718Skan  /* Fill in recog_op_alt with information about the constraints of this insn.  */
695690075Sobrien  preprocess_constraints ();
695790075Sobrien
695890075Sobrien  for (opno = 0; opno < recog_data.n_operands; opno++)
695990075Sobrien    {
696090075Sobrien      /* Things we need to fix can only occur in inputs.  */
696190075Sobrien      if (recog_data.operand_type[opno] != OP_IN)
696290075Sobrien	continue;
696390075Sobrien
696490075Sobrien      /* If this alternative is a memory reference, then any mention
696590075Sobrien	 of constants in this alternative is really to fool reload
696690075Sobrien	 into allowing us to accept one there.  We need to fix them up
696790075Sobrien	 now so that we output the right code.  */
696890075Sobrien      if (recog_op_alt[opno][which_alternative].memory_ok)
696990075Sobrien	{
697090075Sobrien	  rtx op = recog_data.operand[opno];
697190075Sobrien
697290075Sobrien	  if (CONSTANT_P (op))
6973132718Skan	    {
6974132718Skan	      if (do_pushes)
6975132718Skan		push_minipool_fix (insn, address, recog_data.operand_loc[opno],
6976132718Skan				   recog_data.operand_mode[opno], op);
6977132718Skan	      result = true;
6978132718Skan	    }
697990075Sobrien	  else if (GET_CODE (op) == MEM
698090075Sobrien		   && GET_CODE (XEXP (op, 0)) == SYMBOL_REF
698190075Sobrien		   && CONSTANT_POOL_ADDRESS_P (XEXP (op, 0)))
6982132718Skan	    {
6983132718Skan	      if (do_pushes)
6984132718Skan		{
6985132718Skan		  rtx cop = avoid_constant_pool_reference (op);
6986132718Skan
6987132718Skan		  /* Casting the address of something to a mode narrower
6988132718Skan		     than a word can cause avoid_constant_pool_reference()
6989132718Skan		     to return the pool reference itself.  That's no good to
6990132718Skan		     us here.  Lets just hope that we can use the
6991132718Skan		     constant pool value directly.  */
6992132718Skan		  if (op == cop)
6993132718Skan		    cop = get_pool_constant (XEXP (op, 0));
6994132718Skan
6995132718Skan		  push_minipool_fix (insn, address,
6996132718Skan				     recog_data.operand_loc[opno],
6997132718Skan				     recog_data.operand_mode[opno], cop);
6998132718Skan		}
6999132718Skan
7000132718Skan	      result = true;
7001132718Skan	    }
700290075Sobrien	}
700390075Sobrien    }
7004132718Skan
7005132718Skan  return result;
700690075Sobrien}
700790075Sobrien
7008132718Skan/* Gcc puts the pool in the wrong place for ARM, since we can only
7009132718Skan   load addresses a limited distance around the pc.  We do some
7010132718Skan   special munging to move the constant pool values to the correct
7011132718Skan   point in the code.  */
7012132718Skanstatic void
7013132718Skanarm_reorg (void)
701490075Sobrien{
701590075Sobrien  rtx insn;
701690075Sobrien  HOST_WIDE_INT address = 0;
701790075Sobrien  Mfix * fix;
701890075Sobrien
701990075Sobrien  minipool_fix_head = minipool_fix_tail = NULL;
702090075Sobrien
702190075Sobrien  /* The first insn must always be a note, or the code below won't
702290075Sobrien     scan it properly.  */
7023132718Skan  insn = get_insns ();
7024132718Skan  if (GET_CODE (insn) != NOTE)
702590075Sobrien    abort ();
702690075Sobrien
702790075Sobrien  /* Scan all the insns and record the operands that will need fixing.  */
7028132718Skan  for (insn = next_nonnote_insn (insn); insn; insn = next_nonnote_insn (insn))
702990075Sobrien    {
7030132718Skan      if (TARGET_CIRRUS_FIX_INVALID_INSNS
7031132718Skan          && (arm_cirrus_insn_p (insn)
7032132718Skan	      || GET_CODE (insn) == JUMP_INSN
7033132718Skan	      || arm_memory_load_p (insn)))
7034132718Skan	cirrus_reorg (insn);
7035132718Skan
703690075Sobrien      if (GET_CODE (insn) == BARRIER)
703790075Sobrien	push_minipool_barrier (insn, address);
7038132718Skan      else if (INSN_P (insn))
703990075Sobrien	{
704090075Sobrien	  rtx table;
704190075Sobrien
7042132718Skan	  note_invalid_constants (insn, address, true);
704390075Sobrien	  address += get_attr_length (insn);
704490075Sobrien
704590075Sobrien	  /* If the insn is a vector jump, add the size of the table
704690075Sobrien	     and skip the table.  */
704790075Sobrien	  if ((table = is_jump_table (insn)) != NULL)
704890075Sobrien	    {
704990075Sobrien	      address += get_jump_table_size (table);
705090075Sobrien	      insn = table;
705190075Sobrien	    }
705290075Sobrien	}
705390075Sobrien    }
705490075Sobrien
705590075Sobrien  fix = minipool_fix_head;
705690075Sobrien
705790075Sobrien  /* Now scan the fixups and perform the required changes.  */
705890075Sobrien  while (fix)
705990075Sobrien    {
706090075Sobrien      Mfix * ftmp;
706190075Sobrien      Mfix * fdel;
706290075Sobrien      Mfix *  last_added_fix;
706390075Sobrien      Mfix * last_barrier = NULL;
706490075Sobrien      Mfix * this_fix;
706590075Sobrien
706690075Sobrien      /* Skip any further barriers before the next fix.  */
706790075Sobrien      while (fix && GET_CODE (fix->insn) == BARRIER)
706890075Sobrien	fix = fix->next;
706990075Sobrien
707090075Sobrien      /* No more fixes.  */
707190075Sobrien      if (fix == NULL)
707290075Sobrien	break;
707390075Sobrien
707490075Sobrien      last_added_fix = NULL;
707590075Sobrien
707690075Sobrien      for (ftmp = fix; ftmp; ftmp = ftmp->next)
707790075Sobrien	{
707890075Sobrien	  if (GET_CODE (ftmp->insn) == BARRIER)
707990075Sobrien	    {
708090075Sobrien	      if (ftmp->address >= minipool_vector_head->max_address)
708190075Sobrien		break;
708290075Sobrien
708390075Sobrien	      last_barrier = ftmp;
708490075Sobrien	    }
708590075Sobrien	  else if ((ftmp->minipool = add_minipool_forward_ref (ftmp)) == NULL)
708690075Sobrien	    break;
708790075Sobrien
708890075Sobrien	  last_added_fix = ftmp;  /* Keep track of the last fix added.  */
708990075Sobrien	}
709090075Sobrien
709190075Sobrien      /* If we found a barrier, drop back to that; any fixes that we
709290075Sobrien	 could have reached but come after the barrier will now go in
709390075Sobrien	 the next mini-pool.  */
709490075Sobrien      if (last_barrier != NULL)
709590075Sobrien	{
709690075Sobrien	  /* Reduce the refcount for those fixes that won't go into this
709790075Sobrien	     pool after all.  */
709890075Sobrien	  for (fdel = last_barrier->next;
709990075Sobrien	       fdel && fdel != ftmp;
710090075Sobrien	       fdel = fdel->next)
710190075Sobrien	    {
710290075Sobrien	      fdel->minipool->refcount--;
710390075Sobrien	      fdel->minipool = NULL;
710490075Sobrien	    }
710590075Sobrien
710690075Sobrien	  ftmp = last_barrier;
710790075Sobrien	}
710890075Sobrien      else
710990075Sobrien        {
711090075Sobrien	  /* ftmp is first fix that we can't fit into this pool and
711190075Sobrien	     there no natural barriers that we could use.  Insert a
711290075Sobrien	     new barrier in the code somewhere between the previous
711390075Sobrien	     fix and this one, and arrange to jump around it.  */
711490075Sobrien	  HOST_WIDE_INT max_address;
711590075Sobrien
711690075Sobrien	  /* The last item on the list of fixes must be a barrier, so
711790075Sobrien	     we can never run off the end of the list of fixes without
711890075Sobrien	     last_barrier being set.  */
711990075Sobrien	  if (ftmp == NULL)
712090075Sobrien	    abort ();
712190075Sobrien
712290075Sobrien	  max_address = minipool_vector_head->max_address;
712390075Sobrien	  /* Check that there isn't another fix that is in range that
712490075Sobrien	     we couldn't fit into this pool because the pool was
712590075Sobrien	     already too large: we need to put the pool before such an
712690075Sobrien	     instruction.  */
712790075Sobrien	  if (ftmp->address < max_address)
712890075Sobrien	    max_address = ftmp->address;
712990075Sobrien
713090075Sobrien	  last_barrier = create_fix_barrier (last_added_fix, max_address);
713190075Sobrien	}
713290075Sobrien
713390075Sobrien      assign_minipool_offsets (last_barrier);
713490075Sobrien
713590075Sobrien      while (ftmp)
713690075Sobrien	{
713790075Sobrien	  if (GET_CODE (ftmp->insn) != BARRIER
713890075Sobrien	      && ((ftmp->minipool = add_minipool_backward_ref (ftmp))
713990075Sobrien		  == NULL))
714090075Sobrien	    break;
714190075Sobrien
714290075Sobrien	  ftmp = ftmp->next;
714390075Sobrien	}
714490075Sobrien
714590075Sobrien      /* Scan over the fixes we have identified for this pool, fixing them
714690075Sobrien	 up and adding the constants to the pool itself.  */
714790075Sobrien      for (this_fix = fix; this_fix && ftmp != this_fix;
714890075Sobrien	   this_fix = this_fix->next)
714990075Sobrien	if (GET_CODE (this_fix->insn) != BARRIER)
715090075Sobrien	  {
715190075Sobrien	    rtx addr
715290075Sobrien	      = plus_constant (gen_rtx_LABEL_REF (VOIDmode,
715390075Sobrien						  minipool_vector_label),
715490075Sobrien			       this_fix->minipool->offset);
715590075Sobrien	    *this_fix->loc = gen_rtx_MEM (this_fix->mode, addr);
715690075Sobrien	  }
715790075Sobrien
715890075Sobrien      dump_minipool (last_barrier->insn);
715990075Sobrien      fix = ftmp;
716090075Sobrien    }
716190075Sobrien
716290075Sobrien  /* From now on we must synthesize any constants that we can't handle
716390075Sobrien     directly.  This can happen if the RTL gets split during final
716490075Sobrien     instruction generation.  */
716590075Sobrien  after_arm_reorg = 1;
716690075Sobrien
716790075Sobrien  /* Free the minipool memory.  */
716890075Sobrien  obstack_free (&minipool_obstack, minipool_startobj);
716990075Sobrien}
717090075Sobrien
717190075Sobrien/* Routines to output assembly language.  */
717290075Sobrien
717390075Sobrien/* If the rtx is the correct value then return the string of the number.
717490075Sobrien   In this way we can ensure that valid double constants are generated even
717590075Sobrien   when cross compiling.  */
717690075Sobrienconst char *
7177132718Skanfp_immediate_constant (rtx x)
717890075Sobrien{
717990075Sobrien  REAL_VALUE_TYPE r;
718090075Sobrien  int i;
718190075Sobrien
718290075Sobrien  if (!fpa_consts_inited)
718390075Sobrien    init_fpa_table ();
718490075Sobrien
718590075Sobrien  REAL_VALUE_FROM_CONST_DOUBLE (r, x);
718690075Sobrien  for (i = 0; i < 8; i++)
718790075Sobrien    if (REAL_VALUES_EQUAL (r, values_fpa[i]))
718890075Sobrien      return strings_fpa[i];
718990075Sobrien
719090075Sobrien  abort ();
719190075Sobrien}
719290075Sobrien
719390075Sobrien/* As for fp_immediate_constant, but value is passed directly, not in rtx.  */
719490075Sobrienstatic const char *
7195132718Skanfp_const_from_val (REAL_VALUE_TYPE *r)
719690075Sobrien{
719790075Sobrien  int i;
719890075Sobrien
719990075Sobrien  if (!fpa_consts_inited)
720090075Sobrien    init_fpa_table ();
720190075Sobrien
720290075Sobrien  for (i = 0; i < 8; i++)
720390075Sobrien    if (REAL_VALUES_EQUAL (*r, values_fpa[i]))
720490075Sobrien      return strings_fpa[i];
720590075Sobrien
720690075Sobrien  abort ();
720790075Sobrien}
720890075Sobrien
720990075Sobrien/* Output the operands of a LDM/STM instruction to STREAM.
721090075Sobrien   MASK is the ARM register set mask of which only bits 0-15 are important.
721190075Sobrien   REG is the base register, either the frame pointer or the stack pointer,
721290075Sobrien   INSTR is the possibly suffixed load or store instruction.  */
721390075Sobrienstatic void
7214132718Skanprint_multi_reg (FILE *stream, const char *instr, int reg, int mask)
721590075Sobrien{
721690075Sobrien  int i;
721790075Sobrien  int not_first = FALSE;
721890075Sobrien
721990075Sobrien  fputc ('\t', stream);
722090075Sobrien  asm_fprintf (stream, instr, reg);
722190075Sobrien  fputs (", {", stream);
722290075Sobrien
722390075Sobrien  for (i = 0; i <= LAST_ARM_REGNUM; i++)
722490075Sobrien    if (mask & (1 << i))
722590075Sobrien      {
722690075Sobrien	if (not_first)
722790075Sobrien	  fprintf (stream, ", ");
722890075Sobrien
722990075Sobrien	asm_fprintf (stream, "%r", i);
723090075Sobrien	not_first = TRUE;
723190075Sobrien      }
723290075Sobrien
7233132718Skan  fprintf (stream, "}");
7234132718Skan
7235132718Skan  /* Add a ^ character for the 26-bit ABI, but only if we were loading
7236132718Skan     the PC.  Otherwise we would generate an UNPREDICTABLE instruction.
7237132718Skan     Strictly speaking the instruction would be unpredicatble only if
7238132718Skan     we were writing back the base register as well, but since we never
7239132718Skan     want to generate an LDM type 2 instruction (register bank switching)
7240132718Skan     which is what you get if the PC is not being loaded, we do not need
7241132718Skan     to check for writeback.  */
7242132718Skan  if (! TARGET_APCS_32
7243132718Skan      && ((mask & (1 << PC_REGNUM)) != 0))
7244132718Skan    fprintf (stream, "^");
7245132718Skan
7246132718Skan  fprintf (stream, "\n");
724790075Sobrien}
724890075Sobrien
724990075Sobrien/* Output a 'call' insn.  */
725090075Sobrienconst char *
7251132718Skanoutput_call (rtx *operands)
725290075Sobrien{
725390075Sobrien  /* Handle calls to lr using ip (which may be clobbered in subr anyway).  */
725490075Sobrien
725590075Sobrien  if (REGNO (operands[0]) == LR_REGNUM)
725690075Sobrien    {
725790075Sobrien      operands[0] = gen_rtx_REG (SImode, IP_REGNUM);
725890075Sobrien      output_asm_insn ("mov%?\t%0, %|lr", operands);
725990075Sobrien    }
726090075Sobrien
726190075Sobrien  output_asm_insn ("mov%?\t%|lr, %|pc", operands);
726290075Sobrien
726390075Sobrien  if (TARGET_INTERWORK)
726490075Sobrien    output_asm_insn ("bx%?\t%0", operands);
726590075Sobrien  else
726690075Sobrien    output_asm_insn ("mov%?\t%|pc, %0", operands);
726790075Sobrien
726890075Sobrien  return "";
726990075Sobrien}
727090075Sobrien
727190075Sobrien/* Output a 'call' insn that is a reference in memory.  */
727290075Sobrienconst char *
7273132718Skanoutput_call_mem (rtx *operands)
727490075Sobrien{
727590075Sobrien  if (TARGET_INTERWORK)
727690075Sobrien    {
727790075Sobrien      output_asm_insn ("ldr%?\t%|ip, %0", operands);
727890075Sobrien      output_asm_insn ("mov%?\t%|lr, %|pc", operands);
727990075Sobrien      output_asm_insn ("bx%?\t%|ip", operands);
728090075Sobrien    }
7281117395Skan  else if (regno_use_in (LR_REGNUM, operands[0]))
7282117395Skan    {
7283117395Skan      /* LR is used in the memory address.  We load the address in the
7284117395Skan	 first instruction.  It's safe to use IP as the target of the
7285117395Skan	 load since the call will kill it anyway.  */
7286117395Skan      output_asm_insn ("ldr%?\t%|ip, %0", operands);
7287117395Skan      output_asm_insn ("mov%?\t%|lr, %|pc", operands);
7288117395Skan      output_asm_insn ("mov%?\t%|pc, %|ip", operands);
7289117395Skan    }
729090075Sobrien  else
729190075Sobrien    {
729290075Sobrien      output_asm_insn ("mov%?\t%|lr, %|pc", operands);
729390075Sobrien      output_asm_insn ("ldr%?\t%|pc, %0", operands);
729490075Sobrien    }
729590075Sobrien
729690075Sobrien  return "";
729790075Sobrien}
729890075Sobrien
7299132718Skan/* Output a move from arm registers to an fpa registers.
7300132718Skan   OPERANDS[0] is an fpa register.
730190075Sobrien   OPERANDS[1] is the first registers of an arm register pair.  */
730290075Sobrienconst char *
7303132718Skanoutput_mov_long_double_fpa_from_arm (rtx *operands)
730490075Sobrien{
730590075Sobrien  int arm_reg0 = REGNO (operands[1]);
730690075Sobrien  rtx ops[3];
730790075Sobrien
730890075Sobrien  if (arm_reg0 == IP_REGNUM)
730990075Sobrien    abort ();
731090075Sobrien
731190075Sobrien  ops[0] = gen_rtx_REG (SImode, arm_reg0);
731290075Sobrien  ops[1] = gen_rtx_REG (SImode, 1 + arm_reg0);
731390075Sobrien  ops[2] = gen_rtx_REG (SImode, 2 + arm_reg0);
731490075Sobrien
731590075Sobrien  output_asm_insn ("stm%?fd\t%|sp!, {%0, %1, %2}", ops);
731690075Sobrien  output_asm_insn ("ldf%?e\t%0, [%|sp], #12", operands);
731790075Sobrien
731890075Sobrien  return "";
731990075Sobrien}
732090075Sobrien
7321132718Skan/* Output a move from an fpa register to arm registers.
732290075Sobrien   OPERANDS[0] is the first registers of an arm register pair.
7323132718Skan   OPERANDS[1] is an fpa register.  */
732490075Sobrienconst char *
7325132718Skanoutput_mov_long_double_arm_from_fpa (rtx *operands)
732690075Sobrien{
732790075Sobrien  int arm_reg0 = REGNO (operands[0]);
732890075Sobrien  rtx ops[3];
732990075Sobrien
733090075Sobrien  if (arm_reg0 == IP_REGNUM)
733190075Sobrien    abort ();
733290075Sobrien
733390075Sobrien  ops[0] = gen_rtx_REG (SImode, arm_reg0);
733490075Sobrien  ops[1] = gen_rtx_REG (SImode, 1 + arm_reg0);
733590075Sobrien  ops[2] = gen_rtx_REG (SImode, 2 + arm_reg0);
733690075Sobrien
733790075Sobrien  output_asm_insn ("stf%?e\t%1, [%|sp, #-12]!", operands);
733890075Sobrien  output_asm_insn ("ldm%?fd\t%|sp!, {%0, %1, %2}", ops);
733990075Sobrien  return "";
734090075Sobrien}
734190075Sobrien
734290075Sobrien/* Output a move from arm registers to arm registers of a long double
734390075Sobrien   OPERANDS[0] is the destination.
734490075Sobrien   OPERANDS[1] is the source.  */
734590075Sobrienconst char *
7346132718Skanoutput_mov_long_double_arm_from_arm (rtx *operands)
734790075Sobrien{
734890075Sobrien  /* We have to be careful here because the two might overlap.  */
734990075Sobrien  int dest_start = REGNO (operands[0]);
735090075Sobrien  int src_start = REGNO (operands[1]);
735190075Sobrien  rtx ops[2];
735290075Sobrien  int i;
735390075Sobrien
735490075Sobrien  if (dest_start < src_start)
735590075Sobrien    {
735690075Sobrien      for (i = 0; i < 3; i++)
735790075Sobrien	{
735890075Sobrien	  ops[0] = gen_rtx_REG (SImode, dest_start + i);
735990075Sobrien	  ops[1] = gen_rtx_REG (SImode, src_start + i);
736090075Sobrien	  output_asm_insn ("mov%?\t%0, %1", ops);
736190075Sobrien	}
736290075Sobrien    }
736390075Sobrien  else
736490075Sobrien    {
736590075Sobrien      for (i = 2; i >= 0; i--)
736690075Sobrien	{
736790075Sobrien	  ops[0] = gen_rtx_REG (SImode, dest_start + i);
736890075Sobrien	  ops[1] = gen_rtx_REG (SImode, src_start + i);
736990075Sobrien	  output_asm_insn ("mov%?\t%0, %1", ops);
737090075Sobrien	}
737190075Sobrien    }
737290075Sobrien
737390075Sobrien  return "";
737490075Sobrien}
737590075Sobrien
737690075Sobrien
7377132718Skan/* Output a move from arm registers to an fpa registers.
7378132718Skan   OPERANDS[0] is an fpa register.
737990075Sobrien   OPERANDS[1] is the first registers of an arm register pair.  */
738090075Sobrienconst char *
7381132718Skanoutput_mov_double_fpa_from_arm (rtx *operands)
738290075Sobrien{
738390075Sobrien  int arm_reg0 = REGNO (operands[1]);
738490075Sobrien  rtx ops[2];
738590075Sobrien
738690075Sobrien  if (arm_reg0 == IP_REGNUM)
738790075Sobrien    abort ();
738890075Sobrien
738990075Sobrien  ops[0] = gen_rtx_REG (SImode, arm_reg0);
739090075Sobrien  ops[1] = gen_rtx_REG (SImode, 1 + arm_reg0);
739190075Sobrien  output_asm_insn ("stm%?fd\t%|sp!, {%0, %1}", ops);
739290075Sobrien  output_asm_insn ("ldf%?d\t%0, [%|sp], #8", operands);
739390075Sobrien  return "";
739490075Sobrien}
739590075Sobrien
7396132718Skan/* Output a move from an fpa register to arm registers.
739790075Sobrien   OPERANDS[0] is the first registers of an arm register pair.
7398132718Skan   OPERANDS[1] is an fpa register.  */
739990075Sobrienconst char *
7400132718Skanoutput_mov_double_arm_from_fpa (rtx *operands)
740190075Sobrien{
740290075Sobrien  int arm_reg0 = REGNO (operands[0]);
740390075Sobrien  rtx ops[2];
740490075Sobrien
740590075Sobrien  if (arm_reg0 == IP_REGNUM)
740690075Sobrien    abort ();
740790075Sobrien
740890075Sobrien  ops[0] = gen_rtx_REG (SImode, arm_reg0);
740990075Sobrien  ops[1] = gen_rtx_REG (SImode, 1 + arm_reg0);
741090075Sobrien  output_asm_insn ("stf%?d\t%1, [%|sp, #-8]!", operands);
741190075Sobrien  output_asm_insn ("ldm%?fd\t%|sp!, {%0, %1}", ops);
741290075Sobrien  return "";
741390075Sobrien}
741490075Sobrien
741590075Sobrien/* Output a move between double words.
741690075Sobrien   It must be REG<-REG, REG<-CONST_DOUBLE, REG<-CONST_INT, REG<-MEM
741790075Sobrien   or MEM<-REG and all MEMs must be offsettable addresses.  */
741890075Sobrienconst char *
7419132718Skanoutput_move_double (rtx *operands)
742090075Sobrien{
742190075Sobrien  enum rtx_code code0 = GET_CODE (operands[0]);
742290075Sobrien  enum rtx_code code1 = GET_CODE (operands[1]);
742390075Sobrien  rtx otherops[3];
742490075Sobrien
742590075Sobrien  if (code0 == REG)
742690075Sobrien    {
742790075Sobrien      int reg0 = REGNO (operands[0]);
742890075Sobrien
742990075Sobrien      otherops[0] = gen_rtx_REG (SImode, 1 + reg0);
743090075Sobrien
743190075Sobrien      if (code1 == REG)
743290075Sobrien	{
743390075Sobrien	  int reg1 = REGNO (operands[1]);
743490075Sobrien	  if (reg1 == IP_REGNUM)
743590075Sobrien	    abort ();
743690075Sobrien
743790075Sobrien	  /* Ensure the second source is not overwritten.  */
743890075Sobrien	  if (reg1 == reg0 + (WORDS_BIG_ENDIAN ? -1 : 1))
743990075Sobrien	    output_asm_insn ("mov%?\t%Q0, %Q1\n\tmov%?\t%R0, %R1", operands);
744090075Sobrien	  else
744190075Sobrien	    output_asm_insn ("mov%?\t%R0, %R1\n\tmov%?\t%Q0, %Q1", operands);
744290075Sobrien	}
7443132718Skan      else if (code1 == CONST_VECTOR)
7444132718Skan	{
7445132718Skan	  HOST_WIDE_INT hint = 0;
7446132718Skan
7447132718Skan	  switch (GET_MODE (operands[1]))
7448132718Skan	    {
7449132718Skan	    case V2SImode:
7450132718Skan	      otherops[1] = GEN_INT (INTVAL (CONST_VECTOR_ELT (operands[1], 1)));
7451132718Skan	      operands[1] = GEN_INT (INTVAL (CONST_VECTOR_ELT (operands[1], 0)));
7452132718Skan	      break;
7453132718Skan
7454132718Skan	    case V4HImode:
7455132718Skan	      if (BYTES_BIG_ENDIAN)
7456132718Skan		{
7457132718Skan		  hint = INTVAL (CONST_VECTOR_ELT (operands[1], 2));
7458132718Skan		  hint <<= 16;
7459132718Skan		  hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 3));
7460132718Skan		}
7461132718Skan	      else
7462132718Skan		{
7463132718Skan		  hint = INTVAL (CONST_VECTOR_ELT (operands[1], 3));
7464132718Skan		  hint <<= 16;
7465132718Skan		  hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 2));
7466132718Skan		}
7467132718Skan
7468132718Skan	      otherops[1] = GEN_INT (hint);
7469132718Skan	      hint = 0;
7470132718Skan
7471132718Skan	      if (BYTES_BIG_ENDIAN)
7472132718Skan		{
7473132718Skan		  hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 0));
7474132718Skan		  hint <<= 16;
7475132718Skan		  hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 1));
7476132718Skan		}
7477132718Skan	      else
7478132718Skan		{
7479132718Skan		  hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 1));
7480132718Skan		  hint <<= 16;
7481132718Skan		  hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 0));
7482132718Skan		}
7483132718Skan
7484132718Skan	      operands[1] = GEN_INT (hint);
7485132718Skan	      break;
7486132718Skan
7487132718Skan	    case V8QImode:
7488132718Skan	      if (BYTES_BIG_ENDIAN)
7489132718Skan		{
7490132718Skan		  hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 4));
7491132718Skan		  hint <<= 8;
7492132718Skan		  hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 5));
7493132718Skan		  hint <<= 8;
7494132718Skan		  hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 6));
7495132718Skan		  hint <<= 8;
7496132718Skan		  hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 7));
7497132718Skan		}
7498132718Skan	      else
7499132718Skan		{
7500132718Skan		  hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 7));
7501132718Skan		  hint <<= 8;
7502132718Skan		  hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 6));
7503132718Skan		  hint <<= 8;
7504132718Skan		  hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 5));
7505132718Skan		  hint <<= 8;
7506132718Skan		  hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 4));
7507132718Skan		}
7508132718Skan
7509132718Skan	      otherops[1] = GEN_INT (hint);
7510132718Skan	      hint = 0;
7511132718Skan
7512132718Skan	      if (BYTES_BIG_ENDIAN)
7513132718Skan		{
7514132718Skan		  hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 0));
7515132718Skan		  hint <<= 8;
7516132718Skan		  hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 1));
7517132718Skan		  hint <<= 8;
7518132718Skan		  hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 2));
7519132718Skan		  hint <<= 8;
7520132718Skan		  hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 3));
7521132718Skan		}
7522132718Skan	      else
7523132718Skan		{
7524132718Skan		  hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 3));
7525132718Skan		  hint <<= 8;
7526132718Skan		  hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 2));
7527132718Skan		  hint <<= 8;
7528132718Skan		  hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 1));
7529132718Skan		  hint <<= 8;
7530132718Skan		  hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 0));
7531132718Skan		}
7532132718Skan
7533132718Skan	      operands[1] = GEN_INT (hint);
7534132718Skan	      break;
7535132718Skan
7536132718Skan	    default:
7537132718Skan	      abort ();
7538132718Skan	    }
7539132718Skan	  output_mov_immediate (operands);
7540132718Skan	  output_mov_immediate (otherops);
7541132718Skan	}
754290075Sobrien      else if (code1 == CONST_DOUBLE)
754390075Sobrien	{
754490075Sobrien	  if (GET_MODE (operands[1]) == DFmode)
754590075Sobrien	    {
7546117395Skan	      REAL_VALUE_TYPE r;
754790075Sobrien	      long l[2];
754890075Sobrien
7549117395Skan	      REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);
7550117395Skan	      REAL_VALUE_TO_TARGET_DOUBLE (r, l);
755190075Sobrien	      otherops[1] = GEN_INT (l[1]);
755290075Sobrien	      operands[1] = GEN_INT (l[0]);
755390075Sobrien	    }
755490075Sobrien	  else if (GET_MODE (operands[1]) != VOIDmode)
755590075Sobrien	    abort ();
755690075Sobrien	  else if (WORDS_BIG_ENDIAN)
755790075Sobrien	    {
755890075Sobrien	      otherops[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1]));
755990075Sobrien	      operands[1] = GEN_INT (CONST_DOUBLE_HIGH (operands[1]));
756090075Sobrien	    }
756190075Sobrien	  else
756290075Sobrien	    {
756390075Sobrien	      otherops[1] = GEN_INT (CONST_DOUBLE_HIGH (operands[1]));
756490075Sobrien	      operands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1]));
756590075Sobrien	    }
756690075Sobrien
756790075Sobrien	  output_mov_immediate (operands);
756890075Sobrien	  output_mov_immediate (otherops);
756990075Sobrien	}
757090075Sobrien      else if (code1 == CONST_INT)
757190075Sobrien	{
757290075Sobrien#if HOST_BITS_PER_WIDE_INT > 32
757390075Sobrien	  /* If HOST_WIDE_INT is more than 32 bits, the intval tells us
757490075Sobrien	     what the upper word is.  */
757590075Sobrien	  if (WORDS_BIG_ENDIAN)
757690075Sobrien	    {
757790075Sobrien	      otherops[1] = GEN_INT (ARM_SIGN_EXTEND (INTVAL (operands[1])));
757890075Sobrien	      operands[1] = GEN_INT (INTVAL (operands[1]) >> 32);
757990075Sobrien	    }
758090075Sobrien	  else
758190075Sobrien	    {
758290075Sobrien	      otherops[1] = GEN_INT (INTVAL (operands[1]) >> 32);
758390075Sobrien	      operands[1] = GEN_INT (ARM_SIGN_EXTEND (INTVAL (operands[1])));
758490075Sobrien	    }
758590075Sobrien#else
758690075Sobrien	  /* Sign extend the intval into the high-order word.  */
758790075Sobrien	  if (WORDS_BIG_ENDIAN)
758890075Sobrien	    {
758990075Sobrien	      otherops[1] = operands[1];
759090075Sobrien	      operands[1] = (INTVAL (operands[1]) < 0
759190075Sobrien			     ? constm1_rtx : const0_rtx);
759290075Sobrien	    }
759390075Sobrien	  else
759490075Sobrien	    otherops[1] = INTVAL (operands[1]) < 0 ? constm1_rtx : const0_rtx;
759590075Sobrien#endif
759690075Sobrien	  output_mov_immediate (otherops);
759790075Sobrien	  output_mov_immediate (operands);
759890075Sobrien	}
759990075Sobrien      else if (code1 == MEM)
760090075Sobrien	{
760190075Sobrien	  switch (GET_CODE (XEXP (operands[1], 0)))
760290075Sobrien	    {
760390075Sobrien	    case REG:
760490075Sobrien	      output_asm_insn ("ldm%?ia\t%m1, %M0", operands);
760590075Sobrien	      break;
760690075Sobrien
760790075Sobrien  	    case PRE_INC:
760890075Sobrien	      abort (); /* Should never happen now.  */
760990075Sobrien	      break;
761090075Sobrien
761190075Sobrien	    case PRE_DEC:
761290075Sobrien	      output_asm_insn ("ldm%?db\t%m1!, %M0", operands);
761390075Sobrien	      break;
761490075Sobrien
761590075Sobrien	    case POST_INC:
761690075Sobrien	      output_asm_insn ("ldm%?ia\t%m1!, %M0", operands);
761790075Sobrien	      break;
761890075Sobrien
761990075Sobrien	    case POST_DEC:
762090075Sobrien	      abort (); /* Should never happen now.  */
762190075Sobrien	      break;
762290075Sobrien
762390075Sobrien	    case LABEL_REF:
762490075Sobrien	    case CONST:
762590075Sobrien	      output_asm_insn ("adr%?\t%0, %1", operands);
762690075Sobrien	      output_asm_insn ("ldm%?ia\t%0, %M0", operands);
762790075Sobrien	      break;
762890075Sobrien
762990075Sobrien	    default:
763090075Sobrien	      if (arm_add_operand (XEXP (XEXP (operands[1], 0), 1),
763190075Sobrien				   GET_MODE (XEXP (XEXP (operands[1], 0), 1))))
763290075Sobrien		{
763390075Sobrien		  otherops[0] = operands[0];
763490075Sobrien		  otherops[1] = XEXP (XEXP (operands[1], 0), 0);
763590075Sobrien		  otherops[2] = XEXP (XEXP (operands[1], 0), 1);
763690075Sobrien
763790075Sobrien		  if (GET_CODE (XEXP (operands[1], 0)) == PLUS)
763890075Sobrien		    {
763990075Sobrien		      if (GET_CODE (otherops[2]) == CONST_INT)
764090075Sobrien			{
7641132718Skan			  switch ((int) INTVAL (otherops[2]))
764290075Sobrien			    {
764390075Sobrien			    case -8:
764490075Sobrien			      output_asm_insn ("ldm%?db\t%1, %M0", otherops);
764590075Sobrien			      return "";
764690075Sobrien			    case -4:
764790075Sobrien			      output_asm_insn ("ldm%?da\t%1, %M0", otherops);
764890075Sobrien			      return "";
764990075Sobrien			    case 4:
765090075Sobrien			      output_asm_insn ("ldm%?ib\t%1, %M0", otherops);
765190075Sobrien			      return "";
765290075Sobrien			    }
765390075Sobrien
765490075Sobrien			  if (!(const_ok_for_arm (INTVAL (otherops[2]))))
765590075Sobrien			    output_asm_insn ("sub%?\t%0, %1, #%n2", otherops);
765690075Sobrien			  else
765790075Sobrien			    output_asm_insn ("add%?\t%0, %1, %2", otherops);
765890075Sobrien			}
765990075Sobrien		      else
766090075Sobrien			output_asm_insn ("add%?\t%0, %1, %2", otherops);
766190075Sobrien		    }
766290075Sobrien		  else
766390075Sobrien		    output_asm_insn ("sub%?\t%0, %1, %2", otherops);
766490075Sobrien
766590075Sobrien		  return "ldm%?ia\t%0, %M0";
766690075Sobrien                }
766790075Sobrien              else
766890075Sobrien                {
7669117395Skan		  otherops[1] = adjust_address (operands[1], SImode, 4);
767090075Sobrien		  /* Take care of overlapping base/data reg.  */
767190075Sobrien		  if (reg_mentioned_p (operands[0], operands[1]))
767290075Sobrien		    {
767390075Sobrien		      output_asm_insn ("ldr%?\t%0, %1", otherops);
767490075Sobrien		      output_asm_insn ("ldr%?\t%0, %1", operands);
767590075Sobrien		    }
767690075Sobrien		  else
767790075Sobrien		    {
767890075Sobrien		      output_asm_insn ("ldr%?\t%0, %1", operands);
767990075Sobrien		      output_asm_insn ("ldr%?\t%0, %1", otherops);
768090075Sobrien		    }
768190075Sobrien		}
768290075Sobrien	    }
768390075Sobrien	}
768490075Sobrien      else
768590075Sobrien	abort ();  /* Constraints should prevent this.  */
768690075Sobrien    }
768790075Sobrien  else if (code0 == MEM && code1 == REG)
768890075Sobrien    {
768990075Sobrien      if (REGNO (operands[1]) == IP_REGNUM)
769090075Sobrien	abort ();
769190075Sobrien
769290075Sobrien      switch (GET_CODE (XEXP (operands[0], 0)))
769390075Sobrien        {
769490075Sobrien	case REG:
769590075Sobrien	  output_asm_insn ("stm%?ia\t%m0, %M1", operands);
769690075Sobrien	  break;
769790075Sobrien
769890075Sobrien        case PRE_INC:
769990075Sobrien	  abort (); /* Should never happen now.  */
770090075Sobrien	  break;
770190075Sobrien
770290075Sobrien        case PRE_DEC:
770390075Sobrien	  output_asm_insn ("stm%?db\t%m0!, %M1", operands);
770490075Sobrien	  break;
770590075Sobrien
770690075Sobrien        case POST_INC:
770790075Sobrien	  output_asm_insn ("stm%?ia\t%m0!, %M1", operands);
770890075Sobrien	  break;
770990075Sobrien
771090075Sobrien        case POST_DEC:
771190075Sobrien	  abort (); /* Should never happen now.  */
771290075Sobrien	  break;
771390075Sobrien
771490075Sobrien	case PLUS:
771590075Sobrien	  if (GET_CODE (XEXP (XEXP (operands[0], 0), 1)) == CONST_INT)
771690075Sobrien	    {
7717132718Skan	      switch ((int) INTVAL (XEXP (XEXP (operands[0], 0), 1)))
771890075Sobrien		{
771990075Sobrien		case -8:
772090075Sobrien		  output_asm_insn ("stm%?db\t%m0, %M1", operands);
772190075Sobrien		  return "";
772290075Sobrien
772390075Sobrien		case -4:
772490075Sobrien		  output_asm_insn ("stm%?da\t%m0, %M1", operands);
772590075Sobrien		  return "";
772690075Sobrien
772790075Sobrien		case 4:
772890075Sobrien		  output_asm_insn ("stm%?ib\t%m0, %M1", operands);
772990075Sobrien		  return "";
773090075Sobrien		}
773190075Sobrien	    }
773290075Sobrien	  /* Fall through */
773390075Sobrien
773490075Sobrien        default:
7735117395Skan	  otherops[0] = adjust_address (operands[0], SImode, 4);
773690075Sobrien	  otherops[1] = gen_rtx_REG (SImode, 1 + REGNO (operands[1]));
773790075Sobrien	  output_asm_insn ("str%?\t%1, %0", operands);
773890075Sobrien	  output_asm_insn ("str%?\t%1, %0", otherops);
773990075Sobrien	}
774090075Sobrien    }
774190075Sobrien  else
774290075Sobrien    /* Constraints should prevent this.  */
774390075Sobrien    abort ();
774490075Sobrien
774590075Sobrien  return "";
774690075Sobrien}
774790075Sobrien
774890075Sobrien
774990075Sobrien/* Output an arbitrary MOV reg, #n.
775090075Sobrien   OPERANDS[0] is a register.  OPERANDS[1] is a const_int.  */
775190075Sobrienconst char *
7752132718Skanoutput_mov_immediate (rtx *operands)
775390075Sobrien{
775490075Sobrien  HOST_WIDE_INT n = INTVAL (operands[1]);
775590075Sobrien
775690075Sobrien  /* Try to use one MOV.  */
775790075Sobrien  if (const_ok_for_arm (n))
775890075Sobrien    output_asm_insn ("mov%?\t%0, %1", operands);
775990075Sobrien
776090075Sobrien  /* Try to use one MVN.  */
776190075Sobrien  else if (const_ok_for_arm (~n))
776290075Sobrien    {
776390075Sobrien      operands[1] = GEN_INT (~n);
776490075Sobrien      output_asm_insn ("mvn%?\t%0, %1", operands);
776590075Sobrien    }
776690075Sobrien  else
776790075Sobrien    {
776890075Sobrien      int n_ones = 0;
776990075Sobrien      int i;
777090075Sobrien
777190075Sobrien      /* If all else fails, make it out of ORRs or BICs as appropriate.  */
7772132718Skan      for (i = 0; i < 32; i++)
777390075Sobrien	if (n & 1 << i)
7774132718Skan	  n_ones++;
777590075Sobrien
777690075Sobrien      if (n_ones > 16)  /* Shorter to use MVN with BIC in this case.  */
777790075Sobrien	output_multi_immediate (operands, "mvn%?\t%0, %1", "bic%?\t%0, %0, %1", 1, ~ n);
777890075Sobrien      else
777990075Sobrien	output_multi_immediate (operands, "mov%?\t%0, %1", "orr%?\t%0, %0, %1", 1, n);
778090075Sobrien    }
778190075Sobrien
778290075Sobrien  return "";
778390075Sobrien}
778490075Sobrien
778590075Sobrien/* Output an ADD r, s, #n where n may be too big for one instruction.
778690075Sobrien   If adding zero to one register, output nothing.  */
778790075Sobrienconst char *
7788132718Skanoutput_add_immediate (rtx *operands)
778990075Sobrien{
779090075Sobrien  HOST_WIDE_INT n = INTVAL (operands[2]);
779190075Sobrien
779290075Sobrien  if (n != 0 || REGNO (operands[0]) != REGNO (operands[1]))
779390075Sobrien    {
779490075Sobrien      if (n < 0)
779590075Sobrien	output_multi_immediate (operands,
779690075Sobrien				"sub%?\t%0, %1, %2", "sub%?\t%0, %0, %2", 2,
779790075Sobrien				-n);
779890075Sobrien      else
779990075Sobrien	output_multi_immediate (operands,
780090075Sobrien				"add%?\t%0, %1, %2", "add%?\t%0, %0, %2", 2,
780190075Sobrien				n);
780290075Sobrien    }
780390075Sobrien
780490075Sobrien  return "";
780590075Sobrien}
780690075Sobrien
780790075Sobrien/* Output a multiple immediate operation.
780890075Sobrien   OPERANDS is the vector of operands referred to in the output patterns.
780990075Sobrien   INSTR1 is the output pattern to use for the first constant.
781090075Sobrien   INSTR2 is the output pattern to use for subsequent constants.
781190075Sobrien   IMMED_OP is the index of the constant slot in OPERANDS.
781290075Sobrien   N is the constant value.  */
781390075Sobrienstatic const char *
7814132718Skanoutput_multi_immediate (rtx *operands, const char *instr1, const char *instr2,
7815132718Skan			int immed_op, HOST_WIDE_INT n)
781690075Sobrien{
781790075Sobrien#if HOST_BITS_PER_WIDE_INT > 32
781890075Sobrien  n &= 0xffffffff;
781990075Sobrien#endif
782090075Sobrien
782190075Sobrien  if (n == 0)
782290075Sobrien    {
782390075Sobrien      /* Quick and easy output.  */
782490075Sobrien      operands[immed_op] = const0_rtx;
782590075Sobrien      output_asm_insn (instr1, operands);
782690075Sobrien    }
782790075Sobrien  else
782890075Sobrien    {
782990075Sobrien      int i;
783090075Sobrien      const char * instr = instr1;
783190075Sobrien
783290075Sobrien      /* Note that n is never zero here (which would give no output).  */
783390075Sobrien      for (i = 0; i < 32; i += 2)
783490075Sobrien	{
783590075Sobrien	  if (n & (3 << i))
783690075Sobrien	    {
783790075Sobrien	      operands[immed_op] = GEN_INT (n & (255 << i));
783890075Sobrien	      output_asm_insn (instr, operands);
783990075Sobrien	      instr = instr2;
784090075Sobrien	      i += 6;
784190075Sobrien	    }
784290075Sobrien	}
784390075Sobrien    }
784490075Sobrien
784590075Sobrien  return "";
784690075Sobrien}
784790075Sobrien
784890075Sobrien/* Return the appropriate ARM instruction for the operation code.
784990075Sobrien   The returned result should not be overwritten.  OP is the rtx of the
785090075Sobrien   operation.  SHIFT_FIRST_ARG is TRUE if the first argument of the operator
785190075Sobrien   was shifted.  */
785290075Sobrienconst char *
7853132718Skanarithmetic_instr (rtx op, int shift_first_arg)
785490075Sobrien{
785590075Sobrien  switch (GET_CODE (op))
785690075Sobrien    {
785790075Sobrien    case PLUS:
785890075Sobrien      return "add";
785990075Sobrien
786090075Sobrien    case MINUS:
786190075Sobrien      return shift_first_arg ? "rsb" : "sub";
786290075Sobrien
786390075Sobrien    case IOR:
786490075Sobrien      return "orr";
786590075Sobrien
786690075Sobrien    case XOR:
786790075Sobrien      return "eor";
786890075Sobrien
786990075Sobrien    case AND:
787090075Sobrien      return "and";
787190075Sobrien
787290075Sobrien    default:
787390075Sobrien      abort ();
787490075Sobrien    }
787590075Sobrien}
787690075Sobrien
787790075Sobrien/* Ensure valid constant shifts and return the appropriate shift mnemonic
787890075Sobrien   for the operation code.  The returned result should not be overwritten.
787990075Sobrien   OP is the rtx code of the shift.
788090075Sobrien   On exit, *AMOUNTP will be -1 if the shift is by a register, or a constant
788190075Sobrien   shift.  */
788290075Sobrienstatic const char *
7883132718Skanshift_op (rtx op, HOST_WIDE_INT *amountp)
788490075Sobrien{
788590075Sobrien  const char * mnem;
788690075Sobrien  enum rtx_code code = GET_CODE (op);
788790075Sobrien
788890075Sobrien  if (GET_CODE (XEXP (op, 1)) == REG || GET_CODE (XEXP (op, 1)) == SUBREG)
788990075Sobrien    *amountp = -1;
789090075Sobrien  else if (GET_CODE (XEXP (op, 1)) == CONST_INT)
789190075Sobrien    *amountp = INTVAL (XEXP (op, 1));
789290075Sobrien  else
789390075Sobrien    abort ();
789490075Sobrien
789590075Sobrien  switch (code)
789690075Sobrien    {
789790075Sobrien    case ASHIFT:
789890075Sobrien      mnem = "asl";
789990075Sobrien      break;
790090075Sobrien
790190075Sobrien    case ASHIFTRT:
790290075Sobrien      mnem = "asr";
790390075Sobrien      break;
790490075Sobrien
790590075Sobrien    case LSHIFTRT:
790690075Sobrien      mnem = "lsr";
790790075Sobrien      break;
790890075Sobrien
790990075Sobrien    case ROTATERT:
791090075Sobrien      mnem = "ror";
791190075Sobrien      break;
791290075Sobrien
791390075Sobrien    case MULT:
791490075Sobrien      /* We never have to worry about the amount being other than a
791590075Sobrien	 power of 2, since this case can never be reloaded from a reg.  */
791690075Sobrien      if (*amountp != -1)
791790075Sobrien	*amountp = int_log2 (*amountp);
791890075Sobrien      else
791990075Sobrien	abort ();
792090075Sobrien      return "asl";
792190075Sobrien
792290075Sobrien    default:
792390075Sobrien      abort ();
792490075Sobrien    }
792590075Sobrien
792690075Sobrien  if (*amountp != -1)
792790075Sobrien    {
792890075Sobrien      /* This is not 100% correct, but follows from the desire to merge
792990075Sobrien	 multiplication by a power of 2 with the recognizer for a
793090075Sobrien	 shift.  >=32 is not a valid shift for "asl", so we must try and
793190075Sobrien	 output a shift that produces the correct arithmetical result.
793290075Sobrien	 Using lsr #32 is identical except for the fact that the carry bit
793390075Sobrien	 is not set correctly if we set the flags; but we never use the
793490075Sobrien	 carry bit from such an operation, so we can ignore that.  */
793590075Sobrien      if (code == ROTATERT)
793690075Sobrien	/* Rotate is just modulo 32.  */
793790075Sobrien	*amountp &= 31;
793890075Sobrien      else if (*amountp != (*amountp & 31))
793990075Sobrien	{
794090075Sobrien	  if (code == ASHIFT)
794190075Sobrien	    mnem = "lsr";
794290075Sobrien	  *amountp = 32;
794390075Sobrien	}
794490075Sobrien
794590075Sobrien      /* Shifts of 0 are no-ops.  */
794690075Sobrien      if (*amountp == 0)
794790075Sobrien	return NULL;
794890075Sobrien    }
794990075Sobrien
795090075Sobrien  return mnem;
795190075Sobrien}
795290075Sobrien
795390075Sobrien/* Obtain the shift from the POWER of two.  */
795490075Sobrien
795590075Sobrienstatic HOST_WIDE_INT
7956132718Skanint_log2 (HOST_WIDE_INT power)
795790075Sobrien{
795890075Sobrien  HOST_WIDE_INT shift = 0;
795990075Sobrien
796090075Sobrien  while ((((HOST_WIDE_INT) 1 << shift) & power) == 0)
796190075Sobrien    {
796290075Sobrien      if (shift > 31)
796390075Sobrien	abort ();
7964132718Skan      shift++;
796590075Sobrien    }
796690075Sobrien
796790075Sobrien  return shift;
796890075Sobrien}
796990075Sobrien
797090075Sobrien/* Output a .ascii pseudo-op, keeping track of lengths.  This is because
797190075Sobrien   /bin/as is horribly restrictive.  */
797290075Sobrien#define MAX_ASCII_LEN 51
797390075Sobrien
797490075Sobrienvoid
7975132718Skanoutput_ascii_pseudo_op (FILE *stream, const unsigned char *p, int len)
797690075Sobrien{
797790075Sobrien  int i;
797890075Sobrien  int len_so_far = 0;
797990075Sobrien
798090075Sobrien  fputs ("\t.ascii\t\"", stream);
798190075Sobrien
798290075Sobrien  for (i = 0; i < len; i++)
798390075Sobrien    {
798490075Sobrien      int c = p[i];
798590075Sobrien
798690075Sobrien      if (len_so_far >= MAX_ASCII_LEN)
798790075Sobrien	{
798890075Sobrien	  fputs ("\"\n\t.ascii\t\"", stream);
798990075Sobrien	  len_so_far = 0;
799090075Sobrien	}
799190075Sobrien
799290075Sobrien      switch (c)
799390075Sobrien	{
799490075Sobrien	case TARGET_TAB:
799590075Sobrien	  fputs ("\\t", stream);
799690075Sobrien	  len_so_far += 2;
799790075Sobrien	  break;
799890075Sobrien
799990075Sobrien	case TARGET_FF:
800090075Sobrien	  fputs ("\\f", stream);
800190075Sobrien	  len_so_far += 2;
800290075Sobrien	  break;
800390075Sobrien
800490075Sobrien	case TARGET_BS:
800590075Sobrien	  fputs ("\\b", stream);
800690075Sobrien	  len_so_far += 2;
800790075Sobrien	  break;
800890075Sobrien
800990075Sobrien	case TARGET_CR:
801090075Sobrien	  fputs ("\\r", stream);
801190075Sobrien	  len_so_far += 2;
801290075Sobrien	  break;
801390075Sobrien
801490075Sobrien	case TARGET_NEWLINE:
801590075Sobrien	  fputs ("\\n", stream);
801690075Sobrien	  c = p [i + 1];
801790075Sobrien	  if ((c >= ' ' && c <= '~')
801890075Sobrien	      || c == TARGET_TAB)
801990075Sobrien	    /* This is a good place for a line break.  */
802090075Sobrien	    len_so_far = MAX_ASCII_LEN;
802190075Sobrien	  else
802290075Sobrien	    len_so_far += 2;
802390075Sobrien	  break;
802490075Sobrien
802590075Sobrien	case '\"':
802690075Sobrien	case '\\':
802790075Sobrien	  putc ('\\', stream);
802890075Sobrien	  len_so_far++;
8029132718Skan	  /* Drop through.  */
803090075Sobrien
803190075Sobrien	default:
803290075Sobrien	  if (c >= ' ' && c <= '~')
803390075Sobrien	    {
803490075Sobrien	      putc (c, stream);
803590075Sobrien	      len_so_far++;
803690075Sobrien	    }
803790075Sobrien	  else
803890075Sobrien	    {
803990075Sobrien	      fprintf (stream, "\\%03o", c);
804090075Sobrien	      len_so_far += 4;
804190075Sobrien	    }
804290075Sobrien	  break;
804390075Sobrien	}
804490075Sobrien    }
804590075Sobrien
804690075Sobrien  fputs ("\"\n", stream);
804790075Sobrien}
804890075Sobrien
804990075Sobrien/* Compute the register sabe mask for registers 0 through 12
805090075Sobrien   inclusive.  This code is used by both arm_compute_save_reg_mask
805190075Sobrien   and arm_compute_initial_elimination_offset.  */
805290075Sobrienstatic unsigned long
8053132718Skanarm_compute_save_reg0_reg12_mask (void)
805490075Sobrien{
805590075Sobrien  unsigned long func_type = arm_current_func_type ();
805690075Sobrien  unsigned int save_reg_mask = 0;
805790075Sobrien  unsigned int reg;
805890075Sobrien
805990075Sobrien  if (IS_INTERRUPT (func_type))
806090075Sobrien    {
806190075Sobrien      unsigned int max_reg;
806290075Sobrien      /* Interrupt functions must not corrupt any registers,
806390075Sobrien	 even call clobbered ones.  If this is a leaf function
806490075Sobrien	 we can just examine the registers used by the RTL, but
806590075Sobrien	 otherwise we have to assume that whatever function is
806690075Sobrien	 called might clobber anything, and so we have to save
806790075Sobrien	 all the call-clobbered registers as well.  */
806890075Sobrien      if (ARM_FUNC_TYPE (func_type) == ARM_FT_FIQ)
806990075Sobrien	/* FIQ handlers have registers r8 - r12 banked, so
807090075Sobrien	   we only need to check r0 - r7, Normal ISRs only
807190075Sobrien	   bank r14 and r15, so we must check up to r12.
807290075Sobrien	   r13 is the stack pointer which is always preserved,
807390075Sobrien	   so we do not need to consider it here.  */
807490075Sobrien	max_reg = 7;
807590075Sobrien      else
807690075Sobrien	max_reg = 12;
807790075Sobrien
807890075Sobrien      for (reg = 0; reg <= max_reg; reg++)
807990075Sobrien	if (regs_ever_live[reg]
808090075Sobrien	    || (! current_function_is_leaf && call_used_regs [reg]))
808190075Sobrien	  save_reg_mask |= (1 << reg);
808290075Sobrien    }
808390075Sobrien  else
808490075Sobrien    {
808590075Sobrien      /* In the normal case we only need to save those registers
808690075Sobrien	 which are call saved and which are used by this function.  */
808790075Sobrien      for (reg = 0; reg <= 10; reg++)
808890075Sobrien	if (regs_ever_live[reg] && ! call_used_regs [reg])
808990075Sobrien	  save_reg_mask |= (1 << reg);
809090075Sobrien
809190075Sobrien      /* Handle the frame pointer as a special case.  */
809290075Sobrien      if (! TARGET_APCS_FRAME
809390075Sobrien	  && ! frame_pointer_needed
809490075Sobrien	  && regs_ever_live[HARD_FRAME_POINTER_REGNUM]
809590075Sobrien	  && ! call_used_regs[HARD_FRAME_POINTER_REGNUM])
809690075Sobrien	save_reg_mask |= 1 << HARD_FRAME_POINTER_REGNUM;
809790075Sobrien
809890075Sobrien      /* If we aren't loading the PIC register,
809990075Sobrien	 don't stack it even though it may be live.  */
810090075Sobrien      if (flag_pic
810190075Sobrien	  && ! TARGET_SINGLE_PIC_BASE
810290075Sobrien	  && regs_ever_live[PIC_OFFSET_TABLE_REGNUM])
810390075Sobrien	save_reg_mask |= 1 << PIC_OFFSET_TABLE_REGNUM;
810490075Sobrien    }
810590075Sobrien
810690075Sobrien  return save_reg_mask;
810790075Sobrien}
810890075Sobrien
810990075Sobrien/* Compute a bit mask of which registers need to be
811090075Sobrien   saved on the stack for the current function.  */
811190075Sobrien
811290075Sobrienstatic unsigned long
8113132718Skanarm_compute_save_reg_mask (void)
811490075Sobrien{
811590075Sobrien  unsigned int save_reg_mask = 0;
811690075Sobrien  unsigned long func_type = arm_current_func_type ();
811790075Sobrien
811890075Sobrien  if (IS_NAKED (func_type))
811990075Sobrien    /* This should never really happen.  */
812090075Sobrien    return 0;
812190075Sobrien
812290075Sobrien  /* If we are creating a stack frame, then we must save the frame pointer,
812390075Sobrien     IP (which will hold the old stack pointer), LR and the PC.  */
812490075Sobrien  if (frame_pointer_needed)
812590075Sobrien    save_reg_mask |=
812690075Sobrien      (1 << ARM_HARD_FRAME_POINTER_REGNUM)
812790075Sobrien      | (1 << IP_REGNUM)
812890075Sobrien      | (1 << LR_REGNUM)
812990075Sobrien      | (1 << PC_REGNUM);
813090075Sobrien
813190075Sobrien  /* Volatile functions do not return, so there
813290075Sobrien     is no need to save any other registers.  */
813390075Sobrien  if (IS_VOLATILE (func_type))
813490075Sobrien    return save_reg_mask;
813590075Sobrien
813690075Sobrien  save_reg_mask |= arm_compute_save_reg0_reg12_mask ();
813790075Sobrien
813890075Sobrien  /* Decide if we need to save the link register.
813990075Sobrien     Interrupt routines have their own banked link register,
814090075Sobrien     so they never need to save it.
814196263Sobrien     Otherwise if we do not use the link register we do not need to save
814290075Sobrien     it.  If we are pushing other registers onto the stack however, we
814390075Sobrien     can save an instruction in the epilogue by pushing the link register
814490075Sobrien     now and then popping it back into the PC.  This incurs extra memory
8145132718Skan     accesses though, so we only do it when optimizing for size, and only
814690075Sobrien     if we know that we will not need a fancy return sequence.  */
814796263Sobrien  if (regs_ever_live [LR_REGNUM]
814890075Sobrien	  || (save_reg_mask
814990075Sobrien	      && optimize_size
815096263Sobrien	      && ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL))
815190075Sobrien    save_reg_mask |= 1 << LR_REGNUM;
815290075Sobrien
815390075Sobrien  if (cfun->machine->lr_save_eliminated)
815490075Sobrien    save_reg_mask &= ~ (1 << LR_REGNUM);
815590075Sobrien
8156132718Skan  if (TARGET_REALLY_IWMMXT
8157132718Skan      && ((bit_count (save_reg_mask)
8158132718Skan	   + ARM_NUM_INTS (current_function_pretend_args_size)) % 2) != 0)
8159132718Skan    {
8160132718Skan      unsigned int reg;
8161132718Skan
8162132718Skan      /* The total number of registers that are going to be pushed
8163132718Skan	 onto the stack is odd.  We need to ensure that the stack
8164132718Skan	 is 64-bit aligned before we start to save iWMMXt registers,
8165132718Skan	 and also before we start to create locals.  (A local variable
8166132718Skan	 might be a double or long long which we will load/store using
8167132718Skan	 an iWMMXt instruction).  Therefore we need to push another
8168132718Skan	 ARM register, so that the stack will be 64-bit aligned.  We
8169132718Skan	 try to avoid using the arg registers (r0 -r3) as they might be
8170132718Skan	 used to pass values in a tail call.  */
8171132718Skan      for (reg = 4; reg <= 12; reg++)
8172132718Skan	if ((save_reg_mask & (1 << reg)) == 0)
8173132718Skan	  break;
8174132718Skan
8175132718Skan      if (reg <= 12)
8176132718Skan	save_reg_mask |= (1 << reg);
8177132718Skan      else
8178132718Skan	{
8179132718Skan	  cfun->machine->sibcall_blocked = 1;
8180132718Skan	  save_reg_mask |= (1 << 3);
8181132718Skan	}
8182132718Skan    }
8183132718Skan
818490075Sobrien  return save_reg_mask;
818590075Sobrien}
818690075Sobrien
8187132718Skan/* Generate a function exit sequence.  If REALLY_RETURN is false, then do
818890075Sobrien   everything bar the final return instruction.  */
818990075Sobrienconst char *
8190132718Skanoutput_return_instruction (rtx operand, int really_return, int reverse)
819190075Sobrien{
819290075Sobrien  char conditional[10];
819390075Sobrien  char instr[100];
819490075Sobrien  int reg;
819590075Sobrien  unsigned long live_regs_mask;
819690075Sobrien  unsigned long func_type;
8197117395Skan
819890075Sobrien  func_type = arm_current_func_type ();
819990075Sobrien
820090075Sobrien  if (IS_NAKED (func_type))
820190075Sobrien    return "";
820290075Sobrien
820390075Sobrien  if (IS_VOLATILE (func_type) && TARGET_ABORT_NORETURN)
820490075Sobrien    {
8205132718Skan      /* If this function was declared non-returning, and we have
8206132718Skan	 found a tail call, then we have to trust that the called
8207132718Skan	 function won't return.  */
820890075Sobrien      if (really_return)
820990075Sobrien	{
821090075Sobrien	  rtx ops[2];
821190075Sobrien
821290075Sobrien	  /* Otherwise, trap an attempted return by aborting.  */
821390075Sobrien	  ops[0] = operand;
821490075Sobrien	  ops[1] = gen_rtx_SYMBOL_REF (Pmode, NEED_PLT_RELOC ? "abort(PLT)"
821590075Sobrien				       : "abort");
821690075Sobrien	  assemble_external_libcall (ops[1]);
821790075Sobrien	  output_asm_insn (reverse ? "bl%D0\t%a1" : "bl%d0\t%a1", ops);
821890075Sobrien	}
821990075Sobrien
822090075Sobrien      return "";
822190075Sobrien    }
822290075Sobrien
822390075Sobrien  if (current_function_calls_alloca && !really_return)
822490075Sobrien    abort ();
822590075Sobrien
822690075Sobrien  sprintf (conditional, "%%?%%%c0", reverse ? 'D' : 'd');
822790075Sobrien
822890075Sobrien  return_used_this_function = 1;
822990075Sobrien
823090075Sobrien  live_regs_mask = arm_compute_save_reg_mask ();
823190075Sobrien
823296263Sobrien  if (live_regs_mask)
823390075Sobrien    {
823496263Sobrien      const char * return_reg;
823596263Sobrien
823696263Sobrien      /* If we do not have any special requirements for function exit
823796263Sobrien	 (eg interworking, or ISR) then we can load the return address
823896263Sobrien	 directly into the PC.  Otherwise we must load it into LR.  */
823996263Sobrien      if (really_return
824096263Sobrien	  && ! TARGET_INTERWORK)
824196263Sobrien	return_reg = reg_names[PC_REGNUM];
824290075Sobrien      else
824396263Sobrien	return_reg = reg_names[LR_REGNUM];
824496263Sobrien
824590075Sobrien      if ((live_regs_mask & (1 << IP_REGNUM)) == (1 << IP_REGNUM))
8246132718Skan	{
8247132718Skan	  /* There are three possible reasons for the IP register
8248132718Skan	     being saved.  1) a stack frame was created, in which case
8249132718Skan	     IP contains the old stack pointer, or 2) an ISR routine
8250132718Skan	     corrupted it, or 3) it was saved to align the stack on
8251132718Skan	     iWMMXt.  In case 1, restore IP into SP, otherwise just
8252132718Skan	     restore IP.  */
8253132718Skan	  if (frame_pointer_needed)
8254132718Skan	    {
8255132718Skan	      live_regs_mask &= ~ (1 << IP_REGNUM);
8256132718Skan	      live_regs_mask |=   (1 << SP_REGNUM);
8257132718Skan	    }
8258132718Skan	  else
8259132718Skan	    {
8260132718Skan	      if (! IS_INTERRUPT (func_type)
8261132718Skan		  && ! TARGET_REALLY_IWMMXT)
8262132718Skan		abort ();
8263132718Skan	    }
8264132718Skan	}
826590075Sobrien
826696263Sobrien      /* On some ARM architectures it is faster to use LDR rather than
826796263Sobrien	 LDM to load a single register.  On other architectures, the
826896263Sobrien	 cost is the same.  In 26 bit mode, or for exception handlers,
826996263Sobrien	 we have to use LDM to load the PC so that the CPSR is also
827096263Sobrien	 restored.  */
827196263Sobrien      for (reg = 0; reg <= LAST_ARM_REGNUM; reg++)
827290075Sobrien	{
827396263Sobrien	  if (live_regs_mask == (unsigned int)(1 << reg))
827496263Sobrien	    break;
827590075Sobrien	}
827696263Sobrien      if (reg <= LAST_ARM_REGNUM
827796263Sobrien	  && (reg != LR_REGNUM
827896263Sobrien	      || ! really_return
827996263Sobrien	      || (TARGET_APCS_32 && ! IS_INTERRUPT (func_type))))
828096263Sobrien	{
828196263Sobrien	  sprintf (instr, "ldr%s\t%%|%s, [%%|sp], #4", conditional,
828296263Sobrien		   (reg == LR_REGNUM) ? return_reg : reg_names[reg]);
828396263Sobrien	}
828490075Sobrien      else
828590075Sobrien	{
828696263Sobrien	  char *p;
828796263Sobrien	  int first = 1;
828890075Sobrien
8289132718Skan	  /* Generate the load multiple instruction to restore the
8290132718Skan	     registers.  Note we can get here, even if
8291132718Skan	     frame_pointer_needed is true, but only if sp already
8292132718Skan	     points to the base of the saved core registers.  */
8293132718Skan	  if (live_regs_mask & (1 << SP_REGNUM))
8294132718Skan	    {
8295132718Skan	      unsigned HOST_WIDE_INT stack_adjust =
8296132718Skan		arm_get_frame_size () + current_function_outgoing_args_size;
8297132718Skan
8298132718Skan	      if (stack_adjust != 0 && stack_adjust != 4)
8299132718Skan		abort ();
8300132718Skan
8301132718Skan	      if (stack_adjust && arm_arch5)
8302132718Skan		sprintf (instr, "ldm%sib\t%%|sp, {", conditional);
8303132718Skan	      else
8304132718Skan		{
8305132718Skan		  /* If we can't use ldmib (SA110 bug), then try to pop r3
8306132718Skan		     instead.  */
8307132718Skan		  if (stack_adjust)
8308132718Skan		    live_regs_mask |= 1 << 3;
8309132718Skan		  sprintf (instr, "ldm%sfd\t%%|sp, {", conditional);
8310132718Skan		}
8311132718Skan	    }
831290075Sobrien	  else
831396263Sobrien	    sprintf (instr, "ldm%sfd\t%%|sp!, {", conditional);
831490075Sobrien
831596263Sobrien	  p = instr + strlen (instr);
831690075Sobrien
831796263Sobrien	  for (reg = 0; reg <= SP_REGNUM; reg++)
831896263Sobrien	    if (live_regs_mask & (1 << reg))
831996263Sobrien	      {
832096263Sobrien		int l = strlen (reg_names[reg]);
832190075Sobrien
832296263Sobrien		if (first)
832396263Sobrien		  first = 0;
832496263Sobrien		else
832596263Sobrien		  {
832696263Sobrien		    memcpy (p, ", ", 2);
832796263Sobrien		    p += 2;
832896263Sobrien		  }
832990075Sobrien
833096263Sobrien		memcpy (p, "%|", 2);
833196263Sobrien		memcpy (p + 2, reg_names[reg], l);
833296263Sobrien		p += l + 2;
833396263Sobrien	      }
833496263Sobrien
833596263Sobrien	  if (live_regs_mask & (1 << LR_REGNUM))
833696263Sobrien	    {
8337132718Skan	      sprintf (p, "%s%%|%s}", first ? "" : ", ", return_reg);
8338132718Skan	      /* Decide if we need to add the ^ symbol to the end of the
8339132718Skan		 register list.	 This causes the saved condition codes
8340132718Skan		 register to be copied into the current condition codes
8341132718Skan		 register.  We do the copy if we are conforming to the 32-bit
8342132718Skan		 ABI and this is an interrupt function, or if we are
8343132718Skan		 conforming to the 26-bit ABI.  There is a special case for
8344132718Skan		 the 26-bit ABI however, which is if we are writing back the
8345132718Skan		 stack pointer but not loading the PC.  In this case adding
8346132718Skan		 the ^ symbol would create a type 2 LDM instruction, where
8347132718Skan		 writeback is UNPREDICTABLE.  We are safe in leaving the ^
8348132718Skan		 character off in this case however, since the actual return
8349132718Skan		 instruction will be a MOVS which will restore the CPSR.  */
8350132718Skan	      if ((TARGET_APCS_32 && IS_INTERRUPT (func_type))
8351132718Skan		  || (! TARGET_APCS_32 && really_return))
8352132718Skan		strcat (p, "^");
835390075Sobrien	    }
835496263Sobrien	  else
835596263Sobrien	    strcpy (p, "}");
835690075Sobrien	}
835796263Sobrien
835896263Sobrien      output_asm_insn (instr, & operand);
835996263Sobrien
836096263Sobrien      /* See if we need to generate an extra instruction to
836196263Sobrien	 perform the actual function return.  */
836296263Sobrien      if (really_return
836396263Sobrien	  && func_type != ARM_FT_INTERWORKED
836496263Sobrien	  && (live_regs_mask & (1 << LR_REGNUM)) != 0)
836596263Sobrien	{
836696263Sobrien	  /* The return has already been handled
836796263Sobrien	     by loading the LR into the PC.  */
836896263Sobrien	  really_return = 0;
836996263Sobrien	}
837090075Sobrien    }
8371117395Skan
837296263Sobrien  if (really_return)
837390075Sobrien    {
837490075Sobrien      switch ((int) ARM_FUNC_TYPE (func_type))
837590075Sobrien	{
837690075Sobrien	case ARM_FT_ISR:
837790075Sobrien	case ARM_FT_FIQ:
837890075Sobrien	  sprintf (instr, "sub%ss\t%%|pc, %%|lr, #4", conditional);
837990075Sobrien	  break;
838090075Sobrien
838190075Sobrien	case ARM_FT_INTERWORKED:
838290075Sobrien	  sprintf (instr, "bx%s\t%%|lr", conditional);
838390075Sobrien	  break;
838490075Sobrien
838590075Sobrien	case ARM_FT_EXCEPTION:
838690075Sobrien	  sprintf (instr, "mov%ss\t%%|pc, %%|lr", conditional);
838790075Sobrien	  break;
838890075Sobrien
838990075Sobrien	default:
839096263Sobrien	  /* ARMv5 implementations always provide BX, so interworking
839196263Sobrien	     is the default unless APCS-26 is in use.  */
839296263Sobrien	  if ((insn_flags & FL_ARCH5) != 0 && TARGET_APCS_32)
839396263Sobrien	    sprintf (instr, "bx%s\t%%|lr", conditional);
839496263Sobrien	  else
839596263Sobrien	    sprintf (instr, "mov%s%s\t%%|pc, %%|lr",
839696263Sobrien		     conditional, TARGET_APCS_32 ? "" : "s");
839790075Sobrien	  break;
839890075Sobrien	}
839996263Sobrien
840096263Sobrien      output_asm_insn (instr, & operand);
840190075Sobrien    }
840290075Sobrien
840390075Sobrien  return "";
840490075Sobrien}
840590075Sobrien
840690075Sobrien/* Write the function name into the code section, directly preceding
840790075Sobrien   the function prologue.
840890075Sobrien
840990075Sobrien   Code will be output similar to this:
841090075Sobrien     t0
841190075Sobrien	 .ascii "arm_poke_function_name", 0
841290075Sobrien	 .align
841390075Sobrien     t1
841490075Sobrien	 .word 0xff000000 + (t1 - t0)
841590075Sobrien     arm_poke_function_name
841690075Sobrien	 mov     ip, sp
841790075Sobrien	 stmfd   sp!, {fp, ip, lr, pc}
841890075Sobrien	 sub     fp, ip, #4
841990075Sobrien
842090075Sobrien   When performing a stack backtrace, code can inspect the value
842190075Sobrien   of 'pc' stored at 'fp' + 0.  If the trace function then looks
842290075Sobrien   at location pc - 12 and the top 8 bits are set, then we know
842390075Sobrien   that there is a function name embedded immediately preceding this
842490075Sobrien   location and has length ((pc[-3]) & 0xff000000).
842590075Sobrien
842690075Sobrien   We assume that pc is declared as a pointer to an unsigned long.
842790075Sobrien
842890075Sobrien   It is of no benefit to output the function name if we are assembling
842990075Sobrien   a leaf function.  These function types will not contain a stack
843090075Sobrien   backtrace structure, therefore it is not possible to determine the
843190075Sobrien   function name.  */
843290075Sobrienvoid
8433132718Skanarm_poke_function_name (FILE *stream, const char *name)
843490075Sobrien{
843590075Sobrien  unsigned long alignlength;
843690075Sobrien  unsigned long length;
843790075Sobrien  rtx           x;
843890075Sobrien
843990075Sobrien  length      = strlen (name) + 1;
8440132718Skan  alignlength = ROUND_UP_WORD (length);
844190075Sobrien
844290075Sobrien  ASM_OUTPUT_ASCII (stream, name, length);
844390075Sobrien  ASM_OUTPUT_ALIGN (stream, 2);
844490075Sobrien  x = GEN_INT ((unsigned HOST_WIDE_INT) 0xff000000 + alignlength);
844590075Sobrien  assemble_aligned_integer (UNITS_PER_WORD, x);
844690075Sobrien}
844790075Sobrien
844890075Sobrien/* Place some comments into the assembler stream
844990075Sobrien   describing the current function.  */
845090075Sobrienstatic void
8451132718Skanarm_output_function_prologue (FILE *f, HOST_WIDE_INT frame_size)
845290075Sobrien{
845390075Sobrien  unsigned long func_type;
845490075Sobrien
845590075Sobrien  if (!TARGET_ARM)
845690075Sobrien    {
845790075Sobrien      thumb_output_function_prologue (f, frame_size);
845890075Sobrien      return;
845990075Sobrien    }
846090075Sobrien
846190075Sobrien  /* Sanity check.  */
846290075Sobrien  if (arm_ccfsm_state || arm_target_insn)
846390075Sobrien    abort ();
846490075Sobrien
846590075Sobrien  func_type = arm_current_func_type ();
846690075Sobrien
846790075Sobrien  switch ((int) ARM_FUNC_TYPE (func_type))
846890075Sobrien    {
846990075Sobrien    default:
847090075Sobrien    case ARM_FT_NORMAL:
847190075Sobrien      break;
847290075Sobrien    case ARM_FT_INTERWORKED:
847390075Sobrien      asm_fprintf (f, "\t%@ Function supports interworking.\n");
847490075Sobrien      break;
847590075Sobrien    case ARM_FT_EXCEPTION_HANDLER:
847690075Sobrien      asm_fprintf (f, "\t%@ C++ Exception Handler.\n");
847790075Sobrien      break;
847890075Sobrien    case ARM_FT_ISR:
847990075Sobrien      asm_fprintf (f, "\t%@ Interrupt Service Routine.\n");
848090075Sobrien      break;
848190075Sobrien    case ARM_FT_FIQ:
848290075Sobrien      asm_fprintf (f, "\t%@ Fast Interrupt Service Routine.\n");
848390075Sobrien      break;
848490075Sobrien    case ARM_FT_EXCEPTION:
848590075Sobrien      asm_fprintf (f, "\t%@ ARM Exception Handler.\n");
848690075Sobrien      break;
848790075Sobrien    }
848890075Sobrien
848990075Sobrien  if (IS_NAKED (func_type))
849090075Sobrien    asm_fprintf (f, "\t%@ Naked Function: prologue and epilogue provided by programmer.\n");
849190075Sobrien
849290075Sobrien  if (IS_VOLATILE (func_type))
849390075Sobrien    asm_fprintf (f, "\t%@ Volatile: function does not return.\n");
849490075Sobrien
849590075Sobrien  if (IS_NESTED (func_type))
849690075Sobrien    asm_fprintf (f, "\t%@ Nested: function declared inside another function.\n");
849790075Sobrien
8498132718Skan  asm_fprintf (f, "\t%@ args = %d, pretend = %d, frame = %wd\n",
849990075Sobrien	       current_function_args_size,
850090075Sobrien	       current_function_pretend_args_size, frame_size);
850190075Sobrien
850296263Sobrien  asm_fprintf (f, "\t%@ frame_needed = %d, uses_anonymous_args = %d\n",
850390075Sobrien	       frame_pointer_needed,
850496263Sobrien	       cfun->machine->uses_anonymous_args);
850590075Sobrien
850690075Sobrien  if (cfun->machine->lr_save_eliminated)
850790075Sobrien    asm_fprintf (f, "\t%@ link register save eliminated.\n");
850890075Sobrien
850990075Sobrien#ifdef AOF_ASSEMBLER
851090075Sobrien  if (flag_pic)
851190075Sobrien    asm_fprintf (f, "\tmov\t%r, %r\n", IP_REGNUM, PIC_OFFSET_TABLE_REGNUM);
851290075Sobrien#endif
851390075Sobrien
851490075Sobrien  return_used_this_function = 0;
851590075Sobrien}
851690075Sobrien
851790075Sobrienconst char *
8518132718Skanarm_output_epilogue (rtx sibling)
851990075Sobrien{
852090075Sobrien  int reg;
852190075Sobrien  unsigned long saved_regs_mask;
852290075Sobrien  unsigned long func_type;
852396263Sobrien  /* Floats_offset is the offset from the "virtual" frame.  In an APCS
852496263Sobrien     frame that is $fp + 4 for a non-variadic function.  */
852596263Sobrien  int floats_offset = 0;
852690075Sobrien  rtx operands[3];
8527117395Skan  int frame_size = arm_get_frame_size ();
852890075Sobrien  FILE * f = asm_out_file;
852990075Sobrien  rtx eh_ofs = cfun->machine->eh_epilogue_sp_ofs;
8530132718Skan  unsigned int lrm_count = 0;
8531132718Skan  int really_return = (sibling == NULL);
853290075Sobrien
853390075Sobrien  /* If we have already generated the return instruction
853490075Sobrien     then it is futile to generate anything else.  */
8535132718Skan  if (use_return_insn (FALSE, sibling) && return_used_this_function)
853690075Sobrien    return "";
853790075Sobrien
853890075Sobrien  func_type = arm_current_func_type ();
853990075Sobrien
854090075Sobrien  if (IS_NAKED (func_type))
854190075Sobrien    /* Naked functions don't have epilogues.  */
854290075Sobrien    return "";
854390075Sobrien
854490075Sobrien  if (IS_VOLATILE (func_type) && TARGET_ABORT_NORETURN)
854590075Sobrien    {
854690075Sobrien      rtx op;
854790075Sobrien
854890075Sobrien      /* A volatile function should never return.  Call abort.  */
854990075Sobrien      op = gen_rtx_SYMBOL_REF (Pmode, NEED_PLT_RELOC ? "abort(PLT)" : "abort");
855090075Sobrien      assemble_external_libcall (op);
855190075Sobrien      output_asm_insn ("bl\t%a0", &op);
855290075Sobrien
855390075Sobrien      return "";
855490075Sobrien    }
855590075Sobrien
855690075Sobrien  if (ARM_FUNC_TYPE (func_type) == ARM_FT_EXCEPTION_HANDLER
855790075Sobrien      && ! really_return)
855890075Sobrien    /* If we are throwing an exception, then we really must
855990075Sobrien       be doing a return,  so we can't tail-call.  */
856090075Sobrien    abort ();
856190075Sobrien
856290075Sobrien  saved_regs_mask = arm_compute_save_reg_mask ();
8563132718Skan
8564132718Skan  if (TARGET_IWMMXT)
8565132718Skan    lrm_count = bit_count (saved_regs_mask);
8566132718Skan
856796263Sobrien  /* XXX We should adjust floats_offset for any anonymous args, and then
856896263Sobrien     re-adjust vfp_offset below to compensate.  */
856996263Sobrien
857090075Sobrien  /* Compute how far away the floats will be.  */
8571132718Skan  for (reg = 0; reg <= LAST_ARM_REGNUM; reg++)
857290075Sobrien    if (saved_regs_mask & (1 << reg))
857390075Sobrien      floats_offset += 4;
857490075Sobrien
857590075Sobrien  if (frame_pointer_needed)
857690075Sobrien    {
857796263Sobrien      int vfp_offset = 4;
857896263Sobrien
8579132718Skan      if (arm_fpu_arch == FPUTYPE_FPA_EMU2)
858090075Sobrien	{
858190075Sobrien	  for (reg = LAST_ARM_FP_REGNUM; reg >= FIRST_ARM_FP_REGNUM; reg--)
858290075Sobrien	    if (regs_ever_live[reg] && !call_used_regs[reg])
858390075Sobrien	      {
858490075Sobrien		floats_offset += 12;
858590075Sobrien		asm_fprintf (f, "\tldfe\t%r, [%r, #-%d]\n",
858696263Sobrien			     reg, FP_REGNUM, floats_offset - vfp_offset);
858790075Sobrien	      }
858890075Sobrien	}
858990075Sobrien      else
859090075Sobrien	{
859190075Sobrien	  int start_reg = LAST_ARM_FP_REGNUM;
859290075Sobrien
859390075Sobrien	  for (reg = LAST_ARM_FP_REGNUM; reg >= FIRST_ARM_FP_REGNUM; reg--)
859490075Sobrien	    {
859590075Sobrien	      if (regs_ever_live[reg] && !call_used_regs[reg])
859690075Sobrien		{
859790075Sobrien		  floats_offset += 12;
859890075Sobrien
859990075Sobrien		  /* We can't unstack more than four registers at once.  */
860090075Sobrien		  if (start_reg - reg == 3)
860190075Sobrien		    {
860290075Sobrien		      asm_fprintf (f, "\tlfm\t%r, 4, [%r, #-%d]\n",
860396263Sobrien			           reg, FP_REGNUM, floats_offset - vfp_offset);
860490075Sobrien		      start_reg = reg - 1;
860590075Sobrien		    }
860690075Sobrien		}
860790075Sobrien	      else
860890075Sobrien		{
860990075Sobrien		  if (reg != start_reg)
861090075Sobrien		    asm_fprintf (f, "\tlfm\t%r, %d, [%r, #-%d]\n",
861190075Sobrien				 reg + 1, start_reg - reg,
861296263Sobrien				 FP_REGNUM, floats_offset - vfp_offset);
861390075Sobrien		  start_reg = reg - 1;
861490075Sobrien		}
861590075Sobrien	    }
861690075Sobrien
861790075Sobrien	  /* Just in case the last register checked also needs unstacking.  */
861890075Sobrien	  if (reg != start_reg)
861990075Sobrien	    asm_fprintf (f, "\tlfm\t%r, %d, [%r, #-%d]\n",
862090075Sobrien			 reg + 1, start_reg - reg,
862196263Sobrien			 FP_REGNUM, floats_offset - vfp_offset);
862290075Sobrien	}
862390075Sobrien
8624132718Skan      if (TARGET_IWMMXT)
8625132718Skan	{
8626132718Skan	  /* The frame pointer is guaranteed to be non-double-word aligned.
8627132718Skan	     This is because it is set to (old_stack_pointer - 4) and the
8628132718Skan	     old_stack_pointer was double word aligned.  Thus the offset to
8629132718Skan	     the iWMMXt registers to be loaded must also be non-double-word
8630132718Skan	     sized, so that the resultant address *is* double-word aligned.
8631132718Skan	     We can ignore floats_offset since that was already included in
8632132718Skan	     the live_regs_mask.  */
8633132718Skan	  lrm_count += (lrm_count % 2 ? 2 : 1);
8634132718Skan
8635132718Skan	  for (reg = FIRST_IWMMXT_REGNUM; reg <= LAST_IWMMXT_REGNUM; reg++)
8636132718Skan	    if (regs_ever_live[reg] && !call_used_regs[reg])
8637132718Skan	      {
8638132718Skan		asm_fprintf (f, "\twldrd\t%r, [%r, #-%d]\n",
8639132718Skan			     reg, FP_REGNUM, lrm_count * 4);
8640132718Skan		lrm_count += 2;
8641132718Skan	      }
8642132718Skan	}
8643132718Skan
864490075Sobrien      /* saved_regs_mask should contain the IP, which at the time of stack
864590075Sobrien	 frame generation actually contains the old stack pointer.  So a
864690075Sobrien	 quick way to unwind the stack is just pop the IP register directly
864790075Sobrien	 into the stack pointer.  */
864890075Sobrien      if ((saved_regs_mask & (1 << IP_REGNUM)) == 0)
864990075Sobrien	abort ();
865090075Sobrien      saved_regs_mask &= ~ (1 << IP_REGNUM);
865190075Sobrien      saved_regs_mask |=   (1 << SP_REGNUM);
865290075Sobrien
865390075Sobrien      /* There are two registers left in saved_regs_mask - LR and PC.  We
865490075Sobrien	 only need to restore the LR register (the return address), but to
865590075Sobrien	 save time we can load it directly into the PC, unless we need a
865690075Sobrien	 special function exit sequence, or we are not really returning.  */
865790075Sobrien      if (really_return && ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL)
865890075Sobrien	/* Delete the LR from the register mask, so that the LR on
865990075Sobrien	   the stack is loaded into the PC in the register mask.  */
866090075Sobrien	saved_regs_mask &= ~ (1 << LR_REGNUM);
866190075Sobrien      else
866290075Sobrien	saved_regs_mask &= ~ (1 << PC_REGNUM);
866390075Sobrien
8664132718Skan      /* We must use SP as the base register, because SP is one of the
8665132718Skan         registers being restored.  If an interrupt or page fault
8666132718Skan         happens in the ldm instruction, the SP might or might not
8667132718Skan         have been restored.  That would be bad, as then SP will no
8668132718Skan         longer indicate the safe area of stack, and we can get stack
8669132718Skan         corruption.  Using SP as the base register means that it will
8670132718Skan         be reset correctly to the original value, should an interrupt
8671132718Skan         occur.  If the stack pointer already points at the right
8672132718Skan         place, then omit the subtraction.  */
8673132718Skan      if (((frame_size + current_function_outgoing_args_size + floats_offset)
8674132718Skan	   != 4 * (1 + (int) bit_count (saved_regs_mask)))
8675132718Skan	  || current_function_calls_alloca)
8676132718Skan	asm_fprintf (f, "\tsub\t%r, %r, #%d\n", SP_REGNUM, FP_REGNUM,
8677132718Skan		     4 * bit_count (saved_regs_mask));
8678132718Skan      print_multi_reg (f, "ldmfd\t%r", SP_REGNUM, saved_regs_mask);
8679132718Skan
868090075Sobrien      if (IS_INTERRUPT (func_type))
868190075Sobrien	/* Interrupt handlers will have pushed the
868290075Sobrien	   IP onto the stack, so restore it now.  */
8683117395Skan	print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM, 1 << IP_REGNUM);
868490075Sobrien    }
868590075Sobrien  else
868690075Sobrien    {
868790075Sobrien      /* Restore stack pointer if necessary.  */
868890075Sobrien      if (frame_size + current_function_outgoing_args_size != 0)
868990075Sobrien	{
869090075Sobrien	  operands[0] = operands[1] = stack_pointer_rtx;
869190075Sobrien	  operands[2] = GEN_INT (frame_size
869290075Sobrien				 + current_function_outgoing_args_size);
869390075Sobrien	  output_add_immediate (operands);
869490075Sobrien	}
869590075Sobrien
8696132718Skan      if (arm_fpu_arch == FPUTYPE_FPA_EMU2)
869790075Sobrien	{
869890075Sobrien	  for (reg = FIRST_ARM_FP_REGNUM; reg <= LAST_ARM_FP_REGNUM; reg++)
869990075Sobrien	    if (regs_ever_live[reg] && !call_used_regs[reg])
870090075Sobrien	      asm_fprintf (f, "\tldfe\t%r, [%r], #12\n",
870190075Sobrien			   reg, SP_REGNUM);
870290075Sobrien	}
870390075Sobrien      else
870490075Sobrien	{
870590075Sobrien	  int start_reg = FIRST_ARM_FP_REGNUM;
870690075Sobrien
870790075Sobrien	  for (reg = FIRST_ARM_FP_REGNUM; reg <= LAST_ARM_FP_REGNUM; reg++)
870890075Sobrien	    {
870990075Sobrien	      if (regs_ever_live[reg] && !call_used_regs[reg])
871090075Sobrien		{
871190075Sobrien		  if (reg - start_reg == 3)
871290075Sobrien		    {
871390075Sobrien		      asm_fprintf (f, "\tlfmfd\t%r, 4, [%r]!\n",
871490075Sobrien				   start_reg, SP_REGNUM);
871590075Sobrien		      start_reg = reg + 1;
871690075Sobrien		    }
871790075Sobrien		}
871890075Sobrien	      else
871990075Sobrien		{
872090075Sobrien		  if (reg != start_reg)
872190075Sobrien		    asm_fprintf (f, "\tlfmfd\t%r, %d, [%r]!\n",
872290075Sobrien				 start_reg, reg - start_reg,
872390075Sobrien				 SP_REGNUM);
872490075Sobrien
872590075Sobrien		  start_reg = reg + 1;
872690075Sobrien		}
872790075Sobrien	    }
872890075Sobrien
872990075Sobrien	  /* Just in case the last register checked also needs unstacking.  */
873090075Sobrien	  if (reg != start_reg)
873190075Sobrien	    asm_fprintf (f, "\tlfmfd\t%r, %d, [%r]!\n",
873290075Sobrien			 start_reg, reg - start_reg, SP_REGNUM);
873390075Sobrien	}
873490075Sobrien
8735132718Skan      if (TARGET_IWMMXT)
8736132718Skan	for (reg = FIRST_IWMMXT_REGNUM; reg <= LAST_IWMMXT_REGNUM; reg++)
8737132718Skan	  if (regs_ever_live[reg] && !call_used_regs[reg])
8738132718Skan	    asm_fprintf (f, "\twldrd\t%r, [%r, #+8]!\n", reg, SP_REGNUM);
8739132718Skan
874090075Sobrien      /* If we can, restore the LR into the PC.  */
874190075Sobrien      if (ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL
874290075Sobrien	  && really_return
874390075Sobrien	  && current_function_pretend_args_size == 0
874490075Sobrien	  && saved_regs_mask & (1 << LR_REGNUM))
874590075Sobrien	{
874690075Sobrien	  saved_regs_mask &= ~ (1 << LR_REGNUM);
874790075Sobrien	  saved_regs_mask |=   (1 << PC_REGNUM);
874890075Sobrien	}
874990075Sobrien
875090075Sobrien      /* Load the registers off the stack.  If we only have one register
875190075Sobrien	 to load use the LDR instruction - it is faster.  */
875290075Sobrien      if (saved_regs_mask == (1 << LR_REGNUM))
875390075Sobrien	{
875496263Sobrien	  /* The exception handler ignores the LR, so we do
875590075Sobrien	     not really need to load it off the stack.  */
875690075Sobrien	  if (eh_ofs)
875790075Sobrien	    asm_fprintf (f, "\tadd\t%r, %r, #4\n", SP_REGNUM, SP_REGNUM);
875890075Sobrien	  else
875990075Sobrien	    asm_fprintf (f, "\tldr\t%r, [%r], #4\n", LR_REGNUM, SP_REGNUM);
876090075Sobrien	}
876190075Sobrien      else if (saved_regs_mask)
8762117395Skan	{
8763117395Skan	  if (saved_regs_mask & (1 << SP_REGNUM))
8764117395Skan	    /* Note - write back to the stack register is not enabled
8765117395Skan	       (ie "ldmfd sp!...").  We know that the stack pointer is
8766117395Skan	       in the list of registers and if we add writeback the
8767117395Skan	       instruction becomes UNPREDICTABLE.  */
8768117395Skan	    print_multi_reg (f, "ldmfd\t%r", SP_REGNUM, saved_regs_mask);
8769117395Skan	  else
8770117395Skan	    print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM, saved_regs_mask);
8771117395Skan	}
877290075Sobrien
877390075Sobrien      if (current_function_pretend_args_size)
877490075Sobrien	{
877590075Sobrien	  /* Unwind the pre-pushed regs.  */
877690075Sobrien	  operands[0] = operands[1] = stack_pointer_rtx;
877790075Sobrien	  operands[2] = GEN_INT (current_function_pretend_args_size);
877890075Sobrien	  output_add_immediate (operands);
877990075Sobrien	}
878090075Sobrien    }
878190075Sobrien
878296263Sobrien  if (! really_return
878396263Sobrien    || (ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL
878496263Sobrien	&& current_function_pretend_args_size == 0
878596263Sobrien	&& saved_regs_mask & (1 << PC_REGNUM)))
878690075Sobrien    return "";
878790075Sobrien
878890075Sobrien  /* Generate the return instruction.  */
878990075Sobrien  switch ((int) ARM_FUNC_TYPE (func_type))
879090075Sobrien    {
879190075Sobrien    case ARM_FT_EXCEPTION_HANDLER:
879290075Sobrien      /* Even in 26-bit mode we do a mov (rather than a movs)
879390075Sobrien	 because we don't have the PSR bits set in the address.  */
879490075Sobrien      asm_fprintf (f, "\tmov\t%r, %r\n", PC_REGNUM, EXCEPTION_LR_REGNUM);
879590075Sobrien      break;
879690075Sobrien
879790075Sobrien    case ARM_FT_ISR:
879890075Sobrien    case ARM_FT_FIQ:
879990075Sobrien      asm_fprintf (f, "\tsubs\t%r, %r, #4\n", PC_REGNUM, LR_REGNUM);
880090075Sobrien      break;
880190075Sobrien
880290075Sobrien    case ARM_FT_EXCEPTION:
880390075Sobrien      asm_fprintf (f, "\tmovs\t%r, %r\n", PC_REGNUM, LR_REGNUM);
880490075Sobrien      break;
880590075Sobrien
880690075Sobrien    case ARM_FT_INTERWORKED:
880790075Sobrien      asm_fprintf (f, "\tbx\t%r\n", LR_REGNUM);
880890075Sobrien      break;
880990075Sobrien
881090075Sobrien    default:
881190075Sobrien      if (frame_pointer_needed)
8812117395Skan	/* If we used the frame pointer then the return address
881390075Sobrien	   will have been loaded off the stack directly into the
881490075Sobrien	   PC, so there is no need to issue a MOV instruction
881590075Sobrien	   here.  */
881690075Sobrien	;
881790075Sobrien      else if (current_function_pretend_args_size == 0
881890075Sobrien	       && (saved_regs_mask & (1 << LR_REGNUM)))
881990075Sobrien	/* Similarly we may have been able to load LR into the PC
882090075Sobrien	   even if we did not create a stack frame.  */
882190075Sobrien	;
882290075Sobrien      else if (TARGET_APCS_32)
882390075Sobrien	asm_fprintf (f, "\tmov\t%r, %r\n", PC_REGNUM, LR_REGNUM);
882490075Sobrien      else
882590075Sobrien	asm_fprintf (f, "\tmovs\t%r, %r\n", PC_REGNUM, LR_REGNUM);
882690075Sobrien      break;
882790075Sobrien    }
882890075Sobrien
882990075Sobrien  return "";
883090075Sobrien}
883190075Sobrien
883290075Sobrienstatic void
8833132718Skanarm_output_function_epilogue (FILE *file ATTRIBUTE_UNUSED,
8834132718Skan			      HOST_WIDE_INT frame_size)
883590075Sobrien{
883690075Sobrien  if (TARGET_THUMB)
883790075Sobrien    {
883890075Sobrien      /* ??? Probably not safe to set this here, since it assumes that a
883990075Sobrien	 function will be emitted as assembly immediately after we generate
884090075Sobrien	 RTL for it.  This does not happen for inline functions.  */
884190075Sobrien      return_used_this_function = 0;
884290075Sobrien    }
884390075Sobrien  else
884490075Sobrien    {
8845117395Skan      /* We need to take into account any stack-frame rounding.  */
8846117395Skan      frame_size = arm_get_frame_size ();
8847117395Skan
8848132718Skan      if (use_return_insn (FALSE, NULL)
884990075Sobrien	  && return_used_this_function
885090075Sobrien	  && (frame_size + current_function_outgoing_args_size) != 0
885190075Sobrien	  && !frame_pointer_needed)
885290075Sobrien	abort ();
885390075Sobrien
885490075Sobrien      /* Reset the ARM-specific per-function variables.  */
885590075Sobrien      after_arm_reorg = 0;
885690075Sobrien    }
885790075Sobrien}
885890075Sobrien
885990075Sobrien/* Generate and emit an insn that we will recognize as a push_multi.
886090075Sobrien   Unfortunately, since this insn does not reflect very well the actual
886190075Sobrien   semantics of the operation, we need to annotate the insn for the benefit
886290075Sobrien   of DWARF2 frame unwind information.  */
886390075Sobrienstatic rtx
8864132718Skanemit_multi_reg_push (int mask)
886590075Sobrien{
886690075Sobrien  int num_regs = 0;
886790075Sobrien  int num_dwarf_regs;
886890075Sobrien  int i, j;
886990075Sobrien  rtx par;
887090075Sobrien  rtx dwarf;
887190075Sobrien  int dwarf_par_index;
887290075Sobrien  rtx tmp, reg;
887390075Sobrien
887490075Sobrien  for (i = 0; i <= LAST_ARM_REGNUM; i++)
887590075Sobrien    if (mask & (1 << i))
887690075Sobrien      num_regs++;
887790075Sobrien
887890075Sobrien  if (num_regs == 0 || num_regs > 16)
887990075Sobrien    abort ();
888090075Sobrien
888190075Sobrien  /* We don't record the PC in the dwarf frame information.  */
888290075Sobrien  num_dwarf_regs = num_regs;
888390075Sobrien  if (mask & (1 << PC_REGNUM))
888490075Sobrien    num_dwarf_regs--;
888590075Sobrien
888690075Sobrien  /* For the body of the insn we are going to generate an UNSPEC in
8887117395Skan     parallel with several USEs.  This allows the insn to be recognized
888890075Sobrien     by the push_multi pattern in the arm.md file.  The insn looks
888990075Sobrien     something like this:
889090075Sobrien
889190075Sobrien       (parallel [
889290075Sobrien           (set (mem:BLK (pre_dec:BLK (reg:SI sp)))
889390075Sobrien	        (unspec:BLK [(reg:SI r4)] UNSPEC_PUSH_MULT))
889490075Sobrien           (use (reg:SI 11 fp))
889590075Sobrien           (use (reg:SI 12 ip))
889690075Sobrien           (use (reg:SI 14 lr))
889790075Sobrien           (use (reg:SI 15 pc))
889890075Sobrien        ])
889990075Sobrien
890090075Sobrien     For the frame note however, we try to be more explicit and actually
890190075Sobrien     show each register being stored into the stack frame, plus a (single)
890290075Sobrien     decrement of the stack pointer.  We do it this way in order to be
890390075Sobrien     friendly to the stack unwinding code, which only wants to see a single
890490075Sobrien     stack decrement per instruction.  The RTL we generate for the note looks
890590075Sobrien     something like this:
890690075Sobrien
890790075Sobrien      (sequence [
890890075Sobrien           (set (reg:SI sp) (plus:SI (reg:SI sp) (const_int -20)))
890990075Sobrien           (set (mem:SI (reg:SI sp)) (reg:SI r4))
891090075Sobrien           (set (mem:SI (plus:SI (reg:SI sp) (const_int 4))) (reg:SI fp))
891190075Sobrien           (set (mem:SI (plus:SI (reg:SI sp) (const_int 8))) (reg:SI ip))
891290075Sobrien           (set (mem:SI (plus:SI (reg:SI sp) (const_int 12))) (reg:SI lr))
891390075Sobrien        ])
891490075Sobrien
891590075Sobrien      This sequence is used both by the code to support stack unwinding for
891690075Sobrien      exceptions handlers and the code to generate dwarf2 frame debugging.  */
891790075Sobrien
891890075Sobrien  par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (num_regs));
891990075Sobrien  dwarf = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (num_dwarf_regs + 1));
892090075Sobrien  dwarf_par_index = 1;
892190075Sobrien
892290075Sobrien  for (i = 0; i <= LAST_ARM_REGNUM; i++)
892390075Sobrien    {
892490075Sobrien      if (mask & (1 << i))
892590075Sobrien	{
892690075Sobrien	  reg = gen_rtx_REG (SImode, i);
892790075Sobrien
892890075Sobrien	  XVECEXP (par, 0, 0)
892990075Sobrien	    = gen_rtx_SET (VOIDmode,
893090075Sobrien			   gen_rtx_MEM (BLKmode,
893190075Sobrien					gen_rtx_PRE_DEC (BLKmode,
893290075Sobrien							 stack_pointer_rtx)),
893390075Sobrien			   gen_rtx_UNSPEC (BLKmode,
893490075Sobrien					   gen_rtvec (1, reg),
893590075Sobrien					   UNSPEC_PUSH_MULT));
893690075Sobrien
893790075Sobrien	  if (i != PC_REGNUM)
893890075Sobrien	    {
893990075Sobrien	      tmp = gen_rtx_SET (VOIDmode,
894090075Sobrien				 gen_rtx_MEM (SImode, stack_pointer_rtx),
894190075Sobrien				 reg);
894290075Sobrien	      RTX_FRAME_RELATED_P (tmp) = 1;
894390075Sobrien	      XVECEXP (dwarf, 0, dwarf_par_index) = tmp;
894490075Sobrien	      dwarf_par_index++;
894590075Sobrien	    }
894690075Sobrien
894790075Sobrien	  break;
894890075Sobrien	}
894990075Sobrien    }
895090075Sobrien
895190075Sobrien  for (j = 1, i++; j < num_regs; i++)
895290075Sobrien    {
895390075Sobrien      if (mask & (1 << i))
895490075Sobrien	{
895590075Sobrien	  reg = gen_rtx_REG (SImode, i);
895690075Sobrien
895790075Sobrien	  XVECEXP (par, 0, j) = gen_rtx_USE (VOIDmode, reg);
895890075Sobrien
895990075Sobrien	  if (i != PC_REGNUM)
896090075Sobrien	    {
896190075Sobrien	      tmp = gen_rtx_SET (VOIDmode,
896290075Sobrien				 gen_rtx_MEM (SImode,
896390075Sobrien					      plus_constant (stack_pointer_rtx,
896490075Sobrien							     4 * j)),
896590075Sobrien				 reg);
896690075Sobrien	      RTX_FRAME_RELATED_P (tmp) = 1;
896790075Sobrien	      XVECEXP (dwarf, 0, dwarf_par_index++) = tmp;
896890075Sobrien	    }
896990075Sobrien
897090075Sobrien	  j++;
897190075Sobrien	}
897290075Sobrien    }
897390075Sobrien
897490075Sobrien  par = emit_insn (par);
897590075Sobrien
897690075Sobrien  tmp = gen_rtx_SET (SImode,
897790075Sobrien		     stack_pointer_rtx,
897890075Sobrien		     gen_rtx_PLUS (SImode,
897990075Sobrien				   stack_pointer_rtx,
898090075Sobrien				   GEN_INT (-4 * num_regs)));
898190075Sobrien  RTX_FRAME_RELATED_P (tmp) = 1;
898290075Sobrien  XVECEXP (dwarf, 0, 0) = tmp;
898390075Sobrien
898490075Sobrien  REG_NOTES (par) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
898590075Sobrien				       REG_NOTES (par));
898690075Sobrien  return par;
898790075Sobrien}
898890075Sobrien
898990075Sobrienstatic rtx
8990132718Skanemit_sfm (int base_reg, int count)
899190075Sobrien{
899290075Sobrien  rtx par;
899390075Sobrien  rtx dwarf;
899490075Sobrien  rtx tmp, reg;
899590075Sobrien  int i;
899690075Sobrien
899790075Sobrien  par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count));
899890075Sobrien  dwarf = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count));
899990075Sobrien
900090075Sobrien  reg = gen_rtx_REG (XFmode, base_reg++);
900190075Sobrien
900290075Sobrien  XVECEXP (par, 0, 0)
900390075Sobrien    = gen_rtx_SET (VOIDmode,
900490075Sobrien		   gen_rtx_MEM (BLKmode,
900590075Sobrien				gen_rtx_PRE_DEC (BLKmode, stack_pointer_rtx)),
900690075Sobrien		   gen_rtx_UNSPEC (BLKmode,
900790075Sobrien				   gen_rtvec (1, reg),
900890075Sobrien				   UNSPEC_PUSH_MULT));
900990075Sobrien  tmp
901090075Sobrien    = gen_rtx_SET (VOIDmode,
901190075Sobrien		   gen_rtx_MEM (XFmode,
901290075Sobrien				gen_rtx_PRE_DEC (BLKmode, stack_pointer_rtx)),
901390075Sobrien		   reg);
901490075Sobrien  RTX_FRAME_RELATED_P (tmp) = 1;
901590075Sobrien  XVECEXP (dwarf, 0, count - 1) = tmp;
901690075Sobrien
901790075Sobrien  for (i = 1; i < count; i++)
901890075Sobrien    {
901990075Sobrien      reg = gen_rtx_REG (XFmode, base_reg++);
902090075Sobrien      XVECEXP (par, 0, i) = gen_rtx_USE (VOIDmode, reg);
902190075Sobrien
902290075Sobrien      tmp = gen_rtx_SET (VOIDmode,
902390075Sobrien			 gen_rtx_MEM (XFmode,
902490075Sobrien				      gen_rtx_PRE_DEC (BLKmode,
902590075Sobrien						       stack_pointer_rtx)),
902690075Sobrien			 reg);
902790075Sobrien      RTX_FRAME_RELATED_P (tmp) = 1;
902890075Sobrien      XVECEXP (dwarf, 0, count - i - 1) = tmp;
902990075Sobrien    }
903090075Sobrien
903190075Sobrien  par = emit_insn (par);
903290075Sobrien  REG_NOTES (par) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
903390075Sobrien				       REG_NOTES (par));
903490075Sobrien  return par;
903590075Sobrien}
903690075Sobrien
903790075Sobrien/* Compute the distance from register FROM to register TO.
903890075Sobrien   These can be the arg pointer (26), the soft frame pointer (25),
903990075Sobrien   the stack pointer (13) or the hard frame pointer (11).
904090075Sobrien   Typical stack layout looks like this:
904190075Sobrien
904290075Sobrien       old stack pointer -> |    |
904390075Sobrien                             ----
904490075Sobrien                            |    | \
904590075Sobrien                            |    |   saved arguments for
904690075Sobrien                            |    |   vararg functions
904790075Sobrien			    |    | /
904890075Sobrien                              --
904990075Sobrien   hard FP & arg pointer -> |    | \
905090075Sobrien                            |    |   stack
905190075Sobrien                            |    |   frame
905290075Sobrien                            |    | /
905390075Sobrien                              --
905490075Sobrien                            |    | \
905590075Sobrien                            |    |   call saved
905690075Sobrien                            |    |   registers
905790075Sobrien      soft frame pointer -> |    | /
905890075Sobrien                              --
905990075Sobrien                            |    | \
906090075Sobrien                            |    |   local
906190075Sobrien                            |    |   variables
906290075Sobrien                            |    | /
906390075Sobrien                              --
906490075Sobrien                            |    | \
906590075Sobrien                            |    |   outgoing
906690075Sobrien                            |    |   arguments
906790075Sobrien   current stack pointer -> |    | /
906890075Sobrien                              --
906990075Sobrien
9070117395Skan  For a given function some or all of these stack components
907190075Sobrien  may not be needed, giving rise to the possibility of
907290075Sobrien  eliminating some of the registers.
907390075Sobrien
9074117395Skan  The values returned by this function must reflect the behavior
907590075Sobrien  of arm_expand_prologue() and arm_compute_save_reg_mask().
907690075Sobrien
907790075Sobrien  The sign of the number returned reflects the direction of stack
907890075Sobrien  growth, so the values are positive for all eliminations except
907990075Sobrien  from the soft frame pointer to the hard frame pointer.  */
908090075Sobrienunsigned int
9081132718Skanarm_compute_initial_elimination_offset (unsigned int from, unsigned int to)
908290075Sobrien{
9083117395Skan  unsigned int local_vars    = arm_get_frame_size ();
908490075Sobrien  unsigned int outgoing_args = current_function_outgoing_args_size;
908590075Sobrien  unsigned int stack_frame;
908690075Sobrien  unsigned int call_saved_registers;
908790075Sobrien  unsigned long func_type;
908890075Sobrien
908990075Sobrien  func_type = arm_current_func_type ();
909090075Sobrien
909190075Sobrien  /* Volatile functions never return, so there is
909290075Sobrien     no need to save call saved registers.  */
909390075Sobrien  call_saved_registers = 0;
909490075Sobrien  if (! IS_VOLATILE (func_type))
909590075Sobrien    {
909690075Sobrien      unsigned int reg_mask;
909790075Sobrien      unsigned int reg;
909890075Sobrien
909990075Sobrien      /* Make sure that we compute which registers will be saved
910090075Sobrien	 on the stack using the same algorithm that is used by
9101132718Skan	 the prologue creation code.  */
9102132718Skan      reg_mask = arm_compute_save_reg_mask ();
910390075Sobrien
910490075Sobrien      /* Now count the number of bits set in save_reg_mask.
9105132718Skan	 If we have already counted the registers in the stack
9106132718Skan	 frame, do not count them again.  Non call-saved registers
9107132718Skan	 might be saved in the call-save area of the stack, if
9108132718Skan	 doing so will preserve the stack's alignment.  Hence we
9109132718Skan	 must count them here.  For each set bit we need 4 bytes
9110132718Skan	 of stack space.  */
9111132718Skan      if (frame_pointer_needed)
9112132718Skan	reg_mask &= 0x07ff;
9113132718Skan      call_saved_registers += 4 * bit_count (reg_mask);
911490075Sobrien
911590075Sobrien      /* If the hard floating point registers are going to be
911690075Sobrien	 used then they must be saved on the stack as well.
911790075Sobrien         Each register occupies 12 bytes of stack space.  */
9118132718Skan      for (reg = FIRST_ARM_FP_REGNUM; reg <= LAST_ARM_FP_REGNUM; reg++)
911990075Sobrien	if (regs_ever_live[reg] && ! call_used_regs[reg])
912090075Sobrien	  call_saved_registers += 12;
9121132718Skan
9122132718Skan      if (TARGET_REALLY_IWMMXT)
9123132718Skan	/* Check for the call-saved iWMMXt registers.  */
9124132718Skan	for (reg = FIRST_IWMMXT_REGNUM; reg <= LAST_IWMMXT_REGNUM; reg++)
9125132718Skan	  if (regs_ever_live[reg] && ! call_used_regs [reg])
9126132718Skan	    call_saved_registers += 8;
912790075Sobrien    }
912890075Sobrien
912990075Sobrien  /* The stack frame contains 4 registers - the old frame pointer,
913090075Sobrien     the old stack pointer, the return address and PC of the start
913190075Sobrien     of the function.  */
913290075Sobrien  stack_frame = frame_pointer_needed ? 16 : 0;
913390075Sobrien
913490075Sobrien  /* OK, now we have enough information to compute the distances.
913590075Sobrien     There must be an entry in these switch tables for each pair
913690075Sobrien     of registers in ELIMINABLE_REGS, even if some of the entries
913790075Sobrien     seem to be redundant or useless.  */
913890075Sobrien  switch (from)
913990075Sobrien    {
914090075Sobrien    case ARG_POINTER_REGNUM:
914190075Sobrien      switch (to)
914290075Sobrien	{
914390075Sobrien	case THUMB_HARD_FRAME_POINTER_REGNUM:
914490075Sobrien	  return 0;
914590075Sobrien
914690075Sobrien	case FRAME_POINTER_REGNUM:
914790075Sobrien	  /* This is the reverse of the soft frame pointer
914890075Sobrien	     to hard frame pointer elimination below.  */
914990075Sobrien	  if (call_saved_registers == 0 && stack_frame == 0)
915090075Sobrien	    return 0;
915190075Sobrien	  return (call_saved_registers + stack_frame - 4);
915290075Sobrien
915390075Sobrien	case ARM_HARD_FRAME_POINTER_REGNUM:
915490075Sobrien	  /* If there is no stack frame then the hard
915590075Sobrien	     frame pointer and the arg pointer coincide.  */
915690075Sobrien	  if (stack_frame == 0 && call_saved_registers != 0)
915790075Sobrien	    return 0;
915890075Sobrien	  /* FIXME:  Not sure about this.  Maybe we should always return 0 ?  */
915990075Sobrien	  return (frame_pointer_needed
916090075Sobrien		  && current_function_needs_context
916196263Sobrien		  && ! cfun->machine->uses_anonymous_args) ? 4 : 0;
916290075Sobrien
916390075Sobrien	case STACK_POINTER_REGNUM:
916490075Sobrien	  /* If nothing has been pushed on the stack at all
916590075Sobrien	     then this will return -4.  This *is* correct!  */
916690075Sobrien	  return call_saved_registers + stack_frame + local_vars + outgoing_args - 4;
916790075Sobrien
916890075Sobrien	default:
916990075Sobrien	  abort ();
917090075Sobrien	}
917190075Sobrien      break;
917290075Sobrien
917390075Sobrien    case FRAME_POINTER_REGNUM:
917490075Sobrien      switch (to)
917590075Sobrien	{
917690075Sobrien	case THUMB_HARD_FRAME_POINTER_REGNUM:
917790075Sobrien	  return 0;
917890075Sobrien
917990075Sobrien	case ARM_HARD_FRAME_POINTER_REGNUM:
918090075Sobrien	  /* The hard frame pointer points to the top entry in the
918190075Sobrien	     stack frame.  The soft frame pointer to the bottom entry
918290075Sobrien	     in the stack frame.  If there is no stack frame at all,
918390075Sobrien	     then they are identical.  */
918490075Sobrien	  if (call_saved_registers == 0 && stack_frame == 0)
918590075Sobrien	    return 0;
918690075Sobrien	  return - (call_saved_registers + stack_frame - 4);
918790075Sobrien
918890075Sobrien	case STACK_POINTER_REGNUM:
918990075Sobrien	  return local_vars + outgoing_args;
919090075Sobrien
919190075Sobrien	default:
919290075Sobrien	  abort ();
919390075Sobrien	}
919490075Sobrien      break;
919590075Sobrien
919690075Sobrien    default:
919790075Sobrien      /* You cannot eliminate from the stack pointer.
919890075Sobrien	 In theory you could eliminate from the hard frame
919990075Sobrien	 pointer to the stack pointer, but this will never
920090075Sobrien	 happen, since if a stack frame is not needed the
920190075Sobrien	 hard frame pointer will never be used.  */
920290075Sobrien      abort ();
920390075Sobrien    }
920490075Sobrien}
920590075Sobrien
9206117395Skan/* Calculate the size of the stack frame, taking into account any
9207117395Skan   padding that is required to ensure stack-alignment.  */
9208117395SkanHOST_WIDE_INT
9209132718Skanarm_get_frame_size (void)
9210117395Skan{
9211117395Skan  int regno;
9212117395Skan
9213132718Skan  int base_size = ROUND_UP_WORD (get_frame_size ());
9214117395Skan  int entry_size = 0;
9215117395Skan  unsigned long func_type = arm_current_func_type ();
9216117395Skan  int leaf;
9217117395Skan
9218117395Skan  if (! TARGET_ARM)
9219117395Skan    abort();
9220117395Skan
9221117395Skan  if (! TARGET_ATPCS)
9222117395Skan    return base_size;
9223117395Skan
9224117395Skan  /* We need to know if we are a leaf function.  Unfortunately, it
9225117395Skan     is possible to be called after start_sequence has been called,
9226117395Skan     which causes get_insns to return the insns for the sequence,
9227117395Skan     not the function, which will cause leaf_function_p to return
9228117395Skan     the incorrect result.
9229117395Skan
9230117395Skan     To work around this, we cache the computed frame size.  This
9231117395Skan     works because we will only be calling RTL expanders that need
9232117395Skan     to know about leaf functions once reload has completed, and the
9233117395Skan     frame size cannot be changed after that time, so we can safely
9234117395Skan     use the cached value.  */
9235117395Skan
9236117395Skan  if (reload_completed)
9237117395Skan    return cfun->machine->frame_size;
9238117395Skan
9239117395Skan  leaf = leaf_function_p ();
9240117395Skan
9241117395Skan  /* A leaf function does not need any stack alignment if it has nothing
9242117395Skan     on the stack.  */
9243117395Skan  if (leaf && base_size == 0)
9244117395Skan    {
9245117395Skan      cfun->machine->frame_size = 0;
9246117395Skan      return 0;
9247117395Skan    }
9248117395Skan
9249117395Skan  /* We know that SP will be word aligned on entry, and we must
9250117395Skan     preserve that condition at any subroutine call.  But those are
9251117395Skan     the only constraints.  */
9252117395Skan
9253117395Skan  /* Space for variadic functions.  */
9254117395Skan  if (current_function_pretend_args_size)
9255117395Skan    entry_size += current_function_pretend_args_size;
9256117395Skan
9257117395Skan  /* Space for saved registers.  */
9258117395Skan  entry_size += bit_count (arm_compute_save_reg_mask ()) * 4;
9259117395Skan
9260117395Skan  /* Space for saved FPA registers.  */
9261117395Skan  if (! IS_VOLATILE (func_type))
9262117395Skan    {
9263117395Skan      for (regno = FIRST_ARM_FP_REGNUM; regno <= LAST_ARM_FP_REGNUM; regno++)
9264117395Skan      if (regs_ever_live[regno] && ! call_used_regs[regno])
9265117395Skan	entry_size += 12;
9266117395Skan    }
9267117395Skan
9268132718Skan  if (TARGET_REALLY_IWMMXT)
9269132718Skan    {
9270132718Skan      /* Check for the call-saved iWMMXt registers.  */
9271132718Skan      for (regno = FIRST_IWMMXT_REGNUM; regno <= LAST_IWMMXT_REGNUM; regno++)
9272132718Skan	if (regs_ever_live [regno] && ! call_used_regs [regno])
9273132718Skan	  entry_size += 8;
9274132718Skan    }
9275132718Skan
9276117395Skan  if ((entry_size + base_size + current_function_outgoing_args_size) & 7)
9277117395Skan    base_size += 4;
9278117395Skan  if ((entry_size + base_size + current_function_outgoing_args_size) & 7)
9279117395Skan    abort ();
9280117395Skan
9281117395Skan  cfun->machine->frame_size = base_size;
9282117395Skan
9283117395Skan  return base_size;
9284117395Skan}
9285117395Skan
928690075Sobrien/* Generate the prologue instructions for entry into an ARM function.  */
928790075Sobrienvoid
9288132718Skanarm_expand_prologue (void)
928990075Sobrien{
929090075Sobrien  int reg;
929190075Sobrien  rtx amount;
929290075Sobrien  rtx insn;
929390075Sobrien  rtx ip_rtx;
929490075Sobrien  unsigned long live_regs_mask;
929590075Sobrien  unsigned long func_type;
929690075Sobrien  int fp_offset = 0;
929790075Sobrien  int saved_pretend_args = 0;
929890075Sobrien  unsigned int args_to_push;
929990075Sobrien
930090075Sobrien  func_type = arm_current_func_type ();
930190075Sobrien
930290075Sobrien  /* Naked functions don't have prologues.  */
930390075Sobrien  if (IS_NAKED (func_type))
930490075Sobrien    return;
930590075Sobrien
930690075Sobrien  /* Make a copy of c_f_p_a_s as we may need to modify it locally.  */
930790075Sobrien  args_to_push = current_function_pretend_args_size;
930890075Sobrien
930990075Sobrien  /* Compute which register we will have to save onto the stack.  */
931090075Sobrien  live_regs_mask = arm_compute_save_reg_mask ();
931190075Sobrien
931290075Sobrien  ip_rtx = gen_rtx_REG (SImode, IP_REGNUM);
931390075Sobrien
931490075Sobrien  if (frame_pointer_needed)
931590075Sobrien    {
931690075Sobrien      if (IS_INTERRUPT (func_type))
931790075Sobrien	{
931890075Sobrien	  /* Interrupt functions must not corrupt any registers.
931990075Sobrien	     Creating a frame pointer however, corrupts the IP
932090075Sobrien	     register, so we must push it first.  */
932190075Sobrien	  insn = emit_multi_reg_push (1 << IP_REGNUM);
932290075Sobrien
932390075Sobrien	  /* Do not set RTX_FRAME_RELATED_P on this insn.
932490075Sobrien	     The dwarf stack unwinding code only wants to see one
932590075Sobrien	     stack decrement per function, and this is not it.  If
932690075Sobrien	     this instruction is labeled as being part of the frame
932790075Sobrien	     creation sequence then dwarf2out_frame_debug_expr will
932890075Sobrien	     abort when it encounters the assignment of IP to FP
932990075Sobrien	     later on, since the use of SP here establishes SP as
933090075Sobrien	     the CFA register and not IP.
933190075Sobrien
933290075Sobrien	     Anyway this instruction is not really part of the stack
933390075Sobrien	     frame creation although it is part of the prologue.  */
933490075Sobrien	}
933590075Sobrien      else if (IS_NESTED (func_type))
933690075Sobrien	{
933790075Sobrien	  /* The Static chain register is the same as the IP register
933890075Sobrien	     used as a scratch register during stack frame creation.
933990075Sobrien	     To get around this need to find somewhere to store IP
934090075Sobrien	     whilst the frame is being created.  We try the following
934190075Sobrien	     places in order:
934290075Sobrien
934390075Sobrien	       1. The last argument register.
934490075Sobrien	       2. A slot on the stack above the frame.  (This only
934590075Sobrien	          works if the function is not a varargs function).
934690075Sobrien	       3. Register r3, after pushing the argument registers
934790075Sobrien	          onto the stack.
934890075Sobrien
934990075Sobrien	     Note - we only need to tell the dwarf2 backend about the SP
935090075Sobrien	     adjustment in the second variant; the static chain register
935190075Sobrien	     doesn't need to be unwound, as it doesn't contain a value
935290075Sobrien	     inherited from the caller.  */
935390075Sobrien
935490075Sobrien	  if (regs_ever_live[3] == 0)
935590075Sobrien	    {
935690075Sobrien	      insn = gen_rtx_REG (SImode, 3);
935790075Sobrien	      insn = gen_rtx_SET (SImode, insn, ip_rtx);
935890075Sobrien	      insn = emit_insn (insn);
935990075Sobrien	    }
936090075Sobrien	  else if (args_to_push == 0)
936190075Sobrien	    {
936290075Sobrien	      rtx dwarf;
936390075Sobrien	      insn = gen_rtx_PRE_DEC (SImode, stack_pointer_rtx);
936490075Sobrien	      insn = gen_rtx_MEM (SImode, insn);
936590075Sobrien	      insn = gen_rtx_SET (VOIDmode, insn, ip_rtx);
936690075Sobrien	      insn = emit_insn (insn);
936790075Sobrien
936890075Sobrien	      fp_offset = 4;
936990075Sobrien
937090075Sobrien	      /* Just tell the dwarf backend that we adjusted SP.  */
937190075Sobrien	      dwarf = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
937290075Sobrien				   gen_rtx_PLUS (SImode, stack_pointer_rtx,
937390075Sobrien						 GEN_INT (-fp_offset)));
937490075Sobrien	      RTX_FRAME_RELATED_P (insn) = 1;
937590075Sobrien	      REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
937690075Sobrien						    dwarf, REG_NOTES (insn));
937790075Sobrien	    }
937890075Sobrien	  else
937990075Sobrien	    {
938090075Sobrien	      /* Store the args on the stack.  */
938196263Sobrien	      if (cfun->machine->uses_anonymous_args)
938290075Sobrien		insn = emit_multi_reg_push
938390075Sobrien		  ((0xf0 >> (args_to_push / 4)) & 0xf);
938490075Sobrien	      else
938590075Sobrien		insn = emit_insn
938690075Sobrien		  (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
938790075Sobrien			       GEN_INT (- args_to_push)));
938890075Sobrien
938990075Sobrien	      RTX_FRAME_RELATED_P (insn) = 1;
939090075Sobrien
939190075Sobrien	      saved_pretend_args = 1;
939290075Sobrien	      fp_offset = args_to_push;
939390075Sobrien	      args_to_push = 0;
939490075Sobrien
939590075Sobrien	      /* Now reuse r3 to preserve IP.  */
939690075Sobrien	      insn = gen_rtx_REG (SImode, 3);
939790075Sobrien	      insn = gen_rtx_SET (SImode, insn, ip_rtx);
939890075Sobrien	      (void) emit_insn (insn);
939990075Sobrien	    }
940090075Sobrien	}
940190075Sobrien
940290075Sobrien      if (fp_offset)
940390075Sobrien	{
940490075Sobrien	  insn = gen_rtx_PLUS (SImode, stack_pointer_rtx, GEN_INT (fp_offset));
940590075Sobrien	  insn = gen_rtx_SET  (SImode, ip_rtx, insn);
940690075Sobrien	}
940790075Sobrien      else
940890075Sobrien	insn = gen_movsi (ip_rtx, stack_pointer_rtx);
940990075Sobrien
941090075Sobrien      insn = emit_insn (insn);
941190075Sobrien      RTX_FRAME_RELATED_P (insn) = 1;
941290075Sobrien    }
941390075Sobrien
941490075Sobrien  if (args_to_push)
941590075Sobrien    {
941690075Sobrien      /* Push the argument registers, or reserve space for them.  */
941796263Sobrien      if (cfun->machine->uses_anonymous_args)
941890075Sobrien	insn = emit_multi_reg_push
941990075Sobrien	  ((0xf0 >> (args_to_push / 4)) & 0xf);
942090075Sobrien      else
942190075Sobrien	insn = emit_insn
942290075Sobrien	  (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
942390075Sobrien		       GEN_INT (- args_to_push)));
942490075Sobrien      RTX_FRAME_RELATED_P (insn) = 1;
942590075Sobrien    }
942690075Sobrien
9427117395Skan  /* If this is an interrupt service routine, and the link register
9428117395Skan     is going to be pushed, and we are not creating a stack frame,
9429117395Skan     (which would involve an extra push of IP and a pop in the epilogue)
9430117395Skan     subtracting four from LR now will mean that the function return
9431117395Skan     can be done with a single instruction.  */
943296263Sobrien  if ((func_type == ARM_FT_ISR || func_type == ARM_FT_FIQ)
9433117395Skan      && (live_regs_mask & (1 << LR_REGNUM)) != 0
9434117395Skan      && ! frame_pointer_needed)
9435117395Skan    emit_insn (gen_rtx_SET (SImode,
9436117395Skan			    gen_rtx_REG (SImode, LR_REGNUM),
9437117395Skan			    gen_rtx_PLUS (SImode,
9438117395Skan					  gen_rtx_REG (SImode, LR_REGNUM),
9439117395Skan					  GEN_INT (-4))));
944096263Sobrien
944190075Sobrien  if (live_regs_mask)
944290075Sobrien    {
944390075Sobrien      insn = emit_multi_reg_push (live_regs_mask);
944490075Sobrien      RTX_FRAME_RELATED_P (insn) = 1;
944590075Sobrien    }
944690075Sobrien
9447132718Skan  if (TARGET_IWMMXT)
9448132718Skan    for (reg = FIRST_IWMMXT_REGNUM; reg <= LAST_IWMMXT_REGNUM; reg++)
9449132718Skan      if (regs_ever_live[reg] && ! call_used_regs [reg])
9450132718Skan	{
9451132718Skan	  insn = gen_rtx_PRE_DEC (V2SImode, stack_pointer_rtx);
9452132718Skan	  insn = gen_rtx_MEM (V2SImode, insn);
9453132718Skan	  insn = emit_insn (gen_rtx_SET (VOIDmode, insn,
9454132718Skan					 gen_rtx_REG (V2SImode, reg)));
9455132718Skan	  RTX_FRAME_RELATED_P (insn) = 1;
9456132718Skan	}
9457132718Skan
945890075Sobrien  if (! IS_VOLATILE (func_type))
945990075Sobrien    {
9460132718Skan      /* Save any floating point call-saved registers used by this
9461132718Skan	 function.  */
9462132718Skan      if (arm_fpu_arch == FPUTYPE_FPA_EMU2)
946390075Sobrien	{
9464132718Skan	  for (reg = LAST_ARM_FP_REGNUM; reg >= FIRST_ARM_FP_REGNUM; reg--)
946590075Sobrien	    if (regs_ever_live[reg] && !call_used_regs[reg])
946690075Sobrien	      {
946790075Sobrien		insn = gen_rtx_PRE_DEC (XFmode, stack_pointer_rtx);
946890075Sobrien		insn = gen_rtx_MEM (XFmode, insn);
946990075Sobrien		insn = emit_insn (gen_rtx_SET (VOIDmode, insn,
947090075Sobrien					       gen_rtx_REG (XFmode, reg)));
947190075Sobrien		RTX_FRAME_RELATED_P (insn) = 1;
947290075Sobrien	      }
947390075Sobrien	}
947490075Sobrien      else
947590075Sobrien	{
947690075Sobrien	  int start_reg = LAST_ARM_FP_REGNUM;
947790075Sobrien
9478132718Skan	  for (reg = LAST_ARM_FP_REGNUM; reg >= FIRST_ARM_FP_REGNUM; reg--)
947990075Sobrien	    {
948090075Sobrien	      if (regs_ever_live[reg] && !call_used_regs[reg])
948190075Sobrien		{
948290075Sobrien		  if (start_reg - reg == 3)
948390075Sobrien		    {
948490075Sobrien		      insn = emit_sfm (reg, 4);
948590075Sobrien		      RTX_FRAME_RELATED_P (insn) = 1;
948690075Sobrien		      start_reg = reg - 1;
948790075Sobrien		    }
948890075Sobrien		}
948990075Sobrien	      else
949090075Sobrien		{
949190075Sobrien		  if (start_reg != reg)
949290075Sobrien		    {
949390075Sobrien		      insn = emit_sfm (reg + 1, start_reg - reg);
949490075Sobrien		      RTX_FRAME_RELATED_P (insn) = 1;
949590075Sobrien		    }
949690075Sobrien		  start_reg = reg - 1;
949790075Sobrien		}
949890075Sobrien	    }
949990075Sobrien
950090075Sobrien	  if (start_reg != reg)
950190075Sobrien	    {
950290075Sobrien	      insn = emit_sfm (reg + 1, start_reg - reg);
950390075Sobrien	      RTX_FRAME_RELATED_P (insn) = 1;
950490075Sobrien	    }
950590075Sobrien	}
950690075Sobrien    }
950790075Sobrien
950890075Sobrien  if (frame_pointer_needed)
950990075Sobrien    {
951090075Sobrien      /* Create the new frame pointer.  */
951190075Sobrien      insn = GEN_INT (-(4 + args_to_push + fp_offset));
951290075Sobrien      insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx, ip_rtx, insn));
951390075Sobrien      RTX_FRAME_RELATED_P (insn) = 1;
951490075Sobrien
951590075Sobrien      if (IS_NESTED (func_type))
951690075Sobrien	{
951790075Sobrien	  /* Recover the static chain register.  */
951890075Sobrien	  if (regs_ever_live [3] == 0
951990075Sobrien	      || saved_pretend_args)
952090075Sobrien	    insn = gen_rtx_REG (SImode, 3);
952190075Sobrien	  else /* if (current_function_pretend_args_size == 0) */
952290075Sobrien	    {
9523132718Skan	      insn = gen_rtx_PLUS (SImode, hard_frame_pointer_rtx,
9524132718Skan				   GEN_INT (4));
952590075Sobrien	      insn = gen_rtx_MEM (SImode, insn);
952690075Sobrien	    }
952790075Sobrien
952890075Sobrien	  emit_insn (gen_rtx_SET (SImode, ip_rtx, insn));
952990075Sobrien	  /* Add a USE to stop propagate_one_insn() from barfing.  */
953090075Sobrien	  emit_insn (gen_prologue_use (ip_rtx));
953190075Sobrien	}
953290075Sobrien    }
953390075Sobrien
9534117395Skan  amount = GEN_INT (-(arm_get_frame_size ()
953590075Sobrien		      + current_function_outgoing_args_size));
953690075Sobrien
953790075Sobrien  if (amount != const0_rtx)
953890075Sobrien    {
953990075Sobrien      /* This add can produce multiple insns for a large constant, so we
954090075Sobrien	 need to get tricky.  */
954190075Sobrien      rtx last = get_last_insn ();
954290075Sobrien      insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
954390075Sobrien				    amount));
954490075Sobrien      do
954590075Sobrien	{
954690075Sobrien	  last = last ? NEXT_INSN (last) : get_insns ();
954790075Sobrien	  RTX_FRAME_RELATED_P (last) = 1;
954890075Sobrien	}
954990075Sobrien      while (last != insn);
955090075Sobrien
955190075Sobrien      /* If the frame pointer is needed, emit a special barrier that
955290075Sobrien	 will prevent the scheduler from moving stores to the frame
955390075Sobrien	 before the stack adjustment.  */
955490075Sobrien      if (frame_pointer_needed)
9555117395Skan	insn = emit_insn (gen_stack_tie (stack_pointer_rtx,
9556117395Skan					 hard_frame_pointer_rtx));
955790075Sobrien    }
955890075Sobrien
955990075Sobrien  /* If we are profiling, make sure no instructions are scheduled before
956090075Sobrien     the call to mcount.  Similarly if the user has requested no
956190075Sobrien     scheduling in the prolog.  */
956290075Sobrien  if (current_function_profile || TARGET_NO_SCHED_PRO)
956390075Sobrien    emit_insn (gen_blockage ());
956490075Sobrien
956590075Sobrien  /* If the link register is being kept alive, with the return address in it,
956690075Sobrien     then make sure that it does not get reused by the ce2 pass.  */
956790075Sobrien  if ((live_regs_mask & (1 << LR_REGNUM)) == 0)
956890075Sobrien    {
956990075Sobrien      emit_insn (gen_prologue_use (gen_rtx_REG (SImode, LR_REGNUM)));
957090075Sobrien      cfun->machine->lr_save_eliminated = 1;
957190075Sobrien    }
957290075Sobrien}
957390075Sobrien
957490075Sobrien/* If CODE is 'd', then the X is a condition operand and the instruction
957590075Sobrien   should only be executed if the condition is true.
957690075Sobrien   if CODE is 'D', then the X is a condition operand and the instruction
957790075Sobrien   should only be executed if the condition is false: however, if the mode
957890075Sobrien   of the comparison is CCFPEmode, then always execute the instruction -- we
957990075Sobrien   do this because in these circumstances !GE does not necessarily imply LT;
958090075Sobrien   in these cases the instruction pattern will take care to make sure that
958190075Sobrien   an instruction containing %d will follow, thereby undoing the effects of
958290075Sobrien   doing this instruction unconditionally.
958390075Sobrien   If CODE is 'N' then X is a floating point operand that must be negated
958490075Sobrien   before output.
958590075Sobrien   If CODE is 'B' then output a bitwise inverted value of X (a const int).
958690075Sobrien   If X is a REG and CODE is `M', output a ldm/stm style multi-reg.  */
958790075Sobrienvoid
9588132718Skanarm_print_operand (FILE *stream, rtx x, int code)
958990075Sobrien{
959090075Sobrien  switch (code)
959190075Sobrien    {
959290075Sobrien    case '@':
959390075Sobrien      fputs (ASM_COMMENT_START, stream);
959490075Sobrien      return;
959590075Sobrien
959690075Sobrien    case '_':
959790075Sobrien      fputs (user_label_prefix, stream);
959890075Sobrien      return;
959990075Sobrien
960090075Sobrien    case '|':
960190075Sobrien      fputs (REGISTER_PREFIX, stream);
960290075Sobrien      return;
960390075Sobrien
960490075Sobrien    case '?':
960590075Sobrien      if (arm_ccfsm_state == 3 || arm_ccfsm_state == 4)
960690075Sobrien	{
960790075Sobrien	  if (TARGET_THUMB || current_insn_predicate != NULL)
960890075Sobrien	    abort ();
960990075Sobrien
961090075Sobrien	  fputs (arm_condition_codes[arm_current_cc], stream);
961190075Sobrien	}
961290075Sobrien      else if (current_insn_predicate)
961390075Sobrien	{
961490075Sobrien	  enum arm_cond_code code;
961590075Sobrien
961690075Sobrien	  if (TARGET_THUMB)
961790075Sobrien	    abort ();
961890075Sobrien
961990075Sobrien	  code = get_arm_condition_code (current_insn_predicate);
962090075Sobrien	  fputs (arm_condition_codes[code], stream);
962190075Sobrien	}
962290075Sobrien      return;
962390075Sobrien
962490075Sobrien    case 'N':
962590075Sobrien      {
962690075Sobrien	REAL_VALUE_TYPE r;
962790075Sobrien	REAL_VALUE_FROM_CONST_DOUBLE (r, x);
962890075Sobrien	r = REAL_VALUE_NEGATE (r);
962990075Sobrien	fprintf (stream, "%s", fp_const_from_val (&r));
963090075Sobrien      }
963190075Sobrien      return;
963290075Sobrien
963390075Sobrien    case 'B':
963490075Sobrien      if (GET_CODE (x) == CONST_INT)
963590075Sobrien	{
963690075Sobrien	  HOST_WIDE_INT val;
963790075Sobrien	  val = ARM_SIGN_EXTEND (~INTVAL (x));
963890075Sobrien	  fprintf (stream, HOST_WIDE_INT_PRINT_DEC, val);
963990075Sobrien	}
964090075Sobrien      else
964190075Sobrien	{
964290075Sobrien	  putc ('~', stream);
964390075Sobrien	  output_addr_const (stream, x);
964490075Sobrien	}
964590075Sobrien      return;
964690075Sobrien
964790075Sobrien    case 'i':
964890075Sobrien      fprintf (stream, "%s", arithmetic_instr (x, 1));
964990075Sobrien      return;
965090075Sobrien
9651132718Skan    /* Truncate Cirrus shift counts.  */
9652132718Skan    case 's':
9653132718Skan      if (GET_CODE (x) == CONST_INT)
9654132718Skan	{
9655132718Skan	  fprintf (stream, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) & 0x3f);
9656132718Skan	  return;
9657132718Skan	}
9658132718Skan      arm_print_operand (stream, x, 0);
9659132718Skan      return;
9660132718Skan
966190075Sobrien    case 'I':
966290075Sobrien      fprintf (stream, "%s", arithmetic_instr (x, 0));
966390075Sobrien      return;
966490075Sobrien
966590075Sobrien    case 'S':
966690075Sobrien      {
966790075Sobrien	HOST_WIDE_INT val;
966890075Sobrien	const char * shift = shift_op (x, &val);
966990075Sobrien
967090075Sobrien	if (shift)
967190075Sobrien	  {
967290075Sobrien	    fprintf (stream, ", %s ", shift_op (x, &val));
967390075Sobrien	    if (val == -1)
967490075Sobrien	      arm_print_operand (stream, XEXP (x, 1), 0);
967590075Sobrien	    else
9676132718Skan	      fprintf (stream, "#" HOST_WIDE_INT_PRINT_DEC, val);
967790075Sobrien	  }
967890075Sobrien      }
967990075Sobrien      return;
968090075Sobrien
968190075Sobrien      /* An explanation of the 'Q', 'R' and 'H' register operands:
968290075Sobrien
968390075Sobrien	 In a pair of registers containing a DI or DF value the 'Q'
968490075Sobrien	 operand returns the register number of the register containing
9685132718Skan	 the least significant part of the value.  The 'R' operand returns
968690075Sobrien	 the register number of the register containing the most
968790075Sobrien	 significant part of the value.
968890075Sobrien
968990075Sobrien	 The 'H' operand returns the higher of the two register numbers.
969090075Sobrien	 On a run where WORDS_BIG_ENDIAN is true the 'H' operand is the
9691132718Skan	 same as the 'Q' operand, since the most significant part of the
969290075Sobrien	 value is held in the lower number register.  The reverse is true
969390075Sobrien	 on systems where WORDS_BIG_ENDIAN is false.
969490075Sobrien
969590075Sobrien	 The purpose of these operands is to distinguish between cases
969690075Sobrien	 where the endian-ness of the values is important (for example
969790075Sobrien	 when they are added together), and cases where the endian-ness
969890075Sobrien	 is irrelevant, but the order of register operations is important.
969990075Sobrien	 For example when loading a value from memory into a register
970090075Sobrien	 pair, the endian-ness does not matter.  Provided that the value
970190075Sobrien	 from the lower memory address is put into the lower numbered
970290075Sobrien	 register, and the value from the higher address is put into the
970390075Sobrien	 higher numbered register, the load will work regardless of whether
970490075Sobrien	 the value being loaded is big-wordian or little-wordian.  The
970590075Sobrien	 order of the two register loads can matter however, if the address
970690075Sobrien	 of the memory location is actually held in one of the registers
970790075Sobrien	 being overwritten by the load.  */
970890075Sobrien    case 'Q':
970990075Sobrien      if (REGNO (x) > LAST_ARM_REGNUM)
971090075Sobrien	abort ();
971190075Sobrien      asm_fprintf (stream, "%r", REGNO (x) + (WORDS_BIG_ENDIAN ? 1 : 0));
971290075Sobrien      return;
971390075Sobrien
971490075Sobrien    case 'R':
971590075Sobrien      if (REGNO (x) > LAST_ARM_REGNUM)
971690075Sobrien	abort ();
971790075Sobrien      asm_fprintf (stream, "%r", REGNO (x) + (WORDS_BIG_ENDIAN ? 0 : 1));
971890075Sobrien      return;
971990075Sobrien
972090075Sobrien    case 'H':
972190075Sobrien      if (REGNO (x) > LAST_ARM_REGNUM)
972290075Sobrien	abort ();
972390075Sobrien      asm_fprintf (stream, "%r", REGNO (x) + 1);
972490075Sobrien      return;
972590075Sobrien
972690075Sobrien    case 'm':
972790075Sobrien      asm_fprintf (stream, "%r",
972890075Sobrien		   GET_CODE (XEXP (x, 0)) == REG
972990075Sobrien		   ? REGNO (XEXP (x, 0)) : REGNO (XEXP (XEXP (x, 0), 0)));
973090075Sobrien      return;
973190075Sobrien
973290075Sobrien    case 'M':
973390075Sobrien      asm_fprintf (stream, "{%r-%r}",
973490075Sobrien		   REGNO (x),
9735117395Skan		   REGNO (x) + ARM_NUM_REGS (GET_MODE (x)) - 1);
973690075Sobrien      return;
973790075Sobrien
973890075Sobrien    case 'd':
9739117395Skan      /* CONST_TRUE_RTX means always -- that's the default.  */
9740117395Skan      if (x == const_true_rtx)
974190075Sobrien	return;
974290075Sobrien
9743132718Skan      fputs (arm_condition_codes[get_arm_condition_code (x)],
9744132718Skan	     stream);
974590075Sobrien      return;
974690075Sobrien
974790075Sobrien    case 'D':
9748117395Skan      /* CONST_TRUE_RTX means not always -- ie never.  We shouldn't ever
9749117395Skan	 want to do that.  */
9750117395Skan      if (x == const_true_rtx)
9751117395Skan	abort ();
975290075Sobrien
9753132718Skan      fputs (arm_condition_codes[ARM_INVERSE_CONDITION_CODE
9754132718Skan				 (get_arm_condition_code (x))],
9755132718Skan	     stream);
9756132718Skan      return;
9757132718Skan
9758132718Skan    /* Cirrus registers can be accessed in a variety of ways:
9759132718Skan         single floating point (f)
9760132718Skan	 double floating point (d)
9761132718Skan	 32bit integer         (fx)
9762132718Skan	 64bit integer         (dx).  */
9763132718Skan    case 'W':			/* Cirrus register in F mode.  */
9764132718Skan    case 'X':			/* Cirrus register in D mode.  */
9765132718Skan    case 'Y':			/* Cirrus register in FX mode.  */
9766132718Skan    case 'Z':			/* Cirrus register in DX mode.  */
9767132718Skan      if (GET_CODE (x) != REG || REGNO_REG_CLASS (REGNO (x)) != CIRRUS_REGS)
9768132718Skan	abort ();
9769132718Skan
9770132718Skan      fprintf (stream, "mv%s%s",
9771132718Skan	       code == 'W' ? "f"
9772132718Skan	       : code == 'X' ? "d"
9773132718Skan	       : code == 'Y' ? "fx" : "dx", reg_names[REGNO (x)] + 2);
9774132718Skan
9775132718Skan      return;
9776132718Skan
9777132718Skan    /* Print cirrus register in the mode specified by the register's mode.  */
9778132718Skan    case 'V':
9779132718Skan      {
9780132718Skan	int mode = GET_MODE (x);
9781132718Skan
9782132718Skan	if (GET_CODE (x) != REG || REGNO_REG_CLASS (REGNO (x)) != CIRRUS_REGS)
9783132718Skan	  abort ();
9784132718Skan
9785132718Skan	fprintf (stream, "mv%s%s",
9786132718Skan		 mode == DFmode ? "d"
9787132718Skan		 : mode == SImode ? "fx"
9788132718Skan		 : mode == DImode ? "dx"
9789132718Skan		 : "f", reg_names[REGNO (x)] + 2);
9790132718Skan
9791132718Skan	return;
9792132718Skan      }
9793132718Skan
9794132718Skan    case 'U':
9795132718Skan      if (GET_CODE (x) != REG
9796132718Skan	  || REGNO (x) < FIRST_IWMMXT_GR_REGNUM
9797132718Skan	  || REGNO (x) > LAST_IWMMXT_GR_REGNUM)
9798132718Skan	/* Bad value for wCG register number.  */
9799132718Skan	abort ();
980090075Sobrien      else
9801132718Skan	fprintf (stream, "%d", REGNO (x) - FIRST_IWMMXT_GR_REGNUM);
980290075Sobrien      return;
980390075Sobrien
9804132718Skan      /* Print an iWMMXt control register name.  */
9805132718Skan    case 'w':
9806132718Skan      if (GET_CODE (x) != CONST_INT
9807132718Skan	  || INTVAL (x) < 0
9808132718Skan	  || INTVAL (x) >= 16)
9809132718Skan	/* Bad value for wC register number.  */
9810132718Skan	abort ();
9811132718Skan      else
9812132718Skan	{
9813132718Skan	  static const char * wc_reg_names [16] =
9814132718Skan	    {
9815132718Skan	      "wCID",  "wCon",  "wCSSF", "wCASF",
9816132718Skan	      "wC4",   "wC5",   "wC6",   "wC7",
9817132718Skan	      "wCGR0", "wCGR1", "wCGR2", "wCGR3",
9818132718Skan	      "wC12",  "wC13",  "wC14",  "wC15"
9819132718Skan	    };
9820132718Skan
9821132718Skan	  fprintf (stream, wc_reg_names [INTVAL (x)]);
9822132718Skan	}
9823132718Skan      return;
9824132718Skan
982590075Sobrien    default:
982690075Sobrien      if (x == 0)
982790075Sobrien	abort ();
982890075Sobrien
982990075Sobrien      if (GET_CODE (x) == REG)
983090075Sobrien	asm_fprintf (stream, "%r", REGNO (x));
983190075Sobrien      else if (GET_CODE (x) == MEM)
983290075Sobrien	{
983390075Sobrien	  output_memory_reference_mode = GET_MODE (x);
983490075Sobrien	  output_address (XEXP (x, 0));
983590075Sobrien	}
983690075Sobrien      else if (GET_CODE (x) == CONST_DOUBLE)
983790075Sobrien	fprintf (stream, "#%s", fp_immediate_constant (x));
983890075Sobrien      else if (GET_CODE (x) == NEG)
983990075Sobrien	abort (); /* This should never happen now.  */
984090075Sobrien      else
984190075Sobrien	{
984290075Sobrien	  fputc ('#', stream);
984390075Sobrien	  output_addr_const (stream, x);
984490075Sobrien	}
984590075Sobrien    }
984690075Sobrien}
984790075Sobrien
984890075Sobrien#ifndef AOF_ASSEMBLER
984990075Sobrien/* Target hook for assembling integer objects.  The ARM version needs to
985090075Sobrien   handle word-sized values specially.  */
985190075Sobrienstatic bool
9852132718Skanarm_assemble_integer (rtx x, unsigned int size, int aligned_p)
985390075Sobrien{
985490075Sobrien  if (size == UNITS_PER_WORD && aligned_p)
985590075Sobrien    {
985690075Sobrien      fputs ("\t.word\t", asm_out_file);
985790075Sobrien      output_addr_const (asm_out_file, x);
985890075Sobrien
985990075Sobrien      /* Mark symbols as position independent.  We only do this in the
9860132718Skan	 .text segment, not in the .data segment.  */
986190075Sobrien      if (NEED_GOT_RELOC && flag_pic && making_const_table &&
986290075Sobrien	  (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF))
986390075Sobrien	{
9864117395Skan	  if (GET_CODE (x) == SYMBOL_REF
986596263Sobrien	      && (CONSTANT_POOL_ADDRESS_P (x)
9866132718Skan		  || SYMBOL_REF_LOCAL_P (x)))
986790075Sobrien	    fputs ("(GOTOFF)", asm_out_file);
986890075Sobrien	  else if (GET_CODE (x) == LABEL_REF)
986990075Sobrien	    fputs ("(GOTOFF)", asm_out_file);
987090075Sobrien	  else
987190075Sobrien	    fputs ("(GOT)", asm_out_file);
987290075Sobrien	}
987390075Sobrien      fputc ('\n', asm_out_file);
987490075Sobrien      return true;
987590075Sobrien    }
987690075Sobrien
9877132718Skan  if (VECTOR_MODE_SUPPORTED_P (GET_MODE (x)))
9878132718Skan    {
9879132718Skan      int i, units;
9880132718Skan
9881132718Skan      if (GET_CODE (x) != CONST_VECTOR)
9882132718Skan	abort ();
9883132718Skan
9884132718Skan      units = CONST_VECTOR_NUNITS (x);
9885132718Skan
9886132718Skan      switch (GET_MODE (x))
9887132718Skan	{
9888132718Skan	case V2SImode: size = 4; break;
9889132718Skan	case V4HImode: size = 2; break;
9890132718Skan	case V8QImode: size = 1; break;
9891132718Skan	default:
9892132718Skan	  abort ();
9893132718Skan	}
9894132718Skan
9895132718Skan      for (i = 0; i < units; i++)
9896132718Skan	{
9897132718Skan	  rtx elt;
9898132718Skan
9899132718Skan	  elt = CONST_VECTOR_ELT (x, i);
9900132718Skan	  assemble_integer
9901132718Skan	    (elt, size, i == 0 ? BIGGEST_ALIGNMENT : size * BITS_PER_UNIT, 1);
9902132718Skan	}
9903132718Skan
9904132718Skan      return true;
9905132718Skan    }
9906132718Skan
990790075Sobrien  return default_assemble_integer (x, size, aligned_p);
990890075Sobrien}
990990075Sobrien#endif
991090075Sobrien
991190075Sobrien/* A finite state machine takes care of noticing whether or not instructions
991290075Sobrien   can be conditionally executed, and thus decrease execution time and code
991390075Sobrien   size by deleting branch instructions.  The fsm is controlled by
991490075Sobrien   final_prescan_insn, and controls the actions of ASM_OUTPUT_OPCODE.  */
991590075Sobrien
991690075Sobrien/* The state of the fsm controlling condition codes are:
991790075Sobrien   0: normal, do nothing special
991890075Sobrien   1: make ASM_OUTPUT_OPCODE not output this instruction
991990075Sobrien   2: make ASM_OUTPUT_OPCODE not output this instruction
992090075Sobrien   3: make instructions conditional
992190075Sobrien   4: make instructions conditional
992290075Sobrien
992390075Sobrien   State transitions (state->state by whom under condition):
992490075Sobrien   0 -> 1 final_prescan_insn if the `target' is a label
992590075Sobrien   0 -> 2 final_prescan_insn if the `target' is an unconditional branch
992690075Sobrien   1 -> 3 ASM_OUTPUT_OPCODE after not having output the conditional branch
992790075Sobrien   2 -> 4 ASM_OUTPUT_OPCODE after not having output the conditional branch
9928132718Skan   3 -> 0 (*targetm.asm_out.internal_label) if the `target' label is reached
992990075Sobrien          (the target label has CODE_LABEL_NUMBER equal to arm_target_label).
993090075Sobrien   4 -> 0 final_prescan_insn if the `target' unconditional branch is reached
993190075Sobrien          (the target insn is arm_target_insn).
993290075Sobrien
993390075Sobrien   If the jump clobbers the conditions then we use states 2 and 4.
993490075Sobrien
993590075Sobrien   A similar thing can be done with conditional return insns.
993690075Sobrien
993790075Sobrien   XXX In case the `target' is an unconditional branch, this conditionalising
993890075Sobrien   of the instructions always reduces code size, but not always execution
993990075Sobrien   time.  But then, I want to reduce the code size to somewhere near what
994090075Sobrien   /bin/cc produces.  */
994190075Sobrien
994290075Sobrien/* Returns the index of the ARM condition code string in
994390075Sobrien   `arm_condition_codes'.  COMPARISON should be an rtx like
994490075Sobrien   `(eq (...) (...))'.  */
994590075Sobrienstatic enum arm_cond_code
9946132718Skanget_arm_condition_code (rtx comparison)
994790075Sobrien{
994890075Sobrien  enum machine_mode mode = GET_MODE (XEXP (comparison, 0));
994990075Sobrien  int code;
995090075Sobrien  enum rtx_code comp_code = GET_CODE (comparison);
995190075Sobrien
995290075Sobrien  if (GET_MODE_CLASS (mode) != MODE_CC)
995390075Sobrien    mode = SELECT_CC_MODE (comp_code, XEXP (comparison, 0),
995490075Sobrien			   XEXP (comparison, 1));
995590075Sobrien
995690075Sobrien  switch (mode)
995790075Sobrien    {
995890075Sobrien    case CC_DNEmode: code = ARM_NE; goto dominance;
995990075Sobrien    case CC_DEQmode: code = ARM_EQ; goto dominance;
996090075Sobrien    case CC_DGEmode: code = ARM_GE; goto dominance;
996190075Sobrien    case CC_DGTmode: code = ARM_GT; goto dominance;
996290075Sobrien    case CC_DLEmode: code = ARM_LE; goto dominance;
996390075Sobrien    case CC_DLTmode: code = ARM_LT; goto dominance;
996490075Sobrien    case CC_DGEUmode: code = ARM_CS; goto dominance;
996590075Sobrien    case CC_DGTUmode: code = ARM_HI; goto dominance;
996690075Sobrien    case CC_DLEUmode: code = ARM_LS; goto dominance;
996790075Sobrien    case CC_DLTUmode: code = ARM_CC;
996890075Sobrien
996990075Sobrien    dominance:
997090075Sobrien      if (comp_code != EQ && comp_code != NE)
997190075Sobrien	abort ();
997290075Sobrien
997390075Sobrien      if (comp_code == EQ)
997490075Sobrien	return ARM_INVERSE_CONDITION_CODE (code);
997590075Sobrien      return code;
997690075Sobrien
997790075Sobrien    case CC_NOOVmode:
997890075Sobrien      switch (comp_code)
997990075Sobrien	{
998090075Sobrien	case NE: return ARM_NE;
998190075Sobrien	case EQ: return ARM_EQ;
998290075Sobrien	case GE: return ARM_PL;
998390075Sobrien	case LT: return ARM_MI;
998490075Sobrien	default: abort ();
998590075Sobrien	}
998690075Sobrien
998790075Sobrien    case CC_Zmode:
998890075Sobrien      switch (comp_code)
998990075Sobrien	{
999090075Sobrien	case NE: return ARM_NE;
999190075Sobrien	case EQ: return ARM_EQ;
999290075Sobrien	default: abort ();
999390075Sobrien	}
999490075Sobrien
9995132718Skan    case CC_Nmode:
9996132718Skan      switch (comp_code)
9997132718Skan	{
9998132718Skan	case NE: return ARM_MI;
9999132718Skan	case EQ: return ARM_PL;
10000132718Skan	default: abort ();
10001132718Skan	}
10002132718Skan
1000390075Sobrien    case CCFPEmode:
1000490075Sobrien    case CCFPmode:
1000590075Sobrien      /* These encodings assume that AC=1 in the FPA system control
1000690075Sobrien	 byte.  This allows us to handle all cases except UNEQ and
1000790075Sobrien	 LTGT.  */
1000890075Sobrien      switch (comp_code)
1000990075Sobrien	{
1001090075Sobrien	case GE: return ARM_GE;
1001190075Sobrien	case GT: return ARM_GT;
1001290075Sobrien	case LE: return ARM_LS;
1001390075Sobrien	case LT: return ARM_MI;
1001490075Sobrien	case NE: return ARM_NE;
1001590075Sobrien	case EQ: return ARM_EQ;
1001690075Sobrien	case ORDERED: return ARM_VC;
1001790075Sobrien	case UNORDERED: return ARM_VS;
1001890075Sobrien	case UNLT: return ARM_LT;
1001990075Sobrien	case UNLE: return ARM_LE;
1002090075Sobrien	case UNGT: return ARM_HI;
1002190075Sobrien	case UNGE: return ARM_PL;
1002290075Sobrien	  /* UNEQ and LTGT do not have a representation.  */
1002390075Sobrien	case UNEQ: /* Fall through.  */
1002490075Sobrien	case LTGT: /* Fall through.  */
1002590075Sobrien	default: abort ();
1002690075Sobrien	}
1002790075Sobrien
1002890075Sobrien    case CC_SWPmode:
1002990075Sobrien      switch (comp_code)
1003090075Sobrien	{
1003190075Sobrien	case NE: return ARM_NE;
1003290075Sobrien	case EQ: return ARM_EQ;
1003390075Sobrien	case GE: return ARM_LE;
1003490075Sobrien	case GT: return ARM_LT;
1003590075Sobrien	case LE: return ARM_GE;
1003690075Sobrien	case LT: return ARM_GT;
1003790075Sobrien	case GEU: return ARM_LS;
1003890075Sobrien	case GTU: return ARM_CC;
1003990075Sobrien	case LEU: return ARM_CS;
1004090075Sobrien	case LTU: return ARM_HI;
1004190075Sobrien	default: abort ();
1004290075Sobrien	}
1004390075Sobrien
1004490075Sobrien    case CC_Cmode:
1004590075Sobrien      switch (comp_code)
1004690075Sobrien      {
1004790075Sobrien      case LTU: return ARM_CS;
1004890075Sobrien      case GEU: return ARM_CC;
1004990075Sobrien      default: abort ();
1005090075Sobrien      }
1005190075Sobrien
1005290075Sobrien    case CCmode:
1005390075Sobrien      switch (comp_code)
1005490075Sobrien	{
1005590075Sobrien	case NE: return ARM_NE;
1005690075Sobrien	case EQ: return ARM_EQ;
1005790075Sobrien	case GE: return ARM_GE;
1005890075Sobrien	case GT: return ARM_GT;
1005990075Sobrien	case LE: return ARM_LE;
1006090075Sobrien	case LT: return ARM_LT;
1006190075Sobrien	case GEU: return ARM_CS;
1006290075Sobrien	case GTU: return ARM_HI;
1006390075Sobrien	case LEU: return ARM_LS;
1006490075Sobrien	case LTU: return ARM_CC;
1006590075Sobrien	default: abort ();
1006690075Sobrien	}
1006790075Sobrien
1006890075Sobrien    default: abort ();
1006990075Sobrien    }
1007090075Sobrien
1007190075Sobrien  abort ();
1007290075Sobrien}
1007390075Sobrien
1007490075Sobrienvoid
10075132718Skanarm_final_prescan_insn (rtx insn)
1007690075Sobrien{
1007790075Sobrien  /* BODY will hold the body of INSN.  */
1007890075Sobrien  rtx body = PATTERN (insn);
1007990075Sobrien
1008090075Sobrien  /* This will be 1 if trying to repeat the trick, and things need to be
1008190075Sobrien     reversed if it appears to fail.  */
1008290075Sobrien  int reverse = 0;
1008390075Sobrien
1008490075Sobrien  /* JUMP_CLOBBERS will be one implies that the conditions if a branch is
1008590075Sobrien     taken are clobbered, even if the rtl suggests otherwise.  It also
1008690075Sobrien     means that we have to grub around within the jump expression to find
1008790075Sobrien     out what the conditions are when the jump isn't taken.  */
1008890075Sobrien  int jump_clobbers = 0;
1008990075Sobrien
1009090075Sobrien  /* If we start with a return insn, we only succeed if we find another one.  */
1009190075Sobrien  int seeking_return = 0;
1009290075Sobrien
1009390075Sobrien  /* START_INSN will hold the insn from where we start looking.  This is the
1009490075Sobrien     first insn after the following code_label if REVERSE is true.  */
1009590075Sobrien  rtx start_insn = insn;
1009690075Sobrien
1009790075Sobrien  /* If in state 4, check if the target branch is reached, in order to
1009890075Sobrien     change back to state 0.  */
1009990075Sobrien  if (arm_ccfsm_state == 4)
1010090075Sobrien    {
1010190075Sobrien      if (insn == arm_target_insn)
1010290075Sobrien	{
1010390075Sobrien	  arm_target_insn = NULL;
1010490075Sobrien	  arm_ccfsm_state = 0;
1010590075Sobrien	}
1010690075Sobrien      return;
1010790075Sobrien    }
1010890075Sobrien
1010990075Sobrien  /* If in state 3, it is possible to repeat the trick, if this insn is an
1011090075Sobrien     unconditional branch to a label, and immediately following this branch
1011190075Sobrien     is the previous target label which is only used once, and the label this
1011290075Sobrien     branch jumps to is not too far off.  */
1011390075Sobrien  if (arm_ccfsm_state == 3)
1011490075Sobrien    {
1011590075Sobrien      if (simplejump_p (insn))
1011690075Sobrien	{
1011790075Sobrien	  start_insn = next_nonnote_insn (start_insn);
1011890075Sobrien	  if (GET_CODE (start_insn) == BARRIER)
1011990075Sobrien	    {
1012090075Sobrien	      /* XXX Isn't this always a barrier?  */
1012190075Sobrien	      start_insn = next_nonnote_insn (start_insn);
1012290075Sobrien	    }
1012390075Sobrien	  if (GET_CODE (start_insn) == CODE_LABEL
1012490075Sobrien	      && CODE_LABEL_NUMBER (start_insn) == arm_target_label
1012590075Sobrien	      && LABEL_NUSES (start_insn) == 1)
1012690075Sobrien	    reverse = TRUE;
1012790075Sobrien	  else
1012890075Sobrien	    return;
1012990075Sobrien	}
1013090075Sobrien      else if (GET_CODE (body) == RETURN)
1013190075Sobrien        {
1013290075Sobrien	  start_insn = next_nonnote_insn (start_insn);
1013390075Sobrien	  if (GET_CODE (start_insn) == BARRIER)
1013490075Sobrien	    start_insn = next_nonnote_insn (start_insn);
1013590075Sobrien	  if (GET_CODE (start_insn) == CODE_LABEL
1013690075Sobrien	      && CODE_LABEL_NUMBER (start_insn) == arm_target_label
1013790075Sobrien	      && LABEL_NUSES (start_insn) == 1)
1013890075Sobrien	    {
1013990075Sobrien	      reverse = TRUE;
1014090075Sobrien	      seeking_return = 1;
1014190075Sobrien	    }
1014290075Sobrien	  else
1014390075Sobrien	    return;
1014490075Sobrien        }
1014590075Sobrien      else
1014690075Sobrien	return;
1014790075Sobrien    }
1014890075Sobrien
1014990075Sobrien  if (arm_ccfsm_state != 0 && !reverse)
1015090075Sobrien    abort ();
1015190075Sobrien  if (GET_CODE (insn) != JUMP_INSN)
1015290075Sobrien    return;
1015390075Sobrien
1015490075Sobrien  /* This jump might be paralleled with a clobber of the condition codes
1015590075Sobrien     the jump should always come first */
1015690075Sobrien  if (GET_CODE (body) == PARALLEL && XVECLEN (body, 0) > 0)
1015790075Sobrien    body = XVECEXP (body, 0, 0);
1015890075Sobrien
1015990075Sobrien  if (reverse
1016090075Sobrien      || (GET_CODE (body) == SET && GET_CODE (SET_DEST (body)) == PC
1016190075Sobrien	  && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE))
1016290075Sobrien    {
1016390075Sobrien      int insns_skipped;
1016490075Sobrien      int fail = FALSE, succeed = FALSE;
1016590075Sobrien      /* Flag which part of the IF_THEN_ELSE is the LABEL_REF.  */
1016690075Sobrien      int then_not_else = TRUE;
1016790075Sobrien      rtx this_insn = start_insn, label = 0;
1016890075Sobrien
1016990075Sobrien      /* If the jump cannot be done with one instruction, we cannot
1017090075Sobrien	 conditionally execute the instruction in the inverse case.  */
1017190075Sobrien      if (get_attr_conds (insn) == CONDS_JUMP_CLOB)
1017290075Sobrien	{
1017390075Sobrien	  jump_clobbers = 1;
1017490075Sobrien	  return;
1017590075Sobrien	}
1017690075Sobrien
1017790075Sobrien      /* Register the insn jumped to.  */
1017890075Sobrien      if (reverse)
1017990075Sobrien        {
1018090075Sobrien	  if (!seeking_return)
1018190075Sobrien	    label = XEXP (SET_SRC (body), 0);
1018290075Sobrien        }
1018390075Sobrien      else if (GET_CODE (XEXP (SET_SRC (body), 1)) == LABEL_REF)
1018490075Sobrien	label = XEXP (XEXP (SET_SRC (body), 1), 0);
1018590075Sobrien      else if (GET_CODE (XEXP (SET_SRC (body), 2)) == LABEL_REF)
1018690075Sobrien	{
1018790075Sobrien	  label = XEXP (XEXP (SET_SRC (body), 2), 0);
1018890075Sobrien	  then_not_else = FALSE;
1018990075Sobrien	}
1019090075Sobrien      else if (GET_CODE (XEXP (SET_SRC (body), 1)) == RETURN)
1019190075Sobrien	seeking_return = 1;
1019290075Sobrien      else if (GET_CODE (XEXP (SET_SRC (body), 2)) == RETURN)
1019390075Sobrien        {
1019490075Sobrien	  seeking_return = 1;
1019590075Sobrien	  then_not_else = FALSE;
1019690075Sobrien        }
1019790075Sobrien      else
1019890075Sobrien	abort ();
1019990075Sobrien
1020090075Sobrien      /* See how many insns this branch skips, and what kind of insns.  If all
1020190075Sobrien	 insns are okay, and the label or unconditional branch to the same
1020290075Sobrien	 label is not too far away, succeed.  */
1020390075Sobrien      for (insns_skipped = 0;
1020490075Sobrien	   !fail && !succeed && insns_skipped++ < max_insns_skipped;)
1020590075Sobrien	{
1020690075Sobrien	  rtx scanbody;
1020790075Sobrien
1020890075Sobrien	  this_insn = next_nonnote_insn (this_insn);
1020990075Sobrien	  if (!this_insn)
1021090075Sobrien	    break;
1021190075Sobrien
1021290075Sobrien	  switch (GET_CODE (this_insn))
1021390075Sobrien	    {
1021490075Sobrien	    case CODE_LABEL:
1021590075Sobrien	      /* Succeed if it is the target label, otherwise fail since
1021690075Sobrien		 control falls in from somewhere else.  */
1021790075Sobrien	      if (this_insn == label)
1021890075Sobrien		{
1021990075Sobrien		  if (jump_clobbers)
1022090075Sobrien		    {
1022190075Sobrien		      arm_ccfsm_state = 2;
1022290075Sobrien		      this_insn = next_nonnote_insn (this_insn);
1022390075Sobrien		    }
1022490075Sobrien		  else
1022590075Sobrien		    arm_ccfsm_state = 1;
1022690075Sobrien		  succeed = TRUE;
1022790075Sobrien		}
1022890075Sobrien	      else
1022990075Sobrien		fail = TRUE;
1023090075Sobrien	      break;
1023190075Sobrien
1023290075Sobrien	    case BARRIER:
1023390075Sobrien	      /* Succeed if the following insn is the target label.
1023490075Sobrien		 Otherwise fail.
1023590075Sobrien		 If return insns are used then the last insn in a function
1023690075Sobrien		 will be a barrier.  */
1023790075Sobrien	      this_insn = next_nonnote_insn (this_insn);
1023890075Sobrien	      if (this_insn && this_insn == label)
1023990075Sobrien		{
1024090075Sobrien		  if (jump_clobbers)
1024190075Sobrien		    {
1024290075Sobrien		      arm_ccfsm_state = 2;
1024390075Sobrien		      this_insn = next_nonnote_insn (this_insn);
1024490075Sobrien		    }
1024590075Sobrien		  else
1024690075Sobrien		    arm_ccfsm_state = 1;
1024790075Sobrien		  succeed = TRUE;
1024890075Sobrien		}
1024990075Sobrien	      else
1025090075Sobrien		fail = TRUE;
1025190075Sobrien	      break;
1025290075Sobrien
1025390075Sobrien	    case CALL_INSN:
1025490075Sobrien	      /* If using 32-bit addresses the cc is not preserved over
1025590075Sobrien		 calls.  */
1025690075Sobrien	      if (TARGET_APCS_32)
1025790075Sobrien		{
1025890075Sobrien		  /* Succeed if the following insn is the target label,
1025990075Sobrien		     or if the following two insns are a barrier and
1026090075Sobrien		     the target label.  */
1026190075Sobrien		  this_insn = next_nonnote_insn (this_insn);
1026290075Sobrien		  if (this_insn && GET_CODE (this_insn) == BARRIER)
1026390075Sobrien		    this_insn = next_nonnote_insn (this_insn);
1026490075Sobrien
1026590075Sobrien		  if (this_insn && this_insn == label
1026690075Sobrien		      && insns_skipped < max_insns_skipped)
1026790075Sobrien		    {
1026890075Sobrien		      if (jump_clobbers)
1026990075Sobrien			{
1027090075Sobrien			  arm_ccfsm_state = 2;
1027190075Sobrien			  this_insn = next_nonnote_insn (this_insn);
1027290075Sobrien			}
1027390075Sobrien		      else
1027490075Sobrien			arm_ccfsm_state = 1;
1027590075Sobrien		      succeed = TRUE;
1027690075Sobrien		    }
1027790075Sobrien		  else
1027890075Sobrien		    fail = TRUE;
1027990075Sobrien		}
1028090075Sobrien	      break;
1028190075Sobrien
1028290075Sobrien	    case JUMP_INSN:
1028390075Sobrien      	      /* If this is an unconditional branch to the same label, succeed.
1028490075Sobrien		 If it is to another label, do nothing.  If it is conditional,
1028590075Sobrien		 fail.  */
10286132718Skan	      /* XXX Probably, the tests for SET and the PC are
10287132718Skan		 unnecessary.  */
1028890075Sobrien
1028990075Sobrien	      scanbody = PATTERN (this_insn);
1029090075Sobrien	      if (GET_CODE (scanbody) == SET
1029190075Sobrien		  && GET_CODE (SET_DEST (scanbody)) == PC)
1029290075Sobrien		{
1029390075Sobrien		  if (GET_CODE (SET_SRC (scanbody)) == LABEL_REF
1029490075Sobrien		      && XEXP (SET_SRC (scanbody), 0) == label && !reverse)
1029590075Sobrien		    {
1029690075Sobrien		      arm_ccfsm_state = 2;
1029790075Sobrien		      succeed = TRUE;
1029890075Sobrien		    }
1029990075Sobrien		  else if (GET_CODE (SET_SRC (scanbody)) == IF_THEN_ELSE)
1030090075Sobrien		    fail = TRUE;
1030190075Sobrien		}
1030290075Sobrien	      /* Fail if a conditional return is undesirable (eg on a
1030390075Sobrien		 StrongARM), but still allow this if optimizing for size.  */
1030490075Sobrien	      else if (GET_CODE (scanbody) == RETURN
10305132718Skan		       && !use_return_insn (TRUE, NULL)
1030690075Sobrien		       && !optimize_size)
1030790075Sobrien		fail = TRUE;
1030890075Sobrien	      else if (GET_CODE (scanbody) == RETURN
1030990075Sobrien		       && seeking_return)
1031090075Sobrien	        {
1031190075Sobrien		  arm_ccfsm_state = 2;
1031290075Sobrien		  succeed = TRUE;
1031390075Sobrien	        }
1031490075Sobrien	      else if (GET_CODE (scanbody) == PARALLEL)
1031590075Sobrien	        {
1031690075Sobrien		  switch (get_attr_conds (this_insn))
1031790075Sobrien		    {
1031890075Sobrien		    case CONDS_NOCOND:
1031990075Sobrien		      break;
1032090075Sobrien		    default:
1032190075Sobrien		      fail = TRUE;
1032290075Sobrien		      break;
1032390075Sobrien		    }
1032490075Sobrien		}
1032590075Sobrien	      else
1032690075Sobrien		fail = TRUE;	/* Unrecognized jump (eg epilogue).  */
1032790075Sobrien
1032890075Sobrien	      break;
1032990075Sobrien
1033090075Sobrien	    case INSN:
1033190075Sobrien	      /* Instructions using or affecting the condition codes make it
1033290075Sobrien		 fail.  */
1033390075Sobrien	      scanbody = PATTERN (this_insn);
1033490075Sobrien	      if (!(GET_CODE (scanbody) == SET
1033590075Sobrien		    || GET_CODE (scanbody) == PARALLEL)
1033690075Sobrien		  || get_attr_conds (this_insn) != CONDS_NOCOND)
1033790075Sobrien		fail = TRUE;
10338132718Skan
10339132718Skan	      /* A conditional cirrus instruction must be followed by
10340132718Skan		 a non Cirrus instruction.  However, since we
10341132718Skan		 conditionalize instructions in this function and by
10342132718Skan		 the time we get here we can't add instructions
10343132718Skan		 (nops), because shorten_branches() has already been
10344132718Skan		 called, we will disable conditionalizing Cirrus
10345132718Skan		 instructions to be safe.  */
10346132718Skan	      if (GET_CODE (scanbody) != USE
10347132718Skan		  && GET_CODE (scanbody) != CLOBBER
10348132718Skan		  && get_attr_cirrus (this_insn) != CIRRUS_NOT)
10349132718Skan		fail = TRUE;
1035090075Sobrien	      break;
1035190075Sobrien
1035290075Sobrien	    default:
1035390075Sobrien	      break;
1035490075Sobrien	    }
1035590075Sobrien	}
1035690075Sobrien      if (succeed)
1035790075Sobrien	{
1035890075Sobrien	  if ((!seeking_return) && (arm_ccfsm_state == 1 || reverse))
1035990075Sobrien	    arm_target_label = CODE_LABEL_NUMBER (label);
1036090075Sobrien	  else if (seeking_return || arm_ccfsm_state == 2)
1036190075Sobrien	    {
1036290075Sobrien	      while (this_insn && GET_CODE (PATTERN (this_insn)) == USE)
1036390075Sobrien	        {
1036490075Sobrien		  this_insn = next_nonnote_insn (this_insn);
1036590075Sobrien		  if (this_insn && (GET_CODE (this_insn) == BARRIER
1036690075Sobrien				    || GET_CODE (this_insn) == CODE_LABEL))
1036790075Sobrien		    abort ();
1036890075Sobrien	        }
1036990075Sobrien	      if (!this_insn)
1037090075Sobrien	        {
10371132718Skan		  /* Oh, dear! we ran off the end.. give up.  */
1037290075Sobrien		  recog (PATTERN (insn), insn, NULL);
1037390075Sobrien		  arm_ccfsm_state = 0;
1037490075Sobrien		  arm_target_insn = NULL;
1037590075Sobrien		  return;
1037690075Sobrien	        }
1037790075Sobrien	      arm_target_insn = this_insn;
1037890075Sobrien	    }
1037990075Sobrien	  else
1038090075Sobrien	    abort ();
1038190075Sobrien	  if (jump_clobbers)
1038290075Sobrien	    {
1038390075Sobrien	      if (reverse)
1038490075Sobrien		abort ();
1038590075Sobrien	      arm_current_cc =
1038690075Sobrien		  get_arm_condition_code (XEXP (XEXP (XEXP (SET_SRC (body),
1038790075Sobrien							    0), 0), 1));
1038890075Sobrien	      if (GET_CODE (XEXP (XEXP (SET_SRC (body), 0), 0)) == AND)
1038990075Sobrien		arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc);
1039090075Sobrien	      if (GET_CODE (XEXP (SET_SRC (body), 0)) == NE)
1039190075Sobrien		arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc);
1039290075Sobrien	    }
1039390075Sobrien	  else
1039490075Sobrien	    {
1039590075Sobrien	      /* If REVERSE is true, ARM_CURRENT_CC needs to be inverted from
1039690075Sobrien		 what it was.  */
1039790075Sobrien	      if (!reverse)
1039890075Sobrien		arm_current_cc = get_arm_condition_code (XEXP (SET_SRC (body),
1039990075Sobrien							       0));
1040090075Sobrien	    }
1040190075Sobrien
1040290075Sobrien	  if (reverse || then_not_else)
1040390075Sobrien	    arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc);
1040490075Sobrien	}
1040590075Sobrien
1040690075Sobrien      /* Restore recog_data (getting the attributes of other insns can
1040790075Sobrien	 destroy this array, but final.c assumes that it remains intact
1040890075Sobrien	 across this call; since the insn has been recognized already we
1040990075Sobrien	 call recog direct).  */
1041090075Sobrien      recog (PATTERN (insn), insn, NULL);
1041190075Sobrien    }
1041290075Sobrien}
1041390075Sobrien
1041490075Sobrien/* Returns true if REGNO is a valid register
1041590075Sobrien   for holding a quantity of tyoe MODE.  */
1041690075Sobrienint
10417132718Skanarm_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
1041890075Sobrien{
1041990075Sobrien  if (GET_MODE_CLASS (mode) == MODE_CC)
1042090075Sobrien    return regno == CC_REGNUM;
1042190075Sobrien
1042290075Sobrien  if (TARGET_THUMB)
1042390075Sobrien    /* For the Thumb we only allow values bigger than SImode in
1042490075Sobrien       registers 0 - 6, so that there is always a second low
1042590075Sobrien       register available to hold the upper part of the value.
1042690075Sobrien       We probably we ought to ensure that the register is the
1042790075Sobrien       start of an even numbered register pair.  */
10428117395Skan    return (ARM_NUM_REGS (mode) < 2) || (regno < LAST_LO_REGNUM);
1042990075Sobrien
10430132718Skan  if (IS_CIRRUS_REGNUM (regno))
10431132718Skan    /* We have outlawed SI values in Cirrus registers because they
10432132718Skan       reside in the lower 32 bits, but SF values reside in the
10433132718Skan       upper 32 bits.  This causes gcc all sorts of grief.  We can't
10434132718Skan       even split the registers into pairs because Cirrus SI values
10435132718Skan       get sign extended to 64bits-- aldyh.  */
10436132718Skan    return (GET_MODE_CLASS (mode) == MODE_FLOAT) || (mode == DImode);
10437132718Skan
10438132718Skan  if (IS_IWMMXT_GR_REGNUM (regno))
10439132718Skan    return mode == SImode;
10440132718Skan
10441132718Skan  if (IS_IWMMXT_REGNUM (regno))
10442132718Skan    return VALID_IWMMXT_REG_MODE (mode);
10443132718Skan
1044490075Sobrien  if (regno <= LAST_ARM_REGNUM)
10445132718Skan    /* We allow any value to be stored in the general registers.  */
1044696263Sobrien    return 1;
1044790075Sobrien
1044890075Sobrien  if (   regno == FRAME_POINTER_REGNUM
1044990075Sobrien      || regno == ARG_POINTER_REGNUM)
1045090075Sobrien    /* We only allow integers in the fake hard registers.  */
1045190075Sobrien    return GET_MODE_CLASS (mode) == MODE_INT;
1045290075Sobrien
10453132718Skan  /* The only registers left are the FPA registers
1045490075Sobrien     which we only allow to hold FP values.  */
1045590075Sobrien  return GET_MODE_CLASS (mode) == MODE_FLOAT
1045690075Sobrien    && regno >= FIRST_ARM_FP_REGNUM
1045790075Sobrien    && regno <= LAST_ARM_FP_REGNUM;
1045890075Sobrien}
1045990075Sobrien
1046090075Sobrienint
10461132718Skanarm_regno_class (int regno)
1046290075Sobrien{
1046390075Sobrien  if (TARGET_THUMB)
1046490075Sobrien    {
1046590075Sobrien      if (regno == STACK_POINTER_REGNUM)
1046690075Sobrien	return STACK_REG;
1046790075Sobrien      if (regno == CC_REGNUM)
1046890075Sobrien	return CC_REG;
1046990075Sobrien      if (regno < 8)
1047090075Sobrien	return LO_REGS;
1047190075Sobrien      return HI_REGS;
1047290075Sobrien    }
1047390075Sobrien
1047490075Sobrien  if (   regno <= LAST_ARM_REGNUM
1047590075Sobrien      || regno == FRAME_POINTER_REGNUM
1047690075Sobrien      || regno == ARG_POINTER_REGNUM)
1047790075Sobrien    return GENERAL_REGS;
1047890075Sobrien
1047990075Sobrien  if (regno == CC_REGNUM)
1048090075Sobrien    return NO_REGS;
1048190075Sobrien
10482132718Skan  if (IS_CIRRUS_REGNUM (regno))
10483132718Skan    return CIRRUS_REGS;
10484132718Skan
10485132718Skan  if (IS_IWMMXT_REGNUM (regno))
10486132718Skan    return IWMMXT_REGS;
10487132718Skan
10488132718Skan  if (IS_IWMMXT_GR_REGNUM (regno))
10489132718Skan    return IWMMXT_GR_REGS;
10490132718Skan
10491132718Skan  return FPA_REGS;
1049290075Sobrien}
1049390075Sobrien
1049490075Sobrien/* Handle a special case when computing the offset
1049590075Sobrien   of an argument from the frame pointer.  */
1049690075Sobrienint
10497132718Skanarm_debugger_arg_offset (int value, rtx addr)
1049890075Sobrien{
1049990075Sobrien  rtx insn;
1050090075Sobrien
1050190075Sobrien  /* We are only interested if dbxout_parms() failed to compute the offset.  */
1050290075Sobrien  if (value != 0)
1050390075Sobrien    return 0;
1050490075Sobrien
1050590075Sobrien  /* We can only cope with the case where the address is held in a register.  */
1050690075Sobrien  if (GET_CODE (addr) != REG)
1050790075Sobrien    return 0;
1050890075Sobrien
1050990075Sobrien  /* If we are using the frame pointer to point at the argument, then
1051090075Sobrien     an offset of 0 is correct.  */
1051190075Sobrien  if (REGNO (addr) == (unsigned) HARD_FRAME_POINTER_REGNUM)
1051290075Sobrien    return 0;
1051390075Sobrien
1051490075Sobrien  /* If we are using the stack pointer to point at the
1051590075Sobrien     argument, then an offset of 0 is correct.  */
1051690075Sobrien  if ((TARGET_THUMB || !frame_pointer_needed)
1051790075Sobrien      && REGNO (addr) == SP_REGNUM)
1051890075Sobrien    return 0;
1051990075Sobrien
1052090075Sobrien  /* Oh dear.  The argument is pointed to by a register rather
1052190075Sobrien     than being held in a register, or being stored at a known
1052290075Sobrien     offset from the frame pointer.  Since GDB only understands
1052390075Sobrien     those two kinds of argument we must translate the address
1052490075Sobrien     held in the register into an offset from the frame pointer.
1052590075Sobrien     We do this by searching through the insns for the function
1052690075Sobrien     looking to see where this register gets its value.  If the
10527117395Skan     register is initialized from the frame pointer plus an offset
1052890075Sobrien     then we are in luck and we can continue, otherwise we give up.
1052990075Sobrien
1053090075Sobrien     This code is exercised by producing debugging information
1053190075Sobrien     for a function with arguments like this:
1053290075Sobrien
1053390075Sobrien           double func (double a, double b, int c, double d) {return d;}
1053490075Sobrien
1053590075Sobrien     Without this code the stab for parameter 'd' will be set to
1053690075Sobrien     an offset of 0 from the frame pointer, rather than 8.  */
1053790075Sobrien
1053890075Sobrien  /* The if() statement says:
1053990075Sobrien
1054090075Sobrien     If the insn is a normal instruction
1054190075Sobrien     and if the insn is setting the value in a register
1054290075Sobrien     and if the register being set is the register holding the address of the argument
1054390075Sobrien     and if the address is computing by an addition
1054490075Sobrien     that involves adding to a register
1054590075Sobrien     which is the frame pointer
1054690075Sobrien     a constant integer
1054790075Sobrien
10548132718Skan     then...  */
1054990075Sobrien
1055090075Sobrien  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
1055190075Sobrien    {
1055290075Sobrien      if (   GET_CODE (insn) == INSN
1055390075Sobrien	  && GET_CODE (PATTERN (insn)) == SET
1055490075Sobrien	  && REGNO    (XEXP (PATTERN (insn), 0)) == REGNO (addr)
1055590075Sobrien	  && GET_CODE (XEXP (PATTERN (insn), 1)) == PLUS
1055690075Sobrien	  && GET_CODE (XEXP (XEXP (PATTERN (insn), 1), 0)) == REG
1055790075Sobrien	  && REGNO    (XEXP (XEXP (PATTERN (insn), 1), 0)) == (unsigned) HARD_FRAME_POINTER_REGNUM
1055890075Sobrien	  && GET_CODE (XEXP (XEXP (PATTERN (insn), 1), 1)) == CONST_INT
1055990075Sobrien	     )
1056090075Sobrien	{
1056190075Sobrien	  value = INTVAL (XEXP (XEXP (PATTERN (insn), 1), 1));
1056290075Sobrien
1056390075Sobrien	  break;
1056490075Sobrien	}
1056590075Sobrien    }
1056690075Sobrien
1056790075Sobrien  if (value == 0)
1056890075Sobrien    {
1056990075Sobrien      debug_rtx (addr);
1057090075Sobrien      warning ("unable to compute real location of stacked parameter");
1057190075Sobrien      value = 8; /* XXX magic hack */
1057290075Sobrien    }
1057390075Sobrien
1057490075Sobrien  return value;
1057590075Sobrien}
10576132718Skan
10577132718Skan#define def_mbuiltin(MASK, NAME, TYPE, CODE)				\
10578132718Skan  do									\
10579132718Skan    {									\
10580132718Skan      if ((MASK) & insn_flags)						\
10581132718Skan        builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, NULL, NULL_TREE);	\
10582132718Skan    }									\
10583132718Skan  while (0)
1058490075Sobrien
10585132718Skanstruct builtin_description
10586132718Skan{
10587132718Skan  const unsigned int       mask;
10588132718Skan  const enum insn_code     icode;
10589132718Skan  const char * const       name;
10590132718Skan  const enum arm_builtins  code;
10591132718Skan  const enum rtx_code      comparison;
10592132718Skan  const unsigned int       flag;
10593132718Skan};
1059490075Sobrien
10595132718Skanstatic const struct builtin_description bdesc_2arg[] =
1059690075Sobrien{
10597132718Skan#define IWMMXT_BUILTIN(code, string, builtin) \
10598132718Skan  { FL_IWMMXT, CODE_FOR_##code, "__builtin_arm_" string, \
10599132718Skan    ARM_BUILTIN_##builtin, 0, 0 },
10600132718Skan
10601132718Skan  IWMMXT_BUILTIN (addv8qi3, "waddb", WADDB)
10602132718Skan  IWMMXT_BUILTIN (addv4hi3, "waddh", WADDH)
10603132718Skan  IWMMXT_BUILTIN (addv2si3, "waddw", WADDW)
10604132718Skan  IWMMXT_BUILTIN (subv8qi3, "wsubb", WSUBB)
10605132718Skan  IWMMXT_BUILTIN (subv4hi3, "wsubh", WSUBH)
10606132718Skan  IWMMXT_BUILTIN (subv2si3, "wsubw", WSUBW)
10607132718Skan  IWMMXT_BUILTIN (ssaddv8qi3, "waddbss", WADDSSB)
10608132718Skan  IWMMXT_BUILTIN (ssaddv4hi3, "waddhss", WADDSSH)
10609132718Skan  IWMMXT_BUILTIN (ssaddv2si3, "waddwss", WADDSSW)
10610132718Skan  IWMMXT_BUILTIN (sssubv8qi3, "wsubbss", WSUBSSB)
10611132718Skan  IWMMXT_BUILTIN (sssubv4hi3, "wsubhss", WSUBSSH)
10612132718Skan  IWMMXT_BUILTIN (sssubv2si3, "wsubwss", WSUBSSW)
10613132718Skan  IWMMXT_BUILTIN (usaddv8qi3, "waddbus", WADDUSB)
10614132718Skan  IWMMXT_BUILTIN (usaddv4hi3, "waddhus", WADDUSH)
10615132718Skan  IWMMXT_BUILTIN (usaddv2si3, "waddwus", WADDUSW)
10616132718Skan  IWMMXT_BUILTIN (ussubv8qi3, "wsubbus", WSUBUSB)
10617132718Skan  IWMMXT_BUILTIN (ussubv4hi3, "wsubhus", WSUBUSH)
10618132718Skan  IWMMXT_BUILTIN (ussubv2si3, "wsubwus", WSUBUSW)
10619132718Skan  IWMMXT_BUILTIN (mulv4hi3, "wmulul", WMULUL)
10620132718Skan  IWMMXT_BUILTIN (smulv4hi3_highpart, "wmulsh", WMULSH)
10621132718Skan  IWMMXT_BUILTIN (umulv4hi3_highpart, "wmuluh", WMULUH)
10622132718Skan  IWMMXT_BUILTIN (eqv8qi3, "wcmpeqb", WCMPEQB)
10623132718Skan  IWMMXT_BUILTIN (eqv4hi3, "wcmpeqh", WCMPEQH)
10624132718Skan  IWMMXT_BUILTIN (eqv2si3, "wcmpeqw", WCMPEQW)
10625132718Skan  IWMMXT_BUILTIN (gtuv8qi3, "wcmpgtub", WCMPGTUB)
10626132718Skan  IWMMXT_BUILTIN (gtuv4hi3, "wcmpgtuh", WCMPGTUH)
10627132718Skan  IWMMXT_BUILTIN (gtuv2si3, "wcmpgtuw", WCMPGTUW)
10628132718Skan  IWMMXT_BUILTIN (gtv8qi3, "wcmpgtsb", WCMPGTSB)
10629132718Skan  IWMMXT_BUILTIN (gtv4hi3, "wcmpgtsh", WCMPGTSH)
10630132718Skan  IWMMXT_BUILTIN (gtv2si3, "wcmpgtsw", WCMPGTSW)
10631132718Skan  IWMMXT_BUILTIN (umaxv8qi3, "wmaxub", WMAXUB)
10632132718Skan  IWMMXT_BUILTIN (smaxv8qi3, "wmaxsb", WMAXSB)
10633132718Skan  IWMMXT_BUILTIN (umaxv4hi3, "wmaxuh", WMAXUH)
10634132718Skan  IWMMXT_BUILTIN (smaxv4hi3, "wmaxsh", WMAXSH)
10635132718Skan  IWMMXT_BUILTIN (umaxv2si3, "wmaxuw", WMAXUW)
10636132718Skan  IWMMXT_BUILTIN (smaxv2si3, "wmaxsw", WMAXSW)
10637132718Skan  IWMMXT_BUILTIN (uminv8qi3, "wminub", WMINUB)
10638132718Skan  IWMMXT_BUILTIN (sminv8qi3, "wminsb", WMINSB)
10639132718Skan  IWMMXT_BUILTIN (uminv4hi3, "wminuh", WMINUH)
10640132718Skan  IWMMXT_BUILTIN (sminv4hi3, "wminsh", WMINSH)
10641132718Skan  IWMMXT_BUILTIN (uminv2si3, "wminuw", WMINUW)
10642132718Skan  IWMMXT_BUILTIN (sminv2si3, "wminsw", WMINSW)
10643132718Skan  IWMMXT_BUILTIN (iwmmxt_anddi3, "wand", WAND)
10644132718Skan  IWMMXT_BUILTIN (iwmmxt_nanddi3, "wandn", WANDN)
10645132718Skan  IWMMXT_BUILTIN (iwmmxt_iordi3, "wor", WOR)
10646132718Skan  IWMMXT_BUILTIN (iwmmxt_xordi3, "wxor", WXOR)
10647132718Skan  IWMMXT_BUILTIN (iwmmxt_uavgv8qi3, "wavg2b", WAVG2B)
10648132718Skan  IWMMXT_BUILTIN (iwmmxt_uavgv4hi3, "wavg2h", WAVG2H)
10649132718Skan  IWMMXT_BUILTIN (iwmmxt_uavgrndv8qi3, "wavg2br", WAVG2BR)
10650132718Skan  IWMMXT_BUILTIN (iwmmxt_uavgrndv4hi3, "wavg2hr", WAVG2HR)
10651132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckilb, "wunpckilb", WUNPCKILB)
10652132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckilh, "wunpckilh", WUNPCKILH)
10653132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckilw, "wunpckilw", WUNPCKILW)
10654132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckihb, "wunpckihb", WUNPCKIHB)
10655132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckihh, "wunpckihh", WUNPCKIHH)
10656132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckihw, "wunpckihw", WUNPCKIHW)
10657132718Skan  IWMMXT_BUILTIN (iwmmxt_wmadds, "wmadds", WMADDS)
10658132718Skan  IWMMXT_BUILTIN (iwmmxt_wmaddu, "wmaddu", WMADDU)
10659132718Skan
10660132718Skan#define IWMMXT_BUILTIN2(code, builtin) \
10661132718Skan  { FL_IWMMXT, CODE_FOR_##code, NULL, ARM_BUILTIN_##builtin, 0, 0 },
10662132718Skan
10663132718Skan  IWMMXT_BUILTIN2 (iwmmxt_wpackhss, WPACKHSS)
10664132718Skan  IWMMXT_BUILTIN2 (iwmmxt_wpackwss, WPACKWSS)
10665132718Skan  IWMMXT_BUILTIN2 (iwmmxt_wpackdss, WPACKDSS)
10666132718Skan  IWMMXT_BUILTIN2 (iwmmxt_wpackhus, WPACKHUS)
10667132718Skan  IWMMXT_BUILTIN2 (iwmmxt_wpackwus, WPACKWUS)
10668132718Skan  IWMMXT_BUILTIN2 (iwmmxt_wpackdus, WPACKDUS)
10669132718Skan  IWMMXT_BUILTIN2 (ashlv4hi3_di,    WSLLH)
10670132718Skan  IWMMXT_BUILTIN2 (ashlv4hi3,       WSLLHI)
10671132718Skan  IWMMXT_BUILTIN2 (ashlv2si3_di,    WSLLW)
10672132718Skan  IWMMXT_BUILTIN2 (ashlv2si3,       WSLLWI)
10673132718Skan  IWMMXT_BUILTIN2 (ashldi3_di,      WSLLD)
10674132718Skan  IWMMXT_BUILTIN2 (ashldi3_iwmmxt,  WSLLDI)
10675132718Skan  IWMMXT_BUILTIN2 (lshrv4hi3_di,    WSRLH)
10676132718Skan  IWMMXT_BUILTIN2 (lshrv4hi3,       WSRLHI)
10677132718Skan  IWMMXT_BUILTIN2 (lshrv2si3_di,    WSRLW)
10678132718Skan  IWMMXT_BUILTIN2 (lshrv2si3,       WSRLWI)
10679132718Skan  IWMMXT_BUILTIN2 (lshrdi3_di,      WSRLD)
10680132718Skan  IWMMXT_BUILTIN2 (lshrdi3,         WSRLDI)
10681132718Skan  IWMMXT_BUILTIN2 (ashrv4hi3_di,    WSRAH)
10682132718Skan  IWMMXT_BUILTIN2 (ashrv4hi3,       WSRAHI)
10683132718Skan  IWMMXT_BUILTIN2 (ashrv2si3_di,    WSRAW)
10684132718Skan  IWMMXT_BUILTIN2 (ashrv2si3,       WSRAWI)
10685132718Skan  IWMMXT_BUILTIN2 (ashrdi3_di,      WSRAD)
10686132718Skan  IWMMXT_BUILTIN2 (ashrdi3,         WSRADI)
10687132718Skan  IWMMXT_BUILTIN2 (rorv4hi3_di,     WRORH)
10688132718Skan  IWMMXT_BUILTIN2 (rorv4hi3,        WRORHI)
10689132718Skan  IWMMXT_BUILTIN2 (rorv2si3_di,     WRORW)
10690132718Skan  IWMMXT_BUILTIN2 (rorv2si3,        WRORWI)
10691132718Skan  IWMMXT_BUILTIN2 (rordi3_di,       WRORD)
10692132718Skan  IWMMXT_BUILTIN2 (rordi3,          WRORDI)
10693132718Skan  IWMMXT_BUILTIN2 (iwmmxt_wmacuz,   WMACUZ)
10694132718Skan  IWMMXT_BUILTIN2 (iwmmxt_wmacsz,   WMACSZ)
10695132718Skan};
10696132718Skan
10697132718Skanstatic const struct builtin_description bdesc_1arg[] =
10698132718Skan{
10699132718Skan  IWMMXT_BUILTIN (iwmmxt_tmovmskb, "tmovmskb", TMOVMSKB)
10700132718Skan  IWMMXT_BUILTIN (iwmmxt_tmovmskh, "tmovmskh", TMOVMSKH)
10701132718Skan  IWMMXT_BUILTIN (iwmmxt_tmovmskw, "tmovmskw", TMOVMSKW)
10702132718Skan  IWMMXT_BUILTIN (iwmmxt_waccb, "waccb", WACCB)
10703132718Skan  IWMMXT_BUILTIN (iwmmxt_wacch, "wacch", WACCH)
10704132718Skan  IWMMXT_BUILTIN (iwmmxt_waccw, "waccw", WACCW)
10705132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckehub, "wunpckehub", WUNPCKEHUB)
10706132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckehuh, "wunpckehuh", WUNPCKEHUH)
10707132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckehuw, "wunpckehuw", WUNPCKEHUW)
10708132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckehsb, "wunpckehsb", WUNPCKEHSB)
10709132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckehsh, "wunpckehsh", WUNPCKEHSH)
10710132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckehsw, "wunpckehsw", WUNPCKEHSW)
10711132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckelub, "wunpckelub", WUNPCKELUB)
10712132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckeluh, "wunpckeluh", WUNPCKELUH)
10713132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckeluw, "wunpckeluw", WUNPCKELUW)
10714132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckelsb, "wunpckelsb", WUNPCKELSB)
10715132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckelsh, "wunpckelsh", WUNPCKELSH)
10716132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckelsw, "wunpckelsw", WUNPCKELSW)
10717132718Skan};
10718132718Skan
10719132718Skan/* Set up all the iWMMXt builtins.  This is
10720132718Skan   not called if TARGET_IWMMXT is zero.  */
10721132718Skan
10722132718Skanstatic void
10723132718Skanarm_init_iwmmxt_builtins (void)
10724132718Skan{
10725132718Skan  const struct builtin_description * d;
10726132718Skan  size_t i;
1072790075Sobrien  tree endlink = void_list_node;
1072890075Sobrien
10729132718Skan  tree int_ftype_int
10730132718Skan    = build_function_type (integer_type_node,
10731132718Skan			   tree_cons (NULL_TREE, integer_type_node, endlink));
10732132718Skan  tree v8qi_ftype_v8qi_v8qi_int
10733132718Skan    = build_function_type (V8QI_type_node,
10734132718Skan			   tree_cons (NULL_TREE, V8QI_type_node,
10735132718Skan				      tree_cons (NULL_TREE, V8QI_type_node,
10736132718Skan						 tree_cons (NULL_TREE,
10737132718Skan							    integer_type_node,
10738132718Skan							    endlink))));
10739132718Skan  tree v4hi_ftype_v4hi_int
10740132718Skan    = build_function_type (V4HI_type_node,
10741132718Skan			   tree_cons (NULL_TREE, V4HI_type_node,
10742132718Skan				      tree_cons (NULL_TREE, integer_type_node,
10743132718Skan						 endlink)));
10744132718Skan  tree v2si_ftype_v2si_int
10745132718Skan    = build_function_type (V2SI_type_node,
10746132718Skan			   tree_cons (NULL_TREE, V2SI_type_node,
10747132718Skan				      tree_cons (NULL_TREE, integer_type_node,
10748132718Skan						 endlink)));
10749132718Skan  tree v2si_ftype_di_di
10750132718Skan    = build_function_type (V2SI_type_node,
10751132718Skan			   tree_cons (NULL_TREE, long_long_integer_type_node,
10752132718Skan				      tree_cons (NULL_TREE, long_long_integer_type_node,
10753132718Skan						 endlink)));
10754132718Skan  tree di_ftype_di_int
10755132718Skan    = build_function_type (long_long_integer_type_node,
10756132718Skan			   tree_cons (NULL_TREE, long_long_integer_type_node,
10757132718Skan				      tree_cons (NULL_TREE, integer_type_node,
10758132718Skan						 endlink)));
10759132718Skan  tree di_ftype_di_int_int
10760132718Skan    = build_function_type (long_long_integer_type_node,
10761132718Skan			   tree_cons (NULL_TREE, long_long_integer_type_node,
10762132718Skan				      tree_cons (NULL_TREE, integer_type_node,
10763132718Skan						 tree_cons (NULL_TREE,
10764132718Skan							    integer_type_node,
10765132718Skan							    endlink))));
10766132718Skan  tree int_ftype_v8qi
10767132718Skan    = build_function_type (integer_type_node,
10768132718Skan			   tree_cons (NULL_TREE, V8QI_type_node,
10769132718Skan				      endlink));
10770132718Skan  tree int_ftype_v4hi
10771132718Skan    = build_function_type (integer_type_node,
10772132718Skan			   tree_cons (NULL_TREE, V4HI_type_node,
10773132718Skan				      endlink));
10774132718Skan  tree int_ftype_v2si
10775132718Skan    = build_function_type (integer_type_node,
10776132718Skan			   tree_cons (NULL_TREE, V2SI_type_node,
10777132718Skan				      endlink));
10778132718Skan  tree int_ftype_v8qi_int
10779132718Skan    = build_function_type (integer_type_node,
10780132718Skan			   tree_cons (NULL_TREE, V8QI_type_node,
10781132718Skan				      tree_cons (NULL_TREE, integer_type_node,
10782132718Skan						 endlink)));
10783132718Skan  tree int_ftype_v4hi_int
10784132718Skan    = build_function_type (integer_type_node,
10785132718Skan			   tree_cons (NULL_TREE, V4HI_type_node,
10786132718Skan				      tree_cons (NULL_TREE, integer_type_node,
10787132718Skan						 endlink)));
10788132718Skan  tree int_ftype_v2si_int
10789132718Skan    = build_function_type (integer_type_node,
10790132718Skan			   tree_cons (NULL_TREE, V2SI_type_node,
10791132718Skan				      tree_cons (NULL_TREE, integer_type_node,
10792132718Skan						 endlink)));
10793132718Skan  tree v8qi_ftype_v8qi_int_int
10794132718Skan    = build_function_type (V8QI_type_node,
10795132718Skan			   tree_cons (NULL_TREE, V8QI_type_node,
10796132718Skan				      tree_cons (NULL_TREE, integer_type_node,
10797132718Skan						 tree_cons (NULL_TREE,
10798132718Skan							    integer_type_node,
10799132718Skan							    endlink))));
10800132718Skan  tree v4hi_ftype_v4hi_int_int
10801132718Skan    = build_function_type (V4HI_type_node,
10802132718Skan			   tree_cons (NULL_TREE, V4HI_type_node,
10803132718Skan				      tree_cons (NULL_TREE, integer_type_node,
10804132718Skan						 tree_cons (NULL_TREE,
10805132718Skan							    integer_type_node,
10806132718Skan							    endlink))));
10807132718Skan  tree v2si_ftype_v2si_int_int
10808132718Skan    = build_function_type (V2SI_type_node,
10809132718Skan			   tree_cons (NULL_TREE, V2SI_type_node,
10810132718Skan				      tree_cons (NULL_TREE, integer_type_node,
10811132718Skan						 tree_cons (NULL_TREE,
10812132718Skan							    integer_type_node,
10813132718Skan							    endlink))));
10814132718Skan  /* Miscellaneous.  */
10815132718Skan  tree v8qi_ftype_v4hi_v4hi
10816132718Skan    = build_function_type (V8QI_type_node,
10817132718Skan			   tree_cons (NULL_TREE, V4HI_type_node,
10818132718Skan				      tree_cons (NULL_TREE, V4HI_type_node,
10819132718Skan						 endlink)));
10820132718Skan  tree v4hi_ftype_v2si_v2si
10821132718Skan    = build_function_type (V4HI_type_node,
10822132718Skan			   tree_cons (NULL_TREE, V2SI_type_node,
10823132718Skan				      tree_cons (NULL_TREE, V2SI_type_node,
10824132718Skan						 endlink)));
10825132718Skan  tree v2si_ftype_v4hi_v4hi
10826132718Skan    = build_function_type (V2SI_type_node,
10827132718Skan			   tree_cons (NULL_TREE, V4HI_type_node,
10828132718Skan				      tree_cons (NULL_TREE, V4HI_type_node,
10829132718Skan						 endlink)));
10830132718Skan  tree v2si_ftype_v8qi_v8qi
10831132718Skan    = build_function_type (V2SI_type_node,
10832132718Skan			   tree_cons (NULL_TREE, V8QI_type_node,
10833132718Skan				      tree_cons (NULL_TREE, V8QI_type_node,
10834132718Skan						 endlink)));
10835132718Skan  tree v4hi_ftype_v4hi_di
10836132718Skan    = build_function_type (V4HI_type_node,
10837132718Skan			   tree_cons (NULL_TREE, V4HI_type_node,
10838132718Skan				      tree_cons (NULL_TREE,
10839132718Skan						 long_long_integer_type_node,
10840132718Skan						 endlink)));
10841132718Skan  tree v2si_ftype_v2si_di
10842132718Skan    = build_function_type (V2SI_type_node,
10843132718Skan			   tree_cons (NULL_TREE, V2SI_type_node,
10844132718Skan				      tree_cons (NULL_TREE,
10845132718Skan						 long_long_integer_type_node,
10846132718Skan						 endlink)));
10847132718Skan  tree void_ftype_int_int
10848132718Skan    = build_function_type (void_type_node,
10849132718Skan			   tree_cons (NULL_TREE, integer_type_node,
10850132718Skan				      tree_cons (NULL_TREE, integer_type_node,
10851132718Skan						 endlink)));
10852132718Skan  tree di_ftype_void
10853132718Skan    = build_function_type (long_long_unsigned_type_node, endlink);
10854132718Skan  tree di_ftype_v8qi
10855132718Skan    = build_function_type (long_long_integer_type_node,
10856132718Skan			   tree_cons (NULL_TREE, V8QI_type_node,
10857132718Skan				      endlink));
10858132718Skan  tree di_ftype_v4hi
10859132718Skan    = build_function_type (long_long_integer_type_node,
10860132718Skan			   tree_cons (NULL_TREE, V4HI_type_node,
10861132718Skan				      endlink));
10862132718Skan  tree di_ftype_v2si
10863132718Skan    = build_function_type (long_long_integer_type_node,
10864132718Skan			   tree_cons (NULL_TREE, V2SI_type_node,
10865132718Skan				      endlink));
10866132718Skan  tree v2si_ftype_v4hi
10867132718Skan    = build_function_type (V2SI_type_node,
10868132718Skan			   tree_cons (NULL_TREE, V4HI_type_node,
10869132718Skan				      endlink));
10870132718Skan  tree v4hi_ftype_v8qi
10871132718Skan    = build_function_type (V4HI_type_node,
10872132718Skan			   tree_cons (NULL_TREE, V8QI_type_node,
10873132718Skan				      endlink));
1087490075Sobrien
10875132718Skan  tree di_ftype_di_v4hi_v4hi
10876132718Skan    = build_function_type (long_long_unsigned_type_node,
10877132718Skan			   tree_cons (NULL_TREE,
10878132718Skan				      long_long_unsigned_type_node,
10879132718Skan				      tree_cons (NULL_TREE, V4HI_type_node,
10880132718Skan						 tree_cons (NULL_TREE,
10881132718Skan							    V4HI_type_node,
10882132718Skan							    endlink))));
1088390075Sobrien
10884132718Skan  tree di_ftype_v4hi_v4hi
10885132718Skan    = build_function_type (long_long_unsigned_type_node,
10886132718Skan			   tree_cons (NULL_TREE, V4HI_type_node,
10887132718Skan				      tree_cons (NULL_TREE, V4HI_type_node,
10888132718Skan						 endlink)));
1088990075Sobrien
10890132718Skan  /* Normal vector binops.  */
10891132718Skan  tree v8qi_ftype_v8qi_v8qi
10892132718Skan    = build_function_type (V8QI_type_node,
10893132718Skan			   tree_cons (NULL_TREE, V8QI_type_node,
10894132718Skan				      tree_cons (NULL_TREE, V8QI_type_node,
10895132718Skan						 endlink)));
10896132718Skan  tree v4hi_ftype_v4hi_v4hi
10897132718Skan    = build_function_type (V4HI_type_node,
10898132718Skan			   tree_cons (NULL_TREE, V4HI_type_node,
10899132718Skan				      tree_cons (NULL_TREE, V4HI_type_node,
10900132718Skan						 endlink)));
10901132718Skan  tree v2si_ftype_v2si_v2si
10902132718Skan    = build_function_type (V2SI_type_node,
10903132718Skan			   tree_cons (NULL_TREE, V2SI_type_node,
10904132718Skan				      tree_cons (NULL_TREE, V2SI_type_node,
10905132718Skan						 endlink)));
10906132718Skan  tree di_ftype_di_di
10907132718Skan    = build_function_type (long_long_unsigned_type_node,
10908132718Skan			   tree_cons (NULL_TREE, long_long_unsigned_type_node,
10909132718Skan				      tree_cons (NULL_TREE,
10910132718Skan						 long_long_unsigned_type_node,
10911132718Skan						 endlink)));
10912132718Skan
10913132718Skan  /* Add all builtins that are more or less simple operations on two
10914132718Skan     operands.  */
10915132718Skan  for (i = 0, d = bdesc_2arg; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
10916132718Skan    {
10917132718Skan      /* Use one of the operands; the target can have a different mode for
10918132718Skan	 mask-generating compares.  */
10919132718Skan      enum machine_mode mode;
10920132718Skan      tree type;
10921132718Skan
10922132718Skan      if (d->name == 0)
10923132718Skan	continue;
10924132718Skan
10925132718Skan      mode = insn_data[d->icode].operand[1].mode;
10926132718Skan
10927132718Skan      switch (mode)
10928132718Skan	{
10929132718Skan	case V8QImode:
10930132718Skan	  type = v8qi_ftype_v8qi_v8qi;
10931132718Skan	  break;
10932132718Skan	case V4HImode:
10933132718Skan	  type = v4hi_ftype_v4hi_v4hi;
10934132718Skan	  break;
10935132718Skan	case V2SImode:
10936132718Skan	  type = v2si_ftype_v2si_v2si;
10937132718Skan	  break;
10938132718Skan	case DImode:
10939132718Skan	  type = di_ftype_di_di;
10940132718Skan	  break;
10941132718Skan
10942132718Skan	default:
10943132718Skan	  abort ();
10944132718Skan	}
10945132718Skan
10946132718Skan      def_mbuiltin (d->mask, d->name, type, d->code);
10947132718Skan    }
10948132718Skan
10949132718Skan  /* Add the remaining MMX insns with somewhat more complicated types.  */
10950132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wzero", di_ftype_void, ARM_BUILTIN_WZERO);
10951132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_setwcx", void_ftype_int_int, ARM_BUILTIN_SETWCX);
10952132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_getwcx", int_ftype_int, ARM_BUILTIN_GETWCX);
10953132718Skan
10954132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsllh", v4hi_ftype_v4hi_di, ARM_BUILTIN_WSLLH);
10955132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsllw", v2si_ftype_v2si_di, ARM_BUILTIN_WSLLW);
10956132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wslld", di_ftype_di_di, ARM_BUILTIN_WSLLD);
10957132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsllhi", v4hi_ftype_v4hi_int, ARM_BUILTIN_WSLLHI);
10958132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsllwi", v2si_ftype_v2si_int, ARM_BUILTIN_WSLLWI);
10959132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wslldi", di_ftype_di_int, ARM_BUILTIN_WSLLDI);
10960132718Skan
10961132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrlh", v4hi_ftype_v4hi_di, ARM_BUILTIN_WSRLH);
10962132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrlw", v2si_ftype_v2si_di, ARM_BUILTIN_WSRLW);
10963132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrld", di_ftype_di_di, ARM_BUILTIN_WSRLD);
10964132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrlhi", v4hi_ftype_v4hi_int, ARM_BUILTIN_WSRLHI);
10965132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrlwi", v2si_ftype_v2si_int, ARM_BUILTIN_WSRLWI);
10966132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrldi", di_ftype_di_int, ARM_BUILTIN_WSRLDI);
10967132718Skan
10968132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrah", v4hi_ftype_v4hi_di, ARM_BUILTIN_WSRAH);
10969132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsraw", v2si_ftype_v2si_di, ARM_BUILTIN_WSRAW);
10970132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrad", di_ftype_di_di, ARM_BUILTIN_WSRAD);
10971132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrahi", v4hi_ftype_v4hi_int, ARM_BUILTIN_WSRAHI);
10972132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrawi", v2si_ftype_v2si_int, ARM_BUILTIN_WSRAWI);
10973132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsradi", di_ftype_di_int, ARM_BUILTIN_WSRADI);
10974132718Skan
10975132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wrorh", v4hi_ftype_v4hi_di, ARM_BUILTIN_WRORH);
10976132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wrorw", v2si_ftype_v2si_di, ARM_BUILTIN_WRORW);
10977132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wrord", di_ftype_di_di, ARM_BUILTIN_WRORD);
10978132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wrorhi", v4hi_ftype_v4hi_int, ARM_BUILTIN_WRORHI);
10979132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wrorwi", v2si_ftype_v2si_int, ARM_BUILTIN_WRORWI);
10980132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wrordi", di_ftype_di_int, ARM_BUILTIN_WRORDI);
10981132718Skan
10982132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wshufh", v4hi_ftype_v4hi_int, ARM_BUILTIN_WSHUFH);
10983132718Skan
10984132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsadb", v2si_ftype_v8qi_v8qi, ARM_BUILTIN_WSADB);
10985132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsadh", v2si_ftype_v4hi_v4hi, ARM_BUILTIN_WSADH);
10986132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsadbz", v2si_ftype_v8qi_v8qi, ARM_BUILTIN_WSADBZ);
10987132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsadhz", v2si_ftype_v4hi_v4hi, ARM_BUILTIN_WSADHZ);
10988132718Skan
10989132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_textrmsb", int_ftype_v8qi_int, ARM_BUILTIN_TEXTRMSB);
10990132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_textrmsh", int_ftype_v4hi_int, ARM_BUILTIN_TEXTRMSH);
10991132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_textrmsw", int_ftype_v2si_int, ARM_BUILTIN_TEXTRMSW);
10992132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_textrmub", int_ftype_v8qi_int, ARM_BUILTIN_TEXTRMUB);
10993132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_textrmuh", int_ftype_v4hi_int, ARM_BUILTIN_TEXTRMUH);
10994132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_textrmuw", int_ftype_v2si_int, ARM_BUILTIN_TEXTRMUW);
10995132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tinsrb", v8qi_ftype_v8qi_int_int, ARM_BUILTIN_TINSRB);
10996132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tinsrh", v4hi_ftype_v4hi_int_int, ARM_BUILTIN_TINSRH);
10997132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tinsrw", v2si_ftype_v2si_int_int, ARM_BUILTIN_TINSRW);
10998132718Skan
10999132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_waccb", di_ftype_v8qi, ARM_BUILTIN_WACCB);
11000132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wacch", di_ftype_v4hi, ARM_BUILTIN_WACCH);
11001132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_waccw", di_ftype_v2si, ARM_BUILTIN_WACCW);
11002132718Skan
11003132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmovmskb", int_ftype_v8qi, ARM_BUILTIN_TMOVMSKB);
11004132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmovmskh", int_ftype_v4hi, ARM_BUILTIN_TMOVMSKH);
11005132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmovmskw", int_ftype_v2si, ARM_BUILTIN_TMOVMSKW);
11006132718Skan
11007132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wpackhss", v8qi_ftype_v4hi_v4hi, ARM_BUILTIN_WPACKHSS);
11008132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wpackhus", v8qi_ftype_v4hi_v4hi, ARM_BUILTIN_WPACKHUS);
11009132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wpackwus", v4hi_ftype_v2si_v2si, ARM_BUILTIN_WPACKWUS);
11010132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wpackwss", v4hi_ftype_v2si_v2si, ARM_BUILTIN_WPACKWSS);
11011132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wpackdus", v2si_ftype_di_di, ARM_BUILTIN_WPACKDUS);
11012132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wpackdss", v2si_ftype_di_di, ARM_BUILTIN_WPACKDSS);
11013132718Skan
11014132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckehub", v4hi_ftype_v8qi, ARM_BUILTIN_WUNPCKEHUB);
11015132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckehuh", v2si_ftype_v4hi, ARM_BUILTIN_WUNPCKEHUH);
11016132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckehuw", di_ftype_v2si, ARM_BUILTIN_WUNPCKEHUW);
11017132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckehsb", v4hi_ftype_v8qi, ARM_BUILTIN_WUNPCKEHSB);
11018132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckehsh", v2si_ftype_v4hi, ARM_BUILTIN_WUNPCKEHSH);
11019132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckehsw", di_ftype_v2si, ARM_BUILTIN_WUNPCKEHSW);
11020132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckelub", v4hi_ftype_v8qi, ARM_BUILTIN_WUNPCKELUB);
11021132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckeluh", v2si_ftype_v4hi, ARM_BUILTIN_WUNPCKELUH);
11022132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckeluw", di_ftype_v2si, ARM_BUILTIN_WUNPCKELUW);
11023132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckelsb", v4hi_ftype_v8qi, ARM_BUILTIN_WUNPCKELSB);
11024132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckelsh", v2si_ftype_v4hi, ARM_BUILTIN_WUNPCKELSH);
11025132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckelsw", di_ftype_v2si, ARM_BUILTIN_WUNPCKELSW);
11026132718Skan
11027132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wmacs", di_ftype_di_v4hi_v4hi, ARM_BUILTIN_WMACS);
11028132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wmacsz", di_ftype_v4hi_v4hi, ARM_BUILTIN_WMACSZ);
11029132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wmacu", di_ftype_di_v4hi_v4hi, ARM_BUILTIN_WMACU);
11030132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wmacuz", di_ftype_v4hi_v4hi, ARM_BUILTIN_WMACUZ);
11031132718Skan
11032132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_walign", v8qi_ftype_v8qi_v8qi_int, ARM_BUILTIN_WALIGN);
11033132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmia", di_ftype_di_int_int, ARM_BUILTIN_TMIA);
11034132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmiaph", di_ftype_di_int_int, ARM_BUILTIN_TMIAPH);
11035132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmiabb", di_ftype_di_int_int, ARM_BUILTIN_TMIABB);
11036132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmiabt", di_ftype_di_int_int, ARM_BUILTIN_TMIABT);
11037132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmiatb", di_ftype_di_int_int, ARM_BUILTIN_TMIATB);
11038132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmiatt", di_ftype_di_int_int, ARM_BUILTIN_TMIATT);
1103990075Sobrien}
1104090075Sobrien
11041132718Skanstatic void
11042132718Skanarm_init_builtins (void)
11043132718Skan{
11044132718Skan  if (TARGET_REALLY_IWMMXT)
11045132718Skan    arm_init_iwmmxt_builtins ();
11046132718Skan}
11047132718Skan
11048132718Skan/* Errors in the source file can cause expand_expr to return const0_rtx
11049132718Skan   where we expect a vector.  To avoid crashing, use one of the vector
11050132718Skan   clear instructions.  */
11051132718Skan
11052132718Skanstatic rtx
11053132718Skansafe_vector_operand (rtx x, enum machine_mode mode)
11054132718Skan{
11055132718Skan  if (x != const0_rtx)
11056132718Skan    return x;
11057132718Skan  x = gen_reg_rtx (mode);
11058132718Skan
11059132718Skan  emit_insn (gen_iwmmxt_clrdi (mode == DImode ? x
11060132718Skan			       : gen_rtx_SUBREG (DImode, x, 0)));
11061132718Skan  return x;
11062132718Skan}
11063132718Skan
11064132718Skan/* Subroutine of arm_expand_builtin to take care of binop insns.  */
11065132718Skan
11066132718Skanstatic rtx
11067132718Skanarm_expand_binop_builtin (enum insn_code icode,
11068132718Skan			  tree arglist, rtx target)
11069132718Skan{
11070132718Skan  rtx pat;
11071132718Skan  tree arg0 = TREE_VALUE (arglist);
11072132718Skan  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
11073132718Skan  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
11074132718Skan  rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
11075132718Skan  enum machine_mode tmode = insn_data[icode].operand[0].mode;
11076132718Skan  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
11077132718Skan  enum machine_mode mode1 = insn_data[icode].operand[2].mode;
11078132718Skan
11079132718Skan  if (VECTOR_MODE_P (mode0))
11080132718Skan    op0 = safe_vector_operand (op0, mode0);
11081132718Skan  if (VECTOR_MODE_P (mode1))
11082132718Skan    op1 = safe_vector_operand (op1, mode1);
11083132718Skan
11084132718Skan  if (! target
11085132718Skan      || GET_MODE (target) != tmode
11086132718Skan      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
11087132718Skan    target = gen_reg_rtx (tmode);
11088132718Skan
11089132718Skan  /* In case the insn wants input operands in modes different from
11090132718Skan     the result, abort.  */
11091132718Skan  if (GET_MODE (op0) != mode0 || GET_MODE (op1) != mode1)
11092132718Skan    abort ();
11093132718Skan
11094132718Skan  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
11095132718Skan    op0 = copy_to_mode_reg (mode0, op0);
11096132718Skan  if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
11097132718Skan    op1 = copy_to_mode_reg (mode1, op1);
11098132718Skan
11099132718Skan  pat = GEN_FCN (icode) (target, op0, op1);
11100132718Skan  if (! pat)
11101132718Skan    return 0;
11102132718Skan  emit_insn (pat);
11103132718Skan  return target;
11104132718Skan}
11105132718Skan
11106132718Skan/* Subroutine of arm_expand_builtin to take care of unop insns.  */
11107132718Skan
11108132718Skanstatic rtx
11109132718Skanarm_expand_unop_builtin (enum insn_code icode,
11110132718Skan			 tree arglist, rtx target, int do_load)
11111132718Skan{
11112132718Skan  rtx pat;
11113132718Skan  tree arg0 = TREE_VALUE (arglist);
11114132718Skan  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
11115132718Skan  enum machine_mode tmode = insn_data[icode].operand[0].mode;
11116132718Skan  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
11117132718Skan
11118132718Skan  if (! target
11119132718Skan      || GET_MODE (target) != tmode
11120132718Skan      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
11121132718Skan    target = gen_reg_rtx (tmode);
11122132718Skan  if (do_load)
11123132718Skan    op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
11124132718Skan  else
11125132718Skan    {
11126132718Skan      if (VECTOR_MODE_P (mode0))
11127132718Skan	op0 = safe_vector_operand (op0, mode0);
11128132718Skan
11129132718Skan      if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
11130132718Skan	op0 = copy_to_mode_reg (mode0, op0);
11131132718Skan    }
11132132718Skan
11133132718Skan  pat = GEN_FCN (icode) (target, op0);
11134132718Skan  if (! pat)
11135132718Skan    return 0;
11136132718Skan  emit_insn (pat);
11137132718Skan  return target;
11138132718Skan}
11139132718Skan
1114090075Sobrien/* Expand an expression EXP that calls a built-in function,
1114190075Sobrien   with result going to TARGET if that's convenient
1114290075Sobrien   (and in mode MODE if that's convenient).
1114390075Sobrien   SUBTARGET may be used as the target for computing one of EXP's operands.
1114490075Sobrien   IGNORE is nonzero if the value is to be ignored.  */
1114590075Sobrien
11146132718Skanstatic rtx
11147132718Skanarm_expand_builtin (tree exp,
11148132718Skan		    rtx target,
11149132718Skan		    rtx subtarget ATTRIBUTE_UNUSED,
11150132718Skan		    enum machine_mode mode ATTRIBUTE_UNUSED,
11151132718Skan		    int ignore ATTRIBUTE_UNUSED)
1115290075Sobrien{
11153132718Skan  const struct builtin_description * d;
11154132718Skan  enum insn_code    icode;
11155132718Skan  tree              fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
11156132718Skan  tree              arglist = TREE_OPERAND (exp, 1);
11157132718Skan  tree              arg0;
11158132718Skan  tree              arg1;
11159132718Skan  tree              arg2;
11160132718Skan  rtx               op0;
11161132718Skan  rtx               op1;
11162132718Skan  rtx               op2;
11163132718Skan  rtx               pat;
11164132718Skan  int               fcode = DECL_FUNCTION_CODE (fndecl);
11165132718Skan  size_t            i;
11166132718Skan  enum machine_mode tmode;
11167132718Skan  enum machine_mode mode0;
11168132718Skan  enum machine_mode mode1;
11169132718Skan  enum machine_mode mode2;
1117090075Sobrien
1117190075Sobrien  switch (fcode)
1117290075Sobrien    {
11173132718Skan    case ARM_BUILTIN_TEXTRMSB:
11174132718Skan    case ARM_BUILTIN_TEXTRMUB:
11175132718Skan    case ARM_BUILTIN_TEXTRMSH:
11176132718Skan    case ARM_BUILTIN_TEXTRMUH:
11177132718Skan    case ARM_BUILTIN_TEXTRMSW:
11178132718Skan    case ARM_BUILTIN_TEXTRMUW:
11179132718Skan      icode = (fcode == ARM_BUILTIN_TEXTRMSB ? CODE_FOR_iwmmxt_textrmsb
11180132718Skan	       : fcode == ARM_BUILTIN_TEXTRMUB ? CODE_FOR_iwmmxt_textrmub
11181132718Skan	       : fcode == ARM_BUILTIN_TEXTRMSH ? CODE_FOR_iwmmxt_textrmsh
11182132718Skan	       : fcode == ARM_BUILTIN_TEXTRMUH ? CODE_FOR_iwmmxt_textrmuh
11183132718Skan	       : CODE_FOR_iwmmxt_textrmw);
11184132718Skan
1118590075Sobrien      arg0 = TREE_VALUE (arglist);
11186132718Skan      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
1118790075Sobrien      op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
11188132718Skan      op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
1118990075Sobrien      tmode = insn_data[icode].operand[0].mode;
1119090075Sobrien      mode0 = insn_data[icode].operand[1].mode;
11191132718Skan      mode1 = insn_data[icode].operand[2].mode;
1119290075Sobrien
1119390075Sobrien      if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
1119490075Sobrien	op0 = copy_to_mode_reg (mode0, op0);
11195132718Skan      if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
11196132718Skan	{
11197132718Skan	  /* @@@ better error message */
11198132718Skan	  error ("selector must be an immediate");
11199132718Skan	  return gen_reg_rtx (tmode);
11200132718Skan	}
1120190075Sobrien      if (target == 0
1120290075Sobrien	  || GET_MODE (target) != tmode
1120390075Sobrien	  || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
1120490075Sobrien	target = gen_reg_rtx (tmode);
11205132718Skan      pat = GEN_FCN (icode) (target, op0, op1);
1120690075Sobrien      if (! pat)
1120790075Sobrien	return 0;
1120890075Sobrien      emit_insn (pat);
1120990075Sobrien      return target;
11210132718Skan
11211132718Skan    case ARM_BUILTIN_TINSRB:
11212132718Skan    case ARM_BUILTIN_TINSRH:
11213132718Skan    case ARM_BUILTIN_TINSRW:
11214132718Skan      icode = (fcode == ARM_BUILTIN_TINSRB ? CODE_FOR_iwmmxt_tinsrb
11215132718Skan	       : fcode == ARM_BUILTIN_TINSRH ? CODE_FOR_iwmmxt_tinsrh
11216132718Skan	       : CODE_FOR_iwmmxt_tinsrw);
11217132718Skan      arg0 = TREE_VALUE (arglist);
11218132718Skan      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
11219132718Skan      arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
11220132718Skan      op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
11221132718Skan      op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
11222132718Skan      op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
11223132718Skan      tmode = insn_data[icode].operand[0].mode;
11224132718Skan      mode0 = insn_data[icode].operand[1].mode;
11225132718Skan      mode1 = insn_data[icode].operand[2].mode;
11226132718Skan      mode2 = insn_data[icode].operand[3].mode;
11227132718Skan
11228132718Skan      if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
11229132718Skan	op0 = copy_to_mode_reg (mode0, op0);
11230132718Skan      if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
11231132718Skan	op1 = copy_to_mode_reg (mode1, op1);
11232132718Skan      if (! (*insn_data[icode].operand[3].predicate) (op2, mode2))
11233132718Skan	{
11234132718Skan	  /* @@@ better error message */
11235132718Skan	  error ("selector must be an immediate");
11236132718Skan	  return const0_rtx;
11237132718Skan	}
11238132718Skan      if (target == 0
11239132718Skan	  || GET_MODE (target) != tmode
11240132718Skan	  || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
11241132718Skan	target = gen_reg_rtx (tmode);
11242132718Skan      pat = GEN_FCN (icode) (target, op0, op1, op2);
11243132718Skan      if (! pat)
11244132718Skan	return 0;
11245132718Skan      emit_insn (pat);
11246132718Skan      return target;
11247132718Skan
11248132718Skan    case ARM_BUILTIN_SETWCX:
11249132718Skan      arg0 = TREE_VALUE (arglist);
11250132718Skan      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
11251132718Skan      op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
11252132718Skan      op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
11253132718Skan      emit_insn (gen_iwmmxt_tmcr (op0, op1));
11254132718Skan      return 0;
11255132718Skan
11256132718Skan    case ARM_BUILTIN_GETWCX:
11257132718Skan      arg0 = TREE_VALUE (arglist);
11258132718Skan      op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
11259132718Skan      target = gen_reg_rtx (SImode);
11260132718Skan      emit_insn (gen_iwmmxt_tmrc (target, op0));
11261132718Skan      return target;
11262132718Skan
11263132718Skan    case ARM_BUILTIN_WSHUFH:
11264132718Skan      icode = CODE_FOR_iwmmxt_wshufh;
11265132718Skan      arg0 = TREE_VALUE (arglist);
11266132718Skan      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
11267132718Skan      op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
11268132718Skan      op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
11269132718Skan      tmode = insn_data[icode].operand[0].mode;
11270132718Skan      mode1 = insn_data[icode].operand[1].mode;
11271132718Skan      mode2 = insn_data[icode].operand[2].mode;
11272132718Skan
11273132718Skan      if (! (*insn_data[icode].operand[1].predicate) (op0, mode1))
11274132718Skan	op0 = copy_to_mode_reg (mode1, op0);
11275132718Skan      if (! (*insn_data[icode].operand[2].predicate) (op1, mode2))
11276132718Skan	{
11277132718Skan	  /* @@@ better error message */
11278132718Skan	  error ("mask must be an immediate");
11279132718Skan	  return const0_rtx;
11280132718Skan	}
11281132718Skan      if (target == 0
11282132718Skan	  || GET_MODE (target) != tmode
11283132718Skan	  || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
11284132718Skan	target = gen_reg_rtx (tmode);
11285132718Skan      pat = GEN_FCN (icode) (target, op0, op1);
11286132718Skan      if (! pat)
11287132718Skan	return 0;
11288132718Skan      emit_insn (pat);
11289132718Skan      return target;
11290132718Skan
11291132718Skan    case ARM_BUILTIN_WSADB:
11292132718Skan      return arm_expand_binop_builtin (CODE_FOR_iwmmxt_wsadb, arglist, target);
11293132718Skan    case ARM_BUILTIN_WSADH:
11294132718Skan      return arm_expand_binop_builtin (CODE_FOR_iwmmxt_wsadh, arglist, target);
11295132718Skan    case ARM_BUILTIN_WSADBZ:
11296132718Skan      return arm_expand_binop_builtin (CODE_FOR_iwmmxt_wsadbz, arglist, target);
11297132718Skan    case ARM_BUILTIN_WSADHZ:
11298132718Skan      return arm_expand_binop_builtin (CODE_FOR_iwmmxt_wsadhz, arglist, target);
11299132718Skan
11300132718Skan      /* Several three-argument builtins.  */
11301132718Skan    case ARM_BUILTIN_WMACS:
11302132718Skan    case ARM_BUILTIN_WMACU:
11303132718Skan    case ARM_BUILTIN_WALIGN:
11304132718Skan    case ARM_BUILTIN_TMIA:
11305132718Skan    case ARM_BUILTIN_TMIAPH:
11306132718Skan    case ARM_BUILTIN_TMIATT:
11307132718Skan    case ARM_BUILTIN_TMIATB:
11308132718Skan    case ARM_BUILTIN_TMIABT:
11309132718Skan    case ARM_BUILTIN_TMIABB:
11310132718Skan      icode = (fcode == ARM_BUILTIN_WMACS ? CODE_FOR_iwmmxt_wmacs
11311132718Skan	       : fcode == ARM_BUILTIN_WMACU ? CODE_FOR_iwmmxt_wmacu
11312132718Skan	       : fcode == ARM_BUILTIN_TMIA ? CODE_FOR_iwmmxt_tmia
11313132718Skan	       : fcode == ARM_BUILTIN_TMIAPH ? CODE_FOR_iwmmxt_tmiaph
11314132718Skan	       : fcode == ARM_BUILTIN_TMIABB ? CODE_FOR_iwmmxt_tmiabb
11315132718Skan	       : fcode == ARM_BUILTIN_TMIABT ? CODE_FOR_iwmmxt_tmiabt
11316132718Skan	       : fcode == ARM_BUILTIN_TMIATB ? CODE_FOR_iwmmxt_tmiatb
11317132718Skan	       : fcode == ARM_BUILTIN_TMIATT ? CODE_FOR_iwmmxt_tmiatt
11318132718Skan	       : CODE_FOR_iwmmxt_walign);
11319132718Skan      arg0 = TREE_VALUE (arglist);
11320132718Skan      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
11321132718Skan      arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
11322132718Skan      op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
11323132718Skan      op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
11324132718Skan      op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
11325132718Skan      tmode = insn_data[icode].operand[0].mode;
11326132718Skan      mode0 = insn_data[icode].operand[1].mode;
11327132718Skan      mode1 = insn_data[icode].operand[2].mode;
11328132718Skan      mode2 = insn_data[icode].operand[3].mode;
11329132718Skan
11330132718Skan      if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
11331132718Skan	op0 = copy_to_mode_reg (mode0, op0);
11332132718Skan      if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
11333132718Skan	op1 = copy_to_mode_reg (mode1, op1);
11334132718Skan      if (! (*insn_data[icode].operand[3].predicate) (op2, mode2))
11335132718Skan	op2 = copy_to_mode_reg (mode2, op2);
11336132718Skan      if (target == 0
11337132718Skan	  || GET_MODE (target) != tmode
11338132718Skan	  || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
11339132718Skan	target = gen_reg_rtx (tmode);
11340132718Skan      pat = GEN_FCN (icode) (target, op0, op1, op2);
11341132718Skan      if (! pat)
11342132718Skan	return 0;
11343132718Skan      emit_insn (pat);
11344132718Skan      return target;
11345132718Skan
11346132718Skan    case ARM_BUILTIN_WZERO:
11347132718Skan      target = gen_reg_rtx (DImode);
11348132718Skan      emit_insn (gen_iwmmxt_clrdi (target));
11349132718Skan      return target;
11350132718Skan
11351132718Skan    default:
11352132718Skan      break;
1135390075Sobrien    }
11354117395Skan
11355132718Skan  for (i = 0, d = bdesc_2arg; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
11356132718Skan    if (d->code == (const enum arm_builtins) fcode)
11357132718Skan      return arm_expand_binop_builtin (d->icode, arglist, target);
11358132718Skan
11359132718Skan  for (i = 0, d = bdesc_1arg; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
11360132718Skan    if (d->code == (const enum arm_builtins) fcode)
11361132718Skan      return arm_expand_unop_builtin (d->icode, arglist, target, 0);
11362132718Skan
1136390075Sobrien  /* @@@ Should really do something sensible here.  */
1136490075Sobrien  return NULL_RTX;
1136590075Sobrien}
1136690075Sobrien
1136790075Sobrien/* Recursively search through all of the blocks in a function
1136890075Sobrien   checking to see if any of the variables created in that
1136990075Sobrien   function match the RTX called 'orig'.  If they do then
1137090075Sobrien   replace them with the RTX called 'new'.  */
1137190075Sobrienstatic void
11372132718Skanreplace_symbols_in_block (tree block, rtx orig, rtx new)
1137390075Sobrien{
1137490075Sobrien  for (; block; block = BLOCK_CHAIN (block))
1137590075Sobrien    {
1137690075Sobrien      tree sym;
1137790075Sobrien
1137890075Sobrien      if (!TREE_USED (block))
1137990075Sobrien	continue;
1138090075Sobrien
1138190075Sobrien      for (sym = BLOCK_VARS (block); sym; sym = TREE_CHAIN (sym))
1138290075Sobrien	{
1138390075Sobrien	  if (  (DECL_NAME (sym) == 0 && TREE_CODE (sym) != TYPE_DECL)
1138490075Sobrien	      || DECL_IGNORED_P (sym)
1138590075Sobrien	      || TREE_CODE (sym) != VAR_DECL
1138690075Sobrien	      || DECL_EXTERNAL (sym)
1138790075Sobrien	      || !rtx_equal_p (DECL_RTL (sym), orig)
1138890075Sobrien	      )
1138990075Sobrien	    continue;
1139090075Sobrien
1139190075Sobrien	  SET_DECL_RTL (sym, new);
1139290075Sobrien	}
1139390075Sobrien
1139490075Sobrien      replace_symbols_in_block (BLOCK_SUBBLOCKS (block), orig, new);
1139590075Sobrien    }
1139690075Sobrien}
1139790075Sobrien
1139890075Sobrien/* Return the number (counting from 0) of
1139990075Sobrien   the least significant set bit in MASK.  */
1140090075Sobrien
11401132718Skaninline static int
11402132718Skannumber_of_first_bit_set (int mask)
1140390075Sobrien{
1140490075Sobrien  int bit;
1140590075Sobrien
1140690075Sobrien  for (bit = 0;
1140790075Sobrien       (mask & (1 << bit)) == 0;
1140890075Sobrien       ++bit)
1140990075Sobrien    continue;
1141090075Sobrien
1141190075Sobrien  return bit;
1141290075Sobrien}
1141390075Sobrien
1141490075Sobrien/* Generate code to return from a thumb function.
1141590075Sobrien   If 'reg_containing_return_addr' is -1, then the return address is
1141690075Sobrien   actually on the stack, at the stack pointer.  */
1141790075Sobrienstatic void
11418132718Skanthumb_exit (FILE *f, int reg_containing_return_addr, rtx eh_ofs)
1141990075Sobrien{
1142090075Sobrien  unsigned regs_available_for_popping;
1142190075Sobrien  unsigned regs_to_pop;
1142290075Sobrien  int pops_needed;
1142390075Sobrien  unsigned available;
1142490075Sobrien  unsigned required;
1142590075Sobrien  int mode;
1142690075Sobrien  int size;
1142790075Sobrien  int restore_a4 = FALSE;
1142890075Sobrien
1142990075Sobrien  /* Compute the registers we need to pop.  */
1143090075Sobrien  regs_to_pop = 0;
1143190075Sobrien  pops_needed = 0;
1143290075Sobrien
1143390075Sobrien  /* There is an assumption here, that if eh_ofs is not NULL, the
1143490075Sobrien     normal return address will have been pushed.  */
1143590075Sobrien  if (reg_containing_return_addr == -1 || eh_ofs)
1143690075Sobrien    {
1143790075Sobrien      /* When we are generating a return for __builtin_eh_return,
1143890075Sobrien	 reg_containing_return_addr must specify the return regno.  */
1143990075Sobrien      if (eh_ofs && reg_containing_return_addr == -1)
1144090075Sobrien	abort ();
1144190075Sobrien
1144290075Sobrien      regs_to_pop |= 1 << LR_REGNUM;
1144390075Sobrien      ++pops_needed;
1144490075Sobrien    }
1144590075Sobrien
1144690075Sobrien  if (TARGET_BACKTRACE)
1144790075Sobrien    {
1144890075Sobrien      /* Restore the (ARM) frame pointer and stack pointer.  */
1144990075Sobrien      regs_to_pop |= (1 << ARM_HARD_FRAME_POINTER_REGNUM) | (1 << SP_REGNUM);
1145090075Sobrien      pops_needed += 2;
1145190075Sobrien    }
1145290075Sobrien
1145390075Sobrien  /* If there is nothing to pop then just emit the BX instruction and
1145490075Sobrien     return.  */
1145590075Sobrien  if (pops_needed == 0)
1145690075Sobrien    {
1145790075Sobrien      if (eh_ofs)
1145890075Sobrien	asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, REGNO (eh_ofs));
1145990075Sobrien
1146090075Sobrien      asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
1146190075Sobrien      return;
1146290075Sobrien    }
1146390075Sobrien  /* Otherwise if we are not supporting interworking and we have not created
1146490075Sobrien     a backtrace structure and the function was not entered in ARM mode then
1146590075Sobrien     just pop the return address straight into the PC.  */
1146690075Sobrien  else if (!TARGET_INTERWORK
1146790075Sobrien	   && !TARGET_BACKTRACE
1146890075Sobrien	   && !is_called_in_ARM_mode (current_function_decl))
1146990075Sobrien    {
1147090075Sobrien      if (eh_ofs)
1147190075Sobrien	{
1147290075Sobrien	  asm_fprintf (f, "\tadd\t%r, #4\n", SP_REGNUM);
1147390075Sobrien	  asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, REGNO (eh_ofs));
1147490075Sobrien	  asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
1147590075Sobrien	}
1147690075Sobrien      else
1147790075Sobrien	asm_fprintf (f, "\tpop\t{%r}\n", PC_REGNUM);
1147890075Sobrien
1147990075Sobrien      return;
1148090075Sobrien    }
1148190075Sobrien
1148290075Sobrien  /* Find out how many of the (return) argument registers we can corrupt.  */
1148390075Sobrien  regs_available_for_popping = 0;
1148490075Sobrien
1148590075Sobrien  /* If returning via __builtin_eh_return, the bottom three registers
1148690075Sobrien     all contain information needed for the return.  */
1148790075Sobrien  if (eh_ofs)
1148890075Sobrien    size = 12;
1148990075Sobrien  else
1149090075Sobrien    {
1149190075Sobrien#ifdef RTX_CODE
1149290075Sobrien      /* If we can deduce the registers used from the function's
1149390075Sobrien	 return value.  This is more reliable that examining
1149490075Sobrien	 regs_ever_live[] because that will be set if the register is
1149590075Sobrien	 ever used in the function, not just if the register is used
1149690075Sobrien	 to hold a return value.  */
1149790075Sobrien
1149890075Sobrien      if (current_function_return_rtx != 0)
1149990075Sobrien	mode = GET_MODE (current_function_return_rtx);
1150090075Sobrien      else
1150190075Sobrien#endif
1150290075Sobrien	mode = DECL_MODE (DECL_RESULT (current_function_decl));
1150390075Sobrien
1150490075Sobrien      size = GET_MODE_SIZE (mode);
1150590075Sobrien
1150690075Sobrien      if (size == 0)
1150790075Sobrien	{
1150890075Sobrien	  /* In a void function we can use any argument register.
1150990075Sobrien	     In a function that returns a structure on the stack
1151090075Sobrien	     we can use the second and third argument registers.  */
1151190075Sobrien	  if (mode == VOIDmode)
1151290075Sobrien	    regs_available_for_popping =
1151390075Sobrien	      (1 << ARG_REGISTER (1))
1151490075Sobrien	      | (1 << ARG_REGISTER (2))
1151590075Sobrien	      | (1 << ARG_REGISTER (3));
1151690075Sobrien	  else
1151790075Sobrien	    regs_available_for_popping =
1151890075Sobrien	      (1 << ARG_REGISTER (2))
1151990075Sobrien	      | (1 << ARG_REGISTER (3));
1152090075Sobrien	}
1152190075Sobrien      else if (size <= 4)
1152290075Sobrien	regs_available_for_popping =
1152390075Sobrien	  (1 << ARG_REGISTER (2))
1152490075Sobrien	  | (1 << ARG_REGISTER (3));
1152590075Sobrien      else if (size <= 8)
1152690075Sobrien	regs_available_for_popping =
1152790075Sobrien	  (1 << ARG_REGISTER (3));
1152890075Sobrien    }
1152990075Sobrien
1153090075Sobrien  /* Match registers to be popped with registers into which we pop them.  */
1153190075Sobrien  for (available = regs_available_for_popping,
1153290075Sobrien       required  = regs_to_pop;
1153390075Sobrien       required != 0 && available != 0;
1153490075Sobrien       available &= ~(available & - available),
1153590075Sobrien       required  &= ~(required  & - required))
1153690075Sobrien    -- pops_needed;
1153790075Sobrien
1153890075Sobrien  /* If we have any popping registers left over, remove them.  */
1153990075Sobrien  if (available > 0)
1154090075Sobrien    regs_available_for_popping &= ~available;
1154190075Sobrien
1154290075Sobrien  /* Otherwise if we need another popping register we can use
1154390075Sobrien     the fourth argument register.  */
1154490075Sobrien  else if (pops_needed)
1154590075Sobrien    {
1154690075Sobrien      /* If we have not found any free argument registers and
1154790075Sobrien	 reg a4 contains the return address, we must move it.  */
1154890075Sobrien      if (regs_available_for_popping == 0
1154990075Sobrien	  && reg_containing_return_addr == LAST_ARG_REGNUM)
1155090075Sobrien	{
1155190075Sobrien	  asm_fprintf (f, "\tmov\t%r, %r\n", LR_REGNUM, LAST_ARG_REGNUM);
1155290075Sobrien	  reg_containing_return_addr = LR_REGNUM;
1155390075Sobrien	}
1155490075Sobrien      else if (size > 12)
1155590075Sobrien	{
1155690075Sobrien	  /* Register a4 is being used to hold part of the return value,
1155790075Sobrien	     but we have dire need of a free, low register.  */
1155890075Sobrien	  restore_a4 = TRUE;
1155990075Sobrien
1156090075Sobrien	  asm_fprintf (f, "\tmov\t%r, %r\n",IP_REGNUM, LAST_ARG_REGNUM);
1156190075Sobrien	}
1156290075Sobrien
1156390075Sobrien      if (reg_containing_return_addr != LAST_ARG_REGNUM)
1156490075Sobrien	{
1156590075Sobrien	  /* The fourth argument register is available.  */
1156690075Sobrien	  regs_available_for_popping |= 1 << LAST_ARG_REGNUM;
1156790075Sobrien
1156890075Sobrien	  --pops_needed;
1156990075Sobrien	}
1157090075Sobrien    }
1157190075Sobrien
1157290075Sobrien  /* Pop as many registers as we can.  */
11573132718Skan  thumb_pushpop (f, regs_available_for_popping, FALSE, NULL,
11574132718Skan		 regs_available_for_popping);
1157590075Sobrien
1157690075Sobrien  /* Process the registers we popped.  */
1157790075Sobrien  if (reg_containing_return_addr == -1)
1157890075Sobrien    {
1157990075Sobrien      /* The return address was popped into the lowest numbered register.  */
1158090075Sobrien      regs_to_pop &= ~(1 << LR_REGNUM);
1158190075Sobrien
1158290075Sobrien      reg_containing_return_addr =
1158390075Sobrien	number_of_first_bit_set (regs_available_for_popping);
1158490075Sobrien
1158590075Sobrien      /* Remove this register for the mask of available registers, so that
11586132718Skan         the return address will not be corrupted by further pops.  */
1158790075Sobrien      regs_available_for_popping &= ~(1 << reg_containing_return_addr);
1158890075Sobrien    }
1158990075Sobrien
1159090075Sobrien  /* If we popped other registers then handle them here.  */
1159190075Sobrien  if (regs_available_for_popping)
1159290075Sobrien    {
1159390075Sobrien      int frame_pointer;
1159490075Sobrien
1159590075Sobrien      /* Work out which register currently contains the frame pointer.  */
1159690075Sobrien      frame_pointer = number_of_first_bit_set (regs_available_for_popping);
1159790075Sobrien
1159890075Sobrien      /* Move it into the correct place.  */
1159990075Sobrien      asm_fprintf (f, "\tmov\t%r, %r\n",
1160090075Sobrien		   ARM_HARD_FRAME_POINTER_REGNUM, frame_pointer);
1160190075Sobrien
1160290075Sobrien      /* (Temporarily) remove it from the mask of popped registers.  */
1160390075Sobrien      regs_available_for_popping &= ~(1 << frame_pointer);
1160490075Sobrien      regs_to_pop &= ~(1 << ARM_HARD_FRAME_POINTER_REGNUM);
1160590075Sobrien
1160690075Sobrien      if (regs_available_for_popping)
1160790075Sobrien	{
1160890075Sobrien	  int stack_pointer;
1160990075Sobrien
1161090075Sobrien	  /* We popped the stack pointer as well,
1161190075Sobrien	     find the register that contains it.  */
1161290075Sobrien	  stack_pointer = number_of_first_bit_set (regs_available_for_popping);
1161390075Sobrien
1161490075Sobrien	  /* Move it into the stack register.  */
1161590075Sobrien	  asm_fprintf (f, "\tmov\t%r, %r\n", SP_REGNUM, stack_pointer);
1161690075Sobrien
1161790075Sobrien	  /* At this point we have popped all necessary registers, so
1161890075Sobrien	     do not worry about restoring regs_available_for_popping
1161990075Sobrien	     to its correct value:
1162090075Sobrien
1162190075Sobrien	     assert (pops_needed == 0)
1162290075Sobrien	     assert (regs_available_for_popping == (1 << frame_pointer))
1162390075Sobrien	     assert (regs_to_pop == (1 << STACK_POINTER))  */
1162490075Sobrien	}
1162590075Sobrien      else
1162690075Sobrien	{
1162790075Sobrien	  /* Since we have just move the popped value into the frame
1162890075Sobrien	     pointer, the popping register is available for reuse, and
1162990075Sobrien	     we know that we still have the stack pointer left to pop.  */
1163090075Sobrien	  regs_available_for_popping |= (1 << frame_pointer);
1163190075Sobrien	}
1163290075Sobrien    }
1163390075Sobrien
1163490075Sobrien  /* If we still have registers left on the stack, but we no longer have
1163590075Sobrien     any registers into which we can pop them, then we must move the return
1163690075Sobrien     address into the link register and make available the register that
1163790075Sobrien     contained it.  */
1163890075Sobrien  if (regs_available_for_popping == 0 && pops_needed > 0)
1163990075Sobrien    {
1164090075Sobrien      regs_available_for_popping |= 1 << reg_containing_return_addr;
1164190075Sobrien
1164290075Sobrien      asm_fprintf (f, "\tmov\t%r, %r\n", LR_REGNUM,
1164390075Sobrien		   reg_containing_return_addr);
1164490075Sobrien
1164590075Sobrien      reg_containing_return_addr = LR_REGNUM;
1164690075Sobrien    }
1164790075Sobrien
1164890075Sobrien  /* If we have registers left on the stack then pop some more.
1164990075Sobrien     We know that at most we will want to pop FP and SP.  */
1165090075Sobrien  if (pops_needed > 0)
1165190075Sobrien    {
1165290075Sobrien      int  popped_into;
1165390075Sobrien      int  move_to;
1165490075Sobrien
11655132718Skan      thumb_pushpop (f, regs_available_for_popping, FALSE, NULL,
11656132718Skan		     regs_available_for_popping);
1165790075Sobrien
1165890075Sobrien      /* We have popped either FP or SP.
1165990075Sobrien	 Move whichever one it is into the correct register.  */
1166090075Sobrien      popped_into = number_of_first_bit_set (regs_available_for_popping);
1166190075Sobrien      move_to     = number_of_first_bit_set (regs_to_pop);
1166290075Sobrien
1166390075Sobrien      asm_fprintf (f, "\tmov\t%r, %r\n", move_to, popped_into);
1166490075Sobrien
1166590075Sobrien      regs_to_pop &= ~(1 << move_to);
1166690075Sobrien
1166790075Sobrien      --pops_needed;
1166890075Sobrien    }
1166990075Sobrien
1167090075Sobrien  /* If we still have not popped everything then we must have only
1167190075Sobrien     had one register available to us and we are now popping the SP.  */
1167290075Sobrien  if (pops_needed > 0)
1167390075Sobrien    {
1167490075Sobrien      int  popped_into;
1167590075Sobrien
11676132718Skan      thumb_pushpop (f, regs_available_for_popping, FALSE, NULL,
11677132718Skan		     regs_available_for_popping);
1167890075Sobrien
1167990075Sobrien      popped_into = number_of_first_bit_set (regs_available_for_popping);
1168090075Sobrien
1168190075Sobrien      asm_fprintf (f, "\tmov\t%r, %r\n", SP_REGNUM, popped_into);
1168290075Sobrien      /*
1168390075Sobrien	assert (regs_to_pop == (1 << STACK_POINTER))
1168490075Sobrien	assert (pops_needed == 1)
1168590075Sobrien      */
1168690075Sobrien    }
1168790075Sobrien
1168890075Sobrien  /* If necessary restore the a4 register.  */
1168990075Sobrien  if (restore_a4)
1169090075Sobrien    {
1169190075Sobrien      if (reg_containing_return_addr != LR_REGNUM)
1169290075Sobrien	{
1169390075Sobrien	  asm_fprintf (f, "\tmov\t%r, %r\n", LR_REGNUM, LAST_ARG_REGNUM);
1169490075Sobrien	  reg_containing_return_addr = LR_REGNUM;
1169590075Sobrien	}
1169690075Sobrien
1169790075Sobrien      asm_fprintf (f, "\tmov\t%r, %r\n", LAST_ARG_REGNUM, IP_REGNUM);
1169890075Sobrien    }
1169990075Sobrien
1170090075Sobrien  if (eh_ofs)
1170190075Sobrien    asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, REGNO (eh_ofs));
1170290075Sobrien
1170390075Sobrien  /* Return to caller.  */
1170490075Sobrien  asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
1170590075Sobrien}
1170690075Sobrien
11707132718Skan/* Emit code to push or pop registers to or from the stack.  F is the
11708132718Skan   assembly file.  MASK is the registers to push or pop.  PUSH is
11709132718Skan   non-zero if we should push, and zero if we should pop.  For debugging
11710132718Skan   output, if pushing, adjust CFA_OFFSET by the amount of space added
11711132718Skan   to the stack.  REAL_REGS should have the same number of bits set as
11712132718Skan   MASK, and will be used instead (in the same order) to describe which
11713132718Skan   registers were saved - this is used to mark the save slots when we
11714132718Skan   push high registers after moving them to low registers.  */
1171590075Sobrienstatic void
11716132718Skanthumb_pushpop (FILE *f, int mask, int push, int *cfa_offset, int real_regs)
1171790075Sobrien{
1171890075Sobrien  int regno;
1171990075Sobrien  int lo_mask = mask & 0xFF;
11720132718Skan  int pushed_words = 0;
1172190075Sobrien
1172290075Sobrien  if (lo_mask == 0 && !push && (mask & (1 << 15)))
1172390075Sobrien    {
1172490075Sobrien      /* Special case.  Do not generate a POP PC statement here, do it in
1172590075Sobrien	 thumb_exit() */
1172690075Sobrien      thumb_exit (f, -1, NULL_RTX);
1172790075Sobrien      return;
1172890075Sobrien    }
1172990075Sobrien
1173090075Sobrien  fprintf (f, "\t%s\t{", push ? "push" : "pop");
1173190075Sobrien
1173290075Sobrien  /* Look at the low registers first.  */
1173390075Sobrien  for (regno = 0; regno <= LAST_LO_REGNUM; regno++, lo_mask >>= 1)
1173490075Sobrien    {
1173590075Sobrien      if (lo_mask & 1)
1173690075Sobrien	{
1173790075Sobrien	  asm_fprintf (f, "%r", regno);
1173890075Sobrien
1173990075Sobrien	  if ((lo_mask & ~1) != 0)
1174090075Sobrien	    fprintf (f, ", ");
11741132718Skan
11742132718Skan	  pushed_words++;
1174390075Sobrien	}
1174490075Sobrien    }
1174590075Sobrien
1174690075Sobrien  if (push && (mask & (1 << LR_REGNUM)))
1174790075Sobrien    {
1174890075Sobrien      /* Catch pushing the LR.  */
1174990075Sobrien      if (mask & 0xFF)
1175090075Sobrien	fprintf (f, ", ");
1175190075Sobrien
1175290075Sobrien      asm_fprintf (f, "%r", LR_REGNUM);
11753132718Skan
11754132718Skan      pushed_words++;
1175590075Sobrien    }
1175690075Sobrien  else if (!push && (mask & (1 << PC_REGNUM)))
1175790075Sobrien    {
1175890075Sobrien      /* Catch popping the PC.  */
1175990075Sobrien      if (TARGET_INTERWORK || TARGET_BACKTRACE)
1176090075Sobrien	{
1176190075Sobrien	  /* The PC is never poped directly, instead
1176290075Sobrien	     it is popped into r3 and then BX is used.  */
1176390075Sobrien	  fprintf (f, "}\n");
1176490075Sobrien
1176590075Sobrien	  thumb_exit (f, -1, NULL_RTX);
1176690075Sobrien
1176790075Sobrien	  return;
1176890075Sobrien	}
1176990075Sobrien      else
1177090075Sobrien	{
1177190075Sobrien	  if (mask & 0xFF)
1177290075Sobrien	    fprintf (f, ", ");
1177390075Sobrien
1177490075Sobrien	  asm_fprintf (f, "%r", PC_REGNUM);
1177590075Sobrien	}
1177690075Sobrien    }
1177790075Sobrien
1177890075Sobrien  fprintf (f, "}\n");
11779132718Skan
11780132718Skan  if (push && pushed_words && dwarf2out_do_frame ())
11781132718Skan    {
11782132718Skan      char *l = dwarf2out_cfi_label ();
11783132718Skan      int pushed_mask = real_regs;
11784132718Skan
11785132718Skan      *cfa_offset += pushed_words * 4;
11786132718Skan      dwarf2out_def_cfa (l, SP_REGNUM, *cfa_offset);
11787132718Skan
11788132718Skan      pushed_words = 0;
11789132718Skan      pushed_mask = real_regs;
11790132718Skan      for (regno = 0; regno <= 14; regno++, pushed_mask >>= 1)
11791132718Skan	{
11792132718Skan	  if (pushed_mask & 1)
11793132718Skan	    dwarf2out_reg_save (l, regno, 4 * pushed_words++ - *cfa_offset);
11794132718Skan	}
11795132718Skan    }
1179690075Sobrien}
1179790075Sobrien
1179890075Sobrienvoid
11799132718Skanthumb_final_prescan_insn (rtx insn)
1180090075Sobrien{
1180190075Sobrien  if (flag_print_asm_name)
1180290075Sobrien    asm_fprintf (asm_out_file, "%@ 0x%04x\n",
1180390075Sobrien		 INSN_ADDRESSES (INSN_UID (insn)));
1180490075Sobrien}
1180590075Sobrien
1180690075Sobrienint
11807132718Skanthumb_shiftable_const (unsigned HOST_WIDE_INT val)
1180890075Sobrien{
1180990075Sobrien  unsigned HOST_WIDE_INT mask = 0xff;
1181090075Sobrien  int i;
1181190075Sobrien
1181290075Sobrien  if (val == 0) /* XXX */
1181390075Sobrien    return 0;
1181490075Sobrien
1181590075Sobrien  for (i = 0; i < 25; i++)
1181690075Sobrien    if ((val & (mask << i)) == val)
1181790075Sobrien      return 1;
1181890075Sobrien
1181990075Sobrien  return 0;
1182090075Sobrien}
1182190075Sobrien
11822117395Skan/* Returns nonzero if the current function contains,
1182390075Sobrien   or might contain a far jump.  */
1182490075Sobrienint
11825132718Skanthumb_far_jump_used_p (int in_prologue)
1182690075Sobrien{
1182790075Sobrien  rtx insn;
1182890075Sobrien
1182990075Sobrien  /* This test is only important for leaf functions.  */
1183090075Sobrien  /* assert (!leaf_function_p ()); */
1183190075Sobrien
1183290075Sobrien  /* If we have already decided that far jumps may be used,
1183390075Sobrien     do not bother checking again, and always return true even if
1183490075Sobrien     it turns out that they are not being used.  Once we have made
1183590075Sobrien     the decision that far jumps are present (and that hence the link
1183690075Sobrien     register will be pushed onto the stack) we cannot go back on it.  */
1183790075Sobrien  if (cfun->machine->far_jump_used)
1183890075Sobrien    return 1;
1183990075Sobrien
1184090075Sobrien  /* If this function is not being called from the prologue/epilogue
1184190075Sobrien     generation code then it must be being called from the
1184290075Sobrien     INITIAL_ELIMINATION_OFFSET macro.  */
1184390075Sobrien  if (!in_prologue)
1184490075Sobrien    {
1184590075Sobrien      /* In this case we know that we are being asked about the elimination
1184690075Sobrien	 of the arg pointer register.  If that register is not being used,
1184790075Sobrien	 then there are no arguments on the stack, and we do not have to
1184890075Sobrien	 worry that a far jump might force the prologue to push the link
1184990075Sobrien	 register, changing the stack offsets.  In this case we can just
1185090075Sobrien	 return false, since the presence of far jumps in the function will
1185190075Sobrien	 not affect stack offsets.
1185290075Sobrien
1185390075Sobrien	 If the arg pointer is live (or if it was live, but has now been
1185490075Sobrien	 eliminated and so set to dead) then we do have to test to see if
1185590075Sobrien	 the function might contain a far jump.  This test can lead to some
1185690075Sobrien	 false negatives, since before reload is completed, then length of
1185790075Sobrien	 branch instructions is not known, so gcc defaults to returning their
1185890075Sobrien	 longest length, which in turn sets the far jump attribute to true.
1185990075Sobrien
1186090075Sobrien	 A false negative will not result in bad code being generated, but it
1186190075Sobrien	 will result in a needless push and pop of the link register.  We
1186290075Sobrien	 hope that this does not occur too often.  */
1186390075Sobrien      if (regs_ever_live [ARG_POINTER_REGNUM])
1186490075Sobrien	cfun->machine->arg_pointer_live = 1;
1186590075Sobrien      else if (!cfun->machine->arg_pointer_live)
1186690075Sobrien	return 0;
1186790075Sobrien    }
1186890075Sobrien
1186990075Sobrien  /* Check to see if the function contains a branch
1187090075Sobrien     insn with the far jump attribute set.  */
1187190075Sobrien  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
1187290075Sobrien    {
1187390075Sobrien      if (GET_CODE (insn) == JUMP_INSN
1187490075Sobrien	  /* Ignore tablejump patterns.  */
1187590075Sobrien	  && GET_CODE (PATTERN (insn)) != ADDR_VEC
1187690075Sobrien	  && GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC
1187790075Sobrien	  && get_attr_far_jump (insn) == FAR_JUMP_YES
1187890075Sobrien	  )
1187990075Sobrien	{
11880132718Skan	  /* Record the fact that we have decided that
1188190075Sobrien	     the function does use far jumps.  */
1188290075Sobrien	  cfun->machine->far_jump_used = 1;
1188390075Sobrien	  return 1;
1188490075Sobrien	}
1188590075Sobrien    }
1188690075Sobrien
1188790075Sobrien  return 0;
1188890075Sobrien}
1188990075Sobrien
11890117395Skan/* Return nonzero if FUNC must be entered in ARM mode.  */
1189190075Sobrienint
11892132718Skanis_called_in_ARM_mode (tree func)
1189390075Sobrien{
1189490075Sobrien  if (TREE_CODE (func) != FUNCTION_DECL)
1189590075Sobrien    abort ();
1189690075Sobrien
1189790075Sobrien  /* Ignore the problem about functions whoes address is taken.  */
1189890075Sobrien  if (TARGET_CALLEE_INTERWORKING && TREE_PUBLIC (func))
1189990075Sobrien    return TRUE;
1190090075Sobrien
1190190075Sobrien#ifdef ARM_PE
1190290075Sobrien  return lookup_attribute ("interfacearm", DECL_ATTRIBUTES (func)) != NULL_TREE;
1190390075Sobrien#else
1190490075Sobrien  return FALSE;
1190590075Sobrien#endif
1190690075Sobrien}
1190790075Sobrien
11908132718Skan/* The bits which aren't usefully expanded as rtl.  */
1190990075Sobrienconst char *
11910132718Skanthumb_unexpanded_epilogue (void)
1191190075Sobrien{
1191290075Sobrien  int regno;
1191390075Sobrien  int live_regs_mask = 0;
1191490075Sobrien  int high_regs_pushed = 0;
1191590075Sobrien  int leaf_function = leaf_function_p ();
1191690075Sobrien  int had_to_push_lr;
1191790075Sobrien  rtx eh_ofs = cfun->machine->eh_epilogue_sp_ofs;
1191890075Sobrien
1191990075Sobrien  if (return_used_this_function)
1192090075Sobrien    return "";
1192190075Sobrien
11922117395Skan  if (IS_NAKED (arm_current_func_type ()))
11923117395Skan    return "";
11924117395Skan
1192590075Sobrien  for (regno = 0; regno <= LAST_LO_REGNUM; regno++)
11926117395Skan    if (THUMB_REG_PUSHED_P (regno))
1192790075Sobrien      live_regs_mask |= 1 << regno;
1192890075Sobrien
1192990075Sobrien  for (regno = 8; regno < 13; regno++)
11930117395Skan    if (THUMB_REG_PUSHED_P (regno))
11931117395Skan      high_regs_pushed++;
1193290075Sobrien
1193390075Sobrien  /* The prolog may have pushed some high registers to use as
11934132718Skan     work registers.  eg the testsuite file:
1193590075Sobrien     gcc/testsuite/gcc/gcc.c-torture/execute/complex-2.c
1193690075Sobrien     compiles to produce:
1193790075Sobrien	push	{r4, r5, r6, r7, lr}
1193890075Sobrien	mov	r7, r9
1193990075Sobrien	mov	r6, r8
1194090075Sobrien	push	{r6, r7}
1194190075Sobrien     as part of the prolog.  We have to undo that pushing here.  */
1194290075Sobrien
1194390075Sobrien  if (high_regs_pushed)
1194490075Sobrien    {
1194590075Sobrien      int mask = live_regs_mask;
1194690075Sobrien      int next_hi_reg;
1194790075Sobrien      int size;
1194890075Sobrien      int mode;
1194990075Sobrien
1195090075Sobrien#ifdef RTX_CODE
1195190075Sobrien      /* If we can deduce the registers used from the function's return value.
1195290075Sobrien	 This is more reliable that examining regs_ever_live[] because that
1195390075Sobrien	 will be set if the register is ever used in the function, not just if
1195490075Sobrien	 the register is used to hold a return value.  */
1195590075Sobrien
1195690075Sobrien      if (current_function_return_rtx != 0)
1195790075Sobrien	mode = GET_MODE (current_function_return_rtx);
1195890075Sobrien      else
1195990075Sobrien#endif
1196090075Sobrien	mode = DECL_MODE (DECL_RESULT (current_function_decl));
1196190075Sobrien
1196290075Sobrien      size = GET_MODE_SIZE (mode);
1196390075Sobrien
1196490075Sobrien      /* Unless we are returning a type of size > 12 register r3 is
1196590075Sobrien         available.  */
1196690075Sobrien      if (size < 13)
1196790075Sobrien	mask |=  1 << 3;
1196890075Sobrien
1196990075Sobrien      if (mask == 0)
1197090075Sobrien	/* Oh dear!  We have no low registers into which we can pop
1197190075Sobrien           high registers!  */
1197290075Sobrien	internal_error
1197390075Sobrien	  ("no low registers available for popping high registers");
1197490075Sobrien
1197590075Sobrien      for (next_hi_reg = 8; next_hi_reg < 13; next_hi_reg++)
11976117395Skan	if (THUMB_REG_PUSHED_P (next_hi_reg))
1197790075Sobrien	  break;
1197890075Sobrien
1197990075Sobrien      while (high_regs_pushed)
1198090075Sobrien	{
1198190075Sobrien	  /* Find lo register(s) into which the high register(s) can
1198290075Sobrien             be popped.  */
1198390075Sobrien	  for (regno = 0; regno <= LAST_LO_REGNUM; regno++)
1198490075Sobrien	    {
1198590075Sobrien	      if (mask & (1 << regno))
1198690075Sobrien		high_regs_pushed--;
1198790075Sobrien	      if (high_regs_pushed == 0)
1198890075Sobrien		break;
1198990075Sobrien	    }
1199090075Sobrien
1199190075Sobrien	  mask &= (2 << regno) - 1;	/* A noop if regno == 8 */
1199290075Sobrien
11993132718Skan	  /* Pop the values into the low register(s).  */
11994132718Skan	  thumb_pushpop (asm_out_file, mask, 0, NULL, mask);
1199590075Sobrien
1199690075Sobrien	  /* Move the value(s) into the high registers.  */
1199790075Sobrien	  for (regno = 0; regno <= LAST_LO_REGNUM; regno++)
1199890075Sobrien	    {
1199990075Sobrien	      if (mask & (1 << regno))
1200090075Sobrien		{
1200190075Sobrien		  asm_fprintf (asm_out_file, "\tmov\t%r, %r\n", next_hi_reg,
1200290075Sobrien			       regno);
1200390075Sobrien
1200490075Sobrien		  for (next_hi_reg++; next_hi_reg < 13; next_hi_reg++)
12005117395Skan		    if (THUMB_REG_PUSHED_P (next_hi_reg))
1200690075Sobrien		      break;
1200790075Sobrien		}
1200890075Sobrien	    }
1200990075Sobrien	}
1201090075Sobrien    }
1201190075Sobrien
1201290075Sobrien  had_to_push_lr = (live_regs_mask || !leaf_function
1201390075Sobrien		    || thumb_far_jump_used_p (1));
1201490075Sobrien
1201590075Sobrien  if (TARGET_BACKTRACE
1201690075Sobrien      && ((live_regs_mask & 0xFF) == 0)
1201790075Sobrien      && regs_ever_live [LAST_ARG_REGNUM] != 0)
1201890075Sobrien    {
1201990075Sobrien      /* The stack backtrace structure creation code had to
1202090075Sobrien	 push R7 in order to get a work register, so we pop
12021132718Skan	 it now.  */
1202290075Sobrien      live_regs_mask |= (1 << LAST_LO_REGNUM);
1202390075Sobrien    }
1202490075Sobrien
1202590075Sobrien  if (current_function_pretend_args_size == 0 || TARGET_BACKTRACE)
1202690075Sobrien    {
1202790075Sobrien      if (had_to_push_lr
1202890075Sobrien	  && !is_called_in_ARM_mode (current_function_decl)
1202990075Sobrien	  && !eh_ofs)
1203090075Sobrien	live_regs_mask |= 1 << PC_REGNUM;
1203190075Sobrien
1203290075Sobrien      /* Either no argument registers were pushed or a backtrace
1203390075Sobrien	 structure was created which includes an adjusted stack
1203490075Sobrien	 pointer, so just pop everything.  */
1203590075Sobrien      if (live_regs_mask)
12036132718Skan	thumb_pushpop (asm_out_file, live_regs_mask, FALSE, NULL,
12037132718Skan		       live_regs_mask);
1203890075Sobrien
1203990075Sobrien      if (eh_ofs)
1204090075Sobrien	thumb_exit (asm_out_file, 2, eh_ofs);
1204190075Sobrien      /* We have either just popped the return address into the
1204290075Sobrien	 PC or it is was kept in LR for the entire function or
1204390075Sobrien	 it is still on the stack because we do not want to
1204490075Sobrien	 return by doing a pop {pc}.  */
1204590075Sobrien      else if ((live_regs_mask & (1 << PC_REGNUM)) == 0)
1204690075Sobrien	thumb_exit (asm_out_file,
1204790075Sobrien		    (had_to_push_lr
1204890075Sobrien		     && is_called_in_ARM_mode (current_function_decl)) ?
1204990075Sobrien		    -1 : LR_REGNUM, NULL_RTX);
1205090075Sobrien    }
1205190075Sobrien  else
1205290075Sobrien    {
1205390075Sobrien      /* Pop everything but the return address.  */
1205490075Sobrien      live_regs_mask &= ~(1 << PC_REGNUM);
1205590075Sobrien
1205690075Sobrien      if (live_regs_mask)
12057132718Skan	thumb_pushpop (asm_out_file, live_regs_mask, FALSE, NULL,
12058132718Skan		       live_regs_mask);
1205990075Sobrien
1206090075Sobrien      if (had_to_push_lr)
1206190075Sobrien	/* Get the return address into a temporary register.  */
12062132718Skan	thumb_pushpop (asm_out_file, 1 << LAST_ARG_REGNUM, 0, NULL,
12063132718Skan		       1 << LAST_ARG_REGNUM);
1206490075Sobrien
1206590075Sobrien      /* Remove the argument registers that were pushed onto the stack.  */
1206690075Sobrien      asm_fprintf (asm_out_file, "\tadd\t%r, %r, #%d\n",
1206790075Sobrien		   SP_REGNUM, SP_REGNUM,
1206890075Sobrien		   current_function_pretend_args_size);
1206990075Sobrien
1207090075Sobrien      if (eh_ofs)
1207190075Sobrien	thumb_exit (asm_out_file, 2, eh_ofs);
1207290075Sobrien      else
1207390075Sobrien	thumb_exit (asm_out_file,
1207490075Sobrien		    had_to_push_lr ? LAST_ARG_REGNUM : LR_REGNUM, NULL_RTX);
1207590075Sobrien    }
1207690075Sobrien
1207790075Sobrien  return "";
1207890075Sobrien}
1207990075Sobrien
1208090075Sobrien/* Functions to save and restore machine-specific function data.  */
12081117395Skanstatic struct machine_function *
12082132718Skanarm_init_machine_status (void)
1208390075Sobrien{
12084117395Skan  struct machine_function *machine;
12085117395Skan  machine = (machine_function *) ggc_alloc_cleared (sizeof (machine_function));
1208690075Sobrien
12087117395Skan#if ARM_FT_UNKNOWN != 0
12088117395Skan  machine->func_type = ARM_FT_UNKNOWN;
1208990075Sobrien#endif
12090117395Skan  return machine;
1209190075Sobrien}
1209290075Sobrien
1209390075Sobrien/* Return an RTX indicating where the return address to the
1209490075Sobrien   calling function can be found.  */
1209590075Sobrienrtx
12096132718Skanarm_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
1209790075Sobrien{
1209890075Sobrien  if (count != 0)
1209990075Sobrien    return NULL_RTX;
1210090075Sobrien
1210190075Sobrien  if (TARGET_APCS_32)
1210290075Sobrien    return get_hard_reg_initial_val (Pmode, LR_REGNUM);
1210390075Sobrien  else
1210490075Sobrien    {
1210590075Sobrien      rtx lr = gen_rtx_AND (Pmode, gen_rtx_REG (Pmode, LR_REGNUM),
1210690075Sobrien			    GEN_INT (RETURN_ADDR_MASK26));
1210790075Sobrien      return get_func_hard_reg_initial_val (cfun, lr);
1210890075Sobrien    }
1210990075Sobrien}
1211090075Sobrien
1211190075Sobrien/* Do anything needed before RTL is emitted for each function.  */
1211290075Sobrienvoid
12113132718Skanarm_init_expanders (void)
1211490075Sobrien{
1211590075Sobrien  /* Arrange to initialize and mark the machine per-function status.  */
1211690075Sobrien  init_machine_status = arm_init_machine_status;
1211790075Sobrien}
1211890075Sobrien
12119117395SkanHOST_WIDE_INT
12120132718Skanthumb_get_frame_size (void)
12121117395Skan{
12122117395Skan  int regno;
12123117395Skan
12124132718Skan  int base_size = ROUND_UP_WORD (get_frame_size ());
12125117395Skan  int count_regs = 0;
12126117395Skan  int entry_size = 0;
12127117395Skan  int leaf;
12128117395Skan
12129117395Skan  if (! TARGET_THUMB)
12130117395Skan    abort ();
12131117395Skan
12132117395Skan  if (! TARGET_ATPCS)
12133117395Skan    return base_size;
12134117395Skan
12135117395Skan  /* We need to know if we are a leaf function.  Unfortunately, it
12136117395Skan     is possible to be called after start_sequence has been called,
12137117395Skan     which causes get_insns to return the insns for the sequence,
12138117395Skan     not the function, which will cause leaf_function_p to return
12139117395Skan     the incorrect result.
12140117395Skan
12141117395Skan     To work around this, we cache the computed frame size.  This
12142117395Skan     works because we will only be calling RTL expanders that need
12143117395Skan     to know about leaf functions once reload has completed, and the
12144117395Skan     frame size cannot be changed after that time, so we can safely
12145117395Skan     use the cached value.  */
12146117395Skan
12147117395Skan  if (reload_completed)
12148117395Skan    return cfun->machine->frame_size;
12149117395Skan
12150117395Skan  leaf = leaf_function_p ();
12151117395Skan
12152117395Skan  /* A leaf function does not need any stack alignment if it has nothing
12153117395Skan     on the stack.  */
12154117395Skan  if (leaf && base_size == 0)
12155117395Skan    {
12156117395Skan      cfun->machine->frame_size = 0;
12157117395Skan      return 0;
12158117395Skan    }
12159117395Skan
12160117395Skan  /* We know that SP will be word aligned on entry, and we must
12161117395Skan     preserve that condition at any subroutine call.  But those are
12162117395Skan     the only constraints.  */
12163117395Skan
12164117395Skan  /* Space for variadic functions.  */
12165117395Skan  if (current_function_pretend_args_size)
12166117395Skan    entry_size += current_function_pretend_args_size;
12167117395Skan
12168117395Skan  /* Space for pushed lo registers.  */
12169117395Skan  for (regno = 0; regno <= LAST_LO_REGNUM; regno++)
12170117395Skan    if (THUMB_REG_PUSHED_P (regno))
12171117395Skan      count_regs++;
12172117395Skan
12173117395Skan  /* Space for backtrace structure.  */
12174117395Skan  if (TARGET_BACKTRACE)
12175117395Skan    {
12176117395Skan      if (count_regs == 0 && regs_ever_live[LAST_ARG_REGNUM] != 0)
12177117395Skan	entry_size += 20;
12178117395Skan      else
12179117395Skan	entry_size += 16;
12180117395Skan    }
12181117395Skan
12182117395Skan  if (count_regs || !leaf || thumb_far_jump_used_p (1))
12183117395Skan    count_regs++;	/* LR */
12184117395Skan
12185117395Skan  entry_size += count_regs * 4;
12186117395Skan  count_regs = 0;
12187117395Skan
12188117395Skan  /* Space for pushed hi regs.  */
12189117395Skan  for (regno = 8; regno < 13; regno++)
12190117395Skan    if (THUMB_REG_PUSHED_P (regno))
12191117395Skan      count_regs++;
12192117395Skan
12193117395Skan  entry_size += count_regs * 4;
12194117395Skan
12195117395Skan  if ((entry_size + base_size + current_function_outgoing_args_size) & 7)
12196117395Skan    base_size += 4;
12197117395Skan  if ((entry_size + base_size + current_function_outgoing_args_size) & 7)
12198117395Skan    abort ();
12199117395Skan
12200117395Skan  cfun->machine->frame_size = base_size;
12201117395Skan
12202117395Skan  return base_size;
12203117395Skan}
12204117395Skan
1220590075Sobrien/* Generate the rest of a function's prologue.  */
1220690075Sobrienvoid
12207132718Skanthumb_expand_prologue (void)
1220890075Sobrien{
12209132718Skan  rtx insn, dwarf;
12210132718Skan
12211117395Skan  HOST_WIDE_INT amount = (thumb_get_frame_size ()
1221290075Sobrien			  + current_function_outgoing_args_size);
1221390075Sobrien  unsigned long func_type;
1221490075Sobrien
1221590075Sobrien  func_type = arm_current_func_type ();
1221690075Sobrien
1221790075Sobrien  /* Naked functions don't have prologues.  */
1221890075Sobrien  if (IS_NAKED (func_type))
1221990075Sobrien    return;
1222090075Sobrien
1222190075Sobrien  if (IS_INTERRUPT (func_type))
1222290075Sobrien    {
1222390075Sobrien      error ("interrupt Service Routines cannot be coded in Thumb mode");
1222490075Sobrien      return;
1222590075Sobrien    }
1222690075Sobrien
1222790075Sobrien  if (frame_pointer_needed)
12228132718Skan    {
12229132718Skan      insn = emit_insn (gen_movsi (hard_frame_pointer_rtx, stack_pointer_rtx));
12230132718Skan      RTX_FRAME_RELATED_P (insn) = 1;
12231132718Skan    }
1223290075Sobrien
1223390075Sobrien  if (amount)
1223490075Sobrien    {
12235132718Skan      amount = ROUND_UP_WORD (amount);
1223690075Sobrien
1223790075Sobrien      if (amount < 512)
12238132718Skan	{
12239132718Skan	  insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
12240132718Skan					GEN_INT (- amount)));
12241132718Skan	  RTX_FRAME_RELATED_P (insn) = 1;
12242132718Skan	}
1224390075Sobrien      else
1224490075Sobrien	{
1224590075Sobrien	  int regno;
1224690075Sobrien	  rtx reg;
1224790075Sobrien
1224890075Sobrien	  /* The stack decrement is too big for an immediate value in a single
1224990075Sobrien	     insn.  In theory we could issue multiple subtracts, but after
1225090075Sobrien	     three of them it becomes more space efficient to place the full
1225190075Sobrien	     value in the constant pool and load into a register.  (Also the
1225290075Sobrien	     ARM debugger really likes to see only one stack decrement per
1225390075Sobrien	     function).  So instead we look for a scratch register into which
1225490075Sobrien	     we can load the decrement, and then we subtract this from the
1225590075Sobrien	     stack pointer.  Unfortunately on the thumb the only available
1225690075Sobrien	     scratch registers are the argument registers, and we cannot use
1225790075Sobrien	     these as they may hold arguments to the function.  Instead we
1225890075Sobrien	     attempt to locate a call preserved register which is used by this
1225990075Sobrien	     function.  If we can find one, then we know that it will have
1226090075Sobrien	     been pushed at the start of the prologue and so we can corrupt
1226190075Sobrien	     it now.  */
1226290075Sobrien	  for (regno = LAST_ARG_REGNUM + 1; regno <= LAST_LO_REGNUM; regno++)
12263117395Skan	    if (THUMB_REG_PUSHED_P (regno)
1226490075Sobrien		&& !(frame_pointer_needed
1226590075Sobrien		     && (regno == THUMB_HARD_FRAME_POINTER_REGNUM)))
1226690075Sobrien	      break;
1226790075Sobrien
12268117395Skan	  if (regno > LAST_LO_REGNUM) /* Very unlikely.  */
1226990075Sobrien	    {
1227090075Sobrien	      rtx spare = gen_rtx (REG, SImode, IP_REGNUM);
1227190075Sobrien
12272132718Skan	      /* Choose an arbitrary, non-argument low register.  */
1227390075Sobrien	      reg = gen_rtx (REG, SImode, LAST_LO_REGNUM);
1227490075Sobrien
1227590075Sobrien	      /* Save it by copying it into a high, scratch register.  */
1227690075Sobrien	      emit_insn (gen_movsi (spare, reg));
1227790075Sobrien	      /* Add a USE to stop propagate_one_insn() from barfing.  */
1227890075Sobrien	      emit_insn (gen_prologue_use (spare));
1227990075Sobrien
1228090075Sobrien	      /* Decrement the stack.  */
1228190075Sobrien	      emit_insn (gen_movsi (reg, GEN_INT (- amount)));
12282132718Skan	      insn = emit_insn (gen_addsi3 (stack_pointer_rtx,
12283132718Skan					    stack_pointer_rtx, reg));
12284132718Skan	      RTX_FRAME_RELATED_P (insn) = 1;
12285132718Skan	      dwarf = gen_rtx_SET (SImode, stack_pointer_rtx,
12286132718Skan				   plus_constant (stack_pointer_rtx,
12287132718Skan						  GEN_INT (- amount)));
12288132718Skan	      RTX_FRAME_RELATED_P (dwarf) = 1;
12289132718Skan	      REG_NOTES (insn)
12290132718Skan		= gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
12291132718Skan				     REG_NOTES (insn));
1229290075Sobrien
1229390075Sobrien	      /* Restore the low register's original value.  */
1229490075Sobrien	      emit_insn (gen_movsi (reg, spare));
1229590075Sobrien
1229690075Sobrien	      /* Emit a USE of the restored scratch register, so that flow
1229790075Sobrien		 analysis will not consider the restore redundant.  The
1229890075Sobrien		 register won't be used again in this function and isn't
1229990075Sobrien		 restored by the epilogue.  */
1230090075Sobrien	      emit_insn (gen_prologue_use (reg));
1230190075Sobrien	    }
1230290075Sobrien	  else
1230390075Sobrien	    {
1230490075Sobrien	      reg = gen_rtx (REG, SImode, regno);
1230590075Sobrien
1230690075Sobrien	      emit_insn (gen_movsi (reg, GEN_INT (- amount)));
12307132718Skan
12308132718Skan	      insn = emit_insn (gen_addsi3 (stack_pointer_rtx,
12309132718Skan					    stack_pointer_rtx, reg));
12310132718Skan	      RTX_FRAME_RELATED_P (insn) = 1;
12311132718Skan	      dwarf = gen_rtx_SET (SImode, stack_pointer_rtx,
12312132718Skan				   plus_constant (stack_pointer_rtx,
12313132718Skan						  GEN_INT (- amount)));
12314132718Skan	      RTX_FRAME_RELATED_P (dwarf) = 1;
12315132718Skan	      REG_NOTES (insn)
12316132718Skan		= gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
12317132718Skan				     REG_NOTES (insn));
1231890075Sobrien	    }
1231990075Sobrien	}
1232090075Sobrien    }
1232190075Sobrien
1232290075Sobrien  if (current_function_profile || TARGET_NO_SCHED_PRO)
1232390075Sobrien    emit_insn (gen_blockage ());
1232490075Sobrien}
1232590075Sobrien
1232690075Sobrienvoid
12327132718Skanthumb_expand_epilogue (void)
1232890075Sobrien{
12329117395Skan  HOST_WIDE_INT amount = (thumb_get_frame_size ()
1233090075Sobrien			  + current_function_outgoing_args_size);
12331132718Skan  int regno;
12332132718Skan
1233390075Sobrien  /* Naked functions don't have prologues.  */
1233490075Sobrien  if (IS_NAKED (arm_current_func_type ()))
1233590075Sobrien    return;
1233690075Sobrien
1233790075Sobrien  if (frame_pointer_needed)
1233890075Sobrien    emit_insn (gen_movsi (stack_pointer_rtx, hard_frame_pointer_rtx));
1233990075Sobrien  else if (amount)
1234090075Sobrien    {
12341132718Skan      amount = ROUND_UP_WORD (amount);
1234290075Sobrien
1234390075Sobrien      if (amount < 512)
1234490075Sobrien	emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
1234590075Sobrien			       GEN_INT (amount)));
1234690075Sobrien      else
1234790075Sobrien	{
1234890075Sobrien	  /* r3 is always free in the epilogue.  */
1234990075Sobrien	  rtx reg = gen_rtx (REG, SImode, LAST_ARG_REGNUM);
1235090075Sobrien
1235190075Sobrien	  emit_insn (gen_movsi (reg, GEN_INT (amount)));
1235290075Sobrien	  emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, reg));
1235390075Sobrien	}
1235490075Sobrien    }
1235590075Sobrien
1235690075Sobrien  /* Emit a USE (stack_pointer_rtx), so that
1235790075Sobrien     the stack adjustment will not be deleted.  */
1235890075Sobrien  emit_insn (gen_prologue_use (stack_pointer_rtx));
1235990075Sobrien
1236090075Sobrien  if (current_function_profile || TARGET_NO_SCHED_PRO)
1236190075Sobrien    emit_insn (gen_blockage ());
12362132718Skan
12363132718Skan  /* Emit a clobber for each insn that will be restored in the epilogue,
12364132718Skan     so that flow2 will get register lifetimes correct.  */
12365132718Skan  for (regno = 0; regno < 13; regno++)
12366132718Skan    if (regs_ever_live[regno] && !call_used_regs[regno])
12367132718Skan      emit_insn (gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, regno)));
12368132718Skan
12369132718Skan  if (! regs_ever_live[LR_REGNUM])
12370132718Skan    emit_insn (gen_rtx_USE (VOIDmode, gen_rtx_REG (SImode, LR_REGNUM)));
1237190075Sobrien}
1237290075Sobrien
1237390075Sobrienstatic void
12374132718Skanthumb_output_function_prologue (FILE *f, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
1237590075Sobrien{
1237690075Sobrien  int live_regs_mask = 0;
1237790075Sobrien  int high_regs_pushed = 0;
12378132718Skan  int cfa_offset = 0;
1237990075Sobrien  int regno;
1238090075Sobrien
1238190075Sobrien  if (IS_NAKED (arm_current_func_type ()))
1238290075Sobrien    return;
1238390075Sobrien
1238490075Sobrien  if (is_called_in_ARM_mode (current_function_decl))
1238590075Sobrien    {
1238690075Sobrien      const char * name;
1238790075Sobrien
1238890075Sobrien      if (GET_CODE (DECL_RTL (current_function_decl)) != MEM)
1238990075Sobrien	abort ();
1239090075Sobrien      if (GET_CODE (XEXP (DECL_RTL (current_function_decl), 0)) != SYMBOL_REF)
1239190075Sobrien	abort ();
1239290075Sobrien      name = XSTR  (XEXP (DECL_RTL (current_function_decl), 0), 0);
1239390075Sobrien
1239490075Sobrien      /* Generate code sequence to switch us into Thumb mode.  */
1239590075Sobrien      /* The .code 32 directive has already been emitted by
1239690075Sobrien	 ASM_DECLARE_FUNCTION_NAME.  */
1239790075Sobrien      asm_fprintf (f, "\torr\t%r, %r, #1\n", IP_REGNUM, PC_REGNUM);
1239890075Sobrien      asm_fprintf (f, "\tbx\t%r\n", IP_REGNUM);
1239990075Sobrien
1240090075Sobrien      /* Generate a label, so that the debugger will notice the
1240190075Sobrien	 change in instruction sets.  This label is also used by
1240290075Sobrien	 the assembler to bypass the ARM code when this function
1240390075Sobrien	 is called from a Thumb encoded function elsewhere in the
1240490075Sobrien	 same file.  Hence the definition of STUB_NAME here must
12405132718Skan	 agree with the definition in gas/config/tc-arm.c.  */
1240690075Sobrien
1240790075Sobrien#define STUB_NAME ".real_start_of"
1240890075Sobrien
12409117395Skan      fprintf (f, "\t.code\t16\n");
1241090075Sobrien#ifdef ARM_PE
1241190075Sobrien      if (arm_dllexport_name_p (name))
1241290075Sobrien        name = arm_strip_name_encoding (name);
1241390075Sobrien#endif
1241490075Sobrien      asm_fprintf (f, "\t.globl %s%U%s\n", STUB_NAME, name);
12415117395Skan      fprintf (f, "\t.thumb_func\n");
1241690075Sobrien      asm_fprintf (f, "%s%U%s:\n", STUB_NAME, name);
1241790075Sobrien    }
1241890075Sobrien
1241990075Sobrien  if (current_function_pretend_args_size)
1242090075Sobrien    {
1242196263Sobrien      if (cfun->machine->uses_anonymous_args)
1242290075Sobrien	{
1242390075Sobrien	  int num_pushes;
1242490075Sobrien
12425117395Skan	  fprintf (f, "\tpush\t{");
1242690075Sobrien
12427117395Skan	  num_pushes = ARM_NUM_INTS (current_function_pretend_args_size);
1242890075Sobrien
1242990075Sobrien	  for (regno = LAST_ARG_REGNUM + 1 - num_pushes;
1243090075Sobrien	       regno <= LAST_ARG_REGNUM;
1243190075Sobrien	       regno++)
1243290075Sobrien	    asm_fprintf (f, "%r%s", regno,
1243390075Sobrien			 regno == LAST_ARG_REGNUM ? "" : ", ");
1243490075Sobrien
12435117395Skan	  fprintf (f, "}\n");
1243690075Sobrien	}
1243790075Sobrien      else
1243890075Sobrien	asm_fprintf (f, "\tsub\t%r, %r, #%d\n",
1243990075Sobrien		     SP_REGNUM, SP_REGNUM,
1244090075Sobrien		     current_function_pretend_args_size);
12441132718Skan
12442132718Skan      /* We don't need to record the stores for unwinding (would it
12443132718Skan	 help the debugger any if we did?), but record the change in
12444132718Skan	 the stack pointer.  */
12445132718Skan      if (dwarf2out_do_frame ())
12446132718Skan	{
12447132718Skan	  char *l = dwarf2out_cfi_label ();
12448132718Skan	  cfa_offset = cfa_offset + current_function_pretend_args_size;
12449132718Skan	  dwarf2out_def_cfa (l, SP_REGNUM, cfa_offset);
12450132718Skan	}
1245190075Sobrien    }
1245290075Sobrien
1245390075Sobrien  for (regno = 0; regno <= LAST_LO_REGNUM; regno++)
12454117395Skan    if (THUMB_REG_PUSHED_P (regno))
1245590075Sobrien      live_regs_mask |= 1 << regno;
1245690075Sobrien
1245790075Sobrien  if (live_regs_mask || !leaf_function_p () || thumb_far_jump_used_p (1))
1245890075Sobrien    live_regs_mask |= 1 << LR_REGNUM;
1245990075Sobrien
1246090075Sobrien  if (TARGET_BACKTRACE)
1246190075Sobrien    {
1246290075Sobrien      int    offset;
1246390075Sobrien      int    work_register = 0;
1246490075Sobrien      int    wr;
1246590075Sobrien
1246690075Sobrien      /* We have been asked to create a stack backtrace structure.
1246790075Sobrien         The code looks like this:
1246890075Sobrien
1246990075Sobrien	 0   .align 2
1247090075Sobrien	 0   func:
1247190075Sobrien         0     sub   SP, #16         Reserve space for 4 registers.
1247290075Sobrien	 2     push  {R7}            Get a work register.
1247390075Sobrien         4     add   R7, SP, #20     Get the stack pointer before the push.
1247490075Sobrien         6     str   R7, [SP, #8]    Store the stack pointer (before reserving the space).
1247590075Sobrien         8     mov   R7, PC          Get hold of the start of this code plus 12.
1247690075Sobrien        10     str   R7, [SP, #16]   Store it.
1247790075Sobrien        12     mov   R7, FP          Get hold of the current frame pointer.
1247890075Sobrien        14     str   R7, [SP, #4]    Store it.
1247990075Sobrien        16     mov   R7, LR          Get hold of the current return address.
1248090075Sobrien        18     str   R7, [SP, #12]   Store it.
1248190075Sobrien        20     add   R7, SP, #16     Point at the start of the backtrace structure.
1248290075Sobrien        22     mov   FP, R7          Put this value into the frame pointer.  */
1248390075Sobrien
1248490075Sobrien      if ((live_regs_mask & 0xFF) == 0)
1248590075Sobrien	{
1248690075Sobrien	  /* See if the a4 register is free.  */
1248790075Sobrien
1248890075Sobrien	  if (regs_ever_live [LAST_ARG_REGNUM] == 0)
1248990075Sobrien	    work_register = LAST_ARG_REGNUM;
12490132718Skan	  else	  /* We must push a register of our own.  */
1249190075Sobrien	    live_regs_mask |= (1 << LAST_LO_REGNUM);
1249290075Sobrien	}
1249390075Sobrien
1249490075Sobrien      if (work_register == 0)
1249590075Sobrien	{
1249690075Sobrien	  /* Select a register from the list that will be pushed to
1249790075Sobrien             use as our work register.  */
1249890075Sobrien	  for (work_register = (LAST_LO_REGNUM + 1); work_register--;)
1249990075Sobrien	    if ((1 << work_register) & live_regs_mask)
1250090075Sobrien	      break;
1250190075Sobrien	}
1250290075Sobrien
1250390075Sobrien      asm_fprintf
1250490075Sobrien	(f, "\tsub\t%r, %r, #16\t%@ Create stack backtrace structure\n",
1250590075Sobrien	 SP_REGNUM, SP_REGNUM);
12506132718Skan
12507132718Skan      if (dwarf2out_do_frame ())
12508132718Skan	{
12509132718Skan	  char *l = dwarf2out_cfi_label ();
12510132718Skan	  cfa_offset = cfa_offset + 16;
12511132718Skan	  dwarf2out_def_cfa (l, SP_REGNUM, cfa_offset);
12512132718Skan	}
12513132718Skan
1251490075Sobrien      if (live_regs_mask)
12515132718Skan	thumb_pushpop (f, live_regs_mask, 1, &cfa_offset, live_regs_mask);
1251690075Sobrien
1251790075Sobrien      for (offset = 0, wr = 1 << 15; wr != 0; wr >>= 1)
1251890075Sobrien	if (wr & live_regs_mask)
1251990075Sobrien	  offset += 4;
1252090075Sobrien
1252190075Sobrien      asm_fprintf (f, "\tadd\t%r, %r, #%d\n", work_register, SP_REGNUM,
1252290075Sobrien		   offset + 16 + current_function_pretend_args_size);
1252390075Sobrien
1252490075Sobrien      asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
1252590075Sobrien		   offset + 4);
1252690075Sobrien
1252790075Sobrien      /* Make sure that the instruction fetching the PC is in the right place
1252890075Sobrien	 to calculate "start of backtrace creation code + 12".  */
1252990075Sobrien      if (live_regs_mask)
1253090075Sobrien	{
1253190075Sobrien	  asm_fprintf (f, "\tmov\t%r, %r\n", work_register, PC_REGNUM);
1253290075Sobrien	  asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
1253390075Sobrien		       offset + 12);
1253490075Sobrien	  asm_fprintf (f, "\tmov\t%r, %r\n", work_register,
1253590075Sobrien		       ARM_HARD_FRAME_POINTER_REGNUM);
1253690075Sobrien	  asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
1253790075Sobrien		       offset);
1253890075Sobrien	}
1253990075Sobrien      else
1254090075Sobrien	{
1254190075Sobrien	  asm_fprintf (f, "\tmov\t%r, %r\n", work_register,
1254290075Sobrien		       ARM_HARD_FRAME_POINTER_REGNUM);
1254390075Sobrien	  asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
1254490075Sobrien		       offset);
1254590075Sobrien	  asm_fprintf (f, "\tmov\t%r, %r\n", work_register, PC_REGNUM);
1254690075Sobrien	  asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
1254790075Sobrien		       offset + 12);
1254890075Sobrien	}
1254990075Sobrien
1255090075Sobrien      asm_fprintf (f, "\tmov\t%r, %r\n", work_register, LR_REGNUM);
1255190075Sobrien      asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
1255290075Sobrien		   offset + 8);
1255390075Sobrien      asm_fprintf (f, "\tadd\t%r, %r, #%d\n", work_register, SP_REGNUM,
1255490075Sobrien		   offset + 12);
1255590075Sobrien      asm_fprintf (f, "\tmov\t%r, %r\t\t%@ Backtrace structure created\n",
1255690075Sobrien		   ARM_HARD_FRAME_POINTER_REGNUM, work_register);
1255790075Sobrien    }
1255890075Sobrien  else if (live_regs_mask)
12559132718Skan    thumb_pushpop (f, live_regs_mask, 1, &cfa_offset, live_regs_mask);
1256090075Sobrien
1256190075Sobrien  for (regno = 8; regno < 13; regno++)
12562117395Skan    if (THUMB_REG_PUSHED_P (regno))
12563117395Skan      high_regs_pushed++;
1256490075Sobrien
1256590075Sobrien  if (high_regs_pushed)
1256690075Sobrien    {
1256790075Sobrien      int pushable_regs = 0;
1256890075Sobrien      int mask = live_regs_mask & 0xff;
1256990075Sobrien      int next_hi_reg;
1257090075Sobrien
1257190075Sobrien      for (next_hi_reg = 12; next_hi_reg > LAST_LO_REGNUM; next_hi_reg--)
12572117395Skan	if (THUMB_REG_PUSHED_P (next_hi_reg))
12573117395Skan	  break;
1257490075Sobrien
1257590075Sobrien      pushable_regs = mask;
1257690075Sobrien
1257790075Sobrien      if (pushable_regs == 0)
1257890075Sobrien	{
1257990075Sobrien	  /* Desperation time -- this probably will never happen.  */
12580117395Skan	  if (THUMB_REG_PUSHED_P (LAST_ARG_REGNUM))
1258190075Sobrien	    asm_fprintf (f, "\tmov\t%r, %r\n", IP_REGNUM, LAST_ARG_REGNUM);
1258290075Sobrien	  mask = 1 << LAST_ARG_REGNUM;
1258390075Sobrien	}
1258490075Sobrien
1258590075Sobrien      while (high_regs_pushed > 0)
1258690075Sobrien	{
12587132718Skan	  int real_regs_mask = 0;
12588132718Skan
1258990075Sobrien	  for (regno = LAST_LO_REGNUM; regno >= 0; regno--)
1259090075Sobrien	    {
1259190075Sobrien	      if (mask & (1 << regno))
1259290075Sobrien		{
1259390075Sobrien		  asm_fprintf (f, "\tmov\t%r, %r\n", regno, next_hi_reg);
1259490075Sobrien
1259590075Sobrien		  high_regs_pushed--;
12596132718Skan		  real_regs_mask |= (1 << next_hi_reg);
1259790075Sobrien
1259890075Sobrien		  if (high_regs_pushed)
12599117395Skan		    {
12600117395Skan		      for (next_hi_reg--; next_hi_reg > LAST_LO_REGNUM;
12601117395Skan			   next_hi_reg--)
12602117395Skan			if (THUMB_REG_PUSHED_P (next_hi_reg))
1260390075Sobrien			  break;
12604117395Skan		    }
1260590075Sobrien		  else
1260690075Sobrien		    {
1260790075Sobrien		      mask &= ~((1 << regno) - 1);
1260890075Sobrien		      break;
1260990075Sobrien		    }
1261090075Sobrien		}
1261190075Sobrien	    }
12612132718Skan
12613132718Skan	  thumb_pushpop (f, mask, 1, &cfa_offset, real_regs_mask);
1261490075Sobrien	}
1261590075Sobrien
1261690075Sobrien      if (pushable_regs == 0
12617117395Skan	  && (THUMB_REG_PUSHED_P (LAST_ARG_REGNUM)))
1261890075Sobrien	asm_fprintf (f, "\tmov\t%r, %r\n", LAST_ARG_REGNUM, IP_REGNUM);
1261990075Sobrien    }
1262090075Sobrien}
1262190075Sobrien
1262290075Sobrien/* Handle the case of a double word load into a low register from
1262390075Sobrien   a computed memory address.  The computed address may involve a
1262490075Sobrien   register which is overwritten by the load.  */
1262590075Sobrienconst char *
12626132718Skanthumb_load_double_from_address (rtx *operands)
1262790075Sobrien{
1262890075Sobrien  rtx addr;
1262990075Sobrien  rtx base;
1263090075Sobrien  rtx offset;
1263190075Sobrien  rtx arg1;
1263290075Sobrien  rtx arg2;
1263390075Sobrien
1263490075Sobrien  if (GET_CODE (operands[0]) != REG)
1263590075Sobrien    abort ();
1263690075Sobrien
1263790075Sobrien  if (GET_CODE (operands[1]) != MEM)
1263890075Sobrien    abort ();
1263990075Sobrien
1264090075Sobrien  /* Get the memory address.  */
1264190075Sobrien  addr = XEXP (operands[1], 0);
1264290075Sobrien
1264390075Sobrien  /* Work out how the memory address is computed.  */
1264490075Sobrien  switch (GET_CODE (addr))
1264590075Sobrien    {
1264690075Sobrien    case REG:
1264790075Sobrien      operands[2] = gen_rtx (MEM, SImode,
1264890075Sobrien			     plus_constant (XEXP (operands[1], 0), 4));
1264990075Sobrien
1265090075Sobrien      if (REGNO (operands[0]) == REGNO (addr))
1265190075Sobrien	{
1265290075Sobrien	  output_asm_insn ("ldr\t%H0, %2", operands);
1265390075Sobrien	  output_asm_insn ("ldr\t%0, %1", operands);
1265490075Sobrien	}
1265590075Sobrien      else
1265690075Sobrien	{
1265790075Sobrien	  output_asm_insn ("ldr\t%0, %1", operands);
1265890075Sobrien	  output_asm_insn ("ldr\t%H0, %2", operands);
1265990075Sobrien	}
1266090075Sobrien      break;
1266190075Sobrien
1266290075Sobrien    case CONST:
1266390075Sobrien      /* Compute <address> + 4 for the high order load.  */
1266490075Sobrien      operands[2] = gen_rtx (MEM, SImode,
1266590075Sobrien			     plus_constant (XEXP (operands[1], 0), 4));
1266690075Sobrien
1266790075Sobrien      output_asm_insn ("ldr\t%0, %1", operands);
1266890075Sobrien      output_asm_insn ("ldr\t%H0, %2", operands);
1266990075Sobrien      break;
1267090075Sobrien
1267190075Sobrien    case PLUS:
1267290075Sobrien      arg1   = XEXP (addr, 0);
1267390075Sobrien      arg2   = XEXP (addr, 1);
1267490075Sobrien
1267590075Sobrien      if (CONSTANT_P (arg1))
1267690075Sobrien	base = arg2, offset = arg1;
1267790075Sobrien      else
1267890075Sobrien	base = arg1, offset = arg2;
1267990075Sobrien
1268090075Sobrien      if (GET_CODE (base) != REG)
1268190075Sobrien	abort ();
1268290075Sobrien
1268390075Sobrien      /* Catch the case of <address> = <reg> + <reg> */
1268490075Sobrien      if (GET_CODE (offset) == REG)
1268590075Sobrien	{
1268690075Sobrien	  int reg_offset = REGNO (offset);
1268790075Sobrien	  int reg_base   = REGNO (base);
1268890075Sobrien	  int reg_dest   = REGNO (operands[0]);
1268990075Sobrien
1269090075Sobrien	  /* Add the base and offset registers together into the
1269190075Sobrien             higher destination register.  */
1269290075Sobrien	  asm_fprintf (asm_out_file, "\tadd\t%r, %r, %r",
1269390075Sobrien		       reg_dest + 1, reg_base, reg_offset);
1269490075Sobrien
1269590075Sobrien	  /* Load the lower destination register from the address in
1269690075Sobrien             the higher destination register.  */
1269790075Sobrien	  asm_fprintf (asm_out_file, "\tldr\t%r, [%r, #0]",
1269890075Sobrien		       reg_dest, reg_dest + 1);
1269990075Sobrien
1270090075Sobrien	  /* Load the higher destination register from its own address
1270190075Sobrien             plus 4.  */
1270290075Sobrien	  asm_fprintf (asm_out_file, "\tldr\t%r, [%r, #4]",
1270390075Sobrien		       reg_dest + 1, reg_dest + 1);
1270490075Sobrien	}
1270590075Sobrien      else
1270690075Sobrien	{
1270790075Sobrien	  /* Compute <address> + 4 for the high order load.  */
1270890075Sobrien	  operands[2] = gen_rtx (MEM, SImode,
1270990075Sobrien				 plus_constant (XEXP (operands[1], 0), 4));
1271090075Sobrien
1271190075Sobrien	  /* If the computed address is held in the low order register
1271290075Sobrien	     then load the high order register first, otherwise always
1271390075Sobrien	     load the low order register first.  */
1271490075Sobrien	  if (REGNO (operands[0]) == REGNO (base))
1271590075Sobrien	    {
1271690075Sobrien	      output_asm_insn ("ldr\t%H0, %2", operands);
1271790075Sobrien	      output_asm_insn ("ldr\t%0, %1", operands);
1271890075Sobrien	    }
1271990075Sobrien	  else
1272090075Sobrien	    {
1272190075Sobrien	      output_asm_insn ("ldr\t%0, %1", operands);
1272290075Sobrien	      output_asm_insn ("ldr\t%H0, %2", operands);
1272390075Sobrien	    }
1272490075Sobrien	}
1272590075Sobrien      break;
1272690075Sobrien
1272790075Sobrien    case LABEL_REF:
1272890075Sobrien      /* With no registers to worry about we can just load the value
1272990075Sobrien         directly.  */
1273090075Sobrien      operands[2] = gen_rtx (MEM, SImode,
1273190075Sobrien			     plus_constant (XEXP (operands[1], 0), 4));
1273290075Sobrien
1273390075Sobrien      output_asm_insn ("ldr\t%H0, %2", operands);
1273490075Sobrien      output_asm_insn ("ldr\t%0, %1", operands);
1273590075Sobrien      break;
1273690075Sobrien
1273790075Sobrien    default:
1273890075Sobrien      abort ();
1273990075Sobrien      break;
1274090075Sobrien    }
1274190075Sobrien
1274290075Sobrien  return "";
1274390075Sobrien}
1274490075Sobrien
1274590075Sobrienconst char *
12746132718Skanthumb_output_move_mem_multiple (int n, rtx *operands)
1274790075Sobrien{
1274890075Sobrien  rtx tmp;
1274990075Sobrien
1275090075Sobrien  switch (n)
1275190075Sobrien    {
1275290075Sobrien    case 2:
1275390075Sobrien      if (REGNO (operands[4]) > REGNO (operands[5]))
1275490075Sobrien	{
1275590075Sobrien	  tmp = operands[4];
1275690075Sobrien	  operands[4] = operands[5];
1275790075Sobrien	  operands[5] = tmp;
1275890075Sobrien	}
1275990075Sobrien      output_asm_insn ("ldmia\t%1!, {%4, %5}", operands);
1276090075Sobrien      output_asm_insn ("stmia\t%0!, {%4, %5}", operands);
1276190075Sobrien      break;
1276290075Sobrien
1276390075Sobrien    case 3:
1276490075Sobrien      if (REGNO (operands[4]) > REGNO (operands[5]))
1276590075Sobrien	{
1276690075Sobrien	  tmp = operands[4];
1276790075Sobrien	  operands[4] = operands[5];
1276890075Sobrien	  operands[5] = tmp;
1276990075Sobrien	}
1277090075Sobrien      if (REGNO (operands[5]) > REGNO (operands[6]))
1277190075Sobrien	{
1277290075Sobrien	  tmp = operands[5];
1277390075Sobrien	  operands[5] = operands[6];
1277490075Sobrien	  operands[6] = tmp;
1277590075Sobrien	}
1277690075Sobrien      if (REGNO (operands[4]) > REGNO (operands[5]))
1277790075Sobrien	{
1277890075Sobrien	  tmp = operands[4];
1277990075Sobrien	  operands[4] = operands[5];
1278090075Sobrien	  operands[5] = tmp;
1278190075Sobrien	}
1278290075Sobrien
1278390075Sobrien      output_asm_insn ("ldmia\t%1!, {%4, %5, %6}", operands);
1278490075Sobrien      output_asm_insn ("stmia\t%0!, {%4, %5, %6}", operands);
1278590075Sobrien      break;
1278690075Sobrien
1278790075Sobrien    default:
1278890075Sobrien      abort ();
1278990075Sobrien    }
1279090075Sobrien
1279190075Sobrien  return "";
1279290075Sobrien}
1279390075Sobrien
1279490075Sobrien/* Routines for generating rtl.  */
1279590075Sobrienvoid
12796132718Skanthumb_expand_movstrqi (rtx *operands)
1279790075Sobrien{
1279890075Sobrien  rtx out = copy_to_mode_reg (SImode, XEXP (operands[0], 0));
1279990075Sobrien  rtx in  = copy_to_mode_reg (SImode, XEXP (operands[1], 0));
1280090075Sobrien  HOST_WIDE_INT len = INTVAL (operands[2]);
1280190075Sobrien  HOST_WIDE_INT offset = 0;
1280290075Sobrien
1280390075Sobrien  while (len >= 12)
1280490075Sobrien    {
1280590075Sobrien      emit_insn (gen_movmem12b (out, in, out, in));
1280690075Sobrien      len -= 12;
1280790075Sobrien    }
1280890075Sobrien
1280990075Sobrien  if (len >= 8)
1281090075Sobrien    {
1281190075Sobrien      emit_insn (gen_movmem8b (out, in, out, in));
1281290075Sobrien      len -= 8;
1281390075Sobrien    }
1281490075Sobrien
1281590075Sobrien  if (len >= 4)
1281690075Sobrien    {
1281790075Sobrien      rtx reg = gen_reg_rtx (SImode);
1281890075Sobrien      emit_insn (gen_movsi (reg, gen_rtx (MEM, SImode, in)));
1281990075Sobrien      emit_insn (gen_movsi (gen_rtx (MEM, SImode, out), reg));
1282090075Sobrien      len -= 4;
1282190075Sobrien      offset += 4;
1282290075Sobrien    }
1282390075Sobrien
1282490075Sobrien  if (len >= 2)
1282590075Sobrien    {
1282690075Sobrien      rtx reg = gen_reg_rtx (HImode);
1282790075Sobrien      emit_insn (gen_movhi (reg, gen_rtx (MEM, HImode,
1282890075Sobrien					  plus_constant (in, offset))));
1282990075Sobrien      emit_insn (gen_movhi (gen_rtx (MEM, HImode, plus_constant (out, offset)),
1283090075Sobrien			    reg));
1283190075Sobrien      len -= 2;
1283290075Sobrien      offset += 2;
1283390075Sobrien    }
1283490075Sobrien
1283590075Sobrien  if (len)
1283690075Sobrien    {
1283790075Sobrien      rtx reg = gen_reg_rtx (QImode);
1283890075Sobrien      emit_insn (gen_movqi (reg, gen_rtx (MEM, QImode,
1283990075Sobrien					  plus_constant (in, offset))));
1284090075Sobrien      emit_insn (gen_movqi (gen_rtx (MEM, QImode, plus_constant (out, offset)),
1284190075Sobrien			    reg));
1284290075Sobrien    }
1284390075Sobrien}
1284490075Sobrien
1284590075Sobrienint
12846132718Skanthumb_cmp_operand (rtx op, enum machine_mode mode)
1284790075Sobrien{
1284890075Sobrien  return ((GET_CODE (op) == CONST_INT
12849132718Skan	   && INTVAL (op) < 256
12850132718Skan	   && INTVAL (op) >= 0)
12851132718Skan	  || s_register_operand (op, mode));
1285290075Sobrien}
1285390075Sobrien
12854132718Skanint
12855132718Skanthumb_cmpneg_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
1285690075Sobrien{
12857132718Skan  return (GET_CODE (op) == CONST_INT
12858132718Skan	  && INTVAL (op) < 0
12859132718Skan	  && INTVAL (op) > -256);
12860132718Skan}
1286190075Sobrien
12862132718Skan/* Return TRUE if a result can be stored in OP without clobbering the
12863132718Skan   condition code register.  Prior to reload we only accept a
12864132718Skan   register.  After reload we have to be able to handle memory as
12865132718Skan   well, since a pseudo may not get a hard reg and reload cannot
12866132718Skan   handle output-reloads on jump insns.
1286790075Sobrien
12868132718Skan   We could possibly handle mem before reload as well, but that might
12869132718Skan   complicate things with the need to handle increment
12870132718Skan   side-effects.  */
12871132718Skan
12872132718Skanint
12873132718Skanthumb_cbrch_target_operand (rtx op, enum machine_mode mode)
12874132718Skan{
12875132718Skan  return (s_register_operand (op, mode)
12876132718Skan	  || ((reload_in_progress || reload_completed)
12877132718Skan	      && memory_operand (op, mode)));
1287890075Sobrien}
1287990075Sobrien
1288090075Sobrien/* Handle storing a half-word to memory during reload.  */
1288190075Sobrienvoid
12882132718Skanthumb_reload_out_hi (rtx *operands)
1288390075Sobrien{
1288490075Sobrien  emit_insn (gen_thumb_movhi_clobber (operands[0], operands[1], operands[2]));
1288590075Sobrien}
1288690075Sobrien
12887132718Skan/* Handle reading a half-word from memory during reload.  */
1288890075Sobrienvoid
12889132718Skanthumb_reload_in_hi (rtx *operands ATTRIBUTE_UNUSED)
1289090075Sobrien{
1289190075Sobrien  abort ();
1289290075Sobrien}
1289390075Sobrien
1289490075Sobrien/* Return the length of a function name prefix
1289590075Sobrien    that starts with the character 'c'.  */
1289690075Sobrienstatic int
12897132718Skanarm_get_strip_length (int c)
1289890075Sobrien{
1289990075Sobrien  switch (c)
1290090075Sobrien    {
1290190075Sobrien    ARM_NAME_ENCODING_LENGTHS
1290290075Sobrien      default: return 0;
1290390075Sobrien    }
1290490075Sobrien}
1290590075Sobrien
1290690075Sobrien/* Return a pointer to a function's name with any
1290790075Sobrien   and all prefix encodings stripped from it.  */
1290890075Sobrienconst char *
12909132718Skanarm_strip_name_encoding (const char *name)
1291090075Sobrien{
1291190075Sobrien  int skip;
1291290075Sobrien
1291390075Sobrien  while ((skip = arm_get_strip_length (* name)))
1291490075Sobrien    name += skip;
1291590075Sobrien
1291690075Sobrien  return name;
1291790075Sobrien}
1291890075Sobrien
12919117395Skan/* If there is a '*' anywhere in the name's prefix, then
12920117395Skan   emit the stripped name verbatim, otherwise prepend an
12921117395Skan   underscore if leading underscores are being used.  */
12922117395Skanvoid
12923132718Skanarm_asm_output_labelref (FILE *stream, const char *name)
12924117395Skan{
12925117395Skan  int skip;
12926117395Skan  int verbatim = 0;
12927117395Skan
12928117395Skan  while ((skip = arm_get_strip_length (* name)))
12929117395Skan    {
12930117395Skan      verbatim |= (*name == '*');
12931117395Skan      name += skip;
12932117395Skan    }
12933117395Skan
12934117395Skan  if (verbatim)
12935117395Skan    fputs (name, stream);
12936117395Skan  else
12937117395Skan    asm_fprintf (stream, "%U%s", name);
12938117395Skan}
12939117395Skan
12940117395Skanrtx aof_pic_label;
12941117395Skan
1294290075Sobrien#ifdef AOF_ASSEMBLER
1294390075Sobrien/* Special functions only needed when producing AOF syntax assembler.  */
1294490075Sobrien
1294590075Sobrienstruct pic_chain
1294690075Sobrien{
1294790075Sobrien  struct pic_chain * next;
1294890075Sobrien  const char * symname;
1294990075Sobrien};
1295090075Sobrien
1295190075Sobrienstatic struct pic_chain * aof_pic_chain = NULL;
1295290075Sobrien
1295390075Sobrienrtx
12954132718Skanaof_pic_entry (rtx x)
1295590075Sobrien{
1295690075Sobrien  struct pic_chain ** chainp;
1295790075Sobrien  int offset;
1295890075Sobrien
1295990075Sobrien  if (aof_pic_label == NULL_RTX)
1296090075Sobrien    {
1296190075Sobrien      aof_pic_label = gen_rtx_SYMBOL_REF (Pmode, "x$adcons");
1296290075Sobrien    }
1296390075Sobrien
1296490075Sobrien  for (offset = 0, chainp = &aof_pic_chain; *chainp;
1296590075Sobrien       offset += 4, chainp = &(*chainp)->next)
1296690075Sobrien    if ((*chainp)->symname == XSTR (x, 0))
1296790075Sobrien      return plus_constant (aof_pic_label, offset);
1296890075Sobrien
1296990075Sobrien  *chainp = (struct pic_chain *) xmalloc (sizeof (struct pic_chain));
1297090075Sobrien  (*chainp)->next = NULL;
1297190075Sobrien  (*chainp)->symname = XSTR (x, 0);
1297290075Sobrien  return plus_constant (aof_pic_label, offset);
1297390075Sobrien}
1297490075Sobrien
1297590075Sobrienvoid
12976132718Skanaof_dump_pic_table (FILE *f)
1297790075Sobrien{
1297890075Sobrien  struct pic_chain * chain;
1297990075Sobrien
1298090075Sobrien  if (aof_pic_chain == NULL)
1298190075Sobrien    return;
1298290075Sobrien
1298390075Sobrien  asm_fprintf (f, "\tAREA |%r$$adcons|, BASED %r\n",
1298490075Sobrien	       PIC_OFFSET_TABLE_REGNUM,
1298590075Sobrien	       PIC_OFFSET_TABLE_REGNUM);
1298690075Sobrien  fputs ("|x$adcons|\n", f);
1298790075Sobrien
1298890075Sobrien  for (chain = aof_pic_chain; chain; chain = chain->next)
1298990075Sobrien    {
1299090075Sobrien      fputs ("\tDCD\t", f);
1299190075Sobrien      assemble_name (f, chain->symname);
1299290075Sobrien      fputs ("\n", f);
1299390075Sobrien    }
1299490075Sobrien}
1299590075Sobrien
1299690075Sobrienint arm_text_section_count = 1;
1299790075Sobrien
1299890075Sobrienchar *
12999132718Skanaof_text_section (void )
1300090075Sobrien{
1300190075Sobrien  static char buf[100];
1300290075Sobrien  sprintf (buf, "\tAREA |C$$code%d|, CODE, READONLY",
1300390075Sobrien	   arm_text_section_count++);
1300490075Sobrien  if (flag_pic)
1300590075Sobrien    strcat (buf, ", PIC, REENTRANT");
1300690075Sobrien  return buf;
1300790075Sobrien}
1300890075Sobrien
1300990075Sobrienstatic int arm_data_section_count = 1;
1301090075Sobrien
1301190075Sobrienchar *
13012132718Skanaof_data_section (void)
1301390075Sobrien{
1301490075Sobrien  static char buf[100];
1301590075Sobrien  sprintf (buf, "\tAREA |C$$data%d|, DATA", arm_data_section_count++);
1301690075Sobrien  return buf;
1301790075Sobrien}
1301890075Sobrien
1301990075Sobrien/* The AOF assembler is religiously strict about declarations of
1302090075Sobrien   imported and exported symbols, so that it is impossible to declare
1302190075Sobrien   a function as imported near the beginning of the file, and then to
1302290075Sobrien   export it later on.  It is, however, possible to delay the decision
1302390075Sobrien   until all the functions in the file have been compiled.  To get
1302490075Sobrien   around this, we maintain a list of the imports and exports, and
1302590075Sobrien   delete from it any that are subsequently defined.  At the end of
1302690075Sobrien   compilation we spit the remainder of the list out before the END
1302790075Sobrien   directive.  */
1302890075Sobrien
1302990075Sobrienstruct import
1303090075Sobrien{
1303190075Sobrien  struct import * next;
1303290075Sobrien  const char * name;
1303390075Sobrien};
1303490075Sobrien
1303590075Sobrienstatic struct import * imports_list = NULL;
1303690075Sobrien
1303790075Sobrienvoid
13038132718Skanaof_add_import (const char *name)
1303990075Sobrien{
1304090075Sobrien  struct import * new;
1304190075Sobrien
1304290075Sobrien  for (new = imports_list; new; new = new->next)
1304390075Sobrien    if (new->name == name)
1304490075Sobrien      return;
1304590075Sobrien
1304690075Sobrien  new = (struct import *) xmalloc (sizeof (struct import));
1304790075Sobrien  new->next = imports_list;
1304890075Sobrien  imports_list = new;
1304990075Sobrien  new->name = name;
1305090075Sobrien}
1305190075Sobrien
1305290075Sobrienvoid
13053132718Skanaof_delete_import (const char *name)
1305490075Sobrien{
1305590075Sobrien  struct import ** old;
1305690075Sobrien
1305790075Sobrien  for (old = &imports_list; *old; old = & (*old)->next)
1305890075Sobrien    {
1305990075Sobrien      if ((*old)->name == name)
1306090075Sobrien	{
1306190075Sobrien	  *old = (*old)->next;
1306290075Sobrien	  return;
1306390075Sobrien	}
1306490075Sobrien    }
1306590075Sobrien}
1306690075Sobrien
1306790075Sobrienint arm_main_function = 0;
1306890075Sobrien
13069132718Skanstatic void
13070132718Skanaof_dump_imports (FILE *f)
1307190075Sobrien{
1307290075Sobrien  /* The AOF assembler needs this to cause the startup code to be extracted
1307390075Sobrien     from the library.  Brining in __main causes the whole thing to work
1307490075Sobrien     automagically.  */
1307590075Sobrien  if (arm_main_function)
1307690075Sobrien    {
1307790075Sobrien      text_section ();
1307890075Sobrien      fputs ("\tIMPORT __main\n", f);
1307990075Sobrien      fputs ("\tDCD __main\n", f);
1308090075Sobrien    }
1308190075Sobrien
1308290075Sobrien  /* Now dump the remaining imports.  */
1308390075Sobrien  while (imports_list)
1308490075Sobrien    {
1308590075Sobrien      fprintf (f, "\tIMPORT\t");
1308690075Sobrien      assemble_name (f, imports_list->name);
1308790075Sobrien      fputc ('\n', f);
1308890075Sobrien      imports_list = imports_list->next;
1308990075Sobrien    }
1309090075Sobrien}
13091117395Skan
13092117395Skanstatic void
13093132718Skanaof_globalize_label (FILE *stream, const char *name)
13094117395Skan{
13095117395Skan  default_globalize_label (stream, name);
13096117395Skan  if (! strcmp (name, "main"))
13097117395Skan    arm_main_function = 1;
13098117395Skan}
13099132718Skan
13100132718Skanstatic void
13101132718Skanaof_file_start (void)
13102132718Skan{
13103132718Skan  fputs ("__r0\tRN\t0\n", asm_out_file);
13104132718Skan  fputs ("__a1\tRN\t0\n", asm_out_file);
13105132718Skan  fputs ("__a2\tRN\t1\n", asm_out_file);
13106132718Skan  fputs ("__a3\tRN\t2\n", asm_out_file);
13107132718Skan  fputs ("__a4\tRN\t3\n", asm_out_file);
13108132718Skan  fputs ("__v1\tRN\t4\n", asm_out_file);
13109132718Skan  fputs ("__v2\tRN\t5\n", asm_out_file);
13110132718Skan  fputs ("__v3\tRN\t6\n", asm_out_file);
13111132718Skan  fputs ("__v4\tRN\t7\n", asm_out_file);
13112132718Skan  fputs ("__v5\tRN\t8\n", asm_out_file);
13113132718Skan  fputs ("__v6\tRN\t9\n", asm_out_file);
13114132718Skan  fputs ("__sl\tRN\t10\n", asm_out_file);
13115132718Skan  fputs ("__fp\tRN\t11\n", asm_out_file);
13116132718Skan  fputs ("__ip\tRN\t12\n", asm_out_file);
13117132718Skan  fputs ("__sp\tRN\t13\n", asm_out_file);
13118132718Skan  fputs ("__lr\tRN\t14\n", asm_out_file);
13119132718Skan  fputs ("__pc\tRN\t15\n", asm_out_file);
13120132718Skan  fputs ("__f0\tFN\t0\n", asm_out_file);
13121132718Skan  fputs ("__f1\tFN\t1\n", asm_out_file);
13122132718Skan  fputs ("__f2\tFN\t2\n", asm_out_file);
13123132718Skan  fputs ("__f3\tFN\t3\n", asm_out_file);
13124132718Skan  fputs ("__f4\tFN\t4\n", asm_out_file);
13125132718Skan  fputs ("__f5\tFN\t5\n", asm_out_file);
13126132718Skan  fputs ("__f6\tFN\t6\n", asm_out_file);
13127132718Skan  fputs ("__f7\tFN\t7\n", asm_out_file);
13128132718Skan  text_section ();
13129132718Skan}
13130132718Skan
13131132718Skanstatic void
13132132718Skanaof_file_end (void)
13133132718Skan{
13134132718Skan  if (flag_pic)
13135132718Skan    aof_dump_pic_table (asm_out_file);
13136132718Skan  aof_dump_imports (asm_out_file);
13137132718Skan  fputs ("\tEND\n", asm_out_file);
13138132718Skan}
1313990075Sobrien#endif /* AOF_ASSEMBLER */
1314090075Sobrien
1314190075Sobrien#ifdef OBJECT_FORMAT_ELF
1314290075Sobrien/* Switch to an arbitrary section NAME with attributes as specified
1314390075Sobrien   by FLAGS.  ALIGN specifies any known alignment requirements for
1314490075Sobrien   the section; 0 if the default should be used.
1314590075Sobrien
1314690075Sobrien   Differs from the default elf version only in the prefix character
1314790075Sobrien   used before the section type.  */
1314890075Sobrien
1314990075Sobrienstatic void
13150132718Skanarm_elf_asm_named_section (const char *name, unsigned int flags)
1315190075Sobrien{
13152117395Skan  char flagchars[10], *f = flagchars;
1315390075Sobrien
13154117395Skan  if (! named_section_first_declaration (name))
13155117395Skan    {
13156117395Skan      fprintf (asm_out_file, "\t.section\t%s\n", name);
13157117395Skan      return;
13158117395Skan    }
13159117395Skan
1316090075Sobrien  if (!(flags & SECTION_DEBUG))
1316190075Sobrien    *f++ = 'a';
1316290075Sobrien  if (flags & SECTION_WRITE)
1316390075Sobrien    *f++ = 'w';
1316490075Sobrien  if (flags & SECTION_CODE)
1316590075Sobrien    *f++ = 'x';
1316690075Sobrien  if (flags & SECTION_SMALL)
1316790075Sobrien    *f++ = 's';
1316890075Sobrien  if (flags & SECTION_MERGE)
1316990075Sobrien    *f++ = 'M';
1317090075Sobrien  if (flags & SECTION_STRINGS)
1317190075Sobrien    *f++ = 'S';
13172117395Skan  if (flags & SECTION_TLS)
13173117395Skan    *f++ = 'T';
1317490075Sobrien  *f = '\0';
1317590075Sobrien
13176117395Skan  fprintf (asm_out_file, "\t.section\t%s,\"%s\"", name, flagchars);
1317790075Sobrien
13178117395Skan  if (!(flags & SECTION_NOTYPE))
13179117395Skan    {
13180117395Skan      const char *type;
13181117395Skan
13182117395Skan      if (flags & SECTION_BSS)
13183117395Skan	type = "nobits";
13184117395Skan      else
13185117395Skan	type = "progbits";
13186117395Skan
13187117395Skan      fprintf (asm_out_file, ",%%%s", type);
13188117395Skan
13189117395Skan      if (flags & SECTION_ENTSIZE)
13190117395Skan	fprintf (asm_out_file, ",%d", flags & SECTION_ENTSIZE);
13191117395Skan    }
13192117395Skan
13193117395Skan  putc ('\n', asm_out_file);
1319490075Sobrien}
1319590075Sobrien#endif
13196117395Skan
13197117395Skan#ifndef ARM_PE
13198117395Skan/* Symbols in the text segment can be accessed without indirecting via the
13199117395Skan   constant pool; it may take an extra binary operation, but this is still
13200117395Skan   faster than indirecting via memory.  Don't do this when not optimizing,
13201117395Skan   since we won't be calculating al of the offsets necessary to do this
13202117395Skan   simplification.  */
13203117395Skan
13204117395Skanstatic void
13205132718Skanarm_encode_section_info (tree decl, rtx rtl, int first)
13206117395Skan{
13207117395Skan  /* This doesn't work with AOF syntax, since the string table may be in
13208117395Skan     a different AREA.  */
13209117395Skan#ifndef AOF_ASSEMBLER
13210117395Skan  if (optimize > 0 && TREE_CONSTANT (decl)
13211117395Skan      && (!flag_writable_strings || TREE_CODE (decl) != STRING_CST))
13212132718Skan    SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1;
13213117395Skan#endif
13214117395Skan
13215117395Skan  /* If we are referencing a function that is weak then encode a long call
13216117395Skan     flag in the function name, otherwise if the function is static or
13217117395Skan     or known to be defined in this file then encode a short call flag.  */
13218117395Skan  if (first && TREE_CODE_CLASS (TREE_CODE (decl)) == 'd')
13219117395Skan    {
13220117395Skan      if (TREE_CODE (decl) == FUNCTION_DECL && DECL_WEAK (decl))
13221117395Skan        arm_encode_call_attribute (decl, LONG_CALL_FLAG_CHAR);
13222117395Skan      else if (! TREE_PUBLIC (decl))
13223117395Skan        arm_encode_call_attribute (decl, SHORT_CALL_FLAG_CHAR);
13224117395Skan    }
13225117395Skan}
13226117395Skan#endif /* !ARM_PE */
13227117395Skan
13228132718Skanstatic void
13229132718Skanarm_internal_label (FILE *stream, const char *prefix, unsigned long labelno)
13230132718Skan{
13231132718Skan  if (arm_ccfsm_state == 3 && (unsigned) arm_target_label == labelno
13232132718Skan      && !strcmp (prefix, "L"))
13233132718Skan    {
13234132718Skan      arm_ccfsm_state = 0;
13235132718Skan      arm_target_insn = NULL;
13236132718Skan    }
13237132718Skan  default_internal_label (stream, prefix, labelno);
13238132718Skan}
13239132718Skan
13240117395Skan/* Output code to add DELTA to the first argument, and then jump
13241117395Skan   to FUNCTION.  Used for C++ multiple inheritance.  */
13242117395Skanstatic void
13243132718Skanarm_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
13244132718Skan		     HOST_WIDE_INT delta,
13245132718Skan		     HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED,
13246132718Skan		     tree function)
13247117395Skan{
13248132718Skan  static int thunk_label = 0;
13249132718Skan  char label[256];
13250117395Skan  int mi_delta = delta;
13251117395Skan  const char *const mi_op = mi_delta < 0 ? "sub" : "add";
13252117395Skan  int shift = 0;
13253132718Skan  int this_regno = (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function)
13254117395Skan                    ? 1 : 0);
13255117395Skan  if (mi_delta < 0)
13256117395Skan    mi_delta = - mi_delta;
13257132718Skan  if (TARGET_THUMB)
13258132718Skan    {
13259132718Skan      int labelno = thunk_label++;
13260132718Skan      ASM_GENERATE_INTERNAL_LABEL (label, "LTHUMBFUNC", labelno);
13261132718Skan      fputs ("\tldr\tr12, ", file);
13262132718Skan      assemble_name (file, label);
13263132718Skan      fputc ('\n', file);
13264132718Skan    }
13265117395Skan  while (mi_delta != 0)
13266117395Skan    {
13267117395Skan      if ((mi_delta & (3 << shift)) == 0)
13268117395Skan        shift += 2;
13269117395Skan      else
13270117395Skan        {
13271117395Skan          asm_fprintf (file, "\t%s\t%r, %r, #%d\n",
13272117395Skan                       mi_op, this_regno, this_regno,
13273117395Skan                       mi_delta & (0xff << shift));
13274117395Skan          mi_delta &= ~(0xff << shift);
13275117395Skan          shift += 8;
13276117395Skan        }
13277117395Skan    }
13278132718Skan  if (TARGET_THUMB)
13279132718Skan    {
13280132718Skan      fprintf (file, "\tbx\tr12\n");
13281132718Skan      ASM_OUTPUT_ALIGN (file, 2);
13282132718Skan      assemble_name (file, label);
13283132718Skan      fputs (":\n", file);
13284132718Skan      assemble_integer (XEXP (DECL_RTL (function), 0), 4, BITS_PER_WORD, 1);
13285132718Skan    }
13286132718Skan  else
13287132718Skan    {
13288132718Skan      fputs ("\tb\t", file);
13289132718Skan      assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0));
13290132718Skan      if (NEED_PLT_RELOC)
13291132718Skan        fputs ("(PLT)", file);
13292132718Skan      fputc ('\n', file);
13293132718Skan    }
13294117395Skan}
13295117395Skan
13296132718Skanint
13297132718Skanarm_emit_vector_const (FILE *file, rtx x)
13298132718Skan{
13299132718Skan  int i;
13300132718Skan  const char * pattern;
13301132718Skan
13302132718Skan  if (GET_CODE (x) != CONST_VECTOR)
13303132718Skan    abort ();
13304132718Skan
13305132718Skan  switch (GET_MODE (x))
13306132718Skan    {
13307132718Skan    case V2SImode: pattern = "%08x"; break;
13308132718Skan    case V4HImode: pattern = "%04x"; break;
13309132718Skan    case V8QImode: pattern = "%02x"; break;
13310132718Skan    default:       abort ();
13311132718Skan    }
13312132718Skan
13313132718Skan  fprintf (file, "0x");
13314132718Skan  for (i = CONST_VECTOR_NUNITS (x); i--;)
13315132718Skan    {
13316132718Skan      rtx element;
13317132718Skan
13318132718Skan      element = CONST_VECTOR_ELT (x, i);
13319132718Skan      fprintf (file, pattern, INTVAL (element));
13320132718Skan    }
13321132718Skan
13322132718Skan  return 1;
13323132718Skan}
13324132718Skan
13325132718Skanconst char *
13326132718Skanarm_output_load_gr (rtx *operands)
13327132718Skan{
13328132718Skan  rtx reg;
13329132718Skan  rtx offset;
13330132718Skan  rtx wcgr;
13331132718Skan  rtx sum;
13332132718Skan
13333132718Skan  if (GET_CODE (operands [1]) != MEM
13334132718Skan      || GET_CODE (sum = XEXP (operands [1], 0)) != PLUS
13335132718Skan      || GET_CODE (reg = XEXP (sum, 0)) != REG
13336132718Skan      || GET_CODE (offset = XEXP (sum, 1)) != CONST_INT
13337132718Skan      || ((INTVAL (offset) < 1024) && (INTVAL (offset) > -1024)))
13338132718Skan    return "wldrw%?\t%0, %1";
13339132718Skan
13340132718Skan  /* Fix up an out-of-range load of a GR register.  */
13341132718Skan  output_asm_insn ("str%?\t%0, [sp, #-4]!\t@ Start of GR load expansion", & reg);
13342132718Skan  wcgr = operands[0];
13343132718Skan  operands[0] = reg;
13344132718Skan  output_asm_insn ("ldr%?\t%0, %1", operands);
13345132718Skan
13346132718Skan  operands[0] = wcgr;
13347132718Skan  operands[1] = reg;
13348132718Skan  output_asm_insn ("tmcr%?\t%0, %1", operands);
13349132718Skan  output_asm_insn ("ldr%?\t%0, [sp], #4\t@ End of GR load expansion", & reg);
13350132718Skan
13351132718Skan  return "";
13352132718Skan}
13353