arm.c revision 227391
190075Sobrien/* Output routines for GCC for ARM.
2132718Skan   Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
3169689Skan   2002, 2003, 2004, 2005, 2006  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
22169689Skan   the Free Software Foundation, 51 Franklin Street, Fifth Floor,
23169689Skan   Boston, MA 02110-1301, USA.  */
24169689Skan
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"
54169689Skan#include "langhooks.h"
5590075Sobrien
5690075Sobrien/* Forward definitions of types.  */
5790075Sobrientypedef struct minipool_node    Mnode;
5890075Sobrientypedef struct minipool_fixup   Mfix;
5990075Sobrien
6090075Sobrienconst struct attribute_spec arm_attribute_table[];
6190075Sobrien
6290075Sobrien/* Forward function declarations.  */
63169689Skanstatic arm_stack_offsets *arm_get_frame_offsets (void);
64132718Skanstatic void arm_add_gc_roots (void);
65169689Skanstatic int arm_gen_constant (enum rtx_code, enum machine_mode, rtx,
66169689Skan			     HOST_WIDE_INT, rtx, rtx, int, int);
67132718Skanstatic unsigned bit_count (unsigned long);
68132718Skanstatic int arm_address_register_rtx_p (rtx, int);
69169689Skanstatic int arm_legitimate_index_p (enum machine_mode, rtx, RTX_CODE, int);
70132718Skanstatic int thumb_base_register_rtx_p (rtx, enum machine_mode, int);
71132718Skaninline static int thumb_index_register_rtx_p (rtx, int);
72169689Skanstatic int thumb_far_jump_used_p (void);
73169689Skanstatic bool thumb_force_lr_save (void);
74132718Skanstatic int const_ok_for_op (HOST_WIDE_INT, enum rtx_code);
75132718Skanstatic rtx emit_sfm (int, int);
76169689Skanstatic int arm_size_return_regs (void);
7790075Sobrien#ifndef AOF_ASSEMBLER
78132718Skanstatic bool arm_assemble_integer (rtx, unsigned int, int);
7990075Sobrien#endif
80132718Skanstatic const char *fp_const_from_val (REAL_VALUE_TYPE *);
81132718Skanstatic arm_cc get_arm_condition_code (rtx);
82132718Skanstatic HOST_WIDE_INT int_log2 (HOST_WIDE_INT);
83132718Skanstatic rtx is_jump_table (rtx);
84132718Skanstatic const char *output_multi_immediate (rtx *, const char *, const char *,
85132718Skan					   int, HOST_WIDE_INT);
86132718Skanstatic const char *shift_op (rtx, HOST_WIDE_INT *);
87132718Skanstatic struct machine_function *arm_init_machine_status (void);
88169689Skanstatic void thumb_exit (FILE *, int);
89132718Skanstatic rtx is_jump_table (rtx);
90132718Skanstatic HOST_WIDE_INT get_jump_table_size (rtx);
91132718Skanstatic Mnode *move_minipool_fix_forward_ref (Mnode *, Mnode *, HOST_WIDE_INT);
92132718Skanstatic Mnode *add_minipool_forward_ref (Mfix *);
93132718Skanstatic Mnode *move_minipool_fix_backward_ref (Mnode *, Mnode *, HOST_WIDE_INT);
94132718Skanstatic Mnode *add_minipool_backward_ref (Mfix *);
95132718Skanstatic void assign_minipool_offsets (Mfix *);
96132718Skanstatic void arm_print_value (FILE *, rtx);
97132718Skanstatic void dump_minipool (rtx);
98132718Skanstatic int arm_barrier_cost (rtx);
99132718Skanstatic Mfix *create_fix_barrier (Mfix *, HOST_WIDE_INT);
100132718Skanstatic void push_minipool_barrier (rtx, HOST_WIDE_INT);
101132718Skanstatic void push_minipool_fix (rtx, HOST_WIDE_INT, rtx *, enum machine_mode,
102132718Skan			       rtx);
103132718Skanstatic void arm_reorg (void);
104132718Skanstatic bool note_invalid_constants (rtx, HOST_WIDE_INT, int);
105132718Skanstatic int current_file_function_operand (rtx);
106132718Skanstatic unsigned long arm_compute_save_reg0_reg12_mask (void);
107132718Skanstatic unsigned long arm_compute_save_reg_mask (void);
108132718Skanstatic unsigned long arm_isr_value (tree);
109132718Skanstatic unsigned long arm_compute_func_type (void);
110132718Skanstatic tree arm_handle_fndecl_attribute (tree *, tree, tree, int, bool *);
111132718Skanstatic tree arm_handle_isr_attribute (tree *, tree, tree, int, bool *);
112169689Skan#if TARGET_DLLIMPORT_DECL_ATTRIBUTES
113169689Skanstatic tree arm_handle_notshared_attribute (tree *, tree, tree, int, bool *);
114169689Skan#endif
115132718Skanstatic void arm_output_function_epilogue (FILE *, HOST_WIDE_INT);
116132718Skanstatic void arm_output_function_prologue (FILE *, HOST_WIDE_INT);
117132718Skanstatic void thumb_output_function_prologue (FILE *, HOST_WIDE_INT);
118132718Skanstatic int arm_comp_type_attributes (tree, tree);
119132718Skanstatic void arm_set_default_type_attributes (tree);
120132718Skanstatic int arm_adjust_cost (rtx, rtx, rtx, int);
121132718Skanstatic int count_insns_for_constant (HOST_WIDE_INT, int);
122132718Skanstatic int arm_get_strip_length (int);
123132718Skanstatic bool arm_function_ok_for_sibcall (tree, tree);
124132718Skanstatic void arm_internal_label (FILE *, const char *, unsigned long);
125132718Skanstatic void arm_output_mi_thunk (FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT,
126132718Skan				 tree);
127132718Skanstatic int arm_rtx_costs_1 (rtx, enum rtx_code, enum rtx_code);
128169689Skanstatic bool arm_size_rtx_costs (rtx, int, int, int *);
129169689Skanstatic bool arm_slowmul_rtx_costs (rtx, int, int, int *);
130169689Skanstatic bool arm_fastmul_rtx_costs (rtx, int, int, int *);
131169689Skanstatic bool arm_xscale_rtx_costs (rtx, int, int, int *);
132169689Skanstatic bool arm_9e_rtx_costs (rtx, int, int, int *);
133132718Skanstatic int arm_address_cost (rtx);
134132718Skanstatic bool arm_memory_load_p (rtx);
135132718Skanstatic bool arm_cirrus_insn_p (rtx);
136132718Skanstatic void cirrus_reorg (rtx);
137132718Skanstatic void arm_init_builtins (void);
138132718Skanstatic rtx arm_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
139132718Skanstatic void arm_init_iwmmxt_builtins (void);
140132718Skanstatic rtx safe_vector_operand (rtx, enum machine_mode);
141132718Skanstatic rtx arm_expand_binop_builtin (enum insn_code, tree, rtx);
142132718Skanstatic rtx arm_expand_unop_builtin (enum insn_code, tree, rtx, int);
143132718Skanstatic rtx arm_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
144169689Skanstatic void emit_constant_insn (rtx cond, rtx pattern);
145169689Skanstatic rtx emit_set_insn (rtx, rtx);
146169689Skanstatic int arm_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,
147169689Skan				  tree, bool);
148132718Skan
14990075Sobrien#ifdef OBJECT_FORMAT_ELF
150169689Skanstatic void arm_elf_asm_constructor (rtx, int);
15190075Sobrien#endif
152117395Skan#ifndef ARM_PE
153132718Skanstatic void arm_encode_section_info (tree, rtx, int);
154117395Skan#endif
155169689Skan
156169689Skanstatic void arm_file_end (void);
157169689Skan
158117395Skan#ifdef AOF_ASSEMBLER
159132718Skanstatic void aof_globalize_label (FILE *, const char *);
160132718Skanstatic void aof_dump_imports (FILE *);
161132718Skanstatic void aof_dump_pic_table (FILE *);
162132718Skanstatic void aof_file_start (void);
163132718Skanstatic void aof_file_end (void);
164169689Skanstatic void aof_asm_init_sections (void);
165117395Skan#endif
166169689Skanstatic void arm_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode,
167169689Skan					tree, int *, int);
168169689Skanstatic bool arm_pass_by_reference (CUMULATIVE_ARGS *,
169169689Skan				   enum machine_mode, tree, bool);
170169689Skanstatic bool arm_promote_prototypes (tree);
171169689Skanstatic bool arm_default_short_enums (void);
172169689Skanstatic bool arm_align_anon_bitfield (void);
173169689Skanstatic bool arm_return_in_msb (tree);
174169689Skanstatic bool arm_must_pass_in_stack (enum machine_mode, tree);
175169689Skan#ifdef TARGET_UNWIND_INFO
176169689Skanstatic void arm_unwind_emit (FILE *, rtx);
177169689Skanstatic bool arm_output_ttype (rtx);
178169689Skan#endif
17990075Sobrien
180169689Skanstatic tree arm_cxx_guard_type (void);
181169689Skanstatic bool arm_cxx_guard_mask_bit (void);
182169689Skanstatic tree arm_get_cookie_size (tree);
183169689Skanstatic bool arm_cookie_has_size (void);
184169689Skanstatic bool arm_cxx_cdtor_returns_this (void);
185169689Skanstatic bool arm_cxx_key_method_may_be_inline (void);
186169689Skanstatic void arm_cxx_determine_class_data_visibility (tree);
187169689Skanstatic bool arm_cxx_class_data_always_comdat (void);
188169689Skanstatic bool arm_cxx_use_aeabi_atexit (void);
189169689Skanstatic void arm_init_libfuncs (void);
190169689Skanstatic bool arm_handle_option (size_t, const char *, int);
191169689Skanstatic unsigned HOST_WIDE_INT arm_shift_truncation_mask (enum machine_mode);
192169689Skanstatic bool arm_cannot_copy_insn_p (rtx);
193169689Skanstatic bool arm_tls_symbol_p (rtx x);
194169689Skan
19590075Sobrien
19690075Sobrien/* Initialize the GCC target structure.  */
197169689Skan#if TARGET_DLLIMPORT_DECL_ATTRIBUTES
19890075Sobrien#undef  TARGET_MERGE_DECL_ATTRIBUTES
19990075Sobrien#define TARGET_MERGE_DECL_ATTRIBUTES merge_dllimport_decl_attributes
20090075Sobrien#endif
20190075Sobrien
20290075Sobrien#undef  TARGET_ATTRIBUTE_TABLE
20390075Sobrien#define TARGET_ATTRIBUTE_TABLE arm_attribute_table
20490075Sobrien
205169689Skan#undef TARGET_ASM_FILE_END
206169689Skan#define TARGET_ASM_FILE_END arm_file_end
207169689Skan
20890075Sobrien#ifdef AOF_ASSEMBLER
20990075Sobrien#undef  TARGET_ASM_BYTE_OP
21090075Sobrien#define TARGET_ASM_BYTE_OP "\tDCB\t"
21190075Sobrien#undef  TARGET_ASM_ALIGNED_HI_OP
21290075Sobrien#define TARGET_ASM_ALIGNED_HI_OP "\tDCW\t"
21390075Sobrien#undef  TARGET_ASM_ALIGNED_SI_OP
21490075Sobrien#define TARGET_ASM_ALIGNED_SI_OP "\tDCD\t"
215117395Skan#undef TARGET_ASM_GLOBALIZE_LABEL
216117395Skan#define TARGET_ASM_GLOBALIZE_LABEL aof_globalize_label
217132718Skan#undef TARGET_ASM_FILE_START
218132718Skan#define TARGET_ASM_FILE_START aof_file_start
219132718Skan#undef TARGET_ASM_FILE_END
220132718Skan#define TARGET_ASM_FILE_END aof_file_end
22190075Sobrien#else
22290075Sobrien#undef  TARGET_ASM_ALIGNED_SI_OP
22390075Sobrien#define TARGET_ASM_ALIGNED_SI_OP NULL
22490075Sobrien#undef  TARGET_ASM_INTEGER
22590075Sobrien#define TARGET_ASM_INTEGER arm_assemble_integer
22690075Sobrien#endif
22790075Sobrien
22890075Sobrien#undef  TARGET_ASM_FUNCTION_PROLOGUE
22990075Sobrien#define TARGET_ASM_FUNCTION_PROLOGUE arm_output_function_prologue
23090075Sobrien
23190075Sobrien#undef  TARGET_ASM_FUNCTION_EPILOGUE
23290075Sobrien#define TARGET_ASM_FUNCTION_EPILOGUE arm_output_function_epilogue
23390075Sobrien
234169689Skan#undef  TARGET_DEFAULT_TARGET_FLAGS
235169689Skan#define TARGET_DEFAULT_TARGET_FLAGS (TARGET_DEFAULT | MASK_SCHED_PROLOG)
236169689Skan#undef  TARGET_HANDLE_OPTION
237169689Skan#define TARGET_HANDLE_OPTION arm_handle_option
238169689Skan
23990075Sobrien#undef  TARGET_COMP_TYPE_ATTRIBUTES
24090075Sobrien#define TARGET_COMP_TYPE_ATTRIBUTES arm_comp_type_attributes
24190075Sobrien
24290075Sobrien#undef  TARGET_SET_DEFAULT_TYPE_ATTRIBUTES
24390075Sobrien#define TARGET_SET_DEFAULT_TYPE_ATTRIBUTES arm_set_default_type_attributes
24490075Sobrien
24590075Sobrien#undef  TARGET_SCHED_ADJUST_COST
24690075Sobrien#define TARGET_SCHED_ADJUST_COST arm_adjust_cost
24790075Sobrien
248117395Skan#undef TARGET_ENCODE_SECTION_INFO
249117395Skan#ifdef ARM_PE
250117395Skan#define TARGET_ENCODE_SECTION_INFO  arm_pe_encode_section_info
251117395Skan#else
252117395Skan#define TARGET_ENCODE_SECTION_INFO  arm_encode_section_info
253117395Skan#endif
254117395Skan
255132718Skan#undef  TARGET_STRIP_NAME_ENCODING
256117395Skan#define TARGET_STRIP_NAME_ENCODING arm_strip_name_encoding
257117395Skan
258132718Skan#undef  TARGET_ASM_INTERNAL_LABEL
259132718Skan#define TARGET_ASM_INTERNAL_LABEL arm_internal_label
260132718Skan
261132718Skan#undef  TARGET_FUNCTION_OK_FOR_SIBCALL
262132718Skan#define TARGET_FUNCTION_OK_FOR_SIBCALL arm_function_ok_for_sibcall
263132718Skan
264132718Skan#undef  TARGET_ASM_OUTPUT_MI_THUNK
265117395Skan#define TARGET_ASM_OUTPUT_MI_THUNK arm_output_mi_thunk
266132718Skan#undef  TARGET_ASM_CAN_OUTPUT_MI_THUNK
267117395Skan#define TARGET_ASM_CAN_OUTPUT_MI_THUNK default_can_output_mi_thunk_no_vcall
268117395Skan
269169689Skan/* This will be overridden in arm_override_options.  */
270132718Skan#undef  TARGET_RTX_COSTS
271169689Skan#define TARGET_RTX_COSTS arm_slowmul_rtx_costs
272132718Skan#undef  TARGET_ADDRESS_COST
273132718Skan#define TARGET_ADDRESS_COST arm_address_cost
274132718Skan
275169689Skan#undef TARGET_SHIFT_TRUNCATION_MASK
276169689Skan#define TARGET_SHIFT_TRUNCATION_MASK arm_shift_truncation_mask
277169689Skan#undef TARGET_VECTOR_MODE_SUPPORTED_P
278169689Skan#define TARGET_VECTOR_MODE_SUPPORTED_P arm_vector_mode_supported_p
279169689Skan
280132718Skan#undef  TARGET_MACHINE_DEPENDENT_REORG
281132718Skan#define TARGET_MACHINE_DEPENDENT_REORG arm_reorg
282132718Skan
283132718Skan#undef  TARGET_INIT_BUILTINS
284132718Skan#define TARGET_INIT_BUILTINS  arm_init_builtins
285132718Skan#undef  TARGET_EXPAND_BUILTIN
286132718Skan#define TARGET_EXPAND_BUILTIN arm_expand_builtin
287132718Skan
288169689Skan#undef TARGET_INIT_LIBFUNCS
289169689Skan#define TARGET_INIT_LIBFUNCS arm_init_libfuncs
290169689Skan
291169689Skan#undef TARGET_PROMOTE_FUNCTION_ARGS
292169689Skan#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true
293169689Skan#undef TARGET_PROMOTE_FUNCTION_RETURN
294169689Skan#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
295169689Skan#undef TARGET_PROMOTE_PROTOTYPES
296169689Skan#define TARGET_PROMOTE_PROTOTYPES arm_promote_prototypes
297169689Skan#undef TARGET_PASS_BY_REFERENCE
298169689Skan#define TARGET_PASS_BY_REFERENCE arm_pass_by_reference
299169689Skan#undef TARGET_ARG_PARTIAL_BYTES
300169689Skan#define TARGET_ARG_PARTIAL_BYTES arm_arg_partial_bytes
301169689Skan
302169689Skan#undef  TARGET_SETUP_INCOMING_VARARGS
303169689Skan#define TARGET_SETUP_INCOMING_VARARGS arm_setup_incoming_varargs
304169689Skan
305169689Skan#undef TARGET_DEFAULT_SHORT_ENUMS
306169689Skan#define TARGET_DEFAULT_SHORT_ENUMS arm_default_short_enums
307169689Skan
308169689Skan#undef TARGET_ALIGN_ANON_BITFIELD
309169689Skan#define TARGET_ALIGN_ANON_BITFIELD arm_align_anon_bitfield
310169689Skan
311169689Skan#undef TARGET_NARROW_VOLATILE_BITFIELD
312169689Skan#define TARGET_NARROW_VOLATILE_BITFIELD hook_bool_void_false
313169689Skan
314169689Skan#undef TARGET_CXX_GUARD_TYPE
315169689Skan#define TARGET_CXX_GUARD_TYPE arm_cxx_guard_type
316169689Skan
317169689Skan#undef TARGET_CXX_GUARD_MASK_BIT
318169689Skan#define TARGET_CXX_GUARD_MASK_BIT arm_cxx_guard_mask_bit
319169689Skan
320169689Skan#undef TARGET_CXX_GET_COOKIE_SIZE
321169689Skan#define TARGET_CXX_GET_COOKIE_SIZE arm_get_cookie_size
322169689Skan
323169689Skan#undef TARGET_CXX_COOKIE_HAS_SIZE
324169689Skan#define TARGET_CXX_COOKIE_HAS_SIZE arm_cookie_has_size
325169689Skan
326169689Skan#undef TARGET_CXX_CDTOR_RETURNS_THIS
327169689Skan#define TARGET_CXX_CDTOR_RETURNS_THIS arm_cxx_cdtor_returns_this
328169689Skan
329169689Skan#undef TARGET_CXX_KEY_METHOD_MAY_BE_INLINE
330169689Skan#define TARGET_CXX_KEY_METHOD_MAY_BE_INLINE arm_cxx_key_method_may_be_inline
331169689Skan
332169689Skan#undef TARGET_CXX_USE_AEABI_ATEXIT
333169689Skan#define TARGET_CXX_USE_AEABI_ATEXIT arm_cxx_use_aeabi_atexit
334169689Skan
335169689Skan#undef TARGET_CXX_DETERMINE_CLASS_DATA_VISIBILITY
336169689Skan#define TARGET_CXX_DETERMINE_CLASS_DATA_VISIBILITY \
337169689Skan  arm_cxx_determine_class_data_visibility
338169689Skan
339169689Skan#undef TARGET_CXX_CLASS_DATA_ALWAYS_COMDAT
340169689Skan#define TARGET_CXX_CLASS_DATA_ALWAYS_COMDAT arm_cxx_class_data_always_comdat
341169689Skan
342169689Skan#undef TARGET_RETURN_IN_MSB
343169689Skan#define TARGET_RETURN_IN_MSB arm_return_in_msb
344169689Skan
345169689Skan#undef TARGET_MUST_PASS_IN_STACK
346169689Skan#define TARGET_MUST_PASS_IN_STACK arm_must_pass_in_stack
347169689Skan
348169689Skan#ifdef TARGET_UNWIND_INFO
349169689Skan#undef TARGET_UNWIND_EMIT
350169689Skan#define TARGET_UNWIND_EMIT arm_unwind_emit
351169689Skan
352169689Skan/* EABI unwinding tables use a different format for the typeinfo tables.  */
353169689Skan#undef TARGET_ASM_TTYPE
354169689Skan#define TARGET_ASM_TTYPE arm_output_ttype
355169689Skan
356169689Skan#undef TARGET_ARM_EABI_UNWINDER
357169689Skan#define TARGET_ARM_EABI_UNWINDER true
358169689Skan#endif /* TARGET_UNWIND_INFO */
359169689Skan
360169689Skan#undef  TARGET_CANNOT_COPY_INSN_P
361169689Skan#define TARGET_CANNOT_COPY_INSN_P arm_cannot_copy_insn_p
362169689Skan
363169689Skan#ifdef HAVE_AS_TLS
364169689Skan#undef TARGET_HAVE_TLS
365169689Skan#define TARGET_HAVE_TLS true
366169689Skan#endif
367169689Skan
368169689Skan#undef TARGET_CANNOT_FORCE_CONST_MEM
369169689Skan#define TARGET_CANNOT_FORCE_CONST_MEM arm_tls_referenced_p
370169689Skan
37190075Sobrienstruct gcc_target targetm = TARGET_INITIALIZER;
37290075Sobrien
37390075Sobrien/* Obstack for minipool constant handling.  */
37490075Sobrienstatic struct obstack minipool_obstack;
37590075Sobrienstatic char *         minipool_startobj;
37690075Sobrien
37790075Sobrien/* The maximum number of insns skipped which
37890075Sobrien   will be conditionalised if possible.  */
37990075Sobrienstatic int max_insns_skipped = 5;
38090075Sobrien
38190075Sobrienextern FILE * asm_out_file;
38290075Sobrien
38390075Sobrien/* True if we are currently building a constant table.  */
38490075Sobrienint making_const_table;
38590075Sobrien
38690075Sobrien/* Define the information needed to generate branch insns.  This is
38790075Sobrien   stored from the compare operation.  */
38890075Sobrienrtx arm_compare_op0, arm_compare_op1;
38990075Sobrien
390169689Skan/* The processor for which instructions should be scheduled.  */
391169689Skanenum processor_type arm_tune = arm_none;
39290075Sobrien
393169689Skan/* Which floating point model to use.  */
394169689Skanenum arm_fp_model arm_fp_model;
395169689Skan
396169689Skan/* Which floating point hardware is available.  */
397132718Skanenum fputype arm_fpu_arch;
39890075Sobrien
399169689Skan/* Which floating point hardware to schedule for.  */
400169689Skanenum fputype arm_fpu_tune;
40190075Sobrien
402169689Skan/* Whether to use floating point hardware.  */
403169689Skanenum float_abi_type arm_float_abi;
40490075Sobrien
405169689Skan/* Which ABI to use.  */
406169689Skanenum arm_abi_type arm_abi;
407169689Skan
408169689Skan/* Which thread pointer model to use.  */
409169689Skanenum arm_tp_type target_thread_pointer = TP_AUTO;
410169689Skan
41190075Sobrien/* Used to parse -mstructure_size_boundary command line option.  */
41290075Sobrienint    arm_structure_size_boundary = DEFAULT_STRUCTURE_SIZE_BOUNDARY;
41390075Sobrien
414169689Skan/* Used for Thumb call_via trampolines.  */
415169689Skanrtx thumb_call_via_label[14];
416169689Skanstatic int thumb_call_reg_needed;
417169689Skan
41890075Sobrien/* Bit values used to identify processor capabilities.  */
41990075Sobrien#define FL_CO_PROC    (1 << 0)        /* Has external co-processor bus */
420169689Skan#define FL_ARCH3M     (1 << 1)        /* Extended multiply */
42190075Sobrien#define FL_MODE26     (1 << 2)        /* 26-bit mode support */
42290075Sobrien#define FL_MODE32     (1 << 3)        /* 32-bit mode support */
42390075Sobrien#define FL_ARCH4      (1 << 4)        /* Architecture rel 4 */
42490075Sobrien#define FL_ARCH5      (1 << 5)        /* Architecture rel 5 */
42590075Sobrien#define FL_THUMB      (1 << 6)        /* Thumb aware */
42690075Sobrien#define FL_LDSCHED    (1 << 7)	      /* Load scheduling necessary */
42790075Sobrien#define FL_STRONG     (1 << 8)	      /* StrongARM */
428132718Skan#define FL_ARCH5E     (1 << 9)        /* DSP extensions to v5 */
42990075Sobrien#define FL_XSCALE     (1 << 10)	      /* XScale */
430132718Skan#define FL_CIRRUS     (1 << 11)	      /* Cirrus/DSP.  */
431169689Skan#define FL_ARCH6      (1 << 12)       /* Architecture rel 6.  Adds
432132718Skan					 media instructions.  */
433132718Skan#define FL_VFPV2      (1 << 13)       /* Vector Floating Point V2.  */
434169689Skan#define FL_WBUF	      (1 << 14)	      /* Schedule for write buffer ops.
435169689Skan					 Note: ARM6 & 7 derivatives only.  */
436169689Skan#define FL_ARCH6K     (1 << 15)       /* Architecture rel 6 K extensions.  */
43790075Sobrien
438169689Skan#define FL_IWMMXT     (1 << 29)	      /* XScale v2 or "Intel Wireless MMX technology".  */
439169689Skan
440169689Skan#define FL_FOR_ARCH2	0
441169689Skan#define FL_FOR_ARCH3	FL_MODE32
442169689Skan#define FL_FOR_ARCH3M	(FL_FOR_ARCH3 | FL_ARCH3M)
443169689Skan#define FL_FOR_ARCH4	(FL_FOR_ARCH3M | FL_ARCH4)
444169689Skan#define FL_FOR_ARCH4T	(FL_FOR_ARCH4 | FL_THUMB)
445169689Skan#define FL_FOR_ARCH5	(FL_FOR_ARCH4 | FL_ARCH5)
446169689Skan#define FL_FOR_ARCH5T	(FL_FOR_ARCH5 | FL_THUMB)
447169689Skan#define FL_FOR_ARCH5E	(FL_FOR_ARCH5 | FL_ARCH5E)
448169689Skan#define FL_FOR_ARCH5TE	(FL_FOR_ARCH5E | FL_THUMB)
449169689Skan#define FL_FOR_ARCH5TEJ	FL_FOR_ARCH5TE
450169689Skan#define FL_FOR_ARCH6	(FL_FOR_ARCH5TE | FL_ARCH6)
451169689Skan#define FL_FOR_ARCH6J	FL_FOR_ARCH6
452169689Skan#define FL_FOR_ARCH6K	(FL_FOR_ARCH6 | FL_ARCH6K)
453169689Skan#define FL_FOR_ARCH6Z	FL_FOR_ARCH6
454169689Skan#define FL_FOR_ARCH6ZK	FL_FOR_ARCH6K
455169689Skan
45690075Sobrien/* The bits in this mask specify which
45790075Sobrien   instructions we are allowed to generate.  */
458117395Skanstatic unsigned long insn_flags = 0;
45990075Sobrien
46090075Sobrien/* The bits in this mask specify which instruction scheduling options should
461169689Skan   be used.  */
462117395Skanstatic unsigned long tune_flags = 0;
46390075Sobrien
46490075Sobrien/* The following are used in the arm.md file as equivalents to bits
46590075Sobrien   in the above two flag variables.  */
46690075Sobrien
467169689Skan/* Nonzero if this chip supports the ARM Architecture 3M extensions.  */
468169689Skanint arm_arch3m = 0;
46990075Sobrien
47090075Sobrien/* Nonzero if this chip supports the ARM Architecture 4 extensions.  */
47190075Sobrienint arm_arch4 = 0;
47290075Sobrien
473169689Skan/* Nonzero if this chip supports the ARM Architecture 4t extensions.  */
474169689Skanint arm_arch4t = 0;
475169689Skan
47690075Sobrien/* Nonzero if this chip supports the ARM Architecture 5 extensions.  */
47790075Sobrienint arm_arch5 = 0;
47890075Sobrien
47990075Sobrien/* Nonzero if this chip supports the ARM Architecture 5E extensions.  */
48090075Sobrienint arm_arch5e = 0;
48190075Sobrien
482169689Skan/* Nonzero if this chip supports the ARM Architecture 6 extensions.  */
483169689Skanint arm_arch6 = 0;
484169689Skan
485169689Skan/* Nonzero if this chip supports the ARM 6K extensions.  */
486169689Skanint arm_arch6k = 0;
487169689Skan
48890075Sobrien/* Nonzero if this chip can benefit from load scheduling.  */
48990075Sobrienint arm_ld_sched = 0;
49090075Sobrien
49190075Sobrien/* Nonzero if this chip is a StrongARM.  */
492169689Skanint arm_tune_strongarm = 0;
49390075Sobrien
494169689Skan/* Nonzero if this chip is a Cirrus variant.  */
495169689Skanint arm_arch_cirrus = 0;
496169689Skan
497132718Skan/* Nonzero if this chip supports Intel Wireless MMX technology.  */
498132718Skanint arm_arch_iwmmxt = 0;
499132718Skan
50090075Sobrien/* Nonzero if this chip is an XScale.  */
501132718Skanint arm_arch_xscale = 0;
50290075Sobrien
503132718Skan/* Nonzero if tuning for XScale  */
504132718Skanint arm_tune_xscale = 0;
505132718Skan
506169689Skan/* Nonzero if we want to tune for stores that access the write-buffer.
507169689Skan   This typically means an ARM6 or ARM7 with MMU or MPU.  */
508169689Skanint arm_tune_wbuf = 0;
50990075Sobrien
51090075Sobrien/* Nonzero if generating Thumb instructions.  */
51190075Sobrienint thumb_code = 0;
51290075Sobrien
513169689Skan/* Nonzero if we should define __THUMB_INTERWORK__ in the
514169689Skan   preprocessor.
515169689Skan   XXX This is a bit of a hack, it's intended to help work around
516169689Skan   problems in GLD which doesn't understand that armv5t code is
517169689Skan   interworking clean.  */
518169689Skanint arm_cpp_interwork = 0;
519169689Skan
52090075Sobrien/* In case of a PRE_INC, POST_INC, PRE_DEC, POST_DEC memory reference, we
52190075Sobrien   must report the mode of the memory reference from PRINT_OPERAND to
52290075Sobrien   PRINT_OPERAND_ADDRESS.  */
52390075Sobrienenum machine_mode output_memory_reference_mode;
52490075Sobrien
52590075Sobrien/* The register number to be used for the PIC offset register.  */
526169689Skanunsigned arm_pic_register = INVALID_REGNUM;
52790075Sobrien
52890075Sobrien/* Set to 1 when a return insn is output, this means that the epilogue
52990075Sobrien   is not needed.  */
53090075Sobrienint return_used_this_function;
53190075Sobrien
53290075Sobrien/* Set to 1 after arm_reorg has started.  Reset to start at the start of
53390075Sobrien   the next function.  */
53490075Sobrienstatic int after_arm_reorg = 0;
53590075Sobrien
53690075Sobrien/* The maximum number of insns to be used when loading a constant.  */
53790075Sobrienstatic int arm_constant_limit = 3;
53890075Sobrien
53990075Sobrien/* For an explanation of these variables, see final_prescan_insn below.  */
54090075Sobrienint arm_ccfsm_state;
54190075Sobrienenum arm_cond_code arm_current_cc;
54290075Sobrienrtx arm_target_insn;
54390075Sobrienint arm_target_label;
54490075Sobrien
54590075Sobrien/* The condition codes of the ARM, and the inverse function.  */
54690075Sobrienstatic const char * const arm_condition_codes[] =
54790075Sobrien{
54890075Sobrien  "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
54990075Sobrien  "hi", "ls", "ge", "lt", "gt", "le", "al", "nv"
55090075Sobrien};
55190075Sobrien
55290075Sobrien#define streq(string1, string2) (strcmp (string1, string2) == 0)
55390075Sobrien
55490075Sobrien/* Initialization code.  */
55590075Sobrien
55690075Sobrienstruct processors
55790075Sobrien{
55890075Sobrien  const char *const name;
559169689Skan  enum processor_type core;
560169689Skan  const char *arch;
561117395Skan  const unsigned long flags;
562169689Skan  bool (* rtx_costs) (rtx, int, int, int *);
56390075Sobrien};
56490075Sobrien
56590075Sobrien/* Not all of these give usefully different compilation alternatives,
56690075Sobrien   but there is no simple way of generalizing them.  */
56790075Sobrienstatic const struct processors all_cores[] =
56890075Sobrien{
56990075Sobrien  /* ARM Cores */
570169689Skan#define ARM_CORE(NAME, IDENT, ARCH, FLAGS, COSTS) \
571169689Skan  {NAME, arm_none, #ARCH, FLAGS | FL_FOR_ARCH##ARCH, arm_##COSTS##_rtx_costs},
572169689Skan#include "arm-cores.def"
573169689Skan#undef ARM_CORE
574169689Skan  {NULL, arm_none, NULL, 0, NULL}
57590075Sobrien};
57690075Sobrien
57790075Sobrienstatic const struct processors all_architectures[] =
57890075Sobrien{
57990075Sobrien  /* ARM Architectures */
580169689Skan  /* We don't specify rtx_costs here as it will be figured out
581169689Skan     from the core.  */
582169689Skan
583169689Skan  {"armv2",   arm2,       "2",   FL_CO_PROC | FL_MODE26 | FL_FOR_ARCH2, NULL},
584169689Skan  {"armv2a",  arm2,       "2",   FL_CO_PROC | FL_MODE26 | FL_FOR_ARCH2, NULL},
585169689Skan  {"armv3",   arm6,       "3",   FL_CO_PROC | FL_MODE26 | FL_FOR_ARCH3, NULL},
586169689Skan  {"armv3m",  arm7m,      "3M",  FL_CO_PROC | FL_MODE26 | FL_FOR_ARCH3M, NULL},
587169689Skan  {"armv4",   arm7tdmi,   "4",   FL_CO_PROC | FL_MODE26 | FL_FOR_ARCH4, NULL},
58890075Sobrien  /* Strictly, FL_MODE26 is a permitted option for v4t, but there are no
58990075Sobrien     implementations that support it, so we will leave it out for now.  */
590169689Skan  {"armv4t",  arm7tdmi,   "4T",  FL_CO_PROC |             FL_FOR_ARCH4T, NULL},
591169689Skan  {"armv5",   arm10tdmi,  "5",   FL_CO_PROC |             FL_FOR_ARCH5, NULL},
592169689Skan  {"armv5t",  arm10tdmi,  "5T",  FL_CO_PROC |             FL_FOR_ARCH5T, NULL},
593169689Skan  {"armv5e",  arm1026ejs, "5E",  FL_CO_PROC |             FL_FOR_ARCH5E, NULL},
594169689Skan  {"armv5te", arm1026ejs, "5TE", FL_CO_PROC |             FL_FOR_ARCH5TE, NULL},
595169689Skan  {"armv6",   arm1136js,  "6",   FL_CO_PROC |             FL_FOR_ARCH6, NULL},
596169689Skan  {"armv6j",  arm1136js,  "6J",  FL_CO_PROC |             FL_FOR_ARCH6J, NULL},
597169689Skan  {"armv6k",  mpcore,	  "6K",  FL_CO_PROC |             FL_FOR_ARCH6K, NULL},
598169689Skan  {"armv6z",  arm1176jzs, "6Z",  FL_CO_PROC |             FL_FOR_ARCH6Z, NULL},
599169689Skan  {"armv6zk", arm1176jzs, "6ZK", FL_CO_PROC |             FL_FOR_ARCH6ZK, NULL},
600169689Skan  {"ep9312",  ep9312,     "4T",  FL_LDSCHED | FL_CIRRUS | FL_FOR_ARCH4, NULL},
601169689Skan  {"iwmmxt",  iwmmxt,     "5TE", FL_LDSCHED | FL_STRONG | FL_FOR_ARCH5TE | FL_XSCALE | FL_IWMMXT , NULL},
602169689Skan  {NULL, arm_none, NULL, 0 , NULL}
60390075Sobrien};
60490075Sobrien
605169689Skanstruct arm_cpu_select
606169689Skan{
607169689Skan  const char *              string;
608169689Skan  const char *              name;
609169689Skan  const struct processors * processors;
610169689Skan};
611169689Skan
612132718Skan/* This is a magic structure.  The 'string' field is magically filled in
61390075Sobrien   with a pointer to the value specified by the user on the command line
61490075Sobrien   assuming that the user has specified such a value.  */
61590075Sobrien
616169689Skanstatic struct arm_cpu_select arm_select[] =
61790075Sobrien{
618169689Skan  /* string	  name            processors  */
61990075Sobrien  { NULL,	"-mcpu=",	all_cores  },
62090075Sobrien  { NULL,	"-march=",	all_architectures },
62190075Sobrien  { NULL,	"-mtune=",	all_cores }
62290075Sobrien};
62390075Sobrien
624169689Skan/* Defines representing the indexes into the above table.  */
625169689Skan#define ARM_OPT_SET_CPU 0
626169689Skan#define ARM_OPT_SET_ARCH 1
627169689Skan#define ARM_OPT_SET_TUNE 2
628169689Skan
629169689Skan/* The name of the preprocessor macro to define for this architecture.  */
630169689Skan
631169689Skanchar arm_arch_name[] = "__ARM_ARCH_0UNK__";
632169689Skan
633169689Skanstruct fpu_desc
634169689Skan{
635169689Skan  const char * name;
636169689Skan  enum fputype fpu;
637169689Skan};
638169689Skan
639169689Skan
640169689Skan/* Available values for -mfpu=.  */
641169689Skan
642169689Skanstatic const struct fpu_desc all_fpus[] =
643169689Skan{
644169689Skan  {"fpa",	FPUTYPE_FPA},
645169689Skan  {"fpe2",	FPUTYPE_FPA_EMU2},
646169689Skan  {"fpe3",	FPUTYPE_FPA_EMU2},
647169689Skan  {"maverick",	FPUTYPE_MAVERICK},
648169689Skan  {"vfp",	FPUTYPE_VFP}
649169689Skan};
650169689Skan
651169689Skan
652169689Skan/* Floating point models used by the different hardware.
653169689Skan   See fputype in arm.h.  */
654169689Skan
655169689Skanstatic const enum fputype fp_model_for_fpu[] =
656169689Skan{
657169689Skan  /* No FP hardware.  */
658169689Skan  ARM_FP_MODEL_UNKNOWN,		/* FPUTYPE_NONE  */
659169689Skan  ARM_FP_MODEL_FPA,		/* FPUTYPE_FPA  */
660169689Skan  ARM_FP_MODEL_FPA,		/* FPUTYPE_FPA_EMU2  */
661169689Skan  ARM_FP_MODEL_FPA,		/* FPUTYPE_FPA_EMU3  */
662169689Skan  ARM_FP_MODEL_MAVERICK,	/* FPUTYPE_MAVERICK  */
663169689Skan  ARM_FP_MODEL_VFP		/* FPUTYPE_VFP  */
664169689Skan};
665169689Skan
666169689Skan
667169689Skanstruct float_abi
668169689Skan{
669169689Skan  const char * name;
670169689Skan  enum float_abi_type abi_type;
671169689Skan};
672169689Skan
673169689Skan
674169689Skan/* Available values for -mfloat-abi=.  */
675169689Skan
676169689Skanstatic const struct float_abi all_float_abis[] =
677169689Skan{
678169689Skan  {"soft",	ARM_FLOAT_ABI_SOFT},
679169689Skan  {"softfp",	ARM_FLOAT_ABI_SOFTFP},
680169689Skan  {"hard",	ARM_FLOAT_ABI_HARD}
681169689Skan};
682169689Skan
683169689Skan
684169689Skanstruct abi_name
685169689Skan{
686169689Skan  const char *name;
687169689Skan  enum arm_abi_type abi_type;
688169689Skan};
689169689Skan
690169689Skan
691169689Skan/* Available values for -mabi=.  */
692169689Skan
693169689Skanstatic const struct abi_name arm_all_abis[] =
694169689Skan{
695169689Skan  {"apcs-gnu",    ARM_ABI_APCS},
696169689Skan  {"atpcs",   ARM_ABI_ATPCS},
697169689Skan  {"aapcs",   ARM_ABI_AAPCS},
698169689Skan  {"iwmmxt",  ARM_ABI_IWMMXT},
699169689Skan  {"aapcs-linux",   ARM_ABI_AAPCS_LINUX}
700169689Skan};
701169689Skan
702169689Skan/* Supported TLS relocations.  */
703169689Skan
704169689Skanenum tls_reloc {
705169689Skan  TLS_GD32,
706169689Skan  TLS_LDM32,
707169689Skan  TLS_LDO32,
708169689Skan  TLS_IE32,
709169689Skan  TLS_LE32
710169689Skan};
711169689Skan
712169689Skan/* Emit an insn that's a simple single-set.  Both the operands must be known
713169689Skan   to be valid.  */
714169689Skaninline static rtx
715169689Skanemit_set_insn (rtx x, rtx y)
716169689Skan{
717169689Skan  return emit_insn (gen_rtx_SET (VOIDmode, x, y));
718169689Skan}
719169689Skan
720117395Skan/* Return the number of bits set in VALUE.  */
721117395Skanstatic unsigned
722132718Skanbit_count (unsigned long value)
72390075Sobrien{
72490075Sobrien  unsigned long count = 0;
725169689Skan
72690075Sobrien  while (value)
72790075Sobrien    {
728117395Skan      count++;
729117395Skan      value &= value - 1;  /* Clear the least-significant set bit.  */
73090075Sobrien    }
73190075Sobrien
73290075Sobrien  return count;
73390075Sobrien}
73490075Sobrien
735169689Skan/* Set up library functions unique to ARM.  */
736169689Skan
737169689Skanstatic void
738169689Skanarm_init_libfuncs (void)
739169689Skan{
740169689Skan  /* There are no special library functions unless we are using the
741169689Skan     ARM BPABI.  */
742169689Skan  if (!TARGET_BPABI)
743169689Skan    return;
744169689Skan
745169689Skan  /* The functions below are described in Section 4 of the "Run-Time
746169689Skan     ABI for the ARM architecture", Version 1.0.  */
747169689Skan
748169689Skan  /* Double-precision floating-point arithmetic.  Table 2.  */
749169689Skan  set_optab_libfunc (add_optab, DFmode, "__aeabi_dadd");
750169689Skan  set_optab_libfunc (sdiv_optab, DFmode, "__aeabi_ddiv");
751169689Skan  set_optab_libfunc (smul_optab, DFmode, "__aeabi_dmul");
752169689Skan  set_optab_libfunc (neg_optab, DFmode, "__aeabi_dneg");
753169689Skan  set_optab_libfunc (sub_optab, DFmode, "__aeabi_dsub");
754169689Skan
755169689Skan  /* Double-precision comparisons.  Table 3.  */
756169689Skan  set_optab_libfunc (eq_optab, DFmode, "__aeabi_dcmpeq");
757169689Skan  set_optab_libfunc (ne_optab, DFmode, NULL);
758169689Skan  set_optab_libfunc (lt_optab, DFmode, "__aeabi_dcmplt");
759169689Skan  set_optab_libfunc (le_optab, DFmode, "__aeabi_dcmple");
760169689Skan  set_optab_libfunc (ge_optab, DFmode, "__aeabi_dcmpge");
761169689Skan  set_optab_libfunc (gt_optab, DFmode, "__aeabi_dcmpgt");
762169689Skan  set_optab_libfunc (unord_optab, DFmode, "__aeabi_dcmpun");
763169689Skan
764169689Skan  /* Single-precision floating-point arithmetic.  Table 4.  */
765169689Skan  set_optab_libfunc (add_optab, SFmode, "__aeabi_fadd");
766169689Skan  set_optab_libfunc (sdiv_optab, SFmode, "__aeabi_fdiv");
767169689Skan  set_optab_libfunc (smul_optab, SFmode, "__aeabi_fmul");
768169689Skan  set_optab_libfunc (neg_optab, SFmode, "__aeabi_fneg");
769169689Skan  set_optab_libfunc (sub_optab, SFmode, "__aeabi_fsub");
770169689Skan
771169689Skan  /* Single-precision comparisons.  Table 5.  */
772169689Skan  set_optab_libfunc (eq_optab, SFmode, "__aeabi_fcmpeq");
773169689Skan  set_optab_libfunc (ne_optab, SFmode, NULL);
774169689Skan  set_optab_libfunc (lt_optab, SFmode, "__aeabi_fcmplt");
775169689Skan  set_optab_libfunc (le_optab, SFmode, "__aeabi_fcmple");
776169689Skan  set_optab_libfunc (ge_optab, SFmode, "__aeabi_fcmpge");
777169689Skan  set_optab_libfunc (gt_optab, SFmode, "__aeabi_fcmpgt");
778169689Skan  set_optab_libfunc (unord_optab, SFmode, "__aeabi_fcmpun");
779169689Skan
780169689Skan  /* Floating-point to integer conversions.  Table 6.  */
781169689Skan  set_conv_libfunc (sfix_optab, SImode, DFmode, "__aeabi_d2iz");
782169689Skan  set_conv_libfunc (ufix_optab, SImode, DFmode, "__aeabi_d2uiz");
783169689Skan  set_conv_libfunc (sfix_optab, DImode, DFmode, "__aeabi_d2lz");
784169689Skan  set_conv_libfunc (ufix_optab, DImode, DFmode, "__aeabi_d2ulz");
785169689Skan  set_conv_libfunc (sfix_optab, SImode, SFmode, "__aeabi_f2iz");
786169689Skan  set_conv_libfunc (ufix_optab, SImode, SFmode, "__aeabi_f2uiz");
787169689Skan  set_conv_libfunc (sfix_optab, DImode, SFmode, "__aeabi_f2lz");
788169689Skan  set_conv_libfunc (ufix_optab, DImode, SFmode, "__aeabi_f2ulz");
789169689Skan
790169689Skan  /* Conversions between floating types.  Table 7.  */
791169689Skan  set_conv_libfunc (trunc_optab, SFmode, DFmode, "__aeabi_d2f");
792169689Skan  set_conv_libfunc (sext_optab, DFmode, SFmode, "__aeabi_f2d");
793169689Skan
794169689Skan  /* Integer to floating-point conversions.  Table 8.  */
795169689Skan  set_conv_libfunc (sfloat_optab, DFmode, SImode, "__aeabi_i2d");
796169689Skan  set_conv_libfunc (ufloat_optab, DFmode, SImode, "__aeabi_ui2d");
797169689Skan  set_conv_libfunc (sfloat_optab, DFmode, DImode, "__aeabi_l2d");
798169689Skan  set_conv_libfunc (ufloat_optab, DFmode, DImode, "__aeabi_ul2d");
799169689Skan  set_conv_libfunc (sfloat_optab, SFmode, SImode, "__aeabi_i2f");
800169689Skan  set_conv_libfunc (ufloat_optab, SFmode, SImode, "__aeabi_ui2f");
801169689Skan  set_conv_libfunc (sfloat_optab, SFmode, DImode, "__aeabi_l2f");
802169689Skan  set_conv_libfunc (ufloat_optab, SFmode, DImode, "__aeabi_ul2f");
803169689Skan
804169689Skan  /* Long long.  Table 9.  */
805169689Skan  set_optab_libfunc (smul_optab, DImode, "__aeabi_lmul");
806169689Skan  set_optab_libfunc (sdivmod_optab, DImode, "__aeabi_ldivmod");
807169689Skan  set_optab_libfunc (udivmod_optab, DImode, "__aeabi_uldivmod");
808169689Skan  set_optab_libfunc (ashl_optab, DImode, "__aeabi_llsl");
809169689Skan  set_optab_libfunc (lshr_optab, DImode, "__aeabi_llsr");
810169689Skan  set_optab_libfunc (ashr_optab, DImode, "__aeabi_lasr");
811169689Skan  set_optab_libfunc (cmp_optab, DImode, "__aeabi_lcmp");
812169689Skan  set_optab_libfunc (ucmp_optab, DImode, "__aeabi_ulcmp");
813169689Skan
814169689Skan  /* Integer (32/32->32) division.  \S 4.3.1.  */
815169689Skan  set_optab_libfunc (sdivmod_optab, SImode, "__aeabi_idivmod");
816169689Skan  set_optab_libfunc (udivmod_optab, SImode, "__aeabi_uidivmod");
817169689Skan
818169689Skan  /* The divmod functions are designed so that they can be used for
819169689Skan     plain division, even though they return both the quotient and the
820169689Skan     remainder.  The quotient is returned in the usual location (i.e.,
821169689Skan     r0 for SImode, {r0, r1} for DImode), just as would be expected
822169689Skan     for an ordinary division routine.  Because the AAPCS calling
823169689Skan     conventions specify that all of { r0, r1, r2, r3 } are
824169689Skan     callee-saved registers, there is no need to tell the compiler
825169689Skan     explicitly that those registers are clobbered by these
826169689Skan     routines.  */
827169689Skan  set_optab_libfunc (sdiv_optab, DImode, "__aeabi_ldivmod");
828169689Skan  set_optab_libfunc (udiv_optab, DImode, "__aeabi_uldivmod");
829169689Skan
830169689Skan  /* For SImode division the ABI provides div-without-mod routines,
831169689Skan     which are faster.  */
832169689Skan  set_optab_libfunc (sdiv_optab, SImode, "__aeabi_idiv");
833169689Skan  set_optab_libfunc (udiv_optab, SImode, "__aeabi_uidiv");
834169689Skan
835169689Skan  /* We don't have mod libcalls.  Fortunately gcc knows how to use the
836169689Skan     divmod libcalls instead.  */
837169689Skan  set_optab_libfunc (smod_optab, DImode, NULL);
838169689Skan  set_optab_libfunc (umod_optab, DImode, NULL);
839169689Skan  set_optab_libfunc (smod_optab, SImode, NULL);
840169689Skan  set_optab_libfunc (umod_optab, SImode, NULL);
841169689Skan}
842169689Skan
843169689Skan/* Implement TARGET_HANDLE_OPTION.  */
844169689Skan
845169689Skanstatic bool
846169689Skanarm_handle_option (size_t code, const char *arg, int value ATTRIBUTE_UNUSED)
847169689Skan{
848169689Skan  switch (code)
849169689Skan    {
850169689Skan    case OPT_march_:
851169689Skan      arm_select[1].string = arg;
852169689Skan      return true;
853169689Skan
854169689Skan    case OPT_mcpu_:
855169689Skan      arm_select[0].string = arg;
856169689Skan      return true;
857169689Skan
858169689Skan    case OPT_mhard_float:
859169689Skan      target_float_abi_name = "hard";
860169689Skan      return true;
861169689Skan
862169689Skan    case OPT_msoft_float:
863169689Skan      target_float_abi_name = "soft";
864169689Skan      return true;
865169689Skan
866169689Skan    case OPT_mtune_:
867169689Skan      arm_select[2].string = arg;
868169689Skan      return true;
869169689Skan
870169689Skan    default:
871169689Skan      return true;
872169689Skan    }
873169689Skan}
874169689Skan
87590075Sobrien/* Fix up any incompatible options that the user has specified.
87690075Sobrien   This has now turned into a maze.  */
87790075Sobrienvoid
878132718Skanarm_override_options (void)
87990075Sobrien{
88090075Sobrien  unsigned i;
881169689Skan  enum processor_type target_arch_cpu = arm_none;
882169689Skan
88390075Sobrien  /* Set up the flags based on the cpu/architecture selected by the user.  */
88490075Sobrien  for (i = ARRAY_SIZE (arm_select); i--;)
88590075Sobrien    {
88690075Sobrien      struct arm_cpu_select * ptr = arm_select + i;
887169689Skan
88890075Sobrien      if (ptr->string != NULL && ptr->string[0] != '\0')
88990075Sobrien        {
89090075Sobrien	  const struct processors * sel;
89190075Sobrien
89290075Sobrien          for (sel = ptr->processors; sel->name != NULL; sel++)
89390075Sobrien            if (streq (ptr->string, sel->name))
89490075Sobrien              {
895169689Skan		/* Set the architecture define.  */
896169689Skan		if (i != ARM_OPT_SET_TUNE)
897169689Skan		  sprintf (arm_arch_name, "__ARM_ARCH_%s__", sel->arch);
898169689Skan
899169689Skan		/* Determine the processor core for which we should
900169689Skan		   tune code-generation.  */
901169689Skan		if (/* -mcpu= is a sensible default.  */
902169689Skan		    i == ARM_OPT_SET_CPU
903169689Skan		    /* -mtune= overrides -mcpu= and -march=.  */
904169689Skan		    || i == ARM_OPT_SET_TUNE)
905169689Skan		  arm_tune = (enum processor_type) (sel - ptr->processors);
906169689Skan
907169689Skan		/* Remember the CPU associated with this architecture.
908169689Skan		   If no other option is used to set the CPU type,
909169689Skan		   we'll use this to guess the most suitable tuning
910169689Skan		   options.  */
911169689Skan		if (i == ARM_OPT_SET_ARCH)
912169689Skan		  target_arch_cpu = sel->core;
913169689Skan
914169689Skan		if (i != ARM_OPT_SET_TUNE)
91590075Sobrien		  {
91690075Sobrien		    /* If we have been given an architecture and a processor
91790075Sobrien		       make sure that they are compatible.  We only generate
91890075Sobrien		       a warning though, and we prefer the CPU over the
91990075Sobrien		       architecture.  */
92090075Sobrien		    if (insn_flags != 0 && (insn_flags ^ sel->flags))
921169689Skan		      warning (0, "switch -mcpu=%s conflicts with -march= switch",
92290075Sobrien			       ptr->string);
923169689Skan
92490075Sobrien		    insn_flags = sel->flags;
92590075Sobrien		  }
926169689Skan
92790075Sobrien                break;
92890075Sobrien              }
92990075Sobrien
93090075Sobrien          if (sel->name == NULL)
93190075Sobrien            error ("bad value (%s) for %s switch", ptr->string, ptr->name);
93290075Sobrien        }
93390075Sobrien    }
934169689Skan
935169689Skan  /* Guess the tuning options from the architecture if necessary.  */
936169689Skan  if (arm_tune == arm_none)
937169689Skan    arm_tune = target_arch_cpu;
938169689Skan
93990075Sobrien  /* If the user did not specify a processor, choose one for them.  */
94090075Sobrien  if (insn_flags == 0)
94190075Sobrien    {
94290075Sobrien      const struct processors * sel;
94390075Sobrien      unsigned int        sought;
944169689Skan      enum processor_type cpu;
94590075Sobrien
946169689Skan      cpu = TARGET_CPU_DEFAULT;
947169689Skan      if (cpu == arm_none)
948169689Skan	{
949169689Skan#ifdef SUBTARGET_CPU_DEFAULT
950169689Skan	  /* Use the subtarget default CPU if none was specified by
951169689Skan	     configure.  */
952169689Skan	  cpu = SUBTARGET_CPU_DEFAULT;
953169689Skan#endif
954169689Skan	  /* Default to ARM6.  */
955169689Skan	  if (cpu == arm_none)
956169689Skan	    cpu = arm6;
957169689Skan	}
958169689Skan      sel = &all_cores[cpu];
95990075Sobrien
96090075Sobrien      insn_flags = sel->flags;
961169689Skan
96290075Sobrien      /* Now check to see if the user has specified some command line
96390075Sobrien	 switch that require certain abilities from the cpu.  */
96490075Sobrien      sought = 0;
965169689Skan
96690075Sobrien      if (TARGET_INTERWORK || TARGET_THUMB)
96790075Sobrien	{
96890075Sobrien	  sought |= (FL_THUMB | FL_MODE32);
96990075Sobrien
97090075Sobrien	  /* There are no ARM processors that support both APCS-26 and
97190075Sobrien	     interworking.  Therefore we force FL_MODE26 to be removed
97290075Sobrien	     from insn_flags here (if it was set), so that the search
97390075Sobrien	     below will always be able to find a compatible processor.  */
97490075Sobrien	  insn_flags &= ~FL_MODE26;
97590075Sobrien	}
976169689Skan
97790075Sobrien      if (sought != 0 && ((sought & insn_flags) != sought))
97890075Sobrien	{
97990075Sobrien	  /* Try to locate a CPU type that supports all of the abilities
98090075Sobrien	     of the default CPU, plus the extra abilities requested by
98190075Sobrien	     the user.  */
98290075Sobrien	  for (sel = all_cores; sel->name != NULL; sel++)
98390075Sobrien	    if ((sel->flags & sought) == (sought | insn_flags))
98490075Sobrien	      break;
98590075Sobrien
98690075Sobrien	  if (sel->name == NULL)
98790075Sobrien	    {
988117395Skan	      unsigned current_bit_count = 0;
98990075Sobrien	      const struct processors * best_fit = NULL;
990169689Skan
99190075Sobrien	      /* Ideally we would like to issue an error message here
99290075Sobrien		 saying that it was not possible to find a CPU compatible
99390075Sobrien		 with the default CPU, but which also supports the command
99490075Sobrien		 line options specified by the programmer, and so they
99590075Sobrien		 ought to use the -mcpu=<name> command line option to
99690075Sobrien		 override the default CPU type.
99790075Sobrien
998169689Skan		 If we cannot find a cpu that has both the
999169689Skan		 characteristics of the default cpu and the given
1000169689Skan		 command line options we scan the array again looking
1001169689Skan		 for a best match.  */
100290075Sobrien	      for (sel = all_cores; sel->name != NULL; sel++)
100390075Sobrien		if ((sel->flags & sought) == sought)
100490075Sobrien		  {
1005117395Skan		    unsigned count;
100690075Sobrien
100790075Sobrien		    count = bit_count (sel->flags & insn_flags);
100890075Sobrien
100990075Sobrien		    if (count >= current_bit_count)
101090075Sobrien		      {
101190075Sobrien			best_fit = sel;
101290075Sobrien			current_bit_count = count;
101390075Sobrien		      }
101490075Sobrien		  }
101590075Sobrien
1016169689Skan	      gcc_assert (best_fit);
1017169689Skan	      sel = best_fit;
101890075Sobrien	    }
101990075Sobrien
102090075Sobrien	  insn_flags = sel->flags;
102190075Sobrien	}
1022169689Skan      sprintf (arm_arch_name, "__ARM_ARCH_%s__", sel->arch);
1023169689Skan      if (arm_tune == arm_none)
1024169689Skan	arm_tune = (enum processor_type) (sel - all_cores);
102590075Sobrien    }
1026117395Skan
1027169689Skan  /* The processor for which we should tune should now have been
1028169689Skan     chosen.  */
1029169689Skan  gcc_assert (arm_tune != arm_none);
1030169689Skan
1031169689Skan  tune_flags = all_cores[(int)arm_tune].flags;
1032169689Skan  if (optimize_size)
1033169689Skan    targetm.rtx_costs = arm_size_rtx_costs;
1034169689Skan  else
1035169689Skan    targetm.rtx_costs = all_cores[(int)arm_tune].rtx_costs;
1036169689Skan
103790075Sobrien  /* Make sure that the processor choice does not conflict with any of the
103890075Sobrien     other command line choices.  */
103990075Sobrien  if (TARGET_INTERWORK && !(insn_flags & FL_THUMB))
104090075Sobrien    {
1041169689Skan      warning (0, "target CPU does not support interworking" );
1042169689Skan      target_flags &= ~MASK_INTERWORK;
104390075Sobrien    }
1044169689Skan
104590075Sobrien  if (TARGET_THUMB && !(insn_flags & FL_THUMB))
104690075Sobrien    {
1047169689Skan      warning (0, "target CPU does not support THUMB instructions");
1048169689Skan      target_flags &= ~MASK_THUMB;
104990075Sobrien    }
105090075Sobrien
105190075Sobrien  if (TARGET_APCS_FRAME && TARGET_THUMB)
105290075Sobrien    {
1053169689Skan      /* warning (0, "ignoring -mapcs-frame because -mthumb was used"); */
1054169689Skan      target_flags &= ~MASK_APCS_FRAME;
105590075Sobrien    }
105690075Sobrien
1057169689Skan  /* Callee super interworking implies thumb interworking.  Adding
1058169689Skan     this to the flags here simplifies the logic elsewhere.  */
1059169689Skan  if (TARGET_THUMB && TARGET_CALLEE_INTERWORKING)
1060169689Skan      target_flags |= MASK_INTERWORK;
1061169689Skan
106290075Sobrien  /* TARGET_BACKTRACE calls leaf_function_p, which causes a crash if done
106390075Sobrien     from here where no function is being compiled currently.  */
1064169689Skan  if ((TARGET_TPCS_FRAME || TARGET_TPCS_LEAF_FRAME) && TARGET_ARM)
1065169689Skan    warning (0, "enabling backtrace support is only meaningful when compiling for the Thumb");
106690075Sobrien
106790075Sobrien  if (TARGET_ARM && TARGET_CALLEE_INTERWORKING)
1068169689Skan    warning (0, "enabling callee interworking support is only meaningful when compiling for the Thumb");
106990075Sobrien
107090075Sobrien  if (TARGET_ARM && TARGET_CALLER_INTERWORKING)
1071169689Skan    warning (0, "enabling caller interworking support is only meaningful when compiling for the Thumb");
107290075Sobrien
107390075Sobrien  if (TARGET_APCS_STACK && !TARGET_APCS_FRAME)
107490075Sobrien    {
1075169689Skan      warning (0, "-mapcs-stack-check incompatible with -mno-apcs-frame");
1076169689Skan      target_flags |= MASK_APCS_FRAME;
107790075Sobrien    }
1078169689Skan
107990075Sobrien  if (TARGET_POKE_FUNCTION_NAME)
1080169689Skan    target_flags |= MASK_APCS_FRAME;
1081169689Skan
108290075Sobrien  if (TARGET_APCS_REENT && flag_pic)
108390075Sobrien    error ("-fpic and -mapcs-reent are incompatible");
1084169689Skan
108590075Sobrien  if (TARGET_APCS_REENT)
1086169689Skan    warning (0, "APCS reentrant code not supported.  Ignored");
1087169689Skan
108890075Sobrien  /* If this target is normally configured to use APCS frames, warn if they
108990075Sobrien     are turned off and debugging is turned on.  */
109090075Sobrien  if (TARGET_ARM
109190075Sobrien      && write_symbols != NO_DEBUG
109290075Sobrien      && !TARGET_APCS_FRAME
1093169689Skan      && (TARGET_DEFAULT & MASK_APCS_FRAME))
1094169689Skan    warning (0, "-g with -mno-apcs-frame may not give sensible debugging");
1095169689Skan
109690075Sobrien  /* If stack checking is disabled, we can use r10 as the PIC register,
109790075Sobrien     which keeps r9 available.  */
1098169689Skan  if (flag_pic && TARGET_SINGLE_PIC_BASE)
109996263Sobrien    arm_pic_register = TARGET_APCS_STACK ? 9 : 10;
1100169689Skan
110190075Sobrien  if (TARGET_APCS_FLOAT)
1102169689Skan    warning (0, "passing floating point arguments in fp regs not yet supported");
1103169689Skan
1104117395Skan  /* Initialize boolean versions of the flags, for use in the arm.md file.  */
1105169689Skan  arm_arch3m = (insn_flags & FL_ARCH3M) != 0;
1106169689Skan  arm_arch4 = (insn_flags & FL_ARCH4) != 0;
1107169689Skan  arm_arch4t = arm_arch4 & ((insn_flags & FL_THUMB) != 0);
1108169689Skan  arm_arch5 = (insn_flags & FL_ARCH5) != 0;
1109169689Skan  arm_arch5e = (insn_flags & FL_ARCH5E) != 0;
1110169689Skan  arm_arch6 = (insn_flags & FL_ARCH6) != 0;
1111169689Skan  arm_arch6k = (insn_flags & FL_ARCH6K) != 0;
1112169689Skan  arm_arch_xscale = (insn_flags & FL_XSCALE) != 0;
1113169689Skan  arm_arch_cirrus = (insn_flags & FL_CIRRUS) != 0;
111490075Sobrien
1115169689Skan  arm_ld_sched = (tune_flags & FL_LDSCHED) != 0;
1116169689Skan  arm_tune_strongarm = (tune_flags & FL_STRONG) != 0;
1117169689Skan  thumb_code = (TARGET_ARM == 0);
1118169689Skan  arm_tune_wbuf = (tune_flags & FL_WBUF) != 0;
1119169689Skan  arm_tune_xscale = (tune_flags & FL_XSCALE) != 0;
1120169689Skan  arm_arch_iwmmxt = (insn_flags & FL_IWMMXT) != 0;
112190075Sobrien
1122169689Skan  /* V5 code we generate is completely interworking capable, so we turn off
1123169689Skan     TARGET_INTERWORK here to avoid many tests later on.  */
1124132718Skan
1125169689Skan  /* XXX However, we must pass the right pre-processor defines to CPP
1126169689Skan     or GLD can get confused.  This is a hack.  */
1127169689Skan  if (TARGET_INTERWORK)
1128169689Skan    arm_cpp_interwork = 1;
1129169689Skan
1130169689Skan  if (arm_arch5)
1131169689Skan    target_flags &= ~MASK_INTERWORK;
1132169689Skan
1133169689Skan  if (target_abi_name)
1134132718Skan    {
1135169689Skan      for (i = 0; i < ARRAY_SIZE (arm_all_abis); i++)
1136169689Skan	{
1137169689Skan	  if (streq (arm_all_abis[i].name, target_abi_name))
1138169689Skan	    {
1139169689Skan	      arm_abi = arm_all_abis[i].abi_type;
1140169689Skan	      break;
1141169689Skan	    }
1142169689Skan	}
1143169689Skan      if (i == ARRAY_SIZE (arm_all_abis))
1144169689Skan	error ("invalid ABI option: -mabi=%s", target_abi_name);
1145169689Skan    }
1146169689Skan  else
1147169689Skan    arm_abi = ARM_DEFAULT_ABI;
1148132718Skan
1149169689Skan  if (TARGET_IWMMXT && !ARM_DOUBLEWORD_ALIGN)
1150169689Skan    error ("iwmmxt requires an AAPCS compatible ABI for proper operation");
1151169689Skan
1152169689Skan  if (TARGET_IWMMXT_ABI && !TARGET_IWMMXT)
1153169689Skan    error ("iwmmxt abi requires an iwmmxt capable cpu");
1154169689Skan
1155169689Skan  arm_fp_model = ARM_FP_MODEL_UNKNOWN;
1156169689Skan  if (target_fpu_name == NULL && target_fpe_name != NULL)
1157169689Skan    {
1158169689Skan      if (streq (target_fpe_name, "2"))
1159169689Skan	target_fpu_name = "fpe2";
1160169689Skan      else if (streq (target_fpe_name, "3"))
1161169689Skan	target_fpu_name = "fpe3";
1162169689Skan      else
1163169689Skan	error ("invalid floating point emulation option: -mfpe=%s",
1164169689Skan	       target_fpe_name);
1165132718Skan    }
1166169689Skan  if (target_fpu_name != NULL)
1167169689Skan    {
1168169689Skan      /* The user specified a FPU.  */
1169169689Skan      for (i = 0; i < ARRAY_SIZE (all_fpus); i++)
1170169689Skan	{
1171169689Skan	  if (streq (all_fpus[i].name, target_fpu_name))
1172169689Skan	    {
1173169689Skan	      arm_fpu_arch = all_fpus[i].fpu;
1174169689Skan	      arm_fpu_tune = arm_fpu_arch;
1175169689Skan	      arm_fp_model = fp_model_for_fpu[arm_fpu_arch];
1176169689Skan	      break;
1177169689Skan	    }
1178169689Skan	}
1179169689Skan      if (arm_fp_model == ARM_FP_MODEL_UNKNOWN)
1180169689Skan	error ("invalid floating point option: -mfpu=%s", target_fpu_name);
1181169689Skan    }
1182132718Skan  else
118390075Sobrien    {
1184169689Skan#ifdef FPUTYPE_DEFAULT
1185169689Skan      /* Use the default if it is specified for this platform.  */
1186169689Skan      arm_fpu_arch = FPUTYPE_DEFAULT;
1187169689Skan      arm_fpu_tune = FPUTYPE_DEFAULT;
1188169689Skan#else
1189169689Skan      /* Pick one based on CPU type.  */
1190169689Skan      /* ??? Some targets assume FPA is the default.
1191169689Skan      if ((insn_flags & FL_VFP) != 0)
1192169689Skan	arm_fpu_arch = FPUTYPE_VFP;
1193169689Skan      else
1194169689Skan      */
1195169689Skan      if (arm_arch_cirrus)
1196169689Skan	arm_fpu_arch = FPUTYPE_MAVERICK;
1197169689Skan      else
1198132718Skan	arm_fpu_arch = FPUTYPE_FPA_EMU2;
1199169689Skan#endif
1200169689Skan      if (tune_flags & FL_CO_PROC && arm_fpu_arch == FPUTYPE_FPA_EMU2)
1201169689Skan	arm_fpu_tune = FPUTYPE_FPA;
120290075Sobrien      else
1203169689Skan	arm_fpu_tune = arm_fpu_arch;
1204169689Skan      arm_fp_model = fp_model_for_fpu[arm_fpu_arch];
1205169689Skan      gcc_assert (arm_fp_model != ARM_FP_MODEL_UNKNOWN);
120690075Sobrien    }
1207169689Skan
1208169689Skan  if (target_float_abi_name != NULL)
1209132718Skan    {
1210169689Skan      /* The user specified a FP ABI.  */
1211169689Skan      for (i = 0; i < ARRAY_SIZE (all_float_abis); i++)
1212169689Skan	{
1213169689Skan	  if (streq (all_float_abis[i].name, target_float_abi_name))
1214169689Skan	    {
1215169689Skan	      arm_float_abi = all_float_abis[i].abi_type;
1216169689Skan	      break;
1217169689Skan	    }
1218169689Skan	}
1219169689Skan      if (i == ARRAY_SIZE (all_float_abis))
1220169689Skan	error ("invalid floating point abi: -mfloat-abi=%s",
1221169689Skan	       target_float_abi_name);
1222132718Skan    }
1223169689Skan  else
1224169689Skan    arm_float_abi = TARGET_DEFAULT_FLOAT_ABI;
1225169689Skan
1226169689Skan  if (arm_float_abi == ARM_FLOAT_ABI_HARD && TARGET_VFP)
1227169689Skan    sorry ("-mfloat-abi=hard and VFP");
1228169689Skan
1229169689Skan  /* FPA and iWMMXt are incompatible because the insn encodings overlap.
1230169689Skan     VFP and iWMMXt can theoretically coexist, but it's unlikely such silicon
1231169689Skan     will ever exist.  GCC makes no attempt to support this combination.  */
1232169689Skan  if (TARGET_IWMMXT && !TARGET_SOFT_FLOAT)
1233169689Skan    sorry ("iWMMXt and hardware floating point");
1234169689Skan
1235169689Skan  /* If soft-float is specified then don't use FPU.  */
1236169689Skan  if (TARGET_SOFT_FLOAT)
1237169689Skan    arm_fpu_arch = FPUTYPE_NONE;
1238169689Skan
123990075Sobrien  /* For arm2/3 there is no need to do any scheduling if there is only
124090075Sobrien     a floating point emulator, or we are doing software floating-point.  */
1241169689Skan  if ((TARGET_SOFT_FLOAT
1242169689Skan       || arm_fpu_tune == FPUTYPE_FPA_EMU2
1243169689Skan       || arm_fpu_tune == FPUTYPE_FPA_EMU3)
124490075Sobrien      && (tune_flags & FL_MODE32) == 0)
124590075Sobrien    flag_schedule_insns = flag_schedule_insns_after_reload = 0;
1246169689Skan
1247169689Skan  if (target_thread_switch)
1248169689Skan    {
1249169689Skan      if (strcmp (target_thread_switch, "soft") == 0)
1250169689Skan	target_thread_pointer = TP_SOFT;
1251169689Skan      else if (strcmp (target_thread_switch, "auto") == 0)
1252169689Skan	target_thread_pointer = TP_AUTO;
1253169689Skan      else if (strcmp (target_thread_switch, "cp15") == 0)
1254169689Skan	target_thread_pointer = TP_CP15;
1255169689Skan      else
1256169689Skan	error ("invalid thread pointer option: -mtp=%s", target_thread_switch);
1257169689Skan    }
1258169689Skan
1259169689Skan  /* Use the cp15 method if it is available.  */
1260169689Skan  if (target_thread_pointer == TP_AUTO)
1261169689Skan    {
1262169689Skan      if (arm_arch6k && !TARGET_THUMB)
1263169689Skan	target_thread_pointer = TP_CP15;
1264169689Skan      else
1265169689Skan	target_thread_pointer = TP_SOFT;
1266169689Skan    }
1267169689Skan
1268169689Skan  if (TARGET_HARD_TP && TARGET_THUMB)
1269169689Skan    error ("can not use -mtp=cp15 with -mthumb");
1270169689Skan
1271169689Skan  /* Override the default structure alignment for AAPCS ABI.  */
1272169689Skan  if (TARGET_AAPCS_BASED)
1273169689Skan    arm_structure_size_boundary = 8;
1274169689Skan
127590075Sobrien  if (structure_size_string != NULL)
127690075Sobrien    {
127790075Sobrien      int size = strtol (structure_size_string, NULL, 0);
1278169689Skan
1279169689Skan      if (size == 8 || size == 32
1280169689Skan	  || (ARM_DOUBLEWORD_ALIGN && size == 64))
128190075Sobrien	arm_structure_size_boundary = size;
128290075Sobrien      else
1283169689Skan	warning (0, "structure size boundary can only be set to %s",
1284169689Skan		 ARM_DOUBLEWORD_ALIGN ? "8, 32 or 64": "8 or 32");
128590075Sobrien    }
128690075Sobrien
128790075Sobrien  if (arm_pic_register_string != NULL)
128890075Sobrien    {
128996263Sobrien      int pic_register = decode_reg_name (arm_pic_register_string);
1290117395Skan
129190075Sobrien      if (!flag_pic)
1292169689Skan	warning (0, "-mpic-register= is useless without -fpic");
129390075Sobrien
129490075Sobrien      /* Prevent the user from choosing an obviously stupid PIC register.  */
129596263Sobrien      else if (pic_register < 0 || call_used_regs[pic_register]
129696263Sobrien	       || pic_register == HARD_FRAME_POINTER_REGNUM
129796263Sobrien	       || pic_register == STACK_POINTER_REGNUM
129896263Sobrien	       || pic_register >= PC_REGNUM)
129990075Sobrien	error ("unable to use '%s' for PIC register", arm_pic_register_string);
130090075Sobrien      else
130190075Sobrien	arm_pic_register = pic_register;
130290075Sobrien    }
130390075Sobrien
130490075Sobrien  if (TARGET_THUMB && flag_schedule_insns)
130590075Sobrien    {
130690075Sobrien      /* Don't warn since it's on by default in -O2.  */
130790075Sobrien      flag_schedule_insns = 0;
130890075Sobrien    }
130990075Sobrien
131090075Sobrien  if (optimize_size)
1311132718Skan    {
1312132718Skan      arm_constant_limit = 1;
131390075Sobrien
1314132718Skan      /* If optimizing for size, bump the number of instructions that we
1315132718Skan         are prepared to conditionally execute (even on a StrongARM).  */
1316132718Skan      max_insns_skipped = 6;
1317132718Skan    }
1318132718Skan  else
1319132718Skan    {
1320132718Skan      /* For processors with load scheduling, it never costs more than
1321132718Skan         2 cycles to load a constant, and the load scheduler may well
1322132718Skan	 reduce that to 1.  */
1323169689Skan      if (arm_ld_sched)
1324132718Skan        arm_constant_limit = 1;
1325132718Skan
1326132718Skan      /* On XScale the longer latency of a load makes it more difficult
1327132718Skan         to achieve a good schedule, so it's faster to synthesize
1328132718Skan	 constants that can be done in two insns.  */
1329132718Skan      if (arm_tune_xscale)
1330132718Skan        arm_constant_limit = 2;
1331132718Skan
1332132718Skan      /* StrongARM has early execution of branches, so a sequence
1333132718Skan         that is worth skipping is shorter.  */
1334169689Skan      if (arm_tune_strongarm)
1335132718Skan        max_insns_skipped = 3;
1336132718Skan    }
1337132718Skan
133890075Sobrien  /* Register global variables with the garbage collector.  */
133990075Sobrien  arm_add_gc_roots ();
134090075Sobrien}
134190075Sobrien
134290075Sobrienstatic void
1343132718Skanarm_add_gc_roots (void)
134490075Sobrien{
134590075Sobrien  gcc_obstack_init(&minipool_obstack);
134690075Sobrien  minipool_startobj = (char *) obstack_alloc (&minipool_obstack, 0);
134790075Sobrien}
134890075Sobrien
134990075Sobrien/* A table of known ARM exception types.
135090075Sobrien   For use with the interrupt function attribute.  */
135190075Sobrien
135290075Sobrientypedef struct
135390075Sobrien{
135490075Sobrien  const char *const arg;
135590075Sobrien  const unsigned long return_value;
135690075Sobrien}
135790075Sobrienisr_attribute_arg;
135890075Sobrien
135990075Sobrienstatic const isr_attribute_arg isr_attribute_args [] =
136090075Sobrien{
136190075Sobrien  { "IRQ",   ARM_FT_ISR },
136290075Sobrien  { "irq",   ARM_FT_ISR },
136390075Sobrien  { "FIQ",   ARM_FT_FIQ },
136490075Sobrien  { "fiq",   ARM_FT_FIQ },
136590075Sobrien  { "ABORT", ARM_FT_ISR },
136690075Sobrien  { "abort", ARM_FT_ISR },
136790075Sobrien  { "ABORT", ARM_FT_ISR },
136890075Sobrien  { "abort", ARM_FT_ISR },
136990075Sobrien  { "UNDEF", ARM_FT_EXCEPTION },
137090075Sobrien  { "undef", ARM_FT_EXCEPTION },
137190075Sobrien  { "SWI",   ARM_FT_EXCEPTION },
137290075Sobrien  { "swi",   ARM_FT_EXCEPTION },
137390075Sobrien  { NULL,    ARM_FT_NORMAL }
137490075Sobrien};
137590075Sobrien
137690075Sobrien/* Returns the (interrupt) function type of the current
137790075Sobrien   function, or ARM_FT_UNKNOWN if the type cannot be determined.  */
137890075Sobrien
137990075Sobrienstatic unsigned long
1380132718Skanarm_isr_value (tree argument)
138190075Sobrien{
138290075Sobrien  const isr_attribute_arg * ptr;
138390075Sobrien  const char *              arg;
138490075Sobrien
138590075Sobrien  /* No argument - default to IRQ.  */
138690075Sobrien  if (argument == NULL_TREE)
138790075Sobrien    return ARM_FT_ISR;
138890075Sobrien
138990075Sobrien  /* Get the value of the argument.  */
139090075Sobrien  if (TREE_VALUE (argument) == NULL_TREE
139190075Sobrien      || TREE_CODE (TREE_VALUE (argument)) != STRING_CST)
139290075Sobrien    return ARM_FT_UNKNOWN;
139390075Sobrien
139490075Sobrien  arg = TREE_STRING_POINTER (TREE_VALUE (argument));
139590075Sobrien
139690075Sobrien  /* Check it against the list of known arguments.  */
1397132718Skan  for (ptr = isr_attribute_args; ptr->arg != NULL; ptr++)
139890075Sobrien    if (streq (arg, ptr->arg))
139990075Sobrien      return ptr->return_value;
140090075Sobrien
1401117395Skan  /* An unrecognized interrupt type.  */
140290075Sobrien  return ARM_FT_UNKNOWN;
140390075Sobrien}
140490075Sobrien
140590075Sobrien/* Computes the type of the current function.  */
140690075Sobrien
140790075Sobrienstatic unsigned long
1408132718Skanarm_compute_func_type (void)
140990075Sobrien{
141090075Sobrien  unsigned long type = ARM_FT_UNKNOWN;
141190075Sobrien  tree a;
141290075Sobrien  tree attr;
141390075Sobrien
1414169689Skan  gcc_assert (TREE_CODE (current_function_decl) == FUNCTION_DECL);
1415169689Skan
141690075Sobrien  /* Decide if the current function is volatile.  Such functions
141790075Sobrien     never return, and many memory cycles can be saved by not storing
141890075Sobrien     register values that will never be needed again.  This optimization
141990075Sobrien     was added to speed up context switching in a kernel application.  */
142090075Sobrien  if (optimize > 0
1421169689Skan      && (TREE_NOTHROW (current_function_decl)
1422169689Skan          || !(flag_unwind_tables
1423169689Skan               || (flag_exceptions && !USING_SJLJ_EXCEPTIONS)))
142490075Sobrien      && TREE_THIS_VOLATILE (current_function_decl))
142590075Sobrien    type |= ARM_FT_VOLATILE;
1426169689Skan
1427169689Skan  if (cfun->static_chain_decl != NULL)
142890075Sobrien    type |= ARM_FT_NESTED;
142990075Sobrien
143090075Sobrien  attr = DECL_ATTRIBUTES (current_function_decl);
1431169689Skan
143290075Sobrien  a = lookup_attribute ("naked", attr);
143390075Sobrien  if (a != NULL_TREE)
143490075Sobrien    type |= ARM_FT_NAKED;
143590075Sobrien
1436169689Skan  a = lookup_attribute ("isr", attr);
1437169689Skan  if (a == NULL_TREE)
1438169689Skan    a = lookup_attribute ("interrupt", attr);
1439169689Skan
1440169689Skan  if (a == NULL_TREE)
1441169689Skan    type |= TARGET_INTERWORK ? ARM_FT_INTERWORKED : ARM_FT_NORMAL;
144290075Sobrien  else
1443169689Skan    type |= arm_isr_value (TREE_VALUE (a));
1444169689Skan
144590075Sobrien  return type;
144690075Sobrien}
144790075Sobrien
144890075Sobrien/* Returns the type of the current function.  */
144990075Sobrien
145090075Sobrienunsigned long
1451132718Skanarm_current_func_type (void)
145290075Sobrien{
145390075Sobrien  if (ARM_FUNC_TYPE (cfun->machine->func_type) == ARM_FT_UNKNOWN)
145490075Sobrien    cfun->machine->func_type = arm_compute_func_type ();
145590075Sobrien
145690075Sobrien  return cfun->machine->func_type;
145790075Sobrien}
145890075Sobrien
1459169689Skan/* Return 1 if it is possible to return using a single instruction.
1460132718Skan   If SIBLING is non-null, this is a test for a return before a sibling
1461132718Skan   call.  SIBLING is the call insn, so we can examine its register usage.  */
146290075Sobrien
146390075Sobrienint
1464132718Skanuse_return_insn (int iscond, rtx sibling)
146590075Sobrien{
146690075Sobrien  int regno;
146790075Sobrien  unsigned int func_type;
1468107590Sobrien  unsigned long saved_int_regs;
1469132718Skan  unsigned HOST_WIDE_INT stack_adjust;
1470169689Skan  arm_stack_offsets *offsets;
147190075Sobrien
147290075Sobrien  /* Never use a return instruction before reload has run.  */
147390075Sobrien  if (!reload_completed)
147490075Sobrien    return 0;
1475132718Skan
147690075Sobrien  func_type = arm_current_func_type ();
147790075Sobrien
147896263Sobrien  /* Naked functions and volatile functions need special
147996263Sobrien     consideration.  */
148096263Sobrien  if (func_type & (ARM_FT_VOLATILE | ARM_FT_NAKED))
148190075Sobrien    return 0;
1482117395Skan
1483117395Skan  /* So do interrupt functions that use the frame pointer.  */
1484117395Skan  if (IS_INTERRUPT (func_type) && frame_pointer_needed)
1485117395Skan    return 0;
1486132718Skan
1487169689Skan  offsets = arm_get_frame_offsets ();
1488169689Skan  stack_adjust = offsets->outgoing_args - offsets->saved_regs;
1489132718Skan
149090075Sobrien  /* As do variadic functions.  */
149190075Sobrien  if (current_function_pretend_args_size
149296263Sobrien      || cfun->machine->uses_anonymous_args
1493132718Skan      /* Or if the function calls __builtin_eh_return () */
1494169689Skan      || current_function_calls_eh_return
1495132718Skan      /* Or if the function calls alloca */
1496132718Skan      || current_function_calls_alloca
1497132718Skan      /* Or if there is a stack adjustment.  However, if the stack pointer
1498132718Skan	 is saved on the stack, we can use a pre-incrementing stack load.  */
1499132718Skan      || !(stack_adjust == 0 || (frame_pointer_needed && stack_adjust == 4)))
150090075Sobrien    return 0;
150190075Sobrien
1502107590Sobrien  saved_int_regs = arm_compute_save_reg_mask ();
1503107590Sobrien
1504132718Skan  /* Unfortunately, the insn
1505132718Skan
1506132718Skan       ldmib sp, {..., sp, ...}
1507132718Skan
1508132718Skan     triggers a bug on most SA-110 based devices, such that the stack
1509132718Skan     pointer won't be correctly restored if the instruction takes a
1510132718Skan     page fault.  We work around this problem by popping r3 along with
1511132718Skan     the other registers, since that is never slower than executing
1512169689Skan     another instruction.
1513132718Skan
1514132718Skan     We test for !arm_arch5 here, because code for any architecture
1515132718Skan     less than this could potentially be run on one of the buggy
1516132718Skan     chips.  */
1517132718Skan  if (stack_adjust == 4 && !arm_arch5)
1518132718Skan    {
1519132718Skan      /* Validate that r3 is a call-clobbered register (always true in
1520132718Skan	 the default abi) ...  */
1521132718Skan      if (!call_used_regs[3])
1522132718Skan	return 0;
1523132718Skan
1524169689Skan      /* ... that it isn't being used for a return value ... */
1525169689Skan      if (arm_size_return_regs () >= (4 * UNITS_PER_WORD))
1526169689Skan	return 0;
1527169689Skan
1528169689Skan      /* ... or for a tail-call argument ...  */
1529132718Skan      if (sibling)
1530132718Skan	{
1531169689Skan	  gcc_assert (GET_CODE (sibling) == CALL_INSN);
1532132718Skan
1533132718Skan	  if (find_regno_fusage (sibling, USE, 3))
1534132718Skan	    return 0;
1535132718Skan	}
1536132718Skan
1537132718Skan      /* ... and that there are no call-saved registers in r0-r2
1538132718Skan	 (always true in the default ABI).  */
1539132718Skan      if (saved_int_regs & 0x7)
1540132718Skan	return 0;
1541132718Skan    }
1542132718Skan
154390075Sobrien  /* Can't be done if interworking with Thumb, and any registers have been
1544107590Sobrien     stacked.  */
1545107590Sobrien  if (TARGET_INTERWORK && saved_int_regs != 0)
154690075Sobrien    return 0;
1547107590Sobrien
1548107590Sobrien  /* On StrongARM, conditional returns are expensive if they aren't
1549107590Sobrien     taken and multiple registers have been stacked.  */
1550169689Skan  if (iscond && arm_tune_strongarm)
155190075Sobrien    {
1552169689Skan      /* Conditional return when just the LR is stored is a simple
1553107590Sobrien	 conditional-load instruction, that's not expensive.  */
1554107590Sobrien      if (saved_int_regs != 0 && saved_int_regs != (1 << LR_REGNUM))
1555107590Sobrien	return 0;
155690075Sobrien
1557169689Skan      if (flag_pic
1558169689Skan	  && arm_pic_register != INVALID_REGNUM
1559169689Skan	  && regs_ever_live[PIC_OFFSET_TABLE_REGNUM])
156090075Sobrien	return 0;
156190075Sobrien    }
1562107590Sobrien
1563107590Sobrien  /* If there are saved registers but the LR isn't saved, then we need
1564107590Sobrien     two instructions for the return.  */
1565107590Sobrien  if (saved_int_regs && !(saved_int_regs & (1 << LR_REGNUM)))
1566107590Sobrien    return 0;
1567107590Sobrien
1568132718Skan  /* Can't be done if any of the FPA regs are pushed,
156990075Sobrien     since this also requires an insn.  */
1570169689Skan  if (TARGET_HARD_FLOAT && TARGET_FPA)
1571169689Skan    for (regno = FIRST_FPA_REGNUM; regno <= LAST_FPA_REGNUM; regno++)
157290075Sobrien      if (regs_ever_live[regno] && !call_used_regs[regno])
157390075Sobrien	return 0;
157490075Sobrien
1575169689Skan  /* Likewise VFP regs.  */
1576169689Skan  if (TARGET_HARD_FLOAT && TARGET_VFP)
1577169689Skan    for (regno = FIRST_VFP_REGNUM; regno <= LAST_VFP_REGNUM; regno++)
1578169689Skan      if (regs_ever_live[regno] && !call_used_regs[regno])
1579169689Skan	return 0;
1580169689Skan
1581132718Skan  if (TARGET_REALLY_IWMMXT)
1582132718Skan    for (regno = FIRST_IWMMXT_REGNUM; regno <= LAST_IWMMXT_REGNUM; regno++)
1583132718Skan      if (regs_ever_live[regno] && ! call_used_regs [regno])
1584132718Skan	return 0;
1585132718Skan
158690075Sobrien  return 1;
158790075Sobrien}
158890075Sobrien
158990075Sobrien/* Return TRUE if int I is a valid immediate ARM constant.  */
159090075Sobrien
159190075Sobrienint
1592132718Skanconst_ok_for_arm (HOST_WIDE_INT i)
159390075Sobrien{
1594169689Skan  int lowbit;
159590075Sobrien
1596169689Skan  /* For machines with >32 bit HOST_WIDE_INT, the bits above bit 31 must
159790075Sobrien     be all zero, or all one.  */
159890075Sobrien  if ((i & ~(unsigned HOST_WIDE_INT) 0xffffffff) != 0
159990075Sobrien      && ((i & ~(unsigned HOST_WIDE_INT) 0xffffffff)
160090075Sobrien	  != ((~(unsigned HOST_WIDE_INT) 0)
160190075Sobrien	      & ~(unsigned HOST_WIDE_INT) 0xffffffff)))
160290075Sobrien    return FALSE;
1603169689Skan
1604169689Skan  i &= (unsigned HOST_WIDE_INT) 0xffffffff;
1605169689Skan
1606169689Skan  /* Fast return for 0 and small values.  We must do this for zero, since
1607169689Skan     the code below can't handle that one case.  */
1608169689Skan  if ((i & ~(unsigned HOST_WIDE_INT) 0xff) == 0)
160990075Sobrien    return TRUE;
161090075Sobrien
1611169689Skan  /* Get the number of trailing zeros, rounded down to the nearest even
1612169689Skan     number.  */
1613169689Skan  lowbit = (ffs ((int) i) - 1) & ~1;
161490075Sobrien
1615169689Skan  if ((i & ~(((unsigned HOST_WIDE_INT) 0xff) << lowbit)) == 0)
1616169689Skan    return TRUE;
1617169689Skan  else if (lowbit <= 4
1618169689Skan	   && ((i & ~0xc000003f) == 0
1619169689Skan	       || (i & ~0xf000000f) == 0
1620169689Skan	       || (i & ~0xfc000003) == 0))
1621169689Skan    return TRUE;
1622169689Skan
162390075Sobrien  return FALSE;
162490075Sobrien}
162590075Sobrien
162690075Sobrien/* Return true if I is a valid constant for the operation CODE.  */
162790075Sobrienstatic int
1628132718Skanconst_ok_for_op (HOST_WIDE_INT i, enum rtx_code code)
162990075Sobrien{
163090075Sobrien  if (const_ok_for_arm (i))
163190075Sobrien    return 1;
163290075Sobrien
163390075Sobrien  switch (code)
163490075Sobrien    {
163590075Sobrien    case PLUS:
163690075Sobrien      return const_ok_for_arm (ARM_SIGN_EXTEND (-i));
163790075Sobrien
163890075Sobrien    case MINUS:		/* Should only occur with (MINUS I reg) => rsb */
163990075Sobrien    case XOR:
164090075Sobrien    case IOR:
164190075Sobrien      return 0;
164290075Sobrien
164390075Sobrien    case AND:
164490075Sobrien      return const_ok_for_arm (ARM_SIGN_EXTEND (~i));
164590075Sobrien
164690075Sobrien    default:
1647169689Skan      gcc_unreachable ();
164890075Sobrien    }
164990075Sobrien}
165090075Sobrien
165190075Sobrien/* Emit a sequence of insns to handle a large constant.
165290075Sobrien   CODE is the code of the operation required, it can be any of SET, PLUS,
165390075Sobrien   IOR, AND, XOR, MINUS;
165490075Sobrien   MODE is the mode in which the operation is being performed;
165590075Sobrien   VAL is the integer to operate on;
165690075Sobrien   SOURCE is the other operand (a register, or a null-pointer for SET);
165790075Sobrien   SUBTARGETS means it is safe to create scratch registers if that will
165890075Sobrien   either produce a simpler sequence, or we will want to cse the values.
165990075Sobrien   Return value is the number of insns emitted.  */
166090075Sobrien
166190075Sobrienint
1662169689Skanarm_split_constant (enum rtx_code code, enum machine_mode mode, rtx insn,
1663132718Skan		    HOST_WIDE_INT val, rtx target, rtx source, int subtargets)
166490075Sobrien{
1665169689Skan  rtx cond;
1666169689Skan
1667169689Skan  if (insn && GET_CODE (PATTERN (insn)) == COND_EXEC)
1668169689Skan    cond = COND_EXEC_TEST (PATTERN (insn));
1669169689Skan  else
1670169689Skan    cond = NULL_RTX;
1671169689Skan
167290075Sobrien  if (subtargets || code == SET
167390075Sobrien      || (GET_CODE (target) == REG && GET_CODE (source) == REG
167490075Sobrien	  && REGNO (target) != REGNO (source)))
167590075Sobrien    {
167690075Sobrien      /* After arm_reorg has been called, we can't fix up expensive
1677117395Skan	 constants by pushing them into memory so we must synthesize
167890075Sobrien	 them in-line, regardless of the cost.  This is only likely to
167990075Sobrien	 be more costly on chips that have load delay slots and we are
168090075Sobrien	 compiling without running the scheduler (so no splitting
168190075Sobrien	 occurred before the final instruction emission).
168290075Sobrien
168390075Sobrien	 Ref: gcc -O1 -mcpu=strongarm gcc.c-torture/compile/980506-2.c
168490075Sobrien      */
168590075Sobrien      if (!after_arm_reorg
1686169689Skan	  && !cond
1687169689Skan	  && (arm_gen_constant (code, mode, NULL_RTX, val, target, source,
1688169689Skan				1, 0)
168990075Sobrien	      > arm_constant_limit + (code != SET)))
169090075Sobrien	{
169190075Sobrien	  if (code == SET)
169290075Sobrien	    {
169390075Sobrien	      /* Currently SET is the only monadic value for CODE, all
169490075Sobrien		 the rest are diadic.  */
1695169689Skan	      emit_set_insn (target, GEN_INT (val));
169690075Sobrien	      return 1;
169790075Sobrien	    }
169890075Sobrien	  else
169990075Sobrien	    {
170090075Sobrien	      rtx temp = subtargets ? gen_reg_rtx (mode) : target;
170190075Sobrien
1702169689Skan	      emit_set_insn (temp, GEN_INT (val));
170390075Sobrien	      /* For MINUS, the value is subtracted from, since we never
170490075Sobrien		 have subtraction of a constant.  */
170590075Sobrien	      if (code == MINUS)
1706169689Skan		emit_set_insn (target, gen_rtx_MINUS (mode, temp, source));
170790075Sobrien	      else
1708169689Skan		emit_set_insn (target,
1709169689Skan			       gen_rtx_fmt_ee (code, mode, source, temp));
171090075Sobrien	      return 2;
171190075Sobrien	    }
171290075Sobrien	}
171390075Sobrien    }
171490075Sobrien
1715169689Skan  return arm_gen_constant (code, mode, cond, val, target, source, subtargets,
1716169689Skan			   1);
171790075Sobrien}
171890075Sobrien
171990075Sobrienstatic int
1720132718Skancount_insns_for_constant (HOST_WIDE_INT remainder, int i)
172190075Sobrien{
172290075Sobrien  HOST_WIDE_INT temp1;
172390075Sobrien  int num_insns = 0;
172490075Sobrien  do
172590075Sobrien    {
172690075Sobrien      int end;
1727169689Skan
172890075Sobrien      if (i <= 0)
172990075Sobrien	i += 32;
173090075Sobrien      if (remainder & (3 << (i - 2)))
173190075Sobrien	{
173290075Sobrien	  end = i - 8;
173390075Sobrien	  if (end < 0)
173490075Sobrien	    end += 32;
173590075Sobrien	  temp1 = remainder & ((0x0ff << end)
173690075Sobrien				    | ((i < end) ? (0xff >> (32 - end)) : 0));
173790075Sobrien	  remainder &= ~temp1;
173890075Sobrien	  num_insns++;
173990075Sobrien	  i -= 6;
174090075Sobrien	}
174190075Sobrien      i -= 2;
174290075Sobrien    } while (remainder);
174390075Sobrien  return num_insns;
174490075Sobrien}
174590075Sobrien
1746169689Skan/* Emit an instruction with the indicated PATTERN.  If COND is
1747169689Skan   non-NULL, conditionalize the execution of the instruction on COND
1748169689Skan   being true.  */
1749169689Skan
1750169689Skanstatic void
1751169689Skanemit_constant_insn (rtx cond, rtx pattern)
1752169689Skan{
1753169689Skan  if (cond)
1754169689Skan    pattern = gen_rtx_COND_EXEC (VOIDmode, copy_rtx (cond), pattern);
1755169689Skan  emit_insn (pattern);
1756169689Skan}
1757169689Skan
175890075Sobrien/* As above, but extra parameter GENERATE which, if clear, suppresses
175990075Sobrien   RTL generation.  */
176090075Sobrien
176190075Sobrienstatic int
1762169689Skanarm_gen_constant (enum rtx_code code, enum machine_mode mode, rtx cond,
1763132718Skan		  HOST_WIDE_INT val, rtx target, rtx source, int subtargets,
1764132718Skan		  int generate)
176590075Sobrien{
176690075Sobrien  int can_invert = 0;
176790075Sobrien  int can_negate = 0;
176890075Sobrien  int can_negate_initial = 0;
176990075Sobrien  int can_shift = 0;
177090075Sobrien  int i;
177190075Sobrien  int num_bits_set = 0;
177290075Sobrien  int set_sign_bit_copies = 0;
177390075Sobrien  int clear_sign_bit_copies = 0;
177490075Sobrien  int clear_zero_bit_copies = 0;
177590075Sobrien  int set_zero_bit_copies = 0;
177690075Sobrien  int insns = 0;
177790075Sobrien  unsigned HOST_WIDE_INT temp1, temp2;
177890075Sobrien  unsigned HOST_WIDE_INT remainder = val & 0xffffffff;
177990075Sobrien
178090075Sobrien  /* Find out which operations are safe for a given CODE.  Also do a quick
178190075Sobrien     check for degenerate cases; these can occur when DImode operations
178290075Sobrien     are split.  */
178390075Sobrien  switch (code)
178490075Sobrien    {
178590075Sobrien    case SET:
178690075Sobrien      can_invert = 1;
178790075Sobrien      can_shift = 1;
178890075Sobrien      can_negate = 1;
178990075Sobrien      break;
179090075Sobrien
179190075Sobrien    case PLUS:
179290075Sobrien      can_negate = 1;
179390075Sobrien      can_negate_initial = 1;
179490075Sobrien      break;
179590075Sobrien
179690075Sobrien    case IOR:
179790075Sobrien      if (remainder == 0xffffffff)
179890075Sobrien	{
179990075Sobrien	  if (generate)
1800169689Skan	    emit_constant_insn (cond,
1801169689Skan				gen_rtx_SET (VOIDmode, target,
1802169689Skan					     GEN_INT (ARM_SIGN_EXTEND (val))));
180390075Sobrien	  return 1;
180490075Sobrien	}
180590075Sobrien      if (remainder == 0)
180690075Sobrien	{
180790075Sobrien	  if (reload_completed && rtx_equal_p (target, source))
180890075Sobrien	    return 0;
180990075Sobrien	  if (generate)
1810169689Skan	    emit_constant_insn (cond,
1811169689Skan				gen_rtx_SET (VOIDmode, target, source));
181290075Sobrien	  return 1;
181390075Sobrien	}
181490075Sobrien      break;
181590075Sobrien
181690075Sobrien    case AND:
181790075Sobrien      if (remainder == 0)
181890075Sobrien	{
181990075Sobrien	  if (generate)
1820169689Skan	    emit_constant_insn (cond,
1821169689Skan				gen_rtx_SET (VOIDmode, target, const0_rtx));
182290075Sobrien	  return 1;
182390075Sobrien	}
182490075Sobrien      if (remainder == 0xffffffff)
182590075Sobrien	{
182690075Sobrien	  if (reload_completed && rtx_equal_p (target, source))
182790075Sobrien	    return 0;
182890075Sobrien	  if (generate)
1829169689Skan	    emit_constant_insn (cond,
1830169689Skan				gen_rtx_SET (VOIDmode, target, source));
183190075Sobrien	  return 1;
183290075Sobrien	}
183390075Sobrien      can_invert = 1;
183490075Sobrien      break;
183590075Sobrien
183690075Sobrien    case XOR:
183790075Sobrien      if (remainder == 0)
183890075Sobrien	{
183990075Sobrien	  if (reload_completed && rtx_equal_p (target, source))
184090075Sobrien	    return 0;
184190075Sobrien	  if (generate)
1842169689Skan	    emit_constant_insn (cond,
1843169689Skan				gen_rtx_SET (VOIDmode, target, source));
184490075Sobrien	  return 1;
184590075Sobrien	}
184690075Sobrien
1847169689Skan      /* We don't know how to handle other cases yet.  */
1848169689Skan      gcc_assert (remainder == 0xffffffff);
184990075Sobrien
1850169689Skan      if (generate)
1851169689Skan	emit_constant_insn (cond,
1852169689Skan			    gen_rtx_SET (VOIDmode, target,
1853169689Skan					 gen_rtx_NOT (mode, source)));
1854169689Skan      return 1;
1855169689Skan
185690075Sobrien    case MINUS:
185790075Sobrien      /* We treat MINUS as (val - source), since (source - val) is always
185890075Sobrien	 passed as (source + (-val)).  */
185990075Sobrien      if (remainder == 0)
186090075Sobrien	{
186190075Sobrien	  if (generate)
1862169689Skan	    emit_constant_insn (cond,
1863169689Skan				gen_rtx_SET (VOIDmode, target,
1864169689Skan					     gen_rtx_NEG (mode, source)));
186590075Sobrien	  return 1;
186690075Sobrien	}
186790075Sobrien      if (const_ok_for_arm (val))
186890075Sobrien	{
186990075Sobrien	  if (generate)
1870169689Skan	    emit_constant_insn (cond,
1871169689Skan				gen_rtx_SET (VOIDmode, target,
1872169689Skan					     gen_rtx_MINUS (mode, GEN_INT (val),
1873169689Skan							    source)));
187490075Sobrien	  return 1;
187590075Sobrien	}
187690075Sobrien      can_negate = 1;
187790075Sobrien
187890075Sobrien      break;
187990075Sobrien
188090075Sobrien    default:
1881169689Skan      gcc_unreachable ();
188290075Sobrien    }
188390075Sobrien
188490075Sobrien  /* If we can do it in one insn get out quickly.  */
188590075Sobrien  if (const_ok_for_arm (val)
188690075Sobrien      || (can_negate_initial && const_ok_for_arm (-val))
188790075Sobrien      || (can_invert && const_ok_for_arm (~val)))
188890075Sobrien    {
188990075Sobrien      if (generate)
1890169689Skan	emit_constant_insn (cond,
1891169689Skan			    gen_rtx_SET (VOIDmode, target,
1892169689Skan					 (source
1893169689Skan					  ? gen_rtx_fmt_ee (code, mode, source,
1894169689Skan							    GEN_INT (val))
1895169689Skan					  : GEN_INT (val))));
189690075Sobrien      return 1;
189790075Sobrien    }
189890075Sobrien
189990075Sobrien  /* Calculate a few attributes that may be useful for specific
190090075Sobrien     optimizations.  */
190190075Sobrien  for (i = 31; i >= 0; i--)
190290075Sobrien    {
190390075Sobrien      if ((remainder & (1 << i)) == 0)
190490075Sobrien	clear_sign_bit_copies++;
190590075Sobrien      else
190690075Sobrien	break;
190790075Sobrien    }
190890075Sobrien
190990075Sobrien  for (i = 31; i >= 0; i--)
191090075Sobrien    {
191190075Sobrien      if ((remainder & (1 << i)) != 0)
191290075Sobrien	set_sign_bit_copies++;
191390075Sobrien      else
191490075Sobrien	break;
191590075Sobrien    }
191690075Sobrien
191790075Sobrien  for (i = 0; i <= 31; i++)
191890075Sobrien    {
191990075Sobrien      if ((remainder & (1 << i)) == 0)
192090075Sobrien	clear_zero_bit_copies++;
192190075Sobrien      else
192290075Sobrien	break;
192390075Sobrien    }
192490075Sobrien
192590075Sobrien  for (i = 0; i <= 31; i++)
192690075Sobrien    {
192790075Sobrien      if ((remainder & (1 << i)) != 0)
192890075Sobrien	set_zero_bit_copies++;
192990075Sobrien      else
193090075Sobrien	break;
193190075Sobrien    }
193290075Sobrien
193390075Sobrien  switch (code)
193490075Sobrien    {
193590075Sobrien    case SET:
193690075Sobrien      /* See if we can do this by sign_extending a constant that is known
193790075Sobrien	 to be negative.  This is a good, way of doing it, since the shift
193890075Sobrien	 may well merge into a subsequent insn.  */
193990075Sobrien      if (set_sign_bit_copies > 1)
194090075Sobrien	{
194190075Sobrien	  if (const_ok_for_arm
1942169689Skan	      (temp1 = ARM_SIGN_EXTEND (remainder
194390075Sobrien					<< (set_sign_bit_copies - 1))))
194490075Sobrien	    {
194590075Sobrien	      if (generate)
194690075Sobrien		{
194790075Sobrien		  rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
1948169689Skan		  emit_constant_insn (cond,
1949169689Skan				      gen_rtx_SET (VOIDmode, new_src,
1950169689Skan						   GEN_INT (temp1)));
1951169689Skan		  emit_constant_insn (cond,
1952169689Skan				      gen_ashrsi3 (target, new_src,
1953169689Skan						   GEN_INT (set_sign_bit_copies - 1)));
195490075Sobrien		}
195590075Sobrien	      return 2;
195690075Sobrien	    }
195790075Sobrien	  /* For an inverted constant, we will need to set the low bits,
195890075Sobrien	     these will be shifted out of harm's way.  */
195990075Sobrien	  temp1 |= (1 << (set_sign_bit_copies - 1)) - 1;
196090075Sobrien	  if (const_ok_for_arm (~temp1))
196190075Sobrien	    {
196290075Sobrien	      if (generate)
196390075Sobrien		{
196490075Sobrien		  rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
1965169689Skan		  emit_constant_insn (cond,
1966169689Skan				      gen_rtx_SET (VOIDmode, new_src,
1967169689Skan						   GEN_INT (temp1)));
1968169689Skan		  emit_constant_insn (cond,
1969169689Skan				      gen_ashrsi3 (target, new_src,
1970169689Skan						   GEN_INT (set_sign_bit_copies - 1)));
197190075Sobrien		}
197290075Sobrien	      return 2;
197390075Sobrien	    }
197490075Sobrien	}
197590075Sobrien
1976169689Skan      /* See if we can calculate the value as the difference between two
1977169689Skan	 valid immediates.  */
1978169689Skan      if (clear_sign_bit_copies + clear_zero_bit_copies <= 16)
1979169689Skan	{
1980169689Skan	  int topshift = clear_sign_bit_copies & ~1;
1981169689Skan
1982169689Skan	  temp1 = ARM_SIGN_EXTEND ((remainder + (0x00800000 >> topshift))
1983169689Skan				   & (0xff000000 >> topshift));
1984169689Skan
1985169689Skan	  /* If temp1 is zero, then that means the 9 most significant
1986169689Skan	     bits of remainder were 1 and we've caused it to overflow.
1987169689Skan	     When topshift is 0 we don't need to do anything since we
1988169689Skan	     can borrow from 'bit 32'.  */
1989169689Skan	  if (temp1 == 0 && topshift != 0)
1990169689Skan	    temp1 = 0x80000000 >> (topshift - 1);
1991169689Skan
1992169689Skan	  temp2 = ARM_SIGN_EXTEND (temp1 - remainder);
1993169689Skan
1994169689Skan	  if (const_ok_for_arm (temp2))
1995169689Skan	    {
1996169689Skan	      if (generate)
1997169689Skan		{
1998169689Skan		  rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
1999169689Skan		  emit_constant_insn (cond,
2000169689Skan				      gen_rtx_SET (VOIDmode, new_src,
2001169689Skan						   GEN_INT (temp1)));
2002169689Skan		  emit_constant_insn (cond,
2003169689Skan				      gen_addsi3 (target, new_src,
2004169689Skan						  GEN_INT (-temp2)));
2005169689Skan		}
2006169689Skan
2007169689Skan	      return 2;
2008169689Skan	    }
2009169689Skan	}
2010169689Skan
201190075Sobrien      /* See if we can generate this by setting the bottom (or the top)
201290075Sobrien	 16 bits, and then shifting these into the other half of the
201390075Sobrien	 word.  We only look for the simplest cases, to do more would cost
201490075Sobrien	 too much.  Be careful, however, not to generate this when the
201590075Sobrien	 alternative would take fewer insns.  */
201690075Sobrien      if (val & 0xffff0000)
201790075Sobrien	{
201890075Sobrien	  temp1 = remainder & 0xffff0000;
201990075Sobrien	  temp2 = remainder & 0x0000ffff;
202090075Sobrien
202190075Sobrien	  /* Overlaps outside this range are best done using other methods.  */
202290075Sobrien	  for (i = 9; i < 24; i++)
202390075Sobrien	    {
202490075Sobrien	      if ((((temp2 | (temp2 << i)) & 0xffffffff) == remainder)
202590075Sobrien		  && !const_ok_for_arm (temp2))
202690075Sobrien		{
202790075Sobrien		  rtx new_src = (subtargets
202890075Sobrien				 ? (generate ? gen_reg_rtx (mode) : NULL_RTX)
202990075Sobrien				 : target);
2030169689Skan		  insns = arm_gen_constant (code, mode, cond, temp2, new_src,
203190075Sobrien					    source, subtargets, generate);
203290075Sobrien		  source = new_src;
203390075Sobrien		  if (generate)
2034169689Skan		    emit_constant_insn
2035169689Skan		      (cond,
2036169689Skan		       gen_rtx_SET
2037169689Skan		       (VOIDmode, target,
2038169689Skan			gen_rtx_IOR (mode,
2039169689Skan				     gen_rtx_ASHIFT (mode, source,
2040169689Skan						     GEN_INT (i)),
2041169689Skan				     source)));
204290075Sobrien		  return insns + 1;
204390075Sobrien		}
204490075Sobrien	    }
204590075Sobrien
204690075Sobrien	  /* Don't duplicate cases already considered.  */
204790075Sobrien	  for (i = 17; i < 24; i++)
204890075Sobrien	    {
204990075Sobrien	      if (((temp1 | (temp1 >> i)) == remainder)
205090075Sobrien		  && !const_ok_for_arm (temp1))
205190075Sobrien		{
205290075Sobrien		  rtx new_src = (subtargets
205390075Sobrien				 ? (generate ? gen_reg_rtx (mode) : NULL_RTX)
205490075Sobrien				 : target);
2055169689Skan		  insns = arm_gen_constant (code, mode, cond, temp1, new_src,
205690075Sobrien					    source, subtargets, generate);
205790075Sobrien		  source = new_src;
205890075Sobrien		  if (generate)
2059169689Skan		    emit_constant_insn
2060169689Skan		      (cond,
2061169689Skan		       gen_rtx_SET (VOIDmode, target,
206290075Sobrien				    gen_rtx_IOR
206390075Sobrien				    (mode,
206490075Sobrien				     gen_rtx_LSHIFTRT (mode, source,
206590075Sobrien						       GEN_INT (i)),
206690075Sobrien				     source)));
206790075Sobrien		  return insns + 1;
206890075Sobrien		}
206990075Sobrien	    }
207090075Sobrien	}
207190075Sobrien      break;
207290075Sobrien
207390075Sobrien    case IOR:
207490075Sobrien    case XOR:
207590075Sobrien      /* If we have IOR or XOR, and the constant can be loaded in a
207690075Sobrien	 single instruction, and we can find a temporary to put it in,
207790075Sobrien	 then this can be done in two instructions instead of 3-4.  */
207890075Sobrien      if (subtargets
207990075Sobrien	  /* TARGET can't be NULL if SUBTARGETS is 0 */
208090075Sobrien	  || (reload_completed && !reg_mentioned_p (target, source)))
208190075Sobrien	{
208290075Sobrien	  if (const_ok_for_arm (ARM_SIGN_EXTEND (~val)))
208390075Sobrien	    {
208490075Sobrien	      if (generate)
208590075Sobrien		{
208690075Sobrien		  rtx sub = subtargets ? gen_reg_rtx (mode) : target;
208790075Sobrien
2088169689Skan		  emit_constant_insn (cond,
2089169689Skan				      gen_rtx_SET (VOIDmode, sub,
2090169689Skan						   GEN_INT (val)));
2091169689Skan		  emit_constant_insn (cond,
2092169689Skan				      gen_rtx_SET (VOIDmode, target,
2093169689Skan						   gen_rtx_fmt_ee (code, mode,
2094169689Skan								   source, sub)));
209590075Sobrien		}
209690075Sobrien	      return 2;
209790075Sobrien	    }
209890075Sobrien	}
209990075Sobrien
210090075Sobrien      if (code == XOR)
210190075Sobrien	break;
210290075Sobrien
210390075Sobrien      if (set_sign_bit_copies > 8
210490075Sobrien	  && (val & (-1 << (32 - set_sign_bit_copies))) == val)
210590075Sobrien	{
210690075Sobrien	  if (generate)
210790075Sobrien	    {
210890075Sobrien	      rtx sub = subtargets ? gen_reg_rtx (mode) : target;
210990075Sobrien	      rtx shift = GEN_INT (set_sign_bit_copies);
211090075Sobrien
2111169689Skan	      emit_constant_insn
2112169689Skan		(cond,
2113169689Skan		 gen_rtx_SET (VOIDmode, sub,
2114169689Skan			      gen_rtx_NOT (mode,
2115169689Skan					   gen_rtx_ASHIFT (mode,
2116169689Skan							   source,
2117169689Skan							   shift))));
2118169689Skan	      emit_constant_insn
2119169689Skan		(cond,
2120169689Skan		 gen_rtx_SET (VOIDmode, target,
2121169689Skan			      gen_rtx_NOT (mode,
2122169689Skan					   gen_rtx_LSHIFTRT (mode, sub,
2123169689Skan							     shift))));
212490075Sobrien	    }
212590075Sobrien	  return 2;
212690075Sobrien	}
212790075Sobrien
212890075Sobrien      if (set_zero_bit_copies > 8
212990075Sobrien	  && (remainder & ((1 << set_zero_bit_copies) - 1)) == remainder)
213090075Sobrien	{
213190075Sobrien	  if (generate)
213290075Sobrien	    {
213390075Sobrien	      rtx sub = subtargets ? gen_reg_rtx (mode) : target;
213490075Sobrien	      rtx shift = GEN_INT (set_zero_bit_copies);
213590075Sobrien
2136169689Skan	      emit_constant_insn
2137169689Skan		(cond,
2138169689Skan		 gen_rtx_SET (VOIDmode, sub,
2139169689Skan			      gen_rtx_NOT (mode,
2140169689Skan					   gen_rtx_LSHIFTRT (mode,
2141169689Skan							     source,
2142169689Skan							     shift))));
2143169689Skan	      emit_constant_insn
2144169689Skan		(cond,
2145169689Skan		 gen_rtx_SET (VOIDmode, target,
2146169689Skan			      gen_rtx_NOT (mode,
2147169689Skan					   gen_rtx_ASHIFT (mode, sub,
2148169689Skan							   shift))));
214990075Sobrien	    }
215090075Sobrien	  return 2;
215190075Sobrien	}
215290075Sobrien
215390075Sobrien      if (const_ok_for_arm (temp1 = ARM_SIGN_EXTEND (~val)))
215490075Sobrien	{
215590075Sobrien	  if (generate)
215690075Sobrien	    {
215790075Sobrien	      rtx sub = subtargets ? gen_reg_rtx (mode) : target;
2158169689Skan	      emit_constant_insn (cond,
2159169689Skan				  gen_rtx_SET (VOIDmode, sub,
2160169689Skan					       gen_rtx_NOT (mode, source)));
216190075Sobrien	      source = sub;
216290075Sobrien	      if (subtargets)
216390075Sobrien		sub = gen_reg_rtx (mode);
2164169689Skan	      emit_constant_insn (cond,
2165169689Skan				  gen_rtx_SET (VOIDmode, sub,
2166169689Skan					       gen_rtx_AND (mode, source,
2167169689Skan							    GEN_INT (temp1))));
2168169689Skan	      emit_constant_insn (cond,
2169169689Skan				  gen_rtx_SET (VOIDmode, target,
2170169689Skan					       gen_rtx_NOT (mode, sub)));
217190075Sobrien	    }
217290075Sobrien	  return 3;
217390075Sobrien	}
217490075Sobrien      break;
217590075Sobrien
217690075Sobrien    case AND:
217790075Sobrien      /* See if two shifts will do 2 or more insn's worth of work.  */
217890075Sobrien      if (clear_sign_bit_copies >= 16 && clear_sign_bit_copies < 24)
217990075Sobrien	{
218090075Sobrien	  HOST_WIDE_INT shift_mask = ((0xffffffff
218190075Sobrien				       << (32 - clear_sign_bit_copies))
218290075Sobrien				      & 0xffffffff);
218390075Sobrien
218490075Sobrien	  if ((remainder | shift_mask) != 0xffffffff)
218590075Sobrien	    {
218690075Sobrien	      if (generate)
218790075Sobrien		{
218890075Sobrien		  rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
2189169689Skan		  insns = arm_gen_constant (AND, mode, cond,
2190169689Skan					    remainder | shift_mask,
219190075Sobrien					    new_src, source, subtargets, 1);
219290075Sobrien		  source = new_src;
219390075Sobrien		}
219490075Sobrien	      else
219590075Sobrien		{
219690075Sobrien		  rtx targ = subtargets ? NULL_RTX : target;
2197169689Skan		  insns = arm_gen_constant (AND, mode, cond,
2198169689Skan					    remainder | shift_mask,
219990075Sobrien					    targ, source, subtargets, 0);
220090075Sobrien		}
220190075Sobrien	    }
220290075Sobrien
220390075Sobrien	  if (generate)
220490075Sobrien	    {
220590075Sobrien	      rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
220690075Sobrien	      rtx shift = GEN_INT (clear_sign_bit_copies);
220790075Sobrien
220890075Sobrien	      emit_insn (gen_ashlsi3 (new_src, source, shift));
220990075Sobrien	      emit_insn (gen_lshrsi3 (target, new_src, shift));
221090075Sobrien	    }
221190075Sobrien
221290075Sobrien	  return insns + 2;
221390075Sobrien	}
221490075Sobrien
221590075Sobrien      if (clear_zero_bit_copies >= 16 && clear_zero_bit_copies < 24)
221690075Sobrien	{
221790075Sobrien	  HOST_WIDE_INT shift_mask = (1 << clear_zero_bit_copies) - 1;
2218169689Skan
221990075Sobrien	  if ((remainder | shift_mask) != 0xffffffff)
222090075Sobrien	    {
222190075Sobrien	      if (generate)
222290075Sobrien		{
222390075Sobrien		  rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
222490075Sobrien
2225169689Skan		  insns = arm_gen_constant (AND, mode, cond,
2226169689Skan					    remainder | shift_mask,
222790075Sobrien					    new_src, source, subtargets, 1);
222890075Sobrien		  source = new_src;
222990075Sobrien		}
223090075Sobrien	      else
223190075Sobrien		{
223290075Sobrien		  rtx targ = subtargets ? NULL_RTX : target;
223390075Sobrien
2234169689Skan		  insns = arm_gen_constant (AND, mode, cond,
2235169689Skan					    remainder | shift_mask,
223690075Sobrien					    targ, source, subtargets, 0);
223790075Sobrien		}
223890075Sobrien	    }
223990075Sobrien
224090075Sobrien	  if (generate)
224190075Sobrien	    {
224290075Sobrien	      rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
224390075Sobrien	      rtx shift = GEN_INT (clear_zero_bit_copies);
224490075Sobrien
224590075Sobrien	      emit_insn (gen_lshrsi3 (new_src, source, shift));
224690075Sobrien	      emit_insn (gen_ashlsi3 (target, new_src, shift));
224790075Sobrien	    }
224890075Sobrien
224990075Sobrien	  return insns + 2;
225090075Sobrien	}
225190075Sobrien
225290075Sobrien      break;
225390075Sobrien
225490075Sobrien    default:
225590075Sobrien      break;
225690075Sobrien    }
225790075Sobrien
225890075Sobrien  for (i = 0; i < 32; i++)
225990075Sobrien    if (remainder & (1 << i))
226090075Sobrien      num_bits_set++;
226190075Sobrien
226290075Sobrien  if (code == AND || (can_invert && num_bits_set > 16))
226390075Sobrien    remainder = (~remainder) & 0xffffffff;
226490075Sobrien  else if (code == PLUS && num_bits_set > 16)
226590075Sobrien    remainder = (-remainder) & 0xffffffff;
226690075Sobrien  else
226790075Sobrien    {
226890075Sobrien      can_invert = 0;
226990075Sobrien      can_negate = 0;
227090075Sobrien    }
227190075Sobrien
227290075Sobrien  /* Now try and find a way of doing the job in either two or three
227390075Sobrien     instructions.
227490075Sobrien     We start by looking for the largest block of zeros that are aligned on
227590075Sobrien     a 2-bit boundary, we then fill up the temps, wrapping around to the
227690075Sobrien     top of the word when we drop off the bottom.
227790075Sobrien     In the worst case this code should produce no more than four insns.  */
227890075Sobrien  {
227990075Sobrien    int best_start = 0;
228090075Sobrien    int best_consecutive_zeros = 0;
228190075Sobrien
228290075Sobrien    for (i = 0; i < 32; i += 2)
228390075Sobrien      {
228490075Sobrien	int consecutive_zeros = 0;
228590075Sobrien
228690075Sobrien	if (!(remainder & (3 << i)))
228790075Sobrien	  {
228890075Sobrien	    while ((i < 32) && !(remainder & (3 << i)))
228990075Sobrien	      {
229090075Sobrien		consecutive_zeros += 2;
229190075Sobrien		i += 2;
229290075Sobrien	      }
229390075Sobrien	    if (consecutive_zeros > best_consecutive_zeros)
229490075Sobrien	      {
229590075Sobrien		best_consecutive_zeros = consecutive_zeros;
229690075Sobrien		best_start = i - consecutive_zeros;
229790075Sobrien	      }
229890075Sobrien	    i -= 2;
229990075Sobrien	  }
230090075Sobrien      }
230190075Sobrien
230290075Sobrien    /* So long as it won't require any more insns to do so, it's
230390075Sobrien       desirable to emit a small constant (in bits 0...9) in the last
230490075Sobrien       insn.  This way there is more chance that it can be combined with
230590075Sobrien       a later addressing insn to form a pre-indexed load or store
230690075Sobrien       operation.  Consider:
230790075Sobrien
230890075Sobrien	       *((volatile int *)0xe0000100) = 1;
230990075Sobrien	       *((volatile int *)0xe0000110) = 2;
231090075Sobrien
231190075Sobrien       We want this to wind up as:
231290075Sobrien
231390075Sobrien		mov rA, #0xe0000000
231490075Sobrien		mov rB, #1
231590075Sobrien		str rB, [rA, #0x100]
231690075Sobrien		mov rB, #2
231790075Sobrien		str rB, [rA, #0x110]
231890075Sobrien
231990075Sobrien       rather than having to synthesize both large constants from scratch.
232090075Sobrien
232190075Sobrien       Therefore, we calculate how many insns would be required to emit
2322169689Skan       the constant starting from `best_start', and also starting from
2323169689Skan       zero (i.e. with bit 31 first to be output).  If `best_start' doesn't
232490075Sobrien       yield a shorter sequence, we may as well use zero.  */
232590075Sobrien    if (best_start != 0
232690075Sobrien	&& ((((unsigned HOST_WIDE_INT) 1) << best_start) < remainder)
2327169689Skan	&& (count_insns_for_constant (remainder, 0) <=
232890075Sobrien	    count_insns_for_constant (remainder, best_start)))
232990075Sobrien      best_start = 0;
233090075Sobrien
233190075Sobrien    /* Now start emitting the insns.  */
233290075Sobrien    i = best_start;
233390075Sobrien    do
233490075Sobrien      {
233590075Sobrien	int end;
233690075Sobrien
233790075Sobrien	if (i <= 0)
233890075Sobrien	  i += 32;
233990075Sobrien	if (remainder & (3 << (i - 2)))
234090075Sobrien	  {
234190075Sobrien	    end = i - 8;
234290075Sobrien	    if (end < 0)
234390075Sobrien	      end += 32;
234490075Sobrien	    temp1 = remainder & ((0x0ff << end)
234590075Sobrien				 | ((i < end) ? (0xff >> (32 - end)) : 0));
234690075Sobrien	    remainder &= ~temp1;
234790075Sobrien
234890075Sobrien	    if (generate)
234990075Sobrien	      {
235090075Sobrien		rtx new_src, temp1_rtx;
235190075Sobrien
235290075Sobrien		if (code == SET || code == MINUS)
235390075Sobrien		  {
235490075Sobrien		    new_src = (subtargets ? gen_reg_rtx (mode) : target);
235590075Sobrien		    if (can_invert && code != MINUS)
235690075Sobrien		      temp1 = ~temp1;
235790075Sobrien		  }
235890075Sobrien		else
235990075Sobrien		  {
236090075Sobrien		    if (remainder && subtargets)
236190075Sobrien		      new_src = gen_reg_rtx (mode);
236290075Sobrien		    else
236390075Sobrien		      new_src = target;
236490075Sobrien		    if (can_invert)
236590075Sobrien		      temp1 = ~temp1;
236690075Sobrien		    else if (can_negate)
236790075Sobrien		      temp1 = -temp1;
236890075Sobrien		  }
236990075Sobrien
237090075Sobrien		temp1 = trunc_int_for_mode (temp1, mode);
237190075Sobrien		temp1_rtx = GEN_INT (temp1);
237290075Sobrien
237390075Sobrien		if (code == SET)
237490075Sobrien		  ;
237590075Sobrien		else if (code == MINUS)
237690075Sobrien		  temp1_rtx = gen_rtx_MINUS (mode, temp1_rtx, source);
237790075Sobrien		else
237890075Sobrien		  temp1_rtx = gen_rtx_fmt_ee (code, mode, source, temp1_rtx);
237990075Sobrien
2380169689Skan		emit_constant_insn (cond,
2381169689Skan				    gen_rtx_SET (VOIDmode, new_src,
2382169689Skan						 temp1_rtx));
238390075Sobrien		source = new_src;
238490075Sobrien	      }
238590075Sobrien
238690075Sobrien	    if (code == SET)
238790075Sobrien	      {
238890075Sobrien		can_invert = 0;
238990075Sobrien		code = PLUS;
239090075Sobrien	      }
239190075Sobrien	    else if (code == MINUS)
239290075Sobrien	      code = PLUS;
239390075Sobrien
239490075Sobrien	    insns++;
239590075Sobrien	    i -= 6;
239690075Sobrien	  }
239790075Sobrien	i -= 2;
239890075Sobrien      }
239990075Sobrien    while (remainder);
240090075Sobrien  }
240190075Sobrien
240290075Sobrien  return insns;
240390075Sobrien}
240490075Sobrien
240590075Sobrien/* Canonicalize a comparison so that we are more likely to recognize it.
240690075Sobrien   This can be done for a few constant compares, where we can make the
240790075Sobrien   immediate value easier to load.  */
240890075Sobrien
240990075Sobrienenum rtx_code
2410169689Skanarm_canonicalize_comparison (enum rtx_code code, enum machine_mode mode,
2411169689Skan			     rtx * op1)
241290075Sobrien{
241390075Sobrien  unsigned HOST_WIDE_INT i = INTVAL (*op1);
2414169689Skan  unsigned HOST_WIDE_INT maxval;
2415169689Skan  maxval = (((unsigned HOST_WIDE_INT) 1) << (GET_MODE_BITSIZE(mode) - 1)) - 1;
241690075Sobrien
241790075Sobrien  switch (code)
241890075Sobrien    {
241990075Sobrien    case EQ:
242090075Sobrien    case NE:
242190075Sobrien      return code;
242290075Sobrien
242390075Sobrien    case GT:
242490075Sobrien    case LE:
2425169689Skan      if (i != maxval
242690075Sobrien	  && (const_ok_for_arm (i + 1) || const_ok_for_arm (-(i + 1))))
242790075Sobrien	{
242890075Sobrien	  *op1 = GEN_INT (i + 1);
242990075Sobrien	  return code == GT ? GE : LT;
243090075Sobrien	}
243190075Sobrien      break;
243290075Sobrien
243390075Sobrien    case GE:
243490075Sobrien    case LT:
2435169689Skan      if (i != ~maxval
243690075Sobrien	  && (const_ok_for_arm (i - 1) || const_ok_for_arm (-(i - 1))))
243790075Sobrien	{
243890075Sobrien	  *op1 = GEN_INT (i - 1);
243990075Sobrien	  return code == GE ? GT : LE;
244090075Sobrien	}
244190075Sobrien      break;
244290075Sobrien
244390075Sobrien    case GTU:
244490075Sobrien    case LEU:
244590075Sobrien      if (i != ~((unsigned HOST_WIDE_INT) 0)
244690075Sobrien	  && (const_ok_for_arm (i + 1) || const_ok_for_arm (-(i + 1))))
244790075Sobrien	{
244890075Sobrien	  *op1 = GEN_INT (i + 1);
244990075Sobrien	  return code == GTU ? GEU : LTU;
245090075Sobrien	}
245190075Sobrien      break;
245290075Sobrien
245390075Sobrien    case GEU:
245490075Sobrien    case LTU:
245590075Sobrien      if (i != 0
245690075Sobrien	  && (const_ok_for_arm (i - 1) || const_ok_for_arm (-(i - 1))))
245790075Sobrien	{
245890075Sobrien	  *op1 = GEN_INT (i - 1);
245990075Sobrien	  return code == GEU ? GTU : LEU;
246090075Sobrien	}
246190075Sobrien      break;
246290075Sobrien
246390075Sobrien    default:
2464169689Skan      gcc_unreachable ();
246590075Sobrien    }
246690075Sobrien
246790075Sobrien  return code;
246890075Sobrien}
246990075Sobrien
2470169689Skan
2471169689Skan/* Define how to find the value returned by a function.  */
2472169689Skan
2473169689Skanrtx
2474169689Skanarm_function_value(tree type, tree func ATTRIBUTE_UNUSED)
2475169689Skan{
2476169689Skan  enum machine_mode mode;
2477169689Skan  int unsignedp ATTRIBUTE_UNUSED;
2478169689Skan  rtx r ATTRIBUTE_UNUSED;
2479169689Skan
2480169689Skan  mode = TYPE_MODE (type);
2481169689Skan  /* Promote integer types.  */
2482169689Skan  if (INTEGRAL_TYPE_P (type))
2483169689Skan    PROMOTE_FUNCTION_MODE (mode, unsignedp, type);
2484169689Skan
2485169689Skan  /* Promotes small structs returned in a register to full-word size
2486169689Skan     for big-endian AAPCS.  */
2487169689Skan  if (arm_return_in_msb (type))
2488169689Skan    {
2489169689Skan      HOST_WIDE_INT size = int_size_in_bytes (type);
2490169689Skan      if (size % UNITS_PER_WORD != 0)
2491169689Skan	{
2492169689Skan	  size += UNITS_PER_WORD - size % UNITS_PER_WORD;
2493169689Skan	  mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0);
2494169689Skan	}
2495169689Skan    }
2496169689Skan
2497169689Skan  return LIBCALL_VALUE(mode);
2498169689Skan}
2499169689Skan
2500169689Skan/* Determine the amount of memory needed to store the possible return
2501169689Skan   registers of an untyped call.  */
2502169689Skanint
2503169689Skanarm_apply_result_size (void)
2504169689Skan{
2505169689Skan  int size = 16;
2506169689Skan
2507169689Skan  if (TARGET_ARM)
2508169689Skan    {
2509169689Skan      if (TARGET_HARD_FLOAT_ABI)
2510169689Skan	{
2511169689Skan	  if (TARGET_FPA)
2512169689Skan	    size += 12;
2513169689Skan	  if (TARGET_MAVERICK)
2514169689Skan	    size += 8;
2515169689Skan	}
2516169689Skan      if (TARGET_IWMMXT_ABI)
2517169689Skan	size += 8;
2518169689Skan    }
2519169689Skan
2520169689Skan  return size;
2521169689Skan}
2522169689Skan
252390075Sobrien/* Decide whether a type should be returned in memory (true)
252490075Sobrien   or in a register (false).  This is called by the macro
252590075Sobrien   RETURN_IN_MEMORY.  */
252690075Sobrienint
2527132718Skanarm_return_in_memory (tree type)
252890075Sobrien{
2529117395Skan  HOST_WIDE_INT size;
2530117395Skan
2531169689Skan  if (!AGGREGATE_TYPE_P (type) &&
2532169689Skan      (TREE_CODE (type) != VECTOR_TYPE) &&
2533169689Skan      !(TARGET_AAPCS_BASED && TREE_CODE (type) == COMPLEX_TYPE))
2534169689Skan    /* All simple types are returned in registers.
2535169689Skan       For AAPCS, complex types are treated the same as aggregates.  */
253690075Sobrien    return 0;
2537117395Skan
2538117395Skan  size = int_size_in_bytes (type);
2539117395Skan
2540169689Skan  if (arm_abi != ARM_ABI_APCS)
2541117395Skan    {
2542169689Skan      /* ATPCS and later return aggregate types in memory only if they are
2543117395Skan	 larger than a word (or are variable size).  */
2544117395Skan      return (size < 0 || size > UNITS_PER_WORD);
2545117395Skan    }
2546169689Skan
2547169689Skan  /* To maximize backwards compatibility with previous versions of gcc,
2548169689Skan     return vectors up to 4 words in registers.  */
2549169689Skan  if (TREE_CODE (type) == VECTOR_TYPE)
2550169689Skan    return (size < 0 || size > (4 * UNITS_PER_WORD));
2551169689Skan
2552132718Skan  /* For the arm-wince targets we choose to be compatible with Microsoft's
255390075Sobrien     ARM and Thumb compilers, which always return aggregates in memory.  */
255490075Sobrien#ifndef ARM_WINCE
255590075Sobrien  /* All structures/unions bigger than one word are returned in memory.
255690075Sobrien     Also catch the case where int_size_in_bytes returns -1.  In this case
2557132718Skan     the aggregate is either huge or of variable size, and in either case
255890075Sobrien     we will want to return it via memory and not in a register.  */
2559117395Skan  if (size < 0 || size > UNITS_PER_WORD)
256090075Sobrien    return 1;
2561169689Skan
256290075Sobrien  if (TREE_CODE (type) == RECORD_TYPE)
256390075Sobrien    {
256490075Sobrien      tree field;
256590075Sobrien
256690075Sobrien      /* For a struct the APCS says that we only return in a register
256790075Sobrien	 if the type is 'integer like' and every addressable element
256890075Sobrien	 has an offset of zero.  For practical purposes this means
256990075Sobrien	 that the structure can have at most one non bit-field element
257090075Sobrien	 and that this element must be the first one in the structure.  */
2571169689Skan
257290075Sobrien      /* Find the first field, ignoring non FIELD_DECL things which will
257390075Sobrien	 have been created by C++.  */
257490075Sobrien      for (field = TYPE_FIELDS (type);
257590075Sobrien	   field && TREE_CODE (field) != FIELD_DECL;
257690075Sobrien	   field = TREE_CHAIN (field))
257790075Sobrien	continue;
2578169689Skan
257990075Sobrien      if (field == NULL)
258090075Sobrien	return 0; /* An empty structure.  Allowed by an extension to ANSI C.  */
258190075Sobrien
258290075Sobrien      /* Check that the first field is valid for returning in a register.  */
258390075Sobrien
258490075Sobrien      /* ... Floats are not allowed */
258590075Sobrien      if (FLOAT_TYPE_P (TREE_TYPE (field)))
258690075Sobrien	return 1;
258790075Sobrien
258890075Sobrien      /* ... Aggregates that are not themselves valid for returning in
258990075Sobrien	 a register are not allowed.  */
259090075Sobrien      if (RETURN_IN_MEMORY (TREE_TYPE (field)))
259190075Sobrien	return 1;
259290075Sobrien
259390075Sobrien      /* Now check the remaining fields, if any.  Only bitfields are allowed,
259490075Sobrien	 since they are not addressable.  */
259590075Sobrien      for (field = TREE_CHAIN (field);
259690075Sobrien	   field;
259790075Sobrien	   field = TREE_CHAIN (field))
259890075Sobrien	{
259990075Sobrien	  if (TREE_CODE (field) != FIELD_DECL)
260090075Sobrien	    continue;
2601169689Skan
260290075Sobrien	  if (!DECL_BIT_FIELD_TYPE (field))
260390075Sobrien	    return 1;
260490075Sobrien	}
260590075Sobrien
260690075Sobrien      return 0;
260790075Sobrien    }
2608169689Skan
260990075Sobrien  if (TREE_CODE (type) == UNION_TYPE)
261090075Sobrien    {
261190075Sobrien      tree field;
261290075Sobrien
261390075Sobrien      /* Unions can be returned in registers if every element is
261490075Sobrien	 integral, or can be returned in an integer register.  */
261590075Sobrien      for (field = TYPE_FIELDS (type);
261690075Sobrien	   field;
261790075Sobrien	   field = TREE_CHAIN (field))
261890075Sobrien	{
261990075Sobrien	  if (TREE_CODE (field) != FIELD_DECL)
262090075Sobrien	    continue;
262190075Sobrien
262290075Sobrien	  if (FLOAT_TYPE_P (TREE_TYPE (field)))
262390075Sobrien	    return 1;
2624169689Skan
262590075Sobrien	  if (RETURN_IN_MEMORY (TREE_TYPE (field)))
262690075Sobrien	    return 1;
262790075Sobrien	}
2628169689Skan
262990075Sobrien      return 0;
263090075Sobrien    }
2631169689Skan#endif /* not ARM_WINCE */
2632169689Skan
263390075Sobrien  /* Return all other types in memory.  */
263490075Sobrien  return 1;
263590075Sobrien}
263690075Sobrien
2637132718Skan/* Indicate whether or not words of a double are in big-endian order.  */
2638117395Skan
2639117395Skanint
2640132718Skanarm_float_words_big_endian (void)
2641117395Skan{
2642169689Skan  if (TARGET_MAVERICK)
2643132718Skan    return 0;
2644117395Skan
2645117395Skan  /* For FPA, float words are always big-endian.  For VFP, floats words
2646117395Skan     follow the memory system mode.  */
2647117395Skan
2648169689Skan  if (TARGET_FPA)
2649117395Skan    {
2650117395Skan      return 1;
2651117395Skan    }
2652117395Skan
2653117395Skan  if (TARGET_VFP)
2654117395Skan    return (TARGET_BIG_END ? 1 : 0);
2655117395Skan
2656117395Skan  return 1;
2657117395Skan}
2658117395Skan
265990075Sobrien/* Initialize a variable CUM of type CUMULATIVE_ARGS
266090075Sobrien   for a call to a function whose data type is FNTYPE.
266190075Sobrien   For a library call, FNTYPE is NULL.  */
266290075Sobrienvoid
2663169689Skanarm_init_cumulative_args (CUMULATIVE_ARGS *pcum, tree fntype,
2664132718Skan			  rtx libname  ATTRIBUTE_UNUSED,
2665132718Skan			  tree fndecl ATTRIBUTE_UNUSED)
266690075Sobrien{
266790075Sobrien  /* On the ARM, the offset starts at 0.  */
2668169689Skan  pcum->nregs = 0;
2669132718Skan  pcum->iwmmxt_nregs = 0;
2670169689Skan  pcum->can_split = true;
2671169689Skan
267290075Sobrien  pcum->call_cookie = CALL_NORMAL;
267390075Sobrien
267490075Sobrien  if (TARGET_LONG_CALLS)
267590075Sobrien    pcum->call_cookie = CALL_LONG;
2676169689Skan
267790075Sobrien  /* Check for long call/short call attributes.  The attributes
267890075Sobrien     override any command line option.  */
267990075Sobrien  if (fntype)
268090075Sobrien    {
268190075Sobrien      if (lookup_attribute ("short_call", TYPE_ATTRIBUTES (fntype)))
268290075Sobrien	pcum->call_cookie = CALL_SHORT;
268390075Sobrien      else if (lookup_attribute ("long_call", TYPE_ATTRIBUTES (fntype)))
268490075Sobrien	pcum->call_cookie = CALL_LONG;
268590075Sobrien    }
2686132718Skan
2687132718Skan  /* Varargs vectors are treated the same as long long.
2688132718Skan     named_count avoids having to change the way arm handles 'named' */
2689132718Skan  pcum->named_count = 0;
2690132718Skan  pcum->nargs = 0;
2691132718Skan
2692132718Skan  if (TARGET_REALLY_IWMMXT && fntype)
2693132718Skan    {
2694132718Skan      tree fn_arg;
2695132718Skan
2696132718Skan      for (fn_arg = TYPE_ARG_TYPES (fntype);
2697132718Skan	   fn_arg;
2698132718Skan	   fn_arg = TREE_CHAIN (fn_arg))
2699132718Skan	pcum->named_count += 1;
2700132718Skan
2701132718Skan      if (! pcum->named_count)
2702132718Skan	pcum->named_count = INT_MAX;
2703132718Skan    }
270490075Sobrien}
270590075Sobrien
2706169689Skan
2707169689Skan/* Return true if mode/type need doubleword alignment.  */
2708169689Skanbool
2709169689Skanarm_needs_doubleword_align (enum machine_mode mode, tree type)
2710169689Skan{
2711169689Skan  return (GET_MODE_ALIGNMENT (mode) > PARM_BOUNDARY
2712169689Skan	  || (type && TYPE_ALIGN (type) > PARM_BOUNDARY));
2713169689Skan}
2714169689Skan
2715169689Skan
271690075Sobrien/* Determine where to put an argument to a function.
271790075Sobrien   Value is zero to push the argument on the stack,
271890075Sobrien   or a hard register in which to store the argument.
271990075Sobrien
272090075Sobrien   MODE is the argument's machine mode.
272190075Sobrien   TYPE is the data type of the argument (as a tree).
272290075Sobrien    This is null for libcalls where that information may
272390075Sobrien    not be available.
272490075Sobrien   CUM is a variable of type CUMULATIVE_ARGS which gives info about
272590075Sobrien    the preceding args and about the function being called.
272690075Sobrien   NAMED is nonzero if this argument is a named parameter
272790075Sobrien    (otherwise it is an extra parameter matching an ellipsis).  */
272890075Sobrien
272990075Sobrienrtx
2730132718Skanarm_function_arg (CUMULATIVE_ARGS *pcum, enum machine_mode mode,
2731169689Skan		  tree type, int named)
273290075Sobrien{
2733169689Skan  int nregs;
2734169689Skan
2735169689Skan  /* Varargs vectors are treated the same as long long.
2736169689Skan     named_count avoids having to change the way arm handles 'named' */
2737169689Skan  if (TARGET_IWMMXT_ABI
2738169689Skan      && arm_vector_mode_supported_p (mode)
2739169689Skan      && pcum->named_count > pcum->nargs + 1)
2740132718Skan    {
2741169689Skan      if (pcum->iwmmxt_nregs <= 9)
2742169689Skan	return gen_rtx_REG (mode, pcum->iwmmxt_nregs + FIRST_IWMMXT_REGNUM);
2743169689Skan      else
2744132718Skan	{
2745169689Skan	  pcum->can_split = false;
2746169689Skan	  return NULL_RTX;
2747132718Skan	}
2748132718Skan    }
2749132718Skan
2750169689Skan  /* Put doubleword aligned quantities in even register pairs.  */
2751169689Skan  if (pcum->nregs & 1
2752169689Skan      && ARM_DOUBLEWORD_ALIGN
2753169689Skan      && arm_needs_doubleword_align (mode, type))
2754169689Skan    pcum->nregs++;
2755169689Skan
275690075Sobrien  if (mode == VOIDmode)
275790075Sobrien    /* Compute operand 2 of the call insn.  */
275890075Sobrien    return GEN_INT (pcum->call_cookie);
2759169689Skan
2760169689Skan  /* Only allow splitting an arg between regs and memory if all preceding
2761169689Skan     args were allocated to regs.  For args passed by reference we only count
2762169689Skan     the reference pointer.  */
2763169689Skan  if (pcum->can_split)
2764169689Skan    nregs = 1;
2765169689Skan  else
2766169689Skan    nregs = ARM_NUM_REGS2 (mode, type);
2767169689Skan
2768169689Skan  if (!named || pcum->nregs + nregs > NUM_ARG_REGS)
276990075Sobrien    return NULL_RTX;
2770169689Skan
277190075Sobrien  return gen_rtx_REG (mode, pcum->nregs);
277290075Sobrien}
2773117395Skan
2774169689Skanstatic int
2775169689Skanarm_arg_partial_bytes (CUMULATIVE_ARGS *pcum, enum machine_mode mode,
2776169689Skan		       tree type, bool named ATTRIBUTE_UNUSED)
2777117395Skan{
2778169689Skan  int nregs = pcum->nregs;
2779117395Skan
2780169689Skan  if (arm_vector_mode_supported_p (mode))
2781169689Skan    return 0;
2782117395Skan
2783169689Skan  if (NUM_ARG_REGS > nregs
2784169689Skan      && (NUM_ARG_REGS < nregs + ARM_NUM_REGS2 (mode, type))
2785169689Skan      && pcum->can_split)
2786169689Skan    return (NUM_ARG_REGS - nregs) * UNITS_PER_WORD;
2787117395Skan
2788169689Skan  return 0;
2789169689Skan}
2790132718Skan
2791169689Skan/* Variable sized types are passed by reference.  This is a GCC
2792169689Skan   extension to the ARM ABI.  */
2793132718Skan
2794169689Skanstatic bool
2795169689Skanarm_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
2796169689Skan		       enum machine_mode mode ATTRIBUTE_UNUSED,
2797169689Skan		       tree type, bool named ATTRIBUTE_UNUSED)
2798169689Skan{
2799169689Skan  return type && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST;
2800117395Skan}
280190075Sobrien
280290075Sobrien/* Encode the current state of the #pragma [no_]long_calls.  */
280390075Sobrientypedef enum
280490075Sobrien{
2805169689Skan  OFF,		/* No #pragma [no_]long_calls is in effect.  */
280690075Sobrien  LONG,		/* #pragma long_calls is in effect.  */
280790075Sobrien  SHORT		/* #pragma no_long_calls is in effect.  */
280890075Sobrien} arm_pragma_enum;
280990075Sobrien
281090075Sobrienstatic arm_pragma_enum arm_pragma_long_calls = OFF;
281190075Sobrien
281290075Sobrienvoid
2813132718Skanarm_pr_long_calls (struct cpp_reader * pfile ATTRIBUTE_UNUSED)
281490075Sobrien{
281590075Sobrien  arm_pragma_long_calls = LONG;
281690075Sobrien}
281790075Sobrien
281890075Sobrienvoid
2819132718Skanarm_pr_no_long_calls (struct cpp_reader * pfile ATTRIBUTE_UNUSED)
282090075Sobrien{
282190075Sobrien  arm_pragma_long_calls = SHORT;
282290075Sobrien}
282390075Sobrien
282490075Sobrienvoid
2825132718Skanarm_pr_long_calls_off (struct cpp_reader * pfile ATTRIBUTE_UNUSED)
282690075Sobrien{
282790075Sobrien  arm_pragma_long_calls = OFF;
282890075Sobrien}
282990075Sobrien
283090075Sobrien/* Table of machine attributes.  */
283190075Sobrienconst struct attribute_spec arm_attribute_table[] =
283290075Sobrien{
283390075Sobrien  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
283490075Sobrien  /* Function calls made to this symbol must be done indirectly, because
283590075Sobrien     it may lie outside of the 26 bit addressing range of a normal function
283690075Sobrien     call.  */
283790075Sobrien  { "long_call",    0, 0, false, true,  true,  NULL },
283890075Sobrien  /* Whereas these functions are always known to reside within the 26 bit
283990075Sobrien     addressing range.  */
284090075Sobrien  { "short_call",   0, 0, false, true,  true,  NULL },
2841169689Skan  /* Interrupt Service Routines have special prologue and epilogue requirements.  */
284290075Sobrien  { "isr",          0, 1, false, false, false, arm_handle_isr_attribute },
284390075Sobrien  { "interrupt",    0, 1, false, false, false, arm_handle_isr_attribute },
284490075Sobrien  { "naked",        0, 0, true,  false, false, arm_handle_fndecl_attribute },
284590075Sobrien#ifdef ARM_PE
284690075Sobrien  /* ARM/PE has three new attributes:
284790075Sobrien     interfacearm - ?
284890075Sobrien     dllexport - for exporting a function/variable that will live in a dll
284990075Sobrien     dllimport - for importing a function/variable from a dll
285090075Sobrien
285190075Sobrien     Microsoft allows multiple declspecs in one __declspec, separating
285290075Sobrien     them with spaces.  We do NOT support this.  Instead, use __declspec
285390075Sobrien     multiple times.
285490075Sobrien  */
285590075Sobrien  { "dllimport",    0, 0, true,  false, false, NULL },
285690075Sobrien  { "dllexport",    0, 0, true,  false, false, NULL },
285790075Sobrien  { "interfacearm", 0, 0, true,  false, false, arm_handle_fndecl_attribute },
2858169689Skan#elif TARGET_DLLIMPORT_DECL_ATTRIBUTES
2859169689Skan  { "dllimport",    0, 0, false, false, false, handle_dll_attribute },
2860169689Skan  { "dllexport",    0, 0, false, false, false, handle_dll_attribute },
2861169689Skan  { "notshared",    0, 0, false, true, false, arm_handle_notshared_attribute },
286290075Sobrien#endif
286390075Sobrien  { NULL,           0, 0, false, false, false, NULL }
286490075Sobrien};
286590075Sobrien
286690075Sobrien/* Handle an attribute requiring a FUNCTION_DECL;
286790075Sobrien   arguments as in struct attribute_spec.handler.  */
286890075Sobrienstatic tree
2869132718Skanarm_handle_fndecl_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
2870132718Skan			     int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
287190075Sobrien{
287290075Sobrien  if (TREE_CODE (*node) != FUNCTION_DECL)
287390075Sobrien    {
2874169689Skan      warning (OPT_Wattributes, "%qs attribute only applies to functions",
287590075Sobrien	       IDENTIFIER_POINTER (name));
287690075Sobrien      *no_add_attrs = true;
287790075Sobrien    }
287890075Sobrien
287990075Sobrien  return NULL_TREE;
288090075Sobrien}
288190075Sobrien
288290075Sobrien/* Handle an "interrupt" or "isr" attribute;
288390075Sobrien   arguments as in struct attribute_spec.handler.  */
288490075Sobrienstatic tree
2885132718Skanarm_handle_isr_attribute (tree *node, tree name, tree args, int flags,
2886132718Skan			  bool *no_add_attrs)
288790075Sobrien{
288890075Sobrien  if (DECL_P (*node))
288990075Sobrien    {
289090075Sobrien      if (TREE_CODE (*node) != FUNCTION_DECL)
289190075Sobrien	{
2892169689Skan	  warning (OPT_Wattributes, "%qs attribute only applies to functions",
289390075Sobrien		   IDENTIFIER_POINTER (name));
289490075Sobrien	  *no_add_attrs = true;
289590075Sobrien	}
289690075Sobrien      /* FIXME: the argument if any is checked for type attributes;
289790075Sobrien	 should it be checked for decl ones?  */
289890075Sobrien    }
289990075Sobrien  else
290090075Sobrien    {
290190075Sobrien      if (TREE_CODE (*node) == FUNCTION_TYPE
290290075Sobrien	  || TREE_CODE (*node) == METHOD_TYPE)
290390075Sobrien	{
290490075Sobrien	  if (arm_isr_value (args) == ARM_FT_UNKNOWN)
290590075Sobrien	    {
2906169689Skan	      warning (OPT_Wattributes, "%qs attribute ignored",
2907169689Skan		       IDENTIFIER_POINTER (name));
290890075Sobrien	      *no_add_attrs = true;
290990075Sobrien	    }
291090075Sobrien	}
291190075Sobrien      else if (TREE_CODE (*node) == POINTER_TYPE
291290075Sobrien	       && (TREE_CODE (TREE_TYPE (*node)) == FUNCTION_TYPE
291390075Sobrien		   || TREE_CODE (TREE_TYPE (*node)) == METHOD_TYPE)
291490075Sobrien	       && arm_isr_value (args) != ARM_FT_UNKNOWN)
291590075Sobrien	{
2916169689Skan	  *node = build_variant_type_copy (*node);
291790075Sobrien	  TREE_TYPE (*node) = build_type_attribute_variant
291890075Sobrien	    (TREE_TYPE (*node),
291990075Sobrien	     tree_cons (name, args, TYPE_ATTRIBUTES (TREE_TYPE (*node))));
292090075Sobrien	  *no_add_attrs = true;
292190075Sobrien	}
292290075Sobrien      else
292390075Sobrien	{
292490075Sobrien	  /* Possibly pass this attribute on from the type to a decl.  */
292590075Sobrien	  if (flags & ((int) ATTR_FLAG_DECL_NEXT
292690075Sobrien		       | (int) ATTR_FLAG_FUNCTION_NEXT
292790075Sobrien		       | (int) ATTR_FLAG_ARRAY_NEXT))
292890075Sobrien	    {
292990075Sobrien	      *no_add_attrs = true;
293090075Sobrien	      return tree_cons (name, args, NULL_TREE);
293190075Sobrien	    }
293290075Sobrien	  else
293390075Sobrien	    {
2934169689Skan	      warning (OPT_Wattributes, "%qs attribute ignored",
2935169689Skan		       IDENTIFIER_POINTER (name));
293690075Sobrien	    }
293790075Sobrien	}
293890075Sobrien    }
293990075Sobrien
294090075Sobrien  return NULL_TREE;
294190075Sobrien}
294290075Sobrien
2943169689Skan#if TARGET_DLLIMPORT_DECL_ATTRIBUTES
2944169689Skan/* Handle the "notshared" attribute.  This attribute is another way of
2945169689Skan   requesting hidden visibility.  ARM's compiler supports
2946169689Skan   "__declspec(notshared)"; we support the same thing via an
2947169689Skan   attribute.  */
2948169689Skan
2949169689Skanstatic tree
2950169689Skanarm_handle_notshared_attribute (tree *node,
2951169689Skan				tree name ATTRIBUTE_UNUSED,
2952169689Skan				tree args ATTRIBUTE_UNUSED,
2953169689Skan				int flags ATTRIBUTE_UNUSED,
2954169689Skan				bool *no_add_attrs)
2955169689Skan{
2956169689Skan  tree decl = TYPE_NAME (*node);
2957169689Skan
2958169689Skan  if (decl)
2959169689Skan    {
2960169689Skan      DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN;
2961169689Skan      DECL_VISIBILITY_SPECIFIED (decl) = 1;
2962169689Skan      *no_add_attrs = false;
2963169689Skan    }
2964169689Skan  return NULL_TREE;
2965169689Skan}
2966169689Skan#endif
2967169689Skan
296890075Sobrien/* Return 0 if the attributes for two types are incompatible, 1 if they
296990075Sobrien   are compatible, and 2 if they are nearly compatible (which causes a
297090075Sobrien   warning to be generated).  */
297190075Sobrienstatic int
2972132718Skanarm_comp_type_attributes (tree type1, tree type2)
297390075Sobrien{
297490075Sobrien  int l1, l2, s1, s2;
2975169689Skan
297690075Sobrien  /* Check for mismatch of non-default calling convention.  */
297790075Sobrien  if (TREE_CODE (type1) != FUNCTION_TYPE)
297890075Sobrien    return 1;
297990075Sobrien
298090075Sobrien  /* Check for mismatched call attributes.  */
298190075Sobrien  l1 = lookup_attribute ("long_call", TYPE_ATTRIBUTES (type1)) != NULL;
298290075Sobrien  l2 = lookup_attribute ("long_call", TYPE_ATTRIBUTES (type2)) != NULL;
298390075Sobrien  s1 = lookup_attribute ("short_call", TYPE_ATTRIBUTES (type1)) != NULL;
298490075Sobrien  s2 = lookup_attribute ("short_call", TYPE_ATTRIBUTES (type2)) != NULL;
298590075Sobrien
298690075Sobrien  /* Only bother to check if an attribute is defined.  */
298790075Sobrien  if (l1 | l2 | s1 | s2)
298890075Sobrien    {
298990075Sobrien      /* If one type has an attribute, the other must have the same attribute.  */
299090075Sobrien      if ((l1 != l2) || (s1 != s2))
299190075Sobrien	return 0;
299290075Sobrien
299390075Sobrien      /* Disallow mixed attributes.  */
299490075Sobrien      if ((l1 & s2) || (l2 & s1))
299590075Sobrien	return 0;
299690075Sobrien    }
2997169689Skan
299890075Sobrien  /* Check for mismatched ISR attribute.  */
299990075Sobrien  l1 = lookup_attribute ("isr", TYPE_ATTRIBUTES (type1)) != NULL;
300090075Sobrien  if (! l1)
300190075Sobrien    l1 = lookup_attribute ("interrupt", TYPE_ATTRIBUTES (type1)) != NULL;
300290075Sobrien  l2 = lookup_attribute ("isr", TYPE_ATTRIBUTES (type2)) != NULL;
300390075Sobrien  if (! l2)
300490075Sobrien    l1 = lookup_attribute ("interrupt", TYPE_ATTRIBUTES (type2)) != NULL;
300590075Sobrien  if (l1 != l2)
300690075Sobrien    return 0;
300790075Sobrien
300890075Sobrien  return 1;
300990075Sobrien}
301090075Sobrien
301190075Sobrien/*  Encode long_call or short_call attribute by prefixing
301290075Sobrien    symbol name in DECL with a special character FLAG.  */
301390075Sobrienvoid
3014132718Skanarm_encode_call_attribute (tree decl, int flag)
301590075Sobrien{
301690075Sobrien  const char * str = XSTR (XEXP (DECL_RTL (decl), 0), 0);
301790075Sobrien  int          len = strlen (str);
301890075Sobrien  char *       newstr;
301990075Sobrien
302090075Sobrien  /* Do not allow weak functions to be treated as short call.  */
302190075Sobrien  if (DECL_WEAK (decl) && flag == SHORT_CALL_FLAG_CHAR)
302290075Sobrien    return;
302390075Sobrien
302490075Sobrien  newstr = alloca (len + 2);
302590075Sobrien  newstr[0] = flag;
302690075Sobrien  strcpy (newstr + 1, str);
302790075Sobrien
302890075Sobrien  newstr = (char *) ggc_alloc_string (newstr, len + 1);
302990075Sobrien  XSTR (XEXP (DECL_RTL (decl), 0), 0) = newstr;
303090075Sobrien}
303190075Sobrien
303290075Sobrien/*  Assigns default attributes to newly defined type.  This is used to
303390075Sobrien    set short_call/long_call attributes for function types of
303490075Sobrien    functions defined inside corresponding #pragma scopes.  */
303590075Sobrienstatic void
3036132718Skanarm_set_default_type_attributes (tree type)
303790075Sobrien{
303890075Sobrien  /* Add __attribute__ ((long_call)) to all functions, when
303990075Sobrien     inside #pragma long_calls or __attribute__ ((short_call)),
304090075Sobrien     when inside #pragma no_long_calls.  */
304190075Sobrien  if (TREE_CODE (type) == FUNCTION_TYPE || TREE_CODE (type) == METHOD_TYPE)
304290075Sobrien    {
304390075Sobrien      tree type_attr_list, attr_name;
304490075Sobrien      type_attr_list = TYPE_ATTRIBUTES (type);
304590075Sobrien
304690075Sobrien      if (arm_pragma_long_calls == LONG)
304790075Sobrien 	attr_name = get_identifier ("long_call");
304890075Sobrien      else if (arm_pragma_long_calls == SHORT)
304990075Sobrien 	attr_name = get_identifier ("short_call");
305090075Sobrien      else
305190075Sobrien 	return;
305290075Sobrien
305390075Sobrien      type_attr_list = tree_cons (attr_name, NULL_TREE, type_attr_list);
305490075Sobrien      TYPE_ATTRIBUTES (type) = type_attr_list;
305590075Sobrien    }
305690075Sobrien}
305790075Sobrien
305890075Sobrien/* Return 1 if the operand is a SYMBOL_REF for a function known to be
3059132718Skan   defined within the current compilation unit.  If this cannot be
306090075Sobrien   determined, then 0 is returned.  */
306190075Sobrienstatic int
3062132718Skancurrent_file_function_operand (rtx sym_ref)
306390075Sobrien{
306490075Sobrien  /* This is a bit of a fib.  A function will have a short call flag
306590075Sobrien     applied to its name if it has the short call attribute, or it has
306690075Sobrien     already been defined within the current compilation unit.  */
306790075Sobrien  if (ENCODED_SHORT_CALL_ATTR_P (XSTR (sym_ref, 0)))
306890075Sobrien    return 1;
306990075Sobrien
307090075Sobrien  /* The current function is always defined within the current compilation
3071169689Skan     unit.  If it s a weak definition however, then this may not be the real
307290075Sobrien     definition of the function, and so we have to say no.  */
307390075Sobrien  if (sym_ref == XEXP (DECL_RTL (current_function_decl), 0)
307490075Sobrien      && !DECL_WEAK (current_function_decl))
307590075Sobrien    return 1;
307690075Sobrien
307790075Sobrien  /* We cannot make the determination - default to returning 0.  */
307890075Sobrien  return 0;
307990075Sobrien}
308090075Sobrien
3081117395Skan/* Return nonzero if a 32 bit "long_call" should be generated for
308290075Sobrien   this call.  We generate a long_call if the function:
308390075Sobrien
308490075Sobrien        a.  has an __attribute__((long call))
308590075Sobrien     or b.  is within the scope of a #pragma long_calls
308690075Sobrien     or c.  the -mlong-calls command line switch has been specified
3087169689Skan         .  and either:
3088169689Skan                1. -ffunction-sections is in effect
3089169689Skan	     or 2. the current function has __attribute__ ((section))
3090169689Skan	     or 3. the target function has __attribute__ ((section))
309190075Sobrien
309290075Sobrien   However we do not generate a long call if the function:
3093169689Skan
309490075Sobrien        d.  has an __attribute__ ((short_call))
309590075Sobrien     or e.  is inside the scope of a #pragma no_long_calls
3096169689Skan     or f.  is defined within the current compilation unit.
3097169689Skan
309890075Sobrien   This function will be called by C fragments contained in the machine
3099169689Skan   description file.  SYM_REF and CALL_COOKIE correspond to the matched
310090075Sobrien   rtl operands.  CALL_SYMBOL is used to distinguish between
310190075Sobrien   two different callers of the function.  It is set to 1 in the
310290075Sobrien   "call_symbol" and "call_symbol_value" patterns and to 0 in the "call"
310390075Sobrien   and "call_value" patterns.  This is because of the difference in the
310490075Sobrien   SYM_REFs passed by these patterns.  */
310590075Sobrienint
3106132718Skanarm_is_longcall_p (rtx sym_ref, int call_cookie, int call_symbol)
310790075Sobrien{
310890075Sobrien  if (!call_symbol)
310990075Sobrien    {
311090075Sobrien      if (GET_CODE (sym_ref) != MEM)
311190075Sobrien	return 0;
311290075Sobrien
311390075Sobrien      sym_ref = XEXP (sym_ref, 0);
311490075Sobrien    }
311590075Sobrien
311690075Sobrien  if (GET_CODE (sym_ref) != SYMBOL_REF)
311790075Sobrien    return 0;
311890075Sobrien
311990075Sobrien  if (call_cookie & CALL_SHORT)
312090075Sobrien    return 0;
312190075Sobrien
3122169689Skan  if (TARGET_LONG_CALLS)
3123169689Skan    {
3124169689Skan      if (flag_function_sections
3125169689Skan	  || DECL_SECTION_NAME (current_function_decl))
3126169689Skan	/* c.3 is handled by the definition of the
3127169689Skan	   ARM_DECLARE_FUNCTION_SIZE macro.  */
3128169689Skan	return 1;
3129169689Skan    }
3130169689Skan
313190075Sobrien  if (current_file_function_operand (sym_ref))
313290075Sobrien    return 0;
3133169689Skan
313490075Sobrien  return (call_cookie & CALL_LONG)
313590075Sobrien    || ENCODED_LONG_CALL_ATTR_P (XSTR (sym_ref, 0))
313690075Sobrien    || TARGET_LONG_CALLS;
313790075Sobrien}
313890075Sobrien
3139117395Skan/* Return nonzero if it is ok to make a tail-call to DECL.  */
3140132718Skanstatic bool
3141132718Skanarm_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
314290075Sobrien{
314390075Sobrien  int call_type = TARGET_LONG_CALLS ? CALL_LONG : CALL_NORMAL;
314490075Sobrien
3145132718Skan  if (cfun->machine->sibcall_blocked)
3146132718Skan    return false;
3147132718Skan
314890075Sobrien  /* Never tailcall something for which we have no decl, or if we
314990075Sobrien     are in Thumb mode.  */
315090075Sobrien  if (decl == NULL || TARGET_THUMB)
3151132718Skan    return false;
315290075Sobrien
315390075Sobrien  /* Get the calling method.  */
315490075Sobrien  if (lookup_attribute ("short_call", TYPE_ATTRIBUTES (TREE_TYPE (decl))))
315590075Sobrien    call_type = CALL_SHORT;
315690075Sobrien  else if (lookup_attribute ("long_call", TYPE_ATTRIBUTES (TREE_TYPE (decl))))
315790075Sobrien    call_type = CALL_LONG;
315890075Sobrien
315990075Sobrien  /* Cannot tail-call to long calls, since these are out of range of
316090075Sobrien     a branch instruction.  However, if not compiling PIC, we know
316190075Sobrien     we can reach the symbol if it is in this compilation unit.  */
316290075Sobrien  if (call_type == CALL_LONG && (flag_pic || !TREE_ASM_WRITTEN (decl)))
3163132718Skan    return false;
316490075Sobrien
316590075Sobrien  /* If we are interworking and the function is not declared static
3166169689Skan     then we can't tail-call it unless we know that it exists in this
316790075Sobrien     compilation unit (since it might be a Thumb routine).  */
316890075Sobrien  if (TARGET_INTERWORK && TREE_PUBLIC (decl) && !TREE_ASM_WRITTEN (decl))
3169132718Skan    return false;
317090075Sobrien
317190075Sobrien  /* Never tailcall from an ISR routine - it needs a special exit sequence.  */
317290075Sobrien  if (IS_INTERRUPT (arm_current_func_type ()))
3173132718Skan    return false;
317490075Sobrien
317590075Sobrien  /* Everything else is ok.  */
3176132718Skan  return true;
317790075Sobrien}
317890075Sobrien
317990075Sobrien
3180132718Skan/* Addressing mode support functions.  */
3181132718Skan
3182132718Skan/* Return nonzero if X is a legitimate immediate operand when compiling
3183169689Skan   for PIC.  We know that X satisfies CONSTANT_P and flag_pic is true.  */
318490075Sobrienint
3185132718Skanlegitimate_pic_operand_p (rtx x)
318690075Sobrien{
3187169689Skan  if (GET_CODE (x) == SYMBOL_REF
3188169689Skan      || (GET_CODE (x) == CONST
3189169689Skan	  && GET_CODE (XEXP (x, 0)) == PLUS
3190169689Skan	  && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF))
319190075Sobrien    return 0;
319290075Sobrien
319390075Sobrien  return 1;
319490075Sobrien}
319590075Sobrien
319690075Sobrienrtx
3197132718Skanlegitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
319890075Sobrien{
319990075Sobrien  if (GET_CODE (orig) == SYMBOL_REF
320090075Sobrien      || GET_CODE (orig) == LABEL_REF)
320190075Sobrien    {
320290075Sobrien#ifndef AOF_ASSEMBLER
320390075Sobrien      rtx pic_ref, address;
320490075Sobrien#endif
320590075Sobrien      rtx insn;
320690075Sobrien      int subregs = 0;
320790075Sobrien
3208169689Skan      /* If this function doesn't have a pic register, create one now.
3209169689Skan	 A lot of the logic here is made obscure by the fact that this
3210169689Skan	 routine gets called as part of the rtx cost estimation
3211169689Skan	 process.  We don't want those calls to affect any assumptions
3212169689Skan	 about the real function; and further, we can't call
3213169689Skan	 entry_of_function() until we start the real expansion
3214169689Skan	 process.  */
3215169689Skan      if (!current_function_uses_pic_offset_table)
321690075Sobrien	{
3217169689Skan	  gcc_assert (!no_new_pseudos);
3218169689Skan	  if (arm_pic_register != INVALID_REGNUM)
3219169689Skan	    {
3220227391Sfabient	      if (!cfun->machine->pic_reg)
3221227391Sfabient		cfun->machine->pic_reg = gen_rtx_REG (Pmode, arm_pic_register);
3222169689Skan
3223169689Skan	      /* Play games to avoid marking the function as needing pic
3224169689Skan		 if we are being called as part of the cost-estimation
3225169689Skan		 process.  */
3226169689Skan	      if (!ir_type())
3227169689Skan		current_function_uses_pic_offset_table = 1;
3228169689Skan	    }
322990075Sobrien	  else
3230169689Skan	    {
3231169689Skan	      rtx seq;
323290075Sobrien
3233227391Sfabient	      if (!cfun->machine->pic_reg)
3234227391Sfabient		  cfun->machine->pic_reg = gen_reg_rtx (Pmode);
3235169689Skan
3236169689Skan	      /* Play games to avoid marking the function as needing pic
3237169689Skan		 if we are being called as part of the cost-estimation
3238169689Skan		 process.  */
3239169689Skan	      if (!ir_type())
3240169689Skan		{
3241169689Skan		  current_function_uses_pic_offset_table = 1;
3242169689Skan		  start_sequence ();
3243169689Skan
3244169689Skan		  arm_load_pic_register (0UL);
3245169689Skan
3246169689Skan		  seq = get_insns ();
3247169689Skan		  end_sequence ();
3248169689Skan		  emit_insn_after (seq, entry_of_function ());
3249169689Skan		}
3250169689Skan	    }
3251169689Skan	}
3252169689Skan
3253169689Skan      if (reg == 0)
3254169689Skan	{
3255169689Skan	  gcc_assert (!no_new_pseudos);
3256169689Skan	  reg = gen_reg_rtx (Pmode);
3257169689Skan
325890075Sobrien	  subregs = 1;
325990075Sobrien	}
326090075Sobrien
326190075Sobrien#ifdef AOF_ASSEMBLER
326290075Sobrien      /* The AOF assembler can generate relocations for these directly, and
326390075Sobrien	 understands that the PIC register has to be added into the offset.  */
326490075Sobrien      insn = emit_insn (gen_pic_load_addr_based (reg, orig));
326590075Sobrien#else
326690075Sobrien      if (subregs)
326790075Sobrien	address = gen_reg_rtx (Pmode);
326890075Sobrien      else
326990075Sobrien	address = reg;
327090075Sobrien
327190075Sobrien      if (TARGET_ARM)
327290075Sobrien	emit_insn (gen_pic_load_addr_arm (address, orig));
327390075Sobrien      else
327490075Sobrien	emit_insn (gen_pic_load_addr_thumb (address, orig));
327590075Sobrien
327696263Sobrien      if ((GET_CODE (orig) == LABEL_REF
3277169689Skan	   || (GET_CODE (orig) == SYMBOL_REF &&
3278132718Skan	       SYMBOL_REF_LOCAL_P (orig)))
327996263Sobrien	  && NEED_GOT_RELOC)
3280169689Skan	pic_ref = gen_rtx_PLUS (Pmode, cfun->machine->pic_reg, address);
328190075Sobrien      else
328290075Sobrien	{
3283169689Skan	  pic_ref = gen_const_mem (Pmode,
3284169689Skan				   gen_rtx_PLUS (Pmode, cfun->machine->pic_reg,
3285169689Skan					         address));
328690075Sobrien	}
328790075Sobrien
328890075Sobrien      insn = emit_move_insn (reg, pic_ref);
328990075Sobrien#endif
329090075Sobrien      /* Put a REG_EQUAL note on this insn, so that it can be optimized
329190075Sobrien	 by loop.  */
329290075Sobrien      REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, orig,
329390075Sobrien					    REG_NOTES (insn));
329490075Sobrien      return reg;
329590075Sobrien    }
329690075Sobrien  else if (GET_CODE (orig) == CONST)
329790075Sobrien    {
329890075Sobrien      rtx base, offset;
329990075Sobrien
330090075Sobrien      if (GET_CODE (XEXP (orig, 0)) == PLUS
3301169689Skan	  && XEXP (XEXP (orig, 0), 0) == cfun->machine->pic_reg)
330290075Sobrien	return orig;
330390075Sobrien
3304169689Skan      if (GET_CODE (XEXP (orig, 0)) == UNSPEC
3305169689Skan	  && XINT (XEXP (orig, 0), 1) == UNSPEC_TLS)
3306169689Skan	return orig;
3307169689Skan
330890075Sobrien      if (reg == 0)
330990075Sobrien	{
3310169689Skan	  gcc_assert (!no_new_pseudos);
3311169689Skan	  reg = gen_reg_rtx (Pmode);
331290075Sobrien	}
331390075Sobrien
3314169689Skan      gcc_assert (GET_CODE (XEXP (orig, 0)) == PLUS);
331590075Sobrien
3316169689Skan      base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg);
3317169689Skan      offset = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode,
3318169689Skan				       base == reg ? 0 : reg);
3319169689Skan
332090075Sobrien      if (GET_CODE (offset) == CONST_INT)
332190075Sobrien	{
332290075Sobrien	  /* The base register doesn't really matter, we only want to
332390075Sobrien	     test the index for the appropriate mode.  */
3324169689Skan	  if (!arm_legitimate_index_p (mode, offset, SET, 0))
3325132718Skan	    {
3326169689Skan	      gcc_assert (!no_new_pseudos);
3327169689Skan	      offset = force_reg (Pmode, offset);
3328132718Skan	    }
332990075Sobrien
333090075Sobrien	  if (GET_CODE (offset) == CONST_INT)
333190075Sobrien	    return plus_constant (base, INTVAL (offset));
333290075Sobrien	}
333390075Sobrien
333490075Sobrien      if (GET_MODE_SIZE (mode) > 4
333590075Sobrien	  && (GET_MODE_CLASS (mode) == MODE_INT
333690075Sobrien	      || TARGET_SOFT_FLOAT))
333790075Sobrien	{
333890075Sobrien	  emit_insn (gen_addsi3 (reg, base, offset));
333990075Sobrien	  return reg;
334090075Sobrien	}
334190075Sobrien
334290075Sobrien      return gen_rtx_PLUS (Pmode, base, offset);
334390075Sobrien    }
334490075Sobrien
334590075Sobrien  return orig;
334690075Sobrien}
334790075Sobrien
3348169689Skan
3349169689Skan/* Find a spare low register to use during the prolog of a function.  */
3350169689Skan
3351169689Skanstatic int
3352169689Skanthumb_find_work_register (unsigned long pushed_regs_mask)
3353169689Skan{
3354169689Skan  int reg;
3355169689Skan
3356169689Skan  /* Check the argument registers first as these are call-used.  The
3357169689Skan     register allocation order means that sometimes r3 might be used
3358169689Skan     but earlier argument registers might not, so check them all.  */
3359169689Skan  for (reg = LAST_ARG_REGNUM; reg >= 0; reg --)
3360169689Skan    if (!regs_ever_live[reg])
3361169689Skan      return reg;
3362169689Skan
3363169689Skan  /* Before going on to check the call-saved registers we can try a couple
3364169689Skan     more ways of deducing that r3 is available.  The first is when we are
3365169689Skan     pushing anonymous arguments onto the stack and we have less than 4
3366169689Skan     registers worth of fixed arguments(*).  In this case r3 will be part of
3367169689Skan     the variable argument list and so we can be sure that it will be
3368169689Skan     pushed right at the start of the function.  Hence it will be available
3369169689Skan     for the rest of the prologue.
3370169689Skan     (*): ie current_function_pretend_args_size is greater than 0.  */
3371169689Skan  if (cfun->machine->uses_anonymous_args
3372169689Skan      && current_function_pretend_args_size > 0)
3373169689Skan    return LAST_ARG_REGNUM;
3374169689Skan
3375169689Skan  /* The other case is when we have fixed arguments but less than 4 registers
3376169689Skan     worth.  In this case r3 might be used in the body of the function, but
3377169689Skan     it is not being used to convey an argument into the function.  In theory
3378169689Skan     we could just check current_function_args_size to see how many bytes are
3379169689Skan     being passed in argument registers, but it seems that it is unreliable.
3380169689Skan     Sometimes it will have the value 0 when in fact arguments are being
3381169689Skan     passed.  (See testcase execute/20021111-1.c for an example).  So we also
3382169689Skan     check the args_info.nregs field as well.  The problem with this field is
3383169689Skan     that it makes no allowances for arguments that are passed to the
3384169689Skan     function but which are not used.  Hence we could miss an opportunity
3385169689Skan     when a function has an unused argument in r3.  But it is better to be
3386169689Skan     safe than to be sorry.  */
3387169689Skan  if (! cfun->machine->uses_anonymous_args
3388169689Skan      && current_function_args_size >= 0
3389169689Skan      && current_function_args_size <= (LAST_ARG_REGNUM * UNITS_PER_WORD)
3390169689Skan      && cfun->args_info.nregs < 4)
3391169689Skan    return LAST_ARG_REGNUM;
3392169689Skan
3393169689Skan  /* Otherwise look for a call-saved register that is going to be pushed.  */
3394169689Skan  for (reg = LAST_LO_REGNUM; reg > LAST_ARG_REGNUM; reg --)
3395169689Skan    if (pushed_regs_mask & (1 << reg))
3396169689Skan      return reg;
3397169689Skan
3398169689Skan  /* Something went wrong - thumb_compute_save_reg_mask()
3399169689Skan     should have arranged for a suitable register to be pushed.  */
3400169689Skan  gcc_unreachable ();
3401169689Skan}
3402169689Skan
3403169689Skanstatic GTY(()) int pic_labelno;
3404169689Skan
3405169689Skan/* Generate code to load the PIC register.  In thumb mode SCRATCH is a
3406169689Skan   low register.  */
3407169689Skan
340890075Sobrienvoid
3409169689Skanarm_load_pic_register (unsigned long saved_regs ATTRIBUTE_UNUSED)
341090075Sobrien{
341190075Sobrien#ifndef AOF_ASSEMBLER
3412169689Skan  rtx l1, labelno, pic_tmp, pic_tmp2, pic_rtx;
341390075Sobrien  rtx global_offset_table;
341490075Sobrien
341590075Sobrien  if (current_function_uses_pic_offset_table == 0 || TARGET_SINGLE_PIC_BASE)
341690075Sobrien    return;
341790075Sobrien
3418169689Skan  gcc_assert (flag_pic);
341990075Sobrien
3420169689Skan  /* We use an UNSPEC rather than a LABEL_REF because this label never appears
3421169689Skan     in the code stream.  */
342290075Sobrien
3423169689Skan  labelno = GEN_INT (pic_labelno++);
3424169689Skan  l1 = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, labelno), UNSPEC_PIC_LABEL);
3425169689Skan  l1 = gen_rtx_CONST (VOIDmode, l1);
3426169689Skan
342790075Sobrien  global_offset_table = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
342890075Sobrien  /* On the ARM the PC register contains 'dot + 8' at the time of the
342990075Sobrien     addition, on the Thumb it is 'dot + 4'.  */
3430169689Skan  pic_tmp = plus_constant (l1, TARGET_ARM ? 8 : 4);
343190075Sobrien  if (GOT_PCREL)
343290075Sobrien    pic_tmp2 = gen_rtx_CONST (VOIDmode,
343390075Sobrien			    gen_rtx_PLUS (Pmode, global_offset_table, pc_rtx));
343490075Sobrien  else
343590075Sobrien    pic_tmp2 = gen_rtx_CONST (VOIDmode, global_offset_table);
343690075Sobrien
343790075Sobrien  pic_rtx = gen_rtx_CONST (Pmode, gen_rtx_MINUS (Pmode, pic_tmp2, pic_tmp));
3438169689Skan
343990075Sobrien  if (TARGET_ARM)
344090075Sobrien    {
3441169689Skan      emit_insn (gen_pic_load_addr_arm (cfun->machine->pic_reg, pic_rtx));
3442169689Skan      emit_insn (gen_pic_add_dot_plus_eight (cfun->machine->pic_reg,
3443169689Skan					     cfun->machine->pic_reg, labelno));
344490075Sobrien    }
344590075Sobrien  else
344690075Sobrien    {
3447169689Skan      if (arm_pic_register != INVALID_REGNUM
3448169689Skan	  && REGNO (cfun->machine->pic_reg) > LAST_LO_REGNUM)
3449169689Skan	{
3450169689Skan	  /* We will have pushed the pic register, so we should always be
3451169689Skan	     able to find a work register.  */
3452169689Skan	  pic_tmp = gen_rtx_REG (SImode,
3453169689Skan				 thumb_find_work_register (saved_regs));
3454169689Skan	  emit_insn (gen_pic_load_addr_thumb (pic_tmp, pic_rtx));
3455169689Skan	  emit_insn (gen_movsi (pic_offset_table_rtx, pic_tmp));
3456169689Skan	}
3457169689Skan      else
3458169689Skan	emit_insn (gen_pic_load_addr_thumb (cfun->machine->pic_reg, pic_rtx));
3459169689Skan      emit_insn (gen_pic_add_dot_plus_four (cfun->machine->pic_reg,
3460169689Skan					    cfun->machine->pic_reg, labelno));
346190075Sobrien    }
346290075Sobrien
346390075Sobrien  /* Need to emit this whether or not we obey regdecls,
346490075Sobrien     since setjmp/longjmp can cause life info to screw up.  */
3465169689Skan  emit_insn (gen_rtx_USE (VOIDmode, cfun->machine->pic_reg));
346690075Sobrien#endif /* AOF_ASSEMBLER */
346790075Sobrien}
346890075Sobrien
3469169689Skan
3470132718Skan/* Return nonzero if X is valid as an ARM state addressing register.  */
3471132718Skanstatic int
3472132718Skanarm_address_register_rtx_p (rtx x, int strict_p)
3473132718Skan{
3474132718Skan  int regno;
3475132718Skan
3476132718Skan  if (GET_CODE (x) != REG)
3477132718Skan    return 0;
3478132718Skan
3479132718Skan  regno = REGNO (x);
3480132718Skan
3481132718Skan  if (strict_p)
3482132718Skan    return ARM_REGNO_OK_FOR_BASE_P (regno);
3483132718Skan
3484132718Skan  return (regno <= LAST_ARM_REGNUM
3485132718Skan	  || regno >= FIRST_PSEUDO_REGISTER
3486132718Skan	  || regno == FRAME_POINTER_REGNUM
3487132718Skan	  || regno == ARG_POINTER_REGNUM);
3488132718Skan}
3489132718Skan
3490169689Skan/* Return TRUE if this rtx is the difference of a symbol and a label,
3491169689Skan   and will reduce to a PC-relative relocation in the object file.
3492169689Skan   Expressions like this can be left alone when generating PIC, rather
3493169689Skan   than forced through the GOT.  */
3494169689Skanstatic int
3495169689Skanpcrel_constant_p (rtx x)
3496169689Skan{
3497169689Skan  if (GET_CODE (x) == MINUS)
3498169689Skan    return symbol_mentioned_p (XEXP (x, 0)) && label_mentioned_p (XEXP (x, 1));
3499169689Skan
3500169689Skan  return FALSE;
3501169689Skan}
3502169689Skan
3503132718Skan/* Return nonzero if X is a valid ARM state address operand.  */
3504132718Skanint
3505169689Skanarm_legitimate_address_p (enum machine_mode mode, rtx x, RTX_CODE outer,
3506169689Skan			  int strict_p)
3507132718Skan{
3508169689Skan  bool use_ldrd;
3509169689Skan  enum rtx_code code = GET_CODE (x);
3510169689Skan
3511132718Skan  if (arm_address_register_rtx_p (x, strict_p))
3512132718Skan    return 1;
3513132718Skan
3514169689Skan  use_ldrd = (TARGET_LDRD
3515169689Skan	      && (mode == DImode
3516169689Skan		  || (mode == DFmode && (TARGET_SOFT_FLOAT || TARGET_VFP))));
3517169689Skan
3518169689Skan  if (code == POST_INC || code == PRE_DEC
3519169689Skan      || ((code == PRE_INC || code == POST_DEC)
3520169689Skan	  && (use_ldrd || GET_MODE_SIZE (mode) <= 4)))
3521132718Skan    return arm_address_register_rtx_p (XEXP (x, 0), strict_p);
3522132718Skan
3523169689Skan  else if ((code == POST_MODIFY || code == PRE_MODIFY)
3524132718Skan	   && arm_address_register_rtx_p (XEXP (x, 0), strict_p)
3525132718Skan	   && GET_CODE (XEXP (x, 1)) == PLUS
3526132718Skan	   && rtx_equal_p (XEXP (XEXP (x, 1), 0), XEXP (x, 0)))
3527169689Skan    {
3528169689Skan      rtx addend = XEXP (XEXP (x, 1), 1);
3529132718Skan
3530169689Skan      /* Don't allow ldrd post increment by register because it's hard
3531169689Skan	 to fixup invalid register choices.  */
3532169689Skan      if (use_ldrd
3533169689Skan	  && GET_CODE (x) == POST_MODIFY
3534169689Skan	  && GET_CODE (addend) == REG)
3535169689Skan	return 0;
3536169689Skan
3537169689Skan      return ((use_ldrd || GET_MODE_SIZE (mode) <= 4)
3538169689Skan	      && arm_legitimate_index_p (mode, addend, outer, strict_p));
3539169689Skan    }
3540169689Skan
3541132718Skan  /* After reload constants split into minipools will have addresses
3542132718Skan     from a LABEL_REF.  */
3543132718Skan  else if (reload_completed
3544169689Skan	   && (code == LABEL_REF
3545169689Skan	       || (code == CONST
3546132718Skan		   && GET_CODE (XEXP (x, 0)) == PLUS
3547132718Skan		   && GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF
3548132718Skan		   && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)))
3549132718Skan    return 1;
3550132718Skan
3551132718Skan  else if (mode == TImode)
3552132718Skan    return 0;
3553132718Skan
3554169689Skan  else if (code == PLUS)
3555132718Skan    {
3556132718Skan      rtx xop0 = XEXP (x, 0);
3557132718Skan      rtx xop1 = XEXP (x, 1);
3558132718Skan
3559132718Skan      return ((arm_address_register_rtx_p (xop0, strict_p)
3560169689Skan	       && arm_legitimate_index_p (mode, xop1, outer, strict_p))
3561132718Skan	      || (arm_address_register_rtx_p (xop1, strict_p)
3562169689Skan		  && arm_legitimate_index_p (mode, xop0, outer, strict_p)));
3563132718Skan    }
3564132718Skan
3565132718Skan#if 0
3566132718Skan  /* Reload currently can't handle MINUS, so disable this for now */
3567132718Skan  else if (GET_CODE (x) == MINUS)
3568132718Skan    {
3569132718Skan      rtx xop0 = XEXP (x, 0);
3570132718Skan      rtx xop1 = XEXP (x, 1);
3571132718Skan
3572132718Skan      return (arm_address_register_rtx_p (xop0, strict_p)
3573169689Skan	      && arm_legitimate_index_p (mode, xop1, outer, strict_p));
3574132718Skan    }
3575132718Skan#endif
3576132718Skan
3577132718Skan  else if (GET_MODE_CLASS (mode) != MODE_FLOAT
3578169689Skan	   && code == SYMBOL_REF
3579132718Skan	   && CONSTANT_POOL_ADDRESS_P (x)
3580132718Skan	   && ! (flag_pic
3581169689Skan		 && symbol_mentioned_p (get_pool_constant (x))
3582169689Skan		 && ! pcrel_constant_p (get_pool_constant (x))))
3583132718Skan    return 1;
3584132718Skan
3585132718Skan  return 0;
3586132718Skan}
3587132718Skan
3588132718Skan/* Return nonzero if INDEX is valid for an address index operand in
3589132718Skan   ARM state.  */
3590132718Skanstatic int
3591169689Skanarm_legitimate_index_p (enum machine_mode mode, rtx index, RTX_CODE outer,
3592169689Skan			int strict_p)
3593132718Skan{
3594132718Skan  HOST_WIDE_INT range;
3595132718Skan  enum rtx_code code = GET_CODE (index);
3596132718Skan
3597169689Skan  /* Standard coprocessor addressing modes.  */
3598169689Skan  if (TARGET_HARD_FLOAT
3599169689Skan      && (TARGET_FPA || TARGET_MAVERICK)
3600169689Skan      && (GET_MODE_CLASS (mode) == MODE_FLOAT
3601169689Skan	  || (TARGET_MAVERICK && mode == DImode)))
3602132718Skan    return (code == CONST_INT && INTVAL (index) < 1024
3603132718Skan	    && INTVAL (index) > -1024
3604132718Skan	    && (INTVAL (index) & 3) == 0);
3605132718Skan
3606169689Skan  if (TARGET_REALLY_IWMMXT && VALID_IWMMXT_REG_MODE (mode))
3607169689Skan    {
3608169689Skan      /* For DImode assume values will usually live in core regs
3609169689Skan	 and only allow LDRD addressing modes.  */
3610169689Skan      if (!TARGET_LDRD || mode != DImode)
3611169689Skan	return (code == CONST_INT
3612169689Skan		&& INTVAL (index) < 1024
3613169689Skan		&& INTVAL (index) > -1024
3614169689Skan		&& (INTVAL (index) & 3) == 0);
3615169689Skan    }
3616132718Skan
3617132718Skan  if (arm_address_register_rtx_p (index, strict_p)
3618169689Skan      && (GET_MODE_SIZE (mode) <= 4))
3619132718Skan    return 1;
3620132718Skan
3621169689Skan  if (mode == DImode || mode == DFmode)
3622132718Skan    {
3623169689Skan      if (code == CONST_INT)
3624169689Skan	{
3625169689Skan	  HOST_WIDE_INT val = INTVAL (index);
3626132718Skan
3627169689Skan	  if (TARGET_LDRD)
3628169689Skan	    return val > -256 && val < 256;
3629169689Skan	  else
3630169689Skan	    return val > -4096 && val < 4092;
3631169689Skan	}
3632169689Skan
3633169689Skan      return TARGET_LDRD && arm_address_register_rtx_p (index, strict_p);
3634132718Skan    }
3635132718Skan
3636132718Skan  if (GET_MODE_SIZE (mode) <= 4
3637169689Skan      && ! (arm_arch4
3638169689Skan	    && (mode == HImode
3639169689Skan		|| (mode == QImode && outer == SIGN_EXTEND))))
3640132718Skan    {
3641169689Skan      if (code == MULT)
3642169689Skan	{
3643169689Skan	  rtx xiop0 = XEXP (index, 0);
3644169689Skan	  rtx xiop1 = XEXP (index, 1);
3645132718Skan
3646169689Skan	  return ((arm_address_register_rtx_p (xiop0, strict_p)
3647169689Skan		   && power_of_two_operand (xiop1, SImode))
3648169689Skan		  || (arm_address_register_rtx_p (xiop1, strict_p)
3649169689Skan		      && power_of_two_operand (xiop0, SImode)));
3650169689Skan	}
3651169689Skan      else if (code == LSHIFTRT || code == ASHIFTRT
3652169689Skan	       || code == ASHIFT || code == ROTATERT)
3653169689Skan	{
3654169689Skan	  rtx op = XEXP (index, 1);
3655169689Skan
3656169689Skan	  return (arm_address_register_rtx_p (XEXP (index, 0), strict_p)
3657169689Skan		  && GET_CODE (op) == CONST_INT
3658169689Skan		  && INTVAL (op) > 0
3659169689Skan		  && INTVAL (op) <= 31);
3660169689Skan	}
3661132718Skan    }
3662132718Skan
3663169689Skan  /* For ARM v4 we may be doing a sign-extend operation during the
3664169689Skan     load.  */
3665132718Skan  if (arm_arch4)
3666169689Skan    {
3667169689Skan      if (mode == HImode || (outer == SIGN_EXTEND && mode == QImode))
3668169689Skan	range = 256;
3669169689Skan      else
3670169689Skan	range = 4096;
3671169689Skan    }
3672132718Skan  else
3673132718Skan    range = (mode == HImode) ? 4095 : 4096;
3674132718Skan
3675132718Skan  return (code == CONST_INT
3676132718Skan	  && INTVAL (index) < range
3677132718Skan	  && INTVAL (index) > -range);
3678132718Skan}
3679132718Skan
3680132718Skan/* Return nonzero if X is valid as a Thumb state base register.  */
3681132718Skanstatic int
3682132718Skanthumb_base_register_rtx_p (rtx x, enum machine_mode mode, int strict_p)
3683132718Skan{
3684132718Skan  int regno;
3685132718Skan
3686132718Skan  if (GET_CODE (x) != REG)
3687132718Skan    return 0;
3688132718Skan
3689132718Skan  regno = REGNO (x);
3690132718Skan
3691132718Skan  if (strict_p)
3692132718Skan    return THUMB_REGNO_MODE_OK_FOR_BASE_P (regno, mode);
3693132718Skan
3694132718Skan  return (regno <= LAST_LO_REGNUM
3695132718Skan	  || regno > LAST_VIRTUAL_REGISTER
3696132718Skan	  || regno == FRAME_POINTER_REGNUM
3697132718Skan	  || (GET_MODE_SIZE (mode) >= 4
3698132718Skan	      && (regno == STACK_POINTER_REGNUM
3699132718Skan		  || regno >= FIRST_PSEUDO_REGISTER
3700132718Skan		  || x == hard_frame_pointer_rtx
3701132718Skan		  || x == arg_pointer_rtx)));
3702132718Skan}
3703132718Skan
3704132718Skan/* Return nonzero if x is a legitimate index register.  This is the case
3705132718Skan   for any base register that can access a QImode object.  */
3706132718Skaninline static int
3707132718Skanthumb_index_register_rtx_p (rtx x, int strict_p)
3708132718Skan{
3709132718Skan  return thumb_base_register_rtx_p (x, QImode, strict_p);
3710132718Skan}
3711132718Skan
3712132718Skan/* Return nonzero if x is a legitimate Thumb-state address.
3713169689Skan
3714132718Skan   The AP may be eliminated to either the SP or the FP, so we use the
3715132718Skan   least common denominator, e.g. SImode, and offsets from 0 to 64.
3716132718Skan
3717132718Skan   ??? Verify whether the above is the right approach.
3718132718Skan
3719132718Skan   ??? Also, the FP may be eliminated to the SP, so perhaps that
3720132718Skan   needs special handling also.
3721132718Skan
3722132718Skan   ??? Look at how the mips16 port solves this problem.  It probably uses
3723132718Skan   better ways to solve some of these problems.
3724132718Skan
3725132718Skan   Although it is not incorrect, we don't accept QImode and HImode
3726132718Skan   addresses based on the frame pointer or arg pointer until the
3727132718Skan   reload pass starts.  This is so that eliminating such addresses
3728132718Skan   into stack based ones won't produce impossible code.  */
3729132718Skanint
3730132718Skanthumb_legitimate_address_p (enum machine_mode mode, rtx x, int strict_p)
3731132718Skan{
3732132718Skan  /* ??? Not clear if this is right.  Experiment.  */
3733132718Skan  if (GET_MODE_SIZE (mode) < 4
3734132718Skan      && !(reload_in_progress || reload_completed)
3735132718Skan      && (reg_mentioned_p (frame_pointer_rtx, x)
3736132718Skan	  || reg_mentioned_p (arg_pointer_rtx, x)
3737132718Skan	  || reg_mentioned_p (virtual_incoming_args_rtx, x)
3738132718Skan	  || reg_mentioned_p (virtual_outgoing_args_rtx, x)
3739132718Skan	  || reg_mentioned_p (virtual_stack_dynamic_rtx, x)
3740132718Skan	  || reg_mentioned_p (virtual_stack_vars_rtx, x)))
3741132718Skan    return 0;
3742132718Skan
3743132718Skan  /* Accept any base register.  SP only in SImode or larger.  */
3744132718Skan  else if (thumb_base_register_rtx_p (x, mode, strict_p))
3745132718Skan    return 1;
3746132718Skan
3747132718Skan  /* This is PC relative data before arm_reorg runs.  */
3748132718Skan  else if (GET_MODE_SIZE (mode) >= 4 && CONSTANT_P (x)
3749132718Skan	   && GET_CODE (x) == SYMBOL_REF
3750169689Skan           && CONSTANT_POOL_ADDRESS_P (x) && !flag_pic)
3751132718Skan    return 1;
3752132718Skan
3753132718Skan  /* This is PC relative data after arm_reorg runs.  */
3754132718Skan  else if (GET_MODE_SIZE (mode) >= 4 && reload_completed
3755132718Skan	   && (GET_CODE (x) == LABEL_REF
3756132718Skan	       || (GET_CODE (x) == CONST
3757132718Skan		   && GET_CODE (XEXP (x, 0)) == PLUS
3758132718Skan		   && GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF
3759132718Skan		   && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)))
3760132718Skan    return 1;
3761132718Skan
3762132718Skan  /* Post-inc indexing only supported for SImode and larger.  */
3763132718Skan  else if (GET_CODE (x) == POST_INC && GET_MODE_SIZE (mode) >= 4
3764132718Skan	   && thumb_index_register_rtx_p (XEXP (x, 0), strict_p))
3765132718Skan    return 1;
3766132718Skan
3767132718Skan  else if (GET_CODE (x) == PLUS)
3768132718Skan    {
3769132718Skan      /* REG+REG address can be any two index registers.  */
3770132718Skan      /* We disallow FRAME+REG addressing since we know that FRAME
3771132718Skan	 will be replaced with STACK, and SP relative addressing only
3772132718Skan	 permits SP+OFFSET.  */
3773132718Skan      if (GET_MODE_SIZE (mode) <= 4
3774132718Skan	  && XEXP (x, 0) != frame_pointer_rtx
3775132718Skan	  && XEXP (x, 1) != frame_pointer_rtx
3776132718Skan	  && thumb_index_register_rtx_p (XEXP (x, 0), strict_p)
3777132718Skan	  && thumb_index_register_rtx_p (XEXP (x, 1), strict_p))
3778132718Skan	return 1;
3779132718Skan
3780132718Skan      /* REG+const has 5-7 bit offset for non-SP registers.  */
3781132718Skan      else if ((thumb_index_register_rtx_p (XEXP (x, 0), strict_p)
3782132718Skan		|| XEXP (x, 0) == arg_pointer_rtx)
3783132718Skan	       && GET_CODE (XEXP (x, 1)) == CONST_INT
3784132718Skan	       && thumb_legitimate_offset_p (mode, INTVAL (XEXP (x, 1))))
3785132718Skan	return 1;
3786132718Skan
3787132718Skan      /* REG+const has 10 bit offset for SP, but only SImode and
3788132718Skan	 larger is supported.  */
3789132718Skan      /* ??? Should probably check for DI/DFmode overflow here
3790132718Skan	 just like GO_IF_LEGITIMATE_OFFSET does.  */
3791132718Skan      else if (GET_CODE (XEXP (x, 0)) == REG
3792132718Skan	       && REGNO (XEXP (x, 0)) == STACK_POINTER_REGNUM
3793132718Skan	       && GET_MODE_SIZE (mode) >= 4
3794132718Skan	       && GET_CODE (XEXP (x, 1)) == CONST_INT
3795132718Skan	       && INTVAL (XEXP (x, 1)) >= 0
3796132718Skan	       && INTVAL (XEXP (x, 1)) + GET_MODE_SIZE (mode) <= 1024
3797132718Skan	       && (INTVAL (XEXP (x, 1)) & 3) == 0)
3798132718Skan	return 1;
3799132718Skan
3800132718Skan      else if (GET_CODE (XEXP (x, 0)) == REG
3801132718Skan	       && REGNO (XEXP (x, 0)) == FRAME_POINTER_REGNUM
3802132718Skan	       && GET_MODE_SIZE (mode) >= 4
3803132718Skan	       && GET_CODE (XEXP (x, 1)) == CONST_INT
3804132718Skan	       && (INTVAL (XEXP (x, 1)) & 3) == 0)
3805132718Skan	return 1;
3806132718Skan    }
3807132718Skan
3808132718Skan  else if (GET_MODE_CLASS (mode) != MODE_FLOAT
3809132718Skan	   && GET_MODE_SIZE (mode) == 4
3810132718Skan	   && GET_CODE (x) == SYMBOL_REF
3811132718Skan	   && CONSTANT_POOL_ADDRESS_P (x)
3812169689Skan	   && ! (flag_pic
3813169689Skan		 && symbol_mentioned_p (get_pool_constant (x))
3814169689Skan		 && ! pcrel_constant_p (get_pool_constant (x))))
3815132718Skan    return 1;
3816132718Skan
3817132718Skan  return 0;
3818132718Skan}
3819132718Skan
3820132718Skan/* Return nonzero if VAL can be used as an offset in a Thumb-state address
3821132718Skan   instruction of mode MODE.  */
3822132718Skanint
3823132718Skanthumb_legitimate_offset_p (enum machine_mode mode, HOST_WIDE_INT val)
3824132718Skan{
3825132718Skan  switch (GET_MODE_SIZE (mode))
3826132718Skan    {
3827132718Skan    case 1:
3828132718Skan      return val >= 0 && val < 32;
3829132718Skan
3830132718Skan    case 2:
3831132718Skan      return val >= 0 && val < 64 && (val & 1) == 0;
3832132718Skan
3833132718Skan    default:
3834132718Skan      return (val >= 0
3835132718Skan	      && (val + GET_MODE_SIZE (mode)) <= 128
3836132718Skan	      && (val & 3) == 0);
3837132718Skan    }
3838132718Skan}
3839132718Skan
3840169689Skan/* Build the SYMBOL_REF for __tls_get_addr.  */
3841169689Skan
3842169689Skanstatic GTY(()) rtx tls_get_addr_libfunc;
3843169689Skan
3844169689Skanstatic rtx
3845169689Skanget_tls_get_addr (void)
3846169689Skan{
3847169689Skan  if (!tls_get_addr_libfunc)
3848169689Skan    tls_get_addr_libfunc = init_one_libfunc ("__tls_get_addr");
3849169689Skan  return tls_get_addr_libfunc;
3850169689Skan}
3851169689Skan
3852169689Skanstatic rtx
3853169689Skanarm_load_tp (rtx target)
3854169689Skan{
3855169689Skan  if (!target)
3856169689Skan    target = gen_reg_rtx (SImode);
3857169689Skan
3858169689Skan  if (TARGET_HARD_TP)
3859169689Skan    {
3860169689Skan      /* Can return in any reg.  */
3861169689Skan      emit_insn (gen_load_tp_hard (target));
3862169689Skan    }
3863169689Skan  else
3864169689Skan    {
3865169689Skan      /* Always returned in r0.  Immediately copy the result into a pseudo,
3866169689Skan	 otherwise other uses of r0 (e.g. setting up function arguments) may
3867169689Skan	 clobber the value.  */
3868169689Skan
3869169689Skan      rtx tmp;
3870169689Skan
3871169689Skan      emit_insn (gen_load_tp_soft ());
3872169689Skan
3873169689Skan      tmp = gen_rtx_REG (SImode, 0);
3874169689Skan      emit_move_insn (target, tmp);
3875169689Skan    }
3876169689Skan  return target;
3877169689Skan}
3878169689Skan
3879169689Skanstatic rtx
3880169689Skanload_tls_operand (rtx x, rtx reg)
3881169689Skan{
3882169689Skan  rtx tmp;
3883169689Skan
3884169689Skan  if (reg == NULL_RTX)
3885169689Skan    reg = gen_reg_rtx (SImode);
3886169689Skan
3887169689Skan  tmp = gen_rtx_CONST (SImode, x);
3888169689Skan
3889169689Skan  emit_move_insn (reg, tmp);
3890169689Skan
3891169689Skan  return reg;
3892169689Skan}
3893169689Skan
3894169689Skanstatic rtx
3895169689Skanarm_call_tls_get_addr (rtx x, rtx reg, rtx *valuep, int reloc)
3896169689Skan{
3897169689Skan  rtx insns, label, labelno, sum;
3898169689Skan
3899169689Skan  start_sequence ();
3900169689Skan
3901169689Skan  labelno = GEN_INT (pic_labelno++);
3902169689Skan  label = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, labelno), UNSPEC_PIC_LABEL);
3903169689Skan  label = gen_rtx_CONST (VOIDmode, label);
3904169689Skan
3905169689Skan  sum = gen_rtx_UNSPEC (Pmode,
3906169689Skan			gen_rtvec (4, x, GEN_INT (reloc), label,
3907169689Skan				   GEN_INT (TARGET_ARM ? 8 : 4)),
3908169689Skan			UNSPEC_TLS);
3909169689Skan  reg = load_tls_operand (sum, reg);
3910169689Skan
3911169689Skan  if (TARGET_ARM)
3912169689Skan    emit_insn (gen_pic_add_dot_plus_eight (reg, reg, labelno));
3913169689Skan  else
3914169689Skan    emit_insn (gen_pic_add_dot_plus_four (reg, reg, labelno));
3915169689Skan
3916169689Skan  *valuep = emit_library_call_value (get_tls_get_addr (), NULL_RTX, LCT_PURE, /* LCT_CONST?  */
3917169689Skan				     Pmode, 1, reg, Pmode);
3918169689Skan
3919169689Skan  insns = get_insns ();
3920169689Skan  end_sequence ();
3921169689Skan
3922169689Skan  return insns;
3923169689Skan}
3924169689Skan
3925169689Skanrtx
3926169689Skanlegitimize_tls_address (rtx x, rtx reg)
3927169689Skan{
3928169689Skan  rtx dest, tp, label, labelno, sum, insns, ret, eqv, addend;
3929169689Skan  unsigned int model = SYMBOL_REF_TLS_MODEL (x);
3930169689Skan
3931169689Skan  switch (model)
3932169689Skan    {
3933169689Skan    case TLS_MODEL_GLOBAL_DYNAMIC:
3934169689Skan      insns = arm_call_tls_get_addr (x, reg, &ret, TLS_GD32);
3935169689Skan      dest = gen_reg_rtx (Pmode);
3936169689Skan      emit_libcall_block (insns, dest, ret, x);
3937169689Skan      return dest;
3938169689Skan
3939169689Skan    case TLS_MODEL_LOCAL_DYNAMIC:
3940169689Skan      insns = arm_call_tls_get_addr (x, reg, &ret, TLS_LDM32);
3941169689Skan
3942169689Skan      /* Attach a unique REG_EQUIV, to allow the RTL optimizers to
3943169689Skan	 share the LDM result with other LD model accesses.  */
3944169689Skan      eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const1_rtx),
3945169689Skan			    UNSPEC_TLS);
3946169689Skan      dest = gen_reg_rtx (Pmode);
3947169689Skan      emit_libcall_block (insns, dest, ret, eqv);
3948169689Skan
3949169689Skan      /* Load the addend.  */
3950169689Skan      addend = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, x, GEN_INT (TLS_LDO32)),
3951169689Skan			       UNSPEC_TLS);
3952169689Skan      addend = force_reg (SImode, gen_rtx_CONST (SImode, addend));
3953169689Skan      return gen_rtx_PLUS (Pmode, dest, addend);
3954169689Skan
3955169689Skan    case TLS_MODEL_INITIAL_EXEC:
3956169689Skan      labelno = GEN_INT (pic_labelno++);
3957169689Skan      label = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, labelno), UNSPEC_PIC_LABEL);
3958169689Skan      label = gen_rtx_CONST (VOIDmode, label);
3959169689Skan      sum = gen_rtx_UNSPEC (Pmode,
3960169689Skan			    gen_rtvec (4, x, GEN_INT (TLS_IE32), label,
3961169689Skan				       GEN_INT (TARGET_ARM ? 8 : 4)),
3962169689Skan			    UNSPEC_TLS);
3963169689Skan      reg = load_tls_operand (sum, reg);
3964169689Skan
3965169689Skan      if (TARGET_ARM)
3966169689Skan	emit_insn (gen_tls_load_dot_plus_eight (reg, reg, labelno));
3967169689Skan      else
3968169689Skan	{
3969169689Skan	  emit_insn (gen_pic_add_dot_plus_four (reg, reg, labelno));
3970169689Skan	  emit_move_insn (reg, gen_const_mem (SImode, reg));
3971169689Skan	}
3972169689Skan
3973169689Skan      tp = arm_load_tp (NULL_RTX);
3974169689Skan
3975169689Skan      return gen_rtx_PLUS (Pmode, tp, reg);
3976169689Skan
3977169689Skan    case TLS_MODEL_LOCAL_EXEC:
3978169689Skan      tp = arm_load_tp (NULL_RTX);
3979169689Skan
3980169689Skan      reg = gen_rtx_UNSPEC (Pmode,
3981169689Skan			    gen_rtvec (2, x, GEN_INT (TLS_LE32)),
3982169689Skan			    UNSPEC_TLS);
3983169689Skan      reg = force_reg (SImode, gen_rtx_CONST (SImode, reg));
3984169689Skan
3985169689Skan      return gen_rtx_PLUS (Pmode, tp, reg);
3986169689Skan
3987169689Skan    default:
3988169689Skan      abort ();
3989169689Skan    }
3990169689Skan}
3991169689Skan
3992132718Skan/* Try machine-dependent ways of modifying an illegitimate address
3993132718Skan   to be legitimate.  If we find one, return the new, valid address.  */
3994132718Skanrtx
3995132718Skanarm_legitimize_address (rtx x, rtx orig_x, enum machine_mode mode)
3996132718Skan{
3997169689Skan  if (arm_tls_symbol_p (x))
3998169689Skan    return legitimize_tls_address (x, NULL_RTX);
3999169689Skan
4000132718Skan  if (GET_CODE (x) == PLUS)
4001132718Skan    {
4002132718Skan      rtx xop0 = XEXP (x, 0);
4003132718Skan      rtx xop1 = XEXP (x, 1);
4004132718Skan
4005132718Skan      if (CONSTANT_P (xop0) && !symbol_mentioned_p (xop0))
4006132718Skan	xop0 = force_reg (SImode, xop0);
4007132718Skan
4008132718Skan      if (CONSTANT_P (xop1) && !symbol_mentioned_p (xop1))
4009132718Skan	xop1 = force_reg (SImode, xop1);
4010132718Skan
4011132718Skan      if (ARM_BASE_REGISTER_RTX_P (xop0)
4012132718Skan	  && GET_CODE (xop1) == CONST_INT)
4013132718Skan	{
4014132718Skan	  HOST_WIDE_INT n, low_n;
4015132718Skan	  rtx base_reg, val;
4016132718Skan	  n = INTVAL (xop1);
4017132718Skan
4018169689Skan	  /* VFP addressing modes actually allow greater offsets, but for
4019169689Skan	     now we just stick with the lowest common denominator.  */
4020169689Skan	  if (mode == DImode
4021169689Skan	      || ((TARGET_SOFT_FLOAT || TARGET_VFP) && mode == DFmode))
4022132718Skan	    {
4023132718Skan	      low_n = n & 0x0f;
4024132718Skan	      n &= ~0x0f;
4025132718Skan	      if (low_n > 4)
4026132718Skan		{
4027132718Skan		  n += 16;
4028132718Skan		  low_n -= 16;
4029132718Skan		}
4030132718Skan	    }
4031132718Skan	  else
4032132718Skan	    {
4033132718Skan	      low_n = ((mode) == TImode ? 0
4034132718Skan		       : n >= 0 ? (n & 0xfff) : -((-n) & 0xfff));
4035132718Skan	      n -= low_n;
4036132718Skan	    }
4037132718Skan
4038132718Skan	  base_reg = gen_reg_rtx (SImode);
4039169689Skan	  val = force_operand (plus_constant (xop0, n), NULL_RTX);
4040132718Skan	  emit_move_insn (base_reg, val);
4041169689Skan	  x = plus_constant (base_reg, low_n);
4042132718Skan	}
4043132718Skan      else if (xop0 != XEXP (x, 0) || xop1 != XEXP (x, 1))
4044132718Skan	x = gen_rtx_PLUS (SImode, xop0, xop1);
4045132718Skan    }
4046132718Skan
4047132718Skan  /* XXX We don't allow MINUS any more -- see comment in
4048132718Skan     arm_legitimate_address_p ().  */
4049132718Skan  else if (GET_CODE (x) == MINUS)
4050132718Skan    {
4051132718Skan      rtx xop0 = XEXP (x, 0);
4052132718Skan      rtx xop1 = XEXP (x, 1);
4053132718Skan
4054132718Skan      if (CONSTANT_P (xop0))
4055132718Skan	xop0 = force_reg (SImode, xop0);
4056132718Skan
4057132718Skan      if (CONSTANT_P (xop1) && ! symbol_mentioned_p (xop1))
4058132718Skan	xop1 = force_reg (SImode, xop1);
4059132718Skan
4060132718Skan      if (xop0 != XEXP (x, 0) || xop1 != XEXP (x, 1))
4061132718Skan	x = gen_rtx_MINUS (SImode, xop0, xop1);
4062132718Skan    }
4063132718Skan
4064169689Skan  /* Make sure to take full advantage of the pre-indexed addressing mode
4065169689Skan     with absolute addresses which often allows for the base register to
4066169689Skan     be factorized for multiple adjacent memory references, and it might
4067169689Skan     even allows for the mini pool to be avoided entirely. */
4068169689Skan  else if (GET_CODE (x) == CONST_INT && optimize > 0)
4069169689Skan    {
4070169689Skan      unsigned int bits;
4071169689Skan      HOST_WIDE_INT mask, base, index;
4072169689Skan      rtx base_reg;
4073169689Skan
4074169689Skan      /* ldr and ldrb can use a 12 bit index, ldrsb and the rest can only
4075169689Skan         use a 8 bit index. So let's use a 12 bit index for SImode only and
4076169689Skan         hope that arm_gen_constant will enable ldrb to use more bits. */
4077169689Skan      bits = (mode == SImode) ? 12 : 8;
4078169689Skan      mask = (1 << bits) - 1;
4079169689Skan      base = INTVAL (x) & ~mask;
4080169689Skan      index = INTVAL (x) & mask;
4081169689Skan      if (bit_count (base & 0xffffffff) > (32 - bits)/2)
4082169689Skan        {
4083169689Skan	  /* It'll most probably be more efficient to generate the base
4084169689Skan	     with more bits set and use a negative index instead. */
4085169689Skan	  base |= mask;
4086169689Skan	  index -= mask;
4087169689Skan	}
4088169689Skan      base_reg = force_reg (SImode, GEN_INT (base));
4089169689Skan      x = plus_constant (base_reg, index);
4090169689Skan    }
4091169689Skan
4092132718Skan  if (flag_pic)
4093132718Skan    {
4094132718Skan      /* We need to find and carefully transform any SYMBOL and LABEL
4095132718Skan	 references; so go back to the original address expression.  */
4096132718Skan      rtx new_x = legitimize_pic_address (orig_x, mode, NULL_RTX);
4097132718Skan
4098132718Skan      if (new_x != orig_x)
4099132718Skan	x = new_x;
4100132718Skan    }
4101132718Skan
4102132718Skan  return x;
4103132718Skan}
4104132718Skan
4105169689Skan
4106169689Skan/* Try machine-dependent ways of modifying an illegitimate Thumb address
4107169689Skan   to be legitimate.  If we find one, return the new, valid address.  */
4108169689Skanrtx
4109169689Skanthumb_legitimize_address (rtx x, rtx orig_x, enum machine_mode mode)
4110169689Skan{
4111169689Skan  if (arm_tls_symbol_p (x))
4112169689Skan    return legitimize_tls_address (x, NULL_RTX);
4113169689Skan
4114169689Skan  if (GET_CODE (x) == PLUS
4115169689Skan      && GET_CODE (XEXP (x, 1)) == CONST_INT
4116169689Skan      && (INTVAL (XEXP (x, 1)) >= 32 * GET_MODE_SIZE (mode)
4117169689Skan	  || INTVAL (XEXP (x, 1)) < 0))
4118169689Skan    {
4119169689Skan      rtx xop0 = XEXP (x, 0);
4120169689Skan      rtx xop1 = XEXP (x, 1);
4121169689Skan      HOST_WIDE_INT offset = INTVAL (xop1);
4122169689Skan
4123169689Skan      /* Try and fold the offset into a biasing of the base register and
4124169689Skan	 then offsetting that.  Don't do this when optimizing for space
4125169689Skan	 since it can cause too many CSEs.  */
4126169689Skan      if (optimize_size && offset >= 0
4127169689Skan	  && offset < 256 + 31 * GET_MODE_SIZE (mode))
4128169689Skan	{
4129169689Skan	  HOST_WIDE_INT delta;
4130169689Skan
4131169689Skan	  if (offset >= 256)
4132169689Skan	    delta = offset - (256 - GET_MODE_SIZE (mode));
4133169689Skan	  else if (offset < 32 * GET_MODE_SIZE (mode) + 8)
4134169689Skan	    delta = 31 * GET_MODE_SIZE (mode);
4135169689Skan	  else
4136169689Skan	    delta = offset & (~31 * GET_MODE_SIZE (mode));
4137169689Skan
4138169689Skan	  xop0 = force_operand (plus_constant (xop0, offset - delta),
4139169689Skan				NULL_RTX);
4140169689Skan	  x = plus_constant (xop0, delta);
4141169689Skan	}
4142169689Skan      else if (offset < 0 && offset > -256)
4143169689Skan	/* Small negative offsets are best done with a subtract before the
4144169689Skan	   dereference, forcing these into a register normally takes two
4145169689Skan	   instructions.  */
4146169689Skan	x = force_operand (x, NULL_RTX);
4147169689Skan      else
4148169689Skan	{
4149169689Skan	  /* For the remaining cases, force the constant into a register.  */
4150169689Skan	  xop1 = force_reg (SImode, xop1);
4151169689Skan	  x = gen_rtx_PLUS (SImode, xop0, xop1);
4152169689Skan	}
4153169689Skan    }
4154169689Skan  else if (GET_CODE (x) == PLUS
4155169689Skan	   && s_register_operand (XEXP (x, 1), SImode)
4156169689Skan	   && !s_register_operand (XEXP (x, 0), SImode))
4157169689Skan    {
4158169689Skan      rtx xop0 = force_operand (XEXP (x, 0), NULL_RTX);
4159169689Skan
4160169689Skan      x = gen_rtx_PLUS (SImode, xop0, XEXP (x, 1));
4161169689Skan    }
4162169689Skan
4163169689Skan  if (flag_pic)
4164169689Skan    {
4165169689Skan      /* We need to find and carefully transform any SYMBOL and LABEL
4166169689Skan	 references; so go back to the original address expression.  */
4167169689Skan      rtx new_x = legitimize_pic_address (orig_x, mode, NULL_RTX);
4168169689Skan
4169169689Skan      if (new_x != orig_x)
4170169689Skan	x = new_x;
4171169689Skan    }
4172169689Skan
4173169689Skan  return x;
4174169689Skan}
4175169689Skan
4176169689Skanrtx
4177169689Skanthumb_legitimize_reload_address (rtx *x_p,
4178169689Skan				 enum machine_mode mode,
4179169689Skan				 int opnum, int type,
4180169689Skan				 int ind_levels ATTRIBUTE_UNUSED)
4181169689Skan{
4182169689Skan  rtx x = *x_p;
4183169689Skan
4184169689Skan  if (GET_CODE (x) == PLUS
4185169689Skan      && GET_MODE_SIZE (mode) < 4
4186169689Skan      && REG_P (XEXP (x, 0))
4187169689Skan      && XEXP (x, 0) == stack_pointer_rtx
4188169689Skan      && GET_CODE (XEXP (x, 1)) == CONST_INT
4189169689Skan      && !thumb_legitimate_offset_p (mode, INTVAL (XEXP (x, 1))))
4190169689Skan    {
4191169689Skan      rtx orig_x = x;
4192169689Skan
4193169689Skan      x = copy_rtx (x);
4194169689Skan      push_reload (orig_x, NULL_RTX, x_p, NULL, MODE_BASE_REG_CLASS (mode),
4195169689Skan		   Pmode, VOIDmode, 0, 0, opnum, type);
4196169689Skan      return x;
4197169689Skan    }
4198169689Skan
4199169689Skan  /* If both registers are hi-regs, then it's better to reload the
4200169689Skan     entire expression rather than each register individually.  That
4201169689Skan     only requires one reload register rather than two.  */
4202169689Skan  if (GET_CODE (x) == PLUS
4203169689Skan      && REG_P (XEXP (x, 0))
4204169689Skan      && REG_P (XEXP (x, 1))
4205169689Skan      && !REG_MODE_OK_FOR_REG_BASE_P (XEXP (x, 0), mode)
4206169689Skan      && !REG_MODE_OK_FOR_REG_BASE_P (XEXP (x, 1), mode))
4207169689Skan    {
4208169689Skan      rtx orig_x = x;
4209169689Skan
4210169689Skan      x = copy_rtx (x);
4211169689Skan      push_reload (orig_x, NULL_RTX, x_p, NULL, MODE_BASE_REG_CLASS (mode),
4212169689Skan		   Pmode, VOIDmode, 0, 0, opnum, type);
4213169689Skan      return x;
4214169689Skan    }
4215169689Skan
4216169689Skan  return NULL;
4217169689Skan}
4218169689Skan
4219169689Skan/* Test for various thread-local symbols.  */
4220169689Skan
4221169689Skan/* Return TRUE if X is a thread-local symbol.  */
4222169689Skan
4223169689Skanstatic bool
4224169689Skanarm_tls_symbol_p (rtx x)
4225169689Skan{
4226169689Skan  if (! TARGET_HAVE_TLS)
4227169689Skan    return false;
4228169689Skan
4229169689Skan  if (GET_CODE (x) != SYMBOL_REF)
4230169689Skan    return false;
4231169689Skan
4232169689Skan  return SYMBOL_REF_TLS_MODEL (x) != 0;
4233169689Skan}
4234169689Skan
4235169689Skan/* Helper for arm_tls_referenced_p.  */
4236169689Skan
4237169689Skanstatic int
4238169689Skanarm_tls_operand_p_1 (rtx *x, void *data ATTRIBUTE_UNUSED)
4239169689Skan{
4240169689Skan  if (GET_CODE (*x) == SYMBOL_REF)
4241169689Skan    return SYMBOL_REF_TLS_MODEL (*x) != 0;
4242169689Skan
4243169689Skan  /* Don't recurse into UNSPEC_TLS looking for TLS symbols; these are
4244169689Skan     TLS offsets, not real symbol references.  */
4245169689Skan  if (GET_CODE (*x) == UNSPEC
4246169689Skan      && XINT (*x, 1) == UNSPEC_TLS)
4247169689Skan    return -1;
4248169689Skan
4249169689Skan  return 0;
4250169689Skan}
4251169689Skan
4252169689Skan/* Return TRUE if X contains any TLS symbol references.  */
4253169689Skan
4254169689Skanbool
4255169689Skanarm_tls_referenced_p (rtx x)
4256169689Skan{
4257169689Skan  if (! TARGET_HAVE_TLS)
4258169689Skan    return false;
4259169689Skan
4260169689Skan  return for_each_rtx (&x, arm_tls_operand_p_1, NULL);
4261169689Skan}
4262132718Skan
426390075Sobrien#define REG_OR_SUBREG_REG(X)						\
426490075Sobrien  (GET_CODE (X) == REG							\
426590075Sobrien   || (GET_CODE (X) == SUBREG && GET_CODE (SUBREG_REG (X)) == REG))
426690075Sobrien
426790075Sobrien#define REG_OR_SUBREG_RTX(X)			\
426890075Sobrien   (GET_CODE (X) == REG ? (X) : SUBREG_REG (X))
426990075Sobrien
427090075Sobrien#ifndef COSTS_N_INSNS
427190075Sobrien#define COSTS_N_INSNS(N) ((N) * 4 - 2)
427290075Sobrien#endif
4273132718Skanstatic inline int
4274169689Skanthumb_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer)
427590075Sobrien{
427690075Sobrien  enum machine_mode mode = GET_MODE (x);
427790075Sobrien
4278169689Skan  switch (code)
427990075Sobrien    {
4280169689Skan    case ASHIFT:
4281169689Skan    case ASHIFTRT:
4282169689Skan    case LSHIFTRT:
4283169689Skan    case ROTATERT:
4284169689Skan    case PLUS:
4285169689Skan    case MINUS:
4286169689Skan    case COMPARE:
4287169689Skan    case NEG:
4288169689Skan    case NOT:
4289169689Skan      return COSTS_N_INSNS (1);
4290169689Skan
4291169689Skan    case MULT:
4292169689Skan      if (GET_CODE (XEXP (x, 1)) == CONST_INT)
429390075Sobrien	{
4294169689Skan	  int cycles = 0;
4295169689Skan	  unsigned HOST_WIDE_INT i = INTVAL (XEXP (x, 1));
4296169689Skan
4297169689Skan	  while (i)
4298169689Skan	    {
4299169689Skan	      i >>= 2;
4300169689Skan	      cycles++;
430190075Sobrien	    }
4302169689Skan	  return COSTS_N_INSNS (2) + cycles;
4303169689Skan	}
4304169689Skan      return COSTS_N_INSNS (1) + 16;
4305169689Skan
4306169689Skan    case SET:
4307169689Skan      return (COSTS_N_INSNS (1)
4308169689Skan	      + 4 * ((GET_CODE (SET_SRC (x)) == MEM)
4309169689Skan		     + GET_CODE (SET_DEST (x)) == MEM));
4310169689Skan
4311169689Skan    case CONST_INT:
4312169689Skan      if (outer == SET)
4313169689Skan	{
4314169689Skan	  if ((unsigned HOST_WIDE_INT) INTVAL (x) < 256)
4315132718Skan	    return 0;
4316169689Skan	  if (thumb_shiftable_const (INTVAL (x)))
4317169689Skan	    return COSTS_N_INSNS (2);
431890075Sobrien	  return COSTS_N_INSNS (3);
4319169689Skan	}
4320169689Skan      else if ((outer == PLUS || outer == COMPARE)
4321169689Skan	       && INTVAL (x) < 256 && INTVAL (x) > -256)
4322169689Skan	return 0;
4323169689Skan      else if (outer == AND
4324169689Skan	       && INTVAL (x) < 256 && INTVAL (x) >= -256)
4325169689Skan	return COSTS_N_INSNS (1);
4326169689Skan      else if (outer == ASHIFT || outer == ASHIFTRT
4327169689Skan	       || outer == LSHIFTRT)
4328169689Skan	return 0;
4329169689Skan      return COSTS_N_INSNS (2);
433090075Sobrien
4331169689Skan    case CONST:
4332169689Skan    case CONST_DOUBLE:
4333169689Skan    case LABEL_REF:
4334169689Skan    case SYMBOL_REF:
4335169689Skan      return COSTS_N_INSNS (3);
433690075Sobrien
4337169689Skan    case UDIV:
4338169689Skan    case UMOD:
4339169689Skan    case DIV:
4340169689Skan    case MOD:
4341169689Skan      return 100;
434290075Sobrien
4343169689Skan    case TRUNCATE:
4344169689Skan      return 99;
434590075Sobrien
4346169689Skan    case AND:
4347169689Skan    case XOR:
4348169689Skan    case IOR:
4349169689Skan      /* XXX guess.  */
4350169689Skan      return 8;
435190075Sobrien
4352169689Skan    case MEM:
4353169689Skan      /* XXX another guess.  */
4354169689Skan      /* Memory costs quite a lot for the first word, but subsequent words
4355169689Skan	 load at the equivalent of a single insn each.  */
4356169689Skan      return (10 + 4 * ((GET_MODE_SIZE (mode) - 1) / UNITS_PER_WORD)
4357169689Skan	      + ((GET_CODE (x) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (x))
4358169689Skan		 ? 4 : 0));
4359169689Skan
4360169689Skan    case IF_THEN_ELSE:
4361169689Skan      /* XXX a guess.  */
4362169689Skan      if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC)
4363169689Skan	return 14;
4364169689Skan      return 2;
4365169689Skan
4366169689Skan    case ZERO_EXTEND:
4367169689Skan      /* XXX still guessing.  */
4368169689Skan      switch (GET_MODE (XEXP (x, 0)))
4369169689Skan	{
4370169689Skan	case QImode:
4371169689Skan	  return (1 + (mode == DImode ? 4 : 0)
4372169689Skan		  + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
4373169689Skan
4374169689Skan	case HImode:
4375169689Skan	  return (4 + (mode == DImode ? 4 : 0)
4376169689Skan		  + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
4377169689Skan
4378169689Skan	case SImode:
4379169689Skan	  return (1 + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
4380169689Skan
438190075Sobrien	default:
438290075Sobrien	  return 99;
438390075Sobrien	}
4384169689Skan
4385169689Skan    default:
4386169689Skan      return 99;
438790075Sobrien    }
4388169689Skan}
4389169689Skan
4390169689Skan
4391169689Skan/* Worker routine for arm_rtx_costs.  */
4392169689Skanstatic inline int
4393169689Skanarm_rtx_costs_1 (rtx x, enum rtx_code code, enum rtx_code outer)
4394169689Skan{
4395169689Skan  enum machine_mode mode = GET_MODE (x);
4396169689Skan  enum rtx_code subcode;
4397169689Skan  int extra_cost;
4398169689Skan
439990075Sobrien  switch (code)
440090075Sobrien    {
440190075Sobrien    case MEM:
440290075Sobrien      /* Memory costs quite a lot for the first word, but subsequent words
440390075Sobrien	 load at the equivalent of a single insn each.  */
440490075Sobrien      return (10 + 4 * ((GET_MODE_SIZE (mode) - 1) / UNITS_PER_WORD)
4405117395Skan	      + (GET_CODE (x) == SYMBOL_REF
4406117395Skan		 && CONSTANT_POOL_ADDRESS_P (x) ? 4 : 0));
440790075Sobrien
440890075Sobrien    case DIV:
440990075Sobrien    case MOD:
4410132718Skan    case UDIV:
4411132718Skan    case UMOD:
4412132718Skan      return optimize_size ? COSTS_N_INSNS (2) : 100;
441390075Sobrien
441490075Sobrien    case ROTATE:
441590075Sobrien      if (mode == SImode && GET_CODE (XEXP (x, 1)) == REG)
441690075Sobrien	return 4;
441790075Sobrien      /* Fall through */
441890075Sobrien    case ROTATERT:
441990075Sobrien      if (mode != SImode)
442090075Sobrien	return 8;
442190075Sobrien      /* Fall through */
442290075Sobrien    case ASHIFT: case LSHIFTRT: case ASHIFTRT:
442390075Sobrien      if (mode == DImode)
442490075Sobrien	return (8 + (GET_CODE (XEXP (x, 1)) == CONST_INT ? 0 : 8)
4425169689Skan		+ ((GET_CODE (XEXP (x, 0)) == REG
442690075Sobrien		    || (GET_CODE (XEXP (x, 0)) == SUBREG
442790075Sobrien			&& GET_CODE (SUBREG_REG (XEXP (x, 0))) == REG))
442890075Sobrien		   ? 0 : 8));
442990075Sobrien      return (1 + ((GET_CODE (XEXP (x, 0)) == REG
443090075Sobrien		    || (GET_CODE (XEXP (x, 0)) == SUBREG
443190075Sobrien			&& GET_CODE (SUBREG_REG (XEXP (x, 0))) == REG))
443290075Sobrien		   ? 0 : 4)
443390075Sobrien	      + ((GET_CODE (XEXP (x, 1)) == REG
443490075Sobrien		  || (GET_CODE (XEXP (x, 1)) == SUBREG
443590075Sobrien		      && GET_CODE (SUBREG_REG (XEXP (x, 1))) == REG)
443690075Sobrien		  || (GET_CODE (XEXP (x, 1)) == CONST_INT))
443790075Sobrien		 ? 0 : 4));
443890075Sobrien
443990075Sobrien    case MINUS:
444090075Sobrien      if (mode == DImode)
444190075Sobrien	return (4 + (REG_OR_SUBREG_REG (XEXP (x, 1)) ? 0 : 8)
444290075Sobrien		+ ((REG_OR_SUBREG_REG (XEXP (x, 0))
444390075Sobrien		    || (GET_CODE (XEXP (x, 0)) == CONST_INT
444490075Sobrien		       && const_ok_for_arm (INTVAL (XEXP (x, 0)))))
444590075Sobrien		   ? 0 : 8));
444690075Sobrien
444790075Sobrien      if (GET_MODE_CLASS (mode) == MODE_FLOAT)
444890075Sobrien	return (2 + ((REG_OR_SUBREG_REG (XEXP (x, 1))
444990075Sobrien		      || (GET_CODE (XEXP (x, 1)) == CONST_DOUBLE
4450169689Skan			  && arm_const_double_rtx (XEXP (x, 1))))
445190075Sobrien		     ? 0 : 8)
445290075Sobrien		+ ((REG_OR_SUBREG_REG (XEXP (x, 0))
445390075Sobrien		    || (GET_CODE (XEXP (x, 0)) == CONST_DOUBLE
4454169689Skan			&& arm_const_double_rtx (XEXP (x, 0))))
445590075Sobrien		   ? 0 : 8));
445690075Sobrien
445790075Sobrien      if (((GET_CODE (XEXP (x, 0)) == CONST_INT
445890075Sobrien	    && const_ok_for_arm (INTVAL (XEXP (x, 0)))
445990075Sobrien	    && REG_OR_SUBREG_REG (XEXP (x, 1))))
446090075Sobrien	  || (((subcode = GET_CODE (XEXP (x, 1))) == ASHIFT
446190075Sobrien	       || subcode == ASHIFTRT || subcode == LSHIFTRT
446290075Sobrien	       || subcode == ROTATE || subcode == ROTATERT
446390075Sobrien	       || (subcode == MULT
446490075Sobrien		   && GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT
446590075Sobrien		   && ((INTVAL (XEXP (XEXP (x, 1), 1)) &
446690075Sobrien			(INTVAL (XEXP (XEXP (x, 1), 1)) - 1)) == 0)))
446790075Sobrien	      && REG_OR_SUBREG_REG (XEXP (XEXP (x, 1), 0))
446890075Sobrien	      && (REG_OR_SUBREG_REG (XEXP (XEXP (x, 1), 1))
446990075Sobrien		  || GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT)
447090075Sobrien	      && REG_OR_SUBREG_REG (XEXP (x, 0))))
447190075Sobrien	return 1;
447290075Sobrien      /* Fall through */
447390075Sobrien
4474169689Skan    case PLUS:
4475169689Skan      if (GET_CODE (XEXP (x, 0)) == MULT)
4476169689Skan	{
4477169689Skan	  extra_cost = rtx_cost (XEXP (x, 0), code);
4478169689Skan	  if (!REG_OR_SUBREG_REG (XEXP (x, 1)))
4479169689Skan	    extra_cost += 4 * ARM_NUM_REGS (mode);
4480169689Skan	  return extra_cost;
4481169689Skan	}
4482169689Skan
448390075Sobrien      if (GET_MODE_CLASS (mode) == MODE_FLOAT)
448490075Sobrien	return (2 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 8)
448590075Sobrien		+ ((REG_OR_SUBREG_REG (XEXP (x, 1))
448690075Sobrien		    || (GET_CODE (XEXP (x, 1)) == CONST_DOUBLE
4487169689Skan			&& arm_const_double_rtx (XEXP (x, 1))))
448890075Sobrien		   ? 0 : 8));
448990075Sobrien
449090075Sobrien      /* Fall through */
4491169689Skan    case AND: case XOR: case IOR:
449290075Sobrien      extra_cost = 0;
449390075Sobrien
449490075Sobrien      /* Normally the frame registers will be spilt into reg+const during
449590075Sobrien	 reload, so it is a bad idea to combine them with other instructions,
449690075Sobrien	 since then they might not be moved outside of loops.  As a compromise
449790075Sobrien	 we allow integration with ops that have a constant as their second
449890075Sobrien	 operand.  */
449990075Sobrien      if ((REG_OR_SUBREG_REG (XEXP (x, 0))
450090075Sobrien	   && ARM_FRAME_RTX (REG_OR_SUBREG_RTX (XEXP (x, 0)))
450190075Sobrien	   && GET_CODE (XEXP (x, 1)) != CONST_INT)
450290075Sobrien	  || (REG_OR_SUBREG_REG (XEXP (x, 0))
450390075Sobrien	      && ARM_FRAME_RTX (REG_OR_SUBREG_RTX (XEXP (x, 0)))))
450490075Sobrien	extra_cost = 4;
450590075Sobrien
450690075Sobrien      if (mode == DImode)
450790075Sobrien	return (4 + extra_cost + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 8)
450890075Sobrien		+ ((REG_OR_SUBREG_REG (XEXP (x, 1))
450990075Sobrien		    || (GET_CODE (XEXP (x, 1)) == CONST_INT
451090075Sobrien			&& const_ok_for_op (INTVAL (XEXP (x, 1)), code)))
451190075Sobrien		   ? 0 : 8));
451290075Sobrien
451390075Sobrien      if (REG_OR_SUBREG_REG (XEXP (x, 0)))
451490075Sobrien	return (1 + (GET_CODE (XEXP (x, 1)) == CONST_INT ? 0 : extra_cost)
451590075Sobrien		+ ((REG_OR_SUBREG_REG (XEXP (x, 1))
451690075Sobrien		    || (GET_CODE (XEXP (x, 1)) == CONST_INT
451790075Sobrien			&& const_ok_for_op (INTVAL (XEXP (x, 1)), code)))
451890075Sobrien		   ? 0 : 4));
451990075Sobrien
452090075Sobrien      else if (REG_OR_SUBREG_REG (XEXP (x, 1)))
452190075Sobrien	return (1 + extra_cost
452290075Sobrien		+ ((((subcode = GET_CODE (XEXP (x, 0))) == ASHIFT
452390075Sobrien		     || subcode == LSHIFTRT || subcode == ASHIFTRT
452490075Sobrien		     || subcode == ROTATE || subcode == ROTATERT
452590075Sobrien		     || (subcode == MULT
452690075Sobrien			 && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
452790075Sobrien			 && ((INTVAL (XEXP (XEXP (x, 0), 1)) &
452890075Sobrien			      (INTVAL (XEXP (XEXP (x, 0), 1)) - 1)) == 0)))
452990075Sobrien		    && (REG_OR_SUBREG_REG (XEXP (XEXP (x, 0), 0)))
453090075Sobrien		    && ((REG_OR_SUBREG_REG (XEXP (XEXP (x, 0), 1)))
453190075Sobrien			|| GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT))
453290075Sobrien		   ? 0 : 4));
453390075Sobrien
453490075Sobrien      return 8;
453590075Sobrien
453690075Sobrien    case MULT:
4537169689Skan      /* This should have been handled by the CPU specific routines.  */
4538169689Skan      gcc_unreachable ();
453990075Sobrien
454090075Sobrien    case TRUNCATE:
4541169689Skan      if (arm_arch3m && mode == SImode
454290075Sobrien	  && GET_CODE (XEXP (x, 0)) == LSHIFTRT
454390075Sobrien	  && GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT
454490075Sobrien	  && (GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0))
454590075Sobrien	      == GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 1)))
454690075Sobrien	  && (GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == ZERO_EXTEND
454790075Sobrien	      || GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == SIGN_EXTEND))
454890075Sobrien	return 8;
454990075Sobrien      return 99;
455090075Sobrien
455190075Sobrien    case NEG:
455290075Sobrien      if (GET_MODE_CLASS (mode) == MODE_FLOAT)
455390075Sobrien	return 4 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 6);
455490075Sobrien      /* Fall through */
455590075Sobrien    case NOT:
455690075Sobrien      if (mode == DImode)
455790075Sobrien	return 4 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4);
455890075Sobrien
455990075Sobrien      return 1 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4);
456090075Sobrien
456190075Sobrien    case IF_THEN_ELSE:
456290075Sobrien      if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC)
456390075Sobrien	return 14;
456490075Sobrien      return 2;
456590075Sobrien
456690075Sobrien    case COMPARE:
456790075Sobrien      return 1;
456890075Sobrien
456990075Sobrien    case ABS:
457090075Sobrien      return 4 + (mode == DImode ? 4 : 0);
457190075Sobrien
457290075Sobrien    case SIGN_EXTEND:
457390075Sobrien      if (GET_MODE (XEXP (x, 0)) == QImode)
457490075Sobrien	return (4 + (mode == DImode ? 4 : 0)
457590075Sobrien		+ (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
457690075Sobrien      /* Fall through */
457790075Sobrien    case ZERO_EXTEND:
457890075Sobrien      switch (GET_MODE (XEXP (x, 0)))
457990075Sobrien	{
458090075Sobrien	case QImode:
458190075Sobrien	  return (1 + (mode == DImode ? 4 : 0)
458290075Sobrien		  + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
458390075Sobrien
458490075Sobrien	case HImode:
458590075Sobrien	  return (4 + (mode == DImode ? 4 : 0)
458690075Sobrien		  + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
458790075Sobrien
458890075Sobrien	case SImode:
458990075Sobrien	  return (1 + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
459090075Sobrien
4591132718Skan	case V8QImode:
4592132718Skan	case V4HImode:
4593132718Skan	case V2SImode:
4594132718Skan	case V4QImode:
4595132718Skan	case V2HImode:
4596132718Skan	    return 1;
4597132718Skan
459890075Sobrien	default:
4599169689Skan	  gcc_unreachable ();
460090075Sobrien	}
4601169689Skan      gcc_unreachable ();
460290075Sobrien
4603169689Skan    case CONST_INT:
4604169689Skan      if (const_ok_for_arm (INTVAL (x)))
4605169689Skan	return outer == SET ? 2 : -1;
4606169689Skan      else if (outer == AND
4607169689Skan	       && const_ok_for_arm (~INTVAL (x)))
4608169689Skan	return -1;
4609169689Skan      else if ((outer == COMPARE
4610169689Skan		|| outer == PLUS || outer == MINUS)
4611169689Skan	       && const_ok_for_arm (-INTVAL (x)))
4612169689Skan	return -1;
4613169689Skan      else
461490075Sobrien	return 5;
4615169689Skan
4616169689Skan    case CONST:
4617169689Skan    case LABEL_REF:
4618169689Skan    case SYMBOL_REF:
461990075Sobrien      return 6;
4620169689Skan
4621169689Skan    case CONST_DOUBLE:
4622169689Skan      if (arm_const_double_rtx (x))
4623169689Skan	return outer == SET ? 2 : -1;
4624169689Skan      else if ((outer == COMPARE || outer == PLUS)
4625169689Skan	       && neg_const_double_rtx_ok_for_fpa (x))
4626169689Skan	return -1;
462790075Sobrien      return 7;
4628169689Skan
462990075Sobrien    default:
463090075Sobrien      return 99;
463190075Sobrien    }
463290075Sobrien}
463390075Sobrien
4634169689Skan/* RTX costs when optimizing for size.  */
4635132718Skanstatic bool
4636169689Skanarm_size_rtx_costs (rtx x, int code, int outer_code, int *total)
4637132718Skan{
4638169689Skan  enum machine_mode mode = GET_MODE (x);
4639169689Skan
4640169689Skan  if (TARGET_THUMB)
4641169689Skan    {
4642169689Skan      /* XXX TBD.  For now, use the standard costs.  */
4643169689Skan      *total = thumb_rtx_costs (x, code, outer_code);
4644169689Skan      return true;
4645169689Skan    }
4646169689Skan
4647169689Skan  switch (code)
4648169689Skan    {
4649169689Skan    case MEM:
4650169689Skan      /* A memory access costs 1 insn if the mode is small, or the address is
4651169689Skan	 a single register, otherwise it costs one insn per word.  */
4652169689Skan      if (REG_P (XEXP (x, 0)))
4653169689Skan	*total = COSTS_N_INSNS (1);
4654169689Skan      else
4655169689Skan	*total = COSTS_N_INSNS (ARM_NUM_REGS (mode));
4656169689Skan      return true;
4657169689Skan
4658169689Skan    case DIV:
4659169689Skan    case MOD:
4660169689Skan    case UDIV:
4661169689Skan    case UMOD:
4662169689Skan      /* Needs a libcall, so it costs about this.  */
4663169689Skan      *total = COSTS_N_INSNS (2);
4664169689Skan      return false;
4665169689Skan
4666169689Skan    case ROTATE:
4667169689Skan      if (mode == SImode && GET_CODE (XEXP (x, 1)) == REG)
4668169689Skan	{
4669169689Skan	  *total = COSTS_N_INSNS (2) + rtx_cost (XEXP (x, 0), code);
4670169689Skan	  return true;
4671169689Skan	}
4672169689Skan      /* Fall through */
4673169689Skan    case ROTATERT:
4674169689Skan    case ASHIFT:
4675169689Skan    case LSHIFTRT:
4676169689Skan    case ASHIFTRT:
4677169689Skan      if (mode == DImode && GET_CODE (XEXP (x, 1)) == CONST_INT)
4678169689Skan	{
4679169689Skan	  *total = COSTS_N_INSNS (3) + rtx_cost (XEXP (x, 0), code);
4680169689Skan	  return true;
4681169689Skan	}
4682169689Skan      else if (mode == SImode)
4683169689Skan	{
4684169689Skan	  *total = COSTS_N_INSNS (1) + rtx_cost (XEXP (x, 0), code);
4685169689Skan	  /* Slightly disparage register shifts, but not by much.  */
4686169689Skan	  if (GET_CODE (XEXP (x, 1)) != CONST_INT)
4687169689Skan	    *total += 1 + rtx_cost (XEXP (x, 1), code);
4688169689Skan	  return true;
4689169689Skan	}
4690169689Skan
4691169689Skan      /* Needs a libcall.  */
4692169689Skan      *total = COSTS_N_INSNS (2);
4693169689Skan      return false;
4694169689Skan
4695169689Skan    case MINUS:
4696169689Skan      if (TARGET_HARD_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT)
4697169689Skan	{
4698169689Skan	  *total = COSTS_N_INSNS (1);
4699169689Skan	  return false;
4700169689Skan	}
4701169689Skan
4702169689Skan      if (mode == SImode)
4703169689Skan	{
4704169689Skan	  enum rtx_code subcode0 = GET_CODE (XEXP (x, 0));
4705169689Skan	  enum rtx_code subcode1 = GET_CODE (XEXP (x, 1));
4706169689Skan
4707169689Skan	  if (subcode0 == ROTATE || subcode0 == ROTATERT || subcode0 == ASHIFT
4708169689Skan	      || subcode0 == LSHIFTRT || subcode0 == ASHIFTRT
4709169689Skan	      || subcode1 == ROTATE || subcode1 == ROTATERT
4710169689Skan	      || subcode1 == ASHIFT || subcode1 == LSHIFTRT
4711169689Skan	      || subcode1 == ASHIFTRT)
4712169689Skan	    {
4713169689Skan	      /* It's just the cost of the two operands.  */
4714169689Skan	      *total = 0;
4715169689Skan	      return false;
4716169689Skan	    }
4717169689Skan
4718169689Skan	  *total = COSTS_N_INSNS (1);
4719169689Skan	  return false;
4720169689Skan	}
4721169689Skan
4722169689Skan      *total = COSTS_N_INSNS (ARM_NUM_REGS (mode));
4723169689Skan      return false;
4724169689Skan
4725169689Skan    case PLUS:
4726169689Skan      if (TARGET_HARD_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT)
4727169689Skan	{
4728169689Skan	  *total = COSTS_N_INSNS (1);
4729169689Skan	  return false;
4730169689Skan	}
4731169689Skan
4732169689Skan      /* Fall through */
4733169689Skan    case AND: case XOR: case IOR:
4734169689Skan      if (mode == SImode)
4735169689Skan	{
4736169689Skan	  enum rtx_code subcode = GET_CODE (XEXP (x, 0));
4737169689Skan
4738169689Skan	  if (subcode == ROTATE || subcode == ROTATERT || subcode == ASHIFT
4739169689Skan	      || subcode == LSHIFTRT || subcode == ASHIFTRT
4740169689Skan	      || (code == AND && subcode == NOT))
4741169689Skan	    {
4742169689Skan	      /* It's just the cost of the two operands.  */
4743169689Skan	      *total = 0;
4744169689Skan	      return false;
4745169689Skan	    }
4746169689Skan	}
4747169689Skan
4748169689Skan      *total = COSTS_N_INSNS (ARM_NUM_REGS (mode));
4749169689Skan      return false;
4750169689Skan
4751169689Skan    case MULT:
4752169689Skan      *total = COSTS_N_INSNS (ARM_NUM_REGS (mode));
4753169689Skan      return false;
4754169689Skan
4755169689Skan    case NEG:
4756169689Skan      if (TARGET_HARD_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT)
4757169689Skan	*total = COSTS_N_INSNS (1);
4758169689Skan      /* Fall through */
4759169689Skan    case NOT:
4760169689Skan      *total = COSTS_N_INSNS (ARM_NUM_REGS (mode));
4761169689Skan
4762169689Skan      return false;
4763169689Skan
4764169689Skan    case IF_THEN_ELSE:
4765169689Skan      *total = 0;
4766169689Skan      return false;
4767169689Skan
4768169689Skan    case COMPARE:
4769169689Skan      if (cc_register (XEXP (x, 0), VOIDmode))
4770169689Skan	* total = 0;
4771169689Skan      else
4772169689Skan	*total = COSTS_N_INSNS (1);
4773169689Skan      return false;
4774169689Skan
4775169689Skan    case ABS:
4776169689Skan      if (TARGET_HARD_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT)
4777169689Skan	*total = COSTS_N_INSNS (1);
4778169689Skan      else
4779169689Skan	*total = COSTS_N_INSNS (1 + ARM_NUM_REGS (mode));
4780169689Skan      return false;
4781169689Skan
4782169689Skan    case SIGN_EXTEND:
4783169689Skan      *total = 0;
4784169689Skan      if (GET_MODE_SIZE (GET_MODE (XEXP (x, 0))) < 4)
4785169689Skan	{
4786169689Skan	  if (!(arm_arch4 && MEM_P (XEXP (x, 0))))
4787169689Skan	    *total += COSTS_N_INSNS (arm_arch6 ? 1 : 2);
4788169689Skan	}
4789169689Skan      if (mode == DImode)
4790169689Skan	*total += COSTS_N_INSNS (1);
4791169689Skan      return false;
4792169689Skan
4793169689Skan    case ZERO_EXTEND:
4794169689Skan      *total = 0;
4795169689Skan      if (!(arm_arch4 && MEM_P (XEXP (x, 0))))
4796169689Skan	{
4797169689Skan	  switch (GET_MODE (XEXP (x, 0)))
4798169689Skan	    {
4799169689Skan	    case QImode:
4800169689Skan	      *total += COSTS_N_INSNS (1);
4801169689Skan	      break;
4802169689Skan
4803169689Skan	    case HImode:
4804169689Skan	      *total += COSTS_N_INSNS (arm_arch6 ? 1 : 2);
4805169689Skan
4806169689Skan	    case SImode:
4807169689Skan	      break;
4808169689Skan
4809169689Skan	    default:
4810169689Skan	      *total += COSTS_N_INSNS (2);
4811169689Skan	    }
4812169689Skan	}
4813169689Skan
4814169689Skan      if (mode == DImode)
4815169689Skan	*total += COSTS_N_INSNS (1);
4816169689Skan
4817169689Skan      return false;
4818169689Skan
4819169689Skan    case CONST_INT:
4820169689Skan      if (const_ok_for_arm (INTVAL (x)))
4821169689Skan	*total = COSTS_N_INSNS (outer_code == SET ? 1 : 0);
4822169689Skan      else if (const_ok_for_arm (~INTVAL (x)))
4823169689Skan	*total = COSTS_N_INSNS (outer_code == AND ? 0 : 1);
4824169689Skan      else if (const_ok_for_arm (-INTVAL (x)))
4825169689Skan	{
4826169689Skan	  if (outer_code == COMPARE || outer_code == PLUS
4827169689Skan	      || outer_code == MINUS)
4828169689Skan	    *total = 0;
4829169689Skan	  else
4830169689Skan	    *total = COSTS_N_INSNS (1);
4831169689Skan	}
4832169689Skan      else
4833169689Skan	*total = COSTS_N_INSNS (2);
4834169689Skan      return true;
4835169689Skan
4836169689Skan    case CONST:
4837169689Skan    case LABEL_REF:
4838169689Skan    case SYMBOL_REF:
4839169689Skan      *total = COSTS_N_INSNS (2);
4840169689Skan      return true;
4841169689Skan
4842169689Skan    case CONST_DOUBLE:
4843169689Skan      *total = COSTS_N_INSNS (4);
4844169689Skan      return true;
4845169689Skan
4846169689Skan    default:
4847169689Skan      if (mode != VOIDmode)
4848169689Skan	*total = COSTS_N_INSNS (ARM_NUM_REGS (mode));
4849169689Skan      else
4850169689Skan	*total = COSTS_N_INSNS (4); /* How knows?  */
4851169689Skan      return false;
4852169689Skan    }
4853132718Skan}
4854132718Skan
4855169689Skan/* RTX costs for cores with a slow MUL implementation.  */
4856169689Skan
4857169689Skanstatic bool
4858169689Skanarm_slowmul_rtx_costs (rtx x, int code, int outer_code, int *total)
4859169689Skan{
4860169689Skan  enum machine_mode mode = GET_MODE (x);
4861169689Skan
4862169689Skan  if (TARGET_THUMB)
4863169689Skan    {
4864169689Skan      *total = thumb_rtx_costs (x, code, outer_code);
4865169689Skan      return true;
4866169689Skan    }
4867169689Skan
4868169689Skan  switch (code)
4869169689Skan    {
4870169689Skan    case MULT:
4871169689Skan      if (GET_MODE_CLASS (mode) == MODE_FLOAT
4872169689Skan	  || mode == DImode)
4873169689Skan	{
4874169689Skan	  *total = 30;
4875169689Skan	  return true;
4876169689Skan	}
4877169689Skan
4878169689Skan      if (GET_CODE (XEXP (x, 1)) == CONST_INT)
4879169689Skan	{
4880169689Skan	  unsigned HOST_WIDE_INT i = (INTVAL (XEXP (x, 1))
4881169689Skan				      & (unsigned HOST_WIDE_INT) 0xffffffff);
4882169689Skan	  int cost, const_ok = const_ok_for_arm (i);
4883169689Skan	  int j, booth_unit_size;
4884169689Skan
4885169689Skan	  /* Tune as appropriate.  */
4886169689Skan	  cost = const_ok ? 4 : 8;
4887169689Skan	  booth_unit_size = 2;
4888169689Skan	  for (j = 0; i && j < 32; j += booth_unit_size)
4889169689Skan	    {
4890169689Skan	      i >>= booth_unit_size;
4891169689Skan	      cost += 2;
4892169689Skan	    }
4893169689Skan
4894169689Skan	  *total = cost;
4895169689Skan	  return true;
4896169689Skan	}
4897169689Skan
4898169689Skan      *total = 30 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4)
4899169689Skan	          + (REG_OR_SUBREG_REG (XEXP (x, 1)) ? 0 : 4);
4900169689Skan      return true;
4901169689Skan
4902169689Skan    default:
4903169689Skan      *total = arm_rtx_costs_1 (x, code, outer_code);
4904169689Skan      return true;
4905169689Skan    }
4906169689Skan}
4907169689Skan
4908169689Skan
4909169689Skan/* RTX cost for cores with a fast multiply unit (M variants).  */
4910169689Skan
4911169689Skanstatic bool
4912169689Skanarm_fastmul_rtx_costs (rtx x, int code, int outer_code, int *total)
4913169689Skan{
4914169689Skan  enum machine_mode mode = GET_MODE (x);
4915169689Skan
4916169689Skan  if (TARGET_THUMB)
4917169689Skan    {
4918169689Skan      *total = thumb_rtx_costs (x, code, outer_code);
4919169689Skan      return true;
4920169689Skan    }
4921169689Skan
4922169689Skan  switch (code)
4923169689Skan    {
4924169689Skan    case MULT:
4925169689Skan      /* There is no point basing this on the tuning, since it is always the
4926169689Skan	 fast variant if it exists at all.  */
4927169689Skan      if (mode == DImode
4928169689Skan	  && (GET_CODE (XEXP (x, 0)) == GET_CODE (XEXP (x, 1)))
4929169689Skan	  && (GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
4930169689Skan	      || GET_CODE (XEXP (x, 0)) == SIGN_EXTEND))
4931169689Skan	{
4932169689Skan	  *total = 8;
4933169689Skan	  return true;
4934169689Skan	}
4935169689Skan
4936169689Skan
4937169689Skan      if (GET_MODE_CLASS (mode) == MODE_FLOAT
4938169689Skan	  || mode == DImode)
4939169689Skan	{
4940169689Skan	  *total = 30;
4941169689Skan	  return true;
4942169689Skan	}
4943169689Skan
4944169689Skan      if (GET_CODE (XEXP (x, 1)) == CONST_INT)
4945169689Skan	{
4946169689Skan	  unsigned HOST_WIDE_INT i = (INTVAL (XEXP (x, 1))
4947169689Skan				      & (unsigned HOST_WIDE_INT) 0xffffffff);
4948169689Skan	  int cost, const_ok = const_ok_for_arm (i);
4949169689Skan	  int j, booth_unit_size;
4950169689Skan
4951169689Skan	  /* Tune as appropriate.  */
4952169689Skan	  cost = const_ok ? 4 : 8;
4953169689Skan	  booth_unit_size = 8;
4954169689Skan	  for (j = 0; i && j < 32; j += booth_unit_size)
4955169689Skan	    {
4956169689Skan	      i >>= booth_unit_size;
4957169689Skan	      cost += 2;
4958169689Skan	    }
4959169689Skan
4960169689Skan	  *total = cost;
4961169689Skan	  return true;
4962169689Skan	}
4963169689Skan
4964169689Skan      *total = 8 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4)
4965169689Skan	         + (REG_OR_SUBREG_REG (XEXP (x, 1)) ? 0 : 4);
4966169689Skan      return true;
4967169689Skan
4968169689Skan    default:
4969169689Skan      *total = arm_rtx_costs_1 (x, code, outer_code);
4970169689Skan      return true;
4971169689Skan    }
4972169689Skan}
4973169689Skan
4974169689Skan
4975169689Skan/* RTX cost for XScale CPUs.  */
4976169689Skan
4977169689Skanstatic bool
4978169689Skanarm_xscale_rtx_costs (rtx x, int code, int outer_code, int *total)
4979169689Skan{
4980169689Skan  enum machine_mode mode = GET_MODE (x);
4981169689Skan
4982169689Skan  if (TARGET_THUMB)
4983169689Skan    {
4984169689Skan      *total = thumb_rtx_costs (x, code, outer_code);
4985169689Skan      return true;
4986169689Skan    }
4987169689Skan
4988169689Skan  switch (code)
4989169689Skan    {
4990169689Skan    case MULT:
4991169689Skan      /* There is no point basing this on the tuning, since it is always the
4992169689Skan	 fast variant if it exists at all.  */
4993169689Skan      if (mode == DImode
4994169689Skan	  && (GET_CODE (XEXP (x, 0)) == GET_CODE (XEXP (x, 1)))
4995169689Skan	  && (GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
4996169689Skan	      || GET_CODE (XEXP (x, 0)) == SIGN_EXTEND))
4997169689Skan	{
4998169689Skan	  *total = 8;
4999169689Skan	  return true;
5000169689Skan	}
5001169689Skan
5002169689Skan
5003169689Skan      if (GET_MODE_CLASS (mode) == MODE_FLOAT
5004169689Skan	  || mode == DImode)
5005169689Skan	{
5006169689Skan	  *total = 30;
5007169689Skan	  return true;
5008169689Skan	}
5009169689Skan
5010169689Skan      if (GET_CODE (XEXP (x, 1)) == CONST_INT)
5011169689Skan	{
5012169689Skan	  unsigned HOST_WIDE_INT i = (INTVAL (XEXP (x, 1))
5013169689Skan				      & (unsigned HOST_WIDE_INT) 0xffffffff);
5014169689Skan	  int cost, const_ok = const_ok_for_arm (i);
5015169689Skan	  unsigned HOST_WIDE_INT masked_const;
5016169689Skan
5017169689Skan	  /* The cost will be related to two insns.
5018169689Skan	     First a load of the constant (MOV or LDR), then a multiply.  */
5019169689Skan	  cost = 2;
5020169689Skan	  if (! const_ok)
5021169689Skan	    cost += 1;      /* LDR is probably more expensive because
5022169689Skan			       of longer result latency.  */
5023169689Skan	  masked_const = i & 0xffff8000;
5024169689Skan	  if (masked_const != 0 && masked_const != 0xffff8000)
5025169689Skan	    {
5026169689Skan	      masked_const = i & 0xf8000000;
5027169689Skan	      if (masked_const == 0 || masked_const == 0xf8000000)
5028169689Skan		cost += 1;
5029169689Skan	      else
5030169689Skan		cost += 2;
5031169689Skan	    }
5032169689Skan	  *total = cost;
5033169689Skan	  return true;
5034169689Skan	}
5035169689Skan
5036169689Skan      *total = 8 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4)
5037169689Skan		 + (REG_OR_SUBREG_REG (XEXP (x, 1)) ? 0 : 4);
5038169689Skan      return true;
5039169689Skan
5040169689Skan    case COMPARE:
5041169689Skan      /* A COMPARE of a MULT is slow on XScale; the muls instruction
5042169689Skan	 will stall until the multiplication is complete.  */
5043169689Skan      if (GET_CODE (XEXP (x, 0)) == MULT)
5044169689Skan	*total = 4 + rtx_cost (XEXP (x, 0), code);
5045169689Skan      else
5046169689Skan	*total = arm_rtx_costs_1 (x, code, outer_code);
5047169689Skan      return true;
5048169689Skan
5049169689Skan    default:
5050169689Skan      *total = arm_rtx_costs_1 (x, code, outer_code);
5051169689Skan      return true;
5052169689Skan    }
5053169689Skan}
5054169689Skan
5055169689Skan
5056169689Skan/* RTX costs for 9e (and later) cores.  */
5057169689Skan
5058169689Skanstatic bool
5059169689Skanarm_9e_rtx_costs (rtx x, int code, int outer_code, int *total)
5060169689Skan{
5061169689Skan  enum machine_mode mode = GET_MODE (x);
5062169689Skan  int nonreg_cost;
5063169689Skan  int cost;
5064169689Skan
5065169689Skan  if (TARGET_THUMB)
5066169689Skan    {
5067169689Skan      switch (code)
5068169689Skan	{
5069169689Skan	case MULT:
5070169689Skan	  *total = COSTS_N_INSNS (3);
5071169689Skan	  return true;
5072169689Skan
5073169689Skan	default:
5074169689Skan	  *total = thumb_rtx_costs (x, code, outer_code);
5075169689Skan	  return true;
5076169689Skan	}
5077169689Skan    }
5078169689Skan
5079169689Skan  switch (code)
5080169689Skan    {
5081169689Skan    case MULT:
5082169689Skan      /* There is no point basing this on the tuning, since it is always the
5083169689Skan	 fast variant if it exists at all.  */
5084169689Skan      if (mode == DImode
5085169689Skan	  && (GET_CODE (XEXP (x, 0)) == GET_CODE (XEXP (x, 1)))
5086169689Skan	  && (GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
5087169689Skan	      || GET_CODE (XEXP (x, 0)) == SIGN_EXTEND))
5088169689Skan	{
5089169689Skan	  *total = 3;
5090169689Skan	  return true;
5091169689Skan	}
5092169689Skan
5093169689Skan
5094169689Skan      if (GET_MODE_CLASS (mode) == MODE_FLOAT)
5095169689Skan	{
5096169689Skan	  *total = 30;
5097169689Skan	  return true;
5098169689Skan	}
5099169689Skan      if (mode == DImode)
5100169689Skan	{
5101169689Skan	  cost = 7;
5102169689Skan	  nonreg_cost = 8;
5103169689Skan	}
5104169689Skan      else
5105169689Skan	{
5106169689Skan	  cost = 2;
5107169689Skan	  nonreg_cost = 4;
5108169689Skan	}
5109169689Skan
5110169689Skan
5111169689Skan      *total = cost + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : nonreg_cost)
5112169689Skan		    + (REG_OR_SUBREG_REG (XEXP (x, 1)) ? 0 : nonreg_cost);
5113169689Skan      return true;
5114169689Skan
5115169689Skan    default:
5116169689Skan      *total = arm_rtx_costs_1 (x, code, outer_code);
5117169689Skan      return true;
5118169689Skan    }
5119169689Skan}
5120132718Skan/* All address computations that can be done are free, but rtx cost returns
5121132718Skan   the same for practically all of them.  So we weight the different types
5122132718Skan   of address here in the order (most pref first):
5123132718Skan   PRE/POST_INC/DEC, SHIFT or NON-INT sum, INT sum, REG, MEM or LABEL.  */
5124132718Skanstatic inline int
5125132718Skanarm_arm_address_cost (rtx x)
5126132718Skan{
5127132718Skan  enum rtx_code c  = GET_CODE (x);
5128132718Skan
5129132718Skan  if (c == PRE_INC || c == PRE_DEC || c == POST_INC || c == POST_DEC)
5130132718Skan    return 0;
5131132718Skan  if (c == MEM || c == LABEL_REF || c == SYMBOL_REF)
5132132718Skan    return 10;
5133132718Skan
5134132718Skan  if (c == PLUS || c == MINUS)
5135132718Skan    {
5136132718Skan      if (GET_CODE (XEXP (x, 0)) == CONST_INT)
5137132718Skan	return 2;
5138132718Skan
5139169689Skan      if (ARITHMETIC_P (XEXP (x, 0)) || ARITHMETIC_P (XEXP (x, 1)))
5140132718Skan	return 3;
5141132718Skan
5142132718Skan      return 4;
5143132718Skan    }
5144132718Skan
5145132718Skan  return 6;
5146132718Skan}
5147132718Skan
5148132718Skanstatic inline int
5149132718Skanarm_thumb_address_cost (rtx x)
5150132718Skan{
5151132718Skan  enum rtx_code c  = GET_CODE (x);
5152132718Skan
5153132718Skan  if (c == REG)
5154132718Skan    return 1;
5155132718Skan  if (c == PLUS
5156132718Skan      && GET_CODE (XEXP (x, 0)) == REG
5157132718Skan      && GET_CODE (XEXP (x, 1)) == CONST_INT)
5158132718Skan    return 1;
5159132718Skan
5160132718Skan  return 2;
5161132718Skan}
5162132718Skan
516390075Sobrienstatic int
5164132718Skanarm_address_cost (rtx x)
516590075Sobrien{
5166132718Skan  return TARGET_ARM ? arm_arm_address_cost (x) : arm_thumb_address_cost (x);
5167132718Skan}
5168132718Skan
5169132718Skanstatic int
5170132718Skanarm_adjust_cost (rtx insn, rtx link, rtx dep, int cost)
5171132718Skan{
517290075Sobrien  rtx i_pat, d_pat;
517390075Sobrien
517490075Sobrien  /* Some true dependencies can have a higher cost depending
517590075Sobrien     on precisely how certain input operands are used.  */
5176132718Skan  if (arm_tune_xscale
517790075Sobrien      && REG_NOTE_KIND (link) == 0
5178132718Skan      && recog_memoized (insn) >= 0
5179132718Skan      && recog_memoized (dep) >= 0)
518090075Sobrien    {
518190075Sobrien      int shift_opnum = get_attr_shift (insn);
518290075Sobrien      enum attr_type attr_type = get_attr_type (dep);
518390075Sobrien
518490075Sobrien      /* If nonzero, SHIFT_OPNUM contains the operand number of a shifted
518590075Sobrien	 operand for INSN.  If we have a shifted input operand and the
518690075Sobrien	 instruction we depend on is another ALU instruction, then we may
518790075Sobrien	 have to account for an additional stall.  */
5188169689Skan      if (shift_opnum != 0
5189169689Skan	  && (attr_type == TYPE_ALU_SHIFT || attr_type == TYPE_ALU_SHIFT_REG))
519090075Sobrien	{
519190075Sobrien	  rtx shifted_operand;
519290075Sobrien	  int opno;
5193169689Skan
519490075Sobrien	  /* Get the shifted operand.  */
519590075Sobrien	  extract_insn (insn);
519690075Sobrien	  shifted_operand = recog_data.operand[shift_opnum];
519790075Sobrien
519890075Sobrien	  /* Iterate over all the operands in DEP.  If we write an operand
519990075Sobrien	     that overlaps with SHIFTED_OPERAND, then we have increase the
520090075Sobrien	     cost of this dependency.  */
520190075Sobrien	  extract_insn (dep);
520290075Sobrien	  preprocess_constraints ();
520390075Sobrien	  for (opno = 0; opno < recog_data.n_operands; opno++)
520490075Sobrien	    {
520590075Sobrien	      /* We can ignore strict inputs.  */
520690075Sobrien	      if (recog_data.operand_type[opno] == OP_IN)
520790075Sobrien		continue;
520890075Sobrien
520990075Sobrien	      if (reg_overlap_mentioned_p (recog_data.operand[opno],
521090075Sobrien					   shifted_operand))
521190075Sobrien		return 2;
521290075Sobrien	    }
521390075Sobrien	}
521490075Sobrien    }
521590075Sobrien
521690075Sobrien  /* XXX This is not strictly true for the FPA.  */
521790075Sobrien  if (REG_NOTE_KIND (link) == REG_DEP_ANTI
521890075Sobrien      || REG_NOTE_KIND (link) == REG_DEP_OUTPUT)
521990075Sobrien    return 0;
522090075Sobrien
522190075Sobrien  /* Call insns don't incur a stall, even if they follow a load.  */
522290075Sobrien  if (REG_NOTE_KIND (link) == 0
522390075Sobrien      && GET_CODE (insn) == CALL_INSN)
522490075Sobrien    return 1;
522590075Sobrien
522690075Sobrien  if ((i_pat = single_set (insn)) != NULL
522790075Sobrien      && GET_CODE (SET_SRC (i_pat)) == MEM
522890075Sobrien      && (d_pat = single_set (dep)) != NULL
522990075Sobrien      && GET_CODE (SET_DEST (d_pat)) == MEM)
523090075Sobrien    {
5231117395Skan      rtx src_mem = XEXP (SET_SRC (i_pat), 0);
523290075Sobrien      /* This is a load after a store, there is no conflict if the load reads
523390075Sobrien	 from a cached area.  Assume that loads from the stack, and from the
5234169689Skan	 constant pool are cached, and that others will miss.  This is a
523590075Sobrien	 hack.  */
5236169689Skan
5237117395Skan      if ((GET_CODE (src_mem) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (src_mem))
5238117395Skan	  || reg_mentioned_p (stack_pointer_rtx, src_mem)
5239117395Skan	  || reg_mentioned_p (frame_pointer_rtx, src_mem)
5240117395Skan	  || reg_mentioned_p (hard_frame_pointer_rtx, src_mem))
524190075Sobrien	return 1;
524290075Sobrien    }
524390075Sobrien
524490075Sobrien  return cost;
524590075Sobrien}
524690075Sobrien
5247169689Skanstatic int fp_consts_inited = 0;
524890075Sobrien
5249169689Skan/* Only zero is valid for VFP.  Other values are also valid for FPA.  */
5250169689Skanstatic const char * const strings_fp[8] =
525190075Sobrien{
525290075Sobrien  "0",   "1",   "2",   "3",
525390075Sobrien  "4",   "5",   "0.5", "10"
525490075Sobrien};
525590075Sobrien
5256169689Skanstatic REAL_VALUE_TYPE values_fp[8];
525790075Sobrien
525890075Sobrienstatic void
5259169689Skaninit_fp_table (void)
526090075Sobrien{
526190075Sobrien  int i;
526290075Sobrien  REAL_VALUE_TYPE r;
526390075Sobrien
5264169689Skan  if (TARGET_VFP)
5265169689Skan    fp_consts_inited = 1;
5266169689Skan  else
5267169689Skan    fp_consts_inited = 8;
5268169689Skan
5269169689Skan  for (i = 0; i < fp_consts_inited; i++)
527090075Sobrien    {
5271169689Skan      r = REAL_VALUE_ATOF (strings_fp[i], DFmode);
5272169689Skan      values_fp[i] = r;
527390075Sobrien    }
527490075Sobrien}
527590075Sobrien
5276169689Skan/* Return TRUE if rtx X is a valid immediate FP constant.  */
527790075Sobrienint
5278169689Skanarm_const_double_rtx (rtx x)
527990075Sobrien{
528090075Sobrien  REAL_VALUE_TYPE r;
528190075Sobrien  int i;
5282169689Skan
5283169689Skan  if (!fp_consts_inited)
5284169689Skan    init_fp_table ();
5285169689Skan
528690075Sobrien  REAL_VALUE_FROM_CONST_DOUBLE (r, x);
528790075Sobrien  if (REAL_VALUE_MINUS_ZERO (r))
528890075Sobrien    return 0;
528990075Sobrien
5290169689Skan  for (i = 0; i < fp_consts_inited; i++)
5291169689Skan    if (REAL_VALUES_EQUAL (r, values_fp[i]))
529290075Sobrien      return 1;
529390075Sobrien
529490075Sobrien  return 0;
529590075Sobrien}
529690075Sobrien
5297132718Skan/* Return TRUE if rtx X is a valid immediate FPA constant.  */
529890075Sobrienint
5299132718Skanneg_const_double_rtx_ok_for_fpa (rtx x)
530090075Sobrien{
530190075Sobrien  REAL_VALUE_TYPE r;
530290075Sobrien  int i;
5303169689Skan
5304169689Skan  if (!fp_consts_inited)
5305169689Skan    init_fp_table ();
5306169689Skan
530790075Sobrien  REAL_VALUE_FROM_CONST_DOUBLE (r, x);
530890075Sobrien  r = REAL_VALUE_NEGATE (r);
530990075Sobrien  if (REAL_VALUE_MINUS_ZERO (r))
531090075Sobrien    return 0;
531190075Sobrien
531290075Sobrien  for (i = 0; i < 8; i++)
5313169689Skan    if (REAL_VALUES_EQUAL (r, values_fp[i]))
531490075Sobrien      return 1;
531590075Sobrien
531690075Sobrien  return 0;
531790075Sobrien}
531890075Sobrien
531990075Sobrien/* Predicates for `match_operand' and `match_operator'.  */
532090075Sobrien
5321132718Skan/* Return nonzero if OP is a valid Cirrus memory address pattern.  */
5322132718Skanint
5323132718Skancirrus_memory_offset (rtx op)
5324132718Skan{
5325132718Skan  /* Reject eliminable registers.  */
5326132718Skan  if (! (reload_in_progress || reload_completed)
5327132718Skan      && (   reg_mentioned_p (frame_pointer_rtx, op)
5328132718Skan	  || reg_mentioned_p (arg_pointer_rtx, op)
5329132718Skan	  || reg_mentioned_p (virtual_incoming_args_rtx, op)
5330132718Skan	  || reg_mentioned_p (virtual_outgoing_args_rtx, op)
5331132718Skan	  || reg_mentioned_p (virtual_stack_dynamic_rtx, op)
5332132718Skan	  || reg_mentioned_p (virtual_stack_vars_rtx, op)))
5333132718Skan    return 0;
533490075Sobrien
5335132718Skan  if (GET_CODE (op) == MEM)
5336132718Skan    {
5337132718Skan      rtx ind;
5338132718Skan
5339132718Skan      ind = XEXP (op, 0);
5340132718Skan
5341132718Skan      /* Match: (mem (reg)).  */
5342132718Skan      if (GET_CODE (ind) == REG)
5343132718Skan	return 1;
5344132718Skan
5345132718Skan      /* Match:
5346132718Skan	 (mem (plus (reg)
5347132718Skan	            (const))).  */
5348132718Skan      if (GET_CODE (ind) == PLUS
5349132718Skan	  && GET_CODE (XEXP (ind, 0)) == REG
5350132718Skan	  && REG_MODE_OK_FOR_BASE_P (XEXP (ind, 0), VOIDmode)
5351132718Skan	  && GET_CODE (XEXP (ind, 1)) == CONST_INT)
5352132718Skan	return 1;
5353132718Skan    }
5354132718Skan
5355132718Skan  return 0;
5356132718Skan}
5357132718Skan
5358169689Skan/* Return TRUE if OP is a valid coprocessor memory address pattern.
5359169689Skan   WB if true if writeback address modes are allowed.  */
5360169689Skan
536190075Sobrienint
5362169689Skanarm_coproc_mem_operand (rtx op, bool wb)
536390075Sobrien{
5364169689Skan  rtx ind;
5365169689Skan
5366169689Skan  /* Reject eliminable registers.  */
5367169689Skan  if (! (reload_in_progress || reload_completed)
5368169689Skan      && (   reg_mentioned_p (frame_pointer_rtx, op)
5369169689Skan	  || reg_mentioned_p (arg_pointer_rtx, op)
5370169689Skan	  || reg_mentioned_p (virtual_incoming_args_rtx, op)
5371169689Skan	  || reg_mentioned_p (virtual_outgoing_args_rtx, op)
5372169689Skan	  || reg_mentioned_p (virtual_stack_dynamic_rtx, op)
5373169689Skan	  || reg_mentioned_p (virtual_stack_vars_rtx, op)))
5374132718Skan    return FALSE;
5375132718Skan
5376169689Skan  /* Constants are converted into offsets from labels.  */
5377169689Skan  if (GET_CODE (op) != MEM)
5378169689Skan    return FALSE;
5379132718Skan
5380169689Skan  ind = XEXP (op, 0);
5381132718Skan
5382169689Skan  if (reload_completed
5383169689Skan      && (GET_CODE (ind) == LABEL_REF
5384169689Skan	  || (GET_CODE (ind) == CONST
5385169689Skan	      && GET_CODE (XEXP (ind, 0)) == PLUS
5386169689Skan	      && GET_CODE (XEXP (XEXP (ind, 0), 0)) == LABEL_REF
5387169689Skan	      && GET_CODE (XEXP (XEXP (ind, 0), 1)) == CONST_INT)))
5388169689Skan    return TRUE;
5389132718Skan
5390169689Skan  /* Match: (mem (reg)).  */
5391169689Skan  if (GET_CODE (ind) == REG)
5392169689Skan    return arm_address_register_rtx_p (ind, 0);
5393132718Skan
5394169689Skan  /* Autoincremment addressing modes.  */
5395169689Skan  if (wb
5396169689Skan      && (GET_CODE (ind) == PRE_INC
5397169689Skan	  || GET_CODE (ind) == POST_INC
5398169689Skan	  || GET_CODE (ind) == PRE_DEC
5399169689Skan	  || GET_CODE (ind) == POST_DEC))
5400169689Skan    return arm_address_register_rtx_p (XEXP (ind, 0), 0);
5401132718Skan
5402169689Skan  if (wb
5403169689Skan      && (GET_CODE (ind) == POST_MODIFY || GET_CODE (ind) == PRE_MODIFY)
5404169689Skan      && arm_address_register_rtx_p (XEXP (ind, 0), 0)
5405169689Skan      && GET_CODE (XEXP (ind, 1)) == PLUS
5406169689Skan      && rtx_equal_p (XEXP (XEXP (ind, 1), 0), XEXP (ind, 0)))
5407169689Skan    ind = XEXP (ind, 1);
5408169689Skan
5409169689Skan  /* Match:
5410169689Skan     (plus (reg)
5411169689Skan	   (const)).  */
5412169689Skan  if (GET_CODE (ind) == PLUS
5413169689Skan      && GET_CODE (XEXP (ind, 0)) == REG
5414169689Skan      && REG_MODE_OK_FOR_BASE_P (XEXP (ind, 0), VOIDmode)
5415169689Skan      && GET_CODE (XEXP (ind, 1)) == CONST_INT
5416169689Skan      && INTVAL (XEXP (ind, 1)) > -1024
5417169689Skan      && INTVAL (XEXP (ind, 1)) <  1024
5418169689Skan      && (INTVAL (XEXP (ind, 1)) & 3) == 0)
5419169689Skan    return TRUE;
5420169689Skan
5421169689Skan  return FALSE;
5422132718Skan}
5423132718Skan
5424146895Skan/* Return true if X is a register that will be eliminated later on.  */
5425146895Skanint
5426146895Skanarm_eliminable_register (rtx x)
5427146895Skan{
5428146895Skan  return REG_P (x) && (REGNO (x) == FRAME_POINTER_REGNUM
5429146895Skan		       || REGNO (x) == ARG_POINTER_REGNUM
5430146895Skan		       || (REGNO (x) >= FIRST_VIRTUAL_REGISTER
5431146895Skan			   && REGNO (x) <= LAST_VIRTUAL_REGISTER));
5432146895Skan}
5433146895Skan
5434169689Skan/* Return GENERAL_REGS if a scratch register required to reload x to/from
5435169689Skan   coprocessor registers.  Otherwise return NO_REGS.  */
5436169689Skan
5437169689Skanenum reg_class
5438169689Skancoproc_secondary_reload_class (enum machine_mode mode, rtx x, bool wb)
5439169689Skan{
5440169689Skan  if (arm_coproc_mem_operand (x, wb) || s_register_operand (x, mode))
5441169689Skan    return NO_REGS;
5442169689Skan
5443169689Skan  return GENERAL_REGS;
5444169689Skan}
5445169689Skan
5446169689Skan/* Values which must be returned in the most-significant end of the return
5447169689Skan   register.  */
5448169689Skan
5449169689Skanstatic bool
5450169689Skanarm_return_in_msb (tree valtype)
5451169689Skan{
5452169689Skan  return (TARGET_AAPCS_BASED
5453169689Skan          && BYTES_BIG_ENDIAN
5454169689Skan          && (AGGREGATE_TYPE_P (valtype)
5455169689Skan              || TREE_CODE (valtype) == COMPLEX_TYPE));
5456169689Skan}
5457169689Skan
5458132718Skan/* Returns TRUE if INSN is an "LDR REG, ADDR" instruction.
5459132718Skan   Use by the Cirrus Maverick code which has to workaround
5460132718Skan   a hardware bug triggered by such instructions.  */
5461132718Skanstatic bool
5462132718Skanarm_memory_load_p (rtx insn)
5463132718Skan{
5464132718Skan  rtx body, lhs, rhs;;
5465132718Skan
5466132718Skan  if (insn == NULL_RTX || GET_CODE (insn) != INSN)
5467132718Skan    return false;
5468132718Skan
5469132718Skan  body = PATTERN (insn);
5470132718Skan
5471132718Skan  if (GET_CODE (body) != SET)
5472132718Skan    return false;
5473132718Skan
5474132718Skan  lhs = XEXP (body, 0);
5475132718Skan  rhs = XEXP (body, 1);
5476132718Skan
5477132718Skan  lhs = REG_OR_SUBREG_RTX (lhs);
5478132718Skan
5479132718Skan  /* If the destination is not a general purpose
5480132718Skan     register we do not have to worry.  */
5481132718Skan  if (GET_CODE (lhs) != REG
5482132718Skan      || REGNO_REG_CLASS (REGNO (lhs)) != GENERAL_REGS)
5483132718Skan    return false;
5484132718Skan
5485132718Skan  /* As well as loads from memory we also have to react
5486132718Skan     to loads of invalid constants which will be turned
5487132718Skan     into loads from the minipool.  */
5488132718Skan  return (GET_CODE (rhs) == MEM
5489132718Skan	  || GET_CODE (rhs) == SYMBOL_REF
5490132718Skan	  || note_invalid_constants (insn, -1, false));
5491132718Skan}
5492132718Skan
5493132718Skan/* Return TRUE if INSN is a Cirrus instruction.  */
5494132718Skanstatic bool
5495132718Skanarm_cirrus_insn_p (rtx insn)
5496132718Skan{
5497132718Skan  enum attr_cirrus attr;
5498132718Skan
5499169689Skan  /* get_attr cannot accept USE or CLOBBER.  */
5500132718Skan  if (!insn
5501132718Skan      || GET_CODE (insn) != INSN
5502132718Skan      || GET_CODE (PATTERN (insn)) == USE
5503132718Skan      || GET_CODE (PATTERN (insn)) == CLOBBER)
5504132718Skan    return 0;
5505132718Skan
5506132718Skan  attr = get_attr_cirrus (insn);
5507132718Skan
5508132718Skan  return attr != CIRRUS_NOT;
5509132718Skan}
5510132718Skan
5511132718Skan/* Cirrus reorg for invalid instruction combinations.  */
5512132718Skanstatic void
5513132718Skancirrus_reorg (rtx first)
5514132718Skan{
5515132718Skan  enum attr_cirrus attr;
5516132718Skan  rtx body = PATTERN (first);
5517132718Skan  rtx t;
5518132718Skan  int nops;
5519132718Skan
5520132718Skan  /* Any branch must be followed by 2 non Cirrus instructions.  */
5521132718Skan  if (GET_CODE (first) == JUMP_INSN && GET_CODE (body) != RETURN)
5522132718Skan    {
5523132718Skan      nops = 0;
5524132718Skan      t = next_nonnote_insn (first);
5525132718Skan
5526132718Skan      if (arm_cirrus_insn_p (t))
5527132718Skan	++ nops;
5528132718Skan
5529132718Skan      if (arm_cirrus_insn_p (next_nonnote_insn (t)))
5530132718Skan	++ nops;
5531132718Skan
5532132718Skan      while (nops --)
5533132718Skan	emit_insn_after (gen_nop (), first);
5534132718Skan
5535132718Skan      return;
5536132718Skan    }
5537132718Skan
5538132718Skan  /* (float (blah)) is in parallel with a clobber.  */
5539132718Skan  if (GET_CODE (body) == PARALLEL && XVECLEN (body, 0) > 0)
5540132718Skan    body = XVECEXP (body, 0, 0);
5541132718Skan
5542132718Skan  if (GET_CODE (body) == SET)
5543132718Skan    {
5544132718Skan      rtx lhs = XEXP (body, 0), rhs = XEXP (body, 1);
5545132718Skan
5546132718Skan      /* cfldrd, cfldr64, cfstrd, cfstr64 must
5547132718Skan	 be followed by a non Cirrus insn.  */
5548132718Skan      if (get_attr_cirrus (first) == CIRRUS_DOUBLE)
5549132718Skan	{
5550132718Skan	  if (arm_cirrus_insn_p (next_nonnote_insn (first)))
5551132718Skan	    emit_insn_after (gen_nop (), first);
5552132718Skan
5553132718Skan	  return;
5554132718Skan	}
5555132718Skan      else if (arm_memory_load_p (first))
5556132718Skan	{
5557132718Skan	  unsigned int arm_regno;
5558132718Skan
5559132718Skan	  /* Any ldr/cfmvdlr, ldr/cfmvdhr, ldr/cfmvsr, ldr/cfmv64lr,
5560132718Skan	     ldr/cfmv64hr combination where the Rd field is the same
5561132718Skan	     in both instructions must be split with a non Cirrus
5562132718Skan	     insn.  Example:
5563132718Skan
5564132718Skan	     ldr r0, blah
5565132718Skan	     nop
5566132718Skan	     cfmvsr mvf0, r0.  */
5567132718Skan
5568132718Skan	  /* Get Arm register number for ldr insn.  */
5569132718Skan	  if (GET_CODE (lhs) == REG)
5570132718Skan	    arm_regno = REGNO (lhs);
5571132718Skan	  else
5572169689Skan	    {
5573169689Skan	      gcc_assert (GET_CODE (rhs) == REG);
5574169689Skan	      arm_regno = REGNO (rhs);
5575169689Skan	    }
5576132718Skan
5577132718Skan	  /* Next insn.  */
5578132718Skan	  first = next_nonnote_insn (first);
5579132718Skan
5580132718Skan	  if (! arm_cirrus_insn_p (first))
5581132718Skan	    return;
5582132718Skan
5583132718Skan	  body = PATTERN (first);
5584132718Skan
5585132718Skan          /* (float (blah)) is in parallel with a clobber.  */
5586132718Skan          if (GET_CODE (body) == PARALLEL && XVECLEN (body, 0))
5587132718Skan	    body = XVECEXP (body, 0, 0);
5588132718Skan
5589132718Skan	  if (GET_CODE (body) == FLOAT)
5590132718Skan	    body = XEXP (body, 0);
5591132718Skan
5592132718Skan	  if (get_attr_cirrus (first) == CIRRUS_MOVE
5593132718Skan	      && GET_CODE (XEXP (body, 1)) == REG
5594132718Skan	      && arm_regno == REGNO (XEXP (body, 1)))
5595132718Skan	    emit_insn_after (gen_nop (), first);
5596132718Skan
5597132718Skan	  return;
5598132718Skan	}
5599132718Skan    }
5600132718Skan
5601169689Skan  /* get_attr cannot accept USE or CLOBBER.  */
5602132718Skan  if (!first
5603132718Skan      || GET_CODE (first) != INSN
5604132718Skan      || GET_CODE (PATTERN (first)) == USE
5605132718Skan      || GET_CODE (PATTERN (first)) == CLOBBER)
5606132718Skan    return;
5607132718Skan
5608132718Skan  attr = get_attr_cirrus (first);
5609132718Skan
5610132718Skan  /* Any coprocessor compare instruction (cfcmps, cfcmpd, ...)
5611132718Skan     must be followed by a non-coprocessor instruction.  */
5612132718Skan  if (attr == CIRRUS_COMPARE)
5613132718Skan    {
5614132718Skan      nops = 0;
5615132718Skan
5616132718Skan      t = next_nonnote_insn (first);
5617132718Skan
5618132718Skan      if (arm_cirrus_insn_p (t))
5619132718Skan	++ nops;
5620132718Skan
5621132718Skan      if (arm_cirrus_insn_p (next_nonnote_insn (t)))
5622132718Skan	++ nops;
5623132718Skan
5624132718Skan      while (nops --)
5625132718Skan	emit_insn_after (gen_nop (), first);
5626132718Skan
5627132718Skan      return;
5628132718Skan    }
5629132718Skan}
5630132718Skan
563190075Sobrien/* Return TRUE if X references a SYMBOL_REF.  */
563290075Sobrienint
5633132718Skansymbol_mentioned_p (rtx x)
563490075Sobrien{
563590075Sobrien  const char * fmt;
563690075Sobrien  int i;
563790075Sobrien
563890075Sobrien  if (GET_CODE (x) == SYMBOL_REF)
563990075Sobrien    return 1;
564090075Sobrien
5641169689Skan  /* UNSPEC_TLS entries for a symbol include the SYMBOL_REF, but they
5642169689Skan     are constant offsets, not symbols.  */
5643169689Skan  if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLS)
5644169689Skan    return 0;
5645169689Skan
564690075Sobrien  fmt = GET_RTX_FORMAT (GET_CODE (x));
5647169689Skan
564890075Sobrien  for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
564990075Sobrien    {
565090075Sobrien      if (fmt[i] == 'E')
565190075Sobrien	{
565290075Sobrien	  int j;
565390075Sobrien
565490075Sobrien	  for (j = XVECLEN (x, i) - 1; j >= 0; j--)
565590075Sobrien	    if (symbol_mentioned_p (XVECEXP (x, i, j)))
565690075Sobrien	      return 1;
565790075Sobrien	}
565890075Sobrien      else if (fmt[i] == 'e' && symbol_mentioned_p (XEXP (x, i)))
565990075Sobrien	return 1;
566090075Sobrien    }
566190075Sobrien
566290075Sobrien  return 0;
566390075Sobrien}
566490075Sobrien
566590075Sobrien/* Return TRUE if X references a LABEL_REF.  */
566690075Sobrienint
5667132718Skanlabel_mentioned_p (rtx x)
566890075Sobrien{
566990075Sobrien  const char * fmt;
567090075Sobrien  int i;
567190075Sobrien
567290075Sobrien  if (GET_CODE (x) == LABEL_REF)
567390075Sobrien    return 1;
567490075Sobrien
5675169689Skan  /* UNSPEC_TLS entries for a symbol include a LABEL_REF for the referencing
5676169689Skan     instruction, but they are constant offsets, not symbols.  */
5677169689Skan  if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLS)
5678169689Skan    return 0;
5679169689Skan
568090075Sobrien  fmt = GET_RTX_FORMAT (GET_CODE (x));
568190075Sobrien  for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
568290075Sobrien    {
568390075Sobrien      if (fmt[i] == 'E')
568490075Sobrien	{
568590075Sobrien	  int j;
568690075Sobrien
568790075Sobrien	  for (j = XVECLEN (x, i) - 1; j >= 0; j--)
568890075Sobrien	    if (label_mentioned_p (XVECEXP (x, i, j)))
568990075Sobrien	      return 1;
569090075Sobrien	}
569190075Sobrien      else if (fmt[i] == 'e' && label_mentioned_p (XEXP (x, i)))
569290075Sobrien	return 1;
569390075Sobrien    }
569490075Sobrien
569590075Sobrien  return 0;
569690075Sobrien}
569790075Sobrien
5698169689Skanint
5699169689Skantls_mentioned_p (rtx x)
5700169689Skan{
5701169689Skan  switch (GET_CODE (x))
5702169689Skan    {
5703169689Skan    case CONST:
5704169689Skan      return tls_mentioned_p (XEXP (x, 0));
5705169689Skan
5706169689Skan    case UNSPEC:
5707169689Skan      if (XINT (x, 1) == UNSPEC_TLS)
5708169689Skan	return 1;
5709169689Skan
5710169689Skan    default:
5711169689Skan      return 0;
5712169689Skan    }
5713169689Skan}
5714169689Skan
5715169689Skan/* Must not copy a SET whose source operand is PC-relative.  */
5716169689Skan
5717169689Skanstatic bool
5718169689Skanarm_cannot_copy_insn_p (rtx insn)
5719169689Skan{
5720169689Skan  rtx pat = PATTERN (insn);
5721169689Skan
5722169689Skan  if (GET_CODE (pat) == PARALLEL
5723169689Skan      && GET_CODE (XVECEXP (pat, 0, 0)) == SET)
5724169689Skan    {
5725169689Skan      rtx rhs = SET_SRC (XVECEXP (pat, 0, 0));
5726169689Skan
5727169689Skan      if (GET_CODE (rhs) == UNSPEC
5728169689Skan	  && XINT (rhs, 1) == UNSPEC_PIC_BASE)
5729169689Skan	return TRUE;
5730169689Skan
5731169689Skan      if (GET_CODE (rhs) == MEM
5732169689Skan	  && GET_CODE (XEXP (rhs, 0)) == UNSPEC
5733169689Skan	  && XINT (XEXP (rhs, 0), 1) == UNSPEC_PIC_BASE)
5734169689Skan	return TRUE;
5735169689Skan    }
5736169689Skan
5737169689Skan  return FALSE;
5738169689Skan}
5739169689Skan
574090075Sobrienenum rtx_code
5741132718Skanminmax_code (rtx x)
574290075Sobrien{
574390075Sobrien  enum rtx_code code = GET_CODE (x);
574490075Sobrien
5745169689Skan  switch (code)
5746169689Skan    {
5747169689Skan    case SMAX:
5748169689Skan      return GE;
5749169689Skan    case SMIN:
5750169689Skan      return LE;
5751169689Skan    case UMIN:
5752169689Skan      return LEU;
5753169689Skan    case UMAX:
5754169689Skan      return GEU;
5755169689Skan    default:
5756169689Skan      gcc_unreachable ();
5757169689Skan    }
575890075Sobrien}
575990075Sobrien
576090075Sobrien/* Return 1 if memory locations are adjacent.  */
576190075Sobrienint
5762132718Skanadjacent_mem_locations (rtx a, rtx b)
576390075Sobrien{
5764169689Skan  /* We don't guarantee to preserve the order of these memory refs.  */
5765169689Skan  if (volatile_refs_p (a) || volatile_refs_p (b))
5766169689Skan    return 0;
5767169689Skan
576890075Sobrien  if ((GET_CODE (XEXP (a, 0)) == REG
576990075Sobrien       || (GET_CODE (XEXP (a, 0)) == PLUS
577090075Sobrien	   && GET_CODE (XEXP (XEXP (a, 0), 1)) == CONST_INT))
577190075Sobrien      && (GET_CODE (XEXP (b, 0)) == REG
577290075Sobrien	  || (GET_CODE (XEXP (b, 0)) == PLUS
577390075Sobrien	      && GET_CODE (XEXP (XEXP (b, 0), 1)) == CONST_INT)))
577490075Sobrien    {
5775146895Skan      HOST_WIDE_INT val0 = 0, val1 = 0;
5776146895Skan      rtx reg0, reg1;
5777146895Skan      int val_diff;
5778146895Skan
577990075Sobrien      if (GET_CODE (XEXP (a, 0)) == PLUS)
578090075Sobrien        {
5781146895Skan	  reg0 = XEXP (XEXP (a, 0), 0);
578290075Sobrien	  val0 = INTVAL (XEXP (XEXP (a, 0), 1));
578390075Sobrien        }
578490075Sobrien      else
5785146895Skan	reg0 = XEXP (a, 0);
578690075Sobrien
578790075Sobrien      if (GET_CODE (XEXP (b, 0)) == PLUS)
578890075Sobrien        {
5789146895Skan	  reg1 = XEXP (XEXP (b, 0), 0);
579090075Sobrien	  val1 = INTVAL (XEXP (XEXP (b, 0), 1));
579190075Sobrien        }
579290075Sobrien      else
5793146895Skan	reg1 = XEXP (b, 0);
579490075Sobrien
5795132718Skan      /* Don't accept any offset that will require multiple
5796132718Skan	 instructions to handle, since this would cause the
5797132718Skan	 arith_adjacentmem pattern to output an overlong sequence.  */
5798132718Skan      if (!const_ok_for_op (PLUS, val0) || !const_ok_for_op (PLUS, val1))
5799132718Skan	return 0;
5800146895Skan
5801146895Skan      /* Don't allow an eliminable register: register elimination can make
5802146895Skan	 the offset too large.  */
5803146895Skan      if (arm_eliminable_register (reg0))
5804146895Skan	return 0;
5805146895Skan
5806146895Skan      val_diff = val1 - val0;
5807169689Skan
5808169689Skan      if (arm_ld_sched)
5809169689Skan	{
5810169689Skan	  /* If the target has load delay slots, then there's no benefit
5811169689Skan	     to using an ldm instruction unless the offset is zero and
5812169689Skan	     we are optimizing for size.  */
5813169689Skan	  return (optimize_size && (REGNO (reg0) == REGNO (reg1))
5814169689Skan		  && (val0 == 0 || val1 == 0 || val0 == 4 || val1 == 4)
5815169689Skan		  && (val_diff == 4 || val_diff == -4));
5816169689Skan	}
5817169689Skan
5818146895Skan      return ((REGNO (reg0) == REGNO (reg1))
5819146895Skan	      && (val_diff == 4 || val_diff == -4));
582090075Sobrien    }
5821146895Skan
582290075Sobrien  return 0;
582390075Sobrien}
582490075Sobrien
582590075Sobrienint
5826132718Skanload_multiple_sequence (rtx *operands, int nops, int *regs, int *base,
5827132718Skan			HOST_WIDE_INT *load_offset)
582890075Sobrien{
582990075Sobrien  int unsorted_regs[4];
583090075Sobrien  HOST_WIDE_INT unsorted_offsets[4];
583190075Sobrien  int order[4];
583290075Sobrien  int base_reg = -1;
583390075Sobrien  int i;
583490075Sobrien
583590075Sobrien  /* Can only handle 2, 3, or 4 insns at present,
583690075Sobrien     though could be easily extended if required.  */
5837169689Skan  gcc_assert (nops >= 2 && nops <= 4);
583890075Sobrien
583990075Sobrien  /* Loop over the operands and check that the memory references are
5840169689Skan     suitable (i.e. immediate offsets from the same base register).  At
584190075Sobrien     the same time, extract the target register, and the memory
584290075Sobrien     offsets.  */
584390075Sobrien  for (i = 0; i < nops; i++)
584490075Sobrien    {
584590075Sobrien      rtx reg;
584690075Sobrien      rtx offset;
584790075Sobrien
584890075Sobrien      /* Convert a subreg of a mem into the mem itself.  */
584990075Sobrien      if (GET_CODE (operands[nops + i]) == SUBREG)
585090075Sobrien	operands[nops + i] = alter_subreg (operands + (nops + i));
585190075Sobrien
5852169689Skan      gcc_assert (GET_CODE (operands[nops + i]) == MEM);
585390075Sobrien
585490075Sobrien      /* Don't reorder volatile memory references; it doesn't seem worth
585590075Sobrien	 looking for the case where the order is ok anyway.  */
585690075Sobrien      if (MEM_VOLATILE_P (operands[nops + i]))
585790075Sobrien	return 0;
585890075Sobrien
585990075Sobrien      offset = const0_rtx;
586090075Sobrien
586190075Sobrien      if ((GET_CODE (reg = XEXP (operands[nops + i], 0)) == REG
586290075Sobrien	   || (GET_CODE (reg) == SUBREG
586390075Sobrien	       && GET_CODE (reg = SUBREG_REG (reg)) == REG))
586490075Sobrien	  || (GET_CODE (XEXP (operands[nops + i], 0)) == PLUS
586590075Sobrien	      && ((GET_CODE (reg = XEXP (XEXP (operands[nops + i], 0), 0))
586690075Sobrien		   == REG)
586790075Sobrien		  || (GET_CODE (reg) == SUBREG
586890075Sobrien		      && GET_CODE (reg = SUBREG_REG (reg)) == REG))
586990075Sobrien	      && (GET_CODE (offset = XEXP (XEXP (operands[nops + i], 0), 1))
587090075Sobrien		  == CONST_INT)))
587190075Sobrien	{
587290075Sobrien	  if (i == 0)
587390075Sobrien	    {
587490075Sobrien	      base_reg = REGNO (reg);
587590075Sobrien	      unsorted_regs[0] = (GET_CODE (operands[i]) == REG
587690075Sobrien				  ? REGNO (operands[i])
587790075Sobrien				  : REGNO (SUBREG_REG (operands[i])));
587890075Sobrien	      order[0] = 0;
587990075Sobrien	    }
5880169689Skan	  else
588190075Sobrien	    {
588290075Sobrien	      if (base_reg != (int) REGNO (reg))
588390075Sobrien		/* Not addressed from the same base register.  */
588490075Sobrien		return 0;
588590075Sobrien
588690075Sobrien	      unsorted_regs[i] = (GET_CODE (operands[i]) == REG
588790075Sobrien				  ? REGNO (operands[i])
588890075Sobrien				  : REGNO (SUBREG_REG (operands[i])));
588990075Sobrien	      if (unsorted_regs[i] < unsorted_regs[order[0]])
589090075Sobrien		order[0] = i;
589190075Sobrien	    }
589290075Sobrien
589390075Sobrien	  /* If it isn't an integer register, or if it overwrites the
589490075Sobrien	     base register but isn't the last insn in the list, then
589590075Sobrien	     we can't do this.  */
589690075Sobrien	  if (unsorted_regs[i] < 0 || unsorted_regs[i] > 14
589790075Sobrien	      || (i != nops - 1 && unsorted_regs[i] == base_reg))
589890075Sobrien	    return 0;
589990075Sobrien
590090075Sobrien	  unsorted_offsets[i] = INTVAL (offset);
590190075Sobrien	}
590290075Sobrien      else
590390075Sobrien	/* Not a suitable memory address.  */
590490075Sobrien	return 0;
590590075Sobrien    }
590690075Sobrien
590790075Sobrien  /* All the useful information has now been extracted from the
590890075Sobrien     operands into unsorted_regs and unsorted_offsets; additionally,
590990075Sobrien     order[0] has been set to the lowest numbered register in the
591090075Sobrien     list.  Sort the registers into order, and check that the memory
591190075Sobrien     offsets are ascending and adjacent.  */
591290075Sobrien
591390075Sobrien  for (i = 1; i < nops; i++)
591490075Sobrien    {
591590075Sobrien      int j;
591690075Sobrien
591790075Sobrien      order[i] = order[i - 1];
591890075Sobrien      for (j = 0; j < nops; j++)
591990075Sobrien	if (unsorted_regs[j] > unsorted_regs[order[i - 1]]
592090075Sobrien	    && (order[i] == order[i - 1]
592190075Sobrien		|| unsorted_regs[j] < unsorted_regs[order[i]]))
592290075Sobrien	  order[i] = j;
592390075Sobrien
592490075Sobrien      /* Have we found a suitable register? if not, one must be used more
592590075Sobrien	 than once.  */
592690075Sobrien      if (order[i] == order[i - 1])
592790075Sobrien	return 0;
592890075Sobrien
592990075Sobrien      /* Is the memory address adjacent and ascending? */
593090075Sobrien      if (unsorted_offsets[order[i]] != unsorted_offsets[order[i - 1]] + 4)
593190075Sobrien	return 0;
593290075Sobrien    }
593390075Sobrien
593490075Sobrien  if (base)
593590075Sobrien    {
593690075Sobrien      *base = base_reg;
593790075Sobrien
593890075Sobrien      for (i = 0; i < nops; i++)
593990075Sobrien	regs[i] = unsorted_regs[order[i]];
594090075Sobrien
594190075Sobrien      *load_offset = unsorted_offsets[order[0]];
594290075Sobrien    }
594390075Sobrien
594490075Sobrien  if (unsorted_offsets[order[0]] == 0)
594590075Sobrien    return 1; /* ldmia */
594690075Sobrien
594790075Sobrien  if (unsorted_offsets[order[0]] == 4)
594890075Sobrien    return 2; /* ldmib */
594990075Sobrien
595090075Sobrien  if (unsorted_offsets[order[nops - 1]] == 0)
595190075Sobrien    return 3; /* ldmda */
595290075Sobrien
595390075Sobrien  if (unsorted_offsets[order[nops - 1]] == -4)
595490075Sobrien    return 4; /* ldmdb */
595590075Sobrien
595690075Sobrien  /* For ARM8,9 & StrongARM, 2 ldr instructions are faster than an ldm
595790075Sobrien     if the offset isn't small enough.  The reason 2 ldrs are faster
595890075Sobrien     is because these ARMs are able to do more than one cache access
595990075Sobrien     in a single cycle.  The ARM9 and StrongARM have Harvard caches,
596090075Sobrien     whilst the ARM8 has a double bandwidth cache.  This means that
596190075Sobrien     these cores can do both an instruction fetch and a data fetch in
596290075Sobrien     a single cycle, so the trick of calculating the address into a
596390075Sobrien     scratch register (one of the result regs) and then doing a load
596490075Sobrien     multiple actually becomes slower (and no smaller in code size).
596590075Sobrien     That is the transformation
5966169689Skan
596790075Sobrien 	ldr	rd1, [rbase + offset]
596890075Sobrien 	ldr	rd2, [rbase + offset + 4]
5969169689Skan
597090075Sobrien     to
5971169689Skan
597290075Sobrien 	add	rd1, rbase, offset
597390075Sobrien 	ldmia	rd1, {rd1, rd2}
5974169689Skan
597590075Sobrien     produces worse code -- '3 cycles + any stalls on rd2' instead of
597690075Sobrien     '2 cycles + any stalls on rd2'.  On ARMs with only one cache
597790075Sobrien     access per cycle, the first sequence could never complete in less
597890075Sobrien     than 6 cycles, whereas the ldm sequence would only take 5 and
597990075Sobrien     would make better use of sequential accesses if not hitting the
598090075Sobrien     cache.
598190075Sobrien
598290075Sobrien     We cheat here and test 'arm_ld_sched' which we currently know to
598390075Sobrien     only be true for the ARM8, ARM9 and StrongARM.  If this ever
598490075Sobrien     changes, then the test below needs to be reworked.  */
598590075Sobrien  if (nops == 2 && arm_ld_sched)
598690075Sobrien    return 0;
598790075Sobrien
598890075Sobrien  /* Can't do it without setting up the offset, only do this if it takes
598990075Sobrien     no more than one insn.  */
5990169689Skan  return (const_ok_for_arm (unsorted_offsets[order[0]])
599190075Sobrien	  || const_ok_for_arm (-unsorted_offsets[order[0]])) ? 5 : 0;
599290075Sobrien}
599390075Sobrien
599490075Sobrienconst char *
5995132718Skanemit_ldm_seq (rtx *operands, int nops)
599690075Sobrien{
599790075Sobrien  int regs[4];
599890075Sobrien  int base_reg;
599990075Sobrien  HOST_WIDE_INT offset;
600090075Sobrien  char buf[100];
600190075Sobrien  int i;
600290075Sobrien
600390075Sobrien  switch (load_multiple_sequence (operands, nops, regs, &base_reg, &offset))
600490075Sobrien    {
600590075Sobrien    case 1:
600690075Sobrien      strcpy (buf, "ldm%?ia\t");
600790075Sobrien      break;
600890075Sobrien
600990075Sobrien    case 2:
601090075Sobrien      strcpy (buf, "ldm%?ib\t");
601190075Sobrien      break;
601290075Sobrien
601390075Sobrien    case 3:
601490075Sobrien      strcpy (buf, "ldm%?da\t");
601590075Sobrien      break;
601690075Sobrien
601790075Sobrien    case 4:
601890075Sobrien      strcpy (buf, "ldm%?db\t");
601990075Sobrien      break;
602090075Sobrien
602190075Sobrien    case 5:
602290075Sobrien      if (offset >= 0)
602390075Sobrien	sprintf (buf, "add%%?\t%s%s, %s%s, #%ld", REGISTER_PREFIX,
602490075Sobrien		 reg_names[regs[0]], REGISTER_PREFIX, reg_names[base_reg],
602590075Sobrien		 (long) offset);
602690075Sobrien      else
602790075Sobrien	sprintf (buf, "sub%%?\t%s%s, %s%s, #%ld", REGISTER_PREFIX,
602890075Sobrien		 reg_names[regs[0]], REGISTER_PREFIX, reg_names[base_reg],
602990075Sobrien		 (long) -offset);
603090075Sobrien      output_asm_insn (buf, operands);
603190075Sobrien      base_reg = regs[0];
603290075Sobrien      strcpy (buf, "ldm%?ia\t");
603390075Sobrien      break;
603490075Sobrien
603590075Sobrien    default:
6036169689Skan      gcc_unreachable ();
603790075Sobrien    }
603890075Sobrien
6039169689Skan  sprintf (buf + strlen (buf), "%s%s, {%s%s", REGISTER_PREFIX,
604090075Sobrien	   reg_names[base_reg], REGISTER_PREFIX, reg_names[regs[0]]);
604190075Sobrien
604290075Sobrien  for (i = 1; i < nops; i++)
604390075Sobrien    sprintf (buf + strlen (buf), ", %s%s", REGISTER_PREFIX,
604490075Sobrien	     reg_names[regs[i]]);
604590075Sobrien
604690075Sobrien  strcat (buf, "}\t%@ phole ldm");
604790075Sobrien
604890075Sobrien  output_asm_insn (buf, operands);
604990075Sobrien  return "";
605090075Sobrien}
605190075Sobrien
605290075Sobrienint
6053132718Skanstore_multiple_sequence (rtx *operands, int nops, int *regs, int *base,
6054132718Skan			 HOST_WIDE_INT * load_offset)
605590075Sobrien{
605690075Sobrien  int unsorted_regs[4];
605790075Sobrien  HOST_WIDE_INT unsorted_offsets[4];
605890075Sobrien  int order[4];
605990075Sobrien  int base_reg = -1;
606090075Sobrien  int i;
606190075Sobrien
606290075Sobrien  /* Can only handle 2, 3, or 4 insns at present, though could be easily
606390075Sobrien     extended if required.  */
6064169689Skan  gcc_assert (nops >= 2 && nops <= 4);
606590075Sobrien
606690075Sobrien  /* Loop over the operands and check that the memory references are
6067169689Skan     suitable (i.e. immediate offsets from the same base register).  At
606890075Sobrien     the same time, extract the target register, and the memory
606990075Sobrien     offsets.  */
607090075Sobrien  for (i = 0; i < nops; i++)
607190075Sobrien    {
607290075Sobrien      rtx reg;
607390075Sobrien      rtx offset;
607490075Sobrien
607590075Sobrien      /* Convert a subreg of a mem into the mem itself.  */
607690075Sobrien      if (GET_CODE (operands[nops + i]) == SUBREG)
607790075Sobrien	operands[nops + i] = alter_subreg (operands + (nops + i));
607890075Sobrien
6079169689Skan      gcc_assert (GET_CODE (operands[nops + i]) == MEM);
608090075Sobrien
608190075Sobrien      /* Don't reorder volatile memory references; it doesn't seem worth
608290075Sobrien	 looking for the case where the order is ok anyway.  */
608390075Sobrien      if (MEM_VOLATILE_P (operands[nops + i]))
608490075Sobrien	return 0;
608590075Sobrien
608690075Sobrien      offset = const0_rtx;
608790075Sobrien
608890075Sobrien      if ((GET_CODE (reg = XEXP (operands[nops + i], 0)) == REG
608990075Sobrien	   || (GET_CODE (reg) == SUBREG
609090075Sobrien	       && GET_CODE (reg = SUBREG_REG (reg)) == REG))
609190075Sobrien	  || (GET_CODE (XEXP (operands[nops + i], 0)) == PLUS
609290075Sobrien	      && ((GET_CODE (reg = XEXP (XEXP (operands[nops + i], 0), 0))
609390075Sobrien		   == REG)
609490075Sobrien		  || (GET_CODE (reg) == SUBREG
609590075Sobrien		      && GET_CODE (reg = SUBREG_REG (reg)) == REG))
609690075Sobrien	      && (GET_CODE (offset = XEXP (XEXP (operands[nops + i], 0), 1))
609790075Sobrien		  == CONST_INT)))
609890075Sobrien	{
609990075Sobrien	  if (i == 0)
610090075Sobrien	    {
610190075Sobrien	      base_reg = REGNO (reg);
610290075Sobrien	      unsorted_regs[0] = (GET_CODE (operands[i]) == REG
610390075Sobrien				  ? REGNO (operands[i])
610490075Sobrien				  : REGNO (SUBREG_REG (operands[i])));
610590075Sobrien	      order[0] = 0;
610690075Sobrien	    }
6107169689Skan	  else
610890075Sobrien	    {
610990075Sobrien	      if (base_reg != (int) REGNO (reg))
611090075Sobrien		/* Not addressed from the same base register.  */
611190075Sobrien		return 0;
611290075Sobrien
611390075Sobrien	      unsorted_regs[i] = (GET_CODE (operands[i]) == REG
611490075Sobrien				  ? REGNO (operands[i])
611590075Sobrien				  : REGNO (SUBREG_REG (operands[i])));
611690075Sobrien	      if (unsorted_regs[i] < unsorted_regs[order[0]])
611790075Sobrien		order[0] = i;
611890075Sobrien	    }
611990075Sobrien
612090075Sobrien	  /* If it isn't an integer register, then we can't do this.  */
612190075Sobrien	  if (unsorted_regs[i] < 0 || unsorted_regs[i] > 14)
612290075Sobrien	    return 0;
612390075Sobrien
612490075Sobrien	  unsorted_offsets[i] = INTVAL (offset);
612590075Sobrien	}
612690075Sobrien      else
612790075Sobrien	/* Not a suitable memory address.  */
612890075Sobrien	return 0;
612990075Sobrien    }
613090075Sobrien
613190075Sobrien  /* All the useful information has now been extracted from the
613290075Sobrien     operands into unsorted_regs and unsorted_offsets; additionally,
613390075Sobrien     order[0] has been set to the lowest numbered register in the
613490075Sobrien     list.  Sort the registers into order, and check that the memory
613590075Sobrien     offsets are ascending and adjacent.  */
613690075Sobrien
613790075Sobrien  for (i = 1; i < nops; i++)
613890075Sobrien    {
613990075Sobrien      int j;
614090075Sobrien
614190075Sobrien      order[i] = order[i - 1];
614290075Sobrien      for (j = 0; j < nops; j++)
614390075Sobrien	if (unsorted_regs[j] > unsorted_regs[order[i - 1]]
614490075Sobrien	    && (order[i] == order[i - 1]
614590075Sobrien		|| unsorted_regs[j] < unsorted_regs[order[i]]))
614690075Sobrien	  order[i] = j;
614790075Sobrien
614890075Sobrien      /* Have we found a suitable register? if not, one must be used more
614990075Sobrien	 than once.  */
615090075Sobrien      if (order[i] == order[i - 1])
615190075Sobrien	return 0;
615290075Sobrien
615390075Sobrien      /* Is the memory address adjacent and ascending? */
615490075Sobrien      if (unsorted_offsets[order[i]] != unsorted_offsets[order[i - 1]] + 4)
615590075Sobrien	return 0;
615690075Sobrien    }
615790075Sobrien
615890075Sobrien  if (base)
615990075Sobrien    {
616090075Sobrien      *base = base_reg;
616190075Sobrien
616290075Sobrien      for (i = 0; i < nops; i++)
616390075Sobrien	regs[i] = unsorted_regs[order[i]];
616490075Sobrien
616590075Sobrien      *load_offset = unsorted_offsets[order[0]];
616690075Sobrien    }
616790075Sobrien
616890075Sobrien  if (unsorted_offsets[order[0]] == 0)
616990075Sobrien    return 1; /* stmia */
617090075Sobrien
617190075Sobrien  if (unsorted_offsets[order[0]] == 4)
617290075Sobrien    return 2; /* stmib */
617390075Sobrien
617490075Sobrien  if (unsorted_offsets[order[nops - 1]] == 0)
617590075Sobrien    return 3; /* stmda */
617690075Sobrien
617790075Sobrien  if (unsorted_offsets[order[nops - 1]] == -4)
617890075Sobrien    return 4; /* stmdb */
617990075Sobrien
618090075Sobrien  return 0;
618190075Sobrien}
618290075Sobrien
618390075Sobrienconst char *
6184132718Skanemit_stm_seq (rtx *operands, int nops)
618590075Sobrien{
618690075Sobrien  int regs[4];
618790075Sobrien  int base_reg;
618890075Sobrien  HOST_WIDE_INT offset;
618990075Sobrien  char buf[100];
619090075Sobrien  int i;
619190075Sobrien
619290075Sobrien  switch (store_multiple_sequence (operands, nops, regs, &base_reg, &offset))
619390075Sobrien    {
619490075Sobrien    case 1:
619590075Sobrien      strcpy (buf, "stm%?ia\t");
619690075Sobrien      break;
619790075Sobrien
619890075Sobrien    case 2:
619990075Sobrien      strcpy (buf, "stm%?ib\t");
620090075Sobrien      break;
620190075Sobrien
620290075Sobrien    case 3:
620390075Sobrien      strcpy (buf, "stm%?da\t");
620490075Sobrien      break;
620590075Sobrien
620690075Sobrien    case 4:
620790075Sobrien      strcpy (buf, "stm%?db\t");
620890075Sobrien      break;
620990075Sobrien
621090075Sobrien    default:
6211169689Skan      gcc_unreachable ();
621290075Sobrien    }
621390075Sobrien
6214169689Skan  sprintf (buf + strlen (buf), "%s%s, {%s%s", REGISTER_PREFIX,
621590075Sobrien	   reg_names[base_reg], REGISTER_PREFIX, reg_names[regs[0]]);
621690075Sobrien
621790075Sobrien  for (i = 1; i < nops; i++)
621890075Sobrien    sprintf (buf + strlen (buf), ", %s%s", REGISTER_PREFIX,
621990075Sobrien	     reg_names[regs[i]]);
622090075Sobrien
622190075Sobrien  strcat (buf, "}\t%@ phole stm");
622290075Sobrien
622390075Sobrien  output_asm_insn (buf, operands);
622490075Sobrien  return "";
622590075Sobrien}
622690075Sobrien
622790075Sobrien/* Routines for use in generating RTL.  */
622890075Sobrien
622990075Sobrienrtx
6230132718Skanarm_gen_load_multiple (int base_regno, int count, rtx from, int up,
6231161651Skan		       int write_back, rtx basemem, HOST_WIDE_INT *offsetp)
623290075Sobrien{
6233161651Skan  HOST_WIDE_INT offset = *offsetp;
623490075Sobrien  int i = 0, j;
623590075Sobrien  rtx result;
623690075Sobrien  int sign = up ? 1 : -1;
6237161651Skan  rtx mem, addr;
623890075Sobrien
623990075Sobrien  /* XScale has load-store double instructions, but they have stricter
6240169689Skan     alignment requirements than load-store multiple, so we cannot
624190075Sobrien     use them.
624290075Sobrien
624390075Sobrien     For XScale ldm requires 2 + NREGS cycles to complete and blocks
624490075Sobrien     the pipeline until completion.
624590075Sobrien
624690075Sobrien	NREGS		CYCLES
624790075Sobrien	  1		  3
624890075Sobrien	  2		  4
624990075Sobrien	  3		  5
625090075Sobrien	  4		  6
625190075Sobrien
625290075Sobrien     An ldr instruction takes 1-3 cycles, but does not block the
625390075Sobrien     pipeline.
625490075Sobrien
625590075Sobrien	NREGS		CYCLES
625690075Sobrien	  1		 1-3
625790075Sobrien	  2		 2-6
625890075Sobrien	  3		 3-9
625990075Sobrien	  4		 4-12
626090075Sobrien
626190075Sobrien     Best case ldr will always win.  However, the more ldr instructions
626290075Sobrien     we issue, the less likely we are to be able to schedule them well.
626390075Sobrien     Using ldr instructions also increases code size.
626490075Sobrien
626590075Sobrien     As a compromise, we use ldr for counts of 1 or 2 regs, and ldm
626690075Sobrien     for counts of 3 or 4 regs.  */
6267132718Skan  if (arm_tune_xscale && count <= 2 && ! optimize_size)
626890075Sobrien    {
626990075Sobrien      rtx seq;
6270169689Skan
627190075Sobrien      start_sequence ();
6272169689Skan
627390075Sobrien      for (i = 0; i < count; i++)
627490075Sobrien	{
6275161651Skan	  addr = plus_constant (from, i * 4 * sign);
6276161651Skan	  mem = adjust_automodify_address (basemem, SImode, addr, offset);
627790075Sobrien	  emit_move_insn (gen_rtx_REG (SImode, base_regno + i), mem);
6278161651Skan	  offset += 4 * sign;
627990075Sobrien	}
628090075Sobrien
628190075Sobrien      if (write_back)
6282161651Skan	{
6283161651Skan	  emit_move_insn (from, plus_constant (from, count * 4 * sign));
6284161651Skan	  *offsetp = offset;
6285161651Skan	}
628690075Sobrien
6287117395Skan      seq = get_insns ();
628890075Sobrien      end_sequence ();
6289169689Skan
629090075Sobrien      return seq;
629190075Sobrien    }
629290075Sobrien
629390075Sobrien  result = gen_rtx_PARALLEL (VOIDmode,
629490075Sobrien			     rtvec_alloc (count + (write_back ? 1 : 0)));
629590075Sobrien  if (write_back)
629690075Sobrien    {
629790075Sobrien      XVECEXP (result, 0, 0)
6298169689Skan	= gen_rtx_SET (VOIDmode, from, plus_constant (from, count * 4 * sign));
629990075Sobrien      i = 1;
630090075Sobrien      count++;
630190075Sobrien    }
630290075Sobrien
630390075Sobrien  for (j = 0; i < count; i++, j++)
630490075Sobrien    {
6305161651Skan      addr = plus_constant (from, j * 4 * sign);
6306161651Skan      mem = adjust_automodify_address_nv (basemem, SImode, addr, offset);
630790075Sobrien      XVECEXP (result, 0, i)
630890075Sobrien	= gen_rtx_SET (VOIDmode, gen_rtx_REG (SImode, base_regno + j), mem);
6309161651Skan      offset += 4 * sign;
631090075Sobrien    }
631190075Sobrien
6312161651Skan  if (write_back)
6313161651Skan    *offsetp = offset;
6314161651Skan
631590075Sobrien  return result;
631690075Sobrien}
631790075Sobrien
631890075Sobrienrtx
6319132718Skanarm_gen_store_multiple (int base_regno, int count, rtx to, int up,
6320161651Skan			int write_back, rtx basemem, HOST_WIDE_INT *offsetp)
632190075Sobrien{
6322161651Skan  HOST_WIDE_INT offset = *offsetp;
632390075Sobrien  int i = 0, j;
632490075Sobrien  rtx result;
632590075Sobrien  int sign = up ? 1 : -1;
6326161651Skan  rtx mem, addr;
632790075Sobrien
632890075Sobrien  /* See arm_gen_load_multiple for discussion of
632990075Sobrien     the pros/cons of ldm/stm usage for XScale.  */
6330132718Skan  if (arm_tune_xscale && count <= 2 && ! optimize_size)
633190075Sobrien    {
633290075Sobrien      rtx seq;
6333169689Skan
633490075Sobrien      start_sequence ();
6335169689Skan
633690075Sobrien      for (i = 0; i < count; i++)
633790075Sobrien	{
6338161651Skan	  addr = plus_constant (to, i * 4 * sign);
6339161651Skan	  mem = adjust_automodify_address (basemem, SImode, addr, offset);
634090075Sobrien	  emit_move_insn (mem, gen_rtx_REG (SImode, base_regno + i));
6341161651Skan	  offset += 4 * sign;
634290075Sobrien	}
634390075Sobrien
634490075Sobrien      if (write_back)
6345161651Skan	{
6346161651Skan	  emit_move_insn (to, plus_constant (to, count * 4 * sign));
6347161651Skan	  *offsetp = offset;
6348161651Skan	}
634990075Sobrien
6350117395Skan      seq = get_insns ();
635190075Sobrien      end_sequence ();
6352169689Skan
635390075Sobrien      return seq;
635490075Sobrien    }
635590075Sobrien
635690075Sobrien  result = gen_rtx_PARALLEL (VOIDmode,
635790075Sobrien			     rtvec_alloc (count + (write_back ? 1 : 0)));
635890075Sobrien  if (write_back)
635990075Sobrien    {
636090075Sobrien      XVECEXP (result, 0, 0)
6361169689Skan	= gen_rtx_SET (VOIDmode, to,
636290075Sobrien		       plus_constant (to, count * 4 * sign));
636390075Sobrien      i = 1;
636490075Sobrien      count++;
636590075Sobrien    }
636690075Sobrien
636790075Sobrien  for (j = 0; i < count; i++, j++)
636890075Sobrien    {
6369161651Skan      addr = plus_constant (to, j * 4 * sign);
6370161651Skan      mem = adjust_automodify_address_nv (basemem, SImode, addr, offset);
637190075Sobrien      XVECEXP (result, 0, i)
637290075Sobrien	= gen_rtx_SET (VOIDmode, mem, gen_rtx_REG (SImode, base_regno + j));
6373161651Skan      offset += 4 * sign;
637490075Sobrien    }
637590075Sobrien
6376161651Skan  if (write_back)
6377161651Skan    *offsetp = offset;
6378161651Skan
637990075Sobrien  return result;
638090075Sobrien}
638190075Sobrien
638290075Sobrienint
6383169689Skanarm_gen_movmemqi (rtx *operands)
638490075Sobrien{
638590075Sobrien  HOST_WIDE_INT in_words_to_go, out_words_to_go, last_bytes;
6386161651Skan  HOST_WIDE_INT srcoffset, dstoffset;
638790075Sobrien  int i;
6388161651Skan  rtx src, dst, srcbase, dstbase;
638990075Sobrien  rtx part_bytes_reg = NULL;
639090075Sobrien  rtx mem;
639190075Sobrien
639290075Sobrien  if (GET_CODE (operands[2]) != CONST_INT
639390075Sobrien      || GET_CODE (operands[3]) != CONST_INT
639490075Sobrien      || INTVAL (operands[2]) > 64
639590075Sobrien      || INTVAL (operands[3]) & 3)
639690075Sobrien    return 0;
639790075Sobrien
6398161651Skan  dstbase = operands[0];
6399161651Skan  srcbase = operands[1];
6400169689Skan
6401161651Skan  dst = copy_to_mode_reg (SImode, XEXP (dstbase, 0));
6402161651Skan  src = copy_to_mode_reg (SImode, XEXP (srcbase, 0));
640390075Sobrien
6404117395Skan  in_words_to_go = ARM_NUM_INTS (INTVAL (operands[2]));
640590075Sobrien  out_words_to_go = INTVAL (operands[2]) / 4;
640690075Sobrien  last_bytes = INTVAL (operands[2]) & 3;
6407161651Skan  dstoffset = srcoffset = 0;
6408169689Skan
640990075Sobrien  if (out_words_to_go != in_words_to_go && ((in_words_to_go - 1) & 3) != 0)
641090075Sobrien    part_bytes_reg = gen_rtx_REG (SImode, (in_words_to_go - 1) & 3);
641190075Sobrien
641290075Sobrien  for (i = 0; in_words_to_go >= 2; i+=4)
641390075Sobrien    {
641490075Sobrien      if (in_words_to_go > 4)
641590075Sobrien	emit_insn (arm_gen_load_multiple (0, 4, src, TRUE, TRUE,
6416161651Skan					  srcbase, &srcoffset));
641790075Sobrien      else
6418169689Skan	emit_insn (arm_gen_load_multiple (0, in_words_to_go, src, TRUE,
6419161651Skan					  FALSE, srcbase, &srcoffset));
642090075Sobrien
642190075Sobrien      if (out_words_to_go)
642290075Sobrien	{
642390075Sobrien	  if (out_words_to_go > 4)
642490075Sobrien	    emit_insn (arm_gen_store_multiple (0, 4, dst, TRUE, TRUE,
6425161651Skan					       dstbase, &dstoffset));
642690075Sobrien	  else if (out_words_to_go != 1)
642790075Sobrien	    emit_insn (arm_gen_store_multiple (0, out_words_to_go,
6428169689Skan					       dst, TRUE,
642990075Sobrien					       (last_bytes == 0
643090075Sobrien						? FALSE : TRUE),
6431161651Skan					       dstbase, &dstoffset));
643290075Sobrien	  else
643390075Sobrien	    {
6434161651Skan	      mem = adjust_automodify_address (dstbase, SImode, dst, dstoffset);
643590075Sobrien	      emit_move_insn (mem, gen_rtx_REG (SImode, 0));
643690075Sobrien	      if (last_bytes != 0)
6437161651Skan		{
6438161651Skan		  emit_insn (gen_addsi3 (dst, dst, GEN_INT (4)));
6439161651Skan		  dstoffset += 4;
6440161651Skan		}
644190075Sobrien	    }
644290075Sobrien	}
644390075Sobrien
644490075Sobrien      in_words_to_go -= in_words_to_go < 4 ? in_words_to_go : 4;
644590075Sobrien      out_words_to_go -= out_words_to_go < 4 ? out_words_to_go : 4;
644690075Sobrien    }
644790075Sobrien
644890075Sobrien  /* OUT_WORDS_TO_GO will be zero here if there are byte stores to do.  */
644990075Sobrien  if (out_words_to_go)
645090075Sobrien    {
645190075Sobrien      rtx sreg;
6452161651Skan
6453161651Skan      mem = adjust_automodify_address (srcbase, SImode, src, srcoffset);
6454161651Skan      sreg = copy_to_reg (mem);
6455161651Skan
6456161651Skan      mem = adjust_automodify_address (dstbase, SImode, dst, dstoffset);
645790075Sobrien      emit_move_insn (mem, sreg);
645890075Sobrien      in_words_to_go--;
6459169689Skan
6460169689Skan      gcc_assert (!in_words_to_go);	/* Sanity check */
646190075Sobrien    }
646290075Sobrien
646390075Sobrien  if (in_words_to_go)
646490075Sobrien    {
6465169689Skan      gcc_assert (in_words_to_go > 0);
646690075Sobrien
6467161651Skan      mem = adjust_automodify_address (srcbase, SImode, src, srcoffset);
646890075Sobrien      part_bytes_reg = copy_to_mode_reg (SImode, mem);
646990075Sobrien    }
647090075Sobrien
6471169689Skan  gcc_assert (!last_bytes || part_bytes_reg);
647290075Sobrien
647390075Sobrien  if (BYTES_BIG_ENDIAN && last_bytes)
647490075Sobrien    {
647590075Sobrien      rtx tmp = gen_reg_rtx (SImode);
647690075Sobrien
647790075Sobrien      /* The bytes we want are in the top end of the word.  */
647890075Sobrien      emit_insn (gen_lshrsi3 (tmp, part_bytes_reg,
647990075Sobrien			      GEN_INT (8 * (4 - last_bytes))));
648090075Sobrien      part_bytes_reg = tmp;
6481169689Skan
648290075Sobrien      while (last_bytes)
648390075Sobrien	{
6484161651Skan	  mem = adjust_automodify_address (dstbase, QImode,
6485161651Skan					   plus_constant (dst, last_bytes - 1),
6486161651Skan					   dstoffset + last_bytes - 1);
6487102780Skan	  emit_move_insn (mem, gen_lowpart (QImode, part_bytes_reg));
6488102780Skan
648990075Sobrien	  if (--last_bytes)
649090075Sobrien	    {
649190075Sobrien	      tmp = gen_reg_rtx (SImode);
649290075Sobrien	      emit_insn (gen_lshrsi3 (tmp, part_bytes_reg, GEN_INT (8)));
649390075Sobrien	      part_bytes_reg = tmp;
649490075Sobrien	    }
649590075Sobrien	}
6496169689Skan
649790075Sobrien    }
649890075Sobrien  else
649990075Sobrien    {
650090075Sobrien      if (last_bytes > 1)
650190075Sobrien	{
6502161651Skan	  mem = adjust_automodify_address (dstbase, HImode, dst, dstoffset);
6503102780Skan	  emit_move_insn (mem, gen_lowpart (HImode, part_bytes_reg));
650490075Sobrien	  last_bytes -= 2;
650590075Sobrien	  if (last_bytes)
650690075Sobrien	    {
650790075Sobrien	      rtx tmp = gen_reg_rtx (SImode);
6508169689Skan	      emit_insn (gen_addsi3 (dst, dst, const2_rtx));
650990075Sobrien	      emit_insn (gen_lshrsi3 (tmp, part_bytes_reg, GEN_INT (16)));
651090075Sobrien	      part_bytes_reg = tmp;
6511161651Skan	      dstoffset += 2;
651290075Sobrien	    }
651390075Sobrien	}
6514169689Skan
651590075Sobrien      if (last_bytes)
651690075Sobrien	{
6517161651Skan	  mem = adjust_automodify_address (dstbase, QImode, dst, dstoffset);
6518102780Skan	  emit_move_insn (mem, gen_lowpart (QImode, part_bytes_reg));
651990075Sobrien	}
652090075Sobrien    }
652190075Sobrien
652290075Sobrien  return 1;
652390075Sobrien}
652490075Sobrien
6525132718Skan/* Select a dominance comparison mode if possible for a test of the general
6526132718Skan   form (OP (COND_OR (X) (Y)) (const_int 0)).  We support three forms.
6527169689Skan   COND_OR == DOM_CC_X_AND_Y => (X && Y)
6528132718Skan   COND_OR == DOM_CC_NX_OR_Y => ((! X) || Y)
6529169689Skan   COND_OR == DOM_CC_X_OR_Y => (X || Y)
6530132718Skan   In all cases OP will be either EQ or NE, but we don't need to know which
6531169689Skan   here.  If we are unable to support a dominance comparison we return
6532132718Skan   CC mode.  This will then fail to match for the RTL expressions that
6533132718Skan   generate this call.  */
6534132718Skanenum machine_mode
6535132718Skanarm_select_dominance_cc_mode (rtx x, rtx y, HOST_WIDE_INT cond_or)
653690075Sobrien{
653790075Sobrien  enum rtx_code cond1, cond2;
653890075Sobrien  int swapped = 0;
653990075Sobrien
654090075Sobrien  /* Currently we will probably get the wrong result if the individual
654190075Sobrien     comparisons are not simple.  This also ensures that it is safe to
654290075Sobrien     reverse a comparison if necessary.  */
654390075Sobrien  if ((arm_select_cc_mode (cond1 = GET_CODE (x), XEXP (x, 0), XEXP (x, 1))
654490075Sobrien       != CCmode)
654590075Sobrien      || (arm_select_cc_mode (cond2 = GET_CODE (y), XEXP (y, 0), XEXP (y, 1))
654690075Sobrien	  != CCmode))
654790075Sobrien    return CCmode;
654890075Sobrien
654990075Sobrien  /* The if_then_else variant of this tests the second condition if the
655090075Sobrien     first passes, but is true if the first fails.  Reverse the first
655190075Sobrien     condition to get a true "inclusive-or" expression.  */
6552132718Skan  if (cond_or == DOM_CC_NX_OR_Y)
655390075Sobrien    cond1 = reverse_condition (cond1);
655490075Sobrien
655590075Sobrien  /* If the comparisons are not equal, and one doesn't dominate the other,
655690075Sobrien     then we can't do this.  */
6557169689Skan  if (cond1 != cond2
655890075Sobrien      && !comparison_dominates_p (cond1, cond2)
655990075Sobrien      && (swapped = 1, !comparison_dominates_p (cond2, cond1)))
656090075Sobrien    return CCmode;
656190075Sobrien
656290075Sobrien  if (swapped)
656390075Sobrien    {
656490075Sobrien      enum rtx_code temp = cond1;
656590075Sobrien      cond1 = cond2;
656690075Sobrien      cond2 = temp;
656790075Sobrien    }
656890075Sobrien
656990075Sobrien  switch (cond1)
657090075Sobrien    {
657190075Sobrien    case EQ:
6572169689Skan      if (cond_or == DOM_CC_X_AND_Y)
657390075Sobrien	return CC_DEQmode;
657490075Sobrien
657590075Sobrien      switch (cond2)
657690075Sobrien	{
6577169689Skan	case EQ: return CC_DEQmode;
657890075Sobrien	case LE: return CC_DLEmode;
657990075Sobrien	case LEU: return CC_DLEUmode;
658090075Sobrien	case GE: return CC_DGEmode;
658190075Sobrien	case GEU: return CC_DGEUmode;
6582169689Skan	default: gcc_unreachable ();
658390075Sobrien	}
658490075Sobrien
658590075Sobrien    case LT:
6586169689Skan      if (cond_or == DOM_CC_X_AND_Y)
658790075Sobrien	return CC_DLTmode;
658890075Sobrien
6589169689Skan      switch (cond2)
6590169689Skan	{
6591169689Skan	case  LT:
6592169689Skan	    return CC_DLTmode;
6593169689Skan	case LE:
6594169689Skan	  return CC_DLEmode;
6595169689Skan	case NE:
6596169689Skan	  return CC_DNEmode;
6597169689Skan	default:
6598169689Skan	  gcc_unreachable ();
6599169689Skan	}
6600169689Skan
660190075Sobrien    case GT:
6602169689Skan      if (cond_or == DOM_CC_X_AND_Y)
660390075Sobrien	return CC_DGTmode;
6604169689Skan
6605169689Skan      switch (cond2)
6606169689Skan	{
6607169689Skan	case GT:
6608169689Skan	  return CC_DGTmode;
6609169689Skan	case GE:
6610169689Skan	  return CC_DGEmode;
6611169689Skan	case NE:
6612169689Skan	  return CC_DNEmode;
6613169689Skan	default:
6614169689Skan	  gcc_unreachable ();
6615169689Skan	}
6616169689Skan
661790075Sobrien    case LTU:
6618169689Skan      if (cond_or == DOM_CC_X_AND_Y)
661990075Sobrien	return CC_DLTUmode;
662090075Sobrien
6621169689Skan      switch (cond2)
6622169689Skan	{
6623169689Skan	case LTU:
6624169689Skan	  return CC_DLTUmode;
6625169689Skan	case LEU:
6626169689Skan	  return CC_DLEUmode;
6627169689Skan	case NE:
6628169689Skan	  return CC_DNEmode;
6629169689Skan	default:
6630169689Skan	  gcc_unreachable ();
6631169689Skan	}
6632169689Skan
663390075Sobrien    case GTU:
6634169689Skan      if (cond_or == DOM_CC_X_AND_Y)
663590075Sobrien	return CC_DGTUmode;
663690075Sobrien
6637169689Skan      switch (cond2)
6638169689Skan	{
6639169689Skan	case GTU:
6640169689Skan	  return CC_DGTUmode;
6641169689Skan	case GEU:
6642169689Skan	  return CC_DGEUmode;
6643169689Skan	case NE:
6644169689Skan	  return CC_DNEmode;
6645169689Skan	default:
6646169689Skan	  gcc_unreachable ();
6647169689Skan	}
6648169689Skan
664990075Sobrien    /* The remaining cases only occur when both comparisons are the
665090075Sobrien       same.  */
665190075Sobrien    case NE:
6652169689Skan      gcc_assert (cond1 == cond2);
665390075Sobrien      return CC_DNEmode;
665490075Sobrien
665590075Sobrien    case LE:
6656169689Skan      gcc_assert (cond1 == cond2);
665790075Sobrien      return CC_DLEmode;
665890075Sobrien
665990075Sobrien    case GE:
6660169689Skan      gcc_assert (cond1 == cond2);
666190075Sobrien      return CC_DGEmode;
666290075Sobrien
666390075Sobrien    case LEU:
6664169689Skan      gcc_assert (cond1 == cond2);
666590075Sobrien      return CC_DLEUmode;
666690075Sobrien
666790075Sobrien    case GEU:
6668169689Skan      gcc_assert (cond1 == cond2);
666990075Sobrien      return CC_DGEUmode;
667090075Sobrien
667190075Sobrien    default:
6672169689Skan      gcc_unreachable ();
667390075Sobrien    }
667490075Sobrien}
667590075Sobrien
667690075Sobrienenum machine_mode
6677132718Skanarm_select_cc_mode (enum rtx_code op, rtx x, rtx y)
667890075Sobrien{
667990075Sobrien  /* All floating point compares return CCFP if it is an equality
668090075Sobrien     comparison, and CCFPE otherwise.  */
668190075Sobrien  if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
668290075Sobrien    {
668390075Sobrien      switch (op)
668490075Sobrien	{
668590075Sobrien	case EQ:
668690075Sobrien	case NE:
668790075Sobrien	case UNORDERED:
668890075Sobrien	case ORDERED:
668990075Sobrien	case UNLT:
669090075Sobrien	case UNLE:
669190075Sobrien	case UNGT:
669290075Sobrien	case UNGE:
669390075Sobrien	case UNEQ:
669490075Sobrien	case LTGT:
669590075Sobrien	  return CCFPmode;
669690075Sobrien
669790075Sobrien	case LT:
669890075Sobrien	case LE:
669990075Sobrien	case GT:
670090075Sobrien	case GE:
6701169689Skan	  if (TARGET_HARD_FLOAT && TARGET_MAVERICK)
6702132718Skan	    return CCFPmode;
670390075Sobrien	  return CCFPEmode;
670490075Sobrien
670590075Sobrien	default:
6706169689Skan	  gcc_unreachable ();
670790075Sobrien	}
670890075Sobrien    }
6709169689Skan
671090075Sobrien  /* A compare with a shifted operand.  Because of canonicalization, the
671190075Sobrien     comparison will have to be swapped when we emit the assembler.  */
671290075Sobrien  if (GET_MODE (y) == SImode && GET_CODE (y) == REG
671390075Sobrien      && (GET_CODE (x) == ASHIFT || GET_CODE (x) == ASHIFTRT
671490075Sobrien	  || GET_CODE (x) == LSHIFTRT || GET_CODE (x) == ROTATE
671590075Sobrien	  || GET_CODE (x) == ROTATERT))
671690075Sobrien    return CC_SWPmode;
671790075Sobrien
6718169689Skan  /* This operation is performed swapped, but since we only rely on the Z
6719169689Skan     flag we don't need an additional mode.  */
6720169689Skan  if (GET_MODE (y) == SImode && REG_P (y)
6721169689Skan      && GET_CODE (x) == NEG
6722169689Skan      && (op ==	EQ || op == NE))
6723169689Skan    return CC_Zmode;
6724169689Skan
6725169689Skan  /* This is a special case that is used by combine to allow a
672690075Sobrien     comparison of a shifted byte load to be split into a zero-extend
672790075Sobrien     followed by a comparison of the shifted integer (only valid for
672890075Sobrien     equalities and unsigned inequalities).  */
672990075Sobrien  if (GET_MODE (x) == SImode
673090075Sobrien      && GET_CODE (x) == ASHIFT
673190075Sobrien      && GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) == 24
673290075Sobrien      && GET_CODE (XEXP (x, 0)) == SUBREG
673390075Sobrien      && GET_CODE (SUBREG_REG (XEXP (x, 0))) == MEM
673490075Sobrien      && GET_MODE (SUBREG_REG (XEXP (x, 0))) == QImode
673590075Sobrien      && (op == EQ || op == NE
673690075Sobrien	  || op == GEU || op == GTU || op == LTU || op == LEU)
673790075Sobrien      && GET_CODE (y) == CONST_INT)
673890075Sobrien    return CC_Zmode;
673990075Sobrien
674090075Sobrien  /* A construct for a conditional compare, if the false arm contains
674190075Sobrien     0, then both conditions must be true, otherwise either condition
674290075Sobrien     must be true.  Not all conditions are possible, so CCmode is
674390075Sobrien     returned if it can't be done.  */
674490075Sobrien  if (GET_CODE (x) == IF_THEN_ELSE
674590075Sobrien      && (XEXP (x, 2) == const0_rtx
674690075Sobrien	  || XEXP (x, 2) == const1_rtx)
6747169689Skan      && COMPARISON_P (XEXP (x, 0))
6748169689Skan      && COMPARISON_P (XEXP (x, 1)))
6749169689Skan    return arm_select_dominance_cc_mode (XEXP (x, 0), XEXP (x, 1),
6750132718Skan					 INTVAL (XEXP (x, 2)));
675190075Sobrien
675290075Sobrien  /* Alternate canonicalizations of the above.  These are somewhat cleaner.  */
675390075Sobrien  if (GET_CODE (x) == AND
6754169689Skan      && COMPARISON_P (XEXP (x, 0))
6755169689Skan      && COMPARISON_P (XEXP (x, 1)))
6756132718Skan    return arm_select_dominance_cc_mode (XEXP (x, 0), XEXP (x, 1),
6757132718Skan					 DOM_CC_X_AND_Y);
675890075Sobrien
675990075Sobrien  if (GET_CODE (x) == IOR
6760169689Skan      && COMPARISON_P (XEXP (x, 0))
6761169689Skan      && COMPARISON_P (XEXP (x, 1)))
6762132718Skan    return arm_select_dominance_cc_mode (XEXP (x, 0), XEXP (x, 1),
6763132718Skan					 DOM_CC_X_OR_Y);
676490075Sobrien
6765132718Skan  /* An operation (on Thumb) where we want to test for a single bit.
6766132718Skan     This is done by shifting that bit up into the top bit of a
6767132718Skan     scratch register; we can then branch on the sign bit.  */
6768132718Skan  if (TARGET_THUMB
6769132718Skan      && GET_MODE (x) == SImode
6770132718Skan      && (op == EQ || op == NE)
6771169689Skan      && GET_CODE (x) == ZERO_EXTRACT
6772169689Skan      && XEXP (x, 1) == const1_rtx)
6773132718Skan    return CC_Nmode;
6774132718Skan
677590075Sobrien  /* An operation that sets the condition codes as a side-effect, the
677690075Sobrien     V flag is not set correctly, so we can only use comparisons where
677790075Sobrien     this doesn't matter.  (For LT and GE we can use "mi" and "pl"
6778132718Skan     instead.)  */
677990075Sobrien  if (GET_MODE (x) == SImode
678090075Sobrien      && y == const0_rtx
678190075Sobrien      && (op == EQ || op == NE || op == LT || op == GE)
678290075Sobrien      && (GET_CODE (x) == PLUS || GET_CODE (x) == MINUS
678390075Sobrien	  || GET_CODE (x) == AND || GET_CODE (x) == IOR
678490075Sobrien	  || GET_CODE (x) == XOR || GET_CODE (x) == MULT
678590075Sobrien	  || GET_CODE (x) == NOT || GET_CODE (x) == NEG
678690075Sobrien	  || GET_CODE (x) == LSHIFTRT
678790075Sobrien	  || GET_CODE (x) == ASHIFT || GET_CODE (x) == ASHIFTRT
6788132718Skan	  || GET_CODE (x) == ROTATERT
6789132718Skan	  || (TARGET_ARM && GET_CODE (x) == ZERO_EXTRACT)))
679090075Sobrien    return CC_NOOVmode;
679190075Sobrien
679290075Sobrien  if (GET_MODE (x) == QImode && (op == EQ || op == NE))
679390075Sobrien    return CC_Zmode;
679490075Sobrien
679590075Sobrien  if (GET_MODE (x) == SImode && (op == LTU || op == GEU)
679690075Sobrien      && GET_CODE (x) == PLUS
679790075Sobrien      && (rtx_equal_p (XEXP (x, 0), y) || rtx_equal_p (XEXP (x, 1), y)))
679890075Sobrien    return CC_Cmode;
679990075Sobrien
680090075Sobrien  return CCmode;
680190075Sobrien}
680290075Sobrien
680390075Sobrien/* X and Y are two things to compare using CODE.  Emit the compare insn and
680490075Sobrien   return the rtx for register 0 in the proper mode.  FP means this is a
680590075Sobrien   floating point compare: I don't think that it is needed on the arm.  */
680690075Sobrienrtx
6807132718Skanarm_gen_compare_reg (enum rtx_code code, rtx x, rtx y)
680890075Sobrien{
680990075Sobrien  enum machine_mode mode = SELECT_CC_MODE (code, x, y);
681090075Sobrien  rtx cc_reg = gen_rtx_REG (mode, CC_REGNUM);
681190075Sobrien
6812169689Skan  emit_set_insn (cc_reg, gen_rtx_COMPARE (mode, x, y));
681390075Sobrien
681490075Sobrien  return cc_reg;
681590075Sobrien}
681690075Sobrien
6817117395Skan/* Generate a sequence of insns that will generate the correct return
6818117395Skan   address mask depending on the physical architecture that the program
6819117395Skan   is running on.  */
6820117395Skanrtx
6821132718Skanarm_gen_return_addr_mask (void)
6822117395Skan{
6823117395Skan  rtx reg = gen_reg_rtx (Pmode);
6824117395Skan
6825117395Skan  emit_insn (gen_return_addr_mask (reg));
6826117395Skan  return reg;
6827117395Skan}
6828117395Skan
682990075Sobrienvoid
6830132718Skanarm_reload_in_hi (rtx *operands)
683190075Sobrien{
683290075Sobrien  rtx ref = operands[1];
683390075Sobrien  rtx base, scratch;
683490075Sobrien  HOST_WIDE_INT offset = 0;
683590075Sobrien
683690075Sobrien  if (GET_CODE (ref) == SUBREG)
683790075Sobrien    {
683890075Sobrien      offset = SUBREG_BYTE (ref);
683990075Sobrien      ref = SUBREG_REG (ref);
684090075Sobrien    }
684190075Sobrien
684290075Sobrien  if (GET_CODE (ref) == REG)
684390075Sobrien    {
684490075Sobrien      /* We have a pseudo which has been spilt onto the stack; there
684590075Sobrien	 are two cases here: the first where there is a simple
684690075Sobrien	 stack-slot replacement and a second where the stack-slot is
684790075Sobrien	 out of range, or is used as a subreg.  */
684890075Sobrien      if (reg_equiv_mem[REGNO (ref)])
684990075Sobrien	{
685090075Sobrien	  ref = reg_equiv_mem[REGNO (ref)];
685190075Sobrien	  base = find_replacement (&XEXP (ref, 0));
685290075Sobrien	}
685390075Sobrien      else
685490075Sobrien	/* The slot is out of range, or was dressed up in a SUBREG.  */
685590075Sobrien	base = reg_equiv_address[REGNO (ref)];
685690075Sobrien    }
685790075Sobrien  else
685890075Sobrien    base = find_replacement (&XEXP (ref, 0));
685990075Sobrien
686090075Sobrien  /* Handle the case where the address is too complex to be offset by 1.  */
686190075Sobrien  if (GET_CODE (base) == MINUS
686290075Sobrien      || (GET_CODE (base) == PLUS && GET_CODE (XEXP (base, 1)) != CONST_INT))
686390075Sobrien    {
686490075Sobrien      rtx base_plus = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
686590075Sobrien
6866169689Skan      emit_set_insn (base_plus, base);
686790075Sobrien      base = base_plus;
686890075Sobrien    }
686990075Sobrien  else if (GET_CODE (base) == PLUS)
687090075Sobrien    {
687190075Sobrien      /* The addend must be CONST_INT, or we would have dealt with it above.  */
687290075Sobrien      HOST_WIDE_INT hi, lo;
687390075Sobrien
687490075Sobrien      offset += INTVAL (XEXP (base, 1));
687590075Sobrien      base = XEXP (base, 0);
687690075Sobrien
687790075Sobrien      /* Rework the address into a legal sequence of insns.  */
687890075Sobrien      /* Valid range for lo is -4095 -> 4095 */
687990075Sobrien      lo = (offset >= 0
688090075Sobrien	    ? (offset & 0xfff)
688190075Sobrien	    : -((-offset) & 0xfff));
688290075Sobrien
688390075Sobrien      /* Corner case, if lo is the max offset then we would be out of range
688490075Sobrien	 once we have added the additional 1 below, so bump the msb into the
688590075Sobrien	 pre-loading insn(s).  */
688690075Sobrien      if (lo == 4095)
688790075Sobrien	lo &= 0x7ff;
688890075Sobrien
688990075Sobrien      hi = ((((offset - lo) & (HOST_WIDE_INT) 0xffffffff)
689090075Sobrien	     ^ (HOST_WIDE_INT) 0x80000000)
689190075Sobrien	    - (HOST_WIDE_INT) 0x80000000);
689290075Sobrien
6893169689Skan      gcc_assert (hi + lo == offset);
689490075Sobrien
689590075Sobrien      if (hi != 0)
689690075Sobrien	{
689790075Sobrien	  rtx base_plus = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
689890075Sobrien
689990075Sobrien	  /* Get the base address; addsi3 knows how to handle constants
690090075Sobrien	     that require more than one insn.  */
690190075Sobrien	  emit_insn (gen_addsi3 (base_plus, base, GEN_INT (hi)));
690290075Sobrien	  base = base_plus;
690390075Sobrien	  offset = lo;
690490075Sobrien	}
690590075Sobrien    }
690690075Sobrien
6907117395Skan  /* Operands[2] may overlap operands[0] (though it won't overlap
6908117395Skan     operands[1]), that's why we asked for a DImode reg -- so we can
6909117395Skan     use the bit that does not overlap.  */
6910117395Skan  if (REGNO (operands[2]) == REGNO (operands[0]))
6911117395Skan    scratch = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
6912117395Skan  else
6913117395Skan    scratch = gen_rtx_REG (SImode, REGNO (operands[2]));
6914117395Skan
691590075Sobrien  emit_insn (gen_zero_extendqisi2 (scratch,
691690075Sobrien				   gen_rtx_MEM (QImode,
691790075Sobrien						plus_constant (base,
691890075Sobrien							       offset))));
691990075Sobrien  emit_insn (gen_zero_extendqisi2 (gen_rtx_SUBREG (SImode, operands[0], 0),
6920169689Skan				   gen_rtx_MEM (QImode,
692190075Sobrien						plus_constant (base,
692290075Sobrien							       offset + 1))));
692390075Sobrien  if (!BYTES_BIG_ENDIAN)
6924169689Skan    emit_set_insn (gen_rtx_SUBREG (SImode, operands[0], 0),
6925169689Skan		   gen_rtx_IOR (SImode,
6926169689Skan				gen_rtx_ASHIFT
6927169689Skan				(SImode,
6928169689Skan				 gen_rtx_SUBREG (SImode, operands[0], 0),
6929169689Skan				 GEN_INT (8)),
6930169689Skan				scratch));
693190075Sobrien  else
6932169689Skan    emit_set_insn (gen_rtx_SUBREG (SImode, operands[0], 0),
6933169689Skan		   gen_rtx_IOR (SImode,
6934169689Skan				gen_rtx_ASHIFT (SImode, scratch,
6935169689Skan						GEN_INT (8)),
6936169689Skan				gen_rtx_SUBREG (SImode, operands[0], 0)));
693790075Sobrien}
693890075Sobrien
6939132718Skan/* Handle storing a half-word to memory during reload by synthesizing as two
694090075Sobrien   byte stores.  Take care not to clobber the input values until after we
694190075Sobrien   have moved them somewhere safe.  This code assumes that if the DImode
694290075Sobrien   scratch in operands[2] overlaps either the input value or output address
694390075Sobrien   in some way, then that value must die in this insn (we absolutely need
694490075Sobrien   two scratch registers for some corner cases).  */
694590075Sobrienvoid
6946132718Skanarm_reload_out_hi (rtx *operands)
694790075Sobrien{
694890075Sobrien  rtx ref = operands[0];
694990075Sobrien  rtx outval = operands[1];
695090075Sobrien  rtx base, scratch;
695190075Sobrien  HOST_WIDE_INT offset = 0;
695290075Sobrien
695390075Sobrien  if (GET_CODE (ref) == SUBREG)
695490075Sobrien    {
695590075Sobrien      offset = SUBREG_BYTE (ref);
695690075Sobrien      ref = SUBREG_REG (ref);
695790075Sobrien    }
695890075Sobrien
695990075Sobrien  if (GET_CODE (ref) == REG)
696090075Sobrien    {
696190075Sobrien      /* We have a pseudo which has been spilt onto the stack; there
696290075Sobrien	 are two cases here: the first where there is a simple
696390075Sobrien	 stack-slot replacement and a second where the stack-slot is
696490075Sobrien	 out of range, or is used as a subreg.  */
696590075Sobrien      if (reg_equiv_mem[REGNO (ref)])
696690075Sobrien	{
696790075Sobrien	  ref = reg_equiv_mem[REGNO (ref)];
696890075Sobrien	  base = find_replacement (&XEXP (ref, 0));
696990075Sobrien	}
697090075Sobrien      else
697190075Sobrien	/* The slot is out of range, or was dressed up in a SUBREG.  */
697290075Sobrien	base = reg_equiv_address[REGNO (ref)];
697390075Sobrien    }
697490075Sobrien  else
697590075Sobrien    base = find_replacement (&XEXP (ref, 0));
697690075Sobrien
697790075Sobrien  scratch = gen_rtx_REG (SImode, REGNO (operands[2]));
697890075Sobrien
697990075Sobrien  /* Handle the case where the address is too complex to be offset by 1.  */
698090075Sobrien  if (GET_CODE (base) == MINUS
698190075Sobrien      || (GET_CODE (base) == PLUS && GET_CODE (XEXP (base, 1)) != CONST_INT))
698290075Sobrien    {
698390075Sobrien      rtx base_plus = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
698490075Sobrien
698590075Sobrien      /* Be careful not to destroy OUTVAL.  */
698690075Sobrien      if (reg_overlap_mentioned_p (base_plus, outval))
698790075Sobrien	{
698890075Sobrien	  /* Updating base_plus might destroy outval, see if we can
698990075Sobrien	     swap the scratch and base_plus.  */
699090075Sobrien	  if (!reg_overlap_mentioned_p (scratch, outval))
699190075Sobrien	    {
699290075Sobrien	      rtx tmp = scratch;
699390075Sobrien	      scratch = base_plus;
699490075Sobrien	      base_plus = tmp;
699590075Sobrien	    }
699690075Sobrien	  else
699790075Sobrien	    {
699890075Sobrien	      rtx scratch_hi = gen_rtx_REG (HImode, REGNO (operands[2]));
699990075Sobrien
700090075Sobrien	      /* Be conservative and copy OUTVAL into the scratch now,
700190075Sobrien		 this should only be necessary if outval is a subreg
700290075Sobrien		 of something larger than a word.  */
700390075Sobrien	      /* XXX Might this clobber base?  I can't see how it can,
700490075Sobrien		 since scratch is known to overlap with OUTVAL, and
700590075Sobrien		 must be wider than a word.  */
700690075Sobrien	      emit_insn (gen_movhi (scratch_hi, outval));
700790075Sobrien	      outval = scratch_hi;
700890075Sobrien	    }
700990075Sobrien	}
701090075Sobrien
7011169689Skan      emit_set_insn (base_plus, base);
701290075Sobrien      base = base_plus;
701390075Sobrien    }
701490075Sobrien  else if (GET_CODE (base) == PLUS)
701590075Sobrien    {
701690075Sobrien      /* The addend must be CONST_INT, or we would have dealt with it above.  */
701790075Sobrien      HOST_WIDE_INT hi, lo;
701890075Sobrien
701990075Sobrien      offset += INTVAL (XEXP (base, 1));
702090075Sobrien      base = XEXP (base, 0);
702190075Sobrien
702290075Sobrien      /* Rework the address into a legal sequence of insns.  */
702390075Sobrien      /* Valid range for lo is -4095 -> 4095 */
702490075Sobrien      lo = (offset >= 0
702590075Sobrien	    ? (offset & 0xfff)
702690075Sobrien	    : -((-offset) & 0xfff));
702790075Sobrien
702890075Sobrien      /* Corner case, if lo is the max offset then we would be out of range
702990075Sobrien	 once we have added the additional 1 below, so bump the msb into the
703090075Sobrien	 pre-loading insn(s).  */
703190075Sobrien      if (lo == 4095)
703290075Sobrien	lo &= 0x7ff;
703390075Sobrien
703490075Sobrien      hi = ((((offset - lo) & (HOST_WIDE_INT) 0xffffffff)
703590075Sobrien	     ^ (HOST_WIDE_INT) 0x80000000)
703690075Sobrien	    - (HOST_WIDE_INT) 0x80000000);
703790075Sobrien
7038169689Skan      gcc_assert (hi + lo == offset);
703990075Sobrien
704090075Sobrien      if (hi != 0)
704190075Sobrien	{
704290075Sobrien	  rtx base_plus = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
704390075Sobrien
704490075Sobrien	  /* Be careful not to destroy OUTVAL.  */
704590075Sobrien	  if (reg_overlap_mentioned_p (base_plus, outval))
704690075Sobrien	    {
704790075Sobrien	      /* Updating base_plus might destroy outval, see if we
704890075Sobrien		 can swap the scratch and base_plus.  */
704990075Sobrien	      if (!reg_overlap_mentioned_p (scratch, outval))
705090075Sobrien		{
705190075Sobrien		  rtx tmp = scratch;
705290075Sobrien		  scratch = base_plus;
705390075Sobrien		  base_plus = tmp;
705490075Sobrien		}
705590075Sobrien	      else
705690075Sobrien		{
705790075Sobrien		  rtx scratch_hi = gen_rtx_REG (HImode, REGNO (operands[2]));
705890075Sobrien
705990075Sobrien		  /* Be conservative and copy outval into scratch now,
706090075Sobrien		     this should only be necessary if outval is a
706190075Sobrien		     subreg of something larger than a word.  */
706290075Sobrien		  /* XXX Might this clobber base?  I can't see how it
706390075Sobrien		     can, since scratch is known to overlap with
706490075Sobrien		     outval.  */
706590075Sobrien		  emit_insn (gen_movhi (scratch_hi, outval));
706690075Sobrien		  outval = scratch_hi;
706790075Sobrien		}
706890075Sobrien	    }
706990075Sobrien
707090075Sobrien	  /* Get the base address; addsi3 knows how to handle constants
707190075Sobrien	     that require more than one insn.  */
707290075Sobrien	  emit_insn (gen_addsi3 (base_plus, base, GEN_INT (hi)));
707390075Sobrien	  base = base_plus;
707490075Sobrien	  offset = lo;
707590075Sobrien	}
707690075Sobrien    }
707790075Sobrien
707890075Sobrien  if (BYTES_BIG_ENDIAN)
707990075Sobrien    {
7080169689Skan      emit_insn (gen_movqi (gen_rtx_MEM (QImode,
708190075Sobrien					 plus_constant (base, offset + 1)),
7082102780Skan			    gen_lowpart (QImode, outval)));
708390075Sobrien      emit_insn (gen_lshrsi3 (scratch,
708490075Sobrien			      gen_rtx_SUBREG (SImode, outval, 0),
708590075Sobrien			      GEN_INT (8)));
708690075Sobrien      emit_insn (gen_movqi (gen_rtx_MEM (QImode, plus_constant (base, offset)),
7087102780Skan			    gen_lowpart (QImode, scratch)));
708890075Sobrien    }
708990075Sobrien  else
709090075Sobrien    {
709190075Sobrien      emit_insn (gen_movqi (gen_rtx_MEM (QImode, plus_constant (base, offset)),
7092102780Skan			    gen_lowpart (QImode, outval)));
709390075Sobrien      emit_insn (gen_lshrsi3 (scratch,
709490075Sobrien			      gen_rtx_SUBREG (SImode, outval, 0),
709590075Sobrien			      GEN_INT (8)));
709690075Sobrien      emit_insn (gen_movqi (gen_rtx_MEM (QImode,
709790075Sobrien					 plus_constant (base, offset + 1)),
7098102780Skan			    gen_lowpart (QImode, scratch)));
709990075Sobrien    }
710090075Sobrien}
7101169689Skan
7102169689Skan/* Return true if a type must be passed in memory. For AAPCS, small aggregates
7103169689Skan   (padded to the size of a word) should be passed in a register.  */
7104169689Skan
7105169689Skanstatic bool
7106169689Skanarm_must_pass_in_stack (enum machine_mode mode, tree type)
7107169689Skan{
7108169689Skan  if (TARGET_AAPCS_BASED)
7109169689Skan    return must_pass_in_stack_var_size (mode, type);
7110169689Skan  else
7111169689Skan    return must_pass_in_stack_var_size_or_pad (mode, type);
7112169689Skan}
7113169689Skan
7114169689Skan
7115169689Skan/* For use by FUNCTION_ARG_PADDING (MODE, TYPE).
7116169689Skan   Return true if an argument passed on the stack should be padded upwards,
7117169689Skan   i.e. if the least-significant byte has useful data.
7118169689Skan   For legacy APCS ABIs we use the default.  For AAPCS based ABIs small
7119169689Skan   aggregate types are placed in the lowest memory address.  */
7120169689Skan
7121169689Skanbool
7122169689Skanarm_pad_arg_upward (enum machine_mode mode, tree type)
7123169689Skan{
7124169689Skan  if (!TARGET_AAPCS_BASED)
7125169689Skan    return DEFAULT_FUNCTION_ARG_PADDING(mode, type) == upward;
7126169689Skan
7127169689Skan  if (type && BYTES_BIG_ENDIAN && INTEGRAL_TYPE_P (type))
7128169689Skan    return false;
7129169689Skan
7130169689Skan  return true;
7131169689Skan}
7132169689Skan
7133169689Skan
7134169689Skan/* Similarly, for use by BLOCK_REG_PADDING (MODE, TYPE, FIRST).
7135169689Skan   For non-AAPCS, return !BYTES_BIG_ENDIAN if the least significant
7136169689Skan   byte of the register has useful data, and return the opposite if the
7137169689Skan   most significant byte does.
7138169689Skan   For AAPCS, small aggregates and small complex types are always padded
7139169689Skan   upwards.  */
7140169689Skan
7141169689Skanbool
7142169689Skanarm_pad_reg_upward (enum machine_mode mode ATTRIBUTE_UNUSED,
7143169689Skan                    tree type, int first ATTRIBUTE_UNUSED)
7144169689Skan{
7145169689Skan  if (TARGET_AAPCS_BASED
7146169689Skan      && BYTES_BIG_ENDIAN
7147169689Skan      && (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == COMPLEX_TYPE)
7148169689Skan      && int_size_in_bytes (type) <= 4)
7149169689Skan    return true;
7150169689Skan
7151169689Skan  /* Otherwise, use default padding.  */
7152169689Skan  return !BYTES_BIG_ENDIAN;
7153169689Skan}
7154169689Skan
715590075Sobrien
715690075Sobrien/* Print a symbolic form of X to the debug file, F.  */
715790075Sobrienstatic void
7158132718Skanarm_print_value (FILE *f, rtx x)
715990075Sobrien{
716090075Sobrien  switch (GET_CODE (x))
716190075Sobrien    {
716290075Sobrien    case CONST_INT:
716390075Sobrien      fprintf (f, HOST_WIDE_INT_PRINT_HEX, INTVAL (x));
716490075Sobrien      return;
716590075Sobrien
716690075Sobrien    case CONST_DOUBLE:
716790075Sobrien      fprintf (f, "<0x%lx,0x%lx>", (long)XWINT (x, 2), (long)XWINT (x, 3));
716890075Sobrien      return;
716990075Sobrien
7170132718Skan    case CONST_VECTOR:
7171132718Skan      {
7172132718Skan	int i;
7173132718Skan
7174132718Skan	fprintf (f, "<");
7175132718Skan	for (i = 0; i < CONST_VECTOR_NUNITS (x); i++)
7176132718Skan	  {
7177132718Skan	    fprintf (f, HOST_WIDE_INT_PRINT_HEX, INTVAL (CONST_VECTOR_ELT (x, i)));
7178132718Skan	    if (i < (CONST_VECTOR_NUNITS (x) - 1))
7179132718Skan	      fputc (',', f);
7180132718Skan	  }
7181132718Skan	fprintf (f, ">");
7182132718Skan      }
7183132718Skan      return;
7184132718Skan
718590075Sobrien    case CONST_STRING:
718690075Sobrien      fprintf (f, "\"%s\"", XSTR (x, 0));
718790075Sobrien      return;
718890075Sobrien
718990075Sobrien    case SYMBOL_REF:
719090075Sobrien      fprintf (f, "`%s'", XSTR (x, 0));
719190075Sobrien      return;
719290075Sobrien
719390075Sobrien    case LABEL_REF:
719490075Sobrien      fprintf (f, "L%d", INSN_UID (XEXP (x, 0)));
719590075Sobrien      return;
719690075Sobrien
719790075Sobrien    case CONST:
719890075Sobrien      arm_print_value (f, XEXP (x, 0));
719990075Sobrien      return;
720090075Sobrien
720190075Sobrien    case PLUS:
720290075Sobrien      arm_print_value (f, XEXP (x, 0));
720390075Sobrien      fprintf (f, "+");
720490075Sobrien      arm_print_value (f, XEXP (x, 1));
720590075Sobrien      return;
720690075Sobrien
720790075Sobrien    case PC:
720890075Sobrien      fprintf (f, "pc");
720990075Sobrien      return;
721090075Sobrien
721190075Sobrien    default:
721290075Sobrien      fprintf (f, "????");
721390075Sobrien      return;
721490075Sobrien    }
721590075Sobrien}
721690075Sobrien
721790075Sobrien/* Routines for manipulation of the constant pool.  */
721890075Sobrien
721990075Sobrien/* Arm instructions cannot load a large constant directly into a
722090075Sobrien   register; they have to come from a pc relative load.  The constant
722190075Sobrien   must therefore be placed in the addressable range of the pc
722290075Sobrien   relative load.  Depending on the precise pc relative load
722390075Sobrien   instruction the range is somewhere between 256 bytes and 4k.  This
722490075Sobrien   means that we often have to dump a constant inside a function, and
722590075Sobrien   generate code to branch around it.
722690075Sobrien
722790075Sobrien   It is important to minimize this, since the branches will slow
722890075Sobrien   things down and make the code larger.
722990075Sobrien
723090075Sobrien   Normally we can hide the table after an existing unconditional
723190075Sobrien   branch so that there is no interruption of the flow, but in the
723290075Sobrien   worst case the code looks like this:
723390075Sobrien
723490075Sobrien	ldr	rn, L1
723590075Sobrien	...
723690075Sobrien	b	L2
723790075Sobrien	align
723890075Sobrien	L1:	.long value
723990075Sobrien	L2:
724090075Sobrien	...
724190075Sobrien
724290075Sobrien	ldr	rn, L3
724390075Sobrien	...
724490075Sobrien	b	L4
724590075Sobrien	align
724690075Sobrien	L3:	.long value
724790075Sobrien	L4:
724890075Sobrien	...
724990075Sobrien
725090075Sobrien   We fix this by performing a scan after scheduling, which notices
725190075Sobrien   which instructions need to have their operands fetched from the
725290075Sobrien   constant table and builds the table.
725390075Sobrien
725490075Sobrien   The algorithm starts by building a table of all the constants that
725590075Sobrien   need fixing up and all the natural barriers in the function (places
725690075Sobrien   where a constant table can be dropped without breaking the flow).
725790075Sobrien   For each fixup we note how far the pc-relative replacement will be
725890075Sobrien   able to reach and the offset of the instruction into the function.
725990075Sobrien
726090075Sobrien   Having built the table we then group the fixes together to form
726190075Sobrien   tables that are as large as possible (subject to addressing
726290075Sobrien   constraints) and emit each table of constants after the last
726390075Sobrien   barrier that is within range of all the instructions in the group.
726490075Sobrien   If a group does not contain a barrier, then we forcibly create one
726590075Sobrien   by inserting a jump instruction into the flow.  Once the table has
726690075Sobrien   been inserted, the insns are then modified to reference the
726790075Sobrien   relevant entry in the pool.
726890075Sobrien
726990075Sobrien   Possible enhancements to the algorithm (not implemented) are:
727090075Sobrien
727190075Sobrien   1) For some processors and object formats, there may be benefit in
727290075Sobrien   aligning the pools to the start of cache lines; this alignment
727390075Sobrien   would need to be taken into account when calculating addressability
727490075Sobrien   of a pool.  */
727590075Sobrien
727690075Sobrien/* These typedefs are located at the start of this file, so that
727790075Sobrien   they can be used in the prototypes there.  This comment is to
727890075Sobrien   remind readers of that fact so that the following structures
727990075Sobrien   can be understood more easily.
728090075Sobrien
728190075Sobrien     typedef struct minipool_node    Mnode;
728290075Sobrien     typedef struct minipool_fixup   Mfix;  */
728390075Sobrien
728490075Sobrienstruct minipool_node
728590075Sobrien{
728690075Sobrien  /* Doubly linked chain of entries.  */
728790075Sobrien  Mnode * next;
728890075Sobrien  Mnode * prev;
728990075Sobrien  /* The maximum offset into the code that this entry can be placed.  While
729090075Sobrien     pushing fixes for forward references, all entries are sorted in order
729190075Sobrien     of increasing max_address.  */
729290075Sobrien  HOST_WIDE_INT max_address;
729390075Sobrien  /* Similarly for an entry inserted for a backwards ref.  */
729490075Sobrien  HOST_WIDE_INT min_address;
729590075Sobrien  /* The number of fixes referencing this entry.  This can become zero
729690075Sobrien     if we "unpush" an entry.  In this case we ignore the entry when we
729790075Sobrien     come to emit the code.  */
729890075Sobrien  int refcount;
729990075Sobrien  /* The offset from the start of the minipool.  */
730090075Sobrien  HOST_WIDE_INT offset;
730190075Sobrien  /* The value in table.  */
730290075Sobrien  rtx value;
730390075Sobrien  /* The mode of value.  */
730490075Sobrien  enum machine_mode mode;
7305132718Skan  /* The size of the value.  With iWMMXt enabled
7306132718Skan     sizes > 4 also imply an alignment of 8-bytes.  */
730790075Sobrien  int fix_size;
730890075Sobrien};
730990075Sobrien
731090075Sobrienstruct minipool_fixup
731190075Sobrien{
731290075Sobrien  Mfix *            next;
731390075Sobrien  rtx               insn;
731490075Sobrien  HOST_WIDE_INT     address;
731590075Sobrien  rtx *             loc;
731690075Sobrien  enum machine_mode mode;
731790075Sobrien  int               fix_size;
731890075Sobrien  rtx               value;
731990075Sobrien  Mnode *           minipool;
732090075Sobrien  HOST_WIDE_INT     forwards;
732190075Sobrien  HOST_WIDE_INT     backwards;
732290075Sobrien};
732390075Sobrien
732490075Sobrien/* Fixes less than a word need padding out to a word boundary.  */
732590075Sobrien#define MINIPOOL_FIX_SIZE(mode) \
732690075Sobrien  (GET_MODE_SIZE ((mode)) >= 4 ? GET_MODE_SIZE ((mode)) : 4)
732790075Sobrien
732890075Sobrienstatic Mnode *	minipool_vector_head;
732990075Sobrienstatic Mnode *	minipool_vector_tail;
733090075Sobrienstatic rtx	minipool_vector_label;
7331169689Skanstatic int	minipool_pad;
733290075Sobrien
733390075Sobrien/* The linked list of all minipool fixes required for this function.  */
733490075SobrienMfix * 		minipool_fix_head;
733590075SobrienMfix * 		minipool_fix_tail;
733690075Sobrien/* The fix entry for the current minipool, once it has been placed.  */
733790075SobrienMfix *		minipool_barrier;
733890075Sobrien
733990075Sobrien/* Determines if INSN is the start of a jump table.  Returns the end
734090075Sobrien   of the TABLE or NULL_RTX.  */
734190075Sobrienstatic rtx
7342132718Skanis_jump_table (rtx insn)
734390075Sobrien{
734490075Sobrien  rtx table;
7345169689Skan
734690075Sobrien  if (GET_CODE (insn) == JUMP_INSN
734790075Sobrien      && JUMP_LABEL (insn) != NULL
734890075Sobrien      && ((table = next_real_insn (JUMP_LABEL (insn)))
734990075Sobrien	  == next_real_insn (insn))
735090075Sobrien      && table != NULL
735190075Sobrien      && GET_CODE (table) == JUMP_INSN
735290075Sobrien      && (GET_CODE (PATTERN (table)) == ADDR_VEC
735390075Sobrien	  || GET_CODE (PATTERN (table)) == ADDR_DIFF_VEC))
735490075Sobrien    return table;
735590075Sobrien
735690075Sobrien  return NULL_RTX;
735790075Sobrien}
735890075Sobrien
735996263Sobrien#ifndef JUMP_TABLES_IN_TEXT_SECTION
736096263Sobrien#define JUMP_TABLES_IN_TEXT_SECTION 0
736196263Sobrien#endif
736296263Sobrien
736390075Sobrienstatic HOST_WIDE_INT
7364132718Skanget_jump_table_size (rtx insn)
736590075Sobrien{
736696263Sobrien  /* ADDR_VECs only take room if read-only data does into the text
736796263Sobrien     section.  */
7368169689Skan  if (JUMP_TABLES_IN_TEXT_SECTION || readonly_data_section == text_section)
736996263Sobrien    {
737096263Sobrien      rtx body = PATTERN (insn);
737196263Sobrien      int elt = GET_CODE (body) == ADDR_DIFF_VEC ? 1 : 0;
737290075Sobrien
737396263Sobrien      return GET_MODE_SIZE (GET_MODE (body)) * XVECLEN (body, elt);
737496263Sobrien    }
737596263Sobrien
737696263Sobrien  return 0;
737790075Sobrien}
737890075Sobrien
737990075Sobrien/* Move a minipool fix MP from its current location to before MAX_MP.
738090075Sobrien   If MAX_MP is NULL, then MP doesn't need moving, but the addressing
7381132718Skan   constraints may need updating.  */
738290075Sobrienstatic Mnode *
7383132718Skanmove_minipool_fix_forward_ref (Mnode *mp, Mnode *max_mp,
7384132718Skan			       HOST_WIDE_INT max_address)
738590075Sobrien{
7386169689Skan  /* The code below assumes these are different.  */
7387169689Skan  gcc_assert (mp != max_mp);
738890075Sobrien
738990075Sobrien  if (max_mp == NULL)
739090075Sobrien    {
739190075Sobrien      if (max_address < mp->max_address)
739290075Sobrien	mp->max_address = max_address;
739390075Sobrien    }
739490075Sobrien  else
739590075Sobrien    {
739690075Sobrien      if (max_address > max_mp->max_address - mp->fix_size)
739790075Sobrien	mp->max_address = max_mp->max_address - mp->fix_size;
739890075Sobrien      else
739990075Sobrien	mp->max_address = max_address;
740090075Sobrien
740190075Sobrien      /* Unlink MP from its current position.  Since max_mp is non-null,
740290075Sobrien       mp->prev must be non-null.  */
740390075Sobrien      mp->prev->next = mp->next;
740490075Sobrien      if (mp->next != NULL)
740590075Sobrien	mp->next->prev = mp->prev;
740690075Sobrien      else
740790075Sobrien	minipool_vector_tail = mp->prev;
740890075Sobrien
740990075Sobrien      /* Re-insert it before MAX_MP.  */
741090075Sobrien      mp->next = max_mp;
741190075Sobrien      mp->prev = max_mp->prev;
741290075Sobrien      max_mp->prev = mp;
7413169689Skan
741490075Sobrien      if (mp->prev != NULL)
741590075Sobrien	mp->prev->next = mp;
741690075Sobrien      else
741790075Sobrien	minipool_vector_head = mp;
741890075Sobrien    }
741990075Sobrien
742090075Sobrien  /* Save the new entry.  */
742190075Sobrien  max_mp = mp;
742290075Sobrien
742390075Sobrien  /* Scan over the preceding entries and adjust their addresses as
742490075Sobrien     required.  */
742590075Sobrien  while (mp->prev != NULL
742690075Sobrien	 && mp->prev->max_address > mp->max_address - mp->prev->fix_size)
742790075Sobrien    {
742890075Sobrien      mp->prev->max_address = mp->max_address - mp->prev->fix_size;
742990075Sobrien      mp = mp->prev;
743090075Sobrien    }
743190075Sobrien
743290075Sobrien  return max_mp;
743390075Sobrien}
743490075Sobrien
743590075Sobrien/* Add a constant to the minipool for a forward reference.  Returns the
743690075Sobrien   node added or NULL if the constant will not fit in this pool.  */
743790075Sobrienstatic Mnode *
7438132718Skanadd_minipool_forward_ref (Mfix *fix)
743990075Sobrien{
744090075Sobrien  /* If set, max_mp is the first pool_entry that has a lower
744190075Sobrien     constraint than the one we are trying to add.  */
744290075Sobrien  Mnode *       max_mp = NULL;
7443169689Skan  HOST_WIDE_INT max_address = fix->address + fix->forwards - minipool_pad;
744490075Sobrien  Mnode *       mp;
7445169689Skan
7446169689Skan  /* If the minipool starts before the end of FIX->INSN then this FIX
7447169689Skan     can not be placed into the current pool.  Furthermore, adding the
7448169689Skan     new constant pool entry may cause the pool to start FIX_SIZE bytes
7449169689Skan     earlier.  */
745090075Sobrien  if (minipool_vector_head &&
7451169689Skan      (fix->address + get_attr_length (fix->insn)
7452169689Skan       >= minipool_vector_head->max_address - fix->fix_size))
745390075Sobrien    return NULL;
745490075Sobrien
745590075Sobrien  /* Scan the pool to see if a constant with the same value has
745690075Sobrien     already been added.  While we are doing this, also note the
745790075Sobrien     location where we must insert the constant if it doesn't already
745890075Sobrien     exist.  */
745990075Sobrien  for (mp = minipool_vector_head; mp != NULL; mp = mp->next)
746090075Sobrien    {
746190075Sobrien      if (GET_CODE (fix->value) == GET_CODE (mp->value)
746290075Sobrien	  && fix->mode == mp->mode
746390075Sobrien	  && (GET_CODE (fix->value) != CODE_LABEL
746490075Sobrien	      || (CODE_LABEL_NUMBER (fix->value)
746590075Sobrien		  == CODE_LABEL_NUMBER (mp->value)))
746690075Sobrien	  && rtx_equal_p (fix->value, mp->value))
746790075Sobrien	{
746890075Sobrien	  /* More than one fix references this entry.  */
746990075Sobrien	  mp->refcount++;
747090075Sobrien	  return move_minipool_fix_forward_ref (mp, max_mp, max_address);
747190075Sobrien	}
747290075Sobrien
747390075Sobrien      /* Note the insertion point if necessary.  */
747490075Sobrien      if (max_mp == NULL
747590075Sobrien	  && mp->max_address > max_address)
747690075Sobrien	max_mp = mp;
7477132718Skan
7478132718Skan      /* If we are inserting an 8-bytes aligned quantity and
7479132718Skan	 we have not already found an insertion point, then
7480132718Skan	 make sure that all such 8-byte aligned quantities are
7481132718Skan	 placed at the start of the pool.  */
7482169689Skan      if (ARM_DOUBLEWORD_ALIGN
7483132718Skan	  && max_mp == NULL
7484132718Skan	  && fix->fix_size == 8
7485132718Skan	  && mp->fix_size != 8)
7486132718Skan	{
7487132718Skan	  max_mp = mp;
7488132718Skan	  max_address = mp->max_address;
7489132718Skan	}
749090075Sobrien    }
749190075Sobrien
749290075Sobrien  /* The value is not currently in the minipool, so we need to create
749390075Sobrien     a new entry for it.  If MAX_MP is NULL, the entry will be put on
749490075Sobrien     the end of the list since the placement is less constrained than
749590075Sobrien     any existing entry.  Otherwise, we insert the new fix before
7496132718Skan     MAX_MP and, if necessary, adjust the constraints on the other
749790075Sobrien     entries.  */
7498169689Skan  mp = XNEW (Mnode);
749990075Sobrien  mp->fix_size = fix->fix_size;
750090075Sobrien  mp->mode = fix->mode;
750190075Sobrien  mp->value = fix->value;
750290075Sobrien  mp->refcount = 1;
750390075Sobrien  /* Not yet required for a backwards ref.  */
750490075Sobrien  mp->min_address = -65536;
750590075Sobrien
750690075Sobrien  if (max_mp == NULL)
750790075Sobrien    {
750890075Sobrien      mp->max_address = max_address;
750990075Sobrien      mp->next = NULL;
751090075Sobrien      mp->prev = minipool_vector_tail;
751190075Sobrien
751290075Sobrien      if (mp->prev == NULL)
751390075Sobrien	{
751490075Sobrien	  minipool_vector_head = mp;
751590075Sobrien	  minipool_vector_label = gen_label_rtx ();
751690075Sobrien	}
751790075Sobrien      else
751890075Sobrien	mp->prev->next = mp;
751990075Sobrien
752090075Sobrien      minipool_vector_tail = mp;
752190075Sobrien    }
752290075Sobrien  else
752390075Sobrien    {
752490075Sobrien      if (max_address > max_mp->max_address - mp->fix_size)
752590075Sobrien	mp->max_address = max_mp->max_address - mp->fix_size;
752690075Sobrien      else
752790075Sobrien	mp->max_address = max_address;
752890075Sobrien
752990075Sobrien      mp->next = max_mp;
753090075Sobrien      mp->prev = max_mp->prev;
753190075Sobrien      max_mp->prev = mp;
753290075Sobrien      if (mp->prev != NULL)
753390075Sobrien	mp->prev->next = mp;
753490075Sobrien      else
753590075Sobrien	minipool_vector_head = mp;
753690075Sobrien    }
753790075Sobrien
753890075Sobrien  /* Save the new entry.  */
753990075Sobrien  max_mp = mp;
754090075Sobrien
754190075Sobrien  /* Scan over the preceding entries and adjust their addresses as
754290075Sobrien     required.  */
754390075Sobrien  while (mp->prev != NULL
754490075Sobrien	 && mp->prev->max_address > mp->max_address - mp->prev->fix_size)
754590075Sobrien    {
754690075Sobrien      mp->prev->max_address = mp->max_address - mp->prev->fix_size;
754790075Sobrien      mp = mp->prev;
754890075Sobrien    }
754990075Sobrien
755090075Sobrien  return max_mp;
755190075Sobrien}
755290075Sobrien
755390075Sobrienstatic Mnode *
7554132718Skanmove_minipool_fix_backward_ref (Mnode *mp, Mnode *min_mp,
7555132718Skan				HOST_WIDE_INT  min_address)
755690075Sobrien{
755790075Sobrien  HOST_WIDE_INT offset;
755890075Sobrien
7559169689Skan  /* The code below assumes these are different.  */
7560169689Skan  gcc_assert (mp != min_mp);
756190075Sobrien
756290075Sobrien  if (min_mp == NULL)
756390075Sobrien    {
756490075Sobrien      if (min_address > mp->min_address)
756590075Sobrien	mp->min_address = min_address;
756690075Sobrien    }
756790075Sobrien  else
756890075Sobrien    {
756990075Sobrien      /* We will adjust this below if it is too loose.  */
757090075Sobrien      mp->min_address = min_address;
757190075Sobrien
757290075Sobrien      /* Unlink MP from its current position.  Since min_mp is non-null,
757390075Sobrien	 mp->next must be non-null.  */
757490075Sobrien      mp->next->prev = mp->prev;
757590075Sobrien      if (mp->prev != NULL)
757690075Sobrien	mp->prev->next = mp->next;
757790075Sobrien      else
757890075Sobrien	minipool_vector_head = mp->next;
757990075Sobrien
758090075Sobrien      /* Reinsert it after MIN_MP.  */
758190075Sobrien      mp->prev = min_mp;
758290075Sobrien      mp->next = min_mp->next;
758390075Sobrien      min_mp->next = mp;
758490075Sobrien      if (mp->next != NULL)
758590075Sobrien	mp->next->prev = mp;
758690075Sobrien      else
758790075Sobrien	minipool_vector_tail = mp;
758890075Sobrien    }
758990075Sobrien
759090075Sobrien  min_mp = mp;
759190075Sobrien
759290075Sobrien  offset = 0;
759390075Sobrien  for (mp = minipool_vector_head; mp != NULL; mp = mp->next)
759490075Sobrien    {
759590075Sobrien      mp->offset = offset;
759690075Sobrien      if (mp->refcount > 0)
759790075Sobrien	offset += mp->fix_size;
759890075Sobrien
759990075Sobrien      if (mp->next && mp->next->min_address < mp->min_address + mp->fix_size)
760090075Sobrien	mp->next->min_address = mp->min_address + mp->fix_size;
760190075Sobrien    }
760290075Sobrien
760390075Sobrien  return min_mp;
7604169689Skan}
760590075Sobrien
760690075Sobrien/* Add a constant to the minipool for a backward reference.  Returns the
7607169689Skan   node added or NULL if the constant will not fit in this pool.
760890075Sobrien
760990075Sobrien   Note that the code for insertion for a backwards reference can be
761090075Sobrien   somewhat confusing because the calculated offsets for each fix do
761190075Sobrien   not take into account the size of the pool (which is still under
761290075Sobrien   construction.  */
761390075Sobrienstatic Mnode *
7614132718Skanadd_minipool_backward_ref (Mfix *fix)
761590075Sobrien{
761690075Sobrien  /* If set, min_mp is the last pool_entry that has a lower constraint
761790075Sobrien     than the one we are trying to add.  */
7618132718Skan  Mnode *min_mp = NULL;
761990075Sobrien  /* This can be negative, since it is only a constraint.  */
762090075Sobrien  HOST_WIDE_INT  min_address = fix->address - fix->backwards;
7621132718Skan  Mnode *mp;
762290075Sobrien
762390075Sobrien  /* If we can't reach the current pool from this insn, or if we can't
762490075Sobrien     insert this entry at the end of the pool without pushing other
762590075Sobrien     fixes out of range, then we don't try.  This ensures that we
762690075Sobrien     can't fail later on.  */
762790075Sobrien  if (min_address >= minipool_barrier->address
762890075Sobrien      || (minipool_vector_tail->min_address + fix->fix_size
762990075Sobrien	  >= minipool_barrier->address))
763090075Sobrien    return NULL;
763190075Sobrien
763290075Sobrien  /* Scan the pool to see if a constant with the same value has
763390075Sobrien     already been added.  While we are doing this, also note the
763490075Sobrien     location where we must insert the constant if it doesn't already
763590075Sobrien     exist.  */
763690075Sobrien  for (mp = minipool_vector_tail; mp != NULL; mp = mp->prev)
763790075Sobrien    {
763890075Sobrien      if (GET_CODE (fix->value) == GET_CODE (mp->value)
763990075Sobrien	  && fix->mode == mp->mode
764090075Sobrien	  && (GET_CODE (fix->value) != CODE_LABEL
764190075Sobrien	      || (CODE_LABEL_NUMBER (fix->value)
764290075Sobrien		  == CODE_LABEL_NUMBER (mp->value)))
764390075Sobrien	  && rtx_equal_p (fix->value, mp->value)
764490075Sobrien	  /* Check that there is enough slack to move this entry to the
764590075Sobrien	     end of the table (this is conservative).  */
7646169689Skan	  && (mp->max_address
7647169689Skan	      > (minipool_barrier->address
764890075Sobrien		 + minipool_vector_tail->offset
764990075Sobrien		 + minipool_vector_tail->fix_size)))
765090075Sobrien	{
765190075Sobrien	  mp->refcount++;
765290075Sobrien	  return move_minipool_fix_backward_ref (mp, min_mp, min_address);
765390075Sobrien	}
765490075Sobrien
765590075Sobrien      if (min_mp != NULL)
765690075Sobrien	mp->min_address += fix->fix_size;
765790075Sobrien      else
765890075Sobrien	{
765990075Sobrien	  /* Note the insertion point if necessary.  */
766090075Sobrien	  if (mp->min_address < min_address)
7661132718Skan	    {
7662132718Skan	      /* For now, we do not allow the insertion of 8-byte alignment
7663132718Skan		 requiring nodes anywhere but at the start of the pool.  */
7664169689Skan	      if (ARM_DOUBLEWORD_ALIGN
7665169689Skan		  && fix->fix_size == 8 && mp->fix_size != 8)
7666132718Skan		return NULL;
7667132718Skan	      else
7668132718Skan		min_mp = mp;
7669132718Skan	    }
767090075Sobrien	  else if (mp->max_address
767190075Sobrien		   < minipool_barrier->address + mp->offset + fix->fix_size)
767290075Sobrien	    {
767390075Sobrien	      /* Inserting before this entry would push the fix beyond
767490075Sobrien		 its maximum address (which can happen if we have
767590075Sobrien		 re-located a forwards fix); force the new fix to come
767690075Sobrien		 after it.  */
767790075Sobrien	      min_mp = mp;
767890075Sobrien	      min_address = mp->min_address + fix->fix_size;
767990075Sobrien	    }
7680132718Skan	  /* If we are inserting an 8-bytes aligned quantity and
7681132718Skan	     we have not already found an insertion point, then
7682132718Skan	     make sure that all such 8-byte aligned quantities are
7683132718Skan	     placed at the start of the pool.  */
7684169689Skan	  else if (ARM_DOUBLEWORD_ALIGN
7685132718Skan		   && min_mp == NULL
7686132718Skan		   && fix->fix_size == 8
7687132718Skan		   && mp->fix_size < 8)
7688132718Skan	    {
7689132718Skan	      min_mp = mp;
7690132718Skan	      min_address = mp->min_address + fix->fix_size;
7691132718Skan	    }
769290075Sobrien	}
769390075Sobrien    }
769490075Sobrien
769590075Sobrien  /* We need to create a new entry.  */
7696169689Skan  mp = XNEW (Mnode);
769790075Sobrien  mp->fix_size = fix->fix_size;
769890075Sobrien  mp->mode = fix->mode;
769990075Sobrien  mp->value = fix->value;
770090075Sobrien  mp->refcount = 1;
770190075Sobrien  mp->max_address = minipool_barrier->address + 65536;
770290075Sobrien
770390075Sobrien  mp->min_address = min_address;
770490075Sobrien
770590075Sobrien  if (min_mp == NULL)
770690075Sobrien    {
770790075Sobrien      mp->prev = NULL;
770890075Sobrien      mp->next = minipool_vector_head;
770990075Sobrien
771090075Sobrien      if (mp->next == NULL)
771190075Sobrien	{
771290075Sobrien	  minipool_vector_tail = mp;
771390075Sobrien	  minipool_vector_label = gen_label_rtx ();
771490075Sobrien	}
771590075Sobrien      else
771690075Sobrien	mp->next->prev = mp;
771790075Sobrien
771890075Sobrien      minipool_vector_head = mp;
771990075Sobrien    }
772090075Sobrien  else
772190075Sobrien    {
772290075Sobrien      mp->next = min_mp->next;
772390075Sobrien      mp->prev = min_mp;
772490075Sobrien      min_mp->next = mp;
7725169689Skan
772690075Sobrien      if (mp->next != NULL)
772790075Sobrien	mp->next->prev = mp;
772890075Sobrien      else
772990075Sobrien	minipool_vector_tail = mp;
773090075Sobrien    }
773190075Sobrien
773290075Sobrien  /* Save the new entry.  */
773390075Sobrien  min_mp = mp;
773490075Sobrien
773590075Sobrien  if (mp->prev)
773690075Sobrien    mp = mp->prev;
773790075Sobrien  else
773890075Sobrien    mp->offset = 0;
773990075Sobrien
774090075Sobrien  /* Scan over the following entries and adjust their offsets.  */
774190075Sobrien  while (mp->next != NULL)
774290075Sobrien    {
774390075Sobrien      if (mp->next->min_address < mp->min_address + mp->fix_size)
774490075Sobrien	mp->next->min_address = mp->min_address + mp->fix_size;
774590075Sobrien
774690075Sobrien      if (mp->refcount)
774790075Sobrien	mp->next->offset = mp->offset + mp->fix_size;
774890075Sobrien      else
774990075Sobrien	mp->next->offset = mp->offset;
775090075Sobrien
775190075Sobrien      mp = mp->next;
775290075Sobrien    }
775390075Sobrien
775490075Sobrien  return min_mp;
775590075Sobrien}
775690075Sobrien
775790075Sobrienstatic void
7758132718Skanassign_minipool_offsets (Mfix *barrier)
775990075Sobrien{
776090075Sobrien  HOST_WIDE_INT offset = 0;
7761132718Skan  Mnode *mp;
776290075Sobrien
776390075Sobrien  minipool_barrier = barrier;
776490075Sobrien
776590075Sobrien  for (mp = minipool_vector_head; mp != NULL; mp = mp->next)
776690075Sobrien    {
776790075Sobrien      mp->offset = offset;
7768169689Skan
776990075Sobrien      if (mp->refcount > 0)
777090075Sobrien	offset += mp->fix_size;
777190075Sobrien    }
777290075Sobrien}
777390075Sobrien
777490075Sobrien/* Output the literal table */
777590075Sobrienstatic void
7776132718Skandump_minipool (rtx scan)
777790075Sobrien{
777890075Sobrien  Mnode * mp;
777990075Sobrien  Mnode * nmp;
7780132718Skan  int align64 = 0;
778190075Sobrien
7782169689Skan  if (ARM_DOUBLEWORD_ALIGN)
7783132718Skan    for (mp = minipool_vector_head; mp != NULL; mp = mp->next)
7784132718Skan      if (mp->refcount > 0 && mp->fix_size == 8)
7785132718Skan	{
7786132718Skan	  align64 = 1;
7787132718Skan	  break;
7788132718Skan	}
7789132718Skan
7790169689Skan  if (dump_file)
7791169689Skan    fprintf (dump_file,
7792132718Skan	     ";; Emitting minipool after insn %u; address %ld; align %d (bytes)\n",
7793132718Skan	     INSN_UID (scan), (unsigned long) minipool_barrier->address, align64 ? 8 : 4);
779490075Sobrien
779590075Sobrien  scan = emit_label_after (gen_label_rtx (), scan);
7796132718Skan  scan = emit_insn_after (align64 ? gen_align_8 () : gen_align_4 (), scan);
779790075Sobrien  scan = emit_label_after (minipool_vector_label, scan);
779890075Sobrien
779990075Sobrien  for (mp = minipool_vector_head; mp != NULL; mp = nmp)
780090075Sobrien    {
780190075Sobrien      if (mp->refcount > 0)
780290075Sobrien	{
7803169689Skan	  if (dump_file)
780490075Sobrien	    {
7805169689Skan	      fprintf (dump_file,
780690075Sobrien		       ";;  Offset %u, min %ld, max %ld ",
780790075Sobrien		       (unsigned) mp->offset, (unsigned long) mp->min_address,
780890075Sobrien		       (unsigned long) mp->max_address);
7809169689Skan	      arm_print_value (dump_file, mp->value);
7810169689Skan	      fputc ('\n', dump_file);
781190075Sobrien	    }
781290075Sobrien
781390075Sobrien	  switch (mp->fix_size)
781490075Sobrien	    {
781590075Sobrien#ifdef HAVE_consttable_1
781690075Sobrien	    case 1:
781790075Sobrien	      scan = emit_insn_after (gen_consttable_1 (mp->value), scan);
781890075Sobrien	      break;
781990075Sobrien
782090075Sobrien#endif
782190075Sobrien#ifdef HAVE_consttable_2
782290075Sobrien	    case 2:
782390075Sobrien	      scan = emit_insn_after (gen_consttable_2 (mp->value), scan);
782490075Sobrien	      break;
782590075Sobrien
782690075Sobrien#endif
782790075Sobrien#ifdef HAVE_consttable_4
782890075Sobrien	    case 4:
782990075Sobrien	      scan = emit_insn_after (gen_consttable_4 (mp->value), scan);
783090075Sobrien	      break;
783190075Sobrien
783290075Sobrien#endif
783390075Sobrien#ifdef HAVE_consttable_8
783490075Sobrien	    case 8:
783590075Sobrien	      scan = emit_insn_after (gen_consttable_8 (mp->value), scan);
783690075Sobrien	      break;
783790075Sobrien
783890075Sobrien#endif
783990075Sobrien	    default:
7840169689Skan	      gcc_unreachable ();
784190075Sobrien	    }
784290075Sobrien	}
784390075Sobrien
784490075Sobrien      nmp = mp->next;
784590075Sobrien      free (mp);
784690075Sobrien    }
784790075Sobrien
784890075Sobrien  minipool_vector_head = minipool_vector_tail = NULL;
784990075Sobrien  scan = emit_insn_after (gen_consttable_end (), scan);
785090075Sobrien  scan = emit_barrier_after (scan);
785190075Sobrien}
785290075Sobrien
785390075Sobrien/* Return the cost of forcibly inserting a barrier after INSN.  */
785490075Sobrienstatic int
7855132718Skanarm_barrier_cost (rtx insn)
785690075Sobrien{
785790075Sobrien  /* Basing the location of the pool on the loop depth is preferable,
785890075Sobrien     but at the moment, the basic block information seems to be
785990075Sobrien     corrupt by this stage of the compilation.  */
786090075Sobrien  int base_cost = 50;
786190075Sobrien  rtx next = next_nonnote_insn (insn);
786290075Sobrien
786390075Sobrien  if (next != NULL && GET_CODE (next) == CODE_LABEL)
786490075Sobrien    base_cost -= 20;
786590075Sobrien
786690075Sobrien  switch (GET_CODE (insn))
786790075Sobrien    {
786890075Sobrien    case CODE_LABEL:
786990075Sobrien      /* It will always be better to place the table before the label, rather
787090075Sobrien	 than after it.  */
7871169689Skan      return 50;
787290075Sobrien
787390075Sobrien    case INSN:
787490075Sobrien    case CALL_INSN:
787590075Sobrien      return base_cost;
787690075Sobrien
787790075Sobrien    case JUMP_INSN:
787890075Sobrien      return base_cost - 10;
787990075Sobrien
788090075Sobrien    default:
788190075Sobrien      return base_cost + 10;
788290075Sobrien    }
788390075Sobrien}
788490075Sobrien
788590075Sobrien/* Find the best place in the insn stream in the range
788690075Sobrien   (FIX->address,MAX_ADDRESS) to forcibly insert a minipool barrier.
788790075Sobrien   Create the barrier by inserting a jump and add a new fix entry for
788890075Sobrien   it.  */
788990075Sobrienstatic Mfix *
7890132718Skancreate_fix_barrier (Mfix *fix, HOST_WIDE_INT max_address)
789190075Sobrien{
789290075Sobrien  HOST_WIDE_INT count = 0;
789390075Sobrien  rtx barrier;
789490075Sobrien  rtx from = fix->insn;
7895169689Skan  /* The instruction after which we will insert the jump.  */
7896169689Skan  rtx selected = NULL;
789790075Sobrien  int selected_cost;
7898169689Skan  /* The address at which the jump instruction will be placed.  */
789990075Sobrien  HOST_WIDE_INT selected_address;
790090075Sobrien  Mfix * new_fix;
790190075Sobrien  HOST_WIDE_INT max_count = max_address - fix->address;
790290075Sobrien  rtx label = gen_label_rtx ();
790390075Sobrien
790490075Sobrien  selected_cost = arm_barrier_cost (from);
790590075Sobrien  selected_address = fix->address;
790690075Sobrien
790790075Sobrien  while (from && count < max_count)
790890075Sobrien    {
790990075Sobrien      rtx tmp;
791090075Sobrien      int new_cost;
791190075Sobrien
791290075Sobrien      /* This code shouldn't have been called if there was a natural barrier
791390075Sobrien	 within range.  */
7914169689Skan      gcc_assert (GET_CODE (from) != BARRIER);
791590075Sobrien
791690075Sobrien      /* Count the length of this insn.  */
791790075Sobrien      count += get_attr_length (from);
791890075Sobrien
791990075Sobrien      /* If there is a jump table, add its length.  */
792090075Sobrien      tmp = is_jump_table (from);
792190075Sobrien      if (tmp != NULL)
792290075Sobrien	{
792390075Sobrien	  count += get_jump_table_size (tmp);
792490075Sobrien
792590075Sobrien	  /* Jump tables aren't in a basic block, so base the cost on
792690075Sobrien	     the dispatch insn.  If we select this location, we will
792790075Sobrien	     still put the pool after the table.  */
792890075Sobrien	  new_cost = arm_barrier_cost (from);
792990075Sobrien
7930169689Skan	  if (count < max_count
7931169689Skan	      && (!selected || new_cost <= selected_cost))
793290075Sobrien	    {
793390075Sobrien	      selected = tmp;
793490075Sobrien	      selected_cost = new_cost;
793590075Sobrien	      selected_address = fix->address + count;
793690075Sobrien	    }
793790075Sobrien
793890075Sobrien	  /* Continue after the dispatch table.  */
793990075Sobrien	  from = NEXT_INSN (tmp);
794090075Sobrien	  continue;
794190075Sobrien	}
794290075Sobrien
794390075Sobrien      new_cost = arm_barrier_cost (from);
7944169689Skan
7945169689Skan      if (count < max_count
7946169689Skan	  && (!selected || new_cost <= selected_cost))
794790075Sobrien	{
794890075Sobrien	  selected = from;
794990075Sobrien	  selected_cost = new_cost;
795090075Sobrien	  selected_address = fix->address + count;
795190075Sobrien	}
795290075Sobrien
795390075Sobrien      from = NEXT_INSN (from);
795490075Sobrien    }
795590075Sobrien
7956169689Skan  /* Make sure that we found a place to insert the jump.  */
7957169689Skan  gcc_assert (selected);
7958169689Skan
795990075Sobrien  /* Create a new JUMP_INSN that branches around a barrier.  */
796090075Sobrien  from = emit_jump_insn_after (gen_jump (label), selected);
796190075Sobrien  JUMP_LABEL (from) = label;
796290075Sobrien  barrier = emit_barrier_after (from);
796390075Sobrien  emit_label_after (label, barrier);
796490075Sobrien
796590075Sobrien  /* Create a minipool barrier entry for the new barrier.  */
796690075Sobrien  new_fix = (Mfix *) obstack_alloc (&minipool_obstack, sizeof (* new_fix));
796790075Sobrien  new_fix->insn = barrier;
796890075Sobrien  new_fix->address = selected_address;
796990075Sobrien  new_fix->next = fix->next;
797090075Sobrien  fix->next = new_fix;
797190075Sobrien
797290075Sobrien  return new_fix;
797390075Sobrien}
797490075Sobrien
797590075Sobrien/* Record that there is a natural barrier in the insn stream at
797690075Sobrien   ADDRESS.  */
797790075Sobrienstatic void
7978132718Skanpush_minipool_barrier (rtx insn, HOST_WIDE_INT address)
797990075Sobrien{
798090075Sobrien  Mfix * fix = (Mfix *) obstack_alloc (&minipool_obstack, sizeof (* fix));
798190075Sobrien
798290075Sobrien  fix->insn = insn;
798390075Sobrien  fix->address = address;
798490075Sobrien
798590075Sobrien  fix->next = NULL;
798690075Sobrien  if (minipool_fix_head != NULL)
798790075Sobrien    minipool_fix_tail->next = fix;
798890075Sobrien  else
798990075Sobrien    minipool_fix_head = fix;
799090075Sobrien
799190075Sobrien  minipool_fix_tail = fix;
799290075Sobrien}
799390075Sobrien
799490075Sobrien/* Record INSN, which will need fixing up to load a value from the
799590075Sobrien   minipool.  ADDRESS is the offset of the insn since the start of the
799690075Sobrien   function; LOC is a pointer to the part of the insn which requires
799790075Sobrien   fixing; VALUE is the constant that must be loaded, which is of type
799890075Sobrien   MODE.  */
799990075Sobrienstatic void
8000132718Skanpush_minipool_fix (rtx insn, HOST_WIDE_INT address, rtx *loc,
8001132718Skan		   enum machine_mode mode, rtx value)
800290075Sobrien{
800390075Sobrien  Mfix * fix = (Mfix *) obstack_alloc (&minipool_obstack, sizeof (* fix));
800490075Sobrien
800590075Sobrien#ifdef AOF_ASSEMBLER
8006132718Skan  /* PIC symbol references need to be converted into offsets into the
800790075Sobrien     based area.  */
800890075Sobrien  /* XXX This shouldn't be done here.  */
800990075Sobrien  if (flag_pic && GET_CODE (value) == SYMBOL_REF)
801090075Sobrien    value = aof_pic_entry (value);
801190075Sobrien#endif /* AOF_ASSEMBLER */
801290075Sobrien
801390075Sobrien  fix->insn = insn;
801490075Sobrien  fix->address = address;
801590075Sobrien  fix->loc = loc;
801690075Sobrien  fix->mode = mode;
801790075Sobrien  fix->fix_size = MINIPOOL_FIX_SIZE (mode);
801890075Sobrien  fix->value = value;
801990075Sobrien  fix->forwards = get_attr_pool_range (insn);
802090075Sobrien  fix->backwards = get_attr_neg_pool_range (insn);
802190075Sobrien  fix->minipool = NULL;
802290075Sobrien
802390075Sobrien  /* If an insn doesn't have a range defined for it, then it isn't
8024169689Skan     expecting to be reworked by this code.  Better to stop now than
802590075Sobrien     to generate duff assembly code.  */
8026169689Skan  gcc_assert (fix->forwards || fix->backwards);
802790075Sobrien
8028169689Skan  /* If an entry requires 8-byte alignment then assume all constant pools
8029169689Skan     require 4 bytes of padding.  Trying to do this later on a per-pool
8030169689Skan     basis is awkward because existing pool entries have to be modified.  */
8031169689Skan  if (ARM_DOUBLEWORD_ALIGN && fix->fix_size == 8)
8032169689Skan    minipool_pad = 4;
8033132718Skan
8034169689Skan  if (dump_file)
803590075Sobrien    {
8036169689Skan      fprintf (dump_file,
803790075Sobrien	       ";; %smode fixup for i%d; addr %lu, range (%ld,%ld): ",
803890075Sobrien	       GET_MODE_NAME (mode),
8039169689Skan	       INSN_UID (insn), (unsigned long) address,
804090075Sobrien	       -1 * (long)fix->backwards, (long)fix->forwards);
8041169689Skan      arm_print_value (dump_file, fix->value);
8042169689Skan      fprintf (dump_file, "\n");
804390075Sobrien    }
804490075Sobrien
804590075Sobrien  /* Add it to the chain of fixes.  */
804690075Sobrien  fix->next = NULL;
8047169689Skan
804890075Sobrien  if (minipool_fix_head != NULL)
804990075Sobrien    minipool_fix_tail->next = fix;
805090075Sobrien  else
805190075Sobrien    minipool_fix_head = fix;
805290075Sobrien
805390075Sobrien  minipool_fix_tail = fix;
805490075Sobrien}
805590075Sobrien
8056169689Skan/* Return the cost of synthesizing a 64-bit constant VAL inline.
8057169689Skan   Returns the number of insns needed, or 99 if we don't know how to
8058169689Skan   do it.  */
8059169689Skanint
8060169689Skanarm_const_double_inline_cost (rtx val)
8061169689Skan{
8062169689Skan  rtx lowpart, highpart;
8063169689Skan  enum machine_mode mode;
8064169689Skan
8065169689Skan  mode = GET_MODE (val);
8066169689Skan
8067169689Skan  if (mode == VOIDmode)
8068169689Skan    mode = DImode;
8069169689Skan
8070169689Skan  gcc_assert (GET_MODE_SIZE (mode) == 8);
8071169689Skan
8072169689Skan  lowpart = gen_lowpart (SImode, val);
8073169689Skan  highpart = gen_highpart_mode (SImode, mode, val);
8074169689Skan
8075169689Skan  gcc_assert (GET_CODE (lowpart) == CONST_INT);
8076169689Skan  gcc_assert (GET_CODE (highpart) == CONST_INT);
8077169689Skan
8078169689Skan  return (arm_gen_constant (SET, SImode, NULL_RTX, INTVAL (lowpart),
8079169689Skan			    NULL_RTX, NULL_RTX, 0, 0)
8080169689Skan	  + arm_gen_constant (SET, SImode, NULL_RTX, INTVAL (highpart),
8081169689Skan			      NULL_RTX, NULL_RTX, 0, 0));
8082169689Skan}
8083169689Skan
8084169689Skan/* Return true if it is worthwhile to split a 64-bit constant into two
8085169689Skan   32-bit operations.  This is the case if optimizing for size, or
8086169689Skan   if we have load delay slots, or if one 32-bit part can be done with
8087169689Skan   a single data operation.  */
8088169689Skanbool
8089169689Skanarm_const_double_by_parts (rtx val)
8090169689Skan{
8091169689Skan  enum machine_mode mode = GET_MODE (val);
8092169689Skan  rtx part;
8093169689Skan
8094169689Skan  if (optimize_size || arm_ld_sched)
8095169689Skan    return true;
8096169689Skan
8097169689Skan  if (mode == VOIDmode)
8098169689Skan    mode = DImode;
8099169689Skan
8100169689Skan  part = gen_highpart_mode (SImode, mode, val);
8101169689Skan
8102169689Skan  gcc_assert (GET_CODE (part) == CONST_INT);
8103169689Skan
8104169689Skan  if (const_ok_for_arm (INTVAL (part))
8105169689Skan      || const_ok_for_arm (~INTVAL (part)))
8106169689Skan    return true;
8107169689Skan
8108169689Skan  part = gen_lowpart (SImode, val);
8109169689Skan
8110169689Skan  gcc_assert (GET_CODE (part) == CONST_INT);
8111169689Skan
8112169689Skan  if (const_ok_for_arm (INTVAL (part))
8113169689Skan      || const_ok_for_arm (~INTVAL (part)))
8114169689Skan    return true;
8115169689Skan
8116169689Skan  return false;
8117169689Skan}
8118169689Skan
8119132718Skan/* Scan INSN and note any of its operands that need fixing.
8120132718Skan   If DO_PUSHES is false we do not actually push any of the fixups
8121169689Skan   needed.  The function returns TRUE if any fixups were needed/pushed.
8122132718Skan   This is used by arm_memory_load_p() which needs to know about loads
8123132718Skan   of constants that will be converted into minipool loads.  */
8124132718Skanstatic bool
8125132718Skannote_invalid_constants (rtx insn, HOST_WIDE_INT address, int do_pushes)
812690075Sobrien{
8127132718Skan  bool result = false;
812890075Sobrien  int opno;
812990075Sobrien
813090075Sobrien  extract_insn (insn);
813190075Sobrien
813290075Sobrien  if (!constrain_operands (1))
813390075Sobrien    fatal_insn_not_found (insn);
813490075Sobrien
8135132718Skan  if (recog_data.n_alternatives == 0)
8136132718Skan    return false;
8137132718Skan
8138169689Skan  /* Fill in recog_op_alt with information about the constraints of
8139169689Skan     this insn.  */
814090075Sobrien  preprocess_constraints ();
814190075Sobrien
814290075Sobrien  for (opno = 0; opno < recog_data.n_operands; opno++)
814390075Sobrien    {
814490075Sobrien      /* Things we need to fix can only occur in inputs.  */
814590075Sobrien      if (recog_data.operand_type[opno] != OP_IN)
814690075Sobrien	continue;
814790075Sobrien
814890075Sobrien      /* If this alternative is a memory reference, then any mention
814990075Sobrien	 of constants in this alternative is really to fool reload
815090075Sobrien	 into allowing us to accept one there.  We need to fix them up
815190075Sobrien	 now so that we output the right code.  */
815290075Sobrien      if (recog_op_alt[opno][which_alternative].memory_ok)
815390075Sobrien	{
815490075Sobrien	  rtx op = recog_data.operand[opno];
815590075Sobrien
815690075Sobrien	  if (CONSTANT_P (op))
8157132718Skan	    {
8158132718Skan	      if (do_pushes)
8159132718Skan		push_minipool_fix (insn, address, recog_data.operand_loc[opno],
8160132718Skan				   recog_data.operand_mode[opno], op);
8161132718Skan	      result = true;
8162132718Skan	    }
816390075Sobrien	  else if (GET_CODE (op) == MEM
816490075Sobrien		   && GET_CODE (XEXP (op, 0)) == SYMBOL_REF
816590075Sobrien		   && CONSTANT_POOL_ADDRESS_P (XEXP (op, 0)))
8166132718Skan	    {
8167132718Skan	      if (do_pushes)
8168132718Skan		{
8169132718Skan		  rtx cop = avoid_constant_pool_reference (op);
8170132718Skan
8171132718Skan		  /* Casting the address of something to a mode narrower
8172132718Skan		     than a word can cause avoid_constant_pool_reference()
8173132718Skan		     to return the pool reference itself.  That's no good to
8174169689Skan		     us here.  Lets just hope that we can use the
8175132718Skan		     constant pool value directly.  */
8176132718Skan		  if (op == cop)
8177132718Skan		    cop = get_pool_constant (XEXP (op, 0));
8178132718Skan
8179132718Skan		  push_minipool_fix (insn, address,
8180132718Skan				     recog_data.operand_loc[opno],
8181132718Skan				     recog_data.operand_mode[opno], cop);
8182132718Skan		}
8183132718Skan
8184132718Skan	      result = true;
8185132718Skan	    }
818690075Sobrien	}
818790075Sobrien    }
8188132718Skan
8189132718Skan  return result;
819090075Sobrien}
819190075Sobrien
8192132718Skan/* Gcc puts the pool in the wrong place for ARM, since we can only
8193132718Skan   load addresses a limited distance around the pc.  We do some
8194132718Skan   special munging to move the constant pool values to the correct
8195132718Skan   point in the code.  */
8196132718Skanstatic void
8197132718Skanarm_reorg (void)
819890075Sobrien{
819990075Sobrien  rtx insn;
820090075Sobrien  HOST_WIDE_INT address = 0;
820190075Sobrien  Mfix * fix;
820290075Sobrien
820390075Sobrien  minipool_fix_head = minipool_fix_tail = NULL;
820490075Sobrien
820590075Sobrien  /* The first insn must always be a note, or the code below won't
820690075Sobrien     scan it properly.  */
8207132718Skan  insn = get_insns ();
8208169689Skan  gcc_assert (GET_CODE (insn) == NOTE);
8209169689Skan  minipool_pad = 0;
821090075Sobrien
821190075Sobrien  /* Scan all the insns and record the operands that will need fixing.  */
8212132718Skan  for (insn = next_nonnote_insn (insn); insn; insn = next_nonnote_insn (insn))
821390075Sobrien    {
8214132718Skan      if (TARGET_CIRRUS_FIX_INVALID_INSNS
8215132718Skan          && (arm_cirrus_insn_p (insn)
8216132718Skan	      || GET_CODE (insn) == JUMP_INSN
8217132718Skan	      || arm_memory_load_p (insn)))
8218132718Skan	cirrus_reorg (insn);
8219132718Skan
822090075Sobrien      if (GET_CODE (insn) == BARRIER)
822190075Sobrien	push_minipool_barrier (insn, address);
8222132718Skan      else if (INSN_P (insn))
822390075Sobrien	{
822490075Sobrien	  rtx table;
822590075Sobrien
8226132718Skan	  note_invalid_constants (insn, address, true);
822790075Sobrien	  address += get_attr_length (insn);
822890075Sobrien
822990075Sobrien	  /* If the insn is a vector jump, add the size of the table
823090075Sobrien	     and skip the table.  */
823190075Sobrien	  if ((table = is_jump_table (insn)) != NULL)
823290075Sobrien	    {
823390075Sobrien	      address += get_jump_table_size (table);
823490075Sobrien	      insn = table;
823590075Sobrien	    }
823690075Sobrien	}
823790075Sobrien    }
823890075Sobrien
823990075Sobrien  fix = minipool_fix_head;
8240169689Skan
824190075Sobrien  /* Now scan the fixups and perform the required changes.  */
824290075Sobrien  while (fix)
824390075Sobrien    {
824490075Sobrien      Mfix * ftmp;
824590075Sobrien      Mfix * fdel;
824690075Sobrien      Mfix *  last_added_fix;
824790075Sobrien      Mfix * last_barrier = NULL;
824890075Sobrien      Mfix * this_fix;
824990075Sobrien
825090075Sobrien      /* Skip any further barriers before the next fix.  */
825190075Sobrien      while (fix && GET_CODE (fix->insn) == BARRIER)
825290075Sobrien	fix = fix->next;
825390075Sobrien
825490075Sobrien      /* No more fixes.  */
825590075Sobrien      if (fix == NULL)
825690075Sobrien	break;
825790075Sobrien
825890075Sobrien      last_added_fix = NULL;
825990075Sobrien
826090075Sobrien      for (ftmp = fix; ftmp; ftmp = ftmp->next)
826190075Sobrien	{
826290075Sobrien	  if (GET_CODE (ftmp->insn) == BARRIER)
826390075Sobrien	    {
826490075Sobrien	      if (ftmp->address >= minipool_vector_head->max_address)
826590075Sobrien		break;
826690075Sobrien
826790075Sobrien	      last_barrier = ftmp;
826890075Sobrien	    }
826990075Sobrien	  else if ((ftmp->minipool = add_minipool_forward_ref (ftmp)) == NULL)
827090075Sobrien	    break;
827190075Sobrien
827290075Sobrien	  last_added_fix = ftmp;  /* Keep track of the last fix added.  */
827390075Sobrien	}
827490075Sobrien
827590075Sobrien      /* If we found a barrier, drop back to that; any fixes that we
827690075Sobrien	 could have reached but come after the barrier will now go in
827790075Sobrien	 the next mini-pool.  */
827890075Sobrien      if (last_barrier != NULL)
827990075Sobrien	{
8280169689Skan	  /* Reduce the refcount for those fixes that won't go into this
828190075Sobrien	     pool after all.  */
828290075Sobrien	  for (fdel = last_barrier->next;
828390075Sobrien	       fdel && fdel != ftmp;
828490075Sobrien	       fdel = fdel->next)
828590075Sobrien	    {
828690075Sobrien	      fdel->minipool->refcount--;
828790075Sobrien	      fdel->minipool = NULL;
828890075Sobrien	    }
828990075Sobrien
829090075Sobrien	  ftmp = last_barrier;
829190075Sobrien	}
829290075Sobrien      else
829390075Sobrien        {
829490075Sobrien	  /* ftmp is first fix that we can't fit into this pool and
829590075Sobrien	     there no natural barriers that we could use.  Insert a
829690075Sobrien	     new barrier in the code somewhere between the previous
829790075Sobrien	     fix and this one, and arrange to jump around it.  */
829890075Sobrien	  HOST_WIDE_INT max_address;
829990075Sobrien
830090075Sobrien	  /* The last item on the list of fixes must be a barrier, so
830190075Sobrien	     we can never run off the end of the list of fixes without
830290075Sobrien	     last_barrier being set.  */
8303169689Skan	  gcc_assert (ftmp);
830490075Sobrien
830590075Sobrien	  max_address = minipool_vector_head->max_address;
830690075Sobrien	  /* Check that there isn't another fix that is in range that
830790075Sobrien	     we couldn't fit into this pool because the pool was
830890075Sobrien	     already too large: we need to put the pool before such an
8309169689Skan	     instruction.  The pool itself may come just after the
8310169689Skan	     fix because create_fix_barrier also allows space for a
8311169689Skan	     jump instruction.  */
831290075Sobrien	  if (ftmp->address < max_address)
8313169689Skan	    max_address = ftmp->address + 1;
831490075Sobrien
831590075Sobrien	  last_barrier = create_fix_barrier (last_added_fix, max_address);
831690075Sobrien	}
831790075Sobrien
831890075Sobrien      assign_minipool_offsets (last_barrier);
831990075Sobrien
832090075Sobrien      while (ftmp)
832190075Sobrien	{
832290075Sobrien	  if (GET_CODE (ftmp->insn) != BARRIER
832390075Sobrien	      && ((ftmp->minipool = add_minipool_backward_ref (ftmp))
832490075Sobrien		  == NULL))
832590075Sobrien	    break;
832690075Sobrien
832790075Sobrien	  ftmp = ftmp->next;
832890075Sobrien	}
832990075Sobrien
833090075Sobrien      /* Scan over the fixes we have identified for this pool, fixing them
833190075Sobrien	 up and adding the constants to the pool itself.  */
833290075Sobrien      for (this_fix = fix; this_fix && ftmp != this_fix;
833390075Sobrien	   this_fix = this_fix->next)
833490075Sobrien	if (GET_CODE (this_fix->insn) != BARRIER)
833590075Sobrien	  {
833690075Sobrien	    rtx addr
8337169689Skan	      = plus_constant (gen_rtx_LABEL_REF (VOIDmode,
833890075Sobrien						  minipool_vector_label),
833990075Sobrien			       this_fix->minipool->offset);
834090075Sobrien	    *this_fix->loc = gen_rtx_MEM (this_fix->mode, addr);
834190075Sobrien	  }
834290075Sobrien
834390075Sobrien      dump_minipool (last_barrier->insn);
834490075Sobrien      fix = ftmp;
834590075Sobrien    }
834690075Sobrien
834790075Sobrien  /* From now on we must synthesize any constants that we can't handle
834890075Sobrien     directly.  This can happen if the RTL gets split during final
834990075Sobrien     instruction generation.  */
835090075Sobrien  after_arm_reorg = 1;
835190075Sobrien
835290075Sobrien  /* Free the minipool memory.  */
835390075Sobrien  obstack_free (&minipool_obstack, minipool_startobj);
835490075Sobrien}
835590075Sobrien
835690075Sobrien/* Routines to output assembly language.  */
835790075Sobrien
835890075Sobrien/* If the rtx is the correct value then return the string of the number.
835990075Sobrien   In this way we can ensure that valid double constants are generated even
836090075Sobrien   when cross compiling.  */
836190075Sobrienconst char *
8362132718Skanfp_immediate_constant (rtx x)
836390075Sobrien{
836490075Sobrien  REAL_VALUE_TYPE r;
836590075Sobrien  int i;
8366169689Skan
8367169689Skan  if (!fp_consts_inited)
8368169689Skan    init_fp_table ();
8369169689Skan
837090075Sobrien  REAL_VALUE_FROM_CONST_DOUBLE (r, x);
837190075Sobrien  for (i = 0; i < 8; i++)
8372169689Skan    if (REAL_VALUES_EQUAL (r, values_fp[i]))
8373169689Skan      return strings_fp[i];
837490075Sobrien
8375169689Skan  gcc_unreachable ();
837690075Sobrien}
837790075Sobrien
837890075Sobrien/* As for fp_immediate_constant, but value is passed directly, not in rtx.  */
837990075Sobrienstatic const char *
8380132718Skanfp_const_from_val (REAL_VALUE_TYPE *r)
838190075Sobrien{
838290075Sobrien  int i;
838390075Sobrien
8384169689Skan  if (!fp_consts_inited)
8385169689Skan    init_fp_table ();
838690075Sobrien
838790075Sobrien  for (i = 0; i < 8; i++)
8388169689Skan    if (REAL_VALUES_EQUAL (*r, values_fp[i]))
8389169689Skan      return strings_fp[i];
839090075Sobrien
8391169689Skan  gcc_unreachable ();
839290075Sobrien}
839390075Sobrien
839490075Sobrien/* Output the operands of a LDM/STM instruction to STREAM.
839590075Sobrien   MASK is the ARM register set mask of which only bits 0-15 are important.
839690075Sobrien   REG is the base register, either the frame pointer or the stack pointer,
839790075Sobrien   INSTR is the possibly suffixed load or store instruction.  */
8398169689Skan
839990075Sobrienstatic void
8400169689Skanprint_multi_reg (FILE *stream, const char *instr, unsigned reg,
8401169689Skan		 unsigned long mask)
840290075Sobrien{
8403169689Skan  unsigned i;
8404169689Skan  bool not_first = FALSE;
840590075Sobrien
840690075Sobrien  fputc ('\t', stream);
840790075Sobrien  asm_fprintf (stream, instr, reg);
840890075Sobrien  fputs (", {", stream);
8409169689Skan
841090075Sobrien  for (i = 0; i <= LAST_ARM_REGNUM; i++)
841190075Sobrien    if (mask & (1 << i))
841290075Sobrien      {
841390075Sobrien	if (not_first)
841490075Sobrien	  fprintf (stream, ", ");
8415169689Skan
841690075Sobrien	asm_fprintf (stream, "%r", i);
841790075Sobrien	not_first = TRUE;
841890075Sobrien      }
841990075Sobrien
8420169689Skan  fprintf (stream, "}\n");
8421169689Skan}
8422132718Skan
8423169689Skan
8424169689Skan/* Output a FLDMX instruction to STREAM.
8425169689Skan   BASE if the register containing the address.
8426169689Skan   REG and COUNT specify the register range.
8427169689Skan   Extra registers may be added to avoid hardware bugs.  */
8428169689Skan
8429169689Skanstatic void
8430169689Skanarm_output_fldmx (FILE * stream, unsigned int base, int reg, int count)
8431169689Skan{
8432169689Skan  int i;
8433169689Skan
8434169689Skan  /* Workaround ARM10 VFPr1 bug.  */
8435169689Skan  if (count == 2 && !arm_arch6)
8436169689Skan    {
8437169689Skan      if (reg == 15)
8438169689Skan	reg--;
8439169689Skan      count++;
8440169689Skan    }
8441169689Skan
8442169689Skan  fputc ('\t', stream);
8443169689Skan  asm_fprintf (stream, "fldmfdx\t%r!, {", base);
8444169689Skan
8445169689Skan  for (i = reg; i < reg + count; i++)
8446169689Skan    {
8447169689Skan      if (i > reg)
8448169689Skan	fputs (", ", stream);
8449169689Skan      asm_fprintf (stream, "d%d", i);
8450169689Skan    }
8451169689Skan  fputs ("}\n", stream);
8452169689Skan
845390075Sobrien}
845490075Sobrien
8455169689Skan
8456169689Skan/* Output the assembly for a store multiple.  */
8457169689Skan
8458169689Skanconst char *
8459169689Skanvfp_output_fstmx (rtx * operands)
8460169689Skan{
8461169689Skan  char pattern[100];
8462169689Skan  int p;
8463169689Skan  int base;
8464169689Skan  int i;
8465169689Skan
8466169689Skan  strcpy (pattern, "fstmfdx\t%m0!, {%P1");
8467169689Skan  p = strlen (pattern);
8468169689Skan
8469169689Skan  gcc_assert (GET_CODE (operands[1]) == REG);
8470169689Skan
8471169689Skan  base = (REGNO (operands[1]) - FIRST_VFP_REGNUM) / 2;
8472169689Skan  for (i = 1; i < XVECLEN (operands[2], 0); i++)
8473169689Skan    {
8474169689Skan      p += sprintf (&pattern[p], ", d%d", base + i);
8475169689Skan    }
8476169689Skan  strcpy (&pattern[p], "}");
8477169689Skan
8478169689Skan  output_asm_insn (pattern, operands);
8479169689Skan  return "";
8480169689Skan}
8481169689Skan
8482169689Skan
8483169689Skan/* Emit RTL to save block of VFP register pairs to the stack.  Returns the
8484169689Skan   number of bytes pushed.  */
8485169689Skan
8486169689Skanstatic int
8487169689Skanvfp_emit_fstmx (int base_reg, int count)
8488169689Skan{
8489169689Skan  rtx par;
8490169689Skan  rtx dwarf;
8491169689Skan  rtx tmp, reg;
8492169689Skan  int i;
8493169689Skan
8494169689Skan  /* Workaround ARM10 VFPr1 bug.  Data corruption can occur when exactly two
8495169689Skan     register pairs are stored by a store multiple insn.  We avoid this
8496169689Skan     by pushing an extra pair.  */
8497169689Skan  if (count == 2 && !arm_arch6)
8498169689Skan    {
8499169689Skan      if (base_reg == LAST_VFP_REGNUM - 3)
8500169689Skan	base_reg -= 2;
8501169689Skan      count++;
8502169689Skan    }
8503169689Skan
8504169689Skan  /* ??? The frame layout is implementation defined.  We describe
8505169689Skan     standard format 1 (equivalent to a FSTMD insn and unused pad word).
8506169689Skan     We really need some way of representing the whole block so that the
8507169689Skan     unwinder can figure it out at runtime.  */
8508169689Skan  par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count));
8509169689Skan  dwarf = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (count + 1));
8510169689Skan
8511169689Skan  reg = gen_rtx_REG (DFmode, base_reg);
8512169689Skan  base_reg += 2;
8513169689Skan
8514169689Skan  XVECEXP (par, 0, 0)
8515169689Skan    = gen_rtx_SET (VOIDmode,
8516169689Skan		   gen_frame_mem (BLKmode,
8517169689Skan				  gen_rtx_PRE_DEC (BLKmode,
8518169689Skan						   stack_pointer_rtx)),
8519169689Skan		   gen_rtx_UNSPEC (BLKmode,
8520169689Skan				   gen_rtvec (1, reg),
8521169689Skan				   UNSPEC_PUSH_MULT));
8522169689Skan
8523169689Skan  tmp = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
8524169689Skan		     plus_constant (stack_pointer_rtx, -(count * 8 + 4)));
8525169689Skan  RTX_FRAME_RELATED_P (tmp) = 1;
8526169689Skan  XVECEXP (dwarf, 0, 0) = tmp;
8527169689Skan
8528169689Skan  tmp = gen_rtx_SET (VOIDmode,
8529169689Skan		     gen_frame_mem (DFmode, stack_pointer_rtx),
8530169689Skan		     reg);
8531169689Skan  RTX_FRAME_RELATED_P (tmp) = 1;
8532169689Skan  XVECEXP (dwarf, 0, 1) = tmp;
8533169689Skan
8534169689Skan  for (i = 1; i < count; i++)
8535169689Skan    {
8536169689Skan      reg = gen_rtx_REG (DFmode, base_reg);
8537169689Skan      base_reg += 2;
8538169689Skan      XVECEXP (par, 0, i) = gen_rtx_USE (VOIDmode, reg);
8539169689Skan
8540169689Skan      tmp = gen_rtx_SET (VOIDmode,
8541169689Skan			 gen_frame_mem (DFmode,
8542169689Skan					plus_constant (stack_pointer_rtx,
8543169689Skan						       i * 8)),
8544169689Skan			 reg);
8545169689Skan      RTX_FRAME_RELATED_P (tmp) = 1;
8546169689Skan      XVECEXP (dwarf, 0, i + 1) = tmp;
8547169689Skan    }
8548169689Skan
8549169689Skan  par = emit_insn (par);
8550169689Skan  REG_NOTES (par) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
8551169689Skan				       REG_NOTES (par));
8552169689Skan  RTX_FRAME_RELATED_P (par) = 1;
8553169689Skan
8554169689Skan  return count * 8 + 4;
8555169689Skan}
8556169689Skan
8557169689Skan
855890075Sobrien/* Output a 'call' insn.  */
855990075Sobrienconst char *
8560132718Skanoutput_call (rtx *operands)
856190075Sobrien{
8562169689Skan  gcc_assert (!arm_arch5); /* Patterns should call blx <reg> directly.  */
8563169689Skan
856490075Sobrien  /* Handle calls to lr using ip (which may be clobbered in subr anyway).  */
856590075Sobrien  if (REGNO (operands[0]) == LR_REGNUM)
856690075Sobrien    {
856790075Sobrien      operands[0] = gen_rtx_REG (SImode, IP_REGNUM);
856890075Sobrien      output_asm_insn ("mov%?\t%0, %|lr", operands);
856990075Sobrien    }
8570169689Skan
857190075Sobrien  output_asm_insn ("mov%?\t%|lr, %|pc", operands);
8572169689Skan
8573169689Skan  if (TARGET_INTERWORK || arm_arch4t)
857490075Sobrien    output_asm_insn ("bx%?\t%0", operands);
857590075Sobrien  else
857690075Sobrien    output_asm_insn ("mov%?\t%|pc, %0", operands);
8577169689Skan
857890075Sobrien  return "";
857990075Sobrien}
858090075Sobrien
858190075Sobrien/* Output a 'call' insn that is a reference in memory.  */
858290075Sobrienconst char *
8583132718Skanoutput_call_mem (rtx *operands)
858490075Sobrien{
8585169689Skan  if (TARGET_INTERWORK && !arm_arch5)
858690075Sobrien    {
858790075Sobrien      output_asm_insn ("ldr%?\t%|ip, %0", operands);
858890075Sobrien      output_asm_insn ("mov%?\t%|lr, %|pc", operands);
858990075Sobrien      output_asm_insn ("bx%?\t%|ip", operands);
859090075Sobrien    }
8591117395Skan  else if (regno_use_in (LR_REGNUM, operands[0]))
8592117395Skan    {
8593117395Skan      /* LR is used in the memory address.  We load the address in the
8594117395Skan	 first instruction.  It's safe to use IP as the target of the
8595117395Skan	 load since the call will kill it anyway.  */
8596117395Skan      output_asm_insn ("ldr%?\t%|ip, %0", operands);
8597169689Skan      if (arm_arch5)
8598169689Skan	output_asm_insn ("blx%?\t%|ip", operands);
8599169689Skan      else
8600169689Skan	{
8601169689Skan	  output_asm_insn ("mov%?\t%|lr, %|pc", operands);
8602169689Skan	  if (arm_arch4t)
8603169689Skan	    output_asm_insn ("bx%?\t%|ip", operands);
8604169689Skan	  else
8605169689Skan	    output_asm_insn ("mov%?\t%|pc, %|ip", operands);
8606169689Skan	}
8607117395Skan    }
860890075Sobrien  else
860990075Sobrien    {
861090075Sobrien      output_asm_insn ("mov%?\t%|lr, %|pc", operands);
861190075Sobrien      output_asm_insn ("ldr%?\t%|pc, %0", operands);
861290075Sobrien    }
861390075Sobrien
861490075Sobrien  return "";
861590075Sobrien}
861690075Sobrien
8617169689Skan
8618132718Skan/* Output a move from arm registers to an fpa registers.
8619132718Skan   OPERANDS[0] is an fpa register.
862090075Sobrien   OPERANDS[1] is the first registers of an arm register pair.  */
862190075Sobrienconst char *
8622132718Skanoutput_mov_long_double_fpa_from_arm (rtx *operands)
862390075Sobrien{
862490075Sobrien  int arm_reg0 = REGNO (operands[1]);
862590075Sobrien  rtx ops[3];
862690075Sobrien
8627169689Skan  gcc_assert (arm_reg0 != IP_REGNUM);
862890075Sobrien
862990075Sobrien  ops[0] = gen_rtx_REG (SImode, arm_reg0);
863090075Sobrien  ops[1] = gen_rtx_REG (SImode, 1 + arm_reg0);
863190075Sobrien  ops[2] = gen_rtx_REG (SImode, 2 + arm_reg0);
8632169689Skan
863390075Sobrien  output_asm_insn ("stm%?fd\t%|sp!, {%0, %1, %2}", ops);
863490075Sobrien  output_asm_insn ("ldf%?e\t%0, [%|sp], #12", operands);
8635169689Skan
863690075Sobrien  return "";
863790075Sobrien}
863890075Sobrien
8639132718Skan/* Output a move from an fpa register to arm registers.
864090075Sobrien   OPERANDS[0] is the first registers of an arm register pair.
8641132718Skan   OPERANDS[1] is an fpa register.  */
864290075Sobrienconst char *
8643132718Skanoutput_mov_long_double_arm_from_fpa (rtx *operands)
864490075Sobrien{
864590075Sobrien  int arm_reg0 = REGNO (operands[0]);
864690075Sobrien  rtx ops[3];
864790075Sobrien
8648169689Skan  gcc_assert (arm_reg0 != IP_REGNUM);
864990075Sobrien
865090075Sobrien  ops[0] = gen_rtx_REG (SImode, arm_reg0);
865190075Sobrien  ops[1] = gen_rtx_REG (SImode, 1 + arm_reg0);
865290075Sobrien  ops[2] = gen_rtx_REG (SImode, 2 + arm_reg0);
865390075Sobrien
865490075Sobrien  output_asm_insn ("stf%?e\t%1, [%|sp, #-12]!", operands);
865590075Sobrien  output_asm_insn ("ldm%?fd\t%|sp!, {%0, %1, %2}", ops);
865690075Sobrien  return "";
865790075Sobrien}
865890075Sobrien
865990075Sobrien/* Output a move from arm registers to arm registers of a long double
866090075Sobrien   OPERANDS[0] is the destination.
866190075Sobrien   OPERANDS[1] is the source.  */
866290075Sobrienconst char *
8663132718Skanoutput_mov_long_double_arm_from_arm (rtx *operands)
866490075Sobrien{
866590075Sobrien  /* We have to be careful here because the two might overlap.  */
866690075Sobrien  int dest_start = REGNO (operands[0]);
866790075Sobrien  int src_start = REGNO (operands[1]);
866890075Sobrien  rtx ops[2];
866990075Sobrien  int i;
867090075Sobrien
867190075Sobrien  if (dest_start < src_start)
867290075Sobrien    {
867390075Sobrien      for (i = 0; i < 3; i++)
867490075Sobrien	{
867590075Sobrien	  ops[0] = gen_rtx_REG (SImode, dest_start + i);
867690075Sobrien	  ops[1] = gen_rtx_REG (SImode, src_start + i);
867790075Sobrien	  output_asm_insn ("mov%?\t%0, %1", ops);
867890075Sobrien	}
867990075Sobrien    }
868090075Sobrien  else
868190075Sobrien    {
868290075Sobrien      for (i = 2; i >= 0; i--)
868390075Sobrien	{
868490075Sobrien	  ops[0] = gen_rtx_REG (SImode, dest_start + i);
868590075Sobrien	  ops[1] = gen_rtx_REG (SImode, src_start + i);
868690075Sobrien	  output_asm_insn ("mov%?\t%0, %1", ops);
868790075Sobrien	}
868890075Sobrien    }
868990075Sobrien
869090075Sobrien  return "";
869190075Sobrien}
869290075Sobrien
869390075Sobrien
8694132718Skan/* Output a move from arm registers to an fpa registers.
8695132718Skan   OPERANDS[0] is an fpa register.
869690075Sobrien   OPERANDS[1] is the first registers of an arm register pair.  */
869790075Sobrienconst char *
8698132718Skanoutput_mov_double_fpa_from_arm (rtx *operands)
869990075Sobrien{
870090075Sobrien  int arm_reg0 = REGNO (operands[1]);
870190075Sobrien  rtx ops[2];
870290075Sobrien
8703169689Skan  gcc_assert (arm_reg0 != IP_REGNUM);
8704169689Skan
870590075Sobrien  ops[0] = gen_rtx_REG (SImode, arm_reg0);
870690075Sobrien  ops[1] = gen_rtx_REG (SImode, 1 + arm_reg0);
870790075Sobrien  output_asm_insn ("stm%?fd\t%|sp!, {%0, %1}", ops);
870890075Sobrien  output_asm_insn ("ldf%?d\t%0, [%|sp], #8", operands);
870990075Sobrien  return "";
871090075Sobrien}
871190075Sobrien
8712132718Skan/* Output a move from an fpa register to arm registers.
871390075Sobrien   OPERANDS[0] is the first registers of an arm register pair.
8714132718Skan   OPERANDS[1] is an fpa register.  */
871590075Sobrienconst char *
8716132718Skanoutput_mov_double_arm_from_fpa (rtx *operands)
871790075Sobrien{
871890075Sobrien  int arm_reg0 = REGNO (operands[0]);
871990075Sobrien  rtx ops[2];
872090075Sobrien
8721169689Skan  gcc_assert (arm_reg0 != IP_REGNUM);
872290075Sobrien
872390075Sobrien  ops[0] = gen_rtx_REG (SImode, arm_reg0);
872490075Sobrien  ops[1] = gen_rtx_REG (SImode, 1 + arm_reg0);
872590075Sobrien  output_asm_insn ("stf%?d\t%1, [%|sp, #-8]!", operands);
872690075Sobrien  output_asm_insn ("ldm%?fd\t%|sp!, {%0, %1}", ops);
872790075Sobrien  return "";
872890075Sobrien}
872990075Sobrien
873090075Sobrien/* Output a move between double words.
873190075Sobrien   It must be REG<-REG, REG<-CONST_DOUBLE, REG<-CONST_INT, REG<-MEM
873290075Sobrien   or MEM<-REG and all MEMs must be offsettable addresses.  */
873390075Sobrienconst char *
8734132718Skanoutput_move_double (rtx *operands)
873590075Sobrien{
873690075Sobrien  enum rtx_code code0 = GET_CODE (operands[0]);
873790075Sobrien  enum rtx_code code1 = GET_CODE (operands[1]);
873890075Sobrien  rtx otherops[3];
873990075Sobrien
874090075Sobrien  if (code0 == REG)
874190075Sobrien    {
874290075Sobrien      int reg0 = REGNO (operands[0]);
874390075Sobrien
874490075Sobrien      otherops[0] = gen_rtx_REG (SImode, 1 + reg0);
874590075Sobrien
8746169689Skan      gcc_assert (code1 == MEM);  /* Constraints should ensure this.  */
8747169689Skan
8748169689Skan      switch (GET_CODE (XEXP (operands[1], 0)))
8749132718Skan	{
8750169689Skan	case REG:
8751169689Skan	  output_asm_insn ("ldm%?ia\t%m1, %M0", operands);
8752169689Skan	  break;
8753132718Skan
8754169689Skan	case PRE_INC:
8755169689Skan	  gcc_assert (TARGET_LDRD);
8756169689Skan	  output_asm_insn ("ldr%?d\t%0, [%m1, #8]!", operands);
8757169689Skan	  break;
8758132718Skan
8759169689Skan	case PRE_DEC:
8760169689Skan	  output_asm_insn ("ldm%?db\t%m1!, %M0", operands);
8761169689Skan	  break;
8762132718Skan
8763169689Skan	case POST_INC:
8764169689Skan	  output_asm_insn ("ldm%?ia\t%m1!, %M0", operands);
8765169689Skan	  break;
8766132718Skan
8767169689Skan	case POST_DEC:
8768169689Skan	  gcc_assert (TARGET_LDRD);
8769169689Skan	  output_asm_insn ("ldr%?d\t%0, [%m1], #-8", operands);
8770169689Skan	  break;
8771132718Skan
8772169689Skan	case PRE_MODIFY:
8773169689Skan	case POST_MODIFY:
8774169689Skan	  otherops[0] = operands[0];
8775169689Skan	  otherops[1] = XEXP (XEXP (XEXP (operands[1], 0), 1), 0);
8776169689Skan	  otherops[2] = XEXP (XEXP (XEXP (operands[1], 0), 1), 1);
8777132718Skan
8778169689Skan	  if (GET_CODE (XEXP (operands[1], 0)) == PRE_MODIFY)
8779169689Skan	    {
8780169689Skan	      if (reg_overlap_mentioned_p (otherops[0], otherops[2]))
8781132718Skan		{
8782169689Skan		  /* Registers overlap so split out the increment.  */
8783169689Skan		  output_asm_insn ("add%?\t%1, %1, %2", otherops);
8784169689Skan		  output_asm_insn ("ldr%?d\t%0, [%1] @split", otherops);
8785132718Skan		}
8786132718Skan	      else
8787132718Skan		{
8788169689Skan		  /* IWMMXT allows offsets larger than ldrd can handle,
8789169689Skan		     fix these up with a pair of ldr.  */
8790169689Skan		  if (GET_CODE (otherops[2]) == CONST_INT
8791169689Skan		      && (INTVAL(otherops[2]) <= -256
8792169689Skan			  || INTVAL(otherops[2]) >= 256))
8793169689Skan		    {
8794169689Skan		      output_asm_insn ("ldr%?\t%0, [%1, %2]!", otherops);
8795169689Skan		      otherops[0] = gen_rtx_REG (SImode, 1 + reg0);
8796169689Skan		      output_asm_insn ("ldr%?\t%0, [%1, #4]", otherops);
8797169689Skan		    }
8798169689Skan		  else
8799169689Skan		    output_asm_insn ("ldr%?d\t%0, [%1, %2]!", otherops);
8800132718Skan		}
8801169689Skan	    }
8802169689Skan	  else
8803169689Skan	    {
8804169689Skan	      /* IWMMXT allows offsets larger than ldrd can handle,
8805169689Skan		 fix these up with a pair of ldr.  */
8806169689Skan	      if (GET_CODE (otherops[2]) == CONST_INT
8807169689Skan		  && (INTVAL(otherops[2]) <= -256
8808169689Skan		      || INTVAL(otherops[2]) >= 256))
8809132718Skan		{
8810169689Skan		  otherops[0] = gen_rtx_REG (SImode, 1 + reg0);
8811169689Skan		  output_asm_insn ("ldr%?\t%0, [%1, #4]", otherops);
8812169689Skan		  otherops[0] = operands[0];
8813169689Skan		  output_asm_insn ("ldr%?\t%0, [%1], %2", otherops);
8814132718Skan		}
8815132718Skan	      else
8816169689Skan		/* We only allow constant increments, so this is safe.  */
8817169689Skan		output_asm_insn ("ldr%?d\t%0, [%1], %2", otherops);
8818132718Skan	    }
8819169689Skan	  break;
882090075Sobrien
8821169689Skan	case LABEL_REF:
8822169689Skan	case CONST:
8823169689Skan	  output_asm_insn ("adr%?\t%0, %1", operands);
8824169689Skan	  output_asm_insn ("ldm%?ia\t%0, %M0", operands);
8825169689Skan	  break;
8826169689Skan
8827169689Skan	default:
8828169689Skan	  if (arm_add_operand (XEXP (XEXP (operands[1], 0), 1),
8829169689Skan			       GET_MODE (XEXP (XEXP (operands[1], 0), 1))))
883090075Sobrien	    {
8831169689Skan	      otherops[0] = operands[0];
8832169689Skan	      otherops[1] = XEXP (XEXP (operands[1], 0), 0);
8833169689Skan	      otherops[2] = XEXP (XEXP (operands[1], 0), 1);
883490075Sobrien
8835169689Skan	      if (GET_CODE (XEXP (operands[1], 0)) == PLUS)
883690075Sobrien		{
8837169689Skan		  if (GET_CODE (otherops[2]) == CONST_INT)
883890075Sobrien		    {
8839169689Skan		      switch ((int) INTVAL (otherops[2]))
884090075Sobrien			{
8841169689Skan			case -8:
8842169689Skan			  output_asm_insn ("ldm%?db\t%1, %M0", otherops);
8843169689Skan			  return "";
8844169689Skan			case -4:
8845169689Skan			  output_asm_insn ("ldm%?da\t%1, %M0", otherops);
8846169689Skan			  return "";
8847169689Skan			case 4:
8848169689Skan			  output_asm_insn ("ldm%?ib\t%1, %M0", otherops);
8849169689Skan			  return "";
885090075Sobrien			}
8851169689Skan		    }
8852169689Skan		  if (TARGET_LDRD
8853169689Skan		      && (GET_CODE (otherops[2]) == REG
8854169689Skan			  || (GET_CODE (otherops[2]) == CONST_INT
8855169689Skan			      && INTVAL (otherops[2]) > -256
8856169689Skan			      && INTVAL (otherops[2]) < 256)))
8857169689Skan		    {
8858169689Skan		      if (reg_overlap_mentioned_p (otherops[0],
8859169689Skan						   otherops[2]))
8860169689Skan			{
8861169689Skan			  /* Swap base and index registers over to
8862169689Skan			     avoid a conflict.  */
8863169689Skan			  otherops[1] = XEXP (XEXP (operands[1], 0), 1);
8864169689Skan			  otherops[2] = XEXP (XEXP (operands[1], 0), 0);
8865169689Skan			}
8866169689Skan		      /* If both registers conflict, it will usually
8867169689Skan			 have been fixed by a splitter.  */
8868169689Skan		      if (reg_overlap_mentioned_p (otherops[0], otherops[2]))
8869169689Skan			{
8870169689Skan			  output_asm_insn ("add%?\t%1, %1, %2", otherops);
8871169689Skan			  output_asm_insn ("ldr%?d\t%0, [%1]",
8872169689Skan					   otherops);
8873169689Skan			}
887490075Sobrien		      else
8875169689Skan			output_asm_insn ("ldr%?d\t%0, [%1, %2]", otherops);
8876169689Skan		      return "";
887790075Sobrien		    }
8878169689Skan
8879169689Skan		  if (GET_CODE (otherops[2]) == CONST_INT)
888090075Sobrien		    {
8881169689Skan		      if (!(const_ok_for_arm (INTVAL (otherops[2]))))
8882169689Skan			output_asm_insn ("sub%?\t%0, %1, #%n2", otherops);
8883169689Skan		      else
8884169689Skan			output_asm_insn ("add%?\t%0, %1, %2", otherops);
888590075Sobrien		    }
888690075Sobrien		  else
8887169689Skan		    output_asm_insn ("add%?\t%0, %1, %2", otherops);
888890075Sobrien		}
8889169689Skan	      else
8890169689Skan		output_asm_insn ("sub%?\t%0, %1, %2", otherops);
8891169689Skan
8892169689Skan	      return "ldm%?ia\t%0, %M0";
889390075Sobrien	    }
8894169689Skan	  else
8895169689Skan	    {
8896169689Skan	      otherops[1] = adjust_address (operands[1], SImode, 4);
8897169689Skan	      /* Take care of overlapping base/data reg.  */
8898169689Skan	      if (reg_mentioned_p (operands[0], operands[1]))
8899169689Skan		{
8900169689Skan		  output_asm_insn ("ldr%?\t%0, %1", otherops);
8901169689Skan		  output_asm_insn ("ldr%?\t%0, %1", operands);
8902169689Skan		}
8903169689Skan	      else
8904169689Skan		{
8905169689Skan		  output_asm_insn ("ldr%?\t%0, %1", operands);
8906169689Skan		  output_asm_insn ("ldr%?\t%0, %1", otherops);
8907169689Skan		}
8908169689Skan	    }
890990075Sobrien	}
891090075Sobrien    }
8911169689Skan  else
891290075Sobrien    {
8913169689Skan      /* Constraints should ensure this.  */
8914169689Skan      gcc_assert (code0 == MEM && code1 == REG);
8915169689Skan      gcc_assert (REGNO (operands[1]) != IP_REGNUM);
891690075Sobrien
891790075Sobrien      switch (GET_CODE (XEXP (operands[0], 0)))
891890075Sobrien        {
891990075Sobrien	case REG:
892090075Sobrien	  output_asm_insn ("stm%?ia\t%m0, %M1", operands);
892190075Sobrien	  break;
892290075Sobrien
892390075Sobrien        case PRE_INC:
8924169689Skan	  gcc_assert (TARGET_LDRD);
8925169689Skan	  output_asm_insn ("str%?d\t%1, [%m0, #8]!", operands);
892690075Sobrien	  break;
892790075Sobrien
892890075Sobrien        case PRE_DEC:
892990075Sobrien	  output_asm_insn ("stm%?db\t%m0!, %M1", operands);
893090075Sobrien	  break;
893190075Sobrien
893290075Sobrien        case POST_INC:
893390075Sobrien	  output_asm_insn ("stm%?ia\t%m0!, %M1", operands);
893490075Sobrien	  break;
893590075Sobrien
893690075Sobrien        case POST_DEC:
8937169689Skan	  gcc_assert (TARGET_LDRD);
8938169689Skan	  output_asm_insn ("str%?d\t%1, [%m0], #-8", operands);
893990075Sobrien	  break;
894090075Sobrien
8941169689Skan	case PRE_MODIFY:
8942169689Skan	case POST_MODIFY:
8943169689Skan	  otherops[0] = operands[1];
8944169689Skan	  otherops[1] = XEXP (XEXP (XEXP (operands[0], 0), 1), 0);
8945169689Skan	  otherops[2] = XEXP (XEXP (XEXP (operands[0], 0), 1), 1);
8946169689Skan
8947169689Skan	  /* IWMMXT allows offsets larger than ldrd can handle,
8948169689Skan	     fix these up with a pair of ldr.  */
8949169689Skan	  if (GET_CODE (otherops[2]) == CONST_INT
8950169689Skan	      && (INTVAL(otherops[2]) <= -256
8951169689Skan		  || INTVAL(otherops[2]) >= 256))
8952169689Skan	    {
8953169689Skan	      rtx reg1;
8954169689Skan	      reg1 = gen_rtx_REG (SImode, 1 + REGNO (operands[1]));
8955169689Skan	      if (GET_CODE (XEXP (operands[0], 0)) == PRE_MODIFY)
8956169689Skan		{
8957169689Skan		  output_asm_insn ("ldr%?\t%0, [%1, %2]!", otherops);
8958169689Skan		  otherops[0] = reg1;
8959169689Skan		  output_asm_insn ("ldr%?\t%0, [%1, #4]", otherops);
8960169689Skan		}
8961169689Skan	      else
8962169689Skan		{
8963169689Skan		  otherops[0] = reg1;
8964169689Skan		  output_asm_insn ("ldr%?\t%0, [%1, #4]", otherops);
8965169689Skan		  otherops[0] = operands[1];
8966169689Skan		  output_asm_insn ("ldr%?\t%0, [%1], %2", otherops);
8967169689Skan		}
8968169689Skan	    }
8969169689Skan	  else if (GET_CODE (XEXP (operands[0], 0)) == PRE_MODIFY)
8970169689Skan	    output_asm_insn ("str%?d\t%0, [%1, %2]!", otherops);
8971169689Skan	  else
8972169689Skan	    output_asm_insn ("str%?d\t%0, [%1], %2", otherops);
8973169689Skan	  break;
8974169689Skan
897590075Sobrien	case PLUS:
8976169689Skan	  otherops[2] = XEXP (XEXP (operands[0], 0), 1);
8977169689Skan	  if (GET_CODE (otherops[2]) == CONST_INT)
897890075Sobrien	    {
8979132718Skan	      switch ((int) INTVAL (XEXP (XEXP (operands[0], 0), 1)))
898090075Sobrien		{
898190075Sobrien		case -8:
898290075Sobrien		  output_asm_insn ("stm%?db\t%m0, %M1", operands);
898390075Sobrien		  return "";
898490075Sobrien
898590075Sobrien		case -4:
898690075Sobrien		  output_asm_insn ("stm%?da\t%m0, %M1", operands);
898790075Sobrien		  return "";
898890075Sobrien
898990075Sobrien		case 4:
899090075Sobrien		  output_asm_insn ("stm%?ib\t%m0, %M1", operands);
899190075Sobrien		  return "";
899290075Sobrien		}
899390075Sobrien	    }
8994169689Skan	  if (TARGET_LDRD
8995169689Skan	      && (GET_CODE (otherops[2]) == REG
8996169689Skan		  || (GET_CODE (otherops[2]) == CONST_INT
8997169689Skan		      && INTVAL (otherops[2]) > -256
8998169689Skan		      && INTVAL (otherops[2]) < 256)))
8999169689Skan	    {
9000169689Skan	      otherops[0] = operands[1];
9001169689Skan	      otherops[1] = XEXP (XEXP (operands[0], 0), 0);
9002169689Skan	      output_asm_insn ("str%?d\t%0, [%1, %2]", otherops);
9003169689Skan	      return "";
9004169689Skan	    }
900590075Sobrien	  /* Fall through */
900690075Sobrien
900790075Sobrien        default:
9008117395Skan	  otherops[0] = adjust_address (operands[0], SImode, 4);
900990075Sobrien	  otherops[1] = gen_rtx_REG (SImode, 1 + REGNO (operands[1]));
901090075Sobrien	  output_asm_insn ("str%?\t%1, %0", operands);
901190075Sobrien	  output_asm_insn ("str%?\t%1, %0", otherops);
901290075Sobrien	}
901390075Sobrien    }
901490075Sobrien
901590075Sobrien  return "";
901690075Sobrien}
901790075Sobrien
901890075Sobrien/* Output an ADD r, s, #n where n may be too big for one instruction.
901990075Sobrien   If adding zero to one register, output nothing.  */
902090075Sobrienconst char *
9021132718Skanoutput_add_immediate (rtx *operands)
902290075Sobrien{
902390075Sobrien  HOST_WIDE_INT n = INTVAL (operands[2]);
902490075Sobrien
902590075Sobrien  if (n != 0 || REGNO (operands[0]) != REGNO (operands[1]))
902690075Sobrien    {
902790075Sobrien      if (n < 0)
902890075Sobrien	output_multi_immediate (operands,
902990075Sobrien				"sub%?\t%0, %1, %2", "sub%?\t%0, %0, %2", 2,
903090075Sobrien				-n);
903190075Sobrien      else
903290075Sobrien	output_multi_immediate (operands,
903390075Sobrien				"add%?\t%0, %1, %2", "add%?\t%0, %0, %2", 2,
903490075Sobrien				n);
903590075Sobrien    }
903690075Sobrien
903790075Sobrien  return "";
903890075Sobrien}
903990075Sobrien
904090075Sobrien/* Output a multiple immediate operation.
904190075Sobrien   OPERANDS is the vector of operands referred to in the output patterns.
904290075Sobrien   INSTR1 is the output pattern to use for the first constant.
904390075Sobrien   INSTR2 is the output pattern to use for subsequent constants.
904490075Sobrien   IMMED_OP is the index of the constant slot in OPERANDS.
904590075Sobrien   N is the constant value.  */
904690075Sobrienstatic const char *
9047132718Skanoutput_multi_immediate (rtx *operands, const char *instr1, const char *instr2,
9048132718Skan			int immed_op, HOST_WIDE_INT n)
904990075Sobrien{
905090075Sobrien#if HOST_BITS_PER_WIDE_INT > 32
905190075Sobrien  n &= 0xffffffff;
905290075Sobrien#endif
905390075Sobrien
905490075Sobrien  if (n == 0)
905590075Sobrien    {
905690075Sobrien      /* Quick and easy output.  */
905790075Sobrien      operands[immed_op] = const0_rtx;
905890075Sobrien      output_asm_insn (instr1, operands);
905990075Sobrien    }
906090075Sobrien  else
906190075Sobrien    {
906290075Sobrien      int i;
906390075Sobrien      const char * instr = instr1;
906490075Sobrien
906590075Sobrien      /* Note that n is never zero here (which would give no output).  */
906690075Sobrien      for (i = 0; i < 32; i += 2)
906790075Sobrien	{
906890075Sobrien	  if (n & (3 << i))
906990075Sobrien	    {
907090075Sobrien	      operands[immed_op] = GEN_INT (n & (255 << i));
907190075Sobrien	      output_asm_insn (instr, operands);
907290075Sobrien	      instr = instr2;
907390075Sobrien	      i += 6;
907490075Sobrien	    }
907590075Sobrien	}
907690075Sobrien    }
9077169689Skan
907890075Sobrien  return "";
907990075Sobrien}
908090075Sobrien
908190075Sobrien/* Return the appropriate ARM instruction for the operation code.
908290075Sobrien   The returned result should not be overwritten.  OP is the rtx of the
908390075Sobrien   operation.  SHIFT_FIRST_ARG is TRUE if the first argument of the operator
908490075Sobrien   was shifted.  */
908590075Sobrienconst char *
9086132718Skanarithmetic_instr (rtx op, int shift_first_arg)
908790075Sobrien{
908890075Sobrien  switch (GET_CODE (op))
908990075Sobrien    {
909090075Sobrien    case PLUS:
909190075Sobrien      return "add";
909290075Sobrien
909390075Sobrien    case MINUS:
909490075Sobrien      return shift_first_arg ? "rsb" : "sub";
909590075Sobrien
909690075Sobrien    case IOR:
909790075Sobrien      return "orr";
909890075Sobrien
909990075Sobrien    case XOR:
910090075Sobrien      return "eor";
910190075Sobrien
910290075Sobrien    case AND:
910390075Sobrien      return "and";
910490075Sobrien
910590075Sobrien    default:
9106169689Skan      gcc_unreachable ();
910790075Sobrien    }
910890075Sobrien}
910990075Sobrien
911090075Sobrien/* Ensure valid constant shifts and return the appropriate shift mnemonic
911190075Sobrien   for the operation code.  The returned result should not be overwritten.
911290075Sobrien   OP is the rtx code of the shift.
911390075Sobrien   On exit, *AMOUNTP will be -1 if the shift is by a register, or a constant
911490075Sobrien   shift.  */
911590075Sobrienstatic const char *
9116132718Skanshift_op (rtx op, HOST_WIDE_INT *amountp)
911790075Sobrien{
911890075Sobrien  const char * mnem;
911990075Sobrien  enum rtx_code code = GET_CODE (op);
912090075Sobrien
9121169689Skan  switch (GET_CODE (XEXP (op, 1)))
9122169689Skan    {
9123169689Skan    case REG:
9124169689Skan    case SUBREG:
9125169689Skan      *amountp = -1;
9126169689Skan      break;
912790075Sobrien
9128169689Skan    case CONST_INT:
9129169689Skan      *amountp = INTVAL (XEXP (op, 1));
9130169689Skan      break;
9131169689Skan
9132169689Skan    default:
9133169689Skan      gcc_unreachable ();
9134169689Skan    }
9135169689Skan
913690075Sobrien  switch (code)
913790075Sobrien    {
913890075Sobrien    case ASHIFT:
913990075Sobrien      mnem = "asl";
914090075Sobrien      break;
914190075Sobrien
914290075Sobrien    case ASHIFTRT:
914390075Sobrien      mnem = "asr";
914490075Sobrien      break;
914590075Sobrien
914690075Sobrien    case LSHIFTRT:
914790075Sobrien      mnem = "lsr";
914890075Sobrien      break;
914990075Sobrien
9150169689Skan    case ROTATE:
9151169689Skan      gcc_assert (*amountp != -1);
9152169689Skan      *amountp = 32 - *amountp;
9153169689Skan
9154169689Skan      /* Fall through.  */
9155169689Skan
915690075Sobrien    case ROTATERT:
915790075Sobrien      mnem = "ror";
915890075Sobrien      break;
915990075Sobrien
916090075Sobrien    case MULT:
916190075Sobrien      /* We never have to worry about the amount being other than a
916290075Sobrien	 power of 2, since this case can never be reloaded from a reg.  */
9163169689Skan      gcc_assert (*amountp != -1);
9164169689Skan      *amountp = int_log2 (*amountp);
916590075Sobrien      return "asl";
916690075Sobrien
916790075Sobrien    default:
9168169689Skan      gcc_unreachable ();
916990075Sobrien    }
917090075Sobrien
917190075Sobrien  if (*amountp != -1)
917290075Sobrien    {
917390075Sobrien      /* This is not 100% correct, but follows from the desire to merge
917490075Sobrien	 multiplication by a power of 2 with the recognizer for a
917590075Sobrien	 shift.  >=32 is not a valid shift for "asl", so we must try and
917690075Sobrien	 output a shift that produces the correct arithmetical result.
917790075Sobrien	 Using lsr #32 is identical except for the fact that the carry bit
9178169689Skan	 is not set correctly if we set the flags; but we never use the
917990075Sobrien	 carry bit from such an operation, so we can ignore that.  */
918090075Sobrien      if (code == ROTATERT)
918190075Sobrien	/* Rotate is just modulo 32.  */
918290075Sobrien	*amountp &= 31;
918390075Sobrien      else if (*amountp != (*amountp & 31))
918490075Sobrien	{
918590075Sobrien	  if (code == ASHIFT)
918690075Sobrien	    mnem = "lsr";
918790075Sobrien	  *amountp = 32;
918890075Sobrien	}
918990075Sobrien
919090075Sobrien      /* Shifts of 0 are no-ops.  */
919190075Sobrien      if (*amountp == 0)
919290075Sobrien	return NULL;
9193169689Skan    }
919490075Sobrien
919590075Sobrien  return mnem;
919690075Sobrien}
919790075Sobrien
919890075Sobrien/* Obtain the shift from the POWER of two.  */
919990075Sobrien
920090075Sobrienstatic HOST_WIDE_INT
9201132718Skanint_log2 (HOST_WIDE_INT power)
920290075Sobrien{
920390075Sobrien  HOST_WIDE_INT shift = 0;
920490075Sobrien
920590075Sobrien  while ((((HOST_WIDE_INT) 1 << shift) & power) == 0)
920690075Sobrien    {
9207169689Skan      gcc_assert (shift <= 31);
9208132718Skan      shift++;
920990075Sobrien    }
921090075Sobrien
921190075Sobrien  return shift;
921290075Sobrien}
921390075Sobrien
9214169689Skan/* Output a .ascii pseudo-op, keeping track of lengths.  This is
9215169689Skan   because /bin/as is horribly restrictive.  The judgement about
9216169689Skan   whether or not each character is 'printable' (and can be output as
9217169689Skan   is) or not (and must be printed with an octal escape) must be made
9218169689Skan   with reference to the *host* character set -- the situation is
9219169689Skan   similar to that discussed in the comments above pp_c_char in
9220169689Skan   c-pretty-print.c.  */
9221169689Skan
922290075Sobrien#define MAX_ASCII_LEN 51
922390075Sobrien
922490075Sobrienvoid
9225132718Skanoutput_ascii_pseudo_op (FILE *stream, const unsigned char *p, int len)
922690075Sobrien{
922790075Sobrien  int i;
922890075Sobrien  int len_so_far = 0;
922990075Sobrien
923090075Sobrien  fputs ("\t.ascii\t\"", stream);
9231169689Skan
923290075Sobrien  for (i = 0; i < len; i++)
923390075Sobrien    {
923490075Sobrien      int c = p[i];
923590075Sobrien
923690075Sobrien      if (len_so_far >= MAX_ASCII_LEN)
923790075Sobrien	{
923890075Sobrien	  fputs ("\"\n\t.ascii\t\"", stream);
923990075Sobrien	  len_so_far = 0;
924090075Sobrien	}
924190075Sobrien
9242169689Skan      if (ISPRINT (c))
924390075Sobrien	{
9244169689Skan	  if (c == '\\' || c == '\"')
924590075Sobrien	    {
9246169689Skan	      putc ('\\', stream);
924790075Sobrien	      len_so_far++;
924890075Sobrien	    }
9249169689Skan	  putc (c, stream);
9250169689Skan	  len_so_far++;
925190075Sobrien	}
9252169689Skan      else
9253169689Skan	{
9254169689Skan	  fprintf (stream, "\\%03o", c);
9255169689Skan	  len_so_far += 4;
9256169689Skan	}
925790075Sobrien    }
925890075Sobrien
925990075Sobrien  fputs ("\"\n", stream);
926090075Sobrien}
926190075Sobrien
9262169689Skan/* Compute the register save mask for registers 0 through 12
9263169689Skan   inclusive.  This code is used by arm_compute_save_reg_mask.  */
9264169689Skan
926590075Sobrienstatic unsigned long
9266132718Skanarm_compute_save_reg0_reg12_mask (void)
926790075Sobrien{
926890075Sobrien  unsigned long func_type = arm_current_func_type ();
9269169689Skan  unsigned long save_reg_mask = 0;
927090075Sobrien  unsigned int reg;
927190075Sobrien
927290075Sobrien  if (IS_INTERRUPT (func_type))
927390075Sobrien    {
927490075Sobrien      unsigned int max_reg;
927590075Sobrien      /* Interrupt functions must not corrupt any registers,
927690075Sobrien	 even call clobbered ones.  If this is a leaf function
927790075Sobrien	 we can just examine the registers used by the RTL, but
927890075Sobrien	 otherwise we have to assume that whatever function is
927990075Sobrien	 called might clobber anything, and so we have to save
928090075Sobrien	 all the call-clobbered registers as well.  */
928190075Sobrien      if (ARM_FUNC_TYPE (func_type) == ARM_FT_FIQ)
928290075Sobrien	/* FIQ handlers have registers r8 - r12 banked, so
928390075Sobrien	   we only need to check r0 - r7, Normal ISRs only
928490075Sobrien	   bank r14 and r15, so we must check up to r12.
928590075Sobrien	   r13 is the stack pointer which is always preserved,
928690075Sobrien	   so we do not need to consider it here.  */
928790075Sobrien	max_reg = 7;
928890075Sobrien      else
928990075Sobrien	max_reg = 12;
9290169689Skan
929190075Sobrien      for (reg = 0; reg <= max_reg; reg++)
929290075Sobrien	if (regs_ever_live[reg]
929390075Sobrien	    || (! current_function_is_leaf && call_used_regs [reg]))
929490075Sobrien	  save_reg_mask |= (1 << reg);
9295169689Skan
9296169689Skan      /* Also save the pic base register if necessary.  */
9297169689Skan      if (flag_pic
9298169689Skan	  && !TARGET_SINGLE_PIC_BASE
9299169689Skan	  && arm_pic_register != INVALID_REGNUM
9300169689Skan	  && current_function_uses_pic_offset_table)
9301169689Skan	save_reg_mask |= 1 << PIC_OFFSET_TABLE_REGNUM;
930290075Sobrien    }
930390075Sobrien  else
930490075Sobrien    {
930590075Sobrien      /* In the normal case we only need to save those registers
930690075Sobrien	 which are call saved and which are used by this function.  */
930790075Sobrien      for (reg = 0; reg <= 10; reg++)
930890075Sobrien	if (regs_ever_live[reg] && ! call_used_regs [reg])
930990075Sobrien	  save_reg_mask |= (1 << reg);
931090075Sobrien
931190075Sobrien      /* Handle the frame pointer as a special case.  */
931290075Sobrien      if (! TARGET_APCS_FRAME
931390075Sobrien	  && ! frame_pointer_needed
931490075Sobrien	  && regs_ever_live[HARD_FRAME_POINTER_REGNUM]
931590075Sobrien	  && ! call_used_regs[HARD_FRAME_POINTER_REGNUM])
931690075Sobrien	save_reg_mask |= 1 << HARD_FRAME_POINTER_REGNUM;
931790075Sobrien
931890075Sobrien      /* If we aren't loading the PIC register,
931990075Sobrien	 don't stack it even though it may be live.  */
932090075Sobrien      if (flag_pic
9321169689Skan	  && !TARGET_SINGLE_PIC_BASE
9322169689Skan	  && arm_pic_register != INVALID_REGNUM
9323169689Skan	  && (regs_ever_live[PIC_OFFSET_TABLE_REGNUM]
9324169689Skan	      || current_function_uses_pic_offset_table))
932590075Sobrien	save_reg_mask |= 1 << PIC_OFFSET_TABLE_REGNUM;
932690075Sobrien    }
932790075Sobrien
9328169689Skan  /* Save registers so the exception handler can modify them.  */
9329169689Skan  if (current_function_calls_eh_return)
9330169689Skan    {
9331169689Skan      unsigned int i;
9332169689Skan
9333169689Skan      for (i = 0; ; i++)
9334169689Skan	{
9335169689Skan	  reg = EH_RETURN_DATA_REGNO (i);
9336169689Skan	  if (reg == INVALID_REGNUM)
9337169689Skan	    break;
9338169689Skan	  save_reg_mask |= 1 << reg;
9339169689Skan	}
9340169689Skan    }
9341169689Skan
934290075Sobrien  return save_reg_mask;
934390075Sobrien}
934490075Sobrien
934590075Sobrien/* Compute a bit mask of which registers need to be
934690075Sobrien   saved on the stack for the current function.  */
934790075Sobrien
934890075Sobrienstatic unsigned long
9349132718Skanarm_compute_save_reg_mask (void)
935090075Sobrien{
935190075Sobrien  unsigned int save_reg_mask = 0;
935290075Sobrien  unsigned long func_type = arm_current_func_type ();
935390075Sobrien
935490075Sobrien  if (IS_NAKED (func_type))
935590075Sobrien    /* This should never really happen.  */
935690075Sobrien    return 0;
935790075Sobrien
935890075Sobrien  /* If we are creating a stack frame, then we must save the frame pointer,
935990075Sobrien     IP (which will hold the old stack pointer), LR and the PC.  */
936090075Sobrien  if (frame_pointer_needed)
936190075Sobrien    save_reg_mask |=
936290075Sobrien      (1 << ARM_HARD_FRAME_POINTER_REGNUM)
936390075Sobrien      | (1 << IP_REGNUM)
936490075Sobrien      | (1 << LR_REGNUM)
936590075Sobrien      | (1 << PC_REGNUM);
936690075Sobrien
936790075Sobrien  /* Volatile functions do not return, so there
936890075Sobrien     is no need to save any other registers.  */
936990075Sobrien  if (IS_VOLATILE (func_type))
937090075Sobrien    return save_reg_mask;
937190075Sobrien
937290075Sobrien  save_reg_mask |= arm_compute_save_reg0_reg12_mask ();
937390075Sobrien
937490075Sobrien  /* Decide if we need to save the link register.
937590075Sobrien     Interrupt routines have their own banked link register,
937690075Sobrien     so they never need to save it.
937796263Sobrien     Otherwise if we do not use the link register we do not need to save
937890075Sobrien     it.  If we are pushing other registers onto the stack however, we
937990075Sobrien     can save an instruction in the epilogue by pushing the link register
938090075Sobrien     now and then popping it back into the PC.  This incurs extra memory
9381132718Skan     accesses though, so we only do it when optimizing for size, and only
938290075Sobrien     if we know that we will not need a fancy return sequence.  */
938396263Sobrien  if (regs_ever_live [LR_REGNUM]
938490075Sobrien	  || (save_reg_mask
938590075Sobrien	      && optimize_size
9386169689Skan	      && ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL
9387169689Skan	      && !current_function_calls_eh_return))
938890075Sobrien    save_reg_mask |= 1 << LR_REGNUM;
938990075Sobrien
939090075Sobrien  if (cfun->machine->lr_save_eliminated)
939190075Sobrien    save_reg_mask &= ~ (1 << LR_REGNUM);
939290075Sobrien
9393132718Skan  if (TARGET_REALLY_IWMMXT
9394132718Skan      && ((bit_count (save_reg_mask)
9395132718Skan	   + ARM_NUM_INTS (current_function_pretend_args_size)) % 2) != 0)
9396132718Skan    {
9397132718Skan      unsigned int reg;
9398132718Skan
9399132718Skan      /* The total number of registers that are going to be pushed
9400132718Skan	 onto the stack is odd.  We need to ensure that the stack
9401132718Skan	 is 64-bit aligned before we start to save iWMMXt registers,
9402132718Skan	 and also before we start to create locals.  (A local variable
9403132718Skan	 might be a double or long long which we will load/store using
9404132718Skan	 an iWMMXt instruction).  Therefore we need to push another
9405132718Skan	 ARM register, so that the stack will be 64-bit aligned.  We
9406132718Skan	 try to avoid using the arg registers (r0 -r3) as they might be
9407132718Skan	 used to pass values in a tail call.  */
9408132718Skan      for (reg = 4; reg <= 12; reg++)
9409132718Skan	if ((save_reg_mask & (1 << reg)) == 0)
9410132718Skan	  break;
9411132718Skan
9412132718Skan      if (reg <= 12)
9413132718Skan	save_reg_mask |= (1 << reg);
9414132718Skan      else
9415132718Skan	{
9416132718Skan	  cfun->machine->sibcall_blocked = 1;
9417132718Skan	  save_reg_mask |= (1 << 3);
9418132718Skan	}
9419132718Skan    }
9420132718Skan
942190075Sobrien  return save_reg_mask;
942290075Sobrien}
942390075Sobrien
9424169689Skan
9425169689Skan/* Compute a bit mask of which registers need to be
9426169689Skan   saved on the stack for the current function.  */
9427169689Skanstatic unsigned long
9428169689Skanthumb_compute_save_reg_mask (void)
9429169689Skan{
9430169689Skan  unsigned long mask;
9431169689Skan  unsigned reg;
9432169689Skan
9433169689Skan  mask = 0;
9434169689Skan  for (reg = 0; reg < 12; reg ++)
9435169689Skan    if (regs_ever_live[reg] && !call_used_regs[reg])
9436169689Skan      mask |= 1 << reg;
9437169689Skan
9438169689Skan  if (flag_pic
9439169689Skan      && !TARGET_SINGLE_PIC_BASE
9440169689Skan      && arm_pic_register != INVALID_REGNUM
9441169689Skan      && current_function_uses_pic_offset_table)
9442169689Skan    mask |= 1 << PIC_OFFSET_TABLE_REGNUM;
9443169689Skan
9444169689Skan  /* See if we might need r11 for calls to _interwork_r11_call_via_rN().  */
9445169689Skan  if (!frame_pointer_needed && CALLER_INTERWORKING_SLOT_SIZE > 0)
9446169689Skan    mask |= 1 << ARM_HARD_FRAME_POINTER_REGNUM;
9447169689Skan
9448169689Skan  /* LR will also be pushed if any lo regs are pushed.  */
9449169689Skan  if (mask & 0xff || thumb_force_lr_save ())
9450169689Skan    mask |= (1 << LR_REGNUM);
9451169689Skan
9452169689Skan  /* Make sure we have a low work register if we need one.
9453169689Skan     We will need one if we are going to push a high register,
9454169689Skan     but we are not currently intending to push a low register.  */
9455169689Skan  if ((mask & 0xff) == 0
9456169689Skan      && ((mask & 0x0f00) || TARGET_BACKTRACE))
9457169689Skan    {
9458169689Skan      /* Use thumb_find_work_register to choose which register
9459169689Skan	 we will use.  If the register is live then we will
9460169689Skan	 have to push it.  Use LAST_LO_REGNUM as our fallback
9461169689Skan	 choice for the register to select.  */
9462169689Skan      reg = thumb_find_work_register (1 << LAST_LO_REGNUM);
9463169689Skan
9464169689Skan      if (! call_used_regs[reg])
9465169689Skan	mask |= 1 << reg;
9466169689Skan    }
9467169689Skan
9468169689Skan  return mask;
9469169689Skan}
9470169689Skan
9471169689Skan
9472169689Skan/* Return the number of bytes required to save VFP registers.  */
9473169689Skanstatic int
9474169689Skanarm_get_vfp_saved_size (void)
9475169689Skan{
9476169689Skan  unsigned int regno;
9477169689Skan  int count;
9478169689Skan  int saved;
9479169689Skan
9480169689Skan  saved = 0;
9481169689Skan  /* Space for saved VFP registers.  */
9482169689Skan  if (TARGET_HARD_FLOAT && TARGET_VFP)
9483169689Skan    {
9484169689Skan      count = 0;
9485169689Skan      for (regno = FIRST_VFP_REGNUM;
9486169689Skan	   regno < LAST_VFP_REGNUM;
9487169689Skan	   regno += 2)
9488169689Skan	{
9489169689Skan	  if ((!regs_ever_live[regno] || call_used_regs[regno])
9490169689Skan	      && (!regs_ever_live[regno + 1] || call_used_regs[regno + 1]))
9491169689Skan	    {
9492169689Skan	      if (count > 0)
9493169689Skan		{
9494169689Skan		  /* Workaround ARM10 VFPr1 bug.  */
9495169689Skan		  if (count == 2 && !arm_arch6)
9496169689Skan		    count++;
9497169689Skan		  saved += count * 8 + 4;
9498169689Skan		}
9499169689Skan	      count = 0;
9500169689Skan	    }
9501169689Skan	  else
9502169689Skan	    count++;
9503169689Skan	}
9504169689Skan      if (count > 0)
9505169689Skan	{
9506169689Skan	  if (count == 2 && !arm_arch6)
9507169689Skan	    count++;
9508169689Skan	  saved += count * 8 + 4;
9509169689Skan	}
9510169689Skan    }
9511169689Skan  return saved;
9512169689Skan}
9513169689Skan
9514169689Skan
9515132718Skan/* Generate a function exit sequence.  If REALLY_RETURN is false, then do
951690075Sobrien   everything bar the final return instruction.  */
951790075Sobrienconst char *
9518132718Skanoutput_return_instruction (rtx operand, int really_return, int reverse)
951990075Sobrien{
952090075Sobrien  char conditional[10];
952190075Sobrien  char instr[100];
9522169689Skan  unsigned reg;
952390075Sobrien  unsigned long live_regs_mask;
952490075Sobrien  unsigned long func_type;
9525169689Skan  arm_stack_offsets *offsets;
9526117395Skan
952790075Sobrien  func_type = arm_current_func_type ();
952890075Sobrien
952990075Sobrien  if (IS_NAKED (func_type))
953090075Sobrien    return "";
953190075Sobrien
953290075Sobrien  if (IS_VOLATILE (func_type) && TARGET_ABORT_NORETURN)
953390075Sobrien    {
9534132718Skan      /* If this function was declared non-returning, and we have
9535132718Skan	 found a tail call, then we have to trust that the called
9536132718Skan	 function won't return.  */
953790075Sobrien      if (really_return)
953890075Sobrien	{
953990075Sobrien	  rtx ops[2];
9540169689Skan
954190075Sobrien	  /* Otherwise, trap an attempted return by aborting.  */
954290075Sobrien	  ops[0] = operand;
9543169689Skan	  ops[1] = gen_rtx_SYMBOL_REF (Pmode, NEED_PLT_RELOC ? "abort(PLT)"
954490075Sobrien				       : "abort");
954590075Sobrien	  assemble_external_libcall (ops[1]);
954690075Sobrien	  output_asm_insn (reverse ? "bl%D0\t%a1" : "bl%d0\t%a1", ops);
954790075Sobrien	}
9548169689Skan
954990075Sobrien      return "";
955090075Sobrien    }
955190075Sobrien
9552169689Skan  gcc_assert (!current_function_calls_alloca || really_return);
955390075Sobrien
955490075Sobrien  sprintf (conditional, "%%?%%%c0", reverse ? 'D' : 'd');
955590075Sobrien
955690075Sobrien  return_used_this_function = 1;
955790075Sobrien
955890075Sobrien  live_regs_mask = arm_compute_save_reg_mask ();
955990075Sobrien
956096263Sobrien  if (live_regs_mask)
956190075Sobrien    {
956296263Sobrien      const char * return_reg;
956396263Sobrien
9564169689Skan      /* If we do not have any special requirements for function exit
9565169689Skan	 (e.g. interworking, or ISR) then we can load the return address
956696263Sobrien	 directly into the PC.  Otherwise we must load it into LR.  */
956796263Sobrien      if (really_return
956896263Sobrien	  && ! TARGET_INTERWORK)
956996263Sobrien	return_reg = reg_names[PC_REGNUM];
957090075Sobrien      else
957196263Sobrien	return_reg = reg_names[LR_REGNUM];
957296263Sobrien
957390075Sobrien      if ((live_regs_mask & (1 << IP_REGNUM)) == (1 << IP_REGNUM))
9574132718Skan	{
9575132718Skan	  /* There are three possible reasons for the IP register
9576132718Skan	     being saved.  1) a stack frame was created, in which case
9577132718Skan	     IP contains the old stack pointer, or 2) an ISR routine
9578132718Skan	     corrupted it, or 3) it was saved to align the stack on
9579132718Skan	     iWMMXt.  In case 1, restore IP into SP, otherwise just
9580132718Skan	     restore IP.  */
9581132718Skan	  if (frame_pointer_needed)
9582132718Skan	    {
9583132718Skan	      live_regs_mask &= ~ (1 << IP_REGNUM);
9584132718Skan	      live_regs_mask |=   (1 << SP_REGNUM);
9585132718Skan	    }
9586132718Skan	  else
9587169689Skan	    gcc_assert (IS_INTERRUPT (func_type) || TARGET_REALLY_IWMMXT);
9588132718Skan	}
958990075Sobrien
959096263Sobrien      /* On some ARM architectures it is faster to use LDR rather than
959196263Sobrien	 LDM to load a single register.  On other architectures, the
959296263Sobrien	 cost is the same.  In 26 bit mode, or for exception handlers,
959396263Sobrien	 we have to use LDM to load the PC so that the CPSR is also
959496263Sobrien	 restored.  */
959596263Sobrien      for (reg = 0; reg <= LAST_ARM_REGNUM; reg++)
9596169689Skan	if (live_regs_mask == (1U << reg))
9597169689Skan	  break;
9598169689Skan
959996263Sobrien      if (reg <= LAST_ARM_REGNUM
960096263Sobrien	  && (reg != LR_REGNUM
9601169689Skan	      || ! really_return
9602169689Skan	      || ! IS_INTERRUPT (func_type)))
960396263Sobrien	{
9604169689Skan	  sprintf (instr, "ldr%s\t%%|%s, [%%|sp], #4", conditional,
960596263Sobrien		   (reg == LR_REGNUM) ? return_reg : reg_names[reg]);
960696263Sobrien	}
960790075Sobrien      else
960890075Sobrien	{
960996263Sobrien	  char *p;
961096263Sobrien	  int first = 1;
961190075Sobrien
9612132718Skan	  /* Generate the load multiple instruction to restore the
9613132718Skan	     registers.  Note we can get here, even if
9614132718Skan	     frame_pointer_needed is true, but only if sp already
9615132718Skan	     points to the base of the saved core registers.  */
9616132718Skan	  if (live_regs_mask & (1 << SP_REGNUM))
9617132718Skan	    {
9618169689Skan	      unsigned HOST_WIDE_INT stack_adjust;
9619132718Skan
9620169689Skan	      offsets = arm_get_frame_offsets ();
9621169689Skan	      stack_adjust = offsets->outgoing_args - offsets->saved_regs;
9622169689Skan	      gcc_assert (stack_adjust == 0 || stack_adjust == 4);
9623169689Skan
9624132718Skan	      if (stack_adjust && arm_arch5)
9625132718Skan		sprintf (instr, "ldm%sib\t%%|sp, {", conditional);
9626132718Skan	      else
9627132718Skan		{
9628169689Skan		  /* If we can't use ldmib (SA110 bug),
9629169689Skan		     then try to pop r3 instead.  */
9630132718Skan		  if (stack_adjust)
9631132718Skan		    live_regs_mask |= 1 << 3;
9632132718Skan		  sprintf (instr, "ldm%sfd\t%%|sp, {", conditional);
9633132718Skan		}
9634132718Skan	    }
963590075Sobrien	  else
963696263Sobrien	    sprintf (instr, "ldm%sfd\t%%|sp!, {", conditional);
963790075Sobrien
963896263Sobrien	  p = instr + strlen (instr);
963990075Sobrien
964096263Sobrien	  for (reg = 0; reg <= SP_REGNUM; reg++)
964196263Sobrien	    if (live_regs_mask & (1 << reg))
964296263Sobrien	      {
964396263Sobrien		int l = strlen (reg_names[reg]);
964490075Sobrien
964596263Sobrien		if (first)
964696263Sobrien		  first = 0;
964796263Sobrien		else
964896263Sobrien		  {
964996263Sobrien		    memcpy (p, ", ", 2);
965096263Sobrien		    p += 2;
965196263Sobrien		  }
965290075Sobrien
965396263Sobrien		memcpy (p, "%|", 2);
965496263Sobrien		memcpy (p + 2, reg_names[reg], l);
965596263Sobrien		p += l + 2;
965696263Sobrien	      }
9657169689Skan
965896263Sobrien	  if (live_regs_mask & (1 << LR_REGNUM))
965996263Sobrien	    {
9660132718Skan	      sprintf (p, "%s%%|%s}", first ? "" : ", ", return_reg);
9661169689Skan	      /* If returning from an interrupt, restore the CPSR.  */
9662169689Skan	      if (IS_INTERRUPT (func_type))
9663132718Skan		strcat (p, "^");
966490075Sobrien	    }
966596263Sobrien	  else
966696263Sobrien	    strcpy (p, "}");
966790075Sobrien	}
966896263Sobrien
966996263Sobrien      output_asm_insn (instr, & operand);
967096263Sobrien
967196263Sobrien      /* See if we need to generate an extra instruction to
967296263Sobrien	 perform the actual function return.  */
967396263Sobrien      if (really_return
967496263Sobrien	  && func_type != ARM_FT_INTERWORKED
967596263Sobrien	  && (live_regs_mask & (1 << LR_REGNUM)) != 0)
967696263Sobrien	{
967796263Sobrien	  /* The return has already been handled
967896263Sobrien	     by loading the LR into the PC.  */
967996263Sobrien	  really_return = 0;
968096263Sobrien	}
968190075Sobrien    }
9682117395Skan
968396263Sobrien  if (really_return)
968490075Sobrien    {
968590075Sobrien      switch ((int) ARM_FUNC_TYPE (func_type))
968690075Sobrien	{
968790075Sobrien	case ARM_FT_ISR:
968890075Sobrien	case ARM_FT_FIQ:
968990075Sobrien	  sprintf (instr, "sub%ss\t%%|pc, %%|lr, #4", conditional);
969090075Sobrien	  break;
969190075Sobrien
969290075Sobrien	case ARM_FT_INTERWORKED:
969390075Sobrien	  sprintf (instr, "bx%s\t%%|lr", conditional);
969490075Sobrien	  break;
969590075Sobrien
969690075Sobrien	case ARM_FT_EXCEPTION:
969790075Sobrien	  sprintf (instr, "mov%ss\t%%|pc, %%|lr", conditional);
969890075Sobrien	  break;
969990075Sobrien
970090075Sobrien	default:
9701169689Skan	  /* Use bx if it's available.  */
9702169689Skan	  if (arm_arch5 || arm_arch4t)
9703169689Skan	    sprintf (instr, "bx%s\t%%|lr", conditional);
970496263Sobrien	  else
9705169689Skan	    sprintf (instr, "mov%s\t%%|pc, %%|lr", conditional);
970690075Sobrien	  break;
970790075Sobrien	}
970896263Sobrien
970996263Sobrien      output_asm_insn (instr, & operand);
971090075Sobrien    }
971190075Sobrien
971290075Sobrien  return "";
971390075Sobrien}
971490075Sobrien
971590075Sobrien/* Write the function name into the code section, directly preceding
971690075Sobrien   the function prologue.
971790075Sobrien
971890075Sobrien   Code will be output similar to this:
971990075Sobrien     t0
972090075Sobrien	 .ascii "arm_poke_function_name", 0
972190075Sobrien	 .align
972290075Sobrien     t1
972390075Sobrien	 .word 0xff000000 + (t1 - t0)
972490075Sobrien     arm_poke_function_name
972590075Sobrien	 mov     ip, sp
972690075Sobrien	 stmfd   sp!, {fp, ip, lr, pc}
972790075Sobrien	 sub     fp, ip, #4
972890075Sobrien
972990075Sobrien   When performing a stack backtrace, code can inspect the value
973090075Sobrien   of 'pc' stored at 'fp' + 0.  If the trace function then looks
973190075Sobrien   at location pc - 12 and the top 8 bits are set, then we know
973290075Sobrien   that there is a function name embedded immediately preceding this
973390075Sobrien   location and has length ((pc[-3]) & 0xff000000).
973490075Sobrien
973590075Sobrien   We assume that pc is declared as a pointer to an unsigned long.
973690075Sobrien
973790075Sobrien   It is of no benefit to output the function name if we are assembling
973890075Sobrien   a leaf function.  These function types will not contain a stack
973990075Sobrien   backtrace structure, therefore it is not possible to determine the
974090075Sobrien   function name.  */
974190075Sobrienvoid
9742132718Skanarm_poke_function_name (FILE *stream, const char *name)
974390075Sobrien{
974490075Sobrien  unsigned long alignlength;
974590075Sobrien  unsigned long length;
974690075Sobrien  rtx           x;
974790075Sobrien
974890075Sobrien  length      = strlen (name) + 1;
9749132718Skan  alignlength = ROUND_UP_WORD (length);
9750169689Skan
975190075Sobrien  ASM_OUTPUT_ASCII (stream, name, length);
975290075Sobrien  ASM_OUTPUT_ALIGN (stream, 2);
975390075Sobrien  x = GEN_INT ((unsigned HOST_WIDE_INT) 0xff000000 + alignlength);
975490075Sobrien  assemble_aligned_integer (UNITS_PER_WORD, x);
975590075Sobrien}
975690075Sobrien
975790075Sobrien/* Place some comments into the assembler stream
975890075Sobrien   describing the current function.  */
975990075Sobrienstatic void
9760132718Skanarm_output_function_prologue (FILE *f, HOST_WIDE_INT frame_size)
976190075Sobrien{
976290075Sobrien  unsigned long func_type;
976390075Sobrien
976490075Sobrien  if (!TARGET_ARM)
976590075Sobrien    {
976690075Sobrien      thumb_output_function_prologue (f, frame_size);
976790075Sobrien      return;
976890075Sobrien    }
9769169689Skan
977090075Sobrien  /* Sanity check.  */
9771169689Skan  gcc_assert (!arm_ccfsm_state && !arm_target_insn);
977290075Sobrien
977390075Sobrien  func_type = arm_current_func_type ();
9774169689Skan
977590075Sobrien  switch ((int) ARM_FUNC_TYPE (func_type))
977690075Sobrien    {
977790075Sobrien    default:
977890075Sobrien    case ARM_FT_NORMAL:
977990075Sobrien      break;
978090075Sobrien    case ARM_FT_INTERWORKED:
978190075Sobrien      asm_fprintf (f, "\t%@ Function supports interworking.\n");
978290075Sobrien      break;
978390075Sobrien    case ARM_FT_ISR:
978490075Sobrien      asm_fprintf (f, "\t%@ Interrupt Service Routine.\n");
978590075Sobrien      break;
978690075Sobrien    case ARM_FT_FIQ:
978790075Sobrien      asm_fprintf (f, "\t%@ Fast Interrupt Service Routine.\n");
978890075Sobrien      break;
978990075Sobrien    case ARM_FT_EXCEPTION:
979090075Sobrien      asm_fprintf (f, "\t%@ ARM Exception Handler.\n");
979190075Sobrien      break;
979290075Sobrien    }
9793169689Skan
979490075Sobrien  if (IS_NAKED (func_type))
979590075Sobrien    asm_fprintf (f, "\t%@ Naked Function: prologue and epilogue provided by programmer.\n");
979690075Sobrien
979790075Sobrien  if (IS_VOLATILE (func_type))
979890075Sobrien    asm_fprintf (f, "\t%@ Volatile: function does not return.\n");
979990075Sobrien
980090075Sobrien  if (IS_NESTED (func_type))
980190075Sobrien    asm_fprintf (f, "\t%@ Nested: function declared inside another function.\n");
9802169689Skan
9803132718Skan  asm_fprintf (f, "\t%@ args = %d, pretend = %d, frame = %wd\n",
980490075Sobrien	       current_function_args_size,
980590075Sobrien	       current_function_pretend_args_size, frame_size);
980690075Sobrien
980796263Sobrien  asm_fprintf (f, "\t%@ frame_needed = %d, uses_anonymous_args = %d\n",
980890075Sobrien	       frame_pointer_needed,
980996263Sobrien	       cfun->machine->uses_anonymous_args);
981090075Sobrien
981190075Sobrien  if (cfun->machine->lr_save_eliminated)
981290075Sobrien    asm_fprintf (f, "\t%@ link register save eliminated.\n");
981390075Sobrien
9814169689Skan  if (current_function_calls_eh_return)
9815169689Skan    asm_fprintf (f, "\t@ Calls __builtin_eh_return.\n");
9816169689Skan
981790075Sobrien#ifdef AOF_ASSEMBLER
981890075Sobrien  if (flag_pic)
981990075Sobrien    asm_fprintf (f, "\tmov\t%r, %r\n", IP_REGNUM, PIC_OFFSET_TABLE_REGNUM);
982090075Sobrien#endif
982190075Sobrien
9822169689Skan  return_used_this_function = 0;
982390075Sobrien}
982490075Sobrien
982590075Sobrienconst char *
9826132718Skanarm_output_epilogue (rtx sibling)
982790075Sobrien{
982890075Sobrien  int reg;
982990075Sobrien  unsigned long saved_regs_mask;
983090075Sobrien  unsigned long func_type;
9831169689Skan  /* Floats_offset is the offset from the "virtual" frame.  In an APCS
983296263Sobrien     frame that is $fp + 4 for a non-variadic function.  */
983396263Sobrien  int floats_offset = 0;
983490075Sobrien  rtx operands[3];
983590075Sobrien  FILE * f = asm_out_file;
9836132718Skan  unsigned int lrm_count = 0;
9837132718Skan  int really_return = (sibling == NULL);
9838169689Skan  int start_reg;
9839169689Skan  arm_stack_offsets *offsets;
984090075Sobrien
984190075Sobrien  /* If we have already generated the return instruction
984290075Sobrien     then it is futile to generate anything else.  */
9843132718Skan  if (use_return_insn (FALSE, sibling) && return_used_this_function)
984490075Sobrien    return "";
984590075Sobrien
984690075Sobrien  func_type = arm_current_func_type ();
984790075Sobrien
984890075Sobrien  if (IS_NAKED (func_type))
984990075Sobrien    /* Naked functions don't have epilogues.  */
985090075Sobrien    return "";
985190075Sobrien
985290075Sobrien  if (IS_VOLATILE (func_type) && TARGET_ABORT_NORETURN)
985390075Sobrien    {
985490075Sobrien      rtx op;
9855169689Skan
985690075Sobrien      /* A volatile function should never return.  Call abort.  */
985790075Sobrien      op = gen_rtx_SYMBOL_REF (Pmode, NEED_PLT_RELOC ? "abort(PLT)" : "abort");
985890075Sobrien      assemble_external_libcall (op);
985990075Sobrien      output_asm_insn ("bl\t%a0", &op);
9860169689Skan
986190075Sobrien      return "";
986290075Sobrien    }
986390075Sobrien
9864169689Skan  /* If we are throwing an exception, then we really must be doing a
9865169689Skan     return, so we can't tail-call.  */
9866169689Skan  gcc_assert (!current_function_calls_eh_return || really_return);
9867169689Skan
9868169689Skan  offsets = arm_get_frame_offsets ();
986990075Sobrien  saved_regs_mask = arm_compute_save_reg_mask ();
9870132718Skan
9871132718Skan  if (TARGET_IWMMXT)
9872132718Skan    lrm_count = bit_count (saved_regs_mask);
9873132718Skan
9874169689Skan  floats_offset = offsets->saved_args;
987590075Sobrien  /* Compute how far away the floats will be.  */
9876132718Skan  for (reg = 0; reg <= LAST_ARM_REGNUM; reg++)
987790075Sobrien    if (saved_regs_mask & (1 << reg))
987890075Sobrien      floats_offset += 4;
9879169689Skan
988090075Sobrien  if (frame_pointer_needed)
988190075Sobrien    {
9882169689Skan      /* This variable is for the Virtual Frame Pointer, not VFP regs.  */
9883169689Skan      int vfp_offset = offsets->frame;
988496263Sobrien
9885132718Skan      if (arm_fpu_arch == FPUTYPE_FPA_EMU2)
988690075Sobrien	{
9887169689Skan	  for (reg = LAST_FPA_REGNUM; reg >= FIRST_FPA_REGNUM; reg--)
988890075Sobrien	    if (regs_ever_live[reg] && !call_used_regs[reg])
988990075Sobrien	      {
989090075Sobrien		floats_offset += 12;
9891169689Skan		asm_fprintf (f, "\tldfe\t%r, [%r, #-%d]\n",
989296263Sobrien			     reg, FP_REGNUM, floats_offset - vfp_offset);
989390075Sobrien	      }
989490075Sobrien	}
989590075Sobrien      else
989690075Sobrien	{
9897169689Skan	  start_reg = LAST_FPA_REGNUM;
989890075Sobrien
9899169689Skan	  for (reg = LAST_FPA_REGNUM; reg >= FIRST_FPA_REGNUM; reg--)
990090075Sobrien	    {
990190075Sobrien	      if (regs_ever_live[reg] && !call_used_regs[reg])
990290075Sobrien		{
990390075Sobrien		  floats_offset += 12;
9904169689Skan
990590075Sobrien		  /* We can't unstack more than four registers at once.  */
990690075Sobrien		  if (start_reg - reg == 3)
990790075Sobrien		    {
990890075Sobrien		      asm_fprintf (f, "\tlfm\t%r, 4, [%r, #-%d]\n",
990996263Sobrien			           reg, FP_REGNUM, floats_offset - vfp_offset);
991090075Sobrien		      start_reg = reg - 1;
991190075Sobrien		    }
991290075Sobrien		}
991390075Sobrien	      else
991490075Sobrien		{
991590075Sobrien		  if (reg != start_reg)
991690075Sobrien		    asm_fprintf (f, "\tlfm\t%r, %d, [%r, #-%d]\n",
991790075Sobrien				 reg + 1, start_reg - reg,
991896263Sobrien				 FP_REGNUM, floats_offset - vfp_offset);
991990075Sobrien		  start_reg = reg - 1;
992090075Sobrien		}
992190075Sobrien	    }
992290075Sobrien
992390075Sobrien	  /* Just in case the last register checked also needs unstacking.  */
992490075Sobrien	  if (reg != start_reg)
992590075Sobrien	    asm_fprintf (f, "\tlfm\t%r, %d, [%r, #-%d]\n",
992690075Sobrien			 reg + 1, start_reg - reg,
992796263Sobrien			 FP_REGNUM, floats_offset - vfp_offset);
992890075Sobrien	}
992990075Sobrien
9930169689Skan      if (TARGET_HARD_FLOAT && TARGET_VFP)
9931169689Skan	{
9932169689Skan	  int saved_size;
9933169689Skan
9934169689Skan	  /* The fldmx insn does not have base+offset addressing modes,
9935169689Skan	     so we use IP to hold the address.  */
9936169689Skan	  saved_size = arm_get_vfp_saved_size ();
9937169689Skan
9938169689Skan	  if (saved_size > 0)
9939169689Skan	    {
9940169689Skan	      floats_offset += saved_size;
9941169689Skan	      asm_fprintf (f, "\tsub\t%r, %r, #%d\n", IP_REGNUM,
9942169689Skan			   FP_REGNUM, floats_offset - vfp_offset);
9943169689Skan	    }
9944169689Skan	  start_reg = FIRST_VFP_REGNUM;
9945169689Skan	  for (reg = FIRST_VFP_REGNUM; reg < LAST_VFP_REGNUM; reg += 2)
9946169689Skan	    {
9947169689Skan	      if ((!regs_ever_live[reg] || call_used_regs[reg])
9948169689Skan		  && (!regs_ever_live[reg + 1] || call_used_regs[reg + 1]))
9949169689Skan		{
9950169689Skan		  if (start_reg != reg)
9951169689Skan		    arm_output_fldmx (f, IP_REGNUM,
9952169689Skan				      (start_reg - FIRST_VFP_REGNUM) / 2,
9953169689Skan				      (reg - start_reg) / 2);
9954169689Skan		  start_reg = reg + 2;
9955169689Skan		}
9956169689Skan	    }
9957169689Skan	  if (start_reg != reg)
9958169689Skan	    arm_output_fldmx (f, IP_REGNUM,
9959169689Skan			      (start_reg - FIRST_VFP_REGNUM) / 2,
9960169689Skan			      (reg - start_reg) / 2);
9961169689Skan	}
9962169689Skan
9963132718Skan      if (TARGET_IWMMXT)
9964132718Skan	{
9965132718Skan	  /* The frame pointer is guaranteed to be non-double-word aligned.
9966132718Skan	     This is because it is set to (old_stack_pointer - 4) and the
9967132718Skan	     old_stack_pointer was double word aligned.  Thus the offset to
9968132718Skan	     the iWMMXt registers to be loaded must also be non-double-word
9969132718Skan	     sized, so that the resultant address *is* double-word aligned.
9970132718Skan	     We can ignore floats_offset since that was already included in
9971132718Skan	     the live_regs_mask.  */
9972132718Skan	  lrm_count += (lrm_count % 2 ? 2 : 1);
9973169689Skan
9974169689Skan	  for (reg = LAST_IWMMXT_REGNUM; reg >= FIRST_IWMMXT_REGNUM; reg--)
9975132718Skan	    if (regs_ever_live[reg] && !call_used_regs[reg])
9976132718Skan	      {
9977169689Skan		asm_fprintf (f, "\twldrd\t%r, [%r, #-%d]\n",
9978132718Skan			     reg, FP_REGNUM, lrm_count * 4);
9979169689Skan		lrm_count += 2;
9980132718Skan	      }
9981132718Skan	}
9982132718Skan
998390075Sobrien      /* saved_regs_mask should contain the IP, which at the time of stack
998490075Sobrien	 frame generation actually contains the old stack pointer.  So a
998590075Sobrien	 quick way to unwind the stack is just pop the IP register directly
998690075Sobrien	 into the stack pointer.  */
9987169689Skan      gcc_assert (saved_regs_mask & (1 << IP_REGNUM));
998890075Sobrien      saved_regs_mask &= ~ (1 << IP_REGNUM);
998990075Sobrien      saved_regs_mask |=   (1 << SP_REGNUM);
999090075Sobrien
999190075Sobrien      /* There are two registers left in saved_regs_mask - LR and PC.  We
999290075Sobrien	 only need to restore the LR register (the return address), but to
999390075Sobrien	 save time we can load it directly into the PC, unless we need a
999490075Sobrien	 special function exit sequence, or we are not really returning.  */
9995169689Skan      if (really_return
9996169689Skan	  && ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL
9997169689Skan	  && !current_function_calls_eh_return)
999890075Sobrien	/* Delete the LR from the register mask, so that the LR on
999990075Sobrien	   the stack is loaded into the PC in the register mask.  */
1000090075Sobrien	saved_regs_mask &= ~ (1 << LR_REGNUM);
1000190075Sobrien      else
1000290075Sobrien	saved_regs_mask &= ~ (1 << PC_REGNUM);
1000390075Sobrien
10004132718Skan      /* We must use SP as the base register, because SP is one of the
10005132718Skan         registers being restored.  If an interrupt or page fault
10006132718Skan         happens in the ldm instruction, the SP might or might not
10007132718Skan         have been restored.  That would be bad, as then SP will no
10008132718Skan         longer indicate the safe area of stack, and we can get stack
10009132718Skan         corruption.  Using SP as the base register means that it will
10010132718Skan         be reset correctly to the original value, should an interrupt
10011132718Skan         occur.  If the stack pointer already points at the right
10012132718Skan         place, then omit the subtraction.  */
10013169689Skan      if (offsets->outgoing_args != (1 + (int) bit_count (saved_regs_mask))
10014132718Skan	  || current_function_calls_alloca)
10015132718Skan	asm_fprintf (f, "\tsub\t%r, %r, #%d\n", SP_REGNUM, FP_REGNUM,
10016132718Skan		     4 * bit_count (saved_regs_mask));
10017132718Skan      print_multi_reg (f, "ldmfd\t%r", SP_REGNUM, saved_regs_mask);
10018132718Skan
1001990075Sobrien      if (IS_INTERRUPT (func_type))
1002090075Sobrien	/* Interrupt handlers will have pushed the
1002190075Sobrien	   IP onto the stack, so restore it now.  */
10022117395Skan	print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM, 1 << IP_REGNUM);
1002390075Sobrien    }
1002490075Sobrien  else
1002590075Sobrien    {
1002690075Sobrien      /* Restore stack pointer if necessary.  */
10027169689Skan      if (offsets->outgoing_args != offsets->saved_regs)
1002890075Sobrien	{
1002990075Sobrien	  operands[0] = operands[1] = stack_pointer_rtx;
10030169689Skan	  operands[2] = GEN_INT (offsets->outgoing_args - offsets->saved_regs);
1003190075Sobrien	  output_add_immediate (operands);
1003290075Sobrien	}
1003390075Sobrien
10034132718Skan      if (arm_fpu_arch == FPUTYPE_FPA_EMU2)
1003590075Sobrien	{
10036169689Skan	  for (reg = FIRST_FPA_REGNUM; reg <= LAST_FPA_REGNUM; reg++)
1003790075Sobrien	    if (regs_ever_live[reg] && !call_used_regs[reg])
1003890075Sobrien	      asm_fprintf (f, "\tldfe\t%r, [%r], #12\n",
1003990075Sobrien			   reg, SP_REGNUM);
1004090075Sobrien	}
1004190075Sobrien      else
1004290075Sobrien	{
10043169689Skan	  start_reg = FIRST_FPA_REGNUM;
1004490075Sobrien
10045169689Skan	  for (reg = FIRST_FPA_REGNUM; reg <= LAST_FPA_REGNUM; reg++)
1004690075Sobrien	    {
1004790075Sobrien	      if (regs_ever_live[reg] && !call_used_regs[reg])
1004890075Sobrien		{
1004990075Sobrien		  if (reg - start_reg == 3)
1005090075Sobrien		    {
1005190075Sobrien		      asm_fprintf (f, "\tlfmfd\t%r, 4, [%r]!\n",
1005290075Sobrien				   start_reg, SP_REGNUM);
1005390075Sobrien		      start_reg = reg + 1;
1005490075Sobrien		    }
1005590075Sobrien		}
1005690075Sobrien	      else
1005790075Sobrien		{
1005890075Sobrien		  if (reg != start_reg)
1005990075Sobrien		    asm_fprintf (f, "\tlfmfd\t%r, %d, [%r]!\n",
1006090075Sobrien				 start_reg, reg - start_reg,
1006190075Sobrien				 SP_REGNUM);
10062169689Skan
1006390075Sobrien		  start_reg = reg + 1;
1006490075Sobrien		}
1006590075Sobrien	    }
1006690075Sobrien
1006790075Sobrien	  /* Just in case the last register checked also needs unstacking.  */
1006890075Sobrien	  if (reg != start_reg)
1006990075Sobrien	    asm_fprintf (f, "\tlfmfd\t%r, %d, [%r]!\n",
1007090075Sobrien			 start_reg, reg - start_reg, SP_REGNUM);
1007190075Sobrien	}
1007290075Sobrien
10073169689Skan      if (TARGET_HARD_FLOAT && TARGET_VFP)
10074169689Skan	{
10075169689Skan	  start_reg = FIRST_VFP_REGNUM;
10076169689Skan	  for (reg = FIRST_VFP_REGNUM; reg < LAST_VFP_REGNUM; reg += 2)
10077169689Skan	    {
10078169689Skan	      if ((!regs_ever_live[reg] || call_used_regs[reg])
10079169689Skan		  && (!regs_ever_live[reg + 1] || call_used_regs[reg + 1]))
10080169689Skan		{
10081169689Skan		  if (start_reg != reg)
10082169689Skan		    arm_output_fldmx (f, SP_REGNUM,
10083169689Skan				      (start_reg - FIRST_VFP_REGNUM) / 2,
10084169689Skan				      (reg - start_reg) / 2);
10085169689Skan		  start_reg = reg + 2;
10086169689Skan		}
10087169689Skan	    }
10088169689Skan	  if (start_reg != reg)
10089169689Skan	    arm_output_fldmx (f, SP_REGNUM,
10090169689Skan			      (start_reg - FIRST_VFP_REGNUM) / 2,
10091169689Skan			      (reg - start_reg) / 2);
10092169689Skan	}
10093132718Skan      if (TARGET_IWMMXT)
10094132718Skan	for (reg = FIRST_IWMMXT_REGNUM; reg <= LAST_IWMMXT_REGNUM; reg++)
10095132718Skan	  if (regs_ever_live[reg] && !call_used_regs[reg])
10096169689Skan	    asm_fprintf (f, "\twldrd\t%r, [%r], #8\n", reg, SP_REGNUM);
10097132718Skan
1009890075Sobrien      /* If we can, restore the LR into the PC.  */
1009990075Sobrien      if (ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL
1010090075Sobrien	  && really_return
1010190075Sobrien	  && current_function_pretend_args_size == 0
10102169689Skan	  && saved_regs_mask & (1 << LR_REGNUM)
10103169689Skan	  && !current_function_calls_eh_return)
1010490075Sobrien	{
1010590075Sobrien	  saved_regs_mask &= ~ (1 << LR_REGNUM);
1010690075Sobrien	  saved_regs_mask |=   (1 << PC_REGNUM);
1010790075Sobrien	}
1010890075Sobrien
1010990075Sobrien      /* Load the registers off the stack.  If we only have one register
1011090075Sobrien	 to load use the LDR instruction - it is faster.  */
1011190075Sobrien      if (saved_regs_mask == (1 << LR_REGNUM))
1011290075Sobrien	{
10113169689Skan	  asm_fprintf (f, "\tldr\t%r, [%r], #4\n", LR_REGNUM, SP_REGNUM);
1011490075Sobrien	}
1011590075Sobrien      else if (saved_regs_mask)
10116117395Skan	{
10117117395Skan	  if (saved_regs_mask & (1 << SP_REGNUM))
10118117395Skan	    /* Note - write back to the stack register is not enabled
10119169689Skan	       (i.e. "ldmfd sp!...").  We know that the stack pointer is
10120117395Skan	       in the list of registers and if we add writeback the
10121117395Skan	       instruction becomes UNPREDICTABLE.  */
10122117395Skan	    print_multi_reg (f, "ldmfd\t%r", SP_REGNUM, saved_regs_mask);
10123117395Skan	  else
10124117395Skan	    print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM, saved_regs_mask);
10125117395Skan	}
1012690075Sobrien
1012790075Sobrien      if (current_function_pretend_args_size)
1012890075Sobrien	{
1012990075Sobrien	  /* Unwind the pre-pushed regs.  */
1013090075Sobrien	  operands[0] = operands[1] = stack_pointer_rtx;
1013190075Sobrien	  operands[2] = GEN_INT (current_function_pretend_args_size);
1013290075Sobrien	  output_add_immediate (operands);
1013390075Sobrien	}
1013490075Sobrien    }
1013590075Sobrien
10136169689Skan  /* We may have already restored PC directly from the stack.  */
10137169689Skan  if (!really_return || saved_regs_mask & (1 << PC_REGNUM))
1013890075Sobrien    return "";
1013990075Sobrien
10140169689Skan  /* Stack adjustment for exception handler.  */
10141169689Skan  if (current_function_calls_eh_return)
10142169689Skan    asm_fprintf (f, "\tadd\t%r, %r, %r\n", SP_REGNUM, SP_REGNUM,
10143169689Skan		 ARM_EH_STACKADJ_REGNUM);
10144169689Skan
1014590075Sobrien  /* Generate the return instruction.  */
1014690075Sobrien  switch ((int) ARM_FUNC_TYPE (func_type))
1014790075Sobrien    {
1014890075Sobrien    case ARM_FT_ISR:
1014990075Sobrien    case ARM_FT_FIQ:
1015090075Sobrien      asm_fprintf (f, "\tsubs\t%r, %r, #4\n", PC_REGNUM, LR_REGNUM);
1015190075Sobrien      break;
1015290075Sobrien
1015390075Sobrien    case ARM_FT_EXCEPTION:
1015490075Sobrien      asm_fprintf (f, "\tmovs\t%r, %r\n", PC_REGNUM, LR_REGNUM);
1015590075Sobrien      break;
1015690075Sobrien
1015790075Sobrien    case ARM_FT_INTERWORKED:
1015890075Sobrien      asm_fprintf (f, "\tbx\t%r\n", LR_REGNUM);
1015990075Sobrien      break;
1016090075Sobrien
1016190075Sobrien    default:
10162169689Skan      if (arm_arch5 || arm_arch4t)
10163169689Skan	asm_fprintf (f, "\tbx\t%r\n", LR_REGNUM);
10164169689Skan      else
1016590075Sobrien	asm_fprintf (f, "\tmov\t%r, %r\n", PC_REGNUM, LR_REGNUM);
1016690075Sobrien      break;
1016790075Sobrien    }
1016890075Sobrien
1016990075Sobrien  return "";
1017090075Sobrien}
1017190075Sobrien
1017290075Sobrienstatic void
10173132718Skanarm_output_function_epilogue (FILE *file ATTRIBUTE_UNUSED,
10174169689Skan			      HOST_WIDE_INT frame_size ATTRIBUTE_UNUSED)
1017590075Sobrien{
10176169689Skan  arm_stack_offsets *offsets;
10177169689Skan
1017890075Sobrien  if (TARGET_THUMB)
1017990075Sobrien    {
10180169689Skan      int regno;
10181169689Skan
10182169689Skan      /* Emit any call-via-reg trampolines that are needed for v4t support
10183169689Skan	 of call_reg and call_value_reg type insns.  */
10184169689Skan      for (regno = 0; regno < LR_REGNUM; regno++)
10185169689Skan	{
10186169689Skan	  rtx label = cfun->machine->call_via[regno];
10187169689Skan
10188169689Skan	  if (label != NULL)
10189169689Skan	    {
10190169689Skan	      switch_to_section (function_section (current_function_decl));
10191169689Skan	      targetm.asm_out.internal_label (asm_out_file, "L",
10192169689Skan					      CODE_LABEL_NUMBER (label));
10193169689Skan	      asm_fprintf (asm_out_file, "\tbx\t%r\n", regno);
10194169689Skan	    }
10195169689Skan	}
10196169689Skan
1019790075Sobrien      /* ??? Probably not safe to set this here, since it assumes that a
1019890075Sobrien	 function will be emitted as assembly immediately after we generate
1019990075Sobrien	 RTL for it.  This does not happen for inline functions.  */
1020090075Sobrien      return_used_this_function = 0;
1020190075Sobrien    }
1020290075Sobrien  else
1020390075Sobrien    {
10204117395Skan      /* We need to take into account any stack-frame rounding.  */
10205169689Skan      offsets = arm_get_frame_offsets ();
10206117395Skan
10207169689Skan      gcc_assert (!use_return_insn (FALSE, NULL)
10208169689Skan		  || !return_used_this_function
10209169689Skan		  || offsets->saved_regs == offsets->outgoing_args
10210169689Skan		  || frame_pointer_needed);
1021190075Sobrien
1021290075Sobrien      /* Reset the ARM-specific per-function variables.  */
1021390075Sobrien      after_arm_reorg = 0;
1021490075Sobrien    }
1021590075Sobrien}
1021690075Sobrien
1021790075Sobrien/* Generate and emit an insn that we will recognize as a push_multi.
1021890075Sobrien   Unfortunately, since this insn does not reflect very well the actual
1021990075Sobrien   semantics of the operation, we need to annotate the insn for the benefit
1022090075Sobrien   of DWARF2 frame unwind information.  */
1022190075Sobrienstatic rtx
10222169689Skanemit_multi_reg_push (unsigned long mask)
1022390075Sobrien{
1022490075Sobrien  int num_regs = 0;
1022590075Sobrien  int num_dwarf_regs;
1022690075Sobrien  int i, j;
1022790075Sobrien  rtx par;
1022890075Sobrien  rtx dwarf;
1022990075Sobrien  int dwarf_par_index;
1023090075Sobrien  rtx tmp, reg;
1023190075Sobrien
1023290075Sobrien  for (i = 0; i <= LAST_ARM_REGNUM; i++)
1023390075Sobrien    if (mask & (1 << i))
1023490075Sobrien      num_regs++;
1023590075Sobrien
10236169689Skan  gcc_assert (num_regs && num_regs <= 16);
1023790075Sobrien
1023890075Sobrien  /* We don't record the PC in the dwarf frame information.  */
1023990075Sobrien  num_dwarf_regs = num_regs;
1024090075Sobrien  if (mask & (1 << PC_REGNUM))
1024190075Sobrien    num_dwarf_regs--;
1024290075Sobrien
1024390075Sobrien  /* For the body of the insn we are going to generate an UNSPEC in
10244117395Skan     parallel with several USEs.  This allows the insn to be recognized
1024590075Sobrien     by the push_multi pattern in the arm.md file.  The insn looks
1024690075Sobrien     something like this:
1024790075Sobrien
10248169689Skan       (parallel [
1024990075Sobrien           (set (mem:BLK (pre_dec:BLK (reg:SI sp)))
1025090075Sobrien	        (unspec:BLK [(reg:SI r4)] UNSPEC_PUSH_MULT))
1025190075Sobrien           (use (reg:SI 11 fp))
1025290075Sobrien           (use (reg:SI 12 ip))
1025390075Sobrien           (use (reg:SI 14 lr))
1025490075Sobrien           (use (reg:SI 15 pc))
1025590075Sobrien        ])
1025690075Sobrien
1025790075Sobrien     For the frame note however, we try to be more explicit and actually
1025890075Sobrien     show each register being stored into the stack frame, plus a (single)
1025990075Sobrien     decrement of the stack pointer.  We do it this way in order to be
1026090075Sobrien     friendly to the stack unwinding code, which only wants to see a single
1026190075Sobrien     stack decrement per instruction.  The RTL we generate for the note looks
1026290075Sobrien     something like this:
1026390075Sobrien
10264169689Skan      (sequence [
1026590075Sobrien           (set (reg:SI sp) (plus:SI (reg:SI sp) (const_int -20)))
1026690075Sobrien           (set (mem:SI (reg:SI sp)) (reg:SI r4))
1026790075Sobrien           (set (mem:SI (plus:SI (reg:SI sp) (const_int 4))) (reg:SI fp))
1026890075Sobrien           (set (mem:SI (plus:SI (reg:SI sp) (const_int 8))) (reg:SI ip))
1026990075Sobrien           (set (mem:SI (plus:SI (reg:SI sp) (const_int 12))) (reg:SI lr))
1027090075Sobrien        ])
1027190075Sobrien
1027290075Sobrien      This sequence is used both by the code to support stack unwinding for
1027390075Sobrien      exceptions handlers and the code to generate dwarf2 frame debugging.  */
10274169689Skan
1027590075Sobrien  par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (num_regs));
1027690075Sobrien  dwarf = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (num_dwarf_regs + 1));
1027790075Sobrien  dwarf_par_index = 1;
1027890075Sobrien
1027990075Sobrien  for (i = 0; i <= LAST_ARM_REGNUM; i++)
1028090075Sobrien    {
1028190075Sobrien      if (mask & (1 << i))
1028290075Sobrien	{
1028390075Sobrien	  reg = gen_rtx_REG (SImode, i);
1028490075Sobrien
1028590075Sobrien	  XVECEXP (par, 0, 0)
1028690075Sobrien	    = gen_rtx_SET (VOIDmode,
10287169689Skan			   gen_frame_mem (BLKmode,
10288169689Skan					  gen_rtx_PRE_DEC (BLKmode,
10289169689Skan							   stack_pointer_rtx)),
1029090075Sobrien			   gen_rtx_UNSPEC (BLKmode,
1029190075Sobrien					   gen_rtvec (1, reg),
1029290075Sobrien					   UNSPEC_PUSH_MULT));
1029390075Sobrien
1029490075Sobrien	  if (i != PC_REGNUM)
1029590075Sobrien	    {
1029690075Sobrien	      tmp = gen_rtx_SET (VOIDmode,
10297169689Skan				 gen_frame_mem (SImode, stack_pointer_rtx),
1029890075Sobrien				 reg);
1029990075Sobrien	      RTX_FRAME_RELATED_P (tmp) = 1;
1030090075Sobrien	      XVECEXP (dwarf, 0, dwarf_par_index) = tmp;
1030190075Sobrien	      dwarf_par_index++;
1030290075Sobrien	    }
1030390075Sobrien
1030490075Sobrien	  break;
1030590075Sobrien	}
1030690075Sobrien    }
1030790075Sobrien
1030890075Sobrien  for (j = 1, i++; j < num_regs; i++)
1030990075Sobrien    {
1031090075Sobrien      if (mask & (1 << i))
1031190075Sobrien	{
1031290075Sobrien	  reg = gen_rtx_REG (SImode, i);
1031390075Sobrien
1031490075Sobrien	  XVECEXP (par, 0, j) = gen_rtx_USE (VOIDmode, reg);
1031590075Sobrien
1031690075Sobrien	  if (i != PC_REGNUM)
1031790075Sobrien	    {
10318169689Skan	      tmp
10319169689Skan		= gen_rtx_SET (VOIDmode,
10320169689Skan			       gen_frame_mem (SImode,
1032190075Sobrien					      plus_constant (stack_pointer_rtx,
1032290075Sobrien							     4 * j)),
10323169689Skan			       reg);
1032490075Sobrien	      RTX_FRAME_RELATED_P (tmp) = 1;
1032590075Sobrien	      XVECEXP (dwarf, 0, dwarf_par_index++) = tmp;
1032690075Sobrien	    }
1032790075Sobrien
1032890075Sobrien	  j++;
1032990075Sobrien	}
1033090075Sobrien    }
1033190075Sobrien
1033290075Sobrien  par = emit_insn (par);
10333169689Skan
10334169689Skan  tmp = gen_rtx_SET (VOIDmode,
1033590075Sobrien		     stack_pointer_rtx,
10336169689Skan		     plus_constant (stack_pointer_rtx, -4 * num_regs));
1033790075Sobrien  RTX_FRAME_RELATED_P (tmp) = 1;
1033890075Sobrien  XVECEXP (dwarf, 0, 0) = tmp;
10339169689Skan
1034090075Sobrien  REG_NOTES (par) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
1034190075Sobrien				       REG_NOTES (par));
1034290075Sobrien  return par;
1034390075Sobrien}
1034490075Sobrien
10345169689Skan/* Calculate the size of the return value that is passed in registers.  */
10346169689Skanstatic int
10347169689Skanarm_size_return_regs (void)
10348169689Skan{
10349169689Skan  enum machine_mode mode;
10350169689Skan
10351169689Skan  if (current_function_return_rtx != 0)
10352169689Skan    mode = GET_MODE (current_function_return_rtx);
10353169689Skan  else
10354169689Skan    mode = DECL_MODE (DECL_RESULT (current_function_decl));
10355169689Skan
10356169689Skan  return GET_MODE_SIZE (mode);
10357169689Skan}
10358169689Skan
1035990075Sobrienstatic rtx
10360132718Skanemit_sfm (int base_reg, int count)
1036190075Sobrien{
1036290075Sobrien  rtx par;
1036390075Sobrien  rtx dwarf;
1036490075Sobrien  rtx tmp, reg;
1036590075Sobrien  int i;
1036690075Sobrien
1036790075Sobrien  par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count));
10368169689Skan  dwarf = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (count + 1));
1036990075Sobrien
1037090075Sobrien  reg = gen_rtx_REG (XFmode, base_reg++);
1037190075Sobrien
1037290075Sobrien  XVECEXP (par, 0, 0)
10373169689Skan    = gen_rtx_SET (VOIDmode,
10374169689Skan		   gen_frame_mem (BLKmode,
10375169689Skan				  gen_rtx_PRE_DEC (BLKmode,
10376169689Skan						   stack_pointer_rtx)),
1037790075Sobrien		   gen_rtx_UNSPEC (BLKmode,
1037890075Sobrien				   gen_rtvec (1, reg),
1037990075Sobrien				   UNSPEC_PUSH_MULT));
10380169689Skan  tmp = gen_rtx_SET (VOIDmode,
10381169689Skan		     gen_frame_mem (XFmode, stack_pointer_rtx), reg);
1038290075Sobrien  RTX_FRAME_RELATED_P (tmp) = 1;
10383169689Skan  XVECEXP (dwarf, 0, 1) = tmp;
10384169689Skan
1038590075Sobrien  for (i = 1; i < count; i++)
1038690075Sobrien    {
1038790075Sobrien      reg = gen_rtx_REG (XFmode, base_reg++);
1038890075Sobrien      XVECEXP (par, 0, i) = gen_rtx_USE (VOIDmode, reg);
1038990075Sobrien
10390169689Skan      tmp = gen_rtx_SET (VOIDmode,
10391169689Skan			 gen_frame_mem (XFmode,
10392169689Skan					plus_constant (stack_pointer_rtx,
10393169689Skan						       i * 12)),
1039490075Sobrien			 reg);
1039590075Sobrien      RTX_FRAME_RELATED_P (tmp) = 1;
10396169689Skan      XVECEXP (dwarf, 0, i + 1) = tmp;
1039790075Sobrien    }
1039890075Sobrien
10399169689Skan  tmp = gen_rtx_SET (VOIDmode,
10400169689Skan		     stack_pointer_rtx,
10401169689Skan		     plus_constant (stack_pointer_rtx, -12 * count));
10402169689Skan
10403169689Skan  RTX_FRAME_RELATED_P (tmp) = 1;
10404169689Skan  XVECEXP (dwarf, 0, 0) = tmp;
10405169689Skan
1040690075Sobrien  par = emit_insn (par);
1040790075Sobrien  REG_NOTES (par) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
1040890075Sobrien				       REG_NOTES (par));
1040990075Sobrien  return par;
1041090075Sobrien}
1041190075Sobrien
10412169689Skan
10413169689Skan/* Return true if the current function needs to save/restore LR.  */
10414169689Skan
10415169689Skanstatic bool
10416169689Skanthumb_force_lr_save (void)
10417169689Skan{
10418169689Skan  return !cfun->machine->lr_save_eliminated
10419169689Skan	 && (!leaf_function_p ()
10420169689Skan	     || thumb_far_jump_used_p ()
10421169689Skan	     || regs_ever_live [LR_REGNUM]);
10422169689Skan}
10423169689Skan
10424169689Skan
1042590075Sobrien/* Compute the distance from register FROM to register TO.
1042690075Sobrien   These can be the arg pointer (26), the soft frame pointer (25),
1042790075Sobrien   the stack pointer (13) or the hard frame pointer (11).
10428169689Skan   In thumb mode r7 is used as the soft frame pointer, if needed.
1042990075Sobrien   Typical stack layout looks like this:
1043090075Sobrien
1043190075Sobrien       old stack pointer -> |    |
1043290075Sobrien                             ----
1043390075Sobrien                            |    | \
1043490075Sobrien                            |    |   saved arguments for
1043590075Sobrien                            |    |   vararg functions
1043690075Sobrien			    |    | /
1043790075Sobrien                              --
1043890075Sobrien   hard FP & arg pointer -> |    | \
1043990075Sobrien                            |    |   stack
1044090075Sobrien                            |    |   frame
1044190075Sobrien                            |    | /
1044290075Sobrien                              --
1044390075Sobrien                            |    | \
1044490075Sobrien                            |    |   call saved
1044590075Sobrien                            |    |   registers
1044690075Sobrien      soft frame pointer -> |    | /
1044790075Sobrien                              --
1044890075Sobrien                            |    | \
1044990075Sobrien                            |    |   local
1045090075Sobrien                            |    |   variables
10451169689Skan     locals base pointer -> |    | /
1045290075Sobrien                              --
1045390075Sobrien                            |    | \
1045490075Sobrien                            |    |   outgoing
1045590075Sobrien                            |    |   arguments
1045690075Sobrien   current stack pointer -> |    | /
1045790075Sobrien                              --
1045890075Sobrien
10459117395Skan  For a given function some or all of these stack components
1046090075Sobrien  may not be needed, giving rise to the possibility of
1046190075Sobrien  eliminating some of the registers.
1046290075Sobrien
10463117395Skan  The values returned by this function must reflect the behavior
1046490075Sobrien  of arm_expand_prologue() and arm_compute_save_reg_mask().
1046590075Sobrien
1046690075Sobrien  The sign of the number returned reflects the direction of stack
1046790075Sobrien  growth, so the values are positive for all eliminations except
10468169689Skan  from the soft frame pointer to the hard frame pointer.
10469169689Skan
10470169689Skan  SFP may point just inside the local variables block to ensure correct
10471169689Skan  alignment.  */
10472169689Skan
10473169689Skan
10474169689Skan/* Calculate stack offsets.  These are used to calculate register elimination
10475169689Skan   offsets and in prologue/epilogue code.  */
10476169689Skan
10477169689Skanstatic arm_stack_offsets *
10478169689Skanarm_get_frame_offsets (void)
1047990075Sobrien{
10480169689Skan  struct arm_stack_offsets *offsets;
1048190075Sobrien  unsigned long func_type;
10482169689Skan  int leaf;
10483169689Skan  int saved;
10484169689Skan  HOST_WIDE_INT frame_size;
1048590075Sobrien
10486169689Skan  offsets = &cfun->machine->stack_offsets;
10487169689Skan
10488169689Skan  /* We need to know if we are a leaf function.  Unfortunately, it
10489169689Skan     is possible to be called after start_sequence has been called,
10490169689Skan     which causes get_insns to return the insns for the sequence,
10491169689Skan     not the function, which will cause leaf_function_p to return
10492169689Skan     the incorrect result.
10493169689Skan
10494169689Skan     to know about leaf functions once reload has completed, and the
10495169689Skan     frame size cannot be changed after that time, so we can safely
10496169689Skan     use the cached value.  */
10497169689Skan
10498169689Skan  if (reload_completed)
10499169689Skan    return offsets;
10500169689Skan
10501169689Skan  /* Initially this is the size of the local variables.  It will translated
10502169689Skan     into an offset once we have determined the size of preceding data.  */
10503169689Skan  frame_size = ROUND_UP_WORD (get_frame_size ());
10504169689Skan
10505169689Skan  leaf = leaf_function_p ();
10506169689Skan
10507169689Skan  /* Space for variadic functions.  */
10508169689Skan  offsets->saved_args = current_function_pretend_args_size;
10509169689Skan
10510169689Skan  offsets->frame = offsets->saved_args + (frame_pointer_needed ? 4 : 0);
10511169689Skan
10512169689Skan  if (TARGET_ARM)
1051390075Sobrien    {
10514169689Skan      unsigned int regno;
1051590075Sobrien
10516169689Skan      saved = bit_count (arm_compute_save_reg_mask ()) * 4;
1051790075Sobrien
10518169689Skan      /* We know that SP will be doubleword aligned on entry, and we must
10519169689Skan	 preserve that condition at any subroutine call.  We also require the
10520169689Skan	 soft frame pointer to be doubleword aligned.  */
1052190075Sobrien
10522169689Skan      if (TARGET_REALLY_IWMMXT)
10523169689Skan	{
10524169689Skan	  /* Check for the call-saved iWMMXt registers.  */
10525169689Skan	  for (regno = FIRST_IWMMXT_REGNUM;
10526169689Skan	       regno <= LAST_IWMMXT_REGNUM;
10527169689Skan	       regno++)
10528169689Skan	    if (regs_ever_live [regno] && ! call_used_regs [regno])
10529169689Skan	      saved += 8;
10530169689Skan	}
10531132718Skan
10532169689Skan      func_type = arm_current_func_type ();
10533169689Skan      if (! IS_VOLATILE (func_type))
10534169689Skan	{
10535169689Skan	  /* Space for saved FPA registers.  */
10536169689Skan	  for (regno = FIRST_FPA_REGNUM; regno <= LAST_FPA_REGNUM; regno++)
10537169689Skan	  if (regs_ever_live[regno] && ! call_used_regs[regno])
10538169689Skan	    saved += 12;
10539169689Skan
10540169689Skan	  /* Space for saved VFP registers.  */
10541169689Skan	  if (TARGET_HARD_FLOAT && TARGET_VFP)
10542169689Skan	    saved += arm_get_vfp_saved_size ();
10543169689Skan	}
1054490075Sobrien    }
10545169689Skan  else /* TARGET_THUMB */
10546169689Skan    {
10547169689Skan      saved = bit_count (thumb_compute_save_reg_mask ()) * 4;
10548169689Skan      if (TARGET_BACKTRACE)
10549169689Skan	saved += 16;
10550169689Skan    }
1055190075Sobrien
10552169689Skan  /* Saved registers include the stack frame.  */
10553169689Skan  offsets->saved_regs = offsets->saved_args + saved;
10554169689Skan  offsets->soft_frame = offsets->saved_regs + CALLER_INTERWORKING_SLOT_SIZE;
10555169689Skan  /* A leaf function does not need any stack alignment if it has nothing
10556169689Skan     on the stack.  */
10557169689Skan  if (leaf && frame_size == 0)
10558169689Skan    {
10559169689Skan      offsets->outgoing_args = offsets->soft_frame;
10560171825Skan      offsets->locals_base = offsets->soft_frame;
10561169689Skan      return offsets;
10562169689Skan    }
1056390075Sobrien
10564169689Skan  /* Ensure SFP has the correct alignment.  */
10565169689Skan  if (ARM_DOUBLEWORD_ALIGN
10566169689Skan      && (offsets->soft_frame & 7))
10567169689Skan    offsets->soft_frame += 4;
10568169689Skan
10569169689Skan  offsets->locals_base = offsets->soft_frame + frame_size;
10570169689Skan  offsets->outgoing_args = (offsets->locals_base
10571169689Skan			    + current_function_outgoing_args_size);
10572169689Skan
10573169689Skan  if (ARM_DOUBLEWORD_ALIGN)
10574169689Skan    {
10575169689Skan      /* Ensure SP remains doubleword aligned.  */
10576169689Skan      if (offsets->outgoing_args & 7)
10577169689Skan	offsets->outgoing_args += 4;
10578169689Skan      gcc_assert (!(offsets->outgoing_args & 7));
10579169689Skan    }
10580169689Skan
10581169689Skan  return offsets;
10582169689Skan}
10583169689Skan
10584169689Skan
10585169689Skan/* Calculate the relative offsets for the different stack pointers.  Positive
10586169689Skan   offsets are in the direction of stack growth.  */
10587169689Skan
10588169689SkanHOST_WIDE_INT
10589169689Skanarm_compute_initial_elimination_offset (unsigned int from, unsigned int to)
10590169689Skan{
10591169689Skan  arm_stack_offsets *offsets;
10592169689Skan
10593169689Skan  offsets = arm_get_frame_offsets ();
10594169689Skan
1059590075Sobrien  /* OK, now we have enough information to compute the distances.
1059690075Sobrien     There must be an entry in these switch tables for each pair
1059790075Sobrien     of registers in ELIMINABLE_REGS, even if some of the entries
1059890075Sobrien     seem to be redundant or useless.  */
1059990075Sobrien  switch (from)
1060090075Sobrien    {
1060190075Sobrien    case ARG_POINTER_REGNUM:
1060290075Sobrien      switch (to)
1060390075Sobrien	{
1060490075Sobrien	case THUMB_HARD_FRAME_POINTER_REGNUM:
1060590075Sobrien	  return 0;
1060690075Sobrien
1060790075Sobrien	case FRAME_POINTER_REGNUM:
1060890075Sobrien	  /* This is the reverse of the soft frame pointer
1060990075Sobrien	     to hard frame pointer elimination below.  */
10610169689Skan	  return offsets->soft_frame - offsets->saved_args;
1061190075Sobrien
1061290075Sobrien	case ARM_HARD_FRAME_POINTER_REGNUM:
1061390075Sobrien	  /* If there is no stack frame then the hard
1061490075Sobrien	     frame pointer and the arg pointer coincide.  */
10615169689Skan	  if (offsets->frame == offsets->saved_regs)
1061690075Sobrien	    return 0;
1061790075Sobrien	  /* FIXME:  Not sure about this.  Maybe we should always return 0 ?  */
1061890075Sobrien	  return (frame_pointer_needed
10619169689Skan		  && cfun->static_chain_decl != NULL
1062096263Sobrien		  && ! cfun->machine->uses_anonymous_args) ? 4 : 0;
1062190075Sobrien
1062290075Sobrien	case STACK_POINTER_REGNUM:
1062390075Sobrien	  /* If nothing has been pushed on the stack at all
1062490075Sobrien	     then this will return -4.  This *is* correct!  */
10625169689Skan	  return offsets->outgoing_args - (offsets->saved_args + 4);
1062690075Sobrien
1062790075Sobrien	default:
10628169689Skan	  gcc_unreachable ();
1062990075Sobrien	}
10630169689Skan      gcc_unreachable ();
1063190075Sobrien
1063290075Sobrien    case FRAME_POINTER_REGNUM:
1063390075Sobrien      switch (to)
1063490075Sobrien	{
1063590075Sobrien	case THUMB_HARD_FRAME_POINTER_REGNUM:
1063690075Sobrien	  return 0;
1063790075Sobrien
1063890075Sobrien	case ARM_HARD_FRAME_POINTER_REGNUM:
1063990075Sobrien	  /* The hard frame pointer points to the top entry in the
1064090075Sobrien	     stack frame.  The soft frame pointer to the bottom entry
1064190075Sobrien	     in the stack frame.  If there is no stack frame at all,
1064290075Sobrien	     then they are identical.  */
1064390075Sobrien
10644169689Skan	  return offsets->frame - offsets->soft_frame;
10645169689Skan
1064690075Sobrien	case STACK_POINTER_REGNUM:
10647169689Skan	  return offsets->outgoing_args - offsets->soft_frame;
1064890075Sobrien
1064990075Sobrien	default:
10650169689Skan	  gcc_unreachable ();
1065190075Sobrien	}
10652169689Skan      gcc_unreachable ();
1065390075Sobrien
1065490075Sobrien    default:
1065590075Sobrien      /* You cannot eliminate from the stack pointer.
1065690075Sobrien	 In theory you could eliminate from the hard frame
1065790075Sobrien	 pointer to the stack pointer, but this will never
1065890075Sobrien	 happen, since if a stack frame is not needed the
1065990075Sobrien	 hard frame pointer will never be used.  */
10660169689Skan      gcc_unreachable ();
1066190075Sobrien    }
1066290075Sobrien}
1066390075Sobrien
10664117395Skan
1066590075Sobrien/* Generate the prologue instructions for entry into an ARM function.  */
1066690075Sobrienvoid
10667132718Skanarm_expand_prologue (void)
1066890075Sobrien{
1066990075Sobrien  int reg;
1067090075Sobrien  rtx amount;
1067190075Sobrien  rtx insn;
1067290075Sobrien  rtx ip_rtx;
1067390075Sobrien  unsigned long live_regs_mask;
1067490075Sobrien  unsigned long func_type;
1067590075Sobrien  int fp_offset = 0;
1067690075Sobrien  int saved_pretend_args = 0;
10677169689Skan  int saved_regs = 0;
10678169689Skan  unsigned HOST_WIDE_INT args_to_push;
10679169689Skan  arm_stack_offsets *offsets;
1068090075Sobrien
1068190075Sobrien  func_type = arm_current_func_type ();
1068290075Sobrien
1068390075Sobrien  /* Naked functions don't have prologues.  */
1068490075Sobrien  if (IS_NAKED (func_type))
1068590075Sobrien    return;
1068690075Sobrien
1068790075Sobrien  /* Make a copy of c_f_p_a_s as we may need to modify it locally.  */
1068890075Sobrien  args_to_push = current_function_pretend_args_size;
10689169689Skan
1069090075Sobrien  /* Compute which register we will have to save onto the stack.  */
1069190075Sobrien  live_regs_mask = arm_compute_save_reg_mask ();
1069290075Sobrien
1069390075Sobrien  ip_rtx = gen_rtx_REG (SImode, IP_REGNUM);
1069490075Sobrien
1069590075Sobrien  if (frame_pointer_needed)
1069690075Sobrien    {
1069790075Sobrien      if (IS_INTERRUPT (func_type))
1069890075Sobrien	{
1069990075Sobrien	  /* Interrupt functions must not corrupt any registers.
1070090075Sobrien	     Creating a frame pointer however, corrupts the IP
1070190075Sobrien	     register, so we must push it first.  */
1070290075Sobrien	  insn = emit_multi_reg_push (1 << IP_REGNUM);
1070390075Sobrien
1070490075Sobrien	  /* Do not set RTX_FRAME_RELATED_P on this insn.
1070590075Sobrien	     The dwarf stack unwinding code only wants to see one
1070690075Sobrien	     stack decrement per function, and this is not it.  If
1070790075Sobrien	     this instruction is labeled as being part of the frame
1070890075Sobrien	     creation sequence then dwarf2out_frame_debug_expr will
10709169689Skan	     die when it encounters the assignment of IP to FP
1071090075Sobrien	     later on, since the use of SP here establishes SP as
1071190075Sobrien	     the CFA register and not IP.
1071290075Sobrien
1071390075Sobrien	     Anyway this instruction is not really part of the stack
1071490075Sobrien	     frame creation although it is part of the prologue.  */
1071590075Sobrien	}
1071690075Sobrien      else if (IS_NESTED (func_type))
1071790075Sobrien	{
1071890075Sobrien	  /* The Static chain register is the same as the IP register
1071990075Sobrien	     used as a scratch register during stack frame creation.
1072090075Sobrien	     To get around this need to find somewhere to store IP
1072190075Sobrien	     whilst the frame is being created.  We try the following
1072290075Sobrien	     places in order:
10723169689Skan
1072490075Sobrien	       1. The last argument register.
1072590075Sobrien	       2. A slot on the stack above the frame.  (This only
1072690075Sobrien	          works if the function is not a varargs function).
1072790075Sobrien	       3. Register r3, after pushing the argument registers
1072890075Sobrien	          onto the stack.
1072990075Sobrien
1073090075Sobrien	     Note - we only need to tell the dwarf2 backend about the SP
1073190075Sobrien	     adjustment in the second variant; the static chain register
1073290075Sobrien	     doesn't need to be unwound, as it doesn't contain a value
1073390075Sobrien	     inherited from the caller.  */
1073490075Sobrien
1073590075Sobrien	  if (regs_ever_live[3] == 0)
10736169689Skan	    insn = emit_set_insn (gen_rtx_REG (SImode, 3), ip_rtx);
1073790075Sobrien	  else if (args_to_push == 0)
1073890075Sobrien	    {
1073990075Sobrien	      rtx dwarf;
10740169689Skan
1074190075Sobrien	      insn = gen_rtx_PRE_DEC (SImode, stack_pointer_rtx);
10742169689Skan	      insn = emit_set_insn (gen_frame_mem (SImode, insn), ip_rtx);
1074390075Sobrien	      fp_offset = 4;
1074490075Sobrien
1074590075Sobrien	      /* Just tell the dwarf backend that we adjusted SP.  */
1074690075Sobrien	      dwarf = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
10747169689Skan				   plus_constant (stack_pointer_rtx,
10748169689Skan						  -fp_offset));
1074990075Sobrien	      RTX_FRAME_RELATED_P (insn) = 1;
1075090075Sobrien	      REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
1075190075Sobrien						    dwarf, REG_NOTES (insn));
1075290075Sobrien	    }
1075390075Sobrien	  else
1075490075Sobrien	    {
1075590075Sobrien	      /* Store the args on the stack.  */
1075696263Sobrien	      if (cfun->machine->uses_anonymous_args)
1075790075Sobrien		insn = emit_multi_reg_push
1075890075Sobrien		  ((0xf0 >> (args_to_push / 4)) & 0xf);
1075990075Sobrien	      else
1076090075Sobrien		insn = emit_insn
10761169689Skan		  (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
1076290075Sobrien			       GEN_INT (- args_to_push)));
1076390075Sobrien
1076490075Sobrien	      RTX_FRAME_RELATED_P (insn) = 1;
1076590075Sobrien
1076690075Sobrien	      saved_pretend_args = 1;
1076790075Sobrien	      fp_offset = args_to_push;
1076890075Sobrien	      args_to_push = 0;
1076990075Sobrien
1077090075Sobrien	      /* Now reuse r3 to preserve IP.  */
10771169689Skan	      emit_set_insn (gen_rtx_REG (SImode, 3), ip_rtx);
1077290075Sobrien	    }
1077390075Sobrien	}
1077490075Sobrien
10775169689Skan      insn = emit_set_insn (ip_rtx,
10776169689Skan			    plus_constant (stack_pointer_rtx, fp_offset));
1077790075Sobrien      RTX_FRAME_RELATED_P (insn) = 1;
1077890075Sobrien    }
1077990075Sobrien
1078090075Sobrien  if (args_to_push)
1078190075Sobrien    {
1078290075Sobrien      /* Push the argument registers, or reserve space for them.  */
1078396263Sobrien      if (cfun->machine->uses_anonymous_args)
1078490075Sobrien	insn = emit_multi_reg_push
1078590075Sobrien	  ((0xf0 >> (args_to_push / 4)) & 0xf);
1078690075Sobrien      else
1078790075Sobrien	insn = emit_insn
10788169689Skan	  (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
1078990075Sobrien		       GEN_INT (- args_to_push)));
1079090075Sobrien      RTX_FRAME_RELATED_P (insn) = 1;
1079190075Sobrien    }
1079290075Sobrien
10793117395Skan  /* If this is an interrupt service routine, and the link register
10794117395Skan     is going to be pushed, and we are not creating a stack frame,
10795117395Skan     (which would involve an extra push of IP and a pop in the epilogue)
10796117395Skan     subtracting four from LR now will mean that the function return
10797117395Skan     can be done with a single instruction.  */
1079896263Sobrien  if ((func_type == ARM_FT_ISR || func_type == ARM_FT_FIQ)
10799117395Skan      && (live_regs_mask & (1 << LR_REGNUM)) != 0
10800117395Skan      && ! frame_pointer_needed)
10801169689Skan    {
10802169689Skan      rtx lr = gen_rtx_REG (SImode, LR_REGNUM);
10803169689Skan
10804169689Skan      emit_set_insn (lr, plus_constant (lr, -4));
10805169689Skan    }
1080696263Sobrien
1080790075Sobrien  if (live_regs_mask)
1080890075Sobrien    {
1080990075Sobrien      insn = emit_multi_reg_push (live_regs_mask);
10810169689Skan      saved_regs += bit_count (live_regs_mask) * 4;
1081190075Sobrien      RTX_FRAME_RELATED_P (insn) = 1;
1081290075Sobrien    }
1081390075Sobrien
10814132718Skan  if (TARGET_IWMMXT)
10815169689Skan    for (reg = LAST_IWMMXT_REGNUM; reg >= FIRST_IWMMXT_REGNUM; reg--)
10816132718Skan      if (regs_ever_live[reg] && ! call_used_regs [reg])
10817132718Skan	{
10818132718Skan	  insn = gen_rtx_PRE_DEC (V2SImode, stack_pointer_rtx);
10819169689Skan	  insn = gen_frame_mem (V2SImode, insn);
10820169689Skan	  insn = emit_set_insn (insn, gen_rtx_REG (V2SImode, reg));
10821132718Skan	  RTX_FRAME_RELATED_P (insn) = 1;
10822169689Skan	  saved_regs += 8;
10823132718Skan	}
10824132718Skan
1082590075Sobrien  if (! IS_VOLATILE (func_type))
1082690075Sobrien    {
10827169689Skan      int start_reg;
10828169689Skan
10829132718Skan      /* Save any floating point call-saved registers used by this
10830132718Skan	 function.  */
10831132718Skan      if (arm_fpu_arch == FPUTYPE_FPA_EMU2)
1083290075Sobrien	{
10833169689Skan	  for (reg = LAST_FPA_REGNUM; reg >= FIRST_FPA_REGNUM; reg--)
1083490075Sobrien	    if (regs_ever_live[reg] && !call_used_regs[reg])
1083590075Sobrien	      {
1083690075Sobrien		insn = gen_rtx_PRE_DEC (XFmode, stack_pointer_rtx);
10837169689Skan		insn = gen_frame_mem (XFmode, insn);
10838169689Skan		insn = emit_set_insn (insn, gen_rtx_REG (XFmode, reg));
1083990075Sobrien		RTX_FRAME_RELATED_P (insn) = 1;
10840169689Skan		saved_regs += 12;
1084190075Sobrien	      }
1084290075Sobrien	}
1084390075Sobrien      else
1084490075Sobrien	{
10845169689Skan	  start_reg = LAST_FPA_REGNUM;
1084690075Sobrien
10847169689Skan	  for (reg = LAST_FPA_REGNUM; reg >= FIRST_FPA_REGNUM; reg--)
1084890075Sobrien	    {
1084990075Sobrien	      if (regs_ever_live[reg] && !call_used_regs[reg])
1085090075Sobrien		{
1085190075Sobrien		  if (start_reg - reg == 3)
1085290075Sobrien		    {
1085390075Sobrien		      insn = emit_sfm (reg, 4);
1085490075Sobrien		      RTX_FRAME_RELATED_P (insn) = 1;
10855169689Skan		      saved_regs += 48;
1085690075Sobrien		      start_reg = reg - 1;
1085790075Sobrien		    }
1085890075Sobrien		}
1085990075Sobrien	      else
1086090075Sobrien		{
1086190075Sobrien		  if (start_reg != reg)
1086290075Sobrien		    {
1086390075Sobrien		      insn = emit_sfm (reg + 1, start_reg - reg);
1086490075Sobrien		      RTX_FRAME_RELATED_P (insn) = 1;
10865169689Skan		      saved_regs += (start_reg - reg) * 12;
1086690075Sobrien		    }
1086790075Sobrien		  start_reg = reg - 1;
1086890075Sobrien		}
1086990075Sobrien	    }
1087090075Sobrien
1087190075Sobrien	  if (start_reg != reg)
1087290075Sobrien	    {
1087390075Sobrien	      insn = emit_sfm (reg + 1, start_reg - reg);
10874169689Skan	      saved_regs += (start_reg - reg) * 12;
1087590075Sobrien	      RTX_FRAME_RELATED_P (insn) = 1;
1087690075Sobrien	    }
1087790075Sobrien	}
10878169689Skan      if (TARGET_HARD_FLOAT && TARGET_VFP)
10879169689Skan	{
10880169689Skan	  start_reg = FIRST_VFP_REGNUM;
10881169689Skan
10882169689Skan 	  for (reg = FIRST_VFP_REGNUM; reg < LAST_VFP_REGNUM; reg += 2)
10883169689Skan	    {
10884169689Skan	      if ((!regs_ever_live[reg] || call_used_regs[reg])
10885169689Skan		  && (!regs_ever_live[reg + 1] || call_used_regs[reg + 1]))
10886169689Skan		{
10887169689Skan		  if (start_reg != reg)
10888169689Skan		    saved_regs += vfp_emit_fstmx (start_reg,
10889169689Skan						  (reg - start_reg) / 2);
10890169689Skan		  start_reg = reg + 2;
10891169689Skan		}
10892169689Skan	    }
10893169689Skan	  if (start_reg != reg)
10894169689Skan	    saved_regs += vfp_emit_fstmx (start_reg,
10895169689Skan					  (reg - start_reg) / 2);
10896169689Skan	}
1089790075Sobrien    }
1089890075Sobrien
1089990075Sobrien  if (frame_pointer_needed)
1090090075Sobrien    {
1090190075Sobrien      /* Create the new frame pointer.  */
1090290075Sobrien      insn = GEN_INT (-(4 + args_to_push + fp_offset));
1090390075Sobrien      insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx, ip_rtx, insn));
1090490075Sobrien      RTX_FRAME_RELATED_P (insn) = 1;
10905169689Skan
1090690075Sobrien      if (IS_NESTED (func_type))
1090790075Sobrien	{
1090890075Sobrien	  /* Recover the static chain register.  */
1090990075Sobrien	  if (regs_ever_live [3] == 0
1091090075Sobrien	      || saved_pretend_args)
1091190075Sobrien	    insn = gen_rtx_REG (SImode, 3);
1091290075Sobrien	  else /* if (current_function_pretend_args_size == 0) */
1091390075Sobrien	    {
10914169689Skan	      insn = plus_constant (hard_frame_pointer_rtx, 4);
10915169689Skan	      insn = gen_frame_mem (SImode, insn);
1091690075Sobrien	    }
1091790075Sobrien
10918169689Skan	  emit_set_insn (ip_rtx, insn);
1091990075Sobrien	  /* Add a USE to stop propagate_one_insn() from barfing.  */
1092090075Sobrien	  emit_insn (gen_prologue_use (ip_rtx));
1092190075Sobrien	}
1092290075Sobrien    }
1092390075Sobrien
10924169689Skan  offsets = arm_get_frame_offsets ();
10925169689Skan  if (offsets->outgoing_args != offsets->saved_args + saved_regs)
1092690075Sobrien    {
1092790075Sobrien      /* This add can produce multiple insns for a large constant, so we
1092890075Sobrien	 need to get tricky.  */
1092990075Sobrien      rtx last = get_last_insn ();
10930169689Skan
10931169689Skan      amount = GEN_INT (offsets->saved_args + saved_regs
10932169689Skan			- offsets->outgoing_args);
10933169689Skan
1093490075Sobrien      insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
1093590075Sobrien				    amount));
1093690075Sobrien      do
1093790075Sobrien	{
1093890075Sobrien	  last = last ? NEXT_INSN (last) : get_insns ();
1093990075Sobrien	  RTX_FRAME_RELATED_P (last) = 1;
1094090075Sobrien	}
1094190075Sobrien      while (last != insn);
1094290075Sobrien
1094390075Sobrien      /* If the frame pointer is needed, emit a special barrier that
1094490075Sobrien	 will prevent the scheduler from moving stores to the frame
1094590075Sobrien	 before the stack adjustment.  */
1094690075Sobrien      if (frame_pointer_needed)
10947117395Skan	insn = emit_insn (gen_stack_tie (stack_pointer_rtx,
10948117395Skan					 hard_frame_pointer_rtx));
1094990075Sobrien    }
1095090075Sobrien
10951169689Skan
10952169689Skan  if (flag_pic && arm_pic_register != INVALID_REGNUM)
10953169689Skan    arm_load_pic_register (0UL);
10954169689Skan
1095590075Sobrien  /* If we are profiling, make sure no instructions are scheduled before
1095690075Sobrien     the call to mcount.  Similarly if the user has requested no
10957169689Skan     scheduling in the prolog.  Similarly if we want non-call exceptions
10958169689Skan     using the EABI unwinder, to prevent faulting instructions from being
10959169689Skan     swapped with a stack adjustment.  */
10960169689Skan  if (current_function_profile || !TARGET_SCHED_PROLOG
10961169689Skan      || (ARM_EABI_UNWIND_TABLES && flag_non_call_exceptions))
1096290075Sobrien    emit_insn (gen_blockage ());
1096390075Sobrien
1096490075Sobrien  /* If the link register is being kept alive, with the return address in it,
1096590075Sobrien     then make sure that it does not get reused by the ce2 pass.  */
1096690075Sobrien  if ((live_regs_mask & (1 << LR_REGNUM)) == 0)
1096790075Sobrien    {
1096890075Sobrien      emit_insn (gen_prologue_use (gen_rtx_REG (SImode, LR_REGNUM)));
1096990075Sobrien      cfun->machine->lr_save_eliminated = 1;
1097090075Sobrien    }
1097190075Sobrien}
1097290075Sobrien
1097390075Sobrien/* If CODE is 'd', then the X is a condition operand and the instruction
1097490075Sobrien   should only be executed if the condition is true.
1097590075Sobrien   if CODE is 'D', then the X is a condition operand and the instruction
1097690075Sobrien   should only be executed if the condition is false: however, if the mode
1097790075Sobrien   of the comparison is CCFPEmode, then always execute the instruction -- we
1097890075Sobrien   do this because in these circumstances !GE does not necessarily imply LT;
1097990075Sobrien   in these cases the instruction pattern will take care to make sure that
1098090075Sobrien   an instruction containing %d will follow, thereby undoing the effects of
1098190075Sobrien   doing this instruction unconditionally.
1098290075Sobrien   If CODE is 'N' then X is a floating point operand that must be negated
1098390075Sobrien   before output.
1098490075Sobrien   If CODE is 'B' then output a bitwise inverted value of X (a const int).
1098590075Sobrien   If X is a REG and CODE is `M', output a ldm/stm style multi-reg.  */
1098690075Sobrienvoid
10987132718Skanarm_print_operand (FILE *stream, rtx x, int code)
1098890075Sobrien{
1098990075Sobrien  switch (code)
1099090075Sobrien    {
1099190075Sobrien    case '@':
1099290075Sobrien      fputs (ASM_COMMENT_START, stream);
1099390075Sobrien      return;
1099490075Sobrien
1099590075Sobrien    case '_':
1099690075Sobrien      fputs (user_label_prefix, stream);
1099790075Sobrien      return;
10998169689Skan
1099990075Sobrien    case '|':
1100090075Sobrien      fputs (REGISTER_PREFIX, stream);
1100190075Sobrien      return;
1100290075Sobrien
1100390075Sobrien    case '?':
1100490075Sobrien      if (arm_ccfsm_state == 3 || arm_ccfsm_state == 4)
1100590075Sobrien	{
11006169689Skan	  if (TARGET_THUMB)
11007169689Skan	    {
11008169689Skan	      output_operand_lossage ("predicated Thumb instruction");
11009169689Skan	      break;
11010169689Skan	    }
11011169689Skan	  if (current_insn_predicate != NULL)
11012169689Skan	    {
11013169689Skan	      output_operand_lossage
11014169689Skan		("predicated instruction in conditional sequence");
11015169689Skan	      break;
11016169689Skan	    }
1101790075Sobrien
1101890075Sobrien	  fputs (arm_condition_codes[arm_current_cc], stream);
1101990075Sobrien	}
1102090075Sobrien      else if (current_insn_predicate)
1102190075Sobrien	{
1102290075Sobrien	  enum arm_cond_code code;
1102390075Sobrien
1102490075Sobrien	  if (TARGET_THUMB)
11025169689Skan	    {
11026169689Skan	      output_operand_lossage ("predicated Thumb instruction");
11027169689Skan	      break;
11028169689Skan	    }
1102990075Sobrien
1103090075Sobrien	  code = get_arm_condition_code (current_insn_predicate);
1103190075Sobrien	  fputs (arm_condition_codes[code], stream);
1103290075Sobrien	}
1103390075Sobrien      return;
1103490075Sobrien
1103590075Sobrien    case 'N':
1103690075Sobrien      {
1103790075Sobrien	REAL_VALUE_TYPE r;
1103890075Sobrien	REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1103990075Sobrien	r = REAL_VALUE_NEGATE (r);
1104090075Sobrien	fprintf (stream, "%s", fp_const_from_val (&r));
1104190075Sobrien      }
1104290075Sobrien      return;
1104390075Sobrien
1104490075Sobrien    case 'B':
1104590075Sobrien      if (GET_CODE (x) == CONST_INT)
1104690075Sobrien	{
1104790075Sobrien	  HOST_WIDE_INT val;
1104890075Sobrien	  val = ARM_SIGN_EXTEND (~INTVAL (x));
1104990075Sobrien	  fprintf (stream, HOST_WIDE_INT_PRINT_DEC, val);
1105090075Sobrien	}
1105190075Sobrien      else
1105290075Sobrien	{
1105390075Sobrien	  putc ('~', stream);
1105490075Sobrien	  output_addr_const (stream, x);
1105590075Sobrien	}
1105690075Sobrien      return;
1105790075Sobrien
1105890075Sobrien    case 'i':
1105990075Sobrien      fprintf (stream, "%s", arithmetic_instr (x, 1));
1106090075Sobrien      return;
1106190075Sobrien
11062132718Skan    /* Truncate Cirrus shift counts.  */
11063132718Skan    case 's':
11064132718Skan      if (GET_CODE (x) == CONST_INT)
11065132718Skan	{
11066132718Skan	  fprintf (stream, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) & 0x3f);
11067132718Skan	  return;
11068132718Skan	}
11069132718Skan      arm_print_operand (stream, x, 0);
11070132718Skan      return;
11071132718Skan
1107290075Sobrien    case 'I':
1107390075Sobrien      fprintf (stream, "%s", arithmetic_instr (x, 0));
1107490075Sobrien      return;
1107590075Sobrien
1107690075Sobrien    case 'S':
1107790075Sobrien      {
1107890075Sobrien	HOST_WIDE_INT val;
11079169689Skan	const char *shift;
1108090075Sobrien
11081169689Skan	if (!shift_operator (x, SImode))
11082169689Skan	  {
11083169689Skan	    output_operand_lossage ("invalid shift operand");
11084169689Skan	    break;
11085169689Skan	  }
11086169689Skan
11087169689Skan	shift = shift_op (x, &val);
11088169689Skan
1108990075Sobrien	if (shift)
1109090075Sobrien	  {
11091169689Skan	    fprintf (stream, ", %s ", shift);
1109290075Sobrien	    if (val == -1)
1109390075Sobrien	      arm_print_operand (stream, XEXP (x, 1), 0);
1109490075Sobrien	    else
11095132718Skan	      fprintf (stream, "#" HOST_WIDE_INT_PRINT_DEC, val);
1109690075Sobrien	  }
1109790075Sobrien      }
1109890075Sobrien      return;
1109990075Sobrien
1110090075Sobrien      /* An explanation of the 'Q', 'R' and 'H' register operands:
11101169689Skan
1110290075Sobrien	 In a pair of registers containing a DI or DF value the 'Q'
1110390075Sobrien	 operand returns the register number of the register containing
11104132718Skan	 the least significant part of the value.  The 'R' operand returns
1110590075Sobrien	 the register number of the register containing the most
1110690075Sobrien	 significant part of the value.
11107169689Skan
1110890075Sobrien	 The 'H' operand returns the higher of the two register numbers.
1110990075Sobrien	 On a run where WORDS_BIG_ENDIAN is true the 'H' operand is the
11110132718Skan	 same as the 'Q' operand, since the most significant part of the
1111190075Sobrien	 value is held in the lower number register.  The reverse is true
1111290075Sobrien	 on systems where WORDS_BIG_ENDIAN is false.
11113169689Skan
1111490075Sobrien	 The purpose of these operands is to distinguish between cases
1111590075Sobrien	 where the endian-ness of the values is important (for example
1111690075Sobrien	 when they are added together), and cases where the endian-ness
1111790075Sobrien	 is irrelevant, but the order of register operations is important.
1111890075Sobrien	 For example when loading a value from memory into a register
1111990075Sobrien	 pair, the endian-ness does not matter.  Provided that the value
1112090075Sobrien	 from the lower memory address is put into the lower numbered
1112190075Sobrien	 register, and the value from the higher address is put into the
1112290075Sobrien	 higher numbered register, the load will work regardless of whether
1112390075Sobrien	 the value being loaded is big-wordian or little-wordian.  The
1112490075Sobrien	 order of the two register loads can matter however, if the address
1112590075Sobrien	 of the memory location is actually held in one of the registers
1112690075Sobrien	 being overwritten by the load.  */
1112790075Sobrien    case 'Q':
11128169689Skan      if (GET_CODE (x) != REG || REGNO (x) > LAST_ARM_REGNUM)
11129169689Skan	{
11130169689Skan	  output_operand_lossage ("invalid operand for code '%c'", code);
11131169689Skan	  return;
11132169689Skan	}
11133169689Skan
1113490075Sobrien      asm_fprintf (stream, "%r", REGNO (x) + (WORDS_BIG_ENDIAN ? 1 : 0));
1113590075Sobrien      return;
1113690075Sobrien
1113790075Sobrien    case 'R':
11138169689Skan      if (GET_CODE (x) != REG || REGNO (x) > LAST_ARM_REGNUM)
11139169689Skan	{
11140169689Skan	  output_operand_lossage ("invalid operand for code '%c'", code);
11141169689Skan	  return;
11142169689Skan	}
11143169689Skan
1114490075Sobrien      asm_fprintf (stream, "%r", REGNO (x) + (WORDS_BIG_ENDIAN ? 0 : 1));
1114590075Sobrien      return;
1114690075Sobrien
1114790075Sobrien    case 'H':
11148169689Skan      if (GET_CODE (x) != REG || REGNO (x) > LAST_ARM_REGNUM)
11149169689Skan	{
11150169689Skan	  output_operand_lossage ("invalid operand for code '%c'", code);
11151169689Skan	  return;
11152169689Skan	}
11153169689Skan
1115490075Sobrien      asm_fprintf (stream, "%r", REGNO (x) + 1);
1115590075Sobrien      return;
1115690075Sobrien
1115790075Sobrien    case 'm':
11158169689Skan      asm_fprintf (stream, "%r",
1115990075Sobrien		   GET_CODE (XEXP (x, 0)) == REG
1116090075Sobrien		   ? REGNO (XEXP (x, 0)) : REGNO (XEXP (XEXP (x, 0), 0)));
1116190075Sobrien      return;
1116290075Sobrien
1116390075Sobrien    case 'M':
1116490075Sobrien      asm_fprintf (stream, "{%r-%r}",
1116590075Sobrien		   REGNO (x),
11166117395Skan		   REGNO (x) + ARM_NUM_REGS (GET_MODE (x)) - 1);
1116790075Sobrien      return;
1116890075Sobrien
1116990075Sobrien    case 'd':
11170117395Skan      /* CONST_TRUE_RTX means always -- that's the default.  */
11171117395Skan      if (x == const_true_rtx)
1117290075Sobrien	return;
11173169689Skan
11174169689Skan      if (!COMPARISON_P (x))
11175169689Skan	{
11176169689Skan	  output_operand_lossage ("invalid operand for code '%c'", code);
11177169689Skan	  return;
11178169689Skan	}
11179169689Skan
11180132718Skan      fputs (arm_condition_codes[get_arm_condition_code (x)],
11181132718Skan	     stream);
1118290075Sobrien      return;
1118390075Sobrien
1118490075Sobrien    case 'D':
11185169689Skan      /* CONST_TRUE_RTX means not always -- i.e. never.  We shouldn't ever
11186117395Skan	 want to do that.  */
11187117395Skan      if (x == const_true_rtx)
11188169689Skan	{
11189169689Skan	  output_operand_lossage ("instruction never exectued");
11190169689Skan	  return;
11191169689Skan	}
11192169689Skan      if (!COMPARISON_P (x))
11193169689Skan	{
11194169689Skan	  output_operand_lossage ("invalid operand for code '%c'", code);
11195169689Skan	  return;
11196169689Skan	}
1119790075Sobrien
11198132718Skan      fputs (arm_condition_codes[ARM_INVERSE_CONDITION_CODE
11199132718Skan				 (get_arm_condition_code (x))],
11200132718Skan	     stream);
11201132718Skan      return;
11202132718Skan
11203132718Skan    /* Cirrus registers can be accessed in a variety of ways:
11204132718Skan         single floating point (f)
11205132718Skan	 double floating point (d)
11206132718Skan	 32bit integer         (fx)
11207132718Skan	 64bit integer         (dx).  */
11208132718Skan    case 'W':			/* Cirrus register in F mode.  */
11209132718Skan    case 'X':			/* Cirrus register in D mode.  */
11210132718Skan    case 'Y':			/* Cirrus register in FX mode.  */
11211132718Skan    case 'Z':			/* Cirrus register in DX mode.  */
11212169689Skan      gcc_assert (GET_CODE (x) == REG
11213169689Skan		  && REGNO_REG_CLASS (REGNO (x)) == CIRRUS_REGS);
11214132718Skan
11215132718Skan      fprintf (stream, "mv%s%s",
11216132718Skan	       code == 'W' ? "f"
11217132718Skan	       : code == 'X' ? "d"
11218132718Skan	       : code == 'Y' ? "fx" : "dx", reg_names[REGNO (x)] + 2);
11219132718Skan
11220132718Skan      return;
11221132718Skan
11222132718Skan    /* Print cirrus register in the mode specified by the register's mode.  */
11223132718Skan    case 'V':
11224132718Skan      {
11225132718Skan	int mode = GET_MODE (x);
11226132718Skan
11227132718Skan	if (GET_CODE (x) != REG || REGNO_REG_CLASS (REGNO (x)) != CIRRUS_REGS)
11228169689Skan	  {
11229169689Skan	    output_operand_lossage ("invalid operand for code '%c'", code);
11230169689Skan	    return;
11231169689Skan	  }
11232132718Skan
11233132718Skan	fprintf (stream, "mv%s%s",
11234132718Skan		 mode == DFmode ? "d"
11235132718Skan		 : mode == SImode ? "fx"
11236132718Skan		 : mode == DImode ? "dx"
11237132718Skan		 : "f", reg_names[REGNO (x)] + 2);
11238132718Skan
11239132718Skan	return;
11240132718Skan      }
11241132718Skan
11242132718Skan    case 'U':
11243132718Skan      if (GET_CODE (x) != REG
11244132718Skan	  || REGNO (x) < FIRST_IWMMXT_GR_REGNUM
11245132718Skan	  || REGNO (x) > LAST_IWMMXT_GR_REGNUM)
11246132718Skan	/* Bad value for wCG register number.  */
11247169689Skan	{
11248169689Skan	  output_operand_lossage ("invalid operand for code '%c'", code);
11249169689Skan	  return;
11250169689Skan	}
11251169689Skan
1125290075Sobrien      else
11253132718Skan	fprintf (stream, "%d", REGNO (x) - FIRST_IWMMXT_GR_REGNUM);
1125490075Sobrien      return;
1125590075Sobrien
11256132718Skan      /* Print an iWMMXt control register name.  */
11257132718Skan    case 'w':
11258132718Skan      if (GET_CODE (x) != CONST_INT
11259132718Skan	  || INTVAL (x) < 0
11260132718Skan	  || INTVAL (x) >= 16)
11261132718Skan	/* Bad value for wC register number.  */
11262169689Skan	{
11263169689Skan	  output_operand_lossage ("invalid operand for code '%c'", code);
11264169689Skan	  return;
11265169689Skan	}
11266169689Skan
11267132718Skan      else
11268132718Skan	{
11269132718Skan	  static const char * wc_reg_names [16] =
11270132718Skan	    {
11271132718Skan	      "wCID",  "wCon",  "wCSSF", "wCASF",
11272132718Skan	      "wC4",   "wC5",   "wC6",   "wC7",
11273132718Skan	      "wCGR0", "wCGR1", "wCGR2", "wCGR3",
11274132718Skan	      "wC12",  "wC13",  "wC14",  "wC15"
11275132718Skan	    };
11276169689Skan
11277132718Skan	  fprintf (stream, wc_reg_names [INTVAL (x)]);
11278132718Skan	}
11279132718Skan      return;
11280132718Skan
11281169689Skan      /* Print a VFP double precision register name.  */
11282169689Skan    case 'P':
11283169689Skan      {
11284169689Skan	int mode = GET_MODE (x);
11285169689Skan	int num;
11286169689Skan
11287169689Skan	if (mode != DImode && mode != DFmode)
11288169689Skan	  {
11289169689Skan	    output_operand_lossage ("invalid operand for code '%c'", code);
11290169689Skan	    return;
11291169689Skan	  }
11292169689Skan
11293169689Skan	if (GET_CODE (x) != REG
11294169689Skan	    || !IS_VFP_REGNUM (REGNO (x)))
11295169689Skan	  {
11296169689Skan	    output_operand_lossage ("invalid operand for code '%c'", code);
11297169689Skan	    return;
11298169689Skan	  }
11299169689Skan
11300169689Skan	num = REGNO(x) - FIRST_VFP_REGNUM;
11301169689Skan	if (num & 1)
11302169689Skan	  {
11303169689Skan	    output_operand_lossage ("invalid operand for code '%c'", code);
11304169689Skan	    return;
11305169689Skan	  }
11306169689Skan
11307169689Skan	fprintf (stream, "d%d", num >> 1);
11308169689Skan      }
11309169689Skan      return;
11310169689Skan
1131190075Sobrien    default:
1131290075Sobrien      if (x == 0)
11313169689Skan	{
11314169689Skan	  output_operand_lossage ("missing operand");
11315169689Skan	  return;
11316169689Skan	}
1131790075Sobrien
11318169689Skan      switch (GET_CODE (x))
1131990075Sobrien	{
11320169689Skan	case REG:
11321169689Skan	  asm_fprintf (stream, "%r", REGNO (x));
11322169689Skan	  break;
11323169689Skan
11324169689Skan	case MEM:
1132590075Sobrien	  output_memory_reference_mode = GET_MODE (x);
1132690075Sobrien	  output_address (XEXP (x, 0));
11327169689Skan	  break;
11328169689Skan
11329169689Skan	case CONST_DOUBLE:
11330169689Skan	  fprintf (stream, "#%s", fp_immediate_constant (x));
11331169689Skan	  break;
11332169689Skan
11333169689Skan	default:
11334169689Skan	  gcc_assert (GET_CODE (x) != NEG);
1133590075Sobrien	  fputc ('#', stream);
1133690075Sobrien	  output_addr_const (stream, x);
11337169689Skan	  break;
1133890075Sobrien	}
1133990075Sobrien    }
1134090075Sobrien}
1134190075Sobrien
1134290075Sobrien#ifndef AOF_ASSEMBLER
1134390075Sobrien/* Target hook for assembling integer objects.  The ARM version needs to
1134490075Sobrien   handle word-sized values specially.  */
1134590075Sobrienstatic bool
11346132718Skanarm_assemble_integer (rtx x, unsigned int size, int aligned_p)
1134790075Sobrien{
1134890075Sobrien  if (size == UNITS_PER_WORD && aligned_p)
1134990075Sobrien    {
1135090075Sobrien      fputs ("\t.word\t", asm_out_file);
1135190075Sobrien      output_addr_const (asm_out_file, x);
1135290075Sobrien
1135390075Sobrien      /* Mark symbols as position independent.  We only do this in the
11354132718Skan	 .text segment, not in the .data segment.  */
1135590075Sobrien      if (NEED_GOT_RELOC && flag_pic && making_const_table &&
1135690075Sobrien	  (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF))
1135790075Sobrien	{
11358117395Skan	  if (GET_CODE (x) == SYMBOL_REF
1135996263Sobrien	      && (CONSTANT_POOL_ADDRESS_P (x)
11360132718Skan		  || SYMBOL_REF_LOCAL_P (x)))
1136190075Sobrien	    fputs ("(GOTOFF)", asm_out_file);
1136290075Sobrien	  else if (GET_CODE (x) == LABEL_REF)
1136390075Sobrien	    fputs ("(GOTOFF)", asm_out_file);
1136490075Sobrien	  else
1136590075Sobrien	    fputs ("(GOT)", asm_out_file);
1136690075Sobrien	}
1136790075Sobrien      fputc ('\n', asm_out_file);
1136890075Sobrien      return true;
1136990075Sobrien    }
1137090075Sobrien
11371169689Skan  if (arm_vector_mode_supported_p (GET_MODE (x)))
11372132718Skan    {
11373132718Skan      int i, units;
11374132718Skan
11375169689Skan      gcc_assert (GET_CODE (x) == CONST_VECTOR);
11376132718Skan
11377132718Skan      units = CONST_VECTOR_NUNITS (x);
11378132718Skan
11379132718Skan      switch (GET_MODE (x))
11380132718Skan	{
11381132718Skan	case V2SImode: size = 4; break;
11382132718Skan	case V4HImode: size = 2; break;
11383132718Skan	case V8QImode: size = 1; break;
11384132718Skan	default:
11385169689Skan	  gcc_unreachable ();
11386132718Skan	}
11387132718Skan
11388132718Skan      for (i = 0; i < units; i++)
11389132718Skan	{
11390132718Skan	  rtx elt;
11391132718Skan
11392132718Skan	  elt = CONST_VECTOR_ELT (x, i);
11393132718Skan	  assemble_integer
11394132718Skan	    (elt, size, i == 0 ? BIGGEST_ALIGNMENT : size * BITS_PER_UNIT, 1);
11395132718Skan	}
11396132718Skan
11397132718Skan      return true;
11398132718Skan    }
11399132718Skan
1140090075Sobrien  return default_assemble_integer (x, size, aligned_p);
1140190075Sobrien}
11402169689Skan
11403169689Skan
11404169689Skan/* Add a function to the list of static constructors.  */
11405169689Skan
11406169689Skanstatic void
11407169689Skanarm_elf_asm_constructor (rtx symbol, int priority ATTRIBUTE_UNUSED)
11408169689Skan{
11409169689Skan  if (!TARGET_AAPCS_BASED)
11410169689Skan    {
11411169689Skan      default_named_section_asm_out_constructor (symbol, priority);
11412169689Skan      return;
11413169689Skan    }
11414169689Skan
11415169689Skan  /* Put these in the .init_array section, using a special relocation.  */
11416169689Skan  switch_to_section (ctors_section);
11417169689Skan  assemble_align (POINTER_SIZE);
11418169689Skan  fputs ("\t.word\t", asm_out_file);
11419169689Skan  output_addr_const (asm_out_file, symbol);
11420169689Skan  fputs ("(target1)\n", asm_out_file);
11421169689Skan}
1142290075Sobrien#endif
1142390075Sobrien
1142490075Sobrien/* A finite state machine takes care of noticing whether or not instructions
1142590075Sobrien   can be conditionally executed, and thus decrease execution time and code
1142690075Sobrien   size by deleting branch instructions.  The fsm is controlled by
1142790075Sobrien   final_prescan_insn, and controls the actions of ASM_OUTPUT_OPCODE.  */
1142890075Sobrien
1142990075Sobrien/* The state of the fsm controlling condition codes are:
1143090075Sobrien   0: normal, do nothing special
1143190075Sobrien   1: make ASM_OUTPUT_OPCODE not output this instruction
1143290075Sobrien   2: make ASM_OUTPUT_OPCODE not output this instruction
1143390075Sobrien   3: make instructions conditional
1143490075Sobrien   4: make instructions conditional
1143590075Sobrien
1143690075Sobrien   State transitions (state->state by whom under condition):
1143790075Sobrien   0 -> 1 final_prescan_insn if the `target' is a label
1143890075Sobrien   0 -> 2 final_prescan_insn if the `target' is an unconditional branch
1143990075Sobrien   1 -> 3 ASM_OUTPUT_OPCODE after not having output the conditional branch
1144090075Sobrien   2 -> 4 ASM_OUTPUT_OPCODE after not having output the conditional branch
11441132718Skan   3 -> 0 (*targetm.asm_out.internal_label) if the `target' label is reached
1144290075Sobrien          (the target label has CODE_LABEL_NUMBER equal to arm_target_label).
1144390075Sobrien   4 -> 0 final_prescan_insn if the `target' unconditional branch is reached
1144490075Sobrien          (the target insn is arm_target_insn).
1144590075Sobrien
1144690075Sobrien   If the jump clobbers the conditions then we use states 2 and 4.
1144790075Sobrien
1144890075Sobrien   A similar thing can be done with conditional return insns.
1144990075Sobrien
1145090075Sobrien   XXX In case the `target' is an unconditional branch, this conditionalising
1145190075Sobrien   of the instructions always reduces code size, but not always execution
1145290075Sobrien   time.  But then, I want to reduce the code size to somewhere near what
1145390075Sobrien   /bin/cc produces.  */
1145490075Sobrien
1145590075Sobrien/* Returns the index of the ARM condition code string in
1145690075Sobrien   `arm_condition_codes'.  COMPARISON should be an rtx like
1145790075Sobrien   `(eq (...) (...))'.  */
1145890075Sobrienstatic enum arm_cond_code
11459132718Skanget_arm_condition_code (rtx comparison)
1146090075Sobrien{
1146190075Sobrien  enum machine_mode mode = GET_MODE (XEXP (comparison, 0));
1146290075Sobrien  int code;
1146390075Sobrien  enum rtx_code comp_code = GET_CODE (comparison);
1146490075Sobrien
1146590075Sobrien  if (GET_MODE_CLASS (mode) != MODE_CC)
1146690075Sobrien    mode = SELECT_CC_MODE (comp_code, XEXP (comparison, 0),
1146790075Sobrien			   XEXP (comparison, 1));
1146890075Sobrien
1146990075Sobrien  switch (mode)
1147090075Sobrien    {
1147190075Sobrien    case CC_DNEmode: code = ARM_NE; goto dominance;
1147290075Sobrien    case CC_DEQmode: code = ARM_EQ; goto dominance;
1147390075Sobrien    case CC_DGEmode: code = ARM_GE; goto dominance;
1147490075Sobrien    case CC_DGTmode: code = ARM_GT; goto dominance;
1147590075Sobrien    case CC_DLEmode: code = ARM_LE; goto dominance;
1147690075Sobrien    case CC_DLTmode: code = ARM_LT; goto dominance;
1147790075Sobrien    case CC_DGEUmode: code = ARM_CS; goto dominance;
1147890075Sobrien    case CC_DGTUmode: code = ARM_HI; goto dominance;
1147990075Sobrien    case CC_DLEUmode: code = ARM_LS; goto dominance;
1148090075Sobrien    case CC_DLTUmode: code = ARM_CC;
1148190075Sobrien
1148290075Sobrien    dominance:
11483169689Skan      gcc_assert (comp_code == EQ || comp_code == NE);
1148490075Sobrien
1148590075Sobrien      if (comp_code == EQ)
1148690075Sobrien	return ARM_INVERSE_CONDITION_CODE (code);
1148790075Sobrien      return code;
1148890075Sobrien
1148990075Sobrien    case CC_NOOVmode:
1149090075Sobrien      switch (comp_code)
1149190075Sobrien	{
1149290075Sobrien	case NE: return ARM_NE;
1149390075Sobrien	case EQ: return ARM_EQ;
1149490075Sobrien	case GE: return ARM_PL;
1149590075Sobrien	case LT: return ARM_MI;
11496169689Skan	default: gcc_unreachable ();
1149790075Sobrien	}
1149890075Sobrien
1149990075Sobrien    case CC_Zmode:
1150090075Sobrien      switch (comp_code)
1150190075Sobrien	{
1150290075Sobrien	case NE: return ARM_NE;
1150390075Sobrien	case EQ: return ARM_EQ;
11504169689Skan	default: gcc_unreachable ();
1150590075Sobrien	}
1150690075Sobrien
11507132718Skan    case CC_Nmode:
11508132718Skan      switch (comp_code)
11509132718Skan	{
11510132718Skan	case NE: return ARM_MI;
11511132718Skan	case EQ: return ARM_PL;
11512169689Skan	default: gcc_unreachable ();
11513132718Skan	}
11514132718Skan
1151590075Sobrien    case CCFPEmode:
1151690075Sobrien    case CCFPmode:
1151790075Sobrien      /* These encodings assume that AC=1 in the FPA system control
1151890075Sobrien	 byte.  This allows us to handle all cases except UNEQ and
1151990075Sobrien	 LTGT.  */
1152090075Sobrien      switch (comp_code)
1152190075Sobrien	{
1152290075Sobrien	case GE: return ARM_GE;
1152390075Sobrien	case GT: return ARM_GT;
1152490075Sobrien	case LE: return ARM_LS;
1152590075Sobrien	case LT: return ARM_MI;
1152690075Sobrien	case NE: return ARM_NE;
1152790075Sobrien	case EQ: return ARM_EQ;
1152890075Sobrien	case ORDERED: return ARM_VC;
1152990075Sobrien	case UNORDERED: return ARM_VS;
1153090075Sobrien	case UNLT: return ARM_LT;
1153190075Sobrien	case UNLE: return ARM_LE;
1153290075Sobrien	case UNGT: return ARM_HI;
1153390075Sobrien	case UNGE: return ARM_PL;
1153490075Sobrien	  /* UNEQ and LTGT do not have a representation.  */
1153590075Sobrien	case UNEQ: /* Fall through.  */
1153690075Sobrien	case LTGT: /* Fall through.  */
11537169689Skan	default: gcc_unreachable ();
1153890075Sobrien	}
1153990075Sobrien
1154090075Sobrien    case CC_SWPmode:
1154190075Sobrien      switch (comp_code)
1154290075Sobrien	{
1154390075Sobrien	case NE: return ARM_NE;
1154490075Sobrien	case EQ: return ARM_EQ;
1154590075Sobrien	case GE: return ARM_LE;
1154690075Sobrien	case GT: return ARM_LT;
1154790075Sobrien	case LE: return ARM_GE;
1154890075Sobrien	case LT: return ARM_GT;
1154990075Sobrien	case GEU: return ARM_LS;
1155090075Sobrien	case GTU: return ARM_CC;
1155190075Sobrien	case LEU: return ARM_CS;
1155290075Sobrien	case LTU: return ARM_HI;
11553169689Skan	default: gcc_unreachable ();
1155490075Sobrien	}
1155590075Sobrien
1155690075Sobrien    case CC_Cmode:
1155790075Sobrien      switch (comp_code)
1155890075Sobrien      {
1155990075Sobrien      case LTU: return ARM_CS;
1156090075Sobrien      case GEU: return ARM_CC;
11561169689Skan      default: gcc_unreachable ();
1156290075Sobrien      }
11563169689Skan
1156490075Sobrien    case CCmode:
1156590075Sobrien      switch (comp_code)
1156690075Sobrien	{
1156790075Sobrien	case NE: return ARM_NE;
1156890075Sobrien	case EQ: return ARM_EQ;
1156990075Sobrien	case GE: return ARM_GE;
1157090075Sobrien	case GT: return ARM_GT;
1157190075Sobrien	case LE: return ARM_LE;
1157290075Sobrien	case LT: return ARM_LT;
1157390075Sobrien	case GEU: return ARM_CS;
1157490075Sobrien	case GTU: return ARM_HI;
1157590075Sobrien	case LEU: return ARM_LS;
1157690075Sobrien	case LTU: return ARM_CC;
11577169689Skan	default: gcc_unreachable ();
1157890075Sobrien	}
1157990075Sobrien
11580169689Skan    default: gcc_unreachable ();
1158190075Sobrien    }
1158290075Sobrien}
1158390075Sobrien
1158490075Sobrienvoid
11585132718Skanarm_final_prescan_insn (rtx insn)
1158690075Sobrien{
1158790075Sobrien  /* BODY will hold the body of INSN.  */
1158890075Sobrien  rtx body = PATTERN (insn);
1158990075Sobrien
1159090075Sobrien  /* This will be 1 if trying to repeat the trick, and things need to be
1159190075Sobrien     reversed if it appears to fail.  */
1159290075Sobrien  int reverse = 0;
1159390075Sobrien
1159490075Sobrien  /* JUMP_CLOBBERS will be one implies that the conditions if a branch is
1159590075Sobrien     taken are clobbered, even if the rtl suggests otherwise.  It also
1159690075Sobrien     means that we have to grub around within the jump expression to find
1159790075Sobrien     out what the conditions are when the jump isn't taken.  */
1159890075Sobrien  int jump_clobbers = 0;
11599169689Skan
1160090075Sobrien  /* If we start with a return insn, we only succeed if we find another one.  */
1160190075Sobrien  int seeking_return = 0;
11602169689Skan
1160390075Sobrien  /* START_INSN will hold the insn from where we start looking.  This is the
1160490075Sobrien     first insn after the following code_label if REVERSE is true.  */
1160590075Sobrien  rtx start_insn = insn;
1160690075Sobrien
1160790075Sobrien  /* If in state 4, check if the target branch is reached, in order to
1160890075Sobrien     change back to state 0.  */
1160990075Sobrien  if (arm_ccfsm_state == 4)
1161090075Sobrien    {
1161190075Sobrien      if (insn == arm_target_insn)
1161290075Sobrien	{
1161390075Sobrien	  arm_target_insn = NULL;
1161490075Sobrien	  arm_ccfsm_state = 0;
1161590075Sobrien	}
1161690075Sobrien      return;
1161790075Sobrien    }
1161890075Sobrien
1161990075Sobrien  /* If in state 3, it is possible to repeat the trick, if this insn is an
1162090075Sobrien     unconditional branch to a label, and immediately following this branch
1162190075Sobrien     is the previous target label which is only used once, and the label this
1162290075Sobrien     branch jumps to is not too far off.  */
1162390075Sobrien  if (arm_ccfsm_state == 3)
1162490075Sobrien    {
1162590075Sobrien      if (simplejump_p (insn))
1162690075Sobrien	{
1162790075Sobrien	  start_insn = next_nonnote_insn (start_insn);
1162890075Sobrien	  if (GET_CODE (start_insn) == BARRIER)
1162990075Sobrien	    {
1163090075Sobrien	      /* XXX Isn't this always a barrier?  */
1163190075Sobrien	      start_insn = next_nonnote_insn (start_insn);
1163290075Sobrien	    }
1163390075Sobrien	  if (GET_CODE (start_insn) == CODE_LABEL
1163490075Sobrien	      && CODE_LABEL_NUMBER (start_insn) == arm_target_label
1163590075Sobrien	      && LABEL_NUSES (start_insn) == 1)
1163690075Sobrien	    reverse = TRUE;
1163790075Sobrien	  else
1163890075Sobrien	    return;
1163990075Sobrien	}
1164090075Sobrien      else if (GET_CODE (body) == RETURN)
1164190075Sobrien        {
1164290075Sobrien	  start_insn = next_nonnote_insn (start_insn);
1164390075Sobrien	  if (GET_CODE (start_insn) == BARRIER)
1164490075Sobrien	    start_insn = next_nonnote_insn (start_insn);
1164590075Sobrien	  if (GET_CODE (start_insn) == CODE_LABEL
1164690075Sobrien	      && CODE_LABEL_NUMBER (start_insn) == arm_target_label
1164790075Sobrien	      && LABEL_NUSES (start_insn) == 1)
1164890075Sobrien	    {
1164990075Sobrien	      reverse = TRUE;
1165090075Sobrien	      seeking_return = 1;
1165190075Sobrien	    }
1165290075Sobrien	  else
1165390075Sobrien	    return;
1165490075Sobrien        }
1165590075Sobrien      else
1165690075Sobrien	return;
1165790075Sobrien    }
1165890075Sobrien
11659169689Skan  gcc_assert (!arm_ccfsm_state || reverse);
1166090075Sobrien  if (GET_CODE (insn) != JUMP_INSN)
1166190075Sobrien    return;
1166290075Sobrien
11663169689Skan  /* This jump might be paralleled with a clobber of the condition codes
1166490075Sobrien     the jump should always come first */
1166590075Sobrien  if (GET_CODE (body) == PARALLEL && XVECLEN (body, 0) > 0)
1166690075Sobrien    body = XVECEXP (body, 0, 0);
1166790075Sobrien
1166890075Sobrien  if (reverse
1166990075Sobrien      || (GET_CODE (body) == SET && GET_CODE (SET_DEST (body)) == PC
1167090075Sobrien	  && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE))
1167190075Sobrien    {
1167290075Sobrien      int insns_skipped;
1167390075Sobrien      int fail = FALSE, succeed = FALSE;
1167490075Sobrien      /* Flag which part of the IF_THEN_ELSE is the LABEL_REF.  */
1167590075Sobrien      int then_not_else = TRUE;
1167690075Sobrien      rtx this_insn = start_insn, label = 0;
1167790075Sobrien
11678169689Skan      /* If the jump cannot be done with one instruction, we cannot
1167990075Sobrien	 conditionally execute the instruction in the inverse case.  */
1168090075Sobrien      if (get_attr_conds (insn) == CONDS_JUMP_CLOB)
1168190075Sobrien	{
1168290075Sobrien	  jump_clobbers = 1;
1168390075Sobrien	  return;
1168490075Sobrien	}
11685169689Skan
1168690075Sobrien      /* Register the insn jumped to.  */
1168790075Sobrien      if (reverse)
1168890075Sobrien        {
1168990075Sobrien	  if (!seeking_return)
1169090075Sobrien	    label = XEXP (SET_SRC (body), 0);
1169190075Sobrien        }
1169290075Sobrien      else if (GET_CODE (XEXP (SET_SRC (body), 1)) == LABEL_REF)
1169390075Sobrien	label = XEXP (XEXP (SET_SRC (body), 1), 0);
1169490075Sobrien      else if (GET_CODE (XEXP (SET_SRC (body), 2)) == LABEL_REF)
1169590075Sobrien	{
1169690075Sobrien	  label = XEXP (XEXP (SET_SRC (body), 2), 0);
1169790075Sobrien	  then_not_else = FALSE;
1169890075Sobrien	}
1169990075Sobrien      else if (GET_CODE (XEXP (SET_SRC (body), 1)) == RETURN)
1170090075Sobrien	seeking_return = 1;
1170190075Sobrien      else if (GET_CODE (XEXP (SET_SRC (body), 2)) == RETURN)
1170290075Sobrien        {
1170390075Sobrien	  seeking_return = 1;
1170490075Sobrien	  then_not_else = FALSE;
1170590075Sobrien        }
1170690075Sobrien      else
11707169689Skan	gcc_unreachable ();
1170890075Sobrien
1170990075Sobrien      /* See how many insns this branch skips, and what kind of insns.  If all
1171090075Sobrien	 insns are okay, and the label or unconditional branch to the same
1171190075Sobrien	 label is not too far away, succeed.  */
1171290075Sobrien      for (insns_skipped = 0;
1171390075Sobrien	   !fail && !succeed && insns_skipped++ < max_insns_skipped;)
1171490075Sobrien	{
1171590075Sobrien	  rtx scanbody;
1171690075Sobrien
1171790075Sobrien	  this_insn = next_nonnote_insn (this_insn);
1171890075Sobrien	  if (!this_insn)
1171990075Sobrien	    break;
1172090075Sobrien
1172190075Sobrien	  switch (GET_CODE (this_insn))
1172290075Sobrien	    {
1172390075Sobrien	    case CODE_LABEL:
1172490075Sobrien	      /* Succeed if it is the target label, otherwise fail since
1172590075Sobrien		 control falls in from somewhere else.  */
1172690075Sobrien	      if (this_insn == label)
1172790075Sobrien		{
1172890075Sobrien		  if (jump_clobbers)
1172990075Sobrien		    {
1173090075Sobrien		      arm_ccfsm_state = 2;
1173190075Sobrien		      this_insn = next_nonnote_insn (this_insn);
1173290075Sobrien		    }
1173390075Sobrien		  else
1173490075Sobrien		    arm_ccfsm_state = 1;
1173590075Sobrien		  succeed = TRUE;
1173690075Sobrien		}
1173790075Sobrien	      else
1173890075Sobrien		fail = TRUE;
1173990075Sobrien	      break;
1174090075Sobrien
1174190075Sobrien	    case BARRIER:
1174290075Sobrien	      /* Succeed if the following insn is the target label.
11743169689Skan		 Otherwise fail.
11744169689Skan		 If return insns are used then the last insn in a function
1174590075Sobrien		 will be a barrier.  */
1174690075Sobrien	      this_insn = next_nonnote_insn (this_insn);
1174790075Sobrien	      if (this_insn && this_insn == label)
1174890075Sobrien		{
1174990075Sobrien		  if (jump_clobbers)
1175090075Sobrien		    {
1175190075Sobrien		      arm_ccfsm_state = 2;
1175290075Sobrien		      this_insn = next_nonnote_insn (this_insn);
1175390075Sobrien		    }
1175490075Sobrien		  else
1175590075Sobrien		    arm_ccfsm_state = 1;
1175690075Sobrien		  succeed = TRUE;
1175790075Sobrien		}
1175890075Sobrien	      else
1175990075Sobrien		fail = TRUE;
1176090075Sobrien	      break;
1176190075Sobrien
1176290075Sobrien	    case CALL_INSN:
11763169689Skan	      /* The AAPCS says that conditional calls should not be
11764169689Skan		 used since they make interworking inefficient (the
11765169689Skan		 linker can't transform BL<cond> into BLX).  That's
11766169689Skan		 only a problem if the machine has BLX.  */
11767169689Skan	      if (arm_arch5)
1176890075Sobrien		{
11769169689Skan		  fail = TRUE;
11770169689Skan		  break;
11771169689Skan		}
1177290075Sobrien
11773169689Skan	      /* Succeed if the following insn is the target label, or
11774169689Skan		 if the following two insns are a barrier and the
11775169689Skan		 target label.  */
11776169689Skan	      this_insn = next_nonnote_insn (this_insn);
11777169689Skan	      if (this_insn && GET_CODE (this_insn) == BARRIER)
11778169689Skan		this_insn = next_nonnote_insn (this_insn);
11779169689Skan
11780169689Skan	      if (this_insn && this_insn == label
11781169689Skan		  && insns_skipped < max_insns_skipped)
11782169689Skan		{
11783169689Skan		  if (jump_clobbers)
1178490075Sobrien		    {
11785169689Skan		      arm_ccfsm_state = 2;
11786169689Skan		      this_insn = next_nonnote_insn (this_insn);
1178790075Sobrien		    }
1178890075Sobrien		  else
11789169689Skan		    arm_ccfsm_state = 1;
11790169689Skan		  succeed = TRUE;
1179190075Sobrien		}
11792169689Skan	      else
11793169689Skan		fail = TRUE;
1179490075Sobrien	      break;
1179590075Sobrien
1179690075Sobrien	    case JUMP_INSN:
1179790075Sobrien      	      /* If this is an unconditional branch to the same label, succeed.
1179890075Sobrien		 If it is to another label, do nothing.  If it is conditional,
1179990075Sobrien		 fail.  */
11800132718Skan	      /* XXX Probably, the tests for SET and the PC are
11801132718Skan		 unnecessary.  */
1180290075Sobrien
1180390075Sobrien	      scanbody = PATTERN (this_insn);
1180490075Sobrien	      if (GET_CODE (scanbody) == SET
1180590075Sobrien		  && GET_CODE (SET_DEST (scanbody)) == PC)
1180690075Sobrien		{
1180790075Sobrien		  if (GET_CODE (SET_SRC (scanbody)) == LABEL_REF
1180890075Sobrien		      && XEXP (SET_SRC (scanbody), 0) == label && !reverse)
1180990075Sobrien		    {
1181090075Sobrien		      arm_ccfsm_state = 2;
1181190075Sobrien		      succeed = TRUE;
1181290075Sobrien		    }
1181390075Sobrien		  else if (GET_CODE (SET_SRC (scanbody)) == IF_THEN_ELSE)
1181490075Sobrien		    fail = TRUE;
1181590075Sobrien		}
11816169689Skan	      /* Fail if a conditional return is undesirable (e.g. on a
1181790075Sobrien		 StrongARM), but still allow this if optimizing for size.  */
1181890075Sobrien	      else if (GET_CODE (scanbody) == RETURN
11819132718Skan		       && !use_return_insn (TRUE, NULL)
1182090075Sobrien		       && !optimize_size)
1182190075Sobrien		fail = TRUE;
1182290075Sobrien	      else if (GET_CODE (scanbody) == RETURN
1182390075Sobrien		       && seeking_return)
1182490075Sobrien	        {
1182590075Sobrien		  arm_ccfsm_state = 2;
1182690075Sobrien		  succeed = TRUE;
1182790075Sobrien	        }
1182890075Sobrien	      else if (GET_CODE (scanbody) == PARALLEL)
1182990075Sobrien	        {
1183090075Sobrien		  switch (get_attr_conds (this_insn))
1183190075Sobrien		    {
1183290075Sobrien		    case CONDS_NOCOND:
1183390075Sobrien		      break;
1183490075Sobrien		    default:
1183590075Sobrien		      fail = TRUE;
1183690075Sobrien		      break;
1183790075Sobrien		    }
1183890075Sobrien		}
1183990075Sobrien	      else
11840169689Skan		fail = TRUE;	/* Unrecognized jump (e.g. epilogue).  */
1184190075Sobrien
1184290075Sobrien	      break;
1184390075Sobrien
1184490075Sobrien	    case INSN:
1184590075Sobrien	      /* Instructions using or affecting the condition codes make it
1184690075Sobrien		 fail.  */
1184790075Sobrien	      scanbody = PATTERN (this_insn);
1184890075Sobrien	      if (!(GET_CODE (scanbody) == SET
1184990075Sobrien		    || GET_CODE (scanbody) == PARALLEL)
1185090075Sobrien		  || get_attr_conds (this_insn) != CONDS_NOCOND)
1185190075Sobrien		fail = TRUE;
11852132718Skan
11853132718Skan	      /* A conditional cirrus instruction must be followed by
11854132718Skan		 a non Cirrus instruction.  However, since we
11855132718Skan		 conditionalize instructions in this function and by
11856132718Skan		 the time we get here we can't add instructions
11857132718Skan		 (nops), because shorten_branches() has already been
11858132718Skan		 called, we will disable conditionalizing Cirrus
11859132718Skan		 instructions to be safe.  */
11860132718Skan	      if (GET_CODE (scanbody) != USE
11861132718Skan		  && GET_CODE (scanbody) != CLOBBER
11862132718Skan		  && get_attr_cirrus (this_insn) != CIRRUS_NOT)
11863132718Skan		fail = TRUE;
1186490075Sobrien	      break;
1186590075Sobrien
1186690075Sobrien	    default:
1186790075Sobrien	      break;
1186890075Sobrien	    }
1186990075Sobrien	}
1187090075Sobrien      if (succeed)
1187190075Sobrien	{
1187290075Sobrien	  if ((!seeking_return) && (arm_ccfsm_state == 1 || reverse))
1187390075Sobrien	    arm_target_label = CODE_LABEL_NUMBER (label);
11874169689Skan	  else
1187590075Sobrien	    {
11876169689Skan	      gcc_assert (seeking_return || arm_ccfsm_state == 2);
11877169689Skan
1187890075Sobrien	      while (this_insn && GET_CODE (PATTERN (this_insn)) == USE)
1187990075Sobrien	        {
1188090075Sobrien		  this_insn = next_nonnote_insn (this_insn);
11881169689Skan		  gcc_assert (!this_insn
11882169689Skan			      || (GET_CODE (this_insn) != BARRIER
11883169689Skan				  && GET_CODE (this_insn) != CODE_LABEL));
1188490075Sobrien	        }
1188590075Sobrien	      if (!this_insn)
1188690075Sobrien	        {
11887132718Skan		  /* Oh, dear! we ran off the end.. give up.  */
1188890075Sobrien		  recog (PATTERN (insn), insn, NULL);
1188990075Sobrien		  arm_ccfsm_state = 0;
1189090075Sobrien		  arm_target_insn = NULL;
1189190075Sobrien		  return;
1189290075Sobrien	        }
1189390075Sobrien	      arm_target_insn = this_insn;
1189490075Sobrien	    }
1189590075Sobrien	  if (jump_clobbers)
1189690075Sobrien	    {
11897169689Skan	      gcc_assert (!reverse);
11898169689Skan	      arm_current_cc =
1189990075Sobrien		  get_arm_condition_code (XEXP (XEXP (XEXP (SET_SRC (body),
1190090075Sobrien							    0), 0), 1));
1190190075Sobrien	      if (GET_CODE (XEXP (XEXP (SET_SRC (body), 0), 0)) == AND)
1190290075Sobrien		arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc);
1190390075Sobrien	      if (GET_CODE (XEXP (SET_SRC (body), 0)) == NE)
1190490075Sobrien		arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc);
1190590075Sobrien	    }
1190690075Sobrien	  else
1190790075Sobrien	    {
1190890075Sobrien	      /* If REVERSE is true, ARM_CURRENT_CC needs to be inverted from
1190990075Sobrien		 what it was.  */
1191090075Sobrien	      if (!reverse)
1191190075Sobrien		arm_current_cc = get_arm_condition_code (XEXP (SET_SRC (body),
1191290075Sobrien							       0));
1191390075Sobrien	    }
1191490075Sobrien
1191590075Sobrien	  if (reverse || then_not_else)
1191690075Sobrien	    arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc);
1191790075Sobrien	}
11918169689Skan
1191990075Sobrien      /* Restore recog_data (getting the attributes of other insns can
1192090075Sobrien	 destroy this array, but final.c assumes that it remains intact
1192190075Sobrien	 across this call; since the insn has been recognized already we
1192290075Sobrien	 call recog direct).  */
1192390075Sobrien      recog (PATTERN (insn), insn, NULL);
1192490075Sobrien    }
1192590075Sobrien}
1192690075Sobrien
1192790075Sobrien/* Returns true if REGNO is a valid register
11928169689Skan   for holding a quantity of type MODE.  */
1192990075Sobrienint
11930132718Skanarm_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
1193190075Sobrien{
1193290075Sobrien  if (GET_MODE_CLASS (mode) == MODE_CC)
11933169689Skan    return (regno == CC_REGNUM
11934169689Skan	    || (TARGET_HARD_FLOAT && TARGET_VFP
11935169689Skan		&& regno == VFPCC_REGNUM));
11936169689Skan
1193790075Sobrien  if (TARGET_THUMB)
1193890075Sobrien    /* For the Thumb we only allow values bigger than SImode in
1193990075Sobrien       registers 0 - 6, so that there is always a second low
1194090075Sobrien       register available to hold the upper part of the value.
1194190075Sobrien       We probably we ought to ensure that the register is the
1194290075Sobrien       start of an even numbered register pair.  */
11943117395Skan    return (ARM_NUM_REGS (mode) < 2) || (regno < LAST_LO_REGNUM);
1194490075Sobrien
11945169689Skan  if (TARGET_HARD_FLOAT && TARGET_MAVERICK
11946169689Skan      && IS_CIRRUS_REGNUM (regno))
11947132718Skan    /* We have outlawed SI values in Cirrus registers because they
11948132718Skan       reside in the lower 32 bits, but SF values reside in the
11949132718Skan       upper 32 bits.  This causes gcc all sorts of grief.  We can't
11950132718Skan       even split the registers into pairs because Cirrus SI values
11951132718Skan       get sign extended to 64bits-- aldyh.  */
11952132718Skan    return (GET_MODE_CLASS (mode) == MODE_FLOAT) || (mode == DImode);
11953132718Skan
11954169689Skan  if (TARGET_HARD_FLOAT && TARGET_VFP
11955169689Skan      && IS_VFP_REGNUM (regno))
11956169689Skan    {
11957169689Skan      if (mode == SFmode || mode == SImode)
11958169689Skan	return TRUE;
11959132718Skan
11960169689Skan      /* DFmode values are only valid in even register pairs.  */
11961169689Skan      if (mode == DFmode)
11962169689Skan	return ((regno - FIRST_VFP_REGNUM) & 1) == 0;
11963169689Skan      return FALSE;
11964169689Skan    }
11965132718Skan
11966169689Skan  if (TARGET_REALLY_IWMMXT)
11967169689Skan    {
11968169689Skan      if (IS_IWMMXT_GR_REGNUM (regno))
11969169689Skan	return mode == SImode;
11970169689Skan
11971169689Skan      if (IS_IWMMXT_REGNUM (regno))
11972169689Skan	return VALID_IWMMXT_REG_MODE (mode);
11973169689Skan    }
11974169689Skan
11975169689Skan  /* We allow any value to be stored in the general registers.
11976169689Skan     Restrict doubleword quantities to even register pairs so that we can
11977169689Skan     use ldrd.  */
1197890075Sobrien  if (regno <= LAST_ARM_REGNUM)
11979169689Skan    return !(TARGET_LDRD && GET_MODE_SIZE (mode) > 4 && (regno & 1) != 0);
1198090075Sobrien
11981169689Skan  if (regno == FRAME_POINTER_REGNUM
1198290075Sobrien      || regno == ARG_POINTER_REGNUM)
1198390075Sobrien    /* We only allow integers in the fake hard registers.  */
1198490075Sobrien    return GET_MODE_CLASS (mode) == MODE_INT;
1198590075Sobrien
11986132718Skan  /* The only registers left are the FPA registers
1198790075Sobrien     which we only allow to hold FP values.  */
11988169689Skan  return (TARGET_HARD_FLOAT && TARGET_FPA
11989169689Skan	  && GET_MODE_CLASS (mode) == MODE_FLOAT
11990169689Skan	  && regno >= FIRST_FPA_REGNUM
11991169689Skan	  && regno <= LAST_FPA_REGNUM);
1199290075Sobrien}
1199390075Sobrien
1199490075Sobrienint
11995132718Skanarm_regno_class (int regno)
1199690075Sobrien{
1199790075Sobrien  if (TARGET_THUMB)
1199890075Sobrien    {
1199990075Sobrien      if (regno == STACK_POINTER_REGNUM)
1200090075Sobrien	return STACK_REG;
1200190075Sobrien      if (regno == CC_REGNUM)
1200290075Sobrien	return CC_REG;
1200390075Sobrien      if (regno < 8)
1200490075Sobrien	return LO_REGS;
1200590075Sobrien      return HI_REGS;
1200690075Sobrien    }
1200790075Sobrien
1200890075Sobrien  if (   regno <= LAST_ARM_REGNUM
1200990075Sobrien      || regno == FRAME_POINTER_REGNUM
1201090075Sobrien      || regno == ARG_POINTER_REGNUM)
1201190075Sobrien    return GENERAL_REGS;
12012169689Skan
12013169689Skan  if (regno == CC_REGNUM || regno == VFPCC_REGNUM)
1201490075Sobrien    return NO_REGS;
1201590075Sobrien
12016132718Skan  if (IS_CIRRUS_REGNUM (regno))
12017132718Skan    return CIRRUS_REGS;
12018132718Skan
12019169689Skan  if (IS_VFP_REGNUM (regno))
12020169689Skan    return VFP_REGS;
12021169689Skan
12022132718Skan  if (IS_IWMMXT_REGNUM (regno))
12023132718Skan    return IWMMXT_REGS;
12024132718Skan
12025132718Skan  if (IS_IWMMXT_GR_REGNUM (regno))
12026132718Skan    return IWMMXT_GR_REGS;
12027132718Skan
12028132718Skan  return FPA_REGS;
1202990075Sobrien}
1203090075Sobrien
1203190075Sobrien/* Handle a special case when computing the offset
1203290075Sobrien   of an argument from the frame pointer.  */
1203390075Sobrienint
12034132718Skanarm_debugger_arg_offset (int value, rtx addr)
1203590075Sobrien{
1203690075Sobrien  rtx insn;
1203790075Sobrien
1203890075Sobrien  /* We are only interested if dbxout_parms() failed to compute the offset.  */
1203990075Sobrien  if (value != 0)
1204090075Sobrien    return 0;
1204190075Sobrien
1204290075Sobrien  /* We can only cope with the case where the address is held in a register.  */
1204390075Sobrien  if (GET_CODE (addr) != REG)
1204490075Sobrien    return 0;
1204590075Sobrien
1204690075Sobrien  /* If we are using the frame pointer to point at the argument, then
1204790075Sobrien     an offset of 0 is correct.  */
1204890075Sobrien  if (REGNO (addr) == (unsigned) HARD_FRAME_POINTER_REGNUM)
1204990075Sobrien    return 0;
12050169689Skan
1205190075Sobrien  /* If we are using the stack pointer to point at the
1205290075Sobrien     argument, then an offset of 0 is correct.  */
1205390075Sobrien  if ((TARGET_THUMB || !frame_pointer_needed)
1205490075Sobrien      && REGNO (addr) == SP_REGNUM)
1205590075Sobrien    return 0;
12056169689Skan
1205790075Sobrien  /* Oh dear.  The argument is pointed to by a register rather
1205890075Sobrien     than being held in a register, or being stored at a known
1205990075Sobrien     offset from the frame pointer.  Since GDB only understands
1206090075Sobrien     those two kinds of argument we must translate the address
1206190075Sobrien     held in the register into an offset from the frame pointer.
1206290075Sobrien     We do this by searching through the insns for the function
1206390075Sobrien     looking to see where this register gets its value.  If the
12064117395Skan     register is initialized from the frame pointer plus an offset
1206590075Sobrien     then we are in luck and we can continue, otherwise we give up.
12066169689Skan
1206790075Sobrien     This code is exercised by producing debugging information
1206890075Sobrien     for a function with arguments like this:
12069169689Skan
1207090075Sobrien           double func (double a, double b, int c, double d) {return d;}
12071169689Skan
1207290075Sobrien     Without this code the stab for parameter 'd' will be set to
1207390075Sobrien     an offset of 0 from the frame pointer, rather than 8.  */
1207490075Sobrien
1207590075Sobrien  /* The if() statement says:
1207690075Sobrien
1207790075Sobrien     If the insn is a normal instruction
1207890075Sobrien     and if the insn is setting the value in a register
1207990075Sobrien     and if the register being set is the register holding the address of the argument
1208090075Sobrien     and if the address is computing by an addition
1208190075Sobrien     that involves adding to a register
1208290075Sobrien     which is the frame pointer
1208390075Sobrien     a constant integer
1208490075Sobrien
12085132718Skan     then...  */
12086169689Skan
1208790075Sobrien  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
1208890075Sobrien    {
12089169689Skan      if (   GET_CODE (insn) == INSN
1209090075Sobrien	  && GET_CODE (PATTERN (insn)) == SET
1209190075Sobrien	  && REGNO    (XEXP (PATTERN (insn), 0)) == REGNO (addr)
1209290075Sobrien	  && GET_CODE (XEXP (PATTERN (insn), 1)) == PLUS
1209390075Sobrien	  && GET_CODE (XEXP (XEXP (PATTERN (insn), 1), 0)) == REG
1209490075Sobrien	  && REGNO    (XEXP (XEXP (PATTERN (insn), 1), 0)) == (unsigned) HARD_FRAME_POINTER_REGNUM
1209590075Sobrien	  && GET_CODE (XEXP (XEXP (PATTERN (insn), 1), 1)) == CONST_INT
1209690075Sobrien	     )
1209790075Sobrien	{
1209890075Sobrien	  value = INTVAL (XEXP (XEXP (PATTERN (insn), 1), 1));
12099169689Skan
1210090075Sobrien	  break;
1210190075Sobrien	}
1210290075Sobrien    }
12103169689Skan
1210490075Sobrien  if (value == 0)
1210590075Sobrien    {
1210690075Sobrien      debug_rtx (addr);
12107169689Skan      warning (0, "unable to compute real location of stacked parameter");
1210890075Sobrien      value = 8; /* XXX magic hack */
1210990075Sobrien    }
1211090075Sobrien
1211190075Sobrien  return value;
1211290075Sobrien}
12113132718Skan
12114132718Skan#define def_mbuiltin(MASK, NAME, TYPE, CODE)				\
12115132718Skan  do									\
12116132718Skan    {									\
12117132718Skan      if ((MASK) & insn_flags)						\
12118169689Skan        lang_hooks.builtin_function ((NAME), (TYPE), (CODE),		\
12119169689Skan				     BUILT_IN_MD, NULL, NULL_TREE);	\
12120132718Skan    }									\
12121132718Skan  while (0)
1212290075Sobrien
12123132718Skanstruct builtin_description
12124132718Skan{
12125132718Skan  const unsigned int       mask;
12126132718Skan  const enum insn_code     icode;
12127132718Skan  const char * const       name;
12128132718Skan  const enum arm_builtins  code;
12129132718Skan  const enum rtx_code      comparison;
12130132718Skan  const unsigned int       flag;
12131132718Skan};
1213290075Sobrien
12133132718Skanstatic const struct builtin_description bdesc_2arg[] =
1213490075Sobrien{
12135132718Skan#define IWMMXT_BUILTIN(code, string, builtin) \
12136132718Skan  { FL_IWMMXT, CODE_FOR_##code, "__builtin_arm_" string, \
12137132718Skan    ARM_BUILTIN_##builtin, 0, 0 },
12138132718Skan
12139132718Skan  IWMMXT_BUILTIN (addv8qi3, "waddb", WADDB)
12140132718Skan  IWMMXT_BUILTIN (addv4hi3, "waddh", WADDH)
12141132718Skan  IWMMXT_BUILTIN (addv2si3, "waddw", WADDW)
12142132718Skan  IWMMXT_BUILTIN (subv8qi3, "wsubb", WSUBB)
12143132718Skan  IWMMXT_BUILTIN (subv4hi3, "wsubh", WSUBH)
12144132718Skan  IWMMXT_BUILTIN (subv2si3, "wsubw", WSUBW)
12145132718Skan  IWMMXT_BUILTIN (ssaddv8qi3, "waddbss", WADDSSB)
12146132718Skan  IWMMXT_BUILTIN (ssaddv4hi3, "waddhss", WADDSSH)
12147132718Skan  IWMMXT_BUILTIN (ssaddv2si3, "waddwss", WADDSSW)
12148132718Skan  IWMMXT_BUILTIN (sssubv8qi3, "wsubbss", WSUBSSB)
12149132718Skan  IWMMXT_BUILTIN (sssubv4hi3, "wsubhss", WSUBSSH)
12150132718Skan  IWMMXT_BUILTIN (sssubv2si3, "wsubwss", WSUBSSW)
12151132718Skan  IWMMXT_BUILTIN (usaddv8qi3, "waddbus", WADDUSB)
12152132718Skan  IWMMXT_BUILTIN (usaddv4hi3, "waddhus", WADDUSH)
12153132718Skan  IWMMXT_BUILTIN (usaddv2si3, "waddwus", WADDUSW)
12154132718Skan  IWMMXT_BUILTIN (ussubv8qi3, "wsubbus", WSUBUSB)
12155132718Skan  IWMMXT_BUILTIN (ussubv4hi3, "wsubhus", WSUBUSH)
12156132718Skan  IWMMXT_BUILTIN (ussubv2si3, "wsubwus", WSUBUSW)
12157132718Skan  IWMMXT_BUILTIN (mulv4hi3, "wmulul", WMULUL)
12158169689Skan  IWMMXT_BUILTIN (smulv4hi3_highpart, "wmulsm", WMULSM)
12159169689Skan  IWMMXT_BUILTIN (umulv4hi3_highpart, "wmulum", WMULUM)
12160132718Skan  IWMMXT_BUILTIN (eqv8qi3, "wcmpeqb", WCMPEQB)
12161132718Skan  IWMMXT_BUILTIN (eqv4hi3, "wcmpeqh", WCMPEQH)
12162132718Skan  IWMMXT_BUILTIN (eqv2si3, "wcmpeqw", WCMPEQW)
12163132718Skan  IWMMXT_BUILTIN (gtuv8qi3, "wcmpgtub", WCMPGTUB)
12164132718Skan  IWMMXT_BUILTIN (gtuv4hi3, "wcmpgtuh", WCMPGTUH)
12165132718Skan  IWMMXT_BUILTIN (gtuv2si3, "wcmpgtuw", WCMPGTUW)
12166132718Skan  IWMMXT_BUILTIN (gtv8qi3, "wcmpgtsb", WCMPGTSB)
12167132718Skan  IWMMXT_BUILTIN (gtv4hi3, "wcmpgtsh", WCMPGTSH)
12168132718Skan  IWMMXT_BUILTIN (gtv2si3, "wcmpgtsw", WCMPGTSW)
12169132718Skan  IWMMXT_BUILTIN (umaxv8qi3, "wmaxub", WMAXUB)
12170132718Skan  IWMMXT_BUILTIN (smaxv8qi3, "wmaxsb", WMAXSB)
12171132718Skan  IWMMXT_BUILTIN (umaxv4hi3, "wmaxuh", WMAXUH)
12172132718Skan  IWMMXT_BUILTIN (smaxv4hi3, "wmaxsh", WMAXSH)
12173132718Skan  IWMMXT_BUILTIN (umaxv2si3, "wmaxuw", WMAXUW)
12174132718Skan  IWMMXT_BUILTIN (smaxv2si3, "wmaxsw", WMAXSW)
12175132718Skan  IWMMXT_BUILTIN (uminv8qi3, "wminub", WMINUB)
12176132718Skan  IWMMXT_BUILTIN (sminv8qi3, "wminsb", WMINSB)
12177132718Skan  IWMMXT_BUILTIN (uminv4hi3, "wminuh", WMINUH)
12178132718Skan  IWMMXT_BUILTIN (sminv4hi3, "wminsh", WMINSH)
12179132718Skan  IWMMXT_BUILTIN (uminv2si3, "wminuw", WMINUW)
12180132718Skan  IWMMXT_BUILTIN (sminv2si3, "wminsw", WMINSW)
12181132718Skan  IWMMXT_BUILTIN (iwmmxt_anddi3, "wand", WAND)
12182132718Skan  IWMMXT_BUILTIN (iwmmxt_nanddi3, "wandn", WANDN)
12183132718Skan  IWMMXT_BUILTIN (iwmmxt_iordi3, "wor", WOR)
12184132718Skan  IWMMXT_BUILTIN (iwmmxt_xordi3, "wxor", WXOR)
12185132718Skan  IWMMXT_BUILTIN (iwmmxt_uavgv8qi3, "wavg2b", WAVG2B)
12186132718Skan  IWMMXT_BUILTIN (iwmmxt_uavgv4hi3, "wavg2h", WAVG2H)
12187132718Skan  IWMMXT_BUILTIN (iwmmxt_uavgrndv8qi3, "wavg2br", WAVG2BR)
12188132718Skan  IWMMXT_BUILTIN (iwmmxt_uavgrndv4hi3, "wavg2hr", WAVG2HR)
12189132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckilb, "wunpckilb", WUNPCKILB)
12190132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckilh, "wunpckilh", WUNPCKILH)
12191132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckilw, "wunpckilw", WUNPCKILW)
12192132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckihb, "wunpckihb", WUNPCKIHB)
12193132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckihh, "wunpckihh", WUNPCKIHH)
12194132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckihw, "wunpckihw", WUNPCKIHW)
12195132718Skan  IWMMXT_BUILTIN (iwmmxt_wmadds, "wmadds", WMADDS)
12196132718Skan  IWMMXT_BUILTIN (iwmmxt_wmaddu, "wmaddu", WMADDU)
12197132718Skan
12198132718Skan#define IWMMXT_BUILTIN2(code, builtin) \
12199132718Skan  { FL_IWMMXT, CODE_FOR_##code, NULL, ARM_BUILTIN_##builtin, 0, 0 },
12200169689Skan
12201132718Skan  IWMMXT_BUILTIN2 (iwmmxt_wpackhss, WPACKHSS)
12202132718Skan  IWMMXT_BUILTIN2 (iwmmxt_wpackwss, WPACKWSS)
12203132718Skan  IWMMXT_BUILTIN2 (iwmmxt_wpackdss, WPACKDSS)
12204132718Skan  IWMMXT_BUILTIN2 (iwmmxt_wpackhus, WPACKHUS)
12205132718Skan  IWMMXT_BUILTIN2 (iwmmxt_wpackwus, WPACKWUS)
12206132718Skan  IWMMXT_BUILTIN2 (iwmmxt_wpackdus, WPACKDUS)
12207132718Skan  IWMMXT_BUILTIN2 (ashlv4hi3_di,    WSLLH)
12208132718Skan  IWMMXT_BUILTIN2 (ashlv4hi3,       WSLLHI)
12209132718Skan  IWMMXT_BUILTIN2 (ashlv2si3_di,    WSLLW)
12210132718Skan  IWMMXT_BUILTIN2 (ashlv2si3,       WSLLWI)
12211132718Skan  IWMMXT_BUILTIN2 (ashldi3_di,      WSLLD)
12212132718Skan  IWMMXT_BUILTIN2 (ashldi3_iwmmxt,  WSLLDI)
12213132718Skan  IWMMXT_BUILTIN2 (lshrv4hi3_di,    WSRLH)
12214132718Skan  IWMMXT_BUILTIN2 (lshrv4hi3,       WSRLHI)
12215132718Skan  IWMMXT_BUILTIN2 (lshrv2si3_di,    WSRLW)
12216132718Skan  IWMMXT_BUILTIN2 (lshrv2si3,       WSRLWI)
12217132718Skan  IWMMXT_BUILTIN2 (lshrdi3_di,      WSRLD)
12218169689Skan  IWMMXT_BUILTIN2 (lshrdi3_iwmmxt,  WSRLDI)
12219132718Skan  IWMMXT_BUILTIN2 (ashrv4hi3_di,    WSRAH)
12220132718Skan  IWMMXT_BUILTIN2 (ashrv4hi3,       WSRAHI)
12221132718Skan  IWMMXT_BUILTIN2 (ashrv2si3_di,    WSRAW)
12222132718Skan  IWMMXT_BUILTIN2 (ashrv2si3,       WSRAWI)
12223132718Skan  IWMMXT_BUILTIN2 (ashrdi3_di,      WSRAD)
12224169689Skan  IWMMXT_BUILTIN2 (ashrdi3_iwmmxt,  WSRADI)
12225132718Skan  IWMMXT_BUILTIN2 (rorv4hi3_di,     WRORH)
12226132718Skan  IWMMXT_BUILTIN2 (rorv4hi3,        WRORHI)
12227132718Skan  IWMMXT_BUILTIN2 (rorv2si3_di,     WRORW)
12228132718Skan  IWMMXT_BUILTIN2 (rorv2si3,        WRORWI)
12229132718Skan  IWMMXT_BUILTIN2 (rordi3_di,       WRORD)
12230132718Skan  IWMMXT_BUILTIN2 (rordi3,          WRORDI)
12231132718Skan  IWMMXT_BUILTIN2 (iwmmxt_wmacuz,   WMACUZ)
12232132718Skan  IWMMXT_BUILTIN2 (iwmmxt_wmacsz,   WMACSZ)
12233132718Skan};
12234132718Skan
12235132718Skanstatic const struct builtin_description bdesc_1arg[] =
12236132718Skan{
12237132718Skan  IWMMXT_BUILTIN (iwmmxt_tmovmskb, "tmovmskb", TMOVMSKB)
12238132718Skan  IWMMXT_BUILTIN (iwmmxt_tmovmskh, "tmovmskh", TMOVMSKH)
12239132718Skan  IWMMXT_BUILTIN (iwmmxt_tmovmskw, "tmovmskw", TMOVMSKW)
12240132718Skan  IWMMXT_BUILTIN (iwmmxt_waccb, "waccb", WACCB)
12241132718Skan  IWMMXT_BUILTIN (iwmmxt_wacch, "wacch", WACCH)
12242132718Skan  IWMMXT_BUILTIN (iwmmxt_waccw, "waccw", WACCW)
12243132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckehub, "wunpckehub", WUNPCKEHUB)
12244132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckehuh, "wunpckehuh", WUNPCKEHUH)
12245132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckehuw, "wunpckehuw", WUNPCKEHUW)
12246132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckehsb, "wunpckehsb", WUNPCKEHSB)
12247132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckehsh, "wunpckehsh", WUNPCKEHSH)
12248132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckehsw, "wunpckehsw", WUNPCKEHSW)
12249132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckelub, "wunpckelub", WUNPCKELUB)
12250132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckeluh, "wunpckeluh", WUNPCKELUH)
12251132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckeluw, "wunpckeluw", WUNPCKELUW)
12252132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckelsb, "wunpckelsb", WUNPCKELSB)
12253132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckelsh, "wunpckelsh", WUNPCKELSH)
12254132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckelsw, "wunpckelsw", WUNPCKELSW)
12255132718Skan};
12256132718Skan
12257132718Skan/* Set up all the iWMMXt builtins.  This is
12258132718Skan   not called if TARGET_IWMMXT is zero.  */
12259132718Skan
12260132718Skanstatic void
12261132718Skanarm_init_iwmmxt_builtins (void)
12262132718Skan{
12263132718Skan  const struct builtin_description * d;
12264132718Skan  size_t i;
1226590075Sobrien  tree endlink = void_list_node;
1226690075Sobrien
12267169689Skan  tree V2SI_type_node = build_vector_type_for_mode (intSI_type_node, V2SImode);
12268169689Skan  tree V4HI_type_node = build_vector_type_for_mode (intHI_type_node, V4HImode);
12269169689Skan  tree V8QI_type_node = build_vector_type_for_mode (intQI_type_node, V8QImode);
12270169689Skan
12271132718Skan  tree int_ftype_int
12272132718Skan    = build_function_type (integer_type_node,
12273132718Skan			   tree_cons (NULL_TREE, integer_type_node, endlink));
12274132718Skan  tree v8qi_ftype_v8qi_v8qi_int
12275132718Skan    = build_function_type (V8QI_type_node,
12276132718Skan			   tree_cons (NULL_TREE, V8QI_type_node,
12277132718Skan				      tree_cons (NULL_TREE, V8QI_type_node,
12278132718Skan						 tree_cons (NULL_TREE,
12279132718Skan							    integer_type_node,
12280132718Skan							    endlink))));
12281132718Skan  tree v4hi_ftype_v4hi_int
12282132718Skan    = build_function_type (V4HI_type_node,
12283132718Skan			   tree_cons (NULL_TREE, V4HI_type_node,
12284132718Skan				      tree_cons (NULL_TREE, integer_type_node,
12285132718Skan						 endlink)));
12286132718Skan  tree v2si_ftype_v2si_int
12287132718Skan    = build_function_type (V2SI_type_node,
12288132718Skan			   tree_cons (NULL_TREE, V2SI_type_node,
12289132718Skan				      tree_cons (NULL_TREE, integer_type_node,
12290132718Skan						 endlink)));
12291132718Skan  tree v2si_ftype_di_di
12292132718Skan    = build_function_type (V2SI_type_node,
12293132718Skan			   tree_cons (NULL_TREE, long_long_integer_type_node,
12294132718Skan				      tree_cons (NULL_TREE, long_long_integer_type_node,
12295132718Skan						 endlink)));
12296132718Skan  tree di_ftype_di_int
12297132718Skan    = build_function_type (long_long_integer_type_node,
12298132718Skan			   tree_cons (NULL_TREE, long_long_integer_type_node,
12299132718Skan				      tree_cons (NULL_TREE, integer_type_node,
12300132718Skan						 endlink)));
12301132718Skan  tree di_ftype_di_int_int
12302132718Skan    = build_function_type (long_long_integer_type_node,
12303132718Skan			   tree_cons (NULL_TREE, long_long_integer_type_node,
12304132718Skan				      tree_cons (NULL_TREE, integer_type_node,
12305132718Skan						 tree_cons (NULL_TREE,
12306132718Skan							    integer_type_node,
12307132718Skan							    endlink))));
12308132718Skan  tree int_ftype_v8qi
12309132718Skan    = build_function_type (integer_type_node,
12310132718Skan			   tree_cons (NULL_TREE, V8QI_type_node,
12311132718Skan				      endlink));
12312132718Skan  tree int_ftype_v4hi
12313132718Skan    = build_function_type (integer_type_node,
12314132718Skan			   tree_cons (NULL_TREE, V4HI_type_node,
12315132718Skan				      endlink));
12316132718Skan  tree int_ftype_v2si
12317132718Skan    = build_function_type (integer_type_node,
12318132718Skan			   tree_cons (NULL_TREE, V2SI_type_node,
12319132718Skan				      endlink));
12320132718Skan  tree int_ftype_v8qi_int
12321132718Skan    = build_function_type (integer_type_node,
12322132718Skan			   tree_cons (NULL_TREE, V8QI_type_node,
12323132718Skan				      tree_cons (NULL_TREE, integer_type_node,
12324132718Skan						 endlink)));
12325132718Skan  tree int_ftype_v4hi_int
12326132718Skan    = build_function_type (integer_type_node,
12327132718Skan			   tree_cons (NULL_TREE, V4HI_type_node,
12328132718Skan				      tree_cons (NULL_TREE, integer_type_node,
12329132718Skan						 endlink)));
12330132718Skan  tree int_ftype_v2si_int
12331132718Skan    = build_function_type (integer_type_node,
12332132718Skan			   tree_cons (NULL_TREE, V2SI_type_node,
12333132718Skan				      tree_cons (NULL_TREE, integer_type_node,
12334132718Skan						 endlink)));
12335132718Skan  tree v8qi_ftype_v8qi_int_int
12336132718Skan    = build_function_type (V8QI_type_node,
12337132718Skan			   tree_cons (NULL_TREE, V8QI_type_node,
12338132718Skan				      tree_cons (NULL_TREE, integer_type_node,
12339132718Skan						 tree_cons (NULL_TREE,
12340132718Skan							    integer_type_node,
12341132718Skan							    endlink))));
12342132718Skan  tree v4hi_ftype_v4hi_int_int
12343132718Skan    = build_function_type (V4HI_type_node,
12344132718Skan			   tree_cons (NULL_TREE, V4HI_type_node,
12345132718Skan				      tree_cons (NULL_TREE, integer_type_node,
12346132718Skan						 tree_cons (NULL_TREE,
12347132718Skan							    integer_type_node,
12348132718Skan							    endlink))));
12349132718Skan  tree v2si_ftype_v2si_int_int
12350132718Skan    = build_function_type (V2SI_type_node,
12351132718Skan			   tree_cons (NULL_TREE, V2SI_type_node,
12352132718Skan				      tree_cons (NULL_TREE, integer_type_node,
12353132718Skan						 tree_cons (NULL_TREE,
12354132718Skan							    integer_type_node,
12355132718Skan							    endlink))));
12356132718Skan  /* Miscellaneous.  */
12357132718Skan  tree v8qi_ftype_v4hi_v4hi
12358132718Skan    = build_function_type (V8QI_type_node,
12359132718Skan			   tree_cons (NULL_TREE, V4HI_type_node,
12360132718Skan				      tree_cons (NULL_TREE, V4HI_type_node,
12361132718Skan						 endlink)));
12362132718Skan  tree v4hi_ftype_v2si_v2si
12363132718Skan    = build_function_type (V4HI_type_node,
12364132718Skan			   tree_cons (NULL_TREE, V2SI_type_node,
12365132718Skan				      tree_cons (NULL_TREE, V2SI_type_node,
12366132718Skan						 endlink)));
12367132718Skan  tree v2si_ftype_v4hi_v4hi
12368132718Skan    = build_function_type (V2SI_type_node,
12369132718Skan			   tree_cons (NULL_TREE, V4HI_type_node,
12370132718Skan				      tree_cons (NULL_TREE, V4HI_type_node,
12371132718Skan						 endlink)));
12372132718Skan  tree v2si_ftype_v8qi_v8qi
12373132718Skan    = build_function_type (V2SI_type_node,
12374132718Skan			   tree_cons (NULL_TREE, V8QI_type_node,
12375132718Skan				      tree_cons (NULL_TREE, V8QI_type_node,
12376132718Skan						 endlink)));
12377132718Skan  tree v4hi_ftype_v4hi_di
12378132718Skan    = build_function_type (V4HI_type_node,
12379132718Skan			   tree_cons (NULL_TREE, V4HI_type_node,
12380132718Skan				      tree_cons (NULL_TREE,
12381132718Skan						 long_long_integer_type_node,
12382132718Skan						 endlink)));
12383132718Skan  tree v2si_ftype_v2si_di
12384132718Skan    = build_function_type (V2SI_type_node,
12385132718Skan			   tree_cons (NULL_TREE, V2SI_type_node,
12386132718Skan				      tree_cons (NULL_TREE,
12387132718Skan						 long_long_integer_type_node,
12388132718Skan						 endlink)));
12389132718Skan  tree void_ftype_int_int
12390132718Skan    = build_function_type (void_type_node,
12391132718Skan			   tree_cons (NULL_TREE, integer_type_node,
12392132718Skan				      tree_cons (NULL_TREE, integer_type_node,
12393132718Skan						 endlink)));
12394132718Skan  tree di_ftype_void
12395132718Skan    = build_function_type (long_long_unsigned_type_node, endlink);
12396132718Skan  tree di_ftype_v8qi
12397132718Skan    = build_function_type (long_long_integer_type_node,
12398132718Skan			   tree_cons (NULL_TREE, V8QI_type_node,
12399132718Skan				      endlink));
12400132718Skan  tree di_ftype_v4hi
12401132718Skan    = build_function_type (long_long_integer_type_node,
12402132718Skan			   tree_cons (NULL_TREE, V4HI_type_node,
12403132718Skan				      endlink));
12404132718Skan  tree di_ftype_v2si
12405132718Skan    = build_function_type (long_long_integer_type_node,
12406132718Skan			   tree_cons (NULL_TREE, V2SI_type_node,
12407132718Skan				      endlink));
12408132718Skan  tree v2si_ftype_v4hi
12409132718Skan    = build_function_type (V2SI_type_node,
12410132718Skan			   tree_cons (NULL_TREE, V4HI_type_node,
12411132718Skan				      endlink));
12412132718Skan  tree v4hi_ftype_v8qi
12413132718Skan    = build_function_type (V4HI_type_node,
12414132718Skan			   tree_cons (NULL_TREE, V8QI_type_node,
12415132718Skan				      endlink));
1241690075Sobrien
12417132718Skan  tree di_ftype_di_v4hi_v4hi
12418132718Skan    = build_function_type (long_long_unsigned_type_node,
12419132718Skan			   tree_cons (NULL_TREE,
12420132718Skan				      long_long_unsigned_type_node,
12421132718Skan				      tree_cons (NULL_TREE, V4HI_type_node,
12422132718Skan						 tree_cons (NULL_TREE,
12423132718Skan							    V4HI_type_node,
12424132718Skan							    endlink))));
1242590075Sobrien
12426132718Skan  tree di_ftype_v4hi_v4hi
12427132718Skan    = build_function_type (long_long_unsigned_type_node,
12428132718Skan			   tree_cons (NULL_TREE, V4HI_type_node,
12429132718Skan				      tree_cons (NULL_TREE, V4HI_type_node,
12430132718Skan						 endlink)));
1243190075Sobrien
12432132718Skan  /* Normal vector binops.  */
12433132718Skan  tree v8qi_ftype_v8qi_v8qi
12434132718Skan    = build_function_type (V8QI_type_node,
12435132718Skan			   tree_cons (NULL_TREE, V8QI_type_node,
12436132718Skan				      tree_cons (NULL_TREE, V8QI_type_node,
12437132718Skan						 endlink)));
12438132718Skan  tree v4hi_ftype_v4hi_v4hi
12439132718Skan    = build_function_type (V4HI_type_node,
12440132718Skan			   tree_cons (NULL_TREE, V4HI_type_node,
12441132718Skan				      tree_cons (NULL_TREE, V4HI_type_node,
12442132718Skan						 endlink)));
12443132718Skan  tree v2si_ftype_v2si_v2si
12444132718Skan    = build_function_type (V2SI_type_node,
12445132718Skan			   tree_cons (NULL_TREE, V2SI_type_node,
12446132718Skan				      tree_cons (NULL_TREE, V2SI_type_node,
12447132718Skan						 endlink)));
12448132718Skan  tree di_ftype_di_di
12449132718Skan    = build_function_type (long_long_unsigned_type_node,
12450132718Skan			   tree_cons (NULL_TREE, long_long_unsigned_type_node,
12451132718Skan				      tree_cons (NULL_TREE,
12452132718Skan						 long_long_unsigned_type_node,
12453132718Skan						 endlink)));
12454132718Skan
12455132718Skan  /* Add all builtins that are more or less simple operations on two
12456132718Skan     operands.  */
12457132718Skan  for (i = 0, d = bdesc_2arg; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
12458132718Skan    {
12459132718Skan      /* Use one of the operands; the target can have a different mode for
12460132718Skan	 mask-generating compares.  */
12461132718Skan      enum machine_mode mode;
12462132718Skan      tree type;
12463132718Skan
12464132718Skan      if (d->name == 0)
12465132718Skan	continue;
12466132718Skan
12467132718Skan      mode = insn_data[d->icode].operand[1].mode;
12468132718Skan
12469132718Skan      switch (mode)
12470132718Skan	{
12471132718Skan	case V8QImode:
12472132718Skan	  type = v8qi_ftype_v8qi_v8qi;
12473132718Skan	  break;
12474132718Skan	case V4HImode:
12475132718Skan	  type = v4hi_ftype_v4hi_v4hi;
12476132718Skan	  break;
12477132718Skan	case V2SImode:
12478132718Skan	  type = v2si_ftype_v2si_v2si;
12479132718Skan	  break;
12480132718Skan	case DImode:
12481132718Skan	  type = di_ftype_di_di;
12482132718Skan	  break;
12483132718Skan
12484132718Skan	default:
12485169689Skan	  gcc_unreachable ();
12486132718Skan	}
12487132718Skan
12488132718Skan      def_mbuiltin (d->mask, d->name, type, d->code);
12489132718Skan    }
12490132718Skan
12491132718Skan  /* Add the remaining MMX insns with somewhat more complicated types.  */
12492132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wzero", di_ftype_void, ARM_BUILTIN_WZERO);
12493132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_setwcx", void_ftype_int_int, ARM_BUILTIN_SETWCX);
12494132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_getwcx", int_ftype_int, ARM_BUILTIN_GETWCX);
12495132718Skan
12496132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsllh", v4hi_ftype_v4hi_di, ARM_BUILTIN_WSLLH);
12497132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsllw", v2si_ftype_v2si_di, ARM_BUILTIN_WSLLW);
12498132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wslld", di_ftype_di_di, ARM_BUILTIN_WSLLD);
12499132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsllhi", v4hi_ftype_v4hi_int, ARM_BUILTIN_WSLLHI);
12500132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsllwi", v2si_ftype_v2si_int, ARM_BUILTIN_WSLLWI);
12501132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wslldi", di_ftype_di_int, ARM_BUILTIN_WSLLDI);
12502132718Skan
12503132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrlh", v4hi_ftype_v4hi_di, ARM_BUILTIN_WSRLH);
12504132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrlw", v2si_ftype_v2si_di, ARM_BUILTIN_WSRLW);
12505132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrld", di_ftype_di_di, ARM_BUILTIN_WSRLD);
12506132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrlhi", v4hi_ftype_v4hi_int, ARM_BUILTIN_WSRLHI);
12507132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrlwi", v2si_ftype_v2si_int, ARM_BUILTIN_WSRLWI);
12508132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrldi", di_ftype_di_int, ARM_BUILTIN_WSRLDI);
12509132718Skan
12510132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrah", v4hi_ftype_v4hi_di, ARM_BUILTIN_WSRAH);
12511132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsraw", v2si_ftype_v2si_di, ARM_BUILTIN_WSRAW);
12512132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrad", di_ftype_di_di, ARM_BUILTIN_WSRAD);
12513132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrahi", v4hi_ftype_v4hi_int, ARM_BUILTIN_WSRAHI);
12514132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrawi", v2si_ftype_v2si_int, ARM_BUILTIN_WSRAWI);
12515132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsradi", di_ftype_di_int, ARM_BUILTIN_WSRADI);
12516132718Skan
12517132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wrorh", v4hi_ftype_v4hi_di, ARM_BUILTIN_WRORH);
12518132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wrorw", v2si_ftype_v2si_di, ARM_BUILTIN_WRORW);
12519132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wrord", di_ftype_di_di, ARM_BUILTIN_WRORD);
12520132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wrorhi", v4hi_ftype_v4hi_int, ARM_BUILTIN_WRORHI);
12521132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wrorwi", v2si_ftype_v2si_int, ARM_BUILTIN_WRORWI);
12522132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wrordi", di_ftype_di_int, ARM_BUILTIN_WRORDI);
12523132718Skan
12524132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wshufh", v4hi_ftype_v4hi_int, ARM_BUILTIN_WSHUFH);
12525132718Skan
12526132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsadb", v2si_ftype_v8qi_v8qi, ARM_BUILTIN_WSADB);
12527132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsadh", v2si_ftype_v4hi_v4hi, ARM_BUILTIN_WSADH);
12528132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsadbz", v2si_ftype_v8qi_v8qi, ARM_BUILTIN_WSADBZ);
12529132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsadhz", v2si_ftype_v4hi_v4hi, ARM_BUILTIN_WSADHZ);
12530132718Skan
12531132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_textrmsb", int_ftype_v8qi_int, ARM_BUILTIN_TEXTRMSB);
12532132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_textrmsh", int_ftype_v4hi_int, ARM_BUILTIN_TEXTRMSH);
12533132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_textrmsw", int_ftype_v2si_int, ARM_BUILTIN_TEXTRMSW);
12534132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_textrmub", int_ftype_v8qi_int, ARM_BUILTIN_TEXTRMUB);
12535132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_textrmuh", int_ftype_v4hi_int, ARM_BUILTIN_TEXTRMUH);
12536132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_textrmuw", int_ftype_v2si_int, ARM_BUILTIN_TEXTRMUW);
12537132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tinsrb", v8qi_ftype_v8qi_int_int, ARM_BUILTIN_TINSRB);
12538132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tinsrh", v4hi_ftype_v4hi_int_int, ARM_BUILTIN_TINSRH);
12539132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tinsrw", v2si_ftype_v2si_int_int, ARM_BUILTIN_TINSRW);
12540132718Skan
12541132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_waccb", di_ftype_v8qi, ARM_BUILTIN_WACCB);
12542132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wacch", di_ftype_v4hi, ARM_BUILTIN_WACCH);
12543132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_waccw", di_ftype_v2si, ARM_BUILTIN_WACCW);
12544132718Skan
12545132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmovmskb", int_ftype_v8qi, ARM_BUILTIN_TMOVMSKB);
12546132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmovmskh", int_ftype_v4hi, ARM_BUILTIN_TMOVMSKH);
12547132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmovmskw", int_ftype_v2si, ARM_BUILTIN_TMOVMSKW);
12548132718Skan
12549132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wpackhss", v8qi_ftype_v4hi_v4hi, ARM_BUILTIN_WPACKHSS);
12550132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wpackhus", v8qi_ftype_v4hi_v4hi, ARM_BUILTIN_WPACKHUS);
12551132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wpackwus", v4hi_ftype_v2si_v2si, ARM_BUILTIN_WPACKWUS);
12552132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wpackwss", v4hi_ftype_v2si_v2si, ARM_BUILTIN_WPACKWSS);
12553132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wpackdus", v2si_ftype_di_di, ARM_BUILTIN_WPACKDUS);
12554132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wpackdss", v2si_ftype_di_di, ARM_BUILTIN_WPACKDSS);
12555132718Skan
12556132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckehub", v4hi_ftype_v8qi, ARM_BUILTIN_WUNPCKEHUB);
12557132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckehuh", v2si_ftype_v4hi, ARM_BUILTIN_WUNPCKEHUH);
12558132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckehuw", di_ftype_v2si, ARM_BUILTIN_WUNPCKEHUW);
12559132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckehsb", v4hi_ftype_v8qi, ARM_BUILTIN_WUNPCKEHSB);
12560132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckehsh", v2si_ftype_v4hi, ARM_BUILTIN_WUNPCKEHSH);
12561132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckehsw", di_ftype_v2si, ARM_BUILTIN_WUNPCKEHSW);
12562132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckelub", v4hi_ftype_v8qi, ARM_BUILTIN_WUNPCKELUB);
12563132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckeluh", v2si_ftype_v4hi, ARM_BUILTIN_WUNPCKELUH);
12564132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckeluw", di_ftype_v2si, ARM_BUILTIN_WUNPCKELUW);
12565132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckelsb", v4hi_ftype_v8qi, ARM_BUILTIN_WUNPCKELSB);
12566132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckelsh", v2si_ftype_v4hi, ARM_BUILTIN_WUNPCKELSH);
12567132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckelsw", di_ftype_v2si, ARM_BUILTIN_WUNPCKELSW);
12568132718Skan
12569132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wmacs", di_ftype_di_v4hi_v4hi, ARM_BUILTIN_WMACS);
12570132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wmacsz", di_ftype_v4hi_v4hi, ARM_BUILTIN_WMACSZ);
12571132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wmacu", di_ftype_di_v4hi_v4hi, ARM_BUILTIN_WMACU);
12572132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wmacuz", di_ftype_v4hi_v4hi, ARM_BUILTIN_WMACUZ);
12573132718Skan
12574132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_walign", v8qi_ftype_v8qi_v8qi_int, ARM_BUILTIN_WALIGN);
12575132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmia", di_ftype_di_int_int, ARM_BUILTIN_TMIA);
12576132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmiaph", di_ftype_di_int_int, ARM_BUILTIN_TMIAPH);
12577132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmiabb", di_ftype_di_int_int, ARM_BUILTIN_TMIABB);
12578132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmiabt", di_ftype_di_int_int, ARM_BUILTIN_TMIABT);
12579132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmiatb", di_ftype_di_int_int, ARM_BUILTIN_TMIATB);
12580132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmiatt", di_ftype_di_int_int, ARM_BUILTIN_TMIATT);
1258190075Sobrien}
1258290075Sobrien
12583132718Skanstatic void
12584169689Skanarm_init_tls_builtins (void)
12585169689Skan{
12586169689Skan  tree ftype;
12587169689Skan  tree nothrow = tree_cons (get_identifier ("nothrow"), NULL, NULL);
12588169689Skan  tree const_nothrow = tree_cons (get_identifier ("const"), NULL, nothrow);
12589169689Skan
12590169689Skan  ftype = build_function_type (ptr_type_node, void_list_node);
12591169689Skan  lang_hooks.builtin_function ("__builtin_thread_pointer", ftype,
12592169689Skan			       ARM_BUILTIN_THREAD_POINTER, BUILT_IN_MD,
12593169689Skan			       NULL, const_nothrow);
12594169689Skan}
12595169689Skan
12596169689Skanstatic void
12597132718Skanarm_init_builtins (void)
12598132718Skan{
12599169689Skan  arm_init_tls_builtins ();
12600169689Skan
12601132718Skan  if (TARGET_REALLY_IWMMXT)
12602132718Skan    arm_init_iwmmxt_builtins ();
12603132718Skan}
12604132718Skan
12605132718Skan/* Errors in the source file can cause expand_expr to return const0_rtx
12606132718Skan   where we expect a vector.  To avoid crashing, use one of the vector
12607132718Skan   clear instructions.  */
12608132718Skan
12609132718Skanstatic rtx
12610132718Skansafe_vector_operand (rtx x, enum machine_mode mode)
12611132718Skan{
12612132718Skan  if (x != const0_rtx)
12613132718Skan    return x;
12614132718Skan  x = gen_reg_rtx (mode);
12615132718Skan
12616132718Skan  emit_insn (gen_iwmmxt_clrdi (mode == DImode ? x
12617132718Skan			       : gen_rtx_SUBREG (DImode, x, 0)));
12618132718Skan  return x;
12619132718Skan}
12620132718Skan
12621132718Skan/* Subroutine of arm_expand_builtin to take care of binop insns.  */
12622132718Skan
12623132718Skanstatic rtx
12624132718Skanarm_expand_binop_builtin (enum insn_code icode,
12625132718Skan			  tree arglist, rtx target)
12626132718Skan{
12627132718Skan  rtx pat;
12628132718Skan  tree arg0 = TREE_VALUE (arglist);
12629132718Skan  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
12630169689Skan  rtx op0 = expand_normal (arg0);
12631169689Skan  rtx op1 = expand_normal (arg1);
12632132718Skan  enum machine_mode tmode = insn_data[icode].operand[0].mode;
12633132718Skan  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
12634132718Skan  enum machine_mode mode1 = insn_data[icode].operand[2].mode;
12635132718Skan
12636132718Skan  if (VECTOR_MODE_P (mode0))
12637132718Skan    op0 = safe_vector_operand (op0, mode0);
12638132718Skan  if (VECTOR_MODE_P (mode1))
12639132718Skan    op1 = safe_vector_operand (op1, mode1);
12640132718Skan
12641132718Skan  if (! target
12642132718Skan      || GET_MODE (target) != tmode
12643132718Skan      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
12644132718Skan    target = gen_reg_rtx (tmode);
12645132718Skan
12646169689Skan  gcc_assert (GET_MODE (op0) == mode0 && GET_MODE (op1) == mode1);
12647132718Skan
12648132718Skan  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
12649132718Skan    op0 = copy_to_mode_reg (mode0, op0);
12650132718Skan  if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
12651132718Skan    op1 = copy_to_mode_reg (mode1, op1);
12652132718Skan
12653132718Skan  pat = GEN_FCN (icode) (target, op0, op1);
12654132718Skan  if (! pat)
12655132718Skan    return 0;
12656132718Skan  emit_insn (pat);
12657132718Skan  return target;
12658132718Skan}
12659132718Skan
12660132718Skan/* Subroutine of arm_expand_builtin to take care of unop insns.  */
12661132718Skan
12662132718Skanstatic rtx
12663132718Skanarm_expand_unop_builtin (enum insn_code icode,
12664132718Skan			 tree arglist, rtx target, int do_load)
12665132718Skan{
12666132718Skan  rtx pat;
12667132718Skan  tree arg0 = TREE_VALUE (arglist);
12668169689Skan  rtx op0 = expand_normal (arg0);
12669132718Skan  enum machine_mode tmode = insn_data[icode].operand[0].mode;
12670132718Skan  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
12671132718Skan
12672132718Skan  if (! target
12673132718Skan      || GET_MODE (target) != tmode
12674132718Skan      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
12675132718Skan    target = gen_reg_rtx (tmode);
12676132718Skan  if (do_load)
12677132718Skan    op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
12678132718Skan  else
12679132718Skan    {
12680132718Skan      if (VECTOR_MODE_P (mode0))
12681132718Skan	op0 = safe_vector_operand (op0, mode0);
12682132718Skan
12683132718Skan      if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
12684132718Skan	op0 = copy_to_mode_reg (mode0, op0);
12685132718Skan    }
12686132718Skan
12687132718Skan  pat = GEN_FCN (icode) (target, op0);
12688132718Skan  if (! pat)
12689132718Skan    return 0;
12690132718Skan  emit_insn (pat);
12691132718Skan  return target;
12692132718Skan}
12693132718Skan
1269490075Sobrien/* Expand an expression EXP that calls a built-in function,
1269590075Sobrien   with result going to TARGET if that's convenient
1269690075Sobrien   (and in mode MODE if that's convenient).
1269790075Sobrien   SUBTARGET may be used as the target for computing one of EXP's operands.
1269890075Sobrien   IGNORE is nonzero if the value is to be ignored.  */
1269990075Sobrien
12700132718Skanstatic rtx
12701132718Skanarm_expand_builtin (tree exp,
12702132718Skan		    rtx target,
12703132718Skan		    rtx subtarget ATTRIBUTE_UNUSED,
12704132718Skan		    enum machine_mode mode ATTRIBUTE_UNUSED,
12705132718Skan		    int ignore ATTRIBUTE_UNUSED)
1270690075Sobrien{
12707132718Skan  const struct builtin_description * d;
12708132718Skan  enum insn_code    icode;
12709132718Skan  tree              fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
12710132718Skan  tree              arglist = TREE_OPERAND (exp, 1);
12711132718Skan  tree              arg0;
12712132718Skan  tree              arg1;
12713132718Skan  tree              arg2;
12714132718Skan  rtx               op0;
12715132718Skan  rtx               op1;
12716132718Skan  rtx               op2;
12717132718Skan  rtx               pat;
12718132718Skan  int               fcode = DECL_FUNCTION_CODE (fndecl);
12719132718Skan  size_t            i;
12720132718Skan  enum machine_mode tmode;
12721132718Skan  enum machine_mode mode0;
12722132718Skan  enum machine_mode mode1;
12723132718Skan  enum machine_mode mode2;
1272490075Sobrien
1272590075Sobrien  switch (fcode)
1272690075Sobrien    {
12727132718Skan    case ARM_BUILTIN_TEXTRMSB:
12728132718Skan    case ARM_BUILTIN_TEXTRMUB:
12729132718Skan    case ARM_BUILTIN_TEXTRMSH:
12730132718Skan    case ARM_BUILTIN_TEXTRMUH:
12731132718Skan    case ARM_BUILTIN_TEXTRMSW:
12732132718Skan    case ARM_BUILTIN_TEXTRMUW:
12733132718Skan      icode = (fcode == ARM_BUILTIN_TEXTRMSB ? CODE_FOR_iwmmxt_textrmsb
12734132718Skan	       : fcode == ARM_BUILTIN_TEXTRMUB ? CODE_FOR_iwmmxt_textrmub
12735132718Skan	       : fcode == ARM_BUILTIN_TEXTRMSH ? CODE_FOR_iwmmxt_textrmsh
12736132718Skan	       : fcode == ARM_BUILTIN_TEXTRMUH ? CODE_FOR_iwmmxt_textrmuh
12737132718Skan	       : CODE_FOR_iwmmxt_textrmw);
12738132718Skan
1273990075Sobrien      arg0 = TREE_VALUE (arglist);
12740132718Skan      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
12741169689Skan      op0 = expand_normal (arg0);
12742169689Skan      op1 = expand_normal (arg1);
1274390075Sobrien      tmode = insn_data[icode].operand[0].mode;
1274490075Sobrien      mode0 = insn_data[icode].operand[1].mode;
12745132718Skan      mode1 = insn_data[icode].operand[2].mode;
1274690075Sobrien
1274790075Sobrien      if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
1274890075Sobrien	op0 = copy_to_mode_reg (mode0, op0);
12749132718Skan      if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
12750132718Skan	{
12751132718Skan	  /* @@@ better error message */
12752132718Skan	  error ("selector must be an immediate");
12753132718Skan	  return gen_reg_rtx (tmode);
12754132718Skan	}
1275590075Sobrien      if (target == 0
1275690075Sobrien	  || GET_MODE (target) != tmode
1275790075Sobrien	  || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
1275890075Sobrien	target = gen_reg_rtx (tmode);
12759132718Skan      pat = GEN_FCN (icode) (target, op0, op1);
1276090075Sobrien      if (! pat)
1276190075Sobrien	return 0;
1276290075Sobrien      emit_insn (pat);
1276390075Sobrien      return target;
12764132718Skan
12765132718Skan    case ARM_BUILTIN_TINSRB:
12766132718Skan    case ARM_BUILTIN_TINSRH:
12767132718Skan    case ARM_BUILTIN_TINSRW:
12768132718Skan      icode = (fcode == ARM_BUILTIN_TINSRB ? CODE_FOR_iwmmxt_tinsrb
12769132718Skan	       : fcode == ARM_BUILTIN_TINSRH ? CODE_FOR_iwmmxt_tinsrh
12770132718Skan	       : CODE_FOR_iwmmxt_tinsrw);
12771132718Skan      arg0 = TREE_VALUE (arglist);
12772132718Skan      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
12773132718Skan      arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
12774169689Skan      op0 = expand_normal (arg0);
12775169689Skan      op1 = expand_normal (arg1);
12776169689Skan      op2 = expand_normal (arg2);
12777132718Skan      tmode = insn_data[icode].operand[0].mode;
12778132718Skan      mode0 = insn_data[icode].operand[1].mode;
12779132718Skan      mode1 = insn_data[icode].operand[2].mode;
12780132718Skan      mode2 = insn_data[icode].operand[3].mode;
12781132718Skan
12782132718Skan      if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
12783132718Skan	op0 = copy_to_mode_reg (mode0, op0);
12784132718Skan      if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
12785132718Skan	op1 = copy_to_mode_reg (mode1, op1);
12786132718Skan      if (! (*insn_data[icode].operand[3].predicate) (op2, mode2))
12787132718Skan	{
12788132718Skan	  /* @@@ better error message */
12789132718Skan	  error ("selector must be an immediate");
12790132718Skan	  return const0_rtx;
12791132718Skan	}
12792132718Skan      if (target == 0
12793132718Skan	  || GET_MODE (target) != tmode
12794132718Skan	  || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
12795132718Skan	target = gen_reg_rtx (tmode);
12796132718Skan      pat = GEN_FCN (icode) (target, op0, op1, op2);
12797132718Skan      if (! pat)
12798132718Skan	return 0;
12799132718Skan      emit_insn (pat);
12800132718Skan      return target;
12801132718Skan
12802132718Skan    case ARM_BUILTIN_SETWCX:
12803132718Skan      arg0 = TREE_VALUE (arglist);
12804132718Skan      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
12805169689Skan      op0 = force_reg (SImode, expand_normal (arg0));
12806169689Skan      op1 = expand_normal (arg1);
12807169689Skan      emit_insn (gen_iwmmxt_tmcr (op1, op0));
12808132718Skan      return 0;
12809132718Skan
12810132718Skan    case ARM_BUILTIN_GETWCX:
12811132718Skan      arg0 = TREE_VALUE (arglist);
12812169689Skan      op0 = expand_normal (arg0);
12813132718Skan      target = gen_reg_rtx (SImode);
12814132718Skan      emit_insn (gen_iwmmxt_tmrc (target, op0));
12815132718Skan      return target;
12816132718Skan
12817132718Skan    case ARM_BUILTIN_WSHUFH:
12818132718Skan      icode = CODE_FOR_iwmmxt_wshufh;
12819132718Skan      arg0 = TREE_VALUE (arglist);
12820132718Skan      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
12821169689Skan      op0 = expand_normal (arg0);
12822169689Skan      op1 = expand_normal (arg1);
12823132718Skan      tmode = insn_data[icode].operand[0].mode;
12824132718Skan      mode1 = insn_data[icode].operand[1].mode;
12825132718Skan      mode2 = insn_data[icode].operand[2].mode;
12826132718Skan
12827132718Skan      if (! (*insn_data[icode].operand[1].predicate) (op0, mode1))
12828132718Skan	op0 = copy_to_mode_reg (mode1, op0);
12829132718Skan      if (! (*insn_data[icode].operand[2].predicate) (op1, mode2))
12830132718Skan	{
12831132718Skan	  /* @@@ better error message */
12832132718Skan	  error ("mask must be an immediate");
12833132718Skan	  return const0_rtx;
12834132718Skan	}
12835132718Skan      if (target == 0
12836132718Skan	  || GET_MODE (target) != tmode
12837132718Skan	  || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
12838132718Skan	target = gen_reg_rtx (tmode);
12839132718Skan      pat = GEN_FCN (icode) (target, op0, op1);
12840132718Skan      if (! pat)
12841132718Skan	return 0;
12842132718Skan      emit_insn (pat);
12843132718Skan      return target;
12844132718Skan
12845132718Skan    case ARM_BUILTIN_WSADB:
12846132718Skan      return arm_expand_binop_builtin (CODE_FOR_iwmmxt_wsadb, arglist, target);
12847132718Skan    case ARM_BUILTIN_WSADH:
12848132718Skan      return arm_expand_binop_builtin (CODE_FOR_iwmmxt_wsadh, arglist, target);
12849132718Skan    case ARM_BUILTIN_WSADBZ:
12850132718Skan      return arm_expand_binop_builtin (CODE_FOR_iwmmxt_wsadbz, arglist, target);
12851132718Skan    case ARM_BUILTIN_WSADHZ:
12852132718Skan      return arm_expand_binop_builtin (CODE_FOR_iwmmxt_wsadhz, arglist, target);
12853132718Skan
12854132718Skan      /* Several three-argument builtins.  */
12855132718Skan    case ARM_BUILTIN_WMACS:
12856132718Skan    case ARM_BUILTIN_WMACU:
12857132718Skan    case ARM_BUILTIN_WALIGN:
12858132718Skan    case ARM_BUILTIN_TMIA:
12859132718Skan    case ARM_BUILTIN_TMIAPH:
12860132718Skan    case ARM_BUILTIN_TMIATT:
12861132718Skan    case ARM_BUILTIN_TMIATB:
12862132718Skan    case ARM_BUILTIN_TMIABT:
12863132718Skan    case ARM_BUILTIN_TMIABB:
12864132718Skan      icode = (fcode == ARM_BUILTIN_WMACS ? CODE_FOR_iwmmxt_wmacs
12865132718Skan	       : fcode == ARM_BUILTIN_WMACU ? CODE_FOR_iwmmxt_wmacu
12866132718Skan	       : fcode == ARM_BUILTIN_TMIA ? CODE_FOR_iwmmxt_tmia
12867132718Skan	       : fcode == ARM_BUILTIN_TMIAPH ? CODE_FOR_iwmmxt_tmiaph
12868132718Skan	       : fcode == ARM_BUILTIN_TMIABB ? CODE_FOR_iwmmxt_tmiabb
12869132718Skan	       : fcode == ARM_BUILTIN_TMIABT ? CODE_FOR_iwmmxt_tmiabt
12870132718Skan	       : fcode == ARM_BUILTIN_TMIATB ? CODE_FOR_iwmmxt_tmiatb
12871132718Skan	       : fcode == ARM_BUILTIN_TMIATT ? CODE_FOR_iwmmxt_tmiatt
12872132718Skan	       : CODE_FOR_iwmmxt_walign);
12873132718Skan      arg0 = TREE_VALUE (arglist);
12874132718Skan      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
12875132718Skan      arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
12876169689Skan      op0 = expand_normal (arg0);
12877169689Skan      op1 = expand_normal (arg1);
12878169689Skan      op2 = expand_normal (arg2);
12879132718Skan      tmode = insn_data[icode].operand[0].mode;
12880132718Skan      mode0 = insn_data[icode].operand[1].mode;
12881132718Skan      mode1 = insn_data[icode].operand[2].mode;
12882132718Skan      mode2 = insn_data[icode].operand[3].mode;
12883132718Skan
12884132718Skan      if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
12885132718Skan	op0 = copy_to_mode_reg (mode0, op0);
12886132718Skan      if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
12887132718Skan	op1 = copy_to_mode_reg (mode1, op1);
12888132718Skan      if (! (*insn_data[icode].operand[3].predicate) (op2, mode2))
12889132718Skan	op2 = copy_to_mode_reg (mode2, op2);
12890132718Skan      if (target == 0
12891132718Skan	  || GET_MODE (target) != tmode
12892132718Skan	  || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
12893132718Skan	target = gen_reg_rtx (tmode);
12894132718Skan      pat = GEN_FCN (icode) (target, op0, op1, op2);
12895132718Skan      if (! pat)
12896132718Skan	return 0;
12897132718Skan      emit_insn (pat);
12898132718Skan      return target;
12899169689Skan
12900132718Skan    case ARM_BUILTIN_WZERO:
12901132718Skan      target = gen_reg_rtx (DImode);
12902132718Skan      emit_insn (gen_iwmmxt_clrdi (target));
12903132718Skan      return target;
12904132718Skan
12905169689Skan    case ARM_BUILTIN_THREAD_POINTER:
12906169689Skan      return arm_load_tp (target);
12907169689Skan
12908132718Skan    default:
12909132718Skan      break;
1291090075Sobrien    }
12911117395Skan
12912132718Skan  for (i = 0, d = bdesc_2arg; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
12913132718Skan    if (d->code == (const enum arm_builtins) fcode)
12914132718Skan      return arm_expand_binop_builtin (d->icode, arglist, target);
12915132718Skan
12916132718Skan  for (i = 0, d = bdesc_1arg; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
12917132718Skan    if (d->code == (const enum arm_builtins) fcode)
12918132718Skan      return arm_expand_unop_builtin (d->icode, arglist, target, 0);
12919132718Skan
1292090075Sobrien  /* @@@ Should really do something sensible here.  */
1292190075Sobrien  return NULL_RTX;
1292290075Sobrien}
1292390075Sobrien
1292490075Sobrien/* Return the number (counting from 0) of
1292590075Sobrien   the least significant set bit in MASK.  */
1292690075Sobrien
12927132718Skaninline static int
12928169689Skannumber_of_first_bit_set (unsigned mask)
1292990075Sobrien{
1293090075Sobrien  int bit;
1293190075Sobrien
1293290075Sobrien  for (bit = 0;
1293390075Sobrien       (mask & (1 << bit)) == 0;
1293490075Sobrien       ++bit)
1293590075Sobrien    continue;
1293690075Sobrien
1293790075Sobrien  return bit;
1293890075Sobrien}
1293990075Sobrien
12940169689Skan/* Emit code to push or pop registers to or from the stack.  F is the
12941169689Skan   assembly file.  MASK is the registers to push or pop.  PUSH is
12942169689Skan   nonzero if we should push, and zero if we should pop.  For debugging
12943169689Skan   output, if pushing, adjust CFA_OFFSET by the amount of space added
12944169689Skan   to the stack.  REAL_REGS should have the same number of bits set as
12945169689Skan   MASK, and will be used instead (in the same order) to describe which
12946169689Skan   registers were saved - this is used to mark the save slots when we
12947169689Skan   push high registers after moving them to low registers.  */
12948169689Skanstatic void
12949169689Skanthumb_pushpop (FILE *f, unsigned long mask, int push, int *cfa_offset,
12950169689Skan	       unsigned long real_regs)
12951169689Skan{
12952169689Skan  int regno;
12953169689Skan  int lo_mask = mask & 0xFF;
12954169689Skan  int pushed_words = 0;
12955169689Skan
12956169689Skan  gcc_assert (mask);
12957169689Skan
12958169689Skan  if (lo_mask == 0 && !push && (mask & (1 << PC_REGNUM)))
12959169689Skan    {
12960169689Skan      /* Special case.  Do not generate a POP PC statement here, do it in
12961169689Skan	 thumb_exit() */
12962169689Skan      thumb_exit (f, -1);
12963169689Skan      return;
12964169689Skan    }
12965169689Skan
12966169689Skan  if (ARM_EABI_UNWIND_TABLES && push)
12967169689Skan    {
12968169689Skan      fprintf (f, "\t.save\t{");
12969169689Skan      for (regno = 0; regno < 15; regno++)
12970169689Skan	{
12971169689Skan	  if (real_regs & (1 << regno))
12972169689Skan	    {
12973169689Skan	      if (real_regs & ((1 << regno) -1))
12974169689Skan		fprintf (f, ", ");
12975169689Skan	      asm_fprintf (f, "%r", regno);
12976169689Skan	    }
12977169689Skan	}
12978169689Skan      fprintf (f, "}\n");
12979169689Skan    }
12980169689Skan
12981169689Skan  fprintf (f, "\t%s\t{", push ? "push" : "pop");
12982169689Skan
12983169689Skan  /* Look at the low registers first.  */
12984169689Skan  for (regno = 0; regno <= LAST_LO_REGNUM; regno++, lo_mask >>= 1)
12985169689Skan    {
12986169689Skan      if (lo_mask & 1)
12987169689Skan	{
12988169689Skan	  asm_fprintf (f, "%r", regno);
12989169689Skan
12990169689Skan	  if ((lo_mask & ~1) != 0)
12991169689Skan	    fprintf (f, ", ");
12992169689Skan
12993169689Skan	  pushed_words++;
12994169689Skan	}
12995169689Skan    }
12996169689Skan
12997169689Skan  if (push && (mask & (1 << LR_REGNUM)))
12998169689Skan    {
12999169689Skan      /* Catch pushing the LR.  */
13000169689Skan      if (mask & 0xFF)
13001169689Skan	fprintf (f, ", ");
13002169689Skan
13003169689Skan      asm_fprintf (f, "%r", LR_REGNUM);
13004169689Skan
13005169689Skan      pushed_words++;
13006169689Skan    }
13007169689Skan  else if (!push && (mask & (1 << PC_REGNUM)))
13008169689Skan    {
13009169689Skan      /* Catch popping the PC.  */
13010169689Skan      if (TARGET_INTERWORK || TARGET_BACKTRACE
13011169689Skan	  || current_function_calls_eh_return)
13012169689Skan	{
13013169689Skan	  /* The PC is never poped directly, instead
13014169689Skan	     it is popped into r3 and then BX is used.  */
13015169689Skan	  fprintf (f, "}\n");
13016169689Skan
13017169689Skan	  thumb_exit (f, -1);
13018169689Skan
13019169689Skan	  return;
13020169689Skan	}
13021169689Skan      else
13022169689Skan	{
13023169689Skan	  if (mask & 0xFF)
13024169689Skan	    fprintf (f, ", ");
13025169689Skan
13026169689Skan	  asm_fprintf (f, "%r", PC_REGNUM);
13027169689Skan	}
13028169689Skan    }
13029169689Skan
13030169689Skan  fprintf (f, "}\n");
13031169689Skan
13032169689Skan  if (push && pushed_words && dwarf2out_do_frame ())
13033169689Skan    {
13034169689Skan      char *l = dwarf2out_cfi_label ();
13035169689Skan      int pushed_mask = real_regs;
13036169689Skan
13037169689Skan      *cfa_offset += pushed_words * 4;
13038169689Skan      dwarf2out_def_cfa (l, SP_REGNUM, *cfa_offset);
13039169689Skan
13040169689Skan      pushed_words = 0;
13041169689Skan      pushed_mask = real_regs;
13042169689Skan      for (regno = 0; regno <= 14; regno++, pushed_mask >>= 1)
13043169689Skan	{
13044169689Skan	  if (pushed_mask & 1)
13045169689Skan	    dwarf2out_reg_save (l, regno, 4 * pushed_words++ - *cfa_offset);
13046169689Skan	}
13047169689Skan    }
13048169689Skan}
13049169689Skan
1305090075Sobrien/* Generate code to return from a thumb function.
1305190075Sobrien   If 'reg_containing_return_addr' is -1, then the return address is
1305290075Sobrien   actually on the stack, at the stack pointer.  */
1305390075Sobrienstatic void
13054169689Skanthumb_exit (FILE *f, int reg_containing_return_addr)
1305590075Sobrien{
1305690075Sobrien  unsigned regs_available_for_popping;
1305790075Sobrien  unsigned regs_to_pop;
1305890075Sobrien  int pops_needed;
1305990075Sobrien  unsigned available;
1306090075Sobrien  unsigned required;
1306190075Sobrien  int mode;
1306290075Sobrien  int size;
1306390075Sobrien  int restore_a4 = FALSE;
1306490075Sobrien
1306590075Sobrien  /* Compute the registers we need to pop.  */
1306690075Sobrien  regs_to_pop = 0;
1306790075Sobrien  pops_needed = 0;
1306890075Sobrien
13069169689Skan  if (reg_containing_return_addr == -1)
1307090075Sobrien    {
1307190075Sobrien      regs_to_pop |= 1 << LR_REGNUM;
1307290075Sobrien      ++pops_needed;
1307390075Sobrien    }
1307490075Sobrien
1307590075Sobrien  if (TARGET_BACKTRACE)
1307690075Sobrien    {
1307790075Sobrien      /* Restore the (ARM) frame pointer and stack pointer.  */
1307890075Sobrien      regs_to_pop |= (1 << ARM_HARD_FRAME_POINTER_REGNUM) | (1 << SP_REGNUM);
1307990075Sobrien      pops_needed += 2;
1308090075Sobrien    }
1308190075Sobrien
1308290075Sobrien  /* If there is nothing to pop then just emit the BX instruction and
1308390075Sobrien     return.  */
1308490075Sobrien  if (pops_needed == 0)
1308590075Sobrien    {
13086169689Skan      if (current_function_calls_eh_return)
13087169689Skan	asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, ARM_EH_STACKADJ_REGNUM);
1308890075Sobrien
1308990075Sobrien      asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
1309090075Sobrien      return;
1309190075Sobrien    }
1309290075Sobrien  /* Otherwise if we are not supporting interworking and we have not created
1309390075Sobrien     a backtrace structure and the function was not entered in ARM mode then
1309490075Sobrien     just pop the return address straight into the PC.  */
1309590075Sobrien  else if (!TARGET_INTERWORK
1309690075Sobrien	   && !TARGET_BACKTRACE
13097169689Skan	   && !is_called_in_ARM_mode (current_function_decl)
13098169689Skan	   && !current_function_calls_eh_return)
1309990075Sobrien    {
13100169689Skan      asm_fprintf (f, "\tpop\t{%r}\n", PC_REGNUM);
1310190075Sobrien      return;
1310290075Sobrien    }
1310390075Sobrien
1310490075Sobrien  /* Find out how many of the (return) argument registers we can corrupt.  */
1310590075Sobrien  regs_available_for_popping = 0;
1310690075Sobrien
1310790075Sobrien  /* If returning via __builtin_eh_return, the bottom three registers
1310890075Sobrien     all contain information needed for the return.  */
13109169689Skan  if (current_function_calls_eh_return)
1311090075Sobrien    size = 12;
1311190075Sobrien  else
1311290075Sobrien    {
1311390075Sobrien      /* If we can deduce the registers used from the function's
1311490075Sobrien	 return value.  This is more reliable that examining
1311590075Sobrien	 regs_ever_live[] because that will be set if the register is
1311690075Sobrien	 ever used in the function, not just if the register is used
1311790075Sobrien	 to hold a return value.  */
1311890075Sobrien
1311990075Sobrien      if (current_function_return_rtx != 0)
1312090075Sobrien	mode = GET_MODE (current_function_return_rtx);
1312190075Sobrien      else
1312290075Sobrien	mode = DECL_MODE (DECL_RESULT (current_function_decl));
1312390075Sobrien
1312490075Sobrien      size = GET_MODE_SIZE (mode);
1312590075Sobrien
1312690075Sobrien      if (size == 0)
1312790075Sobrien	{
1312890075Sobrien	  /* In a void function we can use any argument register.
1312990075Sobrien	     In a function that returns a structure on the stack
1313090075Sobrien	     we can use the second and third argument registers.  */
1313190075Sobrien	  if (mode == VOIDmode)
1313290075Sobrien	    regs_available_for_popping =
1313390075Sobrien	      (1 << ARG_REGISTER (1))
1313490075Sobrien	      | (1 << ARG_REGISTER (2))
1313590075Sobrien	      | (1 << ARG_REGISTER (3));
1313690075Sobrien	  else
1313790075Sobrien	    regs_available_for_popping =
1313890075Sobrien	      (1 << ARG_REGISTER (2))
1313990075Sobrien	      | (1 << ARG_REGISTER (3));
1314090075Sobrien	}
1314190075Sobrien      else if (size <= 4)
1314290075Sobrien	regs_available_for_popping =
1314390075Sobrien	  (1 << ARG_REGISTER (2))
1314490075Sobrien	  | (1 << ARG_REGISTER (3));
1314590075Sobrien      else if (size <= 8)
1314690075Sobrien	regs_available_for_popping =
1314790075Sobrien	  (1 << ARG_REGISTER (3));
1314890075Sobrien    }
1314990075Sobrien
1315090075Sobrien  /* Match registers to be popped with registers into which we pop them.  */
1315190075Sobrien  for (available = regs_available_for_popping,
1315290075Sobrien       required  = regs_to_pop;
1315390075Sobrien       required != 0 && available != 0;
1315490075Sobrien       available &= ~(available & - available),
1315590075Sobrien       required  &= ~(required  & - required))
1315690075Sobrien    -- pops_needed;
1315790075Sobrien
1315890075Sobrien  /* If we have any popping registers left over, remove them.  */
1315990075Sobrien  if (available > 0)
1316090075Sobrien    regs_available_for_popping &= ~available;
13161169689Skan
1316290075Sobrien  /* Otherwise if we need another popping register we can use
1316390075Sobrien     the fourth argument register.  */
1316490075Sobrien  else if (pops_needed)
1316590075Sobrien    {
1316690075Sobrien      /* If we have not found any free argument registers and
1316790075Sobrien	 reg a4 contains the return address, we must move it.  */
1316890075Sobrien      if (regs_available_for_popping == 0
1316990075Sobrien	  && reg_containing_return_addr == LAST_ARG_REGNUM)
1317090075Sobrien	{
1317190075Sobrien	  asm_fprintf (f, "\tmov\t%r, %r\n", LR_REGNUM, LAST_ARG_REGNUM);
1317290075Sobrien	  reg_containing_return_addr = LR_REGNUM;
1317390075Sobrien	}
1317490075Sobrien      else if (size > 12)
1317590075Sobrien	{
1317690075Sobrien	  /* Register a4 is being used to hold part of the return value,
1317790075Sobrien	     but we have dire need of a free, low register.  */
1317890075Sobrien	  restore_a4 = TRUE;
13179169689Skan
1318090075Sobrien	  asm_fprintf (f, "\tmov\t%r, %r\n",IP_REGNUM, LAST_ARG_REGNUM);
1318190075Sobrien	}
13182169689Skan
1318390075Sobrien      if (reg_containing_return_addr != LAST_ARG_REGNUM)
1318490075Sobrien	{
1318590075Sobrien	  /* The fourth argument register is available.  */
1318690075Sobrien	  regs_available_for_popping |= 1 << LAST_ARG_REGNUM;
13187169689Skan
1318890075Sobrien	  --pops_needed;
1318990075Sobrien	}
1319090075Sobrien    }
1319190075Sobrien
1319290075Sobrien  /* Pop as many registers as we can.  */
13193132718Skan  thumb_pushpop (f, regs_available_for_popping, FALSE, NULL,
13194132718Skan		 regs_available_for_popping);
1319590075Sobrien
1319690075Sobrien  /* Process the registers we popped.  */
1319790075Sobrien  if (reg_containing_return_addr == -1)
1319890075Sobrien    {
1319990075Sobrien      /* The return address was popped into the lowest numbered register.  */
1320090075Sobrien      regs_to_pop &= ~(1 << LR_REGNUM);
13201169689Skan
1320290075Sobrien      reg_containing_return_addr =
1320390075Sobrien	number_of_first_bit_set (regs_available_for_popping);
1320490075Sobrien
1320590075Sobrien      /* Remove this register for the mask of available registers, so that
13206132718Skan         the return address will not be corrupted by further pops.  */
1320790075Sobrien      regs_available_for_popping &= ~(1 << reg_containing_return_addr);
1320890075Sobrien    }
1320990075Sobrien
1321090075Sobrien  /* If we popped other registers then handle them here.  */
1321190075Sobrien  if (regs_available_for_popping)
1321290075Sobrien    {
1321390075Sobrien      int frame_pointer;
13214169689Skan
1321590075Sobrien      /* Work out which register currently contains the frame pointer.  */
1321690075Sobrien      frame_pointer = number_of_first_bit_set (regs_available_for_popping);
1321790075Sobrien
1321890075Sobrien      /* Move it into the correct place.  */
1321990075Sobrien      asm_fprintf (f, "\tmov\t%r, %r\n",
1322090075Sobrien		   ARM_HARD_FRAME_POINTER_REGNUM, frame_pointer);
1322190075Sobrien
1322290075Sobrien      /* (Temporarily) remove it from the mask of popped registers.  */
1322390075Sobrien      regs_available_for_popping &= ~(1 << frame_pointer);
1322490075Sobrien      regs_to_pop &= ~(1 << ARM_HARD_FRAME_POINTER_REGNUM);
13225169689Skan
1322690075Sobrien      if (regs_available_for_popping)
1322790075Sobrien	{
1322890075Sobrien	  int stack_pointer;
13229169689Skan
1323090075Sobrien	  /* We popped the stack pointer as well,
1323190075Sobrien	     find the register that contains it.  */
1323290075Sobrien	  stack_pointer = number_of_first_bit_set (regs_available_for_popping);
1323390075Sobrien
1323490075Sobrien	  /* Move it into the stack register.  */
1323590075Sobrien	  asm_fprintf (f, "\tmov\t%r, %r\n", SP_REGNUM, stack_pointer);
13236169689Skan
1323790075Sobrien	  /* At this point we have popped all necessary registers, so
1323890075Sobrien	     do not worry about restoring regs_available_for_popping
1323990075Sobrien	     to its correct value:
1324090075Sobrien
1324190075Sobrien	     assert (pops_needed == 0)
1324290075Sobrien	     assert (regs_available_for_popping == (1 << frame_pointer))
1324390075Sobrien	     assert (regs_to_pop == (1 << STACK_POINTER))  */
1324490075Sobrien	}
1324590075Sobrien      else
1324690075Sobrien	{
1324790075Sobrien	  /* Since we have just move the popped value into the frame
1324890075Sobrien	     pointer, the popping register is available for reuse, and
1324990075Sobrien	     we know that we still have the stack pointer left to pop.  */
1325090075Sobrien	  regs_available_for_popping |= (1 << frame_pointer);
1325190075Sobrien	}
1325290075Sobrien    }
13253169689Skan
1325490075Sobrien  /* If we still have registers left on the stack, but we no longer have
1325590075Sobrien     any registers into which we can pop them, then we must move the return
1325690075Sobrien     address into the link register and make available the register that
1325790075Sobrien     contained it.  */
1325890075Sobrien  if (regs_available_for_popping == 0 && pops_needed > 0)
1325990075Sobrien    {
1326090075Sobrien      regs_available_for_popping |= 1 << reg_containing_return_addr;
13261169689Skan
1326290075Sobrien      asm_fprintf (f, "\tmov\t%r, %r\n", LR_REGNUM,
1326390075Sobrien		   reg_containing_return_addr);
13264169689Skan
1326590075Sobrien      reg_containing_return_addr = LR_REGNUM;
1326690075Sobrien    }
1326790075Sobrien
1326890075Sobrien  /* If we have registers left on the stack then pop some more.
1326990075Sobrien     We know that at most we will want to pop FP and SP.  */
1327090075Sobrien  if (pops_needed > 0)
1327190075Sobrien    {
1327290075Sobrien      int  popped_into;
1327390075Sobrien      int  move_to;
13274169689Skan
13275132718Skan      thumb_pushpop (f, regs_available_for_popping, FALSE, NULL,
13276132718Skan		     regs_available_for_popping);
1327790075Sobrien
1327890075Sobrien      /* We have popped either FP or SP.
1327990075Sobrien	 Move whichever one it is into the correct register.  */
1328090075Sobrien      popped_into = number_of_first_bit_set (regs_available_for_popping);
1328190075Sobrien      move_to     = number_of_first_bit_set (regs_to_pop);
1328290075Sobrien
1328390075Sobrien      asm_fprintf (f, "\tmov\t%r, %r\n", move_to, popped_into);
1328490075Sobrien
1328590075Sobrien      regs_to_pop &= ~(1 << move_to);
1328690075Sobrien
1328790075Sobrien      --pops_needed;
1328890075Sobrien    }
13289169689Skan
1329090075Sobrien  /* If we still have not popped everything then we must have only
1329190075Sobrien     had one register available to us and we are now popping the SP.  */
1329290075Sobrien  if (pops_needed > 0)
1329390075Sobrien    {
1329490075Sobrien      int  popped_into;
13295169689Skan
13296132718Skan      thumb_pushpop (f, regs_available_for_popping, FALSE, NULL,
13297132718Skan		     regs_available_for_popping);
1329890075Sobrien
1329990075Sobrien      popped_into = number_of_first_bit_set (regs_available_for_popping);
1330090075Sobrien
1330190075Sobrien      asm_fprintf (f, "\tmov\t%r, %r\n", SP_REGNUM, popped_into);
1330290075Sobrien      /*
1330390075Sobrien	assert (regs_to_pop == (1 << STACK_POINTER))
1330490075Sobrien	assert (pops_needed == 1)
1330590075Sobrien      */
1330690075Sobrien    }
1330790075Sobrien
1330890075Sobrien  /* If necessary restore the a4 register.  */
1330990075Sobrien  if (restore_a4)
1331090075Sobrien    {
1331190075Sobrien      if (reg_containing_return_addr != LR_REGNUM)
1331290075Sobrien	{
1331390075Sobrien	  asm_fprintf (f, "\tmov\t%r, %r\n", LR_REGNUM, LAST_ARG_REGNUM);
1331490075Sobrien	  reg_containing_return_addr = LR_REGNUM;
1331590075Sobrien	}
13316169689Skan
1331790075Sobrien      asm_fprintf (f, "\tmov\t%r, %r\n", LAST_ARG_REGNUM, IP_REGNUM);
1331890075Sobrien    }
1331990075Sobrien
13320169689Skan  if (current_function_calls_eh_return)
13321169689Skan    asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, ARM_EH_STACKADJ_REGNUM);
1332290075Sobrien
1332390075Sobrien  /* Return to caller.  */
1332490075Sobrien  asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
1332590075Sobrien}
1332690075Sobrien
1332790075Sobrien
1332890075Sobrienvoid
13329132718Skanthumb_final_prescan_insn (rtx insn)
1333090075Sobrien{
1333190075Sobrien  if (flag_print_asm_name)
1333290075Sobrien    asm_fprintf (asm_out_file, "%@ 0x%04x\n",
1333390075Sobrien		 INSN_ADDRESSES (INSN_UID (insn)));
1333490075Sobrien}
1333590075Sobrien
1333690075Sobrienint
13337132718Skanthumb_shiftable_const (unsigned HOST_WIDE_INT val)
1333890075Sobrien{
1333990075Sobrien  unsigned HOST_WIDE_INT mask = 0xff;
1334090075Sobrien  int i;
1334190075Sobrien
1334290075Sobrien  if (val == 0) /* XXX */
1334390075Sobrien    return 0;
13344169689Skan
1334590075Sobrien  for (i = 0; i < 25; i++)
1334690075Sobrien    if ((val & (mask << i)) == val)
1334790075Sobrien      return 1;
1334890075Sobrien
1334990075Sobrien  return 0;
1335090075Sobrien}
1335190075Sobrien
13352117395Skan/* Returns nonzero if the current function contains,
1335390075Sobrien   or might contain a far jump.  */
13354169689Skanstatic int
13355169689Skanthumb_far_jump_used_p (void)
1335690075Sobrien{
1335790075Sobrien  rtx insn;
1335890075Sobrien
1335990075Sobrien  /* This test is only important for leaf functions.  */
1336090075Sobrien  /* assert (!leaf_function_p ()); */
13361169689Skan
1336290075Sobrien  /* If we have already decided that far jumps may be used,
1336390075Sobrien     do not bother checking again, and always return true even if
1336490075Sobrien     it turns out that they are not being used.  Once we have made
1336590075Sobrien     the decision that far jumps are present (and that hence the link
1336690075Sobrien     register will be pushed onto the stack) we cannot go back on it.  */
1336790075Sobrien  if (cfun->machine->far_jump_used)
1336890075Sobrien    return 1;
1336990075Sobrien
1337090075Sobrien  /* If this function is not being called from the prologue/epilogue
1337190075Sobrien     generation code then it must be being called from the
1337290075Sobrien     INITIAL_ELIMINATION_OFFSET macro.  */
13373169689Skan  if (!(ARM_DOUBLEWORD_ALIGN || reload_completed))
1337490075Sobrien    {
1337590075Sobrien      /* In this case we know that we are being asked about the elimination
1337690075Sobrien	 of the arg pointer register.  If that register is not being used,
1337790075Sobrien	 then there are no arguments on the stack, and we do not have to
1337890075Sobrien	 worry that a far jump might force the prologue to push the link
1337990075Sobrien	 register, changing the stack offsets.  In this case we can just
1338090075Sobrien	 return false, since the presence of far jumps in the function will
1338190075Sobrien	 not affect stack offsets.
1338290075Sobrien
1338390075Sobrien	 If the arg pointer is live (or if it was live, but has now been
1338490075Sobrien	 eliminated and so set to dead) then we do have to test to see if
1338590075Sobrien	 the function might contain a far jump.  This test can lead to some
1338690075Sobrien	 false negatives, since before reload is completed, then length of
1338790075Sobrien	 branch instructions is not known, so gcc defaults to returning their
1338890075Sobrien	 longest length, which in turn sets the far jump attribute to true.
1338990075Sobrien
1339090075Sobrien	 A false negative will not result in bad code being generated, but it
1339190075Sobrien	 will result in a needless push and pop of the link register.  We
13392169689Skan	 hope that this does not occur too often.
13393169689Skan
13394169689Skan	 If we need doubleword stack alignment this could affect the other
13395169689Skan	 elimination offsets so we can't risk getting it wrong.  */
1339690075Sobrien      if (regs_ever_live [ARG_POINTER_REGNUM])
1339790075Sobrien	cfun->machine->arg_pointer_live = 1;
1339890075Sobrien      else if (!cfun->machine->arg_pointer_live)
1339990075Sobrien	return 0;
1340090075Sobrien    }
1340190075Sobrien
1340290075Sobrien  /* Check to see if the function contains a branch
1340390075Sobrien     insn with the far jump attribute set.  */
1340490075Sobrien  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
1340590075Sobrien    {
1340690075Sobrien      if (GET_CODE (insn) == JUMP_INSN
1340790075Sobrien	  /* Ignore tablejump patterns.  */
1340890075Sobrien	  && GET_CODE (PATTERN (insn)) != ADDR_VEC
1340990075Sobrien	  && GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC
1341090075Sobrien	  && get_attr_far_jump (insn) == FAR_JUMP_YES
1341190075Sobrien	  )
1341290075Sobrien	{
13413132718Skan	  /* Record the fact that we have decided that
1341490075Sobrien	     the function does use far jumps.  */
1341590075Sobrien	  cfun->machine->far_jump_used = 1;
1341690075Sobrien	  return 1;
1341790075Sobrien	}
1341890075Sobrien    }
13419169689Skan
1342090075Sobrien  return 0;
1342190075Sobrien}
1342290075Sobrien
13423117395Skan/* Return nonzero if FUNC must be entered in ARM mode.  */
1342490075Sobrienint
13425132718Skanis_called_in_ARM_mode (tree func)
1342690075Sobrien{
13427169689Skan  gcc_assert (TREE_CODE (func) == FUNCTION_DECL);
1342890075Sobrien
13429169689Skan  /* Ignore the problem about functions whose address is taken.  */
1343090075Sobrien  if (TARGET_CALLEE_INTERWORKING && TREE_PUBLIC (func))
1343190075Sobrien    return TRUE;
1343290075Sobrien
13433169689Skan#ifdef ARM_PE
1343490075Sobrien  return lookup_attribute ("interfacearm", DECL_ATTRIBUTES (func)) != NULL_TREE;
1343590075Sobrien#else
1343690075Sobrien  return FALSE;
1343790075Sobrien#endif
1343890075Sobrien}
1343990075Sobrien
13440132718Skan/* The bits which aren't usefully expanded as rtl.  */
1344190075Sobrienconst char *
13442132718Skanthumb_unexpanded_epilogue (void)
1344390075Sobrien{
1344490075Sobrien  int regno;
13445169689Skan  unsigned long live_regs_mask = 0;
1344690075Sobrien  int high_regs_pushed = 0;
1344790075Sobrien  int had_to_push_lr;
13448169689Skan  int size;
1344990075Sobrien
1345090075Sobrien  if (return_used_this_function)
1345190075Sobrien    return "";
1345290075Sobrien
13453117395Skan  if (IS_NAKED (arm_current_func_type ()))
13454117395Skan    return "";
13455117395Skan
13456169689Skan  live_regs_mask = thumb_compute_save_reg_mask ();
13457169689Skan  high_regs_pushed = bit_count (live_regs_mask & 0x0f00);
1345890075Sobrien
13459169689Skan  /* If we can deduce the registers used from the function's return value.
13460169689Skan     This is more reliable that examining regs_ever_live[] because that
13461169689Skan     will be set if the register is ever used in the function, not just if
13462169689Skan     the register is used to hold a return value.  */
13463169689Skan  size = arm_size_return_regs ();
1346490075Sobrien
1346590075Sobrien  /* The prolog may have pushed some high registers to use as
13466169689Skan     work registers.  e.g. the testsuite file:
1346790075Sobrien     gcc/testsuite/gcc/gcc.c-torture/execute/complex-2.c
1346890075Sobrien     compiles to produce:
1346990075Sobrien	push	{r4, r5, r6, r7, lr}
1347090075Sobrien	mov	r7, r9
1347190075Sobrien	mov	r6, r8
1347290075Sobrien	push	{r6, r7}
1347390075Sobrien     as part of the prolog.  We have to undo that pushing here.  */
13474169689Skan
1347590075Sobrien  if (high_regs_pushed)
1347690075Sobrien    {
13477169689Skan      unsigned long mask = live_regs_mask & 0xff;
1347890075Sobrien      int next_hi_reg;
1347990075Sobrien
13480169689Skan      /* The available low registers depend on the size of the value we are
13481169689Skan         returning.  */
13482169689Skan      if (size <= 12)
1348390075Sobrien	mask |=  1 << 3;
13484169689Skan      if (size <= 8)
13485169689Skan	mask |= 1 << 2;
1348690075Sobrien
1348790075Sobrien      if (mask == 0)
1348890075Sobrien	/* Oh dear!  We have no low registers into which we can pop
1348990075Sobrien           high registers!  */
1349090075Sobrien	internal_error
1349190075Sobrien	  ("no low registers available for popping high registers");
13492169689Skan
1349390075Sobrien      for (next_hi_reg = 8; next_hi_reg < 13; next_hi_reg++)
13494169689Skan	if (live_regs_mask & (1 << next_hi_reg))
1349590075Sobrien	  break;
1349690075Sobrien
1349790075Sobrien      while (high_regs_pushed)
1349890075Sobrien	{
1349990075Sobrien	  /* Find lo register(s) into which the high register(s) can
1350090075Sobrien             be popped.  */
1350190075Sobrien	  for (regno = 0; regno <= LAST_LO_REGNUM; regno++)
1350290075Sobrien	    {
1350390075Sobrien	      if (mask & (1 << regno))
1350490075Sobrien		high_regs_pushed--;
1350590075Sobrien	      if (high_regs_pushed == 0)
1350690075Sobrien		break;
1350790075Sobrien	    }
1350890075Sobrien
1350990075Sobrien	  mask &= (2 << regno) - 1;	/* A noop if regno == 8 */
1351090075Sobrien
13511132718Skan	  /* Pop the values into the low register(s).  */
13512132718Skan	  thumb_pushpop (asm_out_file, mask, 0, NULL, mask);
1351390075Sobrien
1351490075Sobrien	  /* Move the value(s) into the high registers.  */
1351590075Sobrien	  for (regno = 0; regno <= LAST_LO_REGNUM; regno++)
1351690075Sobrien	    {
1351790075Sobrien	      if (mask & (1 << regno))
1351890075Sobrien		{
1351990075Sobrien		  asm_fprintf (asm_out_file, "\tmov\t%r, %r\n", next_hi_reg,
1352090075Sobrien			       regno);
13521169689Skan
1352290075Sobrien		  for (next_hi_reg++; next_hi_reg < 13; next_hi_reg++)
13523169689Skan		    if (live_regs_mask & (1 << next_hi_reg))
1352490075Sobrien		      break;
1352590075Sobrien		}
1352690075Sobrien	    }
1352790075Sobrien	}
13528169689Skan      live_regs_mask &= ~0x0f00;
1352990075Sobrien    }
1353090075Sobrien
13531169689Skan  had_to_push_lr = (live_regs_mask & (1 << LR_REGNUM)) != 0;
13532169689Skan  live_regs_mask &= 0xff;
13533169689Skan
1353490075Sobrien  if (current_function_pretend_args_size == 0 || TARGET_BACKTRACE)
1353590075Sobrien    {
13536169689Skan      /* Pop the return address into the PC.  */
13537169689Skan      if (had_to_push_lr)
1353890075Sobrien	live_regs_mask |= 1 << PC_REGNUM;
1353990075Sobrien
1354090075Sobrien      /* Either no argument registers were pushed or a backtrace
1354190075Sobrien	 structure was created which includes an adjusted stack
1354290075Sobrien	 pointer, so just pop everything.  */
1354390075Sobrien      if (live_regs_mask)
13544132718Skan	thumb_pushpop (asm_out_file, live_regs_mask, FALSE, NULL,
13545132718Skan		       live_regs_mask);
13546169689Skan
1354790075Sobrien      /* We have either just popped the return address into the
13548169689Skan	 PC or it is was kept in LR for the entire function.  */
13549169689Skan      if (!had_to_push_lr)
13550169689Skan	thumb_exit (asm_out_file, LR_REGNUM);
1355190075Sobrien    }
1355290075Sobrien  else
1355390075Sobrien    {
1355490075Sobrien      /* Pop everything but the return address.  */
1355590075Sobrien      if (live_regs_mask)
13556132718Skan	thumb_pushpop (asm_out_file, live_regs_mask, FALSE, NULL,
13557132718Skan		       live_regs_mask);
1355890075Sobrien
1355990075Sobrien      if (had_to_push_lr)
13560169689Skan	{
13561169689Skan	  if (size > 12)
13562169689Skan	    {
13563169689Skan	      /* We have no free low regs, so save one.  */
13564169689Skan	      asm_fprintf (asm_out_file, "\tmov\t%r, %r\n", IP_REGNUM,
13565169689Skan			   LAST_ARG_REGNUM);
13566169689Skan	    }
13567169689Skan
13568169689Skan	  /* Get the return address into a temporary register.  */
13569169689Skan	  thumb_pushpop (asm_out_file, 1 << LAST_ARG_REGNUM, 0, NULL,
13570169689Skan			 1 << LAST_ARG_REGNUM);
13571169689Skan
13572169689Skan	  if (size > 12)
13573169689Skan	    {
13574169689Skan	      /* Move the return address to lr.  */
13575169689Skan	      asm_fprintf (asm_out_file, "\tmov\t%r, %r\n", LR_REGNUM,
13576169689Skan			   LAST_ARG_REGNUM);
13577169689Skan	      /* Restore the low register.  */
13578169689Skan	      asm_fprintf (asm_out_file, "\tmov\t%r, %r\n", LAST_ARG_REGNUM,
13579169689Skan			   IP_REGNUM);
13580169689Skan	      regno = LR_REGNUM;
13581169689Skan	    }
13582169689Skan	  else
13583169689Skan	    regno = LAST_ARG_REGNUM;
13584169689Skan	}
13585169689Skan      else
13586169689Skan	regno = LR_REGNUM;
13587169689Skan
1358890075Sobrien      /* Remove the argument registers that were pushed onto the stack.  */
1358990075Sobrien      asm_fprintf (asm_out_file, "\tadd\t%r, %r, #%d\n",
1359090075Sobrien		   SP_REGNUM, SP_REGNUM,
1359190075Sobrien		   current_function_pretend_args_size);
13592169689Skan
13593169689Skan      thumb_exit (asm_out_file, regno);
1359490075Sobrien    }
1359590075Sobrien
1359690075Sobrien  return "";
1359790075Sobrien}
1359890075Sobrien
1359990075Sobrien/* Functions to save and restore machine-specific function data.  */
13600117395Skanstatic struct machine_function *
13601132718Skanarm_init_machine_status (void)
1360290075Sobrien{
13603117395Skan  struct machine_function *machine;
13604117395Skan  machine = (machine_function *) ggc_alloc_cleared (sizeof (machine_function));
1360590075Sobrien
13606169689Skan#if ARM_FT_UNKNOWN != 0
13607117395Skan  machine->func_type = ARM_FT_UNKNOWN;
1360890075Sobrien#endif
13609117395Skan  return machine;
1361090075Sobrien}
1361190075Sobrien
1361290075Sobrien/* Return an RTX indicating where the return address to the
1361390075Sobrien   calling function can be found.  */
1361490075Sobrienrtx
13615132718Skanarm_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
1361690075Sobrien{
1361790075Sobrien  if (count != 0)
1361890075Sobrien    return NULL_RTX;
1361990075Sobrien
13620169689Skan  return get_hard_reg_initial_val (Pmode, LR_REGNUM);
1362190075Sobrien}
1362290075Sobrien
1362390075Sobrien/* Do anything needed before RTL is emitted for each function.  */
1362490075Sobrienvoid
13625132718Skanarm_init_expanders (void)
1362690075Sobrien{
1362790075Sobrien  /* Arrange to initialize and mark the machine per-function status.  */
1362890075Sobrien  init_machine_status = arm_init_machine_status;
13629169689Skan
13630169689Skan  /* This is to stop the combine pass optimizing away the alignment
13631169689Skan     adjustment of va_arg.  */
13632169689Skan  /* ??? It is claimed that this should not be necessary.  */
13633169689Skan  if (cfun)
13634169689Skan    mark_reg_pointer (arg_pointer_rtx, PARM_BOUNDARY);
1363590075Sobrien}
1363690075Sobrien
13637169689Skan
13638169689Skan/* Like arm_compute_initial_elimination offset.  Simpler because there
13639169689Skan   isn't an ABI specified frame pointer for Thumb.  Instead, we set it
13640169689Skan   to point at the base of the local variables after static stack
13641169689Skan   space for a function has been allocated.  */
13642169689Skan
13643117395SkanHOST_WIDE_INT
13644169689Skanthumb_compute_initial_elimination_offset (unsigned int from, unsigned int to)
13645117395Skan{
13646169689Skan  arm_stack_offsets *offsets;
13647117395Skan
13648169689Skan  offsets = arm_get_frame_offsets ();
13649117395Skan
13650169689Skan  switch (from)
13651169689Skan    {
13652169689Skan    case ARG_POINTER_REGNUM:
13653169689Skan      switch (to)
13654169689Skan	{
13655169689Skan	case STACK_POINTER_REGNUM:
13656169689Skan	  return offsets->outgoing_args - offsets->saved_args;
13657117395Skan
13658169689Skan	case FRAME_POINTER_REGNUM:
13659169689Skan	  return offsets->soft_frame - offsets->saved_args;
13660117395Skan
13661169689Skan	case ARM_HARD_FRAME_POINTER_REGNUM:
13662169689Skan	  return offsets->saved_regs - offsets->saved_args;
13663117395Skan
13664169689Skan	case THUMB_HARD_FRAME_POINTER_REGNUM:
13665169689Skan	  return offsets->locals_base - offsets->saved_args;
13666117395Skan
13667169689Skan	default:
13668169689Skan	  gcc_unreachable ();
13669169689Skan	}
13670169689Skan      break;
13671117395Skan
13672169689Skan    case FRAME_POINTER_REGNUM:
13673169689Skan      switch (to)
13674169689Skan	{
13675169689Skan	case STACK_POINTER_REGNUM:
13676169689Skan	  return offsets->outgoing_args - offsets->soft_frame;
13677117395Skan
13678169689Skan	case ARM_HARD_FRAME_POINTER_REGNUM:
13679169689Skan	  return offsets->saved_regs - offsets->soft_frame;
13680117395Skan
13681169689Skan	case THUMB_HARD_FRAME_POINTER_REGNUM:
13682169689Skan	  return offsets->locals_base - offsets->soft_frame;
13683117395Skan
13684169689Skan	default:
13685169689Skan	  gcc_unreachable ();
13686169689Skan	}
13687169689Skan      break;
13688117395Skan
13689169689Skan    default:
13690169689Skan      gcc_unreachable ();
13691117395Skan    }
13692169689Skan}
13693117395Skan
13694117395Skan
1369590075Sobrien/* Generate the rest of a function's prologue.  */
1369690075Sobrienvoid
13697132718Skanthumb_expand_prologue (void)
1369890075Sobrien{
13699132718Skan  rtx insn, dwarf;
13700132718Skan
13701169689Skan  HOST_WIDE_INT amount;
13702169689Skan  arm_stack_offsets *offsets;
1370390075Sobrien  unsigned long func_type;
13704169689Skan  int regno;
13705169689Skan  unsigned long live_regs_mask;
1370690075Sobrien
1370790075Sobrien  func_type = arm_current_func_type ();
13708169689Skan
1370990075Sobrien  /* Naked functions don't have prologues.  */
1371090075Sobrien  if (IS_NAKED (func_type))
1371190075Sobrien    return;
1371290075Sobrien
1371390075Sobrien  if (IS_INTERRUPT (func_type))
1371490075Sobrien    {
1371590075Sobrien      error ("interrupt Service Routines cannot be coded in Thumb mode");
1371690075Sobrien      return;
1371790075Sobrien    }
1371890075Sobrien
13719169689Skan  live_regs_mask = thumb_compute_save_reg_mask ();
13720169689Skan  /* Load the pic register before setting the frame pointer,
13721169689Skan     so we can use r7 as a temporary work register.  */
13722169689Skan  if (flag_pic && arm_pic_register != INVALID_REGNUM)
13723169689Skan    arm_load_pic_register (live_regs_mask);
1372490075Sobrien
13725169689Skan  if (!frame_pointer_needed && CALLER_INTERWORKING_SLOT_SIZE > 0)
13726169689Skan    emit_move_insn (gen_rtx_REG (Pmode, ARM_HARD_FRAME_POINTER_REGNUM),
13727169689Skan		    stack_pointer_rtx);
13728169689Skan
13729169689Skan  offsets = arm_get_frame_offsets ();
13730169689Skan  amount = offsets->outgoing_args - offsets->saved_regs;
1373190075Sobrien  if (amount)
1373290075Sobrien    {
1373390075Sobrien      if (amount < 512)
13734132718Skan	{
13735132718Skan	  insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
13736132718Skan					GEN_INT (- amount)));
13737132718Skan	  RTX_FRAME_RELATED_P (insn) = 1;
13738132718Skan	}
1373990075Sobrien      else
1374090075Sobrien	{
1374190075Sobrien	  rtx reg;
1374290075Sobrien
1374390075Sobrien	  /* The stack decrement is too big for an immediate value in a single
1374490075Sobrien	     insn.  In theory we could issue multiple subtracts, but after
1374590075Sobrien	     three of them it becomes more space efficient to place the full
1374690075Sobrien	     value in the constant pool and load into a register.  (Also the
1374790075Sobrien	     ARM debugger really likes to see only one stack decrement per
1374890075Sobrien	     function).  So instead we look for a scratch register into which
1374990075Sobrien	     we can load the decrement, and then we subtract this from the
1375090075Sobrien	     stack pointer.  Unfortunately on the thumb the only available
1375190075Sobrien	     scratch registers are the argument registers, and we cannot use
1375290075Sobrien	     these as they may hold arguments to the function.  Instead we
1375390075Sobrien	     attempt to locate a call preserved register which is used by this
1375490075Sobrien	     function.  If we can find one, then we know that it will have
1375590075Sobrien	     been pushed at the start of the prologue and so we can corrupt
1375690075Sobrien	     it now.  */
1375790075Sobrien	  for (regno = LAST_ARG_REGNUM + 1; regno <= LAST_LO_REGNUM; regno++)
13758169689Skan	    if (live_regs_mask & (1 << regno)
1375990075Sobrien		&& !(frame_pointer_needed
1376090075Sobrien		     && (regno == THUMB_HARD_FRAME_POINTER_REGNUM)))
1376190075Sobrien	      break;
1376290075Sobrien
13763117395Skan	  if (regno > LAST_LO_REGNUM) /* Very unlikely.  */
1376490075Sobrien	    {
13765169689Skan	      rtx spare = gen_rtx_REG (SImode, IP_REGNUM);
1376690075Sobrien
13767132718Skan	      /* Choose an arbitrary, non-argument low register.  */
13768169689Skan	      reg = gen_rtx_REG (SImode, LAST_LO_REGNUM);
1376990075Sobrien
1377090075Sobrien	      /* Save it by copying it into a high, scratch register.  */
1377190075Sobrien	      emit_insn (gen_movsi (spare, reg));
1377290075Sobrien	      /* Add a USE to stop propagate_one_insn() from barfing.  */
1377390075Sobrien	      emit_insn (gen_prologue_use (spare));
1377490075Sobrien
1377590075Sobrien	      /* Decrement the stack.  */
1377690075Sobrien	      emit_insn (gen_movsi (reg, GEN_INT (- amount)));
13777132718Skan	      insn = emit_insn (gen_addsi3 (stack_pointer_rtx,
13778132718Skan					    stack_pointer_rtx, reg));
13779132718Skan	      RTX_FRAME_RELATED_P (insn) = 1;
13780169689Skan	      dwarf = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
13781132718Skan				   plus_constant (stack_pointer_rtx,
13782169689Skan						  -amount));
13783132718Skan	      RTX_FRAME_RELATED_P (dwarf) = 1;
13784132718Skan	      REG_NOTES (insn)
13785132718Skan		= gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
13786132718Skan				     REG_NOTES (insn));
1378790075Sobrien
1378890075Sobrien	      /* Restore the low register's original value.  */
1378990075Sobrien	      emit_insn (gen_movsi (reg, spare));
13790169689Skan
1379190075Sobrien	      /* Emit a USE of the restored scratch register, so that flow
1379290075Sobrien		 analysis will not consider the restore redundant.  The
1379390075Sobrien		 register won't be used again in this function and isn't
1379490075Sobrien		 restored by the epilogue.  */
1379590075Sobrien	      emit_insn (gen_prologue_use (reg));
1379690075Sobrien	    }
1379790075Sobrien	  else
1379890075Sobrien	    {
13799169689Skan	      reg = gen_rtx_REG (SImode, regno);
1380090075Sobrien
1380190075Sobrien	      emit_insn (gen_movsi (reg, GEN_INT (- amount)));
13802132718Skan
13803132718Skan	      insn = emit_insn (gen_addsi3 (stack_pointer_rtx,
13804132718Skan					    stack_pointer_rtx, reg));
13805132718Skan	      RTX_FRAME_RELATED_P (insn) = 1;
13806169689Skan	      dwarf = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
13807132718Skan				   plus_constant (stack_pointer_rtx,
13808169689Skan						  -amount));
13809132718Skan	      RTX_FRAME_RELATED_P (dwarf) = 1;
13810132718Skan	      REG_NOTES (insn)
13811132718Skan		= gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
13812132718Skan				     REG_NOTES (insn));
1381390075Sobrien	    }
1381490075Sobrien	}
1381590075Sobrien    }
13816169689Skan
13817169689Skan  if (frame_pointer_needed)
13818169689Skan    {
13819169689Skan      amount = offsets->outgoing_args - offsets->locals_base;
13820169689Skan
13821169689Skan      if (amount < 1024)
13822169689Skan	insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx,
13823169689Skan				      stack_pointer_rtx, GEN_INT (amount)));
13824169689Skan      else
13825169689Skan	{
13826169689Skan	  emit_insn (gen_movsi (hard_frame_pointer_rtx, GEN_INT (amount)));
13827169689Skan	  insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx,
13828169689Skan					hard_frame_pointer_rtx,
13829169689Skan					stack_pointer_rtx));
13830169689Skan	  dwarf = gen_rtx_SET (VOIDmode, hard_frame_pointer_rtx,
13831169689Skan			       plus_constant (stack_pointer_rtx, amount));
13832169689Skan	  RTX_FRAME_RELATED_P (dwarf) = 1;
13833169689Skan	  REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
13834169689Skan						REG_NOTES (insn));
13835169689Skan	}
13836169689Skan
13837169689Skan      RTX_FRAME_RELATED_P (insn) = 1;
13838169689Skan    }
13839169689Skan
13840169689Skan  /* If we are profiling, make sure no instructions are scheduled before
13841169689Skan     the call to mcount.  Similarly if the user has requested no
13842169689Skan     scheduling in the prolog.  Similarly if we want non-call exceptions
13843169689Skan     using the EABI unwinder, to prevent faulting instructions from being
13844169689Skan     swapped with a stack adjustment.  */
13845169689Skan  if (current_function_profile || !TARGET_SCHED_PROLOG
13846169689Skan      || (ARM_EABI_UNWIND_TABLES && flag_non_call_exceptions))
1384790075Sobrien    emit_insn (gen_blockage ());
13848169689Skan
13849169689Skan  cfun->machine->lr_save_eliminated = !thumb_force_lr_save ();
13850169689Skan  if (live_regs_mask & 0xff)
13851169689Skan    cfun->machine->lr_save_eliminated = 0;
13852169689Skan
13853169689Skan  /* If the link register is being kept alive, with the return address in it,
13854169689Skan     then make sure that it does not get reused by the ce2 pass.  */
13855169689Skan  if (cfun->machine->lr_save_eliminated)
13856169689Skan    emit_insn (gen_prologue_use (gen_rtx_REG (SImode, LR_REGNUM)));
1385790075Sobrien}
1385890075Sobrien
13859169689Skan
1386090075Sobrienvoid
13861132718Skanthumb_expand_epilogue (void)
1386290075Sobrien{
13863169689Skan  HOST_WIDE_INT amount;
13864169689Skan  arm_stack_offsets *offsets;
13865132718Skan  int regno;
13866132718Skan
1386790075Sobrien  /* Naked functions don't have prologues.  */
1386890075Sobrien  if (IS_NAKED (arm_current_func_type ()))
1386990075Sobrien    return;
1387090075Sobrien
13871169689Skan  offsets = arm_get_frame_offsets ();
13872169689Skan  amount = offsets->outgoing_args - offsets->saved_regs;
13873169689Skan
1387490075Sobrien  if (frame_pointer_needed)
1387590075Sobrien    {
13876169689Skan      emit_insn (gen_movsi (stack_pointer_rtx, hard_frame_pointer_rtx));
13877169689Skan      amount = offsets->locals_base - offsets->saved_regs;
13878169689Skan    }
13879169689Skan
13880171825Skan  gcc_assert (amount >= 0);
13881169689Skan  if (amount)
13882169689Skan    {
1388390075Sobrien      if (amount < 512)
1388490075Sobrien	emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
1388590075Sobrien			       GEN_INT (amount)));
1388690075Sobrien      else
1388790075Sobrien	{
1388890075Sobrien	  /* r3 is always free in the epilogue.  */
13889169689Skan	  rtx reg = gen_rtx_REG (SImode, LAST_ARG_REGNUM);
1389090075Sobrien
1389190075Sobrien	  emit_insn (gen_movsi (reg, GEN_INT (amount)));
1389290075Sobrien	  emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, reg));
1389390075Sobrien	}
1389490075Sobrien    }
13895169689Skan
1389690075Sobrien  /* Emit a USE (stack_pointer_rtx), so that
1389790075Sobrien     the stack adjustment will not be deleted.  */
1389890075Sobrien  emit_insn (gen_prologue_use (stack_pointer_rtx));
1389990075Sobrien
13900169689Skan  if (current_function_profile || !TARGET_SCHED_PROLOG)
1390190075Sobrien    emit_insn (gen_blockage ());
13902132718Skan
13903132718Skan  /* Emit a clobber for each insn that will be restored in the epilogue,
13904132718Skan     so that flow2 will get register lifetimes correct.  */
13905132718Skan  for (regno = 0; regno < 13; regno++)
13906132718Skan    if (regs_ever_live[regno] && !call_used_regs[regno])
13907132718Skan      emit_insn (gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, regno)));
13908132718Skan
13909132718Skan  if (! regs_ever_live[LR_REGNUM])
13910132718Skan    emit_insn (gen_rtx_USE (VOIDmode, gen_rtx_REG (SImode, LR_REGNUM)));
1391190075Sobrien}
1391290075Sobrien
1391390075Sobrienstatic void
13914132718Skanthumb_output_function_prologue (FILE *f, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
1391590075Sobrien{
13916169689Skan  unsigned long live_regs_mask = 0;
13917169689Skan  unsigned long l_mask;
13918169689Skan  unsigned high_regs_pushed = 0;
13919132718Skan  int cfa_offset = 0;
1392090075Sobrien  int regno;
1392190075Sobrien
1392290075Sobrien  if (IS_NAKED (arm_current_func_type ()))
1392390075Sobrien    return;
1392490075Sobrien
1392590075Sobrien  if (is_called_in_ARM_mode (current_function_decl))
1392690075Sobrien    {
1392790075Sobrien      const char * name;
1392890075Sobrien
13929169689Skan      gcc_assert (GET_CODE (DECL_RTL (current_function_decl)) == MEM);
13930169689Skan      gcc_assert (GET_CODE (XEXP (DECL_RTL (current_function_decl), 0))
13931169689Skan		  == SYMBOL_REF);
1393290075Sobrien      name = XSTR  (XEXP (DECL_RTL (current_function_decl), 0), 0);
13933169689Skan
1393490075Sobrien      /* Generate code sequence to switch us into Thumb mode.  */
1393590075Sobrien      /* The .code 32 directive has already been emitted by
1393690075Sobrien	 ASM_DECLARE_FUNCTION_NAME.  */
1393790075Sobrien      asm_fprintf (f, "\torr\t%r, %r, #1\n", IP_REGNUM, PC_REGNUM);
1393890075Sobrien      asm_fprintf (f, "\tbx\t%r\n", IP_REGNUM);
1393990075Sobrien
1394090075Sobrien      /* Generate a label, so that the debugger will notice the
1394190075Sobrien	 change in instruction sets.  This label is also used by
1394290075Sobrien	 the assembler to bypass the ARM code when this function
1394390075Sobrien	 is called from a Thumb encoded function elsewhere in the
1394490075Sobrien	 same file.  Hence the definition of STUB_NAME here must
13945132718Skan	 agree with the definition in gas/config/tc-arm.c.  */
13946169689Skan
1394790075Sobrien#define STUB_NAME ".real_start_of"
13948169689Skan
13949117395Skan      fprintf (f, "\t.code\t16\n");
1395090075Sobrien#ifdef ARM_PE
1395190075Sobrien      if (arm_dllexport_name_p (name))
1395290075Sobrien        name = arm_strip_name_encoding (name);
13953169689Skan#endif
1395490075Sobrien      asm_fprintf (f, "\t.globl %s%U%s\n", STUB_NAME, name);
13955117395Skan      fprintf (f, "\t.thumb_func\n");
1395690075Sobrien      asm_fprintf (f, "%s%U%s:\n", STUB_NAME, name);
1395790075Sobrien    }
13958169689Skan
1395990075Sobrien  if (current_function_pretend_args_size)
1396090075Sobrien    {
13961169689Skan      /* Output unwind directive for the stack adjustment.  */
13962169689Skan      if (ARM_EABI_UNWIND_TABLES)
13963169689Skan	fprintf (f, "\t.pad #%d\n",
13964169689Skan		 current_function_pretend_args_size);
13965169689Skan
1396696263Sobrien      if (cfun->machine->uses_anonymous_args)
1396790075Sobrien	{
1396890075Sobrien	  int num_pushes;
13969169689Skan
13970117395Skan	  fprintf (f, "\tpush\t{");
1397190075Sobrien
13972117395Skan	  num_pushes = ARM_NUM_INTS (current_function_pretend_args_size);
13973169689Skan
1397490075Sobrien	  for (regno = LAST_ARG_REGNUM + 1 - num_pushes;
1397590075Sobrien	       regno <= LAST_ARG_REGNUM;
1397690075Sobrien	       regno++)
1397790075Sobrien	    asm_fprintf (f, "%r%s", regno,
1397890075Sobrien			 regno == LAST_ARG_REGNUM ? "" : ", ");
1397990075Sobrien
13980117395Skan	  fprintf (f, "}\n");
1398190075Sobrien	}
1398290075Sobrien      else
13983169689Skan	asm_fprintf (f, "\tsub\t%r, %r, #%d\n",
1398490075Sobrien		     SP_REGNUM, SP_REGNUM,
1398590075Sobrien		     current_function_pretend_args_size);
13986132718Skan
13987132718Skan      /* We don't need to record the stores for unwinding (would it
13988132718Skan	 help the debugger any if we did?), but record the change in
13989132718Skan	 the stack pointer.  */
13990132718Skan      if (dwarf2out_do_frame ())
13991132718Skan	{
13992132718Skan	  char *l = dwarf2out_cfi_label ();
13993169689Skan
13994132718Skan	  cfa_offset = cfa_offset + current_function_pretend_args_size;
13995132718Skan	  dwarf2out_def_cfa (l, SP_REGNUM, cfa_offset);
13996132718Skan	}
1399790075Sobrien    }
1399890075Sobrien
13999169689Skan  /* Get the registers we are going to push.  */
14000169689Skan  live_regs_mask = thumb_compute_save_reg_mask ();
14001169689Skan  /* Extract a mask of the ones we can give to the Thumb's push instruction.  */
14002169689Skan  l_mask = live_regs_mask & 0x40ff;
14003169689Skan  /* Then count how many other high registers will need to be pushed.  */
14004169689Skan  high_regs_pushed = bit_count (live_regs_mask & 0x0f00);
1400590075Sobrien
1400690075Sobrien  if (TARGET_BACKTRACE)
1400790075Sobrien    {
14008169689Skan      unsigned offset;
14009169689Skan      unsigned work_register;
14010169689Skan
1401190075Sobrien      /* We have been asked to create a stack backtrace structure.
1401290075Sobrien         The code looks like this:
14013169689Skan
1401490075Sobrien	 0   .align 2
1401590075Sobrien	 0   func:
1401690075Sobrien         0     sub   SP, #16         Reserve space for 4 registers.
14017169689Skan	 2     push  {R7}            Push low registers.
1401890075Sobrien         4     add   R7, SP, #20     Get the stack pointer before the push.
1401990075Sobrien         6     str   R7, [SP, #8]    Store the stack pointer (before reserving the space).
1402090075Sobrien         8     mov   R7, PC          Get hold of the start of this code plus 12.
1402190075Sobrien        10     str   R7, [SP, #16]   Store it.
1402290075Sobrien        12     mov   R7, FP          Get hold of the current frame pointer.
1402390075Sobrien        14     str   R7, [SP, #4]    Store it.
1402490075Sobrien        16     mov   R7, LR          Get hold of the current return address.
1402590075Sobrien        18     str   R7, [SP, #12]   Store it.
1402690075Sobrien        20     add   R7, SP, #16     Point at the start of the backtrace structure.
1402790075Sobrien        22     mov   FP, R7          Put this value into the frame pointer.  */
1402890075Sobrien
14029169689Skan      work_register = thumb_find_work_register (live_regs_mask);
1403090075Sobrien
14031169689Skan      if (ARM_EABI_UNWIND_TABLES)
14032169689Skan	asm_fprintf (f, "\t.pad #16\n");
1403390075Sobrien
1403490075Sobrien      asm_fprintf
1403590075Sobrien	(f, "\tsub\t%r, %r, #16\t%@ Create stack backtrace structure\n",
1403690075Sobrien	 SP_REGNUM, SP_REGNUM);
14037132718Skan
14038132718Skan      if (dwarf2out_do_frame ())
14039132718Skan	{
14040132718Skan	  char *l = dwarf2out_cfi_label ();
14041169689Skan
14042132718Skan	  cfa_offset = cfa_offset + 16;
14043132718Skan	  dwarf2out_def_cfa (l, SP_REGNUM, cfa_offset);
14044132718Skan	}
14045132718Skan
14046169689Skan      if (l_mask)
14047169689Skan	{
14048169689Skan	  thumb_pushpop (f, l_mask, 1, &cfa_offset, l_mask);
14049169689Skan	  offset = bit_count (l_mask) * UNITS_PER_WORD;
14050169689Skan	}
14051169689Skan      else
14052169689Skan	offset = 0;
14053169689Skan
1405490075Sobrien      asm_fprintf (f, "\tadd\t%r, %r, #%d\n", work_register, SP_REGNUM,
1405590075Sobrien		   offset + 16 + current_function_pretend_args_size);
14056169689Skan
1405790075Sobrien      asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
1405890075Sobrien		   offset + 4);
1405990075Sobrien
1406090075Sobrien      /* Make sure that the instruction fetching the PC is in the right place
1406190075Sobrien	 to calculate "start of backtrace creation code + 12".  */
14062169689Skan      if (l_mask)
1406390075Sobrien	{
1406490075Sobrien	  asm_fprintf (f, "\tmov\t%r, %r\n", work_register, PC_REGNUM);
1406590075Sobrien	  asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
1406690075Sobrien		       offset + 12);
1406790075Sobrien	  asm_fprintf (f, "\tmov\t%r, %r\n", work_register,
1406890075Sobrien		       ARM_HARD_FRAME_POINTER_REGNUM);
1406990075Sobrien	  asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
1407090075Sobrien		       offset);
1407190075Sobrien	}
1407290075Sobrien      else
1407390075Sobrien	{
1407490075Sobrien	  asm_fprintf (f, "\tmov\t%r, %r\n", work_register,
1407590075Sobrien		       ARM_HARD_FRAME_POINTER_REGNUM);
1407690075Sobrien	  asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
1407790075Sobrien		       offset);
1407890075Sobrien	  asm_fprintf (f, "\tmov\t%r, %r\n", work_register, PC_REGNUM);
1407990075Sobrien	  asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
1408090075Sobrien		       offset + 12);
1408190075Sobrien	}
14082169689Skan
1408390075Sobrien      asm_fprintf (f, "\tmov\t%r, %r\n", work_register, LR_REGNUM);
1408490075Sobrien      asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
1408590075Sobrien		   offset + 8);
1408690075Sobrien      asm_fprintf (f, "\tadd\t%r, %r, #%d\n", work_register, SP_REGNUM,
1408790075Sobrien		   offset + 12);
1408890075Sobrien      asm_fprintf (f, "\tmov\t%r, %r\t\t%@ Backtrace structure created\n",
1408990075Sobrien		   ARM_HARD_FRAME_POINTER_REGNUM, work_register);
1409090075Sobrien    }
14091169689Skan  /* Optimization:  If we are not pushing any low registers but we are going
14092169689Skan     to push some high registers then delay our first push.  This will just
14093169689Skan     be a push of LR and we can combine it with the push of the first high
14094169689Skan     register.  */
14095169689Skan  else if ((l_mask & 0xff) != 0
14096169689Skan	   || (high_regs_pushed == 0 && l_mask))
14097169689Skan    thumb_pushpop (f, l_mask, 1, &cfa_offset, l_mask);
1409890075Sobrien
1409990075Sobrien  if (high_regs_pushed)
1410090075Sobrien    {
14101169689Skan      unsigned pushable_regs;
14102169689Skan      unsigned next_hi_reg;
1410390075Sobrien
1410490075Sobrien      for (next_hi_reg = 12; next_hi_reg > LAST_LO_REGNUM; next_hi_reg--)
14105169689Skan	if (live_regs_mask & (1 << next_hi_reg))
14106117395Skan	  break;
1410790075Sobrien
14108169689Skan      pushable_regs = l_mask & 0xff;
1410990075Sobrien
1411090075Sobrien      if (pushable_regs == 0)
14111169689Skan	pushable_regs = 1 << thumb_find_work_register (live_regs_mask);
1411290075Sobrien
1411390075Sobrien      while (high_regs_pushed > 0)
1411490075Sobrien	{
14115169689Skan	  unsigned long real_regs_mask = 0;
14116132718Skan
14117169689Skan	  for (regno = LAST_LO_REGNUM; regno >= 0; regno --)
1411890075Sobrien	    {
14119169689Skan	      if (pushable_regs & (1 << regno))
1412090075Sobrien		{
1412190075Sobrien		  asm_fprintf (f, "\tmov\t%r, %r\n", regno, next_hi_reg);
14122169689Skan
14123169689Skan		  high_regs_pushed --;
14124132718Skan		  real_regs_mask |= (1 << next_hi_reg);
14125169689Skan
1412690075Sobrien		  if (high_regs_pushed)
14127117395Skan		    {
14128169689Skan		      for (next_hi_reg --; next_hi_reg > LAST_LO_REGNUM;
14129169689Skan			   next_hi_reg --)
14130169689Skan			if (live_regs_mask & (1 << next_hi_reg))
1413190075Sobrien			  break;
14132117395Skan		    }
1413390075Sobrien		  else
1413490075Sobrien		    {
14135169689Skan		      pushable_regs &= ~((1 << regno) - 1);
1413690075Sobrien		      break;
1413790075Sobrien		    }
1413890075Sobrien		}
1413990075Sobrien	    }
14140132718Skan
14141169689Skan	  /* If we had to find a work register and we have not yet
14142169689Skan	     saved the LR then add it to the list of regs to push.  */
14143169689Skan	  if (l_mask == (1 << LR_REGNUM))
14144169689Skan	    {
14145169689Skan	      thumb_pushpop (f, pushable_regs | (1 << LR_REGNUM),
14146169689Skan			     1, &cfa_offset,
14147169689Skan			     real_regs_mask | (1 << LR_REGNUM));
14148169689Skan	      l_mask = 0;
14149169689Skan	    }
14150169689Skan	  else
14151169689Skan	    thumb_pushpop (f, pushable_regs, 1, &cfa_offset, real_regs_mask);
1415290075Sobrien	}
1415390075Sobrien    }
1415490075Sobrien}
1415590075Sobrien
1415690075Sobrien/* Handle the case of a double word load into a low register from
1415790075Sobrien   a computed memory address.  The computed address may involve a
1415890075Sobrien   register which is overwritten by the load.  */
1415990075Sobrienconst char *
14160132718Skanthumb_load_double_from_address (rtx *operands)
1416190075Sobrien{
1416290075Sobrien  rtx addr;
1416390075Sobrien  rtx base;
1416490075Sobrien  rtx offset;
1416590075Sobrien  rtx arg1;
1416690075Sobrien  rtx arg2;
1416790075Sobrien
14168169689Skan  gcc_assert (GET_CODE (operands[0]) == REG);
14169169689Skan  gcc_assert (GET_CODE (operands[1]) == MEM);
14170169689Skan
1417190075Sobrien  /* Get the memory address.  */
1417290075Sobrien  addr = XEXP (operands[1], 0);
14173169689Skan
1417490075Sobrien  /* Work out how the memory address is computed.  */
1417590075Sobrien  switch (GET_CODE (addr))
1417690075Sobrien    {
1417790075Sobrien    case REG:
14178169689Skan      operands[2] = adjust_address (operands[1], SImode, 4);
1417990075Sobrien
1418090075Sobrien      if (REGNO (operands[0]) == REGNO (addr))
1418190075Sobrien	{
1418290075Sobrien	  output_asm_insn ("ldr\t%H0, %2", operands);
1418390075Sobrien	  output_asm_insn ("ldr\t%0, %1", operands);
1418490075Sobrien	}
1418590075Sobrien      else
1418690075Sobrien	{
1418790075Sobrien	  output_asm_insn ("ldr\t%0, %1", operands);
1418890075Sobrien	  output_asm_insn ("ldr\t%H0, %2", operands);
1418990075Sobrien	}
1419090075Sobrien      break;
14191169689Skan
1419290075Sobrien    case CONST:
1419390075Sobrien      /* Compute <address> + 4 for the high order load.  */
14194169689Skan      operands[2] = adjust_address (operands[1], SImode, 4);
14195169689Skan
1419690075Sobrien      output_asm_insn ("ldr\t%0, %1", operands);
1419790075Sobrien      output_asm_insn ("ldr\t%H0, %2", operands);
1419890075Sobrien      break;
14199169689Skan
1420090075Sobrien    case PLUS:
1420190075Sobrien      arg1   = XEXP (addr, 0);
1420290075Sobrien      arg2   = XEXP (addr, 1);
14203169689Skan
1420490075Sobrien      if (CONSTANT_P (arg1))
1420590075Sobrien	base = arg2, offset = arg1;
1420690075Sobrien      else
1420790075Sobrien	base = arg1, offset = arg2;
1420890075Sobrien
14209169689Skan      gcc_assert (GET_CODE (base) == REG);
14210169689Skan
1421190075Sobrien      /* Catch the case of <address> = <reg> + <reg> */
1421290075Sobrien      if (GET_CODE (offset) == REG)
1421390075Sobrien	{
1421490075Sobrien	  int reg_offset = REGNO (offset);
1421590075Sobrien	  int reg_base   = REGNO (base);
1421690075Sobrien	  int reg_dest   = REGNO (operands[0]);
14217169689Skan
1421890075Sobrien	  /* Add the base and offset registers together into the
1421990075Sobrien             higher destination register.  */
1422090075Sobrien	  asm_fprintf (asm_out_file, "\tadd\t%r, %r, %r",
1422190075Sobrien		       reg_dest + 1, reg_base, reg_offset);
14222169689Skan
1422390075Sobrien	  /* Load the lower destination register from the address in
1422490075Sobrien             the higher destination register.  */
1422590075Sobrien	  asm_fprintf (asm_out_file, "\tldr\t%r, [%r, #0]",
1422690075Sobrien		       reg_dest, reg_dest + 1);
14227169689Skan
1422890075Sobrien	  /* Load the higher destination register from its own address
1422990075Sobrien             plus 4.  */
1423090075Sobrien	  asm_fprintf (asm_out_file, "\tldr\t%r, [%r, #4]",
1423190075Sobrien		       reg_dest + 1, reg_dest + 1);
1423290075Sobrien	}
1423390075Sobrien      else
1423490075Sobrien	{
1423590075Sobrien	  /* Compute <address> + 4 for the high order load.  */
14236169689Skan	  operands[2] = adjust_address (operands[1], SImode, 4);
14237169689Skan
1423890075Sobrien	  /* If the computed address is held in the low order register
1423990075Sobrien	     then load the high order register first, otherwise always
1424090075Sobrien	     load the low order register first.  */
1424190075Sobrien	  if (REGNO (operands[0]) == REGNO (base))
1424290075Sobrien	    {
1424390075Sobrien	      output_asm_insn ("ldr\t%H0, %2", operands);
1424490075Sobrien	      output_asm_insn ("ldr\t%0, %1", operands);
1424590075Sobrien	    }
1424690075Sobrien	  else
1424790075Sobrien	    {
1424890075Sobrien	      output_asm_insn ("ldr\t%0, %1", operands);
1424990075Sobrien	      output_asm_insn ("ldr\t%H0, %2", operands);
1425090075Sobrien	    }
1425190075Sobrien	}
1425290075Sobrien      break;
1425390075Sobrien
1425490075Sobrien    case LABEL_REF:
1425590075Sobrien      /* With no registers to worry about we can just load the value
1425690075Sobrien         directly.  */
14257169689Skan      operands[2] = adjust_address (operands[1], SImode, 4);
14258169689Skan
1425990075Sobrien      output_asm_insn ("ldr\t%H0, %2", operands);
1426090075Sobrien      output_asm_insn ("ldr\t%0, %1", operands);
1426190075Sobrien      break;
14262169689Skan
1426390075Sobrien    default:
14264169689Skan      gcc_unreachable ();
1426590075Sobrien    }
14266169689Skan
1426790075Sobrien  return "";
1426890075Sobrien}
1426990075Sobrien
1427090075Sobrienconst char *
14271132718Skanthumb_output_move_mem_multiple (int n, rtx *operands)
1427290075Sobrien{
1427390075Sobrien  rtx tmp;
1427490075Sobrien
1427590075Sobrien  switch (n)
1427690075Sobrien    {
1427790075Sobrien    case 2:
1427890075Sobrien      if (REGNO (operands[4]) > REGNO (operands[5]))
1427990075Sobrien	{
1428090075Sobrien	  tmp = operands[4];
1428190075Sobrien	  operands[4] = operands[5];
1428290075Sobrien	  operands[5] = tmp;
1428390075Sobrien	}
1428490075Sobrien      output_asm_insn ("ldmia\t%1!, {%4, %5}", operands);
1428590075Sobrien      output_asm_insn ("stmia\t%0!, {%4, %5}", operands);
1428690075Sobrien      break;
1428790075Sobrien
1428890075Sobrien    case 3:
1428990075Sobrien      if (REGNO (operands[4]) > REGNO (operands[5]))
1429090075Sobrien	{
1429190075Sobrien	  tmp = operands[4];
1429290075Sobrien	  operands[4] = operands[5];
1429390075Sobrien	  operands[5] = tmp;
1429490075Sobrien	}
1429590075Sobrien      if (REGNO (operands[5]) > REGNO (operands[6]))
1429690075Sobrien	{
1429790075Sobrien	  tmp = operands[5];
1429890075Sobrien	  operands[5] = operands[6];
1429990075Sobrien	  operands[6] = tmp;
1430090075Sobrien	}
1430190075Sobrien      if (REGNO (operands[4]) > REGNO (operands[5]))
1430290075Sobrien	{
1430390075Sobrien	  tmp = operands[4];
1430490075Sobrien	  operands[4] = operands[5];
1430590075Sobrien	  operands[5] = tmp;
1430690075Sobrien	}
14307169689Skan
1430890075Sobrien      output_asm_insn ("ldmia\t%1!, {%4, %5, %6}", operands);
1430990075Sobrien      output_asm_insn ("stmia\t%0!, {%4, %5, %6}", operands);
1431090075Sobrien      break;
1431190075Sobrien
1431290075Sobrien    default:
14313169689Skan      gcc_unreachable ();
1431490075Sobrien    }
1431590075Sobrien
1431690075Sobrien  return "";
1431790075Sobrien}
1431890075Sobrien
14319169689Skan/* Output a call-via instruction for thumb state.  */
14320169689Skanconst char *
14321169689Skanthumb_call_via_reg (rtx reg)
14322169689Skan{
14323169689Skan  int regno = REGNO (reg);
14324169689Skan  rtx *labelp;
14325169689Skan
14326169689Skan  gcc_assert (regno < LR_REGNUM);
14327169689Skan
14328169689Skan  /* If we are in the normal text section we can use a single instance
14329169689Skan     per compilation unit.  If we are doing function sections, then we need
14330169689Skan     an entry per section, since we can't rely on reachability.  */
14331169689Skan  if (in_section == text_section)
14332169689Skan    {
14333169689Skan      thumb_call_reg_needed = 1;
14334169689Skan
14335169689Skan      if (thumb_call_via_label[regno] == NULL)
14336169689Skan	thumb_call_via_label[regno] = gen_label_rtx ();
14337169689Skan      labelp = thumb_call_via_label + regno;
14338169689Skan    }
14339169689Skan  else
14340169689Skan    {
14341169689Skan      if (cfun->machine->call_via[regno] == NULL)
14342169689Skan	cfun->machine->call_via[regno] = gen_label_rtx ();
14343169689Skan      labelp = cfun->machine->call_via + regno;
14344169689Skan    }
14345169689Skan
14346169689Skan  output_asm_insn ("bl\t%a0", labelp);
14347169689Skan  return "";
14348169689Skan}
14349169689Skan
1435090075Sobrien/* Routines for generating rtl.  */
1435190075Sobrienvoid
14352169689Skanthumb_expand_movmemqi (rtx *operands)
1435390075Sobrien{
1435490075Sobrien  rtx out = copy_to_mode_reg (SImode, XEXP (operands[0], 0));
1435590075Sobrien  rtx in  = copy_to_mode_reg (SImode, XEXP (operands[1], 0));
1435690075Sobrien  HOST_WIDE_INT len = INTVAL (operands[2]);
1435790075Sobrien  HOST_WIDE_INT offset = 0;
1435890075Sobrien
1435990075Sobrien  while (len >= 12)
1436090075Sobrien    {
1436190075Sobrien      emit_insn (gen_movmem12b (out, in, out, in));
1436290075Sobrien      len -= 12;
1436390075Sobrien    }
14364169689Skan
1436590075Sobrien  if (len >= 8)
1436690075Sobrien    {
1436790075Sobrien      emit_insn (gen_movmem8b (out, in, out, in));
1436890075Sobrien      len -= 8;
1436990075Sobrien    }
14370169689Skan
1437190075Sobrien  if (len >= 4)
1437290075Sobrien    {
1437390075Sobrien      rtx reg = gen_reg_rtx (SImode);
14374169689Skan      emit_insn (gen_movsi (reg, gen_rtx_MEM (SImode, in)));
14375169689Skan      emit_insn (gen_movsi (gen_rtx_MEM (SImode, out), reg));
1437690075Sobrien      len -= 4;
1437790075Sobrien      offset += 4;
1437890075Sobrien    }
14379169689Skan
1438090075Sobrien  if (len >= 2)
1438190075Sobrien    {
1438290075Sobrien      rtx reg = gen_reg_rtx (HImode);
14383169689Skan      emit_insn (gen_movhi (reg, gen_rtx_MEM (HImode,
14384169689Skan					      plus_constant (in, offset))));
14385169689Skan      emit_insn (gen_movhi (gen_rtx_MEM (HImode, plus_constant (out, offset)),
1438690075Sobrien			    reg));
1438790075Sobrien      len -= 2;
1438890075Sobrien      offset += 2;
1438990075Sobrien    }
14390169689Skan
1439190075Sobrien  if (len)
1439290075Sobrien    {
1439390075Sobrien      rtx reg = gen_reg_rtx (QImode);
14394169689Skan      emit_insn (gen_movqi (reg, gen_rtx_MEM (QImode,
14395169689Skan					      plus_constant (in, offset))));
14396169689Skan      emit_insn (gen_movqi (gen_rtx_MEM (QImode, plus_constant (out, offset)),
1439790075Sobrien			    reg));
1439890075Sobrien    }
1439990075Sobrien}
1440090075Sobrien
1440190075Sobrienvoid
14402132718Skanthumb_reload_out_hi (rtx *operands)
1440390075Sobrien{
1440490075Sobrien  emit_insn (gen_thumb_movhi_clobber (operands[0], operands[1], operands[2]));
1440590075Sobrien}
1440690075Sobrien
14407169689Skan/* Handle reading a half-word from memory during reload.  */
1440890075Sobrienvoid
14409132718Skanthumb_reload_in_hi (rtx *operands ATTRIBUTE_UNUSED)
1441090075Sobrien{
14411169689Skan  gcc_unreachable ();
1441290075Sobrien}
1441390075Sobrien
1441490075Sobrien/* Return the length of a function name prefix
1441590075Sobrien    that starts with the character 'c'.  */
1441690075Sobrienstatic int
14417132718Skanarm_get_strip_length (int c)
1441890075Sobrien{
1441990075Sobrien  switch (c)
1442090075Sobrien    {
1442190075Sobrien    ARM_NAME_ENCODING_LENGTHS
14422169689Skan      default: return 0;
1442390075Sobrien    }
1442490075Sobrien}
1442590075Sobrien
1442690075Sobrien/* Return a pointer to a function's name with any
1442790075Sobrien   and all prefix encodings stripped from it.  */
1442890075Sobrienconst char *
14429132718Skanarm_strip_name_encoding (const char *name)
1443090075Sobrien{
1443190075Sobrien  int skip;
14432169689Skan
1443390075Sobrien  while ((skip = arm_get_strip_length (* name)))
1443490075Sobrien    name += skip;
1443590075Sobrien
1443690075Sobrien  return name;
1443790075Sobrien}
1443890075Sobrien
14439117395Skan/* If there is a '*' anywhere in the name's prefix, then
14440117395Skan   emit the stripped name verbatim, otherwise prepend an
14441117395Skan   underscore if leading underscores are being used.  */
14442117395Skanvoid
14443132718Skanarm_asm_output_labelref (FILE *stream, const char *name)
14444117395Skan{
14445117395Skan  int skip;
14446117395Skan  int verbatim = 0;
14447117395Skan
14448117395Skan  while ((skip = arm_get_strip_length (* name)))
14449117395Skan    {
14450117395Skan      verbatim |= (*name == '*');
14451117395Skan      name += skip;
14452117395Skan    }
14453117395Skan
14454117395Skan  if (verbatim)
14455117395Skan    fputs (name, stream);
14456117395Skan  else
14457117395Skan    asm_fprintf (stream, "%U%s", name);
14458117395Skan}
14459117395Skan
14460169689Skanstatic void
14461169689Skanarm_file_end (void)
14462169689Skan{
14463169689Skan  int regno;
14464169689Skan
14465169689Skan  if (! thumb_call_reg_needed)
14466169689Skan    return;
14467169689Skan
14468169689Skan  switch_to_section (text_section);
14469169689Skan  asm_fprintf (asm_out_file, "\t.code 16\n");
14470169689Skan  ASM_OUTPUT_ALIGN (asm_out_file, 1);
14471169689Skan
14472169689Skan  for (regno = 0; regno < LR_REGNUM; regno++)
14473169689Skan    {
14474169689Skan      rtx label = thumb_call_via_label[regno];
14475169689Skan
14476169689Skan      if (label != 0)
14477169689Skan	{
14478169689Skan	  targetm.asm_out.internal_label (asm_out_file, "L",
14479169689Skan					  CODE_LABEL_NUMBER (label));
14480169689Skan	  asm_fprintf (asm_out_file, "\tbx\t%r\n", regno);
14481169689Skan	}
14482169689Skan    }
14483169689Skan}
14484169689Skan
14485117395Skanrtx aof_pic_label;
14486117395Skan
1448790075Sobrien#ifdef AOF_ASSEMBLER
1448890075Sobrien/* Special functions only needed when producing AOF syntax assembler.  */
1448990075Sobrien
1449090075Sobrienstruct pic_chain
1449190075Sobrien{
1449290075Sobrien  struct pic_chain * next;
1449390075Sobrien  const char * symname;
1449490075Sobrien};
1449590075Sobrien
1449690075Sobrienstatic struct pic_chain * aof_pic_chain = NULL;
1449790075Sobrien
1449890075Sobrienrtx
14499132718Skanaof_pic_entry (rtx x)
1450090075Sobrien{
1450190075Sobrien  struct pic_chain ** chainp;
1450290075Sobrien  int offset;
1450390075Sobrien
1450490075Sobrien  if (aof_pic_label == NULL_RTX)
1450590075Sobrien    {
1450690075Sobrien      aof_pic_label = gen_rtx_SYMBOL_REF (Pmode, "x$adcons");
1450790075Sobrien    }
1450890075Sobrien
1450990075Sobrien  for (offset = 0, chainp = &aof_pic_chain; *chainp;
1451090075Sobrien       offset += 4, chainp = &(*chainp)->next)
1451190075Sobrien    if ((*chainp)->symname == XSTR (x, 0))
1451290075Sobrien      return plus_constant (aof_pic_label, offset);
1451390075Sobrien
1451490075Sobrien  *chainp = (struct pic_chain *) xmalloc (sizeof (struct pic_chain));
1451590075Sobrien  (*chainp)->next = NULL;
1451690075Sobrien  (*chainp)->symname = XSTR (x, 0);
1451790075Sobrien  return plus_constant (aof_pic_label, offset);
1451890075Sobrien}
1451990075Sobrien
1452090075Sobrienvoid
14521132718Skanaof_dump_pic_table (FILE *f)
1452290075Sobrien{
1452390075Sobrien  struct pic_chain * chain;
1452490075Sobrien
1452590075Sobrien  if (aof_pic_chain == NULL)
1452690075Sobrien    return;
1452790075Sobrien
1452890075Sobrien  asm_fprintf (f, "\tAREA |%r$$adcons|, BASED %r\n",
1452990075Sobrien	       PIC_OFFSET_TABLE_REGNUM,
1453090075Sobrien	       PIC_OFFSET_TABLE_REGNUM);
1453190075Sobrien  fputs ("|x$adcons|\n", f);
14532169689Skan
1453390075Sobrien  for (chain = aof_pic_chain; chain; chain = chain->next)
1453490075Sobrien    {
1453590075Sobrien      fputs ("\tDCD\t", f);
1453690075Sobrien      assemble_name (f, chain->symname);
1453790075Sobrien      fputs ("\n", f);
1453890075Sobrien    }
1453990075Sobrien}
1454090075Sobrien
1454190075Sobrienint arm_text_section_count = 1;
1454290075Sobrien
14543169689Skan/* A get_unnamed_section callback for switching to the text section.  */
14544169689Skan
14545169689Skanstatic void
14546169689Skanaof_output_text_section_asm_op (const void *data ATTRIBUTE_UNUSED)
1454790075Sobrien{
14548169689Skan  fprintf (asm_out_file, "\tAREA |C$$code%d|, CODE, READONLY",
1454990075Sobrien	   arm_text_section_count++);
1455090075Sobrien  if (flag_pic)
14551169689Skan    fprintf (asm_out_file, ", PIC, REENTRANT");
14552169689Skan  fprintf (asm_out_file, "\n");
1455390075Sobrien}
1455490075Sobrien
1455590075Sobrienstatic int arm_data_section_count = 1;
1455690075Sobrien
14557169689Skan/* A get_unnamed_section callback for switching to the data section.  */
14558169689Skan
14559169689Skanstatic void
14560169689Skanaof_output_data_section_asm_op (const void *data ATTRIBUTE_UNUSED)
1456190075Sobrien{
14562169689Skan  fprintf (asm_out_file, "\tAREA |C$$data%d|, DATA\n",
14563169689Skan	   arm_data_section_count++);
1456490075Sobrien}
1456590075Sobrien
14566169689Skan/* Implement TARGET_ASM_INIT_SECTIONS.
14567169689Skan
14568169689Skan   AOF Assembler syntax is a nightmare when it comes to areas, since once
14569169689Skan   we change from one area to another, we can't go back again.  Instead,
14570169689Skan   we must create a new area with the same attributes and add the new output
14571169689Skan   to that.  Unfortunately, there is nothing we can do here to guarantee that
14572169689Skan   two areas with the same attributes will be linked adjacently in the
14573169689Skan   resulting executable, so we have to be careful not to do pc-relative
14574169689Skan   addressing across such boundaries.  */
14575169689Skan
14576169689Skanstatic void
14577169689Skanaof_asm_init_sections (void)
14578169689Skan{
14579169689Skan  text_section = get_unnamed_section (SECTION_CODE,
14580169689Skan				      aof_output_text_section_asm_op, NULL);
14581169689Skan  data_section = get_unnamed_section (SECTION_WRITE,
14582169689Skan				      aof_output_data_section_asm_op, NULL);
14583169689Skan  readonly_data_section = text_section;
14584169689Skan}
14585169689Skan
14586169689Skanvoid
14587169689Skanzero_init_section (void)
14588169689Skan{
14589169689Skan  static int zero_init_count = 1;
14590169689Skan
14591169689Skan  fprintf (asm_out_file, "\tAREA |C$$zidata%d|,NOINIT\n", zero_init_count++);
14592169689Skan  in_section = NULL;
14593169689Skan}
14594169689Skan
1459590075Sobrien/* The AOF assembler is religiously strict about declarations of
1459690075Sobrien   imported and exported symbols, so that it is impossible to declare
1459790075Sobrien   a function as imported near the beginning of the file, and then to
1459890075Sobrien   export it later on.  It is, however, possible to delay the decision
1459990075Sobrien   until all the functions in the file have been compiled.  To get
1460090075Sobrien   around this, we maintain a list of the imports and exports, and
1460190075Sobrien   delete from it any that are subsequently defined.  At the end of
1460290075Sobrien   compilation we spit the remainder of the list out before the END
1460390075Sobrien   directive.  */
1460490075Sobrien
1460590075Sobrienstruct import
1460690075Sobrien{
1460790075Sobrien  struct import * next;
1460890075Sobrien  const char * name;
1460990075Sobrien};
1461090075Sobrien
1461190075Sobrienstatic struct import * imports_list = NULL;
1461290075Sobrien
1461390075Sobrienvoid
14614132718Skanaof_add_import (const char *name)
1461590075Sobrien{
1461690075Sobrien  struct import * new;
1461790075Sobrien
1461890075Sobrien  for (new = imports_list; new; new = new->next)
1461990075Sobrien    if (new->name == name)
1462090075Sobrien      return;
1462190075Sobrien
1462290075Sobrien  new = (struct import *) xmalloc (sizeof (struct import));
1462390075Sobrien  new->next = imports_list;
1462490075Sobrien  imports_list = new;
1462590075Sobrien  new->name = name;
1462690075Sobrien}
1462790075Sobrien
1462890075Sobrienvoid
14629132718Skanaof_delete_import (const char *name)
1463090075Sobrien{
1463190075Sobrien  struct import ** old;
1463290075Sobrien
1463390075Sobrien  for (old = &imports_list; *old; old = & (*old)->next)
1463490075Sobrien    {
1463590075Sobrien      if ((*old)->name == name)
1463690075Sobrien	{
1463790075Sobrien	  *old = (*old)->next;
1463890075Sobrien	  return;
1463990075Sobrien	}
1464090075Sobrien    }
1464190075Sobrien}
1464290075Sobrien
1464390075Sobrienint arm_main_function = 0;
1464490075Sobrien
14645132718Skanstatic void
14646132718Skanaof_dump_imports (FILE *f)
1464790075Sobrien{
1464890075Sobrien  /* The AOF assembler needs this to cause the startup code to be extracted
1464990075Sobrien     from the library.  Brining in __main causes the whole thing to work
1465090075Sobrien     automagically.  */
1465190075Sobrien  if (arm_main_function)
1465290075Sobrien    {
14653169689Skan      switch_to_section (text_section);
1465490075Sobrien      fputs ("\tIMPORT __main\n", f);
1465590075Sobrien      fputs ("\tDCD __main\n", f);
1465690075Sobrien    }
1465790075Sobrien
1465890075Sobrien  /* Now dump the remaining imports.  */
1465990075Sobrien  while (imports_list)
1466090075Sobrien    {
1466190075Sobrien      fprintf (f, "\tIMPORT\t");
1466290075Sobrien      assemble_name (f, imports_list->name);
1466390075Sobrien      fputc ('\n', f);
1466490075Sobrien      imports_list = imports_list->next;
1466590075Sobrien    }
1466690075Sobrien}
14667117395Skan
14668117395Skanstatic void
14669132718Skanaof_globalize_label (FILE *stream, const char *name)
14670117395Skan{
14671117395Skan  default_globalize_label (stream, name);
14672117395Skan  if (! strcmp (name, "main"))
14673117395Skan    arm_main_function = 1;
14674117395Skan}
14675132718Skan
14676132718Skanstatic void
14677132718Skanaof_file_start (void)
14678132718Skan{
14679132718Skan  fputs ("__r0\tRN\t0\n", asm_out_file);
14680132718Skan  fputs ("__a1\tRN\t0\n", asm_out_file);
14681132718Skan  fputs ("__a2\tRN\t1\n", asm_out_file);
14682132718Skan  fputs ("__a3\tRN\t2\n", asm_out_file);
14683132718Skan  fputs ("__a4\tRN\t3\n", asm_out_file);
14684132718Skan  fputs ("__v1\tRN\t4\n", asm_out_file);
14685132718Skan  fputs ("__v2\tRN\t5\n", asm_out_file);
14686132718Skan  fputs ("__v3\tRN\t6\n", asm_out_file);
14687132718Skan  fputs ("__v4\tRN\t7\n", asm_out_file);
14688132718Skan  fputs ("__v5\tRN\t8\n", asm_out_file);
14689132718Skan  fputs ("__v6\tRN\t9\n", asm_out_file);
14690132718Skan  fputs ("__sl\tRN\t10\n", asm_out_file);
14691132718Skan  fputs ("__fp\tRN\t11\n", asm_out_file);
14692132718Skan  fputs ("__ip\tRN\t12\n", asm_out_file);
14693132718Skan  fputs ("__sp\tRN\t13\n", asm_out_file);
14694132718Skan  fputs ("__lr\tRN\t14\n", asm_out_file);
14695132718Skan  fputs ("__pc\tRN\t15\n", asm_out_file);
14696132718Skan  fputs ("__f0\tFN\t0\n", asm_out_file);
14697132718Skan  fputs ("__f1\tFN\t1\n", asm_out_file);
14698132718Skan  fputs ("__f2\tFN\t2\n", asm_out_file);
14699132718Skan  fputs ("__f3\tFN\t3\n", asm_out_file);
14700132718Skan  fputs ("__f4\tFN\t4\n", asm_out_file);
14701132718Skan  fputs ("__f5\tFN\t5\n", asm_out_file);
14702132718Skan  fputs ("__f6\tFN\t6\n", asm_out_file);
14703132718Skan  fputs ("__f7\tFN\t7\n", asm_out_file);
14704169689Skan  switch_to_section (text_section);
14705132718Skan}
14706132718Skan
14707132718Skanstatic void
14708132718Skanaof_file_end (void)
14709132718Skan{
14710132718Skan  if (flag_pic)
14711132718Skan    aof_dump_pic_table (asm_out_file);
14712169689Skan  arm_file_end ();
14713132718Skan  aof_dump_imports (asm_out_file);
14714132718Skan  fputs ("\tEND\n", asm_out_file);
14715132718Skan}
1471690075Sobrien#endif /* AOF_ASSEMBLER */
1471790075Sobrien
14718117395Skan#ifndef ARM_PE
14719117395Skan/* Symbols in the text segment can be accessed without indirecting via the
14720117395Skan   constant pool; it may take an extra binary operation, but this is still
14721117395Skan   faster than indirecting via memory.  Don't do this when not optimizing,
14722117395Skan   since we won't be calculating al of the offsets necessary to do this
14723117395Skan   simplification.  */
14724117395Skan
14725117395Skanstatic void
14726132718Skanarm_encode_section_info (tree decl, rtx rtl, int first)
14727117395Skan{
14728117395Skan  /* This doesn't work with AOF syntax, since the string table may be in
14729117395Skan     a different AREA.  */
14730117395Skan#ifndef AOF_ASSEMBLER
14731169689Skan  if (optimize > 0 && TREE_CONSTANT (decl))
14732132718Skan    SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1;
14733117395Skan#endif
14734117395Skan
14735117395Skan  /* If we are referencing a function that is weak then encode a long call
14736117395Skan     flag in the function name, otherwise if the function is static or
14737117395Skan     or known to be defined in this file then encode a short call flag.  */
14738169689Skan  if (first && DECL_P (decl))
14739117395Skan    {
14740117395Skan      if (TREE_CODE (decl) == FUNCTION_DECL && DECL_WEAK (decl))
14741117395Skan        arm_encode_call_attribute (decl, LONG_CALL_FLAG_CHAR);
14742117395Skan      else if (! TREE_PUBLIC (decl))
14743117395Skan        arm_encode_call_attribute (decl, SHORT_CALL_FLAG_CHAR);
14744117395Skan    }
14745169689Skan
14746169689Skan  default_encode_section_info (decl, rtl, first);
14747117395Skan}
14748117395Skan#endif /* !ARM_PE */
14749117395Skan
14750132718Skanstatic void
14751132718Skanarm_internal_label (FILE *stream, const char *prefix, unsigned long labelno)
14752132718Skan{
14753132718Skan  if (arm_ccfsm_state == 3 && (unsigned) arm_target_label == labelno
14754132718Skan      && !strcmp (prefix, "L"))
14755132718Skan    {
14756132718Skan      arm_ccfsm_state = 0;
14757132718Skan      arm_target_insn = NULL;
14758132718Skan    }
14759132718Skan  default_internal_label (stream, prefix, labelno);
14760132718Skan}
14761132718Skan
14762117395Skan/* Output code to add DELTA to the first argument, and then jump
14763117395Skan   to FUNCTION.  Used for C++ multiple inheritance.  */
14764117395Skanstatic void
14765132718Skanarm_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
14766132718Skan		     HOST_WIDE_INT delta,
14767132718Skan		     HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED,
14768132718Skan		     tree function)
14769117395Skan{
14770132718Skan  static int thunk_label = 0;
14771132718Skan  char label[256];
14772169689Skan  char labelpc[256];
14773117395Skan  int mi_delta = delta;
14774117395Skan  const char *const mi_op = mi_delta < 0 ? "sub" : "add";
14775117395Skan  int shift = 0;
14776132718Skan  int this_regno = (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function)
14777117395Skan                    ? 1 : 0);
14778117395Skan  if (mi_delta < 0)
14779117395Skan    mi_delta = - mi_delta;
14780132718Skan  if (TARGET_THUMB)
14781132718Skan    {
14782132718Skan      int labelno = thunk_label++;
14783132718Skan      ASM_GENERATE_INTERNAL_LABEL (label, "LTHUMBFUNC", labelno);
14784132718Skan      fputs ("\tldr\tr12, ", file);
14785132718Skan      assemble_name (file, label);
14786132718Skan      fputc ('\n', file);
14787169689Skan      if (flag_pic)
14788169689Skan	{
14789169689Skan	  /* If we are generating PIC, the ldr instruction below loads
14790169689Skan	     "(target - 7) - .LTHUNKPCn" into r12.  The pc reads as
14791169689Skan	     the address of the add + 8, so we have:
14792169689Skan
14793169689Skan	     r12 = (target - 7) - .LTHUNKPCn + (.LTHUNKPCn + 8)
14794169689Skan	         = target + 1.
14795169689Skan
14796169689Skan	     Note that we have "+ 1" because some versions of GNU ld
14797169689Skan	     don't set the low bit of the result for R_ARM_REL32
14798169689Skan	     relocations against thumb function symbols.  */
14799169689Skan	  ASM_GENERATE_INTERNAL_LABEL (labelpc, "LTHUNKPC", labelno);
14800169689Skan	  assemble_name (file, labelpc);
14801169689Skan	  fputs (":\n", file);
14802169689Skan	  fputs ("\tadd\tr12, pc, r12\n", file);
14803169689Skan	}
14804132718Skan    }
14805117395Skan  while (mi_delta != 0)
14806117395Skan    {
14807117395Skan      if ((mi_delta & (3 << shift)) == 0)
14808117395Skan        shift += 2;
14809117395Skan      else
14810117395Skan        {
14811117395Skan          asm_fprintf (file, "\t%s\t%r, %r, #%d\n",
14812117395Skan                       mi_op, this_regno, this_regno,
14813117395Skan                       mi_delta & (0xff << shift));
14814117395Skan          mi_delta &= ~(0xff << shift);
14815117395Skan          shift += 8;
14816117395Skan        }
14817117395Skan    }
14818132718Skan  if (TARGET_THUMB)
14819132718Skan    {
14820132718Skan      fprintf (file, "\tbx\tr12\n");
14821132718Skan      ASM_OUTPUT_ALIGN (file, 2);
14822132718Skan      assemble_name (file, label);
14823132718Skan      fputs (":\n", file);
14824169689Skan      if (flag_pic)
14825169689Skan	{
14826169689Skan	  /* Output ".word .LTHUNKn-7-.LTHUNKPCn".  */
14827169689Skan	  rtx tem = XEXP (DECL_RTL (function), 0);
14828169689Skan	  tem = gen_rtx_PLUS (GET_MODE (tem), tem, GEN_INT (-7));
14829169689Skan	  tem = gen_rtx_MINUS (GET_MODE (tem),
14830169689Skan			       tem,
14831169689Skan			       gen_rtx_SYMBOL_REF (Pmode,
14832169689Skan						   ggc_strdup (labelpc)));
14833169689Skan	  assemble_integer (tem, 4, BITS_PER_WORD, 1);
14834169689Skan	}
14835169689Skan      else
14836169689Skan	/* Output ".word .LTHUNKn".  */
14837169689Skan	assemble_integer (XEXP (DECL_RTL (function), 0), 4, BITS_PER_WORD, 1);
14838132718Skan    }
14839132718Skan  else
14840132718Skan    {
14841132718Skan      fputs ("\tb\t", file);
14842132718Skan      assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0));
14843132718Skan      if (NEED_PLT_RELOC)
14844132718Skan        fputs ("(PLT)", file);
14845132718Skan      fputc ('\n', file);
14846132718Skan    }
14847117395Skan}
14848117395Skan
14849132718Skanint
14850132718Skanarm_emit_vector_const (FILE *file, rtx x)
14851132718Skan{
14852132718Skan  int i;
14853132718Skan  const char * pattern;
14854132718Skan
14855169689Skan  gcc_assert (GET_CODE (x) == CONST_VECTOR);
14856132718Skan
14857132718Skan  switch (GET_MODE (x))
14858132718Skan    {
14859132718Skan    case V2SImode: pattern = "%08x"; break;
14860132718Skan    case V4HImode: pattern = "%04x"; break;
14861132718Skan    case V8QImode: pattern = "%02x"; break;
14862169689Skan    default:       gcc_unreachable ();
14863132718Skan    }
14864132718Skan
14865132718Skan  fprintf (file, "0x");
14866132718Skan  for (i = CONST_VECTOR_NUNITS (x); i--;)
14867132718Skan    {
14868132718Skan      rtx element;
14869132718Skan
14870132718Skan      element = CONST_VECTOR_ELT (x, i);
14871132718Skan      fprintf (file, pattern, INTVAL (element));
14872132718Skan    }
14873132718Skan
14874132718Skan  return 1;
14875132718Skan}
14876132718Skan
14877132718Skanconst char *
14878132718Skanarm_output_load_gr (rtx *operands)
14879132718Skan{
14880132718Skan  rtx reg;
14881132718Skan  rtx offset;
14882132718Skan  rtx wcgr;
14883132718Skan  rtx sum;
14884169689Skan
14885132718Skan  if (GET_CODE (operands [1]) != MEM
14886132718Skan      || GET_CODE (sum = XEXP (operands [1], 0)) != PLUS
14887132718Skan      || GET_CODE (reg = XEXP (sum, 0)) != REG
14888132718Skan      || GET_CODE (offset = XEXP (sum, 1)) != CONST_INT
14889132718Skan      || ((INTVAL (offset) < 1024) && (INTVAL (offset) > -1024)))
14890132718Skan    return "wldrw%?\t%0, %1";
14891169689Skan
14892169689Skan  /* Fix up an out-of-range load of a GR register.  */
14893132718Skan  output_asm_insn ("str%?\t%0, [sp, #-4]!\t@ Start of GR load expansion", & reg);
14894132718Skan  wcgr = operands[0];
14895132718Skan  operands[0] = reg;
14896132718Skan  output_asm_insn ("ldr%?\t%0, %1", operands);
14897132718Skan
14898132718Skan  operands[0] = wcgr;
14899132718Skan  operands[1] = reg;
14900132718Skan  output_asm_insn ("tmcr%?\t%0, %1", operands);
14901132718Skan  output_asm_insn ("ldr%?\t%0, [sp], #4\t@ End of GR load expansion", & reg);
14902132718Skan
14903132718Skan  return "";
14904132718Skan}
14905169689Skan
14906169689Skan/* Worker function for TARGET_SETUP_INCOMING_VARARGS.
14907169689Skan
14908169689Skan   On the ARM, PRETEND_SIZE is set in order to have the prologue push the last
14909169689Skan   named arg and all anonymous args onto the stack.
14910169689Skan   XXX I know the prologue shouldn't be pushing registers, but it is faster
14911169689Skan   that way.  */
14912169689Skan
14913169689Skanstatic void
14914169689Skanarm_setup_incoming_varargs (CUMULATIVE_ARGS *cum,
14915169689Skan			    enum machine_mode mode ATTRIBUTE_UNUSED,
14916169689Skan			    tree type ATTRIBUTE_UNUSED,
14917169689Skan			    int *pretend_size,
14918169689Skan			    int second_time ATTRIBUTE_UNUSED)
14919169689Skan{
14920169689Skan  cfun->machine->uses_anonymous_args = 1;
14921169689Skan  if (cum->nregs < NUM_ARG_REGS)
14922169689Skan    *pretend_size = (NUM_ARG_REGS - cum->nregs) * UNITS_PER_WORD;
14923169689Skan}
14924169689Skan
14925169689Skan/* Return nonzero if the CONSUMER instruction (a store) does not need
14926169689Skan   PRODUCER's value to calculate the address.  */
14927169689Skan
14928169689Skanint
14929169689Skanarm_no_early_store_addr_dep (rtx producer, rtx consumer)
14930169689Skan{
14931169689Skan  rtx value = PATTERN (producer);
14932169689Skan  rtx addr = PATTERN (consumer);
14933169689Skan
14934169689Skan  if (GET_CODE (value) == COND_EXEC)
14935169689Skan    value = COND_EXEC_CODE (value);
14936169689Skan  if (GET_CODE (value) == PARALLEL)
14937169689Skan    value = XVECEXP (value, 0, 0);
14938169689Skan  value = XEXP (value, 0);
14939169689Skan  if (GET_CODE (addr) == COND_EXEC)
14940169689Skan    addr = COND_EXEC_CODE (addr);
14941169689Skan  if (GET_CODE (addr) == PARALLEL)
14942169689Skan    addr = XVECEXP (addr, 0, 0);
14943169689Skan  addr = XEXP (addr, 0);
14944169689Skan
14945169689Skan  return !reg_overlap_mentioned_p (value, addr);
14946169689Skan}
14947169689Skan
14948169689Skan/* Return nonzero if the CONSUMER instruction (an ALU op) does not
14949169689Skan   have an early register shift value or amount dependency on the
14950169689Skan   result of PRODUCER.  */
14951169689Skan
14952169689Skanint
14953169689Skanarm_no_early_alu_shift_dep (rtx producer, rtx consumer)
14954169689Skan{
14955169689Skan  rtx value = PATTERN (producer);
14956169689Skan  rtx op = PATTERN (consumer);
14957169689Skan  rtx early_op;
14958169689Skan
14959169689Skan  if (GET_CODE (value) == COND_EXEC)
14960169689Skan    value = COND_EXEC_CODE (value);
14961169689Skan  if (GET_CODE (value) == PARALLEL)
14962169689Skan    value = XVECEXP (value, 0, 0);
14963169689Skan  value = XEXP (value, 0);
14964169689Skan  if (GET_CODE (op) == COND_EXEC)
14965169689Skan    op = COND_EXEC_CODE (op);
14966169689Skan  if (GET_CODE (op) == PARALLEL)
14967169689Skan    op = XVECEXP (op, 0, 0);
14968169689Skan  op = XEXP (op, 1);
14969169689Skan
14970169689Skan  early_op = XEXP (op, 0);
14971169689Skan  /* This is either an actual independent shift, or a shift applied to
14972169689Skan     the first operand of another operation.  We want the whole shift
14973169689Skan     operation.  */
14974169689Skan  if (GET_CODE (early_op) == REG)
14975169689Skan    early_op = op;
14976169689Skan
14977169689Skan  return !reg_overlap_mentioned_p (value, early_op);
14978169689Skan}
14979169689Skan
14980169689Skan/* Return nonzero if the CONSUMER instruction (an ALU op) does not
14981169689Skan   have an early register shift value dependency on the result of
14982169689Skan   PRODUCER.  */
14983169689Skan
14984169689Skanint
14985169689Skanarm_no_early_alu_shift_value_dep (rtx producer, rtx consumer)
14986169689Skan{
14987169689Skan  rtx value = PATTERN (producer);
14988169689Skan  rtx op = PATTERN (consumer);
14989169689Skan  rtx early_op;
14990169689Skan
14991169689Skan  if (GET_CODE (value) == COND_EXEC)
14992169689Skan    value = COND_EXEC_CODE (value);
14993169689Skan  if (GET_CODE (value) == PARALLEL)
14994169689Skan    value = XVECEXP (value, 0, 0);
14995169689Skan  value = XEXP (value, 0);
14996169689Skan  if (GET_CODE (op) == COND_EXEC)
14997169689Skan    op = COND_EXEC_CODE (op);
14998169689Skan  if (GET_CODE (op) == PARALLEL)
14999169689Skan    op = XVECEXP (op, 0, 0);
15000169689Skan  op = XEXP (op, 1);
15001169689Skan
15002169689Skan  early_op = XEXP (op, 0);
15003169689Skan
15004169689Skan  /* This is either an actual independent shift, or a shift applied to
15005169689Skan     the first operand of another operation.  We want the value being
15006169689Skan     shifted, in either case.  */
15007169689Skan  if (GET_CODE (early_op) != REG)
15008169689Skan    early_op = XEXP (early_op, 0);
15009169689Skan
15010169689Skan  return !reg_overlap_mentioned_p (value, early_op);
15011169689Skan}
15012169689Skan
15013169689Skan/* Return nonzero if the CONSUMER (a mul or mac op) does not
15014169689Skan   have an early register mult dependency on the result of
15015169689Skan   PRODUCER.  */
15016169689Skan
15017169689Skanint
15018169689Skanarm_no_early_mul_dep (rtx producer, rtx consumer)
15019169689Skan{
15020169689Skan  rtx value = PATTERN (producer);
15021169689Skan  rtx op = PATTERN (consumer);
15022169689Skan
15023169689Skan  if (GET_CODE (value) == COND_EXEC)
15024169689Skan    value = COND_EXEC_CODE (value);
15025169689Skan  if (GET_CODE (value) == PARALLEL)
15026169689Skan    value = XVECEXP (value, 0, 0);
15027169689Skan  value = XEXP (value, 0);
15028169689Skan  if (GET_CODE (op) == COND_EXEC)
15029169689Skan    op = COND_EXEC_CODE (op);
15030169689Skan  if (GET_CODE (op) == PARALLEL)
15031169689Skan    op = XVECEXP (op, 0, 0);
15032169689Skan  op = XEXP (op, 1);
15033169689Skan
15034169689Skan  return (GET_CODE (op) == PLUS
15035169689Skan	  && !reg_overlap_mentioned_p (value, XEXP (op, 0)));
15036169689Skan}
15037169689Skan
15038169689Skan
15039169689Skan/* We can't rely on the caller doing the proper promotion when
15040169689Skan   using APCS or ATPCS.  */
15041169689Skan
15042169689Skanstatic bool
15043169689Skanarm_promote_prototypes (tree t ATTRIBUTE_UNUSED)
15044169689Skan{
15045169689Skan    return !TARGET_AAPCS_BASED;
15046169689Skan}
15047169689Skan
15048169689Skan
15049169689Skan/* AAPCS based ABIs use short enums by default.  */
15050169689Skan
15051169689Skanstatic bool
15052169689Skanarm_default_short_enums (void)
15053169689Skan{
15054169689Skan  return TARGET_AAPCS_BASED && arm_abi != ARM_ABI_AAPCS_LINUX;
15055169689Skan}
15056169689Skan
15057169689Skan
15058169689Skan/* AAPCS requires that anonymous bitfields affect structure alignment.  */
15059169689Skan
15060169689Skanstatic bool
15061169689Skanarm_align_anon_bitfield (void)
15062169689Skan{
15063169689Skan  return TARGET_AAPCS_BASED;
15064169689Skan}
15065169689Skan
15066169689Skan
15067169689Skan/* The generic C++ ABI says 64-bit (long long).  The EABI says 32-bit.  */
15068169689Skan
15069169689Skanstatic tree
15070169689Skanarm_cxx_guard_type (void)
15071169689Skan{
15072169689Skan  return TARGET_AAPCS_BASED ? integer_type_node : long_long_integer_type_node;
15073169689Skan}
15074169689Skan
15075169689Skan
15076169689Skan/* The EABI says test the least significant bit of a guard variable.  */
15077169689Skan
15078169689Skanstatic bool
15079169689Skanarm_cxx_guard_mask_bit (void)
15080169689Skan{
15081169689Skan  return TARGET_AAPCS_BASED;
15082169689Skan}
15083169689Skan
15084169689Skan
15085169689Skan/* The EABI specifies that all array cookies are 8 bytes long.  */
15086169689Skan
15087169689Skanstatic tree
15088169689Skanarm_get_cookie_size (tree type)
15089169689Skan{
15090169689Skan  tree size;
15091169689Skan
15092169689Skan  if (!TARGET_AAPCS_BASED)
15093169689Skan    return default_cxx_get_cookie_size (type);
15094169689Skan
15095169689Skan  size = build_int_cst (sizetype, 8);
15096169689Skan  return size;
15097169689Skan}
15098169689Skan
15099169689Skan
15100169689Skan/* The EABI says that array cookies should also contain the element size.  */
15101169689Skan
15102169689Skanstatic bool
15103169689Skanarm_cookie_has_size (void)
15104169689Skan{
15105169689Skan  return TARGET_AAPCS_BASED;
15106169689Skan}
15107169689Skan
15108169689Skan
15109169689Skan/* The EABI says constructors and destructors should return a pointer to
15110169689Skan   the object constructed/destroyed.  */
15111169689Skan
15112169689Skanstatic bool
15113169689Skanarm_cxx_cdtor_returns_this (void)
15114169689Skan{
15115169689Skan  return TARGET_AAPCS_BASED;
15116169689Skan}
15117169689Skan
15118169689Skan/* The EABI says that an inline function may never be the key
15119169689Skan   method.  */
15120169689Skan
15121169689Skanstatic bool
15122169689Skanarm_cxx_key_method_may_be_inline (void)
15123169689Skan{
15124169689Skan  return !TARGET_AAPCS_BASED;
15125169689Skan}
15126169689Skan
15127169689Skanstatic void
15128169689Skanarm_cxx_determine_class_data_visibility (tree decl)
15129169689Skan{
15130169689Skan  if (!TARGET_AAPCS_BASED)
15131169689Skan    return;
15132169689Skan
15133169689Skan  /* In general, \S 3.2.5.5 of the ARM EABI requires that class data
15134169689Skan     is exported.  However, on systems without dynamic vague linkage,
15135169689Skan     \S 3.2.5.6 says that COMDAT class data has hidden linkage.  */
15136169689Skan  if (!TARGET_ARM_DYNAMIC_VAGUE_LINKAGE_P && DECL_COMDAT (decl))
15137169689Skan    DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN;
15138169689Skan  else
15139169689Skan    DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
15140169689Skan  DECL_VISIBILITY_SPECIFIED (decl) = 1;
15141169689Skan}
15142169689Skan
15143169689Skanstatic bool
15144169689Skanarm_cxx_class_data_always_comdat (void)
15145169689Skan{
15146169689Skan  /* \S 3.2.5.4 of the ARM C++ ABI says that class data only have
15147169689Skan     vague linkage if the class has no key function.  */
15148169689Skan  return !TARGET_AAPCS_BASED;
15149169689Skan}
15150169689Skan
15151169689Skan
15152169689Skan/* The EABI says __aeabi_atexit should be used to register static
15153169689Skan   destructors.  */
15154169689Skan
15155169689Skanstatic bool
15156169689Skanarm_cxx_use_aeabi_atexit (void)
15157169689Skan{
15158169689Skan  return TARGET_AAPCS_BASED;
15159169689Skan}
15160169689Skan
15161169689Skan
15162169689Skanvoid
15163169689Skanarm_set_return_address (rtx source, rtx scratch)
15164169689Skan{
15165169689Skan  arm_stack_offsets *offsets;
15166169689Skan  HOST_WIDE_INT delta;
15167169689Skan  rtx addr;
15168169689Skan  unsigned long saved_regs;
15169169689Skan
15170169689Skan  saved_regs = arm_compute_save_reg_mask ();
15171169689Skan
15172169689Skan  if ((saved_regs & (1 << LR_REGNUM)) == 0)
15173169689Skan    emit_move_insn (gen_rtx_REG (Pmode, LR_REGNUM), source);
15174169689Skan  else
15175169689Skan    {
15176169689Skan      if (frame_pointer_needed)
15177169689Skan	addr = plus_constant(hard_frame_pointer_rtx, -4);
15178169689Skan      else
15179169689Skan	{
15180169689Skan	  /* LR will be the first saved register.  */
15181169689Skan	  offsets = arm_get_frame_offsets ();
15182169689Skan	  delta = offsets->outgoing_args - (offsets->frame + 4);
15183169689Skan
15184169689Skan
15185169689Skan	  if (delta >= 4096)
15186169689Skan	    {
15187169689Skan	      emit_insn (gen_addsi3 (scratch, stack_pointer_rtx,
15188169689Skan				     GEN_INT (delta & ~4095)));
15189169689Skan	      addr = scratch;
15190169689Skan	      delta &= 4095;
15191169689Skan	    }
15192169689Skan	  else
15193169689Skan	    addr = stack_pointer_rtx;
15194169689Skan
15195169689Skan	  addr = plus_constant (addr, delta);
15196169689Skan	}
15197169689Skan      emit_move_insn (gen_frame_mem (Pmode, addr), source);
15198169689Skan    }
15199169689Skan}
15200169689Skan
15201169689Skan
15202169689Skanvoid
15203169689Skanthumb_set_return_address (rtx source, rtx scratch)
15204169689Skan{
15205169689Skan  arm_stack_offsets *offsets;
15206169689Skan  HOST_WIDE_INT delta;
15207169689Skan  int reg;
15208169689Skan  rtx addr;
15209169689Skan  unsigned long mask;
15210169689Skan
15211169689Skan  emit_insn (gen_rtx_USE (VOIDmode, source));
15212169689Skan
15213169689Skan  mask = thumb_compute_save_reg_mask ();
15214169689Skan  if (mask & (1 << LR_REGNUM))
15215169689Skan    {
15216169689Skan      offsets = arm_get_frame_offsets ();
15217169689Skan
15218169689Skan      /* Find the saved regs.  */
15219169689Skan      if (frame_pointer_needed)
15220169689Skan	{
15221169689Skan	  delta = offsets->soft_frame - offsets->saved_args;
15222169689Skan	  reg = THUMB_HARD_FRAME_POINTER_REGNUM;
15223169689Skan	}
15224169689Skan      else
15225169689Skan	{
15226169689Skan	  delta = offsets->outgoing_args - offsets->saved_args;
15227169689Skan	  reg = SP_REGNUM;
15228169689Skan	}
15229169689Skan      /* Allow for the stack frame.  */
15230169689Skan      if (TARGET_BACKTRACE)
15231169689Skan	delta -= 16;
15232169689Skan      /* The link register is always the first saved register.  */
15233169689Skan      delta -= 4;
15234169689Skan
15235169689Skan      /* Construct the address.  */
15236169689Skan      addr = gen_rtx_REG (SImode, reg);
15237169689Skan      if ((reg != SP_REGNUM && delta >= 128)
15238169689Skan	  || delta >= 1024)
15239169689Skan	{
15240169689Skan	  emit_insn (gen_movsi (scratch, GEN_INT (delta)));
15241169689Skan	  emit_insn (gen_addsi3 (scratch, scratch, stack_pointer_rtx));
15242169689Skan	  addr = scratch;
15243169689Skan	}
15244169689Skan      else
15245169689Skan	addr = plus_constant (addr, delta);
15246169689Skan
15247169689Skan      emit_move_insn (gen_frame_mem (Pmode, addr), source);
15248169689Skan    }
15249169689Skan  else
15250169689Skan    emit_move_insn (gen_rtx_REG (Pmode, LR_REGNUM), source);
15251169689Skan}
15252169689Skan
15253169689Skan/* Implements target hook vector_mode_supported_p.  */
15254169689Skanbool
15255169689Skanarm_vector_mode_supported_p (enum machine_mode mode)
15256169689Skan{
15257169689Skan  if ((mode == V2SImode)
15258169689Skan      || (mode == V4HImode)
15259169689Skan      || (mode == V8QImode))
15260169689Skan    return true;
15261169689Skan
15262169689Skan  return false;
15263169689Skan}
15264169689Skan
15265169689Skan/* Implement TARGET_SHIFT_TRUNCATION_MASK.  SImode shifts use normal
15266169689Skan   ARM insns and therefore guarantee that the shift count is modulo 256.
15267169689Skan   DImode shifts (those implemented by lib1funcs.asm or by optabs.c)
15268169689Skan   guarantee no particular behavior for out-of-range counts.  */
15269169689Skan
15270169689Skanstatic unsigned HOST_WIDE_INT
15271169689Skanarm_shift_truncation_mask (enum machine_mode mode)
15272169689Skan{
15273169689Skan  return mode == SImode ? 255 : 0;
15274169689Skan}
15275169689Skan
15276169689Skan
15277169689Skan/* Map internal gcc register numbers to DWARF2 register numbers.  */
15278169689Skan
15279169689Skanunsigned int
15280169689Skanarm_dbx_register_number (unsigned int regno)
15281169689Skan{
15282169689Skan  if (regno < 16)
15283169689Skan    return regno;
15284169689Skan
15285169689Skan  /* TODO: Legacy targets output FPA regs as registers 16-23 for backwards
15286169689Skan     compatibility.  The EABI defines them as registers 96-103.  */
15287169689Skan  if (IS_FPA_REGNUM (regno))
15288169689Skan    return (TARGET_AAPCS_BASED ? 96 : 16) + regno - FIRST_FPA_REGNUM;
15289169689Skan
15290169689Skan  if (IS_VFP_REGNUM (regno))
15291169689Skan    return 64 + regno - FIRST_VFP_REGNUM;
15292169689Skan
15293169689Skan  if (IS_IWMMXT_GR_REGNUM (regno))
15294169689Skan    return 104 + regno - FIRST_IWMMXT_GR_REGNUM;
15295169689Skan
15296169689Skan  if (IS_IWMMXT_REGNUM (regno))
15297169689Skan    return 112 + regno - FIRST_IWMMXT_REGNUM;
15298169689Skan
15299169689Skan  gcc_unreachable ();
15300169689Skan}
15301169689Skan
15302169689Skan
15303169689Skan#ifdef TARGET_UNWIND_INFO
15304169689Skan/* Emit unwind directives for a store-multiple instruction.  This should
15305169689Skan   only ever be generated by the function prologue code, so we expect it
15306169689Skan   to have a particular form.  */
15307169689Skan
15308169689Skanstatic void
15309169689Skanarm_unwind_emit_stm (FILE * asm_out_file, rtx p)
15310169689Skan{
15311169689Skan  int i;
15312169689Skan  HOST_WIDE_INT offset;
15313169689Skan  HOST_WIDE_INT nregs;
15314169689Skan  int reg_size;
15315169689Skan  unsigned reg;
15316169689Skan  unsigned lastreg;
15317169689Skan  rtx e;
15318169689Skan
15319169689Skan  /* First insn will adjust the stack pointer.  */
15320169689Skan  e = XVECEXP (p, 0, 0);
15321169689Skan  if (GET_CODE (e) != SET
15322169689Skan      || GET_CODE (XEXP (e, 0)) != REG
15323169689Skan      || REGNO (XEXP (e, 0)) != SP_REGNUM
15324169689Skan      || GET_CODE (XEXP (e, 1)) != PLUS)
15325169689Skan    abort ();
15326169689Skan
15327169689Skan  offset = -INTVAL (XEXP (XEXP (e, 1), 1));
15328169689Skan  nregs = XVECLEN (p, 0) - 1;
15329169689Skan
15330169689Skan  reg = REGNO (XEXP (XVECEXP (p, 0, 1), 1));
15331169689Skan  if (reg < 16)
15332169689Skan    {
15333169689Skan      /* The function prologue may also push pc, but not annotate it as it is
15334169689Skan	 never restored.  We turn this into a stack pointer adjustment.  */
15335169689Skan      if (nregs * 4 == offset - 4)
15336169689Skan	{
15337169689Skan	  fprintf (asm_out_file, "\t.pad #4\n");
15338169689Skan	  offset -= 4;
15339169689Skan	}
15340169689Skan      reg_size = 4;
15341169689Skan    }
15342169689Skan  else if (IS_VFP_REGNUM (reg))
15343169689Skan    {
15344169689Skan      /* FPA register saves use an additional word.  */
15345169689Skan      offset -= 4;
15346169689Skan      reg_size = 8;
15347169689Skan    }
15348169689Skan  else if (reg >= FIRST_FPA_REGNUM && reg <= LAST_FPA_REGNUM)
15349169689Skan    {
15350169689Skan      /* FPA registers are done differently.  */
15351169689Skan      asm_fprintf (asm_out_file, "\t.save %r, %wd\n", reg, nregs);
15352169689Skan      return;
15353169689Skan    }
15354169689Skan  else
15355169689Skan    /* Unknown register type.  */
15356169689Skan    abort ();
15357169689Skan
15358169689Skan  /* If the stack increment doesn't match the size of the saved registers,
15359169689Skan     something has gone horribly wrong.  */
15360169689Skan  if (offset != nregs * reg_size)
15361169689Skan    abort ();
15362169689Skan
15363169689Skan  fprintf (asm_out_file, "\t.save {");
15364169689Skan
15365169689Skan  offset = 0;
15366169689Skan  lastreg = 0;
15367169689Skan  /* The remaining insns will describe the stores.  */
15368169689Skan  for (i = 1; i <= nregs; i++)
15369169689Skan    {
15370169689Skan      /* Expect (set (mem <addr>) (reg)).
15371169689Skan         Where <addr> is (reg:SP) or (plus (reg:SP) (const_int)).  */
15372169689Skan      e = XVECEXP (p, 0, i);
15373169689Skan      if (GET_CODE (e) != SET
15374169689Skan	  || GET_CODE (XEXP (e, 0)) != MEM
15375169689Skan	  || GET_CODE (XEXP (e, 1)) != REG)
15376169689Skan	abort ();
15377169689Skan
15378169689Skan      reg = REGNO (XEXP (e, 1));
15379169689Skan      if (reg < lastreg)
15380169689Skan	abort ();
15381169689Skan
15382169689Skan      if (i != 1)
15383169689Skan	fprintf (asm_out_file, ", ");
15384169689Skan      /* We can't use %r for vfp because we need to use the
15385169689Skan	 double precision register names.  */
15386169689Skan      if (IS_VFP_REGNUM (reg))
15387169689Skan	asm_fprintf (asm_out_file, "d%d", (reg - FIRST_VFP_REGNUM) / 2);
15388169689Skan      else
15389169689Skan	asm_fprintf (asm_out_file, "%r", reg);
15390169689Skan
15391169689Skan#ifdef ENABLE_CHECKING
15392169689Skan      /* Check that the addresses are consecutive.  */
15393169689Skan      e = XEXP (XEXP (e, 0), 0);
15394169689Skan      if (GET_CODE (e) == PLUS)
15395169689Skan	{
15396169689Skan	  offset += reg_size;
15397169689Skan	  if (GET_CODE (XEXP (e, 0)) != REG
15398169689Skan	      || REGNO (XEXP (e, 0)) != SP_REGNUM
15399169689Skan	      || GET_CODE (XEXP (e, 1)) != CONST_INT
15400169689Skan	      || offset != INTVAL (XEXP (e, 1)))
15401169689Skan	    abort ();
15402169689Skan	}
15403169689Skan      else if (i != 1
15404169689Skan	       || GET_CODE (e) != REG
15405169689Skan	       || REGNO (e) != SP_REGNUM)
15406169689Skan	abort ();
15407169689Skan#endif
15408169689Skan    }
15409169689Skan  fprintf (asm_out_file, "}\n");
15410169689Skan}
15411169689Skan
15412169689Skan/*  Emit unwind directives for a SET.  */
15413169689Skan
15414169689Skanstatic void
15415169689Skanarm_unwind_emit_set (FILE * asm_out_file, rtx p)
15416169689Skan{
15417169689Skan  rtx e0;
15418169689Skan  rtx e1;
15419169689Skan
15420169689Skan  e0 = XEXP (p, 0);
15421169689Skan  e1 = XEXP (p, 1);
15422169689Skan  switch (GET_CODE (e0))
15423169689Skan    {
15424169689Skan    case MEM:
15425169689Skan      /* Pushing a single register.  */
15426169689Skan      if (GET_CODE (XEXP (e0, 0)) != PRE_DEC
15427169689Skan	  || GET_CODE (XEXP (XEXP (e0, 0), 0)) != REG
15428169689Skan	  || REGNO (XEXP (XEXP (e0, 0), 0)) != SP_REGNUM)
15429169689Skan	abort ();
15430169689Skan
15431169689Skan      asm_fprintf (asm_out_file, "\t.save ");
15432169689Skan      if (IS_VFP_REGNUM (REGNO (e1)))
15433169689Skan	asm_fprintf(asm_out_file, "{d%d}\n",
15434169689Skan		    (REGNO (e1) - FIRST_VFP_REGNUM) / 2);
15435169689Skan      else
15436169689Skan	asm_fprintf(asm_out_file, "{%r}\n", REGNO (e1));
15437169689Skan      break;
15438169689Skan
15439169689Skan    case REG:
15440169689Skan      if (REGNO (e0) == SP_REGNUM)
15441169689Skan	{
15442169689Skan	  /* A stack increment.  */
15443169689Skan	  if (GET_CODE (e1) != PLUS
15444169689Skan	      || GET_CODE (XEXP (e1, 0)) != REG
15445169689Skan	      || REGNO (XEXP (e1, 0)) != SP_REGNUM
15446169689Skan	      || GET_CODE (XEXP (e1, 1)) != CONST_INT)
15447169689Skan	    abort ();
15448169689Skan
15449169689Skan	  asm_fprintf (asm_out_file, "\t.pad #%wd\n",
15450169689Skan		       -INTVAL (XEXP (e1, 1)));
15451169689Skan	}
15452169689Skan      else if (REGNO (e0) == HARD_FRAME_POINTER_REGNUM)
15453169689Skan	{
15454169689Skan	  HOST_WIDE_INT offset;
15455169689Skan	  unsigned reg;
15456169689Skan
15457169689Skan	  if (GET_CODE (e1) == PLUS)
15458169689Skan	    {
15459169689Skan	      if (GET_CODE (XEXP (e1, 0)) != REG
15460169689Skan		  || GET_CODE (XEXP (e1, 1)) != CONST_INT)
15461169689Skan		abort ();
15462169689Skan	      reg = REGNO (XEXP (e1, 0));
15463169689Skan	      offset = INTVAL (XEXP (e1, 1));
15464169689Skan	      asm_fprintf (asm_out_file, "\t.setfp %r, %r, #%wd\n",
15465169689Skan			   HARD_FRAME_POINTER_REGNUM, reg,
15466169689Skan			   INTVAL (XEXP (e1, 1)));
15467169689Skan	    }
15468169689Skan	  else if (GET_CODE (e1) == REG)
15469169689Skan	    {
15470169689Skan	      reg = REGNO (e1);
15471169689Skan	      asm_fprintf (asm_out_file, "\t.setfp %r, %r\n",
15472169689Skan			   HARD_FRAME_POINTER_REGNUM, reg);
15473169689Skan	    }
15474169689Skan	  else
15475169689Skan	    abort ();
15476169689Skan	}
15477169689Skan      else if (GET_CODE (e1) == REG && REGNO (e1) == SP_REGNUM)
15478169689Skan	{
15479169689Skan	  /* Move from sp to reg.  */
15480169689Skan	  asm_fprintf (asm_out_file, "\t.movsp %r\n", REGNO (e0));
15481169689Skan	}
15482169689Skan     else if (GET_CODE (e1) == PLUS
15483169689Skan	      && GET_CODE (XEXP (e1, 0)) == REG
15484169689Skan	      && REGNO (XEXP (e1, 0)) == SP_REGNUM
15485169689Skan	      && GET_CODE (XEXP (e1, 1)) == CONST_INT)
15486169689Skan	{
15487169689Skan	  /* Set reg to offset from sp.  */
15488169689Skan	  asm_fprintf (asm_out_file, "\t.movsp %r, #%d\n",
15489169689Skan		       REGNO (e0), (int)INTVAL(XEXP (e1, 1)));
15490169689Skan	}
15491169689Skan      else
15492169689Skan	abort ();
15493169689Skan      break;
15494169689Skan
15495169689Skan    default:
15496169689Skan      abort ();
15497169689Skan    }
15498169689Skan}
15499169689Skan
15500169689Skan
15501169689Skan/* Emit unwind directives for the given insn.  */
15502169689Skan
15503169689Skanstatic void
15504169689Skanarm_unwind_emit (FILE * asm_out_file, rtx insn)
15505169689Skan{
15506169689Skan  rtx pat;
15507169689Skan
15508169689Skan  if (!ARM_EABI_UNWIND_TABLES)
15509169689Skan    return;
15510169689Skan
15511169689Skan  if (GET_CODE (insn) == NOTE || !RTX_FRAME_RELATED_P (insn))
15512169689Skan    return;
15513169689Skan
15514169689Skan  pat = find_reg_note (insn, REG_FRAME_RELATED_EXPR, NULL_RTX);
15515169689Skan  if (pat)
15516169689Skan    pat = XEXP (pat, 0);
15517169689Skan  else
15518169689Skan    pat = PATTERN (insn);
15519169689Skan
15520169689Skan  switch (GET_CODE (pat))
15521169689Skan    {
15522169689Skan    case SET:
15523169689Skan      arm_unwind_emit_set (asm_out_file, pat);
15524169689Skan      break;
15525169689Skan
15526169689Skan    case SEQUENCE:
15527169689Skan      /* Store multiple.  */
15528169689Skan      arm_unwind_emit_stm (asm_out_file, pat);
15529169689Skan      break;
15530169689Skan
15531169689Skan    default:
15532169689Skan      abort();
15533169689Skan    }
15534169689Skan}
15535169689Skan
15536169689Skan
15537169689Skan/* Output a reference from a function exception table to the type_info
15538169689Skan   object X.  The EABI specifies that the symbol should be relocated by
15539169689Skan   an R_ARM_TARGET2 relocation.  */
15540169689Skan
15541169689Skanstatic bool
15542169689Skanarm_output_ttype (rtx x)
15543169689Skan{
15544169689Skan  fputs ("\t.word\t", asm_out_file);
15545169689Skan  output_addr_const (asm_out_file, x);
15546169689Skan  /* Use special relocations for symbol references.  */
15547169689Skan  if (GET_CODE (x) != CONST_INT)
15548169689Skan    fputs ("(TARGET2)", asm_out_file);
15549169689Skan  fputc ('\n', asm_out_file);
15550169689Skan
15551169689Skan  return TRUE;
15552169689Skan}
15553169689Skan#endif /* TARGET_UNWIND_INFO */
15554169689Skan
15555169689Skan
15556169689Skan/* Output unwind directives for the start/end of a function.  */
15557169689Skan
15558169689Skanvoid
15559169689Skanarm_output_fn_unwind (FILE * f, bool prologue)
15560169689Skan{
15561169689Skan  if (!ARM_EABI_UNWIND_TABLES)
15562169689Skan    return;
15563169689Skan
15564169689Skan  if (prologue)
15565169689Skan    fputs ("\t.fnstart\n", f);
15566169689Skan  else
15567169689Skan    fputs ("\t.fnend\n", f);
15568169689Skan}
15569169689Skan
15570169689Skanstatic bool
15571169689Skanarm_emit_tls_decoration (FILE *fp, rtx x)
15572169689Skan{
15573169689Skan  enum tls_reloc reloc;
15574169689Skan  rtx val;
15575169689Skan
15576169689Skan  val = XVECEXP (x, 0, 0);
15577169689Skan  reloc = INTVAL (XVECEXP (x, 0, 1));
15578169689Skan
15579169689Skan  output_addr_const (fp, val);
15580169689Skan
15581169689Skan  switch (reloc)
15582169689Skan    {
15583169689Skan    case TLS_GD32:
15584169689Skan      fputs ("(tlsgd)", fp);
15585169689Skan      break;
15586169689Skan    case TLS_LDM32:
15587169689Skan      fputs ("(tlsldm)", fp);
15588169689Skan      break;
15589169689Skan    case TLS_LDO32:
15590169689Skan      fputs ("(tlsldo)", fp);
15591169689Skan      break;
15592169689Skan    case TLS_IE32:
15593169689Skan      fputs ("(gottpoff)", fp);
15594169689Skan      break;
15595169689Skan    case TLS_LE32:
15596169689Skan      fputs ("(tpoff)", fp);
15597169689Skan      break;
15598169689Skan    default:
15599169689Skan      gcc_unreachable ();
15600169689Skan    }
15601169689Skan
15602169689Skan  switch (reloc)
15603169689Skan    {
15604169689Skan    case TLS_GD32:
15605169689Skan    case TLS_LDM32:
15606169689Skan    case TLS_IE32:
15607169689Skan      fputs (" + (. - ", fp);
15608169689Skan      output_addr_const (fp, XVECEXP (x, 0, 2));
15609169689Skan      fputs (" - ", fp);
15610169689Skan      output_addr_const (fp, XVECEXP (x, 0, 3));
15611169689Skan      fputc (')', fp);
15612169689Skan      break;
15613169689Skan    default:
15614169689Skan      break;
15615169689Skan    }
15616169689Skan
15617169689Skan  return TRUE;
15618169689Skan}
15619169689Skan
15620169689Skanbool
15621169689Skanarm_output_addr_const_extra (FILE *fp, rtx x)
15622169689Skan{
15623169689Skan  if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLS)
15624169689Skan    return arm_emit_tls_decoration (fp, x);
15625169689Skan  else if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_PIC_LABEL)
15626169689Skan    {
15627169689Skan      char label[256];
15628169689Skan      int labelno = INTVAL (XVECEXP (x, 0, 0));
15629169689Skan
15630169689Skan      ASM_GENERATE_INTERNAL_LABEL (label, "LPIC", labelno);
15631169689Skan      assemble_name_raw (fp, label);
15632169689Skan
15633169689Skan      return TRUE;
15634169689Skan    }
15635169689Skan  else if (GET_CODE (x) == CONST_VECTOR)
15636169689Skan    return arm_emit_vector_const (fp, x);
15637169689Skan
15638169689Skan  return FALSE;
15639169689Skan}
15640169689Skan
15641169689Skan#include "gt-arm.h"
15642