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);
157259873Spfgstatic 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
206259873Spfg#undef TARGET_ASM_FILE_START
207259873Spfg#define TARGET_ASM_FILE_START arm_file_start
208259873Spfg
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
397259873Spfg/* The default processor used if not overriden by commandline.  */
398259873Spfgstatic enum processor_type arm_default_cpu = arm_none;
399259873Spfg
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},
607276045Sian  /* Clang compatibility... define __ARM_ARCH_7A__, but codegen is still 6ZK. */
608276045Sian  {"armv7a",  arm1176jzs, "7A",  FL_CO_PROC |             FL_FOR_ARCH6ZK, NULL},
609169689Skan  {"ep9312",  ep9312,     "4T",  FL_LDSCHED | FL_CIRRUS | FL_FOR_ARCH4, NULL},
610169689Skan  {"iwmmxt",  iwmmxt,     "5TE", FL_LDSCHED | FL_STRONG | FL_FOR_ARCH5TE | FL_XSCALE | FL_IWMMXT , NULL},
611169689Skan  {NULL, arm_none, NULL, 0 , NULL}
61290075Sobrien};
61390075Sobrien
614169689Skanstruct arm_cpu_select
615169689Skan{
616169689Skan  const char *              string;
617169689Skan  const char *              name;
618169689Skan  const struct processors * processors;
619169689Skan};
620169689Skan
621132718Skan/* This is a magic structure.  The 'string' field is magically filled in
62290075Sobrien   with a pointer to the value specified by the user on the command line
62390075Sobrien   assuming that the user has specified such a value.  */
62490075Sobrien
625169689Skanstatic struct arm_cpu_select arm_select[] =
62690075Sobrien{
627169689Skan  /* string	  name            processors  */
62890075Sobrien  { NULL,	"-mcpu=",	all_cores  },
62990075Sobrien  { NULL,	"-march=",	all_architectures },
63090075Sobrien  { NULL,	"-mtune=",	all_cores }
63190075Sobrien};
63290075Sobrien
633169689Skan/* Defines representing the indexes into the above table.  */
634169689Skan#define ARM_OPT_SET_CPU 0
635169689Skan#define ARM_OPT_SET_ARCH 1
636169689Skan#define ARM_OPT_SET_TUNE 2
637169689Skan
638169689Skan/* The name of the preprocessor macro to define for this architecture.  */
639169689Skan
640169689Skanchar arm_arch_name[] = "__ARM_ARCH_0UNK__";
641169689Skan
642169689Skanstruct fpu_desc
643169689Skan{
644169689Skan  const char * name;
645169689Skan  enum fputype fpu;
646169689Skan};
647169689Skan
648169689Skan
649169689Skan/* Available values for -mfpu=.  */
650169689Skan
651169689Skanstatic const struct fpu_desc all_fpus[] =
652169689Skan{
653169689Skan  {"fpa",	FPUTYPE_FPA},
654169689Skan  {"fpe2",	FPUTYPE_FPA_EMU2},
655169689Skan  {"fpe3",	FPUTYPE_FPA_EMU2},
656169689Skan  {"maverick",	FPUTYPE_MAVERICK},
657169689Skan  {"vfp",	FPUTYPE_VFP}
658169689Skan};
659169689Skan
660169689Skan
661169689Skan/* Floating point models used by the different hardware.
662169689Skan   See fputype in arm.h.  */
663169689Skan
664169689Skanstatic const enum fputype fp_model_for_fpu[] =
665169689Skan{
666169689Skan  /* No FP hardware.  */
667169689Skan  ARM_FP_MODEL_UNKNOWN,		/* FPUTYPE_NONE  */
668169689Skan  ARM_FP_MODEL_FPA,		/* FPUTYPE_FPA  */
669169689Skan  ARM_FP_MODEL_FPA,		/* FPUTYPE_FPA_EMU2  */
670169689Skan  ARM_FP_MODEL_FPA,		/* FPUTYPE_FPA_EMU3  */
671169689Skan  ARM_FP_MODEL_MAVERICK,	/* FPUTYPE_MAVERICK  */
672169689Skan  ARM_FP_MODEL_VFP		/* FPUTYPE_VFP  */
673169689Skan};
674169689Skan
675169689Skan
676169689Skanstruct float_abi
677169689Skan{
678169689Skan  const char * name;
679169689Skan  enum float_abi_type abi_type;
680169689Skan};
681169689Skan
682169689Skan
683169689Skan/* Available values for -mfloat-abi=.  */
684169689Skan
685169689Skanstatic const struct float_abi all_float_abis[] =
686169689Skan{
687169689Skan  {"soft",	ARM_FLOAT_ABI_SOFT},
688169689Skan  {"softfp",	ARM_FLOAT_ABI_SOFTFP},
689169689Skan  {"hard",	ARM_FLOAT_ABI_HARD}
690169689Skan};
691169689Skan
692169689Skan
693169689Skanstruct abi_name
694169689Skan{
695169689Skan  const char *name;
696169689Skan  enum arm_abi_type abi_type;
697169689Skan};
698169689Skan
699169689Skan
700169689Skan/* Available values for -mabi=.  */
701169689Skan
702169689Skanstatic const struct abi_name arm_all_abis[] =
703169689Skan{
704169689Skan  {"apcs-gnu",    ARM_ABI_APCS},
705169689Skan  {"atpcs",   ARM_ABI_ATPCS},
706169689Skan  {"aapcs",   ARM_ABI_AAPCS},
707169689Skan  {"iwmmxt",  ARM_ABI_IWMMXT},
708169689Skan  {"aapcs-linux",   ARM_ABI_AAPCS_LINUX}
709169689Skan};
710169689Skan
711169689Skan/* Supported TLS relocations.  */
712169689Skan
713169689Skanenum tls_reloc {
714169689Skan  TLS_GD32,
715169689Skan  TLS_LDM32,
716169689Skan  TLS_LDO32,
717169689Skan  TLS_IE32,
718169689Skan  TLS_LE32
719169689Skan};
720169689Skan
721169689Skan/* Emit an insn that's a simple single-set.  Both the operands must be known
722169689Skan   to be valid.  */
723169689Skaninline static rtx
724169689Skanemit_set_insn (rtx x, rtx y)
725169689Skan{
726169689Skan  return emit_insn (gen_rtx_SET (VOIDmode, x, y));
727169689Skan}
728169689Skan
729117395Skan/* Return the number of bits set in VALUE.  */
730117395Skanstatic unsigned
731132718Skanbit_count (unsigned long value)
73290075Sobrien{
73390075Sobrien  unsigned long count = 0;
734169689Skan
73590075Sobrien  while (value)
73690075Sobrien    {
737117395Skan      count++;
738117395Skan      value &= value - 1;  /* Clear the least-significant set bit.  */
73990075Sobrien    }
74090075Sobrien
74190075Sobrien  return count;
74290075Sobrien}
74390075Sobrien
744169689Skan/* Set up library functions unique to ARM.  */
745169689Skan
746169689Skanstatic void
747169689Skanarm_init_libfuncs (void)
748169689Skan{
749169689Skan  /* There are no special library functions unless we are using the
750169689Skan     ARM BPABI.  */
751169689Skan  if (!TARGET_BPABI)
752169689Skan    return;
753169689Skan
754169689Skan  /* The functions below are described in Section 4 of the "Run-Time
755169689Skan     ABI for the ARM architecture", Version 1.0.  */
756169689Skan
757169689Skan  /* Double-precision floating-point arithmetic.  Table 2.  */
758169689Skan  set_optab_libfunc (add_optab, DFmode, "__aeabi_dadd");
759169689Skan  set_optab_libfunc (sdiv_optab, DFmode, "__aeabi_ddiv");
760169689Skan  set_optab_libfunc (smul_optab, DFmode, "__aeabi_dmul");
761169689Skan  set_optab_libfunc (neg_optab, DFmode, "__aeabi_dneg");
762169689Skan  set_optab_libfunc (sub_optab, DFmode, "__aeabi_dsub");
763169689Skan
764169689Skan  /* Double-precision comparisons.  Table 3.  */
765169689Skan  set_optab_libfunc (eq_optab, DFmode, "__aeabi_dcmpeq");
766169689Skan  set_optab_libfunc (ne_optab, DFmode, NULL);
767169689Skan  set_optab_libfunc (lt_optab, DFmode, "__aeabi_dcmplt");
768169689Skan  set_optab_libfunc (le_optab, DFmode, "__aeabi_dcmple");
769169689Skan  set_optab_libfunc (ge_optab, DFmode, "__aeabi_dcmpge");
770169689Skan  set_optab_libfunc (gt_optab, DFmode, "__aeabi_dcmpgt");
771169689Skan  set_optab_libfunc (unord_optab, DFmode, "__aeabi_dcmpun");
772169689Skan
773169689Skan  /* Single-precision floating-point arithmetic.  Table 4.  */
774169689Skan  set_optab_libfunc (add_optab, SFmode, "__aeabi_fadd");
775169689Skan  set_optab_libfunc (sdiv_optab, SFmode, "__aeabi_fdiv");
776169689Skan  set_optab_libfunc (smul_optab, SFmode, "__aeabi_fmul");
777169689Skan  set_optab_libfunc (neg_optab, SFmode, "__aeabi_fneg");
778169689Skan  set_optab_libfunc (sub_optab, SFmode, "__aeabi_fsub");
779169689Skan
780169689Skan  /* Single-precision comparisons.  Table 5.  */
781169689Skan  set_optab_libfunc (eq_optab, SFmode, "__aeabi_fcmpeq");
782169689Skan  set_optab_libfunc (ne_optab, SFmode, NULL);
783169689Skan  set_optab_libfunc (lt_optab, SFmode, "__aeabi_fcmplt");
784169689Skan  set_optab_libfunc (le_optab, SFmode, "__aeabi_fcmple");
785169689Skan  set_optab_libfunc (ge_optab, SFmode, "__aeabi_fcmpge");
786169689Skan  set_optab_libfunc (gt_optab, SFmode, "__aeabi_fcmpgt");
787169689Skan  set_optab_libfunc (unord_optab, SFmode, "__aeabi_fcmpun");
788169689Skan
789169689Skan  /* Floating-point to integer conversions.  Table 6.  */
790169689Skan  set_conv_libfunc (sfix_optab, SImode, DFmode, "__aeabi_d2iz");
791169689Skan  set_conv_libfunc (ufix_optab, SImode, DFmode, "__aeabi_d2uiz");
792169689Skan  set_conv_libfunc (sfix_optab, DImode, DFmode, "__aeabi_d2lz");
793169689Skan  set_conv_libfunc (ufix_optab, DImode, DFmode, "__aeabi_d2ulz");
794169689Skan  set_conv_libfunc (sfix_optab, SImode, SFmode, "__aeabi_f2iz");
795169689Skan  set_conv_libfunc (ufix_optab, SImode, SFmode, "__aeabi_f2uiz");
796169689Skan  set_conv_libfunc (sfix_optab, DImode, SFmode, "__aeabi_f2lz");
797169689Skan  set_conv_libfunc (ufix_optab, DImode, SFmode, "__aeabi_f2ulz");
798169689Skan
799169689Skan  /* Conversions between floating types.  Table 7.  */
800169689Skan  set_conv_libfunc (trunc_optab, SFmode, DFmode, "__aeabi_d2f");
801169689Skan  set_conv_libfunc (sext_optab, DFmode, SFmode, "__aeabi_f2d");
802169689Skan
803169689Skan  /* Integer to floating-point conversions.  Table 8.  */
804169689Skan  set_conv_libfunc (sfloat_optab, DFmode, SImode, "__aeabi_i2d");
805169689Skan  set_conv_libfunc (ufloat_optab, DFmode, SImode, "__aeabi_ui2d");
806169689Skan  set_conv_libfunc (sfloat_optab, DFmode, DImode, "__aeabi_l2d");
807169689Skan  set_conv_libfunc (ufloat_optab, DFmode, DImode, "__aeabi_ul2d");
808169689Skan  set_conv_libfunc (sfloat_optab, SFmode, SImode, "__aeabi_i2f");
809169689Skan  set_conv_libfunc (ufloat_optab, SFmode, SImode, "__aeabi_ui2f");
810169689Skan  set_conv_libfunc (sfloat_optab, SFmode, DImode, "__aeabi_l2f");
811169689Skan  set_conv_libfunc (ufloat_optab, SFmode, DImode, "__aeabi_ul2f");
812169689Skan
813169689Skan  /* Long long.  Table 9.  */
814169689Skan  set_optab_libfunc (smul_optab, DImode, "__aeabi_lmul");
815169689Skan  set_optab_libfunc (sdivmod_optab, DImode, "__aeabi_ldivmod");
816169689Skan  set_optab_libfunc (udivmod_optab, DImode, "__aeabi_uldivmod");
817169689Skan  set_optab_libfunc (ashl_optab, DImode, "__aeabi_llsl");
818169689Skan  set_optab_libfunc (lshr_optab, DImode, "__aeabi_llsr");
819169689Skan  set_optab_libfunc (ashr_optab, DImode, "__aeabi_lasr");
820169689Skan  set_optab_libfunc (cmp_optab, DImode, "__aeabi_lcmp");
821169689Skan  set_optab_libfunc (ucmp_optab, DImode, "__aeabi_ulcmp");
822169689Skan
823169689Skan  /* Integer (32/32->32) division.  \S 4.3.1.  */
824169689Skan  set_optab_libfunc (sdivmod_optab, SImode, "__aeabi_idivmod");
825169689Skan  set_optab_libfunc (udivmod_optab, SImode, "__aeabi_uidivmod");
826169689Skan
827169689Skan  /* The divmod functions are designed so that they can be used for
828169689Skan     plain division, even though they return both the quotient and the
829169689Skan     remainder.  The quotient is returned in the usual location (i.e.,
830169689Skan     r0 for SImode, {r0, r1} for DImode), just as would be expected
831169689Skan     for an ordinary division routine.  Because the AAPCS calling
832169689Skan     conventions specify that all of { r0, r1, r2, r3 } are
833169689Skan     callee-saved registers, there is no need to tell the compiler
834169689Skan     explicitly that those registers are clobbered by these
835169689Skan     routines.  */
836169689Skan  set_optab_libfunc (sdiv_optab, DImode, "__aeabi_ldivmod");
837169689Skan  set_optab_libfunc (udiv_optab, DImode, "__aeabi_uldivmod");
838169689Skan
839169689Skan  /* For SImode division the ABI provides div-without-mod routines,
840169689Skan     which are faster.  */
841169689Skan  set_optab_libfunc (sdiv_optab, SImode, "__aeabi_idiv");
842169689Skan  set_optab_libfunc (udiv_optab, SImode, "__aeabi_uidiv");
843169689Skan
844169689Skan  /* We don't have mod libcalls.  Fortunately gcc knows how to use the
845169689Skan     divmod libcalls instead.  */
846169689Skan  set_optab_libfunc (smod_optab, DImode, NULL);
847169689Skan  set_optab_libfunc (umod_optab, DImode, NULL);
848169689Skan  set_optab_libfunc (smod_optab, SImode, NULL);
849169689Skan  set_optab_libfunc (umod_optab, SImode, NULL);
850169689Skan}
851169689Skan
852169689Skan/* Implement TARGET_HANDLE_OPTION.  */
853169689Skan
854169689Skanstatic bool
855169689Skanarm_handle_option (size_t code, const char *arg, int value ATTRIBUTE_UNUSED)
856169689Skan{
857169689Skan  switch (code)
858169689Skan    {
859169689Skan    case OPT_march_:
860169689Skan      arm_select[1].string = arg;
861169689Skan      return true;
862169689Skan
863169689Skan    case OPT_mcpu_:
864169689Skan      arm_select[0].string = arg;
865169689Skan      return true;
866169689Skan
867169689Skan    case OPT_mhard_float:
868169689Skan      target_float_abi_name = "hard";
869169689Skan      return true;
870169689Skan
871169689Skan    case OPT_msoft_float:
872169689Skan      target_float_abi_name = "soft";
873169689Skan      return true;
874169689Skan
875169689Skan    case OPT_mtune_:
876169689Skan      arm_select[2].string = arg;
877169689Skan      return true;
878169689Skan
879169689Skan    default:
880169689Skan      return true;
881169689Skan    }
882169689Skan}
883169689Skan
88490075Sobrien/* Fix up any incompatible options that the user has specified.
88590075Sobrien   This has now turned into a maze.  */
88690075Sobrienvoid
887132718Skanarm_override_options (void)
88890075Sobrien{
88990075Sobrien  unsigned i;
890169689Skan  enum processor_type target_arch_cpu = arm_none;
891169689Skan
89290075Sobrien  /* Set up the flags based on the cpu/architecture selected by the user.  */
89390075Sobrien  for (i = ARRAY_SIZE (arm_select); i--;)
89490075Sobrien    {
89590075Sobrien      struct arm_cpu_select * ptr = arm_select + i;
896169689Skan
89790075Sobrien      if (ptr->string != NULL && ptr->string[0] != '\0')
89890075Sobrien        {
89990075Sobrien	  const struct processors * sel;
90090075Sobrien
90190075Sobrien          for (sel = ptr->processors; sel->name != NULL; sel++)
90290075Sobrien            if (streq (ptr->string, sel->name))
90390075Sobrien              {
904169689Skan		/* Set the architecture define.  */
905169689Skan		if (i != ARM_OPT_SET_TUNE)
906169689Skan		  sprintf (arm_arch_name, "__ARM_ARCH_%s__", sel->arch);
907169689Skan
908169689Skan		/* Determine the processor core for which we should
909169689Skan		   tune code-generation.  */
910169689Skan		if (/* -mcpu= is a sensible default.  */
911169689Skan		    i == ARM_OPT_SET_CPU
912169689Skan		    /* -mtune= overrides -mcpu= and -march=.  */
913169689Skan		    || i == ARM_OPT_SET_TUNE)
914169689Skan		  arm_tune = (enum processor_type) (sel - ptr->processors);
915169689Skan
916169689Skan		/* Remember the CPU associated with this architecture.
917169689Skan		   If no other option is used to set the CPU type,
918169689Skan		   we'll use this to guess the most suitable tuning
919169689Skan		   options.  */
920169689Skan		if (i == ARM_OPT_SET_ARCH)
921169689Skan		  target_arch_cpu = sel->core;
922169689Skan
923169689Skan		if (i != ARM_OPT_SET_TUNE)
92490075Sobrien		  {
92590075Sobrien		    /* If we have been given an architecture and a processor
92690075Sobrien		       make sure that they are compatible.  We only generate
92790075Sobrien		       a warning though, and we prefer the CPU over the
92890075Sobrien		       architecture.  */
92990075Sobrien		    if (insn_flags != 0 && (insn_flags ^ sel->flags))
930169689Skan		      warning (0, "switch -mcpu=%s conflicts with -march= switch",
93190075Sobrien			       ptr->string);
932169689Skan
93390075Sobrien		    insn_flags = sel->flags;
93490075Sobrien		  }
935169689Skan
93690075Sobrien                break;
93790075Sobrien              }
93890075Sobrien
93990075Sobrien          if (sel->name == NULL)
94090075Sobrien            error ("bad value (%s) for %s switch", ptr->string, ptr->name);
94190075Sobrien        }
94290075Sobrien    }
943169689Skan
944169689Skan  /* Guess the tuning options from the architecture if necessary.  */
945169689Skan  if (arm_tune == arm_none)
946169689Skan    arm_tune = target_arch_cpu;
947169689Skan
94890075Sobrien  /* If the user did not specify a processor, choose one for them.  */
94990075Sobrien  if (insn_flags == 0)
95090075Sobrien    {
95190075Sobrien      const struct processors * sel;
95290075Sobrien      unsigned int        sought;
953169689Skan      enum processor_type cpu;
95490075Sobrien
955169689Skan      cpu = TARGET_CPU_DEFAULT;
956169689Skan      if (cpu == arm_none)
957169689Skan	{
958169689Skan#ifdef SUBTARGET_CPU_DEFAULT
959169689Skan	  /* Use the subtarget default CPU if none was specified by
960169689Skan	     configure.  */
961169689Skan	  cpu = SUBTARGET_CPU_DEFAULT;
962169689Skan#endif
963169689Skan	  /* Default to ARM6.  */
964169689Skan	  if (cpu == arm_none)
965169689Skan	    cpu = arm6;
966169689Skan	}
967169689Skan      sel = &all_cores[cpu];
96890075Sobrien
96990075Sobrien      insn_flags = sel->flags;
970169689Skan
97190075Sobrien      /* Now check to see if the user has specified some command line
97290075Sobrien	 switch that require certain abilities from the cpu.  */
97390075Sobrien      sought = 0;
974169689Skan
97590075Sobrien      if (TARGET_INTERWORK || TARGET_THUMB)
97690075Sobrien	{
97790075Sobrien	  sought |= (FL_THUMB | FL_MODE32);
97890075Sobrien
97990075Sobrien	  /* There are no ARM processors that support both APCS-26 and
98090075Sobrien	     interworking.  Therefore we force FL_MODE26 to be removed
98190075Sobrien	     from insn_flags here (if it was set), so that the search
98290075Sobrien	     below will always be able to find a compatible processor.  */
98390075Sobrien	  insn_flags &= ~FL_MODE26;
98490075Sobrien	}
985169689Skan
98690075Sobrien      if (sought != 0 && ((sought & insn_flags) != sought))
98790075Sobrien	{
98890075Sobrien	  /* Try to locate a CPU type that supports all of the abilities
98990075Sobrien	     of the default CPU, plus the extra abilities requested by
99090075Sobrien	     the user.  */
99190075Sobrien	  for (sel = all_cores; sel->name != NULL; sel++)
99290075Sobrien	    if ((sel->flags & sought) == (sought | insn_flags))
99390075Sobrien	      break;
99490075Sobrien
99590075Sobrien	  if (sel->name == NULL)
99690075Sobrien	    {
997117395Skan	      unsigned current_bit_count = 0;
99890075Sobrien	      const struct processors * best_fit = NULL;
999169689Skan
100090075Sobrien	      /* Ideally we would like to issue an error message here
100190075Sobrien		 saying that it was not possible to find a CPU compatible
100290075Sobrien		 with the default CPU, but which also supports the command
100390075Sobrien		 line options specified by the programmer, and so they
100490075Sobrien		 ought to use the -mcpu=<name> command line option to
100590075Sobrien		 override the default CPU type.
100690075Sobrien
1007169689Skan		 If we cannot find a cpu that has both the
1008169689Skan		 characteristics of the default cpu and the given
1009169689Skan		 command line options we scan the array again looking
1010169689Skan		 for a best match.  */
101190075Sobrien	      for (sel = all_cores; sel->name != NULL; sel++)
101290075Sobrien		if ((sel->flags & sought) == sought)
101390075Sobrien		  {
1014117395Skan		    unsigned count;
101590075Sobrien
101690075Sobrien		    count = bit_count (sel->flags & insn_flags);
101790075Sobrien
101890075Sobrien		    if (count >= current_bit_count)
101990075Sobrien		      {
102090075Sobrien			best_fit = sel;
102190075Sobrien			current_bit_count = count;
102290075Sobrien		      }
102390075Sobrien		  }
102490075Sobrien
1025169689Skan	      gcc_assert (best_fit);
1026169689Skan	      sel = best_fit;
102790075Sobrien	    }
102890075Sobrien
102990075Sobrien	  insn_flags = sel->flags;
103090075Sobrien	}
1031169689Skan      sprintf (arm_arch_name, "__ARM_ARCH_%s__", sel->arch);
1032259873Spfg      arm_default_cpu = (enum processor_type) (sel - all_cores);
1033169689Skan      if (arm_tune == arm_none)
1034259873Spfg	arm_tune = arm_default_cpu;
103590075Sobrien    }
1036117395Skan
1037169689Skan  /* The processor for which we should tune should now have been
1038169689Skan     chosen.  */
1039169689Skan  gcc_assert (arm_tune != arm_none);
1040169689Skan
1041169689Skan  tune_flags = all_cores[(int)arm_tune].flags;
1042169689Skan  if (optimize_size)
1043169689Skan    targetm.rtx_costs = arm_size_rtx_costs;
1044169689Skan  else
1045169689Skan    targetm.rtx_costs = all_cores[(int)arm_tune].rtx_costs;
1046169689Skan
104790075Sobrien  /* Make sure that the processor choice does not conflict with any of the
104890075Sobrien     other command line choices.  */
104990075Sobrien  if (TARGET_INTERWORK && !(insn_flags & FL_THUMB))
105090075Sobrien    {
1051169689Skan      warning (0, "target CPU does not support interworking" );
1052169689Skan      target_flags &= ~MASK_INTERWORK;
105390075Sobrien    }
1054169689Skan
105590075Sobrien  if (TARGET_THUMB && !(insn_flags & FL_THUMB))
105690075Sobrien    {
1057169689Skan      warning (0, "target CPU does not support THUMB instructions");
1058169689Skan      target_flags &= ~MASK_THUMB;
105990075Sobrien    }
106090075Sobrien
106190075Sobrien  if (TARGET_APCS_FRAME && TARGET_THUMB)
106290075Sobrien    {
1063169689Skan      /* warning (0, "ignoring -mapcs-frame because -mthumb was used"); */
1064169689Skan      target_flags &= ~MASK_APCS_FRAME;
106590075Sobrien    }
106690075Sobrien
1067169689Skan  /* Callee super interworking implies thumb interworking.  Adding
1068169689Skan     this to the flags here simplifies the logic elsewhere.  */
1069169689Skan  if (TARGET_THUMB && TARGET_CALLEE_INTERWORKING)
1070169689Skan      target_flags |= MASK_INTERWORK;
1071169689Skan
107290075Sobrien  /* TARGET_BACKTRACE calls leaf_function_p, which causes a crash if done
107390075Sobrien     from here where no function is being compiled currently.  */
1074169689Skan  if ((TARGET_TPCS_FRAME || TARGET_TPCS_LEAF_FRAME) && TARGET_ARM)
1075169689Skan    warning (0, "enabling backtrace support is only meaningful when compiling for the Thumb");
107690075Sobrien
107790075Sobrien  if (TARGET_ARM && TARGET_CALLEE_INTERWORKING)
1078169689Skan    warning (0, "enabling callee interworking support is only meaningful when compiling for the Thumb");
107990075Sobrien
108090075Sobrien  if (TARGET_ARM && TARGET_CALLER_INTERWORKING)
1081169689Skan    warning (0, "enabling caller interworking support is only meaningful when compiling for the Thumb");
108290075Sobrien
108390075Sobrien  if (TARGET_APCS_STACK && !TARGET_APCS_FRAME)
108490075Sobrien    {
1085169689Skan      warning (0, "-mapcs-stack-check incompatible with -mno-apcs-frame");
1086169689Skan      target_flags |= MASK_APCS_FRAME;
108790075Sobrien    }
1088169689Skan
108990075Sobrien  if (TARGET_POKE_FUNCTION_NAME)
1090169689Skan    target_flags |= MASK_APCS_FRAME;
1091169689Skan
109290075Sobrien  if (TARGET_APCS_REENT && flag_pic)
109390075Sobrien    error ("-fpic and -mapcs-reent are incompatible");
1094169689Skan
109590075Sobrien  if (TARGET_APCS_REENT)
1096169689Skan    warning (0, "APCS reentrant code not supported.  Ignored");
1097169689Skan
109890075Sobrien  /* If this target is normally configured to use APCS frames, warn if they
109990075Sobrien     are turned off and debugging is turned on.  */
110090075Sobrien  if (TARGET_ARM
110190075Sobrien      && write_symbols != NO_DEBUG
110290075Sobrien      && !TARGET_APCS_FRAME
1103169689Skan      && (TARGET_DEFAULT & MASK_APCS_FRAME))
1104169689Skan    warning (0, "-g with -mno-apcs-frame may not give sensible debugging");
1105169689Skan
110690075Sobrien  /* If stack checking is disabled, we can use r10 as the PIC register,
110790075Sobrien     which keeps r9 available.  */
1108169689Skan  if (flag_pic && TARGET_SINGLE_PIC_BASE)
110996263Sobrien    arm_pic_register = TARGET_APCS_STACK ? 9 : 10;
1110169689Skan
111190075Sobrien  if (TARGET_APCS_FLOAT)
1112169689Skan    warning (0, "passing floating point arguments in fp regs not yet supported");
1113169689Skan
1114117395Skan  /* Initialize boolean versions of the flags, for use in the arm.md file.  */
1115169689Skan  arm_arch3m = (insn_flags & FL_ARCH3M) != 0;
1116169689Skan  arm_arch4 = (insn_flags & FL_ARCH4) != 0;
1117169689Skan  arm_arch4t = arm_arch4 & ((insn_flags & FL_THUMB) != 0);
1118169689Skan  arm_arch5 = (insn_flags & FL_ARCH5) != 0;
1119169689Skan  arm_arch5e = (insn_flags & FL_ARCH5E) != 0;
1120169689Skan  arm_arch6 = (insn_flags & FL_ARCH6) != 0;
1121169689Skan  arm_arch6k = (insn_flags & FL_ARCH6K) != 0;
1122169689Skan  arm_arch_xscale = (insn_flags & FL_XSCALE) != 0;
1123169689Skan  arm_arch_cirrus = (insn_flags & FL_CIRRUS) != 0;
112490075Sobrien
1125169689Skan  arm_ld_sched = (tune_flags & FL_LDSCHED) != 0;
1126169689Skan  arm_tune_strongarm = (tune_flags & FL_STRONG) != 0;
1127169689Skan  thumb_code = (TARGET_ARM == 0);
1128169689Skan  arm_tune_wbuf = (tune_flags & FL_WBUF) != 0;
1129169689Skan  arm_tune_xscale = (tune_flags & FL_XSCALE) != 0;
1130169689Skan  arm_arch_iwmmxt = (insn_flags & FL_IWMMXT) != 0;
113190075Sobrien
1132169689Skan  /* V5 code we generate is completely interworking capable, so we turn off
1133169689Skan     TARGET_INTERWORK here to avoid many tests later on.  */
1134132718Skan
1135169689Skan  /* XXX However, we must pass the right pre-processor defines to CPP
1136169689Skan     or GLD can get confused.  This is a hack.  */
1137169689Skan  if (TARGET_INTERWORK)
1138169689Skan    arm_cpp_interwork = 1;
1139169689Skan
1140169689Skan  if (arm_arch5)
1141169689Skan    target_flags &= ~MASK_INTERWORK;
1142169689Skan
1143169689Skan  if (target_abi_name)
1144132718Skan    {
1145169689Skan      for (i = 0; i < ARRAY_SIZE (arm_all_abis); i++)
1146169689Skan	{
1147169689Skan	  if (streq (arm_all_abis[i].name, target_abi_name))
1148169689Skan	    {
1149169689Skan	      arm_abi = arm_all_abis[i].abi_type;
1150169689Skan	      break;
1151169689Skan	    }
1152169689Skan	}
1153169689Skan      if (i == ARRAY_SIZE (arm_all_abis))
1154169689Skan	error ("invalid ABI option: -mabi=%s", target_abi_name);
1155169689Skan    }
1156169689Skan  else
1157169689Skan    arm_abi = ARM_DEFAULT_ABI;
1158132718Skan
1159169689Skan  if (TARGET_IWMMXT && !ARM_DOUBLEWORD_ALIGN)
1160169689Skan    error ("iwmmxt requires an AAPCS compatible ABI for proper operation");
1161169689Skan
1162169689Skan  if (TARGET_IWMMXT_ABI && !TARGET_IWMMXT)
1163169689Skan    error ("iwmmxt abi requires an iwmmxt capable cpu");
1164169689Skan
1165169689Skan  arm_fp_model = ARM_FP_MODEL_UNKNOWN;
1166169689Skan  if (target_fpu_name == NULL && target_fpe_name != NULL)
1167169689Skan    {
1168169689Skan      if (streq (target_fpe_name, "2"))
1169169689Skan	target_fpu_name = "fpe2";
1170169689Skan      else if (streq (target_fpe_name, "3"))
1171169689Skan	target_fpu_name = "fpe3";
1172169689Skan      else
1173169689Skan	error ("invalid floating point emulation option: -mfpe=%s",
1174169689Skan	       target_fpe_name);
1175132718Skan    }
1176169689Skan  if (target_fpu_name != NULL)
1177169689Skan    {
1178169689Skan      /* The user specified a FPU.  */
1179169689Skan      for (i = 0; i < ARRAY_SIZE (all_fpus); i++)
1180169689Skan	{
1181169689Skan	  if (streq (all_fpus[i].name, target_fpu_name))
1182169689Skan	    {
1183169689Skan	      arm_fpu_arch = all_fpus[i].fpu;
1184169689Skan	      arm_fpu_tune = arm_fpu_arch;
1185169689Skan	      arm_fp_model = fp_model_for_fpu[arm_fpu_arch];
1186169689Skan	      break;
1187169689Skan	    }
1188169689Skan	}
1189169689Skan      if (arm_fp_model == ARM_FP_MODEL_UNKNOWN)
1190169689Skan	error ("invalid floating point option: -mfpu=%s", target_fpu_name);
1191169689Skan    }
1192132718Skan  else
119390075Sobrien    {
1194169689Skan#ifdef FPUTYPE_DEFAULT
1195169689Skan      /* Use the default if it is specified for this platform.  */
1196169689Skan      arm_fpu_arch = FPUTYPE_DEFAULT;
1197169689Skan      arm_fpu_tune = FPUTYPE_DEFAULT;
1198169689Skan#else
1199169689Skan      /* Pick one based on CPU type.  */
1200169689Skan      /* ??? Some targets assume FPA is the default.
1201169689Skan      if ((insn_flags & FL_VFP) != 0)
1202169689Skan	arm_fpu_arch = FPUTYPE_VFP;
1203169689Skan      else
1204169689Skan      */
1205169689Skan      if (arm_arch_cirrus)
1206169689Skan	arm_fpu_arch = FPUTYPE_MAVERICK;
1207169689Skan      else
1208132718Skan	arm_fpu_arch = FPUTYPE_FPA_EMU2;
1209169689Skan#endif
1210169689Skan      if (tune_flags & FL_CO_PROC && arm_fpu_arch == FPUTYPE_FPA_EMU2)
1211169689Skan	arm_fpu_tune = FPUTYPE_FPA;
121290075Sobrien      else
1213169689Skan	arm_fpu_tune = arm_fpu_arch;
1214169689Skan      arm_fp_model = fp_model_for_fpu[arm_fpu_arch];
1215169689Skan      gcc_assert (arm_fp_model != ARM_FP_MODEL_UNKNOWN);
121690075Sobrien    }
1217169689Skan
1218169689Skan  if (target_float_abi_name != NULL)
1219132718Skan    {
1220169689Skan      /* The user specified a FP ABI.  */
1221169689Skan      for (i = 0; i < ARRAY_SIZE (all_float_abis); i++)
1222169689Skan	{
1223169689Skan	  if (streq (all_float_abis[i].name, target_float_abi_name))
1224169689Skan	    {
1225169689Skan	      arm_float_abi = all_float_abis[i].abi_type;
1226169689Skan	      break;
1227169689Skan	    }
1228169689Skan	}
1229169689Skan      if (i == ARRAY_SIZE (all_float_abis))
1230169689Skan	error ("invalid floating point abi: -mfloat-abi=%s",
1231169689Skan	       target_float_abi_name);
1232132718Skan    }
1233169689Skan  else
1234169689Skan    arm_float_abi = TARGET_DEFAULT_FLOAT_ABI;
1235169689Skan
1236169689Skan  if (arm_float_abi == ARM_FLOAT_ABI_HARD && TARGET_VFP)
1237169689Skan    sorry ("-mfloat-abi=hard and VFP");
1238169689Skan
1239169689Skan  /* FPA and iWMMXt are incompatible because the insn encodings overlap.
1240169689Skan     VFP and iWMMXt can theoretically coexist, but it's unlikely such silicon
1241169689Skan     will ever exist.  GCC makes no attempt to support this combination.  */
1242169689Skan  if (TARGET_IWMMXT && !TARGET_SOFT_FLOAT)
1243169689Skan    sorry ("iWMMXt and hardware floating point");
1244169689Skan
1245169689Skan  /* If soft-float is specified then don't use FPU.  */
1246169689Skan  if (TARGET_SOFT_FLOAT)
1247169689Skan    arm_fpu_arch = FPUTYPE_NONE;
1248169689Skan
124990075Sobrien  /* For arm2/3 there is no need to do any scheduling if there is only
125090075Sobrien     a floating point emulator, or we are doing software floating-point.  */
1251169689Skan  if ((TARGET_SOFT_FLOAT
1252169689Skan       || arm_fpu_tune == FPUTYPE_FPA_EMU2
1253169689Skan       || arm_fpu_tune == FPUTYPE_FPA_EMU3)
125490075Sobrien      && (tune_flags & FL_MODE32) == 0)
125590075Sobrien    flag_schedule_insns = flag_schedule_insns_after_reload = 0;
1256169689Skan
1257169689Skan  if (target_thread_switch)
1258169689Skan    {
1259169689Skan      if (strcmp (target_thread_switch, "soft") == 0)
1260169689Skan	target_thread_pointer = TP_SOFT;
1261169689Skan      else if (strcmp (target_thread_switch, "auto") == 0)
1262169689Skan	target_thread_pointer = TP_AUTO;
1263169689Skan      else if (strcmp (target_thread_switch, "cp15") == 0)
1264169689Skan	target_thread_pointer = TP_CP15;
1265169689Skan      else
1266169689Skan	error ("invalid thread pointer option: -mtp=%s", target_thread_switch);
1267169689Skan    }
1268169689Skan
1269169689Skan  /* Use the cp15 method if it is available.  */
1270169689Skan  if (target_thread_pointer == TP_AUTO)
1271169689Skan    {
1272169689Skan      if (arm_arch6k && !TARGET_THUMB)
1273169689Skan	target_thread_pointer = TP_CP15;
1274169689Skan      else
1275169689Skan	target_thread_pointer = TP_SOFT;
1276169689Skan    }
1277169689Skan
1278169689Skan  if (TARGET_HARD_TP && TARGET_THUMB)
1279169689Skan    error ("can not use -mtp=cp15 with -mthumb");
1280169689Skan
1281169689Skan  /* Override the default structure alignment for AAPCS ABI.  */
1282169689Skan  if (TARGET_AAPCS_BASED)
1283169689Skan    arm_structure_size_boundary = 8;
1284169689Skan
128590075Sobrien  if (structure_size_string != NULL)
128690075Sobrien    {
128790075Sobrien      int size = strtol (structure_size_string, NULL, 0);
1288169689Skan
1289169689Skan      if (size == 8 || size == 32
1290169689Skan	  || (ARM_DOUBLEWORD_ALIGN && size == 64))
129190075Sobrien	arm_structure_size_boundary = size;
129290075Sobrien      else
1293169689Skan	warning (0, "structure size boundary can only be set to %s",
1294169689Skan		 ARM_DOUBLEWORD_ALIGN ? "8, 32 or 64": "8 or 32");
129590075Sobrien    }
129690075Sobrien
129790075Sobrien  if (arm_pic_register_string != NULL)
129890075Sobrien    {
129996263Sobrien      int pic_register = decode_reg_name (arm_pic_register_string);
1300117395Skan
130190075Sobrien      if (!flag_pic)
1302169689Skan	warning (0, "-mpic-register= is useless without -fpic");
130390075Sobrien
130490075Sobrien      /* Prevent the user from choosing an obviously stupid PIC register.  */
130596263Sobrien      else if (pic_register < 0 || call_used_regs[pic_register]
130696263Sobrien	       || pic_register == HARD_FRAME_POINTER_REGNUM
130796263Sobrien	       || pic_register == STACK_POINTER_REGNUM
130896263Sobrien	       || pic_register >= PC_REGNUM)
130990075Sobrien	error ("unable to use '%s' for PIC register", arm_pic_register_string);
131090075Sobrien      else
131190075Sobrien	arm_pic_register = pic_register;
131290075Sobrien    }
131390075Sobrien
131490075Sobrien  if (TARGET_THUMB && flag_schedule_insns)
131590075Sobrien    {
131690075Sobrien      /* Don't warn since it's on by default in -O2.  */
131790075Sobrien      flag_schedule_insns = 0;
131890075Sobrien    }
131990075Sobrien
132090075Sobrien  if (optimize_size)
1321132718Skan    {
1322132718Skan      arm_constant_limit = 1;
132390075Sobrien
1324132718Skan      /* If optimizing for size, bump the number of instructions that we
1325132718Skan         are prepared to conditionally execute (even on a StrongARM).  */
1326132718Skan      max_insns_skipped = 6;
1327132718Skan    }
1328132718Skan  else
1329132718Skan    {
1330132718Skan      /* For processors with load scheduling, it never costs more than
1331132718Skan         2 cycles to load a constant, and the load scheduler may well
1332132718Skan	 reduce that to 1.  */
1333169689Skan      if (arm_ld_sched)
1334132718Skan        arm_constant_limit = 1;
1335132718Skan
1336132718Skan      /* On XScale the longer latency of a load makes it more difficult
1337132718Skan         to achieve a good schedule, so it's faster to synthesize
1338132718Skan	 constants that can be done in two insns.  */
1339132718Skan      if (arm_tune_xscale)
1340132718Skan        arm_constant_limit = 2;
1341132718Skan
1342132718Skan      /* StrongARM has early execution of branches, so a sequence
1343132718Skan         that is worth skipping is shorter.  */
1344169689Skan      if (arm_tune_strongarm)
1345132718Skan        max_insns_skipped = 3;
1346132718Skan    }
1347132718Skan
134890075Sobrien  /* Register global variables with the garbage collector.  */
134990075Sobrien  arm_add_gc_roots ();
135090075Sobrien}
135190075Sobrien
135290075Sobrienstatic void
1353132718Skanarm_add_gc_roots (void)
135490075Sobrien{
135590075Sobrien  gcc_obstack_init(&minipool_obstack);
135690075Sobrien  minipool_startobj = (char *) obstack_alloc (&minipool_obstack, 0);
135790075Sobrien}
135890075Sobrien
135990075Sobrien/* A table of known ARM exception types.
136090075Sobrien   For use with the interrupt function attribute.  */
136190075Sobrien
136290075Sobrientypedef struct
136390075Sobrien{
136490075Sobrien  const char *const arg;
136590075Sobrien  const unsigned long return_value;
136690075Sobrien}
136790075Sobrienisr_attribute_arg;
136890075Sobrien
136990075Sobrienstatic const isr_attribute_arg isr_attribute_args [] =
137090075Sobrien{
137190075Sobrien  { "IRQ",   ARM_FT_ISR },
137290075Sobrien  { "irq",   ARM_FT_ISR },
137390075Sobrien  { "FIQ",   ARM_FT_FIQ },
137490075Sobrien  { "fiq",   ARM_FT_FIQ },
137590075Sobrien  { "ABORT", ARM_FT_ISR },
137690075Sobrien  { "abort", ARM_FT_ISR },
137790075Sobrien  { "ABORT", ARM_FT_ISR },
137890075Sobrien  { "abort", ARM_FT_ISR },
137990075Sobrien  { "UNDEF", ARM_FT_EXCEPTION },
138090075Sobrien  { "undef", ARM_FT_EXCEPTION },
138190075Sobrien  { "SWI",   ARM_FT_EXCEPTION },
138290075Sobrien  { "swi",   ARM_FT_EXCEPTION },
138390075Sobrien  { NULL,    ARM_FT_NORMAL }
138490075Sobrien};
138590075Sobrien
138690075Sobrien/* Returns the (interrupt) function type of the current
138790075Sobrien   function, or ARM_FT_UNKNOWN if the type cannot be determined.  */
138890075Sobrien
138990075Sobrienstatic unsigned long
1390132718Skanarm_isr_value (tree argument)
139190075Sobrien{
139290075Sobrien  const isr_attribute_arg * ptr;
139390075Sobrien  const char *              arg;
139490075Sobrien
139590075Sobrien  /* No argument - default to IRQ.  */
139690075Sobrien  if (argument == NULL_TREE)
139790075Sobrien    return ARM_FT_ISR;
139890075Sobrien
139990075Sobrien  /* Get the value of the argument.  */
140090075Sobrien  if (TREE_VALUE (argument) == NULL_TREE
140190075Sobrien      || TREE_CODE (TREE_VALUE (argument)) != STRING_CST)
140290075Sobrien    return ARM_FT_UNKNOWN;
140390075Sobrien
140490075Sobrien  arg = TREE_STRING_POINTER (TREE_VALUE (argument));
140590075Sobrien
140690075Sobrien  /* Check it against the list of known arguments.  */
1407132718Skan  for (ptr = isr_attribute_args; ptr->arg != NULL; ptr++)
140890075Sobrien    if (streq (arg, ptr->arg))
140990075Sobrien      return ptr->return_value;
141090075Sobrien
1411117395Skan  /* An unrecognized interrupt type.  */
141290075Sobrien  return ARM_FT_UNKNOWN;
141390075Sobrien}
141490075Sobrien
141590075Sobrien/* Computes the type of the current function.  */
141690075Sobrien
141790075Sobrienstatic unsigned long
1418132718Skanarm_compute_func_type (void)
141990075Sobrien{
142090075Sobrien  unsigned long type = ARM_FT_UNKNOWN;
142190075Sobrien  tree a;
142290075Sobrien  tree attr;
142390075Sobrien
1424169689Skan  gcc_assert (TREE_CODE (current_function_decl) == FUNCTION_DECL);
1425169689Skan
142690075Sobrien  /* Decide if the current function is volatile.  Such functions
142790075Sobrien     never return, and many memory cycles can be saved by not storing
142890075Sobrien     register values that will never be needed again.  This optimization
142990075Sobrien     was added to speed up context switching in a kernel application.  */
143090075Sobrien  if (optimize > 0
1431169689Skan      && (TREE_NOTHROW (current_function_decl)
1432169689Skan          || !(flag_unwind_tables
1433169689Skan               || (flag_exceptions && !USING_SJLJ_EXCEPTIONS)))
143490075Sobrien      && TREE_THIS_VOLATILE (current_function_decl))
143590075Sobrien    type |= ARM_FT_VOLATILE;
1436169689Skan
1437169689Skan  if (cfun->static_chain_decl != NULL)
143890075Sobrien    type |= ARM_FT_NESTED;
143990075Sobrien
144090075Sobrien  attr = DECL_ATTRIBUTES (current_function_decl);
1441169689Skan
144290075Sobrien  a = lookup_attribute ("naked", attr);
144390075Sobrien  if (a != NULL_TREE)
144490075Sobrien    type |= ARM_FT_NAKED;
144590075Sobrien
1446169689Skan  a = lookup_attribute ("isr", attr);
1447169689Skan  if (a == NULL_TREE)
1448169689Skan    a = lookup_attribute ("interrupt", attr);
1449169689Skan
1450169689Skan  if (a == NULL_TREE)
1451169689Skan    type |= TARGET_INTERWORK ? ARM_FT_INTERWORKED : ARM_FT_NORMAL;
145290075Sobrien  else
1453169689Skan    type |= arm_isr_value (TREE_VALUE (a));
1454169689Skan
145590075Sobrien  return type;
145690075Sobrien}
145790075Sobrien
145890075Sobrien/* Returns the type of the current function.  */
145990075Sobrien
146090075Sobrienunsigned long
1461132718Skanarm_current_func_type (void)
146290075Sobrien{
146390075Sobrien  if (ARM_FUNC_TYPE (cfun->machine->func_type) == ARM_FT_UNKNOWN)
146490075Sobrien    cfun->machine->func_type = arm_compute_func_type ();
146590075Sobrien
146690075Sobrien  return cfun->machine->func_type;
146790075Sobrien}
146890075Sobrien
1469169689Skan/* Return 1 if it is possible to return using a single instruction.
1470132718Skan   If SIBLING is non-null, this is a test for a return before a sibling
1471132718Skan   call.  SIBLING is the call insn, so we can examine its register usage.  */
147290075Sobrien
147390075Sobrienint
1474132718Skanuse_return_insn (int iscond, rtx sibling)
147590075Sobrien{
147690075Sobrien  int regno;
147790075Sobrien  unsigned int func_type;
1478107590Sobrien  unsigned long saved_int_regs;
1479132718Skan  unsigned HOST_WIDE_INT stack_adjust;
1480169689Skan  arm_stack_offsets *offsets;
148190075Sobrien
148290075Sobrien  /* Never use a return instruction before reload has run.  */
148390075Sobrien  if (!reload_completed)
148490075Sobrien    return 0;
1485132718Skan
148690075Sobrien  func_type = arm_current_func_type ();
148790075Sobrien
148896263Sobrien  /* Naked functions and volatile functions need special
148996263Sobrien     consideration.  */
149096263Sobrien  if (func_type & (ARM_FT_VOLATILE | ARM_FT_NAKED))
149190075Sobrien    return 0;
1492117395Skan
1493117395Skan  /* So do interrupt functions that use the frame pointer.  */
1494117395Skan  if (IS_INTERRUPT (func_type) && frame_pointer_needed)
1495117395Skan    return 0;
1496132718Skan
1497169689Skan  offsets = arm_get_frame_offsets ();
1498169689Skan  stack_adjust = offsets->outgoing_args - offsets->saved_regs;
1499132718Skan
150090075Sobrien  /* As do variadic functions.  */
150190075Sobrien  if (current_function_pretend_args_size
150296263Sobrien      || cfun->machine->uses_anonymous_args
1503132718Skan      /* Or if the function calls __builtin_eh_return () */
1504169689Skan      || current_function_calls_eh_return
1505132718Skan      /* Or if the function calls alloca */
1506132718Skan      || current_function_calls_alloca
1507132718Skan      /* Or if there is a stack adjustment.  However, if the stack pointer
1508132718Skan	 is saved on the stack, we can use a pre-incrementing stack load.  */
1509132718Skan      || !(stack_adjust == 0 || (frame_pointer_needed && stack_adjust == 4)))
151090075Sobrien    return 0;
151190075Sobrien
1512107590Sobrien  saved_int_regs = arm_compute_save_reg_mask ();
1513107590Sobrien
1514132718Skan  /* Unfortunately, the insn
1515132718Skan
1516132718Skan       ldmib sp, {..., sp, ...}
1517132718Skan
1518132718Skan     triggers a bug on most SA-110 based devices, such that the stack
1519132718Skan     pointer won't be correctly restored if the instruction takes a
1520132718Skan     page fault.  We work around this problem by popping r3 along with
1521132718Skan     the other registers, since that is never slower than executing
1522169689Skan     another instruction.
1523132718Skan
1524132718Skan     We test for !arm_arch5 here, because code for any architecture
1525132718Skan     less than this could potentially be run on one of the buggy
1526132718Skan     chips.  */
1527132718Skan  if (stack_adjust == 4 && !arm_arch5)
1528132718Skan    {
1529132718Skan      /* Validate that r3 is a call-clobbered register (always true in
1530132718Skan	 the default abi) ...  */
1531132718Skan      if (!call_used_regs[3])
1532132718Skan	return 0;
1533132718Skan
1534169689Skan      /* ... that it isn't being used for a return value ... */
1535169689Skan      if (arm_size_return_regs () >= (4 * UNITS_PER_WORD))
1536169689Skan	return 0;
1537169689Skan
1538169689Skan      /* ... or for a tail-call argument ...  */
1539132718Skan      if (sibling)
1540132718Skan	{
1541169689Skan	  gcc_assert (GET_CODE (sibling) == CALL_INSN);
1542132718Skan
1543132718Skan	  if (find_regno_fusage (sibling, USE, 3))
1544132718Skan	    return 0;
1545132718Skan	}
1546132718Skan
1547132718Skan      /* ... and that there are no call-saved registers in r0-r2
1548132718Skan	 (always true in the default ABI).  */
1549132718Skan      if (saved_int_regs & 0x7)
1550132718Skan	return 0;
1551132718Skan    }
1552132718Skan
155390075Sobrien  /* Can't be done if interworking with Thumb, and any registers have been
1554107590Sobrien     stacked.  */
1555107590Sobrien  if (TARGET_INTERWORK && saved_int_regs != 0)
155690075Sobrien    return 0;
1557107590Sobrien
1558107590Sobrien  /* On StrongARM, conditional returns are expensive if they aren't
1559107590Sobrien     taken and multiple registers have been stacked.  */
1560169689Skan  if (iscond && arm_tune_strongarm)
156190075Sobrien    {
1562169689Skan      /* Conditional return when just the LR is stored is a simple
1563107590Sobrien	 conditional-load instruction, that's not expensive.  */
1564107590Sobrien      if (saved_int_regs != 0 && saved_int_regs != (1 << LR_REGNUM))
1565107590Sobrien	return 0;
156690075Sobrien
1567169689Skan      if (flag_pic
1568169689Skan	  && arm_pic_register != INVALID_REGNUM
1569169689Skan	  && regs_ever_live[PIC_OFFSET_TABLE_REGNUM])
157090075Sobrien	return 0;
157190075Sobrien    }
1572107590Sobrien
1573107590Sobrien  /* If there are saved registers but the LR isn't saved, then we need
1574107590Sobrien     two instructions for the return.  */
1575107590Sobrien  if (saved_int_regs && !(saved_int_regs & (1 << LR_REGNUM)))
1576107590Sobrien    return 0;
1577107590Sobrien
1578132718Skan  /* Can't be done if any of the FPA regs are pushed,
157990075Sobrien     since this also requires an insn.  */
1580169689Skan  if (TARGET_HARD_FLOAT && TARGET_FPA)
1581169689Skan    for (regno = FIRST_FPA_REGNUM; regno <= LAST_FPA_REGNUM; regno++)
158290075Sobrien      if (regs_ever_live[regno] && !call_used_regs[regno])
158390075Sobrien	return 0;
158490075Sobrien
1585169689Skan  /* Likewise VFP regs.  */
1586169689Skan  if (TARGET_HARD_FLOAT && TARGET_VFP)
1587169689Skan    for (regno = FIRST_VFP_REGNUM; regno <= LAST_VFP_REGNUM; regno++)
1588169689Skan      if (regs_ever_live[regno] && !call_used_regs[regno])
1589169689Skan	return 0;
1590169689Skan
1591132718Skan  if (TARGET_REALLY_IWMMXT)
1592132718Skan    for (regno = FIRST_IWMMXT_REGNUM; regno <= LAST_IWMMXT_REGNUM; regno++)
1593132718Skan      if (regs_ever_live[regno] && ! call_used_regs [regno])
1594132718Skan	return 0;
1595132718Skan
159690075Sobrien  return 1;
159790075Sobrien}
159890075Sobrien
159990075Sobrien/* Return TRUE if int I is a valid immediate ARM constant.  */
160090075Sobrien
160190075Sobrienint
1602132718Skanconst_ok_for_arm (HOST_WIDE_INT i)
160390075Sobrien{
1604169689Skan  int lowbit;
160590075Sobrien
1606169689Skan  /* For machines with >32 bit HOST_WIDE_INT, the bits above bit 31 must
160790075Sobrien     be all zero, or all one.  */
160890075Sobrien  if ((i & ~(unsigned HOST_WIDE_INT) 0xffffffff) != 0
160990075Sobrien      && ((i & ~(unsigned HOST_WIDE_INT) 0xffffffff)
161090075Sobrien	  != ((~(unsigned HOST_WIDE_INT) 0)
161190075Sobrien	      & ~(unsigned HOST_WIDE_INT) 0xffffffff)))
161290075Sobrien    return FALSE;
1613169689Skan
1614169689Skan  i &= (unsigned HOST_WIDE_INT) 0xffffffff;
1615169689Skan
1616169689Skan  /* Fast return for 0 and small values.  We must do this for zero, since
1617169689Skan     the code below can't handle that one case.  */
1618169689Skan  if ((i & ~(unsigned HOST_WIDE_INT) 0xff) == 0)
161990075Sobrien    return TRUE;
162090075Sobrien
1621169689Skan  /* Get the number of trailing zeros, rounded down to the nearest even
1622169689Skan     number.  */
1623169689Skan  lowbit = (ffs ((int) i) - 1) & ~1;
162490075Sobrien
1625169689Skan  if ((i & ~(((unsigned HOST_WIDE_INT) 0xff) << lowbit)) == 0)
1626169689Skan    return TRUE;
1627169689Skan  else if (lowbit <= 4
1628169689Skan	   && ((i & ~0xc000003f) == 0
1629169689Skan	       || (i & ~0xf000000f) == 0
1630169689Skan	       || (i & ~0xfc000003) == 0))
1631169689Skan    return TRUE;
1632169689Skan
163390075Sobrien  return FALSE;
163490075Sobrien}
163590075Sobrien
163690075Sobrien/* Return true if I is a valid constant for the operation CODE.  */
163790075Sobrienstatic int
1638132718Skanconst_ok_for_op (HOST_WIDE_INT i, enum rtx_code code)
163990075Sobrien{
164090075Sobrien  if (const_ok_for_arm (i))
164190075Sobrien    return 1;
164290075Sobrien
164390075Sobrien  switch (code)
164490075Sobrien    {
164590075Sobrien    case PLUS:
164690075Sobrien      return const_ok_for_arm (ARM_SIGN_EXTEND (-i));
164790075Sobrien
164890075Sobrien    case MINUS:		/* Should only occur with (MINUS I reg) => rsb */
164990075Sobrien    case XOR:
165090075Sobrien    case IOR:
165190075Sobrien      return 0;
165290075Sobrien
165390075Sobrien    case AND:
165490075Sobrien      return const_ok_for_arm (ARM_SIGN_EXTEND (~i));
165590075Sobrien
165690075Sobrien    default:
1657169689Skan      gcc_unreachable ();
165890075Sobrien    }
165990075Sobrien}
166090075Sobrien
166190075Sobrien/* Emit a sequence of insns to handle a large constant.
166290075Sobrien   CODE is the code of the operation required, it can be any of SET, PLUS,
166390075Sobrien   IOR, AND, XOR, MINUS;
166490075Sobrien   MODE is the mode in which the operation is being performed;
166590075Sobrien   VAL is the integer to operate on;
166690075Sobrien   SOURCE is the other operand (a register, or a null-pointer for SET);
166790075Sobrien   SUBTARGETS means it is safe to create scratch registers if that will
166890075Sobrien   either produce a simpler sequence, or we will want to cse the values.
166990075Sobrien   Return value is the number of insns emitted.  */
167090075Sobrien
167190075Sobrienint
1672169689Skanarm_split_constant (enum rtx_code code, enum machine_mode mode, rtx insn,
1673132718Skan		    HOST_WIDE_INT val, rtx target, rtx source, int subtargets)
167490075Sobrien{
1675169689Skan  rtx cond;
1676169689Skan
1677169689Skan  if (insn && GET_CODE (PATTERN (insn)) == COND_EXEC)
1678169689Skan    cond = COND_EXEC_TEST (PATTERN (insn));
1679169689Skan  else
1680169689Skan    cond = NULL_RTX;
1681169689Skan
168290075Sobrien  if (subtargets || code == SET
168390075Sobrien      || (GET_CODE (target) == REG && GET_CODE (source) == REG
168490075Sobrien	  && REGNO (target) != REGNO (source)))
168590075Sobrien    {
168690075Sobrien      /* After arm_reorg has been called, we can't fix up expensive
1687117395Skan	 constants by pushing them into memory so we must synthesize
168890075Sobrien	 them in-line, regardless of the cost.  This is only likely to
168990075Sobrien	 be more costly on chips that have load delay slots and we are
169090075Sobrien	 compiling without running the scheduler (so no splitting
169190075Sobrien	 occurred before the final instruction emission).
169290075Sobrien
169390075Sobrien	 Ref: gcc -O1 -mcpu=strongarm gcc.c-torture/compile/980506-2.c
169490075Sobrien      */
169590075Sobrien      if (!after_arm_reorg
1696169689Skan	  && !cond
1697169689Skan	  && (arm_gen_constant (code, mode, NULL_RTX, val, target, source,
1698169689Skan				1, 0)
169990075Sobrien	      > arm_constant_limit + (code != SET)))
170090075Sobrien	{
170190075Sobrien	  if (code == SET)
170290075Sobrien	    {
170390075Sobrien	      /* Currently SET is the only monadic value for CODE, all
170490075Sobrien		 the rest are diadic.  */
1705169689Skan	      emit_set_insn (target, GEN_INT (val));
170690075Sobrien	      return 1;
170790075Sobrien	    }
170890075Sobrien	  else
170990075Sobrien	    {
171090075Sobrien	      rtx temp = subtargets ? gen_reg_rtx (mode) : target;
171190075Sobrien
1712169689Skan	      emit_set_insn (temp, GEN_INT (val));
171390075Sobrien	      /* For MINUS, the value is subtracted from, since we never
171490075Sobrien		 have subtraction of a constant.  */
171590075Sobrien	      if (code == MINUS)
1716169689Skan		emit_set_insn (target, gen_rtx_MINUS (mode, temp, source));
171790075Sobrien	      else
1718169689Skan		emit_set_insn (target,
1719169689Skan			       gen_rtx_fmt_ee (code, mode, source, temp));
172090075Sobrien	      return 2;
172190075Sobrien	    }
172290075Sobrien	}
172390075Sobrien    }
172490075Sobrien
1725169689Skan  return arm_gen_constant (code, mode, cond, val, target, source, subtargets,
1726169689Skan			   1);
172790075Sobrien}
172890075Sobrien
172990075Sobrienstatic int
1730132718Skancount_insns_for_constant (HOST_WIDE_INT remainder, int i)
173190075Sobrien{
173290075Sobrien  HOST_WIDE_INT temp1;
173390075Sobrien  int num_insns = 0;
173490075Sobrien  do
173590075Sobrien    {
173690075Sobrien      int end;
1737169689Skan
173890075Sobrien      if (i <= 0)
173990075Sobrien	i += 32;
174090075Sobrien      if (remainder & (3 << (i - 2)))
174190075Sobrien	{
174290075Sobrien	  end = i - 8;
174390075Sobrien	  if (end < 0)
174490075Sobrien	    end += 32;
174590075Sobrien	  temp1 = remainder & ((0x0ff << end)
174690075Sobrien				    | ((i < end) ? (0xff >> (32 - end)) : 0));
174790075Sobrien	  remainder &= ~temp1;
174890075Sobrien	  num_insns++;
174990075Sobrien	  i -= 6;
175090075Sobrien	}
175190075Sobrien      i -= 2;
175290075Sobrien    } while (remainder);
175390075Sobrien  return num_insns;
175490075Sobrien}
175590075Sobrien
1756169689Skan/* Emit an instruction with the indicated PATTERN.  If COND is
1757169689Skan   non-NULL, conditionalize the execution of the instruction on COND
1758169689Skan   being true.  */
1759169689Skan
1760169689Skanstatic void
1761169689Skanemit_constant_insn (rtx cond, rtx pattern)
1762169689Skan{
1763169689Skan  if (cond)
1764169689Skan    pattern = gen_rtx_COND_EXEC (VOIDmode, copy_rtx (cond), pattern);
1765169689Skan  emit_insn (pattern);
1766169689Skan}
1767169689Skan
176890075Sobrien/* As above, but extra parameter GENERATE which, if clear, suppresses
176990075Sobrien   RTL generation.  */
177090075Sobrien
177190075Sobrienstatic int
1772169689Skanarm_gen_constant (enum rtx_code code, enum machine_mode mode, rtx cond,
1773132718Skan		  HOST_WIDE_INT val, rtx target, rtx source, int subtargets,
1774132718Skan		  int generate)
177590075Sobrien{
177690075Sobrien  int can_invert = 0;
177790075Sobrien  int can_negate = 0;
177890075Sobrien  int can_negate_initial = 0;
177990075Sobrien  int can_shift = 0;
178090075Sobrien  int i;
178190075Sobrien  int num_bits_set = 0;
178290075Sobrien  int set_sign_bit_copies = 0;
178390075Sobrien  int clear_sign_bit_copies = 0;
178490075Sobrien  int clear_zero_bit_copies = 0;
178590075Sobrien  int set_zero_bit_copies = 0;
178690075Sobrien  int insns = 0;
178790075Sobrien  unsigned HOST_WIDE_INT temp1, temp2;
178890075Sobrien  unsigned HOST_WIDE_INT remainder = val & 0xffffffff;
178990075Sobrien
179090075Sobrien  /* Find out which operations are safe for a given CODE.  Also do a quick
179190075Sobrien     check for degenerate cases; these can occur when DImode operations
179290075Sobrien     are split.  */
179390075Sobrien  switch (code)
179490075Sobrien    {
179590075Sobrien    case SET:
179690075Sobrien      can_invert = 1;
179790075Sobrien      can_shift = 1;
179890075Sobrien      can_negate = 1;
179990075Sobrien      break;
180090075Sobrien
180190075Sobrien    case PLUS:
180290075Sobrien      can_negate = 1;
180390075Sobrien      can_negate_initial = 1;
180490075Sobrien      break;
180590075Sobrien
180690075Sobrien    case IOR:
180790075Sobrien      if (remainder == 0xffffffff)
180890075Sobrien	{
180990075Sobrien	  if (generate)
1810169689Skan	    emit_constant_insn (cond,
1811169689Skan				gen_rtx_SET (VOIDmode, target,
1812169689Skan					     GEN_INT (ARM_SIGN_EXTEND (val))));
181390075Sobrien	  return 1;
181490075Sobrien	}
181590075Sobrien      if (remainder == 0)
181690075Sobrien	{
181790075Sobrien	  if (reload_completed && rtx_equal_p (target, source))
181890075Sobrien	    return 0;
181990075Sobrien	  if (generate)
1820169689Skan	    emit_constant_insn (cond,
1821169689Skan				gen_rtx_SET (VOIDmode, target, source));
182290075Sobrien	  return 1;
182390075Sobrien	}
182490075Sobrien      break;
182590075Sobrien
182690075Sobrien    case AND:
182790075Sobrien      if (remainder == 0)
182890075Sobrien	{
182990075Sobrien	  if (generate)
1830169689Skan	    emit_constant_insn (cond,
1831169689Skan				gen_rtx_SET (VOIDmode, target, const0_rtx));
183290075Sobrien	  return 1;
183390075Sobrien	}
183490075Sobrien      if (remainder == 0xffffffff)
183590075Sobrien	{
183690075Sobrien	  if (reload_completed && rtx_equal_p (target, source))
183790075Sobrien	    return 0;
183890075Sobrien	  if (generate)
1839169689Skan	    emit_constant_insn (cond,
1840169689Skan				gen_rtx_SET (VOIDmode, target, source));
184190075Sobrien	  return 1;
184290075Sobrien	}
184390075Sobrien      can_invert = 1;
184490075Sobrien      break;
184590075Sobrien
184690075Sobrien    case XOR:
184790075Sobrien      if (remainder == 0)
184890075Sobrien	{
184990075Sobrien	  if (reload_completed && rtx_equal_p (target, source))
185090075Sobrien	    return 0;
185190075Sobrien	  if (generate)
1852169689Skan	    emit_constant_insn (cond,
1853169689Skan				gen_rtx_SET (VOIDmode, target, source));
185490075Sobrien	  return 1;
185590075Sobrien	}
185690075Sobrien
1857169689Skan      /* We don't know how to handle other cases yet.  */
1858169689Skan      gcc_assert (remainder == 0xffffffff);
185990075Sobrien
1860169689Skan      if (generate)
1861169689Skan	emit_constant_insn (cond,
1862169689Skan			    gen_rtx_SET (VOIDmode, target,
1863169689Skan					 gen_rtx_NOT (mode, source)));
1864169689Skan      return 1;
1865169689Skan
186690075Sobrien    case MINUS:
186790075Sobrien      /* We treat MINUS as (val - source), since (source - val) is always
186890075Sobrien	 passed as (source + (-val)).  */
186990075Sobrien      if (remainder == 0)
187090075Sobrien	{
187190075Sobrien	  if (generate)
1872169689Skan	    emit_constant_insn (cond,
1873169689Skan				gen_rtx_SET (VOIDmode, target,
1874169689Skan					     gen_rtx_NEG (mode, source)));
187590075Sobrien	  return 1;
187690075Sobrien	}
187790075Sobrien      if (const_ok_for_arm (val))
187890075Sobrien	{
187990075Sobrien	  if (generate)
1880169689Skan	    emit_constant_insn (cond,
1881169689Skan				gen_rtx_SET (VOIDmode, target,
1882169689Skan					     gen_rtx_MINUS (mode, GEN_INT (val),
1883169689Skan							    source)));
188490075Sobrien	  return 1;
188590075Sobrien	}
188690075Sobrien      can_negate = 1;
188790075Sobrien
188890075Sobrien      break;
188990075Sobrien
189090075Sobrien    default:
1891169689Skan      gcc_unreachable ();
189290075Sobrien    }
189390075Sobrien
189490075Sobrien  /* If we can do it in one insn get out quickly.  */
189590075Sobrien  if (const_ok_for_arm (val)
189690075Sobrien      || (can_negate_initial && const_ok_for_arm (-val))
189790075Sobrien      || (can_invert && const_ok_for_arm (~val)))
189890075Sobrien    {
189990075Sobrien      if (generate)
1900169689Skan	emit_constant_insn (cond,
1901169689Skan			    gen_rtx_SET (VOIDmode, target,
1902169689Skan					 (source
1903169689Skan					  ? gen_rtx_fmt_ee (code, mode, source,
1904169689Skan							    GEN_INT (val))
1905169689Skan					  : GEN_INT (val))));
190690075Sobrien      return 1;
190790075Sobrien    }
190890075Sobrien
190990075Sobrien  /* Calculate a few attributes that may be useful for specific
191090075Sobrien     optimizations.  */
191190075Sobrien  for (i = 31; i >= 0; i--)
191290075Sobrien    {
191390075Sobrien      if ((remainder & (1 << i)) == 0)
191490075Sobrien	clear_sign_bit_copies++;
191590075Sobrien      else
191690075Sobrien	break;
191790075Sobrien    }
191890075Sobrien
191990075Sobrien  for (i = 31; i >= 0; i--)
192090075Sobrien    {
192190075Sobrien      if ((remainder & (1 << i)) != 0)
192290075Sobrien	set_sign_bit_copies++;
192390075Sobrien      else
192490075Sobrien	break;
192590075Sobrien    }
192690075Sobrien
192790075Sobrien  for (i = 0; i <= 31; i++)
192890075Sobrien    {
192990075Sobrien      if ((remainder & (1 << i)) == 0)
193090075Sobrien	clear_zero_bit_copies++;
193190075Sobrien      else
193290075Sobrien	break;
193390075Sobrien    }
193490075Sobrien
193590075Sobrien  for (i = 0; i <= 31; i++)
193690075Sobrien    {
193790075Sobrien      if ((remainder & (1 << i)) != 0)
193890075Sobrien	set_zero_bit_copies++;
193990075Sobrien      else
194090075Sobrien	break;
194190075Sobrien    }
194290075Sobrien
194390075Sobrien  switch (code)
194490075Sobrien    {
194590075Sobrien    case SET:
194690075Sobrien      /* See if we can do this by sign_extending a constant that is known
194790075Sobrien	 to be negative.  This is a good, way of doing it, since the shift
194890075Sobrien	 may well merge into a subsequent insn.  */
194990075Sobrien      if (set_sign_bit_copies > 1)
195090075Sobrien	{
195190075Sobrien	  if (const_ok_for_arm
1952169689Skan	      (temp1 = ARM_SIGN_EXTEND (remainder
195390075Sobrien					<< (set_sign_bit_copies - 1))))
195490075Sobrien	    {
195590075Sobrien	      if (generate)
195690075Sobrien		{
195790075Sobrien		  rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
1958169689Skan		  emit_constant_insn (cond,
1959169689Skan				      gen_rtx_SET (VOIDmode, new_src,
1960169689Skan						   GEN_INT (temp1)));
1961169689Skan		  emit_constant_insn (cond,
1962169689Skan				      gen_ashrsi3 (target, new_src,
1963169689Skan						   GEN_INT (set_sign_bit_copies - 1)));
196490075Sobrien		}
196590075Sobrien	      return 2;
196690075Sobrien	    }
196790075Sobrien	  /* For an inverted constant, we will need to set the low bits,
196890075Sobrien	     these will be shifted out of harm's way.  */
196990075Sobrien	  temp1 |= (1 << (set_sign_bit_copies - 1)) - 1;
197090075Sobrien	  if (const_ok_for_arm (~temp1))
197190075Sobrien	    {
197290075Sobrien	      if (generate)
197390075Sobrien		{
197490075Sobrien		  rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
1975169689Skan		  emit_constant_insn (cond,
1976169689Skan				      gen_rtx_SET (VOIDmode, new_src,
1977169689Skan						   GEN_INT (temp1)));
1978169689Skan		  emit_constant_insn (cond,
1979169689Skan				      gen_ashrsi3 (target, new_src,
1980169689Skan						   GEN_INT (set_sign_bit_copies - 1)));
198190075Sobrien		}
198290075Sobrien	      return 2;
198390075Sobrien	    }
198490075Sobrien	}
198590075Sobrien
1986169689Skan      /* See if we can calculate the value as the difference between two
1987169689Skan	 valid immediates.  */
1988169689Skan      if (clear_sign_bit_copies + clear_zero_bit_copies <= 16)
1989169689Skan	{
1990169689Skan	  int topshift = clear_sign_bit_copies & ~1;
1991169689Skan
1992169689Skan	  temp1 = ARM_SIGN_EXTEND ((remainder + (0x00800000 >> topshift))
1993169689Skan				   & (0xff000000 >> topshift));
1994169689Skan
1995169689Skan	  /* If temp1 is zero, then that means the 9 most significant
1996169689Skan	     bits of remainder were 1 and we've caused it to overflow.
1997169689Skan	     When topshift is 0 we don't need to do anything since we
1998169689Skan	     can borrow from 'bit 32'.  */
1999169689Skan	  if (temp1 == 0 && topshift != 0)
2000169689Skan	    temp1 = 0x80000000 >> (topshift - 1);
2001169689Skan
2002169689Skan	  temp2 = ARM_SIGN_EXTEND (temp1 - remainder);
2003169689Skan
2004169689Skan	  if (const_ok_for_arm (temp2))
2005169689Skan	    {
2006169689Skan	      if (generate)
2007169689Skan		{
2008169689Skan		  rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
2009169689Skan		  emit_constant_insn (cond,
2010169689Skan				      gen_rtx_SET (VOIDmode, new_src,
2011169689Skan						   GEN_INT (temp1)));
2012169689Skan		  emit_constant_insn (cond,
2013169689Skan				      gen_addsi3 (target, new_src,
2014169689Skan						  GEN_INT (-temp2)));
2015169689Skan		}
2016169689Skan
2017169689Skan	      return 2;
2018169689Skan	    }
2019169689Skan	}
2020169689Skan
202190075Sobrien      /* See if we can generate this by setting the bottom (or the top)
202290075Sobrien	 16 bits, and then shifting these into the other half of the
202390075Sobrien	 word.  We only look for the simplest cases, to do more would cost
202490075Sobrien	 too much.  Be careful, however, not to generate this when the
202590075Sobrien	 alternative would take fewer insns.  */
202690075Sobrien      if (val & 0xffff0000)
202790075Sobrien	{
202890075Sobrien	  temp1 = remainder & 0xffff0000;
202990075Sobrien	  temp2 = remainder & 0x0000ffff;
203090075Sobrien
203190075Sobrien	  /* Overlaps outside this range are best done using other methods.  */
203290075Sobrien	  for (i = 9; i < 24; i++)
203390075Sobrien	    {
203490075Sobrien	      if ((((temp2 | (temp2 << i)) & 0xffffffff) == remainder)
203590075Sobrien		  && !const_ok_for_arm (temp2))
203690075Sobrien		{
203790075Sobrien		  rtx new_src = (subtargets
203890075Sobrien				 ? (generate ? gen_reg_rtx (mode) : NULL_RTX)
203990075Sobrien				 : target);
2040169689Skan		  insns = arm_gen_constant (code, mode, cond, temp2, new_src,
204190075Sobrien					    source, subtargets, generate);
204290075Sobrien		  source = new_src;
204390075Sobrien		  if (generate)
2044169689Skan		    emit_constant_insn
2045169689Skan		      (cond,
2046169689Skan		       gen_rtx_SET
2047169689Skan		       (VOIDmode, target,
2048169689Skan			gen_rtx_IOR (mode,
2049169689Skan				     gen_rtx_ASHIFT (mode, source,
2050169689Skan						     GEN_INT (i)),
2051169689Skan				     source)));
205290075Sobrien		  return insns + 1;
205390075Sobrien		}
205490075Sobrien	    }
205590075Sobrien
205690075Sobrien	  /* Don't duplicate cases already considered.  */
205790075Sobrien	  for (i = 17; i < 24; i++)
205890075Sobrien	    {
205990075Sobrien	      if (((temp1 | (temp1 >> i)) == remainder)
206090075Sobrien		  && !const_ok_for_arm (temp1))
206190075Sobrien		{
206290075Sobrien		  rtx new_src = (subtargets
206390075Sobrien				 ? (generate ? gen_reg_rtx (mode) : NULL_RTX)
206490075Sobrien				 : target);
2065169689Skan		  insns = arm_gen_constant (code, mode, cond, temp1, new_src,
206690075Sobrien					    source, subtargets, generate);
206790075Sobrien		  source = new_src;
206890075Sobrien		  if (generate)
2069169689Skan		    emit_constant_insn
2070169689Skan		      (cond,
2071169689Skan		       gen_rtx_SET (VOIDmode, target,
207290075Sobrien				    gen_rtx_IOR
207390075Sobrien				    (mode,
207490075Sobrien				     gen_rtx_LSHIFTRT (mode, source,
207590075Sobrien						       GEN_INT (i)),
207690075Sobrien				     source)));
207790075Sobrien		  return insns + 1;
207890075Sobrien		}
207990075Sobrien	    }
208090075Sobrien	}
208190075Sobrien      break;
208290075Sobrien
208390075Sobrien    case IOR:
208490075Sobrien    case XOR:
208590075Sobrien      /* If we have IOR or XOR, and the constant can be loaded in a
208690075Sobrien	 single instruction, and we can find a temporary to put it in,
208790075Sobrien	 then this can be done in two instructions instead of 3-4.  */
208890075Sobrien      if (subtargets
208990075Sobrien	  /* TARGET can't be NULL if SUBTARGETS is 0 */
209090075Sobrien	  || (reload_completed && !reg_mentioned_p (target, source)))
209190075Sobrien	{
209290075Sobrien	  if (const_ok_for_arm (ARM_SIGN_EXTEND (~val)))
209390075Sobrien	    {
209490075Sobrien	      if (generate)
209590075Sobrien		{
209690075Sobrien		  rtx sub = subtargets ? gen_reg_rtx (mode) : target;
209790075Sobrien
2098169689Skan		  emit_constant_insn (cond,
2099169689Skan				      gen_rtx_SET (VOIDmode, sub,
2100169689Skan						   GEN_INT (val)));
2101169689Skan		  emit_constant_insn (cond,
2102169689Skan				      gen_rtx_SET (VOIDmode, target,
2103169689Skan						   gen_rtx_fmt_ee (code, mode,
2104169689Skan								   source, sub)));
210590075Sobrien		}
210690075Sobrien	      return 2;
210790075Sobrien	    }
210890075Sobrien	}
210990075Sobrien
211090075Sobrien      if (code == XOR)
211190075Sobrien	break;
211290075Sobrien
211390075Sobrien      if (set_sign_bit_copies > 8
211490075Sobrien	  && (val & (-1 << (32 - set_sign_bit_copies))) == val)
211590075Sobrien	{
211690075Sobrien	  if (generate)
211790075Sobrien	    {
211890075Sobrien	      rtx sub = subtargets ? gen_reg_rtx (mode) : target;
211990075Sobrien	      rtx shift = GEN_INT (set_sign_bit_copies);
212090075Sobrien
2121169689Skan	      emit_constant_insn
2122169689Skan		(cond,
2123169689Skan		 gen_rtx_SET (VOIDmode, sub,
2124169689Skan			      gen_rtx_NOT (mode,
2125169689Skan					   gen_rtx_ASHIFT (mode,
2126169689Skan							   source,
2127169689Skan							   shift))));
2128169689Skan	      emit_constant_insn
2129169689Skan		(cond,
2130169689Skan		 gen_rtx_SET (VOIDmode, target,
2131169689Skan			      gen_rtx_NOT (mode,
2132169689Skan					   gen_rtx_LSHIFTRT (mode, sub,
2133169689Skan							     shift))));
213490075Sobrien	    }
213590075Sobrien	  return 2;
213690075Sobrien	}
213790075Sobrien
213890075Sobrien      if (set_zero_bit_copies > 8
213990075Sobrien	  && (remainder & ((1 << set_zero_bit_copies) - 1)) == remainder)
214090075Sobrien	{
214190075Sobrien	  if (generate)
214290075Sobrien	    {
214390075Sobrien	      rtx sub = subtargets ? gen_reg_rtx (mode) : target;
214490075Sobrien	      rtx shift = GEN_INT (set_zero_bit_copies);
214590075Sobrien
2146169689Skan	      emit_constant_insn
2147169689Skan		(cond,
2148169689Skan		 gen_rtx_SET (VOIDmode, sub,
2149169689Skan			      gen_rtx_NOT (mode,
2150169689Skan					   gen_rtx_LSHIFTRT (mode,
2151169689Skan							     source,
2152169689Skan							     shift))));
2153169689Skan	      emit_constant_insn
2154169689Skan		(cond,
2155169689Skan		 gen_rtx_SET (VOIDmode, target,
2156169689Skan			      gen_rtx_NOT (mode,
2157169689Skan					   gen_rtx_ASHIFT (mode, sub,
2158169689Skan							   shift))));
215990075Sobrien	    }
216090075Sobrien	  return 2;
216190075Sobrien	}
216290075Sobrien
216390075Sobrien      if (const_ok_for_arm (temp1 = ARM_SIGN_EXTEND (~val)))
216490075Sobrien	{
216590075Sobrien	  if (generate)
216690075Sobrien	    {
216790075Sobrien	      rtx sub = subtargets ? gen_reg_rtx (mode) : target;
2168169689Skan	      emit_constant_insn (cond,
2169169689Skan				  gen_rtx_SET (VOIDmode, sub,
2170169689Skan					       gen_rtx_NOT (mode, source)));
217190075Sobrien	      source = sub;
217290075Sobrien	      if (subtargets)
217390075Sobrien		sub = gen_reg_rtx (mode);
2174169689Skan	      emit_constant_insn (cond,
2175169689Skan				  gen_rtx_SET (VOIDmode, sub,
2176169689Skan					       gen_rtx_AND (mode, source,
2177169689Skan							    GEN_INT (temp1))));
2178169689Skan	      emit_constant_insn (cond,
2179169689Skan				  gen_rtx_SET (VOIDmode, target,
2180169689Skan					       gen_rtx_NOT (mode, sub)));
218190075Sobrien	    }
218290075Sobrien	  return 3;
218390075Sobrien	}
218490075Sobrien      break;
218590075Sobrien
218690075Sobrien    case AND:
218790075Sobrien      /* See if two shifts will do 2 or more insn's worth of work.  */
218890075Sobrien      if (clear_sign_bit_copies >= 16 && clear_sign_bit_copies < 24)
218990075Sobrien	{
219090075Sobrien	  HOST_WIDE_INT shift_mask = ((0xffffffff
219190075Sobrien				       << (32 - clear_sign_bit_copies))
219290075Sobrien				      & 0xffffffff);
219390075Sobrien
219490075Sobrien	  if ((remainder | shift_mask) != 0xffffffff)
219590075Sobrien	    {
219690075Sobrien	      if (generate)
219790075Sobrien		{
219890075Sobrien		  rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
2199169689Skan		  insns = arm_gen_constant (AND, mode, cond,
2200169689Skan					    remainder | shift_mask,
220190075Sobrien					    new_src, source, subtargets, 1);
220290075Sobrien		  source = new_src;
220390075Sobrien		}
220490075Sobrien	      else
220590075Sobrien		{
220690075Sobrien		  rtx targ = subtargets ? NULL_RTX : target;
2207169689Skan		  insns = arm_gen_constant (AND, mode, cond,
2208169689Skan					    remainder | shift_mask,
220990075Sobrien					    targ, source, subtargets, 0);
221090075Sobrien		}
221190075Sobrien	    }
221290075Sobrien
221390075Sobrien	  if (generate)
221490075Sobrien	    {
221590075Sobrien	      rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
221690075Sobrien	      rtx shift = GEN_INT (clear_sign_bit_copies);
221790075Sobrien
221890075Sobrien	      emit_insn (gen_ashlsi3 (new_src, source, shift));
221990075Sobrien	      emit_insn (gen_lshrsi3 (target, new_src, shift));
222090075Sobrien	    }
222190075Sobrien
222290075Sobrien	  return insns + 2;
222390075Sobrien	}
222490075Sobrien
222590075Sobrien      if (clear_zero_bit_copies >= 16 && clear_zero_bit_copies < 24)
222690075Sobrien	{
222790075Sobrien	  HOST_WIDE_INT shift_mask = (1 << clear_zero_bit_copies) - 1;
2228169689Skan
222990075Sobrien	  if ((remainder | shift_mask) != 0xffffffff)
223090075Sobrien	    {
223190075Sobrien	      if (generate)
223290075Sobrien		{
223390075Sobrien		  rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
223490075Sobrien
2235169689Skan		  insns = arm_gen_constant (AND, mode, cond,
2236169689Skan					    remainder | shift_mask,
223790075Sobrien					    new_src, source, subtargets, 1);
223890075Sobrien		  source = new_src;
223990075Sobrien		}
224090075Sobrien	      else
224190075Sobrien		{
224290075Sobrien		  rtx targ = subtargets ? NULL_RTX : target;
224390075Sobrien
2244169689Skan		  insns = arm_gen_constant (AND, mode, cond,
2245169689Skan					    remainder | shift_mask,
224690075Sobrien					    targ, source, subtargets, 0);
224790075Sobrien		}
224890075Sobrien	    }
224990075Sobrien
225090075Sobrien	  if (generate)
225190075Sobrien	    {
225290075Sobrien	      rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
225390075Sobrien	      rtx shift = GEN_INT (clear_zero_bit_copies);
225490075Sobrien
225590075Sobrien	      emit_insn (gen_lshrsi3 (new_src, source, shift));
225690075Sobrien	      emit_insn (gen_ashlsi3 (target, new_src, shift));
225790075Sobrien	    }
225890075Sobrien
225990075Sobrien	  return insns + 2;
226090075Sobrien	}
226190075Sobrien
226290075Sobrien      break;
226390075Sobrien
226490075Sobrien    default:
226590075Sobrien      break;
226690075Sobrien    }
226790075Sobrien
226890075Sobrien  for (i = 0; i < 32; i++)
226990075Sobrien    if (remainder & (1 << i))
227090075Sobrien      num_bits_set++;
227190075Sobrien
227290075Sobrien  if (code == AND || (can_invert && num_bits_set > 16))
227390075Sobrien    remainder = (~remainder) & 0xffffffff;
227490075Sobrien  else if (code == PLUS && num_bits_set > 16)
227590075Sobrien    remainder = (-remainder) & 0xffffffff;
227690075Sobrien  else
227790075Sobrien    {
227890075Sobrien      can_invert = 0;
227990075Sobrien      can_negate = 0;
228090075Sobrien    }
228190075Sobrien
228290075Sobrien  /* Now try and find a way of doing the job in either two or three
228390075Sobrien     instructions.
228490075Sobrien     We start by looking for the largest block of zeros that are aligned on
228590075Sobrien     a 2-bit boundary, we then fill up the temps, wrapping around to the
228690075Sobrien     top of the word when we drop off the bottom.
228790075Sobrien     In the worst case this code should produce no more than four insns.  */
228890075Sobrien  {
228990075Sobrien    int best_start = 0;
229090075Sobrien    int best_consecutive_zeros = 0;
229190075Sobrien
229290075Sobrien    for (i = 0; i < 32; i += 2)
229390075Sobrien      {
229490075Sobrien	int consecutive_zeros = 0;
229590075Sobrien
229690075Sobrien	if (!(remainder & (3 << i)))
229790075Sobrien	  {
229890075Sobrien	    while ((i < 32) && !(remainder & (3 << i)))
229990075Sobrien	      {
230090075Sobrien		consecutive_zeros += 2;
230190075Sobrien		i += 2;
230290075Sobrien	      }
230390075Sobrien	    if (consecutive_zeros > best_consecutive_zeros)
230490075Sobrien	      {
230590075Sobrien		best_consecutive_zeros = consecutive_zeros;
230690075Sobrien		best_start = i - consecutive_zeros;
230790075Sobrien	      }
230890075Sobrien	    i -= 2;
230990075Sobrien	  }
231090075Sobrien      }
231190075Sobrien
231290075Sobrien    /* So long as it won't require any more insns to do so, it's
231390075Sobrien       desirable to emit a small constant (in bits 0...9) in the last
231490075Sobrien       insn.  This way there is more chance that it can be combined with
231590075Sobrien       a later addressing insn to form a pre-indexed load or store
231690075Sobrien       operation.  Consider:
231790075Sobrien
231890075Sobrien	       *((volatile int *)0xe0000100) = 1;
231990075Sobrien	       *((volatile int *)0xe0000110) = 2;
232090075Sobrien
232190075Sobrien       We want this to wind up as:
232290075Sobrien
232390075Sobrien		mov rA, #0xe0000000
232490075Sobrien		mov rB, #1
232590075Sobrien		str rB, [rA, #0x100]
232690075Sobrien		mov rB, #2
232790075Sobrien		str rB, [rA, #0x110]
232890075Sobrien
232990075Sobrien       rather than having to synthesize both large constants from scratch.
233090075Sobrien
233190075Sobrien       Therefore, we calculate how many insns would be required to emit
2332169689Skan       the constant starting from `best_start', and also starting from
2333169689Skan       zero (i.e. with bit 31 first to be output).  If `best_start' doesn't
233490075Sobrien       yield a shorter sequence, we may as well use zero.  */
233590075Sobrien    if (best_start != 0
233690075Sobrien	&& ((((unsigned HOST_WIDE_INT) 1) << best_start) < remainder)
2337169689Skan	&& (count_insns_for_constant (remainder, 0) <=
233890075Sobrien	    count_insns_for_constant (remainder, best_start)))
233990075Sobrien      best_start = 0;
234090075Sobrien
234190075Sobrien    /* Now start emitting the insns.  */
234290075Sobrien    i = best_start;
234390075Sobrien    do
234490075Sobrien      {
234590075Sobrien	int end;
234690075Sobrien
234790075Sobrien	if (i <= 0)
234890075Sobrien	  i += 32;
234990075Sobrien	if (remainder & (3 << (i - 2)))
235090075Sobrien	  {
235190075Sobrien	    end = i - 8;
235290075Sobrien	    if (end < 0)
235390075Sobrien	      end += 32;
235490075Sobrien	    temp1 = remainder & ((0x0ff << end)
235590075Sobrien				 | ((i < end) ? (0xff >> (32 - end)) : 0));
235690075Sobrien	    remainder &= ~temp1;
235790075Sobrien
235890075Sobrien	    if (generate)
235990075Sobrien	      {
236090075Sobrien		rtx new_src, temp1_rtx;
236190075Sobrien
236290075Sobrien		if (code == SET || code == MINUS)
236390075Sobrien		  {
236490075Sobrien		    new_src = (subtargets ? gen_reg_rtx (mode) : target);
236590075Sobrien		    if (can_invert && code != MINUS)
236690075Sobrien		      temp1 = ~temp1;
236790075Sobrien		  }
236890075Sobrien		else
236990075Sobrien		  {
237090075Sobrien		    if (remainder && subtargets)
237190075Sobrien		      new_src = gen_reg_rtx (mode);
237290075Sobrien		    else
237390075Sobrien		      new_src = target;
237490075Sobrien		    if (can_invert)
237590075Sobrien		      temp1 = ~temp1;
237690075Sobrien		    else if (can_negate)
237790075Sobrien		      temp1 = -temp1;
237890075Sobrien		  }
237990075Sobrien
238090075Sobrien		temp1 = trunc_int_for_mode (temp1, mode);
238190075Sobrien		temp1_rtx = GEN_INT (temp1);
238290075Sobrien
238390075Sobrien		if (code == SET)
238490075Sobrien		  ;
238590075Sobrien		else if (code == MINUS)
238690075Sobrien		  temp1_rtx = gen_rtx_MINUS (mode, temp1_rtx, source);
238790075Sobrien		else
238890075Sobrien		  temp1_rtx = gen_rtx_fmt_ee (code, mode, source, temp1_rtx);
238990075Sobrien
2390169689Skan		emit_constant_insn (cond,
2391169689Skan				    gen_rtx_SET (VOIDmode, new_src,
2392169689Skan						 temp1_rtx));
239390075Sobrien		source = new_src;
239490075Sobrien	      }
239590075Sobrien
239690075Sobrien	    if (code == SET)
239790075Sobrien	      {
239890075Sobrien		can_invert = 0;
239990075Sobrien		code = PLUS;
240090075Sobrien	      }
240190075Sobrien	    else if (code == MINUS)
240290075Sobrien	      code = PLUS;
240390075Sobrien
240490075Sobrien	    insns++;
240590075Sobrien	    i -= 6;
240690075Sobrien	  }
240790075Sobrien	i -= 2;
240890075Sobrien      }
240990075Sobrien    while (remainder);
241090075Sobrien  }
241190075Sobrien
241290075Sobrien  return insns;
241390075Sobrien}
241490075Sobrien
241590075Sobrien/* Canonicalize a comparison so that we are more likely to recognize it.
241690075Sobrien   This can be done for a few constant compares, where we can make the
241790075Sobrien   immediate value easier to load.  */
241890075Sobrien
241990075Sobrienenum rtx_code
2420169689Skanarm_canonicalize_comparison (enum rtx_code code, enum machine_mode mode,
2421169689Skan			     rtx * op1)
242290075Sobrien{
242390075Sobrien  unsigned HOST_WIDE_INT i = INTVAL (*op1);
2424169689Skan  unsigned HOST_WIDE_INT maxval;
2425169689Skan  maxval = (((unsigned HOST_WIDE_INT) 1) << (GET_MODE_BITSIZE(mode) - 1)) - 1;
242690075Sobrien
242790075Sobrien  switch (code)
242890075Sobrien    {
242990075Sobrien    case EQ:
243090075Sobrien    case NE:
243190075Sobrien      return code;
243290075Sobrien
243390075Sobrien    case GT:
243490075Sobrien    case LE:
2435169689Skan      if (i != maxval
243690075Sobrien	  && (const_ok_for_arm (i + 1) || const_ok_for_arm (-(i + 1))))
243790075Sobrien	{
243890075Sobrien	  *op1 = GEN_INT (i + 1);
243990075Sobrien	  return code == GT ? GE : LT;
244090075Sobrien	}
244190075Sobrien      break;
244290075Sobrien
244390075Sobrien    case GE:
244490075Sobrien    case LT:
2445169689Skan      if (i != ~maxval
244690075Sobrien	  && (const_ok_for_arm (i - 1) || const_ok_for_arm (-(i - 1))))
244790075Sobrien	{
244890075Sobrien	  *op1 = GEN_INT (i - 1);
244990075Sobrien	  return code == GE ? GT : LE;
245090075Sobrien	}
245190075Sobrien      break;
245290075Sobrien
245390075Sobrien    case GTU:
245490075Sobrien    case LEU:
245590075Sobrien      if (i != ~((unsigned HOST_WIDE_INT) 0)
245690075Sobrien	  && (const_ok_for_arm (i + 1) || const_ok_for_arm (-(i + 1))))
245790075Sobrien	{
245890075Sobrien	  *op1 = GEN_INT (i + 1);
245990075Sobrien	  return code == GTU ? GEU : LTU;
246090075Sobrien	}
246190075Sobrien      break;
246290075Sobrien
246390075Sobrien    case GEU:
246490075Sobrien    case LTU:
246590075Sobrien      if (i != 0
246690075Sobrien	  && (const_ok_for_arm (i - 1) || const_ok_for_arm (-(i - 1))))
246790075Sobrien	{
246890075Sobrien	  *op1 = GEN_INT (i - 1);
246990075Sobrien	  return code == GEU ? GTU : LEU;
247090075Sobrien	}
247190075Sobrien      break;
247290075Sobrien
247390075Sobrien    default:
2474169689Skan      gcc_unreachable ();
247590075Sobrien    }
247690075Sobrien
247790075Sobrien  return code;
247890075Sobrien}
247990075Sobrien
2480169689Skan
2481169689Skan/* Define how to find the value returned by a function.  */
2482169689Skan
2483169689Skanrtx
2484169689Skanarm_function_value(tree type, tree func ATTRIBUTE_UNUSED)
2485169689Skan{
2486169689Skan  enum machine_mode mode;
2487169689Skan  int unsignedp ATTRIBUTE_UNUSED;
2488169689Skan  rtx r ATTRIBUTE_UNUSED;
2489169689Skan
2490169689Skan  mode = TYPE_MODE (type);
2491169689Skan  /* Promote integer types.  */
2492169689Skan  if (INTEGRAL_TYPE_P (type))
2493169689Skan    PROMOTE_FUNCTION_MODE (mode, unsignedp, type);
2494169689Skan
2495169689Skan  /* Promotes small structs returned in a register to full-word size
2496169689Skan     for big-endian AAPCS.  */
2497169689Skan  if (arm_return_in_msb (type))
2498169689Skan    {
2499169689Skan      HOST_WIDE_INT size = int_size_in_bytes (type);
2500169689Skan      if (size % UNITS_PER_WORD != 0)
2501169689Skan	{
2502169689Skan	  size += UNITS_PER_WORD - size % UNITS_PER_WORD;
2503169689Skan	  mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0);
2504169689Skan	}
2505169689Skan    }
2506169689Skan
2507169689Skan  return LIBCALL_VALUE(mode);
2508169689Skan}
2509169689Skan
2510169689Skan/* Determine the amount of memory needed to store the possible return
2511169689Skan   registers of an untyped call.  */
2512169689Skanint
2513169689Skanarm_apply_result_size (void)
2514169689Skan{
2515169689Skan  int size = 16;
2516169689Skan
2517169689Skan  if (TARGET_ARM)
2518169689Skan    {
2519169689Skan      if (TARGET_HARD_FLOAT_ABI)
2520169689Skan	{
2521169689Skan	  if (TARGET_FPA)
2522169689Skan	    size += 12;
2523169689Skan	  if (TARGET_MAVERICK)
2524169689Skan	    size += 8;
2525169689Skan	}
2526169689Skan      if (TARGET_IWMMXT_ABI)
2527169689Skan	size += 8;
2528169689Skan    }
2529169689Skan
2530169689Skan  return size;
2531169689Skan}
2532169689Skan
253390075Sobrien/* Decide whether a type should be returned in memory (true)
253490075Sobrien   or in a register (false).  This is called by the macro
253590075Sobrien   RETURN_IN_MEMORY.  */
253690075Sobrienint
2537132718Skanarm_return_in_memory (tree type)
253890075Sobrien{
2539117395Skan  HOST_WIDE_INT size;
2540117395Skan
2541169689Skan  if (!AGGREGATE_TYPE_P (type) &&
2542169689Skan      (TREE_CODE (type) != VECTOR_TYPE) &&
2543169689Skan      !(TARGET_AAPCS_BASED && TREE_CODE (type) == COMPLEX_TYPE))
2544169689Skan    /* All simple types are returned in registers.
2545169689Skan       For AAPCS, complex types are treated the same as aggregates.  */
254690075Sobrien    return 0;
2547117395Skan
2548117395Skan  size = int_size_in_bytes (type);
2549117395Skan
2550169689Skan  if (arm_abi != ARM_ABI_APCS)
2551117395Skan    {
2552169689Skan      /* ATPCS and later return aggregate types in memory only if they are
2553117395Skan	 larger than a word (or are variable size).  */
2554117395Skan      return (size < 0 || size > UNITS_PER_WORD);
2555117395Skan    }
2556169689Skan
2557169689Skan  /* To maximize backwards compatibility with previous versions of gcc,
2558169689Skan     return vectors up to 4 words in registers.  */
2559169689Skan  if (TREE_CODE (type) == VECTOR_TYPE)
2560169689Skan    return (size < 0 || size > (4 * UNITS_PER_WORD));
2561169689Skan
2562132718Skan  /* For the arm-wince targets we choose to be compatible with Microsoft's
256390075Sobrien     ARM and Thumb compilers, which always return aggregates in memory.  */
256490075Sobrien#ifndef ARM_WINCE
256590075Sobrien  /* All structures/unions bigger than one word are returned in memory.
256690075Sobrien     Also catch the case where int_size_in_bytes returns -1.  In this case
2567132718Skan     the aggregate is either huge or of variable size, and in either case
256890075Sobrien     we will want to return it via memory and not in a register.  */
2569117395Skan  if (size < 0 || size > UNITS_PER_WORD)
257090075Sobrien    return 1;
2571169689Skan
257290075Sobrien  if (TREE_CODE (type) == RECORD_TYPE)
257390075Sobrien    {
257490075Sobrien      tree field;
257590075Sobrien
257690075Sobrien      /* For a struct the APCS says that we only return in a register
257790075Sobrien	 if the type is 'integer like' and every addressable element
257890075Sobrien	 has an offset of zero.  For practical purposes this means
257990075Sobrien	 that the structure can have at most one non bit-field element
258090075Sobrien	 and that this element must be the first one in the structure.  */
2581169689Skan
258290075Sobrien      /* Find the first field, ignoring non FIELD_DECL things which will
258390075Sobrien	 have been created by C++.  */
258490075Sobrien      for (field = TYPE_FIELDS (type);
258590075Sobrien	   field && TREE_CODE (field) != FIELD_DECL;
258690075Sobrien	   field = TREE_CHAIN (field))
258790075Sobrien	continue;
2588169689Skan
258990075Sobrien      if (field == NULL)
259090075Sobrien	return 0; /* An empty structure.  Allowed by an extension to ANSI C.  */
259190075Sobrien
259290075Sobrien      /* Check that the first field is valid for returning in a register.  */
259390075Sobrien
259490075Sobrien      /* ... Floats are not allowed */
259590075Sobrien      if (FLOAT_TYPE_P (TREE_TYPE (field)))
259690075Sobrien	return 1;
259790075Sobrien
259890075Sobrien      /* ... Aggregates that are not themselves valid for returning in
259990075Sobrien	 a register are not allowed.  */
260090075Sobrien      if (RETURN_IN_MEMORY (TREE_TYPE (field)))
260190075Sobrien	return 1;
260290075Sobrien
260390075Sobrien      /* Now check the remaining fields, if any.  Only bitfields are allowed,
260490075Sobrien	 since they are not addressable.  */
260590075Sobrien      for (field = TREE_CHAIN (field);
260690075Sobrien	   field;
260790075Sobrien	   field = TREE_CHAIN (field))
260890075Sobrien	{
260990075Sobrien	  if (TREE_CODE (field) != FIELD_DECL)
261090075Sobrien	    continue;
2611169689Skan
261290075Sobrien	  if (!DECL_BIT_FIELD_TYPE (field))
261390075Sobrien	    return 1;
261490075Sobrien	}
261590075Sobrien
261690075Sobrien      return 0;
261790075Sobrien    }
2618169689Skan
261990075Sobrien  if (TREE_CODE (type) == UNION_TYPE)
262090075Sobrien    {
262190075Sobrien      tree field;
262290075Sobrien
262390075Sobrien      /* Unions can be returned in registers if every element is
262490075Sobrien	 integral, or can be returned in an integer register.  */
262590075Sobrien      for (field = TYPE_FIELDS (type);
262690075Sobrien	   field;
262790075Sobrien	   field = TREE_CHAIN (field))
262890075Sobrien	{
262990075Sobrien	  if (TREE_CODE (field) != FIELD_DECL)
263090075Sobrien	    continue;
263190075Sobrien
263290075Sobrien	  if (FLOAT_TYPE_P (TREE_TYPE (field)))
263390075Sobrien	    return 1;
2634169689Skan
263590075Sobrien	  if (RETURN_IN_MEMORY (TREE_TYPE (field)))
263690075Sobrien	    return 1;
263790075Sobrien	}
2638169689Skan
263990075Sobrien      return 0;
264090075Sobrien    }
2641169689Skan#endif /* not ARM_WINCE */
2642169689Skan
264390075Sobrien  /* Return all other types in memory.  */
264490075Sobrien  return 1;
264590075Sobrien}
264690075Sobrien
2647132718Skan/* Indicate whether or not words of a double are in big-endian order.  */
2648117395Skan
2649117395Skanint
2650132718Skanarm_float_words_big_endian (void)
2651117395Skan{
2652169689Skan  if (TARGET_MAVERICK)
2653132718Skan    return 0;
2654117395Skan
2655117395Skan  /* For FPA, float words are always big-endian.  For VFP, floats words
2656117395Skan     follow the memory system mode.  */
2657117395Skan
2658169689Skan  if (TARGET_FPA)
2659117395Skan    {
2660117395Skan      return 1;
2661117395Skan    }
2662117395Skan
2663117395Skan  if (TARGET_VFP)
2664117395Skan    return (TARGET_BIG_END ? 1 : 0);
2665117395Skan
2666117395Skan  return 1;
2667117395Skan}
2668117395Skan
266990075Sobrien/* Initialize a variable CUM of type CUMULATIVE_ARGS
267090075Sobrien   for a call to a function whose data type is FNTYPE.
267190075Sobrien   For a library call, FNTYPE is NULL.  */
267290075Sobrienvoid
2673169689Skanarm_init_cumulative_args (CUMULATIVE_ARGS *pcum, tree fntype,
2674132718Skan			  rtx libname  ATTRIBUTE_UNUSED,
2675132718Skan			  tree fndecl ATTRIBUTE_UNUSED)
267690075Sobrien{
267790075Sobrien  /* On the ARM, the offset starts at 0.  */
2678169689Skan  pcum->nregs = 0;
2679132718Skan  pcum->iwmmxt_nregs = 0;
2680169689Skan  pcum->can_split = true;
2681169689Skan
268290075Sobrien  pcum->call_cookie = CALL_NORMAL;
268390075Sobrien
268490075Sobrien  if (TARGET_LONG_CALLS)
268590075Sobrien    pcum->call_cookie = CALL_LONG;
2686169689Skan
268790075Sobrien  /* Check for long call/short call attributes.  The attributes
268890075Sobrien     override any command line option.  */
268990075Sobrien  if (fntype)
269090075Sobrien    {
269190075Sobrien      if (lookup_attribute ("short_call", TYPE_ATTRIBUTES (fntype)))
269290075Sobrien	pcum->call_cookie = CALL_SHORT;
269390075Sobrien      else if (lookup_attribute ("long_call", TYPE_ATTRIBUTES (fntype)))
269490075Sobrien	pcum->call_cookie = CALL_LONG;
269590075Sobrien    }
2696132718Skan
2697132718Skan  /* Varargs vectors are treated the same as long long.
2698132718Skan     named_count avoids having to change the way arm handles 'named' */
2699132718Skan  pcum->named_count = 0;
2700132718Skan  pcum->nargs = 0;
2701132718Skan
2702132718Skan  if (TARGET_REALLY_IWMMXT && fntype)
2703132718Skan    {
2704132718Skan      tree fn_arg;
2705132718Skan
2706132718Skan      for (fn_arg = TYPE_ARG_TYPES (fntype);
2707132718Skan	   fn_arg;
2708132718Skan	   fn_arg = TREE_CHAIN (fn_arg))
2709132718Skan	pcum->named_count += 1;
2710132718Skan
2711132718Skan      if (! pcum->named_count)
2712132718Skan	pcum->named_count = INT_MAX;
2713132718Skan    }
271490075Sobrien}
271590075Sobrien
2716169689Skan
2717169689Skan/* Return true if mode/type need doubleword alignment.  */
2718169689Skanbool
2719169689Skanarm_needs_doubleword_align (enum machine_mode mode, tree type)
2720169689Skan{
2721169689Skan  return (GET_MODE_ALIGNMENT (mode) > PARM_BOUNDARY
2722169689Skan	  || (type && TYPE_ALIGN (type) > PARM_BOUNDARY));
2723169689Skan}
2724169689Skan
2725169689Skan
272690075Sobrien/* Determine where to put an argument to a function.
272790075Sobrien   Value is zero to push the argument on the stack,
272890075Sobrien   or a hard register in which to store the argument.
272990075Sobrien
273090075Sobrien   MODE is the argument's machine mode.
273190075Sobrien   TYPE is the data type of the argument (as a tree).
273290075Sobrien    This is null for libcalls where that information may
273390075Sobrien    not be available.
273490075Sobrien   CUM is a variable of type CUMULATIVE_ARGS which gives info about
273590075Sobrien    the preceding args and about the function being called.
273690075Sobrien   NAMED is nonzero if this argument is a named parameter
273790075Sobrien    (otherwise it is an extra parameter matching an ellipsis).  */
273890075Sobrien
273990075Sobrienrtx
2740132718Skanarm_function_arg (CUMULATIVE_ARGS *pcum, enum machine_mode mode,
2741169689Skan		  tree type, int named)
274290075Sobrien{
2743169689Skan  int nregs;
2744169689Skan
2745169689Skan  /* Varargs vectors are treated the same as long long.
2746169689Skan     named_count avoids having to change the way arm handles 'named' */
2747169689Skan  if (TARGET_IWMMXT_ABI
2748169689Skan      && arm_vector_mode_supported_p (mode)
2749169689Skan      && pcum->named_count > pcum->nargs + 1)
2750132718Skan    {
2751169689Skan      if (pcum->iwmmxt_nregs <= 9)
2752169689Skan	return gen_rtx_REG (mode, pcum->iwmmxt_nregs + FIRST_IWMMXT_REGNUM);
2753169689Skan      else
2754132718Skan	{
2755169689Skan	  pcum->can_split = false;
2756169689Skan	  return NULL_RTX;
2757132718Skan	}
2758132718Skan    }
2759132718Skan
2760169689Skan  /* Put doubleword aligned quantities in even register pairs.  */
2761169689Skan  if (pcum->nregs & 1
2762169689Skan      && ARM_DOUBLEWORD_ALIGN
2763169689Skan      && arm_needs_doubleword_align (mode, type))
2764169689Skan    pcum->nregs++;
2765169689Skan
276690075Sobrien  if (mode == VOIDmode)
276790075Sobrien    /* Compute operand 2 of the call insn.  */
276890075Sobrien    return GEN_INT (pcum->call_cookie);
2769169689Skan
2770169689Skan  /* Only allow splitting an arg between regs and memory if all preceding
2771169689Skan     args were allocated to regs.  For args passed by reference we only count
2772169689Skan     the reference pointer.  */
2773169689Skan  if (pcum->can_split)
2774169689Skan    nregs = 1;
2775169689Skan  else
2776169689Skan    nregs = ARM_NUM_REGS2 (mode, type);
2777169689Skan
2778169689Skan  if (!named || pcum->nregs + nregs > NUM_ARG_REGS)
277990075Sobrien    return NULL_RTX;
2780169689Skan
278190075Sobrien  return gen_rtx_REG (mode, pcum->nregs);
278290075Sobrien}
2783117395Skan
2784169689Skanstatic int
2785169689Skanarm_arg_partial_bytes (CUMULATIVE_ARGS *pcum, enum machine_mode mode,
2786169689Skan		       tree type, bool named ATTRIBUTE_UNUSED)
2787117395Skan{
2788169689Skan  int nregs = pcum->nregs;
2789117395Skan
2790169689Skan  if (arm_vector_mode_supported_p (mode))
2791169689Skan    return 0;
2792117395Skan
2793169689Skan  if (NUM_ARG_REGS > nregs
2794169689Skan      && (NUM_ARG_REGS < nregs + ARM_NUM_REGS2 (mode, type))
2795169689Skan      && pcum->can_split)
2796169689Skan    return (NUM_ARG_REGS - nregs) * UNITS_PER_WORD;
2797117395Skan
2798169689Skan  return 0;
2799169689Skan}
2800132718Skan
2801169689Skan/* Variable sized types are passed by reference.  This is a GCC
2802169689Skan   extension to the ARM ABI.  */
2803132718Skan
2804169689Skanstatic bool
2805169689Skanarm_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
2806169689Skan		       enum machine_mode mode ATTRIBUTE_UNUSED,
2807169689Skan		       tree type, bool named ATTRIBUTE_UNUSED)
2808169689Skan{
2809169689Skan  return type && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST;
2810117395Skan}
281190075Sobrien
281290075Sobrien/* Encode the current state of the #pragma [no_]long_calls.  */
281390075Sobrientypedef enum
281490075Sobrien{
2815169689Skan  OFF,		/* No #pragma [no_]long_calls is in effect.  */
281690075Sobrien  LONG,		/* #pragma long_calls is in effect.  */
281790075Sobrien  SHORT		/* #pragma no_long_calls is in effect.  */
281890075Sobrien} arm_pragma_enum;
281990075Sobrien
282090075Sobrienstatic arm_pragma_enum arm_pragma_long_calls = OFF;
282190075Sobrien
282290075Sobrienvoid
2823132718Skanarm_pr_long_calls (struct cpp_reader * pfile ATTRIBUTE_UNUSED)
282490075Sobrien{
282590075Sobrien  arm_pragma_long_calls = LONG;
282690075Sobrien}
282790075Sobrien
282890075Sobrienvoid
2829132718Skanarm_pr_no_long_calls (struct cpp_reader * pfile ATTRIBUTE_UNUSED)
283090075Sobrien{
283190075Sobrien  arm_pragma_long_calls = SHORT;
283290075Sobrien}
283390075Sobrien
283490075Sobrienvoid
2835132718Skanarm_pr_long_calls_off (struct cpp_reader * pfile ATTRIBUTE_UNUSED)
283690075Sobrien{
283790075Sobrien  arm_pragma_long_calls = OFF;
283890075Sobrien}
283990075Sobrien
284090075Sobrien/* Table of machine attributes.  */
284190075Sobrienconst struct attribute_spec arm_attribute_table[] =
284290075Sobrien{
284390075Sobrien  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
284490075Sobrien  /* Function calls made to this symbol must be done indirectly, because
284590075Sobrien     it may lie outside of the 26 bit addressing range of a normal function
284690075Sobrien     call.  */
284790075Sobrien  { "long_call",    0, 0, false, true,  true,  NULL },
284890075Sobrien  /* Whereas these functions are always known to reside within the 26 bit
284990075Sobrien     addressing range.  */
285090075Sobrien  { "short_call",   0, 0, false, true,  true,  NULL },
2851169689Skan  /* Interrupt Service Routines have special prologue and epilogue requirements.  */
285290075Sobrien  { "isr",          0, 1, false, false, false, arm_handle_isr_attribute },
285390075Sobrien  { "interrupt",    0, 1, false, false, false, arm_handle_isr_attribute },
285490075Sobrien  { "naked",        0, 0, true,  false, false, arm_handle_fndecl_attribute },
285590075Sobrien#ifdef ARM_PE
285690075Sobrien  /* ARM/PE has three new attributes:
285790075Sobrien     interfacearm - ?
285890075Sobrien     dllexport - for exporting a function/variable that will live in a dll
285990075Sobrien     dllimport - for importing a function/variable from a dll
286090075Sobrien
286190075Sobrien     Microsoft allows multiple declspecs in one __declspec, separating
286290075Sobrien     them with spaces.  We do NOT support this.  Instead, use __declspec
286390075Sobrien     multiple times.
286490075Sobrien  */
286590075Sobrien  { "dllimport",    0, 0, true,  false, false, NULL },
286690075Sobrien  { "dllexport",    0, 0, true,  false, false, NULL },
286790075Sobrien  { "interfacearm", 0, 0, true,  false, false, arm_handle_fndecl_attribute },
2868169689Skan#elif TARGET_DLLIMPORT_DECL_ATTRIBUTES
2869169689Skan  { "dllimport",    0, 0, false, false, false, handle_dll_attribute },
2870169689Skan  { "dllexport",    0, 0, false, false, false, handle_dll_attribute },
2871169689Skan  { "notshared",    0, 0, false, true, false, arm_handle_notshared_attribute },
287290075Sobrien#endif
287390075Sobrien  { NULL,           0, 0, false, false, false, NULL }
287490075Sobrien};
287590075Sobrien
287690075Sobrien/* Handle an attribute requiring a FUNCTION_DECL;
287790075Sobrien   arguments as in struct attribute_spec.handler.  */
287890075Sobrienstatic tree
2879132718Skanarm_handle_fndecl_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
2880132718Skan			     int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
288190075Sobrien{
288290075Sobrien  if (TREE_CODE (*node) != FUNCTION_DECL)
288390075Sobrien    {
2884169689Skan      warning (OPT_Wattributes, "%qs attribute only applies to functions",
288590075Sobrien	       IDENTIFIER_POINTER (name));
288690075Sobrien      *no_add_attrs = true;
288790075Sobrien    }
288890075Sobrien
288990075Sobrien  return NULL_TREE;
289090075Sobrien}
289190075Sobrien
289290075Sobrien/* Handle an "interrupt" or "isr" attribute;
289390075Sobrien   arguments as in struct attribute_spec.handler.  */
289490075Sobrienstatic tree
2895132718Skanarm_handle_isr_attribute (tree *node, tree name, tree args, int flags,
2896132718Skan			  bool *no_add_attrs)
289790075Sobrien{
289890075Sobrien  if (DECL_P (*node))
289990075Sobrien    {
290090075Sobrien      if (TREE_CODE (*node) != FUNCTION_DECL)
290190075Sobrien	{
2902169689Skan	  warning (OPT_Wattributes, "%qs attribute only applies to functions",
290390075Sobrien		   IDENTIFIER_POINTER (name));
290490075Sobrien	  *no_add_attrs = true;
290590075Sobrien	}
290690075Sobrien      /* FIXME: the argument if any is checked for type attributes;
290790075Sobrien	 should it be checked for decl ones?  */
290890075Sobrien    }
290990075Sobrien  else
291090075Sobrien    {
291190075Sobrien      if (TREE_CODE (*node) == FUNCTION_TYPE
291290075Sobrien	  || TREE_CODE (*node) == METHOD_TYPE)
291390075Sobrien	{
291490075Sobrien	  if (arm_isr_value (args) == ARM_FT_UNKNOWN)
291590075Sobrien	    {
2916169689Skan	      warning (OPT_Wattributes, "%qs attribute ignored",
2917169689Skan		       IDENTIFIER_POINTER (name));
291890075Sobrien	      *no_add_attrs = true;
291990075Sobrien	    }
292090075Sobrien	}
292190075Sobrien      else if (TREE_CODE (*node) == POINTER_TYPE
292290075Sobrien	       && (TREE_CODE (TREE_TYPE (*node)) == FUNCTION_TYPE
292390075Sobrien		   || TREE_CODE (TREE_TYPE (*node)) == METHOD_TYPE)
292490075Sobrien	       && arm_isr_value (args) != ARM_FT_UNKNOWN)
292590075Sobrien	{
2926169689Skan	  *node = build_variant_type_copy (*node);
292790075Sobrien	  TREE_TYPE (*node) = build_type_attribute_variant
292890075Sobrien	    (TREE_TYPE (*node),
292990075Sobrien	     tree_cons (name, args, TYPE_ATTRIBUTES (TREE_TYPE (*node))));
293090075Sobrien	  *no_add_attrs = true;
293190075Sobrien	}
293290075Sobrien      else
293390075Sobrien	{
293490075Sobrien	  /* Possibly pass this attribute on from the type to a decl.  */
293590075Sobrien	  if (flags & ((int) ATTR_FLAG_DECL_NEXT
293690075Sobrien		       | (int) ATTR_FLAG_FUNCTION_NEXT
293790075Sobrien		       | (int) ATTR_FLAG_ARRAY_NEXT))
293890075Sobrien	    {
293990075Sobrien	      *no_add_attrs = true;
294090075Sobrien	      return tree_cons (name, args, NULL_TREE);
294190075Sobrien	    }
294290075Sobrien	  else
294390075Sobrien	    {
2944169689Skan	      warning (OPT_Wattributes, "%qs attribute ignored",
2945169689Skan		       IDENTIFIER_POINTER (name));
294690075Sobrien	    }
294790075Sobrien	}
294890075Sobrien    }
294990075Sobrien
295090075Sobrien  return NULL_TREE;
295190075Sobrien}
295290075Sobrien
2953169689Skan#if TARGET_DLLIMPORT_DECL_ATTRIBUTES
2954169689Skan/* Handle the "notshared" attribute.  This attribute is another way of
2955169689Skan   requesting hidden visibility.  ARM's compiler supports
2956169689Skan   "__declspec(notshared)"; we support the same thing via an
2957169689Skan   attribute.  */
2958169689Skan
2959169689Skanstatic tree
2960169689Skanarm_handle_notshared_attribute (tree *node,
2961169689Skan				tree name ATTRIBUTE_UNUSED,
2962169689Skan				tree args ATTRIBUTE_UNUSED,
2963169689Skan				int flags ATTRIBUTE_UNUSED,
2964169689Skan				bool *no_add_attrs)
2965169689Skan{
2966169689Skan  tree decl = TYPE_NAME (*node);
2967169689Skan
2968169689Skan  if (decl)
2969169689Skan    {
2970169689Skan      DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN;
2971169689Skan      DECL_VISIBILITY_SPECIFIED (decl) = 1;
2972169689Skan      *no_add_attrs = false;
2973169689Skan    }
2974169689Skan  return NULL_TREE;
2975169689Skan}
2976169689Skan#endif
2977169689Skan
297890075Sobrien/* Return 0 if the attributes for two types are incompatible, 1 if they
297990075Sobrien   are compatible, and 2 if they are nearly compatible (which causes a
298090075Sobrien   warning to be generated).  */
298190075Sobrienstatic int
2982132718Skanarm_comp_type_attributes (tree type1, tree type2)
298390075Sobrien{
298490075Sobrien  int l1, l2, s1, s2;
2985169689Skan
298690075Sobrien  /* Check for mismatch of non-default calling convention.  */
298790075Sobrien  if (TREE_CODE (type1) != FUNCTION_TYPE)
298890075Sobrien    return 1;
298990075Sobrien
299090075Sobrien  /* Check for mismatched call attributes.  */
299190075Sobrien  l1 = lookup_attribute ("long_call", TYPE_ATTRIBUTES (type1)) != NULL;
299290075Sobrien  l2 = lookup_attribute ("long_call", TYPE_ATTRIBUTES (type2)) != NULL;
299390075Sobrien  s1 = lookup_attribute ("short_call", TYPE_ATTRIBUTES (type1)) != NULL;
299490075Sobrien  s2 = lookup_attribute ("short_call", TYPE_ATTRIBUTES (type2)) != NULL;
299590075Sobrien
299690075Sobrien  /* Only bother to check if an attribute is defined.  */
299790075Sobrien  if (l1 | l2 | s1 | s2)
299890075Sobrien    {
299990075Sobrien      /* If one type has an attribute, the other must have the same attribute.  */
300090075Sobrien      if ((l1 != l2) || (s1 != s2))
300190075Sobrien	return 0;
300290075Sobrien
300390075Sobrien      /* Disallow mixed attributes.  */
300490075Sobrien      if ((l1 & s2) || (l2 & s1))
300590075Sobrien	return 0;
300690075Sobrien    }
3007169689Skan
300890075Sobrien  /* Check for mismatched ISR attribute.  */
300990075Sobrien  l1 = lookup_attribute ("isr", TYPE_ATTRIBUTES (type1)) != NULL;
301090075Sobrien  if (! l1)
301190075Sobrien    l1 = lookup_attribute ("interrupt", TYPE_ATTRIBUTES (type1)) != NULL;
301290075Sobrien  l2 = lookup_attribute ("isr", TYPE_ATTRIBUTES (type2)) != NULL;
301390075Sobrien  if (! l2)
301490075Sobrien    l1 = lookup_attribute ("interrupt", TYPE_ATTRIBUTES (type2)) != NULL;
301590075Sobrien  if (l1 != l2)
301690075Sobrien    return 0;
301790075Sobrien
301890075Sobrien  return 1;
301990075Sobrien}
302090075Sobrien
302190075Sobrien/*  Encode long_call or short_call attribute by prefixing
302290075Sobrien    symbol name in DECL with a special character FLAG.  */
302390075Sobrienvoid
3024132718Skanarm_encode_call_attribute (tree decl, int flag)
302590075Sobrien{
302690075Sobrien  const char * str = XSTR (XEXP (DECL_RTL (decl), 0), 0);
302790075Sobrien  int          len = strlen (str);
302890075Sobrien  char *       newstr;
302990075Sobrien
303090075Sobrien  /* Do not allow weak functions to be treated as short call.  */
303190075Sobrien  if (DECL_WEAK (decl) && flag == SHORT_CALL_FLAG_CHAR)
303290075Sobrien    return;
303390075Sobrien
303490075Sobrien  newstr = alloca (len + 2);
303590075Sobrien  newstr[0] = flag;
303690075Sobrien  strcpy (newstr + 1, str);
303790075Sobrien
303890075Sobrien  newstr = (char *) ggc_alloc_string (newstr, len + 1);
303990075Sobrien  XSTR (XEXP (DECL_RTL (decl), 0), 0) = newstr;
304090075Sobrien}
304190075Sobrien
304290075Sobrien/*  Assigns default attributes to newly defined type.  This is used to
304390075Sobrien    set short_call/long_call attributes for function types of
304490075Sobrien    functions defined inside corresponding #pragma scopes.  */
304590075Sobrienstatic void
3046132718Skanarm_set_default_type_attributes (tree type)
304790075Sobrien{
304890075Sobrien  /* Add __attribute__ ((long_call)) to all functions, when
304990075Sobrien     inside #pragma long_calls or __attribute__ ((short_call)),
305090075Sobrien     when inside #pragma no_long_calls.  */
305190075Sobrien  if (TREE_CODE (type) == FUNCTION_TYPE || TREE_CODE (type) == METHOD_TYPE)
305290075Sobrien    {
305390075Sobrien      tree type_attr_list, attr_name;
305490075Sobrien      type_attr_list = TYPE_ATTRIBUTES (type);
305590075Sobrien
305690075Sobrien      if (arm_pragma_long_calls == LONG)
305790075Sobrien 	attr_name = get_identifier ("long_call");
305890075Sobrien      else if (arm_pragma_long_calls == SHORT)
305990075Sobrien 	attr_name = get_identifier ("short_call");
306090075Sobrien      else
306190075Sobrien 	return;
306290075Sobrien
306390075Sobrien      type_attr_list = tree_cons (attr_name, NULL_TREE, type_attr_list);
306490075Sobrien      TYPE_ATTRIBUTES (type) = type_attr_list;
306590075Sobrien    }
306690075Sobrien}
306790075Sobrien
306890075Sobrien/* Return 1 if the operand is a SYMBOL_REF for a function known to be
3069132718Skan   defined within the current compilation unit.  If this cannot be
307090075Sobrien   determined, then 0 is returned.  */
307190075Sobrienstatic int
3072132718Skancurrent_file_function_operand (rtx sym_ref)
307390075Sobrien{
307490075Sobrien  /* This is a bit of a fib.  A function will have a short call flag
307590075Sobrien     applied to its name if it has the short call attribute, or it has
307690075Sobrien     already been defined within the current compilation unit.  */
307790075Sobrien  if (ENCODED_SHORT_CALL_ATTR_P (XSTR (sym_ref, 0)))
307890075Sobrien    return 1;
307990075Sobrien
308090075Sobrien  /* The current function is always defined within the current compilation
3081169689Skan     unit.  If it s a weak definition however, then this may not be the real
308290075Sobrien     definition of the function, and so we have to say no.  */
308390075Sobrien  if (sym_ref == XEXP (DECL_RTL (current_function_decl), 0)
308490075Sobrien      && !DECL_WEAK (current_function_decl))
308590075Sobrien    return 1;
308690075Sobrien
308790075Sobrien  /* We cannot make the determination - default to returning 0.  */
308890075Sobrien  return 0;
308990075Sobrien}
309090075Sobrien
3091117395Skan/* Return nonzero if a 32 bit "long_call" should be generated for
309290075Sobrien   this call.  We generate a long_call if the function:
309390075Sobrien
309490075Sobrien        a.  has an __attribute__((long call))
309590075Sobrien     or b.  is within the scope of a #pragma long_calls
309690075Sobrien     or c.  the -mlong-calls command line switch has been specified
3097169689Skan         .  and either:
3098169689Skan                1. -ffunction-sections is in effect
3099169689Skan	     or 2. the current function has __attribute__ ((section))
3100169689Skan	     or 3. the target function has __attribute__ ((section))
310190075Sobrien
310290075Sobrien   However we do not generate a long call if the function:
3103169689Skan
310490075Sobrien        d.  has an __attribute__ ((short_call))
310590075Sobrien     or e.  is inside the scope of a #pragma no_long_calls
3106169689Skan     or f.  is defined within the current compilation unit.
3107169689Skan
310890075Sobrien   This function will be called by C fragments contained in the machine
3109169689Skan   description file.  SYM_REF and CALL_COOKIE correspond to the matched
311090075Sobrien   rtl operands.  CALL_SYMBOL is used to distinguish between
311190075Sobrien   two different callers of the function.  It is set to 1 in the
311290075Sobrien   "call_symbol" and "call_symbol_value" patterns and to 0 in the "call"
311390075Sobrien   and "call_value" patterns.  This is because of the difference in the
311490075Sobrien   SYM_REFs passed by these patterns.  */
311590075Sobrienint
3116132718Skanarm_is_longcall_p (rtx sym_ref, int call_cookie, int call_symbol)
311790075Sobrien{
311890075Sobrien  if (!call_symbol)
311990075Sobrien    {
312090075Sobrien      if (GET_CODE (sym_ref) != MEM)
312190075Sobrien	return 0;
312290075Sobrien
312390075Sobrien      sym_ref = XEXP (sym_ref, 0);
312490075Sobrien    }
312590075Sobrien
312690075Sobrien  if (GET_CODE (sym_ref) != SYMBOL_REF)
312790075Sobrien    return 0;
312890075Sobrien
312990075Sobrien  if (call_cookie & CALL_SHORT)
313090075Sobrien    return 0;
313190075Sobrien
3132169689Skan  if (TARGET_LONG_CALLS)
3133169689Skan    {
3134169689Skan      if (flag_function_sections
3135169689Skan	  || DECL_SECTION_NAME (current_function_decl))
3136169689Skan	/* c.3 is handled by the definition of the
3137169689Skan	   ARM_DECLARE_FUNCTION_SIZE macro.  */
3138169689Skan	return 1;
3139169689Skan    }
3140169689Skan
314190075Sobrien  if (current_file_function_operand (sym_ref))
314290075Sobrien    return 0;
3143169689Skan
314490075Sobrien  return (call_cookie & CALL_LONG)
314590075Sobrien    || ENCODED_LONG_CALL_ATTR_P (XSTR (sym_ref, 0))
314690075Sobrien    || TARGET_LONG_CALLS;
314790075Sobrien}
314890075Sobrien
3149117395Skan/* Return nonzero if it is ok to make a tail-call to DECL.  */
3150132718Skanstatic bool
3151132718Skanarm_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
315290075Sobrien{
315390075Sobrien  int call_type = TARGET_LONG_CALLS ? CALL_LONG : CALL_NORMAL;
315490075Sobrien
3155132718Skan  if (cfun->machine->sibcall_blocked)
3156132718Skan    return false;
3157132718Skan
315890075Sobrien  /* Never tailcall something for which we have no decl, or if we
315990075Sobrien     are in Thumb mode.  */
316090075Sobrien  if (decl == NULL || TARGET_THUMB)
3161132718Skan    return false;
316290075Sobrien
316390075Sobrien  /* Get the calling method.  */
316490075Sobrien  if (lookup_attribute ("short_call", TYPE_ATTRIBUTES (TREE_TYPE (decl))))
316590075Sobrien    call_type = CALL_SHORT;
316690075Sobrien  else if (lookup_attribute ("long_call", TYPE_ATTRIBUTES (TREE_TYPE (decl))))
316790075Sobrien    call_type = CALL_LONG;
316890075Sobrien
316990075Sobrien  /* Cannot tail-call to long calls, since these are out of range of
317090075Sobrien     a branch instruction.  However, if not compiling PIC, we know
317190075Sobrien     we can reach the symbol if it is in this compilation unit.  */
317290075Sobrien  if (call_type == CALL_LONG && (flag_pic || !TREE_ASM_WRITTEN (decl)))
3173132718Skan    return false;
317490075Sobrien
317590075Sobrien  /* If we are interworking and the function is not declared static
3176169689Skan     then we can't tail-call it unless we know that it exists in this
317790075Sobrien     compilation unit (since it might be a Thumb routine).  */
317890075Sobrien  if (TARGET_INTERWORK && TREE_PUBLIC (decl) && !TREE_ASM_WRITTEN (decl))
3179132718Skan    return false;
318090075Sobrien
318190075Sobrien  /* Never tailcall from an ISR routine - it needs a special exit sequence.  */
318290075Sobrien  if (IS_INTERRUPT (arm_current_func_type ()))
3183132718Skan    return false;
318490075Sobrien
318590075Sobrien  /* Everything else is ok.  */
3186132718Skan  return true;
318790075Sobrien}
318890075Sobrien
318990075Sobrien
3190132718Skan/* Addressing mode support functions.  */
3191132718Skan
3192132718Skan/* Return nonzero if X is a legitimate immediate operand when compiling
3193169689Skan   for PIC.  We know that X satisfies CONSTANT_P and flag_pic is true.  */
319490075Sobrienint
3195132718Skanlegitimate_pic_operand_p (rtx x)
319690075Sobrien{
3197169689Skan  if (GET_CODE (x) == SYMBOL_REF
3198169689Skan      || (GET_CODE (x) == CONST
3199169689Skan	  && GET_CODE (XEXP (x, 0)) == PLUS
3200169689Skan	  && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF))
320190075Sobrien    return 0;
320290075Sobrien
320390075Sobrien  return 1;
320490075Sobrien}
320590075Sobrien
320690075Sobrienrtx
3207132718Skanlegitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
320890075Sobrien{
320990075Sobrien  if (GET_CODE (orig) == SYMBOL_REF
321090075Sobrien      || GET_CODE (orig) == LABEL_REF)
321190075Sobrien    {
321290075Sobrien#ifndef AOF_ASSEMBLER
321390075Sobrien      rtx pic_ref, address;
321490075Sobrien#endif
321590075Sobrien      rtx insn;
321690075Sobrien      int subregs = 0;
321790075Sobrien
3218169689Skan      /* If this function doesn't have a pic register, create one now.
3219169689Skan	 A lot of the logic here is made obscure by the fact that this
3220169689Skan	 routine gets called as part of the rtx cost estimation
3221169689Skan	 process.  We don't want those calls to affect any assumptions
3222169689Skan	 about the real function; and further, we can't call
3223169689Skan	 entry_of_function() until we start the real expansion
3224169689Skan	 process.  */
3225169689Skan      if (!current_function_uses_pic_offset_table)
322690075Sobrien	{
3227169689Skan	  gcc_assert (!no_new_pseudos);
3228169689Skan	  if (arm_pic_register != INVALID_REGNUM)
3229169689Skan	    {
3230227391Sfabient	      if (!cfun->machine->pic_reg)
3231227391Sfabient		cfun->machine->pic_reg = gen_rtx_REG (Pmode, arm_pic_register);
3232169689Skan
3233169689Skan	      /* Play games to avoid marking the function as needing pic
3234169689Skan		 if we are being called as part of the cost-estimation
3235169689Skan		 process.  */
3236169689Skan	      if (!ir_type())
3237169689Skan		current_function_uses_pic_offset_table = 1;
3238169689Skan	    }
323990075Sobrien	  else
3240169689Skan	    {
3241169689Skan	      rtx seq;
324290075Sobrien
3243227391Sfabient	      if (!cfun->machine->pic_reg)
3244227391Sfabient		  cfun->machine->pic_reg = gen_reg_rtx (Pmode);
3245169689Skan
3246169689Skan	      /* Play games to avoid marking the function as needing pic
3247169689Skan		 if we are being called as part of the cost-estimation
3248169689Skan		 process.  */
3249169689Skan	      if (!ir_type())
3250169689Skan		{
3251169689Skan		  current_function_uses_pic_offset_table = 1;
3252169689Skan		  start_sequence ();
3253169689Skan
3254169689Skan		  arm_load_pic_register (0UL);
3255169689Skan
3256169689Skan		  seq = get_insns ();
3257169689Skan		  end_sequence ();
3258169689Skan		  emit_insn_after (seq, entry_of_function ());
3259169689Skan		}
3260169689Skan	    }
3261169689Skan	}
3262169689Skan
3263169689Skan      if (reg == 0)
3264169689Skan	{
3265169689Skan	  gcc_assert (!no_new_pseudos);
3266169689Skan	  reg = gen_reg_rtx (Pmode);
3267169689Skan
326890075Sobrien	  subregs = 1;
326990075Sobrien	}
327090075Sobrien
327190075Sobrien#ifdef AOF_ASSEMBLER
327290075Sobrien      /* The AOF assembler can generate relocations for these directly, and
327390075Sobrien	 understands that the PIC register has to be added into the offset.  */
327490075Sobrien      insn = emit_insn (gen_pic_load_addr_based (reg, orig));
327590075Sobrien#else
327690075Sobrien      if (subregs)
327790075Sobrien	address = gen_reg_rtx (Pmode);
327890075Sobrien      else
327990075Sobrien	address = reg;
328090075Sobrien
328190075Sobrien      if (TARGET_ARM)
328290075Sobrien	emit_insn (gen_pic_load_addr_arm (address, orig));
328390075Sobrien      else
328490075Sobrien	emit_insn (gen_pic_load_addr_thumb (address, orig));
328590075Sobrien
328696263Sobrien      if ((GET_CODE (orig) == LABEL_REF
3287169689Skan	   || (GET_CODE (orig) == SYMBOL_REF &&
3288132718Skan	       SYMBOL_REF_LOCAL_P (orig)))
328996263Sobrien	  && NEED_GOT_RELOC)
3290169689Skan	pic_ref = gen_rtx_PLUS (Pmode, cfun->machine->pic_reg, address);
329190075Sobrien      else
329290075Sobrien	{
3293169689Skan	  pic_ref = gen_const_mem (Pmode,
3294169689Skan				   gen_rtx_PLUS (Pmode, cfun->machine->pic_reg,
3295169689Skan					         address));
329690075Sobrien	}
329790075Sobrien
329890075Sobrien      insn = emit_move_insn (reg, pic_ref);
329990075Sobrien#endif
330090075Sobrien      /* Put a REG_EQUAL note on this insn, so that it can be optimized
330190075Sobrien	 by loop.  */
330290075Sobrien      REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, orig,
330390075Sobrien					    REG_NOTES (insn));
330490075Sobrien      return reg;
330590075Sobrien    }
330690075Sobrien  else if (GET_CODE (orig) == CONST)
330790075Sobrien    {
330890075Sobrien      rtx base, offset;
330990075Sobrien
331090075Sobrien      if (GET_CODE (XEXP (orig, 0)) == PLUS
3311169689Skan	  && XEXP (XEXP (orig, 0), 0) == cfun->machine->pic_reg)
331290075Sobrien	return orig;
331390075Sobrien
3314169689Skan      if (GET_CODE (XEXP (orig, 0)) == UNSPEC
3315169689Skan	  && XINT (XEXP (orig, 0), 1) == UNSPEC_TLS)
3316169689Skan	return orig;
3317169689Skan
331890075Sobrien      if (reg == 0)
331990075Sobrien	{
3320169689Skan	  gcc_assert (!no_new_pseudos);
3321169689Skan	  reg = gen_reg_rtx (Pmode);
332290075Sobrien	}
332390075Sobrien
3324169689Skan      gcc_assert (GET_CODE (XEXP (orig, 0)) == PLUS);
332590075Sobrien
3326169689Skan      base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg);
3327169689Skan      offset = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode,
3328169689Skan				       base == reg ? 0 : reg);
3329169689Skan
333090075Sobrien      if (GET_CODE (offset) == CONST_INT)
333190075Sobrien	{
333290075Sobrien	  /* The base register doesn't really matter, we only want to
333390075Sobrien	     test the index for the appropriate mode.  */
3334169689Skan	  if (!arm_legitimate_index_p (mode, offset, SET, 0))
3335132718Skan	    {
3336169689Skan	      gcc_assert (!no_new_pseudos);
3337169689Skan	      offset = force_reg (Pmode, offset);
3338132718Skan	    }
333990075Sobrien
334090075Sobrien	  if (GET_CODE (offset) == CONST_INT)
334190075Sobrien	    return plus_constant (base, INTVAL (offset));
334290075Sobrien	}
334390075Sobrien
334490075Sobrien      if (GET_MODE_SIZE (mode) > 4
334590075Sobrien	  && (GET_MODE_CLASS (mode) == MODE_INT
334690075Sobrien	      || TARGET_SOFT_FLOAT))
334790075Sobrien	{
334890075Sobrien	  emit_insn (gen_addsi3 (reg, base, offset));
334990075Sobrien	  return reg;
335090075Sobrien	}
335190075Sobrien
335290075Sobrien      return gen_rtx_PLUS (Pmode, base, offset);
335390075Sobrien    }
335490075Sobrien
335590075Sobrien  return orig;
335690075Sobrien}
335790075Sobrien
3358169689Skan
3359169689Skan/* Find a spare low register to use during the prolog of a function.  */
3360169689Skan
3361169689Skanstatic int
3362169689Skanthumb_find_work_register (unsigned long pushed_regs_mask)
3363169689Skan{
3364169689Skan  int reg;
3365169689Skan
3366169689Skan  /* Check the argument registers first as these are call-used.  The
3367169689Skan     register allocation order means that sometimes r3 might be used
3368169689Skan     but earlier argument registers might not, so check them all.  */
3369169689Skan  for (reg = LAST_ARG_REGNUM; reg >= 0; reg --)
3370169689Skan    if (!regs_ever_live[reg])
3371169689Skan      return reg;
3372169689Skan
3373169689Skan  /* Before going on to check the call-saved registers we can try a couple
3374169689Skan     more ways of deducing that r3 is available.  The first is when we are
3375169689Skan     pushing anonymous arguments onto the stack and we have less than 4
3376169689Skan     registers worth of fixed arguments(*).  In this case r3 will be part of
3377169689Skan     the variable argument list and so we can be sure that it will be
3378169689Skan     pushed right at the start of the function.  Hence it will be available
3379169689Skan     for the rest of the prologue.
3380169689Skan     (*): ie current_function_pretend_args_size is greater than 0.  */
3381169689Skan  if (cfun->machine->uses_anonymous_args
3382169689Skan      && current_function_pretend_args_size > 0)
3383169689Skan    return LAST_ARG_REGNUM;
3384169689Skan
3385169689Skan  /* The other case is when we have fixed arguments but less than 4 registers
3386169689Skan     worth.  In this case r3 might be used in the body of the function, but
3387169689Skan     it is not being used to convey an argument into the function.  In theory
3388169689Skan     we could just check current_function_args_size to see how many bytes are
3389169689Skan     being passed in argument registers, but it seems that it is unreliable.
3390169689Skan     Sometimes it will have the value 0 when in fact arguments are being
3391169689Skan     passed.  (See testcase execute/20021111-1.c for an example).  So we also
3392169689Skan     check the args_info.nregs field as well.  The problem with this field is
3393169689Skan     that it makes no allowances for arguments that are passed to the
3394169689Skan     function but which are not used.  Hence we could miss an opportunity
3395169689Skan     when a function has an unused argument in r3.  But it is better to be
3396169689Skan     safe than to be sorry.  */
3397169689Skan  if (! cfun->machine->uses_anonymous_args
3398169689Skan      && current_function_args_size >= 0
3399169689Skan      && current_function_args_size <= (LAST_ARG_REGNUM * UNITS_PER_WORD)
3400169689Skan      && cfun->args_info.nregs < 4)
3401169689Skan    return LAST_ARG_REGNUM;
3402169689Skan
3403169689Skan  /* Otherwise look for a call-saved register that is going to be pushed.  */
3404169689Skan  for (reg = LAST_LO_REGNUM; reg > LAST_ARG_REGNUM; reg --)
3405169689Skan    if (pushed_regs_mask & (1 << reg))
3406169689Skan      return reg;
3407169689Skan
3408169689Skan  /* Something went wrong - thumb_compute_save_reg_mask()
3409169689Skan     should have arranged for a suitable register to be pushed.  */
3410169689Skan  gcc_unreachable ();
3411169689Skan}
3412169689Skan
3413169689Skanstatic GTY(()) int pic_labelno;
3414169689Skan
3415169689Skan/* Generate code to load the PIC register.  In thumb mode SCRATCH is a
3416169689Skan   low register.  */
3417169689Skan
341890075Sobrienvoid
3419169689Skanarm_load_pic_register (unsigned long saved_regs ATTRIBUTE_UNUSED)
342090075Sobrien{
342190075Sobrien#ifndef AOF_ASSEMBLER
3422169689Skan  rtx l1, labelno, pic_tmp, pic_tmp2, pic_rtx;
342390075Sobrien  rtx global_offset_table;
342490075Sobrien
342590075Sobrien  if (current_function_uses_pic_offset_table == 0 || TARGET_SINGLE_PIC_BASE)
342690075Sobrien    return;
342790075Sobrien
3428169689Skan  gcc_assert (flag_pic);
342990075Sobrien
3430169689Skan  /* We use an UNSPEC rather than a LABEL_REF because this label never appears
3431169689Skan     in the code stream.  */
343290075Sobrien
3433169689Skan  labelno = GEN_INT (pic_labelno++);
3434169689Skan  l1 = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, labelno), UNSPEC_PIC_LABEL);
3435169689Skan  l1 = gen_rtx_CONST (VOIDmode, l1);
3436169689Skan
343790075Sobrien  global_offset_table = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
343890075Sobrien  /* On the ARM the PC register contains 'dot + 8' at the time of the
343990075Sobrien     addition, on the Thumb it is 'dot + 4'.  */
3440169689Skan  pic_tmp = plus_constant (l1, TARGET_ARM ? 8 : 4);
344190075Sobrien  if (GOT_PCREL)
344290075Sobrien    pic_tmp2 = gen_rtx_CONST (VOIDmode,
344390075Sobrien			    gen_rtx_PLUS (Pmode, global_offset_table, pc_rtx));
344490075Sobrien  else
344590075Sobrien    pic_tmp2 = gen_rtx_CONST (VOIDmode, global_offset_table);
344690075Sobrien
344790075Sobrien  pic_rtx = gen_rtx_CONST (Pmode, gen_rtx_MINUS (Pmode, pic_tmp2, pic_tmp));
3448169689Skan
344990075Sobrien  if (TARGET_ARM)
345090075Sobrien    {
3451169689Skan      emit_insn (gen_pic_load_addr_arm (cfun->machine->pic_reg, pic_rtx));
3452169689Skan      emit_insn (gen_pic_add_dot_plus_eight (cfun->machine->pic_reg,
3453169689Skan					     cfun->machine->pic_reg, labelno));
345490075Sobrien    }
345590075Sobrien  else
345690075Sobrien    {
3457169689Skan      if (arm_pic_register != INVALID_REGNUM
3458169689Skan	  && REGNO (cfun->machine->pic_reg) > LAST_LO_REGNUM)
3459169689Skan	{
3460169689Skan	  /* We will have pushed the pic register, so we should always be
3461169689Skan	     able to find a work register.  */
3462169689Skan	  pic_tmp = gen_rtx_REG (SImode,
3463169689Skan				 thumb_find_work_register (saved_regs));
3464169689Skan	  emit_insn (gen_pic_load_addr_thumb (pic_tmp, pic_rtx));
3465169689Skan	  emit_insn (gen_movsi (pic_offset_table_rtx, pic_tmp));
3466169689Skan	}
3467169689Skan      else
3468169689Skan	emit_insn (gen_pic_load_addr_thumb (cfun->machine->pic_reg, pic_rtx));
3469169689Skan      emit_insn (gen_pic_add_dot_plus_four (cfun->machine->pic_reg,
3470169689Skan					    cfun->machine->pic_reg, labelno));
347190075Sobrien    }
347290075Sobrien
347390075Sobrien  /* Need to emit this whether or not we obey regdecls,
347490075Sobrien     since setjmp/longjmp can cause life info to screw up.  */
3475169689Skan  emit_insn (gen_rtx_USE (VOIDmode, cfun->machine->pic_reg));
347690075Sobrien#endif /* AOF_ASSEMBLER */
347790075Sobrien}
347890075Sobrien
3479169689Skan
3480132718Skan/* Return nonzero if X is valid as an ARM state addressing register.  */
3481132718Skanstatic int
3482132718Skanarm_address_register_rtx_p (rtx x, int strict_p)
3483132718Skan{
3484132718Skan  int regno;
3485132718Skan
3486132718Skan  if (GET_CODE (x) != REG)
3487132718Skan    return 0;
3488132718Skan
3489132718Skan  regno = REGNO (x);
3490132718Skan
3491132718Skan  if (strict_p)
3492132718Skan    return ARM_REGNO_OK_FOR_BASE_P (regno);
3493132718Skan
3494132718Skan  return (regno <= LAST_ARM_REGNUM
3495132718Skan	  || regno >= FIRST_PSEUDO_REGISTER
3496132718Skan	  || regno == FRAME_POINTER_REGNUM
3497132718Skan	  || regno == ARG_POINTER_REGNUM);
3498132718Skan}
3499132718Skan
3500169689Skan/* Return TRUE if this rtx is the difference of a symbol and a label,
3501169689Skan   and will reduce to a PC-relative relocation in the object file.
3502169689Skan   Expressions like this can be left alone when generating PIC, rather
3503169689Skan   than forced through the GOT.  */
3504169689Skanstatic int
3505169689Skanpcrel_constant_p (rtx x)
3506169689Skan{
3507169689Skan  if (GET_CODE (x) == MINUS)
3508169689Skan    return symbol_mentioned_p (XEXP (x, 0)) && label_mentioned_p (XEXP (x, 1));
3509169689Skan
3510169689Skan  return FALSE;
3511169689Skan}
3512169689Skan
3513132718Skan/* Return nonzero if X is a valid ARM state address operand.  */
3514132718Skanint
3515169689Skanarm_legitimate_address_p (enum machine_mode mode, rtx x, RTX_CODE outer,
3516169689Skan			  int strict_p)
3517132718Skan{
3518169689Skan  bool use_ldrd;
3519169689Skan  enum rtx_code code = GET_CODE (x);
3520169689Skan
3521132718Skan  if (arm_address_register_rtx_p (x, strict_p))
3522132718Skan    return 1;
3523132718Skan
3524169689Skan  use_ldrd = (TARGET_LDRD
3525169689Skan	      && (mode == DImode
3526169689Skan		  || (mode == DFmode && (TARGET_SOFT_FLOAT || TARGET_VFP))));
3527169689Skan
3528169689Skan  if (code == POST_INC || code == PRE_DEC
3529169689Skan      || ((code == PRE_INC || code == POST_DEC)
3530169689Skan	  && (use_ldrd || GET_MODE_SIZE (mode) <= 4)))
3531132718Skan    return arm_address_register_rtx_p (XEXP (x, 0), strict_p);
3532132718Skan
3533169689Skan  else if ((code == POST_MODIFY || code == PRE_MODIFY)
3534132718Skan	   && arm_address_register_rtx_p (XEXP (x, 0), strict_p)
3535132718Skan	   && GET_CODE (XEXP (x, 1)) == PLUS
3536132718Skan	   && rtx_equal_p (XEXP (XEXP (x, 1), 0), XEXP (x, 0)))
3537169689Skan    {
3538169689Skan      rtx addend = XEXP (XEXP (x, 1), 1);
3539132718Skan
3540169689Skan      /* Don't allow ldrd post increment by register because it's hard
3541169689Skan	 to fixup invalid register choices.  */
3542169689Skan      if (use_ldrd
3543169689Skan	  && GET_CODE (x) == POST_MODIFY
3544169689Skan	  && GET_CODE (addend) == REG)
3545169689Skan	return 0;
3546169689Skan
3547169689Skan      return ((use_ldrd || GET_MODE_SIZE (mode) <= 4)
3548169689Skan	      && arm_legitimate_index_p (mode, addend, outer, strict_p));
3549169689Skan    }
3550169689Skan
3551132718Skan  /* After reload constants split into minipools will have addresses
3552132718Skan     from a LABEL_REF.  */
3553132718Skan  else if (reload_completed
3554169689Skan	   && (code == LABEL_REF
3555169689Skan	       || (code == CONST
3556132718Skan		   && GET_CODE (XEXP (x, 0)) == PLUS
3557132718Skan		   && GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF
3558132718Skan		   && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)))
3559132718Skan    return 1;
3560132718Skan
3561132718Skan  else if (mode == TImode)
3562132718Skan    return 0;
3563132718Skan
3564169689Skan  else if (code == PLUS)
3565132718Skan    {
3566132718Skan      rtx xop0 = XEXP (x, 0);
3567132718Skan      rtx xop1 = XEXP (x, 1);
3568132718Skan
3569132718Skan      return ((arm_address_register_rtx_p (xop0, strict_p)
3570169689Skan	       && arm_legitimate_index_p (mode, xop1, outer, strict_p))
3571132718Skan	      || (arm_address_register_rtx_p (xop1, strict_p)
3572169689Skan		  && arm_legitimate_index_p (mode, xop0, outer, strict_p)));
3573132718Skan    }
3574132718Skan
3575132718Skan#if 0
3576132718Skan  /* Reload currently can't handle MINUS, so disable this for now */
3577132718Skan  else if (GET_CODE (x) == MINUS)
3578132718Skan    {
3579132718Skan      rtx xop0 = XEXP (x, 0);
3580132718Skan      rtx xop1 = XEXP (x, 1);
3581132718Skan
3582132718Skan      return (arm_address_register_rtx_p (xop0, strict_p)
3583169689Skan	      && arm_legitimate_index_p (mode, xop1, outer, strict_p));
3584132718Skan    }
3585132718Skan#endif
3586132718Skan
3587132718Skan  else if (GET_MODE_CLASS (mode) != MODE_FLOAT
3588169689Skan	   && code == SYMBOL_REF
3589132718Skan	   && CONSTANT_POOL_ADDRESS_P (x)
3590132718Skan	   && ! (flag_pic
3591169689Skan		 && symbol_mentioned_p (get_pool_constant (x))
3592169689Skan		 && ! pcrel_constant_p (get_pool_constant (x))))
3593132718Skan    return 1;
3594132718Skan
3595132718Skan  return 0;
3596132718Skan}
3597132718Skan
3598132718Skan/* Return nonzero if INDEX is valid for an address index operand in
3599132718Skan   ARM state.  */
3600132718Skanstatic int
3601169689Skanarm_legitimate_index_p (enum machine_mode mode, rtx index, RTX_CODE outer,
3602169689Skan			int strict_p)
3603132718Skan{
3604132718Skan  HOST_WIDE_INT range;
3605132718Skan  enum rtx_code code = GET_CODE (index);
3606132718Skan
3607169689Skan  /* Standard coprocessor addressing modes.  */
3608169689Skan  if (TARGET_HARD_FLOAT
3609169689Skan      && (TARGET_FPA || TARGET_MAVERICK)
3610169689Skan      && (GET_MODE_CLASS (mode) == MODE_FLOAT
3611169689Skan	  || (TARGET_MAVERICK && mode == DImode)))
3612132718Skan    return (code == CONST_INT && INTVAL (index) < 1024
3613132718Skan	    && INTVAL (index) > -1024
3614132718Skan	    && (INTVAL (index) & 3) == 0);
3615132718Skan
3616169689Skan  if (TARGET_REALLY_IWMMXT && VALID_IWMMXT_REG_MODE (mode))
3617169689Skan    {
3618169689Skan      /* For DImode assume values will usually live in core regs
3619169689Skan	 and only allow LDRD addressing modes.  */
3620169689Skan      if (!TARGET_LDRD || mode != DImode)
3621169689Skan	return (code == CONST_INT
3622169689Skan		&& INTVAL (index) < 1024
3623169689Skan		&& INTVAL (index) > -1024
3624169689Skan		&& (INTVAL (index) & 3) == 0);
3625169689Skan    }
3626132718Skan
3627132718Skan  if (arm_address_register_rtx_p (index, strict_p)
3628169689Skan      && (GET_MODE_SIZE (mode) <= 4))
3629132718Skan    return 1;
3630132718Skan
3631169689Skan  if (mode == DImode || mode == DFmode)
3632132718Skan    {
3633169689Skan      if (code == CONST_INT)
3634169689Skan	{
3635169689Skan	  HOST_WIDE_INT val = INTVAL (index);
3636132718Skan
3637169689Skan	  if (TARGET_LDRD)
3638169689Skan	    return val > -256 && val < 256;
3639169689Skan	  else
3640169689Skan	    return val > -4096 && val < 4092;
3641169689Skan	}
3642169689Skan
3643169689Skan      return TARGET_LDRD && arm_address_register_rtx_p (index, strict_p);
3644132718Skan    }
3645132718Skan
3646132718Skan  if (GET_MODE_SIZE (mode) <= 4
3647169689Skan      && ! (arm_arch4
3648169689Skan	    && (mode == HImode
3649169689Skan		|| (mode == QImode && outer == SIGN_EXTEND))))
3650132718Skan    {
3651169689Skan      if (code == MULT)
3652169689Skan	{
3653169689Skan	  rtx xiop0 = XEXP (index, 0);
3654169689Skan	  rtx xiop1 = XEXP (index, 1);
3655132718Skan
3656169689Skan	  return ((arm_address_register_rtx_p (xiop0, strict_p)
3657169689Skan		   && power_of_two_operand (xiop1, SImode))
3658169689Skan		  || (arm_address_register_rtx_p (xiop1, strict_p)
3659169689Skan		      && power_of_two_operand (xiop0, SImode)));
3660169689Skan	}
3661169689Skan      else if (code == LSHIFTRT || code == ASHIFTRT
3662169689Skan	       || code == ASHIFT || code == ROTATERT)
3663169689Skan	{
3664169689Skan	  rtx op = XEXP (index, 1);
3665169689Skan
3666169689Skan	  return (arm_address_register_rtx_p (XEXP (index, 0), strict_p)
3667169689Skan		  && GET_CODE (op) == CONST_INT
3668169689Skan		  && INTVAL (op) > 0
3669169689Skan		  && INTVAL (op) <= 31);
3670169689Skan	}
3671132718Skan    }
3672132718Skan
3673169689Skan  /* For ARM v4 we may be doing a sign-extend operation during the
3674169689Skan     load.  */
3675132718Skan  if (arm_arch4)
3676169689Skan    {
3677169689Skan      if (mode == HImode || (outer == SIGN_EXTEND && mode == QImode))
3678169689Skan	range = 256;
3679169689Skan      else
3680169689Skan	range = 4096;
3681169689Skan    }
3682132718Skan  else
3683132718Skan    range = (mode == HImode) ? 4095 : 4096;
3684132718Skan
3685132718Skan  return (code == CONST_INT
3686132718Skan	  && INTVAL (index) < range
3687132718Skan	  && INTVAL (index) > -range);
3688132718Skan}
3689132718Skan
3690132718Skan/* Return nonzero if X is valid as a Thumb state base register.  */
3691132718Skanstatic int
3692132718Skanthumb_base_register_rtx_p (rtx x, enum machine_mode mode, int strict_p)
3693132718Skan{
3694132718Skan  int regno;
3695132718Skan
3696132718Skan  if (GET_CODE (x) != REG)
3697132718Skan    return 0;
3698132718Skan
3699132718Skan  regno = REGNO (x);
3700132718Skan
3701132718Skan  if (strict_p)
3702132718Skan    return THUMB_REGNO_MODE_OK_FOR_BASE_P (regno, mode);
3703132718Skan
3704132718Skan  return (regno <= LAST_LO_REGNUM
3705132718Skan	  || regno > LAST_VIRTUAL_REGISTER
3706132718Skan	  || regno == FRAME_POINTER_REGNUM
3707132718Skan	  || (GET_MODE_SIZE (mode) >= 4
3708132718Skan	      && (regno == STACK_POINTER_REGNUM
3709132718Skan		  || regno >= FIRST_PSEUDO_REGISTER
3710132718Skan		  || x == hard_frame_pointer_rtx
3711132718Skan		  || x == arg_pointer_rtx)));
3712132718Skan}
3713132718Skan
3714132718Skan/* Return nonzero if x is a legitimate index register.  This is the case
3715132718Skan   for any base register that can access a QImode object.  */
3716132718Skaninline static int
3717132718Skanthumb_index_register_rtx_p (rtx x, int strict_p)
3718132718Skan{
3719132718Skan  return thumb_base_register_rtx_p (x, QImode, strict_p);
3720132718Skan}
3721132718Skan
3722132718Skan/* Return nonzero if x is a legitimate Thumb-state address.
3723169689Skan
3724132718Skan   The AP may be eliminated to either the SP or the FP, so we use the
3725132718Skan   least common denominator, e.g. SImode, and offsets from 0 to 64.
3726132718Skan
3727132718Skan   ??? Verify whether the above is the right approach.
3728132718Skan
3729132718Skan   ??? Also, the FP may be eliminated to the SP, so perhaps that
3730132718Skan   needs special handling also.
3731132718Skan
3732132718Skan   ??? Look at how the mips16 port solves this problem.  It probably uses
3733132718Skan   better ways to solve some of these problems.
3734132718Skan
3735132718Skan   Although it is not incorrect, we don't accept QImode and HImode
3736132718Skan   addresses based on the frame pointer or arg pointer until the
3737132718Skan   reload pass starts.  This is so that eliminating such addresses
3738132718Skan   into stack based ones won't produce impossible code.  */
3739132718Skanint
3740132718Skanthumb_legitimate_address_p (enum machine_mode mode, rtx x, int strict_p)
3741132718Skan{
3742132718Skan  /* ??? Not clear if this is right.  Experiment.  */
3743132718Skan  if (GET_MODE_SIZE (mode) < 4
3744132718Skan      && !(reload_in_progress || reload_completed)
3745132718Skan      && (reg_mentioned_p (frame_pointer_rtx, x)
3746132718Skan	  || reg_mentioned_p (arg_pointer_rtx, x)
3747132718Skan	  || reg_mentioned_p (virtual_incoming_args_rtx, x)
3748132718Skan	  || reg_mentioned_p (virtual_outgoing_args_rtx, x)
3749132718Skan	  || reg_mentioned_p (virtual_stack_dynamic_rtx, x)
3750132718Skan	  || reg_mentioned_p (virtual_stack_vars_rtx, x)))
3751132718Skan    return 0;
3752132718Skan
3753132718Skan  /* Accept any base register.  SP only in SImode or larger.  */
3754132718Skan  else if (thumb_base_register_rtx_p (x, mode, strict_p))
3755132718Skan    return 1;
3756132718Skan
3757132718Skan  /* This is PC relative data before arm_reorg runs.  */
3758132718Skan  else if (GET_MODE_SIZE (mode) >= 4 && CONSTANT_P (x)
3759132718Skan	   && GET_CODE (x) == SYMBOL_REF
3760169689Skan           && CONSTANT_POOL_ADDRESS_P (x) && !flag_pic)
3761132718Skan    return 1;
3762132718Skan
3763132718Skan  /* This is PC relative data after arm_reorg runs.  */
3764132718Skan  else if (GET_MODE_SIZE (mode) >= 4 && reload_completed
3765132718Skan	   && (GET_CODE (x) == LABEL_REF
3766132718Skan	       || (GET_CODE (x) == CONST
3767132718Skan		   && GET_CODE (XEXP (x, 0)) == PLUS
3768132718Skan		   && GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF
3769132718Skan		   && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)))
3770132718Skan    return 1;
3771132718Skan
3772132718Skan  /* Post-inc indexing only supported for SImode and larger.  */
3773132718Skan  else if (GET_CODE (x) == POST_INC && GET_MODE_SIZE (mode) >= 4
3774132718Skan	   && thumb_index_register_rtx_p (XEXP (x, 0), strict_p))
3775132718Skan    return 1;
3776132718Skan
3777132718Skan  else if (GET_CODE (x) == PLUS)
3778132718Skan    {
3779132718Skan      /* REG+REG address can be any two index registers.  */
3780132718Skan      /* We disallow FRAME+REG addressing since we know that FRAME
3781132718Skan	 will be replaced with STACK, and SP relative addressing only
3782132718Skan	 permits SP+OFFSET.  */
3783132718Skan      if (GET_MODE_SIZE (mode) <= 4
3784132718Skan	  && XEXP (x, 0) != frame_pointer_rtx
3785132718Skan	  && XEXP (x, 1) != frame_pointer_rtx
3786132718Skan	  && thumb_index_register_rtx_p (XEXP (x, 0), strict_p)
3787132718Skan	  && thumb_index_register_rtx_p (XEXP (x, 1), strict_p))
3788132718Skan	return 1;
3789132718Skan
3790132718Skan      /* REG+const has 5-7 bit offset for non-SP registers.  */
3791132718Skan      else if ((thumb_index_register_rtx_p (XEXP (x, 0), strict_p)
3792132718Skan		|| XEXP (x, 0) == arg_pointer_rtx)
3793132718Skan	       && GET_CODE (XEXP (x, 1)) == CONST_INT
3794132718Skan	       && thumb_legitimate_offset_p (mode, INTVAL (XEXP (x, 1))))
3795132718Skan	return 1;
3796132718Skan
3797132718Skan      /* REG+const has 10 bit offset for SP, but only SImode and
3798132718Skan	 larger is supported.  */
3799132718Skan      /* ??? Should probably check for DI/DFmode overflow here
3800132718Skan	 just like GO_IF_LEGITIMATE_OFFSET does.  */
3801132718Skan      else if (GET_CODE (XEXP (x, 0)) == REG
3802132718Skan	       && REGNO (XEXP (x, 0)) == STACK_POINTER_REGNUM
3803132718Skan	       && GET_MODE_SIZE (mode) >= 4
3804132718Skan	       && GET_CODE (XEXP (x, 1)) == CONST_INT
3805132718Skan	       && INTVAL (XEXP (x, 1)) >= 0
3806132718Skan	       && INTVAL (XEXP (x, 1)) + GET_MODE_SIZE (mode) <= 1024
3807132718Skan	       && (INTVAL (XEXP (x, 1)) & 3) == 0)
3808132718Skan	return 1;
3809132718Skan
3810132718Skan      else if (GET_CODE (XEXP (x, 0)) == REG
3811132718Skan	       && REGNO (XEXP (x, 0)) == FRAME_POINTER_REGNUM
3812132718Skan	       && GET_MODE_SIZE (mode) >= 4
3813132718Skan	       && GET_CODE (XEXP (x, 1)) == CONST_INT
3814132718Skan	       && (INTVAL (XEXP (x, 1)) & 3) == 0)
3815132718Skan	return 1;
3816132718Skan    }
3817132718Skan
3818132718Skan  else if (GET_MODE_CLASS (mode) != MODE_FLOAT
3819132718Skan	   && GET_MODE_SIZE (mode) == 4
3820132718Skan	   && GET_CODE (x) == SYMBOL_REF
3821132718Skan	   && CONSTANT_POOL_ADDRESS_P (x)
3822169689Skan	   && ! (flag_pic
3823169689Skan		 && symbol_mentioned_p (get_pool_constant (x))
3824169689Skan		 && ! pcrel_constant_p (get_pool_constant (x))))
3825132718Skan    return 1;
3826132718Skan
3827132718Skan  return 0;
3828132718Skan}
3829132718Skan
3830132718Skan/* Return nonzero if VAL can be used as an offset in a Thumb-state address
3831132718Skan   instruction of mode MODE.  */
3832132718Skanint
3833132718Skanthumb_legitimate_offset_p (enum machine_mode mode, HOST_WIDE_INT val)
3834132718Skan{
3835132718Skan  switch (GET_MODE_SIZE (mode))
3836132718Skan    {
3837132718Skan    case 1:
3838132718Skan      return val >= 0 && val < 32;
3839132718Skan
3840132718Skan    case 2:
3841132718Skan      return val >= 0 && val < 64 && (val & 1) == 0;
3842132718Skan
3843132718Skan    default:
3844132718Skan      return (val >= 0
3845132718Skan	      && (val + GET_MODE_SIZE (mode)) <= 128
3846132718Skan	      && (val & 3) == 0);
3847132718Skan    }
3848132718Skan}
3849132718Skan
3850169689Skan/* Build the SYMBOL_REF for __tls_get_addr.  */
3851169689Skan
3852169689Skanstatic GTY(()) rtx tls_get_addr_libfunc;
3853169689Skan
3854169689Skanstatic rtx
3855169689Skanget_tls_get_addr (void)
3856169689Skan{
3857169689Skan  if (!tls_get_addr_libfunc)
3858169689Skan    tls_get_addr_libfunc = init_one_libfunc ("__tls_get_addr");
3859169689Skan  return tls_get_addr_libfunc;
3860169689Skan}
3861169689Skan
3862169689Skanstatic rtx
3863169689Skanarm_load_tp (rtx target)
3864169689Skan{
3865169689Skan  if (!target)
3866169689Skan    target = gen_reg_rtx (SImode);
3867169689Skan
3868169689Skan  if (TARGET_HARD_TP)
3869169689Skan    {
3870169689Skan      /* Can return in any reg.  */
3871169689Skan      emit_insn (gen_load_tp_hard (target));
3872169689Skan    }
3873169689Skan  else
3874169689Skan    {
3875169689Skan      /* Always returned in r0.  Immediately copy the result into a pseudo,
3876169689Skan	 otherwise other uses of r0 (e.g. setting up function arguments) may
3877169689Skan	 clobber the value.  */
3878169689Skan
3879169689Skan      rtx tmp;
3880169689Skan
3881169689Skan      emit_insn (gen_load_tp_soft ());
3882169689Skan
3883169689Skan      tmp = gen_rtx_REG (SImode, 0);
3884169689Skan      emit_move_insn (target, tmp);
3885169689Skan    }
3886169689Skan  return target;
3887169689Skan}
3888169689Skan
3889169689Skanstatic rtx
3890169689Skanload_tls_operand (rtx x, rtx reg)
3891169689Skan{
3892169689Skan  rtx tmp;
3893169689Skan
3894169689Skan  if (reg == NULL_RTX)
3895169689Skan    reg = gen_reg_rtx (SImode);
3896169689Skan
3897169689Skan  tmp = gen_rtx_CONST (SImode, x);
3898169689Skan
3899169689Skan  emit_move_insn (reg, tmp);
3900169689Skan
3901169689Skan  return reg;
3902169689Skan}
3903169689Skan
3904169689Skanstatic rtx
3905169689Skanarm_call_tls_get_addr (rtx x, rtx reg, rtx *valuep, int reloc)
3906169689Skan{
3907169689Skan  rtx insns, label, labelno, sum;
3908169689Skan
3909169689Skan  start_sequence ();
3910169689Skan
3911169689Skan  labelno = GEN_INT (pic_labelno++);
3912169689Skan  label = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, labelno), UNSPEC_PIC_LABEL);
3913169689Skan  label = gen_rtx_CONST (VOIDmode, label);
3914169689Skan
3915169689Skan  sum = gen_rtx_UNSPEC (Pmode,
3916169689Skan			gen_rtvec (4, x, GEN_INT (reloc), label,
3917169689Skan				   GEN_INT (TARGET_ARM ? 8 : 4)),
3918169689Skan			UNSPEC_TLS);
3919169689Skan  reg = load_tls_operand (sum, reg);
3920169689Skan
3921169689Skan  if (TARGET_ARM)
3922169689Skan    emit_insn (gen_pic_add_dot_plus_eight (reg, reg, labelno));
3923169689Skan  else
3924169689Skan    emit_insn (gen_pic_add_dot_plus_four (reg, reg, labelno));
3925169689Skan
3926169689Skan  *valuep = emit_library_call_value (get_tls_get_addr (), NULL_RTX, LCT_PURE, /* LCT_CONST?  */
3927169689Skan				     Pmode, 1, reg, Pmode);
3928169689Skan
3929169689Skan  insns = get_insns ();
3930169689Skan  end_sequence ();
3931169689Skan
3932169689Skan  return insns;
3933169689Skan}
3934169689Skan
3935169689Skanrtx
3936169689Skanlegitimize_tls_address (rtx x, rtx reg)
3937169689Skan{
3938169689Skan  rtx dest, tp, label, labelno, sum, insns, ret, eqv, addend;
3939169689Skan  unsigned int model = SYMBOL_REF_TLS_MODEL (x);
3940169689Skan
3941169689Skan  switch (model)
3942169689Skan    {
3943169689Skan    case TLS_MODEL_GLOBAL_DYNAMIC:
3944169689Skan      insns = arm_call_tls_get_addr (x, reg, &ret, TLS_GD32);
3945169689Skan      dest = gen_reg_rtx (Pmode);
3946169689Skan      emit_libcall_block (insns, dest, ret, x);
3947169689Skan      return dest;
3948169689Skan
3949169689Skan    case TLS_MODEL_LOCAL_DYNAMIC:
3950169689Skan      insns = arm_call_tls_get_addr (x, reg, &ret, TLS_LDM32);
3951169689Skan
3952169689Skan      /* Attach a unique REG_EQUIV, to allow the RTL optimizers to
3953169689Skan	 share the LDM result with other LD model accesses.  */
3954169689Skan      eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const1_rtx),
3955169689Skan			    UNSPEC_TLS);
3956169689Skan      dest = gen_reg_rtx (Pmode);
3957169689Skan      emit_libcall_block (insns, dest, ret, eqv);
3958169689Skan
3959169689Skan      /* Load the addend.  */
3960169689Skan      addend = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, x, GEN_INT (TLS_LDO32)),
3961169689Skan			       UNSPEC_TLS);
3962169689Skan      addend = force_reg (SImode, gen_rtx_CONST (SImode, addend));
3963169689Skan      return gen_rtx_PLUS (Pmode, dest, addend);
3964169689Skan
3965169689Skan    case TLS_MODEL_INITIAL_EXEC:
3966169689Skan      labelno = GEN_INT (pic_labelno++);
3967169689Skan      label = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, labelno), UNSPEC_PIC_LABEL);
3968169689Skan      label = gen_rtx_CONST (VOIDmode, label);
3969169689Skan      sum = gen_rtx_UNSPEC (Pmode,
3970169689Skan			    gen_rtvec (4, x, GEN_INT (TLS_IE32), label,
3971169689Skan				       GEN_INT (TARGET_ARM ? 8 : 4)),
3972169689Skan			    UNSPEC_TLS);
3973169689Skan      reg = load_tls_operand (sum, reg);
3974169689Skan
3975169689Skan      if (TARGET_ARM)
3976169689Skan	emit_insn (gen_tls_load_dot_plus_eight (reg, reg, labelno));
3977169689Skan      else
3978169689Skan	{
3979169689Skan	  emit_insn (gen_pic_add_dot_plus_four (reg, reg, labelno));
3980169689Skan	  emit_move_insn (reg, gen_const_mem (SImode, reg));
3981169689Skan	}
3982169689Skan
3983169689Skan      tp = arm_load_tp (NULL_RTX);
3984169689Skan
3985169689Skan      return gen_rtx_PLUS (Pmode, tp, reg);
3986169689Skan
3987169689Skan    case TLS_MODEL_LOCAL_EXEC:
3988169689Skan      tp = arm_load_tp (NULL_RTX);
3989169689Skan
3990169689Skan      reg = gen_rtx_UNSPEC (Pmode,
3991169689Skan			    gen_rtvec (2, x, GEN_INT (TLS_LE32)),
3992169689Skan			    UNSPEC_TLS);
3993169689Skan      reg = force_reg (SImode, gen_rtx_CONST (SImode, reg));
3994169689Skan
3995169689Skan      return gen_rtx_PLUS (Pmode, tp, reg);
3996169689Skan
3997169689Skan    default:
3998169689Skan      abort ();
3999169689Skan    }
4000169689Skan}
4001169689Skan
4002132718Skan/* Try machine-dependent ways of modifying an illegitimate address
4003132718Skan   to be legitimate.  If we find one, return the new, valid address.  */
4004132718Skanrtx
4005132718Skanarm_legitimize_address (rtx x, rtx orig_x, enum machine_mode mode)
4006132718Skan{
4007169689Skan  if (arm_tls_symbol_p (x))
4008169689Skan    return legitimize_tls_address (x, NULL_RTX);
4009169689Skan
4010132718Skan  if (GET_CODE (x) == PLUS)
4011132718Skan    {
4012132718Skan      rtx xop0 = XEXP (x, 0);
4013132718Skan      rtx xop1 = XEXP (x, 1);
4014132718Skan
4015132718Skan      if (CONSTANT_P (xop0) && !symbol_mentioned_p (xop0))
4016132718Skan	xop0 = force_reg (SImode, xop0);
4017132718Skan
4018132718Skan      if (CONSTANT_P (xop1) && !symbol_mentioned_p (xop1))
4019132718Skan	xop1 = force_reg (SImode, xop1);
4020132718Skan
4021132718Skan      if (ARM_BASE_REGISTER_RTX_P (xop0)
4022132718Skan	  && GET_CODE (xop1) == CONST_INT)
4023132718Skan	{
4024132718Skan	  HOST_WIDE_INT n, low_n;
4025132718Skan	  rtx base_reg, val;
4026132718Skan	  n = INTVAL (xop1);
4027132718Skan
4028169689Skan	  /* VFP addressing modes actually allow greater offsets, but for
4029169689Skan	     now we just stick with the lowest common denominator.  */
4030169689Skan	  if (mode == DImode
4031169689Skan	      || ((TARGET_SOFT_FLOAT || TARGET_VFP) && mode == DFmode))
4032132718Skan	    {
4033132718Skan	      low_n = n & 0x0f;
4034132718Skan	      n &= ~0x0f;
4035132718Skan	      if (low_n > 4)
4036132718Skan		{
4037132718Skan		  n += 16;
4038132718Skan		  low_n -= 16;
4039132718Skan		}
4040132718Skan	    }
4041132718Skan	  else
4042132718Skan	    {
4043132718Skan	      low_n = ((mode) == TImode ? 0
4044132718Skan		       : n >= 0 ? (n & 0xfff) : -((-n) & 0xfff));
4045132718Skan	      n -= low_n;
4046132718Skan	    }
4047132718Skan
4048132718Skan	  base_reg = gen_reg_rtx (SImode);
4049169689Skan	  val = force_operand (plus_constant (xop0, n), NULL_RTX);
4050132718Skan	  emit_move_insn (base_reg, val);
4051169689Skan	  x = plus_constant (base_reg, low_n);
4052132718Skan	}
4053132718Skan      else if (xop0 != XEXP (x, 0) || xop1 != XEXP (x, 1))
4054132718Skan	x = gen_rtx_PLUS (SImode, xop0, xop1);
4055132718Skan    }
4056132718Skan
4057132718Skan  /* XXX We don't allow MINUS any more -- see comment in
4058132718Skan     arm_legitimate_address_p ().  */
4059132718Skan  else if (GET_CODE (x) == MINUS)
4060132718Skan    {
4061132718Skan      rtx xop0 = XEXP (x, 0);
4062132718Skan      rtx xop1 = XEXP (x, 1);
4063132718Skan
4064132718Skan      if (CONSTANT_P (xop0))
4065132718Skan	xop0 = force_reg (SImode, xop0);
4066132718Skan
4067132718Skan      if (CONSTANT_P (xop1) && ! symbol_mentioned_p (xop1))
4068132718Skan	xop1 = force_reg (SImode, xop1);
4069132718Skan
4070132718Skan      if (xop0 != XEXP (x, 0) || xop1 != XEXP (x, 1))
4071132718Skan	x = gen_rtx_MINUS (SImode, xop0, xop1);
4072132718Skan    }
4073132718Skan
4074169689Skan  /* Make sure to take full advantage of the pre-indexed addressing mode
4075169689Skan     with absolute addresses which often allows for the base register to
4076169689Skan     be factorized for multiple adjacent memory references, and it might
4077169689Skan     even allows for the mini pool to be avoided entirely. */
4078169689Skan  else if (GET_CODE (x) == CONST_INT && optimize > 0)
4079169689Skan    {
4080169689Skan      unsigned int bits;
4081169689Skan      HOST_WIDE_INT mask, base, index;
4082169689Skan      rtx base_reg;
4083169689Skan
4084169689Skan      /* ldr and ldrb can use a 12 bit index, ldrsb and the rest can only
4085169689Skan         use a 8 bit index. So let's use a 12 bit index for SImode only and
4086169689Skan         hope that arm_gen_constant will enable ldrb to use more bits. */
4087169689Skan      bits = (mode == SImode) ? 12 : 8;
4088169689Skan      mask = (1 << bits) - 1;
4089169689Skan      base = INTVAL (x) & ~mask;
4090169689Skan      index = INTVAL (x) & mask;
4091169689Skan      if (bit_count (base & 0xffffffff) > (32 - bits)/2)
4092169689Skan        {
4093169689Skan	  /* It'll most probably be more efficient to generate the base
4094169689Skan	     with more bits set and use a negative index instead. */
4095169689Skan	  base |= mask;
4096169689Skan	  index -= mask;
4097169689Skan	}
4098169689Skan      base_reg = force_reg (SImode, GEN_INT (base));
4099169689Skan      x = plus_constant (base_reg, index);
4100169689Skan    }
4101169689Skan
4102132718Skan  if (flag_pic)
4103132718Skan    {
4104132718Skan      /* We need to find and carefully transform any SYMBOL and LABEL
4105132718Skan	 references; so go back to the original address expression.  */
4106132718Skan      rtx new_x = legitimize_pic_address (orig_x, mode, NULL_RTX);
4107132718Skan
4108132718Skan      if (new_x != orig_x)
4109132718Skan	x = new_x;
4110132718Skan    }
4111132718Skan
4112132718Skan  return x;
4113132718Skan}
4114132718Skan
4115169689Skan
4116169689Skan/* Try machine-dependent ways of modifying an illegitimate Thumb address
4117169689Skan   to be legitimate.  If we find one, return the new, valid address.  */
4118169689Skanrtx
4119169689Skanthumb_legitimize_address (rtx x, rtx orig_x, enum machine_mode mode)
4120169689Skan{
4121169689Skan  if (arm_tls_symbol_p (x))
4122169689Skan    return legitimize_tls_address (x, NULL_RTX);
4123169689Skan
4124169689Skan  if (GET_CODE (x) == PLUS
4125169689Skan      && GET_CODE (XEXP (x, 1)) == CONST_INT
4126169689Skan      && (INTVAL (XEXP (x, 1)) >= 32 * GET_MODE_SIZE (mode)
4127169689Skan	  || INTVAL (XEXP (x, 1)) < 0))
4128169689Skan    {
4129169689Skan      rtx xop0 = XEXP (x, 0);
4130169689Skan      rtx xop1 = XEXP (x, 1);
4131169689Skan      HOST_WIDE_INT offset = INTVAL (xop1);
4132169689Skan
4133169689Skan      /* Try and fold the offset into a biasing of the base register and
4134169689Skan	 then offsetting that.  Don't do this when optimizing for space
4135169689Skan	 since it can cause too many CSEs.  */
4136169689Skan      if (optimize_size && offset >= 0
4137169689Skan	  && offset < 256 + 31 * GET_MODE_SIZE (mode))
4138169689Skan	{
4139169689Skan	  HOST_WIDE_INT delta;
4140169689Skan
4141169689Skan	  if (offset >= 256)
4142169689Skan	    delta = offset - (256 - GET_MODE_SIZE (mode));
4143169689Skan	  else if (offset < 32 * GET_MODE_SIZE (mode) + 8)
4144169689Skan	    delta = 31 * GET_MODE_SIZE (mode);
4145169689Skan	  else
4146169689Skan	    delta = offset & (~31 * GET_MODE_SIZE (mode));
4147169689Skan
4148169689Skan	  xop0 = force_operand (plus_constant (xop0, offset - delta),
4149169689Skan				NULL_RTX);
4150169689Skan	  x = plus_constant (xop0, delta);
4151169689Skan	}
4152169689Skan      else if (offset < 0 && offset > -256)
4153169689Skan	/* Small negative offsets are best done with a subtract before the
4154169689Skan	   dereference, forcing these into a register normally takes two
4155169689Skan	   instructions.  */
4156169689Skan	x = force_operand (x, NULL_RTX);
4157169689Skan      else
4158169689Skan	{
4159169689Skan	  /* For the remaining cases, force the constant into a register.  */
4160169689Skan	  xop1 = force_reg (SImode, xop1);
4161169689Skan	  x = gen_rtx_PLUS (SImode, xop0, xop1);
4162169689Skan	}
4163169689Skan    }
4164169689Skan  else if (GET_CODE (x) == PLUS
4165169689Skan	   && s_register_operand (XEXP (x, 1), SImode)
4166169689Skan	   && !s_register_operand (XEXP (x, 0), SImode))
4167169689Skan    {
4168169689Skan      rtx xop0 = force_operand (XEXP (x, 0), NULL_RTX);
4169169689Skan
4170169689Skan      x = gen_rtx_PLUS (SImode, xop0, XEXP (x, 1));
4171169689Skan    }
4172169689Skan
4173169689Skan  if (flag_pic)
4174169689Skan    {
4175169689Skan      /* We need to find and carefully transform any SYMBOL and LABEL
4176169689Skan	 references; so go back to the original address expression.  */
4177169689Skan      rtx new_x = legitimize_pic_address (orig_x, mode, NULL_RTX);
4178169689Skan
4179169689Skan      if (new_x != orig_x)
4180169689Skan	x = new_x;
4181169689Skan    }
4182169689Skan
4183169689Skan  return x;
4184169689Skan}
4185169689Skan
4186169689Skanrtx
4187169689Skanthumb_legitimize_reload_address (rtx *x_p,
4188169689Skan				 enum machine_mode mode,
4189169689Skan				 int opnum, int type,
4190169689Skan				 int ind_levels ATTRIBUTE_UNUSED)
4191169689Skan{
4192169689Skan  rtx x = *x_p;
4193169689Skan
4194169689Skan  if (GET_CODE (x) == PLUS
4195169689Skan      && GET_MODE_SIZE (mode) < 4
4196169689Skan      && REG_P (XEXP (x, 0))
4197169689Skan      && XEXP (x, 0) == stack_pointer_rtx
4198169689Skan      && GET_CODE (XEXP (x, 1)) == CONST_INT
4199169689Skan      && !thumb_legitimate_offset_p (mode, INTVAL (XEXP (x, 1))))
4200169689Skan    {
4201169689Skan      rtx orig_x = x;
4202169689Skan
4203169689Skan      x = copy_rtx (x);
4204169689Skan      push_reload (orig_x, NULL_RTX, x_p, NULL, MODE_BASE_REG_CLASS (mode),
4205169689Skan		   Pmode, VOIDmode, 0, 0, opnum, type);
4206169689Skan      return x;
4207169689Skan    }
4208169689Skan
4209169689Skan  /* If both registers are hi-regs, then it's better to reload the
4210169689Skan     entire expression rather than each register individually.  That
4211169689Skan     only requires one reload register rather than two.  */
4212169689Skan  if (GET_CODE (x) == PLUS
4213169689Skan      && REG_P (XEXP (x, 0))
4214169689Skan      && REG_P (XEXP (x, 1))
4215169689Skan      && !REG_MODE_OK_FOR_REG_BASE_P (XEXP (x, 0), mode)
4216169689Skan      && !REG_MODE_OK_FOR_REG_BASE_P (XEXP (x, 1), mode))
4217169689Skan    {
4218169689Skan      rtx orig_x = x;
4219169689Skan
4220169689Skan      x = copy_rtx (x);
4221169689Skan      push_reload (orig_x, NULL_RTX, x_p, NULL, MODE_BASE_REG_CLASS (mode),
4222169689Skan		   Pmode, VOIDmode, 0, 0, opnum, type);
4223169689Skan      return x;
4224169689Skan    }
4225169689Skan
4226169689Skan  return NULL;
4227169689Skan}
4228169689Skan
4229169689Skan/* Test for various thread-local symbols.  */
4230169689Skan
4231169689Skan/* Return TRUE if X is a thread-local symbol.  */
4232169689Skan
4233169689Skanstatic bool
4234169689Skanarm_tls_symbol_p (rtx x)
4235169689Skan{
4236169689Skan  if (! TARGET_HAVE_TLS)
4237169689Skan    return false;
4238169689Skan
4239169689Skan  if (GET_CODE (x) != SYMBOL_REF)
4240169689Skan    return false;
4241169689Skan
4242169689Skan  return SYMBOL_REF_TLS_MODEL (x) != 0;
4243169689Skan}
4244169689Skan
4245169689Skan/* Helper for arm_tls_referenced_p.  */
4246169689Skan
4247169689Skanstatic int
4248169689Skanarm_tls_operand_p_1 (rtx *x, void *data ATTRIBUTE_UNUSED)
4249169689Skan{
4250169689Skan  if (GET_CODE (*x) == SYMBOL_REF)
4251169689Skan    return SYMBOL_REF_TLS_MODEL (*x) != 0;
4252169689Skan
4253169689Skan  /* Don't recurse into UNSPEC_TLS looking for TLS symbols; these are
4254169689Skan     TLS offsets, not real symbol references.  */
4255169689Skan  if (GET_CODE (*x) == UNSPEC
4256169689Skan      && XINT (*x, 1) == UNSPEC_TLS)
4257169689Skan    return -1;
4258169689Skan
4259169689Skan  return 0;
4260169689Skan}
4261169689Skan
4262169689Skan/* Return TRUE if X contains any TLS symbol references.  */
4263169689Skan
4264169689Skanbool
4265169689Skanarm_tls_referenced_p (rtx x)
4266169689Skan{
4267169689Skan  if (! TARGET_HAVE_TLS)
4268169689Skan    return false;
4269169689Skan
4270169689Skan  return for_each_rtx (&x, arm_tls_operand_p_1, NULL);
4271169689Skan}
4272132718Skan
427390075Sobrien#define REG_OR_SUBREG_REG(X)						\
427490075Sobrien  (GET_CODE (X) == REG							\
427590075Sobrien   || (GET_CODE (X) == SUBREG && GET_CODE (SUBREG_REG (X)) == REG))
427690075Sobrien
427790075Sobrien#define REG_OR_SUBREG_RTX(X)			\
427890075Sobrien   (GET_CODE (X) == REG ? (X) : SUBREG_REG (X))
427990075Sobrien
428090075Sobrien#ifndef COSTS_N_INSNS
428190075Sobrien#define COSTS_N_INSNS(N) ((N) * 4 - 2)
428290075Sobrien#endif
4283132718Skanstatic inline int
4284169689Skanthumb_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer)
428590075Sobrien{
428690075Sobrien  enum machine_mode mode = GET_MODE (x);
428790075Sobrien
4288169689Skan  switch (code)
428990075Sobrien    {
4290169689Skan    case ASHIFT:
4291169689Skan    case ASHIFTRT:
4292169689Skan    case LSHIFTRT:
4293169689Skan    case ROTATERT:
4294169689Skan    case PLUS:
4295169689Skan    case MINUS:
4296169689Skan    case COMPARE:
4297169689Skan    case NEG:
4298169689Skan    case NOT:
4299169689Skan      return COSTS_N_INSNS (1);
4300169689Skan
4301169689Skan    case MULT:
4302169689Skan      if (GET_CODE (XEXP (x, 1)) == CONST_INT)
430390075Sobrien	{
4304169689Skan	  int cycles = 0;
4305169689Skan	  unsigned HOST_WIDE_INT i = INTVAL (XEXP (x, 1));
4306169689Skan
4307169689Skan	  while (i)
4308169689Skan	    {
4309169689Skan	      i >>= 2;
4310169689Skan	      cycles++;
431190075Sobrien	    }
4312169689Skan	  return COSTS_N_INSNS (2) + cycles;
4313169689Skan	}
4314169689Skan      return COSTS_N_INSNS (1) + 16;
4315169689Skan
4316169689Skan    case SET:
4317169689Skan      return (COSTS_N_INSNS (1)
4318169689Skan	      + 4 * ((GET_CODE (SET_SRC (x)) == MEM)
4319169689Skan		     + GET_CODE (SET_DEST (x)) == MEM));
4320169689Skan
4321169689Skan    case CONST_INT:
4322169689Skan      if (outer == SET)
4323169689Skan	{
4324169689Skan	  if ((unsigned HOST_WIDE_INT) INTVAL (x) < 256)
4325132718Skan	    return 0;
4326169689Skan	  if (thumb_shiftable_const (INTVAL (x)))
4327169689Skan	    return COSTS_N_INSNS (2);
432890075Sobrien	  return COSTS_N_INSNS (3);
4329169689Skan	}
4330169689Skan      else if ((outer == PLUS || outer == COMPARE)
4331169689Skan	       && INTVAL (x) < 256 && INTVAL (x) > -256)
4332169689Skan	return 0;
4333169689Skan      else if (outer == AND
4334169689Skan	       && INTVAL (x) < 256 && INTVAL (x) >= -256)
4335169689Skan	return COSTS_N_INSNS (1);
4336169689Skan      else if (outer == ASHIFT || outer == ASHIFTRT
4337169689Skan	       || outer == LSHIFTRT)
4338169689Skan	return 0;
4339169689Skan      return COSTS_N_INSNS (2);
434090075Sobrien
4341169689Skan    case CONST:
4342169689Skan    case CONST_DOUBLE:
4343169689Skan    case LABEL_REF:
4344169689Skan    case SYMBOL_REF:
4345169689Skan      return COSTS_N_INSNS (3);
434690075Sobrien
4347169689Skan    case UDIV:
4348169689Skan    case UMOD:
4349169689Skan    case DIV:
4350169689Skan    case MOD:
4351169689Skan      return 100;
435290075Sobrien
4353169689Skan    case TRUNCATE:
4354169689Skan      return 99;
435590075Sobrien
4356169689Skan    case AND:
4357169689Skan    case XOR:
4358169689Skan    case IOR:
4359169689Skan      /* XXX guess.  */
4360169689Skan      return 8;
436190075Sobrien
4362169689Skan    case MEM:
4363169689Skan      /* XXX another guess.  */
4364169689Skan      /* Memory costs quite a lot for the first word, but subsequent words
4365169689Skan	 load at the equivalent of a single insn each.  */
4366169689Skan      return (10 + 4 * ((GET_MODE_SIZE (mode) - 1) / UNITS_PER_WORD)
4367169689Skan	      + ((GET_CODE (x) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (x))
4368169689Skan		 ? 4 : 0));
4369169689Skan
4370169689Skan    case IF_THEN_ELSE:
4371169689Skan      /* XXX a guess.  */
4372169689Skan      if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC)
4373169689Skan	return 14;
4374169689Skan      return 2;
4375169689Skan
4376169689Skan    case ZERO_EXTEND:
4377169689Skan      /* XXX still guessing.  */
4378169689Skan      switch (GET_MODE (XEXP (x, 0)))
4379169689Skan	{
4380169689Skan	case QImode:
4381169689Skan	  return (1 + (mode == DImode ? 4 : 0)
4382169689Skan		  + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
4383169689Skan
4384169689Skan	case HImode:
4385169689Skan	  return (4 + (mode == DImode ? 4 : 0)
4386169689Skan		  + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
4387169689Skan
4388169689Skan	case SImode:
4389169689Skan	  return (1 + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
4390169689Skan
439190075Sobrien	default:
439290075Sobrien	  return 99;
439390075Sobrien	}
4394169689Skan
4395169689Skan    default:
4396169689Skan      return 99;
439790075Sobrien    }
4398169689Skan}
4399169689Skan
4400169689Skan
4401169689Skan/* Worker routine for arm_rtx_costs.  */
4402169689Skanstatic inline int
4403169689Skanarm_rtx_costs_1 (rtx x, enum rtx_code code, enum rtx_code outer)
4404169689Skan{
4405169689Skan  enum machine_mode mode = GET_MODE (x);
4406169689Skan  enum rtx_code subcode;
4407169689Skan  int extra_cost;
4408169689Skan
440990075Sobrien  switch (code)
441090075Sobrien    {
441190075Sobrien    case MEM:
441290075Sobrien      /* Memory costs quite a lot for the first word, but subsequent words
441390075Sobrien	 load at the equivalent of a single insn each.  */
441490075Sobrien      return (10 + 4 * ((GET_MODE_SIZE (mode) - 1) / UNITS_PER_WORD)
4415117395Skan	      + (GET_CODE (x) == SYMBOL_REF
4416117395Skan		 && CONSTANT_POOL_ADDRESS_P (x) ? 4 : 0));
441790075Sobrien
441890075Sobrien    case DIV:
441990075Sobrien    case MOD:
4420132718Skan    case UDIV:
4421132718Skan    case UMOD:
4422132718Skan      return optimize_size ? COSTS_N_INSNS (2) : 100;
442390075Sobrien
442490075Sobrien    case ROTATE:
442590075Sobrien      if (mode == SImode && GET_CODE (XEXP (x, 1)) == REG)
442690075Sobrien	return 4;
442790075Sobrien      /* Fall through */
442890075Sobrien    case ROTATERT:
442990075Sobrien      if (mode != SImode)
443090075Sobrien	return 8;
443190075Sobrien      /* Fall through */
443290075Sobrien    case ASHIFT: case LSHIFTRT: case ASHIFTRT:
443390075Sobrien      if (mode == DImode)
443490075Sobrien	return (8 + (GET_CODE (XEXP (x, 1)) == CONST_INT ? 0 : 8)
4435169689Skan		+ ((GET_CODE (XEXP (x, 0)) == REG
443690075Sobrien		    || (GET_CODE (XEXP (x, 0)) == SUBREG
443790075Sobrien			&& GET_CODE (SUBREG_REG (XEXP (x, 0))) == REG))
443890075Sobrien		   ? 0 : 8));
443990075Sobrien      return (1 + ((GET_CODE (XEXP (x, 0)) == REG
444090075Sobrien		    || (GET_CODE (XEXP (x, 0)) == SUBREG
444190075Sobrien			&& GET_CODE (SUBREG_REG (XEXP (x, 0))) == REG))
444290075Sobrien		   ? 0 : 4)
444390075Sobrien	      + ((GET_CODE (XEXP (x, 1)) == REG
444490075Sobrien		  || (GET_CODE (XEXP (x, 1)) == SUBREG
444590075Sobrien		      && GET_CODE (SUBREG_REG (XEXP (x, 1))) == REG)
444690075Sobrien		  || (GET_CODE (XEXP (x, 1)) == CONST_INT))
444790075Sobrien		 ? 0 : 4));
444890075Sobrien
444990075Sobrien    case MINUS:
445090075Sobrien      if (mode == DImode)
445190075Sobrien	return (4 + (REG_OR_SUBREG_REG (XEXP (x, 1)) ? 0 : 8)
445290075Sobrien		+ ((REG_OR_SUBREG_REG (XEXP (x, 0))
445390075Sobrien		    || (GET_CODE (XEXP (x, 0)) == CONST_INT
445490075Sobrien		       && const_ok_for_arm (INTVAL (XEXP (x, 0)))))
445590075Sobrien		   ? 0 : 8));
445690075Sobrien
445790075Sobrien      if (GET_MODE_CLASS (mode) == MODE_FLOAT)
445890075Sobrien	return (2 + ((REG_OR_SUBREG_REG (XEXP (x, 1))
445990075Sobrien		      || (GET_CODE (XEXP (x, 1)) == CONST_DOUBLE
4460169689Skan			  && arm_const_double_rtx (XEXP (x, 1))))
446190075Sobrien		     ? 0 : 8)
446290075Sobrien		+ ((REG_OR_SUBREG_REG (XEXP (x, 0))
446390075Sobrien		    || (GET_CODE (XEXP (x, 0)) == CONST_DOUBLE
4464169689Skan			&& arm_const_double_rtx (XEXP (x, 0))))
446590075Sobrien		   ? 0 : 8));
446690075Sobrien
446790075Sobrien      if (((GET_CODE (XEXP (x, 0)) == CONST_INT
446890075Sobrien	    && const_ok_for_arm (INTVAL (XEXP (x, 0)))
446990075Sobrien	    && REG_OR_SUBREG_REG (XEXP (x, 1))))
447090075Sobrien	  || (((subcode = GET_CODE (XEXP (x, 1))) == ASHIFT
447190075Sobrien	       || subcode == ASHIFTRT || subcode == LSHIFTRT
447290075Sobrien	       || subcode == ROTATE || subcode == ROTATERT
447390075Sobrien	       || (subcode == MULT
447490075Sobrien		   && GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT
447590075Sobrien		   && ((INTVAL (XEXP (XEXP (x, 1), 1)) &
447690075Sobrien			(INTVAL (XEXP (XEXP (x, 1), 1)) - 1)) == 0)))
447790075Sobrien	      && REG_OR_SUBREG_REG (XEXP (XEXP (x, 1), 0))
447890075Sobrien	      && (REG_OR_SUBREG_REG (XEXP (XEXP (x, 1), 1))
447990075Sobrien		  || GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT)
448090075Sobrien	      && REG_OR_SUBREG_REG (XEXP (x, 0))))
448190075Sobrien	return 1;
448290075Sobrien      /* Fall through */
448390075Sobrien
4484169689Skan    case PLUS:
4485169689Skan      if (GET_CODE (XEXP (x, 0)) == MULT)
4486169689Skan	{
4487169689Skan	  extra_cost = rtx_cost (XEXP (x, 0), code);
4488169689Skan	  if (!REG_OR_SUBREG_REG (XEXP (x, 1)))
4489169689Skan	    extra_cost += 4 * ARM_NUM_REGS (mode);
4490169689Skan	  return extra_cost;
4491169689Skan	}
4492169689Skan
449390075Sobrien      if (GET_MODE_CLASS (mode) == MODE_FLOAT)
449490075Sobrien	return (2 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 8)
449590075Sobrien		+ ((REG_OR_SUBREG_REG (XEXP (x, 1))
449690075Sobrien		    || (GET_CODE (XEXP (x, 1)) == CONST_DOUBLE
4497169689Skan			&& arm_const_double_rtx (XEXP (x, 1))))
449890075Sobrien		   ? 0 : 8));
449990075Sobrien
450090075Sobrien      /* Fall through */
4501169689Skan    case AND: case XOR: case IOR:
450290075Sobrien      extra_cost = 0;
450390075Sobrien
450490075Sobrien      /* Normally the frame registers will be spilt into reg+const during
450590075Sobrien	 reload, so it is a bad idea to combine them with other instructions,
450690075Sobrien	 since then they might not be moved outside of loops.  As a compromise
450790075Sobrien	 we allow integration with ops that have a constant as their second
450890075Sobrien	 operand.  */
450990075Sobrien      if ((REG_OR_SUBREG_REG (XEXP (x, 0))
451090075Sobrien	   && ARM_FRAME_RTX (REG_OR_SUBREG_RTX (XEXP (x, 0)))
451190075Sobrien	   && GET_CODE (XEXP (x, 1)) != CONST_INT)
451290075Sobrien	  || (REG_OR_SUBREG_REG (XEXP (x, 0))
451390075Sobrien	      && ARM_FRAME_RTX (REG_OR_SUBREG_RTX (XEXP (x, 0)))))
451490075Sobrien	extra_cost = 4;
451590075Sobrien
451690075Sobrien      if (mode == DImode)
451790075Sobrien	return (4 + extra_cost + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 8)
451890075Sobrien		+ ((REG_OR_SUBREG_REG (XEXP (x, 1))
451990075Sobrien		    || (GET_CODE (XEXP (x, 1)) == CONST_INT
452090075Sobrien			&& const_ok_for_op (INTVAL (XEXP (x, 1)), code)))
452190075Sobrien		   ? 0 : 8));
452290075Sobrien
452390075Sobrien      if (REG_OR_SUBREG_REG (XEXP (x, 0)))
452490075Sobrien	return (1 + (GET_CODE (XEXP (x, 1)) == CONST_INT ? 0 : extra_cost)
452590075Sobrien		+ ((REG_OR_SUBREG_REG (XEXP (x, 1))
452690075Sobrien		    || (GET_CODE (XEXP (x, 1)) == CONST_INT
452790075Sobrien			&& const_ok_for_op (INTVAL (XEXP (x, 1)), code)))
452890075Sobrien		   ? 0 : 4));
452990075Sobrien
453090075Sobrien      else if (REG_OR_SUBREG_REG (XEXP (x, 1)))
453190075Sobrien	return (1 + extra_cost
453290075Sobrien		+ ((((subcode = GET_CODE (XEXP (x, 0))) == ASHIFT
453390075Sobrien		     || subcode == LSHIFTRT || subcode == ASHIFTRT
453490075Sobrien		     || subcode == ROTATE || subcode == ROTATERT
453590075Sobrien		     || (subcode == MULT
453690075Sobrien			 && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
453790075Sobrien			 && ((INTVAL (XEXP (XEXP (x, 0), 1)) &
453890075Sobrien			      (INTVAL (XEXP (XEXP (x, 0), 1)) - 1)) == 0)))
453990075Sobrien		    && (REG_OR_SUBREG_REG (XEXP (XEXP (x, 0), 0)))
454090075Sobrien		    && ((REG_OR_SUBREG_REG (XEXP (XEXP (x, 0), 1)))
454190075Sobrien			|| GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT))
454290075Sobrien		   ? 0 : 4));
454390075Sobrien
454490075Sobrien      return 8;
454590075Sobrien
454690075Sobrien    case MULT:
4547169689Skan      /* This should have been handled by the CPU specific routines.  */
4548169689Skan      gcc_unreachable ();
454990075Sobrien
455090075Sobrien    case TRUNCATE:
4551169689Skan      if (arm_arch3m && mode == SImode
455290075Sobrien	  && GET_CODE (XEXP (x, 0)) == LSHIFTRT
455390075Sobrien	  && GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT
455490075Sobrien	  && (GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0))
455590075Sobrien	      == GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 1)))
455690075Sobrien	  && (GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == ZERO_EXTEND
455790075Sobrien	      || GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == SIGN_EXTEND))
455890075Sobrien	return 8;
455990075Sobrien      return 99;
456090075Sobrien
456190075Sobrien    case NEG:
456290075Sobrien      if (GET_MODE_CLASS (mode) == MODE_FLOAT)
456390075Sobrien	return 4 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 6);
456490075Sobrien      /* Fall through */
456590075Sobrien    case NOT:
456690075Sobrien      if (mode == DImode)
456790075Sobrien	return 4 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4);
456890075Sobrien
456990075Sobrien      return 1 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4);
457090075Sobrien
457190075Sobrien    case IF_THEN_ELSE:
457290075Sobrien      if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC)
457390075Sobrien	return 14;
457490075Sobrien      return 2;
457590075Sobrien
457690075Sobrien    case COMPARE:
457790075Sobrien      return 1;
457890075Sobrien
457990075Sobrien    case ABS:
458090075Sobrien      return 4 + (mode == DImode ? 4 : 0);
458190075Sobrien
458290075Sobrien    case SIGN_EXTEND:
458390075Sobrien      if (GET_MODE (XEXP (x, 0)) == QImode)
458490075Sobrien	return (4 + (mode == DImode ? 4 : 0)
458590075Sobrien		+ (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
458690075Sobrien      /* Fall through */
458790075Sobrien    case ZERO_EXTEND:
458890075Sobrien      switch (GET_MODE (XEXP (x, 0)))
458990075Sobrien	{
459090075Sobrien	case QImode:
459190075Sobrien	  return (1 + (mode == DImode ? 4 : 0)
459290075Sobrien		  + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
459390075Sobrien
459490075Sobrien	case HImode:
459590075Sobrien	  return (4 + (mode == DImode ? 4 : 0)
459690075Sobrien		  + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
459790075Sobrien
459890075Sobrien	case SImode:
459990075Sobrien	  return (1 + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
460090075Sobrien
4601132718Skan	case V8QImode:
4602132718Skan	case V4HImode:
4603132718Skan	case V2SImode:
4604132718Skan	case V4QImode:
4605132718Skan	case V2HImode:
4606132718Skan	    return 1;
4607132718Skan
460890075Sobrien	default:
4609169689Skan	  gcc_unreachable ();
461090075Sobrien	}
4611169689Skan      gcc_unreachable ();
461290075Sobrien
4613169689Skan    case CONST_INT:
4614169689Skan      if (const_ok_for_arm (INTVAL (x)))
4615169689Skan	return outer == SET ? 2 : -1;
4616169689Skan      else if (outer == AND
4617169689Skan	       && const_ok_for_arm (~INTVAL (x)))
4618169689Skan	return -1;
4619169689Skan      else if ((outer == COMPARE
4620169689Skan		|| outer == PLUS || outer == MINUS)
4621169689Skan	       && const_ok_for_arm (-INTVAL (x)))
4622169689Skan	return -1;
4623169689Skan      else
462490075Sobrien	return 5;
4625169689Skan
4626169689Skan    case CONST:
4627169689Skan    case LABEL_REF:
4628169689Skan    case SYMBOL_REF:
462990075Sobrien      return 6;
4630169689Skan
4631169689Skan    case CONST_DOUBLE:
4632169689Skan      if (arm_const_double_rtx (x))
4633169689Skan	return outer == SET ? 2 : -1;
4634169689Skan      else if ((outer == COMPARE || outer == PLUS)
4635169689Skan	       && neg_const_double_rtx_ok_for_fpa (x))
4636169689Skan	return -1;
463790075Sobrien      return 7;
4638169689Skan
463990075Sobrien    default:
464090075Sobrien      return 99;
464190075Sobrien    }
464290075Sobrien}
464390075Sobrien
4644169689Skan/* RTX costs when optimizing for size.  */
4645132718Skanstatic bool
4646169689Skanarm_size_rtx_costs (rtx x, int code, int outer_code, int *total)
4647132718Skan{
4648169689Skan  enum machine_mode mode = GET_MODE (x);
4649169689Skan
4650169689Skan  if (TARGET_THUMB)
4651169689Skan    {
4652169689Skan      /* XXX TBD.  For now, use the standard costs.  */
4653169689Skan      *total = thumb_rtx_costs (x, code, outer_code);
4654169689Skan      return true;
4655169689Skan    }
4656169689Skan
4657169689Skan  switch (code)
4658169689Skan    {
4659169689Skan    case MEM:
4660169689Skan      /* A memory access costs 1 insn if the mode is small, or the address is
4661169689Skan	 a single register, otherwise it costs one insn per word.  */
4662169689Skan      if (REG_P (XEXP (x, 0)))
4663169689Skan	*total = COSTS_N_INSNS (1);
4664169689Skan      else
4665169689Skan	*total = COSTS_N_INSNS (ARM_NUM_REGS (mode));
4666169689Skan      return true;
4667169689Skan
4668169689Skan    case DIV:
4669169689Skan    case MOD:
4670169689Skan    case UDIV:
4671169689Skan    case UMOD:
4672169689Skan      /* Needs a libcall, so it costs about this.  */
4673169689Skan      *total = COSTS_N_INSNS (2);
4674169689Skan      return false;
4675169689Skan
4676169689Skan    case ROTATE:
4677169689Skan      if (mode == SImode && GET_CODE (XEXP (x, 1)) == REG)
4678169689Skan	{
4679169689Skan	  *total = COSTS_N_INSNS (2) + rtx_cost (XEXP (x, 0), code);
4680169689Skan	  return true;
4681169689Skan	}
4682169689Skan      /* Fall through */
4683169689Skan    case ROTATERT:
4684169689Skan    case ASHIFT:
4685169689Skan    case LSHIFTRT:
4686169689Skan    case ASHIFTRT:
4687169689Skan      if (mode == DImode && GET_CODE (XEXP (x, 1)) == CONST_INT)
4688169689Skan	{
4689169689Skan	  *total = COSTS_N_INSNS (3) + rtx_cost (XEXP (x, 0), code);
4690169689Skan	  return true;
4691169689Skan	}
4692169689Skan      else if (mode == SImode)
4693169689Skan	{
4694169689Skan	  *total = COSTS_N_INSNS (1) + rtx_cost (XEXP (x, 0), code);
4695169689Skan	  /* Slightly disparage register shifts, but not by much.  */
4696169689Skan	  if (GET_CODE (XEXP (x, 1)) != CONST_INT)
4697169689Skan	    *total += 1 + rtx_cost (XEXP (x, 1), code);
4698169689Skan	  return true;
4699169689Skan	}
4700169689Skan
4701169689Skan      /* Needs a libcall.  */
4702169689Skan      *total = COSTS_N_INSNS (2);
4703169689Skan      return false;
4704169689Skan
4705169689Skan    case MINUS:
4706169689Skan      if (TARGET_HARD_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT)
4707169689Skan	{
4708169689Skan	  *total = COSTS_N_INSNS (1);
4709169689Skan	  return false;
4710169689Skan	}
4711169689Skan
4712169689Skan      if (mode == SImode)
4713169689Skan	{
4714169689Skan	  enum rtx_code subcode0 = GET_CODE (XEXP (x, 0));
4715169689Skan	  enum rtx_code subcode1 = GET_CODE (XEXP (x, 1));
4716169689Skan
4717169689Skan	  if (subcode0 == ROTATE || subcode0 == ROTATERT || subcode0 == ASHIFT
4718169689Skan	      || subcode0 == LSHIFTRT || subcode0 == ASHIFTRT
4719169689Skan	      || subcode1 == ROTATE || subcode1 == ROTATERT
4720169689Skan	      || subcode1 == ASHIFT || subcode1 == LSHIFTRT
4721169689Skan	      || subcode1 == ASHIFTRT)
4722169689Skan	    {
4723169689Skan	      /* It's just the cost of the two operands.  */
4724169689Skan	      *total = 0;
4725169689Skan	      return false;
4726169689Skan	    }
4727169689Skan
4728169689Skan	  *total = COSTS_N_INSNS (1);
4729169689Skan	  return false;
4730169689Skan	}
4731169689Skan
4732169689Skan      *total = COSTS_N_INSNS (ARM_NUM_REGS (mode));
4733169689Skan      return false;
4734169689Skan
4735169689Skan    case PLUS:
4736169689Skan      if (TARGET_HARD_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT)
4737169689Skan	{
4738169689Skan	  *total = COSTS_N_INSNS (1);
4739169689Skan	  return false;
4740169689Skan	}
4741169689Skan
4742169689Skan      /* Fall through */
4743169689Skan    case AND: case XOR: case IOR:
4744169689Skan      if (mode == SImode)
4745169689Skan	{
4746169689Skan	  enum rtx_code subcode = GET_CODE (XEXP (x, 0));
4747169689Skan
4748169689Skan	  if (subcode == ROTATE || subcode == ROTATERT || subcode == ASHIFT
4749169689Skan	      || subcode == LSHIFTRT || subcode == ASHIFTRT
4750169689Skan	      || (code == AND && subcode == NOT))
4751169689Skan	    {
4752169689Skan	      /* It's just the cost of the two operands.  */
4753169689Skan	      *total = 0;
4754169689Skan	      return false;
4755169689Skan	    }
4756169689Skan	}
4757169689Skan
4758169689Skan      *total = COSTS_N_INSNS (ARM_NUM_REGS (mode));
4759169689Skan      return false;
4760169689Skan
4761169689Skan    case MULT:
4762169689Skan      *total = COSTS_N_INSNS (ARM_NUM_REGS (mode));
4763169689Skan      return false;
4764169689Skan
4765169689Skan    case NEG:
4766169689Skan      if (TARGET_HARD_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT)
4767169689Skan	*total = COSTS_N_INSNS (1);
4768169689Skan      /* Fall through */
4769169689Skan    case NOT:
4770169689Skan      *total = COSTS_N_INSNS (ARM_NUM_REGS (mode));
4771169689Skan
4772169689Skan      return false;
4773169689Skan
4774169689Skan    case IF_THEN_ELSE:
4775169689Skan      *total = 0;
4776169689Skan      return false;
4777169689Skan
4778169689Skan    case COMPARE:
4779169689Skan      if (cc_register (XEXP (x, 0), VOIDmode))
4780169689Skan	* total = 0;
4781169689Skan      else
4782169689Skan	*total = COSTS_N_INSNS (1);
4783169689Skan      return false;
4784169689Skan
4785169689Skan    case ABS:
4786169689Skan      if (TARGET_HARD_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT)
4787169689Skan	*total = COSTS_N_INSNS (1);
4788169689Skan      else
4789169689Skan	*total = COSTS_N_INSNS (1 + ARM_NUM_REGS (mode));
4790169689Skan      return false;
4791169689Skan
4792169689Skan    case SIGN_EXTEND:
4793169689Skan      *total = 0;
4794169689Skan      if (GET_MODE_SIZE (GET_MODE (XEXP (x, 0))) < 4)
4795169689Skan	{
4796169689Skan	  if (!(arm_arch4 && MEM_P (XEXP (x, 0))))
4797169689Skan	    *total += COSTS_N_INSNS (arm_arch6 ? 1 : 2);
4798169689Skan	}
4799169689Skan      if (mode == DImode)
4800169689Skan	*total += COSTS_N_INSNS (1);
4801169689Skan      return false;
4802169689Skan
4803169689Skan    case ZERO_EXTEND:
4804169689Skan      *total = 0;
4805169689Skan      if (!(arm_arch4 && MEM_P (XEXP (x, 0))))
4806169689Skan	{
4807169689Skan	  switch (GET_MODE (XEXP (x, 0)))
4808169689Skan	    {
4809169689Skan	    case QImode:
4810169689Skan	      *total += COSTS_N_INSNS (1);
4811169689Skan	      break;
4812169689Skan
4813169689Skan	    case HImode:
4814169689Skan	      *total += COSTS_N_INSNS (arm_arch6 ? 1 : 2);
4815169689Skan
4816169689Skan	    case SImode:
4817169689Skan	      break;
4818169689Skan
4819169689Skan	    default:
4820169689Skan	      *total += COSTS_N_INSNS (2);
4821169689Skan	    }
4822169689Skan	}
4823169689Skan
4824169689Skan      if (mode == DImode)
4825169689Skan	*total += COSTS_N_INSNS (1);
4826169689Skan
4827169689Skan      return false;
4828169689Skan
4829169689Skan    case CONST_INT:
4830169689Skan      if (const_ok_for_arm (INTVAL (x)))
4831169689Skan	*total = COSTS_N_INSNS (outer_code == SET ? 1 : 0);
4832169689Skan      else if (const_ok_for_arm (~INTVAL (x)))
4833169689Skan	*total = COSTS_N_INSNS (outer_code == AND ? 0 : 1);
4834169689Skan      else if (const_ok_for_arm (-INTVAL (x)))
4835169689Skan	{
4836169689Skan	  if (outer_code == COMPARE || outer_code == PLUS
4837169689Skan	      || outer_code == MINUS)
4838169689Skan	    *total = 0;
4839169689Skan	  else
4840169689Skan	    *total = COSTS_N_INSNS (1);
4841169689Skan	}
4842169689Skan      else
4843169689Skan	*total = COSTS_N_INSNS (2);
4844169689Skan      return true;
4845169689Skan
4846169689Skan    case CONST:
4847169689Skan    case LABEL_REF:
4848169689Skan    case SYMBOL_REF:
4849169689Skan      *total = COSTS_N_INSNS (2);
4850169689Skan      return true;
4851169689Skan
4852169689Skan    case CONST_DOUBLE:
4853169689Skan      *total = COSTS_N_INSNS (4);
4854169689Skan      return true;
4855169689Skan
4856169689Skan    default:
4857169689Skan      if (mode != VOIDmode)
4858169689Skan	*total = COSTS_N_INSNS (ARM_NUM_REGS (mode));
4859169689Skan      else
4860169689Skan	*total = COSTS_N_INSNS (4); /* How knows?  */
4861169689Skan      return false;
4862169689Skan    }
4863132718Skan}
4864132718Skan
4865169689Skan/* RTX costs for cores with a slow MUL implementation.  */
4866169689Skan
4867169689Skanstatic bool
4868169689Skanarm_slowmul_rtx_costs (rtx x, int code, int outer_code, int *total)
4869169689Skan{
4870169689Skan  enum machine_mode mode = GET_MODE (x);
4871169689Skan
4872169689Skan  if (TARGET_THUMB)
4873169689Skan    {
4874169689Skan      *total = thumb_rtx_costs (x, code, outer_code);
4875169689Skan      return true;
4876169689Skan    }
4877169689Skan
4878169689Skan  switch (code)
4879169689Skan    {
4880169689Skan    case MULT:
4881169689Skan      if (GET_MODE_CLASS (mode) == MODE_FLOAT
4882169689Skan	  || mode == DImode)
4883169689Skan	{
4884169689Skan	  *total = 30;
4885169689Skan	  return true;
4886169689Skan	}
4887169689Skan
4888169689Skan      if (GET_CODE (XEXP (x, 1)) == CONST_INT)
4889169689Skan	{
4890169689Skan	  unsigned HOST_WIDE_INT i = (INTVAL (XEXP (x, 1))
4891169689Skan				      & (unsigned HOST_WIDE_INT) 0xffffffff);
4892169689Skan	  int cost, const_ok = const_ok_for_arm (i);
4893169689Skan	  int j, booth_unit_size;
4894169689Skan
4895169689Skan	  /* Tune as appropriate.  */
4896169689Skan	  cost = const_ok ? 4 : 8;
4897169689Skan	  booth_unit_size = 2;
4898169689Skan	  for (j = 0; i && j < 32; j += booth_unit_size)
4899169689Skan	    {
4900169689Skan	      i >>= booth_unit_size;
4901169689Skan	      cost += 2;
4902169689Skan	    }
4903169689Skan
4904169689Skan	  *total = cost;
4905169689Skan	  return true;
4906169689Skan	}
4907169689Skan
4908169689Skan      *total = 30 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4)
4909169689Skan	          + (REG_OR_SUBREG_REG (XEXP (x, 1)) ? 0 : 4);
4910169689Skan      return true;
4911169689Skan
4912169689Skan    default:
4913169689Skan      *total = arm_rtx_costs_1 (x, code, outer_code);
4914169689Skan      return true;
4915169689Skan    }
4916169689Skan}
4917169689Skan
4918169689Skan
4919169689Skan/* RTX cost for cores with a fast multiply unit (M variants).  */
4920169689Skan
4921169689Skanstatic bool
4922169689Skanarm_fastmul_rtx_costs (rtx x, int code, int outer_code, int *total)
4923169689Skan{
4924169689Skan  enum machine_mode mode = GET_MODE (x);
4925169689Skan
4926169689Skan  if (TARGET_THUMB)
4927169689Skan    {
4928169689Skan      *total = thumb_rtx_costs (x, code, outer_code);
4929169689Skan      return true;
4930169689Skan    }
4931169689Skan
4932169689Skan  switch (code)
4933169689Skan    {
4934169689Skan    case MULT:
4935169689Skan      /* There is no point basing this on the tuning, since it is always the
4936169689Skan	 fast variant if it exists at all.  */
4937169689Skan      if (mode == DImode
4938169689Skan	  && (GET_CODE (XEXP (x, 0)) == GET_CODE (XEXP (x, 1)))
4939169689Skan	  && (GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
4940169689Skan	      || GET_CODE (XEXP (x, 0)) == SIGN_EXTEND))
4941169689Skan	{
4942169689Skan	  *total = 8;
4943169689Skan	  return true;
4944169689Skan	}
4945169689Skan
4946169689Skan
4947169689Skan      if (GET_MODE_CLASS (mode) == MODE_FLOAT
4948169689Skan	  || mode == DImode)
4949169689Skan	{
4950169689Skan	  *total = 30;
4951169689Skan	  return true;
4952169689Skan	}
4953169689Skan
4954169689Skan      if (GET_CODE (XEXP (x, 1)) == CONST_INT)
4955169689Skan	{
4956169689Skan	  unsigned HOST_WIDE_INT i = (INTVAL (XEXP (x, 1))
4957169689Skan				      & (unsigned HOST_WIDE_INT) 0xffffffff);
4958169689Skan	  int cost, const_ok = const_ok_for_arm (i);
4959169689Skan	  int j, booth_unit_size;
4960169689Skan
4961169689Skan	  /* Tune as appropriate.  */
4962169689Skan	  cost = const_ok ? 4 : 8;
4963169689Skan	  booth_unit_size = 8;
4964169689Skan	  for (j = 0; i && j < 32; j += booth_unit_size)
4965169689Skan	    {
4966169689Skan	      i >>= booth_unit_size;
4967169689Skan	      cost += 2;
4968169689Skan	    }
4969169689Skan
4970169689Skan	  *total = cost;
4971169689Skan	  return true;
4972169689Skan	}
4973169689Skan
4974169689Skan      *total = 8 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4)
4975169689Skan	         + (REG_OR_SUBREG_REG (XEXP (x, 1)) ? 0 : 4);
4976169689Skan      return true;
4977169689Skan
4978169689Skan    default:
4979169689Skan      *total = arm_rtx_costs_1 (x, code, outer_code);
4980169689Skan      return true;
4981169689Skan    }
4982169689Skan}
4983169689Skan
4984169689Skan
4985169689Skan/* RTX cost for XScale CPUs.  */
4986169689Skan
4987169689Skanstatic bool
4988169689Skanarm_xscale_rtx_costs (rtx x, int code, int outer_code, int *total)
4989169689Skan{
4990169689Skan  enum machine_mode mode = GET_MODE (x);
4991169689Skan
4992169689Skan  if (TARGET_THUMB)
4993169689Skan    {
4994169689Skan      *total = thumb_rtx_costs (x, code, outer_code);
4995169689Skan      return true;
4996169689Skan    }
4997169689Skan
4998169689Skan  switch (code)
4999169689Skan    {
5000169689Skan    case MULT:
5001169689Skan      /* There is no point basing this on the tuning, since it is always the
5002169689Skan	 fast variant if it exists at all.  */
5003169689Skan      if (mode == DImode
5004169689Skan	  && (GET_CODE (XEXP (x, 0)) == GET_CODE (XEXP (x, 1)))
5005169689Skan	  && (GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
5006169689Skan	      || GET_CODE (XEXP (x, 0)) == SIGN_EXTEND))
5007169689Skan	{
5008169689Skan	  *total = 8;
5009169689Skan	  return true;
5010169689Skan	}
5011169689Skan
5012169689Skan
5013169689Skan      if (GET_MODE_CLASS (mode) == MODE_FLOAT
5014169689Skan	  || mode == DImode)
5015169689Skan	{
5016169689Skan	  *total = 30;
5017169689Skan	  return true;
5018169689Skan	}
5019169689Skan
5020169689Skan      if (GET_CODE (XEXP (x, 1)) == CONST_INT)
5021169689Skan	{
5022169689Skan	  unsigned HOST_WIDE_INT i = (INTVAL (XEXP (x, 1))
5023169689Skan				      & (unsigned HOST_WIDE_INT) 0xffffffff);
5024169689Skan	  int cost, const_ok = const_ok_for_arm (i);
5025169689Skan	  unsigned HOST_WIDE_INT masked_const;
5026169689Skan
5027169689Skan	  /* The cost will be related to two insns.
5028169689Skan	     First a load of the constant (MOV or LDR), then a multiply.  */
5029169689Skan	  cost = 2;
5030169689Skan	  if (! const_ok)
5031169689Skan	    cost += 1;      /* LDR is probably more expensive because
5032169689Skan			       of longer result latency.  */
5033169689Skan	  masked_const = i & 0xffff8000;
5034169689Skan	  if (masked_const != 0 && masked_const != 0xffff8000)
5035169689Skan	    {
5036169689Skan	      masked_const = i & 0xf8000000;
5037169689Skan	      if (masked_const == 0 || masked_const == 0xf8000000)
5038169689Skan		cost += 1;
5039169689Skan	      else
5040169689Skan		cost += 2;
5041169689Skan	    }
5042169689Skan	  *total = cost;
5043169689Skan	  return true;
5044169689Skan	}
5045169689Skan
5046169689Skan      *total = 8 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4)
5047169689Skan		 + (REG_OR_SUBREG_REG (XEXP (x, 1)) ? 0 : 4);
5048169689Skan      return true;
5049169689Skan
5050169689Skan    case COMPARE:
5051169689Skan      /* A COMPARE of a MULT is slow on XScale; the muls instruction
5052169689Skan	 will stall until the multiplication is complete.  */
5053169689Skan      if (GET_CODE (XEXP (x, 0)) == MULT)
5054169689Skan	*total = 4 + rtx_cost (XEXP (x, 0), code);
5055169689Skan      else
5056169689Skan	*total = arm_rtx_costs_1 (x, code, outer_code);
5057169689Skan      return true;
5058169689Skan
5059169689Skan    default:
5060169689Skan      *total = arm_rtx_costs_1 (x, code, outer_code);
5061169689Skan      return true;
5062169689Skan    }
5063169689Skan}
5064169689Skan
5065169689Skan
5066169689Skan/* RTX costs for 9e (and later) cores.  */
5067169689Skan
5068169689Skanstatic bool
5069169689Skanarm_9e_rtx_costs (rtx x, int code, int outer_code, int *total)
5070169689Skan{
5071169689Skan  enum machine_mode mode = GET_MODE (x);
5072169689Skan  int nonreg_cost;
5073169689Skan  int cost;
5074169689Skan
5075169689Skan  if (TARGET_THUMB)
5076169689Skan    {
5077169689Skan      switch (code)
5078169689Skan	{
5079169689Skan	case MULT:
5080169689Skan	  *total = COSTS_N_INSNS (3);
5081169689Skan	  return true;
5082169689Skan
5083169689Skan	default:
5084169689Skan	  *total = thumb_rtx_costs (x, code, outer_code);
5085169689Skan	  return true;
5086169689Skan	}
5087169689Skan    }
5088169689Skan
5089169689Skan  switch (code)
5090169689Skan    {
5091169689Skan    case MULT:
5092169689Skan      /* There is no point basing this on the tuning, since it is always the
5093169689Skan	 fast variant if it exists at all.  */
5094169689Skan      if (mode == DImode
5095169689Skan	  && (GET_CODE (XEXP (x, 0)) == GET_CODE (XEXP (x, 1)))
5096169689Skan	  && (GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
5097169689Skan	      || GET_CODE (XEXP (x, 0)) == SIGN_EXTEND))
5098169689Skan	{
5099169689Skan	  *total = 3;
5100169689Skan	  return true;
5101169689Skan	}
5102169689Skan
5103169689Skan
5104169689Skan      if (GET_MODE_CLASS (mode) == MODE_FLOAT)
5105169689Skan	{
5106169689Skan	  *total = 30;
5107169689Skan	  return true;
5108169689Skan	}
5109169689Skan      if (mode == DImode)
5110169689Skan	{
5111169689Skan	  cost = 7;
5112169689Skan	  nonreg_cost = 8;
5113169689Skan	}
5114169689Skan      else
5115169689Skan	{
5116169689Skan	  cost = 2;
5117169689Skan	  nonreg_cost = 4;
5118169689Skan	}
5119169689Skan
5120169689Skan
5121169689Skan      *total = cost + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : nonreg_cost)
5122169689Skan		    + (REG_OR_SUBREG_REG (XEXP (x, 1)) ? 0 : nonreg_cost);
5123169689Skan      return true;
5124169689Skan
5125169689Skan    default:
5126169689Skan      *total = arm_rtx_costs_1 (x, code, outer_code);
5127169689Skan      return true;
5128169689Skan    }
5129169689Skan}
5130132718Skan/* All address computations that can be done are free, but rtx cost returns
5131132718Skan   the same for practically all of them.  So we weight the different types
5132132718Skan   of address here in the order (most pref first):
5133132718Skan   PRE/POST_INC/DEC, SHIFT or NON-INT sum, INT sum, REG, MEM or LABEL.  */
5134132718Skanstatic inline int
5135132718Skanarm_arm_address_cost (rtx x)
5136132718Skan{
5137132718Skan  enum rtx_code c  = GET_CODE (x);
5138132718Skan
5139132718Skan  if (c == PRE_INC || c == PRE_DEC || c == POST_INC || c == POST_DEC)
5140132718Skan    return 0;
5141132718Skan  if (c == MEM || c == LABEL_REF || c == SYMBOL_REF)
5142132718Skan    return 10;
5143132718Skan
5144132718Skan  if (c == PLUS || c == MINUS)
5145132718Skan    {
5146132718Skan      if (GET_CODE (XEXP (x, 0)) == CONST_INT)
5147132718Skan	return 2;
5148132718Skan
5149169689Skan      if (ARITHMETIC_P (XEXP (x, 0)) || ARITHMETIC_P (XEXP (x, 1)))
5150132718Skan	return 3;
5151132718Skan
5152132718Skan      return 4;
5153132718Skan    }
5154132718Skan
5155132718Skan  return 6;
5156132718Skan}
5157132718Skan
5158132718Skanstatic inline int
5159132718Skanarm_thumb_address_cost (rtx x)
5160132718Skan{
5161132718Skan  enum rtx_code c  = GET_CODE (x);
5162132718Skan
5163132718Skan  if (c == REG)
5164132718Skan    return 1;
5165132718Skan  if (c == PLUS
5166132718Skan      && GET_CODE (XEXP (x, 0)) == REG
5167132718Skan      && GET_CODE (XEXP (x, 1)) == CONST_INT)
5168132718Skan    return 1;
5169132718Skan
5170132718Skan  return 2;
5171132718Skan}
5172132718Skan
517390075Sobrienstatic int
5174132718Skanarm_address_cost (rtx x)
517590075Sobrien{
5176132718Skan  return TARGET_ARM ? arm_arm_address_cost (x) : arm_thumb_address_cost (x);
5177132718Skan}
5178132718Skan
5179132718Skanstatic int
5180132718Skanarm_adjust_cost (rtx insn, rtx link, rtx dep, int cost)
5181132718Skan{
518290075Sobrien  rtx i_pat, d_pat;
518390075Sobrien
518490075Sobrien  /* Some true dependencies can have a higher cost depending
518590075Sobrien     on precisely how certain input operands are used.  */
5186132718Skan  if (arm_tune_xscale
518790075Sobrien      && REG_NOTE_KIND (link) == 0
5188132718Skan      && recog_memoized (insn) >= 0
5189132718Skan      && recog_memoized (dep) >= 0)
519090075Sobrien    {
519190075Sobrien      int shift_opnum = get_attr_shift (insn);
519290075Sobrien      enum attr_type attr_type = get_attr_type (dep);
519390075Sobrien
519490075Sobrien      /* If nonzero, SHIFT_OPNUM contains the operand number of a shifted
519590075Sobrien	 operand for INSN.  If we have a shifted input operand and the
519690075Sobrien	 instruction we depend on is another ALU instruction, then we may
519790075Sobrien	 have to account for an additional stall.  */
5198169689Skan      if (shift_opnum != 0
5199169689Skan	  && (attr_type == TYPE_ALU_SHIFT || attr_type == TYPE_ALU_SHIFT_REG))
520090075Sobrien	{
520190075Sobrien	  rtx shifted_operand;
520290075Sobrien	  int opno;
5203169689Skan
520490075Sobrien	  /* Get the shifted operand.  */
520590075Sobrien	  extract_insn (insn);
520690075Sobrien	  shifted_operand = recog_data.operand[shift_opnum];
520790075Sobrien
520890075Sobrien	  /* Iterate over all the operands in DEP.  If we write an operand
520990075Sobrien	     that overlaps with SHIFTED_OPERAND, then we have increase the
521090075Sobrien	     cost of this dependency.  */
521190075Sobrien	  extract_insn (dep);
521290075Sobrien	  preprocess_constraints ();
521390075Sobrien	  for (opno = 0; opno < recog_data.n_operands; opno++)
521490075Sobrien	    {
521590075Sobrien	      /* We can ignore strict inputs.  */
521690075Sobrien	      if (recog_data.operand_type[opno] == OP_IN)
521790075Sobrien		continue;
521890075Sobrien
521990075Sobrien	      if (reg_overlap_mentioned_p (recog_data.operand[opno],
522090075Sobrien					   shifted_operand))
522190075Sobrien		return 2;
522290075Sobrien	    }
522390075Sobrien	}
522490075Sobrien    }
522590075Sobrien
522690075Sobrien  /* XXX This is not strictly true for the FPA.  */
522790075Sobrien  if (REG_NOTE_KIND (link) == REG_DEP_ANTI
522890075Sobrien      || REG_NOTE_KIND (link) == REG_DEP_OUTPUT)
522990075Sobrien    return 0;
523090075Sobrien
523190075Sobrien  /* Call insns don't incur a stall, even if they follow a load.  */
523290075Sobrien  if (REG_NOTE_KIND (link) == 0
523390075Sobrien      && GET_CODE (insn) == CALL_INSN)
523490075Sobrien    return 1;
523590075Sobrien
523690075Sobrien  if ((i_pat = single_set (insn)) != NULL
523790075Sobrien      && GET_CODE (SET_SRC (i_pat)) == MEM
523890075Sobrien      && (d_pat = single_set (dep)) != NULL
523990075Sobrien      && GET_CODE (SET_DEST (d_pat)) == MEM)
524090075Sobrien    {
5241117395Skan      rtx src_mem = XEXP (SET_SRC (i_pat), 0);
524290075Sobrien      /* This is a load after a store, there is no conflict if the load reads
524390075Sobrien	 from a cached area.  Assume that loads from the stack, and from the
5244169689Skan	 constant pool are cached, and that others will miss.  This is a
524590075Sobrien	 hack.  */
5246169689Skan
5247117395Skan      if ((GET_CODE (src_mem) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (src_mem))
5248117395Skan	  || reg_mentioned_p (stack_pointer_rtx, src_mem)
5249117395Skan	  || reg_mentioned_p (frame_pointer_rtx, src_mem)
5250117395Skan	  || reg_mentioned_p (hard_frame_pointer_rtx, src_mem))
525190075Sobrien	return 1;
525290075Sobrien    }
525390075Sobrien
525490075Sobrien  return cost;
525590075Sobrien}
525690075Sobrien
5257169689Skanstatic int fp_consts_inited = 0;
525890075Sobrien
5259169689Skan/* Only zero is valid for VFP.  Other values are also valid for FPA.  */
5260169689Skanstatic const char * const strings_fp[8] =
526190075Sobrien{
526290075Sobrien  "0",   "1",   "2",   "3",
526390075Sobrien  "4",   "5",   "0.5", "10"
526490075Sobrien};
526590075Sobrien
5266169689Skanstatic REAL_VALUE_TYPE values_fp[8];
526790075Sobrien
526890075Sobrienstatic void
5269169689Skaninit_fp_table (void)
527090075Sobrien{
527190075Sobrien  int i;
527290075Sobrien  REAL_VALUE_TYPE r;
527390075Sobrien
5274169689Skan  if (TARGET_VFP)
5275169689Skan    fp_consts_inited = 1;
5276169689Skan  else
5277169689Skan    fp_consts_inited = 8;
5278169689Skan
5279169689Skan  for (i = 0; i < fp_consts_inited; i++)
528090075Sobrien    {
5281169689Skan      r = REAL_VALUE_ATOF (strings_fp[i], DFmode);
5282169689Skan      values_fp[i] = r;
528390075Sobrien    }
528490075Sobrien}
528590075Sobrien
5286169689Skan/* Return TRUE if rtx X is a valid immediate FP constant.  */
528790075Sobrienint
5288169689Skanarm_const_double_rtx (rtx x)
528990075Sobrien{
529090075Sobrien  REAL_VALUE_TYPE r;
529190075Sobrien  int i;
5292169689Skan
5293169689Skan  if (!fp_consts_inited)
5294169689Skan    init_fp_table ();
5295169689Skan
529690075Sobrien  REAL_VALUE_FROM_CONST_DOUBLE (r, x);
529790075Sobrien  if (REAL_VALUE_MINUS_ZERO (r))
529890075Sobrien    return 0;
529990075Sobrien
5300169689Skan  for (i = 0; i < fp_consts_inited; i++)
5301169689Skan    if (REAL_VALUES_EQUAL (r, values_fp[i]))
530290075Sobrien      return 1;
530390075Sobrien
530490075Sobrien  return 0;
530590075Sobrien}
530690075Sobrien
5307132718Skan/* Return TRUE if rtx X is a valid immediate FPA constant.  */
530890075Sobrienint
5309132718Skanneg_const_double_rtx_ok_for_fpa (rtx x)
531090075Sobrien{
531190075Sobrien  REAL_VALUE_TYPE r;
531290075Sobrien  int i;
5313169689Skan
5314169689Skan  if (!fp_consts_inited)
5315169689Skan    init_fp_table ();
5316169689Skan
531790075Sobrien  REAL_VALUE_FROM_CONST_DOUBLE (r, x);
531890075Sobrien  r = REAL_VALUE_NEGATE (r);
531990075Sobrien  if (REAL_VALUE_MINUS_ZERO (r))
532090075Sobrien    return 0;
532190075Sobrien
532290075Sobrien  for (i = 0; i < 8; i++)
5323169689Skan    if (REAL_VALUES_EQUAL (r, values_fp[i]))
532490075Sobrien      return 1;
532590075Sobrien
532690075Sobrien  return 0;
532790075Sobrien}
532890075Sobrien
532990075Sobrien/* Predicates for `match_operand' and `match_operator'.  */
533090075Sobrien
5331132718Skan/* Return nonzero if OP is a valid Cirrus memory address pattern.  */
5332132718Skanint
5333132718Skancirrus_memory_offset (rtx op)
5334132718Skan{
5335132718Skan  /* Reject eliminable registers.  */
5336132718Skan  if (! (reload_in_progress || reload_completed)
5337132718Skan      && (   reg_mentioned_p (frame_pointer_rtx, op)
5338132718Skan	  || reg_mentioned_p (arg_pointer_rtx, op)
5339132718Skan	  || reg_mentioned_p (virtual_incoming_args_rtx, op)
5340132718Skan	  || reg_mentioned_p (virtual_outgoing_args_rtx, op)
5341132718Skan	  || reg_mentioned_p (virtual_stack_dynamic_rtx, op)
5342132718Skan	  || reg_mentioned_p (virtual_stack_vars_rtx, op)))
5343132718Skan    return 0;
534490075Sobrien
5345132718Skan  if (GET_CODE (op) == MEM)
5346132718Skan    {
5347132718Skan      rtx ind;
5348132718Skan
5349132718Skan      ind = XEXP (op, 0);
5350132718Skan
5351132718Skan      /* Match: (mem (reg)).  */
5352132718Skan      if (GET_CODE (ind) == REG)
5353132718Skan	return 1;
5354132718Skan
5355132718Skan      /* Match:
5356132718Skan	 (mem (plus (reg)
5357132718Skan	            (const))).  */
5358132718Skan      if (GET_CODE (ind) == PLUS
5359132718Skan	  && GET_CODE (XEXP (ind, 0)) == REG
5360132718Skan	  && REG_MODE_OK_FOR_BASE_P (XEXP (ind, 0), VOIDmode)
5361132718Skan	  && GET_CODE (XEXP (ind, 1)) == CONST_INT)
5362132718Skan	return 1;
5363132718Skan    }
5364132718Skan
5365132718Skan  return 0;
5366132718Skan}
5367132718Skan
5368169689Skan/* Return TRUE if OP is a valid coprocessor memory address pattern.
5369169689Skan   WB if true if writeback address modes are allowed.  */
5370169689Skan
537190075Sobrienint
5372169689Skanarm_coproc_mem_operand (rtx op, bool wb)
537390075Sobrien{
5374169689Skan  rtx ind;
5375169689Skan
5376169689Skan  /* Reject eliminable registers.  */
5377169689Skan  if (! (reload_in_progress || reload_completed)
5378169689Skan      && (   reg_mentioned_p (frame_pointer_rtx, op)
5379169689Skan	  || reg_mentioned_p (arg_pointer_rtx, op)
5380169689Skan	  || reg_mentioned_p (virtual_incoming_args_rtx, op)
5381169689Skan	  || reg_mentioned_p (virtual_outgoing_args_rtx, op)
5382169689Skan	  || reg_mentioned_p (virtual_stack_dynamic_rtx, op)
5383169689Skan	  || reg_mentioned_p (virtual_stack_vars_rtx, op)))
5384132718Skan    return FALSE;
5385132718Skan
5386169689Skan  /* Constants are converted into offsets from labels.  */
5387169689Skan  if (GET_CODE (op) != MEM)
5388169689Skan    return FALSE;
5389132718Skan
5390169689Skan  ind = XEXP (op, 0);
5391132718Skan
5392169689Skan  if (reload_completed
5393169689Skan      && (GET_CODE (ind) == LABEL_REF
5394169689Skan	  || (GET_CODE (ind) == CONST
5395169689Skan	      && GET_CODE (XEXP (ind, 0)) == PLUS
5396169689Skan	      && GET_CODE (XEXP (XEXP (ind, 0), 0)) == LABEL_REF
5397169689Skan	      && GET_CODE (XEXP (XEXP (ind, 0), 1)) == CONST_INT)))
5398169689Skan    return TRUE;
5399132718Skan
5400169689Skan  /* Match: (mem (reg)).  */
5401169689Skan  if (GET_CODE (ind) == REG)
5402169689Skan    return arm_address_register_rtx_p (ind, 0);
5403132718Skan
5404169689Skan  /* Autoincremment addressing modes.  */
5405169689Skan  if (wb
5406169689Skan      && (GET_CODE (ind) == PRE_INC
5407169689Skan	  || GET_CODE (ind) == POST_INC
5408169689Skan	  || GET_CODE (ind) == PRE_DEC
5409169689Skan	  || GET_CODE (ind) == POST_DEC))
5410169689Skan    return arm_address_register_rtx_p (XEXP (ind, 0), 0);
5411132718Skan
5412169689Skan  if (wb
5413169689Skan      && (GET_CODE (ind) == POST_MODIFY || GET_CODE (ind) == PRE_MODIFY)
5414169689Skan      && arm_address_register_rtx_p (XEXP (ind, 0), 0)
5415169689Skan      && GET_CODE (XEXP (ind, 1)) == PLUS
5416169689Skan      && rtx_equal_p (XEXP (XEXP (ind, 1), 0), XEXP (ind, 0)))
5417169689Skan    ind = XEXP (ind, 1);
5418169689Skan
5419169689Skan  /* Match:
5420169689Skan     (plus (reg)
5421169689Skan	   (const)).  */
5422169689Skan  if (GET_CODE (ind) == PLUS
5423169689Skan      && GET_CODE (XEXP (ind, 0)) == REG
5424169689Skan      && REG_MODE_OK_FOR_BASE_P (XEXP (ind, 0), VOIDmode)
5425169689Skan      && GET_CODE (XEXP (ind, 1)) == CONST_INT
5426169689Skan      && INTVAL (XEXP (ind, 1)) > -1024
5427169689Skan      && INTVAL (XEXP (ind, 1)) <  1024
5428169689Skan      && (INTVAL (XEXP (ind, 1)) & 3) == 0)
5429169689Skan    return TRUE;
5430169689Skan
5431169689Skan  return FALSE;
5432132718Skan}
5433132718Skan
5434146895Skan/* Return true if X is a register that will be eliminated later on.  */
5435146895Skanint
5436146895Skanarm_eliminable_register (rtx x)
5437146895Skan{
5438146895Skan  return REG_P (x) && (REGNO (x) == FRAME_POINTER_REGNUM
5439146895Skan		       || REGNO (x) == ARG_POINTER_REGNUM
5440146895Skan		       || (REGNO (x) >= FIRST_VIRTUAL_REGISTER
5441146895Skan			   && REGNO (x) <= LAST_VIRTUAL_REGISTER));
5442146895Skan}
5443146895Skan
5444169689Skan/* Return GENERAL_REGS if a scratch register required to reload x to/from
5445169689Skan   coprocessor registers.  Otherwise return NO_REGS.  */
5446169689Skan
5447169689Skanenum reg_class
5448169689Skancoproc_secondary_reload_class (enum machine_mode mode, rtx x, bool wb)
5449169689Skan{
5450169689Skan  if (arm_coproc_mem_operand (x, wb) || s_register_operand (x, mode))
5451169689Skan    return NO_REGS;
5452169689Skan
5453169689Skan  return GENERAL_REGS;
5454169689Skan}
5455169689Skan
5456169689Skan/* Values which must be returned in the most-significant end of the return
5457169689Skan   register.  */
5458169689Skan
5459169689Skanstatic bool
5460169689Skanarm_return_in_msb (tree valtype)
5461169689Skan{
5462169689Skan  return (TARGET_AAPCS_BASED
5463169689Skan          && BYTES_BIG_ENDIAN
5464169689Skan          && (AGGREGATE_TYPE_P (valtype)
5465169689Skan              || TREE_CODE (valtype) == COMPLEX_TYPE));
5466169689Skan}
5467169689Skan
5468132718Skan/* Returns TRUE if INSN is an "LDR REG, ADDR" instruction.
5469132718Skan   Use by the Cirrus Maverick code which has to workaround
5470132718Skan   a hardware bug triggered by such instructions.  */
5471132718Skanstatic bool
5472132718Skanarm_memory_load_p (rtx insn)
5473132718Skan{
5474132718Skan  rtx body, lhs, rhs;;
5475132718Skan
5476132718Skan  if (insn == NULL_RTX || GET_CODE (insn) != INSN)
5477132718Skan    return false;
5478132718Skan
5479132718Skan  body = PATTERN (insn);
5480132718Skan
5481132718Skan  if (GET_CODE (body) != SET)
5482132718Skan    return false;
5483132718Skan
5484132718Skan  lhs = XEXP (body, 0);
5485132718Skan  rhs = XEXP (body, 1);
5486132718Skan
5487132718Skan  lhs = REG_OR_SUBREG_RTX (lhs);
5488132718Skan
5489132718Skan  /* If the destination is not a general purpose
5490132718Skan     register we do not have to worry.  */
5491132718Skan  if (GET_CODE (lhs) != REG
5492132718Skan      || REGNO_REG_CLASS (REGNO (lhs)) != GENERAL_REGS)
5493132718Skan    return false;
5494132718Skan
5495132718Skan  /* As well as loads from memory we also have to react
5496132718Skan     to loads of invalid constants which will be turned
5497132718Skan     into loads from the minipool.  */
5498132718Skan  return (GET_CODE (rhs) == MEM
5499132718Skan	  || GET_CODE (rhs) == SYMBOL_REF
5500132718Skan	  || note_invalid_constants (insn, -1, false));
5501132718Skan}
5502132718Skan
5503132718Skan/* Return TRUE if INSN is a Cirrus instruction.  */
5504132718Skanstatic bool
5505132718Skanarm_cirrus_insn_p (rtx insn)
5506132718Skan{
5507132718Skan  enum attr_cirrus attr;
5508132718Skan
5509169689Skan  /* get_attr cannot accept USE or CLOBBER.  */
5510132718Skan  if (!insn
5511132718Skan      || GET_CODE (insn) != INSN
5512132718Skan      || GET_CODE (PATTERN (insn)) == USE
5513132718Skan      || GET_CODE (PATTERN (insn)) == CLOBBER)
5514132718Skan    return 0;
5515132718Skan
5516132718Skan  attr = get_attr_cirrus (insn);
5517132718Skan
5518132718Skan  return attr != CIRRUS_NOT;
5519132718Skan}
5520132718Skan
5521132718Skan/* Cirrus reorg for invalid instruction combinations.  */
5522132718Skanstatic void
5523132718Skancirrus_reorg (rtx first)
5524132718Skan{
5525132718Skan  enum attr_cirrus attr;
5526132718Skan  rtx body = PATTERN (first);
5527132718Skan  rtx t;
5528132718Skan  int nops;
5529132718Skan
5530132718Skan  /* Any branch must be followed by 2 non Cirrus instructions.  */
5531132718Skan  if (GET_CODE (first) == JUMP_INSN && GET_CODE (body) != RETURN)
5532132718Skan    {
5533132718Skan      nops = 0;
5534132718Skan      t = next_nonnote_insn (first);
5535132718Skan
5536132718Skan      if (arm_cirrus_insn_p (t))
5537132718Skan	++ nops;
5538132718Skan
5539132718Skan      if (arm_cirrus_insn_p (next_nonnote_insn (t)))
5540132718Skan	++ nops;
5541132718Skan
5542132718Skan      while (nops --)
5543132718Skan	emit_insn_after (gen_nop (), first);
5544132718Skan
5545132718Skan      return;
5546132718Skan    }
5547132718Skan
5548132718Skan  /* (float (blah)) is in parallel with a clobber.  */
5549132718Skan  if (GET_CODE (body) == PARALLEL && XVECLEN (body, 0) > 0)
5550132718Skan    body = XVECEXP (body, 0, 0);
5551132718Skan
5552132718Skan  if (GET_CODE (body) == SET)
5553132718Skan    {
5554132718Skan      rtx lhs = XEXP (body, 0), rhs = XEXP (body, 1);
5555132718Skan
5556132718Skan      /* cfldrd, cfldr64, cfstrd, cfstr64 must
5557132718Skan	 be followed by a non Cirrus insn.  */
5558132718Skan      if (get_attr_cirrus (first) == CIRRUS_DOUBLE)
5559132718Skan	{
5560132718Skan	  if (arm_cirrus_insn_p (next_nonnote_insn (first)))
5561132718Skan	    emit_insn_after (gen_nop (), first);
5562132718Skan
5563132718Skan	  return;
5564132718Skan	}
5565132718Skan      else if (arm_memory_load_p (first))
5566132718Skan	{
5567132718Skan	  unsigned int arm_regno;
5568132718Skan
5569132718Skan	  /* Any ldr/cfmvdlr, ldr/cfmvdhr, ldr/cfmvsr, ldr/cfmv64lr,
5570132718Skan	     ldr/cfmv64hr combination where the Rd field is the same
5571132718Skan	     in both instructions must be split with a non Cirrus
5572132718Skan	     insn.  Example:
5573132718Skan
5574132718Skan	     ldr r0, blah
5575132718Skan	     nop
5576132718Skan	     cfmvsr mvf0, r0.  */
5577132718Skan
5578132718Skan	  /* Get Arm register number for ldr insn.  */
5579132718Skan	  if (GET_CODE (lhs) == REG)
5580132718Skan	    arm_regno = REGNO (lhs);
5581132718Skan	  else
5582169689Skan	    {
5583169689Skan	      gcc_assert (GET_CODE (rhs) == REG);
5584169689Skan	      arm_regno = REGNO (rhs);
5585169689Skan	    }
5586132718Skan
5587132718Skan	  /* Next insn.  */
5588132718Skan	  first = next_nonnote_insn (first);
5589132718Skan
5590132718Skan	  if (! arm_cirrus_insn_p (first))
5591132718Skan	    return;
5592132718Skan
5593132718Skan	  body = PATTERN (first);
5594132718Skan
5595132718Skan          /* (float (blah)) is in parallel with a clobber.  */
5596132718Skan          if (GET_CODE (body) == PARALLEL && XVECLEN (body, 0))
5597132718Skan	    body = XVECEXP (body, 0, 0);
5598132718Skan
5599132718Skan	  if (GET_CODE (body) == FLOAT)
5600132718Skan	    body = XEXP (body, 0);
5601132718Skan
5602132718Skan	  if (get_attr_cirrus (first) == CIRRUS_MOVE
5603132718Skan	      && GET_CODE (XEXP (body, 1)) == REG
5604132718Skan	      && arm_regno == REGNO (XEXP (body, 1)))
5605132718Skan	    emit_insn_after (gen_nop (), first);
5606132718Skan
5607132718Skan	  return;
5608132718Skan	}
5609132718Skan    }
5610132718Skan
5611169689Skan  /* get_attr cannot accept USE or CLOBBER.  */
5612132718Skan  if (!first
5613132718Skan      || GET_CODE (first) != INSN
5614132718Skan      || GET_CODE (PATTERN (first)) == USE
5615132718Skan      || GET_CODE (PATTERN (first)) == CLOBBER)
5616132718Skan    return;
5617132718Skan
5618132718Skan  attr = get_attr_cirrus (first);
5619132718Skan
5620132718Skan  /* Any coprocessor compare instruction (cfcmps, cfcmpd, ...)
5621132718Skan     must be followed by a non-coprocessor instruction.  */
5622132718Skan  if (attr == CIRRUS_COMPARE)
5623132718Skan    {
5624132718Skan      nops = 0;
5625132718Skan
5626132718Skan      t = next_nonnote_insn (first);
5627132718Skan
5628132718Skan      if (arm_cirrus_insn_p (t))
5629132718Skan	++ nops;
5630132718Skan
5631132718Skan      if (arm_cirrus_insn_p (next_nonnote_insn (t)))
5632132718Skan	++ nops;
5633132718Skan
5634132718Skan      while (nops --)
5635132718Skan	emit_insn_after (gen_nop (), first);
5636132718Skan
5637132718Skan      return;
5638132718Skan    }
5639132718Skan}
5640132718Skan
564190075Sobrien/* Return TRUE if X references a SYMBOL_REF.  */
564290075Sobrienint
5643132718Skansymbol_mentioned_p (rtx x)
564490075Sobrien{
564590075Sobrien  const char * fmt;
564690075Sobrien  int i;
564790075Sobrien
564890075Sobrien  if (GET_CODE (x) == SYMBOL_REF)
564990075Sobrien    return 1;
565090075Sobrien
5651169689Skan  /* UNSPEC_TLS entries for a symbol include the SYMBOL_REF, but they
5652169689Skan     are constant offsets, not symbols.  */
5653169689Skan  if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLS)
5654169689Skan    return 0;
5655169689Skan
565690075Sobrien  fmt = GET_RTX_FORMAT (GET_CODE (x));
5657169689Skan
565890075Sobrien  for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
565990075Sobrien    {
566090075Sobrien      if (fmt[i] == 'E')
566190075Sobrien	{
566290075Sobrien	  int j;
566390075Sobrien
566490075Sobrien	  for (j = XVECLEN (x, i) - 1; j >= 0; j--)
566590075Sobrien	    if (symbol_mentioned_p (XVECEXP (x, i, j)))
566690075Sobrien	      return 1;
566790075Sobrien	}
566890075Sobrien      else if (fmt[i] == 'e' && symbol_mentioned_p (XEXP (x, i)))
566990075Sobrien	return 1;
567090075Sobrien    }
567190075Sobrien
567290075Sobrien  return 0;
567390075Sobrien}
567490075Sobrien
567590075Sobrien/* Return TRUE if X references a LABEL_REF.  */
567690075Sobrienint
5677132718Skanlabel_mentioned_p (rtx x)
567890075Sobrien{
567990075Sobrien  const char * fmt;
568090075Sobrien  int i;
568190075Sobrien
568290075Sobrien  if (GET_CODE (x) == LABEL_REF)
568390075Sobrien    return 1;
568490075Sobrien
5685169689Skan  /* UNSPEC_TLS entries for a symbol include a LABEL_REF for the referencing
5686169689Skan     instruction, but they are constant offsets, not symbols.  */
5687169689Skan  if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLS)
5688169689Skan    return 0;
5689169689Skan
569090075Sobrien  fmt = GET_RTX_FORMAT (GET_CODE (x));
569190075Sobrien  for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
569290075Sobrien    {
569390075Sobrien      if (fmt[i] == 'E')
569490075Sobrien	{
569590075Sobrien	  int j;
569690075Sobrien
569790075Sobrien	  for (j = XVECLEN (x, i) - 1; j >= 0; j--)
569890075Sobrien	    if (label_mentioned_p (XVECEXP (x, i, j)))
569990075Sobrien	      return 1;
570090075Sobrien	}
570190075Sobrien      else if (fmt[i] == 'e' && label_mentioned_p (XEXP (x, i)))
570290075Sobrien	return 1;
570390075Sobrien    }
570490075Sobrien
570590075Sobrien  return 0;
570690075Sobrien}
570790075Sobrien
5708169689Skanint
5709169689Skantls_mentioned_p (rtx x)
5710169689Skan{
5711169689Skan  switch (GET_CODE (x))
5712169689Skan    {
5713169689Skan    case CONST:
5714169689Skan      return tls_mentioned_p (XEXP (x, 0));
5715169689Skan
5716169689Skan    case UNSPEC:
5717169689Skan      if (XINT (x, 1) == UNSPEC_TLS)
5718169689Skan	return 1;
5719169689Skan
5720169689Skan    default:
5721169689Skan      return 0;
5722169689Skan    }
5723169689Skan}
5724169689Skan
5725169689Skan/* Must not copy a SET whose source operand is PC-relative.  */
5726169689Skan
5727169689Skanstatic bool
5728169689Skanarm_cannot_copy_insn_p (rtx insn)
5729169689Skan{
5730169689Skan  rtx pat = PATTERN (insn);
5731169689Skan
5732169689Skan  if (GET_CODE (pat) == PARALLEL
5733169689Skan      && GET_CODE (XVECEXP (pat, 0, 0)) == SET)
5734169689Skan    {
5735169689Skan      rtx rhs = SET_SRC (XVECEXP (pat, 0, 0));
5736169689Skan
5737169689Skan      if (GET_CODE (rhs) == UNSPEC
5738169689Skan	  && XINT (rhs, 1) == UNSPEC_PIC_BASE)
5739169689Skan	return TRUE;
5740169689Skan
5741169689Skan      if (GET_CODE (rhs) == MEM
5742169689Skan	  && GET_CODE (XEXP (rhs, 0)) == UNSPEC
5743169689Skan	  && XINT (XEXP (rhs, 0), 1) == UNSPEC_PIC_BASE)
5744169689Skan	return TRUE;
5745169689Skan    }
5746169689Skan
5747169689Skan  return FALSE;
5748169689Skan}
5749169689Skan
575090075Sobrienenum rtx_code
5751132718Skanminmax_code (rtx x)
575290075Sobrien{
575390075Sobrien  enum rtx_code code = GET_CODE (x);
575490075Sobrien
5755169689Skan  switch (code)
5756169689Skan    {
5757169689Skan    case SMAX:
5758169689Skan      return GE;
5759169689Skan    case SMIN:
5760169689Skan      return LE;
5761169689Skan    case UMIN:
5762169689Skan      return LEU;
5763169689Skan    case UMAX:
5764169689Skan      return GEU;
5765169689Skan    default:
5766169689Skan      gcc_unreachable ();
5767169689Skan    }
576890075Sobrien}
576990075Sobrien
577090075Sobrien/* Return 1 if memory locations are adjacent.  */
577190075Sobrienint
5772132718Skanadjacent_mem_locations (rtx a, rtx b)
577390075Sobrien{
5774169689Skan  /* We don't guarantee to preserve the order of these memory refs.  */
5775169689Skan  if (volatile_refs_p (a) || volatile_refs_p (b))
5776169689Skan    return 0;
5777169689Skan
577890075Sobrien  if ((GET_CODE (XEXP (a, 0)) == REG
577990075Sobrien       || (GET_CODE (XEXP (a, 0)) == PLUS
578090075Sobrien	   && GET_CODE (XEXP (XEXP (a, 0), 1)) == CONST_INT))
578190075Sobrien      && (GET_CODE (XEXP (b, 0)) == REG
578290075Sobrien	  || (GET_CODE (XEXP (b, 0)) == PLUS
578390075Sobrien	      && GET_CODE (XEXP (XEXP (b, 0), 1)) == CONST_INT)))
578490075Sobrien    {
5785146895Skan      HOST_WIDE_INT val0 = 0, val1 = 0;
5786146895Skan      rtx reg0, reg1;
5787146895Skan      int val_diff;
5788146895Skan
578990075Sobrien      if (GET_CODE (XEXP (a, 0)) == PLUS)
579090075Sobrien        {
5791146895Skan	  reg0 = XEXP (XEXP (a, 0), 0);
579290075Sobrien	  val0 = INTVAL (XEXP (XEXP (a, 0), 1));
579390075Sobrien        }
579490075Sobrien      else
5795146895Skan	reg0 = XEXP (a, 0);
579690075Sobrien
579790075Sobrien      if (GET_CODE (XEXP (b, 0)) == PLUS)
579890075Sobrien        {
5799146895Skan	  reg1 = XEXP (XEXP (b, 0), 0);
580090075Sobrien	  val1 = INTVAL (XEXP (XEXP (b, 0), 1));
580190075Sobrien        }
580290075Sobrien      else
5803146895Skan	reg1 = XEXP (b, 0);
580490075Sobrien
5805132718Skan      /* Don't accept any offset that will require multiple
5806132718Skan	 instructions to handle, since this would cause the
5807132718Skan	 arith_adjacentmem pattern to output an overlong sequence.  */
5808132718Skan      if (!const_ok_for_op (PLUS, val0) || !const_ok_for_op (PLUS, val1))
5809132718Skan	return 0;
5810146895Skan
5811146895Skan      /* Don't allow an eliminable register: register elimination can make
5812146895Skan	 the offset too large.  */
5813146895Skan      if (arm_eliminable_register (reg0))
5814146895Skan	return 0;
5815146895Skan
5816146895Skan      val_diff = val1 - val0;
5817169689Skan
5818169689Skan      if (arm_ld_sched)
5819169689Skan	{
5820169689Skan	  /* If the target has load delay slots, then there's no benefit
5821169689Skan	     to using an ldm instruction unless the offset is zero and
5822169689Skan	     we are optimizing for size.  */
5823169689Skan	  return (optimize_size && (REGNO (reg0) == REGNO (reg1))
5824169689Skan		  && (val0 == 0 || val1 == 0 || val0 == 4 || val1 == 4)
5825169689Skan		  && (val_diff == 4 || val_diff == -4));
5826169689Skan	}
5827169689Skan
5828146895Skan      return ((REGNO (reg0) == REGNO (reg1))
5829146895Skan	      && (val_diff == 4 || val_diff == -4));
583090075Sobrien    }
5831146895Skan
583290075Sobrien  return 0;
583390075Sobrien}
583490075Sobrien
583590075Sobrienint
5836132718Skanload_multiple_sequence (rtx *operands, int nops, int *regs, int *base,
5837132718Skan			HOST_WIDE_INT *load_offset)
583890075Sobrien{
583990075Sobrien  int unsorted_regs[4];
584090075Sobrien  HOST_WIDE_INT unsorted_offsets[4];
584190075Sobrien  int order[4];
584290075Sobrien  int base_reg = -1;
584390075Sobrien  int i;
584490075Sobrien
584590075Sobrien  /* Can only handle 2, 3, or 4 insns at present,
584690075Sobrien     though could be easily extended if required.  */
5847169689Skan  gcc_assert (nops >= 2 && nops <= 4);
584890075Sobrien
584990075Sobrien  /* Loop over the operands and check that the memory references are
5850169689Skan     suitable (i.e. immediate offsets from the same base register).  At
585190075Sobrien     the same time, extract the target register, and the memory
585290075Sobrien     offsets.  */
585390075Sobrien  for (i = 0; i < nops; i++)
585490075Sobrien    {
585590075Sobrien      rtx reg;
585690075Sobrien      rtx offset;
585790075Sobrien
585890075Sobrien      /* Convert a subreg of a mem into the mem itself.  */
585990075Sobrien      if (GET_CODE (operands[nops + i]) == SUBREG)
586090075Sobrien	operands[nops + i] = alter_subreg (operands + (nops + i));
586190075Sobrien
5862169689Skan      gcc_assert (GET_CODE (operands[nops + i]) == MEM);
586390075Sobrien
586490075Sobrien      /* Don't reorder volatile memory references; it doesn't seem worth
586590075Sobrien	 looking for the case where the order is ok anyway.  */
586690075Sobrien      if (MEM_VOLATILE_P (operands[nops + i]))
586790075Sobrien	return 0;
586890075Sobrien
586990075Sobrien      offset = const0_rtx;
587090075Sobrien
587190075Sobrien      if ((GET_CODE (reg = XEXP (operands[nops + i], 0)) == REG
587290075Sobrien	   || (GET_CODE (reg) == SUBREG
587390075Sobrien	       && GET_CODE (reg = SUBREG_REG (reg)) == REG))
587490075Sobrien	  || (GET_CODE (XEXP (operands[nops + i], 0)) == PLUS
587590075Sobrien	      && ((GET_CODE (reg = XEXP (XEXP (operands[nops + i], 0), 0))
587690075Sobrien		   == REG)
587790075Sobrien		  || (GET_CODE (reg) == SUBREG
587890075Sobrien		      && GET_CODE (reg = SUBREG_REG (reg)) == REG))
587990075Sobrien	      && (GET_CODE (offset = XEXP (XEXP (operands[nops + i], 0), 1))
588090075Sobrien		  == CONST_INT)))
588190075Sobrien	{
588290075Sobrien	  if (i == 0)
588390075Sobrien	    {
588490075Sobrien	      base_reg = REGNO (reg);
588590075Sobrien	      unsorted_regs[0] = (GET_CODE (operands[i]) == REG
588690075Sobrien				  ? REGNO (operands[i])
588790075Sobrien				  : REGNO (SUBREG_REG (operands[i])));
588890075Sobrien	      order[0] = 0;
588990075Sobrien	    }
5890169689Skan	  else
589190075Sobrien	    {
589290075Sobrien	      if (base_reg != (int) REGNO (reg))
589390075Sobrien		/* Not addressed from the same base register.  */
589490075Sobrien		return 0;
589590075Sobrien
589690075Sobrien	      unsorted_regs[i] = (GET_CODE (operands[i]) == REG
589790075Sobrien				  ? REGNO (operands[i])
589890075Sobrien				  : REGNO (SUBREG_REG (operands[i])));
589990075Sobrien	      if (unsorted_regs[i] < unsorted_regs[order[0]])
590090075Sobrien		order[0] = i;
590190075Sobrien	    }
590290075Sobrien
590390075Sobrien	  /* If it isn't an integer register, or if it overwrites the
590490075Sobrien	     base register but isn't the last insn in the list, then
590590075Sobrien	     we can't do this.  */
590690075Sobrien	  if (unsorted_regs[i] < 0 || unsorted_regs[i] > 14
590790075Sobrien	      || (i != nops - 1 && unsorted_regs[i] == base_reg))
590890075Sobrien	    return 0;
590990075Sobrien
591090075Sobrien	  unsorted_offsets[i] = INTVAL (offset);
591190075Sobrien	}
591290075Sobrien      else
591390075Sobrien	/* Not a suitable memory address.  */
591490075Sobrien	return 0;
591590075Sobrien    }
591690075Sobrien
591790075Sobrien  /* All the useful information has now been extracted from the
591890075Sobrien     operands into unsorted_regs and unsorted_offsets; additionally,
591990075Sobrien     order[0] has been set to the lowest numbered register in the
592090075Sobrien     list.  Sort the registers into order, and check that the memory
592190075Sobrien     offsets are ascending and adjacent.  */
592290075Sobrien
592390075Sobrien  for (i = 1; i < nops; i++)
592490075Sobrien    {
592590075Sobrien      int j;
592690075Sobrien
592790075Sobrien      order[i] = order[i - 1];
592890075Sobrien      for (j = 0; j < nops; j++)
592990075Sobrien	if (unsorted_regs[j] > unsorted_regs[order[i - 1]]
593090075Sobrien	    && (order[i] == order[i - 1]
593190075Sobrien		|| unsorted_regs[j] < unsorted_regs[order[i]]))
593290075Sobrien	  order[i] = j;
593390075Sobrien
593490075Sobrien      /* Have we found a suitable register? if not, one must be used more
593590075Sobrien	 than once.  */
593690075Sobrien      if (order[i] == order[i - 1])
593790075Sobrien	return 0;
593890075Sobrien
593990075Sobrien      /* Is the memory address adjacent and ascending? */
594090075Sobrien      if (unsorted_offsets[order[i]] != unsorted_offsets[order[i - 1]] + 4)
594190075Sobrien	return 0;
594290075Sobrien    }
594390075Sobrien
594490075Sobrien  if (base)
594590075Sobrien    {
594690075Sobrien      *base = base_reg;
594790075Sobrien
594890075Sobrien      for (i = 0; i < nops; i++)
594990075Sobrien	regs[i] = unsorted_regs[order[i]];
595090075Sobrien
595190075Sobrien      *load_offset = unsorted_offsets[order[0]];
595290075Sobrien    }
595390075Sobrien
595490075Sobrien  if (unsorted_offsets[order[0]] == 0)
595590075Sobrien    return 1; /* ldmia */
595690075Sobrien
595790075Sobrien  if (unsorted_offsets[order[0]] == 4)
595890075Sobrien    return 2; /* ldmib */
595990075Sobrien
596090075Sobrien  if (unsorted_offsets[order[nops - 1]] == 0)
596190075Sobrien    return 3; /* ldmda */
596290075Sobrien
596390075Sobrien  if (unsorted_offsets[order[nops - 1]] == -4)
596490075Sobrien    return 4; /* ldmdb */
596590075Sobrien
596690075Sobrien  /* For ARM8,9 & StrongARM, 2 ldr instructions are faster than an ldm
596790075Sobrien     if the offset isn't small enough.  The reason 2 ldrs are faster
596890075Sobrien     is because these ARMs are able to do more than one cache access
596990075Sobrien     in a single cycle.  The ARM9 and StrongARM have Harvard caches,
597090075Sobrien     whilst the ARM8 has a double bandwidth cache.  This means that
597190075Sobrien     these cores can do both an instruction fetch and a data fetch in
597290075Sobrien     a single cycle, so the trick of calculating the address into a
597390075Sobrien     scratch register (one of the result regs) and then doing a load
597490075Sobrien     multiple actually becomes slower (and no smaller in code size).
597590075Sobrien     That is the transformation
5976169689Skan
597790075Sobrien 	ldr	rd1, [rbase + offset]
597890075Sobrien 	ldr	rd2, [rbase + offset + 4]
5979169689Skan
598090075Sobrien     to
5981169689Skan
598290075Sobrien 	add	rd1, rbase, offset
598390075Sobrien 	ldmia	rd1, {rd1, rd2}
5984169689Skan
598590075Sobrien     produces worse code -- '3 cycles + any stalls on rd2' instead of
598690075Sobrien     '2 cycles + any stalls on rd2'.  On ARMs with only one cache
598790075Sobrien     access per cycle, the first sequence could never complete in less
598890075Sobrien     than 6 cycles, whereas the ldm sequence would only take 5 and
598990075Sobrien     would make better use of sequential accesses if not hitting the
599090075Sobrien     cache.
599190075Sobrien
599290075Sobrien     We cheat here and test 'arm_ld_sched' which we currently know to
599390075Sobrien     only be true for the ARM8, ARM9 and StrongARM.  If this ever
599490075Sobrien     changes, then the test below needs to be reworked.  */
599590075Sobrien  if (nops == 2 && arm_ld_sched)
599690075Sobrien    return 0;
599790075Sobrien
599890075Sobrien  /* Can't do it without setting up the offset, only do this if it takes
599990075Sobrien     no more than one insn.  */
6000169689Skan  return (const_ok_for_arm (unsorted_offsets[order[0]])
600190075Sobrien	  || const_ok_for_arm (-unsorted_offsets[order[0]])) ? 5 : 0;
600290075Sobrien}
600390075Sobrien
600490075Sobrienconst char *
6005132718Skanemit_ldm_seq (rtx *operands, int nops)
600690075Sobrien{
600790075Sobrien  int regs[4];
600890075Sobrien  int base_reg;
600990075Sobrien  HOST_WIDE_INT offset;
601090075Sobrien  char buf[100];
601190075Sobrien  int i;
601290075Sobrien
601390075Sobrien  switch (load_multiple_sequence (operands, nops, regs, &base_reg, &offset))
601490075Sobrien    {
601590075Sobrien    case 1:
601690075Sobrien      strcpy (buf, "ldm%?ia\t");
601790075Sobrien      break;
601890075Sobrien
601990075Sobrien    case 2:
602090075Sobrien      strcpy (buf, "ldm%?ib\t");
602190075Sobrien      break;
602290075Sobrien
602390075Sobrien    case 3:
602490075Sobrien      strcpy (buf, "ldm%?da\t");
602590075Sobrien      break;
602690075Sobrien
602790075Sobrien    case 4:
602890075Sobrien      strcpy (buf, "ldm%?db\t");
602990075Sobrien      break;
603090075Sobrien
603190075Sobrien    case 5:
603290075Sobrien      if (offset >= 0)
603390075Sobrien	sprintf (buf, "add%%?\t%s%s, %s%s, #%ld", REGISTER_PREFIX,
603490075Sobrien		 reg_names[regs[0]], REGISTER_PREFIX, reg_names[base_reg],
603590075Sobrien		 (long) offset);
603690075Sobrien      else
603790075Sobrien	sprintf (buf, "sub%%?\t%s%s, %s%s, #%ld", REGISTER_PREFIX,
603890075Sobrien		 reg_names[regs[0]], REGISTER_PREFIX, reg_names[base_reg],
603990075Sobrien		 (long) -offset);
604090075Sobrien      output_asm_insn (buf, operands);
604190075Sobrien      base_reg = regs[0];
604290075Sobrien      strcpy (buf, "ldm%?ia\t");
604390075Sobrien      break;
604490075Sobrien
604590075Sobrien    default:
6046169689Skan      gcc_unreachable ();
604790075Sobrien    }
604890075Sobrien
6049169689Skan  sprintf (buf + strlen (buf), "%s%s, {%s%s", REGISTER_PREFIX,
605090075Sobrien	   reg_names[base_reg], REGISTER_PREFIX, reg_names[regs[0]]);
605190075Sobrien
605290075Sobrien  for (i = 1; i < nops; i++)
605390075Sobrien    sprintf (buf + strlen (buf), ", %s%s", REGISTER_PREFIX,
605490075Sobrien	     reg_names[regs[i]]);
605590075Sobrien
605690075Sobrien  strcat (buf, "}\t%@ phole ldm");
605790075Sobrien
605890075Sobrien  output_asm_insn (buf, operands);
605990075Sobrien  return "";
606090075Sobrien}
606190075Sobrien
606290075Sobrienint
6063132718Skanstore_multiple_sequence (rtx *operands, int nops, int *regs, int *base,
6064132718Skan			 HOST_WIDE_INT * load_offset)
606590075Sobrien{
606690075Sobrien  int unsorted_regs[4];
606790075Sobrien  HOST_WIDE_INT unsorted_offsets[4];
606890075Sobrien  int order[4];
606990075Sobrien  int base_reg = -1;
607090075Sobrien  int i;
607190075Sobrien
607290075Sobrien  /* Can only handle 2, 3, or 4 insns at present, though could be easily
607390075Sobrien     extended if required.  */
6074169689Skan  gcc_assert (nops >= 2 && nops <= 4);
607590075Sobrien
607690075Sobrien  /* Loop over the operands and check that the memory references are
6077169689Skan     suitable (i.e. immediate offsets from the same base register).  At
607890075Sobrien     the same time, extract the target register, and the memory
607990075Sobrien     offsets.  */
608090075Sobrien  for (i = 0; i < nops; i++)
608190075Sobrien    {
608290075Sobrien      rtx reg;
608390075Sobrien      rtx offset;
608490075Sobrien
608590075Sobrien      /* Convert a subreg of a mem into the mem itself.  */
608690075Sobrien      if (GET_CODE (operands[nops + i]) == SUBREG)
608790075Sobrien	operands[nops + i] = alter_subreg (operands + (nops + i));
608890075Sobrien
6089169689Skan      gcc_assert (GET_CODE (operands[nops + i]) == MEM);
609090075Sobrien
609190075Sobrien      /* Don't reorder volatile memory references; it doesn't seem worth
609290075Sobrien	 looking for the case where the order is ok anyway.  */
609390075Sobrien      if (MEM_VOLATILE_P (operands[nops + i]))
609490075Sobrien	return 0;
609590075Sobrien
609690075Sobrien      offset = const0_rtx;
609790075Sobrien
609890075Sobrien      if ((GET_CODE (reg = XEXP (operands[nops + i], 0)) == REG
609990075Sobrien	   || (GET_CODE (reg) == SUBREG
610090075Sobrien	       && GET_CODE (reg = SUBREG_REG (reg)) == REG))
610190075Sobrien	  || (GET_CODE (XEXP (operands[nops + i], 0)) == PLUS
610290075Sobrien	      && ((GET_CODE (reg = XEXP (XEXP (operands[nops + i], 0), 0))
610390075Sobrien		   == REG)
610490075Sobrien		  || (GET_CODE (reg) == SUBREG
610590075Sobrien		      && GET_CODE (reg = SUBREG_REG (reg)) == REG))
610690075Sobrien	      && (GET_CODE (offset = XEXP (XEXP (operands[nops + i], 0), 1))
610790075Sobrien		  == CONST_INT)))
610890075Sobrien	{
610990075Sobrien	  if (i == 0)
611090075Sobrien	    {
611190075Sobrien	      base_reg = REGNO (reg);
611290075Sobrien	      unsorted_regs[0] = (GET_CODE (operands[i]) == REG
611390075Sobrien				  ? REGNO (operands[i])
611490075Sobrien				  : REGNO (SUBREG_REG (operands[i])));
611590075Sobrien	      order[0] = 0;
611690075Sobrien	    }
6117169689Skan	  else
611890075Sobrien	    {
611990075Sobrien	      if (base_reg != (int) REGNO (reg))
612090075Sobrien		/* Not addressed from the same base register.  */
612190075Sobrien		return 0;
612290075Sobrien
612390075Sobrien	      unsorted_regs[i] = (GET_CODE (operands[i]) == REG
612490075Sobrien				  ? REGNO (operands[i])
612590075Sobrien				  : REGNO (SUBREG_REG (operands[i])));
612690075Sobrien	      if (unsorted_regs[i] < unsorted_regs[order[0]])
612790075Sobrien		order[0] = i;
612890075Sobrien	    }
612990075Sobrien
613090075Sobrien	  /* If it isn't an integer register, then we can't do this.  */
613190075Sobrien	  if (unsorted_regs[i] < 0 || unsorted_regs[i] > 14)
613290075Sobrien	    return 0;
613390075Sobrien
613490075Sobrien	  unsorted_offsets[i] = INTVAL (offset);
613590075Sobrien	}
613690075Sobrien      else
613790075Sobrien	/* Not a suitable memory address.  */
613890075Sobrien	return 0;
613990075Sobrien    }
614090075Sobrien
614190075Sobrien  /* All the useful information has now been extracted from the
614290075Sobrien     operands into unsorted_regs and unsorted_offsets; additionally,
614390075Sobrien     order[0] has been set to the lowest numbered register in the
614490075Sobrien     list.  Sort the registers into order, and check that the memory
614590075Sobrien     offsets are ascending and adjacent.  */
614690075Sobrien
614790075Sobrien  for (i = 1; i < nops; i++)
614890075Sobrien    {
614990075Sobrien      int j;
615090075Sobrien
615190075Sobrien      order[i] = order[i - 1];
615290075Sobrien      for (j = 0; j < nops; j++)
615390075Sobrien	if (unsorted_regs[j] > unsorted_regs[order[i - 1]]
615490075Sobrien	    && (order[i] == order[i - 1]
615590075Sobrien		|| unsorted_regs[j] < unsorted_regs[order[i]]))
615690075Sobrien	  order[i] = j;
615790075Sobrien
615890075Sobrien      /* Have we found a suitable register? if not, one must be used more
615990075Sobrien	 than once.  */
616090075Sobrien      if (order[i] == order[i - 1])
616190075Sobrien	return 0;
616290075Sobrien
616390075Sobrien      /* Is the memory address adjacent and ascending? */
616490075Sobrien      if (unsorted_offsets[order[i]] != unsorted_offsets[order[i - 1]] + 4)
616590075Sobrien	return 0;
616690075Sobrien    }
616790075Sobrien
616890075Sobrien  if (base)
616990075Sobrien    {
617090075Sobrien      *base = base_reg;
617190075Sobrien
617290075Sobrien      for (i = 0; i < nops; i++)
617390075Sobrien	regs[i] = unsorted_regs[order[i]];
617490075Sobrien
617590075Sobrien      *load_offset = unsorted_offsets[order[0]];
617690075Sobrien    }
617790075Sobrien
617890075Sobrien  if (unsorted_offsets[order[0]] == 0)
617990075Sobrien    return 1; /* stmia */
618090075Sobrien
618190075Sobrien  if (unsorted_offsets[order[0]] == 4)
618290075Sobrien    return 2; /* stmib */
618390075Sobrien
618490075Sobrien  if (unsorted_offsets[order[nops - 1]] == 0)
618590075Sobrien    return 3; /* stmda */
618690075Sobrien
618790075Sobrien  if (unsorted_offsets[order[nops - 1]] == -4)
618890075Sobrien    return 4; /* stmdb */
618990075Sobrien
619090075Sobrien  return 0;
619190075Sobrien}
619290075Sobrien
619390075Sobrienconst char *
6194132718Skanemit_stm_seq (rtx *operands, int nops)
619590075Sobrien{
619690075Sobrien  int regs[4];
619790075Sobrien  int base_reg;
619890075Sobrien  HOST_WIDE_INT offset;
619990075Sobrien  char buf[100];
620090075Sobrien  int i;
620190075Sobrien
620290075Sobrien  switch (store_multiple_sequence (operands, nops, regs, &base_reg, &offset))
620390075Sobrien    {
620490075Sobrien    case 1:
620590075Sobrien      strcpy (buf, "stm%?ia\t");
620690075Sobrien      break;
620790075Sobrien
620890075Sobrien    case 2:
620990075Sobrien      strcpy (buf, "stm%?ib\t");
621090075Sobrien      break;
621190075Sobrien
621290075Sobrien    case 3:
621390075Sobrien      strcpy (buf, "stm%?da\t");
621490075Sobrien      break;
621590075Sobrien
621690075Sobrien    case 4:
621790075Sobrien      strcpy (buf, "stm%?db\t");
621890075Sobrien      break;
621990075Sobrien
622090075Sobrien    default:
6221169689Skan      gcc_unreachable ();
622290075Sobrien    }
622390075Sobrien
6224169689Skan  sprintf (buf + strlen (buf), "%s%s, {%s%s", REGISTER_PREFIX,
622590075Sobrien	   reg_names[base_reg], REGISTER_PREFIX, reg_names[regs[0]]);
622690075Sobrien
622790075Sobrien  for (i = 1; i < nops; i++)
622890075Sobrien    sprintf (buf + strlen (buf), ", %s%s", REGISTER_PREFIX,
622990075Sobrien	     reg_names[regs[i]]);
623090075Sobrien
623190075Sobrien  strcat (buf, "}\t%@ phole stm");
623290075Sobrien
623390075Sobrien  output_asm_insn (buf, operands);
623490075Sobrien  return "";
623590075Sobrien}
623690075Sobrien
623790075Sobrien/* Routines for use in generating RTL.  */
623890075Sobrien
623990075Sobrienrtx
6240132718Skanarm_gen_load_multiple (int base_regno, int count, rtx from, int up,
6241161651Skan		       int write_back, rtx basemem, HOST_WIDE_INT *offsetp)
624290075Sobrien{
6243161651Skan  HOST_WIDE_INT offset = *offsetp;
624490075Sobrien  int i = 0, j;
624590075Sobrien  rtx result;
624690075Sobrien  int sign = up ? 1 : -1;
6247161651Skan  rtx mem, addr;
624890075Sobrien
624990075Sobrien  /* XScale has load-store double instructions, but they have stricter
6250169689Skan     alignment requirements than load-store multiple, so we cannot
625190075Sobrien     use them.
625290075Sobrien
625390075Sobrien     For XScale ldm requires 2 + NREGS cycles to complete and blocks
625490075Sobrien     the pipeline until completion.
625590075Sobrien
625690075Sobrien	NREGS		CYCLES
625790075Sobrien	  1		  3
625890075Sobrien	  2		  4
625990075Sobrien	  3		  5
626090075Sobrien	  4		  6
626190075Sobrien
626290075Sobrien     An ldr instruction takes 1-3 cycles, but does not block the
626390075Sobrien     pipeline.
626490075Sobrien
626590075Sobrien	NREGS		CYCLES
626690075Sobrien	  1		 1-3
626790075Sobrien	  2		 2-6
626890075Sobrien	  3		 3-9
626990075Sobrien	  4		 4-12
627090075Sobrien
627190075Sobrien     Best case ldr will always win.  However, the more ldr instructions
627290075Sobrien     we issue, the less likely we are to be able to schedule them well.
627390075Sobrien     Using ldr instructions also increases code size.
627490075Sobrien
627590075Sobrien     As a compromise, we use ldr for counts of 1 or 2 regs, and ldm
627690075Sobrien     for counts of 3 or 4 regs.  */
6277132718Skan  if (arm_tune_xscale && count <= 2 && ! optimize_size)
627890075Sobrien    {
627990075Sobrien      rtx seq;
6280169689Skan
628190075Sobrien      start_sequence ();
6282169689Skan
628390075Sobrien      for (i = 0; i < count; i++)
628490075Sobrien	{
6285161651Skan	  addr = plus_constant (from, i * 4 * sign);
6286161651Skan	  mem = adjust_automodify_address (basemem, SImode, addr, offset);
628790075Sobrien	  emit_move_insn (gen_rtx_REG (SImode, base_regno + i), mem);
6288161651Skan	  offset += 4 * sign;
628990075Sobrien	}
629090075Sobrien
629190075Sobrien      if (write_back)
6292161651Skan	{
6293161651Skan	  emit_move_insn (from, plus_constant (from, count * 4 * sign));
6294161651Skan	  *offsetp = offset;
6295161651Skan	}
629690075Sobrien
6297117395Skan      seq = get_insns ();
629890075Sobrien      end_sequence ();
6299169689Skan
630090075Sobrien      return seq;
630190075Sobrien    }
630290075Sobrien
630390075Sobrien  result = gen_rtx_PARALLEL (VOIDmode,
630490075Sobrien			     rtvec_alloc (count + (write_back ? 1 : 0)));
630590075Sobrien  if (write_back)
630690075Sobrien    {
630790075Sobrien      XVECEXP (result, 0, 0)
6308169689Skan	= gen_rtx_SET (VOIDmode, from, plus_constant (from, count * 4 * sign));
630990075Sobrien      i = 1;
631090075Sobrien      count++;
631190075Sobrien    }
631290075Sobrien
631390075Sobrien  for (j = 0; i < count; i++, j++)
631490075Sobrien    {
6315161651Skan      addr = plus_constant (from, j * 4 * sign);
6316161651Skan      mem = adjust_automodify_address_nv (basemem, SImode, addr, offset);
631790075Sobrien      XVECEXP (result, 0, i)
631890075Sobrien	= gen_rtx_SET (VOIDmode, gen_rtx_REG (SImode, base_regno + j), mem);
6319161651Skan      offset += 4 * sign;
632090075Sobrien    }
632190075Sobrien
6322161651Skan  if (write_back)
6323161651Skan    *offsetp = offset;
6324161651Skan
632590075Sobrien  return result;
632690075Sobrien}
632790075Sobrien
632890075Sobrienrtx
6329132718Skanarm_gen_store_multiple (int base_regno, int count, rtx to, int up,
6330161651Skan			int write_back, rtx basemem, HOST_WIDE_INT *offsetp)
633190075Sobrien{
6332161651Skan  HOST_WIDE_INT offset = *offsetp;
633390075Sobrien  int i = 0, j;
633490075Sobrien  rtx result;
633590075Sobrien  int sign = up ? 1 : -1;
6336161651Skan  rtx mem, addr;
633790075Sobrien
633890075Sobrien  /* See arm_gen_load_multiple for discussion of
633990075Sobrien     the pros/cons of ldm/stm usage for XScale.  */
6340132718Skan  if (arm_tune_xscale && count <= 2 && ! optimize_size)
634190075Sobrien    {
634290075Sobrien      rtx seq;
6343169689Skan
634490075Sobrien      start_sequence ();
6345169689Skan
634690075Sobrien      for (i = 0; i < count; i++)
634790075Sobrien	{
6348161651Skan	  addr = plus_constant (to, i * 4 * sign);
6349161651Skan	  mem = adjust_automodify_address (basemem, SImode, addr, offset);
635090075Sobrien	  emit_move_insn (mem, gen_rtx_REG (SImode, base_regno + i));
6351161651Skan	  offset += 4 * sign;
635290075Sobrien	}
635390075Sobrien
635490075Sobrien      if (write_back)
6355161651Skan	{
6356161651Skan	  emit_move_insn (to, plus_constant (to, count * 4 * sign));
6357161651Skan	  *offsetp = offset;
6358161651Skan	}
635990075Sobrien
6360117395Skan      seq = get_insns ();
636190075Sobrien      end_sequence ();
6362169689Skan
636390075Sobrien      return seq;
636490075Sobrien    }
636590075Sobrien
636690075Sobrien  result = gen_rtx_PARALLEL (VOIDmode,
636790075Sobrien			     rtvec_alloc (count + (write_back ? 1 : 0)));
636890075Sobrien  if (write_back)
636990075Sobrien    {
637090075Sobrien      XVECEXP (result, 0, 0)
6371169689Skan	= gen_rtx_SET (VOIDmode, to,
637290075Sobrien		       plus_constant (to, count * 4 * sign));
637390075Sobrien      i = 1;
637490075Sobrien      count++;
637590075Sobrien    }
637690075Sobrien
637790075Sobrien  for (j = 0; i < count; i++, j++)
637890075Sobrien    {
6379161651Skan      addr = plus_constant (to, j * 4 * sign);
6380161651Skan      mem = adjust_automodify_address_nv (basemem, SImode, addr, offset);
638190075Sobrien      XVECEXP (result, 0, i)
638290075Sobrien	= gen_rtx_SET (VOIDmode, mem, gen_rtx_REG (SImode, base_regno + j));
6383161651Skan      offset += 4 * sign;
638490075Sobrien    }
638590075Sobrien
6386161651Skan  if (write_back)
6387161651Skan    *offsetp = offset;
6388161651Skan
638990075Sobrien  return result;
639090075Sobrien}
639190075Sobrien
639290075Sobrienint
6393169689Skanarm_gen_movmemqi (rtx *operands)
639490075Sobrien{
639590075Sobrien  HOST_WIDE_INT in_words_to_go, out_words_to_go, last_bytes;
6396161651Skan  HOST_WIDE_INT srcoffset, dstoffset;
639790075Sobrien  int i;
6398161651Skan  rtx src, dst, srcbase, dstbase;
639990075Sobrien  rtx part_bytes_reg = NULL;
640090075Sobrien  rtx mem;
640190075Sobrien
640290075Sobrien  if (GET_CODE (operands[2]) != CONST_INT
640390075Sobrien      || GET_CODE (operands[3]) != CONST_INT
640490075Sobrien      || INTVAL (operands[2]) > 64
640590075Sobrien      || INTVAL (operands[3]) & 3)
640690075Sobrien    return 0;
640790075Sobrien
6408161651Skan  dstbase = operands[0];
6409161651Skan  srcbase = operands[1];
6410169689Skan
6411161651Skan  dst = copy_to_mode_reg (SImode, XEXP (dstbase, 0));
6412161651Skan  src = copy_to_mode_reg (SImode, XEXP (srcbase, 0));
641390075Sobrien
6414117395Skan  in_words_to_go = ARM_NUM_INTS (INTVAL (operands[2]));
641590075Sobrien  out_words_to_go = INTVAL (operands[2]) / 4;
641690075Sobrien  last_bytes = INTVAL (operands[2]) & 3;
6417161651Skan  dstoffset = srcoffset = 0;
6418169689Skan
641990075Sobrien  if (out_words_to_go != in_words_to_go && ((in_words_to_go - 1) & 3) != 0)
642090075Sobrien    part_bytes_reg = gen_rtx_REG (SImode, (in_words_to_go - 1) & 3);
642190075Sobrien
642290075Sobrien  for (i = 0; in_words_to_go >= 2; i+=4)
642390075Sobrien    {
642490075Sobrien      if (in_words_to_go > 4)
642590075Sobrien	emit_insn (arm_gen_load_multiple (0, 4, src, TRUE, TRUE,
6426161651Skan					  srcbase, &srcoffset));
642790075Sobrien      else
6428169689Skan	emit_insn (arm_gen_load_multiple (0, in_words_to_go, src, TRUE,
6429161651Skan					  FALSE, srcbase, &srcoffset));
643090075Sobrien
643190075Sobrien      if (out_words_to_go)
643290075Sobrien	{
643390075Sobrien	  if (out_words_to_go > 4)
643490075Sobrien	    emit_insn (arm_gen_store_multiple (0, 4, dst, TRUE, TRUE,
6435161651Skan					       dstbase, &dstoffset));
643690075Sobrien	  else if (out_words_to_go != 1)
643790075Sobrien	    emit_insn (arm_gen_store_multiple (0, out_words_to_go,
6438169689Skan					       dst, TRUE,
643990075Sobrien					       (last_bytes == 0
644090075Sobrien						? FALSE : TRUE),
6441161651Skan					       dstbase, &dstoffset));
644290075Sobrien	  else
644390075Sobrien	    {
6444161651Skan	      mem = adjust_automodify_address (dstbase, SImode, dst, dstoffset);
644590075Sobrien	      emit_move_insn (mem, gen_rtx_REG (SImode, 0));
644690075Sobrien	      if (last_bytes != 0)
6447161651Skan		{
6448161651Skan		  emit_insn (gen_addsi3 (dst, dst, GEN_INT (4)));
6449161651Skan		  dstoffset += 4;
6450161651Skan		}
645190075Sobrien	    }
645290075Sobrien	}
645390075Sobrien
645490075Sobrien      in_words_to_go -= in_words_to_go < 4 ? in_words_to_go : 4;
645590075Sobrien      out_words_to_go -= out_words_to_go < 4 ? out_words_to_go : 4;
645690075Sobrien    }
645790075Sobrien
645890075Sobrien  /* OUT_WORDS_TO_GO will be zero here if there are byte stores to do.  */
645990075Sobrien  if (out_words_to_go)
646090075Sobrien    {
646190075Sobrien      rtx sreg;
6462161651Skan
6463161651Skan      mem = adjust_automodify_address (srcbase, SImode, src, srcoffset);
6464161651Skan      sreg = copy_to_reg (mem);
6465161651Skan
6466161651Skan      mem = adjust_automodify_address (dstbase, SImode, dst, dstoffset);
646790075Sobrien      emit_move_insn (mem, sreg);
646890075Sobrien      in_words_to_go--;
6469169689Skan
6470169689Skan      gcc_assert (!in_words_to_go);	/* Sanity check */
647190075Sobrien    }
647290075Sobrien
647390075Sobrien  if (in_words_to_go)
647490075Sobrien    {
6475169689Skan      gcc_assert (in_words_to_go > 0);
647690075Sobrien
6477161651Skan      mem = adjust_automodify_address (srcbase, SImode, src, srcoffset);
647890075Sobrien      part_bytes_reg = copy_to_mode_reg (SImode, mem);
647990075Sobrien    }
648090075Sobrien
6481169689Skan  gcc_assert (!last_bytes || part_bytes_reg);
648290075Sobrien
648390075Sobrien  if (BYTES_BIG_ENDIAN && last_bytes)
648490075Sobrien    {
648590075Sobrien      rtx tmp = gen_reg_rtx (SImode);
648690075Sobrien
648790075Sobrien      /* The bytes we want are in the top end of the word.  */
648890075Sobrien      emit_insn (gen_lshrsi3 (tmp, part_bytes_reg,
648990075Sobrien			      GEN_INT (8 * (4 - last_bytes))));
649090075Sobrien      part_bytes_reg = tmp;
6491169689Skan
649290075Sobrien      while (last_bytes)
649390075Sobrien	{
6494161651Skan	  mem = adjust_automodify_address (dstbase, QImode,
6495161651Skan					   plus_constant (dst, last_bytes - 1),
6496161651Skan					   dstoffset + last_bytes - 1);
6497102780Skan	  emit_move_insn (mem, gen_lowpart (QImode, part_bytes_reg));
6498102780Skan
649990075Sobrien	  if (--last_bytes)
650090075Sobrien	    {
650190075Sobrien	      tmp = gen_reg_rtx (SImode);
650290075Sobrien	      emit_insn (gen_lshrsi3 (tmp, part_bytes_reg, GEN_INT (8)));
650390075Sobrien	      part_bytes_reg = tmp;
650490075Sobrien	    }
650590075Sobrien	}
6506169689Skan
650790075Sobrien    }
650890075Sobrien  else
650990075Sobrien    {
651090075Sobrien      if (last_bytes > 1)
651190075Sobrien	{
6512161651Skan	  mem = adjust_automodify_address (dstbase, HImode, dst, dstoffset);
6513102780Skan	  emit_move_insn (mem, gen_lowpart (HImode, part_bytes_reg));
651490075Sobrien	  last_bytes -= 2;
651590075Sobrien	  if (last_bytes)
651690075Sobrien	    {
651790075Sobrien	      rtx tmp = gen_reg_rtx (SImode);
6518169689Skan	      emit_insn (gen_addsi3 (dst, dst, const2_rtx));
651990075Sobrien	      emit_insn (gen_lshrsi3 (tmp, part_bytes_reg, GEN_INT (16)));
652090075Sobrien	      part_bytes_reg = tmp;
6521161651Skan	      dstoffset += 2;
652290075Sobrien	    }
652390075Sobrien	}
6524169689Skan
652590075Sobrien      if (last_bytes)
652690075Sobrien	{
6527161651Skan	  mem = adjust_automodify_address (dstbase, QImode, dst, dstoffset);
6528102780Skan	  emit_move_insn (mem, gen_lowpart (QImode, part_bytes_reg));
652990075Sobrien	}
653090075Sobrien    }
653190075Sobrien
653290075Sobrien  return 1;
653390075Sobrien}
653490075Sobrien
6535132718Skan/* Select a dominance comparison mode if possible for a test of the general
6536132718Skan   form (OP (COND_OR (X) (Y)) (const_int 0)).  We support three forms.
6537169689Skan   COND_OR == DOM_CC_X_AND_Y => (X && Y)
6538132718Skan   COND_OR == DOM_CC_NX_OR_Y => ((! X) || Y)
6539169689Skan   COND_OR == DOM_CC_X_OR_Y => (X || Y)
6540132718Skan   In all cases OP will be either EQ or NE, but we don't need to know which
6541169689Skan   here.  If we are unable to support a dominance comparison we return
6542132718Skan   CC mode.  This will then fail to match for the RTL expressions that
6543132718Skan   generate this call.  */
6544132718Skanenum machine_mode
6545132718Skanarm_select_dominance_cc_mode (rtx x, rtx y, HOST_WIDE_INT cond_or)
654690075Sobrien{
654790075Sobrien  enum rtx_code cond1, cond2;
654890075Sobrien  int swapped = 0;
654990075Sobrien
655090075Sobrien  /* Currently we will probably get the wrong result if the individual
655190075Sobrien     comparisons are not simple.  This also ensures that it is safe to
655290075Sobrien     reverse a comparison if necessary.  */
655390075Sobrien  if ((arm_select_cc_mode (cond1 = GET_CODE (x), XEXP (x, 0), XEXP (x, 1))
655490075Sobrien       != CCmode)
655590075Sobrien      || (arm_select_cc_mode (cond2 = GET_CODE (y), XEXP (y, 0), XEXP (y, 1))
655690075Sobrien	  != CCmode))
655790075Sobrien    return CCmode;
655890075Sobrien
655990075Sobrien  /* The if_then_else variant of this tests the second condition if the
656090075Sobrien     first passes, but is true if the first fails.  Reverse the first
656190075Sobrien     condition to get a true "inclusive-or" expression.  */
6562132718Skan  if (cond_or == DOM_CC_NX_OR_Y)
656390075Sobrien    cond1 = reverse_condition (cond1);
656490075Sobrien
656590075Sobrien  /* If the comparisons are not equal, and one doesn't dominate the other,
656690075Sobrien     then we can't do this.  */
6567169689Skan  if (cond1 != cond2
656890075Sobrien      && !comparison_dominates_p (cond1, cond2)
656990075Sobrien      && (swapped = 1, !comparison_dominates_p (cond2, cond1)))
657090075Sobrien    return CCmode;
657190075Sobrien
657290075Sobrien  if (swapped)
657390075Sobrien    {
657490075Sobrien      enum rtx_code temp = cond1;
657590075Sobrien      cond1 = cond2;
657690075Sobrien      cond2 = temp;
657790075Sobrien    }
657890075Sobrien
657990075Sobrien  switch (cond1)
658090075Sobrien    {
658190075Sobrien    case EQ:
6582169689Skan      if (cond_or == DOM_CC_X_AND_Y)
658390075Sobrien	return CC_DEQmode;
658490075Sobrien
658590075Sobrien      switch (cond2)
658690075Sobrien	{
6587169689Skan	case EQ: return CC_DEQmode;
658890075Sobrien	case LE: return CC_DLEmode;
658990075Sobrien	case LEU: return CC_DLEUmode;
659090075Sobrien	case GE: return CC_DGEmode;
659190075Sobrien	case GEU: return CC_DGEUmode;
6592169689Skan	default: gcc_unreachable ();
659390075Sobrien	}
659490075Sobrien
659590075Sobrien    case LT:
6596169689Skan      if (cond_or == DOM_CC_X_AND_Y)
659790075Sobrien	return CC_DLTmode;
659890075Sobrien
6599169689Skan      switch (cond2)
6600169689Skan	{
6601169689Skan	case  LT:
6602169689Skan	    return CC_DLTmode;
6603169689Skan	case LE:
6604169689Skan	  return CC_DLEmode;
6605169689Skan	case NE:
6606169689Skan	  return CC_DNEmode;
6607169689Skan	default:
6608169689Skan	  gcc_unreachable ();
6609169689Skan	}
6610169689Skan
661190075Sobrien    case GT:
6612169689Skan      if (cond_or == DOM_CC_X_AND_Y)
661390075Sobrien	return CC_DGTmode;
6614169689Skan
6615169689Skan      switch (cond2)
6616169689Skan	{
6617169689Skan	case GT:
6618169689Skan	  return CC_DGTmode;
6619169689Skan	case GE:
6620169689Skan	  return CC_DGEmode;
6621169689Skan	case NE:
6622169689Skan	  return CC_DNEmode;
6623169689Skan	default:
6624169689Skan	  gcc_unreachable ();
6625169689Skan	}
6626169689Skan
662790075Sobrien    case LTU:
6628169689Skan      if (cond_or == DOM_CC_X_AND_Y)
662990075Sobrien	return CC_DLTUmode;
663090075Sobrien
6631169689Skan      switch (cond2)
6632169689Skan	{
6633169689Skan	case LTU:
6634169689Skan	  return CC_DLTUmode;
6635169689Skan	case LEU:
6636169689Skan	  return CC_DLEUmode;
6637169689Skan	case NE:
6638169689Skan	  return CC_DNEmode;
6639169689Skan	default:
6640169689Skan	  gcc_unreachable ();
6641169689Skan	}
6642169689Skan
664390075Sobrien    case GTU:
6644169689Skan      if (cond_or == DOM_CC_X_AND_Y)
664590075Sobrien	return CC_DGTUmode;
664690075Sobrien
6647169689Skan      switch (cond2)
6648169689Skan	{
6649169689Skan	case GTU:
6650169689Skan	  return CC_DGTUmode;
6651169689Skan	case GEU:
6652169689Skan	  return CC_DGEUmode;
6653169689Skan	case NE:
6654169689Skan	  return CC_DNEmode;
6655169689Skan	default:
6656169689Skan	  gcc_unreachable ();
6657169689Skan	}
6658169689Skan
665990075Sobrien    /* The remaining cases only occur when both comparisons are the
666090075Sobrien       same.  */
666190075Sobrien    case NE:
6662169689Skan      gcc_assert (cond1 == cond2);
666390075Sobrien      return CC_DNEmode;
666490075Sobrien
666590075Sobrien    case LE:
6666169689Skan      gcc_assert (cond1 == cond2);
666790075Sobrien      return CC_DLEmode;
666890075Sobrien
666990075Sobrien    case GE:
6670169689Skan      gcc_assert (cond1 == cond2);
667190075Sobrien      return CC_DGEmode;
667290075Sobrien
667390075Sobrien    case LEU:
6674169689Skan      gcc_assert (cond1 == cond2);
667590075Sobrien      return CC_DLEUmode;
667690075Sobrien
667790075Sobrien    case GEU:
6678169689Skan      gcc_assert (cond1 == cond2);
667990075Sobrien      return CC_DGEUmode;
668090075Sobrien
668190075Sobrien    default:
6682169689Skan      gcc_unreachable ();
668390075Sobrien    }
668490075Sobrien}
668590075Sobrien
668690075Sobrienenum machine_mode
6687132718Skanarm_select_cc_mode (enum rtx_code op, rtx x, rtx y)
668890075Sobrien{
668990075Sobrien  /* All floating point compares return CCFP if it is an equality
669090075Sobrien     comparison, and CCFPE otherwise.  */
669190075Sobrien  if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
669290075Sobrien    {
669390075Sobrien      switch (op)
669490075Sobrien	{
669590075Sobrien	case EQ:
669690075Sobrien	case NE:
669790075Sobrien	case UNORDERED:
669890075Sobrien	case ORDERED:
669990075Sobrien	case UNLT:
670090075Sobrien	case UNLE:
670190075Sobrien	case UNGT:
670290075Sobrien	case UNGE:
670390075Sobrien	case UNEQ:
670490075Sobrien	case LTGT:
670590075Sobrien	  return CCFPmode;
670690075Sobrien
670790075Sobrien	case LT:
670890075Sobrien	case LE:
670990075Sobrien	case GT:
671090075Sobrien	case GE:
6711169689Skan	  if (TARGET_HARD_FLOAT && TARGET_MAVERICK)
6712132718Skan	    return CCFPmode;
671390075Sobrien	  return CCFPEmode;
671490075Sobrien
671590075Sobrien	default:
6716169689Skan	  gcc_unreachable ();
671790075Sobrien	}
671890075Sobrien    }
6719169689Skan
672090075Sobrien  /* A compare with a shifted operand.  Because of canonicalization, the
672190075Sobrien     comparison will have to be swapped when we emit the assembler.  */
672290075Sobrien  if (GET_MODE (y) == SImode && GET_CODE (y) == REG
672390075Sobrien      && (GET_CODE (x) == ASHIFT || GET_CODE (x) == ASHIFTRT
672490075Sobrien	  || GET_CODE (x) == LSHIFTRT || GET_CODE (x) == ROTATE
672590075Sobrien	  || GET_CODE (x) == ROTATERT))
672690075Sobrien    return CC_SWPmode;
672790075Sobrien
6728169689Skan  /* This operation is performed swapped, but since we only rely on the Z
6729169689Skan     flag we don't need an additional mode.  */
6730169689Skan  if (GET_MODE (y) == SImode && REG_P (y)
6731169689Skan      && GET_CODE (x) == NEG
6732169689Skan      && (op ==	EQ || op == NE))
6733169689Skan    return CC_Zmode;
6734169689Skan
6735169689Skan  /* This is a special case that is used by combine to allow a
673690075Sobrien     comparison of a shifted byte load to be split into a zero-extend
673790075Sobrien     followed by a comparison of the shifted integer (only valid for
673890075Sobrien     equalities and unsigned inequalities).  */
673990075Sobrien  if (GET_MODE (x) == SImode
674090075Sobrien      && GET_CODE (x) == ASHIFT
674190075Sobrien      && GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) == 24
674290075Sobrien      && GET_CODE (XEXP (x, 0)) == SUBREG
674390075Sobrien      && GET_CODE (SUBREG_REG (XEXP (x, 0))) == MEM
674490075Sobrien      && GET_MODE (SUBREG_REG (XEXP (x, 0))) == QImode
674590075Sobrien      && (op == EQ || op == NE
674690075Sobrien	  || op == GEU || op == GTU || op == LTU || op == LEU)
674790075Sobrien      && GET_CODE (y) == CONST_INT)
674890075Sobrien    return CC_Zmode;
674990075Sobrien
675090075Sobrien  /* A construct for a conditional compare, if the false arm contains
675190075Sobrien     0, then both conditions must be true, otherwise either condition
675290075Sobrien     must be true.  Not all conditions are possible, so CCmode is
675390075Sobrien     returned if it can't be done.  */
675490075Sobrien  if (GET_CODE (x) == IF_THEN_ELSE
675590075Sobrien      && (XEXP (x, 2) == const0_rtx
675690075Sobrien	  || XEXP (x, 2) == const1_rtx)
6757169689Skan      && COMPARISON_P (XEXP (x, 0))
6758169689Skan      && COMPARISON_P (XEXP (x, 1)))
6759169689Skan    return arm_select_dominance_cc_mode (XEXP (x, 0), XEXP (x, 1),
6760132718Skan					 INTVAL (XEXP (x, 2)));
676190075Sobrien
676290075Sobrien  /* Alternate canonicalizations of the above.  These are somewhat cleaner.  */
676390075Sobrien  if (GET_CODE (x) == AND
6764169689Skan      && COMPARISON_P (XEXP (x, 0))
6765169689Skan      && COMPARISON_P (XEXP (x, 1)))
6766132718Skan    return arm_select_dominance_cc_mode (XEXP (x, 0), XEXP (x, 1),
6767132718Skan					 DOM_CC_X_AND_Y);
676890075Sobrien
676990075Sobrien  if (GET_CODE (x) == IOR
6770169689Skan      && COMPARISON_P (XEXP (x, 0))
6771169689Skan      && COMPARISON_P (XEXP (x, 1)))
6772132718Skan    return arm_select_dominance_cc_mode (XEXP (x, 0), XEXP (x, 1),
6773132718Skan					 DOM_CC_X_OR_Y);
677490075Sobrien
6775132718Skan  /* An operation (on Thumb) where we want to test for a single bit.
6776132718Skan     This is done by shifting that bit up into the top bit of a
6777132718Skan     scratch register; we can then branch on the sign bit.  */
6778132718Skan  if (TARGET_THUMB
6779132718Skan      && GET_MODE (x) == SImode
6780132718Skan      && (op == EQ || op == NE)
6781169689Skan      && GET_CODE (x) == ZERO_EXTRACT
6782169689Skan      && XEXP (x, 1) == const1_rtx)
6783132718Skan    return CC_Nmode;
6784132718Skan
678590075Sobrien  /* An operation that sets the condition codes as a side-effect, the
678690075Sobrien     V flag is not set correctly, so we can only use comparisons where
678790075Sobrien     this doesn't matter.  (For LT and GE we can use "mi" and "pl"
6788132718Skan     instead.)  */
678990075Sobrien  if (GET_MODE (x) == SImode
679090075Sobrien      && y == const0_rtx
679190075Sobrien      && (op == EQ || op == NE || op == LT || op == GE)
679290075Sobrien      && (GET_CODE (x) == PLUS || GET_CODE (x) == MINUS
679390075Sobrien	  || GET_CODE (x) == AND || GET_CODE (x) == IOR
679490075Sobrien	  || GET_CODE (x) == XOR || GET_CODE (x) == MULT
679590075Sobrien	  || GET_CODE (x) == NOT || GET_CODE (x) == NEG
679690075Sobrien	  || GET_CODE (x) == LSHIFTRT
679790075Sobrien	  || GET_CODE (x) == ASHIFT || GET_CODE (x) == ASHIFTRT
6798132718Skan	  || GET_CODE (x) == ROTATERT
6799132718Skan	  || (TARGET_ARM && GET_CODE (x) == ZERO_EXTRACT)))
680090075Sobrien    return CC_NOOVmode;
680190075Sobrien
680290075Sobrien  if (GET_MODE (x) == QImode && (op == EQ || op == NE))
680390075Sobrien    return CC_Zmode;
680490075Sobrien
680590075Sobrien  if (GET_MODE (x) == SImode && (op == LTU || op == GEU)
680690075Sobrien      && GET_CODE (x) == PLUS
680790075Sobrien      && (rtx_equal_p (XEXP (x, 0), y) || rtx_equal_p (XEXP (x, 1), y)))
680890075Sobrien    return CC_Cmode;
680990075Sobrien
681090075Sobrien  return CCmode;
681190075Sobrien}
681290075Sobrien
681390075Sobrien/* X and Y are two things to compare using CODE.  Emit the compare insn and
681490075Sobrien   return the rtx for register 0 in the proper mode.  FP means this is a
681590075Sobrien   floating point compare: I don't think that it is needed on the arm.  */
681690075Sobrienrtx
6817132718Skanarm_gen_compare_reg (enum rtx_code code, rtx x, rtx y)
681890075Sobrien{
681990075Sobrien  enum machine_mode mode = SELECT_CC_MODE (code, x, y);
682090075Sobrien  rtx cc_reg = gen_rtx_REG (mode, CC_REGNUM);
682190075Sobrien
6822169689Skan  emit_set_insn (cc_reg, gen_rtx_COMPARE (mode, x, y));
682390075Sobrien
682490075Sobrien  return cc_reg;
682590075Sobrien}
682690075Sobrien
6827117395Skan/* Generate a sequence of insns that will generate the correct return
6828117395Skan   address mask depending on the physical architecture that the program
6829117395Skan   is running on.  */
6830117395Skanrtx
6831132718Skanarm_gen_return_addr_mask (void)
6832117395Skan{
6833117395Skan  rtx reg = gen_reg_rtx (Pmode);
6834117395Skan
6835117395Skan  emit_insn (gen_return_addr_mask (reg));
6836117395Skan  return reg;
6837117395Skan}
6838117395Skan
683990075Sobrienvoid
6840132718Skanarm_reload_in_hi (rtx *operands)
684190075Sobrien{
684290075Sobrien  rtx ref = operands[1];
684390075Sobrien  rtx base, scratch;
684490075Sobrien  HOST_WIDE_INT offset = 0;
684590075Sobrien
684690075Sobrien  if (GET_CODE (ref) == SUBREG)
684790075Sobrien    {
684890075Sobrien      offset = SUBREG_BYTE (ref);
684990075Sobrien      ref = SUBREG_REG (ref);
685090075Sobrien    }
685190075Sobrien
685290075Sobrien  if (GET_CODE (ref) == REG)
685390075Sobrien    {
685490075Sobrien      /* We have a pseudo which has been spilt onto the stack; there
685590075Sobrien	 are two cases here: the first where there is a simple
685690075Sobrien	 stack-slot replacement and a second where the stack-slot is
685790075Sobrien	 out of range, or is used as a subreg.  */
685890075Sobrien      if (reg_equiv_mem[REGNO (ref)])
685990075Sobrien	{
686090075Sobrien	  ref = reg_equiv_mem[REGNO (ref)];
686190075Sobrien	  base = find_replacement (&XEXP (ref, 0));
686290075Sobrien	}
686390075Sobrien      else
686490075Sobrien	/* The slot is out of range, or was dressed up in a SUBREG.  */
686590075Sobrien	base = reg_equiv_address[REGNO (ref)];
686690075Sobrien    }
686790075Sobrien  else
686890075Sobrien    base = find_replacement (&XEXP (ref, 0));
686990075Sobrien
687090075Sobrien  /* Handle the case where the address is too complex to be offset by 1.  */
687190075Sobrien  if (GET_CODE (base) == MINUS
687290075Sobrien      || (GET_CODE (base) == PLUS && GET_CODE (XEXP (base, 1)) != CONST_INT))
687390075Sobrien    {
687490075Sobrien      rtx base_plus = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
687590075Sobrien
6876169689Skan      emit_set_insn (base_plus, base);
687790075Sobrien      base = base_plus;
687890075Sobrien    }
687990075Sobrien  else if (GET_CODE (base) == PLUS)
688090075Sobrien    {
688190075Sobrien      /* The addend must be CONST_INT, or we would have dealt with it above.  */
688290075Sobrien      HOST_WIDE_INT hi, lo;
688390075Sobrien
688490075Sobrien      offset += INTVAL (XEXP (base, 1));
688590075Sobrien      base = XEXP (base, 0);
688690075Sobrien
688790075Sobrien      /* Rework the address into a legal sequence of insns.  */
688890075Sobrien      /* Valid range for lo is -4095 -> 4095 */
688990075Sobrien      lo = (offset >= 0
689090075Sobrien	    ? (offset & 0xfff)
689190075Sobrien	    : -((-offset) & 0xfff));
689290075Sobrien
689390075Sobrien      /* Corner case, if lo is the max offset then we would be out of range
689490075Sobrien	 once we have added the additional 1 below, so bump the msb into the
689590075Sobrien	 pre-loading insn(s).  */
689690075Sobrien      if (lo == 4095)
689790075Sobrien	lo &= 0x7ff;
689890075Sobrien
689990075Sobrien      hi = ((((offset - lo) & (HOST_WIDE_INT) 0xffffffff)
690090075Sobrien	     ^ (HOST_WIDE_INT) 0x80000000)
690190075Sobrien	    - (HOST_WIDE_INT) 0x80000000);
690290075Sobrien
6903169689Skan      gcc_assert (hi + lo == offset);
690490075Sobrien
690590075Sobrien      if (hi != 0)
690690075Sobrien	{
690790075Sobrien	  rtx base_plus = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
690890075Sobrien
690990075Sobrien	  /* Get the base address; addsi3 knows how to handle constants
691090075Sobrien	     that require more than one insn.  */
691190075Sobrien	  emit_insn (gen_addsi3 (base_plus, base, GEN_INT (hi)));
691290075Sobrien	  base = base_plus;
691390075Sobrien	  offset = lo;
691490075Sobrien	}
691590075Sobrien    }
691690075Sobrien
6917117395Skan  /* Operands[2] may overlap operands[0] (though it won't overlap
6918117395Skan     operands[1]), that's why we asked for a DImode reg -- so we can
6919117395Skan     use the bit that does not overlap.  */
6920117395Skan  if (REGNO (operands[2]) == REGNO (operands[0]))
6921117395Skan    scratch = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
6922117395Skan  else
6923117395Skan    scratch = gen_rtx_REG (SImode, REGNO (operands[2]));
6924117395Skan
692590075Sobrien  emit_insn (gen_zero_extendqisi2 (scratch,
692690075Sobrien				   gen_rtx_MEM (QImode,
692790075Sobrien						plus_constant (base,
692890075Sobrien							       offset))));
692990075Sobrien  emit_insn (gen_zero_extendqisi2 (gen_rtx_SUBREG (SImode, operands[0], 0),
6930169689Skan				   gen_rtx_MEM (QImode,
693190075Sobrien						plus_constant (base,
693290075Sobrien							       offset + 1))));
693390075Sobrien  if (!BYTES_BIG_ENDIAN)
6934169689Skan    emit_set_insn (gen_rtx_SUBREG (SImode, operands[0], 0),
6935169689Skan		   gen_rtx_IOR (SImode,
6936169689Skan				gen_rtx_ASHIFT
6937169689Skan				(SImode,
6938169689Skan				 gen_rtx_SUBREG (SImode, operands[0], 0),
6939169689Skan				 GEN_INT (8)),
6940169689Skan				scratch));
694190075Sobrien  else
6942169689Skan    emit_set_insn (gen_rtx_SUBREG (SImode, operands[0], 0),
6943169689Skan		   gen_rtx_IOR (SImode,
6944169689Skan				gen_rtx_ASHIFT (SImode, scratch,
6945169689Skan						GEN_INT (8)),
6946169689Skan				gen_rtx_SUBREG (SImode, operands[0], 0)));
694790075Sobrien}
694890075Sobrien
6949132718Skan/* Handle storing a half-word to memory during reload by synthesizing as two
695090075Sobrien   byte stores.  Take care not to clobber the input values until after we
695190075Sobrien   have moved them somewhere safe.  This code assumes that if the DImode
695290075Sobrien   scratch in operands[2] overlaps either the input value or output address
695390075Sobrien   in some way, then that value must die in this insn (we absolutely need
695490075Sobrien   two scratch registers for some corner cases).  */
695590075Sobrienvoid
6956132718Skanarm_reload_out_hi (rtx *operands)
695790075Sobrien{
695890075Sobrien  rtx ref = operands[0];
695990075Sobrien  rtx outval = operands[1];
696090075Sobrien  rtx base, scratch;
696190075Sobrien  HOST_WIDE_INT offset = 0;
696290075Sobrien
696390075Sobrien  if (GET_CODE (ref) == SUBREG)
696490075Sobrien    {
696590075Sobrien      offset = SUBREG_BYTE (ref);
696690075Sobrien      ref = SUBREG_REG (ref);
696790075Sobrien    }
696890075Sobrien
696990075Sobrien  if (GET_CODE (ref) == REG)
697090075Sobrien    {
697190075Sobrien      /* We have a pseudo which has been spilt onto the stack; there
697290075Sobrien	 are two cases here: the first where there is a simple
697390075Sobrien	 stack-slot replacement and a second where the stack-slot is
697490075Sobrien	 out of range, or is used as a subreg.  */
697590075Sobrien      if (reg_equiv_mem[REGNO (ref)])
697690075Sobrien	{
697790075Sobrien	  ref = reg_equiv_mem[REGNO (ref)];
697890075Sobrien	  base = find_replacement (&XEXP (ref, 0));
697990075Sobrien	}
698090075Sobrien      else
698190075Sobrien	/* The slot is out of range, or was dressed up in a SUBREG.  */
698290075Sobrien	base = reg_equiv_address[REGNO (ref)];
698390075Sobrien    }
698490075Sobrien  else
698590075Sobrien    base = find_replacement (&XEXP (ref, 0));
698690075Sobrien
698790075Sobrien  scratch = gen_rtx_REG (SImode, REGNO (operands[2]));
698890075Sobrien
698990075Sobrien  /* Handle the case where the address is too complex to be offset by 1.  */
699090075Sobrien  if (GET_CODE (base) == MINUS
699190075Sobrien      || (GET_CODE (base) == PLUS && GET_CODE (XEXP (base, 1)) != CONST_INT))
699290075Sobrien    {
699390075Sobrien      rtx base_plus = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
699490075Sobrien
699590075Sobrien      /* Be careful not to destroy OUTVAL.  */
699690075Sobrien      if (reg_overlap_mentioned_p (base_plus, outval))
699790075Sobrien	{
699890075Sobrien	  /* Updating base_plus might destroy outval, see if we can
699990075Sobrien	     swap the scratch and base_plus.  */
700090075Sobrien	  if (!reg_overlap_mentioned_p (scratch, outval))
700190075Sobrien	    {
700290075Sobrien	      rtx tmp = scratch;
700390075Sobrien	      scratch = base_plus;
700490075Sobrien	      base_plus = tmp;
700590075Sobrien	    }
700690075Sobrien	  else
700790075Sobrien	    {
700890075Sobrien	      rtx scratch_hi = gen_rtx_REG (HImode, REGNO (operands[2]));
700990075Sobrien
701090075Sobrien	      /* Be conservative and copy OUTVAL into the scratch now,
701190075Sobrien		 this should only be necessary if outval is a subreg
701290075Sobrien		 of something larger than a word.  */
701390075Sobrien	      /* XXX Might this clobber base?  I can't see how it can,
701490075Sobrien		 since scratch is known to overlap with OUTVAL, and
701590075Sobrien		 must be wider than a word.  */
701690075Sobrien	      emit_insn (gen_movhi (scratch_hi, outval));
701790075Sobrien	      outval = scratch_hi;
701890075Sobrien	    }
701990075Sobrien	}
702090075Sobrien
7021169689Skan      emit_set_insn (base_plus, base);
702290075Sobrien      base = base_plus;
702390075Sobrien    }
702490075Sobrien  else if (GET_CODE (base) == PLUS)
702590075Sobrien    {
702690075Sobrien      /* The addend must be CONST_INT, or we would have dealt with it above.  */
702790075Sobrien      HOST_WIDE_INT hi, lo;
702890075Sobrien
702990075Sobrien      offset += INTVAL (XEXP (base, 1));
703090075Sobrien      base = XEXP (base, 0);
703190075Sobrien
703290075Sobrien      /* Rework the address into a legal sequence of insns.  */
703390075Sobrien      /* Valid range for lo is -4095 -> 4095 */
703490075Sobrien      lo = (offset >= 0
703590075Sobrien	    ? (offset & 0xfff)
703690075Sobrien	    : -((-offset) & 0xfff));
703790075Sobrien
703890075Sobrien      /* Corner case, if lo is the max offset then we would be out of range
703990075Sobrien	 once we have added the additional 1 below, so bump the msb into the
704090075Sobrien	 pre-loading insn(s).  */
704190075Sobrien      if (lo == 4095)
704290075Sobrien	lo &= 0x7ff;
704390075Sobrien
704490075Sobrien      hi = ((((offset - lo) & (HOST_WIDE_INT) 0xffffffff)
704590075Sobrien	     ^ (HOST_WIDE_INT) 0x80000000)
704690075Sobrien	    - (HOST_WIDE_INT) 0x80000000);
704790075Sobrien
7048169689Skan      gcc_assert (hi + lo == offset);
704990075Sobrien
705090075Sobrien      if (hi != 0)
705190075Sobrien	{
705290075Sobrien	  rtx base_plus = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
705390075Sobrien
705490075Sobrien	  /* Be careful not to destroy OUTVAL.  */
705590075Sobrien	  if (reg_overlap_mentioned_p (base_plus, outval))
705690075Sobrien	    {
705790075Sobrien	      /* Updating base_plus might destroy outval, see if we
705890075Sobrien		 can swap the scratch and base_plus.  */
705990075Sobrien	      if (!reg_overlap_mentioned_p (scratch, outval))
706090075Sobrien		{
706190075Sobrien		  rtx tmp = scratch;
706290075Sobrien		  scratch = base_plus;
706390075Sobrien		  base_plus = tmp;
706490075Sobrien		}
706590075Sobrien	      else
706690075Sobrien		{
706790075Sobrien		  rtx scratch_hi = gen_rtx_REG (HImode, REGNO (operands[2]));
706890075Sobrien
706990075Sobrien		  /* Be conservative and copy outval into scratch now,
707090075Sobrien		     this should only be necessary if outval is a
707190075Sobrien		     subreg of something larger than a word.  */
707290075Sobrien		  /* XXX Might this clobber base?  I can't see how it
707390075Sobrien		     can, since scratch is known to overlap with
707490075Sobrien		     outval.  */
707590075Sobrien		  emit_insn (gen_movhi (scratch_hi, outval));
707690075Sobrien		  outval = scratch_hi;
707790075Sobrien		}
707890075Sobrien	    }
707990075Sobrien
708090075Sobrien	  /* Get the base address; addsi3 knows how to handle constants
708190075Sobrien	     that require more than one insn.  */
708290075Sobrien	  emit_insn (gen_addsi3 (base_plus, base, GEN_INT (hi)));
708390075Sobrien	  base = base_plus;
708490075Sobrien	  offset = lo;
708590075Sobrien	}
708690075Sobrien    }
708790075Sobrien
708890075Sobrien  if (BYTES_BIG_ENDIAN)
708990075Sobrien    {
7090169689Skan      emit_insn (gen_movqi (gen_rtx_MEM (QImode,
709190075Sobrien					 plus_constant (base, offset + 1)),
7092102780Skan			    gen_lowpart (QImode, outval)));
709390075Sobrien      emit_insn (gen_lshrsi3 (scratch,
709490075Sobrien			      gen_rtx_SUBREG (SImode, outval, 0),
709590075Sobrien			      GEN_INT (8)));
709690075Sobrien      emit_insn (gen_movqi (gen_rtx_MEM (QImode, plus_constant (base, offset)),
7097102780Skan			    gen_lowpart (QImode, scratch)));
709890075Sobrien    }
709990075Sobrien  else
710090075Sobrien    {
710190075Sobrien      emit_insn (gen_movqi (gen_rtx_MEM (QImode, plus_constant (base, offset)),
7102102780Skan			    gen_lowpart (QImode, outval)));
710390075Sobrien      emit_insn (gen_lshrsi3 (scratch,
710490075Sobrien			      gen_rtx_SUBREG (SImode, outval, 0),
710590075Sobrien			      GEN_INT (8)));
710690075Sobrien      emit_insn (gen_movqi (gen_rtx_MEM (QImode,
710790075Sobrien					 plus_constant (base, offset + 1)),
7108102780Skan			    gen_lowpart (QImode, scratch)));
710990075Sobrien    }
711090075Sobrien}
7111169689Skan
7112169689Skan/* Return true if a type must be passed in memory. For AAPCS, small aggregates
7113169689Skan   (padded to the size of a word) should be passed in a register.  */
7114169689Skan
7115169689Skanstatic bool
7116169689Skanarm_must_pass_in_stack (enum machine_mode mode, tree type)
7117169689Skan{
7118169689Skan  if (TARGET_AAPCS_BASED)
7119169689Skan    return must_pass_in_stack_var_size (mode, type);
7120169689Skan  else
7121169689Skan    return must_pass_in_stack_var_size_or_pad (mode, type);
7122169689Skan}
7123169689Skan
7124169689Skan
7125169689Skan/* For use by FUNCTION_ARG_PADDING (MODE, TYPE).
7126169689Skan   Return true if an argument passed on the stack should be padded upwards,
7127169689Skan   i.e. if the least-significant byte has useful data.
7128169689Skan   For legacy APCS ABIs we use the default.  For AAPCS based ABIs small
7129169689Skan   aggregate types are placed in the lowest memory address.  */
7130169689Skan
7131169689Skanbool
7132169689Skanarm_pad_arg_upward (enum machine_mode mode, tree type)
7133169689Skan{
7134169689Skan  if (!TARGET_AAPCS_BASED)
7135169689Skan    return DEFAULT_FUNCTION_ARG_PADDING(mode, type) == upward;
7136169689Skan
7137169689Skan  if (type && BYTES_BIG_ENDIAN && INTEGRAL_TYPE_P (type))
7138169689Skan    return false;
7139169689Skan
7140169689Skan  return true;
7141169689Skan}
7142169689Skan
7143169689Skan
7144169689Skan/* Similarly, for use by BLOCK_REG_PADDING (MODE, TYPE, FIRST).
7145169689Skan   For non-AAPCS, return !BYTES_BIG_ENDIAN if the least significant
7146169689Skan   byte of the register has useful data, and return the opposite if the
7147169689Skan   most significant byte does.
7148169689Skan   For AAPCS, small aggregates and small complex types are always padded
7149169689Skan   upwards.  */
7150169689Skan
7151169689Skanbool
7152169689Skanarm_pad_reg_upward (enum machine_mode mode ATTRIBUTE_UNUSED,
7153169689Skan                    tree type, int first ATTRIBUTE_UNUSED)
7154169689Skan{
7155169689Skan  if (TARGET_AAPCS_BASED
7156169689Skan      && BYTES_BIG_ENDIAN
7157169689Skan      && (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == COMPLEX_TYPE)
7158169689Skan      && int_size_in_bytes (type) <= 4)
7159169689Skan    return true;
7160169689Skan
7161169689Skan  /* Otherwise, use default padding.  */
7162169689Skan  return !BYTES_BIG_ENDIAN;
7163169689Skan}
7164169689Skan
716590075Sobrien
716690075Sobrien/* Print a symbolic form of X to the debug file, F.  */
716790075Sobrienstatic void
7168132718Skanarm_print_value (FILE *f, rtx x)
716990075Sobrien{
717090075Sobrien  switch (GET_CODE (x))
717190075Sobrien    {
717290075Sobrien    case CONST_INT:
717390075Sobrien      fprintf (f, HOST_WIDE_INT_PRINT_HEX, INTVAL (x));
717490075Sobrien      return;
717590075Sobrien
717690075Sobrien    case CONST_DOUBLE:
717790075Sobrien      fprintf (f, "<0x%lx,0x%lx>", (long)XWINT (x, 2), (long)XWINT (x, 3));
717890075Sobrien      return;
717990075Sobrien
7180132718Skan    case CONST_VECTOR:
7181132718Skan      {
7182132718Skan	int i;
7183132718Skan
7184132718Skan	fprintf (f, "<");
7185132718Skan	for (i = 0; i < CONST_VECTOR_NUNITS (x); i++)
7186132718Skan	  {
7187132718Skan	    fprintf (f, HOST_WIDE_INT_PRINT_HEX, INTVAL (CONST_VECTOR_ELT (x, i)));
7188132718Skan	    if (i < (CONST_VECTOR_NUNITS (x) - 1))
7189132718Skan	      fputc (',', f);
7190132718Skan	  }
7191132718Skan	fprintf (f, ">");
7192132718Skan      }
7193132718Skan      return;
7194132718Skan
719590075Sobrien    case CONST_STRING:
719690075Sobrien      fprintf (f, "\"%s\"", XSTR (x, 0));
719790075Sobrien      return;
719890075Sobrien
719990075Sobrien    case SYMBOL_REF:
720090075Sobrien      fprintf (f, "`%s'", XSTR (x, 0));
720190075Sobrien      return;
720290075Sobrien
720390075Sobrien    case LABEL_REF:
720490075Sobrien      fprintf (f, "L%d", INSN_UID (XEXP (x, 0)));
720590075Sobrien      return;
720690075Sobrien
720790075Sobrien    case CONST:
720890075Sobrien      arm_print_value (f, XEXP (x, 0));
720990075Sobrien      return;
721090075Sobrien
721190075Sobrien    case PLUS:
721290075Sobrien      arm_print_value (f, XEXP (x, 0));
721390075Sobrien      fprintf (f, "+");
721490075Sobrien      arm_print_value (f, XEXP (x, 1));
721590075Sobrien      return;
721690075Sobrien
721790075Sobrien    case PC:
721890075Sobrien      fprintf (f, "pc");
721990075Sobrien      return;
722090075Sobrien
722190075Sobrien    default:
722290075Sobrien      fprintf (f, "????");
722390075Sobrien      return;
722490075Sobrien    }
722590075Sobrien}
722690075Sobrien
722790075Sobrien/* Routines for manipulation of the constant pool.  */
722890075Sobrien
722990075Sobrien/* Arm instructions cannot load a large constant directly into a
723090075Sobrien   register; they have to come from a pc relative load.  The constant
723190075Sobrien   must therefore be placed in the addressable range of the pc
723290075Sobrien   relative load.  Depending on the precise pc relative load
723390075Sobrien   instruction the range is somewhere between 256 bytes and 4k.  This
723490075Sobrien   means that we often have to dump a constant inside a function, and
723590075Sobrien   generate code to branch around it.
723690075Sobrien
723790075Sobrien   It is important to minimize this, since the branches will slow
723890075Sobrien   things down and make the code larger.
723990075Sobrien
724090075Sobrien   Normally we can hide the table after an existing unconditional
724190075Sobrien   branch so that there is no interruption of the flow, but in the
724290075Sobrien   worst case the code looks like this:
724390075Sobrien
724490075Sobrien	ldr	rn, L1
724590075Sobrien	...
724690075Sobrien	b	L2
724790075Sobrien	align
724890075Sobrien	L1:	.long value
724990075Sobrien	L2:
725090075Sobrien	...
725190075Sobrien
725290075Sobrien	ldr	rn, L3
725390075Sobrien	...
725490075Sobrien	b	L4
725590075Sobrien	align
725690075Sobrien	L3:	.long value
725790075Sobrien	L4:
725890075Sobrien	...
725990075Sobrien
726090075Sobrien   We fix this by performing a scan after scheduling, which notices
726190075Sobrien   which instructions need to have their operands fetched from the
726290075Sobrien   constant table and builds the table.
726390075Sobrien
726490075Sobrien   The algorithm starts by building a table of all the constants that
726590075Sobrien   need fixing up and all the natural barriers in the function (places
726690075Sobrien   where a constant table can be dropped without breaking the flow).
726790075Sobrien   For each fixup we note how far the pc-relative replacement will be
726890075Sobrien   able to reach and the offset of the instruction into the function.
726990075Sobrien
727090075Sobrien   Having built the table we then group the fixes together to form
727190075Sobrien   tables that are as large as possible (subject to addressing
727290075Sobrien   constraints) and emit each table of constants after the last
727390075Sobrien   barrier that is within range of all the instructions in the group.
727490075Sobrien   If a group does not contain a barrier, then we forcibly create one
727590075Sobrien   by inserting a jump instruction into the flow.  Once the table has
727690075Sobrien   been inserted, the insns are then modified to reference the
727790075Sobrien   relevant entry in the pool.
727890075Sobrien
727990075Sobrien   Possible enhancements to the algorithm (not implemented) are:
728090075Sobrien
728190075Sobrien   1) For some processors and object formats, there may be benefit in
728290075Sobrien   aligning the pools to the start of cache lines; this alignment
728390075Sobrien   would need to be taken into account when calculating addressability
728490075Sobrien   of a pool.  */
728590075Sobrien
728690075Sobrien/* These typedefs are located at the start of this file, so that
728790075Sobrien   they can be used in the prototypes there.  This comment is to
728890075Sobrien   remind readers of that fact so that the following structures
728990075Sobrien   can be understood more easily.
729090075Sobrien
729190075Sobrien     typedef struct minipool_node    Mnode;
729290075Sobrien     typedef struct minipool_fixup   Mfix;  */
729390075Sobrien
729490075Sobrienstruct minipool_node
729590075Sobrien{
729690075Sobrien  /* Doubly linked chain of entries.  */
729790075Sobrien  Mnode * next;
729890075Sobrien  Mnode * prev;
729990075Sobrien  /* The maximum offset into the code that this entry can be placed.  While
730090075Sobrien     pushing fixes for forward references, all entries are sorted in order
730190075Sobrien     of increasing max_address.  */
730290075Sobrien  HOST_WIDE_INT max_address;
730390075Sobrien  /* Similarly for an entry inserted for a backwards ref.  */
730490075Sobrien  HOST_WIDE_INT min_address;
730590075Sobrien  /* The number of fixes referencing this entry.  This can become zero
730690075Sobrien     if we "unpush" an entry.  In this case we ignore the entry when we
730790075Sobrien     come to emit the code.  */
730890075Sobrien  int refcount;
730990075Sobrien  /* The offset from the start of the minipool.  */
731090075Sobrien  HOST_WIDE_INT offset;
731190075Sobrien  /* The value in table.  */
731290075Sobrien  rtx value;
731390075Sobrien  /* The mode of value.  */
731490075Sobrien  enum machine_mode mode;
7315132718Skan  /* The size of the value.  With iWMMXt enabled
7316132718Skan     sizes > 4 also imply an alignment of 8-bytes.  */
731790075Sobrien  int fix_size;
731890075Sobrien};
731990075Sobrien
732090075Sobrienstruct minipool_fixup
732190075Sobrien{
732290075Sobrien  Mfix *            next;
732390075Sobrien  rtx               insn;
732490075Sobrien  HOST_WIDE_INT     address;
732590075Sobrien  rtx *             loc;
732690075Sobrien  enum machine_mode mode;
732790075Sobrien  int               fix_size;
732890075Sobrien  rtx               value;
732990075Sobrien  Mnode *           minipool;
733090075Sobrien  HOST_WIDE_INT     forwards;
733190075Sobrien  HOST_WIDE_INT     backwards;
733290075Sobrien};
733390075Sobrien
733490075Sobrien/* Fixes less than a word need padding out to a word boundary.  */
733590075Sobrien#define MINIPOOL_FIX_SIZE(mode) \
733690075Sobrien  (GET_MODE_SIZE ((mode)) >= 4 ? GET_MODE_SIZE ((mode)) : 4)
733790075Sobrien
733890075Sobrienstatic Mnode *	minipool_vector_head;
733990075Sobrienstatic Mnode *	minipool_vector_tail;
734090075Sobrienstatic rtx	minipool_vector_label;
7341169689Skanstatic int	minipool_pad;
734290075Sobrien
734390075Sobrien/* The linked list of all minipool fixes required for this function.  */
734490075SobrienMfix * 		minipool_fix_head;
734590075SobrienMfix * 		minipool_fix_tail;
734690075Sobrien/* The fix entry for the current minipool, once it has been placed.  */
734790075SobrienMfix *		minipool_barrier;
734890075Sobrien
734990075Sobrien/* Determines if INSN is the start of a jump table.  Returns the end
735090075Sobrien   of the TABLE or NULL_RTX.  */
735190075Sobrienstatic rtx
7352132718Skanis_jump_table (rtx insn)
735390075Sobrien{
735490075Sobrien  rtx table;
7355169689Skan
735690075Sobrien  if (GET_CODE (insn) == JUMP_INSN
735790075Sobrien      && JUMP_LABEL (insn) != NULL
735890075Sobrien      && ((table = next_real_insn (JUMP_LABEL (insn)))
735990075Sobrien	  == next_real_insn (insn))
736090075Sobrien      && table != NULL
736190075Sobrien      && GET_CODE (table) == JUMP_INSN
736290075Sobrien      && (GET_CODE (PATTERN (table)) == ADDR_VEC
736390075Sobrien	  || GET_CODE (PATTERN (table)) == ADDR_DIFF_VEC))
736490075Sobrien    return table;
736590075Sobrien
736690075Sobrien  return NULL_RTX;
736790075Sobrien}
736890075Sobrien
736996263Sobrien#ifndef JUMP_TABLES_IN_TEXT_SECTION
737096263Sobrien#define JUMP_TABLES_IN_TEXT_SECTION 0
737196263Sobrien#endif
737296263Sobrien
737390075Sobrienstatic HOST_WIDE_INT
7374132718Skanget_jump_table_size (rtx insn)
737590075Sobrien{
737696263Sobrien  /* ADDR_VECs only take room if read-only data does into the text
737796263Sobrien     section.  */
7378169689Skan  if (JUMP_TABLES_IN_TEXT_SECTION || readonly_data_section == text_section)
737996263Sobrien    {
738096263Sobrien      rtx body = PATTERN (insn);
738196263Sobrien      int elt = GET_CODE (body) == ADDR_DIFF_VEC ? 1 : 0;
738290075Sobrien
738396263Sobrien      return GET_MODE_SIZE (GET_MODE (body)) * XVECLEN (body, elt);
738496263Sobrien    }
738596263Sobrien
738696263Sobrien  return 0;
738790075Sobrien}
738890075Sobrien
738990075Sobrien/* Move a minipool fix MP from its current location to before MAX_MP.
739090075Sobrien   If MAX_MP is NULL, then MP doesn't need moving, but the addressing
7391132718Skan   constraints may need updating.  */
739290075Sobrienstatic Mnode *
7393132718Skanmove_minipool_fix_forward_ref (Mnode *mp, Mnode *max_mp,
7394132718Skan			       HOST_WIDE_INT max_address)
739590075Sobrien{
7396169689Skan  /* The code below assumes these are different.  */
7397169689Skan  gcc_assert (mp != max_mp);
739890075Sobrien
739990075Sobrien  if (max_mp == NULL)
740090075Sobrien    {
740190075Sobrien      if (max_address < mp->max_address)
740290075Sobrien	mp->max_address = max_address;
740390075Sobrien    }
740490075Sobrien  else
740590075Sobrien    {
740690075Sobrien      if (max_address > max_mp->max_address - mp->fix_size)
740790075Sobrien	mp->max_address = max_mp->max_address - mp->fix_size;
740890075Sobrien      else
740990075Sobrien	mp->max_address = max_address;
741090075Sobrien
741190075Sobrien      /* Unlink MP from its current position.  Since max_mp is non-null,
741290075Sobrien       mp->prev must be non-null.  */
741390075Sobrien      mp->prev->next = mp->next;
741490075Sobrien      if (mp->next != NULL)
741590075Sobrien	mp->next->prev = mp->prev;
741690075Sobrien      else
741790075Sobrien	minipool_vector_tail = mp->prev;
741890075Sobrien
741990075Sobrien      /* Re-insert it before MAX_MP.  */
742090075Sobrien      mp->next = max_mp;
742190075Sobrien      mp->prev = max_mp->prev;
742290075Sobrien      max_mp->prev = mp;
7423169689Skan
742490075Sobrien      if (mp->prev != NULL)
742590075Sobrien	mp->prev->next = mp;
742690075Sobrien      else
742790075Sobrien	minipool_vector_head = mp;
742890075Sobrien    }
742990075Sobrien
743090075Sobrien  /* Save the new entry.  */
743190075Sobrien  max_mp = mp;
743290075Sobrien
743390075Sobrien  /* Scan over the preceding entries and adjust their addresses as
743490075Sobrien     required.  */
743590075Sobrien  while (mp->prev != NULL
743690075Sobrien	 && mp->prev->max_address > mp->max_address - mp->prev->fix_size)
743790075Sobrien    {
743890075Sobrien      mp->prev->max_address = mp->max_address - mp->prev->fix_size;
743990075Sobrien      mp = mp->prev;
744090075Sobrien    }
744190075Sobrien
744290075Sobrien  return max_mp;
744390075Sobrien}
744490075Sobrien
744590075Sobrien/* Add a constant to the minipool for a forward reference.  Returns the
744690075Sobrien   node added or NULL if the constant will not fit in this pool.  */
744790075Sobrienstatic Mnode *
7448132718Skanadd_minipool_forward_ref (Mfix *fix)
744990075Sobrien{
745090075Sobrien  /* If set, max_mp is the first pool_entry that has a lower
745190075Sobrien     constraint than the one we are trying to add.  */
745290075Sobrien  Mnode *       max_mp = NULL;
7453169689Skan  HOST_WIDE_INT max_address = fix->address + fix->forwards - minipool_pad;
745490075Sobrien  Mnode *       mp;
7455169689Skan
7456169689Skan  /* If the minipool starts before the end of FIX->INSN then this FIX
7457169689Skan     can not be placed into the current pool.  Furthermore, adding the
7458169689Skan     new constant pool entry may cause the pool to start FIX_SIZE bytes
7459169689Skan     earlier.  */
746090075Sobrien  if (minipool_vector_head &&
7461169689Skan      (fix->address + get_attr_length (fix->insn)
7462169689Skan       >= minipool_vector_head->max_address - fix->fix_size))
746390075Sobrien    return NULL;
746490075Sobrien
746590075Sobrien  /* Scan the pool to see if a constant with the same value has
746690075Sobrien     already been added.  While we are doing this, also note the
746790075Sobrien     location where we must insert the constant if it doesn't already
746890075Sobrien     exist.  */
746990075Sobrien  for (mp = minipool_vector_head; mp != NULL; mp = mp->next)
747090075Sobrien    {
747190075Sobrien      if (GET_CODE (fix->value) == GET_CODE (mp->value)
747290075Sobrien	  && fix->mode == mp->mode
747390075Sobrien	  && (GET_CODE (fix->value) != CODE_LABEL
747490075Sobrien	      || (CODE_LABEL_NUMBER (fix->value)
747590075Sobrien		  == CODE_LABEL_NUMBER (mp->value)))
747690075Sobrien	  && rtx_equal_p (fix->value, mp->value))
747790075Sobrien	{
747890075Sobrien	  /* More than one fix references this entry.  */
747990075Sobrien	  mp->refcount++;
748090075Sobrien	  return move_minipool_fix_forward_ref (mp, max_mp, max_address);
748190075Sobrien	}
748290075Sobrien
748390075Sobrien      /* Note the insertion point if necessary.  */
748490075Sobrien      if (max_mp == NULL
748590075Sobrien	  && mp->max_address > max_address)
748690075Sobrien	max_mp = mp;
7487132718Skan
7488132718Skan      /* If we are inserting an 8-bytes aligned quantity and
7489132718Skan	 we have not already found an insertion point, then
7490132718Skan	 make sure that all such 8-byte aligned quantities are
7491132718Skan	 placed at the start of the pool.  */
7492169689Skan      if (ARM_DOUBLEWORD_ALIGN
7493132718Skan	  && max_mp == NULL
7494132718Skan	  && fix->fix_size == 8
7495132718Skan	  && mp->fix_size != 8)
7496132718Skan	{
7497132718Skan	  max_mp = mp;
7498132718Skan	  max_address = mp->max_address;
7499132718Skan	}
750090075Sobrien    }
750190075Sobrien
750290075Sobrien  /* The value is not currently in the minipool, so we need to create
750390075Sobrien     a new entry for it.  If MAX_MP is NULL, the entry will be put on
750490075Sobrien     the end of the list since the placement is less constrained than
750590075Sobrien     any existing entry.  Otherwise, we insert the new fix before
7506132718Skan     MAX_MP and, if necessary, adjust the constraints on the other
750790075Sobrien     entries.  */
7508169689Skan  mp = XNEW (Mnode);
750990075Sobrien  mp->fix_size = fix->fix_size;
751090075Sobrien  mp->mode = fix->mode;
751190075Sobrien  mp->value = fix->value;
751290075Sobrien  mp->refcount = 1;
751390075Sobrien  /* Not yet required for a backwards ref.  */
751490075Sobrien  mp->min_address = -65536;
751590075Sobrien
751690075Sobrien  if (max_mp == NULL)
751790075Sobrien    {
751890075Sobrien      mp->max_address = max_address;
751990075Sobrien      mp->next = NULL;
752090075Sobrien      mp->prev = minipool_vector_tail;
752190075Sobrien
752290075Sobrien      if (mp->prev == NULL)
752390075Sobrien	{
752490075Sobrien	  minipool_vector_head = mp;
752590075Sobrien	  minipool_vector_label = gen_label_rtx ();
752690075Sobrien	}
752790075Sobrien      else
752890075Sobrien	mp->prev->next = mp;
752990075Sobrien
753090075Sobrien      minipool_vector_tail = mp;
753190075Sobrien    }
753290075Sobrien  else
753390075Sobrien    {
753490075Sobrien      if (max_address > max_mp->max_address - mp->fix_size)
753590075Sobrien	mp->max_address = max_mp->max_address - mp->fix_size;
753690075Sobrien      else
753790075Sobrien	mp->max_address = max_address;
753890075Sobrien
753990075Sobrien      mp->next = max_mp;
754090075Sobrien      mp->prev = max_mp->prev;
754190075Sobrien      max_mp->prev = mp;
754290075Sobrien      if (mp->prev != NULL)
754390075Sobrien	mp->prev->next = mp;
754490075Sobrien      else
754590075Sobrien	minipool_vector_head = mp;
754690075Sobrien    }
754790075Sobrien
754890075Sobrien  /* Save the new entry.  */
754990075Sobrien  max_mp = mp;
755090075Sobrien
755190075Sobrien  /* Scan over the preceding entries and adjust their addresses as
755290075Sobrien     required.  */
755390075Sobrien  while (mp->prev != NULL
755490075Sobrien	 && mp->prev->max_address > mp->max_address - mp->prev->fix_size)
755590075Sobrien    {
755690075Sobrien      mp->prev->max_address = mp->max_address - mp->prev->fix_size;
755790075Sobrien      mp = mp->prev;
755890075Sobrien    }
755990075Sobrien
756090075Sobrien  return max_mp;
756190075Sobrien}
756290075Sobrien
756390075Sobrienstatic Mnode *
7564132718Skanmove_minipool_fix_backward_ref (Mnode *mp, Mnode *min_mp,
7565132718Skan				HOST_WIDE_INT  min_address)
756690075Sobrien{
756790075Sobrien  HOST_WIDE_INT offset;
756890075Sobrien
7569169689Skan  /* The code below assumes these are different.  */
7570169689Skan  gcc_assert (mp != min_mp);
757190075Sobrien
757290075Sobrien  if (min_mp == NULL)
757390075Sobrien    {
757490075Sobrien      if (min_address > mp->min_address)
757590075Sobrien	mp->min_address = min_address;
757690075Sobrien    }
757790075Sobrien  else
757890075Sobrien    {
757990075Sobrien      /* We will adjust this below if it is too loose.  */
758090075Sobrien      mp->min_address = min_address;
758190075Sobrien
758290075Sobrien      /* Unlink MP from its current position.  Since min_mp is non-null,
758390075Sobrien	 mp->next must be non-null.  */
758490075Sobrien      mp->next->prev = mp->prev;
758590075Sobrien      if (mp->prev != NULL)
758690075Sobrien	mp->prev->next = mp->next;
758790075Sobrien      else
758890075Sobrien	minipool_vector_head = mp->next;
758990075Sobrien
759090075Sobrien      /* Reinsert it after MIN_MP.  */
759190075Sobrien      mp->prev = min_mp;
759290075Sobrien      mp->next = min_mp->next;
759390075Sobrien      min_mp->next = mp;
759490075Sobrien      if (mp->next != NULL)
759590075Sobrien	mp->next->prev = mp;
759690075Sobrien      else
759790075Sobrien	minipool_vector_tail = mp;
759890075Sobrien    }
759990075Sobrien
760090075Sobrien  min_mp = mp;
760190075Sobrien
760290075Sobrien  offset = 0;
760390075Sobrien  for (mp = minipool_vector_head; mp != NULL; mp = mp->next)
760490075Sobrien    {
760590075Sobrien      mp->offset = offset;
760690075Sobrien      if (mp->refcount > 0)
760790075Sobrien	offset += mp->fix_size;
760890075Sobrien
760990075Sobrien      if (mp->next && mp->next->min_address < mp->min_address + mp->fix_size)
761090075Sobrien	mp->next->min_address = mp->min_address + mp->fix_size;
761190075Sobrien    }
761290075Sobrien
761390075Sobrien  return min_mp;
7614169689Skan}
761590075Sobrien
761690075Sobrien/* Add a constant to the minipool for a backward reference.  Returns the
7617169689Skan   node added or NULL if the constant will not fit in this pool.
761890075Sobrien
761990075Sobrien   Note that the code for insertion for a backwards reference can be
762090075Sobrien   somewhat confusing because the calculated offsets for each fix do
762190075Sobrien   not take into account the size of the pool (which is still under
762290075Sobrien   construction.  */
762390075Sobrienstatic Mnode *
7624132718Skanadd_minipool_backward_ref (Mfix *fix)
762590075Sobrien{
762690075Sobrien  /* If set, min_mp is the last pool_entry that has a lower constraint
762790075Sobrien     than the one we are trying to add.  */
7628132718Skan  Mnode *min_mp = NULL;
762990075Sobrien  /* This can be negative, since it is only a constraint.  */
763090075Sobrien  HOST_WIDE_INT  min_address = fix->address - fix->backwards;
7631132718Skan  Mnode *mp;
763290075Sobrien
763390075Sobrien  /* If we can't reach the current pool from this insn, or if we can't
763490075Sobrien     insert this entry at the end of the pool without pushing other
763590075Sobrien     fixes out of range, then we don't try.  This ensures that we
763690075Sobrien     can't fail later on.  */
763790075Sobrien  if (min_address >= minipool_barrier->address
763890075Sobrien      || (minipool_vector_tail->min_address + fix->fix_size
763990075Sobrien	  >= minipool_barrier->address))
764090075Sobrien    return NULL;
764190075Sobrien
764290075Sobrien  /* Scan the pool to see if a constant with the same value has
764390075Sobrien     already been added.  While we are doing this, also note the
764490075Sobrien     location where we must insert the constant if it doesn't already
764590075Sobrien     exist.  */
764690075Sobrien  for (mp = minipool_vector_tail; mp != NULL; mp = mp->prev)
764790075Sobrien    {
764890075Sobrien      if (GET_CODE (fix->value) == GET_CODE (mp->value)
764990075Sobrien	  && fix->mode == mp->mode
765090075Sobrien	  && (GET_CODE (fix->value) != CODE_LABEL
765190075Sobrien	      || (CODE_LABEL_NUMBER (fix->value)
765290075Sobrien		  == CODE_LABEL_NUMBER (mp->value)))
765390075Sobrien	  && rtx_equal_p (fix->value, mp->value)
765490075Sobrien	  /* Check that there is enough slack to move this entry to the
765590075Sobrien	     end of the table (this is conservative).  */
7656169689Skan	  && (mp->max_address
7657169689Skan	      > (minipool_barrier->address
765890075Sobrien		 + minipool_vector_tail->offset
765990075Sobrien		 + minipool_vector_tail->fix_size)))
766090075Sobrien	{
766190075Sobrien	  mp->refcount++;
766290075Sobrien	  return move_minipool_fix_backward_ref (mp, min_mp, min_address);
766390075Sobrien	}
766490075Sobrien
766590075Sobrien      if (min_mp != NULL)
766690075Sobrien	mp->min_address += fix->fix_size;
766790075Sobrien      else
766890075Sobrien	{
766990075Sobrien	  /* Note the insertion point if necessary.  */
767090075Sobrien	  if (mp->min_address < min_address)
7671132718Skan	    {
7672132718Skan	      /* For now, we do not allow the insertion of 8-byte alignment
7673132718Skan		 requiring nodes anywhere but at the start of the pool.  */
7674169689Skan	      if (ARM_DOUBLEWORD_ALIGN
7675169689Skan		  && fix->fix_size == 8 && mp->fix_size != 8)
7676132718Skan		return NULL;
7677132718Skan	      else
7678132718Skan		min_mp = mp;
7679132718Skan	    }
768090075Sobrien	  else if (mp->max_address
768190075Sobrien		   < minipool_barrier->address + mp->offset + fix->fix_size)
768290075Sobrien	    {
768390075Sobrien	      /* Inserting before this entry would push the fix beyond
768490075Sobrien		 its maximum address (which can happen if we have
768590075Sobrien		 re-located a forwards fix); force the new fix to come
768690075Sobrien		 after it.  */
768790075Sobrien	      min_mp = mp;
768890075Sobrien	      min_address = mp->min_address + fix->fix_size;
768990075Sobrien	    }
7690132718Skan	  /* If we are inserting an 8-bytes aligned quantity and
7691132718Skan	     we have not already found an insertion point, then
7692132718Skan	     make sure that all such 8-byte aligned quantities are
7693132718Skan	     placed at the start of the pool.  */
7694169689Skan	  else if (ARM_DOUBLEWORD_ALIGN
7695132718Skan		   && min_mp == NULL
7696132718Skan		   && fix->fix_size == 8
7697132718Skan		   && mp->fix_size < 8)
7698132718Skan	    {
7699132718Skan	      min_mp = mp;
7700132718Skan	      min_address = mp->min_address + fix->fix_size;
7701132718Skan	    }
770290075Sobrien	}
770390075Sobrien    }
770490075Sobrien
770590075Sobrien  /* We need to create a new entry.  */
7706169689Skan  mp = XNEW (Mnode);
770790075Sobrien  mp->fix_size = fix->fix_size;
770890075Sobrien  mp->mode = fix->mode;
770990075Sobrien  mp->value = fix->value;
771090075Sobrien  mp->refcount = 1;
771190075Sobrien  mp->max_address = minipool_barrier->address + 65536;
771290075Sobrien
771390075Sobrien  mp->min_address = min_address;
771490075Sobrien
771590075Sobrien  if (min_mp == NULL)
771690075Sobrien    {
771790075Sobrien      mp->prev = NULL;
771890075Sobrien      mp->next = minipool_vector_head;
771990075Sobrien
772090075Sobrien      if (mp->next == NULL)
772190075Sobrien	{
772290075Sobrien	  minipool_vector_tail = mp;
772390075Sobrien	  minipool_vector_label = gen_label_rtx ();
772490075Sobrien	}
772590075Sobrien      else
772690075Sobrien	mp->next->prev = mp;
772790075Sobrien
772890075Sobrien      minipool_vector_head = mp;
772990075Sobrien    }
773090075Sobrien  else
773190075Sobrien    {
773290075Sobrien      mp->next = min_mp->next;
773390075Sobrien      mp->prev = min_mp;
773490075Sobrien      min_mp->next = mp;
7735169689Skan
773690075Sobrien      if (mp->next != NULL)
773790075Sobrien	mp->next->prev = mp;
773890075Sobrien      else
773990075Sobrien	minipool_vector_tail = mp;
774090075Sobrien    }
774190075Sobrien
774290075Sobrien  /* Save the new entry.  */
774390075Sobrien  min_mp = mp;
774490075Sobrien
774590075Sobrien  if (mp->prev)
774690075Sobrien    mp = mp->prev;
774790075Sobrien  else
774890075Sobrien    mp->offset = 0;
774990075Sobrien
775090075Sobrien  /* Scan over the following entries and adjust their offsets.  */
775190075Sobrien  while (mp->next != NULL)
775290075Sobrien    {
775390075Sobrien      if (mp->next->min_address < mp->min_address + mp->fix_size)
775490075Sobrien	mp->next->min_address = mp->min_address + mp->fix_size;
775590075Sobrien
775690075Sobrien      if (mp->refcount)
775790075Sobrien	mp->next->offset = mp->offset + mp->fix_size;
775890075Sobrien      else
775990075Sobrien	mp->next->offset = mp->offset;
776090075Sobrien
776190075Sobrien      mp = mp->next;
776290075Sobrien    }
776390075Sobrien
776490075Sobrien  return min_mp;
776590075Sobrien}
776690075Sobrien
776790075Sobrienstatic void
7768132718Skanassign_minipool_offsets (Mfix *barrier)
776990075Sobrien{
777090075Sobrien  HOST_WIDE_INT offset = 0;
7771132718Skan  Mnode *mp;
777290075Sobrien
777390075Sobrien  minipool_barrier = barrier;
777490075Sobrien
777590075Sobrien  for (mp = minipool_vector_head; mp != NULL; mp = mp->next)
777690075Sobrien    {
777790075Sobrien      mp->offset = offset;
7778169689Skan
777990075Sobrien      if (mp->refcount > 0)
778090075Sobrien	offset += mp->fix_size;
778190075Sobrien    }
778290075Sobrien}
778390075Sobrien
778490075Sobrien/* Output the literal table */
778590075Sobrienstatic void
7786132718Skandump_minipool (rtx scan)
778790075Sobrien{
778890075Sobrien  Mnode * mp;
778990075Sobrien  Mnode * nmp;
7790132718Skan  int align64 = 0;
779190075Sobrien
7792169689Skan  if (ARM_DOUBLEWORD_ALIGN)
7793132718Skan    for (mp = minipool_vector_head; mp != NULL; mp = mp->next)
7794132718Skan      if (mp->refcount > 0 && mp->fix_size == 8)
7795132718Skan	{
7796132718Skan	  align64 = 1;
7797132718Skan	  break;
7798132718Skan	}
7799132718Skan
7800169689Skan  if (dump_file)
7801169689Skan    fprintf (dump_file,
7802132718Skan	     ";; Emitting minipool after insn %u; address %ld; align %d (bytes)\n",
7803132718Skan	     INSN_UID (scan), (unsigned long) minipool_barrier->address, align64 ? 8 : 4);
780490075Sobrien
780590075Sobrien  scan = emit_label_after (gen_label_rtx (), scan);
7806132718Skan  scan = emit_insn_after (align64 ? gen_align_8 () : gen_align_4 (), scan);
780790075Sobrien  scan = emit_label_after (minipool_vector_label, scan);
780890075Sobrien
780990075Sobrien  for (mp = minipool_vector_head; mp != NULL; mp = nmp)
781090075Sobrien    {
781190075Sobrien      if (mp->refcount > 0)
781290075Sobrien	{
7813169689Skan	  if (dump_file)
781490075Sobrien	    {
7815169689Skan	      fprintf (dump_file,
781690075Sobrien		       ";;  Offset %u, min %ld, max %ld ",
781790075Sobrien		       (unsigned) mp->offset, (unsigned long) mp->min_address,
781890075Sobrien		       (unsigned long) mp->max_address);
7819169689Skan	      arm_print_value (dump_file, mp->value);
7820169689Skan	      fputc ('\n', dump_file);
782190075Sobrien	    }
782290075Sobrien
782390075Sobrien	  switch (mp->fix_size)
782490075Sobrien	    {
782590075Sobrien#ifdef HAVE_consttable_1
782690075Sobrien	    case 1:
782790075Sobrien	      scan = emit_insn_after (gen_consttable_1 (mp->value), scan);
782890075Sobrien	      break;
782990075Sobrien
783090075Sobrien#endif
783190075Sobrien#ifdef HAVE_consttable_2
783290075Sobrien	    case 2:
783390075Sobrien	      scan = emit_insn_after (gen_consttable_2 (mp->value), scan);
783490075Sobrien	      break;
783590075Sobrien
783690075Sobrien#endif
783790075Sobrien#ifdef HAVE_consttable_4
783890075Sobrien	    case 4:
783990075Sobrien	      scan = emit_insn_after (gen_consttable_4 (mp->value), scan);
784090075Sobrien	      break;
784190075Sobrien
784290075Sobrien#endif
784390075Sobrien#ifdef HAVE_consttable_8
784490075Sobrien	    case 8:
784590075Sobrien	      scan = emit_insn_after (gen_consttable_8 (mp->value), scan);
784690075Sobrien	      break;
784790075Sobrien
784890075Sobrien#endif
784990075Sobrien	    default:
7850169689Skan	      gcc_unreachable ();
785190075Sobrien	    }
785290075Sobrien	}
785390075Sobrien
785490075Sobrien      nmp = mp->next;
785590075Sobrien      free (mp);
785690075Sobrien    }
785790075Sobrien
785890075Sobrien  minipool_vector_head = minipool_vector_tail = NULL;
785990075Sobrien  scan = emit_insn_after (gen_consttable_end (), scan);
786090075Sobrien  scan = emit_barrier_after (scan);
786190075Sobrien}
786290075Sobrien
786390075Sobrien/* Return the cost of forcibly inserting a barrier after INSN.  */
786490075Sobrienstatic int
7865132718Skanarm_barrier_cost (rtx insn)
786690075Sobrien{
786790075Sobrien  /* Basing the location of the pool on the loop depth is preferable,
786890075Sobrien     but at the moment, the basic block information seems to be
786990075Sobrien     corrupt by this stage of the compilation.  */
787090075Sobrien  int base_cost = 50;
787190075Sobrien  rtx next = next_nonnote_insn (insn);
787290075Sobrien
787390075Sobrien  if (next != NULL && GET_CODE (next) == CODE_LABEL)
787490075Sobrien    base_cost -= 20;
787590075Sobrien
787690075Sobrien  switch (GET_CODE (insn))
787790075Sobrien    {
787890075Sobrien    case CODE_LABEL:
787990075Sobrien      /* It will always be better to place the table before the label, rather
788090075Sobrien	 than after it.  */
7881169689Skan      return 50;
788290075Sobrien
788390075Sobrien    case INSN:
788490075Sobrien    case CALL_INSN:
788590075Sobrien      return base_cost;
788690075Sobrien
788790075Sobrien    case JUMP_INSN:
788890075Sobrien      return base_cost - 10;
788990075Sobrien
789090075Sobrien    default:
789190075Sobrien      return base_cost + 10;
789290075Sobrien    }
789390075Sobrien}
789490075Sobrien
789590075Sobrien/* Find the best place in the insn stream in the range
789690075Sobrien   (FIX->address,MAX_ADDRESS) to forcibly insert a minipool barrier.
789790075Sobrien   Create the barrier by inserting a jump and add a new fix entry for
789890075Sobrien   it.  */
789990075Sobrienstatic Mfix *
7900132718Skancreate_fix_barrier (Mfix *fix, HOST_WIDE_INT max_address)
790190075Sobrien{
790290075Sobrien  HOST_WIDE_INT count = 0;
790390075Sobrien  rtx barrier;
790490075Sobrien  rtx from = fix->insn;
7905169689Skan  /* The instruction after which we will insert the jump.  */
7906169689Skan  rtx selected = NULL;
790790075Sobrien  int selected_cost;
7908169689Skan  /* The address at which the jump instruction will be placed.  */
790990075Sobrien  HOST_WIDE_INT selected_address;
791090075Sobrien  Mfix * new_fix;
791190075Sobrien  HOST_WIDE_INT max_count = max_address - fix->address;
791290075Sobrien  rtx label = gen_label_rtx ();
791390075Sobrien
791490075Sobrien  selected_cost = arm_barrier_cost (from);
791590075Sobrien  selected_address = fix->address;
791690075Sobrien
791790075Sobrien  while (from && count < max_count)
791890075Sobrien    {
791990075Sobrien      rtx tmp;
792090075Sobrien      int new_cost;
792190075Sobrien
792290075Sobrien      /* This code shouldn't have been called if there was a natural barrier
792390075Sobrien	 within range.  */
7924169689Skan      gcc_assert (GET_CODE (from) != BARRIER);
792590075Sobrien
792690075Sobrien      /* Count the length of this insn.  */
792790075Sobrien      count += get_attr_length (from);
792890075Sobrien
792990075Sobrien      /* If there is a jump table, add its length.  */
793090075Sobrien      tmp = is_jump_table (from);
793190075Sobrien      if (tmp != NULL)
793290075Sobrien	{
793390075Sobrien	  count += get_jump_table_size (tmp);
793490075Sobrien
793590075Sobrien	  /* Jump tables aren't in a basic block, so base the cost on
793690075Sobrien	     the dispatch insn.  If we select this location, we will
793790075Sobrien	     still put the pool after the table.  */
793890075Sobrien	  new_cost = arm_barrier_cost (from);
793990075Sobrien
7940169689Skan	  if (count < max_count
7941169689Skan	      && (!selected || new_cost <= selected_cost))
794290075Sobrien	    {
794390075Sobrien	      selected = tmp;
794490075Sobrien	      selected_cost = new_cost;
794590075Sobrien	      selected_address = fix->address + count;
794690075Sobrien	    }
794790075Sobrien
794890075Sobrien	  /* Continue after the dispatch table.  */
794990075Sobrien	  from = NEXT_INSN (tmp);
795090075Sobrien	  continue;
795190075Sobrien	}
795290075Sobrien
795390075Sobrien      new_cost = arm_barrier_cost (from);
7954169689Skan
7955169689Skan      if (count < max_count
7956169689Skan	  && (!selected || new_cost <= selected_cost))
795790075Sobrien	{
795890075Sobrien	  selected = from;
795990075Sobrien	  selected_cost = new_cost;
796090075Sobrien	  selected_address = fix->address + count;
796190075Sobrien	}
796290075Sobrien
796390075Sobrien      from = NEXT_INSN (from);
796490075Sobrien    }
796590075Sobrien
7966169689Skan  /* Make sure that we found a place to insert the jump.  */
7967169689Skan  gcc_assert (selected);
7968169689Skan
796990075Sobrien  /* Create a new JUMP_INSN that branches around a barrier.  */
797090075Sobrien  from = emit_jump_insn_after (gen_jump (label), selected);
797190075Sobrien  JUMP_LABEL (from) = label;
797290075Sobrien  barrier = emit_barrier_after (from);
797390075Sobrien  emit_label_after (label, barrier);
797490075Sobrien
797590075Sobrien  /* Create a minipool barrier entry for the new barrier.  */
797690075Sobrien  new_fix = (Mfix *) obstack_alloc (&minipool_obstack, sizeof (* new_fix));
797790075Sobrien  new_fix->insn = barrier;
797890075Sobrien  new_fix->address = selected_address;
797990075Sobrien  new_fix->next = fix->next;
798090075Sobrien  fix->next = new_fix;
798190075Sobrien
798290075Sobrien  return new_fix;
798390075Sobrien}
798490075Sobrien
798590075Sobrien/* Record that there is a natural barrier in the insn stream at
798690075Sobrien   ADDRESS.  */
798790075Sobrienstatic void
7988132718Skanpush_minipool_barrier (rtx insn, HOST_WIDE_INT address)
798990075Sobrien{
799090075Sobrien  Mfix * fix = (Mfix *) obstack_alloc (&minipool_obstack, sizeof (* fix));
799190075Sobrien
799290075Sobrien  fix->insn = insn;
799390075Sobrien  fix->address = address;
799490075Sobrien
799590075Sobrien  fix->next = NULL;
799690075Sobrien  if (minipool_fix_head != NULL)
799790075Sobrien    minipool_fix_tail->next = fix;
799890075Sobrien  else
799990075Sobrien    minipool_fix_head = fix;
800090075Sobrien
800190075Sobrien  minipool_fix_tail = fix;
800290075Sobrien}
800390075Sobrien
800490075Sobrien/* Record INSN, which will need fixing up to load a value from the
800590075Sobrien   minipool.  ADDRESS is the offset of the insn since the start of the
800690075Sobrien   function; LOC is a pointer to the part of the insn which requires
800790075Sobrien   fixing; VALUE is the constant that must be loaded, which is of type
800890075Sobrien   MODE.  */
800990075Sobrienstatic void
8010132718Skanpush_minipool_fix (rtx insn, HOST_WIDE_INT address, rtx *loc,
8011132718Skan		   enum machine_mode mode, rtx value)
801290075Sobrien{
801390075Sobrien  Mfix * fix = (Mfix *) obstack_alloc (&minipool_obstack, sizeof (* fix));
801490075Sobrien
801590075Sobrien#ifdef AOF_ASSEMBLER
8016132718Skan  /* PIC symbol references need to be converted into offsets into the
801790075Sobrien     based area.  */
801890075Sobrien  /* XXX This shouldn't be done here.  */
801990075Sobrien  if (flag_pic && GET_CODE (value) == SYMBOL_REF)
802090075Sobrien    value = aof_pic_entry (value);
802190075Sobrien#endif /* AOF_ASSEMBLER */
802290075Sobrien
802390075Sobrien  fix->insn = insn;
802490075Sobrien  fix->address = address;
802590075Sobrien  fix->loc = loc;
802690075Sobrien  fix->mode = mode;
802790075Sobrien  fix->fix_size = MINIPOOL_FIX_SIZE (mode);
802890075Sobrien  fix->value = value;
802990075Sobrien  fix->forwards = get_attr_pool_range (insn);
803090075Sobrien  fix->backwards = get_attr_neg_pool_range (insn);
803190075Sobrien  fix->minipool = NULL;
803290075Sobrien
803390075Sobrien  /* If an insn doesn't have a range defined for it, then it isn't
8034169689Skan     expecting to be reworked by this code.  Better to stop now than
803590075Sobrien     to generate duff assembly code.  */
8036169689Skan  gcc_assert (fix->forwards || fix->backwards);
803790075Sobrien
8038169689Skan  /* If an entry requires 8-byte alignment then assume all constant pools
8039169689Skan     require 4 bytes of padding.  Trying to do this later on a per-pool
8040169689Skan     basis is awkward because existing pool entries have to be modified.  */
8041169689Skan  if (ARM_DOUBLEWORD_ALIGN && fix->fix_size == 8)
8042169689Skan    minipool_pad = 4;
8043132718Skan
8044169689Skan  if (dump_file)
804590075Sobrien    {
8046169689Skan      fprintf (dump_file,
804790075Sobrien	       ";; %smode fixup for i%d; addr %lu, range (%ld,%ld): ",
804890075Sobrien	       GET_MODE_NAME (mode),
8049169689Skan	       INSN_UID (insn), (unsigned long) address,
805090075Sobrien	       -1 * (long)fix->backwards, (long)fix->forwards);
8051169689Skan      arm_print_value (dump_file, fix->value);
8052169689Skan      fprintf (dump_file, "\n");
805390075Sobrien    }
805490075Sobrien
805590075Sobrien  /* Add it to the chain of fixes.  */
805690075Sobrien  fix->next = NULL;
8057169689Skan
805890075Sobrien  if (minipool_fix_head != NULL)
805990075Sobrien    minipool_fix_tail->next = fix;
806090075Sobrien  else
806190075Sobrien    minipool_fix_head = fix;
806290075Sobrien
806390075Sobrien  minipool_fix_tail = fix;
806490075Sobrien}
806590075Sobrien
8066169689Skan/* Return the cost of synthesizing a 64-bit constant VAL inline.
8067169689Skan   Returns the number of insns needed, or 99 if we don't know how to
8068169689Skan   do it.  */
8069169689Skanint
8070169689Skanarm_const_double_inline_cost (rtx val)
8071169689Skan{
8072169689Skan  rtx lowpart, highpart;
8073169689Skan  enum machine_mode mode;
8074169689Skan
8075169689Skan  mode = GET_MODE (val);
8076169689Skan
8077169689Skan  if (mode == VOIDmode)
8078169689Skan    mode = DImode;
8079169689Skan
8080169689Skan  gcc_assert (GET_MODE_SIZE (mode) == 8);
8081169689Skan
8082169689Skan  lowpart = gen_lowpart (SImode, val);
8083169689Skan  highpart = gen_highpart_mode (SImode, mode, val);
8084169689Skan
8085169689Skan  gcc_assert (GET_CODE (lowpart) == CONST_INT);
8086169689Skan  gcc_assert (GET_CODE (highpart) == CONST_INT);
8087169689Skan
8088169689Skan  return (arm_gen_constant (SET, SImode, NULL_RTX, INTVAL (lowpart),
8089169689Skan			    NULL_RTX, NULL_RTX, 0, 0)
8090169689Skan	  + arm_gen_constant (SET, SImode, NULL_RTX, INTVAL (highpart),
8091169689Skan			      NULL_RTX, NULL_RTX, 0, 0));
8092169689Skan}
8093169689Skan
8094169689Skan/* Return true if it is worthwhile to split a 64-bit constant into two
8095169689Skan   32-bit operations.  This is the case if optimizing for size, or
8096169689Skan   if we have load delay slots, or if one 32-bit part can be done with
8097169689Skan   a single data operation.  */
8098169689Skanbool
8099169689Skanarm_const_double_by_parts (rtx val)
8100169689Skan{
8101169689Skan  enum machine_mode mode = GET_MODE (val);
8102169689Skan  rtx part;
8103169689Skan
8104169689Skan  if (optimize_size || arm_ld_sched)
8105169689Skan    return true;
8106169689Skan
8107169689Skan  if (mode == VOIDmode)
8108169689Skan    mode = DImode;
8109169689Skan
8110169689Skan  part = gen_highpart_mode (SImode, mode, val);
8111169689Skan
8112169689Skan  gcc_assert (GET_CODE (part) == CONST_INT);
8113169689Skan
8114169689Skan  if (const_ok_for_arm (INTVAL (part))
8115169689Skan      || const_ok_for_arm (~INTVAL (part)))
8116169689Skan    return true;
8117169689Skan
8118169689Skan  part = gen_lowpart (SImode, val);
8119169689Skan
8120169689Skan  gcc_assert (GET_CODE (part) == CONST_INT);
8121169689Skan
8122169689Skan  if (const_ok_for_arm (INTVAL (part))
8123169689Skan      || const_ok_for_arm (~INTVAL (part)))
8124169689Skan    return true;
8125169689Skan
8126169689Skan  return false;
8127169689Skan}
8128169689Skan
8129132718Skan/* Scan INSN and note any of its operands that need fixing.
8130132718Skan   If DO_PUSHES is false we do not actually push any of the fixups
8131169689Skan   needed.  The function returns TRUE if any fixups were needed/pushed.
8132132718Skan   This is used by arm_memory_load_p() which needs to know about loads
8133132718Skan   of constants that will be converted into minipool loads.  */
8134132718Skanstatic bool
8135132718Skannote_invalid_constants (rtx insn, HOST_WIDE_INT address, int do_pushes)
813690075Sobrien{
8137132718Skan  bool result = false;
813890075Sobrien  int opno;
813990075Sobrien
814090075Sobrien  extract_insn (insn);
814190075Sobrien
814290075Sobrien  if (!constrain_operands (1))
814390075Sobrien    fatal_insn_not_found (insn);
814490075Sobrien
8145132718Skan  if (recog_data.n_alternatives == 0)
8146132718Skan    return false;
8147132718Skan
8148169689Skan  /* Fill in recog_op_alt with information about the constraints of
8149169689Skan     this insn.  */
815090075Sobrien  preprocess_constraints ();
815190075Sobrien
815290075Sobrien  for (opno = 0; opno < recog_data.n_operands; opno++)
815390075Sobrien    {
815490075Sobrien      /* Things we need to fix can only occur in inputs.  */
815590075Sobrien      if (recog_data.operand_type[opno] != OP_IN)
815690075Sobrien	continue;
815790075Sobrien
815890075Sobrien      /* If this alternative is a memory reference, then any mention
815990075Sobrien	 of constants in this alternative is really to fool reload
816090075Sobrien	 into allowing us to accept one there.  We need to fix them up
816190075Sobrien	 now so that we output the right code.  */
816290075Sobrien      if (recog_op_alt[opno][which_alternative].memory_ok)
816390075Sobrien	{
816490075Sobrien	  rtx op = recog_data.operand[opno];
816590075Sobrien
816690075Sobrien	  if (CONSTANT_P (op))
8167132718Skan	    {
8168132718Skan	      if (do_pushes)
8169132718Skan		push_minipool_fix (insn, address, recog_data.operand_loc[opno],
8170132718Skan				   recog_data.operand_mode[opno], op);
8171132718Skan	      result = true;
8172132718Skan	    }
817390075Sobrien	  else if (GET_CODE (op) == MEM
817490075Sobrien		   && GET_CODE (XEXP (op, 0)) == SYMBOL_REF
817590075Sobrien		   && CONSTANT_POOL_ADDRESS_P (XEXP (op, 0)))
8176132718Skan	    {
8177132718Skan	      if (do_pushes)
8178132718Skan		{
8179132718Skan		  rtx cop = avoid_constant_pool_reference (op);
8180132718Skan
8181132718Skan		  /* Casting the address of something to a mode narrower
8182132718Skan		     than a word can cause avoid_constant_pool_reference()
8183132718Skan		     to return the pool reference itself.  That's no good to
8184169689Skan		     us here.  Lets just hope that we can use the
8185132718Skan		     constant pool value directly.  */
8186132718Skan		  if (op == cop)
8187132718Skan		    cop = get_pool_constant (XEXP (op, 0));
8188132718Skan
8189132718Skan		  push_minipool_fix (insn, address,
8190132718Skan				     recog_data.operand_loc[opno],
8191132718Skan				     recog_data.operand_mode[opno], cop);
8192132718Skan		}
8193132718Skan
8194132718Skan	      result = true;
8195132718Skan	    }
819690075Sobrien	}
819790075Sobrien    }
8198132718Skan
8199132718Skan  return result;
820090075Sobrien}
820190075Sobrien
8202132718Skan/* Gcc puts the pool in the wrong place for ARM, since we can only
8203132718Skan   load addresses a limited distance around the pc.  We do some
8204132718Skan   special munging to move the constant pool values to the correct
8205132718Skan   point in the code.  */
8206132718Skanstatic void
8207132718Skanarm_reorg (void)
820890075Sobrien{
820990075Sobrien  rtx insn;
821090075Sobrien  HOST_WIDE_INT address = 0;
821190075Sobrien  Mfix * fix;
821290075Sobrien
821390075Sobrien  minipool_fix_head = minipool_fix_tail = NULL;
821490075Sobrien
821590075Sobrien  /* The first insn must always be a note, or the code below won't
821690075Sobrien     scan it properly.  */
8217132718Skan  insn = get_insns ();
8218169689Skan  gcc_assert (GET_CODE (insn) == NOTE);
8219169689Skan  minipool_pad = 0;
822090075Sobrien
822190075Sobrien  /* Scan all the insns and record the operands that will need fixing.  */
8222132718Skan  for (insn = next_nonnote_insn (insn); insn; insn = next_nonnote_insn (insn))
822390075Sobrien    {
8224132718Skan      if (TARGET_CIRRUS_FIX_INVALID_INSNS
8225132718Skan          && (arm_cirrus_insn_p (insn)
8226132718Skan	      || GET_CODE (insn) == JUMP_INSN
8227132718Skan	      || arm_memory_load_p (insn)))
8228132718Skan	cirrus_reorg (insn);
8229132718Skan
823090075Sobrien      if (GET_CODE (insn) == BARRIER)
823190075Sobrien	push_minipool_barrier (insn, address);
8232132718Skan      else if (INSN_P (insn))
823390075Sobrien	{
823490075Sobrien	  rtx table;
823590075Sobrien
8236132718Skan	  note_invalid_constants (insn, address, true);
823790075Sobrien	  address += get_attr_length (insn);
823890075Sobrien
823990075Sobrien	  /* If the insn is a vector jump, add the size of the table
824090075Sobrien	     and skip the table.  */
824190075Sobrien	  if ((table = is_jump_table (insn)) != NULL)
824290075Sobrien	    {
824390075Sobrien	      address += get_jump_table_size (table);
824490075Sobrien	      insn = table;
824590075Sobrien	    }
824690075Sobrien	}
824790075Sobrien    }
824890075Sobrien
824990075Sobrien  fix = minipool_fix_head;
8250169689Skan
825190075Sobrien  /* Now scan the fixups and perform the required changes.  */
825290075Sobrien  while (fix)
825390075Sobrien    {
825490075Sobrien      Mfix * ftmp;
825590075Sobrien      Mfix * fdel;
825690075Sobrien      Mfix *  last_added_fix;
825790075Sobrien      Mfix * last_barrier = NULL;
825890075Sobrien      Mfix * this_fix;
825990075Sobrien
826090075Sobrien      /* Skip any further barriers before the next fix.  */
826190075Sobrien      while (fix && GET_CODE (fix->insn) == BARRIER)
826290075Sobrien	fix = fix->next;
826390075Sobrien
826490075Sobrien      /* No more fixes.  */
826590075Sobrien      if (fix == NULL)
826690075Sobrien	break;
826790075Sobrien
826890075Sobrien      last_added_fix = NULL;
826990075Sobrien
827090075Sobrien      for (ftmp = fix; ftmp; ftmp = ftmp->next)
827190075Sobrien	{
827290075Sobrien	  if (GET_CODE (ftmp->insn) == BARRIER)
827390075Sobrien	    {
827490075Sobrien	      if (ftmp->address >= minipool_vector_head->max_address)
827590075Sobrien		break;
827690075Sobrien
827790075Sobrien	      last_barrier = ftmp;
827890075Sobrien	    }
827990075Sobrien	  else if ((ftmp->minipool = add_minipool_forward_ref (ftmp)) == NULL)
828090075Sobrien	    break;
828190075Sobrien
828290075Sobrien	  last_added_fix = ftmp;  /* Keep track of the last fix added.  */
828390075Sobrien	}
828490075Sobrien
828590075Sobrien      /* If we found a barrier, drop back to that; any fixes that we
828690075Sobrien	 could have reached but come after the barrier will now go in
828790075Sobrien	 the next mini-pool.  */
828890075Sobrien      if (last_barrier != NULL)
828990075Sobrien	{
8290169689Skan	  /* Reduce the refcount for those fixes that won't go into this
829190075Sobrien	     pool after all.  */
829290075Sobrien	  for (fdel = last_barrier->next;
829390075Sobrien	       fdel && fdel != ftmp;
829490075Sobrien	       fdel = fdel->next)
829590075Sobrien	    {
829690075Sobrien	      fdel->minipool->refcount--;
829790075Sobrien	      fdel->minipool = NULL;
829890075Sobrien	    }
829990075Sobrien
830090075Sobrien	  ftmp = last_barrier;
830190075Sobrien	}
830290075Sobrien      else
830390075Sobrien        {
830490075Sobrien	  /* ftmp is first fix that we can't fit into this pool and
830590075Sobrien	     there no natural barriers that we could use.  Insert a
830690075Sobrien	     new barrier in the code somewhere between the previous
830790075Sobrien	     fix and this one, and arrange to jump around it.  */
830890075Sobrien	  HOST_WIDE_INT max_address;
830990075Sobrien
831090075Sobrien	  /* The last item on the list of fixes must be a barrier, so
831190075Sobrien	     we can never run off the end of the list of fixes without
831290075Sobrien	     last_barrier being set.  */
8313169689Skan	  gcc_assert (ftmp);
831490075Sobrien
831590075Sobrien	  max_address = minipool_vector_head->max_address;
831690075Sobrien	  /* Check that there isn't another fix that is in range that
831790075Sobrien	     we couldn't fit into this pool because the pool was
831890075Sobrien	     already too large: we need to put the pool before such an
8319169689Skan	     instruction.  The pool itself may come just after the
8320169689Skan	     fix because create_fix_barrier also allows space for a
8321169689Skan	     jump instruction.  */
832290075Sobrien	  if (ftmp->address < max_address)
8323169689Skan	    max_address = ftmp->address + 1;
832490075Sobrien
832590075Sobrien	  last_barrier = create_fix_barrier (last_added_fix, max_address);
832690075Sobrien	}
832790075Sobrien
832890075Sobrien      assign_minipool_offsets (last_barrier);
832990075Sobrien
833090075Sobrien      while (ftmp)
833190075Sobrien	{
833290075Sobrien	  if (GET_CODE (ftmp->insn) != BARRIER
833390075Sobrien	      && ((ftmp->minipool = add_minipool_backward_ref (ftmp))
833490075Sobrien		  == NULL))
833590075Sobrien	    break;
833690075Sobrien
833790075Sobrien	  ftmp = ftmp->next;
833890075Sobrien	}
833990075Sobrien
834090075Sobrien      /* Scan over the fixes we have identified for this pool, fixing them
834190075Sobrien	 up and adding the constants to the pool itself.  */
834290075Sobrien      for (this_fix = fix; this_fix && ftmp != this_fix;
834390075Sobrien	   this_fix = this_fix->next)
834490075Sobrien	if (GET_CODE (this_fix->insn) != BARRIER)
834590075Sobrien	  {
834690075Sobrien	    rtx addr
8347169689Skan	      = plus_constant (gen_rtx_LABEL_REF (VOIDmode,
834890075Sobrien						  minipool_vector_label),
834990075Sobrien			       this_fix->minipool->offset);
835090075Sobrien	    *this_fix->loc = gen_rtx_MEM (this_fix->mode, addr);
835190075Sobrien	  }
835290075Sobrien
835390075Sobrien      dump_minipool (last_barrier->insn);
835490075Sobrien      fix = ftmp;
835590075Sobrien    }
835690075Sobrien
835790075Sobrien  /* From now on we must synthesize any constants that we can't handle
835890075Sobrien     directly.  This can happen if the RTL gets split during final
835990075Sobrien     instruction generation.  */
836090075Sobrien  after_arm_reorg = 1;
836190075Sobrien
836290075Sobrien  /* Free the minipool memory.  */
836390075Sobrien  obstack_free (&minipool_obstack, minipool_startobj);
836490075Sobrien}
836590075Sobrien
836690075Sobrien/* Routines to output assembly language.  */
836790075Sobrien
836890075Sobrien/* If the rtx is the correct value then return the string of the number.
836990075Sobrien   In this way we can ensure that valid double constants are generated even
837090075Sobrien   when cross compiling.  */
837190075Sobrienconst char *
8372132718Skanfp_immediate_constant (rtx x)
837390075Sobrien{
837490075Sobrien  REAL_VALUE_TYPE r;
837590075Sobrien  int i;
8376169689Skan
8377169689Skan  if (!fp_consts_inited)
8378169689Skan    init_fp_table ();
8379169689Skan
838090075Sobrien  REAL_VALUE_FROM_CONST_DOUBLE (r, x);
838190075Sobrien  for (i = 0; i < 8; i++)
8382169689Skan    if (REAL_VALUES_EQUAL (r, values_fp[i]))
8383169689Skan      return strings_fp[i];
838490075Sobrien
8385169689Skan  gcc_unreachable ();
838690075Sobrien}
838790075Sobrien
838890075Sobrien/* As for fp_immediate_constant, but value is passed directly, not in rtx.  */
838990075Sobrienstatic const char *
8390132718Skanfp_const_from_val (REAL_VALUE_TYPE *r)
839190075Sobrien{
839290075Sobrien  int i;
839390075Sobrien
8394169689Skan  if (!fp_consts_inited)
8395169689Skan    init_fp_table ();
839690075Sobrien
839790075Sobrien  for (i = 0; i < 8; i++)
8398169689Skan    if (REAL_VALUES_EQUAL (*r, values_fp[i]))
8399169689Skan      return strings_fp[i];
840090075Sobrien
8401169689Skan  gcc_unreachable ();
840290075Sobrien}
840390075Sobrien
840490075Sobrien/* Output the operands of a LDM/STM instruction to STREAM.
840590075Sobrien   MASK is the ARM register set mask of which only bits 0-15 are important.
840690075Sobrien   REG is the base register, either the frame pointer or the stack pointer,
840790075Sobrien   INSTR is the possibly suffixed load or store instruction.  */
8408169689Skan
840990075Sobrienstatic void
8410169689Skanprint_multi_reg (FILE *stream, const char *instr, unsigned reg,
8411169689Skan		 unsigned long mask)
841290075Sobrien{
8413169689Skan  unsigned i;
8414169689Skan  bool not_first = FALSE;
841590075Sobrien
841690075Sobrien  fputc ('\t', stream);
841790075Sobrien  asm_fprintf (stream, instr, reg);
841890075Sobrien  fputs (", {", stream);
8419169689Skan
842090075Sobrien  for (i = 0; i <= LAST_ARM_REGNUM; i++)
842190075Sobrien    if (mask & (1 << i))
842290075Sobrien      {
842390075Sobrien	if (not_first)
842490075Sobrien	  fprintf (stream, ", ");
8425169689Skan
842690075Sobrien	asm_fprintf (stream, "%r", i);
842790075Sobrien	not_first = TRUE;
842890075Sobrien      }
842990075Sobrien
8430169689Skan  fprintf (stream, "}\n");
8431169689Skan}
8432132718Skan
8433169689Skan
8434169689Skan/* Output a FLDMX instruction to STREAM.
8435169689Skan   BASE if the register containing the address.
8436169689Skan   REG and COUNT specify the register range.
8437169689Skan   Extra registers may be added to avoid hardware bugs.  */
8438169689Skan
8439169689Skanstatic void
8440169689Skanarm_output_fldmx (FILE * stream, unsigned int base, int reg, int count)
8441169689Skan{
8442169689Skan  int i;
8443169689Skan
8444169689Skan  /* Workaround ARM10 VFPr1 bug.  */
8445169689Skan  if (count == 2 && !arm_arch6)
8446169689Skan    {
8447169689Skan      if (reg == 15)
8448169689Skan	reg--;
8449169689Skan      count++;
8450169689Skan    }
8451169689Skan
8452169689Skan  fputc ('\t', stream);
8453169689Skan  asm_fprintf (stream, "fldmfdx\t%r!, {", base);
8454169689Skan
8455169689Skan  for (i = reg; i < reg + count; i++)
8456169689Skan    {
8457169689Skan      if (i > reg)
8458169689Skan	fputs (", ", stream);
8459169689Skan      asm_fprintf (stream, "d%d", i);
8460169689Skan    }
8461169689Skan  fputs ("}\n", stream);
8462169689Skan
846390075Sobrien}
846490075Sobrien
8465169689Skan
8466169689Skan/* Output the assembly for a store multiple.  */
8467169689Skan
8468169689Skanconst char *
8469169689Skanvfp_output_fstmx (rtx * operands)
8470169689Skan{
8471169689Skan  char pattern[100];
8472169689Skan  int p;
8473169689Skan  int base;
8474169689Skan  int i;
8475169689Skan
8476169689Skan  strcpy (pattern, "fstmfdx\t%m0!, {%P1");
8477169689Skan  p = strlen (pattern);
8478169689Skan
8479169689Skan  gcc_assert (GET_CODE (operands[1]) == REG);
8480169689Skan
8481169689Skan  base = (REGNO (operands[1]) - FIRST_VFP_REGNUM) / 2;
8482169689Skan  for (i = 1; i < XVECLEN (operands[2], 0); i++)
8483169689Skan    {
8484169689Skan      p += sprintf (&pattern[p], ", d%d", base + i);
8485169689Skan    }
8486169689Skan  strcpy (&pattern[p], "}");
8487169689Skan
8488169689Skan  output_asm_insn (pattern, operands);
8489169689Skan  return "";
8490169689Skan}
8491169689Skan
8492169689Skan
8493169689Skan/* Emit RTL to save block of VFP register pairs to the stack.  Returns the
8494169689Skan   number of bytes pushed.  */
8495169689Skan
8496169689Skanstatic int
8497169689Skanvfp_emit_fstmx (int base_reg, int count)
8498169689Skan{
8499169689Skan  rtx par;
8500169689Skan  rtx dwarf;
8501169689Skan  rtx tmp, reg;
8502169689Skan  int i;
8503169689Skan
8504169689Skan  /* Workaround ARM10 VFPr1 bug.  Data corruption can occur when exactly two
8505169689Skan     register pairs are stored by a store multiple insn.  We avoid this
8506169689Skan     by pushing an extra pair.  */
8507169689Skan  if (count == 2 && !arm_arch6)
8508169689Skan    {
8509169689Skan      if (base_reg == LAST_VFP_REGNUM - 3)
8510169689Skan	base_reg -= 2;
8511169689Skan      count++;
8512169689Skan    }
8513169689Skan
8514169689Skan  /* ??? The frame layout is implementation defined.  We describe
8515169689Skan     standard format 1 (equivalent to a FSTMD insn and unused pad word).
8516169689Skan     We really need some way of representing the whole block so that the
8517169689Skan     unwinder can figure it out at runtime.  */
8518169689Skan  par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count));
8519169689Skan  dwarf = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (count + 1));
8520169689Skan
8521169689Skan  reg = gen_rtx_REG (DFmode, base_reg);
8522169689Skan  base_reg += 2;
8523169689Skan
8524169689Skan  XVECEXP (par, 0, 0)
8525169689Skan    = gen_rtx_SET (VOIDmode,
8526169689Skan		   gen_frame_mem (BLKmode,
8527169689Skan				  gen_rtx_PRE_DEC (BLKmode,
8528169689Skan						   stack_pointer_rtx)),
8529169689Skan		   gen_rtx_UNSPEC (BLKmode,
8530169689Skan				   gen_rtvec (1, reg),
8531169689Skan				   UNSPEC_PUSH_MULT));
8532169689Skan
8533169689Skan  tmp = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
8534169689Skan		     plus_constant (stack_pointer_rtx, -(count * 8 + 4)));
8535169689Skan  RTX_FRAME_RELATED_P (tmp) = 1;
8536169689Skan  XVECEXP (dwarf, 0, 0) = tmp;
8537169689Skan
8538169689Skan  tmp = gen_rtx_SET (VOIDmode,
8539169689Skan		     gen_frame_mem (DFmode, stack_pointer_rtx),
8540169689Skan		     reg);
8541169689Skan  RTX_FRAME_RELATED_P (tmp) = 1;
8542169689Skan  XVECEXP (dwarf, 0, 1) = tmp;
8543169689Skan
8544169689Skan  for (i = 1; i < count; i++)
8545169689Skan    {
8546169689Skan      reg = gen_rtx_REG (DFmode, base_reg);
8547169689Skan      base_reg += 2;
8548169689Skan      XVECEXP (par, 0, i) = gen_rtx_USE (VOIDmode, reg);
8549169689Skan
8550169689Skan      tmp = gen_rtx_SET (VOIDmode,
8551169689Skan			 gen_frame_mem (DFmode,
8552169689Skan					plus_constant (stack_pointer_rtx,
8553169689Skan						       i * 8)),
8554169689Skan			 reg);
8555169689Skan      RTX_FRAME_RELATED_P (tmp) = 1;
8556169689Skan      XVECEXP (dwarf, 0, i + 1) = tmp;
8557169689Skan    }
8558169689Skan
8559169689Skan  par = emit_insn (par);
8560169689Skan  REG_NOTES (par) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
8561169689Skan				       REG_NOTES (par));
8562169689Skan  RTX_FRAME_RELATED_P (par) = 1;
8563169689Skan
8564169689Skan  return count * 8 + 4;
8565169689Skan}
8566169689Skan
8567169689Skan
856890075Sobrien/* Output a 'call' insn.  */
856990075Sobrienconst char *
8570132718Skanoutput_call (rtx *operands)
857190075Sobrien{
8572169689Skan  gcc_assert (!arm_arch5); /* Patterns should call blx <reg> directly.  */
8573169689Skan
857490075Sobrien  /* Handle calls to lr using ip (which may be clobbered in subr anyway).  */
857590075Sobrien  if (REGNO (operands[0]) == LR_REGNUM)
857690075Sobrien    {
857790075Sobrien      operands[0] = gen_rtx_REG (SImode, IP_REGNUM);
857890075Sobrien      output_asm_insn ("mov%?\t%0, %|lr", operands);
857990075Sobrien    }
8580169689Skan
858190075Sobrien  output_asm_insn ("mov%?\t%|lr, %|pc", operands);
8582169689Skan
8583169689Skan  if (TARGET_INTERWORK || arm_arch4t)
858490075Sobrien    output_asm_insn ("bx%?\t%0", operands);
858590075Sobrien  else
858690075Sobrien    output_asm_insn ("mov%?\t%|pc, %0", operands);
8587169689Skan
858890075Sobrien  return "";
858990075Sobrien}
859090075Sobrien
859190075Sobrien/* Output a 'call' insn that is a reference in memory.  */
859290075Sobrienconst char *
8593132718Skanoutput_call_mem (rtx *operands)
859490075Sobrien{
8595169689Skan  if (TARGET_INTERWORK && !arm_arch5)
859690075Sobrien    {
859790075Sobrien      output_asm_insn ("ldr%?\t%|ip, %0", operands);
859890075Sobrien      output_asm_insn ("mov%?\t%|lr, %|pc", operands);
859990075Sobrien      output_asm_insn ("bx%?\t%|ip", operands);
860090075Sobrien    }
8601117395Skan  else if (regno_use_in (LR_REGNUM, operands[0]))
8602117395Skan    {
8603117395Skan      /* LR is used in the memory address.  We load the address in the
8604117395Skan	 first instruction.  It's safe to use IP as the target of the
8605117395Skan	 load since the call will kill it anyway.  */
8606117395Skan      output_asm_insn ("ldr%?\t%|ip, %0", operands);
8607169689Skan      if (arm_arch5)
8608169689Skan	output_asm_insn ("blx%?\t%|ip", operands);
8609169689Skan      else
8610169689Skan	{
8611169689Skan	  output_asm_insn ("mov%?\t%|lr, %|pc", operands);
8612169689Skan	  if (arm_arch4t)
8613169689Skan	    output_asm_insn ("bx%?\t%|ip", operands);
8614169689Skan	  else
8615169689Skan	    output_asm_insn ("mov%?\t%|pc, %|ip", operands);
8616169689Skan	}
8617117395Skan    }
861890075Sobrien  else
861990075Sobrien    {
862090075Sobrien      output_asm_insn ("mov%?\t%|lr, %|pc", operands);
862190075Sobrien      output_asm_insn ("ldr%?\t%|pc, %0", operands);
862290075Sobrien    }
862390075Sobrien
862490075Sobrien  return "";
862590075Sobrien}
862690075Sobrien
8627169689Skan
8628132718Skan/* Output a move from arm registers to an fpa registers.
8629132718Skan   OPERANDS[0] is an fpa register.
863090075Sobrien   OPERANDS[1] is the first registers of an arm register pair.  */
863190075Sobrienconst char *
8632132718Skanoutput_mov_long_double_fpa_from_arm (rtx *operands)
863390075Sobrien{
863490075Sobrien  int arm_reg0 = REGNO (operands[1]);
863590075Sobrien  rtx ops[3];
863690075Sobrien
8637169689Skan  gcc_assert (arm_reg0 != IP_REGNUM);
863890075Sobrien
863990075Sobrien  ops[0] = gen_rtx_REG (SImode, arm_reg0);
864090075Sobrien  ops[1] = gen_rtx_REG (SImode, 1 + arm_reg0);
864190075Sobrien  ops[2] = gen_rtx_REG (SImode, 2 + arm_reg0);
8642169689Skan
864390075Sobrien  output_asm_insn ("stm%?fd\t%|sp!, {%0, %1, %2}", ops);
864490075Sobrien  output_asm_insn ("ldf%?e\t%0, [%|sp], #12", operands);
8645169689Skan
864690075Sobrien  return "";
864790075Sobrien}
864890075Sobrien
8649132718Skan/* Output a move from an fpa register to arm registers.
865090075Sobrien   OPERANDS[0] is the first registers of an arm register pair.
8651132718Skan   OPERANDS[1] is an fpa register.  */
865290075Sobrienconst char *
8653132718Skanoutput_mov_long_double_arm_from_fpa (rtx *operands)
865490075Sobrien{
865590075Sobrien  int arm_reg0 = REGNO (operands[0]);
865690075Sobrien  rtx ops[3];
865790075Sobrien
8658169689Skan  gcc_assert (arm_reg0 != IP_REGNUM);
865990075Sobrien
866090075Sobrien  ops[0] = gen_rtx_REG (SImode, arm_reg0);
866190075Sobrien  ops[1] = gen_rtx_REG (SImode, 1 + arm_reg0);
866290075Sobrien  ops[2] = gen_rtx_REG (SImode, 2 + arm_reg0);
866390075Sobrien
866490075Sobrien  output_asm_insn ("stf%?e\t%1, [%|sp, #-12]!", operands);
866590075Sobrien  output_asm_insn ("ldm%?fd\t%|sp!, {%0, %1, %2}", ops);
866690075Sobrien  return "";
866790075Sobrien}
866890075Sobrien
866990075Sobrien/* Output a move from arm registers to arm registers of a long double
867090075Sobrien   OPERANDS[0] is the destination.
867190075Sobrien   OPERANDS[1] is the source.  */
867290075Sobrienconst char *
8673132718Skanoutput_mov_long_double_arm_from_arm (rtx *operands)
867490075Sobrien{
867590075Sobrien  /* We have to be careful here because the two might overlap.  */
867690075Sobrien  int dest_start = REGNO (operands[0]);
867790075Sobrien  int src_start = REGNO (operands[1]);
867890075Sobrien  rtx ops[2];
867990075Sobrien  int i;
868090075Sobrien
868190075Sobrien  if (dest_start < src_start)
868290075Sobrien    {
868390075Sobrien      for (i = 0; i < 3; i++)
868490075Sobrien	{
868590075Sobrien	  ops[0] = gen_rtx_REG (SImode, dest_start + i);
868690075Sobrien	  ops[1] = gen_rtx_REG (SImode, src_start + i);
868790075Sobrien	  output_asm_insn ("mov%?\t%0, %1", ops);
868890075Sobrien	}
868990075Sobrien    }
869090075Sobrien  else
869190075Sobrien    {
869290075Sobrien      for (i = 2; i >= 0; i--)
869390075Sobrien	{
869490075Sobrien	  ops[0] = gen_rtx_REG (SImode, dest_start + i);
869590075Sobrien	  ops[1] = gen_rtx_REG (SImode, src_start + i);
869690075Sobrien	  output_asm_insn ("mov%?\t%0, %1", ops);
869790075Sobrien	}
869890075Sobrien    }
869990075Sobrien
870090075Sobrien  return "";
870190075Sobrien}
870290075Sobrien
870390075Sobrien
8704132718Skan/* Output a move from arm registers to an fpa registers.
8705132718Skan   OPERANDS[0] is an fpa register.
870690075Sobrien   OPERANDS[1] is the first registers of an arm register pair.  */
870790075Sobrienconst char *
8708132718Skanoutput_mov_double_fpa_from_arm (rtx *operands)
870990075Sobrien{
871090075Sobrien  int arm_reg0 = REGNO (operands[1]);
871190075Sobrien  rtx ops[2];
871290075Sobrien
8713169689Skan  gcc_assert (arm_reg0 != IP_REGNUM);
8714169689Skan
871590075Sobrien  ops[0] = gen_rtx_REG (SImode, arm_reg0);
871690075Sobrien  ops[1] = gen_rtx_REG (SImode, 1 + arm_reg0);
871790075Sobrien  output_asm_insn ("stm%?fd\t%|sp!, {%0, %1}", ops);
871890075Sobrien  output_asm_insn ("ldf%?d\t%0, [%|sp], #8", operands);
871990075Sobrien  return "";
872090075Sobrien}
872190075Sobrien
8722132718Skan/* Output a move from an fpa register to arm registers.
872390075Sobrien   OPERANDS[0] is the first registers of an arm register pair.
8724132718Skan   OPERANDS[1] is an fpa register.  */
872590075Sobrienconst char *
8726132718Skanoutput_mov_double_arm_from_fpa (rtx *operands)
872790075Sobrien{
872890075Sobrien  int arm_reg0 = REGNO (operands[0]);
872990075Sobrien  rtx ops[2];
873090075Sobrien
8731169689Skan  gcc_assert (arm_reg0 != IP_REGNUM);
873290075Sobrien
873390075Sobrien  ops[0] = gen_rtx_REG (SImode, arm_reg0);
873490075Sobrien  ops[1] = gen_rtx_REG (SImode, 1 + arm_reg0);
873590075Sobrien  output_asm_insn ("stf%?d\t%1, [%|sp, #-8]!", operands);
873690075Sobrien  output_asm_insn ("ldm%?fd\t%|sp!, {%0, %1}", ops);
873790075Sobrien  return "";
873890075Sobrien}
873990075Sobrien
874090075Sobrien/* Output a move between double words.
874190075Sobrien   It must be REG<-REG, REG<-CONST_DOUBLE, REG<-CONST_INT, REG<-MEM
874290075Sobrien   or MEM<-REG and all MEMs must be offsettable addresses.  */
874390075Sobrienconst char *
8744132718Skanoutput_move_double (rtx *operands)
874590075Sobrien{
874690075Sobrien  enum rtx_code code0 = GET_CODE (operands[0]);
874790075Sobrien  enum rtx_code code1 = GET_CODE (operands[1]);
874890075Sobrien  rtx otherops[3];
874990075Sobrien
875090075Sobrien  if (code0 == REG)
875190075Sobrien    {
875290075Sobrien      int reg0 = REGNO (operands[0]);
875390075Sobrien
875490075Sobrien      otherops[0] = gen_rtx_REG (SImode, 1 + reg0);
875590075Sobrien
8756169689Skan      gcc_assert (code1 == MEM);  /* Constraints should ensure this.  */
8757169689Skan
8758169689Skan      switch (GET_CODE (XEXP (operands[1], 0)))
8759132718Skan	{
8760169689Skan	case REG:
8761169689Skan	  output_asm_insn ("ldm%?ia\t%m1, %M0", operands);
8762169689Skan	  break;
8763132718Skan
8764169689Skan	case PRE_INC:
8765169689Skan	  gcc_assert (TARGET_LDRD);
8766169689Skan	  output_asm_insn ("ldr%?d\t%0, [%m1, #8]!", operands);
8767169689Skan	  break;
8768132718Skan
8769169689Skan	case PRE_DEC:
8770169689Skan	  output_asm_insn ("ldm%?db\t%m1!, %M0", operands);
8771169689Skan	  break;
8772132718Skan
8773169689Skan	case POST_INC:
8774169689Skan	  output_asm_insn ("ldm%?ia\t%m1!, %M0", operands);
8775169689Skan	  break;
8776132718Skan
8777169689Skan	case POST_DEC:
8778169689Skan	  gcc_assert (TARGET_LDRD);
8779169689Skan	  output_asm_insn ("ldr%?d\t%0, [%m1], #-8", operands);
8780169689Skan	  break;
8781132718Skan
8782169689Skan	case PRE_MODIFY:
8783169689Skan	case POST_MODIFY:
8784169689Skan	  otherops[0] = operands[0];
8785169689Skan	  otherops[1] = XEXP (XEXP (XEXP (operands[1], 0), 1), 0);
8786169689Skan	  otherops[2] = XEXP (XEXP (XEXP (operands[1], 0), 1), 1);
8787132718Skan
8788169689Skan	  if (GET_CODE (XEXP (operands[1], 0)) == PRE_MODIFY)
8789169689Skan	    {
8790169689Skan	      if (reg_overlap_mentioned_p (otherops[0], otherops[2]))
8791132718Skan		{
8792169689Skan		  /* Registers overlap so split out the increment.  */
8793169689Skan		  output_asm_insn ("add%?\t%1, %1, %2", otherops);
8794169689Skan		  output_asm_insn ("ldr%?d\t%0, [%1] @split", otherops);
8795132718Skan		}
8796132718Skan	      else
8797132718Skan		{
8798169689Skan		  /* IWMMXT allows offsets larger than ldrd can handle,
8799169689Skan		     fix these up with a pair of ldr.  */
8800169689Skan		  if (GET_CODE (otherops[2]) == CONST_INT
8801169689Skan		      && (INTVAL(otherops[2]) <= -256
8802169689Skan			  || INTVAL(otherops[2]) >= 256))
8803169689Skan		    {
8804169689Skan		      output_asm_insn ("ldr%?\t%0, [%1, %2]!", otherops);
8805169689Skan		      otherops[0] = gen_rtx_REG (SImode, 1 + reg0);
8806169689Skan		      output_asm_insn ("ldr%?\t%0, [%1, #4]", otherops);
8807169689Skan		    }
8808169689Skan		  else
8809169689Skan		    output_asm_insn ("ldr%?d\t%0, [%1, %2]!", otherops);
8810132718Skan		}
8811169689Skan	    }
8812169689Skan	  else
8813169689Skan	    {
8814169689Skan	      /* IWMMXT allows offsets larger than ldrd can handle,
8815169689Skan		 fix these up with a pair of ldr.  */
8816169689Skan	      if (GET_CODE (otherops[2]) == CONST_INT
8817169689Skan		  && (INTVAL(otherops[2]) <= -256
8818169689Skan		      || INTVAL(otherops[2]) >= 256))
8819132718Skan		{
8820169689Skan		  otherops[0] = gen_rtx_REG (SImode, 1 + reg0);
8821169689Skan		  output_asm_insn ("ldr%?\t%0, [%1, #4]", otherops);
8822169689Skan		  otherops[0] = operands[0];
8823169689Skan		  output_asm_insn ("ldr%?\t%0, [%1], %2", otherops);
8824132718Skan		}
8825132718Skan	      else
8826169689Skan		/* We only allow constant increments, so this is safe.  */
8827169689Skan		output_asm_insn ("ldr%?d\t%0, [%1], %2", otherops);
8828132718Skan	    }
8829169689Skan	  break;
883090075Sobrien
8831169689Skan	case LABEL_REF:
8832169689Skan	case CONST:
8833169689Skan	  output_asm_insn ("adr%?\t%0, %1", operands);
8834169689Skan	  output_asm_insn ("ldm%?ia\t%0, %M0", operands);
8835169689Skan	  break;
8836169689Skan
8837169689Skan	default:
8838169689Skan	  if (arm_add_operand (XEXP (XEXP (operands[1], 0), 1),
8839169689Skan			       GET_MODE (XEXP (XEXP (operands[1], 0), 1))))
884090075Sobrien	    {
8841169689Skan	      otherops[0] = operands[0];
8842169689Skan	      otherops[1] = XEXP (XEXP (operands[1], 0), 0);
8843169689Skan	      otherops[2] = XEXP (XEXP (operands[1], 0), 1);
884490075Sobrien
8845169689Skan	      if (GET_CODE (XEXP (operands[1], 0)) == PLUS)
884690075Sobrien		{
8847169689Skan		  if (GET_CODE (otherops[2]) == CONST_INT)
884890075Sobrien		    {
8849169689Skan		      switch ((int) INTVAL (otherops[2]))
885090075Sobrien			{
8851169689Skan			case -8:
8852169689Skan			  output_asm_insn ("ldm%?db\t%1, %M0", otherops);
8853169689Skan			  return "";
8854169689Skan			case -4:
8855169689Skan			  output_asm_insn ("ldm%?da\t%1, %M0", otherops);
8856169689Skan			  return "";
8857169689Skan			case 4:
8858169689Skan			  output_asm_insn ("ldm%?ib\t%1, %M0", otherops);
8859169689Skan			  return "";
886090075Sobrien			}
8861169689Skan		    }
8862169689Skan		  if (TARGET_LDRD
8863169689Skan		      && (GET_CODE (otherops[2]) == REG
8864169689Skan			  || (GET_CODE (otherops[2]) == CONST_INT
8865169689Skan			      && INTVAL (otherops[2]) > -256
8866169689Skan			      && INTVAL (otherops[2]) < 256)))
8867169689Skan		    {
8868169689Skan		      if (reg_overlap_mentioned_p (otherops[0],
8869169689Skan						   otherops[2]))
8870169689Skan			{
8871169689Skan			  /* Swap base and index registers over to
8872169689Skan			     avoid a conflict.  */
8873169689Skan			  otherops[1] = XEXP (XEXP (operands[1], 0), 1);
8874169689Skan			  otherops[2] = XEXP (XEXP (operands[1], 0), 0);
8875169689Skan			}
8876169689Skan		      /* If both registers conflict, it will usually
8877169689Skan			 have been fixed by a splitter.  */
8878169689Skan		      if (reg_overlap_mentioned_p (otherops[0], otherops[2]))
8879169689Skan			{
8880169689Skan			  output_asm_insn ("add%?\t%1, %1, %2", otherops);
8881169689Skan			  output_asm_insn ("ldr%?d\t%0, [%1]",
8882169689Skan					   otherops);
8883169689Skan			}
888490075Sobrien		      else
8885169689Skan			output_asm_insn ("ldr%?d\t%0, [%1, %2]", otherops);
8886169689Skan		      return "";
888790075Sobrien		    }
8888169689Skan
8889169689Skan		  if (GET_CODE (otherops[2]) == CONST_INT)
889090075Sobrien		    {
8891169689Skan		      if (!(const_ok_for_arm (INTVAL (otherops[2]))))
8892169689Skan			output_asm_insn ("sub%?\t%0, %1, #%n2", otherops);
8893169689Skan		      else
8894169689Skan			output_asm_insn ("add%?\t%0, %1, %2", otherops);
889590075Sobrien		    }
889690075Sobrien		  else
8897169689Skan		    output_asm_insn ("add%?\t%0, %1, %2", otherops);
889890075Sobrien		}
8899169689Skan	      else
8900169689Skan		output_asm_insn ("sub%?\t%0, %1, %2", otherops);
8901169689Skan
8902169689Skan	      return "ldm%?ia\t%0, %M0";
890390075Sobrien	    }
8904169689Skan	  else
8905169689Skan	    {
8906169689Skan	      otherops[1] = adjust_address (operands[1], SImode, 4);
8907169689Skan	      /* Take care of overlapping base/data reg.  */
8908169689Skan	      if (reg_mentioned_p (operands[0], operands[1]))
8909169689Skan		{
8910169689Skan		  output_asm_insn ("ldr%?\t%0, %1", otherops);
8911169689Skan		  output_asm_insn ("ldr%?\t%0, %1", operands);
8912169689Skan		}
8913169689Skan	      else
8914169689Skan		{
8915169689Skan		  output_asm_insn ("ldr%?\t%0, %1", operands);
8916169689Skan		  output_asm_insn ("ldr%?\t%0, %1", otherops);
8917169689Skan		}
8918169689Skan	    }
891990075Sobrien	}
892090075Sobrien    }
8921169689Skan  else
892290075Sobrien    {
8923169689Skan      /* Constraints should ensure this.  */
8924169689Skan      gcc_assert (code0 == MEM && code1 == REG);
8925169689Skan      gcc_assert (REGNO (operands[1]) != IP_REGNUM);
892690075Sobrien
892790075Sobrien      switch (GET_CODE (XEXP (operands[0], 0)))
892890075Sobrien        {
892990075Sobrien	case REG:
893090075Sobrien	  output_asm_insn ("stm%?ia\t%m0, %M1", operands);
893190075Sobrien	  break;
893290075Sobrien
893390075Sobrien        case PRE_INC:
8934169689Skan	  gcc_assert (TARGET_LDRD);
8935169689Skan	  output_asm_insn ("str%?d\t%1, [%m0, #8]!", operands);
893690075Sobrien	  break;
893790075Sobrien
893890075Sobrien        case PRE_DEC:
893990075Sobrien	  output_asm_insn ("stm%?db\t%m0!, %M1", operands);
894090075Sobrien	  break;
894190075Sobrien
894290075Sobrien        case POST_INC:
894390075Sobrien	  output_asm_insn ("stm%?ia\t%m0!, %M1", operands);
894490075Sobrien	  break;
894590075Sobrien
894690075Sobrien        case POST_DEC:
8947169689Skan	  gcc_assert (TARGET_LDRD);
8948169689Skan	  output_asm_insn ("str%?d\t%1, [%m0], #-8", operands);
894990075Sobrien	  break;
895090075Sobrien
8951169689Skan	case PRE_MODIFY:
8952169689Skan	case POST_MODIFY:
8953169689Skan	  otherops[0] = operands[1];
8954169689Skan	  otherops[1] = XEXP (XEXP (XEXP (operands[0], 0), 1), 0);
8955169689Skan	  otherops[2] = XEXP (XEXP (XEXP (operands[0], 0), 1), 1);
8956169689Skan
8957169689Skan	  /* IWMMXT allows offsets larger than ldrd can handle,
8958169689Skan	     fix these up with a pair of ldr.  */
8959169689Skan	  if (GET_CODE (otherops[2]) == CONST_INT
8960169689Skan	      && (INTVAL(otherops[2]) <= -256
8961169689Skan		  || INTVAL(otherops[2]) >= 256))
8962169689Skan	    {
8963169689Skan	      rtx reg1;
8964169689Skan	      reg1 = gen_rtx_REG (SImode, 1 + REGNO (operands[1]));
8965169689Skan	      if (GET_CODE (XEXP (operands[0], 0)) == PRE_MODIFY)
8966169689Skan		{
8967169689Skan		  output_asm_insn ("ldr%?\t%0, [%1, %2]!", otherops);
8968169689Skan		  otherops[0] = reg1;
8969169689Skan		  output_asm_insn ("ldr%?\t%0, [%1, #4]", otherops);
8970169689Skan		}
8971169689Skan	      else
8972169689Skan		{
8973169689Skan		  otherops[0] = reg1;
8974169689Skan		  output_asm_insn ("ldr%?\t%0, [%1, #4]", otherops);
8975169689Skan		  otherops[0] = operands[1];
8976169689Skan		  output_asm_insn ("ldr%?\t%0, [%1], %2", otherops);
8977169689Skan		}
8978169689Skan	    }
8979169689Skan	  else if (GET_CODE (XEXP (operands[0], 0)) == PRE_MODIFY)
8980169689Skan	    output_asm_insn ("str%?d\t%0, [%1, %2]!", otherops);
8981169689Skan	  else
8982169689Skan	    output_asm_insn ("str%?d\t%0, [%1], %2", otherops);
8983169689Skan	  break;
8984169689Skan
898590075Sobrien	case PLUS:
8986169689Skan	  otherops[2] = XEXP (XEXP (operands[0], 0), 1);
8987169689Skan	  if (GET_CODE (otherops[2]) == CONST_INT)
898890075Sobrien	    {
8989132718Skan	      switch ((int) INTVAL (XEXP (XEXP (operands[0], 0), 1)))
899090075Sobrien		{
899190075Sobrien		case -8:
899290075Sobrien		  output_asm_insn ("stm%?db\t%m0, %M1", operands);
899390075Sobrien		  return "";
899490075Sobrien
899590075Sobrien		case -4:
899690075Sobrien		  output_asm_insn ("stm%?da\t%m0, %M1", operands);
899790075Sobrien		  return "";
899890075Sobrien
899990075Sobrien		case 4:
900090075Sobrien		  output_asm_insn ("stm%?ib\t%m0, %M1", operands);
900190075Sobrien		  return "";
900290075Sobrien		}
900390075Sobrien	    }
9004169689Skan	  if (TARGET_LDRD
9005169689Skan	      && (GET_CODE (otherops[2]) == REG
9006169689Skan		  || (GET_CODE (otherops[2]) == CONST_INT
9007169689Skan		      && INTVAL (otherops[2]) > -256
9008169689Skan		      && INTVAL (otherops[2]) < 256)))
9009169689Skan	    {
9010169689Skan	      otherops[0] = operands[1];
9011169689Skan	      otherops[1] = XEXP (XEXP (operands[0], 0), 0);
9012169689Skan	      output_asm_insn ("str%?d\t%0, [%1, %2]", otherops);
9013169689Skan	      return "";
9014169689Skan	    }
901590075Sobrien	  /* Fall through */
901690075Sobrien
901790075Sobrien        default:
9018117395Skan	  otherops[0] = adjust_address (operands[0], SImode, 4);
901990075Sobrien	  otherops[1] = gen_rtx_REG (SImode, 1 + REGNO (operands[1]));
902090075Sobrien	  output_asm_insn ("str%?\t%1, %0", operands);
902190075Sobrien	  output_asm_insn ("str%?\t%1, %0", otherops);
902290075Sobrien	}
902390075Sobrien    }
902490075Sobrien
902590075Sobrien  return "";
902690075Sobrien}
902790075Sobrien
902890075Sobrien/* Output an ADD r, s, #n where n may be too big for one instruction.
902990075Sobrien   If adding zero to one register, output nothing.  */
903090075Sobrienconst char *
9031132718Skanoutput_add_immediate (rtx *operands)
903290075Sobrien{
903390075Sobrien  HOST_WIDE_INT n = INTVAL (operands[2]);
903490075Sobrien
903590075Sobrien  if (n != 0 || REGNO (operands[0]) != REGNO (operands[1]))
903690075Sobrien    {
903790075Sobrien      if (n < 0)
903890075Sobrien	output_multi_immediate (operands,
903990075Sobrien				"sub%?\t%0, %1, %2", "sub%?\t%0, %0, %2", 2,
904090075Sobrien				-n);
904190075Sobrien      else
904290075Sobrien	output_multi_immediate (operands,
904390075Sobrien				"add%?\t%0, %1, %2", "add%?\t%0, %0, %2", 2,
904490075Sobrien				n);
904590075Sobrien    }
904690075Sobrien
904790075Sobrien  return "";
904890075Sobrien}
904990075Sobrien
905090075Sobrien/* Output a multiple immediate operation.
905190075Sobrien   OPERANDS is the vector of operands referred to in the output patterns.
905290075Sobrien   INSTR1 is the output pattern to use for the first constant.
905390075Sobrien   INSTR2 is the output pattern to use for subsequent constants.
905490075Sobrien   IMMED_OP is the index of the constant slot in OPERANDS.
905590075Sobrien   N is the constant value.  */
905690075Sobrienstatic const char *
9057132718Skanoutput_multi_immediate (rtx *operands, const char *instr1, const char *instr2,
9058132718Skan			int immed_op, HOST_WIDE_INT n)
905990075Sobrien{
906090075Sobrien#if HOST_BITS_PER_WIDE_INT > 32
906190075Sobrien  n &= 0xffffffff;
906290075Sobrien#endif
906390075Sobrien
906490075Sobrien  if (n == 0)
906590075Sobrien    {
906690075Sobrien      /* Quick and easy output.  */
906790075Sobrien      operands[immed_op] = const0_rtx;
906890075Sobrien      output_asm_insn (instr1, operands);
906990075Sobrien    }
907090075Sobrien  else
907190075Sobrien    {
907290075Sobrien      int i;
907390075Sobrien      const char * instr = instr1;
907490075Sobrien
907590075Sobrien      /* Note that n is never zero here (which would give no output).  */
907690075Sobrien      for (i = 0; i < 32; i += 2)
907790075Sobrien	{
907890075Sobrien	  if (n & (3 << i))
907990075Sobrien	    {
908090075Sobrien	      operands[immed_op] = GEN_INT (n & (255 << i));
908190075Sobrien	      output_asm_insn (instr, operands);
908290075Sobrien	      instr = instr2;
908390075Sobrien	      i += 6;
908490075Sobrien	    }
908590075Sobrien	}
908690075Sobrien    }
9087169689Skan
908890075Sobrien  return "";
908990075Sobrien}
909090075Sobrien
909190075Sobrien/* Return the appropriate ARM instruction for the operation code.
909290075Sobrien   The returned result should not be overwritten.  OP is the rtx of the
909390075Sobrien   operation.  SHIFT_FIRST_ARG is TRUE if the first argument of the operator
909490075Sobrien   was shifted.  */
909590075Sobrienconst char *
9096132718Skanarithmetic_instr (rtx op, int shift_first_arg)
909790075Sobrien{
909890075Sobrien  switch (GET_CODE (op))
909990075Sobrien    {
910090075Sobrien    case PLUS:
910190075Sobrien      return "add";
910290075Sobrien
910390075Sobrien    case MINUS:
910490075Sobrien      return shift_first_arg ? "rsb" : "sub";
910590075Sobrien
910690075Sobrien    case IOR:
910790075Sobrien      return "orr";
910890075Sobrien
910990075Sobrien    case XOR:
911090075Sobrien      return "eor";
911190075Sobrien
911290075Sobrien    case AND:
911390075Sobrien      return "and";
911490075Sobrien
911590075Sobrien    default:
9116169689Skan      gcc_unreachable ();
911790075Sobrien    }
911890075Sobrien}
911990075Sobrien
912090075Sobrien/* Ensure valid constant shifts and return the appropriate shift mnemonic
912190075Sobrien   for the operation code.  The returned result should not be overwritten.
912290075Sobrien   OP is the rtx code of the shift.
912390075Sobrien   On exit, *AMOUNTP will be -1 if the shift is by a register, or a constant
912490075Sobrien   shift.  */
912590075Sobrienstatic const char *
9126132718Skanshift_op (rtx op, HOST_WIDE_INT *amountp)
912790075Sobrien{
912890075Sobrien  const char * mnem;
912990075Sobrien  enum rtx_code code = GET_CODE (op);
913090075Sobrien
9131169689Skan  switch (GET_CODE (XEXP (op, 1)))
9132169689Skan    {
9133169689Skan    case REG:
9134169689Skan    case SUBREG:
9135169689Skan      *amountp = -1;
9136169689Skan      break;
913790075Sobrien
9138169689Skan    case CONST_INT:
9139169689Skan      *amountp = INTVAL (XEXP (op, 1));
9140169689Skan      break;
9141169689Skan
9142169689Skan    default:
9143169689Skan      gcc_unreachable ();
9144169689Skan    }
9145169689Skan
914690075Sobrien  switch (code)
914790075Sobrien    {
914890075Sobrien    case ASHIFT:
914990075Sobrien      mnem = "asl";
915090075Sobrien      break;
915190075Sobrien
915290075Sobrien    case ASHIFTRT:
915390075Sobrien      mnem = "asr";
915490075Sobrien      break;
915590075Sobrien
915690075Sobrien    case LSHIFTRT:
915790075Sobrien      mnem = "lsr";
915890075Sobrien      break;
915990075Sobrien
9160169689Skan    case ROTATE:
9161169689Skan      gcc_assert (*amountp != -1);
9162169689Skan      *amountp = 32 - *amountp;
9163169689Skan
9164169689Skan      /* Fall through.  */
9165169689Skan
916690075Sobrien    case ROTATERT:
916790075Sobrien      mnem = "ror";
916890075Sobrien      break;
916990075Sobrien
917090075Sobrien    case MULT:
917190075Sobrien      /* We never have to worry about the amount being other than a
917290075Sobrien	 power of 2, since this case can never be reloaded from a reg.  */
9173169689Skan      gcc_assert (*amountp != -1);
9174169689Skan      *amountp = int_log2 (*amountp);
917590075Sobrien      return "asl";
917690075Sobrien
917790075Sobrien    default:
9178169689Skan      gcc_unreachable ();
917990075Sobrien    }
918090075Sobrien
918190075Sobrien  if (*amountp != -1)
918290075Sobrien    {
918390075Sobrien      /* This is not 100% correct, but follows from the desire to merge
918490075Sobrien	 multiplication by a power of 2 with the recognizer for a
918590075Sobrien	 shift.  >=32 is not a valid shift for "asl", so we must try and
918690075Sobrien	 output a shift that produces the correct arithmetical result.
918790075Sobrien	 Using lsr #32 is identical except for the fact that the carry bit
9188169689Skan	 is not set correctly if we set the flags; but we never use the
918990075Sobrien	 carry bit from such an operation, so we can ignore that.  */
919090075Sobrien      if (code == ROTATERT)
919190075Sobrien	/* Rotate is just modulo 32.  */
919290075Sobrien	*amountp &= 31;
919390075Sobrien      else if (*amountp != (*amountp & 31))
919490075Sobrien	{
919590075Sobrien	  if (code == ASHIFT)
919690075Sobrien	    mnem = "lsr";
919790075Sobrien	  *amountp = 32;
919890075Sobrien	}
919990075Sobrien
920090075Sobrien      /* Shifts of 0 are no-ops.  */
920190075Sobrien      if (*amountp == 0)
920290075Sobrien	return NULL;
9203169689Skan    }
920490075Sobrien
920590075Sobrien  return mnem;
920690075Sobrien}
920790075Sobrien
920890075Sobrien/* Obtain the shift from the POWER of two.  */
920990075Sobrien
921090075Sobrienstatic HOST_WIDE_INT
9211132718Skanint_log2 (HOST_WIDE_INT power)
921290075Sobrien{
921390075Sobrien  HOST_WIDE_INT shift = 0;
921490075Sobrien
921590075Sobrien  while ((((HOST_WIDE_INT) 1 << shift) & power) == 0)
921690075Sobrien    {
9217169689Skan      gcc_assert (shift <= 31);
9218132718Skan      shift++;
921990075Sobrien    }
922090075Sobrien
922190075Sobrien  return shift;
922290075Sobrien}
922390075Sobrien
9224169689Skan/* Output a .ascii pseudo-op, keeping track of lengths.  This is
9225169689Skan   because /bin/as is horribly restrictive.  The judgement about
9226169689Skan   whether or not each character is 'printable' (and can be output as
9227169689Skan   is) or not (and must be printed with an octal escape) must be made
9228169689Skan   with reference to the *host* character set -- the situation is
9229169689Skan   similar to that discussed in the comments above pp_c_char in
9230169689Skan   c-pretty-print.c.  */
9231169689Skan
923290075Sobrien#define MAX_ASCII_LEN 51
923390075Sobrien
923490075Sobrienvoid
9235132718Skanoutput_ascii_pseudo_op (FILE *stream, const unsigned char *p, int len)
923690075Sobrien{
923790075Sobrien  int i;
923890075Sobrien  int len_so_far = 0;
923990075Sobrien
924090075Sobrien  fputs ("\t.ascii\t\"", stream);
9241169689Skan
924290075Sobrien  for (i = 0; i < len; i++)
924390075Sobrien    {
924490075Sobrien      int c = p[i];
924590075Sobrien
924690075Sobrien      if (len_so_far >= MAX_ASCII_LEN)
924790075Sobrien	{
924890075Sobrien	  fputs ("\"\n\t.ascii\t\"", stream);
924990075Sobrien	  len_so_far = 0;
925090075Sobrien	}
925190075Sobrien
9252169689Skan      if (ISPRINT (c))
925390075Sobrien	{
9254169689Skan	  if (c == '\\' || c == '\"')
925590075Sobrien	    {
9256169689Skan	      putc ('\\', stream);
925790075Sobrien	      len_so_far++;
925890075Sobrien	    }
9259169689Skan	  putc (c, stream);
9260169689Skan	  len_so_far++;
926190075Sobrien	}
9262169689Skan      else
9263169689Skan	{
9264169689Skan	  fprintf (stream, "\\%03o", c);
9265169689Skan	  len_so_far += 4;
9266169689Skan	}
926790075Sobrien    }
926890075Sobrien
926990075Sobrien  fputs ("\"\n", stream);
927090075Sobrien}
927190075Sobrien
9272169689Skan/* Compute the register save mask for registers 0 through 12
9273169689Skan   inclusive.  This code is used by arm_compute_save_reg_mask.  */
9274169689Skan
927590075Sobrienstatic unsigned long
9276132718Skanarm_compute_save_reg0_reg12_mask (void)
927790075Sobrien{
927890075Sobrien  unsigned long func_type = arm_current_func_type ();
9279169689Skan  unsigned long save_reg_mask = 0;
928090075Sobrien  unsigned int reg;
928190075Sobrien
928290075Sobrien  if (IS_INTERRUPT (func_type))
928390075Sobrien    {
928490075Sobrien      unsigned int max_reg;
928590075Sobrien      /* Interrupt functions must not corrupt any registers,
928690075Sobrien	 even call clobbered ones.  If this is a leaf function
928790075Sobrien	 we can just examine the registers used by the RTL, but
928890075Sobrien	 otherwise we have to assume that whatever function is
928990075Sobrien	 called might clobber anything, and so we have to save
929090075Sobrien	 all the call-clobbered registers as well.  */
929190075Sobrien      if (ARM_FUNC_TYPE (func_type) == ARM_FT_FIQ)
929290075Sobrien	/* FIQ handlers have registers r8 - r12 banked, so
929390075Sobrien	   we only need to check r0 - r7, Normal ISRs only
929490075Sobrien	   bank r14 and r15, so we must check up to r12.
929590075Sobrien	   r13 is the stack pointer which is always preserved,
929690075Sobrien	   so we do not need to consider it here.  */
929790075Sobrien	max_reg = 7;
929890075Sobrien      else
929990075Sobrien	max_reg = 12;
9300169689Skan
930190075Sobrien      for (reg = 0; reg <= max_reg; reg++)
930290075Sobrien	if (regs_ever_live[reg]
930390075Sobrien	    || (! current_function_is_leaf && call_used_regs [reg]))
930490075Sobrien	  save_reg_mask |= (1 << reg);
9305169689Skan
9306169689Skan      /* Also save the pic base register if necessary.  */
9307169689Skan      if (flag_pic
9308169689Skan	  && !TARGET_SINGLE_PIC_BASE
9309169689Skan	  && arm_pic_register != INVALID_REGNUM
9310169689Skan	  && current_function_uses_pic_offset_table)
9311169689Skan	save_reg_mask |= 1 << PIC_OFFSET_TABLE_REGNUM;
931290075Sobrien    }
931390075Sobrien  else
931490075Sobrien    {
931590075Sobrien      /* In the normal case we only need to save those registers
931690075Sobrien	 which are call saved and which are used by this function.  */
931790075Sobrien      for (reg = 0; reg <= 10; reg++)
931890075Sobrien	if (regs_ever_live[reg] && ! call_used_regs [reg])
931990075Sobrien	  save_reg_mask |= (1 << reg);
932090075Sobrien
932190075Sobrien      /* Handle the frame pointer as a special case.  */
932290075Sobrien      if (! TARGET_APCS_FRAME
932390075Sobrien	  && ! frame_pointer_needed
932490075Sobrien	  && regs_ever_live[HARD_FRAME_POINTER_REGNUM]
932590075Sobrien	  && ! call_used_regs[HARD_FRAME_POINTER_REGNUM])
932690075Sobrien	save_reg_mask |= 1 << HARD_FRAME_POINTER_REGNUM;
932790075Sobrien
932890075Sobrien      /* If we aren't loading the PIC register,
932990075Sobrien	 don't stack it even though it may be live.  */
933090075Sobrien      if (flag_pic
9331169689Skan	  && !TARGET_SINGLE_PIC_BASE
9332169689Skan	  && arm_pic_register != INVALID_REGNUM
9333169689Skan	  && (regs_ever_live[PIC_OFFSET_TABLE_REGNUM]
9334169689Skan	      || current_function_uses_pic_offset_table))
933590075Sobrien	save_reg_mask |= 1 << PIC_OFFSET_TABLE_REGNUM;
933690075Sobrien    }
933790075Sobrien
9338169689Skan  /* Save registers so the exception handler can modify them.  */
9339169689Skan  if (current_function_calls_eh_return)
9340169689Skan    {
9341169689Skan      unsigned int i;
9342169689Skan
9343169689Skan      for (i = 0; ; i++)
9344169689Skan	{
9345169689Skan	  reg = EH_RETURN_DATA_REGNO (i);
9346169689Skan	  if (reg == INVALID_REGNUM)
9347169689Skan	    break;
9348169689Skan	  save_reg_mask |= 1 << reg;
9349169689Skan	}
9350169689Skan    }
9351169689Skan
935290075Sobrien  return save_reg_mask;
935390075Sobrien}
935490075Sobrien
935590075Sobrien/* Compute a bit mask of which registers need to be
935690075Sobrien   saved on the stack for the current function.  */
935790075Sobrien
935890075Sobrienstatic unsigned long
9359132718Skanarm_compute_save_reg_mask (void)
936090075Sobrien{
936190075Sobrien  unsigned int save_reg_mask = 0;
936290075Sobrien  unsigned long func_type = arm_current_func_type ();
936390075Sobrien
936490075Sobrien  if (IS_NAKED (func_type))
936590075Sobrien    /* This should never really happen.  */
936690075Sobrien    return 0;
936790075Sobrien
936890075Sobrien  /* If we are creating a stack frame, then we must save the frame pointer,
936990075Sobrien     IP (which will hold the old stack pointer), LR and the PC.  */
937090075Sobrien  if (frame_pointer_needed)
937190075Sobrien    save_reg_mask |=
937290075Sobrien      (1 << ARM_HARD_FRAME_POINTER_REGNUM)
937390075Sobrien      | (1 << IP_REGNUM)
937490075Sobrien      | (1 << LR_REGNUM)
937590075Sobrien      | (1 << PC_REGNUM);
937690075Sobrien
937790075Sobrien  /* Volatile functions do not return, so there
937890075Sobrien     is no need to save any other registers.  */
937990075Sobrien  if (IS_VOLATILE (func_type))
938090075Sobrien    return save_reg_mask;
938190075Sobrien
938290075Sobrien  save_reg_mask |= arm_compute_save_reg0_reg12_mask ();
938390075Sobrien
938490075Sobrien  /* Decide if we need to save the link register.
938590075Sobrien     Interrupt routines have their own banked link register,
938690075Sobrien     so they never need to save it.
938796263Sobrien     Otherwise if we do not use the link register we do not need to save
938890075Sobrien     it.  If we are pushing other registers onto the stack however, we
938990075Sobrien     can save an instruction in the epilogue by pushing the link register
939090075Sobrien     now and then popping it back into the PC.  This incurs extra memory
9391132718Skan     accesses though, so we only do it when optimizing for size, and only
939290075Sobrien     if we know that we will not need a fancy return sequence.  */
939396263Sobrien  if (regs_ever_live [LR_REGNUM]
939490075Sobrien	  || (save_reg_mask
939590075Sobrien	      && optimize_size
9396169689Skan	      && ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL
9397169689Skan	      && !current_function_calls_eh_return))
939890075Sobrien    save_reg_mask |= 1 << LR_REGNUM;
939990075Sobrien
940090075Sobrien  if (cfun->machine->lr_save_eliminated)
940190075Sobrien    save_reg_mask &= ~ (1 << LR_REGNUM);
940290075Sobrien
9403132718Skan  if (TARGET_REALLY_IWMMXT
9404132718Skan      && ((bit_count (save_reg_mask)
9405132718Skan	   + ARM_NUM_INTS (current_function_pretend_args_size)) % 2) != 0)
9406132718Skan    {
9407132718Skan      unsigned int reg;
9408132718Skan
9409132718Skan      /* The total number of registers that are going to be pushed
9410132718Skan	 onto the stack is odd.  We need to ensure that the stack
9411132718Skan	 is 64-bit aligned before we start to save iWMMXt registers,
9412132718Skan	 and also before we start to create locals.  (A local variable
9413132718Skan	 might be a double or long long which we will load/store using
9414132718Skan	 an iWMMXt instruction).  Therefore we need to push another
9415132718Skan	 ARM register, so that the stack will be 64-bit aligned.  We
9416132718Skan	 try to avoid using the arg registers (r0 -r3) as they might be
9417132718Skan	 used to pass values in a tail call.  */
9418132718Skan      for (reg = 4; reg <= 12; reg++)
9419132718Skan	if ((save_reg_mask & (1 << reg)) == 0)
9420132718Skan	  break;
9421132718Skan
9422132718Skan      if (reg <= 12)
9423132718Skan	save_reg_mask |= (1 << reg);
9424132718Skan      else
9425132718Skan	{
9426132718Skan	  cfun->machine->sibcall_blocked = 1;
9427132718Skan	  save_reg_mask |= (1 << 3);
9428132718Skan	}
9429132718Skan    }
9430132718Skan
943190075Sobrien  return save_reg_mask;
943290075Sobrien}
943390075Sobrien
9434169689Skan
9435169689Skan/* Compute a bit mask of which registers need to be
9436169689Skan   saved on the stack for the current function.  */
9437169689Skanstatic unsigned long
9438169689Skanthumb_compute_save_reg_mask (void)
9439169689Skan{
9440169689Skan  unsigned long mask;
9441169689Skan  unsigned reg;
9442169689Skan
9443169689Skan  mask = 0;
9444169689Skan  for (reg = 0; reg < 12; reg ++)
9445169689Skan    if (regs_ever_live[reg] && !call_used_regs[reg])
9446169689Skan      mask |= 1 << reg;
9447169689Skan
9448169689Skan  if (flag_pic
9449169689Skan      && !TARGET_SINGLE_PIC_BASE
9450169689Skan      && arm_pic_register != INVALID_REGNUM
9451169689Skan      && current_function_uses_pic_offset_table)
9452169689Skan    mask |= 1 << PIC_OFFSET_TABLE_REGNUM;
9453169689Skan
9454169689Skan  /* See if we might need r11 for calls to _interwork_r11_call_via_rN().  */
9455169689Skan  if (!frame_pointer_needed && CALLER_INTERWORKING_SLOT_SIZE > 0)
9456169689Skan    mask |= 1 << ARM_HARD_FRAME_POINTER_REGNUM;
9457169689Skan
9458169689Skan  /* LR will also be pushed if any lo regs are pushed.  */
9459169689Skan  if (mask & 0xff || thumb_force_lr_save ())
9460169689Skan    mask |= (1 << LR_REGNUM);
9461169689Skan
9462169689Skan  /* Make sure we have a low work register if we need one.
9463169689Skan     We will need one if we are going to push a high register,
9464169689Skan     but we are not currently intending to push a low register.  */
9465169689Skan  if ((mask & 0xff) == 0
9466169689Skan      && ((mask & 0x0f00) || TARGET_BACKTRACE))
9467169689Skan    {
9468169689Skan      /* Use thumb_find_work_register to choose which register
9469169689Skan	 we will use.  If the register is live then we will
9470169689Skan	 have to push it.  Use LAST_LO_REGNUM as our fallback
9471169689Skan	 choice for the register to select.  */
9472169689Skan      reg = thumb_find_work_register (1 << LAST_LO_REGNUM);
9473169689Skan
9474169689Skan      if (! call_used_regs[reg])
9475169689Skan	mask |= 1 << reg;
9476169689Skan    }
9477169689Skan
9478169689Skan  return mask;
9479169689Skan}
9480169689Skan
9481169689Skan
9482169689Skan/* Return the number of bytes required to save VFP registers.  */
9483169689Skanstatic int
9484169689Skanarm_get_vfp_saved_size (void)
9485169689Skan{
9486169689Skan  unsigned int regno;
9487169689Skan  int count;
9488169689Skan  int saved;
9489169689Skan
9490169689Skan  saved = 0;
9491169689Skan  /* Space for saved VFP registers.  */
9492169689Skan  if (TARGET_HARD_FLOAT && TARGET_VFP)
9493169689Skan    {
9494169689Skan      count = 0;
9495169689Skan      for (regno = FIRST_VFP_REGNUM;
9496169689Skan	   regno < LAST_VFP_REGNUM;
9497169689Skan	   regno += 2)
9498169689Skan	{
9499169689Skan	  if ((!regs_ever_live[regno] || call_used_regs[regno])
9500169689Skan	      && (!regs_ever_live[regno + 1] || call_used_regs[regno + 1]))
9501169689Skan	    {
9502169689Skan	      if (count > 0)
9503169689Skan		{
9504169689Skan		  /* Workaround ARM10 VFPr1 bug.  */
9505169689Skan		  if (count == 2 && !arm_arch6)
9506169689Skan		    count++;
9507169689Skan		  saved += count * 8 + 4;
9508169689Skan		}
9509169689Skan	      count = 0;
9510169689Skan	    }
9511169689Skan	  else
9512169689Skan	    count++;
9513169689Skan	}
9514169689Skan      if (count > 0)
9515169689Skan	{
9516169689Skan	  if (count == 2 && !arm_arch6)
9517169689Skan	    count++;
9518169689Skan	  saved += count * 8 + 4;
9519169689Skan	}
9520169689Skan    }
9521169689Skan  return saved;
9522169689Skan}
9523169689Skan
9524169689Skan
9525132718Skan/* Generate a function exit sequence.  If REALLY_RETURN is false, then do
952690075Sobrien   everything bar the final return instruction.  */
952790075Sobrienconst char *
9528132718Skanoutput_return_instruction (rtx operand, int really_return, int reverse)
952990075Sobrien{
953090075Sobrien  char conditional[10];
953190075Sobrien  char instr[100];
9532169689Skan  unsigned reg;
953390075Sobrien  unsigned long live_regs_mask;
953490075Sobrien  unsigned long func_type;
9535169689Skan  arm_stack_offsets *offsets;
9536117395Skan
953790075Sobrien  func_type = arm_current_func_type ();
953890075Sobrien
953990075Sobrien  if (IS_NAKED (func_type))
954090075Sobrien    return "";
954190075Sobrien
954290075Sobrien  if (IS_VOLATILE (func_type) && TARGET_ABORT_NORETURN)
954390075Sobrien    {
9544132718Skan      /* If this function was declared non-returning, and we have
9545132718Skan	 found a tail call, then we have to trust that the called
9546132718Skan	 function won't return.  */
954790075Sobrien      if (really_return)
954890075Sobrien	{
954990075Sobrien	  rtx ops[2];
9550169689Skan
955190075Sobrien	  /* Otherwise, trap an attempted return by aborting.  */
955290075Sobrien	  ops[0] = operand;
9553169689Skan	  ops[1] = gen_rtx_SYMBOL_REF (Pmode, NEED_PLT_RELOC ? "abort(PLT)"
955490075Sobrien				       : "abort");
955590075Sobrien	  assemble_external_libcall (ops[1]);
955690075Sobrien	  output_asm_insn (reverse ? "bl%D0\t%a1" : "bl%d0\t%a1", ops);
955790075Sobrien	}
9558169689Skan
955990075Sobrien      return "";
956090075Sobrien    }
956190075Sobrien
9562169689Skan  gcc_assert (!current_function_calls_alloca || really_return);
956390075Sobrien
956490075Sobrien  sprintf (conditional, "%%?%%%c0", reverse ? 'D' : 'd');
956590075Sobrien
956690075Sobrien  return_used_this_function = 1;
956790075Sobrien
956890075Sobrien  live_regs_mask = arm_compute_save_reg_mask ();
956990075Sobrien
957096263Sobrien  if (live_regs_mask)
957190075Sobrien    {
957296263Sobrien      const char * return_reg;
957396263Sobrien
9574169689Skan      /* If we do not have any special requirements for function exit
9575169689Skan	 (e.g. interworking, or ISR) then we can load the return address
957696263Sobrien	 directly into the PC.  Otherwise we must load it into LR.  */
957796263Sobrien      if (really_return
957896263Sobrien	  && ! TARGET_INTERWORK)
957996263Sobrien	return_reg = reg_names[PC_REGNUM];
958090075Sobrien      else
958196263Sobrien	return_reg = reg_names[LR_REGNUM];
958296263Sobrien
958390075Sobrien      if ((live_regs_mask & (1 << IP_REGNUM)) == (1 << IP_REGNUM))
9584132718Skan	{
9585132718Skan	  /* There are three possible reasons for the IP register
9586132718Skan	     being saved.  1) a stack frame was created, in which case
9587132718Skan	     IP contains the old stack pointer, or 2) an ISR routine
9588132718Skan	     corrupted it, or 3) it was saved to align the stack on
9589132718Skan	     iWMMXt.  In case 1, restore IP into SP, otherwise just
9590132718Skan	     restore IP.  */
9591132718Skan	  if (frame_pointer_needed)
9592132718Skan	    {
9593132718Skan	      live_regs_mask &= ~ (1 << IP_REGNUM);
9594132718Skan	      live_regs_mask |=   (1 << SP_REGNUM);
9595132718Skan	    }
9596132718Skan	  else
9597169689Skan	    gcc_assert (IS_INTERRUPT (func_type) || TARGET_REALLY_IWMMXT);
9598132718Skan	}
959990075Sobrien
960096263Sobrien      /* On some ARM architectures it is faster to use LDR rather than
960196263Sobrien	 LDM to load a single register.  On other architectures, the
960296263Sobrien	 cost is the same.  In 26 bit mode, or for exception handlers,
960396263Sobrien	 we have to use LDM to load the PC so that the CPSR is also
960496263Sobrien	 restored.  */
960596263Sobrien      for (reg = 0; reg <= LAST_ARM_REGNUM; reg++)
9606169689Skan	if (live_regs_mask == (1U << reg))
9607169689Skan	  break;
9608169689Skan
960996263Sobrien      if (reg <= LAST_ARM_REGNUM
961096263Sobrien	  && (reg != LR_REGNUM
9611169689Skan	      || ! really_return
9612169689Skan	      || ! IS_INTERRUPT (func_type)))
961396263Sobrien	{
9614169689Skan	  sprintf (instr, "ldr%s\t%%|%s, [%%|sp], #4", conditional,
961596263Sobrien		   (reg == LR_REGNUM) ? return_reg : reg_names[reg]);
961696263Sobrien	}
961790075Sobrien      else
961890075Sobrien	{
961996263Sobrien	  char *p;
962096263Sobrien	  int first = 1;
962190075Sobrien
9622132718Skan	  /* Generate the load multiple instruction to restore the
9623132718Skan	     registers.  Note we can get here, even if
9624132718Skan	     frame_pointer_needed is true, but only if sp already
9625132718Skan	     points to the base of the saved core registers.  */
9626132718Skan	  if (live_regs_mask & (1 << SP_REGNUM))
9627132718Skan	    {
9628169689Skan	      unsigned HOST_WIDE_INT stack_adjust;
9629132718Skan
9630169689Skan	      offsets = arm_get_frame_offsets ();
9631169689Skan	      stack_adjust = offsets->outgoing_args - offsets->saved_regs;
9632169689Skan	      gcc_assert (stack_adjust == 0 || stack_adjust == 4);
9633169689Skan
9634132718Skan	      if (stack_adjust && arm_arch5)
9635132718Skan		sprintf (instr, "ldm%sib\t%%|sp, {", conditional);
9636132718Skan	      else
9637132718Skan		{
9638169689Skan		  /* If we can't use ldmib (SA110 bug),
9639169689Skan		     then try to pop r3 instead.  */
9640132718Skan		  if (stack_adjust)
9641132718Skan		    live_regs_mask |= 1 << 3;
9642132718Skan		  sprintf (instr, "ldm%sfd\t%%|sp, {", conditional);
9643132718Skan		}
9644132718Skan	    }
964590075Sobrien	  else
964696263Sobrien	    sprintf (instr, "ldm%sfd\t%%|sp!, {", conditional);
964790075Sobrien
964896263Sobrien	  p = instr + strlen (instr);
964990075Sobrien
965096263Sobrien	  for (reg = 0; reg <= SP_REGNUM; reg++)
965196263Sobrien	    if (live_regs_mask & (1 << reg))
965296263Sobrien	      {
965396263Sobrien		int l = strlen (reg_names[reg]);
965490075Sobrien
965596263Sobrien		if (first)
965696263Sobrien		  first = 0;
965796263Sobrien		else
965896263Sobrien		  {
965996263Sobrien		    memcpy (p, ", ", 2);
966096263Sobrien		    p += 2;
966196263Sobrien		  }
966290075Sobrien
966396263Sobrien		memcpy (p, "%|", 2);
966496263Sobrien		memcpy (p + 2, reg_names[reg], l);
966596263Sobrien		p += l + 2;
966696263Sobrien	      }
9667169689Skan
966896263Sobrien	  if (live_regs_mask & (1 << LR_REGNUM))
966996263Sobrien	    {
9670132718Skan	      sprintf (p, "%s%%|%s}", first ? "" : ", ", return_reg);
9671169689Skan	      /* If returning from an interrupt, restore the CPSR.  */
9672169689Skan	      if (IS_INTERRUPT (func_type))
9673132718Skan		strcat (p, "^");
967490075Sobrien	    }
967596263Sobrien	  else
967696263Sobrien	    strcpy (p, "}");
967790075Sobrien	}
967896263Sobrien
967996263Sobrien      output_asm_insn (instr, & operand);
968096263Sobrien
968196263Sobrien      /* See if we need to generate an extra instruction to
968296263Sobrien	 perform the actual function return.  */
968396263Sobrien      if (really_return
968496263Sobrien	  && func_type != ARM_FT_INTERWORKED
968596263Sobrien	  && (live_regs_mask & (1 << LR_REGNUM)) != 0)
968696263Sobrien	{
968796263Sobrien	  /* The return has already been handled
968896263Sobrien	     by loading the LR into the PC.  */
968996263Sobrien	  really_return = 0;
969096263Sobrien	}
969190075Sobrien    }
9692117395Skan
969396263Sobrien  if (really_return)
969490075Sobrien    {
969590075Sobrien      switch ((int) ARM_FUNC_TYPE (func_type))
969690075Sobrien	{
969790075Sobrien	case ARM_FT_ISR:
969890075Sobrien	case ARM_FT_FIQ:
969990075Sobrien	  sprintf (instr, "sub%ss\t%%|pc, %%|lr, #4", conditional);
970090075Sobrien	  break;
970190075Sobrien
970290075Sobrien	case ARM_FT_INTERWORKED:
970390075Sobrien	  sprintf (instr, "bx%s\t%%|lr", conditional);
970490075Sobrien	  break;
970590075Sobrien
970690075Sobrien	case ARM_FT_EXCEPTION:
970790075Sobrien	  sprintf (instr, "mov%ss\t%%|pc, %%|lr", conditional);
970890075Sobrien	  break;
970990075Sobrien
971090075Sobrien	default:
9711169689Skan	  /* Use bx if it's available.  */
9712169689Skan	  if (arm_arch5 || arm_arch4t)
9713169689Skan	    sprintf (instr, "bx%s\t%%|lr", conditional);
971496263Sobrien	  else
9715169689Skan	    sprintf (instr, "mov%s\t%%|pc, %%|lr", conditional);
971690075Sobrien	  break;
971790075Sobrien	}
971896263Sobrien
971996263Sobrien      output_asm_insn (instr, & operand);
972090075Sobrien    }
972190075Sobrien
972290075Sobrien  return "";
972390075Sobrien}
972490075Sobrien
972590075Sobrien/* Write the function name into the code section, directly preceding
972690075Sobrien   the function prologue.
972790075Sobrien
972890075Sobrien   Code will be output similar to this:
972990075Sobrien     t0
973090075Sobrien	 .ascii "arm_poke_function_name", 0
973190075Sobrien	 .align
973290075Sobrien     t1
973390075Sobrien	 .word 0xff000000 + (t1 - t0)
973490075Sobrien     arm_poke_function_name
973590075Sobrien	 mov     ip, sp
973690075Sobrien	 stmfd   sp!, {fp, ip, lr, pc}
973790075Sobrien	 sub     fp, ip, #4
973890075Sobrien
973990075Sobrien   When performing a stack backtrace, code can inspect the value
974090075Sobrien   of 'pc' stored at 'fp' + 0.  If the trace function then looks
974190075Sobrien   at location pc - 12 and the top 8 bits are set, then we know
974290075Sobrien   that there is a function name embedded immediately preceding this
974390075Sobrien   location and has length ((pc[-3]) & 0xff000000).
974490075Sobrien
974590075Sobrien   We assume that pc is declared as a pointer to an unsigned long.
974690075Sobrien
974790075Sobrien   It is of no benefit to output the function name if we are assembling
974890075Sobrien   a leaf function.  These function types will not contain a stack
974990075Sobrien   backtrace structure, therefore it is not possible to determine the
975090075Sobrien   function name.  */
975190075Sobrienvoid
9752132718Skanarm_poke_function_name (FILE *stream, const char *name)
975390075Sobrien{
975490075Sobrien  unsigned long alignlength;
975590075Sobrien  unsigned long length;
975690075Sobrien  rtx           x;
975790075Sobrien
975890075Sobrien  length      = strlen (name) + 1;
9759132718Skan  alignlength = ROUND_UP_WORD (length);
9760169689Skan
976190075Sobrien  ASM_OUTPUT_ASCII (stream, name, length);
976290075Sobrien  ASM_OUTPUT_ALIGN (stream, 2);
976390075Sobrien  x = GEN_INT ((unsigned HOST_WIDE_INT) 0xff000000 + alignlength);
976490075Sobrien  assemble_aligned_integer (UNITS_PER_WORD, x);
976590075Sobrien}
976690075Sobrien
976790075Sobrien/* Place some comments into the assembler stream
976890075Sobrien   describing the current function.  */
976990075Sobrienstatic void
9770132718Skanarm_output_function_prologue (FILE *f, HOST_WIDE_INT frame_size)
977190075Sobrien{
977290075Sobrien  unsigned long func_type;
977390075Sobrien
977490075Sobrien  if (!TARGET_ARM)
977590075Sobrien    {
977690075Sobrien      thumb_output_function_prologue (f, frame_size);
977790075Sobrien      return;
977890075Sobrien    }
9779169689Skan
978090075Sobrien  /* Sanity check.  */
9781169689Skan  gcc_assert (!arm_ccfsm_state && !arm_target_insn);
978290075Sobrien
978390075Sobrien  func_type = arm_current_func_type ();
9784169689Skan
978590075Sobrien  switch ((int) ARM_FUNC_TYPE (func_type))
978690075Sobrien    {
978790075Sobrien    default:
978890075Sobrien    case ARM_FT_NORMAL:
978990075Sobrien      break;
979090075Sobrien    case ARM_FT_INTERWORKED:
979190075Sobrien      asm_fprintf (f, "\t%@ Function supports interworking.\n");
979290075Sobrien      break;
979390075Sobrien    case ARM_FT_ISR:
979490075Sobrien      asm_fprintf (f, "\t%@ Interrupt Service Routine.\n");
979590075Sobrien      break;
979690075Sobrien    case ARM_FT_FIQ:
979790075Sobrien      asm_fprintf (f, "\t%@ Fast Interrupt Service Routine.\n");
979890075Sobrien      break;
979990075Sobrien    case ARM_FT_EXCEPTION:
980090075Sobrien      asm_fprintf (f, "\t%@ ARM Exception Handler.\n");
980190075Sobrien      break;
980290075Sobrien    }
9803169689Skan
980490075Sobrien  if (IS_NAKED (func_type))
980590075Sobrien    asm_fprintf (f, "\t%@ Naked Function: prologue and epilogue provided by programmer.\n");
980690075Sobrien
980790075Sobrien  if (IS_VOLATILE (func_type))
980890075Sobrien    asm_fprintf (f, "\t%@ Volatile: function does not return.\n");
980990075Sobrien
981090075Sobrien  if (IS_NESTED (func_type))
981190075Sobrien    asm_fprintf (f, "\t%@ Nested: function declared inside another function.\n");
9812169689Skan
9813132718Skan  asm_fprintf (f, "\t%@ args = %d, pretend = %d, frame = %wd\n",
981490075Sobrien	       current_function_args_size,
981590075Sobrien	       current_function_pretend_args_size, frame_size);
981690075Sobrien
981796263Sobrien  asm_fprintf (f, "\t%@ frame_needed = %d, uses_anonymous_args = %d\n",
981890075Sobrien	       frame_pointer_needed,
981996263Sobrien	       cfun->machine->uses_anonymous_args);
982090075Sobrien
982190075Sobrien  if (cfun->machine->lr_save_eliminated)
982290075Sobrien    asm_fprintf (f, "\t%@ link register save eliminated.\n");
982390075Sobrien
9824169689Skan  if (current_function_calls_eh_return)
9825169689Skan    asm_fprintf (f, "\t@ Calls __builtin_eh_return.\n");
9826169689Skan
982790075Sobrien#ifdef AOF_ASSEMBLER
982890075Sobrien  if (flag_pic)
982990075Sobrien    asm_fprintf (f, "\tmov\t%r, %r\n", IP_REGNUM, PIC_OFFSET_TABLE_REGNUM);
983090075Sobrien#endif
983190075Sobrien
9832169689Skan  return_used_this_function = 0;
983390075Sobrien}
983490075Sobrien
983590075Sobrienconst char *
9836132718Skanarm_output_epilogue (rtx sibling)
983790075Sobrien{
983890075Sobrien  int reg;
983990075Sobrien  unsigned long saved_regs_mask;
984090075Sobrien  unsigned long func_type;
9841169689Skan  /* Floats_offset is the offset from the "virtual" frame.  In an APCS
984296263Sobrien     frame that is $fp + 4 for a non-variadic function.  */
984396263Sobrien  int floats_offset = 0;
984490075Sobrien  rtx operands[3];
984590075Sobrien  FILE * f = asm_out_file;
9846132718Skan  unsigned int lrm_count = 0;
9847132718Skan  int really_return = (sibling == NULL);
9848169689Skan  int start_reg;
9849169689Skan  arm_stack_offsets *offsets;
985090075Sobrien
985190075Sobrien  /* If we have already generated the return instruction
985290075Sobrien     then it is futile to generate anything else.  */
9853132718Skan  if (use_return_insn (FALSE, sibling) && return_used_this_function)
985490075Sobrien    return "";
985590075Sobrien
985690075Sobrien  func_type = arm_current_func_type ();
985790075Sobrien
985890075Sobrien  if (IS_NAKED (func_type))
985990075Sobrien    /* Naked functions don't have epilogues.  */
986090075Sobrien    return "";
986190075Sobrien
986290075Sobrien  if (IS_VOLATILE (func_type) && TARGET_ABORT_NORETURN)
986390075Sobrien    {
986490075Sobrien      rtx op;
9865169689Skan
986690075Sobrien      /* A volatile function should never return.  Call abort.  */
986790075Sobrien      op = gen_rtx_SYMBOL_REF (Pmode, NEED_PLT_RELOC ? "abort(PLT)" : "abort");
986890075Sobrien      assemble_external_libcall (op);
986990075Sobrien      output_asm_insn ("bl\t%a0", &op);
9870169689Skan
987190075Sobrien      return "";
987290075Sobrien    }
987390075Sobrien
9874169689Skan  /* If we are throwing an exception, then we really must be doing a
9875169689Skan     return, so we can't tail-call.  */
9876169689Skan  gcc_assert (!current_function_calls_eh_return || really_return);
9877169689Skan
9878169689Skan  offsets = arm_get_frame_offsets ();
987990075Sobrien  saved_regs_mask = arm_compute_save_reg_mask ();
9880132718Skan
9881132718Skan  if (TARGET_IWMMXT)
9882132718Skan    lrm_count = bit_count (saved_regs_mask);
9883132718Skan
9884169689Skan  floats_offset = offsets->saved_args;
988590075Sobrien  /* Compute how far away the floats will be.  */
9886132718Skan  for (reg = 0; reg <= LAST_ARM_REGNUM; reg++)
988790075Sobrien    if (saved_regs_mask & (1 << reg))
988890075Sobrien      floats_offset += 4;
9889169689Skan
989090075Sobrien  if (frame_pointer_needed)
989190075Sobrien    {
9892169689Skan      /* This variable is for the Virtual Frame Pointer, not VFP regs.  */
9893169689Skan      int vfp_offset = offsets->frame;
989496263Sobrien
9895132718Skan      if (arm_fpu_arch == FPUTYPE_FPA_EMU2)
989690075Sobrien	{
9897169689Skan	  for (reg = LAST_FPA_REGNUM; reg >= FIRST_FPA_REGNUM; reg--)
989890075Sobrien	    if (regs_ever_live[reg] && !call_used_regs[reg])
989990075Sobrien	      {
990090075Sobrien		floats_offset += 12;
9901169689Skan		asm_fprintf (f, "\tldfe\t%r, [%r, #-%d]\n",
990296263Sobrien			     reg, FP_REGNUM, floats_offset - vfp_offset);
990390075Sobrien	      }
990490075Sobrien	}
990590075Sobrien      else
990690075Sobrien	{
9907169689Skan	  start_reg = LAST_FPA_REGNUM;
990890075Sobrien
9909169689Skan	  for (reg = LAST_FPA_REGNUM; reg >= FIRST_FPA_REGNUM; reg--)
991090075Sobrien	    {
991190075Sobrien	      if (regs_ever_live[reg] && !call_used_regs[reg])
991290075Sobrien		{
991390075Sobrien		  floats_offset += 12;
9914169689Skan
991590075Sobrien		  /* We can't unstack more than four registers at once.  */
991690075Sobrien		  if (start_reg - reg == 3)
991790075Sobrien		    {
991890075Sobrien		      asm_fprintf (f, "\tlfm\t%r, 4, [%r, #-%d]\n",
991996263Sobrien			           reg, FP_REGNUM, floats_offset - vfp_offset);
992090075Sobrien		      start_reg = reg - 1;
992190075Sobrien		    }
992290075Sobrien		}
992390075Sobrien	      else
992490075Sobrien		{
992590075Sobrien		  if (reg != start_reg)
992690075Sobrien		    asm_fprintf (f, "\tlfm\t%r, %d, [%r, #-%d]\n",
992790075Sobrien				 reg + 1, start_reg - reg,
992896263Sobrien				 FP_REGNUM, floats_offset - vfp_offset);
992990075Sobrien		  start_reg = reg - 1;
993090075Sobrien		}
993190075Sobrien	    }
993290075Sobrien
993390075Sobrien	  /* Just in case the last register checked also needs unstacking.  */
993490075Sobrien	  if (reg != start_reg)
993590075Sobrien	    asm_fprintf (f, "\tlfm\t%r, %d, [%r, #-%d]\n",
993690075Sobrien			 reg + 1, start_reg - reg,
993796263Sobrien			 FP_REGNUM, floats_offset - vfp_offset);
993890075Sobrien	}
993990075Sobrien
9940169689Skan      if (TARGET_HARD_FLOAT && TARGET_VFP)
9941169689Skan	{
9942169689Skan	  int saved_size;
9943169689Skan
9944169689Skan	  /* The fldmx insn does not have base+offset addressing modes,
9945169689Skan	     so we use IP to hold the address.  */
9946169689Skan	  saved_size = arm_get_vfp_saved_size ();
9947169689Skan
9948169689Skan	  if (saved_size > 0)
9949169689Skan	    {
9950169689Skan	      floats_offset += saved_size;
9951169689Skan	      asm_fprintf (f, "\tsub\t%r, %r, #%d\n", IP_REGNUM,
9952169689Skan			   FP_REGNUM, floats_offset - vfp_offset);
9953169689Skan	    }
9954169689Skan	  start_reg = FIRST_VFP_REGNUM;
9955169689Skan	  for (reg = FIRST_VFP_REGNUM; reg < LAST_VFP_REGNUM; reg += 2)
9956169689Skan	    {
9957169689Skan	      if ((!regs_ever_live[reg] || call_used_regs[reg])
9958169689Skan		  && (!regs_ever_live[reg + 1] || call_used_regs[reg + 1]))
9959169689Skan		{
9960169689Skan		  if (start_reg != reg)
9961169689Skan		    arm_output_fldmx (f, IP_REGNUM,
9962169689Skan				      (start_reg - FIRST_VFP_REGNUM) / 2,
9963169689Skan				      (reg - start_reg) / 2);
9964169689Skan		  start_reg = reg + 2;
9965169689Skan		}
9966169689Skan	    }
9967169689Skan	  if (start_reg != reg)
9968169689Skan	    arm_output_fldmx (f, IP_REGNUM,
9969169689Skan			      (start_reg - FIRST_VFP_REGNUM) / 2,
9970169689Skan			      (reg - start_reg) / 2);
9971169689Skan	}
9972169689Skan
9973132718Skan      if (TARGET_IWMMXT)
9974132718Skan	{
9975132718Skan	  /* The frame pointer is guaranteed to be non-double-word aligned.
9976132718Skan	     This is because it is set to (old_stack_pointer - 4) and the
9977132718Skan	     old_stack_pointer was double word aligned.  Thus the offset to
9978132718Skan	     the iWMMXt registers to be loaded must also be non-double-word
9979132718Skan	     sized, so that the resultant address *is* double-word aligned.
9980132718Skan	     We can ignore floats_offset since that was already included in
9981132718Skan	     the live_regs_mask.  */
9982132718Skan	  lrm_count += (lrm_count % 2 ? 2 : 1);
9983169689Skan
9984169689Skan	  for (reg = LAST_IWMMXT_REGNUM; reg >= FIRST_IWMMXT_REGNUM; reg--)
9985132718Skan	    if (regs_ever_live[reg] && !call_used_regs[reg])
9986132718Skan	      {
9987169689Skan		asm_fprintf (f, "\twldrd\t%r, [%r, #-%d]\n",
9988132718Skan			     reg, FP_REGNUM, lrm_count * 4);
9989169689Skan		lrm_count += 2;
9990132718Skan	      }
9991132718Skan	}
9992132718Skan
999390075Sobrien      /* saved_regs_mask should contain the IP, which at the time of stack
999490075Sobrien	 frame generation actually contains the old stack pointer.  So a
999590075Sobrien	 quick way to unwind the stack is just pop the IP register directly
999690075Sobrien	 into the stack pointer.  */
9997169689Skan      gcc_assert (saved_regs_mask & (1 << IP_REGNUM));
999890075Sobrien      saved_regs_mask &= ~ (1 << IP_REGNUM);
999990075Sobrien      saved_regs_mask |=   (1 << SP_REGNUM);
1000090075Sobrien
1000190075Sobrien      /* There are two registers left in saved_regs_mask - LR and PC.  We
1000290075Sobrien	 only need to restore the LR register (the return address), but to
1000390075Sobrien	 save time we can load it directly into the PC, unless we need a
1000490075Sobrien	 special function exit sequence, or we are not really returning.  */
10005169689Skan      if (really_return
10006169689Skan	  && ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL
10007169689Skan	  && !current_function_calls_eh_return)
1000890075Sobrien	/* Delete the LR from the register mask, so that the LR on
1000990075Sobrien	   the stack is loaded into the PC in the register mask.  */
1001090075Sobrien	saved_regs_mask &= ~ (1 << LR_REGNUM);
1001190075Sobrien      else
1001290075Sobrien	saved_regs_mask &= ~ (1 << PC_REGNUM);
1001390075Sobrien
10014132718Skan      /* We must use SP as the base register, because SP is one of the
10015132718Skan         registers being restored.  If an interrupt or page fault
10016132718Skan         happens in the ldm instruction, the SP might or might not
10017132718Skan         have been restored.  That would be bad, as then SP will no
10018132718Skan         longer indicate the safe area of stack, and we can get stack
10019132718Skan         corruption.  Using SP as the base register means that it will
10020132718Skan         be reset correctly to the original value, should an interrupt
10021132718Skan         occur.  If the stack pointer already points at the right
10022132718Skan         place, then omit the subtraction.  */
10023169689Skan      if (offsets->outgoing_args != (1 + (int) bit_count (saved_regs_mask))
10024132718Skan	  || current_function_calls_alloca)
10025132718Skan	asm_fprintf (f, "\tsub\t%r, %r, #%d\n", SP_REGNUM, FP_REGNUM,
10026132718Skan		     4 * bit_count (saved_regs_mask));
10027132718Skan      print_multi_reg (f, "ldmfd\t%r", SP_REGNUM, saved_regs_mask);
10028132718Skan
1002990075Sobrien      if (IS_INTERRUPT (func_type))
1003090075Sobrien	/* Interrupt handlers will have pushed the
1003190075Sobrien	   IP onto the stack, so restore it now.  */
10032117395Skan	print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM, 1 << IP_REGNUM);
1003390075Sobrien    }
1003490075Sobrien  else
1003590075Sobrien    {
1003690075Sobrien      /* Restore stack pointer if necessary.  */
10037169689Skan      if (offsets->outgoing_args != offsets->saved_regs)
1003890075Sobrien	{
1003990075Sobrien	  operands[0] = operands[1] = stack_pointer_rtx;
10040169689Skan	  operands[2] = GEN_INT (offsets->outgoing_args - offsets->saved_regs);
1004190075Sobrien	  output_add_immediate (operands);
1004290075Sobrien	}
1004390075Sobrien
10044132718Skan      if (arm_fpu_arch == FPUTYPE_FPA_EMU2)
1004590075Sobrien	{
10046169689Skan	  for (reg = FIRST_FPA_REGNUM; reg <= LAST_FPA_REGNUM; reg++)
1004790075Sobrien	    if (regs_ever_live[reg] && !call_used_regs[reg])
1004890075Sobrien	      asm_fprintf (f, "\tldfe\t%r, [%r], #12\n",
1004990075Sobrien			   reg, SP_REGNUM);
1005090075Sobrien	}
1005190075Sobrien      else
1005290075Sobrien	{
10053169689Skan	  start_reg = FIRST_FPA_REGNUM;
1005490075Sobrien
10055169689Skan	  for (reg = FIRST_FPA_REGNUM; reg <= LAST_FPA_REGNUM; reg++)
1005690075Sobrien	    {
1005790075Sobrien	      if (regs_ever_live[reg] && !call_used_regs[reg])
1005890075Sobrien		{
1005990075Sobrien		  if (reg - start_reg == 3)
1006090075Sobrien		    {
1006190075Sobrien		      asm_fprintf (f, "\tlfmfd\t%r, 4, [%r]!\n",
1006290075Sobrien				   start_reg, SP_REGNUM);
1006390075Sobrien		      start_reg = reg + 1;
1006490075Sobrien		    }
1006590075Sobrien		}
1006690075Sobrien	      else
1006790075Sobrien		{
1006890075Sobrien		  if (reg != start_reg)
1006990075Sobrien		    asm_fprintf (f, "\tlfmfd\t%r, %d, [%r]!\n",
1007090075Sobrien				 start_reg, reg - start_reg,
1007190075Sobrien				 SP_REGNUM);
10072169689Skan
1007390075Sobrien		  start_reg = reg + 1;
1007490075Sobrien		}
1007590075Sobrien	    }
1007690075Sobrien
1007790075Sobrien	  /* Just in case the last register checked also needs unstacking.  */
1007890075Sobrien	  if (reg != start_reg)
1007990075Sobrien	    asm_fprintf (f, "\tlfmfd\t%r, %d, [%r]!\n",
1008090075Sobrien			 start_reg, reg - start_reg, SP_REGNUM);
1008190075Sobrien	}
1008290075Sobrien
10083169689Skan      if (TARGET_HARD_FLOAT && TARGET_VFP)
10084169689Skan	{
10085169689Skan	  start_reg = FIRST_VFP_REGNUM;
10086169689Skan	  for (reg = FIRST_VFP_REGNUM; reg < LAST_VFP_REGNUM; reg += 2)
10087169689Skan	    {
10088169689Skan	      if ((!regs_ever_live[reg] || call_used_regs[reg])
10089169689Skan		  && (!regs_ever_live[reg + 1] || call_used_regs[reg + 1]))
10090169689Skan		{
10091169689Skan		  if (start_reg != reg)
10092169689Skan		    arm_output_fldmx (f, SP_REGNUM,
10093169689Skan				      (start_reg - FIRST_VFP_REGNUM) / 2,
10094169689Skan				      (reg - start_reg) / 2);
10095169689Skan		  start_reg = reg + 2;
10096169689Skan		}
10097169689Skan	    }
10098169689Skan	  if (start_reg != reg)
10099169689Skan	    arm_output_fldmx (f, SP_REGNUM,
10100169689Skan			      (start_reg - FIRST_VFP_REGNUM) / 2,
10101169689Skan			      (reg - start_reg) / 2);
10102169689Skan	}
10103132718Skan      if (TARGET_IWMMXT)
10104132718Skan	for (reg = FIRST_IWMMXT_REGNUM; reg <= LAST_IWMMXT_REGNUM; reg++)
10105132718Skan	  if (regs_ever_live[reg] && !call_used_regs[reg])
10106169689Skan	    asm_fprintf (f, "\twldrd\t%r, [%r], #8\n", reg, SP_REGNUM);
10107132718Skan
1010890075Sobrien      /* If we can, restore the LR into the PC.  */
1010990075Sobrien      if (ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL
1011090075Sobrien	  && really_return
1011190075Sobrien	  && current_function_pretend_args_size == 0
10112169689Skan	  && saved_regs_mask & (1 << LR_REGNUM)
10113169689Skan	  && !current_function_calls_eh_return)
1011490075Sobrien	{
1011590075Sobrien	  saved_regs_mask &= ~ (1 << LR_REGNUM);
1011690075Sobrien	  saved_regs_mask |=   (1 << PC_REGNUM);
1011790075Sobrien	}
1011890075Sobrien
1011990075Sobrien      /* Load the registers off the stack.  If we only have one register
1012090075Sobrien	 to load use the LDR instruction - it is faster.  */
1012190075Sobrien      if (saved_regs_mask == (1 << LR_REGNUM))
1012290075Sobrien	{
10123169689Skan	  asm_fprintf (f, "\tldr\t%r, [%r], #4\n", LR_REGNUM, SP_REGNUM);
1012490075Sobrien	}
1012590075Sobrien      else if (saved_regs_mask)
10126117395Skan	{
10127117395Skan	  if (saved_regs_mask & (1 << SP_REGNUM))
10128117395Skan	    /* Note - write back to the stack register is not enabled
10129169689Skan	       (i.e. "ldmfd sp!...").  We know that the stack pointer is
10130117395Skan	       in the list of registers and if we add writeback the
10131117395Skan	       instruction becomes UNPREDICTABLE.  */
10132117395Skan	    print_multi_reg (f, "ldmfd\t%r", SP_REGNUM, saved_regs_mask);
10133117395Skan	  else
10134117395Skan	    print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM, saved_regs_mask);
10135117395Skan	}
1013690075Sobrien
1013790075Sobrien      if (current_function_pretend_args_size)
1013890075Sobrien	{
1013990075Sobrien	  /* Unwind the pre-pushed regs.  */
1014090075Sobrien	  operands[0] = operands[1] = stack_pointer_rtx;
1014190075Sobrien	  operands[2] = GEN_INT (current_function_pretend_args_size);
1014290075Sobrien	  output_add_immediate (operands);
1014390075Sobrien	}
1014490075Sobrien    }
1014590075Sobrien
10146169689Skan  /* We may have already restored PC directly from the stack.  */
10147169689Skan  if (!really_return || saved_regs_mask & (1 << PC_REGNUM))
1014890075Sobrien    return "";
1014990075Sobrien
10150169689Skan  /* Stack adjustment for exception handler.  */
10151169689Skan  if (current_function_calls_eh_return)
10152169689Skan    asm_fprintf (f, "\tadd\t%r, %r, %r\n", SP_REGNUM, SP_REGNUM,
10153169689Skan		 ARM_EH_STACKADJ_REGNUM);
10154169689Skan
1015590075Sobrien  /* Generate the return instruction.  */
1015690075Sobrien  switch ((int) ARM_FUNC_TYPE (func_type))
1015790075Sobrien    {
1015890075Sobrien    case ARM_FT_ISR:
1015990075Sobrien    case ARM_FT_FIQ:
1016090075Sobrien      asm_fprintf (f, "\tsubs\t%r, %r, #4\n", PC_REGNUM, LR_REGNUM);
1016190075Sobrien      break;
1016290075Sobrien
1016390075Sobrien    case ARM_FT_EXCEPTION:
1016490075Sobrien      asm_fprintf (f, "\tmovs\t%r, %r\n", PC_REGNUM, LR_REGNUM);
1016590075Sobrien      break;
1016690075Sobrien
1016790075Sobrien    case ARM_FT_INTERWORKED:
1016890075Sobrien      asm_fprintf (f, "\tbx\t%r\n", LR_REGNUM);
1016990075Sobrien      break;
1017090075Sobrien
1017190075Sobrien    default:
10172169689Skan      if (arm_arch5 || arm_arch4t)
10173169689Skan	asm_fprintf (f, "\tbx\t%r\n", LR_REGNUM);
10174169689Skan      else
1017590075Sobrien	asm_fprintf (f, "\tmov\t%r, %r\n", PC_REGNUM, LR_REGNUM);
1017690075Sobrien      break;
1017790075Sobrien    }
1017890075Sobrien
1017990075Sobrien  return "";
1018090075Sobrien}
1018190075Sobrien
1018290075Sobrienstatic void
10183132718Skanarm_output_function_epilogue (FILE *file ATTRIBUTE_UNUSED,
10184169689Skan			      HOST_WIDE_INT frame_size ATTRIBUTE_UNUSED)
1018590075Sobrien{
10186169689Skan  arm_stack_offsets *offsets;
10187169689Skan
1018890075Sobrien  if (TARGET_THUMB)
1018990075Sobrien    {
10190169689Skan      int regno;
10191169689Skan
10192169689Skan      /* Emit any call-via-reg trampolines that are needed for v4t support
10193169689Skan	 of call_reg and call_value_reg type insns.  */
10194169689Skan      for (regno = 0; regno < LR_REGNUM; regno++)
10195169689Skan	{
10196169689Skan	  rtx label = cfun->machine->call_via[regno];
10197169689Skan
10198169689Skan	  if (label != NULL)
10199169689Skan	    {
10200169689Skan	      switch_to_section (function_section (current_function_decl));
10201169689Skan	      targetm.asm_out.internal_label (asm_out_file, "L",
10202169689Skan					      CODE_LABEL_NUMBER (label));
10203169689Skan	      asm_fprintf (asm_out_file, "\tbx\t%r\n", regno);
10204169689Skan	    }
10205169689Skan	}
10206169689Skan
1020790075Sobrien      /* ??? Probably not safe to set this here, since it assumes that a
1020890075Sobrien	 function will be emitted as assembly immediately after we generate
1020990075Sobrien	 RTL for it.  This does not happen for inline functions.  */
1021090075Sobrien      return_used_this_function = 0;
1021190075Sobrien    }
1021290075Sobrien  else
1021390075Sobrien    {
10214117395Skan      /* We need to take into account any stack-frame rounding.  */
10215169689Skan      offsets = arm_get_frame_offsets ();
10216117395Skan
10217169689Skan      gcc_assert (!use_return_insn (FALSE, NULL)
10218169689Skan		  || !return_used_this_function
10219169689Skan		  || offsets->saved_regs == offsets->outgoing_args
10220169689Skan		  || frame_pointer_needed);
1022190075Sobrien
1022290075Sobrien      /* Reset the ARM-specific per-function variables.  */
1022390075Sobrien      after_arm_reorg = 0;
1022490075Sobrien    }
1022590075Sobrien}
1022690075Sobrien
1022790075Sobrien/* Generate and emit an insn that we will recognize as a push_multi.
1022890075Sobrien   Unfortunately, since this insn does not reflect very well the actual
1022990075Sobrien   semantics of the operation, we need to annotate the insn for the benefit
1023090075Sobrien   of DWARF2 frame unwind information.  */
1023190075Sobrienstatic rtx
10232169689Skanemit_multi_reg_push (unsigned long mask)
1023390075Sobrien{
1023490075Sobrien  int num_regs = 0;
1023590075Sobrien  int num_dwarf_regs;
1023690075Sobrien  int i, j;
1023790075Sobrien  rtx par;
1023890075Sobrien  rtx dwarf;
1023990075Sobrien  int dwarf_par_index;
1024090075Sobrien  rtx tmp, reg;
1024190075Sobrien
1024290075Sobrien  for (i = 0; i <= LAST_ARM_REGNUM; i++)
1024390075Sobrien    if (mask & (1 << i))
1024490075Sobrien      num_regs++;
1024590075Sobrien
10246169689Skan  gcc_assert (num_regs && num_regs <= 16);
1024790075Sobrien
1024890075Sobrien  /* We don't record the PC in the dwarf frame information.  */
1024990075Sobrien  num_dwarf_regs = num_regs;
1025090075Sobrien  if (mask & (1 << PC_REGNUM))
1025190075Sobrien    num_dwarf_regs--;
1025290075Sobrien
1025390075Sobrien  /* For the body of the insn we are going to generate an UNSPEC in
10254117395Skan     parallel with several USEs.  This allows the insn to be recognized
1025590075Sobrien     by the push_multi pattern in the arm.md file.  The insn looks
1025690075Sobrien     something like this:
1025790075Sobrien
10258169689Skan       (parallel [
1025990075Sobrien           (set (mem:BLK (pre_dec:BLK (reg:SI sp)))
1026090075Sobrien	        (unspec:BLK [(reg:SI r4)] UNSPEC_PUSH_MULT))
1026190075Sobrien           (use (reg:SI 11 fp))
1026290075Sobrien           (use (reg:SI 12 ip))
1026390075Sobrien           (use (reg:SI 14 lr))
1026490075Sobrien           (use (reg:SI 15 pc))
1026590075Sobrien        ])
1026690075Sobrien
1026790075Sobrien     For the frame note however, we try to be more explicit and actually
1026890075Sobrien     show each register being stored into the stack frame, plus a (single)
1026990075Sobrien     decrement of the stack pointer.  We do it this way in order to be
1027090075Sobrien     friendly to the stack unwinding code, which only wants to see a single
1027190075Sobrien     stack decrement per instruction.  The RTL we generate for the note looks
1027290075Sobrien     something like this:
1027390075Sobrien
10274169689Skan      (sequence [
1027590075Sobrien           (set (reg:SI sp) (plus:SI (reg:SI sp) (const_int -20)))
1027690075Sobrien           (set (mem:SI (reg:SI sp)) (reg:SI r4))
1027790075Sobrien           (set (mem:SI (plus:SI (reg:SI sp) (const_int 4))) (reg:SI fp))
1027890075Sobrien           (set (mem:SI (plus:SI (reg:SI sp) (const_int 8))) (reg:SI ip))
1027990075Sobrien           (set (mem:SI (plus:SI (reg:SI sp) (const_int 12))) (reg:SI lr))
1028090075Sobrien        ])
1028190075Sobrien
1028290075Sobrien      This sequence is used both by the code to support stack unwinding for
1028390075Sobrien      exceptions handlers and the code to generate dwarf2 frame debugging.  */
10284169689Skan
1028590075Sobrien  par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (num_regs));
1028690075Sobrien  dwarf = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (num_dwarf_regs + 1));
1028790075Sobrien  dwarf_par_index = 1;
1028890075Sobrien
1028990075Sobrien  for (i = 0; i <= LAST_ARM_REGNUM; i++)
1029090075Sobrien    {
1029190075Sobrien      if (mask & (1 << i))
1029290075Sobrien	{
1029390075Sobrien	  reg = gen_rtx_REG (SImode, i);
1029490075Sobrien
1029590075Sobrien	  XVECEXP (par, 0, 0)
1029690075Sobrien	    = gen_rtx_SET (VOIDmode,
10297169689Skan			   gen_frame_mem (BLKmode,
10298169689Skan					  gen_rtx_PRE_DEC (BLKmode,
10299169689Skan							   stack_pointer_rtx)),
1030090075Sobrien			   gen_rtx_UNSPEC (BLKmode,
1030190075Sobrien					   gen_rtvec (1, reg),
1030290075Sobrien					   UNSPEC_PUSH_MULT));
1030390075Sobrien
1030490075Sobrien	  if (i != PC_REGNUM)
1030590075Sobrien	    {
1030690075Sobrien	      tmp = gen_rtx_SET (VOIDmode,
10307169689Skan				 gen_frame_mem (SImode, stack_pointer_rtx),
1030890075Sobrien				 reg);
1030990075Sobrien	      RTX_FRAME_RELATED_P (tmp) = 1;
1031090075Sobrien	      XVECEXP (dwarf, 0, dwarf_par_index) = tmp;
1031190075Sobrien	      dwarf_par_index++;
1031290075Sobrien	    }
1031390075Sobrien
1031490075Sobrien	  break;
1031590075Sobrien	}
1031690075Sobrien    }
1031790075Sobrien
1031890075Sobrien  for (j = 1, i++; j < num_regs; i++)
1031990075Sobrien    {
1032090075Sobrien      if (mask & (1 << i))
1032190075Sobrien	{
1032290075Sobrien	  reg = gen_rtx_REG (SImode, i);
1032390075Sobrien
1032490075Sobrien	  XVECEXP (par, 0, j) = gen_rtx_USE (VOIDmode, reg);
1032590075Sobrien
1032690075Sobrien	  if (i != PC_REGNUM)
1032790075Sobrien	    {
10328169689Skan	      tmp
10329169689Skan		= gen_rtx_SET (VOIDmode,
10330169689Skan			       gen_frame_mem (SImode,
1033190075Sobrien					      plus_constant (stack_pointer_rtx,
1033290075Sobrien							     4 * j)),
10333169689Skan			       reg);
1033490075Sobrien	      RTX_FRAME_RELATED_P (tmp) = 1;
1033590075Sobrien	      XVECEXP (dwarf, 0, dwarf_par_index++) = tmp;
1033690075Sobrien	    }
1033790075Sobrien
1033890075Sobrien	  j++;
1033990075Sobrien	}
1034090075Sobrien    }
1034190075Sobrien
1034290075Sobrien  par = emit_insn (par);
10343169689Skan
10344169689Skan  tmp = gen_rtx_SET (VOIDmode,
1034590075Sobrien		     stack_pointer_rtx,
10346169689Skan		     plus_constant (stack_pointer_rtx, -4 * num_regs));
1034790075Sobrien  RTX_FRAME_RELATED_P (tmp) = 1;
1034890075Sobrien  XVECEXP (dwarf, 0, 0) = tmp;
10349169689Skan
1035090075Sobrien  REG_NOTES (par) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
1035190075Sobrien				       REG_NOTES (par));
1035290075Sobrien  return par;
1035390075Sobrien}
1035490075Sobrien
10355169689Skan/* Calculate the size of the return value that is passed in registers.  */
10356169689Skanstatic int
10357169689Skanarm_size_return_regs (void)
10358169689Skan{
10359169689Skan  enum machine_mode mode;
10360169689Skan
10361169689Skan  if (current_function_return_rtx != 0)
10362169689Skan    mode = GET_MODE (current_function_return_rtx);
10363169689Skan  else
10364169689Skan    mode = DECL_MODE (DECL_RESULT (current_function_decl));
10365169689Skan
10366169689Skan  return GET_MODE_SIZE (mode);
10367169689Skan}
10368169689Skan
1036990075Sobrienstatic rtx
10370132718Skanemit_sfm (int base_reg, int count)
1037190075Sobrien{
1037290075Sobrien  rtx par;
1037390075Sobrien  rtx dwarf;
1037490075Sobrien  rtx tmp, reg;
1037590075Sobrien  int i;
1037690075Sobrien
1037790075Sobrien  par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count));
10378169689Skan  dwarf = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (count + 1));
1037990075Sobrien
1038090075Sobrien  reg = gen_rtx_REG (XFmode, base_reg++);
1038190075Sobrien
1038290075Sobrien  XVECEXP (par, 0, 0)
10383169689Skan    = gen_rtx_SET (VOIDmode,
10384169689Skan		   gen_frame_mem (BLKmode,
10385169689Skan				  gen_rtx_PRE_DEC (BLKmode,
10386169689Skan						   stack_pointer_rtx)),
1038790075Sobrien		   gen_rtx_UNSPEC (BLKmode,
1038890075Sobrien				   gen_rtvec (1, reg),
1038990075Sobrien				   UNSPEC_PUSH_MULT));
10390169689Skan  tmp = gen_rtx_SET (VOIDmode,
10391169689Skan		     gen_frame_mem (XFmode, stack_pointer_rtx), reg);
1039290075Sobrien  RTX_FRAME_RELATED_P (tmp) = 1;
10393169689Skan  XVECEXP (dwarf, 0, 1) = tmp;
10394169689Skan
1039590075Sobrien  for (i = 1; i < count; i++)
1039690075Sobrien    {
1039790075Sobrien      reg = gen_rtx_REG (XFmode, base_reg++);
1039890075Sobrien      XVECEXP (par, 0, i) = gen_rtx_USE (VOIDmode, reg);
1039990075Sobrien
10400169689Skan      tmp = gen_rtx_SET (VOIDmode,
10401169689Skan			 gen_frame_mem (XFmode,
10402169689Skan					plus_constant (stack_pointer_rtx,
10403169689Skan						       i * 12)),
1040490075Sobrien			 reg);
1040590075Sobrien      RTX_FRAME_RELATED_P (tmp) = 1;
10406169689Skan      XVECEXP (dwarf, 0, i + 1) = tmp;
1040790075Sobrien    }
1040890075Sobrien
10409169689Skan  tmp = gen_rtx_SET (VOIDmode,
10410169689Skan		     stack_pointer_rtx,
10411169689Skan		     plus_constant (stack_pointer_rtx, -12 * count));
10412169689Skan
10413169689Skan  RTX_FRAME_RELATED_P (tmp) = 1;
10414169689Skan  XVECEXP (dwarf, 0, 0) = tmp;
10415169689Skan
1041690075Sobrien  par = emit_insn (par);
1041790075Sobrien  REG_NOTES (par) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
1041890075Sobrien				       REG_NOTES (par));
1041990075Sobrien  return par;
1042090075Sobrien}
1042190075Sobrien
10422169689Skan
10423169689Skan/* Return true if the current function needs to save/restore LR.  */
10424169689Skan
10425169689Skanstatic bool
10426169689Skanthumb_force_lr_save (void)
10427169689Skan{
10428169689Skan  return !cfun->machine->lr_save_eliminated
10429169689Skan	 && (!leaf_function_p ()
10430169689Skan	     || thumb_far_jump_used_p ()
10431169689Skan	     || regs_ever_live [LR_REGNUM]);
10432169689Skan}
10433169689Skan
10434169689Skan
1043590075Sobrien/* Compute the distance from register FROM to register TO.
1043690075Sobrien   These can be the arg pointer (26), the soft frame pointer (25),
1043790075Sobrien   the stack pointer (13) or the hard frame pointer (11).
10438169689Skan   In thumb mode r7 is used as the soft frame pointer, if needed.
1043990075Sobrien   Typical stack layout looks like this:
1044090075Sobrien
1044190075Sobrien       old stack pointer -> |    |
1044290075Sobrien                             ----
1044390075Sobrien                            |    | \
1044490075Sobrien                            |    |   saved arguments for
1044590075Sobrien                            |    |   vararg functions
1044690075Sobrien			    |    | /
1044790075Sobrien                              --
1044890075Sobrien   hard FP & arg pointer -> |    | \
1044990075Sobrien                            |    |   stack
1045090075Sobrien                            |    |   frame
1045190075Sobrien                            |    | /
1045290075Sobrien                              --
1045390075Sobrien                            |    | \
1045490075Sobrien                            |    |   call saved
1045590075Sobrien                            |    |   registers
1045690075Sobrien      soft frame pointer -> |    | /
1045790075Sobrien                              --
1045890075Sobrien                            |    | \
1045990075Sobrien                            |    |   local
1046090075Sobrien                            |    |   variables
10461169689Skan     locals base pointer -> |    | /
1046290075Sobrien                              --
1046390075Sobrien                            |    | \
1046490075Sobrien                            |    |   outgoing
1046590075Sobrien                            |    |   arguments
1046690075Sobrien   current stack pointer -> |    | /
1046790075Sobrien                              --
1046890075Sobrien
10469117395Skan  For a given function some or all of these stack components
1047090075Sobrien  may not be needed, giving rise to the possibility of
1047190075Sobrien  eliminating some of the registers.
1047290075Sobrien
10473117395Skan  The values returned by this function must reflect the behavior
1047490075Sobrien  of arm_expand_prologue() and arm_compute_save_reg_mask().
1047590075Sobrien
1047690075Sobrien  The sign of the number returned reflects the direction of stack
1047790075Sobrien  growth, so the values are positive for all eliminations except
10478169689Skan  from the soft frame pointer to the hard frame pointer.
10479169689Skan
10480169689Skan  SFP may point just inside the local variables block to ensure correct
10481169689Skan  alignment.  */
10482169689Skan
10483169689Skan
10484169689Skan/* Calculate stack offsets.  These are used to calculate register elimination
10485169689Skan   offsets and in prologue/epilogue code.  */
10486169689Skan
10487169689Skanstatic arm_stack_offsets *
10488169689Skanarm_get_frame_offsets (void)
1048990075Sobrien{
10490169689Skan  struct arm_stack_offsets *offsets;
1049190075Sobrien  unsigned long func_type;
10492169689Skan  int leaf;
10493169689Skan  int saved;
10494169689Skan  HOST_WIDE_INT frame_size;
1049590075Sobrien
10496169689Skan  offsets = &cfun->machine->stack_offsets;
10497169689Skan
10498169689Skan  /* We need to know if we are a leaf function.  Unfortunately, it
10499169689Skan     is possible to be called after start_sequence has been called,
10500169689Skan     which causes get_insns to return the insns for the sequence,
10501169689Skan     not the function, which will cause leaf_function_p to return
10502169689Skan     the incorrect result.
10503169689Skan
10504169689Skan     to know about leaf functions once reload has completed, and the
10505169689Skan     frame size cannot be changed after that time, so we can safely
10506169689Skan     use the cached value.  */
10507169689Skan
10508169689Skan  if (reload_completed)
10509169689Skan    return offsets;
10510169689Skan
10511169689Skan  /* Initially this is the size of the local variables.  It will translated
10512169689Skan     into an offset once we have determined the size of preceding data.  */
10513169689Skan  frame_size = ROUND_UP_WORD (get_frame_size ());
10514169689Skan
10515169689Skan  leaf = leaf_function_p ();
10516169689Skan
10517169689Skan  /* Space for variadic functions.  */
10518169689Skan  offsets->saved_args = current_function_pretend_args_size;
10519169689Skan
10520169689Skan  offsets->frame = offsets->saved_args + (frame_pointer_needed ? 4 : 0);
10521169689Skan
10522169689Skan  if (TARGET_ARM)
1052390075Sobrien    {
10524169689Skan      unsigned int regno;
1052590075Sobrien
10526169689Skan      saved = bit_count (arm_compute_save_reg_mask ()) * 4;
1052790075Sobrien
10528169689Skan      /* We know that SP will be doubleword aligned on entry, and we must
10529169689Skan	 preserve that condition at any subroutine call.  We also require the
10530169689Skan	 soft frame pointer to be doubleword aligned.  */
1053190075Sobrien
10532169689Skan      if (TARGET_REALLY_IWMMXT)
10533169689Skan	{
10534169689Skan	  /* Check for the call-saved iWMMXt registers.  */
10535169689Skan	  for (regno = FIRST_IWMMXT_REGNUM;
10536169689Skan	       regno <= LAST_IWMMXT_REGNUM;
10537169689Skan	       regno++)
10538169689Skan	    if (regs_ever_live [regno] && ! call_used_regs [regno])
10539169689Skan	      saved += 8;
10540169689Skan	}
10541132718Skan
10542169689Skan      func_type = arm_current_func_type ();
10543169689Skan      if (! IS_VOLATILE (func_type))
10544169689Skan	{
10545169689Skan	  /* Space for saved FPA registers.  */
10546169689Skan	  for (regno = FIRST_FPA_REGNUM; regno <= LAST_FPA_REGNUM; regno++)
10547169689Skan	  if (regs_ever_live[regno] && ! call_used_regs[regno])
10548169689Skan	    saved += 12;
10549169689Skan
10550169689Skan	  /* Space for saved VFP registers.  */
10551169689Skan	  if (TARGET_HARD_FLOAT && TARGET_VFP)
10552169689Skan	    saved += arm_get_vfp_saved_size ();
10553169689Skan	}
1055490075Sobrien    }
10555169689Skan  else /* TARGET_THUMB */
10556169689Skan    {
10557169689Skan      saved = bit_count (thumb_compute_save_reg_mask ()) * 4;
10558169689Skan      if (TARGET_BACKTRACE)
10559169689Skan	saved += 16;
10560169689Skan    }
1056190075Sobrien
10562169689Skan  /* Saved registers include the stack frame.  */
10563169689Skan  offsets->saved_regs = offsets->saved_args + saved;
10564169689Skan  offsets->soft_frame = offsets->saved_regs + CALLER_INTERWORKING_SLOT_SIZE;
10565169689Skan  /* A leaf function does not need any stack alignment if it has nothing
10566169689Skan     on the stack.  */
10567169689Skan  if (leaf && frame_size == 0)
10568169689Skan    {
10569169689Skan      offsets->outgoing_args = offsets->soft_frame;
10570171825Skan      offsets->locals_base = offsets->soft_frame;
10571169689Skan      return offsets;
10572169689Skan    }
1057390075Sobrien
10574169689Skan  /* Ensure SFP has the correct alignment.  */
10575169689Skan  if (ARM_DOUBLEWORD_ALIGN
10576169689Skan      && (offsets->soft_frame & 7))
10577169689Skan    offsets->soft_frame += 4;
10578169689Skan
10579169689Skan  offsets->locals_base = offsets->soft_frame + frame_size;
10580169689Skan  offsets->outgoing_args = (offsets->locals_base
10581169689Skan			    + current_function_outgoing_args_size);
10582169689Skan
10583169689Skan  if (ARM_DOUBLEWORD_ALIGN)
10584169689Skan    {
10585169689Skan      /* Ensure SP remains doubleword aligned.  */
10586169689Skan      if (offsets->outgoing_args & 7)
10587169689Skan	offsets->outgoing_args += 4;
10588169689Skan      gcc_assert (!(offsets->outgoing_args & 7));
10589169689Skan    }
10590169689Skan
10591169689Skan  return offsets;
10592169689Skan}
10593169689Skan
10594169689Skan
10595169689Skan/* Calculate the relative offsets for the different stack pointers.  Positive
10596169689Skan   offsets are in the direction of stack growth.  */
10597169689Skan
10598169689SkanHOST_WIDE_INT
10599169689Skanarm_compute_initial_elimination_offset (unsigned int from, unsigned int to)
10600169689Skan{
10601169689Skan  arm_stack_offsets *offsets;
10602169689Skan
10603169689Skan  offsets = arm_get_frame_offsets ();
10604169689Skan
1060590075Sobrien  /* OK, now we have enough information to compute the distances.
1060690075Sobrien     There must be an entry in these switch tables for each pair
1060790075Sobrien     of registers in ELIMINABLE_REGS, even if some of the entries
1060890075Sobrien     seem to be redundant or useless.  */
1060990075Sobrien  switch (from)
1061090075Sobrien    {
1061190075Sobrien    case ARG_POINTER_REGNUM:
1061290075Sobrien      switch (to)
1061390075Sobrien	{
1061490075Sobrien	case THUMB_HARD_FRAME_POINTER_REGNUM:
1061590075Sobrien	  return 0;
1061690075Sobrien
1061790075Sobrien	case FRAME_POINTER_REGNUM:
1061890075Sobrien	  /* This is the reverse of the soft frame pointer
1061990075Sobrien	     to hard frame pointer elimination below.  */
10620169689Skan	  return offsets->soft_frame - offsets->saved_args;
1062190075Sobrien
1062290075Sobrien	case ARM_HARD_FRAME_POINTER_REGNUM:
1062390075Sobrien	  /* If there is no stack frame then the hard
1062490075Sobrien	     frame pointer and the arg pointer coincide.  */
10625169689Skan	  if (offsets->frame == offsets->saved_regs)
1062690075Sobrien	    return 0;
1062790075Sobrien	  /* FIXME:  Not sure about this.  Maybe we should always return 0 ?  */
1062890075Sobrien	  return (frame_pointer_needed
10629169689Skan		  && cfun->static_chain_decl != NULL
1063096263Sobrien		  && ! cfun->machine->uses_anonymous_args) ? 4 : 0;
1063190075Sobrien
1063290075Sobrien	case STACK_POINTER_REGNUM:
1063390075Sobrien	  /* If nothing has been pushed on the stack at all
1063490075Sobrien	     then this will return -4.  This *is* correct!  */
10635169689Skan	  return offsets->outgoing_args - (offsets->saved_args + 4);
1063690075Sobrien
1063790075Sobrien	default:
10638169689Skan	  gcc_unreachable ();
1063990075Sobrien	}
10640169689Skan      gcc_unreachable ();
1064190075Sobrien
1064290075Sobrien    case FRAME_POINTER_REGNUM:
1064390075Sobrien      switch (to)
1064490075Sobrien	{
1064590075Sobrien	case THUMB_HARD_FRAME_POINTER_REGNUM:
1064690075Sobrien	  return 0;
1064790075Sobrien
1064890075Sobrien	case ARM_HARD_FRAME_POINTER_REGNUM:
1064990075Sobrien	  /* The hard frame pointer points to the top entry in the
1065090075Sobrien	     stack frame.  The soft frame pointer to the bottom entry
1065190075Sobrien	     in the stack frame.  If there is no stack frame at all,
1065290075Sobrien	     then they are identical.  */
1065390075Sobrien
10654169689Skan	  return offsets->frame - offsets->soft_frame;
10655169689Skan
1065690075Sobrien	case STACK_POINTER_REGNUM:
10657169689Skan	  return offsets->outgoing_args - offsets->soft_frame;
1065890075Sobrien
1065990075Sobrien	default:
10660169689Skan	  gcc_unreachable ();
1066190075Sobrien	}
10662169689Skan      gcc_unreachable ();
1066390075Sobrien
1066490075Sobrien    default:
1066590075Sobrien      /* You cannot eliminate from the stack pointer.
1066690075Sobrien	 In theory you could eliminate from the hard frame
1066790075Sobrien	 pointer to the stack pointer, but this will never
1066890075Sobrien	 happen, since if a stack frame is not needed the
1066990075Sobrien	 hard frame pointer will never be used.  */
10670169689Skan      gcc_unreachable ();
1067190075Sobrien    }
1067290075Sobrien}
1067390075Sobrien
10674117395Skan
1067590075Sobrien/* Generate the prologue instructions for entry into an ARM function.  */
1067690075Sobrienvoid
10677132718Skanarm_expand_prologue (void)
1067890075Sobrien{
1067990075Sobrien  int reg;
1068090075Sobrien  rtx amount;
1068190075Sobrien  rtx insn;
1068290075Sobrien  rtx ip_rtx;
1068390075Sobrien  unsigned long live_regs_mask;
1068490075Sobrien  unsigned long func_type;
1068590075Sobrien  int fp_offset = 0;
1068690075Sobrien  int saved_pretend_args = 0;
10687169689Skan  int saved_regs = 0;
10688169689Skan  unsigned HOST_WIDE_INT args_to_push;
10689169689Skan  arm_stack_offsets *offsets;
1069090075Sobrien
1069190075Sobrien  func_type = arm_current_func_type ();
1069290075Sobrien
1069390075Sobrien  /* Naked functions don't have prologues.  */
1069490075Sobrien  if (IS_NAKED (func_type))
1069590075Sobrien    return;
1069690075Sobrien
1069790075Sobrien  /* Make a copy of c_f_p_a_s as we may need to modify it locally.  */
1069890075Sobrien  args_to_push = current_function_pretend_args_size;
10699169689Skan
1070090075Sobrien  /* Compute which register we will have to save onto the stack.  */
1070190075Sobrien  live_regs_mask = arm_compute_save_reg_mask ();
1070290075Sobrien
1070390075Sobrien  ip_rtx = gen_rtx_REG (SImode, IP_REGNUM);
1070490075Sobrien
1070590075Sobrien  if (frame_pointer_needed)
1070690075Sobrien    {
1070790075Sobrien      if (IS_INTERRUPT (func_type))
1070890075Sobrien	{
1070990075Sobrien	  /* Interrupt functions must not corrupt any registers.
1071090075Sobrien	     Creating a frame pointer however, corrupts the IP
1071190075Sobrien	     register, so we must push it first.  */
1071290075Sobrien	  insn = emit_multi_reg_push (1 << IP_REGNUM);
1071390075Sobrien
1071490075Sobrien	  /* Do not set RTX_FRAME_RELATED_P on this insn.
1071590075Sobrien	     The dwarf stack unwinding code only wants to see one
1071690075Sobrien	     stack decrement per function, and this is not it.  If
1071790075Sobrien	     this instruction is labeled as being part of the frame
1071890075Sobrien	     creation sequence then dwarf2out_frame_debug_expr will
10719169689Skan	     die when it encounters the assignment of IP to FP
1072090075Sobrien	     later on, since the use of SP here establishes SP as
1072190075Sobrien	     the CFA register and not IP.
1072290075Sobrien
1072390075Sobrien	     Anyway this instruction is not really part of the stack
1072490075Sobrien	     frame creation although it is part of the prologue.  */
1072590075Sobrien	}
1072690075Sobrien      else if (IS_NESTED (func_type))
1072790075Sobrien	{
1072890075Sobrien	  /* The Static chain register is the same as the IP register
1072990075Sobrien	     used as a scratch register during stack frame creation.
1073090075Sobrien	     To get around this need to find somewhere to store IP
1073190075Sobrien	     whilst the frame is being created.  We try the following
1073290075Sobrien	     places in order:
10733169689Skan
1073490075Sobrien	       1. The last argument register.
1073590075Sobrien	       2. A slot on the stack above the frame.  (This only
1073690075Sobrien	          works if the function is not a varargs function).
1073790075Sobrien	       3. Register r3, after pushing the argument registers
1073890075Sobrien	          onto the stack.
1073990075Sobrien
1074090075Sobrien	     Note - we only need to tell the dwarf2 backend about the SP
1074190075Sobrien	     adjustment in the second variant; the static chain register
1074290075Sobrien	     doesn't need to be unwound, as it doesn't contain a value
1074390075Sobrien	     inherited from the caller.  */
1074490075Sobrien
1074590075Sobrien	  if (regs_ever_live[3] == 0)
10746169689Skan	    insn = emit_set_insn (gen_rtx_REG (SImode, 3), ip_rtx);
1074790075Sobrien	  else if (args_to_push == 0)
1074890075Sobrien	    {
1074990075Sobrien	      rtx dwarf;
10750169689Skan
1075190075Sobrien	      insn = gen_rtx_PRE_DEC (SImode, stack_pointer_rtx);
10752169689Skan	      insn = emit_set_insn (gen_frame_mem (SImode, insn), ip_rtx);
1075390075Sobrien	      fp_offset = 4;
1075490075Sobrien
1075590075Sobrien	      /* Just tell the dwarf backend that we adjusted SP.  */
1075690075Sobrien	      dwarf = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
10757169689Skan				   plus_constant (stack_pointer_rtx,
10758169689Skan						  -fp_offset));
1075990075Sobrien	      RTX_FRAME_RELATED_P (insn) = 1;
1076090075Sobrien	      REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
1076190075Sobrien						    dwarf, REG_NOTES (insn));
1076290075Sobrien	    }
1076390075Sobrien	  else
1076490075Sobrien	    {
1076590075Sobrien	      /* Store the args on the stack.  */
1076696263Sobrien	      if (cfun->machine->uses_anonymous_args)
1076790075Sobrien		insn = emit_multi_reg_push
1076890075Sobrien		  ((0xf0 >> (args_to_push / 4)) & 0xf);
1076990075Sobrien	      else
1077090075Sobrien		insn = emit_insn
10771169689Skan		  (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
1077290075Sobrien			       GEN_INT (- args_to_push)));
1077390075Sobrien
1077490075Sobrien	      RTX_FRAME_RELATED_P (insn) = 1;
1077590075Sobrien
1077690075Sobrien	      saved_pretend_args = 1;
1077790075Sobrien	      fp_offset = args_to_push;
1077890075Sobrien	      args_to_push = 0;
1077990075Sobrien
1078090075Sobrien	      /* Now reuse r3 to preserve IP.  */
10781169689Skan	      emit_set_insn (gen_rtx_REG (SImode, 3), ip_rtx);
1078290075Sobrien	    }
1078390075Sobrien	}
1078490075Sobrien
10785169689Skan      insn = emit_set_insn (ip_rtx,
10786169689Skan			    plus_constant (stack_pointer_rtx, fp_offset));
1078790075Sobrien      RTX_FRAME_RELATED_P (insn) = 1;
1078890075Sobrien    }
1078990075Sobrien
1079090075Sobrien  if (args_to_push)
1079190075Sobrien    {
1079290075Sobrien      /* Push the argument registers, or reserve space for them.  */
1079396263Sobrien      if (cfun->machine->uses_anonymous_args)
1079490075Sobrien	insn = emit_multi_reg_push
1079590075Sobrien	  ((0xf0 >> (args_to_push / 4)) & 0xf);
1079690075Sobrien      else
1079790075Sobrien	insn = emit_insn
10798169689Skan	  (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
1079990075Sobrien		       GEN_INT (- args_to_push)));
1080090075Sobrien      RTX_FRAME_RELATED_P (insn) = 1;
1080190075Sobrien    }
1080290075Sobrien
10803117395Skan  /* If this is an interrupt service routine, and the link register
10804117395Skan     is going to be pushed, and we are not creating a stack frame,
10805117395Skan     (which would involve an extra push of IP and a pop in the epilogue)
10806117395Skan     subtracting four from LR now will mean that the function return
10807117395Skan     can be done with a single instruction.  */
1080896263Sobrien  if ((func_type == ARM_FT_ISR || func_type == ARM_FT_FIQ)
10809117395Skan      && (live_regs_mask & (1 << LR_REGNUM)) != 0
10810117395Skan      && ! frame_pointer_needed)
10811169689Skan    {
10812169689Skan      rtx lr = gen_rtx_REG (SImode, LR_REGNUM);
10813169689Skan
10814169689Skan      emit_set_insn (lr, plus_constant (lr, -4));
10815169689Skan    }
1081696263Sobrien
1081790075Sobrien  if (live_regs_mask)
1081890075Sobrien    {
1081990075Sobrien      insn = emit_multi_reg_push (live_regs_mask);
10820169689Skan      saved_regs += bit_count (live_regs_mask) * 4;
1082190075Sobrien      RTX_FRAME_RELATED_P (insn) = 1;
1082290075Sobrien    }
1082390075Sobrien
10824132718Skan  if (TARGET_IWMMXT)
10825169689Skan    for (reg = LAST_IWMMXT_REGNUM; reg >= FIRST_IWMMXT_REGNUM; reg--)
10826132718Skan      if (regs_ever_live[reg] && ! call_used_regs [reg])
10827132718Skan	{
10828132718Skan	  insn = gen_rtx_PRE_DEC (V2SImode, stack_pointer_rtx);
10829169689Skan	  insn = gen_frame_mem (V2SImode, insn);
10830169689Skan	  insn = emit_set_insn (insn, gen_rtx_REG (V2SImode, reg));
10831132718Skan	  RTX_FRAME_RELATED_P (insn) = 1;
10832169689Skan	  saved_regs += 8;
10833132718Skan	}
10834132718Skan
1083590075Sobrien  if (! IS_VOLATILE (func_type))
1083690075Sobrien    {
10837169689Skan      int start_reg;
10838169689Skan
10839132718Skan      /* Save any floating point call-saved registers used by this
10840132718Skan	 function.  */
10841132718Skan      if (arm_fpu_arch == FPUTYPE_FPA_EMU2)
1084290075Sobrien	{
10843169689Skan	  for (reg = LAST_FPA_REGNUM; reg >= FIRST_FPA_REGNUM; reg--)
1084490075Sobrien	    if (regs_ever_live[reg] && !call_used_regs[reg])
1084590075Sobrien	      {
1084690075Sobrien		insn = gen_rtx_PRE_DEC (XFmode, stack_pointer_rtx);
10847169689Skan		insn = gen_frame_mem (XFmode, insn);
10848169689Skan		insn = emit_set_insn (insn, gen_rtx_REG (XFmode, reg));
1084990075Sobrien		RTX_FRAME_RELATED_P (insn) = 1;
10850169689Skan		saved_regs += 12;
1085190075Sobrien	      }
1085290075Sobrien	}
1085390075Sobrien      else
1085490075Sobrien	{
10855169689Skan	  start_reg = LAST_FPA_REGNUM;
1085690075Sobrien
10857169689Skan	  for (reg = LAST_FPA_REGNUM; reg >= FIRST_FPA_REGNUM; reg--)
1085890075Sobrien	    {
1085990075Sobrien	      if (regs_ever_live[reg] && !call_used_regs[reg])
1086090075Sobrien		{
1086190075Sobrien		  if (start_reg - reg == 3)
1086290075Sobrien		    {
1086390075Sobrien		      insn = emit_sfm (reg, 4);
1086490075Sobrien		      RTX_FRAME_RELATED_P (insn) = 1;
10865169689Skan		      saved_regs += 48;
1086690075Sobrien		      start_reg = reg - 1;
1086790075Sobrien		    }
1086890075Sobrien		}
1086990075Sobrien	      else
1087090075Sobrien		{
1087190075Sobrien		  if (start_reg != reg)
1087290075Sobrien		    {
1087390075Sobrien		      insn = emit_sfm (reg + 1, start_reg - reg);
1087490075Sobrien		      RTX_FRAME_RELATED_P (insn) = 1;
10875169689Skan		      saved_regs += (start_reg - reg) * 12;
1087690075Sobrien		    }
1087790075Sobrien		  start_reg = reg - 1;
1087890075Sobrien		}
1087990075Sobrien	    }
1088090075Sobrien
1088190075Sobrien	  if (start_reg != reg)
1088290075Sobrien	    {
1088390075Sobrien	      insn = emit_sfm (reg + 1, start_reg - reg);
10884169689Skan	      saved_regs += (start_reg - reg) * 12;
1088590075Sobrien	      RTX_FRAME_RELATED_P (insn) = 1;
1088690075Sobrien	    }
1088790075Sobrien	}
10888169689Skan      if (TARGET_HARD_FLOAT && TARGET_VFP)
10889169689Skan	{
10890169689Skan	  start_reg = FIRST_VFP_REGNUM;
10891169689Skan
10892169689Skan 	  for (reg = FIRST_VFP_REGNUM; reg < LAST_VFP_REGNUM; reg += 2)
10893169689Skan	    {
10894169689Skan	      if ((!regs_ever_live[reg] || call_used_regs[reg])
10895169689Skan		  && (!regs_ever_live[reg + 1] || call_used_regs[reg + 1]))
10896169689Skan		{
10897169689Skan		  if (start_reg != reg)
10898169689Skan		    saved_regs += vfp_emit_fstmx (start_reg,
10899169689Skan						  (reg - start_reg) / 2);
10900169689Skan		  start_reg = reg + 2;
10901169689Skan		}
10902169689Skan	    }
10903169689Skan	  if (start_reg != reg)
10904169689Skan	    saved_regs += vfp_emit_fstmx (start_reg,
10905169689Skan					  (reg - start_reg) / 2);
10906169689Skan	}
1090790075Sobrien    }
1090890075Sobrien
1090990075Sobrien  if (frame_pointer_needed)
1091090075Sobrien    {
1091190075Sobrien      /* Create the new frame pointer.  */
1091290075Sobrien      insn = GEN_INT (-(4 + args_to_push + fp_offset));
1091390075Sobrien      insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx, ip_rtx, insn));
1091490075Sobrien      RTX_FRAME_RELATED_P (insn) = 1;
10915169689Skan
1091690075Sobrien      if (IS_NESTED (func_type))
1091790075Sobrien	{
1091890075Sobrien	  /* Recover the static chain register.  */
1091990075Sobrien	  if (regs_ever_live [3] == 0
1092090075Sobrien	      || saved_pretend_args)
1092190075Sobrien	    insn = gen_rtx_REG (SImode, 3);
1092290075Sobrien	  else /* if (current_function_pretend_args_size == 0) */
1092390075Sobrien	    {
10924169689Skan	      insn = plus_constant (hard_frame_pointer_rtx, 4);
10925169689Skan	      insn = gen_frame_mem (SImode, insn);
1092690075Sobrien	    }
1092790075Sobrien
10928169689Skan	  emit_set_insn (ip_rtx, insn);
1092990075Sobrien	  /* Add a USE to stop propagate_one_insn() from barfing.  */
1093090075Sobrien	  emit_insn (gen_prologue_use (ip_rtx));
1093190075Sobrien	}
1093290075Sobrien    }
1093390075Sobrien
10934169689Skan  offsets = arm_get_frame_offsets ();
10935169689Skan  if (offsets->outgoing_args != offsets->saved_args + saved_regs)
1093690075Sobrien    {
1093790075Sobrien      /* This add can produce multiple insns for a large constant, so we
1093890075Sobrien	 need to get tricky.  */
1093990075Sobrien      rtx last = get_last_insn ();
10940169689Skan
10941169689Skan      amount = GEN_INT (offsets->saved_args + saved_regs
10942169689Skan			- offsets->outgoing_args);
10943169689Skan
1094490075Sobrien      insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
1094590075Sobrien				    amount));
1094690075Sobrien      do
1094790075Sobrien	{
1094890075Sobrien	  last = last ? NEXT_INSN (last) : get_insns ();
1094990075Sobrien	  RTX_FRAME_RELATED_P (last) = 1;
1095090075Sobrien	}
1095190075Sobrien      while (last != insn);
1095290075Sobrien
1095390075Sobrien      /* If the frame pointer is needed, emit a special barrier that
1095490075Sobrien	 will prevent the scheduler from moving stores to the frame
1095590075Sobrien	 before the stack adjustment.  */
1095690075Sobrien      if (frame_pointer_needed)
10957117395Skan	insn = emit_insn (gen_stack_tie (stack_pointer_rtx,
10958117395Skan					 hard_frame_pointer_rtx));
1095990075Sobrien    }
1096090075Sobrien
10961169689Skan
10962169689Skan  if (flag_pic && arm_pic_register != INVALID_REGNUM)
10963169689Skan    arm_load_pic_register (0UL);
10964169689Skan
1096590075Sobrien  /* If we are profiling, make sure no instructions are scheduled before
1096690075Sobrien     the call to mcount.  Similarly if the user has requested no
10967169689Skan     scheduling in the prolog.  Similarly if we want non-call exceptions
10968169689Skan     using the EABI unwinder, to prevent faulting instructions from being
10969169689Skan     swapped with a stack adjustment.  */
10970169689Skan  if (current_function_profile || !TARGET_SCHED_PROLOG
10971169689Skan      || (ARM_EABI_UNWIND_TABLES && flag_non_call_exceptions))
1097290075Sobrien    emit_insn (gen_blockage ());
1097390075Sobrien
1097490075Sobrien  /* If the link register is being kept alive, with the return address in it,
1097590075Sobrien     then make sure that it does not get reused by the ce2 pass.  */
1097690075Sobrien  if ((live_regs_mask & (1 << LR_REGNUM)) == 0)
1097790075Sobrien    {
1097890075Sobrien      emit_insn (gen_prologue_use (gen_rtx_REG (SImode, LR_REGNUM)));
1097990075Sobrien      cfun->machine->lr_save_eliminated = 1;
1098090075Sobrien    }
1098190075Sobrien}
1098290075Sobrien
1098390075Sobrien/* If CODE is 'd', then the X is a condition operand and the instruction
1098490075Sobrien   should only be executed if the condition is true.
1098590075Sobrien   if CODE is 'D', then the X is a condition operand and the instruction
1098690075Sobrien   should only be executed if the condition is false: however, if the mode
1098790075Sobrien   of the comparison is CCFPEmode, then always execute the instruction -- we
1098890075Sobrien   do this because in these circumstances !GE does not necessarily imply LT;
1098990075Sobrien   in these cases the instruction pattern will take care to make sure that
1099090075Sobrien   an instruction containing %d will follow, thereby undoing the effects of
1099190075Sobrien   doing this instruction unconditionally.
1099290075Sobrien   If CODE is 'N' then X is a floating point operand that must be negated
1099390075Sobrien   before output.
1099490075Sobrien   If CODE is 'B' then output a bitwise inverted value of X (a const int).
1099590075Sobrien   If X is a REG and CODE is `M', output a ldm/stm style multi-reg.  */
1099690075Sobrienvoid
10997132718Skanarm_print_operand (FILE *stream, rtx x, int code)
1099890075Sobrien{
1099990075Sobrien  switch (code)
1100090075Sobrien    {
1100190075Sobrien    case '@':
1100290075Sobrien      fputs (ASM_COMMENT_START, stream);
1100390075Sobrien      return;
1100490075Sobrien
1100590075Sobrien    case '_':
1100690075Sobrien      fputs (user_label_prefix, stream);
1100790075Sobrien      return;
11008169689Skan
1100990075Sobrien    case '|':
1101090075Sobrien      fputs (REGISTER_PREFIX, stream);
1101190075Sobrien      return;
1101290075Sobrien
1101390075Sobrien    case '?':
1101490075Sobrien      if (arm_ccfsm_state == 3 || arm_ccfsm_state == 4)
1101590075Sobrien	{
11016169689Skan	  if (TARGET_THUMB)
11017169689Skan	    {
11018169689Skan	      output_operand_lossage ("predicated Thumb instruction");
11019169689Skan	      break;
11020169689Skan	    }
11021169689Skan	  if (current_insn_predicate != NULL)
11022169689Skan	    {
11023169689Skan	      output_operand_lossage
11024169689Skan		("predicated instruction in conditional sequence");
11025169689Skan	      break;
11026169689Skan	    }
1102790075Sobrien
1102890075Sobrien	  fputs (arm_condition_codes[arm_current_cc], stream);
1102990075Sobrien	}
1103090075Sobrien      else if (current_insn_predicate)
1103190075Sobrien	{
1103290075Sobrien	  enum arm_cond_code code;
1103390075Sobrien
1103490075Sobrien	  if (TARGET_THUMB)
11035169689Skan	    {
11036169689Skan	      output_operand_lossage ("predicated Thumb instruction");
11037169689Skan	      break;
11038169689Skan	    }
1103990075Sobrien
1104090075Sobrien	  code = get_arm_condition_code (current_insn_predicate);
1104190075Sobrien	  fputs (arm_condition_codes[code], stream);
1104290075Sobrien	}
1104390075Sobrien      return;
1104490075Sobrien
1104590075Sobrien    case 'N':
1104690075Sobrien      {
1104790075Sobrien	REAL_VALUE_TYPE r;
1104890075Sobrien	REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1104990075Sobrien	r = REAL_VALUE_NEGATE (r);
1105090075Sobrien	fprintf (stream, "%s", fp_const_from_val (&r));
1105190075Sobrien      }
1105290075Sobrien      return;
1105390075Sobrien
1105490075Sobrien    case 'B':
1105590075Sobrien      if (GET_CODE (x) == CONST_INT)
1105690075Sobrien	{
1105790075Sobrien	  HOST_WIDE_INT val;
1105890075Sobrien	  val = ARM_SIGN_EXTEND (~INTVAL (x));
1105990075Sobrien	  fprintf (stream, HOST_WIDE_INT_PRINT_DEC, val);
1106090075Sobrien	}
1106190075Sobrien      else
1106290075Sobrien	{
1106390075Sobrien	  putc ('~', stream);
1106490075Sobrien	  output_addr_const (stream, x);
1106590075Sobrien	}
1106690075Sobrien      return;
1106790075Sobrien
1106890075Sobrien    case 'i':
1106990075Sobrien      fprintf (stream, "%s", arithmetic_instr (x, 1));
1107090075Sobrien      return;
1107190075Sobrien
11072132718Skan    /* Truncate Cirrus shift counts.  */
11073132718Skan    case 's':
11074132718Skan      if (GET_CODE (x) == CONST_INT)
11075132718Skan	{
11076132718Skan	  fprintf (stream, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) & 0x3f);
11077132718Skan	  return;
11078132718Skan	}
11079132718Skan      arm_print_operand (stream, x, 0);
11080132718Skan      return;
11081132718Skan
1108290075Sobrien    case 'I':
1108390075Sobrien      fprintf (stream, "%s", arithmetic_instr (x, 0));
1108490075Sobrien      return;
1108590075Sobrien
1108690075Sobrien    case 'S':
1108790075Sobrien      {
1108890075Sobrien	HOST_WIDE_INT val;
11089169689Skan	const char *shift;
1109090075Sobrien
11091169689Skan	if (!shift_operator (x, SImode))
11092169689Skan	  {
11093169689Skan	    output_operand_lossage ("invalid shift operand");
11094169689Skan	    break;
11095169689Skan	  }
11096169689Skan
11097169689Skan	shift = shift_op (x, &val);
11098169689Skan
1109990075Sobrien	if (shift)
1110090075Sobrien	  {
11101169689Skan	    fprintf (stream, ", %s ", shift);
1110290075Sobrien	    if (val == -1)
1110390075Sobrien	      arm_print_operand (stream, XEXP (x, 1), 0);
1110490075Sobrien	    else
11105132718Skan	      fprintf (stream, "#" HOST_WIDE_INT_PRINT_DEC, val);
1110690075Sobrien	  }
1110790075Sobrien      }
1110890075Sobrien      return;
1110990075Sobrien
1111090075Sobrien      /* An explanation of the 'Q', 'R' and 'H' register operands:
11111169689Skan
1111290075Sobrien	 In a pair of registers containing a DI or DF value the 'Q'
1111390075Sobrien	 operand returns the register number of the register containing
11114132718Skan	 the least significant part of the value.  The 'R' operand returns
1111590075Sobrien	 the register number of the register containing the most
1111690075Sobrien	 significant part of the value.
11117169689Skan
1111890075Sobrien	 The 'H' operand returns the higher of the two register numbers.
1111990075Sobrien	 On a run where WORDS_BIG_ENDIAN is true the 'H' operand is the
11120132718Skan	 same as the 'Q' operand, since the most significant part of the
1112190075Sobrien	 value is held in the lower number register.  The reverse is true
1112290075Sobrien	 on systems where WORDS_BIG_ENDIAN is false.
11123169689Skan
1112490075Sobrien	 The purpose of these operands is to distinguish between cases
1112590075Sobrien	 where the endian-ness of the values is important (for example
1112690075Sobrien	 when they are added together), and cases where the endian-ness
1112790075Sobrien	 is irrelevant, but the order of register operations is important.
1112890075Sobrien	 For example when loading a value from memory into a register
1112990075Sobrien	 pair, the endian-ness does not matter.  Provided that the value
1113090075Sobrien	 from the lower memory address is put into the lower numbered
1113190075Sobrien	 register, and the value from the higher address is put into the
1113290075Sobrien	 higher numbered register, the load will work regardless of whether
1113390075Sobrien	 the value being loaded is big-wordian or little-wordian.  The
1113490075Sobrien	 order of the two register loads can matter however, if the address
1113590075Sobrien	 of the memory location is actually held in one of the registers
1113690075Sobrien	 being overwritten by the load.  */
1113790075Sobrien    case 'Q':
11138169689Skan      if (GET_CODE (x) != REG || REGNO (x) > LAST_ARM_REGNUM)
11139169689Skan	{
11140169689Skan	  output_operand_lossage ("invalid operand for code '%c'", code);
11141169689Skan	  return;
11142169689Skan	}
11143169689Skan
1114490075Sobrien      asm_fprintf (stream, "%r", REGNO (x) + (WORDS_BIG_ENDIAN ? 1 : 0));
1114590075Sobrien      return;
1114690075Sobrien
1114790075Sobrien    case 'R':
11148169689Skan      if (GET_CODE (x) != REG || REGNO (x) > LAST_ARM_REGNUM)
11149169689Skan	{
11150169689Skan	  output_operand_lossage ("invalid operand for code '%c'", code);
11151169689Skan	  return;
11152169689Skan	}
11153169689Skan
1115490075Sobrien      asm_fprintf (stream, "%r", REGNO (x) + (WORDS_BIG_ENDIAN ? 0 : 1));
1115590075Sobrien      return;
1115690075Sobrien
1115790075Sobrien    case 'H':
11158169689Skan      if (GET_CODE (x) != REG || REGNO (x) > LAST_ARM_REGNUM)
11159169689Skan	{
11160169689Skan	  output_operand_lossage ("invalid operand for code '%c'", code);
11161169689Skan	  return;
11162169689Skan	}
11163169689Skan
1116490075Sobrien      asm_fprintf (stream, "%r", REGNO (x) + 1);
1116590075Sobrien      return;
1116690075Sobrien
1116790075Sobrien    case 'm':
11168169689Skan      asm_fprintf (stream, "%r",
1116990075Sobrien		   GET_CODE (XEXP (x, 0)) == REG
1117090075Sobrien		   ? REGNO (XEXP (x, 0)) : REGNO (XEXP (XEXP (x, 0), 0)));
1117190075Sobrien      return;
1117290075Sobrien
1117390075Sobrien    case 'M':
1117490075Sobrien      asm_fprintf (stream, "{%r-%r}",
1117590075Sobrien		   REGNO (x),
11176117395Skan		   REGNO (x) + ARM_NUM_REGS (GET_MODE (x)) - 1);
1117790075Sobrien      return;
1117890075Sobrien
1117990075Sobrien    case 'd':
11180117395Skan      /* CONST_TRUE_RTX means always -- that's the default.  */
11181117395Skan      if (x == const_true_rtx)
1118290075Sobrien	return;
11183169689Skan
11184169689Skan      if (!COMPARISON_P (x))
11185169689Skan	{
11186169689Skan	  output_operand_lossage ("invalid operand for code '%c'", code);
11187169689Skan	  return;
11188169689Skan	}
11189169689Skan
11190132718Skan      fputs (arm_condition_codes[get_arm_condition_code (x)],
11191132718Skan	     stream);
1119290075Sobrien      return;
1119390075Sobrien
1119490075Sobrien    case 'D':
11195169689Skan      /* CONST_TRUE_RTX means not always -- i.e. never.  We shouldn't ever
11196117395Skan	 want to do that.  */
11197117395Skan      if (x == const_true_rtx)
11198169689Skan	{
11199169689Skan	  output_operand_lossage ("instruction never exectued");
11200169689Skan	  return;
11201169689Skan	}
11202169689Skan      if (!COMPARISON_P (x))
11203169689Skan	{
11204169689Skan	  output_operand_lossage ("invalid operand for code '%c'", code);
11205169689Skan	  return;
11206169689Skan	}
1120790075Sobrien
11208132718Skan      fputs (arm_condition_codes[ARM_INVERSE_CONDITION_CODE
11209132718Skan				 (get_arm_condition_code (x))],
11210132718Skan	     stream);
11211132718Skan      return;
11212132718Skan
11213132718Skan    /* Cirrus registers can be accessed in a variety of ways:
11214132718Skan         single floating point (f)
11215132718Skan	 double floating point (d)
11216132718Skan	 32bit integer         (fx)
11217132718Skan	 64bit integer         (dx).  */
11218132718Skan    case 'W':			/* Cirrus register in F mode.  */
11219132718Skan    case 'X':			/* Cirrus register in D mode.  */
11220132718Skan    case 'Y':			/* Cirrus register in FX mode.  */
11221132718Skan    case 'Z':			/* Cirrus register in DX mode.  */
11222169689Skan      gcc_assert (GET_CODE (x) == REG
11223169689Skan		  && REGNO_REG_CLASS (REGNO (x)) == CIRRUS_REGS);
11224132718Skan
11225132718Skan      fprintf (stream, "mv%s%s",
11226132718Skan	       code == 'W' ? "f"
11227132718Skan	       : code == 'X' ? "d"
11228132718Skan	       : code == 'Y' ? "fx" : "dx", reg_names[REGNO (x)] + 2);
11229132718Skan
11230132718Skan      return;
11231132718Skan
11232132718Skan    /* Print cirrus register in the mode specified by the register's mode.  */
11233132718Skan    case 'V':
11234132718Skan      {
11235132718Skan	int mode = GET_MODE (x);
11236132718Skan
11237132718Skan	if (GET_CODE (x) != REG || REGNO_REG_CLASS (REGNO (x)) != CIRRUS_REGS)
11238169689Skan	  {
11239169689Skan	    output_operand_lossage ("invalid operand for code '%c'", code);
11240169689Skan	    return;
11241169689Skan	  }
11242132718Skan
11243132718Skan	fprintf (stream, "mv%s%s",
11244132718Skan		 mode == DFmode ? "d"
11245132718Skan		 : mode == SImode ? "fx"
11246132718Skan		 : mode == DImode ? "dx"
11247132718Skan		 : "f", reg_names[REGNO (x)] + 2);
11248132718Skan
11249132718Skan	return;
11250132718Skan      }
11251132718Skan
11252132718Skan    case 'U':
11253132718Skan      if (GET_CODE (x) != REG
11254132718Skan	  || REGNO (x) < FIRST_IWMMXT_GR_REGNUM
11255132718Skan	  || REGNO (x) > LAST_IWMMXT_GR_REGNUM)
11256132718Skan	/* Bad value for wCG register number.  */
11257169689Skan	{
11258169689Skan	  output_operand_lossage ("invalid operand for code '%c'", code);
11259169689Skan	  return;
11260169689Skan	}
11261169689Skan
1126290075Sobrien      else
11263132718Skan	fprintf (stream, "%d", REGNO (x) - FIRST_IWMMXT_GR_REGNUM);
1126490075Sobrien      return;
1126590075Sobrien
11266132718Skan      /* Print an iWMMXt control register name.  */
11267132718Skan    case 'w':
11268132718Skan      if (GET_CODE (x) != CONST_INT
11269132718Skan	  || INTVAL (x) < 0
11270132718Skan	  || INTVAL (x) >= 16)
11271132718Skan	/* Bad value for wC register number.  */
11272169689Skan	{
11273169689Skan	  output_operand_lossage ("invalid operand for code '%c'", code);
11274169689Skan	  return;
11275169689Skan	}
11276169689Skan
11277132718Skan      else
11278132718Skan	{
11279132718Skan	  static const char * wc_reg_names [16] =
11280132718Skan	    {
11281132718Skan	      "wCID",  "wCon",  "wCSSF", "wCASF",
11282132718Skan	      "wC4",   "wC5",   "wC6",   "wC7",
11283132718Skan	      "wCGR0", "wCGR1", "wCGR2", "wCGR3",
11284132718Skan	      "wC12",  "wC13",  "wC14",  "wC15"
11285132718Skan	    };
11286169689Skan
11287132718Skan	  fprintf (stream, wc_reg_names [INTVAL (x)]);
11288132718Skan	}
11289132718Skan      return;
11290132718Skan
11291169689Skan      /* Print a VFP double precision register name.  */
11292169689Skan    case 'P':
11293169689Skan      {
11294169689Skan	int mode = GET_MODE (x);
11295169689Skan	int num;
11296169689Skan
11297169689Skan	if (mode != DImode && mode != DFmode)
11298169689Skan	  {
11299169689Skan	    output_operand_lossage ("invalid operand for code '%c'", code);
11300169689Skan	    return;
11301169689Skan	  }
11302169689Skan
11303169689Skan	if (GET_CODE (x) != REG
11304169689Skan	    || !IS_VFP_REGNUM (REGNO (x)))
11305169689Skan	  {
11306169689Skan	    output_operand_lossage ("invalid operand for code '%c'", code);
11307169689Skan	    return;
11308169689Skan	  }
11309169689Skan
11310169689Skan	num = REGNO(x) - FIRST_VFP_REGNUM;
11311169689Skan	if (num & 1)
11312169689Skan	  {
11313169689Skan	    output_operand_lossage ("invalid operand for code '%c'", code);
11314169689Skan	    return;
11315169689Skan	  }
11316169689Skan
11317169689Skan	fprintf (stream, "d%d", num >> 1);
11318169689Skan      }
11319169689Skan      return;
11320169689Skan
1132190075Sobrien    default:
1132290075Sobrien      if (x == 0)
11323169689Skan	{
11324169689Skan	  output_operand_lossage ("missing operand");
11325169689Skan	  return;
11326169689Skan	}
1132790075Sobrien
11328169689Skan      switch (GET_CODE (x))
1132990075Sobrien	{
11330169689Skan	case REG:
11331169689Skan	  asm_fprintf (stream, "%r", REGNO (x));
11332169689Skan	  break;
11333169689Skan
11334169689Skan	case MEM:
1133590075Sobrien	  output_memory_reference_mode = GET_MODE (x);
1133690075Sobrien	  output_address (XEXP (x, 0));
11337169689Skan	  break;
11338169689Skan
11339169689Skan	case CONST_DOUBLE:
11340169689Skan	  fprintf (stream, "#%s", fp_immediate_constant (x));
11341169689Skan	  break;
11342169689Skan
11343169689Skan	default:
11344169689Skan	  gcc_assert (GET_CODE (x) != NEG);
1134590075Sobrien	  fputc ('#', stream);
1134690075Sobrien	  output_addr_const (stream, x);
11347169689Skan	  break;
1134890075Sobrien	}
1134990075Sobrien    }
1135090075Sobrien}
1135190075Sobrien
1135290075Sobrien#ifndef AOF_ASSEMBLER
1135390075Sobrien/* Target hook for assembling integer objects.  The ARM version needs to
1135490075Sobrien   handle word-sized values specially.  */
1135590075Sobrienstatic bool
11356132718Skanarm_assemble_integer (rtx x, unsigned int size, int aligned_p)
1135790075Sobrien{
1135890075Sobrien  if (size == UNITS_PER_WORD && aligned_p)
1135990075Sobrien    {
1136090075Sobrien      fputs ("\t.word\t", asm_out_file);
1136190075Sobrien      output_addr_const (asm_out_file, x);
1136290075Sobrien
1136390075Sobrien      /* Mark symbols as position independent.  We only do this in the
11364132718Skan	 .text segment, not in the .data segment.  */
1136590075Sobrien      if (NEED_GOT_RELOC && flag_pic && making_const_table &&
1136690075Sobrien	  (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF))
1136790075Sobrien	{
11368117395Skan	  if (GET_CODE (x) == SYMBOL_REF
1136996263Sobrien	      && (CONSTANT_POOL_ADDRESS_P (x)
11370132718Skan		  || SYMBOL_REF_LOCAL_P (x)))
1137190075Sobrien	    fputs ("(GOTOFF)", asm_out_file);
1137290075Sobrien	  else if (GET_CODE (x) == LABEL_REF)
1137390075Sobrien	    fputs ("(GOTOFF)", asm_out_file);
1137490075Sobrien	  else
1137590075Sobrien	    fputs ("(GOT)", asm_out_file);
1137690075Sobrien	}
1137790075Sobrien      fputc ('\n', asm_out_file);
1137890075Sobrien      return true;
1137990075Sobrien    }
1138090075Sobrien
11381169689Skan  if (arm_vector_mode_supported_p (GET_MODE (x)))
11382132718Skan    {
11383132718Skan      int i, units;
11384132718Skan
11385169689Skan      gcc_assert (GET_CODE (x) == CONST_VECTOR);
11386132718Skan
11387132718Skan      units = CONST_VECTOR_NUNITS (x);
11388132718Skan
11389132718Skan      switch (GET_MODE (x))
11390132718Skan	{
11391132718Skan	case V2SImode: size = 4; break;
11392132718Skan	case V4HImode: size = 2; break;
11393132718Skan	case V8QImode: size = 1; break;
11394132718Skan	default:
11395169689Skan	  gcc_unreachable ();
11396132718Skan	}
11397132718Skan
11398132718Skan      for (i = 0; i < units; i++)
11399132718Skan	{
11400132718Skan	  rtx elt;
11401132718Skan
11402132718Skan	  elt = CONST_VECTOR_ELT (x, i);
11403132718Skan	  assemble_integer
11404132718Skan	    (elt, size, i == 0 ? BIGGEST_ALIGNMENT : size * BITS_PER_UNIT, 1);
11405132718Skan	}
11406132718Skan
11407132718Skan      return true;
11408132718Skan    }
11409132718Skan
1141090075Sobrien  return default_assemble_integer (x, size, aligned_p);
1141190075Sobrien}
11412169689Skan
11413169689Skan
11414169689Skan/* Add a function to the list of static constructors.  */
11415169689Skan
11416169689Skanstatic void
11417169689Skanarm_elf_asm_constructor (rtx symbol, int priority ATTRIBUTE_UNUSED)
11418169689Skan{
11419169689Skan  if (!TARGET_AAPCS_BASED)
11420169689Skan    {
11421169689Skan      default_named_section_asm_out_constructor (symbol, priority);
11422169689Skan      return;
11423169689Skan    }
11424169689Skan
11425169689Skan  /* Put these in the .init_array section, using a special relocation.  */
11426169689Skan  switch_to_section (ctors_section);
11427169689Skan  assemble_align (POINTER_SIZE);
11428169689Skan  fputs ("\t.word\t", asm_out_file);
11429169689Skan  output_addr_const (asm_out_file, symbol);
11430169689Skan  fputs ("(target1)\n", asm_out_file);
11431169689Skan}
1143290075Sobrien#endif
1143390075Sobrien
1143490075Sobrien/* A finite state machine takes care of noticing whether or not instructions
1143590075Sobrien   can be conditionally executed, and thus decrease execution time and code
1143690075Sobrien   size by deleting branch instructions.  The fsm is controlled by
1143790075Sobrien   final_prescan_insn, and controls the actions of ASM_OUTPUT_OPCODE.  */
1143890075Sobrien
1143990075Sobrien/* The state of the fsm controlling condition codes are:
1144090075Sobrien   0: normal, do nothing special
1144190075Sobrien   1: make ASM_OUTPUT_OPCODE not output this instruction
1144290075Sobrien   2: make ASM_OUTPUT_OPCODE not output this instruction
1144390075Sobrien   3: make instructions conditional
1144490075Sobrien   4: make instructions conditional
1144590075Sobrien
1144690075Sobrien   State transitions (state->state by whom under condition):
1144790075Sobrien   0 -> 1 final_prescan_insn if the `target' is a label
1144890075Sobrien   0 -> 2 final_prescan_insn if the `target' is an unconditional branch
1144990075Sobrien   1 -> 3 ASM_OUTPUT_OPCODE after not having output the conditional branch
1145090075Sobrien   2 -> 4 ASM_OUTPUT_OPCODE after not having output the conditional branch
11451132718Skan   3 -> 0 (*targetm.asm_out.internal_label) if the `target' label is reached
1145290075Sobrien          (the target label has CODE_LABEL_NUMBER equal to arm_target_label).
1145390075Sobrien   4 -> 0 final_prescan_insn if the `target' unconditional branch is reached
1145490075Sobrien          (the target insn is arm_target_insn).
1145590075Sobrien
1145690075Sobrien   If the jump clobbers the conditions then we use states 2 and 4.
1145790075Sobrien
1145890075Sobrien   A similar thing can be done with conditional return insns.
1145990075Sobrien
1146090075Sobrien   XXX In case the `target' is an unconditional branch, this conditionalising
1146190075Sobrien   of the instructions always reduces code size, but not always execution
1146290075Sobrien   time.  But then, I want to reduce the code size to somewhere near what
1146390075Sobrien   /bin/cc produces.  */
1146490075Sobrien
1146590075Sobrien/* Returns the index of the ARM condition code string in
1146690075Sobrien   `arm_condition_codes'.  COMPARISON should be an rtx like
1146790075Sobrien   `(eq (...) (...))'.  */
1146890075Sobrienstatic enum arm_cond_code
11469132718Skanget_arm_condition_code (rtx comparison)
1147090075Sobrien{
1147190075Sobrien  enum machine_mode mode = GET_MODE (XEXP (comparison, 0));
1147290075Sobrien  int code;
1147390075Sobrien  enum rtx_code comp_code = GET_CODE (comparison);
1147490075Sobrien
1147590075Sobrien  if (GET_MODE_CLASS (mode) != MODE_CC)
1147690075Sobrien    mode = SELECT_CC_MODE (comp_code, XEXP (comparison, 0),
1147790075Sobrien			   XEXP (comparison, 1));
1147890075Sobrien
1147990075Sobrien  switch (mode)
1148090075Sobrien    {
1148190075Sobrien    case CC_DNEmode: code = ARM_NE; goto dominance;
1148290075Sobrien    case CC_DEQmode: code = ARM_EQ; goto dominance;
1148390075Sobrien    case CC_DGEmode: code = ARM_GE; goto dominance;
1148490075Sobrien    case CC_DGTmode: code = ARM_GT; goto dominance;
1148590075Sobrien    case CC_DLEmode: code = ARM_LE; goto dominance;
1148690075Sobrien    case CC_DLTmode: code = ARM_LT; goto dominance;
1148790075Sobrien    case CC_DGEUmode: code = ARM_CS; goto dominance;
1148890075Sobrien    case CC_DGTUmode: code = ARM_HI; goto dominance;
1148990075Sobrien    case CC_DLEUmode: code = ARM_LS; goto dominance;
1149090075Sobrien    case CC_DLTUmode: code = ARM_CC;
1149190075Sobrien
1149290075Sobrien    dominance:
11493169689Skan      gcc_assert (comp_code == EQ || comp_code == NE);
1149490075Sobrien
1149590075Sobrien      if (comp_code == EQ)
1149690075Sobrien	return ARM_INVERSE_CONDITION_CODE (code);
1149790075Sobrien      return code;
1149890075Sobrien
1149990075Sobrien    case CC_NOOVmode:
1150090075Sobrien      switch (comp_code)
1150190075Sobrien	{
1150290075Sobrien	case NE: return ARM_NE;
1150390075Sobrien	case EQ: return ARM_EQ;
1150490075Sobrien	case GE: return ARM_PL;
1150590075Sobrien	case LT: return ARM_MI;
11506169689Skan	default: gcc_unreachable ();
1150790075Sobrien	}
1150890075Sobrien
1150990075Sobrien    case CC_Zmode:
1151090075Sobrien      switch (comp_code)
1151190075Sobrien	{
1151290075Sobrien	case NE: return ARM_NE;
1151390075Sobrien	case EQ: return ARM_EQ;
11514169689Skan	default: gcc_unreachable ();
1151590075Sobrien	}
1151690075Sobrien
11517132718Skan    case CC_Nmode:
11518132718Skan      switch (comp_code)
11519132718Skan	{
11520132718Skan	case NE: return ARM_MI;
11521132718Skan	case EQ: return ARM_PL;
11522169689Skan	default: gcc_unreachable ();
11523132718Skan	}
11524132718Skan
1152590075Sobrien    case CCFPEmode:
1152690075Sobrien    case CCFPmode:
1152790075Sobrien      /* These encodings assume that AC=1 in the FPA system control
1152890075Sobrien	 byte.  This allows us to handle all cases except UNEQ and
1152990075Sobrien	 LTGT.  */
1153090075Sobrien      switch (comp_code)
1153190075Sobrien	{
1153290075Sobrien	case GE: return ARM_GE;
1153390075Sobrien	case GT: return ARM_GT;
1153490075Sobrien	case LE: return ARM_LS;
1153590075Sobrien	case LT: return ARM_MI;
1153690075Sobrien	case NE: return ARM_NE;
1153790075Sobrien	case EQ: return ARM_EQ;
1153890075Sobrien	case ORDERED: return ARM_VC;
1153990075Sobrien	case UNORDERED: return ARM_VS;
1154090075Sobrien	case UNLT: return ARM_LT;
1154190075Sobrien	case UNLE: return ARM_LE;
1154290075Sobrien	case UNGT: return ARM_HI;
1154390075Sobrien	case UNGE: return ARM_PL;
1154490075Sobrien	  /* UNEQ and LTGT do not have a representation.  */
1154590075Sobrien	case UNEQ: /* Fall through.  */
1154690075Sobrien	case LTGT: /* Fall through.  */
11547169689Skan	default: gcc_unreachable ();
1154890075Sobrien	}
1154990075Sobrien
1155090075Sobrien    case CC_SWPmode:
1155190075Sobrien      switch (comp_code)
1155290075Sobrien	{
1155390075Sobrien	case NE: return ARM_NE;
1155490075Sobrien	case EQ: return ARM_EQ;
1155590075Sobrien	case GE: return ARM_LE;
1155690075Sobrien	case GT: return ARM_LT;
1155790075Sobrien	case LE: return ARM_GE;
1155890075Sobrien	case LT: return ARM_GT;
1155990075Sobrien	case GEU: return ARM_LS;
1156090075Sobrien	case GTU: return ARM_CC;
1156190075Sobrien	case LEU: return ARM_CS;
1156290075Sobrien	case LTU: return ARM_HI;
11563169689Skan	default: gcc_unreachable ();
1156490075Sobrien	}
1156590075Sobrien
1156690075Sobrien    case CC_Cmode:
1156790075Sobrien      switch (comp_code)
1156890075Sobrien      {
1156990075Sobrien      case LTU: return ARM_CS;
1157090075Sobrien      case GEU: return ARM_CC;
11571169689Skan      default: gcc_unreachable ();
1157290075Sobrien      }
11573169689Skan
1157490075Sobrien    case CCmode:
1157590075Sobrien      switch (comp_code)
1157690075Sobrien	{
1157790075Sobrien	case NE: return ARM_NE;
1157890075Sobrien	case EQ: return ARM_EQ;
1157990075Sobrien	case GE: return ARM_GE;
1158090075Sobrien	case GT: return ARM_GT;
1158190075Sobrien	case LE: return ARM_LE;
1158290075Sobrien	case LT: return ARM_LT;
1158390075Sobrien	case GEU: return ARM_CS;
1158490075Sobrien	case GTU: return ARM_HI;
1158590075Sobrien	case LEU: return ARM_LS;
1158690075Sobrien	case LTU: return ARM_CC;
11587169689Skan	default: gcc_unreachable ();
1158890075Sobrien	}
1158990075Sobrien
11590169689Skan    default: gcc_unreachable ();
1159190075Sobrien    }
1159290075Sobrien}
1159390075Sobrien
1159490075Sobrienvoid
11595132718Skanarm_final_prescan_insn (rtx insn)
1159690075Sobrien{
1159790075Sobrien  /* BODY will hold the body of INSN.  */
1159890075Sobrien  rtx body = PATTERN (insn);
1159990075Sobrien
1160090075Sobrien  /* This will be 1 if trying to repeat the trick, and things need to be
1160190075Sobrien     reversed if it appears to fail.  */
1160290075Sobrien  int reverse = 0;
1160390075Sobrien
1160490075Sobrien  /* JUMP_CLOBBERS will be one implies that the conditions if a branch is
1160590075Sobrien     taken are clobbered, even if the rtl suggests otherwise.  It also
1160690075Sobrien     means that we have to grub around within the jump expression to find
1160790075Sobrien     out what the conditions are when the jump isn't taken.  */
1160890075Sobrien  int jump_clobbers = 0;
11609169689Skan
1161090075Sobrien  /* If we start with a return insn, we only succeed if we find another one.  */
1161190075Sobrien  int seeking_return = 0;
11612169689Skan
1161390075Sobrien  /* START_INSN will hold the insn from where we start looking.  This is the
1161490075Sobrien     first insn after the following code_label if REVERSE is true.  */
1161590075Sobrien  rtx start_insn = insn;
1161690075Sobrien
1161790075Sobrien  /* If in state 4, check if the target branch is reached, in order to
1161890075Sobrien     change back to state 0.  */
1161990075Sobrien  if (arm_ccfsm_state == 4)
1162090075Sobrien    {
1162190075Sobrien      if (insn == arm_target_insn)
1162290075Sobrien	{
1162390075Sobrien	  arm_target_insn = NULL;
1162490075Sobrien	  arm_ccfsm_state = 0;
1162590075Sobrien	}
1162690075Sobrien      return;
1162790075Sobrien    }
1162890075Sobrien
1162990075Sobrien  /* If in state 3, it is possible to repeat the trick, if this insn is an
1163090075Sobrien     unconditional branch to a label, and immediately following this branch
1163190075Sobrien     is the previous target label which is only used once, and the label this
1163290075Sobrien     branch jumps to is not too far off.  */
1163390075Sobrien  if (arm_ccfsm_state == 3)
1163490075Sobrien    {
1163590075Sobrien      if (simplejump_p (insn))
1163690075Sobrien	{
1163790075Sobrien	  start_insn = next_nonnote_insn (start_insn);
1163890075Sobrien	  if (GET_CODE (start_insn) == BARRIER)
1163990075Sobrien	    {
1164090075Sobrien	      /* XXX Isn't this always a barrier?  */
1164190075Sobrien	      start_insn = next_nonnote_insn (start_insn);
1164290075Sobrien	    }
1164390075Sobrien	  if (GET_CODE (start_insn) == CODE_LABEL
1164490075Sobrien	      && CODE_LABEL_NUMBER (start_insn) == arm_target_label
1164590075Sobrien	      && LABEL_NUSES (start_insn) == 1)
1164690075Sobrien	    reverse = TRUE;
1164790075Sobrien	  else
1164890075Sobrien	    return;
1164990075Sobrien	}
1165090075Sobrien      else if (GET_CODE (body) == RETURN)
1165190075Sobrien        {
1165290075Sobrien	  start_insn = next_nonnote_insn (start_insn);
1165390075Sobrien	  if (GET_CODE (start_insn) == BARRIER)
1165490075Sobrien	    start_insn = next_nonnote_insn (start_insn);
1165590075Sobrien	  if (GET_CODE (start_insn) == CODE_LABEL
1165690075Sobrien	      && CODE_LABEL_NUMBER (start_insn) == arm_target_label
1165790075Sobrien	      && LABEL_NUSES (start_insn) == 1)
1165890075Sobrien	    {
1165990075Sobrien	      reverse = TRUE;
1166090075Sobrien	      seeking_return = 1;
1166190075Sobrien	    }
1166290075Sobrien	  else
1166390075Sobrien	    return;
1166490075Sobrien        }
1166590075Sobrien      else
1166690075Sobrien	return;
1166790075Sobrien    }
1166890075Sobrien
11669169689Skan  gcc_assert (!arm_ccfsm_state || reverse);
1167090075Sobrien  if (GET_CODE (insn) != JUMP_INSN)
1167190075Sobrien    return;
1167290075Sobrien
11673169689Skan  /* This jump might be paralleled with a clobber of the condition codes
1167490075Sobrien     the jump should always come first */
1167590075Sobrien  if (GET_CODE (body) == PARALLEL && XVECLEN (body, 0) > 0)
1167690075Sobrien    body = XVECEXP (body, 0, 0);
1167790075Sobrien
1167890075Sobrien  if (reverse
1167990075Sobrien      || (GET_CODE (body) == SET && GET_CODE (SET_DEST (body)) == PC
1168090075Sobrien	  && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE))
1168190075Sobrien    {
1168290075Sobrien      int insns_skipped;
1168390075Sobrien      int fail = FALSE, succeed = FALSE;
1168490075Sobrien      /* Flag which part of the IF_THEN_ELSE is the LABEL_REF.  */
1168590075Sobrien      int then_not_else = TRUE;
1168690075Sobrien      rtx this_insn = start_insn, label = 0;
1168790075Sobrien
11688169689Skan      /* If the jump cannot be done with one instruction, we cannot
1168990075Sobrien	 conditionally execute the instruction in the inverse case.  */
1169090075Sobrien      if (get_attr_conds (insn) == CONDS_JUMP_CLOB)
1169190075Sobrien	{
1169290075Sobrien	  jump_clobbers = 1;
1169390075Sobrien	  return;
1169490075Sobrien	}
11695169689Skan
1169690075Sobrien      /* Register the insn jumped to.  */
1169790075Sobrien      if (reverse)
1169890075Sobrien        {
1169990075Sobrien	  if (!seeking_return)
1170090075Sobrien	    label = XEXP (SET_SRC (body), 0);
1170190075Sobrien        }
1170290075Sobrien      else if (GET_CODE (XEXP (SET_SRC (body), 1)) == LABEL_REF)
1170390075Sobrien	label = XEXP (XEXP (SET_SRC (body), 1), 0);
1170490075Sobrien      else if (GET_CODE (XEXP (SET_SRC (body), 2)) == LABEL_REF)
1170590075Sobrien	{
1170690075Sobrien	  label = XEXP (XEXP (SET_SRC (body), 2), 0);
1170790075Sobrien	  then_not_else = FALSE;
1170890075Sobrien	}
1170990075Sobrien      else if (GET_CODE (XEXP (SET_SRC (body), 1)) == RETURN)
1171090075Sobrien	seeking_return = 1;
1171190075Sobrien      else if (GET_CODE (XEXP (SET_SRC (body), 2)) == RETURN)
1171290075Sobrien        {
1171390075Sobrien	  seeking_return = 1;
1171490075Sobrien	  then_not_else = FALSE;
1171590075Sobrien        }
1171690075Sobrien      else
11717169689Skan	gcc_unreachable ();
1171890075Sobrien
1171990075Sobrien      /* See how many insns this branch skips, and what kind of insns.  If all
1172090075Sobrien	 insns are okay, and the label or unconditional branch to the same
1172190075Sobrien	 label is not too far away, succeed.  */
1172290075Sobrien      for (insns_skipped = 0;
1172390075Sobrien	   !fail && !succeed && insns_skipped++ < max_insns_skipped;)
1172490075Sobrien	{
1172590075Sobrien	  rtx scanbody;
1172690075Sobrien
1172790075Sobrien	  this_insn = next_nonnote_insn (this_insn);
1172890075Sobrien	  if (!this_insn)
1172990075Sobrien	    break;
1173090075Sobrien
1173190075Sobrien	  switch (GET_CODE (this_insn))
1173290075Sobrien	    {
1173390075Sobrien	    case CODE_LABEL:
1173490075Sobrien	      /* Succeed if it is the target label, otherwise fail since
1173590075Sobrien		 control falls in from somewhere else.  */
1173690075Sobrien	      if (this_insn == label)
1173790075Sobrien		{
1173890075Sobrien		  if (jump_clobbers)
1173990075Sobrien		    {
1174090075Sobrien		      arm_ccfsm_state = 2;
1174190075Sobrien		      this_insn = next_nonnote_insn (this_insn);
1174290075Sobrien		    }
1174390075Sobrien		  else
1174490075Sobrien		    arm_ccfsm_state = 1;
1174590075Sobrien		  succeed = TRUE;
1174690075Sobrien		}
1174790075Sobrien	      else
1174890075Sobrien		fail = TRUE;
1174990075Sobrien	      break;
1175090075Sobrien
1175190075Sobrien	    case BARRIER:
1175290075Sobrien	      /* Succeed if the following insn is the target label.
11753169689Skan		 Otherwise fail.
11754169689Skan		 If return insns are used then the last insn in a function
1175590075Sobrien		 will be a barrier.  */
1175690075Sobrien	      this_insn = next_nonnote_insn (this_insn);
1175790075Sobrien	      if (this_insn && this_insn == label)
1175890075Sobrien		{
1175990075Sobrien		  if (jump_clobbers)
1176090075Sobrien		    {
1176190075Sobrien		      arm_ccfsm_state = 2;
1176290075Sobrien		      this_insn = next_nonnote_insn (this_insn);
1176390075Sobrien		    }
1176490075Sobrien		  else
1176590075Sobrien		    arm_ccfsm_state = 1;
1176690075Sobrien		  succeed = TRUE;
1176790075Sobrien		}
1176890075Sobrien	      else
1176990075Sobrien		fail = TRUE;
1177090075Sobrien	      break;
1177190075Sobrien
1177290075Sobrien	    case CALL_INSN:
11773169689Skan	      /* The AAPCS says that conditional calls should not be
11774169689Skan		 used since they make interworking inefficient (the
11775169689Skan		 linker can't transform BL<cond> into BLX).  That's
11776169689Skan		 only a problem if the machine has BLX.  */
11777169689Skan	      if (arm_arch5)
1177890075Sobrien		{
11779169689Skan		  fail = TRUE;
11780169689Skan		  break;
11781169689Skan		}
1178290075Sobrien
11783169689Skan	      /* Succeed if the following insn is the target label, or
11784169689Skan		 if the following two insns are a barrier and the
11785169689Skan		 target label.  */
11786169689Skan	      this_insn = next_nonnote_insn (this_insn);
11787169689Skan	      if (this_insn && GET_CODE (this_insn) == BARRIER)
11788169689Skan		this_insn = next_nonnote_insn (this_insn);
11789169689Skan
11790169689Skan	      if (this_insn && this_insn == label
11791169689Skan		  && insns_skipped < max_insns_skipped)
11792169689Skan		{
11793169689Skan		  if (jump_clobbers)
1179490075Sobrien		    {
11795169689Skan		      arm_ccfsm_state = 2;
11796169689Skan		      this_insn = next_nonnote_insn (this_insn);
1179790075Sobrien		    }
1179890075Sobrien		  else
11799169689Skan		    arm_ccfsm_state = 1;
11800169689Skan		  succeed = TRUE;
1180190075Sobrien		}
11802169689Skan	      else
11803169689Skan		fail = TRUE;
1180490075Sobrien	      break;
1180590075Sobrien
1180690075Sobrien	    case JUMP_INSN:
1180790075Sobrien      	      /* If this is an unconditional branch to the same label, succeed.
1180890075Sobrien		 If it is to another label, do nothing.  If it is conditional,
1180990075Sobrien		 fail.  */
11810132718Skan	      /* XXX Probably, the tests for SET and the PC are
11811132718Skan		 unnecessary.  */
1181290075Sobrien
1181390075Sobrien	      scanbody = PATTERN (this_insn);
1181490075Sobrien	      if (GET_CODE (scanbody) == SET
1181590075Sobrien		  && GET_CODE (SET_DEST (scanbody)) == PC)
1181690075Sobrien		{
1181790075Sobrien		  if (GET_CODE (SET_SRC (scanbody)) == LABEL_REF
1181890075Sobrien		      && XEXP (SET_SRC (scanbody), 0) == label && !reverse)
1181990075Sobrien		    {
1182090075Sobrien		      arm_ccfsm_state = 2;
1182190075Sobrien		      succeed = TRUE;
1182290075Sobrien		    }
1182390075Sobrien		  else if (GET_CODE (SET_SRC (scanbody)) == IF_THEN_ELSE)
1182490075Sobrien		    fail = TRUE;
1182590075Sobrien		}
11826169689Skan	      /* Fail if a conditional return is undesirable (e.g. on a
1182790075Sobrien		 StrongARM), but still allow this if optimizing for size.  */
1182890075Sobrien	      else if (GET_CODE (scanbody) == RETURN
11829132718Skan		       && !use_return_insn (TRUE, NULL)
1183090075Sobrien		       && !optimize_size)
1183190075Sobrien		fail = TRUE;
1183290075Sobrien	      else if (GET_CODE (scanbody) == RETURN
1183390075Sobrien		       && seeking_return)
1183490075Sobrien	        {
1183590075Sobrien		  arm_ccfsm_state = 2;
1183690075Sobrien		  succeed = TRUE;
1183790075Sobrien	        }
1183890075Sobrien	      else if (GET_CODE (scanbody) == PARALLEL)
1183990075Sobrien	        {
1184090075Sobrien		  switch (get_attr_conds (this_insn))
1184190075Sobrien		    {
1184290075Sobrien		    case CONDS_NOCOND:
1184390075Sobrien		      break;
1184490075Sobrien		    default:
1184590075Sobrien		      fail = TRUE;
1184690075Sobrien		      break;
1184790075Sobrien		    }
1184890075Sobrien		}
1184990075Sobrien	      else
11850169689Skan		fail = TRUE;	/* Unrecognized jump (e.g. epilogue).  */
1185190075Sobrien
1185290075Sobrien	      break;
1185390075Sobrien
1185490075Sobrien	    case INSN:
1185590075Sobrien	      /* Instructions using or affecting the condition codes make it
1185690075Sobrien		 fail.  */
1185790075Sobrien	      scanbody = PATTERN (this_insn);
1185890075Sobrien	      if (!(GET_CODE (scanbody) == SET
1185990075Sobrien		    || GET_CODE (scanbody) == PARALLEL)
1186090075Sobrien		  || get_attr_conds (this_insn) != CONDS_NOCOND)
1186190075Sobrien		fail = TRUE;
11862132718Skan
11863132718Skan	      /* A conditional cirrus instruction must be followed by
11864132718Skan		 a non Cirrus instruction.  However, since we
11865132718Skan		 conditionalize instructions in this function and by
11866132718Skan		 the time we get here we can't add instructions
11867132718Skan		 (nops), because shorten_branches() has already been
11868132718Skan		 called, we will disable conditionalizing Cirrus
11869132718Skan		 instructions to be safe.  */
11870132718Skan	      if (GET_CODE (scanbody) != USE
11871132718Skan		  && GET_CODE (scanbody) != CLOBBER
11872132718Skan		  && get_attr_cirrus (this_insn) != CIRRUS_NOT)
11873132718Skan		fail = TRUE;
1187490075Sobrien	      break;
1187590075Sobrien
1187690075Sobrien	    default:
1187790075Sobrien	      break;
1187890075Sobrien	    }
1187990075Sobrien	}
1188090075Sobrien      if (succeed)
1188190075Sobrien	{
1188290075Sobrien	  if ((!seeking_return) && (arm_ccfsm_state == 1 || reverse))
1188390075Sobrien	    arm_target_label = CODE_LABEL_NUMBER (label);
11884169689Skan	  else
1188590075Sobrien	    {
11886169689Skan	      gcc_assert (seeking_return || arm_ccfsm_state == 2);
11887169689Skan
1188890075Sobrien	      while (this_insn && GET_CODE (PATTERN (this_insn)) == USE)
1188990075Sobrien	        {
1189090075Sobrien		  this_insn = next_nonnote_insn (this_insn);
11891169689Skan		  gcc_assert (!this_insn
11892169689Skan			      || (GET_CODE (this_insn) != BARRIER
11893169689Skan				  && GET_CODE (this_insn) != CODE_LABEL));
1189490075Sobrien	        }
1189590075Sobrien	      if (!this_insn)
1189690075Sobrien	        {
11897132718Skan		  /* Oh, dear! we ran off the end.. give up.  */
1189890075Sobrien		  recog (PATTERN (insn), insn, NULL);
1189990075Sobrien		  arm_ccfsm_state = 0;
1190090075Sobrien		  arm_target_insn = NULL;
1190190075Sobrien		  return;
1190290075Sobrien	        }
1190390075Sobrien	      arm_target_insn = this_insn;
1190490075Sobrien	    }
1190590075Sobrien	  if (jump_clobbers)
1190690075Sobrien	    {
11907169689Skan	      gcc_assert (!reverse);
11908169689Skan	      arm_current_cc =
1190990075Sobrien		  get_arm_condition_code (XEXP (XEXP (XEXP (SET_SRC (body),
1191090075Sobrien							    0), 0), 1));
1191190075Sobrien	      if (GET_CODE (XEXP (XEXP (SET_SRC (body), 0), 0)) == AND)
1191290075Sobrien		arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc);
1191390075Sobrien	      if (GET_CODE (XEXP (SET_SRC (body), 0)) == NE)
1191490075Sobrien		arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc);
1191590075Sobrien	    }
1191690075Sobrien	  else
1191790075Sobrien	    {
1191890075Sobrien	      /* If REVERSE is true, ARM_CURRENT_CC needs to be inverted from
1191990075Sobrien		 what it was.  */
1192090075Sobrien	      if (!reverse)
1192190075Sobrien		arm_current_cc = get_arm_condition_code (XEXP (SET_SRC (body),
1192290075Sobrien							       0));
1192390075Sobrien	    }
1192490075Sobrien
1192590075Sobrien	  if (reverse || then_not_else)
1192690075Sobrien	    arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc);
1192790075Sobrien	}
11928169689Skan
1192990075Sobrien      /* Restore recog_data (getting the attributes of other insns can
1193090075Sobrien	 destroy this array, but final.c assumes that it remains intact
1193190075Sobrien	 across this call; since the insn has been recognized already we
1193290075Sobrien	 call recog direct).  */
1193390075Sobrien      recog (PATTERN (insn), insn, NULL);
1193490075Sobrien    }
1193590075Sobrien}
1193690075Sobrien
1193790075Sobrien/* Returns true if REGNO is a valid register
11938169689Skan   for holding a quantity of type MODE.  */
1193990075Sobrienint
11940132718Skanarm_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
1194190075Sobrien{
1194290075Sobrien  if (GET_MODE_CLASS (mode) == MODE_CC)
11943169689Skan    return (regno == CC_REGNUM
11944169689Skan	    || (TARGET_HARD_FLOAT && TARGET_VFP
11945169689Skan		&& regno == VFPCC_REGNUM));
11946169689Skan
1194790075Sobrien  if (TARGET_THUMB)
1194890075Sobrien    /* For the Thumb we only allow values bigger than SImode in
1194990075Sobrien       registers 0 - 6, so that there is always a second low
1195090075Sobrien       register available to hold the upper part of the value.
1195190075Sobrien       We probably we ought to ensure that the register is the
1195290075Sobrien       start of an even numbered register pair.  */
11953117395Skan    return (ARM_NUM_REGS (mode) < 2) || (regno < LAST_LO_REGNUM);
1195490075Sobrien
11955169689Skan  if (TARGET_HARD_FLOAT && TARGET_MAVERICK
11956169689Skan      && IS_CIRRUS_REGNUM (regno))
11957132718Skan    /* We have outlawed SI values in Cirrus registers because they
11958132718Skan       reside in the lower 32 bits, but SF values reside in the
11959132718Skan       upper 32 bits.  This causes gcc all sorts of grief.  We can't
11960132718Skan       even split the registers into pairs because Cirrus SI values
11961132718Skan       get sign extended to 64bits-- aldyh.  */
11962132718Skan    return (GET_MODE_CLASS (mode) == MODE_FLOAT) || (mode == DImode);
11963132718Skan
11964169689Skan  if (TARGET_HARD_FLOAT && TARGET_VFP
11965169689Skan      && IS_VFP_REGNUM (regno))
11966169689Skan    {
11967169689Skan      if (mode == SFmode || mode == SImode)
11968169689Skan	return TRUE;
11969132718Skan
11970169689Skan      /* DFmode values are only valid in even register pairs.  */
11971169689Skan      if (mode == DFmode)
11972169689Skan	return ((regno - FIRST_VFP_REGNUM) & 1) == 0;
11973169689Skan      return FALSE;
11974169689Skan    }
11975132718Skan
11976169689Skan  if (TARGET_REALLY_IWMMXT)
11977169689Skan    {
11978169689Skan      if (IS_IWMMXT_GR_REGNUM (regno))
11979169689Skan	return mode == SImode;
11980169689Skan
11981169689Skan      if (IS_IWMMXT_REGNUM (regno))
11982169689Skan	return VALID_IWMMXT_REG_MODE (mode);
11983169689Skan    }
11984169689Skan
11985169689Skan  /* We allow any value to be stored in the general registers.
11986169689Skan     Restrict doubleword quantities to even register pairs so that we can
11987169689Skan     use ldrd.  */
1198890075Sobrien  if (regno <= LAST_ARM_REGNUM)
11989169689Skan    return !(TARGET_LDRD && GET_MODE_SIZE (mode) > 4 && (regno & 1) != 0);
1199090075Sobrien
11991169689Skan  if (regno == FRAME_POINTER_REGNUM
1199290075Sobrien      || regno == ARG_POINTER_REGNUM)
1199390075Sobrien    /* We only allow integers in the fake hard registers.  */
1199490075Sobrien    return GET_MODE_CLASS (mode) == MODE_INT;
1199590075Sobrien
11996132718Skan  /* The only registers left are the FPA registers
1199790075Sobrien     which we only allow to hold FP values.  */
11998169689Skan  return (TARGET_HARD_FLOAT && TARGET_FPA
11999169689Skan	  && GET_MODE_CLASS (mode) == MODE_FLOAT
12000169689Skan	  && regno >= FIRST_FPA_REGNUM
12001169689Skan	  && regno <= LAST_FPA_REGNUM);
1200290075Sobrien}
1200390075Sobrien
1200490075Sobrienint
12005132718Skanarm_regno_class (int regno)
1200690075Sobrien{
1200790075Sobrien  if (TARGET_THUMB)
1200890075Sobrien    {
1200990075Sobrien      if (regno == STACK_POINTER_REGNUM)
1201090075Sobrien	return STACK_REG;
1201190075Sobrien      if (regno == CC_REGNUM)
1201290075Sobrien	return CC_REG;
1201390075Sobrien      if (regno < 8)
1201490075Sobrien	return LO_REGS;
1201590075Sobrien      return HI_REGS;
1201690075Sobrien    }
1201790075Sobrien
1201890075Sobrien  if (   regno <= LAST_ARM_REGNUM
1201990075Sobrien      || regno == FRAME_POINTER_REGNUM
1202090075Sobrien      || regno == ARG_POINTER_REGNUM)
1202190075Sobrien    return GENERAL_REGS;
12022169689Skan
12023169689Skan  if (regno == CC_REGNUM || regno == VFPCC_REGNUM)
1202490075Sobrien    return NO_REGS;
1202590075Sobrien
12026132718Skan  if (IS_CIRRUS_REGNUM (regno))
12027132718Skan    return CIRRUS_REGS;
12028132718Skan
12029169689Skan  if (IS_VFP_REGNUM (regno))
12030169689Skan    return VFP_REGS;
12031169689Skan
12032132718Skan  if (IS_IWMMXT_REGNUM (regno))
12033132718Skan    return IWMMXT_REGS;
12034132718Skan
12035132718Skan  if (IS_IWMMXT_GR_REGNUM (regno))
12036132718Skan    return IWMMXT_GR_REGS;
12037132718Skan
12038132718Skan  return FPA_REGS;
1203990075Sobrien}
1204090075Sobrien
1204190075Sobrien/* Handle a special case when computing the offset
1204290075Sobrien   of an argument from the frame pointer.  */
1204390075Sobrienint
12044132718Skanarm_debugger_arg_offset (int value, rtx addr)
1204590075Sobrien{
1204690075Sobrien  rtx insn;
1204790075Sobrien
1204890075Sobrien  /* We are only interested if dbxout_parms() failed to compute the offset.  */
1204990075Sobrien  if (value != 0)
1205090075Sobrien    return 0;
1205190075Sobrien
1205290075Sobrien  /* We can only cope with the case where the address is held in a register.  */
1205390075Sobrien  if (GET_CODE (addr) != REG)
1205490075Sobrien    return 0;
1205590075Sobrien
1205690075Sobrien  /* If we are using the frame pointer to point at the argument, then
1205790075Sobrien     an offset of 0 is correct.  */
1205890075Sobrien  if (REGNO (addr) == (unsigned) HARD_FRAME_POINTER_REGNUM)
1205990075Sobrien    return 0;
12060169689Skan
1206190075Sobrien  /* If we are using the stack pointer to point at the
1206290075Sobrien     argument, then an offset of 0 is correct.  */
1206390075Sobrien  if ((TARGET_THUMB || !frame_pointer_needed)
1206490075Sobrien      && REGNO (addr) == SP_REGNUM)
1206590075Sobrien    return 0;
12066169689Skan
1206790075Sobrien  /* Oh dear.  The argument is pointed to by a register rather
1206890075Sobrien     than being held in a register, or being stored at a known
1206990075Sobrien     offset from the frame pointer.  Since GDB only understands
1207090075Sobrien     those two kinds of argument we must translate the address
1207190075Sobrien     held in the register into an offset from the frame pointer.
1207290075Sobrien     We do this by searching through the insns for the function
1207390075Sobrien     looking to see where this register gets its value.  If the
12074117395Skan     register is initialized from the frame pointer plus an offset
1207590075Sobrien     then we are in luck and we can continue, otherwise we give up.
12076169689Skan
1207790075Sobrien     This code is exercised by producing debugging information
1207890075Sobrien     for a function with arguments like this:
12079169689Skan
1208090075Sobrien           double func (double a, double b, int c, double d) {return d;}
12081169689Skan
1208290075Sobrien     Without this code the stab for parameter 'd' will be set to
1208390075Sobrien     an offset of 0 from the frame pointer, rather than 8.  */
1208490075Sobrien
1208590075Sobrien  /* The if() statement says:
1208690075Sobrien
1208790075Sobrien     If the insn is a normal instruction
1208890075Sobrien     and if the insn is setting the value in a register
1208990075Sobrien     and if the register being set is the register holding the address of the argument
1209090075Sobrien     and if the address is computing by an addition
1209190075Sobrien     that involves adding to a register
1209290075Sobrien     which is the frame pointer
1209390075Sobrien     a constant integer
1209490075Sobrien
12095132718Skan     then...  */
12096169689Skan
1209790075Sobrien  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
1209890075Sobrien    {
12099169689Skan      if (   GET_CODE (insn) == INSN
1210090075Sobrien	  && GET_CODE (PATTERN (insn)) == SET
1210190075Sobrien	  && REGNO    (XEXP (PATTERN (insn), 0)) == REGNO (addr)
1210290075Sobrien	  && GET_CODE (XEXP (PATTERN (insn), 1)) == PLUS
1210390075Sobrien	  && GET_CODE (XEXP (XEXP (PATTERN (insn), 1), 0)) == REG
1210490075Sobrien	  && REGNO    (XEXP (XEXP (PATTERN (insn), 1), 0)) == (unsigned) HARD_FRAME_POINTER_REGNUM
1210590075Sobrien	  && GET_CODE (XEXP (XEXP (PATTERN (insn), 1), 1)) == CONST_INT
1210690075Sobrien	     )
1210790075Sobrien	{
1210890075Sobrien	  value = INTVAL (XEXP (XEXP (PATTERN (insn), 1), 1));
12109169689Skan
1211090075Sobrien	  break;
1211190075Sobrien	}
1211290075Sobrien    }
12113169689Skan
1211490075Sobrien  if (value == 0)
1211590075Sobrien    {
1211690075Sobrien      debug_rtx (addr);
12117169689Skan      warning (0, "unable to compute real location of stacked parameter");
1211890075Sobrien      value = 8; /* XXX magic hack */
1211990075Sobrien    }
1212090075Sobrien
1212190075Sobrien  return value;
1212290075Sobrien}
12123132718Skan
12124132718Skan#define def_mbuiltin(MASK, NAME, TYPE, CODE)				\
12125132718Skan  do									\
12126132718Skan    {									\
12127132718Skan      if ((MASK) & insn_flags)						\
12128169689Skan        lang_hooks.builtin_function ((NAME), (TYPE), (CODE),		\
12129169689Skan				     BUILT_IN_MD, NULL, NULL_TREE);	\
12130132718Skan    }									\
12131132718Skan  while (0)
1213290075Sobrien
12133132718Skanstruct builtin_description
12134132718Skan{
12135132718Skan  const unsigned int       mask;
12136132718Skan  const enum insn_code     icode;
12137132718Skan  const char * const       name;
12138132718Skan  const enum arm_builtins  code;
12139132718Skan  const enum rtx_code      comparison;
12140132718Skan  const unsigned int       flag;
12141132718Skan};
1214290075Sobrien
12143132718Skanstatic const struct builtin_description bdesc_2arg[] =
1214490075Sobrien{
12145132718Skan#define IWMMXT_BUILTIN(code, string, builtin) \
12146132718Skan  { FL_IWMMXT, CODE_FOR_##code, "__builtin_arm_" string, \
12147132718Skan    ARM_BUILTIN_##builtin, 0, 0 },
12148132718Skan
12149132718Skan  IWMMXT_BUILTIN (addv8qi3, "waddb", WADDB)
12150132718Skan  IWMMXT_BUILTIN (addv4hi3, "waddh", WADDH)
12151132718Skan  IWMMXT_BUILTIN (addv2si3, "waddw", WADDW)
12152132718Skan  IWMMXT_BUILTIN (subv8qi3, "wsubb", WSUBB)
12153132718Skan  IWMMXT_BUILTIN (subv4hi3, "wsubh", WSUBH)
12154132718Skan  IWMMXT_BUILTIN (subv2si3, "wsubw", WSUBW)
12155132718Skan  IWMMXT_BUILTIN (ssaddv8qi3, "waddbss", WADDSSB)
12156132718Skan  IWMMXT_BUILTIN (ssaddv4hi3, "waddhss", WADDSSH)
12157132718Skan  IWMMXT_BUILTIN (ssaddv2si3, "waddwss", WADDSSW)
12158132718Skan  IWMMXT_BUILTIN (sssubv8qi3, "wsubbss", WSUBSSB)
12159132718Skan  IWMMXT_BUILTIN (sssubv4hi3, "wsubhss", WSUBSSH)
12160132718Skan  IWMMXT_BUILTIN (sssubv2si3, "wsubwss", WSUBSSW)
12161132718Skan  IWMMXT_BUILTIN (usaddv8qi3, "waddbus", WADDUSB)
12162132718Skan  IWMMXT_BUILTIN (usaddv4hi3, "waddhus", WADDUSH)
12163132718Skan  IWMMXT_BUILTIN (usaddv2si3, "waddwus", WADDUSW)
12164132718Skan  IWMMXT_BUILTIN (ussubv8qi3, "wsubbus", WSUBUSB)
12165132718Skan  IWMMXT_BUILTIN (ussubv4hi3, "wsubhus", WSUBUSH)
12166132718Skan  IWMMXT_BUILTIN (ussubv2si3, "wsubwus", WSUBUSW)
12167132718Skan  IWMMXT_BUILTIN (mulv4hi3, "wmulul", WMULUL)
12168169689Skan  IWMMXT_BUILTIN (smulv4hi3_highpart, "wmulsm", WMULSM)
12169169689Skan  IWMMXT_BUILTIN (umulv4hi3_highpart, "wmulum", WMULUM)
12170132718Skan  IWMMXT_BUILTIN (eqv8qi3, "wcmpeqb", WCMPEQB)
12171132718Skan  IWMMXT_BUILTIN (eqv4hi3, "wcmpeqh", WCMPEQH)
12172132718Skan  IWMMXT_BUILTIN (eqv2si3, "wcmpeqw", WCMPEQW)
12173132718Skan  IWMMXT_BUILTIN (gtuv8qi3, "wcmpgtub", WCMPGTUB)
12174132718Skan  IWMMXT_BUILTIN (gtuv4hi3, "wcmpgtuh", WCMPGTUH)
12175132718Skan  IWMMXT_BUILTIN (gtuv2si3, "wcmpgtuw", WCMPGTUW)
12176132718Skan  IWMMXT_BUILTIN (gtv8qi3, "wcmpgtsb", WCMPGTSB)
12177132718Skan  IWMMXT_BUILTIN (gtv4hi3, "wcmpgtsh", WCMPGTSH)
12178132718Skan  IWMMXT_BUILTIN (gtv2si3, "wcmpgtsw", WCMPGTSW)
12179132718Skan  IWMMXT_BUILTIN (umaxv8qi3, "wmaxub", WMAXUB)
12180132718Skan  IWMMXT_BUILTIN (smaxv8qi3, "wmaxsb", WMAXSB)
12181132718Skan  IWMMXT_BUILTIN (umaxv4hi3, "wmaxuh", WMAXUH)
12182132718Skan  IWMMXT_BUILTIN (smaxv4hi3, "wmaxsh", WMAXSH)
12183132718Skan  IWMMXT_BUILTIN (umaxv2si3, "wmaxuw", WMAXUW)
12184132718Skan  IWMMXT_BUILTIN (smaxv2si3, "wmaxsw", WMAXSW)
12185132718Skan  IWMMXT_BUILTIN (uminv8qi3, "wminub", WMINUB)
12186132718Skan  IWMMXT_BUILTIN (sminv8qi3, "wminsb", WMINSB)
12187132718Skan  IWMMXT_BUILTIN (uminv4hi3, "wminuh", WMINUH)
12188132718Skan  IWMMXT_BUILTIN (sminv4hi3, "wminsh", WMINSH)
12189132718Skan  IWMMXT_BUILTIN (uminv2si3, "wminuw", WMINUW)
12190132718Skan  IWMMXT_BUILTIN (sminv2si3, "wminsw", WMINSW)
12191132718Skan  IWMMXT_BUILTIN (iwmmxt_anddi3, "wand", WAND)
12192132718Skan  IWMMXT_BUILTIN (iwmmxt_nanddi3, "wandn", WANDN)
12193132718Skan  IWMMXT_BUILTIN (iwmmxt_iordi3, "wor", WOR)
12194132718Skan  IWMMXT_BUILTIN (iwmmxt_xordi3, "wxor", WXOR)
12195132718Skan  IWMMXT_BUILTIN (iwmmxt_uavgv8qi3, "wavg2b", WAVG2B)
12196132718Skan  IWMMXT_BUILTIN (iwmmxt_uavgv4hi3, "wavg2h", WAVG2H)
12197132718Skan  IWMMXT_BUILTIN (iwmmxt_uavgrndv8qi3, "wavg2br", WAVG2BR)
12198132718Skan  IWMMXT_BUILTIN (iwmmxt_uavgrndv4hi3, "wavg2hr", WAVG2HR)
12199132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckilb, "wunpckilb", WUNPCKILB)
12200132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckilh, "wunpckilh", WUNPCKILH)
12201132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckilw, "wunpckilw", WUNPCKILW)
12202132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckihb, "wunpckihb", WUNPCKIHB)
12203132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckihh, "wunpckihh", WUNPCKIHH)
12204132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckihw, "wunpckihw", WUNPCKIHW)
12205132718Skan  IWMMXT_BUILTIN (iwmmxt_wmadds, "wmadds", WMADDS)
12206132718Skan  IWMMXT_BUILTIN (iwmmxt_wmaddu, "wmaddu", WMADDU)
12207132718Skan
12208132718Skan#define IWMMXT_BUILTIN2(code, builtin) \
12209132718Skan  { FL_IWMMXT, CODE_FOR_##code, NULL, ARM_BUILTIN_##builtin, 0, 0 },
12210169689Skan
12211132718Skan  IWMMXT_BUILTIN2 (iwmmxt_wpackhss, WPACKHSS)
12212132718Skan  IWMMXT_BUILTIN2 (iwmmxt_wpackwss, WPACKWSS)
12213132718Skan  IWMMXT_BUILTIN2 (iwmmxt_wpackdss, WPACKDSS)
12214132718Skan  IWMMXT_BUILTIN2 (iwmmxt_wpackhus, WPACKHUS)
12215132718Skan  IWMMXT_BUILTIN2 (iwmmxt_wpackwus, WPACKWUS)
12216132718Skan  IWMMXT_BUILTIN2 (iwmmxt_wpackdus, WPACKDUS)
12217132718Skan  IWMMXT_BUILTIN2 (ashlv4hi3_di,    WSLLH)
12218132718Skan  IWMMXT_BUILTIN2 (ashlv4hi3,       WSLLHI)
12219132718Skan  IWMMXT_BUILTIN2 (ashlv2si3_di,    WSLLW)
12220132718Skan  IWMMXT_BUILTIN2 (ashlv2si3,       WSLLWI)
12221132718Skan  IWMMXT_BUILTIN2 (ashldi3_di,      WSLLD)
12222132718Skan  IWMMXT_BUILTIN2 (ashldi3_iwmmxt,  WSLLDI)
12223132718Skan  IWMMXT_BUILTIN2 (lshrv4hi3_di,    WSRLH)
12224132718Skan  IWMMXT_BUILTIN2 (lshrv4hi3,       WSRLHI)
12225132718Skan  IWMMXT_BUILTIN2 (lshrv2si3_di,    WSRLW)
12226132718Skan  IWMMXT_BUILTIN2 (lshrv2si3,       WSRLWI)
12227132718Skan  IWMMXT_BUILTIN2 (lshrdi3_di,      WSRLD)
12228169689Skan  IWMMXT_BUILTIN2 (lshrdi3_iwmmxt,  WSRLDI)
12229132718Skan  IWMMXT_BUILTIN2 (ashrv4hi3_di,    WSRAH)
12230132718Skan  IWMMXT_BUILTIN2 (ashrv4hi3,       WSRAHI)
12231132718Skan  IWMMXT_BUILTIN2 (ashrv2si3_di,    WSRAW)
12232132718Skan  IWMMXT_BUILTIN2 (ashrv2si3,       WSRAWI)
12233132718Skan  IWMMXT_BUILTIN2 (ashrdi3_di,      WSRAD)
12234169689Skan  IWMMXT_BUILTIN2 (ashrdi3_iwmmxt,  WSRADI)
12235132718Skan  IWMMXT_BUILTIN2 (rorv4hi3_di,     WRORH)
12236132718Skan  IWMMXT_BUILTIN2 (rorv4hi3,        WRORHI)
12237132718Skan  IWMMXT_BUILTIN2 (rorv2si3_di,     WRORW)
12238132718Skan  IWMMXT_BUILTIN2 (rorv2si3,        WRORWI)
12239132718Skan  IWMMXT_BUILTIN2 (rordi3_di,       WRORD)
12240132718Skan  IWMMXT_BUILTIN2 (rordi3,          WRORDI)
12241132718Skan  IWMMXT_BUILTIN2 (iwmmxt_wmacuz,   WMACUZ)
12242132718Skan  IWMMXT_BUILTIN2 (iwmmxt_wmacsz,   WMACSZ)
12243132718Skan};
12244132718Skan
12245132718Skanstatic const struct builtin_description bdesc_1arg[] =
12246132718Skan{
12247132718Skan  IWMMXT_BUILTIN (iwmmxt_tmovmskb, "tmovmskb", TMOVMSKB)
12248132718Skan  IWMMXT_BUILTIN (iwmmxt_tmovmskh, "tmovmskh", TMOVMSKH)
12249132718Skan  IWMMXT_BUILTIN (iwmmxt_tmovmskw, "tmovmskw", TMOVMSKW)
12250132718Skan  IWMMXT_BUILTIN (iwmmxt_waccb, "waccb", WACCB)
12251132718Skan  IWMMXT_BUILTIN (iwmmxt_wacch, "wacch", WACCH)
12252132718Skan  IWMMXT_BUILTIN (iwmmxt_waccw, "waccw", WACCW)
12253132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckehub, "wunpckehub", WUNPCKEHUB)
12254132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckehuh, "wunpckehuh", WUNPCKEHUH)
12255132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckehuw, "wunpckehuw", WUNPCKEHUW)
12256132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckehsb, "wunpckehsb", WUNPCKEHSB)
12257132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckehsh, "wunpckehsh", WUNPCKEHSH)
12258132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckehsw, "wunpckehsw", WUNPCKEHSW)
12259132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckelub, "wunpckelub", WUNPCKELUB)
12260132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckeluh, "wunpckeluh", WUNPCKELUH)
12261132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckeluw, "wunpckeluw", WUNPCKELUW)
12262132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckelsb, "wunpckelsb", WUNPCKELSB)
12263132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckelsh, "wunpckelsh", WUNPCKELSH)
12264132718Skan  IWMMXT_BUILTIN (iwmmxt_wunpckelsw, "wunpckelsw", WUNPCKELSW)
12265132718Skan};
12266132718Skan
12267132718Skan/* Set up all the iWMMXt builtins.  This is
12268132718Skan   not called if TARGET_IWMMXT is zero.  */
12269132718Skan
12270132718Skanstatic void
12271132718Skanarm_init_iwmmxt_builtins (void)
12272132718Skan{
12273132718Skan  const struct builtin_description * d;
12274132718Skan  size_t i;
1227590075Sobrien  tree endlink = void_list_node;
1227690075Sobrien
12277169689Skan  tree V2SI_type_node = build_vector_type_for_mode (intSI_type_node, V2SImode);
12278169689Skan  tree V4HI_type_node = build_vector_type_for_mode (intHI_type_node, V4HImode);
12279169689Skan  tree V8QI_type_node = build_vector_type_for_mode (intQI_type_node, V8QImode);
12280169689Skan
12281132718Skan  tree int_ftype_int
12282132718Skan    = build_function_type (integer_type_node,
12283132718Skan			   tree_cons (NULL_TREE, integer_type_node, endlink));
12284132718Skan  tree v8qi_ftype_v8qi_v8qi_int
12285132718Skan    = build_function_type (V8QI_type_node,
12286132718Skan			   tree_cons (NULL_TREE, V8QI_type_node,
12287132718Skan				      tree_cons (NULL_TREE, V8QI_type_node,
12288132718Skan						 tree_cons (NULL_TREE,
12289132718Skan							    integer_type_node,
12290132718Skan							    endlink))));
12291132718Skan  tree v4hi_ftype_v4hi_int
12292132718Skan    = build_function_type (V4HI_type_node,
12293132718Skan			   tree_cons (NULL_TREE, V4HI_type_node,
12294132718Skan				      tree_cons (NULL_TREE, integer_type_node,
12295132718Skan						 endlink)));
12296132718Skan  tree v2si_ftype_v2si_int
12297132718Skan    = build_function_type (V2SI_type_node,
12298132718Skan			   tree_cons (NULL_TREE, V2SI_type_node,
12299132718Skan				      tree_cons (NULL_TREE, integer_type_node,
12300132718Skan						 endlink)));
12301132718Skan  tree v2si_ftype_di_di
12302132718Skan    = build_function_type (V2SI_type_node,
12303132718Skan			   tree_cons (NULL_TREE, long_long_integer_type_node,
12304132718Skan				      tree_cons (NULL_TREE, long_long_integer_type_node,
12305132718Skan						 endlink)));
12306132718Skan  tree di_ftype_di_int
12307132718Skan    = build_function_type (long_long_integer_type_node,
12308132718Skan			   tree_cons (NULL_TREE, long_long_integer_type_node,
12309132718Skan				      tree_cons (NULL_TREE, integer_type_node,
12310132718Skan						 endlink)));
12311132718Skan  tree di_ftype_di_int_int
12312132718Skan    = build_function_type (long_long_integer_type_node,
12313132718Skan			   tree_cons (NULL_TREE, long_long_integer_type_node,
12314132718Skan				      tree_cons (NULL_TREE, integer_type_node,
12315132718Skan						 tree_cons (NULL_TREE,
12316132718Skan							    integer_type_node,
12317132718Skan							    endlink))));
12318132718Skan  tree int_ftype_v8qi
12319132718Skan    = build_function_type (integer_type_node,
12320132718Skan			   tree_cons (NULL_TREE, V8QI_type_node,
12321132718Skan				      endlink));
12322132718Skan  tree int_ftype_v4hi
12323132718Skan    = build_function_type (integer_type_node,
12324132718Skan			   tree_cons (NULL_TREE, V4HI_type_node,
12325132718Skan				      endlink));
12326132718Skan  tree int_ftype_v2si
12327132718Skan    = build_function_type (integer_type_node,
12328132718Skan			   tree_cons (NULL_TREE, V2SI_type_node,
12329132718Skan				      endlink));
12330132718Skan  tree int_ftype_v8qi_int
12331132718Skan    = build_function_type (integer_type_node,
12332132718Skan			   tree_cons (NULL_TREE, V8QI_type_node,
12333132718Skan				      tree_cons (NULL_TREE, integer_type_node,
12334132718Skan						 endlink)));
12335132718Skan  tree int_ftype_v4hi_int
12336132718Skan    = build_function_type (integer_type_node,
12337132718Skan			   tree_cons (NULL_TREE, V4HI_type_node,
12338132718Skan				      tree_cons (NULL_TREE, integer_type_node,
12339132718Skan						 endlink)));
12340132718Skan  tree int_ftype_v2si_int
12341132718Skan    = build_function_type (integer_type_node,
12342132718Skan			   tree_cons (NULL_TREE, V2SI_type_node,
12343132718Skan				      tree_cons (NULL_TREE, integer_type_node,
12344132718Skan						 endlink)));
12345132718Skan  tree v8qi_ftype_v8qi_int_int
12346132718Skan    = build_function_type (V8QI_type_node,
12347132718Skan			   tree_cons (NULL_TREE, V8QI_type_node,
12348132718Skan				      tree_cons (NULL_TREE, integer_type_node,
12349132718Skan						 tree_cons (NULL_TREE,
12350132718Skan							    integer_type_node,
12351132718Skan							    endlink))));
12352132718Skan  tree v4hi_ftype_v4hi_int_int
12353132718Skan    = build_function_type (V4HI_type_node,
12354132718Skan			   tree_cons (NULL_TREE, V4HI_type_node,
12355132718Skan				      tree_cons (NULL_TREE, integer_type_node,
12356132718Skan						 tree_cons (NULL_TREE,
12357132718Skan							    integer_type_node,
12358132718Skan							    endlink))));
12359132718Skan  tree v2si_ftype_v2si_int_int
12360132718Skan    = build_function_type (V2SI_type_node,
12361132718Skan			   tree_cons (NULL_TREE, V2SI_type_node,
12362132718Skan				      tree_cons (NULL_TREE, integer_type_node,
12363132718Skan						 tree_cons (NULL_TREE,
12364132718Skan							    integer_type_node,
12365132718Skan							    endlink))));
12366132718Skan  /* Miscellaneous.  */
12367132718Skan  tree v8qi_ftype_v4hi_v4hi
12368132718Skan    = build_function_type (V8QI_type_node,
12369132718Skan			   tree_cons (NULL_TREE, V4HI_type_node,
12370132718Skan				      tree_cons (NULL_TREE, V4HI_type_node,
12371132718Skan						 endlink)));
12372132718Skan  tree v4hi_ftype_v2si_v2si
12373132718Skan    = build_function_type (V4HI_type_node,
12374132718Skan			   tree_cons (NULL_TREE, V2SI_type_node,
12375132718Skan				      tree_cons (NULL_TREE, V2SI_type_node,
12376132718Skan						 endlink)));
12377132718Skan  tree v2si_ftype_v4hi_v4hi
12378132718Skan    = build_function_type (V2SI_type_node,
12379132718Skan			   tree_cons (NULL_TREE, V4HI_type_node,
12380132718Skan				      tree_cons (NULL_TREE, V4HI_type_node,
12381132718Skan						 endlink)));
12382132718Skan  tree v2si_ftype_v8qi_v8qi
12383132718Skan    = build_function_type (V2SI_type_node,
12384132718Skan			   tree_cons (NULL_TREE, V8QI_type_node,
12385132718Skan				      tree_cons (NULL_TREE, V8QI_type_node,
12386132718Skan						 endlink)));
12387132718Skan  tree v4hi_ftype_v4hi_di
12388132718Skan    = build_function_type (V4HI_type_node,
12389132718Skan			   tree_cons (NULL_TREE, V4HI_type_node,
12390132718Skan				      tree_cons (NULL_TREE,
12391132718Skan						 long_long_integer_type_node,
12392132718Skan						 endlink)));
12393132718Skan  tree v2si_ftype_v2si_di
12394132718Skan    = build_function_type (V2SI_type_node,
12395132718Skan			   tree_cons (NULL_TREE, V2SI_type_node,
12396132718Skan				      tree_cons (NULL_TREE,
12397132718Skan						 long_long_integer_type_node,
12398132718Skan						 endlink)));
12399132718Skan  tree void_ftype_int_int
12400132718Skan    = build_function_type (void_type_node,
12401132718Skan			   tree_cons (NULL_TREE, integer_type_node,
12402132718Skan				      tree_cons (NULL_TREE, integer_type_node,
12403132718Skan						 endlink)));
12404132718Skan  tree di_ftype_void
12405132718Skan    = build_function_type (long_long_unsigned_type_node, endlink);
12406132718Skan  tree di_ftype_v8qi
12407132718Skan    = build_function_type (long_long_integer_type_node,
12408132718Skan			   tree_cons (NULL_TREE, V8QI_type_node,
12409132718Skan				      endlink));
12410132718Skan  tree di_ftype_v4hi
12411132718Skan    = build_function_type (long_long_integer_type_node,
12412132718Skan			   tree_cons (NULL_TREE, V4HI_type_node,
12413132718Skan				      endlink));
12414132718Skan  tree di_ftype_v2si
12415132718Skan    = build_function_type (long_long_integer_type_node,
12416132718Skan			   tree_cons (NULL_TREE, V2SI_type_node,
12417132718Skan				      endlink));
12418132718Skan  tree v2si_ftype_v4hi
12419132718Skan    = build_function_type (V2SI_type_node,
12420132718Skan			   tree_cons (NULL_TREE, V4HI_type_node,
12421132718Skan				      endlink));
12422132718Skan  tree v4hi_ftype_v8qi
12423132718Skan    = build_function_type (V4HI_type_node,
12424132718Skan			   tree_cons (NULL_TREE, V8QI_type_node,
12425132718Skan				      endlink));
1242690075Sobrien
12427132718Skan  tree di_ftype_di_v4hi_v4hi
12428132718Skan    = build_function_type (long_long_unsigned_type_node,
12429132718Skan			   tree_cons (NULL_TREE,
12430132718Skan				      long_long_unsigned_type_node,
12431132718Skan				      tree_cons (NULL_TREE, V4HI_type_node,
12432132718Skan						 tree_cons (NULL_TREE,
12433132718Skan							    V4HI_type_node,
12434132718Skan							    endlink))));
1243590075Sobrien
12436132718Skan  tree di_ftype_v4hi_v4hi
12437132718Skan    = build_function_type (long_long_unsigned_type_node,
12438132718Skan			   tree_cons (NULL_TREE, V4HI_type_node,
12439132718Skan				      tree_cons (NULL_TREE, V4HI_type_node,
12440132718Skan						 endlink)));
1244190075Sobrien
12442132718Skan  /* Normal vector binops.  */
12443132718Skan  tree v8qi_ftype_v8qi_v8qi
12444132718Skan    = build_function_type (V8QI_type_node,
12445132718Skan			   tree_cons (NULL_TREE, V8QI_type_node,
12446132718Skan				      tree_cons (NULL_TREE, V8QI_type_node,
12447132718Skan						 endlink)));
12448132718Skan  tree v4hi_ftype_v4hi_v4hi
12449132718Skan    = build_function_type (V4HI_type_node,
12450132718Skan			   tree_cons (NULL_TREE, V4HI_type_node,
12451132718Skan				      tree_cons (NULL_TREE, V4HI_type_node,
12452132718Skan						 endlink)));
12453132718Skan  tree v2si_ftype_v2si_v2si
12454132718Skan    = build_function_type (V2SI_type_node,
12455132718Skan			   tree_cons (NULL_TREE, V2SI_type_node,
12456132718Skan				      tree_cons (NULL_TREE, V2SI_type_node,
12457132718Skan						 endlink)));
12458132718Skan  tree di_ftype_di_di
12459132718Skan    = build_function_type (long_long_unsigned_type_node,
12460132718Skan			   tree_cons (NULL_TREE, long_long_unsigned_type_node,
12461132718Skan				      tree_cons (NULL_TREE,
12462132718Skan						 long_long_unsigned_type_node,
12463132718Skan						 endlink)));
12464132718Skan
12465132718Skan  /* Add all builtins that are more or less simple operations on two
12466132718Skan     operands.  */
12467132718Skan  for (i = 0, d = bdesc_2arg; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
12468132718Skan    {
12469132718Skan      /* Use one of the operands; the target can have a different mode for
12470132718Skan	 mask-generating compares.  */
12471132718Skan      enum machine_mode mode;
12472132718Skan      tree type;
12473132718Skan
12474132718Skan      if (d->name == 0)
12475132718Skan	continue;
12476132718Skan
12477132718Skan      mode = insn_data[d->icode].operand[1].mode;
12478132718Skan
12479132718Skan      switch (mode)
12480132718Skan	{
12481132718Skan	case V8QImode:
12482132718Skan	  type = v8qi_ftype_v8qi_v8qi;
12483132718Skan	  break;
12484132718Skan	case V4HImode:
12485132718Skan	  type = v4hi_ftype_v4hi_v4hi;
12486132718Skan	  break;
12487132718Skan	case V2SImode:
12488132718Skan	  type = v2si_ftype_v2si_v2si;
12489132718Skan	  break;
12490132718Skan	case DImode:
12491132718Skan	  type = di_ftype_di_di;
12492132718Skan	  break;
12493132718Skan
12494132718Skan	default:
12495169689Skan	  gcc_unreachable ();
12496132718Skan	}
12497132718Skan
12498132718Skan      def_mbuiltin (d->mask, d->name, type, d->code);
12499132718Skan    }
12500132718Skan
12501132718Skan  /* Add the remaining MMX insns with somewhat more complicated types.  */
12502132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wzero", di_ftype_void, ARM_BUILTIN_WZERO);
12503132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_setwcx", void_ftype_int_int, ARM_BUILTIN_SETWCX);
12504132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_getwcx", int_ftype_int, ARM_BUILTIN_GETWCX);
12505132718Skan
12506132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsllh", v4hi_ftype_v4hi_di, ARM_BUILTIN_WSLLH);
12507132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsllw", v2si_ftype_v2si_di, ARM_BUILTIN_WSLLW);
12508132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wslld", di_ftype_di_di, ARM_BUILTIN_WSLLD);
12509132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsllhi", v4hi_ftype_v4hi_int, ARM_BUILTIN_WSLLHI);
12510132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsllwi", v2si_ftype_v2si_int, ARM_BUILTIN_WSLLWI);
12511132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wslldi", di_ftype_di_int, ARM_BUILTIN_WSLLDI);
12512132718Skan
12513132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrlh", v4hi_ftype_v4hi_di, ARM_BUILTIN_WSRLH);
12514132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrlw", v2si_ftype_v2si_di, ARM_BUILTIN_WSRLW);
12515132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrld", di_ftype_di_di, ARM_BUILTIN_WSRLD);
12516132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrlhi", v4hi_ftype_v4hi_int, ARM_BUILTIN_WSRLHI);
12517132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrlwi", v2si_ftype_v2si_int, ARM_BUILTIN_WSRLWI);
12518132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrldi", di_ftype_di_int, ARM_BUILTIN_WSRLDI);
12519132718Skan
12520132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrah", v4hi_ftype_v4hi_di, ARM_BUILTIN_WSRAH);
12521132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsraw", v2si_ftype_v2si_di, ARM_BUILTIN_WSRAW);
12522132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrad", di_ftype_di_di, ARM_BUILTIN_WSRAD);
12523132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrahi", v4hi_ftype_v4hi_int, ARM_BUILTIN_WSRAHI);
12524132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrawi", v2si_ftype_v2si_int, ARM_BUILTIN_WSRAWI);
12525132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsradi", di_ftype_di_int, ARM_BUILTIN_WSRADI);
12526132718Skan
12527132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wrorh", v4hi_ftype_v4hi_di, ARM_BUILTIN_WRORH);
12528132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wrorw", v2si_ftype_v2si_di, ARM_BUILTIN_WRORW);
12529132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wrord", di_ftype_di_di, ARM_BUILTIN_WRORD);
12530132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wrorhi", v4hi_ftype_v4hi_int, ARM_BUILTIN_WRORHI);
12531132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wrorwi", v2si_ftype_v2si_int, ARM_BUILTIN_WRORWI);
12532132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wrordi", di_ftype_di_int, ARM_BUILTIN_WRORDI);
12533132718Skan
12534132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wshufh", v4hi_ftype_v4hi_int, ARM_BUILTIN_WSHUFH);
12535132718Skan
12536132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsadb", v2si_ftype_v8qi_v8qi, ARM_BUILTIN_WSADB);
12537132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsadh", v2si_ftype_v4hi_v4hi, ARM_BUILTIN_WSADH);
12538132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsadbz", v2si_ftype_v8qi_v8qi, ARM_BUILTIN_WSADBZ);
12539132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsadhz", v2si_ftype_v4hi_v4hi, ARM_BUILTIN_WSADHZ);
12540132718Skan
12541132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_textrmsb", int_ftype_v8qi_int, ARM_BUILTIN_TEXTRMSB);
12542132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_textrmsh", int_ftype_v4hi_int, ARM_BUILTIN_TEXTRMSH);
12543132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_textrmsw", int_ftype_v2si_int, ARM_BUILTIN_TEXTRMSW);
12544132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_textrmub", int_ftype_v8qi_int, ARM_BUILTIN_TEXTRMUB);
12545132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_textrmuh", int_ftype_v4hi_int, ARM_BUILTIN_TEXTRMUH);
12546132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_textrmuw", int_ftype_v2si_int, ARM_BUILTIN_TEXTRMUW);
12547132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tinsrb", v8qi_ftype_v8qi_int_int, ARM_BUILTIN_TINSRB);
12548132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tinsrh", v4hi_ftype_v4hi_int_int, ARM_BUILTIN_TINSRH);
12549132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tinsrw", v2si_ftype_v2si_int_int, ARM_BUILTIN_TINSRW);
12550132718Skan
12551132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_waccb", di_ftype_v8qi, ARM_BUILTIN_WACCB);
12552132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wacch", di_ftype_v4hi, ARM_BUILTIN_WACCH);
12553132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_waccw", di_ftype_v2si, ARM_BUILTIN_WACCW);
12554132718Skan
12555132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmovmskb", int_ftype_v8qi, ARM_BUILTIN_TMOVMSKB);
12556132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmovmskh", int_ftype_v4hi, ARM_BUILTIN_TMOVMSKH);
12557132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmovmskw", int_ftype_v2si, ARM_BUILTIN_TMOVMSKW);
12558132718Skan
12559132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wpackhss", v8qi_ftype_v4hi_v4hi, ARM_BUILTIN_WPACKHSS);
12560132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wpackhus", v8qi_ftype_v4hi_v4hi, ARM_BUILTIN_WPACKHUS);
12561132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wpackwus", v4hi_ftype_v2si_v2si, ARM_BUILTIN_WPACKWUS);
12562132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wpackwss", v4hi_ftype_v2si_v2si, ARM_BUILTIN_WPACKWSS);
12563132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wpackdus", v2si_ftype_di_di, ARM_BUILTIN_WPACKDUS);
12564132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wpackdss", v2si_ftype_di_di, ARM_BUILTIN_WPACKDSS);
12565132718Skan
12566132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckehub", v4hi_ftype_v8qi, ARM_BUILTIN_WUNPCKEHUB);
12567132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckehuh", v2si_ftype_v4hi, ARM_BUILTIN_WUNPCKEHUH);
12568132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckehuw", di_ftype_v2si, ARM_BUILTIN_WUNPCKEHUW);
12569132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckehsb", v4hi_ftype_v8qi, ARM_BUILTIN_WUNPCKEHSB);
12570132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckehsh", v2si_ftype_v4hi, ARM_BUILTIN_WUNPCKEHSH);
12571132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckehsw", di_ftype_v2si, ARM_BUILTIN_WUNPCKEHSW);
12572132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckelub", v4hi_ftype_v8qi, ARM_BUILTIN_WUNPCKELUB);
12573132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckeluh", v2si_ftype_v4hi, ARM_BUILTIN_WUNPCKELUH);
12574132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckeluw", di_ftype_v2si, ARM_BUILTIN_WUNPCKELUW);
12575132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckelsb", v4hi_ftype_v8qi, ARM_BUILTIN_WUNPCKELSB);
12576132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckelsh", v2si_ftype_v4hi, ARM_BUILTIN_WUNPCKELSH);
12577132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckelsw", di_ftype_v2si, ARM_BUILTIN_WUNPCKELSW);
12578132718Skan
12579132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wmacs", di_ftype_di_v4hi_v4hi, ARM_BUILTIN_WMACS);
12580132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wmacsz", di_ftype_v4hi_v4hi, ARM_BUILTIN_WMACSZ);
12581132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wmacu", di_ftype_di_v4hi_v4hi, ARM_BUILTIN_WMACU);
12582132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wmacuz", di_ftype_v4hi_v4hi, ARM_BUILTIN_WMACUZ);
12583132718Skan
12584132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_walign", v8qi_ftype_v8qi_v8qi_int, ARM_BUILTIN_WALIGN);
12585132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmia", di_ftype_di_int_int, ARM_BUILTIN_TMIA);
12586132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmiaph", di_ftype_di_int_int, ARM_BUILTIN_TMIAPH);
12587132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmiabb", di_ftype_di_int_int, ARM_BUILTIN_TMIABB);
12588132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmiabt", di_ftype_di_int_int, ARM_BUILTIN_TMIABT);
12589132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmiatb", di_ftype_di_int_int, ARM_BUILTIN_TMIATB);
12590132718Skan  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmiatt", di_ftype_di_int_int, ARM_BUILTIN_TMIATT);
1259190075Sobrien}
1259290075Sobrien
12593132718Skanstatic void
12594169689Skanarm_init_tls_builtins (void)
12595169689Skan{
12596169689Skan  tree ftype;
12597169689Skan  tree nothrow = tree_cons (get_identifier ("nothrow"), NULL, NULL);
12598169689Skan  tree const_nothrow = tree_cons (get_identifier ("const"), NULL, nothrow);
12599169689Skan
12600169689Skan  ftype = build_function_type (ptr_type_node, void_list_node);
12601169689Skan  lang_hooks.builtin_function ("__builtin_thread_pointer", ftype,
12602169689Skan			       ARM_BUILTIN_THREAD_POINTER, BUILT_IN_MD,
12603169689Skan			       NULL, const_nothrow);
12604169689Skan}
12605169689Skan
12606169689Skanstatic void
12607132718Skanarm_init_builtins (void)
12608132718Skan{
12609169689Skan  arm_init_tls_builtins ();
12610169689Skan
12611132718Skan  if (TARGET_REALLY_IWMMXT)
12612132718Skan    arm_init_iwmmxt_builtins ();
12613132718Skan}
12614132718Skan
12615132718Skan/* Errors in the source file can cause expand_expr to return const0_rtx
12616132718Skan   where we expect a vector.  To avoid crashing, use one of the vector
12617132718Skan   clear instructions.  */
12618132718Skan
12619132718Skanstatic rtx
12620132718Skansafe_vector_operand (rtx x, enum machine_mode mode)
12621132718Skan{
12622132718Skan  if (x != const0_rtx)
12623132718Skan    return x;
12624132718Skan  x = gen_reg_rtx (mode);
12625132718Skan
12626132718Skan  emit_insn (gen_iwmmxt_clrdi (mode == DImode ? x
12627132718Skan			       : gen_rtx_SUBREG (DImode, x, 0)));
12628132718Skan  return x;
12629132718Skan}
12630132718Skan
12631132718Skan/* Subroutine of arm_expand_builtin to take care of binop insns.  */
12632132718Skan
12633132718Skanstatic rtx
12634132718Skanarm_expand_binop_builtin (enum insn_code icode,
12635132718Skan			  tree arglist, rtx target)
12636132718Skan{
12637132718Skan  rtx pat;
12638132718Skan  tree arg0 = TREE_VALUE (arglist);
12639132718Skan  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
12640169689Skan  rtx op0 = expand_normal (arg0);
12641169689Skan  rtx op1 = expand_normal (arg1);
12642132718Skan  enum machine_mode tmode = insn_data[icode].operand[0].mode;
12643132718Skan  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
12644132718Skan  enum machine_mode mode1 = insn_data[icode].operand[2].mode;
12645132718Skan
12646132718Skan  if (VECTOR_MODE_P (mode0))
12647132718Skan    op0 = safe_vector_operand (op0, mode0);
12648132718Skan  if (VECTOR_MODE_P (mode1))
12649132718Skan    op1 = safe_vector_operand (op1, mode1);
12650132718Skan
12651132718Skan  if (! target
12652132718Skan      || GET_MODE (target) != tmode
12653132718Skan      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
12654132718Skan    target = gen_reg_rtx (tmode);
12655132718Skan
12656169689Skan  gcc_assert (GET_MODE (op0) == mode0 && GET_MODE (op1) == mode1);
12657132718Skan
12658132718Skan  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
12659132718Skan    op0 = copy_to_mode_reg (mode0, op0);
12660132718Skan  if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
12661132718Skan    op1 = copy_to_mode_reg (mode1, op1);
12662132718Skan
12663132718Skan  pat = GEN_FCN (icode) (target, op0, op1);
12664132718Skan  if (! pat)
12665132718Skan    return 0;
12666132718Skan  emit_insn (pat);
12667132718Skan  return target;
12668132718Skan}
12669132718Skan
12670132718Skan/* Subroutine of arm_expand_builtin to take care of unop insns.  */
12671132718Skan
12672132718Skanstatic rtx
12673132718Skanarm_expand_unop_builtin (enum insn_code icode,
12674132718Skan			 tree arglist, rtx target, int do_load)
12675132718Skan{
12676132718Skan  rtx pat;
12677132718Skan  tree arg0 = TREE_VALUE (arglist);
12678169689Skan  rtx op0 = expand_normal (arg0);
12679132718Skan  enum machine_mode tmode = insn_data[icode].operand[0].mode;
12680132718Skan  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
12681132718Skan
12682132718Skan  if (! target
12683132718Skan      || GET_MODE (target) != tmode
12684132718Skan      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
12685132718Skan    target = gen_reg_rtx (tmode);
12686132718Skan  if (do_load)
12687132718Skan    op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
12688132718Skan  else
12689132718Skan    {
12690132718Skan      if (VECTOR_MODE_P (mode0))
12691132718Skan	op0 = safe_vector_operand (op0, mode0);
12692132718Skan
12693132718Skan      if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
12694132718Skan	op0 = copy_to_mode_reg (mode0, op0);
12695132718Skan    }
12696132718Skan
12697132718Skan  pat = GEN_FCN (icode) (target, op0);
12698132718Skan  if (! pat)
12699132718Skan    return 0;
12700132718Skan  emit_insn (pat);
12701132718Skan  return target;
12702132718Skan}
12703132718Skan
1270490075Sobrien/* Expand an expression EXP that calls a built-in function,
1270590075Sobrien   with result going to TARGET if that's convenient
1270690075Sobrien   (and in mode MODE if that's convenient).
1270790075Sobrien   SUBTARGET may be used as the target for computing one of EXP's operands.
1270890075Sobrien   IGNORE is nonzero if the value is to be ignored.  */
1270990075Sobrien
12710132718Skanstatic rtx
12711132718Skanarm_expand_builtin (tree exp,
12712132718Skan		    rtx target,
12713132718Skan		    rtx subtarget ATTRIBUTE_UNUSED,
12714132718Skan		    enum machine_mode mode ATTRIBUTE_UNUSED,
12715132718Skan		    int ignore ATTRIBUTE_UNUSED)
1271690075Sobrien{
12717132718Skan  const struct builtin_description * d;
12718132718Skan  enum insn_code    icode;
12719132718Skan  tree              fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
12720132718Skan  tree              arglist = TREE_OPERAND (exp, 1);
12721132718Skan  tree              arg0;
12722132718Skan  tree              arg1;
12723132718Skan  tree              arg2;
12724132718Skan  rtx               op0;
12725132718Skan  rtx               op1;
12726132718Skan  rtx               op2;
12727132718Skan  rtx               pat;
12728132718Skan  int               fcode = DECL_FUNCTION_CODE (fndecl);
12729132718Skan  size_t            i;
12730132718Skan  enum machine_mode tmode;
12731132718Skan  enum machine_mode mode0;
12732132718Skan  enum machine_mode mode1;
12733132718Skan  enum machine_mode mode2;
1273490075Sobrien
1273590075Sobrien  switch (fcode)
1273690075Sobrien    {
12737132718Skan    case ARM_BUILTIN_TEXTRMSB:
12738132718Skan    case ARM_BUILTIN_TEXTRMUB:
12739132718Skan    case ARM_BUILTIN_TEXTRMSH:
12740132718Skan    case ARM_BUILTIN_TEXTRMUH:
12741132718Skan    case ARM_BUILTIN_TEXTRMSW:
12742132718Skan    case ARM_BUILTIN_TEXTRMUW:
12743132718Skan      icode = (fcode == ARM_BUILTIN_TEXTRMSB ? CODE_FOR_iwmmxt_textrmsb
12744132718Skan	       : fcode == ARM_BUILTIN_TEXTRMUB ? CODE_FOR_iwmmxt_textrmub
12745132718Skan	       : fcode == ARM_BUILTIN_TEXTRMSH ? CODE_FOR_iwmmxt_textrmsh
12746132718Skan	       : fcode == ARM_BUILTIN_TEXTRMUH ? CODE_FOR_iwmmxt_textrmuh
12747132718Skan	       : CODE_FOR_iwmmxt_textrmw);
12748132718Skan
1274990075Sobrien      arg0 = TREE_VALUE (arglist);
12750132718Skan      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
12751169689Skan      op0 = expand_normal (arg0);
12752169689Skan      op1 = expand_normal (arg1);
1275390075Sobrien      tmode = insn_data[icode].operand[0].mode;
1275490075Sobrien      mode0 = insn_data[icode].operand[1].mode;
12755132718Skan      mode1 = insn_data[icode].operand[2].mode;
1275690075Sobrien
1275790075Sobrien      if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
1275890075Sobrien	op0 = copy_to_mode_reg (mode0, op0);
12759132718Skan      if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
12760132718Skan	{
12761132718Skan	  /* @@@ better error message */
12762132718Skan	  error ("selector must be an immediate");
12763132718Skan	  return gen_reg_rtx (tmode);
12764132718Skan	}
1276590075Sobrien      if (target == 0
1276690075Sobrien	  || GET_MODE (target) != tmode
1276790075Sobrien	  || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
1276890075Sobrien	target = gen_reg_rtx (tmode);
12769132718Skan      pat = GEN_FCN (icode) (target, op0, op1);
1277090075Sobrien      if (! pat)
1277190075Sobrien	return 0;
1277290075Sobrien      emit_insn (pat);
1277390075Sobrien      return target;
12774132718Skan
12775132718Skan    case ARM_BUILTIN_TINSRB:
12776132718Skan    case ARM_BUILTIN_TINSRH:
12777132718Skan    case ARM_BUILTIN_TINSRW:
12778132718Skan      icode = (fcode == ARM_BUILTIN_TINSRB ? CODE_FOR_iwmmxt_tinsrb
12779132718Skan	       : fcode == ARM_BUILTIN_TINSRH ? CODE_FOR_iwmmxt_tinsrh
12780132718Skan	       : CODE_FOR_iwmmxt_tinsrw);
12781132718Skan      arg0 = TREE_VALUE (arglist);
12782132718Skan      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
12783132718Skan      arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
12784169689Skan      op0 = expand_normal (arg0);
12785169689Skan      op1 = expand_normal (arg1);
12786169689Skan      op2 = expand_normal (arg2);
12787132718Skan      tmode = insn_data[icode].operand[0].mode;
12788132718Skan      mode0 = insn_data[icode].operand[1].mode;
12789132718Skan      mode1 = insn_data[icode].operand[2].mode;
12790132718Skan      mode2 = insn_data[icode].operand[3].mode;
12791132718Skan
12792132718Skan      if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
12793132718Skan	op0 = copy_to_mode_reg (mode0, op0);
12794132718Skan      if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
12795132718Skan	op1 = copy_to_mode_reg (mode1, op1);
12796132718Skan      if (! (*insn_data[icode].operand[3].predicate) (op2, mode2))
12797132718Skan	{
12798132718Skan	  /* @@@ better error message */
12799132718Skan	  error ("selector must be an immediate");
12800132718Skan	  return const0_rtx;
12801132718Skan	}
12802132718Skan      if (target == 0
12803132718Skan	  || GET_MODE (target) != tmode
12804132718Skan	  || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
12805132718Skan	target = gen_reg_rtx (tmode);
12806132718Skan      pat = GEN_FCN (icode) (target, op0, op1, op2);
12807132718Skan      if (! pat)
12808132718Skan	return 0;
12809132718Skan      emit_insn (pat);
12810132718Skan      return target;
12811132718Skan
12812132718Skan    case ARM_BUILTIN_SETWCX:
12813132718Skan      arg0 = TREE_VALUE (arglist);
12814132718Skan      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
12815169689Skan      op0 = force_reg (SImode, expand_normal (arg0));
12816169689Skan      op1 = expand_normal (arg1);
12817169689Skan      emit_insn (gen_iwmmxt_tmcr (op1, op0));
12818132718Skan      return 0;
12819132718Skan
12820132718Skan    case ARM_BUILTIN_GETWCX:
12821132718Skan      arg0 = TREE_VALUE (arglist);
12822169689Skan      op0 = expand_normal (arg0);
12823132718Skan      target = gen_reg_rtx (SImode);
12824132718Skan      emit_insn (gen_iwmmxt_tmrc (target, op0));
12825132718Skan      return target;
12826132718Skan
12827132718Skan    case ARM_BUILTIN_WSHUFH:
12828132718Skan      icode = CODE_FOR_iwmmxt_wshufh;
12829132718Skan      arg0 = TREE_VALUE (arglist);
12830132718Skan      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
12831169689Skan      op0 = expand_normal (arg0);
12832169689Skan      op1 = expand_normal (arg1);
12833132718Skan      tmode = insn_data[icode].operand[0].mode;
12834132718Skan      mode1 = insn_data[icode].operand[1].mode;
12835132718Skan      mode2 = insn_data[icode].operand[2].mode;
12836132718Skan
12837132718Skan      if (! (*insn_data[icode].operand[1].predicate) (op0, mode1))
12838132718Skan	op0 = copy_to_mode_reg (mode1, op0);
12839132718Skan      if (! (*insn_data[icode].operand[2].predicate) (op1, mode2))
12840132718Skan	{
12841132718Skan	  /* @@@ better error message */
12842132718Skan	  error ("mask must be an immediate");
12843132718Skan	  return const0_rtx;
12844132718Skan	}
12845132718Skan      if (target == 0
12846132718Skan	  || GET_MODE (target) != tmode
12847132718Skan	  || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
12848132718Skan	target = gen_reg_rtx (tmode);
12849132718Skan      pat = GEN_FCN (icode) (target, op0, op1);
12850132718Skan      if (! pat)
12851132718Skan	return 0;
12852132718Skan      emit_insn (pat);
12853132718Skan      return target;
12854132718Skan
12855132718Skan    case ARM_BUILTIN_WSADB:
12856132718Skan      return arm_expand_binop_builtin (CODE_FOR_iwmmxt_wsadb, arglist, target);
12857132718Skan    case ARM_BUILTIN_WSADH:
12858132718Skan      return arm_expand_binop_builtin (CODE_FOR_iwmmxt_wsadh, arglist, target);
12859132718Skan    case ARM_BUILTIN_WSADBZ:
12860132718Skan      return arm_expand_binop_builtin (CODE_FOR_iwmmxt_wsadbz, arglist, target);
12861132718Skan    case ARM_BUILTIN_WSADHZ:
12862132718Skan      return arm_expand_binop_builtin (CODE_FOR_iwmmxt_wsadhz, arglist, target);
12863132718Skan
12864132718Skan      /* Several three-argument builtins.  */
12865132718Skan    case ARM_BUILTIN_WMACS:
12866132718Skan    case ARM_BUILTIN_WMACU:
12867132718Skan    case ARM_BUILTIN_WALIGN:
12868132718Skan    case ARM_BUILTIN_TMIA:
12869132718Skan    case ARM_BUILTIN_TMIAPH:
12870132718Skan    case ARM_BUILTIN_TMIATT:
12871132718Skan    case ARM_BUILTIN_TMIATB:
12872132718Skan    case ARM_BUILTIN_TMIABT:
12873132718Skan    case ARM_BUILTIN_TMIABB:
12874132718Skan      icode = (fcode == ARM_BUILTIN_WMACS ? CODE_FOR_iwmmxt_wmacs
12875132718Skan	       : fcode == ARM_BUILTIN_WMACU ? CODE_FOR_iwmmxt_wmacu
12876132718Skan	       : fcode == ARM_BUILTIN_TMIA ? CODE_FOR_iwmmxt_tmia
12877132718Skan	       : fcode == ARM_BUILTIN_TMIAPH ? CODE_FOR_iwmmxt_tmiaph
12878132718Skan	       : fcode == ARM_BUILTIN_TMIABB ? CODE_FOR_iwmmxt_tmiabb
12879132718Skan	       : fcode == ARM_BUILTIN_TMIABT ? CODE_FOR_iwmmxt_tmiabt
12880132718Skan	       : fcode == ARM_BUILTIN_TMIATB ? CODE_FOR_iwmmxt_tmiatb
12881132718Skan	       : fcode == ARM_BUILTIN_TMIATT ? CODE_FOR_iwmmxt_tmiatt
12882132718Skan	       : CODE_FOR_iwmmxt_walign);
12883132718Skan      arg0 = TREE_VALUE (arglist);
12884132718Skan      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
12885132718Skan      arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
12886169689Skan      op0 = expand_normal (arg0);
12887169689Skan      op1 = expand_normal (arg1);
12888169689Skan      op2 = expand_normal (arg2);
12889132718Skan      tmode = insn_data[icode].operand[0].mode;
12890132718Skan      mode0 = insn_data[icode].operand[1].mode;
12891132718Skan      mode1 = insn_data[icode].operand[2].mode;
12892132718Skan      mode2 = insn_data[icode].operand[3].mode;
12893132718Skan
12894132718Skan      if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
12895132718Skan	op0 = copy_to_mode_reg (mode0, op0);
12896132718Skan      if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
12897132718Skan	op1 = copy_to_mode_reg (mode1, op1);
12898132718Skan      if (! (*insn_data[icode].operand[3].predicate) (op2, mode2))
12899132718Skan	op2 = copy_to_mode_reg (mode2, op2);
12900132718Skan      if (target == 0
12901132718Skan	  || GET_MODE (target) != tmode
12902132718Skan	  || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
12903132718Skan	target = gen_reg_rtx (tmode);
12904132718Skan      pat = GEN_FCN (icode) (target, op0, op1, op2);
12905132718Skan      if (! pat)
12906132718Skan	return 0;
12907132718Skan      emit_insn (pat);
12908132718Skan      return target;
12909169689Skan
12910132718Skan    case ARM_BUILTIN_WZERO:
12911132718Skan      target = gen_reg_rtx (DImode);
12912132718Skan      emit_insn (gen_iwmmxt_clrdi (target));
12913132718Skan      return target;
12914132718Skan
12915169689Skan    case ARM_BUILTIN_THREAD_POINTER:
12916169689Skan      return arm_load_tp (target);
12917169689Skan
12918132718Skan    default:
12919132718Skan      break;
1292090075Sobrien    }
12921117395Skan
12922132718Skan  for (i = 0, d = bdesc_2arg; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
12923132718Skan    if (d->code == (const enum arm_builtins) fcode)
12924132718Skan      return arm_expand_binop_builtin (d->icode, arglist, target);
12925132718Skan
12926132718Skan  for (i = 0, d = bdesc_1arg; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
12927132718Skan    if (d->code == (const enum arm_builtins) fcode)
12928132718Skan      return arm_expand_unop_builtin (d->icode, arglist, target, 0);
12929132718Skan
1293090075Sobrien  /* @@@ Should really do something sensible here.  */
1293190075Sobrien  return NULL_RTX;
1293290075Sobrien}
1293390075Sobrien
1293490075Sobrien/* Return the number (counting from 0) of
1293590075Sobrien   the least significant set bit in MASK.  */
1293690075Sobrien
12937132718Skaninline static int
12938169689Skannumber_of_first_bit_set (unsigned mask)
1293990075Sobrien{
1294090075Sobrien  int bit;
1294190075Sobrien
1294290075Sobrien  for (bit = 0;
1294390075Sobrien       (mask & (1 << bit)) == 0;
1294490075Sobrien       ++bit)
1294590075Sobrien    continue;
1294690075Sobrien
1294790075Sobrien  return bit;
1294890075Sobrien}
1294990075Sobrien
12950169689Skan/* Emit code to push or pop registers to or from the stack.  F is the
12951169689Skan   assembly file.  MASK is the registers to push or pop.  PUSH is
12952169689Skan   nonzero if we should push, and zero if we should pop.  For debugging
12953169689Skan   output, if pushing, adjust CFA_OFFSET by the amount of space added
12954169689Skan   to the stack.  REAL_REGS should have the same number of bits set as
12955169689Skan   MASK, and will be used instead (in the same order) to describe which
12956169689Skan   registers were saved - this is used to mark the save slots when we
12957169689Skan   push high registers after moving them to low registers.  */
12958169689Skanstatic void
12959169689Skanthumb_pushpop (FILE *f, unsigned long mask, int push, int *cfa_offset,
12960169689Skan	       unsigned long real_regs)
12961169689Skan{
12962169689Skan  int regno;
12963169689Skan  int lo_mask = mask & 0xFF;
12964169689Skan  int pushed_words = 0;
12965169689Skan
12966169689Skan  gcc_assert (mask);
12967169689Skan
12968169689Skan  if (lo_mask == 0 && !push && (mask & (1 << PC_REGNUM)))
12969169689Skan    {
12970169689Skan      /* Special case.  Do not generate a POP PC statement here, do it in
12971169689Skan	 thumb_exit() */
12972169689Skan      thumb_exit (f, -1);
12973169689Skan      return;
12974169689Skan    }
12975169689Skan
12976169689Skan  if (ARM_EABI_UNWIND_TABLES && push)
12977169689Skan    {
12978169689Skan      fprintf (f, "\t.save\t{");
12979169689Skan      for (regno = 0; regno < 15; regno++)
12980169689Skan	{
12981169689Skan	  if (real_regs & (1 << regno))
12982169689Skan	    {
12983169689Skan	      if (real_regs & ((1 << regno) -1))
12984169689Skan		fprintf (f, ", ");
12985169689Skan	      asm_fprintf (f, "%r", regno);
12986169689Skan	    }
12987169689Skan	}
12988169689Skan      fprintf (f, "}\n");
12989169689Skan    }
12990169689Skan
12991169689Skan  fprintf (f, "\t%s\t{", push ? "push" : "pop");
12992169689Skan
12993169689Skan  /* Look at the low registers first.  */
12994169689Skan  for (regno = 0; regno <= LAST_LO_REGNUM; regno++, lo_mask >>= 1)
12995169689Skan    {
12996169689Skan      if (lo_mask & 1)
12997169689Skan	{
12998169689Skan	  asm_fprintf (f, "%r", regno);
12999169689Skan
13000169689Skan	  if ((lo_mask & ~1) != 0)
13001169689Skan	    fprintf (f, ", ");
13002169689Skan
13003169689Skan	  pushed_words++;
13004169689Skan	}
13005169689Skan    }
13006169689Skan
13007169689Skan  if (push && (mask & (1 << LR_REGNUM)))
13008169689Skan    {
13009169689Skan      /* Catch pushing the LR.  */
13010169689Skan      if (mask & 0xFF)
13011169689Skan	fprintf (f, ", ");
13012169689Skan
13013169689Skan      asm_fprintf (f, "%r", LR_REGNUM);
13014169689Skan
13015169689Skan      pushed_words++;
13016169689Skan    }
13017169689Skan  else if (!push && (mask & (1 << PC_REGNUM)))
13018169689Skan    {
13019169689Skan      /* Catch popping the PC.  */
13020169689Skan      if (TARGET_INTERWORK || TARGET_BACKTRACE
13021169689Skan	  || current_function_calls_eh_return)
13022169689Skan	{
13023169689Skan	  /* The PC is never poped directly, instead
13024169689Skan	     it is popped into r3 and then BX is used.  */
13025169689Skan	  fprintf (f, "}\n");
13026169689Skan
13027169689Skan	  thumb_exit (f, -1);
13028169689Skan
13029169689Skan	  return;
13030169689Skan	}
13031169689Skan      else
13032169689Skan	{
13033169689Skan	  if (mask & 0xFF)
13034169689Skan	    fprintf (f, ", ");
13035169689Skan
13036169689Skan	  asm_fprintf (f, "%r", PC_REGNUM);
13037169689Skan	}
13038169689Skan    }
13039169689Skan
13040169689Skan  fprintf (f, "}\n");
13041169689Skan
13042169689Skan  if (push && pushed_words && dwarf2out_do_frame ())
13043169689Skan    {
13044169689Skan      char *l = dwarf2out_cfi_label ();
13045169689Skan      int pushed_mask = real_regs;
13046169689Skan
13047169689Skan      *cfa_offset += pushed_words * 4;
13048169689Skan      dwarf2out_def_cfa (l, SP_REGNUM, *cfa_offset);
13049169689Skan
13050169689Skan      pushed_words = 0;
13051169689Skan      pushed_mask = real_regs;
13052169689Skan      for (regno = 0; regno <= 14; regno++, pushed_mask >>= 1)
13053169689Skan	{
13054169689Skan	  if (pushed_mask & 1)
13055169689Skan	    dwarf2out_reg_save (l, regno, 4 * pushed_words++ - *cfa_offset);
13056169689Skan	}
13057169689Skan    }
13058169689Skan}
13059169689Skan
1306090075Sobrien/* Generate code to return from a thumb function.
1306190075Sobrien   If 'reg_containing_return_addr' is -1, then the return address is
1306290075Sobrien   actually on the stack, at the stack pointer.  */
1306390075Sobrienstatic void
13064169689Skanthumb_exit (FILE *f, int reg_containing_return_addr)
1306590075Sobrien{
1306690075Sobrien  unsigned regs_available_for_popping;
1306790075Sobrien  unsigned regs_to_pop;
1306890075Sobrien  int pops_needed;
1306990075Sobrien  unsigned available;
1307090075Sobrien  unsigned required;
1307190075Sobrien  int mode;
1307290075Sobrien  int size;
1307390075Sobrien  int restore_a4 = FALSE;
1307490075Sobrien
1307590075Sobrien  /* Compute the registers we need to pop.  */
1307690075Sobrien  regs_to_pop = 0;
1307790075Sobrien  pops_needed = 0;
1307890075Sobrien
13079169689Skan  if (reg_containing_return_addr == -1)
1308090075Sobrien    {
1308190075Sobrien      regs_to_pop |= 1 << LR_REGNUM;
1308290075Sobrien      ++pops_needed;
1308390075Sobrien    }
1308490075Sobrien
1308590075Sobrien  if (TARGET_BACKTRACE)
1308690075Sobrien    {
1308790075Sobrien      /* Restore the (ARM) frame pointer and stack pointer.  */
1308890075Sobrien      regs_to_pop |= (1 << ARM_HARD_FRAME_POINTER_REGNUM) | (1 << SP_REGNUM);
1308990075Sobrien      pops_needed += 2;
1309090075Sobrien    }
1309190075Sobrien
1309290075Sobrien  /* If there is nothing to pop then just emit the BX instruction and
1309390075Sobrien     return.  */
1309490075Sobrien  if (pops_needed == 0)
1309590075Sobrien    {
13096169689Skan      if (current_function_calls_eh_return)
13097169689Skan	asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, ARM_EH_STACKADJ_REGNUM);
1309890075Sobrien
1309990075Sobrien      asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
1310090075Sobrien      return;
1310190075Sobrien    }
1310290075Sobrien  /* Otherwise if we are not supporting interworking and we have not created
1310390075Sobrien     a backtrace structure and the function was not entered in ARM mode then
1310490075Sobrien     just pop the return address straight into the PC.  */
1310590075Sobrien  else if (!TARGET_INTERWORK
1310690075Sobrien	   && !TARGET_BACKTRACE
13107169689Skan	   && !is_called_in_ARM_mode (current_function_decl)
13108169689Skan	   && !current_function_calls_eh_return)
1310990075Sobrien    {
13110169689Skan      asm_fprintf (f, "\tpop\t{%r}\n", PC_REGNUM);
1311190075Sobrien      return;
1311290075Sobrien    }
1311390075Sobrien
1311490075Sobrien  /* Find out how many of the (return) argument registers we can corrupt.  */
1311590075Sobrien  regs_available_for_popping = 0;
1311690075Sobrien
1311790075Sobrien  /* If returning via __builtin_eh_return, the bottom three registers
1311890075Sobrien     all contain information needed for the return.  */
13119169689Skan  if (current_function_calls_eh_return)
1312090075Sobrien    size = 12;
1312190075Sobrien  else
1312290075Sobrien    {
1312390075Sobrien      /* If we can deduce the registers used from the function's
1312490075Sobrien	 return value.  This is more reliable that examining
1312590075Sobrien	 regs_ever_live[] because that will be set if the register is
1312690075Sobrien	 ever used in the function, not just if the register is used
1312790075Sobrien	 to hold a return value.  */
1312890075Sobrien
1312990075Sobrien      if (current_function_return_rtx != 0)
1313090075Sobrien	mode = GET_MODE (current_function_return_rtx);
1313190075Sobrien      else
1313290075Sobrien	mode = DECL_MODE (DECL_RESULT (current_function_decl));
1313390075Sobrien
1313490075Sobrien      size = GET_MODE_SIZE (mode);
1313590075Sobrien
1313690075Sobrien      if (size == 0)
1313790075Sobrien	{
1313890075Sobrien	  /* In a void function we can use any argument register.
1313990075Sobrien	     In a function that returns a structure on the stack
1314090075Sobrien	     we can use the second and third argument registers.  */
1314190075Sobrien	  if (mode == VOIDmode)
1314290075Sobrien	    regs_available_for_popping =
1314390075Sobrien	      (1 << ARG_REGISTER (1))
1314490075Sobrien	      | (1 << ARG_REGISTER (2))
1314590075Sobrien	      | (1 << ARG_REGISTER (3));
1314690075Sobrien	  else
1314790075Sobrien	    regs_available_for_popping =
1314890075Sobrien	      (1 << ARG_REGISTER (2))
1314990075Sobrien	      | (1 << ARG_REGISTER (3));
1315090075Sobrien	}
1315190075Sobrien      else if (size <= 4)
1315290075Sobrien	regs_available_for_popping =
1315390075Sobrien	  (1 << ARG_REGISTER (2))
1315490075Sobrien	  | (1 << ARG_REGISTER (3));
1315590075Sobrien      else if (size <= 8)
1315690075Sobrien	regs_available_for_popping =
1315790075Sobrien	  (1 << ARG_REGISTER (3));
1315890075Sobrien    }
1315990075Sobrien
1316090075Sobrien  /* Match registers to be popped with registers into which we pop them.  */
1316190075Sobrien  for (available = regs_available_for_popping,
1316290075Sobrien       required  = regs_to_pop;
1316390075Sobrien       required != 0 && available != 0;
1316490075Sobrien       available &= ~(available & - available),
1316590075Sobrien       required  &= ~(required  & - required))
1316690075Sobrien    -- pops_needed;
1316790075Sobrien
1316890075Sobrien  /* If we have any popping registers left over, remove them.  */
1316990075Sobrien  if (available > 0)
1317090075Sobrien    regs_available_for_popping &= ~available;
13171169689Skan
1317290075Sobrien  /* Otherwise if we need another popping register we can use
1317390075Sobrien     the fourth argument register.  */
1317490075Sobrien  else if (pops_needed)
1317590075Sobrien    {
1317690075Sobrien      /* If we have not found any free argument registers and
1317790075Sobrien	 reg a4 contains the return address, we must move it.  */
1317890075Sobrien      if (regs_available_for_popping == 0
1317990075Sobrien	  && reg_containing_return_addr == LAST_ARG_REGNUM)
1318090075Sobrien	{
1318190075Sobrien	  asm_fprintf (f, "\tmov\t%r, %r\n", LR_REGNUM, LAST_ARG_REGNUM);
1318290075Sobrien	  reg_containing_return_addr = LR_REGNUM;
1318390075Sobrien	}
1318490075Sobrien      else if (size > 12)
1318590075Sobrien	{
1318690075Sobrien	  /* Register a4 is being used to hold part of the return value,
1318790075Sobrien	     but we have dire need of a free, low register.  */
1318890075Sobrien	  restore_a4 = TRUE;
13189169689Skan
1319090075Sobrien	  asm_fprintf (f, "\tmov\t%r, %r\n",IP_REGNUM, LAST_ARG_REGNUM);
1319190075Sobrien	}
13192169689Skan
1319390075Sobrien      if (reg_containing_return_addr != LAST_ARG_REGNUM)
1319490075Sobrien	{
1319590075Sobrien	  /* The fourth argument register is available.  */
1319690075Sobrien	  regs_available_for_popping |= 1 << LAST_ARG_REGNUM;
13197169689Skan
1319890075Sobrien	  --pops_needed;
1319990075Sobrien	}
1320090075Sobrien    }
1320190075Sobrien
1320290075Sobrien  /* Pop as many registers as we can.  */
13203132718Skan  thumb_pushpop (f, regs_available_for_popping, FALSE, NULL,
13204132718Skan		 regs_available_for_popping);
1320590075Sobrien
1320690075Sobrien  /* Process the registers we popped.  */
1320790075Sobrien  if (reg_containing_return_addr == -1)
1320890075Sobrien    {
1320990075Sobrien      /* The return address was popped into the lowest numbered register.  */
1321090075Sobrien      regs_to_pop &= ~(1 << LR_REGNUM);
13211169689Skan
1321290075Sobrien      reg_containing_return_addr =
1321390075Sobrien	number_of_first_bit_set (regs_available_for_popping);
1321490075Sobrien
1321590075Sobrien      /* Remove this register for the mask of available registers, so that
13216132718Skan         the return address will not be corrupted by further pops.  */
1321790075Sobrien      regs_available_for_popping &= ~(1 << reg_containing_return_addr);
1321890075Sobrien    }
1321990075Sobrien
1322090075Sobrien  /* If we popped other registers then handle them here.  */
1322190075Sobrien  if (regs_available_for_popping)
1322290075Sobrien    {
1322390075Sobrien      int frame_pointer;
13224169689Skan
1322590075Sobrien      /* Work out which register currently contains the frame pointer.  */
1322690075Sobrien      frame_pointer = number_of_first_bit_set (regs_available_for_popping);
1322790075Sobrien
1322890075Sobrien      /* Move it into the correct place.  */
1322990075Sobrien      asm_fprintf (f, "\tmov\t%r, %r\n",
1323090075Sobrien		   ARM_HARD_FRAME_POINTER_REGNUM, frame_pointer);
1323190075Sobrien
1323290075Sobrien      /* (Temporarily) remove it from the mask of popped registers.  */
1323390075Sobrien      regs_available_for_popping &= ~(1 << frame_pointer);
1323490075Sobrien      regs_to_pop &= ~(1 << ARM_HARD_FRAME_POINTER_REGNUM);
13235169689Skan
1323690075Sobrien      if (regs_available_for_popping)
1323790075Sobrien	{
1323890075Sobrien	  int stack_pointer;
13239169689Skan
1324090075Sobrien	  /* We popped the stack pointer as well,
1324190075Sobrien	     find the register that contains it.  */
1324290075Sobrien	  stack_pointer = number_of_first_bit_set (regs_available_for_popping);
1324390075Sobrien
1324490075Sobrien	  /* Move it into the stack register.  */
1324590075Sobrien	  asm_fprintf (f, "\tmov\t%r, %r\n", SP_REGNUM, stack_pointer);
13246169689Skan
1324790075Sobrien	  /* At this point we have popped all necessary registers, so
1324890075Sobrien	     do not worry about restoring regs_available_for_popping
1324990075Sobrien	     to its correct value:
1325090075Sobrien
1325190075Sobrien	     assert (pops_needed == 0)
1325290075Sobrien	     assert (regs_available_for_popping == (1 << frame_pointer))
1325390075Sobrien	     assert (regs_to_pop == (1 << STACK_POINTER))  */
1325490075Sobrien	}
1325590075Sobrien      else
1325690075Sobrien	{
1325790075Sobrien	  /* Since we have just move the popped value into the frame
1325890075Sobrien	     pointer, the popping register is available for reuse, and
1325990075Sobrien	     we know that we still have the stack pointer left to pop.  */
1326090075Sobrien	  regs_available_for_popping |= (1 << frame_pointer);
1326190075Sobrien	}
1326290075Sobrien    }
13263169689Skan
1326490075Sobrien  /* If we still have registers left on the stack, but we no longer have
1326590075Sobrien     any registers into which we can pop them, then we must move the return
1326690075Sobrien     address into the link register and make available the register that
1326790075Sobrien     contained it.  */
1326890075Sobrien  if (regs_available_for_popping == 0 && pops_needed > 0)
1326990075Sobrien    {
1327090075Sobrien      regs_available_for_popping |= 1 << reg_containing_return_addr;
13271169689Skan
1327290075Sobrien      asm_fprintf (f, "\tmov\t%r, %r\n", LR_REGNUM,
1327390075Sobrien		   reg_containing_return_addr);
13274169689Skan
1327590075Sobrien      reg_containing_return_addr = LR_REGNUM;
1327690075Sobrien    }
1327790075Sobrien
1327890075Sobrien  /* If we have registers left on the stack then pop some more.
1327990075Sobrien     We know that at most we will want to pop FP and SP.  */
1328090075Sobrien  if (pops_needed > 0)
1328190075Sobrien    {
1328290075Sobrien      int  popped_into;
1328390075Sobrien      int  move_to;
13284169689Skan
13285132718Skan      thumb_pushpop (f, regs_available_for_popping, FALSE, NULL,
13286132718Skan		     regs_available_for_popping);
1328790075Sobrien
1328890075Sobrien      /* We have popped either FP or SP.
1328990075Sobrien	 Move whichever one it is into the correct register.  */
1329090075Sobrien      popped_into = number_of_first_bit_set (regs_available_for_popping);
1329190075Sobrien      move_to     = number_of_first_bit_set (regs_to_pop);
1329290075Sobrien
1329390075Sobrien      asm_fprintf (f, "\tmov\t%r, %r\n", move_to, popped_into);
1329490075Sobrien
1329590075Sobrien      regs_to_pop &= ~(1 << move_to);
1329690075Sobrien
1329790075Sobrien      --pops_needed;
1329890075Sobrien    }
13299169689Skan
1330090075Sobrien  /* If we still have not popped everything then we must have only
1330190075Sobrien     had one register available to us and we are now popping the SP.  */
1330290075Sobrien  if (pops_needed > 0)
1330390075Sobrien    {
1330490075Sobrien      int  popped_into;
13305169689Skan
13306132718Skan      thumb_pushpop (f, regs_available_for_popping, FALSE, NULL,
13307132718Skan		     regs_available_for_popping);
1330890075Sobrien
1330990075Sobrien      popped_into = number_of_first_bit_set (regs_available_for_popping);
1331090075Sobrien
1331190075Sobrien      asm_fprintf (f, "\tmov\t%r, %r\n", SP_REGNUM, popped_into);
1331290075Sobrien      /*
1331390075Sobrien	assert (regs_to_pop == (1 << STACK_POINTER))
1331490075Sobrien	assert (pops_needed == 1)
1331590075Sobrien      */
1331690075Sobrien    }
1331790075Sobrien
1331890075Sobrien  /* If necessary restore the a4 register.  */
1331990075Sobrien  if (restore_a4)
1332090075Sobrien    {
1332190075Sobrien      if (reg_containing_return_addr != LR_REGNUM)
1332290075Sobrien	{
1332390075Sobrien	  asm_fprintf (f, "\tmov\t%r, %r\n", LR_REGNUM, LAST_ARG_REGNUM);
1332490075Sobrien	  reg_containing_return_addr = LR_REGNUM;
1332590075Sobrien	}
13326169689Skan
1332790075Sobrien      asm_fprintf (f, "\tmov\t%r, %r\n", LAST_ARG_REGNUM, IP_REGNUM);
1332890075Sobrien    }
1332990075Sobrien
13330169689Skan  if (current_function_calls_eh_return)
13331169689Skan    asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, ARM_EH_STACKADJ_REGNUM);
1333290075Sobrien
1333390075Sobrien  /* Return to caller.  */
1333490075Sobrien  asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
1333590075Sobrien}
1333690075Sobrien
1333790075Sobrien
1333890075Sobrienvoid
13339132718Skanthumb_final_prescan_insn (rtx insn)
1334090075Sobrien{
1334190075Sobrien  if (flag_print_asm_name)
1334290075Sobrien    asm_fprintf (asm_out_file, "%@ 0x%04x\n",
1334390075Sobrien		 INSN_ADDRESSES (INSN_UID (insn)));
1334490075Sobrien}
1334590075Sobrien
1334690075Sobrienint
13347132718Skanthumb_shiftable_const (unsigned HOST_WIDE_INT val)
1334890075Sobrien{
1334990075Sobrien  unsigned HOST_WIDE_INT mask = 0xff;
1335090075Sobrien  int i;
1335190075Sobrien
1335290075Sobrien  if (val == 0) /* XXX */
1335390075Sobrien    return 0;
13354169689Skan
1335590075Sobrien  for (i = 0; i < 25; i++)
1335690075Sobrien    if ((val & (mask << i)) == val)
1335790075Sobrien      return 1;
1335890075Sobrien
1335990075Sobrien  return 0;
1336090075Sobrien}
1336190075Sobrien
13362117395Skan/* Returns nonzero if the current function contains,
1336390075Sobrien   or might contain a far jump.  */
13364169689Skanstatic int
13365169689Skanthumb_far_jump_used_p (void)
1336690075Sobrien{
1336790075Sobrien  rtx insn;
1336890075Sobrien
1336990075Sobrien  /* This test is only important for leaf functions.  */
1337090075Sobrien  /* assert (!leaf_function_p ()); */
13371169689Skan
1337290075Sobrien  /* If we have already decided that far jumps may be used,
1337390075Sobrien     do not bother checking again, and always return true even if
1337490075Sobrien     it turns out that they are not being used.  Once we have made
1337590075Sobrien     the decision that far jumps are present (and that hence the link
1337690075Sobrien     register will be pushed onto the stack) we cannot go back on it.  */
1337790075Sobrien  if (cfun->machine->far_jump_used)
1337890075Sobrien    return 1;
1337990075Sobrien
1338090075Sobrien  /* If this function is not being called from the prologue/epilogue
1338190075Sobrien     generation code then it must be being called from the
1338290075Sobrien     INITIAL_ELIMINATION_OFFSET macro.  */
13383169689Skan  if (!(ARM_DOUBLEWORD_ALIGN || reload_completed))
1338490075Sobrien    {
1338590075Sobrien      /* In this case we know that we are being asked about the elimination
1338690075Sobrien	 of the arg pointer register.  If that register is not being used,
1338790075Sobrien	 then there are no arguments on the stack, and we do not have to
1338890075Sobrien	 worry that a far jump might force the prologue to push the link
1338990075Sobrien	 register, changing the stack offsets.  In this case we can just
1339090075Sobrien	 return false, since the presence of far jumps in the function will
1339190075Sobrien	 not affect stack offsets.
1339290075Sobrien
1339390075Sobrien	 If the arg pointer is live (or if it was live, but has now been
1339490075Sobrien	 eliminated and so set to dead) then we do have to test to see if
1339590075Sobrien	 the function might contain a far jump.  This test can lead to some
1339690075Sobrien	 false negatives, since before reload is completed, then length of
1339790075Sobrien	 branch instructions is not known, so gcc defaults to returning their
1339890075Sobrien	 longest length, which in turn sets the far jump attribute to true.
1339990075Sobrien
1340090075Sobrien	 A false negative will not result in bad code being generated, but it
1340190075Sobrien	 will result in a needless push and pop of the link register.  We
13402169689Skan	 hope that this does not occur too often.
13403169689Skan
13404169689Skan	 If we need doubleword stack alignment this could affect the other
13405169689Skan	 elimination offsets so we can't risk getting it wrong.  */
1340690075Sobrien      if (regs_ever_live [ARG_POINTER_REGNUM])
1340790075Sobrien	cfun->machine->arg_pointer_live = 1;
1340890075Sobrien      else if (!cfun->machine->arg_pointer_live)
1340990075Sobrien	return 0;
1341090075Sobrien    }
1341190075Sobrien
1341290075Sobrien  /* Check to see if the function contains a branch
1341390075Sobrien     insn with the far jump attribute set.  */
1341490075Sobrien  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
1341590075Sobrien    {
1341690075Sobrien      if (GET_CODE (insn) == JUMP_INSN
1341790075Sobrien	  /* Ignore tablejump patterns.  */
1341890075Sobrien	  && GET_CODE (PATTERN (insn)) != ADDR_VEC
1341990075Sobrien	  && GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC
1342090075Sobrien	  && get_attr_far_jump (insn) == FAR_JUMP_YES
1342190075Sobrien	  )
1342290075Sobrien	{
13423132718Skan	  /* Record the fact that we have decided that
1342490075Sobrien	     the function does use far jumps.  */
1342590075Sobrien	  cfun->machine->far_jump_used = 1;
1342690075Sobrien	  return 1;
1342790075Sobrien	}
1342890075Sobrien    }
13429169689Skan
1343090075Sobrien  return 0;
1343190075Sobrien}
1343290075Sobrien
13433117395Skan/* Return nonzero if FUNC must be entered in ARM mode.  */
1343490075Sobrienint
13435132718Skanis_called_in_ARM_mode (tree func)
1343690075Sobrien{
13437169689Skan  gcc_assert (TREE_CODE (func) == FUNCTION_DECL);
1343890075Sobrien
13439169689Skan  /* Ignore the problem about functions whose address is taken.  */
1344090075Sobrien  if (TARGET_CALLEE_INTERWORKING && TREE_PUBLIC (func))
1344190075Sobrien    return TRUE;
1344290075Sobrien
13443169689Skan#ifdef ARM_PE
1344490075Sobrien  return lookup_attribute ("interfacearm", DECL_ATTRIBUTES (func)) != NULL_TREE;
1344590075Sobrien#else
1344690075Sobrien  return FALSE;
1344790075Sobrien#endif
1344890075Sobrien}
1344990075Sobrien
13450132718Skan/* The bits which aren't usefully expanded as rtl.  */
1345190075Sobrienconst char *
13452132718Skanthumb_unexpanded_epilogue (void)
1345390075Sobrien{
1345490075Sobrien  int regno;
13455169689Skan  unsigned long live_regs_mask = 0;
1345690075Sobrien  int high_regs_pushed = 0;
1345790075Sobrien  int had_to_push_lr;
13458169689Skan  int size;
1345990075Sobrien
1346090075Sobrien  if (return_used_this_function)
1346190075Sobrien    return "";
1346290075Sobrien
13463117395Skan  if (IS_NAKED (arm_current_func_type ()))
13464117395Skan    return "";
13465117395Skan
13466169689Skan  live_regs_mask = thumb_compute_save_reg_mask ();
13467169689Skan  high_regs_pushed = bit_count (live_regs_mask & 0x0f00);
1346890075Sobrien
13469169689Skan  /* If we can deduce the registers used from the function's return value.
13470169689Skan     This is more reliable that examining regs_ever_live[] because that
13471169689Skan     will be set if the register is ever used in the function, not just if
13472169689Skan     the register is used to hold a return value.  */
13473169689Skan  size = arm_size_return_regs ();
1347490075Sobrien
1347590075Sobrien  /* The prolog may have pushed some high registers to use as
13476169689Skan     work registers.  e.g. the testsuite file:
1347790075Sobrien     gcc/testsuite/gcc/gcc.c-torture/execute/complex-2.c
1347890075Sobrien     compiles to produce:
1347990075Sobrien	push	{r4, r5, r6, r7, lr}
1348090075Sobrien	mov	r7, r9
1348190075Sobrien	mov	r6, r8
1348290075Sobrien	push	{r6, r7}
1348390075Sobrien     as part of the prolog.  We have to undo that pushing here.  */
13484169689Skan
1348590075Sobrien  if (high_regs_pushed)
1348690075Sobrien    {
13487169689Skan      unsigned long mask = live_regs_mask & 0xff;
1348890075Sobrien      int next_hi_reg;
1348990075Sobrien
13490169689Skan      /* The available low registers depend on the size of the value we are
13491169689Skan         returning.  */
13492169689Skan      if (size <= 12)
1349390075Sobrien	mask |=  1 << 3;
13494169689Skan      if (size <= 8)
13495169689Skan	mask |= 1 << 2;
1349690075Sobrien
1349790075Sobrien      if (mask == 0)
1349890075Sobrien	/* Oh dear!  We have no low registers into which we can pop
1349990075Sobrien           high registers!  */
1350090075Sobrien	internal_error
1350190075Sobrien	  ("no low registers available for popping high registers");
13502169689Skan
1350390075Sobrien      for (next_hi_reg = 8; next_hi_reg < 13; next_hi_reg++)
13504169689Skan	if (live_regs_mask & (1 << next_hi_reg))
1350590075Sobrien	  break;
1350690075Sobrien
1350790075Sobrien      while (high_regs_pushed)
1350890075Sobrien	{
1350990075Sobrien	  /* Find lo register(s) into which the high register(s) can
1351090075Sobrien             be popped.  */
1351190075Sobrien	  for (regno = 0; regno <= LAST_LO_REGNUM; regno++)
1351290075Sobrien	    {
1351390075Sobrien	      if (mask & (1 << regno))
1351490075Sobrien		high_regs_pushed--;
1351590075Sobrien	      if (high_regs_pushed == 0)
1351690075Sobrien		break;
1351790075Sobrien	    }
1351890075Sobrien
1351990075Sobrien	  mask &= (2 << regno) - 1;	/* A noop if regno == 8 */
1352090075Sobrien
13521132718Skan	  /* Pop the values into the low register(s).  */
13522132718Skan	  thumb_pushpop (asm_out_file, mask, 0, NULL, mask);
1352390075Sobrien
1352490075Sobrien	  /* Move the value(s) into the high registers.  */
1352590075Sobrien	  for (regno = 0; regno <= LAST_LO_REGNUM; regno++)
1352690075Sobrien	    {
1352790075Sobrien	      if (mask & (1 << regno))
1352890075Sobrien		{
1352990075Sobrien		  asm_fprintf (asm_out_file, "\tmov\t%r, %r\n", next_hi_reg,
1353090075Sobrien			       regno);
13531169689Skan
1353290075Sobrien		  for (next_hi_reg++; next_hi_reg < 13; next_hi_reg++)
13533169689Skan		    if (live_regs_mask & (1 << next_hi_reg))
1353490075Sobrien		      break;
1353590075Sobrien		}
1353690075Sobrien	    }
1353790075Sobrien	}
13538169689Skan      live_regs_mask &= ~0x0f00;
1353990075Sobrien    }
1354090075Sobrien
13541169689Skan  had_to_push_lr = (live_regs_mask & (1 << LR_REGNUM)) != 0;
13542169689Skan  live_regs_mask &= 0xff;
13543169689Skan
1354490075Sobrien  if (current_function_pretend_args_size == 0 || TARGET_BACKTRACE)
1354590075Sobrien    {
13546169689Skan      /* Pop the return address into the PC.  */
13547169689Skan      if (had_to_push_lr)
1354890075Sobrien	live_regs_mask |= 1 << PC_REGNUM;
1354990075Sobrien
1355090075Sobrien      /* Either no argument registers were pushed or a backtrace
1355190075Sobrien	 structure was created which includes an adjusted stack
1355290075Sobrien	 pointer, so just pop everything.  */
1355390075Sobrien      if (live_regs_mask)
13554132718Skan	thumb_pushpop (asm_out_file, live_regs_mask, FALSE, NULL,
13555132718Skan		       live_regs_mask);
13556169689Skan
1355790075Sobrien      /* We have either just popped the return address into the
13558169689Skan	 PC or it is was kept in LR for the entire function.  */
13559169689Skan      if (!had_to_push_lr)
13560169689Skan	thumb_exit (asm_out_file, LR_REGNUM);
1356190075Sobrien    }
1356290075Sobrien  else
1356390075Sobrien    {
1356490075Sobrien      /* Pop everything but the return address.  */
1356590075Sobrien      if (live_regs_mask)
13566132718Skan	thumb_pushpop (asm_out_file, live_regs_mask, FALSE, NULL,
13567132718Skan		       live_regs_mask);
1356890075Sobrien
1356990075Sobrien      if (had_to_push_lr)
13570169689Skan	{
13571169689Skan	  if (size > 12)
13572169689Skan	    {
13573169689Skan	      /* We have no free low regs, so save one.  */
13574169689Skan	      asm_fprintf (asm_out_file, "\tmov\t%r, %r\n", IP_REGNUM,
13575169689Skan			   LAST_ARG_REGNUM);
13576169689Skan	    }
13577169689Skan
13578169689Skan	  /* Get the return address into a temporary register.  */
13579169689Skan	  thumb_pushpop (asm_out_file, 1 << LAST_ARG_REGNUM, 0, NULL,
13580169689Skan			 1 << LAST_ARG_REGNUM);
13581169689Skan
13582169689Skan	  if (size > 12)
13583169689Skan	    {
13584169689Skan	      /* Move the return address to lr.  */
13585169689Skan	      asm_fprintf (asm_out_file, "\tmov\t%r, %r\n", LR_REGNUM,
13586169689Skan			   LAST_ARG_REGNUM);
13587169689Skan	      /* Restore the low register.  */
13588169689Skan	      asm_fprintf (asm_out_file, "\tmov\t%r, %r\n", LAST_ARG_REGNUM,
13589169689Skan			   IP_REGNUM);
13590169689Skan	      regno = LR_REGNUM;
13591169689Skan	    }
13592169689Skan	  else
13593169689Skan	    regno = LAST_ARG_REGNUM;
13594169689Skan	}
13595169689Skan      else
13596169689Skan	regno = LR_REGNUM;
13597169689Skan
1359890075Sobrien      /* Remove the argument registers that were pushed onto the stack.  */
1359990075Sobrien      asm_fprintf (asm_out_file, "\tadd\t%r, %r, #%d\n",
1360090075Sobrien		   SP_REGNUM, SP_REGNUM,
1360190075Sobrien		   current_function_pretend_args_size);
13602169689Skan
13603169689Skan      thumb_exit (asm_out_file, regno);
1360490075Sobrien    }
1360590075Sobrien
1360690075Sobrien  return "";
1360790075Sobrien}
1360890075Sobrien
1360990075Sobrien/* Functions to save and restore machine-specific function data.  */
13610117395Skanstatic struct machine_function *
13611132718Skanarm_init_machine_status (void)
1361290075Sobrien{
13613117395Skan  struct machine_function *machine;
13614117395Skan  machine = (machine_function *) ggc_alloc_cleared (sizeof (machine_function));
1361590075Sobrien
13616169689Skan#if ARM_FT_UNKNOWN != 0
13617117395Skan  machine->func_type = ARM_FT_UNKNOWN;
1361890075Sobrien#endif
13619117395Skan  return machine;
1362090075Sobrien}
1362190075Sobrien
1362290075Sobrien/* Return an RTX indicating where the return address to the
1362390075Sobrien   calling function can be found.  */
1362490075Sobrienrtx
13625132718Skanarm_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
1362690075Sobrien{
1362790075Sobrien  if (count != 0)
1362890075Sobrien    return NULL_RTX;
1362990075Sobrien
13630169689Skan  return get_hard_reg_initial_val (Pmode, LR_REGNUM);
1363190075Sobrien}
1363290075Sobrien
1363390075Sobrien/* Do anything needed before RTL is emitted for each function.  */
1363490075Sobrienvoid
13635132718Skanarm_init_expanders (void)
1363690075Sobrien{
1363790075Sobrien  /* Arrange to initialize and mark the machine per-function status.  */
1363890075Sobrien  init_machine_status = arm_init_machine_status;
13639169689Skan
13640169689Skan  /* This is to stop the combine pass optimizing away the alignment
13641169689Skan     adjustment of va_arg.  */
13642169689Skan  /* ??? It is claimed that this should not be necessary.  */
13643169689Skan  if (cfun)
13644169689Skan    mark_reg_pointer (arg_pointer_rtx, PARM_BOUNDARY);
1364590075Sobrien}
1364690075Sobrien
13647169689Skan
13648169689Skan/* Like arm_compute_initial_elimination offset.  Simpler because there
13649169689Skan   isn't an ABI specified frame pointer for Thumb.  Instead, we set it
13650169689Skan   to point at the base of the local variables after static stack
13651169689Skan   space for a function has been allocated.  */
13652169689Skan
13653117395SkanHOST_WIDE_INT
13654169689Skanthumb_compute_initial_elimination_offset (unsigned int from, unsigned int to)
13655117395Skan{
13656169689Skan  arm_stack_offsets *offsets;
13657117395Skan
13658169689Skan  offsets = arm_get_frame_offsets ();
13659117395Skan
13660169689Skan  switch (from)
13661169689Skan    {
13662169689Skan    case ARG_POINTER_REGNUM:
13663169689Skan      switch (to)
13664169689Skan	{
13665169689Skan	case STACK_POINTER_REGNUM:
13666169689Skan	  return offsets->outgoing_args - offsets->saved_args;
13667117395Skan
13668169689Skan	case FRAME_POINTER_REGNUM:
13669169689Skan	  return offsets->soft_frame - offsets->saved_args;
13670117395Skan
13671169689Skan	case ARM_HARD_FRAME_POINTER_REGNUM:
13672169689Skan	  return offsets->saved_regs - offsets->saved_args;
13673117395Skan
13674169689Skan	case THUMB_HARD_FRAME_POINTER_REGNUM:
13675169689Skan	  return offsets->locals_base - offsets->saved_args;
13676117395Skan
13677169689Skan	default:
13678169689Skan	  gcc_unreachable ();
13679169689Skan	}
13680169689Skan      break;
13681117395Skan
13682169689Skan    case FRAME_POINTER_REGNUM:
13683169689Skan      switch (to)
13684169689Skan	{
13685169689Skan	case STACK_POINTER_REGNUM:
13686169689Skan	  return offsets->outgoing_args - offsets->soft_frame;
13687117395Skan
13688169689Skan	case ARM_HARD_FRAME_POINTER_REGNUM:
13689169689Skan	  return offsets->saved_regs - offsets->soft_frame;
13690117395Skan
13691169689Skan	case THUMB_HARD_FRAME_POINTER_REGNUM:
13692169689Skan	  return offsets->locals_base - offsets->soft_frame;
13693117395Skan
13694169689Skan	default:
13695169689Skan	  gcc_unreachable ();
13696169689Skan	}
13697169689Skan      break;
13698117395Skan
13699169689Skan    default:
13700169689Skan      gcc_unreachable ();
13701117395Skan    }
13702169689Skan}
13703117395Skan
13704117395Skan
1370590075Sobrien/* Generate the rest of a function's prologue.  */
1370690075Sobrienvoid
13707132718Skanthumb_expand_prologue (void)
1370890075Sobrien{
13709132718Skan  rtx insn, dwarf;
13710132718Skan
13711169689Skan  HOST_WIDE_INT amount;
13712169689Skan  arm_stack_offsets *offsets;
1371390075Sobrien  unsigned long func_type;
13714169689Skan  int regno;
13715169689Skan  unsigned long live_regs_mask;
1371690075Sobrien
1371790075Sobrien  func_type = arm_current_func_type ();
13718169689Skan
1371990075Sobrien  /* Naked functions don't have prologues.  */
1372090075Sobrien  if (IS_NAKED (func_type))
1372190075Sobrien    return;
1372290075Sobrien
1372390075Sobrien  if (IS_INTERRUPT (func_type))
1372490075Sobrien    {
1372590075Sobrien      error ("interrupt Service Routines cannot be coded in Thumb mode");
1372690075Sobrien      return;
1372790075Sobrien    }
1372890075Sobrien
13729169689Skan  live_regs_mask = thumb_compute_save_reg_mask ();
13730169689Skan  /* Load the pic register before setting the frame pointer,
13731169689Skan     so we can use r7 as a temporary work register.  */
13732169689Skan  if (flag_pic && arm_pic_register != INVALID_REGNUM)
13733169689Skan    arm_load_pic_register (live_regs_mask);
1373490075Sobrien
13735169689Skan  if (!frame_pointer_needed && CALLER_INTERWORKING_SLOT_SIZE > 0)
13736169689Skan    emit_move_insn (gen_rtx_REG (Pmode, ARM_HARD_FRAME_POINTER_REGNUM),
13737169689Skan		    stack_pointer_rtx);
13738169689Skan
13739169689Skan  offsets = arm_get_frame_offsets ();
13740169689Skan  amount = offsets->outgoing_args - offsets->saved_regs;
1374190075Sobrien  if (amount)
1374290075Sobrien    {
1374390075Sobrien      if (amount < 512)
13744132718Skan	{
13745132718Skan	  insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
13746132718Skan					GEN_INT (- amount)));
13747132718Skan	  RTX_FRAME_RELATED_P (insn) = 1;
13748132718Skan	}
1374990075Sobrien      else
1375090075Sobrien	{
1375190075Sobrien	  rtx reg;
1375290075Sobrien
1375390075Sobrien	  /* The stack decrement is too big for an immediate value in a single
1375490075Sobrien	     insn.  In theory we could issue multiple subtracts, but after
1375590075Sobrien	     three of them it becomes more space efficient to place the full
1375690075Sobrien	     value in the constant pool and load into a register.  (Also the
1375790075Sobrien	     ARM debugger really likes to see only one stack decrement per
1375890075Sobrien	     function).  So instead we look for a scratch register into which
1375990075Sobrien	     we can load the decrement, and then we subtract this from the
1376090075Sobrien	     stack pointer.  Unfortunately on the thumb the only available
1376190075Sobrien	     scratch registers are the argument registers, and we cannot use
1376290075Sobrien	     these as they may hold arguments to the function.  Instead we
1376390075Sobrien	     attempt to locate a call preserved register which is used by this
1376490075Sobrien	     function.  If we can find one, then we know that it will have
1376590075Sobrien	     been pushed at the start of the prologue and so we can corrupt
1376690075Sobrien	     it now.  */
1376790075Sobrien	  for (regno = LAST_ARG_REGNUM + 1; regno <= LAST_LO_REGNUM; regno++)
13768169689Skan	    if (live_regs_mask & (1 << regno)
1376990075Sobrien		&& !(frame_pointer_needed
1377090075Sobrien		     && (regno == THUMB_HARD_FRAME_POINTER_REGNUM)))
1377190075Sobrien	      break;
1377290075Sobrien
13773117395Skan	  if (regno > LAST_LO_REGNUM) /* Very unlikely.  */
1377490075Sobrien	    {
13775169689Skan	      rtx spare = gen_rtx_REG (SImode, IP_REGNUM);
1377690075Sobrien
13777132718Skan	      /* Choose an arbitrary, non-argument low register.  */
13778169689Skan	      reg = gen_rtx_REG (SImode, LAST_LO_REGNUM);
1377990075Sobrien
1378090075Sobrien	      /* Save it by copying it into a high, scratch register.  */
1378190075Sobrien	      emit_insn (gen_movsi (spare, reg));
1378290075Sobrien	      /* Add a USE to stop propagate_one_insn() from barfing.  */
1378390075Sobrien	      emit_insn (gen_prologue_use (spare));
1378490075Sobrien
1378590075Sobrien	      /* Decrement the stack.  */
1378690075Sobrien	      emit_insn (gen_movsi (reg, GEN_INT (- amount)));
13787132718Skan	      insn = emit_insn (gen_addsi3 (stack_pointer_rtx,
13788132718Skan					    stack_pointer_rtx, reg));
13789132718Skan	      RTX_FRAME_RELATED_P (insn) = 1;
13790169689Skan	      dwarf = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
13791132718Skan				   plus_constant (stack_pointer_rtx,
13792169689Skan						  -amount));
13793132718Skan	      RTX_FRAME_RELATED_P (dwarf) = 1;
13794132718Skan	      REG_NOTES (insn)
13795132718Skan		= gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
13796132718Skan				     REG_NOTES (insn));
1379790075Sobrien
1379890075Sobrien	      /* Restore the low register's original value.  */
1379990075Sobrien	      emit_insn (gen_movsi (reg, spare));
13800169689Skan
1380190075Sobrien	      /* Emit a USE of the restored scratch register, so that flow
1380290075Sobrien		 analysis will not consider the restore redundant.  The
1380390075Sobrien		 register won't be used again in this function and isn't
1380490075Sobrien		 restored by the epilogue.  */
1380590075Sobrien	      emit_insn (gen_prologue_use (reg));
1380690075Sobrien	    }
1380790075Sobrien	  else
1380890075Sobrien	    {
13809169689Skan	      reg = gen_rtx_REG (SImode, regno);
1381090075Sobrien
1381190075Sobrien	      emit_insn (gen_movsi (reg, GEN_INT (- amount)));
13812132718Skan
13813132718Skan	      insn = emit_insn (gen_addsi3 (stack_pointer_rtx,
13814132718Skan					    stack_pointer_rtx, reg));
13815132718Skan	      RTX_FRAME_RELATED_P (insn) = 1;
13816169689Skan	      dwarf = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
13817132718Skan				   plus_constant (stack_pointer_rtx,
13818169689Skan						  -amount));
13819132718Skan	      RTX_FRAME_RELATED_P (dwarf) = 1;
13820132718Skan	      REG_NOTES (insn)
13821132718Skan		= gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
13822132718Skan				     REG_NOTES (insn));
1382390075Sobrien	    }
1382490075Sobrien	}
1382590075Sobrien    }
13826169689Skan
13827169689Skan  if (frame_pointer_needed)
13828169689Skan    {
13829169689Skan      amount = offsets->outgoing_args - offsets->locals_base;
13830169689Skan
13831169689Skan      if (amount < 1024)
13832169689Skan	insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx,
13833169689Skan				      stack_pointer_rtx, GEN_INT (amount)));
13834169689Skan      else
13835169689Skan	{
13836169689Skan	  emit_insn (gen_movsi (hard_frame_pointer_rtx, GEN_INT (amount)));
13837169689Skan	  insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx,
13838169689Skan					hard_frame_pointer_rtx,
13839169689Skan					stack_pointer_rtx));
13840169689Skan	  dwarf = gen_rtx_SET (VOIDmode, hard_frame_pointer_rtx,
13841169689Skan			       plus_constant (stack_pointer_rtx, amount));
13842169689Skan	  RTX_FRAME_RELATED_P (dwarf) = 1;
13843169689Skan	  REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
13844169689Skan						REG_NOTES (insn));
13845169689Skan	}
13846169689Skan
13847169689Skan      RTX_FRAME_RELATED_P (insn) = 1;
13848169689Skan    }
13849169689Skan
13850169689Skan  /* If we are profiling, make sure no instructions are scheduled before
13851169689Skan     the call to mcount.  Similarly if the user has requested no
13852169689Skan     scheduling in the prolog.  Similarly if we want non-call exceptions
13853169689Skan     using the EABI unwinder, to prevent faulting instructions from being
13854169689Skan     swapped with a stack adjustment.  */
13855169689Skan  if (current_function_profile || !TARGET_SCHED_PROLOG
13856169689Skan      || (ARM_EABI_UNWIND_TABLES && flag_non_call_exceptions))
1385790075Sobrien    emit_insn (gen_blockage ());
13858169689Skan
13859169689Skan  cfun->machine->lr_save_eliminated = !thumb_force_lr_save ();
13860169689Skan  if (live_regs_mask & 0xff)
13861169689Skan    cfun->machine->lr_save_eliminated = 0;
13862169689Skan
13863169689Skan  /* If the link register is being kept alive, with the return address in it,
13864169689Skan     then make sure that it does not get reused by the ce2 pass.  */
13865169689Skan  if (cfun->machine->lr_save_eliminated)
13866169689Skan    emit_insn (gen_prologue_use (gen_rtx_REG (SImode, LR_REGNUM)));
1386790075Sobrien}
1386890075Sobrien
13869169689Skan
1387090075Sobrienvoid
13871132718Skanthumb_expand_epilogue (void)
1387290075Sobrien{
13873169689Skan  HOST_WIDE_INT amount;
13874169689Skan  arm_stack_offsets *offsets;
13875132718Skan  int regno;
13876132718Skan
1387790075Sobrien  /* Naked functions don't have prologues.  */
1387890075Sobrien  if (IS_NAKED (arm_current_func_type ()))
1387990075Sobrien    return;
1388090075Sobrien
13881169689Skan  offsets = arm_get_frame_offsets ();
13882169689Skan  amount = offsets->outgoing_args - offsets->saved_regs;
13883169689Skan
1388490075Sobrien  if (frame_pointer_needed)
1388590075Sobrien    {
13886169689Skan      emit_insn (gen_movsi (stack_pointer_rtx, hard_frame_pointer_rtx));
13887169689Skan      amount = offsets->locals_base - offsets->saved_regs;
13888169689Skan    }
13889169689Skan
13890171825Skan  gcc_assert (amount >= 0);
13891169689Skan  if (amount)
13892169689Skan    {
1389390075Sobrien      if (amount < 512)
1389490075Sobrien	emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
1389590075Sobrien			       GEN_INT (amount)));
1389690075Sobrien      else
1389790075Sobrien	{
1389890075Sobrien	  /* r3 is always free in the epilogue.  */
13899169689Skan	  rtx reg = gen_rtx_REG (SImode, LAST_ARG_REGNUM);
1390090075Sobrien
1390190075Sobrien	  emit_insn (gen_movsi (reg, GEN_INT (amount)));
1390290075Sobrien	  emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, reg));
1390390075Sobrien	}
1390490075Sobrien    }
13905169689Skan
1390690075Sobrien  /* Emit a USE (stack_pointer_rtx), so that
1390790075Sobrien     the stack adjustment will not be deleted.  */
1390890075Sobrien  emit_insn (gen_prologue_use (stack_pointer_rtx));
1390990075Sobrien
13910169689Skan  if (current_function_profile || !TARGET_SCHED_PROLOG)
1391190075Sobrien    emit_insn (gen_blockage ());
13912132718Skan
13913132718Skan  /* Emit a clobber for each insn that will be restored in the epilogue,
13914132718Skan     so that flow2 will get register lifetimes correct.  */
13915132718Skan  for (regno = 0; regno < 13; regno++)
13916132718Skan    if (regs_ever_live[regno] && !call_used_regs[regno])
13917132718Skan      emit_insn (gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, regno)));
13918132718Skan
13919132718Skan  if (! regs_ever_live[LR_REGNUM])
13920132718Skan    emit_insn (gen_rtx_USE (VOIDmode, gen_rtx_REG (SImode, LR_REGNUM)));
1392190075Sobrien}
1392290075Sobrien
1392390075Sobrienstatic void
13924132718Skanthumb_output_function_prologue (FILE *f, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
1392590075Sobrien{
13926169689Skan  unsigned long live_regs_mask = 0;
13927169689Skan  unsigned long l_mask;
13928169689Skan  unsigned high_regs_pushed = 0;
13929132718Skan  int cfa_offset = 0;
1393090075Sobrien  int regno;
1393190075Sobrien
1393290075Sobrien  if (IS_NAKED (arm_current_func_type ()))
1393390075Sobrien    return;
1393490075Sobrien
1393590075Sobrien  if (is_called_in_ARM_mode (current_function_decl))
1393690075Sobrien    {
1393790075Sobrien      const char * name;
1393890075Sobrien
13939169689Skan      gcc_assert (GET_CODE (DECL_RTL (current_function_decl)) == MEM);
13940169689Skan      gcc_assert (GET_CODE (XEXP (DECL_RTL (current_function_decl), 0))
13941169689Skan		  == SYMBOL_REF);
1394290075Sobrien      name = XSTR  (XEXP (DECL_RTL (current_function_decl), 0), 0);
13943169689Skan
1394490075Sobrien      /* Generate code sequence to switch us into Thumb mode.  */
1394590075Sobrien      /* The .code 32 directive has already been emitted by
1394690075Sobrien	 ASM_DECLARE_FUNCTION_NAME.  */
1394790075Sobrien      asm_fprintf (f, "\torr\t%r, %r, #1\n", IP_REGNUM, PC_REGNUM);
1394890075Sobrien      asm_fprintf (f, "\tbx\t%r\n", IP_REGNUM);
1394990075Sobrien
1395090075Sobrien      /* Generate a label, so that the debugger will notice the
1395190075Sobrien	 change in instruction sets.  This label is also used by
1395290075Sobrien	 the assembler to bypass the ARM code when this function
1395390075Sobrien	 is called from a Thumb encoded function elsewhere in the
1395490075Sobrien	 same file.  Hence the definition of STUB_NAME here must
13955132718Skan	 agree with the definition in gas/config/tc-arm.c.  */
13956169689Skan
1395790075Sobrien#define STUB_NAME ".real_start_of"
13958169689Skan
13959117395Skan      fprintf (f, "\t.code\t16\n");
1396090075Sobrien#ifdef ARM_PE
1396190075Sobrien      if (arm_dllexport_name_p (name))
1396290075Sobrien        name = arm_strip_name_encoding (name);
13963169689Skan#endif
1396490075Sobrien      asm_fprintf (f, "\t.globl %s%U%s\n", STUB_NAME, name);
13965117395Skan      fprintf (f, "\t.thumb_func\n");
1396690075Sobrien      asm_fprintf (f, "%s%U%s:\n", STUB_NAME, name);
1396790075Sobrien    }
13968169689Skan
1396990075Sobrien  if (current_function_pretend_args_size)
1397090075Sobrien    {
13971169689Skan      /* Output unwind directive for the stack adjustment.  */
13972169689Skan      if (ARM_EABI_UNWIND_TABLES)
13973169689Skan	fprintf (f, "\t.pad #%d\n",
13974169689Skan		 current_function_pretend_args_size);
13975169689Skan
1397696263Sobrien      if (cfun->machine->uses_anonymous_args)
1397790075Sobrien	{
1397890075Sobrien	  int num_pushes;
13979169689Skan
13980117395Skan	  fprintf (f, "\tpush\t{");
1398190075Sobrien
13982117395Skan	  num_pushes = ARM_NUM_INTS (current_function_pretend_args_size);
13983169689Skan
1398490075Sobrien	  for (regno = LAST_ARG_REGNUM + 1 - num_pushes;
1398590075Sobrien	       regno <= LAST_ARG_REGNUM;
1398690075Sobrien	       regno++)
1398790075Sobrien	    asm_fprintf (f, "%r%s", regno,
1398890075Sobrien			 regno == LAST_ARG_REGNUM ? "" : ", ");
1398990075Sobrien
13990117395Skan	  fprintf (f, "}\n");
1399190075Sobrien	}
1399290075Sobrien      else
13993169689Skan	asm_fprintf (f, "\tsub\t%r, %r, #%d\n",
1399490075Sobrien		     SP_REGNUM, SP_REGNUM,
1399590075Sobrien		     current_function_pretend_args_size);
13996132718Skan
13997132718Skan      /* We don't need to record the stores for unwinding (would it
13998132718Skan	 help the debugger any if we did?), but record the change in
13999132718Skan	 the stack pointer.  */
14000132718Skan      if (dwarf2out_do_frame ())
14001132718Skan	{
14002132718Skan	  char *l = dwarf2out_cfi_label ();
14003169689Skan
14004132718Skan	  cfa_offset = cfa_offset + current_function_pretend_args_size;
14005132718Skan	  dwarf2out_def_cfa (l, SP_REGNUM, cfa_offset);
14006132718Skan	}
1400790075Sobrien    }
1400890075Sobrien
14009169689Skan  /* Get the registers we are going to push.  */
14010169689Skan  live_regs_mask = thumb_compute_save_reg_mask ();
14011169689Skan  /* Extract a mask of the ones we can give to the Thumb's push instruction.  */
14012169689Skan  l_mask = live_regs_mask & 0x40ff;
14013169689Skan  /* Then count how many other high registers will need to be pushed.  */
14014169689Skan  high_regs_pushed = bit_count (live_regs_mask & 0x0f00);
1401590075Sobrien
1401690075Sobrien  if (TARGET_BACKTRACE)
1401790075Sobrien    {
14018169689Skan      unsigned offset;
14019169689Skan      unsigned work_register;
14020169689Skan
1402190075Sobrien      /* We have been asked to create a stack backtrace structure.
1402290075Sobrien         The code looks like this:
14023169689Skan
1402490075Sobrien	 0   .align 2
1402590075Sobrien	 0   func:
1402690075Sobrien         0     sub   SP, #16         Reserve space for 4 registers.
14027169689Skan	 2     push  {R7}            Push low registers.
1402890075Sobrien         4     add   R7, SP, #20     Get the stack pointer before the push.
1402990075Sobrien         6     str   R7, [SP, #8]    Store the stack pointer (before reserving the space).
1403090075Sobrien         8     mov   R7, PC          Get hold of the start of this code plus 12.
1403190075Sobrien        10     str   R7, [SP, #16]   Store it.
1403290075Sobrien        12     mov   R7, FP          Get hold of the current frame pointer.
1403390075Sobrien        14     str   R7, [SP, #4]    Store it.
1403490075Sobrien        16     mov   R7, LR          Get hold of the current return address.
1403590075Sobrien        18     str   R7, [SP, #12]   Store it.
1403690075Sobrien        20     add   R7, SP, #16     Point at the start of the backtrace structure.
1403790075Sobrien        22     mov   FP, R7          Put this value into the frame pointer.  */
1403890075Sobrien
14039169689Skan      work_register = thumb_find_work_register (live_regs_mask);
1404090075Sobrien
14041169689Skan      if (ARM_EABI_UNWIND_TABLES)
14042169689Skan	asm_fprintf (f, "\t.pad #16\n");
1404390075Sobrien
1404490075Sobrien      asm_fprintf
1404590075Sobrien	(f, "\tsub\t%r, %r, #16\t%@ Create stack backtrace structure\n",
1404690075Sobrien	 SP_REGNUM, SP_REGNUM);
14047132718Skan
14048132718Skan      if (dwarf2out_do_frame ())
14049132718Skan	{
14050132718Skan	  char *l = dwarf2out_cfi_label ();
14051169689Skan
14052132718Skan	  cfa_offset = cfa_offset + 16;
14053132718Skan	  dwarf2out_def_cfa (l, SP_REGNUM, cfa_offset);
14054132718Skan	}
14055132718Skan
14056169689Skan      if (l_mask)
14057169689Skan	{
14058169689Skan	  thumb_pushpop (f, l_mask, 1, &cfa_offset, l_mask);
14059169689Skan	  offset = bit_count (l_mask) * UNITS_PER_WORD;
14060169689Skan	}
14061169689Skan      else
14062169689Skan	offset = 0;
14063169689Skan
1406490075Sobrien      asm_fprintf (f, "\tadd\t%r, %r, #%d\n", work_register, SP_REGNUM,
1406590075Sobrien		   offset + 16 + current_function_pretend_args_size);
14066169689Skan
1406790075Sobrien      asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
1406890075Sobrien		   offset + 4);
1406990075Sobrien
1407090075Sobrien      /* Make sure that the instruction fetching the PC is in the right place
1407190075Sobrien	 to calculate "start of backtrace creation code + 12".  */
14072169689Skan      if (l_mask)
1407390075Sobrien	{
1407490075Sobrien	  asm_fprintf (f, "\tmov\t%r, %r\n", work_register, PC_REGNUM);
1407590075Sobrien	  asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
1407690075Sobrien		       offset + 12);
1407790075Sobrien	  asm_fprintf (f, "\tmov\t%r, %r\n", work_register,
1407890075Sobrien		       ARM_HARD_FRAME_POINTER_REGNUM);
1407990075Sobrien	  asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
1408090075Sobrien		       offset);
1408190075Sobrien	}
1408290075Sobrien      else
1408390075Sobrien	{
1408490075Sobrien	  asm_fprintf (f, "\tmov\t%r, %r\n", work_register,
1408590075Sobrien		       ARM_HARD_FRAME_POINTER_REGNUM);
1408690075Sobrien	  asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
1408790075Sobrien		       offset);
1408890075Sobrien	  asm_fprintf (f, "\tmov\t%r, %r\n", work_register, PC_REGNUM);
1408990075Sobrien	  asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
1409090075Sobrien		       offset + 12);
1409190075Sobrien	}
14092169689Skan
1409390075Sobrien      asm_fprintf (f, "\tmov\t%r, %r\n", work_register, LR_REGNUM);
1409490075Sobrien      asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
1409590075Sobrien		   offset + 8);
1409690075Sobrien      asm_fprintf (f, "\tadd\t%r, %r, #%d\n", work_register, SP_REGNUM,
1409790075Sobrien		   offset + 12);
1409890075Sobrien      asm_fprintf (f, "\tmov\t%r, %r\t\t%@ Backtrace structure created\n",
1409990075Sobrien		   ARM_HARD_FRAME_POINTER_REGNUM, work_register);
1410090075Sobrien    }
14101169689Skan  /* Optimization:  If we are not pushing any low registers but we are going
14102169689Skan     to push some high registers then delay our first push.  This will just
14103169689Skan     be a push of LR and we can combine it with the push of the first high
14104169689Skan     register.  */
14105169689Skan  else if ((l_mask & 0xff) != 0
14106169689Skan	   || (high_regs_pushed == 0 && l_mask))
14107169689Skan    thumb_pushpop (f, l_mask, 1, &cfa_offset, l_mask);
1410890075Sobrien
1410990075Sobrien  if (high_regs_pushed)
1411090075Sobrien    {
14111169689Skan      unsigned pushable_regs;
14112169689Skan      unsigned next_hi_reg;
1411390075Sobrien
1411490075Sobrien      for (next_hi_reg = 12; next_hi_reg > LAST_LO_REGNUM; next_hi_reg--)
14115169689Skan	if (live_regs_mask & (1 << next_hi_reg))
14116117395Skan	  break;
1411790075Sobrien
14118169689Skan      pushable_regs = l_mask & 0xff;
1411990075Sobrien
1412090075Sobrien      if (pushable_regs == 0)
14121169689Skan	pushable_regs = 1 << thumb_find_work_register (live_regs_mask);
1412290075Sobrien
1412390075Sobrien      while (high_regs_pushed > 0)
1412490075Sobrien	{
14125169689Skan	  unsigned long real_regs_mask = 0;
14126132718Skan
14127169689Skan	  for (regno = LAST_LO_REGNUM; regno >= 0; regno --)
1412890075Sobrien	    {
14129169689Skan	      if (pushable_regs & (1 << regno))
1413090075Sobrien		{
1413190075Sobrien		  asm_fprintf (f, "\tmov\t%r, %r\n", regno, next_hi_reg);
14132169689Skan
14133169689Skan		  high_regs_pushed --;
14134132718Skan		  real_regs_mask |= (1 << next_hi_reg);
14135169689Skan
1413690075Sobrien		  if (high_regs_pushed)
14137117395Skan		    {
14138169689Skan		      for (next_hi_reg --; next_hi_reg > LAST_LO_REGNUM;
14139169689Skan			   next_hi_reg --)
14140169689Skan			if (live_regs_mask & (1 << next_hi_reg))
1414190075Sobrien			  break;
14142117395Skan		    }
1414390075Sobrien		  else
1414490075Sobrien		    {
14145169689Skan		      pushable_regs &= ~((1 << regno) - 1);
1414690075Sobrien		      break;
1414790075Sobrien		    }
1414890075Sobrien		}
1414990075Sobrien	    }
14150132718Skan
14151169689Skan	  /* If we had to find a work register and we have not yet
14152169689Skan	     saved the LR then add it to the list of regs to push.  */
14153169689Skan	  if (l_mask == (1 << LR_REGNUM))
14154169689Skan	    {
14155169689Skan	      thumb_pushpop (f, pushable_regs | (1 << LR_REGNUM),
14156169689Skan			     1, &cfa_offset,
14157169689Skan			     real_regs_mask | (1 << LR_REGNUM));
14158169689Skan	      l_mask = 0;
14159169689Skan	    }
14160169689Skan	  else
14161169689Skan	    thumb_pushpop (f, pushable_regs, 1, &cfa_offset, real_regs_mask);
1416290075Sobrien	}
1416390075Sobrien    }
1416490075Sobrien}
1416590075Sobrien
1416690075Sobrien/* Handle the case of a double word load into a low register from
1416790075Sobrien   a computed memory address.  The computed address may involve a
1416890075Sobrien   register which is overwritten by the load.  */
1416990075Sobrienconst char *
14170132718Skanthumb_load_double_from_address (rtx *operands)
1417190075Sobrien{
1417290075Sobrien  rtx addr;
1417390075Sobrien  rtx base;
1417490075Sobrien  rtx offset;
1417590075Sobrien  rtx arg1;
1417690075Sobrien  rtx arg2;
1417790075Sobrien
14178169689Skan  gcc_assert (GET_CODE (operands[0]) == REG);
14179169689Skan  gcc_assert (GET_CODE (operands[1]) == MEM);
14180169689Skan
1418190075Sobrien  /* Get the memory address.  */
1418290075Sobrien  addr = XEXP (operands[1], 0);
14183169689Skan
1418490075Sobrien  /* Work out how the memory address is computed.  */
1418590075Sobrien  switch (GET_CODE (addr))
1418690075Sobrien    {
1418790075Sobrien    case REG:
14188169689Skan      operands[2] = adjust_address (operands[1], SImode, 4);
1418990075Sobrien
1419090075Sobrien      if (REGNO (operands[0]) == REGNO (addr))
1419190075Sobrien	{
1419290075Sobrien	  output_asm_insn ("ldr\t%H0, %2", operands);
1419390075Sobrien	  output_asm_insn ("ldr\t%0, %1", operands);
1419490075Sobrien	}
1419590075Sobrien      else
1419690075Sobrien	{
1419790075Sobrien	  output_asm_insn ("ldr\t%0, %1", operands);
1419890075Sobrien	  output_asm_insn ("ldr\t%H0, %2", operands);
1419990075Sobrien	}
1420090075Sobrien      break;
14201169689Skan
1420290075Sobrien    case CONST:
1420390075Sobrien      /* Compute <address> + 4 for the high order load.  */
14204169689Skan      operands[2] = adjust_address (operands[1], SImode, 4);
14205169689Skan
1420690075Sobrien      output_asm_insn ("ldr\t%0, %1", operands);
1420790075Sobrien      output_asm_insn ("ldr\t%H0, %2", operands);
1420890075Sobrien      break;
14209169689Skan
1421090075Sobrien    case PLUS:
1421190075Sobrien      arg1   = XEXP (addr, 0);
1421290075Sobrien      arg2   = XEXP (addr, 1);
14213169689Skan
1421490075Sobrien      if (CONSTANT_P (arg1))
1421590075Sobrien	base = arg2, offset = arg1;
1421690075Sobrien      else
1421790075Sobrien	base = arg1, offset = arg2;
1421890075Sobrien
14219169689Skan      gcc_assert (GET_CODE (base) == REG);
14220169689Skan
1422190075Sobrien      /* Catch the case of <address> = <reg> + <reg> */
1422290075Sobrien      if (GET_CODE (offset) == REG)
1422390075Sobrien	{
1422490075Sobrien	  int reg_offset = REGNO (offset);
1422590075Sobrien	  int reg_base   = REGNO (base);
1422690075Sobrien	  int reg_dest   = REGNO (operands[0]);
14227169689Skan
1422890075Sobrien	  /* Add the base and offset registers together into the
1422990075Sobrien             higher destination register.  */
1423090075Sobrien	  asm_fprintf (asm_out_file, "\tadd\t%r, %r, %r",
1423190075Sobrien		       reg_dest + 1, reg_base, reg_offset);
14232169689Skan
1423390075Sobrien	  /* Load the lower destination register from the address in
1423490075Sobrien             the higher destination register.  */
1423590075Sobrien	  asm_fprintf (asm_out_file, "\tldr\t%r, [%r, #0]",
1423690075Sobrien		       reg_dest, reg_dest + 1);
14237169689Skan
1423890075Sobrien	  /* Load the higher destination register from its own address
1423990075Sobrien             plus 4.  */
1424090075Sobrien	  asm_fprintf (asm_out_file, "\tldr\t%r, [%r, #4]",
1424190075Sobrien		       reg_dest + 1, reg_dest + 1);
1424290075Sobrien	}
1424390075Sobrien      else
1424490075Sobrien	{
1424590075Sobrien	  /* Compute <address> + 4 for the high order load.  */
14246169689Skan	  operands[2] = adjust_address (operands[1], SImode, 4);
14247169689Skan
1424890075Sobrien	  /* If the computed address is held in the low order register
1424990075Sobrien	     then load the high order register first, otherwise always
1425090075Sobrien	     load the low order register first.  */
1425190075Sobrien	  if (REGNO (operands[0]) == REGNO (base))
1425290075Sobrien	    {
1425390075Sobrien	      output_asm_insn ("ldr\t%H0, %2", operands);
1425490075Sobrien	      output_asm_insn ("ldr\t%0, %1", operands);
1425590075Sobrien	    }
1425690075Sobrien	  else
1425790075Sobrien	    {
1425890075Sobrien	      output_asm_insn ("ldr\t%0, %1", operands);
1425990075Sobrien	      output_asm_insn ("ldr\t%H0, %2", operands);
1426090075Sobrien	    }
1426190075Sobrien	}
1426290075Sobrien      break;
1426390075Sobrien
1426490075Sobrien    case LABEL_REF:
1426590075Sobrien      /* With no registers to worry about we can just load the value
1426690075Sobrien         directly.  */
14267169689Skan      operands[2] = adjust_address (operands[1], SImode, 4);
14268169689Skan
1426990075Sobrien      output_asm_insn ("ldr\t%H0, %2", operands);
1427090075Sobrien      output_asm_insn ("ldr\t%0, %1", operands);
1427190075Sobrien      break;
14272169689Skan
1427390075Sobrien    default:
14274169689Skan      gcc_unreachable ();
1427590075Sobrien    }
14276169689Skan
1427790075Sobrien  return "";
1427890075Sobrien}
1427990075Sobrien
1428090075Sobrienconst char *
14281132718Skanthumb_output_move_mem_multiple (int n, rtx *operands)
1428290075Sobrien{
1428390075Sobrien  rtx tmp;
1428490075Sobrien
1428590075Sobrien  switch (n)
1428690075Sobrien    {
1428790075Sobrien    case 2:
1428890075Sobrien      if (REGNO (operands[4]) > REGNO (operands[5]))
1428990075Sobrien	{
1429090075Sobrien	  tmp = operands[4];
1429190075Sobrien	  operands[4] = operands[5];
1429290075Sobrien	  operands[5] = tmp;
1429390075Sobrien	}
1429490075Sobrien      output_asm_insn ("ldmia\t%1!, {%4, %5}", operands);
1429590075Sobrien      output_asm_insn ("stmia\t%0!, {%4, %5}", operands);
1429690075Sobrien      break;
1429790075Sobrien
1429890075Sobrien    case 3:
1429990075Sobrien      if (REGNO (operands[4]) > REGNO (operands[5]))
1430090075Sobrien	{
1430190075Sobrien	  tmp = operands[4];
1430290075Sobrien	  operands[4] = operands[5];
1430390075Sobrien	  operands[5] = tmp;
1430490075Sobrien	}
1430590075Sobrien      if (REGNO (operands[5]) > REGNO (operands[6]))
1430690075Sobrien	{
1430790075Sobrien	  tmp = operands[5];
1430890075Sobrien	  operands[5] = operands[6];
1430990075Sobrien	  operands[6] = tmp;
1431090075Sobrien	}
1431190075Sobrien      if (REGNO (operands[4]) > REGNO (operands[5]))
1431290075Sobrien	{
1431390075Sobrien	  tmp = operands[4];
1431490075Sobrien	  operands[4] = operands[5];
1431590075Sobrien	  operands[5] = tmp;
1431690075Sobrien	}
14317169689Skan
1431890075Sobrien      output_asm_insn ("ldmia\t%1!, {%4, %5, %6}", operands);
1431990075Sobrien      output_asm_insn ("stmia\t%0!, {%4, %5, %6}", operands);
1432090075Sobrien      break;
1432190075Sobrien
1432290075Sobrien    default:
14323169689Skan      gcc_unreachable ();
1432490075Sobrien    }
1432590075Sobrien
1432690075Sobrien  return "";
1432790075Sobrien}
1432890075Sobrien
14329169689Skan/* Output a call-via instruction for thumb state.  */
14330169689Skanconst char *
14331169689Skanthumb_call_via_reg (rtx reg)
14332169689Skan{
14333169689Skan  int regno = REGNO (reg);
14334169689Skan  rtx *labelp;
14335169689Skan
14336169689Skan  gcc_assert (regno < LR_REGNUM);
14337169689Skan
14338169689Skan  /* If we are in the normal text section we can use a single instance
14339169689Skan     per compilation unit.  If we are doing function sections, then we need
14340169689Skan     an entry per section, since we can't rely on reachability.  */
14341169689Skan  if (in_section == text_section)
14342169689Skan    {
14343169689Skan      thumb_call_reg_needed = 1;
14344169689Skan
14345169689Skan      if (thumb_call_via_label[regno] == NULL)
14346169689Skan	thumb_call_via_label[regno] = gen_label_rtx ();
14347169689Skan      labelp = thumb_call_via_label + regno;
14348169689Skan    }
14349169689Skan  else
14350169689Skan    {
14351169689Skan      if (cfun->machine->call_via[regno] == NULL)
14352169689Skan	cfun->machine->call_via[regno] = gen_label_rtx ();
14353169689Skan      labelp = cfun->machine->call_via + regno;
14354169689Skan    }
14355169689Skan
14356169689Skan  output_asm_insn ("bl\t%a0", labelp);
14357169689Skan  return "";
14358169689Skan}
14359169689Skan
1436090075Sobrien/* Routines for generating rtl.  */
1436190075Sobrienvoid
14362169689Skanthumb_expand_movmemqi (rtx *operands)
1436390075Sobrien{
1436490075Sobrien  rtx out = copy_to_mode_reg (SImode, XEXP (operands[0], 0));
1436590075Sobrien  rtx in  = copy_to_mode_reg (SImode, XEXP (operands[1], 0));
1436690075Sobrien  HOST_WIDE_INT len = INTVAL (operands[2]);
1436790075Sobrien  HOST_WIDE_INT offset = 0;
1436890075Sobrien
1436990075Sobrien  while (len >= 12)
1437090075Sobrien    {
1437190075Sobrien      emit_insn (gen_movmem12b (out, in, out, in));
1437290075Sobrien      len -= 12;
1437390075Sobrien    }
14374169689Skan
1437590075Sobrien  if (len >= 8)
1437690075Sobrien    {
1437790075Sobrien      emit_insn (gen_movmem8b (out, in, out, in));
1437890075Sobrien      len -= 8;
1437990075Sobrien    }
14380169689Skan
1438190075Sobrien  if (len >= 4)
1438290075Sobrien    {
1438390075Sobrien      rtx reg = gen_reg_rtx (SImode);
14384169689Skan      emit_insn (gen_movsi (reg, gen_rtx_MEM (SImode, in)));
14385169689Skan      emit_insn (gen_movsi (gen_rtx_MEM (SImode, out), reg));
1438690075Sobrien      len -= 4;
1438790075Sobrien      offset += 4;
1438890075Sobrien    }
14389169689Skan
1439090075Sobrien  if (len >= 2)
1439190075Sobrien    {
1439290075Sobrien      rtx reg = gen_reg_rtx (HImode);
14393169689Skan      emit_insn (gen_movhi (reg, gen_rtx_MEM (HImode,
14394169689Skan					      plus_constant (in, offset))));
14395169689Skan      emit_insn (gen_movhi (gen_rtx_MEM (HImode, plus_constant (out, offset)),
1439690075Sobrien			    reg));
1439790075Sobrien      len -= 2;
1439890075Sobrien      offset += 2;
1439990075Sobrien    }
14400169689Skan
1440190075Sobrien  if (len)
1440290075Sobrien    {
1440390075Sobrien      rtx reg = gen_reg_rtx (QImode);
14404169689Skan      emit_insn (gen_movqi (reg, gen_rtx_MEM (QImode,
14405169689Skan					      plus_constant (in, offset))));
14406169689Skan      emit_insn (gen_movqi (gen_rtx_MEM (QImode, plus_constant (out, offset)),
1440790075Sobrien			    reg));
1440890075Sobrien    }
1440990075Sobrien}
1441090075Sobrien
1441190075Sobrienvoid
14412132718Skanthumb_reload_out_hi (rtx *operands)
1441390075Sobrien{
1441490075Sobrien  emit_insn (gen_thumb_movhi_clobber (operands[0], operands[1], operands[2]));
1441590075Sobrien}
1441690075Sobrien
14417169689Skan/* Handle reading a half-word from memory during reload.  */
1441890075Sobrienvoid
14419132718Skanthumb_reload_in_hi (rtx *operands ATTRIBUTE_UNUSED)
1442090075Sobrien{
14421169689Skan  gcc_unreachable ();
1442290075Sobrien}
1442390075Sobrien
1442490075Sobrien/* Return the length of a function name prefix
1442590075Sobrien    that starts with the character 'c'.  */
1442690075Sobrienstatic int
14427132718Skanarm_get_strip_length (int c)
1442890075Sobrien{
1442990075Sobrien  switch (c)
1443090075Sobrien    {
1443190075Sobrien    ARM_NAME_ENCODING_LENGTHS
14432169689Skan      default: return 0;
1443390075Sobrien    }
1443490075Sobrien}
1443590075Sobrien
1443690075Sobrien/* Return a pointer to a function's name with any
1443790075Sobrien   and all prefix encodings stripped from it.  */
1443890075Sobrienconst char *
14439132718Skanarm_strip_name_encoding (const char *name)
1444090075Sobrien{
1444190075Sobrien  int skip;
14442169689Skan
1444390075Sobrien  while ((skip = arm_get_strip_length (* name)))
1444490075Sobrien    name += skip;
1444590075Sobrien
1444690075Sobrien  return name;
1444790075Sobrien}
1444890075Sobrien
14449117395Skan/* If there is a '*' anywhere in the name's prefix, then
14450117395Skan   emit the stripped name verbatim, otherwise prepend an
14451117395Skan   underscore if leading underscores are being used.  */
14452117395Skanvoid
14453132718Skanarm_asm_output_labelref (FILE *stream, const char *name)
14454117395Skan{
14455117395Skan  int skip;
14456117395Skan  int verbatim = 0;
14457117395Skan
14458117395Skan  while ((skip = arm_get_strip_length (* name)))
14459117395Skan    {
14460117395Skan      verbatim |= (*name == '*');
14461117395Skan      name += skip;
14462117395Skan    }
14463117395Skan
14464117395Skan  if (verbatim)
14465117395Skan    fputs (name, stream);
14466117395Skan  else
14467117395Skan    asm_fprintf (stream, "%U%s", name);
14468117395Skan}
14469117395Skan
14470169689Skanstatic void
14471259873Spfgarm_file_start (void)
14472259873Spfg{
14473259873Spfg  int val;
14474259873Spfg
14475259873Spfg  if (TARGET_BPABI)
14476259873Spfg    {
14477259873Spfg      const char *fpu_name;
14478259873Spfg      if (arm_select[0].string)
14479259873Spfg	asm_fprintf (asm_out_file, "\t.cpu %s\n", arm_select[0].string);
14480259873Spfg      else if (arm_select[1].string)
14481259873Spfg	asm_fprintf (asm_out_file, "\t.arch %s\n", arm_select[1].string);
14482259873Spfg      else
14483259873Spfg	asm_fprintf (asm_out_file, "\t.cpu %s\n",
14484259873Spfg		     all_cores[arm_default_cpu].name);
14485259873Spfg
14486259873Spfg      if (TARGET_SOFT_FLOAT)
14487259873Spfg	{
14488259873Spfg	  if (TARGET_VFP)
14489259873Spfg	    fpu_name = "softvfp";
14490259873Spfg	  else
14491259873Spfg	    fpu_name = "softfpa";
14492259873Spfg	}
14493259873Spfg      else
14494259873Spfg	{
14495259873Spfg	  switch (arm_fpu_arch)
14496259873Spfg	    {
14497259873Spfg	    case FPUTYPE_FPA:
14498259873Spfg	      fpu_name = "fpa";
14499259873Spfg	      break;
14500259873Spfg	    case FPUTYPE_FPA_EMU2:
14501259873Spfg	      fpu_name = "fpe2";
14502259873Spfg	      break;
14503259873Spfg	    case FPUTYPE_FPA_EMU3:
14504259873Spfg	      fpu_name = "fpe3";
14505259873Spfg	      break;
14506259873Spfg	    case FPUTYPE_MAVERICK:
14507259873Spfg	      fpu_name = "maverick";
14508259873Spfg	      break;
14509259873Spfg	    case FPUTYPE_VFP:
14510259873Spfg	      if (TARGET_HARD_FLOAT)
14511259873Spfg		asm_fprintf (asm_out_file, "\t.eabi_attribute 27, 3\n");
14512259873Spfg	      if (TARGET_HARD_FLOAT_ABI)
14513259873Spfg		asm_fprintf (asm_out_file, "\t.eabi_attribute 28, 1\n");
14514259873Spfg	      fpu_name = "vfp";
14515259873Spfg	      break;
14516259873Spfg	    default:
14517259873Spfg	      abort();
14518259873Spfg	    }
14519259873Spfg	}
14520259873Spfg      asm_fprintf (asm_out_file, "\t.fpu %s\n", fpu_name);
14521259873Spfg
14522259873Spfg      /* Some of these attributes only apply when the corresponding features
14523259873Spfg         are used.  However we don't have any easy way of figuring this out.
14524259873Spfg	 Conservatively record the setting that would have been used.  */
14525259873Spfg
14526259873Spfg      /* Tag_ABI_PCS_wchar_t.  */
14527259873Spfg      asm_fprintf (asm_out_file, "\t.eabi_attribute 18, %d\n",
14528259873Spfg		   (int)WCHAR_TYPE_SIZE / BITS_PER_UNIT);
14529259873Spfg
14530259873Spfg      /* Tag_ABI_FP_rounding.  */
14531259873Spfg      if (flag_rounding_math)
14532259873Spfg	asm_fprintf (asm_out_file, "\t.eabi_attribute 19, 1\n");
14533259873Spfg      if (!flag_unsafe_math_optimizations)
14534259873Spfg	{
14535259873Spfg	  /* Tag_ABI_FP_denomal.  */
14536259873Spfg	  asm_fprintf (asm_out_file, "\t.eabi_attribute 20, 1\n");
14537259873Spfg	  /* Tag_ABI_FP_exceptions.  */
14538259873Spfg	  asm_fprintf (asm_out_file, "\t.eabi_attribute 21, 1\n");
14539259873Spfg	}
14540259873Spfg      /* Tag_ABI_FP_user_exceptions.  */
14541259873Spfg      if (flag_signaling_nans)
14542259873Spfg	asm_fprintf (asm_out_file, "\t.eabi_attribute 22, 1\n");
14543259873Spfg      /* Tag_ABI_FP_number_model.  */
14544259873Spfg      asm_fprintf (asm_out_file, "\t.eabi_attribute 23, %d\n",
14545259873Spfg		   flag_finite_math_only ? 1 : 3);
14546259873Spfg
14547259873Spfg      /* Tag_ABI_align8_needed.  */
14548259873Spfg      asm_fprintf (asm_out_file, "\t.eabi_attribute 24, 1\n");
14549259873Spfg      /* Tag_ABI_align8_preserved.  */
14550259873Spfg      asm_fprintf (asm_out_file, "\t.eabi_attribute 25, 1\n");
14551259873Spfg      /* Tag_ABI_enum_size.  */
14552259873Spfg      asm_fprintf (asm_out_file, "\t.eabi_attribute 26, %d\n",
14553259873Spfg		   flag_short_enums ? 1 : 2);
14554259873Spfg
14555259873Spfg      /* Tag_ABI_optimization_goals.  */
14556259873Spfg      if (optimize_size)
14557259873Spfg	val = 4;
14558259873Spfg      else if (optimize >= 2)
14559259873Spfg	val = 2;
14560259873Spfg      else if (optimize)
14561259873Spfg	val = 1;
14562259873Spfg      else
14563259873Spfg	val = 6;
14564259873Spfg      asm_fprintf (asm_out_file, "\t.eabi_attribute 30, %d\n", val);
14565259873Spfg    }
14566259873Spfg  default_file_start();
14567259873Spfg}
14568259873Spfg
14569259873Spfgstatic void
14570169689Skanarm_file_end (void)
14571169689Skan{
14572169689Skan  int regno;
14573169689Skan
14574169689Skan  if (! thumb_call_reg_needed)
14575169689Skan    return;
14576169689Skan
14577169689Skan  switch_to_section (text_section);
14578169689Skan  asm_fprintf (asm_out_file, "\t.code 16\n");
14579169689Skan  ASM_OUTPUT_ALIGN (asm_out_file, 1);
14580169689Skan
14581169689Skan  for (regno = 0; regno < LR_REGNUM; regno++)
14582169689Skan    {
14583169689Skan      rtx label = thumb_call_via_label[regno];
14584169689Skan
14585169689Skan      if (label != 0)
14586169689Skan	{
14587169689Skan	  targetm.asm_out.internal_label (asm_out_file, "L",
14588169689Skan					  CODE_LABEL_NUMBER (label));
14589169689Skan	  asm_fprintf (asm_out_file, "\tbx\t%r\n", regno);
14590169689Skan	}
14591169689Skan    }
14592169689Skan}
14593169689Skan
14594117395Skanrtx aof_pic_label;
14595117395Skan
1459690075Sobrien#ifdef AOF_ASSEMBLER
1459790075Sobrien/* Special functions only needed when producing AOF syntax assembler.  */
1459890075Sobrien
1459990075Sobrienstruct pic_chain
1460090075Sobrien{
1460190075Sobrien  struct pic_chain * next;
1460290075Sobrien  const char * symname;
1460390075Sobrien};
1460490075Sobrien
1460590075Sobrienstatic struct pic_chain * aof_pic_chain = NULL;
1460690075Sobrien
1460790075Sobrienrtx
14608132718Skanaof_pic_entry (rtx x)
1460990075Sobrien{
1461090075Sobrien  struct pic_chain ** chainp;
1461190075Sobrien  int offset;
1461290075Sobrien
1461390075Sobrien  if (aof_pic_label == NULL_RTX)
1461490075Sobrien    {
1461590075Sobrien      aof_pic_label = gen_rtx_SYMBOL_REF (Pmode, "x$adcons");
1461690075Sobrien    }
1461790075Sobrien
1461890075Sobrien  for (offset = 0, chainp = &aof_pic_chain; *chainp;
1461990075Sobrien       offset += 4, chainp = &(*chainp)->next)
1462090075Sobrien    if ((*chainp)->symname == XSTR (x, 0))
1462190075Sobrien      return plus_constant (aof_pic_label, offset);
1462290075Sobrien
1462390075Sobrien  *chainp = (struct pic_chain *) xmalloc (sizeof (struct pic_chain));
1462490075Sobrien  (*chainp)->next = NULL;
1462590075Sobrien  (*chainp)->symname = XSTR (x, 0);
1462690075Sobrien  return plus_constant (aof_pic_label, offset);
1462790075Sobrien}
1462890075Sobrien
1462990075Sobrienvoid
14630132718Skanaof_dump_pic_table (FILE *f)
1463190075Sobrien{
1463290075Sobrien  struct pic_chain * chain;
1463390075Sobrien
1463490075Sobrien  if (aof_pic_chain == NULL)
1463590075Sobrien    return;
1463690075Sobrien
1463790075Sobrien  asm_fprintf (f, "\tAREA |%r$$adcons|, BASED %r\n",
1463890075Sobrien	       PIC_OFFSET_TABLE_REGNUM,
1463990075Sobrien	       PIC_OFFSET_TABLE_REGNUM);
1464090075Sobrien  fputs ("|x$adcons|\n", f);
14641169689Skan
1464290075Sobrien  for (chain = aof_pic_chain; chain; chain = chain->next)
1464390075Sobrien    {
1464490075Sobrien      fputs ("\tDCD\t", f);
1464590075Sobrien      assemble_name (f, chain->symname);
1464690075Sobrien      fputs ("\n", f);
1464790075Sobrien    }
1464890075Sobrien}
1464990075Sobrien
1465090075Sobrienint arm_text_section_count = 1;
1465190075Sobrien
14652169689Skan/* A get_unnamed_section callback for switching to the text section.  */
14653169689Skan
14654169689Skanstatic void
14655169689Skanaof_output_text_section_asm_op (const void *data ATTRIBUTE_UNUSED)
1465690075Sobrien{
14657169689Skan  fprintf (asm_out_file, "\tAREA |C$$code%d|, CODE, READONLY",
1465890075Sobrien	   arm_text_section_count++);
1465990075Sobrien  if (flag_pic)
14660169689Skan    fprintf (asm_out_file, ", PIC, REENTRANT");
14661169689Skan  fprintf (asm_out_file, "\n");
1466290075Sobrien}
1466390075Sobrien
1466490075Sobrienstatic int arm_data_section_count = 1;
1466590075Sobrien
14666169689Skan/* A get_unnamed_section callback for switching to the data section.  */
14667169689Skan
14668169689Skanstatic void
14669169689Skanaof_output_data_section_asm_op (const void *data ATTRIBUTE_UNUSED)
1467090075Sobrien{
14671169689Skan  fprintf (asm_out_file, "\tAREA |C$$data%d|, DATA\n",
14672169689Skan	   arm_data_section_count++);
1467390075Sobrien}
1467490075Sobrien
14675169689Skan/* Implement TARGET_ASM_INIT_SECTIONS.
14676169689Skan
14677169689Skan   AOF Assembler syntax is a nightmare when it comes to areas, since once
14678169689Skan   we change from one area to another, we can't go back again.  Instead,
14679169689Skan   we must create a new area with the same attributes and add the new output
14680169689Skan   to that.  Unfortunately, there is nothing we can do here to guarantee that
14681169689Skan   two areas with the same attributes will be linked adjacently in the
14682169689Skan   resulting executable, so we have to be careful not to do pc-relative
14683169689Skan   addressing across such boundaries.  */
14684169689Skan
14685169689Skanstatic void
14686169689Skanaof_asm_init_sections (void)
14687169689Skan{
14688169689Skan  text_section = get_unnamed_section (SECTION_CODE,
14689169689Skan				      aof_output_text_section_asm_op, NULL);
14690169689Skan  data_section = get_unnamed_section (SECTION_WRITE,
14691169689Skan				      aof_output_data_section_asm_op, NULL);
14692169689Skan  readonly_data_section = text_section;
14693169689Skan}
14694169689Skan
14695169689Skanvoid
14696169689Skanzero_init_section (void)
14697169689Skan{
14698169689Skan  static int zero_init_count = 1;
14699169689Skan
14700169689Skan  fprintf (asm_out_file, "\tAREA |C$$zidata%d|,NOINIT\n", zero_init_count++);
14701169689Skan  in_section = NULL;
14702169689Skan}
14703169689Skan
1470490075Sobrien/* The AOF assembler is religiously strict about declarations of
1470590075Sobrien   imported and exported symbols, so that it is impossible to declare
1470690075Sobrien   a function as imported near the beginning of the file, and then to
1470790075Sobrien   export it later on.  It is, however, possible to delay the decision
1470890075Sobrien   until all the functions in the file have been compiled.  To get
1470990075Sobrien   around this, we maintain a list of the imports and exports, and
1471090075Sobrien   delete from it any that are subsequently defined.  At the end of
1471190075Sobrien   compilation we spit the remainder of the list out before the END
1471290075Sobrien   directive.  */
1471390075Sobrien
1471490075Sobrienstruct import
1471590075Sobrien{
1471690075Sobrien  struct import * next;
1471790075Sobrien  const char * name;
1471890075Sobrien};
1471990075Sobrien
1472090075Sobrienstatic struct import * imports_list = NULL;
1472190075Sobrien
1472290075Sobrienvoid
14723132718Skanaof_add_import (const char *name)
1472490075Sobrien{
1472590075Sobrien  struct import * new;
1472690075Sobrien
1472790075Sobrien  for (new = imports_list; new; new = new->next)
1472890075Sobrien    if (new->name == name)
1472990075Sobrien      return;
1473090075Sobrien
1473190075Sobrien  new = (struct import *) xmalloc (sizeof (struct import));
1473290075Sobrien  new->next = imports_list;
1473390075Sobrien  imports_list = new;
1473490075Sobrien  new->name = name;
1473590075Sobrien}
1473690075Sobrien
1473790075Sobrienvoid
14738132718Skanaof_delete_import (const char *name)
1473990075Sobrien{
1474090075Sobrien  struct import ** old;
1474190075Sobrien
1474290075Sobrien  for (old = &imports_list; *old; old = & (*old)->next)
1474390075Sobrien    {
1474490075Sobrien      if ((*old)->name == name)
1474590075Sobrien	{
1474690075Sobrien	  *old = (*old)->next;
1474790075Sobrien	  return;
1474890075Sobrien	}
1474990075Sobrien    }
1475090075Sobrien}
1475190075Sobrien
1475290075Sobrienint arm_main_function = 0;
1475390075Sobrien
14754132718Skanstatic void
14755132718Skanaof_dump_imports (FILE *f)
1475690075Sobrien{
1475790075Sobrien  /* The AOF assembler needs this to cause the startup code to be extracted
1475890075Sobrien     from the library.  Brining in __main causes the whole thing to work
1475990075Sobrien     automagically.  */
1476090075Sobrien  if (arm_main_function)
1476190075Sobrien    {
14762169689Skan      switch_to_section (text_section);
1476390075Sobrien      fputs ("\tIMPORT __main\n", f);
1476490075Sobrien      fputs ("\tDCD __main\n", f);
1476590075Sobrien    }
1476690075Sobrien
1476790075Sobrien  /* Now dump the remaining imports.  */
1476890075Sobrien  while (imports_list)
1476990075Sobrien    {
1477090075Sobrien      fprintf (f, "\tIMPORT\t");
1477190075Sobrien      assemble_name (f, imports_list->name);
1477290075Sobrien      fputc ('\n', f);
1477390075Sobrien      imports_list = imports_list->next;
1477490075Sobrien    }
1477590075Sobrien}
14776117395Skan
14777117395Skanstatic void
14778132718Skanaof_globalize_label (FILE *stream, const char *name)
14779117395Skan{
14780117395Skan  default_globalize_label (stream, name);
14781117395Skan  if (! strcmp (name, "main"))
14782117395Skan    arm_main_function = 1;
14783117395Skan}
14784132718Skan
14785132718Skanstatic void
14786132718Skanaof_file_start (void)
14787132718Skan{
14788132718Skan  fputs ("__r0\tRN\t0\n", asm_out_file);
14789132718Skan  fputs ("__a1\tRN\t0\n", asm_out_file);
14790132718Skan  fputs ("__a2\tRN\t1\n", asm_out_file);
14791132718Skan  fputs ("__a3\tRN\t2\n", asm_out_file);
14792132718Skan  fputs ("__a4\tRN\t3\n", asm_out_file);
14793132718Skan  fputs ("__v1\tRN\t4\n", asm_out_file);
14794132718Skan  fputs ("__v2\tRN\t5\n", asm_out_file);
14795132718Skan  fputs ("__v3\tRN\t6\n", asm_out_file);
14796132718Skan  fputs ("__v4\tRN\t7\n", asm_out_file);
14797132718Skan  fputs ("__v5\tRN\t8\n", asm_out_file);
14798132718Skan  fputs ("__v6\tRN\t9\n", asm_out_file);
14799132718Skan  fputs ("__sl\tRN\t10\n", asm_out_file);
14800132718Skan  fputs ("__fp\tRN\t11\n", asm_out_file);
14801132718Skan  fputs ("__ip\tRN\t12\n", asm_out_file);
14802132718Skan  fputs ("__sp\tRN\t13\n", asm_out_file);
14803132718Skan  fputs ("__lr\tRN\t14\n", asm_out_file);
14804132718Skan  fputs ("__pc\tRN\t15\n", asm_out_file);
14805132718Skan  fputs ("__f0\tFN\t0\n", asm_out_file);
14806132718Skan  fputs ("__f1\tFN\t1\n", asm_out_file);
14807132718Skan  fputs ("__f2\tFN\t2\n", asm_out_file);
14808132718Skan  fputs ("__f3\tFN\t3\n", asm_out_file);
14809132718Skan  fputs ("__f4\tFN\t4\n", asm_out_file);
14810132718Skan  fputs ("__f5\tFN\t5\n", asm_out_file);
14811132718Skan  fputs ("__f6\tFN\t6\n", asm_out_file);
14812132718Skan  fputs ("__f7\tFN\t7\n", asm_out_file);
14813169689Skan  switch_to_section (text_section);
14814132718Skan}
14815132718Skan
14816132718Skanstatic void
14817132718Skanaof_file_end (void)
14818132718Skan{
14819132718Skan  if (flag_pic)
14820132718Skan    aof_dump_pic_table (asm_out_file);
14821169689Skan  arm_file_end ();
14822132718Skan  aof_dump_imports (asm_out_file);
14823132718Skan  fputs ("\tEND\n", asm_out_file);
14824132718Skan}
1482590075Sobrien#endif /* AOF_ASSEMBLER */
1482690075Sobrien
14827117395Skan#ifndef ARM_PE
14828117395Skan/* Symbols in the text segment can be accessed without indirecting via the
14829117395Skan   constant pool; it may take an extra binary operation, but this is still
14830117395Skan   faster than indirecting via memory.  Don't do this when not optimizing,
14831117395Skan   since we won't be calculating al of the offsets necessary to do this
14832117395Skan   simplification.  */
14833117395Skan
14834117395Skanstatic void
14835132718Skanarm_encode_section_info (tree decl, rtx rtl, int first)
14836117395Skan{
14837117395Skan  /* This doesn't work with AOF syntax, since the string table may be in
14838117395Skan     a different AREA.  */
14839117395Skan#ifndef AOF_ASSEMBLER
14840169689Skan  if (optimize > 0 && TREE_CONSTANT (decl))
14841132718Skan    SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1;
14842117395Skan#endif
14843117395Skan
14844117395Skan  /* If we are referencing a function that is weak then encode a long call
14845117395Skan     flag in the function name, otherwise if the function is static or
14846117395Skan     or known to be defined in this file then encode a short call flag.  */
14847169689Skan  if (first && DECL_P (decl))
14848117395Skan    {
14849117395Skan      if (TREE_CODE (decl) == FUNCTION_DECL && DECL_WEAK (decl))
14850117395Skan        arm_encode_call_attribute (decl, LONG_CALL_FLAG_CHAR);
14851117395Skan      else if (! TREE_PUBLIC (decl))
14852117395Skan        arm_encode_call_attribute (decl, SHORT_CALL_FLAG_CHAR);
14853117395Skan    }
14854169689Skan
14855169689Skan  default_encode_section_info (decl, rtl, first);
14856117395Skan}
14857117395Skan#endif /* !ARM_PE */
14858117395Skan
14859132718Skanstatic void
14860132718Skanarm_internal_label (FILE *stream, const char *prefix, unsigned long labelno)
14861132718Skan{
14862132718Skan  if (arm_ccfsm_state == 3 && (unsigned) arm_target_label == labelno
14863132718Skan      && !strcmp (prefix, "L"))
14864132718Skan    {
14865132718Skan      arm_ccfsm_state = 0;
14866132718Skan      arm_target_insn = NULL;
14867132718Skan    }
14868132718Skan  default_internal_label (stream, prefix, labelno);
14869132718Skan}
14870132718Skan
14871117395Skan/* Output code to add DELTA to the first argument, and then jump
14872117395Skan   to FUNCTION.  Used for C++ multiple inheritance.  */
14873117395Skanstatic void
14874132718Skanarm_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
14875132718Skan		     HOST_WIDE_INT delta,
14876132718Skan		     HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED,
14877132718Skan		     tree function)
14878117395Skan{
14879132718Skan  static int thunk_label = 0;
14880132718Skan  char label[256];
14881169689Skan  char labelpc[256];
14882117395Skan  int mi_delta = delta;
14883117395Skan  const char *const mi_op = mi_delta < 0 ? "sub" : "add";
14884117395Skan  int shift = 0;
14885132718Skan  int this_regno = (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function)
14886117395Skan                    ? 1 : 0);
14887117395Skan  if (mi_delta < 0)
14888117395Skan    mi_delta = - mi_delta;
14889132718Skan  if (TARGET_THUMB)
14890132718Skan    {
14891132718Skan      int labelno = thunk_label++;
14892132718Skan      ASM_GENERATE_INTERNAL_LABEL (label, "LTHUMBFUNC", labelno);
14893132718Skan      fputs ("\tldr\tr12, ", file);
14894132718Skan      assemble_name (file, label);
14895132718Skan      fputc ('\n', file);
14896169689Skan      if (flag_pic)
14897169689Skan	{
14898169689Skan	  /* If we are generating PIC, the ldr instruction below loads
14899169689Skan	     "(target - 7) - .LTHUNKPCn" into r12.  The pc reads as
14900169689Skan	     the address of the add + 8, so we have:
14901169689Skan
14902169689Skan	     r12 = (target - 7) - .LTHUNKPCn + (.LTHUNKPCn + 8)
14903169689Skan	         = target + 1.
14904169689Skan
14905169689Skan	     Note that we have "+ 1" because some versions of GNU ld
14906169689Skan	     don't set the low bit of the result for R_ARM_REL32
14907169689Skan	     relocations against thumb function symbols.  */
14908169689Skan	  ASM_GENERATE_INTERNAL_LABEL (labelpc, "LTHUNKPC", labelno);
14909169689Skan	  assemble_name (file, labelpc);
14910169689Skan	  fputs (":\n", file);
14911169689Skan	  fputs ("\tadd\tr12, pc, r12\n", file);
14912169689Skan	}
14913132718Skan    }
14914117395Skan  while (mi_delta != 0)
14915117395Skan    {
14916117395Skan      if ((mi_delta & (3 << shift)) == 0)
14917117395Skan        shift += 2;
14918117395Skan      else
14919117395Skan        {
14920117395Skan          asm_fprintf (file, "\t%s\t%r, %r, #%d\n",
14921117395Skan                       mi_op, this_regno, this_regno,
14922117395Skan                       mi_delta & (0xff << shift));
14923117395Skan          mi_delta &= ~(0xff << shift);
14924117395Skan          shift += 8;
14925117395Skan        }
14926117395Skan    }
14927132718Skan  if (TARGET_THUMB)
14928132718Skan    {
14929132718Skan      fprintf (file, "\tbx\tr12\n");
14930132718Skan      ASM_OUTPUT_ALIGN (file, 2);
14931132718Skan      assemble_name (file, label);
14932132718Skan      fputs (":\n", file);
14933169689Skan      if (flag_pic)
14934169689Skan	{
14935169689Skan	  /* Output ".word .LTHUNKn-7-.LTHUNKPCn".  */
14936169689Skan	  rtx tem = XEXP (DECL_RTL (function), 0);
14937169689Skan	  tem = gen_rtx_PLUS (GET_MODE (tem), tem, GEN_INT (-7));
14938169689Skan	  tem = gen_rtx_MINUS (GET_MODE (tem),
14939169689Skan			       tem,
14940169689Skan			       gen_rtx_SYMBOL_REF (Pmode,
14941169689Skan						   ggc_strdup (labelpc)));
14942169689Skan	  assemble_integer (tem, 4, BITS_PER_WORD, 1);
14943169689Skan	}
14944169689Skan      else
14945169689Skan	/* Output ".word .LTHUNKn".  */
14946169689Skan	assemble_integer (XEXP (DECL_RTL (function), 0), 4, BITS_PER_WORD, 1);
14947132718Skan    }
14948132718Skan  else
14949132718Skan    {
14950132718Skan      fputs ("\tb\t", file);
14951132718Skan      assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0));
14952132718Skan      if (NEED_PLT_RELOC)
14953132718Skan        fputs ("(PLT)", file);
14954132718Skan      fputc ('\n', file);
14955132718Skan    }
14956117395Skan}
14957117395Skan
14958132718Skanint
14959132718Skanarm_emit_vector_const (FILE *file, rtx x)
14960132718Skan{
14961132718Skan  int i;
14962132718Skan  const char * pattern;
14963132718Skan
14964169689Skan  gcc_assert (GET_CODE (x) == CONST_VECTOR);
14965132718Skan
14966132718Skan  switch (GET_MODE (x))
14967132718Skan    {
14968132718Skan    case V2SImode: pattern = "%08x"; break;
14969132718Skan    case V4HImode: pattern = "%04x"; break;
14970132718Skan    case V8QImode: pattern = "%02x"; break;
14971169689Skan    default:       gcc_unreachable ();
14972132718Skan    }
14973132718Skan
14974132718Skan  fprintf (file, "0x");
14975132718Skan  for (i = CONST_VECTOR_NUNITS (x); i--;)
14976132718Skan    {
14977132718Skan      rtx element;
14978132718Skan
14979132718Skan      element = CONST_VECTOR_ELT (x, i);
14980132718Skan      fprintf (file, pattern, INTVAL (element));
14981132718Skan    }
14982132718Skan
14983132718Skan  return 1;
14984132718Skan}
14985132718Skan
14986132718Skanconst char *
14987132718Skanarm_output_load_gr (rtx *operands)
14988132718Skan{
14989132718Skan  rtx reg;
14990132718Skan  rtx offset;
14991132718Skan  rtx wcgr;
14992132718Skan  rtx sum;
14993169689Skan
14994132718Skan  if (GET_CODE (operands [1]) != MEM
14995132718Skan      || GET_CODE (sum = XEXP (operands [1], 0)) != PLUS
14996132718Skan      || GET_CODE (reg = XEXP (sum, 0)) != REG
14997132718Skan      || GET_CODE (offset = XEXP (sum, 1)) != CONST_INT
14998132718Skan      || ((INTVAL (offset) < 1024) && (INTVAL (offset) > -1024)))
14999132718Skan    return "wldrw%?\t%0, %1";
15000169689Skan
15001169689Skan  /* Fix up an out-of-range load of a GR register.  */
15002132718Skan  output_asm_insn ("str%?\t%0, [sp, #-4]!\t@ Start of GR load expansion", & reg);
15003132718Skan  wcgr = operands[0];
15004132718Skan  operands[0] = reg;
15005132718Skan  output_asm_insn ("ldr%?\t%0, %1", operands);
15006132718Skan
15007132718Skan  operands[0] = wcgr;
15008132718Skan  operands[1] = reg;
15009132718Skan  output_asm_insn ("tmcr%?\t%0, %1", operands);
15010132718Skan  output_asm_insn ("ldr%?\t%0, [sp], #4\t@ End of GR load expansion", & reg);
15011132718Skan
15012132718Skan  return "";
15013132718Skan}
15014169689Skan
15015169689Skan/* Worker function for TARGET_SETUP_INCOMING_VARARGS.
15016169689Skan
15017169689Skan   On the ARM, PRETEND_SIZE is set in order to have the prologue push the last
15018169689Skan   named arg and all anonymous args onto the stack.
15019169689Skan   XXX I know the prologue shouldn't be pushing registers, but it is faster
15020169689Skan   that way.  */
15021169689Skan
15022169689Skanstatic void
15023169689Skanarm_setup_incoming_varargs (CUMULATIVE_ARGS *cum,
15024169689Skan			    enum machine_mode mode ATTRIBUTE_UNUSED,
15025169689Skan			    tree type ATTRIBUTE_UNUSED,
15026169689Skan			    int *pretend_size,
15027169689Skan			    int second_time ATTRIBUTE_UNUSED)
15028169689Skan{
15029169689Skan  cfun->machine->uses_anonymous_args = 1;
15030169689Skan  if (cum->nregs < NUM_ARG_REGS)
15031169689Skan    *pretend_size = (NUM_ARG_REGS - cum->nregs) * UNITS_PER_WORD;
15032169689Skan}
15033169689Skan
15034169689Skan/* Return nonzero if the CONSUMER instruction (a store) does not need
15035169689Skan   PRODUCER's value to calculate the address.  */
15036169689Skan
15037169689Skanint
15038169689Skanarm_no_early_store_addr_dep (rtx producer, rtx consumer)
15039169689Skan{
15040169689Skan  rtx value = PATTERN (producer);
15041169689Skan  rtx addr = PATTERN (consumer);
15042169689Skan
15043169689Skan  if (GET_CODE (value) == COND_EXEC)
15044169689Skan    value = COND_EXEC_CODE (value);
15045169689Skan  if (GET_CODE (value) == PARALLEL)
15046169689Skan    value = XVECEXP (value, 0, 0);
15047169689Skan  value = XEXP (value, 0);
15048169689Skan  if (GET_CODE (addr) == COND_EXEC)
15049169689Skan    addr = COND_EXEC_CODE (addr);
15050169689Skan  if (GET_CODE (addr) == PARALLEL)
15051169689Skan    addr = XVECEXP (addr, 0, 0);
15052169689Skan  addr = XEXP (addr, 0);
15053169689Skan
15054169689Skan  return !reg_overlap_mentioned_p (value, addr);
15055169689Skan}
15056169689Skan
15057169689Skan/* Return nonzero if the CONSUMER instruction (an ALU op) does not
15058169689Skan   have an early register shift value or amount dependency on the
15059169689Skan   result of PRODUCER.  */
15060169689Skan
15061169689Skanint
15062169689Skanarm_no_early_alu_shift_dep (rtx producer, rtx consumer)
15063169689Skan{
15064169689Skan  rtx value = PATTERN (producer);
15065169689Skan  rtx op = PATTERN (consumer);
15066169689Skan  rtx early_op;
15067169689Skan
15068169689Skan  if (GET_CODE (value) == COND_EXEC)
15069169689Skan    value = COND_EXEC_CODE (value);
15070169689Skan  if (GET_CODE (value) == PARALLEL)
15071169689Skan    value = XVECEXP (value, 0, 0);
15072169689Skan  value = XEXP (value, 0);
15073169689Skan  if (GET_CODE (op) == COND_EXEC)
15074169689Skan    op = COND_EXEC_CODE (op);
15075169689Skan  if (GET_CODE (op) == PARALLEL)
15076169689Skan    op = XVECEXP (op, 0, 0);
15077169689Skan  op = XEXP (op, 1);
15078169689Skan
15079169689Skan  early_op = XEXP (op, 0);
15080169689Skan  /* This is either an actual independent shift, or a shift applied to
15081169689Skan     the first operand of another operation.  We want the whole shift
15082169689Skan     operation.  */
15083169689Skan  if (GET_CODE (early_op) == REG)
15084169689Skan    early_op = op;
15085169689Skan
15086169689Skan  return !reg_overlap_mentioned_p (value, early_op);
15087169689Skan}
15088169689Skan
15089169689Skan/* Return nonzero if the CONSUMER instruction (an ALU op) does not
15090169689Skan   have an early register shift value dependency on the result of
15091169689Skan   PRODUCER.  */
15092169689Skan
15093169689Skanint
15094169689Skanarm_no_early_alu_shift_value_dep (rtx producer, rtx consumer)
15095169689Skan{
15096169689Skan  rtx value = PATTERN (producer);
15097169689Skan  rtx op = PATTERN (consumer);
15098169689Skan  rtx early_op;
15099169689Skan
15100169689Skan  if (GET_CODE (value) == COND_EXEC)
15101169689Skan    value = COND_EXEC_CODE (value);
15102169689Skan  if (GET_CODE (value) == PARALLEL)
15103169689Skan    value = XVECEXP (value, 0, 0);
15104169689Skan  value = XEXP (value, 0);
15105169689Skan  if (GET_CODE (op) == COND_EXEC)
15106169689Skan    op = COND_EXEC_CODE (op);
15107169689Skan  if (GET_CODE (op) == PARALLEL)
15108169689Skan    op = XVECEXP (op, 0, 0);
15109169689Skan  op = XEXP (op, 1);
15110169689Skan
15111169689Skan  early_op = XEXP (op, 0);
15112169689Skan
15113169689Skan  /* This is either an actual independent shift, or a shift applied to
15114169689Skan     the first operand of another operation.  We want the value being
15115169689Skan     shifted, in either case.  */
15116169689Skan  if (GET_CODE (early_op) != REG)
15117169689Skan    early_op = XEXP (early_op, 0);
15118169689Skan
15119169689Skan  return !reg_overlap_mentioned_p (value, early_op);
15120169689Skan}
15121169689Skan
15122169689Skan/* Return nonzero if the CONSUMER (a mul or mac op) does not
15123169689Skan   have an early register mult dependency on the result of
15124169689Skan   PRODUCER.  */
15125169689Skan
15126169689Skanint
15127169689Skanarm_no_early_mul_dep (rtx producer, rtx consumer)
15128169689Skan{
15129169689Skan  rtx value = PATTERN (producer);
15130169689Skan  rtx op = PATTERN (consumer);
15131169689Skan
15132169689Skan  if (GET_CODE (value) == COND_EXEC)
15133169689Skan    value = COND_EXEC_CODE (value);
15134169689Skan  if (GET_CODE (value) == PARALLEL)
15135169689Skan    value = XVECEXP (value, 0, 0);
15136169689Skan  value = XEXP (value, 0);
15137169689Skan  if (GET_CODE (op) == COND_EXEC)
15138169689Skan    op = COND_EXEC_CODE (op);
15139169689Skan  if (GET_CODE (op) == PARALLEL)
15140169689Skan    op = XVECEXP (op, 0, 0);
15141169689Skan  op = XEXP (op, 1);
15142169689Skan
15143169689Skan  return (GET_CODE (op) == PLUS
15144169689Skan	  && !reg_overlap_mentioned_p (value, XEXP (op, 0)));
15145169689Skan}
15146169689Skan
15147169689Skan
15148169689Skan/* We can't rely on the caller doing the proper promotion when
15149169689Skan   using APCS or ATPCS.  */
15150169689Skan
15151169689Skanstatic bool
15152169689Skanarm_promote_prototypes (tree t ATTRIBUTE_UNUSED)
15153169689Skan{
15154169689Skan    return !TARGET_AAPCS_BASED;
15155169689Skan}
15156169689Skan
15157169689Skan
15158169689Skan/* AAPCS based ABIs use short enums by default.  */
15159169689Skan
15160169689Skanstatic bool
15161169689Skanarm_default_short_enums (void)
15162169689Skan{
15163169689Skan  return TARGET_AAPCS_BASED && arm_abi != ARM_ABI_AAPCS_LINUX;
15164169689Skan}
15165169689Skan
15166169689Skan
15167169689Skan/* AAPCS requires that anonymous bitfields affect structure alignment.  */
15168169689Skan
15169169689Skanstatic bool
15170169689Skanarm_align_anon_bitfield (void)
15171169689Skan{
15172169689Skan  return TARGET_AAPCS_BASED;
15173169689Skan}
15174169689Skan
15175169689Skan
15176169689Skan/* The generic C++ ABI says 64-bit (long long).  The EABI says 32-bit.  */
15177169689Skan
15178169689Skanstatic tree
15179169689Skanarm_cxx_guard_type (void)
15180169689Skan{
15181169689Skan  return TARGET_AAPCS_BASED ? integer_type_node : long_long_integer_type_node;
15182169689Skan}
15183169689Skan
15184169689Skan
15185169689Skan/* The EABI says test the least significant bit of a guard variable.  */
15186169689Skan
15187169689Skanstatic bool
15188169689Skanarm_cxx_guard_mask_bit (void)
15189169689Skan{
15190169689Skan  return TARGET_AAPCS_BASED;
15191169689Skan}
15192169689Skan
15193169689Skan
15194169689Skan/* The EABI specifies that all array cookies are 8 bytes long.  */
15195169689Skan
15196169689Skanstatic tree
15197169689Skanarm_get_cookie_size (tree type)
15198169689Skan{
15199169689Skan  tree size;
15200169689Skan
15201169689Skan  if (!TARGET_AAPCS_BASED)
15202169689Skan    return default_cxx_get_cookie_size (type);
15203169689Skan
15204169689Skan  size = build_int_cst (sizetype, 8);
15205169689Skan  return size;
15206169689Skan}
15207169689Skan
15208169689Skan
15209169689Skan/* The EABI says that array cookies should also contain the element size.  */
15210169689Skan
15211169689Skanstatic bool
15212169689Skanarm_cookie_has_size (void)
15213169689Skan{
15214169689Skan  return TARGET_AAPCS_BASED;
15215169689Skan}
15216169689Skan
15217169689Skan
15218169689Skan/* The EABI says constructors and destructors should return a pointer to
15219169689Skan   the object constructed/destroyed.  */
15220169689Skan
15221169689Skanstatic bool
15222169689Skanarm_cxx_cdtor_returns_this (void)
15223169689Skan{
15224169689Skan  return TARGET_AAPCS_BASED;
15225169689Skan}
15226169689Skan
15227169689Skan/* The EABI says that an inline function may never be the key
15228169689Skan   method.  */
15229169689Skan
15230169689Skanstatic bool
15231169689Skanarm_cxx_key_method_may_be_inline (void)
15232169689Skan{
15233169689Skan  return !TARGET_AAPCS_BASED;
15234169689Skan}
15235169689Skan
15236169689Skanstatic void
15237169689Skanarm_cxx_determine_class_data_visibility (tree decl)
15238169689Skan{
15239169689Skan  if (!TARGET_AAPCS_BASED)
15240169689Skan    return;
15241169689Skan
15242169689Skan  /* In general, \S 3.2.5.5 of the ARM EABI requires that class data
15243169689Skan     is exported.  However, on systems without dynamic vague linkage,
15244169689Skan     \S 3.2.5.6 says that COMDAT class data has hidden linkage.  */
15245169689Skan  if (!TARGET_ARM_DYNAMIC_VAGUE_LINKAGE_P && DECL_COMDAT (decl))
15246169689Skan    DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN;
15247169689Skan  else
15248169689Skan    DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
15249169689Skan  DECL_VISIBILITY_SPECIFIED (decl) = 1;
15250169689Skan}
15251169689Skan
15252169689Skanstatic bool
15253169689Skanarm_cxx_class_data_always_comdat (void)
15254169689Skan{
15255169689Skan  /* \S 3.2.5.4 of the ARM C++ ABI says that class data only have
15256169689Skan     vague linkage if the class has no key function.  */
15257169689Skan  return !TARGET_AAPCS_BASED;
15258169689Skan}
15259169689Skan
15260169689Skan
15261169689Skan/* The EABI says __aeabi_atexit should be used to register static
15262169689Skan   destructors.  */
15263169689Skan
15264169689Skanstatic bool
15265169689Skanarm_cxx_use_aeabi_atexit (void)
15266169689Skan{
15267169689Skan  return TARGET_AAPCS_BASED;
15268169689Skan}
15269169689Skan
15270169689Skan
15271169689Skanvoid
15272169689Skanarm_set_return_address (rtx source, rtx scratch)
15273169689Skan{
15274169689Skan  arm_stack_offsets *offsets;
15275169689Skan  HOST_WIDE_INT delta;
15276169689Skan  rtx addr;
15277169689Skan  unsigned long saved_regs;
15278169689Skan
15279169689Skan  saved_regs = arm_compute_save_reg_mask ();
15280169689Skan
15281169689Skan  if ((saved_regs & (1 << LR_REGNUM)) == 0)
15282169689Skan    emit_move_insn (gen_rtx_REG (Pmode, LR_REGNUM), source);
15283169689Skan  else
15284169689Skan    {
15285169689Skan      if (frame_pointer_needed)
15286169689Skan	addr = plus_constant(hard_frame_pointer_rtx, -4);
15287169689Skan      else
15288169689Skan	{
15289169689Skan	  /* LR will be the first saved register.  */
15290169689Skan	  offsets = arm_get_frame_offsets ();
15291169689Skan	  delta = offsets->outgoing_args - (offsets->frame + 4);
15292169689Skan
15293169689Skan
15294169689Skan	  if (delta >= 4096)
15295169689Skan	    {
15296169689Skan	      emit_insn (gen_addsi3 (scratch, stack_pointer_rtx,
15297169689Skan				     GEN_INT (delta & ~4095)));
15298169689Skan	      addr = scratch;
15299169689Skan	      delta &= 4095;
15300169689Skan	    }
15301169689Skan	  else
15302169689Skan	    addr = stack_pointer_rtx;
15303169689Skan
15304169689Skan	  addr = plus_constant (addr, delta);
15305169689Skan	}
15306169689Skan      emit_move_insn (gen_frame_mem (Pmode, addr), source);
15307169689Skan    }
15308169689Skan}
15309169689Skan
15310169689Skan
15311169689Skanvoid
15312169689Skanthumb_set_return_address (rtx source, rtx scratch)
15313169689Skan{
15314169689Skan  arm_stack_offsets *offsets;
15315169689Skan  HOST_WIDE_INT delta;
15316169689Skan  int reg;
15317169689Skan  rtx addr;
15318169689Skan  unsigned long mask;
15319169689Skan
15320169689Skan  emit_insn (gen_rtx_USE (VOIDmode, source));
15321169689Skan
15322169689Skan  mask = thumb_compute_save_reg_mask ();
15323169689Skan  if (mask & (1 << LR_REGNUM))
15324169689Skan    {
15325169689Skan      offsets = arm_get_frame_offsets ();
15326169689Skan
15327169689Skan      /* Find the saved regs.  */
15328169689Skan      if (frame_pointer_needed)
15329169689Skan	{
15330169689Skan	  delta = offsets->soft_frame - offsets->saved_args;
15331169689Skan	  reg = THUMB_HARD_FRAME_POINTER_REGNUM;
15332169689Skan	}
15333169689Skan      else
15334169689Skan	{
15335169689Skan	  delta = offsets->outgoing_args - offsets->saved_args;
15336169689Skan	  reg = SP_REGNUM;
15337169689Skan	}
15338169689Skan      /* Allow for the stack frame.  */
15339169689Skan      if (TARGET_BACKTRACE)
15340169689Skan	delta -= 16;
15341169689Skan      /* The link register is always the first saved register.  */
15342169689Skan      delta -= 4;
15343169689Skan
15344169689Skan      /* Construct the address.  */
15345169689Skan      addr = gen_rtx_REG (SImode, reg);
15346169689Skan      if ((reg != SP_REGNUM && delta >= 128)
15347169689Skan	  || delta >= 1024)
15348169689Skan	{
15349169689Skan	  emit_insn (gen_movsi (scratch, GEN_INT (delta)));
15350169689Skan	  emit_insn (gen_addsi3 (scratch, scratch, stack_pointer_rtx));
15351169689Skan	  addr = scratch;
15352169689Skan	}
15353169689Skan      else
15354169689Skan	addr = plus_constant (addr, delta);
15355169689Skan
15356169689Skan      emit_move_insn (gen_frame_mem (Pmode, addr), source);
15357169689Skan    }
15358169689Skan  else
15359169689Skan    emit_move_insn (gen_rtx_REG (Pmode, LR_REGNUM), source);
15360169689Skan}
15361169689Skan
15362169689Skan/* Implements target hook vector_mode_supported_p.  */
15363169689Skanbool
15364169689Skanarm_vector_mode_supported_p (enum machine_mode mode)
15365169689Skan{
15366169689Skan  if ((mode == V2SImode)
15367169689Skan      || (mode == V4HImode)
15368169689Skan      || (mode == V8QImode))
15369169689Skan    return true;
15370169689Skan
15371169689Skan  return false;
15372169689Skan}
15373169689Skan
15374169689Skan/* Implement TARGET_SHIFT_TRUNCATION_MASK.  SImode shifts use normal
15375169689Skan   ARM insns and therefore guarantee that the shift count is modulo 256.
15376169689Skan   DImode shifts (those implemented by lib1funcs.asm or by optabs.c)
15377169689Skan   guarantee no particular behavior for out-of-range counts.  */
15378169689Skan
15379169689Skanstatic unsigned HOST_WIDE_INT
15380169689Skanarm_shift_truncation_mask (enum machine_mode mode)
15381169689Skan{
15382169689Skan  return mode == SImode ? 255 : 0;
15383169689Skan}
15384169689Skan
15385169689Skan
15386169689Skan/* Map internal gcc register numbers to DWARF2 register numbers.  */
15387169689Skan
15388169689Skanunsigned int
15389169689Skanarm_dbx_register_number (unsigned int regno)
15390169689Skan{
15391169689Skan  if (regno < 16)
15392169689Skan    return regno;
15393169689Skan
15394169689Skan  /* TODO: Legacy targets output FPA regs as registers 16-23 for backwards
15395169689Skan     compatibility.  The EABI defines them as registers 96-103.  */
15396169689Skan  if (IS_FPA_REGNUM (regno))
15397169689Skan    return (TARGET_AAPCS_BASED ? 96 : 16) + regno - FIRST_FPA_REGNUM;
15398169689Skan
15399169689Skan  if (IS_VFP_REGNUM (regno))
15400169689Skan    return 64 + regno - FIRST_VFP_REGNUM;
15401169689Skan
15402169689Skan  if (IS_IWMMXT_GR_REGNUM (regno))
15403169689Skan    return 104 + regno - FIRST_IWMMXT_GR_REGNUM;
15404169689Skan
15405169689Skan  if (IS_IWMMXT_REGNUM (regno))
15406169689Skan    return 112 + regno - FIRST_IWMMXT_REGNUM;
15407169689Skan
15408169689Skan  gcc_unreachable ();
15409169689Skan}
15410169689Skan
15411169689Skan
15412169689Skan#ifdef TARGET_UNWIND_INFO
15413169689Skan/* Emit unwind directives for a store-multiple instruction.  This should
15414169689Skan   only ever be generated by the function prologue code, so we expect it
15415169689Skan   to have a particular form.  */
15416169689Skan
15417169689Skanstatic void
15418169689Skanarm_unwind_emit_stm (FILE * asm_out_file, rtx p)
15419169689Skan{
15420169689Skan  int i;
15421169689Skan  HOST_WIDE_INT offset;
15422169689Skan  HOST_WIDE_INT nregs;
15423169689Skan  int reg_size;
15424169689Skan  unsigned reg;
15425169689Skan  unsigned lastreg;
15426169689Skan  rtx e;
15427169689Skan
15428169689Skan  /* First insn will adjust the stack pointer.  */
15429169689Skan  e = XVECEXP (p, 0, 0);
15430169689Skan  if (GET_CODE (e) != SET
15431169689Skan      || GET_CODE (XEXP (e, 0)) != REG
15432169689Skan      || REGNO (XEXP (e, 0)) != SP_REGNUM
15433169689Skan      || GET_CODE (XEXP (e, 1)) != PLUS)
15434169689Skan    abort ();
15435169689Skan
15436169689Skan  offset = -INTVAL (XEXP (XEXP (e, 1), 1));
15437169689Skan  nregs = XVECLEN (p, 0) - 1;
15438169689Skan
15439169689Skan  reg = REGNO (XEXP (XVECEXP (p, 0, 1), 1));
15440169689Skan  if (reg < 16)
15441169689Skan    {
15442169689Skan      /* The function prologue may also push pc, but not annotate it as it is
15443169689Skan	 never restored.  We turn this into a stack pointer adjustment.  */
15444169689Skan      if (nregs * 4 == offset - 4)
15445169689Skan	{
15446169689Skan	  fprintf (asm_out_file, "\t.pad #4\n");
15447169689Skan	  offset -= 4;
15448169689Skan	}
15449169689Skan      reg_size = 4;
15450169689Skan    }
15451169689Skan  else if (IS_VFP_REGNUM (reg))
15452169689Skan    {
15453169689Skan      /* FPA register saves use an additional word.  */
15454169689Skan      offset -= 4;
15455169689Skan      reg_size = 8;
15456169689Skan    }
15457169689Skan  else if (reg >= FIRST_FPA_REGNUM && reg <= LAST_FPA_REGNUM)
15458169689Skan    {
15459169689Skan      /* FPA registers are done differently.  */
15460169689Skan      asm_fprintf (asm_out_file, "\t.save %r, %wd\n", reg, nregs);
15461169689Skan      return;
15462169689Skan    }
15463169689Skan  else
15464169689Skan    /* Unknown register type.  */
15465169689Skan    abort ();
15466169689Skan
15467169689Skan  /* If the stack increment doesn't match the size of the saved registers,
15468169689Skan     something has gone horribly wrong.  */
15469169689Skan  if (offset != nregs * reg_size)
15470169689Skan    abort ();
15471169689Skan
15472169689Skan  fprintf (asm_out_file, "\t.save {");
15473169689Skan
15474169689Skan  offset = 0;
15475169689Skan  lastreg = 0;
15476169689Skan  /* The remaining insns will describe the stores.  */
15477169689Skan  for (i = 1; i <= nregs; i++)
15478169689Skan    {
15479169689Skan      /* Expect (set (mem <addr>) (reg)).
15480169689Skan         Where <addr> is (reg:SP) or (plus (reg:SP) (const_int)).  */
15481169689Skan      e = XVECEXP (p, 0, i);
15482169689Skan      if (GET_CODE (e) != SET
15483169689Skan	  || GET_CODE (XEXP (e, 0)) != MEM
15484169689Skan	  || GET_CODE (XEXP (e, 1)) != REG)
15485169689Skan	abort ();
15486169689Skan
15487169689Skan      reg = REGNO (XEXP (e, 1));
15488169689Skan      if (reg < lastreg)
15489169689Skan	abort ();
15490169689Skan
15491169689Skan      if (i != 1)
15492169689Skan	fprintf (asm_out_file, ", ");
15493169689Skan      /* We can't use %r for vfp because we need to use the
15494169689Skan	 double precision register names.  */
15495169689Skan      if (IS_VFP_REGNUM (reg))
15496169689Skan	asm_fprintf (asm_out_file, "d%d", (reg - FIRST_VFP_REGNUM) / 2);
15497169689Skan      else
15498169689Skan	asm_fprintf (asm_out_file, "%r", reg);
15499169689Skan
15500169689Skan#ifdef ENABLE_CHECKING
15501169689Skan      /* Check that the addresses are consecutive.  */
15502169689Skan      e = XEXP (XEXP (e, 0), 0);
15503169689Skan      if (GET_CODE (e) == PLUS)
15504169689Skan	{
15505169689Skan	  offset += reg_size;
15506169689Skan	  if (GET_CODE (XEXP (e, 0)) != REG
15507169689Skan	      || REGNO (XEXP (e, 0)) != SP_REGNUM
15508169689Skan	      || GET_CODE (XEXP (e, 1)) != CONST_INT
15509169689Skan	      || offset != INTVAL (XEXP (e, 1)))
15510169689Skan	    abort ();
15511169689Skan	}
15512169689Skan      else if (i != 1
15513169689Skan	       || GET_CODE (e) != REG
15514169689Skan	       || REGNO (e) != SP_REGNUM)
15515169689Skan	abort ();
15516169689Skan#endif
15517169689Skan    }
15518169689Skan  fprintf (asm_out_file, "}\n");
15519169689Skan}
15520169689Skan
15521169689Skan/*  Emit unwind directives for a SET.  */
15522169689Skan
15523169689Skanstatic void
15524169689Skanarm_unwind_emit_set (FILE * asm_out_file, rtx p)
15525169689Skan{
15526169689Skan  rtx e0;
15527169689Skan  rtx e1;
15528169689Skan
15529169689Skan  e0 = XEXP (p, 0);
15530169689Skan  e1 = XEXP (p, 1);
15531169689Skan  switch (GET_CODE (e0))
15532169689Skan    {
15533169689Skan    case MEM:
15534169689Skan      /* Pushing a single register.  */
15535169689Skan      if (GET_CODE (XEXP (e0, 0)) != PRE_DEC
15536169689Skan	  || GET_CODE (XEXP (XEXP (e0, 0), 0)) != REG
15537169689Skan	  || REGNO (XEXP (XEXP (e0, 0), 0)) != SP_REGNUM)
15538169689Skan	abort ();
15539169689Skan
15540169689Skan      asm_fprintf (asm_out_file, "\t.save ");
15541169689Skan      if (IS_VFP_REGNUM (REGNO (e1)))
15542169689Skan	asm_fprintf(asm_out_file, "{d%d}\n",
15543169689Skan		    (REGNO (e1) - FIRST_VFP_REGNUM) / 2);
15544169689Skan      else
15545169689Skan	asm_fprintf(asm_out_file, "{%r}\n", REGNO (e1));
15546169689Skan      break;
15547169689Skan
15548169689Skan    case REG:
15549169689Skan      if (REGNO (e0) == SP_REGNUM)
15550169689Skan	{
15551169689Skan	  /* A stack increment.  */
15552169689Skan	  if (GET_CODE (e1) != PLUS
15553169689Skan	      || GET_CODE (XEXP (e1, 0)) != REG
15554169689Skan	      || REGNO (XEXP (e1, 0)) != SP_REGNUM
15555169689Skan	      || GET_CODE (XEXP (e1, 1)) != CONST_INT)
15556169689Skan	    abort ();
15557169689Skan
15558169689Skan	  asm_fprintf (asm_out_file, "\t.pad #%wd\n",
15559169689Skan		       -INTVAL (XEXP (e1, 1)));
15560169689Skan	}
15561169689Skan      else if (REGNO (e0) == HARD_FRAME_POINTER_REGNUM)
15562169689Skan	{
15563169689Skan	  HOST_WIDE_INT offset;
15564169689Skan	  unsigned reg;
15565169689Skan
15566169689Skan	  if (GET_CODE (e1) == PLUS)
15567169689Skan	    {
15568169689Skan	      if (GET_CODE (XEXP (e1, 0)) != REG
15569169689Skan		  || GET_CODE (XEXP (e1, 1)) != CONST_INT)
15570169689Skan		abort ();
15571169689Skan	      reg = REGNO (XEXP (e1, 0));
15572169689Skan	      offset = INTVAL (XEXP (e1, 1));
15573169689Skan	      asm_fprintf (asm_out_file, "\t.setfp %r, %r, #%wd\n",
15574169689Skan			   HARD_FRAME_POINTER_REGNUM, reg,
15575169689Skan			   INTVAL (XEXP (e1, 1)));
15576169689Skan	    }
15577169689Skan	  else if (GET_CODE (e1) == REG)
15578169689Skan	    {
15579169689Skan	      reg = REGNO (e1);
15580169689Skan	      asm_fprintf (asm_out_file, "\t.setfp %r, %r\n",
15581169689Skan			   HARD_FRAME_POINTER_REGNUM, reg);
15582169689Skan	    }
15583169689Skan	  else
15584169689Skan	    abort ();
15585169689Skan	}
15586169689Skan      else if (GET_CODE (e1) == REG && REGNO (e1) == SP_REGNUM)
15587169689Skan	{
15588169689Skan	  /* Move from sp to reg.  */
15589169689Skan	  asm_fprintf (asm_out_file, "\t.movsp %r\n", REGNO (e0));
15590169689Skan	}
15591169689Skan     else if (GET_CODE (e1) == PLUS
15592169689Skan	      && GET_CODE (XEXP (e1, 0)) == REG
15593169689Skan	      && REGNO (XEXP (e1, 0)) == SP_REGNUM
15594169689Skan	      && GET_CODE (XEXP (e1, 1)) == CONST_INT)
15595169689Skan	{
15596169689Skan	  /* Set reg to offset from sp.  */
15597169689Skan	  asm_fprintf (asm_out_file, "\t.movsp %r, #%d\n",
15598169689Skan		       REGNO (e0), (int)INTVAL(XEXP (e1, 1)));
15599169689Skan	}
15600169689Skan      else
15601169689Skan	abort ();
15602169689Skan      break;
15603169689Skan
15604169689Skan    default:
15605169689Skan      abort ();
15606169689Skan    }
15607169689Skan}
15608169689Skan
15609169689Skan
15610169689Skan/* Emit unwind directives for the given insn.  */
15611169689Skan
15612169689Skanstatic void
15613169689Skanarm_unwind_emit (FILE * asm_out_file, rtx insn)
15614169689Skan{
15615169689Skan  rtx pat;
15616169689Skan
15617169689Skan  if (!ARM_EABI_UNWIND_TABLES)
15618169689Skan    return;
15619169689Skan
15620169689Skan  if (GET_CODE (insn) == NOTE || !RTX_FRAME_RELATED_P (insn))
15621169689Skan    return;
15622169689Skan
15623169689Skan  pat = find_reg_note (insn, REG_FRAME_RELATED_EXPR, NULL_RTX);
15624169689Skan  if (pat)
15625169689Skan    pat = XEXP (pat, 0);
15626169689Skan  else
15627169689Skan    pat = PATTERN (insn);
15628169689Skan
15629169689Skan  switch (GET_CODE (pat))
15630169689Skan    {
15631169689Skan    case SET:
15632169689Skan      arm_unwind_emit_set (asm_out_file, pat);
15633169689Skan      break;
15634169689Skan
15635169689Skan    case SEQUENCE:
15636169689Skan      /* Store multiple.  */
15637169689Skan      arm_unwind_emit_stm (asm_out_file, pat);
15638169689Skan      break;
15639169689Skan
15640169689Skan    default:
15641169689Skan      abort();
15642169689Skan    }
15643169689Skan}
15644169689Skan
15645169689Skan
15646169689Skan/* Output a reference from a function exception table to the type_info
15647169689Skan   object X.  The EABI specifies that the symbol should be relocated by
15648169689Skan   an R_ARM_TARGET2 relocation.  */
15649169689Skan
15650169689Skanstatic bool
15651169689Skanarm_output_ttype (rtx x)
15652169689Skan{
15653169689Skan  fputs ("\t.word\t", asm_out_file);
15654169689Skan  output_addr_const (asm_out_file, x);
15655169689Skan  /* Use special relocations for symbol references.  */
15656169689Skan  if (GET_CODE (x) != CONST_INT)
15657169689Skan    fputs ("(TARGET2)", asm_out_file);
15658169689Skan  fputc ('\n', asm_out_file);
15659169689Skan
15660169689Skan  return TRUE;
15661169689Skan}
15662169689Skan#endif /* TARGET_UNWIND_INFO */
15663169689Skan
15664169689Skan
15665169689Skan/* Output unwind directives for the start/end of a function.  */
15666169689Skan
15667169689Skanvoid
15668169689Skanarm_output_fn_unwind (FILE * f, bool prologue)
15669169689Skan{
15670169689Skan  if (!ARM_EABI_UNWIND_TABLES)
15671169689Skan    return;
15672169689Skan
15673169689Skan  if (prologue)
15674169689Skan    fputs ("\t.fnstart\n", f);
15675169689Skan  else
15676169689Skan    fputs ("\t.fnend\n", f);
15677169689Skan}
15678169689Skan
15679169689Skanstatic bool
15680169689Skanarm_emit_tls_decoration (FILE *fp, rtx x)
15681169689Skan{
15682169689Skan  enum tls_reloc reloc;
15683169689Skan  rtx val;
15684169689Skan
15685169689Skan  val = XVECEXP (x, 0, 0);
15686169689Skan  reloc = INTVAL (XVECEXP (x, 0, 1));
15687169689Skan
15688169689Skan  output_addr_const (fp, val);
15689169689Skan
15690169689Skan  switch (reloc)
15691169689Skan    {
15692169689Skan    case TLS_GD32:
15693169689Skan      fputs ("(tlsgd)", fp);
15694169689Skan      break;
15695169689Skan    case TLS_LDM32:
15696169689Skan      fputs ("(tlsldm)", fp);
15697169689Skan      break;
15698169689Skan    case TLS_LDO32:
15699169689Skan      fputs ("(tlsldo)", fp);
15700169689Skan      break;
15701169689Skan    case TLS_IE32:
15702169689Skan      fputs ("(gottpoff)", fp);
15703169689Skan      break;
15704169689Skan    case TLS_LE32:
15705169689Skan      fputs ("(tpoff)", fp);
15706169689Skan      break;
15707169689Skan    default:
15708169689Skan      gcc_unreachable ();
15709169689Skan    }
15710169689Skan
15711169689Skan  switch (reloc)
15712169689Skan    {
15713169689Skan    case TLS_GD32:
15714169689Skan    case TLS_LDM32:
15715169689Skan    case TLS_IE32:
15716169689Skan      fputs (" + (. - ", fp);
15717169689Skan      output_addr_const (fp, XVECEXP (x, 0, 2));
15718169689Skan      fputs (" - ", fp);
15719169689Skan      output_addr_const (fp, XVECEXP (x, 0, 3));
15720169689Skan      fputc (')', fp);
15721169689Skan      break;
15722169689Skan    default:
15723169689Skan      break;
15724169689Skan    }
15725169689Skan
15726169689Skan  return TRUE;
15727169689Skan}
15728169689Skan
15729169689Skanbool
15730169689Skanarm_output_addr_const_extra (FILE *fp, rtx x)
15731169689Skan{
15732169689Skan  if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLS)
15733169689Skan    return arm_emit_tls_decoration (fp, x);
15734169689Skan  else if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_PIC_LABEL)
15735169689Skan    {
15736169689Skan      char label[256];
15737169689Skan      int labelno = INTVAL (XVECEXP (x, 0, 0));
15738169689Skan
15739169689Skan      ASM_GENERATE_INTERNAL_LABEL (label, "LPIC", labelno);
15740169689Skan      assemble_name_raw (fp, label);
15741169689Skan
15742169689Skan      return TRUE;
15743169689Skan    }
15744169689Skan  else if (GET_CODE (x) == CONST_VECTOR)
15745169689Skan    return arm_emit_vector_const (fp, x);
15746169689Skan
15747169689Skan  return FALSE;
15748169689Skan}
15749169689Skan
15750169689Skan#include "gt-arm.h"
15751