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);
157260456Spfgstatic void arm_file_start (void);
158169689Skan
159117395Skan#ifdef AOF_ASSEMBLER
160132718Skanstatic void aof_globalize_label (FILE *, const char *);
161132718Skanstatic void aof_dump_imports (FILE *);
162132718Skanstatic void aof_dump_pic_table (FILE *);
163132718Skanstatic void aof_file_start (void);
164132718Skanstatic void aof_file_end (void);
165169689Skanstatic void aof_asm_init_sections (void);
166117395Skan#endif
167169689Skanstatic void arm_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode,
168169689Skan					tree, int *, int);
169169689Skanstatic bool arm_pass_by_reference (CUMULATIVE_ARGS *,
170169689Skan				   enum machine_mode, tree, bool);
171169689Skanstatic bool arm_promote_prototypes (tree);
172169689Skanstatic bool arm_default_short_enums (void);
173169689Skanstatic bool arm_align_anon_bitfield (void);
174169689Skanstatic bool arm_return_in_msb (tree);
175169689Skanstatic bool arm_must_pass_in_stack (enum machine_mode, tree);
176169689Skan#ifdef TARGET_UNWIND_INFO
177169689Skanstatic void arm_unwind_emit (FILE *, rtx);
178169689Skanstatic bool arm_output_ttype (rtx);
179169689Skan#endif
18090075Sobrien
181169689Skanstatic tree arm_cxx_guard_type (void);
182169689Skanstatic bool arm_cxx_guard_mask_bit (void);
183169689Skanstatic tree arm_get_cookie_size (tree);
184169689Skanstatic bool arm_cookie_has_size (void);
185169689Skanstatic bool arm_cxx_cdtor_returns_this (void);
186169689Skanstatic bool arm_cxx_key_method_may_be_inline (void);
187169689Skanstatic void arm_cxx_determine_class_data_visibility (tree);
188169689Skanstatic bool arm_cxx_class_data_always_comdat (void);
189169689Skanstatic bool arm_cxx_use_aeabi_atexit (void);
190169689Skanstatic void arm_init_libfuncs (void);
191169689Skanstatic bool arm_handle_option (size_t, const char *, int);
192169689Skanstatic unsigned HOST_WIDE_INT arm_shift_truncation_mask (enum machine_mode);
193169689Skanstatic bool arm_cannot_copy_insn_p (rtx);
194169689Skanstatic bool arm_tls_symbol_p (rtx x);
195169689Skan
19690075Sobrien
19790075Sobrien/* Initialize the GCC target structure.  */
198169689Skan#if TARGET_DLLIMPORT_DECL_ATTRIBUTES
19990075Sobrien#undef  TARGET_MERGE_DECL_ATTRIBUTES
20090075Sobrien#define TARGET_MERGE_DECL_ATTRIBUTES merge_dllimport_decl_attributes
20190075Sobrien#endif
20290075Sobrien
20390075Sobrien#undef  TARGET_ATTRIBUTE_TABLE
20490075Sobrien#define TARGET_ATTRIBUTE_TABLE arm_attribute_table
20590075Sobrien
206260456Spfg#undef TARGET_ASM_FILE_START
207260456Spfg#define TARGET_ASM_FILE_START arm_file_start
208260456Spfg
209169689Skan#undef TARGET_ASM_FILE_END
210169689Skan#define TARGET_ASM_FILE_END arm_file_end
211169689Skan
21290075Sobrien#ifdef AOF_ASSEMBLER
21390075Sobrien#undef  TARGET_ASM_BYTE_OP
21490075Sobrien#define TARGET_ASM_BYTE_OP "\tDCB\t"
21590075Sobrien#undef  TARGET_ASM_ALIGNED_HI_OP
21690075Sobrien#define TARGET_ASM_ALIGNED_HI_OP "\tDCW\t"
21790075Sobrien#undef  TARGET_ASM_ALIGNED_SI_OP
21890075Sobrien#define TARGET_ASM_ALIGNED_SI_OP "\tDCD\t"
219117395Skan#undef TARGET_ASM_GLOBALIZE_LABEL
220117395Skan#define TARGET_ASM_GLOBALIZE_LABEL aof_globalize_label
221132718Skan#undef TARGET_ASM_FILE_START
222132718Skan#define TARGET_ASM_FILE_START aof_file_start
223132718Skan#undef TARGET_ASM_FILE_END
224132718Skan#define TARGET_ASM_FILE_END aof_file_end
22590075Sobrien#else
22690075Sobrien#undef  TARGET_ASM_ALIGNED_SI_OP
22790075Sobrien#define TARGET_ASM_ALIGNED_SI_OP NULL
22890075Sobrien#undef  TARGET_ASM_INTEGER
22990075Sobrien#define TARGET_ASM_INTEGER arm_assemble_integer
23090075Sobrien#endif
23190075Sobrien
23290075Sobrien#undef  TARGET_ASM_FUNCTION_PROLOGUE
23390075Sobrien#define TARGET_ASM_FUNCTION_PROLOGUE arm_output_function_prologue
23490075Sobrien
23590075Sobrien#undef  TARGET_ASM_FUNCTION_EPILOGUE
23690075Sobrien#define TARGET_ASM_FUNCTION_EPILOGUE arm_output_function_epilogue
23790075Sobrien
238169689Skan#undef  TARGET_DEFAULT_TARGET_FLAGS
239169689Skan#define TARGET_DEFAULT_TARGET_FLAGS (TARGET_DEFAULT | MASK_SCHED_PROLOG)
240169689Skan#undef  TARGET_HANDLE_OPTION
241169689Skan#define TARGET_HANDLE_OPTION arm_handle_option
242169689Skan
24390075Sobrien#undef  TARGET_COMP_TYPE_ATTRIBUTES
24490075Sobrien#define TARGET_COMP_TYPE_ATTRIBUTES arm_comp_type_attributes
24590075Sobrien
24690075Sobrien#undef  TARGET_SET_DEFAULT_TYPE_ATTRIBUTES
24790075Sobrien#define TARGET_SET_DEFAULT_TYPE_ATTRIBUTES arm_set_default_type_attributes
24890075Sobrien
24990075Sobrien#undef  TARGET_SCHED_ADJUST_COST
25090075Sobrien#define TARGET_SCHED_ADJUST_COST arm_adjust_cost
25190075Sobrien
252117395Skan#undef TARGET_ENCODE_SECTION_INFO
253117395Skan#ifdef ARM_PE
254117395Skan#define TARGET_ENCODE_SECTION_INFO  arm_pe_encode_section_info
255117395Skan#else
256117395Skan#define TARGET_ENCODE_SECTION_INFO  arm_encode_section_info
257117395Skan#endif
258117395Skan
259132718Skan#undef  TARGET_STRIP_NAME_ENCODING
260117395Skan#define TARGET_STRIP_NAME_ENCODING arm_strip_name_encoding
261117395Skan
262132718Skan#undef  TARGET_ASM_INTERNAL_LABEL
263132718Skan#define TARGET_ASM_INTERNAL_LABEL arm_internal_label
264132718Skan
265132718Skan#undef  TARGET_FUNCTION_OK_FOR_SIBCALL
266132718Skan#define TARGET_FUNCTION_OK_FOR_SIBCALL arm_function_ok_for_sibcall
267132718Skan
268132718Skan#undef  TARGET_ASM_OUTPUT_MI_THUNK
269117395Skan#define TARGET_ASM_OUTPUT_MI_THUNK arm_output_mi_thunk
270132718Skan#undef  TARGET_ASM_CAN_OUTPUT_MI_THUNK
271117395Skan#define TARGET_ASM_CAN_OUTPUT_MI_THUNK default_can_output_mi_thunk_no_vcall
272117395Skan
273169689Skan/* This will be overridden in arm_override_options.  */
274132718Skan#undef  TARGET_RTX_COSTS
275169689Skan#define TARGET_RTX_COSTS arm_slowmul_rtx_costs
276132718Skan#undef  TARGET_ADDRESS_COST
277132718Skan#define TARGET_ADDRESS_COST arm_address_cost
278132718Skan
279169689Skan#undef TARGET_SHIFT_TRUNCATION_MASK
280169689Skan#define TARGET_SHIFT_TRUNCATION_MASK arm_shift_truncation_mask
281169689Skan#undef TARGET_VECTOR_MODE_SUPPORTED_P
282169689Skan#define TARGET_VECTOR_MODE_SUPPORTED_P arm_vector_mode_supported_p
283169689Skan
284132718Skan#undef  TARGET_MACHINE_DEPENDENT_REORG
285132718Skan#define TARGET_MACHINE_DEPENDENT_REORG arm_reorg
286132718Skan
287132718Skan#undef  TARGET_INIT_BUILTINS
288132718Skan#define TARGET_INIT_BUILTINS  arm_init_builtins
289132718Skan#undef  TARGET_EXPAND_BUILTIN
290132718Skan#define TARGET_EXPAND_BUILTIN arm_expand_builtin
291132718Skan
292169689Skan#undef TARGET_INIT_LIBFUNCS
293169689Skan#define TARGET_INIT_LIBFUNCS arm_init_libfuncs
294169689Skan
295169689Skan#undef TARGET_PROMOTE_FUNCTION_ARGS
296169689Skan#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true
297169689Skan#undef TARGET_PROMOTE_FUNCTION_RETURN
298169689Skan#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
299169689Skan#undef TARGET_PROMOTE_PROTOTYPES
300169689Skan#define TARGET_PROMOTE_PROTOTYPES arm_promote_prototypes
301169689Skan#undef TARGET_PASS_BY_REFERENCE
302169689Skan#define TARGET_PASS_BY_REFERENCE arm_pass_by_reference
303169689Skan#undef TARGET_ARG_PARTIAL_BYTES
304169689Skan#define TARGET_ARG_PARTIAL_BYTES arm_arg_partial_bytes
305169689Skan
306169689Skan#undef  TARGET_SETUP_INCOMING_VARARGS
307169689Skan#define TARGET_SETUP_INCOMING_VARARGS arm_setup_incoming_varargs
308169689Skan
309169689Skan#undef TARGET_DEFAULT_SHORT_ENUMS
310169689Skan#define TARGET_DEFAULT_SHORT_ENUMS arm_default_short_enums
311169689Skan
312169689Skan#undef TARGET_ALIGN_ANON_BITFIELD
313169689Skan#define TARGET_ALIGN_ANON_BITFIELD arm_align_anon_bitfield
314169689Skan
315169689Skan#undef TARGET_NARROW_VOLATILE_BITFIELD
316169689Skan#define TARGET_NARROW_VOLATILE_BITFIELD hook_bool_void_false
317169689Skan
318169689Skan#undef TARGET_CXX_GUARD_TYPE
319169689Skan#define TARGET_CXX_GUARD_TYPE arm_cxx_guard_type
320169689Skan
321169689Skan#undef TARGET_CXX_GUARD_MASK_BIT
322169689Skan#define TARGET_CXX_GUARD_MASK_BIT arm_cxx_guard_mask_bit
323169689Skan
324169689Skan#undef TARGET_CXX_GET_COOKIE_SIZE
325169689Skan#define TARGET_CXX_GET_COOKIE_SIZE arm_get_cookie_size
326169689Skan
327169689Skan#undef TARGET_CXX_COOKIE_HAS_SIZE
328169689Skan#define TARGET_CXX_COOKIE_HAS_SIZE arm_cookie_has_size
329169689Skan
330169689Skan#undef TARGET_CXX_CDTOR_RETURNS_THIS
331169689Skan#define TARGET_CXX_CDTOR_RETURNS_THIS arm_cxx_cdtor_returns_this
332169689Skan
333169689Skan#undef TARGET_CXX_KEY_METHOD_MAY_BE_INLINE
334169689Skan#define TARGET_CXX_KEY_METHOD_MAY_BE_INLINE arm_cxx_key_method_may_be_inline
335169689Skan
336169689Skan#undef TARGET_CXX_USE_AEABI_ATEXIT
337169689Skan#define TARGET_CXX_USE_AEABI_ATEXIT arm_cxx_use_aeabi_atexit
338169689Skan
339169689Skan#undef TARGET_CXX_DETERMINE_CLASS_DATA_VISIBILITY
340169689Skan#define TARGET_CXX_DETERMINE_CLASS_DATA_VISIBILITY \
341169689Skan  arm_cxx_determine_class_data_visibility
342169689Skan
343169689Skan#undef TARGET_CXX_CLASS_DATA_ALWAYS_COMDAT
344169689Skan#define TARGET_CXX_CLASS_DATA_ALWAYS_COMDAT arm_cxx_class_data_always_comdat
345169689Skan
346169689Skan#undef TARGET_RETURN_IN_MSB
347169689Skan#define TARGET_RETURN_IN_MSB arm_return_in_msb
348169689Skan
349169689Skan#undef TARGET_MUST_PASS_IN_STACK
350169689Skan#define TARGET_MUST_PASS_IN_STACK arm_must_pass_in_stack
351169689Skan
352169689Skan#ifdef TARGET_UNWIND_INFO
353169689Skan#undef TARGET_UNWIND_EMIT
354169689Skan#define TARGET_UNWIND_EMIT arm_unwind_emit
355169689Skan
356169689Skan/* EABI unwinding tables use a different format for the typeinfo tables.  */
357169689Skan#undef TARGET_ASM_TTYPE
358169689Skan#define TARGET_ASM_TTYPE arm_output_ttype
359169689Skan
360169689Skan#undef TARGET_ARM_EABI_UNWINDER
361169689Skan#define TARGET_ARM_EABI_UNWINDER true
362169689Skan#endif /* TARGET_UNWIND_INFO */
363169689Skan
364169689Skan#undef  TARGET_CANNOT_COPY_INSN_P
365169689Skan#define TARGET_CANNOT_COPY_INSN_P arm_cannot_copy_insn_p
366169689Skan
367169689Skan#ifdef HAVE_AS_TLS
368169689Skan#undef TARGET_HAVE_TLS
369169689Skan#define TARGET_HAVE_TLS true
370169689Skan#endif
371169689Skan
372169689Skan#undef TARGET_CANNOT_FORCE_CONST_MEM
373169689Skan#define TARGET_CANNOT_FORCE_CONST_MEM arm_tls_referenced_p
374169689Skan
37590075Sobrienstruct gcc_target targetm = TARGET_INITIALIZER;
37690075Sobrien
37790075Sobrien/* Obstack for minipool constant handling.  */
37890075Sobrienstatic struct obstack minipool_obstack;
37990075Sobrienstatic char *         minipool_startobj;
38090075Sobrien
38190075Sobrien/* The maximum number of insns skipped which
38290075Sobrien   will be conditionalised if possible.  */
38390075Sobrienstatic int max_insns_skipped = 5;
38490075Sobrien
38590075Sobrienextern FILE * asm_out_file;
38690075Sobrien
38790075Sobrien/* True if we are currently building a constant table.  */
38890075Sobrienint making_const_table;
38990075Sobrien
39090075Sobrien/* Define the information needed to generate branch insns.  This is
39190075Sobrien   stored from the compare operation.  */
39290075Sobrienrtx arm_compare_op0, arm_compare_op1;
39390075Sobrien
394169689Skan/* The processor for which instructions should be scheduled.  */
395169689Skanenum processor_type arm_tune = arm_none;
39690075Sobrien
397260456Spfg/* The default processor used if not overriden by commandline.  */
398260456Spfgstatic enum processor_type arm_default_cpu = arm_none;
399260456Spfg
400169689Skan/* Which floating point model to use.  */
401169689Skanenum arm_fp_model arm_fp_model;
402169689Skan
403169689Skan/* Which floating point hardware is available.  */
404132718Skanenum fputype arm_fpu_arch;
40590075Sobrien
406169689Skan/* Which floating point hardware to schedule for.  */
407169689Skanenum fputype arm_fpu_tune;
40890075Sobrien
409169689Skan/* Whether to use floating point hardware.  */
410169689Skanenum float_abi_type arm_float_abi;
41190075Sobrien
412169689Skan/* Which ABI to use.  */
413169689Skanenum arm_abi_type arm_abi;
414169689Skan
415169689Skan/* Which thread pointer model to use.  */
416169689Skanenum arm_tp_type target_thread_pointer = TP_AUTO;
417169689Skan
41890075Sobrien/* Used to parse -mstructure_size_boundary command line option.  */
41990075Sobrienint    arm_structure_size_boundary = DEFAULT_STRUCTURE_SIZE_BOUNDARY;
42090075Sobrien
421169689Skan/* Used for Thumb call_via trampolines.  */
422169689Skanrtx thumb_call_via_label[14];
423169689Skanstatic int thumb_call_reg_needed;
424169689Skan
42590075Sobrien/* Bit values used to identify processor capabilities.  */
42690075Sobrien#define FL_CO_PROC    (1 << 0)        /* Has external co-processor bus */
427169689Skan#define FL_ARCH3M     (1 << 1)        /* Extended multiply */
42890075Sobrien#define FL_MODE26     (1 << 2)        /* 26-bit mode support */
42990075Sobrien#define FL_MODE32     (1 << 3)        /* 32-bit mode support */
43090075Sobrien#define FL_ARCH4      (1 << 4)        /* Architecture rel 4 */
43190075Sobrien#define FL_ARCH5      (1 << 5)        /* Architecture rel 5 */
43290075Sobrien#define FL_THUMB      (1 << 6)        /* Thumb aware */
43390075Sobrien#define FL_LDSCHED    (1 << 7)	      /* Load scheduling necessary */
43490075Sobrien#define FL_STRONG     (1 << 8)	      /* StrongARM */
435132718Skan#define FL_ARCH5E     (1 << 9)        /* DSP extensions to v5 */
43690075Sobrien#define FL_XSCALE     (1 << 10)	      /* XScale */
437132718Skan#define FL_CIRRUS     (1 << 11)	      /* Cirrus/DSP.  */
438169689Skan#define FL_ARCH6      (1 << 12)       /* Architecture rel 6.  Adds
439132718Skan					 media instructions.  */
440132718Skan#define FL_VFPV2      (1 << 13)       /* Vector Floating Point V2.  */
441169689Skan#define FL_WBUF	      (1 << 14)	      /* Schedule for write buffer ops.
442169689Skan					 Note: ARM6 & 7 derivatives only.  */
443169689Skan#define FL_ARCH6K     (1 << 15)       /* Architecture rel 6 K extensions.  */
44490075Sobrien
445169689Skan#define FL_IWMMXT     (1 << 29)	      /* XScale v2 or "Intel Wireless MMX technology".  */
446169689Skan
447169689Skan#define FL_FOR_ARCH2	0
448169689Skan#define FL_FOR_ARCH3	FL_MODE32
449169689Skan#define FL_FOR_ARCH3M	(FL_FOR_ARCH3 | FL_ARCH3M)
450169689Skan#define FL_FOR_ARCH4	(FL_FOR_ARCH3M | FL_ARCH4)
451169689Skan#define FL_FOR_ARCH4T	(FL_FOR_ARCH4 | FL_THUMB)
452169689Skan#define FL_FOR_ARCH5	(FL_FOR_ARCH4 | FL_ARCH5)
453169689Skan#define FL_FOR_ARCH5T	(FL_FOR_ARCH5 | FL_THUMB)
454169689Skan#define FL_FOR_ARCH5E	(FL_FOR_ARCH5 | FL_ARCH5E)
455169689Skan#define FL_FOR_ARCH5TE	(FL_FOR_ARCH5E | FL_THUMB)
456169689Skan#define FL_FOR_ARCH5TEJ	FL_FOR_ARCH5TE
457169689Skan#define FL_FOR_ARCH6	(FL_FOR_ARCH5TE | FL_ARCH6)
458169689Skan#define FL_FOR_ARCH6J	FL_FOR_ARCH6
459169689Skan#define FL_FOR_ARCH6K	(FL_FOR_ARCH6 | FL_ARCH6K)
460169689Skan#define FL_FOR_ARCH6Z	FL_FOR_ARCH6
461169689Skan#define FL_FOR_ARCH6ZK	FL_FOR_ARCH6K
462169689Skan
46390075Sobrien/* The bits in this mask specify which
46490075Sobrien   instructions we are allowed to generate.  */
465117395Skanstatic unsigned long insn_flags = 0;
46690075Sobrien
46790075Sobrien/* The bits in this mask specify which instruction scheduling options should
468169689Skan   be used.  */
469117395Skanstatic unsigned long tune_flags = 0;
47090075Sobrien
47190075Sobrien/* The following are used in the arm.md file as equivalents to bits
47290075Sobrien   in the above two flag variables.  */
47390075Sobrien
474169689Skan/* Nonzero if this chip supports the ARM Architecture 3M extensions.  */
475169689Skanint arm_arch3m = 0;
47690075Sobrien
47790075Sobrien/* Nonzero if this chip supports the ARM Architecture 4 extensions.  */
47890075Sobrienint arm_arch4 = 0;
47990075Sobrien
480169689Skan/* Nonzero if this chip supports the ARM Architecture 4t extensions.  */
481169689Skanint arm_arch4t = 0;
482169689Skan
48390075Sobrien/* Nonzero if this chip supports the ARM Architecture 5 extensions.  */
48490075Sobrienint arm_arch5 = 0;
48590075Sobrien
48690075Sobrien/* Nonzero if this chip supports the ARM Architecture 5E extensions.  */
48790075Sobrienint arm_arch5e = 0;
48890075Sobrien
489169689Skan/* Nonzero if this chip supports the ARM Architecture 6 extensions.  */
490169689Skanint arm_arch6 = 0;
491169689Skan
492169689Skan/* Nonzero if this chip supports the ARM 6K extensions.  */
493169689Skanint arm_arch6k = 0;
494169689Skan
49590075Sobrien/* Nonzero if this chip can benefit from load scheduling.  */
49690075Sobrienint arm_ld_sched = 0;
49790075Sobrien
49890075Sobrien/* Nonzero if this chip is a StrongARM.  */
499169689Skanint arm_tune_strongarm = 0;
50090075Sobrien
501169689Skan/* Nonzero if this chip is a Cirrus variant.  */
502169689Skanint arm_arch_cirrus = 0;
503169689Skan
504132718Skan/* Nonzero if this chip supports Intel Wireless MMX technology.  */
505132718Skanint arm_arch_iwmmxt = 0;
506132718Skan
50790075Sobrien/* Nonzero if this chip is an XScale.  */
508132718Skanint arm_arch_xscale = 0;
50990075Sobrien
510132718Skan/* Nonzero if tuning for XScale  */
511132718Skanint arm_tune_xscale = 0;
512132718Skan
513169689Skan/* Nonzero if we want to tune for stores that access the write-buffer.
514169689Skan   This typically means an ARM6 or ARM7 with MMU or MPU.  */
515169689Skanint arm_tune_wbuf = 0;
51690075Sobrien
51790075Sobrien/* Nonzero if generating Thumb instructions.  */
51890075Sobrienint thumb_code = 0;
51990075Sobrien
520169689Skan/* Nonzero if we should define __THUMB_INTERWORK__ in the
521169689Skan   preprocessor.
522169689Skan   XXX This is a bit of a hack, it's intended to help work around
523169689Skan   problems in GLD which doesn't understand that armv5t code is
524169689Skan   interworking clean.  */
525169689Skanint arm_cpp_interwork = 0;
526169689Skan
52790075Sobrien/* In case of a PRE_INC, POST_INC, PRE_DEC, POST_DEC memory reference, we
52890075Sobrien   must report the mode of the memory reference from PRINT_OPERAND to
52990075Sobrien   PRINT_OPERAND_ADDRESS.  */
53090075Sobrienenum machine_mode output_memory_reference_mode;
53190075Sobrien
53290075Sobrien/* The register number to be used for the PIC offset register.  */
533169689Skanunsigned arm_pic_register = INVALID_REGNUM;
53490075Sobrien
53590075Sobrien/* Set to 1 when a return insn is output, this means that the epilogue
53690075Sobrien   is not needed.  */
53790075Sobrienint return_used_this_function;
53890075Sobrien
53990075Sobrien/* Set to 1 after arm_reorg has started.  Reset to start at the start of
54090075Sobrien   the next function.  */
54190075Sobrienstatic int after_arm_reorg = 0;
54290075Sobrien
54390075Sobrien/* The maximum number of insns to be used when loading a constant.  */
54490075Sobrienstatic int arm_constant_limit = 3;
54590075Sobrien
54690075Sobrien/* For an explanation of these variables, see final_prescan_insn below.  */
54790075Sobrienint arm_ccfsm_state;
54890075Sobrienenum arm_cond_code arm_current_cc;
54990075Sobrienrtx arm_target_insn;
55090075Sobrienint arm_target_label;
55190075Sobrien
55290075Sobrien/* The condition codes of the ARM, and the inverse function.  */
55390075Sobrienstatic const char * const arm_condition_codes[] =
55490075Sobrien{
55590075Sobrien  "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
55690075Sobrien  "hi", "ls", "ge", "lt", "gt", "le", "al", "nv"
55790075Sobrien};
55890075Sobrien
55990075Sobrien#define streq(string1, string2) (strcmp (string1, string2) == 0)
56090075Sobrien
56190075Sobrien/* Initialization code.  */
56290075Sobrien
56390075Sobrienstruct processors
56490075Sobrien{
56590075Sobrien  const char *const name;
566169689Skan  enum processor_type core;
567169689Skan  const char *arch;
568117395Skan  const unsigned long flags;
569169689Skan  bool (* rtx_costs) (rtx, int, int, int *);
57090075Sobrien};
57190075Sobrien
57290075Sobrien/* Not all of these give usefully different compilation alternatives,
57390075Sobrien   but there is no simple way of generalizing them.  */
57490075Sobrienstatic const struct processors all_cores[] =
57590075Sobrien{
57690075Sobrien  /* ARM Cores */
577169689Skan#define ARM_CORE(NAME, IDENT, ARCH, FLAGS, COSTS) \
578169689Skan  {NAME, arm_none, #ARCH, FLAGS | FL_FOR_ARCH##ARCH, arm_##COSTS##_rtx_costs},
579169689Skan#include "arm-cores.def"
580169689Skan#undef ARM_CORE
581169689Skan  {NULL, arm_none, NULL, 0, NULL}
58290075Sobrien};
58390075Sobrien
58490075Sobrienstatic const struct processors all_architectures[] =
58590075Sobrien{
58690075Sobrien  /* ARM Architectures */
587169689Skan  /* We don't specify rtx_costs here as it will be figured out
588169689Skan     from the core.  */
589169689Skan
590169689Skan  {"armv2",   arm2,       "2",   FL_CO_PROC | FL_MODE26 | FL_FOR_ARCH2, NULL},
591169689Skan  {"armv2a",  arm2,       "2",   FL_CO_PROC | FL_MODE26 | FL_FOR_ARCH2, NULL},
592169689Skan  {"armv3",   arm6,       "3",   FL_CO_PROC | FL_MODE26 | FL_FOR_ARCH3, NULL},
593169689Skan  {"armv3m",  arm7m,      "3M",  FL_CO_PROC | FL_MODE26 | FL_FOR_ARCH3M, NULL},
594169689Skan  {"armv4",   arm7tdmi,   "4",   FL_CO_PROC | FL_MODE26 | FL_FOR_ARCH4, NULL},
59590075Sobrien  /* Strictly, FL_MODE26 is a permitted option for v4t, but there are no
59690075Sobrien     implementations that support it, so we will leave it out for now.  */
597169689Skan  {"armv4t",  arm7tdmi,   "4T",  FL_CO_PROC |             FL_FOR_ARCH4T, NULL},
598169689Skan  {"armv5",   arm10tdmi,  "5",   FL_CO_PROC |             FL_FOR_ARCH5, NULL},
599169689Skan  {"armv5t",  arm10tdmi,  "5T",  FL_CO_PROC |             FL_FOR_ARCH5T, NULL},
600169689Skan  {"armv5e",  arm1026ejs, "5E",  FL_CO_PROC |             FL_FOR_ARCH5E, NULL},
601169689Skan  {"armv5te", arm1026ejs, "5TE", FL_CO_PROC |             FL_FOR_ARCH5TE, NULL},
602169689Skan  {"armv6",   arm1136js,  "6",   FL_CO_PROC |             FL_FOR_ARCH6, NULL},
603169689Skan  {"armv6j",  arm1136js,  "6J",  FL_CO_PROC |             FL_FOR_ARCH6J, NULL},
604169689Skan  {"armv6k",  mpcore,	  "6K",  FL_CO_PROC |             FL_FOR_ARCH6K, NULL},
605169689Skan  {"armv6z",  arm1176jzs, "6Z",  FL_CO_PROC |             FL_FOR_ARCH6Z, NULL},
606169689Skan  {"armv6zk", arm1176jzs, "6ZK", FL_CO_PROC |             FL_FOR_ARCH6ZK, NULL},
607169689Skan  {"ep9312",  ep9312,     "4T",  FL_LDSCHED | FL_CIRRUS | FL_FOR_ARCH4, NULL},
608169689Skan  {"iwmmxt",  iwmmxt,     "5TE", FL_LDSCHED | FL_STRONG | FL_FOR_ARCH5TE | FL_XSCALE | FL_IWMMXT , NULL},
609169689Skan  {NULL, arm_none, NULL, 0 , NULL}
61090075Sobrien};
61190075Sobrien
612169689Skanstruct arm_cpu_select
613169689Skan{
614169689Skan  const char *              string;
615169689Skan  const char *              name;
616169689Skan  const struct processors * processors;
617169689Skan};
618169689Skan
619132718Skan/* This is a magic structure.  The 'string' field is magically filled in
62090075Sobrien   with a pointer to the value specified by the user on the command line
62190075Sobrien   assuming that the user has specified such a value.  */
62290075Sobrien
623169689Skanstatic struct arm_cpu_select arm_select[] =
62490075Sobrien{
625169689Skan  /* string	  name            processors  */
62690075Sobrien  { NULL,	"-mcpu=",	all_cores  },
62790075Sobrien  { NULL,	"-march=",	all_architectures },
62890075Sobrien  { NULL,	"-mtune=",	all_cores }
62990075Sobrien};
63090075Sobrien
631169689Skan/* Defines representing the indexes into the above table.  */
632169689Skan#define ARM_OPT_SET_CPU 0
633169689Skan#define ARM_OPT_SET_ARCH 1
634169689Skan#define ARM_OPT_SET_TUNE 2
635169689Skan
636169689Skan/* The name of the preprocessor macro to define for this architecture.  */
637169689Skan
638169689Skanchar arm_arch_name[] = "__ARM_ARCH_0UNK__";
639169689Skan
640169689Skanstruct fpu_desc
641169689Skan{
642169689Skan  const char * name;
643169689Skan  enum fputype fpu;
644169689Skan};
645169689Skan
646169689Skan
647169689Skan/* Available values for -mfpu=.  */
648169689Skan
649169689Skanstatic const struct fpu_desc all_fpus[] =
650169689Skan{
651169689Skan  {"fpa",	FPUTYPE_FPA},
652169689Skan  {"fpe2",	FPUTYPE_FPA_EMU2},
653169689Skan  {"fpe3",	FPUTYPE_FPA_EMU2},
654169689Skan  {"maverick",	FPUTYPE_MAVERICK},
655169689Skan  {"vfp",	FPUTYPE_VFP}
656169689Skan};
657169689Skan
658169689Skan
659169689Skan/* Floating point models used by the different hardware.
660169689Skan   See fputype in arm.h.  */
661169689Skan
662169689Skanstatic const enum fputype fp_model_for_fpu[] =
663169689Skan{
664169689Skan  /* No FP hardware.  */
665169689Skan  ARM_FP_MODEL_UNKNOWN,		/* FPUTYPE_NONE  */
666169689Skan  ARM_FP_MODEL_FPA,		/* FPUTYPE_FPA  */
667169689Skan  ARM_FP_MODEL_FPA,		/* FPUTYPE_FPA_EMU2  */
668169689Skan  ARM_FP_MODEL_FPA,		/* FPUTYPE_FPA_EMU3  */
669169689Skan  ARM_FP_MODEL_MAVERICK,	/* FPUTYPE_MAVERICK  */
670169689Skan  ARM_FP_MODEL_VFP		/* FPUTYPE_VFP  */
671169689Skan};
672169689Skan
673169689Skan
674169689Skanstruct float_abi
675169689Skan{
676169689Skan  const char * name;
677169689Skan  enum float_abi_type abi_type;
678169689Skan};
679169689Skan
680169689Skan
681169689Skan/* Available values for -mfloat-abi=.  */
682169689Skan
683169689Skanstatic const struct float_abi all_float_abis[] =
684169689Skan{
685169689Skan  {"soft",	ARM_FLOAT_ABI_SOFT},
686169689Skan  {"softfp",	ARM_FLOAT_ABI_SOFTFP},
687169689Skan  {"hard",	ARM_FLOAT_ABI_HARD}
688169689Skan};
689169689Skan
690169689Skan
691169689Skanstruct abi_name
692169689Skan{
693169689Skan  const char *name;
694169689Skan  enum arm_abi_type abi_type;
695169689Skan};
696169689Skan
697169689Skan
698169689Skan/* Available values for -mabi=.  */
699169689Skan
700169689Skanstatic const struct abi_name arm_all_abis[] =
701169689Skan{
702169689Skan  {"apcs-gnu",    ARM_ABI_APCS},
703169689Skan  {"atpcs",   ARM_ABI_ATPCS},
704169689Skan  {"aapcs",   ARM_ABI_AAPCS},
705169689Skan  {"iwmmxt",  ARM_ABI_IWMMXT},
706169689Skan  {"aapcs-linux",   ARM_ABI_AAPCS_LINUX}
707169689Skan};
708169689Skan
709169689Skan/* Supported TLS relocations.  */
710169689Skan
711169689Skanenum tls_reloc {
712169689Skan  TLS_GD32,
713169689Skan  TLS_LDM32,
714169689Skan  TLS_LDO32,
715169689Skan  TLS_IE32,
716169689Skan  TLS_LE32
717169689Skan};
718169689Skan
719169689Skan/* Emit an insn that's a simple single-set.  Both the operands must be known
720169689Skan   to be valid.  */
721169689Skaninline static rtx
722169689Skanemit_set_insn (rtx x, rtx y)
723169689Skan{
724169689Skan  return emit_insn (gen_rtx_SET (VOIDmode, x, y));
725169689Skan}
726169689Skan
727117395Skan/* Return the number of bits set in VALUE.  */
728117395Skanstatic unsigned
729132718Skanbit_count (unsigned long value)
73090075Sobrien{
73190075Sobrien  unsigned long count = 0;
732169689Skan
73390075Sobrien  while (value)
73490075Sobrien    {
735117395Skan      count++;
736117395Skan      value &= value - 1;  /* Clear the least-significant set bit.  */
73790075Sobrien    }
73890075Sobrien
73990075Sobrien  return count;
74090075Sobrien}
74190075Sobrien
742169689Skan/* Set up library functions unique to ARM.  */
743169689Skan
744169689Skanstatic void
745169689Skanarm_init_libfuncs (void)
746169689Skan{
747169689Skan  /* There are no special library functions unless we are using the
748169689Skan     ARM BPABI.  */
749169689Skan  if (!TARGET_BPABI)
750169689Skan    return;
751169689Skan
752169689Skan  /* The functions below are described in Section 4 of the "Run-Time
753169689Skan     ABI for the ARM architecture", Version 1.0.  */
754169689Skan
755169689Skan  /* Double-precision floating-point arithmetic.  Table 2.  */
756169689Skan  set_optab_libfunc (add_optab, DFmode, "__aeabi_dadd");
757169689Skan  set_optab_libfunc (sdiv_optab, DFmode, "__aeabi_ddiv");
758169689Skan  set_optab_libfunc (smul_optab, DFmode, "__aeabi_dmul");
759169689Skan  set_optab_libfunc (neg_optab, DFmode, "__aeabi_dneg");
760169689Skan  set_optab_libfunc (sub_optab, DFmode, "__aeabi_dsub");
761169689Skan
762169689Skan  /* Double-precision comparisons.  Table 3.  */
763169689Skan  set_optab_libfunc (eq_optab, DFmode, "__aeabi_dcmpeq");
764169689Skan  set_optab_libfunc (ne_optab, DFmode, NULL);
765169689Skan  set_optab_libfunc (lt_optab, DFmode, "__aeabi_dcmplt");
766169689Skan  set_optab_libfunc (le_optab, DFmode, "__aeabi_dcmple");
767169689Skan  set_optab_libfunc (ge_optab, DFmode, "__aeabi_dcmpge");
768169689Skan  set_optab_libfunc (gt_optab, DFmode, "__aeabi_dcmpgt");
769169689Skan  set_optab_libfunc (unord_optab, DFmode, "__aeabi_dcmpun");
770169689Skan
771169689Skan  /* Single-precision floating-point arithmetic.  Table 4.  */
772169689Skan  set_optab_libfunc (add_optab, SFmode, "__aeabi_fadd");
773169689Skan  set_optab_libfunc (sdiv_optab, SFmode, "__aeabi_fdiv");
774169689Skan  set_optab_libfunc (smul_optab, SFmode, "__aeabi_fmul");
775169689Skan  set_optab_libfunc (neg_optab, SFmode, "__aeabi_fneg");
776169689Skan  set_optab_libfunc (sub_optab, SFmode, "__aeabi_fsub");
777169689Skan
778169689Skan  /* Single-precision comparisons.  Table 5.  */
779169689Skan  set_optab_libfunc (eq_optab, SFmode, "__aeabi_fcmpeq");
780169689Skan  set_optab_libfunc (ne_optab, SFmode, NULL);
781169689Skan  set_optab_libfunc (lt_optab, SFmode, "__aeabi_fcmplt");
782169689Skan  set_optab_libfunc (le_optab, SFmode, "__aeabi_fcmple");
783169689Skan  set_optab_libfunc (ge_optab, SFmode, "__aeabi_fcmpge");
784169689Skan  set_optab_libfunc (gt_optab, SFmode, "__aeabi_fcmpgt");
785169689Skan  set_optab_libfunc (unord_optab, SFmode, "__aeabi_fcmpun");
786169689Skan
787169689Skan  /* Floating-point to integer conversions.  Table 6.  */
788169689Skan  set_conv_libfunc (sfix_optab, SImode, DFmode, "__aeabi_d2iz");
789169689Skan  set_conv_libfunc (ufix_optab, SImode, DFmode, "__aeabi_d2uiz");
790169689Skan  set_conv_libfunc (sfix_optab, DImode, DFmode, "__aeabi_d2lz");
791169689Skan  set_conv_libfunc (ufix_optab, DImode, DFmode, "__aeabi_d2ulz");
792169689Skan  set_conv_libfunc (sfix_optab, SImode, SFmode, "__aeabi_f2iz");
793169689Skan  set_conv_libfunc (ufix_optab, SImode, SFmode, "__aeabi_f2uiz");
794169689Skan  set_conv_libfunc (sfix_optab, DImode, SFmode, "__aeabi_f2lz");
795169689Skan  set_conv_libfunc (ufix_optab, DImode, SFmode, "__aeabi_f2ulz");
796169689Skan
797169689Skan  /* Conversions between floating types.  Table 7.  */
798169689Skan  set_conv_libfunc (trunc_optab, SFmode, DFmode, "__aeabi_d2f");
799169689Skan  set_conv_libfunc (sext_optab, DFmode, SFmode, "__aeabi_f2d");
800169689Skan
801169689Skan  /* Integer to floating-point conversions.  Table 8.  */
802169689Skan  set_conv_libfunc (sfloat_optab, DFmode, SImode, "__aeabi_i2d");
803169689Skan  set_conv_libfunc (ufloat_optab, DFmode, SImode, "__aeabi_ui2d");
804169689Skan  set_conv_libfunc (sfloat_optab, DFmode, DImode, "__aeabi_l2d");
805169689Skan  set_conv_libfunc (ufloat_optab, DFmode, DImode, "__aeabi_ul2d");
806169689Skan  set_conv_libfunc (sfloat_optab, SFmode, SImode, "__aeabi_i2f");
807169689Skan  set_conv_libfunc (ufloat_optab, SFmode, SImode, "__aeabi_ui2f");
808169689Skan  set_conv_libfunc (sfloat_optab, SFmode, DImode, "__aeabi_l2f");
809169689Skan  set_conv_libfunc (ufloat_optab, SFmode, DImode, "__aeabi_ul2f");
810169689Skan
811169689Skan  /* Long long.  Table 9.  */
812169689Skan  set_optab_libfunc (smul_optab, DImode, "__aeabi_lmul");
813169689Skan  set_optab_libfunc (sdivmod_optab, DImode, "__aeabi_ldivmod");
814169689Skan  set_optab_libfunc (udivmod_optab, DImode, "__aeabi_uldivmod");
815169689Skan  set_optab_libfunc (ashl_optab, DImode, "__aeabi_llsl");
816169689Skan  set_optab_libfunc (lshr_optab, DImode, "__aeabi_llsr");
817169689Skan  set_optab_libfunc (ashr_optab, DImode, "__aeabi_lasr");
818169689Skan  set_optab_libfunc (cmp_optab, DImode, "__aeabi_lcmp");
819169689Skan  set_optab_libfunc (ucmp_optab, DImode, "__aeabi_ulcmp");
820169689Skan
821169689Skan  /* Integer (32/32->32) division.  \S 4.3.1.  */
822169689Skan  set_optab_libfunc (sdivmod_optab, SImode, "__aeabi_idivmod");
823169689Skan  set_optab_libfunc (udivmod_optab, SImode, "__aeabi_uidivmod");
824169689Skan
825169689Skan  /* The divmod functions are designed so that they can be used for
826169689Skan     plain division, even though they return both the quotient and the
827169689Skan     remainder.  The quotient is returned in the usual location (i.e.,
828169689Skan     r0 for SImode, {r0, r1} for DImode), just as would be expected
829169689Skan     for an ordinary division routine.  Because the AAPCS calling
830169689Skan     conventions specify that all of { r0, r1, r2, r3 } are
831169689Skan     callee-saved registers, there is no need to tell the compiler
832169689Skan     explicitly that those registers are clobbered by these
833169689Skan     routines.  */
834169689Skan  set_optab_libfunc (sdiv_optab, DImode, "__aeabi_ldivmod");
835169689Skan  set_optab_libfunc (udiv_optab, DImode, "__aeabi_uldivmod");
836169689Skan
837169689Skan  /* For SImode division the ABI provides div-without-mod routines,
838169689Skan     which are faster.  */
839169689Skan  set_optab_libfunc (sdiv_optab, SImode, "__aeabi_idiv");
840169689Skan  set_optab_libfunc (udiv_optab, SImode, "__aeabi_uidiv");
841169689Skan
842169689Skan  /* We don't have mod libcalls.  Fortunately gcc knows how to use the
843169689Skan     divmod libcalls instead.  */
844169689Skan  set_optab_libfunc (smod_optab, DImode, NULL);
845169689Skan  set_optab_libfunc (umod_optab, DImode, NULL);
846169689Skan  set_optab_libfunc (smod_optab, SImode, NULL);
847169689Skan  set_optab_libfunc (umod_optab, SImode, NULL);
848169689Skan}
849169689Skan
850169689Skan/* Implement TARGET_HANDLE_OPTION.  */
851169689Skan
852169689Skanstatic bool
853169689Skanarm_handle_option (size_t code, const char *arg, int value ATTRIBUTE_UNUSED)
854169689Skan{
855169689Skan  switch (code)
856169689Skan    {
857169689Skan    case OPT_march_:
858169689Skan      arm_select[1].string = arg;
859169689Skan      return true;
860169689Skan
861169689Skan    case OPT_mcpu_:
862169689Skan      arm_select[0].string = arg;
863169689Skan      return true;
864169689Skan
865169689Skan    case OPT_mhard_float:
866169689Skan      target_float_abi_name = "hard";
867169689Skan      return true;
868169689Skan
869169689Skan    case OPT_msoft_float:
870169689Skan      target_float_abi_name = "soft";
871169689Skan      return true;
872169689Skan
873169689Skan    case OPT_mtune_:
874169689Skan      arm_select[2].string = arg;
875169689Skan      return true;
876169689Skan
877169689Skan    default:
878169689Skan      return true;
879169689Skan    }
880169689Skan}
881169689Skan
88290075Sobrien/* Fix up any incompatible options that the user has specified.
88390075Sobrien   This has now turned into a maze.  */
88490075Sobrienvoid
885132718Skanarm_override_options (void)
88690075Sobrien{
88790075Sobrien  unsigned i;
888169689Skan  enum processor_type target_arch_cpu = arm_none;
889169689Skan
89090075Sobrien  /* Set up the flags based on the cpu/architecture selected by the user.  */
89190075Sobrien  for (i = ARRAY_SIZE (arm_select); i--;)
89290075Sobrien    {
89390075Sobrien      struct arm_cpu_select * ptr = arm_select + i;
894169689Skan
89590075Sobrien      if (ptr->string != NULL && ptr->string[0] != '\0')
89690075Sobrien        {
89790075Sobrien	  const struct processors * sel;
89890075Sobrien
89990075Sobrien          for (sel = ptr->processors; sel->name != NULL; sel++)
90090075Sobrien            if (streq (ptr->string, sel->name))
90190075Sobrien              {
902169689Skan		/* Set the architecture define.  */
903169689Skan		if (i != ARM_OPT_SET_TUNE)
904169689Skan		  sprintf (arm_arch_name, "__ARM_ARCH_%s__", sel->arch);
905169689Skan
906169689Skan		/* Determine the processor core for which we should
907169689Skan		   tune code-generation.  */
908169689Skan		if (/* -mcpu= is a sensible default.  */
909169689Skan		    i == ARM_OPT_SET_CPU
910169689Skan		    /* -mtune= overrides -mcpu= and -march=.  */
911169689Skan		    || i == ARM_OPT_SET_TUNE)
912169689Skan		  arm_tune = (enum processor_type) (sel - ptr->processors);
913169689Skan
914169689Skan		/* Remember the CPU associated with this architecture.
915169689Skan		   If no other option is used to set the CPU type,
916169689Skan		   we'll use this to guess the most suitable tuning
917169689Skan		   options.  */
918169689Skan		if (i == ARM_OPT_SET_ARCH)
919169689Skan		  target_arch_cpu = sel->core;
920169689Skan
921169689Skan		if (i != ARM_OPT_SET_TUNE)
92290075Sobrien		  {
92390075Sobrien		    /* If we have been given an architecture and a processor
92490075Sobrien		       make sure that they are compatible.  We only generate
92590075Sobrien		       a warning though, and we prefer the CPU over the
92690075Sobrien		       architecture.  */
92790075Sobrien		    if (insn_flags != 0 && (insn_flags ^ sel->flags))
928169689Skan		      warning (0, "switch -mcpu=%s conflicts with -march= switch",
92990075Sobrien			       ptr->string);
930169689Skan
93190075Sobrien		    insn_flags = sel->flags;
93290075Sobrien		  }
933169689Skan
93490075Sobrien                break;
93590075Sobrien              }
93690075Sobrien
93790075Sobrien          if (sel->name == NULL)
93890075Sobrien            error ("bad value (%s) for %s switch", ptr->string, ptr->name);
93990075Sobrien        }
94090075Sobrien    }
941169689Skan
942169689Skan  /* Guess the tuning options from the architecture if necessary.  */
943169689Skan  if (arm_tune == arm_none)
944169689Skan    arm_tune = target_arch_cpu;
945169689Skan
94690075Sobrien  /* If the user did not specify a processor, choose one for them.  */
94790075Sobrien  if (insn_flags == 0)
94890075Sobrien    {
94990075Sobrien      const struct processors * sel;
95090075Sobrien      unsigned int        sought;
951169689Skan      enum processor_type cpu;
95290075Sobrien
953169689Skan      cpu = TARGET_CPU_DEFAULT;
954169689Skan      if (cpu == arm_none)
955169689Skan	{
956169689Skan#ifdef SUBTARGET_CPU_DEFAULT
957169689Skan	  /* Use the subtarget default CPU if none was specified by
958169689Skan	     configure.  */
959169689Skan	  cpu = SUBTARGET_CPU_DEFAULT;
960169689Skan#endif
961169689Skan	  /* Default to ARM6.  */
962169689Skan	  if (cpu == arm_none)
963169689Skan	    cpu = arm6;
964169689Skan	}
965169689Skan      sel = &all_cores[cpu];
96690075Sobrien
96790075Sobrien      insn_flags = sel->flags;
968169689Skan
96990075Sobrien      /* Now check to see if the user has specified some command line
97090075Sobrien	 switch that require certain abilities from the cpu.  */
97190075Sobrien      sought = 0;
972169689Skan
97390075Sobrien      if (TARGET_INTERWORK || TARGET_THUMB)
97490075Sobrien	{
97590075Sobrien	  sought |= (FL_THUMB | FL_MODE32);
97690075Sobrien
97790075Sobrien	  /* There are no ARM processors that support both APCS-26 and
97890075Sobrien	     interworking.  Therefore we force FL_MODE26 to be removed
97990075Sobrien	     from insn_flags here (if it was set), so that the search
98090075Sobrien	     below will always be able to find a compatible processor.  */
98190075Sobrien	  insn_flags &= ~FL_MODE26;
98290075Sobrien	}
983169689Skan
98490075Sobrien      if (sought != 0 && ((sought & insn_flags) != sought))
98590075Sobrien	{
98690075Sobrien	  /* Try to locate a CPU type that supports all of the abilities
98790075Sobrien	     of the default CPU, plus the extra abilities requested by
98890075Sobrien	     the user.  */
98990075Sobrien	  for (sel = all_cores; sel->name != NULL; sel++)
99090075Sobrien	    if ((sel->flags & sought) == (sought | insn_flags))
99190075Sobrien	      break;
99290075Sobrien
99390075Sobrien	  if (sel->name == NULL)
99490075Sobrien	    {
995117395Skan	      unsigned current_bit_count = 0;
99690075Sobrien	      const struct processors * best_fit = NULL;
997169689Skan
99890075Sobrien	      /* Ideally we would like to issue an error message here
99990075Sobrien		 saying that it was not possible to find a CPU compatible
100090075Sobrien		 with the default CPU, but which also supports the command
100190075Sobrien		 line options specified by the programmer, and so they
100290075Sobrien		 ought to use the -mcpu=<name> command line option to
100390075Sobrien		 override the default CPU type.
100490075Sobrien
1005169689Skan		 If we cannot find a cpu that has both the
1006169689Skan		 characteristics of the default cpu and the given
1007169689Skan		 command line options we scan the array again looking
1008169689Skan		 for a best match.  */
100990075Sobrien	      for (sel = all_cores; sel->name != NULL; sel++)
101090075Sobrien		if ((sel->flags & sought) == sought)
101190075Sobrien		  {
1012117395Skan		    unsigned count;
101390075Sobrien
101490075Sobrien		    count = bit_count (sel->flags & insn_flags);
101590075Sobrien
101690075Sobrien		    if (count >= current_bit_count)
101790075Sobrien		      {
101890075Sobrien			best_fit = sel;
101990075Sobrien			current_bit_count = count;
102090075Sobrien		      }
102190075Sobrien		  }
102290075Sobrien
1023169689Skan	      gcc_assert (best_fit);
1024169689Skan	      sel = best_fit;
102590075Sobrien	    }
102690075Sobrien
102790075Sobrien	  insn_flags = sel->flags;
102890075Sobrien	}
1029169689Skan      sprintf (arm_arch_name, "__ARM_ARCH_%s__", sel->arch);
1030260456Spfg      arm_default_cpu = (enum processor_type) (sel - all_cores);
1031169689Skan      if (arm_tune == arm_none)
1032260456Spfg	arm_tune = arm_default_cpu;
103390075Sobrien    }
1034117395Skan
1035169689Skan  /* The processor for which we should tune should now have been
1036169689Skan     chosen.  */
1037169689Skan  gcc_assert (arm_tune != arm_none);
1038169689Skan
1039169689Skan  tune_flags = all_cores[(int)arm_tune].flags;
1040169689Skan  if (optimize_size)
1041169689Skan    targetm.rtx_costs = arm_size_rtx_costs;
1042169689Skan  else
1043169689Skan    targetm.rtx_costs = all_cores[(int)arm_tune].rtx_costs;
1044169689Skan
104590075Sobrien  /* Make sure that the processor choice does not conflict with any of the
104690075Sobrien     other command line choices.  */
104790075Sobrien  if (TARGET_INTERWORK && !(insn_flags & FL_THUMB))
104890075Sobrien    {
1049169689Skan      warning (0, "target CPU does not support interworking" );
1050169689Skan      target_flags &= ~MASK_INTERWORK;
105190075Sobrien    }
1052169689Skan
105390075Sobrien  if (TARGET_THUMB && !(insn_flags & FL_THUMB))
105490075Sobrien    {
1055169689Skan      warning (0, "target CPU does not support THUMB instructions");
1056169689Skan      target_flags &= ~MASK_THUMB;
105790075Sobrien    }
105890075Sobrien
105990075Sobrien  if (TARGET_APCS_FRAME && TARGET_THUMB)
106090075Sobrien    {
1061169689Skan      /* warning (0, "ignoring -mapcs-frame because -mthumb was used"); */
1062169689Skan      target_flags &= ~MASK_APCS_FRAME;
106390075Sobrien    }
106490075Sobrien
1065169689Skan  /* Callee super interworking implies thumb interworking.  Adding
1066169689Skan     this to the flags here simplifies the logic elsewhere.  */
1067169689Skan  if (TARGET_THUMB && TARGET_CALLEE_INTERWORKING)
1068169689Skan      target_flags |= MASK_INTERWORK;
1069169689Skan
107090075Sobrien  /* TARGET_BACKTRACE calls leaf_function_p, which causes a crash if done
107190075Sobrien     from here where no function is being compiled currently.  */
1072169689Skan  if ((TARGET_TPCS_FRAME || TARGET_TPCS_LEAF_FRAME) && TARGET_ARM)
1073169689Skan    warning (0, "enabling backtrace support is only meaningful when compiling for the Thumb");
107490075Sobrien
107590075Sobrien  if (TARGET_ARM && TARGET_CALLEE_INTERWORKING)
1076169689Skan    warning (0, "enabling callee interworking support is only meaningful when compiling for the Thumb");
107790075Sobrien
107890075Sobrien  if (TARGET_ARM && TARGET_CALLER_INTERWORKING)
1079169689Skan    warning (0, "enabling caller interworking support is only meaningful when compiling for the Thumb");
108090075Sobrien
108190075Sobrien  if (TARGET_APCS_STACK && !TARGET_APCS_FRAME)
108290075Sobrien    {
1083169689Skan      warning (0, "-mapcs-stack-check incompatible with -mno-apcs-frame");
1084169689Skan      target_flags |= MASK_APCS_FRAME;
108590075Sobrien    }
1086169689Skan
108790075Sobrien  if (TARGET_POKE_FUNCTION_NAME)
1088169689Skan    target_flags |= MASK_APCS_FRAME;
1089169689Skan
109090075Sobrien  if (TARGET_APCS_REENT && flag_pic)
109190075Sobrien    error ("-fpic and -mapcs-reent are incompatible");
1092169689Skan
109390075Sobrien  if (TARGET_APCS_REENT)
1094169689Skan    warning (0, "APCS reentrant code not supported.  Ignored");
1095169689Skan
109690075Sobrien  /* If this target is normally configured to use APCS frames, warn if they
109790075Sobrien     are turned off and debugging is turned on.  */
109890075Sobrien  if (TARGET_ARM
109990075Sobrien      && write_symbols != NO_DEBUG
110090075Sobrien      && !TARGET_APCS_FRAME
1101169689Skan      && (TARGET_DEFAULT & MASK_APCS_FRAME))
1102169689Skan    warning (0, "-g with -mno-apcs-frame may not give sensible debugging");
1103169689Skan
110490075Sobrien  /* If stack checking is disabled, we can use r10 as the PIC register,
110590075Sobrien     which keeps r9 available.  */
1106169689Skan  if (flag_pic && TARGET_SINGLE_PIC_BASE)
110796263Sobrien    arm_pic_register = TARGET_APCS_STACK ? 9 : 10;
1108169689Skan
110990075Sobrien  if (TARGET_APCS_FLOAT)
1110169689Skan    warning (0, "passing floating point arguments in fp regs not yet supported");
1111169689Skan
1112117395Skan  /* Initialize boolean versions of the flags, for use in the arm.md file.  */
1113169689Skan  arm_arch3m = (insn_flags & FL_ARCH3M) != 0;
1114169689Skan  arm_arch4 = (insn_flags & FL_ARCH4) != 0;
1115169689Skan  arm_arch4t = arm_arch4 & ((insn_flags & FL_THUMB) != 0);
1116169689Skan  arm_arch5 = (insn_flags & FL_ARCH5) != 0;
1117169689Skan  arm_arch5e = (insn_flags & FL_ARCH5E) != 0;
1118169689Skan  arm_arch6 = (insn_flags & FL_ARCH6) != 0;
1119169689Skan  arm_arch6k = (insn_flags & FL_ARCH6K) != 0;
1120169689Skan  arm_arch_xscale = (insn_flags & FL_XSCALE) != 0;
1121169689Skan  arm_arch_cirrus = (insn_flags & FL_CIRRUS) != 0;
112290075Sobrien
1123169689Skan  arm_ld_sched = (tune_flags & FL_LDSCHED) != 0;
1124169689Skan  arm_tune_strongarm = (tune_flags & FL_STRONG) != 0;
1125169689Skan  thumb_code = (TARGET_ARM == 0);
1126169689Skan  arm_tune_wbuf = (tune_flags & FL_WBUF) != 0;
1127169689Skan  arm_tune_xscale = (tune_flags & FL_XSCALE) != 0;
1128169689Skan  arm_arch_iwmmxt = (insn_flags & FL_IWMMXT) != 0;
112990075Sobrien
1130169689Skan  /* V5 code we generate is completely interworking capable, so we turn off
1131169689Skan     TARGET_INTERWORK here to avoid many tests later on.  */
1132132718Skan
1133169689Skan  /* XXX However, we must pass the right pre-processor defines to CPP
1134169689Skan     or GLD can get confused.  This is a hack.  */
1135169689Skan  if (TARGET_INTERWORK)
1136169689Skan    arm_cpp_interwork = 1;
1137169689Skan
1138169689Skan  if (arm_arch5)
1139169689Skan    target_flags &= ~MASK_INTERWORK;
1140169689Skan
1141169689Skan  if (target_abi_name)
1142132718Skan    {
1143169689Skan      for (i = 0; i < ARRAY_SIZE (arm_all_abis); i++)
1144169689Skan	{
1145169689Skan	  if (streq (arm_all_abis[i].name, target_abi_name))
1146169689Skan	    {
1147169689Skan	      arm_abi = arm_all_abis[i].abi_type;
1148169689Skan	      break;
1149169689Skan	    }
1150169689Skan	}
1151169689Skan      if (i == ARRAY_SIZE (arm_all_abis))
1152169689Skan	error ("invalid ABI option: -mabi=%s", target_abi_name);
1153169689Skan    }
1154169689Skan  else
1155169689Skan    arm_abi = ARM_DEFAULT_ABI;
1156132718Skan
1157169689Skan  if (TARGET_IWMMXT && !ARM_DOUBLEWORD_ALIGN)
1158169689Skan    error ("iwmmxt requires an AAPCS compatible ABI for proper operation");
1159169689Skan
1160169689Skan  if (TARGET_IWMMXT_ABI && !TARGET_IWMMXT)
1161169689Skan    error ("iwmmxt abi requires an iwmmxt capable cpu");
1162169689Skan
1163169689Skan  arm_fp_model = ARM_FP_MODEL_UNKNOWN;
1164169689Skan  if (target_fpu_name == NULL && target_fpe_name != NULL)
1165169689Skan    {
1166169689Skan      if (streq (target_fpe_name, "2"))
1167169689Skan	target_fpu_name = "fpe2";
1168169689Skan      else if (streq (target_fpe_name, "3"))
1169169689Skan	target_fpu_name = "fpe3";
1170169689Skan      else
1171169689Skan	error ("invalid floating point emulation option: -mfpe=%s",
1172169689Skan	       target_fpe_name);
1173132718Skan    }
1174169689Skan  if (target_fpu_name != NULL)
1175169689Skan    {
1176169689Skan      /* The user specified a FPU.  */
1177169689Skan      for (i = 0; i < ARRAY_SIZE (all_fpus); i++)
1178169689Skan	{
1179169689Skan	  if (streq (all_fpus[i].name, target_fpu_name))
1180169689Skan	    {
1181169689Skan	      arm_fpu_arch = all_fpus[i].fpu;
1182169689Skan	      arm_fpu_tune = arm_fpu_arch;
1183169689Skan	      arm_fp_model = fp_model_for_fpu[arm_fpu_arch];
1184169689Skan	      break;
1185169689Skan	    }
1186169689Skan	}
1187169689Skan      if (arm_fp_model == ARM_FP_MODEL_UNKNOWN)
1188169689Skan	error ("invalid floating point option: -mfpu=%s", target_fpu_name);
1189169689Skan    }
1190132718Skan  else
119190075Sobrien    {
1192169689Skan#ifdef FPUTYPE_DEFAULT
1193169689Skan      /* Use the default if it is specified for this platform.  */
1194169689Skan      arm_fpu_arch = FPUTYPE_DEFAULT;
1195169689Skan      arm_fpu_tune = FPUTYPE_DEFAULT;
1196169689Skan#else
1197169689Skan      /* Pick one based on CPU type.  */
1198169689Skan      /* ??? Some targets assume FPA is the default.
1199169689Skan      if ((insn_flags & FL_VFP) != 0)
1200169689Skan	arm_fpu_arch = FPUTYPE_VFP;
1201169689Skan      else
1202169689Skan      */
1203169689Skan      if (arm_arch_cirrus)
1204169689Skan	arm_fpu_arch = FPUTYPE_MAVERICK;
1205169689Skan      else
1206132718Skan	arm_fpu_arch = FPUTYPE_FPA_EMU2;
1207169689Skan#endif
1208169689Skan      if (tune_flags & FL_CO_PROC && arm_fpu_arch == FPUTYPE_FPA_EMU2)
1209169689Skan	arm_fpu_tune = FPUTYPE_FPA;
121090075Sobrien      else
1211169689Skan	arm_fpu_tune = arm_fpu_arch;
1212169689Skan      arm_fp_model = fp_model_for_fpu[arm_fpu_arch];
1213169689Skan      gcc_assert (arm_fp_model != ARM_FP_MODEL_UNKNOWN);
121490075Sobrien    }
1215169689Skan
1216169689Skan  if (target_float_abi_name != NULL)
1217132718Skan    {
1218169689Skan      /* The user specified a FP ABI.  */
1219169689Skan      for (i = 0; i < ARRAY_SIZE (all_float_abis); i++)
1220169689Skan	{
1221169689Skan	  if (streq (all_float_abis[i].name, target_float_abi_name))
1222169689Skan	    {
1223169689Skan	      arm_float_abi = all_float_abis[i].abi_type;
1224169689Skan	      break;
1225169689Skan	    }
1226169689Skan	}
1227169689Skan      if (i == ARRAY_SIZE (all_float_abis))
1228169689Skan	error ("invalid floating point abi: -mfloat-abi=%s",
1229169689Skan	       target_float_abi_name);
1230132718Skan    }
1231169689Skan  else
1232169689Skan    arm_float_abi = TARGET_DEFAULT_FLOAT_ABI;
1233169689Skan
1234169689Skan  if (arm_float_abi == ARM_FLOAT_ABI_HARD && TARGET_VFP)
1235169689Skan    sorry ("-mfloat-abi=hard and VFP");
1236169689Skan
1237169689Skan  /* FPA and iWMMXt are incompatible because the insn encodings overlap.
1238169689Skan     VFP and iWMMXt can theoretically coexist, but it's unlikely such silicon
1239169689Skan     will ever exist.  GCC makes no attempt to support this combination.  */
1240169689Skan  if (TARGET_IWMMXT && !TARGET_SOFT_FLOAT)
1241169689Skan    sorry ("iWMMXt and hardware floating point");
1242169689Skan
1243169689Skan  /* If soft-float is specified then don't use FPU.  */
1244169689Skan  if (TARGET_SOFT_FLOAT)
1245169689Skan    arm_fpu_arch = FPUTYPE_NONE;
1246169689Skan
124790075Sobrien  /* For arm2/3 there is no need to do any scheduling if there is only
124890075Sobrien     a floating point emulator, or we are doing software floating-point.  */
1249169689Skan  if ((TARGET_SOFT_FLOAT
1250169689Skan       || arm_fpu_tune == FPUTYPE_FPA_EMU2
1251169689Skan       || arm_fpu_tune == FPUTYPE_FPA_EMU3)
125290075Sobrien      && (tune_flags & FL_MODE32) == 0)
125390075Sobrien    flag_schedule_insns = flag_schedule_insns_after_reload = 0;
1254169689Skan
1255169689Skan  if (target_thread_switch)
1256169689Skan    {
1257169689Skan      if (strcmp (target_thread_switch, "soft") == 0)
1258169689Skan	target_thread_pointer = TP_SOFT;
1259169689Skan      else if (strcmp (target_thread_switch, "auto") == 0)
1260169689Skan	target_thread_pointer = TP_AUTO;
1261169689Skan      else if (strcmp (target_thread_switch, "cp15") == 0)
1262169689Skan	target_thread_pointer = TP_CP15;
1263169689Skan      else
1264169689Skan	error ("invalid thread pointer option: -mtp=%s", target_thread_switch);
1265169689Skan    }
1266169689Skan
1267169689Skan  /* Use the cp15 method if it is available.  */
1268169689Skan  if (target_thread_pointer == TP_AUTO)
1269169689Skan    {
1270169689Skan      if (arm_arch6k && !TARGET_THUMB)
1271169689Skan	target_thread_pointer = TP_CP15;
1272169689Skan      else
1273169689Skan	target_thread_pointer = TP_SOFT;
1274169689Skan    }
1275169689Skan
1276169689Skan  if (TARGET_HARD_TP && TARGET_THUMB)
1277169689Skan    error ("can not use -mtp=cp15 with -mthumb");
1278169689Skan
1279169689Skan  /* Override the default structure alignment for AAPCS ABI.  */
1280169689Skan  if (TARGET_AAPCS_BASED)
1281169689Skan    arm_structure_size_boundary = 8;
1282169689Skan
128390075Sobrien  if (structure_size_string != NULL)
128490075Sobrien    {
128590075Sobrien      int size = strtol (structure_size_string, NULL, 0);
1286169689Skan
1287169689Skan      if (size == 8 || size == 32
1288169689Skan	  || (ARM_DOUBLEWORD_ALIGN && size == 64))
128990075Sobrien	arm_structure_size_boundary = size;
129090075Sobrien      else
1291169689Skan	warning (0, "structure size boundary can only be set to %s",
1292169689Skan		 ARM_DOUBLEWORD_ALIGN ? "8, 32 or 64": "8 or 32");
129390075Sobrien    }
129490075Sobrien
129590075Sobrien  if (arm_pic_register_string != NULL)
129690075Sobrien    {
129796263Sobrien      int pic_register = decode_reg_name (arm_pic_register_string);
1298117395Skan
129990075Sobrien      if (!flag_pic)
1300169689Skan	warning (0, "-mpic-register= is useless without -fpic");
130190075Sobrien
130290075Sobrien      /* Prevent the user from choosing an obviously stupid PIC register.  */
130396263Sobrien      else if (pic_register < 0 || call_used_regs[pic_register]
130496263Sobrien	       || pic_register == HARD_FRAME_POINTER_REGNUM
130596263Sobrien	       || pic_register == STACK_POINTER_REGNUM
130696263Sobrien	       || pic_register >= PC_REGNUM)
130790075Sobrien	error ("unable to use '%s' for PIC register", arm_pic_register_string);
130890075Sobrien      else
130990075Sobrien	arm_pic_register = pic_register;
131090075Sobrien    }
131190075Sobrien
131290075Sobrien  if (TARGET_THUMB && flag_schedule_insns)
131390075Sobrien    {
131490075Sobrien      /* Don't warn since it's on by default in -O2.  */
131590075Sobrien      flag_schedule_insns = 0;
131690075Sobrien    }
131790075Sobrien
131890075Sobrien  if (optimize_size)
1319132718Skan    {
1320132718Skan      arm_constant_limit = 1;
132190075Sobrien
1322132718Skan      /* If optimizing for size, bump the number of instructions that we
1323132718Skan         are prepared to conditionally execute (even on a StrongARM).  */
1324132718Skan      max_insns_skipped = 6;
1325132718Skan    }
1326132718Skan  else
1327132718Skan    {
1328132718Skan      /* For processors with load scheduling, it never costs more than
1329132718Skan         2 cycles to load a constant, and the load scheduler may well
1330132718Skan	 reduce that to 1.  */
1331169689Skan      if (arm_ld_sched)
1332132718Skan        arm_constant_limit = 1;
1333132718Skan
1334132718Skan      /* On XScale the longer latency of a load makes it more difficult
1335132718Skan         to achieve a good schedule, so it's faster to synthesize
1336132718Skan	 constants that can be done in two insns.  */
1337132718Skan      if (arm_tune_xscale)
1338132718Skan        arm_constant_limit = 2;
1339132718Skan
1340132718Skan      /* StrongARM has early execution of branches, so a sequence
1341132718Skan         that is worth skipping is shorter.  */
1342169689Skan      if (arm_tune_strongarm)
1343132718Skan        max_insns_skipped = 3;
1344132718Skan    }
1345132718Skan
134690075Sobrien  /* Register global variables with the garbage collector.  */
134790075Sobrien  arm_add_gc_roots ();
134890075Sobrien}
134990075Sobrien
135090075Sobrienstatic void
1351132718Skanarm_add_gc_roots (void)
135290075Sobrien{
135390075Sobrien  gcc_obstack_init(&minipool_obstack);
135490075Sobrien  minipool_startobj = (char *) obstack_alloc (&minipool_obstack, 0);
135590075Sobrien}
135690075Sobrien
135790075Sobrien/* A table of known ARM exception types.
135890075Sobrien   For use with the interrupt function attribute.  */
135990075Sobrien
136090075Sobrientypedef struct
136190075Sobrien{
136290075Sobrien  const char *const arg;
136390075Sobrien  const unsigned long return_value;
136490075Sobrien}
136590075Sobrienisr_attribute_arg;
136690075Sobrien
136790075Sobrienstatic const isr_attribute_arg isr_attribute_args [] =
136890075Sobrien{
136990075Sobrien  { "IRQ",   ARM_FT_ISR },
137090075Sobrien  { "irq",   ARM_FT_ISR },
137190075Sobrien  { "FIQ",   ARM_FT_FIQ },
137290075Sobrien  { "fiq",   ARM_FT_FIQ },
137390075Sobrien  { "ABORT", ARM_FT_ISR },
137490075Sobrien  { "abort", ARM_FT_ISR },
137590075Sobrien  { "ABORT", ARM_FT_ISR },
137690075Sobrien  { "abort", ARM_FT_ISR },
137790075Sobrien  { "UNDEF", ARM_FT_EXCEPTION },
137890075Sobrien  { "undef", ARM_FT_EXCEPTION },
137990075Sobrien  { "SWI",   ARM_FT_EXCEPTION },
138090075Sobrien  { "swi",   ARM_FT_EXCEPTION },
138190075Sobrien  { NULL,    ARM_FT_NORMAL }
138290075Sobrien};
138390075Sobrien
138490075Sobrien/* Returns the (interrupt) function type of the current
138590075Sobrien   function, or ARM_FT_UNKNOWN if the type cannot be determined.  */
138690075Sobrien
138790075Sobrienstatic unsigned long
1388132718Skanarm_isr_value (tree argument)
138990075Sobrien{
139090075Sobrien  const isr_attribute_arg * ptr;
139190075Sobrien  const char *              arg;
139290075Sobrien
139390075Sobrien  /* No argument - default to IRQ.  */
139490075Sobrien  if (argument == NULL_TREE)
139590075Sobrien    return ARM_FT_ISR;
139690075Sobrien
139790075Sobrien  /* Get the value of the argument.  */
139890075Sobrien  if (TREE_VALUE (argument) == NULL_TREE
139990075Sobrien      || TREE_CODE (TREE_VALUE (argument)) != STRING_CST)
140090075Sobrien    return ARM_FT_UNKNOWN;
140190075Sobrien
140290075Sobrien  arg = TREE_STRING_POINTER (TREE_VALUE (argument));
140390075Sobrien
140490075Sobrien  /* Check it against the list of known arguments.  */
1405132718Skan  for (ptr = isr_attribute_args; ptr->arg != NULL; ptr++)
140690075Sobrien    if (streq (arg, ptr->arg))
140790075Sobrien      return ptr->return_value;
140890075Sobrien
1409117395Skan  /* An unrecognized interrupt type.  */
141090075Sobrien  return ARM_FT_UNKNOWN;
141190075Sobrien}
141290075Sobrien
141390075Sobrien/* Computes the type of the current function.  */
141490075Sobrien
141590075Sobrienstatic unsigned long
1416132718Skanarm_compute_func_type (void)
141790075Sobrien{
141890075Sobrien  unsigned long type = ARM_FT_UNKNOWN;
141990075Sobrien  tree a;
142090075Sobrien  tree attr;
142190075Sobrien
1422169689Skan  gcc_assert (TREE_CODE (current_function_decl) == FUNCTION_DECL);
1423169689Skan
142490075Sobrien  /* Decide if the current function is volatile.  Such functions
142590075Sobrien     never return, and many memory cycles can be saved by not storing
142690075Sobrien     register values that will never be needed again.  This optimization
142790075Sobrien     was added to speed up context switching in a kernel application.  */
142890075Sobrien  if (optimize > 0
1429169689Skan      && (TREE_NOTHROW (current_function_decl)
1430169689Skan          || !(flag_unwind_tables
1431169689Skan               || (flag_exceptions && !USING_SJLJ_EXCEPTIONS)))
143290075Sobrien      && TREE_THIS_VOLATILE (current_function_decl))
143390075Sobrien    type |= ARM_FT_VOLATILE;
1434169689Skan
1435169689Skan  if (cfun->static_chain_decl != NULL)
143690075Sobrien    type |= ARM_FT_NESTED;
143790075Sobrien
143890075Sobrien  attr = DECL_ATTRIBUTES (current_function_decl);
1439169689Skan
144090075Sobrien  a = lookup_attribute ("naked", attr);
144190075Sobrien  if (a != NULL_TREE)
144290075Sobrien    type |= ARM_FT_NAKED;
144390075Sobrien
1444169689Skan  a = lookup_attribute ("isr", attr);
1445169689Skan  if (a == NULL_TREE)
1446169689Skan    a = lookup_attribute ("interrupt", attr);
1447169689Skan
1448169689Skan  if (a == NULL_TREE)
1449169689Skan    type |= TARGET_INTERWORK ? ARM_FT_INTERWORKED : ARM_FT_NORMAL;
145090075Sobrien  else
1451169689Skan    type |= arm_isr_value (TREE_VALUE (a));
1452169689Skan
145390075Sobrien  return type;
145490075Sobrien}
145590075Sobrien
145690075Sobrien/* Returns the type of the current function.  */
145790075Sobrien
145890075Sobrienunsigned long
1459132718Skanarm_current_func_type (void)
146090075Sobrien{
146190075Sobrien  if (ARM_FUNC_TYPE (cfun->machine->func_type) == ARM_FT_UNKNOWN)
146290075Sobrien    cfun->machine->func_type = arm_compute_func_type ();
146390075Sobrien
146490075Sobrien  return cfun->machine->func_type;
146590075Sobrien}
146690075Sobrien
1467169689Skan/* Return 1 if it is possible to return using a single instruction.
1468132718Skan   If SIBLING is non-null, this is a test for a return before a sibling
1469132718Skan   call.  SIBLING is the call insn, so we can examine its register usage.  */
147090075Sobrien
147190075Sobrienint
1472132718Skanuse_return_insn (int iscond, rtx sibling)
147390075Sobrien{
147490075Sobrien  int regno;
147590075Sobrien  unsigned int func_type;
1476107590Sobrien  unsigned long saved_int_regs;
1477132718Skan  unsigned HOST_WIDE_INT stack_adjust;
1478169689Skan  arm_stack_offsets *offsets;
147990075Sobrien
148090075Sobrien  /* Never use a return instruction before reload has run.  */
148190075Sobrien  if (!reload_completed)
148290075Sobrien    return 0;
1483132718Skan
148490075Sobrien  func_type = arm_current_func_type ();
148590075Sobrien
148696263Sobrien  /* Naked functions and volatile functions need special
148796263Sobrien     consideration.  */
148896263Sobrien  if (func_type & (ARM_FT_VOLATILE | ARM_FT_NAKED))
148990075Sobrien    return 0;
1490117395Skan
1491117395Skan  /* So do interrupt functions that use the frame pointer.  */
1492117395Skan  if (IS_INTERRUPT (func_type) && frame_pointer_needed)
1493117395Skan    return 0;
1494132718Skan
1495169689Skan  offsets = arm_get_frame_offsets ();
1496169689Skan  stack_adjust = offsets->outgoing_args - offsets->saved_regs;
1497132718Skan
149890075Sobrien  /* As do variadic functions.  */
149990075Sobrien  if (current_function_pretend_args_size
150096263Sobrien      || cfun->machine->uses_anonymous_args
1501132718Skan      /* Or if the function calls __builtin_eh_return () */
1502169689Skan      || current_function_calls_eh_return
1503132718Skan      /* Or if the function calls alloca */
1504132718Skan      || current_function_calls_alloca
1505132718Skan      /* Or if there is a stack adjustment.  However, if the stack pointer
1506132718Skan	 is saved on the stack, we can use a pre-incrementing stack load.  */
1507132718Skan      || !(stack_adjust == 0 || (frame_pointer_needed && stack_adjust == 4)))
150890075Sobrien    return 0;
150990075Sobrien
1510107590Sobrien  saved_int_regs = arm_compute_save_reg_mask ();
1511107590Sobrien
1512132718Skan  /* Unfortunately, the insn
1513132718Skan
1514132718Skan       ldmib sp, {..., sp, ...}
1515132718Skan
1516132718Skan     triggers a bug on most SA-110 based devices, such that the stack
1517132718Skan     pointer won't be correctly restored if the instruction takes a
1518132718Skan     page fault.  We work around this problem by popping r3 along with
1519132718Skan     the other registers, since that is never slower than executing
1520169689Skan     another instruction.
1521132718Skan
1522132718Skan     We test for !arm_arch5 here, because code for any architecture
1523132718Skan     less than this could potentially be run on one of the buggy
1524132718Skan     chips.  */
1525132718Skan  if (stack_adjust == 4 && !arm_arch5)
1526132718Skan    {
1527132718Skan      /* Validate that r3 is a call-clobbered register (always true in
1528132718Skan	 the default abi) ...  */
1529132718Skan      if (!call_used_regs[3])
1530132718Skan	return 0;
1531132718Skan
1532169689Skan      /* ... that it isn't being used for a return value ... */
1533169689Skan      if (arm_size_return_regs () >= (4 * UNITS_PER_WORD))
1534169689Skan	return 0;
1535169689Skan
1536169689Skan      /* ... or for a tail-call argument ...  */
1537132718Skan      if (sibling)
1538132718Skan	{
1539169689Skan	  gcc_assert (GET_CODE (sibling) == CALL_INSN);
1540132718Skan
1541132718Skan	  if (find_regno_fusage (sibling, USE, 3))
1542132718Skan	    return 0;
1543132718Skan	}
1544132718Skan
1545132718Skan      /* ... and that there are no call-saved registers in r0-r2
1546132718Skan	 (always true in the default ABI).  */
1547132718Skan      if (saved_int_regs & 0x7)
1548132718Skan	return 0;
1549132718Skan    }
1550132718Skan
155190075Sobrien  /* Can't be done if interworking with Thumb, and any registers have been
1552107590Sobrien     stacked.  */
1553107590Sobrien  if (TARGET_INTERWORK && saved_int_regs != 0)
155490075Sobrien    return 0;
1555107590Sobrien
1556107590Sobrien  /* On StrongARM, conditional returns are expensive if they aren't
1557107590Sobrien     taken and multiple registers have been stacked.  */
1558169689Skan  if (iscond && arm_tune_strongarm)
155990075Sobrien    {
1560169689Skan      /* Conditional return when just the LR is stored is a simple
1561107590Sobrien	 conditional-load instruction, that's not expensive.  */
1562107590Sobrien      if (saved_int_regs != 0 && saved_int_regs != (1 << LR_REGNUM))
1563107590Sobrien	return 0;
156490075Sobrien
1565169689Skan      if (flag_pic
1566169689Skan	  && arm_pic_register != INVALID_REGNUM
1567169689Skan	  && regs_ever_live[PIC_OFFSET_TABLE_REGNUM])
156890075Sobrien	return 0;
156990075Sobrien    }
1570107590Sobrien
1571107590Sobrien  /* If there are saved registers but the LR isn't saved, then we need
1572107590Sobrien     two instructions for the return.  */
1573107590Sobrien  if (saved_int_regs && !(saved_int_regs & (1 << LR_REGNUM)))
1574107590Sobrien    return 0;
1575107590Sobrien
1576132718Skan  /* Can't be done if any of the FPA regs are pushed,
157790075Sobrien     since this also requires an insn.  */
1578169689Skan  if (TARGET_HARD_FLOAT && TARGET_FPA)
1579169689Skan    for (regno = FIRST_FPA_REGNUM; regno <= LAST_FPA_REGNUM; regno++)
158090075Sobrien      if (regs_ever_live[regno] && !call_used_regs[regno])
158190075Sobrien	return 0;
158290075Sobrien
1583169689Skan  /* Likewise VFP regs.  */
1584169689Skan  if (TARGET_HARD_FLOAT && TARGET_VFP)
1585169689Skan    for (regno = FIRST_VFP_REGNUM; regno <= LAST_VFP_REGNUM; regno++)
1586169689Skan      if (regs_ever_live[regno] && !call_used_regs[regno])
1587169689Skan	return 0;
1588169689Skan
1589132718Skan  if (TARGET_REALLY_IWMMXT)
1590132718Skan    for (regno = FIRST_IWMMXT_REGNUM; regno <= LAST_IWMMXT_REGNUM; regno++)
1591132718Skan      if (regs_ever_live[regno] && ! call_used_regs [regno])
1592132718Skan	return 0;
1593132718Skan
159490075Sobrien  return 1;
159590075Sobrien}
159690075Sobrien
159790075Sobrien/* Return TRUE if int I is a valid immediate ARM constant.  */
159890075Sobrien
159990075Sobrienint
1600132718Skanconst_ok_for_arm (HOST_WIDE_INT i)
160190075Sobrien{
1602169689Skan  int lowbit;
160390075Sobrien
1604169689Skan  /* For machines with >32 bit HOST_WIDE_INT, the bits above bit 31 must
160590075Sobrien     be all zero, or all one.  */
160690075Sobrien  if ((i & ~(unsigned HOST_WIDE_INT) 0xffffffff) != 0
160790075Sobrien      && ((i & ~(unsigned HOST_WIDE_INT) 0xffffffff)
160890075Sobrien	  != ((~(unsigned HOST_WIDE_INT) 0)
160990075Sobrien	      & ~(unsigned HOST_WIDE_INT) 0xffffffff)))
161090075Sobrien    return FALSE;
1611169689Skan
1612169689Skan  i &= (unsigned HOST_WIDE_INT) 0xffffffff;
1613169689Skan
1614169689Skan  /* Fast return for 0 and small values.  We must do this for zero, since
1615169689Skan     the code below can't handle that one case.  */
1616169689Skan  if ((i & ~(unsigned HOST_WIDE_INT) 0xff) == 0)
161790075Sobrien    return TRUE;
161890075Sobrien
1619169689Skan  /* Get the number of trailing zeros, rounded down to the nearest even
1620169689Skan     number.  */
1621169689Skan  lowbit = (ffs ((int) i) - 1) & ~1;
162290075Sobrien
1623169689Skan  if ((i & ~(((unsigned HOST_WIDE_INT) 0xff) << lowbit)) == 0)
1624169689Skan    return TRUE;
1625169689Skan  else if (lowbit <= 4
1626169689Skan	   && ((i & ~0xc000003f) == 0
1627169689Skan	       || (i & ~0xf000000f) == 0
1628169689Skan	       || (i & ~0xfc000003) == 0))
1629169689Skan    return TRUE;
1630169689Skan
163190075Sobrien  return FALSE;
163290075Sobrien}
163390075Sobrien
163490075Sobrien/* Return true if I is a valid constant for the operation CODE.  */
163590075Sobrienstatic int
1636132718Skanconst_ok_for_op (HOST_WIDE_INT i, enum rtx_code code)
163790075Sobrien{
163890075Sobrien  if (const_ok_for_arm (i))
163990075Sobrien    return 1;
164090075Sobrien
164190075Sobrien  switch (code)
164290075Sobrien    {
164390075Sobrien    case PLUS:
164490075Sobrien      return const_ok_for_arm (ARM_SIGN_EXTEND (-i));
164590075Sobrien
164690075Sobrien    case MINUS:		/* Should only occur with (MINUS I reg) => rsb */
164790075Sobrien    case XOR:
164890075Sobrien    case IOR:
164990075Sobrien      return 0;
165090075Sobrien
165190075Sobrien    case AND:
165290075Sobrien      return const_ok_for_arm (ARM_SIGN_EXTEND (~i));
165390075Sobrien
165490075Sobrien    default:
1655169689Skan      gcc_unreachable ();
165690075Sobrien    }
165790075Sobrien}
165890075Sobrien
165990075Sobrien/* Emit a sequence of insns to handle a large constant.
166090075Sobrien   CODE is the code of the operation required, it can be any of SET, PLUS,
166190075Sobrien   IOR, AND, XOR, MINUS;
166290075Sobrien   MODE is the mode in which the operation is being performed;
166390075Sobrien   VAL is the integer to operate on;
166490075Sobrien   SOURCE is the other operand (a register, or a null-pointer for SET);
166590075Sobrien   SUBTARGETS means it is safe to create scratch registers if that will
166690075Sobrien   either produce a simpler sequence, or we will want to cse the values.
166790075Sobrien   Return value is the number of insns emitted.  */
166890075Sobrien
166990075Sobrienint
1670169689Skanarm_split_constant (enum rtx_code code, enum machine_mode mode, rtx insn,
1671132718Skan		    HOST_WIDE_INT val, rtx target, rtx source, int subtargets)
167290075Sobrien{
1673169689Skan  rtx cond;
1674169689Skan
1675169689Skan  if (insn && GET_CODE (PATTERN (insn)) == COND_EXEC)
1676169689Skan    cond = COND_EXEC_TEST (PATTERN (insn));
1677169689Skan  else
1678169689Skan    cond = NULL_RTX;
1679169689Skan
168090075Sobrien  if (subtargets || code == SET
168190075Sobrien      || (GET_CODE (target) == REG && GET_CODE (source) == REG
168290075Sobrien	  && REGNO (target) != REGNO (source)))
168390075Sobrien    {
168490075Sobrien      /* After arm_reorg has been called, we can't fix up expensive
1685117395Skan	 constants by pushing them into memory so we must synthesize
168690075Sobrien	 them in-line, regardless of the cost.  This is only likely to
168790075Sobrien	 be more costly on chips that have load delay slots and we are
168890075Sobrien	 compiling without running the scheduler (so no splitting
168990075Sobrien	 occurred before the final instruction emission).
169090075Sobrien
169190075Sobrien	 Ref: gcc -O1 -mcpu=strongarm gcc.c-torture/compile/980506-2.c
169290075Sobrien      */
169390075Sobrien      if (!after_arm_reorg
1694169689Skan	  && !cond
1695169689Skan	  && (arm_gen_constant (code, mode, NULL_RTX, val, target, source,
1696169689Skan				1, 0)
169790075Sobrien	      > arm_constant_limit + (code != SET)))
169890075Sobrien	{
169990075Sobrien	  if (code == SET)
170090075Sobrien	    {
170190075Sobrien	      /* Currently SET is the only monadic value for CODE, all
170290075Sobrien		 the rest are diadic.  */
1703169689Skan	      emit_set_insn (target, GEN_INT (val));
170490075Sobrien	      return 1;
170590075Sobrien	    }
170690075Sobrien	  else
170790075Sobrien	    {
170890075Sobrien	      rtx temp = subtargets ? gen_reg_rtx (mode) : target;
170990075Sobrien
1710169689Skan	      emit_set_insn (temp, GEN_INT (val));
171190075Sobrien	      /* For MINUS, the value is subtracted from, since we never
171290075Sobrien		 have subtraction of a constant.  */
171390075Sobrien	      if (code == MINUS)
1714169689Skan		emit_set_insn (target, gen_rtx_MINUS (mode, temp, source));
171590075Sobrien	      else
1716169689Skan		emit_set_insn (target,
1717169689Skan			       gen_rtx_fmt_ee (code, mode, source, temp));
171890075Sobrien	      return 2;
171990075Sobrien	    }
172090075Sobrien	}
172190075Sobrien    }
172290075Sobrien
1723169689Skan  return arm_gen_constant (code, mode, cond, val, target, source, subtargets,
1724169689Skan			   1);
172590075Sobrien}
172690075Sobrien
172790075Sobrienstatic int
1728132718Skancount_insns_for_constant (HOST_WIDE_INT remainder, int i)
172990075Sobrien{
173090075Sobrien  HOST_WIDE_INT temp1;
173190075Sobrien  int num_insns = 0;
173290075Sobrien  do
173390075Sobrien    {
173490075Sobrien      int end;
1735169689Skan
173690075Sobrien      if (i <= 0)
173790075Sobrien	i += 32;
173890075Sobrien      if (remainder & (3 << (i - 2)))
173990075Sobrien	{
174090075Sobrien	  end = i - 8;
174190075Sobrien	  if (end < 0)
174290075Sobrien	    end += 32;
174390075Sobrien	  temp1 = remainder & ((0x0ff << end)
174490075Sobrien				    | ((i < end) ? (0xff >> (32 - end)) : 0));
174590075Sobrien	  remainder &= ~temp1;
174690075Sobrien	  num_insns++;
174790075Sobrien	  i -= 6;
174890075Sobrien	}
174990075Sobrien      i -= 2;
175090075Sobrien    } while (remainder);
175190075Sobrien  return num_insns;
175290075Sobrien}
175390075Sobrien
1754169689Skan/* Emit an instruction with the indicated PATTERN.  If COND is
1755169689Skan   non-NULL, conditionalize the execution of the instruction on COND
1756169689Skan   being true.  */
1757169689Skan
1758169689Skanstatic void
1759169689Skanemit_constant_insn (rtx cond, rtx pattern)
1760169689Skan{
1761169689Skan  if (cond)
1762169689Skan    pattern = gen_rtx_COND_EXEC (VOIDmode, copy_rtx (cond), pattern);
1763169689Skan  emit_insn (pattern);
1764169689Skan}
1765169689Skan
176690075Sobrien/* As above, but extra parameter GENERATE which, if clear, suppresses
176790075Sobrien   RTL generation.  */
176890075Sobrien
176990075Sobrienstatic int
1770169689Skanarm_gen_constant (enum rtx_code code, enum machine_mode mode, rtx cond,
1771132718Skan		  HOST_WIDE_INT val, rtx target, rtx source, int subtargets,
1772132718Skan		  int generate)
177390075Sobrien{
177490075Sobrien  int can_invert = 0;
177590075Sobrien  int can_negate = 0;
177690075Sobrien  int can_negate_initial = 0;
177790075Sobrien  int can_shift = 0;
177890075Sobrien  int i;
177990075Sobrien  int num_bits_set = 0;
178090075Sobrien  int set_sign_bit_copies = 0;
178190075Sobrien  int clear_sign_bit_copies = 0;
178290075Sobrien  int clear_zero_bit_copies = 0;
178390075Sobrien  int set_zero_bit_copies = 0;
178490075Sobrien  int insns = 0;
178590075Sobrien  unsigned HOST_WIDE_INT temp1, temp2;
178690075Sobrien  unsigned HOST_WIDE_INT remainder = val & 0xffffffff;
178790075Sobrien
178890075Sobrien  /* Find out which operations are safe for a given CODE.  Also do a quick
178990075Sobrien     check for degenerate cases; these can occur when DImode operations
179090075Sobrien     are split.  */
179190075Sobrien  switch (code)
179290075Sobrien    {
179390075Sobrien    case SET:
179490075Sobrien      can_invert = 1;
179590075Sobrien      can_shift = 1;
179690075Sobrien      can_negate = 1;
179790075Sobrien      break;
179890075Sobrien
179990075Sobrien    case PLUS:
180090075Sobrien      can_negate = 1;
180190075Sobrien      can_negate_initial = 1;
180290075Sobrien      break;
180390075Sobrien
180490075Sobrien    case IOR:
180590075Sobrien      if (remainder == 0xffffffff)
180690075Sobrien	{
180790075Sobrien	  if (generate)
1808169689Skan	    emit_constant_insn (cond,
1809169689Skan				gen_rtx_SET (VOIDmode, target,
1810169689Skan					     GEN_INT (ARM_SIGN_EXTEND (val))));
181190075Sobrien	  return 1;
181290075Sobrien	}
181390075Sobrien      if (remainder == 0)
181490075Sobrien	{
181590075Sobrien	  if (reload_completed && rtx_equal_p (target, source))
181690075Sobrien	    return 0;
181790075Sobrien	  if (generate)
1818169689Skan	    emit_constant_insn (cond,
1819169689Skan				gen_rtx_SET (VOIDmode, target, source));
182090075Sobrien	  return 1;
182190075Sobrien	}
182290075Sobrien      break;
182390075Sobrien
182490075Sobrien    case AND:
182590075Sobrien      if (remainder == 0)
182690075Sobrien	{
182790075Sobrien	  if (generate)
1828169689Skan	    emit_constant_insn (cond,
1829169689Skan				gen_rtx_SET (VOIDmode, target, const0_rtx));
183090075Sobrien	  return 1;
183190075Sobrien	}
183290075Sobrien      if (remainder == 0xffffffff)
183390075Sobrien	{
183490075Sobrien	  if (reload_completed && rtx_equal_p (target, source))
183590075Sobrien	    return 0;
183690075Sobrien	  if (generate)
1837169689Skan	    emit_constant_insn (cond,
1838169689Skan				gen_rtx_SET (VOIDmode, target, source));
183990075Sobrien	  return 1;
184090075Sobrien	}
184190075Sobrien      can_invert = 1;
184290075Sobrien      break;
184390075Sobrien
184490075Sobrien    case XOR:
184590075Sobrien      if (remainder == 0)
184690075Sobrien	{
184790075Sobrien	  if (reload_completed && rtx_equal_p (target, source))
184890075Sobrien	    return 0;
184990075Sobrien	  if (generate)
1850169689Skan	    emit_constant_insn (cond,
1851169689Skan				gen_rtx_SET (VOIDmode, target, source));
185290075Sobrien	  return 1;
185390075Sobrien	}
185490075Sobrien
1855169689Skan      /* We don't know how to handle other cases yet.  */
1856169689Skan      gcc_assert (remainder == 0xffffffff);
185790075Sobrien
1858169689Skan      if (generate)
1859169689Skan	emit_constant_insn (cond,
1860169689Skan			    gen_rtx_SET (VOIDmode, target,
1861169689Skan					 gen_rtx_NOT (mode, source)));
1862169689Skan      return 1;
1863169689Skan
186490075Sobrien    case MINUS:
186590075Sobrien      /* We treat MINUS as (val - source), since (source - val) is always
186690075Sobrien	 passed as (source + (-val)).  */
186790075Sobrien      if (remainder == 0)
186890075Sobrien	{
186990075Sobrien	  if (generate)
1870169689Skan	    emit_constant_insn (cond,
1871169689Skan				gen_rtx_SET (VOIDmode, target,
1872169689Skan					     gen_rtx_NEG (mode, source)));
187390075Sobrien	  return 1;
187490075Sobrien	}
187590075Sobrien      if (const_ok_for_arm (val))
187690075Sobrien	{
187790075Sobrien	  if (generate)
1878169689Skan	    emit_constant_insn (cond,
1879169689Skan				gen_rtx_SET (VOIDmode, target,
1880169689Skan					     gen_rtx_MINUS (mode, GEN_INT (val),
1881169689Skan							    source)));
188290075Sobrien	  return 1;
188390075Sobrien	}
188490075Sobrien      can_negate = 1;
188590075Sobrien
188690075Sobrien      break;
188790075Sobrien
188890075Sobrien    default:
1889169689Skan      gcc_unreachable ();
189090075Sobrien    }
189190075Sobrien
189290075Sobrien  /* If we can do it in one insn get out quickly.  */
189390075Sobrien  if (const_ok_for_arm (val)
189490075Sobrien      || (can_negate_initial && const_ok_for_arm (-val))
189590075Sobrien      || (can_invert && const_ok_for_arm (~val)))
189690075Sobrien    {
189790075Sobrien      if (generate)
1898169689Skan	emit_constant_insn (cond,
1899169689Skan			    gen_rtx_SET (VOIDmode, target,
1900169689Skan					 (source
1901169689Skan					  ? gen_rtx_fmt_ee (code, mode, source,
1902169689Skan							    GEN_INT (val))
1903169689Skan					  : GEN_INT (val))));
190490075Sobrien      return 1;
190590075Sobrien    }
190690075Sobrien
190790075Sobrien  /* Calculate a few attributes that may be useful for specific
190890075Sobrien     optimizations.  */
190990075Sobrien  for (i = 31; i >= 0; i--)
191090075Sobrien    {
191190075Sobrien      if ((remainder & (1 << i)) == 0)
191290075Sobrien	clear_sign_bit_copies++;
191390075Sobrien      else
191490075Sobrien	break;
191590075Sobrien    }
191690075Sobrien
191790075Sobrien  for (i = 31; i >= 0; i--)
191890075Sobrien    {
191990075Sobrien      if ((remainder & (1 << i)) != 0)
192090075Sobrien	set_sign_bit_copies++;
192190075Sobrien      else
192290075Sobrien	break;
192390075Sobrien    }
192490075Sobrien
192590075Sobrien  for (i = 0; i <= 31; i++)
192690075Sobrien    {
192790075Sobrien      if ((remainder & (1 << i)) == 0)
192890075Sobrien	clear_zero_bit_copies++;
192990075Sobrien      else
193090075Sobrien	break;
193190075Sobrien    }
193290075Sobrien
193390075Sobrien  for (i = 0; i <= 31; i++)
193490075Sobrien    {
193590075Sobrien      if ((remainder & (1 << i)) != 0)
193690075Sobrien	set_zero_bit_copies++;
193790075Sobrien      else
193890075Sobrien	break;
193990075Sobrien    }
194090075Sobrien
194190075Sobrien  switch (code)
194290075Sobrien    {
194390075Sobrien    case SET:
194490075Sobrien      /* See if we can do this by sign_extending a constant that is known
194590075Sobrien	 to be negative.  This is a good, way of doing it, since the shift
194690075Sobrien	 may well merge into a subsequent insn.  */
194790075Sobrien      if (set_sign_bit_copies > 1)
194890075Sobrien	{
194990075Sobrien	  if (const_ok_for_arm
1950169689Skan	      (temp1 = ARM_SIGN_EXTEND (remainder
195190075Sobrien					<< (set_sign_bit_copies - 1))))
195290075Sobrien	    {
195390075Sobrien	      if (generate)
195490075Sobrien		{
195590075Sobrien		  rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
1956169689Skan		  emit_constant_insn (cond,
1957169689Skan				      gen_rtx_SET (VOIDmode, new_src,
1958169689Skan						   GEN_INT (temp1)));
1959169689Skan		  emit_constant_insn (cond,
1960169689Skan				      gen_ashrsi3 (target, new_src,
1961169689Skan						   GEN_INT (set_sign_bit_copies - 1)));
196290075Sobrien		}
196390075Sobrien	      return 2;
196490075Sobrien	    }
196590075Sobrien	  /* For an inverted constant, we will need to set the low bits,
196690075Sobrien	     these will be shifted out of harm's way.  */
196790075Sobrien	  temp1 |= (1 << (set_sign_bit_copies - 1)) - 1;
196890075Sobrien	  if (const_ok_for_arm (~temp1))
196990075Sobrien	    {
197090075Sobrien	      if (generate)
197190075Sobrien		{
197290075Sobrien		  rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
1973169689Skan		  emit_constant_insn (cond,
1974169689Skan				      gen_rtx_SET (VOIDmode, new_src,
1975169689Skan						   GEN_INT (temp1)));
1976169689Skan		  emit_constant_insn (cond,
1977169689Skan				      gen_ashrsi3 (target, new_src,
1978169689Skan						   GEN_INT (set_sign_bit_copies - 1)));
197990075Sobrien		}
198090075Sobrien	      return 2;
198190075Sobrien	    }
198290075Sobrien	}
198390075Sobrien
1984169689Skan      /* See if we can calculate the value as the difference between two
1985169689Skan	 valid immediates.  */
1986169689Skan      if (clear_sign_bit_copies + clear_zero_bit_copies <= 16)
1987169689Skan	{
1988169689Skan	  int topshift = clear_sign_bit_copies & ~1;
1989169689Skan
1990169689Skan	  temp1 = ARM_SIGN_EXTEND ((remainder + (0x00800000 >> topshift))
1991169689Skan				   & (0xff000000 >> topshift));
1992169689Skan
1993169689Skan	  /* If temp1 is zero, then that means the 9 most significant
1994169689Skan	     bits of remainder were 1 and we've caused it to overflow.
1995169689Skan	     When topshift is 0 we don't need to do anything since we
1996169689Skan	     can borrow from 'bit 32'.  */
1997169689Skan	  if (temp1 == 0 && topshift != 0)
1998169689Skan	    temp1 = 0x80000000 >> (topshift - 1);
1999169689Skan
2000169689Skan	  temp2 = ARM_SIGN_EXTEND (temp1 - remainder);
2001169689Skan
2002169689Skan	  if (const_ok_for_arm (temp2))
2003169689Skan	    {
2004169689Skan	      if (generate)
2005169689Skan		{
2006169689Skan		  rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
2007169689Skan		  emit_constant_insn (cond,
2008169689Skan				      gen_rtx_SET (VOIDmode, new_src,
2009169689Skan						   GEN_INT (temp1)));
2010169689Skan		  emit_constant_insn (cond,
2011169689Skan				      gen_addsi3 (target, new_src,
2012169689Skan						  GEN_INT (-temp2)));
2013169689Skan		}
2014169689Skan
2015169689Skan	      return 2;
2016169689Skan	    }
2017169689Skan	}
2018169689Skan
201990075Sobrien      /* See if we can generate this by setting the bottom (or the top)
202090075Sobrien	 16 bits, and then shifting these into the other half of the
202190075Sobrien	 word.  We only look for the simplest cases, to do more would cost
202290075Sobrien	 too much.  Be careful, however, not to generate this when the
202390075Sobrien	 alternative would take fewer insns.  */
202490075Sobrien      if (val & 0xffff0000)
202590075Sobrien	{
202690075Sobrien	  temp1 = remainder & 0xffff0000;
202790075Sobrien	  temp2 = remainder & 0x0000ffff;
202890075Sobrien
202990075Sobrien	  /* Overlaps outside this range are best done using other methods.  */
203090075Sobrien	  for (i = 9; i < 24; i++)
203190075Sobrien	    {
203290075Sobrien	      if ((((temp2 | (temp2 << i)) & 0xffffffff) == remainder)
203390075Sobrien		  && !const_ok_for_arm (temp2))
203490075Sobrien		{
203590075Sobrien		  rtx new_src = (subtargets
203690075Sobrien				 ? (generate ? gen_reg_rtx (mode) : NULL_RTX)
203790075Sobrien				 : target);
2038169689Skan		  insns = arm_gen_constant (code, mode, cond, temp2, new_src,
203990075Sobrien					    source, subtargets, generate);
204090075Sobrien		  source = new_src;
204190075Sobrien		  if (generate)
2042169689Skan		    emit_constant_insn
2043169689Skan		      (cond,
2044169689Skan		       gen_rtx_SET
2045169689Skan		       (VOIDmode, target,
2046169689Skan			gen_rtx_IOR (mode,
2047169689Skan				     gen_rtx_ASHIFT (mode, source,
2048169689Skan						     GEN_INT (i)),
2049169689Skan				     source)));
205090075Sobrien		  return insns + 1;
205190075Sobrien		}
205290075Sobrien	    }
205390075Sobrien
205490075Sobrien	  /* Don't duplicate cases already considered.  */
205590075Sobrien	  for (i = 17; i < 24; i++)
205690075Sobrien	    {
205790075Sobrien	      if (((temp1 | (temp1 >> i)) == remainder)
205890075Sobrien		  && !const_ok_for_arm (temp1))
205990075Sobrien		{
206090075Sobrien		  rtx new_src = (subtargets
206190075Sobrien				 ? (generate ? gen_reg_rtx (mode) : NULL_RTX)
206290075Sobrien				 : target);
2063169689Skan		  insns = arm_gen_constant (code, mode, cond, temp1, new_src,
206490075Sobrien					    source, subtargets, generate);
206590075Sobrien		  source = new_src;
206690075Sobrien		  if (generate)
2067169689Skan		    emit_constant_insn
2068169689Skan		      (cond,
2069169689Skan		       gen_rtx_SET (VOIDmode, target,
207090075Sobrien				    gen_rtx_IOR
207190075Sobrien				    (mode,
207290075Sobrien				     gen_rtx_LSHIFTRT (mode, source,
207390075Sobrien						       GEN_INT (i)),
207490075Sobrien				     source)));
207590075Sobrien		  return insns + 1;
207690075Sobrien		}
207790075Sobrien	    }
207890075Sobrien	}
207990075Sobrien      break;
208090075Sobrien
208190075Sobrien    case IOR:
208290075Sobrien    case XOR:
208390075Sobrien      /* If we have IOR or XOR, and the constant can be loaded in a
208490075Sobrien	 single instruction, and we can find a temporary to put it in,
208590075Sobrien	 then this can be done in two instructions instead of 3-4.  */
208690075Sobrien      if (subtargets
208790075Sobrien	  /* TARGET can't be NULL if SUBTARGETS is 0 */
208890075Sobrien	  || (reload_completed && !reg_mentioned_p (target, source)))
208990075Sobrien	{
209090075Sobrien	  if (const_ok_for_arm (ARM_SIGN_EXTEND (~val)))
209190075Sobrien	    {
209290075Sobrien	      if (generate)
209390075Sobrien		{
209490075Sobrien		  rtx sub = subtargets ? gen_reg_rtx (mode) : target;
209590075Sobrien
2096169689Skan		  emit_constant_insn (cond,
2097169689Skan				      gen_rtx_SET (VOIDmode, sub,
2098169689Skan						   GEN_INT (val)));
2099169689Skan		  emit_constant_insn (cond,
2100169689Skan				      gen_rtx_SET (VOIDmode, target,
2101169689Skan						   gen_rtx_fmt_ee (code, mode,
2102169689Skan								   source, sub)));
210390075Sobrien		}
210490075Sobrien	      return 2;
210590075Sobrien	    }
210690075Sobrien	}
210790075Sobrien
210890075Sobrien      if (code == XOR)
210990075Sobrien	break;
211090075Sobrien
211190075Sobrien      if (set_sign_bit_copies > 8
211290075Sobrien	  && (val & (-1 << (32 - set_sign_bit_copies))) == val)
211390075Sobrien	{
211490075Sobrien	  if (generate)
211590075Sobrien	    {
211690075Sobrien	      rtx sub = subtargets ? gen_reg_rtx (mode) : target;
211790075Sobrien	      rtx shift = GEN_INT (set_sign_bit_copies);
211890075Sobrien
2119169689Skan	      emit_constant_insn
2120169689Skan		(cond,
2121169689Skan		 gen_rtx_SET (VOIDmode, sub,
2122169689Skan			      gen_rtx_NOT (mode,
2123169689Skan					   gen_rtx_ASHIFT (mode,
2124169689Skan							   source,
2125169689Skan							   shift))));
2126169689Skan	      emit_constant_insn
2127169689Skan		(cond,
2128169689Skan		 gen_rtx_SET (VOIDmode, target,
2129169689Skan			      gen_rtx_NOT (mode,
2130169689Skan					   gen_rtx_LSHIFTRT (mode, sub,
2131169689Skan							     shift))));
213290075Sobrien	    }
213390075Sobrien	  return 2;
213490075Sobrien	}
213590075Sobrien
213690075Sobrien      if (set_zero_bit_copies > 8
213790075Sobrien	  && (remainder & ((1 << set_zero_bit_copies) - 1)) == remainder)
213890075Sobrien	{
213990075Sobrien	  if (generate)
214090075Sobrien	    {
214190075Sobrien	      rtx sub = subtargets ? gen_reg_rtx (mode) : target;
214290075Sobrien	      rtx shift = GEN_INT (set_zero_bit_copies);
214390075Sobrien
2144169689Skan	      emit_constant_insn
2145169689Skan		(cond,
2146169689Skan		 gen_rtx_SET (VOIDmode, sub,
2147169689Skan			      gen_rtx_NOT (mode,
2148169689Skan					   gen_rtx_LSHIFTRT (mode,
2149169689Skan							     source,
2150169689Skan							     shift))));
2151169689Skan	      emit_constant_insn
2152169689Skan		(cond,
2153169689Skan		 gen_rtx_SET (VOIDmode, target,
2154169689Skan			      gen_rtx_NOT (mode,
2155169689Skan					   gen_rtx_ASHIFT (mode, sub,
2156169689Skan							   shift))));
215790075Sobrien	    }
215890075Sobrien	  return 2;
215990075Sobrien	}
216090075Sobrien
216190075Sobrien      if (const_ok_for_arm (temp1 = ARM_SIGN_EXTEND (~val)))
216290075Sobrien	{
216390075Sobrien	  if (generate)
216490075Sobrien	    {
216590075Sobrien	      rtx sub = subtargets ? gen_reg_rtx (mode) : target;
2166169689Skan	      emit_constant_insn (cond,
2167169689Skan				  gen_rtx_SET (VOIDmode, sub,
2168169689Skan					       gen_rtx_NOT (mode, source)));
216990075Sobrien	      source = sub;
217090075Sobrien	      if (subtargets)
217190075Sobrien		sub = gen_reg_rtx (mode);
2172169689Skan	      emit_constant_insn (cond,
2173169689Skan				  gen_rtx_SET (VOIDmode, sub,
2174169689Skan					       gen_rtx_AND (mode, source,
2175169689Skan							    GEN_INT (temp1))));
2176169689Skan	      emit_constant_insn (cond,
2177169689Skan				  gen_rtx_SET (VOIDmode, target,
2178169689Skan					       gen_rtx_NOT (mode, sub)));
217990075Sobrien	    }
218090075Sobrien	  return 3;
218190075Sobrien	}
218290075Sobrien      break;
218390075Sobrien
218490075Sobrien    case AND:
218590075Sobrien      /* See if two shifts will do 2 or more insn's worth of work.  */
218690075Sobrien      if (clear_sign_bit_copies >= 16 && clear_sign_bit_copies < 24)
218790075Sobrien	{
218890075Sobrien	  HOST_WIDE_INT shift_mask = ((0xffffffff
218990075Sobrien				       << (32 - clear_sign_bit_copies))
219090075Sobrien				      & 0xffffffff);
219190075Sobrien
219290075Sobrien	  if ((remainder | shift_mask) != 0xffffffff)
219390075Sobrien	    {
219490075Sobrien	      if (generate)
219590075Sobrien		{
219690075Sobrien		  rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
2197169689Skan		  insns = arm_gen_constant (AND, mode, cond,
2198169689Skan					    remainder | shift_mask,
219990075Sobrien					    new_src, source, subtargets, 1);
220090075Sobrien		  source = new_src;
220190075Sobrien		}
220290075Sobrien	      else
220390075Sobrien		{
220490075Sobrien		  rtx targ = subtargets ? NULL_RTX : target;
2205169689Skan		  insns = arm_gen_constant (AND, mode, cond,
2206169689Skan					    remainder | shift_mask,
220790075Sobrien					    targ, source, subtargets, 0);
220890075Sobrien		}
220990075Sobrien	    }
221090075Sobrien
221190075Sobrien	  if (generate)
221290075Sobrien	    {
221390075Sobrien	      rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
221490075Sobrien	      rtx shift = GEN_INT (clear_sign_bit_copies);
221590075Sobrien
221690075Sobrien	      emit_insn (gen_ashlsi3 (new_src, source, shift));
221790075Sobrien	      emit_insn (gen_lshrsi3 (target, new_src, shift));
221890075Sobrien	    }
221990075Sobrien
222090075Sobrien	  return insns + 2;
222190075Sobrien	}
222290075Sobrien
222390075Sobrien      if (clear_zero_bit_copies >= 16 && clear_zero_bit_copies < 24)
222490075Sobrien	{
222590075Sobrien	  HOST_WIDE_INT shift_mask = (1 << clear_zero_bit_copies) - 1;
2226169689Skan
222790075Sobrien	  if ((remainder | shift_mask) != 0xffffffff)
222890075Sobrien	    {
222990075Sobrien	      if (generate)
223090075Sobrien		{
223190075Sobrien		  rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
223290075Sobrien
2233169689Skan		  insns = arm_gen_constant (AND, mode, cond,
2234169689Skan					    remainder | shift_mask,
223590075Sobrien					    new_src, source, subtargets, 1);
223690075Sobrien		  source = new_src;
223790075Sobrien		}
223890075Sobrien	      else
223990075Sobrien		{
224090075Sobrien		  rtx targ = subtargets ? NULL_RTX : target;
224190075Sobrien
2242169689Skan		  insns = arm_gen_constant (AND, mode, cond,
2243169689Skan					    remainder | shift_mask,
224490075Sobrien					    targ, source, subtargets, 0);
224590075Sobrien		}
224690075Sobrien	    }
224790075Sobrien
224890075Sobrien	  if (generate)
224990075Sobrien	    {
225090075Sobrien	      rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
225190075Sobrien	      rtx shift = GEN_INT (clear_zero_bit_copies);
225290075Sobrien
225390075Sobrien	      emit_insn (gen_lshrsi3 (new_src, source, shift));
225490075Sobrien	      emit_insn (gen_ashlsi3 (target, new_src, shift));
225590075Sobrien	    }
225690075Sobrien
225790075Sobrien	  return insns + 2;
225890075Sobrien	}
225990075Sobrien
226090075Sobrien      break;
226190075Sobrien
226290075Sobrien    default:
226390075Sobrien      break;
226490075Sobrien    }
226590075Sobrien
226690075Sobrien  for (i = 0; i < 32; i++)
226790075Sobrien    if (remainder & (1 << i))
226890075Sobrien      num_bits_set++;
226990075Sobrien
227090075Sobrien  if (code == AND || (can_invert && num_bits_set > 16))
227190075Sobrien    remainder = (~remainder) & 0xffffffff;
227290075Sobrien  else if (code == PLUS && num_bits_set > 16)
227390075Sobrien    remainder = (-remainder) & 0xffffffff;
227490075Sobrien  else
227590075Sobrien    {
227690075Sobrien      can_invert = 0;
227790075Sobrien      can_negate = 0;
227890075Sobrien    }
227990075Sobrien
228090075Sobrien  /* Now try and find a way of doing the job in either two or three
228190075Sobrien     instructions.
228290075Sobrien     We start by looking for the largest block of zeros that are aligned on
228390075Sobrien     a 2-bit boundary, we then fill up the temps, wrapping around to the
228490075Sobrien     top of the word when we drop off the bottom.
228590075Sobrien     In the worst case this code should produce no more than four insns.  */
228690075Sobrien  {
228790075Sobrien    int best_start = 0;
228890075Sobrien    int best_consecutive_zeros = 0;
228990075Sobrien
229090075Sobrien    for (i = 0; i < 32; i += 2)
229190075Sobrien      {
229290075Sobrien	int consecutive_zeros = 0;
229390075Sobrien
229490075Sobrien	if (!(remainder & (3 << i)))
229590075Sobrien	  {
229690075Sobrien	    while ((i < 32) && !(remainder & (3 << i)))
229790075Sobrien	      {
229890075Sobrien		consecutive_zeros += 2;
229990075Sobrien		i += 2;
230090075Sobrien	      }
230190075Sobrien	    if (consecutive_zeros > best_consecutive_zeros)
230290075Sobrien	      {
230390075Sobrien		best_consecutive_zeros = consecutive_zeros;
230490075Sobrien		best_start = i - consecutive_zeros;
230590075Sobrien	      }
230690075Sobrien	    i -= 2;
230790075Sobrien	  }
230890075Sobrien      }
230990075Sobrien
231090075Sobrien    /* So long as it won't require any more insns to do so, it's
231190075Sobrien       desirable to emit a small constant (in bits 0...9) in the last
231290075Sobrien       insn.  This way there is more chance that it can be combined with
231390075Sobrien       a later addressing insn to form a pre-indexed load or store
231490075Sobrien       operation.  Consider:
231590075Sobrien
231690075Sobrien	       *((volatile int *)0xe0000100) = 1;
231790075Sobrien	       *((volatile int *)0xe0000110) = 2;
231890075Sobrien
231990075Sobrien       We want this to wind up as:
232090075Sobrien
232190075Sobrien		mov rA, #0xe0000000
232290075Sobrien		mov rB, #1
232390075Sobrien		str rB, [rA, #0x100]
232490075Sobrien		mov rB, #2
232590075Sobrien		str rB, [rA, #0x110]
232690075Sobrien
232790075Sobrien       rather than having to synthesize both large constants from scratch.
232890075Sobrien
232990075Sobrien       Therefore, we calculate how many insns would be required to emit
2330169689Skan       the constant starting from `best_start', and also starting from
2331169689Skan       zero (i.e. with bit 31 first to be output).  If `best_start' doesn't
233290075Sobrien       yield a shorter sequence, we may as well use zero.  */
233390075Sobrien    if (best_start != 0
233490075Sobrien	&& ((((unsigned HOST_WIDE_INT) 1) << best_start) < remainder)
2335169689Skan	&& (count_insns_for_constant (remainder, 0) <=
233690075Sobrien	    count_insns_for_constant (remainder, best_start)))
233790075Sobrien      best_start = 0;
233890075Sobrien
233990075Sobrien    /* Now start emitting the insns.  */
234090075Sobrien    i = best_start;
234190075Sobrien    do
234290075Sobrien      {
234390075Sobrien	int end;
234490075Sobrien
234590075Sobrien	if (i <= 0)
234690075Sobrien	  i += 32;
234790075Sobrien	if (remainder & (3 << (i - 2)))
234890075Sobrien	  {
234990075Sobrien	    end = i - 8;
235090075Sobrien	    if (end < 0)
235190075Sobrien	      end += 32;
235290075Sobrien	    temp1 = remainder & ((0x0ff << end)
235390075Sobrien				 | ((i < end) ? (0xff >> (32 - end)) : 0));
235490075Sobrien	    remainder &= ~temp1;
235590075Sobrien
235690075Sobrien	    if (generate)
235790075Sobrien	      {
235890075Sobrien		rtx new_src, temp1_rtx;
235990075Sobrien
236090075Sobrien		if (code == SET || code == MINUS)
236190075Sobrien		  {
236290075Sobrien		    new_src = (subtargets ? gen_reg_rtx (mode) : target);
236390075Sobrien		    if (can_invert && code != MINUS)
236490075Sobrien		      temp1 = ~temp1;
236590075Sobrien		  }
236690075Sobrien		else
236790075Sobrien		  {
236890075Sobrien		    if (remainder && subtargets)
236990075Sobrien		      new_src = gen_reg_rtx (mode);
237090075Sobrien		    else
237190075Sobrien		      new_src = target;
237290075Sobrien		    if (can_invert)
237390075Sobrien		      temp1 = ~temp1;
237490075Sobrien		    else if (can_negate)
237590075Sobrien		      temp1 = -temp1;
237690075Sobrien		  }
237790075Sobrien
237890075Sobrien		temp1 = trunc_int_for_mode (temp1, mode);
237990075Sobrien		temp1_rtx = GEN_INT (temp1);
238090075Sobrien
238190075Sobrien		if (code == SET)
238290075Sobrien		  ;
238390075Sobrien		else if (code == MINUS)
238490075Sobrien		  temp1_rtx = gen_rtx_MINUS (mode, temp1_rtx, source);
238590075Sobrien		else
238690075Sobrien		  temp1_rtx = gen_rtx_fmt_ee (code, mode, source, temp1_rtx);
238790075Sobrien
2388169689Skan		emit_constant_insn (cond,
2389169689Skan				    gen_rtx_SET (VOIDmode, new_src,
2390169689Skan						 temp1_rtx));
239190075Sobrien		source = new_src;
239290075Sobrien	      }
239390075Sobrien
239490075Sobrien	    if (code == SET)
239590075Sobrien	      {
239690075Sobrien		can_invert = 0;
239790075Sobrien		code = PLUS;
239890075Sobrien	      }
239990075Sobrien	    else if (code == MINUS)
240090075Sobrien	      code = PLUS;
240190075Sobrien
240290075Sobrien	    insns++;
240390075Sobrien	    i -= 6;
240490075Sobrien	  }
240590075Sobrien	i -= 2;
240690075Sobrien      }
240790075Sobrien    while (remainder);
240890075Sobrien  }
240990075Sobrien
241090075Sobrien  return insns;
241190075Sobrien}
241290075Sobrien
241390075Sobrien/* Canonicalize a comparison so that we are more likely to recognize it.
241490075Sobrien   This can be done for a few constant compares, where we can make the
241590075Sobrien   immediate value easier to load.  */
241690075Sobrien
241790075Sobrienenum rtx_code
2418169689Skanarm_canonicalize_comparison (enum rtx_code code, enum machine_mode mode,
2419169689Skan			     rtx * op1)
242090075Sobrien{
242190075Sobrien  unsigned HOST_WIDE_INT i = INTVAL (*op1);
2422169689Skan  unsigned HOST_WIDE_INT maxval;
2423169689Skan  maxval = (((unsigned HOST_WIDE_INT) 1) << (GET_MODE_BITSIZE(mode) - 1)) - 1;
242490075Sobrien
242590075Sobrien  switch (code)
242690075Sobrien    {
242790075Sobrien    case EQ:
242890075Sobrien    case NE:
242990075Sobrien      return code;
243090075Sobrien
243190075Sobrien    case GT:
243290075Sobrien    case LE:
2433169689Skan      if (i != maxval
243490075Sobrien	  && (const_ok_for_arm (i + 1) || const_ok_for_arm (-(i + 1))))
243590075Sobrien	{
243690075Sobrien	  *op1 = GEN_INT (i + 1);
243790075Sobrien	  return code == GT ? GE : LT;
243890075Sobrien	}
243990075Sobrien      break;
244090075Sobrien
244190075Sobrien    case GE:
244290075Sobrien    case LT:
2443169689Skan      if (i != ~maxval
244490075Sobrien	  && (const_ok_for_arm (i - 1) || const_ok_for_arm (-(i - 1))))
244590075Sobrien	{
244690075Sobrien	  *op1 = GEN_INT (i - 1);
244790075Sobrien	  return code == GE ? GT : LE;
244890075Sobrien	}
244990075Sobrien      break;
245090075Sobrien
245190075Sobrien    case GTU:
245290075Sobrien    case LEU:
245390075Sobrien      if (i != ~((unsigned HOST_WIDE_INT) 0)
245490075Sobrien	  && (const_ok_for_arm (i + 1) || const_ok_for_arm (-(i + 1))))
245590075Sobrien	{
245690075Sobrien	  *op1 = GEN_INT (i + 1);
245790075Sobrien	  return code == GTU ? GEU : LTU;
245890075Sobrien	}
245990075Sobrien      break;
246090075Sobrien
246190075Sobrien    case GEU:
246290075Sobrien    case LTU:
246390075Sobrien      if (i != 0
246490075Sobrien	  && (const_ok_for_arm (i - 1) || const_ok_for_arm (-(i - 1))))
246590075Sobrien	{
246690075Sobrien	  *op1 = GEN_INT (i - 1);
246790075Sobrien	  return code == GEU ? GTU : LEU;
246890075Sobrien	}
246990075Sobrien      break;
247090075Sobrien
247190075Sobrien    default:
2472169689Skan      gcc_unreachable ();
247390075Sobrien    }
247490075Sobrien
247590075Sobrien  return code;
247690075Sobrien}
247790075Sobrien
2478169689Skan
2479169689Skan/* Define how to find the value returned by a function.  */
2480169689Skan
2481169689Skanrtx
2482169689Skanarm_function_value(tree type, tree func ATTRIBUTE_UNUSED)
2483169689Skan{
2484169689Skan  enum machine_mode mode;
2485169689Skan  int unsignedp ATTRIBUTE_UNUSED;
2486169689Skan  rtx r ATTRIBUTE_UNUSED;
2487169689Skan
2488169689Skan  mode = TYPE_MODE (type);
2489169689Skan  /* Promote integer types.  */
2490169689Skan  if (INTEGRAL_TYPE_P (type))
2491169689Skan    PROMOTE_FUNCTION_MODE (mode, unsignedp, type);
2492169689Skan
2493169689Skan  /* Promotes small structs returned in a register to full-word size
2494169689Skan     for big-endian AAPCS.  */
2495169689Skan  if (arm_return_in_msb (type))
2496169689Skan    {
2497169689Skan      HOST_WIDE_INT size = int_size_in_bytes (type);
2498169689Skan      if (size % UNITS_PER_WORD != 0)
2499169689Skan	{
2500169689Skan	  size += UNITS_PER_WORD - size % UNITS_PER_WORD;
2501169689Skan	  mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0);
2502169689Skan	}
2503169689Skan    }
2504169689Skan
2505169689Skan  return LIBCALL_VALUE(mode);
2506169689Skan}
2507169689Skan
2508169689Skan/* Determine the amount of memory needed to store the possible return
2509169689Skan   registers of an untyped call.  */
2510169689Skanint
2511169689Skanarm_apply_result_size (void)
2512169689Skan{
2513169689Skan  int size = 16;
2514169689Skan
2515169689Skan  if (TARGET_ARM)
2516169689Skan    {
2517169689Skan      if (TARGET_HARD_FLOAT_ABI)
2518169689Skan	{
2519169689Skan	  if (TARGET_FPA)
2520169689Skan	    size += 12;
2521169689Skan	  if (TARGET_MAVERICK)
2522169689Skan	    size += 8;
2523169689Skan	}
2524169689Skan      if (TARGET_IWMMXT_ABI)
2525169689Skan	size += 8;
2526169689Skan    }
2527169689Skan
2528169689Skan  return size;
2529169689Skan}
2530169689Skan
253190075Sobrien/* Decide whether a type should be returned in memory (true)
253290075Sobrien   or in a register (false).  This is called by the macro
253390075Sobrien   RETURN_IN_MEMORY.  */
253490075Sobrienint
2535132718Skanarm_return_in_memory (tree type)
253690075Sobrien{
2537117395Skan  HOST_WIDE_INT size;
2538117395Skan
2539169689Skan  if (!AGGREGATE_TYPE_P (type) &&
2540169689Skan      (TREE_CODE (type) != VECTOR_TYPE) &&
2541169689Skan      !(TARGET_AAPCS_BASED && TREE_CODE (type) == COMPLEX_TYPE))
2542169689Skan    /* All simple types are returned in registers.
2543169689Skan       For AAPCS, complex types are treated the same as aggregates.  */
254490075Sobrien    return 0;
2545117395Skan
2546117395Skan  size = int_size_in_bytes (type);
2547117395Skan
2548169689Skan  if (arm_abi != ARM_ABI_APCS)
2549117395Skan    {
2550169689Skan      /* ATPCS and later return aggregate types in memory only if they are
2551117395Skan	 larger than a word (or are variable size).  */
2552117395Skan      return (size < 0 || size > UNITS_PER_WORD);
2553117395Skan    }
2554169689Skan
2555169689Skan  /* To maximize backwards compatibility with previous versions of gcc,
2556169689Skan     return vectors up to 4 words in registers.  */
2557169689Skan  if (TREE_CODE (type) == VECTOR_TYPE)
2558169689Skan    return (size < 0 || size > (4 * UNITS_PER_WORD));
2559169689Skan
2560132718Skan  /* For the arm-wince targets we choose to be compatible with Microsoft's
256190075Sobrien     ARM and Thumb compilers, which always return aggregates in memory.  */
256290075Sobrien#ifndef ARM_WINCE
256390075Sobrien  /* All structures/unions bigger than one word are returned in memory.
256490075Sobrien     Also catch the case where int_size_in_bytes returns -1.  In this case
2565132718Skan     the aggregate is either huge or of variable size, and in either case
256690075Sobrien     we will want to return it via memory and not in a register.  */
2567117395Skan  if (size < 0 || size > UNITS_PER_WORD)
256890075Sobrien    return 1;
2569169689Skan
257090075Sobrien  if (TREE_CODE (type) == RECORD_TYPE)
257190075Sobrien    {
257290075Sobrien      tree field;
257390075Sobrien
257490075Sobrien      /* For a struct the APCS says that we only return in a register
257590075Sobrien	 if the type is 'integer like' and every addressable element
257690075Sobrien	 has an offset of zero.  For practical purposes this means
257790075Sobrien	 that the structure can have at most one non bit-field element
257890075Sobrien	 and that this element must be the first one in the structure.  */
2579169689Skan
258090075Sobrien      /* Find the first field, ignoring non FIELD_DECL things which will
258190075Sobrien	 have been created by C++.  */
258290075Sobrien      for (field = TYPE_FIELDS (type);
258390075Sobrien	   field && TREE_CODE (field) != FIELD_DECL;
258490075Sobrien	   field = TREE_CHAIN (field))
258590075Sobrien	continue;
2586169689Skan
258790075Sobrien      if (field == NULL)
258890075Sobrien	return 0; /* An empty structure.  Allowed by an extension to ANSI C.  */
258990075Sobrien
259090075Sobrien      /* Check that the first field is valid for returning in a register.  */
259190075Sobrien
259290075Sobrien      /* ... Floats are not allowed */
259390075Sobrien      if (FLOAT_TYPE_P (TREE_TYPE (field)))
259490075Sobrien	return 1;
259590075Sobrien
259690075Sobrien      /* ... Aggregates that are not themselves valid for returning in
259790075Sobrien	 a register are not allowed.  */
259890075Sobrien      if (RETURN_IN_MEMORY (TREE_TYPE (field)))
259990075Sobrien	return 1;
260090075Sobrien
260190075Sobrien      /* Now check the remaining fields, if any.  Only bitfields are allowed,
260290075Sobrien	 since they are not addressable.  */
260390075Sobrien      for (field = TREE_CHAIN (field);
260490075Sobrien	   field;
260590075Sobrien	   field = TREE_CHAIN (field))
260690075Sobrien	{
260790075Sobrien	  if (TREE_CODE (field) != FIELD_DECL)
260890075Sobrien	    continue;
2609169689Skan
261090075Sobrien	  if (!DECL_BIT_FIELD_TYPE (field))
261190075Sobrien	    return 1;
261290075Sobrien	}
261390075Sobrien
261490075Sobrien      return 0;
261590075Sobrien    }
2616169689Skan
261790075Sobrien  if (TREE_CODE (type) == UNION_TYPE)
261890075Sobrien    {
261990075Sobrien      tree field;
262090075Sobrien
262190075Sobrien      /* Unions can be returned in registers if every element is
262290075Sobrien	 integral, or can be returned in an integer register.  */
262390075Sobrien      for (field = TYPE_FIELDS (type);
262490075Sobrien	   field;
262590075Sobrien	   field = TREE_CHAIN (field))
262690075Sobrien	{
262790075Sobrien	  if (TREE_CODE (field) != FIELD_DECL)
262890075Sobrien	    continue;
262990075Sobrien
263090075Sobrien	  if (FLOAT_TYPE_P (TREE_TYPE (field)))
263190075Sobrien	    return 1;
2632169689Skan
263390075Sobrien	  if (RETURN_IN_MEMORY (TREE_TYPE (field)))
263490075Sobrien	    return 1;
263590075Sobrien	}
2636169689Skan
263790075Sobrien      return 0;
263890075Sobrien    }
2639169689Skan#endif /* not ARM_WINCE */
2640169689Skan
264190075Sobrien  /* Return all other types in memory.  */
264290075Sobrien  return 1;
264390075Sobrien}
264490075Sobrien
2645132718Skan/* Indicate whether or not words of a double are in big-endian order.  */
2646117395Skan
2647117395Skanint
2648132718Skanarm_float_words_big_endian (void)
2649117395Skan{
2650169689Skan  if (TARGET_MAVERICK)
2651132718Skan    return 0;
2652117395Skan
2653117395Skan  /* For FPA, float words are always big-endian.  For VFP, floats words
2654117395Skan     follow the memory system mode.  */
2655117395Skan
2656169689Skan  if (TARGET_FPA)
2657117395Skan    {
2658117395Skan      return 1;
2659117395Skan    }
2660117395Skan
2661117395Skan  if (TARGET_VFP)
2662117395Skan    return (TARGET_BIG_END ? 1 : 0);
2663117395Skan
2664117395Skan  return 1;
2665117395Skan}
2666117395Skan
266790075Sobrien/* Initialize a variable CUM of type CUMULATIVE_ARGS
266890075Sobrien   for a call to a function whose data type is FNTYPE.
266990075Sobrien   For a library call, FNTYPE is NULL.  */
267090075Sobrienvoid
2671169689Skanarm_init_cumulative_args (CUMULATIVE_ARGS *pcum, tree fntype,
2672132718Skan			  rtx libname  ATTRIBUTE_UNUSED,
2673132718Skan			  tree fndecl ATTRIBUTE_UNUSED)
267490075Sobrien{
267590075Sobrien  /* On the ARM, the offset starts at 0.  */
2676169689Skan  pcum->nregs = 0;
2677132718Skan  pcum->iwmmxt_nregs = 0;
2678169689Skan  pcum->can_split = true;
2679169689Skan
268090075Sobrien  pcum->call_cookie = CALL_NORMAL;
268190075Sobrien
268290075Sobrien  if (TARGET_LONG_CALLS)
268390075Sobrien    pcum->call_cookie = CALL_LONG;
2684169689Skan
268590075Sobrien  /* Check for long call/short call attributes.  The attributes
268690075Sobrien     override any command line option.  */
268790075Sobrien  if (fntype)
268890075Sobrien    {
268990075Sobrien      if (lookup_attribute ("short_call", TYPE_ATTRIBUTES (fntype)))
269090075Sobrien	pcum->call_cookie = CALL_SHORT;
269190075Sobrien      else if (lookup_attribute ("long_call", TYPE_ATTRIBUTES (fntype)))
269290075Sobrien	pcum->call_cookie = CALL_LONG;
269390075Sobrien    }
2694132718Skan
2695132718Skan  /* Varargs vectors are treated the same as long long.
2696132718Skan     named_count avoids having to change the way arm handles 'named' */
2697132718Skan  pcum->named_count = 0;
2698132718Skan  pcum->nargs = 0;
2699132718Skan
2700132718Skan  if (TARGET_REALLY_IWMMXT && fntype)
2701132718Skan    {
2702132718Skan      tree fn_arg;
2703132718Skan
2704132718Skan      for (fn_arg = TYPE_ARG_TYPES (fntype);
2705132718Skan	   fn_arg;
2706132718Skan	   fn_arg = TREE_CHAIN (fn_arg))
2707132718Skan	pcum->named_count += 1;
2708132718Skan
2709132718Skan      if (! pcum->named_count)
2710132718Skan	pcum->named_count = INT_MAX;
2711132718Skan    }
271290075Sobrien}
271390075Sobrien
2714169689Skan
2715169689Skan/* Return true if mode/type need doubleword alignment.  */
2716169689Skanbool
2717169689Skanarm_needs_doubleword_align (enum machine_mode mode, tree type)
2718169689Skan{
2719169689Skan  return (GET_MODE_ALIGNMENT (mode) > PARM_BOUNDARY
2720169689Skan	  || (type && TYPE_ALIGN (type) > PARM_BOUNDARY));
2721169689Skan}
2722169689Skan
2723169689Skan
272490075Sobrien/* Determine where to put an argument to a function.
272590075Sobrien   Value is zero to push the argument on the stack,
272690075Sobrien   or a hard register in which to store the argument.
272790075Sobrien
272890075Sobrien   MODE is the argument's machine mode.
272990075Sobrien   TYPE is the data type of the argument (as a tree).
273090075Sobrien    This is null for libcalls where that information may
273190075Sobrien    not be available.
273290075Sobrien   CUM is a variable of type CUMULATIVE_ARGS which gives info about
273390075Sobrien    the preceding args and about the function being called.
273490075Sobrien   NAMED is nonzero if this argument is a named parameter
273590075Sobrien    (otherwise it is an extra parameter matching an ellipsis).  */
273690075Sobrien
273790075Sobrienrtx
2738132718Skanarm_function_arg (CUMULATIVE_ARGS *pcum, enum machine_mode mode,
2739169689Skan		  tree type, int named)
274090075Sobrien{
2741169689Skan  int nregs;
2742169689Skan
2743169689Skan  /* Varargs vectors are treated the same as long long.
2744169689Skan     named_count avoids having to change the way arm handles 'named' */
2745169689Skan  if (TARGET_IWMMXT_ABI
2746169689Skan      && arm_vector_mode_supported_p (mode)
2747169689Skan      && pcum->named_count > pcum->nargs + 1)
2748132718Skan    {
2749169689Skan      if (pcum->iwmmxt_nregs <= 9)
2750169689Skan	return gen_rtx_REG (mode, pcum->iwmmxt_nregs + FIRST_IWMMXT_REGNUM);
2751169689Skan      else
2752132718Skan	{
2753169689Skan	  pcum->can_split = false;
2754169689Skan	  return NULL_RTX;
2755132718Skan	}
2756132718Skan    }
2757132718Skan
2758169689Skan  /* Put doubleword aligned quantities in even register pairs.  */
2759169689Skan  if (pcum->nregs & 1
2760169689Skan      && ARM_DOUBLEWORD_ALIGN
2761169689Skan      && arm_needs_doubleword_align (mode, type))
2762169689Skan    pcum->nregs++;
2763169689Skan
276490075Sobrien  if (mode == VOIDmode)
276590075Sobrien    /* Compute operand 2 of the call insn.  */
276690075Sobrien    return GEN_INT (pcum->call_cookie);
2767169689Skan
2768169689Skan  /* Only allow splitting an arg between regs and memory if all preceding
2769169689Skan     args were allocated to regs.  For args passed by reference we only count
2770169689Skan     the reference pointer.  */
2771169689Skan  if (pcum->can_split)
2772169689Skan    nregs = 1;
2773169689Skan  else
2774169689Skan    nregs = ARM_NUM_REGS2 (mode, type);
2775169689Skan
2776169689Skan  if (!named || pcum->nregs + nregs > NUM_ARG_REGS)
277790075Sobrien    return NULL_RTX;
2778169689Skan
277990075Sobrien  return gen_rtx_REG (mode, pcum->nregs);
278090075Sobrien}
2781117395Skan
2782169689Skanstatic int
2783169689Skanarm_arg_partial_bytes (CUMULATIVE_ARGS *pcum, enum machine_mode mode,
2784169689Skan		       tree type, bool named ATTRIBUTE_UNUSED)
2785117395Skan{
2786169689Skan  int nregs = pcum->nregs;
2787117395Skan
2788169689Skan  if (arm_vector_mode_supported_p (mode))
2789169689Skan    return 0;
2790117395Skan
2791169689Skan  if (NUM_ARG_REGS > nregs
2792169689Skan      && (NUM_ARG_REGS < nregs + ARM_NUM_REGS2 (mode, type))
2793169689Skan      && pcum->can_split)
2794169689Skan    return (NUM_ARG_REGS - nregs) * UNITS_PER_WORD;
2795117395Skan
2796169689Skan  return 0;
2797169689Skan}
2798132718Skan
2799169689Skan/* Variable sized types are passed by reference.  This is a GCC
2800169689Skan   extension to the ARM ABI.  */
2801132718Skan
2802169689Skanstatic bool
2803169689Skanarm_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
2804169689Skan		       enum machine_mode mode ATTRIBUTE_UNUSED,
2805169689Skan		       tree type, bool named ATTRIBUTE_UNUSED)
2806169689Skan{
2807169689Skan  return type && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST;
2808117395Skan}
280990075Sobrien
281090075Sobrien/* Encode the current state of the #pragma [no_]long_calls.  */
281190075Sobrientypedef enum
281290075Sobrien{
2813169689Skan  OFF,		/* No #pragma [no_]long_calls is in effect.  */
281490075Sobrien  LONG,		/* #pragma long_calls is in effect.  */
281590075Sobrien  SHORT		/* #pragma no_long_calls is in effect.  */
281690075Sobrien} arm_pragma_enum;
281790075Sobrien
281890075Sobrienstatic arm_pragma_enum arm_pragma_long_calls = OFF;
281990075Sobrien
282090075Sobrienvoid
2821132718Skanarm_pr_long_calls (struct cpp_reader * pfile ATTRIBUTE_UNUSED)
282290075Sobrien{
282390075Sobrien  arm_pragma_long_calls = LONG;
282490075Sobrien}
282590075Sobrien
282690075Sobrienvoid
2827132718Skanarm_pr_no_long_calls (struct cpp_reader * pfile ATTRIBUTE_UNUSED)
282890075Sobrien{
282990075Sobrien  arm_pragma_long_calls = SHORT;
283090075Sobrien}
283190075Sobrien
283290075Sobrienvoid
2833132718Skanarm_pr_long_calls_off (struct cpp_reader * pfile ATTRIBUTE_UNUSED)
283490075Sobrien{
283590075Sobrien  arm_pragma_long_calls = OFF;
283690075Sobrien}
283790075Sobrien
283890075Sobrien/* Table of machine attributes.  */
283990075Sobrienconst struct attribute_spec arm_attribute_table[] =
284090075Sobrien{
284190075Sobrien  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
284290075Sobrien  /* Function calls made to this symbol must be done indirectly, because
284390075Sobrien     it may lie outside of the 26 bit addressing range of a normal function
284490075Sobrien     call.  */
284590075Sobrien  { "long_call",    0, 0, false, true,  true,  NULL },
284690075Sobrien  /* Whereas these functions are always known to reside within the 26 bit
284790075Sobrien     addressing range.  */
284890075Sobrien  { "short_call",   0, 0, false, true,  true,  NULL },
2849169689Skan  /* Interrupt Service Routines have special prologue and epilogue requirements.  */
285090075Sobrien  { "isr",          0, 1, false, false, false, arm_handle_isr_attribute },
285190075Sobrien  { "interrupt",    0, 1, false, false, false, arm_handle_isr_attribute },
285290075Sobrien  { "naked",        0, 0, true,  false, false, arm_handle_fndecl_attribute },
285390075Sobrien#ifdef ARM_PE
285490075Sobrien  /* ARM/PE has three new attributes:
285590075Sobrien     interfacearm - ?
285690075Sobrien     dllexport - for exporting a function/variable that will live in a dll
285790075Sobrien     dllimport - for importing a function/variable from a dll
285890075Sobrien
285990075Sobrien     Microsoft allows multiple declspecs in one __declspec, separating
286090075Sobrien     them with spaces.  We do NOT support this.  Instead, use __declspec
286190075Sobrien     multiple times.
286290075Sobrien  */
286390075Sobrien  { "dllimport",    0, 0, true,  false, false, NULL },
286490075Sobrien  { "dllexport",    0, 0, true,  false, false, NULL },
286590075Sobrien  { "interfacearm", 0, 0, true,  false, false, arm_handle_fndecl_attribute },
2866169689Skan#elif TARGET_DLLIMPORT_DECL_ATTRIBUTES
2867169689Skan  { "dllimport",    0, 0, false, false, false, handle_dll_attribute },
2868169689Skan  { "dllexport",    0, 0, false, false, false, handle_dll_attribute },
2869169689Skan  { "notshared",    0, 0, false, true, false, arm_handle_notshared_attribute },
287090075Sobrien#endif
287190075Sobrien  { NULL,           0, 0, false, false, false, NULL }
287290075Sobrien};
287390075Sobrien
287490075Sobrien/* Handle an attribute requiring a FUNCTION_DECL;
287590075Sobrien   arguments as in struct attribute_spec.handler.  */
287690075Sobrienstatic tree
2877132718Skanarm_handle_fndecl_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
2878132718Skan			     int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
287990075Sobrien{
288090075Sobrien  if (TREE_CODE (*node) != FUNCTION_DECL)
288190075Sobrien    {
2882169689Skan      warning (OPT_Wattributes, "%qs attribute only applies to functions",
288390075Sobrien	       IDENTIFIER_POINTER (name));
288490075Sobrien      *no_add_attrs = true;
288590075Sobrien    }
288690075Sobrien
288790075Sobrien  return NULL_TREE;
288890075Sobrien}
288990075Sobrien
289090075Sobrien/* Handle an "interrupt" or "isr" attribute;
289190075Sobrien   arguments as in struct attribute_spec.handler.  */
289290075Sobrienstatic tree
2893132718Skanarm_handle_isr_attribute (tree *node, tree name, tree args, int flags,
2894132718Skan			  bool *no_add_attrs)
289590075Sobrien{
289690075Sobrien  if (DECL_P (*node))
289790075Sobrien    {
289890075Sobrien      if (TREE_CODE (*node) != FUNCTION_DECL)
289990075Sobrien	{
2900169689Skan	  warning (OPT_Wattributes, "%qs attribute only applies to functions",
290190075Sobrien		   IDENTIFIER_POINTER (name));
290290075Sobrien	  *no_add_attrs = true;
290390075Sobrien	}
290490075Sobrien      /* FIXME: the argument if any is checked for type attributes;
290590075Sobrien	 should it be checked for decl ones?  */
290690075Sobrien    }
290790075Sobrien  else
290890075Sobrien    {
290990075Sobrien      if (TREE_CODE (*node) == FUNCTION_TYPE
291090075Sobrien	  || TREE_CODE (*node) == METHOD_TYPE)
291190075Sobrien	{
291290075Sobrien	  if (arm_isr_value (args) == ARM_FT_UNKNOWN)
291390075Sobrien	    {
2914169689Skan	      warning (OPT_Wattributes, "%qs attribute ignored",
2915169689Skan		       IDENTIFIER_POINTER (name));
291690075Sobrien	      *no_add_attrs = true;
291790075Sobrien	    }
291890075Sobrien	}
291990075Sobrien      else if (TREE_CODE (*node) == POINTER_TYPE
292090075Sobrien	       && (TREE_CODE (TREE_TYPE (*node)) == FUNCTION_TYPE
292190075Sobrien		   || TREE_CODE (TREE_TYPE (*node)) == METHOD_TYPE)
292290075Sobrien	       && arm_isr_value (args) != ARM_FT_UNKNOWN)
292390075Sobrien	{
2924169689Skan	  *node = build_variant_type_copy (*node);
292590075Sobrien	  TREE_TYPE (*node) = build_type_attribute_variant
292690075Sobrien	    (TREE_TYPE (*node),
292790075Sobrien	     tree_cons (name, args, TYPE_ATTRIBUTES (TREE_TYPE (*node))));
292890075Sobrien	  *no_add_attrs = true;
292990075Sobrien	}
293090075Sobrien      else
293190075Sobrien	{
293290075Sobrien	  /* Possibly pass this attribute on from the type to a decl.  */
293390075Sobrien	  if (flags & ((int) ATTR_FLAG_DECL_NEXT
293490075Sobrien		       | (int) ATTR_FLAG_FUNCTION_NEXT
293590075Sobrien		       | (int) ATTR_FLAG_ARRAY_NEXT))
293690075Sobrien	    {
293790075Sobrien	      *no_add_attrs = true;
293890075Sobrien	      return tree_cons (name, args, NULL_TREE);
293990075Sobrien	    }
294090075Sobrien	  else
294190075Sobrien	    {
2942169689Skan	      warning (OPT_Wattributes, "%qs attribute ignored",
2943169689Skan		       IDENTIFIER_POINTER (name));
294490075Sobrien	    }
294590075Sobrien	}
294690075Sobrien    }
294790075Sobrien
294890075Sobrien  return NULL_TREE;
294990075Sobrien}
295090075Sobrien
2951169689Skan#if TARGET_DLLIMPORT_DECL_ATTRIBUTES
2952169689Skan/* Handle the "notshared" attribute.  This attribute is another way of
2953169689Skan   requesting hidden visibility.  ARM's compiler supports
2954169689Skan   "__declspec(notshared)"; we support the same thing via an
2955169689Skan   attribute.  */
2956169689Skan
2957169689Skanstatic tree
2958169689Skanarm_handle_notshared_attribute (tree *node,
2959169689Skan				tree name ATTRIBUTE_UNUSED,
2960169689Skan				tree args ATTRIBUTE_UNUSED,
2961169689Skan				int flags ATTRIBUTE_UNUSED,
2962169689Skan				bool *no_add_attrs)
2963169689Skan{
2964169689Skan  tree decl = TYPE_NAME (*node);
2965169689Skan
2966169689Skan  if (decl)
2967169689Skan    {
2968169689Skan      DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN;
2969169689Skan      DECL_VISIBILITY_SPECIFIED (decl) = 1;
2970169689Skan      *no_add_attrs = false;
2971169689Skan    }
2972169689Skan  return NULL_TREE;
2973169689Skan}
2974169689Skan#endif
2975169689Skan
297690075Sobrien/* Return 0 if the attributes for two types are incompatible, 1 if they
297790075Sobrien   are compatible, and 2 if they are nearly compatible (which causes a
297890075Sobrien   warning to be generated).  */
297990075Sobrienstatic int
2980132718Skanarm_comp_type_attributes (tree type1, tree type2)
298190075Sobrien{
298290075Sobrien  int l1, l2, s1, s2;
2983169689Skan
298490075Sobrien  /* Check for mismatch of non-default calling convention.  */
298590075Sobrien  if (TREE_CODE (type1) != FUNCTION_TYPE)
298690075Sobrien    return 1;
298790075Sobrien
298890075Sobrien  /* Check for mismatched call attributes.  */
298990075Sobrien  l1 = lookup_attribute ("long_call", TYPE_ATTRIBUTES (type1)) != NULL;
299090075Sobrien  l2 = lookup_attribute ("long_call", TYPE_ATTRIBUTES (type2)) != NULL;
299190075Sobrien  s1 = lookup_attribute ("short_call", TYPE_ATTRIBUTES (type1)) != NULL;
299290075Sobrien  s2 = lookup_attribute ("short_call", TYPE_ATTRIBUTES (type2)) != NULL;
299390075Sobrien
299490075Sobrien  /* Only bother to check if an attribute is defined.  */
299590075Sobrien  if (l1 | l2 | s1 | s2)
299690075Sobrien    {
299790075Sobrien      /* If one type has an attribute, the other must have the same attribute.  */
299890075Sobrien      if ((l1 != l2) || (s1 != s2))
299990075Sobrien	return 0;
300090075Sobrien
300190075Sobrien      /* Disallow mixed attributes.  */
300290075Sobrien      if ((l1 & s2) || (l2 & s1))
300390075Sobrien	return 0;
300490075Sobrien    }
3005169689Skan
300690075Sobrien  /* Check for mismatched ISR attribute.  */
300790075Sobrien  l1 = lookup_attribute ("isr", TYPE_ATTRIBUTES (type1)) != NULL;
300890075Sobrien  if (! l1)
300990075Sobrien    l1 = lookup_attribute ("interrupt", TYPE_ATTRIBUTES (type1)) != NULL;
301090075Sobrien  l2 = lookup_attribute ("isr", TYPE_ATTRIBUTES (type2)) != NULL;
301190075Sobrien  if (! l2)
301290075Sobrien    l1 = lookup_attribute ("interrupt", TYPE_ATTRIBUTES (type2)) != NULL;
301390075Sobrien  if (l1 != l2)
301490075Sobrien    return 0;
301590075Sobrien
301690075Sobrien  return 1;
301790075Sobrien}
301890075Sobrien
301990075Sobrien/*  Encode long_call or short_call attribute by prefixing
302090075Sobrien    symbol name in DECL with a special character FLAG.  */
302190075Sobrienvoid
3022132718Skanarm_encode_call_attribute (tree decl, int flag)
302390075Sobrien{
302490075Sobrien  const char * str = XSTR (XEXP (DECL_RTL (decl), 0), 0);
302590075Sobrien  int          len = strlen (str);
302690075Sobrien  char *       newstr;
302790075Sobrien
302890075Sobrien  /* Do not allow weak functions to be treated as short call.  */
302990075Sobrien  if (DECL_WEAK (decl) && flag == SHORT_CALL_FLAG_CHAR)
303090075Sobrien    return;
303190075Sobrien
303290075Sobrien  newstr = alloca (len + 2);
303390075Sobrien  newstr[0] = flag;
303490075Sobrien  strcpy (newstr + 1, str);
303590075Sobrien
303690075Sobrien  newstr = (char *) ggc_alloc_string (newstr, len + 1);
303790075Sobrien  XSTR (XEXP (DECL_RTL (decl), 0), 0) = newstr;
303890075Sobrien}
303990075Sobrien
304090075Sobrien/*  Assigns default attributes to newly defined type.  This is used to
304190075Sobrien    set short_call/long_call attributes for function types of
304290075Sobrien    functions defined inside corresponding #pragma scopes.  */
304390075Sobrienstatic void
3044132718Skanarm_set_default_type_attributes (tree type)
304590075Sobrien{
304690075Sobrien  /* Add __attribute__ ((long_call)) to all functions, when
304790075Sobrien     inside #pragma long_calls or __attribute__ ((short_call)),
304890075Sobrien     when inside #pragma no_long_calls.  */
304990075Sobrien  if (TREE_CODE (type) == FUNCTION_TYPE || TREE_CODE (type) == METHOD_TYPE)
305090075Sobrien    {
305190075Sobrien      tree type_attr_list, attr_name;
305290075Sobrien      type_attr_list = TYPE_ATTRIBUTES (type);
305390075Sobrien
305490075Sobrien      if (arm_pragma_long_calls == LONG)
305590075Sobrien 	attr_name = get_identifier ("long_call");
305690075Sobrien      else if (arm_pragma_long_calls == SHORT)
305790075Sobrien 	attr_name = get_identifier ("short_call");
305890075Sobrien      else
305990075Sobrien 	return;
306090075Sobrien
306190075Sobrien      type_attr_list = tree_cons (attr_name, NULL_TREE, type_attr_list);
306290075Sobrien      TYPE_ATTRIBUTES (type) = type_attr_list;
306390075Sobrien    }
306490075Sobrien}
306590075Sobrien
306690075Sobrien/* Return 1 if the operand is a SYMBOL_REF for a function known to be
3067132718Skan   defined within the current compilation unit.  If this cannot be
306890075Sobrien   determined, then 0 is returned.  */
306990075Sobrienstatic int
3070132718Skancurrent_file_function_operand (rtx sym_ref)
307190075Sobrien{
307290075Sobrien  /* This is a bit of a fib.  A function will have a short call flag
307390075Sobrien     applied to its name if it has the short call attribute, or it has
307490075Sobrien     already been defined within the current compilation unit.  */
307590075Sobrien  if (ENCODED_SHORT_CALL_ATTR_P (XSTR (sym_ref, 0)))
307690075Sobrien    return 1;
307790075Sobrien
307890075Sobrien  /* The current function is always defined within the current compilation
3079169689Skan     unit.  If it s a weak definition however, then this may not be the real
308090075Sobrien     definition of the function, and so we have to say no.  */
308190075Sobrien  if (sym_ref == XEXP (DECL_RTL (current_function_decl), 0)
308290075Sobrien      && !DECL_WEAK (current_function_decl))
308390075Sobrien    return 1;
308490075Sobrien
308590075Sobrien  /* We cannot make the determination - default to returning 0.  */
308690075Sobrien  return 0;
308790075Sobrien}
308890075Sobrien
3089117395Skan/* Return nonzero if a 32 bit "long_call" should be generated for
309090075Sobrien   this call.  We generate a long_call if the function:
309190075Sobrien
309290075Sobrien        a.  has an __attribute__((long call))
309390075Sobrien     or b.  is within the scope of a #pragma long_calls
309490075Sobrien     or c.  the -mlong-calls command line switch has been specified
3095169689Skan         .  and either:
3096169689Skan                1. -ffunction-sections is in effect
3097169689Skan	     or 2. the current function has __attribute__ ((section))
3098169689Skan	     or 3. the target function has __attribute__ ((section))
309990075Sobrien
310090075Sobrien   However we do not generate a long call if the function:
3101169689Skan
310290075Sobrien        d.  has an __attribute__ ((short_call))
310390075Sobrien     or e.  is inside the scope of a #pragma no_long_calls
3104169689Skan     or f.  is defined within the current compilation unit.
3105169689Skan
310690075Sobrien   This function will be called by C fragments contained in the machine
3107169689Skan   description file.  SYM_REF and CALL_COOKIE correspond to the matched
310890075Sobrien   rtl operands.  CALL_SYMBOL is used to distinguish between
310990075Sobrien   two different callers of the function.  It is set to 1 in the
311090075Sobrien   "call_symbol" and "call_symbol_value" patterns and to 0 in the "call"
311190075Sobrien   and "call_value" patterns.  This is because of the difference in the
311290075Sobrien   SYM_REFs passed by these patterns.  */
311390075Sobrienint
3114132718Skanarm_is_longcall_p (rtx sym_ref, int call_cookie, int call_symbol)
311590075Sobrien{
311690075Sobrien  if (!call_symbol)
311790075Sobrien    {
311890075Sobrien      if (GET_CODE (sym_ref) != MEM)
311990075Sobrien	return 0;
312090075Sobrien
312190075Sobrien      sym_ref = XEXP (sym_ref, 0);
312290075Sobrien    }
312390075Sobrien
312490075Sobrien  if (GET_CODE (sym_ref) != SYMBOL_REF)
312590075Sobrien    return 0;
312690075Sobrien
312790075Sobrien  if (call_cookie & CALL_SHORT)
312890075Sobrien    return 0;
312990075Sobrien
3130169689Skan  if (TARGET_LONG_CALLS)
3131169689Skan    {
3132169689Skan      if (flag_function_sections
3133169689Skan	  || DECL_SECTION_NAME (current_function_decl))
3134169689Skan	/* c.3 is handled by the definition of the
3135169689Skan	   ARM_DECLARE_FUNCTION_SIZE macro.  */
3136169689Skan	return 1;
3137169689Skan    }
3138169689Skan
313990075Sobrien  if (current_file_function_operand (sym_ref))
314090075Sobrien    return 0;
3141169689Skan
314290075Sobrien  return (call_cookie & CALL_LONG)
314390075Sobrien    || ENCODED_LONG_CALL_ATTR_P (XSTR (sym_ref, 0))
314490075Sobrien    || TARGET_LONG_CALLS;
314590075Sobrien}
314690075Sobrien
3147117395Skan/* Return nonzero if it is ok to make a tail-call to DECL.  */
3148132718Skanstatic bool
3149132718Skanarm_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
315090075Sobrien{
315190075Sobrien  int call_type = TARGET_LONG_CALLS ? CALL_LONG : CALL_NORMAL;
315290075Sobrien
3153132718Skan  if (cfun->machine->sibcall_blocked)
3154132718Skan    return false;
3155132718Skan
315690075Sobrien  /* Never tailcall something for which we have no decl, or if we
315790075Sobrien     are in Thumb mode.  */
315890075Sobrien  if (decl == NULL || TARGET_THUMB)
3159132718Skan    return false;
316090075Sobrien
316190075Sobrien  /* Get the calling method.  */
316290075Sobrien  if (lookup_attribute ("short_call", TYPE_ATTRIBUTES (TREE_TYPE (decl))))
316390075Sobrien    call_type = CALL_SHORT;
316490075Sobrien  else if (lookup_attribute ("long_call", TYPE_ATTRIBUTES (TREE_TYPE (decl))))
316590075Sobrien    call_type = CALL_LONG;
316690075Sobrien
316790075Sobrien  /* Cannot tail-call to long calls, since these are out of range of
316890075Sobrien     a branch instruction.  However, if not compiling PIC, we know
316990075Sobrien     we can reach the symbol if it is in this compilation unit.  */
317090075Sobrien  if (call_type == CALL_LONG && (flag_pic || !TREE_ASM_WRITTEN (decl)))
3171132718Skan    return false;
317290075Sobrien
317390075Sobrien  /* If we are interworking and the function is not declared static
3174169689Skan     then we can't tail-call it unless we know that it exists in this
317590075Sobrien     compilation unit (since it might be a Thumb routine).  */
317690075Sobrien  if (TARGET_INTERWORK && TREE_PUBLIC (decl) && !TREE_ASM_WRITTEN (decl))
3177132718Skan    return false;
317890075Sobrien
317990075Sobrien  /* Never tailcall from an ISR routine - it needs a special exit sequence.  */
318090075Sobrien  if (IS_INTERRUPT (arm_current_func_type ()))
3181132718Skan    return false;
318290075Sobrien
318390075Sobrien  /* Everything else is ok.  */
3184132718Skan  return true;
318590075Sobrien}
318690075Sobrien
318790075Sobrien
3188132718Skan/* Addressing mode support functions.  */
3189132718Skan
3190132718Skan/* Return nonzero if X is a legitimate immediate operand when compiling
3191169689Skan   for PIC.  We know that X satisfies CONSTANT_P and flag_pic is true.  */
319290075Sobrienint
3193132718Skanlegitimate_pic_operand_p (rtx x)
319490075Sobrien{
3195169689Skan  if (GET_CODE (x) == SYMBOL_REF
3196169689Skan      || (GET_CODE (x) == CONST
3197169689Skan	  && GET_CODE (XEXP (x, 0)) == PLUS
3198169689Skan	  && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF))
319990075Sobrien    return 0;
320090075Sobrien
320190075Sobrien  return 1;
320290075Sobrien}
320390075Sobrien
320490075Sobrienrtx
3205132718Skanlegitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
320690075Sobrien{
320790075Sobrien  if (GET_CODE (orig) == SYMBOL_REF
320890075Sobrien      || GET_CODE (orig) == LABEL_REF)
320990075Sobrien    {
321090075Sobrien#ifndef AOF_ASSEMBLER
321190075Sobrien      rtx pic_ref, address;
321290075Sobrien#endif
321390075Sobrien      rtx insn;
321490075Sobrien      int subregs = 0;
321590075Sobrien
3216169689Skan      /* If this function doesn't have a pic register, create one now.
3217169689Skan	 A lot of the logic here is made obscure by the fact that this
3218169689Skan	 routine gets called as part of the rtx cost estimation
3219169689Skan	 process.  We don't want those calls to affect any assumptions
3220169689Skan	 about the real function; and further, we can't call
3221169689Skan	 entry_of_function() until we start the real expansion
3222169689Skan	 process.  */
3223169689Skan      if (!current_function_uses_pic_offset_table)
322490075Sobrien	{
3225169689Skan	  gcc_assert (!no_new_pseudos);
3226169689Skan	  if (arm_pic_register != INVALID_REGNUM)
3227169689Skan	    {
3228227664Sfabient	      if (!cfun->machine->pic_reg)
3229227664Sfabient		cfun->machine->pic_reg = gen_rtx_REG (Pmode, arm_pic_register);
3230169689Skan
3231169689Skan	      /* Play games to avoid marking the function as needing pic
3232169689Skan		 if we are being called as part of the cost-estimation
3233169689Skan		 process.  */
3234169689Skan	      if (!ir_type())
3235169689Skan		current_function_uses_pic_offset_table = 1;
3236169689Skan	    }
323790075Sobrien	  else
3238169689Skan	    {
3239169689Skan	      rtx seq;
324090075Sobrien
3241227664Sfabient	      if (!cfun->machine->pic_reg)
3242227664Sfabient		  cfun->machine->pic_reg = gen_reg_rtx (Pmode);
3243169689Skan
3244169689Skan	      /* Play games to avoid marking the function as needing pic
3245169689Skan		 if we are being called as part of the cost-estimation
3246169689Skan		 process.  */
3247169689Skan	      if (!ir_type())
3248169689Skan		{
3249169689Skan		  current_function_uses_pic_offset_table = 1;
3250169689Skan		  start_sequence ();
3251169689Skan
3252169689Skan		  arm_load_pic_register (0UL);
3253169689Skan
3254169689Skan		  seq = get_insns ();
3255169689Skan		  end_sequence ();
3256169689Skan		  emit_insn_after (seq, entry_of_function ());
3257169689Skan		}
3258169689Skan	    }
3259169689Skan	}
3260169689Skan
3261169689Skan      if (reg == 0)
3262169689Skan	{
3263169689Skan	  gcc_assert (!no_new_pseudos);
3264169689Skan	  reg = gen_reg_rtx (Pmode);
3265169689Skan
326690075Sobrien	  subregs = 1;
326790075Sobrien	}
326890075Sobrien
326990075Sobrien#ifdef AOF_ASSEMBLER
327090075Sobrien      /* The AOF assembler can generate relocations for these directly, and
327190075Sobrien	 understands that the PIC register has to be added into the offset.  */
327290075Sobrien      insn = emit_insn (gen_pic_load_addr_based (reg, orig));
327390075Sobrien#else
327490075Sobrien      if (subregs)
327590075Sobrien	address = gen_reg_rtx (Pmode);
327690075Sobrien      else
327790075Sobrien	address = reg;
327890075Sobrien
327990075Sobrien      if (TARGET_ARM)
328090075Sobrien	emit_insn (gen_pic_load_addr_arm (address, orig));
328190075Sobrien      else
328290075Sobrien	emit_insn (gen_pic_load_addr_thumb (address, orig));
328390075Sobrien
328496263Sobrien      if ((GET_CODE (orig) == LABEL_REF
3285169689Skan	   || (GET_CODE (orig) == SYMBOL_REF &&
3286132718Skan	       SYMBOL_REF_LOCAL_P (orig)))
328796263Sobrien	  && NEED_GOT_RELOC)
3288169689Skan	pic_ref = gen_rtx_PLUS (Pmode, cfun->machine->pic_reg, address);
328990075Sobrien      else
329090075Sobrien	{
3291169689Skan	  pic_ref = gen_const_mem (Pmode,
3292169689Skan				   gen_rtx_PLUS (Pmode, cfun->machine->pic_reg,
3293169689Skan					         address));
329490075Sobrien	}
329590075Sobrien
329690075Sobrien      insn = emit_move_insn (reg, pic_ref);
329790075Sobrien#endif
329890075Sobrien      /* Put a REG_EQUAL note on this insn, so that it can be optimized
329990075Sobrien	 by loop.  */
330090075Sobrien      REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, orig,
330190075Sobrien					    REG_NOTES (insn));
330290075Sobrien      return reg;
330390075Sobrien    }
330490075Sobrien  else if (GET_CODE (orig) == CONST)
330590075Sobrien    {
330690075Sobrien      rtx base, offset;
330790075Sobrien
330890075Sobrien      if (GET_CODE (XEXP (orig, 0)) == PLUS
3309169689Skan	  && XEXP (XEXP (orig, 0), 0) == cfun->machine->pic_reg)
331090075Sobrien	return orig;
331190075Sobrien
3312169689Skan      if (GET_CODE (XEXP (orig, 0)) == UNSPEC
3313169689Skan	  && XINT (XEXP (orig, 0), 1) == UNSPEC_TLS)
3314169689Skan	return orig;
3315169689Skan
331690075Sobrien      if (reg == 0)
331790075Sobrien	{
3318169689Skan	  gcc_assert (!no_new_pseudos);
3319169689Skan	  reg = gen_reg_rtx (Pmode);
332090075Sobrien	}
332190075Sobrien
3322169689Skan      gcc_assert (GET_CODE (XEXP (orig, 0)) == PLUS);
332390075Sobrien
3324169689Skan      base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg);
3325169689Skan      offset = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode,
3326169689Skan				       base == reg ? 0 : reg);
3327169689Skan
332890075Sobrien      if (GET_CODE (offset) == CONST_INT)
332990075Sobrien	{
333090075Sobrien	  /* The base register doesn't really matter, we only want to
333190075Sobrien	     test the index for the appropriate mode.  */
3332169689Skan	  if (!arm_legitimate_index_p (mode, offset, SET, 0))
3333132718Skan	    {
3334169689Skan	      gcc_assert (!no_new_pseudos);
3335169689Skan	      offset = force_reg (Pmode, offset);
3336132718Skan	    }
333790075Sobrien
333890075Sobrien	  if (GET_CODE (offset) == CONST_INT)
333990075Sobrien	    return plus_constant (base, INTVAL (offset));
334090075Sobrien	}
334190075Sobrien
334290075Sobrien      if (GET_MODE_SIZE (mode) > 4
334390075Sobrien	  && (GET_MODE_CLASS (mode) == MODE_INT
334490075Sobrien	      || TARGET_SOFT_FLOAT))
334590075Sobrien	{
334690075Sobrien	  emit_insn (gen_addsi3 (reg, base, offset));
334790075Sobrien	  return reg;
334890075Sobrien	}
334990075Sobrien
335090075Sobrien      return gen_rtx_PLUS (Pmode, base, offset);
335190075Sobrien    }
335290075Sobrien
335390075Sobrien  return orig;
335490075Sobrien}
335590075Sobrien
3356169689Skan
3357169689Skan/* Find a spare low register to use during the prolog of a function.  */
3358169689Skan
3359169689Skanstatic int
3360169689Skanthumb_find_work_register (unsigned long pushed_regs_mask)
3361169689Skan{
3362169689Skan  int reg;
3363169689Skan
3364169689Skan  /* Check the argument registers first as these are call-used.  The
3365169689Skan     register allocation order means that sometimes r3 might be used
3366169689Skan     but earlier argument registers might not, so check them all.  */
3367169689Skan  for (reg = LAST_ARG_REGNUM; reg >= 0; reg --)
3368169689Skan    if (!regs_ever_live[reg])
3369169689Skan      return reg;
3370169689Skan
3371169689Skan  /* Before going on to check the call-saved registers we can try a couple
3372169689Skan     more ways of deducing that r3 is available.  The first is when we are
3373169689Skan     pushing anonymous arguments onto the stack and we have less than 4
3374169689Skan     registers worth of fixed arguments(*).  In this case r3 will be part of
3375169689Skan     the variable argument list and so we can be sure that it will be
3376169689Skan     pushed right at the start of the function.  Hence it will be available
3377169689Skan     for the rest of the prologue.
3378169689Skan     (*): ie current_function_pretend_args_size is greater than 0.  */
3379169689Skan  if (cfun->machine->uses_anonymous_args
3380169689Skan      && current_function_pretend_args_size > 0)
3381169689Skan    return LAST_ARG_REGNUM;
3382169689Skan
3383169689Skan  /* The other case is when we have fixed arguments but less than 4 registers
3384169689Skan     worth.  In this case r3 might be used in the body of the function, but
3385169689Skan     it is not being used to convey an argument into the function.  In theory
3386169689Skan     we could just check current_function_args_size to see how many bytes are
3387169689Skan     being passed in argument registers, but it seems that it is unreliable.
3388169689Skan     Sometimes it will have the value 0 when in fact arguments are being
3389169689Skan     passed.  (See testcase execute/20021111-1.c for an example).  So we also
3390169689Skan     check the args_info.nregs field as well.  The problem with this field is
3391169689Skan     that it makes no allowances for arguments that are passed to the
3392169689Skan     function but which are not used.  Hence we could miss an opportunity
3393169689Skan     when a function has an unused argument in r3.  But it is better to be
3394169689Skan     safe than to be sorry.  */
3395169689Skan  if (! cfun->machine->uses_anonymous_args
3396169689Skan      && current_function_args_size >= 0
3397169689Skan      && current_function_args_size <= (LAST_ARG_REGNUM * UNITS_PER_WORD)
3398169689Skan      && cfun->args_info.nregs < 4)
3399169689Skan    return LAST_ARG_REGNUM;
3400169689Skan
3401169689Skan  /* Otherwise look for a call-saved register that is going to be pushed.  */
3402169689Skan  for (reg = LAST_LO_REGNUM; reg > LAST_ARG_REGNUM; reg --)
3403169689Skan    if (pushed_regs_mask & (1 << reg))
3404169689Skan      return reg;
3405169689Skan
3406169689Skan  /* Something went wrong - thumb_compute_save_reg_mask()
3407169689Skan     should have arranged for a suitable register to be pushed.  */
3408169689Skan  gcc_unreachable ();
3409169689Skan}
3410169689Skan
3411169689Skanstatic GTY(()) int pic_labelno;
3412169689Skan
3413169689Skan/* Generate code to load the PIC register.  In thumb mode SCRATCH is a
3414169689Skan   low register.  */
3415169689Skan
341690075Sobrienvoid
3417169689Skanarm_load_pic_register (unsigned long saved_regs ATTRIBUTE_UNUSED)
341890075Sobrien{
341990075Sobrien#ifndef AOF_ASSEMBLER
3420169689Skan  rtx l1, labelno, pic_tmp, pic_tmp2, pic_rtx;
342190075Sobrien  rtx global_offset_table;
342290075Sobrien
342390075Sobrien  if (current_function_uses_pic_offset_table == 0 || TARGET_SINGLE_PIC_BASE)
342490075Sobrien    return;
342590075Sobrien
3426169689Skan  gcc_assert (flag_pic);
342790075Sobrien
3428169689Skan  /* We use an UNSPEC rather than a LABEL_REF because this label never appears
3429169689Skan     in the code stream.  */
343090075Sobrien
3431169689Skan  labelno = GEN_INT (pic_labelno++);
3432169689Skan  l1 = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, labelno), UNSPEC_PIC_LABEL);
3433169689Skan  l1 = gen_rtx_CONST (VOIDmode, l1);
3434169689Skan
343590075Sobrien  global_offset_table = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
343690075Sobrien  /* On the ARM the PC register contains 'dot + 8' at the time of the
343790075Sobrien     addition, on the Thumb it is 'dot + 4'.  */
3438169689Skan  pic_tmp = plus_constant (l1, TARGET_ARM ? 8 : 4);
343990075Sobrien  if (GOT_PCREL)
344090075Sobrien    pic_tmp2 = gen_rtx_CONST (VOIDmode,
344190075Sobrien			    gen_rtx_PLUS (Pmode, global_offset_table, pc_rtx));
344290075Sobrien  else
344390075Sobrien    pic_tmp2 = gen_rtx_CONST (VOIDmode, global_offset_table);
344490075Sobrien
344590075Sobrien  pic_rtx = gen_rtx_CONST (Pmode, gen_rtx_MINUS (Pmode, pic_tmp2, pic_tmp));
3446169689Skan
344790075Sobrien  if (TARGET_ARM)
344890075Sobrien    {
3449169689Skan      emit_insn (gen_pic_load_addr_arm (cfun->machine->pic_reg, pic_rtx));
3450169689Skan      emit_insn (gen_pic_add_dot_plus_eight (cfun->machine->pic_reg,
3451169689Skan					     cfun->machine->pic_reg, labelno));
345290075Sobrien    }
345390075Sobrien  else
345490075Sobrien    {
3455169689Skan      if (arm_pic_register != INVALID_REGNUM
3456169689Skan	  && REGNO (cfun->machine->pic_reg) > LAST_LO_REGNUM)
3457169689Skan	{
3458169689Skan	  /* We will have pushed the pic register, so we should always be
3459169689Skan	     able to find a work register.  */
3460169689Skan	  pic_tmp = gen_rtx_REG (SImode,
3461169689Skan				 thumb_find_work_register (saved_regs));
3462169689Skan	  emit_insn (gen_pic_load_addr_thumb (pic_tmp, pic_rtx));
3463169689Skan	  emit_insn (gen_movsi (pic_offset_table_rtx, pic_tmp));
3464169689Skan	}
3465169689Skan      else
3466169689Skan	emit_insn (gen_pic_load_addr_thumb (cfun->machine->pic_reg, pic_rtx));
3467169689Skan      emit_insn (gen_pic_add_dot_plus_four (cfun->machine->pic_reg,
3468169689Skan					    cfun->machine->pic_reg, labelno));
346990075Sobrien    }
347090075Sobrien
347190075Sobrien  /* Need to emit this whether or not we obey regdecls,
347290075Sobrien     since setjmp/longjmp can cause life info to screw up.  */
3473169689Skan  emit_insn (gen_rtx_USE (VOIDmode, cfun->machine->pic_reg));
347490075Sobrien#endif /* AOF_ASSEMBLER */
347590075Sobrien}
347690075Sobrien
3477169689Skan
3478132718Skan/* Return nonzero if X is valid as an ARM state addressing register.  */
3479132718Skanstatic int
3480132718Skanarm_address_register_rtx_p (rtx x, int strict_p)
3481132718Skan{
3482132718Skan  int regno;
3483132718Skan
3484132718Skan  if (GET_CODE (x) != REG)
3485132718Skan    return 0;
3486132718Skan
3487132718Skan  regno = REGNO (x);
3488132718Skan
3489132718Skan  if (strict_p)
3490132718Skan    return ARM_REGNO_OK_FOR_BASE_P (regno);
3491132718Skan
3492132718Skan  return (regno <= LAST_ARM_REGNUM
3493132718Skan	  || regno >= FIRST_PSEUDO_REGISTER
3494132718Skan	  || regno == FRAME_POINTER_REGNUM
3495132718Skan	  || regno == ARG_POINTER_REGNUM);
3496132718Skan}
3497132718Skan
3498169689Skan/* Return TRUE if this rtx is the difference of a symbol and a label,
3499169689Skan   and will reduce to a PC-relative relocation in the object file.
3500169689Skan   Expressions like this can be left alone when generating PIC, rather
3501169689Skan   than forced through the GOT.  */
3502169689Skanstatic int
3503169689Skanpcrel_constant_p (rtx x)
3504169689Skan{
3505169689Skan  if (GET_CODE (x) == MINUS)
3506169689Skan    return symbol_mentioned_p (XEXP (x, 0)) && label_mentioned_p (XEXP (x, 1));
3507169689Skan
3508169689Skan  return FALSE;
3509169689Skan}
3510169689Skan
3511132718Skan/* Return nonzero if X is a valid ARM state address operand.  */
3512132718Skanint
3513169689Skanarm_legitimate_address_p (enum machine_mode mode, rtx x, RTX_CODE outer,
3514169689Skan			  int strict_p)
3515132718Skan{
3516169689Skan  bool use_ldrd;
3517169689Skan  enum rtx_code code = GET_CODE (x);
3518169689Skan
3519132718Skan  if (arm_address_register_rtx_p (x, strict_p))
3520132718Skan    return 1;
3521132718Skan
3522169689Skan  use_ldrd = (TARGET_LDRD
3523169689Skan	      && (mode == DImode
3524169689Skan		  || (mode == DFmode && (TARGET_SOFT_FLOAT || TARGET_VFP))));
3525169689Skan
3526169689Skan  if (code == POST_INC || code == PRE_DEC
3527169689Skan      || ((code == PRE_INC || code == POST_DEC)
3528169689Skan	  && (use_ldrd || GET_MODE_SIZE (mode) <= 4)))
3529132718Skan    return arm_address_register_rtx_p (XEXP (x, 0), strict_p);
3530132718Skan
3531169689Skan  else if ((code == POST_MODIFY || code == PRE_MODIFY)
3532132718Skan	   && arm_address_register_rtx_p (XEXP (x, 0), strict_p)
3533132718Skan	   && GET_CODE (XEXP (x, 1)) == PLUS
3534132718Skan	   && rtx_equal_p (XEXP (XEXP (x, 1), 0), XEXP (x, 0)))
3535169689Skan    {
3536169689Skan      rtx addend = XEXP (XEXP (x, 1), 1);
3537132718Skan
3538169689Skan      /* Don't allow ldrd post increment by register because it's hard
3539169689Skan	 to fixup invalid register choices.  */
3540169689Skan      if (use_ldrd
3541169689Skan	  && GET_CODE (x) == POST_MODIFY
3542169689Skan	  && GET_CODE (addend) == REG)
3543169689Skan	return 0;
3544169689Skan
3545169689Skan      return ((use_ldrd || GET_MODE_SIZE (mode) <= 4)
3546169689Skan	      && arm_legitimate_index_p (mode, addend, outer, strict_p));
3547169689Skan    }
3548169689Skan
3549132718Skan  /* After reload constants split into minipools will have addresses
3550132718Skan     from a LABEL_REF.  */
3551132718Skan  else if (reload_completed
3552169689Skan	   && (code == LABEL_REF
3553169689Skan	       || (code == CONST
3554132718Skan		   && GET_CODE (XEXP (x, 0)) == PLUS
3555132718Skan		   && GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF
3556132718Skan		   && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)))
3557132718Skan    return 1;
3558132718Skan
3559132718Skan  else if (mode == TImode)
3560132718Skan    return 0;
3561132718Skan
3562169689Skan  else if (code == PLUS)
3563132718Skan    {
3564132718Skan      rtx xop0 = XEXP (x, 0);
3565132718Skan      rtx xop1 = XEXP (x, 1);
3566132718Skan
3567132718Skan      return ((arm_address_register_rtx_p (xop0, strict_p)
3568169689Skan	       && arm_legitimate_index_p (mode, xop1, outer, strict_p))
3569132718Skan	      || (arm_address_register_rtx_p (xop1, strict_p)
3570169689Skan		  && arm_legitimate_index_p (mode, xop0, outer, strict_p)));
3571132718Skan    }
3572132718Skan
3573132718Skan#if 0
3574132718Skan  /* Reload currently can't handle MINUS, so disable this for now */
3575132718Skan  else if (GET_CODE (x) == MINUS)
3576132718Skan    {
3577132718Skan      rtx xop0 = XEXP (x, 0);
3578132718Skan      rtx xop1 = XEXP (x, 1);
3579132718Skan
3580132718Skan      return (arm_address_register_rtx_p (xop0, strict_p)
3581169689Skan	      && arm_legitimate_index_p (mode, xop1, outer, strict_p));
3582132718Skan    }
3583132718Skan#endif
3584132718Skan
3585132718Skan  else if (GET_MODE_CLASS (mode) != MODE_FLOAT
3586169689Skan	   && code == SYMBOL_REF
3587132718Skan	   && CONSTANT_POOL_ADDRESS_P (x)
3588132718Skan	   && ! (flag_pic
3589169689Skan		 && symbol_mentioned_p (get_pool_constant (x))
3590169689Skan		 && ! pcrel_constant_p (get_pool_constant (x))))
3591132718Skan    return 1;
3592132718Skan
3593132718Skan  return 0;
3594132718Skan}
3595132718Skan
3596132718Skan/* Return nonzero if INDEX is valid for an address index operand in
3597132718Skan   ARM state.  */
3598132718Skanstatic int
3599169689Skanarm_legitimate_index_p (enum machine_mode mode, rtx index, RTX_CODE outer,
3600169689Skan			int strict_p)
3601132718Skan{
3602132718Skan  HOST_WIDE_INT range;
3603132718Skan  enum rtx_code code = GET_CODE (index);
3604132718Skan
3605169689Skan  /* Standard coprocessor addressing modes.  */
3606169689Skan  if (TARGET_HARD_FLOAT
3607169689Skan      && (TARGET_FPA || TARGET_MAVERICK)
3608169689Skan      && (GET_MODE_CLASS (mode) == MODE_FLOAT
3609169689Skan	  || (TARGET_MAVERICK && mode == DImode)))
3610132718Skan    return (code == CONST_INT && INTVAL (index) < 1024
3611132718Skan	    && INTVAL (index) > -1024
3612132718Skan	    && (INTVAL (index) & 3) == 0);
3613132718Skan
3614169689Skan  if (TARGET_REALLY_IWMMXT && VALID_IWMMXT_REG_MODE (mode))
3615169689Skan    {
3616169689Skan      /* For DImode assume values will usually live in core regs
3617169689Skan	 and only allow LDRD addressing modes.  */
3618169689Skan      if (!TARGET_LDRD || mode != DImode)
3619169689Skan	return (code == CONST_INT
3620169689Skan		&& INTVAL (index) < 1024
3621169689Skan		&& INTVAL (index) > -1024
3622169689Skan		&& (INTVAL (index) & 3) == 0);
3623169689Skan    }
3624132718Skan
3625132718Skan  if (arm_address_register_rtx_p (index, strict_p)
3626169689Skan      && (GET_MODE_SIZE (mode) <= 4))
3627132718Skan    return 1;
3628132718Skan
3629169689Skan  if (mode == DImode || mode == DFmode)
3630132718Skan    {
3631169689Skan      if (code == CONST_INT)
3632169689Skan	{
3633169689Skan	  HOST_WIDE_INT val = INTVAL (index);
3634132718Skan
3635169689Skan	  if (TARGET_LDRD)
3636169689Skan	    return val > -256 && val < 256;
3637169689Skan	  else
3638169689Skan	    return val > -4096 && val < 4092;
3639169689Skan	}
3640169689Skan
3641169689Skan      return TARGET_LDRD && arm_address_register_rtx_p (index, strict_p);
3642132718Skan    }
3643132718Skan
3644132718Skan  if (GET_MODE_SIZE (mode) <= 4
3645169689Skan      && ! (arm_arch4
3646169689Skan	    && (mode == HImode
3647169689Skan		|| (mode == QImode && outer == SIGN_EXTEND))))
3648132718Skan    {
3649169689Skan      if (code == MULT)
3650169689Skan	{
3651169689Skan	  rtx xiop0 = XEXP (index, 0);
3652169689Skan	  rtx xiop1 = XEXP (index, 1);
3653132718Skan
3654169689Skan	  return ((arm_address_register_rtx_p (xiop0, strict_p)
3655169689Skan		   && power_of_two_operand (xiop1, SImode))
3656169689Skan		  || (arm_address_register_rtx_p (xiop1, strict_p)
3657169689Skan		      && power_of_two_operand (xiop0, SImode)));
3658169689Skan	}
3659169689Skan      else if (code == LSHIFTRT || code == ASHIFTRT
3660169689Skan	       || code == ASHIFT || code == ROTATERT)
3661169689Skan	{
3662169689Skan	  rtx op = XEXP (index, 1);
3663169689Skan
3664169689Skan	  return (arm_address_register_rtx_p (XEXP (index, 0), strict_p)
3665169689Skan		  && GET_CODE (op) == CONST_INT
3666169689Skan		  && INTVAL (op) > 0
3667169689Skan		  && INTVAL (op) <= 31);
3668169689Skan	}
3669132718Skan    }
3670132718Skan
3671169689Skan  /* For ARM v4 we may be doing a sign-extend operation during the
3672169689Skan     load.  */
3673132718Skan  if (arm_arch4)
3674169689Skan    {
3675169689Skan      if (mode == HImode || (outer == SIGN_EXTEND && mode == QImode))
3676169689Skan	range = 256;
3677169689Skan      else
3678169689Skan	range = 4096;
3679169689Skan    }
3680132718Skan  else
3681132718Skan    range = (mode == HImode) ? 4095 : 4096;
3682132718Skan
3683132718Skan  return (code == CONST_INT
3684132718Skan	  && INTVAL (index) < range
3685132718Skan	  && INTVAL (index) > -range);
3686132718Skan}
3687132718Skan
3688132718Skan/* Return nonzero if X is valid as a Thumb state base register.  */
3689132718Skanstatic int
3690132718Skanthumb_base_register_rtx_p (rtx x, enum machine_mode mode, int strict_p)
3691132718Skan{
3692132718Skan  int regno;
3693132718Skan
3694132718Skan  if (GET_CODE (x) != REG)
3695132718Skan    return 0;
3696132718Skan
3697132718Skan  regno = REGNO (x);
3698132718Skan
3699132718Skan  if (strict_p)
3700132718Skan    return THUMB_REGNO_MODE_OK_FOR_BASE_P (regno, mode);
3701132718Skan
3702132718Skan  return (regno <= LAST_LO_REGNUM
3703132718Skan	  || regno > LAST_VIRTUAL_REGISTER
3704132718Skan	  || regno == FRAME_POINTER_REGNUM
3705132718Skan	  || (GET_MODE_SIZE (mode) >= 4
3706132718Skan	      && (regno == STACK_POINTER_REGNUM
3707132718Skan		  || regno >= FIRST_PSEUDO_REGISTER
3708132718Skan		  || x == hard_frame_pointer_rtx
3709132718Skan		  || x == arg_pointer_rtx)));
3710132718Skan}
3711132718Skan
3712132718Skan/* Return nonzero if x is a legitimate index register.  This is the case
3713132718Skan   for any base register that can access a QImode object.  */
3714132718Skaninline static int
3715132718Skanthumb_index_register_rtx_p (rtx x, int strict_p)
3716132718Skan{
3717132718Skan  return thumb_base_register_rtx_p (x, QImode, strict_p);
3718132718Skan}
3719132718Skan
3720132718Skan/* Return nonzero if x is a legitimate Thumb-state address.
3721169689Skan
3722132718Skan   The AP may be eliminated to either the SP or the FP, so we use the
3723132718Skan   least common denominator, e.g. SImode, and offsets from 0 to 64.
3724132718Skan
3725132718Skan   ??? Verify whether the above is the right approach.
3726132718Skan
3727132718Skan   ??? Also, the FP may be eliminated to the SP, so perhaps that
3728132718Skan   needs special handling also.
3729132718Skan
3730132718Skan   ??? Look at how the mips16 port solves this problem.  It probably uses
3731132718Skan   better ways to solve some of these problems.
3732132718Skan
3733132718Skan   Although it is not incorrect, we don't accept QImode and HImode
3734132718Skan   addresses based on the frame pointer or arg pointer until the
3735132718Skan   reload pass starts.  This is so that eliminating such addresses
3736132718Skan   into stack based ones won't produce impossible code.  */
3737132718Skanint
3738132718Skanthumb_legitimate_address_p (enum machine_mode mode, rtx x, int strict_p)
3739132718Skan{
3740132718Skan  /* ??? Not clear if this is right.  Experiment.  */
3741132718Skan  if (GET_MODE_SIZE (mode) < 4
3742132718Skan      && !(reload_in_progress || reload_completed)
3743132718Skan      && (reg_mentioned_p (frame_pointer_rtx, x)
3744132718Skan	  || reg_mentioned_p (arg_pointer_rtx, x)
3745132718Skan	  || reg_mentioned_p (virtual_incoming_args_rtx, x)
3746132718Skan	  || reg_mentioned_p (virtual_outgoing_args_rtx, x)
3747132718Skan	  || reg_mentioned_p (virtual_stack_dynamic_rtx, x)
3748132718Skan	  || reg_mentioned_p (virtual_stack_vars_rtx, x)))
3749132718Skan    return 0;
3750132718Skan
3751132718Skan  /* Accept any base register.  SP only in SImode or larger.  */
3752132718Skan  else if (thumb_base_register_rtx_p (x, mode, strict_p))
3753132718Skan    return 1;
3754132718Skan
3755132718Skan  /* This is PC relative data before arm_reorg runs.  */
3756132718Skan  else if (GET_MODE_SIZE (mode) >= 4 && CONSTANT_P (x)
3757132718Skan	   && GET_CODE (x) == SYMBOL_REF
3758169689Skan           && CONSTANT_POOL_ADDRESS_P (x) && !flag_pic)
3759132718Skan    return 1;
3760132718Skan
3761132718Skan  /* This is PC relative data after arm_reorg runs.  */
3762132718Skan  else if (GET_MODE_SIZE (mode) >= 4 && reload_completed
3763132718Skan	   && (GET_CODE (x) == LABEL_REF
3764132718Skan	       || (GET_CODE (x) == CONST
3765132718Skan		   && GET_CODE (XEXP (x, 0)) == PLUS
3766132718Skan		   && GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF
3767132718Skan		   && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)))
3768132718Skan    return 1;
3769132718Skan
3770132718Skan  /* Post-inc indexing only supported for SImode and larger.  */
3771132718Skan  else if (GET_CODE (x) == POST_INC && GET_MODE_SIZE (mode) >= 4
3772132718Skan	   && thumb_index_register_rtx_p (XEXP (x, 0), strict_p))
3773132718Skan    return 1;
3774132718Skan
3775132718Skan  else if (GET_CODE (x) == PLUS)
3776132718Skan    {
3777132718Skan      /* REG+REG address can be any two index registers.  */
3778132718Skan      /* We disallow FRAME+REG addressing since we know that FRAME
3779132718Skan	 will be replaced with STACK, and SP relative addressing only
3780132718Skan	 permits SP+OFFSET.  */
3781132718Skan      if (GET_MODE_SIZE (mode) <= 4
3782132718Skan	  && XEXP (x, 0) != frame_pointer_rtx
3783132718Skan	  && XEXP (x, 1) != frame_pointer_rtx
3784132718Skan	  && thumb_index_register_rtx_p (XEXP (x, 0), strict_p)
3785132718Skan	  && thumb_index_register_rtx_p (XEXP (x, 1), strict_p))
3786132718Skan	return 1;
3787132718Skan
3788132718Skan      /* REG+const has 5-7 bit offset for non-SP registers.  */
3789132718Skan      else if ((thumb_index_register_rtx_p (XEXP (x, 0), strict_p)
3790132718Skan		|| XEXP (x, 0) == arg_pointer_rtx)
3791132718Skan	       && GET_CODE (XEXP (x, 1)) == CONST_INT
3792132718Skan	       && thumb_legitimate_offset_p (mode, INTVAL (XEXP (x, 1))))
3793132718Skan	return 1;
3794132718Skan
3795132718Skan      /* REG+const has 10 bit offset for SP, but only SImode and
3796132718Skan	 larger is supported.  */
3797132718Skan      /* ??? Should probably check for DI/DFmode overflow here
3798132718Skan	 just like GO_IF_LEGITIMATE_OFFSET does.  */
3799132718Skan      else if (GET_CODE (XEXP (x, 0)) == REG
3800132718Skan	       && REGNO (XEXP (x, 0)) == STACK_POINTER_REGNUM
3801132718Skan	       && GET_MODE_SIZE (mode) >= 4
3802132718Skan	       && GET_CODE (XEXP (x, 1)) == CONST_INT
3803132718Skan	       && INTVAL (XEXP (x, 1)) >= 0
3804132718Skan	       && INTVAL (XEXP (x, 1)) + GET_MODE_SIZE (mode) <= 1024
3805132718Skan	       && (INTVAL (XEXP (x, 1)) & 3) == 0)
3806132718Skan	return 1;
3807132718Skan
3808132718Skan      else if (GET_CODE (XEXP (x, 0)) == REG
3809132718Skan	       && REGNO (XEXP (x, 0)) == FRAME_POINTER_REGNUM
3810132718Skan	       && GET_MODE_SIZE (mode) >= 4
3811132718Skan	       && GET_CODE (XEXP (x, 1)) == CONST_INT
3812132718Skan	       && (INTVAL (XEXP (x, 1)) & 3) == 0)
3813132718Skan	return 1;
3814132718Skan    }
3815132718Skan
3816132718Skan  else if (GET_MODE_CLASS (mode) != MODE_FLOAT
3817132718Skan	   && GET_MODE_SIZE (mode) == 4
3818132718Skan	   && GET_CODE (x) == SYMBOL_REF
3819132718Skan	   && CONSTANT_POOL_ADDRESS_P (x)
3820169689Skan	   && ! (flag_pic
3821169689Skan		 && symbol_mentioned_p (get_pool_constant (x))
3822169689Skan		 && ! pcrel_constant_p (get_pool_constant (x))))
3823132718Skan    return 1;
3824132718Skan
3825132718Skan  return 0;
3826132718Skan}
3827132718Skan
3828132718Skan/* Return nonzero if VAL can be used as an offset in a Thumb-state address
3829132718Skan   instruction of mode MODE.  */
3830132718Skanint
3831132718Skanthumb_legitimate_offset_p (enum machine_mode mode, HOST_WIDE_INT val)
3832132718Skan{
3833132718Skan  switch (GET_MODE_SIZE (mode))
3834132718Skan    {
3835132718Skan    case 1:
3836132718Skan      return val >= 0 && val < 32;
3837132718Skan
3838132718Skan    case 2:
3839132718Skan      return val >= 0 && val < 64 && (val & 1) == 0;
3840132718Skan
3841132718Skan    default:
3842132718Skan      return (val >= 0
3843132718Skan	      && (val + GET_MODE_SIZE (mode)) <= 128
3844132718Skan	      && (val & 3) == 0);
3845132718Skan    }
3846132718Skan}
3847132718Skan
3848169689Skan/* Build the SYMBOL_REF for __tls_get_addr.  */
3849169689Skan
3850169689Skanstatic GTY(()) rtx tls_get_addr_libfunc;
3851169689Skan
3852169689Skanstatic rtx
3853169689Skanget_tls_get_addr (void)
3854169689Skan{
3855169689Skan  if (!tls_get_addr_libfunc)
3856169689Skan    tls_get_addr_libfunc = init_one_libfunc ("__tls_get_addr");
3857169689Skan  return tls_get_addr_libfunc;
3858169689Skan}
3859169689Skan
3860169689Skanstatic rtx
3861169689Skanarm_load_tp (rtx target)
3862169689Skan{
3863169689Skan  if (!target)
3864169689Skan    target = gen_reg_rtx (SImode);
3865169689Skan
3866169689Skan  if (TARGET_HARD_TP)
3867169689Skan    {
3868169689Skan      /* Can return in any reg.  */
3869169689Skan      emit_insn (gen_load_tp_hard (target));
3870169689Skan    }
3871169689Skan  else
3872169689Skan    {
3873169689Skan      /* Always returned in r0.  Immediately copy the result into a pseudo,
3874169689Skan	 otherwise other uses of r0 (e.g. setting up function arguments) may
3875169689Skan	 clobber the value.  */
3876169689Skan
3877169689Skan      rtx tmp;
3878169689Skan
3879169689Skan      emit_insn (gen_load_tp_soft ());
3880169689Skan
3881169689Skan      tmp = gen_rtx_REG (SImode, 0);
3882169689Skan      emit_move_insn (target, tmp);
3883169689Skan    }
3884169689Skan  return target;
3885169689Skan}
3886169689Skan
3887169689Skanstatic rtx
3888169689Skanload_tls_operand (rtx x, rtx reg)
3889169689Skan{
3890169689Skan  rtx tmp;
3891169689Skan
3892169689Skan  if (reg == NULL_RTX)
3893169689Skan    reg = gen_reg_rtx (SImode);
3894169689Skan
3895169689Skan  tmp = gen_rtx_CONST (SImode, x);
3896169689Skan
3897169689Skan  emit_move_insn (reg, tmp);
3898169689Skan
3899169689Skan  return reg;
3900169689Skan}
3901169689Skan
3902169689Skanstatic rtx
3903169689Skanarm_call_tls_get_addr (rtx x, rtx reg, rtx *valuep, int reloc)
3904169689Skan{
3905169689Skan  rtx insns, label, labelno, sum;
3906169689Skan
3907169689Skan  start_sequence ();
3908169689Skan
3909169689Skan  labelno = GEN_INT (pic_labelno++);
3910169689Skan  label = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, labelno), UNSPEC_PIC_LABEL);
3911169689Skan  label = gen_rtx_CONST (VOIDmode, label);
3912169689Skan
3913169689Skan  sum = gen_rtx_UNSPEC (Pmode,
3914169689Skan			gen_rtvec (4, x, GEN_INT (reloc), label,
3915169689Skan				   GEN_INT (TARGET_ARM ? 8 : 4)),
3916169689Skan			UNSPEC_TLS);
3917169689Skan  reg = load_tls_operand (sum, reg);
3918169689Skan
3919169689Skan  if (TARGET_ARM)
3920169689Skan    emit_insn (gen_pic_add_dot_plus_eight (reg, reg, labelno));
3921169689Skan  else
3922169689Skan    emit_insn (gen_pic_add_dot_plus_four (reg, reg, labelno));
3923169689Skan
3924169689Skan  *valuep = emit_library_call_value (get_tls_get_addr (), NULL_RTX, LCT_PURE, /* LCT_CONST?  */
3925169689Skan				     Pmode, 1, reg, Pmode);
3926169689Skan
3927169689Skan  insns = get_insns ();
3928169689Skan  end_sequence ();
3929169689Skan
3930169689Skan  return insns;
3931169689Skan}
3932169689Skan
3933169689Skanrtx
3934169689Skanlegitimize_tls_address (rtx x, rtx reg)
3935169689Skan{
3936169689Skan  rtx dest, tp, label, labelno, sum, insns, ret, eqv, addend;
3937169689Skan  unsigned int model = SYMBOL_REF_TLS_MODEL (x);
3938169689Skan
3939169689Skan  switch (model)
3940169689Skan    {
3941169689Skan    case TLS_MODEL_GLOBAL_DYNAMIC:
3942169689Skan      insns = arm_call_tls_get_addr (x, reg, &ret, TLS_GD32);
3943169689Skan      dest = gen_reg_rtx (Pmode);
3944169689Skan      emit_libcall_block (insns, dest, ret, x);
3945169689Skan      return dest;
3946169689Skan
3947169689Skan    case TLS_MODEL_LOCAL_DYNAMIC:
3948169689Skan      insns = arm_call_tls_get_addr (x, reg, &ret, TLS_LDM32);
3949169689Skan
3950169689Skan      /* Attach a unique REG_EQUIV, to allow the RTL optimizers to
3951169689Skan	 share the LDM result with other LD model accesses.  */
3952169689Skan      eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const1_rtx),
3953169689Skan			    UNSPEC_TLS);
3954169689Skan      dest = gen_reg_rtx (Pmode);
3955169689Skan      emit_libcall_block (insns, dest, ret, eqv);
3956169689Skan
3957169689Skan      /* Load the addend.  */
3958169689Skan      addend = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, x, GEN_INT (TLS_LDO32)),
3959169689Skan			       UNSPEC_TLS);
3960169689Skan      addend = force_reg (SImode, gen_rtx_CONST (SImode, addend));
3961169689Skan      return gen_rtx_PLUS (Pmode, dest, addend);
3962169689Skan
3963169689Skan    case TLS_MODEL_INITIAL_EXEC:
3964169689Skan      labelno = GEN_INT (pic_labelno++);
3965169689Skan      label = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, labelno), UNSPEC_PIC_LABEL);
3966169689Skan      label = gen_rtx_CONST (VOIDmode, label);
3967169689Skan      sum = gen_rtx_UNSPEC (Pmode,
3968169689Skan			    gen_rtvec (4, x, GEN_INT (TLS_IE32), label,
3969169689Skan				       GEN_INT (TARGET_ARM ? 8 : 4)),
3970169689Skan			    UNSPEC_TLS);
3971169689Skan      reg = load_tls_operand (sum, reg);
3972169689Skan
3973169689Skan      if (TARGET_ARM)
3974169689Skan	emit_insn (gen_tls_load_dot_plus_eight (reg, reg, labelno));
3975169689Skan      else
3976169689Skan	{
3977169689Skan	  emit_insn (gen_pic_add_dot_plus_four (reg, reg, labelno));
3978169689Skan	  emit_move_insn (reg, gen_const_mem (SImode, reg));
3979169689Skan	}
3980169689Skan
3981169689Skan      tp = arm_load_tp (NULL_RTX);
3982169689Skan
3983169689Skan      return gen_rtx_PLUS (Pmode, tp, reg);
3984169689Skan
3985169689Skan    case TLS_MODEL_LOCAL_EXEC:
3986169689Skan      tp = arm_load_tp (NULL_RTX);
3987169689Skan
3988169689Skan      reg = gen_rtx_UNSPEC (Pmode,
3989169689Skan			    gen_rtvec (2, x, GEN_INT (TLS_LE32)),
3990169689Skan			    UNSPEC_TLS);
3991169689Skan      reg = force_reg (SImode, gen_rtx_CONST (SImode, reg));
3992169689Skan
3993169689Skan      return gen_rtx_PLUS (Pmode, tp, reg);
3994169689Skan
3995169689Skan    default:
3996169689Skan      abort ();
3997169689Skan    }
3998169689Skan}
3999169689Skan
4000132718Skan/* Try machine-dependent ways of modifying an illegitimate address
4001132718Skan   to be legitimate.  If we find one, return the new, valid address.  */
4002132718Skanrtx
4003132718Skanarm_legitimize_address (rtx x, rtx orig_x, enum machine_mode mode)
4004132718Skan{
4005169689Skan  if (arm_tls_symbol_p (x))
4006169689Skan    return legitimize_tls_address (x, NULL_RTX);
4007169689Skan
4008132718Skan  if (GET_CODE (x) == PLUS)
4009132718Skan    {
4010132718Skan      rtx xop0 = XEXP (x, 0);
4011132718Skan      rtx xop1 = XEXP (x, 1);
4012132718Skan
4013132718Skan      if (CONSTANT_P (xop0) && !symbol_mentioned_p (xop0))
4014132718Skan	xop0 = force_reg (SImode, xop0);
4015132718Skan
4016132718Skan      if (CONSTANT_P (xop1) && !symbol_mentioned_p (xop1))
4017132718Skan	xop1 = force_reg (SImode, xop1);
4018132718Skan
4019132718Skan      if (ARM_BASE_REGISTER_RTX_P (xop0)
4020132718Skan	  && GET_CODE (xop1) == CONST_INT)
4021132718Skan	{
4022132718Skan	  HOST_WIDE_INT n, low_n;
4023132718Skan	  rtx base_reg, val;
4024132718Skan	  n = INTVAL (xop1);
4025132718Skan
4026169689Skan	  /* VFP addressing modes actually allow greater offsets, but for
4027169689Skan	     now we just stick with the lowest common denominator.  */
4028169689Skan	  if (mode == DImode
4029169689Skan	      || ((TARGET_SOFT_FLOAT || TARGET_VFP) && mode == DFmode))
4030132718Skan	    {
4031132718Skan	      low_n = n & 0x0f;
4032132718Skan	      n &= ~0x0f;
4033132718Skan	      if (low_n > 4)
4034132718Skan		{
4035132718Skan		  n += 16;
4036132718Skan		  low_n -= 16;
4037132718Skan		}
4038132718Skan	    }
4039132718Skan	  else
4040132718Skan	    {
4041132718Skan	      low_n = ((mode) == TImode ? 0
4042132718Skan		       : n >= 0 ? (n & 0xfff) : -((-n) & 0xfff));
4043132718Skan	      n -= low_n;
4044132718Skan	    }
4045132718Skan
4046132718Skan	  base_reg = gen_reg_rtx (SImode);
4047169689Skan	  val = force_operand (plus_constant (xop0, n), NULL_RTX);
4048132718Skan	  emit_move_insn (base_reg, val);
4049169689Skan	  x = plus_constant (base_reg, low_n);
4050132718Skan	}
4051132718Skan      else if (xop0 != XEXP (x, 0) || xop1 != XEXP (x, 1))
4052132718Skan	x = gen_rtx_PLUS (SImode, xop0, xop1);
4053132718Skan    }
4054132718Skan
4055132718Skan  /* XXX We don't allow MINUS any more -- see comment in
4056132718Skan     arm_legitimate_address_p ().  */
4057132718Skan  else if (GET_CODE (x) == MINUS)
4058132718Skan    {
4059132718Skan      rtx xop0 = XEXP (x, 0);
4060132718Skan      rtx xop1 = XEXP (x, 1);
4061132718Skan
4062132718Skan      if (CONSTANT_P (xop0))
4063132718Skan	xop0 = force_reg (SImode, xop0);
4064132718Skan
4065132718Skan      if (CONSTANT_P (xop1) && ! symbol_mentioned_p (xop1))
4066132718Skan	xop1 = force_reg (SImode, xop1);
4067132718Skan
4068132718Skan      if (xop0 != XEXP (x, 0) || xop1 != XEXP (x, 1))
4069132718Skan	x = gen_rtx_MINUS (SImode, xop0, xop1);
4070132718Skan    }
4071132718Skan
4072169689Skan  /* Make sure to take full advantage of the pre-indexed addressing mode
4073169689Skan     with absolute addresses which often allows for the base register to
4074169689Skan     be factorized for multiple adjacent memory references, and it might
4075169689Skan     even allows for the mini pool to be avoided entirely. */
4076169689Skan  else if (GET_CODE (x) == CONST_INT && optimize > 0)
4077169689Skan    {
4078169689Skan      unsigned int bits;
4079169689Skan      HOST_WIDE_INT mask, base, index;
4080169689Skan      rtx base_reg;
4081169689Skan
4082169689Skan      /* ldr and ldrb can use a 12 bit index, ldrsb and the rest can only
4083169689Skan         use a 8 bit index. So let's use a 12 bit index for SImode only and
4084169689Skan         hope that arm_gen_constant will enable ldrb to use more bits. */
4085169689Skan      bits = (mode == SImode) ? 12 : 8;
4086169689Skan      mask = (1 << bits) - 1;
4087169689Skan      base = INTVAL (x) & ~mask;
4088169689Skan      index = INTVAL (x) & mask;
4089169689Skan      if (bit_count (base & 0xffffffff) > (32 - bits)/2)
4090169689Skan        {
4091169689Skan	  /* It'll most probably be more efficient to generate the base
4092169689Skan	     with more bits set and use a negative index instead. */
4093169689Skan	  base |= mask;
4094169689Skan	  index -= mask;
4095169689Skan	}
4096169689Skan      base_reg = force_reg (SImode, GEN_INT (base));
4097169689Skan      x = plus_constant (base_reg, index);
4098169689Skan    }
4099169689Skan
4100132718Skan  if (flag_pic)
4101132718Skan    {
4102132718Skan      /* We need to find and carefully transform any SYMBOL and LABEL
4103132718Skan	 references; so go back to the original address expression.  */
4104132718Skan      rtx new_x = legitimize_pic_address (orig_x, mode, NULL_RTX);
4105132718Skan
4106132718Skan      if (new_x != orig_x)
4107132718Skan	x = new_x;
4108132718Skan    }
4109132718Skan
4110132718Skan  return x;
4111132718Skan}
4112132718Skan
4113169689Skan
4114169689Skan/* Try machine-dependent ways of modifying an illegitimate Thumb address
4115169689Skan   to be legitimate.  If we find one, return the new, valid address.  */
4116169689Skanrtx
4117169689Skanthumb_legitimize_address (rtx x, rtx orig_x, enum machine_mode mode)
4118169689Skan{
4119169689Skan  if (arm_tls_symbol_p (x))
4120169689Skan    return legitimize_tls_address (x, NULL_RTX);
4121169689Skan
4122169689Skan  if (GET_CODE (x) == PLUS
4123169689Skan      && GET_CODE (XEXP (x, 1)) == CONST_INT
4124169689Skan      && (INTVAL (XEXP (x, 1)) >= 32 * GET_MODE_SIZE (mode)
4125169689Skan	  || INTVAL (XEXP (x, 1)) < 0))
4126169689Skan    {
4127169689Skan      rtx xop0 = XEXP (x, 0);
4128169689Skan      rtx xop1 = XEXP (x, 1);
4129169689Skan      HOST_WIDE_INT offset = INTVAL (xop1);
4130169689Skan
4131169689Skan      /* Try and fold the offset into a biasing of the base register and
4132169689Skan	 then offsetting that.  Don't do this when optimizing for space
4133169689Skan	 since it can cause too many CSEs.  */
4134169689Skan      if (optimize_size && offset >= 0
4135169689Skan	  && offset < 256 + 31 * GET_MODE_SIZE (mode))
4136169689Skan	{
4137169689Skan	  HOST_WIDE_INT delta;
4138169689Skan
4139169689Skan	  if (offset >= 256)
4140169689Skan	    delta = offset - (256 - GET_MODE_SIZE (mode));
4141169689Skan	  else if (offset < 32 * GET_MODE_SIZE (mode) + 8)
4142169689Skan	    delta = 31 * GET_MODE_SIZE (mode);
4143169689Skan	  else
4144169689Skan	    delta = offset & (~31 * GET_MODE_SIZE (mode));
4145169689Skan
4146169689Skan	  xop0 = force_operand (plus_constant (xop0, offset - delta),
4147169689Skan				NULL_RTX);
4148169689Skan	  x = plus_constant (xop0, delta);
4149169689Skan	}
4150169689Skan      else if (offset < 0 && offset > -256)
4151169689Skan	/* Small negative offsets are best done with a subtract before the
4152169689Skan	   dereference, forcing these into a register normally takes two
4153169689Skan	   instructions.  */
4154169689Skan	x = force_operand (x, NULL_RTX);
4155169689Skan      else
4156169689Skan	{
4157169689Skan	  /* For the remaining cases, force the constant into a register.  */
4158169689Skan	  xop1 = force_reg (SImode, xop1);
4159169689Skan	  x = gen_rtx_PLUS (SImode, xop0, xop1);
4160169689Skan	}
4161169689Skan    }
4162169689Skan  else if (GET_CODE (x) == PLUS
4163169689Skan	   && s_register_operand (XEXP (x, 1), SImode)
4164169689Skan	   && !s_register_operand (XEXP (x, 0), SImode))
4165169689Skan    {
4166169689Skan      rtx xop0 = force_operand (XEXP (x, 0), NULL_RTX);
4167169689Skan
4168169689Skan      x = gen_rtx_PLUS (SImode, xop0, XEXP (x, 1));
4169169689Skan    }
4170169689Skan
4171169689Skan  if (flag_pic)
4172169689Skan    {
4173169689Skan      /* We need to find and carefully transform any SYMBOL and LABEL
4174169689Skan	 references; so go back to the original address expression.  */
4175169689Skan      rtx new_x = legitimize_pic_address (orig_x, mode, NULL_RTX);
4176169689Skan
4177169689Skan      if (new_x != orig_x)
4178169689Skan	x = new_x;
4179169689Skan    }
4180169689Skan
4181169689Skan  return x;
4182169689Skan}
4183169689Skan
4184169689Skanrtx
4185169689Skanthumb_legitimize_reload_address (rtx *x_p,
4186169689Skan				 enum machine_mode mode,
4187169689Skan				 int opnum, int type,
4188169689Skan				 int ind_levels ATTRIBUTE_UNUSED)
4189169689Skan{
4190169689Skan  rtx x = *x_p;
4191169689Skan
4192169689Skan  if (GET_CODE (x) == PLUS
4193169689Skan      && GET_MODE_SIZE (mode) < 4
4194169689Skan      && REG_P (XEXP (x, 0))
4195169689Skan      && XEXP (x, 0) == stack_pointer_rtx
4196169689Skan      && GET_CODE (XEXP (x, 1)) == CONST_INT
4197169689Skan      && !thumb_legitimate_offset_p (mode, INTVAL (XEXP (x, 1))))
4198169689Skan    {
4199169689Skan      rtx orig_x = x;
4200169689Skan
4201169689Skan      x = copy_rtx (x);
4202169689Skan      push_reload (orig_x, NULL_RTX, x_p, NULL, MODE_BASE_REG_CLASS (mode),
4203169689Skan		   Pmode, VOIDmode, 0, 0, opnum, type);
4204169689Skan      return x;
4205169689Skan    }
4206169689Skan
4207169689Skan  /* If both registers are hi-regs, then it's better to reload the
4208169689Skan     entire expression rather than each register individually.  That
4209169689Skan     only requires one reload register rather than two.  */
4210169689Skan  if (GET_CODE (x) == PLUS
4211169689Skan      && REG_P (XEXP (x, 0))
4212169689Skan      && REG_P (XEXP (x, 1))
4213169689Skan      && !REG_MODE_OK_FOR_REG_BASE_P (XEXP (x, 0), mode)
4214169689Skan      && !REG_MODE_OK_FOR_REG_BASE_P (XEXP (x, 1), mode))
4215169689Skan    {
4216169689Skan      rtx orig_x = x;
4217169689Skan
4218169689Skan      x = copy_rtx (x);
4219169689Skan      push_reload (orig_x, NULL_RTX, x_p, NULL, MODE_BASE_REG_CLASS (mode),
4220169689Skan		   Pmode, VOIDmode, 0, 0, opnum, type);
4221169689Skan      return x;
4222169689Skan    }
4223169689Skan
4224169689Skan  return NULL;
4225169689Skan}
4226169689Skan
4227169689Skan/* Test for various thread-local symbols.  */
4228169689Skan
4229169689Skan/* Return TRUE if X is a thread-local symbol.  */
4230169689Skan
4231169689Skanstatic bool
4232169689Skanarm_tls_symbol_p (rtx x)
4233169689Skan{
4234169689Skan  if (! TARGET_HAVE_TLS)
4235169689Skan    return false;
4236169689Skan
4237169689Skan  if (GET_CODE (x) != SYMBOL_REF)
4238169689Skan    return false;
4239169689Skan
4240169689Skan  return SYMBOL_REF_TLS_MODEL (x) != 0;
4241169689Skan}
4242169689Skan
4243169689Skan/* Helper for arm_tls_referenced_p.  */
4244169689Skan
4245169689Skanstatic int
4246169689Skanarm_tls_operand_p_1 (rtx *x, void *data ATTRIBUTE_UNUSED)
4247169689Skan{
4248169689Skan  if (GET_CODE (*x) == SYMBOL_REF)
4249169689Skan    return SYMBOL_REF_TLS_MODEL (*x) != 0;
4250169689Skan
4251169689Skan  /* Don't recurse into UNSPEC_TLS looking for TLS symbols; these are
4252169689Skan     TLS offsets, not real symbol references.  */
4253169689Skan  if (GET_CODE (*x) == UNSPEC
4254169689Skan      && XINT (*x, 1) == UNSPEC_TLS)
4255169689Skan    return -1;
4256169689Skan
4257169689Skan  return 0;
4258169689Skan}
4259169689Skan
4260169689Skan/* Return TRUE if X contains any TLS symbol references.  */
4261169689Skan
4262169689Skanbool
4263169689Skanarm_tls_referenced_p (rtx x)
4264169689Skan{
4265169689Skan  if (! TARGET_HAVE_TLS)
4266169689Skan    return false;
4267169689Skan
4268169689Skan  return for_each_rtx (&x, arm_tls_operand_p_1, NULL);
4269169689Skan}
4270132718Skan
427190075Sobrien#define REG_OR_SUBREG_REG(X)						\
427290075Sobrien  (GET_CODE (X) == REG							\
427390075Sobrien   || (GET_CODE (X) == SUBREG && GET_CODE (SUBREG_REG (X)) == REG))
427490075Sobrien
427590075Sobrien#define REG_OR_SUBREG_RTX(X)			\
427690075Sobrien   (GET_CODE (X) == REG ? (X) : SUBREG_REG (X))
427790075Sobrien
427890075Sobrien#ifndef COSTS_N_INSNS
427990075Sobrien#define COSTS_N_INSNS(N) ((N) * 4 - 2)
428090075Sobrien#endif
4281132718Skanstatic inline int
4282169689Skanthumb_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer)
428390075Sobrien{
428490075Sobrien  enum machine_mode mode = GET_MODE (x);
428590075Sobrien
4286169689Skan  switch (code)
428790075Sobrien    {
4288169689Skan    case ASHIFT:
4289169689Skan    case ASHIFTRT:
4290169689Skan    case LSHIFTRT:
4291169689Skan    case ROTATERT:
4292169689Skan    case PLUS:
4293169689Skan    case MINUS:
4294169689Skan    case COMPARE:
4295169689Skan    case NEG:
4296169689Skan    case NOT:
4297169689Skan      return COSTS_N_INSNS (1);
4298169689Skan
4299169689Skan    case MULT:
4300169689Skan      if (GET_CODE (XEXP (x, 1)) == CONST_INT)
430190075Sobrien	{
4302169689Skan	  int cycles = 0;
4303169689Skan	  unsigned HOST_WIDE_INT i = INTVAL (XEXP (x, 1));
4304169689Skan
4305169689Skan	  while (i)
4306169689Skan	    {
4307169689Skan	      i >>= 2;
4308169689Skan	      cycles++;
430990075Sobrien	    }
4310169689Skan	  return COSTS_N_INSNS (2) + cycles;
4311169689Skan	}
4312169689Skan      return COSTS_N_INSNS (1) + 16;
4313169689Skan
4314169689Skan    case SET:
4315169689Skan      return (COSTS_N_INSNS (1)
4316169689Skan	      + 4 * ((GET_CODE (SET_SRC (x)) == MEM)
4317169689Skan		     + GET_CODE (SET_DEST (x)) == MEM));
4318169689Skan
4319169689Skan    case CONST_INT:
4320169689Skan      if (outer == SET)
4321169689Skan	{
4322169689Skan	  if ((unsigned HOST_WIDE_INT) INTVAL (x) < 256)
4323132718Skan	    return 0;
4324169689Skan	  if (thumb_shiftable_const (INTVAL (x)))
4325169689Skan	    return COSTS_N_INSNS (2);
432690075Sobrien	  return COSTS_N_INSNS (3);
4327169689Skan	}
4328169689Skan      else if ((outer == PLUS || outer == COMPARE)
4329169689Skan	       && INTVAL (x) < 256 && INTVAL (x) > -256)
4330169689Skan	return 0;
4331169689Skan      else if (outer == AND
4332169689Skan	       && INTVAL (x) < 256 && INTVAL (x) >= -256)
4333169689Skan	return COSTS_N_INSNS (1);
4334169689Skan      else if (outer == ASHIFT || outer == ASHIFTRT
4335169689Skan	       || outer == LSHIFTRT)
4336169689Skan	return 0;
4337169689Skan      return COSTS_N_INSNS (2);
433890075Sobrien
4339169689Skan    case CONST:
4340169689Skan    case CONST_DOUBLE:
4341169689Skan    case LABEL_REF:
4342169689Skan    case SYMBOL_REF:
4343169689Skan      return COSTS_N_INSNS (3);
434490075Sobrien
4345169689Skan    case UDIV:
4346169689Skan    case UMOD:
4347169689Skan    case DIV:
4348169689Skan    case MOD:
4349169689Skan      return 100;
435090075Sobrien
4351169689Skan    case TRUNCATE:
4352169689Skan      return 99;
435390075Sobrien
4354169689Skan    case AND:
4355169689Skan    case XOR:
4356169689Skan    case IOR:
4357169689Skan      /* XXX guess.  */
4358169689Skan      return 8;
435990075Sobrien
4360169689Skan    case MEM:
4361169689Skan      /* XXX another guess.  */
4362169689Skan      /* Memory costs quite a lot for the first word, but subsequent words
4363169689Skan	 load at the equivalent of a single insn each.  */
4364169689Skan      return (10 + 4 * ((GET_MODE_SIZE (mode) - 1) / UNITS_PER_WORD)
4365169689Skan	      + ((GET_CODE (x) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (x))
4366169689Skan		 ? 4 : 0));
4367169689Skan
4368169689Skan    case IF_THEN_ELSE:
4369169689Skan      /* XXX a guess.  */
4370169689Skan      if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC)
4371169689Skan	return 14;
4372169689Skan      return 2;
4373169689Skan
4374169689Skan    case ZERO_EXTEND:
4375169689Skan      /* XXX still guessing.  */
4376169689Skan      switch (GET_MODE (XEXP (x, 0)))
4377169689Skan	{
4378169689Skan	case QImode:
4379169689Skan	  return (1 + (mode == DImode ? 4 : 0)
4380169689Skan		  + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
4381169689Skan
4382169689Skan	case HImode:
4383169689Skan	  return (4 + (mode == DImode ? 4 : 0)
4384169689Skan		  + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
4385169689Skan
4386169689Skan	case SImode:
4387169689Skan	  return (1 + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
4388169689Skan
438990075Sobrien	default:
439090075Sobrien	  return 99;
439190075Sobrien	}
4392169689Skan
4393169689Skan    default:
4394169689Skan      return 99;
439590075Sobrien    }
4396169689Skan}
4397169689Skan
4398169689Skan
4399169689Skan/* Worker routine for arm_rtx_costs.  */
4400169689Skanstatic inline int
4401169689Skanarm_rtx_costs_1 (rtx x, enum rtx_code code, enum rtx_code outer)
4402169689Skan{
4403169689Skan  enum machine_mode mode = GET_MODE (x);
4404169689Skan  enum rtx_code subcode;
4405169689Skan  int extra_cost;
4406169689Skan
440790075Sobrien  switch (code)
440890075Sobrien    {
440990075Sobrien    case MEM:
441090075Sobrien      /* Memory costs quite a lot for the first word, but subsequent words
441190075Sobrien	 load at the equivalent of a single insn each.  */
441290075Sobrien      return (10 + 4 * ((GET_MODE_SIZE (mode) - 1) / UNITS_PER_WORD)
4413117395Skan	      + (GET_CODE (x) == SYMBOL_REF
4414117395Skan		 && CONSTANT_POOL_ADDRESS_P (x) ? 4 : 0));
441590075Sobrien
441690075Sobrien    case DIV:
441790075Sobrien    case MOD:
4418132718Skan    case UDIV:
4419132718Skan    case UMOD:
4420132718Skan      return optimize_size ? COSTS_N_INSNS (2) : 100;
442190075Sobrien
442290075Sobrien    case ROTATE:
442390075Sobrien      if (mode == SImode && GET_CODE (XEXP (x, 1)) == REG)
442490075Sobrien	return 4;
442590075Sobrien      /* Fall through */
442690075Sobrien    case ROTATERT:
442790075Sobrien      if (mode != SImode)
442890075Sobrien	return 8;
442990075Sobrien      /* Fall through */
443090075Sobrien    case ASHIFT: case LSHIFTRT: case ASHIFTRT:
443190075Sobrien      if (mode == DImode)
443290075Sobrien	return (8 + (GET_CODE (XEXP (x, 1)) == CONST_INT ? 0 : 8)
4433169689Skan		+ ((GET_CODE (XEXP (x, 0)) == REG
443490075Sobrien		    || (GET_CODE (XEXP (x, 0)) == SUBREG
443590075Sobrien			&& GET_CODE (SUBREG_REG (XEXP (x, 0))) == REG))
443690075Sobrien		   ? 0 : 8));
443790075Sobrien      return (1 + ((GET_CODE (XEXP (x, 0)) == REG
443890075Sobrien		    || (GET_CODE (XEXP (x, 0)) == SUBREG
443990075Sobrien			&& GET_CODE (SUBREG_REG (XEXP (x, 0))) == REG))
444090075Sobrien		   ? 0 : 4)
444190075Sobrien	      + ((GET_CODE (XEXP (x, 1)) == REG
444290075Sobrien		  || (GET_CODE (XEXP (x, 1)) == SUBREG
444390075Sobrien		      && GET_CODE (SUBREG_REG (XEXP (x, 1))) == REG)
444490075Sobrien		  || (GET_CODE (XEXP (x, 1)) == CONST_INT))
444590075Sobrien		 ? 0 : 4));
444690075Sobrien
444790075Sobrien    case MINUS:
444890075Sobrien      if (mode == DImode)
444990075Sobrien	return (4 + (REG_OR_SUBREG_REG (XEXP (x, 1)) ? 0 : 8)
445090075Sobrien		+ ((REG_OR_SUBREG_REG (XEXP (x, 0))
445190075Sobrien		    || (GET_CODE (XEXP (x, 0)) == CONST_INT
445290075Sobrien		       && const_ok_for_arm (INTVAL (XEXP (x, 0)))))
445390075Sobrien		   ? 0 : 8));
445490075Sobrien
445590075Sobrien      if (GET_MODE_CLASS (mode) == MODE_FLOAT)
445690075Sobrien	return (2 + ((REG_OR_SUBREG_REG (XEXP (x, 1))
445790075Sobrien		      || (GET_CODE (XEXP (x, 1)) == CONST_DOUBLE
4458169689Skan			  && arm_const_double_rtx (XEXP (x, 1))))
445990075Sobrien		     ? 0 : 8)
446090075Sobrien		+ ((REG_OR_SUBREG_REG (XEXP (x, 0))
446190075Sobrien		    || (GET_CODE (XEXP (x, 0)) == CONST_DOUBLE
4462169689Skan			&& arm_const_double_rtx (XEXP (x, 0))))
446390075Sobrien		   ? 0 : 8));
446490075Sobrien
446590075Sobrien      if (((GET_CODE (XEXP (x, 0)) == CONST_INT
446690075Sobrien	    && const_ok_for_arm (INTVAL (XEXP (x, 0)))
446790075Sobrien	    && REG_OR_SUBREG_REG (XEXP (x, 1))))
446890075Sobrien	  || (((subcode = GET_CODE (XEXP (x, 1))) == ASHIFT
446990075Sobrien	       || subcode == ASHIFTRT || subcode == LSHIFTRT
447090075Sobrien	       || subcode == ROTATE || subcode == ROTATERT
447190075Sobrien	       || (subcode == MULT
447290075Sobrien		   && GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT
447390075Sobrien		   && ((INTVAL (XEXP (XEXP (x, 1), 1)) &
447490075Sobrien			(INTVAL (XEXP (XEXP (x, 1), 1)) - 1)) == 0)))
447590075Sobrien	      && REG_OR_SUBREG_REG (XEXP (XEXP (x, 1), 0))
447690075Sobrien	      && (REG_OR_SUBREG_REG (XEXP (XEXP (x, 1), 1))
447790075Sobrien		  || GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT)
447890075Sobrien	      && REG_OR_SUBREG_REG (XEXP (x, 0))))
447990075Sobrien	return 1;
448090075Sobrien      /* Fall through */
448190075Sobrien
4482169689Skan    case PLUS:
4483169689Skan      if (GET_CODE (XEXP (x, 0)) == MULT)
4484169689Skan	{
4485169689Skan	  extra_cost = rtx_cost (XEXP (x, 0), code);
4486169689Skan	  if (!REG_OR_SUBREG_REG (XEXP (x, 1)))
4487169689Skan	    extra_cost += 4 * ARM_NUM_REGS (mode);
4488169689Skan	  return extra_cost;
4489169689Skan	}
4490169689Skan
449190075Sobrien      if (GET_MODE_CLASS (mode) == MODE_FLOAT)
449290075Sobrien	return (2 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 8)
449390075Sobrien		+ ((REG_OR_SUBREG_REG (XEXP (x, 1))
449490075Sobrien		    || (GET_CODE (XEXP (x, 1)) == CONST_DOUBLE
4495169689Skan			&& arm_const_double_rtx (XEXP (x, 1))))
449690075Sobrien		   ? 0 : 8));
449790075Sobrien
449890075Sobrien      /* Fall through */
4499169689Skan    case AND: case XOR: case IOR:
450090075Sobrien      extra_cost = 0;
450190075Sobrien
450290075Sobrien      /* Normally the frame registers will be spilt into reg+const during
450390075Sobrien	 reload, so it is a bad idea to combine them with other instructions,
450490075Sobrien	 since then they might not be moved outside of loops.  As a compromise
450590075Sobrien	 we allow integration with ops that have a constant as their second
450690075Sobrien	 operand.  */
450790075Sobrien      if ((REG_OR_SUBREG_REG (XEXP (x, 0))
450890075Sobrien	   && ARM_FRAME_RTX (REG_OR_SUBREG_RTX (XEXP (x, 0)))
450990075Sobrien	   && GET_CODE (XEXP (x, 1)) != CONST_INT)
451090075Sobrien	  || (REG_OR_SUBREG_REG (XEXP (x, 0))
451190075Sobrien	      && ARM_FRAME_RTX (REG_OR_SUBREG_RTX (XEXP (x, 0)))))
451290075Sobrien	extra_cost = 4;
451390075Sobrien
451490075Sobrien      if (mode == DImode)
451590075Sobrien	return (4 + extra_cost + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 8)
451690075Sobrien		+ ((REG_OR_SUBREG_REG (XEXP (x, 1))
451790075Sobrien		    || (GET_CODE (XEXP (x, 1)) == CONST_INT
451890075Sobrien			&& const_ok_for_op (INTVAL (XEXP (x, 1)), code)))
451990075Sobrien		   ? 0 : 8));
452090075Sobrien
452190075Sobrien      if (REG_OR_SUBREG_REG (XEXP (x, 0)))
452290075Sobrien	return (1 + (GET_CODE (XEXP (x, 1)) == CONST_INT ? 0 : extra_cost)
452390075Sobrien		+ ((REG_OR_SUBREG_REG (XEXP (x, 1))
452490075Sobrien		    || (GET_CODE (XEXP (x, 1)) == CONST_INT
452590075Sobrien			&& const_ok_for_op (INTVAL (XEXP (x, 1)), code)))
452690075Sobrien		   ? 0 : 4));
452790075Sobrien
452890075Sobrien      else if (REG_OR_SUBREG_REG (XEXP (x, 1)))
452990075Sobrien	return (1 + extra_cost
453090075Sobrien		+ ((((subcode = GET_CODE (XEXP (x, 0))) == ASHIFT
453190075Sobrien		     || subcode == LSHIFTRT || subcode == ASHIFTRT
453290075Sobrien		     || subcode == ROTATE || subcode == ROTATERT
453390075Sobrien		     || (subcode == MULT
453490075Sobrien			 && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
453590075Sobrien			 && ((INTVAL (XEXP (XEXP (x, 0), 1)) &
453690075Sobrien			      (INTVAL (XEXP (XEXP (x, 0), 1)) - 1)) == 0)))
453790075Sobrien		    && (REG_OR_SUBREG_REG (XEXP (XEXP (x, 0), 0)))
453890075Sobrien		    && ((REG_OR_SUBREG_REG (XEXP (XEXP (x, 0), 1)))
453990075Sobrien			|| GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT))
454090075Sobrien		   ? 0 : 4));
454190075Sobrien
454290075Sobrien      return 8;
454390075Sobrien
454490075Sobrien    case MULT:
4545169689Skan      /* This should have been handled by the CPU specific routines.  */
4546169689Skan      gcc_unreachable ();
454790075Sobrien
454890075Sobrien    case TRUNCATE:
4549169689Skan      if (arm_arch3m && mode == SImode
455090075Sobrien	  && GET_CODE (XEXP (x, 0)) == LSHIFTRT
455190075Sobrien	  && GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT
455290075Sobrien	  && (GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0))
455390075Sobrien	      == GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 1)))
455490075Sobrien	  && (GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == ZERO_EXTEND
455590075Sobrien	      || GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == SIGN_EXTEND))
455690075Sobrien	return 8;
455790075Sobrien      return 99;
455890075Sobrien
455990075Sobrien    case NEG:
456090075Sobrien      if (GET_MODE_CLASS (mode) == MODE_FLOAT)
456190075Sobrien	return 4 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 6);
456290075Sobrien      /* Fall through */
456390075Sobrien    case NOT:
456490075Sobrien      if (mode == DImode)
456590075Sobrien	return 4 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4);
456690075Sobrien
456790075Sobrien      return 1 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4);
456890075Sobrien
456990075Sobrien    case IF_THEN_ELSE:
457090075Sobrien      if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC)
457190075Sobrien	return 14;
457290075Sobrien      return 2;
457390075Sobrien
457490075Sobrien    case COMPARE:
457590075Sobrien      return 1;
457690075Sobrien
457790075Sobrien    case ABS:
457890075Sobrien      return 4 + (mode == DImode ? 4 : 0);
457990075Sobrien
458090075Sobrien    case SIGN_EXTEND:
458190075Sobrien      if (GET_MODE (XEXP (x, 0)) == QImode)
458290075Sobrien	return (4 + (mode == DImode ? 4 : 0)
458390075Sobrien		+ (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
458490075Sobrien      /* Fall through */
458590075Sobrien    case ZERO_EXTEND:
458690075Sobrien      switch (GET_MODE (XEXP (x, 0)))
458790075Sobrien	{
458890075Sobrien	case QImode:
458990075Sobrien	  return (1 + (mode == DImode ? 4 : 0)
459090075Sobrien		  + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
459190075Sobrien
459290075Sobrien	case HImode:
459390075Sobrien	  return (4 + (mode == DImode ? 4 : 0)
459490075Sobrien		  + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
459590075Sobrien
459690075Sobrien	case SImode:
459790075Sobrien	  return (1 + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
459890075Sobrien
4599132718Skan	case V8QImode:
4600132718Skan	case V4HImode:
4601132718Skan	case V2SImode:
4602132718Skan	case V4QImode:
4603132718Skan	case V2HImode:
4604132718Skan	    return 1;
4605132718Skan
460690075Sobrien	default:
4607169689Skan	  gcc_unreachable ();
460890075Sobrien	}
4609169689Skan      gcc_unreachable ();
461090075Sobrien
4611169689Skan    case CONST_INT:
4612169689Skan      if (const_ok_for_arm (INTVAL (x)))
4613169689Skan	return outer == SET ? 2 : -1;
4614169689Skan      else if (outer == AND
4615169689Skan	       && const_ok_for_arm (~INTVAL (x)))
4616169689Skan	return -1;
4617169689Skan      else if ((outer == COMPARE
4618169689Skan		|| outer == PLUS || outer == MINUS)
4619169689Skan	       && const_ok_for_arm (-INTVAL (x)))
4620169689Skan	return -1;
4621169689Skan      else
462290075Sobrien	return 5;
4623169689Skan
4624169689Skan    case CONST:
4625169689Skan    case LABEL_REF:
4626169689Skan    case SYMBOL_REF:
462790075Sobrien      return 6;
4628169689Skan
4629169689Skan    case CONST_DOUBLE:
4630169689Skan      if (arm_const_double_rtx (x))
4631169689Skan	return outer == SET ? 2 : -1;
4632169689Skan      else if ((outer == COMPARE || outer == PLUS)
4633169689Skan	       && neg_const_double_rtx_ok_for_fpa (x))
4634169689Skan	return -1;
463590075Sobrien      return 7;
4636169689Skan
463790075Sobrien    default:
463890075Sobrien      return 99;
463990075Sobrien    }
464090075Sobrien}
464190075Sobrien
4642169689Skan/* RTX costs when optimizing for size.  */
4643132718Skanstatic bool
4644169689Skanarm_size_rtx_costs (rtx x, int code, int outer_code, int *total)
4645132718Skan{
4646169689Skan  enum machine_mode mode = GET_MODE (x);
4647169689Skan
4648169689Skan  if (TARGET_THUMB)
4649169689Skan    {
4650169689Skan      /* XXX TBD.  For now, use the standard costs.  */
4651169689Skan      *total = thumb_rtx_costs (x, code, outer_code);
4652169689Skan      return true;
4653169689Skan    }
4654169689Skan
4655169689Skan  switch (code)
4656169689Skan    {
4657169689Skan    case MEM:
4658169689Skan      /* A memory access costs 1 insn if the mode is small, or the address is
4659169689Skan	 a single register, otherwise it costs one insn per word.  */
4660169689Skan      if (REG_P (XEXP (x, 0)))
4661169689Skan	*total = COSTS_N_INSNS (1);
4662169689Skan      else
4663169689Skan	*total = COSTS_N_INSNS (ARM_NUM_REGS (mode));
4664169689Skan      return true;
4665169689Skan
4666169689Skan    case DIV:
4667169689Skan    case MOD:
4668169689Skan    case UDIV:
4669169689Skan    case UMOD:
4670169689Skan      /* Needs a libcall, so it costs about this.  */
4671169689Skan      *total = COSTS_N_INSNS (2);
4672169689Skan      return false;
4673169689Skan
4674169689Skan    case ROTATE:
4675169689Skan      if (mode == SImode && GET_CODE (XEXP (x, 1)) == REG)
4676169689Skan	{
4677169689Skan	  *total = COSTS_N_INSNS (2) + rtx_cost (XEXP (x, 0), code);
4678169689Skan	  return true;
4679169689Skan	}
4680169689Skan      /* Fall through */
4681169689Skan    case ROTATERT:
4682169689Skan    case ASHIFT:
4683169689Skan    case LSHIFTRT:
4684169689Skan    case ASHIFTRT:
4685169689Skan      if (mode == DImode && GET_CODE (XEXP (x, 1)) == CONST_INT)
4686169689Skan	{
4687169689Skan	  *total = COSTS_N_INSNS (3) + rtx_cost (XEXP (x, 0), code);
4688169689Skan	  return true;
4689169689Skan	}
4690169689Skan      else if (mode == SImode)
4691169689Skan	{
4692169689Skan	  *total = COSTS_N_INSNS (1) + rtx_cost (XEXP (x, 0), code);
4693169689Skan	  /* Slightly disparage register shifts, but not by much.  */
4694169689Skan	  if (GET_CODE (XEXP (x, 1)) != CONST_INT)
4695169689Skan	    *total += 1 + rtx_cost (XEXP (x, 1), code);
4696169689Skan	  return true;
4697169689Skan	}
4698169689Skan
4699169689Skan      /* Needs a libcall.  */
4700169689Skan      *total = COSTS_N_INSNS (2);
4701169689Skan      return false;
4702169689Skan
4703169689Skan    case MINUS:
4704169689Skan      if (TARGET_HARD_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT)
4705169689Skan	{
4706169689Skan	  *total = COSTS_N_INSNS (1);
4707169689Skan	  return false;
4708169689Skan	}
4709169689Skan
4710169689Skan      if (mode == SImode)
4711169689Skan	{
4712169689Skan	  enum rtx_code subcode0 = GET_CODE (XEXP (x, 0));
4713169689Skan	  enum rtx_code subcode1 = GET_CODE (XEXP (x, 1));
4714169689Skan
4715169689Skan	  if (subcode0 == ROTATE || subcode0 == ROTATERT || subcode0 == ASHIFT
4716169689Skan	      || subcode0 == LSHIFTRT || subcode0 == ASHIFTRT
4717169689Skan	      || subcode1 == ROTATE || subcode1 == ROTATERT
4718169689Skan	      || subcode1 == ASHIFT || subcode1 == LSHIFTRT
4719169689Skan	      || subcode1 == ASHIFTRT)
4720169689Skan	    {
4721169689Skan	      /* It's just the cost of the two operands.  */
4722169689Skan	      *total = 0;
4723169689Skan	      return false;
4724169689Skan	    }
4725169689Skan
4726169689Skan	  *total = COSTS_N_INSNS (1);
4727169689Skan	  return false;
4728169689Skan	}
4729169689Skan
4730169689Skan      *total = COSTS_N_INSNS (ARM_NUM_REGS (mode));
4731169689Skan      return false;
4732169689Skan
4733169689Skan    case PLUS:
4734169689Skan      if (TARGET_HARD_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT)
4735169689Skan	{
4736169689Skan	  *total = COSTS_N_INSNS (1);
4737169689Skan	  return false;
4738169689Skan	}
4739169689Skan
4740169689Skan      /* Fall through */
4741169689Skan    case AND: case XOR: case IOR:
4742169689Skan      if (mode == SImode)
4743169689Skan	{
4744169689Skan	  enum rtx_code subcode = GET_CODE (XEXP (x, 0));
4745169689Skan
4746169689Skan	  if (subcode == ROTATE || subcode == ROTATERT || subcode == ASHIFT
4747169689Skan	      || subcode == LSHIFTRT || subcode == ASHIFTRT
4748169689Skan	      || (code == AND && subcode == NOT))
4749169689Skan	    {
4750169689Skan	      /* It's just the cost of the two operands.  */
4751169689Skan	      *total = 0;
4752169689Skan	      return false;
4753169689Skan	    }
4754169689Skan	}
4755169689Skan
4756169689Skan      *total = COSTS_N_INSNS (ARM_NUM_REGS (mode));
4757169689Skan      return false;
4758169689Skan
4759169689Skan    case MULT:
4760169689Skan      *total = COSTS_N_INSNS (ARM_NUM_REGS (mode));
4761169689Skan      return false;
4762169689Skan
4763169689Skan    case NEG:
4764169689Skan      if (TARGET_HARD_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT)
4765169689Skan	*total = COSTS_N_INSNS (1);
4766169689Skan      /* Fall through */
4767169689Skan    case NOT:
4768169689Skan      *total = COSTS_N_INSNS (ARM_NUM_REGS (mode));
4769169689Skan
4770169689Skan      return false;
4771169689Skan
4772169689Skan    case IF_THEN_ELSE:
4773169689Skan      *total = 0;
4774169689Skan      return false;
4775169689Skan
4776169689Skan    case COMPARE:
4777169689Skan      if (cc_register (XEXP (x, 0), VOIDmode))
4778169689Skan	* total = 0;
4779169689Skan      else
4780169689Skan	*total = COSTS_N_INSNS (1);
4781169689Skan      return false;
4782169689Skan
4783169689Skan    case ABS:
4784169689Skan      if (TARGET_HARD_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT)
4785169689Skan	*total = COSTS_N_INSNS (1);
4786169689Skan      else
4787169689Skan	*total = COSTS_N_INSNS (1 + ARM_NUM_REGS (mode));
4788169689Skan      return false;
4789169689Skan
4790169689Skan    case SIGN_EXTEND:
4791169689Skan      *total = 0;
4792169689Skan      if (GET_MODE_SIZE (GET_MODE (XEXP (x, 0))) < 4)
4793169689Skan	{
4794169689Skan	  if (!(arm_arch4 && MEM_P (XEXP (x, 0))))
4795169689Skan	    *total += COSTS_N_INSNS (arm_arch6 ? 1 : 2);
4796169689Skan	}
4797169689Skan      if (mode == DImode)
4798169689Skan	*total += COSTS_N_INSNS (1);
4799169689Skan      return false;
4800169689Skan
4801169689Skan    case ZERO_EXTEND:
4802169689Skan      *total = 0;
4803169689Skan      if (!(arm_arch4 && MEM_P (XEXP (x, 0))))
4804169689Skan	{
4805169689Skan	  switch (GET_MODE (XEXP (x, 0)))
4806169689Skan	    {
4807169689Skan	    case QImode:
4808169689Skan	      *total += COSTS_N_INSNS (1);
4809169689Skan	      break;
4810169689Skan
4811169689Skan	    case HImode:
4812169689Skan	      *total += COSTS_N_INSNS (arm_arch6 ? 1 : 2);
4813169689Skan
4814169689Skan	    case SImode:
4815169689Skan	      break;
4816169689Skan
4817169689Skan	    default:
4818169689Skan	      *total += COSTS_N_INSNS (2);
4819169689Skan	    }
4820169689Skan	}
4821169689Skan
4822169689Skan      if (mode == DImode)
4823169689Skan	*total += COSTS_N_INSNS (1);
4824169689Skan
4825169689Skan      return false;
4826169689Skan
4827169689Skan    case CONST_INT:
4828169689Skan      if (const_ok_for_arm (INTVAL (x)))
4829169689Skan	*total = COSTS_N_INSNS (outer_code == SET ? 1 : 0);
4830169689Skan      else if (const_ok_for_arm (~INTVAL (x)))
4831169689Skan	*total = COSTS_N_INSNS (outer_code == AND ? 0 : 1);
4832169689Skan      else if (const_ok_for_arm (-INTVAL (x)))
4833169689Skan	{
4834169689Skan	  if (outer_code == COMPARE || outer_code == PLUS
4835169689Skan	      || outer_code == MINUS)
4836169689Skan	    *total = 0;
4837169689Skan	  else
4838169689Skan	    *total = COSTS_N_INSNS (1);
4839169689Skan	}
4840169689Skan      else
4841169689Skan	*total = COSTS_N_INSNS (2);
4842169689Skan      return true;
4843169689Skan
4844169689Skan    case CONST:
4845169689Skan    case LABEL_REF:
4846169689Skan    case SYMBOL_REF:
4847169689Skan      *total = COSTS_N_INSNS (2);
4848169689Skan      return true;
4849169689Skan
4850169689Skan    case CONST_DOUBLE:
4851169689Skan      *total = COSTS_N_INSNS (4);
4852169689Skan      return true;
4853169689Skan
4854169689Skan    default:
4855169689Skan      if (mode != VOIDmode)
4856169689Skan	*total = COSTS_N_INSNS (ARM_NUM_REGS (mode));
4857169689Skan      else
4858169689Skan	*total = COSTS_N_INSNS (4); /* How knows?  */
4859169689Skan      return false;
4860169689Skan    }
4861132718Skan}
4862132718Skan
4863169689Skan/* RTX costs for cores with a slow MUL implementation.  */
4864169689Skan
4865169689Skanstatic bool
4866169689Skanarm_slowmul_rtx_costs (rtx x, int code, int outer_code, int *total)
4867169689Skan{
4868169689Skan  enum machine_mode mode = GET_MODE (x);
4869169689Skan
4870169689Skan  if (TARGET_THUMB)
4871169689Skan    {
4872169689Skan      *total = thumb_rtx_costs (x, code, outer_code);
4873169689Skan      return true;
4874169689Skan    }
4875169689Skan
4876169689Skan  switch (code)
4877169689Skan    {
4878169689Skan    case MULT:
4879169689Skan      if (GET_MODE_CLASS (mode) == MODE_FLOAT
4880169689Skan	  || mode == DImode)
4881169689Skan	{
4882169689Skan	  *total = 30;
4883169689Skan	  return true;
4884169689Skan	}
4885169689Skan
4886169689Skan      if (GET_CODE (XEXP (x, 1)) == CONST_INT)
4887169689Skan	{
4888169689Skan	  unsigned HOST_WIDE_INT i = (INTVAL (XEXP (x, 1))
4889169689Skan				      & (unsigned HOST_WIDE_INT) 0xffffffff);
4890169689Skan	  int cost, const_ok = const_ok_for_arm (i);
4891169689Skan	  int j, booth_unit_size;
4892169689Skan
4893169689Skan	  /* Tune as appropriate.  */
4894169689Skan	  cost = const_ok ? 4 : 8;
4895169689Skan	  booth_unit_size = 2;
4896169689Skan	  for (j = 0; i && j < 32; j += booth_unit_size)
4897169689Skan	    {
4898169689Skan	      i >>= booth_unit_size;
4899169689Skan	      cost += 2;
4900169689Skan	    }
4901169689Skan
4902169689Skan	  *total = cost;
4903169689Skan	  return true;
4904169689Skan	}
4905169689Skan
4906169689Skan      *total = 30 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4)
4907169689Skan	          + (REG_OR_SUBREG_REG (XEXP (x, 1)) ? 0 : 4);
4908169689Skan      return true;
4909169689Skan
4910169689Skan    default:
4911169689Skan      *total = arm_rtx_costs_1 (x, code, outer_code);
4912169689Skan      return true;
4913169689Skan    }
4914169689Skan}
4915169689Skan
4916169689Skan
4917169689Skan/* RTX cost for cores with a fast multiply unit (M variants).  */
4918169689Skan
4919169689Skanstatic bool
4920169689Skanarm_fastmul_rtx_costs (rtx x, int code, int outer_code, int *total)
4921169689Skan{
4922169689Skan  enum machine_mode mode = GET_MODE (x);
4923169689Skan
4924169689Skan  if (TARGET_THUMB)
4925169689Skan    {
4926169689Skan      *total = thumb_rtx_costs (x, code, outer_code);
4927169689Skan      return true;
4928169689Skan    }
4929169689Skan
4930169689Skan  switch (code)
4931169689Skan    {
4932169689Skan    case MULT:
4933169689Skan      /* There is no point basing this on the tuning, since it is always the
4934169689Skan	 fast variant if it exists at all.  */
4935169689Skan      if (mode == DImode
4936169689Skan	  && (GET_CODE (XEXP (x, 0)) == GET_CODE (XEXP (x, 1)))
4937169689Skan	  && (GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
4938169689Skan	      || GET_CODE (XEXP (x, 0)) == SIGN_EXTEND))
4939169689Skan	{
4940169689Skan	  *total = 8;
4941169689Skan	  return true;
4942169689Skan	}
4943169689Skan
4944169689Skan
4945169689Skan      if (GET_MODE_CLASS (mode) == MODE_FLOAT
4946169689Skan	  || mode == DImode)
4947169689Skan	{
4948169689Skan	  *total = 30;
4949169689Skan	  return true;
4950169689Skan	}
4951169689Skan
4952169689Skan      if (GET_CODE (XEXP (x, 1)) == CONST_INT)
4953169689Skan	{
4954169689Skan	  unsigned HOST_WIDE_INT i = (INTVAL (XEXP (x, 1))
4955169689Skan				      & (unsigned HOST_WIDE_INT) 0xffffffff);
4956169689Skan	  int cost, const_ok = const_ok_for_arm (i);
4957169689Skan	  int j, booth_unit_size;
4958169689Skan
4959169689Skan	  /* Tune as appropriate.  */
4960169689Skan	  cost = const_ok ? 4 : 8;
4961169689Skan	  booth_unit_size = 8;
4962169689Skan	  for (j = 0; i && j < 32; j += booth_unit_size)
4963169689Skan	    {
4964169689Skan	      i >>= booth_unit_size;
4965169689Skan	      cost += 2;
4966169689Skan	    }
4967169689Skan
4968169689Skan	  *total = cost;
4969169689Skan	  return true;
4970169689Skan	}
4971169689Skan
4972169689Skan      *total = 8 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4)
4973169689Skan	         + (REG_OR_SUBREG_REG (XEXP (x, 1)) ? 0 : 4);
4974169689Skan      return true;
4975169689Skan
4976169689Skan    default:
4977169689Skan      *total = arm_rtx_costs_1 (x, code, outer_code);
4978169689Skan      return true;
4979169689Skan    }
4980169689Skan}
4981169689Skan
4982169689Skan
4983169689Skan/* RTX cost for XScale CPUs.  */
4984169689Skan
4985169689Skanstatic bool
4986169689Skanarm_xscale_rtx_costs (rtx x, int code, int outer_code, int *total)
4987169689Skan{
4988169689Skan  enum machine_mode mode = GET_MODE (x);
4989169689Skan
4990169689Skan  if (TARGET_THUMB)
4991169689Skan    {
4992169689Skan      *total = thumb_rtx_costs (x, code, outer_code);
4993169689Skan      return true;
4994169689Skan    }
4995169689Skan
4996169689Skan  switch (code)
4997169689Skan    {
4998169689Skan    case MULT:
4999169689Skan      /* There is no point basing this on the tuning, since it is always the
5000169689Skan	 fast variant if it exists at all.  */
5001169689Skan      if (mode == DImode
5002169689Skan	  && (GET_CODE (XEXP (x, 0)) == GET_CODE (XEXP (x, 1)))
5003169689Skan	  && (GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
5004169689Skan	      || GET_CODE (XEXP (x, 0)) == SIGN_EXTEND))
5005169689Skan	{
5006169689Skan	  *total = 8;
5007169689Skan	  return true;
5008169689Skan	}
5009169689Skan
5010169689Skan
5011169689Skan      if (GET_MODE_CLASS (mode) == MODE_FLOAT
5012169689Skan	  || mode == DImode)
5013169689Skan	{
5014169689Skan	  *total = 30;
5015169689Skan	  return true;
5016169689Skan	}
5017169689Skan
5018169689Skan      if (GET_CODE (XEXP (x, 1)) == CONST_INT)
5019169689Skan	{
5020169689Skan	  unsigned HOST_WIDE_INT i = (INTVAL (XEXP (x, 1))
5021169689Skan				      & (unsigned HOST_WIDE_INT) 0xffffffff);
5022169689Skan	  int cost, const_ok = const_ok_for_arm (i);
5023169689Skan	  unsigned HOST_WIDE_INT masked_const;
5024169689Skan
5025169689Skan	  /* The cost will be related to two insns.
5026169689Skan	     First a load of the constant (MOV or LDR), then a multiply.  */
5027169689Skan	  cost = 2;
5028169689Skan	  if (! const_ok)
5029169689Skan	    cost += 1;      /* LDR is probably more expensive because
5030169689Skan			       of longer result latency.  */
5031169689Skan	  masked_const = i & 0xffff8000;
5032169689Skan	  if (masked_const != 0 && masked_const != 0xffff8000)
5033169689Skan	    {
5034169689Skan	      masked_const = i & 0xf8000000;
5035169689Skan	      if (masked_const == 0 || masked_const == 0xf8000000)
5036169689Skan		cost += 1;
5037169689Skan	      else
5038169689Skan		cost += 2;
5039169689Skan	    }
5040169689Skan	  *total = cost;
5041169689Skan	  return true;
5042169689Skan	}
5043169689Skan
5044169689Skan      *total = 8 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4)
5045169689Skan		 + (REG_OR_SUBREG_REG (XEXP (x, 1)) ? 0 : 4);
5046169689Skan      return true;
5047169689Skan
5048169689Skan    case COMPARE:
5049169689Skan      /* A COMPARE of a MULT is slow on XScale; the muls instruction
5050169689Skan	 will stall until the multiplication is complete.  */
5051169689Skan      if (GET_CODE (XEXP (x, 0)) == MULT)
5052169689Skan	*total = 4 + rtx_cost (XEXP (x, 0), code);
5053169689Skan      else
5054169689Skan	*total = arm_rtx_costs_1 (x, code, outer_code);
5055169689Skan      return true;
5056169689Skan
5057169689Skan    default:
5058169689Skan      *total = arm_rtx_costs_1 (x, code, outer_code);
5059169689Skan      return true;
5060169689Skan    }
5061169689Skan}
5062169689Skan
5063169689Skan
5064169689Skan/* RTX costs for 9e (and later) cores.  */
5065169689Skan
5066169689Skanstatic bool
5067169689Skanarm_9e_rtx_costs (rtx x, int code, int outer_code, int *total)
5068169689Skan{
5069169689Skan  enum machine_mode mode = GET_MODE (x);
5070169689Skan  int nonreg_cost;
5071169689Skan  int cost;
5072169689Skan
5073169689Skan  if (TARGET_THUMB)
5074169689Skan    {
5075169689Skan      switch (code)
5076169689Skan	{
5077169689Skan	case MULT:
5078169689Skan	  *total = COSTS_N_INSNS (3);
5079169689Skan	  return true;
5080169689Skan
5081169689Skan	default:
5082169689Skan	  *total = thumb_rtx_costs (x, code, outer_code);
5083169689Skan	  return true;
5084169689Skan	}
5085169689Skan    }
5086169689Skan
5087169689Skan  switch (code)
5088169689Skan    {
5089169689Skan    case MULT:
5090169689Skan      /* There is no point basing this on the tuning, since it is always the
5091169689Skan	 fast variant if it exists at all.  */
5092169689Skan      if (mode == DImode
5093169689Skan	  && (GET_CODE (XEXP (x, 0)) == GET_CODE (XEXP (x, 1)))
5094169689Skan	  && (GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
5095169689Skan	      || GET_CODE (XEXP (x, 0)) == SIGN_EXTEND))
5096169689Skan	{
5097169689Skan	  *total = 3;
5098169689Skan	  return true;
5099169689Skan	}
5100169689Skan
5101169689Skan
5102169689Skan      if (GET_MODE_CLASS (mode) == MODE_FLOAT)
5103169689Skan	{
5104169689Skan	  *total = 30;
5105169689Skan	  return true;
5106169689Skan	}
5107169689Skan      if (mode == DImode)
5108169689Skan	{
5109169689Skan	  cost = 7;
5110169689Skan	  nonreg_cost = 8;
5111169689Skan	}
5112169689Skan      else
5113169689Skan	{
5114169689Skan	  cost = 2;
5115169689Skan	  nonreg_cost = 4;
5116169689Skan	}
5117169689Skan
5118169689Skan
5119169689Skan      *total = cost + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : nonreg_cost)
5120169689Skan		    + (REG_OR_SUBREG_REG (XEXP (x, 1)) ? 0 : nonreg_cost);
5121169689Skan      return true;
5122169689Skan
5123169689Skan    default:
5124169689Skan      *total = arm_rtx_costs_1 (x, code, outer_code);
5125169689Skan      return true;
5126169689Skan    }
5127169689Skan}
5128132718Skan/* All address computations that can be done are free, but rtx cost returns
5129132718Skan   the same for practically all of them.  So we weight the different types
5130132718Skan   of address here in the order (most pref first):
5131132718Skan   PRE/POST_INC/DEC, SHIFT or NON-INT sum, INT sum, REG, MEM or LABEL.  */
5132132718Skanstatic inline int
5133132718Skanarm_arm_address_cost (rtx x)
5134132718Skan{
5135132718Skan  enum rtx_code c  = GET_CODE (x);
5136132718Skan
5137132718Skan  if (c == PRE_INC || c == PRE_DEC || c == POST_INC || c == POST_DEC)
5138132718Skan    return 0;
5139132718Skan  if (c == MEM || c == LABEL_REF || c == SYMBOL_REF)
5140132718Skan    return 10;
5141132718Skan
5142132718Skan  if (c == PLUS || c == MINUS)
5143132718Skan    {
5144132718Skan      if (GET_CODE (XEXP (x, 0)) == CONST_INT)
5145132718Skan	return 2;
5146132718Skan
5147169689Skan      if (ARITHMETIC_P (XEXP (x, 0)) || ARITHMETIC_P (XEXP (x, 1)))
5148132718Skan	return 3;
5149132718Skan
5150132718Skan      return 4;
5151132718Skan    }
5152132718Skan
5153132718Skan  return 6;
5154132718Skan}
5155132718Skan
5156132718Skanstatic inline int
5157132718Skanarm_thumb_address_cost (rtx x)
5158132718Skan{
5159132718Skan  enum rtx_code c  = GET_CODE (x);
5160132718Skan
5161132718Skan  if (c == REG)
5162132718Skan    return 1;
5163132718Skan  if (c == PLUS
5164132718Skan      && GET_CODE (XEXP (x, 0)) == REG
5165132718Skan      && GET_CODE (XEXP (x, 1)) == CONST_INT)
5166132718Skan    return 1;
5167132718Skan
5168132718Skan  return 2;
5169132718Skan}
5170132718Skan
517190075Sobrienstatic int
5172132718Skanarm_address_cost (rtx x)
517390075Sobrien{
5174132718Skan  return TARGET_ARM ? arm_arm_address_cost (x) : arm_thumb_address_cost (x);
5175132718Skan}
5176132718Skan
5177132718Skanstatic int
5178132718Skanarm_adjust_cost (rtx insn, rtx link, rtx dep, int cost)
5179132718Skan{
518090075Sobrien  rtx i_pat, d_pat;
518190075Sobrien
518290075Sobrien  /* Some true dependencies can have a higher cost depending
518390075Sobrien     on precisely how certain input operands are used.  */
5184132718Skan  if (arm_tune_xscale
518590075Sobrien      && REG_NOTE_KIND (link) == 0
5186132718Skan      && recog_memoized (insn) >= 0
5187132718Skan      && recog_memoized (dep) >= 0)
518890075Sobrien    {
518990075Sobrien      int shift_opnum = get_attr_shift (insn);
519090075Sobrien      enum attr_type attr_type = get_attr_type (dep);
519190075Sobrien
519290075Sobrien      /* If nonzero, SHIFT_OPNUM contains the operand number of a shifted
519390075Sobrien	 operand for INSN.  If we have a shifted input operand and the
519490075Sobrien	 instruction we depend on is another ALU instruction, then we may
519590075Sobrien	 have to account for an additional stall.  */
5196169689Skan      if (shift_opnum != 0
5197169689Skan	  && (attr_type == TYPE_ALU_SHIFT || attr_type == TYPE_ALU_SHIFT_REG))
519890075Sobrien	{
519990075Sobrien	  rtx shifted_operand;
520090075Sobrien	  int opno;
5201169689Skan
520290075Sobrien	  /* Get the shifted operand.  */
520390075Sobrien	  extract_insn (insn);
520490075Sobrien	  shifted_operand = recog_data.operand[shift_opnum];
520590075Sobrien
520690075Sobrien	  /* Iterate over all the operands in DEP.  If we write an operand
520790075Sobrien	     that overlaps with SHIFTED_OPERAND, then we have increase the
520890075Sobrien	     cost of this dependency.  */
520990075Sobrien	  extract_insn (dep);
521090075Sobrien	  preprocess_constraints ();
521190075Sobrien	  for (opno = 0; opno < recog_data.n_operands; opno++)
521290075Sobrien	    {
521390075Sobrien	      /* We can ignore strict inputs.  */
521490075Sobrien	      if (recog_data.operand_type[opno] == OP_IN)
521590075Sobrien		continue;
521690075Sobrien
521790075Sobrien	      if (reg_overlap_mentioned_p (recog_data.operand[opno],
521890075Sobrien					   shifted_operand))
521990075Sobrien		return 2;
522090075Sobrien	    }
522190075Sobrien	}
522290075Sobrien    }
522390075Sobrien
522490075Sobrien  /* XXX This is not strictly true for the FPA.  */
522590075Sobrien  if (REG_NOTE_KIND (link) == REG_DEP_ANTI
522690075Sobrien      || REG_NOTE_KIND (link) == REG_DEP_OUTPUT)
522790075Sobrien    return 0;
522890075Sobrien
522990075Sobrien  /* Call insns don't incur a stall, even if they follow a load.  */
523090075Sobrien  if (REG_NOTE_KIND (link) == 0
523190075Sobrien      && GET_CODE (insn) == CALL_INSN)
523290075Sobrien    return 1;
523390075Sobrien
523490075Sobrien  if ((i_pat = single_set (insn)) != NULL
523590075Sobrien      && GET_CODE (SET_SRC (i_pat)) == MEM
523690075Sobrien      && (d_pat = single_set (dep)) != NULL
523790075Sobrien      && GET_CODE (SET_DEST (d_pat)) == MEM)
523890075Sobrien    {
5239117395Skan      rtx src_mem = XEXP (SET_SRC (i_pat), 0);
524090075Sobrien      /* This is a load after a store, there is no conflict if the load reads
524190075Sobrien	 from a cached area.  Assume that loads from the stack, and from the
5242169689Skan	 constant pool are cached, and that others will miss.  This is a
524390075Sobrien	 hack.  */
5244169689Skan
5245117395Skan      if ((GET_CODE (src_mem) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (src_mem))
5246117395Skan	  || reg_mentioned_p (stack_pointer_rtx, src_mem)
5247117395Skan	  || reg_mentioned_p (frame_pointer_rtx, src_mem)
5248117395Skan	  || reg_mentioned_p (hard_frame_pointer_rtx, src_mem))
524990075Sobrien	return 1;
525090075Sobrien    }
525190075Sobrien
525290075Sobrien  return cost;
525390075Sobrien}
525490075Sobrien
5255169689Skanstatic int fp_consts_inited = 0;
525690075Sobrien
5257169689Skan/* Only zero is valid for VFP.  Other values are also valid for FPA.  */
5258169689Skanstatic const char * const strings_fp[8] =
525990075Sobrien{
526090075Sobrien  "0",   "1",   "2",   "3",
526190075Sobrien  "4",   "5",   "0.5", "10"
526290075Sobrien};
526390075Sobrien
5264169689Skanstatic REAL_VALUE_TYPE values_fp[8];
526590075Sobrien
526690075Sobrienstatic void
5267169689Skaninit_fp_table (void)
526890075Sobrien{
526990075Sobrien  int i;
527090075Sobrien  REAL_VALUE_TYPE r;
527190075Sobrien
5272169689Skan  if (TARGET_VFP)
5273169689Skan    fp_consts_inited = 1;
5274169689Skan  else
5275169689Skan    fp_consts_inited = 8;
5276169689Skan
5277169689Skan  for (i = 0; i < fp_consts_inited; i++)
527890075Sobrien    {
5279169689Skan      r = REAL_VALUE_ATOF (strings_fp[i], DFmode);
5280169689Skan      values_fp[i] = r;
528190075Sobrien    }
528290075Sobrien}
528390075Sobrien
5284169689Skan/* Return TRUE if rtx X is a valid immediate FP constant.  */
528590075Sobrienint
5286169689Skanarm_const_double_rtx (rtx x)
528790075Sobrien{
528890075Sobrien  REAL_VALUE_TYPE r;
528990075Sobrien  int i;
5290169689Skan
5291169689Skan  if (!fp_consts_inited)
5292169689Skan    init_fp_table ();
5293169689Skan
529490075Sobrien  REAL_VALUE_FROM_CONST_DOUBLE (r, x);
529590075Sobrien  if (REAL_VALUE_MINUS_ZERO (r))
529690075Sobrien    return 0;
529790075Sobrien
5298169689Skan  for (i = 0; i < fp_consts_inited; i++)
5299169689Skan    if (REAL_VALUES_EQUAL (r, values_fp[i]))
530090075Sobrien      return 1;
530190075Sobrien
530290075Sobrien  return 0;
530390075Sobrien}
530490075Sobrien
5305132718Skan/* Return TRUE if rtx X is a valid immediate FPA constant.  */
530690075Sobrienint
5307132718Skanneg_const_double_rtx_ok_for_fpa (rtx x)
530890075Sobrien{
530990075Sobrien  REAL_VALUE_TYPE r;
531090075Sobrien  int i;
5311169689Skan
5312169689Skan  if (!fp_consts_inited)
5313169689Skan    init_fp_table ();
5314169689Skan
531590075Sobrien  REAL_VALUE_FROM_CONST_DOUBLE (r, x);
531690075Sobrien  r = REAL_VALUE_NEGATE (r);
531790075Sobrien  if (REAL_VALUE_MINUS_ZERO (r))
531890075Sobrien    return 0;
531990075Sobrien
532090075Sobrien  for (i = 0; i < 8; i++)
5321169689Skan    if (REAL_VALUES_EQUAL (r, values_fp[i]))
532290075Sobrien      return 1;
532390075Sobrien
532490075Sobrien  return 0;
532590075Sobrien}
532690075Sobrien
532790075Sobrien/* Predicates for `match_operand' and `match_operator'.  */
532890075Sobrien
5329132718Skan/* Return nonzero if OP is a valid Cirrus memory address pattern.  */
5330132718Skanint
5331132718Skancirrus_memory_offset (rtx op)
5332132718Skan{
5333132718Skan  /* Reject eliminable registers.  */
5334132718Skan  if (! (reload_in_progress || reload_completed)
5335132718Skan      && (   reg_mentioned_p (frame_pointer_rtx, op)
5336132718Skan	  || reg_mentioned_p (arg_pointer_rtx, op)
5337132718Skan	  || reg_mentioned_p (virtual_incoming_args_rtx, op)
5338132718Skan	  || reg_mentioned_p (virtual_outgoing_args_rtx, op)
5339132718Skan	  || reg_mentioned_p (virtual_stack_dynamic_rtx, op)
5340132718Skan	  || reg_mentioned_p (virtual_stack_vars_rtx, op)))
5341132718Skan    return 0;
534290075Sobrien
5343132718Skan  if (GET_CODE (op) == MEM)
5344132718Skan    {
5345132718Skan      rtx ind;
5346132718Skan
5347132718Skan      ind = XEXP (op, 0);
5348132718Skan
5349132718Skan      /* Match: (mem (reg)).  */
5350132718Skan      if (GET_CODE (ind) == REG)
5351132718Skan	return 1;
5352132718Skan
5353132718Skan      /* Match:
5354132718Skan	 (mem (plus (reg)
5355132718Skan	            (const))).  */
5356132718Skan      if (GET_CODE (ind) == PLUS
5357132718Skan	  && GET_CODE (XEXP (ind, 0)) == REG
5358132718Skan	  && REG_MODE_OK_FOR_BASE_P (XEXP (ind, 0), VOIDmode)
5359132718Skan	  && GET_CODE (XEXP (ind, 1)) == CONST_INT)
5360132718Skan	return 1;
5361132718Skan    }
5362132718Skan
5363132718Skan  return 0;
5364132718Skan}
5365132718Skan
5366169689Skan/* Return TRUE if OP is a valid coprocessor memory address pattern.
5367169689Skan   WB if true if writeback address modes are allowed.  */
5368169689Skan
536990075Sobrienint
5370169689Skanarm_coproc_mem_operand (rtx op, bool wb)
537190075Sobrien{
5372169689Skan  rtx ind;
5373169689Skan
5374169689Skan  /* Reject eliminable registers.  */
5375169689Skan  if (! (reload_in_progress || reload_completed)
5376169689Skan      && (   reg_mentioned_p (frame_pointer_rtx, op)
5377169689Skan	  || reg_mentioned_p (arg_pointer_rtx, op)
5378169689Skan	  || reg_mentioned_p (virtual_incoming_args_rtx, op)
5379169689Skan	  || reg_mentioned_p (virtual_outgoing_args_rtx, op)
5380169689Skan	  || reg_mentioned_p (virtual_stack_dynamic_rtx, op)
5381169689Skan	  || reg_mentioned_p (virtual_stack_vars_rtx, op)))
5382132718Skan    return FALSE;
5383132718Skan
5384169689Skan  /* Constants are converted into offsets from labels.  */
5385169689Skan  if (GET_CODE (op) != MEM)
5386169689Skan    return FALSE;
5387132718Skan
5388169689Skan  ind = XEXP (op, 0);
5389132718Skan
5390169689Skan  if (reload_completed
5391169689Skan      && (GET_CODE (ind) == LABEL_REF
5392169689Skan	  || (GET_CODE (ind) == CONST
5393169689Skan	      && GET_CODE (XEXP (ind, 0)) == PLUS
5394169689Skan	      && GET_CODE (XEXP (XEXP (ind, 0), 0)) == LABEL_REF
5395169689Skan	      && GET_CODE (XEXP (XEXP (ind, 0), 1)) == CONST_INT)))
5396169689Skan    return TRUE;
5397132718Skan
5398169689Skan  /* Match: (mem (reg)).  */
5399169689Skan  if (GET_CODE (ind) == REG)
5400169689Skan    return arm_address_register_rtx_p (ind, 0);
5401132718Skan
5402169689Skan  /* Autoincremment addressing modes.  */
5403169689Skan  if (wb
5404169689Skan      && (GET_CODE (ind) == PRE_INC
5405169689Skan	  || GET_CODE (ind) == POST_INC
5406169689Skan	  || GET_CODE (ind) == PRE_DEC
5407169689Skan	  || GET_CODE (ind) == POST_DEC))
5408169689Skan    return arm_address_register_rtx_p (XEXP (ind, 0), 0);
5409132718Skan
5410169689Skan  if (wb
5411169689Skan      && (GET_CODE (ind) == POST_MODIFY || GET_CODE (ind) == PRE_MODIFY)
5412169689Skan      && arm_address_register_rtx_p (XEXP (ind, 0), 0)
5413169689Skan      && GET_CODE (XEXP (ind, 1)) == PLUS
5414169689Skan      && rtx_equal_p (XEXP (XEXP (ind, 1), 0), XEXP (ind, 0)))
5415169689Skan    ind = XEXP (ind, 1);
5416169689Skan
5417169689Skan  /* Match:
5418169689Skan     (plus (reg)
5419169689Skan	   (const)).  */
5420169689Skan  if (GET_CODE (ind) == PLUS
5421169689Skan      && GET_CODE (XEXP (ind, 0)) == REG
5422169689Skan      && REG_MODE_OK_FOR_BASE_P (XEXP (ind, 0), VOIDmode)
5423169689Skan      && GET_CODE (XEXP (ind, 1)) == CONST_INT
5424169689Skan      && INTVAL (XEXP (ind, 1)) > -1024
5425169689Skan      && INTVAL (XEXP (ind, 1)) <  1024
5426169689Skan      && (INTVAL (XEXP (ind, 1)) & 3) == 0)
5427169689Skan    return TRUE;
5428169689Skan
5429169689Skan  return FALSE;
5430132718Skan}
5431132718Skan
5432146895Skan/* Return true if X is a register that will be eliminated later on.  */
5433146895Skanint
5434146895Skanarm_eliminable_register (rtx x)
5435146895Skan{
5436146895Skan  return REG_P (x) && (REGNO (x) == FRAME_POINTER_REGNUM
5437146895Skan		       || REGNO (x) == ARG_POINTER_REGNUM
5438146895Skan		       || (REGNO (x) >= FIRST_VIRTUAL_REGISTER
5439146895Skan			   && REGNO (x) <= LAST_VIRTUAL_REGISTER));
5440146895Skan}
5441146895Skan
5442169689Skan/* Return GENERAL_REGS if a scratch register required to reload x to/from
5443169689Skan   coprocessor registers.  Otherwise return NO_REGS.  */
5444169689Skan
5445169689Skanenum reg_class
5446169689Skancoproc_secondary_reload_class (enum machine_mode mode, rtx x, bool wb)
5447169689Skan{
5448169689Skan  if (arm_coproc_mem_operand (x, wb) || s_register_operand (x, mode))
5449169689Skan    return NO_REGS;
5450169689Skan
5451169689Skan  return GENERAL_REGS;
5452169689Skan}
5453169689Skan
5454169689Skan/* Values which must be returned in the most-significant end of the return
5455169689Skan   register.  */
5456169689Skan
5457169689Skanstatic bool
5458169689Skanarm_return_in_msb (tree valtype)
5459169689Skan{
5460169689Skan  return (TARGET_AAPCS_BASED
5461169689Skan          && BYTES_BIG_ENDIAN
5462169689Skan          && (AGGREGATE_TYPE_P (valtype)
5463169689Skan              || TREE_CODE (valtype) == COMPLEX_TYPE));
5464169689Skan}
5465169689Skan
5466132718Skan/* Returns TRUE if INSN is an "LDR REG, ADDR" instruction.
5467132718Skan   Use by the Cirrus Maverick code which has to workaround
5468132718Skan   a hardware bug triggered by such instructions.  */
5469132718Skanstatic bool
5470132718Skanarm_memory_load_p (rtx insn)
5471132718Skan{
5472132718Skan  rtx body, lhs, rhs;;
5473132718Skan
5474132718Skan  if (insn == NULL_RTX || GET_CODE (insn) != INSN)
5475132718Skan    return false;
5476132718Skan
5477132718Skan  body = PATTERN (insn);
5478132718Skan
5479132718Skan  if (GET_CODE (body) != SET)
5480132718Skan    return false;
5481132718Skan
5482132718Skan  lhs = XEXP (body, 0);
5483132718Skan  rhs = XEXP (body, 1);
5484132718Skan
5485132718Skan  lhs = REG_OR_SUBREG_RTX (lhs);
5486132718Skan
5487132718Skan  /* If the destination is not a general purpose
5488132718Skan     register we do not have to worry.  */
5489132718Skan  if (GET_CODE (lhs) != REG
5490132718Skan      || REGNO_REG_CLASS (REGNO (lhs)) != GENERAL_REGS)
5491132718Skan    return false;
5492132718Skan
5493132718Skan  /* As well as loads from memory we also have to react
5494132718Skan     to loads of invalid constants which will be turned
5495132718Skan     into loads from the minipool.  */
5496132718Skan  return (GET_CODE (rhs) == MEM
5497132718Skan	  || GET_CODE (rhs) == SYMBOL_REF
5498132718Skan	  || note_invalid_constants (insn, -1, false));
5499132718Skan}
5500132718Skan
5501132718Skan/* Return TRUE if INSN is a Cirrus instruction.  */
5502132718Skanstatic bool
5503132718Skanarm_cirrus_insn_p (rtx insn)
5504132718Skan{
5505132718Skan  enum attr_cirrus attr;
5506132718Skan
5507169689Skan  /* get_attr cannot accept USE or CLOBBER.  */
5508132718Skan  if (!insn
5509132718Skan      || GET_CODE (insn) != INSN
5510132718Skan      || GET_CODE (PATTERN (insn)) == USE
5511132718Skan      || GET_CODE (PATTERN (insn)) == CLOBBER)
5512132718Skan    return 0;
5513132718Skan
5514132718Skan  attr = get_attr_cirrus (insn);
5515132718Skan
5516132718Skan  return attr != CIRRUS_NOT;
5517132718Skan}
5518132718Skan
5519132718Skan/* Cirrus reorg for invalid instruction combinations.  */
5520132718Skanstatic void
5521132718Skancirrus_reorg (rtx first)
5522132718Skan{
5523132718Skan  enum attr_cirrus attr;
5524132718Skan  rtx body = PATTERN (first);
5525132718Skan  rtx t;
5526132718Skan  int nops;
5527132718Skan
5528132718Skan  /* Any branch must be followed by 2 non Cirrus instructions.  */
5529132718Skan  if (GET_CODE (first) == JUMP_INSN && GET_CODE (body) != RETURN)
5530132718Skan    {
5531132718Skan      nops = 0;
5532132718Skan      t = next_nonnote_insn (first);
5533132718Skan
5534132718Skan      if (arm_cirrus_insn_p (t))
5535132718Skan	++ nops;
5536132718Skan
5537132718Skan      if (arm_cirrus_insn_p (next_nonnote_insn (t)))
5538132718Skan	++ nops;
5539132718Skan
5540132718Skan      while (nops --)
5541132718Skan	emit_insn_after (gen_nop (), first);
5542132718Skan
5543132718Skan      return;
5544132718Skan    }
5545132718Skan
5546132718Skan  /* (float (blah)) is in parallel with a clobber.  */
5547132718Skan  if (GET_CODE (body) == PARALLEL && XVECLEN (body, 0) > 0)
5548132718Skan    body = XVECEXP (body, 0, 0);
5549132718Skan
5550132718Skan  if (GET_CODE (body) == SET)
5551132718Skan    {
5552132718Skan      rtx lhs = XEXP (body, 0), rhs = XEXP (body, 1);
5553132718Skan
5554132718Skan      /* cfldrd, cfldr64, cfstrd, cfstr64 must
5555132718Skan	 be followed by a non Cirrus insn.  */
5556132718Skan      if (get_attr_cirrus (first) == CIRRUS_DOUBLE)
5557132718Skan	{
5558132718Skan	  if (arm_cirrus_insn_p (next_nonnote_insn (first)))
5559132718Skan	    emit_insn_after (gen_nop (), first);
5560132718Skan
5561132718Skan	  return;
5562132718Skan	}
5563132718Skan      else if (arm_memory_load_p (first))
5564132718Skan	{
5565132718Skan	  unsigned int arm_regno;
5566132718Skan
5567132718Skan	  /* Any ldr/cfmvdlr, ldr/cfmvdhr, ldr/cfmvsr, ldr/cfmv64lr,
5568132718Skan	     ldr/cfmv64hr combination where the Rd field is the same
5569132718Skan	     in both instructions must be split with a non Cirrus
5570132718Skan	     insn.  Example:
5571132718Skan
5572132718Skan	     ldr r0, blah
5573132718Skan	     nop
5574132718Skan	     cfmvsr mvf0, r0.  */
5575132718Skan
5576132718Skan	  /* Get Arm register number for ldr insn.  */
5577132718Skan	  if (GET_CODE (lhs) == REG)
5578132718Skan	    arm_regno = REGNO (lhs);
5579132718Skan	  else
5580169689Skan	    {
5581169689Skan	      gcc_assert (GET_CODE (rhs) == REG);
5582169689Skan	      arm_regno = REGNO (rhs);
5583169689Skan	    }
5584132718Skan
5585132718Skan	  /* Next insn.  */
5586132718Skan	  first = next_nonnote_insn (first);
5587132718Skan
5588132718Skan	  if (! arm_cirrus_insn_p (first))
5589132718Skan	    return;
5590132718Skan
5591132718Skan	  body = PATTERN (first);
5592132718Skan
5593132718Skan          /* (float (blah)) is in parallel with a clobber.  */
5594132718Skan          if (GET_CODE (body) == PARALLEL && XVECLEN (body, 0))
5595132718Skan	    body = XVECEXP (body, 0, 0);
5596132718Skan
5597132718Skan	  if (GET_CODE (body) == FLOAT)
5598132718Skan	    body = XEXP (body, 0);
5599132718Skan
5600132718Skan	  if (get_attr_cirrus (first) == CIRRUS_MOVE
5601132718Skan	      && GET_CODE (XEXP (body, 1)) == REG
5602132718Skan	      && arm_regno == REGNO (XEXP (body, 1)))
5603132718Skan	    emit_insn_after (gen_nop (), first);
5604132718Skan
5605132718Skan	  return;
5606132718Skan	}
5607132718Skan    }
5608132718Skan
5609169689Skan  /* get_attr cannot accept USE or CLOBBER.  */
5610132718Skan  if (!first
5611132718Skan      || GET_CODE (first) != INSN
5612132718Skan      || GET_CODE (PATTERN (first)) == USE
5613132718Skan      || GET_CODE (PATTERN (first)) == CLOBBER)
5614132718Skan    return;
5615132718Skan
5616132718Skan  attr = get_attr_cirrus (first);
5617132718Skan
5618132718Skan  /* Any coprocessor compare instruction (cfcmps, cfcmpd, ...)
5619132718Skan     must be followed by a non-coprocessor instruction.  */
5620132718Skan  if (attr == CIRRUS_COMPARE)
5621132718Skan    {
5622132718Skan      nops = 0;
5623132718Skan
5624132718Skan      t = next_nonnote_insn (first);
5625132718Skan
5626132718Skan      if (arm_cirrus_insn_p (t))
5627132718Skan	++ nops;
5628132718Skan
5629132718Skan      if (arm_cirrus_insn_p (next_nonnote_insn (t)))
5630132718Skan	++ nops;
5631132718Skan
5632132718Skan      while (nops --)
5633132718Skan	emit_insn_after (gen_nop (), first);
5634132718Skan
5635132718Skan      return;
5636132718Skan    }
5637132718Skan}
5638132718Skan
563990075Sobrien/* Return TRUE if X references a SYMBOL_REF.  */
564090075Sobrienint
5641132718Skansymbol_mentioned_p (rtx x)
564290075Sobrien{
564390075Sobrien  const char * fmt;
564490075Sobrien  int i;
564590075Sobrien
564690075Sobrien  if (GET_CODE (x) == SYMBOL_REF)
564790075Sobrien    return 1;
564890075Sobrien
5649169689Skan  /* UNSPEC_TLS entries for a symbol include the SYMBOL_REF, but they
5650169689Skan     are constant offsets, not symbols.  */
5651169689Skan  if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLS)
5652169689Skan    return 0;
5653169689Skan
565490075Sobrien  fmt = GET_RTX_FORMAT (GET_CODE (x));
5655169689Skan
565690075Sobrien  for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
565790075Sobrien    {
565890075Sobrien      if (fmt[i] == 'E')
565990075Sobrien	{
566090075Sobrien	  int j;
566190075Sobrien
566290075Sobrien	  for (j = XVECLEN (x, i) - 1; j >= 0; j--)
566390075Sobrien	    if (symbol_mentioned_p (XVECEXP (x, i, j)))
566490075Sobrien	      return 1;
566590075Sobrien	}
566690075Sobrien      else if (fmt[i] == 'e' && symbol_mentioned_p (XEXP (x, i)))
566790075Sobrien	return 1;
566890075Sobrien    }
566990075Sobrien
567090075Sobrien  return 0;
567190075Sobrien}
567290075Sobrien
567390075Sobrien/* Return TRUE if X references a LABEL_REF.  */
567490075Sobrienint
5675132718Skanlabel_mentioned_p (rtx x)
567690075Sobrien{
567790075Sobrien  const char * fmt;
567890075Sobrien  int i;
567990075Sobrien
568090075Sobrien  if (GET_CODE (x) == LABEL_REF)
568190075Sobrien    return 1;
568290075Sobrien
5683169689Skan  /* UNSPEC_TLS entries for a symbol include a LABEL_REF for the referencing
5684169689Skan     instruction, but they are constant offsets, not symbols.  */
5685169689Skan  if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLS)
5686169689Skan    return 0;
5687169689Skan
568890075Sobrien  fmt = GET_RTX_FORMAT (GET_CODE (x));
568990075Sobrien  for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
569090075Sobrien    {
569190075Sobrien      if (fmt[i] == 'E')
569290075Sobrien	{
569390075Sobrien	  int j;
569490075Sobrien
569590075Sobrien	  for (j = XVECLEN (x, i) - 1; j >= 0; j--)
569690075Sobrien	    if (label_mentioned_p (XVECEXP (x, i, j)))
569790075Sobrien	      return 1;
569890075Sobrien	}
569990075Sobrien      else if (fmt[i] == 'e' && label_mentioned_p (XEXP (x, i)))
570090075Sobrien	return 1;
570190075Sobrien    }
570290075Sobrien
570390075Sobrien  return 0;
570490075Sobrien}
570590075Sobrien
5706169689Skanint
5707169689Skantls_mentioned_p (rtx x)
5708169689Skan{
5709169689Skan  switch (GET_CODE (x))
5710169689Skan    {
5711169689Skan    case CONST:
5712169689Skan      return tls_mentioned_p (XEXP (x, 0));
5713169689Skan
5714169689Skan    case UNSPEC:
5715169689Skan      if (XINT (x, 1) == UNSPEC_TLS)
5716169689Skan	return 1;
5717169689Skan
5718169689Skan    default:
5719169689Skan      return 0;
5720169689Skan    }
5721169689Skan}
5722169689Skan
5723169689Skan/* Must not copy a SET whose source operand is PC-relative.  */
5724169689Skan
5725169689Skanstatic bool
5726169689Skanarm_cannot_copy_insn_p (rtx insn)
5727169689Skan{
5728169689Skan  rtx pat = PATTERN (insn);
5729169689Skan
5730169689Skan  if (GET_CODE (pat) == PARALLEL
5731169689Skan      && GET_CODE (XVECEXP (pat, 0, 0)) == SET)
5732169689Skan    {
5733169689Skan      rtx rhs = SET_SRC (XVECEXP (pat, 0, 0));
5734169689Skan
5735169689Skan      if (GET_CODE (rhs) == UNSPEC
5736169689Skan	  && XINT (rhs, 1) == UNSPEC_PIC_BASE)
5737169689Skan	return TRUE;
5738169689Skan
5739169689Skan      if (GET_CODE (rhs) == MEM
5740169689Skan	  && GET_CODE (XEXP (rhs, 0)) == UNSPEC
5741169689Skan	  && XINT (XEXP (rhs, 0), 1) == UNSPEC_PIC_BASE)
5742169689Skan	return TRUE;
5743169689Skan    }
5744169689Skan
5745169689Skan  return FALSE;
5746169689Skan}
5747169689Skan
574890075Sobrienenum rtx_code
5749132718Skanminmax_code (rtx x)
575090075Sobrien{
575190075Sobrien  enum rtx_code code = GET_CODE (x);
575290075Sobrien
5753169689Skan  switch (code)
5754169689Skan    {
5755169689Skan    case SMAX:
5756169689Skan      return GE;
5757169689Skan    case SMIN:
5758169689Skan      return LE;
5759169689Skan    case UMIN:
5760169689Skan      return LEU;
5761169689Skan    case UMAX:
5762169689Skan      return GEU;
5763169689Skan    default:
5764169689Skan      gcc_unreachable ();
5765169689Skan    }
576690075Sobrien}
576790075Sobrien
576890075Sobrien/* Return 1 if memory locations are adjacent.  */
576990075Sobrienint
5770132718Skanadjacent_mem_locations (rtx a, rtx b)
577190075Sobrien{
5772169689Skan  /* We don't guarantee to preserve the order of these memory refs.  */
5773169689Skan  if (volatile_refs_p (a) || volatile_refs_p (b))
5774169689Skan    return 0;
5775169689Skan
577690075Sobrien  if ((GET_CODE (XEXP (a, 0)) == REG
577790075Sobrien       || (GET_CODE (XEXP (a, 0)) == PLUS
577890075Sobrien	   && GET_CODE (XEXP (XEXP (a, 0), 1)) == CONST_INT))
577990075Sobrien      && (GET_CODE (XEXP (b, 0)) == REG
578090075Sobrien	  || (GET_CODE (XEXP (b, 0)) == PLUS
578190075Sobrien	      && GET_CODE (XEXP (XEXP (b, 0), 1)) == CONST_INT)))
578290075Sobrien    {
5783146895Skan      HOST_WIDE_INT val0 = 0, val1 = 0;
5784146895Skan      rtx reg0, reg1;
5785146895Skan      int val_diff;
5786146895Skan
578790075Sobrien      if (GET_CODE (XEXP (a, 0)) == PLUS)
578890075Sobrien        {
5789146895Skan	  reg0 = XEXP (XEXP (a, 0), 0);
579090075Sobrien	  val0 = INTVAL (XEXP (XEXP (a, 0), 1));
579190075Sobrien        }
579290075Sobrien      else
5793146895Skan	reg0 = XEXP (a, 0);
579490075Sobrien
579590075Sobrien      if (GET_CODE (XEXP (b, 0)) == PLUS)
579690075Sobrien        {
5797146895Skan	  reg1 = XEXP (XEXP (b, 0), 0);
579890075Sobrien	  val1 = INTVAL (XEXP (XEXP (b, 0), 1));
579990075Sobrien        }
580090075Sobrien      else
5801146895Skan	reg1 = XEXP (b, 0);
580290075Sobrien
5803132718Skan      /* Don't accept any offset that will require multiple
5804132718Skan	 instructions to handle, since this would cause the
5805132718Skan	 arith_adjacentmem pattern to output an overlong sequence.  */
5806132718Skan      if (!const_ok_for_op (PLUS, val0) || !const_ok_for_op (PLUS, val1))
5807132718Skan	return 0;
5808146895Skan
5809146895Skan      /* Don't allow an eliminable register: register elimination can make
5810146895Skan	 the offset too large.  */
5811146895Skan      if (arm_eliminable_register (reg0))
5812146895Skan	return 0;
5813146895Skan
5814146895Skan      val_diff = val1 - val0;
5815169689Skan
5816169689Skan      if (arm_ld_sched)
5817169689Skan	{
5818169689Skan	  /* If the target has load delay slots, then there's no benefit
5819169689Skan	     to using an ldm instruction unless the offset is zero and
5820169689Skan	     we are optimizing for size.  */
5821169689Skan	  return (optimize_size && (REGNO (reg0) == REGNO (reg1))
5822169689Skan		  && (val0 == 0 || val1 == 0 || val0 == 4 || val1 == 4)
5823169689Skan		  && (val_diff == 4 || val_diff == -4));
5824169689Skan	}
5825169689Skan
5826146895Skan      return ((REGNO (reg0) == REGNO (reg1))
5827146895Skan	      && (val_diff == 4 || val_diff == -4));
582890075Sobrien    }
5829146895Skan
583090075Sobrien  return 0;
583190075Sobrien}
583290075Sobrien
583390075Sobrienint
5834132718Skanload_multiple_sequence (rtx *operands, int nops, int *regs, int *base,
5835132718Skan			HOST_WIDE_INT *load_offset)
583690075Sobrien{
583790075Sobrien  int unsorted_regs[4];
583890075Sobrien  HOST_WIDE_INT unsorted_offsets[4];
583990075Sobrien  int order[4];
584090075Sobrien  int base_reg = -1;
584190075Sobrien  int i;
584290075Sobrien
584390075Sobrien  /* Can only handle 2, 3, or 4 insns at present,
584490075Sobrien     though could be easily extended if required.  */
5845169689Skan  gcc_assert (nops >= 2 && nops <= 4);
584690075Sobrien
584790075Sobrien  /* Loop over the operands and check that the memory references are
5848169689Skan     suitable (i.e. immediate offsets from the same base register).  At
584990075Sobrien     the same time, extract the target register, and the memory
585090075Sobrien     offsets.  */
585190075Sobrien  for (i = 0; i < nops; i++)
585290075Sobrien    {
585390075Sobrien      rtx reg;
585490075Sobrien      rtx offset;
585590075Sobrien
585690075Sobrien      /* Convert a subreg of a mem into the mem itself.  */
585790075Sobrien      if (GET_CODE (operands[nops + i]) == SUBREG)
585890075Sobrien	operands[nops + i] = alter_subreg (operands + (nops + i));
585990075Sobrien
5860169689Skan      gcc_assert (GET_CODE (operands[nops + i]) == MEM);
586190075Sobrien
586290075Sobrien      /* Don't reorder volatile memory references; it doesn't seem worth
586390075Sobrien	 looking for the case where the order is ok anyway.  */
586490075Sobrien      if (MEM_VOLATILE_P (operands[nops + i]))
586590075Sobrien	return 0;
586690075Sobrien
586790075Sobrien      offset = const0_rtx;
586890075Sobrien
586990075Sobrien      if ((GET_CODE (reg = XEXP (operands[nops + i], 0)) == REG
587090075Sobrien	   || (GET_CODE (reg) == SUBREG
587190075Sobrien	       && GET_CODE (reg = SUBREG_REG (reg)) == REG))
587290075Sobrien	  || (GET_CODE (XEXP (operands[nops + i], 0)) == PLUS
587390075Sobrien	      && ((GET_CODE (reg = XEXP (XEXP (operands[nops + i], 0), 0))
587490075Sobrien		   == REG)
587590075Sobrien		  || (GET_CODE (reg) == SUBREG
587690075Sobrien		      && GET_CODE (reg = SUBREG_REG (reg)) == REG))
587790075Sobrien	      && (GET_CODE (offset = XEXP (XEXP (operands[nops + i], 0), 1))
587890075Sobrien		  == CONST_INT)))
587990075Sobrien	{
588090075Sobrien	  if (i == 0)
588190075Sobrien	    {
588290075Sobrien	      base_reg = REGNO (reg);
588390075Sobrien	      unsorted_regs[0] = (GET_CODE (operands[i]) == REG
588490075Sobrien				  ? REGNO (operands[i])
588590075Sobrien				  : REGNO (SUBREG_REG (operands[i])));
588690075Sobrien	      order[0] = 0;
588790075Sobrien	    }
5888169689Skan	  else
588990075Sobrien	    {
589090075Sobrien	      if (base_reg != (int) REGNO (reg))
589190075Sobrien		/* Not addressed from the same base register.  */
589290075Sobrien		return 0;
589390075Sobrien
589490075Sobrien	      unsorted_regs[i] = (GET_CODE (operands[i]) == REG
589590075Sobrien				  ? REGNO (operands[i])
589690075Sobrien				  : REGNO (SUBREG_REG (operands[i])));
589790075Sobrien	      if (unsorted_regs[i] < unsorted_regs[order[0]])
589890075Sobrien		order[0] = i;
589990075Sobrien	    }
590090075Sobrien
590190075Sobrien	  /* If it isn't an integer register, or if it overwrites the
590290075Sobrien	     base register but isn't the last insn in the list, then
590390075Sobrien	     we can't do this.  */
590490075Sobrien	  if (unsorted_regs[i] < 0 || unsorted_regs[i] > 14
590590075Sobrien	      || (i != nops - 1 && unsorted_regs[i] == base_reg))
590690075Sobrien	    return 0;
590790075Sobrien
590890075Sobrien	  unsorted_offsets[i] = INTVAL (offset);
590990075Sobrien	}
591090075Sobrien      else
591190075Sobrien	/* Not a suitable memory address.  */
591290075Sobrien	return 0;
591390075Sobrien    }
591490075Sobrien
591590075Sobrien  /* All the useful information has now been extracted from the
591690075Sobrien     operands into unsorted_regs and unsorted_offsets; additionally,
591790075Sobrien     order[0] has been set to the lowest numbered register in the
591890075Sobrien     list.  Sort the registers into order, and check that the memory
591990075Sobrien     offsets are ascending and adjacent.  */
592090075Sobrien
592190075Sobrien  for (i = 1; i < nops; i++)
592290075Sobrien    {
592390075Sobrien      int j;
592490075Sobrien
592590075Sobrien      order[i] = order[i - 1];
592690075Sobrien      for (j = 0; j < nops; j++)
592790075Sobrien	if (unsorted_regs[j] > unsorted_regs[order[i - 1]]
592890075Sobrien	    && (order[i] == order[i - 1]
592990075Sobrien		|| unsorted_regs[j] < unsorted_regs[order[i]]))
593090075Sobrien	  order[i] = j;
593190075Sobrien
593290075Sobrien      /* Have we found a suitable register? if not, one must be used more
593390075Sobrien	 than once.  */
593490075Sobrien      if (order[i] == order[i - 1])
593590075Sobrien	return 0;
593690075Sobrien
593790075Sobrien      /* Is the memory address adjacent and ascending? */
593890075Sobrien      if (unsorted_offsets[order[i]] != unsorted_offsets[order[i - 1]] + 4)
593990075Sobrien	return 0;
594090075Sobrien    }
594190075Sobrien
594290075Sobrien  if (base)
594390075Sobrien    {
594490075Sobrien      *base = base_reg;
594590075Sobrien
594690075Sobrien      for (i = 0; i < nops; i++)
594790075Sobrien	regs[i] = unsorted_regs[order[i]];
594890075Sobrien
594990075Sobrien      *load_offset = unsorted_offsets[order[0]];
595090075Sobrien    }
595190075Sobrien
595290075Sobrien  if (unsorted_offsets[order[0]] == 0)
595390075Sobrien    return 1; /* ldmia */
595490075Sobrien
595590075Sobrien  if (unsorted_offsets[order[0]] == 4)
595690075Sobrien    return 2; /* ldmib */
595790075Sobrien
595890075Sobrien  if (unsorted_offsets[order[nops - 1]] == 0)
595990075Sobrien    return 3; /* ldmda */
596090075Sobrien
596190075Sobrien  if (unsorted_offsets[order[nops - 1]] == -4)
596290075Sobrien    return 4; /* ldmdb */
596390075Sobrien
596490075Sobrien  /* For ARM8,9 & StrongARM, 2 ldr instructions are faster than an ldm
596590075Sobrien     if the offset isn't small enough.  The reason 2 ldrs are faster
596690075Sobrien     is because these ARMs are able to do more than one cache access
596790075Sobrien     in a single cycle.  The ARM9 and StrongARM have Harvard caches,
596890075Sobrien     whilst the ARM8 has a double bandwidth cache.  This means that
596990075Sobrien     these cores can do both an instruction fetch and a data fetch in
597090075Sobrien     a single cycle, so the trick of calculating the address into a
597190075Sobrien     scratch register (one of the result regs) and then doing a load
597290075Sobrien     multiple actually becomes slower (and no smaller in code size).
597390075Sobrien     That is the transformation
5974169689Skan
597590075Sobrien 	ldr	rd1, [rbase + offset]
597690075Sobrien 	ldr	rd2, [rbase + offset + 4]
5977169689Skan
597890075Sobrien     to
5979169689Skan
598090075Sobrien 	add	rd1, rbase, offset
598190075Sobrien 	ldmia	rd1, {rd1, rd2}
5982169689Skan
598390075Sobrien     produces worse code -- '3 cycles + any stalls on rd2' instead of
598490075Sobrien     '2 cycles + any stalls on rd2'.  On ARMs with only one cache
598590075Sobrien     access per cycle, the first sequence could never complete in less
598690075Sobrien     than 6 cycles, whereas the ldm sequence would only take 5 and
598790075Sobrien     would make better use of sequential accesses if not hitting the
598890075Sobrien     cache.
598990075Sobrien
599090075Sobrien     We cheat here and test 'arm_ld_sched' which we currently know to
599190075Sobrien     only be true for the ARM8, ARM9 and StrongARM.  If this ever
599290075Sobrien     changes, then the test below needs to be reworked.  */
599390075Sobrien  if (nops == 2 && arm_ld_sched)
599490075Sobrien    return 0;
599590075Sobrien
599690075Sobrien  /* Can't do it without setting up the offset, only do this if it takes
599790075Sobrien     no more than one insn.  */
5998169689Skan  return (const_ok_for_arm (unsorted_offsets[order[0]])
599990075Sobrien	  || const_ok_for_arm (-unsorted_offsets[order[0]])) ? 5 : 0;
600090075Sobrien}
600190075Sobrien
600290075Sobrienconst char *
6003132718Skanemit_ldm_seq (rtx *operands, int nops)
600490075Sobrien{
600590075Sobrien  int regs[4];
600690075Sobrien  int base_reg;
600790075Sobrien  HOST_WIDE_INT offset;
600890075Sobrien  char buf[100];
600990075Sobrien  int i;
601090075Sobrien
601190075Sobrien  switch (load_multiple_sequence (operands, nops, regs, &base_reg, &offset))
601290075Sobrien    {
601390075Sobrien    case 1:
601490075Sobrien      strcpy (buf, "ldm%?ia\t");
601590075Sobrien      break;
601690075Sobrien
601790075Sobrien    case 2:
601890075Sobrien      strcpy (buf, "ldm%?ib\t");
601990075Sobrien      break;
602090075Sobrien
602190075Sobrien    case 3:
602290075Sobrien      strcpy (buf, "ldm%?da\t");
602390075Sobrien      break;
602490075Sobrien
602590075Sobrien    case 4:
602690075Sobrien      strcpy (buf, "ldm%?db\t");
602790075Sobrien      break;
602890075Sobrien
602990075Sobrien    case 5:
603090075Sobrien      if (offset >= 0)
603190075Sobrien	sprintf (buf, "add%%?\t%s%s, %s%s, #%ld", REGISTER_PREFIX,
603290075Sobrien		 reg_names[regs[0]], REGISTER_PREFIX, reg_names[base_reg],
603390075Sobrien		 (long) offset);
603490075Sobrien      else
603590075Sobrien	sprintf (buf, "sub%%?\t%s%s, %s%s, #%ld", REGISTER_PREFIX,
603690075Sobrien		 reg_names[regs[0]], REGISTER_PREFIX, reg_names[base_reg],
603790075Sobrien		 (long) -offset);
603890075Sobrien      output_asm_insn (buf, operands);
603990075Sobrien      base_reg = regs[0];
604090075Sobrien      strcpy (buf, "ldm%?ia\t");
604190075Sobrien      break;
604290075Sobrien
604390075Sobrien    default:
6044169689Skan      gcc_unreachable ();
604590075Sobrien    }
604690075Sobrien
6047169689Skan  sprintf (buf + strlen (buf), "%s%s, {%s%s", REGISTER_PREFIX,
604890075Sobrien	   reg_names[base_reg], REGISTER_PREFIX, reg_names[regs[0]]);
604990075Sobrien
605090075Sobrien  for (i = 1; i < nops; i++)
605190075Sobrien    sprintf (buf + strlen (buf), ", %s%s", REGISTER_PREFIX,
605290075Sobrien	     reg_names[regs[i]]);
605390075Sobrien
605490075Sobrien  strcat (buf, "}\t%@ phole ldm");
605590075Sobrien
605690075Sobrien  output_asm_insn (buf, operands);
605790075Sobrien  return "";
605890075Sobrien}
605990075Sobrien
606090075Sobrienint
6061132718Skanstore_multiple_sequence (rtx *operands, int nops, int *regs, int *base,
6062132718Skan			 HOST_WIDE_INT * load_offset)
606390075Sobrien{
606490075Sobrien  int unsorted_regs[4];
606590075Sobrien  HOST_WIDE_INT unsorted_offsets[4];
606690075Sobrien  int order[4];
606790075Sobrien  int base_reg = -1;
606890075Sobrien  int i;
606990075Sobrien
607090075Sobrien  /* Can only handle 2, 3, or 4 insns at present, though could be easily
607190075Sobrien     extended if required.  */
6072169689Skan  gcc_assert (nops >= 2 && nops <= 4);
607390075Sobrien
607490075Sobrien  /* Loop over the operands and check that the memory references are
6075169689Skan     suitable (i.e. immediate offsets from the same base register).  At
607690075Sobrien     the same time, extract the target register, and the memory
607790075Sobrien     offsets.  */
607890075Sobrien  for (i = 0; i < nops; i++)
607990075Sobrien    {
608090075Sobrien      rtx reg;
608190075Sobrien      rtx offset;
608290075Sobrien
608390075Sobrien      /* Convert a subreg of a mem into the mem itself.  */
608490075Sobrien      if (GET_CODE (operands[nops + i]) == SUBREG)
608590075Sobrien	operands[nops + i] = alter_subreg (operands + (nops + i));
608690075Sobrien
6087169689Skan      gcc_assert (GET_CODE (operands[nops + i]) == MEM);
608890075Sobrien
608990075Sobrien      /* Don't reorder volatile memory references; it doesn't seem worth
609090075Sobrien	 looking for the case where the order is ok anyway.  */
609190075Sobrien      if (MEM_VOLATILE_P (operands[nops + i]))
609290075Sobrien	return 0;
609390075Sobrien
609490075Sobrien      offset = const0_rtx;
609590075Sobrien
609690075Sobrien      if ((GET_CODE (reg = XEXP (operands[nops + i], 0)) == REG
609790075Sobrien	   || (GET_CODE (reg) == SUBREG
609890075Sobrien	       && GET_CODE (reg = SUBREG_REG (reg)) == REG))
609990075Sobrien	  || (GET_CODE (XEXP (operands[nops + i], 0)) == PLUS
610090075Sobrien	      && ((GET_CODE (reg = XEXP (XEXP (operands[nops + i], 0), 0))
610190075Sobrien		   == REG)
610290075Sobrien		  || (GET_CODE (reg) == SUBREG
610390075Sobrien		      && GET_CODE (reg = SUBREG_REG (reg)) == REG))
610490075Sobrien	      && (GET_CODE (offset = XEXP (XEXP (operands[nops + i], 0), 1))
610590075Sobrien		  == CONST_INT)))
610690075Sobrien	{
610790075Sobrien	  if (i == 0)
610890075Sobrien	    {
610990075Sobrien	      base_reg = REGNO (reg);
611090075Sobrien	      unsorted_regs[0] = (GET_CODE (operands[i]) == REG
611190075Sobrien				  ? REGNO (operands[i])
611290075Sobrien				  : REGNO (SUBREG_REG (operands[i])));
611390075Sobrien	      order[0] = 0;
611490075Sobrien	    }
6115169689Skan	  else
611690075Sobrien	    {
611790075Sobrien	      if (base_reg != (int) REGNO (reg))
611890075Sobrien		/* Not addressed from the same base register.  */
611990075Sobrien		return 0;
612090075Sobrien
612190075Sobrien	      unsorted_regs[i] = (GET_CODE (operands[i]) == REG
612290075Sobrien				  ? REGNO (operands[i])
612390075Sobrien				  : REGNO (SUBREG_REG (operands[i])));
612490075Sobrien	      if (unsorted_regs[i] < unsorted_regs[order[0]])
612590075Sobrien		order[0] = i;
612690075Sobrien	    }
612790075Sobrien
612890075Sobrien	  /* If it isn't an integer register, then we can't do this.  */
612990075Sobrien	  if (unsorted_regs[i] < 0 || unsorted_regs[i] > 14)
613090075Sobrien	    return 0;
613190075Sobrien
613290075Sobrien	  unsorted_offsets[i] = INTVAL (offset);
613390075Sobrien	}
613490075Sobrien      else
613590075Sobrien	/* Not a suitable memory address.  */
613690075Sobrien	return 0;
613790075Sobrien    }
613890075Sobrien
613990075Sobrien  /* All the useful information has now been extracted from the
614090075Sobrien     operands into unsorted_regs and unsorted_offsets; additionally,
614190075Sobrien     order[0] has been set to the lowest numbered register in the
614290075Sobrien     list.  Sort the registers into order, and check that the memory
614390075Sobrien     offsets are ascending and adjacent.  */
614490075Sobrien
614590075Sobrien  for (i = 1; i < nops; i++)
614690075Sobrien    {
614790075Sobrien      int j;
614890075Sobrien
614990075Sobrien      order[i] = order[i - 1];
615090075Sobrien      for (j = 0; j < nops; j++)
615190075Sobrien	if (unsorted_regs[j] > unsorted_regs[order[i - 1]]
615290075Sobrien	    && (order[i] == order[i - 1]
615390075Sobrien		|| unsorted_regs[j] < unsorted_regs[order[i]]))
615490075Sobrien	  order[i] = j;
615590075Sobrien
615690075Sobrien      /* Have we found a suitable register? if not, one must be used more
615790075Sobrien	 than once.  */
615890075Sobrien      if (order[i] == order[i - 1])
615990075Sobrien	return 0;
616090075Sobrien
616190075Sobrien      /* Is the memory address adjacent and ascending? */
616290075Sobrien      if (unsorted_offsets[order[i]] != unsorted_offsets[order[i - 1]] + 4)
616390075Sobrien	return 0;
616490075Sobrien    }
616590075Sobrien
616690075Sobrien  if (base)
616790075Sobrien    {
616890075Sobrien      *base = base_reg;
616990075Sobrien
617090075Sobrien      for (i = 0; i < nops; i++)
617190075Sobrien	regs[i] = unsorted_regs[order[i]];
617290075Sobrien
617390075Sobrien      *load_offset = unsorted_offsets[order[0]];
617490075Sobrien    }
617590075Sobrien
617690075Sobrien  if (unsorted_offsets[order[0]] == 0)
617790075Sobrien    return 1; /* stmia */
617890075Sobrien
617990075Sobrien  if (unsorted_offsets[order[0]] == 4)
618090075Sobrien    return 2; /* stmib */
618190075Sobrien
618290075Sobrien  if (unsorted_offsets[order[nops - 1]] == 0)
618390075Sobrien    return 3; /* stmda */
618490075Sobrien
618590075Sobrien  if (unsorted_offsets[order[nops - 1]] == -4)
618690075Sobrien    return 4; /* stmdb */
618790075Sobrien
618890075Sobrien  return 0;
618990075Sobrien}
619090075Sobrien
619190075Sobrienconst char *
6192132718Skanemit_stm_seq (rtx *operands, int nops)
619390075Sobrien{
619490075Sobrien  int regs[4];
619590075Sobrien  int base_reg;
619690075Sobrien  HOST_WIDE_INT offset;
619790075Sobrien  char buf[100];
619890075Sobrien  int i;
619990075Sobrien
620090075Sobrien  switch (store_multiple_sequence (operands, nops, regs, &base_reg, &offset))
620190075Sobrien    {
620290075Sobrien    case 1:
620390075Sobrien      strcpy (buf, "stm%?ia\t");
620490075Sobrien      break;
620590075Sobrien
620690075Sobrien    case 2:
620790075Sobrien      strcpy (buf, "stm%?ib\t");
620890075Sobrien      break;
620990075Sobrien
621090075Sobrien    case 3:
621190075Sobrien      strcpy (buf, "stm%?da\t");
621290075Sobrien      break;
621390075Sobrien
621490075Sobrien    case 4:
621590075Sobrien      strcpy (buf, "stm%?db\t");
621690075Sobrien      break;
621790075Sobrien
621890075Sobrien    default:
6219169689Skan      gcc_unreachable ();
622090075Sobrien    }
622190075Sobrien
6222169689Skan  sprintf (buf + strlen (buf), "%s%s, {%s%s", REGISTER_PREFIX,
622390075Sobrien	   reg_names[base_reg], REGISTER_PREFIX, reg_names[regs[0]]);
622490075Sobrien
622590075Sobrien  for (i = 1; i < nops; i++)
622690075Sobrien    sprintf (buf + strlen (buf), ", %s%s", REGISTER_PREFIX,
622790075Sobrien	     reg_names[regs[i]]);
622890075Sobrien
622990075Sobrien  strcat (buf, "}\t%@ phole stm");
623090075Sobrien
623190075Sobrien  output_asm_insn (buf, operands);
623290075Sobrien  return "";
623390075Sobrien}
623490075Sobrien
623590075Sobrien/* Routines for use in generating RTL.  */
623690075Sobrien
623790075Sobrienrtx
6238132718Skanarm_gen_load_multiple (int base_regno, int count, rtx from, int up,
6239161651Skan		       int write_back, rtx basemem, HOST_WIDE_INT *offsetp)
624090075Sobrien{
6241161651Skan  HOST_WIDE_INT offset = *offsetp;
624290075Sobrien  int i = 0, j;
624390075Sobrien  rtx result;
624490075Sobrien  int sign = up ? 1 : -1;
6245161651Skan  rtx mem, addr;
624690075Sobrien
624790075Sobrien  /* XScale has load-store double instructions, but they have stricter
6248169689Skan     alignment requirements than load-store multiple, so we cannot
624990075Sobrien     use them.
625090075Sobrien
625190075Sobrien     For XScale ldm requires 2 + NREGS cycles to complete and blocks
625290075Sobrien     the pipeline until completion.
625390075Sobrien
625490075Sobrien	NREGS		CYCLES
625590075Sobrien	  1		  3
625690075Sobrien	  2		  4
625790075Sobrien	  3		  5
625890075Sobrien	  4		  6
625990075Sobrien
626090075Sobrien     An ldr instruction takes 1-3 cycles, but does not block the
626190075Sobrien     pipeline.
626290075Sobrien
626390075Sobrien	NREGS		CYCLES
626490075Sobrien	  1		 1-3
626590075Sobrien	  2		 2-6
626690075Sobrien	  3		 3-9
626790075Sobrien	  4		 4-12
626890075Sobrien
626990075Sobrien     Best case ldr will always win.  However, the more ldr instructions
627090075Sobrien     we issue, the less likely we are to be able to schedule them well.
627190075Sobrien     Using ldr instructions also increases code size.
627290075Sobrien
627390075Sobrien     As a compromise, we use ldr for counts of 1 or 2 regs, and ldm
627490075Sobrien     for counts of 3 or 4 regs.  */
6275132718Skan  if (arm_tune_xscale && count <= 2 && ! optimize_size)
627690075Sobrien    {
627790075Sobrien      rtx seq;
6278169689Skan
627990075Sobrien      start_sequence ();
6280169689Skan
628190075Sobrien      for (i = 0; i < count; i++)
628290075Sobrien	{
6283161651Skan	  addr = plus_constant (from, i * 4 * sign);
6284161651Skan	  mem = adjust_automodify_address (basemem, SImode, addr, offset);
628590075Sobrien	  emit_move_insn (gen_rtx_REG (SImode, base_regno + i), mem);
6286161651Skan	  offset += 4 * sign;
628790075Sobrien	}
628890075Sobrien
628990075Sobrien      if (write_back)
6290161651Skan	{
6291161651Skan	  emit_move_insn (from, plus_constant (from, count * 4 * sign));
6292161651Skan	  *offsetp = offset;
6293161651Skan	}
629490075Sobrien
6295117395Skan      seq = get_insns ();
629690075Sobrien      end_sequence ();
6297169689Skan
629890075Sobrien      return seq;
629990075Sobrien    }
630090075Sobrien
630190075Sobrien  result = gen_rtx_PARALLEL (VOIDmode,
630290075Sobrien			     rtvec_alloc (count + (write_back ? 1 : 0)));
630390075Sobrien  if (write_back)
630490075Sobrien    {
630590075Sobrien      XVECEXP (result, 0, 0)
6306169689Skan	= gen_rtx_SET (VOIDmode, from, plus_constant (from, count * 4 * sign));
630790075Sobrien      i = 1;
630890075Sobrien      count++;
630990075Sobrien    }
631090075Sobrien
631190075Sobrien  for (j = 0; i < count; i++, j++)
631290075Sobrien    {
6313161651Skan      addr = plus_constant (from, j * 4 * sign);
6314161651Skan      mem = adjust_automodify_address_nv (basemem, SImode, addr, offset);
631590075Sobrien      XVECEXP (result, 0, i)
631690075Sobrien	= gen_rtx_SET (VOIDmode, gen_rtx_REG (SImode, base_regno + j), mem);
6317161651Skan      offset += 4 * sign;
631890075Sobrien    }
631990075Sobrien
6320161651Skan  if (write_back)
6321161651Skan    *offsetp = offset;
6322161651Skan
632390075Sobrien  return result;
632490075Sobrien}
632590075Sobrien
632690075Sobrienrtx
6327132718Skanarm_gen_store_multiple (int base_regno, int count, rtx to, int up,
6328161651Skan			int write_back, rtx basemem, HOST_WIDE_INT *offsetp)
632990075Sobrien{
6330161651Skan  HOST_WIDE_INT offset = *offsetp;
633190075Sobrien  int i = 0, j;
633290075Sobrien  rtx result;
633390075Sobrien  int sign = up ? 1 : -1;
6334161651Skan  rtx mem, addr;
633590075Sobrien
633690075Sobrien  /* See arm_gen_load_multiple for discussion of
633790075Sobrien     the pros/cons of ldm/stm usage for XScale.  */
6338132718Skan  if (arm_tune_xscale && count <= 2 && ! optimize_size)
633990075Sobrien    {
634090075Sobrien      rtx seq;
6341169689Skan
634290075Sobrien      start_sequence ();
6343169689Skan
634490075Sobrien      for (i = 0; i < count; i++)
634590075Sobrien	{
6346161651Skan	  addr = plus_constant (to, i * 4 * sign);
6347161651Skan	  mem = adjust_automodify_address (basemem, SImode, addr, offset);
634890075Sobrien	  emit_move_insn (mem, gen_rtx_REG (SImode, base_regno + i));
6349161651Skan	  offset += 4 * sign;
635090075Sobrien	}
635190075Sobrien
635290075Sobrien      if (write_back)
6353161651Skan	{
6354161651Skan	  emit_move_insn (to, plus_constant (to, count * 4 * sign));
6355161651Skan	  *offsetp = offset;
6356161651Skan	}
635790075Sobrien
6358117395Skan      seq = get_insns ();
635990075Sobrien      end_sequence ();
6360169689Skan
636190075Sobrien      return seq;
636290075Sobrien    }
636390075Sobrien
636490075Sobrien  result = gen_rtx_PARALLEL (VOIDmode,
636590075Sobrien			     rtvec_alloc (count + (write_back ? 1 : 0)));
636690075Sobrien  if (write_back)
636790075Sobrien    {
636890075Sobrien      XVECEXP (result, 0, 0)
6369169689Skan	= gen_rtx_SET (VOIDmode, to,
637090075Sobrien		       plus_constant (to, count * 4 * sign));
637190075Sobrien      i = 1;
637290075Sobrien      count++;
637390075Sobrien    }
637490075Sobrien
637590075Sobrien  for (j = 0; i < count; i++, j++)
637690075Sobrien    {
6377161651Skan      addr = plus_constant (to, j * 4 * sign);
6378161651Skan      mem = adjust_automodify_address_nv (basemem, SImode, addr, offset);
637990075Sobrien      XVECEXP (result, 0, i)
638090075Sobrien	= gen_rtx_SET (VOIDmode, mem, gen_rtx_REG (SImode, base_regno + j));
6381161651Skan      offset += 4 * sign;
638290075Sobrien    }
638390075Sobrien
6384161651Skan  if (write_back)
6385161651Skan    *offsetp = offset;
6386161651Skan
638790075Sobrien  return result;
638890075Sobrien}
638990075Sobrien
639090075Sobrienint
6391169689Skanarm_gen_movmemqi (rtx *operands)
639290075Sobrien{
639390075Sobrien  HOST_WIDE_INT in_words_to_go, out_words_to_go, last_bytes;
6394161651Skan  HOST_WIDE_INT srcoffset, dstoffset;
639590075Sobrien  int i;
6396161651Skan  rtx src, dst, srcbase, dstbase;
639790075Sobrien  rtx part_bytes_reg = NULL;
639890075Sobrien  rtx mem;
639990075Sobrien
640090075Sobrien  if (GET_CODE (operands[2]) != CONST_INT
640190075Sobrien      || GET_CODE (operands[3]) != CONST_INT
640290075Sobrien      || INTVAL (operands[2]) > 64
640390075Sobrien      || INTVAL (operands[3]) & 3)
640490075Sobrien    return 0;
640590075Sobrien
6406161651Skan  dstbase = operands[0];
6407161651Skan  srcbase = operands[1];
6408169689Skan
6409161651Skan  dst = copy_to_mode_reg (SImode, XEXP (dstbase, 0));
6410161651Skan  src = copy_to_mode_reg (SImode, XEXP (srcbase, 0));
641190075Sobrien
6412117395Skan  in_words_to_go = ARM_NUM_INTS (INTVAL (operands[2]));
641390075Sobrien  out_words_to_go = INTVAL (operands[2]) / 4;
641490075Sobrien  last_bytes = INTVAL (operands[2]) & 3;
6415161651Skan  dstoffset = srcoffset = 0;
6416169689Skan
641790075Sobrien  if (out_words_to_go != in_words_to_go && ((in_words_to_go - 1) & 3) != 0)
641890075Sobrien    part_bytes_reg = gen_rtx_REG (SImode, (in_words_to_go - 1) & 3);
641990075Sobrien
642090075Sobrien  for (i = 0; in_words_to_go >= 2; i+=4)
642190075Sobrien    {
642290075Sobrien      if (in_words_to_go > 4)
642390075Sobrien	emit_insn (arm_gen_load_multiple (0, 4, src, TRUE, TRUE,
6424161651Skan					  srcbase, &srcoffset));
642590075Sobrien      else
6426169689Skan	emit_insn (arm_gen_load_multiple (0, in_words_to_go, src, TRUE,
6427161651Skan					  FALSE, srcbase, &srcoffset));
642890075Sobrien
642990075Sobrien      if (out_words_to_go)
643090075Sobrien	{
643190075Sobrien	  if (out_words_to_go > 4)
643290075Sobrien	    emit_insn (arm_gen_store_multiple (0, 4, dst, TRUE, TRUE,
6433161651Skan					       dstbase, &dstoffset));
643490075Sobrien	  else if (out_words_to_go != 1)
643590075Sobrien	    emit_insn (arm_gen_store_multiple (0, out_words_to_go,
6436169689Skan					       dst, TRUE,
643790075Sobrien					       (last_bytes == 0
643890075Sobrien						? FALSE : TRUE),
6439161651Skan					       dstbase, &dstoffset));
644090075Sobrien	  else
644190075Sobrien	    {
6442161651Skan	      mem = adjust_automodify_address (dstbase, SImode, dst, dstoffset);
644390075Sobrien	      emit_move_insn (mem, gen_rtx_REG (SImode, 0));
644490075Sobrien	      if (last_bytes != 0)
6445161651Skan		{
6446161651Skan		  emit_insn (gen_addsi3 (dst, dst, GEN_INT (4)));
6447161651Skan		  dstoffset += 4;
6448161651Skan		}
644990075Sobrien	    }
645090075Sobrien	}
645190075Sobrien
645290075Sobrien      in_words_to_go -= in_words_to_go < 4 ? in_words_to_go : 4;
645390075Sobrien      out_words_to_go -= out_words_to_go < 4 ? out_words_to_go : 4;
645490075Sobrien    }
645590075Sobrien
645690075Sobrien  /* OUT_WORDS_TO_GO will be zero here if there are byte stores to do.  */
645790075Sobrien  if (out_words_to_go)
645890075Sobrien    {
645990075Sobrien      rtx sreg;
6460161651Skan
6461161651Skan      mem = adjust_automodify_address (srcbase, SImode, src, srcoffset);
6462161651Skan      sreg = copy_to_reg (mem);
6463161651Skan
6464161651Skan      mem = adjust_automodify_address (dstbase, SImode, dst, dstoffset);
646590075Sobrien      emit_move_insn (mem, sreg);
646690075Sobrien      in_words_to_go--;
6467169689Skan
6468169689Skan      gcc_assert (!in_words_to_go);	/* Sanity check */
646990075Sobrien    }
647090075Sobrien
647190075Sobrien  if (in_words_to_go)
647290075Sobrien    {
6473169689Skan      gcc_assert (in_words_to_go > 0);
647490075Sobrien
6475161651Skan      mem = adjust_automodify_address (srcbase, SImode, src, srcoffset);
647690075Sobrien      part_bytes_reg = copy_to_mode_reg (SImode, mem);
647790075Sobrien    }
647890075Sobrien
6479169689Skan  gcc_assert (!last_bytes || part_bytes_reg);
648090075Sobrien
648190075Sobrien  if (BYTES_BIG_ENDIAN && last_bytes)
648290075Sobrien    {
648390075Sobrien      rtx tmp = gen_reg_rtx (SImode);
648490075Sobrien
648590075Sobrien      /* The bytes we want are in the top end of the word.  */
648690075Sobrien      emit_insn (gen_lshrsi3 (tmp, part_bytes_reg,
648790075Sobrien			      GEN_INT (8 * (4 - last_bytes))));
648890075Sobrien      part_bytes_reg = tmp;
6489169689Skan
649090075Sobrien      while (last_bytes)
649190075Sobrien	{
6492161651Skan	  mem = adjust_automodify_address (dstbase, QImode,
6493161651Skan					   plus_constant (dst, last_bytes - 1),
6494161651Skan					   dstoffset + last_bytes - 1);
6495102780Skan	  emit_move_insn (mem, gen_lowpart (QImode, part_bytes_reg));
6496102780Skan
649790075Sobrien	  if (--last_bytes)
649890075Sobrien	    {
649990075Sobrien	      tmp = gen_reg_rtx (SImode);
650090075Sobrien	      emit_insn (gen_lshrsi3 (tmp, part_bytes_reg, GEN_INT (8)));
650190075Sobrien	      part_bytes_reg = tmp;
650290075Sobrien	    }
650390075Sobrien	}
6504169689Skan
650590075Sobrien    }
650690075Sobrien  else
650790075Sobrien    {
650890075Sobrien      if (last_bytes > 1)
650990075Sobrien	{
6510161651Skan	  mem = adjust_automodify_address (dstbase, HImode, dst, dstoffset);
6511102780Skan	  emit_move_insn (mem, gen_lowpart (HImode, part_bytes_reg));
651290075Sobrien	  last_bytes -= 2;
651390075Sobrien	  if (last_bytes)
651490075Sobrien	    {
651590075Sobrien	      rtx tmp = gen_reg_rtx (SImode);
6516169689Skan	      emit_insn (gen_addsi3 (dst, dst, const2_rtx));
651790075Sobrien	      emit_insn (gen_lshrsi3 (tmp, part_bytes_reg, GEN_INT (16)));
651890075Sobrien	      part_bytes_reg = tmp;
6519161651Skan	      dstoffset += 2;
652090075Sobrien	    }
652190075Sobrien	}
6522169689Skan
652390075Sobrien      if (last_bytes)
652490075Sobrien	{
6525161651Skan	  mem = adjust_automodify_address (dstbase, QImode, dst, dstoffset);
6526102780Skan	  emit_move_insn (mem, gen_lowpart (QImode, part_bytes_reg));
652790075Sobrien	}
652890075Sobrien    }
652990075Sobrien
653090075Sobrien  return 1;
653190075Sobrien}
653290075Sobrien
6533132718Skan/* Select a dominance comparison mode if possible for a test of the general
6534132718Skan   form (OP (COND_OR (X) (Y)) (const_int 0)).  We support three forms.
6535169689Skan   COND_OR == DOM_CC_X_AND_Y => (X && Y)
6536132718Skan   COND_OR == DOM_CC_NX_OR_Y => ((! X) || Y)
6537169689Skan   COND_OR == DOM_CC_X_OR_Y => (X || Y)
6538132718Skan   In all cases OP will be either EQ or NE, but we don't need to know which
6539169689Skan   here.  If we are unable to support a dominance comparison we return
6540132718Skan   CC mode.  This will then fail to match for the RTL expressions that
6541132718Skan   generate this call.  */
6542132718Skanenum machine_mode
6543132718Skanarm_select_dominance_cc_mode (rtx x, rtx y, HOST_WIDE_INT cond_or)
654490075Sobrien{
654590075Sobrien  enum rtx_code cond1, cond2;
654690075Sobrien  int swapped = 0;
654790075Sobrien
654890075Sobrien  /* Currently we will probably get the wrong result if the individual
654990075Sobrien     comparisons are not simple.  This also ensures that it is safe to
655090075Sobrien     reverse a comparison if necessary.  */
655190075Sobrien  if ((arm_select_cc_mode (cond1 = GET_CODE (x), XEXP (x, 0), XEXP (x, 1))
655290075Sobrien       != CCmode)
655390075Sobrien      || (arm_select_cc_mode (cond2 = GET_CODE (y), XEXP (y, 0), XEXP (y, 1))
655490075Sobrien	  != CCmode))
655590075Sobrien    return CCmode;
655690075Sobrien
655790075Sobrien  /* The if_then_else variant of this tests the second condition if the
655890075Sobrien     first passes, but is true if the first fails.  Reverse the first
655990075Sobrien     condition to get a true "inclusive-or" expression.  */
6560132718Skan  if (cond_or == DOM_CC_NX_OR_Y)
656190075Sobrien    cond1 = reverse_condition (cond1);
656290075Sobrien
656390075Sobrien  /* If the comparisons are not equal, and one doesn't dominate the other,
656490075Sobrien     then we can't do this.  */
6565169689Skan  if (cond1 != cond2
656690075Sobrien      && !comparison_dominates_p (cond1, cond2)
656790075Sobrien      && (swapped = 1, !comparison_dominates_p (cond2, cond1)))
656890075Sobrien    return CCmode;
656990075Sobrien
657090075Sobrien  if (swapped)
657190075Sobrien    {
657290075Sobrien      enum rtx_code temp = cond1;
657390075Sobrien      cond1 = cond2;
657490075Sobrien      cond2 = temp;
657590075Sobrien    }
657690075Sobrien
657790075Sobrien  switch (cond1)
657890075Sobrien    {
657990075Sobrien    case EQ:
6580169689Skan      if (cond_or == DOM_CC_X_AND_Y)
658190075Sobrien	return CC_DEQmode;
658290075Sobrien
658390075Sobrien      switch (cond2)
658490075Sobrien	{
6585169689Skan	case EQ: return CC_DEQmode;
658690075Sobrien	case LE: return CC_DLEmode;
658790075Sobrien	case LEU: return CC_DLEUmode;
658890075Sobrien	case GE: return CC_DGEmode;
658990075Sobrien	case GEU: return CC_DGEUmode;
6590169689Skan	default: gcc_unreachable ();
659190075Sobrien	}
659290075Sobrien
659390075Sobrien    case LT:
6594169689Skan      if (cond_or == DOM_CC_X_AND_Y)
659590075Sobrien	return CC_DLTmode;
659690075Sobrien
6597169689Skan      switch (cond2)
6598169689Skan	{
6599169689Skan	case  LT:
6600169689Skan	    return CC_DLTmode;
6601169689Skan	case LE:
6602169689Skan	  return CC_DLEmode;
6603169689Skan	case NE:
6604169689Skan	  return CC_DNEmode;
6605169689Skan	default:
6606169689Skan	  gcc_unreachable ();
6607169689Skan	}
6608169689Skan
660990075Sobrien    case GT:
6610169689Skan      if (cond_or == DOM_CC_X_AND_Y)
661190075Sobrien	return CC_DGTmode;
6612169689Skan
6613169689Skan      switch (cond2)
6614169689Skan	{
6615169689Skan	case GT:
6616169689Skan	  return CC_DGTmode;
6617169689Skan	case GE:
6618169689Skan	  return CC_DGEmode;
6619169689Skan	case NE:
6620169689Skan	  return CC_DNEmode;
6621169689Skan	default:
6622169689Skan	  gcc_unreachable ();
6623169689Skan	}
6624169689Skan
662590075Sobrien    case LTU:
6626169689Skan      if (cond_or == DOM_CC_X_AND_Y)
662790075Sobrien	return CC_DLTUmode;
662890075Sobrien
6629169689Skan      switch (cond2)
6630169689Skan	{
6631169689Skan	case LTU:
6632169689Skan	  return CC_DLTUmode;
6633169689Skan	case LEU:
6634169689Skan	  return CC_DLEUmode;
6635169689Skan	case NE:
6636169689Skan	  return CC_DNEmode;
6637169689Skan	default:
6638169689Skan	  gcc_unreachable ();
6639169689Skan	}
6640169689Skan
664190075Sobrien    case GTU:
6642169689Skan      if (cond_or == DOM_CC_X_AND_Y)
664390075Sobrien	return CC_DGTUmode;
664490075Sobrien
6645169689Skan      switch (cond2)
6646169689Skan	{
6647169689Skan	case GTU:
6648169689Skan	  return CC_DGTUmode;
6649169689Skan	case GEU:
6650169689Skan	  return CC_DGEUmode;
6651169689Skan	case NE:
6652169689Skan	  return CC_DNEmode;
6653169689Skan	default:
6654169689Skan	  gcc_unreachable ();
6655169689Skan	}
6656169689Skan
665790075Sobrien    /* The remaining cases only occur when both comparisons are the
665890075Sobrien       same.  */
665990075Sobrien    case NE:
6660169689Skan      gcc_assert (cond1 == cond2);
666190075Sobrien      return CC_DNEmode;
666290075Sobrien
666390075Sobrien    case LE:
6664169689Skan      gcc_assert (cond1 == cond2);
666590075Sobrien      return CC_DLEmode;
666690075Sobrien
666790075Sobrien    case GE:
6668169689Skan      gcc_assert (cond1 == cond2);
666990075Sobrien      return CC_DGEmode;
667090075Sobrien
667190075Sobrien    case LEU:
6672169689Skan      gcc_assert (cond1 == cond2);
667390075Sobrien      return CC_DLEUmode;
667490075Sobrien
667590075Sobrien    case GEU:
6676169689Skan      gcc_assert (cond1 == cond2);
667790075Sobrien      return CC_DGEUmode;
667890075Sobrien
667990075Sobrien    default:
6680169689Skan      gcc_unreachable ();
668190075Sobrien    }
668290075Sobrien}
668390075Sobrien
668490075Sobrienenum machine_mode
6685132718Skanarm_select_cc_mode (enum rtx_code op, rtx x, rtx y)
668690075Sobrien{
668790075Sobrien  /* All floating point compares return CCFP if it is an equality
668890075Sobrien     comparison, and CCFPE otherwise.  */
668990075Sobrien  if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
669090075Sobrien    {
669190075Sobrien      switch (op)
669290075Sobrien	{
669390075Sobrien	case EQ:
669490075Sobrien	case NE:
669590075Sobrien	case UNORDERED:
669690075Sobrien	case ORDERED:
669790075Sobrien	case UNLT:
669890075Sobrien	case UNLE:
669990075Sobrien	case UNGT:
670090075Sobrien	case UNGE:
670190075Sobrien	case UNEQ:
670290075Sobrien	case LTGT:
670390075Sobrien	  return CCFPmode;
670490075Sobrien
670590075Sobrien	case LT:
670690075Sobrien	case LE:
670790075Sobrien	case GT:
670890075Sobrien	case GE:
6709169689Skan	  if (TARGET_HARD_FLOAT && TARGET_MAVERICK)
6710132718Skan	    return CCFPmode;
671190075Sobrien	  return CCFPEmode;
671290075Sobrien
671390075Sobrien	default:
6714169689Skan	  gcc_unreachable ();
671590075Sobrien	}
671690075Sobrien    }
6717169689Skan
671890075Sobrien  /* A compare with a shifted operand.  Because of canonicalization, the
671990075Sobrien     comparison will have to be swapped when we emit the assembler.  */
672090075Sobrien  if (GET_MODE (y) == SImode && GET_CODE (y) == REG
672190075Sobrien      && (GET_CODE (x) == ASHIFT || GET_CODE (x) == ASHIFTRT
672290075Sobrien	  || GET_CODE (x) == LSHIFTRT || GET_CODE (x) == ROTATE
672390075Sobrien	  || GET_CODE (x) == ROTATERT))
672490075Sobrien    return CC_SWPmode;
672590075Sobrien
6726169689Skan  /* This operation is performed swapped, but since we only rely on the Z
6727169689Skan     flag we don't need an additional mode.  */
6728169689Skan  if (GET_MODE (y) == SImode && REG_P (y)
6729169689Skan      && GET_CODE (x) == NEG
6730169689Skan      && (op ==	EQ || op == NE))
6731169689Skan    return CC_Zmode;
6732169689Skan
6733169689Skan  /* This is a special case that is used by combine to allow a
673490075Sobrien     comparison of a shifted byte load to be split into a zero-extend
673590075Sobrien     followed by a comparison of the shifted integer (only valid for
673690075Sobrien     equalities and unsigned inequalities).  */
673790075Sobrien  if (GET_MODE (x) == SImode
673890075Sobrien      && GET_CODE (x) == ASHIFT
673990075Sobrien      && GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) == 24
674090075Sobrien      && GET_CODE (XEXP (x, 0)) == SUBREG
674190075Sobrien      && GET_CODE (SUBREG_REG (XEXP (x, 0))) == MEM
674290075Sobrien      && GET_MODE (SUBREG_REG (XEXP (x, 0))) == QImode
674390075Sobrien      && (op == EQ || op == NE
674490075Sobrien	  || op == GEU || op == GTU || op == LTU || op == LEU)
674590075Sobrien      && GET_CODE (y) == CONST_INT)
674690075Sobrien    return CC_Zmode;
674790075Sobrien
674890075Sobrien  /* A construct for a conditional compare, if the false arm contains
674990075Sobrien     0, then both conditions must be true, otherwise either condition
675090075Sobrien     must be true.  Not all conditions are possible, so CCmode is
675190075Sobrien     returned if it can't be done.  */
675290075Sobrien  if (GET_CODE (x) == IF_THEN_ELSE
675390075Sobrien      && (XEXP (x, 2) == const0_rtx
675490075Sobrien	  || XEXP (x, 2) == const1_rtx)
6755169689Skan      && COMPARISON_P (XEXP (x, 0))
6756169689Skan      && COMPARISON_P (XEXP (x, 1)))
6757169689Skan    return arm_select_dominance_cc_mode (XEXP (x, 0), XEXP (x, 1),
6758132718Skan					 INTVAL (XEXP (x, 2)));
675990075Sobrien
676090075Sobrien  /* Alternate canonicalizations of the above.  These are somewhat cleaner.  */
676190075Sobrien  if (GET_CODE (x) == AND
6762169689Skan      && COMPARISON_P (XEXP (x, 0))
6763169689Skan      && COMPARISON_P (XEXP (x, 1)))
6764132718Skan    return arm_select_dominance_cc_mode (XEXP (x, 0), XEXP (x, 1),
6765132718Skan					 DOM_CC_X_AND_Y);
676690075Sobrien
676790075Sobrien  if (GET_CODE (x) == IOR
6768169689Skan      && COMPARISON_P (XEXP (x, 0))
6769169689Skan      && COMPARISON_P (XEXP (x, 1)))
6770132718Skan    return arm_select_dominance_cc_mode (XEXP (x, 0), XEXP (x, 1),
6771132718Skan					 DOM_CC_X_OR_Y);
677290075Sobrien
6773132718Skan  /* An operation (on Thumb) where we want to test for a single bit.
6774132718Skan     This is done by shifting that bit up into the top bit of a
6775132718Skan     scratch register; we can then branch on the sign bit.  */
6776132718Skan  if (TARGET_THUMB
6777132718Skan      && GET_MODE (x) == SImode
6778132718Skan      && (op == EQ || op == NE)
6779169689Skan      && GET_CODE (x) == ZERO_EXTRACT
6780169689Skan      && XEXP (x, 1) == const1_rtx)
6781132718Skan    return CC_Nmode;
6782132718Skan
678390075Sobrien  /* An operation that sets the condition codes as a side-effect, the
678490075Sobrien     V flag is not set correctly, so we can only use comparisons where
678590075Sobrien     this doesn't matter.  (For LT and GE we can use "mi" and "pl"
6786132718Skan     instead.)  */
678790075Sobrien  if (GET_MODE (x) == SImode
678890075Sobrien      && y == const0_rtx
678990075Sobrien      && (op == EQ || op == NE || op == LT || op == GE)
679090075Sobrien      && (GET_CODE (x) == PLUS || GET_CODE (x) == MINUS
679190075Sobrien	  || GET_CODE (x) == AND || GET_CODE (x) == IOR
679290075Sobrien	  || GET_CODE (x) == XOR || GET_CODE (x) == MULT
679390075Sobrien	  || GET_CODE (x) == NOT || GET_CODE (x) == NEG
679490075Sobrien	  || GET_CODE (x) == LSHIFTRT
679590075Sobrien	  || GET_CODE (x) == ASHIFT || GET_CODE (x) == ASHIFTRT
6796132718Skan	  || GET_CODE (x) == ROTATERT
6797132718Skan	  || (TARGET_ARM && GET_CODE (x) == ZERO_EXTRACT)))
679890075Sobrien    return CC_NOOVmode;
679990075Sobrien
680090075Sobrien  if (GET_MODE (x) == QImode && (op == EQ || op == NE))
680190075Sobrien    return CC_Zmode;
680290075Sobrien
680390075Sobrien  if (GET_MODE (x) == SImode && (op == LTU || op == GEU)
680490075Sobrien      && GET_CODE (x) == PLUS
680590075Sobrien      && (rtx_equal_p (XEXP (x, 0), y) || rtx_equal_p (XEXP (x, 1), y)))
680690075Sobrien    return CC_Cmode;
680790075Sobrien
680890075Sobrien  return CCmode;
680990075Sobrien}
681090075Sobrien
681190075Sobrien/* X and Y are two things to compare using CODE.  Emit the compare insn and
681290075Sobrien   return the rtx for register 0 in the proper mode.  FP means this is a
681390075Sobrien   floating point compare: I don't think that it is needed on the arm.  */
681490075Sobrienrtx
6815132718Skanarm_gen_compare_reg (enum rtx_code code, rtx x, rtx y)
681690075Sobrien{
681790075Sobrien  enum machine_mode mode = SELECT_CC_MODE (code, x, y);
681890075Sobrien  rtx cc_reg = gen_rtx_REG (mode, CC_REGNUM);
681990075Sobrien
6820169689Skan  emit_set_insn (cc_reg, gen_rtx_COMPARE (mode, x, y));
682190075Sobrien
682290075Sobrien  return cc_reg;
682390075Sobrien}
682490075Sobrien
6825117395Skan/* Generate a sequence of insns that will generate the correct return
6826117395Skan   address mask depending on the physical architecture that the program
6827117395Skan   is running on.  */
6828117395Skanrtx
6829132718Skanarm_gen_return_addr_mask (void)
6830117395Skan{
6831117395Skan  rtx reg = gen_reg_rtx (Pmode);
6832117395Skan
6833117395Skan  emit_insn (gen_return_addr_mask (reg));
6834117395Skan  return reg;
6835117395Skan}
6836117395Skan
683790075Sobrienvoid
6838132718Skanarm_reload_in_hi (rtx *operands)
683990075Sobrien{
684090075Sobrien  rtx ref = operands[1];
684190075Sobrien  rtx base, scratch;
684290075Sobrien  HOST_WIDE_INT offset = 0;
684390075Sobrien
684490075Sobrien  if (GET_CODE (ref) == SUBREG)
684590075Sobrien    {
684690075Sobrien      offset = SUBREG_BYTE (ref);
684790075Sobrien      ref = SUBREG_REG (ref);
684890075Sobrien    }
684990075Sobrien
685090075Sobrien  if (GET_CODE (ref) == REG)
685190075Sobrien    {
685290075Sobrien      /* We have a pseudo which has been spilt onto the stack; there
685390075Sobrien	 are two cases here: the first where there is a simple
685490075Sobrien	 stack-slot replacement and a second where the stack-slot is
685590075Sobrien	 out of range, or is used as a subreg.  */
685690075Sobrien      if (reg_equiv_mem[REGNO (ref)])
685790075Sobrien	{
685890075Sobrien	  ref = reg_equiv_mem[REGNO (ref)];
685990075Sobrien	  base = find_replacement (&XEXP (ref, 0));
686090075Sobrien	}
686190075Sobrien      else
686290075Sobrien	/* The slot is out of range, or was dressed up in a SUBREG.  */
686390075Sobrien	base = reg_equiv_address[REGNO (ref)];
686490075Sobrien    }
686590075Sobrien  else
686690075Sobrien    base = find_replacement (&XEXP (ref, 0));
686790075Sobrien
686890075Sobrien  /* Handle the case where the address is too complex to be offset by 1.  */
686990075Sobrien  if (GET_CODE (base) == MINUS
687090075Sobrien      || (GET_CODE (base) == PLUS && GET_CODE (XEXP (base, 1)) != CONST_INT))
687190075Sobrien    {
687290075Sobrien      rtx base_plus = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
687390075Sobrien
6874169689Skan      emit_set_insn (base_plus, base);
687590075Sobrien      base = base_plus;
687690075Sobrien    }
687790075Sobrien  else if (GET_CODE (base) == PLUS)
687890075Sobrien    {
687990075Sobrien      /* The addend must be CONST_INT, or we would have dealt with it above.  */
688090075Sobrien      HOST_WIDE_INT hi, lo;
688190075Sobrien
688290075Sobrien      offset += INTVAL (XEXP (base, 1));
688390075Sobrien      base = XEXP (base, 0);
688490075Sobrien
688590075Sobrien      /* Rework the address into a legal sequence of insns.  */
688690075Sobrien      /* Valid range for lo is -4095 -> 4095 */
688790075Sobrien      lo = (offset >= 0
688890075Sobrien	    ? (offset & 0xfff)
688990075Sobrien	    : -((-offset) & 0xfff));
689090075Sobrien
689190075Sobrien      /* Corner case, if lo is the max offset then we would be out of range
689290075Sobrien	 once we have added the additional 1 below, so bump the msb into the
689390075Sobrien	 pre-loading insn(s).  */
689490075Sobrien      if (lo == 4095)
689590075Sobrien	lo &= 0x7ff;
689690075Sobrien
689790075Sobrien      hi = ((((offset - lo) & (HOST_WIDE_INT) 0xffffffff)
689890075Sobrien	     ^ (HOST_WIDE_INT) 0x80000000)
689990075Sobrien	    - (HOST_WIDE_INT) 0x80000000);
690090075Sobrien
6901169689Skan      gcc_assert (hi + lo == offset);
690290075Sobrien
690390075Sobrien      if (hi != 0)
690490075Sobrien	{
690590075Sobrien	  rtx base_plus = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
690690075Sobrien
690790075Sobrien	  /* Get the base address; addsi3 knows how to handle constants
690890075Sobrien	     that require more than one insn.  */
690990075Sobrien	  emit_insn (gen_addsi3 (base_plus, base, GEN_INT (hi)));
691090075Sobrien	  base = base_plus;
691190075Sobrien	  offset = lo;
691290075Sobrien	}
691390075Sobrien    }
691490075Sobrien
6915117395Skan  /* Operands[2] may overlap operands[0] (though it won't overlap
6916117395Skan     operands[1]), that's why we asked for a DImode reg -- so we can
6917117395Skan     use the bit that does not overlap.  */
6918117395Skan  if (REGNO (operands[2]) == REGNO (operands[0]))
6919117395Skan    scratch = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
6920117395Skan  else
6921117395Skan    scratch = gen_rtx_REG (SImode, REGNO (operands[2]));
6922117395Skan
692390075Sobrien  emit_insn (gen_zero_extendqisi2 (scratch,
692490075Sobrien				   gen_rtx_MEM (QImode,
692590075Sobrien						plus_constant (base,
692690075Sobrien							       offset))));
692790075Sobrien  emit_insn (gen_zero_extendqisi2 (gen_rtx_SUBREG (SImode, operands[0], 0),
6928169689Skan				   gen_rtx_MEM (QImode,
692990075Sobrien						plus_constant (base,
693090075Sobrien							       offset + 1))));
693190075Sobrien  if (!BYTES_BIG_ENDIAN)
6932169689Skan    emit_set_insn (gen_rtx_SUBREG (SImode, operands[0], 0),
6933169689Skan		   gen_rtx_IOR (SImode,
6934169689Skan				gen_rtx_ASHIFT
6935169689Skan				(SImode,
6936169689Skan				 gen_rtx_SUBREG (SImode, operands[0], 0),
6937169689Skan				 GEN_INT (8)),
6938169689Skan				scratch));
693990075Sobrien  else
6940169689Skan    emit_set_insn (gen_rtx_SUBREG (SImode, operands[0], 0),
6941169689Skan		   gen_rtx_IOR (SImode,
6942169689Skan				gen_rtx_ASHIFT (SImode, scratch,
6943169689Skan						GEN_INT (8)),
6944169689Skan				gen_rtx_SUBREG (SImode, operands[0], 0)));
694590075Sobrien}
694690075Sobrien
6947132718Skan/* Handle storing a half-word to memory during reload by synthesizing as two
694890075Sobrien   byte stores.  Take care not to clobber the input values until after we
694990075Sobrien   have moved them somewhere safe.  This code assumes that if the DImode
695090075Sobrien   scratch in operands[2] overlaps either the input value or output address
695190075Sobrien   in some way, then that value must die in this insn (we absolutely need
695290075Sobrien   two scratch registers for some corner cases).  */
695390075Sobrienvoid
6954132718Skanarm_reload_out_hi (rtx *operands)
695590075Sobrien{
695690075Sobrien  rtx ref = operands[0];
695790075Sobrien  rtx outval = operands[1];
695890075Sobrien  rtx base, scratch;
695990075Sobrien  HOST_WIDE_INT offset = 0;
696090075Sobrien
696190075Sobrien  if (GET_CODE (ref) == SUBREG)
696290075Sobrien    {
696390075Sobrien      offset = SUBREG_BYTE (ref);
696490075Sobrien      ref = SUBREG_REG (ref);
696590075Sobrien    }
696690075Sobrien
696790075Sobrien  if (GET_CODE (ref) == REG)
696890075Sobrien    {
696990075Sobrien      /* We have a pseudo which has been spilt onto the stack; there
697090075Sobrien	 are two cases here: the first where there is a simple
697190075Sobrien	 stack-slot replacement and a second where the stack-slot is
697290075Sobrien	 out of range, or is used as a subreg.  */
697390075Sobrien      if (reg_equiv_mem[REGNO (ref)])
697490075Sobrien	{
697590075Sobrien	  ref = reg_equiv_mem[REGNO (ref)];
697690075Sobrien	  base = find_replacement (&XEXP (ref, 0));
697790075Sobrien	}
697890075Sobrien      else
697990075Sobrien	/* The slot is out of range, or was dressed up in a SUBREG.  */
698090075Sobrien	base = reg_equiv_address[REGNO (ref)];
698190075Sobrien    }
698290075Sobrien  else
698390075Sobrien    base = find_replacement (&XEXP (ref, 0));
698490075Sobrien
698590075Sobrien  scratch = gen_rtx_REG (SImode, REGNO (operands[2]));
698690075Sobrien
698790075Sobrien  /* Handle the case where the address is too complex to be offset by 1.  */
698890075Sobrien  if (GET_CODE (base) == MINUS
698990075Sobrien      || (GET_CODE (base) == PLUS && GET_CODE (XEXP (base, 1)) != CONST_INT))
699090075Sobrien    {
699190075Sobrien      rtx base_plus = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
699290075Sobrien
699390075Sobrien      /* Be careful not to destroy OUTVAL.  */
699490075Sobrien      if (reg_overlap_mentioned_p (base_plus, outval))
699590075Sobrien	{
699690075Sobrien	  /* Updating base_plus might destroy outval, see if we can
699790075Sobrien	     swap the scratch and base_plus.  */
699890075Sobrien	  if (!reg_overlap_mentioned_p (scratch, outval))
699990075Sobrien	    {
700090075Sobrien	      rtx tmp = scratch;
700190075Sobrien	      scratch = base_plus;
700290075Sobrien	      base_plus = tmp;
700390075Sobrien	    }
700490075Sobrien	  else
700590075Sobrien	    {
700690075Sobrien	      rtx scratch_hi = gen_rtx_REG (HImode, REGNO (operands[2]));
700790075Sobrien
700890075Sobrien	      /* Be conservative and copy OUTVAL into the scratch now,
700990075Sobrien		 this should only be necessary if outval is a subreg
701090075Sobrien		 of something larger than a word.  */
701190075Sobrien	      /* XXX Might this clobber base?  I can't see how it can,
701290075Sobrien		 since scratch is known to overlap with OUTVAL, and
701390075Sobrien		 must be wider than a word.  */
701490075Sobrien	      emit_insn (gen_movhi (scratch_hi, outval));
701590075Sobrien	      outval = scratch_hi;
701690075Sobrien	    }
701790075Sobrien	}
701890075Sobrien
7019169689Skan      emit_set_insn (base_plus, base);
702090075Sobrien      base = base_plus;
702190075Sobrien    }
702290075Sobrien  else if (GET_CODE (base) == PLUS)
702390075Sobrien    {
702490075Sobrien      /* The addend must be CONST_INT, or we would have dealt with it above.  */
702590075Sobrien      HOST_WIDE_INT hi, lo;
702690075Sobrien
702790075Sobrien      offset += INTVAL (XEXP (base, 1));
702890075Sobrien      base = XEXP (base, 0);
702990075Sobrien
703090075Sobrien      /* Rework the address into a legal sequence of insns.  */
703190075Sobrien      /* Valid range for lo is -4095 -> 4095 */
703290075Sobrien      lo = (offset >= 0
703390075Sobrien	    ? (offset & 0xfff)
703490075Sobrien	    : -((-offset) & 0xfff));
703590075Sobrien
703690075Sobrien      /* Corner case, if lo is the max offset then we would be out of range
703790075Sobrien	 once we have added the additional 1 below, so bump the msb into the
703890075Sobrien	 pre-loading insn(s).  */
703990075Sobrien      if (lo == 4095)
704090075Sobrien	lo &= 0x7ff;
704190075Sobrien
704290075Sobrien      hi = ((((offset - lo) & (HOST_WIDE_INT) 0xffffffff)
704390075Sobrien	     ^ (HOST_WIDE_INT) 0x80000000)
704490075Sobrien	    - (HOST_WIDE_INT) 0x80000000);
704590075Sobrien
7046169689Skan      gcc_assert (hi + lo == offset);
704790075Sobrien
704890075Sobrien      if (hi != 0)
704990075Sobrien	{
705090075Sobrien	  rtx base_plus = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
705190075Sobrien
705290075Sobrien	  /* Be careful not to destroy OUTVAL.  */
705390075Sobrien	  if (reg_overlap_mentioned_p (base_plus, outval))
705490075Sobrien	    {
705590075Sobrien	      /* Updating base_plus might destroy outval, see if we
705690075Sobrien		 can swap the scratch and base_plus.  */
705790075Sobrien	      if (!reg_overlap_mentioned_p (scratch, outval))
705890075Sobrien		{
705990075Sobrien		  rtx tmp = scratch;
706090075Sobrien		  scratch = base_plus;
706190075Sobrien		  base_plus = tmp;
706290075Sobrien		}
706390075Sobrien	      else
706490075Sobrien		{
706590075Sobrien		  rtx scratch_hi = gen_rtx_REG (HImode, REGNO (operands[2]));
706690075Sobrien
706790075Sobrien		  /* Be conservative and copy outval into scratch now,
706890075Sobrien		     this should only be necessary if outval is a
706990075Sobrien		     subreg of something larger than a word.  */
707090075Sobrien		  /* XXX Might this clobber base?  I can't see how it
707190075Sobrien		     can, since scratch is known to overlap with
707290075Sobrien		     outval.  */
707390075Sobrien		  emit_insn (gen_movhi (scratch_hi, outval));
707490075Sobrien		  outval = scratch_hi;
707590075Sobrien		}
707690075Sobrien	    }
707790075Sobrien
707890075Sobrien	  /* Get the base address; addsi3 knows how to handle constants
707990075Sobrien	     that require more than one insn.  */
708090075Sobrien	  emit_insn (gen_addsi3 (base_plus, base, GEN_INT (hi)));
708190075Sobrien	  base = base_plus;
708290075Sobrien	  offset = lo;
708390075Sobrien	}
708490075Sobrien    }
708590075Sobrien
708690075Sobrien  if (BYTES_BIG_ENDIAN)
708790075Sobrien    {
7088169689Skan      emit_insn (gen_movqi (gen_rtx_MEM (QImode,
708990075Sobrien					 plus_constant (base, offset + 1)),
7090102780Skan			    gen_lowpart (QImode, outval)));
709190075Sobrien      emit_insn (gen_lshrsi3 (scratch,
709290075Sobrien			      gen_rtx_SUBREG (SImode, outval, 0),
709390075Sobrien			      GEN_INT (8)));
709490075Sobrien      emit_insn (gen_movqi (gen_rtx_MEM (QImode, plus_constant (base, offset)),
7095102780Skan			    gen_lowpart (QImode, scratch)));
709690075Sobrien    }
709790075Sobrien  else
709890075Sobrien    {
709990075Sobrien      emit_insn (gen_movqi (gen_rtx_MEM (QImode, plus_constant (base, offset)),
7100102780Skan			    gen_lowpart (QImode, outval)));
710190075Sobrien      emit_insn (gen_lshrsi3 (scratch,
710290075Sobrien			      gen_rtx_SUBREG (SImode, outval, 0),
710390075Sobrien			      GEN_INT (8)));
710490075Sobrien      emit_insn (gen_movqi (gen_rtx_MEM (QImode,
710590075Sobrien					 plus_constant (base, offset + 1)),
7106102780Skan			    gen_lowpart (QImode, scratch)));
710790075Sobrien    }
710890075Sobrien}
7109169689Skan
7110169689Skan/* Return true if a type must be passed in memory. For AAPCS, small aggregates
7111169689Skan   (padded to the size of a word) should be passed in a register.  */
7112169689Skan
7113169689Skanstatic bool
7114169689Skanarm_must_pass_in_stack (enum machine_mode mode, tree type)
7115169689Skan{
7116169689Skan  if (TARGET_AAPCS_BASED)
7117169689Skan    return must_pass_in_stack_var_size (mode, type);
7118169689Skan  else
7119169689Skan    return must_pass_in_stack_var_size_or_pad (mode, type);
7120169689Skan}
7121169689Skan
7122169689Skan
7123169689Skan/* For use by FUNCTION_ARG_PADDING (MODE, TYPE).
7124169689Skan   Return true if an argument passed on the stack should be padded upwards,
7125169689Skan   i.e. if the least-significant byte has useful data.
7126169689Skan   For legacy APCS ABIs we use the default.  For AAPCS based ABIs small
7127169689Skan   aggregate types are placed in the lowest memory address.  */
7128169689Skan
7129169689Skanbool
7130169689Skanarm_pad_arg_upward (enum machine_mode mode, tree type)
7131169689Skan{
7132169689Skan  if (!TARGET_AAPCS_BASED)
7133169689Skan    return DEFAULT_FUNCTION_ARG_PADDING(mode, type) == upward;
7134169689Skan
7135169689Skan  if (type && BYTES_BIG_ENDIAN && INTEGRAL_TYPE_P (type))
7136169689Skan    return false;
7137169689Skan
7138169689Skan  return true;
7139169689Skan}
7140169689Skan
7141169689Skan
7142169689Skan/* Similarly, for use by BLOCK_REG_PADDING (MODE, TYPE, FIRST).
7143169689Skan   For non-AAPCS, return !BYTES_BIG_ENDIAN if the least significant
7144169689Skan   byte of the register has useful data, and return the opposite if the
7145169689Skan   most significant byte does.
7146169689Skan   For AAPCS, small aggregates and small complex types are always padded
7147169689Skan   upwards.  */
7148169689Skan
7149169689Skanbool
7150169689Skanarm_pad_reg_upward (enum machine_mode mode ATTRIBUTE_UNUSED,
7151169689Skan                    tree type, int first ATTRIBUTE_UNUSED)
7152169689Skan{
7153169689Skan  if (TARGET_AAPCS_BASED
7154169689Skan      && BYTES_BIG_ENDIAN
7155169689Skan      && (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == COMPLEX_TYPE)
7156169689Skan      && int_size_in_bytes (type) <= 4)
7157169689Skan    return true;
7158169689Skan
7159169689Skan  /* Otherwise, use default padding.  */
7160169689Skan  return !BYTES_BIG_ENDIAN;
7161169689Skan}
7162169689Skan
716390075Sobrien
716490075Sobrien/* Print a symbolic form of X to the debug file, F.  */
716590075Sobrienstatic void
7166132718Skanarm_print_value (FILE *f, rtx x)
716790075Sobrien{
716890075Sobrien  switch (GET_CODE (x))
716990075Sobrien    {
717090075Sobrien    case CONST_INT:
717190075Sobrien      fprintf (f, HOST_WIDE_INT_PRINT_HEX, INTVAL (x));
717290075Sobrien      return;
717390075Sobrien
717490075Sobrien    case CONST_DOUBLE:
717590075Sobrien      fprintf (f, "<0x%lx,0x%lx>", (long)XWINT (x, 2), (long)XWINT (x, 3));
717690075Sobrien      return;
717790075Sobrien
7178132718Skan    case CONST_VECTOR:
7179132718Skan      {
7180132718Skan	int i;
7181132718Skan
7182132718Skan	fprintf (f, "<");
7183132718Skan	for (i = 0; i < CONST_VECTOR_NUNITS (x); i++)
7184132718Skan	  {
7185132718Skan	    fprintf (f, HOST_WIDE_INT_PRINT_HEX, INTVAL (CONST_VECTOR_ELT (x, i)));
7186132718Skan	    if (i < (CONST_VECTOR_NUNITS (x) - 1))
7187132718Skan	      fputc (',', f);
7188132718Skan	  }
7189132718Skan	fprintf (f, ">");
7190132718Skan      }
7191132718Skan      return;
7192132718Skan
719390075Sobrien    case CONST_STRING:
719490075Sobrien      fprintf (f, "\"%s\"", XSTR (x, 0));
719590075Sobrien      return;
719690075Sobrien
719790075Sobrien    case SYMBOL_REF:
719890075Sobrien      fprintf (f, "`%s'", XSTR (x, 0));
719990075Sobrien      return;
720090075Sobrien
720190075Sobrien    case LABEL_REF:
720290075Sobrien      fprintf (f, "L%d", INSN_UID (XEXP (x, 0)));
720390075Sobrien      return;
720490075Sobrien
720590075Sobrien    case CONST:
720690075Sobrien      arm_print_value (f, XEXP (x, 0));
720790075Sobrien      return;
720890075Sobrien
720990075Sobrien    case PLUS:
721090075Sobrien      arm_print_value (f, XEXP (x, 0));
721190075Sobrien      fprintf (f, "+");
721290075Sobrien      arm_print_value (f, XEXP (x, 1));
721390075Sobrien      return;
721490075Sobrien
721590075Sobrien    case PC:
721690075Sobrien      fprintf (f, "pc");
721790075Sobrien      return;
721890075Sobrien
721990075Sobrien    default:
722090075Sobrien      fprintf (f, "????");
722190075Sobrien      return;
722290075Sobrien    }
722390075Sobrien}
722490075Sobrien
722590075Sobrien/* Routines for manipulation of the constant pool.  */
722690075Sobrien
722790075Sobrien/* Arm instructions cannot load a large constant directly into a
722890075Sobrien   register; they have to come from a pc relative load.  The constant
722990075Sobrien   must therefore be placed in the addressable range of the pc
723090075Sobrien   relative load.  Depending on the precise pc relative load
723190075Sobrien   instruction the range is somewhere between 256 bytes and 4k.  This
723290075Sobrien   means that we often have to dump a constant inside a function, and
723390075Sobrien   generate code to branch around it.
723490075Sobrien
723590075Sobrien   It is important to minimize this, since the branches will slow
723690075Sobrien   things down and make the code larger.
723790075Sobrien
723890075Sobrien   Normally we can hide the table after an existing unconditional
723990075Sobrien   branch so that there is no interruption of the flow, but in the
724090075Sobrien   worst case the code looks like this:
724190075Sobrien
724290075Sobrien	ldr	rn, L1
724390075Sobrien	...
724490075Sobrien	b	L2
724590075Sobrien	align
724690075Sobrien	L1:	.long value
724790075Sobrien	L2:
724890075Sobrien	...
724990075Sobrien
725090075Sobrien	ldr	rn, L3
725190075Sobrien	...
725290075Sobrien	b	L4
725390075Sobrien	align
725490075Sobrien	L3:	.long value
725590075Sobrien	L4:
725690075Sobrien	...
725790075Sobrien
725890075Sobrien   We fix this by performing a scan after scheduling, which notices
725990075Sobrien   which instructions need to have their operands fetched from the
726090075Sobrien   constant table and builds the table.
726190075Sobrien
726290075Sobrien   The algorithm starts by building a table of all the constants that
726390075Sobrien   need fixing up and all the natural barriers in the function (places
726490075Sobrien   where a constant table can be dropped without breaking the flow).
726590075Sobrien   For each fixup we note how far the pc-relative replacement will be
726690075Sobrien   able to reach and the offset of the instruction into the function.
726790075Sobrien
726890075Sobrien   Having built the table we then group the fixes together to form
726990075Sobrien   tables that are as large as possible (subject to addressing
727090075Sobrien   constraints) and emit each table of constants after the last
727190075Sobrien   barrier that is within range of all the instructions in the group.
727290075Sobrien   If a group does not contain a barrier, then we forcibly create one
727390075Sobrien   by inserting a jump instruction into the flow.  Once the table has
727490075Sobrien   been inserted, the insns are then modified to reference the
727590075Sobrien   relevant entry in the pool.
727690075Sobrien
727790075Sobrien   Possible enhancements to the algorithm (not implemented) are:
727890075Sobrien
727990075Sobrien   1) For some processors and object formats, there may be benefit in
728090075Sobrien   aligning the pools to the start of cache lines; this alignment
728190075Sobrien   would need to be taken into account when calculating addressability
728290075Sobrien   of a pool.  */
728390075Sobrien
728490075Sobrien/* These typedefs are located at the start of this file, so that
728590075Sobrien   they can be used in the prototypes there.  This comment is to
728690075Sobrien   remind readers of that fact so that the following structures
728790075Sobrien   can be understood more easily.
728890075Sobrien
728990075Sobrien     typedef struct minipool_node    Mnode;
729090075Sobrien     typedef struct minipool_fixup   Mfix;  */
729190075Sobrien
729290075Sobrienstruct minipool_node
729390075Sobrien{
729490075Sobrien  /* Doubly linked chain of entries.  */
729590075Sobrien  Mnode * next;
729690075Sobrien  Mnode * prev;
729790075Sobrien  /* The maximum offset into the code that this entry can be placed.  While
729890075Sobrien     pushing fixes for forward references, all entries are sorted in order
729990075Sobrien     of increasing max_address.  */
730090075Sobrien  HOST_WIDE_INT max_address;
730190075Sobrien  /* Similarly for an entry inserted for a backwards ref.  */
730290075Sobrien  HOST_WIDE_INT min_address;
730390075Sobrien  /* The number of fixes referencing this entry.  This can become zero
730490075Sobrien     if we "unpush" an entry.  In this case we ignore the entry when we
730590075Sobrien     come to emit the code.  */
730690075Sobrien  int refcount;
730790075Sobrien  /* The offset from the start of the minipool.  */
730890075Sobrien  HOST_WIDE_INT offset;
730990075Sobrien  /* The value in table.  */
731090075Sobrien  rtx value;
731190075Sobrien  /* The mode of value.  */
731290075Sobrien  enum machine_mode mode;
7313132718Skan  /* The size of the value.  With iWMMXt enabled
7314132718Skan     sizes > 4 also imply an alignment of 8-bytes.  */
731590075Sobrien  int fix_size;
731690075Sobrien};
731790075Sobrien
731890075Sobrienstruct minipool_fixup
731990075Sobrien{
732090075Sobrien  Mfix *            next;
732190075Sobrien  rtx               insn;
732290075Sobrien  HOST_WIDE_INT     address;
732390075Sobrien  rtx *             loc;
732490075Sobrien  enum machine_mode mode;
732590075Sobrien  int               fix_size;
732690075Sobrien  rtx               value;
732790075Sobrien  Mnode *           minipool;
732890075Sobrien  HOST_WIDE_INT     forwards;
732990075Sobrien  HOST_WIDE_INT     backwards;
733090075Sobrien};
733190075Sobrien
733290075Sobrien/* Fixes less than a word need padding out to a word boundary.  */
733390075Sobrien#define MINIPOOL_FIX_SIZE(mode) \
733490075Sobrien  (GET_MODE_SIZE ((mode)) >= 4 ? GET_MODE_SIZE ((mode)) : 4)
733590075Sobrien
733690075Sobrienstatic Mnode *	minipool_vector_head;
733790075Sobrienstatic Mnode *	minipool_vector_tail;
733890075Sobrienstatic rtx	minipool_vector_label;
7339169689Skanstatic int	minipool_pad;
734090075Sobrien
734190075Sobrien/* The linked list of all minipool fixes required for this function.  */
734290075SobrienMfix * 		minipool_fix_head;
734390075SobrienMfix * 		minipool_fix_tail;
734490075Sobrien/* The fix entry for the current minipool, once it has been placed.  */
734590075SobrienMfix *		minipool_barrier;
734690075Sobrien
734790075Sobrien/* Determines if INSN is the start of a jump table.  Returns the end
734890075Sobrien   of the TABLE or NULL_RTX.  */
734990075Sobrienstatic rtx
7350132718Skanis_jump_table (rtx insn)
735190075Sobrien{
735290075Sobrien  rtx table;
7353169689Skan
735490075Sobrien  if (GET_CODE (insn) == JUMP_INSN
735590075Sobrien      && JUMP_LABEL (insn) != NULL
735690075Sobrien      && ((table = next_real_insn (JUMP_LABEL (insn)))
735790075Sobrien	  == next_real_insn (insn))
735890075Sobrien      && table != NULL
735990075Sobrien      && GET_CODE (table) == JUMP_INSN
736090075Sobrien      && (GET_CODE (PATTERN (table)) == ADDR_VEC
736190075Sobrien	  || GET_CODE (PATTERN (table)) == ADDR_DIFF_VEC))
736290075Sobrien    return table;
736390075Sobrien
736490075Sobrien  return NULL_RTX;
736590075Sobrien}
736690075Sobrien
736796263Sobrien#ifndef JUMP_TABLES_IN_TEXT_SECTION
736896263Sobrien#define JUMP_TABLES_IN_TEXT_SECTION 0
736996263Sobrien#endif
737096263Sobrien
737190075Sobrienstatic HOST_WIDE_INT
7372132718Skanget_jump_table_size (rtx insn)
737390075Sobrien{
737496263Sobrien  /* ADDR_VECs only take room if read-only data does into the text
737596263Sobrien     section.  */
7376169689Skan  if (JUMP_TABLES_IN_TEXT_SECTION || readonly_data_section == text_section)
737796263Sobrien    {
737896263Sobrien      rtx body = PATTERN (insn);
737996263Sobrien      int elt = GET_CODE (body) == ADDR_DIFF_VEC ? 1 : 0;
738090075Sobrien
738196263Sobrien      return GET_MODE_SIZE (GET_MODE (body)) * XVECLEN (body, elt);
738296263Sobrien    }
738396263Sobrien
738496263Sobrien  return 0;
738590075Sobrien}
738690075Sobrien
738790075Sobrien/* Move a minipool fix MP from its current location to before MAX_MP.
738890075Sobrien   If MAX_MP is NULL, then MP doesn't need moving, but the addressing
7389132718Skan   constraints may need updating.  */
739090075Sobrienstatic Mnode *
7391132718Skanmove_minipool_fix_forward_ref (Mnode *mp, Mnode *max_mp,
7392132718Skan			       HOST_WIDE_INT max_address)
739390075Sobrien{
7394169689Skan  /* The code below assumes these are different.  */
7395169689Skan  gcc_assert (mp != max_mp);
739690075Sobrien
739790075Sobrien  if (max_mp == NULL)
739890075Sobrien    {
739990075Sobrien      if (max_address < mp->max_address)
740090075Sobrien	mp->max_address = max_address;
740190075Sobrien    }
740290075Sobrien  else
740390075Sobrien    {
740490075Sobrien      if (max_address > max_mp->max_address - mp->fix_size)
740590075Sobrien	mp->max_address = max_mp->max_address - mp->fix_size;
740690075Sobrien      else
740790075Sobrien	mp->max_address = max_address;
740890075Sobrien
740990075Sobrien      /* Unlink MP from its current position.  Since max_mp is non-null,
741090075Sobrien       mp->prev must be non-null.  */
741190075Sobrien      mp->prev->next = mp->next;
741290075Sobrien      if (mp->next != NULL)
741390075Sobrien	mp->next->prev = mp->prev;
741490075Sobrien      else
741590075Sobrien	minipool_vector_tail = mp->prev;
741690075Sobrien
741790075Sobrien      /* Re-insert it before MAX_MP.  */
741890075Sobrien      mp->next = max_mp;
741990075Sobrien      mp->prev = max_mp->prev;
742090075Sobrien      max_mp->prev = mp;
7421169689Skan
742290075Sobrien      if (mp->prev != NULL)
742390075Sobrien	mp->prev->next = mp;
742490075Sobrien      else
742590075Sobrien	minipool_vector_head = mp;
742690075Sobrien    }
742790075Sobrien
742890075Sobrien  /* Save the new entry.  */
742990075Sobrien  max_mp = mp;
743090075Sobrien
743190075Sobrien  /* Scan over the preceding entries and adjust their addresses as
743290075Sobrien     required.  */
743390075Sobrien  while (mp->prev != NULL
743490075Sobrien	 && mp->prev->max_address > mp->max_address - mp->prev->fix_size)
743590075Sobrien    {
743690075Sobrien      mp->prev->max_address = mp->max_address - mp->prev->fix_size;
743790075Sobrien      mp = mp->prev;
743890075Sobrien    }
743990075Sobrien
744090075Sobrien  return max_mp;
744190075Sobrien}
744290075Sobrien
744390075Sobrien/* Add a constant to the minipool for a forward reference.  Returns the
744490075Sobrien   node added or NULL if the constant will not fit in this pool.  */
744590075Sobrienstatic Mnode *
7446132718Skanadd_minipool_forward_ref (Mfix *fix)
744790075Sobrien{
744890075Sobrien  /* If set, max_mp is the first pool_entry that has a lower
744990075Sobrien     constraint than the one we are trying to add.  */
745090075Sobrien  Mnode *       max_mp = NULL;
7451169689Skan  HOST_WIDE_INT max_address = fix->address + fix->forwards - minipool_pad;
745290075Sobrien  Mnode *       mp;
7453169689Skan
7454169689Skan  /* If the minipool starts before the end of FIX->INSN then this FIX
7455169689Skan     can not be placed into the current pool.  Furthermore, adding the
7456169689Skan     new constant pool entry may cause the pool to start FIX_SIZE bytes
7457169689Skan     earlier.  */
745890075Sobrien  if (minipool_vector_head &&
7459169689Skan      (fix->address + get_attr_length (fix->insn)
7460169689Skan       >= minipool_vector_head->max_address - fix->fix_size))
746190075Sobrien    return NULL;
746290075Sobrien
746390075Sobrien  /* Scan the pool to see if a constant with the same value has
746490075Sobrien     already been added.  While we are doing this, also note the
746590075Sobrien     location where we must insert the constant if it doesn't already
746690075Sobrien     exist.  */
746790075Sobrien  for (mp = minipool_vector_head; mp != NULL; mp = mp->next)
746890075Sobrien    {
746990075Sobrien      if (GET_CODE (fix->value) == GET_CODE (mp->value)
747090075Sobrien	  && fix->mode == mp->mode
747190075Sobrien	  && (GET_CODE (fix->value) != CODE_LABEL
747290075Sobrien	      || (CODE_LABEL_NUMBER (fix->value)
747390075Sobrien		  == CODE_LABEL_NUMBER (mp->value)))
747490075Sobrien	  && rtx_equal_p (fix->value, mp->value))
747590075Sobrien	{
747690075Sobrien	  /* More than one fix references this entry.  */
747790075Sobrien	  mp->refcount++;
747890075Sobrien	  return move_minipool_fix_forward_ref (mp, max_mp, max_address);
747990075Sobrien	}
748090075Sobrien
748190075Sobrien      /* Note the insertion point if necessary.  */
748290075Sobrien      if (max_mp == NULL
748390075Sobrien	  && mp->max_address > max_address)
748490075Sobrien	max_mp = mp;
7485132718Skan
7486132718Skan      /* If we are inserting an 8-bytes aligned quantity and
7487132718Skan	 we have not already found an insertion point, then
7488132718Skan	 make sure that all such 8-byte aligned quantities are
7489132718Skan	 placed at the start of the pool.  */
7490169689Skan      if (ARM_DOUBLEWORD_ALIGN
7491132718Skan	  && max_mp == NULL
7492132718Skan	  && fix->fix_size == 8
7493132718Skan	  && mp->fix_size != 8)
7494132718Skan	{
7495132718Skan	  max_mp = mp;
7496132718Skan	  max_address = mp->max_address;
7497132718Skan	}
749890075Sobrien    }
749990075Sobrien
750090075Sobrien  /* The value is not currently in the minipool, so we need to create
750190075Sobrien     a new entry for it.  If MAX_MP is NULL, the entry will be put on
750290075Sobrien     the end of the list since the placement is less constrained than
750390075Sobrien     any existing entry.  Otherwise, we insert the new fix before
7504132718Skan     MAX_MP and, if necessary, adjust the constraints on the other
750590075Sobrien     entries.  */
7506169689Skan  mp = XNEW (Mnode);
750790075Sobrien  mp->fix_size = fix->fix_size;
750890075Sobrien  mp->mode = fix->mode;
750990075Sobrien  mp->value = fix->value;
751090075Sobrien  mp->refcount = 1;
751190075Sobrien  /* Not yet required for a backwards ref.  */
751290075Sobrien  mp->min_address = -65536;
751390075Sobrien
751490075Sobrien  if (max_mp == NULL)
751590075Sobrien    {
751690075Sobrien      mp->max_address = max_address;
751790075Sobrien      mp->next = NULL;
751890075Sobrien      mp->prev = minipool_vector_tail;
751990075Sobrien
752090075Sobrien      if (mp->prev == NULL)
752190075Sobrien	{
752290075Sobrien	  minipool_vector_head = mp;
752390075Sobrien	  minipool_vector_label = gen_label_rtx ();
752490075Sobrien	}
752590075Sobrien      else
752690075Sobrien	mp->prev->next = mp;
752790075Sobrien
752890075Sobrien      minipool_vector_tail = mp;
752990075Sobrien    }
753090075Sobrien  else
753190075Sobrien    {
753290075Sobrien      if (max_address > max_mp->max_address - mp->fix_size)
753390075Sobrien	mp->max_address = max_mp->max_address - mp->fix_size;
753490075Sobrien      else
753590075Sobrien	mp->max_address = max_address;
753690075Sobrien
753790075Sobrien      mp->next = max_mp;
753890075Sobrien      mp->prev = max_mp->prev;
753990075Sobrien      max_mp->prev = mp;
754090075Sobrien      if (mp->prev != NULL)
754190075Sobrien	mp->prev->next = mp;
754290075Sobrien      else
754390075Sobrien	minipool_vector_head = mp;
754490075Sobrien    }
754590075Sobrien
754690075Sobrien  /* Save the new entry.  */
754790075Sobrien  max_mp = mp;
754890075Sobrien
754990075Sobrien  /* Scan over the preceding entries and adjust their addresses as
755090075Sobrien     required.  */
755190075Sobrien  while (mp->prev != NULL
755290075Sobrien	 && mp->prev->max_address > mp->max_address - mp->prev->fix_size)
755390075Sobrien    {
755490075Sobrien      mp->prev->max_address = mp->max_address - mp->prev->fix_size;
755590075Sobrien      mp = mp->prev;
755690075Sobrien    }
755790075Sobrien
755890075Sobrien  return max_mp;
755990075Sobrien}
756090075Sobrien
756190075Sobrienstatic Mnode *
7562132718Skanmove_minipool_fix_backward_ref (Mnode *mp, Mnode *min_mp,
7563132718Skan				HOST_WIDE_INT  min_address)
756490075Sobrien{
756590075Sobrien  HOST_WIDE_INT offset;
756690075Sobrien
7567169689Skan  /* The code below assumes these are different.  */
7568169689Skan  gcc_assert (mp != min_mp);
756990075Sobrien
757090075Sobrien  if (min_mp == NULL)
757190075Sobrien    {
757290075Sobrien      if (min_address > mp->min_address)
757390075Sobrien	mp->min_address = min_address;
757490075Sobrien    }
757590075Sobrien  else
757690075Sobrien    {
757790075Sobrien      /* We will adjust this below if it is too loose.  */
757890075Sobrien      mp->min_address = min_address;
757990075Sobrien
758090075Sobrien      /* Unlink MP from its current position.  Since min_mp is non-null,
758190075Sobrien	 mp->next must be non-null.  */
758290075Sobrien      mp->next->prev = mp->prev;
758390075Sobrien      if (mp->prev != NULL)
758490075Sobrien	mp->prev->next = mp->next;
758590075Sobrien      else
758690075Sobrien	minipool_vector_head = mp->next;
758790075Sobrien
758890075Sobrien      /* Reinsert it after MIN_MP.  */
758990075Sobrien      mp->prev = min_mp;
759090075Sobrien      mp->next = min_mp->next;
759190075Sobrien      min_mp->next = mp;
759290075Sobrien      if (mp->next != NULL)
759390075Sobrien	mp->next->prev = mp;
759490075Sobrien      else
759590075Sobrien	minipool_vector_tail = mp;
759690075Sobrien    }
759790075Sobrien
759890075Sobrien  min_mp = mp;
759990075Sobrien
760090075Sobrien  offset = 0;
760190075Sobrien  for (mp = minipool_vector_head; mp != NULL; mp = mp->next)
760290075Sobrien    {
760390075Sobrien      mp->offset = offset;
760490075Sobrien      if (mp->refcount > 0)
760590075Sobrien	offset += mp->fix_size;
760690075Sobrien
760790075Sobrien      if (mp->next && mp->next->min_address < mp->min_address + mp->fix_size)
760890075Sobrien	mp->next->min_address = mp->min_address + mp->fix_size;
760990075Sobrien    }
761090075Sobrien
761190075Sobrien  return min_mp;
7612169689Skan}
761390075Sobrien
761490075Sobrien/* Add a constant to the minipool for a backward reference.  Returns the
7615169689Skan   node added or NULL if the constant will not fit in this pool.
761690075Sobrien
761790075Sobrien   Note that the code for insertion for a backwards reference can be
761890075Sobrien   somewhat confusing because the calculated offsets for each fix do
761990075Sobrien   not take into account the size of the pool (which is still under
762090075Sobrien   construction.  */
762190075Sobrienstatic Mnode *
7622132718Skanadd_minipool_backward_ref (Mfix *fix)
762390075Sobrien{
762490075Sobrien  /* If set, min_mp is the last pool_entry that has a lower constraint
762590075Sobrien     than the one we are trying to add.  */
7626132718Skan  Mnode *min_mp = NULL;
762790075Sobrien  /* This can be negative, since it is only a constraint.  */
762890075Sobrien  HOST_WIDE_INT  min_address = fix->address - fix->backwards;
7629132718Skan  Mnode *mp;
763090075Sobrien
763190075Sobrien  /* If we can't reach the current pool from this insn, or if we can't
763290075Sobrien     insert this entry at the end of the pool without pushing other
763390075Sobrien     fixes out of range, then we don't try.  This ensures that we
763490075Sobrien     can't fail later on.  */
763590075Sobrien  if (min_address >= minipool_barrier->address
763690075Sobrien      || (minipool_vector_tail->min_address + fix->fix_size
763790075Sobrien	  >= minipool_barrier->address))
763890075Sobrien    return NULL;
763990075Sobrien
764090075Sobrien  /* Scan the pool to see if a constant with the same value has
764190075Sobrien     already been added.  While we are doing this, also note the
764290075Sobrien     location where we must insert the constant if it doesn't already
764390075Sobrien     exist.  */
764490075Sobrien  for (mp = minipool_vector_tail; mp != NULL; mp = mp->prev)
764590075Sobrien    {
764690075Sobrien      if (GET_CODE (fix->value) == GET_CODE (mp->value)
764790075Sobrien	  && fix->mode == mp->mode
764890075Sobrien	  && (GET_CODE (fix->value) != CODE_LABEL
764990075Sobrien	      || (CODE_LABEL_NUMBER (fix->value)
765090075Sobrien		  == CODE_LABEL_NUMBER (mp->value)))
765190075Sobrien	  && rtx_equal_p (fix->value, mp->value)
765290075Sobrien	  /* Check that there is enough slack to move this entry to the
765390075Sobrien	     end of the table (this is conservative).  */
7654169689Skan	  && (mp->max_address
7655169689Skan	      > (minipool_barrier->address
765690075Sobrien		 + minipool_vector_tail->offset
765790075Sobrien		 + minipool_vector_tail->fix_size)))
765890075Sobrien	{
765990075Sobrien	  mp->refcount++;
766090075Sobrien	  return move_minipool_fix_backward_ref (mp, min_mp, min_address);
766190075Sobrien	}
766290075Sobrien
766390075Sobrien      if (min_mp != NULL)
766490075Sobrien	mp->min_address += fix->fix_size;
766590075Sobrien      else
766690075Sobrien	{
766790075Sobrien	  /* Note the insertion point if necessary.  */
766890075Sobrien	  if (mp->min_address < min_address)
7669132718Skan	    {
7670132718Skan	      /* For now, we do not allow the insertion of 8-byte alignment
7671132718Skan		 requiring nodes anywhere but at the start of the pool.  */
7672169689Skan	      if (ARM_DOUBLEWORD_ALIGN
7673169689Skan		  && fix->fix_size == 8 && mp->fix_size != 8)
7674132718Skan		return NULL;
7675132718Skan	      else
7676132718Skan		min_mp = mp;
7677132718Skan	    }
767890075Sobrien	  else if (mp->max_address
767990075Sobrien		   < minipool_barrier->address + mp->offset + fix->fix_size)
768090075Sobrien	    {
768190075Sobrien	      /* Inserting before this entry would push the fix beyond
768290075Sobrien		 its maximum address (which can happen if we have
768390075Sobrien		 re-located a forwards fix); force the new fix to come
768490075Sobrien		 after it.  */
768590075Sobrien	      min_mp = mp;
768690075Sobrien	      min_address = mp->min_address + fix->fix_size;
768790075Sobrien	    }
7688132718Skan	  /* If we are inserting an 8-bytes aligned quantity and
7689132718Skan	     we have not already found an insertion point, then
7690132718Skan	     make sure that all such 8-byte aligned quantities are
7691132718Skan	     placed at the start of the pool.  */
7692169689Skan	  else if (ARM_DOUBLEWORD_ALIGN
7693132718Skan		   && min_mp == NULL
7694132718Skan		   && fix->fix_size == 8
7695132718Skan		   && mp->fix_size < 8)
7696132718Skan	    {
7697132718Skan	      min_mp = mp;
7698132718Skan	      min_address = mp->min_address + fix->fix_size;
7699132718Skan	    }
770090075Sobrien	}
770190075Sobrien    }
770290075Sobrien
770390075Sobrien  /* We need to create a new entry.  */
7704169689Skan  mp = XNEW (Mnode);
770590075Sobrien  mp->fix_size = fix->fix_size;
770690075Sobrien  mp->mode = fix->mode;
770790075Sobrien  mp->value = fix->value;
770890075Sobrien  mp->refcount = 1;
770990075Sobrien  mp->max_address = minipool_barrier->address + 65536;
771090075Sobrien
771190075Sobrien  mp->min_address = min_address;
771290075Sobrien
771390075Sobrien  if (min_mp == NULL)
771490075Sobrien    {
771590075Sobrien      mp->prev = NULL;
771690075Sobrien      mp->next = minipool_vector_head;
771790075Sobrien
771890075Sobrien      if (mp->next == NULL)
771990075Sobrien	{
772090075Sobrien	  minipool_vector_tail = mp;
772190075Sobrien	  minipool_vector_label = gen_label_rtx ();
772290075Sobrien	}
772390075Sobrien      else
772490075Sobrien	mp->next->prev = mp;
772590075Sobrien
772690075Sobrien      minipool_vector_head = mp;
772790075Sobrien    }
772890075Sobrien  else
772990075Sobrien    {
773090075Sobrien      mp->next = min_mp->next;
773190075Sobrien      mp->prev = min_mp;
773290075Sobrien      min_mp->next = mp;
7733169689Skan
773490075Sobrien      if (mp->next != NULL)
773590075Sobrien	mp->next->prev = mp;
773690075Sobrien      else
773790075Sobrien	minipool_vector_tail = mp;
773890075Sobrien    }
773990075Sobrien
774090075Sobrien  /* Save the new entry.  */
774190075Sobrien  min_mp = mp;
774290075Sobrien
774390075Sobrien  if (mp->prev)
774490075Sobrien    mp = mp->prev;
774590075Sobrien  else
774690075Sobrien    mp->offset = 0;
774790075Sobrien
774890075Sobrien  /* Scan over the following entries and adjust their offsets.  */
774990075Sobrien  while (mp->next != NULL)
775090075Sobrien    {
775190075Sobrien      if (mp->next->min_address < mp->min_address + mp->fix_size)
775290075Sobrien	mp->next->min_address = mp->min_address + mp->fix_size;
775390075Sobrien
775490075Sobrien      if (mp->refcount)
775590075Sobrien	mp->next->offset = mp->offset + mp->fix_size;
775690075Sobrien      else
775790075Sobrien	mp->next->offset = mp->offset;
775890075Sobrien
775990075Sobrien      mp = mp->next;
776090075Sobrien    }
776190075Sobrien
776290075Sobrien  return min_mp;
776390075Sobrien}
776490075Sobrien
776590075Sobrienstatic void
7766132718Skanassign_minipool_offsets (Mfix *barrier)
776790075Sobrien{
776890075Sobrien  HOST_WIDE_INT offset = 0;
7769132718Skan  Mnode *mp;
777090075Sobrien
777190075Sobrien  minipool_barrier = barrier;
777290075Sobrien
777390075Sobrien  for (mp = minipool_vector_head; mp != NULL; mp = mp->next)
777490075Sobrien    {
777590075Sobrien      mp->offset = offset;
7776169689Skan
777790075Sobrien      if (mp->refcount > 0)
777890075Sobrien	offset += mp->fix_size;
777990075Sobrien    }
778090075Sobrien}
778190075Sobrien
778290075Sobrien/* Output the literal table */
778390075Sobrienstatic void
7784132718Skandump_minipool (rtx scan)
778590075Sobrien{
778690075Sobrien  Mnode * mp;
778790075Sobrien  Mnode * nmp;
7788132718Skan  int align64 = 0;
778990075Sobrien
7790169689Skan  if (ARM_DOUBLEWORD_ALIGN)
7791132718Skan    for (mp = minipool_vector_head; mp != NULL; mp = mp->next)
7792132718Skan      if (mp->refcount > 0 && mp->fix_size == 8)
7793132718Skan	{
7794132718Skan	  align64 = 1;
7795132718Skan	  break;
7796132718Skan	}
7797132718Skan
7798169689Skan  if (dump_file)
7799169689Skan    fprintf (dump_file,
7800132718Skan	     ";; Emitting minipool after insn %u; address %ld; align %d (bytes)\n",
7801132718Skan	     INSN_UID (scan), (unsigned long) minipool_barrier->address, align64 ? 8 : 4);
780290075Sobrien
780390075Sobrien  scan = emit_label_after (gen_label_rtx (), scan);
7804132718Skan  scan = emit_insn_after (align64 ? gen_align_8 () : gen_align_4 (), scan);
780590075Sobrien  scan = emit_label_after (minipool_vector_label, scan);
780690075Sobrien
780790075Sobrien  for (mp = minipool_vector_head; mp != NULL; mp = nmp)
780890075Sobrien    {
780990075Sobrien      if (mp->refcount > 0)
781090075Sobrien	{
7811169689Skan	  if (dump_file)
781290075Sobrien	    {
7813169689Skan	      fprintf (dump_file,
781490075Sobrien		       ";;  Offset %u, min %ld, max %ld ",
781590075Sobrien		       (unsigned) mp->offset, (unsigned long) mp->min_address,
781690075Sobrien		       (unsigned long) mp->max_address);
7817169689Skan	      arm_print_value (dump_file, mp->value);
7818169689Skan	      fputc ('\n', dump_file);
781990075Sobrien	    }
782090075Sobrien
782190075Sobrien	  switch (mp->fix_size)
782290075Sobrien	    {
782390075Sobrien#ifdef HAVE_consttable_1
782490075Sobrien	    case 1:
782590075Sobrien	      scan = emit_insn_after (gen_consttable_1 (mp->value), scan);
782690075Sobrien	      break;
782790075Sobrien
782890075Sobrien#endif
782990075Sobrien#ifdef HAVE_consttable_2
783090075Sobrien	    case 2:
783190075Sobrien	      scan = emit_insn_after (gen_consttable_2 (mp->value), scan);
783290075Sobrien	      break;
783390075Sobrien
783490075Sobrien#endif
783590075Sobrien#ifdef HAVE_consttable_4
783690075Sobrien	    case 4:
783790075Sobrien	      scan = emit_insn_after (gen_consttable_4 (mp->value), scan);
783890075Sobrien	      break;
783990075Sobrien
784090075Sobrien#endif
784190075Sobrien#ifdef HAVE_consttable_8
784290075Sobrien	    case 8:
784390075Sobrien	      scan = emit_insn_after (gen_consttable_8 (mp->value), scan);
784490075Sobrien	      break;
784590075Sobrien
784690075Sobrien#endif
784790075Sobrien	    default:
7848169689Skan	      gcc_unreachable ();
784990075Sobrien	    }
785090075Sobrien	}
785190075Sobrien
785290075Sobrien      nmp = mp->next;
785390075Sobrien      free (mp);
785490075Sobrien    }
785590075Sobrien
785690075Sobrien  minipool_vector_head = minipool_vector_tail = NULL;
785790075Sobrien  scan = emit_insn_after (gen_consttable_end (), scan);
785890075Sobrien  scan = emit_barrier_after (scan);
785990075Sobrien}
786090075Sobrien
786190075Sobrien/* Return the cost of forcibly inserting a barrier after INSN.  */
786290075Sobrienstatic int
7863132718Skanarm_barrier_cost (rtx insn)
786490075Sobrien{
786590075Sobrien  /* Basing the location of the pool on the loop depth is preferable,
786690075Sobrien     but at the moment, the basic block information seems to be
786790075Sobrien     corrupt by this stage of the compilation.  */
786890075Sobrien  int base_cost = 50;
786990075Sobrien  rtx next = next_nonnote_insn (insn);
787090075Sobrien
787190075Sobrien  if (next != NULL && GET_CODE (next) == CODE_LABEL)
787290075Sobrien    base_cost -= 20;
787390075Sobrien
787490075Sobrien  switch (GET_CODE (insn))
787590075Sobrien    {
787690075Sobrien    case CODE_LABEL:
787790075Sobrien      /* It will always be better to place the table before the label, rather
787890075Sobrien	 than after it.  */
7879169689Skan      return 50;
788090075Sobrien
788190075Sobrien    case INSN:
788290075Sobrien    case CALL_INSN:
788390075Sobrien      return base_cost;
788490075Sobrien
788590075Sobrien    case JUMP_INSN:
788690075Sobrien      return base_cost - 10;
788790075Sobrien
788890075Sobrien    default:
788990075Sobrien      return base_cost + 10;
789090075Sobrien    }
789190075Sobrien}
789290075Sobrien
789390075Sobrien/* Find the best place in the insn stream in the range
789490075Sobrien   (FIX->address,MAX_ADDRESS) to forcibly insert a minipool barrier.
789590075Sobrien   Create the barrier by inserting a jump and add a new fix entry for
789690075Sobrien   it.  */
789790075Sobrienstatic Mfix *
7898132718Skancreate_fix_barrier (Mfix *fix, HOST_WIDE_INT max_address)
789990075Sobrien{
790090075Sobrien  HOST_WIDE_INT count = 0;
790190075Sobrien  rtx barrier;
790290075Sobrien  rtx from = fix->insn;
7903169689Skan  /* The instruction after which we will insert the jump.  */
7904169689Skan  rtx selected = NULL;
790590075Sobrien  int selected_cost;
7906169689Skan  /* The address at which the jump instruction will be placed.  */
790790075Sobrien  HOST_WIDE_INT selected_address;
790890075Sobrien  Mfix * new_fix;
790990075Sobrien  HOST_WIDE_INT max_count = max_address - fix->address;
791090075Sobrien  rtx label = gen_label_rtx ();
791190075Sobrien
791290075Sobrien  selected_cost = arm_barrier_cost (from);
791390075Sobrien  selected_address = fix->address;
791490075Sobrien
791590075Sobrien  while (from && count < max_count)
791690075Sobrien    {
791790075Sobrien      rtx tmp;
791890075Sobrien      int new_cost;
791990075Sobrien
792090075Sobrien      /* This code shouldn't have been called if there was a natural barrier
792190075Sobrien	 within range.  */
7922169689Skan      gcc_assert (GET_CODE (from) != BARRIER);
792390075Sobrien
792490075Sobrien      /* Count the length of this insn.  */
792590075Sobrien      count += get_attr_length (from);
792690075Sobrien
792790075Sobrien      /* If there is a jump table, add its length.  */
792890075Sobrien      tmp = is_jump_table (from);
792990075Sobrien      if (tmp != NULL)
793090075Sobrien	{
793190075Sobrien	  count += get_jump_table_size (tmp);
793290075Sobrien
793390075Sobrien	  /* Jump tables aren't in a basic block, so base the cost on
793490075Sobrien	     the dispatch insn.  If we select this location, we will
793590075Sobrien	     still put the pool after the table.  */
793690075Sobrien	  new_cost = arm_barrier_cost (from);
793790075Sobrien
7938169689Skan	  if (count < max_count
7939169689Skan	      && (!selected || new_cost <= selected_cost))
794090075Sobrien	    {
794190075Sobrien	      selected = tmp;
794290075Sobrien	      selected_cost = new_cost;
794390075Sobrien	      selected_address = fix->address + count;
794490075Sobrien	    }
794590075Sobrien
794690075Sobrien	  /* Continue after the dispatch table.  */
794790075Sobrien	  from = NEXT_INSN (tmp);
794890075Sobrien	  continue;
794990075Sobrien	}
795090075Sobrien
795190075Sobrien      new_cost = arm_barrier_cost (from);
7952169689Skan
7953169689Skan      if (count < max_count
7954169689Skan	  && (!selected || new_cost <= selected_cost))
795590075Sobrien	{
795690075Sobrien	  selected = from;
795790075Sobrien	  selected_cost = new_cost;
795890075Sobrien	  selected_address = fix->address + count;
795990075Sobrien	}
796090075Sobrien
796190075Sobrien      from = NEXT_INSN (from);
796290075Sobrien    }
796390075Sobrien
7964169689Skan  /* Make sure that we found a place to insert the jump.  */
7965169689Skan  gcc_assert (selected);
7966169689Skan
796790075Sobrien  /* Create a new JUMP_INSN that branches around a barrier.  */
796890075Sobrien  from = emit_jump_insn_after (gen_jump (label), selected);
796990075Sobrien  JUMP_LABEL (from) = label;
797090075Sobrien  barrier = emit_barrier_after (from);
797190075Sobrien  emit_label_after (label, barrier);
797290075Sobrien
797390075Sobrien  /* Create a minipool barrier entry for the new barrier.  */
797490075Sobrien  new_fix = (Mfix *) obstack_alloc (&minipool_obstack, sizeof (* new_fix));
797590075Sobrien  new_fix->insn = barrier;
797690075Sobrien  new_fix->address = selected_address;
797790075Sobrien  new_fix->next = fix->next;
797890075Sobrien  fix->next = new_fix;
797990075Sobrien
798090075Sobrien  return new_fix;
798190075Sobrien}
798290075Sobrien
798390075Sobrien/* Record that there is a natural barrier in the insn stream at
798490075Sobrien   ADDRESS.  */
798590075Sobrienstatic void
7986132718Skanpush_minipool_barrier (rtx insn, HOST_WIDE_INT address)
798790075Sobrien{
798890075Sobrien  Mfix * fix = (Mfix *) obstack_alloc (&minipool_obstack, sizeof (* fix));
798990075Sobrien
799090075Sobrien  fix->insn = insn;
799190075Sobrien  fix->address = address;
799290075Sobrien
799390075Sobrien  fix->next = NULL;
799490075Sobrien  if (minipool_fix_head != NULL)
799590075Sobrien    minipool_fix_tail->next = fix;
799690075Sobrien  else
799790075Sobrien    minipool_fix_head = fix;
799890075Sobrien
799990075Sobrien  minipool_fix_tail = fix;
800090075Sobrien}
800190075Sobrien
800290075Sobrien/* Record INSN, which will need fixing up to load a value from the
800390075Sobrien   minipool.  ADDRESS is the offset of the insn since the start of the
800490075Sobrien   function; LOC is a pointer to the part of the insn which requires
800590075Sobrien   fixing; VALUE is the constant that must be loaded, which is of type
800690075Sobrien   MODE.  */
800790075Sobrienstatic void
8008132718Skanpush_minipool_fix (rtx insn, HOST_WIDE_INT address, rtx *loc,
8009132718Skan		   enum machine_mode mode, rtx value)
801090075Sobrien{
801190075Sobrien  Mfix * fix = (Mfix *) obstack_alloc (&minipool_obstack, sizeof (* fix));
801290075Sobrien
801390075Sobrien#ifdef AOF_ASSEMBLER
8014132718Skan  /* PIC symbol references need to be converted into offsets into the
801590075Sobrien     based area.  */
801690075Sobrien  /* XXX This shouldn't be done here.  */
801790075Sobrien  if (flag_pic && GET_CODE (value) == SYMBOL_REF)
801890075Sobrien    value = aof_pic_entry (value);
801990075Sobrien#endif /* AOF_ASSEMBLER */
802090075Sobrien
802190075Sobrien  fix->insn = insn;
802290075Sobrien  fix->address = address;
802390075Sobrien  fix->loc = loc;
802490075Sobrien  fix->mode = mode;
802590075Sobrien  fix->fix_size = MINIPOOL_FIX_SIZE (mode);
802690075Sobrien  fix->value = value;
802790075Sobrien  fix->forwards = get_attr_pool_range (insn);
802890075Sobrien  fix->backwards = get_attr_neg_pool_range (insn);
802990075Sobrien  fix->minipool = NULL;
803090075Sobrien
803190075Sobrien  /* If an insn doesn't have a range defined for it, then it isn't
8032169689Skan     expecting to be reworked by this code.  Better to stop now than
803390075Sobrien     to generate duff assembly code.  */
8034169689Skan  gcc_assert (fix->forwards || fix->backwards);
803590075Sobrien
8036169689Skan  /* If an entry requires 8-byte alignment then assume all constant pools
8037169689Skan     require 4 bytes of padding.  Trying to do this later on a per-pool
8038169689Skan     basis is awkward because existing pool entries have to be modified.  */
8039169689Skan  if (ARM_DOUBLEWORD_ALIGN && fix->fix_size == 8)
8040169689Skan    minipool_pad = 4;
8041132718Skan
8042169689Skan  if (dump_file)
804390075Sobrien    {
8044169689Skan      fprintf (dump_file,
804590075Sobrien	       ";; %smode fixup for i%d; addr %lu, range (%ld,%ld): ",
804690075Sobrien	       GET_MODE_NAME (mode),
8047169689Skan	       INSN_UID (insn), (unsigned long) address,
804890075Sobrien	       -1 * (long)fix->backwards, (long)fix->forwards);
8049169689Skan      arm_print_value (dump_file, fix->value);
8050169689Skan      fprintf (dump_file, "\n");
805190075Sobrien    }
805290075Sobrien
805390075Sobrien  /* Add it to the chain of fixes.  */
805490075Sobrien  fix->next = NULL;
8055169689Skan
805690075Sobrien  if (minipool_fix_head != NULL)
805790075Sobrien    minipool_fix_tail->next = fix;
805890075Sobrien  else
805990075Sobrien    minipool_fix_head = fix;
806090075Sobrien
806190075Sobrien  minipool_fix_tail = fix;
806290075Sobrien}
806390075Sobrien
8064169689Skan/* Return the cost of synthesizing a 64-bit constant VAL inline.
8065169689Skan   Returns the number of insns needed, or 99 if we don't know how to
8066169689Skan   do it.  */
8067169689Skanint
8068169689Skanarm_const_double_inline_cost (rtx val)
8069169689Skan{
8070169689Skan  rtx lowpart, highpart;
8071169689Skan  enum machine_mode mode;
8072169689Skan
8073169689Skan  mode = GET_MODE (val);
8074169689Skan
8075169689Skan  if (mode == VOIDmode)
8076169689Skan    mode = DImode;
8077169689Skan
8078169689Skan  gcc_assert (GET_MODE_SIZE (mode) == 8);
8079169689Skan
8080169689Skan  lowpart = gen_lowpart (SImode, val);
8081169689Skan  highpart = gen_highpart_mode (SImode, mode, val);
8082169689Skan
8083169689Skan  gcc_assert (GET_CODE (lowpart) == CONST_INT);
8084169689Skan  gcc_assert (GET_CODE (highpart) == CONST_INT);
8085169689Skan
8086169689Skan  return (arm_gen_constant (SET, SImode, NULL_RTX, INTVAL (lowpart),
8087169689Skan			    NULL_RTX, NULL_RTX, 0, 0)
8088169689Skan	  + arm_gen_constant (SET, SImode, NULL_RTX, INTVAL (highpart),
8089169689Skan			      NULL_RTX, NULL_RTX, 0, 0));
8090169689Skan}
8091169689Skan
8092169689Skan/* Return true if it is worthwhile to split a 64-bit constant into two
8093169689Skan   32-bit operations.  This is the case if optimizing for size, or
8094169689Skan   if we have load delay slots, or if one 32-bit part can be done with
8095169689Skan   a single data operation.  */
8096169689Skanbool
8097169689Skanarm_const_double_by_parts (rtx val)
8098169689Skan{
8099169689Skan  enum machine_mode mode = GET_MODE (val);
8100169689Skan  rtx part;
8101169689Skan
8102169689Skan  if (optimize_size || arm_ld_sched)
8103169689Skan    return true;
8104169689Skan
8105169689Skan  if (mode == VOIDmode)
8106169689Skan    mode = DImode;
8107169689Skan
8108169689Skan  part = gen_highpart_mode (SImode, mode, 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  part = gen_lowpart (SImode, val);
8117169689Skan
8118169689Skan  gcc_assert (GET_CODE (part) == CONST_INT);
8119169689Skan
8120169689Skan  if (const_ok_for_arm (INTVAL (part))
8121169689Skan      || const_ok_for_arm (~INTVAL (part)))
8122169689Skan    return true;
8123169689Skan
8124169689Skan  return false;
8125169689Skan}
8126169689Skan
8127132718Skan/* Scan INSN and note any of its operands that need fixing.
8128132718Skan   If DO_PUSHES is false we do not actually push any of the fixups
8129169689Skan   needed.  The function returns TRUE if any fixups were needed/pushed.
8130132718Skan   This is used by arm_memory_load_p() which needs to know about loads
8131132718Skan   of constants that will be converted into minipool loads.  */
8132132718Skanstatic bool
8133132718Skannote_invalid_constants (rtx insn, HOST_WIDE_INT address, int do_pushes)
813490075Sobrien{
8135132718Skan  bool result = false;
813690075Sobrien  int opno;
813790075Sobrien
813890075Sobrien  extract_insn (insn);
813990075Sobrien
814090075Sobrien  if (!constrain_operands (1))
814190075Sobrien    fatal_insn_not_found (insn);
814290075Sobrien
8143132718Skan  if (recog_data.n_alternatives == 0)
8144132718Skan    return false;
8145132718Skan
8146169689Skan  /* Fill in recog_op_alt with information about the constraints of
8147169689Skan     this insn.  */
814890075Sobrien  preprocess_constraints ();
814990075Sobrien
815090075Sobrien  for (opno = 0; opno < recog_data.n_operands; opno++)
815190075Sobrien    {
815290075Sobrien      /* Things we need to fix can only occur in inputs.  */
815390075Sobrien      if (recog_data.operand_type[opno] != OP_IN)
815490075Sobrien	continue;
815590075Sobrien
815690075Sobrien      /* If this alternative is a memory reference, then any mention
815790075Sobrien	 of constants in this alternative is really to fool reload
815890075Sobrien	 into allowing us to accept one there.  We need to fix them up
815990075Sobrien	 now so that we output the right code.  */
816090075Sobrien      if (recog_op_alt[opno][which_alternative].memory_ok)
816190075Sobrien	{
816290075Sobrien	  rtx op = recog_data.operand[opno];
816390075Sobrien
816490075Sobrien	  if (CONSTANT_P (op))
8165132718Skan	    {
8166132718Skan	      if (do_pushes)
8167132718Skan		push_minipool_fix (insn, address, recog_data.operand_loc[opno],
8168132718Skan				   recog_data.operand_mode[opno], op);
8169132718Skan	      result = true;
8170132718Skan	    }
817190075Sobrien	  else if (GET_CODE (op) == MEM
817290075Sobrien		   && GET_CODE (XEXP (op, 0)) == SYMBOL_REF
817390075Sobrien		   && CONSTANT_POOL_ADDRESS_P (XEXP (op, 0)))
8174132718Skan	    {
8175132718Skan	      if (do_pushes)
8176132718Skan		{
8177132718Skan		  rtx cop = avoid_constant_pool_reference (op);
8178132718Skan
8179132718Skan		  /* Casting the address of something to a mode narrower
8180132718Skan		     than a word can cause avoid_constant_pool_reference()
8181132718Skan		     to return the pool reference itself.  That's no good to
8182169689Skan		     us here.  Lets just hope that we can use the
8183132718Skan		     constant pool value directly.  */
8184132718Skan		  if (op == cop)
8185132718Skan		    cop = get_pool_constant (XEXP (op, 0));
8186132718Skan
8187132718Skan		  push_minipool_fix (insn, address,
8188132718Skan				     recog_data.operand_loc[opno],
8189132718Skan				     recog_data.operand_mode[opno], cop);
8190132718Skan		}
8191132718Skan
8192132718Skan	      result = true;
8193132718Skan	    }
819490075Sobrien	}
819590075Sobrien    }
8196132718Skan
8197132718Skan  return result;
819890075Sobrien}
819990075Sobrien
8200132718Skan/* Gcc puts the pool in the wrong place for ARM, since we can only
8201132718Skan   load addresses a limited distance around the pc.  We do some
8202132718Skan   special munging to move the constant pool values to the correct
8203132718Skan   point in the code.  */
8204132718Skanstatic void
8205132718Skanarm_reorg (void)
820690075Sobrien{
820790075Sobrien  rtx insn;
820890075Sobrien  HOST_WIDE_INT address = 0;
820990075Sobrien  Mfix * fix;
821090075Sobrien
821190075Sobrien  minipool_fix_head = minipool_fix_tail = NULL;
821290075Sobrien
821390075Sobrien  /* The first insn must always be a note, or the code below won't
821490075Sobrien     scan it properly.  */
8215132718Skan  insn = get_insns ();
8216169689Skan  gcc_assert (GET_CODE (insn) == NOTE);
8217169689Skan  minipool_pad = 0;
821890075Sobrien
821990075Sobrien  /* Scan all the insns and record the operands that will need fixing.  */
8220132718Skan  for (insn = next_nonnote_insn (insn); insn; insn = next_nonnote_insn (insn))
822190075Sobrien    {
8222132718Skan      if (TARGET_CIRRUS_FIX_INVALID_INSNS
8223132718Skan          && (arm_cirrus_insn_p (insn)
8224132718Skan	      || GET_CODE (insn) == JUMP_INSN
8225132718Skan	      || arm_memory_load_p (insn)))
8226132718Skan	cirrus_reorg (insn);
8227132718Skan
822890075Sobrien      if (GET_CODE (insn) == BARRIER)
822990075Sobrien	push_minipool_barrier (insn, address);
8230132718Skan      else if (INSN_P (insn))
823190075Sobrien	{
823290075Sobrien	  rtx table;
823390075Sobrien
8234132718Skan	  note_invalid_constants (insn, address, true);
823590075Sobrien	  address += get_attr_length (insn);
823690075Sobrien
823790075Sobrien	  /* If the insn is a vector jump, add the size of the table
823890075Sobrien	     and skip the table.  */
823990075Sobrien	  if ((table = is_jump_table (insn)) != NULL)
824090075Sobrien	    {
824190075Sobrien	      address += get_jump_table_size (table);
824290075Sobrien	      insn = table;
824390075Sobrien	    }
824490075Sobrien	}
824590075Sobrien    }
824690075Sobrien
824790075Sobrien  fix = minipool_fix_head;
8248169689Skan
824990075Sobrien  /* Now scan the fixups and perform the required changes.  */
825090075Sobrien  while (fix)
825190075Sobrien    {
825290075Sobrien      Mfix * ftmp;
825390075Sobrien      Mfix * fdel;
825490075Sobrien      Mfix *  last_added_fix;
825590075Sobrien      Mfix * last_barrier = NULL;
825690075Sobrien      Mfix * this_fix;
825790075Sobrien
825890075Sobrien      /* Skip any further barriers before the next fix.  */
825990075Sobrien      while (fix && GET_CODE (fix->insn) == BARRIER)
826090075Sobrien	fix = fix->next;
826190075Sobrien
826290075Sobrien      /* No more fixes.  */
826390075Sobrien      if (fix == NULL)
826490075Sobrien	break;
826590075Sobrien
826690075Sobrien      last_added_fix = NULL;
826790075Sobrien
826890075Sobrien      for (ftmp = fix; ftmp; ftmp = ftmp->next)
826990075Sobrien	{
827090075Sobrien	  if (GET_CODE (ftmp->insn) == BARRIER)
827190075Sobrien	    {
827290075Sobrien	      if (ftmp->address >= minipool_vector_head->max_address)
827390075Sobrien		break;
827490075Sobrien
827590075Sobrien	      last_barrier = ftmp;
827690075Sobrien	    }
827790075Sobrien	  else if ((ftmp->minipool = add_minipool_forward_ref (ftmp)) == NULL)
827890075Sobrien	    break;
827990075Sobrien
828090075Sobrien	  last_added_fix = ftmp;  /* Keep track of the last fix added.  */
828190075Sobrien	}
828290075Sobrien
828390075Sobrien      /* If we found a barrier, drop back to that; any fixes that we
828490075Sobrien	 could have reached but come after the barrier will now go in
828590075Sobrien	 the next mini-pool.  */
828690075Sobrien      if (last_barrier != NULL)
828790075Sobrien	{
8288169689Skan	  /* Reduce the refcount for those fixes that won't go into this
828990075Sobrien	     pool after all.  */
829090075Sobrien	  for (fdel = last_barrier->next;
829190075Sobrien	       fdel && fdel != ftmp;
829290075Sobrien	       fdel = fdel->next)
829390075Sobrien	    {
829490075Sobrien	      fdel->minipool->refcount--;
829590075Sobrien	      fdel->minipool = NULL;
829690075Sobrien	    }
829790075Sobrien
829890075Sobrien	  ftmp = last_barrier;
829990075Sobrien	}
830090075Sobrien      else
830190075Sobrien        {
830290075Sobrien	  /* ftmp is first fix that we can't fit into this pool and
830390075Sobrien	     there no natural barriers that we could use.  Insert a
830490075Sobrien	     new barrier in the code somewhere between the previous
830590075Sobrien	     fix and this one, and arrange to jump around it.  */
830690075Sobrien	  HOST_WIDE_INT max_address;
830790075Sobrien
830890075Sobrien	  /* The last item on the list of fixes must be a barrier, so
830990075Sobrien	     we can never run off the end of the list of fixes without
831090075Sobrien	     last_barrier being set.  */
8311169689Skan	  gcc_assert (ftmp);
831290075Sobrien
831390075Sobrien	  max_address = minipool_vector_head->max_address;
831490075Sobrien	  /* Check that there isn't another fix that is in range that
831590075Sobrien	     we couldn't fit into this pool because the pool was
831690075Sobrien	     already too large: we need to put the pool before such an
8317169689Skan	     instruction.  The pool itself may come just after the
8318169689Skan	     fix because create_fix_barrier also allows space for a
8319169689Skan	     jump instruction.  */
832090075Sobrien	  if (ftmp->address < max_address)
8321169689Skan	    max_address = ftmp->address + 1;
832290075Sobrien
832390075Sobrien	  last_barrier = create_fix_barrier (last_added_fix, max_address);
832490075Sobrien	}
832590075Sobrien
832690075Sobrien      assign_minipool_offsets (last_barrier);
832790075Sobrien
832890075Sobrien      while (ftmp)
832990075Sobrien	{
833090075Sobrien	  if (GET_CODE (ftmp->insn) != BARRIER
833190075Sobrien	      && ((ftmp->minipool = add_minipool_backward_ref (ftmp))
833290075Sobrien		  == NULL))
833390075Sobrien	    break;
833490075Sobrien
833590075Sobrien	  ftmp = ftmp->next;
833690075Sobrien	}
833790075Sobrien
833890075Sobrien      /* Scan over the fixes we have identified for this pool, fixing them
833990075Sobrien	 up and adding the constants to the pool itself.  */
834090075Sobrien      for (this_fix = fix; this_fix && ftmp != this_fix;
834190075Sobrien	   this_fix = this_fix->next)
834290075Sobrien	if (GET_CODE (this_fix->insn) != BARRIER)
834390075Sobrien	  {
834490075Sobrien	    rtx addr
8345169689Skan	      = plus_constant (gen_rtx_LABEL_REF (VOIDmode,
834690075Sobrien						  minipool_vector_label),
834790075Sobrien			       this_fix->minipool->offset);
834890075Sobrien	    *this_fix->loc = gen_rtx_MEM (this_fix->mode, addr);
834990075Sobrien	  }
835090075Sobrien
835190075Sobrien      dump_minipool (last_barrier->insn);
835290075Sobrien      fix = ftmp;
835390075Sobrien    }
835490075Sobrien
835590075Sobrien  /* From now on we must synthesize any constants that we can't handle
835690075Sobrien     directly.  This can happen if the RTL gets split during final
835790075Sobrien     instruction generation.  */
835890075Sobrien  after_arm_reorg = 1;
835990075Sobrien
836090075Sobrien  /* Free the minipool memory.  */
836190075Sobrien  obstack_free (&minipool_obstack, minipool_startobj);
836290075Sobrien}
836390075Sobrien
836490075Sobrien/* Routines to output assembly language.  */
836590075Sobrien
836690075Sobrien/* If the rtx is the correct value then return the string of the number.
836790075Sobrien   In this way we can ensure that valid double constants are generated even
836890075Sobrien   when cross compiling.  */
836990075Sobrienconst char *
8370132718Skanfp_immediate_constant (rtx x)
837190075Sobrien{
837290075Sobrien  REAL_VALUE_TYPE r;
837390075Sobrien  int i;
8374169689Skan
8375169689Skan  if (!fp_consts_inited)
8376169689Skan    init_fp_table ();
8377169689Skan
837890075Sobrien  REAL_VALUE_FROM_CONST_DOUBLE (r, x);
837990075Sobrien  for (i = 0; i < 8; i++)
8380169689Skan    if (REAL_VALUES_EQUAL (r, values_fp[i]))
8381169689Skan      return strings_fp[i];
838290075Sobrien
8383169689Skan  gcc_unreachable ();
838490075Sobrien}
838590075Sobrien
838690075Sobrien/* As for fp_immediate_constant, but value is passed directly, not in rtx.  */
838790075Sobrienstatic const char *
8388132718Skanfp_const_from_val (REAL_VALUE_TYPE *r)
838990075Sobrien{
839090075Sobrien  int i;
839190075Sobrien
8392169689Skan  if (!fp_consts_inited)
8393169689Skan    init_fp_table ();
839490075Sobrien
839590075Sobrien  for (i = 0; i < 8; i++)
8396169689Skan    if (REAL_VALUES_EQUAL (*r, values_fp[i]))
8397169689Skan      return strings_fp[i];
839890075Sobrien
8399169689Skan  gcc_unreachable ();
840090075Sobrien}
840190075Sobrien
840290075Sobrien/* Output the operands of a LDM/STM instruction to STREAM.
840390075Sobrien   MASK is the ARM register set mask of which only bits 0-15 are important.
840490075Sobrien   REG is the base register, either the frame pointer or the stack pointer,
840590075Sobrien   INSTR is the possibly suffixed load or store instruction.  */
8406169689Skan
840790075Sobrienstatic void
8408169689Skanprint_multi_reg (FILE *stream, const char *instr, unsigned reg,
8409169689Skan		 unsigned long mask)
841090075Sobrien{
8411169689Skan  unsigned i;
8412169689Skan  bool not_first = FALSE;
841390075Sobrien
841490075Sobrien  fputc ('\t', stream);
841590075Sobrien  asm_fprintf (stream, instr, reg);
841690075Sobrien  fputs (", {", stream);
8417169689Skan
841890075Sobrien  for (i = 0; i <= LAST_ARM_REGNUM; i++)
841990075Sobrien    if (mask & (1 << i))
842090075Sobrien      {
842190075Sobrien	if (not_first)
842290075Sobrien	  fprintf (stream, ", ");
8423169689Skan
842490075Sobrien	asm_fprintf (stream, "%r", i);
842590075Sobrien	not_first = TRUE;
842690075Sobrien      }
842790075Sobrien
8428169689Skan  fprintf (stream, "}\n");
8429169689Skan}
8430132718Skan
8431169689Skan
8432169689Skan/* Output a FLDMX instruction to STREAM.
8433169689Skan   BASE if the register containing the address.
8434169689Skan   REG and COUNT specify the register range.
8435169689Skan   Extra registers may be added to avoid hardware bugs.  */
8436169689Skan
8437169689Skanstatic void
8438169689Skanarm_output_fldmx (FILE * stream, unsigned int base, int reg, int count)
8439169689Skan{
8440169689Skan  int i;
8441169689Skan
8442169689Skan  /* Workaround ARM10 VFPr1 bug.  */
8443169689Skan  if (count == 2 && !arm_arch6)
8444169689Skan    {
8445169689Skan      if (reg == 15)
8446169689Skan	reg--;
8447169689Skan      count++;
8448169689Skan    }
8449169689Skan
8450169689Skan  fputc ('\t', stream);
8451169689Skan  asm_fprintf (stream, "fldmfdx\t%r!, {", base);
8452169689Skan
8453169689Skan  for (i = reg; i < reg + count; i++)
8454169689Skan    {
8455169689Skan      if (i > reg)
8456169689Skan	fputs (", ", stream);
8457169689Skan      asm_fprintf (stream, "d%d", i);
8458169689Skan    }
8459169689Skan  fputs ("}\n", stream);
8460169689Skan
846190075Sobrien}
846290075Sobrien
8463169689Skan
8464169689Skan/* Output the assembly for a store multiple.  */
8465169689Skan
8466169689Skanconst char *
8467169689Skanvfp_output_fstmx (rtx * operands)
8468169689Skan{
8469169689Skan  char pattern[100];
8470169689Skan  int p;
8471169689Skan  int base;
8472169689Skan  int i;
8473169689Skan
8474169689Skan  strcpy (pattern, "fstmfdx\t%m0!, {%P1");
8475169689Skan  p = strlen (pattern);
8476169689Skan
8477169689Skan  gcc_assert (GET_CODE (operands[1]) == REG);
8478169689Skan
8479169689Skan  base = (REGNO (operands[1]) - FIRST_VFP_REGNUM) / 2;
8480169689Skan  for (i = 1; i < XVECLEN (operands[2], 0); i++)
8481169689Skan    {
8482169689Skan      p += sprintf (&pattern[p], ", d%d", base + i);
8483169689Skan    }
8484169689Skan  strcpy (&pattern[p], "}");
8485169689Skan
8486169689Skan  output_asm_insn (pattern, operands);
8487169689Skan  return "";
8488169689Skan}
8489169689Skan
8490169689Skan
8491169689Skan/* Emit RTL to save block of VFP register pairs to the stack.  Returns the
8492169689Skan   number of bytes pushed.  */
8493169689Skan
8494169689Skanstatic int
8495169689Skanvfp_emit_fstmx (int base_reg, int count)
8496169689Skan{
8497169689Skan  rtx par;
8498169689Skan  rtx dwarf;
8499169689Skan  rtx tmp, reg;
8500169689Skan  int i;
8501169689Skan
8502169689Skan  /* Workaround ARM10 VFPr1 bug.  Data corruption can occur when exactly two
8503169689Skan     register pairs are stored by a store multiple insn.  We avoid this
8504169689Skan     by pushing an extra pair.  */
8505169689Skan  if (count == 2 && !arm_arch6)
8506169689Skan    {
8507169689Skan      if (base_reg == LAST_VFP_REGNUM - 3)
8508169689Skan	base_reg -= 2;
8509169689Skan      count++;
8510169689Skan    }
8511169689Skan
8512169689Skan  /* ??? The frame layout is implementation defined.  We describe
8513169689Skan     standard format 1 (equivalent to a FSTMD insn and unused pad word).
8514169689Skan     We really need some way of representing the whole block so that the
8515169689Skan     unwinder can figure it out at runtime.  */
8516169689Skan  par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count));
8517169689Skan  dwarf = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (count + 1));
8518169689Skan
8519169689Skan  reg = gen_rtx_REG (DFmode, base_reg);
8520169689Skan  base_reg += 2;
8521169689Skan
8522169689Skan  XVECEXP (par, 0, 0)
8523169689Skan    = gen_rtx_SET (VOIDmode,
8524169689Skan		   gen_frame_mem (BLKmode,
8525169689Skan				  gen_rtx_PRE_DEC (BLKmode,
8526169689Skan						   stack_pointer_rtx)),
8527169689Skan		   gen_rtx_UNSPEC (BLKmode,
8528169689Skan				   gen_rtvec (1, reg),
8529169689Skan				   UNSPEC_PUSH_MULT));
8530169689Skan
8531169689Skan  tmp = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
8532169689Skan		     plus_constant (stack_pointer_rtx, -(count * 8 + 4)));
8533169689Skan  RTX_FRAME_RELATED_P (tmp) = 1;
8534169689Skan  XVECEXP (dwarf, 0, 0) = tmp;
8535169689Skan
8536169689Skan  tmp = gen_rtx_SET (VOIDmode,
8537169689Skan		     gen_frame_mem (DFmode, stack_pointer_rtx),
8538169689Skan		     reg);
8539169689Skan  RTX_FRAME_RELATED_P (tmp) = 1;
8540169689Skan  XVECEXP (dwarf, 0, 1) = tmp;
8541169689Skan
8542169689Skan  for (i = 1; i < count; i++)
8543169689Skan    {
8544169689Skan      reg = gen_rtx_REG (DFmode, base_reg);
8545169689Skan      base_reg += 2;
8546169689Skan      XVECEXP (par, 0, i) = gen_rtx_USE (VOIDmode, reg);
8547169689Skan
8548169689Skan      tmp = gen_rtx_SET (VOIDmode,
8549169689Skan			 gen_frame_mem (DFmode,
8550169689Skan					plus_constant (stack_pointer_rtx,
8551169689Skan						       i * 8)),
8552169689Skan			 reg);
8553169689Skan      RTX_FRAME_RELATED_P (tmp) = 1;
8554169689Skan      XVECEXP (dwarf, 0, i + 1) = tmp;
8555169689Skan    }
8556169689Skan
8557169689Skan  par = emit_insn (par);
8558169689Skan  REG_NOTES (par) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
8559169689Skan				       REG_NOTES (par));
8560169689Skan  RTX_FRAME_RELATED_P (par) = 1;
8561169689Skan
8562169689Skan  return count * 8 + 4;
8563169689Skan}
8564169689Skan
8565169689Skan
856690075Sobrien/* Output a 'call' insn.  */
856790075Sobrienconst char *
8568132718Skanoutput_call (rtx *operands)
856990075Sobrien{
8570169689Skan  gcc_assert (!arm_arch5); /* Patterns should call blx <reg> directly.  */
8571169689Skan
857290075Sobrien  /* Handle calls to lr using ip (which may be clobbered in subr anyway).  */
857390075Sobrien  if (REGNO (operands[0]) == LR_REGNUM)
857490075Sobrien    {
857590075Sobrien      operands[0] = gen_rtx_REG (SImode, IP_REGNUM);
857690075Sobrien      output_asm_insn ("mov%?\t%0, %|lr", operands);
857790075Sobrien    }
8578169689Skan
857990075Sobrien  output_asm_insn ("mov%?\t%|lr, %|pc", operands);
8580169689Skan
8581169689Skan  if (TARGET_INTERWORK || arm_arch4t)
858290075Sobrien    output_asm_insn ("bx%?\t%0", operands);
858390075Sobrien  else
858490075Sobrien    output_asm_insn ("mov%?\t%|pc, %0", operands);
8585169689Skan
858690075Sobrien  return "";
858790075Sobrien}
858890075Sobrien
858990075Sobrien/* Output a 'call' insn that is a reference in memory.  */
859090075Sobrienconst char *
8591132718Skanoutput_call_mem (rtx *operands)
859290075Sobrien{
8593169689Skan  if (TARGET_INTERWORK && !arm_arch5)
859490075Sobrien    {
859590075Sobrien      output_asm_insn ("ldr%?\t%|ip, %0", operands);
859690075Sobrien      output_asm_insn ("mov%?\t%|lr, %|pc", operands);
859790075Sobrien      output_asm_insn ("bx%?\t%|ip", operands);
859890075Sobrien    }
8599117395Skan  else if (regno_use_in (LR_REGNUM, operands[0]))
8600117395Skan    {
8601117395Skan      /* LR is used in the memory address.  We load the address in the
8602117395Skan	 first instruction.  It's safe to use IP as the target of the
8603117395Skan	 load since the call will kill it anyway.  */
8604117395Skan      output_asm_insn ("ldr%?\t%|ip, %0", operands);
8605169689Skan      if (arm_arch5)
8606169689Skan	output_asm_insn ("blx%?\t%|ip", operands);
8607169689Skan      else
8608169689Skan	{
8609169689Skan	  output_asm_insn ("mov%?\t%|lr, %|pc", operands);
8610169689Skan	  if (arm_arch4t)
8611169689Skan	    output_asm_insn ("bx%?\t%|ip", operands);
8612169689Skan	  else
8613169689Skan	    output_asm_insn ("mov%?\t%|pc, %|ip", operands);
8614169689Skan	}
8615117395Skan    }
861690075Sobrien  else
861790075Sobrien    {
861890075Sobrien      output_asm_insn ("mov%?\t%|lr, %|pc", operands);
861990075Sobrien      output_asm_insn ("ldr%?\t%|pc, %0", operands);
862090075Sobrien    }
862190075Sobrien
862290075Sobrien  return "";
862390075Sobrien}
862490075Sobrien
8625169689Skan
8626132718Skan/* Output a move from arm registers to an fpa registers.
8627132718Skan   OPERANDS[0] is an fpa register.
862890075Sobrien   OPERANDS[1] is the first registers of an arm register pair.  */
862990075Sobrienconst char *
8630132718Skanoutput_mov_long_double_fpa_from_arm (rtx *operands)
863190075Sobrien{
863290075Sobrien  int arm_reg0 = REGNO (operands[1]);
863390075Sobrien  rtx ops[3];
863490075Sobrien
8635169689Skan  gcc_assert (arm_reg0 != IP_REGNUM);
863690075Sobrien
863790075Sobrien  ops[0] = gen_rtx_REG (SImode, arm_reg0);
863890075Sobrien  ops[1] = gen_rtx_REG (SImode, 1 + arm_reg0);
863990075Sobrien  ops[2] = gen_rtx_REG (SImode, 2 + arm_reg0);
8640169689Skan
864190075Sobrien  output_asm_insn ("stm%?fd\t%|sp!, {%0, %1, %2}", ops);
864290075Sobrien  output_asm_insn ("ldf%?e\t%0, [%|sp], #12", operands);
8643169689Skan
864490075Sobrien  return "";
864590075Sobrien}
864690075Sobrien
8647132718Skan/* Output a move from an fpa register to arm registers.
864890075Sobrien   OPERANDS[0] is the first registers of an arm register pair.
8649132718Skan   OPERANDS[1] is an fpa register.  */
865090075Sobrienconst char *
8651132718Skanoutput_mov_long_double_arm_from_fpa (rtx *operands)
865290075Sobrien{
865390075Sobrien  int arm_reg0 = REGNO (operands[0]);
865490075Sobrien  rtx ops[3];
865590075Sobrien
8656169689Skan  gcc_assert (arm_reg0 != IP_REGNUM);
865790075Sobrien
865890075Sobrien  ops[0] = gen_rtx_REG (SImode, arm_reg0);
865990075Sobrien  ops[1] = gen_rtx_REG (SImode, 1 + arm_reg0);
866090075Sobrien  ops[2] = gen_rtx_REG (SImode, 2 + arm_reg0);
866190075Sobrien
866290075Sobrien  output_asm_insn ("stf%?e\t%1, [%|sp, #-12]!", operands);
866390075Sobrien  output_asm_insn ("ldm%?fd\t%|sp!, {%0, %1, %2}", ops);
866490075Sobrien  return "";
866590075Sobrien}
866690075Sobrien
866790075Sobrien/* Output a move from arm registers to arm registers of a long double
866890075Sobrien   OPERANDS[0] is the destination.
866990075Sobrien   OPERANDS[1] is the source.  */
867090075Sobrienconst char *
8671132718Skanoutput_mov_long_double_arm_from_arm (rtx *operands)
867290075Sobrien{
867390075Sobrien  /* We have to be careful here because the two might overlap.  */
867490075Sobrien  int dest_start = REGNO (operands[0]);
867590075Sobrien  int src_start = REGNO (operands[1]);
867690075Sobrien  rtx ops[2];
867790075Sobrien  int i;
867890075Sobrien
867990075Sobrien  if (dest_start < src_start)
868090075Sobrien    {
868190075Sobrien      for (i = 0; i < 3; i++)
868290075Sobrien	{
868390075Sobrien	  ops[0] = gen_rtx_REG (SImode, dest_start + i);
868490075Sobrien	  ops[1] = gen_rtx_REG (SImode, src_start + i);
868590075Sobrien	  output_asm_insn ("mov%?\t%0, %1", ops);
868690075Sobrien	}
868790075Sobrien    }
868890075Sobrien  else
868990075Sobrien    {
869090075Sobrien      for (i = 2; i >= 0; i--)
869190075Sobrien	{
869290075Sobrien	  ops[0] = gen_rtx_REG (SImode, dest_start + i);
869390075Sobrien	  ops[1] = gen_rtx_REG (SImode, src_start + i);
869490075Sobrien	  output_asm_insn ("mov%?\t%0, %1", ops);
869590075Sobrien	}
869690075Sobrien    }
869790075Sobrien
869890075Sobrien  return "";
869990075Sobrien}
870090075Sobrien
870190075Sobrien
8702132718Skan/* Output a move from arm registers to an fpa registers.
8703132718Skan   OPERANDS[0] is an fpa register.
870490075Sobrien   OPERANDS[1] is the first registers of an arm register pair.  */
870590075Sobrienconst char *
8706132718Skanoutput_mov_double_fpa_from_arm (rtx *operands)
870790075Sobrien{
870890075Sobrien  int arm_reg0 = REGNO (operands[1]);
870990075Sobrien  rtx ops[2];
871090075Sobrien
8711169689Skan  gcc_assert (arm_reg0 != IP_REGNUM);
8712169689Skan
871390075Sobrien  ops[0] = gen_rtx_REG (SImode, arm_reg0);
871490075Sobrien  ops[1] = gen_rtx_REG (SImode, 1 + arm_reg0);
871590075Sobrien  output_asm_insn ("stm%?fd\t%|sp!, {%0, %1}", ops);
871690075Sobrien  output_asm_insn ("ldf%?d\t%0, [%|sp], #8", operands);
871790075Sobrien  return "";
871890075Sobrien}
871990075Sobrien
8720132718Skan/* Output a move from an fpa register to arm registers.
872190075Sobrien   OPERANDS[0] is the first registers of an arm register pair.
8722132718Skan   OPERANDS[1] is an fpa register.  */
872390075Sobrienconst char *
8724132718Skanoutput_mov_double_arm_from_fpa (rtx *operands)
872590075Sobrien{
872690075Sobrien  int arm_reg0 = REGNO (operands[0]);
872790075Sobrien  rtx ops[2];
872890075Sobrien
8729169689Skan  gcc_assert (arm_reg0 != IP_REGNUM);
873090075Sobrien
873190075Sobrien  ops[0] = gen_rtx_REG (SImode, arm_reg0);
873290075Sobrien  ops[1] = gen_rtx_REG (SImode, 1 + arm_reg0);
873390075Sobrien  output_asm_insn ("stf%?d\t%1, [%|sp, #-8]!", operands);
873490075Sobrien  output_asm_insn ("ldm%?fd\t%|sp!, {%0, %1}", ops);
873590075Sobrien  return "";
873690075Sobrien}
873790075Sobrien
873890075Sobrien/* Output a move between double words.
873990075Sobrien   It must be REG<-REG, REG<-CONST_DOUBLE, REG<-CONST_INT, REG<-MEM
874090075Sobrien   or MEM<-REG and all MEMs must be offsettable addresses.  */
874190075Sobrienconst char *
8742132718Skanoutput_move_double (rtx *operands)
874390075Sobrien{
874490075Sobrien  enum rtx_code code0 = GET_CODE (operands[0]);
874590075Sobrien  enum rtx_code code1 = GET_CODE (operands[1]);
874690075Sobrien  rtx otherops[3];
874790075Sobrien
874890075Sobrien  if (code0 == REG)
874990075Sobrien    {
875090075Sobrien      int reg0 = REGNO (operands[0]);
875190075Sobrien
875290075Sobrien      otherops[0] = gen_rtx_REG (SImode, 1 + reg0);
875390075Sobrien
8754169689Skan      gcc_assert (code1 == MEM);  /* Constraints should ensure this.  */
8755169689Skan
8756169689Skan      switch (GET_CODE (XEXP (operands[1], 0)))
8757132718Skan	{
8758169689Skan	case REG:
8759169689Skan	  output_asm_insn ("ldm%?ia\t%m1, %M0", operands);
8760169689Skan	  break;
8761132718Skan
8762169689Skan	case PRE_INC:
8763169689Skan	  gcc_assert (TARGET_LDRD);
8764169689Skan	  output_asm_insn ("ldr%?d\t%0, [%m1, #8]!", operands);
8765169689Skan	  break;
8766132718Skan
8767169689Skan	case PRE_DEC:
8768169689Skan	  output_asm_insn ("ldm%?db\t%m1!, %M0", operands);
8769169689Skan	  break;
8770132718Skan
8771169689Skan	case POST_INC:
8772169689Skan	  output_asm_insn ("ldm%?ia\t%m1!, %M0", operands);
8773169689Skan	  break;
8774132718Skan
8775169689Skan	case POST_DEC:
8776169689Skan	  gcc_assert (TARGET_LDRD);
8777169689Skan	  output_asm_insn ("ldr%?d\t%0, [%m1], #-8", operands);
8778169689Skan	  break;
8779132718Skan
8780169689Skan	case PRE_MODIFY:
8781169689Skan	case POST_MODIFY:
8782169689Skan	  otherops[0] = operands[0];
8783169689Skan	  otherops[1] = XEXP (XEXP (XEXP (operands[1], 0), 1), 0);
8784169689Skan	  otherops[2] = XEXP (XEXP (XEXP (operands[1], 0), 1), 1);
8785132718Skan
8786169689Skan	  if (GET_CODE (XEXP (operands[1], 0)) == PRE_MODIFY)
8787169689Skan	    {
8788169689Skan	      if (reg_overlap_mentioned_p (otherops[0], otherops[2]))
8789132718Skan		{
8790169689Skan		  /* Registers overlap so split out the increment.  */
8791169689Skan		  output_asm_insn ("add%?\t%1, %1, %2", otherops);
8792169689Skan		  output_asm_insn ("ldr%?d\t%0, [%1] @split", otherops);
8793132718Skan		}
8794132718Skan	      else
8795132718Skan		{
8796169689Skan		  /* IWMMXT allows offsets larger than ldrd can handle,
8797169689Skan		     fix these up with a pair of ldr.  */
8798169689Skan		  if (GET_CODE (otherops[2]) == CONST_INT
8799169689Skan		      && (INTVAL(otherops[2]) <= -256
8800169689Skan			  || INTVAL(otherops[2]) >= 256))
8801169689Skan		    {
8802169689Skan		      output_asm_insn ("ldr%?\t%0, [%1, %2]!", otherops);
8803169689Skan		      otherops[0] = gen_rtx_REG (SImode, 1 + reg0);
8804169689Skan		      output_asm_insn ("ldr%?\t%0, [%1, #4]", otherops);
8805169689Skan		    }
8806169689Skan		  else
8807169689Skan		    output_asm_insn ("ldr%?d\t%0, [%1, %2]!", otherops);
8808132718Skan		}
8809169689Skan	    }
8810169689Skan	  else
8811169689Skan	    {
8812169689Skan	      /* IWMMXT allows offsets larger than ldrd can handle,
8813169689Skan		 fix these up with a pair of ldr.  */
8814169689Skan	      if (GET_CODE (otherops[2]) == CONST_INT
8815169689Skan		  && (INTVAL(otherops[2]) <= -256
8816169689Skan		      || INTVAL(otherops[2]) >= 256))
8817132718Skan		{
8818169689Skan		  otherops[0] = gen_rtx_REG (SImode, 1 + reg0);
8819169689Skan		  output_asm_insn ("ldr%?\t%0, [%1, #4]", otherops);
8820169689Skan		  otherops[0] = operands[0];
8821169689Skan		  output_asm_insn ("ldr%?\t%0, [%1], %2", otherops);
8822132718Skan		}
8823132718Skan	      else
8824169689Skan		/* We only allow constant increments, so this is safe.  */
8825169689Skan		output_asm_insn ("ldr%?d\t%0, [%1], %2", otherops);
8826132718Skan	    }
8827169689Skan	  break;
882890075Sobrien
8829169689Skan	case LABEL_REF:
8830169689Skan	case CONST:
8831169689Skan	  output_asm_insn ("adr%?\t%0, %1", operands);
8832169689Skan	  output_asm_insn ("ldm%?ia\t%0, %M0", operands);
8833169689Skan	  break;
8834169689Skan
8835169689Skan	default:
8836169689Skan	  if (arm_add_operand (XEXP (XEXP (operands[1], 0), 1),
8837169689Skan			       GET_MODE (XEXP (XEXP (operands[1], 0), 1))))
883890075Sobrien	    {
8839169689Skan	      otherops[0] = operands[0];
8840169689Skan	      otherops[1] = XEXP (XEXP (operands[1], 0), 0);
8841169689Skan	      otherops[2] = XEXP (XEXP (operands[1], 0), 1);
884290075Sobrien
8843169689Skan	      if (GET_CODE (XEXP (operands[1], 0)) == PLUS)
884490075Sobrien		{
8845169689Skan		  if (GET_CODE (otherops[2]) == CONST_INT)
884690075Sobrien		    {
8847169689Skan		      switch ((int) INTVAL (otherops[2]))
884890075Sobrien			{
8849169689Skan			case -8:
8850169689Skan			  output_asm_insn ("ldm%?db\t%1, %M0", otherops);
8851169689Skan			  return "";
8852169689Skan			case -4:
8853169689Skan			  output_asm_insn ("ldm%?da\t%1, %M0", otherops);
8854169689Skan			  return "";
8855169689Skan			case 4:
8856169689Skan			  output_asm_insn ("ldm%?ib\t%1, %M0", otherops);
8857169689Skan			  return "";
885890075Sobrien			}
8859169689Skan		    }
8860169689Skan		  if (TARGET_LDRD
8861169689Skan		      && (GET_CODE (otherops[2]) == REG
8862169689Skan			  || (GET_CODE (otherops[2]) == CONST_INT
8863169689Skan			      && INTVAL (otherops[2]) > -256
8864169689Skan			      && INTVAL (otherops[2]) < 256)))
8865169689Skan		    {
8866169689Skan		      if (reg_overlap_mentioned_p (otherops[0],
8867169689Skan						   otherops[2]))
8868169689Skan			{
8869169689Skan			  /* Swap base and index registers over to
8870169689Skan			     avoid a conflict.  */
8871169689Skan			  otherops[1] = XEXP (XEXP (operands[1], 0), 1);
8872169689Skan			  otherops[2] = XEXP (XEXP (operands[1], 0), 0);
8873169689Skan			}
8874169689Skan		      /* If both registers conflict, it will usually
8875169689Skan			 have been fixed by a splitter.  */
8876169689Skan		      if (reg_overlap_mentioned_p (otherops[0], otherops[2]))
8877169689Skan			{
8878169689Skan			  output_asm_insn ("add%?\t%1, %1, %2", otherops);
8879169689Skan			  output_asm_insn ("ldr%?d\t%0, [%1]",
8880169689Skan					   otherops);
8881169689Skan			}
888290075Sobrien		      else
8883169689Skan			output_asm_insn ("ldr%?d\t%0, [%1, %2]", otherops);
8884169689Skan		      return "";
888590075Sobrien		    }
8886169689Skan
8887169689Skan		  if (GET_CODE (otherops[2]) == CONST_INT)
888890075Sobrien		    {
8889169689Skan		      if (!(const_ok_for_arm (INTVAL (otherops[2]))))
8890169689Skan			output_asm_insn ("sub%?\t%0, %1, #%n2", otherops);
8891169689Skan		      else
8892169689Skan			output_asm_insn ("add%?\t%0, %1, %2", otherops);
889390075Sobrien		    }
889490075Sobrien		  else
8895169689Skan		    output_asm_insn ("add%?\t%0, %1, %2", otherops);
889690075Sobrien		}
8897169689Skan	      else
8898169689Skan		output_asm_insn ("sub%?\t%0, %1, %2", otherops);
8899169689Skan
8900169689Skan	      return "ldm%?ia\t%0, %M0";
890190075Sobrien	    }
8902169689Skan	  else
8903169689Skan	    {
8904169689Skan	      otherops[1] = adjust_address (operands[1], SImode, 4);
8905169689Skan	      /* Take care of overlapping base/data reg.  */
8906169689Skan	      if (reg_mentioned_p (operands[0], operands[1]))
8907169689Skan		{
8908169689Skan		  output_asm_insn ("ldr%?\t%0, %1", otherops);
8909169689Skan		  output_asm_insn ("ldr%?\t%0, %1", operands);
8910169689Skan		}
8911169689Skan	      else
8912169689Skan		{
8913169689Skan		  output_asm_insn ("ldr%?\t%0, %1", operands);
8914169689Skan		  output_asm_insn ("ldr%?\t%0, %1", otherops);
8915169689Skan		}
8916169689Skan	    }
891790075Sobrien	}
891890075Sobrien    }
8919169689Skan  else
892090075Sobrien    {
8921169689Skan      /* Constraints should ensure this.  */
8922169689Skan      gcc_assert (code0 == MEM && code1 == REG);
8923169689Skan      gcc_assert (REGNO (operands[1]) != IP_REGNUM);
892490075Sobrien
892590075Sobrien      switch (GET_CODE (XEXP (operands[0], 0)))
892690075Sobrien        {
892790075Sobrien	case REG:
892890075Sobrien	  output_asm_insn ("stm%?ia\t%m0, %M1", operands);
892990075Sobrien	  break;
893090075Sobrien
893190075Sobrien        case PRE_INC:
8932169689Skan	  gcc_assert (TARGET_LDRD);
8933169689Skan	  output_asm_insn ("str%?d\t%1, [%m0, #8]!", operands);
893490075Sobrien	  break;
893590075Sobrien
893690075Sobrien        case PRE_DEC:
893790075Sobrien	  output_asm_insn ("stm%?db\t%m0!, %M1", operands);
893890075Sobrien	  break;
893990075Sobrien
894090075Sobrien        case POST_INC:
894190075Sobrien	  output_asm_insn ("stm%?ia\t%m0!, %M1", operands);
894290075Sobrien	  break;
894390075Sobrien
894490075Sobrien        case POST_DEC:
8945169689Skan	  gcc_assert (TARGET_LDRD);
8946169689Skan	  output_asm_insn ("str%?d\t%1, [%m0], #-8", operands);
894790075Sobrien	  break;
894890075Sobrien
8949169689Skan	case PRE_MODIFY:
8950169689Skan	case POST_MODIFY:
8951169689Skan	  otherops[0] = operands[1];
8952169689Skan	  otherops[1] = XEXP (XEXP (XEXP (operands[0], 0), 1), 0);
8953169689Skan	  otherops[2] = XEXP (XEXP (XEXP (operands[0], 0), 1), 1);
8954169689Skan
8955169689Skan	  /* IWMMXT allows offsets larger than ldrd can handle,
8956169689Skan	     fix these up with a pair of ldr.  */
8957169689Skan	  if (GET_CODE (otherops[2]) == CONST_INT
8958169689Skan	      && (INTVAL(otherops[2]) <= -256
8959169689Skan		  || INTVAL(otherops[2]) >= 256))
8960169689Skan	    {
8961169689Skan	      rtx reg1;
8962169689Skan	      reg1 = gen_rtx_REG (SImode, 1 + REGNO (operands[1]));
8963169689Skan	      if (GET_CODE (XEXP (operands[0], 0)) == PRE_MODIFY)
8964169689Skan		{
8965169689Skan		  output_asm_insn ("ldr%?\t%0, [%1, %2]!", otherops);
8966169689Skan		  otherops[0] = reg1;
8967169689Skan		  output_asm_insn ("ldr%?\t%0, [%1, #4]", otherops);
8968169689Skan		}
8969169689Skan	      else
8970169689Skan		{
8971169689Skan		  otherops[0] = reg1;
8972169689Skan		  output_asm_insn ("ldr%?\t%0, [%1, #4]", otherops);
8973169689Skan		  otherops[0] = operands[1];
8974169689Skan		  output_asm_insn ("ldr%?\t%0, [%1], %2", otherops);
8975169689Skan		}
8976169689Skan	    }
8977169689Skan	  else if (GET_CODE (XEXP (operands[0], 0)) == PRE_MODIFY)
8978169689Skan	    output_asm_insn ("str%?d\t%0, [%1, %2]!", otherops);
8979169689Skan	  else
8980169689Skan	    output_asm_insn ("str%?d\t%0, [%1], %2", otherops);
8981169689Skan	  break;
8982169689Skan
898390075Sobrien	case PLUS:
8984169689Skan	  otherops[2] = XEXP (XEXP (operands[0], 0), 1);
8985169689Skan	  if (GET_CODE (otherops[2]) == CONST_INT)
898690075Sobrien	    {
8987132718Skan	      switch ((int) INTVAL (XEXP (XEXP (operands[0], 0), 1)))
898890075Sobrien		{
898990075Sobrien		case -8:
899090075Sobrien		  output_asm_insn ("stm%?db\t%m0, %M1", operands);
899190075Sobrien		  return "";
899290075Sobrien
899390075Sobrien		case -4:
899490075Sobrien		  output_asm_insn ("stm%?da\t%m0, %M1", operands);
899590075Sobrien		  return "";
899690075Sobrien
899790075Sobrien		case 4:
899890075Sobrien		  output_asm_insn ("stm%?ib\t%m0, %M1", operands);
899990075Sobrien		  return "";
900090075Sobrien		}
900190075Sobrien	    }
9002169689Skan	  if (TARGET_LDRD
9003169689Skan	      && (GET_CODE (otherops[2]) == REG
9004169689Skan		  || (GET_CODE (otherops[2]) == CONST_INT
9005169689Skan		      && INTVAL (otherops[2]) > -256
9006169689Skan		      && INTVAL (otherops[2]) < 256)))
9007169689Skan	    {
9008169689Skan	      otherops[0] = operands[1];
9009169689Skan	      otherops[1] = XEXP (XEXP (operands[0], 0), 0);
9010169689Skan	      output_asm_insn ("str%?d\t%0, [%1, %2]", otherops);
9011169689Skan	      return "";
9012169689Skan	    }
901390075Sobrien	  /* Fall through */
901490075Sobrien
901590075Sobrien        default:
9016117395Skan	  otherops[0] = adjust_address (operands[0], SImode, 4);
901790075Sobrien	  otherops[1] = gen_rtx_REG (SImode, 1 + REGNO (operands[1]));
901890075Sobrien	  output_asm_insn ("str%?\t%1, %0", operands);
901990075Sobrien	  output_asm_insn ("str%?\t%1, %0", otherops);
902090075Sobrien	}
902190075Sobrien    }
902290075Sobrien
902390075Sobrien  return "";
902490075Sobrien}
902590075Sobrien
902690075Sobrien/* Output an ADD r, s, #n where n may be too big for one instruction.
902790075Sobrien   If adding zero to one register, output nothing.  */
902890075Sobrienconst char *
9029132718Skanoutput_add_immediate (rtx *operands)
903090075Sobrien{
903190075Sobrien  HOST_WIDE_INT n = INTVAL (operands[2]);
903290075Sobrien
903390075Sobrien  if (n != 0 || REGNO (operands[0]) != REGNO (operands[1]))
903490075Sobrien    {
903590075Sobrien      if (n < 0)
903690075Sobrien	output_multi_immediate (operands,
903790075Sobrien				"sub%?\t%0, %1, %2", "sub%?\t%0, %0, %2", 2,
903890075Sobrien				-n);
903990075Sobrien      else
904090075Sobrien	output_multi_immediate (operands,
904190075Sobrien				"add%?\t%0, %1, %2", "add%?\t%0, %0, %2", 2,
904290075Sobrien				n);
904390075Sobrien    }
904490075Sobrien
904590075Sobrien  return "";
904690075Sobrien}
904790075Sobrien
904890075Sobrien/* Output a multiple immediate operation.
904990075Sobrien   OPERANDS is the vector of operands referred to in the output patterns.
905090075Sobrien   INSTR1 is the output pattern to use for the first constant.
905190075Sobrien   INSTR2 is the output pattern to use for subsequent constants.
905290075Sobrien   IMMED_OP is the index of the constant slot in OPERANDS.
905390075Sobrien   N is the constant value.  */
905490075Sobrienstatic const char *
9055132718Skanoutput_multi_immediate (rtx *operands, const char *instr1, const char *instr2,
9056132718Skan			int immed_op, HOST_WIDE_INT n)
905790075Sobrien{
905890075Sobrien#if HOST_BITS_PER_WIDE_INT > 32
905990075Sobrien  n &= 0xffffffff;
906090075Sobrien#endif
906190075Sobrien
906290075Sobrien  if (n == 0)
906390075Sobrien    {
906490075Sobrien      /* Quick and easy output.  */
906590075Sobrien      operands[immed_op] = const0_rtx;
906690075Sobrien      output_asm_insn (instr1, operands);
906790075Sobrien    }
906890075Sobrien  else
906990075Sobrien    {
907090075Sobrien      int i;
907190075Sobrien      const char * instr = instr1;
907290075Sobrien
907390075Sobrien      /* Note that n is never zero here (which would give no output).  */
907490075Sobrien      for (i = 0; i < 32; i += 2)
907590075Sobrien	{
907690075Sobrien	  if (n & (3 << i))
907790075Sobrien	    {
907890075Sobrien	      operands[immed_op] = GEN_INT (n & (255 << i));
907990075Sobrien	      output_asm_insn (instr, operands);
908090075Sobrien	      instr = instr2;
908190075Sobrien	      i += 6;
908290075Sobrien	    }
908390075Sobrien	}
908490075Sobrien    }
9085169689Skan
908690075Sobrien  return "";
908790075Sobrien}
908890075Sobrien
908990075Sobrien/* Return the appropriate ARM instruction for the operation code.
909090075Sobrien   The returned result should not be overwritten.  OP is the rtx of the
909190075Sobrien   operation.  SHIFT_FIRST_ARG is TRUE if the first argument of the operator
909290075Sobrien   was shifted.  */
909390075Sobrienconst char *
9094132718Skanarithmetic_instr (rtx op, int shift_first_arg)
909590075Sobrien{
909690075Sobrien  switch (GET_CODE (op))
909790075Sobrien    {
909890075Sobrien    case PLUS:
909990075Sobrien      return "add";
910090075Sobrien
910190075Sobrien    case MINUS:
910290075Sobrien      return shift_first_arg ? "rsb" : "sub";
910390075Sobrien
910490075Sobrien    case IOR:
910590075Sobrien      return "orr";
910690075Sobrien
910790075Sobrien    case XOR:
910890075Sobrien      return "eor";
910990075Sobrien
911090075Sobrien    case AND:
911190075Sobrien      return "and";
911290075Sobrien
911390075Sobrien    default:
9114169689Skan      gcc_unreachable ();
911590075Sobrien    }
911690075Sobrien}
911790075Sobrien
911890075Sobrien/* Ensure valid constant shifts and return the appropriate shift mnemonic
911990075Sobrien   for the operation code.  The returned result should not be overwritten.
912090075Sobrien   OP is the rtx code of the shift.
912190075Sobrien   On exit, *AMOUNTP will be -1 if the shift is by a register, or a constant
912290075Sobrien   shift.  */
912390075Sobrienstatic const char *
9124132718Skanshift_op (rtx op, HOST_WIDE_INT *amountp)
912590075Sobrien{
912690075Sobrien  const char * mnem;
912790075Sobrien  enum rtx_code code = GET_CODE (op);
912890075Sobrien
9129169689Skan  switch (GET_CODE (XEXP (op, 1)))
9130169689Skan    {
9131169689Skan    case REG:
9132169689Skan    case SUBREG:
9133169689Skan      *amountp = -1;
9134169689Skan      break;
913590075Sobrien
9136169689Skan    case CONST_INT:
9137169689Skan      *amountp = INTVAL (XEXP (op, 1));
9138169689Skan      break;
9139169689Skan
9140169689Skan    default:
9141169689Skan      gcc_unreachable ();
9142169689Skan    }
9143169689Skan
914490075Sobrien  switch (code)
914590075Sobrien    {
914690075Sobrien    case ASHIFT:
914790075Sobrien      mnem = "asl";
914890075Sobrien      break;
914990075Sobrien
915090075Sobrien    case ASHIFTRT:
915190075Sobrien      mnem = "asr";
915290075Sobrien      break;
915390075Sobrien
915490075Sobrien    case LSHIFTRT:
915590075Sobrien      mnem = "lsr";
915690075Sobrien      break;
915790075Sobrien
9158169689Skan    case ROTATE:
9159169689Skan      gcc_assert (*amountp != -1);
9160169689Skan      *amountp = 32 - *amountp;
9161169689Skan
9162169689Skan      /* Fall through.  */
9163169689Skan
916490075Sobrien    case ROTATERT:
916590075Sobrien      mnem = "ror";
916690075Sobrien      break;
916790075Sobrien
916890075Sobrien    case MULT:
916990075Sobrien      /* We never have to worry about the amount being other than a
917090075Sobrien	 power of 2, since this case can never be reloaded from a reg.  */
9171169689Skan      gcc_assert (*amountp != -1);
9172169689Skan      *amountp = int_log2 (*amountp);
917390075Sobrien      return "asl";
917490075Sobrien
917590075Sobrien    default:
9176169689Skan      gcc_unreachable ();
917790075Sobrien    }
917890075Sobrien
917990075Sobrien  if (*amountp != -1)
918090075Sobrien    {
918190075Sobrien      /* This is not 100% correct, but follows from the desire to merge
918290075Sobrien	 multiplication by a power of 2 with the recognizer for a
918390075Sobrien	 shift.  >=32 is not a valid shift for "asl", so we must try and
918490075Sobrien	 output a shift that produces the correct arithmetical result.
918590075Sobrien	 Using lsr #32 is identical except for the fact that the carry bit
9186169689Skan	 is not set correctly if we set the flags; but we never use the
918790075Sobrien	 carry bit from such an operation, so we can ignore that.  */
918890075Sobrien      if (code == ROTATERT)
918990075Sobrien	/* Rotate is just modulo 32.  */
919090075Sobrien	*amountp &= 31;
919190075Sobrien      else if (*amountp != (*amountp & 31))
919290075Sobrien	{
919390075Sobrien	  if (code == ASHIFT)
919490075Sobrien	    mnem = "lsr";
919590075Sobrien	  *amountp = 32;
919690075Sobrien	}
919790075Sobrien
919890075Sobrien      /* Shifts of 0 are no-ops.  */
919990075Sobrien      if (*amountp == 0)
920090075Sobrien	return NULL;
9201169689Skan    }
920290075Sobrien
920390075Sobrien  return mnem;
920490075Sobrien}
920590075Sobrien
920690075Sobrien/* Obtain the shift from the POWER of two.  */
920790075Sobrien
920890075Sobrienstatic HOST_WIDE_INT
9209132718Skanint_log2 (HOST_WIDE_INT power)
921090075Sobrien{
921190075Sobrien  HOST_WIDE_INT shift = 0;
921290075Sobrien
921390075Sobrien  while ((((HOST_WIDE_INT) 1 << shift) & power) == 0)
921490075Sobrien    {
9215169689Skan      gcc_assert (shift <= 31);
9216132718Skan      shift++;
921790075Sobrien    }
921890075Sobrien
921990075Sobrien  return shift;
922090075Sobrien}
922190075Sobrien
9222169689Skan/* Output a .ascii pseudo-op, keeping track of lengths.  This is
9223169689Skan   because /bin/as is horribly restrictive.  The judgement about
9224169689Skan   whether or not each character is 'printable' (and can be output as
9225169689Skan   is) or not (and must be printed with an octal escape) must be made
9226169689Skan   with reference to the *host* character set -- the situation is
9227169689Skan   similar to that discussed in the comments above pp_c_char in
9228169689Skan   c-pretty-print.c.  */
9229169689Skan
923090075Sobrien#define MAX_ASCII_LEN 51
923190075Sobrien
923290075Sobrienvoid
9233132718Skanoutput_ascii_pseudo_op (FILE *stream, const unsigned char *p, int len)
923490075Sobrien{
923590075Sobrien  int i;
923690075Sobrien  int len_so_far = 0;
923790075Sobrien
923890075Sobrien  fputs ("\t.ascii\t\"", stream);
9239169689Skan
924090075Sobrien  for (i = 0; i < len; i++)
924190075Sobrien    {
924290075Sobrien      int c = p[i];
924390075Sobrien
924490075Sobrien      if (len_so_far >= MAX_ASCII_LEN)
924590075Sobrien	{
924690075Sobrien	  fputs ("\"\n\t.ascii\t\"", stream);
924790075Sobrien	  len_so_far = 0;
924890075Sobrien	}
924990075Sobrien
9250169689Skan      if (ISPRINT (c))
925190075Sobrien	{
9252169689Skan	  if (c == '\\' || c == '\"')
925390075Sobrien	    {
9254169689Skan	      putc ('\\', stream);
925590075Sobrien	      len_so_far++;
925690075Sobrien	    }
9257169689Skan	  putc (c, stream);
9258169689Skan	  len_so_far++;
925990075Sobrien	}
9260169689Skan      else
9261169689Skan	{
9262169689Skan	  fprintf (stream, "\\%03o", c);
9263169689Skan	  len_so_far += 4;
9264169689Skan	}
926590075Sobrien    }
926690075Sobrien
926790075Sobrien  fputs ("\"\n", stream);
926890075Sobrien}
926990075Sobrien
9270169689Skan/* Compute the register save mask for registers 0 through 12
9271169689Skan   inclusive.  This code is used by arm_compute_save_reg_mask.  */
9272169689Skan
927390075Sobrienstatic unsigned long
9274132718Skanarm_compute_save_reg0_reg12_mask (void)
927590075Sobrien{
927690075Sobrien  unsigned long func_type = arm_current_func_type ();
9277169689Skan  unsigned long save_reg_mask = 0;
927890075Sobrien  unsigned int reg;
927990075Sobrien
928090075Sobrien  if (IS_INTERRUPT (func_type))
928190075Sobrien    {
928290075Sobrien      unsigned int max_reg;
928390075Sobrien      /* Interrupt functions must not corrupt any registers,
928490075Sobrien	 even call clobbered ones.  If this is a leaf function
928590075Sobrien	 we can just examine the registers used by the RTL, but
928690075Sobrien	 otherwise we have to assume that whatever function is
928790075Sobrien	 called might clobber anything, and so we have to save
928890075Sobrien	 all the call-clobbered registers as well.  */
928990075Sobrien      if (ARM_FUNC_TYPE (func_type) == ARM_FT_FIQ)
929090075Sobrien	/* FIQ handlers have registers r8 - r12 banked, so
929190075Sobrien	   we only need to check r0 - r7, Normal ISRs only
929290075Sobrien	   bank r14 and r15, so we must check up to r12.
929390075Sobrien	   r13 is the stack pointer which is always preserved,
929490075Sobrien	   so we do not need to consider it here.  */
929590075Sobrien	max_reg = 7;
929690075Sobrien      else
929790075Sobrien	max_reg = 12;
9298169689Skan
929990075Sobrien      for (reg = 0; reg <= max_reg; reg++)
930090075Sobrien	if (regs_ever_live[reg]
930190075Sobrien	    || (! current_function_is_leaf && call_used_regs [reg]))
930290075Sobrien	  save_reg_mask |= (1 << reg);
9303169689Skan
9304169689Skan      /* Also save the pic base register if necessary.  */
9305169689Skan      if (flag_pic
9306169689Skan	  && !TARGET_SINGLE_PIC_BASE
9307169689Skan	  && arm_pic_register != INVALID_REGNUM
9308169689Skan	  && current_function_uses_pic_offset_table)
9309169689Skan	save_reg_mask |= 1 << PIC_OFFSET_TABLE_REGNUM;
931090075Sobrien    }
931190075Sobrien  else
931290075Sobrien    {
931390075Sobrien      /* In the normal case we only need to save those registers
931490075Sobrien	 which are call saved and which are used by this function.  */
931590075Sobrien      for (reg = 0; reg <= 10; reg++)
931690075Sobrien	if (regs_ever_live[reg] && ! call_used_regs [reg])
931790075Sobrien	  save_reg_mask |= (1 << reg);
931890075Sobrien
931990075Sobrien      /* Handle the frame pointer as a special case.  */
932090075Sobrien      if (! TARGET_APCS_FRAME
932190075Sobrien	  && ! frame_pointer_needed
932290075Sobrien	  && regs_ever_live[HARD_FRAME_POINTER_REGNUM]
932390075Sobrien	  && ! call_used_regs[HARD_FRAME_POINTER_REGNUM])
932490075Sobrien	save_reg_mask |= 1 << HARD_FRAME_POINTER_REGNUM;
932590075Sobrien
932690075Sobrien      /* If we aren't loading the PIC register,
932790075Sobrien	 don't stack it even though it may be live.  */
932890075Sobrien      if (flag_pic
9329169689Skan	  && !TARGET_SINGLE_PIC_BASE
9330169689Skan	  && arm_pic_register != INVALID_REGNUM
9331169689Skan	  && (regs_ever_live[PIC_OFFSET_TABLE_REGNUM]
9332169689Skan	      || current_function_uses_pic_offset_table))
933390075Sobrien	save_reg_mask |= 1 << PIC_OFFSET_TABLE_REGNUM;
933490075Sobrien    }
933590075Sobrien
9336169689Skan  /* Save registers so the exception handler can modify them.  */
9337169689Skan  if (current_function_calls_eh_return)
9338169689Skan    {
9339169689Skan      unsigned int i;
9340169689Skan
9341169689Skan      for (i = 0; ; i++)
9342169689Skan	{
9343169689Skan	  reg = EH_RETURN_DATA_REGNO (i);
9344169689Skan	  if (reg == INVALID_REGNUM)
9345169689Skan	    break;
9346169689Skan	  save_reg_mask |= 1 << reg;
9347169689Skan	}
9348169689Skan    }
9349169689Skan
935090075Sobrien  return save_reg_mask;
935190075Sobrien}
935290075Sobrien
935390075Sobrien/* Compute a bit mask of which registers need to be
935490075Sobrien   saved on the stack for the current function.  */
935590075Sobrien
935690075Sobrienstatic unsigned long
9357132718Skanarm_compute_save_reg_mask (void)
935890075Sobrien{
935990075Sobrien  unsigned int save_reg_mask = 0;
936090075Sobrien  unsigned long func_type = arm_current_func_type ();
936190075Sobrien
936290075Sobrien  if (IS_NAKED (func_type))
936390075Sobrien    /* This should never really happen.  */
936490075Sobrien    return 0;
936590075Sobrien
936690075Sobrien  /* If we are creating a stack frame, then we must save the frame pointer,
936790075Sobrien     IP (which will hold the old stack pointer), LR and the PC.  */
936890075Sobrien  if (frame_pointer_needed)
936990075Sobrien    save_reg_mask |=
937090075Sobrien      (1 << ARM_HARD_FRAME_POINTER_REGNUM)
937190075Sobrien      | (1 << IP_REGNUM)
937290075Sobrien      | (1 << LR_REGNUM)
937390075Sobrien      | (1 << PC_REGNUM);
937490075Sobrien
937590075Sobrien  /* Volatile functions do not return, so there
937690075Sobrien     is no need to save any other registers.  */
937790075Sobrien  if (IS_VOLATILE (func_type))
937890075Sobrien    return save_reg_mask;
937990075Sobrien
938090075Sobrien  save_reg_mask |= arm_compute_save_reg0_reg12_mask ();
938190075Sobrien
938290075Sobrien  /* Decide if we need to save the link register.
938390075Sobrien     Interrupt routines have their own banked link register,
938490075Sobrien     so they never need to save it.
938596263Sobrien     Otherwise if we do not use the link register we do not need to save
938690075Sobrien     it.  If we are pushing other registers onto the stack however, we
938790075Sobrien     can save an instruction in the epilogue by pushing the link register
938890075Sobrien     now and then popping it back into the PC.  This incurs extra memory
9389132718Skan     accesses though, so we only do it when optimizing for size, and only
939090075Sobrien     if we know that we will not need a fancy return sequence.  */
939196263Sobrien  if (regs_ever_live [LR_REGNUM]
939290075Sobrien	  || (save_reg_mask
939390075Sobrien	      && optimize_size
9394169689Skan	      && ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL
9395169689Skan	      && !current_function_calls_eh_return))
939690075Sobrien    save_reg_mask |= 1 << LR_REGNUM;
939790075Sobrien
939890075Sobrien  if (cfun->machine->lr_save_eliminated)
939990075Sobrien    save_reg_mask &= ~ (1 << LR_REGNUM);
940090075Sobrien
9401132718Skan  if (TARGET_REALLY_IWMMXT
9402132718Skan      && ((bit_count (save_reg_mask)
9403132718Skan	   + ARM_NUM_INTS (current_function_pretend_args_size)) % 2) != 0)
9404132718Skan    {
9405132718Skan      unsigned int reg;
9406132718Skan
9407132718Skan      /* The total number of registers that are going to be pushed
9408132718Skan	 onto the stack is odd.  We need to ensure that the stack
9409132718Skan	 is 64-bit aligned before we start to save iWMMXt registers,
9410132718Skan	 and also before we start to create locals.  (A local variable
9411132718Skan	 might be a double or long long which we will load/store using
9412132718Skan	 an iWMMXt instruction).  Therefore we need to push another
9413132718Skan	 ARM register, so that the stack will be 64-bit aligned.  We
9414132718Skan	 try to avoid using the arg registers (r0 -r3) as they might be
9415132718Skan	 used to pass values in a tail call.  */
9416132718Skan      for (reg = 4; reg <= 12; reg++)
9417132718Skan	if ((save_reg_mask & (1 << reg)) == 0)
9418132718Skan	  break;
9419132718Skan
9420132718Skan      if (reg <= 12)
9421132718Skan	save_reg_mask |= (1 << reg);
9422132718Skan      else
9423132718Skan	{
9424132718Skan	  cfun->machine->sibcall_blocked = 1;
9425132718Skan	  save_reg_mask |= (1 << 3);
9426132718Skan	}
9427132718Skan    }
9428132718Skan
942990075Sobrien  return save_reg_mask;
943090075Sobrien}
943190075Sobrien
9432169689Skan
9433169689Skan/* Compute a bit mask of which registers need to be
9434169689Skan   saved on the stack for the current function.  */
9435169689Skanstatic unsigned long
9436169689Skanthumb_compute_save_reg_mask (void)
9437169689Skan{
9438169689Skan  unsigned long mask;
9439169689Skan  unsigned reg;
9440169689Skan
9441169689Skan  mask = 0;
9442169689Skan  for (reg = 0; reg < 12; reg ++)
9443169689Skan    if (regs_ever_live[reg] && !call_used_regs[reg])
9444169689Skan      mask |= 1 << reg;
9445169689Skan
9446169689Skan  if (flag_pic
9447169689Skan      && !TARGET_SINGLE_PIC_BASE
9448169689Skan      && arm_pic_register != INVALID_REGNUM
9449169689Skan      && current_function_uses_pic_offset_table)
9450169689Skan    mask |= 1 << PIC_OFFSET_TABLE_REGNUM;
9451169689Skan
9452169689Skan  /* See if we might need r11 for calls to _interwork_r11_call_via_rN().  */
9453169689Skan  if (!frame_pointer_needed && CALLER_INTERWORKING_SLOT_SIZE > 0)
9454169689Skan    mask |= 1 << ARM_HARD_FRAME_POINTER_REGNUM;
9455169689Skan
9456169689Skan  /* LR will also be pushed if any lo regs are pushed.  */
9457169689Skan  if (mask & 0xff || thumb_force_lr_save ())
9458169689Skan    mask |= (1 << LR_REGNUM);
9459169689Skan
9460169689Skan  /* Make sure we have a low work register if we need one.
9461169689Skan     We will need one if we are going to push a high register,
9462169689Skan     but we are not currently intending to push a low register.  */
9463169689Skan  if ((mask & 0xff) == 0
9464169689Skan      && ((mask & 0x0f00) || TARGET_BACKTRACE))
9465169689Skan    {
9466169689Skan      /* Use thumb_find_work_register to choose which register
9467169689Skan	 we will use.  If the register is live then we will
9468169689Skan	 have to push it.  Use LAST_LO_REGNUM as our fallback
9469169689Skan	 choice for the register to select.  */
9470169689Skan      reg = thumb_find_work_register (1 << LAST_LO_REGNUM);
9471169689Skan
9472169689Skan      if (! call_used_regs[reg])
9473169689Skan	mask |= 1 << reg;
9474169689Skan    }
9475169689Skan
9476169689Skan  return mask;
9477169689Skan}
9478169689Skan
9479169689Skan
9480169689Skan/* Return the number of bytes required to save VFP registers.  */
9481169689Skanstatic int
9482169689Skanarm_get_vfp_saved_size (void)
9483169689Skan{
9484169689Skan  unsigned int regno;
9485169689Skan  int count;
9486169689Skan  int saved;
9487169689Skan
9488169689Skan  saved = 0;
9489169689Skan  /* Space for saved VFP registers.  */
9490169689Skan  if (TARGET_HARD_FLOAT && TARGET_VFP)
9491169689Skan    {
9492169689Skan      count = 0;
9493169689Skan      for (regno = FIRST_VFP_REGNUM;
9494169689Skan	   regno < LAST_VFP_REGNUM;
9495169689Skan	   regno += 2)
9496169689Skan	{
9497169689Skan	  if ((!regs_ever_live[regno] || call_used_regs[regno])
9498169689Skan	      && (!regs_ever_live[regno + 1] || call_used_regs[regno + 1]))
9499169689Skan	    {
9500169689Skan	      if (count > 0)
9501169689Skan		{
9502169689Skan		  /* Workaround ARM10 VFPr1 bug.  */
9503169689Skan		  if (count == 2 && !arm_arch6)
9504169689Skan		    count++;
9505169689Skan		  saved += count * 8 + 4;
9506169689Skan		}
9507169689Skan	      count = 0;
9508169689Skan	    }
9509169689Skan	  else
9510169689Skan	    count++;
9511169689Skan	}
9512169689Skan      if (count > 0)
9513169689Skan	{
9514169689Skan	  if (count == 2 && !arm_arch6)
9515169689Skan	    count++;
9516169689Skan	  saved += count * 8 + 4;
9517169689Skan	}
9518169689Skan    }
9519169689Skan  return saved;
9520169689Skan}
9521169689Skan
9522169689Skan
9523132718Skan/* Generate a function exit sequence.  If REALLY_RETURN is false, then do
952490075Sobrien   everything bar the final return instruction.  */
952590075Sobrienconst char *
9526132718Skanoutput_return_instruction (rtx operand, int really_return, int reverse)
952790075Sobrien{
952890075Sobrien  char conditional[10];
952990075Sobrien  char instr[100];
9530169689Skan  unsigned reg;
953190075Sobrien  unsigned long live_regs_mask;
953290075Sobrien  unsigned long func_type;
9533169689Skan  arm_stack_offsets *offsets;
9534117395Skan
953590075Sobrien  func_type = arm_current_func_type ();
953690075Sobrien
953790075Sobrien  if (IS_NAKED (func_type))
953890075Sobrien    return "";
953990075Sobrien
954090075Sobrien  if (IS_VOLATILE (func_type) && TARGET_ABORT_NORETURN)
954190075Sobrien    {
9542132718Skan      /* If this function was declared non-returning, and we have
9543132718Skan	 found a tail call, then we have to trust that the called
9544132718Skan	 function won't return.  */
954590075Sobrien      if (really_return)
954690075Sobrien	{
954790075Sobrien	  rtx ops[2];
9548169689Skan
954990075Sobrien	  /* Otherwise, trap an attempted return by aborting.  */
955090075Sobrien	  ops[0] = operand;
9551169689Skan	  ops[1] = gen_rtx_SYMBOL_REF (Pmode, NEED_PLT_RELOC ? "abort(PLT)"
955290075Sobrien				       : "abort");
955390075Sobrien	  assemble_external_libcall (ops[1]);
955490075Sobrien	  output_asm_insn (reverse ? "bl%D0\t%a1" : "bl%d0\t%a1", ops);
955590075Sobrien	}
9556169689Skan
955790075Sobrien      return "";
955890075Sobrien    }
955990075Sobrien
9560169689Skan  gcc_assert (!current_function_calls_alloca || really_return);
956190075Sobrien
956290075Sobrien  sprintf (conditional, "%%?%%%c0", reverse ? 'D' : 'd');
956390075Sobrien
956490075Sobrien  return_used_this_function = 1;
956590075Sobrien
956690075Sobrien  live_regs_mask = arm_compute_save_reg_mask ();
956790075Sobrien
956896263Sobrien  if (live_regs_mask)
956990075Sobrien    {
957096263Sobrien      const char * return_reg;
957196263Sobrien
9572169689Skan      /* If we do not have any special requirements for function exit
9573169689Skan	 (e.g. interworking, or ISR) then we can load the return address
957496263Sobrien	 directly into the PC.  Otherwise we must load it into LR.  */
957596263Sobrien      if (really_return
957696263Sobrien	  && ! TARGET_INTERWORK)
957796263Sobrien	return_reg = reg_names[PC_REGNUM];
957890075Sobrien      else
957996263Sobrien	return_reg = reg_names[LR_REGNUM];
958096263Sobrien
958190075Sobrien      if ((live_regs_mask & (1 << IP_REGNUM)) == (1 << IP_REGNUM))
9582132718Skan	{
9583132718Skan	  /* There are three possible reasons for the IP register
9584132718Skan	     being saved.  1) a stack frame was created, in which case
9585132718Skan	     IP contains the old stack pointer, or 2) an ISR routine
9586132718Skan	     corrupted it, or 3) it was saved to align the stack on
9587132718Skan	     iWMMXt.  In case 1, restore IP into SP, otherwise just
9588132718Skan	     restore IP.  */
9589132718Skan	  if (frame_pointer_needed)
9590132718Skan	    {
9591132718Skan	      live_regs_mask &= ~ (1 << IP_REGNUM);
9592132718Skan	      live_regs_mask |=   (1 << SP_REGNUM);
9593132718Skan	    }
9594132718Skan	  else
9595169689Skan	    gcc_assert (IS_INTERRUPT (func_type) || TARGET_REALLY_IWMMXT);
9596132718Skan	}
959790075Sobrien
959896263Sobrien      /* On some ARM architectures it is faster to use LDR rather than
959996263Sobrien	 LDM to load a single register.  On other architectures, the
960096263Sobrien	 cost is the same.  In 26 bit mode, or for exception handlers,
960196263Sobrien	 we have to use LDM to load the PC so that the CPSR is also
960296263Sobrien	 restored.  */
960396263Sobrien      for (reg = 0; reg <= LAST_ARM_REGNUM; reg++)
9604169689Skan	if (live_regs_mask == (1U << reg))
9605169689Skan	  break;
9606169689Skan
960796263Sobrien      if (reg <= LAST_ARM_REGNUM
960896263Sobrien	  && (reg != LR_REGNUM
9609169689Skan	      || ! really_return
9610169689Skan	      || ! IS_INTERRUPT (func_type)))
961196263Sobrien	{
9612169689Skan	  sprintf (instr, "ldr%s\t%%|%s, [%%|sp], #4", conditional,
961396263Sobrien		   (reg == LR_REGNUM) ? return_reg : reg_names[reg]);
961496263Sobrien	}
961590075Sobrien      else
961690075Sobrien	{
961796263Sobrien	  char *p;
961896263Sobrien	  int first = 1;
961990075Sobrien
9620132718Skan	  /* Generate the load multiple instruction to restore the
9621132718Skan	     registers.  Note we can get here, even if
9622132718Skan	     frame_pointer_needed is true, but only if sp already
9623132718Skan	     points to the base of the saved core registers.  */
9624132718Skan	  if (live_regs_mask & (1 << SP_REGNUM))
9625132718Skan	    {
9626169689Skan	      unsigned HOST_WIDE_INT stack_adjust;
9627132718Skan
9628169689Skan	      offsets = arm_get_frame_offsets ();
9629169689Skan	      stack_adjust = offsets->outgoing_args - offsets->saved_regs;
9630169689Skan	      gcc_assert (stack_adjust == 0 || stack_adjust == 4);
9631169689Skan
9632132718Skan	      if (stack_adjust && arm_arch5)
9633132718Skan		sprintf (instr, "ldm%sib\t%%|sp, {", conditional);
9634132718Skan	      else
9635132718Skan		{
9636169689Skan		  /* If we can't use ldmib (SA110 bug),
9637169689Skan		     then try to pop r3 instead.  */
9638132718Skan		  if (stack_adjust)
9639132718Skan		    live_regs_mask |= 1 << 3;
9640132718Skan		  sprintf (instr, "ldm%sfd\t%%|sp, {", conditional);
9641132718Skan		}
9642132718Skan	    }
964390075Sobrien	  else
964496263Sobrien	    sprintf (instr, "ldm%sfd\t%%|sp!, {", conditional);
964590075Sobrien
964696263Sobrien	  p = instr + strlen (instr);
964790075Sobrien
964896263Sobrien	  for (reg = 0; reg <= SP_REGNUM; reg++)
964996263Sobrien	    if (live_regs_mask & (1 << reg))
965096263Sobrien	      {
965196263Sobrien		int l = strlen (reg_names[reg]);
965290075Sobrien
965396263Sobrien		if (first)
965496263Sobrien		  first = 0;
965596263Sobrien		else
965696263Sobrien		  {
965796263Sobrien		    memcpy (p, ", ", 2);
965896263Sobrien		    p += 2;
965996263Sobrien		  }
966090075Sobrien
966196263Sobrien		memcpy (p, "%|", 2);
966296263Sobrien		memcpy (p + 2, reg_names[reg], l);
966396263Sobrien		p += l + 2;
966496263Sobrien	      }
9665169689Skan
966696263Sobrien	  if (live_regs_mask & (1 << LR_REGNUM))
966796263Sobrien	    {
9668132718Skan	      sprintf (p, "%s%%|%s}", first ? "" : ", ", return_reg);
9669169689Skan	      /* If returning from an interrupt, restore the CPSR.  */
9670169689Skan	      if (IS_INTERRUPT (func_type))
9671132718Skan		strcat (p, "^");
967290075Sobrien	    }
967396263Sobrien	  else
967496263Sobrien	    strcpy (p, "}");
967590075Sobrien	}
967696263Sobrien
967796263Sobrien      output_asm_insn (instr, & operand);
967896263Sobrien
967996263Sobrien      /* See if we need to generate an extra instruction to
968096263Sobrien	 perform the actual function return.  */
968196263Sobrien      if (really_return
968296263Sobrien	  && func_type != ARM_FT_INTERWORKED
968396263Sobrien	  && (live_regs_mask & (1 << LR_REGNUM)) != 0)
968496263Sobrien	{
968596263Sobrien	  /* The return has already been handled
968696263Sobrien	     by loading the LR into the PC.  */
968796263Sobrien	  really_return = 0;
968896263Sobrien	}
968990075Sobrien    }
9690117395Skan
969196263Sobrien  if (really_return)
969290075Sobrien    {
969390075Sobrien      switch ((int) ARM_FUNC_TYPE (func_type))
969490075Sobrien	{
969590075Sobrien	case ARM_FT_ISR:
969690075Sobrien	case ARM_FT_FIQ:
969790075Sobrien	  sprintf (instr, "sub%ss\t%%|pc, %%|lr, #4", conditional);
969890075Sobrien	  break;
969990075Sobrien
970090075Sobrien	case ARM_FT_INTERWORKED:
970190075Sobrien	  sprintf (instr, "bx%s\t%%|lr", conditional);
970290075Sobrien	  break;
970390075Sobrien
970490075Sobrien	case ARM_FT_EXCEPTION:
970590075Sobrien	  sprintf (instr, "mov%ss\t%%|pc, %%|lr", conditional);
970690075Sobrien	  break;
970790075Sobrien
970890075Sobrien	default:
9709169689Skan	  /* Use bx if it's available.  */
9710169689Skan	  if (arm_arch5 || arm_arch4t)
9711169689Skan	    sprintf (instr, "bx%s\t%%|lr", conditional);
971296263Sobrien	  else
9713169689Skan	    sprintf (instr, "mov%s\t%%|pc, %%|lr", conditional);
971490075Sobrien	  break;
971590075Sobrien	}
971696263Sobrien
971796263Sobrien      output_asm_insn (instr, & operand);
971890075Sobrien    }
971990075Sobrien
972090075Sobrien  return "";
972190075Sobrien}
972290075Sobrien
972390075Sobrien/* Write the function name into the code section, directly preceding
972490075Sobrien   the function prologue.
972590075Sobrien
972690075Sobrien   Code will be output similar to this:
972790075Sobrien     t0
972890075Sobrien	 .ascii "arm_poke_function_name", 0
972990075Sobrien	 .align
973090075Sobrien     t1
973190075Sobrien	 .word 0xff000000 + (t1 - t0)
973290075Sobrien     arm_poke_function_name
973390075Sobrien	 mov     ip, sp
973490075Sobrien	 stmfd   sp!, {fp, ip, lr, pc}
973590075Sobrien	 sub     fp, ip, #4
973690075Sobrien
973790075Sobrien   When performing a stack backtrace, code can inspect the value
973890075Sobrien   of 'pc' stored at 'fp' + 0.  If the trace function then looks
973990075Sobrien   at location pc - 12 and the top 8 bits are set, then we know
974090075Sobrien   that there is a function name embedded immediately preceding this
974190075Sobrien   location and has length ((pc[-3]) & 0xff000000).
974290075Sobrien
974390075Sobrien   We assume that pc is declared as a pointer to an unsigned long.
974490075Sobrien
974590075Sobrien   It is of no benefit to output the function name if we are assembling
974690075Sobrien   a leaf function.  These function types will not contain a stack
974790075Sobrien   backtrace structure, therefore it is not possible to determine the
974890075Sobrien   function name.  */
974990075Sobrienvoid
9750132718Skanarm_poke_function_name (FILE *stream, const char *name)
975190075Sobrien{
975290075Sobrien  unsigned long alignlength;
975390075Sobrien  unsigned long length;
975490075Sobrien  rtx           x;
975590075Sobrien
975690075Sobrien  length      = strlen (name) + 1;
9757132718Skan  alignlength = ROUND_UP_WORD (length);
9758169689Skan
975990075Sobrien  ASM_OUTPUT_ASCII (stream, name, length);
976090075Sobrien  ASM_OUTPUT_ALIGN (stream, 2);
976190075Sobrien  x = GEN_INT ((unsigned HOST_WIDE_INT) 0xff000000 + alignlength);
976290075Sobrien  assemble_aligned_integer (UNITS_PER_WORD, x);
976390075Sobrien}
976490075Sobrien
976590075Sobrien/* Place some comments into the assembler stream
976690075Sobrien   describing the current function.  */
976790075Sobrienstatic void
9768132718Skanarm_output_function_prologue (FILE *f, HOST_WIDE_INT frame_size)
976990075Sobrien{
977090075Sobrien  unsigned long func_type;
977190075Sobrien
977290075Sobrien  if (!TARGET_ARM)
977390075Sobrien    {
977490075Sobrien      thumb_output_function_prologue (f, frame_size);
977590075Sobrien      return;
977690075Sobrien    }
9777169689Skan
977890075Sobrien  /* Sanity check.  */
9779169689Skan  gcc_assert (!arm_ccfsm_state && !arm_target_insn);
978090075Sobrien
978190075Sobrien  func_type = arm_current_func_type ();
9782169689Skan
978390075Sobrien  switch ((int) ARM_FUNC_TYPE (func_type))
978490075Sobrien    {
978590075Sobrien    default:
978690075Sobrien    case ARM_FT_NORMAL:
978790075Sobrien      break;
978890075Sobrien    case ARM_FT_INTERWORKED:
978990075Sobrien      asm_fprintf (f, "\t%@ Function supports interworking.\n");
979090075Sobrien      break;
979190075Sobrien    case ARM_FT_ISR:
979290075Sobrien      asm_fprintf (f, "\t%@ Interrupt Service Routine.\n");
979390075Sobrien      break;
979490075Sobrien    case ARM_FT_FIQ:
979590075Sobrien      asm_fprintf (f, "\t%@ Fast Interrupt Service Routine.\n");
979690075Sobrien      break;
979790075Sobrien    case ARM_FT_EXCEPTION:
979890075Sobrien      asm_fprintf (f, "\t%@ ARM Exception Handler.\n");
979990075Sobrien      break;
980090075Sobrien    }
9801169689Skan
980290075Sobrien  if (IS_NAKED (func_type))
980390075Sobrien    asm_fprintf (f, "\t%@ Naked Function: prologue and epilogue provided by programmer.\n");
980490075Sobrien
980590075Sobrien  if (IS_VOLATILE (func_type))
980690075Sobrien    asm_fprintf (f, "\t%@ Volatile: function does not return.\n");
980790075Sobrien
980890075Sobrien  if (IS_NESTED (func_type))
980990075Sobrien    asm_fprintf (f, "\t%@ Nested: function declared inside another function.\n");
9810169689Skan
9811132718Skan  asm_fprintf (f, "\t%@ args = %d, pretend = %d, frame = %wd\n",
981290075Sobrien	       current_function_args_size,
981390075Sobrien	       current_function_pretend_args_size, frame_size);
981490075Sobrien
981596263Sobrien  asm_fprintf (f, "\t%@ frame_needed = %d, uses_anonymous_args = %d\n",
981690075Sobrien	       frame_pointer_needed,
981796263Sobrien	       cfun->machine->uses_anonymous_args);
981890075Sobrien
981990075Sobrien  if (cfun->machine->lr_save_eliminated)
982090075Sobrien    asm_fprintf (f, "\t%@ link register save eliminated.\n");
982190075Sobrien
9822169689Skan  if (current_function_calls_eh_return)
9823169689Skan    asm_fprintf (f, "\t@ Calls __builtin_eh_return.\n");
9824169689Skan
982590075Sobrien#ifdef AOF_ASSEMBLER
982690075Sobrien  if (flag_pic)
982790075Sobrien    asm_fprintf (f, "\tmov\t%r, %r\n", IP_REGNUM, PIC_OFFSET_TABLE_REGNUM);
982890075Sobrien#endif
982990075Sobrien
9830169689Skan  return_used_this_function = 0;
983190075Sobrien}
983290075Sobrien
983390075Sobrienconst char *
9834132718Skanarm_output_epilogue (rtx sibling)
983590075Sobrien{
983690075Sobrien  int reg;
983790075Sobrien  unsigned long saved_regs_mask;
983890075Sobrien  unsigned long func_type;
9839169689Skan  /* Floats_offset is the offset from the "virtual" frame.  In an APCS
984096263Sobrien     frame that is $fp + 4 for a non-variadic function.  */
984196263Sobrien  int floats_offset = 0;
984290075Sobrien  rtx operands[3];
984390075Sobrien  FILE * f = asm_out_file;
9844132718Skan  unsigned int lrm_count = 0;
9845132718Skan  int really_return = (sibling == NULL);
9846169689Skan  int start_reg;
9847169689Skan  arm_stack_offsets *offsets;
984890075Sobrien
984990075Sobrien  /* If we have already generated the return instruction
985090075Sobrien     then it is futile to generate anything else.  */
9851132718Skan  if (use_return_insn (FALSE, sibling) && return_used_this_function)
985290075Sobrien    return "";
985390075Sobrien
985490075Sobrien  func_type = arm_current_func_type ();
985590075Sobrien
985690075Sobrien  if (IS_NAKED (func_type))
985790075Sobrien    /* Naked functions don't have epilogues.  */
985890075Sobrien    return "";
985990075Sobrien
986090075Sobrien  if (IS_VOLATILE (func_type) && TARGET_ABORT_NORETURN)
986190075Sobrien    {
986290075Sobrien      rtx op;
9863169689Skan
986490075Sobrien      /* A volatile function should never return.  Call abort.  */
986590075Sobrien      op = gen_rtx_SYMBOL_REF (Pmode, NEED_PLT_RELOC ? "abort(PLT)" : "abort");
986690075Sobrien      assemble_external_libcall (op);
986790075Sobrien      output_asm_insn ("bl\t%a0", &op);
9868169689Skan
986990075Sobrien      return "";
987090075Sobrien    }
987190075Sobrien
9872169689Skan  /* If we are throwing an exception, then we really must be doing a
9873169689Skan     return, so we can't tail-call.  */
9874169689Skan  gcc_assert (!current_function_calls_eh_return || really_return);
9875169689Skan
9876169689Skan  offsets = arm_get_frame_offsets ();
987790075Sobrien  saved_regs_mask = arm_compute_save_reg_mask ();
9878132718Skan
9879132718Skan  if (TARGET_IWMMXT)
9880132718Skan    lrm_count = bit_count (saved_regs_mask);
9881132718Skan
9882169689Skan  floats_offset = offsets->saved_args;
988390075Sobrien  /* Compute how far away the floats will be.  */
9884132718Skan  for (reg = 0; reg <= LAST_ARM_REGNUM; reg++)
988590075Sobrien    if (saved_regs_mask & (1 << reg))
988690075Sobrien      floats_offset += 4;
9887169689Skan
988890075Sobrien  if (frame_pointer_needed)
988990075Sobrien    {
9890169689Skan      /* This variable is for the Virtual Frame Pointer, not VFP regs.  */
9891169689Skan      int vfp_offset = offsets->frame;
989296263Sobrien
9893132718Skan      if (arm_fpu_arch == FPUTYPE_FPA_EMU2)
989490075Sobrien	{
9895169689Skan	  for (reg = LAST_FPA_REGNUM; reg >= FIRST_FPA_REGNUM; reg--)
989690075Sobrien	    if (regs_ever_live[reg] && !call_used_regs[reg])
989790075Sobrien	      {
989890075Sobrien		floats_offset += 12;
9899169689Skan		asm_fprintf (f, "\tldfe\t%r, [%r, #-%d]\n",
990096263Sobrien			     reg, FP_REGNUM, floats_offset - vfp_offset);
990190075Sobrien	      }
990290075Sobrien	}
990390075Sobrien      else
990490075Sobrien	{
9905169689Skan	  start_reg = LAST_FPA_REGNUM;
990690075Sobrien
9907169689Skan	  for (reg = LAST_FPA_REGNUM; reg >= FIRST_FPA_REGNUM; reg--)
990890075Sobrien	    {
990990075Sobrien	      if (regs_ever_live[reg] && !call_used_regs[reg])
991090075Sobrien		{
991190075Sobrien		  floats_offset += 12;
9912169689Skan
991390075Sobrien		  /* We can't unstack more than four registers at once.  */
991490075Sobrien		  if (start_reg - reg == 3)
991590075Sobrien		    {
991690075Sobrien		      asm_fprintf (f, "\tlfm\t%r, 4, [%r, #-%d]\n",
991796263Sobrien			           reg, FP_REGNUM, floats_offset - vfp_offset);
991890075Sobrien		      start_reg = reg - 1;
991990075Sobrien		    }
992090075Sobrien		}
992190075Sobrien	      else
992290075Sobrien		{
992390075Sobrien		  if (reg != start_reg)
992490075Sobrien		    asm_fprintf (f, "\tlfm\t%r, %d, [%r, #-%d]\n",
992590075Sobrien				 reg + 1, start_reg - reg,
992696263Sobrien				 FP_REGNUM, floats_offset - vfp_offset);
992790075Sobrien		  start_reg = reg - 1;
992890075Sobrien		}
992990075Sobrien	    }
993090075Sobrien
993190075Sobrien	  /* Just in case the last register checked also needs unstacking.  */
993290075Sobrien	  if (reg != start_reg)
993390075Sobrien	    asm_fprintf (f, "\tlfm\t%r, %d, [%r, #-%d]\n",
993490075Sobrien			 reg + 1, start_reg - reg,
993596263Sobrien			 FP_REGNUM, floats_offset - vfp_offset);
993690075Sobrien	}
993790075Sobrien
9938169689Skan      if (TARGET_HARD_FLOAT && TARGET_VFP)
9939169689Skan	{
9940169689Skan	  int saved_size;
9941169689Skan
9942169689Skan	  /* The fldmx insn does not have base+offset addressing modes,
9943169689Skan	     so we use IP to hold the address.  */
9944169689Skan	  saved_size = arm_get_vfp_saved_size ();
9945169689Skan
9946169689Skan	  if (saved_size > 0)
9947169689Skan	    {
9948169689Skan	      floats_offset += saved_size;
9949169689Skan	      asm_fprintf (f, "\tsub\t%r, %r, #%d\n", IP_REGNUM,
9950169689Skan			   FP_REGNUM, floats_offset - vfp_offset);
9951169689Skan	    }
9952169689Skan	  start_reg = FIRST_VFP_REGNUM;
9953169689Skan	  for (reg = FIRST_VFP_REGNUM; reg < LAST_VFP_REGNUM; reg += 2)
9954169689Skan	    {
9955169689Skan	      if ((!regs_ever_live[reg] || call_used_regs[reg])
9956169689Skan		  && (!regs_ever_live[reg + 1] || call_used_regs[reg + 1]))
9957169689Skan		{
9958169689Skan		  if (start_reg != reg)
9959169689Skan		    arm_output_fldmx (f, IP_REGNUM,
9960169689Skan				      (start_reg - FIRST_VFP_REGNUM) / 2,
9961169689Skan				      (reg - start_reg) / 2);
9962169689Skan		  start_reg = reg + 2;
9963169689Skan		}
9964169689Skan	    }
9965169689Skan	  if (start_reg != reg)
9966169689Skan	    arm_output_fldmx (f, IP_REGNUM,
9967169689Skan			      (start_reg - FIRST_VFP_REGNUM) / 2,
9968169689Skan			      (reg - start_reg) / 2);
9969169689Skan	}
9970169689Skan
9971132718Skan      if (TARGET_IWMMXT)
9972132718Skan	{
9973132718Skan	  /* The frame pointer is guaranteed to be non-double-word aligned.
9974132718Skan	     This is because it is set to (old_stack_pointer - 4) and the
9975132718Skan	     old_stack_pointer was double word aligned.  Thus the offset to
9976132718Skan	     the iWMMXt registers to be loaded must also be non-double-word
9977132718Skan	     sized, so that the resultant address *is* double-word aligned.
9978132718Skan	     We can ignore floats_offset since that was already included in
9979132718Skan	     the live_regs_mask.  */
9980132718Skan	  lrm_count += (lrm_count % 2 ? 2 : 1);
9981169689Skan
9982169689Skan	  for (reg = LAST_IWMMXT_REGNUM; reg >= FIRST_IWMMXT_REGNUM; reg--)
9983132718Skan	    if (regs_ever_live[reg] && !call_used_regs[reg])
9984132718Skan	      {
9985169689Skan		asm_fprintf (f, "\twldrd\t%r, [%r, #-%d]\n",
9986132718Skan			     reg, FP_REGNUM, lrm_count * 4);
9987169689Skan		lrm_count += 2;
9988132718Skan	      }
9989132718Skan	}
9990132718Skan
999190075Sobrien      /* saved_regs_mask should contain the IP, which at the time of stack
999290075Sobrien	 frame generation actually contains the old stack pointer.  So a
999390075Sobrien	 quick way to unwind the stack is just pop the IP register directly
999490075Sobrien	 into the stack pointer.  */
9995169689Skan      gcc_assert (saved_regs_mask & (1 << IP_REGNUM));
999690075Sobrien      saved_regs_mask &= ~ (1 << IP_REGNUM);
999790075Sobrien      saved_regs_mask |=   (1 << SP_REGNUM);
999890075Sobrien
999990075Sobrien      /* There are two registers left in saved_regs_mask - LR and PC.  We
1000090075Sobrien	 only need to restore the LR register (the return address), but to
1000190075Sobrien	 save time we can load it directly into the PC, unless we need a
1000290075Sobrien	 special function exit sequence, or we are not really returning.  */
10003169689Skan      if (really_return
10004169689Skan	  && ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL
10005169689Skan	  && !current_function_calls_eh_return)
1000690075Sobrien	/* Delete the LR from the register mask, so that the LR on
1000790075Sobrien	   the stack is loaded into the PC in the register mask.  */
1000890075Sobrien	saved_regs_mask &= ~ (1 << LR_REGNUM);
1000990075Sobrien      else
1001090075Sobrien	saved_regs_mask &= ~ (1 << PC_REGNUM);
1001190075Sobrien
10012132718Skan      /* We must use SP as the base register, because SP is one of the
10013132718Skan         registers being restored.  If an interrupt or page fault
10014132718Skan         happens in the ldm instruction, the SP might or might not
10015132718Skan         have been restored.  That would be bad, as then SP will no
10016132718Skan         longer indicate the safe area of stack, and we can get stack
10017132718Skan         corruption.  Using SP as the base register means that it will
10018132718Skan         be reset correctly to the original value, should an interrupt
10019132718Skan         occur.  If the stack pointer already points at the right
10020132718Skan         place, then omit the subtraction.  */
10021169689Skan      if (offsets->outgoing_args != (1 + (int) bit_count (saved_regs_mask))
10022132718Skan	  || current_function_calls_alloca)
10023132718Skan	asm_fprintf (f, "\tsub\t%r, %r, #%d\n", SP_REGNUM, FP_REGNUM,
10024132718Skan		     4 * bit_count (saved_regs_mask));
10025132718Skan      print_multi_reg (f, "ldmfd\t%r", SP_REGNUM, saved_regs_mask);
10026132718Skan
1002790075Sobrien      if (IS_INTERRUPT (func_type))
1002890075Sobrien	/* Interrupt handlers will have pushed the
1002990075Sobrien	   IP onto the stack, so restore it now.  */
10030117395Skan	print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM, 1 << IP_REGNUM);
1003190075Sobrien    }
1003290075Sobrien  else
1003390075Sobrien    {
1003490075Sobrien      /* Restore stack pointer if necessary.  */
10035169689Skan      if (offsets->outgoing_args != offsets->saved_regs)
1003690075Sobrien	{
1003790075Sobrien	  operands[0] = operands[1] = stack_pointer_rtx;
10038169689Skan	  operands[2] = GEN_INT (offsets->outgoing_args - offsets->saved_regs);
1003990075Sobrien	  output_add_immediate (operands);
1004090075Sobrien	}
1004190075Sobrien
10042132718Skan      if (arm_fpu_arch == FPUTYPE_FPA_EMU2)
1004390075Sobrien	{
10044169689Skan	  for (reg = FIRST_FPA_REGNUM; reg <= LAST_FPA_REGNUM; reg++)
1004590075Sobrien	    if (regs_ever_live[reg] && !call_used_regs[reg])
1004690075Sobrien	      asm_fprintf (f, "\tldfe\t%r, [%r], #12\n",
1004790075Sobrien			   reg, SP_REGNUM);
1004890075Sobrien	}
1004990075Sobrien      else
1005090075Sobrien	{
10051169689Skan	  start_reg = FIRST_FPA_REGNUM;
1005290075Sobrien
10053169689Skan	  for (reg = FIRST_FPA_REGNUM; reg <= LAST_FPA_REGNUM; reg++)
1005490075Sobrien	    {
1005590075Sobrien	      if (regs_ever_live[reg] && !call_used_regs[reg])
1005690075Sobrien		{
1005790075Sobrien		  if (reg - start_reg == 3)
1005890075Sobrien		    {
1005990075Sobrien		      asm_fprintf (f, "\tlfmfd\t%r, 4, [%r]!\n",
1006090075Sobrien				   start_reg, SP_REGNUM);
1006190075Sobrien		      start_reg = reg + 1;
1006290075Sobrien		    }
1006390075Sobrien		}
1006490075Sobrien	      else
1006590075Sobrien		{
1006690075Sobrien		  if (reg != start_reg)
1006790075Sobrien		    asm_fprintf (f, "\tlfmfd\t%r, %d, [%r]!\n",
1006890075Sobrien				 start_reg, reg - start_reg,
1006990075Sobrien				 SP_REGNUM);
10070169689Skan
1007190075Sobrien		  start_reg = reg + 1;
1007290075Sobrien		}
1007390075Sobrien	    }
1007490075Sobrien
1007590075Sobrien	  /* Just in case the last register checked also needs unstacking.  */
1007690075Sobrien	  if (reg != start_reg)
1007790075Sobrien	    asm_fprintf (f, "\tlfmfd\t%r, %d, [%r]!\n",
1007890075Sobrien			 start_reg, reg - start_reg, SP_REGNUM);
1007990075Sobrien	}
1008090075Sobrien
10081169689Skan      if (TARGET_HARD_FLOAT && TARGET_VFP)
10082169689Skan	{
10083169689Skan	  start_reg = FIRST_VFP_REGNUM;
10084169689Skan	  for (reg = FIRST_VFP_REGNUM; reg < LAST_VFP_REGNUM; reg += 2)
10085169689Skan	    {
10086169689Skan	      if ((!regs_ever_live[reg] || call_used_regs[reg])
10087169689Skan		  && (!regs_ever_live[reg + 1] || call_used_regs[reg + 1]))
10088169689Skan		{
10089169689Skan		  if (start_reg != reg)
10090169689Skan		    arm_output_fldmx (f, SP_REGNUM,
10091169689Skan				      (start_reg - FIRST_VFP_REGNUM) / 2,
10092169689Skan				      (reg - start_reg) / 2);
10093169689Skan		  start_reg = reg + 2;
10094169689Skan		}
10095169689Skan	    }
10096169689Skan	  if (start_reg != reg)
10097169689Skan	    arm_output_fldmx (f, SP_REGNUM,
10098169689Skan			      (start_reg - FIRST_VFP_REGNUM) / 2,
10099169689Skan			      (reg - start_reg) / 2);
10100169689Skan	}
10101132718Skan      if (TARGET_IWMMXT)
10102132718Skan	for (reg = FIRST_IWMMXT_REGNUM; reg <= LAST_IWMMXT_REGNUM; reg++)
10103132718Skan	  if (regs_ever_live[reg] && !call_used_regs[reg])
10104169689Skan	    asm_fprintf (f, "\twldrd\t%r, [%r], #8\n", reg, SP_REGNUM);
10105132718Skan
1010690075Sobrien      /* If we can, restore the LR into the PC.  */
1010790075Sobrien      if (ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL
1010890075Sobrien	  && really_return
1010990075Sobrien	  && current_function_pretend_args_size == 0
10110169689Skan	  && saved_regs_mask & (1 << LR_REGNUM)
10111169689Skan	  && !current_function_calls_eh_return)
1011290075Sobrien	{
1011390075Sobrien	  saved_regs_mask &= ~ (1 << LR_REGNUM);
1011490075Sobrien	  saved_regs_mask |=   (1 << PC_REGNUM);
1011590075Sobrien	}
1011690075Sobrien
1011790075Sobrien      /* Load the registers off the stack.  If we only have one register
1011890075Sobrien	 to load use the LDR instruction - it is faster.  */
1011990075Sobrien      if (saved_regs_mask == (1 << LR_REGNUM))
1012090075Sobrien	{
10121169689Skan	  asm_fprintf (f, "\tldr\t%r, [%r], #4\n", LR_REGNUM, SP_REGNUM);
1012290075Sobrien	}
1012390075Sobrien      else if (saved_regs_mask)
10124117395Skan	{
10125117395Skan	  if (saved_regs_mask & (1 << SP_REGNUM))
10126117395Skan	    /* Note - write back to the stack register is not enabled
10127169689Skan	       (i.e. "ldmfd sp!...").  We know that the stack pointer is
10128117395Skan	       in the list of registers and if we add writeback the
10129117395Skan	       instruction becomes UNPREDICTABLE.  */
10130117395Skan	    print_multi_reg (f, "ldmfd\t%r", SP_REGNUM, saved_regs_mask);
10131117395Skan	  else
10132117395Skan	    print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM, saved_regs_mask);
10133117395Skan	}
1013490075Sobrien
1013590075Sobrien      if (current_function_pretend_args_size)
1013690075Sobrien	{
1013790075Sobrien	  /* Unwind the pre-pushed regs.  */
1013890075Sobrien	  operands[0] = operands[1] = stack_pointer_rtx;
1013990075Sobrien	  operands[2] = GEN_INT (current_function_pretend_args_size);
1014090075Sobrien	  output_add_immediate (operands);
1014190075Sobrien	}
1014290075Sobrien    }
1014390075Sobrien
10144169689Skan  /* We may have already restored PC directly from the stack.  */
10145169689Skan  if (!really_return || saved_regs_mask & (1 << PC_REGNUM))
1014690075Sobrien    return "";
1014790075Sobrien
10148169689Skan  /* Stack adjustment for exception handler.  */
10149169689Skan  if (current_function_calls_eh_return)
10150169689Skan    asm_fprintf (f, "\tadd\t%r, %r, %r\n", SP_REGNUM, SP_REGNUM,
10151169689Skan		 ARM_EH_STACKADJ_REGNUM);
10152169689Skan
1015390075Sobrien  /* Generate the return instruction.  */
1015490075Sobrien  switch ((int) ARM_FUNC_TYPE (func_type))
1015590075Sobrien    {
1015690075Sobrien    case ARM_FT_ISR:
1015790075Sobrien    case ARM_FT_FIQ:
1015890075Sobrien      asm_fprintf (f, "\tsubs\t%r, %r, #4\n", PC_REGNUM, LR_REGNUM);
1015990075Sobrien      break;
1016090075Sobrien
1016190075Sobrien    case ARM_FT_EXCEPTION:
1016290075Sobrien      asm_fprintf (f, "\tmovs\t%r, %r\n", PC_REGNUM, LR_REGNUM);
1016390075Sobrien      break;
1016490075Sobrien
1016590075Sobrien    case ARM_FT_INTERWORKED:
1016690075Sobrien      asm_fprintf (f, "\tbx\t%r\n", LR_REGNUM);
1016790075Sobrien      break;
1016890075Sobrien
1016990075Sobrien    default:
10170169689Skan      if (arm_arch5 || arm_arch4t)
10171169689Skan	asm_fprintf (f, "\tbx\t%r\n", LR_REGNUM);
10172169689Skan      else
1017390075Sobrien	asm_fprintf (f, "\tmov\t%r, %r\n", PC_REGNUM, LR_REGNUM);
1017490075Sobrien      break;
1017590075Sobrien    }
1017690075Sobrien
1017790075Sobrien  return "";
1017890075Sobrien}
1017990075Sobrien
1018090075Sobrienstatic void
10181132718Skanarm_output_function_epilogue (FILE *file ATTRIBUTE_UNUSED,
10182169689Skan			      HOST_WIDE_INT frame_size ATTRIBUTE_UNUSED)
1018390075Sobrien{
10184169689Skan  arm_stack_offsets *offsets;
10185169689Skan
1018690075Sobrien  if (TARGET_THUMB)
1018790075Sobrien    {
10188169689Skan      int regno;
10189169689Skan
10190169689Skan      /* Emit any call-via-reg trampolines that are needed for v4t support
10191169689Skan	 of call_reg and call_value_reg type insns.  */
10192169689Skan      for (regno = 0; regno < LR_REGNUM; regno++)
10193169689Skan	{
10194169689Skan	  rtx label = cfun->machine->call_via[regno];
10195169689Skan
10196169689Skan	  if (label != NULL)
10197169689Skan	    {
10198169689Skan	      switch_to_section (function_section (current_function_decl));
10199169689Skan	      targetm.asm_out.internal_label (asm_out_file, "L",
10200169689Skan					      CODE_LABEL_NUMBER (label));
10201169689Skan	      asm_fprintf (asm_out_file, "\tbx\t%r\n", regno);
10202169689Skan	    }
10203169689Skan	}
10204169689Skan
1020590075Sobrien      /* ??? Probably not safe to set this here, since it assumes that a
1020690075Sobrien	 function will be emitted as assembly immediately after we generate
1020790075Sobrien	 RTL for it.  This does not happen for inline functions.  */
1020890075Sobrien      return_used_this_function = 0;
1020990075Sobrien    }
1021090075Sobrien  else
1021190075Sobrien    {
10212117395Skan      /* We need to take into account any stack-frame rounding.  */
10213169689Skan      offsets = arm_get_frame_offsets ();
10214117395Skan
10215169689Skan      gcc_assert (!use_return_insn (FALSE, NULL)
10216169689Skan		  || !return_used_this_function
10217169689Skan		  || offsets->saved_regs == offsets->outgoing_args
10218169689Skan		  || frame_pointer_needed);
1021990075Sobrien
1022090075Sobrien      /* Reset the ARM-specific per-function variables.  */
1022190075Sobrien      after_arm_reorg = 0;
1022290075Sobrien    }
1022390075Sobrien}
1022490075Sobrien
1022590075Sobrien/* Generate and emit an insn that we will recognize as a push_multi.
1022690075Sobrien   Unfortunately, since this insn does not reflect very well the actual
1022790075Sobrien   semantics of the operation, we need to annotate the insn for the benefit
1022890075Sobrien   of DWARF2 frame unwind information.  */
1022990075Sobrienstatic rtx
10230169689Skanemit_multi_reg_push (unsigned long mask)
1023190075Sobrien{
1023290075Sobrien  int num_regs = 0;
1023390075Sobrien  int num_dwarf_regs;
1023490075Sobrien  int i, j;
1023590075Sobrien  rtx par;
1023690075Sobrien  rtx dwarf;
1023790075Sobrien  int dwarf_par_index;
1023890075Sobrien  rtx tmp, reg;
1023990075Sobrien
1024090075Sobrien  for (i = 0; i <= LAST_ARM_REGNUM; i++)
1024190075Sobrien    if (mask & (1 << i))
1024290075Sobrien      num_regs++;
1024390075Sobrien
10244169689Skan  gcc_assert (num_regs && num_regs <= 16);
1024590075Sobrien
1024690075Sobrien  /* We don't record the PC in the dwarf frame information.  */
1024790075Sobrien  num_dwarf_regs = num_regs;
1024890075Sobrien  if (mask & (1 << PC_REGNUM))
1024990075Sobrien    num_dwarf_regs--;
1025090075Sobrien
1025190075Sobrien  /* For the body of the insn we are going to generate an UNSPEC in
10252117395Skan     parallel with several USEs.  This allows the insn to be recognized
1025390075Sobrien     by the push_multi pattern in the arm.md file.  The insn looks
1025490075Sobrien     something like this:
1025590075Sobrien
10256169689Skan       (parallel [
1025790075Sobrien           (set (mem:BLK (pre_dec:BLK (reg:SI sp)))
1025890075Sobrien	        (unspec:BLK [(reg:SI r4)] UNSPEC_PUSH_MULT))
1025990075Sobrien           (use (reg:SI 11 fp))
1026090075Sobrien           (use (reg:SI 12 ip))
1026190075Sobrien           (use (reg:SI 14 lr))
1026290075Sobrien           (use (reg:SI 15 pc))
1026390075Sobrien        ])
1026490075Sobrien
1026590075Sobrien     For the frame note however, we try to be more explicit and actually
1026690075Sobrien     show each register being stored into the stack frame, plus a (single)
1026790075Sobrien     decrement of the stack pointer.  We do it this way in order to be
1026890075Sobrien     friendly to the stack unwinding code, which only wants to see a single
1026990075Sobrien     stack decrement per instruction.  The RTL we generate for the note looks
1027090075Sobrien     something like this:
1027190075Sobrien
10272169689Skan      (sequence [
1027390075Sobrien           (set (reg:SI sp) (plus:SI (reg:SI sp) (const_int -20)))
1027490075Sobrien           (set (mem:SI (reg:SI sp)) (reg:SI r4))
1027590075Sobrien           (set (mem:SI (plus:SI (reg:SI sp) (const_int 4))) (reg:SI fp))
1027690075Sobrien           (set (mem:SI (plus:SI (reg:SI sp) (const_int 8))) (reg:SI ip))
1027790075Sobrien           (set (mem:SI (plus:SI (reg:SI sp) (const_int 12))) (reg:SI lr))
1027890075Sobrien        ])
1027990075Sobrien
1028090075Sobrien      This sequence is used both by the code to support stack unwinding for
1028190075Sobrien      exceptions handlers and the code to generate dwarf2 frame debugging.  */
10282169689Skan
1028390075Sobrien  par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (num_regs));
1028490075Sobrien  dwarf = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (num_dwarf_regs + 1));
1028590075Sobrien  dwarf_par_index = 1;
1028690075Sobrien
1028790075Sobrien  for (i = 0; i <= LAST_ARM_REGNUM; i++)
1028890075Sobrien    {
1028990075Sobrien      if (mask & (1 << i))
1029090075Sobrien	{
1029190075Sobrien	  reg = gen_rtx_REG (SImode, i);
1029290075Sobrien
1029390075Sobrien	  XVECEXP (par, 0, 0)
1029490075Sobrien	    = gen_rtx_SET (VOIDmode,
10295169689Skan			   gen_frame_mem (BLKmode,
10296169689Skan					  gen_rtx_PRE_DEC (BLKmode,
10297169689Skan							   stack_pointer_rtx)),
1029890075Sobrien			   gen_rtx_UNSPEC (BLKmode,
1029990075Sobrien					   gen_rtvec (1, reg),
1030090075Sobrien					   UNSPEC_PUSH_MULT));
1030190075Sobrien
1030290075Sobrien	  if (i != PC_REGNUM)
1030390075Sobrien	    {
1030490075Sobrien	      tmp = gen_rtx_SET (VOIDmode,
10305169689Skan				 gen_frame_mem (SImode, stack_pointer_rtx),
1030690075Sobrien				 reg);
1030790075Sobrien	      RTX_FRAME_RELATED_P (tmp) = 1;
1030890075Sobrien	      XVECEXP (dwarf, 0, dwarf_par_index) = tmp;
1030990075Sobrien	      dwarf_par_index++;
1031090075Sobrien	    }
1031190075Sobrien
1031290075Sobrien	  break;
1031390075Sobrien	}
1031490075Sobrien    }
1031590075Sobrien
1031690075Sobrien  for (j = 1, i++; j < num_regs; i++)
1031790075Sobrien    {
1031890075Sobrien      if (mask & (1 << i))
1031990075Sobrien	{
1032090075Sobrien	  reg = gen_rtx_REG (SImode, i);
1032190075Sobrien
1032290075Sobrien	  XVECEXP (par, 0, j) = gen_rtx_USE (VOIDmode, reg);
1032390075Sobrien
1032490075Sobrien	  if (i != PC_REGNUM)
1032590075Sobrien	    {
10326169689Skan	      tmp
10327169689Skan		= gen_rtx_SET (VOIDmode,
10328169689Skan			       gen_frame_mem (SImode,
1032990075Sobrien					      plus_constant (stack_pointer_rtx,
1033090075Sobrien							     4 * j)),
10331169689Skan			       reg);
1033290075Sobrien	      RTX_FRAME_RELATED_P (tmp) = 1;
1033390075Sobrien	      XVECEXP (dwarf, 0, dwarf_par_index++) = tmp;
1033490075Sobrien	    }
1033590075Sobrien
1033690075Sobrien	  j++;
1033790075Sobrien	}
1033890075Sobrien    }
1033990075Sobrien
1034090075Sobrien  par = emit_insn (par);
10341169689Skan
10342169689Skan  tmp = gen_rtx_SET (VOIDmode,
1034390075Sobrien		     stack_pointer_rtx,
10344169689Skan		     plus_constant (stack_pointer_rtx, -4 * num_regs));
1034590075Sobrien  RTX_FRAME_RELATED_P (tmp) = 1;
1034690075Sobrien  XVECEXP (dwarf, 0, 0) = tmp;
10347169689Skan
1034890075Sobrien  REG_NOTES (par) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
1034990075Sobrien				       REG_NOTES (par));
1035090075Sobrien  return par;
1035190075Sobrien}
1035290075Sobrien
10353169689Skan/* Calculate the size of the return value that is passed in registers.  */
10354169689Skanstatic int
10355169689Skanarm_size_return_regs (void)
10356169689Skan{
10357169689Skan  enum machine_mode mode;
10358169689Skan
10359169689Skan  if (current_function_return_rtx != 0)
10360169689Skan    mode = GET_MODE (current_function_return_rtx);
10361169689Skan  else
10362169689Skan    mode = DECL_MODE (DECL_RESULT (current_function_decl));
10363169689Skan
10364169689Skan  return GET_MODE_SIZE (mode);
10365169689Skan}
10366169689Skan
1036790075Sobrienstatic rtx
10368132718Skanemit_sfm (int base_reg, int count)
1036990075Sobrien{
1037090075Sobrien  rtx par;
1037190075Sobrien  rtx dwarf;
1037290075Sobrien  rtx tmp, reg;
1037390075Sobrien  int i;
1037490075Sobrien
1037590075Sobrien  par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count));
10376169689Skan  dwarf = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (count + 1));
1037790075Sobrien
1037890075Sobrien  reg = gen_rtx_REG (XFmode, base_reg++);
1037990075Sobrien
1038090075Sobrien  XVECEXP (par, 0, 0)
10381169689Skan    = gen_rtx_SET (VOIDmode,
10382169689Skan		   gen_frame_mem (BLKmode,
10383169689Skan				  gen_rtx_PRE_DEC (BLKmode,
10384169689Skan						   stack_pointer_rtx)),
1038590075Sobrien		   gen_rtx_UNSPEC (BLKmode,
1038690075Sobrien				   gen_rtvec (1, reg),
1038790075Sobrien				   UNSPEC_PUSH_MULT));
10388169689Skan  tmp = gen_rtx_SET (VOIDmode,
10389169689Skan		     gen_frame_mem (XFmode, stack_pointer_rtx), reg);
1039090075Sobrien  RTX_FRAME_RELATED_P (tmp) = 1;
10391169689Skan  XVECEXP (dwarf, 0, 1) = tmp;
10392169689Skan
1039390075Sobrien  for (i = 1; i < count; i++)
1039490075Sobrien    {
1039590075Sobrien      reg = gen_rtx_REG (XFmode, base_reg++);
1039690075Sobrien      XVECEXP (par, 0, i) = gen_rtx_USE (VOIDmode, reg);
1039790075Sobrien
10398169689Skan      tmp = gen_rtx_SET (VOIDmode,
10399169689Skan			 gen_frame_mem (XFmode,
10400169689Skan					plus_constant (stack_pointer_rtx,
10401169689Skan						       i * 12)),
1040290075Sobrien			 reg);
1040390075Sobrien      RTX_FRAME_RELATED_P (tmp) = 1;
10404169689Skan      XVECEXP (dwarf, 0, i + 1) = tmp;
1040590075Sobrien    }
1040690075Sobrien
10407169689Skan  tmp = gen_rtx_SET (VOIDmode,
10408169689Skan		     stack_pointer_rtx,
10409169689Skan		     plus_constant (stack_pointer_rtx, -12 * count));
10410169689Skan
10411169689Skan  RTX_FRAME_RELATED_P (tmp) = 1;
10412169689Skan  XVECEXP (dwarf, 0, 0) = tmp;
10413169689Skan
1041490075Sobrien  par = emit_insn (par);
1041590075Sobrien  REG_NOTES (par) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
1041690075Sobrien				       REG_NOTES (par));
1041790075Sobrien  return par;
1041890075Sobrien}
1041990075Sobrien
10420169689Skan
10421169689Skan/* Return true if the current function needs to save/restore LR.  */
10422169689Skan
10423169689Skanstatic bool
10424169689Skanthumb_force_lr_save (void)
10425169689Skan{
10426169689Skan  return !cfun->machine->lr_save_eliminated
10427169689Skan	 && (!leaf_function_p ()
10428169689Skan	     || thumb_far_jump_used_p ()
10429169689Skan	     || regs_ever_live [LR_REGNUM]);
10430169689Skan}
10431169689Skan
10432169689Skan
1043390075Sobrien/* Compute the distance from register FROM to register TO.
1043490075Sobrien   These can be the arg pointer (26), the soft frame pointer (25),
1043590075Sobrien   the stack pointer (13) or the hard frame pointer (11).
10436169689Skan   In thumb mode r7 is used as the soft frame pointer, if needed.
1043790075Sobrien   Typical stack layout looks like this:
1043890075Sobrien
1043990075Sobrien       old stack pointer -> |    |
1044090075Sobrien                             ----
1044190075Sobrien                            |    | \
1044290075Sobrien                            |    |   saved arguments for
1044390075Sobrien                            |    |   vararg functions
1044490075Sobrien			    |    | /
1044590075Sobrien                              --
1044690075Sobrien   hard FP & arg pointer -> |    | \
1044790075Sobrien                            |    |   stack
1044890075Sobrien                            |    |   frame
1044990075Sobrien                            |    | /
1045090075Sobrien                              --
1045190075Sobrien                            |    | \
1045290075Sobrien                            |    |   call saved
1045390075Sobrien                            |    |   registers
1045490075Sobrien      soft frame pointer -> |    | /
1045590075Sobrien                              --
1045690075Sobrien                            |    | \
1045790075Sobrien                            |    |   local
1045890075Sobrien                            |    |   variables
10459169689Skan     locals base pointer -> |    | /
1046090075Sobrien                              --
1046190075Sobrien                            |    | \
1046290075Sobrien                            |    |   outgoing
1046390075Sobrien                            |    |   arguments
1046490075Sobrien   current stack pointer -> |    | /
1046590075Sobrien                              --
1046690075Sobrien
10467117395Skan  For a given function some or all of these stack components
1046890075Sobrien  may not be needed, giving rise to the possibility of
1046990075Sobrien  eliminating some of the registers.
1047090075Sobrien
10471117395Skan  The values returned by this function must reflect the behavior
1047290075Sobrien  of arm_expand_prologue() and arm_compute_save_reg_mask().
1047390075Sobrien
1047490075Sobrien  The sign of the number returned reflects the direction of stack
1047590075Sobrien  growth, so the values are positive for all eliminations except
10476169689Skan  from the soft frame pointer to the hard frame pointer.
10477169689Skan
10478169689Skan  SFP may point just inside the local variables block to ensure correct
10479169689Skan  alignment.  */
10480169689Skan
10481169689Skan
10482169689Skan/* Calculate stack offsets.  These are used to calculate register elimination
10483169689Skan   offsets and in prologue/epilogue code.  */
10484169689Skan
10485169689Skanstatic arm_stack_offsets *
10486169689Skanarm_get_frame_offsets (void)
1048790075Sobrien{
10488169689Skan  struct arm_stack_offsets *offsets;
1048990075Sobrien  unsigned long func_type;
10490169689Skan  int leaf;
10491169689Skan  int saved;
10492169689Skan  HOST_WIDE_INT frame_size;
1049390075Sobrien
10494169689Skan  offsets = &cfun->machine->stack_offsets;
10495169689Skan
10496169689Skan  /* We need to know if we are a leaf function.  Unfortunately, it
10497169689Skan     is possible to be called after start_sequence has been called,
10498169689Skan     which causes get_insns to return the insns for the sequence,
10499169689Skan     not the function, which will cause leaf_function_p to return
10500169689Skan     the incorrect result.
10501169689Skan
10502169689Skan     to know about leaf functions once reload has completed, and the
10503169689Skan     frame size cannot be changed after that time, so we can safely
10504169689Skan     use the cached value.  */
10505169689Skan
10506169689Skan  if (reload_completed)
10507169689Skan    return offsets;
10508169689Skan
10509169689Skan  /* Initially this is the size of the local variables.  It will translated
10510169689Skan     into an offset once we have determined the size of preceding data.  */
10511169689Skan  frame_size = ROUND_UP_WORD (get_frame_size ());
10512169689Skan
10513169689Skan  leaf = leaf_function_p ();
10514169689Skan
10515169689Skan  /* Space for variadic functions.  */
10516169689Skan  offsets->saved_args = current_function_pretend_args_size;
10517169689Skan
10518169689Skan  offsets->frame = offsets->saved_args + (frame_pointer_needed ? 4 : 0);
10519169689Skan
10520169689Skan  if (TARGET_ARM)
1052190075Sobrien    {
10522169689Skan      unsigned int regno;
1052390075Sobrien
10524169689Skan      saved = bit_count (arm_compute_save_reg_mask ()) * 4;
1052590075Sobrien
10526169689Skan      /* We know that SP will be doubleword aligned on entry, and we must
10527169689Skan	 preserve that condition at any subroutine call.  We also require the
10528169689Skan	 soft frame pointer to be doubleword aligned.  */
1052990075Sobrien
10530169689Skan      if (TARGET_REALLY_IWMMXT)
10531169689Skan	{
10532169689Skan	  /* Check for the call-saved iWMMXt registers.  */
10533169689Skan	  for (regno = FIRST_IWMMXT_REGNUM;
10534169689Skan	       regno <= LAST_IWMMXT_REGNUM;
10535169689Skan	       regno++)
10536169689Skan	    if (regs_ever_live [regno] && ! call_used_regs [regno])
10537169689Skan	      saved += 8;
10538169689Skan	}
10539132718Skan
10540169689Skan      func_type = arm_current_func_type ();
10541169689Skan      if (! IS_VOLATILE (func_type))
10542169689Skan	{
10543169689Skan	  /* Space for saved FPA registers.  */
10544169689Skan	  for (regno = FIRST_FPA_REGNUM; regno <= LAST_FPA_REGNUM; regno++)
10545169689Skan	  if (regs_ever_live[regno] && ! call_used_regs[regno])
10546169689Skan	    saved += 12;
10547169689Skan
10548169689Skan	  /* Space for saved VFP registers.  */
10549169689Skan	  if (TARGET_HARD_FLOAT && TARGET_VFP)
10550169689Skan	    saved += arm_get_vfp_saved_size ();
10551169689Skan	}
1055290075Sobrien    }
10553169689Skan  else /* TARGET_THUMB */
10554169689Skan    {
10555169689Skan      saved = bit_count (thumb_compute_save_reg_mask ()) * 4;
10556169689Skan      if (TARGET_BACKTRACE)
10557169689Skan	saved += 16;
10558169689Skan    }
1055990075Sobrien
10560169689Skan  /* Saved registers include the stack frame.  */
10561169689Skan  offsets->saved_regs = offsets->saved_args + saved;
10562169689Skan  offsets->soft_frame = offsets->saved_regs + CALLER_INTERWORKING_SLOT_SIZE;
10563169689Skan  /* A leaf function does not need any stack alignment if it has nothing
10564169689Skan     on the stack.  */
10565169689Skan  if (leaf && frame_size == 0)
10566169689Skan    {
10567169689Skan      offsets->outgoing_args = offsets->soft_frame;
10568171825Skan      offsets->locals_base = offsets->soft_frame;
10569169689Skan      return offsets;
10570169689Skan    }
1057190075Sobrien
10572169689Skan  /* Ensure SFP has the correct alignment.  */
10573169689Skan  if (ARM_DOUBLEWORD_ALIGN
10574169689Skan      && (offsets->soft_frame & 7))
10575169689Skan    offsets->soft_frame += 4;
10576169689Skan
10577169689Skan  offsets->locals_base = offsets->soft_frame + frame_size;
10578169689Skan  offsets->outgoing_args = (offsets->locals_base
10579169689Skan			    + current_function_outgoing_args_size);
10580169689Skan
10581169689Skan  if (ARM_DOUBLEWORD_ALIGN)
10582169689Skan    {
10583169689Skan      /* Ensure SP remains doubleword aligned.  */
10584169689Skan      if (offsets->outgoing_args & 7)
10585169689Skan	offsets->outgoing_args += 4;
10586169689Skan      gcc_assert (!(offsets->outgoing_args & 7));
10587169689Skan    }
10588169689Skan
10589169689Skan  return offsets;
10590169689Skan}
10591169689Skan
10592169689Skan
10593169689Skan/* Calculate the relative offsets for the different stack pointers.  Positive
10594169689Skan   offsets are in the direction of stack growth.  */
10595169689Skan
10596169689SkanHOST_WIDE_INT
10597169689Skanarm_compute_initial_elimination_offset (unsigned int from, unsigned int to)
10598169689Skan{
10599169689Skan  arm_stack_offsets *offsets;
10600169689Skan
10601169689Skan  offsets = arm_get_frame_offsets ();
10602169689Skan
1060390075Sobrien  /* OK, now we have enough information to compute the distances.
1060490075Sobrien     There must be an entry in these switch tables for each pair
1060590075Sobrien     of registers in ELIMINABLE_REGS, even if some of the entries
1060690075Sobrien     seem to be redundant or useless.  */
1060790075Sobrien  switch (from)
1060890075Sobrien    {
1060990075Sobrien    case ARG_POINTER_REGNUM:
1061090075Sobrien      switch (to)
1061190075Sobrien	{
1061290075Sobrien	case THUMB_HARD_FRAME_POINTER_REGNUM:
1061390075Sobrien	  return 0;
1061490075Sobrien
1061590075Sobrien	case FRAME_POINTER_REGNUM:
1061690075Sobrien	  /* This is the reverse of the soft frame pointer
1061790075Sobrien	     to hard frame pointer elimination below.  */
10618169689Skan	  return offsets->soft_frame - offsets->saved_args;
1061990075Sobrien
1062090075Sobrien	case ARM_HARD_FRAME_POINTER_REGNUM:
1062190075Sobrien	  /* If there is no stack frame then the hard
1062290075Sobrien	     frame pointer and the arg pointer coincide.  */
10623169689Skan	  if (offsets->frame == offsets->saved_regs)
1062490075Sobrien	    return 0;
1062590075Sobrien	  /* FIXME:  Not sure about this.  Maybe we should always return 0 ?  */
1062690075Sobrien	  return (frame_pointer_needed
10627169689Skan		  && cfun->static_chain_decl != NULL
1062896263Sobrien		  && ! cfun->machine->uses_anonymous_args) ? 4 : 0;
1062990075Sobrien
1063090075Sobrien	case STACK_POINTER_REGNUM:
1063190075Sobrien	  /* If nothing has been pushed on the stack at all
1063290075Sobrien	     then this will return -4.  This *is* correct!  */
10633169689Skan	  return offsets->outgoing_args - (offsets->saved_args + 4);
1063490075Sobrien
1063590075Sobrien	default:
10636169689Skan	  gcc_unreachable ();
1063790075Sobrien	}
10638169689Skan      gcc_unreachable ();
1063990075Sobrien
1064090075Sobrien    case FRAME_POINTER_REGNUM:
1064190075Sobrien      switch (to)
1064290075Sobrien	{
1064390075Sobrien	case THUMB_HARD_FRAME_POINTER_REGNUM:
1064490075Sobrien	  return 0;
1064590075Sobrien
1064690075Sobrien	case ARM_HARD_FRAME_POINTER_REGNUM:
1064790075Sobrien	  /* The hard frame pointer points to the top entry in the
1064890075Sobrien	     stack frame.  The soft frame pointer to the bottom entry
1064990075Sobrien	     in the stack frame.  If there is no stack frame at all,
1065090075Sobrien	     then they are identical.  */
1065190075Sobrien
10652169689Skan	  return offsets->frame - offsets->soft_frame;
10653169689Skan
1065490075Sobrien	case STACK_POINTER_REGNUM:
10655169689Skan	  return offsets->outgoing_args - offsets->soft_frame;
1065690075Sobrien
1065790075Sobrien	default:
10658169689Skan	  gcc_unreachable ();
1065990075Sobrien	}
10660169689Skan      gcc_unreachable ();
1066190075Sobrien
1066290075Sobrien    default:
1066390075Sobrien      /* You cannot eliminate from the stack pointer.
1066490075Sobrien	 In theory you could eliminate from the hard frame
1066590075Sobrien	 pointer to the stack pointer, but this will never
1066690075Sobrien	 happen, since if a stack frame is not needed the
1066790075Sobrien	 hard frame pointer will never be used.  */
10668169689Skan      gcc_unreachable ();
1066990075Sobrien    }
1067090075Sobrien}
1067190075Sobrien
10672117395Skan
1067390075Sobrien/* Generate the prologue instructions for entry into an ARM function.  */
1067490075Sobrienvoid
10675132718Skanarm_expand_prologue (void)
1067690075Sobrien{
1067790075Sobrien  int reg;
1067890075Sobrien  rtx amount;
1067990075Sobrien  rtx insn;
1068090075Sobrien  rtx ip_rtx;
1068190075Sobrien  unsigned long live_regs_mask;
1068290075Sobrien  unsigned long func_type;
1068390075Sobrien  int fp_offset = 0;
1068490075Sobrien  int saved_pretend_args = 0;
10685169689Skan  int saved_regs = 0;
10686169689Skan  unsigned HOST_WIDE_INT args_to_push;
10687169689Skan  arm_stack_offsets *offsets;
1068890075Sobrien
1068990075Sobrien  func_type = arm_current_func_type ();
1069090075Sobrien
1069190075Sobrien  /* Naked functions don't have prologues.  */
1069290075Sobrien  if (IS_NAKED (func_type))
1069390075Sobrien    return;
1069490075Sobrien
1069590075Sobrien  /* Make a copy of c_f_p_a_s as we may need to modify it locally.  */
1069690075Sobrien  args_to_push = current_function_pretend_args_size;
10697169689Skan
1069890075Sobrien  /* Compute which register we will have to save onto the stack.  */
1069990075Sobrien  live_regs_mask = arm_compute_save_reg_mask ();
1070090075Sobrien
1070190075Sobrien  ip_rtx = gen_rtx_REG (SImode, IP_REGNUM);
1070290075Sobrien
1070390075Sobrien  if (frame_pointer_needed)
1070490075Sobrien    {
1070590075Sobrien      if (IS_INTERRUPT (func_type))
1070690075Sobrien	{
1070790075Sobrien	  /* Interrupt functions must not corrupt any registers.
1070890075Sobrien	     Creating a frame pointer however, corrupts the IP
1070990075Sobrien	     register, so we must push it first.  */
1071090075Sobrien	  insn = emit_multi_reg_push (1 << IP_REGNUM);
1071190075Sobrien
1071290075Sobrien	  /* Do not set RTX_FRAME_RELATED_P on this insn.
1071390075Sobrien	     The dwarf stack unwinding code only wants to see one
1071490075Sobrien	     stack decrement per function, and this is not it.  If
1071590075Sobrien	     this instruction is labeled as being part of the frame
1071690075Sobrien	     creation sequence then dwarf2out_frame_debug_expr will
10717169689Skan	     die when it encounters the assignment of IP to FP
1071890075Sobrien	     later on, since the use of SP here establishes SP as
1071990075Sobrien	     the CFA register and not IP.
1072090075Sobrien
1072190075Sobrien	     Anyway this instruction is not really part of the stack
1072290075Sobrien	     frame creation although it is part of the prologue.  */
1072390075Sobrien	}
1072490075Sobrien      else if (IS_NESTED (func_type))
1072590075Sobrien	{
1072690075Sobrien	  /* The Static chain register is the same as the IP register
1072790075Sobrien	     used as a scratch register during stack frame creation.
1072890075Sobrien	     To get around this need to find somewhere to store IP
1072990075Sobrien	     whilst the frame is being created.  We try the following
1073090075Sobrien	     places in order:
10731169689Skan
1073290075Sobrien	       1. The last argument register.
1073390075Sobrien	       2. A slot on the stack above the frame.  (This only
1073490075Sobrien	          works if the function is not a varargs function).
1073590075Sobrien	       3. Register r3, after pushing the argument registers
1073690075Sobrien	          onto the stack.
1073790075Sobrien
1073890075Sobrien	     Note - we only need to tell the dwarf2 backend about the SP
1073990075Sobrien	     adjustment in the second variant; the static chain register
1074090075Sobrien	     doesn't need to be unwound, as it doesn't contain a value
1074190075Sobrien	     inherited from the caller.  */
1074290075Sobrien
1074390075Sobrien	  if (regs_ever_live[3] == 0)
10744169689Skan	    insn = emit_set_insn (gen_rtx_REG (SImode, 3), ip_rtx);
1074590075Sobrien	  else if (args_to_push == 0)
1074690075Sobrien	    {
1074790075Sobrien	      rtx dwarf;
10748169689Skan
1074990075Sobrien	      insn = gen_rtx_PRE_DEC (SImode, stack_pointer_rtx);
10750169689Skan	      insn = emit_set_insn (gen_frame_mem (SImode, insn), ip_rtx);
1075190075Sobrien	      fp_offset = 4;
1075290075Sobrien
1075390075Sobrien	      /* Just tell the dwarf backend that we adjusted SP.  */
1075490075Sobrien	      dwarf = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
10755169689Skan				   plus_constant (stack_pointer_rtx,
10756169689Skan						  -fp_offset));
1075790075Sobrien	      RTX_FRAME_RELATED_P (insn) = 1;
1075890075Sobrien	      REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
1075990075Sobrien						    dwarf, REG_NOTES (insn));
1076090075Sobrien	    }
1076190075Sobrien	  else
1076290075Sobrien	    {
1076390075Sobrien	      /* Store the args on the stack.  */
1076496263Sobrien	      if (cfun->machine->uses_anonymous_args)
1076590075Sobrien		insn = emit_multi_reg_push
1076690075Sobrien		  ((0xf0 >> (args_to_push / 4)) & 0xf);
1076790075Sobrien	      else
1076890075Sobrien		insn = emit_insn
10769169689Skan		  (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
1077090075Sobrien			       GEN_INT (- args_to_push)));
1077190075Sobrien
1077290075Sobrien	      RTX_FRAME_RELATED_P (insn) = 1;
1077390075Sobrien
1077490075Sobrien	      saved_pretend_args = 1;
1077590075Sobrien	      fp_offset = args_to_push;
1077690075Sobrien	      args_to_push = 0;
1077790075Sobrien
1077890075Sobrien	      /* Now reuse r3 to preserve IP.  */
10779169689Skan	      emit_set_insn (gen_rtx_REG (SImode, 3), ip_rtx);
1078090075Sobrien	    }
1078190075Sobrien	}
1078290075Sobrien
10783169689Skan      insn = emit_set_insn (ip_rtx,
10784169689Skan			    plus_constant (stack_pointer_rtx, fp_offset));
1078590075Sobrien      RTX_FRAME_RELATED_P (insn) = 1;
1078690075Sobrien    }
1078790075Sobrien
1078890075Sobrien  if (args_to_push)
1078990075Sobrien    {
1079090075Sobrien      /* Push the argument registers, or reserve space for them.  */
1079196263Sobrien      if (cfun->machine->uses_anonymous_args)
1079290075Sobrien	insn = emit_multi_reg_push
1079390075Sobrien	  ((0xf0 >> (args_to_push / 4)) & 0xf);
1079490075Sobrien      else
1079590075Sobrien	insn = emit_insn
10796169689Skan	  (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
1079790075Sobrien		       GEN_INT (- args_to_push)));
1079890075Sobrien      RTX_FRAME_RELATED_P (insn) = 1;
1079990075Sobrien    }
1080090075Sobrien
10801117395Skan  /* If this is an interrupt service routine, and the link register
10802117395Skan     is going to be pushed, and we are not creating a stack frame,
10803117395Skan     (which would involve an extra push of IP and a pop in the epilogue)
10804117395Skan     subtracting four from LR now will mean that the function return
10805117395Skan     can be done with a single instruction.  */
1080696263Sobrien  if ((func_type == ARM_FT_ISR || func_type == ARM_FT_FIQ)
10807117395Skan      && (live_regs_mask & (1 << LR_REGNUM)) != 0
10808117395Skan      && ! frame_pointer_needed)
10809169689Skan    {
10810169689Skan      rtx lr = gen_rtx_REG (SImode, LR_REGNUM);
10811169689Skan
10812169689Skan      emit_set_insn (lr, plus_constant (lr, -4));
10813169689Skan    }
1081496263Sobrien
1081590075Sobrien  if (live_regs_mask)
1081690075Sobrien    {
1081790075Sobrien      insn = emit_multi_reg_push (live_regs_mask);
10818169689Skan      saved_regs += bit_count (live_regs_mask) * 4;
1081990075Sobrien      RTX_FRAME_RELATED_P (insn) = 1;
1082090075Sobrien    }
1082190075Sobrien
10822132718Skan  if (TARGET_IWMMXT)
10823169689Skan    for (reg = LAST_IWMMXT_REGNUM; reg >= FIRST_IWMMXT_REGNUM; reg--)
10824132718Skan      if (regs_ever_live[reg] && ! call_used_regs [reg])
10825132718Skan	{
10826132718Skan	  insn = gen_rtx_PRE_DEC (V2SImode, stack_pointer_rtx);
10827169689Skan	  insn = gen_frame_mem (V2SImode, insn);
10828169689Skan	  insn = emit_set_insn (insn, gen_rtx_REG (V2SImode, reg));
10829132718Skan	  RTX_FRAME_RELATED_P (insn) = 1;
10830169689Skan	  saved_regs += 8;
10831132718Skan	}
10832132718Skan
1083390075Sobrien  if (! IS_VOLATILE (func_type))
1083490075Sobrien    {
10835169689Skan      int start_reg;
10836169689Skan
10837132718Skan      /* Save any floating point call-saved registers used by this
10838132718Skan	 function.  */
10839132718Skan      if (arm_fpu_arch == FPUTYPE_FPA_EMU2)
1084090075Sobrien	{
10841169689Skan	  for (reg = LAST_FPA_REGNUM; reg >= FIRST_FPA_REGNUM; reg--)
1084290075Sobrien	    if (regs_ever_live[reg] && !call_used_regs[reg])
1084390075Sobrien	      {
1084490075Sobrien		insn = gen_rtx_PRE_DEC (XFmode, stack_pointer_rtx);
10845169689Skan		insn = gen_frame_mem (XFmode, insn);
10846169689Skan		insn = emit_set_insn (insn, gen_rtx_REG (XFmode, reg));
1084790075Sobrien		RTX_FRAME_RELATED_P (insn) = 1;
10848169689Skan		saved_regs += 12;
1084990075Sobrien	      }
1085090075Sobrien	}
1085190075Sobrien      else
1085290075Sobrien	{
10853169689Skan	  start_reg = LAST_FPA_REGNUM;
1085490075Sobrien
10855169689Skan	  for (reg = LAST_FPA_REGNUM; reg >= FIRST_FPA_REGNUM; reg--)
1085690075Sobrien	    {
1085790075Sobrien	      if (regs_ever_live[reg] && !call_used_regs[reg])
1085890075Sobrien		{
1085990075Sobrien		  if (start_reg - reg == 3)
1086090075Sobrien		    {
1086190075Sobrien		      insn = emit_sfm (reg, 4);
1086290075Sobrien		      RTX_FRAME_RELATED_P (insn) = 1;
10863169689Skan		      saved_regs += 48;
1086490075Sobrien		      start_reg = reg - 1;
1086590075Sobrien		    }
1086690075Sobrien		}
1086790075Sobrien	      else
1086890075Sobrien		{
1086990075Sobrien		  if (start_reg != reg)
1087090075Sobrien		    {
1087190075Sobrien		      insn = emit_sfm (reg + 1, start_reg - reg);
1087290075Sobrien		      RTX_FRAME_RELATED_P (insn) = 1;
10873169689Skan		      saved_regs += (start_reg - reg) * 12;
1087490075Sobrien		    }
1087590075Sobrien		  start_reg = reg - 1;
1087690075Sobrien		}
1087790075Sobrien	    }
1087890075Sobrien
1087990075Sobrien	  if (start_reg != reg)
1088090075Sobrien	    {
1088190075Sobrien	      insn = emit_sfm (reg + 1, start_reg - reg);
10882169689Skan	      saved_regs += (start_reg - reg) * 12;
1088390075Sobrien	      RTX_FRAME_RELATED_P (insn) = 1;
1088490075Sobrien	    }
1088590075Sobrien	}
10886169689Skan      if (TARGET_HARD_FLOAT && TARGET_VFP)
10887169689Skan	{
10888169689Skan	  start_reg = FIRST_VFP_REGNUM;
10889169689Skan
10890169689Skan 	  for (reg = FIRST_VFP_REGNUM; reg < LAST_VFP_REGNUM; reg += 2)
10891169689Skan	    {
10892169689Skan	      if ((!regs_ever_live[reg] || call_used_regs[reg])
10893169689Skan		  && (!regs_ever_live[reg + 1] || call_used_regs[reg + 1]))
10894169689Skan		{
10895169689Skan		  if (start_reg != reg)
10896169689Skan		    saved_regs += vfp_emit_fstmx (start_reg,
10897169689Skan						  (reg - start_reg) / 2);
10898169689Skan		  start_reg = reg + 2;
10899169689Skan		}
10900169689Skan	    }
10901169689Skan	  if (start_reg != reg)
10902169689Skan	    saved_regs += vfp_emit_fstmx (start_reg,
10903169689Skan					  (reg - start_reg) / 2);
10904169689Skan	}
1090590075Sobrien    }
1090690075Sobrien
1090790075Sobrien  if (frame_pointer_needed)
1090890075Sobrien    {
1090990075Sobrien      /* Create the new frame pointer.  */
1091090075Sobrien      insn = GEN_INT (-(4 + args_to_push + fp_offset));
1091190075Sobrien      insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx, ip_rtx, insn));
1091290075Sobrien      RTX_FRAME_RELATED_P (insn) = 1;
10913169689Skan
1091490075Sobrien      if (IS_NESTED (func_type))
1091590075Sobrien	{
1091690075Sobrien	  /* Recover the static chain register.  */
1091790075Sobrien	  if (regs_ever_live [3] == 0
1091890075Sobrien	      || saved_pretend_args)
1091990075Sobrien	    insn = gen_rtx_REG (SImode, 3);
1092090075Sobrien	  else /* if (current_function_pretend_args_size == 0) */
1092190075Sobrien	    {
10922169689Skan	      insn = plus_constant (hard_frame_pointer_rtx, 4);
10923169689Skan	      insn = gen_frame_mem (SImode, insn);
1092490075Sobrien	    }
1092590075Sobrien
10926169689Skan	  emit_set_insn (ip_rtx, insn);
1092790075Sobrien	  /* Add a USE to stop propagate_one_insn() from barfing.  */
1092890075Sobrien	  emit_insn (gen_prologue_use (ip_rtx));
1092990075Sobrien	}
1093090075Sobrien    }
1093190075Sobrien
10932169689Skan  offsets = arm_get_frame_offsets ();
10933169689Skan  if (offsets->outgoing_args != offsets->saved_args + saved_regs)
1093490075Sobrien    {
1093590075Sobrien      /* This add can produce multiple insns for a large constant, so we
1093690075Sobrien	 need to get tricky.  */
1093790075Sobrien      rtx last = get_last_insn ();
10938169689Skan
10939169689Skan      amount = GEN_INT (offsets->saved_args + saved_regs
10940169689Skan			- offsets->outgoing_args);
10941169689Skan
1094290075Sobrien      insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
1094390075Sobrien				    amount));
1094490075Sobrien      do
1094590075Sobrien	{
1094690075Sobrien	  last = last ? NEXT_INSN (last) : get_insns ();
1094790075Sobrien	  RTX_FRAME_RELATED_P (last) = 1;
1094890075Sobrien	}
1094990075Sobrien      while (last != insn);
1095090075Sobrien
1095190075Sobrien      /* If the frame pointer is needed, emit a special barrier that
1095290075Sobrien	 will prevent the scheduler from moving stores to the frame
1095390075Sobrien	 before the stack adjustment.  */
1095490075Sobrien      if (frame_pointer_needed)
10955117395Skan	insn = emit_insn (gen_stack_tie (stack_pointer_rtx,
10956117395Skan					 hard_frame_pointer_rtx));
1095790075Sobrien    }
1095890075Sobrien
10959169689Skan
10960169689Skan  if (flag_pic && arm_pic_register != INVALID_REGNUM)
10961169689Skan    arm_load_pic_register (0UL);
10962169689Skan
1096390075Sobrien  /* If we are profiling, make sure no instructions are scheduled before
1096490075Sobrien     the call to mcount.  Similarly if the user has requested no
10965169689Skan     scheduling in the prolog.  Similarly if we want non-call exceptions
10966169689Skan     using the EABI unwinder, to prevent faulting instructions from being
10967169689Skan     swapped with a stack adjustment.  */
10968169689Skan  if (current_function_profile || !TARGET_SCHED_PROLOG
10969169689Skan      || (ARM_EABI_UNWIND_TABLES && flag_non_call_exceptions))
1097090075Sobrien    emit_insn (gen_blockage ());
1097190075Sobrien
1097290075Sobrien  /* If the link register is being kept alive, with the return address in it,
1097390075Sobrien     then make sure that it does not get reused by the ce2 pass.  */
1097490075Sobrien  if ((live_regs_mask & (1 << LR_REGNUM)) == 0)
1097590075Sobrien    {
1097690075Sobrien      emit_insn (gen_prologue_use (gen_rtx_REG (SImode, LR_REGNUM)));
1097790075Sobrien      cfun->machine->lr_save_eliminated = 1;
1097890075Sobrien    }
1097990075Sobrien}
1098090075Sobrien
1098190075Sobrien/* If CODE is 'd', then the X is a condition operand and the instruction
1098290075Sobrien   should only be executed if the condition is true.
1098390075Sobrien   if CODE is 'D', then the X is a condition operand and the instruction
1098490075Sobrien   should only be executed if the condition is false: however, if the mode
1098590075Sobrien   of the comparison is CCFPEmode, then always execute the instruction -- we
1098690075Sobrien   do this because in these circumstances !GE does not necessarily imply LT;
1098790075Sobrien   in these cases the instruction pattern will take care to make sure that
1098890075Sobrien   an instruction containing %d will follow, thereby undoing the effects of
1098990075Sobrien   doing this instruction unconditionally.
1099090075Sobrien   If CODE is 'N' then X is a floating point operand that must be negated
1099190075Sobrien   before output.
1099290075Sobrien   If CODE is 'B' then output a bitwise inverted value of X (a const int).
1099390075Sobrien   If X is a REG and CODE is `M', output a ldm/stm style multi-reg.  */
1099490075Sobrienvoid
10995132718Skanarm_print_operand (FILE *stream, rtx x, int code)
1099690075Sobrien{
1099790075Sobrien  switch (code)
1099890075Sobrien    {
1099990075Sobrien    case '@':
1100090075Sobrien      fputs (ASM_COMMENT_START, stream);
1100190075Sobrien      return;
1100290075Sobrien
1100390075Sobrien    case '_':
1100490075Sobrien      fputs (user_label_prefix, stream);
1100590075Sobrien      return;
11006169689Skan
1100790075Sobrien    case '|':
1100890075Sobrien      fputs (REGISTER_PREFIX, stream);
1100990075Sobrien      return;
1101090075Sobrien
1101190075Sobrien    case '?':
1101290075Sobrien      if (arm_ccfsm_state == 3 || arm_ccfsm_state == 4)
1101390075Sobrien	{
11014169689Skan	  if (TARGET_THUMB)
11015169689Skan	    {
11016169689Skan	      output_operand_lossage ("predicated Thumb instruction");
11017169689Skan	      break;
11018169689Skan	    }
11019169689Skan	  if (current_insn_predicate != NULL)
11020169689Skan	    {
11021169689Skan	      output_operand_lossage
11022169689Skan		("predicated instruction in conditional sequence");
11023169689Skan	      break;
11024169689Skan	    }
1102590075Sobrien
1102690075Sobrien	  fputs (arm_condition_codes[arm_current_cc], stream);
1102790075Sobrien	}
1102890075Sobrien      else if (current_insn_predicate)
1102990075Sobrien	{
1103090075Sobrien	  enum arm_cond_code code;
1103190075Sobrien
1103290075Sobrien	  if (TARGET_THUMB)
11033169689Skan	    {
11034169689Skan	      output_operand_lossage ("predicated Thumb instruction");
11035169689Skan	      break;
11036169689Skan	    }
1103790075Sobrien
1103890075Sobrien	  code = get_arm_condition_code (current_insn_predicate);
1103990075Sobrien	  fputs (arm_condition_codes[code], stream);
1104090075Sobrien	}
1104190075Sobrien      return;
1104290075Sobrien
1104390075Sobrien    case 'N':
1104490075Sobrien      {
1104590075Sobrien	REAL_VALUE_TYPE r;
1104690075Sobrien	REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1104790075Sobrien	r = REAL_VALUE_NEGATE (r);
1104890075Sobrien	fprintf (stream, "%s", fp_const_from_val (&r));
1104990075Sobrien      }
1105090075Sobrien      return;
1105190075Sobrien
1105290075Sobrien    case 'B':
1105390075Sobrien      if (GET_CODE (x) == CONST_INT)
1105490075Sobrien	{
1105590075Sobrien	  HOST_WIDE_INT val;
1105690075Sobrien	  val = ARM_SIGN_EXTEND (~INTVAL (x));
1105790075Sobrien	  fprintf (stream, HOST_WIDE_INT_PRINT_DEC, val);
1105890075Sobrien	}
1105990075Sobrien      else
1106090075Sobrien	{
1106190075Sobrien	  putc ('~', stream);
1106290075Sobrien	  output_addr_const (stream, x);
1106390075Sobrien	}
1106490075Sobrien      return;
1106590075Sobrien
1106690075Sobrien    case 'i':
1106790075Sobrien      fprintf (stream, "%s", arithmetic_instr (x, 1));
1106890075Sobrien      return;
1106990075Sobrien
11070132718Skan    /* Truncate Cirrus shift counts.  */
11071132718Skan    case 's':
11072132718Skan      if (GET_CODE (x) == CONST_INT)
11073132718Skan	{
11074132718Skan	  fprintf (stream, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) & 0x3f);
11075132718Skan	  return;
11076132718Skan	}
11077132718Skan      arm_print_operand (stream, x, 0);
11078132718Skan      return;
11079132718Skan
1108090075Sobrien    case 'I':
1108190075Sobrien      fprintf (stream, "%s", arithmetic_instr (x, 0));
1108290075Sobrien      return;
1108390075Sobrien
1108490075Sobrien    case 'S':
1108590075Sobrien      {
1108690075Sobrien	HOST_WIDE_INT val;
11087169689Skan	const char *shift;
1108890075Sobrien
11089169689Skan	if (!shift_operator (x, SImode))
11090169689Skan	  {
11091169689Skan	    output_operand_lossage ("invalid shift operand");
11092169689Skan	    break;
11093169689Skan	  }
11094169689Skan
11095169689Skan	shift = shift_op (x, &val);
11096169689Skan
1109790075Sobrien	if (shift)
1109890075Sobrien	  {
11099169689Skan	    fprintf (stream, ", %s ", shift);
1110090075Sobrien	    if (val == -1)
1110190075Sobrien	      arm_print_operand (stream, XEXP (x, 1), 0);
1110290075Sobrien	    else
11103132718Skan	      fprintf (stream, "#" HOST_WIDE_INT_PRINT_DEC, val);
1110490075Sobrien	  }
1110590075Sobrien      }
1110690075Sobrien      return;
1110790075Sobrien
1110890075Sobrien      /* An explanation of the 'Q', 'R' and 'H' register operands:
11109169689Skan
1111090075Sobrien	 In a pair of registers containing a DI or DF value the 'Q'
1111190075Sobrien	 operand returns the register number of the register containing
11112132718Skan	 the least significant part of the value.  The 'R' operand returns
1111390075Sobrien	 the register number of the register containing the most
1111490075Sobrien	 significant part of the value.
11115169689Skan
1111690075Sobrien	 The 'H' operand returns the higher of the two register numbers.
1111790075Sobrien	 On a run where WORDS_BIG_ENDIAN is true the 'H' operand is the
11118132718Skan	 same as the 'Q' operand, since the most significant part of the
1111990075Sobrien	 value is held in the lower number register.  The reverse is true
1112090075Sobrien	 on systems where WORDS_BIG_ENDIAN is false.
11121169689Skan
1112290075Sobrien	 The purpose of these operands is to distinguish between cases
1112390075Sobrien	 where the endian-ness of the values is important (for example
1112490075Sobrien	 when they are added together), and cases where the endian-ness
1112590075Sobrien	 is irrelevant, but the order of register operations is important.
1112690075Sobrien	 For example when loading a value from memory into a register
1112790075Sobrien	 pair, the endian-ness does not matter.  Provided that the value
1112890075Sobrien	 from the lower memory address is put into the lower numbered
1112990075Sobrien	 register, and the value from the higher address is put into the
1113090075Sobrien	 higher numbered register, the load will work regardless of whether
1113190075Sobrien	 the value being loaded is big-wordian or little-wordian.  The
1113290075Sobrien	 order of the two register loads can matter however, if the address
1113390075Sobrien	 of the memory location is actually held in one of the registers
1113490075Sobrien	 being overwritten by the load.  */
1113590075Sobrien    case 'Q':
11136169689Skan      if (GET_CODE (x) != REG || REGNO (x) > LAST_ARM_REGNUM)
11137169689Skan	{
11138169689Skan	  output_operand_lossage ("invalid operand for code '%c'", code);
11139169689Skan	  return;
11140169689Skan	}
11141169689Skan
1114290075Sobrien      asm_fprintf (stream, "%r", REGNO (x) + (WORDS_BIG_ENDIAN ? 1 : 0));
1114390075Sobrien      return;
1114490075Sobrien
1114590075Sobrien    case 'R':
11146169689Skan      if (GET_CODE (x) != REG || REGNO (x) > LAST_ARM_REGNUM)
11147169689Skan	{
11148169689Skan	  output_operand_lossage ("invalid operand for code '%c'", code);
11149169689Skan	  return;
11150169689Skan	}
11151169689Skan
1115290075Sobrien      asm_fprintf (stream, "%r", REGNO (x) + (WORDS_BIG_ENDIAN ? 0 : 1));
1115390075Sobrien      return;
1115490075Sobrien
1115590075Sobrien    case 'H':
11156169689Skan      if (GET_CODE (x) != REG || REGNO (x) > LAST_ARM_REGNUM)
11157169689Skan	{
11158169689Skan	  output_operand_lossage ("invalid operand for code '%c'", code);
11159169689Skan	  return;
11160169689Skan	}
11161169689Skan
1116290075Sobrien      asm_fprintf (stream, "%r", REGNO (x) + 1);
1116390075Sobrien      return;
1116490075Sobrien
1116590075Sobrien    case 'm':
11166169689Skan      asm_fprintf (stream, "%r",
1116790075Sobrien		   GET_CODE (XEXP (x, 0)) == REG
1116890075Sobrien		   ? REGNO (XEXP (x, 0)) : REGNO (XEXP (XEXP (x, 0), 0)));
1116990075Sobrien      return;
1117090075Sobrien
1117190075Sobrien    case 'M':
1117290075Sobrien      asm_fprintf (stream, "{%r-%r}",
1117390075Sobrien		   REGNO (x),
11174117395Skan		   REGNO (x) + ARM_NUM_REGS (GET_MODE (x)) - 1);
1117590075Sobrien      return;
1117690075Sobrien
1117790075Sobrien    case 'd':
11178117395Skan      /* CONST_TRUE_RTX means always -- that's the default.  */
11179117395Skan      if (x == const_true_rtx)
1118090075Sobrien	return;
11181169689Skan
11182169689Skan      if (!COMPARISON_P (x))
11183169689Skan	{
11184169689Skan	  output_operand_lossage ("invalid operand for code '%c'", code);
11185169689Skan	  return;
11186169689Skan	}
11187169689Skan
11188132718Skan      fputs (arm_condition_codes[get_arm_condition_code (x)],
11189132718Skan	     stream);
1119090075Sobrien      return;
1119190075Sobrien
1119290075Sobrien    case 'D':
11193169689Skan      /* CONST_TRUE_RTX means not always -- i.e. never.  We shouldn't ever
11194117395Skan	 want to do that.  */
11195117395Skan      if (x == const_true_rtx)
11196169689Skan	{
11197169689Skan	  output_operand_lossage ("instruction never exectued");
11198169689Skan	  return;
11199169689Skan	}
11200169689Skan      if (!COMPARISON_P (x))
11201169689Skan	{
11202169689Skan	  output_operand_lossage ("invalid operand for code '%c'", code);
11203169689Skan	  return;
11204169689Skan	}
1120590075Sobrien
11206132718Skan      fputs (arm_condition_codes[ARM_INVERSE_CONDITION_CODE
11207132718Skan				 (get_arm_condition_code (x))],
11208132718Skan	     stream);
11209132718Skan      return;
11210132718Skan
11211132718Skan    /* Cirrus registers can be accessed in a variety of ways:
11212132718Skan         single floating point (f)
11213132718Skan	 double floating point (d)
11214132718Skan	 32bit integer         (fx)
11215132718Skan	 64bit integer         (dx).  */
11216132718Skan    case 'W':			/* Cirrus register in F mode.  */
11217132718Skan    case 'X':			/* Cirrus register in D mode.  */
11218132718Skan    case 'Y':			/* Cirrus register in FX mode.  */
11219132718Skan    case 'Z':			/* Cirrus register in DX mode.  */
11220169689Skan      gcc_assert (GET_CODE (x) == REG
11221169689Skan		  && REGNO_REG_CLASS (REGNO (x)) == CIRRUS_REGS);
11222132718Skan
11223132718Skan      fprintf (stream, "mv%s%s",
11224132718Skan	       code == 'W' ? "f"
11225132718Skan	       : code == 'X' ? "d"
11226132718Skan	       : code == 'Y' ? "fx" : "dx", reg_names[REGNO (x)] + 2);
11227132718Skan
11228132718Skan      return;
11229132718Skan
11230132718Skan    /* Print cirrus register in the mode specified by the register's mode.  */
11231132718Skan    case 'V':
11232132718Skan      {
11233132718Skan	int mode = GET_MODE (x);
11234132718Skan
11235132718Skan	if (GET_CODE (x) != REG || REGNO_REG_CLASS (REGNO (x)) != CIRRUS_REGS)
11236169689Skan	  {
11237169689Skan	    output_operand_lossage ("invalid operand for code '%c'", code);
11238169689Skan	    return;
11239169689Skan	  }
11240132718Skan
11241132718Skan	fprintf (stream, "mv%s%s",
11242132718Skan		 mode == DFmode ? "d"
11243132718Skan		 : mode == SImode ? "fx"
11244132718Skan		 : mode == DImode ? "dx"
11245132718Skan		 : "f", reg_names[REGNO (x)] + 2);
11246132718Skan
11247132718Skan	return;
11248132718Skan      }
11249132718Skan
11250132718Skan    case 'U':
11251132718Skan      if (GET_CODE (x) != REG
11252132718Skan	  || REGNO (x) < FIRST_IWMMXT_GR_REGNUM
11253132718Skan	  || REGNO (x) > LAST_IWMMXT_GR_REGNUM)
11254132718Skan	/* Bad value for wCG register number.  */
11255169689Skan	{
11256169689Skan	  output_operand_lossage ("invalid operand for code '%c'", code);
11257169689Skan	  return;
11258169689Skan	}
11259169689Skan
1126090075Sobrien      else
11261132718Skan	fprintf (stream, "%d", REGNO (x) - FIRST_IWMMXT_GR_REGNUM);
1126290075Sobrien      return;
1126390075Sobrien
11264132718Skan      /* Print an iWMMXt control register name.  */
11265132718Skan    case 'w':
11266132718Skan      if (GET_CODE (x) != CONST_INT
11267132718Skan	  || INTVAL (x) < 0
11268132718Skan	  || INTVAL (x) >= 16)
11269132718Skan	/* Bad value for wC register number.  */
11270169689Skan	{
11271169689Skan	  output_operand_lossage ("invalid operand for code '%c'", code);
11272169689Skan	  return;
11273169689Skan	}
11274169689Skan
11275132718Skan      else
11276132718Skan	{
11277132718Skan	  static const char * wc_reg_names [16] =
11278132718Skan	    {
11279132718Skan	      "wCID",  "wCon",  "wCSSF", "wCASF",
11280132718Skan	      "wC4",   "wC5",   "wC6",   "wC7",
11281132718Skan	      "wCGR0", "wCGR1", "wCGR2", "wCGR3",
11282132718Skan	      "wC12",  "wC13",  "wC14",  "wC15"
11283132718Skan	    };
11284169689Skan
11285132718Skan	  fprintf (stream, wc_reg_names [INTVAL (x)]);
11286132718Skan	}
11287132718Skan      return;
11288132718Skan
11289169689Skan      /* Print a VFP double precision register name.  */
11290169689Skan    case 'P':
11291169689Skan      {
11292169689Skan	int mode = GET_MODE (x);
11293169689Skan	int num;
11294169689Skan
11295169689Skan	if (mode != DImode && mode != DFmode)
11296169689Skan	  {
11297169689Skan	    output_operand_lossage ("invalid operand for code '%c'", code);
11298169689Skan	    return;
11299169689Skan	  }
11300169689Skan
11301169689Skan	if (GET_CODE (x) != REG
11302169689Skan	    || !IS_VFP_REGNUM (REGNO (x)))
11303169689Skan	  {
11304169689Skan	    output_operand_lossage ("invalid operand for code '%c'", code);
11305169689Skan	    return;
11306169689Skan	  }
11307169689Skan
11308169689Skan	num = REGNO(x) - FIRST_VFP_REGNUM;
11309169689Skan	if (num & 1)
11310169689Skan	  {
11311169689Skan	    output_operand_lossage ("invalid operand for code '%c'", code);
11312169689Skan	    return;
11313169689Skan	  }
11314169689Skan
11315169689Skan	fprintf (stream, "d%d", num >> 1);
11316169689Skan      }
11317169689Skan      return;
11318169689Skan
1131990075Sobrien    default:
1132090075Sobrien      if (x == 0)
11321169689Skan	{
11322169689Skan	  output_operand_lossage ("missing operand");
11323169689Skan	  return;
11324169689Skan	}
1132590075Sobrien
11326169689Skan      switch (GET_CODE (x))
1132790075Sobrien	{
11328169689Skan	case REG:
11329169689Skan	  asm_fprintf (stream, "%r", REGNO (x));
11330169689Skan	  break;
11331169689Skan
11332169689Skan	case MEM:
1133390075Sobrien	  output_memory_reference_mode = GET_MODE (x);
1133490075Sobrien	  output_address (XEXP (x, 0));
11335169689Skan	  break;
11336169689Skan
11337169689Skan	case CONST_DOUBLE:
11338169689Skan	  fprintf (stream, "#%s", fp_immediate_constant (x));
11339169689Skan	  break;
11340169689Skan
11341169689Skan	default:
11342169689Skan	  gcc_assert (GET_CODE (x) != NEG);
1134390075Sobrien	  fputc ('#', stream);
1134490075Sobrien	  output_addr_const (stream, x);
11345169689Skan	  break;
1134690075Sobrien	}
1134790075Sobrien    }
1134890075Sobrien}
1134990075Sobrien
1135090075Sobrien#ifndef AOF_ASSEMBLER
1135190075Sobrien/* Target hook for assembling integer objects.  The ARM version needs to
1135290075Sobrien   handle word-sized values specially.  */
1135390075Sobrienstatic bool
11354132718Skanarm_assemble_integer (rtx x, unsigned int size, int aligned_p)
1135590075Sobrien{
1135690075Sobrien  if (size == UNITS_PER_WORD && aligned_p)
1135790075Sobrien    {
1135890075Sobrien      fputs ("\t.word\t", asm_out_file);
1135990075Sobrien      output_addr_const (asm_out_file, x);
1136090075Sobrien
1136190075Sobrien      /* Mark symbols as position independent.  We only do this in the
11362132718Skan	 .text segment, not in the .data segment.  */
1136390075Sobrien      if (NEED_GOT_RELOC && flag_pic && making_const_table &&
1136490075Sobrien	  (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF))
1136590075Sobrien	{
11366117395Skan	  if (GET_CODE (x) == SYMBOL_REF
1136796263Sobrien	      && (CONSTANT_POOL_ADDRESS_P (x)
11368132718Skan		  || SYMBOL_REF_LOCAL_P (x)))
1136990075Sobrien	    fputs ("(GOTOFF)", asm_out_file);
1137090075Sobrien	  else if (GET_CODE (x) == LABEL_REF)
1137190075Sobrien	    fputs ("(GOTOFF)", asm_out_file);
1137290075Sobrien	  else
1137390075Sobrien	    fputs ("(GOT)", asm_out_file);
1137490075Sobrien	}
1137590075Sobrien      fputc ('\n', asm_out_file);
1137690075Sobrien      return true;
1137790075Sobrien    }
1137890075Sobrien
11379169689Skan  if (arm_vector_mode_supported_p (GET_MODE (x)))
11380132718Skan    {
11381132718Skan      int i, units;
11382132718Skan
11383169689Skan      gcc_assert (GET_CODE (x) == CONST_VECTOR);
11384132718Skan
11385132718Skan      units = CONST_VECTOR_NUNITS (x);
11386132718Skan
11387132718Skan      switch (GET_MODE (x))
11388132718Skan	{
11389132718Skan	case V2SImode: size = 4; break;
11390132718Skan	case V4HImode: size = 2; break;
11391132718Skan	case V8QImode: size = 1; break;
11392132718Skan	default:
11393169689Skan	  gcc_unreachable ();
11394132718Skan	}
11395132718Skan
11396132718Skan      for (i = 0; i < units; i++)
11397132718Skan	{
11398132718Skan	  rtx elt;
11399132718Skan
11400132718Skan	  elt = CONST_VECTOR_ELT (x, i);
11401132718Skan	  assemble_integer
11402132718Skan	    (elt, size, i == 0 ? BIGGEST_ALIGNMENT : size * BITS_PER_UNIT, 1);
11403132718Skan	}
11404132718Skan
11405132718Skan      return true;
11406132718Skan    }
11407132718Skan
1140890075Sobrien  return default_assemble_integer (x, size, aligned_p);
1140990075Sobrien}
11410169689Skan
11411169689Skan
11412169689Skan/* Add a function to the list of static constructors.  */
11413169689Skan
11414169689Skanstatic void
11415169689Skanarm_elf_asm_constructor (rtx symbol, int priority ATTRIBUTE_UNUSED)
11416169689Skan{
11417169689Skan  if (!TARGET_AAPCS_BASED)
11418169689Skan    {
11419169689Skan      default_named_section_asm_out_constructor (symbol, priority);
11420169689Skan      return;
11421169689Skan    }
11422169689Skan
11423169689Skan  /* Put these in the .init_array section, using a special relocation.  */
11424169689Skan  switch_to_section (ctors_section);
11425169689Skan  assemble_align (POINTER_SIZE);
11426169689Skan  fputs ("\t.word\t", asm_out_file);
11427169689Skan  output_addr_const (asm_out_file, symbol);
11428169689Skan  fputs ("(target1)\n", asm_out_file);
11429169689Skan}
1143090075Sobrien#endif
1143190075Sobrien
1143290075Sobrien/* A finite state machine takes care of noticing whether or not instructions
1143390075Sobrien   can be conditionally executed, and thus decrease execution time and code
1143490075Sobrien   size by deleting branch instructions.  The fsm is controlled by
1143590075Sobrien   final_prescan_insn, and controls the actions of ASM_OUTPUT_OPCODE.  */
1143690075Sobrien
1143790075Sobrien/* The state of the fsm controlling condition codes are:
1143890075Sobrien   0: normal, do nothing special
1143990075Sobrien   1: make ASM_OUTPUT_OPCODE not output this instruction
1144090075Sobrien   2: make ASM_OUTPUT_OPCODE not output this instruction
1144190075Sobrien   3: make instructions conditional
1144290075Sobrien   4: make instructions conditional
1144390075Sobrien
1144490075Sobrien   State transitions (state->state by whom under condition):
1144590075Sobrien   0 -> 1 final_prescan_insn if the `target' is a label
1144690075Sobrien   0 -> 2 final_prescan_insn if the `target' is an unconditional branch
1144790075Sobrien   1 -> 3 ASM_OUTPUT_OPCODE after not having output the conditional branch
1144890075Sobrien   2 -> 4 ASM_OUTPUT_OPCODE after not having output the conditional branch
11449132718Skan   3 -> 0 (*targetm.asm_out.internal_label) if the `target' label is reached
1145090075Sobrien          (the target label has CODE_LABEL_NUMBER equal to arm_target_label).
1145190075Sobrien   4 -> 0 final_prescan_insn if the `target' unconditional branch is reached
1145290075Sobrien          (the target insn is arm_target_insn).
1145390075Sobrien
1145490075Sobrien   If the jump clobbers the conditions then we use states 2 and 4.
1145590075Sobrien
1145690075Sobrien   A similar thing can be done with conditional return insns.
1145790075Sobrien
1145890075Sobrien   XXX In case the `target' is an unconditional branch, this conditionalising
1145990075Sobrien   of the instructions always reduces code size, but not always execution
1146090075Sobrien   time.  But then, I want to reduce the code size to somewhere near what
1146190075Sobrien   /bin/cc produces.  */
1146290075Sobrien
1146390075Sobrien/* Returns the index of the ARM condition code string in
1146490075Sobrien   `arm_condition_codes'.  COMPARISON should be an rtx like
1146590075Sobrien   `(eq (...) (...))'.  */
1146690075Sobrienstatic enum arm_cond_code
11467132718Skanget_arm_condition_code (rtx comparison)
1146890075Sobrien{
1146990075Sobrien  enum machine_mode mode = GET_MODE (XEXP (comparison, 0));
1147090075Sobrien  int code;
1147190075Sobrien  enum rtx_code comp_code = GET_CODE (comparison);
1147290075Sobrien
1147390075Sobrien  if (GET_MODE_CLASS (mode) != MODE_CC)
1147490075Sobrien    mode = SELECT_CC_MODE (comp_code, XEXP (comparison, 0),
1147590075Sobrien			   XEXP (comparison, 1));
1147690075Sobrien
1147790075Sobrien  switch (mode)
1147890075Sobrien    {
1147990075Sobrien    case CC_DNEmode: code = ARM_NE; goto dominance;
1148090075Sobrien    case CC_DEQmode: code = ARM_EQ; goto dominance;
1148190075Sobrien    case CC_DGEmode: code = ARM_GE; goto dominance;
1148290075Sobrien    case CC_DGTmode: code = ARM_GT; goto dominance;
1148390075Sobrien    case CC_DLEmode: code = ARM_LE; goto dominance;
1148490075Sobrien    case CC_DLTmode: code = ARM_LT; goto dominance;
1148590075Sobrien    case CC_DGEUmode: code = ARM_CS; goto dominance;
1148690075Sobrien    case CC_DGTUmode: code = ARM_HI; goto dominance;
1148790075Sobrien    case CC_DLEUmode: code = ARM_LS; goto dominance;
1148890075Sobrien    case CC_DLTUmode: code = ARM_CC;
1148990075Sobrien
1149090075Sobrien    dominance:
11491169689Skan      gcc_assert (comp_code == EQ || comp_code == NE);
1149290075Sobrien
1149390075Sobrien      if (comp_code == EQ)
1149490075Sobrien	return ARM_INVERSE_CONDITION_CODE (code);
1149590075Sobrien      return code;
1149690075Sobrien
1149790075Sobrien    case CC_NOOVmode:
1149890075Sobrien      switch (comp_code)
1149990075Sobrien	{
1150090075Sobrien	case NE: return ARM_NE;
1150190075Sobrien	case EQ: return ARM_EQ;
1150290075Sobrien	case GE: return ARM_PL;
1150390075Sobrien	case LT: return ARM_MI;
11504169689Skan	default: gcc_unreachable ();
1150590075Sobrien	}
1150690075Sobrien
1150790075Sobrien    case CC_Zmode:
1150890075Sobrien      switch (comp_code)
1150990075Sobrien	{
1151090075Sobrien	case NE: return ARM_NE;
1151190075Sobrien	case EQ: return ARM_EQ;
11512169689Skan	default: gcc_unreachable ();
1151390075Sobrien	}
1151490075Sobrien
11515132718Skan    case CC_Nmode:
11516132718Skan      switch (comp_code)
11517132718Skan	{
11518132718Skan	case NE: return ARM_MI;
11519132718Skan	case EQ: return ARM_PL;
11520169689Skan	default: gcc_unreachable ();
11521132718Skan	}
11522132718Skan
1152390075Sobrien    case CCFPEmode:
1152490075Sobrien    case CCFPmode:
1152590075Sobrien      /* These encodings assume that AC=1 in the FPA system control
1152690075Sobrien	 byte.  This allows us to handle all cases except UNEQ and
1152790075Sobrien	 LTGT.  */
1152890075Sobrien      switch (comp_code)
1152990075Sobrien	{
1153090075Sobrien	case GE: return ARM_GE;
1153190075Sobrien	case GT: return ARM_GT;
1153290075Sobrien	case LE: return ARM_LS;
1153390075Sobrien	case LT: return ARM_MI;
1153490075Sobrien	case NE: return ARM_NE;
1153590075Sobrien	case EQ: return ARM_EQ;
1153690075Sobrien	case ORDERED: return ARM_VC;
1153790075Sobrien	case UNORDERED: return ARM_VS;
1153890075Sobrien	case UNLT: return ARM_LT;
1153990075Sobrien	case UNLE: return ARM_LE;
1154090075Sobrien	case UNGT: return ARM_HI;
1154190075Sobrien	case UNGE: return ARM_PL;
1154290075Sobrien	  /* UNEQ and LTGT do not have a representation.  */
1154390075Sobrien	case UNEQ: /* Fall through.  */
1154490075Sobrien	case LTGT: /* Fall through.  */
11545169689Skan	default: gcc_unreachable ();
1154690075Sobrien	}
1154790075Sobrien
1154890075Sobrien    case CC_SWPmode:
1154990075Sobrien      switch (comp_code)
1155090075Sobrien	{
1155190075Sobrien	case NE: return ARM_NE;
1155290075Sobrien	case EQ: return ARM_EQ;
1155390075Sobrien	case GE: return ARM_LE;
1155490075Sobrien	case GT: return ARM_LT;
1155590075Sobrien	case LE: return ARM_GE;
1155690075Sobrien	case LT: return ARM_GT;
1155790075Sobrien	case GEU: return ARM_LS;
1155890075Sobrien	case GTU: return ARM_CC;
1155990075Sobrien	case LEU: return ARM_CS;
1156090075Sobrien	case LTU: return ARM_HI;
11561169689Skan	default: gcc_unreachable ();
1156290075Sobrien	}
1156390075Sobrien
1156490075Sobrien    case CC_Cmode:
1156590075Sobrien      switch (comp_code)
1156690075Sobrien      {
1156790075Sobrien      case LTU: return ARM_CS;
1156890075Sobrien      case GEU: return ARM_CC;
11569169689Skan      default: gcc_unreachable ();
1157090075Sobrien      }
11571169689Skan
1157290075Sobrien    case CCmode:
1157390075Sobrien      switch (comp_code)
1157490075Sobrien	{
1157590075Sobrien	case NE: return ARM_NE;
1157690075Sobrien	case EQ: return ARM_EQ;
1157790075Sobrien	case GE: return ARM_GE;
1157890075Sobrien	case GT: return ARM_GT;
1157990075Sobrien	case LE: return ARM_LE;
1158090075Sobrien	case LT: return ARM_LT;
1158190075Sobrien	case GEU: return ARM_CS;
1158290075Sobrien	case GTU: return ARM_HI;
1158390075Sobrien	case LEU: return ARM_LS;
1158490075Sobrien	case LTU: return ARM_CC;
11585169689Skan	default: gcc_unreachable ();
1158690075Sobrien	}
1158790075Sobrien
11588169689Skan    default: gcc_unreachable ();
1158990075Sobrien    }
1159090075Sobrien}
1159190075Sobrien
1159290075Sobrienvoid
11593132718Skanarm_final_prescan_insn (rtx insn)
1159490075Sobrien{
1159590075Sobrien  /* BODY will hold the body of INSN.  */
1159690075Sobrien  rtx body = PATTERN (insn);
1159790075Sobrien
1159890075Sobrien  /* This will be 1 if trying to repeat the trick, and things need to be
1159990075Sobrien     reversed if it appears to fail.  */
1160090075Sobrien  int reverse = 0;
1160190075Sobrien
1160290075Sobrien  /* JUMP_CLOBBERS will be one implies that the conditions if a branch is
1160390075Sobrien     taken are clobbered, even if the rtl suggests otherwise.  It also
1160490075Sobrien     means that we have to grub around within the jump expression to find
1160590075Sobrien     out what the conditions are when the jump isn't taken.  */
1160690075Sobrien  int jump_clobbers = 0;
11607169689Skan
1160890075Sobrien  /* If we start with a return insn, we only succeed if we find another one.  */
1160990075Sobrien  int seeking_return = 0;
11610169689Skan
1161190075Sobrien  /* START_INSN will hold the insn from where we start looking.  This is the
1161290075Sobrien     first insn after the following code_label if REVERSE is true.  */
1161390075Sobrien  rtx start_insn = insn;
1161490075Sobrien
1161590075Sobrien  /* If in state 4, check if the target branch is reached, in order to
1161690075Sobrien     change back to state 0.  */
1161790075Sobrien  if (arm_ccfsm_state == 4)
1161890075Sobrien    {
1161990075Sobrien      if (insn == arm_target_insn)
1162090075Sobrien	{
1162190075Sobrien	  arm_target_insn = NULL;
1162290075Sobrien	  arm_ccfsm_state = 0;
1162390075Sobrien	}
1162490075Sobrien      return;
1162590075Sobrien    }
1162690075Sobrien
1162790075Sobrien  /* If in state 3, it is possible to repeat the trick, if this insn is an
1162890075Sobrien     unconditional branch to a label, and immediately following this branch
1162990075Sobrien     is the previous target label which is only used once, and the label this
1163090075Sobrien     branch jumps to is not too far off.  */
1163190075Sobrien  if (arm_ccfsm_state == 3)
1163290075Sobrien    {
1163390075Sobrien      if (simplejump_p (insn))
1163490075Sobrien	{
1163590075Sobrien	  start_insn = next_nonnote_insn (start_insn);
1163690075Sobrien	  if (GET_CODE (start_insn) == BARRIER)
1163790075Sobrien	    {
1163890075Sobrien	      /* XXX Isn't this always a barrier?  */
1163990075Sobrien	      start_insn = next_nonnote_insn (start_insn);
1164090075Sobrien	    }
1164190075Sobrien	  if (GET_CODE (start_insn) == CODE_LABEL
1164290075Sobrien	      && CODE_LABEL_NUMBER (start_insn) == arm_target_label
1164390075Sobrien	      && LABEL_NUSES (start_insn) == 1)
1164490075Sobrien	    reverse = TRUE;
1164590075Sobrien	  else
1164690075Sobrien	    return;
1164790075Sobrien	}
1164890075Sobrien      else if (GET_CODE (body) == RETURN)
1164990075Sobrien        {
1165090075Sobrien	  start_insn = next_nonnote_insn (start_insn);
1165190075Sobrien	  if (GET_CODE (start_insn) == BARRIER)
1165290075Sobrien	    start_insn = next_nonnote_insn (start_insn);
1165390075Sobrien	  if (GET_CODE (start_insn) == CODE_LABEL
1165490075Sobrien	      && CODE_LABEL_NUMBER (start_insn) == arm_target_label
1165590075Sobrien	      && LABEL_NUSES (start_insn) == 1)
1165690075Sobrien	    {
1165790075Sobrien	      reverse = TRUE;
1165890075Sobrien	      seeking_return = 1;
1165990075Sobrien	    }
1166090075Sobrien	  else
1166190075Sobrien	    return;
1166290075Sobrien        }
1166390075Sobrien      else
1166490075Sobrien	return;
1166590075Sobrien    }
1166690075Sobrien
11667169689Skan  gcc_assert (!arm_ccfsm_state || reverse);
1166890075Sobrien  if (GET_CODE (insn) != JUMP_INSN)
1166990075Sobrien    return;
1167090075Sobrien
11671169689Skan  /* This jump might be paralleled with a clobber of the condition codes
1167290075Sobrien     the jump should always come first */
1167390075Sobrien  if (GET_CODE (body) == PARALLEL && XVECLEN (body, 0) > 0)
1167490075Sobrien    body = XVECEXP (body, 0, 0);
1167590075Sobrien
1167690075Sobrien  if (reverse
1167790075Sobrien      || (GET_CODE (body) == SET && GET_CODE (SET_DEST (body)) == PC
1167890075Sobrien	  && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE))
1167990075Sobrien    {
1168090075Sobrien      int insns_skipped;
1168190075Sobrien      int fail = FALSE, succeed = FALSE;
1168290075Sobrien      /* Flag which part of the IF_THEN_ELSE is the LABEL_REF.  */
1168390075Sobrien      int then_not_else = TRUE;
1168490075Sobrien      rtx this_insn = start_insn, label = 0;
1168590075Sobrien
11686169689Skan      /* If the jump cannot be done with one instruction, we cannot
1168790075Sobrien	 conditionally execute the instruction in the inverse case.  */
1168890075Sobrien      if (get_attr_conds (insn) == CONDS_JUMP_CLOB)
1168990075Sobrien	{
1169090075Sobrien	  jump_clobbers = 1;
1169190075Sobrien	  return;
1169290075Sobrien	}
11693169689Skan
1169490075Sobrien      /* Register the insn jumped to.  */
1169590075Sobrien      if (reverse)
1169690075Sobrien        {
1169790075Sobrien	  if (!seeking_return)
1169890075Sobrien	    label = XEXP (SET_SRC (body), 0);
1169990075Sobrien        }
1170090075Sobrien      else if (GET_CODE (XEXP (SET_SRC (body), 1)) == LABEL_REF)
1170190075Sobrien	label = XEXP (XEXP (SET_SRC (body), 1), 0);
1170290075Sobrien      else if (GET_CODE (XEXP (SET_SRC (body), 2)) == LABEL_REF)
1170390075Sobrien	{
1170490075Sobrien	  label = XEXP (XEXP (SET_SRC (body), 2), 0);
1170590075Sobrien	  then_not_else = FALSE;
1170690075Sobrien	}
1170790075Sobrien      else if (GET_CODE (XEXP (SET_SRC (body), 1)) == RETURN)
1170890075Sobrien	seeking_return = 1;
1170990075Sobrien      else if (GET_CODE (XEXP (SET_SRC (body), 2)) == RETURN)
1171090075Sobrien        {
1171190075Sobrien	  seeking_return = 1;
1171290075Sobrien	  then_not_else = FALSE;
1171390075Sobrien        }
1171490075Sobrien      else
11715169689Skan	gcc_unreachable ();
1171690075Sobrien
1171790075Sobrien      /* See how many insns this branch skips, and what kind of insns.  If all
1171890075Sobrien	 insns are okay, and the label or unconditional branch to the same
1171990075Sobrien	 label is not too far away, succeed.  */
1172090075Sobrien      for (insns_skipped = 0;
1172190075Sobrien	   !fail && !succeed && insns_skipped++ < max_insns_skipped;)
1172290075Sobrien	{
1172390075Sobrien	  rtx scanbody;
1172490075Sobrien
1172590075Sobrien	  this_insn = next_nonnote_insn (this_insn);
1172690075Sobrien	  if (!this_insn)
1172790075Sobrien	    break;
1172890075Sobrien
1172990075Sobrien	  switch (GET_CODE (this_insn))
1173090075Sobrien	    {
1173190075Sobrien	    case CODE_LABEL:
1173290075Sobrien	      /* Succeed if it is the target label, otherwise fail since
1173390075Sobrien		 control falls in from somewhere else.  */
1173490075Sobrien	      if (this_insn == label)
1173590075Sobrien		{
1173690075Sobrien		  if (jump_clobbers)
1173790075Sobrien		    {
1173890075Sobrien		      arm_ccfsm_state = 2;
1173990075Sobrien		      this_insn = next_nonnote_insn (this_insn);
1174090075Sobrien		    }
1174190075Sobrien		  else
1174290075Sobrien		    arm_ccfsm_state = 1;
1174390075Sobrien		  succeed = TRUE;
1174490075Sobrien		}
1174590075Sobrien	      else
1174690075Sobrien		fail = TRUE;
1174790075Sobrien	      break;
1174890075Sobrien
1174990075Sobrien	    case BARRIER:
1175090075Sobrien	      /* Succeed if the following insn is the target label.
11751169689Skan		 Otherwise fail.
11752169689Skan		 If return insns are used then the last insn in a function
1175390075Sobrien		 will be a barrier.  */
1175490075Sobrien	      this_insn = next_nonnote_insn (this_insn);
1175590075Sobrien	      if (this_insn && this_insn == label)
1175690075Sobrien		{
1175790075Sobrien		  if (jump_clobbers)
1175890075Sobrien		    {
1175990075Sobrien		      arm_ccfsm_state = 2;
1176090075Sobrien		      this_insn = next_nonnote_insn (this_insn);
1176190075Sobrien		    }
1176290075Sobrien		  else
1176390075Sobrien		    arm_ccfsm_state = 1;
1176490075Sobrien		  succeed = TRUE;
1176590075Sobrien		}
1176690075Sobrien	      else
1176790075Sobrien		fail = TRUE;
1176890075Sobrien	      break;
1176990075Sobrien
1177090075Sobrien	    case CALL_INSN:
11771169689Skan	      /* The AAPCS says that conditional calls should not be
11772169689Skan		 used since they make interworking inefficient (the
11773169689Skan		 linker can't transform BL<cond> into BLX).  That's
11774169689Skan		 only a problem if the machine has BLX.  */
11775169689Skan	      if (arm_arch5)
1177690075Sobrien		{
11777169689Skan		  fail = TRUE;
11778169689Skan		  break;
11779169689Skan		}
1178090075Sobrien
11781169689Skan	      /* Succeed if the following insn is the target label, or
11782169689Skan		 if the following two insns are a barrier and the
11783169689Skan		 target label.  */
11784169689Skan	      this_insn = next_nonnote_insn (this_insn);
11785169689Skan	      if (this_insn && GET_CODE (this_insn) == BARRIER)
11786169689Skan		this_insn = next_nonnote_insn (this_insn);
11787169689Skan
11788169689Skan	      if (this_insn && this_insn == label
11789169689Skan		  && insns_skipped < max_insns_skipped)
11790169689Skan		{
11791169689Skan		  if (jump_clobbers)
1179290075Sobrien		    {
11793169689Skan		      arm_ccfsm_state = 2;
11794169689Skan		      this_insn = next_nonnote_insn (this_insn);
1179590075Sobrien		    }
1179690075Sobrien		  else
11797169689Skan		    arm_ccfsm_state = 1;
11798169689Skan		  succeed = TRUE;
1179990075Sobrien		}
11800169689Skan	      else
11801169689Skan		fail = TRUE;
1180290075Sobrien	      break;
1180390075Sobrien
1180490075Sobrien	    case JUMP_INSN:
1180590075Sobrien      	      /* If this is an unconditional branch to the same label, succeed.
1180690075Sobrien		 If it is to another label, do nothing.  If it is conditional,
1180790075Sobrien		 fail.  */
11808132718Skan	      /* XXX Probably, the tests for SET and the PC are
11809132718Skan		 unnecessary.  */
1181090075Sobrien
1181190075Sobrien	      scanbody = PATTERN (this_insn);
1181290075Sobrien	      if (GET_CODE (scanbody) == SET
1181390075Sobrien		  && GET_CODE (SET_DEST (scanbody)) == PC)
1181490075Sobrien		{
1181590075Sobrien		  if (GET_CODE (SET_SRC (scanbody)) == LABEL_REF
1181690075Sobrien		      && XEXP (SET_SRC (scanbody), 0) == label && !reverse)
1181790075Sobrien		    {
1181890075Sobrien		      arm_ccfsm_state = 2;
1181990075Sobrien		      succeed = TRUE;
1182090075Sobrien		    }
1182190075Sobrien		  else if (GET_CODE (SET_SRC (scanbody)) == IF_THEN_ELSE)
1182290075Sobrien		    fail = TRUE;
1182390075Sobrien		}
11824169689Skan	      /* Fail if a conditional return is undesirable (e.g. on a
1182590075Sobrien		 StrongARM), but still allow this if optimizing for size.  */
1182690075Sobrien	      else if (GET_CODE (scanbody) == RETURN
11827132718Skan		       && !use_return_insn (TRUE, NULL)
1182890075Sobrien		       && !optimize_size)
1182990075Sobrien		fail = TRUE;
1183090075Sobrien	      else if (GET_CODE (scanbody) == RETURN
1183190075Sobrien		       && seeking_return)
1183290075Sobrien	        {
1183390075Sobrien		  arm_ccfsm_state = 2;
1183490075Sobrien		  succeed = TRUE;
1183590075Sobrien	        }
1183690075Sobrien	      else if (GET_CODE (scanbody) == PARALLEL)
1183790075Sobrien	        {
1183890075Sobrien		  switch (get_attr_conds (this_insn))
1183990075Sobrien		    {
1184090075Sobrien		    case CONDS_NOCOND:
1184190075Sobrien		      break;
1184290075Sobrien		    default:
1184390075Sobrien		      fail = TRUE;
1184490075Sobrien		      break;
1184590075Sobrien		    }
1184690075Sobrien		}
1184790075Sobrien	      else
11848169689Skan		fail = TRUE;	/* Unrecognized jump (e.g. epilogue).  */
1184990075Sobrien
1185090075Sobrien	      break;
1185190075Sobrien
1185290075Sobrien	    case INSN:
1185390075Sobrien	      /* Instructions using or affecting the condition codes make it
1185490075Sobrien		 fail.  */
1185590075Sobrien	      scanbody = PATTERN (this_insn);
1185690075Sobrien	      if (!(GET_CODE (scanbody) == SET
1185790075Sobrien		    || GET_CODE (scanbody) == PARALLEL)
1185890075Sobrien		  || get_attr_conds (this_insn) != CONDS_NOCOND)
1185990075Sobrien		fail = TRUE;
11860132718Skan
11861132718Skan	      /* A conditional cirrus instruction must be followed by
11862132718Skan		 a non Cirrus instruction.  However, since we
11863132718Skan		 conditionalize instructions in this function and by
11864132718Skan		 the time we get here we can't add instructions
11865132718Skan		 (nops), because shorten_branches() has already been
11866132718Skan		 called, we will disable conditionalizing Cirrus
11867132718Skan		 instructions to be safe.  */
11868132718Skan	      if (GET_CODE (scanbody) != USE
11869132718Skan		  && GET_CODE (scanbody) != CLOBBER
11870132718Skan		  && get_attr_cirrus (this_insn) != CIRRUS_NOT)
11871132718Skan		fail = TRUE;
1187290075Sobrien	      break;
1187390075Sobrien
1187490075Sobrien	    default:
1187590075Sobrien	      break;
1187690075Sobrien	    }
1187790075Sobrien	}
1187890075Sobrien      if (succeed)
1187990075Sobrien	{
1188090075Sobrien	  if ((!seeking_return) && (arm_ccfsm_state == 1 || reverse))
1188190075Sobrien	    arm_target_label = CODE_LABEL_NUMBER (label);
11882169689Skan	  else
1188390075Sobrien	    {
11884169689Skan	      gcc_assert (seeking_return || arm_ccfsm_state == 2);
11885169689Skan
1188690075Sobrien	      while (this_insn && GET_CODE (PATTERN (this_insn)) == USE)
1188790075Sobrien	        {
1188890075Sobrien		  this_insn = next_nonnote_insn (this_insn);
11889169689Skan		  gcc_assert (!this_insn
11890169689Skan			      || (GET_CODE (this_insn) != BARRIER
11891169689Skan				  && GET_CODE (this_insn) != CODE_LABEL));
1189290075Sobrien	        }
1189390075Sobrien	      if (!this_insn)
1189490075Sobrien	        {
11895132718Skan		  /* Oh, dear! we ran off the end.. give up.  */
1189690075Sobrien		  recog (PATTERN (insn), insn, NULL);
1189790075Sobrien		  arm_ccfsm_state = 0;
1189890075Sobrien		  arm_target_insn = NULL;
1189990075Sobrien		  return;
1190090075Sobrien	        }
1190190075Sobrien	      arm_target_insn = this_insn;
1190290075Sobrien	    }
1190390075Sobrien	  if (jump_clobbers)
1190490075Sobrien	    {
11905169689Skan	      gcc_assert (!reverse);
11906169689Skan	      arm_current_cc =
1190790075Sobrien		  get_arm_condition_code (XEXP (XEXP (XEXP (SET_SRC (body),
1190890075Sobrien							    0), 0), 1));
1190990075Sobrien	      if (GET_CODE (XEXP (XEXP (SET_SRC (body), 0), 0)) == AND)
1191090075Sobrien		arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc);
1191190075Sobrien	      if (GET_CODE (XEXP (SET_SRC (body), 0)) == NE)
1191290075Sobrien		arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc);
1191390075Sobrien	    }
1191490075Sobrien	  else
1191590075Sobrien	    {
1191690075Sobrien	      /* If REVERSE is true, ARM_CURRENT_CC needs to be inverted from
1191790075Sobrien		 what it was.  */
1191890075Sobrien	      if (!reverse)
1191990075Sobrien		arm_current_cc = get_arm_condition_code (XEXP (SET_SRC (body),
1192090075Sobrien							       0));
1192190075Sobrien	    }
1192290075Sobrien
1192390075Sobrien	  if (reverse || then_not_else)
1192490075Sobrien	    arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc);
1192590075Sobrien	}
11926169689Skan
1192790075Sobrien      /* Restore recog_data (getting the attributes of other insns can
1192890075Sobrien	 destroy this array, but final.c assumes that it remains intact
1192990075Sobrien	 across this call; since the insn has been recognized already we
1193090075Sobrien	 call recog direct).  */
1193190075Sobrien      recog (PATTERN (insn), insn, NULL);
1193290075Sobrien    }
1193390075Sobrien}
1193490075Sobrien
1193590075Sobrien/* Returns true if REGNO is a valid register
11936169689Skan   for holding a quantity of type MODE.  */
1193790075Sobrienint
11938132718Skanarm_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
1193990075Sobrien{
1194090075Sobrien  if (GET_MODE_CLASS (mode) == MODE_CC)
11941169689Skan    return (regno == CC_REGNUM
11942169689Skan	    || (TARGET_HARD_FLOAT && TARGET_VFP
11943169689Skan		&& regno == VFPCC_REGNUM));
11944169689Skan
1194590075Sobrien  if (TARGET_THUMB)
1194690075Sobrien    /* For the Thumb we only allow values bigger than SImode in
1194790075Sobrien       registers 0 - 6, so that there is always a second low
1194890075Sobrien       register available to hold the upper part of the value.
1194990075Sobrien       We probably we ought to ensure that the register is the
1195090075Sobrien       start of an even numbered register pair.  */
11951117395Skan    return (ARM_NUM_REGS (mode) < 2) || (regno < LAST_LO_REGNUM);
1195290075Sobrien
11953169689Skan  if (TARGET_HARD_FLOAT && TARGET_MAVERICK
11954169689Skan      && IS_CIRRUS_REGNUM (regno))
11955132718Skan    /* We have outlawed SI values in Cirrus registers because they
11956132718Skan       reside in the lower 32 bits, but SF values reside in the
11957132718Skan       upper 32 bits.  This causes gcc all sorts of grief.  We can't
11958132718Skan       even split the registers into pairs because Cirrus SI values
11959132718Skan       get sign extended to 64bits-- aldyh.  */
11960132718Skan    return (GET_MODE_CLASS (mode) == MODE_FLOAT) || (mode == DImode);
11961132718Skan
11962169689Skan  if (TARGET_HARD_FLOAT && TARGET_VFP
11963169689Skan      && IS_VFP_REGNUM (regno))
11964169689Skan    {
11965169689Skan      if (mode == SFmode || mode == SImode)
11966169689Skan	return TRUE;
11967132718Skan
11968169689Skan      /* DFmode values are only valid in even register pairs.  */
11969169689Skan      if (mode == DFmode)
11970169689Skan	return ((regno - FIRST_VFP_REGNUM) & 1) == 0;
11971169689Skan      return FALSE;
11972169689Skan    }
11973132718Skan
11974169689Skan  if (TARGET_REALLY_IWMMXT)
11975169689Skan    {
11976169689Skan      if (IS_IWMMXT_GR_REGNUM (regno))
11977169689Skan	return mode == SImode;
11978169689Skan
11979169689Skan      if (IS_IWMMXT_REGNUM (regno))
11980169689Skan	return VALID_IWMMXT_REG_MODE (mode);
11981169689Skan    }
11982169689Skan
11983169689Skan  /* We allow any value to be stored in the general registers.
11984169689Skan     Restrict doubleword quantities to even register pairs so that we can
11985169689Skan     use ldrd.  */
1198690075Sobrien  if (regno <= LAST_ARM_REGNUM)
11987169689Skan    return !(TARGET_LDRD && GET_MODE_SIZE (mode) > 4 && (regno & 1) != 0);
1198890075Sobrien
11989169689Skan  if (regno == FRAME_POINTER_REGNUM
1199090075Sobrien      || regno == ARG_POINTER_REGNUM)
1199190075Sobrien    /* We only allow integers in the fake hard registers.  */
1199290075Sobrien    return GET_MODE_CLASS (mode) == MODE_INT;
1199390075Sobrien
11994132718Skan  /* The only registers left are the FPA registers
1199590075Sobrien     which we only allow to hold FP values.  */
11996169689Skan  return (TARGET_HARD_FLOAT && TARGET_FPA
11997169689Skan	  && GET_MODE_CLASS (mode) == MODE_FLOAT
11998169689Skan	  && regno >= FIRST_FPA_REGNUM
11999169689Skan	  && regno <= LAST_FPA_REGNUM);
1200090075Sobrien}
1200190075Sobrien
1200290075Sobrienint
12003132718Skanarm_regno_class (int regno)
1200490075Sobrien{
1200590075Sobrien  if (TARGET_THUMB)
1200690075Sobrien    {
1200790075Sobrien      if (regno == STACK_POINTER_REGNUM)
1200890075Sobrien	return STACK_REG;
1200990075Sobrien      if (regno == CC_REGNUM)
1201090075Sobrien	return CC_REG;
1201190075Sobrien      if (regno < 8)
1201290075Sobrien	return LO_REGS;
1201390075Sobrien      return HI_REGS;
1201490075Sobrien    }
1201590075Sobrien
1201690075Sobrien  if (   regno <= LAST_ARM_REGNUM
1201790075Sobrien      || regno == FRAME_POINTER_REGNUM
1201890075Sobrien      || regno == ARG_POINTER_REGNUM)
1201990075Sobrien    return GENERAL_REGS;
12020169689Skan
12021169689Skan  if (regno == CC_REGNUM || regno == VFPCC_REGNUM)
1202290075Sobrien    return NO_REGS;
1202390075Sobrien
12024132718Skan  if (IS_CIRRUS_REGNUM (regno))
12025132718Skan    return CIRRUS_REGS;
12026132718Skan
12027169689Skan  if (IS_VFP_REGNUM (regno))
12028169689Skan    return VFP_REGS;
12029169689Skan
12030132718Skan  if (IS_IWMMXT_REGNUM (regno))
12031132718Skan    return IWMMXT_REGS;
12032132718Skan
12033132718Skan  if (IS_IWMMXT_GR_REGNUM (regno))
12034132718Skan    return IWMMXT_GR_REGS;
12035132718Skan
12036132718Skan  return FPA_REGS;
1203790075Sobrien}
1203890075Sobrien
1203990075Sobrien/* Handle a special case when computing the offset
1204090075Sobrien   of an argument from the frame pointer.  */
1204190075Sobrienint
12042132718Skanarm_debugger_arg_offset (int value, rtx addr)
1204390075Sobrien{
1204490075Sobrien  rtx insn;
1204590075Sobrien
1204690075Sobrien  /* We are only interested if dbxout_parms() failed to compute the offset.  */
1204790075Sobrien  if (value != 0)
1204890075Sobrien    return 0;
1204990075Sobrien
1205090075Sobrien  /* We can only cope with the case where the address is held in a register.  */
1205190075Sobrien  if (GET_CODE (addr) != REG)
1205290075Sobrien    return 0;
1205390075Sobrien
1205490075Sobrien  /* If we are using the frame pointer to point at the argument, then
1205590075Sobrien     an offset of 0 is correct.  */
1205690075Sobrien  if (REGNO (addr) == (unsigned) HARD_FRAME_POINTER_REGNUM)
1205790075Sobrien    return 0;
12058169689Skan
1205990075Sobrien  /* If we are using the stack pointer to point at the
1206090075Sobrien     argument, then an offset of 0 is correct.  */
1206190075Sobrien  if ((TARGET_THUMB || !frame_pointer_needed)
1206290075Sobrien      && REGNO (addr) == SP_REGNUM)
1206390075Sobrien    return 0;
12064169689Skan
1206590075Sobrien  /* Oh dear.  The argument is pointed to by a register rather
1206690075Sobrien     than being held in a register, or being stored at a known
1206790075Sobrien     offset from the frame pointer.  Since GDB only understands
1206890075Sobrien     those two kinds of argument we must translate the address
1206990075Sobrien     held in the register into an offset from the frame pointer.
1207090075Sobrien     We do this by searching through the insns for the function
1207190075Sobrien     looking to see where this register gets its value.  If the
12072117395Skan     register is initialized from the frame pointer plus an offset
1207390075Sobrien     then we are in luck and we can continue, otherwise we give up.
12074169689Skan
1207590075Sobrien     This code is exercised by producing debugging information
1207690075Sobrien     for a function with arguments like this:
12077169689Skan
1207890075Sobrien           double func (double a, double b, int c, double d) {return d;}
12079169689Skan
1208090075Sobrien     Without this code the stab for parameter 'd' will be set to
1208190075Sobrien     an offset of 0 from the frame pointer, rather than 8.  */
1208290075Sobrien
1208390075Sobrien  /* The if() statement says:
1208490075Sobrien
1208590075Sobrien     If the insn is a normal instruction
1208690075Sobrien     and if the insn is setting the value in a register
1208790075Sobrien     and if the register being set is the register holding the address of the argument
1208890075Sobrien     and if the address is computing by an addition
1208990075Sobrien     that involves adding to a register
1209090075Sobrien     which is the frame pointer
1209190075Sobrien     a constant integer
1209290075Sobrien
12093132718Skan     then...  */
12094169689Skan
1209590075Sobrien  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
1209690075Sobrien    {
12097169689Skan      if (   GET_CODE (insn) == INSN
1209890075Sobrien	  && GET_CODE (PATTERN (insn)) == SET
1209990075Sobrien	  && REGNO    (XEXP (PATTERN (insn), 0)) == REGNO (addr)
1210090075Sobrien	  && GET_CODE (XEXP (PATTERN (insn), 1)) == PLUS
1210190075Sobrien	  && GET_CODE (XEXP (XEXP (PATTERN (insn), 1), 0)) == REG
1210290075Sobrien	  && REGNO    (XEXP (XEXP (PATTERN (insn), 1), 0)) == (unsigned) HARD_FRAME_POINTER_REGNUM
1210390075Sobrien	  && GET_CODE (XEXP (XEXP (PATTERN (insn), 1), 1)) == CONST_INT
1210490075Sobrien	     )
1210590075Sobrien	{
1210690075Sobrien	  value = INTVAL (XEXP (XEXP (PATTERN (insn), 1), 1));
12107169689Skan
1210890075Sobrien	  break;
1210990075Sobrien	}
1211090075Sobrien    }
12111169689Skan
1211290075Sobrien  if (value == 0)
1211390075Sobrien    {
1211490075Sobrien      debug_rtx (addr);
12115169689Skan      warning (0, "unable to compute real location of stacked parameter");
1211690075Sobrien      value = 8; /* XXX magic hack */
1211790075Sobrien    }
1211890075Sobrien
1211990075Sobrien  return value;
1212090075Sobrien}
12121132718Skan
12122132718Skan#define def_mbuiltin(MASK, NAME, TYPE, CODE)				\
12123132718Skan  do									\
12124132718Skan    {									\
12125132718Skan      if ((MASK) & insn_flags)						\
12126169689Skan        lang_hooks.builtin_function ((NAME), (TYPE), (CODE),		\
12127169689Skan				     BUILT_IN_MD, NULL, NULL_TREE);	\
12128132718Skan    }									\
12129132718Skan  while (0)
1213090075Sobrien
12131132718Skanstruct builtin_description
12132132718Skan{
12133132718Skan  const unsigned int       mask;
12134132718Skan  const enum insn_code     icode;
12135132718Skan  const char * const       name;
12136132718Skan  const enum arm_builtins  code;
12137132718Skan  const enum rtx_code      comparison;
12138132718Skan  const unsigned int       flag;
12139132718Skan};
1214090075Sobrien
12141132718Skanstatic const struct builtin_description bdesc_2arg[] =
1214290075Sobrien{
12143132718Skan#define IWMMXT_BUILTIN(code, string, builtin) \
12144132718Skan  { FL_IWMMXT, CODE_FOR_##code, "__builtin_arm_" string, \
12145132718Skan    ARM_BUILTIN_##builtin, 0, 0 },
12146132718Skan
12147132718Skan  IWMMXT_BUILTIN (addv8qi3, "waddb", WADDB)
12148132718Skan  IWMMXT_BUILTIN (addv4hi3, "waddh", WADDH)
12149132718Skan  IWMMXT_BUILTIN (addv2si3, "waddw", WADDW)
12150132718Skan  IWMMXT_BUILTIN (subv8qi3, "wsubb", WSUBB)
12151132718Skan  IWMMXT_BUILTIN (subv4hi3, "wsubh", WSUBH)
12152132718Skan  IWMMXT_BUILTIN (subv2si3, "wsubw", WSUBW)
12153132718Skan  IWMMXT_BUILTIN (ssaddv8qi3, "waddbss", WADDSSB)
12154132718Skan  IWMMXT_BUILTIN (ssaddv4hi3, "waddhss", WADDSSH)
12155132718Skan  IWMMXT_BUILTIN (ssaddv2si3, "waddwss", WADDSSW)
12156132718Skan  IWMMXT_BUILTIN (sssubv8qi3, "wsubbss", WSUBSSB)
12157132718Skan  IWMMXT_BUILTIN (sssubv4hi3, "wsubhss", WSUBSSH)
12158132718Skan  IWMMXT_BUILTIN (sssubv2si3, "wsubwss", WSUBSSW)
12159132718Skan  IWMMXT_BUILTIN (usaddv8qi3, "waddbus", WADDUSB)
12160132718Skan  IWMMXT_BUILTIN (usaddv4hi3, "waddhus", WADDUSH)
12161132718Skan  IWMMXT_BUILTIN (usaddv2si3, "waddwus", WADDUSW)
12162132718Skan  IWMMXT_BUILTIN (ussubv8qi3, "wsubbus", WSUBUSB)
12163132718Skan  IWMMXT_BUILTIN (ussubv4hi3, "wsubhus", WSUBUSH)
12164132718Skan  IWMMXT_BUILTIN (ussubv2si3, "wsubwus", WSUBUSW)
12165132718Skan  IWMMXT_BUILTIN (mulv4hi3, "wmulul", WMULUL)
12166169689Skan  IWMMXT_BUILTIN (smulv4hi3_highpart, "wmulsm", WMULSM)
12167169689Skan  IWMMXT_BUILTIN (umulv4hi3_highpart, "wmulum", WMULUM)
12168132718Skan  IWMMXT_BUILTIN (eqv8qi3, "wcmpeqb", WCMPEQB)
12169132718Skan  IWMMXT_BUILTIN (eqv4hi3, "wcmpeqh", WCMPEQH)
12170132718Skan  IWMMXT_BUILTIN (eqv2si3, "wcmpeqw", WCMPEQW)
12171132718Skan  IWMMXT_BUILTIN (gtuv8qi3, "wcmpgtub", WCMPGTUB)
12172132718Skan  IWMMXT_BUILTIN (gtuv4hi3, "wcmpgtuh", WCMPGTUH)
12173132718Skan  IWMMXT_BUILTIN (gtuv2si3, "wcmpgtuw", WCMPGTUW)
12174132718Skan  IWMMXT_BUILTIN (gtv8qi3, "wcmpgtsb", WCMPGTSB)
12175132718Skan  IWMMXT_BUILTIN (gtv4hi3, "wcmpgtsh", WCMPGTSH)
12176132718Skan  IWMMXT_BUILTIN (gtv2si3, "wcmpgtsw", WCMPGTSW)
12177132718Skan  IWMMXT_BUILTIN (umaxv8qi3, "wmaxub", WMAXUB)
12178132718Skan  IWMMXT_BUILTIN (smaxv8qi3, "wmaxsb", WMAXSB)
12179132718Skan  IWMMXT_BUILTIN (umaxv4hi3, "wmaxuh", WMAXUH)
12180132718Skan  IWMMXT_BUILTIN (smaxv4hi3, "wmaxsh", WMAXSH)
12181132718Skan  IWMMXT_BUILTIN (umaxv2si3, "wmaxuw", WMAXUW)
12182132718Skan  IWMMXT_BUILTIN (smaxv2si3, "wmaxsw", WMAXSW)
12183132718Skan  IWMMXT_BUILTIN (uminv8qi3, "wminub", WMINUB)
12184132718Skan  IWMMXT_BUILTIN (sminv8qi3, "wminsb", WMINSB)
12185132718Skan  IWMMXT_BUILTIN (uminv4hi3, "wminuh", WMINUH)
12186132718Skan  IWMMXT_BUILTIN (sminv4hi3, "wminsh", WMINSH)
12187132718Skan  IWMMXT_BUILTIN (uminv2si3, "wminuw", WMINUW)
12188132718Skan  IWMMXT_BUILTIN (sminv2si3, "wminsw", WMINSW)
12189132718Skan  IWMMXT_BUILTIN (iwmmxt_anddi3, "wand", WAND)
12190132718Skan  IWMMXT_BUILTIN (iwmmxt_nanddi3, "wandn", WANDN)
12191132718Skan  IWMMXT_BUILTIN (iwmmxt_iordi3, "wor", WOR)
12192132718Skan  IWMMXT_BUILTIN (iwmmxt_xordi3, "wxor", WXOR)
12193132718Skan  IWMMXT_BUILTIN (iwmmxt_uavgv8qi3, "wavg2b", WAVG2B)
12194132718Skan  IWMMXT_BUILTIN (iwmmxt_uavgv4hi3, "wavg2h", WAVG2H)
12195132718Skan  IWMMXT_BUILTIN (iwmmxt_uavgrndv8qi3, "wavg2br", WAVG2BR)
12196132718Skan  IWMMXT_BUILTIN (iwmmxt_uavgrndv4hi3, "wavg2hr", WAVG2HR)
12197132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckilb, "wunpckilb", WUNPCKILB)
12198132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckilh, "wunpckilh", WUNPCKILH)
12199132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckilw, "wunpckilw", WUNPCKILW)
12200132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckihb, "wunpckihb", WUNPCKIHB)
12201132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckihh, "wunpckihh", WUNPCKIHH)
12202132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckihw, "wunpckihw", WUNPCKIHW)
12203132718Skan  IWMMXT_BUILTIN (iwmmxt_wmadds, "wmadds", WMADDS)
12204132718Skan  IWMMXT_BUILTIN (iwmmxt_wmaddu, "wmaddu", WMADDU)
12205132718Skan
12206132718Skan#define IWMMXT_BUILTIN2(code, builtin) \
12207132718Skan  { FL_IWMMXT, CODE_FOR_##code, NULL, ARM_BUILTIN_##builtin, 0, 0 },
12208169689Skan
12209132718Skan  IWMMXT_BUILTIN2 (iwmmxt_wpackhss, WPACKHSS)
12210132718Skan  IWMMXT_BUILTIN2 (iwmmxt_wpackwss, WPACKWSS)
12211132718Skan  IWMMXT_BUILTIN2 (iwmmxt_wpackdss, WPACKDSS)
12212132718Skan  IWMMXT_BUILTIN2 (iwmmxt_wpackhus, WPACKHUS)
12213132718Skan  IWMMXT_BUILTIN2 (iwmmxt_wpackwus, WPACKWUS)
12214132718Skan  IWMMXT_BUILTIN2 (iwmmxt_wpackdus, WPACKDUS)
12215132718Skan  IWMMXT_BUILTIN2 (ashlv4hi3_di,    WSLLH)
12216132718Skan  IWMMXT_BUILTIN2 (ashlv4hi3,       WSLLHI)
12217132718Skan  IWMMXT_BUILTIN2 (ashlv2si3_di,    WSLLW)
12218132718Skan  IWMMXT_BUILTIN2 (ashlv2si3,       WSLLWI)
12219132718Skan  IWMMXT_BUILTIN2 (ashldi3_di,      WSLLD)
12220132718Skan  IWMMXT_BUILTIN2 (ashldi3_iwmmxt,  WSLLDI)
12221132718Skan  IWMMXT_BUILTIN2 (lshrv4hi3_di,    WSRLH)
12222132718Skan  IWMMXT_BUILTIN2 (lshrv4hi3,       WSRLHI)
12223132718Skan  IWMMXT_BUILTIN2 (lshrv2si3_di,    WSRLW)
12224132718Skan  IWMMXT_BUILTIN2 (lshrv2si3,       WSRLWI)
12225132718Skan  IWMMXT_BUILTIN2 (lshrdi3_di,      WSRLD)
12226169689Skan  IWMMXT_BUILTIN2 (lshrdi3_iwmmxt,  WSRLDI)
12227132718Skan  IWMMXT_BUILTIN2 (ashrv4hi3_di,    WSRAH)
12228132718Skan  IWMMXT_BUILTIN2 (ashrv4hi3,       WSRAHI)
12229132718Skan  IWMMXT_BUILTIN2 (ashrv2si3_di,    WSRAW)
12230132718Skan  IWMMXT_BUILTIN2 (ashrv2si3,       WSRAWI)
12231132718Skan  IWMMXT_BUILTIN2 (ashrdi3_di,      WSRAD)
12232169689Skan  IWMMXT_BUILTIN2 (ashrdi3_iwmmxt,  WSRADI)
12233132718Skan  IWMMXT_BUILTIN2 (rorv4hi3_di,     WRORH)
12234132718Skan  IWMMXT_BUILTIN2 (rorv4hi3,        WRORHI)
12235132718Skan  IWMMXT_BUILTIN2 (rorv2si3_di,     WRORW)
12236132718Skan  IWMMXT_BUILTIN2 (rorv2si3,        WRORWI)
12237132718Skan  IWMMXT_BUILTIN2 (rordi3_di,       WRORD)
12238132718Skan  IWMMXT_BUILTIN2 (rordi3,          WRORDI)
12239132718Skan  IWMMXT_BUILTIN2 (iwmmxt_wmacuz,   WMACUZ)
12240132718Skan  IWMMXT_BUILTIN2 (iwmmxt_wmacsz,   WMACSZ)
12241132718Skan};
12242132718Skan
12243132718Skanstatic const struct builtin_description bdesc_1arg[] =
12244132718Skan{
12245132718Skan  IWMMXT_BUILTIN (iwmmxt_tmovmskb, "tmovmskb", TMOVMSKB)
12246132718Skan  IWMMXT_BUILTIN (iwmmxt_tmovmskh, "tmovmskh", TMOVMSKH)
12247132718Skan  IWMMXT_BUILTIN (iwmmxt_tmovmskw, "tmovmskw", TMOVMSKW)
12248132718Skan  IWMMXT_BUILTIN (iwmmxt_waccb, "waccb", WACCB)
12249132718Skan  IWMMXT_BUILTIN (iwmmxt_wacch, "wacch", WACCH)
12250132718Skan  IWMMXT_BUILTIN (iwmmxt_waccw, "waccw", WACCW)
12251132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckehub, "wunpckehub", WUNPCKEHUB)
12252132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckehuh, "wunpckehuh", WUNPCKEHUH)
12253132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckehuw, "wunpckehuw", WUNPCKEHUW)
12254132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckehsb, "wunpckehsb", WUNPCKEHSB)
12255132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckehsh, "wunpckehsh", WUNPCKEHSH)
12256132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckehsw, "wunpckehsw", WUNPCKEHSW)
12257132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckelub, "wunpckelub", WUNPCKELUB)
12258132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckeluh, "wunpckeluh", WUNPCKELUH)
12259132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckeluw, "wunpckeluw", WUNPCKELUW)
12260132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckelsb, "wunpckelsb", WUNPCKELSB)
12261132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckelsh, "wunpckelsh", WUNPCKELSH)
12262132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckelsw, "wunpckelsw", WUNPCKELSW)
12263132718Skan};
12264132718Skan
12265132718Skan/* Set up all the iWMMXt builtins.  This is
12266132718Skan   not called if TARGET_IWMMXT is zero.  */
12267132718Skan
12268132718Skanstatic void
12269132718Skanarm_init_iwmmxt_builtins (void)
12270132718Skan{
12271132718Skan  const struct builtin_description * d;
12272132718Skan  size_t i;
1227390075Sobrien  tree endlink = void_list_node;
1227490075Sobrien
12275169689Skan  tree V2SI_type_node = build_vector_type_for_mode (intSI_type_node, V2SImode);
12276169689Skan  tree V4HI_type_node = build_vector_type_for_mode (intHI_type_node, V4HImode);
12277169689Skan  tree V8QI_type_node = build_vector_type_for_mode (intQI_type_node, V8QImode);
12278169689Skan
12279132718Skan  tree int_ftype_int
12280132718Skan    = build_function_type (integer_type_node,
12281132718Skan			   tree_cons (NULL_TREE, integer_type_node, endlink));
12282132718Skan  tree v8qi_ftype_v8qi_v8qi_int
12283132718Skan    = build_function_type (V8QI_type_node,
12284132718Skan			   tree_cons (NULL_TREE, V8QI_type_node,
12285132718Skan				      tree_cons (NULL_TREE, V8QI_type_node,
12286132718Skan						 tree_cons (NULL_TREE,
12287132718Skan							    integer_type_node,
12288132718Skan							    endlink))));
12289132718Skan  tree v4hi_ftype_v4hi_int
12290132718Skan    = build_function_type (V4HI_type_node,
12291132718Skan			   tree_cons (NULL_TREE, V4HI_type_node,
12292132718Skan				      tree_cons (NULL_TREE, integer_type_node,
12293132718Skan						 endlink)));
12294132718Skan  tree v2si_ftype_v2si_int
12295132718Skan    = build_function_type (V2SI_type_node,
12296132718Skan			   tree_cons (NULL_TREE, V2SI_type_node,
12297132718Skan				      tree_cons (NULL_TREE, integer_type_node,
12298132718Skan						 endlink)));
12299132718Skan  tree v2si_ftype_di_di
12300132718Skan    = build_function_type (V2SI_type_node,
12301132718Skan			   tree_cons (NULL_TREE, long_long_integer_type_node,
12302132718Skan				      tree_cons (NULL_TREE, long_long_integer_type_node,
12303132718Skan						 endlink)));
12304132718Skan  tree di_ftype_di_int
12305132718Skan    = build_function_type (long_long_integer_type_node,
12306132718Skan			   tree_cons (NULL_TREE, long_long_integer_type_node,
12307132718Skan				      tree_cons (NULL_TREE, integer_type_node,
12308132718Skan						 endlink)));
12309132718Skan  tree di_ftype_di_int_int
12310132718Skan    = build_function_type (long_long_integer_type_node,
12311132718Skan			   tree_cons (NULL_TREE, long_long_integer_type_node,
12312132718Skan				      tree_cons (NULL_TREE, integer_type_node,
12313132718Skan						 tree_cons (NULL_TREE,
12314132718Skan							    integer_type_node,
12315132718Skan							    endlink))));
12316132718Skan  tree int_ftype_v8qi
12317132718Skan    = build_function_type (integer_type_node,
12318132718Skan			   tree_cons (NULL_TREE, V8QI_type_node,
12319132718Skan				      endlink));
12320132718Skan  tree int_ftype_v4hi
12321132718Skan    = build_function_type (integer_type_node,
12322132718Skan			   tree_cons (NULL_TREE, V4HI_type_node,
12323132718Skan				      endlink));
12324132718Skan  tree int_ftype_v2si
12325132718Skan    = build_function_type (integer_type_node,
12326132718Skan			   tree_cons (NULL_TREE, V2SI_type_node,
12327132718Skan				      endlink));
12328132718Skan  tree int_ftype_v8qi_int
12329132718Skan    = build_function_type (integer_type_node,
12330132718Skan			   tree_cons (NULL_TREE, V8QI_type_node,
12331132718Skan				      tree_cons (NULL_TREE, integer_type_node,
12332132718Skan						 endlink)));
12333132718Skan  tree int_ftype_v4hi_int
12334132718Skan    = build_function_type (integer_type_node,
12335132718Skan			   tree_cons (NULL_TREE, V4HI_type_node,
12336132718Skan				      tree_cons (NULL_TREE, integer_type_node,
12337132718Skan						 endlink)));
12338132718Skan  tree int_ftype_v2si_int
12339132718Skan    = build_function_type (integer_type_node,
12340132718Skan			   tree_cons (NULL_TREE, V2SI_type_node,
12341132718Skan				      tree_cons (NULL_TREE, integer_type_node,
12342132718Skan						 endlink)));
12343132718Skan  tree v8qi_ftype_v8qi_int_int
12344132718Skan    = build_function_type (V8QI_type_node,
12345132718Skan			   tree_cons (NULL_TREE, V8QI_type_node,
12346132718Skan				      tree_cons (NULL_TREE, integer_type_node,
12347132718Skan						 tree_cons (NULL_TREE,
12348132718Skan							    integer_type_node,
12349132718Skan							    endlink))));
12350132718Skan  tree v4hi_ftype_v4hi_int_int
12351132718Skan    = build_function_type (V4HI_type_node,
12352132718Skan			   tree_cons (NULL_TREE, V4HI_type_node,
12353132718Skan				      tree_cons (NULL_TREE, integer_type_node,
12354132718Skan						 tree_cons (NULL_TREE,
12355132718Skan							    integer_type_node,
12356132718Skan							    endlink))));
12357132718Skan  tree v2si_ftype_v2si_int_int
12358132718Skan    = build_function_type (V2SI_type_node,
12359132718Skan			   tree_cons (NULL_TREE, V2SI_type_node,
12360132718Skan				      tree_cons (NULL_TREE, integer_type_node,
12361132718Skan						 tree_cons (NULL_TREE,
12362132718Skan							    integer_type_node,
12363132718Skan							    endlink))));
12364132718Skan  /* Miscellaneous.  */
12365132718Skan  tree v8qi_ftype_v4hi_v4hi
12366132718Skan    = build_function_type (V8QI_type_node,
12367132718Skan			   tree_cons (NULL_TREE, V4HI_type_node,
12368132718Skan				      tree_cons (NULL_TREE, V4HI_type_node,
12369132718Skan						 endlink)));
12370132718Skan  tree v4hi_ftype_v2si_v2si
12371132718Skan    = build_function_type (V4HI_type_node,
12372132718Skan			   tree_cons (NULL_TREE, V2SI_type_node,
12373132718Skan				      tree_cons (NULL_TREE, V2SI_type_node,
12374132718Skan						 endlink)));
12375132718Skan  tree v2si_ftype_v4hi_v4hi
12376132718Skan    = build_function_type (V2SI_type_node,
12377132718Skan			   tree_cons (NULL_TREE, V4HI_type_node,
12378132718Skan				      tree_cons (NULL_TREE, V4HI_type_node,
12379132718Skan						 endlink)));
12380132718Skan  tree v2si_ftype_v8qi_v8qi
12381132718Skan    = build_function_type (V2SI_type_node,
12382132718Skan			   tree_cons (NULL_TREE, V8QI_type_node,
12383132718Skan				      tree_cons (NULL_TREE, V8QI_type_node,
12384132718Skan						 endlink)));
12385132718Skan  tree v4hi_ftype_v4hi_di
12386132718Skan    = build_function_type (V4HI_type_node,
12387132718Skan			   tree_cons (NULL_TREE, V4HI_type_node,
12388132718Skan				      tree_cons (NULL_TREE,
12389132718Skan						 long_long_integer_type_node,
12390132718Skan						 endlink)));
12391132718Skan  tree v2si_ftype_v2si_di
12392132718Skan    = build_function_type (V2SI_type_node,
12393132718Skan			   tree_cons (NULL_TREE, V2SI_type_node,
12394132718Skan				      tree_cons (NULL_TREE,
12395132718Skan						 long_long_integer_type_node,
12396132718Skan						 endlink)));
12397132718Skan  tree void_ftype_int_int
12398132718Skan    = build_function_type (void_type_node,
12399132718Skan			   tree_cons (NULL_TREE, integer_type_node,
12400132718Skan				      tree_cons (NULL_TREE, integer_type_node,
12401132718Skan						 endlink)));
12402132718Skan  tree di_ftype_void
12403132718Skan    = build_function_type (long_long_unsigned_type_node, endlink);
12404132718Skan  tree di_ftype_v8qi
12405132718Skan    = build_function_type (long_long_integer_type_node,
12406132718Skan			   tree_cons (NULL_TREE, V8QI_type_node,
12407132718Skan				      endlink));
12408132718Skan  tree di_ftype_v4hi
12409132718Skan    = build_function_type (long_long_integer_type_node,
12410132718Skan			   tree_cons (NULL_TREE, V4HI_type_node,
12411132718Skan				      endlink));
12412132718Skan  tree di_ftype_v2si
12413132718Skan    = build_function_type (long_long_integer_type_node,
12414132718Skan			   tree_cons (NULL_TREE, V2SI_type_node,
12415132718Skan				      endlink));
12416132718Skan  tree v2si_ftype_v4hi
12417132718Skan    = build_function_type (V2SI_type_node,
12418132718Skan			   tree_cons (NULL_TREE, V4HI_type_node,
12419132718Skan				      endlink));
12420132718Skan  tree v4hi_ftype_v8qi
12421132718Skan    = build_function_type (V4HI_type_node,
12422132718Skan			   tree_cons (NULL_TREE, V8QI_type_node,
12423132718Skan				      endlink));
1242490075Sobrien
12425132718Skan  tree di_ftype_di_v4hi_v4hi
12426132718Skan    = build_function_type (long_long_unsigned_type_node,
12427132718Skan			   tree_cons (NULL_TREE,
12428132718Skan				      long_long_unsigned_type_node,
12429132718Skan				      tree_cons (NULL_TREE, V4HI_type_node,
12430132718Skan						 tree_cons (NULL_TREE,
12431132718Skan							    V4HI_type_node,
12432132718Skan							    endlink))));
1243390075Sobrien
12434132718Skan  tree di_ftype_v4hi_v4hi
12435132718Skan    = build_function_type (long_long_unsigned_type_node,
12436132718Skan			   tree_cons (NULL_TREE, V4HI_type_node,
12437132718Skan				      tree_cons (NULL_TREE, V4HI_type_node,
12438132718Skan						 endlink)));
1243990075Sobrien
12440132718Skan  /* Normal vector binops.  */
12441132718Skan  tree v8qi_ftype_v8qi_v8qi
12442132718Skan    = build_function_type (V8QI_type_node,
12443132718Skan			   tree_cons (NULL_TREE, V8QI_type_node,
12444132718Skan				      tree_cons (NULL_TREE, V8QI_type_node,
12445132718Skan						 endlink)));
12446132718Skan  tree v4hi_ftype_v4hi_v4hi
12447132718Skan    = build_function_type (V4HI_type_node,
12448132718Skan			   tree_cons (NULL_TREE, V4HI_type_node,
12449132718Skan				      tree_cons (NULL_TREE, V4HI_type_node,
12450132718Skan						 endlink)));
12451132718Skan  tree v2si_ftype_v2si_v2si
12452132718Skan    = build_function_type (V2SI_type_node,
12453132718Skan			   tree_cons (NULL_TREE, V2SI_type_node,
12454132718Skan				      tree_cons (NULL_TREE, V2SI_type_node,
12455132718Skan						 endlink)));
12456132718Skan  tree di_ftype_di_di
12457132718Skan    = build_function_type (long_long_unsigned_type_node,
12458132718Skan			   tree_cons (NULL_TREE, long_long_unsigned_type_node,
12459132718Skan				      tree_cons (NULL_TREE,
12460132718Skan						 long_long_unsigned_type_node,
12461132718Skan						 endlink)));
12462132718Skan
12463132718Skan  /* Add all builtins that are more or less simple operations on two
12464132718Skan     operands.  */
12465132718Skan  for (i = 0, d = bdesc_2arg; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
12466132718Skan    {
12467132718Skan      /* Use one of the operands; the target can have a different mode for
12468132718Skan	 mask-generating compares.  */
12469132718Skan      enum machine_mode mode;
12470132718Skan      tree type;
12471132718Skan
12472132718Skan      if (d->name == 0)
12473132718Skan	continue;
12474132718Skan
12475132718Skan      mode = insn_data[d->icode].operand[1].mode;
12476132718Skan
12477132718Skan      switch (mode)
12478132718Skan	{
12479132718Skan	case V8QImode:
12480132718Skan	  type = v8qi_ftype_v8qi_v8qi;
12481132718Skan	  break;
12482132718Skan	case V4HImode:
12483132718Skan	  type = v4hi_ftype_v4hi_v4hi;
12484132718Skan	  break;
12485132718Skan	case V2SImode:
12486132718Skan	  type = v2si_ftype_v2si_v2si;
12487132718Skan	  break;
12488132718Skan	case DImode:
12489132718Skan	  type = di_ftype_di_di;
12490132718Skan	  break;
12491132718Skan
12492132718Skan	default:
12493169689Skan	  gcc_unreachable ();
12494132718Skan	}
12495132718Skan
12496132718Skan      def_mbuiltin (d->mask, d->name, type, d->code);
12497132718Skan    }
12498132718Skan
12499132718Skan  /* Add the remaining MMX insns with somewhat more complicated types.  */
12500132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wzero", di_ftype_void, ARM_BUILTIN_WZERO);
12501132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_setwcx", void_ftype_int_int, ARM_BUILTIN_SETWCX);
12502132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_getwcx", int_ftype_int, ARM_BUILTIN_GETWCX);
12503132718Skan
12504132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsllh", v4hi_ftype_v4hi_di, ARM_BUILTIN_WSLLH);
12505132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsllw", v2si_ftype_v2si_di, ARM_BUILTIN_WSLLW);
12506132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wslld", di_ftype_di_di, ARM_BUILTIN_WSLLD);
12507132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsllhi", v4hi_ftype_v4hi_int, ARM_BUILTIN_WSLLHI);
12508132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsllwi", v2si_ftype_v2si_int, ARM_BUILTIN_WSLLWI);
12509132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wslldi", di_ftype_di_int, ARM_BUILTIN_WSLLDI);
12510132718Skan
12511132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrlh", v4hi_ftype_v4hi_di, ARM_BUILTIN_WSRLH);
12512132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrlw", v2si_ftype_v2si_di, ARM_BUILTIN_WSRLW);
12513132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrld", di_ftype_di_di, ARM_BUILTIN_WSRLD);
12514132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrlhi", v4hi_ftype_v4hi_int, ARM_BUILTIN_WSRLHI);
12515132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrlwi", v2si_ftype_v2si_int, ARM_BUILTIN_WSRLWI);
12516132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrldi", di_ftype_di_int, ARM_BUILTIN_WSRLDI);
12517132718Skan
12518132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrah", v4hi_ftype_v4hi_di, ARM_BUILTIN_WSRAH);
12519132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsraw", v2si_ftype_v2si_di, ARM_BUILTIN_WSRAW);
12520132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrad", di_ftype_di_di, ARM_BUILTIN_WSRAD);
12521132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrahi", v4hi_ftype_v4hi_int, ARM_BUILTIN_WSRAHI);
12522132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrawi", v2si_ftype_v2si_int, ARM_BUILTIN_WSRAWI);
12523132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsradi", di_ftype_di_int, ARM_BUILTIN_WSRADI);
12524132718Skan
12525132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wrorh", v4hi_ftype_v4hi_di, ARM_BUILTIN_WRORH);
12526132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wrorw", v2si_ftype_v2si_di, ARM_BUILTIN_WRORW);
12527132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wrord", di_ftype_di_di, ARM_BUILTIN_WRORD);
12528132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wrorhi", v4hi_ftype_v4hi_int, ARM_BUILTIN_WRORHI);
12529132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wrorwi", v2si_ftype_v2si_int, ARM_BUILTIN_WRORWI);
12530132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wrordi", di_ftype_di_int, ARM_BUILTIN_WRORDI);
12531132718Skan
12532132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wshufh", v4hi_ftype_v4hi_int, ARM_BUILTIN_WSHUFH);
12533132718Skan
12534132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsadb", v2si_ftype_v8qi_v8qi, ARM_BUILTIN_WSADB);
12535132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsadh", v2si_ftype_v4hi_v4hi, ARM_BUILTIN_WSADH);
12536132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsadbz", v2si_ftype_v8qi_v8qi, ARM_BUILTIN_WSADBZ);
12537132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsadhz", v2si_ftype_v4hi_v4hi, ARM_BUILTIN_WSADHZ);
12538132718Skan
12539132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_textrmsb", int_ftype_v8qi_int, ARM_BUILTIN_TEXTRMSB);
12540132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_textrmsh", int_ftype_v4hi_int, ARM_BUILTIN_TEXTRMSH);
12541132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_textrmsw", int_ftype_v2si_int, ARM_BUILTIN_TEXTRMSW);
12542132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_textrmub", int_ftype_v8qi_int, ARM_BUILTIN_TEXTRMUB);
12543132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_textrmuh", int_ftype_v4hi_int, ARM_BUILTIN_TEXTRMUH);
12544132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_textrmuw", int_ftype_v2si_int, ARM_BUILTIN_TEXTRMUW);
12545132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tinsrb", v8qi_ftype_v8qi_int_int, ARM_BUILTIN_TINSRB);
12546132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tinsrh", v4hi_ftype_v4hi_int_int, ARM_BUILTIN_TINSRH);
12547132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tinsrw", v2si_ftype_v2si_int_int, ARM_BUILTIN_TINSRW);
12548132718Skan
12549132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_waccb", di_ftype_v8qi, ARM_BUILTIN_WACCB);
12550132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wacch", di_ftype_v4hi, ARM_BUILTIN_WACCH);
12551132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_waccw", di_ftype_v2si, ARM_BUILTIN_WACCW);
12552132718Skan
12553132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmovmskb", int_ftype_v8qi, ARM_BUILTIN_TMOVMSKB);
12554132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmovmskh", int_ftype_v4hi, ARM_BUILTIN_TMOVMSKH);
12555132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmovmskw", int_ftype_v2si, ARM_BUILTIN_TMOVMSKW);
12556132718Skan
12557132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wpackhss", v8qi_ftype_v4hi_v4hi, ARM_BUILTIN_WPACKHSS);
12558132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wpackhus", v8qi_ftype_v4hi_v4hi, ARM_BUILTIN_WPACKHUS);
12559132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wpackwus", v4hi_ftype_v2si_v2si, ARM_BUILTIN_WPACKWUS);
12560132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wpackwss", v4hi_ftype_v2si_v2si, ARM_BUILTIN_WPACKWSS);
12561132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wpackdus", v2si_ftype_di_di, ARM_BUILTIN_WPACKDUS);
12562132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wpackdss", v2si_ftype_di_di, ARM_BUILTIN_WPACKDSS);
12563132718Skan
12564132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckehub", v4hi_ftype_v8qi, ARM_BUILTIN_WUNPCKEHUB);
12565132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckehuh", v2si_ftype_v4hi, ARM_BUILTIN_WUNPCKEHUH);
12566132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckehuw", di_ftype_v2si, ARM_BUILTIN_WUNPCKEHUW);
12567132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckehsb", v4hi_ftype_v8qi, ARM_BUILTIN_WUNPCKEHSB);
12568132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckehsh", v2si_ftype_v4hi, ARM_BUILTIN_WUNPCKEHSH);
12569132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckehsw", di_ftype_v2si, ARM_BUILTIN_WUNPCKEHSW);
12570132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckelub", v4hi_ftype_v8qi, ARM_BUILTIN_WUNPCKELUB);
12571132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckeluh", v2si_ftype_v4hi, ARM_BUILTIN_WUNPCKELUH);
12572132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckeluw", di_ftype_v2si, ARM_BUILTIN_WUNPCKELUW);
12573132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckelsb", v4hi_ftype_v8qi, ARM_BUILTIN_WUNPCKELSB);
12574132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckelsh", v2si_ftype_v4hi, ARM_BUILTIN_WUNPCKELSH);
12575132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckelsw", di_ftype_v2si, ARM_BUILTIN_WUNPCKELSW);
12576132718Skan
12577132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wmacs", di_ftype_di_v4hi_v4hi, ARM_BUILTIN_WMACS);
12578132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wmacsz", di_ftype_v4hi_v4hi, ARM_BUILTIN_WMACSZ);
12579132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wmacu", di_ftype_di_v4hi_v4hi, ARM_BUILTIN_WMACU);
12580132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wmacuz", di_ftype_v4hi_v4hi, ARM_BUILTIN_WMACUZ);
12581132718Skan
12582132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_walign", v8qi_ftype_v8qi_v8qi_int, ARM_BUILTIN_WALIGN);
12583132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmia", di_ftype_di_int_int, ARM_BUILTIN_TMIA);
12584132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmiaph", di_ftype_di_int_int, ARM_BUILTIN_TMIAPH);
12585132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmiabb", di_ftype_di_int_int, ARM_BUILTIN_TMIABB);
12586132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmiabt", di_ftype_di_int_int, ARM_BUILTIN_TMIABT);
12587132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmiatb", di_ftype_di_int_int, ARM_BUILTIN_TMIATB);
12588132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmiatt", di_ftype_di_int_int, ARM_BUILTIN_TMIATT);
1258990075Sobrien}
1259090075Sobrien
12591132718Skanstatic void
12592169689Skanarm_init_tls_builtins (void)
12593169689Skan{
12594169689Skan  tree ftype;
12595169689Skan  tree nothrow = tree_cons (get_identifier ("nothrow"), NULL, NULL);
12596169689Skan  tree const_nothrow = tree_cons (get_identifier ("const"), NULL, nothrow);
12597169689Skan
12598169689Skan  ftype = build_function_type (ptr_type_node, void_list_node);
12599169689Skan  lang_hooks.builtin_function ("__builtin_thread_pointer", ftype,
12600169689Skan			       ARM_BUILTIN_THREAD_POINTER, BUILT_IN_MD,
12601169689Skan			       NULL, const_nothrow);
12602169689Skan}
12603169689Skan
12604169689Skanstatic void
12605132718Skanarm_init_builtins (void)
12606132718Skan{
12607169689Skan  arm_init_tls_builtins ();
12608169689Skan
12609132718Skan  if (TARGET_REALLY_IWMMXT)
12610132718Skan    arm_init_iwmmxt_builtins ();
12611132718Skan}
12612132718Skan
12613132718Skan/* Errors in the source file can cause expand_expr to return const0_rtx
12614132718Skan   where we expect a vector.  To avoid crashing, use one of the vector
12615132718Skan   clear instructions.  */
12616132718Skan
12617132718Skanstatic rtx
12618132718Skansafe_vector_operand (rtx x, enum machine_mode mode)
12619132718Skan{
12620132718Skan  if (x != const0_rtx)
12621132718Skan    return x;
12622132718Skan  x = gen_reg_rtx (mode);
12623132718Skan
12624132718Skan  emit_insn (gen_iwmmxt_clrdi (mode == DImode ? x
12625132718Skan			       : gen_rtx_SUBREG (DImode, x, 0)));
12626132718Skan  return x;
12627132718Skan}
12628132718Skan
12629132718Skan/* Subroutine of arm_expand_builtin to take care of binop insns.  */
12630132718Skan
12631132718Skanstatic rtx
12632132718Skanarm_expand_binop_builtin (enum insn_code icode,
12633132718Skan			  tree arglist, rtx target)
12634132718Skan{
12635132718Skan  rtx pat;
12636132718Skan  tree arg0 = TREE_VALUE (arglist);
12637132718Skan  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
12638169689Skan  rtx op0 = expand_normal (arg0);
12639169689Skan  rtx op1 = expand_normal (arg1);
12640132718Skan  enum machine_mode tmode = insn_data[icode].operand[0].mode;
12641132718Skan  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
12642132718Skan  enum machine_mode mode1 = insn_data[icode].operand[2].mode;
12643132718Skan
12644132718Skan  if (VECTOR_MODE_P (mode0))
12645132718Skan    op0 = safe_vector_operand (op0, mode0);
12646132718Skan  if (VECTOR_MODE_P (mode1))
12647132718Skan    op1 = safe_vector_operand (op1, mode1);
12648132718Skan
12649132718Skan  if (! target
12650132718Skan      || GET_MODE (target) != tmode
12651132718Skan      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
12652132718Skan    target = gen_reg_rtx (tmode);
12653132718Skan
12654169689Skan  gcc_assert (GET_MODE (op0) == mode0 && GET_MODE (op1) == mode1);
12655132718Skan
12656132718Skan  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
12657132718Skan    op0 = copy_to_mode_reg (mode0, op0);
12658132718Skan  if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
12659132718Skan    op1 = copy_to_mode_reg (mode1, op1);
12660132718Skan
12661132718Skan  pat = GEN_FCN (icode) (target, op0, op1);
12662132718Skan  if (! pat)
12663132718Skan    return 0;
12664132718Skan  emit_insn (pat);
12665132718Skan  return target;
12666132718Skan}
12667132718Skan
12668132718Skan/* Subroutine of arm_expand_builtin to take care of unop insns.  */
12669132718Skan
12670132718Skanstatic rtx
12671132718Skanarm_expand_unop_builtin (enum insn_code icode,
12672132718Skan			 tree arglist, rtx target, int do_load)
12673132718Skan{
12674132718Skan  rtx pat;
12675132718Skan  tree arg0 = TREE_VALUE (arglist);
12676169689Skan  rtx op0 = expand_normal (arg0);
12677132718Skan  enum machine_mode tmode = insn_data[icode].operand[0].mode;
12678132718Skan  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
12679132718Skan
12680132718Skan  if (! target
12681132718Skan      || GET_MODE (target) != tmode
12682132718Skan      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
12683132718Skan    target = gen_reg_rtx (tmode);
12684132718Skan  if (do_load)
12685132718Skan    op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
12686132718Skan  else
12687132718Skan    {
12688132718Skan      if (VECTOR_MODE_P (mode0))
12689132718Skan	op0 = safe_vector_operand (op0, mode0);
12690132718Skan
12691132718Skan      if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
12692132718Skan	op0 = copy_to_mode_reg (mode0, op0);
12693132718Skan    }
12694132718Skan
12695132718Skan  pat = GEN_FCN (icode) (target, op0);
12696132718Skan  if (! pat)
12697132718Skan    return 0;
12698132718Skan  emit_insn (pat);
12699132718Skan  return target;
12700132718Skan}
12701132718Skan
1270290075Sobrien/* Expand an expression EXP that calls a built-in function,
1270390075Sobrien   with result going to TARGET if that's convenient
1270490075Sobrien   (and in mode MODE if that's convenient).
1270590075Sobrien   SUBTARGET may be used as the target for computing one of EXP's operands.
1270690075Sobrien   IGNORE is nonzero if the value is to be ignored.  */
1270790075Sobrien
12708132718Skanstatic rtx
12709132718Skanarm_expand_builtin (tree exp,
12710132718Skan		    rtx target,
12711132718Skan		    rtx subtarget ATTRIBUTE_UNUSED,
12712132718Skan		    enum machine_mode mode ATTRIBUTE_UNUSED,
12713132718Skan		    int ignore ATTRIBUTE_UNUSED)
1271490075Sobrien{
12715132718Skan  const struct builtin_description * d;
12716132718Skan  enum insn_code    icode;
12717132718Skan  tree              fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
12718132718Skan  tree              arglist = TREE_OPERAND (exp, 1);
12719132718Skan  tree              arg0;
12720132718Skan  tree              arg1;
12721132718Skan  tree              arg2;
12722132718Skan  rtx               op0;
12723132718Skan  rtx               op1;
12724132718Skan  rtx               op2;
12725132718Skan  rtx               pat;
12726132718Skan  int               fcode = DECL_FUNCTION_CODE (fndecl);
12727132718Skan  size_t            i;
12728132718Skan  enum machine_mode tmode;
12729132718Skan  enum machine_mode mode0;
12730132718Skan  enum machine_mode mode1;
12731132718Skan  enum machine_mode mode2;
1273290075Sobrien
1273390075Sobrien  switch (fcode)
1273490075Sobrien    {
12735132718Skan    case ARM_BUILTIN_TEXTRMSB:
12736132718Skan    case ARM_BUILTIN_TEXTRMUB:
12737132718Skan    case ARM_BUILTIN_TEXTRMSH:
12738132718Skan    case ARM_BUILTIN_TEXTRMUH:
12739132718Skan    case ARM_BUILTIN_TEXTRMSW:
12740132718Skan    case ARM_BUILTIN_TEXTRMUW:
12741132718Skan      icode = (fcode == ARM_BUILTIN_TEXTRMSB ? CODE_FOR_iwmmxt_textrmsb
12742132718Skan	       : fcode == ARM_BUILTIN_TEXTRMUB ? CODE_FOR_iwmmxt_textrmub
12743132718Skan	       : fcode == ARM_BUILTIN_TEXTRMSH ? CODE_FOR_iwmmxt_textrmsh
12744132718Skan	       : fcode == ARM_BUILTIN_TEXTRMUH ? CODE_FOR_iwmmxt_textrmuh
12745132718Skan	       : CODE_FOR_iwmmxt_textrmw);
12746132718Skan
1274790075Sobrien      arg0 = TREE_VALUE (arglist);
12748132718Skan      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
12749169689Skan      op0 = expand_normal (arg0);
12750169689Skan      op1 = expand_normal (arg1);
1275190075Sobrien      tmode = insn_data[icode].operand[0].mode;
1275290075Sobrien      mode0 = insn_data[icode].operand[1].mode;
12753132718Skan      mode1 = insn_data[icode].operand[2].mode;
1275490075Sobrien
1275590075Sobrien      if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
1275690075Sobrien	op0 = copy_to_mode_reg (mode0, op0);
12757132718Skan      if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
12758132718Skan	{
12759132718Skan	  /* @@@ better error message */
12760132718Skan	  error ("selector must be an immediate");
12761132718Skan	  return gen_reg_rtx (tmode);
12762132718Skan	}
1276390075Sobrien      if (target == 0
1276490075Sobrien	  || GET_MODE (target) != tmode
1276590075Sobrien	  || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
1276690075Sobrien	target = gen_reg_rtx (tmode);
12767132718Skan      pat = GEN_FCN (icode) (target, op0, op1);
1276890075Sobrien      if (! pat)
1276990075Sobrien	return 0;
1277090075Sobrien      emit_insn (pat);
1277190075Sobrien      return target;
12772132718Skan
12773132718Skan    case ARM_BUILTIN_TINSRB:
12774132718Skan    case ARM_BUILTIN_TINSRH:
12775132718Skan    case ARM_BUILTIN_TINSRW:
12776132718Skan      icode = (fcode == ARM_BUILTIN_TINSRB ? CODE_FOR_iwmmxt_tinsrb
12777132718Skan	       : fcode == ARM_BUILTIN_TINSRH ? CODE_FOR_iwmmxt_tinsrh
12778132718Skan	       : CODE_FOR_iwmmxt_tinsrw);
12779132718Skan      arg0 = TREE_VALUE (arglist);
12780132718Skan      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
12781132718Skan      arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
12782169689Skan      op0 = expand_normal (arg0);
12783169689Skan      op1 = expand_normal (arg1);
12784169689Skan      op2 = expand_normal (arg2);
12785132718Skan      tmode = insn_data[icode].operand[0].mode;
12786132718Skan      mode0 = insn_data[icode].operand[1].mode;
12787132718Skan      mode1 = insn_data[icode].operand[2].mode;
12788132718Skan      mode2 = insn_data[icode].operand[3].mode;
12789132718Skan
12790132718Skan      if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
12791132718Skan	op0 = copy_to_mode_reg (mode0, op0);
12792132718Skan      if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
12793132718Skan	op1 = copy_to_mode_reg (mode1, op1);
12794132718Skan      if (! (*insn_data[icode].operand[3].predicate) (op2, mode2))
12795132718Skan	{
12796132718Skan	  /* @@@ better error message */
12797132718Skan	  error ("selector must be an immediate");
12798132718Skan	  return const0_rtx;
12799132718Skan	}
12800132718Skan      if (target == 0
12801132718Skan	  || GET_MODE (target) != tmode
12802132718Skan	  || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
12803132718Skan	target = gen_reg_rtx (tmode);
12804132718Skan      pat = GEN_FCN (icode) (target, op0, op1, op2);
12805132718Skan      if (! pat)
12806132718Skan	return 0;
12807132718Skan      emit_insn (pat);
12808132718Skan      return target;
12809132718Skan
12810132718Skan    case ARM_BUILTIN_SETWCX:
12811132718Skan      arg0 = TREE_VALUE (arglist);
12812132718Skan      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
12813169689Skan      op0 = force_reg (SImode, expand_normal (arg0));
12814169689Skan      op1 = expand_normal (arg1);
12815169689Skan      emit_insn (gen_iwmmxt_tmcr (op1, op0));
12816132718Skan      return 0;
12817132718Skan
12818132718Skan    case ARM_BUILTIN_GETWCX:
12819132718Skan      arg0 = TREE_VALUE (arglist);
12820169689Skan      op0 = expand_normal (arg0);
12821132718Skan      target = gen_reg_rtx (SImode);
12822132718Skan      emit_insn (gen_iwmmxt_tmrc (target, op0));
12823132718Skan      return target;
12824132718Skan
12825132718Skan    case ARM_BUILTIN_WSHUFH:
12826132718Skan      icode = CODE_FOR_iwmmxt_wshufh;
12827132718Skan      arg0 = TREE_VALUE (arglist);
12828132718Skan      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
12829169689Skan      op0 = expand_normal (arg0);
12830169689Skan      op1 = expand_normal (arg1);
12831132718Skan      tmode = insn_data[icode].operand[0].mode;
12832132718Skan      mode1 = insn_data[icode].operand[1].mode;
12833132718Skan      mode2 = insn_data[icode].operand[2].mode;
12834132718Skan
12835132718Skan      if (! (*insn_data[icode].operand[1].predicate) (op0, mode1))
12836132718Skan	op0 = copy_to_mode_reg (mode1, op0);
12837132718Skan      if (! (*insn_data[icode].operand[2].predicate) (op1, mode2))
12838132718Skan	{
12839132718Skan	  /* @@@ better error message */
12840132718Skan	  error ("mask must be an immediate");
12841132718Skan	  return const0_rtx;
12842132718Skan	}
12843132718Skan      if (target == 0
12844132718Skan	  || GET_MODE (target) != tmode
12845132718Skan	  || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
12846132718Skan	target = gen_reg_rtx (tmode);
12847132718Skan      pat = GEN_FCN (icode) (target, op0, op1);
12848132718Skan      if (! pat)
12849132718Skan	return 0;
12850132718Skan      emit_insn (pat);
12851132718Skan      return target;
12852132718Skan
12853132718Skan    case ARM_BUILTIN_WSADB:
12854132718Skan      return arm_expand_binop_builtin (CODE_FOR_iwmmxt_wsadb, arglist, target);
12855132718Skan    case ARM_BUILTIN_WSADH:
12856132718Skan      return arm_expand_binop_builtin (CODE_FOR_iwmmxt_wsadh, arglist, target);
12857132718Skan    case ARM_BUILTIN_WSADBZ:
12858132718Skan      return arm_expand_binop_builtin (CODE_FOR_iwmmxt_wsadbz, arglist, target);
12859132718Skan    case ARM_BUILTIN_WSADHZ:
12860132718Skan      return arm_expand_binop_builtin (CODE_FOR_iwmmxt_wsadhz, arglist, target);
12861132718Skan
12862132718Skan      /* Several three-argument builtins.  */
12863132718Skan    case ARM_BUILTIN_WMACS:
12864132718Skan    case ARM_BUILTIN_WMACU:
12865132718Skan    case ARM_BUILTIN_WALIGN:
12866132718Skan    case ARM_BUILTIN_TMIA:
12867132718Skan    case ARM_BUILTIN_TMIAPH:
12868132718Skan    case ARM_BUILTIN_TMIATT:
12869132718Skan    case ARM_BUILTIN_TMIATB:
12870132718Skan    case ARM_BUILTIN_TMIABT:
12871132718Skan    case ARM_BUILTIN_TMIABB:
12872132718Skan      icode = (fcode == ARM_BUILTIN_WMACS ? CODE_FOR_iwmmxt_wmacs
12873132718Skan	       : fcode == ARM_BUILTIN_WMACU ? CODE_FOR_iwmmxt_wmacu
12874132718Skan	       : fcode == ARM_BUILTIN_TMIA ? CODE_FOR_iwmmxt_tmia
12875132718Skan	       : fcode == ARM_BUILTIN_TMIAPH ? CODE_FOR_iwmmxt_tmiaph
12876132718Skan	       : fcode == ARM_BUILTIN_TMIABB ? CODE_FOR_iwmmxt_tmiabb
12877132718Skan	       : fcode == ARM_BUILTIN_TMIABT ? CODE_FOR_iwmmxt_tmiabt
12878132718Skan	       : fcode == ARM_BUILTIN_TMIATB ? CODE_FOR_iwmmxt_tmiatb
12879132718Skan	       : fcode == ARM_BUILTIN_TMIATT ? CODE_FOR_iwmmxt_tmiatt
12880132718Skan	       : CODE_FOR_iwmmxt_walign);
12881132718Skan      arg0 = TREE_VALUE (arglist);
12882132718Skan      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
12883132718Skan      arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
12884169689Skan      op0 = expand_normal (arg0);
12885169689Skan      op1 = expand_normal (arg1);
12886169689Skan      op2 = expand_normal (arg2);
12887132718Skan      tmode = insn_data[icode].operand[0].mode;
12888132718Skan      mode0 = insn_data[icode].operand[1].mode;
12889132718Skan      mode1 = insn_data[icode].operand[2].mode;
12890132718Skan      mode2 = insn_data[icode].operand[3].mode;
12891132718Skan
12892132718Skan      if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
12893132718Skan	op0 = copy_to_mode_reg (mode0, op0);
12894132718Skan      if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
12895132718Skan	op1 = copy_to_mode_reg (mode1, op1);
12896132718Skan      if (! (*insn_data[icode].operand[3].predicate) (op2, mode2))
12897132718Skan	op2 = copy_to_mode_reg (mode2, op2);
12898132718Skan      if (target == 0
12899132718Skan	  || GET_MODE (target) != tmode
12900132718Skan	  || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
12901132718Skan	target = gen_reg_rtx (tmode);
12902132718Skan      pat = GEN_FCN (icode) (target, op0, op1, op2);
12903132718Skan      if (! pat)
12904132718Skan	return 0;
12905132718Skan      emit_insn (pat);
12906132718Skan      return target;
12907169689Skan
12908132718Skan    case ARM_BUILTIN_WZERO:
12909132718Skan      target = gen_reg_rtx (DImode);
12910132718Skan      emit_insn (gen_iwmmxt_clrdi (target));
12911132718Skan      return target;
12912132718Skan
12913169689Skan    case ARM_BUILTIN_THREAD_POINTER:
12914169689Skan      return arm_load_tp (target);
12915169689Skan
12916132718Skan    default:
12917132718Skan      break;
1291890075Sobrien    }
12919117395Skan
12920132718Skan  for (i = 0, d = bdesc_2arg; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
12921132718Skan    if (d->code == (const enum arm_builtins) fcode)
12922132718Skan      return arm_expand_binop_builtin (d->icode, arglist, target);
12923132718Skan
12924132718Skan  for (i = 0, d = bdesc_1arg; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
12925132718Skan    if (d->code == (const enum arm_builtins) fcode)
12926132718Skan      return arm_expand_unop_builtin (d->icode, arglist, target, 0);
12927132718Skan
1292890075Sobrien  /* @@@ Should really do something sensible here.  */
1292990075Sobrien  return NULL_RTX;
1293090075Sobrien}
1293190075Sobrien
1293290075Sobrien/* Return the number (counting from 0) of
1293390075Sobrien   the least significant set bit in MASK.  */
1293490075Sobrien
12935132718Skaninline static int
12936169689Skannumber_of_first_bit_set (unsigned mask)
1293790075Sobrien{
1293890075Sobrien  int bit;
1293990075Sobrien
1294090075Sobrien  for (bit = 0;
1294190075Sobrien       (mask & (1 << bit)) == 0;
1294290075Sobrien       ++bit)
1294390075Sobrien    continue;
1294490075Sobrien
1294590075Sobrien  return bit;
1294690075Sobrien}
1294790075Sobrien
12948169689Skan/* Emit code to push or pop registers to or from the stack.  F is the
12949169689Skan   assembly file.  MASK is the registers to push or pop.  PUSH is
12950169689Skan   nonzero if we should push, and zero if we should pop.  For debugging
12951169689Skan   output, if pushing, adjust CFA_OFFSET by the amount of space added
12952169689Skan   to the stack.  REAL_REGS should have the same number of bits set as
12953169689Skan   MASK, and will be used instead (in the same order) to describe which
12954169689Skan   registers were saved - this is used to mark the save slots when we
12955169689Skan   push high registers after moving them to low registers.  */
12956169689Skanstatic void
12957169689Skanthumb_pushpop (FILE *f, unsigned long mask, int push, int *cfa_offset,
12958169689Skan	       unsigned long real_regs)
12959169689Skan{
12960169689Skan  int regno;
12961169689Skan  int lo_mask = mask & 0xFF;
12962169689Skan  int pushed_words = 0;
12963169689Skan
12964169689Skan  gcc_assert (mask);
12965169689Skan
12966169689Skan  if (lo_mask == 0 && !push && (mask & (1 << PC_REGNUM)))
12967169689Skan    {
12968169689Skan      /* Special case.  Do not generate a POP PC statement here, do it in
12969169689Skan	 thumb_exit() */
12970169689Skan      thumb_exit (f, -1);
12971169689Skan      return;
12972169689Skan    }
12973169689Skan
12974169689Skan  if (ARM_EABI_UNWIND_TABLES && push)
12975169689Skan    {
12976169689Skan      fprintf (f, "\t.save\t{");
12977169689Skan      for (regno = 0; regno < 15; regno++)
12978169689Skan	{
12979169689Skan	  if (real_regs & (1 << regno))
12980169689Skan	    {
12981169689Skan	      if (real_regs & ((1 << regno) -1))
12982169689Skan		fprintf (f, ", ");
12983169689Skan	      asm_fprintf (f, "%r", regno);
12984169689Skan	    }
12985169689Skan	}
12986169689Skan      fprintf (f, "}\n");
12987169689Skan    }
12988169689Skan
12989169689Skan  fprintf (f, "\t%s\t{", push ? "push" : "pop");
12990169689Skan
12991169689Skan  /* Look at the low registers first.  */
12992169689Skan  for (regno = 0; regno <= LAST_LO_REGNUM; regno++, lo_mask >>= 1)
12993169689Skan    {
12994169689Skan      if (lo_mask & 1)
12995169689Skan	{
12996169689Skan	  asm_fprintf (f, "%r", regno);
12997169689Skan
12998169689Skan	  if ((lo_mask & ~1) != 0)
12999169689Skan	    fprintf (f, ", ");
13000169689Skan
13001169689Skan	  pushed_words++;
13002169689Skan	}
13003169689Skan    }
13004169689Skan
13005169689Skan  if (push && (mask & (1 << LR_REGNUM)))
13006169689Skan    {
13007169689Skan      /* Catch pushing the LR.  */
13008169689Skan      if (mask & 0xFF)
13009169689Skan	fprintf (f, ", ");
13010169689Skan
13011169689Skan      asm_fprintf (f, "%r", LR_REGNUM);
13012169689Skan
13013169689Skan      pushed_words++;
13014169689Skan    }
13015169689Skan  else if (!push && (mask & (1 << PC_REGNUM)))
13016169689Skan    {
13017169689Skan      /* Catch popping the PC.  */
13018169689Skan      if (TARGET_INTERWORK || TARGET_BACKTRACE
13019169689Skan	  || current_function_calls_eh_return)
13020169689Skan	{
13021169689Skan	  /* The PC is never poped directly, instead
13022169689Skan	     it is popped into r3 and then BX is used.  */
13023169689Skan	  fprintf (f, "}\n");
13024169689Skan
13025169689Skan	  thumb_exit (f, -1);
13026169689Skan
13027169689Skan	  return;
13028169689Skan	}
13029169689Skan      else
13030169689Skan	{
13031169689Skan	  if (mask & 0xFF)
13032169689Skan	    fprintf (f, ", ");
13033169689Skan
13034169689Skan	  asm_fprintf (f, "%r", PC_REGNUM);
13035169689Skan	}
13036169689Skan    }
13037169689Skan
13038169689Skan  fprintf (f, "}\n");
13039169689Skan
13040169689Skan  if (push && pushed_words && dwarf2out_do_frame ())
13041169689Skan    {
13042169689Skan      char *l = dwarf2out_cfi_label ();
13043169689Skan      int pushed_mask = real_regs;
13044169689Skan
13045169689Skan      *cfa_offset += pushed_words * 4;
13046169689Skan      dwarf2out_def_cfa (l, SP_REGNUM, *cfa_offset);
13047169689Skan
13048169689Skan      pushed_words = 0;
13049169689Skan      pushed_mask = real_regs;
13050169689Skan      for (regno = 0; regno <= 14; regno++, pushed_mask >>= 1)
13051169689Skan	{
13052169689Skan	  if (pushed_mask & 1)
13053169689Skan	    dwarf2out_reg_save (l, regno, 4 * pushed_words++ - *cfa_offset);
13054169689Skan	}
13055169689Skan    }
13056169689Skan}
13057169689Skan
1305890075Sobrien/* Generate code to return from a thumb function.
1305990075Sobrien   If 'reg_containing_return_addr' is -1, then the return address is
1306090075Sobrien   actually on the stack, at the stack pointer.  */
1306190075Sobrienstatic void
13062169689Skanthumb_exit (FILE *f, int reg_containing_return_addr)
1306390075Sobrien{
1306490075Sobrien  unsigned regs_available_for_popping;
1306590075Sobrien  unsigned regs_to_pop;
1306690075Sobrien  int pops_needed;
1306790075Sobrien  unsigned available;
1306890075Sobrien  unsigned required;
1306990075Sobrien  int mode;
1307090075Sobrien  int size;
1307190075Sobrien  int restore_a4 = FALSE;
1307290075Sobrien
1307390075Sobrien  /* Compute the registers we need to pop.  */
1307490075Sobrien  regs_to_pop = 0;
1307590075Sobrien  pops_needed = 0;
1307690075Sobrien
13077169689Skan  if (reg_containing_return_addr == -1)
1307890075Sobrien    {
1307990075Sobrien      regs_to_pop |= 1 << LR_REGNUM;
1308090075Sobrien      ++pops_needed;
1308190075Sobrien    }
1308290075Sobrien
1308390075Sobrien  if (TARGET_BACKTRACE)
1308490075Sobrien    {
1308590075Sobrien      /* Restore the (ARM) frame pointer and stack pointer.  */
1308690075Sobrien      regs_to_pop |= (1 << ARM_HARD_FRAME_POINTER_REGNUM) | (1 << SP_REGNUM);
1308790075Sobrien      pops_needed += 2;
1308890075Sobrien    }
1308990075Sobrien
1309090075Sobrien  /* If there is nothing to pop then just emit the BX instruction and
1309190075Sobrien     return.  */
1309290075Sobrien  if (pops_needed == 0)
1309390075Sobrien    {
13094169689Skan      if (current_function_calls_eh_return)
13095169689Skan	asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, ARM_EH_STACKADJ_REGNUM);
1309690075Sobrien
1309790075Sobrien      asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
1309890075Sobrien      return;
1309990075Sobrien    }
1310090075Sobrien  /* Otherwise if we are not supporting interworking and we have not created
1310190075Sobrien     a backtrace structure and the function was not entered in ARM mode then
1310290075Sobrien     just pop the return address straight into the PC.  */
1310390075Sobrien  else if (!TARGET_INTERWORK
1310490075Sobrien	   && !TARGET_BACKTRACE
13105169689Skan	   && !is_called_in_ARM_mode (current_function_decl)
13106169689Skan	   && !current_function_calls_eh_return)
1310790075Sobrien    {
13108169689Skan      asm_fprintf (f, "\tpop\t{%r}\n", PC_REGNUM);
1310990075Sobrien      return;
1311090075Sobrien    }
1311190075Sobrien
1311290075Sobrien  /* Find out how many of the (return) argument registers we can corrupt.  */
1311390075Sobrien  regs_available_for_popping = 0;
1311490075Sobrien
1311590075Sobrien  /* If returning via __builtin_eh_return, the bottom three registers
1311690075Sobrien     all contain information needed for the return.  */
13117169689Skan  if (current_function_calls_eh_return)
1311890075Sobrien    size = 12;
1311990075Sobrien  else
1312090075Sobrien    {
1312190075Sobrien      /* If we can deduce the registers used from the function's
1312290075Sobrien	 return value.  This is more reliable that examining
1312390075Sobrien	 regs_ever_live[] because that will be set if the register is
1312490075Sobrien	 ever used in the function, not just if the register is used
1312590075Sobrien	 to hold a return value.  */
1312690075Sobrien
1312790075Sobrien      if (current_function_return_rtx != 0)
1312890075Sobrien	mode = GET_MODE (current_function_return_rtx);
1312990075Sobrien      else
1313090075Sobrien	mode = DECL_MODE (DECL_RESULT (current_function_decl));
1313190075Sobrien
1313290075Sobrien      size = GET_MODE_SIZE (mode);
1313390075Sobrien
1313490075Sobrien      if (size == 0)
1313590075Sobrien	{
1313690075Sobrien	  /* In a void function we can use any argument register.
1313790075Sobrien	     In a function that returns a structure on the stack
1313890075Sobrien	     we can use the second and third argument registers.  */
1313990075Sobrien	  if (mode == VOIDmode)
1314090075Sobrien	    regs_available_for_popping =
1314190075Sobrien	      (1 << ARG_REGISTER (1))
1314290075Sobrien	      | (1 << ARG_REGISTER (2))
1314390075Sobrien	      | (1 << ARG_REGISTER (3));
1314490075Sobrien	  else
1314590075Sobrien	    regs_available_for_popping =
1314690075Sobrien	      (1 << ARG_REGISTER (2))
1314790075Sobrien	      | (1 << ARG_REGISTER (3));
1314890075Sobrien	}
1314990075Sobrien      else if (size <= 4)
1315090075Sobrien	regs_available_for_popping =
1315190075Sobrien	  (1 << ARG_REGISTER (2))
1315290075Sobrien	  | (1 << ARG_REGISTER (3));
1315390075Sobrien      else if (size <= 8)
1315490075Sobrien	regs_available_for_popping =
1315590075Sobrien	  (1 << ARG_REGISTER (3));
1315690075Sobrien    }
1315790075Sobrien
1315890075Sobrien  /* Match registers to be popped with registers into which we pop them.  */
1315990075Sobrien  for (available = regs_available_for_popping,
1316090075Sobrien       required  = regs_to_pop;
1316190075Sobrien       required != 0 && available != 0;
1316290075Sobrien       available &= ~(available & - available),
1316390075Sobrien       required  &= ~(required  & - required))
1316490075Sobrien    -- pops_needed;
1316590075Sobrien
1316690075Sobrien  /* If we have any popping registers left over, remove them.  */
1316790075Sobrien  if (available > 0)
1316890075Sobrien    regs_available_for_popping &= ~available;
13169169689Skan
1317090075Sobrien  /* Otherwise if we need another popping register we can use
1317190075Sobrien     the fourth argument register.  */
1317290075Sobrien  else if (pops_needed)
1317390075Sobrien    {
1317490075Sobrien      /* If we have not found any free argument registers and
1317590075Sobrien	 reg a4 contains the return address, we must move it.  */
1317690075Sobrien      if (regs_available_for_popping == 0
1317790075Sobrien	  && reg_containing_return_addr == LAST_ARG_REGNUM)
1317890075Sobrien	{
1317990075Sobrien	  asm_fprintf (f, "\tmov\t%r, %r\n", LR_REGNUM, LAST_ARG_REGNUM);
1318090075Sobrien	  reg_containing_return_addr = LR_REGNUM;
1318190075Sobrien	}
1318290075Sobrien      else if (size > 12)
1318390075Sobrien	{
1318490075Sobrien	  /* Register a4 is being used to hold part of the return value,
1318590075Sobrien	     but we have dire need of a free, low register.  */
1318690075Sobrien	  restore_a4 = TRUE;
13187169689Skan
1318890075Sobrien	  asm_fprintf (f, "\tmov\t%r, %r\n",IP_REGNUM, LAST_ARG_REGNUM);
1318990075Sobrien	}
13190169689Skan
1319190075Sobrien      if (reg_containing_return_addr != LAST_ARG_REGNUM)
1319290075Sobrien	{
1319390075Sobrien	  /* The fourth argument register is available.  */
1319490075Sobrien	  regs_available_for_popping |= 1 << LAST_ARG_REGNUM;
13195169689Skan
1319690075Sobrien	  --pops_needed;
1319790075Sobrien	}
1319890075Sobrien    }
1319990075Sobrien
1320090075Sobrien  /* Pop as many registers as we can.  */
13201132718Skan  thumb_pushpop (f, regs_available_for_popping, FALSE, NULL,
13202132718Skan		 regs_available_for_popping);
1320390075Sobrien
1320490075Sobrien  /* Process the registers we popped.  */
1320590075Sobrien  if (reg_containing_return_addr == -1)
1320690075Sobrien    {
1320790075Sobrien      /* The return address was popped into the lowest numbered register.  */
1320890075Sobrien      regs_to_pop &= ~(1 << LR_REGNUM);
13209169689Skan
1321090075Sobrien      reg_containing_return_addr =
1321190075Sobrien	number_of_first_bit_set (regs_available_for_popping);
1321290075Sobrien
1321390075Sobrien      /* Remove this register for the mask of available registers, so that
13214132718Skan         the return address will not be corrupted by further pops.  */
1321590075Sobrien      regs_available_for_popping &= ~(1 << reg_containing_return_addr);
1321690075Sobrien    }
1321790075Sobrien
1321890075Sobrien  /* If we popped other registers then handle them here.  */
1321990075Sobrien  if (regs_available_for_popping)
1322090075Sobrien    {
1322190075Sobrien      int frame_pointer;
13222169689Skan
1322390075Sobrien      /* Work out which register currently contains the frame pointer.  */
1322490075Sobrien      frame_pointer = number_of_first_bit_set (regs_available_for_popping);
1322590075Sobrien
1322690075Sobrien      /* Move it into the correct place.  */
1322790075Sobrien      asm_fprintf (f, "\tmov\t%r, %r\n",
1322890075Sobrien		   ARM_HARD_FRAME_POINTER_REGNUM, frame_pointer);
1322990075Sobrien
1323090075Sobrien      /* (Temporarily) remove it from the mask of popped registers.  */
1323190075Sobrien      regs_available_for_popping &= ~(1 << frame_pointer);
1323290075Sobrien      regs_to_pop &= ~(1 << ARM_HARD_FRAME_POINTER_REGNUM);
13233169689Skan
1323490075Sobrien      if (regs_available_for_popping)
1323590075Sobrien	{
1323690075Sobrien	  int stack_pointer;
13237169689Skan
1323890075Sobrien	  /* We popped the stack pointer as well,
1323990075Sobrien	     find the register that contains it.  */
1324090075Sobrien	  stack_pointer = number_of_first_bit_set (regs_available_for_popping);
1324190075Sobrien
1324290075Sobrien	  /* Move it into the stack register.  */
1324390075Sobrien	  asm_fprintf (f, "\tmov\t%r, %r\n", SP_REGNUM, stack_pointer);
13244169689Skan
1324590075Sobrien	  /* At this point we have popped all necessary registers, so
1324690075Sobrien	     do not worry about restoring regs_available_for_popping
1324790075Sobrien	     to its correct value:
1324890075Sobrien
1324990075Sobrien	     assert (pops_needed == 0)
1325090075Sobrien	     assert (regs_available_for_popping == (1 << frame_pointer))
1325190075Sobrien	     assert (regs_to_pop == (1 << STACK_POINTER))  */
1325290075Sobrien	}
1325390075Sobrien      else
1325490075Sobrien	{
1325590075Sobrien	  /* Since we have just move the popped value into the frame
1325690075Sobrien	     pointer, the popping register is available for reuse, and
1325790075Sobrien	     we know that we still have the stack pointer left to pop.  */
1325890075Sobrien	  regs_available_for_popping |= (1 << frame_pointer);
1325990075Sobrien	}
1326090075Sobrien    }
13261169689Skan
1326290075Sobrien  /* If we still have registers left on the stack, but we no longer have
1326390075Sobrien     any registers into which we can pop them, then we must move the return
1326490075Sobrien     address into the link register and make available the register that
1326590075Sobrien     contained it.  */
1326690075Sobrien  if (regs_available_for_popping == 0 && pops_needed > 0)
1326790075Sobrien    {
1326890075Sobrien      regs_available_for_popping |= 1 << reg_containing_return_addr;
13269169689Skan
1327090075Sobrien      asm_fprintf (f, "\tmov\t%r, %r\n", LR_REGNUM,
1327190075Sobrien		   reg_containing_return_addr);
13272169689Skan
1327390075Sobrien      reg_containing_return_addr = LR_REGNUM;
1327490075Sobrien    }
1327590075Sobrien
1327690075Sobrien  /* If we have registers left on the stack then pop some more.
1327790075Sobrien     We know that at most we will want to pop FP and SP.  */
1327890075Sobrien  if (pops_needed > 0)
1327990075Sobrien    {
1328090075Sobrien      int  popped_into;
1328190075Sobrien      int  move_to;
13282169689Skan
13283132718Skan      thumb_pushpop (f, regs_available_for_popping, FALSE, NULL,
13284132718Skan		     regs_available_for_popping);
1328590075Sobrien
1328690075Sobrien      /* We have popped either FP or SP.
1328790075Sobrien	 Move whichever one it is into the correct register.  */
1328890075Sobrien      popped_into = number_of_first_bit_set (regs_available_for_popping);
1328990075Sobrien      move_to     = number_of_first_bit_set (regs_to_pop);
1329090075Sobrien
1329190075Sobrien      asm_fprintf (f, "\tmov\t%r, %r\n", move_to, popped_into);
1329290075Sobrien
1329390075Sobrien      regs_to_pop &= ~(1 << move_to);
1329490075Sobrien
1329590075Sobrien      --pops_needed;
1329690075Sobrien    }
13297169689Skan
1329890075Sobrien  /* If we still have not popped everything then we must have only
1329990075Sobrien     had one register available to us and we are now popping the SP.  */
1330090075Sobrien  if (pops_needed > 0)
1330190075Sobrien    {
1330290075Sobrien      int  popped_into;
13303169689Skan
13304132718Skan      thumb_pushpop (f, regs_available_for_popping, FALSE, NULL,
13305132718Skan		     regs_available_for_popping);
1330690075Sobrien
1330790075Sobrien      popped_into = number_of_first_bit_set (regs_available_for_popping);
1330890075Sobrien
1330990075Sobrien      asm_fprintf (f, "\tmov\t%r, %r\n", SP_REGNUM, popped_into);
1331090075Sobrien      /*
1331190075Sobrien	assert (regs_to_pop == (1 << STACK_POINTER))
1331290075Sobrien	assert (pops_needed == 1)
1331390075Sobrien      */
1331490075Sobrien    }
1331590075Sobrien
1331690075Sobrien  /* If necessary restore the a4 register.  */
1331790075Sobrien  if (restore_a4)
1331890075Sobrien    {
1331990075Sobrien      if (reg_containing_return_addr != LR_REGNUM)
1332090075Sobrien	{
1332190075Sobrien	  asm_fprintf (f, "\tmov\t%r, %r\n", LR_REGNUM, LAST_ARG_REGNUM);
1332290075Sobrien	  reg_containing_return_addr = LR_REGNUM;
1332390075Sobrien	}
13324169689Skan
1332590075Sobrien      asm_fprintf (f, "\tmov\t%r, %r\n", LAST_ARG_REGNUM, IP_REGNUM);
1332690075Sobrien    }
1332790075Sobrien
13328169689Skan  if (current_function_calls_eh_return)
13329169689Skan    asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, ARM_EH_STACKADJ_REGNUM);
1333090075Sobrien
1333190075Sobrien  /* Return to caller.  */
1333290075Sobrien  asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
1333390075Sobrien}
1333490075Sobrien
1333590075Sobrien
1333690075Sobrienvoid
13337132718Skanthumb_final_prescan_insn (rtx insn)
1333890075Sobrien{
1333990075Sobrien  if (flag_print_asm_name)
1334090075Sobrien    asm_fprintf (asm_out_file, "%@ 0x%04x\n",
1334190075Sobrien		 INSN_ADDRESSES (INSN_UID (insn)));
1334290075Sobrien}
1334390075Sobrien
1334490075Sobrienint
13345132718Skanthumb_shiftable_const (unsigned HOST_WIDE_INT val)
1334690075Sobrien{
1334790075Sobrien  unsigned HOST_WIDE_INT mask = 0xff;
1334890075Sobrien  int i;
1334990075Sobrien
1335090075Sobrien  if (val == 0) /* XXX */
1335190075Sobrien    return 0;
13352169689Skan
1335390075Sobrien  for (i = 0; i < 25; i++)
1335490075Sobrien    if ((val & (mask << i)) == val)
1335590075Sobrien      return 1;
1335690075Sobrien
1335790075Sobrien  return 0;
1335890075Sobrien}
1335990075Sobrien
13360117395Skan/* Returns nonzero if the current function contains,
1336190075Sobrien   or might contain a far jump.  */
13362169689Skanstatic int
13363169689Skanthumb_far_jump_used_p (void)
1336490075Sobrien{
1336590075Sobrien  rtx insn;
1336690075Sobrien
1336790075Sobrien  /* This test is only important for leaf functions.  */
1336890075Sobrien  /* assert (!leaf_function_p ()); */
13369169689Skan
1337090075Sobrien  /* If we have already decided that far jumps may be used,
1337190075Sobrien     do not bother checking again, and always return true even if
1337290075Sobrien     it turns out that they are not being used.  Once we have made
1337390075Sobrien     the decision that far jumps are present (and that hence the link
1337490075Sobrien     register will be pushed onto the stack) we cannot go back on it.  */
1337590075Sobrien  if (cfun->machine->far_jump_used)
1337690075Sobrien    return 1;
1337790075Sobrien
1337890075Sobrien  /* If this function is not being called from the prologue/epilogue
1337990075Sobrien     generation code then it must be being called from the
1338090075Sobrien     INITIAL_ELIMINATION_OFFSET macro.  */
13381169689Skan  if (!(ARM_DOUBLEWORD_ALIGN || reload_completed))
1338290075Sobrien    {
1338390075Sobrien      /* In this case we know that we are being asked about the elimination
1338490075Sobrien	 of the arg pointer register.  If that register is not being used,
1338590075Sobrien	 then there are no arguments on the stack, and we do not have to
1338690075Sobrien	 worry that a far jump might force the prologue to push the link
1338790075Sobrien	 register, changing the stack offsets.  In this case we can just
1338890075Sobrien	 return false, since the presence of far jumps in the function will
1338990075Sobrien	 not affect stack offsets.
1339090075Sobrien
1339190075Sobrien	 If the arg pointer is live (or if it was live, but has now been
1339290075Sobrien	 eliminated and so set to dead) then we do have to test to see if
1339390075Sobrien	 the function might contain a far jump.  This test can lead to some
1339490075Sobrien	 false negatives, since before reload is completed, then length of
1339590075Sobrien	 branch instructions is not known, so gcc defaults to returning their
1339690075Sobrien	 longest length, which in turn sets the far jump attribute to true.
1339790075Sobrien
1339890075Sobrien	 A false negative will not result in bad code being generated, but it
1339990075Sobrien	 will result in a needless push and pop of the link register.  We
13400169689Skan	 hope that this does not occur too often.
13401169689Skan
13402169689Skan	 If we need doubleword stack alignment this could affect the other
13403169689Skan	 elimination offsets so we can't risk getting it wrong.  */
1340490075Sobrien      if (regs_ever_live [ARG_POINTER_REGNUM])
1340590075Sobrien	cfun->machine->arg_pointer_live = 1;
1340690075Sobrien      else if (!cfun->machine->arg_pointer_live)
1340790075Sobrien	return 0;
1340890075Sobrien    }
1340990075Sobrien
1341090075Sobrien  /* Check to see if the function contains a branch
1341190075Sobrien     insn with the far jump attribute set.  */
1341290075Sobrien  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
1341390075Sobrien    {
1341490075Sobrien      if (GET_CODE (insn) == JUMP_INSN
1341590075Sobrien	  /* Ignore tablejump patterns.  */
1341690075Sobrien	  && GET_CODE (PATTERN (insn)) != ADDR_VEC
1341790075Sobrien	  && GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC
1341890075Sobrien	  && get_attr_far_jump (insn) == FAR_JUMP_YES
1341990075Sobrien	  )
1342090075Sobrien	{
13421132718Skan	  /* Record the fact that we have decided that
1342290075Sobrien	     the function does use far jumps.  */
1342390075Sobrien	  cfun->machine->far_jump_used = 1;
1342490075Sobrien	  return 1;
1342590075Sobrien	}
1342690075Sobrien    }
13427169689Skan
1342890075Sobrien  return 0;
1342990075Sobrien}
1343090075Sobrien
13431117395Skan/* Return nonzero if FUNC must be entered in ARM mode.  */
1343290075Sobrienint
13433132718Skanis_called_in_ARM_mode (tree func)
1343490075Sobrien{
13435169689Skan  gcc_assert (TREE_CODE (func) == FUNCTION_DECL);
1343690075Sobrien
13437169689Skan  /* Ignore the problem about functions whose address is taken.  */
1343890075Sobrien  if (TARGET_CALLEE_INTERWORKING && TREE_PUBLIC (func))
1343990075Sobrien    return TRUE;
1344090075Sobrien
13441169689Skan#ifdef ARM_PE
1344290075Sobrien  return lookup_attribute ("interfacearm", DECL_ATTRIBUTES (func)) != NULL_TREE;
1344390075Sobrien#else
1344490075Sobrien  return FALSE;
1344590075Sobrien#endif
1344690075Sobrien}
1344790075Sobrien
13448132718Skan/* The bits which aren't usefully expanded as rtl.  */
1344990075Sobrienconst char *
13450132718Skanthumb_unexpanded_epilogue (void)
1345190075Sobrien{
1345290075Sobrien  int regno;
13453169689Skan  unsigned long live_regs_mask = 0;
1345490075Sobrien  int high_regs_pushed = 0;
1345590075Sobrien  int had_to_push_lr;
13456169689Skan  int size;
1345790075Sobrien
1345890075Sobrien  if (return_used_this_function)
1345990075Sobrien    return "";
1346090075Sobrien
13461117395Skan  if (IS_NAKED (arm_current_func_type ()))
13462117395Skan    return "";
13463117395Skan
13464169689Skan  live_regs_mask = thumb_compute_save_reg_mask ();
13465169689Skan  high_regs_pushed = bit_count (live_regs_mask & 0x0f00);
1346690075Sobrien
13467169689Skan  /* If we can deduce the registers used from the function's return value.
13468169689Skan     This is more reliable that examining regs_ever_live[] because that
13469169689Skan     will be set if the register is ever used in the function, not just if
13470169689Skan     the register is used to hold a return value.  */
13471169689Skan  size = arm_size_return_regs ();
1347290075Sobrien
1347390075Sobrien  /* The prolog may have pushed some high registers to use as
13474169689Skan     work registers.  e.g. the testsuite file:
1347590075Sobrien     gcc/testsuite/gcc/gcc.c-torture/execute/complex-2.c
1347690075Sobrien     compiles to produce:
1347790075Sobrien	push	{r4, r5, r6, r7, lr}
1347890075Sobrien	mov	r7, r9
1347990075Sobrien	mov	r6, r8
1348090075Sobrien	push	{r6, r7}
1348190075Sobrien     as part of the prolog.  We have to undo that pushing here.  */
13482169689Skan
1348390075Sobrien  if (high_regs_pushed)
1348490075Sobrien    {
13485169689Skan      unsigned long mask = live_regs_mask & 0xff;
1348690075Sobrien      int next_hi_reg;
1348790075Sobrien
13488169689Skan      /* The available low registers depend on the size of the value we are
13489169689Skan         returning.  */
13490169689Skan      if (size <= 12)
1349190075Sobrien	mask |=  1 << 3;
13492169689Skan      if (size <= 8)
13493169689Skan	mask |= 1 << 2;
1349490075Sobrien
1349590075Sobrien      if (mask == 0)
1349690075Sobrien	/* Oh dear!  We have no low registers into which we can pop
1349790075Sobrien           high registers!  */
1349890075Sobrien	internal_error
1349990075Sobrien	  ("no low registers available for popping high registers");
13500169689Skan
1350190075Sobrien      for (next_hi_reg = 8; next_hi_reg < 13; next_hi_reg++)
13502169689Skan	if (live_regs_mask & (1 << next_hi_reg))
1350390075Sobrien	  break;
1350490075Sobrien
1350590075Sobrien      while (high_regs_pushed)
1350690075Sobrien	{
1350790075Sobrien	  /* Find lo register(s) into which the high register(s) can
1350890075Sobrien             be popped.  */
1350990075Sobrien	  for (regno = 0; regno <= LAST_LO_REGNUM; regno++)
1351090075Sobrien	    {
1351190075Sobrien	      if (mask & (1 << regno))
1351290075Sobrien		high_regs_pushed--;
1351390075Sobrien	      if (high_regs_pushed == 0)
1351490075Sobrien		break;
1351590075Sobrien	    }
1351690075Sobrien
1351790075Sobrien	  mask &= (2 << regno) - 1;	/* A noop if regno == 8 */
1351890075Sobrien
13519132718Skan	  /* Pop the values into the low register(s).  */
13520132718Skan	  thumb_pushpop (asm_out_file, mask, 0, NULL, mask);
1352190075Sobrien
1352290075Sobrien	  /* Move the value(s) into the high registers.  */
1352390075Sobrien	  for (regno = 0; regno <= LAST_LO_REGNUM; regno++)
1352490075Sobrien	    {
1352590075Sobrien	      if (mask & (1 << regno))
1352690075Sobrien		{
1352790075Sobrien		  asm_fprintf (asm_out_file, "\tmov\t%r, %r\n", next_hi_reg,
1352890075Sobrien			       regno);
13529169689Skan
1353090075Sobrien		  for (next_hi_reg++; next_hi_reg < 13; next_hi_reg++)
13531169689Skan		    if (live_regs_mask & (1 << next_hi_reg))
1353290075Sobrien		      break;
1353390075Sobrien		}
1353490075Sobrien	    }
1353590075Sobrien	}
13536169689Skan      live_regs_mask &= ~0x0f00;
1353790075Sobrien    }
1353890075Sobrien
13539169689Skan  had_to_push_lr = (live_regs_mask & (1 << LR_REGNUM)) != 0;
13540169689Skan  live_regs_mask &= 0xff;
13541169689Skan
1354290075Sobrien  if (current_function_pretend_args_size == 0 || TARGET_BACKTRACE)
1354390075Sobrien    {
13544169689Skan      /* Pop the return address into the PC.  */
13545169689Skan      if (had_to_push_lr)
1354690075Sobrien	live_regs_mask |= 1 << PC_REGNUM;
1354790075Sobrien
1354890075Sobrien      /* Either no argument registers were pushed or a backtrace
1354990075Sobrien	 structure was created which includes an adjusted stack
1355090075Sobrien	 pointer, so just pop everything.  */
1355190075Sobrien      if (live_regs_mask)
13552132718Skan	thumb_pushpop (asm_out_file, live_regs_mask, FALSE, NULL,
13553132718Skan		       live_regs_mask);
13554169689Skan
1355590075Sobrien      /* We have either just popped the return address into the
13556169689Skan	 PC or it is was kept in LR for the entire function.  */
13557169689Skan      if (!had_to_push_lr)
13558169689Skan	thumb_exit (asm_out_file, LR_REGNUM);
1355990075Sobrien    }
1356090075Sobrien  else
1356190075Sobrien    {
1356290075Sobrien      /* Pop everything but the return address.  */
1356390075Sobrien      if (live_regs_mask)
13564132718Skan	thumb_pushpop (asm_out_file, live_regs_mask, FALSE, NULL,
13565132718Skan		       live_regs_mask);
1356690075Sobrien
1356790075Sobrien      if (had_to_push_lr)
13568169689Skan	{
13569169689Skan	  if (size > 12)
13570169689Skan	    {
13571169689Skan	      /* We have no free low regs, so save one.  */
13572169689Skan	      asm_fprintf (asm_out_file, "\tmov\t%r, %r\n", IP_REGNUM,
13573169689Skan			   LAST_ARG_REGNUM);
13574169689Skan	    }
13575169689Skan
13576169689Skan	  /* Get the return address into a temporary register.  */
13577169689Skan	  thumb_pushpop (asm_out_file, 1 << LAST_ARG_REGNUM, 0, NULL,
13578169689Skan			 1 << LAST_ARG_REGNUM);
13579169689Skan
13580169689Skan	  if (size > 12)
13581169689Skan	    {
13582169689Skan	      /* Move the return address to lr.  */
13583169689Skan	      asm_fprintf (asm_out_file, "\tmov\t%r, %r\n", LR_REGNUM,
13584169689Skan			   LAST_ARG_REGNUM);
13585169689Skan	      /* Restore the low register.  */
13586169689Skan	      asm_fprintf (asm_out_file, "\tmov\t%r, %r\n", LAST_ARG_REGNUM,
13587169689Skan			   IP_REGNUM);
13588169689Skan	      regno = LR_REGNUM;
13589169689Skan	    }
13590169689Skan	  else
13591169689Skan	    regno = LAST_ARG_REGNUM;
13592169689Skan	}
13593169689Skan      else
13594169689Skan	regno = LR_REGNUM;
13595169689Skan
1359690075Sobrien      /* Remove the argument registers that were pushed onto the stack.  */
1359790075Sobrien      asm_fprintf (asm_out_file, "\tadd\t%r, %r, #%d\n",
1359890075Sobrien		   SP_REGNUM, SP_REGNUM,
1359990075Sobrien		   current_function_pretend_args_size);
13600169689Skan
13601169689Skan      thumb_exit (asm_out_file, regno);
1360290075Sobrien    }
1360390075Sobrien
1360490075Sobrien  return "";
1360590075Sobrien}
1360690075Sobrien
1360790075Sobrien/* Functions to save and restore machine-specific function data.  */
13608117395Skanstatic struct machine_function *
13609132718Skanarm_init_machine_status (void)
1361090075Sobrien{
13611117395Skan  struct machine_function *machine;
13612117395Skan  machine = (machine_function *) ggc_alloc_cleared (sizeof (machine_function));
1361390075Sobrien
13614169689Skan#if ARM_FT_UNKNOWN != 0
13615117395Skan  machine->func_type = ARM_FT_UNKNOWN;
1361690075Sobrien#endif
13617117395Skan  return machine;
1361890075Sobrien}
1361990075Sobrien
1362090075Sobrien/* Return an RTX indicating where the return address to the
1362190075Sobrien   calling function can be found.  */
1362290075Sobrienrtx
13623132718Skanarm_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
1362490075Sobrien{
1362590075Sobrien  if (count != 0)
1362690075Sobrien    return NULL_RTX;
1362790075Sobrien
13628169689Skan  return get_hard_reg_initial_val (Pmode, LR_REGNUM);
1362990075Sobrien}
1363090075Sobrien
1363190075Sobrien/* Do anything needed before RTL is emitted for each function.  */
1363290075Sobrienvoid
13633132718Skanarm_init_expanders (void)
1363490075Sobrien{
1363590075Sobrien  /* Arrange to initialize and mark the machine per-function status.  */
1363690075Sobrien  init_machine_status = arm_init_machine_status;
13637169689Skan
13638169689Skan  /* This is to stop the combine pass optimizing away the alignment
13639169689Skan     adjustment of va_arg.  */
13640169689Skan  /* ??? It is claimed that this should not be necessary.  */
13641169689Skan  if (cfun)
13642169689Skan    mark_reg_pointer (arg_pointer_rtx, PARM_BOUNDARY);
1364390075Sobrien}
1364490075Sobrien
13645169689Skan
13646169689Skan/* Like arm_compute_initial_elimination offset.  Simpler because there
13647169689Skan   isn't an ABI specified frame pointer for Thumb.  Instead, we set it
13648169689Skan   to point at the base of the local variables after static stack
13649169689Skan   space for a function has been allocated.  */
13650169689Skan
13651117395SkanHOST_WIDE_INT
13652169689Skanthumb_compute_initial_elimination_offset (unsigned int from, unsigned int to)
13653117395Skan{
13654169689Skan  arm_stack_offsets *offsets;
13655117395Skan
13656169689Skan  offsets = arm_get_frame_offsets ();
13657117395Skan
13658169689Skan  switch (from)
13659169689Skan    {
13660169689Skan    case ARG_POINTER_REGNUM:
13661169689Skan      switch (to)
13662169689Skan	{
13663169689Skan	case STACK_POINTER_REGNUM:
13664169689Skan	  return offsets->outgoing_args - offsets->saved_args;
13665117395Skan
13666169689Skan	case FRAME_POINTER_REGNUM:
13667169689Skan	  return offsets->soft_frame - offsets->saved_args;
13668117395Skan
13669169689Skan	case ARM_HARD_FRAME_POINTER_REGNUM:
13670169689Skan	  return offsets->saved_regs - offsets->saved_args;
13671117395Skan
13672169689Skan	case THUMB_HARD_FRAME_POINTER_REGNUM:
13673169689Skan	  return offsets->locals_base - offsets->saved_args;
13674117395Skan
13675169689Skan	default:
13676169689Skan	  gcc_unreachable ();
13677169689Skan	}
13678169689Skan      break;
13679117395Skan
13680169689Skan    case FRAME_POINTER_REGNUM:
13681169689Skan      switch (to)
13682169689Skan	{
13683169689Skan	case STACK_POINTER_REGNUM:
13684169689Skan	  return offsets->outgoing_args - offsets->soft_frame;
13685117395Skan
13686169689Skan	case ARM_HARD_FRAME_POINTER_REGNUM:
13687169689Skan	  return offsets->saved_regs - offsets->soft_frame;
13688117395Skan
13689169689Skan	case THUMB_HARD_FRAME_POINTER_REGNUM:
13690169689Skan	  return offsets->locals_base - offsets->soft_frame;
13691117395Skan
13692169689Skan	default:
13693169689Skan	  gcc_unreachable ();
13694169689Skan	}
13695169689Skan      break;
13696117395Skan
13697169689Skan    default:
13698169689Skan      gcc_unreachable ();
13699117395Skan    }
13700169689Skan}
13701117395Skan
13702117395Skan
1370390075Sobrien/* Generate the rest of a function's prologue.  */
1370490075Sobrienvoid
13705132718Skanthumb_expand_prologue (void)
1370690075Sobrien{
13707132718Skan  rtx insn, dwarf;
13708132718Skan
13709169689Skan  HOST_WIDE_INT amount;
13710169689Skan  arm_stack_offsets *offsets;
1371190075Sobrien  unsigned long func_type;
13712169689Skan  int regno;
13713169689Skan  unsigned long live_regs_mask;
1371490075Sobrien
1371590075Sobrien  func_type = arm_current_func_type ();
13716169689Skan
1371790075Sobrien  /* Naked functions don't have prologues.  */
1371890075Sobrien  if (IS_NAKED (func_type))
1371990075Sobrien    return;
1372090075Sobrien
1372190075Sobrien  if (IS_INTERRUPT (func_type))
1372290075Sobrien    {
1372390075Sobrien      error ("interrupt Service Routines cannot be coded in Thumb mode");
1372490075Sobrien      return;
1372590075Sobrien    }
1372690075Sobrien
13727169689Skan  live_regs_mask = thumb_compute_save_reg_mask ();
13728169689Skan  /* Load the pic register before setting the frame pointer,
13729169689Skan     so we can use r7 as a temporary work register.  */
13730169689Skan  if (flag_pic && arm_pic_register != INVALID_REGNUM)
13731169689Skan    arm_load_pic_register (live_regs_mask);
1373290075Sobrien
13733169689Skan  if (!frame_pointer_needed && CALLER_INTERWORKING_SLOT_SIZE > 0)
13734169689Skan    emit_move_insn (gen_rtx_REG (Pmode, ARM_HARD_FRAME_POINTER_REGNUM),
13735169689Skan		    stack_pointer_rtx);
13736169689Skan
13737169689Skan  offsets = arm_get_frame_offsets ();
13738169689Skan  amount = offsets->outgoing_args - offsets->saved_regs;
1373990075Sobrien  if (amount)
1374090075Sobrien    {
1374190075Sobrien      if (amount < 512)
13742132718Skan	{
13743132718Skan	  insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
13744132718Skan					GEN_INT (- amount)));
13745132718Skan	  RTX_FRAME_RELATED_P (insn) = 1;
13746132718Skan	}
1374790075Sobrien      else
1374890075Sobrien	{
1374990075Sobrien	  rtx reg;
1375090075Sobrien
1375190075Sobrien	  /* The stack decrement is too big for an immediate value in a single
1375290075Sobrien	     insn.  In theory we could issue multiple subtracts, but after
1375390075Sobrien	     three of them it becomes more space efficient to place the full
1375490075Sobrien	     value in the constant pool and load into a register.  (Also the
1375590075Sobrien	     ARM debugger really likes to see only one stack decrement per
1375690075Sobrien	     function).  So instead we look for a scratch register into which
1375790075Sobrien	     we can load the decrement, and then we subtract this from the
1375890075Sobrien	     stack pointer.  Unfortunately on the thumb the only available
1375990075Sobrien	     scratch registers are the argument registers, and we cannot use
1376090075Sobrien	     these as they may hold arguments to the function.  Instead we
1376190075Sobrien	     attempt to locate a call preserved register which is used by this
1376290075Sobrien	     function.  If we can find one, then we know that it will have
1376390075Sobrien	     been pushed at the start of the prologue and so we can corrupt
1376490075Sobrien	     it now.  */
1376590075Sobrien	  for (regno = LAST_ARG_REGNUM + 1; regno <= LAST_LO_REGNUM; regno++)
13766169689Skan	    if (live_regs_mask & (1 << regno)
1376790075Sobrien		&& !(frame_pointer_needed
1376890075Sobrien		     && (regno == THUMB_HARD_FRAME_POINTER_REGNUM)))
1376990075Sobrien	      break;
1377090075Sobrien
13771117395Skan	  if (regno > LAST_LO_REGNUM) /* Very unlikely.  */
1377290075Sobrien	    {
13773169689Skan	      rtx spare = gen_rtx_REG (SImode, IP_REGNUM);
1377490075Sobrien
13775132718Skan	      /* Choose an arbitrary, non-argument low register.  */
13776169689Skan	      reg = gen_rtx_REG (SImode, LAST_LO_REGNUM);
1377790075Sobrien
1377890075Sobrien	      /* Save it by copying it into a high, scratch register.  */
1377990075Sobrien	      emit_insn (gen_movsi (spare, reg));
1378090075Sobrien	      /* Add a USE to stop propagate_one_insn() from barfing.  */
1378190075Sobrien	      emit_insn (gen_prologue_use (spare));
1378290075Sobrien
1378390075Sobrien	      /* Decrement the stack.  */
1378490075Sobrien	      emit_insn (gen_movsi (reg, GEN_INT (- amount)));
13785132718Skan	      insn = emit_insn (gen_addsi3 (stack_pointer_rtx,
13786132718Skan					    stack_pointer_rtx, reg));
13787132718Skan	      RTX_FRAME_RELATED_P (insn) = 1;
13788169689Skan	      dwarf = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
13789132718Skan				   plus_constant (stack_pointer_rtx,
13790169689Skan						  -amount));
13791132718Skan	      RTX_FRAME_RELATED_P (dwarf) = 1;
13792132718Skan	      REG_NOTES (insn)
13793132718Skan		= gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
13794132718Skan				     REG_NOTES (insn));
1379590075Sobrien
1379690075Sobrien	      /* Restore the low register's original value.  */
1379790075Sobrien	      emit_insn (gen_movsi (reg, spare));
13798169689Skan
1379990075Sobrien	      /* Emit a USE of the restored scratch register, so that flow
1380090075Sobrien		 analysis will not consider the restore redundant.  The
1380190075Sobrien		 register won't be used again in this function and isn't
1380290075Sobrien		 restored by the epilogue.  */
1380390075Sobrien	      emit_insn (gen_prologue_use (reg));
1380490075Sobrien	    }
1380590075Sobrien	  else
1380690075Sobrien	    {
13807169689Skan	      reg = gen_rtx_REG (SImode, regno);
1380890075Sobrien
1380990075Sobrien	      emit_insn (gen_movsi (reg, GEN_INT (- amount)));
13810132718Skan
13811132718Skan	      insn = emit_insn (gen_addsi3 (stack_pointer_rtx,
13812132718Skan					    stack_pointer_rtx, reg));
13813132718Skan	      RTX_FRAME_RELATED_P (insn) = 1;
13814169689Skan	      dwarf = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
13815132718Skan				   plus_constant (stack_pointer_rtx,
13816169689Skan						  -amount));
13817132718Skan	      RTX_FRAME_RELATED_P (dwarf) = 1;
13818132718Skan	      REG_NOTES (insn)
13819132718Skan		= gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
13820132718Skan				     REG_NOTES (insn));
1382190075Sobrien	    }
1382290075Sobrien	}
1382390075Sobrien    }
13824169689Skan
13825169689Skan  if (frame_pointer_needed)
13826169689Skan    {
13827169689Skan      amount = offsets->outgoing_args - offsets->locals_base;
13828169689Skan
13829169689Skan      if (amount < 1024)
13830169689Skan	insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx,
13831169689Skan				      stack_pointer_rtx, GEN_INT (amount)));
13832169689Skan      else
13833169689Skan	{
13834169689Skan	  emit_insn (gen_movsi (hard_frame_pointer_rtx, GEN_INT (amount)));
13835169689Skan	  insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx,
13836169689Skan					hard_frame_pointer_rtx,
13837169689Skan					stack_pointer_rtx));
13838169689Skan	  dwarf = gen_rtx_SET (VOIDmode, hard_frame_pointer_rtx,
13839169689Skan			       plus_constant (stack_pointer_rtx, amount));
13840169689Skan	  RTX_FRAME_RELATED_P (dwarf) = 1;
13841169689Skan	  REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
13842169689Skan						REG_NOTES (insn));
13843169689Skan	}
13844169689Skan
13845169689Skan      RTX_FRAME_RELATED_P (insn) = 1;
13846169689Skan    }
13847169689Skan
13848169689Skan  /* If we are profiling, make sure no instructions are scheduled before
13849169689Skan     the call to mcount.  Similarly if the user has requested no
13850169689Skan     scheduling in the prolog.  Similarly if we want non-call exceptions
13851169689Skan     using the EABI unwinder, to prevent faulting instructions from being
13852169689Skan     swapped with a stack adjustment.  */
13853169689Skan  if (current_function_profile || !TARGET_SCHED_PROLOG
13854169689Skan      || (ARM_EABI_UNWIND_TABLES && flag_non_call_exceptions))
1385590075Sobrien    emit_insn (gen_blockage ());
13856169689Skan
13857169689Skan  cfun->machine->lr_save_eliminated = !thumb_force_lr_save ();
13858169689Skan  if (live_regs_mask & 0xff)
13859169689Skan    cfun->machine->lr_save_eliminated = 0;
13860169689Skan
13861169689Skan  /* If the link register is being kept alive, with the return address in it,
13862169689Skan     then make sure that it does not get reused by the ce2 pass.  */
13863169689Skan  if (cfun->machine->lr_save_eliminated)
13864169689Skan    emit_insn (gen_prologue_use (gen_rtx_REG (SImode, LR_REGNUM)));
1386590075Sobrien}
1386690075Sobrien
13867169689Skan
1386890075Sobrienvoid
13869132718Skanthumb_expand_epilogue (void)
1387090075Sobrien{
13871169689Skan  HOST_WIDE_INT amount;
13872169689Skan  arm_stack_offsets *offsets;
13873132718Skan  int regno;
13874132718Skan
1387590075Sobrien  /* Naked functions don't have prologues.  */
1387690075Sobrien  if (IS_NAKED (arm_current_func_type ()))
1387790075Sobrien    return;
1387890075Sobrien
13879169689Skan  offsets = arm_get_frame_offsets ();
13880169689Skan  amount = offsets->outgoing_args - offsets->saved_regs;
13881169689Skan
1388290075Sobrien  if (frame_pointer_needed)
1388390075Sobrien    {
13884169689Skan      emit_insn (gen_movsi (stack_pointer_rtx, hard_frame_pointer_rtx));
13885169689Skan      amount = offsets->locals_base - offsets->saved_regs;
13886169689Skan    }
13887169689Skan
13888171825Skan  gcc_assert (amount >= 0);
13889169689Skan  if (amount)
13890169689Skan    {
1389190075Sobrien      if (amount < 512)
1389290075Sobrien	emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
1389390075Sobrien			       GEN_INT (amount)));
1389490075Sobrien      else
1389590075Sobrien	{
1389690075Sobrien	  /* r3 is always free in the epilogue.  */
13897169689Skan	  rtx reg = gen_rtx_REG (SImode, LAST_ARG_REGNUM);
1389890075Sobrien
1389990075Sobrien	  emit_insn (gen_movsi (reg, GEN_INT (amount)));
1390090075Sobrien	  emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, reg));
1390190075Sobrien	}
1390290075Sobrien    }
13903169689Skan
1390490075Sobrien  /* Emit a USE (stack_pointer_rtx), so that
1390590075Sobrien     the stack adjustment will not be deleted.  */
1390690075Sobrien  emit_insn (gen_prologue_use (stack_pointer_rtx));
1390790075Sobrien
13908169689Skan  if (current_function_profile || !TARGET_SCHED_PROLOG)
1390990075Sobrien    emit_insn (gen_blockage ());
13910132718Skan
13911132718Skan  /* Emit a clobber for each insn that will be restored in the epilogue,
13912132718Skan     so that flow2 will get register lifetimes correct.  */
13913132718Skan  for (regno = 0; regno < 13; regno++)
13914132718Skan    if (regs_ever_live[regno] && !call_used_regs[regno])
13915132718Skan      emit_insn (gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, regno)));
13916132718Skan
13917132718Skan  if (! regs_ever_live[LR_REGNUM])
13918132718Skan    emit_insn (gen_rtx_USE (VOIDmode, gen_rtx_REG (SImode, LR_REGNUM)));
1391990075Sobrien}
1392090075Sobrien
1392190075Sobrienstatic void
13922132718Skanthumb_output_function_prologue (FILE *f, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
1392390075Sobrien{
13924169689Skan  unsigned long live_regs_mask = 0;
13925169689Skan  unsigned long l_mask;
13926169689Skan  unsigned high_regs_pushed = 0;
13927132718Skan  int cfa_offset = 0;
1392890075Sobrien  int regno;
1392990075Sobrien
1393090075Sobrien  if (IS_NAKED (arm_current_func_type ()))
1393190075Sobrien    return;
1393290075Sobrien
1393390075Sobrien  if (is_called_in_ARM_mode (current_function_decl))
1393490075Sobrien    {
1393590075Sobrien      const char * name;
1393690075Sobrien
13937169689Skan      gcc_assert (GET_CODE (DECL_RTL (current_function_decl)) == MEM);
13938169689Skan      gcc_assert (GET_CODE (XEXP (DECL_RTL (current_function_decl), 0))
13939169689Skan		  == SYMBOL_REF);
1394090075Sobrien      name = XSTR  (XEXP (DECL_RTL (current_function_decl), 0), 0);
13941169689Skan
1394290075Sobrien      /* Generate code sequence to switch us into Thumb mode.  */
1394390075Sobrien      /* The .code 32 directive has already been emitted by
1394490075Sobrien	 ASM_DECLARE_FUNCTION_NAME.  */
1394590075Sobrien      asm_fprintf (f, "\torr\t%r, %r, #1\n", IP_REGNUM, PC_REGNUM);
1394690075Sobrien      asm_fprintf (f, "\tbx\t%r\n", IP_REGNUM);
1394790075Sobrien
1394890075Sobrien      /* Generate a label, so that the debugger will notice the
1394990075Sobrien	 change in instruction sets.  This label is also used by
1395090075Sobrien	 the assembler to bypass the ARM code when this function
1395190075Sobrien	 is called from a Thumb encoded function elsewhere in the
1395290075Sobrien	 same file.  Hence the definition of STUB_NAME here must
13953132718Skan	 agree with the definition in gas/config/tc-arm.c.  */
13954169689Skan
1395590075Sobrien#define STUB_NAME ".real_start_of"
13956169689Skan
13957117395Skan      fprintf (f, "\t.code\t16\n");
1395890075Sobrien#ifdef ARM_PE
1395990075Sobrien      if (arm_dllexport_name_p (name))
1396090075Sobrien        name = arm_strip_name_encoding (name);
13961169689Skan#endif
1396290075Sobrien      asm_fprintf (f, "\t.globl %s%U%s\n", STUB_NAME, name);
13963117395Skan      fprintf (f, "\t.thumb_func\n");
1396490075Sobrien      asm_fprintf (f, "%s%U%s:\n", STUB_NAME, name);
1396590075Sobrien    }
13966169689Skan
1396790075Sobrien  if (current_function_pretend_args_size)
1396890075Sobrien    {
13969169689Skan      /* Output unwind directive for the stack adjustment.  */
13970169689Skan      if (ARM_EABI_UNWIND_TABLES)
13971169689Skan	fprintf (f, "\t.pad #%d\n",
13972169689Skan		 current_function_pretend_args_size);
13973169689Skan
1397496263Sobrien      if (cfun->machine->uses_anonymous_args)
1397590075Sobrien	{
1397690075Sobrien	  int num_pushes;
13977169689Skan
13978117395Skan	  fprintf (f, "\tpush\t{");
1397990075Sobrien
13980117395Skan	  num_pushes = ARM_NUM_INTS (current_function_pretend_args_size);
13981169689Skan
1398290075Sobrien	  for (regno = LAST_ARG_REGNUM + 1 - num_pushes;
1398390075Sobrien	       regno <= LAST_ARG_REGNUM;
1398490075Sobrien	       regno++)
1398590075Sobrien	    asm_fprintf (f, "%r%s", regno,
1398690075Sobrien			 regno == LAST_ARG_REGNUM ? "" : ", ");
1398790075Sobrien
13988117395Skan	  fprintf (f, "}\n");
1398990075Sobrien	}
1399090075Sobrien      else
13991169689Skan	asm_fprintf (f, "\tsub\t%r, %r, #%d\n",
1399290075Sobrien		     SP_REGNUM, SP_REGNUM,
1399390075Sobrien		     current_function_pretend_args_size);
13994132718Skan
13995132718Skan      /* We don't need to record the stores for unwinding (would it
13996132718Skan	 help the debugger any if we did?), but record the change in
13997132718Skan	 the stack pointer.  */
13998132718Skan      if (dwarf2out_do_frame ())
13999132718Skan	{
14000132718Skan	  char *l = dwarf2out_cfi_label ();
14001169689Skan
14002132718Skan	  cfa_offset = cfa_offset + current_function_pretend_args_size;
14003132718Skan	  dwarf2out_def_cfa (l, SP_REGNUM, cfa_offset);
14004132718Skan	}
1400590075Sobrien    }
1400690075Sobrien
14007169689Skan  /* Get the registers we are going to push.  */
14008169689Skan  live_regs_mask = thumb_compute_save_reg_mask ();
14009169689Skan  /* Extract a mask of the ones we can give to the Thumb's push instruction.  */
14010169689Skan  l_mask = live_regs_mask & 0x40ff;
14011169689Skan  /* Then count how many other high registers will need to be pushed.  */
14012169689Skan  high_regs_pushed = bit_count (live_regs_mask & 0x0f00);
1401390075Sobrien
1401490075Sobrien  if (TARGET_BACKTRACE)
1401590075Sobrien    {
14016169689Skan      unsigned offset;
14017169689Skan      unsigned work_register;
14018169689Skan
1401990075Sobrien      /* We have been asked to create a stack backtrace structure.
1402090075Sobrien         The code looks like this:
14021169689Skan
1402290075Sobrien	 0   .align 2
1402390075Sobrien	 0   func:
1402490075Sobrien         0     sub   SP, #16         Reserve space for 4 registers.
14025169689Skan	 2     push  {R7}            Push low registers.
1402690075Sobrien         4     add   R7, SP, #20     Get the stack pointer before the push.
1402790075Sobrien         6     str   R7, [SP, #8]    Store the stack pointer (before reserving the space).
1402890075Sobrien         8     mov   R7, PC          Get hold of the start of this code plus 12.
1402990075Sobrien        10     str   R7, [SP, #16]   Store it.
1403090075Sobrien        12     mov   R7, FP          Get hold of the current frame pointer.
1403190075Sobrien        14     str   R7, [SP, #4]    Store it.
1403290075Sobrien        16     mov   R7, LR          Get hold of the current return address.
1403390075Sobrien        18     str   R7, [SP, #12]   Store it.
1403490075Sobrien        20     add   R7, SP, #16     Point at the start of the backtrace structure.
1403590075Sobrien        22     mov   FP, R7          Put this value into the frame pointer.  */
1403690075Sobrien
14037169689Skan      work_register = thumb_find_work_register (live_regs_mask);
1403890075Sobrien
14039169689Skan      if (ARM_EABI_UNWIND_TABLES)
14040169689Skan	asm_fprintf (f, "\t.pad #16\n");
1404190075Sobrien
1404290075Sobrien      asm_fprintf
1404390075Sobrien	(f, "\tsub\t%r, %r, #16\t%@ Create stack backtrace structure\n",
1404490075Sobrien	 SP_REGNUM, SP_REGNUM);
14045132718Skan
14046132718Skan      if (dwarf2out_do_frame ())
14047132718Skan	{
14048132718Skan	  char *l = dwarf2out_cfi_label ();
14049169689Skan
14050132718Skan	  cfa_offset = cfa_offset + 16;
14051132718Skan	  dwarf2out_def_cfa (l, SP_REGNUM, cfa_offset);
14052132718Skan	}
14053132718Skan
14054169689Skan      if (l_mask)
14055169689Skan	{
14056169689Skan	  thumb_pushpop (f, l_mask, 1, &cfa_offset, l_mask);
14057169689Skan	  offset = bit_count (l_mask) * UNITS_PER_WORD;
14058169689Skan	}
14059169689Skan      else
14060169689Skan	offset = 0;
14061169689Skan
1406290075Sobrien      asm_fprintf (f, "\tadd\t%r, %r, #%d\n", work_register, SP_REGNUM,
1406390075Sobrien		   offset + 16 + current_function_pretend_args_size);
14064169689Skan
1406590075Sobrien      asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
1406690075Sobrien		   offset + 4);
1406790075Sobrien
1406890075Sobrien      /* Make sure that the instruction fetching the PC is in the right place
1406990075Sobrien	 to calculate "start of backtrace creation code + 12".  */
14070169689Skan      if (l_mask)
1407190075Sobrien	{
1407290075Sobrien	  asm_fprintf (f, "\tmov\t%r, %r\n", work_register, PC_REGNUM);
1407390075Sobrien	  asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
1407490075Sobrien		       offset + 12);
1407590075Sobrien	  asm_fprintf (f, "\tmov\t%r, %r\n", work_register,
1407690075Sobrien		       ARM_HARD_FRAME_POINTER_REGNUM);
1407790075Sobrien	  asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
1407890075Sobrien		       offset);
1407990075Sobrien	}
1408090075Sobrien      else
1408190075Sobrien	{
1408290075Sobrien	  asm_fprintf (f, "\tmov\t%r, %r\n", work_register,
1408390075Sobrien		       ARM_HARD_FRAME_POINTER_REGNUM);
1408490075Sobrien	  asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
1408590075Sobrien		       offset);
1408690075Sobrien	  asm_fprintf (f, "\tmov\t%r, %r\n", work_register, PC_REGNUM);
1408790075Sobrien	  asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
1408890075Sobrien		       offset + 12);
1408990075Sobrien	}
14090169689Skan
1409190075Sobrien      asm_fprintf (f, "\tmov\t%r, %r\n", work_register, LR_REGNUM);
1409290075Sobrien      asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
1409390075Sobrien		   offset + 8);
1409490075Sobrien      asm_fprintf (f, "\tadd\t%r, %r, #%d\n", work_register, SP_REGNUM,
1409590075Sobrien		   offset + 12);
1409690075Sobrien      asm_fprintf (f, "\tmov\t%r, %r\t\t%@ Backtrace structure created\n",
1409790075Sobrien		   ARM_HARD_FRAME_POINTER_REGNUM, work_register);
1409890075Sobrien    }
14099169689Skan  /* Optimization:  If we are not pushing any low registers but we are going
14100169689Skan     to push some high registers then delay our first push.  This will just
14101169689Skan     be a push of LR and we can combine it with the push of the first high
14102169689Skan     register.  */
14103169689Skan  else if ((l_mask & 0xff) != 0
14104169689Skan	   || (high_regs_pushed == 0 && l_mask))
14105169689Skan    thumb_pushpop (f, l_mask, 1, &cfa_offset, l_mask);
1410690075Sobrien
1410790075Sobrien  if (high_regs_pushed)
1410890075Sobrien    {
14109169689Skan      unsigned pushable_regs;
14110169689Skan      unsigned next_hi_reg;
1411190075Sobrien
1411290075Sobrien      for (next_hi_reg = 12; next_hi_reg > LAST_LO_REGNUM; next_hi_reg--)
14113169689Skan	if (live_regs_mask & (1 << next_hi_reg))
14114117395Skan	  break;
1411590075Sobrien
14116169689Skan      pushable_regs = l_mask & 0xff;
1411790075Sobrien
1411890075Sobrien      if (pushable_regs == 0)
14119169689Skan	pushable_regs = 1 << thumb_find_work_register (live_regs_mask);
1412090075Sobrien
1412190075Sobrien      while (high_regs_pushed > 0)
1412290075Sobrien	{
14123169689Skan	  unsigned long real_regs_mask = 0;
14124132718Skan
14125169689Skan	  for (regno = LAST_LO_REGNUM; regno >= 0; regno --)
1412690075Sobrien	    {
14127169689Skan	      if (pushable_regs & (1 << regno))
1412890075Sobrien		{
1412990075Sobrien		  asm_fprintf (f, "\tmov\t%r, %r\n", regno, next_hi_reg);
14130169689Skan
14131169689Skan		  high_regs_pushed --;
14132132718Skan		  real_regs_mask |= (1 << next_hi_reg);
14133169689Skan
1413490075Sobrien		  if (high_regs_pushed)
14135117395Skan		    {
14136169689Skan		      for (next_hi_reg --; next_hi_reg > LAST_LO_REGNUM;
14137169689Skan			   next_hi_reg --)
14138169689Skan			if (live_regs_mask & (1 << next_hi_reg))
1413990075Sobrien			  break;
14140117395Skan		    }
1414190075Sobrien		  else
1414290075Sobrien		    {
14143169689Skan		      pushable_regs &= ~((1 << regno) - 1);
1414490075Sobrien		      break;
1414590075Sobrien		    }
1414690075Sobrien		}
1414790075Sobrien	    }
14148132718Skan
14149169689Skan	  /* If we had to find a work register and we have not yet
14150169689Skan	     saved the LR then add it to the list of regs to push.  */
14151169689Skan	  if (l_mask == (1 << LR_REGNUM))
14152169689Skan	    {
14153169689Skan	      thumb_pushpop (f, pushable_regs | (1 << LR_REGNUM),
14154169689Skan			     1, &cfa_offset,
14155169689Skan			     real_regs_mask | (1 << LR_REGNUM));
14156169689Skan	      l_mask = 0;
14157169689Skan	    }
14158169689Skan	  else
14159169689Skan	    thumb_pushpop (f, pushable_regs, 1, &cfa_offset, real_regs_mask);
1416090075Sobrien	}
1416190075Sobrien    }
1416290075Sobrien}
1416390075Sobrien
1416490075Sobrien/* Handle the case of a double word load into a low register from
1416590075Sobrien   a computed memory address.  The computed address may involve a
1416690075Sobrien   register which is overwritten by the load.  */
1416790075Sobrienconst char *
14168132718Skanthumb_load_double_from_address (rtx *operands)
1416990075Sobrien{
1417090075Sobrien  rtx addr;
1417190075Sobrien  rtx base;
1417290075Sobrien  rtx offset;
1417390075Sobrien  rtx arg1;
1417490075Sobrien  rtx arg2;
1417590075Sobrien
14176169689Skan  gcc_assert (GET_CODE (operands[0]) == REG);
14177169689Skan  gcc_assert (GET_CODE (operands[1]) == MEM);
14178169689Skan
1417990075Sobrien  /* Get the memory address.  */
1418090075Sobrien  addr = XEXP (operands[1], 0);
14181169689Skan
1418290075Sobrien  /* Work out how the memory address is computed.  */
1418390075Sobrien  switch (GET_CODE (addr))
1418490075Sobrien    {
1418590075Sobrien    case REG:
14186169689Skan      operands[2] = adjust_address (operands[1], SImode, 4);
1418790075Sobrien
1418890075Sobrien      if (REGNO (operands[0]) == REGNO (addr))
1418990075Sobrien	{
1419090075Sobrien	  output_asm_insn ("ldr\t%H0, %2", operands);
1419190075Sobrien	  output_asm_insn ("ldr\t%0, %1", operands);
1419290075Sobrien	}
1419390075Sobrien      else
1419490075Sobrien	{
1419590075Sobrien	  output_asm_insn ("ldr\t%0, %1", operands);
1419690075Sobrien	  output_asm_insn ("ldr\t%H0, %2", operands);
1419790075Sobrien	}
1419890075Sobrien      break;
14199169689Skan
1420090075Sobrien    case CONST:
1420190075Sobrien      /* Compute <address> + 4 for the high order load.  */
14202169689Skan      operands[2] = adjust_address (operands[1], SImode, 4);
14203169689Skan
1420490075Sobrien      output_asm_insn ("ldr\t%0, %1", operands);
1420590075Sobrien      output_asm_insn ("ldr\t%H0, %2", operands);
1420690075Sobrien      break;
14207169689Skan
1420890075Sobrien    case PLUS:
1420990075Sobrien      arg1   = XEXP (addr, 0);
1421090075Sobrien      arg2   = XEXP (addr, 1);
14211169689Skan
1421290075Sobrien      if (CONSTANT_P (arg1))
1421390075Sobrien	base = arg2, offset = arg1;
1421490075Sobrien      else
1421590075Sobrien	base = arg1, offset = arg2;
1421690075Sobrien
14217169689Skan      gcc_assert (GET_CODE (base) == REG);
14218169689Skan
1421990075Sobrien      /* Catch the case of <address> = <reg> + <reg> */
1422090075Sobrien      if (GET_CODE (offset) == REG)
1422190075Sobrien	{
1422290075Sobrien	  int reg_offset = REGNO (offset);
1422390075Sobrien	  int reg_base   = REGNO (base);
1422490075Sobrien	  int reg_dest   = REGNO (operands[0]);
14225169689Skan
1422690075Sobrien	  /* Add the base and offset registers together into the
1422790075Sobrien             higher destination register.  */
1422890075Sobrien	  asm_fprintf (asm_out_file, "\tadd\t%r, %r, %r",
1422990075Sobrien		       reg_dest + 1, reg_base, reg_offset);
14230169689Skan
1423190075Sobrien	  /* Load the lower destination register from the address in
1423290075Sobrien             the higher destination register.  */
1423390075Sobrien	  asm_fprintf (asm_out_file, "\tldr\t%r, [%r, #0]",
1423490075Sobrien		       reg_dest, reg_dest + 1);
14235169689Skan
1423690075Sobrien	  /* Load the higher destination register from its own address
1423790075Sobrien             plus 4.  */
1423890075Sobrien	  asm_fprintf (asm_out_file, "\tldr\t%r, [%r, #4]",
1423990075Sobrien		       reg_dest + 1, reg_dest + 1);
1424090075Sobrien	}
1424190075Sobrien      else
1424290075Sobrien	{
1424390075Sobrien	  /* Compute <address> + 4 for the high order load.  */
14244169689Skan	  operands[2] = adjust_address (operands[1], SImode, 4);
14245169689Skan
1424690075Sobrien	  /* If the computed address is held in the low order register
1424790075Sobrien	     then load the high order register first, otherwise always
1424890075Sobrien	     load the low order register first.  */
1424990075Sobrien	  if (REGNO (operands[0]) == REGNO (base))
1425090075Sobrien	    {
1425190075Sobrien	      output_asm_insn ("ldr\t%H0, %2", operands);
1425290075Sobrien	      output_asm_insn ("ldr\t%0, %1", operands);
1425390075Sobrien	    }
1425490075Sobrien	  else
1425590075Sobrien	    {
1425690075Sobrien	      output_asm_insn ("ldr\t%0, %1", operands);
1425790075Sobrien	      output_asm_insn ("ldr\t%H0, %2", operands);
1425890075Sobrien	    }
1425990075Sobrien	}
1426090075Sobrien      break;
1426190075Sobrien
1426290075Sobrien    case LABEL_REF:
1426390075Sobrien      /* With no registers to worry about we can just load the value
1426490075Sobrien         directly.  */
14265169689Skan      operands[2] = adjust_address (operands[1], SImode, 4);
14266169689Skan
1426790075Sobrien      output_asm_insn ("ldr\t%H0, %2", operands);
1426890075Sobrien      output_asm_insn ("ldr\t%0, %1", operands);
1426990075Sobrien      break;
14270169689Skan
1427190075Sobrien    default:
14272169689Skan      gcc_unreachable ();
1427390075Sobrien    }
14274169689Skan
1427590075Sobrien  return "";
1427690075Sobrien}
1427790075Sobrien
1427890075Sobrienconst char *
14279132718Skanthumb_output_move_mem_multiple (int n, rtx *operands)
1428090075Sobrien{
1428190075Sobrien  rtx tmp;
1428290075Sobrien
1428390075Sobrien  switch (n)
1428490075Sobrien    {
1428590075Sobrien    case 2:
1428690075Sobrien      if (REGNO (operands[4]) > REGNO (operands[5]))
1428790075Sobrien	{
1428890075Sobrien	  tmp = operands[4];
1428990075Sobrien	  operands[4] = operands[5];
1429090075Sobrien	  operands[5] = tmp;
1429190075Sobrien	}
1429290075Sobrien      output_asm_insn ("ldmia\t%1!, {%4, %5}", operands);
1429390075Sobrien      output_asm_insn ("stmia\t%0!, {%4, %5}", operands);
1429490075Sobrien      break;
1429590075Sobrien
1429690075Sobrien    case 3:
1429790075Sobrien      if (REGNO (operands[4]) > REGNO (operands[5]))
1429890075Sobrien	{
1429990075Sobrien	  tmp = operands[4];
1430090075Sobrien	  operands[4] = operands[5];
1430190075Sobrien	  operands[5] = tmp;
1430290075Sobrien	}
1430390075Sobrien      if (REGNO (operands[5]) > REGNO (operands[6]))
1430490075Sobrien	{
1430590075Sobrien	  tmp = operands[5];
1430690075Sobrien	  operands[5] = operands[6];
1430790075Sobrien	  operands[6] = tmp;
1430890075Sobrien	}
1430990075Sobrien      if (REGNO (operands[4]) > REGNO (operands[5]))
1431090075Sobrien	{
1431190075Sobrien	  tmp = operands[4];
1431290075Sobrien	  operands[4] = operands[5];
1431390075Sobrien	  operands[5] = tmp;
1431490075Sobrien	}
14315169689Skan
1431690075Sobrien      output_asm_insn ("ldmia\t%1!, {%4, %5, %6}", operands);
1431790075Sobrien      output_asm_insn ("stmia\t%0!, {%4, %5, %6}", operands);
1431890075Sobrien      break;
1431990075Sobrien
1432090075Sobrien    default:
14321169689Skan      gcc_unreachable ();
1432290075Sobrien    }
1432390075Sobrien
1432490075Sobrien  return "";
1432590075Sobrien}
1432690075Sobrien
14327169689Skan/* Output a call-via instruction for thumb state.  */
14328169689Skanconst char *
14329169689Skanthumb_call_via_reg (rtx reg)
14330169689Skan{
14331169689Skan  int regno = REGNO (reg);
14332169689Skan  rtx *labelp;
14333169689Skan
14334169689Skan  gcc_assert (regno < LR_REGNUM);
14335169689Skan
14336169689Skan  /* If we are in the normal text section we can use a single instance
14337169689Skan     per compilation unit.  If we are doing function sections, then we need
14338169689Skan     an entry per section, since we can't rely on reachability.  */
14339169689Skan  if (in_section == text_section)
14340169689Skan    {
14341169689Skan      thumb_call_reg_needed = 1;
14342169689Skan
14343169689Skan      if (thumb_call_via_label[regno] == NULL)
14344169689Skan	thumb_call_via_label[regno] = gen_label_rtx ();
14345169689Skan      labelp = thumb_call_via_label + regno;
14346169689Skan    }
14347169689Skan  else
14348169689Skan    {
14349169689Skan      if (cfun->machine->call_via[regno] == NULL)
14350169689Skan	cfun->machine->call_via[regno] = gen_label_rtx ();
14351169689Skan      labelp = cfun->machine->call_via + regno;
14352169689Skan    }
14353169689Skan
14354169689Skan  output_asm_insn ("bl\t%a0", labelp);
14355169689Skan  return "";
14356169689Skan}
14357169689Skan
1435890075Sobrien/* Routines for generating rtl.  */
1435990075Sobrienvoid
14360169689Skanthumb_expand_movmemqi (rtx *operands)
1436190075Sobrien{
1436290075Sobrien  rtx out = copy_to_mode_reg (SImode, XEXP (operands[0], 0));
1436390075Sobrien  rtx in  = copy_to_mode_reg (SImode, XEXP (operands[1], 0));
1436490075Sobrien  HOST_WIDE_INT len = INTVAL (operands[2]);
1436590075Sobrien  HOST_WIDE_INT offset = 0;
1436690075Sobrien
1436790075Sobrien  while (len >= 12)
1436890075Sobrien    {
1436990075Sobrien      emit_insn (gen_movmem12b (out, in, out, in));
1437090075Sobrien      len -= 12;
1437190075Sobrien    }
14372169689Skan
1437390075Sobrien  if (len >= 8)
1437490075Sobrien    {
1437590075Sobrien      emit_insn (gen_movmem8b (out, in, out, in));
1437690075Sobrien      len -= 8;
1437790075Sobrien    }
14378169689Skan
1437990075Sobrien  if (len >= 4)
1438090075Sobrien    {
1438190075Sobrien      rtx reg = gen_reg_rtx (SImode);
14382169689Skan      emit_insn (gen_movsi (reg, gen_rtx_MEM (SImode, in)));
14383169689Skan      emit_insn (gen_movsi (gen_rtx_MEM (SImode, out), reg));
1438490075Sobrien      len -= 4;
1438590075Sobrien      offset += 4;
1438690075Sobrien    }
14387169689Skan
1438890075Sobrien  if (len >= 2)
1438990075Sobrien    {
1439090075Sobrien      rtx reg = gen_reg_rtx (HImode);
14391169689Skan      emit_insn (gen_movhi (reg, gen_rtx_MEM (HImode,
14392169689Skan					      plus_constant (in, offset))));
14393169689Skan      emit_insn (gen_movhi (gen_rtx_MEM (HImode, plus_constant (out, offset)),
1439490075Sobrien			    reg));
1439590075Sobrien      len -= 2;
1439690075Sobrien      offset += 2;
1439790075Sobrien    }
14398169689Skan
1439990075Sobrien  if (len)
1440090075Sobrien    {
1440190075Sobrien      rtx reg = gen_reg_rtx (QImode);
14402169689Skan      emit_insn (gen_movqi (reg, gen_rtx_MEM (QImode,
14403169689Skan					      plus_constant (in, offset))));
14404169689Skan      emit_insn (gen_movqi (gen_rtx_MEM (QImode, plus_constant (out, offset)),
1440590075Sobrien			    reg));
1440690075Sobrien    }
1440790075Sobrien}
1440890075Sobrien
1440990075Sobrienvoid
14410132718Skanthumb_reload_out_hi (rtx *operands)
1441190075Sobrien{
1441290075Sobrien  emit_insn (gen_thumb_movhi_clobber (operands[0], operands[1], operands[2]));
1441390075Sobrien}
1441490075Sobrien
14415169689Skan/* Handle reading a half-word from memory during reload.  */
1441690075Sobrienvoid
14417132718Skanthumb_reload_in_hi (rtx *operands ATTRIBUTE_UNUSED)
1441890075Sobrien{
14419169689Skan  gcc_unreachable ();
1442090075Sobrien}
1442190075Sobrien
1442290075Sobrien/* Return the length of a function name prefix
1442390075Sobrien    that starts with the character 'c'.  */
1442490075Sobrienstatic int
14425132718Skanarm_get_strip_length (int c)
1442690075Sobrien{
1442790075Sobrien  switch (c)
1442890075Sobrien    {
1442990075Sobrien    ARM_NAME_ENCODING_LENGTHS
14430169689Skan      default: return 0;
1443190075Sobrien    }
1443290075Sobrien}
1443390075Sobrien
1443490075Sobrien/* Return a pointer to a function's name with any
1443590075Sobrien   and all prefix encodings stripped from it.  */
1443690075Sobrienconst char *
14437132718Skanarm_strip_name_encoding (const char *name)
1443890075Sobrien{
1443990075Sobrien  int skip;
14440169689Skan
1444190075Sobrien  while ((skip = arm_get_strip_length (* name)))
1444290075Sobrien    name += skip;
1444390075Sobrien
1444490075Sobrien  return name;
1444590075Sobrien}
1444690075Sobrien
14447117395Skan/* If there is a '*' anywhere in the name's prefix, then
14448117395Skan   emit the stripped name verbatim, otherwise prepend an
14449117395Skan   underscore if leading underscores are being used.  */
14450117395Skanvoid
14451132718Skanarm_asm_output_labelref (FILE *stream, const char *name)
14452117395Skan{
14453117395Skan  int skip;
14454117395Skan  int verbatim = 0;
14455117395Skan
14456117395Skan  while ((skip = arm_get_strip_length (* name)))
14457117395Skan    {
14458117395Skan      verbatim |= (*name == '*');
14459117395Skan      name += skip;
14460117395Skan    }
14461117395Skan
14462117395Skan  if (verbatim)
14463117395Skan    fputs (name, stream);
14464117395Skan  else
14465117395Skan    asm_fprintf (stream, "%U%s", name);
14466117395Skan}
14467117395Skan
14468169689Skanstatic void
14469260456Spfgarm_file_start (void)
14470260456Spfg{
14471260456Spfg  int val;
14472260456Spfg
14473260456Spfg  if (TARGET_BPABI)
14474260456Spfg    {
14475260456Spfg      const char *fpu_name;
14476260456Spfg      if (arm_select[0].string)
14477260456Spfg	asm_fprintf (asm_out_file, "\t.cpu %s\n", arm_select[0].string);
14478260456Spfg      else if (arm_select[1].string)
14479260456Spfg	asm_fprintf (asm_out_file, "\t.arch %s\n", arm_select[1].string);
14480260456Spfg      else
14481260456Spfg	asm_fprintf (asm_out_file, "\t.cpu %s\n",
14482260456Spfg		     all_cores[arm_default_cpu].name);
14483260456Spfg
14484260456Spfg      if (TARGET_SOFT_FLOAT)
14485260456Spfg	{
14486260456Spfg	  if (TARGET_VFP)
14487260456Spfg	    fpu_name = "softvfp";
14488260456Spfg	  else
14489260456Spfg	    fpu_name = "softfpa";
14490260456Spfg	}
14491260456Spfg      else
14492260456Spfg	{
14493260456Spfg	  switch (arm_fpu_arch)
14494260456Spfg	    {
14495260456Spfg	    case FPUTYPE_FPA:
14496260456Spfg	      fpu_name = "fpa";
14497260456Spfg	      break;
14498260456Spfg	    case FPUTYPE_FPA_EMU2:
14499260456Spfg	      fpu_name = "fpe2";
14500260456Spfg	      break;
14501260456Spfg	    case FPUTYPE_FPA_EMU3:
14502260456Spfg	      fpu_name = "fpe3";
14503260456Spfg	      break;
14504260456Spfg	    case FPUTYPE_MAVERICK:
14505260456Spfg	      fpu_name = "maverick";
14506260456Spfg	      break;
14507260456Spfg	    case FPUTYPE_VFP:
14508260456Spfg	      if (TARGET_HARD_FLOAT)
14509260456Spfg		asm_fprintf (asm_out_file, "\t.eabi_attribute 27, 3\n");
14510260456Spfg	      if (TARGET_HARD_FLOAT_ABI)
14511260456Spfg		asm_fprintf (asm_out_file, "\t.eabi_attribute 28, 1\n");
14512260456Spfg	      fpu_name = "vfp";
14513260456Spfg	      break;
14514260456Spfg	    default:
14515260456Spfg	      abort();
14516260456Spfg	    }
14517260456Spfg	}
14518260456Spfg      asm_fprintf (asm_out_file, "\t.fpu %s\n", fpu_name);
14519260456Spfg
14520260456Spfg      /* Some of these attributes only apply when the corresponding features
14521260456Spfg         are used.  However we don't have any easy way of figuring this out.
14522260456Spfg	 Conservatively record the setting that would have been used.  */
14523260456Spfg
14524260456Spfg      /* Tag_ABI_PCS_wchar_t.  */
14525260456Spfg      asm_fprintf (asm_out_file, "\t.eabi_attribute 18, %d\n",
14526260456Spfg		   (int)WCHAR_TYPE_SIZE / BITS_PER_UNIT);
14527260456Spfg
14528260456Spfg      /* Tag_ABI_FP_rounding.  */
14529260456Spfg      if (flag_rounding_math)
14530260456Spfg	asm_fprintf (asm_out_file, "\t.eabi_attribute 19, 1\n");
14531260456Spfg      if (!flag_unsafe_math_optimizations)
14532260456Spfg	{
14533260456Spfg	  /* Tag_ABI_FP_denomal.  */
14534260456Spfg	  asm_fprintf (asm_out_file, "\t.eabi_attribute 20, 1\n");
14535260456Spfg	  /* Tag_ABI_FP_exceptions.  */
14536260456Spfg	  asm_fprintf (asm_out_file, "\t.eabi_attribute 21, 1\n");
14537260456Spfg	}
14538260456Spfg      /* Tag_ABI_FP_user_exceptions.  */
14539260456Spfg      if (flag_signaling_nans)
14540260456Spfg	asm_fprintf (asm_out_file, "\t.eabi_attribute 22, 1\n");
14541260456Spfg      /* Tag_ABI_FP_number_model.  */
14542260456Spfg      asm_fprintf (asm_out_file, "\t.eabi_attribute 23, %d\n",
14543260456Spfg		   flag_finite_math_only ? 1 : 3);
14544260456Spfg
14545260456Spfg      /* Tag_ABI_align8_needed.  */
14546260456Spfg      asm_fprintf (asm_out_file, "\t.eabi_attribute 24, 1\n");
14547260456Spfg      /* Tag_ABI_align8_preserved.  */
14548260456Spfg      asm_fprintf (asm_out_file, "\t.eabi_attribute 25, 1\n");
14549260456Spfg      /* Tag_ABI_enum_size.  */
14550260456Spfg      asm_fprintf (asm_out_file, "\t.eabi_attribute 26, %d\n",
14551260456Spfg		   flag_short_enums ? 1 : 2);
14552260456Spfg
14553260456Spfg      /* Tag_ABI_optimization_goals.  */
14554260456Spfg      if (optimize_size)
14555260456Spfg	val = 4;
14556260456Spfg      else if (optimize >= 2)
14557260456Spfg	val = 2;
14558260456Spfg      else if (optimize)
14559260456Spfg	val = 1;
14560260456Spfg      else
14561260456Spfg	val = 6;
14562260456Spfg      asm_fprintf (asm_out_file, "\t.eabi_attribute 30, %d\n", val);
14563260456Spfg    }
14564260456Spfg  default_file_start();
14565260456Spfg}
14566260456Spfg
14567260456Spfgstatic void
14568169689Skanarm_file_end (void)
14569169689Skan{
14570169689Skan  int regno;
14571169689Skan
14572169689Skan  if (! thumb_call_reg_needed)
14573169689Skan    return;
14574169689Skan
14575169689Skan  switch_to_section (text_section);
14576169689Skan  asm_fprintf (asm_out_file, "\t.code 16\n");
14577169689Skan  ASM_OUTPUT_ALIGN (asm_out_file, 1);
14578169689Skan
14579169689Skan  for (regno = 0; regno < LR_REGNUM; regno++)
14580169689Skan    {
14581169689Skan      rtx label = thumb_call_via_label[regno];
14582169689Skan
14583169689Skan      if (label != 0)
14584169689Skan	{
14585169689Skan	  targetm.asm_out.internal_label (asm_out_file, "L",
14586169689Skan					  CODE_LABEL_NUMBER (label));
14587169689Skan	  asm_fprintf (asm_out_file, "\tbx\t%r\n", regno);
14588169689Skan	}
14589169689Skan    }
14590169689Skan}
14591169689Skan
14592117395Skanrtx aof_pic_label;
14593117395Skan
1459490075Sobrien#ifdef AOF_ASSEMBLER
1459590075Sobrien/* Special functions only needed when producing AOF syntax assembler.  */
1459690075Sobrien
1459790075Sobrienstruct pic_chain
1459890075Sobrien{
1459990075Sobrien  struct pic_chain * next;
1460090075Sobrien  const char * symname;
1460190075Sobrien};
1460290075Sobrien
1460390075Sobrienstatic struct pic_chain * aof_pic_chain = NULL;
1460490075Sobrien
1460590075Sobrienrtx
14606132718Skanaof_pic_entry (rtx x)
1460790075Sobrien{
1460890075Sobrien  struct pic_chain ** chainp;
1460990075Sobrien  int offset;
1461090075Sobrien
1461190075Sobrien  if (aof_pic_label == NULL_RTX)
1461290075Sobrien    {
1461390075Sobrien      aof_pic_label = gen_rtx_SYMBOL_REF (Pmode, "x$adcons");
1461490075Sobrien    }
1461590075Sobrien
1461690075Sobrien  for (offset = 0, chainp = &aof_pic_chain; *chainp;
1461790075Sobrien       offset += 4, chainp = &(*chainp)->next)
1461890075Sobrien    if ((*chainp)->symname == XSTR (x, 0))
1461990075Sobrien      return plus_constant (aof_pic_label, offset);
1462090075Sobrien
1462190075Sobrien  *chainp = (struct pic_chain *) xmalloc (sizeof (struct pic_chain));
1462290075Sobrien  (*chainp)->next = NULL;
1462390075Sobrien  (*chainp)->symname = XSTR (x, 0);
1462490075Sobrien  return plus_constant (aof_pic_label, offset);
1462590075Sobrien}
1462690075Sobrien
1462790075Sobrienvoid
14628132718Skanaof_dump_pic_table (FILE *f)
1462990075Sobrien{
1463090075Sobrien  struct pic_chain * chain;
1463190075Sobrien
1463290075Sobrien  if (aof_pic_chain == NULL)
1463390075Sobrien    return;
1463490075Sobrien
1463590075Sobrien  asm_fprintf (f, "\tAREA |%r$$adcons|, BASED %r\n",
1463690075Sobrien	       PIC_OFFSET_TABLE_REGNUM,
1463790075Sobrien	       PIC_OFFSET_TABLE_REGNUM);
1463890075Sobrien  fputs ("|x$adcons|\n", f);
14639169689Skan
1464090075Sobrien  for (chain = aof_pic_chain; chain; chain = chain->next)
1464190075Sobrien    {
1464290075Sobrien      fputs ("\tDCD\t", f);
1464390075Sobrien      assemble_name (f, chain->symname);
1464490075Sobrien      fputs ("\n", f);
1464590075Sobrien    }
1464690075Sobrien}
1464790075Sobrien
1464890075Sobrienint arm_text_section_count = 1;
1464990075Sobrien
14650169689Skan/* A get_unnamed_section callback for switching to the text section.  */
14651169689Skan
14652169689Skanstatic void
14653169689Skanaof_output_text_section_asm_op (const void *data ATTRIBUTE_UNUSED)
1465490075Sobrien{
14655169689Skan  fprintf (asm_out_file, "\tAREA |C$$code%d|, CODE, READONLY",
1465690075Sobrien	   arm_text_section_count++);
1465790075Sobrien  if (flag_pic)
14658169689Skan    fprintf (asm_out_file, ", PIC, REENTRANT");
14659169689Skan  fprintf (asm_out_file, "\n");
1466090075Sobrien}
1466190075Sobrien
1466290075Sobrienstatic int arm_data_section_count = 1;
1466390075Sobrien
14664169689Skan/* A get_unnamed_section callback for switching to the data section.  */
14665169689Skan
14666169689Skanstatic void
14667169689Skanaof_output_data_section_asm_op (const void *data ATTRIBUTE_UNUSED)
1466890075Sobrien{
14669169689Skan  fprintf (asm_out_file, "\tAREA |C$$data%d|, DATA\n",
14670169689Skan	   arm_data_section_count++);
1467190075Sobrien}
1467290075Sobrien
14673169689Skan/* Implement TARGET_ASM_INIT_SECTIONS.
14674169689Skan
14675169689Skan   AOF Assembler syntax is a nightmare when it comes to areas, since once
14676169689Skan   we change from one area to another, we can't go back again.  Instead,
14677169689Skan   we must create a new area with the same attributes and add the new output
14678169689Skan   to that.  Unfortunately, there is nothing we can do here to guarantee that
14679169689Skan   two areas with the same attributes will be linked adjacently in the
14680169689Skan   resulting executable, so we have to be careful not to do pc-relative
14681169689Skan   addressing across such boundaries.  */
14682169689Skan
14683169689Skanstatic void
14684169689Skanaof_asm_init_sections (void)
14685169689Skan{
14686169689Skan  text_section = get_unnamed_section (SECTION_CODE,
14687169689Skan				      aof_output_text_section_asm_op, NULL);
14688169689Skan  data_section = get_unnamed_section (SECTION_WRITE,
14689169689Skan				      aof_output_data_section_asm_op, NULL);
14690169689Skan  readonly_data_section = text_section;
14691169689Skan}
14692169689Skan
14693169689Skanvoid
14694169689Skanzero_init_section (void)
14695169689Skan{
14696169689Skan  static int zero_init_count = 1;
14697169689Skan
14698169689Skan  fprintf (asm_out_file, "\tAREA |C$$zidata%d|,NOINIT\n", zero_init_count++);
14699169689Skan  in_section = NULL;
14700169689Skan}
14701169689Skan
1470290075Sobrien/* The AOF assembler is religiously strict about declarations of
1470390075Sobrien   imported and exported symbols, so that it is impossible to declare
1470490075Sobrien   a function as imported near the beginning of the file, and then to
1470590075Sobrien   export it later on.  It is, however, possible to delay the decision
1470690075Sobrien   until all the functions in the file have been compiled.  To get
1470790075Sobrien   around this, we maintain a list of the imports and exports, and
1470890075Sobrien   delete from it any that are subsequently defined.  At the end of
1470990075Sobrien   compilation we spit the remainder of the list out before the END
1471090075Sobrien   directive.  */
1471190075Sobrien
1471290075Sobrienstruct import
1471390075Sobrien{
1471490075Sobrien  struct import * next;
1471590075Sobrien  const char * name;
1471690075Sobrien};
1471790075Sobrien
1471890075Sobrienstatic struct import * imports_list = NULL;
1471990075Sobrien
1472090075Sobrienvoid
14721132718Skanaof_add_import (const char *name)
1472290075Sobrien{
1472390075Sobrien  struct import * new;
1472490075Sobrien
1472590075Sobrien  for (new = imports_list; new; new = new->next)
1472690075Sobrien    if (new->name == name)
1472790075Sobrien      return;
1472890075Sobrien
1472990075Sobrien  new = (struct import *) xmalloc (sizeof (struct import));
1473090075Sobrien  new->next = imports_list;
1473190075Sobrien  imports_list = new;
1473290075Sobrien  new->name = name;
1473390075Sobrien}
1473490075Sobrien
1473590075Sobrienvoid
14736132718Skanaof_delete_import (const char *name)
1473790075Sobrien{
1473890075Sobrien  struct import ** old;
1473990075Sobrien
1474090075Sobrien  for (old = &imports_list; *old; old = & (*old)->next)
1474190075Sobrien    {
1474290075Sobrien      if ((*old)->name == name)
1474390075Sobrien	{
1474490075Sobrien	  *old = (*old)->next;
1474590075Sobrien	  return;
1474690075Sobrien	}
1474790075Sobrien    }
1474890075Sobrien}
1474990075Sobrien
1475090075Sobrienint arm_main_function = 0;
1475190075Sobrien
14752132718Skanstatic void
14753132718Skanaof_dump_imports (FILE *f)
1475490075Sobrien{
1475590075Sobrien  /* The AOF assembler needs this to cause the startup code to be extracted
1475690075Sobrien     from the library.  Brining in __main causes the whole thing to work
1475790075Sobrien     automagically.  */
1475890075Sobrien  if (arm_main_function)
1475990075Sobrien    {
14760169689Skan      switch_to_section (text_section);
1476190075Sobrien      fputs ("\tIMPORT __main\n", f);
1476290075Sobrien      fputs ("\tDCD __main\n", f);
1476390075Sobrien    }
1476490075Sobrien
1476590075Sobrien  /* Now dump the remaining imports.  */
1476690075Sobrien  while (imports_list)
1476790075Sobrien    {
1476890075Sobrien      fprintf (f, "\tIMPORT\t");
1476990075Sobrien      assemble_name (f, imports_list->name);
1477090075Sobrien      fputc ('\n', f);
1477190075Sobrien      imports_list = imports_list->next;
1477290075Sobrien    }
1477390075Sobrien}
14774117395Skan
14775117395Skanstatic void
14776132718Skanaof_globalize_label (FILE *stream, const char *name)
14777117395Skan{
14778117395Skan  default_globalize_label (stream, name);
14779117395Skan  if (! strcmp (name, "main"))
14780117395Skan    arm_main_function = 1;
14781117395Skan}
14782132718Skan
14783132718Skanstatic void
14784132718Skanaof_file_start (void)
14785132718Skan{
14786132718Skan  fputs ("__r0\tRN\t0\n", asm_out_file);
14787132718Skan  fputs ("__a1\tRN\t0\n", asm_out_file);
14788132718Skan  fputs ("__a2\tRN\t1\n", asm_out_file);
14789132718Skan  fputs ("__a3\tRN\t2\n", asm_out_file);
14790132718Skan  fputs ("__a4\tRN\t3\n", asm_out_file);
14791132718Skan  fputs ("__v1\tRN\t4\n", asm_out_file);
14792132718Skan  fputs ("__v2\tRN\t5\n", asm_out_file);
14793132718Skan  fputs ("__v3\tRN\t6\n", asm_out_file);
14794132718Skan  fputs ("__v4\tRN\t7\n", asm_out_file);
14795132718Skan  fputs ("__v5\tRN\t8\n", asm_out_file);
14796132718Skan  fputs ("__v6\tRN\t9\n", asm_out_file);
14797132718Skan  fputs ("__sl\tRN\t10\n", asm_out_file);
14798132718Skan  fputs ("__fp\tRN\t11\n", asm_out_file);
14799132718Skan  fputs ("__ip\tRN\t12\n", asm_out_file);
14800132718Skan  fputs ("__sp\tRN\t13\n", asm_out_file);
14801132718Skan  fputs ("__lr\tRN\t14\n", asm_out_file);
14802132718Skan  fputs ("__pc\tRN\t15\n", asm_out_file);
14803132718Skan  fputs ("__f0\tFN\t0\n", asm_out_file);
14804132718Skan  fputs ("__f1\tFN\t1\n", asm_out_file);
14805132718Skan  fputs ("__f2\tFN\t2\n", asm_out_file);
14806132718Skan  fputs ("__f3\tFN\t3\n", asm_out_file);
14807132718Skan  fputs ("__f4\tFN\t4\n", asm_out_file);
14808132718Skan  fputs ("__f5\tFN\t5\n", asm_out_file);
14809132718Skan  fputs ("__f6\tFN\t6\n", asm_out_file);
14810132718Skan  fputs ("__f7\tFN\t7\n", asm_out_file);
14811169689Skan  switch_to_section (text_section);
14812132718Skan}
14813132718Skan
14814132718Skanstatic void
14815132718Skanaof_file_end (void)
14816132718Skan{
14817132718Skan  if (flag_pic)
14818132718Skan    aof_dump_pic_table (asm_out_file);
14819169689Skan  arm_file_end ();
14820132718Skan  aof_dump_imports (asm_out_file);
14821132718Skan  fputs ("\tEND\n", asm_out_file);
14822132718Skan}
1482390075Sobrien#endif /* AOF_ASSEMBLER */
1482490075Sobrien
14825117395Skan#ifndef ARM_PE
14826117395Skan/* Symbols in the text segment can be accessed without indirecting via the
14827117395Skan   constant pool; it may take an extra binary operation, but this is still
14828117395Skan   faster than indirecting via memory.  Don't do this when not optimizing,
14829117395Skan   since we won't be calculating al of the offsets necessary to do this
14830117395Skan   simplification.  */
14831117395Skan
14832117395Skanstatic void
14833132718Skanarm_encode_section_info (tree decl, rtx rtl, int first)
14834117395Skan{
14835117395Skan  /* This doesn't work with AOF syntax, since the string table may be in
14836117395Skan     a different AREA.  */
14837117395Skan#ifndef AOF_ASSEMBLER
14838169689Skan  if (optimize > 0 && TREE_CONSTANT (decl))
14839132718Skan    SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1;
14840117395Skan#endif
14841117395Skan
14842117395Skan  /* If we are referencing a function that is weak then encode a long call
14843117395Skan     flag in the function name, otherwise if the function is static or
14844117395Skan     or known to be defined in this file then encode a short call flag.  */
14845169689Skan  if (first && DECL_P (decl))
14846117395Skan    {
14847117395Skan      if (TREE_CODE (decl) == FUNCTION_DECL && DECL_WEAK (decl))
14848117395Skan        arm_encode_call_attribute (decl, LONG_CALL_FLAG_CHAR);
14849117395Skan      else if (! TREE_PUBLIC (decl))
14850117395Skan        arm_encode_call_attribute (decl, SHORT_CALL_FLAG_CHAR);
14851117395Skan    }
14852169689Skan
14853169689Skan  default_encode_section_info (decl, rtl, first);
14854117395Skan}
14855117395Skan#endif /* !ARM_PE */
14856117395Skan
14857132718Skanstatic void
14858132718Skanarm_internal_label (FILE *stream, const char *prefix, unsigned long labelno)
14859132718Skan{
14860132718Skan  if (arm_ccfsm_state == 3 && (unsigned) arm_target_label == labelno
14861132718Skan      && !strcmp (prefix, "L"))
14862132718Skan    {
14863132718Skan      arm_ccfsm_state = 0;
14864132718Skan      arm_target_insn = NULL;
14865132718Skan    }
14866132718Skan  default_internal_label (stream, prefix, labelno);
14867132718Skan}
14868132718Skan
14869117395Skan/* Output code to add DELTA to the first argument, and then jump
14870117395Skan   to FUNCTION.  Used for C++ multiple inheritance.  */
14871117395Skanstatic void
14872132718Skanarm_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
14873132718Skan		     HOST_WIDE_INT delta,
14874132718Skan		     HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED,
14875132718Skan		     tree function)
14876117395Skan{
14877132718Skan  static int thunk_label = 0;
14878132718Skan  char label[256];
14879169689Skan  char labelpc[256];
14880117395Skan  int mi_delta = delta;
14881117395Skan  const char *const mi_op = mi_delta < 0 ? "sub" : "add";
14882117395Skan  int shift = 0;
14883132718Skan  int this_regno = (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function)
14884117395Skan                    ? 1 : 0);
14885117395Skan  if (mi_delta < 0)
14886117395Skan    mi_delta = - mi_delta;
14887132718Skan  if (TARGET_THUMB)
14888132718Skan    {
14889132718Skan      int labelno = thunk_label++;
14890132718Skan      ASM_GENERATE_INTERNAL_LABEL (label, "LTHUMBFUNC", labelno);
14891132718Skan      fputs ("\tldr\tr12, ", file);
14892132718Skan      assemble_name (file, label);
14893132718Skan      fputc ('\n', file);
14894169689Skan      if (flag_pic)
14895169689Skan	{
14896169689Skan	  /* If we are generating PIC, the ldr instruction below loads
14897169689Skan	     "(target - 7) - .LTHUNKPCn" into r12.  The pc reads as
14898169689Skan	     the address of the add + 8, so we have:
14899169689Skan
14900169689Skan	     r12 = (target - 7) - .LTHUNKPCn + (.LTHUNKPCn + 8)
14901169689Skan	         = target + 1.
14902169689Skan
14903169689Skan	     Note that we have "+ 1" because some versions of GNU ld
14904169689Skan	     don't set the low bit of the result for R_ARM_REL32
14905169689Skan	     relocations against thumb function symbols.  */
14906169689Skan	  ASM_GENERATE_INTERNAL_LABEL (labelpc, "LTHUNKPC", labelno);
14907169689Skan	  assemble_name (file, labelpc);
14908169689Skan	  fputs (":\n", file);
14909169689Skan	  fputs ("\tadd\tr12, pc, r12\n", file);
14910169689Skan	}
14911132718Skan    }
14912117395Skan  while (mi_delta != 0)
14913117395Skan    {
14914117395Skan      if ((mi_delta & (3 << shift)) == 0)
14915117395Skan        shift += 2;
14916117395Skan      else
14917117395Skan        {
14918117395Skan          asm_fprintf (file, "\t%s\t%r, %r, #%d\n",
14919117395Skan                       mi_op, this_regno, this_regno,
14920117395Skan                       mi_delta & (0xff << shift));
14921117395Skan          mi_delta &= ~(0xff << shift);
14922117395Skan          shift += 8;
14923117395Skan        }
14924117395Skan    }
14925132718Skan  if (TARGET_THUMB)
14926132718Skan    {
14927132718Skan      fprintf (file, "\tbx\tr12\n");
14928132718Skan      ASM_OUTPUT_ALIGN (file, 2);
14929132718Skan      assemble_name (file, label);
14930132718Skan      fputs (":\n", file);
14931169689Skan      if (flag_pic)
14932169689Skan	{
14933169689Skan	  /* Output ".word .LTHUNKn-7-.LTHUNKPCn".  */
14934169689Skan	  rtx tem = XEXP (DECL_RTL (function), 0);
14935169689Skan	  tem = gen_rtx_PLUS (GET_MODE (tem), tem, GEN_INT (-7));
14936169689Skan	  tem = gen_rtx_MINUS (GET_MODE (tem),
14937169689Skan			       tem,
14938169689Skan			       gen_rtx_SYMBOL_REF (Pmode,
14939169689Skan						   ggc_strdup (labelpc)));
14940169689Skan	  assemble_integer (tem, 4, BITS_PER_WORD, 1);
14941169689Skan	}
14942169689Skan      else
14943169689Skan	/* Output ".word .LTHUNKn".  */
14944169689Skan	assemble_integer (XEXP (DECL_RTL (function), 0), 4, BITS_PER_WORD, 1);
14945132718Skan    }
14946132718Skan  else
14947132718Skan    {
14948132718Skan      fputs ("\tb\t", file);
14949132718Skan      assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0));
14950132718Skan      if (NEED_PLT_RELOC)
14951132718Skan        fputs ("(PLT)", file);
14952132718Skan      fputc ('\n', file);
14953132718Skan    }
14954117395Skan}
14955117395Skan
14956132718Skanint
14957132718Skanarm_emit_vector_const (FILE *file, rtx x)
14958132718Skan{
14959132718Skan  int i;
14960132718Skan  const char * pattern;
14961132718Skan
14962169689Skan  gcc_assert (GET_CODE (x) == CONST_VECTOR);
14963132718Skan
14964132718Skan  switch (GET_MODE (x))
14965132718Skan    {
14966132718Skan    case V2SImode: pattern = "%08x"; break;
14967132718Skan    case V4HImode: pattern = "%04x"; break;
14968132718Skan    case V8QImode: pattern = "%02x"; break;
14969169689Skan    default:       gcc_unreachable ();
14970132718Skan    }
14971132718Skan
14972132718Skan  fprintf (file, "0x");
14973132718Skan  for (i = CONST_VECTOR_NUNITS (x); i--;)
14974132718Skan    {
14975132718Skan      rtx element;
14976132718Skan
14977132718Skan      element = CONST_VECTOR_ELT (x, i);
14978132718Skan      fprintf (file, pattern, INTVAL (element));
14979132718Skan    }
14980132718Skan
14981132718Skan  return 1;
14982132718Skan}
14983132718Skan
14984132718Skanconst char *
14985132718Skanarm_output_load_gr (rtx *operands)
14986132718Skan{
14987132718Skan  rtx reg;
14988132718Skan  rtx offset;
14989132718Skan  rtx wcgr;
14990132718Skan  rtx sum;
14991169689Skan
14992132718Skan  if (GET_CODE (operands [1]) != MEM
14993132718Skan      || GET_CODE (sum = XEXP (operands [1], 0)) != PLUS
14994132718Skan      || GET_CODE (reg = XEXP (sum, 0)) != REG
14995132718Skan      || GET_CODE (offset = XEXP (sum, 1)) != CONST_INT
14996132718Skan      || ((INTVAL (offset) < 1024) && (INTVAL (offset) > -1024)))
14997132718Skan    return "wldrw%?\t%0, %1";
14998169689Skan
14999169689Skan  /* Fix up an out-of-range load of a GR register.  */
15000132718Skan  output_asm_insn ("str%?\t%0, [sp, #-4]!\t@ Start of GR load expansion", & reg);
15001132718Skan  wcgr = operands[0];
15002132718Skan  operands[0] = reg;
15003132718Skan  output_asm_insn ("ldr%?\t%0, %1", operands);
15004132718Skan
15005132718Skan  operands[0] = wcgr;
15006132718Skan  operands[1] = reg;
15007132718Skan  output_asm_insn ("tmcr%?\t%0, %1", operands);
15008132718Skan  output_asm_insn ("ldr%?\t%0, [sp], #4\t@ End of GR load expansion", & reg);
15009132718Skan
15010132718Skan  return "";
15011132718Skan}
15012169689Skan
15013169689Skan/* Worker function for TARGET_SETUP_INCOMING_VARARGS.
15014169689Skan
15015169689Skan   On the ARM, PRETEND_SIZE is set in order to have the prologue push the last
15016169689Skan   named arg and all anonymous args onto the stack.
15017169689Skan   XXX I know the prologue shouldn't be pushing registers, but it is faster
15018169689Skan   that way.  */
15019169689Skan
15020169689Skanstatic void
15021169689Skanarm_setup_incoming_varargs (CUMULATIVE_ARGS *cum,
15022169689Skan			    enum machine_mode mode ATTRIBUTE_UNUSED,
15023169689Skan			    tree type ATTRIBUTE_UNUSED,
15024169689Skan			    int *pretend_size,
15025169689Skan			    int second_time ATTRIBUTE_UNUSED)
15026169689Skan{
15027169689Skan  cfun->machine->uses_anonymous_args = 1;
15028169689Skan  if (cum->nregs < NUM_ARG_REGS)
15029169689Skan    *pretend_size = (NUM_ARG_REGS - cum->nregs) * UNITS_PER_WORD;
15030169689Skan}
15031169689Skan
15032169689Skan/* Return nonzero if the CONSUMER instruction (a store) does not need
15033169689Skan   PRODUCER's value to calculate the address.  */
15034169689Skan
15035169689Skanint
15036169689Skanarm_no_early_store_addr_dep (rtx producer, rtx consumer)
15037169689Skan{
15038169689Skan  rtx value = PATTERN (producer);
15039169689Skan  rtx addr = PATTERN (consumer);
15040169689Skan
15041169689Skan  if (GET_CODE (value) == COND_EXEC)
15042169689Skan    value = COND_EXEC_CODE (value);
15043169689Skan  if (GET_CODE (value) == PARALLEL)
15044169689Skan    value = XVECEXP (value, 0, 0);
15045169689Skan  value = XEXP (value, 0);
15046169689Skan  if (GET_CODE (addr) == COND_EXEC)
15047169689Skan    addr = COND_EXEC_CODE (addr);
15048169689Skan  if (GET_CODE (addr) == PARALLEL)
15049169689Skan    addr = XVECEXP (addr, 0, 0);
15050169689Skan  addr = XEXP (addr, 0);
15051169689Skan
15052169689Skan  return !reg_overlap_mentioned_p (value, addr);
15053169689Skan}
15054169689Skan
15055169689Skan/* Return nonzero if the CONSUMER instruction (an ALU op) does not
15056169689Skan   have an early register shift value or amount dependency on the
15057169689Skan   result of PRODUCER.  */
15058169689Skan
15059169689Skanint
15060169689Skanarm_no_early_alu_shift_dep (rtx producer, rtx consumer)
15061169689Skan{
15062169689Skan  rtx value = PATTERN (producer);
15063169689Skan  rtx op = PATTERN (consumer);
15064169689Skan  rtx early_op;
15065169689Skan
15066169689Skan  if (GET_CODE (value) == COND_EXEC)
15067169689Skan    value = COND_EXEC_CODE (value);
15068169689Skan  if (GET_CODE (value) == PARALLEL)
15069169689Skan    value = XVECEXP (value, 0, 0);
15070169689Skan  value = XEXP (value, 0);
15071169689Skan  if (GET_CODE (op) == COND_EXEC)
15072169689Skan    op = COND_EXEC_CODE (op);
15073169689Skan  if (GET_CODE (op) == PARALLEL)
15074169689Skan    op = XVECEXP (op, 0, 0);
15075169689Skan  op = XEXP (op, 1);
15076169689Skan
15077169689Skan  early_op = XEXP (op, 0);
15078169689Skan  /* This is either an actual independent shift, or a shift applied to
15079169689Skan     the first operand of another operation.  We want the whole shift
15080169689Skan     operation.  */
15081169689Skan  if (GET_CODE (early_op) == REG)
15082169689Skan    early_op = op;
15083169689Skan
15084169689Skan  return !reg_overlap_mentioned_p (value, early_op);
15085169689Skan}
15086169689Skan
15087169689Skan/* Return nonzero if the CONSUMER instruction (an ALU op) does not
15088169689Skan   have an early register shift value dependency on the result of
15089169689Skan   PRODUCER.  */
15090169689Skan
15091169689Skanint
15092169689Skanarm_no_early_alu_shift_value_dep (rtx producer, rtx consumer)
15093169689Skan{
15094169689Skan  rtx value = PATTERN (producer);
15095169689Skan  rtx op = PATTERN (consumer);
15096169689Skan  rtx early_op;
15097169689Skan
15098169689Skan  if (GET_CODE (value) == COND_EXEC)
15099169689Skan    value = COND_EXEC_CODE (value);
15100169689Skan  if (GET_CODE (value) == PARALLEL)
15101169689Skan    value = XVECEXP (value, 0, 0);
15102169689Skan  value = XEXP (value, 0);
15103169689Skan  if (GET_CODE (op) == COND_EXEC)
15104169689Skan    op = COND_EXEC_CODE (op);
15105169689Skan  if (GET_CODE (op) == PARALLEL)
15106169689Skan    op = XVECEXP (op, 0, 0);
15107169689Skan  op = XEXP (op, 1);
15108169689Skan
15109169689Skan  early_op = XEXP (op, 0);
15110169689Skan
15111169689Skan  /* This is either an actual independent shift, or a shift applied to
15112169689Skan     the first operand of another operation.  We want the value being
15113169689Skan     shifted, in either case.  */
15114169689Skan  if (GET_CODE (early_op) != REG)
15115169689Skan    early_op = XEXP (early_op, 0);
15116169689Skan
15117169689Skan  return !reg_overlap_mentioned_p (value, early_op);
15118169689Skan}
15119169689Skan
15120169689Skan/* Return nonzero if the CONSUMER (a mul or mac op) does not
15121169689Skan   have an early register mult dependency on the result of
15122169689Skan   PRODUCER.  */
15123169689Skan
15124169689Skanint
15125169689Skanarm_no_early_mul_dep (rtx producer, rtx consumer)
15126169689Skan{
15127169689Skan  rtx value = PATTERN (producer);
15128169689Skan  rtx op = PATTERN (consumer);
15129169689Skan
15130169689Skan  if (GET_CODE (value) == COND_EXEC)
15131169689Skan    value = COND_EXEC_CODE (value);
15132169689Skan  if (GET_CODE (value) == PARALLEL)
15133169689Skan    value = XVECEXP (value, 0, 0);
15134169689Skan  value = XEXP (value, 0);
15135169689Skan  if (GET_CODE (op) == COND_EXEC)
15136169689Skan    op = COND_EXEC_CODE (op);
15137169689Skan  if (GET_CODE (op) == PARALLEL)
15138169689Skan    op = XVECEXP (op, 0, 0);
15139169689Skan  op = XEXP (op, 1);
15140169689Skan
15141169689Skan  return (GET_CODE (op) == PLUS
15142169689Skan	  && !reg_overlap_mentioned_p (value, XEXP (op, 0)));
15143169689Skan}
15144169689Skan
15145169689Skan
15146169689Skan/* We can't rely on the caller doing the proper promotion when
15147169689Skan   using APCS or ATPCS.  */
15148169689Skan
15149169689Skanstatic bool
15150169689Skanarm_promote_prototypes (tree t ATTRIBUTE_UNUSED)
15151169689Skan{
15152169689Skan    return !TARGET_AAPCS_BASED;
15153169689Skan}
15154169689Skan
15155169689Skan
15156169689Skan/* AAPCS based ABIs use short enums by default.  */
15157169689Skan
15158169689Skanstatic bool
15159169689Skanarm_default_short_enums (void)
15160169689Skan{
15161169689Skan  return TARGET_AAPCS_BASED && arm_abi != ARM_ABI_AAPCS_LINUX;
15162169689Skan}
15163169689Skan
15164169689Skan
15165169689Skan/* AAPCS requires that anonymous bitfields affect structure alignment.  */
15166169689Skan
15167169689Skanstatic bool
15168169689Skanarm_align_anon_bitfield (void)
15169169689Skan{
15170169689Skan  return TARGET_AAPCS_BASED;
15171169689Skan}
15172169689Skan
15173169689Skan
15174169689Skan/* The generic C++ ABI says 64-bit (long long).  The EABI says 32-bit.  */
15175169689Skan
15176169689Skanstatic tree
15177169689Skanarm_cxx_guard_type (void)
15178169689Skan{
15179169689Skan  return TARGET_AAPCS_BASED ? integer_type_node : long_long_integer_type_node;
15180169689Skan}
15181169689Skan
15182169689Skan
15183169689Skan/* The EABI says test the least significant bit of a guard variable.  */
15184169689Skan
15185169689Skanstatic bool
15186169689Skanarm_cxx_guard_mask_bit (void)
15187169689Skan{
15188169689Skan  return TARGET_AAPCS_BASED;
15189169689Skan}
15190169689Skan
15191169689Skan
15192169689Skan/* The EABI specifies that all array cookies are 8 bytes long.  */
15193169689Skan
15194169689Skanstatic tree
15195169689Skanarm_get_cookie_size (tree type)
15196169689Skan{
15197169689Skan  tree size;
15198169689Skan
15199169689Skan  if (!TARGET_AAPCS_BASED)
15200169689Skan    return default_cxx_get_cookie_size (type);
15201169689Skan
15202169689Skan  size = build_int_cst (sizetype, 8);
15203169689Skan  return size;
15204169689Skan}
15205169689Skan
15206169689Skan
15207169689Skan/* The EABI says that array cookies should also contain the element size.  */
15208169689Skan
15209169689Skanstatic bool
15210169689Skanarm_cookie_has_size (void)
15211169689Skan{
15212169689Skan  return TARGET_AAPCS_BASED;
15213169689Skan}
15214169689Skan
15215169689Skan
15216169689Skan/* The EABI says constructors and destructors should return a pointer to
15217169689Skan   the object constructed/destroyed.  */
15218169689Skan
15219169689Skanstatic bool
15220169689Skanarm_cxx_cdtor_returns_this (void)
15221169689Skan{
15222169689Skan  return TARGET_AAPCS_BASED;
15223169689Skan}
15224169689Skan
15225169689Skan/* The EABI says that an inline function may never be the key
15226169689Skan   method.  */
15227169689Skan
15228169689Skanstatic bool
15229169689Skanarm_cxx_key_method_may_be_inline (void)
15230169689Skan{
15231169689Skan  return !TARGET_AAPCS_BASED;
15232169689Skan}
15233169689Skan
15234169689Skanstatic void
15235169689Skanarm_cxx_determine_class_data_visibility (tree decl)
15236169689Skan{
15237169689Skan  if (!TARGET_AAPCS_BASED)
15238169689Skan    return;
15239169689Skan
15240169689Skan  /* In general, \S 3.2.5.5 of the ARM EABI requires that class data
15241169689Skan     is exported.  However, on systems without dynamic vague linkage,
15242169689Skan     \S 3.2.5.6 says that COMDAT class data has hidden linkage.  */
15243169689Skan  if (!TARGET_ARM_DYNAMIC_VAGUE_LINKAGE_P && DECL_COMDAT (decl))
15244169689Skan    DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN;
15245169689Skan  else
15246169689Skan    DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
15247169689Skan  DECL_VISIBILITY_SPECIFIED (decl) = 1;
15248169689Skan}
15249169689Skan
15250169689Skanstatic bool
15251169689Skanarm_cxx_class_data_always_comdat (void)
15252169689Skan{
15253169689Skan  /* \S 3.2.5.4 of the ARM C++ ABI says that class data only have
15254169689Skan     vague linkage if the class has no key function.  */
15255169689Skan  return !TARGET_AAPCS_BASED;
15256169689Skan}
15257169689Skan
15258169689Skan
15259169689Skan/* The EABI says __aeabi_atexit should be used to register static
15260169689Skan   destructors.  */
15261169689Skan
15262169689Skanstatic bool
15263169689Skanarm_cxx_use_aeabi_atexit (void)
15264169689Skan{
15265169689Skan  return TARGET_AAPCS_BASED;
15266169689Skan}
15267169689Skan
15268169689Skan
15269169689Skanvoid
15270169689Skanarm_set_return_address (rtx source, rtx scratch)
15271169689Skan{
15272169689Skan  arm_stack_offsets *offsets;
15273169689Skan  HOST_WIDE_INT delta;
15274169689Skan  rtx addr;
15275169689Skan  unsigned long saved_regs;
15276169689Skan
15277169689Skan  saved_regs = arm_compute_save_reg_mask ();
15278169689Skan
15279169689Skan  if ((saved_regs & (1 << LR_REGNUM)) == 0)
15280169689Skan    emit_move_insn (gen_rtx_REG (Pmode, LR_REGNUM), source);
15281169689Skan  else
15282169689Skan    {
15283169689Skan      if (frame_pointer_needed)
15284169689Skan	addr = plus_constant(hard_frame_pointer_rtx, -4);
15285169689Skan      else
15286169689Skan	{
15287169689Skan	  /* LR will be the first saved register.  */
15288169689Skan	  offsets = arm_get_frame_offsets ();
15289169689Skan	  delta = offsets->outgoing_args - (offsets->frame + 4);
15290169689Skan
15291169689Skan
15292169689Skan	  if (delta >= 4096)
15293169689Skan	    {
15294169689Skan	      emit_insn (gen_addsi3 (scratch, stack_pointer_rtx,
15295169689Skan				     GEN_INT (delta & ~4095)));
15296169689Skan	      addr = scratch;
15297169689Skan	      delta &= 4095;
15298169689Skan	    }
15299169689Skan	  else
15300169689Skan	    addr = stack_pointer_rtx;
15301169689Skan
15302169689Skan	  addr = plus_constant (addr, delta);
15303169689Skan	}
15304169689Skan      emit_move_insn (gen_frame_mem (Pmode, addr), source);
15305169689Skan    }
15306169689Skan}
15307169689Skan
15308169689Skan
15309169689Skanvoid
15310169689Skanthumb_set_return_address (rtx source, rtx scratch)
15311169689Skan{
15312169689Skan  arm_stack_offsets *offsets;
15313169689Skan  HOST_WIDE_INT delta;
15314169689Skan  int reg;
15315169689Skan  rtx addr;
15316169689Skan  unsigned long mask;
15317169689Skan
15318169689Skan  emit_insn (gen_rtx_USE (VOIDmode, source));
15319169689Skan
15320169689Skan  mask = thumb_compute_save_reg_mask ();
15321169689Skan  if (mask & (1 << LR_REGNUM))
15322169689Skan    {
15323169689Skan      offsets = arm_get_frame_offsets ();
15324169689Skan
15325169689Skan      /* Find the saved regs.  */
15326169689Skan      if (frame_pointer_needed)
15327169689Skan	{
15328169689Skan	  delta = offsets->soft_frame - offsets->saved_args;
15329169689Skan	  reg = THUMB_HARD_FRAME_POINTER_REGNUM;
15330169689Skan	}
15331169689Skan      else
15332169689Skan	{
15333169689Skan	  delta = offsets->outgoing_args - offsets->saved_args;
15334169689Skan	  reg = SP_REGNUM;
15335169689Skan	}
15336169689Skan      /* Allow for the stack frame.  */
15337169689Skan      if (TARGET_BACKTRACE)
15338169689Skan	delta -= 16;
15339169689Skan      /* The link register is always the first saved register.  */
15340169689Skan      delta -= 4;
15341169689Skan
15342169689Skan      /* Construct the address.  */
15343169689Skan      addr = gen_rtx_REG (SImode, reg);
15344169689Skan      if ((reg != SP_REGNUM && delta >= 128)
15345169689Skan	  || delta >= 1024)
15346169689Skan	{
15347169689Skan	  emit_insn (gen_movsi (scratch, GEN_INT (delta)));
15348169689Skan	  emit_insn (gen_addsi3 (scratch, scratch, stack_pointer_rtx));
15349169689Skan	  addr = scratch;
15350169689Skan	}
15351169689Skan      else
15352169689Skan	addr = plus_constant (addr, delta);
15353169689Skan
15354169689Skan      emit_move_insn (gen_frame_mem (Pmode, addr), source);
15355169689Skan    }
15356169689Skan  else
15357169689Skan    emit_move_insn (gen_rtx_REG (Pmode, LR_REGNUM), source);
15358169689Skan}
15359169689Skan
15360169689Skan/* Implements target hook vector_mode_supported_p.  */
15361169689Skanbool
15362169689Skanarm_vector_mode_supported_p (enum machine_mode mode)
15363169689Skan{
15364169689Skan  if ((mode == V2SImode)
15365169689Skan      || (mode == V4HImode)
15366169689Skan      || (mode == V8QImode))
15367169689Skan    return true;
15368169689Skan
15369169689Skan  return false;
15370169689Skan}
15371169689Skan
15372169689Skan/* Implement TARGET_SHIFT_TRUNCATION_MASK.  SImode shifts use normal
15373169689Skan   ARM insns and therefore guarantee that the shift count is modulo 256.
15374169689Skan   DImode shifts (those implemented by lib1funcs.asm or by optabs.c)
15375169689Skan   guarantee no particular behavior for out-of-range counts.  */
15376169689Skan
15377169689Skanstatic unsigned HOST_WIDE_INT
15378169689Skanarm_shift_truncation_mask (enum machine_mode mode)
15379169689Skan{
15380169689Skan  return mode == SImode ? 255 : 0;
15381169689Skan}
15382169689Skan
15383169689Skan
15384169689Skan/* Map internal gcc register numbers to DWARF2 register numbers.  */
15385169689Skan
15386169689Skanunsigned int
15387169689Skanarm_dbx_register_number (unsigned int regno)
15388169689Skan{
15389169689Skan  if (regno < 16)
15390169689Skan    return regno;
15391169689Skan
15392169689Skan  /* TODO: Legacy targets output FPA regs as registers 16-23 for backwards
15393169689Skan     compatibility.  The EABI defines them as registers 96-103.  */
15394169689Skan  if (IS_FPA_REGNUM (regno))
15395169689Skan    return (TARGET_AAPCS_BASED ? 96 : 16) + regno - FIRST_FPA_REGNUM;
15396169689Skan
15397169689Skan  if (IS_VFP_REGNUM (regno))
15398169689Skan    return 64 + regno - FIRST_VFP_REGNUM;
15399169689Skan
15400169689Skan  if (IS_IWMMXT_GR_REGNUM (regno))
15401169689Skan    return 104 + regno - FIRST_IWMMXT_GR_REGNUM;
15402169689Skan
15403169689Skan  if (IS_IWMMXT_REGNUM (regno))
15404169689Skan    return 112 + regno - FIRST_IWMMXT_REGNUM;
15405169689Skan
15406169689Skan  gcc_unreachable ();
15407169689Skan}
15408169689Skan
15409169689Skan
15410169689Skan#ifdef TARGET_UNWIND_INFO
15411169689Skan/* Emit unwind directives for a store-multiple instruction.  This should
15412169689Skan   only ever be generated by the function prologue code, so we expect it
15413169689Skan   to have a particular form.  */
15414169689Skan
15415169689Skanstatic void
15416169689Skanarm_unwind_emit_stm (FILE * asm_out_file, rtx p)
15417169689Skan{
15418169689Skan  int i;
15419169689Skan  HOST_WIDE_INT offset;
15420169689Skan  HOST_WIDE_INT nregs;
15421169689Skan  int reg_size;
15422169689Skan  unsigned reg;
15423169689Skan  unsigned lastreg;
15424169689Skan  rtx e;
15425169689Skan
15426169689Skan  /* First insn will adjust the stack pointer.  */
15427169689Skan  e = XVECEXP (p, 0, 0);
15428169689Skan  if (GET_CODE (e) != SET
15429169689Skan      || GET_CODE (XEXP (e, 0)) != REG
15430169689Skan      || REGNO (XEXP (e, 0)) != SP_REGNUM
15431169689Skan      || GET_CODE (XEXP (e, 1)) != PLUS)
15432169689Skan    abort ();
15433169689Skan
15434169689Skan  offset = -INTVAL (XEXP (XEXP (e, 1), 1));
15435169689Skan  nregs = XVECLEN (p, 0) - 1;
15436169689Skan
15437169689Skan  reg = REGNO (XEXP (XVECEXP (p, 0, 1), 1));
15438169689Skan  if (reg < 16)
15439169689Skan    {
15440169689Skan      /* The function prologue may also push pc, but not annotate it as it is
15441169689Skan	 never restored.  We turn this into a stack pointer adjustment.  */
15442169689Skan      if (nregs * 4 == offset - 4)
15443169689Skan	{
15444169689Skan	  fprintf (asm_out_file, "\t.pad #4\n");
15445169689Skan	  offset -= 4;
15446169689Skan	}
15447169689Skan      reg_size = 4;
15448169689Skan    }
15449169689Skan  else if (IS_VFP_REGNUM (reg))
15450169689Skan    {
15451169689Skan      /* FPA register saves use an additional word.  */
15452169689Skan      offset -= 4;
15453169689Skan      reg_size = 8;
15454169689Skan    }
15455169689Skan  else if (reg >= FIRST_FPA_REGNUM && reg <= LAST_FPA_REGNUM)
15456169689Skan    {
15457169689Skan      /* FPA registers are done differently.  */
15458169689Skan      asm_fprintf (asm_out_file, "\t.save %r, %wd\n", reg, nregs);
15459169689Skan      return;
15460169689Skan    }
15461169689Skan  else
15462169689Skan    /* Unknown register type.  */
15463169689Skan    abort ();
15464169689Skan
15465169689Skan  /* If the stack increment doesn't match the size of the saved registers,
15466169689Skan     something has gone horribly wrong.  */
15467169689Skan  if (offset != nregs * reg_size)
15468169689Skan    abort ();
15469169689Skan
15470169689Skan  fprintf (asm_out_file, "\t.save {");
15471169689Skan
15472169689Skan  offset = 0;
15473169689Skan  lastreg = 0;
15474169689Skan  /* The remaining insns will describe the stores.  */
15475169689Skan  for (i = 1; i <= nregs; i++)
15476169689Skan    {
15477169689Skan      /* Expect (set (mem <addr>) (reg)).
15478169689Skan         Where <addr> is (reg:SP) or (plus (reg:SP) (const_int)).  */
15479169689Skan      e = XVECEXP (p, 0, i);
15480169689Skan      if (GET_CODE (e) != SET
15481169689Skan	  || GET_CODE (XEXP (e, 0)) != MEM
15482169689Skan	  || GET_CODE (XEXP (e, 1)) != REG)
15483169689Skan	abort ();
15484169689Skan
15485169689Skan      reg = REGNO (XEXP (e, 1));
15486169689Skan      if (reg < lastreg)
15487169689Skan	abort ();
15488169689Skan
15489169689Skan      if (i != 1)
15490169689Skan	fprintf (asm_out_file, ", ");
15491169689Skan      /* We can't use %r for vfp because we need to use the
15492169689Skan	 double precision register names.  */
15493169689Skan      if (IS_VFP_REGNUM (reg))
15494169689Skan	asm_fprintf (asm_out_file, "d%d", (reg - FIRST_VFP_REGNUM) / 2);
15495169689Skan      else
15496169689Skan	asm_fprintf (asm_out_file, "%r", reg);
15497169689Skan
15498169689Skan#ifdef ENABLE_CHECKING
15499169689Skan      /* Check that the addresses are consecutive.  */
15500169689Skan      e = XEXP (XEXP (e, 0), 0);
15501169689Skan      if (GET_CODE (e) == PLUS)
15502169689Skan	{
15503169689Skan	  offset += reg_size;
15504169689Skan	  if (GET_CODE (XEXP (e, 0)) != REG
15505169689Skan	      || REGNO (XEXP (e, 0)) != SP_REGNUM
15506169689Skan	      || GET_CODE (XEXP (e, 1)) != CONST_INT
15507169689Skan	      || offset != INTVAL (XEXP (e, 1)))
15508169689Skan	    abort ();
15509169689Skan	}
15510169689Skan      else if (i != 1
15511169689Skan	       || GET_CODE (e) != REG
15512169689Skan	       || REGNO (e) != SP_REGNUM)
15513169689Skan	abort ();
15514169689Skan#endif
15515169689Skan    }
15516169689Skan  fprintf (asm_out_file, "}\n");
15517169689Skan}
15518169689Skan
15519169689Skan/*  Emit unwind directives for a SET.  */
15520169689Skan
15521169689Skanstatic void
15522169689Skanarm_unwind_emit_set (FILE * asm_out_file, rtx p)
15523169689Skan{
15524169689Skan  rtx e0;
15525169689Skan  rtx e1;
15526169689Skan
15527169689Skan  e0 = XEXP (p, 0);
15528169689Skan  e1 = XEXP (p, 1);
15529169689Skan  switch (GET_CODE (e0))
15530169689Skan    {
15531169689Skan    case MEM:
15532169689Skan      /* Pushing a single register.  */
15533169689Skan      if (GET_CODE (XEXP (e0, 0)) != PRE_DEC
15534169689Skan	  || GET_CODE (XEXP (XEXP (e0, 0), 0)) != REG
15535169689Skan	  || REGNO (XEXP (XEXP (e0, 0), 0)) != SP_REGNUM)
15536169689Skan	abort ();
15537169689Skan
15538169689Skan      asm_fprintf (asm_out_file, "\t.save ");
15539169689Skan      if (IS_VFP_REGNUM (REGNO (e1)))
15540169689Skan	asm_fprintf(asm_out_file, "{d%d}\n",
15541169689Skan		    (REGNO (e1) - FIRST_VFP_REGNUM) / 2);
15542169689Skan      else
15543169689Skan	asm_fprintf(asm_out_file, "{%r}\n", REGNO (e1));
15544169689Skan      break;
15545169689Skan
15546169689Skan    case REG:
15547169689Skan      if (REGNO (e0) == SP_REGNUM)
15548169689Skan	{
15549169689Skan	  /* A stack increment.  */
15550169689Skan	  if (GET_CODE (e1) != PLUS
15551169689Skan	      || GET_CODE (XEXP (e1, 0)) != REG
15552169689Skan	      || REGNO (XEXP (e1, 0)) != SP_REGNUM
15553169689Skan	      || GET_CODE (XEXP (e1, 1)) != CONST_INT)
15554169689Skan	    abort ();
15555169689Skan
15556169689Skan	  asm_fprintf (asm_out_file, "\t.pad #%wd\n",
15557169689Skan		       -INTVAL (XEXP (e1, 1)));
15558169689Skan	}
15559169689Skan      else if (REGNO (e0) == HARD_FRAME_POINTER_REGNUM)
15560169689Skan	{
15561169689Skan	  HOST_WIDE_INT offset;
15562169689Skan	  unsigned reg;
15563169689Skan
15564169689Skan	  if (GET_CODE (e1) == PLUS)
15565169689Skan	    {
15566169689Skan	      if (GET_CODE (XEXP (e1, 0)) != REG
15567169689Skan		  || GET_CODE (XEXP (e1, 1)) != CONST_INT)
15568169689Skan		abort ();
15569169689Skan	      reg = REGNO (XEXP (e1, 0));
15570169689Skan	      offset = INTVAL (XEXP (e1, 1));
15571169689Skan	      asm_fprintf (asm_out_file, "\t.setfp %r, %r, #%wd\n",
15572169689Skan			   HARD_FRAME_POINTER_REGNUM, reg,
15573169689Skan			   INTVAL (XEXP (e1, 1)));
15574169689Skan	    }
15575169689Skan	  else if (GET_CODE (e1) == REG)
15576169689Skan	    {
15577169689Skan	      reg = REGNO (e1);
15578169689Skan	      asm_fprintf (asm_out_file, "\t.setfp %r, %r\n",
15579169689Skan			   HARD_FRAME_POINTER_REGNUM, reg);
15580169689Skan	    }
15581169689Skan	  else
15582169689Skan	    abort ();
15583169689Skan	}
15584169689Skan      else if (GET_CODE (e1) == REG && REGNO (e1) == SP_REGNUM)
15585169689Skan	{
15586169689Skan	  /* Move from sp to reg.  */
15587169689Skan	  asm_fprintf (asm_out_file, "\t.movsp %r\n", REGNO (e0));
15588169689Skan	}
15589169689Skan     else if (GET_CODE (e1) == PLUS
15590169689Skan	      && GET_CODE (XEXP (e1, 0)) == REG
15591169689Skan	      && REGNO (XEXP (e1, 0)) == SP_REGNUM
15592169689Skan	      && GET_CODE (XEXP (e1, 1)) == CONST_INT)
15593169689Skan	{
15594169689Skan	  /* Set reg to offset from sp.  */
15595169689Skan	  asm_fprintf (asm_out_file, "\t.movsp %r, #%d\n",
15596169689Skan		       REGNO (e0), (int)INTVAL(XEXP (e1, 1)));
15597169689Skan	}
15598169689Skan      else
15599169689Skan	abort ();
15600169689Skan      break;
15601169689Skan
15602169689Skan    default:
15603169689Skan      abort ();
15604169689Skan    }
15605169689Skan}
15606169689Skan
15607169689Skan
15608169689Skan/* Emit unwind directives for the given insn.  */
15609169689Skan
15610169689Skanstatic void
15611169689Skanarm_unwind_emit (FILE * asm_out_file, rtx insn)
15612169689Skan{
15613169689Skan  rtx pat;
15614169689Skan
15615169689Skan  if (!ARM_EABI_UNWIND_TABLES)
15616169689Skan    return;
15617169689Skan
15618169689Skan  if (GET_CODE (insn) == NOTE || !RTX_FRAME_RELATED_P (insn))
15619169689Skan    return;
15620169689Skan
15621169689Skan  pat = find_reg_note (insn, REG_FRAME_RELATED_EXPR, NULL_RTX);
15622169689Skan  if (pat)
15623169689Skan    pat = XEXP (pat, 0);
15624169689Skan  else
15625169689Skan    pat = PATTERN (insn);
15626169689Skan
15627169689Skan  switch (GET_CODE (pat))
15628169689Skan    {
15629169689Skan    case SET:
15630169689Skan      arm_unwind_emit_set (asm_out_file, pat);
15631169689Skan      break;
15632169689Skan
15633169689Skan    case SEQUENCE:
15634169689Skan      /* Store multiple.  */
15635169689Skan      arm_unwind_emit_stm (asm_out_file, pat);
15636169689Skan      break;
15637169689Skan
15638169689Skan    default:
15639169689Skan      abort();
15640169689Skan    }
15641169689Skan}
15642169689Skan
15643169689Skan
15644169689Skan/* Output a reference from a function exception table to the type_info
15645169689Skan   object X.  The EABI specifies that the symbol should be relocated by
15646169689Skan   an R_ARM_TARGET2 relocation.  */
15647169689Skan
15648169689Skanstatic bool
15649169689Skanarm_output_ttype (rtx x)
15650169689Skan{
15651169689Skan  fputs ("\t.word\t", asm_out_file);
15652169689Skan  output_addr_const (asm_out_file, x);
15653169689Skan  /* Use special relocations for symbol references.  */
15654169689Skan  if (GET_CODE (x) != CONST_INT)
15655169689Skan    fputs ("(TARGET2)", asm_out_file);
15656169689Skan  fputc ('\n', asm_out_file);
15657169689Skan
15658169689Skan  return TRUE;
15659169689Skan}
15660169689Skan#endif /* TARGET_UNWIND_INFO */
15661169689Skan
15662169689Skan
15663169689Skan/* Output unwind directives for the start/end of a function.  */
15664169689Skan
15665169689Skanvoid
15666169689Skanarm_output_fn_unwind (FILE * f, bool prologue)
15667169689Skan{
15668169689Skan  if (!ARM_EABI_UNWIND_TABLES)
15669169689Skan    return;
15670169689Skan
15671169689Skan  if (prologue)
15672169689Skan    fputs ("\t.fnstart\n", f);
15673169689Skan  else
15674169689Skan    fputs ("\t.fnend\n", f);
15675169689Skan}
15676169689Skan
15677169689Skanstatic bool
15678169689Skanarm_emit_tls_decoration (FILE *fp, rtx x)
15679169689Skan{
15680169689Skan  enum tls_reloc reloc;
15681169689Skan  rtx val;
15682169689Skan
15683169689Skan  val = XVECEXP (x, 0, 0);
15684169689Skan  reloc = INTVAL (XVECEXP (x, 0, 1));
15685169689Skan
15686169689Skan  output_addr_const (fp, val);
15687169689Skan
15688169689Skan  switch (reloc)
15689169689Skan    {
15690169689Skan    case TLS_GD32:
15691169689Skan      fputs ("(tlsgd)", fp);
15692169689Skan      break;
15693169689Skan    case TLS_LDM32:
15694169689Skan      fputs ("(tlsldm)", fp);
15695169689Skan      break;
15696169689Skan    case TLS_LDO32:
15697169689Skan      fputs ("(tlsldo)", fp);
15698169689Skan      break;
15699169689Skan    case TLS_IE32:
15700169689Skan      fputs ("(gottpoff)", fp);
15701169689Skan      break;
15702169689Skan    case TLS_LE32:
15703169689Skan      fputs ("(tpoff)", fp);
15704169689Skan      break;
15705169689Skan    default:
15706169689Skan      gcc_unreachable ();
15707169689Skan    }
15708169689Skan
15709169689Skan  switch (reloc)
15710169689Skan    {
15711169689Skan    case TLS_GD32:
15712169689Skan    case TLS_LDM32:
15713169689Skan    case TLS_IE32:
15714169689Skan      fputs (" + (. - ", fp);
15715169689Skan      output_addr_const (fp, XVECEXP (x, 0, 2));
15716169689Skan      fputs (" - ", fp);
15717169689Skan      output_addr_const (fp, XVECEXP (x, 0, 3));
15718169689Skan      fputc (')', fp);
15719169689Skan      break;
15720169689Skan    default:
15721169689Skan      break;
15722169689Skan    }
15723169689Skan
15724169689Skan  return TRUE;
15725169689Skan}
15726169689Skan
15727169689Skanbool
15728169689Skanarm_output_addr_const_extra (FILE *fp, rtx x)
15729169689Skan{
15730169689Skan  if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLS)
15731169689Skan    return arm_emit_tls_decoration (fp, x);
15732169689Skan  else if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_PIC_LABEL)
15733169689Skan    {
15734169689Skan      char label[256];
15735169689Skan      int labelno = INTVAL (XVECEXP (x, 0, 0));
15736169689Skan
15737169689Skan      ASM_GENERATE_INTERNAL_LABEL (label, "LPIC", labelno);
15738169689Skan      assemble_name_raw (fp, label);
15739169689Skan
15740169689Skan      return TRUE;
15741169689Skan    }
15742169689Skan  else if (GET_CODE (x) == CONST_VECTOR)
15743169689Skan    return arm_emit_vector_const (fp, x);
15744169689Skan
15745169689Skan  return FALSE;
15746169689Skan}
15747169689Skan
15748169689Skan#include "gt-arm.h"
15749