rs6000.c revision 132718
190075Sobrien/* Subroutines used for code generation on IBM RS/6000.
290075Sobrien   Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
3132718Skan   2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
490075Sobrien   Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
590075Sobrien
6132718Skan   This file is part of GCC.
790075Sobrien
8132718Skan   GCC is free software; you can redistribute it and/or modify it
9132718Skan   under the terms of the GNU General Public License as published
10132718Skan   by the Free Software Foundation; either version 2, or (at your
11132718Skan   option) any later version.
1290075Sobrien
13132718Skan   GCC is distributed in the hope that it will be useful, but WITHOUT
14132718Skan   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15132718Skan   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
16132718Skan   License for more details.
1790075Sobrien
18132718Skan   You should have received a copy of the GNU General Public License
19132718Skan   along with GCC; see the file COPYING.  If not, write to the
20132718Skan   Free Software Foundation, 59 Temple Place - Suite 330, Boston,
21132718Skan   MA 02111-1307, USA.  */
2290075Sobrien
2390075Sobrien#include "config.h"
2490075Sobrien#include "system.h"
25132718Skan#include "coretypes.h"
26132718Skan#include "tm.h"
2790075Sobrien#include "rtl.h"
2890075Sobrien#include "regs.h"
2990075Sobrien#include "hard-reg-set.h"
3090075Sobrien#include "real.h"
3190075Sobrien#include "insn-config.h"
3290075Sobrien#include "conditions.h"
3390075Sobrien#include "insn-attr.h"
3490075Sobrien#include "flags.h"
3590075Sobrien#include "recog.h"
3690075Sobrien#include "obstack.h"
3790075Sobrien#include "tree.h"
3890075Sobrien#include "expr.h"
3990075Sobrien#include "optabs.h"
4090075Sobrien#include "except.h"
4190075Sobrien#include "function.h"
4290075Sobrien#include "output.h"
4390075Sobrien#include "basic-block.h"
4490075Sobrien#include "integrate.h"
4590075Sobrien#include "toplev.h"
4690075Sobrien#include "ggc.h"
4790075Sobrien#include "hashtab.h"
4890075Sobrien#include "tm_p.h"
4990075Sobrien#include "target.h"
5090075Sobrien#include "target-def.h"
5190075Sobrien#include "langhooks.h"
5290075Sobrien#include "reload.h"
53132718Skan#include "cfglayout.h"
54132718Skan#include "sched-int.h"
55132718Skan#if TARGET_XCOFF
56132718Skan#include "xcoffout.h"  /* get declarations of xcoff_*_section_name */
57132718Skan#endif
5890075Sobrien
5990075Sobrien#ifndef TARGET_NO_PROTOTYPE
6090075Sobrien#define TARGET_NO_PROTOTYPE 0
6190075Sobrien#endif
6290075Sobrien
63132718Skan#define EASY_VECTOR_15(n) ((n) >= -16 && (n) <= 15)
64132718Skan#define EASY_VECTOR_15_ADD_SELF(n) ((n) >= 0x10 && (n) <= 0x1e \
65132718Skan                                          && !((n) & 1))
66132718Skan
6790075Sobrien#define min(A,B)	((A) < (B) ? (A) : (B))
6890075Sobrien#define max(A,B)	((A) > (B) ? (A) : (B))
6990075Sobrien
70132718Skan/* Structure used to define the rs6000 stack */
71132718Skantypedef struct rs6000_stack {
72132718Skan  int first_gp_reg_save;	/* first callee saved GP register used */
73132718Skan  int first_fp_reg_save;	/* first callee saved FP register used */
74132718Skan  int first_altivec_reg_save;	/* first callee saved AltiVec register used */
75132718Skan  int lr_save_p;		/* true if the link reg needs to be saved */
76132718Skan  int cr_save_p;		/* true if the CR reg needs to be saved */
77132718Skan  unsigned int vrsave_mask;	/* mask of vec registers to save */
78132718Skan  int toc_save_p;		/* true if the TOC needs to be saved */
79132718Skan  int push_p;			/* true if we need to allocate stack space */
80132718Skan  int calls_p;			/* true if the function makes any calls */
81132718Skan  enum rs6000_abi abi;		/* which ABI to use */
82132718Skan  int gp_save_offset;		/* offset to save GP regs from initial SP */
83132718Skan  int fp_save_offset;		/* offset to save FP regs from initial SP */
84132718Skan  int altivec_save_offset;	/* offset to save AltiVec regs from initial SP */
85132718Skan  int lr_save_offset;		/* offset to save LR from initial SP */
86132718Skan  int cr_save_offset;		/* offset to save CR from initial SP */
87132718Skan  int vrsave_save_offset;	/* offset to save VRSAVE from initial SP */
88132718Skan  int spe_gp_save_offset;	/* offset to save spe 64-bit gprs  */
89132718Skan  int toc_save_offset;		/* offset to save the TOC pointer */
90132718Skan  int varargs_save_offset;	/* offset to save the varargs registers */
91132718Skan  int ehrd_offset;		/* offset to EH return data */
92132718Skan  int reg_size;			/* register size (4 or 8) */
93132718Skan  int varargs_size;		/* size to hold V.4 args passed in regs */
94132718Skan  HOST_WIDE_INT vars_size;	/* variable save area size */
95132718Skan  int parm_size;		/* outgoing parameter size */
96132718Skan  int save_size;		/* save area size */
97132718Skan  int fixed_size;		/* fixed size of stack frame */
98132718Skan  int gp_size;			/* size of saved GP registers */
99132718Skan  int fp_size;			/* size of saved FP registers */
100132718Skan  int altivec_size;		/* size of saved AltiVec registers */
101132718Skan  int cr_size;			/* size to hold CR if not in save_size */
102132718Skan  int lr_size;			/* size to hold LR if not in save_size */
103132718Skan  int vrsave_size;		/* size to hold VRSAVE if not in save_size */
104132718Skan  int altivec_padding_size;	/* size of altivec alignment padding if
105132718Skan				   not in save_size */
106132718Skan  int spe_gp_size;		/* size of 64-bit GPR save size for SPE */
107132718Skan  int spe_padding_size;
108132718Skan  int toc_size;			/* size to hold TOC if not in save_size */
109132718Skan  HOST_WIDE_INT total_size;	/* total bytes allocated for stack */
110132718Skan  int spe_64bit_regs_used;
111132718Skan} rs6000_stack_t;
112132718Skan
11390075Sobrien/* Target cpu type */
11490075Sobrien
11590075Sobrienenum processor_type rs6000_cpu;
11690075Sobrienstruct rs6000_cpu_select rs6000_select[3] =
11790075Sobrien{
11890075Sobrien  /* switch		name,			tune	arch */
11990075Sobrien  { (const char *)0,	"--with-cpu=",		1,	1 },
12090075Sobrien  { (const char *)0,	"-mcpu=",		1,	1 },
12190075Sobrien  { (const char *)0,	"-mtune=",		1,	0 },
12290075Sobrien};
12390075Sobrien
124132718Skan/* Always emit branch hint bits.  */
125132718Skanstatic GTY(()) bool rs6000_always_hint;
126132718Skan
127132718Skan/* Schedule instructions for group formation.  */
128132718Skanstatic GTY(()) bool rs6000_sched_groups;
129132718Skan
130132718Skan/* Support adjust_priority scheduler hook
131132718Skan   and -mprioritize-restricted-insns= option.  */
132132718Skanconst char *rs6000_sched_restricted_insns_priority_str;
133132718Skanint rs6000_sched_restricted_insns_priority;
134132718Skan
135132718Skan/* Support for -msched-costly-dep option.  */
136132718Skanconst char *rs6000_sched_costly_dep_str;
137132718Skanenum rs6000_dependence_cost rs6000_sched_costly_dep;
138132718Skan
139132718Skan/* Support for -minsert-sched-nops option.  */
140132718Skanconst char *rs6000_sched_insert_nops_str;
141132718Skanenum rs6000_nop_insertion rs6000_sched_insert_nops;
142132718Skan
14390075Sobrien/* Size of long double */
14490075Sobrienconst char *rs6000_long_double_size_string;
14590075Sobrienint rs6000_long_double_type_size;
14690075Sobrien
14790075Sobrien/* Whether -mabi=altivec has appeared */
14890075Sobrienint rs6000_altivec_abi;
14990075Sobrien
150117395Skan/* Whether VRSAVE instructions should be generated.  */
151117395Skanint rs6000_altivec_vrsave;
152117395Skan
153117395Skan/* String from -mvrsave= option.  */
154117395Skanconst char *rs6000_altivec_vrsave_string;
155117395Skan
156117395Skan/* Nonzero if we want SPE ABI extensions.  */
157117395Skanint rs6000_spe_abi;
158117395Skan
159117395Skan/* Whether isel instructions should be generated.  */
160117395Skanint rs6000_isel;
161117395Skan
162132718Skan/* Whether SPE simd instructions should be generated.  */
163132718Skanint rs6000_spe;
164117395Skan
165132718Skan/* Nonzero if floating point operations are done in the GPRs.  */
166132718Skanint rs6000_float_gprs = 0;
167132718Skan
168132718Skan/* String from -mfloat-gprs=.  */
169132718Skanconst char *rs6000_float_gprs_string;
170132718Skan
171117395Skan/* String from -misel=.  */
172117395Skanconst char *rs6000_isel_string;
173117395Skan
174132718Skan/* String from -mspe=.  */
175132718Skanconst char *rs6000_spe_string;
176132718Skan
177117395Skan/* Set to nonzero once AIX common-mode calls have been defined.  */
178132718Skanstatic GTY(()) int common_mode_defined;
17990075Sobrien
18090075Sobrien/* Save information from a "cmpxx" operation until the branch or scc is
18190075Sobrien   emitted.  */
18290075Sobrienrtx rs6000_compare_op0, rs6000_compare_op1;
18390075Sobrienint rs6000_compare_fp_p;
18490075Sobrien
18590075Sobrien/* Label number of label created for -mrelocatable, to call to so we can
18690075Sobrien   get the address of the GOT section */
18790075Sobrienint rs6000_pic_labelno;
18890075Sobrien
18990075Sobrien#ifdef USING_ELFOS_H
19090075Sobrien/* Which abi to adhere to */
191132718Skanconst char *rs6000_abi_name;
19290075Sobrien
19390075Sobrien/* Semantics of the small data area */
19490075Sobrienenum rs6000_sdata_type rs6000_sdata = SDATA_DATA;
19590075Sobrien
19690075Sobrien/* Which small data model to use */
19790075Sobrienconst char *rs6000_sdata_name = (char *)0;
19890075Sobrien
19990075Sobrien/* Counter for labels which are to be placed in .fixup.  */
20090075Sobrienint fixuplabelno = 0;
20190075Sobrien#endif
20290075Sobrien
203132718Skan/* Bit size of immediate TLS offsets and string from which it is decoded.  */
204132718Skanint rs6000_tls_size = 32;
205132718Skanconst char *rs6000_tls_size_string;
206132718Skan
20790075Sobrien/* ABI enumeration available for subtarget to use.  */
20890075Sobrienenum rs6000_abi rs6000_current_abi;
20990075Sobrien
21090075Sobrien/* ABI string from -mabi= option.  */
21190075Sobrienconst char *rs6000_abi_string;
21290075Sobrien
21390075Sobrien/* Debug flags */
21490075Sobrienconst char *rs6000_debug_name;
21590075Sobrienint rs6000_debug_stack;		/* debug stack applications */
21690075Sobrienint rs6000_debug_arg;		/* debug argument handling */
21790075Sobrien
218132718Skan/* Opaque types.  */
219132718Skanstatic GTY(()) tree opaque_V2SI_type_node;
220132718Skanstatic GTY(()) tree opaque_V2SF_type_node;
221132718Skanstatic GTY(()) tree opaque_p_V2SI_type_node;
222132718Skan
223117395Skanconst char *rs6000_traceback_name;
224117395Skanstatic enum {
225117395Skan  traceback_default = 0,
226117395Skan  traceback_none,
227117395Skan  traceback_part,
228117395Skan  traceback_full
229117395Skan} rs6000_traceback;
230117395Skan
23190075Sobrien/* Flag to say the TOC is initialized */
23290075Sobrienint toc_initialized;
23390075Sobrienchar toc_label_name[10];
23490075Sobrien
23590075Sobrien/* Alias set for saves and restores from the rs6000 stack.  */
236132718Skanstatic GTY(()) int rs6000_sr_alias_set;
23790075Sobrien
238117395Skan/* Call distance, overridden by -mlongcall and #pragma longcall(1).
239117395Skan   The only place that looks at this is rs6000_set_default_type_attributes;
240117395Skan   everywhere else should rely on the presence or absence of a longcall
241117395Skan   attribute on the function declaration.  */
242117395Skanint rs6000_default_long_calls;
243117395Skanconst char *rs6000_longcall_switch;
244117395Skan
245132718Skan/* Control alignment for fields within structures.  */
246132718Skan/* String from -malign-XXXXX.  */
247132718Skanconst char *rs6000_alignment_string;
248132718Skanint rs6000_alignment_flags;
249132718Skan
250117395Skanstruct builtin_description
251117395Skan{
252117395Skan  /* mask is not const because we're going to alter it below.  This
253117395Skan     nonsense will go away when we rewrite the -march infrastructure
254117395Skan     to give us more target flag bits.  */
255117395Skan  unsigned int mask;
256117395Skan  const enum insn_code icode;
257117395Skan  const char *const name;
258117395Skan  const enum rs6000_builtins code;
259117395Skan};
260117395Skan
261132718Skanstatic bool rs6000_function_ok_for_sibcall (tree, tree);
262132718Skanstatic int num_insns_constant_wide (HOST_WIDE_INT);
263132718Skanstatic void validate_condition_mode (enum rtx_code, enum machine_mode);
264132718Skanstatic rtx rs6000_generate_compare (enum rtx_code);
265132718Skanstatic void rs6000_maybe_dead (rtx);
266132718Skanstatic void rs6000_emit_stack_tie (void);
267132718Skanstatic void rs6000_frame_related (rtx, rtx, HOST_WIDE_INT, rtx, rtx);
268132718Skanstatic rtx spe_synthesize_frame_save (rtx);
269132718Skanstatic bool spe_func_has_64bit_regs_p (void);
270132718Skanstatic void emit_frame_save (rtx, rtx, enum machine_mode, unsigned int,
271132718Skan			     int, HOST_WIDE_INT);
272132718Skanstatic rtx gen_frame_mem_offset (enum machine_mode, rtx, int);
273132718Skanstatic void rs6000_emit_allocate_stack (HOST_WIDE_INT, int);
274132718Skanstatic unsigned rs6000_hash_constant (rtx);
275132718Skanstatic unsigned toc_hash_function (const void *);
276132718Skanstatic int toc_hash_eq (const void *, const void *);
277132718Skanstatic int constant_pool_expr_1 (rtx, int *, int *);
278132718Skanstatic bool constant_pool_expr_p (rtx);
279132718Skanstatic bool toc_relative_expr_p (rtx);
280132718Skanstatic bool legitimate_small_data_p (enum machine_mode, rtx);
281132718Skanstatic bool legitimate_offset_address_p (enum machine_mode, rtx, int);
282132718Skanstatic bool legitimate_indexed_address_p (rtx, int);
283132718Skanstatic bool legitimate_indirect_address_p (rtx, int);
284132718Skanstatic bool macho_lo_sum_memory_operand (rtx x, enum machine_mode mode);
285132718Skanstatic bool legitimate_lo_sum_address_p (enum machine_mode, rtx, int);
286132718Skanstatic struct machine_function * rs6000_init_machine_status (void);
287132718Skanstatic bool rs6000_assemble_integer (rtx, unsigned int, int);
288117395Skan#ifdef HAVE_GAS_HIDDEN
289132718Skanstatic void rs6000_assemble_visibility (tree, int);
290117395Skan#endif
291132718Skanstatic int rs6000_ra_ever_killed (void);
292132718Skanstatic tree rs6000_handle_longcall_attribute (tree *, tree, tree, int, bool *);
293132718Skanextern const struct attribute_spec rs6000_attribute_table[];
294132718Skanstatic void rs6000_set_default_type_attributes (tree);
295132718Skanstatic void rs6000_output_function_prologue (FILE *, HOST_WIDE_INT);
296132718Skanstatic void rs6000_output_function_epilogue (FILE *, HOST_WIDE_INT);
297132718Skanstatic void rs6000_output_mi_thunk (FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT,
298132718Skan				    tree);
299132718Skanstatic rtx rs6000_emit_set_long_const (rtx, HOST_WIDE_INT, HOST_WIDE_INT);
300132718Skanstatic bool rs6000_return_in_memory (tree, tree);
301132718Skanstatic void rs6000_file_start (void);
30290075Sobrien#if TARGET_ELF
303132718Skanstatic unsigned int rs6000_elf_section_type_flags (tree, const char *, int);
304132718Skanstatic void rs6000_elf_asm_out_constructor (rtx, int);
305132718Skanstatic void rs6000_elf_asm_out_destructor (rtx, int);
306132718Skanstatic void rs6000_elf_select_section (tree, int, unsigned HOST_WIDE_INT);
307132718Skanstatic void rs6000_elf_unique_section (tree, int);
308132718Skanstatic void rs6000_elf_select_rtx_section (enum machine_mode, rtx,
309132718Skan					   unsigned HOST_WIDE_INT);
310132718Skanstatic void rs6000_elf_encode_section_info (tree, rtx, int)
311117395Skan     ATTRIBUTE_UNUSED;
312132718Skanstatic bool rs6000_elf_in_small_data_p (tree);
31390075Sobrien#endif
314117395Skan#if TARGET_XCOFF
315132718Skanstatic void rs6000_xcoff_asm_globalize_label (FILE *, const char *);
316132718Skanstatic void rs6000_xcoff_asm_named_section (const char *, unsigned int);
317132718Skanstatic void rs6000_xcoff_select_section (tree, int, unsigned HOST_WIDE_INT);
318132718Skanstatic void rs6000_xcoff_unique_section (tree, int);
319132718Skanstatic void rs6000_xcoff_select_rtx_section (enum machine_mode, rtx,
320132718Skan					     unsigned HOST_WIDE_INT);
321132718Skanstatic const char * rs6000_xcoff_strip_name_encoding (const char *);
322132718Skanstatic unsigned int rs6000_xcoff_section_type_flags (tree, const char *, int);
323132718Skanstatic void rs6000_xcoff_file_start (void);
324132718Skanstatic void rs6000_xcoff_file_end (void);
32590075Sobrien#endif
326132718Skan#if TARGET_MACHO
327132718Skanstatic bool rs6000_binds_local_p (tree);
328132718Skan#endif
329132718Skanstatic int rs6000_use_dfa_pipeline_interface (void);
330132718Skanstatic int rs6000_variable_issue (FILE *, int, rtx, int);
331132718Skanstatic bool rs6000_rtx_costs (rtx, int, int, int *);
332132718Skanstatic int rs6000_adjust_cost (rtx, rtx, rtx, int);
333132718Skanstatic bool is_microcoded_insn (rtx);
334132718Skanstatic int is_dispatch_slot_restricted (rtx);
335132718Skanstatic bool is_cracked_insn (rtx);
336132718Skanstatic bool is_branch_slot_insn (rtx);
337132718Skanstatic int rs6000_adjust_priority (rtx, int);
338132718Skanstatic int rs6000_issue_rate (void);
339132718Skanstatic bool rs6000_is_costly_dependence (rtx, rtx, rtx, int, int);
340132718Skanstatic rtx get_next_active_insn (rtx, rtx);
341132718Skanstatic bool insn_terminates_group_p (rtx , enum group_termination);
342132718Skanstatic bool is_costly_group (rtx *, rtx);
343132718Skanstatic int force_new_group (int, FILE *, rtx *, rtx, bool *, int, int *);
344132718Skanstatic int redefine_groups (FILE *, int, rtx, rtx);
345132718Skanstatic int pad_groups (FILE *, int, rtx, rtx);
346132718Skanstatic void rs6000_sched_finish (FILE *, int);
347132718Skanstatic int rs6000_use_sched_lookahead (void);
34890075Sobrien
349132718Skanstatic void rs6000_init_builtins (void);
350132718Skanstatic rtx rs6000_expand_unop_builtin (enum insn_code, tree, rtx);
351132718Skanstatic rtx rs6000_expand_binop_builtin (enum insn_code, tree, rtx);
352132718Skanstatic rtx rs6000_expand_ternop_builtin (enum insn_code, tree, rtx);
353132718Skanstatic rtx rs6000_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
354132718Skanstatic void altivec_init_builtins (void);
355132718Skanstatic void rs6000_common_init_builtins (void);
356132718Skanstatic void rs6000_init_libfuncs (void);
357117395Skan
358132718Skanstatic void enable_mask_for_builtins (struct builtin_description *, int,
359132718Skan				      enum rs6000_builtins,
360132718Skan				      enum rs6000_builtins);
361132718Skanstatic void spe_init_builtins (void);
362132718Skanstatic rtx spe_expand_builtin (tree, rtx, bool *);
363132718Skanstatic rtx spe_expand_stv_builtin (enum insn_code, tree);
364132718Skanstatic rtx spe_expand_predicate_builtin (enum insn_code, tree, rtx);
365132718Skanstatic rtx spe_expand_evsel_builtin (enum insn_code, tree, rtx);
366132718Skanstatic int rs6000_emit_int_cmove (rtx, rtx, rtx, rtx);
367132718Skanstatic rs6000_stack_t *rs6000_stack_info (void);
368132718Skanstatic void debug_stack_info (rs6000_stack_t *);
369117395Skan
370132718Skanstatic rtx altivec_expand_builtin (tree, rtx, bool *);
371132718Skanstatic rtx altivec_expand_ld_builtin (tree, rtx, bool *);
372132718Skanstatic rtx altivec_expand_st_builtin (tree, rtx, bool *);
373132718Skanstatic rtx altivec_expand_dst_builtin (tree, rtx, bool *);
374132718Skanstatic rtx altivec_expand_abs_builtin (enum insn_code, tree, rtx);
375132718Skanstatic rtx altivec_expand_predicate_builtin (enum insn_code,
376132718Skan					    const char *, tree, rtx);
377132718Skanstatic rtx altivec_expand_lv_builtin (enum insn_code, tree, rtx);
378132718Skanstatic rtx altivec_expand_stv_builtin (enum insn_code, tree);
379132718Skanstatic void rs6000_parse_abi_options (void);
380132718Skanstatic void rs6000_parse_alignment_option (void);
381132718Skanstatic void rs6000_parse_tls_size_option (void);
382132718Skanstatic void rs6000_parse_yes_no_option (const char *, const char *, int *);
383132718Skanstatic int first_altivec_reg_to_save (void);
384132718Skanstatic unsigned int compute_vrsave_mask (void);
385132718Skanstatic void is_altivec_return_reg (rtx, void *);
386132718Skanstatic rtx generate_set_vrsave (rtx, rs6000_stack_t *, int);
387132718Skanint easy_vector_constant (rtx, enum machine_mode);
388132718Skanstatic int easy_vector_same (rtx, enum machine_mode);
389132718Skanstatic int easy_vector_splat_const (int, enum machine_mode);
390132718Skanstatic bool is_ev64_opaque_type (tree);
391132718Skanstatic rtx rs6000_dwarf_register_span (rtx);
392132718Skanstatic rtx rs6000_legitimize_tls_address (rtx, enum tls_model);
393132718Skanstatic rtx rs6000_tls_get_addr (void);
394132718Skanstatic rtx rs6000_got_sym (void);
395132718Skanstatic inline int rs6000_tls_symbol_ref_1 (rtx *, void *);
396132718Skanstatic const char *rs6000_get_some_local_dynamic_name (void);
397132718Skanstatic int rs6000_get_some_local_dynamic_name_1 (rtx *, void *);
398132718Skanstatic rtx rs6000_complex_function_value (enum machine_mode);
399132718Skanstatic rtx rs6000_spe_function_arg (CUMULATIVE_ARGS *,
400132718Skan				    enum machine_mode, tree);
401132718Skanstatic rtx rs6000_mixed_function_arg (CUMULATIVE_ARGS *,
402132718Skan				      enum machine_mode, tree, int);
403132718Skanstatic void rs6000_move_block_from_reg (int regno, rtx x, int nregs);
404132718Skanstatic void setup_incoming_varargs (CUMULATIVE_ARGS *,
405132718Skan				    enum machine_mode, tree,
406132718Skan				    int *, int);
407132718Skan#if TARGET_MACHO
408132718Skanstatic void macho_branch_islands (void);
409132718Skanstatic void add_compiler_branch_island (tree, tree, int);
410132718Skanstatic int no_previous_def (tree function_name);
411132718Skanstatic tree get_prev_label (tree function_name);
412132718Skan#endif
413132718Skan
414132718Skanstatic tree rs6000_build_builtin_va_list (void);
415132718Skan
416132718Skan/* Hash table stuff for keeping track of TOC entries.  */
417132718Skan
418132718Skanstruct toc_hash_struct GTY(())
419132718Skan{
420132718Skan  /* `key' will satisfy CONSTANT_P; in fact, it will satisfy
421132718Skan     ASM_OUTPUT_SPECIAL_POOL_ENTRY_P.  */
422132718Skan  rtx key;
423132718Skan  enum machine_mode key_mode;
424132718Skan  int labelno;
425132718Skan};
426132718Skan
427132718Skanstatic GTY ((param_is (struct toc_hash_struct))) htab_t toc_hash_table;
42890075Sobrien
42990075Sobrien/* Default register names.  */
43090075Sobrienchar rs6000_reg_names[][8] =
43190075Sobrien{
43290075Sobrien      "0",  "1",  "2",  "3",  "4",  "5",  "6",  "7",
43390075Sobrien      "8",  "9", "10", "11", "12", "13", "14", "15",
43490075Sobrien     "16", "17", "18", "19", "20", "21", "22", "23",
43590075Sobrien     "24", "25", "26", "27", "28", "29", "30", "31",
43690075Sobrien      "0",  "1",  "2",  "3",  "4",  "5",  "6",  "7",
43790075Sobrien      "8",  "9", "10", "11", "12", "13", "14", "15",
43890075Sobrien     "16", "17", "18", "19", "20", "21", "22", "23",
43990075Sobrien     "24", "25", "26", "27", "28", "29", "30", "31",
44090075Sobrien     "mq", "lr", "ctr","ap",
44190075Sobrien      "0",  "1",  "2",  "3",  "4",  "5",  "6",  "7",
44290075Sobrien      "xer",
44390075Sobrien      /* AltiVec registers.  */
44490075Sobrien      "0",  "1",  "2",  "3",  "4",  "5",  "6", "7",
44590075Sobrien      "8",  "9",  "10", "11", "12", "13", "14", "15",
44690075Sobrien      "16", "17", "18", "19", "20", "21", "22", "23",
44790075Sobrien      "24", "25", "26", "27", "28", "29", "30", "31",
448117395Skan      "vrsave", "vscr",
449117395Skan      /* SPE registers.  */
450117395Skan      "spe_acc", "spefscr"
45190075Sobrien};
45290075Sobrien
45390075Sobrien#ifdef TARGET_REGNAMES
45490075Sobrienstatic const char alt_reg_names[][8] =
45590075Sobrien{
45690075Sobrien   "%r0",   "%r1",  "%r2",  "%r3",  "%r4",  "%r5",  "%r6",  "%r7",
45790075Sobrien   "%r8",   "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15",
45890075Sobrien  "%r16",  "%r17", "%r18", "%r19", "%r20", "%r21", "%r22", "%r23",
45990075Sobrien  "%r24",  "%r25", "%r26", "%r27", "%r28", "%r29", "%r30", "%r31",
46090075Sobrien   "%f0",   "%f1",  "%f2",  "%f3",  "%f4",  "%f5",  "%f6",  "%f7",
46190075Sobrien   "%f8",   "%f9", "%f10", "%f11", "%f12", "%f13", "%f14", "%f15",
46290075Sobrien  "%f16",  "%f17", "%f18", "%f19", "%f20", "%f21", "%f22", "%f23",
46390075Sobrien  "%f24",  "%f25", "%f26", "%f27", "%f28", "%f29", "%f30", "%f31",
46490075Sobrien    "mq",    "lr",  "ctr",   "ap",
46590075Sobrien  "%cr0",  "%cr1", "%cr2", "%cr3", "%cr4", "%cr5", "%cr6", "%cr7",
46690075Sobrien   "xer",
467117395Skan  /* AltiVec registers.  */
46890075Sobrien   "%v0",  "%v1",  "%v2",  "%v3",  "%v4",  "%v5",  "%v6", "%v7",
469117395Skan   "%v8",  "%v9", "%v10", "%v11", "%v12", "%v13", "%v14", "%v15",
470117395Skan  "%v16", "%v17", "%v18", "%v19", "%v20", "%v21", "%v22", "%v23",
471117395Skan  "%v24", "%v25", "%v26", "%v27", "%v28", "%v29", "%v30", "%v31",
472117395Skan  "vrsave", "vscr",
473117395Skan  /* SPE registers.  */
474117395Skan  "spe_acc", "spefscr"
47590075Sobrien};
47690075Sobrien#endif
47790075Sobrien
47890075Sobrien#ifndef MASK_STRICT_ALIGN
47990075Sobrien#define MASK_STRICT_ALIGN 0
48090075Sobrien#endif
481132718Skan#ifndef TARGET_PROFILE_KERNEL
482132718Skan#define TARGET_PROFILE_KERNEL 0
483132718Skan#endif
484117395Skan
485117395Skan/* The VRSAVE bitmask puts bit %v0 as the most significant bit.  */
486117395Skan#define ALTIVEC_REG_BIT(REGNO) (0x80000000 >> ((REGNO) - FIRST_ALTIVEC_REGNO))
487132718Skan
488132718Skan/* Return 1 for a symbol ref for a thread-local storage symbol.  */
489132718Skan#define RS6000_SYMBOL_REF_TLS_P(RTX) \
490132718Skan  (GET_CODE (RTX) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (RTX) != 0)
49190075Sobrien
49290075Sobrien/* Initialize the GCC target structure.  */
49390075Sobrien#undef TARGET_ATTRIBUTE_TABLE
49490075Sobrien#define TARGET_ATTRIBUTE_TABLE rs6000_attribute_table
495117395Skan#undef TARGET_SET_DEFAULT_TYPE_ATTRIBUTES
496117395Skan#define TARGET_SET_DEFAULT_TYPE_ATTRIBUTES rs6000_set_default_type_attributes
49790075Sobrien
49890075Sobrien#undef TARGET_ASM_ALIGNED_DI_OP
49990075Sobrien#define TARGET_ASM_ALIGNED_DI_OP DOUBLE_INT_ASM_OP
50090075Sobrien
50190075Sobrien/* Default unaligned ops are only provided for ELF.  Find the ops needed
50290075Sobrien   for non-ELF systems.  */
50390075Sobrien#ifndef OBJECT_FORMAT_ELF
504117395Skan#if TARGET_XCOFF
50590075Sobrien/* For XCOFF.  rs6000_assemble_integer will handle unaligned DIs on
50690075Sobrien   64-bit targets.  */
50790075Sobrien#undef TARGET_ASM_UNALIGNED_HI_OP
50890075Sobrien#define TARGET_ASM_UNALIGNED_HI_OP "\t.vbyte\t2,"
50990075Sobrien#undef TARGET_ASM_UNALIGNED_SI_OP
51090075Sobrien#define TARGET_ASM_UNALIGNED_SI_OP "\t.vbyte\t4,"
51190075Sobrien#undef TARGET_ASM_UNALIGNED_DI_OP
51290075Sobrien#define TARGET_ASM_UNALIGNED_DI_OP "\t.vbyte\t8,"
51390075Sobrien#else
51490075Sobrien/* For Darwin.  */
51590075Sobrien#undef TARGET_ASM_UNALIGNED_HI_OP
51690075Sobrien#define TARGET_ASM_UNALIGNED_HI_OP "\t.short\t"
51790075Sobrien#undef TARGET_ASM_UNALIGNED_SI_OP
51890075Sobrien#define TARGET_ASM_UNALIGNED_SI_OP "\t.long\t"
51990075Sobrien#endif
52090075Sobrien#endif
52190075Sobrien
52290075Sobrien/* This hook deals with fixups for relocatable code and DI-mode objects
52390075Sobrien   in 64-bit code.  */
52490075Sobrien#undef TARGET_ASM_INTEGER
52590075Sobrien#define TARGET_ASM_INTEGER rs6000_assemble_integer
52690075Sobrien
527117395Skan#ifdef HAVE_GAS_HIDDEN
528117395Skan#undef TARGET_ASM_ASSEMBLE_VISIBILITY
529117395Skan#define TARGET_ASM_ASSEMBLE_VISIBILITY rs6000_assemble_visibility
530117395Skan#endif
531117395Skan
532132718Skan#undef TARGET_HAVE_TLS
533132718Skan#define TARGET_HAVE_TLS HAVE_AS_TLS
534132718Skan
535132718Skan#undef TARGET_CANNOT_FORCE_CONST_MEM
536132718Skan#define TARGET_CANNOT_FORCE_CONST_MEM rs6000_tls_referenced_p
537132718Skan
53890075Sobrien#undef TARGET_ASM_FUNCTION_PROLOGUE
53990075Sobrien#define TARGET_ASM_FUNCTION_PROLOGUE rs6000_output_function_prologue
54090075Sobrien#undef TARGET_ASM_FUNCTION_EPILOGUE
54190075Sobrien#define TARGET_ASM_FUNCTION_EPILOGUE rs6000_output_function_epilogue
54290075Sobrien
543132718Skan#undef  TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE
544132718Skan#define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE rs6000_use_dfa_pipeline_interface
545132718Skan#undef  TARGET_SCHED_VARIABLE_ISSUE
546132718Skan#define TARGET_SCHED_VARIABLE_ISSUE rs6000_variable_issue
547132718Skan
54890075Sobrien#undef TARGET_SCHED_ISSUE_RATE
54990075Sobrien#define TARGET_SCHED_ISSUE_RATE rs6000_issue_rate
55090075Sobrien#undef TARGET_SCHED_ADJUST_COST
55190075Sobrien#define TARGET_SCHED_ADJUST_COST rs6000_adjust_cost
55290075Sobrien#undef TARGET_SCHED_ADJUST_PRIORITY
55390075Sobrien#define TARGET_SCHED_ADJUST_PRIORITY rs6000_adjust_priority
554132718Skan#undef TARGET_SCHED_IS_COSTLY_DEPENDENCE
555132718Skan#define TARGET_SCHED_IS_COSTLY_DEPENDENCE rs6000_is_costly_dependence
556132718Skan#undef TARGET_SCHED_FINISH
557132718Skan#define TARGET_SCHED_FINISH rs6000_sched_finish
55890075Sobrien
559132718Skan#undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD
560132718Skan#define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD rs6000_use_sched_lookahead
561132718Skan
56290075Sobrien#undef TARGET_INIT_BUILTINS
56390075Sobrien#define TARGET_INIT_BUILTINS rs6000_init_builtins
56490075Sobrien
56590075Sobrien#undef TARGET_EXPAND_BUILTIN
56690075Sobrien#define TARGET_EXPAND_BUILTIN rs6000_expand_builtin
56790075Sobrien
568132718Skan#undef TARGET_INIT_LIBFUNCS
569132718Skan#define TARGET_INIT_LIBFUNCS rs6000_init_libfuncs
570132718Skan
571132718Skan#if TARGET_MACHO
572117395Skan#undef TARGET_BINDS_LOCAL_P
573117395Skan#define TARGET_BINDS_LOCAL_P rs6000_binds_local_p
574132718Skan#endif
57590075Sobrien
576117395Skan#undef TARGET_ASM_OUTPUT_MI_THUNK
577117395Skan#define TARGET_ASM_OUTPUT_MI_THUNK rs6000_output_mi_thunk
578117395Skan
579117395Skan#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
580132718Skan#define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_tree_hwi_hwi_tree_true
581117395Skan
582132718Skan#undef TARGET_FUNCTION_OK_FOR_SIBCALL
583132718Skan#define TARGET_FUNCTION_OK_FOR_SIBCALL rs6000_function_ok_for_sibcall
584132718Skan
585132718Skan#undef TARGET_RTX_COSTS
586132718Skan#define TARGET_RTX_COSTS rs6000_rtx_costs
587132718Skan#undef TARGET_ADDRESS_COST
588132718Skan#define TARGET_ADDRESS_COST hook_int_rtx_0
589132718Skan
590132718Skan#undef TARGET_VECTOR_OPAQUE_P
591132718Skan#define TARGET_VECTOR_OPAQUE_P is_ev64_opaque_type
592132718Skan
593132718Skan#undef TARGET_DWARF_REGISTER_SPAN
594132718Skan#define TARGET_DWARF_REGISTER_SPAN rs6000_dwarf_register_span
595132718Skan
596132718Skan/* On rs6000, function arguments are promoted, as are function return
597132718Skan   values.  */
598132718Skan#undef TARGET_PROMOTE_FUNCTION_ARGS
599132718Skan#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true
600132718Skan#undef TARGET_PROMOTE_FUNCTION_RETURN
601132718Skan#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
602132718Skan
603132718Skan/* Structure return values are passed as an extra parameter.  */
604132718Skan#undef TARGET_STRUCT_VALUE_RTX
605132718Skan#define TARGET_STRUCT_VALUE_RTX hook_rtx_tree_int_null
606132718Skan
607132718Skan#undef TARGET_RETURN_IN_MEMORY
608132718Skan#define TARGET_RETURN_IN_MEMORY rs6000_return_in_memory
609132718Skan
610132718Skan#undef TARGET_SETUP_INCOMING_VARARGS
611132718Skan#define TARGET_SETUP_INCOMING_VARARGS setup_incoming_varargs
612132718Skan
613132718Skan/* Always strict argument naming on rs6000.  */
614132718Skan#undef TARGET_STRICT_ARGUMENT_NAMING
615132718Skan#define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true
616132718Skan#undef TARGET_PRETEND_OUTGOING_VARARGS_NAMED
617132718Skan#define TARGET_PRETEND_OUTGOING_VARARGS_NAMED hook_bool_CUMULATIVE_ARGS_true
618132718Skan#undef TARGET_SPLIT_COMPLEX_ARG
619132718Skan#define TARGET_SPLIT_COMPLEX_ARG hook_bool_tree_true
620132718Skan
621132718Skan#undef TARGET_BUILD_BUILTIN_VA_LIST
622132718Skan#define TARGET_BUILD_BUILTIN_VA_LIST rs6000_build_builtin_va_list
623132718Skan
62490075Sobrienstruct gcc_target targetm = TARGET_INITIALIZER;
62590075Sobrien
62690075Sobrien/* Override command line options.  Mostly we process the processor
62790075Sobrien   type and sometimes adjust other TARGET_ options.  */
62890075Sobrien
62990075Sobrienvoid
630132718Skanrs6000_override_options (const char *default_cpu)
63190075Sobrien{
63290075Sobrien  size_t i, j;
63390075Sobrien  struct rs6000_cpu_select *ptr;
634132718Skan  int set_masks;
63590075Sobrien
636132718Skan  /* Simplifications for entries below.  */
63790075Sobrien
638132718Skan  enum {
639132718Skan    POWERPC_BASE_MASK = MASK_POWERPC | MASK_NEW_MNEMONICS,
640132718Skan    POWERPC_7400_MASK = POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_ALTIVEC
641132718Skan  };
64290075Sobrien
643132718Skan  /* This table occasionally claims that a processor does not support
644132718Skan     a particular feature even though it does, but the feature is slower
645132718Skan     than the alternative.  Thus, it shouldn't be relied on as a
646132718Skan     complete description of the processor's support.
647132718Skan
648132718Skan     Please keep this list in order, and don't forget to update the
649132718Skan     documentation in invoke.texi when adding a new processor or
650132718Skan     flag.  */
65190075Sobrien  static struct ptt
65290075Sobrien    {
65390075Sobrien      const char *const name;		/* Canonical processor name.  */
65490075Sobrien      const enum processor_type processor; /* Processor type enum value.  */
65590075Sobrien      const int target_enable;	/* Target flags to enable.  */
65690075Sobrien    } const processor_target_table[]
657132718Skan      = {{"401", PROCESSOR_PPC403, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
658132718Skan	 {"403", PROCESSOR_PPC403,
659132718Skan	  POWERPC_BASE_MASK | MASK_SOFT_FLOAT | MASK_STRICT_ALIGN},
660132718Skan	 {"405", PROCESSOR_PPC405, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
661132718Skan	 {"405fp", PROCESSOR_PPC405, POWERPC_BASE_MASK},
662132718Skan	 {"440", PROCESSOR_PPC440, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
663132718Skan	 {"440fp", PROCESSOR_PPC440, POWERPC_BASE_MASK},
664132718Skan	 {"505", PROCESSOR_MPCCORE, POWERPC_BASE_MASK},
665132718Skan	 {"601", PROCESSOR_PPC601,
666132718Skan	  MASK_POWER | POWERPC_BASE_MASK | MASK_MULTIPLE | MASK_STRING},
667132718Skan	 {"602", PROCESSOR_PPC603, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
668132718Skan	 {"603", PROCESSOR_PPC603, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
669132718Skan	 {"603e", PROCESSOR_PPC603, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
670132718Skan	 {"604", PROCESSOR_PPC604, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
671132718Skan	 {"604e", PROCESSOR_PPC604e, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
672132718Skan	 {"620", PROCESSOR_PPC620,
673132718Skan	  POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64},
674132718Skan	 {"630", PROCESSOR_PPC630,
675132718Skan	  POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64},
676132718Skan	 {"740", PROCESSOR_PPC750, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
677132718Skan	 {"7400", PROCESSOR_PPC7400, POWERPC_7400_MASK},
678132718Skan	 {"7450", PROCESSOR_PPC7450, POWERPC_7400_MASK},
679132718Skan	 {"750", PROCESSOR_PPC750, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
680132718Skan	 {"801", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
681132718Skan	 {"821", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
682132718Skan	 {"823", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
683132718Skan	 {"8540", PROCESSOR_PPC8540, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
684132718Skan	 {"860", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
685132718Skan	 {"970", PROCESSOR_POWER4,
686132718Skan	  POWERPC_7400_MASK | MASK_PPC_GPOPT | MASK_MFCRF | MASK_POWERPC64},
687132718Skan	 {"common", PROCESSOR_COMMON, MASK_NEW_MNEMONICS},
688132718Skan	 {"ec603e", PROCESSOR_PPC603, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
689132718Skan	 {"G3", PROCESSOR_PPC750, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
690132718Skan	 {"G4",  PROCESSOR_PPC7450, POWERPC_7400_MASK},
691132718Skan	 {"G5", PROCESSOR_POWER4,
692132718Skan	  POWERPC_7400_MASK | MASK_PPC_GPOPT | MASK_MFCRF | MASK_POWERPC64},
693132718Skan	 {"power", PROCESSOR_POWER, MASK_POWER | MASK_MULTIPLE | MASK_STRING},
69490075Sobrien	 {"power2", PROCESSOR_POWER,
695132718Skan	  MASK_POWER | MASK_POWER2 | MASK_MULTIPLE | MASK_STRING},
69690075Sobrien	 {"power3", PROCESSOR_PPC630,
697132718Skan	  POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64},
698117395Skan	 {"power4", PROCESSOR_POWER4,
699132718Skan	  POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_MFCRF | MASK_POWERPC64},
700132718Skan	 {"power5", PROCESSOR_POWER5,
701132718Skan	  POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_MFCRF | MASK_POWERPC64},
702132718Skan	 {"powerpc", PROCESSOR_POWERPC, POWERPC_BASE_MASK},
70390075Sobrien	 {"powerpc64", PROCESSOR_POWERPC64,
704132718Skan	  POWERPC_BASE_MASK | MASK_POWERPC64},
705132718Skan	 {"rios", PROCESSOR_RIOS1, MASK_POWER | MASK_MULTIPLE | MASK_STRING},
706132718Skan	 {"rios1", PROCESSOR_RIOS1, MASK_POWER | MASK_MULTIPLE | MASK_STRING},
70790075Sobrien	 {"rios2", PROCESSOR_RIOS2,
708132718Skan	  MASK_POWER | MASK_POWER2 | MASK_MULTIPLE | MASK_STRING},
709132718Skan	 {"rsc", PROCESSOR_PPC601, MASK_POWER | MASK_MULTIPLE | MASK_STRING},
710132718Skan	 {"rsc1", PROCESSOR_PPC601, MASK_POWER | MASK_MULTIPLE | MASK_STRING},
711132718Skan	 {"rs64a", PROCESSOR_RS64A, POWERPC_BASE_MASK | MASK_POWERPC64},
712132718Skan      };
71390075Sobrien
714117395Skan  const size_t ptt_size = ARRAY_SIZE (processor_target_table);
71590075Sobrien
716132718Skan  /* Some OSs don't support saving the high part of 64-bit registers on
717132718Skan     context switch.  Other OSs don't support saving Altivec registers.
718132718Skan     On those OSs, we don't touch the MASK_POWERPC64 or MASK_ALTIVEC
719132718Skan     settings; if the user wants either, the user must explicitly specify
720132718Skan     them and we won't interfere with the user's specification.  */
72190075Sobrien
722132718Skan  enum {
723132718Skan    POWER_MASKS = MASK_POWER | MASK_POWER2 | MASK_MULTIPLE | MASK_STRING,
724132718Skan    POWERPC_MASKS = (POWERPC_BASE_MASK | MASK_PPC_GPOPT
725132718Skan		     | MASK_PPC_GFXOPT | MASK_POWERPC64 | MASK_ALTIVEC
726132718Skan		     | MASK_MFCRF)
727132718Skan  };
728132718Skan set_masks = POWER_MASKS | POWERPC_MASKS | MASK_SOFT_FLOAT;
729132718Skan#ifdef OS_MISSING_POWERPC64
730132718Skan  if (OS_MISSING_POWERPC64)
731132718Skan    set_masks &= ~MASK_POWERPC64;
732132718Skan#endif
733132718Skan#ifdef OS_MISSING_ALTIVEC
734132718Skan  if (OS_MISSING_ALTIVEC)
735132718Skan    set_masks &= ~MASK_ALTIVEC;
736132718Skan#endif
737132718Skan
738132718Skan  /* Don't override these by the processor default if given explicitly.  */
739132718Skan  set_masks &= ~(target_flags_explicit
740132718Skan		 & (MASK_MULTIPLE | MASK_STRING | MASK_SOFT_FLOAT));
741132718Skan
74290075Sobrien  /* Identify the processor type.  */
74390075Sobrien  rs6000_select[0].string = default_cpu;
74490075Sobrien  rs6000_cpu = TARGET_POWERPC64 ? PROCESSOR_DEFAULT64 : PROCESSOR_DEFAULT;
74590075Sobrien
74690075Sobrien  for (i = 0; i < ARRAY_SIZE (rs6000_select); i++)
74790075Sobrien    {
74890075Sobrien      ptr = &rs6000_select[i];
74990075Sobrien      if (ptr->string != (char *)0 && ptr->string[0] != '\0')
75090075Sobrien	{
75190075Sobrien	  for (j = 0; j < ptt_size; j++)
75290075Sobrien	    if (! strcmp (ptr->string, processor_target_table[j].name))
75390075Sobrien	      {
75490075Sobrien		if (ptr->set_tune_p)
75590075Sobrien		  rs6000_cpu = processor_target_table[j].processor;
75690075Sobrien
75790075Sobrien		if (ptr->set_arch_p)
75890075Sobrien		  {
759132718Skan		    target_flags &= ~set_masks;
760132718Skan		    target_flags |= (processor_target_table[j].target_enable
761132718Skan				     & set_masks);
76290075Sobrien		  }
76390075Sobrien		break;
76490075Sobrien	      }
76590075Sobrien
76690075Sobrien	  if (j == ptt_size)
76790075Sobrien	    error ("bad value (%s) for %s switch", ptr->string, ptr->name);
76890075Sobrien	}
76990075Sobrien    }
77090075Sobrien
771132718Skan  if (TARGET_E500)
772117395Skan    rs6000_isel = 1;
773117395Skan
774117395Skan  /* If we are optimizing big endian systems for space, use the load/store
775117395Skan     multiple and string instructions.  */
77690075Sobrien  if (BYTES_BIG_ENDIAN && optimize_size)
777132718Skan    target_flags |= ~target_flags_explicit & (MASK_MULTIPLE | MASK_STRING);
77890075Sobrien
77990075Sobrien  /* Don't allow -mmultiple or -mstring on little endian systems
78090075Sobrien     unless the cpu is a 750, because the hardware doesn't support the
78190075Sobrien     instructions used in little endian mode, and causes an alignment
78290075Sobrien     trap.  The 750 does not cause an alignment trap (except when the
78390075Sobrien     target is unaligned).  */
78490075Sobrien
785132718Skan  if (!BYTES_BIG_ENDIAN && rs6000_cpu != PROCESSOR_PPC750)
78690075Sobrien    {
78790075Sobrien      if (TARGET_MULTIPLE)
78890075Sobrien	{
78990075Sobrien	  target_flags &= ~MASK_MULTIPLE;
790132718Skan	  if ((target_flags_explicit & MASK_MULTIPLE) != 0)
79190075Sobrien	    warning ("-mmultiple is not supported on little endian systems");
79290075Sobrien	}
79390075Sobrien
79490075Sobrien      if (TARGET_STRING)
79590075Sobrien	{
79690075Sobrien	  target_flags &= ~MASK_STRING;
797132718Skan	  if ((target_flags_explicit & MASK_STRING) != 0)
79890075Sobrien	    warning ("-mstring is not supported on little endian systems");
79990075Sobrien	}
80090075Sobrien    }
80190075Sobrien
80290075Sobrien  /* Set debug flags */
80390075Sobrien  if (rs6000_debug_name)
80490075Sobrien    {
80590075Sobrien      if (! strcmp (rs6000_debug_name, "all"))
80690075Sobrien	rs6000_debug_stack = rs6000_debug_arg = 1;
80790075Sobrien      else if (! strcmp (rs6000_debug_name, "stack"))
80890075Sobrien	rs6000_debug_stack = 1;
80990075Sobrien      else if (! strcmp (rs6000_debug_name, "arg"))
81090075Sobrien	rs6000_debug_arg = 1;
81190075Sobrien      else
81290075Sobrien	error ("unknown -mdebug-%s switch", rs6000_debug_name);
81390075Sobrien    }
81490075Sobrien
815117395Skan  if (rs6000_traceback_name)
816117395Skan    {
817117395Skan      if (! strncmp (rs6000_traceback_name, "full", 4))
818117395Skan	rs6000_traceback = traceback_full;
819117395Skan      else if (! strncmp (rs6000_traceback_name, "part", 4))
820117395Skan	rs6000_traceback = traceback_part;
821117395Skan      else if (! strncmp (rs6000_traceback_name, "no", 2))
822117395Skan	rs6000_traceback = traceback_none;
823117395Skan      else
824117395Skan	error ("unknown -mtraceback arg `%s'; expecting `full', `partial' or `none'",
825117395Skan	       rs6000_traceback_name);
826117395Skan    }
827117395Skan
82890075Sobrien  /* Set size of long double */
82990075Sobrien  rs6000_long_double_type_size = 64;
83090075Sobrien  if (rs6000_long_double_size_string)
83190075Sobrien    {
83290075Sobrien      char *tail;
83390075Sobrien      int size = strtol (rs6000_long_double_size_string, &tail, 10);
83490075Sobrien      if (*tail != '\0' || (size != 64 && size != 128))
83590075Sobrien	error ("Unknown switch -mlong-double-%s",
83690075Sobrien	       rs6000_long_double_size_string);
83790075Sobrien      else
83890075Sobrien	rs6000_long_double_type_size = size;
83990075Sobrien    }
84090075Sobrien
841132718Skan  /* Set Altivec ABI as default for powerpc64 linux.  */
842132718Skan  if (TARGET_ELF && TARGET_64BIT)
843132718Skan    {
844132718Skan      rs6000_altivec_abi = 1;
845132718Skan      rs6000_altivec_vrsave = 1;
846132718Skan    }
847132718Skan
84890075Sobrien  /* Handle -mabi= options.  */
84990075Sobrien  rs6000_parse_abi_options ();
85090075Sobrien
851132718Skan  /* Handle -malign-XXXXX option.  */
852132718Skan  rs6000_parse_alignment_option ();
85390075Sobrien
854132718Skan  /* Handle generic -mFOO=YES/NO options.  */
855132718Skan  rs6000_parse_yes_no_option ("vrsave", rs6000_altivec_vrsave_string,
856132718Skan			      &rs6000_altivec_vrsave);
857132718Skan  rs6000_parse_yes_no_option ("isel", rs6000_isel_string,
858132718Skan			      &rs6000_isel);
859132718Skan  rs6000_parse_yes_no_option ("spe", rs6000_spe_string, &rs6000_spe);
860132718Skan  rs6000_parse_yes_no_option ("float-gprs", rs6000_float_gprs_string,
861132718Skan			      &rs6000_float_gprs);
862117395Skan
863132718Skan  /* Handle -mtls-size option.  */
864132718Skan  rs6000_parse_tls_size_option ();
865132718Skan
86690075Sobrien#ifdef SUBTARGET_OVERRIDE_OPTIONS
86790075Sobrien  SUBTARGET_OVERRIDE_OPTIONS;
86890075Sobrien#endif
86990075Sobrien#ifdef SUBSUBTARGET_OVERRIDE_OPTIONS
87090075Sobrien  SUBSUBTARGET_OVERRIDE_OPTIONS;
87190075Sobrien#endif
87290075Sobrien
873132718Skan  if (TARGET_E500)
874132718Skan    {
875132718Skan      if (TARGET_ALTIVEC)
876132718Skan      error ("AltiVec and E500 instructions cannot coexist");
877132718Skan
878132718Skan      /* The e500 does not have string instructions, and we set
879132718Skan	 MASK_STRING above when optimizing for size.  */
880132718Skan      if ((target_flags & MASK_STRING) != 0)
881132718Skan	target_flags = target_flags & ~MASK_STRING;
882132718Skan
883132718Skan      /* No SPE means 64-bit long doubles, even if an E500.  */
884132718Skan      if (rs6000_spe_string != 0
885132718Skan          && !strcmp (rs6000_spe_string, "no"))
886132718Skan	rs6000_long_double_type_size = 64;
887132718Skan    }
888132718Skan  else if (rs6000_select[1].string != NULL)
889132718Skan    {
890132718Skan      /* For the powerpc-eabispe configuration, we set all these by
891132718Skan	 default, so let's unset them if we manually set another
892132718Skan	 CPU that is not the E500.  */
893132718Skan      if (rs6000_abi_string == 0)
894132718Skan	rs6000_spe_abi = 0;
895132718Skan      if (rs6000_spe_string == 0)
896132718Skan	rs6000_spe = 0;
897132718Skan      if (rs6000_float_gprs_string == 0)
898132718Skan	rs6000_float_gprs = 0;
899132718Skan      if (rs6000_isel_string == 0)
900132718Skan	rs6000_isel = 0;
901132718Skan      if (rs6000_long_double_size_string == 0)
902132718Skan	rs6000_long_double_type_size = 64;
903132718Skan    }
904132718Skan
905132718Skan  rs6000_always_hint = (rs6000_cpu != PROCESSOR_POWER4
906132718Skan			&& rs6000_cpu != PROCESSOR_POWER5);
907132718Skan  rs6000_sched_groups = (rs6000_cpu == PROCESSOR_POWER4
908132718Skan			 || rs6000_cpu == PROCESSOR_POWER5);
909132718Skan
910117395Skan  /* Handle -m(no-)longcall option.  This is a bit of a cheap hack,
911117395Skan     using TARGET_OPTIONS to handle a toggle switch, but we're out of
912117395Skan     bits in target_flags so TARGET_SWITCHES cannot be used.
913117395Skan     Assumption here is that rs6000_longcall_switch points into the
914117395Skan     text of the complete option, rather than being a copy, so we can
915117395Skan     scan back for the presence or absence of the no- modifier.  */
916117395Skan  if (rs6000_longcall_switch)
917117395Skan    {
918117395Skan      const char *base = rs6000_longcall_switch;
919117395Skan      while (base[-1] != 'm') base--;
920117395Skan
921117395Skan      if (*rs6000_longcall_switch != '\0')
922117395Skan	error ("invalid option `%s'", base);
923117395Skan      rs6000_default_long_calls = (base[0] != 'n');
924117395Skan    }
925117395Skan
926132718Skan  /* Handle -mprioritize-restricted-insns option.  */
927132718Skan  rs6000_sched_restricted_insns_priority
928132718Skan    = (rs6000_sched_groups ? 1 : 0);
929132718Skan  if (rs6000_sched_restricted_insns_priority_str)
930132718Skan    rs6000_sched_restricted_insns_priority =
931132718Skan      atoi (rs6000_sched_restricted_insns_priority_str);
932132718Skan
933132718Skan  /* Handle -msched-costly-dep option.  */
934132718Skan  rs6000_sched_costly_dep
935132718Skan    = (rs6000_sched_groups ? store_to_load_dep_costly : no_dep_costly);
936132718Skan  if (rs6000_sched_costly_dep_str)
937132718Skan    {
938132718Skan      if (! strcmp (rs6000_sched_costly_dep_str, "no"))
939132718Skan        rs6000_sched_costly_dep = no_dep_costly;
940132718Skan      else if (! strcmp (rs6000_sched_costly_dep_str, "all"))
941132718Skan        rs6000_sched_costly_dep = all_deps_costly;
942132718Skan      else if (! strcmp (rs6000_sched_costly_dep_str, "true_store_to_load"))
943132718Skan        rs6000_sched_costly_dep = true_store_to_load_dep_costly;
944132718Skan      else if (! strcmp (rs6000_sched_costly_dep_str, "store_to_load"))
945132718Skan        rs6000_sched_costly_dep = store_to_load_dep_costly;
946132718Skan      else
947132718Skan        rs6000_sched_costly_dep = atoi (rs6000_sched_costly_dep_str);
948132718Skan    }
949132718Skan
950132718Skan  /* Handle -minsert-sched-nops option.  */
951132718Skan  rs6000_sched_insert_nops
952132718Skan    = (rs6000_sched_groups ? sched_finish_regroup_exact : sched_finish_none);
953132718Skan  if (rs6000_sched_insert_nops_str)
954132718Skan    {
955132718Skan      if (! strcmp (rs6000_sched_insert_nops_str, "no"))
956132718Skan        rs6000_sched_insert_nops = sched_finish_none;
957132718Skan      else if (! strcmp (rs6000_sched_insert_nops_str, "pad"))
958132718Skan        rs6000_sched_insert_nops = sched_finish_pad_groups;
959132718Skan      else if (! strcmp (rs6000_sched_insert_nops_str, "regroup_exact"))
960132718Skan        rs6000_sched_insert_nops = sched_finish_regroup_exact;
961132718Skan      else
962132718Skan        rs6000_sched_insert_nops = atoi (rs6000_sched_insert_nops_str);
963132718Skan    }
964132718Skan
965117395Skan#ifdef TARGET_REGNAMES
966117395Skan  /* If the user desires alternate register names, copy in the
967117395Skan     alternate names now.  */
968117395Skan  if (TARGET_REGNAMES)
969117395Skan    memcpy (rs6000_reg_names, alt_reg_names, sizeof (rs6000_reg_names));
970117395Skan#endif
971117395Skan
97290075Sobrien  /* Set TARGET_AIX_STRUCT_RET last, after the ABI is determined.
97390075Sobrien     If -maix-struct-return or -msvr4-struct-return was explicitly
97490075Sobrien     used, don't override with the ABI default.  */
975132718Skan  if ((target_flags_explicit & MASK_AIX_STRUCT_RET) == 0)
97690075Sobrien    {
97790075Sobrien      if (DEFAULT_ABI == ABI_V4 && !DRAFT_V4_STRUCT_RET)
97890075Sobrien	target_flags = (target_flags & ~MASK_AIX_STRUCT_RET);
97990075Sobrien      else
98090075Sobrien	target_flags |= MASK_AIX_STRUCT_RET;
98190075Sobrien    }
98290075Sobrien
983117395Skan  if (TARGET_LONG_DOUBLE_128
984117395Skan      && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_DARWIN))
985132718Skan    REAL_MODE_FORMAT (TFmode) = &ibm_extended_format;
986117395Skan
98790075Sobrien  /* Allocate an alias set for register saves & restores from stack.  */
98890075Sobrien  rs6000_sr_alias_set = new_alias_set ();
98990075Sobrien
99090075Sobrien  if (TARGET_TOC)
99190075Sobrien    ASM_GENERATE_INTERNAL_LABEL (toc_label_name, "LCTOC", 1);
99290075Sobrien
99390075Sobrien  /* We can only guarantee the availability of DI pseudo-ops when
99490075Sobrien     assembling for 64-bit targets.  */
99590075Sobrien  if (!TARGET_64BIT)
99690075Sobrien    {
99790075Sobrien      targetm.asm_out.aligned_op.di = NULL;
99890075Sobrien      targetm.asm_out.unaligned_op.di = NULL;
99990075Sobrien    }
100090075Sobrien
1001132718Skan  /* Set maximum branch target alignment at two instructions, eight bytes.  */
1002132718Skan  align_jumps_max_skip = 8;
1003132718Skan  align_loops_max_skip = 8;
1004132718Skan
100590075Sobrien  /* Arrange to save and restore machine status around nested functions.  */
100690075Sobrien  init_machine_status = rs6000_init_machine_status;
1007132718Skan
1008132718Skan  /* We should always be splitting complex arguments, but we can't break
1009132718Skan     Linux and Darwin ABIs at the moment.  For now, only AIX is fixed.  */
1010132718Skan  if (DEFAULT_ABI != ABI_AIX)
1011132718Skan    targetm.calls.split_complex_arg = NULL;
101290075Sobrien}
101390075Sobrien
1014132718Skan/* Handle generic options of the form -mfoo=yes/no.
1015132718Skan   NAME is the option name.
1016132718Skan   VALUE is the option value.
1017132718Skan   FLAG is the pointer to the flag where to store a 1 or 0, depending on
1018132718Skan   whether the option value is 'yes' or 'no' respectively.  */
1019117395Skanstatic void
1020132718Skanrs6000_parse_yes_no_option (const char *name, const char *value, int *flag)
1021117395Skan{
1022132718Skan  if (value == 0)
1023117395Skan    return;
1024132718Skan  else if (!strcmp (value, "yes"))
1025132718Skan    *flag = 1;
1026132718Skan  else if (!strcmp (value, "no"))
1027132718Skan    *flag = 0;
1028117395Skan  else
1029132718Skan    error ("unknown -m%s= option specified: '%s'", name, value);
1030117395Skan}
1031117395Skan
103290075Sobrien/* Handle -mabi= options.  */
103390075Sobrienstatic void
1034132718Skanrs6000_parse_abi_options (void)
103590075Sobrien{
103690075Sobrien  if (rs6000_abi_string == 0)
103790075Sobrien    return;
103890075Sobrien  else if (! strcmp (rs6000_abi_string, "altivec"))
1039132718Skan    {
1040132718Skan      rs6000_altivec_abi = 1;
1041132718Skan      rs6000_spe_abi = 0;
1042132718Skan    }
104396263Sobrien  else if (! strcmp (rs6000_abi_string, "no-altivec"))
104496263Sobrien    rs6000_altivec_abi = 0;
1045117395Skan  else if (! strcmp (rs6000_abi_string, "spe"))
1046132718Skan    {
1047132718Skan      rs6000_spe_abi = 1;
1048132718Skan      rs6000_altivec_abi = 0;
1049132718Skan      if (!TARGET_SPE_ABI)
1050132718Skan	error ("not configured for ABI: '%s'", rs6000_abi_string);
1051132718Skan    }
1052132718Skan
1053117395Skan  else if (! strcmp (rs6000_abi_string, "no-spe"))
1054117395Skan    rs6000_spe_abi = 0;
105590075Sobrien  else
105690075Sobrien    error ("unknown ABI specified: '%s'", rs6000_abi_string);
105790075Sobrien}
105890075Sobrien
1059132718Skan/* Handle -malign-XXXXXX options.  */
1060132718Skanstatic void
1061132718Skanrs6000_parse_alignment_option (void)
1062132718Skan{
1063132718Skan  if (rs6000_alignment_string == 0)
1064132718Skan    return;
1065132718Skan  else if (! strcmp (rs6000_alignment_string, "power"))
1066132718Skan    rs6000_alignment_flags = MASK_ALIGN_POWER;
1067132718Skan  else if (! strcmp (rs6000_alignment_string, "natural"))
1068132718Skan    rs6000_alignment_flags = MASK_ALIGN_NATURAL;
1069132718Skan  else
1070132718Skan    error ("unknown -malign-XXXXX option specified: '%s'",
1071132718Skan	   rs6000_alignment_string);
1072132718Skan}
1073132718Skan
1074132718Skan/* Validate and record the size specified with the -mtls-size option.  */
1075132718Skan
1076132718Skanstatic void
1077132718Skanrs6000_parse_tls_size_option (void)
1078132718Skan{
1079132718Skan  if (rs6000_tls_size_string == 0)
1080132718Skan    return;
1081132718Skan  else if (strcmp (rs6000_tls_size_string, "16") == 0)
1082132718Skan    rs6000_tls_size = 16;
1083132718Skan  else if (strcmp (rs6000_tls_size_string, "32") == 0)
1084132718Skan    rs6000_tls_size = 32;
1085132718Skan  else if (strcmp (rs6000_tls_size_string, "64") == 0)
1086132718Skan    rs6000_tls_size = 64;
1087132718Skan  else
1088132718Skan    error ("bad value `%s' for -mtls-size switch", rs6000_tls_size_string);
1089132718Skan}
1090132718Skan
109190075Sobrienvoid
1092132718Skanoptimization_options (int level ATTRIBUTE_UNUSED, int size ATTRIBUTE_UNUSED)
109390075Sobrien{
109490075Sobrien}
109590075Sobrien
109690075Sobrien/* Do anything needed at the start of the asm file.  */
109790075Sobrien
1098132718Skanstatic void
1099132718Skanrs6000_file_start (void)
110090075Sobrien{
110190075Sobrien  size_t i;
110290075Sobrien  char buffer[80];
110390075Sobrien  const char *start = buffer;
110490075Sobrien  struct rs6000_cpu_select *ptr;
1105132718Skan  const char *default_cpu = TARGET_CPU_DEFAULT;
1106132718Skan  FILE *file = asm_out_file;
110790075Sobrien
1108132718Skan  default_file_start ();
1109132718Skan
1110132718Skan#ifdef TARGET_BI_ARCH
1111132718Skan  if ((TARGET_DEFAULT ^ target_flags) & MASK_64BIT)
1112132718Skan    default_cpu = 0;
1113132718Skan#endif
1114132718Skan
111590075Sobrien  if (flag_verbose_asm)
111690075Sobrien    {
111790075Sobrien      sprintf (buffer, "\n%s rs6000/powerpc options:", ASM_COMMENT_START);
111890075Sobrien      rs6000_select[0].string = default_cpu;
111990075Sobrien
112090075Sobrien      for (i = 0; i < ARRAY_SIZE (rs6000_select); i++)
112190075Sobrien	{
112290075Sobrien	  ptr = &rs6000_select[i];
112390075Sobrien	  if (ptr->string != (char *)0 && ptr->string[0] != '\0')
112490075Sobrien	    {
112590075Sobrien	      fprintf (file, "%s %s%s", start, ptr->name, ptr->string);
112690075Sobrien	      start = "";
112790075Sobrien	    }
112890075Sobrien	}
112990075Sobrien
113090075Sobrien#ifdef USING_ELFOS_H
113190075Sobrien      switch (rs6000_sdata)
113290075Sobrien	{
113390075Sobrien	case SDATA_NONE: fprintf (file, "%s -msdata=none", start); start = ""; break;
113490075Sobrien	case SDATA_DATA: fprintf (file, "%s -msdata=data", start); start = ""; break;
113590075Sobrien	case SDATA_SYSV: fprintf (file, "%s -msdata=sysv", start); start = ""; break;
113690075Sobrien	case SDATA_EABI: fprintf (file, "%s -msdata=eabi", start); start = ""; break;
113790075Sobrien	}
113890075Sobrien
113990075Sobrien      if (rs6000_sdata && g_switch_value)
114090075Sobrien	{
1141132718Skan	  fprintf (file, "%s -G " HOST_WIDE_INT_PRINT_UNSIGNED, start,
1142132718Skan		   g_switch_value);
114390075Sobrien	  start = "";
114490075Sobrien	}
114590075Sobrien#endif
114690075Sobrien
114790075Sobrien      if (*start == '\0')
114890075Sobrien	putc ('\n', file);
114990075Sobrien    }
115090075Sobrien}
115190075Sobrien
1152117395Skan/* Return nonzero if this function is known to have a null epilogue.  */
115390075Sobrien
115490075Sobrienint
1155132718Skandirect_return (void)
115690075Sobrien{
115790075Sobrien  if (reload_completed)
115890075Sobrien    {
115990075Sobrien      rs6000_stack_t *info = rs6000_stack_info ();
116090075Sobrien
116190075Sobrien      if (info->first_gp_reg_save == 32
116290075Sobrien	  && info->first_fp_reg_save == 64
116390075Sobrien	  && info->first_altivec_reg_save == LAST_ALTIVEC_REGNO + 1
116490075Sobrien	  && ! info->lr_save_p
116590075Sobrien	  && ! info->cr_save_p
116690075Sobrien	  && info->vrsave_mask == 0
116790075Sobrien	  && ! info->push_p)
116890075Sobrien	return 1;
116990075Sobrien    }
117090075Sobrien
117190075Sobrien  return 0;
117290075Sobrien}
117390075Sobrien
117490075Sobrien/* Returns 1 always.  */
117590075Sobrien
117690075Sobrienint
1177132718Skanany_operand (rtx op ATTRIBUTE_UNUSED,
1178132718Skan	     enum machine_mode mode ATTRIBUTE_UNUSED)
117990075Sobrien{
118090075Sobrien  return 1;
118190075Sobrien}
118290075Sobrien
118390075Sobrien/* Returns 1 if op is the count register.  */
118490075Sobrienint
1185132718Skancount_register_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
118690075Sobrien{
118790075Sobrien  if (GET_CODE (op) != REG)
118890075Sobrien    return 0;
118990075Sobrien
119090075Sobrien  if (REGNO (op) == COUNT_REGISTER_REGNUM)
119190075Sobrien    return 1;
119290075Sobrien
119390075Sobrien  if (REGNO (op) > FIRST_PSEUDO_REGISTER)
119490075Sobrien    return 1;
119590075Sobrien
119690075Sobrien  return 0;
119790075Sobrien}
119890075Sobrien
119996263Sobrien/* Returns 1 if op is an altivec register.  */
120090075Sobrienint
1201132718Skanaltivec_register_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
120296263Sobrien{
120396263Sobrien
120496263Sobrien  return (register_operand (op, mode)
120596263Sobrien	  && (GET_CODE (op) != REG
120696263Sobrien	      || REGNO (op) > FIRST_PSEUDO_REGISTER
120796263Sobrien	      || ALTIVEC_REGNO_P (REGNO (op))));
120896263Sobrien}
120996263Sobrien
121096263Sobrienint
1211132718Skanxer_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
121290075Sobrien{
121390075Sobrien  if (GET_CODE (op) != REG)
121490075Sobrien    return 0;
121590075Sobrien
121690075Sobrien  if (XER_REGNO_P (REGNO (op)))
121790075Sobrien    return 1;
121890075Sobrien
121990075Sobrien  return 0;
122090075Sobrien}
122190075Sobrien
122290075Sobrien/* Return 1 if OP is a signed 8-bit constant.  Int multiplication
122390075Sobrien   by such constants completes more quickly.  */
122490075Sobrien
122590075Sobrienint
1226132718Skans8bit_cint_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
122790075Sobrien{
122890075Sobrien  return ( GET_CODE (op) == CONST_INT
122990075Sobrien	  && (INTVAL (op) >= -128 && INTVAL (op) <= 127));
123090075Sobrien}
123190075Sobrien
123290075Sobrien/* Return 1 if OP is a constant that can fit in a D field.  */
123390075Sobrien
123490075Sobrienint
1235132718Skanshort_cint_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
123690075Sobrien{
123790075Sobrien  return (GET_CODE (op) == CONST_INT
123890075Sobrien	  && CONST_OK_FOR_LETTER_P (INTVAL (op), 'I'));
123990075Sobrien}
124090075Sobrien
124190075Sobrien/* Similar for an unsigned D field.  */
124290075Sobrien
124390075Sobrienint
1244132718Skanu_short_cint_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
124590075Sobrien{
124690075Sobrien  return (GET_CODE (op) == CONST_INT
124796263Sobrien	  && CONST_OK_FOR_LETTER_P (INTVAL (op) & GET_MODE_MASK (mode), 'K'));
124890075Sobrien}
124990075Sobrien
125090075Sobrien/* Return 1 if OP is a CONST_INT that cannot fit in a signed D field.  */
125190075Sobrien
125290075Sobrienint
1253132718Skannon_short_cint_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
125490075Sobrien{
125590075Sobrien  return (GET_CODE (op) == CONST_INT
125690075Sobrien	  && (unsigned HOST_WIDE_INT) (INTVAL (op) + 0x8000) >= 0x10000);
125790075Sobrien}
125890075Sobrien
125990075Sobrien/* Returns 1 if OP is a CONST_INT that is a positive value
126090075Sobrien   and an exact power of 2.  */
126190075Sobrien
126290075Sobrienint
1263132718Skanexact_log2_cint_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
126490075Sobrien{
126590075Sobrien  return (GET_CODE (op) == CONST_INT
126690075Sobrien	  && INTVAL (op) > 0
126790075Sobrien	  && exact_log2 (INTVAL (op)) >= 0);
126890075Sobrien}
126990075Sobrien
127090075Sobrien/* Returns 1 if OP is a register that is not special (i.e., not MQ,
127190075Sobrien   ctr, or lr).  */
127290075Sobrien
127390075Sobrienint
1274132718Skangpc_reg_operand (rtx op, enum machine_mode mode)
127590075Sobrien{
127690075Sobrien  return (register_operand (op, mode)
127790075Sobrien	  && (GET_CODE (op) != REG
127890075Sobrien	      || (REGNO (op) >= ARG_POINTER_REGNUM
127990075Sobrien		  && !XER_REGNO_P (REGNO (op)))
128090075Sobrien	      || REGNO (op) < MQ_REGNO));
128190075Sobrien}
128290075Sobrien
128390075Sobrien/* Returns 1 if OP is either a pseudo-register or a register denoting a
128490075Sobrien   CR field.  */
128590075Sobrien
128690075Sobrienint
1287132718Skancc_reg_operand (rtx op, enum machine_mode mode)
128890075Sobrien{
128990075Sobrien  return (register_operand (op, mode)
129090075Sobrien	  && (GET_CODE (op) != REG
129190075Sobrien	      || REGNO (op) >= FIRST_PSEUDO_REGISTER
129290075Sobrien	      || CR_REGNO_P (REGNO (op))));
129390075Sobrien}
129490075Sobrien
129590075Sobrien/* Returns 1 if OP is either a pseudo-register or a register denoting a
129690075Sobrien   CR field that isn't CR0.  */
129790075Sobrien
129890075Sobrienint
1299132718Skancc_reg_not_cr0_operand (rtx op, enum machine_mode mode)
130090075Sobrien{
130190075Sobrien  return (register_operand (op, mode)
130290075Sobrien	  && (GET_CODE (op) != REG
130390075Sobrien	      || REGNO (op) >= FIRST_PSEUDO_REGISTER
130490075Sobrien	      || CR_REGNO_NOT_CR0_P (REGNO (op))));
130590075Sobrien}
130690075Sobrien
130790075Sobrien/* Returns 1 if OP is either a constant integer valid for a D-field or
130890075Sobrien   a non-special register.  If a register, it must be in the proper
130990075Sobrien   mode unless MODE is VOIDmode.  */
131090075Sobrien
131190075Sobrienint
1312132718Skanreg_or_short_operand (rtx op, enum machine_mode mode)
131390075Sobrien{
131490075Sobrien  return short_cint_operand (op, mode) || gpc_reg_operand (op, mode);
131590075Sobrien}
131690075Sobrien
131790075Sobrien/* Similar, except check if the negation of the constant would be
1318132718Skan   valid for a D-field.  Don't allow a constant zero, since all the
1319132718Skan   patterns that call this predicate use "addic r1,r2,-constant" on
1320132718Skan   a constant value to set a carry when r2 is greater or equal to
1321132718Skan   "constant".  That doesn't work for zero.  */
132290075Sobrien
132390075Sobrienint
1324132718Skanreg_or_neg_short_operand (rtx op, enum machine_mode mode)
132590075Sobrien{
132690075Sobrien  if (GET_CODE (op) == CONST_INT)
1327132718Skan    return CONST_OK_FOR_LETTER_P (INTVAL (op), 'P') && INTVAL (op) != 0;
132890075Sobrien
132990075Sobrien  return gpc_reg_operand (op, mode);
133090075Sobrien}
133190075Sobrien
133296263Sobrien/* Returns 1 if OP is either a constant integer valid for a DS-field or
133396263Sobrien   a non-special register.  If a register, it must be in the proper
133496263Sobrien   mode unless MODE is VOIDmode.  */
133596263Sobrien
133696263Sobrienint
1337132718Skanreg_or_aligned_short_operand (rtx op, enum machine_mode mode)
133896263Sobrien{
133996263Sobrien  if (gpc_reg_operand (op, mode))
134096263Sobrien    return 1;
134196263Sobrien  else if (short_cint_operand (op, mode) && !(INTVAL (op) & 3))
134296263Sobrien    return 1;
134396263Sobrien
134496263Sobrien  return 0;
134596263Sobrien}
134696263Sobrien
134796263Sobrien
134890075Sobrien/* Return 1 if the operand is either a register or an integer whose
134990075Sobrien   high-order 16 bits are zero.  */
135090075Sobrien
135190075Sobrienint
1352132718Skanreg_or_u_short_operand (rtx op, enum machine_mode mode)
135390075Sobrien{
135490075Sobrien  return u_short_cint_operand (op, mode) || gpc_reg_operand (op, mode);
135590075Sobrien}
135690075Sobrien
135790075Sobrien/* Return 1 is the operand is either a non-special register or ANY
135890075Sobrien   constant integer.  */
135990075Sobrien
136090075Sobrienint
1361132718Skanreg_or_cint_operand (rtx op, enum machine_mode mode)
136290075Sobrien{
136390075Sobrien  return (GET_CODE (op) == CONST_INT || gpc_reg_operand (op, mode));
136490075Sobrien}
136590075Sobrien
136690075Sobrien/* Return 1 is the operand is either a non-special register or ANY
136790075Sobrien   32-bit signed constant integer.  */
136890075Sobrien
136990075Sobrienint
1370132718Skanreg_or_arith_cint_operand (rtx op, enum machine_mode mode)
137190075Sobrien{
137290075Sobrien  return (gpc_reg_operand (op, mode)
137390075Sobrien	  || (GET_CODE (op) == CONST_INT
137490075Sobrien#if HOST_BITS_PER_WIDE_INT != 32
137590075Sobrien	      && ((unsigned HOST_WIDE_INT) (INTVAL (op) + 0x80000000)
137690075Sobrien		  < (unsigned HOST_WIDE_INT) 0x100000000ll)
137790075Sobrien#endif
137890075Sobrien	      ));
137990075Sobrien}
138090075Sobrien
138190075Sobrien/* Return 1 is the operand is either a non-special register or a 32-bit
138290075Sobrien   signed constant integer valid for 64-bit addition.  */
138390075Sobrien
138490075Sobrienint
1385132718Skanreg_or_add_cint64_operand (rtx op, enum machine_mode mode)
138690075Sobrien{
138790075Sobrien  return (gpc_reg_operand (op, mode)
138890075Sobrien	  || (GET_CODE (op) == CONST_INT
1389117395Skan#if HOST_BITS_PER_WIDE_INT == 32
139090075Sobrien	      && INTVAL (op) < 0x7fff8000
1391117395Skan#else
139290075Sobrien	      && ((unsigned HOST_WIDE_INT) (INTVAL (op) + 0x80008000)
139390075Sobrien		  < 0x100000000ll)
139490075Sobrien#endif
139590075Sobrien	      ));
139690075Sobrien}
139790075Sobrien
139890075Sobrien/* Return 1 is the operand is either a non-special register or a 32-bit
139990075Sobrien   signed constant integer valid for 64-bit subtraction.  */
140090075Sobrien
140190075Sobrienint
1402132718Skanreg_or_sub_cint64_operand (rtx op, enum machine_mode mode)
140390075Sobrien{
140490075Sobrien  return (gpc_reg_operand (op, mode)
140590075Sobrien	  || (GET_CODE (op) == CONST_INT
1406117395Skan#if HOST_BITS_PER_WIDE_INT == 32
140790075Sobrien	      && (- INTVAL (op)) < 0x7fff8000
1408117395Skan#else
140990075Sobrien	      && ((unsigned HOST_WIDE_INT) ((- INTVAL (op)) + 0x80008000)
141090075Sobrien		  < 0x100000000ll)
141190075Sobrien#endif
141290075Sobrien	      ));
141390075Sobrien}
141490075Sobrien
141590075Sobrien/* Return 1 is the operand is either a non-special register or ANY
141690075Sobrien   32-bit unsigned constant integer.  */
141790075Sobrien
141890075Sobrienint
1419132718Skanreg_or_logical_cint_operand (rtx op, enum machine_mode mode)
142090075Sobrien{
142190075Sobrien  if (GET_CODE (op) == CONST_INT)
142290075Sobrien    {
142390075Sobrien      if (GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT)
142490075Sobrien	{
142590075Sobrien	  if (GET_MODE_BITSIZE (mode) <= 32)
142690075Sobrien	    abort ();
142790075Sobrien
142890075Sobrien	  if (INTVAL (op) < 0)
142990075Sobrien	    return 0;
143090075Sobrien	}
143190075Sobrien
143290075Sobrien      return ((INTVAL (op) & GET_MODE_MASK (mode)
143390075Sobrien	       & (~ (unsigned HOST_WIDE_INT) 0xffffffff)) == 0);
143490075Sobrien    }
143590075Sobrien  else if (GET_CODE (op) == CONST_DOUBLE)
143690075Sobrien    {
143790075Sobrien      if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
143890075Sobrien	  || mode != DImode)
143990075Sobrien	abort ();
144090075Sobrien
144190075Sobrien      return CONST_DOUBLE_HIGH (op) == 0;
144290075Sobrien    }
144390075Sobrien  else
144490075Sobrien    return gpc_reg_operand (op, mode);
144590075Sobrien}
144690075Sobrien
144790075Sobrien/* Return 1 if the operand is an operand that can be loaded via the GOT.  */
144890075Sobrien
144990075Sobrienint
1450132718Skangot_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
145190075Sobrien{
145290075Sobrien  return (GET_CODE (op) == SYMBOL_REF
145390075Sobrien	  || GET_CODE (op) == CONST
145490075Sobrien	  || GET_CODE (op) == LABEL_REF);
145590075Sobrien}
145690075Sobrien
145790075Sobrien/* Return 1 if the operand is a simple references that can be loaded via
145890075Sobrien   the GOT (labels involving addition aren't allowed).  */
145990075Sobrien
146090075Sobrienint
1461132718Skangot_no_const_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
146290075Sobrien{
146390075Sobrien  return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF);
146490075Sobrien}
146590075Sobrien
146690075Sobrien/* Return the number of instructions it takes to form a constant in an
146790075Sobrien   integer register.  */
146890075Sobrien
146990075Sobrienstatic int
1470132718Skannum_insns_constant_wide (HOST_WIDE_INT value)
147190075Sobrien{
147290075Sobrien  /* signed constant loadable with {cal|addi} */
147390075Sobrien  if (CONST_OK_FOR_LETTER_P (value, 'I'))
147490075Sobrien    return 1;
147590075Sobrien
147690075Sobrien  /* constant loadable with {cau|addis} */
147790075Sobrien  else if (CONST_OK_FOR_LETTER_P (value, 'L'))
147890075Sobrien    return 1;
147990075Sobrien
148090075Sobrien#if HOST_BITS_PER_WIDE_INT == 64
148190075Sobrien  else if (TARGET_POWERPC64)
148290075Sobrien    {
1483117395Skan      HOST_WIDE_INT low  = ((value & 0xffffffff) ^ 0x80000000) - 0x80000000;
1484117395Skan      HOST_WIDE_INT high = value >> 31;
148590075Sobrien
1486117395Skan      if (high == 0 || high == -1)
148790075Sobrien	return 2;
148890075Sobrien
1489117395Skan      high >>= 1;
149090075Sobrien
1491117395Skan      if (low == 0)
149290075Sobrien	return num_insns_constant_wide (high) + 1;
149390075Sobrien      else
149490075Sobrien	return (num_insns_constant_wide (high)
149590075Sobrien		+ num_insns_constant_wide (low) + 1);
149690075Sobrien    }
149790075Sobrien#endif
149890075Sobrien
149990075Sobrien  else
150090075Sobrien    return 2;
150190075Sobrien}
150290075Sobrien
150390075Sobrienint
1504132718Skannum_insns_constant (rtx op, enum machine_mode mode)
150590075Sobrien{
150690075Sobrien  if (GET_CODE (op) == CONST_INT)
150790075Sobrien    {
150890075Sobrien#if HOST_BITS_PER_WIDE_INT == 64
150990075Sobrien      if ((INTVAL (op) >> 31) != 0 && (INTVAL (op) >> 31) != -1
151090075Sobrien	  && mask64_operand (op, mode))
151190075Sobrien	    return 2;
151290075Sobrien      else
151390075Sobrien#endif
151490075Sobrien	return num_insns_constant_wide (INTVAL (op));
151590075Sobrien    }
151690075Sobrien
151790075Sobrien  else if (GET_CODE (op) == CONST_DOUBLE && mode == SFmode)
151890075Sobrien    {
151990075Sobrien      long l;
152090075Sobrien      REAL_VALUE_TYPE rv;
152190075Sobrien
152290075Sobrien      REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
152390075Sobrien      REAL_VALUE_TO_TARGET_SINGLE (rv, l);
152496263Sobrien      return num_insns_constant_wide ((HOST_WIDE_INT) l);
152590075Sobrien    }
152690075Sobrien
152790075Sobrien  else if (GET_CODE (op) == CONST_DOUBLE)
152890075Sobrien    {
152990075Sobrien      HOST_WIDE_INT low;
153090075Sobrien      HOST_WIDE_INT high;
153190075Sobrien      long l[2];
153290075Sobrien      REAL_VALUE_TYPE rv;
153390075Sobrien      int endian = (WORDS_BIG_ENDIAN == 0);
153490075Sobrien
153590075Sobrien      if (mode == VOIDmode || mode == DImode)
153690075Sobrien	{
153790075Sobrien	  high = CONST_DOUBLE_HIGH (op);
153890075Sobrien	  low  = CONST_DOUBLE_LOW (op);
153990075Sobrien	}
154090075Sobrien      else
154190075Sobrien	{
154290075Sobrien	  REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
154390075Sobrien	  REAL_VALUE_TO_TARGET_DOUBLE (rv, l);
154490075Sobrien	  high = l[endian];
154590075Sobrien	  low  = l[1 - endian];
154690075Sobrien	}
154790075Sobrien
154890075Sobrien      if (TARGET_32BIT)
154990075Sobrien	return (num_insns_constant_wide (low)
155090075Sobrien		+ num_insns_constant_wide (high));
155190075Sobrien
155290075Sobrien      else
155390075Sobrien	{
155496263Sobrien	  if (high == 0 && low >= 0)
155590075Sobrien	    return num_insns_constant_wide (low);
155690075Sobrien
155796263Sobrien	  else if (high == -1 && low < 0)
155890075Sobrien	    return num_insns_constant_wide (low);
155990075Sobrien
156090075Sobrien	  else if (mask64_operand (op, mode))
156190075Sobrien	    return 2;
156290075Sobrien
156390075Sobrien	  else if (low == 0)
156490075Sobrien	    return num_insns_constant_wide (high) + 1;
156590075Sobrien
156690075Sobrien	  else
156790075Sobrien	    return (num_insns_constant_wide (high)
156890075Sobrien		    + num_insns_constant_wide (low) + 1);
156990075Sobrien	}
157090075Sobrien    }
157190075Sobrien
157290075Sobrien  else
157390075Sobrien    abort ();
157490075Sobrien}
157590075Sobrien
157690075Sobrien/* Return 1 if the operand is a CONST_DOUBLE and it can be put into a
157790075Sobrien   register with one instruction per word.  We only do this if we can
157890075Sobrien   safely read CONST_DOUBLE_{LOW,HIGH}.  */
157990075Sobrien
158090075Sobrienint
1581132718Skaneasy_fp_constant (rtx op, enum machine_mode mode)
158290075Sobrien{
158390075Sobrien  if (GET_CODE (op) != CONST_DOUBLE
158490075Sobrien      || GET_MODE (op) != mode
158590075Sobrien      || (GET_MODE_CLASS (mode) != MODE_FLOAT && mode != DImode))
158690075Sobrien    return 0;
158790075Sobrien
158890075Sobrien  /* Consider all constants with -msoft-float to be easy.  */
1589117395Skan  if ((TARGET_SOFT_FLOAT || !TARGET_FPRS)
1590117395Skan      && mode != DImode)
159190075Sobrien    return 1;
159290075Sobrien
159390075Sobrien  /* If we are using V.4 style PIC, consider all constants to be hard.  */
159490075Sobrien  if (flag_pic && DEFAULT_ABI == ABI_V4)
159590075Sobrien    return 0;
159690075Sobrien
159790075Sobrien#ifdef TARGET_RELOCATABLE
159890075Sobrien  /* Similarly if we are using -mrelocatable, consider all constants
159990075Sobrien     to be hard.  */
160090075Sobrien  if (TARGET_RELOCATABLE)
160190075Sobrien    return 0;
160290075Sobrien#endif
160390075Sobrien
1604117395Skan  if (mode == TFmode)
160590075Sobrien    {
1606117395Skan      long k[4];
1607117395Skan      REAL_VALUE_TYPE rv;
1608117395Skan
1609117395Skan      REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
1610117395Skan      REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, k);
1611117395Skan
1612117395Skan      return (num_insns_constant_wide ((HOST_WIDE_INT) k[0]) == 1
1613117395Skan	      && num_insns_constant_wide ((HOST_WIDE_INT) k[1]) == 1
1614117395Skan	      && num_insns_constant_wide ((HOST_WIDE_INT) k[2]) == 1
1615117395Skan	      && num_insns_constant_wide ((HOST_WIDE_INT) k[3]) == 1);
1616117395Skan    }
1617117395Skan
1618117395Skan  else if (mode == DFmode)
1619117395Skan    {
162090075Sobrien      long k[2];
162190075Sobrien      REAL_VALUE_TYPE rv;
162290075Sobrien
162390075Sobrien      REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
162490075Sobrien      REAL_VALUE_TO_TARGET_DOUBLE (rv, k);
162590075Sobrien
1626117395Skan      return (num_insns_constant_wide ((HOST_WIDE_INT) k[0]) == 1
1627117395Skan	      && num_insns_constant_wide ((HOST_WIDE_INT) k[1]) == 1);
162890075Sobrien    }
162990075Sobrien
163090075Sobrien  else if (mode == SFmode)
163190075Sobrien    {
163290075Sobrien      long l;
163390075Sobrien      REAL_VALUE_TYPE rv;
163490075Sobrien
163590075Sobrien      REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
163690075Sobrien      REAL_VALUE_TO_TARGET_SINGLE (rv, l);
163790075Sobrien
163890075Sobrien      return num_insns_constant_wide (l) == 1;
163990075Sobrien    }
164090075Sobrien
164190075Sobrien  else if (mode == DImode)
164290075Sobrien    return ((TARGET_POWERPC64
164390075Sobrien	     && GET_CODE (op) == CONST_DOUBLE && CONST_DOUBLE_LOW (op) == 0)
164490075Sobrien	    || (num_insns_constant (op, DImode) <= 2));
164590075Sobrien
164690075Sobrien  else if (mode == SImode)
164790075Sobrien    return 1;
164890075Sobrien  else
164990075Sobrien    abort ();
165090075Sobrien}
165190075Sobrien
1652132718Skan/* Returns the constant for the splat instrunction, if exists.  */
165396263Sobrien
165496263Sobrienstatic int
1655132718Skaneasy_vector_splat_const (int cst, enum machine_mode mode)
165696263Sobrien{
1657132718Skan  switch (mode)
1658132718Skan    {
1659132718Skan    case V4SImode:
1660132718Skan      if (EASY_VECTOR_15 (cst)
1661132718Skan	  || EASY_VECTOR_15_ADD_SELF (cst))
1662132718Skan	return cst;
1663132718Skan      if ((cst & 0xffff) != ((cst >> 16) & 0xffff))
1664132718Skan	break;
1665132718Skan      cst = cst >> 16;
1666132718Skan    case V8HImode:
1667132718Skan      if (EASY_VECTOR_15 (cst)
1668132718Skan	  || EASY_VECTOR_15_ADD_SELF (cst))
1669132718Skan	return cst;
1670132718Skan      if ((cst & 0xff) != ((cst >> 8) & 0xff))
1671132718Skan	break;
1672132718Skan      cst = cst >> 8;
1673132718Skan    case V16QImode:
1674132718Skan	  if (EASY_VECTOR_15 (cst)
1675132718Skan	      || EASY_VECTOR_15_ADD_SELF (cst))
1676132718Skan	    return cst;
1677132718Skan    default:
1678132718Skan      break;
1679132718Skan    }
1680132718Skan  return 0;
1681132718Skan}
168296263Sobrien
168396263Sobrien
1684132718Skan/* Return nonzero if all elements of a vector have the same value.  */
1685132718Skan
1686132718Skanstatic int
1687132718Skaneasy_vector_same (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
1688132718Skan{
1689132718Skan  int units, i, cst;
1690132718Skan
169196263Sobrien  units = CONST_VECTOR_NUNITS (op);
169296263Sobrien
1693132718Skan  cst = INTVAL (CONST_VECTOR_ELT (op, 0));
1694132718Skan  for (i = 1; i < units; ++i)
1695132718Skan    if (INTVAL (CONST_VECTOR_ELT (op, i)) != cst)
1696132718Skan      break;
1697132718Skan  if (i == units && easy_vector_splat_const (cst, mode))
1698132718Skan    return 1;
1699132718Skan  return 0;
1700132718Skan}
1701132718Skan
1702132718Skan/* Return 1 if the operand is a CONST_INT and can be put into a
1703132718Skan   register without using memory.  */
1704132718Skan
1705132718Skanint
1706132718Skaneasy_vector_constant (rtx op, enum machine_mode mode)
1707132718Skan{
1708132718Skan  int cst, cst2;
1709132718Skan
1710132718Skan  if (GET_CODE (op) != CONST_VECTOR
1711132718Skan      || (!TARGET_ALTIVEC
1712132718Skan	  && !TARGET_SPE))
1713132718Skan    return 0;
1714132718Skan
1715132718Skan  if (zero_constant (op, mode)
1716132718Skan      && ((TARGET_ALTIVEC && ALTIVEC_VECTOR_MODE (mode))
1717132718Skan	  || (TARGET_SPE && SPE_VECTOR_MODE (mode))))
1718132718Skan    return 1;
1719132718Skan
1720132718Skan  if (GET_MODE_CLASS (mode) != MODE_VECTOR_INT)
1721132718Skan    return 0;
1722132718Skan
1723132718Skan  if (TARGET_SPE && mode == V1DImode)
1724132718Skan    return 0;
1725132718Skan
1726132718Skan  cst  = INTVAL (CONST_VECTOR_ELT (op, 0));
1727132718Skan  cst2 = INTVAL (CONST_VECTOR_ELT (op, 1));
1728132718Skan
1729132718Skan  /* Limit SPE vectors to 15 bits signed.  These we can generate with:
1730132718Skan       li r0, CONSTANT1
1731132718Skan       evmergelo r0, r0, r0
1732132718Skan       li r0, CONSTANT2
1733132718Skan
1734132718Skan     I don't know how efficient it would be to allow bigger constants,
1735132718Skan     considering we'll have an extra 'ori' for every 'li'.  I doubt 5
1736132718Skan     instructions is better than a 64-bit memory load, but I don't
1737132718Skan     have the e500 timing specs.  */
1738132718Skan  if (TARGET_SPE && mode == V2SImode
1739132718Skan      && cst  >= -0x7fff && cst <= 0x7fff
1740132718Skan      && cst2 >= -0x7fff && cst2 <= 0x7fff)
1741132718Skan    return 1;
1742132718Skan
1743132718Skan  if (TARGET_ALTIVEC
1744132718Skan      && easy_vector_same (op, mode))
174596263Sobrien    {
1746132718Skan      cst = easy_vector_splat_const (cst, mode);
1747132718Skan      if (EASY_VECTOR_15_ADD_SELF (cst)
1748132718Skan	  || EASY_VECTOR_15 (cst))
1749132718Skan	return 1;
1750132718Skan    }
1751132718Skan  return 0;
1752132718Skan}
175396263Sobrien
1754132718Skan/* Same as easy_vector_constant but only for EASY_VECTOR_15_ADD_SELF.  */
175596263Sobrien
1756132718Skanint
1757132718Skaneasy_vector_constant_add_self (rtx op, enum machine_mode mode)
1758132718Skan{
1759132718Skan  int cst;
1760132718Skan  if (TARGET_ALTIVEC
1761132718Skan      && GET_CODE (op) == CONST_VECTOR
1762132718Skan      && easy_vector_same (op, mode))
1763132718Skan    {
1764132718Skan      cst = easy_vector_splat_const (INTVAL (CONST_VECTOR_ELT (op, 0)), mode);
1765132718Skan      if (EASY_VECTOR_15_ADD_SELF (cst))
1766132718Skan	return 1;
1767132718Skan    }
1768132718Skan  return 0;
1769132718Skan}
1770132718Skan
1771132718Skan/* Generate easy_vector_constant out of a easy_vector_constant_add_self.  */
1772132718Skan
1773132718Skanrtx
1774132718Skangen_easy_vector_constant_add_self (rtx op)
1775132718Skan{
1776132718Skan  int i, units;
1777132718Skan  rtvec v;
1778132718Skan  units = GET_MODE_NUNITS (GET_MODE (op));
1779132718Skan  v = rtvec_alloc (units);
1780132718Skan
1781132718Skan  for (i = 0; i < units; i++)
1782132718Skan    RTVEC_ELT (v, i) =
1783132718Skan      GEN_INT (INTVAL (CONST_VECTOR_ELT (op, i)) >> 1);
1784132718Skan  return gen_rtx_raw_CONST_VECTOR (GET_MODE (op), v);
1785132718Skan}
1786132718Skan
1787132718Skanconst char *
1788132718Skanoutput_vec_const_move (rtx *operands)
1789132718Skan{
1790132718Skan  int cst, cst2;
1791132718Skan  enum machine_mode mode;
1792132718Skan  rtx dest, vec;
1793132718Skan
1794132718Skan  dest = operands[0];
1795132718Skan  vec = operands[1];
1796132718Skan
1797132718Skan  cst = INTVAL (CONST_VECTOR_ELT (vec, 0));
1798132718Skan  cst2 = INTVAL (CONST_VECTOR_ELT (vec, 1));
1799132718Skan  mode = GET_MODE (dest);
1800132718Skan
1801132718Skan  if (TARGET_ALTIVEC)
1802132718Skan    {
1803132718Skan      if (zero_constant (vec, mode))
1804132718Skan	return "vxor %0,%0,%0";
1805132718Skan      else if (easy_vector_constant (vec, mode))
180696263Sobrien	{
1807132718Skan	  operands[1] = GEN_INT (cst);
1808132718Skan	  switch (mode)
1809132718Skan	    {
1810132718Skan	    case V4SImode:
1811132718Skan	      if (EASY_VECTOR_15 (cst))
1812132718Skan		{
1813132718Skan		  operands[1] = GEN_INT (cst);
1814132718Skan		  return "vspltisw %0,%1";
1815132718Skan		}
1816132718Skan	      else if (EASY_VECTOR_15_ADD_SELF (cst))
1817132718Skan		return "#";
1818132718Skan	      cst = cst >> 16;
1819132718Skan	    case V8HImode:
1820132718Skan	      if (EASY_VECTOR_15 (cst))
1821132718Skan		{
1822132718Skan		  operands[1] = GEN_INT (cst);
1823132718Skan		  return "vspltish %0,%1";
1824132718Skan		}
1825132718Skan	      else if (EASY_VECTOR_15_ADD_SELF (cst))
1826132718Skan		return "#";
1827132718Skan	      cst = cst >> 8;
1828132718Skan	    case V16QImode:
1829132718Skan	      if (EASY_VECTOR_15 (cst))
1830132718Skan		{
1831132718Skan		  operands[1] = GEN_INT (cst);
1832132718Skan		  return "vspltisb %0,%1";
1833132718Skan		}
1834132718Skan	      else if (EASY_VECTOR_15_ADD_SELF (cst))
1835132718Skan		return "#";
1836132718Skan	    default:
1837132718Skan	      abort ();
1838132718Skan	    }
183996263Sobrien	}
1840132718Skan      else
1841132718Skan	abort ();
184296263Sobrien    }
184396263Sobrien
1844132718Skan  if (TARGET_SPE)
1845132718Skan    {
1846132718Skan      /* Vector constant 0 is handled as a splitter of V2SI, and in the
1847132718Skan	 pattern of V1DI, V4HI, and V2SF.
1848132718Skan
1849132718Skan	 FIXME: We should probably return # and add post reload
1850132718Skan	 splitters for these, but this way is so easy ;-).
1851132718Skan      */
1852132718Skan      operands[1] = GEN_INT (cst);
1853132718Skan      operands[2] = GEN_INT (cst2);
1854132718Skan      if (cst == cst2)
1855132718Skan	return "li %0,%1\n\tevmergelo %0,%0,%0";
1856132718Skan      else
1857132718Skan	return "li %0,%1\n\tevmergelo %0,%0,%0\n\tli %0,%2";
1858132718Skan    }
1859132718Skan
1860132718Skan  abort ();
186196263Sobrien}
186296263Sobrien
186396263Sobrien/* Return 1 if the operand is the constant 0.  This works for scalars
186496263Sobrien   as well as vectors.  */
186596263Sobrienint
1866132718Skanzero_constant (rtx op, enum machine_mode mode)
186796263Sobrien{
186896263Sobrien  return op == CONST0_RTX (mode);
186996263Sobrien}
187096263Sobrien
187190075Sobrien/* Return 1 if the operand is 0.0.  */
187290075Sobrienint
1873132718Skanzero_fp_constant (rtx op, enum machine_mode mode)
187490075Sobrien{
187590075Sobrien  return GET_MODE_CLASS (mode) == MODE_FLOAT && op == CONST0_RTX (mode);
187690075Sobrien}
187790075Sobrien
187890075Sobrien/* Return 1 if the operand is in volatile memory.  Note that during
187990075Sobrien   the RTL generation phase, memory_operand does not return TRUE for
188090075Sobrien   volatile memory references.  So this function allows us to
188190075Sobrien   recognize volatile references where its safe.  */
188290075Sobrien
188390075Sobrienint
1884132718Skanvolatile_mem_operand (rtx op, enum machine_mode mode)
188590075Sobrien{
188690075Sobrien  if (GET_CODE (op) != MEM)
188790075Sobrien    return 0;
188890075Sobrien
188990075Sobrien  if (!MEM_VOLATILE_P (op))
189090075Sobrien    return 0;
189190075Sobrien
189290075Sobrien  if (mode != GET_MODE (op))
189390075Sobrien    return 0;
189490075Sobrien
189590075Sobrien  if (reload_completed)
189690075Sobrien    return memory_operand (op, mode);
189790075Sobrien
189890075Sobrien  if (reload_in_progress)
189990075Sobrien    return strict_memory_address_p (mode, XEXP (op, 0));
190090075Sobrien
190190075Sobrien  return memory_address_p (mode, XEXP (op, 0));
190290075Sobrien}
190390075Sobrien
190490075Sobrien/* Return 1 if the operand is an offsettable memory operand.  */
190590075Sobrien
190690075Sobrienint
1907132718Skanoffsettable_mem_operand (rtx op, enum machine_mode mode)
190890075Sobrien{
190990075Sobrien  return ((GET_CODE (op) == MEM)
191090075Sobrien	  && offsettable_address_p (reload_completed || reload_in_progress,
191190075Sobrien				    mode, XEXP (op, 0)));
191290075Sobrien}
191390075Sobrien
191490075Sobrien/* Return 1 if the operand is either an easy FP constant (see above) or
191590075Sobrien   memory.  */
191690075Sobrien
191790075Sobrienint
1918132718Skanmem_or_easy_const_operand (rtx op, enum machine_mode mode)
191990075Sobrien{
192090075Sobrien  return memory_operand (op, mode) || easy_fp_constant (op, mode);
192190075Sobrien}
192290075Sobrien
192390075Sobrien/* Return 1 if the operand is either a non-special register or an item
192490075Sobrien   that can be used as the operand of a `mode' add insn.  */
192590075Sobrien
192690075Sobrienint
1927132718Skanadd_operand (rtx op, enum machine_mode mode)
192890075Sobrien{
192990075Sobrien  if (GET_CODE (op) == CONST_INT)
193096263Sobrien    return (CONST_OK_FOR_LETTER_P (INTVAL (op), 'I')
193196263Sobrien	    || CONST_OK_FOR_LETTER_P (INTVAL (op), 'L'));
193290075Sobrien
193390075Sobrien  return gpc_reg_operand (op, mode);
193490075Sobrien}
193590075Sobrien
193690075Sobrien/* Return 1 if OP is a constant but not a valid add_operand.  */
193790075Sobrien
193890075Sobrienint
1939132718Skannon_add_cint_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
194090075Sobrien{
194190075Sobrien  return (GET_CODE (op) == CONST_INT
194296263Sobrien	  && !CONST_OK_FOR_LETTER_P (INTVAL (op), 'I')
194396263Sobrien	  && !CONST_OK_FOR_LETTER_P (INTVAL (op), 'L'));
194490075Sobrien}
194590075Sobrien
194690075Sobrien/* Return 1 if the operand is a non-special register or a constant that
194790075Sobrien   can be used as the operand of an OR or XOR insn on the RS/6000.  */
194890075Sobrien
194990075Sobrienint
1950132718Skanlogical_operand (rtx op, enum machine_mode mode)
195190075Sobrien{
195290075Sobrien  HOST_WIDE_INT opl, oph;
195390075Sobrien
195490075Sobrien  if (gpc_reg_operand (op, mode))
195590075Sobrien    return 1;
195690075Sobrien
195790075Sobrien  if (GET_CODE (op) == CONST_INT)
195890075Sobrien    {
195990075Sobrien      opl = INTVAL (op) & GET_MODE_MASK (mode);
196090075Sobrien
196190075Sobrien#if HOST_BITS_PER_WIDE_INT <= 32
196290075Sobrien      if (GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT && opl < 0)
196390075Sobrien	return 0;
196490075Sobrien#endif
196590075Sobrien    }
196690075Sobrien  else if (GET_CODE (op) == CONST_DOUBLE)
196790075Sobrien    {
196890075Sobrien      if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
196990075Sobrien	abort ();
197090075Sobrien
197190075Sobrien      opl = CONST_DOUBLE_LOW (op);
197290075Sobrien      oph = CONST_DOUBLE_HIGH (op);
197390075Sobrien      if (oph != 0)
197490075Sobrien	return 0;
197590075Sobrien    }
197690075Sobrien  else
197790075Sobrien    return 0;
197890075Sobrien
197990075Sobrien  return ((opl & ~ (unsigned HOST_WIDE_INT) 0xffff) == 0
198090075Sobrien	  || (opl & ~ (unsigned HOST_WIDE_INT) 0xffff0000) == 0);
198190075Sobrien}
198290075Sobrien
198390075Sobrien/* Return 1 if C is a constant that is not a logical operand (as
198490075Sobrien   above), but could be split into one.  */
198590075Sobrien
198690075Sobrienint
1987132718Skannon_logical_cint_operand (rtx op, enum machine_mode mode)
198890075Sobrien{
198990075Sobrien  return ((GET_CODE (op) == CONST_INT || GET_CODE (op) == CONST_DOUBLE)
199090075Sobrien	  && ! logical_operand (op, mode)
199190075Sobrien	  && reg_or_logical_cint_operand (op, mode));
199290075Sobrien}
199390075Sobrien
199490075Sobrien/* Return 1 if C is a constant that can be encoded in a 32-bit mask on the
199590075Sobrien   RS/6000.  It is if there are no more than two 1->0 or 0->1 transitions.
199690075Sobrien   Reject all ones and all zeros, since these should have been optimized
199790075Sobrien   away and confuse the making of MB and ME.  */
199890075Sobrien
199990075Sobrienint
2000132718Skanmask_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
200190075Sobrien{
200290075Sobrien  HOST_WIDE_INT c, lsb;
200390075Sobrien
200490075Sobrien  if (GET_CODE (op) != CONST_INT)
200590075Sobrien    return 0;
200690075Sobrien
200790075Sobrien  c = INTVAL (op);
200890075Sobrien
200996263Sobrien  /* Fail in 64-bit mode if the mask wraps around because the upper
201096263Sobrien     32-bits of the mask will all be 1s, contrary to GCC's internal view.  */
201196263Sobrien  if (TARGET_POWERPC64 && (c & 0x80000001) == 0x80000001)
201296263Sobrien    return 0;
201396263Sobrien
201490075Sobrien  /* We don't change the number of transitions by inverting,
201590075Sobrien     so make sure we start with the LS bit zero.  */
201690075Sobrien  if (c & 1)
201790075Sobrien    c = ~c;
201890075Sobrien
201990075Sobrien  /* Reject all zeros or all ones.  */
202090075Sobrien  if (c == 0)
202190075Sobrien    return 0;
202290075Sobrien
202390075Sobrien  /* Find the first transition.  */
202490075Sobrien  lsb = c & -c;
202590075Sobrien
202690075Sobrien  /* Invert to look for a second transition.  */
202790075Sobrien  c = ~c;
202890075Sobrien
202990075Sobrien  /* Erase first transition.  */
203090075Sobrien  c &= -lsb;
203190075Sobrien
203290075Sobrien  /* Find the second transition (if any).  */
203390075Sobrien  lsb = c & -c;
203490075Sobrien
203590075Sobrien  /* Match if all the bits above are 1's (or c is zero).  */
203690075Sobrien  return c == -lsb;
203790075Sobrien}
203890075Sobrien
2039117395Skan/* Return 1 for the PowerPC64 rlwinm corner case.  */
2040117395Skan
2041117395Skanint
2042132718Skanmask_operand_wrap (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
2043117395Skan{
2044117395Skan  HOST_WIDE_INT c, lsb;
2045117395Skan
2046117395Skan  if (GET_CODE (op) != CONST_INT)
2047117395Skan    return 0;
2048117395Skan
2049117395Skan  c = INTVAL (op);
2050117395Skan
2051117395Skan  if ((c & 0x80000001) != 0x80000001)
2052117395Skan    return 0;
2053117395Skan
2054117395Skan  c = ~c;
2055117395Skan  if (c == 0)
2056117395Skan    return 0;
2057117395Skan
2058117395Skan  lsb = c & -c;
2059117395Skan  c = ~c;
2060117395Skan  c &= -lsb;
2061117395Skan  lsb = c & -c;
2062117395Skan  return c == -lsb;
2063117395Skan}
2064117395Skan
206590075Sobrien/* Return 1 if the operand is a constant that is a PowerPC64 mask.
206690075Sobrien   It is if there are no more than one 1->0 or 0->1 transitions.
2067117395Skan   Reject all zeros, since zero should have been optimized away and
2068117395Skan   confuses the making of MB and ME.  */
206990075Sobrien
207090075Sobrienint
2071132718Skanmask64_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
207290075Sobrien{
207390075Sobrien  if (GET_CODE (op) == CONST_INT)
207490075Sobrien    {
207590075Sobrien      HOST_WIDE_INT c, lsb;
207690075Sobrien
2077117395Skan      c = INTVAL (op);
2078117395Skan
2079117395Skan      /* Reject all zeros.  */
2080117395Skan      if (c == 0)
2081117395Skan	return 0;
2082117395Skan
208390075Sobrien      /* We don't change the number of transitions by inverting,
208490075Sobrien	 so make sure we start with the LS bit zero.  */
208590075Sobrien      if (c & 1)
208690075Sobrien	c = ~c;
208790075Sobrien
208890075Sobrien      /* Find the transition, and check that all bits above are 1's.  */
208990075Sobrien      lsb = c & -c;
2090132718Skan
2091132718Skan      /* Match if all the bits above are 1's (or c is zero).  */
209290075Sobrien      return c == -lsb;
209390075Sobrien    }
2094117395Skan  return 0;
2095117395Skan}
2096117395Skan
2097117395Skan/* Like mask64_operand, but allow up to three transitions.  This
2098117395Skan   predicate is used by insn patterns that generate two rldicl or
2099117395Skan   rldicr machine insns.  */
2100117395Skan
2101117395Skanint
2102132718Skanmask64_2_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
2103117395Skan{
2104117395Skan  if (GET_CODE (op) == CONST_INT)
210590075Sobrien    {
2106117395Skan      HOST_WIDE_INT c, lsb;
210790075Sobrien
2108117395Skan      c = INTVAL (op);
210990075Sobrien
2110117395Skan      /* Disallow all zeros.  */
2111117395Skan      if (c == 0)
2112117395Skan	return 0;
211390075Sobrien
2114117395Skan      /* We don't change the number of transitions by inverting,
2115117395Skan	 so make sure we start with the LS bit zero.  */
2116117395Skan      if (c & 1)
2117117395Skan	c = ~c;
211890075Sobrien
2119117395Skan      /* Find the first transition.  */
2120117395Skan      lsb = c & -c;
212190075Sobrien
2122117395Skan      /* Invert to look for a second transition.  */
2123117395Skan      c = ~c;
2124117395Skan
2125117395Skan      /* Erase first transition.  */
2126117395Skan      c &= -lsb;
2127117395Skan
2128117395Skan      /* Find the second transition.  */
2129117395Skan      lsb = c & -c;
2130117395Skan
2131117395Skan      /* Invert to look for a third transition.  */
2132117395Skan      c = ~c;
2133117395Skan
2134117395Skan      /* Erase second transition.  */
2135117395Skan      c &= -lsb;
2136117395Skan
2137117395Skan      /* Find the third transition (if any).  */
2138117395Skan      lsb = c & -c;
2139117395Skan
2140117395Skan      /* Match if all the bits above are 1's (or c is zero).  */
2141117395Skan      return c == -lsb;
214290075Sobrien    }
2143117395Skan  return 0;
2144117395Skan}
2145117395Skan
2146117395Skan/* Generates shifts and masks for a pair of rldicl or rldicr insns to
2147117395Skan   implement ANDing by the mask IN.  */
2148117395Skanvoid
2149132718Skanbuild_mask64_2_operands (rtx in, rtx *out)
2150117395Skan{
2151117395Skan#if HOST_BITS_PER_WIDE_INT >= 64
2152117395Skan  unsigned HOST_WIDE_INT c, lsb, m1, m2;
2153117395Skan  int shift;
2154117395Skan
2155117395Skan  if (GET_CODE (in) != CONST_INT)
2156117395Skan    abort ();
2157117395Skan
2158117395Skan  c = INTVAL (in);
2159117395Skan  if (c & 1)
2160117395Skan    {
2161117395Skan      /* Assume c initially something like 0x00fff000000fffff.  The idea
2162117395Skan	 is to rotate the word so that the middle ^^^^^^ group of zeros
2163117395Skan	 is at the MS end and can be cleared with an rldicl mask.  We then
2164117395Skan	 rotate back and clear off the MS    ^^ group of zeros with a
2165117395Skan	 second rldicl.  */
2166117395Skan      c = ~c;			/*   c == 0xff000ffffff00000 */
2167117395Skan      lsb = c & -c;		/* lsb == 0x0000000000100000 */
2168117395Skan      m1 = -lsb;		/*  m1 == 0xfffffffffff00000 */
2169117395Skan      c = ~c;			/*   c == 0x00fff000000fffff */
2170117395Skan      c &= -lsb;		/*   c == 0x00fff00000000000 */
2171117395Skan      lsb = c & -c;		/* lsb == 0x0000100000000000 */
2172117395Skan      c = ~c;			/*   c == 0xff000fffffffffff */
2173117395Skan      c &= -lsb;		/*   c == 0xff00000000000000 */
2174117395Skan      shift = 0;
2175117395Skan      while ((lsb >>= 1) != 0)
2176117395Skan	shift++;		/* shift == 44 on exit from loop */
2177117395Skan      m1 <<= 64 - shift;	/*  m1 == 0xffffff0000000000 */
2178117395Skan      m1 = ~m1;			/*  m1 == 0x000000ffffffffff */
2179117395Skan      m2 = ~c;			/*  m2 == 0x00ffffffffffffff */
2180117395Skan    }
218190075Sobrien  else
2182117395Skan    {
2183117395Skan      /* Assume c initially something like 0xff000f0000000000.  The idea
2184117395Skan	 is to rotate the word so that the     ^^^  middle group of zeros
2185117395Skan	 is at the LS end and can be cleared with an rldicr mask.  We then
2186117395Skan	 rotate back and clear off the LS group of ^^^^^^^^^^ zeros with
2187117395Skan	 a second rldicr.  */
2188117395Skan      lsb = c & -c;		/* lsb == 0x0000010000000000 */
2189117395Skan      m2 = -lsb;		/*  m2 == 0xffffff0000000000 */
2190117395Skan      c = ~c;			/*   c == 0x00fff0ffffffffff */
2191117395Skan      c &= -lsb;		/*   c == 0x00fff00000000000 */
2192117395Skan      lsb = c & -c;		/* lsb == 0x0000100000000000 */
2193117395Skan      c = ~c;			/*   c == 0xff000fffffffffff */
2194117395Skan      c &= -lsb;		/*   c == 0xff00000000000000 */
2195117395Skan      shift = 0;
2196117395Skan      while ((lsb >>= 1) != 0)
2197117395Skan	shift++;		/* shift == 44 on exit from loop */
2198117395Skan      m1 = ~c;			/*  m1 == 0x00ffffffffffffff */
2199117395Skan      m1 >>= shift;		/*  m1 == 0x0000000000000fff */
2200117395Skan      m1 = ~m1;			/*  m1 == 0xfffffffffffff000 */
2201117395Skan    }
2202117395Skan
2203117395Skan  /* Note that when we only have two 0->1 and 1->0 transitions, one of the
2204117395Skan     masks will be all 1's.  We are guaranteed more than one transition.  */
2205117395Skan  out[0] = GEN_INT (64 - shift);
2206117395Skan  out[1] = GEN_INT (m1);
2207117395Skan  out[2] = GEN_INT (shift);
2208117395Skan  out[3] = GEN_INT (m2);
2209117395Skan#else
2210117395Skan  (void)in;
2211117395Skan  (void)out;
2212117395Skan  abort ();
2213117395Skan#endif
221490075Sobrien}
221590075Sobrien
221690075Sobrien/* Return 1 if the operand is either a non-special register or a constant
221790075Sobrien   that can be used as the operand of a PowerPC64 logical AND insn.  */
221890075Sobrien
221990075Sobrienint
2220132718Skanand64_operand (rtx op, enum machine_mode mode)
222190075Sobrien{
222290075Sobrien  if (fixed_regs[CR0_REGNO])	/* CR0 not available, don't do andi./andis.  */
222390075Sobrien    return (gpc_reg_operand (op, mode) || mask64_operand (op, mode));
222490075Sobrien
222590075Sobrien  return (logical_operand (op, mode) || mask64_operand (op, mode));
222690075Sobrien}
222790075Sobrien
2228117395Skan/* Like the above, but also match constants that can be implemented
2229117395Skan   with two rldicl or rldicr insns.  */
2230117395Skan
2231117395Skanint
2232132718Skanand64_2_operand (rtx op, enum machine_mode mode)
2233117395Skan{
2234132718Skan  if (fixed_regs[CR0_REGNO])	/* CR0 not available, don't do andi./andis.  */
2235117395Skan    return gpc_reg_operand (op, mode) || mask64_2_operand (op, mode);
2236117395Skan
2237117395Skan  return logical_operand (op, mode) || mask64_2_operand (op, mode);
2238117395Skan}
2239117395Skan
224090075Sobrien/* Return 1 if the operand is either a non-special register or a
224190075Sobrien   constant that can be used as the operand of an RS/6000 logical AND insn.  */
224290075Sobrien
224390075Sobrienint
2244132718Skanand_operand (rtx op, enum machine_mode mode)
224590075Sobrien{
224690075Sobrien  if (fixed_regs[CR0_REGNO])	/* CR0 not available, don't do andi./andis.  */
224790075Sobrien    return (gpc_reg_operand (op, mode) || mask_operand (op, mode));
224890075Sobrien
224990075Sobrien  return (logical_operand (op, mode) || mask_operand (op, mode));
225090075Sobrien}
225190075Sobrien
225290075Sobrien/* Return 1 if the operand is a general register or memory operand.  */
225390075Sobrien
225490075Sobrienint
2255132718Skanreg_or_mem_operand (rtx op, enum machine_mode mode)
225690075Sobrien{
225790075Sobrien  return (gpc_reg_operand (op, mode)
225890075Sobrien	  || memory_operand (op, mode)
2259132718Skan	  || macho_lo_sum_memory_operand (op, mode)
226090075Sobrien	  || volatile_mem_operand (op, mode));
226190075Sobrien}
226290075Sobrien
226390075Sobrien/* Return 1 if the operand is a general register or memory operand without
226490075Sobrien   pre_inc or pre_dec which produces invalid form of PowerPC lwa
226590075Sobrien   instruction.  */
226690075Sobrien
226790075Sobrienint
2268132718Skanlwa_operand (rtx op, enum machine_mode mode)
226990075Sobrien{
227090075Sobrien  rtx inner = op;
227190075Sobrien
227290075Sobrien  if (reload_completed && GET_CODE (inner) == SUBREG)
227390075Sobrien    inner = SUBREG_REG (inner);
227490075Sobrien
227590075Sobrien  return gpc_reg_operand (inner, mode)
227690075Sobrien    || (memory_operand (inner, mode)
227790075Sobrien	&& GET_CODE (XEXP (inner, 0)) != PRE_INC
227890075Sobrien	&& GET_CODE (XEXP (inner, 0)) != PRE_DEC
227990075Sobrien	&& (GET_CODE (XEXP (inner, 0)) != PLUS
228090075Sobrien	    || GET_CODE (XEXP (XEXP (inner, 0), 1)) != CONST_INT
228190075Sobrien	    || INTVAL (XEXP (XEXP (inner, 0), 1)) % 4 == 0));
228290075Sobrien}
228390075Sobrien
2284117395Skan/* Return 1 if the operand, used inside a MEM, is a SYMBOL_REF.  */
2285117395Skan
2286117395Skanint
2287132718Skansymbol_ref_operand (rtx op, enum machine_mode mode)
2288117395Skan{
2289117395Skan  if (mode != VOIDmode && GET_MODE (op) != mode)
2290117395Skan    return 0;
2291117395Skan
2292132718Skan  return (GET_CODE (op) == SYMBOL_REF
2293132718Skan	  && (DEFAULT_ABI != ABI_AIX || SYMBOL_REF_FUNCTION_P (op)));
2294117395Skan}
2295117395Skan
229690075Sobrien/* Return 1 if the operand, used inside a MEM, is a valid first argument
2297117395Skan   to CALL.  This is a SYMBOL_REF, a pseudo-register, LR or CTR.  */
229890075Sobrien
229990075Sobrienint
2300132718Skancall_operand (rtx op, enum machine_mode mode)
230190075Sobrien{
230290075Sobrien  if (mode != VOIDmode && GET_MODE (op) != mode)
230390075Sobrien    return 0;
230490075Sobrien
230590075Sobrien  return (GET_CODE (op) == SYMBOL_REF
2306117395Skan	  || (GET_CODE (op) == REG
2307117395Skan	      && (REGNO (op) == LINK_REGISTER_REGNUM
2308117395Skan		  || REGNO (op) == COUNT_REGISTER_REGNUM
2309117395Skan		  || REGNO (op) >= FIRST_PSEUDO_REGISTER)));
231090075Sobrien}
231190075Sobrien
231290075Sobrien/* Return 1 if the operand is a SYMBOL_REF for a function known to be in
2313132718Skan   this file.  */
231490075Sobrien
231590075Sobrienint
2316132718Skancurrent_file_function_operand (rtx op,
2317132718Skan                              enum machine_mode mode ATTRIBUTE_UNUSED)
231890075Sobrien{
231990075Sobrien  return (GET_CODE (op) == SYMBOL_REF
2320132718Skan	  && (DEFAULT_ABI != ABI_AIX || SYMBOL_REF_FUNCTION_P (op))
2321132718Skan	  && (SYMBOL_REF_LOCAL_P (op)
2322132718Skan	      || (op == XEXP (DECL_RTL (current_function_decl), 0))));
232390075Sobrien}
232490075Sobrien
232590075Sobrien/* Return 1 if this operand is a valid input for a move insn.  */
232690075Sobrien
232790075Sobrienint
2328132718Skaninput_operand (rtx op, enum machine_mode mode)
232990075Sobrien{
233090075Sobrien  /* Memory is always valid.  */
233190075Sobrien  if (memory_operand (op, mode))
233290075Sobrien    return 1;
233390075Sobrien
233490075Sobrien  /* Only a tiny bit of handling for CONSTANT_P_RTX is necessary.  */
233590075Sobrien  if (GET_CODE (op) == CONSTANT_P_RTX)
233690075Sobrien    return 1;
233790075Sobrien
233890075Sobrien  /* For floating-point, easy constants are valid.  */
233990075Sobrien  if (GET_MODE_CLASS (mode) == MODE_FLOAT
234090075Sobrien      && CONSTANT_P (op)
234190075Sobrien      && easy_fp_constant (op, mode))
234290075Sobrien    return 1;
234390075Sobrien
234490075Sobrien  /* Allow any integer constant.  */
234590075Sobrien  if (GET_MODE_CLASS (mode) == MODE_INT
234690075Sobrien      && (GET_CODE (op) == CONST_INT
234790075Sobrien	  || GET_CODE (op) == CONST_DOUBLE))
234890075Sobrien    return 1;
234990075Sobrien
2350132718Skan  /* Allow easy vector constants.  */
2351132718Skan  if (GET_CODE (op) == CONST_VECTOR
2352132718Skan      && easy_vector_constant (op, mode))
2353132718Skan    return 1;
2354132718Skan
235590075Sobrien  /* For floating-point or multi-word mode, the only remaining valid type
235690075Sobrien     is a register.  */
235790075Sobrien  if (GET_MODE_CLASS (mode) == MODE_FLOAT
235890075Sobrien      || GET_MODE_SIZE (mode) > UNITS_PER_WORD)
235990075Sobrien    return register_operand (op, mode);
236090075Sobrien
236190075Sobrien  /* The only cases left are integral modes one word or smaller (we
236290075Sobrien     do not get called for MODE_CC values).  These can be in any
236390075Sobrien     register.  */
236490075Sobrien  if (register_operand (op, mode))
236590075Sobrien    return 1;
236690075Sobrien
236790075Sobrien  /* A SYMBOL_REF referring to the TOC is valid.  */
2368132718Skan  if (legitimate_constant_pool_address_p (op))
236990075Sobrien    return 1;
237090075Sobrien
237190075Sobrien  /* A constant pool expression (relative to the TOC) is valid */
2372132718Skan  if (toc_relative_expr_p (op))
237390075Sobrien    return 1;
237490075Sobrien
237590075Sobrien  /* V.4 allows SYMBOL_REFs and CONSTs that are in the small data region
237690075Sobrien     to be valid.  */
237790075Sobrien  if (DEFAULT_ABI == ABI_V4
237890075Sobrien      && (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == CONST)
237990075Sobrien      && small_data_operand (op, Pmode))
238090075Sobrien    return 1;
238190075Sobrien
238290075Sobrien  return 0;
238390075Sobrien}
238490075Sobrien
2385132718Skan
2386132718Skan/* Darwin, AIX increases natural record alignment to doubleword if the first
2387132718Skan   field is an FP double while the FP fields remain word aligned.  */
2388132718Skan
2389132718Skanunsigned int
2390132718Skanrs6000_special_round_type_align (tree type, int computed, int specified)
2391132718Skan{
2392132718Skan  tree field = TYPE_FIELDS (type);
2393132718Skan
2394132718Skan  /* Skip all the static variables only if ABI is greater than
2395132718Skan     1 or equal to 0.   */
2396132718Skan  while (field != NULL && TREE_CODE (field) == VAR_DECL)
2397132718Skan    field = TREE_CHAIN (field);
2398132718Skan
2399132718Skan  if (field == NULL || field == type || DECL_MODE (field) != DFmode)
2400132718Skan    return MAX (computed, specified);
2401132718Skan
2402132718Skan  return MAX (MAX (computed, specified), 64);
2403132718Skan}
2404132718Skan
240590075Sobrien/* Return 1 for an operand in small memory on V.4/eabi.  */
240690075Sobrien
240790075Sobrienint
2408132718Skansmall_data_operand (rtx op ATTRIBUTE_UNUSED,
2409132718Skan		    enum machine_mode mode ATTRIBUTE_UNUSED)
241090075Sobrien{
241190075Sobrien#if TARGET_ELF
241290075Sobrien  rtx sym_ref;
241390075Sobrien
241490075Sobrien  if (rs6000_sdata == SDATA_NONE || rs6000_sdata == SDATA_DATA)
241590075Sobrien    return 0;
241690075Sobrien
241790075Sobrien  if (DEFAULT_ABI != ABI_V4)
241890075Sobrien    return 0;
241990075Sobrien
242090075Sobrien  if (GET_CODE (op) == SYMBOL_REF)
242190075Sobrien    sym_ref = op;
242290075Sobrien
242390075Sobrien  else if (GET_CODE (op) != CONST
242490075Sobrien	   || GET_CODE (XEXP (op, 0)) != PLUS
242590075Sobrien	   || GET_CODE (XEXP (XEXP (op, 0), 0)) != SYMBOL_REF
242690075Sobrien	   || GET_CODE (XEXP (XEXP (op, 0), 1)) != CONST_INT)
242790075Sobrien    return 0;
242890075Sobrien
242990075Sobrien  else
243090075Sobrien    {
243190075Sobrien      rtx sum = XEXP (op, 0);
243290075Sobrien      HOST_WIDE_INT summand;
243390075Sobrien
243490075Sobrien      /* We have to be careful here, because it is the referenced address
243590075Sobrien        that must be 32k from _SDA_BASE_, not just the symbol.  */
243690075Sobrien      summand = INTVAL (XEXP (sum, 1));
2437132718Skan      if (summand < 0 || (unsigned HOST_WIDE_INT) summand > g_switch_value)
243890075Sobrien       return 0;
243990075Sobrien
244090075Sobrien      sym_ref = XEXP (sum, 0);
244190075Sobrien    }
244290075Sobrien
2443132718Skan  return SYMBOL_REF_SMALL_P (sym_ref);
244490075Sobrien#else
244590075Sobrien  return 0;
244690075Sobrien#endif
244790075Sobrien}
2448132718Skan
2449132718Skan/* Return true, if operand is a memory operand and has a
2450132718Skan   displacement divisible by 4.  */
2451132718Skan
2452132718Skanint
2453132718Skanword_offset_memref_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
2454132718Skan{
2455132718Skan  rtx addr;
2456132718Skan  int off = 0;
2457132718Skan
2458132718Skan  if (!memory_operand (op, mode))
2459132718Skan    return 0;
2460132718Skan
2461132718Skan  addr = XEXP (op, 0);
2462132718Skan  if (GET_CODE (addr) == PLUS
2463132718Skan      && GET_CODE (XEXP (addr, 0)) == REG
2464132718Skan      && GET_CODE (XEXP (addr, 1)) == CONST_INT)
2465132718Skan    off = INTVAL (XEXP (addr, 1));
2466132718Skan
2467132718Skan  return (off % 4) == 0;
2468132718Skan}
2469132718Skan
2470132718Skan/* Return true if operand is a (MEM (PLUS (REG) (offset))) where offset
2471132718Skan   is not divisible by four.  */
2472132718Skan
2473132718Skanint
2474132718Skaninvalid_gpr_mem (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
2475132718Skan{
2476132718Skan  rtx addr;
2477132718Skan  long off;
2478132718Skan
2479132718Skan  if (GET_CODE (op) != MEM)
2480132718Skan    return 0;
2481132718Skan
2482132718Skan  addr = XEXP (op, 0);
2483132718Skan  if (GET_CODE (addr) != PLUS
2484132718Skan      || GET_CODE (XEXP (addr, 0)) != REG
2485132718Skan      || GET_CODE (XEXP (addr, 1)) != CONST_INT)
2486132718Skan    return 0;
2487132718Skan
2488132718Skan  off = INTVAL (XEXP (addr, 1));
2489132718Skan  return (off & 3) != 0;
2490132718Skan}
2491132718Skan
2492132718Skan/* Return true if operand is a hard register that can be used as a base
2493132718Skan   register.  */
2494132718Skan
2495132718Skanint
2496132718Skanbase_reg_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
2497132718Skan{
2498132718Skan  unsigned int regno;
2499132718Skan
2500132718Skan  if (!REG_P (op))
2501132718Skan    return 0;
2502132718Skan
2503132718Skan  regno = REGNO (op);
2504132718Skan  return regno != 0 && regno <= 31;
2505132718Skan}
2506132718Skan
2507132718Skan/* Return true if either operand is a general purpose register.  */
2508132718Skan
2509132718Skanbool
2510132718Skangpr_or_gpr_p (rtx op0, rtx op1)
2511132718Skan{
2512132718Skan  return ((REG_P (op0) && INT_REGNO_P (REGNO (op0)))
2513132718Skan	  || (REG_P (op1) && INT_REGNO_P (REGNO (op1))));
2514132718Skan}
2515132718Skan
251690075Sobrien
2517132718Skan/* Subroutines of rs6000_legitimize_address and rs6000_legitimate_address.  */
2518132718Skan
251990075Sobrienstatic int
2520132718Skanconstant_pool_expr_1 (rtx op, int *have_sym, int *have_toc)
252190075Sobrien{
252290075Sobrien  switch (GET_CODE(op))
252390075Sobrien    {
252490075Sobrien    case SYMBOL_REF:
2525132718Skan      if (RS6000_SYMBOL_REF_TLS_P (op))
2526132718Skan	return 0;
2527132718Skan      else if (CONSTANT_POOL_ADDRESS_P (op))
252890075Sobrien	{
252990075Sobrien	  if (ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (op), Pmode))
253090075Sobrien	    {
253190075Sobrien	      *have_sym = 1;
253290075Sobrien	      return 1;
253390075Sobrien	    }
253490075Sobrien	  else
253590075Sobrien	    return 0;
253690075Sobrien	}
253790075Sobrien      else if (! strcmp (XSTR (op, 0), toc_label_name))
253890075Sobrien	{
253990075Sobrien	  *have_toc = 1;
254090075Sobrien	  return 1;
254190075Sobrien	}
254290075Sobrien      else
254390075Sobrien	return 0;
254490075Sobrien    case PLUS:
254590075Sobrien    case MINUS:
254696263Sobrien      return (constant_pool_expr_1 (XEXP (op, 0), have_sym, have_toc)
254796263Sobrien	      && constant_pool_expr_1 (XEXP (op, 1), have_sym, have_toc));
254890075Sobrien    case CONST:
254990075Sobrien      return constant_pool_expr_1 (XEXP (op, 0), have_sym, have_toc);
255090075Sobrien    case CONST_INT:
255190075Sobrien      return 1;
255290075Sobrien    default:
255390075Sobrien      return 0;
255490075Sobrien    }
255590075Sobrien}
255690075Sobrien
2557132718Skanstatic bool
2558132718Skanconstant_pool_expr_p (rtx op)
255990075Sobrien{
256090075Sobrien  int have_sym = 0;
256190075Sobrien  int have_toc = 0;
256290075Sobrien  return constant_pool_expr_1 (op, &have_sym, &have_toc) && have_sym;
256390075Sobrien}
256490075Sobrien
2565132718Skanstatic bool
2566132718Skantoc_relative_expr_p (rtx op)
256790075Sobrien{
2568132718Skan  int have_sym = 0;
2569132718Skan  int have_toc = 0;
2570132718Skan  return constant_pool_expr_1 (op, &have_sym, &have_toc) && have_toc;
257190075Sobrien}
257290075Sobrien
2573132718Skan/* SPE offset addressing is limited to 5-bits worth of double words.  */
2574132718Skan#define SPE_CONST_OFFSET_OK(x) (((x) & ~0xf8) == 0)
2575132718Skan
2576132718Skanbool
2577132718Skanlegitimate_constant_pool_address_p (rtx x)
2578132718Skan{
2579132718Skan  return (TARGET_TOC
2580132718Skan	  && GET_CODE (x) == PLUS
2581132718Skan	  && GET_CODE (XEXP (x, 0)) == REG
2582132718Skan	  && (TARGET_MINIMAL_TOC || REGNO (XEXP (x, 0)) == TOC_REGISTER)
2583132718Skan	  && constant_pool_expr_p (XEXP (x, 1)));
2584132718Skan}
2585132718Skan
2586132718Skanstatic bool
2587132718Skanlegitimate_small_data_p (enum machine_mode mode, rtx x)
2588132718Skan{
2589132718Skan  return (DEFAULT_ABI == ABI_V4
2590132718Skan	  && !flag_pic && !TARGET_TOC
2591132718Skan	  && (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == CONST)
2592132718Skan	  && small_data_operand (x, mode));
2593132718Skan}
2594132718Skan
2595132718Skanstatic bool
2596132718Skanlegitimate_offset_address_p (enum machine_mode mode, rtx x, int strict)
2597132718Skan{
2598132718Skan  unsigned HOST_WIDE_INT offset, extra;
2599132718Skan
2600132718Skan  if (GET_CODE (x) != PLUS)
2601132718Skan    return false;
2602132718Skan  if (GET_CODE (XEXP (x, 0)) != REG)
2603132718Skan    return false;
2604132718Skan  if (!INT_REG_OK_FOR_BASE_P (XEXP (x, 0), strict))
2605132718Skan    return false;
2606132718Skan  if (GET_CODE (XEXP (x, 1)) != CONST_INT)
2607132718Skan    return false;
2608132718Skan
2609132718Skan  offset = INTVAL (XEXP (x, 1));
2610132718Skan  extra = 0;
2611132718Skan  switch (mode)
2612132718Skan    {
2613132718Skan    case V16QImode:
2614132718Skan    case V8HImode:
2615132718Skan    case V4SFmode:
2616132718Skan    case V4SImode:
2617132718Skan      /* AltiVec vector modes.  Only reg+reg addressing is valid here,
2618132718Skan	 which leaves the only valid constant offset of zero, which by
2619132718Skan	 canonicalization rules is also invalid.  */
2620132718Skan      return false;
2621132718Skan
2622132718Skan    case V4HImode:
2623132718Skan    case V2SImode:
2624132718Skan    case V1DImode:
2625132718Skan    case V2SFmode:
2626132718Skan      /* SPE vector modes.  */
2627132718Skan      return SPE_CONST_OFFSET_OK (offset);
2628132718Skan
2629132718Skan    case DFmode:
2630132718Skan    case DImode:
2631132718Skan      /* Both DFmode and DImode may end up in gprs.  If gprs are 32-bit,
2632132718Skan	 then we need to load/store at both offset and offset+4.  */
2633132718Skan      if (!TARGET_POWERPC64)
2634132718Skan	extra = 4;
2635132718Skan      break;
2636132718Skan
2637132718Skan    case TFmode:
2638132718Skan    case TImode:
2639132718Skan      if (!TARGET_POWERPC64)
2640132718Skan	extra = 12;
2641132718Skan      else
2642132718Skan	extra = 8;
2643132718Skan      break;
2644132718Skan
2645132718Skan    default:
2646132718Skan      break;
2647132718Skan    }
2648132718Skan
2649132718Skan  offset += 0x8000;
2650132718Skan  return (offset < 0x10000) && (offset + extra < 0x10000);
2651132718Skan}
2652132718Skan
2653132718Skanstatic bool
2654132718Skanlegitimate_indexed_address_p (rtx x, int strict)
2655132718Skan{
2656132718Skan  rtx op0, op1;
2657132718Skan
2658132718Skan  if (GET_CODE (x) != PLUS)
2659132718Skan    return false;
2660132718Skan  op0 = XEXP (x, 0);
2661132718Skan  op1 = XEXP (x, 1);
2662132718Skan
2663132718Skan  if (!REG_P (op0) || !REG_P (op1))
2664132718Skan    return false;
2665132718Skan
2666132718Skan  return ((INT_REG_OK_FOR_BASE_P (op0, strict)
2667132718Skan	   && INT_REG_OK_FOR_INDEX_P (op1, strict))
2668132718Skan	  || (INT_REG_OK_FOR_BASE_P (op1, strict)
2669132718Skan	      && INT_REG_OK_FOR_INDEX_P (op0, strict)));
2670132718Skan}
2671132718Skan
2672132718Skanstatic inline bool
2673132718Skanlegitimate_indirect_address_p (rtx x, int strict)
2674132718Skan{
2675132718Skan  return GET_CODE (x) == REG && INT_REG_OK_FOR_BASE_P (x, strict);
2676132718Skan}
2677132718Skan
2678132718Skanstatic bool
2679132718Skanmacho_lo_sum_memory_operand (rtx x, enum machine_mode mode)
2680132718Skan{
2681132718Skan    if (!TARGET_MACHO || !flag_pic
2682132718Skan        || mode != SImode || GET_CODE(x) != MEM)
2683132718Skan      return false;
2684132718Skan    x = XEXP (x, 0);
2685132718Skan
2686132718Skan  if (GET_CODE (x) != LO_SUM)
2687132718Skan    return false;
2688132718Skan  if (GET_CODE (XEXP (x, 0)) != REG)
2689132718Skan    return false;
2690132718Skan  if (!INT_REG_OK_FOR_BASE_P (XEXP (x, 0), 0))
2691132718Skan    return false;
2692132718Skan  x = XEXP (x, 1);
2693132718Skan
2694132718Skan  return CONSTANT_P (x);
2695132718Skan}
2696132718Skan
2697132718Skanstatic bool
2698132718Skanlegitimate_lo_sum_address_p (enum machine_mode mode, rtx x, int strict)
2699132718Skan{
2700132718Skan  if (GET_CODE (x) != LO_SUM)
2701132718Skan    return false;
2702132718Skan  if (GET_CODE (XEXP (x, 0)) != REG)
2703132718Skan    return false;
2704132718Skan  if (!INT_REG_OK_FOR_BASE_P (XEXP (x, 0), strict))
2705132718Skan    return false;
2706132718Skan  x = XEXP (x, 1);
2707132718Skan
2708132718Skan  if (TARGET_ELF || TARGET_MACHO)
2709132718Skan    {
2710132718Skan      if (DEFAULT_ABI != ABI_AIX && DEFAULT_ABI != ABI_DARWIN && flag_pic)
2711132718Skan	return false;
2712132718Skan      if (TARGET_TOC)
2713132718Skan	return false;
2714132718Skan      if (GET_MODE_NUNITS (mode) != 1)
2715132718Skan	return false;
2716132718Skan      if (GET_MODE_BITSIZE (mode) > 32
2717132718Skan	  && !(TARGET_HARD_FLOAT && TARGET_FPRS && mode == DFmode))
2718132718Skan	return false;
2719132718Skan
2720132718Skan      return CONSTANT_P (x);
2721132718Skan    }
2722132718Skan
2723132718Skan  return false;
2724132718Skan}
2725132718Skan
2726132718Skan
272790075Sobrien/* Try machine-dependent ways of modifying an illegitimate address
272890075Sobrien   to be legitimate.  If we find one, return the new, valid address.
272990075Sobrien   This is used from only one place: `memory_address' in explow.c.
273090075Sobrien
273190075Sobrien   OLDX is the address as it was before break_out_memory_refs was
273290075Sobrien   called.  In some cases it is useful to look at this to decide what
273390075Sobrien   needs to be done.
273490075Sobrien
273590075Sobrien   MODE is passed so that this function can use GO_IF_LEGITIMATE_ADDRESS.
273690075Sobrien
273790075Sobrien   It is always safe for this function to do nothing.  It exists to
273890075Sobrien   recognize opportunities to optimize the output.
273990075Sobrien
274090075Sobrien   On RS/6000, first check for the sum of a register with a constant
274190075Sobrien   integer that is out of range.  If so, generate code to add the
274290075Sobrien   constant with the low-order 16 bits masked to the register and force
274390075Sobrien   this result into another register (this can be done with `cau').
274490075Sobrien   Then generate an address of REG+(CONST&0xffff), allowing for the
274590075Sobrien   possibility of bit 16 being a one.
274690075Sobrien
274790075Sobrien   Then check for the sum of a register and something not constant, try to
274890075Sobrien   load the other things into a register and return the sum.  */
2749132718Skan
275090075Sobrienrtx
2751132718Skanrs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
2752132718Skan			   enum machine_mode mode)
275390075Sobrien{
2754132718Skan  if (GET_CODE (x) == SYMBOL_REF)
2755132718Skan    {
2756132718Skan      enum tls_model model = SYMBOL_REF_TLS_MODEL (x);
2757132718Skan      if (model != 0)
2758132718Skan	return rs6000_legitimize_tls_address (x, model);
2759132718Skan    }
2760132718Skan
276190075Sobrien  if (GET_CODE (x) == PLUS
276290075Sobrien      && GET_CODE (XEXP (x, 0)) == REG
276390075Sobrien      && GET_CODE (XEXP (x, 1)) == CONST_INT
276490075Sobrien      && (unsigned HOST_WIDE_INT) (INTVAL (XEXP (x, 1)) + 0x8000) >= 0x10000)
276590075Sobrien    {
276690075Sobrien      HOST_WIDE_INT high_int, low_int;
276790075Sobrien      rtx sum;
2768117395Skan      low_int = ((INTVAL (XEXP (x, 1)) & 0xffff) ^ 0x8000) - 0x8000;
2769117395Skan      high_int = INTVAL (XEXP (x, 1)) - low_int;
277090075Sobrien      sum = force_operand (gen_rtx_PLUS (Pmode, XEXP (x, 0),
277190075Sobrien					 GEN_INT (high_int)), 0);
277290075Sobrien      return gen_rtx_PLUS (Pmode, sum, GEN_INT (low_int));
277390075Sobrien    }
277490075Sobrien  else if (GET_CODE (x) == PLUS
277590075Sobrien	   && GET_CODE (XEXP (x, 0)) == REG
277690075Sobrien	   && GET_CODE (XEXP (x, 1)) != CONST_INT
277790075Sobrien	   && GET_MODE_NUNITS (mode) == 1
2778117395Skan	   && ((TARGET_HARD_FLOAT && TARGET_FPRS)
2779117395Skan	       || TARGET_POWERPC64
2780117395Skan	       || (mode != DFmode && mode != TFmode))
278190075Sobrien	   && (TARGET_POWERPC64 || mode != DImode)
278290075Sobrien	   && mode != TImode)
278390075Sobrien    {
278490075Sobrien      return gen_rtx_PLUS (Pmode, XEXP (x, 0),
278590075Sobrien			   force_reg (Pmode, force_operand (XEXP (x, 1), 0)));
278690075Sobrien    }
278790075Sobrien  else if (ALTIVEC_VECTOR_MODE (mode))
278890075Sobrien    {
278990075Sobrien      rtx reg;
279090075Sobrien
279190075Sobrien      /* Make sure both operands are registers.  */
279290075Sobrien      if (GET_CODE (x) == PLUS)
279390075Sobrien	return gen_rtx_PLUS (Pmode, force_reg (Pmode, XEXP (x, 0)),
279490075Sobrien			     force_reg (Pmode, XEXP (x, 1)));
279590075Sobrien
279690075Sobrien      reg = force_reg (Pmode, x);
279790075Sobrien      return reg;
279890075Sobrien    }
2799117395Skan  else if (SPE_VECTOR_MODE (mode))
2800117395Skan    {
2801117395Skan      /* We accept [reg + reg] and [reg + OFFSET].  */
2802117395Skan
2803117395Skan      if (GET_CODE (x) == PLUS)
2804117395Skan      {
2805117395Skan        rtx op1 = XEXP (x, 0);
2806117395Skan        rtx op2 = XEXP (x, 1);
2807117395Skan
2808117395Skan        op1 = force_reg (Pmode, op1);
2809117395Skan
2810117395Skan        if (GET_CODE (op2) != REG
2811117395Skan            && (GET_CODE (op2) != CONST_INT
2812117395Skan                || !SPE_CONST_OFFSET_OK (INTVAL (op2))))
2813117395Skan          op2 = force_reg (Pmode, op2);
2814117395Skan
2815117395Skan        return gen_rtx_PLUS (Pmode, op1, op2);
2816117395Skan      }
2817117395Skan
2818117395Skan      return force_reg (Pmode, x);
2819117395Skan    }
2820132718Skan  else if (TARGET_ELF
2821132718Skan	   && TARGET_32BIT
2822132718Skan	   && TARGET_NO_TOC
2823132718Skan	   && ! flag_pic
282490075Sobrien	   && GET_CODE (x) != CONST_INT
282590075Sobrien	   && GET_CODE (x) != CONST_DOUBLE
282690075Sobrien	   && CONSTANT_P (x)
282790075Sobrien	   && GET_MODE_NUNITS (mode) == 1
282890075Sobrien	   && (GET_MODE_BITSIZE (mode) <= 32
2829117395Skan	       || ((TARGET_HARD_FLOAT && TARGET_FPRS) && mode == DFmode)))
283090075Sobrien    {
283190075Sobrien      rtx reg = gen_reg_rtx (Pmode);
2832132718Skan      emit_insn (gen_elf_high (reg, x));
2833132718Skan      return gen_rtx_LO_SUM (Pmode, reg, x);
283490075Sobrien    }
283590075Sobrien  else if (TARGET_MACHO && TARGET_32BIT && TARGET_NO_TOC
283690075Sobrien	   && ! flag_pic
2837132718Skan#if TARGET_MACHO
2838132718Skan	   && ! MACHO_DYNAMIC_NO_PIC_P
2839132718Skan#endif
284090075Sobrien	   && GET_CODE (x) != CONST_INT
284190075Sobrien	   && GET_CODE (x) != CONST_DOUBLE
284290075Sobrien	   && CONSTANT_P (x)
2843117395Skan	   && ((TARGET_HARD_FLOAT && TARGET_FPRS) || mode != DFmode)
284490075Sobrien	   && mode != DImode
284590075Sobrien	   && mode != TImode)
284690075Sobrien    {
284790075Sobrien      rtx reg = gen_reg_rtx (Pmode);
2848132718Skan      emit_insn (gen_macho_high (reg, x));
2849132718Skan      return gen_rtx_LO_SUM (Pmode, reg, x);
285090075Sobrien    }
285190075Sobrien  else if (TARGET_TOC
2852132718Skan	   && constant_pool_expr_p (x)
285390075Sobrien	   && ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (x), Pmode))
285490075Sobrien    {
285590075Sobrien      return create_TOC_reference (x);
285690075Sobrien    }
285790075Sobrien  else
285890075Sobrien    return NULL_RTX;
285990075Sobrien}
286090075Sobrien
2861132718Skan/* This is called from dwarf2out.c via ASM_OUTPUT_DWARF_DTPREL.
2862132718Skan   We need to emit DTP-relative relocations.  */
2863132718Skan
2864132718Skanvoid
2865132718Skanrs6000_output_dwarf_dtprel (FILE *file, int size, rtx x)
2866132718Skan{
2867132718Skan  switch (size)
2868132718Skan    {
2869132718Skan    case 4:
2870132718Skan      fputs ("\t.long\t", file);
2871132718Skan      break;
2872132718Skan    case 8:
2873132718Skan      fputs (DOUBLE_INT_ASM_OP, file);
2874132718Skan      break;
2875132718Skan    default:
2876132718Skan      abort ();
2877132718Skan    }
2878132718Skan  output_addr_const (file, x);
2879132718Skan  fputs ("@dtprel+0x8000", file);
2880132718Skan}
2881132718Skan
2882132718Skan/* Construct the SYMBOL_REF for the tls_get_addr function.  */
2883132718Skan
2884132718Skanstatic GTY(()) rtx rs6000_tls_symbol;
2885132718Skanstatic rtx
2886132718Skanrs6000_tls_get_addr (void)
2887132718Skan{
2888132718Skan  if (!rs6000_tls_symbol)
2889132718Skan    rs6000_tls_symbol = init_one_libfunc ("__tls_get_addr");
2890132718Skan
2891132718Skan  return rs6000_tls_symbol;
2892132718Skan}
2893132718Skan
2894132718Skan/* Construct the SYMBOL_REF for TLS GOT references.  */
2895132718Skan
2896132718Skanstatic GTY(()) rtx rs6000_got_symbol;
2897132718Skanstatic rtx
2898132718Skanrs6000_got_sym (void)
2899132718Skan{
2900132718Skan  if (!rs6000_got_symbol)
2901132718Skan    {
2902132718Skan      rs6000_got_symbol = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
2903132718Skan      SYMBOL_REF_FLAGS (rs6000_got_symbol) |= SYMBOL_FLAG_LOCAL;
2904132718Skan      SYMBOL_REF_FLAGS (rs6000_got_symbol) |= SYMBOL_FLAG_EXTERNAL;
2905132718Skan    }
2906132718Skan
2907132718Skan  return rs6000_got_symbol;
2908132718Skan}
2909132718Skan
2910132718Skan/* ADDR contains a thread-local SYMBOL_REF.  Generate code to compute
2911132718Skan   this (thread-local) address.  */
2912132718Skan
2913132718Skanstatic rtx
2914132718Skanrs6000_legitimize_tls_address (rtx addr, enum tls_model model)
2915132718Skan{
2916132718Skan  rtx dest, insn;
2917132718Skan
2918132718Skan  dest = gen_reg_rtx (Pmode);
2919132718Skan  if (model == TLS_MODEL_LOCAL_EXEC && rs6000_tls_size == 16)
2920132718Skan    {
2921132718Skan      rtx tlsreg;
2922132718Skan
2923132718Skan      if (TARGET_64BIT)
2924132718Skan	{
2925132718Skan	  tlsreg = gen_rtx_REG (Pmode, 13);
2926132718Skan	  insn = gen_tls_tprel_64 (dest, tlsreg, addr);
2927132718Skan	}
2928132718Skan      else
2929132718Skan	{
2930132718Skan	  tlsreg = gen_rtx_REG (Pmode, 2);
2931132718Skan	  insn = gen_tls_tprel_32 (dest, tlsreg, addr);
2932132718Skan	}
2933132718Skan      emit_insn (insn);
2934132718Skan    }
2935132718Skan  else if (model == TLS_MODEL_LOCAL_EXEC && rs6000_tls_size == 32)
2936132718Skan    {
2937132718Skan      rtx tlsreg, tmp;
2938132718Skan
2939132718Skan      tmp = gen_reg_rtx (Pmode);
2940132718Skan      if (TARGET_64BIT)
2941132718Skan	{
2942132718Skan	  tlsreg = gen_rtx_REG (Pmode, 13);
2943132718Skan	  insn = gen_tls_tprel_ha_64 (tmp, tlsreg, addr);
2944132718Skan	}
2945132718Skan      else
2946132718Skan	{
2947132718Skan	  tlsreg = gen_rtx_REG (Pmode, 2);
2948132718Skan	  insn = gen_tls_tprel_ha_32 (tmp, tlsreg, addr);
2949132718Skan	}
2950132718Skan      emit_insn (insn);
2951132718Skan      if (TARGET_64BIT)
2952132718Skan	insn = gen_tls_tprel_lo_64 (dest, tmp, addr);
2953132718Skan      else
2954132718Skan	insn = gen_tls_tprel_lo_32 (dest, tmp, addr);
2955132718Skan      emit_insn (insn);
2956132718Skan    }
2957132718Skan  else
2958132718Skan    {
2959132718Skan      rtx r3, got, tga, tmp1, tmp2, eqv;
2960132718Skan
2961132718Skan      if (TARGET_64BIT)
2962132718Skan	got = gen_rtx_REG (Pmode, TOC_REGISTER);
2963132718Skan      else
2964132718Skan	{
2965132718Skan	  if (flag_pic == 1)
2966132718Skan	    got = gen_rtx_REG (Pmode, RS6000_PIC_OFFSET_TABLE_REGNUM);
2967132718Skan	  else
2968132718Skan	    {
2969132718Skan	      rtx gsym = rs6000_got_sym ();
2970132718Skan	      got = gen_reg_rtx (Pmode);
2971132718Skan	      if (flag_pic == 0)
2972132718Skan		rs6000_emit_move (got, gsym, Pmode);
2973132718Skan	      else
2974132718Skan		{
2975132718Skan		  char buf[30];
2976132718Skan		  static int tls_got_labelno = 0;
2977132718Skan		  rtx tempLR, lab, tmp3, mem;
2978132718Skan		  rtx first, last;
2979132718Skan
2980132718Skan		  ASM_GENERATE_INTERNAL_LABEL (buf, "LTLS", tls_got_labelno++);
2981132718Skan		  lab = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
2982132718Skan		  tempLR = gen_reg_rtx (Pmode);
2983132718Skan		  tmp1 = gen_reg_rtx (Pmode);
2984132718Skan		  tmp2 = gen_reg_rtx (Pmode);
2985132718Skan		  tmp3 = gen_reg_rtx (Pmode);
2986132718Skan		  mem = gen_rtx_MEM (Pmode, tmp1);
2987132718Skan		  RTX_UNCHANGING_P (mem) = 1;
2988132718Skan
2989132718Skan		  first = emit_insn (gen_load_toc_v4_PIC_1b (tempLR, lab,
2990132718Skan							     gsym));
2991132718Skan		  emit_move_insn (tmp1, tempLR);
2992132718Skan		  emit_move_insn (tmp2, mem);
2993132718Skan		  emit_insn (gen_addsi3 (tmp3, tmp1, tmp2));
2994132718Skan		  last = emit_move_insn (got, tmp3);
2995132718Skan		  REG_NOTES (last) = gen_rtx_EXPR_LIST (REG_EQUAL, gsym,
2996132718Skan							REG_NOTES (last));
2997132718Skan		  REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last,
2998132718Skan							 REG_NOTES (first));
2999132718Skan		  REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first,
3000132718Skan							REG_NOTES (last));
3001132718Skan		}
3002132718Skan	    }
3003132718Skan	}
3004132718Skan
3005132718Skan      if (model == TLS_MODEL_GLOBAL_DYNAMIC)
3006132718Skan	{
3007132718Skan	  r3 = gen_rtx_REG (Pmode, 3);
3008132718Skan	  if (TARGET_64BIT)
3009132718Skan	    insn = gen_tls_gd_64 (r3, got, addr);
3010132718Skan	  else
3011132718Skan	    insn = gen_tls_gd_32 (r3, got, addr);
3012132718Skan	  start_sequence ();
3013132718Skan	  emit_insn (insn);
3014132718Skan	  tga = gen_rtx_MEM (Pmode, rs6000_tls_get_addr ());
3015132718Skan	  insn = gen_call_value (r3, tga, const0_rtx, const0_rtx);
3016132718Skan	  insn = emit_call_insn (insn);
3017132718Skan	  CONST_OR_PURE_CALL_P (insn) = 1;
3018132718Skan	  use_reg (&CALL_INSN_FUNCTION_USAGE (insn), r3);
3019132718Skan	  insn = get_insns ();
3020132718Skan	  end_sequence ();
3021132718Skan	  emit_libcall_block (insn, dest, r3, addr);
3022132718Skan	}
3023132718Skan      else if (model == TLS_MODEL_LOCAL_DYNAMIC)
3024132718Skan	{
3025132718Skan	  r3 = gen_rtx_REG (Pmode, 3);
3026132718Skan	  if (TARGET_64BIT)
3027132718Skan	    insn = gen_tls_ld_64 (r3, got);
3028132718Skan	  else
3029132718Skan	    insn = gen_tls_ld_32 (r3, got);
3030132718Skan	  start_sequence ();
3031132718Skan	  emit_insn (insn);
3032132718Skan	  tga = gen_rtx_MEM (Pmode, rs6000_tls_get_addr ());
3033132718Skan	  insn = gen_call_value (r3, tga, const0_rtx, const0_rtx);
3034132718Skan	  insn = emit_call_insn (insn);
3035132718Skan	  CONST_OR_PURE_CALL_P (insn) = 1;
3036132718Skan	  use_reg (&CALL_INSN_FUNCTION_USAGE (insn), r3);
3037132718Skan	  insn = get_insns ();
3038132718Skan	  end_sequence ();
3039132718Skan	  tmp1 = gen_reg_rtx (Pmode);
3040132718Skan	  eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx),
3041132718Skan				UNSPEC_TLSLD);
3042132718Skan	  emit_libcall_block (insn, tmp1, r3, eqv);
3043132718Skan	  if (rs6000_tls_size == 16)
3044132718Skan	    {
3045132718Skan	      if (TARGET_64BIT)
3046132718Skan		insn = gen_tls_dtprel_64 (dest, tmp1, addr);
3047132718Skan	      else
3048132718Skan		insn = gen_tls_dtprel_32 (dest, tmp1, addr);
3049132718Skan	    }
3050132718Skan	  else if (rs6000_tls_size == 32)
3051132718Skan	    {
3052132718Skan	      tmp2 = gen_reg_rtx (Pmode);
3053132718Skan	      if (TARGET_64BIT)
3054132718Skan		insn = gen_tls_dtprel_ha_64 (tmp2, tmp1, addr);
3055132718Skan	      else
3056132718Skan		insn = gen_tls_dtprel_ha_32 (tmp2, tmp1, addr);
3057132718Skan	      emit_insn (insn);
3058132718Skan	      if (TARGET_64BIT)
3059132718Skan		insn = gen_tls_dtprel_lo_64 (dest, tmp2, addr);
3060132718Skan	      else
3061132718Skan		insn = gen_tls_dtprel_lo_32 (dest, tmp2, addr);
3062132718Skan	    }
3063132718Skan	  else
3064132718Skan	    {
3065132718Skan	      tmp2 = gen_reg_rtx (Pmode);
3066132718Skan	      if (TARGET_64BIT)
3067132718Skan		insn = gen_tls_got_dtprel_64 (tmp2, got, addr);
3068132718Skan	      else
3069132718Skan		insn = gen_tls_got_dtprel_32 (tmp2, got, addr);
3070132718Skan	      emit_insn (insn);
3071132718Skan	      insn = gen_rtx_SET (Pmode, dest,
3072132718Skan				  gen_rtx_PLUS (Pmode, tmp2, tmp1));
3073132718Skan	    }
3074132718Skan	  emit_insn (insn);
3075132718Skan	}
3076132718Skan      else
3077132718Skan	{
3078132718Skan	  /* IE, or 64 bit offset LE.  */
3079132718Skan	  tmp2 = gen_reg_rtx (Pmode);
3080132718Skan	  if (TARGET_64BIT)
3081132718Skan	    insn = gen_tls_got_tprel_64 (tmp2, got, addr);
3082132718Skan	  else
3083132718Skan	    insn = gen_tls_got_tprel_32 (tmp2, got, addr);
3084132718Skan	  emit_insn (insn);
3085132718Skan	  if (TARGET_64BIT)
3086132718Skan	    insn = gen_tls_tls_64 (dest, tmp2, addr);
3087132718Skan	  else
3088132718Skan	    insn = gen_tls_tls_32 (dest, tmp2, addr);
3089132718Skan	  emit_insn (insn);
3090132718Skan	}
3091132718Skan    }
3092132718Skan
3093132718Skan  return dest;
3094132718Skan}
3095132718Skan
3096132718Skan/* Return 1 if X is a SYMBOL_REF for a TLS symbol.  This is used in
3097132718Skan   instruction definitions.  */
3098132718Skan
3099132718Skanint
3100132718Skanrs6000_tls_symbol_ref (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
3101132718Skan{
3102132718Skan  return RS6000_SYMBOL_REF_TLS_P (x);
3103132718Skan}
3104132718Skan
3105132718Skan/* Return 1 if X contains a thread-local symbol.  */
3106132718Skan
3107132718Skanbool
3108132718Skanrs6000_tls_referenced_p (rtx x)
3109132718Skan{
3110132718Skan  if (! TARGET_HAVE_TLS)
3111132718Skan    return false;
3112132718Skan
3113132718Skan  return for_each_rtx (&x, &rs6000_tls_symbol_ref_1, 0);
3114132718Skan}
3115132718Skan
3116132718Skan/* Return 1 if *X is a thread-local symbol.  This is the same as
3117132718Skan   rs6000_tls_symbol_ref except for the type of the unused argument.  */
3118132718Skan
3119132718Skanstatic inline int
3120132718Skanrs6000_tls_symbol_ref_1 (rtx *x, void *data ATTRIBUTE_UNUSED)
3121132718Skan{
3122132718Skan  return RS6000_SYMBOL_REF_TLS_P (*x);
3123132718Skan}
3124132718Skan
312590075Sobrien/* The convention appears to be to define this wherever it is used.
312690075Sobrien   With legitimize_reload_address now defined here, REG_MODE_OK_FOR_BASE_P
312790075Sobrien   is now used here.  */
312890075Sobrien#ifndef REG_MODE_OK_FOR_BASE_P
312990075Sobrien#define REG_MODE_OK_FOR_BASE_P(REGNO, MODE) REG_OK_FOR_BASE_P (REGNO)
313090075Sobrien#endif
313190075Sobrien
313290075Sobrien/* Our implementation of LEGITIMIZE_RELOAD_ADDRESS.  Returns a value to
313390075Sobrien   replace the input X, or the original X if no replacement is called for.
313490075Sobrien   The output parameter *WIN is 1 if the calling macro should goto WIN,
313590075Sobrien   0 if it should not.
313690075Sobrien
313790075Sobrien   For RS/6000, we wish to handle large displacements off a base
313890075Sobrien   register by splitting the addend across an addiu/addis and the mem insn.
313990075Sobrien   This cuts number of extra insns needed from 3 to 1.
314090075Sobrien
314190075Sobrien   On Darwin, we use this to generate code for floating point constants.
314290075Sobrien   A movsf_low is generated so we wind up with 2 instructions rather than 3.
314390075Sobrien   The Darwin code is inside #if TARGET_MACHO because only then is
314490075Sobrien   machopic_function_base_name() defined.  */
314590075Sobrienrtx
3146132718Skanrs6000_legitimize_reload_address (rtx x, enum machine_mode mode,
3147132718Skan	int opnum, int type, int ind_levels ATTRIBUTE_UNUSED, int *win)
314890075Sobrien{
314990075Sobrien  /* We must recognize output that we have already generated ourselves.  */
315090075Sobrien  if (GET_CODE (x) == PLUS
315190075Sobrien      && GET_CODE (XEXP (x, 0)) == PLUS
315290075Sobrien      && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG
315390075Sobrien      && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
315490075Sobrien      && GET_CODE (XEXP (x, 1)) == CONST_INT)
315590075Sobrien    {
315690075Sobrien      push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
315790075Sobrien                   BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0,
315890075Sobrien                   opnum, (enum reload_type)type);
315990075Sobrien      *win = 1;
316090075Sobrien      return x;
316190075Sobrien    }
316296263Sobrien
316390075Sobrien#if TARGET_MACHO
316490075Sobrien  if (DEFAULT_ABI == ABI_DARWIN && flag_pic
316590075Sobrien      && GET_CODE (x) == LO_SUM
316690075Sobrien      && GET_CODE (XEXP (x, 0)) == PLUS
316790075Sobrien      && XEXP (XEXP (x, 0), 0) == pic_offset_table_rtx
316890075Sobrien      && GET_CODE (XEXP (XEXP (x, 0), 1)) == HIGH
316990075Sobrien      && GET_CODE (XEXP (XEXP (XEXP (x, 0), 1), 0)) == CONST
317090075Sobrien      && XEXP (XEXP (XEXP (x, 0), 1), 0) == XEXP (x, 1)
317190075Sobrien      && GET_CODE (XEXP (XEXP (x, 1), 0)) == MINUS
317290075Sobrien      && GET_CODE (XEXP (XEXP (XEXP (x, 1), 0), 0)) == SYMBOL_REF
317390075Sobrien      && GET_CODE (XEXP (XEXP (XEXP (x, 1), 0), 1)) == SYMBOL_REF)
317490075Sobrien    {
317590075Sobrien      /* Result of previous invocation of this function on Darwin
317690075Sobrien	 floating point constant.  */
317790075Sobrien      push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
317890075Sobrien		BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
317990075Sobrien		opnum, (enum reload_type)type);
318090075Sobrien      *win = 1;
318190075Sobrien      return x;
318290075Sobrien    }
318390075Sobrien#endif
318490075Sobrien  if (GET_CODE (x) == PLUS
318590075Sobrien      && GET_CODE (XEXP (x, 0)) == REG
318690075Sobrien      && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER
318790075Sobrien      && REG_MODE_OK_FOR_BASE_P (XEXP (x, 0), mode)
318896263Sobrien      && GET_CODE (XEXP (x, 1)) == CONST_INT
3189117395Skan      && !SPE_VECTOR_MODE (mode)
319096263Sobrien      && !ALTIVEC_VECTOR_MODE (mode))
319190075Sobrien    {
319290075Sobrien      HOST_WIDE_INT val = INTVAL (XEXP (x, 1));
319390075Sobrien      HOST_WIDE_INT low = ((val & 0xffff) ^ 0x8000) - 0x8000;
319490075Sobrien      HOST_WIDE_INT high
319590075Sobrien        = (((val - low) & 0xffffffff) ^ 0x80000000) - 0x80000000;
319690075Sobrien
319790075Sobrien      /* Check for 32-bit overflow.  */
319890075Sobrien      if (high + low != val)
319990075Sobrien        {
320090075Sobrien	  *win = 0;
320190075Sobrien	  return x;
320290075Sobrien	}
320390075Sobrien
320490075Sobrien      /* Reload the high part into a base reg; leave the low part
320590075Sobrien         in the mem directly.  */
320690075Sobrien
320790075Sobrien      x = gen_rtx_PLUS (GET_MODE (x),
320890075Sobrien                        gen_rtx_PLUS (GET_MODE (x), XEXP (x, 0),
320990075Sobrien                                      GEN_INT (high)),
321090075Sobrien                        GEN_INT (low));
321190075Sobrien
321290075Sobrien      push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
321390075Sobrien                   BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0,
321490075Sobrien                   opnum, (enum reload_type)type);
321590075Sobrien      *win = 1;
321690075Sobrien      return x;
321790075Sobrien    }
321890075Sobrien#if TARGET_MACHO
321990075Sobrien  if (GET_CODE (x) == SYMBOL_REF
322090075Sobrien      && DEFAULT_ABI == ABI_DARWIN
322196263Sobrien      && !ALTIVEC_VECTOR_MODE (mode)
3222132718Skan      && (flag_pic || MACHO_DYNAMIC_NO_PIC_P)
3223132718Skan      /* Don't do this for TFmode, since the result isn't offsettable.  */
3224132718Skan      && mode != TFmode)
322590075Sobrien    {
3226132718Skan      if (flag_pic)
3227132718Skan	{
3228132718Skan	  rtx offset = gen_rtx_CONST (Pmode,
3229132718Skan			 gen_rtx_MINUS (Pmode, x,
3230132718Skan			   gen_rtx_SYMBOL_REF (Pmode,
3231132718Skan			     machopic_function_base_name ())));
3232132718Skan	  x = gen_rtx_LO_SUM (GET_MODE (x),
3233132718Skan		gen_rtx_PLUS (Pmode, pic_offset_table_rtx,
3234132718Skan		  gen_rtx_HIGH (Pmode, offset)), offset);
3235132718Skan	}
3236132718Skan      else
3237132718Skan	x = gen_rtx_LO_SUM (GET_MODE (x),
3238132718Skan              gen_rtx_HIGH (Pmode, x), x);
3239132718Skan
324090075Sobrien      push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
3241132718Skan		   BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
3242132718Skan		   opnum, (enum reload_type)type);
324390075Sobrien      *win = 1;
324490075Sobrien      return x;
324590075Sobrien    }
324690075Sobrien#endif
324790075Sobrien  if (TARGET_TOC
3248132718Skan      && constant_pool_expr_p (x)
324996263Sobrien      && ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (x), mode))
325090075Sobrien    {
325190075Sobrien      (x) = create_TOC_reference (x);
325290075Sobrien      *win = 1;
325390075Sobrien      return x;
325490075Sobrien    }
325590075Sobrien  *win = 0;
325690075Sobrien  return x;
325790075Sobrien}
325890075Sobrien
325990075Sobrien/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression
326090075Sobrien   that is a valid memory address for an instruction.
326190075Sobrien   The MODE argument is the machine mode for the MEM expression
326290075Sobrien   that wants to use this address.
326390075Sobrien
326490075Sobrien   On the RS/6000, there are four valid address: a SYMBOL_REF that
326590075Sobrien   refers to a constant pool entry of an address (or the sum of it
326690075Sobrien   plus a constant), a short (16-bit signed) constant plus a register,
326790075Sobrien   the sum of two registers, or a register indirect, possibly with an
3268132718Skan   auto-increment.  For DFmode and DImode with a constant plus register,
326990075Sobrien   we must ensure that both words are addressable or PowerPC64 with offset
327090075Sobrien   word aligned.
327190075Sobrien
327290075Sobrien   For modes spanning multiple registers (DFmode in 32-bit GPRs,
327390075Sobrien   32-bit DImode, TImode), indexed addressing cannot be used because
327490075Sobrien   adjacent memory cells are accessed by adding word-sized offsets
327590075Sobrien   during assembly output.  */
327690075Sobrienint
3277132718Skanrs6000_legitimate_address (enum machine_mode mode, rtx x, int reg_ok_strict)
327890075Sobrien{
3279132718Skan  if (RS6000_SYMBOL_REF_TLS_P (x))
3280132718Skan    return 0;
3281132718Skan  if (legitimate_indirect_address_p (x, reg_ok_strict))
328290075Sobrien    return 1;
328390075Sobrien  if ((GET_CODE (x) == PRE_INC || GET_CODE (x) == PRE_DEC)
3284107590Sobrien      && !ALTIVEC_VECTOR_MODE (mode)
3285117395Skan      && !SPE_VECTOR_MODE (mode)
328690075Sobrien      && TARGET_UPDATE
3287132718Skan      && legitimate_indirect_address_p (XEXP (x, 0), reg_ok_strict))
328890075Sobrien    return 1;
3289132718Skan  if (legitimate_small_data_p (mode, x))
329090075Sobrien    return 1;
3291132718Skan  if (legitimate_constant_pool_address_p (x))
329290075Sobrien    return 1;
329390075Sobrien  /* If not REG_OK_STRICT (before reload) let pass any stack offset.  */
329490075Sobrien  if (! reg_ok_strict
329590075Sobrien      && GET_CODE (x) == PLUS
329690075Sobrien      && GET_CODE (XEXP (x, 0)) == REG
3297132718Skan      && (XEXP (x, 0) == virtual_stack_vars_rtx
3298132718Skan	  || XEXP (x, 0) == arg_pointer_rtx)
329990075Sobrien      && GET_CODE (XEXP (x, 1)) == CONST_INT)
330090075Sobrien    return 1;
3301132718Skan  if (legitimate_offset_address_p (mode, x, reg_ok_strict))
330290075Sobrien    return 1;
330390075Sobrien  if (mode != TImode
3304117395Skan      && ((TARGET_HARD_FLOAT && TARGET_FPRS)
3305117395Skan	  || TARGET_POWERPC64
3306117395Skan	  || (mode != DFmode && mode != TFmode))
330790075Sobrien      && (TARGET_POWERPC64 || mode != DImode)
3308132718Skan      && legitimate_indexed_address_p (x, reg_ok_strict))
330990075Sobrien    return 1;
3310132718Skan  if (legitimate_lo_sum_address_p (mode, x, reg_ok_strict))
331190075Sobrien    return 1;
331290075Sobrien  return 0;
331390075Sobrien}
3314132718Skan
3315132718Skan/* Go to LABEL if ADDR (a legitimate address expression)
3316132718Skan   has an effect that depends on the machine mode it is used for.
3317132718Skan
3318132718Skan   On the RS/6000 this is true of all integral offsets (since AltiVec
3319132718Skan   modes don't allow them) or is a pre-increment or decrement.
3320132718Skan
3321132718Skan   ??? Except that due to conceptual problems in offsettable_address_p
3322132718Skan   we can't really report the problems of integral offsets.  So leave
3323132718Skan   this assuming that the adjustable offset must be valid for the
3324132718Skan   sub-words of a TFmode operand, which is what we had before.  */
3325132718Skan
3326132718Skanbool
3327132718Skanrs6000_mode_dependent_address (rtx addr)
3328132718Skan{
3329132718Skan  switch (GET_CODE (addr))
3330132718Skan    {
3331132718Skan    case PLUS:
3332132718Skan      if (GET_CODE (XEXP (addr, 1)) == CONST_INT)
3333132718Skan	{
3334132718Skan	  unsigned HOST_WIDE_INT val = INTVAL (XEXP (addr, 1));
3335132718Skan	  return val + 12 + 0x8000 >= 0x10000;
3336132718Skan	}
3337132718Skan      break;
3338132718Skan
3339132718Skan    case LO_SUM:
3340132718Skan      return true;
3341132718Skan
3342132718Skan    case PRE_INC:
3343132718Skan    case PRE_DEC:
3344132718Skan      return TARGET_UPDATE;
3345132718Skan
3346132718Skan    default:
3347132718Skan      break;
3348132718Skan    }
3349132718Skan
3350132718Skan  return false;
3351132718Skan}
335290075Sobrien
335390075Sobrien/* Try to output insns to set TARGET equal to the constant C if it can
335490075Sobrien   be done in less than N insns.  Do all computations in MODE.
335590075Sobrien   Returns the place where the output has been placed if it can be
335690075Sobrien   done and the insns have been emitted.  If it would take more than N
335790075Sobrien   insns, zero is returned and no insns and emitted.  */
335890075Sobrien
335990075Sobrienrtx
3360132718Skanrs6000_emit_set_const (rtx dest, enum machine_mode mode,
3361132718Skan		       rtx source, int n ATTRIBUTE_UNUSED)
336290075Sobrien{
3363117395Skan  rtx result, insn, set;
336490075Sobrien  HOST_WIDE_INT c0, c1;
336590075Sobrien
3366117395Skan  if (mode == QImode || mode == HImode)
336790075Sobrien    {
336890075Sobrien      if (dest == NULL)
336990075Sobrien        dest = gen_reg_rtx (mode);
337090075Sobrien      emit_insn (gen_rtx_SET (VOIDmode, dest, source));
337190075Sobrien      return dest;
337290075Sobrien    }
3373117395Skan  else if (mode == SImode)
3374117395Skan    {
3375117395Skan      result = no_new_pseudos ? dest : gen_reg_rtx (SImode);
337690075Sobrien
3377117395Skan      emit_insn (gen_rtx_SET (VOIDmode, result,
3378117395Skan			      GEN_INT (INTVAL (source)
3379117395Skan				       & (~ (HOST_WIDE_INT) 0xffff))));
3380117395Skan      emit_insn (gen_rtx_SET (VOIDmode, dest,
3381117395Skan			      gen_rtx_IOR (SImode, result,
3382117395Skan					   GEN_INT (INTVAL (source) & 0xffff))));
3383117395Skan      result = dest;
338490075Sobrien    }
3385117395Skan  else if (mode == DImode)
338690075Sobrien    {
3387117395Skan      if (GET_CODE (source) == CONST_INT)
3388117395Skan	{
3389117395Skan	  c0 = INTVAL (source);
3390117395Skan	  c1 = -(c0 < 0);
3391117395Skan	}
3392117395Skan      else if (GET_CODE (source) == CONST_DOUBLE)
3393117395Skan	{
339490075Sobrien#if HOST_BITS_PER_WIDE_INT >= 64
3395117395Skan	  c0 = CONST_DOUBLE_LOW (source);
3396117395Skan	  c1 = -(c0 < 0);
339790075Sobrien#else
3398117395Skan	  c0 = CONST_DOUBLE_LOW (source);
3399117395Skan	  c1 = CONST_DOUBLE_HIGH (source);
340090075Sobrien#endif
3401117395Skan	}
3402117395Skan      else
3403117395Skan	abort ();
3404117395Skan
3405117395Skan      result = rs6000_emit_set_long_const (dest, c0, c1);
340690075Sobrien    }
340790075Sobrien  else
340890075Sobrien    abort ();
340990075Sobrien
3410117395Skan  insn = get_last_insn ();
3411117395Skan  set = single_set (insn);
3412117395Skan  if (! CONSTANT_P (SET_SRC (set)))
3413117395Skan    set_unique_reg_note (insn, REG_EQUAL, source);
3414117395Skan
3415117395Skan  return result;
341690075Sobrien}
341790075Sobrien
341890075Sobrien/* Having failed to find a 3 insn sequence in rs6000_emit_set_const,
341990075Sobrien   fall back to a straight forward decomposition.  We do this to avoid
342090075Sobrien   exponential run times encountered when looking for longer sequences
342190075Sobrien   with rs6000_emit_set_const.  */
342290075Sobrienstatic rtx
3423132718Skanrs6000_emit_set_long_const (rtx dest, HOST_WIDE_INT c1, HOST_WIDE_INT c2)
342490075Sobrien{
342590075Sobrien  if (!TARGET_POWERPC64)
342690075Sobrien    {
342790075Sobrien      rtx operand1, operand2;
342890075Sobrien
342990075Sobrien      operand1 = operand_subword_force (dest, WORDS_BIG_ENDIAN == 0,
343090075Sobrien					DImode);
343190075Sobrien      operand2 = operand_subword_force (dest, WORDS_BIG_ENDIAN != 0,
343290075Sobrien					DImode);
343390075Sobrien      emit_move_insn (operand1, GEN_INT (c1));
343490075Sobrien      emit_move_insn (operand2, GEN_INT (c2));
343590075Sobrien    }
343690075Sobrien  else
343790075Sobrien    {
343890075Sobrien      HOST_WIDE_INT ud1, ud2, ud3, ud4;
343990075Sobrien
344090075Sobrien      ud1 = c1 & 0xffff;
344190075Sobrien      ud2 = (c1 & 0xffff0000) >> 16;
344290075Sobrien#if HOST_BITS_PER_WIDE_INT >= 64
344390075Sobrien      c2 = c1 >> 32;
344490075Sobrien#endif
344590075Sobrien      ud3 = c2 & 0xffff;
344690075Sobrien      ud4 = (c2 & 0xffff0000) >> 16;
344790075Sobrien
344890075Sobrien      if ((ud4 == 0xffff && ud3 == 0xffff && ud2 == 0xffff && (ud1 & 0x8000))
344990075Sobrien	  || (ud4 == 0 && ud3 == 0 && ud2 == 0 && ! (ud1 & 0x8000)))
345090075Sobrien	{
345190075Sobrien	  if (ud1 & 0x8000)
3452132718Skan	    emit_move_insn (dest, GEN_INT (((ud1 ^ 0x8000) -  0x8000)));
345390075Sobrien	  else
345490075Sobrien	    emit_move_insn (dest, GEN_INT (ud1));
345590075Sobrien	}
345690075Sobrien
345790075Sobrien      else if ((ud4 == 0xffff && ud3 == 0xffff && (ud2 & 0x8000))
345890075Sobrien	       || (ud4 == 0 && ud3 == 0 && ! (ud2 & 0x8000)))
345990075Sobrien	{
346090075Sobrien	  if (ud2 & 0x8000)
346190075Sobrien	    emit_move_insn (dest, GEN_INT (((ud2 << 16) ^ 0x80000000)
346290075Sobrien					   - 0x80000000));
346390075Sobrien	  else
346490075Sobrien	    emit_move_insn (dest, GEN_INT (ud2 << 16));
346590075Sobrien	  if (ud1 != 0)
346690075Sobrien	    emit_move_insn (dest, gen_rtx_IOR (DImode, dest, GEN_INT (ud1)));
346790075Sobrien	}
346890075Sobrien      else if ((ud4 == 0xffff && (ud3 & 0x8000))
346990075Sobrien	       || (ud4 == 0 && ! (ud3 & 0x8000)))
347090075Sobrien	{
347190075Sobrien	  if (ud3 & 0x8000)
347290075Sobrien	    emit_move_insn (dest, GEN_INT (((ud3 << 16) ^ 0x80000000)
347390075Sobrien					   - 0x80000000));
347490075Sobrien	  else
347590075Sobrien	    emit_move_insn (dest, GEN_INT (ud3 << 16));
347690075Sobrien
347790075Sobrien	  if (ud2 != 0)
347890075Sobrien	    emit_move_insn (dest, gen_rtx_IOR (DImode, dest, GEN_INT (ud2)));
347990075Sobrien	  emit_move_insn (dest, gen_rtx_ASHIFT (DImode, dest, GEN_INT (16)));
348090075Sobrien	  if (ud1 != 0)
348190075Sobrien	    emit_move_insn (dest, gen_rtx_IOR (DImode, dest, GEN_INT (ud1)));
348290075Sobrien	}
348390075Sobrien      else
348490075Sobrien	{
348590075Sobrien	  if (ud4 & 0x8000)
348690075Sobrien	    emit_move_insn (dest, GEN_INT (((ud4 << 16) ^ 0x80000000)
348790075Sobrien					   - 0x80000000));
348890075Sobrien	  else
348990075Sobrien	    emit_move_insn (dest, GEN_INT (ud4 << 16));
349090075Sobrien
349190075Sobrien	  if (ud3 != 0)
349290075Sobrien	    emit_move_insn (dest, gen_rtx_IOR (DImode, dest, GEN_INT (ud3)));
349390075Sobrien
349490075Sobrien	  emit_move_insn (dest, gen_rtx_ASHIFT (DImode, dest, GEN_INT (32)));
349590075Sobrien	  if (ud2 != 0)
349690075Sobrien	    emit_move_insn (dest, gen_rtx_IOR (DImode, dest,
349790075Sobrien					       GEN_INT (ud2 << 16)));
349890075Sobrien	  if (ud1 != 0)
349990075Sobrien	    emit_move_insn (dest, gen_rtx_IOR (DImode, dest, GEN_INT (ud1)));
350090075Sobrien	}
350190075Sobrien    }
350290075Sobrien  return dest;
350390075Sobrien}
350490075Sobrien
350590075Sobrien/* Emit a move from SOURCE to DEST in mode MODE.  */
350690075Sobrienvoid
3507132718Skanrs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
350890075Sobrien{
350990075Sobrien  rtx operands[2];
351090075Sobrien  operands[0] = dest;
351190075Sobrien  operands[1] = source;
351290075Sobrien
351390075Sobrien  /* Sanity checks.  Check that we get CONST_DOUBLE only when we should.  */
351490075Sobrien  if (GET_CODE (operands[1]) == CONST_DOUBLE
351590075Sobrien      && ! FLOAT_MODE_P (mode)
351690075Sobrien      && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
351790075Sobrien    {
351890075Sobrien      /* FIXME.  This should never happen.  */
351990075Sobrien      /* Since it seems that it does, do the safe thing and convert
352090075Sobrien	 to a CONST_INT.  */
3521117395Skan      operands[1] = gen_int_mode (CONST_DOUBLE_LOW (operands[1]), mode);
352290075Sobrien    }
352390075Sobrien  if (GET_CODE (operands[1]) == CONST_DOUBLE
352490075Sobrien      && ! FLOAT_MODE_P (mode)
352590075Sobrien      && ((CONST_DOUBLE_HIGH (operands[1]) == 0
352690075Sobrien	   && CONST_DOUBLE_LOW (operands[1]) >= 0)
352790075Sobrien	  || (CONST_DOUBLE_HIGH (operands[1]) == -1
352890075Sobrien	      && CONST_DOUBLE_LOW (operands[1]) < 0)))
352990075Sobrien    abort ();
353090075Sobrien
353190075Sobrien  /* Check if GCC is setting up a block move that will end up using FP
353290075Sobrien     registers as temporaries.  We must make sure this is acceptable.  */
353390075Sobrien  if (GET_CODE (operands[0]) == MEM
353490075Sobrien      && GET_CODE (operands[1]) == MEM
353590075Sobrien      && mode == DImode
353690075Sobrien      && (SLOW_UNALIGNED_ACCESS (DImode, MEM_ALIGN (operands[0]))
353790075Sobrien	  || SLOW_UNALIGNED_ACCESS (DImode, MEM_ALIGN (operands[1])))
353890075Sobrien      && ! (SLOW_UNALIGNED_ACCESS (SImode, (MEM_ALIGN (operands[0]) > 32
353990075Sobrien					    ? 32 : MEM_ALIGN (operands[0])))
354090075Sobrien	    || SLOW_UNALIGNED_ACCESS (SImode, (MEM_ALIGN (operands[1]) > 32
354190075Sobrien					       ? 32
354290075Sobrien					       : MEM_ALIGN (operands[1]))))
354390075Sobrien      && ! MEM_VOLATILE_P (operands [0])
354490075Sobrien      && ! MEM_VOLATILE_P (operands [1]))
354590075Sobrien    {
354690075Sobrien      emit_move_insn (adjust_address (operands[0], SImode, 0),
354790075Sobrien		      adjust_address (operands[1], SImode, 0));
354890075Sobrien      emit_move_insn (adjust_address (operands[0], SImode, 4),
354990075Sobrien		      adjust_address (operands[1], SImode, 4));
355090075Sobrien      return;
355190075Sobrien    }
355290075Sobrien
3553117395Skan  if (!no_new_pseudos)
3554117395Skan    {
3555117395Skan      if (GET_CODE (operands[1]) == MEM && optimize > 0
3556117395Skan	  && (mode == QImode || mode == HImode || mode == SImode)
3557117395Skan	  && GET_MODE_SIZE (mode) < GET_MODE_SIZE (word_mode))
3558117395Skan	{
3559117395Skan	  rtx reg = gen_reg_rtx (word_mode);
356090075Sobrien
3561117395Skan	  emit_insn (gen_rtx_SET (word_mode, reg,
3562117395Skan				  gen_rtx_ZERO_EXTEND (word_mode,
3563117395Skan						       operands[1])));
3564117395Skan	  operands[1] = gen_lowpart (mode, reg);
3565117395Skan	}
3566117395Skan      if (GET_CODE (operands[0]) != REG)
3567117395Skan	operands[1] = force_reg (mode, operands[1]);
3568117395Skan    }
3569117395Skan
3570117395Skan  if (mode == SFmode && ! TARGET_POWERPC
3571117395Skan      && TARGET_HARD_FLOAT && TARGET_FPRS
357290075Sobrien      && GET_CODE (operands[0]) == MEM)
357390075Sobrien    {
357490075Sobrien      int regnum;
357590075Sobrien
357690075Sobrien      if (reload_in_progress || reload_completed)
357790075Sobrien	regnum = true_regnum (operands[1]);
357890075Sobrien      else if (GET_CODE (operands[1]) == REG)
357990075Sobrien	regnum = REGNO (operands[1]);
358090075Sobrien      else
358190075Sobrien	regnum = -1;
358290075Sobrien
358390075Sobrien      /* If operands[1] is a register, on POWER it may have
358490075Sobrien	 double-precision data in it, so truncate it to single
358590075Sobrien	 precision.  */
358690075Sobrien      if (FP_REGNO_P (regnum) || regnum >= FIRST_PSEUDO_REGISTER)
358790075Sobrien	{
358890075Sobrien	  rtx newreg;
358990075Sobrien	  newreg = (no_new_pseudos ? operands[1] : gen_reg_rtx (mode));
359090075Sobrien	  emit_insn (gen_aux_truncdfsf2 (newreg, operands[1]));
359190075Sobrien	  operands[1] = newreg;
359290075Sobrien	}
359390075Sobrien    }
359490075Sobrien
3595132718Skan  /* Recognize the case where operand[1] is a reference to thread-local
3596132718Skan     data and load its address to a register.  */
3597132718Skan  if (GET_CODE (operands[1]) == SYMBOL_REF)
3598132718Skan    {
3599132718Skan      enum tls_model model = SYMBOL_REF_TLS_MODEL (operands[1]);
3600132718Skan      if (model != 0)
3601132718Skan	operands[1] = rs6000_legitimize_tls_address (operands[1], model);
3602132718Skan    }
3603132718Skan
3604117395Skan  /* Handle the case where reload calls us with an invalid address.  */
3605117395Skan  if (reload_in_progress && mode == Pmode
360696263Sobrien      && (! general_operand (operands[1], mode)
3607117395Skan	  || ! nonimmediate_operand (operands[0], mode)))
3608117395Skan    goto emit_set;
3609117395Skan
3610117395Skan  /* Handle the case of CONSTANT_P_RTX.  */
3611117395Skan  if (GET_CODE (operands[1]) == CONSTANT_P_RTX)
3612117395Skan    goto emit_set;
3613132718Skan
3614132718Skan  /* 128-bit constant floating-point values on Darwin should really be
3615132718Skan     loaded as two parts.  */
3616132718Skan  if ((DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_DARWIN)
3617132718Skan      && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128
3618132718Skan      && mode == TFmode && GET_CODE (operands[1]) == CONST_DOUBLE)
3619132718Skan    {
3620132718Skan      /* DImode is used, not DFmode, because simplify_gen_subreg doesn't
3621132718Skan	 know how to get a DFmode SUBREG of a TFmode.  */
3622132718Skan      rs6000_emit_move (simplify_gen_subreg (DImode, operands[0], mode, 0),
3623132718Skan			simplify_gen_subreg (DImode, operands[1], mode, 0),
3624132718Skan			DImode);
3625132718Skan      rs6000_emit_move (simplify_gen_subreg (DImode, operands[0], mode,
3626132718Skan					     GET_MODE_SIZE (DImode)),
3627132718Skan			simplify_gen_subreg (DImode, operands[1], mode,
3628132718Skan					     GET_MODE_SIZE (DImode)),
3629132718Skan			DImode);
3630132718Skan      return;
3631132718Skan    }
3632132718Skan
363390075Sobrien  /* FIXME:  In the long term, this switch statement should go away
363490075Sobrien     and be replaced by a sequence of tests based on things like
363590075Sobrien     mode == Pmode.  */
363690075Sobrien  switch (mode)
363790075Sobrien    {
363890075Sobrien    case HImode:
363990075Sobrien    case QImode:
364090075Sobrien      if (CONSTANT_P (operands[1])
364190075Sobrien	  && GET_CODE (operands[1]) != CONST_INT)
364290075Sobrien	operands[1] = force_const_mem (mode, operands[1]);
364390075Sobrien      break;
364490075Sobrien
364590075Sobrien    case TFmode:
364690075Sobrien    case DFmode:
364790075Sobrien    case SFmode:
364890075Sobrien      if (CONSTANT_P (operands[1])
364990075Sobrien	  && ! easy_fp_constant (operands[1], mode))
365090075Sobrien	operands[1] = force_const_mem (mode, operands[1]);
365190075Sobrien      break;
365290075Sobrien
365390075Sobrien    case V16QImode:
365490075Sobrien    case V8HImode:
365590075Sobrien    case V4SFmode:
365690075Sobrien    case V4SImode:
3657117395Skan    case V4HImode:
3658117395Skan    case V2SFmode:
3659117395Skan    case V2SImode:
3660117395Skan    case V1DImode:
366196263Sobrien      if (CONSTANT_P (operands[1])
3662132718Skan	  && !easy_vector_constant (operands[1], mode))
366390075Sobrien	operands[1] = force_const_mem (mode, operands[1]);
366490075Sobrien      break;
366590075Sobrien
366690075Sobrien    case SImode:
366790075Sobrien    case DImode:
366890075Sobrien      /* Use default pattern for address of ELF small data */
366990075Sobrien      if (TARGET_ELF
367090075Sobrien	  && mode == Pmode
367190075Sobrien	  && DEFAULT_ABI == ABI_V4
367290075Sobrien	  && (GET_CODE (operands[1]) == SYMBOL_REF
367390075Sobrien	      || GET_CODE (operands[1]) == CONST)
367490075Sobrien	  && small_data_operand (operands[1], mode))
367590075Sobrien	{
367690075Sobrien	  emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
367790075Sobrien	  return;
367890075Sobrien	}
367990075Sobrien
368090075Sobrien      if (DEFAULT_ABI == ABI_V4
368190075Sobrien	  && mode == Pmode && mode == SImode
368290075Sobrien	  && flag_pic == 1 && got_operand (operands[1], mode))
368390075Sobrien	{
368490075Sobrien	  emit_insn (gen_movsi_got (operands[0], operands[1]));
368590075Sobrien	  return;
368690075Sobrien	}
368790075Sobrien
368890075Sobrien      if ((TARGET_ELF || DEFAULT_ABI == ABI_DARWIN)
3689132718Skan	  && TARGET_NO_TOC
3690132718Skan	  && ! flag_pic
369190075Sobrien	  && mode == Pmode
369290075Sobrien	  && CONSTANT_P (operands[1])
369390075Sobrien	  && GET_CODE (operands[1]) != HIGH
369490075Sobrien	  && GET_CODE (operands[1]) != CONST_INT)
369590075Sobrien	{
369690075Sobrien	  rtx target = (no_new_pseudos ? operands[0] : gen_reg_rtx (mode));
369790075Sobrien
369890075Sobrien	  /* If this is a function address on -mcall-aixdesc,
369990075Sobrien	     convert it to the address of the descriptor.  */
370090075Sobrien	  if (DEFAULT_ABI == ABI_AIX
370190075Sobrien	      && GET_CODE (operands[1]) == SYMBOL_REF
370290075Sobrien	      && XSTR (operands[1], 0)[0] == '.')
370390075Sobrien	    {
370490075Sobrien	      const char *name = XSTR (operands[1], 0);
370590075Sobrien	      rtx new_ref;
370690075Sobrien	      while (*name == '.')
370790075Sobrien		name++;
370890075Sobrien	      new_ref = gen_rtx_SYMBOL_REF (Pmode, name);
370990075Sobrien	      CONSTANT_POOL_ADDRESS_P (new_ref)
371090075Sobrien		= CONSTANT_POOL_ADDRESS_P (operands[1]);
3711132718Skan	      SYMBOL_REF_FLAGS (new_ref) = SYMBOL_REF_FLAGS (operands[1]);
371290075Sobrien	      SYMBOL_REF_USED (new_ref) = SYMBOL_REF_USED (operands[1]);
3713132718Skan	      SYMBOL_REF_DECL (new_ref) = SYMBOL_REF_DECL (operands[1]);
371490075Sobrien	      operands[1] = new_ref;
371590075Sobrien	    }
371690075Sobrien
371790075Sobrien	  if (DEFAULT_ABI == ABI_DARWIN)
371890075Sobrien	    {
3719132718Skan#if TARGET_MACHO
3720132718Skan	      if (MACHO_DYNAMIC_NO_PIC_P)
3721132718Skan		{
3722132718Skan		  /* Take care of any required data indirection.  */
3723132718Skan		  operands[1] = rs6000_machopic_legitimize_pic_address (
3724132718Skan				  operands[1], mode, operands[0]);
3725132718Skan		  if (operands[0] != operands[1])
3726132718Skan		    emit_insn (gen_rtx_SET (VOIDmode,
3727132718Skan				            operands[0], operands[1]));
3728132718Skan		  return;
3729132718Skan		}
3730132718Skan#endif
373190075Sobrien	      emit_insn (gen_macho_high (target, operands[1]));
373290075Sobrien	      emit_insn (gen_macho_low (operands[0], target, operands[1]));
373390075Sobrien	      return;
373490075Sobrien	    }
373590075Sobrien
373690075Sobrien	  emit_insn (gen_elf_high (target, operands[1]));
373790075Sobrien	  emit_insn (gen_elf_low (operands[0], target, operands[1]));
373890075Sobrien	  return;
373990075Sobrien	}
374090075Sobrien
374190075Sobrien      /* If this is a SYMBOL_REF that refers to a constant pool entry,
374290075Sobrien	 and we have put it in the TOC, we just need to make a TOC-relative
374390075Sobrien	 reference to it.  */
374490075Sobrien      if (TARGET_TOC
374590075Sobrien	  && GET_CODE (operands[1]) == SYMBOL_REF
3746132718Skan	  && constant_pool_expr_p (operands[1])
374790075Sobrien	  && ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (operands[1]),
374890075Sobrien					      get_pool_mode (operands[1])))
374990075Sobrien	{
375090075Sobrien	  operands[1] = create_TOC_reference (operands[1]);
375190075Sobrien	}
375290075Sobrien      else if (mode == Pmode
375390075Sobrien	       && CONSTANT_P (operands[1])
375490075Sobrien	       && ((GET_CODE (operands[1]) != CONST_INT
375590075Sobrien		    && ! easy_fp_constant (operands[1], mode))
375690075Sobrien		   || (GET_CODE (operands[1]) == CONST_INT
375790075Sobrien		       && num_insns_constant (operands[1], mode) > 2)
375890075Sobrien		   || (GET_CODE (operands[0]) == REG
375990075Sobrien		       && FP_REGNO_P (REGNO (operands[0]))))
376090075Sobrien	       && GET_CODE (operands[1]) != HIGH
3761132718Skan	       && ! legitimate_constant_pool_address_p (operands[1])
3762132718Skan	       && ! toc_relative_expr_p (operands[1]))
376390075Sobrien	{
376490075Sobrien	  /* Emit a USE operation so that the constant isn't deleted if
376590075Sobrien	     expensive optimizations are turned on because nobody
376690075Sobrien	     references it.  This should only be done for operands that
376790075Sobrien	     contain SYMBOL_REFs with CONSTANT_POOL_ADDRESS_P set.
376890075Sobrien	     This should not be done for operands that contain LABEL_REFs.
376990075Sobrien	     For now, we just handle the obvious case.  */
377090075Sobrien	  if (GET_CODE (operands[1]) != LABEL_REF)
377190075Sobrien	    emit_insn (gen_rtx_USE (VOIDmode, operands[1]));
377290075Sobrien
377390075Sobrien#if TARGET_MACHO
377490075Sobrien	  /* Darwin uses a special PIC legitimizer.  */
3775132718Skan	  if (DEFAULT_ABI == ABI_DARWIN && MACHOPIC_INDIRECT)
377690075Sobrien	    {
377790075Sobrien	      operands[1] =
377890075Sobrien		rs6000_machopic_legitimize_pic_address (operands[1], mode,
377990075Sobrien							operands[0]);
378090075Sobrien	      if (operands[0] != operands[1])
378190075Sobrien		emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
378290075Sobrien	      return;
378390075Sobrien	    }
378490075Sobrien#endif
378590075Sobrien
378690075Sobrien	  /* If we are to limit the number of things we put in the TOC and
378790075Sobrien	     this is a symbol plus a constant we can add in one insn,
378890075Sobrien	     just put the symbol in the TOC and add the constant.  Don't do
378990075Sobrien	     this if reload is in progress.  */
379090075Sobrien	  if (GET_CODE (operands[1]) == CONST
379190075Sobrien	      && TARGET_NO_SUM_IN_TOC && ! reload_in_progress
379290075Sobrien	      && GET_CODE (XEXP (operands[1], 0)) == PLUS
379390075Sobrien	      && add_operand (XEXP (XEXP (operands[1], 0), 1), mode)
379490075Sobrien	      && (GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == LABEL_REF
379590075Sobrien		  || GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == SYMBOL_REF)
379690075Sobrien	      && ! side_effects_p (operands[0]))
379790075Sobrien	    {
379890075Sobrien	      rtx sym =
379990075Sobrien		force_const_mem (mode, XEXP (XEXP (operands[1], 0), 0));
380090075Sobrien	      rtx other = XEXP (XEXP (operands[1], 0), 1);
380190075Sobrien
380290075Sobrien	      sym = force_reg (mode, sym);
380390075Sobrien	      if (mode == SImode)
380490075Sobrien		emit_insn (gen_addsi3 (operands[0], sym, other));
380590075Sobrien	      else
380690075Sobrien		emit_insn (gen_adddi3 (operands[0], sym, other));
380790075Sobrien	      return;
380890075Sobrien	    }
380990075Sobrien
381090075Sobrien	  operands[1] = force_const_mem (mode, operands[1]);
381190075Sobrien
381290075Sobrien	  if (TARGET_TOC
3813132718Skan	      && constant_pool_expr_p (XEXP (operands[1], 0))
381490075Sobrien	      && ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (
381590075Sobrien			get_pool_constant (XEXP (operands[1], 0)),
381690075Sobrien			get_pool_mode (XEXP (operands[1], 0))))
381790075Sobrien	    {
381890075Sobrien	      operands[1]
381990075Sobrien		= gen_rtx_MEM (mode,
382090075Sobrien			       create_TOC_reference (XEXP (operands[1], 0)));
382190075Sobrien	      set_mem_alias_set (operands[1], get_TOC_alias_set ());
382290075Sobrien	      RTX_UNCHANGING_P (operands[1]) = 1;
382390075Sobrien	    }
382490075Sobrien	}
382590075Sobrien      break;
382690075Sobrien
382790075Sobrien    case TImode:
382890075Sobrien      if (GET_CODE (operands[0]) == MEM
382990075Sobrien	  && GET_CODE (XEXP (operands[0], 0)) != REG
383090075Sobrien	  && ! reload_in_progress)
383190075Sobrien	operands[0]
383290075Sobrien	  = replace_equiv_address (operands[0],
383390075Sobrien				   copy_addr_to_reg (XEXP (operands[0], 0)));
383490075Sobrien
383590075Sobrien      if (GET_CODE (operands[1]) == MEM
383690075Sobrien	  && GET_CODE (XEXP (operands[1], 0)) != REG
383790075Sobrien	  && ! reload_in_progress)
383890075Sobrien	operands[1]
383990075Sobrien	  = replace_equiv_address (operands[1],
384090075Sobrien				   copy_addr_to_reg (XEXP (operands[1], 0)));
3841117395Skan      if (TARGET_POWER)
3842132718Skan	{
3843117395Skan	  emit_insn (gen_rtx_PARALLEL (VOIDmode,
3844117395Skan		       gen_rtvec (2,
3845117395Skan				  gen_rtx_SET (VOIDmode,
3846117395Skan					       operands[0], operands[1]),
3847117395Skan				  gen_rtx_CLOBBER (VOIDmode,
3848117395Skan						   gen_rtx_SCRATCH (SImode)))));
3849117395Skan	  return;
3850117395Skan	}
385190075Sobrien      break;
385290075Sobrien
385390075Sobrien    default:
385490075Sobrien      abort ();
385590075Sobrien    }
385690075Sobrien
385790075Sobrien  /* Above, we may have called force_const_mem which may have returned
385890075Sobrien     an invalid address.  If we can, fix this up; otherwise, reload will
385990075Sobrien     have to deal with it.  */
3860117395Skan  if (GET_CODE (operands[1]) == MEM && ! reload_in_progress)
3861117395Skan    operands[1] = validize_mem (operands[1]);
386290075Sobrien
3863117395Skan emit_set:
386490075Sobrien  emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
386590075Sobrien}
386690075Sobrien
3867132718Skan/* Nonzero if we can use a floating-point register to pass this arg.  */
3868132718Skan#define USE_FP_FOR_ARG_P(CUM,MODE,TYPE)		\
3869132718Skan  (GET_MODE_CLASS (MODE) == MODE_FLOAT		\
3870132718Skan   && (CUM)->fregno <= FP_ARG_MAX_REG		\
3871132718Skan   && TARGET_HARD_FLOAT && TARGET_FPRS)
3872132718Skan
3873132718Skan/* Nonzero if we can use an AltiVec register to pass this arg.  */
3874132718Skan#define USE_ALTIVEC_FOR_ARG_P(CUM,MODE,TYPE,NAMED)	\
3875132718Skan  (ALTIVEC_VECTOR_MODE (MODE)				\
3876132718Skan   && (CUM)->vregno <= ALTIVEC_ARG_MAX_REG		\
3877132718Skan   && TARGET_ALTIVEC_ABI				\
3878132718Skan   && (NAMED))
3879132718Skan
3880132718Skan/* Return a nonzero value to say to return the function value in
3881132718Skan   memory, just as large structures are always returned.  TYPE will be
3882132718Skan   the data type of the value, and FNTYPE will be the type of the
3883132718Skan   function doing the returning, or @code{NULL} for libcalls.
3884132718Skan
3885132718Skan   The AIX ABI for the RS/6000 specifies that all structures are
3886132718Skan   returned in memory.  The Darwin ABI does the same.  The SVR4 ABI
3887132718Skan   specifies that structures <= 8 bytes are returned in r3/r4, but a
3888132718Skan   draft put them in memory, and GCC used to implement the draft
3889132718Skan   instead of the final standard.  Therefore, TARGET_AIX_STRUCT_RET
3890132718Skan   controls this instead of DEFAULT_ABI; V.4 targets needing backward
3891132718Skan   compatibility can change DRAFT_V4_STRUCT_RET to override the
3892132718Skan   default, and -m switches get the final word.  See
3893132718Skan   rs6000_override_options for more details.
3894132718Skan
3895132718Skan   The PPC32 SVR4 ABI uses IEEE double extended for long double, if 128-bit
3896132718Skan   long double support is enabled.  These values are returned in memory.
3897132718Skan
3898132718Skan   int_size_in_bytes returns -1 for variable size objects, which go in
3899132718Skan   memory always.  The cast to unsigned makes -1 > 8.  */
3900132718Skan
3901132718Skanstatic bool
3902132718Skanrs6000_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
3903132718Skan{
3904132718Skan  if (AGGREGATE_TYPE_P (type)
3905132718Skan      && (TARGET_AIX_STRUCT_RET
3906132718Skan	  || (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 8))
3907132718Skan    return true;
3908132718Skan  if (DEFAULT_ABI == ABI_V4 && TYPE_MODE (type) == TFmode)
3909132718Skan    return true;
3910132718Skan  return false;
3911132718Skan}
3912132718Skan
391390075Sobrien/* Initialize a variable CUM of type CUMULATIVE_ARGS
391490075Sobrien   for a call to a function whose data type is FNTYPE.
391590075Sobrien   For a library call, FNTYPE is 0.
391690075Sobrien
391790075Sobrien   For incoming args we set the number of arguments in the prototype large
391890075Sobrien   so we never return a PARALLEL.  */
391990075Sobrien
392090075Sobrienvoid
3921132718Skaninit_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
3922132718Skan		      rtx libname ATTRIBUTE_UNUSED, int incoming,
3923132718Skan		      int libcall, int n_named_args)
392490075Sobrien{
392590075Sobrien  static CUMULATIVE_ARGS zero_cumulative;
392690075Sobrien
392790075Sobrien  *cum = zero_cumulative;
392890075Sobrien  cum->words = 0;
392990075Sobrien  cum->fregno = FP_ARG_MIN_REG;
393090075Sobrien  cum->vregno = ALTIVEC_ARG_MIN_REG;
393190075Sobrien  cum->prototype = (fntype && TYPE_ARG_TYPES (fntype));
3932117395Skan  cum->call_cookie = ((DEFAULT_ABI == ABI_V4 && libcall)
3933117395Skan		      ? CALL_LIBCALL : CALL_NORMAL);
393490075Sobrien  cum->sysv_gregno = GP_ARG_MIN_REG;
3935132718Skan  cum->stdarg = fntype
3936132718Skan    && (TYPE_ARG_TYPES (fntype) != 0
3937132718Skan	&& (TREE_VALUE (tree_last  (TYPE_ARG_TYPES (fntype)))
3938132718Skan	    != void_type_node));
393990075Sobrien
3940132718Skan  cum->nargs_prototype = 0;
3941132718Skan  if (incoming || cum->prototype)
3942132718Skan    cum->nargs_prototype = n_named_args;
394390075Sobrien
3944117395Skan  /* Check for a longcall attribute.  */
3945117395Skan  if (fntype
3946117395Skan      && lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype))
3947117395Skan      && !lookup_attribute ("shortcall", TYPE_ATTRIBUTES (fntype)))
394890075Sobrien    cum->call_cookie = CALL_LONG;
394990075Sobrien
395090075Sobrien  if (TARGET_DEBUG_ARG)
395190075Sobrien    {
395290075Sobrien      fprintf (stderr, "\ninit_cumulative_args:");
395390075Sobrien      if (fntype)
395490075Sobrien	{
395590075Sobrien	  tree ret_type = TREE_TYPE (fntype);
395690075Sobrien	  fprintf (stderr, " ret code = %s,",
395790075Sobrien		   tree_code_name[ (int)TREE_CODE (ret_type) ]);
395890075Sobrien	}
395990075Sobrien
396090075Sobrien      if (cum->call_cookie & CALL_LONG)
396190075Sobrien	fprintf (stderr, " longcall,");
396290075Sobrien
396390075Sobrien      fprintf (stderr, " proto = %d, nargs = %d\n",
396490075Sobrien	       cum->prototype, cum->nargs_prototype);
396590075Sobrien    }
3966132718Skan
3967132718Skan    if (fntype
3968132718Skan	&& !TARGET_ALTIVEC
3969132718Skan	&& TARGET_ALTIVEC_ABI
3970132718Skan        && ALTIVEC_VECTOR_MODE (TYPE_MODE (TREE_TYPE (fntype))))
3971132718Skan      {
3972132718Skan	error ("Cannot return value in vector register because"
3973132718Skan	       " altivec instructions are disabled, use -maltivec"
3974132718Skan	       " to enable them.");
3975132718Skan      }
397690075Sobrien}
397790075Sobrien
397890075Sobrien/* If defined, a C expression which determines whether, and in which
397990075Sobrien   direction, to pad out an argument with extra space.  The value
398090075Sobrien   should be of type `enum direction': either `upward' to pad above
398190075Sobrien   the argument, `downward' to pad below, or `none' to inhibit
398290075Sobrien   padding.
398390075Sobrien
398490075Sobrien   For the AIX ABI structs are always stored left shifted in their
398590075Sobrien   argument slot.  */
398690075Sobrien
398790075Sobrienenum direction
3988132718Skanfunction_arg_padding (enum machine_mode mode, tree type)
398990075Sobrien{
3990132718Skan#ifndef AGGREGATE_PADDING_FIXED
3991132718Skan#define AGGREGATE_PADDING_FIXED 0
3992132718Skan#endif
3993132718Skan#ifndef AGGREGATES_PAD_UPWARD_ALWAYS
3994132718Skan#define AGGREGATES_PAD_UPWARD_ALWAYS 0
3995132718Skan#endif
399690075Sobrien
3997132718Skan  if (!AGGREGATE_PADDING_FIXED)
3998132718Skan    {
3999132718Skan      /* GCC used to pass structures of the same size as integer types as
4000132718Skan	 if they were in fact integers, ignoring FUNCTION_ARG_PADDING.
4001132718Skan	 ie. Structures of size 1 or 2 (or 4 when TARGET_64BIT) were
4002132718Skan	 passed padded downward, except that -mstrict-align further
4003132718Skan	 muddied the water in that multi-component structures of 2 and 4
4004132718Skan	 bytes in size were passed padded upward.
4005132718Skan
4006132718Skan	 The following arranges for best compatibility with previous
4007132718Skan	 versions of gcc, but removes the -mstrict-align dependency.  */
4008132718Skan      if (BYTES_BIG_ENDIAN)
4009132718Skan	{
4010132718Skan	  HOST_WIDE_INT size = 0;
4011132718Skan
4012132718Skan	  if (mode == BLKmode)
4013132718Skan	    {
4014132718Skan	      if (type && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST)
4015132718Skan		size = int_size_in_bytes (type);
4016132718Skan	    }
4017132718Skan	  else
4018132718Skan	    size = GET_MODE_SIZE (mode);
4019132718Skan
4020132718Skan	  if (size == 1 || size == 2 || size == 4)
4021132718Skan	    return downward;
4022132718Skan	}
4023132718Skan      return upward;
4024132718Skan    }
4025132718Skan
4026132718Skan  if (AGGREGATES_PAD_UPWARD_ALWAYS)
4027132718Skan    {
4028132718Skan      if (type != 0 && AGGREGATE_TYPE_P (type))
4029132718Skan	return upward;
4030132718Skan    }
4031132718Skan
4032132718Skan  /* Fall back to the default.  */
4033132718Skan  return DEFAULT_FUNCTION_ARG_PADDING (mode, type);
403490075Sobrien}
403590075Sobrien
403690075Sobrien/* If defined, a C expression that gives the alignment boundary, in bits,
403790075Sobrien   of an argument with the specified mode and type.  If it is not defined,
403890075Sobrien   PARM_BOUNDARY is used for all arguments.
403990075Sobrien
404090075Sobrien   V.4 wants long longs to be double word aligned.  */
404190075Sobrien
404290075Sobrienint
4043132718Skanfunction_arg_boundary (enum machine_mode mode, tree type ATTRIBUTE_UNUSED)
404490075Sobrien{
4045132718Skan  if (DEFAULT_ABI == ABI_V4 && GET_MODE_SIZE (mode) == 8)
404690075Sobrien    return 64;
4047132718Skan  else if (SPE_VECTOR_MODE (mode))
4048132718Skan    return 64;
4049132718Skan  else if (ALTIVEC_VECTOR_MODE (mode))
405090075Sobrien    return 128;
405190075Sobrien  else
405290075Sobrien    return PARM_BOUNDARY;
405390075Sobrien}
4054132718Skan
4055132718Skan/* Compute the size (in words) of a function argument.  */
4056132718Skan
4057132718Skanstatic unsigned long
4058132718Skanrs6000_arg_size (enum machine_mode mode, tree type)
4059132718Skan{
4060132718Skan  unsigned long size;
4061132718Skan
4062132718Skan  if (mode != BLKmode)
4063132718Skan    size = GET_MODE_SIZE (mode);
4064132718Skan  else
4065132718Skan    size = int_size_in_bytes (type);
4066132718Skan
4067132718Skan  if (TARGET_32BIT)
4068132718Skan    return (size + 3) >> 2;
4069132718Skan  else
4070132718Skan    return (size + 7) >> 3;
4071132718Skan}
407290075Sobrien
407390075Sobrien/* Update the data in CUM to advance over an argument
407490075Sobrien   of mode MODE and data type TYPE.
4075132718Skan   (TYPE is null for libcalls where that information may not be available.)
407690075Sobrien
4077132718Skan   Note that for args passed by reference, function_arg will be called
4078132718Skan   with MODE and TYPE set to that of the pointer to the arg, not the arg
4079132718Skan   itself.  */
4080132718Skan
408190075Sobrienvoid
4082132718Skanfunction_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
4083132718Skan		      tree type, int named)
408490075Sobrien{
408590075Sobrien  cum->nargs_prototype--;
408690075Sobrien
408790075Sobrien  if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
408890075Sobrien    {
4089132718Skan      bool stack = false;
4090132718Skan
4091132718Skan      if (USE_ALTIVEC_FOR_ARG_P (cum, mode, type, named))
4092132718Skan        {
4093132718Skan	  cum->vregno++;
4094132718Skan	  if (!TARGET_ALTIVEC)
4095132718Skan	    error ("Cannot pass argument in vector register because"
4096132718Skan		   " altivec instructions are disabled, use -maltivec"
4097132718Skan		   " to enable them.");
4098132718Skan
4099132718Skan	  /* PowerPC64 Linux and AIX allocate GPRs for a vector argument
4100132718Skan	     even if it is going to be passed in a vector register.
4101132718Skan	     Darwin does the same for variable-argument functions.  */
4102132718Skan	  if ((DEFAULT_ABI == ABI_AIX && TARGET_64BIT)
4103132718Skan	      || (cum->stdarg && DEFAULT_ABI != ABI_V4))
4104132718Skan	    stack = true;
4105132718Skan	}
410690075Sobrien      else
4107132718Skan	stack = true;
4108132718Skan
4109132718Skan      if (stack)
4110132718Skan        {
4111132718Skan	  int align;
4112132718Skan
4113132718Skan	  /* Vector parameters must be 16-byte aligned.  This places
4114132718Skan	     them at 2 mod 4 in terms of words in 32-bit mode, since
4115132718Skan	     the parameter save area starts at offset 24 from the
4116132718Skan	     stack.  In 64-bit mode, they just have to start on an
4117132718Skan	     even word, since the parameter save area is 16-byte
4118132718Skan	     aligned.  Space for GPRs is reserved even if the argument
4119132718Skan	     will be passed in memory.  */
4120132718Skan	  if (TARGET_32BIT)
4121132718Skan	    align = (2 - cum->words) & 3;
4122132718Skan	  else
4123132718Skan	    align = cum->words & 1;
4124132718Skan	  cum->words += align + rs6000_arg_size (mode, type);
4125132718Skan
4126132718Skan	  if (TARGET_DEBUG_ARG)
4127132718Skan	    {
4128132718Skan	      fprintf (stderr, "function_adv: words = %2d, align=%d, ",
4129132718Skan		       cum->words, align);
4130132718Skan	      fprintf (stderr, "nargs = %4d, proto = %d, mode = %4s\n",
4131132718Skan		       cum->nargs_prototype, cum->prototype,
4132132718Skan		       GET_MODE_NAME (mode));
4133132718Skan	    }
4134132718Skan	}
413590075Sobrien    }
4136117395Skan  else if (TARGET_SPE_ABI && TARGET_SPE && SPE_VECTOR_MODE (mode)
4137132718Skan	   && !cum->stdarg
4138132718Skan	   && cum->sysv_gregno <= GP_ARG_MAX_REG)
4139117395Skan    cum->sysv_gregno++;
414090075Sobrien  else if (DEFAULT_ABI == ABI_V4)
414190075Sobrien    {
4142117395Skan      if (TARGET_HARD_FLOAT && TARGET_FPRS
414390075Sobrien	  && (mode == SFmode || mode == DFmode))
414490075Sobrien	{
414590075Sobrien	  if (cum->fregno <= FP_ARG_V4_MAX_REG)
414690075Sobrien	    cum->fregno++;
414790075Sobrien	  else
414890075Sobrien	    {
414990075Sobrien	      if (mode == DFmode)
415090075Sobrien	        cum->words += cum->words & 1;
4151132718Skan	      cum->words += rs6000_arg_size (mode, type);
415290075Sobrien	    }
415390075Sobrien	}
415490075Sobrien      else
415590075Sobrien	{
4156132718Skan	  int n_words = rs6000_arg_size (mode, type);
415790075Sobrien	  int gregno = cum->sysv_gregno;
415890075Sobrien
4159132718Skan	  /* Long long and SPE vectors are put in (r3,r4), (r5,r6),
4160132718Skan	     (r7,r8) or (r9,r10).  As does any other 2 word item such
4161132718Skan	     as complex int due to a historical mistake.  */
4162132718Skan	  if (n_words == 2)
4163132718Skan	    gregno += (1 - gregno) & 1;
416490075Sobrien
4165132718Skan	  /* Multi-reg args are not split between registers and stack.  */
416690075Sobrien	  if (gregno + n_words - 1 > GP_ARG_MAX_REG)
416790075Sobrien	    {
4168132718Skan	      /* Long long and SPE vectors are aligned on the stack.
4169132718Skan		 So are other 2 word items such as complex int due to
4170132718Skan		 a historical mistake.  */
417190075Sobrien	      if (n_words == 2)
417290075Sobrien		cum->words += cum->words & 1;
417390075Sobrien	      cum->words += n_words;
417490075Sobrien	    }
417590075Sobrien
417690075Sobrien	  /* Note: continuing to accumulate gregno past when we've started
417790075Sobrien	     spilling to the stack indicates the fact that we've started
417890075Sobrien	     spilling to the stack to expand_builtin_saveregs.  */
417990075Sobrien	  cum->sysv_gregno = gregno + n_words;
418090075Sobrien	}
418190075Sobrien
418290075Sobrien      if (TARGET_DEBUG_ARG)
418390075Sobrien	{
418490075Sobrien	  fprintf (stderr, "function_adv: words = %2d, fregno = %2d, ",
418590075Sobrien		   cum->words, cum->fregno);
418690075Sobrien	  fprintf (stderr, "gregno = %2d, nargs = %4d, proto = %d, ",
418790075Sobrien		   cum->sysv_gregno, cum->nargs_prototype, cum->prototype);
418890075Sobrien	  fprintf (stderr, "mode = %4s, named = %d\n",
418990075Sobrien		   GET_MODE_NAME (mode), named);
419090075Sobrien	}
419190075Sobrien    }
419290075Sobrien  else
419390075Sobrien    {
4194132718Skan      int n_words = rs6000_arg_size (mode, type);
4195132718Skan      int align = function_arg_boundary (mode, type) / PARM_BOUNDARY - 1;
419690075Sobrien
4197132718Skan      /* The simple alignment calculation here works because
4198132718Skan	 function_arg_boundary / PARM_BOUNDARY will only be 1 or 2.
4199132718Skan	 If we ever want to handle alignments larger than 8 bytes for
4200132718Skan	 32-bit or 16 bytes for 64-bit, then we'll need to take into
4201132718Skan	 account the offset to the start of the parm save area.  */
4202132718Skan      align &= cum->words;
4203132718Skan      cum->words += align + n_words;
420490075Sobrien
4205117395Skan      if (GET_MODE_CLASS (mode) == MODE_FLOAT
4206117395Skan	  && TARGET_HARD_FLOAT && TARGET_FPRS)
4207132718Skan	cum->fregno += (GET_MODE_SIZE (mode) + 7) >> 3;
420890075Sobrien
420990075Sobrien      if (TARGET_DEBUG_ARG)
421090075Sobrien	{
421190075Sobrien	  fprintf (stderr, "function_adv: words = %2d, fregno = %2d, ",
421290075Sobrien		   cum->words, cum->fregno);
421390075Sobrien	  fprintf (stderr, "nargs = %4d, proto = %d, mode = %4s, ",
421490075Sobrien		   cum->nargs_prototype, cum->prototype, GET_MODE_NAME (mode));
421590075Sobrien	  fprintf (stderr, "named = %d, align = %d\n", named, align);
421690075Sobrien	}
421790075Sobrien    }
421890075Sobrien}
4219132718Skan
4220132718Skan/* Determine where to put a SIMD argument on the SPE.  */
4221132718Skan
4222132718Skanstatic rtx
4223132718Skanrs6000_spe_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
4224132718Skan			 tree type)
4225132718Skan{
4226132718Skan  if (cum->stdarg)
4227132718Skan    {
4228132718Skan      int gregno = cum->sysv_gregno;
4229132718Skan      int n_words = rs6000_arg_size (mode, type);
4230132718Skan
4231132718Skan      /* SPE vectors are put in odd registers.  */
4232132718Skan      if (n_words == 2 && (gregno & 1) == 0)
4233132718Skan	gregno += 1;
4234132718Skan
4235132718Skan      if (gregno + n_words - 1 <= GP_ARG_MAX_REG)
4236132718Skan	{
4237132718Skan	  rtx r1, r2;
4238132718Skan	  enum machine_mode m = SImode;
4239132718Skan
4240132718Skan	  r1 = gen_rtx_REG (m, gregno);
4241132718Skan	  r1 = gen_rtx_EXPR_LIST (m, r1, const0_rtx);
4242132718Skan	  r2 = gen_rtx_REG (m, gregno + 1);
4243132718Skan	  r2 = gen_rtx_EXPR_LIST (m, r2, GEN_INT (4));
4244132718Skan	  return gen_rtx_PARALLEL (mode, gen_rtvec (2, r1, r2));
4245132718Skan	}
4246132718Skan      else
4247132718Skan	return NULL_RTX;
4248132718Skan    }
4249132718Skan  else
4250132718Skan    {
4251132718Skan      if (cum->sysv_gregno <= GP_ARG_MAX_REG)
4252132718Skan	return gen_rtx_REG (mode, cum->sysv_gregno);
4253132718Skan      else
4254132718Skan	return NULL_RTX;
4255132718Skan    }
4256132718Skan}
4257132718Skan
4258132718Skan/* Determine where to place an argument in 64-bit mode with 32-bit ABI.  */
4259132718Skan
4260132718Skanstatic rtx
4261132718Skanrs6000_mixed_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
4262132718Skan			   tree type, int align_words)
4263132718Skan{
4264132718Skan  if (mode == DFmode)
4265132718Skan    {
4266132718Skan      /* -mpowerpc64 with 32bit ABI splits up a DFmode argument
4267132718Skan	 in vararg list into zero, one or two GPRs */
4268132718Skan      if (align_words >= GP_ARG_NUM_REG)
4269132718Skan	return gen_rtx_PARALLEL (DFmode,
4270132718Skan		 gen_rtvec (2,
4271132718Skan			    gen_rtx_EXPR_LIST (VOIDmode,
4272132718Skan					       NULL_RTX, const0_rtx),
4273132718Skan			    gen_rtx_EXPR_LIST (VOIDmode,
4274132718Skan					       gen_rtx_REG (mode,
4275132718Skan							    cum->fregno),
4276132718Skan					       const0_rtx)));
4277132718Skan      else if (align_words + rs6000_arg_size (mode, type)
4278132718Skan	       > GP_ARG_NUM_REG)
4279132718Skan	/* If this is partially on the stack, then we only
4280132718Skan	   include the portion actually in registers here.  */
4281132718Skan	return gen_rtx_PARALLEL (DFmode,
4282132718Skan		 gen_rtvec (2,
4283132718Skan			    gen_rtx_EXPR_LIST (VOIDmode,
4284132718Skan					       gen_rtx_REG (SImode,
4285132718Skan							    GP_ARG_MIN_REG
4286132718Skan							    + align_words),
4287132718Skan					       const0_rtx),
4288132718Skan			    gen_rtx_EXPR_LIST (VOIDmode,
4289132718Skan					       gen_rtx_REG (mode,
4290132718Skan							    cum->fregno),
4291132718Skan					       const0_rtx)));
4292132718Skan
4293132718Skan      /* split a DFmode arg into two GPRs */
4294132718Skan      return gen_rtx_PARALLEL (DFmode,
4295132718Skan	       gen_rtvec (3,
4296132718Skan			  gen_rtx_EXPR_LIST (VOIDmode,
4297132718Skan					     gen_rtx_REG (SImode,
4298132718Skan							  GP_ARG_MIN_REG
4299132718Skan							  + align_words),
4300132718Skan					     const0_rtx),
4301132718Skan			  gen_rtx_EXPR_LIST (VOIDmode,
4302132718Skan					     gen_rtx_REG (SImode,
4303132718Skan							  GP_ARG_MIN_REG
4304132718Skan							  + align_words + 1),
4305132718Skan					     GEN_INT (4)),
4306132718Skan			  gen_rtx_EXPR_LIST (VOIDmode,
4307132718Skan					     gen_rtx_REG (mode, cum->fregno),
4308132718Skan					     const0_rtx)));
4309132718Skan    }
4310132718Skan  /* -mpowerpc64 with 32bit ABI splits up a DImode argument into one
4311132718Skan     or two GPRs */
4312132718Skan  else if (mode == DImode)
4313132718Skan    {
4314132718Skan      if (align_words < GP_ARG_NUM_REG - 1)
4315132718Skan	return gen_rtx_PARALLEL (DImode,
4316132718Skan		 gen_rtvec (2,
4317132718Skan			    gen_rtx_EXPR_LIST (VOIDmode,
4318132718Skan					       gen_rtx_REG (SImode,
4319132718Skan							    GP_ARG_MIN_REG
4320132718Skan							    + align_words),
4321132718Skan					       const0_rtx),
4322132718Skan			    gen_rtx_EXPR_LIST (VOIDmode,
4323132718Skan					       gen_rtx_REG (SImode,
4324132718Skan							    GP_ARG_MIN_REG
4325132718Skan							    + align_words + 1),
4326132718Skan					       GEN_INT (4))));
4327132718Skan      else if (align_words == GP_ARG_NUM_REG - 1)
4328132718Skan	  return gen_rtx_PARALLEL (DImode,
4329132718Skan		   gen_rtvec (2,
4330132718Skan			      gen_rtx_EXPR_LIST (VOIDmode,
4331132718Skan						 NULL_RTX, const0_rtx),
4332132718Skan			      gen_rtx_EXPR_LIST (VOIDmode,
4333132718Skan						 gen_rtx_REG (SImode,
4334132718Skan							      GP_ARG_MIN_REG
4335132718Skan							      + align_words),
4336132718Skan						 const0_rtx)));
4337132718Skan    }
4338132718Skan  else if (mode == BLKmode && align_words <= (GP_ARG_NUM_REG - 1))
4339132718Skan    {
4340132718Skan      int k;
4341132718Skan      int size = int_size_in_bytes (type);
4342132718Skan      int no_units = ((size - 1) / 4) + 1;
4343132718Skan      int max_no_words = GP_ARG_NUM_REG - align_words;
4344132718Skan      int rtlvec_len = no_units < max_no_words ? no_units : max_no_words;
4345132718Skan      rtx *rtlvec = (rtx *) alloca (rtlvec_len * sizeof (rtx));
4346132718Skan
4347132718Skan      memset ((char *) rtlvec, 0, rtlvec_len * sizeof (rtx));
4348132718Skan
4349132718Skan      for (k=0; k < rtlvec_len; k++)
4350132718Skan	rtlvec[k] = gen_rtx_EXPR_LIST (VOIDmode,
4351132718Skan				       gen_rtx_REG (SImode,
4352132718Skan						    GP_ARG_MIN_REG
4353132718Skan						    + align_words + k),
4354132718Skan				       k == 0 ? const0_rtx : GEN_INT (k*4));
4355132718Skan
4356132718Skan      return gen_rtx_PARALLEL (BLKmode, gen_rtvec_v (k, rtlvec));
4357132718Skan  }
4358132718Skan
4359132718Skan  return NULL_RTX;
4360132718Skan}
4361132718Skan
436290075Sobrien/* Determine where to put an argument to a function.
436390075Sobrien   Value is zero to push the argument on the stack,
436490075Sobrien   or a hard register in which to store the argument.
436590075Sobrien
436690075Sobrien   MODE is the argument's machine mode.
436790075Sobrien   TYPE is the data type of the argument (as a tree).
436890075Sobrien    This is null for libcalls where that information may
436990075Sobrien    not be available.
437090075Sobrien   CUM is a variable of type CUMULATIVE_ARGS which gives info about
437190075Sobrien    the preceding args and about the function being called.
437290075Sobrien   NAMED is nonzero if this argument is a named parameter
437390075Sobrien    (otherwise it is an extra parameter matching an ellipsis).
437490075Sobrien
437590075Sobrien   On RS/6000 the first eight words of non-FP are normally in registers
437690075Sobrien   and the rest are pushed.  Under AIX, the first 13 FP args are in registers.
437790075Sobrien   Under V.4, the first 8 FP args are in registers.
437890075Sobrien
437990075Sobrien   If this is floating-point and no prototype is specified, we use
438090075Sobrien   both an FP and integer register (or possibly FP reg and stack).  Library
4381117395Skan   functions (when CALL_LIBCALL is set) always have the proper types for args,
438290075Sobrien   so we can pass the FP value just in one register.  emit_library_function
4383132718Skan   doesn't support PARALLEL anyway.
438490075Sobrien
4385132718Skan   Note that for args passed by reference, function_arg will be called
4386132718Skan   with MODE and TYPE set to that of the pointer to the arg, not the arg
4387132718Skan   itself.  */
4388132718Skan
438990075Sobrienstruct rtx_def *
4390132718Skanfunction_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
4391132718Skan	      tree type, int named)
439290075Sobrien{
439390075Sobrien  enum rs6000_abi abi = DEFAULT_ABI;
439490075Sobrien
439590075Sobrien  /* Return a marker to indicate whether CR1 needs to set or clear the
439690075Sobrien     bit that V.4 uses to say fp args were passed in registers.
439790075Sobrien     Assume that we don't need the marker for software floating point,
439890075Sobrien     or compiler generated library calls.  */
439990075Sobrien  if (mode == VOIDmode)
440090075Sobrien    {
440190075Sobrien      if (abi == ABI_V4
440290075Sobrien	  && cum->nargs_prototype < 0
4403117395Skan	  && (cum->call_cookie & CALL_LIBCALL) == 0
4404117395Skan	  && (cum->prototype || TARGET_NO_PROTOTYPE))
440590075Sobrien	{
4406117395Skan	  /* For the SPE, we need to crxor CR6 always.  */
4407117395Skan	  if (TARGET_SPE_ABI)
4408117395Skan	    return GEN_INT (cum->call_cookie | CALL_V4_SET_FP_ARGS);
4409117395Skan	  else if (TARGET_HARD_FLOAT && TARGET_FPRS)
4410117395Skan	    return GEN_INT (cum->call_cookie
4411117395Skan			    | ((cum->fregno == FP_ARG_MIN_REG)
4412117395Skan			       ? CALL_V4_SET_FP_ARGS
4413117395Skan			       : CALL_V4_CLEAR_FP_ARGS));
441490075Sobrien	}
441590075Sobrien
441690075Sobrien      return GEN_INT (cum->call_cookie);
441790075Sobrien    }
441890075Sobrien
4419132718Skan  if (USE_ALTIVEC_FOR_ARG_P (cum, mode, type, named))
4420132718Skan    if (TARGET_64BIT && ! cum->prototype)
4421132718Skan      {
4422132718Skan       /* Vector parameters get passed in vector register
4423132718Skan          and also in GPRs or memory, in absence of prototype.  */
4424132718Skan       int align_words;
4425132718Skan       rtx slot;
4426132718Skan       align_words = (cum->words + 1) & ~1;
4427132718Skan
4428132718Skan       if (align_words >= GP_ARG_NUM_REG)
4429132718Skan         {
4430132718Skan           slot = NULL_RTX;
4431132718Skan         }
4432132718Skan       else
4433132718Skan         {
4434132718Skan           slot = gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
4435132718Skan         }
4436132718Skan       return gen_rtx_PARALLEL (mode,
4437132718Skan                gen_rtvec (2,
4438132718Skan                           gen_rtx_EXPR_LIST (VOIDmode,
4439132718Skan                                              slot, const0_rtx),
4440132718Skan                           gen_rtx_EXPR_LIST (VOIDmode,
4441132718Skan                                              gen_rtx_REG (mode, cum->vregno),
4442132718Skan                                              const0_rtx)));
4443132718Skan      }
4444132718Skan    else
4445132718Skan      return gen_rtx_REG (mode, cum->vregno);
4446132718Skan  else if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
444790075Sobrien    {
4448132718Skan      if (named || abi == ABI_V4)
4449132718Skan	return NULL_RTX;
445090075Sobrien      else
4451132718Skan	{
4452132718Skan	  /* Vector parameters to varargs functions under AIX or Darwin
4453132718Skan	     get passed in memory and possibly also in GPRs.  */
4454132718Skan	  int align, align_words;
4455132718Skan	  enum machine_mode part_mode = mode;
4456132718Skan
4457132718Skan	  /* Vector parameters must be 16-byte aligned.  This places them at
4458132718Skan	     2 mod 4 in terms of words in 32-bit mode, since the parameter
4459132718Skan	     save area starts at offset 24 from the stack.  In 64-bit mode,
4460132718Skan	     they just have to start on an even word, since the parameter
4461132718Skan	     save area is 16-byte aligned.  */
4462132718Skan	  if (TARGET_32BIT)
4463132718Skan	    align = (2 - cum->words) & 3;
4464132718Skan	  else
4465132718Skan	    align = cum->words & 1;
4466132718Skan	  align_words = cum->words + align;
4467132718Skan
4468132718Skan	  /* Out of registers?  Memory, then.  */
4469132718Skan	  if (align_words >= GP_ARG_NUM_REG)
4470132718Skan	    return NULL_RTX;
4471132718Skan
4472132718Skan	  /* The vector value goes in GPRs.  Only the part of the
4473132718Skan	     value in GPRs is reported here.  */
4474132718Skan	  if (align_words + CLASS_MAX_NREGS (mode, GENERAL_REGS)
4475132718Skan	      > GP_ARG_NUM_REG)
4476132718Skan	    /* Fortunately, there are only two possibilities, the value
4477132718Skan	       is either wholly in GPRs or half in GPRs and half not.  */
4478132718Skan	    part_mode = DImode;
4479132718Skan
4480132718Skan	  return gen_rtx_REG (part_mode, GP_ARG_MIN_REG + align_words);
4481132718Skan	}
448290075Sobrien    }
4483132718Skan  else if (TARGET_SPE_ABI && TARGET_SPE && SPE_VECTOR_MODE (mode))
4484132718Skan    return rs6000_spe_function_arg (cum, mode, type);
448590075Sobrien  else if (abi == ABI_V4)
448690075Sobrien    {
4487117395Skan      if (TARGET_HARD_FLOAT && TARGET_FPRS
448890075Sobrien	  && (mode == SFmode || mode == DFmode))
448990075Sobrien	{
449090075Sobrien	  if (cum->fregno <= FP_ARG_V4_MAX_REG)
449190075Sobrien	    return gen_rtx_REG (mode, cum->fregno);
449290075Sobrien	  else
4493132718Skan	    return NULL_RTX;
449490075Sobrien	}
449590075Sobrien      else
449690075Sobrien	{
4497132718Skan	  int n_words = rs6000_arg_size (mode, type);
449890075Sobrien	  int gregno = cum->sysv_gregno;
449990075Sobrien
4500132718Skan	  /* Long long and SPE vectors are put in (r3,r4), (r5,r6),
4501132718Skan	     (r7,r8) or (r9,r10).  As does any other 2 word item such
4502132718Skan	     as complex int due to a historical mistake.  */
4503132718Skan	  if (n_words == 2)
4504132718Skan	    gregno += (1 - gregno) & 1;
450590075Sobrien
4506132718Skan	  /* Multi-reg args are not split between registers and stack.  */
450790075Sobrien	  if (gregno + n_words - 1 <= GP_ARG_MAX_REG)
4508132718Skan	    return gen_rtx_REG (mode, gregno);
450990075Sobrien	  else
4510132718Skan	    return NULL_RTX;
451190075Sobrien	}
451290075Sobrien    }
451390075Sobrien  else
451490075Sobrien    {
4515132718Skan      int align = function_arg_boundary (mode, type) / PARM_BOUNDARY - 1;
4516132718Skan      int align_words = cum->words + (cum->words & align);
451790075Sobrien
4518132718Skan      if (USE_FP_FOR_ARG_P (cum, mode, type))
4519132718Skan	{
4520132718Skan	  rtx fpr[2];
4521132718Skan	  rtx *r;
4522132718Skan	  bool needs_psave;
4523132718Skan	  enum machine_mode fmode = mode;
4524132718Skan	  int n;
4525132718Skan	  unsigned long n_fpreg = (GET_MODE_SIZE (mode) + 7) >> 3;
452690075Sobrien
4527132718Skan	  if (cum->fregno + n_fpreg > FP_ARG_MAX_REG + 1)
4528132718Skan	    {
4529132718Skan	      /* Long double split over regs and memory.  */
4530132718Skan	      if (fmode == TFmode)
4531132718Skan		fmode = DFmode;
4532132718Skan
4533132718Skan	      /* Currently, we only ever need one reg here because complex
4534132718Skan		 doubles are split.  */
4535132718Skan	      if (cum->fregno != FP_ARG_MAX_REG - 1)
4536132718Skan		abort ();
4537132718Skan	    }
4538132718Skan	  fpr[1] = gen_rtx_REG (fmode, cum->fregno);
4539132718Skan
4540132718Skan	  /* Do we also need to pass this arg in the parameter save
4541132718Skan	     area?  */
4542132718Skan	  needs_psave = (type
4543132718Skan			 && (cum->nargs_prototype <= 0
4544132718Skan			     || (DEFAULT_ABI == ABI_AIX
4545132718Skan				 && TARGET_XL_CALL
4546132718Skan				 && align_words >= GP_ARG_NUM_REG)));
4547132718Skan
4548132718Skan	  if (!needs_psave && mode == fmode)
4549132718Skan	    return fpr[1];
4550132718Skan
4551132718Skan          if (TARGET_32BIT && TARGET_POWERPC64
4552132718Skan              && mode == DFmode && cum->stdarg)
4553132718Skan            return rs6000_mixed_function_arg (cum, mode, type, align_words);
4554132718Skan
4555132718Skan	  /* Describe where this piece goes.  */
4556132718Skan	  r = fpr + 1;
4557132718Skan	  *r = gen_rtx_EXPR_LIST (VOIDmode, *r, const0_rtx);
4558132718Skan	  n = 1;
4559132718Skan
4560132718Skan	  if (needs_psave)
4561132718Skan	    {
4562132718Skan	      /* Now describe the part that goes in gprs or the stack.
4563132718Skan		 This piece must come first, before the fprs.  */
4564132718Skan	      rtx reg = NULL_RTX;
4565132718Skan	      if (align_words < GP_ARG_NUM_REG)
4566132718Skan		{
4567132718Skan		  unsigned long n_words = rs6000_arg_size (mode, type);
4568132718Skan		  enum machine_mode rmode = mode;
4569132718Skan
4570132718Skan		  if (align_words + n_words > GP_ARG_NUM_REG)
4571132718Skan		    /* If this is partially on the stack, then we only
4572132718Skan		       include the portion actually in registers here.
4573132718Skan		       We know this can only be one register because
4574132718Skan		       complex doubles are splt.  */
4575132718Skan		    rmode = Pmode;
4576132718Skan		  reg = gen_rtx_REG (rmode, GP_ARG_MIN_REG + align_words);
4577132718Skan		}
4578132718Skan	      *--r = gen_rtx_EXPR_LIST (VOIDmode, reg, const0_rtx);
4579132718Skan	      ++n;
4580132718Skan	    }
4581132718Skan
4582132718Skan	  return gen_rtx_PARALLEL (mode, gen_rtvec_v (n, r));
4583132718Skan	}
4584132718Skan      else if (align_words < GP_ARG_NUM_REG)
458590075Sobrien	{
4586132718Skan	  if (TARGET_32BIT && TARGET_POWERPC64
4587132718Skan	      && (mode == DImode || mode == BLKmode))
4588132718Skan	    return rs6000_mixed_function_arg (cum, mode, type, align_words);
458990075Sobrien
4590132718Skan	  return gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
459190075Sobrien	}
459290075Sobrien      else
459390075Sobrien	return NULL_RTX;
459490075Sobrien    }
459590075Sobrien}
459690075Sobrien
459790075Sobrien/* For an arg passed partly in registers and partly in memory,
459890075Sobrien   this is the number of registers used.
459990075Sobrien   For args passed entirely in registers or entirely in memory, zero.  */
460090075Sobrien
460190075Sobrienint
4602132718Skanfunction_arg_partial_nregs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
4603132718Skan			    tree type, int named)
460490075Sobrien{
4605132718Skan  int ret = 0;
4606132718Skan
460790075Sobrien  if (DEFAULT_ABI == ABI_V4)
460890075Sobrien    return 0;
460990075Sobrien
4610132718Skan  if (USE_ALTIVEC_FOR_ARG_P (cum, mode, type, named)
4611132718Skan      && cum->nargs_prototype >= 0)
4612132718Skan    return 0;
4613132718Skan
4614132718Skan  if (USE_FP_FOR_ARG_P (cum, mode, type))
461590075Sobrien    {
4616132718Skan      if (cum->fregno + ((GET_MODE_SIZE (mode) + 7) >> 3) > FP_ARG_MAX_REG + 1)
4617132718Skan	ret = FP_ARG_MAX_REG - cum->fregno;
4618132718Skan      else if (cum->nargs_prototype >= 0)
461990075Sobrien	return 0;
462090075Sobrien    }
462190075Sobrien
462290075Sobrien  if (cum->words < GP_ARG_NUM_REG
4623132718Skan      && GP_ARG_NUM_REG < cum->words + rs6000_arg_size (mode, type))
4624132718Skan    ret = GP_ARG_NUM_REG - cum->words;
462590075Sobrien
4626132718Skan  if (ret != 0 && TARGET_DEBUG_ARG)
4627132718Skan    fprintf (stderr, "function_arg_partial_nregs: %d\n", ret);
462890075Sobrien
4629132718Skan  return ret;
463090075Sobrien}
463190075Sobrien
463290075Sobrien/* A C expression that indicates when an argument must be passed by
463390075Sobrien   reference.  If nonzero for an argument, a copy of that argument is
463490075Sobrien   made in memory and a pointer to the argument is passed instead of
463590075Sobrien   the argument itself.  The pointer is passed in whatever way is
463690075Sobrien   appropriate for passing a pointer to that type.
463790075Sobrien
4638132718Skan   Under V.4, aggregates and long double are passed by reference.
463990075Sobrien
4640132718Skan   As an extension to all 32-bit ABIs, AltiVec vectors are passed by
4641132718Skan   reference unless the AltiVec vector extension ABI is in force.
4642132718Skan
4643117395Skan   As an extension to all ABIs, variable sized types are passed by
4644117395Skan   reference.  */
4645117395Skan
464690075Sobrienint
4647132718Skanfunction_arg_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
4648132718Skan				enum machine_mode mode ATTRIBUTE_UNUSED,
4649132718Skan				tree type, int named ATTRIBUTE_UNUSED)
465090075Sobrien{
4651132718Skan  if ((DEFAULT_ABI == ABI_V4
4652132718Skan       && ((type && AGGREGATE_TYPE_P (type))
4653132718Skan	   || mode == TFmode))
4654132718Skan      || (TARGET_32BIT && !TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
4655132718Skan      || (type && int_size_in_bytes (type) < 0))
465690075Sobrien    {
465790075Sobrien      if (TARGET_DEBUG_ARG)
4658132718Skan	fprintf (stderr, "function_arg_pass_by_reference\n");
465990075Sobrien
466090075Sobrien      return 1;
466190075Sobrien    }
4662132718Skan  return 0;
466390075Sobrien}
4664132718Skan
4665132718Skanstatic void
4666132718Skanrs6000_move_block_from_reg (int regno, rtx x, int nregs)
4667132718Skan{
4668132718Skan  int i;
4669132718Skan  enum machine_mode reg_mode = TARGET_32BIT ? SImode : DImode;
4670132718Skan
4671132718Skan  if (nregs == 0)
4672132718Skan    return;
4673132718Skan
4674132718Skan    for (i = 0; i < nregs; i++)
4675132718Skan    {
4676132718Skan      rtx tem = adjust_address_nv (x, reg_mode, i*GET_MODE_SIZE(reg_mode));
4677132718Skan      if (reload_completed)
4678132718Skan      {
4679132718Skan	if (! strict_memory_address_p (reg_mode, XEXP (tem, 0)))
4680132718Skan	  tem = NULL_RTX;
4681132718Skan	else
4682132718Skan	  tem = simplify_gen_subreg (reg_mode, x, BLKmode,
4683132718Skan				     i * GET_MODE_SIZE(reg_mode));
4684132718Skan      }
4685132718Skan      else
4686132718Skan	tem = replace_equiv_address (tem, XEXP (tem, 0));
4687132718Skan
4688132718Skan      if (tem == NULL_RTX)
4689132718Skan        abort ();
4690132718Skan
4691132718Skan      emit_move_insn (tem, gen_rtx_REG (reg_mode, regno + i));
4692132718Skan    }
4693132718Skan}
4694132718Skan
469590075Sobrien
469690075Sobrien/* Perform any needed actions needed for a function that is receiving a
469790075Sobrien   variable number of arguments.
469890075Sobrien
469990075Sobrien   CUM is as above.
470090075Sobrien
470190075Sobrien   MODE and TYPE are the mode and type of the current parameter.
470290075Sobrien
470390075Sobrien   PRETEND_SIZE is a variable that should be set to the amount of stack
470490075Sobrien   that must be pushed by the prolog to pretend that our caller pushed
470590075Sobrien   it.
470690075Sobrien
470790075Sobrien   Normally, this macro will push all remaining incoming registers on the
470890075Sobrien   stack and set PRETEND_SIZE to the length of the registers pushed.  */
470990075Sobrien
4710132718Skanstatic void
4711132718Skansetup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
4712132718Skan		tree type, int *pretend_size ATTRIBUTE_UNUSED, int no_rtl)
471390075Sobrien{
471490075Sobrien  CUMULATIVE_ARGS next_cum;
471590075Sobrien  int reg_size = TARGET_32BIT ? 4 : 8;
471690075Sobrien  rtx save_area = NULL_RTX, mem;
471790075Sobrien  int first_reg_offset, set;
471890075Sobrien
4719132718Skan  /* Skip the last named argument.  */
472090075Sobrien  next_cum = *cum;
4721132718Skan  function_arg_advance (&next_cum, mode, type, 1);
472290075Sobrien
472390075Sobrien  if (DEFAULT_ABI == ABI_V4)
472490075Sobrien    {
472590075Sobrien      /* Indicate to allocate space on the stack for varargs save area.  */
472690075Sobrien      cfun->machine->sysv_varargs_p = 1;
472790075Sobrien      if (! no_rtl)
472890075Sobrien	save_area = plus_constant (virtual_stack_vars_rtx,
472990075Sobrien				   - RS6000_VARARGS_SIZE);
473090075Sobrien
473190075Sobrien      first_reg_offset = next_cum.sysv_gregno - GP_ARG_MIN_REG;
473290075Sobrien    }
473390075Sobrien  else
473490075Sobrien    {
473590075Sobrien      first_reg_offset = next_cum.words;
473690075Sobrien      save_area = virtual_incoming_args_rtx;
473790075Sobrien      cfun->machine->sysv_varargs_p = 0;
473890075Sobrien
473990075Sobrien      if (MUST_PASS_IN_STACK (mode, type))
4740132718Skan	first_reg_offset += rs6000_arg_size (TYPE_MODE (type), type);
474190075Sobrien    }
474290075Sobrien
474390075Sobrien  set = get_varargs_alias_set ();
474490075Sobrien  if (! no_rtl && first_reg_offset < GP_ARG_NUM_REG)
474590075Sobrien    {
474690075Sobrien      mem = gen_rtx_MEM (BLKmode,
474790075Sobrien		         plus_constant (save_area,
474890075Sobrien					first_reg_offset * reg_size)),
474990075Sobrien      set_mem_alias_set (mem, set);
475090075Sobrien      set_mem_align (mem, BITS_PER_WORD);
475190075Sobrien
4752132718Skan      rs6000_move_block_from_reg (GP_ARG_MIN_REG + first_reg_offset, mem,
4753132718Skan			          GP_ARG_NUM_REG - first_reg_offset);
475490075Sobrien    }
475590075Sobrien
475690075Sobrien  /* Save FP registers if needed.  */
475790075Sobrien  if (DEFAULT_ABI == ABI_V4
4758117395Skan      && TARGET_HARD_FLOAT && TARGET_FPRS
4759117395Skan      && ! no_rtl
476090075Sobrien      && next_cum.fregno <= FP_ARG_V4_MAX_REG)
476190075Sobrien    {
476290075Sobrien      int fregno = next_cum.fregno;
476390075Sobrien      rtx cr1 = gen_rtx_REG (CCmode, CR1_REGNO);
476490075Sobrien      rtx lab = gen_label_rtx ();
476590075Sobrien      int off = (GP_ARG_NUM_REG * reg_size) + ((fregno - FP_ARG_MIN_REG) * 8);
476690075Sobrien
476790075Sobrien      emit_jump_insn (gen_rtx_SET (VOIDmode,
476890075Sobrien				   pc_rtx,
476990075Sobrien				   gen_rtx_IF_THEN_ELSE (VOIDmode,
477090075Sobrien					    gen_rtx_NE (VOIDmode, cr1,
477190075Sobrien						        const0_rtx),
477290075Sobrien					    gen_rtx_LABEL_REF (VOIDmode, lab),
477390075Sobrien					    pc_rtx)));
477490075Sobrien
477590075Sobrien      while (fregno <= FP_ARG_V4_MAX_REG)
477690075Sobrien	{
477790075Sobrien	  mem = gen_rtx_MEM (DFmode, plus_constant (save_area, off));
477890075Sobrien          set_mem_alias_set (mem, set);
477990075Sobrien	  emit_move_insn (mem, gen_rtx_REG (DFmode, fregno));
478090075Sobrien	  fregno++;
478190075Sobrien	  off += 8;
478290075Sobrien	}
478390075Sobrien
478490075Sobrien      emit_label (lab);
478590075Sobrien    }
478690075Sobrien}
478790075Sobrien
478890075Sobrien/* Create the va_list data type.  */
478990075Sobrien
4790132718Skanstatic tree
4791132718Skanrs6000_build_builtin_va_list (void)
479290075Sobrien{
4793132718Skan  tree f_gpr, f_fpr, f_res, f_ovf, f_sav, record, type_decl;
479490075Sobrien
479590075Sobrien  /* For AIX, prefer 'char *' because that's what the system
479690075Sobrien     header files like.  */
479790075Sobrien  if (DEFAULT_ABI != ABI_V4)
479890075Sobrien    return build_pointer_type (char_type_node);
479990075Sobrien
4800117395Skan  record = (*lang_hooks.types.make_type) (RECORD_TYPE);
480190075Sobrien  type_decl = build_decl (TYPE_DECL, get_identifier ("__va_list_tag"), record);
480290075Sobrien
480390075Sobrien  f_gpr = build_decl (FIELD_DECL, get_identifier ("gpr"),
480490075Sobrien		      unsigned_char_type_node);
480590075Sobrien  f_fpr = build_decl (FIELD_DECL, get_identifier ("fpr"),
480690075Sobrien		      unsigned_char_type_node);
4807132718Skan  /* Give the two bytes of padding a name, so that -Wpadded won't warn on
4808132718Skan     every user file.  */
4809132718Skan  f_res = build_decl (FIELD_DECL, get_identifier ("reserved"),
4810132718Skan		      short_unsigned_type_node);
481190075Sobrien  f_ovf = build_decl (FIELD_DECL, get_identifier ("overflow_arg_area"),
481290075Sobrien		      ptr_type_node);
481390075Sobrien  f_sav = build_decl (FIELD_DECL, get_identifier ("reg_save_area"),
481490075Sobrien		      ptr_type_node);
481590075Sobrien
481690075Sobrien  DECL_FIELD_CONTEXT (f_gpr) = record;
481790075Sobrien  DECL_FIELD_CONTEXT (f_fpr) = record;
4818132718Skan  DECL_FIELD_CONTEXT (f_res) = record;
481990075Sobrien  DECL_FIELD_CONTEXT (f_ovf) = record;
482090075Sobrien  DECL_FIELD_CONTEXT (f_sav) = record;
482190075Sobrien
482290075Sobrien  TREE_CHAIN (record) = type_decl;
482390075Sobrien  TYPE_NAME (record) = type_decl;
482490075Sobrien  TYPE_FIELDS (record) = f_gpr;
482590075Sobrien  TREE_CHAIN (f_gpr) = f_fpr;
4826132718Skan  TREE_CHAIN (f_fpr) = f_res;
4827132718Skan  TREE_CHAIN (f_res) = f_ovf;
482890075Sobrien  TREE_CHAIN (f_ovf) = f_sav;
482990075Sobrien
483090075Sobrien  layout_type (record);
483190075Sobrien
483290075Sobrien  /* The correct type is an array type of one element.  */
483390075Sobrien  return build_array_type (record, build_index_type (size_zero_node));
483490075Sobrien}
483590075Sobrien
483690075Sobrien/* Implement va_start.  */
483790075Sobrien
483890075Sobrienvoid
4839132718Skanrs6000_va_start (tree valist, rtx nextarg)
484090075Sobrien{
484190075Sobrien  HOST_WIDE_INT words, n_gpr, n_fpr;
4842132718Skan  tree f_gpr, f_fpr, f_res, f_ovf, f_sav;
484390075Sobrien  tree gpr, fpr, ovf, sav, t;
484490075Sobrien
484590075Sobrien  /* Only SVR4 needs something special.  */
484690075Sobrien  if (DEFAULT_ABI != ABI_V4)
484790075Sobrien    {
4848117395Skan      std_expand_builtin_va_start (valist, nextarg);
484990075Sobrien      return;
485090075Sobrien    }
485190075Sobrien
485290075Sobrien  f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
485390075Sobrien  f_fpr = TREE_CHAIN (f_gpr);
4854132718Skan  f_res = TREE_CHAIN (f_fpr);
4855132718Skan  f_ovf = TREE_CHAIN (f_res);
485690075Sobrien  f_sav = TREE_CHAIN (f_ovf);
485790075Sobrien
485890075Sobrien  valist = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)), valist);
485990075Sobrien  gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
486090075Sobrien  fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
486190075Sobrien  ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf);
486290075Sobrien  sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav);
486390075Sobrien
486490075Sobrien  /* Count number of gp and fp argument registers used.  */
486590075Sobrien  words = current_function_args_info.words;
486690075Sobrien  n_gpr = current_function_args_info.sysv_gregno - GP_ARG_MIN_REG;
486790075Sobrien  n_fpr = current_function_args_info.fregno - FP_ARG_MIN_REG;
486890075Sobrien
486990075Sobrien  if (TARGET_DEBUG_ARG)
4870132718Skan    fprintf (stderr, "va_start: words = "HOST_WIDE_INT_PRINT_DEC", n_gpr = "
4871132718Skan	     HOST_WIDE_INT_PRINT_DEC", n_fpr = "HOST_WIDE_INT_PRINT_DEC"\n",
4872132718Skan	     words, n_gpr, n_fpr);
487390075Sobrien
487490075Sobrien  t = build (MODIFY_EXPR, TREE_TYPE (gpr), gpr, build_int_2 (n_gpr, 0));
487590075Sobrien  TREE_SIDE_EFFECTS (t) = 1;
487690075Sobrien  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
487790075Sobrien
487890075Sobrien  t = build (MODIFY_EXPR, TREE_TYPE (fpr), fpr, build_int_2 (n_fpr, 0));
487990075Sobrien  TREE_SIDE_EFFECTS (t) = 1;
488090075Sobrien  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
488190075Sobrien
488290075Sobrien  /* Find the overflow area.  */
488390075Sobrien  t = make_tree (TREE_TYPE (ovf), virtual_incoming_args_rtx);
488490075Sobrien  if (words != 0)
488590075Sobrien    t = build (PLUS_EXPR, TREE_TYPE (ovf), t,
488690075Sobrien	       build_int_2 (words * UNITS_PER_WORD, 0));
488790075Sobrien  t = build (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t);
488890075Sobrien  TREE_SIDE_EFFECTS (t) = 1;
488990075Sobrien  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
489090075Sobrien
489190075Sobrien  /* Find the register save area.  */
489290075Sobrien  t = make_tree (TREE_TYPE (sav), virtual_stack_vars_rtx);
489390075Sobrien  t = build (PLUS_EXPR, TREE_TYPE (sav), t,
489490075Sobrien	     build_int_2 (-RS6000_VARARGS_SIZE, -1));
489590075Sobrien  t = build (MODIFY_EXPR, TREE_TYPE (sav), sav, t);
489690075Sobrien  TREE_SIDE_EFFECTS (t) = 1;
489790075Sobrien  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
489890075Sobrien}
489990075Sobrien
490090075Sobrien/* Implement va_arg.  */
490190075Sobrien
490290075Sobrienrtx
4903132718Skanrs6000_va_arg (tree valist, tree type)
490490075Sobrien{
4905132718Skan  tree f_gpr, f_fpr, f_res, f_ovf, f_sav;
490690075Sobrien  tree gpr, fpr, ovf, sav, reg, t, u;
490790075Sobrien  int indirect_p, size, rsize, n_reg, sav_ofs, sav_scale;
490890075Sobrien  rtx lab_false, lab_over, addr_rtx, r;
4909132718Skan  int align;
491090075Sobrien
491190075Sobrien  if (DEFAULT_ABI != ABI_V4)
4912117395Skan    {
4913132718Skan      /* Variable sized types are passed by reference, as are AltiVec
4914132718Skan	 vectors when 32-bit and not using the AltiVec ABI extension.  */
4915132718Skan      if (int_size_in_bytes (type) < 0
4916132718Skan	  || (TARGET_32BIT
4917132718Skan	      && !TARGET_ALTIVEC_ABI
4918132718Skan	      && ALTIVEC_VECTOR_MODE (TYPE_MODE (type))))
4919117395Skan	{
4920117395Skan	  u = build_pointer_type (type);
492190075Sobrien
4922117395Skan	  /* Args grow upward.  */
4923117395Skan	  t = build (POSTINCREMENT_EXPR, TREE_TYPE (valist), valist,
4924117395Skan		     build_int_2 (POINTER_SIZE / BITS_PER_UNIT, 0));
4925117395Skan	  TREE_SIDE_EFFECTS (t) = 1;
4926117395Skan
4927117395Skan	  t = build1 (NOP_EXPR, build_pointer_type (u), t);
4928117395Skan	  TREE_SIDE_EFFECTS (t) = 1;
4929117395Skan
4930117395Skan	  t = build1 (INDIRECT_REF, u, t);
4931117395Skan	  TREE_SIDE_EFFECTS (t) = 1;
4932117395Skan
4933117395Skan	  return expand_expr (t, NULL_RTX, VOIDmode, EXPAND_NORMAL);
4934117395Skan	}
4935132718Skan      if (targetm.calls.split_complex_arg
4936132718Skan	  && TREE_CODE (type) == COMPLEX_TYPE)
4937132718Skan	{
4938132718Skan	  tree elem_type = TREE_TYPE (type);
4939132718Skan	  enum machine_mode elem_mode = TYPE_MODE (elem_type);
4940132718Skan	  int elem_size = GET_MODE_SIZE (elem_mode);
4941132718Skan
4942132718Skan	  if (elem_size < UNITS_PER_WORD)
4943132718Skan	    {
4944132718Skan	      rtx real_part, imag_part, dest_real, rr;
4945132718Skan
4946132718Skan	      real_part = rs6000_va_arg (valist, elem_type);
4947132718Skan	      imag_part = rs6000_va_arg (valist, elem_type);
4948132718Skan
4949132718Skan	      /* We're not returning the value here, but the address.
4950132718Skan		 real_part and imag_part are not contiguous, and we know
4951132718Skan		 there is space available to pack real_part next to
4952132718Skan		 imag_part.  float _Complex is not promoted to
4953132718Skan		 double _Complex by the default promotion rules that
4954132718Skan		 promote float to double.  */
4955132718Skan	      if (2 * elem_size > UNITS_PER_WORD)
4956132718Skan		abort ();
4957132718Skan
4958132718Skan	      real_part = gen_rtx_MEM (elem_mode, real_part);
4959132718Skan	      imag_part = gen_rtx_MEM (elem_mode, imag_part);
4960132718Skan
4961132718Skan	      dest_real = adjust_address (imag_part, elem_mode, -elem_size);
4962132718Skan	      rr = gen_reg_rtx (elem_mode);
4963132718Skan	      emit_move_insn (rr, real_part);
4964132718Skan	      emit_move_insn (dest_real, rr);
4965132718Skan
4966132718Skan	      return XEXP (dest_real, 0);
4967132718Skan	    }
4968132718Skan	}
4969132718Skan
4970132718Skan      return std_expand_builtin_va_arg (valist, type);
4971117395Skan    }
4972117395Skan
497390075Sobrien  f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
497490075Sobrien  f_fpr = TREE_CHAIN (f_gpr);
4975132718Skan  f_res = TREE_CHAIN (f_fpr);
4976132718Skan  f_ovf = TREE_CHAIN (f_res);
497790075Sobrien  f_sav = TREE_CHAIN (f_ovf);
497890075Sobrien
497990075Sobrien  valist = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)), valist);
498090075Sobrien  gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
498190075Sobrien  fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
498290075Sobrien  ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf);
498390075Sobrien  sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav);
498490075Sobrien
498590075Sobrien  size = int_size_in_bytes (type);
4986132718Skan  rsize = (size + 3) / 4;
4987132718Skan  align = 1;
498890075Sobrien
4989132718Skan  if (AGGREGATE_TYPE_P (type)
4990132718Skan      || TYPE_MODE (type) == TFmode
4991132718Skan      || (!TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (TYPE_MODE (type))))
499290075Sobrien    {
4993132718Skan      /* Aggregates, long doubles, and AltiVec vectors are passed by
4994132718Skan	 reference.  */
499590075Sobrien      indirect_p = 1;
499690075Sobrien      reg = gpr;
499790075Sobrien      n_reg = 1;
499890075Sobrien      sav_ofs = 0;
499990075Sobrien      sav_scale = 4;
5000132718Skan      size = 4;
500196263Sobrien      rsize = 1;
500290075Sobrien    }
5003132718Skan  else if (TARGET_HARD_FLOAT && TARGET_FPRS
5004132718Skan	   && (TYPE_MODE (type) == SFmode || TYPE_MODE (type) == DFmode))
500590075Sobrien    {
500690075Sobrien      /* FP args go in FP registers, if present.  */
500790075Sobrien      indirect_p = 0;
500890075Sobrien      reg = fpr;
500990075Sobrien      n_reg = 1;
501090075Sobrien      sav_ofs = 8*4;
501190075Sobrien      sav_scale = 8;
5012132718Skan      if (TYPE_MODE (type) == DFmode)
5013132718Skan	align = 8;
501490075Sobrien    }
501590075Sobrien  else
501690075Sobrien    {
501790075Sobrien      /* Otherwise into GP registers.  */
501890075Sobrien      indirect_p = 0;
501990075Sobrien      reg = gpr;
502090075Sobrien      n_reg = rsize;
502190075Sobrien      sav_ofs = 0;
502290075Sobrien      sav_scale = 4;
5023132718Skan      if (n_reg == 2)
5024132718Skan	align = 8;
502590075Sobrien    }
502690075Sobrien
5027132718Skan  /* Pull the value out of the saved registers....  */
502890075Sobrien
5029132718Skan  lab_over = NULL_RTX;
503090075Sobrien  addr_rtx = gen_reg_rtx (Pmode);
503190075Sobrien
5032132718Skan  /*  AltiVec vectors never go in registers when -mabi=altivec.  */
5033132718Skan  if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (TYPE_MODE (type)))
5034132718Skan    align = 16;
5035132718Skan  else
503696263Sobrien    {
5037132718Skan      lab_false = gen_label_rtx ();
5038132718Skan      lab_over = gen_label_rtx ();
503990075Sobrien
5040132718Skan      /* Long long and SPE vectors are aligned in the registers.
5041132718Skan	 As are any other 2 gpr item such as complex int due to a
5042132718Skan	 historical mistake.  */
5043132718Skan      u = reg;
5044132718Skan      if (n_reg == 2)
504596263Sobrien	{
504696263Sobrien	  u = build (BIT_AND_EXPR, TREE_TYPE (reg), reg,
504796263Sobrien		     build_int_2 (n_reg - 1, 0));
5048132718Skan	  u = build (POSTINCREMENT_EXPR, TREE_TYPE (reg), reg, u);
504996263Sobrien	  TREE_SIDE_EFFECTS (u) = 1;
505096263Sobrien	}
505196263Sobrien
5052132718Skan      emit_cmp_and_jump_insns
5053132718Skan	(expand_expr (u, NULL_RTX, QImode, EXPAND_NORMAL),
5054132718Skan	 GEN_INT (8 - n_reg + 1), GE, const1_rtx, QImode, 1,
5055132718Skan	 lab_false);
5056132718Skan
5057132718Skan      t = sav;
505896263Sobrien      if (sav_ofs)
505996263Sobrien	t = build (PLUS_EXPR, ptr_type_node, sav, build_int_2 (sav_ofs, 0));
506096263Sobrien
506196263Sobrien      u = build (POSTINCREMENT_EXPR, TREE_TYPE (reg), reg,
506296263Sobrien		 build_int_2 (n_reg, 0));
506390075Sobrien      TREE_SIDE_EFFECTS (u) = 1;
506490075Sobrien
506596263Sobrien      u = build1 (CONVERT_EXPR, integer_type_node, u);
506696263Sobrien      TREE_SIDE_EFFECTS (u) = 1;
506790075Sobrien
506896263Sobrien      u = build (MULT_EXPR, integer_type_node, u, build_int_2 (sav_scale, 0));
506996263Sobrien      TREE_SIDE_EFFECTS (u) = 1;
507090075Sobrien
507196263Sobrien      t = build (PLUS_EXPR, ptr_type_node, t, u);
507296263Sobrien      TREE_SIDE_EFFECTS (t) = 1;
507390075Sobrien
507496263Sobrien      r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
507596263Sobrien      if (r != addr_rtx)
507696263Sobrien	emit_move_insn (addr_rtx, r);
507790075Sobrien
507896263Sobrien      emit_jump_insn (gen_jump (lab_over));
507996263Sobrien      emit_barrier ();
5080132718Skan
5081132718Skan      emit_label (lab_false);
5082132718Skan      if (n_reg > 2)
5083132718Skan	{
5084132718Skan	  /* Ensure that we don't find any more args in regs.
5085132718Skan	     Alignment has taken care of the n_reg == 2 case.  */
5086132718Skan	  t = build (MODIFY_EXPR, TREE_TYPE (reg), reg, build_int_2 (8, 0));
5087132718Skan	  TREE_SIDE_EFFECTS (t) = 1;
5088132718Skan	  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
5089132718Skan	}
509096263Sobrien    }
509190075Sobrien
509290075Sobrien  /* ... otherwise out of the overflow area.  */
509390075Sobrien
509490075Sobrien  /* Care for on-stack alignment if needed.  */
5095132718Skan  t = ovf;
5096132718Skan  if (align != 1)
509790075Sobrien    {
5098132718Skan      t = build (PLUS_EXPR, TREE_TYPE (t), t, build_int_2 (align - 1, 0));
5099132718Skan      t = build (BIT_AND_EXPR, TREE_TYPE (t), t, build_int_2 (-align, -1));
510090075Sobrien    }
510190075Sobrien  t = save_expr (t);
510290075Sobrien
510390075Sobrien  r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
510490075Sobrien  if (r != addr_rtx)
510590075Sobrien    emit_move_insn (addr_rtx, r);
510690075Sobrien
510790075Sobrien  t = build (PLUS_EXPR, TREE_TYPE (t), t, build_int_2 (size, 0));
510890075Sobrien  t = build (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t);
510990075Sobrien  TREE_SIDE_EFFECTS (t) = 1;
511090075Sobrien  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
511190075Sobrien
5112132718Skan  if (lab_over)
5113132718Skan    emit_label (lab_over);
511490075Sobrien
511590075Sobrien  if (indirect_p)
511690075Sobrien    {
511790075Sobrien      r = gen_rtx_MEM (Pmode, addr_rtx);
511890075Sobrien      set_mem_alias_set (r, get_varargs_alias_set ());
511990075Sobrien      emit_move_insn (addr_rtx, r);
512090075Sobrien    }
512190075Sobrien
512290075Sobrien  return addr_rtx;
512390075Sobrien}
512490075Sobrien
512590075Sobrien/* Builtins.  */
512690075Sobrien
5127117395Skan#define def_builtin(MASK, NAME, TYPE, CODE)			\
5128117395Skando {								\
5129117395Skan  if ((MASK) & target_flags)					\
5130117395Skan    builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD,	\
5131117395Skan		      NULL, NULL_TREE);				\
513290075Sobrien} while (0)
513390075Sobrien
513490075Sobrien/* Simple ternary operations: VECd = foo (VECa, VECb, VECc).  */
513590075Sobrien
513690075Sobrienstatic const struct builtin_description bdesc_3arg[] =
513790075Sobrien{
513890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmaddfp, "__builtin_altivec_vmaddfp", ALTIVEC_BUILTIN_VMADDFP },
513990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmhaddshs, "__builtin_altivec_vmhaddshs", ALTIVEC_BUILTIN_VMHADDSHS },
514090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmhraddshs, "__builtin_altivec_vmhraddshs", ALTIVEC_BUILTIN_VMHRADDSHS },
514190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmladduhm, "__builtin_altivec_vmladduhm", ALTIVEC_BUILTIN_VMLADDUHM},
514290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmsumubm, "__builtin_altivec_vmsumubm", ALTIVEC_BUILTIN_VMSUMUBM },
514390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmsummbm, "__builtin_altivec_vmsummbm", ALTIVEC_BUILTIN_VMSUMMBM },
514490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmsumuhm, "__builtin_altivec_vmsumuhm", ALTIVEC_BUILTIN_VMSUMUHM },
514590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmsumshm, "__builtin_altivec_vmsumshm", ALTIVEC_BUILTIN_VMSUMSHM },
514690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmsumuhs, "__builtin_altivec_vmsumuhs", ALTIVEC_BUILTIN_VMSUMUHS },
514790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmsumshs, "__builtin_altivec_vmsumshs", ALTIVEC_BUILTIN_VMSUMSHS },
514890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vnmsubfp, "__builtin_altivec_vnmsubfp", ALTIVEC_BUILTIN_VNMSUBFP },
514990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vperm_4sf, "__builtin_altivec_vperm_4sf", ALTIVEC_BUILTIN_VPERM_4SF },
515090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vperm_4si, "__builtin_altivec_vperm_4si", ALTIVEC_BUILTIN_VPERM_4SI },
515190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vperm_8hi, "__builtin_altivec_vperm_8hi", ALTIVEC_BUILTIN_VPERM_8HI },
515290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vperm_16qi, "__builtin_altivec_vperm_16qi", ALTIVEC_BUILTIN_VPERM_16QI },
515390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsel_4sf, "__builtin_altivec_vsel_4sf", ALTIVEC_BUILTIN_VSEL_4SF },
515490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsel_4si, "__builtin_altivec_vsel_4si", ALTIVEC_BUILTIN_VSEL_4SI },
515590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsel_8hi, "__builtin_altivec_vsel_8hi", ALTIVEC_BUILTIN_VSEL_8HI },
515690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsel_16qi, "__builtin_altivec_vsel_16qi", ALTIVEC_BUILTIN_VSEL_16QI },
515790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsldoi_16qi, "__builtin_altivec_vsldoi_16qi", ALTIVEC_BUILTIN_VSLDOI_16QI },
515890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsldoi_8hi, "__builtin_altivec_vsldoi_8hi", ALTIVEC_BUILTIN_VSLDOI_8HI },
515990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsldoi_4si, "__builtin_altivec_vsldoi_4si", ALTIVEC_BUILTIN_VSLDOI_4SI },
516090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsldoi_4sf, "__builtin_altivec_vsldoi_4sf", ALTIVEC_BUILTIN_VSLDOI_4SF },
516190075Sobrien};
516290075Sobrien
516390075Sobrien/* DST operations: void foo (void *, const int, const char).  */
516490075Sobrien
516590075Sobrienstatic const struct builtin_description bdesc_dst[] =
516690075Sobrien{
516790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_dst, "__builtin_altivec_dst", ALTIVEC_BUILTIN_DST },
516890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_dstt, "__builtin_altivec_dstt", ALTIVEC_BUILTIN_DSTT },
516990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_dstst, "__builtin_altivec_dstst", ALTIVEC_BUILTIN_DSTST },
517090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_dststt, "__builtin_altivec_dststt", ALTIVEC_BUILTIN_DSTSTT }
517190075Sobrien};
517290075Sobrien
517390075Sobrien/* Simple binary operations: VECc = foo (VECa, VECb).  */
517490075Sobrien
5175117395Skanstatic struct builtin_description bdesc_2arg[] =
517690075Sobrien{
517790075Sobrien  { MASK_ALTIVEC, CODE_FOR_addv16qi3, "__builtin_altivec_vaddubm", ALTIVEC_BUILTIN_VADDUBM },
517890075Sobrien  { MASK_ALTIVEC, CODE_FOR_addv8hi3, "__builtin_altivec_vadduhm", ALTIVEC_BUILTIN_VADDUHM },
517990075Sobrien  { MASK_ALTIVEC, CODE_FOR_addv4si3, "__builtin_altivec_vadduwm", ALTIVEC_BUILTIN_VADDUWM },
518090075Sobrien  { MASK_ALTIVEC, CODE_FOR_addv4sf3, "__builtin_altivec_vaddfp", ALTIVEC_BUILTIN_VADDFP },
518190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vaddcuw, "__builtin_altivec_vaddcuw", ALTIVEC_BUILTIN_VADDCUW },
518290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vaddubs, "__builtin_altivec_vaddubs", ALTIVEC_BUILTIN_VADDUBS },
518390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vaddsbs, "__builtin_altivec_vaddsbs", ALTIVEC_BUILTIN_VADDSBS },
518490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vadduhs, "__builtin_altivec_vadduhs", ALTIVEC_BUILTIN_VADDUHS },
518590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vaddshs, "__builtin_altivec_vaddshs", ALTIVEC_BUILTIN_VADDSHS },
518690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vadduws, "__builtin_altivec_vadduws", ALTIVEC_BUILTIN_VADDUWS },
518790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vaddsws, "__builtin_altivec_vaddsws", ALTIVEC_BUILTIN_VADDSWS },
518890075Sobrien  { MASK_ALTIVEC, CODE_FOR_andv4si3, "__builtin_altivec_vand", ALTIVEC_BUILTIN_VAND },
518990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vandc, "__builtin_altivec_vandc", ALTIVEC_BUILTIN_VANDC },
519090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vavgub, "__builtin_altivec_vavgub", ALTIVEC_BUILTIN_VAVGUB },
519190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vavgsb, "__builtin_altivec_vavgsb", ALTIVEC_BUILTIN_VAVGSB },
519290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vavguh, "__builtin_altivec_vavguh", ALTIVEC_BUILTIN_VAVGUH },
519390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vavgsh, "__builtin_altivec_vavgsh", ALTIVEC_BUILTIN_VAVGSH },
519490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vavguw, "__builtin_altivec_vavguw", ALTIVEC_BUILTIN_VAVGUW },
519590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vavgsw, "__builtin_altivec_vavgsw", ALTIVEC_BUILTIN_VAVGSW },
519690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcfux, "__builtin_altivec_vcfux", ALTIVEC_BUILTIN_VCFUX },
519790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcfsx, "__builtin_altivec_vcfsx", ALTIVEC_BUILTIN_VCFSX },
519890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpbfp, "__builtin_altivec_vcmpbfp", ALTIVEC_BUILTIN_VCMPBFP },
519990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpequb, "__builtin_altivec_vcmpequb", ALTIVEC_BUILTIN_VCMPEQUB },
520090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpequh, "__builtin_altivec_vcmpequh", ALTIVEC_BUILTIN_VCMPEQUH },
520190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpequw, "__builtin_altivec_vcmpequw", ALTIVEC_BUILTIN_VCMPEQUW },
520290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpeqfp, "__builtin_altivec_vcmpeqfp", ALTIVEC_BUILTIN_VCMPEQFP },
520390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpgefp, "__builtin_altivec_vcmpgefp", ALTIVEC_BUILTIN_VCMPGEFP },
520490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpgtub, "__builtin_altivec_vcmpgtub", ALTIVEC_BUILTIN_VCMPGTUB },
520590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpgtsb, "__builtin_altivec_vcmpgtsb", ALTIVEC_BUILTIN_VCMPGTSB },
520690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpgtuh, "__builtin_altivec_vcmpgtuh", ALTIVEC_BUILTIN_VCMPGTUH },
520790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpgtsh, "__builtin_altivec_vcmpgtsh", ALTIVEC_BUILTIN_VCMPGTSH },
520890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpgtuw, "__builtin_altivec_vcmpgtuw", ALTIVEC_BUILTIN_VCMPGTUW },
520990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpgtsw, "__builtin_altivec_vcmpgtsw", ALTIVEC_BUILTIN_VCMPGTSW },
521090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpgtfp, "__builtin_altivec_vcmpgtfp", ALTIVEC_BUILTIN_VCMPGTFP },
521190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vctsxs, "__builtin_altivec_vctsxs", ALTIVEC_BUILTIN_VCTSXS },
521290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vctuxs, "__builtin_altivec_vctuxs", ALTIVEC_BUILTIN_VCTUXS },
521390075Sobrien  { MASK_ALTIVEC, CODE_FOR_umaxv16qi3, "__builtin_altivec_vmaxub", ALTIVEC_BUILTIN_VMAXUB },
521490075Sobrien  { MASK_ALTIVEC, CODE_FOR_smaxv16qi3, "__builtin_altivec_vmaxsb", ALTIVEC_BUILTIN_VMAXSB },
5215117395Skan  { MASK_ALTIVEC, CODE_FOR_umaxv8hi3, "__builtin_altivec_vmaxuh", ALTIVEC_BUILTIN_VMAXUH },
5216117395Skan  { MASK_ALTIVEC, CODE_FOR_smaxv8hi3, "__builtin_altivec_vmaxsh", ALTIVEC_BUILTIN_VMAXSH },
5217117395Skan  { MASK_ALTIVEC, CODE_FOR_umaxv4si3, "__builtin_altivec_vmaxuw", ALTIVEC_BUILTIN_VMAXUW },
5218117395Skan  { MASK_ALTIVEC, CODE_FOR_smaxv4si3, "__builtin_altivec_vmaxsw", ALTIVEC_BUILTIN_VMAXSW },
5219117395Skan  { MASK_ALTIVEC, CODE_FOR_smaxv4sf3, "__builtin_altivec_vmaxfp", ALTIVEC_BUILTIN_VMAXFP },
522090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmrghb, "__builtin_altivec_vmrghb", ALTIVEC_BUILTIN_VMRGHB },
522190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmrghh, "__builtin_altivec_vmrghh", ALTIVEC_BUILTIN_VMRGHH },
522290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmrghw, "__builtin_altivec_vmrghw", ALTIVEC_BUILTIN_VMRGHW },
522390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmrglb, "__builtin_altivec_vmrglb", ALTIVEC_BUILTIN_VMRGLB },
522490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmrglh, "__builtin_altivec_vmrglh", ALTIVEC_BUILTIN_VMRGLH },
522590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmrglw, "__builtin_altivec_vmrglw", ALTIVEC_BUILTIN_VMRGLW },
522690075Sobrien  { MASK_ALTIVEC, CODE_FOR_uminv16qi3, "__builtin_altivec_vminub", ALTIVEC_BUILTIN_VMINUB },
522790075Sobrien  { MASK_ALTIVEC, CODE_FOR_sminv16qi3, "__builtin_altivec_vminsb", ALTIVEC_BUILTIN_VMINSB },
522890075Sobrien  { MASK_ALTIVEC, CODE_FOR_uminv8hi3, "__builtin_altivec_vminuh", ALTIVEC_BUILTIN_VMINUH },
522990075Sobrien  { MASK_ALTIVEC, CODE_FOR_sminv8hi3, "__builtin_altivec_vminsh", ALTIVEC_BUILTIN_VMINSH },
523090075Sobrien  { MASK_ALTIVEC, CODE_FOR_uminv4si3, "__builtin_altivec_vminuw", ALTIVEC_BUILTIN_VMINUW },
523190075Sobrien  { MASK_ALTIVEC, CODE_FOR_sminv4si3, "__builtin_altivec_vminsw", ALTIVEC_BUILTIN_VMINSW },
523290075Sobrien  { MASK_ALTIVEC, CODE_FOR_sminv4sf3, "__builtin_altivec_vminfp", ALTIVEC_BUILTIN_VMINFP },
523390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmuleub, "__builtin_altivec_vmuleub", ALTIVEC_BUILTIN_VMULEUB },
523490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmulesb, "__builtin_altivec_vmulesb", ALTIVEC_BUILTIN_VMULESB },
523590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmuleuh, "__builtin_altivec_vmuleuh", ALTIVEC_BUILTIN_VMULEUH },
523690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmulesh, "__builtin_altivec_vmulesh", ALTIVEC_BUILTIN_VMULESH },
523790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmuloub, "__builtin_altivec_vmuloub", ALTIVEC_BUILTIN_VMULOUB },
523890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmulosb, "__builtin_altivec_vmulosb", ALTIVEC_BUILTIN_VMULOSB },
523990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmulouh, "__builtin_altivec_vmulouh", ALTIVEC_BUILTIN_VMULOUH },
524090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmulosh, "__builtin_altivec_vmulosh", ALTIVEC_BUILTIN_VMULOSH },
524190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vnor, "__builtin_altivec_vnor", ALTIVEC_BUILTIN_VNOR },
524290075Sobrien  { MASK_ALTIVEC, CODE_FOR_iorv4si3, "__builtin_altivec_vor", ALTIVEC_BUILTIN_VOR },
524390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkuhum, "__builtin_altivec_vpkuhum", ALTIVEC_BUILTIN_VPKUHUM },
524490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkuwum, "__builtin_altivec_vpkuwum", ALTIVEC_BUILTIN_VPKUWUM },
524590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkpx, "__builtin_altivec_vpkpx", ALTIVEC_BUILTIN_VPKPX },
524690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkuhss, "__builtin_altivec_vpkuhss", ALTIVEC_BUILTIN_VPKUHSS },
524790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkshss, "__builtin_altivec_vpkshss", ALTIVEC_BUILTIN_VPKSHSS },
524890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkuwss, "__builtin_altivec_vpkuwss", ALTIVEC_BUILTIN_VPKUWSS },
524990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkswss, "__builtin_altivec_vpkswss", ALTIVEC_BUILTIN_VPKSWSS },
525090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkuhus, "__builtin_altivec_vpkuhus", ALTIVEC_BUILTIN_VPKUHUS },
525190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkshus, "__builtin_altivec_vpkshus", ALTIVEC_BUILTIN_VPKSHUS },
525290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkuwus, "__builtin_altivec_vpkuwus", ALTIVEC_BUILTIN_VPKUWUS },
525390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkswus, "__builtin_altivec_vpkswus", ALTIVEC_BUILTIN_VPKSWUS },
525490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vrlb, "__builtin_altivec_vrlb", ALTIVEC_BUILTIN_VRLB },
525590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vrlh, "__builtin_altivec_vrlh", ALTIVEC_BUILTIN_VRLH },
525690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vrlw, "__builtin_altivec_vrlw", ALTIVEC_BUILTIN_VRLW },
525790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vslb, "__builtin_altivec_vslb", ALTIVEC_BUILTIN_VSLB },
525890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vslh, "__builtin_altivec_vslh", ALTIVEC_BUILTIN_VSLH },
525990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vslw, "__builtin_altivec_vslw", ALTIVEC_BUILTIN_VSLW },
526090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsl, "__builtin_altivec_vsl", ALTIVEC_BUILTIN_VSL },
526190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vslo, "__builtin_altivec_vslo", ALTIVEC_BUILTIN_VSLO },
526290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vspltb, "__builtin_altivec_vspltb", ALTIVEC_BUILTIN_VSPLTB },
526390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsplth, "__builtin_altivec_vsplth", ALTIVEC_BUILTIN_VSPLTH },
526490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vspltw, "__builtin_altivec_vspltw", ALTIVEC_BUILTIN_VSPLTW },
526590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsrb, "__builtin_altivec_vsrb", ALTIVEC_BUILTIN_VSRB },
526690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsrh, "__builtin_altivec_vsrh", ALTIVEC_BUILTIN_VSRH },
526790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsrw, "__builtin_altivec_vsrw", ALTIVEC_BUILTIN_VSRW },
526890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsrab, "__builtin_altivec_vsrab", ALTIVEC_BUILTIN_VSRAB },
526990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsrah, "__builtin_altivec_vsrah", ALTIVEC_BUILTIN_VSRAH },
527090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsraw, "__builtin_altivec_vsraw", ALTIVEC_BUILTIN_VSRAW },
527190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsr, "__builtin_altivec_vsr", ALTIVEC_BUILTIN_VSR },
527290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsro, "__builtin_altivec_vsro", ALTIVEC_BUILTIN_VSRO },
527390075Sobrien  { MASK_ALTIVEC, CODE_FOR_subv16qi3, "__builtin_altivec_vsububm", ALTIVEC_BUILTIN_VSUBUBM },
527490075Sobrien  { MASK_ALTIVEC, CODE_FOR_subv8hi3, "__builtin_altivec_vsubuhm", ALTIVEC_BUILTIN_VSUBUHM },
527590075Sobrien  { MASK_ALTIVEC, CODE_FOR_subv4si3, "__builtin_altivec_vsubuwm", ALTIVEC_BUILTIN_VSUBUWM },
527690075Sobrien  { MASK_ALTIVEC, CODE_FOR_subv4sf3, "__builtin_altivec_vsubfp", ALTIVEC_BUILTIN_VSUBFP },
527790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsubcuw, "__builtin_altivec_vsubcuw", ALTIVEC_BUILTIN_VSUBCUW },
527890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsububs, "__builtin_altivec_vsububs", ALTIVEC_BUILTIN_VSUBUBS },
527990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsubsbs, "__builtin_altivec_vsubsbs", ALTIVEC_BUILTIN_VSUBSBS },
528090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsubuhs, "__builtin_altivec_vsubuhs", ALTIVEC_BUILTIN_VSUBUHS },
528190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsubshs, "__builtin_altivec_vsubshs", ALTIVEC_BUILTIN_VSUBSHS },
528290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsubuws, "__builtin_altivec_vsubuws", ALTIVEC_BUILTIN_VSUBUWS },
528390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsubsws, "__builtin_altivec_vsubsws", ALTIVEC_BUILTIN_VSUBSWS },
528490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsum4ubs, "__builtin_altivec_vsum4ubs", ALTIVEC_BUILTIN_VSUM4UBS },
528590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsum4sbs, "__builtin_altivec_vsum4sbs", ALTIVEC_BUILTIN_VSUM4SBS },
528690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsum4shs, "__builtin_altivec_vsum4shs", ALTIVEC_BUILTIN_VSUM4SHS },
528790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsum2sws, "__builtin_altivec_vsum2sws", ALTIVEC_BUILTIN_VSUM2SWS },
528890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsumsws, "__builtin_altivec_vsumsws", ALTIVEC_BUILTIN_VSUMSWS },
528990075Sobrien  { MASK_ALTIVEC, CODE_FOR_xorv4si3, "__builtin_altivec_vxor", ALTIVEC_BUILTIN_VXOR },
5290117395Skan
5291117395Skan  /* Place holder, leave as first spe builtin.  */
5292117395Skan  { 0, CODE_FOR_spe_evaddw, "__builtin_spe_evaddw", SPE_BUILTIN_EVADDW },
5293117395Skan  { 0, CODE_FOR_spe_evand, "__builtin_spe_evand", SPE_BUILTIN_EVAND },
5294117395Skan  { 0, CODE_FOR_spe_evandc, "__builtin_spe_evandc", SPE_BUILTIN_EVANDC },
5295117395Skan  { 0, CODE_FOR_spe_evdivws, "__builtin_spe_evdivws", SPE_BUILTIN_EVDIVWS },
5296117395Skan  { 0, CODE_FOR_spe_evdivwu, "__builtin_spe_evdivwu", SPE_BUILTIN_EVDIVWU },
5297117395Skan  { 0, CODE_FOR_spe_eveqv, "__builtin_spe_eveqv", SPE_BUILTIN_EVEQV },
5298117395Skan  { 0, CODE_FOR_spe_evfsadd, "__builtin_spe_evfsadd", SPE_BUILTIN_EVFSADD },
5299117395Skan  { 0, CODE_FOR_spe_evfsdiv, "__builtin_spe_evfsdiv", SPE_BUILTIN_EVFSDIV },
5300117395Skan  { 0, CODE_FOR_spe_evfsmul, "__builtin_spe_evfsmul", SPE_BUILTIN_EVFSMUL },
5301117395Skan  { 0, CODE_FOR_spe_evfssub, "__builtin_spe_evfssub", SPE_BUILTIN_EVFSSUB },
5302117395Skan  { 0, CODE_FOR_spe_evmergehi, "__builtin_spe_evmergehi", SPE_BUILTIN_EVMERGEHI },
5303117395Skan  { 0, CODE_FOR_spe_evmergehilo, "__builtin_spe_evmergehilo", SPE_BUILTIN_EVMERGEHILO },
5304117395Skan  { 0, CODE_FOR_spe_evmergelo, "__builtin_spe_evmergelo", SPE_BUILTIN_EVMERGELO },
5305117395Skan  { 0, CODE_FOR_spe_evmergelohi, "__builtin_spe_evmergelohi", SPE_BUILTIN_EVMERGELOHI },
5306117395Skan  { 0, CODE_FOR_spe_evmhegsmfaa, "__builtin_spe_evmhegsmfaa", SPE_BUILTIN_EVMHEGSMFAA },
5307117395Skan  { 0, CODE_FOR_spe_evmhegsmfan, "__builtin_spe_evmhegsmfan", SPE_BUILTIN_EVMHEGSMFAN },
5308117395Skan  { 0, CODE_FOR_spe_evmhegsmiaa, "__builtin_spe_evmhegsmiaa", SPE_BUILTIN_EVMHEGSMIAA },
5309117395Skan  { 0, CODE_FOR_spe_evmhegsmian, "__builtin_spe_evmhegsmian", SPE_BUILTIN_EVMHEGSMIAN },
5310117395Skan  { 0, CODE_FOR_spe_evmhegumiaa, "__builtin_spe_evmhegumiaa", SPE_BUILTIN_EVMHEGUMIAA },
5311117395Skan  { 0, CODE_FOR_spe_evmhegumian, "__builtin_spe_evmhegumian", SPE_BUILTIN_EVMHEGUMIAN },
5312117395Skan  { 0, CODE_FOR_spe_evmhesmf, "__builtin_spe_evmhesmf", SPE_BUILTIN_EVMHESMF },
5313117395Skan  { 0, CODE_FOR_spe_evmhesmfa, "__builtin_spe_evmhesmfa", SPE_BUILTIN_EVMHESMFA },
5314117395Skan  { 0, CODE_FOR_spe_evmhesmfaaw, "__builtin_spe_evmhesmfaaw", SPE_BUILTIN_EVMHESMFAAW },
5315117395Skan  { 0, CODE_FOR_spe_evmhesmfanw, "__builtin_spe_evmhesmfanw", SPE_BUILTIN_EVMHESMFANW },
5316117395Skan  { 0, CODE_FOR_spe_evmhesmi, "__builtin_spe_evmhesmi", SPE_BUILTIN_EVMHESMI },
5317117395Skan  { 0, CODE_FOR_spe_evmhesmia, "__builtin_spe_evmhesmia", SPE_BUILTIN_EVMHESMIA },
5318117395Skan  { 0, CODE_FOR_spe_evmhesmiaaw, "__builtin_spe_evmhesmiaaw", SPE_BUILTIN_EVMHESMIAAW },
5319117395Skan  { 0, CODE_FOR_spe_evmhesmianw, "__builtin_spe_evmhesmianw", SPE_BUILTIN_EVMHESMIANW },
5320117395Skan  { 0, CODE_FOR_spe_evmhessf, "__builtin_spe_evmhessf", SPE_BUILTIN_EVMHESSF },
5321117395Skan  { 0, CODE_FOR_spe_evmhessfa, "__builtin_spe_evmhessfa", SPE_BUILTIN_EVMHESSFA },
5322117395Skan  { 0, CODE_FOR_spe_evmhessfaaw, "__builtin_spe_evmhessfaaw", SPE_BUILTIN_EVMHESSFAAW },
5323117395Skan  { 0, CODE_FOR_spe_evmhessfanw, "__builtin_spe_evmhessfanw", SPE_BUILTIN_EVMHESSFANW },
5324117395Skan  { 0, CODE_FOR_spe_evmhessiaaw, "__builtin_spe_evmhessiaaw", SPE_BUILTIN_EVMHESSIAAW },
5325117395Skan  { 0, CODE_FOR_spe_evmhessianw, "__builtin_spe_evmhessianw", SPE_BUILTIN_EVMHESSIANW },
5326117395Skan  { 0, CODE_FOR_spe_evmheumi, "__builtin_spe_evmheumi", SPE_BUILTIN_EVMHEUMI },
5327117395Skan  { 0, CODE_FOR_spe_evmheumia, "__builtin_spe_evmheumia", SPE_BUILTIN_EVMHEUMIA },
5328117395Skan  { 0, CODE_FOR_spe_evmheumiaaw, "__builtin_spe_evmheumiaaw", SPE_BUILTIN_EVMHEUMIAAW },
5329117395Skan  { 0, CODE_FOR_spe_evmheumianw, "__builtin_spe_evmheumianw", SPE_BUILTIN_EVMHEUMIANW },
5330117395Skan  { 0, CODE_FOR_spe_evmheusiaaw, "__builtin_spe_evmheusiaaw", SPE_BUILTIN_EVMHEUSIAAW },
5331117395Skan  { 0, CODE_FOR_spe_evmheusianw, "__builtin_spe_evmheusianw", SPE_BUILTIN_EVMHEUSIANW },
5332117395Skan  { 0, CODE_FOR_spe_evmhogsmfaa, "__builtin_spe_evmhogsmfaa", SPE_BUILTIN_EVMHOGSMFAA },
5333117395Skan  { 0, CODE_FOR_spe_evmhogsmfan, "__builtin_spe_evmhogsmfan", SPE_BUILTIN_EVMHOGSMFAN },
5334117395Skan  { 0, CODE_FOR_spe_evmhogsmiaa, "__builtin_spe_evmhogsmiaa", SPE_BUILTIN_EVMHOGSMIAA },
5335117395Skan  { 0, CODE_FOR_spe_evmhogsmian, "__builtin_spe_evmhogsmian", SPE_BUILTIN_EVMHOGSMIAN },
5336117395Skan  { 0, CODE_FOR_spe_evmhogumiaa, "__builtin_spe_evmhogumiaa", SPE_BUILTIN_EVMHOGUMIAA },
5337117395Skan  { 0, CODE_FOR_spe_evmhogumian, "__builtin_spe_evmhogumian", SPE_BUILTIN_EVMHOGUMIAN },
5338117395Skan  { 0, CODE_FOR_spe_evmhosmf, "__builtin_spe_evmhosmf", SPE_BUILTIN_EVMHOSMF },
5339117395Skan  { 0, CODE_FOR_spe_evmhosmfa, "__builtin_spe_evmhosmfa", SPE_BUILTIN_EVMHOSMFA },
5340117395Skan  { 0, CODE_FOR_spe_evmhosmfaaw, "__builtin_spe_evmhosmfaaw", SPE_BUILTIN_EVMHOSMFAAW },
5341117395Skan  { 0, CODE_FOR_spe_evmhosmfanw, "__builtin_spe_evmhosmfanw", SPE_BUILTIN_EVMHOSMFANW },
5342117395Skan  { 0, CODE_FOR_spe_evmhosmi, "__builtin_spe_evmhosmi", SPE_BUILTIN_EVMHOSMI },
5343117395Skan  { 0, CODE_FOR_spe_evmhosmia, "__builtin_spe_evmhosmia", SPE_BUILTIN_EVMHOSMIA },
5344117395Skan  { 0, CODE_FOR_spe_evmhosmiaaw, "__builtin_spe_evmhosmiaaw", SPE_BUILTIN_EVMHOSMIAAW },
5345117395Skan  { 0, CODE_FOR_spe_evmhosmianw, "__builtin_spe_evmhosmianw", SPE_BUILTIN_EVMHOSMIANW },
5346117395Skan  { 0, CODE_FOR_spe_evmhossf, "__builtin_spe_evmhossf", SPE_BUILTIN_EVMHOSSF },
5347117395Skan  { 0, CODE_FOR_spe_evmhossfa, "__builtin_spe_evmhossfa", SPE_BUILTIN_EVMHOSSFA },
5348117395Skan  { 0, CODE_FOR_spe_evmhossfaaw, "__builtin_spe_evmhossfaaw", SPE_BUILTIN_EVMHOSSFAAW },
5349117395Skan  { 0, CODE_FOR_spe_evmhossfanw, "__builtin_spe_evmhossfanw", SPE_BUILTIN_EVMHOSSFANW },
5350117395Skan  { 0, CODE_FOR_spe_evmhossiaaw, "__builtin_spe_evmhossiaaw", SPE_BUILTIN_EVMHOSSIAAW },
5351117395Skan  { 0, CODE_FOR_spe_evmhossianw, "__builtin_spe_evmhossianw", SPE_BUILTIN_EVMHOSSIANW },
5352117395Skan  { 0, CODE_FOR_spe_evmhoumi, "__builtin_spe_evmhoumi", SPE_BUILTIN_EVMHOUMI },
5353117395Skan  { 0, CODE_FOR_spe_evmhoumia, "__builtin_spe_evmhoumia", SPE_BUILTIN_EVMHOUMIA },
5354117395Skan  { 0, CODE_FOR_spe_evmhoumiaaw, "__builtin_spe_evmhoumiaaw", SPE_BUILTIN_EVMHOUMIAAW },
5355117395Skan  { 0, CODE_FOR_spe_evmhoumianw, "__builtin_spe_evmhoumianw", SPE_BUILTIN_EVMHOUMIANW },
5356117395Skan  { 0, CODE_FOR_spe_evmhousiaaw, "__builtin_spe_evmhousiaaw", SPE_BUILTIN_EVMHOUSIAAW },
5357117395Skan  { 0, CODE_FOR_spe_evmhousianw, "__builtin_spe_evmhousianw", SPE_BUILTIN_EVMHOUSIANW },
5358117395Skan  { 0, CODE_FOR_spe_evmwhsmf, "__builtin_spe_evmwhsmf", SPE_BUILTIN_EVMWHSMF },
5359117395Skan  { 0, CODE_FOR_spe_evmwhsmfa, "__builtin_spe_evmwhsmfa", SPE_BUILTIN_EVMWHSMFA },
5360117395Skan  { 0, CODE_FOR_spe_evmwhsmi, "__builtin_spe_evmwhsmi", SPE_BUILTIN_EVMWHSMI },
5361117395Skan  { 0, CODE_FOR_spe_evmwhsmia, "__builtin_spe_evmwhsmia", SPE_BUILTIN_EVMWHSMIA },
5362117395Skan  { 0, CODE_FOR_spe_evmwhssf, "__builtin_spe_evmwhssf", SPE_BUILTIN_EVMWHSSF },
5363117395Skan  { 0, CODE_FOR_spe_evmwhssfa, "__builtin_spe_evmwhssfa", SPE_BUILTIN_EVMWHSSFA },
5364117395Skan  { 0, CODE_FOR_spe_evmwhumi, "__builtin_spe_evmwhumi", SPE_BUILTIN_EVMWHUMI },
5365117395Skan  { 0, CODE_FOR_spe_evmwhumia, "__builtin_spe_evmwhumia", SPE_BUILTIN_EVMWHUMIA },
5366117395Skan  { 0, CODE_FOR_spe_evmwlsmiaaw, "__builtin_spe_evmwlsmiaaw", SPE_BUILTIN_EVMWLSMIAAW },
5367117395Skan  { 0, CODE_FOR_spe_evmwlsmianw, "__builtin_spe_evmwlsmianw", SPE_BUILTIN_EVMWLSMIANW },
5368117395Skan  { 0, CODE_FOR_spe_evmwlssiaaw, "__builtin_spe_evmwlssiaaw", SPE_BUILTIN_EVMWLSSIAAW },
5369117395Skan  { 0, CODE_FOR_spe_evmwlssianw, "__builtin_spe_evmwlssianw", SPE_BUILTIN_EVMWLSSIANW },
5370117395Skan  { 0, CODE_FOR_spe_evmwlumi, "__builtin_spe_evmwlumi", SPE_BUILTIN_EVMWLUMI },
5371117395Skan  { 0, CODE_FOR_spe_evmwlumia, "__builtin_spe_evmwlumia", SPE_BUILTIN_EVMWLUMIA },
5372117395Skan  { 0, CODE_FOR_spe_evmwlumiaaw, "__builtin_spe_evmwlumiaaw", SPE_BUILTIN_EVMWLUMIAAW },
5373117395Skan  { 0, CODE_FOR_spe_evmwlumianw, "__builtin_spe_evmwlumianw", SPE_BUILTIN_EVMWLUMIANW },
5374117395Skan  { 0, CODE_FOR_spe_evmwlusiaaw, "__builtin_spe_evmwlusiaaw", SPE_BUILTIN_EVMWLUSIAAW },
5375117395Skan  { 0, CODE_FOR_spe_evmwlusianw, "__builtin_spe_evmwlusianw", SPE_BUILTIN_EVMWLUSIANW },
5376117395Skan  { 0, CODE_FOR_spe_evmwsmf, "__builtin_spe_evmwsmf", SPE_BUILTIN_EVMWSMF },
5377117395Skan  { 0, CODE_FOR_spe_evmwsmfa, "__builtin_spe_evmwsmfa", SPE_BUILTIN_EVMWSMFA },
5378117395Skan  { 0, CODE_FOR_spe_evmwsmfaa, "__builtin_spe_evmwsmfaa", SPE_BUILTIN_EVMWSMFAA },
5379117395Skan  { 0, CODE_FOR_spe_evmwsmfan, "__builtin_spe_evmwsmfan", SPE_BUILTIN_EVMWSMFAN },
5380117395Skan  { 0, CODE_FOR_spe_evmwsmi, "__builtin_spe_evmwsmi", SPE_BUILTIN_EVMWSMI },
5381117395Skan  { 0, CODE_FOR_spe_evmwsmia, "__builtin_spe_evmwsmia", SPE_BUILTIN_EVMWSMIA },
5382117395Skan  { 0, CODE_FOR_spe_evmwsmiaa, "__builtin_spe_evmwsmiaa", SPE_BUILTIN_EVMWSMIAA },
5383117395Skan  { 0, CODE_FOR_spe_evmwsmian, "__builtin_spe_evmwsmian", SPE_BUILTIN_EVMWSMIAN },
5384117395Skan  { 0, CODE_FOR_spe_evmwssf, "__builtin_spe_evmwssf", SPE_BUILTIN_EVMWSSF },
5385117395Skan  { 0, CODE_FOR_spe_evmwssfa, "__builtin_spe_evmwssfa", SPE_BUILTIN_EVMWSSFA },
5386117395Skan  { 0, CODE_FOR_spe_evmwssfaa, "__builtin_spe_evmwssfaa", SPE_BUILTIN_EVMWSSFAA },
5387117395Skan  { 0, CODE_FOR_spe_evmwssfan, "__builtin_spe_evmwssfan", SPE_BUILTIN_EVMWSSFAN },
5388117395Skan  { 0, CODE_FOR_spe_evmwumi, "__builtin_spe_evmwumi", SPE_BUILTIN_EVMWUMI },
5389117395Skan  { 0, CODE_FOR_spe_evmwumia, "__builtin_spe_evmwumia", SPE_BUILTIN_EVMWUMIA },
5390117395Skan  { 0, CODE_FOR_spe_evmwumiaa, "__builtin_spe_evmwumiaa", SPE_BUILTIN_EVMWUMIAA },
5391117395Skan  { 0, CODE_FOR_spe_evmwumian, "__builtin_spe_evmwumian", SPE_BUILTIN_EVMWUMIAN },
5392117395Skan  { 0, CODE_FOR_spe_evnand, "__builtin_spe_evnand", SPE_BUILTIN_EVNAND },
5393117395Skan  { 0, CODE_FOR_spe_evnor, "__builtin_spe_evnor", SPE_BUILTIN_EVNOR },
5394117395Skan  { 0, CODE_FOR_spe_evor, "__builtin_spe_evor", SPE_BUILTIN_EVOR },
5395117395Skan  { 0, CODE_FOR_spe_evorc, "__builtin_spe_evorc", SPE_BUILTIN_EVORC },
5396117395Skan  { 0, CODE_FOR_spe_evrlw, "__builtin_spe_evrlw", SPE_BUILTIN_EVRLW },
5397117395Skan  { 0, CODE_FOR_spe_evslw, "__builtin_spe_evslw", SPE_BUILTIN_EVSLW },
5398117395Skan  { 0, CODE_FOR_spe_evsrws, "__builtin_spe_evsrws", SPE_BUILTIN_EVSRWS },
5399117395Skan  { 0, CODE_FOR_spe_evsrwu, "__builtin_spe_evsrwu", SPE_BUILTIN_EVSRWU },
5400117395Skan  { 0, CODE_FOR_spe_evsubfw, "__builtin_spe_evsubfw", SPE_BUILTIN_EVSUBFW },
5401117395Skan
5402117395Skan  /* SPE binary operations expecting a 5-bit unsigned literal.  */
5403117395Skan  { 0, CODE_FOR_spe_evaddiw, "__builtin_spe_evaddiw", SPE_BUILTIN_EVADDIW },
5404117395Skan
5405117395Skan  { 0, CODE_FOR_spe_evrlwi, "__builtin_spe_evrlwi", SPE_BUILTIN_EVRLWI },
5406117395Skan  { 0, CODE_FOR_spe_evslwi, "__builtin_spe_evslwi", SPE_BUILTIN_EVSLWI },
5407117395Skan  { 0, CODE_FOR_spe_evsrwis, "__builtin_spe_evsrwis", SPE_BUILTIN_EVSRWIS },
5408117395Skan  { 0, CODE_FOR_spe_evsrwiu, "__builtin_spe_evsrwiu", SPE_BUILTIN_EVSRWIU },
5409117395Skan  { 0, CODE_FOR_spe_evsubifw, "__builtin_spe_evsubifw", SPE_BUILTIN_EVSUBIFW },
5410117395Skan  { 0, CODE_FOR_spe_evmwhssfaa, "__builtin_spe_evmwhssfaa", SPE_BUILTIN_EVMWHSSFAA },
5411117395Skan  { 0, CODE_FOR_spe_evmwhssmaa, "__builtin_spe_evmwhssmaa", SPE_BUILTIN_EVMWHSSMAA },
5412117395Skan  { 0, CODE_FOR_spe_evmwhsmfaa, "__builtin_spe_evmwhsmfaa", SPE_BUILTIN_EVMWHSMFAA },
5413117395Skan  { 0, CODE_FOR_spe_evmwhsmiaa, "__builtin_spe_evmwhsmiaa", SPE_BUILTIN_EVMWHSMIAA },
5414117395Skan  { 0, CODE_FOR_spe_evmwhusiaa, "__builtin_spe_evmwhusiaa", SPE_BUILTIN_EVMWHUSIAA },
5415117395Skan  { 0, CODE_FOR_spe_evmwhumiaa, "__builtin_spe_evmwhumiaa", SPE_BUILTIN_EVMWHUMIAA },
5416117395Skan  { 0, CODE_FOR_spe_evmwhssfan, "__builtin_spe_evmwhssfan", SPE_BUILTIN_EVMWHSSFAN },
5417117395Skan  { 0, CODE_FOR_spe_evmwhssian, "__builtin_spe_evmwhssian", SPE_BUILTIN_EVMWHSSIAN },
5418117395Skan  { 0, CODE_FOR_spe_evmwhsmfan, "__builtin_spe_evmwhsmfan", SPE_BUILTIN_EVMWHSMFAN },
5419117395Skan  { 0, CODE_FOR_spe_evmwhsmian, "__builtin_spe_evmwhsmian", SPE_BUILTIN_EVMWHSMIAN },
5420117395Skan  { 0, CODE_FOR_spe_evmwhusian, "__builtin_spe_evmwhusian", SPE_BUILTIN_EVMWHUSIAN },
5421117395Skan  { 0, CODE_FOR_spe_evmwhumian, "__builtin_spe_evmwhumian", SPE_BUILTIN_EVMWHUMIAN },
5422117395Skan  { 0, CODE_FOR_spe_evmwhgssfaa, "__builtin_spe_evmwhgssfaa", SPE_BUILTIN_EVMWHGSSFAA },
5423117395Skan  { 0, CODE_FOR_spe_evmwhgsmfaa, "__builtin_spe_evmwhgsmfaa", SPE_BUILTIN_EVMWHGSMFAA },
5424117395Skan  { 0, CODE_FOR_spe_evmwhgsmiaa, "__builtin_spe_evmwhgsmiaa", SPE_BUILTIN_EVMWHGSMIAA },
5425117395Skan  { 0, CODE_FOR_spe_evmwhgumiaa, "__builtin_spe_evmwhgumiaa", SPE_BUILTIN_EVMWHGUMIAA },
5426117395Skan  { 0, CODE_FOR_spe_evmwhgssfan, "__builtin_spe_evmwhgssfan", SPE_BUILTIN_EVMWHGSSFAN },
5427117395Skan  { 0, CODE_FOR_spe_evmwhgsmfan, "__builtin_spe_evmwhgsmfan", SPE_BUILTIN_EVMWHGSMFAN },
5428117395Skan  { 0, CODE_FOR_spe_evmwhgsmian, "__builtin_spe_evmwhgsmian", SPE_BUILTIN_EVMWHGSMIAN },
5429117395Skan  { 0, CODE_FOR_spe_evmwhgumian, "__builtin_spe_evmwhgumian", SPE_BUILTIN_EVMWHGUMIAN },
5430117395Skan  { 0, CODE_FOR_spe_brinc, "__builtin_spe_brinc", SPE_BUILTIN_BRINC },
5431117395Skan
5432117395Skan  /* Place-holder.  Leave as last binary SPE builtin.  */
5433132718Skan  { 0, CODE_FOR_xorv2si3, "__builtin_spe_evxor", SPE_BUILTIN_EVXOR },
543490075Sobrien};
543590075Sobrien
543696263Sobrien/* AltiVec predicates.  */
543796263Sobrien
543896263Sobrienstruct builtin_description_predicates
543996263Sobrien{
544096263Sobrien  const unsigned int mask;
544196263Sobrien  const enum insn_code icode;
544296263Sobrien  const char *opcode;
544396263Sobrien  const char *const name;
544496263Sobrien  const enum rs6000_builtins code;
544596263Sobrien};
544696263Sobrien
544796263Sobrienstatic const struct builtin_description_predicates bdesc_altivec_preds[] =
544896263Sobrien{
544996263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v4sf, "*vcmpbfp.", "__builtin_altivec_vcmpbfp_p", ALTIVEC_BUILTIN_VCMPBFP_P },
545096263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v4sf, "*vcmpeqfp.", "__builtin_altivec_vcmpeqfp_p", ALTIVEC_BUILTIN_VCMPEQFP_P },
545196263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v4sf, "*vcmpgefp.", "__builtin_altivec_vcmpgefp_p", ALTIVEC_BUILTIN_VCMPGEFP_P },
545296263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v4sf, "*vcmpgtfp.", "__builtin_altivec_vcmpgtfp_p", ALTIVEC_BUILTIN_VCMPGTFP_P },
545396263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v4si, "*vcmpequw.", "__builtin_altivec_vcmpequw_p", ALTIVEC_BUILTIN_VCMPEQUW_P },
545496263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v4si, "*vcmpgtsw.", "__builtin_altivec_vcmpgtsw_p", ALTIVEC_BUILTIN_VCMPGTSW_P },
545596263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v4si, "*vcmpgtuw.", "__builtin_altivec_vcmpgtuw_p", ALTIVEC_BUILTIN_VCMPGTUW_P },
545696263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v8hi, "*vcmpgtuh.", "__builtin_altivec_vcmpgtuh_p", ALTIVEC_BUILTIN_VCMPGTUH_P },
545796263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v8hi, "*vcmpgtsh.", "__builtin_altivec_vcmpgtsh_p", ALTIVEC_BUILTIN_VCMPGTSH_P },
545896263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v8hi, "*vcmpequh.", "__builtin_altivec_vcmpequh_p", ALTIVEC_BUILTIN_VCMPEQUH_P },
545996263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v16qi, "*vcmpequb.", "__builtin_altivec_vcmpequb_p", ALTIVEC_BUILTIN_VCMPEQUB_P },
546096263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v16qi, "*vcmpgtsb.", "__builtin_altivec_vcmpgtsb_p", ALTIVEC_BUILTIN_VCMPGTSB_P },
546196263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v16qi, "*vcmpgtub.", "__builtin_altivec_vcmpgtub_p", ALTIVEC_BUILTIN_VCMPGTUB_P }
546296263Sobrien};
546396263Sobrien
5464117395Skan/* SPE predicates.  */
5465117395Skanstatic struct builtin_description bdesc_spe_predicates[] =
5466117395Skan{
5467117395Skan  /* Place-holder.  Leave as first.  */
5468117395Skan  { 0, CODE_FOR_spe_evcmpeq, "__builtin_spe_evcmpeq", SPE_BUILTIN_EVCMPEQ },
5469117395Skan  { 0, CODE_FOR_spe_evcmpgts, "__builtin_spe_evcmpgts", SPE_BUILTIN_EVCMPGTS },
5470117395Skan  { 0, CODE_FOR_spe_evcmpgtu, "__builtin_spe_evcmpgtu", SPE_BUILTIN_EVCMPGTU },
5471117395Skan  { 0, CODE_FOR_spe_evcmplts, "__builtin_spe_evcmplts", SPE_BUILTIN_EVCMPLTS },
5472117395Skan  { 0, CODE_FOR_spe_evcmpltu, "__builtin_spe_evcmpltu", SPE_BUILTIN_EVCMPLTU },
5473117395Skan  { 0, CODE_FOR_spe_evfscmpeq, "__builtin_spe_evfscmpeq", SPE_BUILTIN_EVFSCMPEQ },
5474117395Skan  { 0, CODE_FOR_spe_evfscmpgt, "__builtin_spe_evfscmpgt", SPE_BUILTIN_EVFSCMPGT },
5475117395Skan  { 0, CODE_FOR_spe_evfscmplt, "__builtin_spe_evfscmplt", SPE_BUILTIN_EVFSCMPLT },
5476117395Skan  { 0, CODE_FOR_spe_evfststeq, "__builtin_spe_evfststeq", SPE_BUILTIN_EVFSTSTEQ },
5477117395Skan  { 0, CODE_FOR_spe_evfststgt, "__builtin_spe_evfststgt", SPE_BUILTIN_EVFSTSTGT },
5478117395Skan  /* Place-holder.  Leave as last.  */
5479117395Skan  { 0, CODE_FOR_spe_evfststlt, "__builtin_spe_evfststlt", SPE_BUILTIN_EVFSTSTLT },
5480117395Skan};
5481117395Skan
5482117395Skan/* SPE evsel predicates.  */
5483117395Skanstatic struct builtin_description bdesc_spe_evsel[] =
5484117395Skan{
5485117395Skan  /* Place-holder.  Leave as first.  */
5486117395Skan  { 0, CODE_FOR_spe_evcmpgts, "__builtin_spe_evsel_gts", SPE_BUILTIN_EVSEL_CMPGTS },
5487117395Skan  { 0, CODE_FOR_spe_evcmpgtu, "__builtin_spe_evsel_gtu", SPE_BUILTIN_EVSEL_CMPGTU },
5488117395Skan  { 0, CODE_FOR_spe_evcmplts, "__builtin_spe_evsel_lts", SPE_BUILTIN_EVSEL_CMPLTS },
5489117395Skan  { 0, CODE_FOR_spe_evcmpltu, "__builtin_spe_evsel_ltu", SPE_BUILTIN_EVSEL_CMPLTU },
5490117395Skan  { 0, CODE_FOR_spe_evcmpeq, "__builtin_spe_evsel_eq", SPE_BUILTIN_EVSEL_CMPEQ },
5491117395Skan  { 0, CODE_FOR_spe_evfscmpgt, "__builtin_spe_evsel_fsgt", SPE_BUILTIN_EVSEL_FSCMPGT },
5492117395Skan  { 0, CODE_FOR_spe_evfscmplt, "__builtin_spe_evsel_fslt", SPE_BUILTIN_EVSEL_FSCMPLT },
5493117395Skan  { 0, CODE_FOR_spe_evfscmpeq, "__builtin_spe_evsel_fseq", SPE_BUILTIN_EVSEL_FSCMPEQ },
5494117395Skan  { 0, CODE_FOR_spe_evfststgt, "__builtin_spe_evsel_fststgt", SPE_BUILTIN_EVSEL_FSTSTGT },
5495117395Skan  { 0, CODE_FOR_spe_evfststlt, "__builtin_spe_evsel_fststlt", SPE_BUILTIN_EVSEL_FSTSTLT },
5496117395Skan  /* Place-holder.  Leave as last.  */
5497117395Skan  { 0, CODE_FOR_spe_evfststeq, "__builtin_spe_evsel_fststeq", SPE_BUILTIN_EVSEL_FSTSTEQ },
5498117395Skan};
5499117395Skan
5500132718Skan/* ABS* operations.  */
550196263Sobrien
550296263Sobrienstatic const struct builtin_description bdesc_abs[] =
550396263Sobrien{
550496263Sobrien  { MASK_ALTIVEC, CODE_FOR_absv4si2, "__builtin_altivec_abs_v4si", ALTIVEC_BUILTIN_ABS_V4SI },
550596263Sobrien  { MASK_ALTIVEC, CODE_FOR_absv8hi2, "__builtin_altivec_abs_v8hi", ALTIVEC_BUILTIN_ABS_V8HI },
550696263Sobrien  { MASK_ALTIVEC, CODE_FOR_absv4sf2, "__builtin_altivec_abs_v4sf", ALTIVEC_BUILTIN_ABS_V4SF },
550796263Sobrien  { MASK_ALTIVEC, CODE_FOR_absv16qi2, "__builtin_altivec_abs_v16qi", ALTIVEC_BUILTIN_ABS_V16QI },
550896263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_abss_v4si, "__builtin_altivec_abss_v4si", ALTIVEC_BUILTIN_ABSS_V4SI },
550996263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_abss_v8hi, "__builtin_altivec_abss_v8hi", ALTIVEC_BUILTIN_ABSS_V8HI },
551096263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_abss_v16qi, "__builtin_altivec_abss_v16qi", ALTIVEC_BUILTIN_ABSS_V16QI }
551196263Sobrien};
551296263Sobrien
551390075Sobrien/* Simple unary operations: VECb = foo (unsigned literal) or VECb =
551490075Sobrien   foo (VECa).  */
551590075Sobrien
5516117395Skanstatic struct builtin_description bdesc_1arg[] =
551790075Sobrien{
551890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vexptefp, "__builtin_altivec_vexptefp", ALTIVEC_BUILTIN_VEXPTEFP },
551990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vlogefp, "__builtin_altivec_vlogefp", ALTIVEC_BUILTIN_VLOGEFP },
552090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vrefp, "__builtin_altivec_vrefp", ALTIVEC_BUILTIN_VREFP },
552190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vrfim, "__builtin_altivec_vrfim", ALTIVEC_BUILTIN_VRFIM },
552290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vrfin, "__builtin_altivec_vrfin", ALTIVEC_BUILTIN_VRFIN },
552390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vrfip, "__builtin_altivec_vrfip", ALTIVEC_BUILTIN_VRFIP },
552490075Sobrien  { MASK_ALTIVEC, CODE_FOR_ftruncv4sf2, "__builtin_altivec_vrfiz", ALTIVEC_BUILTIN_VRFIZ },
552590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vrsqrtefp, "__builtin_altivec_vrsqrtefp", ALTIVEC_BUILTIN_VRSQRTEFP },
552690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vspltisb, "__builtin_altivec_vspltisb", ALTIVEC_BUILTIN_VSPLTISB },
552790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vspltish, "__builtin_altivec_vspltish", ALTIVEC_BUILTIN_VSPLTISH },
552890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vspltisw, "__builtin_altivec_vspltisw", ALTIVEC_BUILTIN_VSPLTISW },
552990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vupkhsb, "__builtin_altivec_vupkhsb", ALTIVEC_BUILTIN_VUPKHSB },
553090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vupkhpx, "__builtin_altivec_vupkhpx", ALTIVEC_BUILTIN_VUPKHPX },
553190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vupkhsh, "__builtin_altivec_vupkhsh", ALTIVEC_BUILTIN_VUPKHSH },
553290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vupklsb, "__builtin_altivec_vupklsb", ALTIVEC_BUILTIN_VUPKLSB },
553390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vupklpx, "__builtin_altivec_vupklpx", ALTIVEC_BUILTIN_VUPKLPX },
553490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vupklsh, "__builtin_altivec_vupklsh", ALTIVEC_BUILTIN_VUPKLSH },
5535117395Skan
5536117395Skan  /* The SPE unary builtins must start with SPE_BUILTIN_EVABS and
5537117395Skan     end with SPE_BUILTIN_EVSUBFUSIAAW.  */
5538117395Skan  { 0, CODE_FOR_spe_evabs, "__builtin_spe_evabs", SPE_BUILTIN_EVABS },
5539117395Skan  { 0, CODE_FOR_spe_evaddsmiaaw, "__builtin_spe_evaddsmiaaw", SPE_BUILTIN_EVADDSMIAAW },
5540117395Skan  { 0, CODE_FOR_spe_evaddssiaaw, "__builtin_spe_evaddssiaaw", SPE_BUILTIN_EVADDSSIAAW },
5541117395Skan  { 0, CODE_FOR_spe_evaddumiaaw, "__builtin_spe_evaddumiaaw", SPE_BUILTIN_EVADDUMIAAW },
5542117395Skan  { 0, CODE_FOR_spe_evaddusiaaw, "__builtin_spe_evaddusiaaw", SPE_BUILTIN_EVADDUSIAAW },
5543117395Skan  { 0, CODE_FOR_spe_evcntlsw, "__builtin_spe_evcntlsw", SPE_BUILTIN_EVCNTLSW },
5544117395Skan  { 0, CODE_FOR_spe_evcntlzw, "__builtin_spe_evcntlzw", SPE_BUILTIN_EVCNTLZW },
5545117395Skan  { 0, CODE_FOR_spe_evextsb, "__builtin_spe_evextsb", SPE_BUILTIN_EVEXTSB },
5546117395Skan  { 0, CODE_FOR_spe_evextsh, "__builtin_spe_evextsh", SPE_BUILTIN_EVEXTSH },
5547117395Skan  { 0, CODE_FOR_spe_evfsabs, "__builtin_spe_evfsabs", SPE_BUILTIN_EVFSABS },
5548117395Skan  { 0, CODE_FOR_spe_evfscfsf, "__builtin_spe_evfscfsf", SPE_BUILTIN_EVFSCFSF },
5549117395Skan  { 0, CODE_FOR_spe_evfscfsi, "__builtin_spe_evfscfsi", SPE_BUILTIN_EVFSCFSI },
5550117395Skan  { 0, CODE_FOR_spe_evfscfuf, "__builtin_spe_evfscfuf", SPE_BUILTIN_EVFSCFUF },
5551117395Skan  { 0, CODE_FOR_spe_evfscfui, "__builtin_spe_evfscfui", SPE_BUILTIN_EVFSCFUI },
5552117395Skan  { 0, CODE_FOR_spe_evfsctsf, "__builtin_spe_evfsctsf", SPE_BUILTIN_EVFSCTSF },
5553117395Skan  { 0, CODE_FOR_spe_evfsctsi, "__builtin_spe_evfsctsi", SPE_BUILTIN_EVFSCTSI },
5554117395Skan  { 0, CODE_FOR_spe_evfsctsiz, "__builtin_spe_evfsctsiz", SPE_BUILTIN_EVFSCTSIZ },
5555117395Skan  { 0, CODE_FOR_spe_evfsctuf, "__builtin_spe_evfsctuf", SPE_BUILTIN_EVFSCTUF },
5556117395Skan  { 0, CODE_FOR_spe_evfsctui, "__builtin_spe_evfsctui", SPE_BUILTIN_EVFSCTUI },
5557117395Skan  { 0, CODE_FOR_spe_evfsctuiz, "__builtin_spe_evfsctuiz", SPE_BUILTIN_EVFSCTUIZ },
5558117395Skan  { 0, CODE_FOR_spe_evfsnabs, "__builtin_spe_evfsnabs", SPE_BUILTIN_EVFSNABS },
5559117395Skan  { 0, CODE_FOR_spe_evfsneg, "__builtin_spe_evfsneg", SPE_BUILTIN_EVFSNEG },
5560117395Skan  { 0, CODE_FOR_spe_evmra, "__builtin_spe_evmra", SPE_BUILTIN_EVMRA },
5561132718Skan  { 0, CODE_FOR_negv2si2, "__builtin_spe_evneg", SPE_BUILTIN_EVNEG },
5562117395Skan  { 0, CODE_FOR_spe_evrndw, "__builtin_spe_evrndw", SPE_BUILTIN_EVRNDW },
5563117395Skan  { 0, CODE_FOR_spe_evsubfsmiaaw, "__builtin_spe_evsubfsmiaaw", SPE_BUILTIN_EVSUBFSMIAAW },
5564117395Skan  { 0, CODE_FOR_spe_evsubfssiaaw, "__builtin_spe_evsubfssiaaw", SPE_BUILTIN_EVSUBFSSIAAW },
5565117395Skan  { 0, CODE_FOR_spe_evsubfumiaaw, "__builtin_spe_evsubfumiaaw", SPE_BUILTIN_EVSUBFUMIAAW },
5566117395Skan
5567117395Skan  /* Place-holder.  Leave as last unary SPE builtin.  */
5568117395Skan  { 0, CODE_FOR_spe_evsubfusiaaw, "__builtin_spe_evsubfusiaaw", SPE_BUILTIN_EVSUBFUSIAAW },
556990075Sobrien};
557090075Sobrien
557190075Sobrienstatic rtx
5572132718Skanrs6000_expand_unop_builtin (enum insn_code icode, tree arglist, rtx target)
557390075Sobrien{
557490075Sobrien  rtx pat;
557590075Sobrien  tree arg0 = TREE_VALUE (arglist);
557690075Sobrien  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
557790075Sobrien  enum machine_mode tmode = insn_data[icode].operand[0].mode;
557890075Sobrien  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
557990075Sobrien
5580117395Skan  if (icode == CODE_FOR_nothing)
5581117395Skan    /* Builtin not supported on this processor.  */
5582117395Skan    return 0;
5583117395Skan
558490075Sobrien  /* If we got invalid arguments bail out before generating bad rtl.  */
558590075Sobrien  if (arg0 == error_mark_node)
5586117395Skan    return const0_rtx;
558790075Sobrien
5588117395Skan  if (icode == CODE_FOR_altivec_vspltisb
5589117395Skan      || icode == CODE_FOR_altivec_vspltish
5590117395Skan      || icode == CODE_FOR_altivec_vspltisw
5591117395Skan      || icode == CODE_FOR_spe_evsplatfi
5592117395Skan      || icode == CODE_FOR_spe_evsplati)
5593117395Skan    {
5594117395Skan      /* Only allow 5-bit *signed* literals.  */
5595117395Skan      if (GET_CODE (op0) != CONST_INT
5596117395Skan	  || INTVAL (op0) > 0x1f
5597117395Skan	  || INTVAL (op0) < -0x1f)
5598117395Skan	{
5599117395Skan	  error ("argument 1 must be a 5-bit signed literal");
5600117395Skan	  return const0_rtx;
5601117395Skan	}
5602117395Skan    }
5603117395Skan
560490075Sobrien  if (target == 0
560590075Sobrien      || GET_MODE (target) != tmode
560690075Sobrien      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
560790075Sobrien    target = gen_reg_rtx (tmode);
560890075Sobrien
560990075Sobrien  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
561090075Sobrien    op0 = copy_to_mode_reg (mode0, op0);
561190075Sobrien
561290075Sobrien  pat = GEN_FCN (icode) (target, op0);
561390075Sobrien  if (! pat)
561490075Sobrien    return 0;
561590075Sobrien  emit_insn (pat);
561690075Sobrien
561790075Sobrien  return target;
561890075Sobrien}
561996263Sobrien
562090075Sobrienstatic rtx
5621132718Skanaltivec_expand_abs_builtin (enum insn_code icode, tree arglist, rtx target)
562296263Sobrien{
562396263Sobrien  rtx pat, scratch1, scratch2;
562496263Sobrien  tree arg0 = TREE_VALUE (arglist);
562596263Sobrien  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
562696263Sobrien  enum machine_mode tmode = insn_data[icode].operand[0].mode;
562796263Sobrien  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
562896263Sobrien
562996263Sobrien  /* If we have invalid arguments, bail out before generating bad rtl.  */
563096263Sobrien  if (arg0 == error_mark_node)
5631117395Skan    return const0_rtx;
563296263Sobrien
563396263Sobrien  if (target == 0
563496263Sobrien      || GET_MODE (target) != tmode
563596263Sobrien      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
563696263Sobrien    target = gen_reg_rtx (tmode);
563796263Sobrien
563896263Sobrien  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
563996263Sobrien    op0 = copy_to_mode_reg (mode0, op0);
564096263Sobrien
564196263Sobrien  scratch1 = gen_reg_rtx (mode0);
564296263Sobrien  scratch2 = gen_reg_rtx (mode0);
564396263Sobrien
564496263Sobrien  pat = GEN_FCN (icode) (target, op0, scratch1, scratch2);
564596263Sobrien  if (! pat)
564696263Sobrien    return 0;
564796263Sobrien  emit_insn (pat);
564896263Sobrien
564996263Sobrien  return target;
565096263Sobrien}
565196263Sobrien
565296263Sobrienstatic rtx
5653132718Skanrs6000_expand_binop_builtin (enum insn_code icode, tree arglist, rtx target)
565490075Sobrien{
565590075Sobrien  rtx pat;
565690075Sobrien  tree arg0 = TREE_VALUE (arglist);
565790075Sobrien  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
565890075Sobrien  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
565990075Sobrien  rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
566090075Sobrien  enum machine_mode tmode = insn_data[icode].operand[0].mode;
566190075Sobrien  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
566290075Sobrien  enum machine_mode mode1 = insn_data[icode].operand[2].mode;
566390075Sobrien
5664117395Skan  if (icode == CODE_FOR_nothing)
5665117395Skan    /* Builtin not supported on this processor.  */
5666117395Skan    return 0;
5667117395Skan
566890075Sobrien  /* If we got invalid arguments bail out before generating bad rtl.  */
566990075Sobrien  if (arg0 == error_mark_node || arg1 == error_mark_node)
5670117395Skan    return const0_rtx;
567190075Sobrien
5672117395Skan  if (icode == CODE_FOR_altivec_vcfux
5673117395Skan      || icode == CODE_FOR_altivec_vcfsx
5674117395Skan      || icode == CODE_FOR_altivec_vctsxs
5675117395Skan      || icode == CODE_FOR_altivec_vctuxs
5676117395Skan      || icode == CODE_FOR_altivec_vspltb
5677117395Skan      || icode == CODE_FOR_altivec_vsplth
5678117395Skan      || icode == CODE_FOR_altivec_vspltw
5679117395Skan      || icode == CODE_FOR_spe_evaddiw
5680117395Skan      || icode == CODE_FOR_spe_evldd
5681117395Skan      || icode == CODE_FOR_spe_evldh
5682117395Skan      || icode == CODE_FOR_spe_evldw
5683117395Skan      || icode == CODE_FOR_spe_evlhhesplat
5684117395Skan      || icode == CODE_FOR_spe_evlhhossplat
5685117395Skan      || icode == CODE_FOR_spe_evlhhousplat
5686117395Skan      || icode == CODE_FOR_spe_evlwhe
5687117395Skan      || icode == CODE_FOR_spe_evlwhos
5688117395Skan      || icode == CODE_FOR_spe_evlwhou
5689117395Skan      || icode == CODE_FOR_spe_evlwhsplat
5690117395Skan      || icode == CODE_FOR_spe_evlwwsplat
5691117395Skan      || icode == CODE_FOR_spe_evrlwi
5692117395Skan      || icode == CODE_FOR_spe_evslwi
5693117395Skan      || icode == CODE_FOR_spe_evsrwis
5694132718Skan      || icode == CODE_FOR_spe_evsubifw
5695117395Skan      || icode == CODE_FOR_spe_evsrwiu)
5696117395Skan    {
5697117395Skan      /* Only allow 5-bit unsigned literals.  */
5698117395Skan      if (TREE_CODE (arg1) != INTEGER_CST
5699117395Skan	  || TREE_INT_CST_LOW (arg1) & ~0x1f)
5700117395Skan	{
5701117395Skan	  error ("argument 2 must be a 5-bit unsigned literal");
5702117395Skan	  return const0_rtx;
5703117395Skan	}
5704117395Skan    }
5705117395Skan
570690075Sobrien  if (target == 0
570790075Sobrien      || GET_MODE (target) != tmode
570890075Sobrien      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
570990075Sobrien    target = gen_reg_rtx (tmode);
571090075Sobrien
571190075Sobrien  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
571290075Sobrien    op0 = copy_to_mode_reg (mode0, op0);
571390075Sobrien  if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
571490075Sobrien    op1 = copy_to_mode_reg (mode1, op1);
571590075Sobrien
571690075Sobrien  pat = GEN_FCN (icode) (target, op0, op1);
571790075Sobrien  if (! pat)
571890075Sobrien    return 0;
571990075Sobrien  emit_insn (pat);
572090075Sobrien
572190075Sobrien  return target;
572290075Sobrien}
572390075Sobrien
572490075Sobrienstatic rtx
5725132718Skanaltivec_expand_predicate_builtin (enum insn_code icode, const char *opcode,
5726132718Skan				  tree arglist, rtx target)
572796263Sobrien{
572896263Sobrien  rtx pat, scratch;
572996263Sobrien  tree cr6_form = TREE_VALUE (arglist);
573096263Sobrien  tree arg0 = TREE_VALUE (TREE_CHAIN (arglist));
573196263Sobrien  tree arg1 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
573296263Sobrien  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
573396263Sobrien  rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
573496263Sobrien  enum machine_mode tmode = SImode;
573596263Sobrien  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
573696263Sobrien  enum machine_mode mode1 = insn_data[icode].operand[2].mode;
573796263Sobrien  int cr6_form_int;
573896263Sobrien
573996263Sobrien  if (TREE_CODE (cr6_form) != INTEGER_CST)
574096263Sobrien    {
574196263Sobrien      error ("argument 1 of __builtin_altivec_predicate must be a constant");
5742117395Skan      return const0_rtx;
574396263Sobrien    }
574496263Sobrien  else
574596263Sobrien    cr6_form_int = TREE_INT_CST_LOW (cr6_form);
574696263Sobrien
574796263Sobrien  if (mode0 != mode1)
574896263Sobrien    abort ();
574996263Sobrien
575096263Sobrien  /* If we have invalid arguments, bail out before generating bad rtl.  */
575196263Sobrien  if (arg0 == error_mark_node || arg1 == error_mark_node)
5752117395Skan    return const0_rtx;
575396263Sobrien
575496263Sobrien  if (target == 0
575596263Sobrien      || GET_MODE (target) != tmode
575696263Sobrien      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
575796263Sobrien    target = gen_reg_rtx (tmode);
575896263Sobrien
575996263Sobrien  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
576096263Sobrien    op0 = copy_to_mode_reg (mode0, op0);
576196263Sobrien  if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
576296263Sobrien    op1 = copy_to_mode_reg (mode1, op1);
576396263Sobrien
576496263Sobrien  scratch = gen_reg_rtx (mode0);
576596263Sobrien
576696263Sobrien  pat = GEN_FCN (icode) (scratch, op0, op1,
576796263Sobrien			 gen_rtx (SYMBOL_REF, Pmode, opcode));
576896263Sobrien  if (! pat)
576996263Sobrien    return 0;
577096263Sobrien  emit_insn (pat);
577196263Sobrien
577296263Sobrien  /* The vec_any* and vec_all* predicates use the same opcodes for two
577396263Sobrien     different operations, but the bits in CR6 will be different
577496263Sobrien     depending on what information we want.  So we have to play tricks
577596263Sobrien     with CR6 to get the right bits out.
577696263Sobrien
577796263Sobrien     If you think this is disgusting, look at the specs for the
577896263Sobrien     AltiVec predicates.  */
577996263Sobrien
578096263Sobrien     switch (cr6_form_int)
578196263Sobrien       {
578296263Sobrien       case 0:
578396263Sobrien	 emit_insn (gen_cr6_test_for_zero (target));
578496263Sobrien	 break;
578596263Sobrien       case 1:
578696263Sobrien	 emit_insn (gen_cr6_test_for_zero_reverse (target));
578796263Sobrien	 break;
578896263Sobrien       case 2:
578996263Sobrien	 emit_insn (gen_cr6_test_for_lt (target));
579096263Sobrien	 break;
579196263Sobrien       case 3:
579296263Sobrien	 emit_insn (gen_cr6_test_for_lt_reverse (target));
579396263Sobrien	 break;
579496263Sobrien       default:
579596263Sobrien	 error ("argument 1 of __builtin_altivec_predicate is out of range");
579696263Sobrien	 break;
579796263Sobrien       }
579896263Sobrien
579996263Sobrien  return target;
580096263Sobrien}
580196263Sobrien
580296263Sobrienstatic rtx
5803132718Skanaltivec_expand_lv_builtin (enum insn_code icode, tree arglist, rtx target)
580490075Sobrien{
5805132718Skan  rtx pat, addr;
580690075Sobrien  tree arg0 = TREE_VALUE (arglist);
580790075Sobrien  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
5808132718Skan  enum machine_mode tmode = insn_data[icode].operand[0].mode;
5809132718Skan  enum machine_mode mode0 = Pmode;
5810132718Skan  enum machine_mode mode1 = Pmode;
5811132718Skan  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
5812132718Skan  rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
5813132718Skan
5814132718Skan  if (icode == CODE_FOR_nothing)
5815132718Skan    /* Builtin not supported on this processor.  */
5816132718Skan    return 0;
5817132718Skan
5818132718Skan  /* If we got invalid arguments bail out before generating bad rtl.  */
5819132718Skan  if (arg0 == error_mark_node || arg1 == error_mark_node)
5820132718Skan    return const0_rtx;
5821132718Skan
5822132718Skan  if (target == 0
5823132718Skan      || GET_MODE (target) != tmode
5824132718Skan      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
5825132718Skan    target = gen_reg_rtx (tmode);
5826132718Skan
5827132718Skan  op1 = copy_to_mode_reg (mode1, op1);
5828132718Skan
5829132718Skan  if (op0 == const0_rtx)
5830132718Skan    {
5831132718Skan      addr = gen_rtx_MEM (tmode, op1);
5832132718Skan    }
5833132718Skan  else
5834132718Skan    {
5835132718Skan      op0 = copy_to_mode_reg (mode0, op0);
5836132718Skan      addr = gen_rtx_MEM (tmode, gen_rtx_PLUS (Pmode, op0, op1));
5837132718Skan    }
5838132718Skan
5839132718Skan  pat = GEN_FCN (icode) (target, addr);
5840132718Skan
5841132718Skan  if (! pat)
5842132718Skan    return 0;
5843132718Skan  emit_insn (pat);
5844132718Skan
5845132718Skan  return target;
5846132718Skan}
5847132718Skan
5848132718Skanstatic rtx
5849132718Skanspe_expand_stv_builtin (enum insn_code icode, tree arglist)
5850132718Skan{
5851132718Skan  tree arg0 = TREE_VALUE (arglist);
5852132718Skan  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
585390075Sobrien  tree arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
585490075Sobrien  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
585590075Sobrien  rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
585690075Sobrien  rtx op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
585790075Sobrien  rtx pat;
585890075Sobrien  enum machine_mode mode0 = insn_data[icode].operand[0].mode;
585990075Sobrien  enum machine_mode mode1 = insn_data[icode].operand[1].mode;
586090075Sobrien  enum machine_mode mode2 = insn_data[icode].operand[2].mode;
586190075Sobrien
586290075Sobrien  /* Invalid arguments.  Bail before doing anything stoopid!  */
586390075Sobrien  if (arg0 == error_mark_node
586490075Sobrien      || arg1 == error_mark_node
586590075Sobrien      || arg2 == error_mark_node)
5866117395Skan    return const0_rtx;
586790075Sobrien
586890075Sobrien  if (! (*insn_data[icode].operand[2].predicate) (op0, mode2))
586990075Sobrien    op0 = copy_to_mode_reg (mode2, op0);
587090075Sobrien  if (! (*insn_data[icode].operand[0].predicate) (op1, mode0))
587190075Sobrien    op1 = copy_to_mode_reg (mode0, op1);
587290075Sobrien  if (! (*insn_data[icode].operand[1].predicate) (op2, mode1))
587390075Sobrien    op2 = copy_to_mode_reg (mode1, op2);
587490075Sobrien
587590075Sobrien  pat = GEN_FCN (icode) (op1, op2, op0);
587690075Sobrien  if (pat)
587790075Sobrien    emit_insn (pat);
587890075Sobrien  return NULL_RTX;
587990075Sobrien}
588090075Sobrien
588190075Sobrienstatic rtx
5882132718Skanaltivec_expand_stv_builtin (enum insn_code icode, tree arglist)
588390075Sobrien{
5884132718Skan  tree arg0 = TREE_VALUE (arglist);
5885132718Skan  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
5886132718Skan  tree arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
5887132718Skan  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
5888132718Skan  rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
5889132718Skan  rtx op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
5890132718Skan  rtx pat, addr;
5891132718Skan  enum machine_mode tmode = insn_data[icode].operand[0].mode;
5892132718Skan  enum machine_mode mode1 = Pmode;
5893132718Skan  enum machine_mode mode2 = Pmode;
5894132718Skan
5895132718Skan  /* Invalid arguments.  Bail before doing anything stoopid!  */
5896132718Skan  if (arg0 == error_mark_node
5897132718Skan      || arg1 == error_mark_node
5898132718Skan      || arg2 == error_mark_node)
5899132718Skan    return const0_rtx;
5900132718Skan
5901132718Skan  if (! (*insn_data[icode].operand[1].predicate) (op0, tmode))
5902132718Skan    op0 = copy_to_mode_reg (tmode, op0);
5903132718Skan
5904132718Skan  op2 = copy_to_mode_reg (mode2, op2);
5905132718Skan
5906132718Skan  if (op1 == const0_rtx)
5907132718Skan    {
5908132718Skan      addr = gen_rtx_MEM (tmode, op2);
5909132718Skan    }
5910132718Skan  else
5911132718Skan    {
5912132718Skan      op1 = copy_to_mode_reg (mode1, op1);
5913132718Skan      addr = gen_rtx_MEM (tmode, gen_rtx_PLUS (Pmode, op1, op2));
5914132718Skan    }
5915132718Skan
5916132718Skan  pat = GEN_FCN (icode) (addr, op0);
5917132718Skan  if (pat)
5918132718Skan    emit_insn (pat);
5919132718Skan  return NULL_RTX;
5920132718Skan}
5921132718Skan
5922132718Skanstatic rtx
5923132718Skanrs6000_expand_ternop_builtin (enum insn_code icode, tree arglist, rtx target)
5924132718Skan{
592590075Sobrien  rtx pat;
592690075Sobrien  tree arg0 = TREE_VALUE (arglist);
592790075Sobrien  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
592890075Sobrien  tree arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
592990075Sobrien  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
593090075Sobrien  rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
593190075Sobrien  rtx op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
593290075Sobrien  enum machine_mode tmode = insn_data[icode].operand[0].mode;
593390075Sobrien  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
593490075Sobrien  enum machine_mode mode1 = insn_data[icode].operand[2].mode;
593590075Sobrien  enum machine_mode mode2 = insn_data[icode].operand[3].mode;
593690075Sobrien
5937117395Skan  if (icode == CODE_FOR_nothing)
5938117395Skan    /* Builtin not supported on this processor.  */
5939117395Skan    return 0;
5940117395Skan
594190075Sobrien  /* If we got invalid arguments bail out before generating bad rtl.  */
594290075Sobrien  if (arg0 == error_mark_node
594390075Sobrien      || arg1 == error_mark_node
594490075Sobrien      || arg2 == error_mark_node)
5945117395Skan    return const0_rtx;
594690075Sobrien
5947117395Skan  if (icode == CODE_FOR_altivec_vsldoi_4sf
5948117395Skan      || icode == CODE_FOR_altivec_vsldoi_4si
5949117395Skan      || icode == CODE_FOR_altivec_vsldoi_8hi
5950117395Skan      || icode == CODE_FOR_altivec_vsldoi_16qi)
5951117395Skan    {
5952117395Skan      /* Only allow 4-bit unsigned literals.  */
5953117395Skan      if (TREE_CODE (arg2) != INTEGER_CST
5954117395Skan	  || TREE_INT_CST_LOW (arg2) & ~0xf)
5955117395Skan	{
5956117395Skan	  error ("argument 3 must be a 4-bit unsigned literal");
5957117395Skan	  return const0_rtx;
5958117395Skan	}
5959117395Skan    }
5960117395Skan
596190075Sobrien  if (target == 0
596290075Sobrien      || GET_MODE (target) != tmode
596390075Sobrien      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
596490075Sobrien    target = gen_reg_rtx (tmode);
596590075Sobrien
596690075Sobrien  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
596790075Sobrien    op0 = copy_to_mode_reg (mode0, op0);
596890075Sobrien  if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
596990075Sobrien    op1 = copy_to_mode_reg (mode1, op1);
597090075Sobrien  if (! (*insn_data[icode].operand[3].predicate) (op2, mode2))
597190075Sobrien    op2 = copy_to_mode_reg (mode2, op2);
597290075Sobrien
597390075Sobrien  pat = GEN_FCN (icode) (target, op0, op1, op2);
597490075Sobrien  if (! pat)
597590075Sobrien    return 0;
597690075Sobrien  emit_insn (pat);
597790075Sobrien
597890075Sobrien  return target;
597990075Sobrien}
5980117395Skan
5981117395Skan/* Expand the lvx builtins.  */
598290075Sobrienstatic rtx
5983132718Skanaltivec_expand_ld_builtin (tree exp, rtx target, bool *expandedp)
598490075Sobrien{
598590075Sobrien  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
598690075Sobrien  tree arglist = TREE_OPERAND (exp, 1);
598790075Sobrien  unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
5988117395Skan  tree arg0;
5989117395Skan  enum machine_mode tmode, mode0;
5990117395Skan  rtx pat, op0;
5991117395Skan  enum insn_code icode;
5992117395Skan
599390075Sobrien  switch (fcode)
599490075Sobrien    {
599590075Sobrien    case ALTIVEC_BUILTIN_LD_INTERNAL_16qi:
599690075Sobrien      icode = CODE_FOR_altivec_lvx_16qi;
5997117395Skan      break;
5998117395Skan    case ALTIVEC_BUILTIN_LD_INTERNAL_8hi:
5999117395Skan      icode = CODE_FOR_altivec_lvx_8hi;
6000117395Skan      break;
6001117395Skan    case ALTIVEC_BUILTIN_LD_INTERNAL_4si:
6002117395Skan      icode = CODE_FOR_altivec_lvx_4si;
6003117395Skan      break;
6004117395Skan    case ALTIVEC_BUILTIN_LD_INTERNAL_4sf:
6005117395Skan      icode = CODE_FOR_altivec_lvx_4sf;
6006117395Skan      break;
6007117395Skan    default:
6008117395Skan      *expandedp = false;
6009117395Skan      return NULL_RTX;
6010117395Skan    }
601190075Sobrien
6012117395Skan  *expandedp = true;
601390075Sobrien
6014117395Skan  arg0 = TREE_VALUE (arglist);
6015117395Skan  op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6016117395Skan  tmode = insn_data[icode].operand[0].mode;
6017117395Skan  mode0 = insn_data[icode].operand[1].mode;
601890075Sobrien
6019117395Skan  if (target == 0
6020117395Skan      || GET_MODE (target) != tmode
6021117395Skan      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
6022117395Skan    target = gen_reg_rtx (tmode);
602390075Sobrien
6024117395Skan  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
6025117395Skan    op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
602690075Sobrien
6027117395Skan  pat = GEN_FCN (icode) (target, op0);
6028117395Skan  if (! pat)
6029117395Skan    return 0;
6030117395Skan  emit_insn (pat);
6031117395Skan  return target;
6032117395Skan}
603390075Sobrien
6034117395Skan/* Expand the stvx builtins.  */
6035117395Skanstatic rtx
6036132718Skanaltivec_expand_st_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
6037132718Skan			   bool *expandedp)
6038117395Skan{
6039117395Skan  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
6040117395Skan  tree arglist = TREE_OPERAND (exp, 1);
6041117395Skan  unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
6042117395Skan  tree arg0, arg1;
6043117395Skan  enum machine_mode mode0, mode1;
6044117395Skan  rtx pat, op0, op1;
6045117395Skan  enum insn_code icode;
604690075Sobrien
6047117395Skan  switch (fcode)
6048117395Skan    {
6049117395Skan    case ALTIVEC_BUILTIN_ST_INTERNAL_16qi:
6050117395Skan      icode = CODE_FOR_altivec_stvx_16qi;
6051117395Skan      break;
6052117395Skan    case ALTIVEC_BUILTIN_ST_INTERNAL_8hi:
6053117395Skan      icode = CODE_FOR_altivec_stvx_8hi;
6054117395Skan      break;
6055117395Skan    case ALTIVEC_BUILTIN_ST_INTERNAL_4si:
6056117395Skan      icode = CODE_FOR_altivec_stvx_4si;
6057117395Skan      break;
6058117395Skan    case ALTIVEC_BUILTIN_ST_INTERNAL_4sf:
6059117395Skan      icode = CODE_FOR_altivec_stvx_4sf;
6060117395Skan      break;
6061117395Skan    default:
6062117395Skan      *expandedp = false;
6063117395Skan      return NULL_RTX;
6064117395Skan    }
606590075Sobrien
6066117395Skan  arg0 = TREE_VALUE (arglist);
6067117395Skan  arg1 = TREE_VALUE (TREE_CHAIN (arglist));
6068117395Skan  op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6069117395Skan  op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
6070117395Skan  mode0 = insn_data[icode].operand[0].mode;
6071117395Skan  mode1 = insn_data[icode].operand[1].mode;
607290075Sobrien
6073117395Skan  if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
6074117395Skan    op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
6075117395Skan  if (! (*insn_data[icode].operand[1].predicate) (op1, mode1))
6076117395Skan    op1 = copy_to_mode_reg (mode1, op1);
607790075Sobrien
6078117395Skan  pat = GEN_FCN (icode) (op0, op1);
6079117395Skan  if (pat)
6080117395Skan    emit_insn (pat);
608190075Sobrien
6082117395Skan  *expandedp = true;
6083117395Skan  return NULL_RTX;
6084117395Skan}
608590075Sobrien
6086117395Skan/* Expand the dst builtins.  */
6087117395Skanstatic rtx
6088132718Skanaltivec_expand_dst_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
6089132718Skan			    bool *expandedp)
6090117395Skan{
6091117395Skan  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
6092117395Skan  tree arglist = TREE_OPERAND (exp, 1);
6093117395Skan  unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
6094117395Skan  tree arg0, arg1, arg2;
6095117395Skan  enum machine_mode mode0, mode1, mode2;
6096117395Skan  rtx pat, op0, op1, op2;
6097117395Skan  struct builtin_description *d;
6098117395Skan  size_t i;
609990075Sobrien
6100117395Skan  *expandedp = false;
610190075Sobrien
6102117395Skan  /* Handle DST variants.  */
6103117395Skan  d = (struct builtin_description *) bdesc_dst;
6104117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_dst); i++, d++)
6105117395Skan    if (d->code == fcode)
6106117395Skan      {
6107117395Skan	arg0 = TREE_VALUE (arglist);
6108117395Skan	arg1 = TREE_VALUE (TREE_CHAIN (arglist));
6109117395Skan	arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
6110117395Skan	op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6111117395Skan	op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
6112117395Skan	op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
6113117395Skan	mode0 = insn_data[d->icode].operand[0].mode;
6114117395Skan	mode1 = insn_data[d->icode].operand[1].mode;
6115117395Skan	mode2 = insn_data[d->icode].operand[2].mode;
611690075Sobrien
6117117395Skan	/* Invalid arguments, bail out before generating bad rtl.  */
6118117395Skan	if (arg0 == error_mark_node
6119117395Skan	    || arg1 == error_mark_node
6120117395Skan	    || arg2 == error_mark_node)
6121117395Skan	  return const0_rtx;
612290075Sobrien
6123117395Skan	if (TREE_CODE (arg2) != INTEGER_CST
6124117395Skan	    || TREE_INT_CST_LOW (arg2) & ~0x3)
6125117395Skan	  {
6126117395Skan	    error ("argument to `%s' must be a 2-bit unsigned literal", d->name);
6127117395Skan	    return const0_rtx;
6128117395Skan	  }
612990075Sobrien
6130117395Skan	if (! (*insn_data[d->icode].operand[0].predicate) (op0, mode0))
6131132718Skan	  op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
6132117395Skan	if (! (*insn_data[d->icode].operand[1].predicate) (op1, mode1))
6133117395Skan	  op1 = copy_to_mode_reg (mode1, op1);
613490075Sobrien
6135117395Skan	pat = GEN_FCN (d->icode) (op0, op1, op2);
6136117395Skan	if (pat != 0)
6137117395Skan	  emit_insn (pat);
613890075Sobrien
6139117395Skan	*expandedp = true;
6140117395Skan	return NULL_RTX;
6141117395Skan      }
614290075Sobrien
6143117395Skan  return NULL_RTX;
6144117395Skan}
614590075Sobrien
6146117395Skan/* Expand the builtin in EXP and store the result in TARGET.  Store
6147117395Skan   true in *EXPANDEDP if we found a builtin to expand.  */
6148117395Skanstatic rtx
6149132718Skanaltivec_expand_builtin (tree exp, rtx target, bool *expandedp)
6150117395Skan{
6151117395Skan  struct builtin_description *d;
6152117395Skan  struct builtin_description_predicates *dp;
6153117395Skan  size_t i;
6154117395Skan  enum insn_code icode;
6155117395Skan  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
6156117395Skan  tree arglist = TREE_OPERAND (exp, 1);
6157117395Skan  tree arg0;
6158117395Skan  rtx op0, pat;
6159117395Skan  enum machine_mode tmode, mode0;
6160117395Skan  unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
616190075Sobrien
6162117395Skan  target = altivec_expand_ld_builtin (exp, target, expandedp);
6163117395Skan  if (*expandedp)
6164117395Skan    return target;
616590075Sobrien
6166117395Skan  target = altivec_expand_st_builtin (exp, target, expandedp);
6167117395Skan  if (*expandedp)
6168117395Skan    return target;
616990075Sobrien
6170117395Skan  target = altivec_expand_dst_builtin (exp, target, expandedp);
6171117395Skan  if (*expandedp)
6172117395Skan    return target;
617390075Sobrien
6174117395Skan  *expandedp = true;
617590075Sobrien
6176117395Skan  switch (fcode)
6177117395Skan    {
617890075Sobrien    case ALTIVEC_BUILTIN_STVX:
617990075Sobrien      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvx, arglist);
618090075Sobrien    case ALTIVEC_BUILTIN_STVEBX:
618190075Sobrien      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvebx, arglist);
618290075Sobrien    case ALTIVEC_BUILTIN_STVEHX:
618390075Sobrien      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvehx, arglist);
618490075Sobrien    case ALTIVEC_BUILTIN_STVEWX:
618590075Sobrien      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvewx, arglist);
618690075Sobrien    case ALTIVEC_BUILTIN_STVXL:
618790075Sobrien      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvxl, arglist);
6188117395Skan
618990075Sobrien    case ALTIVEC_BUILTIN_MFVSCR:
619090075Sobrien      icode = CODE_FOR_altivec_mfvscr;
619190075Sobrien      tmode = insn_data[icode].operand[0].mode;
619290075Sobrien
619390075Sobrien      if (target == 0
619490075Sobrien	  || GET_MODE (target) != tmode
619590075Sobrien	  || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
619690075Sobrien	target = gen_reg_rtx (tmode);
619790075Sobrien
619890075Sobrien      pat = GEN_FCN (icode) (target);
619990075Sobrien      if (! pat)
620090075Sobrien	return 0;
620190075Sobrien      emit_insn (pat);
620290075Sobrien      return target;
620390075Sobrien
620490075Sobrien    case ALTIVEC_BUILTIN_MTVSCR:
620590075Sobrien      icode = CODE_FOR_altivec_mtvscr;
620690075Sobrien      arg0 = TREE_VALUE (arglist);
620790075Sobrien      op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
620890075Sobrien      mode0 = insn_data[icode].operand[0].mode;
620990075Sobrien
621090075Sobrien      /* If we got invalid arguments bail out before generating bad rtl.  */
621190075Sobrien      if (arg0 == error_mark_node)
6212117395Skan	return const0_rtx;
621390075Sobrien
621490075Sobrien      if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
621590075Sobrien	op0 = copy_to_mode_reg (mode0, op0);
621690075Sobrien
621790075Sobrien      pat = GEN_FCN (icode) (op0);
621890075Sobrien      if (pat)
621990075Sobrien	emit_insn (pat);
622090075Sobrien      return NULL_RTX;
6221117395Skan
622290075Sobrien    case ALTIVEC_BUILTIN_DSSALL:
622390075Sobrien      emit_insn (gen_altivec_dssall ());
622490075Sobrien      return NULL_RTX;
622590075Sobrien
622690075Sobrien    case ALTIVEC_BUILTIN_DSS:
622790075Sobrien      icode = CODE_FOR_altivec_dss;
622890075Sobrien      arg0 = TREE_VALUE (arglist);
622990075Sobrien      op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
623090075Sobrien      mode0 = insn_data[icode].operand[0].mode;
623190075Sobrien
623290075Sobrien      /* If we got invalid arguments bail out before generating bad rtl.  */
623390075Sobrien      if (arg0 == error_mark_node)
6234117395Skan	return const0_rtx;
623590075Sobrien
6236117395Skan      if (TREE_CODE (arg0) != INTEGER_CST
6237117395Skan	  || TREE_INT_CST_LOW (arg0) & ~0x3)
6238117395Skan	{
6239117395Skan	  error ("argument to dss must be a 2-bit unsigned literal");
6240117395Skan	  return const0_rtx;
6241117395Skan	}
6242117395Skan
624390075Sobrien      if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
624490075Sobrien	op0 = copy_to_mode_reg (mode0, op0);
624590075Sobrien
624690075Sobrien      emit_insn (gen_altivec_dss (op0));
624790075Sobrien      return NULL_RTX;
624890075Sobrien    }
624990075Sobrien
625096263Sobrien  /* Expand abs* operations.  */
625196263Sobrien  d = (struct builtin_description *) bdesc_abs;
6252117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_abs); i++, d++)
625396263Sobrien    if (d->code == fcode)
625496263Sobrien      return altivec_expand_abs_builtin (d->icode, arglist, target);
625596263Sobrien
625696263Sobrien  /* Expand the AltiVec predicates.  */
625796263Sobrien  dp = (struct builtin_description_predicates *) bdesc_altivec_preds;
6258117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_altivec_preds); i++, dp++)
625996263Sobrien    if (dp->code == fcode)
626096263Sobrien      return altivec_expand_predicate_builtin (dp->icode, dp->opcode, arglist, target);
626196263Sobrien
626290075Sobrien  /* LV* are funky.  We initialized them differently.  */
626390075Sobrien  switch (fcode)
626490075Sobrien    {
626590075Sobrien    case ALTIVEC_BUILTIN_LVSL:
6266132718Skan      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvsl,
626790075Sobrien					   arglist, target);
626890075Sobrien    case ALTIVEC_BUILTIN_LVSR:
6269132718Skan      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvsr,
6270117395Skan					  arglist, target);
627190075Sobrien    case ALTIVEC_BUILTIN_LVEBX:
6272132718Skan      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvebx,
6273117395Skan					  arglist, target);
627490075Sobrien    case ALTIVEC_BUILTIN_LVEHX:
6275132718Skan      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvehx,
6276117395Skan					  arglist, target);
627790075Sobrien    case ALTIVEC_BUILTIN_LVEWX:
6278132718Skan      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvewx,
6279117395Skan					  arglist, target);
628090075Sobrien    case ALTIVEC_BUILTIN_LVXL:
6281132718Skan      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvxl,
6282117395Skan					  arglist, target);
628390075Sobrien    case ALTIVEC_BUILTIN_LVX:
6284132718Skan      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvx,
6285117395Skan					  arglist, target);
628690075Sobrien    default:
628790075Sobrien      break;
628890075Sobrien      /* Fall through.  */
628990075Sobrien    }
629090075Sobrien
6291117395Skan  *expandedp = false;
6292117395Skan  return NULL_RTX;
6293117395Skan}
6294117395Skan
6295117395Skan/* Binops that need to be initialized manually, but can be expanded
6296117395Skan   automagically by rs6000_expand_binop_builtin.  */
6297117395Skanstatic struct builtin_description bdesc_2arg_spe[] =
6298117395Skan{
6299117395Skan  { 0, CODE_FOR_spe_evlddx, "__builtin_spe_evlddx", SPE_BUILTIN_EVLDDX },
6300117395Skan  { 0, CODE_FOR_spe_evldwx, "__builtin_spe_evldwx", SPE_BUILTIN_EVLDWX },
6301117395Skan  { 0, CODE_FOR_spe_evldhx, "__builtin_spe_evldhx", SPE_BUILTIN_EVLDHX },
6302117395Skan  { 0, CODE_FOR_spe_evlwhex, "__builtin_spe_evlwhex", SPE_BUILTIN_EVLWHEX },
6303117395Skan  { 0, CODE_FOR_spe_evlwhoux, "__builtin_spe_evlwhoux", SPE_BUILTIN_EVLWHOUX },
6304117395Skan  { 0, CODE_FOR_spe_evlwhosx, "__builtin_spe_evlwhosx", SPE_BUILTIN_EVLWHOSX },
6305117395Skan  { 0, CODE_FOR_spe_evlwwsplatx, "__builtin_spe_evlwwsplatx", SPE_BUILTIN_EVLWWSPLATX },
6306117395Skan  { 0, CODE_FOR_spe_evlwhsplatx, "__builtin_spe_evlwhsplatx", SPE_BUILTIN_EVLWHSPLATX },
6307117395Skan  { 0, CODE_FOR_spe_evlhhesplatx, "__builtin_spe_evlhhesplatx", SPE_BUILTIN_EVLHHESPLATX },
6308117395Skan  { 0, CODE_FOR_spe_evlhhousplatx, "__builtin_spe_evlhhousplatx", SPE_BUILTIN_EVLHHOUSPLATX },
6309117395Skan  { 0, CODE_FOR_spe_evlhhossplatx, "__builtin_spe_evlhhossplatx", SPE_BUILTIN_EVLHHOSSPLATX },
6310117395Skan  { 0, CODE_FOR_spe_evldd, "__builtin_spe_evldd", SPE_BUILTIN_EVLDD },
6311117395Skan  { 0, CODE_FOR_spe_evldw, "__builtin_spe_evldw", SPE_BUILTIN_EVLDW },
6312117395Skan  { 0, CODE_FOR_spe_evldh, "__builtin_spe_evldh", SPE_BUILTIN_EVLDH },
6313117395Skan  { 0, CODE_FOR_spe_evlwhe, "__builtin_spe_evlwhe", SPE_BUILTIN_EVLWHE },
6314117395Skan  { 0, CODE_FOR_spe_evlwhou, "__builtin_spe_evlwhou", SPE_BUILTIN_EVLWHOU },
6315117395Skan  { 0, CODE_FOR_spe_evlwhos, "__builtin_spe_evlwhos", SPE_BUILTIN_EVLWHOS },
6316117395Skan  { 0, CODE_FOR_spe_evlwwsplat, "__builtin_spe_evlwwsplat", SPE_BUILTIN_EVLWWSPLAT },
6317117395Skan  { 0, CODE_FOR_spe_evlwhsplat, "__builtin_spe_evlwhsplat", SPE_BUILTIN_EVLWHSPLAT },
6318117395Skan  { 0, CODE_FOR_spe_evlhhesplat, "__builtin_spe_evlhhesplat", SPE_BUILTIN_EVLHHESPLAT },
6319117395Skan  { 0, CODE_FOR_spe_evlhhousplat, "__builtin_spe_evlhhousplat", SPE_BUILTIN_EVLHHOUSPLAT },
6320117395Skan  { 0, CODE_FOR_spe_evlhhossplat, "__builtin_spe_evlhhossplat", SPE_BUILTIN_EVLHHOSSPLAT }
6321117395Skan};
6322117395Skan
6323117395Skan/* Expand the builtin in EXP and store the result in TARGET.  Store
6324117395Skan   true in *EXPANDEDP if we found a builtin to expand.
6325117395Skan
6326117395Skan   This expands the SPE builtins that are not simple unary and binary
6327117395Skan   operations.  */
6328117395Skanstatic rtx
6329132718Skanspe_expand_builtin (tree exp, rtx target, bool *expandedp)
6330117395Skan{
6331117395Skan  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
6332117395Skan  tree arglist = TREE_OPERAND (exp, 1);
6333117395Skan  tree arg1, arg0;
6334117395Skan  unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
6335117395Skan  enum insn_code icode;
6336117395Skan  enum machine_mode tmode, mode0;
6337117395Skan  rtx pat, op0;
6338117395Skan  struct builtin_description *d;
6339117395Skan  size_t i;
6340117395Skan
6341117395Skan  *expandedp = true;
6342117395Skan
6343117395Skan  /* Syntax check for a 5-bit unsigned immediate.  */
6344117395Skan  switch (fcode)
6345117395Skan    {
6346117395Skan    case SPE_BUILTIN_EVSTDD:
6347117395Skan    case SPE_BUILTIN_EVSTDH:
6348117395Skan    case SPE_BUILTIN_EVSTDW:
6349117395Skan    case SPE_BUILTIN_EVSTWHE:
6350117395Skan    case SPE_BUILTIN_EVSTWHO:
6351117395Skan    case SPE_BUILTIN_EVSTWWE:
6352117395Skan    case SPE_BUILTIN_EVSTWWO:
6353117395Skan      arg1 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
6354117395Skan      if (TREE_CODE (arg1) != INTEGER_CST
6355117395Skan	  || TREE_INT_CST_LOW (arg1) & ~0x1f)
6356117395Skan	{
6357117395Skan	  error ("argument 2 must be a 5-bit unsigned literal");
6358117395Skan	  return const0_rtx;
6359117395Skan	}
6360117395Skan      break;
6361117395Skan    default:
6362117395Skan      break;
6363117395Skan    }
6364117395Skan
6365132718Skan  /* The evsplat*i instructions are not quite generic.  */
6366132718Skan  switch (fcode)
6367132718Skan    {
6368132718Skan    case SPE_BUILTIN_EVSPLATFI:
6369132718Skan      return rs6000_expand_unop_builtin (CODE_FOR_spe_evsplatfi,
6370132718Skan					 arglist, target);
6371132718Skan    case SPE_BUILTIN_EVSPLATI:
6372132718Skan      return rs6000_expand_unop_builtin (CODE_FOR_spe_evsplati,
6373132718Skan					 arglist, target);
6374132718Skan    default:
6375132718Skan      break;
6376132718Skan    }
6377132718Skan
6378117395Skan  d = (struct builtin_description *) bdesc_2arg_spe;
6379117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_2arg_spe); ++i, ++d)
638090075Sobrien    if (d->code == fcode)
6381117395Skan      return rs6000_expand_binop_builtin (d->icode, arglist, target);
638290075Sobrien
6383117395Skan  d = (struct builtin_description *) bdesc_spe_predicates;
6384117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_spe_predicates); ++i, ++d)
6385117395Skan    if (d->code == fcode)
6386117395Skan      return spe_expand_predicate_builtin (d->icode, arglist, target);
6387117395Skan
6388117395Skan  d = (struct builtin_description *) bdesc_spe_evsel;
6389117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_spe_evsel); ++i, ++d)
6390117395Skan    if (d->code == fcode)
6391117395Skan      return spe_expand_evsel_builtin (d->icode, arglist, target);
6392117395Skan
6393117395Skan  switch (fcode)
6394117395Skan    {
6395117395Skan    case SPE_BUILTIN_EVSTDDX:
6396132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstddx, arglist);
6397117395Skan    case SPE_BUILTIN_EVSTDHX:
6398132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstdhx, arglist);
6399117395Skan    case SPE_BUILTIN_EVSTDWX:
6400132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstdwx, arglist);
6401117395Skan    case SPE_BUILTIN_EVSTWHEX:
6402132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstwhex, arglist);
6403117395Skan    case SPE_BUILTIN_EVSTWHOX:
6404132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstwhox, arglist);
6405117395Skan    case SPE_BUILTIN_EVSTWWEX:
6406132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstwwex, arglist);
6407117395Skan    case SPE_BUILTIN_EVSTWWOX:
6408132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstwwox, arglist);
6409117395Skan    case SPE_BUILTIN_EVSTDD:
6410132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstdd, arglist);
6411117395Skan    case SPE_BUILTIN_EVSTDH:
6412132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstdh, arglist);
6413117395Skan    case SPE_BUILTIN_EVSTDW:
6414132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstdw, arglist);
6415117395Skan    case SPE_BUILTIN_EVSTWHE:
6416132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstwhe, arglist);
6417117395Skan    case SPE_BUILTIN_EVSTWHO:
6418132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstwho, arglist);
6419117395Skan    case SPE_BUILTIN_EVSTWWE:
6420132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstwwe, arglist);
6421117395Skan    case SPE_BUILTIN_EVSTWWO:
6422132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstwwo, arglist);
6423117395Skan    case SPE_BUILTIN_MFSPEFSCR:
6424117395Skan      icode = CODE_FOR_spe_mfspefscr;
6425117395Skan      tmode = insn_data[icode].operand[0].mode;
6426117395Skan
6427117395Skan      if (target == 0
6428117395Skan	  || GET_MODE (target) != tmode
6429117395Skan	  || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
6430117395Skan	target = gen_reg_rtx (tmode);
6431117395Skan
6432117395Skan      pat = GEN_FCN (icode) (target);
6433117395Skan      if (! pat)
6434117395Skan	return 0;
6435117395Skan      emit_insn (pat);
6436117395Skan      return target;
6437117395Skan    case SPE_BUILTIN_MTSPEFSCR:
6438117395Skan      icode = CODE_FOR_spe_mtspefscr;
6439117395Skan      arg0 = TREE_VALUE (arglist);
6440117395Skan      op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6441117395Skan      mode0 = insn_data[icode].operand[0].mode;
6442117395Skan
6443117395Skan      if (arg0 == error_mark_node)
6444117395Skan	return const0_rtx;
6445117395Skan
6446117395Skan      if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
6447117395Skan	op0 = copy_to_mode_reg (mode0, op0);
6448117395Skan
6449117395Skan      pat = GEN_FCN (icode) (op0);
6450117395Skan      if (pat)
6451117395Skan	emit_insn (pat);
6452117395Skan      return NULL_RTX;
6453117395Skan    default:
6454117395Skan      break;
6455117395Skan    }
6456117395Skan
6457117395Skan  *expandedp = false;
645890075Sobrien  return NULL_RTX;
645990075Sobrien}
646090075Sobrien
6461117395Skanstatic rtx
6462132718Skanspe_expand_predicate_builtin (enum insn_code icode, tree arglist, rtx target)
6463117395Skan{
6464117395Skan  rtx pat, scratch, tmp;
6465117395Skan  tree form = TREE_VALUE (arglist);
6466117395Skan  tree arg0 = TREE_VALUE (TREE_CHAIN (arglist));
6467117395Skan  tree arg1 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
6468117395Skan  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6469117395Skan  rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
6470117395Skan  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
6471117395Skan  enum machine_mode mode1 = insn_data[icode].operand[2].mode;
6472117395Skan  int form_int;
6473117395Skan  enum rtx_code code;
6474117395Skan
6475117395Skan  if (TREE_CODE (form) != INTEGER_CST)
6476117395Skan    {
6477117395Skan      error ("argument 1 of __builtin_spe_predicate must be a constant");
6478117395Skan      return const0_rtx;
6479117395Skan    }
6480117395Skan  else
6481117395Skan    form_int = TREE_INT_CST_LOW (form);
6482117395Skan
6483117395Skan  if (mode0 != mode1)
6484117395Skan    abort ();
6485117395Skan
6486117395Skan  if (arg0 == error_mark_node || arg1 == error_mark_node)
6487117395Skan    return const0_rtx;
6488117395Skan
6489117395Skan  if (target == 0
6490117395Skan      || GET_MODE (target) != SImode
6491117395Skan      || ! (*insn_data[icode].operand[0].predicate) (target, SImode))
6492117395Skan    target = gen_reg_rtx (SImode);
6493117395Skan
6494117395Skan  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
6495117395Skan    op0 = copy_to_mode_reg (mode0, op0);
6496117395Skan  if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
6497117395Skan    op1 = copy_to_mode_reg (mode1, op1);
6498117395Skan
6499117395Skan  scratch = gen_reg_rtx (CCmode);
6500117395Skan
6501117395Skan  pat = GEN_FCN (icode) (scratch, op0, op1);
6502117395Skan  if (! pat)
6503117395Skan    return const0_rtx;
6504117395Skan  emit_insn (pat);
6505117395Skan
6506117395Skan  /* There are 4 variants for each predicate: _any_, _all_, _upper_,
6507117395Skan     _lower_.  We use one compare, but look in different bits of the
6508117395Skan     CR for each variant.
6509117395Skan
6510117395Skan     There are 2 elements in each SPE simd type (upper/lower).  The CR
6511117395Skan     bits are set as follows:
6512117395Skan
6513117395Skan     BIT0  | BIT 1  | BIT 2   | BIT 3
6514117395Skan     U     |   L    | (U | L) | (U & L)
6515117395Skan
6516117395Skan     So, for an "all" relationship, BIT 3 would be set.
6517117395Skan     For an "any" relationship, BIT 2 would be set.  Etc.
6518117395Skan
6519117395Skan     Following traditional nomenclature, these bits map to:
6520117395Skan
6521117395Skan     BIT0  | BIT 1  | BIT 2   | BIT 3
6522117395Skan     LT    | GT     | EQ      | OV
6523117395Skan
6524117395Skan     Later, we will generate rtl to look in the LT/EQ/EQ/OV bits.
6525117395Skan  */
6526117395Skan
6527117395Skan  switch (form_int)
6528117395Skan    {
6529117395Skan      /* All variant.  OV bit.  */
6530117395Skan    case 0:
6531117395Skan      /* We need to get to the OV bit, which is the ORDERED bit.  We
6532117395Skan	 could generate (ordered:SI (reg:CC xx) (const_int 0)), but
6533117395Skan	 that's ugly and will trigger a validate_condition_mode abort.
6534117395Skan	 So let's just use another pattern.  */
6535117395Skan      emit_insn (gen_move_from_CR_ov_bit (target, scratch));
6536117395Skan      return target;
6537117395Skan      /* Any variant.  EQ bit.  */
6538117395Skan    case 1:
6539117395Skan      code = EQ;
6540117395Skan      break;
6541117395Skan      /* Upper variant.  LT bit.  */
6542117395Skan    case 2:
6543117395Skan      code = LT;
6544117395Skan      break;
6545117395Skan      /* Lower variant.  GT bit.  */
6546117395Skan    case 3:
6547117395Skan      code = GT;
6548117395Skan      break;
6549117395Skan    default:
6550117395Skan      error ("argument 1 of __builtin_spe_predicate is out of range");
6551117395Skan      return const0_rtx;
6552117395Skan    }
6553117395Skan
6554117395Skan  tmp = gen_rtx_fmt_ee (code, SImode, scratch, const0_rtx);
6555117395Skan  emit_move_insn (target, tmp);
6556117395Skan
6557117395Skan  return target;
6558117395Skan}
6559117395Skan
6560117395Skan/* The evsel builtins look like this:
6561117395Skan
6562117395Skan     e = __builtin_spe_evsel_OP (a, b, c, d);
6563117395Skan
6564117395Skan   and work like this:
6565117395Skan
6566117395Skan     e[upper] = a[upper] *OP* b[upper] ? c[upper] : d[upper];
6567117395Skan     e[lower] = a[lower] *OP* b[lower] ? c[lower] : d[lower];
6568117395Skan*/
6569117395Skan
6570117395Skanstatic rtx
6571132718Skanspe_expand_evsel_builtin (enum insn_code icode, tree arglist, rtx target)
6572117395Skan{
6573117395Skan  rtx pat, scratch;
6574117395Skan  tree arg0 = TREE_VALUE (arglist);
6575117395Skan  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
6576117395Skan  tree arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
6577117395Skan  tree arg3 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (arglist))));
6578117395Skan  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6579117395Skan  rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
6580117395Skan  rtx op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
6581117395Skan  rtx op3 = expand_expr (arg3, NULL_RTX, VOIDmode, 0);
6582117395Skan  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
6583117395Skan  enum machine_mode mode1 = insn_data[icode].operand[2].mode;
6584117395Skan
6585117395Skan  if (mode0 != mode1)
6586117395Skan    abort ();
6587117395Skan
6588117395Skan  if (arg0 == error_mark_node || arg1 == error_mark_node
6589117395Skan      || arg2 == error_mark_node || arg3 == error_mark_node)
6590117395Skan    return const0_rtx;
6591117395Skan
6592117395Skan  if (target == 0
6593117395Skan      || GET_MODE (target) != mode0
6594117395Skan      || ! (*insn_data[icode].operand[0].predicate) (target, mode0))
6595117395Skan    target = gen_reg_rtx (mode0);
6596117395Skan
6597117395Skan  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
6598117395Skan    op0 = copy_to_mode_reg (mode0, op0);
6599117395Skan  if (! (*insn_data[icode].operand[1].predicate) (op1, mode1))
6600117395Skan    op1 = copy_to_mode_reg (mode0, op1);
6601117395Skan  if (! (*insn_data[icode].operand[1].predicate) (op2, mode1))
6602117395Skan    op2 = copy_to_mode_reg (mode0, op2);
6603117395Skan  if (! (*insn_data[icode].operand[1].predicate) (op3, mode1))
6604117395Skan    op3 = copy_to_mode_reg (mode0, op3);
6605117395Skan
6606117395Skan  /* Generate the compare.  */
6607117395Skan  scratch = gen_reg_rtx (CCmode);
6608117395Skan  pat = GEN_FCN (icode) (scratch, op0, op1);
6609117395Skan  if (! pat)
6610117395Skan    return const0_rtx;
6611117395Skan  emit_insn (pat);
6612117395Skan
6613117395Skan  if (mode0 == V2SImode)
6614117395Skan    emit_insn (gen_spe_evsel (target, op2, op3, scratch));
6615117395Skan  else
6616117395Skan    emit_insn (gen_spe_evsel_fs (target, op2, op3, scratch));
6617117395Skan
6618117395Skan  return target;
6619117395Skan}
6620117395Skan
662190075Sobrien/* Expand an expression EXP that calls a built-in function,
662290075Sobrien   with result going to TARGET if that's convenient
662390075Sobrien   (and in mode MODE if that's convenient).
662490075Sobrien   SUBTARGET may be used as the target for computing one of EXP's operands.
662590075Sobrien   IGNORE is nonzero if the value is to be ignored.  */
662690075Sobrien
662790075Sobrienstatic rtx
6628132718Skanrs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
6629132718Skan		      enum machine_mode mode ATTRIBUTE_UNUSED,
6630132718Skan		      int ignore ATTRIBUTE_UNUSED)
663190075Sobrien{
6632117395Skan  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
6633117395Skan  tree arglist = TREE_OPERAND (exp, 1);
6634117395Skan  unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
6635117395Skan  struct builtin_description *d;
6636117395Skan  size_t i;
6637117395Skan  rtx ret;
6638117395Skan  bool success;
6639117395Skan
664090075Sobrien  if (TARGET_ALTIVEC)
6641117395Skan    {
6642117395Skan      ret = altivec_expand_builtin (exp, target, &success);
664390075Sobrien
6644117395Skan      if (success)
6645117395Skan	return ret;
6646117395Skan    }
6647117395Skan  if (TARGET_SPE)
6648117395Skan    {
6649117395Skan      ret = spe_expand_builtin (exp, target, &success);
6650117395Skan
6651117395Skan      if (success)
6652117395Skan	return ret;
6653117395Skan    }
6654117395Skan
6655117395Skan  if (TARGET_ALTIVEC || TARGET_SPE)
6656117395Skan    {
6657117395Skan      /* Handle simple unary operations.  */
6658117395Skan      d = (struct builtin_description *) bdesc_1arg;
6659117395Skan      for (i = 0; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
6660117395Skan	if (d->code == fcode)
6661117395Skan	  return rs6000_expand_unop_builtin (d->icode, arglist, target);
6662117395Skan
6663117395Skan      /* Handle simple binary operations.  */
6664117395Skan      d = (struct builtin_description *) bdesc_2arg;
6665117395Skan      for (i = 0; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
6666117395Skan	if (d->code == fcode)
6667117395Skan	  return rs6000_expand_binop_builtin (d->icode, arglist, target);
6668117395Skan
6669117395Skan      /* Handle simple ternary operations.  */
6670117395Skan      d = (struct builtin_description *) bdesc_3arg;
6671117395Skan      for (i = 0; i < ARRAY_SIZE  (bdesc_3arg); i++, d++)
6672117395Skan	if (d->code == fcode)
6673117395Skan	  return rs6000_expand_ternop_builtin (d->icode, arglist, target);
6674117395Skan    }
6675117395Skan
667690075Sobrien  abort ();
6677117395Skan  return NULL_RTX;
667890075Sobrien}
667990075Sobrien
668090075Sobrienstatic void
6681132718Skanrs6000_init_builtins (void)
668290075Sobrien{
6683132718Skan  opaque_V2SI_type_node = copy_node (V2SI_type_node);
6684132718Skan  opaque_V2SF_type_node = copy_node (V2SF_type_node);
6685132718Skan  opaque_p_V2SI_type_node = build_pointer_type (opaque_V2SI_type_node);
6686132718Skan
6687117395Skan  if (TARGET_SPE)
6688117395Skan    spe_init_builtins ();
668990075Sobrien  if (TARGET_ALTIVEC)
669090075Sobrien    altivec_init_builtins ();
6691117395Skan  if (TARGET_ALTIVEC || TARGET_SPE)
6692117395Skan    rs6000_common_init_builtins ();
669390075Sobrien}
669490075Sobrien
6695117395Skan/* Search through a set of builtins and enable the mask bits.
6696117395Skan   DESC is an array of builtins.
6697132718Skan   SIZE is the total number of builtins.
6698117395Skan   START is the builtin enum at which to start.
6699117395Skan   END is the builtin enum at which to end.  */
670090075Sobrienstatic void
6701132718Skanenable_mask_for_builtins (struct builtin_description *desc, int size,
6702132718Skan			  enum rs6000_builtins start,
6703132718Skan			  enum rs6000_builtins end)
670490075Sobrien{
6705117395Skan  int i;
670690075Sobrien
6707117395Skan  for (i = 0; i < size; ++i)
6708117395Skan    if (desc[i].code == start)
6709117395Skan      break;
671090075Sobrien
6711117395Skan  if (i == size)
6712117395Skan    return;
671390075Sobrien
6714117395Skan  for (; i < size; ++i)
6715117395Skan    {
6716117395Skan      /* Flip all the bits on.  */
6717117395Skan      desc[i].mask = target_flags;
6718117395Skan      if (desc[i].code == end)
6719117395Skan	break;
6720117395Skan    }
6721117395Skan}
672290075Sobrien
6723117395Skanstatic void
6724132718Skanspe_init_builtins (void)
6725117395Skan{
6726117395Skan  tree endlink = void_list_node;
6727117395Skan  tree puint_type_node = build_pointer_type (unsigned_type_node);
6728117395Skan  tree pushort_type_node = build_pointer_type (short_unsigned_type_node);
6729117395Skan  struct builtin_description *d;
6730117395Skan  size_t i;
673190075Sobrien
6732117395Skan  tree v2si_ftype_4_v2si
6733117395Skan    = build_function_type
6734132718Skan    (opaque_V2SI_type_node,
6735132718Skan     tree_cons (NULL_TREE, opaque_V2SI_type_node,
6736132718Skan		tree_cons (NULL_TREE, opaque_V2SI_type_node,
6737132718Skan			   tree_cons (NULL_TREE, opaque_V2SI_type_node,
6738132718Skan				      tree_cons (NULL_TREE, opaque_V2SI_type_node,
6739117395Skan						 endlink)))));
674090075Sobrien
6741117395Skan  tree v2sf_ftype_4_v2sf
6742117395Skan    = build_function_type
6743132718Skan    (opaque_V2SF_type_node,
6744132718Skan     tree_cons (NULL_TREE, opaque_V2SF_type_node,
6745132718Skan		tree_cons (NULL_TREE, opaque_V2SF_type_node,
6746132718Skan			   tree_cons (NULL_TREE, opaque_V2SF_type_node,
6747132718Skan				      tree_cons (NULL_TREE, opaque_V2SF_type_node,
6748117395Skan						 endlink)))));
674990075Sobrien
6750117395Skan  tree int_ftype_int_v2si_v2si
6751117395Skan    = build_function_type
6752117395Skan    (integer_type_node,
6753117395Skan     tree_cons (NULL_TREE, integer_type_node,
6754132718Skan		tree_cons (NULL_TREE, opaque_V2SI_type_node,
6755132718Skan			   tree_cons (NULL_TREE, opaque_V2SI_type_node,
6756117395Skan				      endlink))));
675790075Sobrien
6758117395Skan  tree int_ftype_int_v2sf_v2sf
6759117395Skan    = build_function_type
6760117395Skan    (integer_type_node,
6761117395Skan     tree_cons (NULL_TREE, integer_type_node,
6762132718Skan		tree_cons (NULL_TREE, opaque_V2SF_type_node,
6763132718Skan			   tree_cons (NULL_TREE, opaque_V2SF_type_node,
6764117395Skan				      endlink))));
676590075Sobrien
6766117395Skan  tree void_ftype_v2si_puint_int
676790075Sobrien    = build_function_type (void_type_node,
6768132718Skan			   tree_cons (NULL_TREE, opaque_V2SI_type_node,
6769117395Skan				      tree_cons (NULL_TREE, puint_type_node,
677090075Sobrien						 tree_cons (NULL_TREE,
6771117395Skan							    integer_type_node,
677290075Sobrien							    endlink))));
677390075Sobrien
6774117395Skan  tree void_ftype_v2si_puint_char
677590075Sobrien    = build_function_type (void_type_node,
6776132718Skan			   tree_cons (NULL_TREE, opaque_V2SI_type_node,
6777117395Skan				      tree_cons (NULL_TREE, puint_type_node,
677890075Sobrien						 tree_cons (NULL_TREE,
6779117395Skan							    char_type_node,
678090075Sobrien							    endlink))));
678190075Sobrien
6782117395Skan  tree void_ftype_v2si_pv2si_int
678390075Sobrien    = build_function_type (void_type_node,
6784132718Skan			   tree_cons (NULL_TREE, opaque_V2SI_type_node,
6785132718Skan				      tree_cons (NULL_TREE, opaque_p_V2SI_type_node,
678690075Sobrien						 tree_cons (NULL_TREE,
6787117395Skan							    integer_type_node,
678890075Sobrien							    endlink))));
678990075Sobrien
6790117395Skan  tree void_ftype_v2si_pv2si_char
679190075Sobrien    = build_function_type (void_type_node,
6792132718Skan			   tree_cons (NULL_TREE, opaque_V2SI_type_node,
6793132718Skan				      tree_cons (NULL_TREE, opaque_p_V2SI_type_node,
679490075Sobrien						 tree_cons (NULL_TREE,
6795117395Skan							    char_type_node,
679690075Sobrien							    endlink))));
679790075Sobrien
6798117395Skan  tree void_ftype_int
679990075Sobrien    = build_function_type (void_type_node,
6800117395Skan			   tree_cons (NULL_TREE, integer_type_node, endlink));
680190075Sobrien
6802117395Skan  tree int_ftype_void
6803132718Skan    = build_function_type (integer_type_node, endlink);
680490075Sobrien
6805117395Skan  tree v2si_ftype_pv2si_int
6806132718Skan    = build_function_type (opaque_V2SI_type_node,
6807132718Skan			   tree_cons (NULL_TREE, opaque_p_V2SI_type_node,
6808117395Skan				      tree_cons (NULL_TREE, integer_type_node,
6809117395Skan						 endlink)));
6810117395Skan
6811117395Skan  tree v2si_ftype_puint_int
6812132718Skan    = build_function_type (opaque_V2SI_type_node,
6813117395Skan			   tree_cons (NULL_TREE, puint_type_node,
6814117395Skan				      tree_cons (NULL_TREE, integer_type_node,
6815117395Skan						 endlink)));
6816117395Skan
6817117395Skan  tree v2si_ftype_pushort_int
6818132718Skan    = build_function_type (opaque_V2SI_type_node,
6819117395Skan			   tree_cons (NULL_TREE, pushort_type_node,
6820117395Skan				      tree_cons (NULL_TREE, integer_type_node,
6821117395Skan						 endlink)));
6822117395Skan
6823132718Skan  tree v2si_ftype_signed_char
6824132718Skan    = build_function_type (opaque_V2SI_type_node,
6825132718Skan			   tree_cons (NULL_TREE, signed_char_type_node,
6826132718Skan				      endlink));
6827132718Skan
6828117395Skan  /* The initialization of the simple binary and unary builtins is
6829117395Skan     done in rs6000_common_init_builtins, but we have to enable the
6830117395Skan     mask bits here manually because we have run out of `target_flags'
6831117395Skan     bits.  We really need to redesign this mask business.  */
6832117395Skan
6833117395Skan  enable_mask_for_builtins ((struct builtin_description *) bdesc_2arg,
6834117395Skan			    ARRAY_SIZE (bdesc_2arg),
6835117395Skan			    SPE_BUILTIN_EVADDW,
6836117395Skan			    SPE_BUILTIN_EVXOR);
6837117395Skan  enable_mask_for_builtins ((struct builtin_description *) bdesc_1arg,
6838117395Skan			    ARRAY_SIZE (bdesc_1arg),
6839117395Skan			    SPE_BUILTIN_EVABS,
6840117395Skan			    SPE_BUILTIN_EVSUBFUSIAAW);
6841117395Skan  enable_mask_for_builtins ((struct builtin_description *) bdesc_spe_predicates,
6842117395Skan			    ARRAY_SIZE (bdesc_spe_predicates),
6843117395Skan			    SPE_BUILTIN_EVCMPEQ,
6844117395Skan			    SPE_BUILTIN_EVFSTSTLT);
6845117395Skan  enable_mask_for_builtins ((struct builtin_description *) bdesc_spe_evsel,
6846117395Skan			    ARRAY_SIZE (bdesc_spe_evsel),
6847117395Skan			    SPE_BUILTIN_EVSEL_CMPGTS,
6848117395Skan			    SPE_BUILTIN_EVSEL_FSTSTEQ);
6849117395Skan
6850132718Skan  (*lang_hooks.decls.pushdecl)
6851132718Skan    (build_decl (TYPE_DECL, get_identifier ("__ev64_opaque__"),
6852132718Skan		 opaque_V2SI_type_node));
6853132718Skan
6854117395Skan  /* Initialize irregular SPE builtins.  */
6855117395Skan
6856117395Skan  def_builtin (target_flags, "__builtin_spe_mtspefscr", void_ftype_int, SPE_BUILTIN_MTSPEFSCR);
6857117395Skan  def_builtin (target_flags, "__builtin_spe_mfspefscr", int_ftype_void, SPE_BUILTIN_MFSPEFSCR);
6858117395Skan  def_builtin (target_flags, "__builtin_spe_evstddx", void_ftype_v2si_pv2si_int, SPE_BUILTIN_EVSTDDX);
6859117395Skan  def_builtin (target_flags, "__builtin_spe_evstdhx", void_ftype_v2si_pv2si_int, SPE_BUILTIN_EVSTDHX);
6860117395Skan  def_builtin (target_flags, "__builtin_spe_evstdwx", void_ftype_v2si_pv2si_int, SPE_BUILTIN_EVSTDWX);
6861117395Skan  def_builtin (target_flags, "__builtin_spe_evstwhex", void_ftype_v2si_puint_int, SPE_BUILTIN_EVSTWHEX);
6862117395Skan  def_builtin (target_flags, "__builtin_spe_evstwhox", void_ftype_v2si_puint_int, SPE_BUILTIN_EVSTWHOX);
6863117395Skan  def_builtin (target_flags, "__builtin_spe_evstwwex", void_ftype_v2si_puint_int, SPE_BUILTIN_EVSTWWEX);
6864117395Skan  def_builtin (target_flags, "__builtin_spe_evstwwox", void_ftype_v2si_puint_int, SPE_BUILTIN_EVSTWWOX);
6865117395Skan  def_builtin (target_flags, "__builtin_spe_evstdd", void_ftype_v2si_pv2si_char, SPE_BUILTIN_EVSTDD);
6866117395Skan  def_builtin (target_flags, "__builtin_spe_evstdh", void_ftype_v2si_pv2si_char, SPE_BUILTIN_EVSTDH);
6867117395Skan  def_builtin (target_flags, "__builtin_spe_evstdw", void_ftype_v2si_pv2si_char, SPE_BUILTIN_EVSTDW);
6868117395Skan  def_builtin (target_flags, "__builtin_spe_evstwhe", void_ftype_v2si_puint_char, SPE_BUILTIN_EVSTWHE);
6869117395Skan  def_builtin (target_flags, "__builtin_spe_evstwho", void_ftype_v2si_puint_char, SPE_BUILTIN_EVSTWHO);
6870117395Skan  def_builtin (target_flags, "__builtin_spe_evstwwe", void_ftype_v2si_puint_char, SPE_BUILTIN_EVSTWWE);
6871117395Skan  def_builtin (target_flags, "__builtin_spe_evstwwo", void_ftype_v2si_puint_char, SPE_BUILTIN_EVSTWWO);
6872132718Skan  def_builtin (target_flags, "__builtin_spe_evsplatfi", v2si_ftype_signed_char, SPE_BUILTIN_EVSPLATFI);
6873132718Skan  def_builtin (target_flags, "__builtin_spe_evsplati", v2si_ftype_signed_char, SPE_BUILTIN_EVSPLATI);
6874117395Skan
6875117395Skan  /* Loads.  */
6876117395Skan  def_builtin (target_flags, "__builtin_spe_evlddx", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDDX);
6877117395Skan  def_builtin (target_flags, "__builtin_spe_evldwx", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDWX);
6878117395Skan  def_builtin (target_flags, "__builtin_spe_evldhx", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDHX);
6879117395Skan  def_builtin (target_flags, "__builtin_spe_evlwhex", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHEX);
6880117395Skan  def_builtin (target_flags, "__builtin_spe_evlwhoux", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHOUX);
6881117395Skan  def_builtin (target_flags, "__builtin_spe_evlwhosx", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHOSX);
6882117395Skan  def_builtin (target_flags, "__builtin_spe_evlwwsplatx", v2si_ftype_puint_int, SPE_BUILTIN_EVLWWSPLATX);
6883117395Skan  def_builtin (target_flags, "__builtin_spe_evlwhsplatx", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHSPLATX);
6884117395Skan  def_builtin (target_flags, "__builtin_spe_evlhhesplatx", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHESPLATX);
6885117395Skan  def_builtin (target_flags, "__builtin_spe_evlhhousplatx", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHOUSPLATX);
6886117395Skan  def_builtin (target_flags, "__builtin_spe_evlhhossplatx", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHOSSPLATX);
6887117395Skan  def_builtin (target_flags, "__builtin_spe_evldd", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDD);
6888117395Skan  def_builtin (target_flags, "__builtin_spe_evldw", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDW);
6889117395Skan  def_builtin (target_flags, "__builtin_spe_evldh", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDH);
6890117395Skan  def_builtin (target_flags, "__builtin_spe_evlhhesplat", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHESPLAT);
6891117395Skan  def_builtin (target_flags, "__builtin_spe_evlhhossplat", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHOSSPLAT);
6892117395Skan  def_builtin (target_flags, "__builtin_spe_evlhhousplat", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHOUSPLAT);
6893117395Skan  def_builtin (target_flags, "__builtin_spe_evlwhe", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHE);
6894117395Skan  def_builtin (target_flags, "__builtin_spe_evlwhos", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHOS);
6895117395Skan  def_builtin (target_flags, "__builtin_spe_evlwhou", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHOU);
6896117395Skan  def_builtin (target_flags, "__builtin_spe_evlwhsplat", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHSPLAT);
6897117395Skan  def_builtin (target_flags, "__builtin_spe_evlwwsplat", v2si_ftype_puint_int, SPE_BUILTIN_EVLWWSPLAT);
6898117395Skan
6899117395Skan  /* Predicates.  */
6900117395Skan  d = (struct builtin_description *) bdesc_spe_predicates;
6901117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_spe_predicates); ++i, d++)
6902117395Skan    {
6903117395Skan      tree type;
6904117395Skan
6905117395Skan      switch (insn_data[d->icode].operand[1].mode)
6906117395Skan	{
6907117395Skan	case V2SImode:
6908117395Skan	  type = int_ftype_int_v2si_v2si;
6909117395Skan	  break;
6910117395Skan	case V2SFmode:
6911117395Skan	  type = int_ftype_int_v2sf_v2sf;
6912117395Skan	  break;
6913117395Skan	default:
6914117395Skan	  abort ();
6915117395Skan	}
6916117395Skan
6917117395Skan      def_builtin (d->mask, d->name, type, d->code);
6918117395Skan    }
6919117395Skan
6920117395Skan  /* Evsel predicates.  */
6921117395Skan  d = (struct builtin_description *) bdesc_spe_evsel;
6922117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_spe_evsel); ++i, d++)
6923117395Skan    {
6924117395Skan      tree type;
6925117395Skan
6926117395Skan      switch (insn_data[d->icode].operand[1].mode)
6927117395Skan	{
6928117395Skan	case V2SImode:
6929117395Skan	  type = v2si_ftype_4_v2si;
6930117395Skan	  break;
6931117395Skan	case V2SFmode:
6932117395Skan	  type = v2sf_ftype_4_v2sf;
6933117395Skan	  break;
6934117395Skan	default:
6935117395Skan	  abort ();
6936117395Skan	}
6937117395Skan
6938117395Skan      def_builtin (d->mask, d->name, type, d->code);
6939117395Skan    }
6940117395Skan}
6941117395Skan
6942117395Skanstatic void
6943132718Skanaltivec_init_builtins (void)
6944117395Skan{
6945117395Skan  struct builtin_description *d;
6946117395Skan  struct builtin_description_predicates *dp;
6947117395Skan  size_t i;
6948117395Skan  tree pfloat_type_node = build_pointer_type (float_type_node);
6949117395Skan  tree pint_type_node = build_pointer_type (integer_type_node);
6950117395Skan  tree pshort_type_node = build_pointer_type (short_integer_type_node);
6951117395Skan  tree pchar_type_node = build_pointer_type (char_type_node);
6952117395Skan
6953117395Skan  tree pvoid_type_node = build_pointer_type (void_type_node);
6954117395Skan
6955117395Skan  tree pcfloat_type_node = build_pointer_type (build_qualified_type (float_type_node, TYPE_QUAL_CONST));
6956117395Skan  tree pcint_type_node = build_pointer_type (build_qualified_type (integer_type_node, TYPE_QUAL_CONST));
6957117395Skan  tree pcshort_type_node = build_pointer_type (build_qualified_type (short_integer_type_node, TYPE_QUAL_CONST));
6958117395Skan  tree pcchar_type_node = build_pointer_type (build_qualified_type (char_type_node, TYPE_QUAL_CONST));
6959117395Skan
6960117395Skan  tree pcvoid_type_node = build_pointer_type (build_qualified_type (void_type_node, TYPE_QUAL_CONST));
6961117395Skan
6962117395Skan  tree int_ftype_int_v4si_v4si
6963117395Skan    = build_function_type_list (integer_type_node,
6964117395Skan				integer_type_node, V4SI_type_node,
6965117395Skan				V4SI_type_node, NULL_TREE);
6966117395Skan  tree v4sf_ftype_pcfloat
6967117395Skan    = build_function_type_list (V4SF_type_node, pcfloat_type_node, NULL_TREE);
6968117395Skan  tree void_ftype_pfloat_v4sf
6969117395Skan    = build_function_type_list (void_type_node,
6970117395Skan				pfloat_type_node, V4SF_type_node, NULL_TREE);
6971117395Skan  tree v4si_ftype_pcint
6972117395Skan    = build_function_type_list (V4SI_type_node, pcint_type_node, NULL_TREE);
6973117395Skan  tree void_ftype_pint_v4si
6974117395Skan    = build_function_type_list (void_type_node,
6975117395Skan				pint_type_node, V4SI_type_node, NULL_TREE);
6976117395Skan  tree v8hi_ftype_pcshort
6977117395Skan    = build_function_type_list (V8HI_type_node, pcshort_type_node, NULL_TREE);
6978117395Skan  tree void_ftype_pshort_v8hi
6979117395Skan    = build_function_type_list (void_type_node,
6980117395Skan				pshort_type_node, V8HI_type_node, NULL_TREE);
6981117395Skan  tree v16qi_ftype_pcchar
6982117395Skan    = build_function_type_list (V16QI_type_node, pcchar_type_node, NULL_TREE);
6983117395Skan  tree void_ftype_pchar_v16qi
6984117395Skan    = build_function_type_list (void_type_node,
6985117395Skan				pchar_type_node, V16QI_type_node, NULL_TREE);
6986117395Skan  tree void_ftype_v4si
6987117395Skan    = build_function_type_list (void_type_node, V4SI_type_node, NULL_TREE);
698890075Sobrien  tree v8hi_ftype_void
698996263Sobrien    = build_function_type (V8HI_type_node, void_list_node);
6990117395Skan  tree void_ftype_void
6991117395Skan    = build_function_type (void_type_node, void_list_node);
6992117395Skan  tree void_ftype_qi
6993117395Skan    = build_function_type_list (void_type_node, char_type_node, NULL_TREE);
699490075Sobrien
6995132718Skan  tree v16qi_ftype_long_pcvoid
6996117395Skan    = build_function_type_list (V16QI_type_node,
6997132718Skan				long_integer_type_node, pcvoid_type_node, NULL_TREE);
6998132718Skan  tree v8hi_ftype_long_pcvoid
6999117395Skan    = build_function_type_list (V8HI_type_node,
7000132718Skan				long_integer_type_node, pcvoid_type_node, NULL_TREE);
7001132718Skan  tree v4si_ftype_long_pcvoid
7002117395Skan    = build_function_type_list (V4SI_type_node,
7003132718Skan				long_integer_type_node, pcvoid_type_node, NULL_TREE);
700490075Sobrien
7005132718Skan  tree void_ftype_v4si_long_pvoid
7006117395Skan    = build_function_type_list (void_type_node,
7007132718Skan				V4SI_type_node, long_integer_type_node,
7008117395Skan				pvoid_type_node, NULL_TREE);
7009132718Skan  tree void_ftype_v16qi_long_pvoid
7010117395Skan    = build_function_type_list (void_type_node,
7011132718Skan				V16QI_type_node, long_integer_type_node,
7012117395Skan				pvoid_type_node, NULL_TREE);
7013132718Skan  tree void_ftype_v8hi_long_pvoid
7014117395Skan    = build_function_type_list (void_type_node,
7015132718Skan				V8HI_type_node, long_integer_type_node,
7016117395Skan				pvoid_type_node, NULL_TREE);
7017117395Skan  tree int_ftype_int_v8hi_v8hi
7018117395Skan    = build_function_type_list (integer_type_node,
7019117395Skan				integer_type_node, V8HI_type_node,
7020117395Skan				V8HI_type_node, NULL_TREE);
7021117395Skan  tree int_ftype_int_v16qi_v16qi
7022117395Skan    = build_function_type_list (integer_type_node,
7023117395Skan				integer_type_node, V16QI_type_node,
7024117395Skan				V16QI_type_node, NULL_TREE);
7025117395Skan  tree int_ftype_int_v4sf_v4sf
7026117395Skan    = build_function_type_list (integer_type_node,
7027117395Skan				integer_type_node, V4SF_type_node,
7028117395Skan				V4SF_type_node, NULL_TREE);
7029117395Skan  tree v4si_ftype_v4si
7030117395Skan    = build_function_type_list (V4SI_type_node, V4SI_type_node, NULL_TREE);
7031117395Skan  tree v8hi_ftype_v8hi
7032117395Skan    = build_function_type_list (V8HI_type_node, V8HI_type_node, NULL_TREE);
7033117395Skan  tree v16qi_ftype_v16qi
7034117395Skan    = build_function_type_list (V16QI_type_node, V16QI_type_node, NULL_TREE);
7035117395Skan  tree v4sf_ftype_v4sf
7036117395Skan    = build_function_type_list (V4SF_type_node, V4SF_type_node, NULL_TREE);
7037117395Skan  tree void_ftype_pcvoid_int_char
7038117395Skan    = build_function_type_list (void_type_node,
7039117395Skan				pcvoid_type_node, integer_type_node,
7040117395Skan				char_type_node, NULL_TREE);
7041117395Skan
7042117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_4sf", v4sf_ftype_pcfloat,
7043117395Skan	       ALTIVEC_BUILTIN_LD_INTERNAL_4sf);
7044117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_4sf", void_ftype_pfloat_v4sf,
7045117395Skan	       ALTIVEC_BUILTIN_ST_INTERNAL_4sf);
7046117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_4si", v4si_ftype_pcint,
7047117395Skan	       ALTIVEC_BUILTIN_LD_INTERNAL_4si);
7048117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_4si", void_ftype_pint_v4si,
7049117395Skan	       ALTIVEC_BUILTIN_ST_INTERNAL_4si);
7050117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_8hi", v8hi_ftype_pcshort,
7051117395Skan	       ALTIVEC_BUILTIN_LD_INTERNAL_8hi);
7052117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_8hi", void_ftype_pshort_v8hi,
7053117395Skan	       ALTIVEC_BUILTIN_ST_INTERNAL_8hi);
7054117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_16qi", v16qi_ftype_pcchar,
7055117395Skan	       ALTIVEC_BUILTIN_LD_INTERNAL_16qi);
7056117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_16qi", void_ftype_pchar_v16qi,
7057117395Skan	       ALTIVEC_BUILTIN_ST_INTERNAL_16qi);
7058117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_mtvscr", void_ftype_v4si, ALTIVEC_BUILTIN_MTVSCR);
7059117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_mfvscr", v8hi_ftype_void, ALTIVEC_BUILTIN_MFVSCR);
7060117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_dssall", void_ftype_void, ALTIVEC_BUILTIN_DSSALL);
7061117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_dss", void_ftype_qi, ALTIVEC_BUILTIN_DSS);
7062132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvsl", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVSL);
7063132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvsr", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVSR);
7064132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvebx", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVEBX);
7065132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvehx", v8hi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVEHX);
7066132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvewx", v4si_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVEWX);
7067132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvxl", v4si_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVXL);
7068132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvx", v4si_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVX);
7069132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvx", void_ftype_v4si_long_pvoid, ALTIVEC_BUILTIN_STVX);
7070132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvewx", void_ftype_v4si_long_pvoid, ALTIVEC_BUILTIN_STVEWX);
7071132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvxl", void_ftype_v4si_long_pvoid, ALTIVEC_BUILTIN_STVXL);
7072132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvebx", void_ftype_v16qi_long_pvoid, ALTIVEC_BUILTIN_STVEBX);
7073132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvehx", void_ftype_v8hi_long_pvoid, ALTIVEC_BUILTIN_STVEHX);
707490075Sobrien
7075117395Skan  /* Add the DST variants.  */
7076117395Skan  d = (struct builtin_description *) bdesc_dst;
7077117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_dst); i++, d++)
7078117395Skan    def_builtin (d->mask, d->name, void_ftype_pcvoid_int_char, d->code);
7079117395Skan
7080117395Skan  /* Initialize the predicates.  */
7081117395Skan  dp = (struct builtin_description_predicates *) bdesc_altivec_preds;
7082117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_altivec_preds); i++, dp++)
7083117395Skan    {
7084117395Skan      enum machine_mode mode1;
7085117395Skan      tree type;
7086117395Skan
7087117395Skan      mode1 = insn_data[dp->icode].operand[1].mode;
7088117395Skan
7089117395Skan      switch (mode1)
7090117395Skan	{
7091117395Skan	case V4SImode:
7092117395Skan	  type = int_ftype_int_v4si_v4si;
7093117395Skan	  break;
7094117395Skan	case V8HImode:
7095117395Skan	  type = int_ftype_int_v8hi_v8hi;
7096117395Skan	  break;
7097117395Skan	case V16QImode:
7098117395Skan	  type = int_ftype_int_v16qi_v16qi;
7099117395Skan	  break;
7100117395Skan	case V4SFmode:
7101117395Skan	  type = int_ftype_int_v4sf_v4sf;
7102117395Skan	  break;
7103117395Skan	default:
7104117395Skan	  abort ();
7105117395Skan	}
7106117395Skan
7107117395Skan      def_builtin (dp->mask, dp->name, type, dp->code);
7108117395Skan    }
7109117395Skan
7110117395Skan  /* Initialize the abs* operators.  */
7111117395Skan  d = (struct builtin_description *) bdesc_abs;
7112117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_abs); i++, d++)
7113117395Skan    {
7114117395Skan      enum machine_mode mode0;
7115117395Skan      tree type;
7116117395Skan
7117117395Skan      mode0 = insn_data[d->icode].operand[0].mode;
7118117395Skan
7119117395Skan      switch (mode0)
7120117395Skan	{
7121117395Skan	case V4SImode:
7122117395Skan	  type = v4si_ftype_v4si;
7123117395Skan	  break;
7124117395Skan	case V8HImode:
7125117395Skan	  type = v8hi_ftype_v8hi;
7126117395Skan	  break;
7127117395Skan	case V16QImode:
7128117395Skan	  type = v16qi_ftype_v16qi;
7129117395Skan	  break;
7130117395Skan	case V4SFmode:
7131117395Skan	  type = v4sf_ftype_v4sf;
7132117395Skan	  break;
7133117395Skan	default:
7134117395Skan	  abort ();
7135117395Skan	}
7136117395Skan
7137117395Skan      def_builtin (d->mask, d->name, type, d->code);
7138117395Skan    }
7139117395Skan}
7140117395Skan
7141117395Skanstatic void
7142132718Skanrs6000_common_init_builtins (void)
7143117395Skan{
7144117395Skan  struct builtin_description *d;
7145117395Skan  size_t i;
7146117395Skan
7147117395Skan  tree v4sf_ftype_v4sf_v4sf_v16qi
7148117395Skan    = build_function_type_list (V4SF_type_node,
7149117395Skan				V4SF_type_node, V4SF_type_node,
7150117395Skan				V16QI_type_node, NULL_TREE);
7151117395Skan  tree v4si_ftype_v4si_v4si_v16qi
7152117395Skan    = build_function_type_list (V4SI_type_node,
7153117395Skan				V4SI_type_node, V4SI_type_node,
7154117395Skan				V16QI_type_node, NULL_TREE);
7155117395Skan  tree v8hi_ftype_v8hi_v8hi_v16qi
7156117395Skan    = build_function_type_list (V8HI_type_node,
7157117395Skan				V8HI_type_node, V8HI_type_node,
7158117395Skan				V16QI_type_node, NULL_TREE);
7159117395Skan  tree v16qi_ftype_v16qi_v16qi_v16qi
7160117395Skan    = build_function_type_list (V16QI_type_node,
7161117395Skan				V16QI_type_node, V16QI_type_node,
7162117395Skan				V16QI_type_node, NULL_TREE);
7163117395Skan  tree v4si_ftype_char
7164117395Skan    = build_function_type_list (V4SI_type_node, char_type_node, NULL_TREE);
7165117395Skan  tree v8hi_ftype_char
7166117395Skan    = build_function_type_list (V8HI_type_node, char_type_node, NULL_TREE);
7167117395Skan  tree v16qi_ftype_char
7168117395Skan    = build_function_type_list (V16QI_type_node, char_type_node, NULL_TREE);
7169117395Skan  tree v8hi_ftype_v16qi
7170117395Skan    = build_function_type_list (V8HI_type_node, V16QI_type_node, NULL_TREE);
7171117395Skan  tree v4sf_ftype_v4sf
7172117395Skan    = build_function_type_list (V4SF_type_node, V4SF_type_node, NULL_TREE);
7173117395Skan
7174117395Skan  tree v2si_ftype_v2si_v2si
7175132718Skan    = build_function_type_list (opaque_V2SI_type_node,
7176132718Skan				opaque_V2SI_type_node,
7177132718Skan				opaque_V2SI_type_node, NULL_TREE);
7178117395Skan
7179117395Skan  tree v2sf_ftype_v2sf_v2sf
7180132718Skan    = build_function_type_list (opaque_V2SF_type_node,
7181132718Skan				opaque_V2SF_type_node,
7182132718Skan				opaque_V2SF_type_node, NULL_TREE);
7183117395Skan
7184117395Skan  tree v2si_ftype_int_int
7185132718Skan    = build_function_type_list (opaque_V2SI_type_node,
7186117395Skan				integer_type_node, integer_type_node,
7187117395Skan				NULL_TREE);
7188117395Skan
7189117395Skan  tree v2si_ftype_v2si
7190132718Skan    = build_function_type_list (opaque_V2SI_type_node,
7191132718Skan				opaque_V2SI_type_node, NULL_TREE);
7192117395Skan
7193117395Skan  tree v2sf_ftype_v2sf
7194132718Skan    = build_function_type_list (opaque_V2SF_type_node,
7195132718Skan				opaque_V2SF_type_node, NULL_TREE);
7196117395Skan
7197117395Skan  tree v2sf_ftype_v2si
7198132718Skan    = build_function_type_list (opaque_V2SF_type_node,
7199132718Skan				opaque_V2SI_type_node, NULL_TREE);
7200117395Skan
7201117395Skan  tree v2si_ftype_v2sf
7202132718Skan    = build_function_type_list (opaque_V2SI_type_node,
7203132718Skan				opaque_V2SF_type_node, NULL_TREE);
7204117395Skan
7205117395Skan  tree v2si_ftype_v2si_char
7206132718Skan    = build_function_type_list (opaque_V2SI_type_node,
7207132718Skan				opaque_V2SI_type_node,
7208132718Skan				char_type_node, NULL_TREE);
7209117395Skan
7210117395Skan  tree v2si_ftype_int_char
7211132718Skan    = build_function_type_list (opaque_V2SI_type_node,
7212117395Skan				integer_type_node, char_type_node, NULL_TREE);
7213117395Skan
7214117395Skan  tree v2si_ftype_char
7215132718Skan    = build_function_type_list (opaque_V2SI_type_node,
7216132718Skan				char_type_node, NULL_TREE);
7217117395Skan
7218117395Skan  tree int_ftype_int_int
7219117395Skan    = build_function_type_list (integer_type_node,
7220117395Skan				integer_type_node, integer_type_node,
7221117395Skan				NULL_TREE);
7222117395Skan
7223117395Skan  tree v4si_ftype_v4si_v4si
7224117395Skan    = build_function_type_list (V4SI_type_node,
7225117395Skan				V4SI_type_node, V4SI_type_node, NULL_TREE);
722690075Sobrien  tree v4sf_ftype_v4si_char
7227117395Skan    = build_function_type_list (V4SF_type_node,
7228117395Skan				V4SI_type_node, char_type_node, NULL_TREE);
722990075Sobrien  tree v4si_ftype_v4sf_char
7230117395Skan    = build_function_type_list (V4SI_type_node,
7231117395Skan				V4SF_type_node, char_type_node, NULL_TREE);
723290075Sobrien  tree v4si_ftype_v4si_char
7233117395Skan    = build_function_type_list (V4SI_type_node,
7234117395Skan				V4SI_type_node, char_type_node, NULL_TREE);
723590075Sobrien  tree v8hi_ftype_v8hi_char
7236117395Skan    = build_function_type_list (V8HI_type_node,
7237117395Skan				V8HI_type_node, char_type_node, NULL_TREE);
723890075Sobrien  tree v16qi_ftype_v16qi_char
7239117395Skan    = build_function_type_list (V16QI_type_node,
7240117395Skan				V16QI_type_node, char_type_node, NULL_TREE);
724190075Sobrien  tree v16qi_ftype_v16qi_v16qi_char
7242117395Skan    = build_function_type_list (V16QI_type_node,
7243117395Skan				V16QI_type_node, V16QI_type_node,
7244117395Skan				char_type_node, NULL_TREE);
724590075Sobrien  tree v8hi_ftype_v8hi_v8hi_char
7246117395Skan    = build_function_type_list (V8HI_type_node,
7247117395Skan				V8HI_type_node, V8HI_type_node,
7248117395Skan				char_type_node, NULL_TREE);
724990075Sobrien  tree v4si_ftype_v4si_v4si_char
7250117395Skan    = build_function_type_list (V4SI_type_node,
7251117395Skan				V4SI_type_node, V4SI_type_node,
7252117395Skan				char_type_node, NULL_TREE);
725390075Sobrien  tree v4sf_ftype_v4sf_v4sf_char
7254117395Skan    = build_function_type_list (V4SF_type_node,
7255117395Skan				V4SF_type_node, V4SF_type_node,
7256117395Skan				char_type_node, NULL_TREE);
725790075Sobrien  tree v4sf_ftype_v4sf_v4sf
7258117395Skan    = build_function_type_list (V4SF_type_node,
7259117395Skan				V4SF_type_node, V4SF_type_node, NULL_TREE);
726090075Sobrien  tree v4sf_ftype_v4sf_v4sf_v4si
7261117395Skan    = build_function_type_list (V4SF_type_node,
7262117395Skan				V4SF_type_node, V4SF_type_node,
7263117395Skan				V4SI_type_node, NULL_TREE);
726490075Sobrien  tree v4sf_ftype_v4sf_v4sf_v4sf
7265117395Skan    = build_function_type_list (V4SF_type_node,
7266117395Skan				V4SF_type_node, V4SF_type_node,
7267117395Skan				V4SF_type_node, NULL_TREE);
726890075Sobrien  tree v4si_ftype_v4si_v4si_v4si
7269117395Skan    = build_function_type_list (V4SI_type_node,
7270117395Skan				V4SI_type_node, V4SI_type_node,
7271117395Skan				V4SI_type_node, NULL_TREE);
727290075Sobrien  tree v8hi_ftype_v8hi_v8hi
7273117395Skan    = build_function_type_list (V8HI_type_node,
7274117395Skan				V8HI_type_node, V8HI_type_node, NULL_TREE);
727590075Sobrien  tree v8hi_ftype_v8hi_v8hi_v8hi
7276117395Skan    = build_function_type_list (V8HI_type_node,
7277117395Skan				V8HI_type_node, V8HI_type_node,
7278117395Skan				V8HI_type_node, NULL_TREE);
727990075Sobrien tree v4si_ftype_v8hi_v8hi_v4si
7280117395Skan    = build_function_type_list (V4SI_type_node,
7281117395Skan				V8HI_type_node, V8HI_type_node,
7282117395Skan				V4SI_type_node, NULL_TREE);
728390075Sobrien tree v4si_ftype_v16qi_v16qi_v4si
7284117395Skan    = build_function_type_list (V4SI_type_node,
7285117395Skan				V16QI_type_node, V16QI_type_node,
7286117395Skan				V4SI_type_node, NULL_TREE);
728790075Sobrien  tree v16qi_ftype_v16qi_v16qi
7288117395Skan    = build_function_type_list (V16QI_type_node,
7289117395Skan				V16QI_type_node, V16QI_type_node, NULL_TREE);
729090075Sobrien  tree v4si_ftype_v4sf_v4sf
7291117395Skan    = build_function_type_list (V4SI_type_node,
7292117395Skan				V4SF_type_node, V4SF_type_node, NULL_TREE);
729390075Sobrien  tree v8hi_ftype_v16qi_v16qi
7294117395Skan    = build_function_type_list (V8HI_type_node,
7295117395Skan				V16QI_type_node, V16QI_type_node, NULL_TREE);
729690075Sobrien  tree v4si_ftype_v8hi_v8hi
7297117395Skan    = build_function_type_list (V4SI_type_node,
7298117395Skan				V8HI_type_node, V8HI_type_node, NULL_TREE);
729990075Sobrien  tree v8hi_ftype_v4si_v4si
7300117395Skan    = build_function_type_list (V8HI_type_node,
7301117395Skan				V4SI_type_node, V4SI_type_node, NULL_TREE);
730290075Sobrien  tree v16qi_ftype_v8hi_v8hi
7303117395Skan    = build_function_type_list (V16QI_type_node,
7304117395Skan				V8HI_type_node, V8HI_type_node, NULL_TREE);
730590075Sobrien  tree v4si_ftype_v16qi_v4si
7306117395Skan    = build_function_type_list (V4SI_type_node,
7307117395Skan				V16QI_type_node, V4SI_type_node, NULL_TREE);
730890075Sobrien  tree v4si_ftype_v16qi_v16qi
7309117395Skan    = build_function_type_list (V4SI_type_node,
7310117395Skan				V16QI_type_node, V16QI_type_node, NULL_TREE);
731190075Sobrien  tree v4si_ftype_v8hi_v4si
7312117395Skan    = build_function_type_list (V4SI_type_node,
7313117395Skan				V8HI_type_node, V4SI_type_node, NULL_TREE);
731490075Sobrien  tree v4si_ftype_v8hi
7315117395Skan    = build_function_type_list (V4SI_type_node, V8HI_type_node, NULL_TREE);
731690075Sobrien  tree int_ftype_v4si_v4si
7317117395Skan    = build_function_type_list (integer_type_node,
7318117395Skan				V4SI_type_node, V4SI_type_node, NULL_TREE);
731990075Sobrien  tree int_ftype_v4sf_v4sf
7320117395Skan    = build_function_type_list (integer_type_node,
7321117395Skan				V4SF_type_node, V4SF_type_node, NULL_TREE);
732290075Sobrien  tree int_ftype_v16qi_v16qi
7323117395Skan    = build_function_type_list (integer_type_node,
7324117395Skan				V16QI_type_node, V16QI_type_node, NULL_TREE);
732590075Sobrien  tree int_ftype_v8hi_v8hi
7326117395Skan    = build_function_type_list (integer_type_node,
7327117395Skan				V8HI_type_node, V8HI_type_node, NULL_TREE);
732890075Sobrien
732990075Sobrien  /* Add the simple ternary operators.  */
733090075Sobrien  d = (struct builtin_description *) bdesc_3arg;
7331117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_3arg); i++, d++)
733290075Sobrien    {
733390075Sobrien
733490075Sobrien      enum machine_mode mode0, mode1, mode2, mode3;
733590075Sobrien      tree type;
733690075Sobrien
7337117395Skan      if (d->name == 0 || d->icode == CODE_FOR_nothing)
733890075Sobrien	continue;
733990075Sobrien
734090075Sobrien      mode0 = insn_data[d->icode].operand[0].mode;
734190075Sobrien      mode1 = insn_data[d->icode].operand[1].mode;
734290075Sobrien      mode2 = insn_data[d->icode].operand[2].mode;
734390075Sobrien      mode3 = insn_data[d->icode].operand[3].mode;
734490075Sobrien
734590075Sobrien      /* When all four are of the same mode.  */
734690075Sobrien      if (mode0 == mode1 && mode1 == mode2 && mode2 == mode3)
734790075Sobrien	{
734890075Sobrien	  switch (mode0)
734990075Sobrien	    {
735090075Sobrien	    case V4SImode:
735190075Sobrien	      type = v4si_ftype_v4si_v4si_v4si;
735290075Sobrien	      break;
735390075Sobrien	    case V4SFmode:
735490075Sobrien	      type = v4sf_ftype_v4sf_v4sf_v4sf;
735590075Sobrien	      break;
735690075Sobrien	    case V8HImode:
735790075Sobrien	      type = v8hi_ftype_v8hi_v8hi_v8hi;
735890075Sobrien	      break;
735990075Sobrien	    case V16QImode:
736090075Sobrien	      type = v16qi_ftype_v16qi_v16qi_v16qi;
736190075Sobrien	      break;
736290075Sobrien	    default:
736390075Sobrien	      abort();
736490075Sobrien	    }
736590075Sobrien	}
736690075Sobrien      else if (mode0 == mode1 && mode1 == mode2 && mode3 == V16QImode)
736790075Sobrien        {
736890075Sobrien	  switch (mode0)
736990075Sobrien	    {
737090075Sobrien	    case V4SImode:
737190075Sobrien	      type = v4si_ftype_v4si_v4si_v16qi;
737290075Sobrien	      break;
737390075Sobrien	    case V4SFmode:
737490075Sobrien	      type = v4sf_ftype_v4sf_v4sf_v16qi;
737590075Sobrien	      break;
737690075Sobrien	    case V8HImode:
737790075Sobrien	      type = v8hi_ftype_v8hi_v8hi_v16qi;
737890075Sobrien	      break;
737990075Sobrien	    case V16QImode:
738090075Sobrien	      type = v16qi_ftype_v16qi_v16qi_v16qi;
738190075Sobrien	      break;
738290075Sobrien	    default:
738390075Sobrien	      abort();
738490075Sobrien	    }
738590075Sobrien	}
738690075Sobrien      else if (mode0 == V4SImode && mode1 == V16QImode && mode2 == V16QImode
738790075Sobrien	       && mode3 == V4SImode)
738890075Sobrien	type = v4si_ftype_v16qi_v16qi_v4si;
738990075Sobrien      else if (mode0 == V4SImode && mode1 == V8HImode && mode2 == V8HImode
739090075Sobrien	       && mode3 == V4SImode)
739190075Sobrien	type = v4si_ftype_v8hi_v8hi_v4si;
739290075Sobrien      else if (mode0 == V4SFmode && mode1 == V4SFmode && mode2 == V4SFmode
739390075Sobrien	       && mode3 == V4SImode)
739490075Sobrien	type = v4sf_ftype_v4sf_v4sf_v4si;
739590075Sobrien
739690075Sobrien      /* vchar, vchar, vchar, 4 bit literal.  */
739790075Sobrien      else if (mode0 == V16QImode && mode1 == mode0 && mode2 == mode0
739890075Sobrien	       && mode3 == QImode)
739990075Sobrien	type = v16qi_ftype_v16qi_v16qi_char;
740090075Sobrien
740190075Sobrien      /* vshort, vshort, vshort, 4 bit literal.  */
740290075Sobrien      else if (mode0 == V8HImode && mode1 == mode0 && mode2 == mode0
740390075Sobrien	       && mode3 == QImode)
740490075Sobrien	type = v8hi_ftype_v8hi_v8hi_char;
740590075Sobrien
740690075Sobrien      /* vint, vint, vint, 4 bit literal.  */
740790075Sobrien      else if (mode0 == V4SImode && mode1 == mode0 && mode2 == mode0
740890075Sobrien	       && mode3 == QImode)
740990075Sobrien	type = v4si_ftype_v4si_v4si_char;
741090075Sobrien
741190075Sobrien      /* vfloat, vfloat, vfloat, 4 bit literal.  */
741290075Sobrien      else if (mode0 == V4SFmode && mode1 == mode0 && mode2 == mode0
741390075Sobrien	       && mode3 == QImode)
741490075Sobrien	type = v4sf_ftype_v4sf_v4sf_char;
741590075Sobrien
741690075Sobrien      else
741790075Sobrien	abort ();
741890075Sobrien
741990075Sobrien      def_builtin (d->mask, d->name, type, d->code);
742090075Sobrien    }
742190075Sobrien
742290075Sobrien  /* Add the simple binary operators.  */
742390075Sobrien  d = (struct builtin_description *) bdesc_2arg;
7424117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
742590075Sobrien    {
742690075Sobrien      enum machine_mode mode0, mode1, mode2;
742790075Sobrien      tree type;
742890075Sobrien
7429117395Skan      if (d->name == 0 || d->icode == CODE_FOR_nothing)
743090075Sobrien	continue;
743190075Sobrien
743290075Sobrien      mode0 = insn_data[d->icode].operand[0].mode;
743390075Sobrien      mode1 = insn_data[d->icode].operand[1].mode;
743490075Sobrien      mode2 = insn_data[d->icode].operand[2].mode;
743590075Sobrien
743690075Sobrien      /* When all three operands are of the same mode.  */
743790075Sobrien      if (mode0 == mode1 && mode1 == mode2)
743890075Sobrien	{
743990075Sobrien	  switch (mode0)
744090075Sobrien	    {
744190075Sobrien	    case V4SFmode:
744290075Sobrien	      type = v4sf_ftype_v4sf_v4sf;
744390075Sobrien	      break;
744490075Sobrien	    case V4SImode:
744590075Sobrien	      type = v4si_ftype_v4si_v4si;
744690075Sobrien	      break;
744790075Sobrien	    case V16QImode:
744890075Sobrien	      type = v16qi_ftype_v16qi_v16qi;
744990075Sobrien	      break;
745090075Sobrien	    case V8HImode:
745190075Sobrien	      type = v8hi_ftype_v8hi_v8hi;
745290075Sobrien	      break;
7453117395Skan	    case V2SImode:
7454117395Skan	      type = v2si_ftype_v2si_v2si;
7455117395Skan	      break;
7456117395Skan	    case V2SFmode:
7457117395Skan	      type = v2sf_ftype_v2sf_v2sf;
7458117395Skan	      break;
7459117395Skan	    case SImode:
7460117395Skan	      type = int_ftype_int_int;
7461117395Skan	      break;
746290075Sobrien	    default:
746390075Sobrien	      abort ();
746490075Sobrien	    }
746590075Sobrien	}
746690075Sobrien
746790075Sobrien      /* A few other combos we really don't want to do manually.  */
746890075Sobrien
746990075Sobrien      /* vint, vfloat, vfloat.  */
747090075Sobrien      else if (mode0 == V4SImode && mode1 == V4SFmode && mode2 == V4SFmode)
747190075Sobrien	type = v4si_ftype_v4sf_v4sf;
747290075Sobrien
747390075Sobrien      /* vshort, vchar, vchar.  */
747490075Sobrien      else if (mode0 == V8HImode && mode1 == V16QImode && mode2 == V16QImode)
747590075Sobrien	type = v8hi_ftype_v16qi_v16qi;
747690075Sobrien
747790075Sobrien      /* vint, vshort, vshort.  */
747890075Sobrien      else if (mode0 == V4SImode && mode1 == V8HImode && mode2 == V8HImode)
747990075Sobrien	type = v4si_ftype_v8hi_v8hi;
748090075Sobrien
748190075Sobrien      /* vshort, vint, vint.  */
748290075Sobrien      else if (mode0 == V8HImode && mode1 == V4SImode && mode2 == V4SImode)
748390075Sobrien	type = v8hi_ftype_v4si_v4si;
748490075Sobrien
748590075Sobrien      /* vchar, vshort, vshort.  */
748690075Sobrien      else if (mode0 == V16QImode && mode1 == V8HImode && mode2 == V8HImode)
748790075Sobrien	type = v16qi_ftype_v8hi_v8hi;
748890075Sobrien
748990075Sobrien      /* vint, vchar, vint.  */
749090075Sobrien      else if (mode0 == V4SImode && mode1 == V16QImode && mode2 == V4SImode)
749190075Sobrien	type = v4si_ftype_v16qi_v4si;
749290075Sobrien
749390075Sobrien      /* vint, vchar, vchar.  */
749490075Sobrien      else if (mode0 == V4SImode && mode1 == V16QImode && mode2 == V16QImode)
749590075Sobrien	type = v4si_ftype_v16qi_v16qi;
749690075Sobrien
749790075Sobrien      /* vint, vshort, vint.  */
749890075Sobrien      else if (mode0 == V4SImode && mode1 == V8HImode && mode2 == V4SImode)
749990075Sobrien	type = v4si_ftype_v8hi_v4si;
750090075Sobrien
750190075Sobrien      /* vint, vint, 5 bit literal.  */
750290075Sobrien      else if (mode0 == V4SImode && mode1 == V4SImode && mode2 == QImode)
750390075Sobrien	type = v4si_ftype_v4si_char;
750490075Sobrien
750590075Sobrien      /* vshort, vshort, 5 bit literal.  */
750690075Sobrien      else if (mode0 == V8HImode && mode1 == V8HImode && mode2 == QImode)
750790075Sobrien	type = v8hi_ftype_v8hi_char;
750890075Sobrien
750990075Sobrien      /* vchar, vchar, 5 bit literal.  */
751090075Sobrien      else if (mode0 == V16QImode && mode1 == V16QImode && mode2 == QImode)
751190075Sobrien	type = v16qi_ftype_v16qi_char;
751290075Sobrien
751390075Sobrien      /* vfloat, vint, 5 bit literal.  */
751490075Sobrien      else if (mode0 == V4SFmode && mode1 == V4SImode && mode2 == QImode)
751590075Sobrien	type = v4sf_ftype_v4si_char;
751690075Sobrien
751790075Sobrien      /* vint, vfloat, 5 bit literal.  */
751890075Sobrien      else if (mode0 == V4SImode && mode1 == V4SFmode && mode2 == QImode)
751990075Sobrien	type = v4si_ftype_v4sf_char;
752090075Sobrien
7521117395Skan      else if (mode0 == V2SImode && mode1 == SImode && mode2 == SImode)
7522117395Skan	type = v2si_ftype_int_int;
7523117395Skan
7524117395Skan      else if (mode0 == V2SImode && mode1 == V2SImode && mode2 == QImode)
7525117395Skan	type = v2si_ftype_v2si_char;
7526117395Skan
7527117395Skan      else if (mode0 == V2SImode && mode1 == SImode && mode2 == QImode)
7528117395Skan	type = v2si_ftype_int_char;
7529117395Skan
753090075Sobrien      /* int, x, x.  */
753190075Sobrien      else if (mode0 == SImode)
753290075Sobrien	{
753390075Sobrien	  switch (mode1)
753490075Sobrien	    {
753590075Sobrien	    case V4SImode:
753690075Sobrien	      type = int_ftype_v4si_v4si;
753790075Sobrien	      break;
753890075Sobrien	    case V4SFmode:
753990075Sobrien	      type = int_ftype_v4sf_v4sf;
754090075Sobrien	      break;
754190075Sobrien	    case V16QImode:
754290075Sobrien	      type = int_ftype_v16qi_v16qi;
754390075Sobrien	      break;
754490075Sobrien	    case V8HImode:
754590075Sobrien	      type = int_ftype_v8hi_v8hi;
754690075Sobrien	      break;
754790075Sobrien	    default:
754890075Sobrien	      abort ();
754990075Sobrien	    }
755090075Sobrien	}
755190075Sobrien
755290075Sobrien      else
755390075Sobrien	abort ();
755490075Sobrien
755590075Sobrien      def_builtin (d->mask, d->name, type, d->code);
755690075Sobrien    }
755790075Sobrien
755890075Sobrien  /* Add the simple unary operators.  */
755990075Sobrien  d = (struct builtin_description *) bdesc_1arg;
7560117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
756190075Sobrien    {
756290075Sobrien      enum machine_mode mode0, mode1;
756390075Sobrien      tree type;
756490075Sobrien
7565117395Skan      if (d->name == 0 || d->icode == CODE_FOR_nothing)
756690075Sobrien	continue;
756790075Sobrien
756890075Sobrien      mode0 = insn_data[d->icode].operand[0].mode;
756990075Sobrien      mode1 = insn_data[d->icode].operand[1].mode;
757090075Sobrien
757190075Sobrien      if (mode0 == V4SImode && mode1 == QImode)
757290075Sobrien        type = v4si_ftype_char;
757390075Sobrien      else if (mode0 == V8HImode && mode1 == QImode)
757490075Sobrien        type = v8hi_ftype_char;
757590075Sobrien      else if (mode0 == V16QImode && mode1 == QImode)
757690075Sobrien        type = v16qi_ftype_char;
757790075Sobrien      else if (mode0 == V4SFmode && mode1 == V4SFmode)
757890075Sobrien	type = v4sf_ftype_v4sf;
757990075Sobrien      else if (mode0 == V8HImode && mode1 == V16QImode)
758090075Sobrien	type = v8hi_ftype_v16qi;
758190075Sobrien      else if (mode0 == V4SImode && mode1 == V8HImode)
758290075Sobrien	type = v4si_ftype_v8hi;
7583117395Skan      else if (mode0 == V2SImode && mode1 == V2SImode)
7584117395Skan	type = v2si_ftype_v2si;
7585117395Skan      else if (mode0 == V2SFmode && mode1 == V2SFmode)
7586117395Skan	type = v2sf_ftype_v2sf;
7587117395Skan      else if (mode0 == V2SFmode && mode1 == V2SImode)
7588117395Skan	type = v2sf_ftype_v2si;
7589117395Skan      else if (mode0 == V2SImode && mode1 == V2SFmode)
7590117395Skan	type = v2si_ftype_v2sf;
7591117395Skan      else if (mode0 == V2SImode && mode1 == QImode)
7592117395Skan	type = v2si_ftype_char;
759390075Sobrien      else
759490075Sobrien	abort ();
759590075Sobrien
759690075Sobrien      def_builtin (d->mask, d->name, type, d->code);
759790075Sobrien    }
759890075Sobrien}
759990075Sobrien
7600132718Skanstatic void
7601132718Skanrs6000_init_libfuncs (void)
7602132718Skan{
7603132718Skan  if (!TARGET_HARD_FLOAT)
7604132718Skan    return;
7605132718Skan
7606132718Skan  if (DEFAULT_ABI != ABI_V4)
7607132718Skan    {
7608132718Skan      if (TARGET_XCOFF && ! TARGET_POWER2 && ! TARGET_POWERPC)
7609132718Skan	{
7610132718Skan	  /* AIX library routines for float->int conversion.  */
7611132718Skan	  set_conv_libfunc (sfix_optab, SImode, DFmode, "__itrunc");
7612132718Skan	  set_conv_libfunc (ufix_optab, SImode, DFmode, "__uitrunc");
7613132718Skan	  set_conv_libfunc (sfix_optab, SImode, TFmode, "_qitrunc");
7614132718Skan	  set_conv_libfunc (ufix_optab, SImode, TFmode, "_quitrunc");
7615132718Skan	}
7616132718Skan
7617132718Skan      /* Standard AIX/Darwin/64-bit SVR4 quad floating point routines.  */
7618132718Skan      set_optab_libfunc (add_optab, TFmode, "_xlqadd");
7619132718Skan      set_optab_libfunc (sub_optab, TFmode, "_xlqsub");
7620132718Skan      set_optab_libfunc (smul_optab, TFmode, "_xlqmul");
7621132718Skan      set_optab_libfunc (sdiv_optab, TFmode, "_xlqdiv");
7622132718Skan    }
7623132718Skan  else
7624132718Skan    {
7625132718Skan      /* 32-bit SVR4 quad floating point routines.  */
7626132718Skan
7627132718Skan      set_optab_libfunc (add_optab, TFmode, "_q_add");
7628132718Skan      set_optab_libfunc (sub_optab, TFmode, "_q_sub");
7629132718Skan      set_optab_libfunc (neg_optab, TFmode, "_q_neg");
7630132718Skan      set_optab_libfunc (smul_optab, TFmode, "_q_mul");
7631132718Skan      set_optab_libfunc (sdiv_optab, TFmode, "_q_div");
7632132718Skan      if (TARGET_PPC_GPOPT || TARGET_POWER2)
7633132718Skan	set_optab_libfunc (sqrt_optab, TFmode, "_q_sqrt");
7634132718Skan
7635132718Skan      set_optab_libfunc (eq_optab, TFmode, "_q_feq");
7636132718Skan      set_optab_libfunc (ne_optab, TFmode, "_q_fne");
7637132718Skan      set_optab_libfunc (gt_optab, TFmode, "_q_fgt");
7638132718Skan      set_optab_libfunc (ge_optab, TFmode, "_q_fge");
7639132718Skan      set_optab_libfunc (lt_optab, TFmode, "_q_flt");
7640132718Skan      set_optab_libfunc (le_optab, TFmode, "_q_fle");
7641132718Skan
7642132718Skan      set_conv_libfunc (sext_optab, TFmode, SFmode, "_q_stoq");
7643132718Skan      set_conv_libfunc (sext_optab, TFmode, DFmode, "_q_dtoq");
7644132718Skan      set_conv_libfunc (trunc_optab, SFmode, TFmode, "_q_qtos");
7645132718Skan      set_conv_libfunc (trunc_optab, DFmode, TFmode, "_q_qtod");
7646132718Skan      set_conv_libfunc (sfix_optab, SImode, TFmode, "_q_qtoi");
7647132718Skan      set_conv_libfunc (ufix_optab, SImode, TFmode, "_q_qtou");
7648132718Skan      set_conv_libfunc (sfloat_optab, TFmode, SImode, "_q_itoq");
7649132718Skan    }
7650132718Skan}
765190075Sobrien
765290075Sobrien/* Expand a block move operation, and return 1 if successful.  Return 0
765390075Sobrien   if we should let the compiler generate normal code.
765490075Sobrien
765590075Sobrien   operands[0] is the destination
765690075Sobrien   operands[1] is the source
765790075Sobrien   operands[2] is the length
765890075Sobrien   operands[3] is the alignment */
765990075Sobrien
766090075Sobrien#define MAX_MOVE_REG 4
766190075Sobrien
766290075Sobrienint
7663132718Skanexpand_block_move (rtx operands[])
766490075Sobrien{
766590075Sobrien  rtx orig_dest = operands[0];
766690075Sobrien  rtx orig_src	= operands[1];
766790075Sobrien  rtx bytes_rtx	= operands[2];
766890075Sobrien  rtx align_rtx = operands[3];
766990075Sobrien  int constp	= (GET_CODE (bytes_rtx) == CONST_INT);
767090075Sobrien  int align;
767190075Sobrien  int bytes;
767290075Sobrien  int offset;
767390075Sobrien  int move_bytes;
7674132718Skan  rtx stores[MAX_MOVE_REG];
7675132718Skan  int num_reg = 0;
767690075Sobrien
767790075Sobrien  /* If this is not a fixed size move, just call memcpy */
767890075Sobrien  if (! constp)
767990075Sobrien    return 0;
768090075Sobrien
768190075Sobrien  /* If this is not a fixed size alignment, abort */
768290075Sobrien  if (GET_CODE (align_rtx) != CONST_INT)
768390075Sobrien    abort ();
768490075Sobrien  align = INTVAL (align_rtx);
768590075Sobrien
768690075Sobrien  /* Anything to move? */
768790075Sobrien  bytes = INTVAL (bytes_rtx);
768890075Sobrien  if (bytes <= 0)
768990075Sobrien    return 1;
769090075Sobrien
769190075Sobrien  /* store_one_arg depends on expand_block_move to handle at least the size of
769290075Sobrien     reg_parm_stack_space.  */
769390075Sobrien  if (bytes > (TARGET_POWERPC64 ? 64 : 32))
769490075Sobrien    return 0;
769590075Sobrien
7696132718Skan  for (offset = 0; bytes > 0; offset += move_bytes, bytes -= move_bytes)
769790075Sobrien    {
7698132718Skan      union {
7699132718Skan	rtx (*movstrsi) (rtx, rtx, rtx, rtx);
7700132718Skan	rtx (*mov) (rtx, rtx);
7701132718Skan      } gen_func;
7702132718Skan      enum machine_mode mode = BLKmode;
7703132718Skan      rtx src, dest;
7704132718Skan
7705132718Skan      if (TARGET_STRING
7706132718Skan	  && bytes > 24		/* move up to 32 bytes at a time */
7707132718Skan	  && ! fixed_regs[5]
7708132718Skan	  && ! fixed_regs[6]
7709132718Skan	  && ! fixed_regs[7]
7710132718Skan	  && ! fixed_regs[8]
7711132718Skan	  && ! fixed_regs[9]
7712132718Skan	  && ! fixed_regs[10]
7713132718Skan	  && ! fixed_regs[11]
7714132718Skan	  && ! fixed_regs[12])
771590075Sobrien	{
7716132718Skan	  move_bytes = (bytes > 32) ? 32 : bytes;
7717132718Skan	  gen_func.movstrsi = gen_movstrsi_8reg;
7718132718Skan	}
7719132718Skan      else if (TARGET_STRING
7720132718Skan	       && bytes > 16	/* move up to 24 bytes at a time */
7721132718Skan	       && ! fixed_regs[5]
7722132718Skan	       && ! fixed_regs[6]
7723132718Skan	       && ! fixed_regs[7]
7724132718Skan	       && ! fixed_regs[8]
7725132718Skan	       && ! fixed_regs[9]
7726132718Skan	       && ! fixed_regs[10])
7727132718Skan	{
7728132718Skan	  move_bytes = (bytes > 24) ? 24 : bytes;
7729132718Skan	  gen_func.movstrsi = gen_movstrsi_6reg;
7730132718Skan	}
7731132718Skan      else if (TARGET_STRING
7732132718Skan	       && bytes > 8	/* move up to 16 bytes at a time */
7733132718Skan	       && ! fixed_regs[5]
7734132718Skan	       && ! fixed_regs[6]
7735132718Skan	       && ! fixed_regs[7]
7736132718Skan	       && ! fixed_regs[8])
7737132718Skan	{
7738132718Skan	  move_bytes = (bytes > 16) ? 16 : bytes;
7739132718Skan	  gen_func.movstrsi = gen_movstrsi_4reg;
7740132718Skan	}
7741132718Skan      else if (bytes >= 8 && TARGET_POWERPC64
7742132718Skan	       /* 64-bit loads and stores require word-aligned
7743132718Skan		  displacements.  */
7744132718Skan	       && (align >= 8 || (! STRICT_ALIGNMENT && align >= 4)))
7745132718Skan	{
7746132718Skan	  move_bytes = 8;
7747132718Skan	  mode = DImode;
7748132718Skan	  gen_func.mov = gen_movdi;
7749132718Skan	}
7750132718Skan      else if (TARGET_STRING && bytes > 4 && !TARGET_POWERPC64)
7751132718Skan	{			/* move up to 8 bytes at a time */
7752132718Skan	  move_bytes = (bytes > 8) ? 8 : bytes;
7753132718Skan	  gen_func.movstrsi = gen_movstrsi_2reg;
7754132718Skan	}
7755132718Skan      else if (bytes >= 4 && (align >= 4 || ! STRICT_ALIGNMENT))
7756132718Skan	{			/* move 4 bytes */
7757132718Skan	  move_bytes = 4;
7758132718Skan	  mode = SImode;
7759132718Skan	  gen_func.mov = gen_movsi;
7760132718Skan	}
7761132718Skan      else if (bytes == 2 && (align >= 2 || ! STRICT_ALIGNMENT))
7762132718Skan	{			/* move 2 bytes */
7763132718Skan	  move_bytes = 2;
7764132718Skan	  mode = HImode;
7765132718Skan	  gen_func.mov = gen_movhi;
7766132718Skan	}
7767132718Skan      else if (TARGET_STRING && bytes > 1)
7768132718Skan	{			/* move up to 4 bytes at a time */
7769132718Skan	  move_bytes = (bytes > 4) ? 4 : bytes;
7770132718Skan	  gen_func.movstrsi = gen_movstrsi_1reg;
7771132718Skan	}
7772132718Skan      else /* move 1 byte at a time */
7773132718Skan	{
7774132718Skan	  move_bytes = 1;
7775132718Skan	  mode = QImode;
7776132718Skan	  gen_func.mov = gen_movqi;
7777132718Skan	}
7778132718Skan
7779132718Skan      src = adjust_address (orig_src, mode, offset);
7780132718Skan      dest = adjust_address (orig_dest, mode, offset);
7781132718Skan
7782132718Skan      if (mode != BLKmode)
7783132718Skan	{
7784132718Skan	  rtx tmp_reg = gen_reg_rtx (mode);
7785132718Skan
7786132718Skan	  emit_insn ((*gen_func.mov) (tmp_reg, src));
7787132718Skan	  stores[num_reg++] = (*gen_func.mov) (dest, tmp_reg);
7788132718Skan	}
7789103445Skan
7790132718Skan      if (mode == BLKmode || num_reg >= MAX_MOVE_REG || bytes == move_bytes)
7791132718Skan	{
7792132718Skan	  int i;
7793132718Skan	  for (i = 0; i < num_reg; i++)
7794132718Skan	    emit_insn (stores[i]);
7795132718Skan	  num_reg = 0;
779690075Sobrien	}
779790075Sobrien
7798132718Skan      if (mode == BLKmode)
779990075Sobrien	{
7800132718Skan	  /* Move the address into scratch registers.  The movstrsi
7801132718Skan	     patterns require zero offset.  */
7802132718Skan	  if (!REG_P (XEXP (src, 0)))
780390075Sobrien	    {
7804132718Skan	      rtx src_reg = copy_addr_to_reg (XEXP (src, 0));
7805132718Skan	      src = replace_equiv_address (src, src_reg);
780690075Sobrien	    }
7807132718Skan	  set_mem_size (src, GEN_INT (move_bytes));
7808132718Skan
7809132718Skan	  if (!REG_P (XEXP (dest, 0)))
781090075Sobrien	    {
7811132718Skan	      rtx dest_reg = copy_addr_to_reg (XEXP (dest, 0));
7812132718Skan	      dest = replace_equiv_address (dest, dest_reg);
781390075Sobrien	    }
7814132718Skan	  set_mem_size (dest, GEN_INT (move_bytes));
7815132718Skan
7816132718Skan	  emit_insn ((*gen_func.movstrsi) (dest, src,
7817132718Skan					   GEN_INT (move_bytes & 31),
7818132718Skan					   align_rtx));
781990075Sobrien	}
782090075Sobrien    }
782190075Sobrien
782290075Sobrien  return 1;
782390075Sobrien}
782490075Sobrien
782590075Sobrien
782690075Sobrien/* Return 1 if OP is a load multiple operation.  It is known to be a
782790075Sobrien   PARALLEL and the first section will be tested.  */
782890075Sobrien
782990075Sobrienint
7830132718Skanload_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
783190075Sobrien{
783290075Sobrien  int count = XVECLEN (op, 0);
783390075Sobrien  unsigned int dest_regno;
783490075Sobrien  rtx src_addr;
783590075Sobrien  int i;
783690075Sobrien
783790075Sobrien  /* Perform a quick check so we don't blow up below.  */
783890075Sobrien  if (count <= 1
783990075Sobrien      || GET_CODE (XVECEXP (op, 0, 0)) != SET
784090075Sobrien      || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != REG
784190075Sobrien      || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != MEM)
784290075Sobrien    return 0;
784390075Sobrien
784490075Sobrien  dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, 0)));
784590075Sobrien  src_addr = XEXP (SET_SRC (XVECEXP (op, 0, 0)), 0);
784690075Sobrien
784790075Sobrien  for (i = 1; i < count; i++)
784890075Sobrien    {
784990075Sobrien      rtx elt = XVECEXP (op, 0, i);
785090075Sobrien
785190075Sobrien      if (GET_CODE (elt) != SET
785290075Sobrien	  || GET_CODE (SET_DEST (elt)) != REG
785390075Sobrien	  || GET_MODE (SET_DEST (elt)) != SImode
785490075Sobrien	  || REGNO (SET_DEST (elt)) != dest_regno + i
785590075Sobrien	  || GET_CODE (SET_SRC (elt)) != MEM
785690075Sobrien	  || GET_MODE (SET_SRC (elt)) != SImode
785790075Sobrien	  || GET_CODE (XEXP (SET_SRC (elt), 0)) != PLUS
785890075Sobrien	  || ! rtx_equal_p (XEXP (XEXP (SET_SRC (elt), 0), 0), src_addr)
785990075Sobrien	  || GET_CODE (XEXP (XEXP (SET_SRC (elt), 0), 1)) != CONST_INT
786090075Sobrien	  || INTVAL (XEXP (XEXP (SET_SRC (elt), 0), 1)) != i * 4)
786190075Sobrien	return 0;
786290075Sobrien    }
786390075Sobrien
786490075Sobrien  return 1;
786590075Sobrien}
786690075Sobrien
786790075Sobrien/* Similar, but tests for store multiple.  Here, the second vector element
786890075Sobrien   is a CLOBBER.  It will be tested later.  */
786990075Sobrien
787090075Sobrienint
7871132718Skanstore_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
787290075Sobrien{
787390075Sobrien  int count = XVECLEN (op, 0) - 1;
787490075Sobrien  unsigned int src_regno;
787590075Sobrien  rtx dest_addr;
787690075Sobrien  int i;
787790075Sobrien
787890075Sobrien  /* Perform a quick check so we don't blow up below.  */
787990075Sobrien  if (count <= 1
788090075Sobrien      || GET_CODE (XVECEXP (op, 0, 0)) != SET
788190075Sobrien      || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != MEM
788290075Sobrien      || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != REG)
788390075Sobrien    return 0;
788490075Sobrien
788590075Sobrien  src_regno = REGNO (SET_SRC (XVECEXP (op, 0, 0)));
788690075Sobrien  dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, 0)), 0);
788790075Sobrien
788890075Sobrien  for (i = 1; i < count; i++)
788990075Sobrien    {
789090075Sobrien      rtx elt = XVECEXP (op, 0, i + 1);
789190075Sobrien
789290075Sobrien      if (GET_CODE (elt) != SET
789390075Sobrien	  || GET_CODE (SET_SRC (elt)) != REG
789490075Sobrien	  || GET_MODE (SET_SRC (elt)) != SImode
789590075Sobrien	  || REGNO (SET_SRC (elt)) != src_regno + i
789690075Sobrien	  || GET_CODE (SET_DEST (elt)) != MEM
789790075Sobrien	  || GET_MODE (SET_DEST (elt)) != SImode
789890075Sobrien	  || GET_CODE (XEXP (SET_DEST (elt), 0)) != PLUS
789990075Sobrien	  || ! rtx_equal_p (XEXP (XEXP (SET_DEST (elt), 0), 0), dest_addr)
790090075Sobrien	  || GET_CODE (XEXP (XEXP (SET_DEST (elt), 0), 1)) != CONST_INT
790190075Sobrien	  || INTVAL (XEXP (XEXP (SET_DEST (elt), 0), 1)) != i * 4)
790290075Sobrien	return 0;
790390075Sobrien    }
790490075Sobrien
790590075Sobrien  return 1;
790690075Sobrien}
790790075Sobrien
7908110611Skan/* Return a string to perform a load_multiple operation.
7909110611Skan   operands[0] is the vector.
7910110611Skan   operands[1] is the source address.
7911110611Skan   operands[2] is the first destination register.  */
7912110611Skan
7913110611Skanconst char *
7914132718Skanrs6000_output_load_multiple (rtx operands[3])
7915110611Skan{
7916110611Skan  /* We have to handle the case where the pseudo used to contain the address
7917110611Skan     is assigned to one of the output registers.  */
7918110611Skan  int i, j;
7919110611Skan  int words = XVECLEN (operands[0], 0);
7920110611Skan  rtx xop[10];
7921110611Skan
7922110611Skan  if (XVECLEN (operands[0], 0) == 1)
7923110611Skan    return "{l|lwz} %2,0(%1)";
7924110611Skan
7925110611Skan  for (i = 0; i < words; i++)
7926110611Skan    if (refers_to_regno_p (REGNO (operands[2]) + i,
7927110611Skan			   REGNO (operands[2]) + i + 1, operands[1], 0))
7928110611Skan      {
7929110611Skan	if (i == words-1)
7930110611Skan	  {
7931110611Skan	    xop[0] = GEN_INT (4 * (words-1));
7932110611Skan	    xop[1] = operands[1];
7933110611Skan	    xop[2] = operands[2];
7934110611Skan	    output_asm_insn ("{lsi|lswi} %2,%1,%0\n\t{l|lwz} %1,%0(%1)", xop);
7935110611Skan	    return "";
7936110611Skan	  }
7937110611Skan	else if (i == 0)
7938110611Skan	  {
7939110611Skan	    xop[0] = GEN_INT (4 * (words-1));
7940110611Skan	    xop[1] = operands[1];
7941110611Skan	    xop[2] = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
7942110611Skan	    output_asm_insn ("{cal %1,4(%1)|addi %1,%1,4}\n\t{lsi|lswi} %2,%1,%0\n\t{l|lwz} %1,-4(%1)", xop);
7943110611Skan	    return "";
7944110611Skan	  }
7945110611Skan	else
7946110611Skan	  {
7947110611Skan	    for (j = 0; j < words; j++)
7948110611Skan	      if (j != i)
7949110611Skan		{
7950110611Skan		  xop[0] = GEN_INT (j * 4);
7951110611Skan		  xop[1] = operands[1];
7952110611Skan		  xop[2] = gen_rtx_REG (SImode, REGNO (operands[2]) + j);
7953110611Skan		  output_asm_insn ("{l|lwz} %2,%0(%1)", xop);
7954110611Skan		}
7955110611Skan	    xop[0] = GEN_INT (i * 4);
7956110611Skan	    xop[1] = operands[1];
7957110611Skan	    output_asm_insn ("{l|lwz} %1,%0(%1)", xop);
7958110611Skan	    return "";
7959110611Skan	  }
7960110611Skan      }
7961110611Skan
7962110611Skan  return "{lsi|lswi} %2,%1,%N0";
7963110611Skan}
7964110611Skan
796590075Sobrien/* Return 1 for a parallel vrsave operation.  */
796690075Sobrien
796790075Sobrienint
7968132718Skanvrsave_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
796990075Sobrien{
797090075Sobrien  int count = XVECLEN (op, 0);
797190075Sobrien  unsigned int dest_regno, src_regno;
797290075Sobrien  int i;
797390075Sobrien
797490075Sobrien  if (count <= 1
797590075Sobrien      || GET_CODE (XVECEXP (op, 0, 0)) != SET
797690075Sobrien      || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != REG
797790075Sobrien      || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != UNSPEC_VOLATILE)
797890075Sobrien    return 0;
797990075Sobrien
798090075Sobrien  dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, 0)));
798190075Sobrien  src_regno  = REGNO (SET_SRC (XVECEXP (op, 0, 0)));
798290075Sobrien
798390075Sobrien  if (dest_regno != VRSAVE_REGNO
798490075Sobrien      && src_regno != VRSAVE_REGNO)
798590075Sobrien    return 0;
798690075Sobrien
798790075Sobrien  for (i = 1; i < count; i++)
798890075Sobrien    {
798990075Sobrien      rtx elt = XVECEXP (op, 0, i);
799090075Sobrien
799190075Sobrien      if (GET_CODE (elt) != CLOBBER
799290075Sobrien	  && GET_CODE (elt) != SET)
799390075Sobrien	return 0;
799490075Sobrien    }
799590075Sobrien
799690075Sobrien  return 1;
799790075Sobrien}
799890075Sobrien
7999132718Skan/* Return 1 for an PARALLEL suitable for mfcr.  */
8000132718Skan
8001132718Skanint
8002132718Skanmfcr_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
8003132718Skan{
8004132718Skan  int count = XVECLEN (op, 0);
8005132718Skan  int i;
8006132718Skan
8007132718Skan  /* Perform a quick check so we don't blow up below.  */
8008132718Skan  if (count < 1
8009132718Skan      || GET_CODE (XVECEXP (op, 0, 0)) != SET
8010132718Skan      || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != UNSPEC
8011132718Skan      || XVECLEN (SET_SRC (XVECEXP (op, 0, 0)), 0) != 2)
8012132718Skan    return 0;
8013132718Skan
8014132718Skan  for (i = 0; i < count; i++)
8015132718Skan    {
8016132718Skan      rtx exp = XVECEXP (op, 0, i);
8017132718Skan      rtx unspec;
8018132718Skan      int maskval;
8019132718Skan      rtx src_reg;
8020132718Skan
8021132718Skan      src_reg = XVECEXP (SET_SRC (exp), 0, 0);
8022132718Skan
8023132718Skan      if (GET_CODE (src_reg) != REG
8024132718Skan	  || GET_MODE (src_reg) != CCmode
8025132718Skan	  || ! CR_REGNO_P (REGNO (src_reg)))
8026132718Skan	return 0;
8027132718Skan
8028132718Skan      if (GET_CODE (exp) != SET
8029132718Skan	  || GET_CODE (SET_DEST (exp)) != REG
8030132718Skan	  || GET_MODE (SET_DEST (exp)) != SImode
8031132718Skan	  || ! INT_REGNO_P (REGNO (SET_DEST (exp))))
8032132718Skan	return 0;
8033132718Skan      unspec = SET_SRC (exp);
8034132718Skan      maskval = 1 << (MAX_CR_REGNO - REGNO (src_reg));
8035132718Skan
8036132718Skan      if (GET_CODE (unspec) != UNSPEC
8037132718Skan	  || XINT (unspec, 1) != UNSPEC_MOVESI_FROM_CR
8038132718Skan	  || XVECLEN (unspec, 0) != 2
8039132718Skan	  || XVECEXP (unspec, 0, 0) != src_reg
8040132718Skan	  || GET_CODE (XVECEXP (unspec, 0, 1)) != CONST_INT
8041132718Skan	  || INTVAL (XVECEXP (unspec, 0, 1)) != maskval)
8042132718Skan	return 0;
8043132718Skan    }
8044132718Skan  return 1;
8045132718Skan}
8046132718Skan
804790075Sobrien/* Return 1 for an PARALLEL suitable for mtcrf.  */
804890075Sobrien
804990075Sobrienint
8050132718Skanmtcrf_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
805190075Sobrien{
805290075Sobrien  int count = XVECLEN (op, 0);
805390075Sobrien  int i;
805490075Sobrien  rtx src_reg;
805590075Sobrien
805690075Sobrien  /* Perform a quick check so we don't blow up below.  */
805790075Sobrien  if (count < 1
805890075Sobrien      || GET_CODE (XVECEXP (op, 0, 0)) != SET
805990075Sobrien      || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != UNSPEC
806090075Sobrien      || XVECLEN (SET_SRC (XVECEXP (op, 0, 0)), 0) != 2)
806190075Sobrien    return 0;
806290075Sobrien  src_reg = XVECEXP (SET_SRC (XVECEXP (op, 0, 0)), 0, 0);
806390075Sobrien
806490075Sobrien  if (GET_CODE (src_reg) != REG
806590075Sobrien      || GET_MODE (src_reg) != SImode
806690075Sobrien      || ! INT_REGNO_P (REGNO (src_reg)))
806790075Sobrien    return 0;
806890075Sobrien
806990075Sobrien  for (i = 0; i < count; i++)
807090075Sobrien    {
807190075Sobrien      rtx exp = XVECEXP (op, 0, i);
807290075Sobrien      rtx unspec;
807390075Sobrien      int maskval;
807490075Sobrien
807590075Sobrien      if (GET_CODE (exp) != SET
807690075Sobrien	  || GET_CODE (SET_DEST (exp)) != REG
807790075Sobrien	  || GET_MODE (SET_DEST (exp)) != CCmode
807890075Sobrien	  || ! CR_REGNO_P (REGNO (SET_DEST (exp))))
807990075Sobrien	return 0;
808090075Sobrien      unspec = SET_SRC (exp);
808190075Sobrien      maskval = 1 << (MAX_CR_REGNO - REGNO (SET_DEST (exp)));
808290075Sobrien
808390075Sobrien      if (GET_CODE (unspec) != UNSPEC
8084132718Skan	  || XINT (unspec, 1) != UNSPEC_MOVESI_TO_CR
808590075Sobrien	  || XVECLEN (unspec, 0) != 2
808690075Sobrien	  || XVECEXP (unspec, 0, 0) != src_reg
808790075Sobrien	  || GET_CODE (XVECEXP (unspec, 0, 1)) != CONST_INT
808890075Sobrien	  || INTVAL (XVECEXP (unspec, 0, 1)) != maskval)
808990075Sobrien	return 0;
809090075Sobrien    }
809190075Sobrien  return 1;
809290075Sobrien}
809390075Sobrien
809490075Sobrien/* Return 1 for an PARALLEL suitable for lmw.  */
809590075Sobrien
809690075Sobrienint
8097132718Skanlmw_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
809890075Sobrien{
809990075Sobrien  int count = XVECLEN (op, 0);
810090075Sobrien  unsigned int dest_regno;
810190075Sobrien  rtx src_addr;
810290075Sobrien  unsigned int base_regno;
810390075Sobrien  HOST_WIDE_INT offset;
810490075Sobrien  int i;
810590075Sobrien
810690075Sobrien  /* Perform a quick check so we don't blow up below.  */
810790075Sobrien  if (count <= 1
810890075Sobrien      || GET_CODE (XVECEXP (op, 0, 0)) != SET
810990075Sobrien      || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != REG
811090075Sobrien      || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != MEM)
811190075Sobrien    return 0;
811290075Sobrien
811390075Sobrien  dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, 0)));
811490075Sobrien  src_addr = XEXP (SET_SRC (XVECEXP (op, 0, 0)), 0);
811590075Sobrien
811690075Sobrien  if (dest_regno > 31
811790075Sobrien      || count != 32 - (int) dest_regno)
811890075Sobrien    return 0;
811990075Sobrien
8120132718Skan  if (legitimate_indirect_address_p (src_addr, 0))
812190075Sobrien    {
812290075Sobrien      offset = 0;
812390075Sobrien      base_regno = REGNO (src_addr);
812490075Sobrien      if (base_regno == 0)
812590075Sobrien	return 0;
812690075Sobrien    }
8127132718Skan  else if (legitimate_offset_address_p (SImode, src_addr, 0))
812890075Sobrien    {
812990075Sobrien      offset = INTVAL (XEXP (src_addr, 1));
813090075Sobrien      base_regno = REGNO (XEXP (src_addr, 0));
813190075Sobrien    }
813290075Sobrien  else
813390075Sobrien    return 0;
813490075Sobrien
813590075Sobrien  for (i = 0; i < count; i++)
813690075Sobrien    {
813790075Sobrien      rtx elt = XVECEXP (op, 0, i);
813890075Sobrien      rtx newaddr;
813990075Sobrien      rtx addr_reg;
814090075Sobrien      HOST_WIDE_INT newoffset;
814190075Sobrien
814290075Sobrien      if (GET_CODE (elt) != SET
814390075Sobrien	  || GET_CODE (SET_DEST (elt)) != REG
814490075Sobrien	  || GET_MODE (SET_DEST (elt)) != SImode
814590075Sobrien	  || REGNO (SET_DEST (elt)) != dest_regno + i
814690075Sobrien	  || GET_CODE (SET_SRC (elt)) != MEM
814790075Sobrien	  || GET_MODE (SET_SRC (elt)) != SImode)
814890075Sobrien	return 0;
814990075Sobrien      newaddr = XEXP (SET_SRC (elt), 0);
8150132718Skan      if (legitimate_indirect_address_p (newaddr, 0))
815190075Sobrien	{
815290075Sobrien	  newoffset = 0;
815390075Sobrien	  addr_reg = newaddr;
815490075Sobrien	}
8155132718Skan      else if (legitimate_offset_address_p (SImode, newaddr, 0))
815690075Sobrien	{
815790075Sobrien	  addr_reg = XEXP (newaddr, 0);
815890075Sobrien	  newoffset = INTVAL (XEXP (newaddr, 1));
815990075Sobrien	}
816090075Sobrien      else
816190075Sobrien	return 0;
816290075Sobrien      if (REGNO (addr_reg) != base_regno
816390075Sobrien	  || newoffset != offset + 4 * i)
816490075Sobrien	return 0;
816590075Sobrien    }
816690075Sobrien
816790075Sobrien  return 1;
816890075Sobrien}
816990075Sobrien
817090075Sobrien/* Return 1 for an PARALLEL suitable for stmw.  */
817190075Sobrien
817290075Sobrienint
8173132718Skanstmw_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
817490075Sobrien{
817590075Sobrien  int count = XVECLEN (op, 0);
817690075Sobrien  unsigned int src_regno;
817790075Sobrien  rtx dest_addr;
817890075Sobrien  unsigned int base_regno;
817990075Sobrien  HOST_WIDE_INT offset;
818090075Sobrien  int i;
818190075Sobrien
818290075Sobrien  /* Perform a quick check so we don't blow up below.  */
818390075Sobrien  if (count <= 1
818490075Sobrien      || GET_CODE (XVECEXP (op, 0, 0)) != SET
818590075Sobrien      || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != MEM
818690075Sobrien      || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != REG)
818790075Sobrien    return 0;
818890075Sobrien
818990075Sobrien  src_regno = REGNO (SET_SRC (XVECEXP (op, 0, 0)));
819090075Sobrien  dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, 0)), 0);
819190075Sobrien
819290075Sobrien  if (src_regno > 31
819390075Sobrien      || count != 32 - (int) src_regno)
819490075Sobrien    return 0;
819590075Sobrien
8196132718Skan  if (legitimate_indirect_address_p (dest_addr, 0))
819790075Sobrien    {
819890075Sobrien      offset = 0;
819990075Sobrien      base_regno = REGNO (dest_addr);
820090075Sobrien      if (base_regno == 0)
820190075Sobrien	return 0;
820290075Sobrien    }
8203132718Skan  else if (legitimate_offset_address_p (SImode, dest_addr, 0))
820490075Sobrien    {
820590075Sobrien      offset = INTVAL (XEXP (dest_addr, 1));
820690075Sobrien      base_regno = REGNO (XEXP (dest_addr, 0));
820790075Sobrien    }
820890075Sobrien  else
820990075Sobrien    return 0;
821090075Sobrien
821190075Sobrien  for (i = 0; i < count; i++)
821290075Sobrien    {
821390075Sobrien      rtx elt = XVECEXP (op, 0, i);
821490075Sobrien      rtx newaddr;
821590075Sobrien      rtx addr_reg;
821690075Sobrien      HOST_WIDE_INT newoffset;
821790075Sobrien
821890075Sobrien      if (GET_CODE (elt) != SET
821990075Sobrien	  || GET_CODE (SET_SRC (elt)) != REG
822090075Sobrien	  || GET_MODE (SET_SRC (elt)) != SImode
822190075Sobrien	  || REGNO (SET_SRC (elt)) != src_regno + i
822290075Sobrien	  || GET_CODE (SET_DEST (elt)) != MEM
822390075Sobrien	  || GET_MODE (SET_DEST (elt)) != SImode)
822490075Sobrien	return 0;
822590075Sobrien      newaddr = XEXP (SET_DEST (elt), 0);
8226132718Skan      if (legitimate_indirect_address_p (newaddr, 0))
822790075Sobrien	{
822890075Sobrien	  newoffset = 0;
822990075Sobrien	  addr_reg = newaddr;
823090075Sobrien	}
8231132718Skan      else if (legitimate_offset_address_p (SImode, newaddr, 0))
823290075Sobrien	{
823390075Sobrien	  addr_reg = XEXP (newaddr, 0);
823490075Sobrien	  newoffset = INTVAL (XEXP (newaddr, 1));
823590075Sobrien	}
823690075Sobrien      else
823790075Sobrien	return 0;
823890075Sobrien      if (REGNO (addr_reg) != base_regno
823990075Sobrien	  || newoffset != offset + 4 * i)
824090075Sobrien	return 0;
824190075Sobrien    }
824290075Sobrien
824390075Sobrien  return 1;
824490075Sobrien}
824590075Sobrien
824690075Sobrien/* A validation routine: say whether CODE, a condition code, and MODE
824790075Sobrien   match.  The other alternatives either don't make sense or should
824890075Sobrien   never be generated.  */
824990075Sobrien
825090075Sobrienstatic void
8251132718Skanvalidate_condition_mode (enum rtx_code code, enum machine_mode mode)
825290075Sobrien{
825390075Sobrien  if (GET_RTX_CLASS (code) != '<'
825490075Sobrien      || GET_MODE_CLASS (mode) != MODE_CC)
825590075Sobrien    abort ();
825690075Sobrien
825790075Sobrien  /* These don't make sense.  */
825890075Sobrien  if ((code == GT || code == LT || code == GE || code == LE)
825990075Sobrien      && mode == CCUNSmode)
826090075Sobrien    abort ();
826190075Sobrien
826290075Sobrien  if ((code == GTU || code == LTU || code == GEU || code == LEU)
826390075Sobrien      && mode != CCUNSmode)
826490075Sobrien    abort ();
826590075Sobrien
826690075Sobrien  if (mode != CCFPmode
826790075Sobrien      && (code == ORDERED || code == UNORDERED
826890075Sobrien	  || code == UNEQ || code == LTGT
826990075Sobrien	  || code == UNGT || code == UNLT
827090075Sobrien	  || code == UNGE || code == UNLE))
827190075Sobrien    abort ();
827290075Sobrien
827390075Sobrien  /* These should never be generated except for
8274132718Skan     flag_finite_math_only.  */
827590075Sobrien  if (mode == CCFPmode
8276117395Skan      && ! flag_finite_math_only
827790075Sobrien      && (code == LE || code == GE
827890075Sobrien	  || code == UNEQ || code == LTGT
827990075Sobrien	  || code == UNGT || code == UNLT))
828090075Sobrien    abort ();
828190075Sobrien
828290075Sobrien  /* These are invalid; the information is not there.  */
828390075Sobrien  if (mode == CCEQmode
828490075Sobrien      && code != EQ && code != NE)
828590075Sobrien    abort ();
828690075Sobrien}
828790075Sobrien
828890075Sobrien/* Return 1 if OP is a comparison operation that is valid for a branch insn.
828990075Sobrien   We only check the opcode against the mode of the CC value here.  */
829090075Sobrien
829190075Sobrienint
8292132718Skanbranch_comparison_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
829390075Sobrien{
829490075Sobrien  enum rtx_code code = GET_CODE (op);
829590075Sobrien  enum machine_mode cc_mode;
829690075Sobrien
829790075Sobrien  if (GET_RTX_CLASS (code) != '<')
829890075Sobrien    return 0;
829990075Sobrien
830090075Sobrien  cc_mode = GET_MODE (XEXP (op, 0));
830190075Sobrien  if (GET_MODE_CLASS (cc_mode) != MODE_CC)
830290075Sobrien    return 0;
830390075Sobrien
830490075Sobrien  validate_condition_mode (code, cc_mode);
830590075Sobrien
830690075Sobrien  return 1;
830790075Sobrien}
830890075Sobrien
830990075Sobrien/* Return 1 if OP is a comparison operation that is valid for a branch
831090075Sobrien   insn and which is true if the corresponding bit in the CC register
831190075Sobrien   is set.  */
831290075Sobrien
831390075Sobrienint
8314132718Skanbranch_positive_comparison_operator (rtx op, enum machine_mode mode)
831590075Sobrien{
831690075Sobrien  enum rtx_code code;
831790075Sobrien
831890075Sobrien  if (! branch_comparison_operator (op, mode))
831990075Sobrien    return 0;
832090075Sobrien
832190075Sobrien  code = GET_CODE (op);
832290075Sobrien  return (code == EQ || code == LT || code == GT
832390075Sobrien	  || code == LTU || code == GTU
832490075Sobrien	  || code == UNORDERED);
832590075Sobrien}
832690075Sobrien
8327132718Skan/* Return 1 if OP is a comparison operation that is valid for an scc
8328132718Skan   insn: it must be a positive comparison.  */
832990075Sobrien
833090075Sobrienint
8331132718Skanscc_comparison_operator (rtx op, enum machine_mode mode)
833290075Sobrien{
8333132718Skan  return branch_positive_comparison_operator (op, mode);
833490075Sobrien}
833590075Sobrien
833690075Sobrienint
8337132718Skantrap_comparison_operator (rtx op, enum machine_mode mode)
833890075Sobrien{
833990075Sobrien  if (mode != VOIDmode && mode != GET_MODE (op))
834090075Sobrien    return 0;
834190075Sobrien  return GET_RTX_CLASS (GET_CODE (op)) == '<';
834290075Sobrien}
834390075Sobrien
834490075Sobrienint
8345132718Skanboolean_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
834690075Sobrien{
834790075Sobrien  enum rtx_code code = GET_CODE (op);
834890075Sobrien  return (code == AND || code == IOR || code == XOR);
834990075Sobrien}
835090075Sobrien
835190075Sobrienint
8352132718Skanboolean_or_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
835390075Sobrien{
835490075Sobrien  enum rtx_code code = GET_CODE (op);
835590075Sobrien  return (code == IOR || code == XOR);
835690075Sobrien}
835790075Sobrien
835890075Sobrienint
8359132718Skanmin_max_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
836090075Sobrien{
836190075Sobrien  enum rtx_code code = GET_CODE (op);
836290075Sobrien  return (code == SMIN || code == SMAX || code == UMIN || code == UMAX);
836390075Sobrien}
836490075Sobrien
836590075Sobrien/* Return 1 if ANDOP is a mask that has no bits on that are not in the
836690075Sobrien   mask required to convert the result of a rotate insn into a shift
836796263Sobrien   left insn of SHIFTOP bits.  Both are known to be SImode CONST_INT.  */
836890075Sobrien
836990075Sobrienint
8370132718Skanincludes_lshift_p (rtx shiftop, rtx andop)
837190075Sobrien{
837290075Sobrien  unsigned HOST_WIDE_INT shift_mask = ~(unsigned HOST_WIDE_INT) 0;
837390075Sobrien
837490075Sobrien  shift_mask <<= INTVAL (shiftop);
837590075Sobrien
837696263Sobrien  return (INTVAL (andop) & 0xffffffff & ~shift_mask) == 0;
837790075Sobrien}
837890075Sobrien
837990075Sobrien/* Similar, but for right shift.  */
838090075Sobrien
838190075Sobrienint
8382132718Skanincludes_rshift_p (rtx shiftop, rtx andop)
838390075Sobrien{
838490075Sobrien  unsigned HOST_WIDE_INT shift_mask = ~(unsigned HOST_WIDE_INT) 0;
838590075Sobrien
838690075Sobrien  shift_mask >>= INTVAL (shiftop);
838790075Sobrien
838896263Sobrien  return (INTVAL (andop) & 0xffffffff & ~shift_mask) == 0;
838990075Sobrien}
839090075Sobrien
839190075Sobrien/* Return 1 if ANDOP is a mask suitable for use with an rldic insn
839290075Sobrien   to perform a left shift.  It must have exactly SHIFTOP least
8393132718Skan   significant 0's, then one or more 1's, then zero or more 0's.  */
839490075Sobrien
839590075Sobrienint
8396132718Skanincludes_rldic_lshift_p (rtx shiftop, rtx andop)
839790075Sobrien{
839890075Sobrien  if (GET_CODE (andop) == CONST_INT)
839990075Sobrien    {
840090075Sobrien      HOST_WIDE_INT c, lsb, shift_mask;
840190075Sobrien
840290075Sobrien      c = INTVAL (andop);
840390075Sobrien      if (c == 0 || c == ~0)
840490075Sobrien	return 0;
840590075Sobrien
840690075Sobrien      shift_mask = ~0;
840790075Sobrien      shift_mask <<= INTVAL (shiftop);
840890075Sobrien
8409132718Skan      /* Find the least significant one bit.  */
841090075Sobrien      lsb = c & -c;
841190075Sobrien
841290075Sobrien      /* It must coincide with the LSB of the shift mask.  */
841390075Sobrien      if (-lsb != shift_mask)
841490075Sobrien	return 0;
841590075Sobrien
841690075Sobrien      /* Invert to look for the next transition (if any).  */
841790075Sobrien      c = ~c;
841890075Sobrien
841990075Sobrien      /* Remove the low group of ones (originally low group of zeros).  */
842090075Sobrien      c &= -lsb;
842190075Sobrien
842290075Sobrien      /* Again find the lsb, and check we have all 1's above.  */
842390075Sobrien      lsb = c & -c;
842490075Sobrien      return c == -lsb;
842590075Sobrien    }
842690075Sobrien  else if (GET_CODE (andop) == CONST_DOUBLE
842790075Sobrien	   && (GET_MODE (andop) == VOIDmode || GET_MODE (andop) == DImode))
842890075Sobrien    {
842990075Sobrien      HOST_WIDE_INT low, high, lsb;
843090075Sobrien      HOST_WIDE_INT shift_mask_low, shift_mask_high;
843190075Sobrien
843290075Sobrien      low = CONST_DOUBLE_LOW (andop);
843390075Sobrien      if (HOST_BITS_PER_WIDE_INT < 64)
843490075Sobrien	high = CONST_DOUBLE_HIGH (andop);
843590075Sobrien
843690075Sobrien      if ((low == 0 && (HOST_BITS_PER_WIDE_INT >= 64 || high == 0))
843790075Sobrien	  || (low == ~0 && (HOST_BITS_PER_WIDE_INT >= 64 || high == ~0)))
843890075Sobrien	return 0;
843990075Sobrien
844090075Sobrien      if (HOST_BITS_PER_WIDE_INT < 64 && low == 0)
844190075Sobrien	{
844290075Sobrien	  shift_mask_high = ~0;
844390075Sobrien	  if (INTVAL (shiftop) > 32)
844490075Sobrien	    shift_mask_high <<= INTVAL (shiftop) - 32;
844590075Sobrien
844690075Sobrien	  lsb = high & -high;
844790075Sobrien
844890075Sobrien	  if (-lsb != shift_mask_high || INTVAL (shiftop) < 32)
844990075Sobrien	    return 0;
845090075Sobrien
845190075Sobrien	  high = ~high;
845290075Sobrien	  high &= -lsb;
845390075Sobrien
845490075Sobrien	  lsb = high & -high;
845590075Sobrien	  return high == -lsb;
845690075Sobrien	}
845790075Sobrien
845890075Sobrien      shift_mask_low = ~0;
845990075Sobrien      shift_mask_low <<= INTVAL (shiftop);
846090075Sobrien
846190075Sobrien      lsb = low & -low;
846290075Sobrien
846390075Sobrien      if (-lsb != shift_mask_low)
846490075Sobrien	return 0;
846590075Sobrien
846690075Sobrien      if (HOST_BITS_PER_WIDE_INT < 64)
846790075Sobrien	high = ~high;
846890075Sobrien      low = ~low;
846990075Sobrien      low &= -lsb;
847090075Sobrien
847190075Sobrien      if (HOST_BITS_PER_WIDE_INT < 64 && low == 0)
847290075Sobrien	{
847390075Sobrien	  lsb = high & -high;
847490075Sobrien	  return high == -lsb;
847590075Sobrien	}
847690075Sobrien
847790075Sobrien      lsb = low & -low;
847890075Sobrien      return low == -lsb && (HOST_BITS_PER_WIDE_INT >= 64 || high == ~0);
847990075Sobrien    }
848090075Sobrien  else
848190075Sobrien    return 0;
848290075Sobrien}
848390075Sobrien
848490075Sobrien/* Return 1 if ANDOP is a mask suitable for use with an rldicr insn
848590075Sobrien   to perform a left shift.  It must have SHIFTOP or more least
8486132718Skan   significant 0's, with the remainder of the word 1's.  */
848790075Sobrien
848890075Sobrienint
8489132718Skanincludes_rldicr_lshift_p (rtx shiftop, rtx andop)
849090075Sobrien{
849190075Sobrien  if (GET_CODE (andop) == CONST_INT)
849290075Sobrien    {
849390075Sobrien      HOST_WIDE_INT c, lsb, shift_mask;
849490075Sobrien
849590075Sobrien      shift_mask = ~0;
849690075Sobrien      shift_mask <<= INTVAL (shiftop);
849790075Sobrien      c = INTVAL (andop);
849890075Sobrien
8499132718Skan      /* Find the least significant one bit.  */
850090075Sobrien      lsb = c & -c;
850190075Sobrien
850290075Sobrien      /* It must be covered by the shift mask.
850390075Sobrien	 This test also rejects c == 0.  */
850490075Sobrien      if ((lsb & shift_mask) == 0)
850590075Sobrien	return 0;
850690075Sobrien
850790075Sobrien      /* Check we have all 1's above the transition, and reject all 1's.  */
850890075Sobrien      return c == -lsb && lsb != 1;
850990075Sobrien    }
851090075Sobrien  else if (GET_CODE (andop) == CONST_DOUBLE
851190075Sobrien	   && (GET_MODE (andop) == VOIDmode || GET_MODE (andop) == DImode))
851290075Sobrien    {
851390075Sobrien      HOST_WIDE_INT low, lsb, shift_mask_low;
851490075Sobrien
851590075Sobrien      low = CONST_DOUBLE_LOW (andop);
851690075Sobrien
851790075Sobrien      if (HOST_BITS_PER_WIDE_INT < 64)
851890075Sobrien	{
851990075Sobrien	  HOST_WIDE_INT high, shift_mask_high;
852090075Sobrien
852190075Sobrien	  high = CONST_DOUBLE_HIGH (andop);
852290075Sobrien
852390075Sobrien	  if (low == 0)
852490075Sobrien	    {
852590075Sobrien	      shift_mask_high = ~0;
852690075Sobrien	      if (INTVAL (shiftop) > 32)
852790075Sobrien		shift_mask_high <<= INTVAL (shiftop) - 32;
852890075Sobrien
852990075Sobrien	      lsb = high & -high;
853090075Sobrien
853190075Sobrien	      if ((lsb & shift_mask_high) == 0)
853290075Sobrien		return 0;
853390075Sobrien
853490075Sobrien	      return high == -lsb;
853590075Sobrien	    }
853690075Sobrien	  if (high != ~0)
853790075Sobrien	    return 0;
853890075Sobrien	}
853990075Sobrien
854090075Sobrien      shift_mask_low = ~0;
854190075Sobrien      shift_mask_low <<= INTVAL (shiftop);
854290075Sobrien
854390075Sobrien      lsb = low & -low;
854490075Sobrien
854590075Sobrien      if ((lsb & shift_mask_low) == 0)
854690075Sobrien	return 0;
854790075Sobrien
854890075Sobrien      return low == -lsb && lsb != 1;
854990075Sobrien    }
855090075Sobrien  else
855190075Sobrien    return 0;
855290075Sobrien}
855390075Sobrien
855490075Sobrien/* Return 1 if REGNO (reg1) == REGNO (reg2) - 1 making them candidates
855590075Sobrien   for lfq and stfq insns.
855690075Sobrien
855790075Sobrien   Note reg1 and reg2 *must* be hard registers.  To be sure we will
855890075Sobrien   abort if we are passed pseudo registers.  */
855990075Sobrien
856090075Sobrienint
8561132718Skanregisters_ok_for_quad_peep (rtx reg1, rtx reg2)
856290075Sobrien{
856390075Sobrien  /* We might have been passed a SUBREG.  */
856490075Sobrien  if (GET_CODE (reg1) != REG || GET_CODE (reg2) != REG)
856590075Sobrien    return 0;
856690075Sobrien
856790075Sobrien  return (REGNO (reg1) == REGNO (reg2) - 1);
856890075Sobrien}
856990075Sobrien
857090075Sobrien/* Return 1 if addr1 and addr2 are suitable for lfq or stfq insn.
857190075Sobrien   addr1 and addr2 must be in consecutive memory locations
857290075Sobrien   (addr2 == addr1 + 8).  */
857390075Sobrien
857490075Sobrienint
8575132718Skanaddrs_ok_for_quad_peep (rtx addr1, rtx addr2)
857690075Sobrien{
857790075Sobrien  unsigned int reg1;
857890075Sobrien  int offset1;
857990075Sobrien
858090075Sobrien  /* Extract an offset (if used) from the first addr.  */
858190075Sobrien  if (GET_CODE (addr1) == PLUS)
858290075Sobrien    {
858390075Sobrien      /* If not a REG, return zero.  */
858490075Sobrien      if (GET_CODE (XEXP (addr1, 0)) != REG)
858590075Sobrien	return 0;
858690075Sobrien      else
858790075Sobrien	{
858890075Sobrien          reg1 = REGNO (XEXP (addr1, 0));
858990075Sobrien	  /* The offset must be constant!  */
859090075Sobrien	  if (GET_CODE (XEXP (addr1, 1)) != CONST_INT)
859190075Sobrien            return 0;
859290075Sobrien          offset1 = INTVAL (XEXP (addr1, 1));
859390075Sobrien	}
859490075Sobrien    }
859590075Sobrien  else if (GET_CODE (addr1) != REG)
859690075Sobrien    return 0;
859790075Sobrien  else
859890075Sobrien    {
859990075Sobrien      reg1 = REGNO (addr1);
860090075Sobrien      /* This was a simple (mem (reg)) expression.  Offset is 0.  */
860190075Sobrien      offset1 = 0;
860290075Sobrien    }
860390075Sobrien
8604132718Skan  /* Make sure the second address is a (mem (plus (reg) (const_int)))
8605132718Skan      or if it is (mem (reg)) then make sure that offset1 is -8 and the same
8606132718Skan      register as addr1.  */
8607132718Skan  if (offset1 == -8 && GET_CODE (addr2) == REG && reg1 == REGNO (addr2))
8608132718Skan   return 1;
860990075Sobrien  if (GET_CODE (addr2) != PLUS)
861090075Sobrien    return 0;
861190075Sobrien
861290075Sobrien  if (GET_CODE (XEXP (addr2, 0)) != REG
861390075Sobrien      || GET_CODE (XEXP (addr2, 1)) != CONST_INT)
861490075Sobrien    return 0;
861590075Sobrien
861690075Sobrien  if (reg1 != REGNO (XEXP (addr2, 0)))
861790075Sobrien    return 0;
861890075Sobrien
861990075Sobrien  /* The offset for the second addr must be 8 more than the first addr.  */
862090075Sobrien  if (INTVAL (XEXP (addr2, 1)) != offset1 + 8)
862190075Sobrien    return 0;
862290075Sobrien
862390075Sobrien  /* All the tests passed.  addr1 and addr2 are valid for lfq or stfq
862490075Sobrien     instructions.  */
862590075Sobrien  return 1;
862690075Sobrien}
862790075Sobrien
862890075Sobrien/* Return the register class of a scratch register needed to copy IN into
862990075Sobrien   or out of a register in CLASS in MODE.  If it can be done directly,
8630132718Skan   NO_REGS is returned.  INP is nonzero if we are loading the reg, zero
8631132718Skan   for storing.  */
863290075Sobrien
863390075Sobrienenum reg_class
8634132718Skansecondary_reload_class (enum reg_class class,
8635132718Skan			enum machine_mode mode,
8636132718Skan			rtx in,
8637132718Skan			int inp)
863890075Sobrien{
863990075Sobrien  int regno;
864090075Sobrien
8641132718Skan  if (TARGET_ELF || (DEFAULT_ABI == ABI_DARWIN
8642132718Skan#if TARGET_MACHO
8643132718Skan                    && MACHOPIC_INDIRECT
8644132718Skan#endif
8645132718Skan                    ))
864690075Sobrien    {
864790075Sobrien      /* We cannot copy a symbolic operand directly into anything
864890075Sobrien         other than BASE_REGS for TARGET_ELF.  So indicate that a
864990075Sobrien         register from BASE_REGS is needed as an intermediate
865090075Sobrien         register.
865190075Sobrien
865290075Sobrien	 On Darwin, pic addresses require a load from memory, which
865390075Sobrien	 needs a base register.  */
865490075Sobrien      if (class != BASE_REGS
865590075Sobrien          && (GET_CODE (in) == SYMBOL_REF
865690075Sobrien              || GET_CODE (in) == HIGH
865790075Sobrien              || GET_CODE (in) == LABEL_REF
865890075Sobrien              || GET_CODE (in) == CONST))
865990075Sobrien        return BASE_REGS;
866090075Sobrien    }
866190075Sobrien
8662132718Skan  /* A 64-bit gpr load or store using an offset that isn't a multiple of
8663132718Skan     four needs a secondary reload.  */
8664132718Skan  if (TARGET_POWERPC64
8665132718Skan      && GET_MODE_UNIT_SIZE (mode) >= 8
8666132718Skan      && (!inp || class != BASE_REGS)
8667132718Skan      && invalid_gpr_mem (in, mode))
8668132718Skan    return BASE_REGS;
8669132718Skan
867090075Sobrien  if (GET_CODE (in) == REG)
867190075Sobrien    {
867290075Sobrien      regno = REGNO (in);
867390075Sobrien      if (regno >= FIRST_PSEUDO_REGISTER)
867490075Sobrien	{
867590075Sobrien	  regno = true_regnum (in);
867690075Sobrien	  if (regno >= FIRST_PSEUDO_REGISTER)
867790075Sobrien	    regno = -1;
867890075Sobrien	}
867990075Sobrien    }
868090075Sobrien  else if (GET_CODE (in) == SUBREG)
868190075Sobrien    {
868290075Sobrien      regno = true_regnum (in);
868390075Sobrien      if (regno >= FIRST_PSEUDO_REGISTER)
868490075Sobrien	regno = -1;
868590075Sobrien    }
868690075Sobrien  else
868790075Sobrien    regno = -1;
868890075Sobrien
868990075Sobrien  /* We can place anything into GENERAL_REGS and can put GENERAL_REGS
869090075Sobrien     into anything.  */
869190075Sobrien  if (class == GENERAL_REGS || class == BASE_REGS
869290075Sobrien      || (regno >= 0 && INT_REGNO_P (regno)))
869390075Sobrien    return NO_REGS;
869490075Sobrien
869590075Sobrien  /* Constants, memory, and FP registers can go into FP registers.  */
869690075Sobrien  if ((regno == -1 || FP_REGNO_P (regno))
869790075Sobrien      && (class == FLOAT_REGS || class == NON_SPECIAL_REGS))
869890075Sobrien    return NO_REGS;
869990075Sobrien
870090075Sobrien  /* Memory, and AltiVec registers can go into AltiVec registers.  */
870190075Sobrien  if ((regno == -1 || ALTIVEC_REGNO_P (regno))
870290075Sobrien      && class == ALTIVEC_REGS)
870390075Sobrien    return NO_REGS;
870490075Sobrien
870590075Sobrien  /* We can copy among the CR registers.  */
870690075Sobrien  if ((class == CR_REGS || class == CR0_REGS)
870790075Sobrien      && regno >= 0 && CR_REGNO_P (regno))
870890075Sobrien    return NO_REGS;
870990075Sobrien
871090075Sobrien  /* Otherwise, we need GENERAL_REGS.  */
871190075Sobrien  return GENERAL_REGS;
871290075Sobrien}
871390075Sobrien
871490075Sobrien/* Given a comparison operation, return the bit number in CCR to test.  We
871590075Sobrien   know this is a valid comparison.
871690075Sobrien
871790075Sobrien   SCC_P is 1 if this is for an scc.  That means that %D will have been
871890075Sobrien   used instead of %C, so the bits will be in different places.
871990075Sobrien
872090075Sobrien   Return -1 if OP isn't a valid comparison for some reason.  */
872190075Sobrien
872290075Sobrienint
8723132718Skanccr_bit (rtx op, int scc_p)
872490075Sobrien{
872590075Sobrien  enum rtx_code code = GET_CODE (op);
872690075Sobrien  enum machine_mode cc_mode;
872790075Sobrien  int cc_regnum;
872890075Sobrien  int base_bit;
872990075Sobrien  rtx reg;
873090075Sobrien
873190075Sobrien  if (GET_RTX_CLASS (code) != '<')
873290075Sobrien    return -1;
873390075Sobrien
873490075Sobrien  reg = XEXP (op, 0);
873590075Sobrien
873690075Sobrien  if (GET_CODE (reg) != REG
873790075Sobrien      || ! CR_REGNO_P (REGNO (reg)))
873890075Sobrien    abort ();
873990075Sobrien
874090075Sobrien  cc_mode = GET_MODE (reg);
874190075Sobrien  cc_regnum = REGNO (reg);
874290075Sobrien  base_bit = 4 * (cc_regnum - CR0_REGNO);
874390075Sobrien
874490075Sobrien  validate_condition_mode (code, cc_mode);
874590075Sobrien
8746132718Skan  /* When generating a sCOND operation, only positive conditions are
8747132718Skan     allowed.  */
8748132718Skan  if (scc_p && code != EQ && code != GT && code != LT && code != UNORDERED
8749132718Skan      && code != GTU && code != LTU)
8750132718Skan    abort ();
8751132718Skan
875290075Sobrien  switch (code)
875390075Sobrien    {
875490075Sobrien    case NE:
875590075Sobrien      return scc_p ? base_bit + 3 : base_bit + 2;
875690075Sobrien    case EQ:
875790075Sobrien      return base_bit + 2;
875890075Sobrien    case GT:  case GTU:  case UNLE:
875990075Sobrien      return base_bit + 1;
876090075Sobrien    case LT:  case LTU:  case UNGE:
876190075Sobrien      return base_bit;
876290075Sobrien    case ORDERED:  case UNORDERED:
876390075Sobrien      return base_bit + 3;
876490075Sobrien
876590075Sobrien    case GE:  case GEU:
876690075Sobrien      /* If scc, we will have done a cror to put the bit in the
876790075Sobrien	 unordered position.  So test that bit.  For integer, this is ! LT
876890075Sobrien	 unless this is an scc insn.  */
876990075Sobrien      return scc_p ? base_bit + 3 : base_bit;
877090075Sobrien
877190075Sobrien    case LE:  case LEU:
877290075Sobrien      return scc_p ? base_bit + 3 : base_bit + 1;
877390075Sobrien
877490075Sobrien    default:
877590075Sobrien      abort ();
877690075Sobrien    }
877790075Sobrien}
877890075Sobrien
877990075Sobrien/* Return the GOT register.  */
878090075Sobrien
878190075Sobrienstruct rtx_def *
8782132718Skanrs6000_got_register (rtx value ATTRIBUTE_UNUSED)
878390075Sobrien{
878490075Sobrien  /* The second flow pass currently (June 1999) can't update
878590075Sobrien     regs_ever_live without disturbing other parts of the compiler, so
878690075Sobrien     update it here to make the prolog/epilogue code happy.  */
878796263Sobrien  if (no_new_pseudos && ! regs_ever_live[RS6000_PIC_OFFSET_TABLE_REGNUM])
878896263Sobrien    regs_ever_live[RS6000_PIC_OFFSET_TABLE_REGNUM] = 1;
878990075Sobrien
879090075Sobrien  current_function_uses_pic_offset_table = 1;
879190075Sobrien
879290075Sobrien  return pic_offset_table_rtx;
879390075Sobrien}
879490075Sobrien
8795117395Skan/* Function to init struct machine_function.
8796117395Skan   This will be called, via a pointer variable,
8797117395Skan   from push_function_context.  */
879890075Sobrien
8799117395Skanstatic struct machine_function *
8800132718Skanrs6000_init_machine_status (void)
880190075Sobrien{
8802117395Skan  return ggc_alloc_cleared (sizeof (machine_function));
880390075Sobrien}
8804117395Skan
8805117395Skan/* These macros test for integers and extract the low-order bits.  */
8806117395Skan#define INT_P(X)  \
8807117395Skan((GET_CODE (X) == CONST_INT || GET_CODE (X) == CONST_DOUBLE)	\
8808117395Skan && GET_MODE (X) == VOIDmode)
880990075Sobrien
8810117395Skan#define INT_LOWPART(X) \
8811117395Skan  (GET_CODE (X) == CONST_INT ? INTVAL (X) : CONST_DOUBLE_LOW (X))
8812117395Skan
8813117395Skanint
8814132718Skanextract_MB (rtx op)
881590075Sobrien{
8816117395Skan  int i;
8817117395Skan  unsigned long val = INT_LOWPART (op);
881890075Sobrien
8819117395Skan  /* If the high bit is zero, the value is the first 1 bit we find
8820117395Skan     from the left.  */
8821117395Skan  if ((val & 0x80000000) == 0)
8822117395Skan    {
8823117395Skan      if ((val & 0xffffffff) == 0)
8824117395Skan	abort ();
8825117395Skan
8826117395Skan      i = 1;
8827117395Skan      while (((val <<= 1) & 0x80000000) == 0)
8828117395Skan	++i;
8829117395Skan      return i;
8830117395Skan    }
8831117395Skan
8832117395Skan  /* If the high bit is set and the low bit is not, or the mask is all
8833117395Skan     1's, the value is zero.  */
8834117395Skan  if ((val & 1) == 0 || (val & 0xffffffff) == 0xffffffff)
8835117395Skan    return 0;
8836117395Skan
8837117395Skan  /* Otherwise we have a wrap-around mask.  Look for the first 0 bit
8838117395Skan     from the right.  */
8839117395Skan  i = 31;
8840117395Skan  while (((val >>= 1) & 1) != 0)
8841117395Skan    --i;
8842117395Skan
8843117395Skan  return i;
884490075Sobrien}
884590075Sobrien
8846117395Skanint
8847132718Skanextract_ME (rtx op)
8848117395Skan{
8849117395Skan  int i;
8850117395Skan  unsigned long val = INT_LOWPART (op);
8851117395Skan
8852117395Skan  /* If the low bit is zero, the value is the first 1 bit we find from
8853117395Skan     the right.  */
8854117395Skan  if ((val & 1) == 0)
8855117395Skan    {
8856117395Skan      if ((val & 0xffffffff) == 0)
8857117395Skan	abort ();
8858117395Skan
8859117395Skan      i = 30;
8860117395Skan      while (((val >>= 1) & 1) == 0)
8861117395Skan	--i;
8862117395Skan
8863117395Skan      return i;
8864117395Skan    }
8865117395Skan
8866117395Skan  /* If the low bit is set and the high bit is not, or the mask is all
8867117395Skan     1's, the value is 31.  */
8868117395Skan  if ((val & 0x80000000) == 0 || (val & 0xffffffff) == 0xffffffff)
8869117395Skan    return 31;
8870117395Skan
8871117395Skan  /* Otherwise we have a wrap-around mask.  Look for the first 0 bit
8872117395Skan     from the left.  */
8873117395Skan  i = 0;
8874117395Skan  while (((val <<= 1) & 0x80000000) != 0)
8875117395Skan    ++i;
8876117395Skan
8877117395Skan  return i;
8878117395Skan}
8879117395Skan
8880132718Skan/* Locate some local-dynamic symbol still in use by this function
8881132718Skan   so that we can print its name in some tls_ld pattern.  */
8882132718Skan
8883132718Skanstatic const char *
8884132718Skanrs6000_get_some_local_dynamic_name (void)
8885132718Skan{
8886132718Skan  rtx insn;
8887132718Skan
8888132718Skan  if (cfun->machine->some_ld_name)
8889132718Skan    return cfun->machine->some_ld_name;
8890132718Skan
8891132718Skan  for (insn = get_insns (); insn ; insn = NEXT_INSN (insn))
8892132718Skan    if (INSN_P (insn)
8893132718Skan	&& for_each_rtx (&PATTERN (insn),
8894132718Skan			 rs6000_get_some_local_dynamic_name_1, 0))
8895132718Skan      return cfun->machine->some_ld_name;
8896132718Skan
8897132718Skan  abort ();
8898132718Skan}
8899132718Skan
8900132718Skan/* Helper function for rs6000_get_some_local_dynamic_name.  */
8901132718Skan
8902132718Skanstatic int
8903132718Skanrs6000_get_some_local_dynamic_name_1 (rtx *px, void *data ATTRIBUTE_UNUSED)
8904132718Skan{
8905132718Skan  rtx x = *px;
8906132718Skan
8907132718Skan  if (GET_CODE (x) == SYMBOL_REF)
8908132718Skan    {
8909132718Skan      const char *str = XSTR (x, 0);
8910132718Skan      if (SYMBOL_REF_TLS_MODEL (x) == TLS_MODEL_LOCAL_DYNAMIC)
8911132718Skan	{
8912132718Skan	  cfun->machine->some_ld_name = str;
8913132718Skan	  return 1;
8914132718Skan	}
8915132718Skan    }
8916132718Skan
8917132718Skan  return 0;
8918132718Skan}
8919132718Skan
892090075Sobrien/* Print an operand.  Recognize special options, documented below.  */
892190075Sobrien
892290075Sobrien#if TARGET_ELF
892390075Sobrien#define SMALL_DATA_RELOC ((rs6000_sdata == SDATA_EABI) ? "sda21" : "sdarel")
892490075Sobrien#define SMALL_DATA_REG ((rs6000_sdata == SDATA_EABI) ? 0 : 13)
892590075Sobrien#else
892690075Sobrien#define SMALL_DATA_RELOC "sda21"
892790075Sobrien#define SMALL_DATA_REG 0
892890075Sobrien#endif
892990075Sobrien
893090075Sobrienvoid
8931132718Skanprint_operand (FILE *file, rtx x, int code)
893290075Sobrien{
893390075Sobrien  int i;
893490075Sobrien  HOST_WIDE_INT val;
8935117395Skan  unsigned HOST_WIDE_INT uval;
893690075Sobrien
893790075Sobrien  switch (code)
893890075Sobrien    {
893990075Sobrien    case '.':
894090075Sobrien      /* Write out an instruction after the call which may be replaced
894190075Sobrien	 with glue code by the loader.  This depends on the AIX version.  */
894290075Sobrien      asm_fprintf (file, RS6000_CALL_GLUE);
894390075Sobrien      return;
894490075Sobrien
894590075Sobrien      /* %a is output_address.  */
894690075Sobrien
894790075Sobrien    case 'A':
894890075Sobrien      /* If X is a constant integer whose low-order 5 bits are zero,
894990075Sobrien	 write 'l'.  Otherwise, write 'r'.  This is a kludge to fix a bug
895090075Sobrien	 in the AIX assembler where "sri" with a zero shift count
895190075Sobrien	 writes a trash instruction.  */
895290075Sobrien      if (GET_CODE (x) == CONST_INT && (INTVAL (x) & 31) == 0)
895390075Sobrien	putc ('l', file);
895490075Sobrien      else
895590075Sobrien	putc ('r', file);
895690075Sobrien      return;
895790075Sobrien
895890075Sobrien    case 'b':
895990075Sobrien      /* If constant, low-order 16 bits of constant, unsigned.
896090075Sobrien	 Otherwise, write normally.  */
896190075Sobrien      if (INT_P (x))
896290075Sobrien	fprintf (file, HOST_WIDE_INT_PRINT_DEC, INT_LOWPART (x) & 0xffff);
896390075Sobrien      else
896490075Sobrien	print_operand (file, x, 0);
896590075Sobrien      return;
896690075Sobrien
896790075Sobrien    case 'B':
896890075Sobrien      /* If the low-order bit is zero, write 'r'; otherwise, write 'l'
896990075Sobrien	 for 64-bit mask direction.  */
897090075Sobrien      putc (((INT_LOWPART(x) & 1) == 0 ? 'r' : 'l'), file);
897190075Sobrien      return;
897290075Sobrien
897390075Sobrien      /* %c is output_addr_const if a CONSTANT_ADDRESS_P, otherwise
897490075Sobrien	 output_operand.  */
897590075Sobrien
8976132718Skan    case 'c':
8977132718Skan      /* X is a CR register.  Print the number of the GT bit of the CR.  */
8978132718Skan      if (GET_CODE (x) != REG || ! CR_REGNO_P (REGNO (x)))
8979132718Skan       output_operand_lossage ("invalid %%E value");
8980132718Skan      else
8981132718Skan       fprintf (file, "%d", 4 * (REGNO (x) - CR0_REGNO) + 1);
8982132718Skan      return;
8983132718Skan
898490075Sobrien    case 'D':
8985132718Skan      /* Like 'J' but get to the GT bit.  */
8986132718Skan      if (GET_CODE (x) != REG)
8987132718Skan       abort ();
898890075Sobrien
8989132718Skan      /* Bit 1 is GT bit.  */
8990132718Skan      i = 4 * (REGNO (x) - CR0_REGNO) + 1;
899190075Sobrien
8992132718Skan      /* If we want bit 31, write a shift count of zero, not 32.  */
8993132718Skan      fprintf (file, "%d", i == 31 ? 0 : i + 1);
899490075Sobrien      return;
899590075Sobrien
899690075Sobrien    case 'E':
899790075Sobrien      /* X is a CR register.  Print the number of the EQ bit of the CR */
899890075Sobrien      if (GET_CODE (x) != REG || ! CR_REGNO_P (REGNO (x)))
899990075Sobrien	output_operand_lossage ("invalid %%E value");
900090075Sobrien      else
900190075Sobrien	fprintf (file, "%d", 4 * (REGNO (x) - CR0_REGNO) + 2);
900290075Sobrien      return;
900390075Sobrien
900490075Sobrien    case 'f':
900590075Sobrien      /* X is a CR register.  Print the shift count needed to move it
900690075Sobrien	 to the high-order four bits.  */
900790075Sobrien      if (GET_CODE (x) != REG || ! CR_REGNO_P (REGNO (x)))
900890075Sobrien	output_operand_lossage ("invalid %%f value");
900990075Sobrien      else
901090075Sobrien	fprintf (file, "%d", 4 * (REGNO (x) - CR0_REGNO));
901190075Sobrien      return;
901290075Sobrien
901390075Sobrien    case 'F':
901490075Sobrien      /* Similar, but print the count for the rotate in the opposite
901590075Sobrien	 direction.  */
901690075Sobrien      if (GET_CODE (x) != REG || ! CR_REGNO_P (REGNO (x)))
901790075Sobrien	output_operand_lossage ("invalid %%F value");
901890075Sobrien      else
901990075Sobrien	fprintf (file, "%d", 32 - 4 * (REGNO (x) - CR0_REGNO));
902090075Sobrien      return;
902190075Sobrien
902290075Sobrien    case 'G':
902390075Sobrien      /* X is a constant integer.  If it is negative, print "m",
9024117395Skan	 otherwise print "z".  This is to make an aze or ame insn.  */
902590075Sobrien      if (GET_CODE (x) != CONST_INT)
902690075Sobrien	output_operand_lossage ("invalid %%G value");
902790075Sobrien      else if (INTVAL (x) >= 0)
902890075Sobrien	putc ('z', file);
902990075Sobrien      else
903090075Sobrien	putc ('m', file);
903190075Sobrien      return;
903290075Sobrien
903390075Sobrien    case 'h':
903490075Sobrien      /* If constant, output low-order five bits.  Otherwise, write
903590075Sobrien	 normally.  */
903690075Sobrien      if (INT_P (x))
903790075Sobrien	fprintf (file, HOST_WIDE_INT_PRINT_DEC, INT_LOWPART (x) & 31);
903890075Sobrien      else
903990075Sobrien	print_operand (file, x, 0);
904090075Sobrien      return;
904190075Sobrien
904290075Sobrien    case 'H':
904390075Sobrien      /* If constant, output low-order six bits.  Otherwise, write
904490075Sobrien	 normally.  */
904590075Sobrien      if (INT_P (x))
904690075Sobrien	fprintf (file, HOST_WIDE_INT_PRINT_DEC, INT_LOWPART (x) & 63);
904790075Sobrien      else
904890075Sobrien	print_operand (file, x, 0);
904990075Sobrien      return;
905090075Sobrien
905190075Sobrien    case 'I':
905290075Sobrien      /* Print `i' if this is a constant, else nothing.  */
905390075Sobrien      if (INT_P (x))
905490075Sobrien	putc ('i', file);
905590075Sobrien      return;
905690075Sobrien
905790075Sobrien    case 'j':
905890075Sobrien      /* Write the bit number in CCR for jump.  */
905990075Sobrien      i = ccr_bit (x, 0);
906090075Sobrien      if (i == -1)
906190075Sobrien	output_operand_lossage ("invalid %%j code");
906290075Sobrien      else
906390075Sobrien	fprintf (file, "%d", i);
906490075Sobrien      return;
906590075Sobrien
906690075Sobrien    case 'J':
906790075Sobrien      /* Similar, but add one for shift count in rlinm for scc and pass
906890075Sobrien	 scc flag to `ccr_bit'.  */
906990075Sobrien      i = ccr_bit (x, 1);
907090075Sobrien      if (i == -1)
907190075Sobrien	output_operand_lossage ("invalid %%J code");
907290075Sobrien      else
907390075Sobrien	/* If we want bit 31, write a shift count of zero, not 32.  */
907490075Sobrien	fprintf (file, "%d", i == 31 ? 0 : i + 1);
907590075Sobrien      return;
907690075Sobrien
907790075Sobrien    case 'k':
907890075Sobrien      /* X must be a constant.  Write the 1's complement of the
907990075Sobrien	 constant.  */
908090075Sobrien      if (! INT_P (x))
908190075Sobrien	output_operand_lossage ("invalid %%k value");
908290075Sobrien      else
908390075Sobrien	fprintf (file, HOST_WIDE_INT_PRINT_DEC, ~ INT_LOWPART (x));
908490075Sobrien      return;
908590075Sobrien
908690075Sobrien    case 'K':
908790075Sobrien      /* X must be a symbolic constant on ELF.  Write an
908890075Sobrien	 expression suitable for an 'addi' that adds in the low 16
908990075Sobrien	 bits of the MEM.  */
909090075Sobrien      if (GET_CODE (x) != CONST)
909190075Sobrien	{
909290075Sobrien	  print_operand_address (file, x);
909390075Sobrien	  fputs ("@l", file);
909490075Sobrien	}
909590075Sobrien      else
909690075Sobrien	{
909790075Sobrien	  if (GET_CODE (XEXP (x, 0)) != PLUS
909890075Sobrien	      || (GET_CODE (XEXP (XEXP (x, 0), 0)) != SYMBOL_REF
909990075Sobrien		  && GET_CODE (XEXP (XEXP (x, 0), 0)) != LABEL_REF)
910090075Sobrien	      || GET_CODE (XEXP (XEXP (x, 0), 1)) != CONST_INT)
910190075Sobrien	    output_operand_lossage ("invalid %%K value");
910290075Sobrien	  print_operand_address (file, XEXP (XEXP (x, 0), 0));
910390075Sobrien	  fputs ("@l", file);
9104117395Skan	  /* For GNU as, there must be a non-alphanumeric character
9105117395Skan	     between 'l' and the number.  The '-' is added by
9106117395Skan	     print_operand() already.  */
9107117395Skan	  if (INTVAL (XEXP (XEXP (x, 0), 1)) >= 0)
9108117395Skan	    fputs ("+", file);
910990075Sobrien	  print_operand (file, XEXP (XEXP (x, 0), 1), 0);
911090075Sobrien	}
911190075Sobrien      return;
911290075Sobrien
911390075Sobrien      /* %l is output_asm_label.  */
911490075Sobrien
911590075Sobrien    case 'L':
911690075Sobrien      /* Write second word of DImode or DFmode reference.  Works on register
911790075Sobrien	 or non-indexed memory only.  */
911890075Sobrien      if (GET_CODE (x) == REG)
911990075Sobrien	fprintf (file, "%s", reg_names[REGNO (x) + 1]);
912090075Sobrien      else if (GET_CODE (x) == MEM)
912190075Sobrien	{
912290075Sobrien	  /* Handle possible auto-increment.  Since it is pre-increment and
912390075Sobrien	     we have already done it, we can just use an offset of word.  */
912490075Sobrien	  if (GET_CODE (XEXP (x, 0)) == PRE_INC
912590075Sobrien	      || GET_CODE (XEXP (x, 0)) == PRE_DEC)
912690075Sobrien	    output_address (plus_constant (XEXP (XEXP (x, 0), 0),
912790075Sobrien					   UNITS_PER_WORD));
912890075Sobrien	  else
912990075Sobrien	    output_address (XEXP (adjust_address_nv (x, SImode,
913090075Sobrien						     UNITS_PER_WORD),
913190075Sobrien				  0));
913290075Sobrien
913390075Sobrien	  if (small_data_operand (x, GET_MODE (x)))
913490075Sobrien	    fprintf (file, "@%s(%s)", SMALL_DATA_RELOC,
913590075Sobrien		     reg_names[SMALL_DATA_REG]);
913690075Sobrien	}
913790075Sobrien      return;
913890075Sobrien
913990075Sobrien    case 'm':
914090075Sobrien      /* MB value for a mask operand.  */
914196263Sobrien      if (! mask_operand (x, SImode))
914290075Sobrien	output_operand_lossage ("invalid %%m value");
914390075Sobrien
9144117395Skan      fprintf (file, "%d", extract_MB (x));
914590075Sobrien      return;
914690075Sobrien
914790075Sobrien    case 'M':
914890075Sobrien      /* ME value for a mask operand.  */
914996263Sobrien      if (! mask_operand (x, SImode))
915090075Sobrien	output_operand_lossage ("invalid %%M value");
915190075Sobrien
9152117395Skan      fprintf (file, "%d", extract_ME (x));
915390075Sobrien      return;
915490075Sobrien
915590075Sobrien      /* %n outputs the negative of its operand.  */
915690075Sobrien
915790075Sobrien    case 'N':
915890075Sobrien      /* Write the number of elements in the vector times 4.  */
915990075Sobrien      if (GET_CODE (x) != PARALLEL)
916090075Sobrien	output_operand_lossage ("invalid %%N value");
916190075Sobrien      else
916290075Sobrien	fprintf (file, "%d", XVECLEN (x, 0) * 4);
916390075Sobrien      return;
916490075Sobrien
916590075Sobrien    case 'O':
916690075Sobrien      /* Similar, but subtract 1 first.  */
916790075Sobrien      if (GET_CODE (x) != PARALLEL)
916890075Sobrien	output_operand_lossage ("invalid %%O value");
916990075Sobrien      else
917090075Sobrien	fprintf (file, "%d", (XVECLEN (x, 0) - 1) * 4);
917190075Sobrien      return;
917290075Sobrien
917390075Sobrien    case 'p':
917490075Sobrien      /* X is a CONST_INT that is a power of two.  Output the logarithm.  */
917590075Sobrien      if (! INT_P (x)
917690075Sobrien	  || INT_LOWPART (x) < 0
917790075Sobrien	  || (i = exact_log2 (INT_LOWPART (x))) < 0)
917890075Sobrien	output_operand_lossage ("invalid %%p value");
917990075Sobrien      else
918090075Sobrien	fprintf (file, "%d", i);
918190075Sobrien      return;
918290075Sobrien
918390075Sobrien    case 'P':
918490075Sobrien      /* The operand must be an indirect memory reference.  The result
918590075Sobrien	 is the register number.  */
918690075Sobrien      if (GET_CODE (x) != MEM || GET_CODE (XEXP (x, 0)) != REG
918790075Sobrien	  || REGNO (XEXP (x, 0)) >= 32)
918890075Sobrien	output_operand_lossage ("invalid %%P value");
918990075Sobrien      else
919090075Sobrien	fprintf (file, "%d", REGNO (XEXP (x, 0)));
919190075Sobrien      return;
919290075Sobrien
919390075Sobrien    case 'q':
919490075Sobrien      /* This outputs the logical code corresponding to a boolean
919590075Sobrien	 expression.  The expression may have one or both operands
919690075Sobrien	 negated (if one, only the first one).  For condition register
919790075Sobrien         logical operations, it will also treat the negated
919890075Sobrien         CR codes as NOTs, but not handle NOTs of them.  */
919990075Sobrien      {
920090075Sobrien	const char *const *t = 0;
920190075Sobrien	const char *s;
920290075Sobrien	enum rtx_code code = GET_CODE (x);
920390075Sobrien	static const char * const tbl[3][3] = {
920490075Sobrien	  { "and", "andc", "nor" },
920590075Sobrien	  { "or", "orc", "nand" },
920690075Sobrien	  { "xor", "eqv", "xor" } };
920790075Sobrien
920890075Sobrien	if (code == AND)
920990075Sobrien	  t = tbl[0];
921090075Sobrien	else if (code == IOR)
921190075Sobrien	  t = tbl[1];
921290075Sobrien	else if (code == XOR)
921390075Sobrien	  t = tbl[2];
921490075Sobrien	else
921590075Sobrien	  output_operand_lossage ("invalid %%q value");
921690075Sobrien
921790075Sobrien	if (GET_CODE (XEXP (x, 0)) != NOT)
921890075Sobrien	  s = t[0];
921990075Sobrien	else
922090075Sobrien	  {
922190075Sobrien	    if (GET_CODE (XEXP (x, 1)) == NOT)
922290075Sobrien	      s = t[2];
922390075Sobrien	    else
922490075Sobrien	      s = t[1];
922590075Sobrien	  }
922690075Sobrien
922790075Sobrien	fputs (s, file);
922890075Sobrien      }
922990075Sobrien      return;
923090075Sobrien
9231132718Skan    case 'Q':
9232132718Skan      if (TARGET_MFCRF)
9233132718Skan	fputc (',',file);
9234132718Skan        /* FALLTHRU */
9235132718Skan      else
9236132718Skan	return;
9237132718Skan
923890075Sobrien    case 'R':
923990075Sobrien      /* X is a CR register.  Print the mask for `mtcrf'.  */
924090075Sobrien      if (GET_CODE (x) != REG || ! CR_REGNO_P (REGNO (x)))
924190075Sobrien	output_operand_lossage ("invalid %%R value");
924290075Sobrien      else
924390075Sobrien	fprintf (file, "%d", 128 >> (REGNO (x) - CR0_REGNO));
924490075Sobrien      return;
924590075Sobrien
924690075Sobrien    case 's':
924790075Sobrien      /* Low 5 bits of 32 - value */
924890075Sobrien      if (! INT_P (x))
924990075Sobrien	output_operand_lossage ("invalid %%s value");
925090075Sobrien      else
925190075Sobrien	fprintf (file, HOST_WIDE_INT_PRINT_DEC, (32 - INT_LOWPART (x)) & 31);
925290075Sobrien      return;
925390075Sobrien
925490075Sobrien    case 'S':
9255117395Skan      /* PowerPC64 mask position.  All 0's is excluded.
925690075Sobrien	 CONST_INT 32-bit mask is considered sign-extended so any
925790075Sobrien	 transition must occur within the CONST_INT, not on the boundary.  */
925896263Sobrien      if (! mask64_operand (x, DImode))
925990075Sobrien	output_operand_lossage ("invalid %%S value");
926090075Sobrien
9261117395Skan      uval = INT_LOWPART (x);
926290075Sobrien
9263117395Skan      if (uval & 1)	/* Clear Left */
926490075Sobrien	{
9265132718Skan#if HOST_BITS_PER_WIDE_INT > 64
9266132718Skan	  uval &= ((unsigned HOST_WIDE_INT) 1 << 64) - 1;
9267132718Skan#endif
9268117395Skan	  i = 64;
926990075Sobrien	}
9270117395Skan      else		/* Clear Right */
927190075Sobrien	{
9272117395Skan	  uval = ~uval;
9273132718Skan#if HOST_BITS_PER_WIDE_INT > 64
9274132718Skan	  uval &= ((unsigned HOST_WIDE_INT) 1 << 64) - 1;
9275132718Skan#endif
9276117395Skan	  i = 63;
9277117395Skan	}
9278117395Skan      while (uval != 0)
9279117395Skan	--i, uval >>= 1;
9280117395Skan      if (i < 0)
9281117395Skan	abort ();
9282117395Skan      fprintf (file, "%d", i);
9283117395Skan      return;
928490075Sobrien
9285117395Skan    case 't':
9286117395Skan      /* Like 'J' but get to the OVERFLOW/UNORDERED bit.  */
9287117395Skan      if (GET_CODE (x) != REG || GET_MODE (x) != CCmode)
9288117395Skan	abort ();
928990075Sobrien
9290117395Skan      /* Bit 3 is OV bit.  */
9291117395Skan      i = 4 * (REGNO (x) - CR0_REGNO) + 3;
929290075Sobrien
9293117395Skan      /* If we want bit 31, write a shift count of zero, not 32.  */
9294117395Skan      fprintf (file, "%d", i == 31 ? 0 : i + 1);
9295117395Skan      return;
929690075Sobrien
929790075Sobrien    case 'T':
929890075Sobrien      /* Print the symbolic name of a branch target register.  */
929990075Sobrien      if (GET_CODE (x) != REG || (REGNO (x) != LINK_REGISTER_REGNUM
930090075Sobrien				  && REGNO (x) != COUNT_REGISTER_REGNUM))
930190075Sobrien	output_operand_lossage ("invalid %%T value");
930290075Sobrien      else if (REGNO (x) == LINK_REGISTER_REGNUM)
930390075Sobrien	fputs (TARGET_NEW_MNEMONICS ? "lr" : "r", file);
930490075Sobrien      else
930590075Sobrien	fputs ("ctr", file);
930690075Sobrien      return;
930790075Sobrien
930890075Sobrien    case 'u':
930990075Sobrien      /* High-order 16 bits of constant for use in unsigned operand.  */
931090075Sobrien      if (! INT_P (x))
931190075Sobrien	output_operand_lossage ("invalid %%u value");
931290075Sobrien      else
931390075Sobrien	fprintf (file, HOST_WIDE_INT_PRINT_HEX,
931490075Sobrien		 (INT_LOWPART (x) >> 16) & 0xffff);
931590075Sobrien      return;
931690075Sobrien
931790075Sobrien    case 'v':
931890075Sobrien      /* High-order 16 bits of constant for use in signed operand.  */
931990075Sobrien      if (! INT_P (x))
932090075Sobrien	output_operand_lossage ("invalid %%v value");
932190075Sobrien      else
932290075Sobrien	fprintf (file, HOST_WIDE_INT_PRINT_HEX,
932390075Sobrien		 (INT_LOWPART (x) >> 16) & 0xffff);
932490075Sobrien      return;
932590075Sobrien
932690075Sobrien    case 'U':
932790075Sobrien      /* Print `u' if this has an auto-increment or auto-decrement.  */
932890075Sobrien      if (GET_CODE (x) == MEM
932990075Sobrien	  && (GET_CODE (XEXP (x, 0)) == PRE_INC
933090075Sobrien	      || GET_CODE (XEXP (x, 0)) == PRE_DEC))
933190075Sobrien	putc ('u', file);
933290075Sobrien      return;
933390075Sobrien
933490075Sobrien    case 'V':
933590075Sobrien      /* Print the trap code for this operand.  */
933690075Sobrien      switch (GET_CODE (x))
933790075Sobrien	{
933890075Sobrien	case EQ:
933990075Sobrien	  fputs ("eq", file);   /* 4 */
934090075Sobrien	  break;
934190075Sobrien	case NE:
934290075Sobrien	  fputs ("ne", file);   /* 24 */
934390075Sobrien	  break;
934490075Sobrien	case LT:
934590075Sobrien	  fputs ("lt", file);   /* 16 */
934690075Sobrien	  break;
934790075Sobrien	case LE:
934890075Sobrien	  fputs ("le", file);   /* 20 */
934990075Sobrien	  break;
935090075Sobrien	case GT:
935190075Sobrien	  fputs ("gt", file);   /* 8 */
935290075Sobrien	  break;
935390075Sobrien	case GE:
935490075Sobrien	  fputs ("ge", file);   /* 12 */
935590075Sobrien	  break;
935690075Sobrien	case LTU:
935790075Sobrien	  fputs ("llt", file);  /* 2 */
935890075Sobrien	  break;
935990075Sobrien	case LEU:
936090075Sobrien	  fputs ("lle", file);  /* 6 */
936190075Sobrien	  break;
936290075Sobrien	case GTU:
936390075Sobrien	  fputs ("lgt", file);  /* 1 */
936490075Sobrien	  break;
936590075Sobrien	case GEU:
936690075Sobrien	  fputs ("lge", file);  /* 5 */
936790075Sobrien	  break;
936890075Sobrien	default:
936990075Sobrien	  abort ();
937090075Sobrien	}
937190075Sobrien      break;
937290075Sobrien
937390075Sobrien    case 'w':
937490075Sobrien      /* If constant, low-order 16 bits of constant, signed.  Otherwise, write
937590075Sobrien	 normally.  */
937690075Sobrien      if (INT_P (x))
937790075Sobrien	fprintf (file, HOST_WIDE_INT_PRINT_DEC,
937890075Sobrien		 ((INT_LOWPART (x) & 0xffff) ^ 0x8000) - 0x8000);
937990075Sobrien      else
938090075Sobrien	print_operand (file, x, 0);
938190075Sobrien      return;
938290075Sobrien
938390075Sobrien    case 'W':
938490075Sobrien      /* MB value for a PowerPC64 rldic operand.  */
938590075Sobrien      val = (GET_CODE (x) == CONST_INT
938690075Sobrien	     ? INTVAL (x) : CONST_DOUBLE_HIGH (x));
938790075Sobrien
938890075Sobrien      if (val < 0)
938990075Sobrien	i = -1;
939090075Sobrien      else
939190075Sobrien	for (i = 0; i < HOST_BITS_PER_WIDE_INT; i++)
939290075Sobrien	  if ((val <<= 1) < 0)
939390075Sobrien	    break;
939490075Sobrien
939590075Sobrien#if HOST_BITS_PER_WIDE_INT == 32
939690075Sobrien      if (GET_CODE (x) == CONST_INT && i >= 0)
939790075Sobrien	i += 32;  /* zero-extend high-part was all 0's */
939890075Sobrien      else if (GET_CODE (x) == CONST_DOUBLE && i == 32)
939990075Sobrien	{
940090075Sobrien	  val = CONST_DOUBLE_LOW (x);
940190075Sobrien
940290075Sobrien	  if (val == 0)
940390075Sobrien	    abort ();
940490075Sobrien	  else if (val < 0)
940590075Sobrien	    --i;
940690075Sobrien	  else
940790075Sobrien	    for ( ; i < 64; i++)
940890075Sobrien	      if ((val <<= 1) < 0)
940990075Sobrien		break;
941090075Sobrien	}
941190075Sobrien#endif
941290075Sobrien
941390075Sobrien      fprintf (file, "%d", i + 1);
941490075Sobrien      return;
941590075Sobrien
941690075Sobrien    case 'X':
941790075Sobrien      if (GET_CODE (x) == MEM
9418132718Skan	  && legitimate_indexed_address_p (XEXP (x, 0), 0))
941990075Sobrien	putc ('x', file);
942090075Sobrien      return;
942190075Sobrien
942290075Sobrien    case 'Y':
942390075Sobrien      /* Like 'L', for third word of TImode  */
942490075Sobrien      if (GET_CODE (x) == REG)
942590075Sobrien	fprintf (file, "%s", reg_names[REGNO (x) + 2]);
942690075Sobrien      else if (GET_CODE (x) == MEM)
942790075Sobrien	{
942890075Sobrien	  if (GET_CODE (XEXP (x, 0)) == PRE_INC
942990075Sobrien	      || GET_CODE (XEXP (x, 0)) == PRE_DEC)
943090075Sobrien	    output_address (plus_constant (XEXP (XEXP (x, 0), 0), 8));
943190075Sobrien	  else
943290075Sobrien	    output_address (XEXP (adjust_address_nv (x, SImode, 8), 0));
943390075Sobrien	  if (small_data_operand (x, GET_MODE (x)))
943490075Sobrien	    fprintf (file, "@%s(%s)", SMALL_DATA_RELOC,
943590075Sobrien		     reg_names[SMALL_DATA_REG]);
943690075Sobrien	}
943790075Sobrien      return;
943890075Sobrien
943990075Sobrien    case 'z':
944090075Sobrien      /* X is a SYMBOL_REF.  Write out the name preceded by a
944190075Sobrien	 period and without any trailing data in brackets.  Used for function
944290075Sobrien	 names.  If we are configured for System V (or the embedded ABI) on
944390075Sobrien	 the PowerPC, do not emit the period, since those systems do not use
944490075Sobrien	 TOCs and the like.  */
944590075Sobrien      if (GET_CODE (x) != SYMBOL_REF)
944690075Sobrien	abort ();
944790075Sobrien
944890075Sobrien      if (XSTR (x, 0)[0] != '.')
944990075Sobrien	{
945090075Sobrien	  switch (DEFAULT_ABI)
945190075Sobrien	    {
945290075Sobrien	    default:
945390075Sobrien	      abort ();
945490075Sobrien
945590075Sobrien	    case ABI_AIX:
945690075Sobrien	      putc ('.', file);
945790075Sobrien	      break;
945890075Sobrien
945990075Sobrien	    case ABI_V4:
946090075Sobrien	    case ABI_DARWIN:
946190075Sobrien	      break;
946290075Sobrien	    }
946390075Sobrien	}
9464132718Skan      if (TARGET_AIX)
9465132718Skan	RS6000_OUTPUT_BASENAME (file, XSTR (x, 0));
9466132718Skan      else
9467132718Skan	assemble_name (file, XSTR (x, 0));
946890075Sobrien      return;
946990075Sobrien
947090075Sobrien    case 'Z':
947190075Sobrien      /* Like 'L', for last word of TImode.  */
947290075Sobrien      if (GET_CODE (x) == REG)
947390075Sobrien	fprintf (file, "%s", reg_names[REGNO (x) + 3]);
947490075Sobrien      else if (GET_CODE (x) == MEM)
947590075Sobrien	{
947690075Sobrien	  if (GET_CODE (XEXP (x, 0)) == PRE_INC
947790075Sobrien	      || GET_CODE (XEXP (x, 0)) == PRE_DEC)
947890075Sobrien	    output_address (plus_constant (XEXP (XEXP (x, 0), 0), 12));
947990075Sobrien	  else
948090075Sobrien	    output_address (XEXP (adjust_address_nv (x, SImode, 12), 0));
948190075Sobrien	  if (small_data_operand (x, GET_MODE (x)))
948290075Sobrien	    fprintf (file, "@%s(%s)", SMALL_DATA_RELOC,
948390075Sobrien		     reg_names[SMALL_DATA_REG]);
948490075Sobrien	}
948590075Sobrien      return;
948690075Sobrien
9487117395Skan      /* Print AltiVec or SPE memory operand.  */
948890075Sobrien    case 'y':
948990075Sobrien      {
949090075Sobrien	rtx tmp;
949190075Sobrien
949290075Sobrien	if (GET_CODE (x) != MEM)
949390075Sobrien	  abort ();
949490075Sobrien
949590075Sobrien	tmp = XEXP (x, 0);
949690075Sobrien
9497132718Skan	if (TARGET_E500)
9498117395Skan	  {
9499117395Skan	    /* Handle [reg].  */
9500117395Skan	    if (GET_CODE (tmp) == REG)
9501117395Skan	      {
9502117395Skan		fprintf (file, "0(%s)", reg_names[REGNO (tmp)]);
9503117395Skan		break;
9504117395Skan	      }
9505117395Skan	    /* Handle [reg+UIMM].  */
9506117395Skan	    else if (GET_CODE (tmp) == PLUS &&
9507117395Skan		     GET_CODE (XEXP (tmp, 1)) == CONST_INT)
9508117395Skan	      {
9509117395Skan		int x;
9510117395Skan
9511117395Skan		if (GET_CODE (XEXP (tmp, 0)) != REG)
9512117395Skan		  abort ();
9513117395Skan
9514117395Skan		x = INTVAL (XEXP (tmp, 1));
9515117395Skan		fprintf (file, "%d(%s)", x, reg_names[REGNO (XEXP (tmp, 0))]);
9516117395Skan		break;
9517117395Skan	      }
9518117395Skan
9519117395Skan	    /* Fall through.  Must be [reg+reg].  */
9520117395Skan	  }
952190075Sobrien	if (GET_CODE (tmp) == REG)
952290075Sobrien	  fprintf (file, "0,%s", reg_names[REGNO (tmp)]);
952390075Sobrien	else if (GET_CODE (tmp) == PLUS && GET_CODE (XEXP (tmp, 1)) == REG)
952490075Sobrien	  {
952590075Sobrien	    if (REGNO (XEXP (tmp, 0)) == 0)
952690075Sobrien	      fprintf (file, "%s,%s", reg_names[ REGNO (XEXP (tmp, 1)) ],
952790075Sobrien		       reg_names[ REGNO (XEXP (tmp, 0)) ]);
952890075Sobrien	    else
952990075Sobrien	      fprintf (file, "%s,%s", reg_names[ REGNO (XEXP (tmp, 0)) ],
953090075Sobrien		       reg_names[ REGNO (XEXP (tmp, 1)) ]);
953190075Sobrien	  }
953290075Sobrien	else
953390075Sobrien	  abort ();
953490075Sobrien	break;
953590075Sobrien      }
953690075Sobrien
953790075Sobrien    case 0:
953890075Sobrien      if (GET_CODE (x) == REG)
953990075Sobrien	fprintf (file, "%s", reg_names[REGNO (x)]);
954090075Sobrien      else if (GET_CODE (x) == MEM)
954190075Sobrien	{
954290075Sobrien	  /* We need to handle PRE_INC and PRE_DEC here, since we need to
954390075Sobrien	     know the width from the mode.  */
954490075Sobrien	  if (GET_CODE (XEXP (x, 0)) == PRE_INC)
954590075Sobrien	    fprintf (file, "%d(%s)", GET_MODE_SIZE (GET_MODE (x)),
954690075Sobrien		     reg_names[REGNO (XEXP (XEXP (x, 0), 0))]);
954790075Sobrien	  else if (GET_CODE (XEXP (x, 0)) == PRE_DEC)
954890075Sobrien	    fprintf (file, "%d(%s)", - GET_MODE_SIZE (GET_MODE (x)),
954990075Sobrien		     reg_names[REGNO (XEXP (XEXP (x, 0), 0))]);
955090075Sobrien	  else
955190075Sobrien	    output_address (XEXP (x, 0));
955290075Sobrien	}
955390075Sobrien      else
955490075Sobrien	output_addr_const (file, x);
955590075Sobrien      return;
955690075Sobrien
9557132718Skan    case '&':
9558132718Skan      assemble_name (file, rs6000_get_some_local_dynamic_name ());
9559132718Skan      return;
9560132718Skan
956190075Sobrien    default:
956290075Sobrien      output_operand_lossage ("invalid %%xn code");
956390075Sobrien    }
956490075Sobrien}
956590075Sobrien
956690075Sobrien/* Print the address of an operand.  */
956790075Sobrien
956890075Sobrienvoid
9569132718Skanprint_operand_address (FILE *file, rtx x)
957090075Sobrien{
957190075Sobrien  if (GET_CODE (x) == REG)
957290075Sobrien    fprintf (file, "0(%s)", reg_names[ REGNO (x) ]);
957390075Sobrien  else if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == CONST
957490075Sobrien	   || GET_CODE (x) == LABEL_REF)
957590075Sobrien    {
957690075Sobrien      output_addr_const (file, x);
957790075Sobrien      if (small_data_operand (x, GET_MODE (x)))
957890075Sobrien	fprintf (file, "@%s(%s)", SMALL_DATA_RELOC,
957990075Sobrien		 reg_names[SMALL_DATA_REG]);
958090075Sobrien      else if (TARGET_TOC)
958190075Sobrien	abort ();
958290075Sobrien    }
958390075Sobrien  else if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == REG)
958490075Sobrien    {
958590075Sobrien      if (REGNO (XEXP (x, 0)) == 0)
958690075Sobrien	fprintf (file, "%s,%s", reg_names[ REGNO (XEXP (x, 1)) ],
958790075Sobrien		 reg_names[ REGNO (XEXP (x, 0)) ]);
958890075Sobrien      else
958990075Sobrien	fprintf (file, "%s,%s", reg_names[ REGNO (XEXP (x, 0)) ],
959090075Sobrien		 reg_names[ REGNO (XEXP (x, 1)) ]);
959190075Sobrien    }
959290075Sobrien  else if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
9593132718Skan    fprintf (file, HOST_WIDE_INT_PRINT_DEC "(%s)",
9594132718Skan	     INTVAL (XEXP (x, 1)), reg_names[ REGNO (XEXP (x, 0)) ]);
959590075Sobrien#if TARGET_ELF
959690075Sobrien  else if (GET_CODE (x) == LO_SUM && GET_CODE (XEXP (x, 0)) == REG
959790075Sobrien           && CONSTANT_P (XEXP (x, 1)))
959890075Sobrien    {
959990075Sobrien      output_addr_const (file, XEXP (x, 1));
960090075Sobrien      fprintf (file, "@l(%s)", reg_names[ REGNO (XEXP (x, 0)) ]);
960190075Sobrien    }
960290075Sobrien#endif
960390075Sobrien#if TARGET_MACHO
960490075Sobrien  else if (GET_CODE (x) == LO_SUM && GET_CODE (XEXP (x, 0)) == REG
960590075Sobrien           && CONSTANT_P (XEXP (x, 1)))
960690075Sobrien    {
960790075Sobrien      fprintf (file, "lo16(");
960890075Sobrien      output_addr_const (file, XEXP (x, 1));
960990075Sobrien      fprintf (file, ")(%s)", reg_names[ REGNO (XEXP (x, 0)) ]);
961090075Sobrien    }
961190075Sobrien#endif
9612132718Skan  else if (legitimate_constant_pool_address_p (x))
961390075Sobrien    {
961490075Sobrien      if (TARGET_AIX && (!TARGET_ELF || !TARGET_MINIMAL_TOC))
961590075Sobrien	{
961690075Sobrien	  rtx contains_minus = XEXP (x, 1);
961790075Sobrien	  rtx minus, symref;
961890075Sobrien	  const char *name;
961990075Sobrien
962090075Sobrien	  /* Find the (minus (sym) (toc)) buried in X, and temporarily
962190075Sobrien	     turn it into (sym) for output_addr_const.  */
962290075Sobrien	  while (GET_CODE (XEXP (contains_minus, 0)) != MINUS)
962390075Sobrien	    contains_minus = XEXP (contains_minus, 0);
962490075Sobrien
962590075Sobrien	  minus = XEXP (contains_minus, 0);
962690075Sobrien	  symref = XEXP (minus, 0);
962790075Sobrien	  XEXP (contains_minus, 0) = symref;
962890075Sobrien	  if (TARGET_ELF)
962990075Sobrien	    {
963090075Sobrien	      char *newname;
963190075Sobrien
963290075Sobrien	      name = XSTR (symref, 0);
963390075Sobrien	      newname = alloca (strlen (name) + sizeof ("@toc"));
963490075Sobrien	      strcpy (newname, name);
963590075Sobrien	      strcat (newname, "@toc");
963690075Sobrien	      XSTR (symref, 0) = newname;
963790075Sobrien	    }
963890075Sobrien	  output_addr_const (file, XEXP (x, 1));
963990075Sobrien	  if (TARGET_ELF)
964090075Sobrien	    XSTR (symref, 0) = name;
964190075Sobrien	  XEXP (contains_minus, 0) = minus;
964290075Sobrien	}
964390075Sobrien      else
964490075Sobrien	output_addr_const (file, XEXP (x, 1));
964590075Sobrien
964690075Sobrien      fprintf (file, "(%s)", reg_names[REGNO (XEXP (x, 0))]);
964790075Sobrien    }
964890075Sobrien  else
964990075Sobrien    abort ();
965090075Sobrien}
965190075Sobrien
9652117395Skan/* Target hook for assembling integer objects.  The PowerPC version has
965390075Sobrien   to handle fixup entries for relocatable code if RELOCATABLE_NEEDS_FIXUP
965490075Sobrien   is defined.  It also needs to handle DI-mode objects on 64-bit
965590075Sobrien   targets.  */
965690075Sobrien
965790075Sobrienstatic bool
9658132718Skanrs6000_assemble_integer (rtx x, unsigned int size, int aligned_p)
965990075Sobrien{
966090075Sobrien#ifdef RELOCATABLE_NEEDS_FIXUP
966190075Sobrien  /* Special handling for SI values.  */
966290075Sobrien  if (size == 4 && aligned_p)
966390075Sobrien    {
9664132718Skan      extern int in_toc_section (void);
966590075Sobrien      static int recurse = 0;
966690075Sobrien
966790075Sobrien      /* For -mrelocatable, we mark all addresses that need to be fixed up
966890075Sobrien	 in the .fixup section.  */
966990075Sobrien      if (TARGET_RELOCATABLE
967090075Sobrien	  && !in_toc_section ()
967190075Sobrien	  && !in_text_section ()
967290075Sobrien	  && !recurse
967390075Sobrien	  && GET_CODE (x) != CONST_INT
967490075Sobrien	  && GET_CODE (x) != CONST_DOUBLE
967590075Sobrien	  && CONSTANT_P (x))
967690075Sobrien	{
967790075Sobrien	  char buf[256];
967890075Sobrien
967990075Sobrien	  recurse = 1;
968090075Sobrien	  ASM_GENERATE_INTERNAL_LABEL (buf, "LCP", fixuplabelno);
968190075Sobrien	  fixuplabelno++;
968290075Sobrien	  ASM_OUTPUT_LABEL (asm_out_file, buf);
968390075Sobrien	  fprintf (asm_out_file, "\t.long\t(");
968490075Sobrien	  output_addr_const (asm_out_file, x);
968590075Sobrien	  fprintf (asm_out_file, ")@fixup\n");
968690075Sobrien	  fprintf (asm_out_file, "\t.section\t\".fixup\",\"aw\"\n");
968790075Sobrien	  ASM_OUTPUT_ALIGN (asm_out_file, 2);
968890075Sobrien	  fprintf (asm_out_file, "\t.long\t");
968990075Sobrien	  assemble_name (asm_out_file, buf);
969090075Sobrien	  fprintf (asm_out_file, "\n\t.previous\n");
969190075Sobrien	  recurse = 0;
969290075Sobrien	  return true;
969390075Sobrien	}
969490075Sobrien      /* Remove initial .'s to turn a -mcall-aixdesc function
969590075Sobrien	 address into the address of the descriptor, not the function
969690075Sobrien	 itself.  */
969790075Sobrien      else if (GET_CODE (x) == SYMBOL_REF
969890075Sobrien	       && XSTR (x, 0)[0] == '.'
969990075Sobrien	       && DEFAULT_ABI == ABI_AIX)
970090075Sobrien	{
970190075Sobrien	  const char *name = XSTR (x, 0);
970290075Sobrien	  while (*name == '.')
970390075Sobrien	    name++;
970490075Sobrien
970590075Sobrien	  fprintf (asm_out_file, "\t.long\t%s\n", name);
970690075Sobrien	  return true;
970790075Sobrien	}
970890075Sobrien    }
970990075Sobrien#endif /* RELOCATABLE_NEEDS_FIXUP */
971090075Sobrien  return default_assemble_integer (x, size, aligned_p);
971190075Sobrien}
9712117395Skan
9713117395Skan#ifdef HAVE_GAS_HIDDEN
9714117395Skan/* Emit an assembler directive to set symbol visibility for DECL to
9715117395Skan   VISIBILITY_TYPE.  */
9716117395Skan
9717117395Skanstatic void
9718132718Skanrs6000_assemble_visibility (tree decl, int vis)
9719117395Skan{
9720117395Skan  /* Functions need to have their entry point symbol visibility set as
9721117395Skan     well as their descriptor symbol visibility.  */
9722117395Skan  if (DEFAULT_ABI == ABI_AIX && TREE_CODE (decl) == FUNCTION_DECL)
9723117395Skan    {
9724117395Skan      static const char * const visibility_types[] = {
9725117395Skan        NULL, "internal", "hidden", "protected"
9726117395Skan      };
9727117395Skan
9728117395Skan      const char *name, *type;
9729117395Skan
9730117395Skan      name = ((* targetm.strip_name_encoding)
9731117395Skan	      (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl))));
9732117395Skan      type = visibility_types[vis];
9733117395Skan
9734117395Skan      fprintf (asm_out_file, "\t.%s\t%s\n", type, name);
9735117395Skan      fprintf (asm_out_file, "\t.%s\t.%s\n", type, name);
9736117395Skan    }
9737117395Skan  else
9738117395Skan    default_assemble_visibility (decl, vis);
9739117395Skan}
9740117395Skan#endif
974190075Sobrien
974290075Sobrienenum rtx_code
9743132718Skanrs6000_reverse_condition (enum machine_mode mode, enum rtx_code code)
974490075Sobrien{
974590075Sobrien  /* Reversal of FP compares takes care -- an ordered compare
974690075Sobrien     becomes an unordered compare and vice versa.  */
9747132718Skan  if (mode == CCFPmode
9748132718Skan      && (!flag_finite_math_only
9749132718Skan	  || code == UNLT || code == UNLE || code == UNGT || code == UNGE
9750132718Skan	  || code == UNEQ || code == LTGT))
975190075Sobrien    return reverse_condition_maybe_unordered (code);
975290075Sobrien  else
975390075Sobrien    return reverse_condition (code);
975490075Sobrien}
975590075Sobrien
975690075Sobrien/* Generate a compare for CODE.  Return a brand-new rtx that
975790075Sobrien   represents the result of the compare.  */
975890075Sobrien
975990075Sobrienstatic rtx
9760132718Skanrs6000_generate_compare (enum rtx_code code)
976190075Sobrien{
976290075Sobrien  enum machine_mode comp_mode;
976390075Sobrien  rtx compare_result;
976490075Sobrien
976590075Sobrien  if (rs6000_compare_fp_p)
976690075Sobrien    comp_mode = CCFPmode;
976790075Sobrien  else if (code == GTU || code == LTU
976890075Sobrien	  || code == GEU || code == LEU)
976990075Sobrien    comp_mode = CCUNSmode;
977090075Sobrien  else
977190075Sobrien    comp_mode = CCmode;
977290075Sobrien
977390075Sobrien  /* First, the compare.  */
977490075Sobrien  compare_result = gen_reg_rtx (comp_mode);
9775117395Skan
9776117395Skan  /* SPE FP compare instructions on the GPRs.  Yuck!  */
9777132718Skan  if ((TARGET_E500 && !TARGET_FPRS && TARGET_HARD_FLOAT)
9778132718Skan      && rs6000_compare_fp_p)
9779117395Skan    {
9780117395Skan      rtx cmp, or1, or2, or_result, compare_result2;
9781117395Skan
9782132718Skan      /* Note: The E500 comparison instructions set the GT bit (x +
9783132718Skan        1), on success.  This explains the mess.  */
9784132718Skan
9785117395Skan      switch (code)
9786117395Skan	{
9787132718Skan       case EQ: case UNEQ: case NE: case LTGT:
9788132718Skan	  cmp = flag_finite_math_only
9789117395Skan	    ? gen_tstsfeq_gpr (compare_result, rs6000_compare_op0,
9790117395Skan			       rs6000_compare_op1)
9791117395Skan	    : gen_cmpsfeq_gpr (compare_result, rs6000_compare_op0,
9792117395Skan			       rs6000_compare_op1);
9793117395Skan	  break;
9794132718Skan       case GT: case GTU: case UNGT: case UNGE: case GE: case GEU:
9795132718Skan	  cmp = flag_finite_math_only
9796117395Skan	    ? gen_tstsfgt_gpr (compare_result, rs6000_compare_op0,
9797117395Skan			       rs6000_compare_op1)
9798117395Skan	    : gen_cmpsfgt_gpr (compare_result, rs6000_compare_op0,
9799117395Skan			       rs6000_compare_op1);
9800117395Skan	  break;
9801132718Skan       case LT: case LTU: case UNLT: case UNLE: case LE: case LEU:
9802132718Skan	  cmp = flag_finite_math_only
9803117395Skan	    ? gen_tstsflt_gpr (compare_result, rs6000_compare_op0,
9804117395Skan			       rs6000_compare_op1)
9805117395Skan	    : gen_cmpsflt_gpr (compare_result, rs6000_compare_op0,
9806117395Skan			       rs6000_compare_op1);
9807117395Skan	  break;
9808117395Skan	default:
9809117395Skan	  abort ();
9810117395Skan	}
9811117395Skan
9812117395Skan      /* Synthesize LE and GE from LT/GT || EQ.  */
9813117395Skan      if (code == LE || code == GE || code == LEU || code == GEU)
9814117395Skan	{
9815117395Skan	  emit_insn (cmp);
9816117395Skan
9817117395Skan	  switch (code)
9818117395Skan	    {
9819117395Skan	    case LE: code = LT; break;
9820117395Skan	    case GE: code = GT; break;
9821117395Skan	    case LEU: code = LT; break;
9822117395Skan	    case GEU: code = GT; break;
9823117395Skan	    default: abort ();
9824117395Skan	    }
9825117395Skan
9826117395Skan	  or1 = gen_reg_rtx (SImode);
9827117395Skan	  or2 = gen_reg_rtx (SImode);
9828117395Skan	  or_result = gen_reg_rtx (CCEQmode);
9829117395Skan	  compare_result2 = gen_reg_rtx (CCFPmode);
9830117395Skan
9831117395Skan	  /* Do the EQ.  */
9832132718Skan	  cmp = flag_finite_math_only
9833117395Skan	    ? gen_tstsfeq_gpr (compare_result2, rs6000_compare_op0,
9834117395Skan			       rs6000_compare_op1)
9835117395Skan	    : gen_cmpsfeq_gpr (compare_result2, rs6000_compare_op0,
9836117395Skan			       rs6000_compare_op1);
9837117395Skan	  emit_insn (cmp);
9838117395Skan
9839132718Skan	  or1 = gen_rtx_GT (SImode, compare_result, const0_rtx);
9840132718Skan	  or2 = gen_rtx_GT (SImode, compare_result2, const0_rtx);
9841117395Skan
9842117395Skan	  /* OR them together.  */
9843117395Skan	  cmp = gen_rtx_SET (VOIDmode, or_result,
9844117395Skan			     gen_rtx_COMPARE (CCEQmode,
9845117395Skan					      gen_rtx_IOR (SImode, or1, or2),
9846117395Skan					      const_true_rtx));
9847117395Skan	  compare_result = or_result;
9848117395Skan	  code = EQ;
9849117395Skan	}
9850117395Skan      else
9851117395Skan	{
9852117395Skan	  if (code == NE || code == LTGT)
9853117395Skan	    code = NE;
9854132718Skan         else
9855132718Skan           code = EQ;
9856117395Skan	}
9857117395Skan
9858117395Skan      emit_insn (cmp);
9859117395Skan    }
9860117395Skan  else
9861117395Skan    emit_insn (gen_rtx_SET (VOIDmode, compare_result,
9862117395Skan			    gen_rtx_COMPARE (comp_mode,
9863117395Skan					     rs6000_compare_op0,
9864117395Skan					     rs6000_compare_op1)));
986590075Sobrien
986690075Sobrien  /* Some kinds of FP comparisons need an OR operation;
9867132718Skan     under flag_finite_math_only we don't bother.  */
986890075Sobrien  if (rs6000_compare_fp_p
9869132718Skan      && ! flag_finite_math_only
9870132718Skan      && ! (TARGET_HARD_FLOAT && TARGET_E500 && !TARGET_FPRS)
987190075Sobrien      && (code == LE || code == GE
987290075Sobrien	  || code == UNEQ || code == LTGT
987390075Sobrien	  || code == UNGT || code == UNLT))
987490075Sobrien    {
987590075Sobrien      enum rtx_code or1, or2;
987690075Sobrien      rtx or1_rtx, or2_rtx, compare2_rtx;
987790075Sobrien      rtx or_result = gen_reg_rtx (CCEQmode);
987890075Sobrien
987990075Sobrien      switch (code)
988090075Sobrien	{
988190075Sobrien	case LE: or1 = LT;  or2 = EQ;  break;
988290075Sobrien	case GE: or1 = GT;  or2 = EQ;  break;
988390075Sobrien	case UNEQ: or1 = UNORDERED;  or2 = EQ;  break;
988490075Sobrien	case LTGT: or1 = LT;  or2 = GT;  break;
988590075Sobrien	case UNGT: or1 = UNORDERED;  or2 = GT;  break;
988690075Sobrien	case UNLT: or1 = UNORDERED;  or2 = LT;  break;
988790075Sobrien	default:  abort ();
988890075Sobrien	}
988990075Sobrien      validate_condition_mode (or1, comp_mode);
989090075Sobrien      validate_condition_mode (or2, comp_mode);
989190075Sobrien      or1_rtx = gen_rtx (or1, SImode, compare_result, const0_rtx);
989290075Sobrien      or2_rtx = gen_rtx (or2, SImode, compare_result, const0_rtx);
989390075Sobrien      compare2_rtx = gen_rtx_COMPARE (CCEQmode,
989490075Sobrien				      gen_rtx_IOR (SImode, or1_rtx, or2_rtx),
989590075Sobrien				      const_true_rtx);
989690075Sobrien      emit_insn (gen_rtx_SET (VOIDmode, or_result, compare2_rtx));
989790075Sobrien
989890075Sobrien      compare_result = or_result;
989990075Sobrien      code = EQ;
990090075Sobrien    }
990190075Sobrien
990290075Sobrien  validate_condition_mode (code, GET_MODE (compare_result));
990390075Sobrien
990490075Sobrien  return gen_rtx (code, VOIDmode, compare_result, const0_rtx);
990590075Sobrien}
990690075Sobrien
990790075Sobrien
990890075Sobrien/* Emit the RTL for an sCOND pattern.  */
990990075Sobrien
991090075Sobrienvoid
9911132718Skanrs6000_emit_sCOND (enum rtx_code code, rtx result)
991290075Sobrien{
991390075Sobrien  rtx condition_rtx;
991490075Sobrien  enum machine_mode op_mode;
9915132718Skan  enum rtx_code cond_code;
991690075Sobrien
991790075Sobrien  condition_rtx = rs6000_generate_compare (code);
9918132718Skan  cond_code = GET_CODE (condition_rtx);
991990075Sobrien
9920132718Skan  if (TARGET_E500 && rs6000_compare_fp_p
9921132718Skan      && !TARGET_FPRS && TARGET_HARD_FLOAT)
9922132718Skan    {
9923132718Skan      rtx t;
9924132718Skan
9925132718Skan      PUT_MODE (condition_rtx, SImode);
9926132718Skan      t = XEXP (condition_rtx, 0);
9927132718Skan
9928132718Skan      if (cond_code != NE && cond_code != EQ)
9929132718Skan       abort ();
9930132718Skan
9931132718Skan      if (cond_code == NE)
9932132718Skan       emit_insn (gen_e500_flip_gt_bit (t, t));
9933132718Skan
9934132718Skan      emit_insn (gen_move_from_CR_gt_bit (result, t));
9935132718Skan      return;
9936132718Skan    }
9937132718Skan
9938132718Skan  if (cond_code == NE
9939132718Skan      || cond_code == GE || cond_code == LE
9940132718Skan      || cond_code == GEU || cond_code == LEU
9941132718Skan      || cond_code == ORDERED || cond_code == UNGE || cond_code == UNLE)
9942132718Skan    {
9943132718Skan      rtx not_result = gen_reg_rtx (CCEQmode);
9944132718Skan      rtx not_op, rev_cond_rtx;
9945132718Skan      enum machine_mode cc_mode;
9946132718Skan
9947132718Skan      cc_mode = GET_MODE (XEXP (condition_rtx, 0));
9948132718Skan
9949132718Skan      rev_cond_rtx = gen_rtx (rs6000_reverse_condition (cc_mode, cond_code),
9950132718Skan			      SImode, XEXP (condition_rtx, 0), const0_rtx);
9951132718Skan      not_op = gen_rtx_COMPARE (CCEQmode, rev_cond_rtx, const0_rtx);
9952132718Skan      emit_insn (gen_rtx_SET (VOIDmode, not_result, not_op));
9953132718Skan      condition_rtx = gen_rtx_EQ (VOIDmode, not_result, const0_rtx);
9954132718Skan    }
9955132718Skan
995690075Sobrien  op_mode = GET_MODE (rs6000_compare_op0);
995790075Sobrien  if (op_mode == VOIDmode)
995890075Sobrien    op_mode = GET_MODE (rs6000_compare_op1);
995990075Sobrien
996090075Sobrien  if (TARGET_POWERPC64 && (op_mode == DImode || rs6000_compare_fp_p))
996190075Sobrien    {
996290075Sobrien      PUT_MODE (condition_rtx, DImode);
996390075Sobrien      convert_move (result, condition_rtx, 0);
996490075Sobrien    }
996590075Sobrien  else
996690075Sobrien    {
996790075Sobrien      PUT_MODE (condition_rtx, SImode);
996890075Sobrien      emit_insn (gen_rtx_SET (VOIDmode, result, condition_rtx));
996990075Sobrien    }
997090075Sobrien}
997190075Sobrien
997290075Sobrien/* Emit a branch of kind CODE to location LOC.  */
997390075Sobrien
997490075Sobrienvoid
9975132718Skanrs6000_emit_cbranch (enum rtx_code code, rtx loc)
997690075Sobrien{
997790075Sobrien  rtx condition_rtx, loc_ref;
997890075Sobrien
997990075Sobrien  condition_rtx = rs6000_generate_compare (code);
998090075Sobrien  loc_ref = gen_rtx_LABEL_REF (VOIDmode, loc);
998190075Sobrien  emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx,
998290075Sobrien			       gen_rtx_IF_THEN_ELSE (VOIDmode, condition_rtx,
998390075Sobrien						     loc_ref, pc_rtx)));
998490075Sobrien}
998590075Sobrien
998690075Sobrien/* Return the string to output a conditional branch to LABEL, which is
998790075Sobrien   the operand number of the label, or -1 if the branch is really a
998890075Sobrien   conditional return.
998990075Sobrien
999090075Sobrien   OP is the conditional expression.  XEXP (OP, 0) is assumed to be a
999190075Sobrien   condition code register and its mode specifies what kind of
999290075Sobrien   comparison we made.
999390075Sobrien
9994117395Skan   REVERSED is nonzero if we should reverse the sense of the comparison.
999590075Sobrien
999690075Sobrien   INSN is the insn.  */
999790075Sobrien
999890075Sobrienchar *
9999132718Skanoutput_cbranch (rtx op, const char *label, int reversed, rtx insn)
1000090075Sobrien{
1000190075Sobrien  static char string[64];
1000290075Sobrien  enum rtx_code code = GET_CODE (op);
1000390075Sobrien  rtx cc_reg = XEXP (op, 0);
1000490075Sobrien  enum machine_mode mode = GET_MODE (cc_reg);
1000590075Sobrien  int cc_regno = REGNO (cc_reg) - CR0_REGNO;
1000690075Sobrien  int need_longbranch = label != NULL && get_attr_length (insn) == 8;
1000790075Sobrien  int really_reversed = reversed ^ need_longbranch;
1000890075Sobrien  char *s = string;
1000990075Sobrien  const char *ccode;
1001090075Sobrien  const char *pred;
1001190075Sobrien  rtx note;
1001290075Sobrien
1001390075Sobrien  validate_condition_mode (code, mode);
1001490075Sobrien
1001590075Sobrien  /* Work out which way this really branches.  We could use
1001690075Sobrien     reverse_condition_maybe_unordered here always but this
1001790075Sobrien     makes the resulting assembler clearer.  */
1001890075Sobrien  if (really_reversed)
10019107590Sobrien    {
10020107590Sobrien      /* Reversal of FP compares takes care -- an ordered compare
10021107590Sobrien	 becomes an unordered compare and vice versa.  */
10022107590Sobrien      if (mode == CCFPmode)
10023107590Sobrien	code = reverse_condition_maybe_unordered (code);
10024107590Sobrien      else
10025107590Sobrien	code = reverse_condition (code);
10026107590Sobrien    }
1002790075Sobrien
10028132718Skan  if ((TARGET_E500 && !TARGET_FPRS && TARGET_HARD_FLOAT) && mode == CCFPmode)
10029117395Skan    {
10030117395Skan      /* The efscmp/tst* instructions twiddle bit 2, which maps nicely
10031117395Skan	 to the GT bit.  */
10032117395Skan      if (code == EQ)
10033117395Skan	/* Opposite of GT.  */
10034132718Skan	code = GT;
10035117395Skan      else if (code == NE)
10036132718Skan       code = UNLE;
10037117395Skan      else
10038117395Skan	abort ();
10039117395Skan    }
10040117395Skan
1004190075Sobrien  switch (code)
1004290075Sobrien    {
1004390075Sobrien      /* Not all of these are actually distinct opcodes, but
1004490075Sobrien	 we distinguish them for clarity of the resulting assembler.  */
1004590075Sobrien    case NE: case LTGT:
1004690075Sobrien      ccode = "ne"; break;
1004790075Sobrien    case EQ: case UNEQ:
1004890075Sobrien      ccode = "eq"; break;
1004990075Sobrien    case GE: case GEU:
1005090075Sobrien      ccode = "ge"; break;
1005190075Sobrien    case GT: case GTU: case UNGT:
1005290075Sobrien      ccode = "gt"; break;
1005390075Sobrien    case LE: case LEU:
1005490075Sobrien      ccode = "le"; break;
1005590075Sobrien    case LT: case LTU: case UNLT:
1005690075Sobrien      ccode = "lt"; break;
1005790075Sobrien    case UNORDERED: ccode = "un"; break;
1005890075Sobrien    case ORDERED: ccode = "nu"; break;
1005990075Sobrien    case UNGE: ccode = "nl"; break;
1006090075Sobrien    case UNLE: ccode = "ng"; break;
1006190075Sobrien    default:
1006290075Sobrien      abort ();
1006390075Sobrien    }
1006490075Sobrien
1006590075Sobrien  /* Maybe we have a guess as to how likely the branch is.
1006690075Sobrien     The old mnemonics don't have a way to specify this information.  */
10067117395Skan  pred = "";
1006890075Sobrien  note = find_reg_note (insn, REG_BR_PROB, NULL_RTX);
1006990075Sobrien  if (note != NULL_RTX)
1007090075Sobrien    {
1007190075Sobrien      /* PROB is the difference from 50%.  */
1007290075Sobrien      int prob = INTVAL (XEXP (note, 0)) - REG_BR_PROB_BASE / 2;
10073117395Skan
10074117395Skan      /* Only hint for highly probable/improbable branches on newer
10075117395Skan	 cpus as static prediction overrides processor dynamic
10076117395Skan	 prediction.  For older cpus we may as well always hint, but
10077117395Skan	 assume not taken for branches that are very close to 50% as a
10078117395Skan	 mispredicted taken branch is more expensive than a
10079117395Skan	 mispredicted not-taken branch.  */
10080132718Skan      if (rs6000_always_hint
10081117395Skan	  || abs (prob) > REG_BR_PROB_BASE / 100 * 48)
10082117395Skan	{
10083117395Skan	  if (abs (prob) > REG_BR_PROB_BASE / 20
10084117395Skan	      && ((prob > 0) ^ need_longbranch))
10085132718Skan              pred = "+";
10086117395Skan	  else
10087117395Skan	    pred = "-";
10088117395Skan	}
1008990075Sobrien    }
1009090075Sobrien
1009190075Sobrien  if (label == NULL)
1009290075Sobrien    s += sprintf (s, "{b%sr|b%slr%s} ", ccode, ccode, pred);
1009390075Sobrien  else
1009490075Sobrien    s += sprintf (s, "{b%s|b%s%s} ", ccode, ccode, pred);
1009590075Sobrien
1009690075Sobrien  /* We need to escape any '%' characters in the reg_names string.
10097132718Skan     Assume they'd only be the first character....  */
1009890075Sobrien  if (reg_names[cc_regno + CR0_REGNO][0] == '%')
1009990075Sobrien    *s++ = '%';
1010090075Sobrien  s += sprintf (s, "%s", reg_names[cc_regno + CR0_REGNO]);
1010190075Sobrien
1010290075Sobrien  if (label != NULL)
1010390075Sobrien    {
1010490075Sobrien      /* If the branch distance was too far, we may have to use an
1010590075Sobrien	 unconditional branch to go the distance.  */
1010690075Sobrien      if (need_longbranch)
1010790075Sobrien	s += sprintf (s, ",$+8\n\tb %s", label);
1010890075Sobrien      else
1010990075Sobrien	s += sprintf (s, ",%s", label);
1011090075Sobrien    }
1011190075Sobrien
1011290075Sobrien  return string;
1011390075Sobrien}
1011490075Sobrien
10115132718Skan/* Return the string to flip the GT bit on a CR.  */
10116132718Skanchar *
10117132718Skanoutput_e500_flip_gt_bit (rtx dst, rtx src)
10118132718Skan{
10119132718Skan  static char string[64];
10120132718Skan  int a, b;
10121132718Skan
10122132718Skan  if (GET_CODE (dst) != REG || ! CR_REGNO_P (REGNO (dst))
10123132718Skan      || GET_CODE (src) != REG || ! CR_REGNO_P (REGNO (src)))
10124132718Skan    abort ();
10125132718Skan
10126132718Skan  /* GT bit.  */
10127132718Skan  a = 4 * (REGNO (dst) - CR0_REGNO) + 1;
10128132718Skan  b = 4 * (REGNO (src) - CR0_REGNO) + 1;
10129132718Skan
10130132718Skan  sprintf (string, "crnot %d,%d", a, b);
10131132718Skan  return string;
10132132718Skan}
10133132718Skan
1013490075Sobrien/* Emit a conditional move: move TRUE_COND to DEST if OP of the
1013590075Sobrien   operands of the last comparison is nonzero/true, FALSE_COND if it
1013690075Sobrien   is zero/false.  Return 0 if the hardware has no such operation.  */
1013790075Sobrien
1013890075Sobrienint
10139132718Skanrs6000_emit_cmove (rtx dest, rtx op, rtx true_cond, rtx false_cond)
1014090075Sobrien{
1014190075Sobrien  enum rtx_code code = GET_CODE (op);
1014290075Sobrien  rtx op0 = rs6000_compare_op0;
1014390075Sobrien  rtx op1 = rs6000_compare_op1;
1014490075Sobrien  REAL_VALUE_TYPE c1;
1014596263Sobrien  enum machine_mode compare_mode = GET_MODE (op0);
1014696263Sobrien  enum machine_mode result_mode = GET_MODE (dest);
1014790075Sobrien  rtx temp;
1014890075Sobrien
10149132718Skan  /* These modes should always match.  */
10150117395Skan  if (GET_MODE (op1) != compare_mode
10151117395Skan      /* In the isel case however, we can use a compare immediate, so
10152117395Skan	 op1 may be a small constant.  */
10153117395Skan      && (!TARGET_ISEL || !short_cint_operand (op1, VOIDmode)))
1015496263Sobrien    return 0;
1015596263Sobrien  if (GET_MODE (true_cond) != result_mode)
1015696263Sobrien    return 0;
1015796263Sobrien  if (GET_MODE (false_cond) != result_mode)
1015896263Sobrien    return 0;
1015996263Sobrien
1016090075Sobrien  /* First, work out if the hardware can do this at all, or
10161132718Skan     if it's too slow....  */
1016290075Sobrien  if (! rs6000_compare_fp_p)
10163117395Skan    {
10164117395Skan      if (TARGET_ISEL)
10165117395Skan	return rs6000_emit_int_cmove (dest, op, true_cond, false_cond);
10166117395Skan      return 0;
10167117395Skan    }
10168132718Skan  else if (TARGET_E500 && TARGET_HARD_FLOAT && !TARGET_FPRS
10169132718Skan	   && GET_MODE_CLASS (compare_mode) == MODE_FLOAT)
10170132718Skan    return 0;
1017190075Sobrien
1017290075Sobrien  /* Eliminate half of the comparisons by switching operands, this
1017390075Sobrien     makes the remaining code simpler.  */
1017490075Sobrien  if (code == UNLT || code == UNGT || code == UNORDERED || code == NE
10175132718Skan      || code == LTGT || code == LT || code == UNLE)
1017690075Sobrien    {
1017790075Sobrien      code = reverse_condition_maybe_unordered (code);
1017890075Sobrien      temp = true_cond;
1017990075Sobrien      true_cond = false_cond;
1018090075Sobrien      false_cond = temp;
1018190075Sobrien    }
1018290075Sobrien
1018390075Sobrien  /* UNEQ and LTGT take four instructions for a comparison with zero,
1018490075Sobrien     it'll probably be faster to use a branch here too.  */
10185132718Skan  if (code == UNEQ && HONOR_NANS (compare_mode))
1018690075Sobrien    return 0;
1018790075Sobrien
1018890075Sobrien  if (GET_CODE (op1) == CONST_DOUBLE)
1018990075Sobrien    REAL_VALUE_FROM_CONST_DOUBLE (c1, op1);
1019090075Sobrien
10191132718Skan  /* We're going to try to implement comparisons by performing
1019290075Sobrien     a subtract, then comparing against zero.  Unfortunately,
1019390075Sobrien     Inf - Inf is NaN which is not zero, and so if we don't
10194117395Skan     know that the operand is finite and the comparison
1019590075Sobrien     would treat EQ different to UNORDERED, we can't do it.  */
10196132718Skan  if (HONOR_INFINITIES (compare_mode)
1019790075Sobrien      && code != GT && code != UNGE
10198117395Skan      && (GET_CODE (op1) != CONST_DOUBLE || real_isinf (&c1))
1019990075Sobrien      /* Constructs of the form (a OP b ? a : b) are safe.  */
1020090075Sobrien      && ((! rtx_equal_p (op0, false_cond) && ! rtx_equal_p (op1, false_cond))
1020190075Sobrien	  || (! rtx_equal_p (op0, true_cond)
1020290075Sobrien	      && ! rtx_equal_p (op1, true_cond))))
1020390075Sobrien    return 0;
1020490075Sobrien  /* At this point we know we can use fsel.  */
1020590075Sobrien
1020690075Sobrien  /* Reduce the comparison to a comparison against zero.  */
1020796263Sobrien  temp = gen_reg_rtx (compare_mode);
1020890075Sobrien  emit_insn (gen_rtx_SET (VOIDmode, temp,
1020996263Sobrien			  gen_rtx_MINUS (compare_mode, op0, op1)));
1021090075Sobrien  op0 = temp;
1021196263Sobrien  op1 = CONST0_RTX (compare_mode);
1021290075Sobrien
1021390075Sobrien  /* If we don't care about NaNs we can reduce some of the comparisons
1021490075Sobrien     down to faster ones.  */
10215132718Skan  if (! HONOR_NANS (compare_mode))
1021690075Sobrien    switch (code)
1021790075Sobrien      {
1021890075Sobrien      case GT:
1021990075Sobrien	code = LE;
1022090075Sobrien	temp = true_cond;
1022190075Sobrien	true_cond = false_cond;
1022290075Sobrien	false_cond = temp;
1022390075Sobrien	break;
1022490075Sobrien      case UNGE:
1022590075Sobrien	code = GE;
1022690075Sobrien	break;
1022790075Sobrien      case UNEQ:
1022890075Sobrien	code = EQ;
1022990075Sobrien	break;
1023090075Sobrien      default:
1023190075Sobrien	break;
1023290075Sobrien      }
1023390075Sobrien
1023490075Sobrien  /* Now, reduce everything down to a GE.  */
1023590075Sobrien  switch (code)
1023690075Sobrien    {
1023790075Sobrien    case GE:
1023890075Sobrien      break;
1023990075Sobrien
1024090075Sobrien    case LE:
1024196263Sobrien      temp = gen_reg_rtx (compare_mode);
1024296263Sobrien      emit_insn (gen_rtx_SET (VOIDmode, temp, gen_rtx_NEG (compare_mode, op0)));
1024390075Sobrien      op0 = temp;
1024490075Sobrien      break;
1024590075Sobrien
1024690075Sobrien    case ORDERED:
1024796263Sobrien      temp = gen_reg_rtx (compare_mode);
1024896263Sobrien      emit_insn (gen_rtx_SET (VOIDmode, temp, gen_rtx_ABS (compare_mode, op0)));
1024990075Sobrien      op0 = temp;
1025090075Sobrien      break;
1025190075Sobrien
1025290075Sobrien    case EQ:
1025396263Sobrien      temp = gen_reg_rtx (compare_mode);
1025490075Sobrien      emit_insn (gen_rtx_SET (VOIDmode, temp,
1025596263Sobrien			      gen_rtx_NEG (compare_mode,
1025696263Sobrien					   gen_rtx_ABS (compare_mode, op0))));
1025790075Sobrien      op0 = temp;
1025890075Sobrien      break;
1025990075Sobrien
1026090075Sobrien    case UNGE:
10261132718Skan      /* a UNGE 0 <-> (a GE 0 || -a UNLT 0) */
1026296263Sobrien      temp = gen_reg_rtx (result_mode);
1026390075Sobrien      emit_insn (gen_rtx_SET (VOIDmode, temp,
1026496263Sobrien			      gen_rtx_IF_THEN_ELSE (result_mode,
1026590075Sobrien						    gen_rtx_GE (VOIDmode,
1026690075Sobrien								op0, op1),
1026790075Sobrien						    true_cond, false_cond)));
10268132718Skan      false_cond = true_cond;
10269132718Skan      true_cond = temp;
1027090075Sobrien
1027196263Sobrien      temp = gen_reg_rtx (compare_mode);
1027296263Sobrien      emit_insn (gen_rtx_SET (VOIDmode, temp, gen_rtx_NEG (compare_mode, op0)));
1027390075Sobrien      op0 = temp;
1027490075Sobrien      break;
1027590075Sobrien
1027690075Sobrien    case GT:
10277132718Skan      /* a GT 0 <-> (a GE 0 && -a UNLT 0) */
1027896263Sobrien      temp = gen_reg_rtx (result_mode);
1027990075Sobrien      emit_insn (gen_rtx_SET (VOIDmode, temp,
1028096263Sobrien			      gen_rtx_IF_THEN_ELSE (result_mode,
1028190075Sobrien						    gen_rtx_GE (VOIDmode,
1028290075Sobrien								op0, op1),
1028390075Sobrien						    true_cond, false_cond)));
10284132718Skan      true_cond = false_cond;
10285132718Skan      false_cond = temp;
1028690075Sobrien
1028796263Sobrien      temp = gen_reg_rtx (compare_mode);
1028896263Sobrien      emit_insn (gen_rtx_SET (VOIDmode, temp, gen_rtx_NEG (compare_mode, op0)));
1028990075Sobrien      op0 = temp;
1029090075Sobrien      break;
1029190075Sobrien
1029290075Sobrien    default:
1029390075Sobrien      abort ();
1029490075Sobrien    }
1029590075Sobrien
1029690075Sobrien  emit_insn (gen_rtx_SET (VOIDmode, dest,
1029796263Sobrien			  gen_rtx_IF_THEN_ELSE (result_mode,
1029890075Sobrien						gen_rtx_GE (VOIDmode,
1029990075Sobrien							    op0, op1),
1030090075Sobrien						true_cond, false_cond)));
1030190075Sobrien  return 1;
1030290075Sobrien}
1030390075Sobrien
10304117395Skan/* Same as above, but for ints (isel).  */
10305117395Skan
10306117395Skanstatic int
10307132718Skanrs6000_emit_int_cmove (rtx dest, rtx op, rtx true_cond, rtx false_cond)
10308117395Skan{
10309117395Skan  rtx condition_rtx, cr;
10310117395Skan
10311117395Skan  /* All isel implementations thus far are 32-bits.  */
10312117395Skan  if (GET_MODE (rs6000_compare_op0) != SImode)
10313117395Skan    return 0;
10314117395Skan
10315117395Skan  /* We still have to do the compare, because isel doesn't do a
10316117395Skan     compare, it just looks at the CRx bits set by a previous compare
10317117395Skan     instruction.  */
10318117395Skan  condition_rtx = rs6000_generate_compare (GET_CODE (op));
10319117395Skan  cr = XEXP (condition_rtx, 0);
10320117395Skan
10321117395Skan  if (GET_MODE (cr) == CCmode)
10322117395Skan    emit_insn (gen_isel_signed (dest, condition_rtx,
10323117395Skan				true_cond, false_cond, cr));
10324117395Skan  else
10325117395Skan    emit_insn (gen_isel_unsigned (dest, condition_rtx,
10326117395Skan				  true_cond, false_cond, cr));
10327117395Skan
10328117395Skan  return 1;
10329117395Skan}
10330117395Skan
10331117395Skanconst char *
10332132718Skanoutput_isel (rtx *operands)
10333117395Skan{
10334117395Skan  enum rtx_code code;
10335117395Skan
10336117395Skan  code = GET_CODE (operands[1]);
10337117395Skan  if (code == GE || code == GEU || code == LE || code == LEU || code == NE)
10338117395Skan    {
10339117395Skan      PUT_CODE (operands[1], reverse_condition (code));
10340117395Skan      return "isel %0,%3,%2,%j1";
10341117395Skan    }
10342117395Skan  else
10343117395Skan    return "isel %0,%2,%3,%j1";
10344117395Skan}
10345117395Skan
1034690075Sobrienvoid
10347132718Skanrs6000_emit_minmax (rtx dest, enum rtx_code code, rtx op0, rtx op1)
1034890075Sobrien{
1034990075Sobrien  enum machine_mode mode = GET_MODE (op0);
10350117395Skan  enum rtx_code c;
1035190075Sobrien  rtx target;
10352117395Skan
10353117395Skan  if (code == SMAX || code == SMIN)
10354117395Skan    c = GE;
10355117395Skan  else
10356117395Skan    c = GEU;
10357117395Skan
1035890075Sobrien  if (code == SMAX || code == UMAX)
10359117395Skan    target = emit_conditional_move (dest, c, op0, op1, mode,
1036090075Sobrien				    op0, op1, mode, 0);
1036190075Sobrien  else
10362117395Skan    target = emit_conditional_move (dest, c, op0, op1, mode,
1036390075Sobrien				    op1, op0, mode, 0);
1036490075Sobrien  if (target == NULL_RTX)
1036590075Sobrien    abort ();
1036690075Sobrien  if (target != dest)
1036790075Sobrien    emit_move_insn (dest, target);
1036890075Sobrien}
10369132718Skan
10370132718Skan/* Emit instructions to move SRC to DST.  Called by splitters for
10371132718Skan   multi-register moves.  It will emit at most one instruction for
10372132718Skan   each register that is accessed; that is, it won't emit li/lis pairs
10373132718Skan   (or equivalent for 64-bit code).  One of SRC or DST must be a hard
10374132718Skan   register.  */
10375132718Skan
10376132718Skanvoid
10377132718Skanrs6000_split_multireg_move (rtx dst, rtx src)
10378132718Skan{
10379132718Skan  /* The register number of the first register being moved.  */
10380132718Skan  int reg;
10381132718Skan  /* The mode that is to be moved.  */
10382132718Skan  enum machine_mode mode;
10383132718Skan  /* The mode that the move is being done in, and its size.  */
10384132718Skan  enum machine_mode reg_mode;
10385132718Skan  int reg_mode_size;
10386132718Skan  /* The number of registers that will be moved.  */
10387132718Skan  int nregs;
10388132718Skan
10389132718Skan  reg = REG_P (dst) ? REGNO (dst) : REGNO (src);
10390132718Skan  mode = GET_MODE (dst);
10391132718Skan  nregs = HARD_REGNO_NREGS (reg, mode);
10392132718Skan  if (FP_REGNO_P (reg))
10393132718Skan    reg_mode = DFmode;
10394132718Skan  else if (ALTIVEC_REGNO_P (reg))
10395132718Skan    reg_mode = V16QImode;
10396132718Skan  else
10397132718Skan    reg_mode = word_mode;
10398132718Skan  reg_mode_size = GET_MODE_SIZE (reg_mode);
10399132718Skan
10400132718Skan  if (reg_mode_size * nregs != GET_MODE_SIZE (mode))
10401132718Skan    abort ();
10402132718Skan
10403132718Skan  if (REG_P (src) && REG_P (dst) && (REGNO (src) < REGNO (dst)))
10404132718Skan    {
10405132718Skan      /* Move register range backwards, if we might have destructive
10406132718Skan	 overlap.  */
10407132718Skan      int i;
10408132718Skan      for (i = nregs - 1; i >= 0; i--)
10409132718Skan	emit_insn (gen_rtx_SET (VOIDmode,
10410132718Skan				simplify_gen_subreg (reg_mode, dst, mode,
10411132718Skan						     i * reg_mode_size),
10412132718Skan				simplify_gen_subreg (reg_mode, src, mode,
10413132718Skan						     i * reg_mode_size)));
10414132718Skan    }
10415132718Skan  else
10416132718Skan    {
10417132718Skan      int i;
10418132718Skan      int j = -1;
10419132718Skan      bool used_update = false;
10420132718Skan
10421132718Skan      if (GET_CODE (src) == MEM && INT_REGNO_P (reg))
10422132718Skan        {
10423132718Skan          rtx breg;
10424132718Skan
10425132718Skan	  if (GET_CODE (XEXP (src, 0)) == PRE_INC
10426132718Skan	      || GET_CODE (XEXP (src, 0)) == PRE_DEC)
10427132718Skan	    {
10428132718Skan	      rtx delta_rtx;
10429132718Skan	      breg = XEXP (XEXP (src, 0), 0);
10430132718Skan	      delta_rtx =  GET_CODE (XEXP (src, 0)) == PRE_INC
10431132718Skan		  ? GEN_INT (GET_MODE_SIZE (GET_MODE (src)))
10432132718Skan		  : GEN_INT (-GET_MODE_SIZE (GET_MODE (src)));
10433132718Skan	      emit_insn (TARGET_32BIT
10434132718Skan			 ? gen_addsi3 (breg, breg, delta_rtx)
10435132718Skan			 : gen_adddi3 (breg, breg, delta_rtx));
10436132718Skan	      src = gen_rtx_MEM (mode, breg);
10437132718Skan	    }
10438132718Skan
10439132718Skan	  /* We have now address involving an base register only.
10440132718Skan	     If we use one of the registers to address memory,
10441132718Skan	     we have change that register last.  */
10442132718Skan
10443132718Skan	  breg = (GET_CODE (XEXP (src, 0)) == PLUS
10444132718Skan		  ? XEXP (XEXP (src, 0), 0)
10445132718Skan		  : XEXP (src, 0));
10446132718Skan
10447132718Skan	  if (!REG_P (breg))
10448132718Skan	      abort();
10449132718Skan
10450132718Skan	  if (REGNO (breg) >= REGNO (dst)
10451132718Skan	      && REGNO (breg) < REGNO (dst) + nregs)
10452132718Skan	    j = REGNO (breg) - REGNO (dst);
10453132718Skan        }
10454132718Skan
10455132718Skan      if (GET_CODE (dst) == MEM && INT_REGNO_P (reg))
10456132718Skan	{
10457132718Skan	  rtx breg;
10458132718Skan
10459132718Skan	  if (GET_CODE (XEXP (dst, 0)) == PRE_INC
10460132718Skan	      || GET_CODE (XEXP (dst, 0)) == PRE_DEC)
10461132718Skan	    {
10462132718Skan	      rtx delta_rtx;
10463132718Skan	      breg = XEXP (XEXP (dst, 0), 0);
10464132718Skan	      delta_rtx = GET_CODE (XEXP (dst, 0)) == PRE_INC
10465132718Skan		? GEN_INT (GET_MODE_SIZE (GET_MODE (dst)))
10466132718Skan		: GEN_INT (-GET_MODE_SIZE (GET_MODE (dst)));
10467132718Skan
10468132718Skan	      /* We have to update the breg before doing the store.
10469132718Skan		 Use store with update, if available.  */
10470132718Skan
10471132718Skan	      if (TARGET_UPDATE)
10472132718Skan		{
10473132718Skan		  rtx nsrc = simplify_gen_subreg (reg_mode, src, mode, 0);
10474132718Skan		  emit_insn (TARGET_32BIT
10475132718Skan			     ? gen_movsi_update (breg, breg, delta_rtx, nsrc)
10476132718Skan			     : gen_movdi_update (breg, breg, delta_rtx, nsrc));
10477132718Skan		  used_update = true;
10478132718Skan		}
10479132718Skan	      else
10480132718Skan		emit_insn (TARGET_32BIT
10481132718Skan			   ? gen_addsi3 (breg, breg, delta_rtx)
10482132718Skan			   : gen_adddi3 (breg, breg, delta_rtx));
10483132718Skan	      dst = gen_rtx_MEM (mode, breg);
10484132718Skan	    }
10485132718Skan	}
10486132718Skan
10487132718Skan      for (i = 0; i < nregs; i++)
10488132718Skan	{
10489132718Skan	  /* Calculate index to next subword.  */
10490132718Skan	  ++j;
10491132718Skan	  if (j == nregs)
10492132718Skan	    j = 0;
10493132718Skan
10494132718Skan	  /* If compiler already emited move of first word by
10495132718Skan	     store with update, no need to do anything.  */
10496132718Skan	  if (j == 0 && used_update)
10497132718Skan	    continue;
10498132718Skan
10499132718Skan	  emit_insn (gen_rtx_SET (VOIDmode,
10500132718Skan				  simplify_gen_subreg (reg_mode, dst, mode,
10501132718Skan						       j * reg_mode_size),
10502132718Skan				  simplify_gen_subreg (reg_mode, src, mode,
10503132718Skan						       j * reg_mode_size)));
10504132718Skan	}
10505132718Skan    }
10506132718Skan}
10507132718Skan
1050890075Sobrien
1050990075Sobrien/* This page contains routines that are used to determine what the
1051090075Sobrien   function prologue and epilogue code will do and write them out.  */
1051190075Sobrien
1051290075Sobrien/* Return the first fixed-point register that is required to be
1051390075Sobrien   saved. 32 if none.  */
1051490075Sobrien
1051590075Sobrienint
10516132718Skanfirst_reg_to_save (void)
1051790075Sobrien{
1051890075Sobrien  int first_reg;
1051990075Sobrien
1052090075Sobrien  /* Find lowest numbered live register.  */
1052190075Sobrien  for (first_reg = 13; first_reg <= 31; first_reg++)
1052290075Sobrien    if (regs_ever_live[first_reg]
1052390075Sobrien	&& (! call_used_regs[first_reg]
1052496263Sobrien	    || (first_reg == RS6000_PIC_OFFSET_TABLE_REGNUM
10525117395Skan		&& ((DEFAULT_ABI == ABI_V4 && flag_pic != 0)
1052690075Sobrien		    || (DEFAULT_ABI == ABI_DARWIN && flag_pic)))))
1052790075Sobrien      break;
1052890075Sobrien
1052990075Sobrien#if TARGET_MACHO
10530117395Skan  if (flag_pic
10531117395Skan      && current_function_uses_pic_offset_table
10532117395Skan      && first_reg > RS6000_PIC_OFFSET_TABLE_REGNUM)
1053396263Sobrien    return RS6000_PIC_OFFSET_TABLE_REGNUM;
1053490075Sobrien#endif
1053590075Sobrien
1053690075Sobrien  return first_reg;
1053790075Sobrien}
1053890075Sobrien
1053990075Sobrien/* Similar, for FP regs.  */
1054090075Sobrien
1054190075Sobrienint
10542132718Skanfirst_fp_reg_to_save (void)
1054390075Sobrien{
1054490075Sobrien  int first_reg;
1054590075Sobrien
1054690075Sobrien  /* Find lowest numbered live register.  */
1054790075Sobrien  for (first_reg = 14 + 32; first_reg <= 63; first_reg++)
1054890075Sobrien    if (regs_ever_live[first_reg])
1054990075Sobrien      break;
1055090075Sobrien
1055190075Sobrien  return first_reg;
1055290075Sobrien}
1055390075Sobrien
1055490075Sobrien/* Similar, for AltiVec regs.  */
1055590075Sobrien
1055690075Sobrienstatic int
10557132718Skanfirst_altivec_reg_to_save (void)
1055890075Sobrien{
1055990075Sobrien  int i;
1056090075Sobrien
1056190075Sobrien  /* Stack frame remains as is unless we are in AltiVec ABI.  */
1056290075Sobrien  if (! TARGET_ALTIVEC_ABI)
1056390075Sobrien    return LAST_ALTIVEC_REGNO + 1;
1056490075Sobrien
1056590075Sobrien  /* Find lowest numbered live register.  */
1056690075Sobrien  for (i = FIRST_ALTIVEC_REGNO + 20; i <= LAST_ALTIVEC_REGNO; ++i)
1056790075Sobrien    if (regs_ever_live[i])
1056890075Sobrien      break;
1056990075Sobrien
1057090075Sobrien  return i;
1057190075Sobrien}
1057290075Sobrien
1057390075Sobrien/* Return a 32-bit mask of the AltiVec registers we need to set in
1057490075Sobrien   VRSAVE.  Bit n of the return value is 1 if Vn is live.  The MSB in
1057590075Sobrien   the 32-bit word is 0.  */
1057690075Sobrien
1057790075Sobrienstatic unsigned int
10578132718Skancompute_vrsave_mask (void)
1057990075Sobrien{
1058090075Sobrien  unsigned int i, mask = 0;
1058190075Sobrien
1058290075Sobrien  /* First, find out if we use _any_ altivec registers.  */
1058390075Sobrien  for (i = FIRST_ALTIVEC_REGNO; i <= LAST_ALTIVEC_REGNO; ++i)
1058490075Sobrien    if (regs_ever_live[i])
1058590075Sobrien      mask |= ALTIVEC_REG_BIT (i);
1058690075Sobrien
1058790075Sobrien  if (mask == 0)
1058890075Sobrien    return mask;
1058990075Sobrien
1059090075Sobrien  /* Next, remove the argument registers from the set.  These must
1059190075Sobrien     be in the VRSAVE mask set by the caller, so we don't need to add
1059290075Sobrien     them in again.  More importantly, the mask we compute here is
1059390075Sobrien     used to generate CLOBBERs in the set_vrsave insn, and we do not
1059490075Sobrien     wish the argument registers to die.  */
10595132718Skan  for (i = cfun->args_info.vregno - 1; i >= ALTIVEC_ARG_MIN_REG; --i)
1059690075Sobrien    mask &= ~ALTIVEC_REG_BIT (i);
1059790075Sobrien
1059890075Sobrien  /* Similarly, remove the return value from the set.  */
1059990075Sobrien  {
1060090075Sobrien    bool yes = false;
1060190075Sobrien    diddle_return_value (is_altivec_return_reg, &yes);
1060290075Sobrien    if (yes)
1060390075Sobrien      mask &= ~ALTIVEC_REG_BIT (ALTIVEC_ARG_RETURN);
1060490075Sobrien  }
1060590075Sobrien
1060690075Sobrien  return mask;
1060790075Sobrien}
1060890075Sobrien
1060990075Sobrienstatic void
10610132718Skanis_altivec_return_reg (rtx reg, void *xyes)
1061190075Sobrien{
1061290075Sobrien  bool *yes = (bool *) xyes;
1061390075Sobrien  if (REGNO (reg) == ALTIVEC_ARG_RETURN)
1061490075Sobrien    *yes = true;
1061590075Sobrien}
1061690075Sobrien
1061790075Sobrien
1061890075Sobrien/* Calculate the stack information for the current function.  This is
1061990075Sobrien   complicated by having two separate calling sequences, the AIX calling
1062090075Sobrien   sequence and the V.4 calling sequence.
1062190075Sobrien
1062290075Sobrien   AIX (and Darwin/Mac OS X) stack frames look like:
1062390075Sobrien							  32-bit  64-bit
1062490075Sobrien	SP---->	+---------------------------------------+
1062590075Sobrien		| back chain to caller			| 0	  0
1062690075Sobrien		+---------------------------------------+
1062790075Sobrien		| saved CR				| 4       8 (8-11)
1062890075Sobrien		+---------------------------------------+
1062990075Sobrien		| saved LR				| 8       16
1063090075Sobrien		+---------------------------------------+
1063190075Sobrien		| reserved for compilers		| 12      24
1063290075Sobrien		+---------------------------------------+
1063390075Sobrien		| reserved for binders			| 16      32
1063490075Sobrien		+---------------------------------------+
1063590075Sobrien		| saved TOC pointer			| 20      40
1063690075Sobrien		+---------------------------------------+
1063790075Sobrien		| Parameter save area (P)		| 24      48
1063890075Sobrien		+---------------------------------------+
1063990075Sobrien		| Alloca space (A)			| 24+P    etc.
1064090075Sobrien		+---------------------------------------+
1064190075Sobrien		| Local variable space (L)		| 24+P+A
1064290075Sobrien		+---------------------------------------+
1064390075Sobrien		| Float/int conversion temporary (X)	| 24+P+A+L
1064490075Sobrien		+---------------------------------------+
1064590075Sobrien		| Save area for AltiVec registers (W)	| 24+P+A+L+X
1064690075Sobrien		+---------------------------------------+
1064790075Sobrien		| AltiVec alignment padding (Y)		| 24+P+A+L+X+W
1064890075Sobrien		+---------------------------------------+
1064990075Sobrien		| Save area for VRSAVE register (Z)	| 24+P+A+L+X+W+Y
1065090075Sobrien		+---------------------------------------+
1065190075Sobrien		| Save area for GP registers (G)	| 24+P+A+X+L+X+W+Y+Z
1065290075Sobrien		+---------------------------------------+
1065390075Sobrien		| Save area for FP registers (F)	| 24+P+A+X+L+X+W+Y+Z+G
1065490075Sobrien		+---------------------------------------+
1065590075Sobrien	old SP->| back chain to caller's caller		|
1065690075Sobrien		+---------------------------------------+
1065790075Sobrien
1065890075Sobrien   The required alignment for AIX configurations is two words (i.e., 8
1065990075Sobrien   or 16 bytes).
1066090075Sobrien
1066190075Sobrien
1066290075Sobrien   V.4 stack frames look like:
1066390075Sobrien
1066490075Sobrien	SP---->	+---------------------------------------+
1066590075Sobrien		| back chain to caller			| 0
1066690075Sobrien		+---------------------------------------+
1066790075Sobrien		| caller's saved LR			| 4
1066890075Sobrien		+---------------------------------------+
1066990075Sobrien		| Parameter save area (P)		| 8
1067090075Sobrien		+---------------------------------------+
1067190075Sobrien		| Alloca space (A)			| 8+P
1067290075Sobrien		+---------------------------------------+
1067390075Sobrien		| Varargs save area (V)			| 8+P+A
1067490075Sobrien		+---------------------------------------+
1067590075Sobrien		| Local variable space (L)		| 8+P+A+V
1067690075Sobrien		+---------------------------------------+
1067790075Sobrien		| Float/int conversion temporary (X)	| 8+P+A+V+L
1067890075Sobrien		+---------------------------------------+
1067990075Sobrien		| Save area for AltiVec registers (W)	| 8+P+A+V+L+X
1068090075Sobrien		+---------------------------------------+
1068190075Sobrien		| AltiVec alignment padding (Y)		| 8+P+A+V+L+X+W
1068290075Sobrien		+---------------------------------------+
1068390075Sobrien		| Save area for VRSAVE register (Z)	| 8+P+A+V+L+X+W+Y
1068490075Sobrien		+---------------------------------------+
10685117395Skan                | SPE: area for 64-bit GP registers     |
10686117395Skan                +---------------------------------------+
10687117395Skan                | SPE alignment padding                 |
10688117395Skan                +---------------------------------------+
1068990075Sobrien		| saved CR (C)				| 8+P+A+V+L+X+W+Y+Z
1069090075Sobrien		+---------------------------------------+
1069190075Sobrien		| Save area for GP registers (G)	| 8+P+A+V+L+X+W+Y+Z+C
1069290075Sobrien		+---------------------------------------+
1069390075Sobrien		| Save area for FP registers (F)	| 8+P+A+V+L+X+W+Y+Z+C+G
1069490075Sobrien		+---------------------------------------+
1069590075Sobrien	old SP->| back chain to caller's caller		|
1069690075Sobrien		+---------------------------------------+
1069790075Sobrien
1069890075Sobrien   The required alignment for V.4 is 16 bytes, or 8 bytes if -meabi is
1069990075Sobrien   given.  (But note below and in sysv4.h that we require only 8 and
1070090075Sobrien   may round up the size of our stack frame anyways.  The historical
1070190075Sobrien   reason is early versions of powerpc-linux which didn't properly
1070290075Sobrien   align the stack at program startup.  A happy side-effect is that
1070390075Sobrien   -mno-eabi libraries can be used with -meabi programs.)
1070490075Sobrien
10705132718Skan   The EABI configuration defaults to the V.4 layout.  However,
1070690075Sobrien   the stack alignment requirements may differ.  If -mno-eabi is not
1070790075Sobrien   given, the required stack alignment is 8 bytes; if -mno-eabi is
1070890075Sobrien   given, the required alignment is 16 bytes.  (But see V.4 comment
1070990075Sobrien   above.)  */
1071090075Sobrien
1071190075Sobrien#ifndef ABI_STACK_BOUNDARY
1071290075Sobrien#define ABI_STACK_BOUNDARY STACK_BOUNDARY
1071390075Sobrien#endif
1071490075Sobrien
10715132718Skanstatic rs6000_stack_t *
10716132718Skanrs6000_stack_info (void)
1071790075Sobrien{
1071890075Sobrien  static rs6000_stack_t info, zero_info;
1071990075Sobrien  rs6000_stack_t *info_ptr = &info;
10720132718Skan  int reg_size = TARGET_32BIT ? 4 : 8;
1072190075Sobrien  int ehrd_size;
10722132718Skan  HOST_WIDE_INT non_fixed_size;
1072390075Sobrien
1072490075Sobrien  /* Zero all fields portably.  */
1072590075Sobrien  info = zero_info;
1072690075Sobrien
10727132718Skan  if (TARGET_SPE)
10728132718Skan    {
10729132718Skan      /* Cache value so we don't rescan instruction chain over and over.  */
10730132718Skan      if (cfun->machine->insn_chain_scanned_p == 0)
10731132718Skan	{
10732132718Skan	  cfun->machine->insn_chain_scanned_p = 1;
10733132718Skan	  info_ptr->spe_64bit_regs_used = (int) spe_func_has_64bit_regs_p ();
10734132718Skan	}
10735132718Skan    }
10736132718Skan
1073790075Sobrien  /* Select which calling sequence.  */
10738132718Skan  info_ptr->abi = DEFAULT_ABI;
1073990075Sobrien
1074090075Sobrien  /* Calculate which registers need to be saved & save area size.  */
1074190075Sobrien  info_ptr->first_gp_reg_save = first_reg_to_save ();
1074296263Sobrien  /* Assume that we will have to save RS6000_PIC_OFFSET_TABLE_REGNUM,
1074390075Sobrien     even if it currently looks like we won't.  */
1074490075Sobrien  if (((TARGET_TOC && TARGET_MINIMAL_TOC)
10745132718Skan       || (flag_pic == 1 && DEFAULT_ABI == ABI_V4)
10746132718Skan       || (flag_pic && DEFAULT_ABI == ABI_DARWIN))
1074796263Sobrien      && info_ptr->first_gp_reg_save > RS6000_PIC_OFFSET_TABLE_REGNUM)
1074896263Sobrien    info_ptr->gp_size = reg_size * (32 - RS6000_PIC_OFFSET_TABLE_REGNUM);
1074990075Sobrien  else
1075090075Sobrien    info_ptr->gp_size = reg_size * (32 - info_ptr->first_gp_reg_save);
1075190075Sobrien
10752117395Skan  /* For the SPE, we have an additional upper 32-bits on each GPR.
10753117395Skan     Ideally we should save the entire 64-bits only when the upper
10754117395Skan     half is used in SIMD instructions.  Since we only record
10755117395Skan     registers live (not the size they are used in), this proves
10756117395Skan     difficult because we'd have to traverse the instruction chain at
10757117395Skan     the right time, taking reload into account.  This is a real pain,
10758132718Skan     so we opt to save the GPRs in 64-bits always if but one register
10759132718Skan     gets used in 64-bits.  Otherwise, all the registers in the frame
10760132718Skan     get saved in 32-bits.
10761117395Skan
10762132718Skan     So... since when we save all GPRs (except the SP) in 64-bits, the
10763117395Skan     traditional GP save area will be empty.  */
10764132718Skan  if (TARGET_SPE_ABI && info_ptr->spe_64bit_regs_used != 0)
10765117395Skan    info_ptr->gp_size = 0;
10766117395Skan
1076790075Sobrien  info_ptr->first_fp_reg_save = first_fp_reg_to_save ();
1076890075Sobrien  info_ptr->fp_size = 8 * (64 - info_ptr->first_fp_reg_save);
1076990075Sobrien
1077090075Sobrien  info_ptr->first_altivec_reg_save = first_altivec_reg_to_save ();
1077190075Sobrien  info_ptr->altivec_size = 16 * (LAST_ALTIVEC_REGNO + 1
1077290075Sobrien				 - info_ptr->first_altivec_reg_save);
1077390075Sobrien
1077490075Sobrien  /* Does this function call anything?  */
1077590075Sobrien  info_ptr->calls_p = (! current_function_is_leaf
1077690075Sobrien		       || cfun->machine->ra_needs_full_frame);
1077790075Sobrien
1077890075Sobrien  /* Determine if we need to save the link register.  */
1077990075Sobrien  if (rs6000_ra_ever_killed ()
10780132718Skan      || (DEFAULT_ABI == ABI_AIX
10781132718Skan	  && current_function_profile
10782132718Skan	  && !TARGET_PROFILE_KERNEL)
1078390075Sobrien#ifdef TARGET_RELOCATABLE
1078490075Sobrien      || (TARGET_RELOCATABLE && (get_pool_size () != 0))
1078590075Sobrien#endif
1078690075Sobrien      || (info_ptr->first_fp_reg_save != 64
1078790075Sobrien	  && !FP_SAVE_INLINE (info_ptr->first_fp_reg_save))
1078890075Sobrien      || info_ptr->first_altivec_reg_save <= LAST_ALTIVEC_REGNO
10789132718Skan      || (DEFAULT_ABI == ABI_V4 && current_function_calls_alloca)
1079090075Sobrien      || (DEFAULT_ABI == ABI_DARWIN
1079190075Sobrien	  && flag_pic
1079290075Sobrien	  && current_function_uses_pic_offset_table)
1079390075Sobrien      || info_ptr->calls_p)
1079490075Sobrien    {
1079590075Sobrien      info_ptr->lr_save_p = 1;
1079690075Sobrien      regs_ever_live[LINK_REGISTER_REGNUM] = 1;
1079790075Sobrien    }
1079890075Sobrien
1079990075Sobrien  /* Determine if we need to save the condition code registers.  */
1080090075Sobrien  if (regs_ever_live[CR2_REGNO]
1080190075Sobrien      || regs_ever_live[CR3_REGNO]
1080290075Sobrien      || regs_ever_live[CR4_REGNO])
1080390075Sobrien    {
1080490075Sobrien      info_ptr->cr_save_p = 1;
10805132718Skan      if (DEFAULT_ABI == ABI_V4)
1080690075Sobrien	info_ptr->cr_size = reg_size;
1080790075Sobrien    }
1080890075Sobrien
1080990075Sobrien  /* If the current function calls __builtin_eh_return, then we need
1081090075Sobrien     to allocate stack space for registers that will hold data for
1081190075Sobrien     the exception handler.  */
1081290075Sobrien  if (current_function_calls_eh_return)
1081390075Sobrien    {
1081490075Sobrien      unsigned int i;
1081590075Sobrien      for (i = 0; EH_RETURN_DATA_REGNO (i) != INVALID_REGNUM; ++i)
1081690075Sobrien	continue;
10817117395Skan
10818117395Skan      /* SPE saves EH registers in 64-bits.  */
10819132718Skan      ehrd_size = i * (TARGET_SPE_ABI
10820132718Skan		       && info_ptr->spe_64bit_regs_used != 0
10821132718Skan		       ? UNITS_PER_SPE_WORD : UNITS_PER_WORD);
1082290075Sobrien    }
1082390075Sobrien  else
1082490075Sobrien    ehrd_size = 0;
1082590075Sobrien
1082690075Sobrien  /* Determine various sizes.  */
1082790075Sobrien  info_ptr->reg_size     = reg_size;
1082890075Sobrien  info_ptr->fixed_size   = RS6000_SAVE_AREA;
1082990075Sobrien  info_ptr->varargs_size = RS6000_VARARGS_AREA;
1083090075Sobrien  info_ptr->vars_size    = RS6000_ALIGN (get_frame_size (), 8);
1083190075Sobrien  info_ptr->parm_size    = RS6000_ALIGN (current_function_outgoing_args_size,
10832132718Skan					 TARGET_ALTIVEC ? 16 : 8);
1083390075Sobrien
10834132718Skan  if (TARGET_SPE_ABI && info_ptr->spe_64bit_regs_used != 0)
10835117395Skan    info_ptr->spe_gp_size = 8 * (32 - info_ptr->first_gp_reg_save);
10836117395Skan  else
10837117395Skan    info_ptr->spe_gp_size = 0;
10838117395Skan
10839132718Skan  if (TARGET_ALTIVEC_ABI)
10840132718Skan    info_ptr->vrsave_mask = compute_vrsave_mask ();
1084190075Sobrien  else
10842132718Skan    info_ptr->vrsave_mask = 0;
1084390075Sobrien
10844132718Skan  if (TARGET_ALTIVEC_VRSAVE && info_ptr->vrsave_mask)
10845132718Skan    info_ptr->vrsave_size  = 4;
10846132718Skan  else
10847132718Skan    info_ptr->vrsave_size  = 0;
10848132718Skan
1084990075Sobrien  /* Calculate the offsets.  */
10850132718Skan  switch (DEFAULT_ABI)
1085190075Sobrien    {
1085290075Sobrien    case ABI_NONE:
1085390075Sobrien    default:
1085490075Sobrien      abort ();
1085590075Sobrien
1085690075Sobrien    case ABI_AIX:
1085790075Sobrien    case ABI_DARWIN:
1085890075Sobrien      info_ptr->fp_save_offset   = - info_ptr->fp_size;
1085990075Sobrien      info_ptr->gp_save_offset   = info_ptr->fp_save_offset - info_ptr->gp_size;
1086090075Sobrien
1086190075Sobrien      if (TARGET_ALTIVEC_ABI)
1086290075Sobrien	{
1086390075Sobrien	  info_ptr->vrsave_save_offset
1086490075Sobrien	    = info_ptr->gp_save_offset - info_ptr->vrsave_size;
1086590075Sobrien
1086690075Sobrien	  /* Align stack so vector save area is on a quadword boundary.  */
1086790075Sobrien	  if (info_ptr->altivec_size != 0)
1086890075Sobrien	    info_ptr->altivec_padding_size
1086990075Sobrien	      = 16 - (-info_ptr->vrsave_save_offset % 16);
1087090075Sobrien	  else
1087190075Sobrien	    info_ptr->altivec_padding_size = 0;
1087290075Sobrien
1087390075Sobrien	  info_ptr->altivec_save_offset
1087490075Sobrien	    = info_ptr->vrsave_save_offset
1087590075Sobrien	    - info_ptr->altivec_padding_size
1087690075Sobrien	    - info_ptr->altivec_size;
1087790075Sobrien
1087890075Sobrien	  /* Adjust for AltiVec case.  */
1087990075Sobrien	  info_ptr->ehrd_offset = info_ptr->altivec_save_offset - ehrd_size;
1088090075Sobrien	}
1088190075Sobrien      else
1088290075Sobrien	info_ptr->ehrd_offset      = info_ptr->gp_save_offset - ehrd_size;
1088390075Sobrien      info_ptr->cr_save_offset   = reg_size; /* first word when 64-bit.  */
1088490075Sobrien      info_ptr->lr_save_offset   = 2*reg_size;
1088590075Sobrien      break;
1088690075Sobrien
1088790075Sobrien    case ABI_V4:
1088890075Sobrien      info_ptr->fp_save_offset   = - info_ptr->fp_size;
1088990075Sobrien      info_ptr->gp_save_offset   = info_ptr->fp_save_offset - info_ptr->gp_size;
1089090075Sobrien      info_ptr->cr_save_offset   = info_ptr->gp_save_offset - info_ptr->cr_size;
1089190075Sobrien
10892132718Skan      if (TARGET_SPE_ABI && info_ptr->spe_64bit_regs_used != 0)
10893117395Skan      {
10894117395Skan        /* Align stack so SPE GPR save area is aligned on a
10895117395Skan           double-word boundary.  */
10896117395Skan        if (info_ptr->spe_gp_size != 0)
10897117395Skan          info_ptr->spe_padding_size
10898117395Skan            = 8 - (-info_ptr->cr_save_offset % 8);
10899117395Skan        else
10900117395Skan          info_ptr->spe_padding_size = 0;
10901117395Skan
10902117395Skan        info_ptr->spe_gp_save_offset
10903117395Skan          = info_ptr->cr_save_offset
10904117395Skan          - info_ptr->spe_padding_size
10905117395Skan          - info_ptr->spe_gp_size;
10906117395Skan
10907117395Skan        /* Adjust for SPE case.  */
10908117395Skan        info_ptr->toc_save_offset
10909117395Skan          = info_ptr->spe_gp_save_offset - info_ptr->toc_size;
10910117395Skan      }
10911117395Skan      else if (TARGET_ALTIVEC_ABI)
1091290075Sobrien	{
1091390075Sobrien	  info_ptr->vrsave_save_offset
1091490075Sobrien	    = info_ptr->cr_save_offset - info_ptr->vrsave_size;
1091590075Sobrien
1091690075Sobrien	  /* Align stack so vector save area is on a quadword boundary.  */
1091790075Sobrien	  if (info_ptr->altivec_size != 0)
1091890075Sobrien	    info_ptr->altivec_padding_size
1091990075Sobrien	      = 16 - (-info_ptr->vrsave_save_offset % 16);
1092090075Sobrien	  else
1092190075Sobrien	    info_ptr->altivec_padding_size = 0;
1092290075Sobrien
1092390075Sobrien	  info_ptr->altivec_save_offset
1092490075Sobrien	    = info_ptr->vrsave_save_offset
1092590075Sobrien	    - info_ptr->altivec_padding_size
1092690075Sobrien	    - info_ptr->altivec_size;
1092790075Sobrien
1092890075Sobrien	  /* Adjust for AltiVec case.  */
1092990075Sobrien	  info_ptr->toc_save_offset
1093090075Sobrien	    = info_ptr->altivec_save_offset - info_ptr->toc_size;
1093190075Sobrien	}
1093290075Sobrien      else
1093390075Sobrien	info_ptr->toc_save_offset  = info_ptr->cr_save_offset - info_ptr->toc_size;
1093490075Sobrien      info_ptr->ehrd_offset      = info_ptr->toc_save_offset - ehrd_size;
1093590075Sobrien      info_ptr->lr_save_offset   = reg_size;
1093690075Sobrien      break;
1093790075Sobrien    }
1093890075Sobrien
1093990075Sobrien  info_ptr->save_size    = RS6000_ALIGN (info_ptr->fp_size
1094090075Sobrien					 + info_ptr->gp_size
1094190075Sobrien					 + info_ptr->altivec_size
1094290075Sobrien					 + info_ptr->altivec_padding_size
10943117395Skan					 + info_ptr->spe_gp_size
10944117395Skan					 + info_ptr->spe_padding_size
1094590075Sobrien					 + ehrd_size
1094690075Sobrien					 + info_ptr->cr_size
1094790075Sobrien					 + info_ptr->lr_size
10948132718Skan					 + info_ptr->vrsave_size
1094990075Sobrien					 + info_ptr->toc_size,
1095090075Sobrien					 (TARGET_ALTIVEC_ABI || ABI_DARWIN)
1095190075Sobrien					 ? 16 : 8);
1095290075Sobrien
10953132718Skan  non_fixed_size	 = (info_ptr->vars_size
1095490075Sobrien			    + info_ptr->parm_size
1095590075Sobrien			    + info_ptr->save_size
10956132718Skan			    + info_ptr->varargs_size);
1095790075Sobrien
10958132718Skan  info_ptr->total_size = RS6000_ALIGN (non_fixed_size + info_ptr->fixed_size,
10959132718Skan				       ABI_STACK_BOUNDARY / BITS_PER_UNIT);
1096090075Sobrien
1096190075Sobrien  /* Determine if we need to allocate any stack frame:
1096290075Sobrien
1096390075Sobrien     For AIX we need to push the stack if a frame pointer is needed
1096490075Sobrien     (because the stack might be dynamically adjusted), if we are
1096590075Sobrien     debugging, if we make calls, or if the sum of fp_save, gp_save,
1096690075Sobrien     and local variables are more than the space needed to save all
1096790075Sobrien     non-volatile registers: 32-bit: 18*8 + 19*4 = 220 or 64-bit: 18*8
1096890075Sobrien     + 18*8 = 288 (GPR13 reserved).
1096990075Sobrien
1097090075Sobrien     For V.4 we don't have the stack cushion that AIX uses, but assume
1097190075Sobrien     that the debugger can handle stackless frames.  */
1097290075Sobrien
1097390075Sobrien  if (info_ptr->calls_p)
1097490075Sobrien    info_ptr->push_p = 1;
1097590075Sobrien
10976132718Skan  else if (DEFAULT_ABI == ABI_V4)
10977132718Skan    info_ptr->push_p = non_fixed_size != 0;
1097890075Sobrien
10979132718Skan  else if (frame_pointer_needed)
10980132718Skan    info_ptr->push_p = 1;
10981132718Skan
10982132718Skan  else if (TARGET_XCOFF && write_symbols != NO_DEBUG)
10983132718Skan    info_ptr->push_p = 1;
10984132718Skan
1098590075Sobrien  else
10986132718Skan    info_ptr->push_p = non_fixed_size > (TARGET_32BIT ? 220 : 288);
1098790075Sobrien
1098890075Sobrien  /* Zero offsets if we're not saving those registers.  */
1098990075Sobrien  if (info_ptr->fp_size == 0)
1099090075Sobrien    info_ptr->fp_save_offset = 0;
1099190075Sobrien
1099290075Sobrien  if (info_ptr->gp_size == 0)
1099390075Sobrien    info_ptr->gp_save_offset = 0;
1099490075Sobrien
1099590075Sobrien  if (! TARGET_ALTIVEC_ABI || info_ptr->altivec_size == 0)
1099690075Sobrien    info_ptr->altivec_save_offset = 0;
1099790075Sobrien
1099890075Sobrien  if (! TARGET_ALTIVEC_ABI || info_ptr->vrsave_mask == 0)
1099990075Sobrien    info_ptr->vrsave_save_offset = 0;
1100090075Sobrien
11001132718Skan  if (! TARGET_SPE_ABI
11002132718Skan      || info_ptr->spe_64bit_regs_used == 0
11003132718Skan      || info_ptr->spe_gp_size == 0)
11004117395Skan    info_ptr->spe_gp_save_offset = 0;
11005117395Skan
1100690075Sobrien  if (! info_ptr->lr_save_p)
1100790075Sobrien    info_ptr->lr_save_offset = 0;
1100890075Sobrien
1100990075Sobrien  if (! info_ptr->cr_save_p)
1101090075Sobrien    info_ptr->cr_save_offset = 0;
1101190075Sobrien
1101290075Sobrien  if (! info_ptr->toc_save_p)
1101390075Sobrien    info_ptr->toc_save_offset = 0;
1101490075Sobrien
1101590075Sobrien  return info_ptr;
1101690075Sobrien}
1101790075Sobrien
11018132718Skan/* Return true if the current function uses any GPRs in 64-bit SIMD
11019132718Skan   mode.  */
11020132718Skan
11021132718Skanstatic bool
11022132718Skanspe_func_has_64bit_regs_p (void)
1102390075Sobrien{
11024132718Skan  rtx insns, insn;
11025132718Skan
11026132718Skan  /* Functions that save and restore all the call-saved registers will
11027132718Skan     need to save/restore the registers in 64-bits.  */
11028132718Skan  if (current_function_calls_eh_return
11029132718Skan      || current_function_calls_setjmp
11030132718Skan      || current_function_has_nonlocal_goto)
11031132718Skan    return true;
11032132718Skan
11033132718Skan  insns = get_insns ();
11034132718Skan
11035132718Skan  for (insn = NEXT_INSN (insns); insn != NULL_RTX; insn = NEXT_INSN (insn))
11036132718Skan    {
11037132718Skan      if (INSN_P (insn))
11038132718Skan	{
11039132718Skan	  rtx i;
11040132718Skan
11041132718Skan	  i = PATTERN (insn);
11042132718Skan	  if (GET_CODE (i) == SET
11043132718Skan	      && SPE_VECTOR_MODE (GET_MODE (SET_SRC (i))))
11044132718Skan	    return true;
11045132718Skan	}
11046132718Skan    }
11047132718Skan
11048132718Skan  return false;
11049132718Skan}
11050132718Skan
11051132718Skanstatic void
11052132718Skandebug_stack_info (rs6000_stack_t *info)
11053132718Skan{
1105490075Sobrien  const char *abi_string;
1105590075Sobrien
1105690075Sobrien  if (! info)
1105790075Sobrien    info = rs6000_stack_info ();
1105890075Sobrien
1105990075Sobrien  fprintf (stderr, "\nStack information for function %s:\n",
1106090075Sobrien	   ((current_function_decl && DECL_NAME (current_function_decl))
1106190075Sobrien	    ? IDENTIFIER_POINTER (DECL_NAME (current_function_decl))
1106290075Sobrien	    : "<unknown>"));
1106390075Sobrien
1106490075Sobrien  switch (info->abi)
1106590075Sobrien    {
1106690075Sobrien    default:		 abi_string = "Unknown";	break;
1106790075Sobrien    case ABI_NONE:	 abi_string = "NONE";		break;
11068132718Skan    case ABI_AIX:	 abi_string = "AIX";		break;
1106990075Sobrien    case ABI_DARWIN:	 abi_string = "Darwin";		break;
1107090075Sobrien    case ABI_V4:	 abi_string = "V.4";		break;
1107190075Sobrien    }
1107290075Sobrien
1107390075Sobrien  fprintf (stderr, "\tABI                 = %5s\n", abi_string);
1107490075Sobrien
1107590075Sobrien  if (TARGET_ALTIVEC_ABI)
1107690075Sobrien    fprintf (stderr, "\tALTIVEC ABI extensions enabled.\n");
1107790075Sobrien
11078117395Skan  if (TARGET_SPE_ABI)
11079117395Skan    fprintf (stderr, "\tSPE ABI extensions enabled.\n");
11080117395Skan
1108190075Sobrien  if (info->first_gp_reg_save != 32)
1108290075Sobrien    fprintf (stderr, "\tfirst_gp_reg_save   = %5d\n", info->first_gp_reg_save);
1108390075Sobrien
1108490075Sobrien  if (info->first_fp_reg_save != 64)
1108590075Sobrien    fprintf (stderr, "\tfirst_fp_reg_save   = %5d\n", info->first_fp_reg_save);
1108690075Sobrien
1108790075Sobrien  if (info->first_altivec_reg_save <= LAST_ALTIVEC_REGNO)
1108890075Sobrien    fprintf (stderr, "\tfirst_altivec_reg_save = %5d\n",
1108990075Sobrien	     info->first_altivec_reg_save);
1109090075Sobrien
1109190075Sobrien  if (info->lr_save_p)
1109290075Sobrien    fprintf (stderr, "\tlr_save_p           = %5d\n", info->lr_save_p);
1109390075Sobrien
1109490075Sobrien  if (info->cr_save_p)
1109590075Sobrien    fprintf (stderr, "\tcr_save_p           = %5d\n", info->cr_save_p);
1109690075Sobrien
1109790075Sobrien  if (info->toc_save_p)
1109890075Sobrien    fprintf (stderr, "\ttoc_save_p          = %5d\n", info->toc_save_p);
1109990075Sobrien
1110090075Sobrien  if (info->vrsave_mask)
1110190075Sobrien    fprintf (stderr, "\tvrsave_mask         = 0x%x\n", info->vrsave_mask);
1110290075Sobrien
1110390075Sobrien  if (info->push_p)
1110490075Sobrien    fprintf (stderr, "\tpush_p              = %5d\n", info->push_p);
1110590075Sobrien
1110690075Sobrien  if (info->calls_p)
1110790075Sobrien    fprintf (stderr, "\tcalls_p             = %5d\n", info->calls_p);
1110890075Sobrien
1110990075Sobrien  if (info->gp_save_offset)
1111090075Sobrien    fprintf (stderr, "\tgp_save_offset      = %5d\n", info->gp_save_offset);
1111190075Sobrien
1111290075Sobrien  if (info->fp_save_offset)
1111390075Sobrien    fprintf (stderr, "\tfp_save_offset      = %5d\n", info->fp_save_offset);
1111490075Sobrien
1111590075Sobrien  if (info->altivec_save_offset)
1111690075Sobrien    fprintf (stderr, "\taltivec_save_offset = %5d\n",
1111790075Sobrien	     info->altivec_save_offset);
1111890075Sobrien
11119117395Skan  if (info->spe_gp_save_offset)
11120117395Skan    fprintf (stderr, "\tspe_gp_save_offset  = %5d\n",
11121117395Skan	     info->spe_gp_save_offset);
11122117395Skan
1112390075Sobrien  if (info->vrsave_save_offset)
1112490075Sobrien    fprintf (stderr, "\tvrsave_save_offset  = %5d\n",
1112590075Sobrien	     info->vrsave_save_offset);
1112690075Sobrien
1112790075Sobrien  if (info->lr_save_offset)
1112890075Sobrien    fprintf (stderr, "\tlr_save_offset      = %5d\n", info->lr_save_offset);
1112990075Sobrien
1113090075Sobrien  if (info->cr_save_offset)
1113190075Sobrien    fprintf (stderr, "\tcr_save_offset      = %5d\n", info->cr_save_offset);
1113290075Sobrien
1113390075Sobrien  if (info->toc_save_offset)
1113490075Sobrien    fprintf (stderr, "\ttoc_save_offset     = %5d\n", info->toc_save_offset);
1113590075Sobrien
1113690075Sobrien  if (info->varargs_save_offset)
1113790075Sobrien    fprintf (stderr, "\tvarargs_save_offset = %5d\n", info->varargs_save_offset);
1113890075Sobrien
1113990075Sobrien  if (info->total_size)
11140132718Skan    fprintf (stderr, "\ttotal_size          = "HOST_WIDE_INT_PRINT_DEC"\n",
11141132718Skan	     info->total_size);
1114290075Sobrien
1114390075Sobrien  if (info->varargs_size)
1114490075Sobrien    fprintf (stderr, "\tvarargs_size        = %5d\n", info->varargs_size);
1114590075Sobrien
1114690075Sobrien  if (info->vars_size)
11147132718Skan    fprintf (stderr, "\tvars_size           = "HOST_WIDE_INT_PRINT_DEC"\n",
11148132718Skan	     info->vars_size);
1114990075Sobrien
1115090075Sobrien  if (info->parm_size)
1115190075Sobrien    fprintf (stderr, "\tparm_size           = %5d\n", info->parm_size);
1115290075Sobrien
1115390075Sobrien  if (info->fixed_size)
1115490075Sobrien    fprintf (stderr, "\tfixed_size          = %5d\n", info->fixed_size);
1115590075Sobrien
1115690075Sobrien  if (info->gp_size)
1115790075Sobrien    fprintf (stderr, "\tgp_size             = %5d\n", info->gp_size);
1115890075Sobrien
11159117395Skan  if (info->spe_gp_size)
11160117395Skan    fprintf (stderr, "\tspe_gp_size         = %5d\n", info->spe_gp_size);
11161117395Skan
1116290075Sobrien  if (info->fp_size)
1116390075Sobrien    fprintf (stderr, "\tfp_size             = %5d\n", info->fp_size);
1116490075Sobrien
1116590075Sobrien  if (info->altivec_size)
1116690075Sobrien    fprintf (stderr, "\taltivec_size        = %5d\n", info->altivec_size);
1116790075Sobrien
1116890075Sobrien  if (info->vrsave_size)
1116990075Sobrien    fprintf (stderr, "\tvrsave_size         = %5d\n", info->vrsave_size);
1117090075Sobrien
1117190075Sobrien  if (info->altivec_padding_size)
1117290075Sobrien    fprintf (stderr, "\taltivec_padding_size= %5d\n",
1117390075Sobrien	     info->altivec_padding_size);
1117490075Sobrien
11175117395Skan  if (info->spe_padding_size)
11176117395Skan    fprintf (stderr, "\tspe_padding_size    = %5d\n",
11177117395Skan	     info->spe_padding_size);
11178117395Skan
1117990075Sobrien  if (info->lr_size)
1118090075Sobrien    fprintf (stderr, "\tlr_size             = %5d\n", info->lr_size);
1118190075Sobrien
1118290075Sobrien  if (info->cr_size)
1118390075Sobrien    fprintf (stderr, "\tcr_size             = %5d\n", info->cr_size);
1118490075Sobrien
1118590075Sobrien  if (info->toc_size)
1118690075Sobrien    fprintf (stderr, "\ttoc_size            = %5d\n", info->toc_size);
1118790075Sobrien
1118890075Sobrien  if (info->save_size)
1118990075Sobrien    fprintf (stderr, "\tsave_size           = %5d\n", info->save_size);
1119090075Sobrien
1119190075Sobrien  if (info->reg_size != 4)
1119290075Sobrien    fprintf (stderr, "\treg_size            = %5d\n", info->reg_size);
1119390075Sobrien
1119490075Sobrien  fprintf (stderr, "\n");
1119590075Sobrien}
1119690075Sobrien
1119790075Sobrienrtx
11198132718Skanrs6000_return_addr (int count, rtx frame)
1119990075Sobrien{
1120090075Sobrien  /* Currently we don't optimize very well between prolog and body
1120190075Sobrien     code and for PIC code the code can be actually quite bad, so
1120290075Sobrien     don't try to be too clever here.  */
11203132718Skan  if (count != 0 || (DEFAULT_ABI != ABI_AIX && flag_pic))
1120490075Sobrien    {
1120590075Sobrien      cfun->machine->ra_needs_full_frame = 1;
1120690075Sobrien
1120790075Sobrien      return
1120890075Sobrien	gen_rtx_MEM
1120990075Sobrien	  (Pmode,
1121090075Sobrien	   memory_address
1121190075Sobrien	   (Pmode,
1121290075Sobrien	    plus_constant (copy_to_reg
1121390075Sobrien			   (gen_rtx_MEM (Pmode,
1121490075Sobrien					 memory_address (Pmode, frame))),
1121590075Sobrien			   RETURN_ADDRESS_OFFSET)));
1121690075Sobrien    }
1121790075Sobrien
11218132718Skan  cfun->machine->ra_need_lr = 1;
1121990075Sobrien  return get_hard_reg_initial_val (Pmode, LINK_REGISTER_REGNUM);
1122090075Sobrien}
1122190075Sobrien
11222117395Skan/* Say whether a function is a candidate for sibcall handling or not.
11223117395Skan   We do not allow indirect calls to be optimized into sibling calls.
11224117395Skan   Also, we can't do it if there are any vector parameters; there's
11225117395Skan   nowhere to put the VRsave code so it works; note that functions with
11226117395Skan   vector parameters are required to have a prototype, so the argument
11227117395Skan   type info must be available here.  (The tail recursion case can work
11228117395Skan   with vector parameters, but there's no way to distinguish here.) */
11229132718Skanstatic bool
11230132718Skanrs6000_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
11231117395Skan{
11232117395Skan  tree type;
11233132718Skan  if (decl)
11234117395Skan    {
11235117395Skan      if (TARGET_ALTIVEC_VRSAVE)
11236117395Skan        {
11237132718Skan	  for (type = TYPE_ARG_TYPES (TREE_TYPE (decl));
11238117395Skan	       type; type = TREE_CHAIN (type))
11239117395Skan	    {
11240117395Skan	      if (TREE_CODE (TREE_VALUE (type)) == VECTOR_TYPE)
11241132718Skan		return false;
11242117395Skan	    }
11243117395Skan        }
11244117395Skan      if (DEFAULT_ABI == ABI_DARWIN
11245132718Skan	  || (*targetm.binds_local_p) (decl))
11246117395Skan	{
11247132718Skan	  tree attr_list = TYPE_ATTRIBUTES (TREE_TYPE (decl));
11248117395Skan
11249117395Skan	  if (!lookup_attribute ("longcall", attr_list)
11250117395Skan	      || lookup_attribute ("shortcall", attr_list))
11251132718Skan	    return true;
11252117395Skan	}
11253117395Skan    }
11254132718Skan  return false;
11255117395Skan}
11256117395Skan
1125790075Sobrienstatic int
11258132718Skanrs6000_ra_ever_killed (void)
1125990075Sobrien{
1126090075Sobrien  rtx top;
11261117395Skan  rtx reg;
11262117395Skan  rtx insn;
1126390075Sobrien
11264132718Skan  if (current_function_is_thunk)
1126590075Sobrien    return 0;
1126690075Sobrien
11267117395Skan  /* regs_ever_live has LR marked as used if any sibcalls are present,
11268117395Skan     but this should not force saving and restoring in the
11269117395Skan     pro/epilogue.  Likewise, reg_set_between_p thinks a sibcall
11270132718Skan     clobbers LR, so that is inappropriate.  */
11271117395Skan
11272117395Skan  /* Also, the prologue can generate a store into LR that
11273117395Skan     doesn't really count, like this:
11274117395Skan
11275117395Skan        move LR->R0
11276117395Skan        bcl to set PIC register
11277117395Skan        move LR->R31
11278117395Skan        move R0->LR
11279117395Skan
11280117395Skan     When we're called from the epilogue, we need to avoid counting
11281117395Skan     this as a store.  */
11282117395Skan
1128390075Sobrien  push_topmost_sequence ();
1128490075Sobrien  top = get_insns ();
1128590075Sobrien  pop_topmost_sequence ();
11286117395Skan  reg = gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM);
1128790075Sobrien
11288117395Skan  for (insn = NEXT_INSN (top); insn != NULL_RTX; insn = NEXT_INSN (insn))
11289117395Skan    {
11290117395Skan      if (INSN_P (insn))
11291117395Skan	{
11292117395Skan	  if (FIND_REG_INC_NOTE (insn, reg))
11293117395Skan	    return 1;
11294117395Skan	  else if (GET_CODE (insn) == CALL_INSN
11295117395Skan		   && !SIBLING_CALL_P (insn))
11296117395Skan	    return 1;
11297117395Skan	  else if (set_of (reg, insn) != NULL_RTX
11298117395Skan		   && !prologue_epilogue_contains (insn))
11299117395Skan	    return 1;
11300117395Skan    	}
11301117395Skan    }
11302117395Skan  return 0;
1130390075Sobrien}
1130490075Sobrien
1130590075Sobrien/* Add a REG_MAYBE_DEAD note to the insn.  */
1130690075Sobrienstatic void
11307132718Skanrs6000_maybe_dead (rtx insn)
1130890075Sobrien{
1130990075Sobrien  REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD,
1131090075Sobrien					const0_rtx,
1131190075Sobrien					REG_NOTES (insn));
1131290075Sobrien}
1131390075Sobrien
1131490075Sobrien/* Emit instructions needed to load the TOC register.
1131590075Sobrien   This is only needed when TARGET_TOC, TARGET_MINIMAL_TOC, and there is
1131690075Sobrien   a constant pool; or for SVR4 -fpic.  */
1131790075Sobrien
1131890075Sobrienvoid
11319132718Skanrs6000_emit_load_toc_table (int fromprolog)
1132090075Sobrien{
11321117395Skan  rtx dest, insn;
1132296263Sobrien  dest = gen_rtx_REG (Pmode, RS6000_PIC_OFFSET_TABLE_REGNUM);
1132390075Sobrien
11324103445Skan  if (TARGET_ELF && DEFAULT_ABI == ABI_V4 && flag_pic == 1)
1132590075Sobrien    {
11326103445Skan      rtx temp = (fromprolog
11327103445Skan		  ? gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM)
11328103445Skan		  : gen_reg_rtx (Pmode));
11329117395Skan      insn = emit_insn (gen_load_toc_v4_pic_si (temp));
11330117395Skan      if (fromprolog)
11331117395Skan	rs6000_maybe_dead (insn);
11332117395Skan      insn = emit_move_insn (dest, temp);
11333117395Skan      if (fromprolog)
11334117395Skan	rs6000_maybe_dead (insn);
11335103445Skan    }
11336103445Skan  else if (TARGET_ELF && DEFAULT_ABI != ABI_AIX && flag_pic == 2)
11337103445Skan    {
11338103445Skan      char buf[30];
11339103445Skan      rtx tempLR = (fromprolog
11340103445Skan		    ? gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM)
11341103445Skan		    : gen_reg_rtx (Pmode));
11342103445Skan      rtx temp0 = (fromprolog
11343103445Skan		   ? gen_rtx_REG (Pmode, 0)
11344103445Skan		   : gen_reg_rtx (Pmode));
11345103445Skan      rtx symF;
11346103445Skan
11347103445Skan      /* possibly create the toc section */
11348103445Skan      if (! toc_initialized)
1134990075Sobrien	{
11350103445Skan	  toc_section ();
11351103445Skan	  function_section (current_function_decl);
1135290075Sobrien	}
1135390075Sobrien
11354103445Skan      if (fromprolog)
11355103445Skan	{
11356103445Skan	  rtx symL;
1135790075Sobrien
11358103445Skan	  ASM_GENERATE_INTERNAL_LABEL (buf, "LCF", rs6000_pic_labelno);
11359103445Skan	  symF = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
1136090075Sobrien
11361103445Skan	  ASM_GENERATE_INTERNAL_LABEL (buf, "LCL", rs6000_pic_labelno);
11362103445Skan	  symL = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
1136390075Sobrien
11364103445Skan	  rs6000_maybe_dead (emit_insn (gen_load_toc_v4_PIC_1 (tempLR,
11365103445Skan							       symF)));
11366103445Skan	  rs6000_maybe_dead (emit_move_insn (dest, tempLR));
11367103445Skan	  rs6000_maybe_dead (emit_insn (gen_load_toc_v4_PIC_2 (temp0, dest,
11368103445Skan							       symL,
11369103445Skan							       symF)));
11370103445Skan	}
11371103445Skan      else
11372103445Skan	{
11373103445Skan	  rtx tocsym;
11374103445Skan	  static int reload_toc_labelno = 0;
1137590075Sobrien
11376103445Skan	  tocsym = gen_rtx_SYMBOL_REF (Pmode, toc_label_name);
1137790075Sobrien
11378103445Skan	  ASM_GENERATE_INTERNAL_LABEL (buf, "LCG", reload_toc_labelno++);
11379103445Skan	  symF = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
11380103445Skan
11381117395Skan	  emit_insn (gen_load_toc_v4_PIC_1b (tempLR, symF, tocsym));
11382117395Skan	  emit_move_insn (dest, tempLR);
11383117395Skan	  emit_move_insn (temp0, gen_rtx_MEM (Pmode, dest));
1138490075Sobrien	}
11385117395Skan      insn = emit_insn (gen_addsi3 (dest, temp0, dest));
11386117395Skan      if (fromprolog)
11387117395Skan	rs6000_maybe_dead (insn);
1138890075Sobrien    }
11389103445Skan  else if (TARGET_ELF && !TARGET_AIX && flag_pic == 0 && TARGET_MINIMAL_TOC)
1139090075Sobrien    {
11391103445Skan      /* This is for AIX code running in non-PIC ELF32.  */
11392103445Skan      char buf[30];
11393103445Skan      rtx realsym;
11394103445Skan      ASM_GENERATE_INTERNAL_LABEL (buf, "LCTOC", 1);
11395103445Skan      realsym = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
11396103445Skan
11397117395Skan      insn = emit_insn (gen_elf_high (dest, realsym));
11398117395Skan      if (fromprolog)
11399117395Skan	rs6000_maybe_dead (insn);
11400117395Skan      insn = emit_insn (gen_elf_low (dest, dest, realsym));
11401117395Skan      if (fromprolog)
11402117395Skan	rs6000_maybe_dead (insn);
11403103445Skan    }
11404103445Skan  else if (DEFAULT_ABI == ABI_AIX)
11405103445Skan    {
1140690075Sobrien      if (TARGET_32BIT)
11407117395Skan	insn = emit_insn (gen_load_toc_aix_si (dest));
1140890075Sobrien      else
11409117395Skan	insn = emit_insn (gen_load_toc_aix_di (dest));
11410117395Skan      if (fromprolog)
11411117395Skan	rs6000_maybe_dead (insn);
1141290075Sobrien    }
11413103445Skan  else
11414103445Skan    abort ();
1141590075Sobrien}
1141690075Sobrien
11417132718Skan/* Emit instructions to restore the link register after determining where
11418132718Skan   its value has been stored.  */
11419132718Skan
11420132718Skanvoid
11421132718Skanrs6000_emit_eh_reg_restore (rtx source, rtx scratch)
11422132718Skan{
11423132718Skan  rs6000_stack_t *info = rs6000_stack_info ();
11424132718Skan  rtx operands[2];
11425132718Skan
11426132718Skan  operands[0] = source;
11427132718Skan  operands[1] = scratch;
11428132718Skan
11429132718Skan  if (info->lr_save_p)
11430132718Skan    {
11431132718Skan      rtx frame_rtx = stack_pointer_rtx;
11432132718Skan      HOST_WIDE_INT sp_offset = 0;
11433132718Skan      rtx tmp;
11434132718Skan
11435132718Skan      if (frame_pointer_needed
11436132718Skan	  || current_function_calls_alloca
11437132718Skan	  || info->total_size > 32767)
11438132718Skan	{
11439132718Skan	  emit_move_insn (operands[1], gen_rtx_MEM (Pmode, frame_rtx));
11440132718Skan	  frame_rtx = operands[1];
11441132718Skan	}
11442132718Skan      else if (info->push_p)
11443132718Skan	sp_offset = info->total_size;
11444132718Skan
11445132718Skan      tmp = plus_constant (frame_rtx, info->lr_save_offset + sp_offset);
11446132718Skan      tmp = gen_rtx_MEM (Pmode, tmp);
11447132718Skan      emit_move_insn (tmp, operands[0]);
11448132718Skan    }
11449132718Skan  else
11450132718Skan    emit_move_insn (gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM), operands[0]);
11451132718Skan}
11452132718Skan
11453132718Skanstatic GTY(()) int set = -1;
11454132718Skan
1145590075Sobrienint
11456132718Skanget_TOC_alias_set (void)
1145790075Sobrien{
11458132718Skan  if (set == -1)
11459132718Skan    set = new_alias_set ();
11460132718Skan  return set;
1146190075Sobrien}
1146290075Sobrien
11463132718Skan/* This returns nonzero if the current function uses the TOC.  This is
11464132718Skan   determined by the presence of (use (unspec ... UNSPEC_TOC)), which
11465132718Skan   is generated by the ABI_V4 load_toc_* patterns.  */
11466132718Skan#if TARGET_ELF
11467132718Skanstatic int
11468132718Skanuses_TOC (void)
1146990075Sobrien{
11470132718Skan  rtx insn;
1147190075Sobrien
11472132718Skan  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
11473132718Skan    if (INSN_P (insn))
11474132718Skan      {
11475132718Skan	rtx pat = PATTERN (insn);
11476132718Skan	int i;
1147790075Sobrien
11478132718Skan	if (GET_CODE (pat) == PARALLEL)
11479132718Skan	  for (i = 0; i < XVECLEN (pat, 0); i++)
11480132718Skan	    {
11481132718Skan	      rtx sub = XVECEXP (pat, 0, i);
11482132718Skan	      if (GET_CODE (sub) == USE)
11483132718Skan		{
11484132718Skan		  sub = XEXP (sub, 0);
11485132718Skan		  if (GET_CODE (sub) == UNSPEC
11486132718Skan		      && XINT (sub, 1) == UNSPEC_TOC)
11487132718Skan		    return 1;
11488132718Skan		}
11489132718Skan	    }
11490132718Skan      }
11491132718Skan  return 0;
1149290075Sobrien}
11493132718Skan#endif
1149490075Sobrien
1149590075Sobrienrtx
11496132718Skancreate_TOC_reference (rtx symbol)
1149790075Sobrien{
1149890075Sobrien  return gen_rtx_PLUS (Pmode,
1149990075Sobrien	   gen_rtx_REG (Pmode, TOC_REGISTER),
1150090075Sobrien	     gen_rtx_CONST (Pmode,
1150190075Sobrien	       gen_rtx_MINUS (Pmode, symbol,
1150290075Sobrien		 gen_rtx_SYMBOL_REF (Pmode, toc_label_name))));
1150390075Sobrien}
1150490075Sobrien
11505132718Skan/* If _Unwind_* has been called from within the same module,
11506132718Skan   toc register is not guaranteed to be saved to 40(1) on function
11507132718Skan   entry.  Save it there in that case.  */
1150890075Sobrien
1150990075Sobrienvoid
11510132718Skanrs6000_aix_emit_builtin_unwind_init (void)
1151190075Sobrien{
1151290075Sobrien  rtx mem;
1151390075Sobrien  rtx stack_top = gen_reg_rtx (Pmode);
1151490075Sobrien  rtx opcode_addr = gen_reg_rtx (Pmode);
11515132718Skan  rtx opcode = gen_reg_rtx (SImode);
11516132718Skan  rtx tocompare = gen_reg_rtx (SImode);
11517132718Skan  rtx no_toc_save_needed = gen_label_rtx ();
1151890075Sobrien
1151990075Sobrien  mem = gen_rtx_MEM (Pmode, hard_frame_pointer_rtx);
1152090075Sobrien  emit_move_insn (stack_top, mem);
1152190075Sobrien
11522132718Skan  mem = gen_rtx_MEM (Pmode,
11523132718Skan		     gen_rtx_PLUS (Pmode, stack_top,
1152490075Sobrien				   GEN_INT (2 * GET_MODE_SIZE (Pmode))));
1152590075Sobrien  emit_move_insn (opcode_addr, mem);
11526132718Skan  emit_move_insn (opcode, gen_rtx_MEM (SImode, opcode_addr));
11527132718Skan  emit_move_insn (tocompare, gen_int_mode (TARGET_32BIT ? 0x80410014
11528117395Skan					   : 0xE8410028, SImode));
1152990075Sobrien
11530132718Skan  do_compare_rtx_and_jump (opcode, tocompare, EQ, 1,
1153190075Sobrien			   SImode, NULL_RTX, NULL_RTX,
11532132718Skan			   no_toc_save_needed);
11533132718Skan
11534132718Skan  mem = gen_rtx_MEM (Pmode,
11535132718Skan		     gen_rtx_PLUS (Pmode, stack_top,
1153690075Sobrien				   GEN_INT (5 * GET_MODE_SIZE (Pmode))));
11537132718Skan  emit_move_insn (mem, gen_rtx_REG (Pmode, 2));
11538132718Skan  emit_label (no_toc_save_needed);
1153990075Sobrien}
1154090075Sobrien
1154190075Sobrien/* This ties together stack memory (MEM with an alias set of
1154290075Sobrien   rs6000_sr_alias_set) and the change to the stack pointer.  */
1154390075Sobrien
1154490075Sobrienstatic void
11545132718Skanrs6000_emit_stack_tie (void)
1154690075Sobrien{
1154790075Sobrien  rtx mem = gen_rtx_MEM (BLKmode, gen_rtx_REG (Pmode, STACK_POINTER_REGNUM));
1154890075Sobrien
1154990075Sobrien  set_mem_alias_set (mem, rs6000_sr_alias_set);
1155090075Sobrien  emit_insn (gen_stack_tie (mem));
1155190075Sobrien}
1155290075Sobrien
1155390075Sobrien/* Emit the correct code for allocating stack space, as insns.
1155490075Sobrien   If COPY_R12, make sure a copy of the old frame is left in r12.
1155590075Sobrien   The generated code may use hard register 0 as a temporary.  */
1155690075Sobrien
1155790075Sobrienstatic void
11558132718Skanrs6000_emit_allocate_stack (HOST_WIDE_INT size, int copy_r12)
1155990075Sobrien{
1156090075Sobrien  rtx insn;
1156190075Sobrien  rtx stack_reg = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
1156290075Sobrien  rtx tmp_reg = gen_rtx_REG (Pmode, 0);
1156390075Sobrien  rtx todec = GEN_INT (-size);
1156490075Sobrien
1156590075Sobrien  if (current_function_limit_stack)
1156690075Sobrien    {
1156790075Sobrien      if (REG_P (stack_limit_rtx)
1156890075Sobrien	  && REGNO (stack_limit_rtx) > 1
1156990075Sobrien	  && REGNO (stack_limit_rtx) <= 31)
1157090075Sobrien	{
11571132718Skan	  emit_insn (TARGET_32BIT
1157290075Sobrien		     ? gen_addsi3 (tmp_reg,
1157390075Sobrien				   stack_limit_rtx,
1157490075Sobrien				   GEN_INT (size))
1157590075Sobrien		     : gen_adddi3 (tmp_reg,
1157690075Sobrien				   stack_limit_rtx,
1157790075Sobrien				   GEN_INT (size)));
11578132718Skan
1157990075Sobrien	  emit_insn (gen_cond_trap (LTU, stack_reg, tmp_reg,
1158090075Sobrien				    const0_rtx));
1158190075Sobrien	}
1158290075Sobrien      else if (GET_CODE (stack_limit_rtx) == SYMBOL_REF
1158390075Sobrien	       && TARGET_32BIT
1158490075Sobrien	       && DEFAULT_ABI == ABI_V4)
1158590075Sobrien	{
1158690075Sobrien	  rtx toload = gen_rtx_CONST (VOIDmode,
1158790075Sobrien				      gen_rtx_PLUS (Pmode,
1158890075Sobrien						    stack_limit_rtx,
1158990075Sobrien						    GEN_INT (size)));
11590132718Skan
1159190075Sobrien	  emit_insn (gen_elf_high (tmp_reg, toload));
1159290075Sobrien	  emit_insn (gen_elf_low (tmp_reg, tmp_reg, toload));
1159390075Sobrien	  emit_insn (gen_cond_trap (LTU, stack_reg, tmp_reg,
1159490075Sobrien				    const0_rtx));
1159590075Sobrien	}
1159690075Sobrien      else
1159790075Sobrien	warning ("stack limit expression is not supported");
1159890075Sobrien    }
1159990075Sobrien
1160090075Sobrien  if (copy_r12 || ! TARGET_UPDATE)
1160190075Sobrien    emit_move_insn (gen_rtx_REG (Pmode, 12), stack_reg);
1160290075Sobrien
1160390075Sobrien  if (TARGET_UPDATE)
1160490075Sobrien    {
1160590075Sobrien      if (size > 32767)
1160690075Sobrien	{
1160790075Sobrien	  /* Need a note here so that try_split doesn't get confused.  */
1160890075Sobrien	  if (get_last_insn() == NULL_RTX)
11609132718Skan	    emit_note (NOTE_INSN_DELETED);
1161090075Sobrien	  insn = emit_move_insn (tmp_reg, todec);
1161190075Sobrien	  try_split (PATTERN (insn), insn, 0);
1161290075Sobrien	  todec = tmp_reg;
1161390075Sobrien	}
11614132718Skan
11615132718Skan      insn = emit_insn (TARGET_32BIT
11616132718Skan			? gen_movsi_update (stack_reg, stack_reg,
11617132718Skan					    todec, stack_reg)
11618132718Skan			: gen_movdi_update (stack_reg, stack_reg,
1161990075Sobrien					    todec, stack_reg));
1162090075Sobrien    }
1162190075Sobrien  else
1162290075Sobrien    {
11623132718Skan      insn = emit_insn (TARGET_32BIT
11624132718Skan			? gen_addsi3 (stack_reg, stack_reg, todec)
11625132718Skan			: gen_adddi3 (stack_reg, stack_reg, todec));
1162690075Sobrien      emit_move_insn (gen_rtx_MEM (Pmode, stack_reg),
1162790075Sobrien		      gen_rtx_REG (Pmode, 12));
1162890075Sobrien    }
11629132718Skan
1163090075Sobrien  RTX_FRAME_RELATED_P (insn) = 1;
1163190075Sobrien  REG_NOTES (insn) =
1163290075Sobrien    gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
1163390075Sobrien		       gen_rtx_SET (VOIDmode, stack_reg,
1163490075Sobrien				    gen_rtx_PLUS (Pmode, stack_reg,
1163590075Sobrien						  GEN_INT (-size))),
1163690075Sobrien		       REG_NOTES (insn));
1163790075Sobrien}
1163890075Sobrien
1163990075Sobrien/* Add to 'insn' a note which is PATTERN (INSN) but with REG replaced
1164090075Sobrien   with (plus:P (reg 1) VAL), and with REG2 replaced with RREG if REG2
1164190075Sobrien   is not NULL.  It would be nice if dwarf2out_frame_debug_expr could
1164290075Sobrien   deduce these equivalences by itself so it wasn't necessary to hold
1164390075Sobrien   its hand so much.  */
1164490075Sobrien
1164590075Sobrienstatic void
11646132718Skanrs6000_frame_related (rtx insn, rtx reg, HOST_WIDE_INT val,
11647132718Skan		      rtx reg2, rtx rreg)
1164890075Sobrien{
1164990075Sobrien  rtx real, temp;
1165090075Sobrien
11651117395Skan  /* copy_rtx will not make unique copies of registers, so we need to
11652117395Skan     ensure we don't have unwanted sharing here.  */
11653117395Skan  if (reg == reg2)
11654117395Skan    reg = gen_raw_REG (GET_MODE (reg), REGNO (reg));
11655117395Skan
11656117395Skan  if (reg == rreg)
11657117395Skan    reg = gen_raw_REG (GET_MODE (reg), REGNO (reg));
11658117395Skan
1165990075Sobrien  real = copy_rtx (PATTERN (insn));
1166090075Sobrien
11661117395Skan  if (reg2 != NULL_RTX)
11662117395Skan    real = replace_rtx (real, reg2, rreg);
11663117395Skan
1166490075Sobrien  real = replace_rtx (real, reg,
1166590075Sobrien		      gen_rtx_PLUS (Pmode, gen_rtx_REG (Pmode,
1166690075Sobrien							STACK_POINTER_REGNUM),
1166790075Sobrien				    GEN_INT (val)));
1166890075Sobrien
1166990075Sobrien  /* We expect that 'real' is either a SET or a PARALLEL containing
1167090075Sobrien     SETs (and possibly other stuff).  In a PARALLEL, all the SETs
1167190075Sobrien     are important so they all have to be marked RTX_FRAME_RELATED_P.  */
1167290075Sobrien
1167390075Sobrien  if (GET_CODE (real) == SET)
1167490075Sobrien    {
1167590075Sobrien      rtx set = real;
1167690075Sobrien
1167790075Sobrien      temp = simplify_rtx (SET_SRC (set));
1167890075Sobrien      if (temp)
1167990075Sobrien	SET_SRC (set) = temp;
1168090075Sobrien      temp = simplify_rtx (SET_DEST (set));
1168190075Sobrien      if (temp)
1168290075Sobrien	SET_DEST (set) = temp;
1168390075Sobrien      if (GET_CODE (SET_DEST (set)) == MEM)
1168490075Sobrien	{
1168590075Sobrien	  temp = simplify_rtx (XEXP (SET_DEST (set), 0));
1168690075Sobrien	  if (temp)
1168790075Sobrien	    XEXP (SET_DEST (set), 0) = temp;
1168890075Sobrien	}
1168990075Sobrien    }
1169090075Sobrien  else if (GET_CODE (real) == PARALLEL)
1169190075Sobrien    {
1169290075Sobrien      int i;
1169390075Sobrien      for (i = 0; i < XVECLEN (real, 0); i++)
1169490075Sobrien	if (GET_CODE (XVECEXP (real, 0, i)) == SET)
1169590075Sobrien	  {
1169690075Sobrien	    rtx set = XVECEXP (real, 0, i);
1169790075Sobrien
1169890075Sobrien	    temp = simplify_rtx (SET_SRC (set));
1169990075Sobrien	    if (temp)
1170090075Sobrien	      SET_SRC (set) = temp;
1170190075Sobrien	    temp = simplify_rtx (SET_DEST (set));
1170290075Sobrien	    if (temp)
1170390075Sobrien	      SET_DEST (set) = temp;
1170490075Sobrien	    if (GET_CODE (SET_DEST (set)) == MEM)
1170590075Sobrien	      {
1170690075Sobrien		temp = simplify_rtx (XEXP (SET_DEST (set), 0));
1170790075Sobrien		if (temp)
1170890075Sobrien		  XEXP (SET_DEST (set), 0) = temp;
1170990075Sobrien	      }
1171090075Sobrien	    RTX_FRAME_RELATED_P (set) = 1;
1171190075Sobrien	  }
1171290075Sobrien    }
1171390075Sobrien  else
1171490075Sobrien    abort ();
11715132718Skan
11716132718Skan  if (TARGET_SPE)
11717132718Skan    real = spe_synthesize_frame_save (real);
11718132718Skan
1171990075Sobrien  RTX_FRAME_RELATED_P (insn) = 1;
1172090075Sobrien  REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
1172190075Sobrien					real,
1172290075Sobrien					REG_NOTES (insn));
1172390075Sobrien}
1172490075Sobrien
11725132718Skan/* Given an SPE frame note, return a PARALLEL of SETs with the
11726132718Skan   original note, plus a synthetic register save.  */
11727132718Skan
11728132718Skanstatic rtx
11729132718Skanspe_synthesize_frame_save (rtx real)
11730132718Skan{
11731132718Skan  rtx synth, offset, reg, real2;
11732132718Skan
11733132718Skan  if (GET_CODE (real) != SET
11734132718Skan      || GET_MODE (SET_SRC (real)) != V2SImode)
11735132718Skan    return real;
11736132718Skan
11737132718Skan  /* For the SPE, registers saved in 64-bits, get a PARALLEL for their
11738132718Skan     frame related note.  The parallel contains a set of the register
11739132718Skan     being saved, and another set to a synthetic register (n+1200).
11740132718Skan     This is so we can differentiate between 64-bit and 32-bit saves.
11741132718Skan     Words cannot describe this nastiness.  */
11742132718Skan
11743132718Skan  if (GET_CODE (SET_DEST (real)) != MEM
11744132718Skan      || GET_CODE (XEXP (SET_DEST (real), 0)) != PLUS
11745132718Skan      || GET_CODE (SET_SRC (real)) != REG)
11746132718Skan    abort ();
11747132718Skan
11748132718Skan  /* Transform:
11749132718Skan       (set (mem (plus (reg x) (const y)))
11750132718Skan            (reg z))
11751132718Skan     into:
11752132718Skan       (set (mem (plus (reg x) (const y+4)))
11753132718Skan            (reg z+1200))
11754132718Skan  */
11755132718Skan
11756132718Skan  real2 = copy_rtx (real);
11757132718Skan  PUT_MODE (SET_DEST (real2), SImode);
11758132718Skan  reg = SET_SRC (real2);
11759132718Skan  real2 = replace_rtx (real2, reg, gen_rtx_REG (SImode, REGNO (reg)));
11760132718Skan  synth = copy_rtx (real2);
11761132718Skan
11762132718Skan  if (BYTES_BIG_ENDIAN)
11763132718Skan    {
11764132718Skan      offset = XEXP (XEXP (SET_DEST (real2), 0), 1);
11765132718Skan      real2 = replace_rtx (real2, offset, GEN_INT (INTVAL (offset) + 4));
11766132718Skan    }
11767132718Skan
11768132718Skan  reg = SET_SRC (synth);
11769132718Skan
11770132718Skan  synth = replace_rtx (synth, reg,
11771132718Skan		       gen_rtx_REG (SImode, REGNO (reg) + 1200));
11772132718Skan
11773132718Skan  offset = XEXP (XEXP (SET_DEST (synth), 0), 1);
11774132718Skan  synth = replace_rtx (synth, offset,
11775132718Skan		       GEN_INT (INTVAL (offset)
11776132718Skan				+ (BYTES_BIG_ENDIAN ? 0 : 4)));
11777132718Skan
11778132718Skan  RTX_FRAME_RELATED_P (synth) = 1;
11779132718Skan  RTX_FRAME_RELATED_P (real2) = 1;
11780132718Skan  if (BYTES_BIG_ENDIAN)
11781132718Skan    real = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, synth, real2));
11782132718Skan  else
11783132718Skan    real = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, real2, synth));
11784132718Skan
11785132718Skan  return real;
11786132718Skan}
11787132718Skan
1178890075Sobrien/* Returns an insn that has a vrsave set operation with the
1178990075Sobrien   appropriate CLOBBERs.  */
1179090075Sobrien
1179190075Sobrienstatic rtx
11792132718Skangenerate_set_vrsave (rtx reg, rs6000_stack_t *info, int epiloguep)
1179390075Sobrien{
1179490075Sobrien  int nclobs, i;
1179590075Sobrien  rtx insn, clobs[TOTAL_ALTIVEC_REGS + 1];
1179690075Sobrien  rtx vrsave = gen_rtx_REG (SImode, VRSAVE_REGNO);
1179790075Sobrien
1179890075Sobrien  clobs[0]
1179990075Sobrien    = gen_rtx_SET (VOIDmode,
1180090075Sobrien		   vrsave,
1180190075Sobrien		   gen_rtx_UNSPEC_VOLATILE (SImode,
1180290075Sobrien					    gen_rtvec (2, reg, vrsave),
1180390075Sobrien					    30));
1180490075Sobrien
1180590075Sobrien  nclobs = 1;
1180690075Sobrien
1180790075Sobrien  /* We need to clobber the registers in the mask so the scheduler
1180890075Sobrien     does not move sets to VRSAVE before sets of AltiVec registers.
1180990075Sobrien
1181090075Sobrien     However, if the function receives nonlocal gotos, reload will set
1181190075Sobrien     all call saved registers live.  We will end up with:
1181290075Sobrien
1181390075Sobrien     	(set (reg 999) (mem))
1181490075Sobrien	(parallel [ (set (reg vrsave) (unspec blah))
1181590075Sobrien		    (clobber (reg 999))])
1181690075Sobrien
1181790075Sobrien     The clobber will cause the store into reg 999 to be dead, and
1181890075Sobrien     flow will attempt to delete an epilogue insn.  In this case, we
1181990075Sobrien     need an unspec use/set of the register.  */
1182090075Sobrien
1182190075Sobrien  for (i = FIRST_ALTIVEC_REGNO; i <= LAST_ALTIVEC_REGNO; ++i)
11822132718Skan    if (info->vrsave_mask & ALTIVEC_REG_BIT (i))
1182390075Sobrien      {
1182490075Sobrien	if (!epiloguep || call_used_regs [i])
1182590075Sobrien	  clobs[nclobs++] = gen_rtx_CLOBBER (VOIDmode,
1182690075Sobrien					     gen_rtx_REG (V4SImode, i));
1182790075Sobrien	else
1182890075Sobrien	  {
1182990075Sobrien	    rtx reg = gen_rtx_REG (V4SImode, i);
1183090075Sobrien
1183190075Sobrien	    clobs[nclobs++]
1183290075Sobrien	      = gen_rtx_SET (VOIDmode,
1183390075Sobrien			     reg,
1183490075Sobrien			     gen_rtx_UNSPEC (V4SImode,
1183590075Sobrien					     gen_rtvec (1, reg), 27));
1183690075Sobrien	  }
1183790075Sobrien      }
1183890075Sobrien
1183990075Sobrien  insn = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (nclobs));
1184090075Sobrien
1184190075Sobrien  for (i = 0; i < nclobs; ++i)
1184290075Sobrien    XVECEXP (insn, 0, i) = clobs[i];
1184390075Sobrien
1184490075Sobrien  return insn;
1184590075Sobrien}
1184690075Sobrien
11847117395Skan/* Save a register into the frame, and emit RTX_FRAME_RELATED_P notes.
11848117395Skan   Save REGNO into [FRAME_REG + OFFSET] in mode MODE.  */
11849117395Skan
11850117395Skanstatic void
11851132718Skanemit_frame_save (rtx frame_reg, rtx frame_ptr, enum machine_mode mode,
11852132718Skan		 unsigned int regno, int offset, HOST_WIDE_INT total_size)
11853117395Skan{
11854117395Skan  rtx reg, offset_rtx, insn, mem, addr, int_rtx;
11855117395Skan  rtx replacea, replaceb;
11856117395Skan
11857117395Skan  int_rtx = GEN_INT (offset);
11858117395Skan
11859117395Skan  /* Some cases that need register indexed addressing.  */
11860117395Skan  if ((TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
11861117395Skan      || (TARGET_SPE_ABI
11862117395Skan	  && SPE_VECTOR_MODE (mode)
11863117395Skan	  && !SPE_CONST_OFFSET_OK (offset)))
11864117395Skan    {
11865117395Skan      /* Whomever calls us must make sure r11 is available in the
11866117395Skan         flow path of instructions in the prologue.  */
11867117395Skan      offset_rtx = gen_rtx_REG (Pmode, 11);
11868117395Skan      emit_move_insn (offset_rtx, int_rtx);
11869117395Skan
11870117395Skan      replacea = offset_rtx;
11871117395Skan      replaceb = int_rtx;
11872117395Skan    }
11873117395Skan  else
11874117395Skan    {
11875117395Skan      offset_rtx = int_rtx;
11876117395Skan      replacea = NULL_RTX;
11877117395Skan      replaceb = NULL_RTX;
11878117395Skan    }
11879117395Skan
11880117395Skan  reg = gen_rtx_REG (mode, regno);
11881117395Skan  addr = gen_rtx_PLUS (Pmode, frame_reg, offset_rtx);
11882117395Skan  mem = gen_rtx_MEM (mode, addr);
11883117395Skan  set_mem_alias_set (mem, rs6000_sr_alias_set);
11884117395Skan
11885117395Skan  insn = emit_move_insn (mem, reg);
11886117395Skan
11887117395Skan  rs6000_frame_related (insn, frame_ptr, total_size, replacea, replaceb);
11888117395Skan}
11889117395Skan
11890117395Skan/* Emit an offset memory reference suitable for a frame store, while
11891117395Skan   converting to a valid addressing mode.  */
11892117395Skan
11893117395Skanstatic rtx
11894132718Skangen_frame_mem_offset (enum machine_mode mode, rtx reg, int offset)
11895117395Skan{
11896117395Skan  rtx int_rtx, offset_rtx;
11897117395Skan
11898117395Skan  int_rtx = GEN_INT (offset);
11899117395Skan
11900117395Skan  if (TARGET_SPE_ABI && SPE_VECTOR_MODE (mode))
11901117395Skan    {
11902117395Skan      offset_rtx = gen_rtx_REG (Pmode, FIXED_SCRATCH);
11903117395Skan      emit_move_insn (offset_rtx, int_rtx);
11904117395Skan    }
11905117395Skan  else
11906117395Skan    offset_rtx = int_rtx;
11907117395Skan
11908117395Skan  return gen_rtx_MEM (mode, gen_rtx_PLUS (Pmode, reg, offset_rtx));
11909117395Skan}
11910117395Skan
1191190075Sobrien/* Emit function prologue as insns.  */
1191290075Sobrien
1191390075Sobrienvoid
11914132718Skanrs6000_emit_prologue (void)
1191590075Sobrien{
1191690075Sobrien  rs6000_stack_t *info = rs6000_stack_info ();
11917132718Skan  enum machine_mode reg_mode = Pmode;
11918132718Skan  int reg_size = TARGET_32BIT ? 4 : 8;
1191990075Sobrien  rtx sp_reg_rtx = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
1192090075Sobrien  rtx frame_ptr_rtx = gen_rtx_REG (Pmode, 12);
1192190075Sobrien  rtx frame_reg_rtx = sp_reg_rtx;
11922132718Skan  rtx cr_save_rtx = NULL_RTX;
1192390075Sobrien  rtx insn;
1192490075Sobrien  int saving_FPRs_inline;
1192590075Sobrien  int using_store_multiple;
1192690075Sobrien  HOST_WIDE_INT sp_offset = 0;
1192790075Sobrien
11928132718Skan   if (TARGET_SPE_ABI && info->spe_64bit_regs_used != 0)
11929117395Skan     {
11930117395Skan       reg_mode = V2SImode;
11931117395Skan       reg_size = 8;
11932117395Skan     }
11933117395Skan
1193490075Sobrien  using_store_multiple = (TARGET_MULTIPLE && ! TARGET_POWERPC64
11935132718Skan			  && (!TARGET_SPE_ABI
11936132718Skan			      || info->spe_64bit_regs_used == 0)
1193790075Sobrien			  && info->first_gp_reg_save < 31);
1193890075Sobrien  saving_FPRs_inline = (info->first_fp_reg_save == 64
11939132718Skan			|| FP_SAVE_INLINE (info->first_fp_reg_save)
11940132718Skan			|| current_function_calls_eh_return
11941132718Skan			|| cfun->machine->ra_need_lr);
1194290075Sobrien
1194390075Sobrien  /* For V.4, update stack before we do any saving and set back pointer.  */
11944132718Skan  if (info->push_p
11945132718Skan      && (DEFAULT_ABI == ABI_V4
11946132718Skan	  || current_function_calls_eh_return))
1194790075Sobrien    {
1194890075Sobrien      if (info->total_size < 32767)
1194990075Sobrien	sp_offset = info->total_size;
1195090075Sobrien      else
1195190075Sobrien	frame_reg_rtx = frame_ptr_rtx;
1195290075Sobrien      rs6000_emit_allocate_stack (info->total_size,
1195390075Sobrien				  (frame_reg_rtx != sp_reg_rtx
1195490075Sobrien				   && (info->cr_save_p
1195590075Sobrien				       || info->lr_save_p
1195690075Sobrien				       || info->first_fp_reg_save < 64
1195790075Sobrien				       || info->first_gp_reg_save < 32
1195890075Sobrien				       )));
1195990075Sobrien      if (frame_reg_rtx != sp_reg_rtx)
1196090075Sobrien	rs6000_emit_stack_tie ();
1196190075Sobrien    }
1196290075Sobrien
1196390075Sobrien  /* Save AltiVec registers if needed.  */
1196490075Sobrien  if (TARGET_ALTIVEC_ABI && info->altivec_size != 0)
1196590075Sobrien    {
1196690075Sobrien      int i;
1196790075Sobrien
1196890075Sobrien      /* There should be a non inline version of this, for when we
1196990075Sobrien	 are saving lots of vector registers.  */
1197090075Sobrien      for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i)
1197190075Sobrien	if (info->vrsave_mask & ALTIVEC_REG_BIT (i))
1197290075Sobrien	  {
1197390075Sobrien	    rtx areg, savereg, mem;
1197490075Sobrien	    int offset;
1197590075Sobrien
1197690075Sobrien	    offset = info->altivec_save_offset + sp_offset
1197790075Sobrien	      + 16 * (i - info->first_altivec_reg_save);
1197890075Sobrien
1197990075Sobrien	    savereg = gen_rtx_REG (V4SImode, i);
1198090075Sobrien
1198190075Sobrien	    areg = gen_rtx_REG (Pmode, 0);
1198290075Sobrien	    emit_move_insn (areg, GEN_INT (offset));
1198390075Sobrien
1198490075Sobrien	    /* AltiVec addressing mode is [reg+reg].  */
1198590075Sobrien	    mem = gen_rtx_MEM (V4SImode,
1198690075Sobrien			       gen_rtx_PLUS (Pmode, frame_reg_rtx, areg));
1198790075Sobrien
1198890075Sobrien	    set_mem_alias_set (mem, rs6000_sr_alias_set);
1198990075Sobrien
1199090075Sobrien	    insn = emit_move_insn (mem, savereg);
1199190075Sobrien
11992132718Skan	    rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
11993132718Skan				  areg, GEN_INT (offset));
1199490075Sobrien	  }
1199590075Sobrien    }
1199690075Sobrien
1199790075Sobrien  /* VRSAVE is a bit vector representing which AltiVec registers
1199890075Sobrien     are used.  The OS uses this to determine which vector
1199990075Sobrien     registers to save on a context switch.  We need to save
1200090075Sobrien     VRSAVE on the stack frame, add whatever AltiVec registers we
1200190075Sobrien     used in this function, and do the corresponding magic in the
1200290075Sobrien     epilogue.  */
1200390075Sobrien
12004132718Skan  if (TARGET_ALTIVEC && TARGET_ALTIVEC_VRSAVE
12005132718Skan      && info->vrsave_mask != 0)
1200690075Sobrien    {
1200790075Sobrien      rtx reg, mem, vrsave;
1200890075Sobrien      int offset;
1200990075Sobrien
1201090075Sobrien      /* Get VRSAVE onto a GPR.  */
1201190075Sobrien      reg = gen_rtx_REG (SImode, 12);
1201290075Sobrien      vrsave = gen_rtx_REG (SImode, VRSAVE_REGNO);
1201396263Sobrien      if (TARGET_MACHO)
1201496263Sobrien	emit_insn (gen_get_vrsave_internal (reg));
1201596263Sobrien      else
1201696263Sobrien	emit_insn (gen_rtx_SET (VOIDmode, reg, vrsave));
1201790075Sobrien
1201890075Sobrien      /* Save VRSAVE.  */
1201990075Sobrien      offset = info->vrsave_save_offset + sp_offset;
1202090075Sobrien      mem
1202190075Sobrien	= gen_rtx_MEM (SImode,
1202290075Sobrien		       gen_rtx_PLUS (Pmode, frame_reg_rtx, GEN_INT (offset)));
1202390075Sobrien      set_mem_alias_set (mem, rs6000_sr_alias_set);
1202490075Sobrien      insn = emit_move_insn (mem, reg);
1202590075Sobrien
1202690075Sobrien      /* Include the registers in the mask.  */
1202790075Sobrien      emit_insn (gen_iorsi3 (reg, reg, GEN_INT ((int) info->vrsave_mask)));
1202890075Sobrien
1202990075Sobrien      insn = emit_insn (generate_set_vrsave (reg, info, 0));
1203090075Sobrien    }
1203190075Sobrien
1203290075Sobrien  /* If we use the link register, get it into r0.  */
1203390075Sobrien  if (info->lr_save_p)
1203490075Sobrien    emit_move_insn (gen_rtx_REG (Pmode, 0),
1203590075Sobrien		    gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM));
1203690075Sobrien
1203790075Sobrien  /* If we need to save CR, put it into r12.  */
1203890075Sobrien  if (info->cr_save_p && frame_reg_rtx != frame_ptr_rtx)
1203990075Sobrien    {
1204090075Sobrien      cr_save_rtx = gen_rtx_REG (SImode, 12);
1204190075Sobrien      emit_insn (gen_movesi_from_cr (cr_save_rtx));
1204290075Sobrien    }
1204390075Sobrien
1204490075Sobrien  /* Do any required saving of fpr's.  If only one or two to save, do
1204590075Sobrien     it ourselves.  Otherwise, call function.  */
1204690075Sobrien  if (saving_FPRs_inline)
1204790075Sobrien    {
1204890075Sobrien      int i;
1204990075Sobrien      for (i = 0; i < 64 - info->first_fp_reg_save; i++)
1205090075Sobrien	if ((regs_ever_live[info->first_fp_reg_save+i]
1205190075Sobrien	     && ! call_used_regs[info->first_fp_reg_save+i]))
12052117395Skan	  emit_frame_save (frame_reg_rtx, frame_ptr_rtx, DFmode,
12053117395Skan			   info->first_fp_reg_save + i,
12054117395Skan			   info->fp_save_offset + sp_offset + 8 * i,
12055117395Skan			   info->total_size);
1205690075Sobrien    }
1205790075Sobrien  else if (info->first_fp_reg_save != 64)
1205890075Sobrien    {
1205990075Sobrien      int i;
1206090075Sobrien      char rname[30];
1206190075Sobrien      const char *alloc_rname;
1206290075Sobrien      rtvec p;
1206390075Sobrien      p = rtvec_alloc (2 + 64 - info->first_fp_reg_save);
1206490075Sobrien
1206590075Sobrien      RTVEC_ELT (p, 0) = gen_rtx_CLOBBER (VOIDmode,
1206690075Sobrien					  gen_rtx_REG (Pmode,
1206790075Sobrien						       LINK_REGISTER_REGNUM));
1206890075Sobrien      sprintf (rname, "%s%d%s", SAVE_FP_PREFIX,
1206990075Sobrien	       info->first_fp_reg_save - 32, SAVE_FP_SUFFIX);
1207090075Sobrien      alloc_rname = ggc_strdup (rname);
1207190075Sobrien      RTVEC_ELT (p, 1) = gen_rtx_USE (VOIDmode,
1207290075Sobrien				      gen_rtx_SYMBOL_REF (Pmode,
1207390075Sobrien							  alloc_rname));
1207490075Sobrien      for (i = 0; i < 64 - info->first_fp_reg_save; i++)
1207590075Sobrien	{
1207690075Sobrien	  rtx addr, reg, mem;
1207790075Sobrien	  reg = gen_rtx_REG (DFmode, info->first_fp_reg_save + i);
1207890075Sobrien	  addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
1207990075Sobrien			       GEN_INT (info->fp_save_offset
1208090075Sobrien					+ sp_offset + 8*i));
1208190075Sobrien	  mem = gen_rtx_MEM (DFmode, addr);
1208290075Sobrien	  set_mem_alias_set (mem, rs6000_sr_alias_set);
1208390075Sobrien
1208490075Sobrien	  RTVEC_ELT (p, i + 2) = gen_rtx_SET (VOIDmode, mem, reg);
1208590075Sobrien	}
1208690075Sobrien      insn = emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
1208790075Sobrien      rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
1208890075Sobrien			    NULL_RTX, NULL_RTX);
1208990075Sobrien    }
1209090075Sobrien
1209190075Sobrien  /* Save GPRs.  This is done as a PARALLEL if we are using
1209290075Sobrien     the store-multiple instructions.  */
1209390075Sobrien  if (using_store_multiple)
1209490075Sobrien    {
12095117395Skan      rtvec p;
1209690075Sobrien      int i;
1209790075Sobrien      p = rtvec_alloc (32 - info->first_gp_reg_save);
1209890075Sobrien      for (i = 0; i < 32 - info->first_gp_reg_save; i++)
1209990075Sobrien	{
1210090075Sobrien	  rtx addr, reg, mem;
1210190075Sobrien	  reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
1210290075Sobrien	  addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
1210390075Sobrien			       GEN_INT (info->gp_save_offset
1210490075Sobrien					+ sp_offset
1210590075Sobrien					+ reg_size * i));
1210690075Sobrien	  mem = gen_rtx_MEM (reg_mode, addr);
1210790075Sobrien	  set_mem_alias_set (mem, rs6000_sr_alias_set);
1210890075Sobrien
1210990075Sobrien	  RTVEC_ELT (p, i) = gen_rtx_SET (VOIDmode, mem, reg);
1211090075Sobrien	}
1211190075Sobrien      insn = emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
1211290075Sobrien      rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
1211390075Sobrien			    NULL_RTX, NULL_RTX);
1211490075Sobrien    }
1211590075Sobrien  else
1211690075Sobrien    {
1211790075Sobrien      int i;
1211890075Sobrien      for (i = 0; i < 32 - info->first_gp_reg_save; i++)
1211990075Sobrien	if ((regs_ever_live[info->first_gp_reg_save+i]
1212090075Sobrien	     && ! call_used_regs[info->first_gp_reg_save+i])
1212196263Sobrien	    || (i+info->first_gp_reg_save == RS6000_PIC_OFFSET_TABLE_REGNUM
12122117395Skan		&& ((DEFAULT_ABI == ABI_V4 && flag_pic != 0)
1212390075Sobrien		    || (DEFAULT_ABI == ABI_DARWIN && flag_pic))))
1212490075Sobrien	  {
1212590075Sobrien	    rtx addr, reg, mem;
1212690075Sobrien	    reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
1212790075Sobrien
12128132718Skan	    if (TARGET_SPE_ABI && info->spe_64bit_regs_used != 0)
12129117395Skan	      {
12130117395Skan		int offset = info->spe_gp_save_offset + sp_offset + 8 * i;
12131117395Skan		rtx b;
12132117395Skan
12133117395Skan		if (!SPE_CONST_OFFSET_OK (offset))
12134117395Skan		  {
12135117395Skan		    b = gen_rtx_REG (Pmode, FIXED_SCRATCH);
12136117395Skan		    emit_move_insn (b, GEN_INT (offset));
12137117395Skan		  }
12138117395Skan		else
12139117395Skan		  b = GEN_INT (offset);
12140117395Skan
12141117395Skan		addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, b);
12142117395Skan		mem = gen_rtx_MEM (V2SImode, addr);
12143117395Skan		set_mem_alias_set (mem, rs6000_sr_alias_set);
12144117395Skan		insn = emit_move_insn (mem, reg);
12145117395Skan
12146117395Skan		if (GET_CODE (b) == CONST_INT)
12147117395Skan		  rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
12148117395Skan					NULL_RTX, NULL_RTX);
12149117395Skan		else
12150117395Skan		  rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
12151117395Skan					b, GEN_INT (offset));
12152117395Skan	      }
12153117395Skan	    else
12154117395Skan	      {
12155117395Skan		addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
12156117395Skan				     GEN_INT (info->gp_save_offset
12157117395Skan					      + sp_offset
12158117395Skan					      + reg_size * i));
12159117395Skan		mem = gen_rtx_MEM (reg_mode, addr);
12160117395Skan		set_mem_alias_set (mem, rs6000_sr_alias_set);
12161117395Skan
12162117395Skan		insn = emit_move_insn (mem, reg);
12163117395Skan		rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
12164117395Skan				      NULL_RTX, NULL_RTX);
12165117395Skan	      }
1216690075Sobrien	  }
1216790075Sobrien    }
1216890075Sobrien
1216990075Sobrien  /* ??? There's no need to emit actual instructions here, but it's the
1217090075Sobrien     easiest way to get the frame unwind information emitted.  */
1217190075Sobrien  if (current_function_calls_eh_return)
1217290075Sobrien    {
1217390075Sobrien      unsigned int i, regno;
1217490075Sobrien
12175132718Skan      /* In AIX ABI we need to pretend we save r2 here.  */
12176132718Skan      if (TARGET_AIX)
12177132718Skan	{
12178132718Skan	  rtx addr, reg, mem;
12179132718Skan
12180132718Skan	  reg = gen_rtx_REG (reg_mode, 2);
12181132718Skan	  addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
12182132718Skan			       GEN_INT (sp_offset + 5 * reg_size));
12183132718Skan	  mem = gen_rtx_MEM (reg_mode, addr);
12184132718Skan	  set_mem_alias_set (mem, rs6000_sr_alias_set);
12185132718Skan
12186132718Skan	  insn = emit_move_insn (mem, reg);
12187132718Skan	  rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
12188132718Skan				NULL_RTX, NULL_RTX);
12189132718Skan	  PATTERN (insn) = gen_blockage ();
12190132718Skan	}
12191132718Skan
1219290075Sobrien      for (i = 0; ; ++i)
1219390075Sobrien	{
1219490075Sobrien	  regno = EH_RETURN_DATA_REGNO (i);
1219590075Sobrien	  if (regno == INVALID_REGNUM)
1219690075Sobrien	    break;
1219790075Sobrien
12198117395Skan	  emit_frame_save (frame_reg_rtx, frame_ptr_rtx, reg_mode, regno,
12199117395Skan			   info->ehrd_offset + sp_offset
12200117395Skan			   + reg_size * (int) i,
12201117395Skan			   info->total_size);
1220290075Sobrien	}
1220390075Sobrien    }
1220490075Sobrien
1220590075Sobrien  /* Save lr if we used it.  */
1220690075Sobrien  if (info->lr_save_p)
1220790075Sobrien    {
1220890075Sobrien      rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
1220990075Sobrien			       GEN_INT (info->lr_save_offset + sp_offset));
1221090075Sobrien      rtx reg = gen_rtx_REG (Pmode, 0);
1221190075Sobrien      rtx mem = gen_rtx_MEM (Pmode, addr);
1221290075Sobrien      /* This should not be of rs6000_sr_alias_set, because of
1221390075Sobrien	 __builtin_return_address.  */
1221490075Sobrien
1221590075Sobrien      insn = emit_move_insn (mem, reg);
1221690075Sobrien      rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
1221790075Sobrien			    reg, gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM));
1221890075Sobrien    }
1221990075Sobrien
1222090075Sobrien  /* Save CR if we use any that must be preserved.  */
1222190075Sobrien  if (info->cr_save_p)
1222290075Sobrien    {
1222390075Sobrien      rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
1222490075Sobrien			       GEN_INT (info->cr_save_offset + sp_offset));
1222590075Sobrien      rtx mem = gen_rtx_MEM (SImode, addr);
1222690075Sobrien
1222790075Sobrien      set_mem_alias_set (mem, rs6000_sr_alias_set);
1222890075Sobrien
1222990075Sobrien      /* If r12 was used to hold the original sp, copy cr into r0 now
1223090075Sobrien	 that it's free.  */
1223190075Sobrien      if (REGNO (frame_reg_rtx) == 12)
1223290075Sobrien	{
1223390075Sobrien	  cr_save_rtx = gen_rtx_REG (SImode, 0);
1223490075Sobrien	  emit_insn (gen_movesi_from_cr (cr_save_rtx));
1223590075Sobrien	}
1223690075Sobrien      insn = emit_move_insn (mem, cr_save_rtx);
1223790075Sobrien
1223890075Sobrien      /* Now, there's no way that dwarf2out_frame_debug_expr is going
12239132718Skan	 to understand '(unspec:SI [(reg:CC 68) ...] UNSPEC_MOVESI_FROM_CR)'.
12240132718Skan	 But that's OK.  All we have to do is specify that _one_ condition
12241132718Skan	 code register is saved in this stack slot.  The thrower's epilogue
1224290075Sobrien	 will then restore all the call-saved registers.
1224390075Sobrien	 We use CR2_REGNO (70) to be compatible with gcc-2.95 on Linux.  */
1224490075Sobrien      rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
1224590075Sobrien			    cr_save_rtx, gen_rtx_REG (SImode, CR2_REGNO));
1224690075Sobrien    }
1224790075Sobrien
1224890075Sobrien  /* Update stack and set back pointer unless this is V.4,
1224990075Sobrien     for which it was done previously.  */
12250132718Skan  if (info->push_p
12251132718Skan      && !(DEFAULT_ABI == ABI_V4 || current_function_calls_eh_return))
1225290075Sobrien    rs6000_emit_allocate_stack (info->total_size, FALSE);
1225390075Sobrien
1225490075Sobrien  /* Set frame pointer, if needed.  */
1225590075Sobrien  if (frame_pointer_needed)
1225690075Sobrien    {
12257117395Skan      insn = emit_move_insn (gen_rtx_REG (Pmode, FRAME_POINTER_REGNUM),
1225890075Sobrien			     sp_reg_rtx);
1225990075Sobrien      RTX_FRAME_RELATED_P (insn) = 1;
1226090075Sobrien    }
1226190075Sobrien
1226296263Sobrien  /* If we are using RS6000_PIC_OFFSET_TABLE_REGNUM, we need to set it up.  */
1226390075Sobrien  if ((TARGET_TOC && TARGET_MINIMAL_TOC && get_pool_size () != 0)
1226490075Sobrien      || (DEFAULT_ABI == ABI_V4 && flag_pic == 1
1226596263Sobrien	  && regs_ever_live[RS6000_PIC_OFFSET_TABLE_REGNUM]))
1226690075Sobrien  {
1226790075Sobrien    /* If emit_load_toc_table will use the link register, we need to save
12268132718Skan       it.  We use R12 for this purpose because emit_load_toc_table
1226990075Sobrien       can use register 0.  This allows us to use a plain 'blr' to return
1227090075Sobrien       from the procedure more often.  */
12271132718Skan    int save_LR_around_toc_setup = (TARGET_ELF
12272132718Skan				    && DEFAULT_ABI != ABI_AIX
12273132718Skan				    && flag_pic
1227490075Sobrien				    && ! info->lr_save_p
1227590075Sobrien				    && EXIT_BLOCK_PTR->pred != NULL);
1227690075Sobrien    if (save_LR_around_toc_setup)
12277132718Skan      {
12278132718Skan	rtx lr = gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM);
12279132718Skan	rs6000_maybe_dead (emit_move_insn (frame_ptr_rtx, lr));
12280132718Skan	rs6000_emit_load_toc_table (TRUE);
12281132718Skan	rs6000_maybe_dead (emit_move_insn (lr, frame_ptr_rtx));
12282132718Skan      }
12283132718Skan    else
12284132718Skan      rs6000_emit_load_toc_table (TRUE);
1228590075Sobrien  }
1228690075Sobrien
12287117395Skan#if TARGET_MACHO
1228890075Sobrien  if (DEFAULT_ABI == ABI_DARWIN
1228990075Sobrien      && flag_pic && current_function_uses_pic_offset_table)
1229090075Sobrien    {
1229190075Sobrien      rtx dest = gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM);
12292132718Skan      const char *picbase = machopic_function_base_name ();
12293132718Skan      rtx src = gen_rtx_SYMBOL_REF (Pmode, picbase);
1229490075Sobrien
12295117395Skan      rs6000_maybe_dead (emit_insn (gen_load_macho_picbase (dest, src)));
1229690075Sobrien
1229790075Sobrien      rs6000_maybe_dead (
1229896263Sobrien	emit_move_insn (gen_rtx_REG (Pmode, RS6000_PIC_OFFSET_TABLE_REGNUM),
1229990075Sobrien			gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM)));
1230090075Sobrien    }
12301117395Skan#endif
1230290075Sobrien}
1230390075Sobrien
1230490075Sobrien/* Write function prologue.  */
1230590075Sobrien
1230690075Sobrienstatic void
12307132718Skanrs6000_output_function_prologue (FILE *file,
12308132718Skan				 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
1230990075Sobrien{
1231090075Sobrien  rs6000_stack_t *info = rs6000_stack_info ();
1231190075Sobrien
1231290075Sobrien  if (TARGET_DEBUG_STACK)
1231390075Sobrien    debug_stack_info (info);
1231490075Sobrien
1231590075Sobrien  /* Write .extern for any function we will call to save and restore
1231690075Sobrien     fp values.  */
1231790075Sobrien  if (info->first_fp_reg_save < 64
1231890075Sobrien      && !FP_SAVE_INLINE (info->first_fp_reg_save))
1231990075Sobrien    fprintf (file, "\t.extern %s%d%s\n\t.extern %s%d%s\n",
1232090075Sobrien	     SAVE_FP_PREFIX, info->first_fp_reg_save - 32, SAVE_FP_SUFFIX,
1232190075Sobrien	     RESTORE_FP_PREFIX, info->first_fp_reg_save - 32,
1232290075Sobrien	     RESTORE_FP_SUFFIX);
1232390075Sobrien
1232490075Sobrien  /* Write .extern for AIX common mode routines, if needed.  */
1232590075Sobrien  if (! TARGET_POWER && ! TARGET_POWERPC && ! common_mode_defined)
1232690075Sobrien    {
1232790075Sobrien      fputs ("\t.extern __mulh\n", file);
1232890075Sobrien      fputs ("\t.extern __mull\n", file);
1232990075Sobrien      fputs ("\t.extern __divss\n", file);
1233090075Sobrien      fputs ("\t.extern __divus\n", file);
1233190075Sobrien      fputs ("\t.extern __quoss\n", file);
1233290075Sobrien      fputs ("\t.extern __quous\n", file);
1233390075Sobrien      common_mode_defined = 1;
1233490075Sobrien    }
1233590075Sobrien
1233690075Sobrien  if (! HAVE_prologue)
1233790075Sobrien    {
1233890075Sobrien      start_sequence ();
1233996263Sobrien
1234090075Sobrien      /* A NOTE_INSN_DELETED is supposed to be at the start and end of
1234190075Sobrien	 the "toplevel" insn chain.  */
12342132718Skan      emit_note (NOTE_INSN_DELETED);
1234390075Sobrien      rs6000_emit_prologue ();
12344132718Skan      emit_note (NOTE_INSN_DELETED);
1234596263Sobrien
12346132718Skan      /* Expand INSN_ADDRESSES so final() doesn't crash.  */
1234796263Sobrien      {
1234896263Sobrien	rtx insn;
1234996263Sobrien	unsigned addr = 0;
1235096263Sobrien	for (insn = get_insns (); insn != 0; insn = NEXT_INSN (insn))
1235196263Sobrien	  {
1235296263Sobrien	    INSN_ADDRESSES_NEW (insn, addr);
1235396263Sobrien	    addr += 4;
1235496263Sobrien	  }
1235596263Sobrien      }
1235696263Sobrien
1235790075Sobrien      if (TARGET_DEBUG_STACK)
1235890075Sobrien	debug_rtx_list (get_insns (), 100);
1235990075Sobrien      final (get_insns (), file, FALSE, FALSE);
1236090075Sobrien      end_sequence ();
1236190075Sobrien    }
1236290075Sobrien
1236390075Sobrien  rs6000_pic_labelno++;
1236490075Sobrien}
1236590075Sobrien
1236690075Sobrien/* Emit function epilogue as insns.
1236790075Sobrien
1236890075Sobrien   At present, dwarf2out_frame_debug_expr doesn't understand
1236990075Sobrien   register restores, so we don't bother setting RTX_FRAME_RELATED_P
1237090075Sobrien   anywhere in the epilogue.  Most of the insns below would in any case
1237190075Sobrien   need special notes to explain where r11 is in relation to the stack.  */
1237290075Sobrien
1237390075Sobrienvoid
12374132718Skanrs6000_emit_epilogue (int sibcall)
1237590075Sobrien{
1237690075Sobrien  rs6000_stack_t *info;
1237790075Sobrien  int restoring_FPRs_inline;
1237890075Sobrien  int using_load_multiple;
1237990075Sobrien  int using_mfcr_multiple;
1238090075Sobrien  int use_backchain_to_restore_sp;
1238190075Sobrien  int sp_offset = 0;
1238290075Sobrien  rtx sp_reg_rtx = gen_rtx_REG (Pmode, 1);
1238390075Sobrien  rtx frame_reg_rtx = sp_reg_rtx;
12384132718Skan  enum machine_mode reg_mode = Pmode;
12385132718Skan  int reg_size = TARGET_32BIT ? 4 : 8;
1238690075Sobrien  int i;
1238790075Sobrien
12388132718Skan  info = rs6000_stack_info ();
12389132718Skan
12390132718Skan  if (TARGET_SPE_ABI && info->spe_64bit_regs_used != 0)
12391117395Skan    {
12392117395Skan      reg_mode = V2SImode;
12393117395Skan      reg_size = 8;
12394117395Skan    }
12395117395Skan
1239690075Sobrien  using_load_multiple = (TARGET_MULTIPLE && ! TARGET_POWERPC64
12397132718Skan			 && (!TARGET_SPE_ABI
12398132718Skan			     || info->spe_64bit_regs_used == 0)
1239990075Sobrien			 && info->first_gp_reg_save < 31);
1240090075Sobrien  restoring_FPRs_inline = (sibcall
1240190075Sobrien			   || current_function_calls_eh_return
1240290075Sobrien			   || info->first_fp_reg_save == 64
1240390075Sobrien			   || FP_SAVE_INLINE (info->first_fp_reg_save));
1240490075Sobrien  use_backchain_to_restore_sp = (frame_pointer_needed
1240590075Sobrien				 || current_function_calls_alloca
1240690075Sobrien				 || info->total_size > 32767);
1240790075Sobrien  using_mfcr_multiple = (rs6000_cpu == PROCESSOR_PPC601
1240890075Sobrien			 || rs6000_cpu == PROCESSOR_PPC603
1240990075Sobrien			 || rs6000_cpu == PROCESSOR_PPC750
1241090075Sobrien			 || optimize_size);
1241190075Sobrien
1241290075Sobrien  /* If we have a frame pointer, a call to alloca,  or a large stack
1241390075Sobrien     frame, restore the old stack pointer using the backchain.  Otherwise,
1241490075Sobrien     we know what size to update it with.  */
1241590075Sobrien  if (use_backchain_to_restore_sp)
1241690075Sobrien    {
1241790075Sobrien      /* Under V.4, don't reset the stack pointer until after we're done
1241890075Sobrien	 loading the saved registers.  */
1241990075Sobrien      if (DEFAULT_ABI == ABI_V4)
1242090075Sobrien	frame_reg_rtx = gen_rtx_REG (Pmode, 11);
1242190075Sobrien
1242290075Sobrien      emit_move_insn (frame_reg_rtx,
1242390075Sobrien		      gen_rtx_MEM (Pmode, sp_reg_rtx));
1242490075Sobrien
1242590075Sobrien    }
1242690075Sobrien  else if (info->push_p)
1242790075Sobrien    {
12428132718Skan      if (DEFAULT_ABI == ABI_V4
12429132718Skan	  || current_function_calls_eh_return)
1243090075Sobrien	sp_offset = info->total_size;
1243190075Sobrien      else
1243290075Sobrien	{
1243390075Sobrien	  emit_insn (TARGET_32BIT
1243490075Sobrien		     ? gen_addsi3 (sp_reg_rtx, sp_reg_rtx,
1243590075Sobrien				   GEN_INT (info->total_size))
1243690075Sobrien		     : gen_adddi3 (sp_reg_rtx, sp_reg_rtx,
1243790075Sobrien				   GEN_INT (info->total_size)));
1243890075Sobrien	}
1243990075Sobrien    }
1244090075Sobrien
1244190075Sobrien  /* Restore AltiVec registers if needed.  */
1244290075Sobrien  if (TARGET_ALTIVEC_ABI && info->altivec_size != 0)
1244390075Sobrien    {
1244490075Sobrien      int i;
1244590075Sobrien
1244690075Sobrien      for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i)
1244790075Sobrien	if (info->vrsave_mask & ALTIVEC_REG_BIT (i))
1244890075Sobrien	  {
1244990075Sobrien	    rtx addr, areg, mem;
1245090075Sobrien
1245190075Sobrien	    areg = gen_rtx_REG (Pmode, 0);
1245290075Sobrien	    emit_move_insn
1245390075Sobrien	      (areg, GEN_INT (info->altivec_save_offset
1245490075Sobrien			      + sp_offset
1245590075Sobrien			      + 16 * (i - info->first_altivec_reg_save)));
1245690075Sobrien
1245790075Sobrien	    /* AltiVec addressing mode is [reg+reg].  */
1245890075Sobrien	    addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, areg);
1245990075Sobrien	    mem = gen_rtx_MEM (V4SImode, addr);
1246090075Sobrien	    set_mem_alias_set (mem, rs6000_sr_alias_set);
1246190075Sobrien
1246290075Sobrien	    emit_move_insn (gen_rtx_REG (V4SImode, i), mem);
1246390075Sobrien	  }
1246490075Sobrien    }
1246590075Sobrien
1246690075Sobrien  /* Restore VRSAVE if needed.  */
12467132718Skan  if (TARGET_ALTIVEC && TARGET_ALTIVEC_VRSAVE
12468132718Skan      && info->vrsave_mask != 0)
1246990075Sobrien    {
1247090075Sobrien      rtx addr, mem, reg;
1247190075Sobrien
1247290075Sobrien      addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
1247390075Sobrien			   GEN_INT (info->vrsave_save_offset + sp_offset));
1247490075Sobrien      mem = gen_rtx_MEM (SImode, addr);
1247590075Sobrien      set_mem_alias_set (mem, rs6000_sr_alias_set);
1247690075Sobrien      reg = gen_rtx_REG (SImode, 12);
1247790075Sobrien      emit_move_insn (reg, mem);
1247890075Sobrien
1247990075Sobrien      emit_insn (generate_set_vrsave (reg, info, 1));
1248090075Sobrien    }
1248190075Sobrien
1248290075Sobrien  /* Get the old lr if we saved it.  */
1248390075Sobrien  if (info->lr_save_p)
1248490075Sobrien    {
12485117395Skan      rtx mem = gen_frame_mem_offset (Pmode, frame_reg_rtx,
12486117395Skan				      info->lr_save_offset + sp_offset);
1248790075Sobrien
1248890075Sobrien      set_mem_alias_set (mem, rs6000_sr_alias_set);
1248990075Sobrien
1249090075Sobrien      emit_move_insn (gen_rtx_REG (Pmode, 0), mem);
1249190075Sobrien    }
1249290075Sobrien
1249390075Sobrien  /* Get the old cr if we saved it.  */
1249490075Sobrien  if (info->cr_save_p)
1249590075Sobrien    {
1249690075Sobrien      rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
1249790075Sobrien			       GEN_INT (info->cr_save_offset + sp_offset));
1249890075Sobrien      rtx mem = gen_rtx_MEM (SImode, addr);
1249990075Sobrien
1250090075Sobrien      set_mem_alias_set (mem, rs6000_sr_alias_set);
1250190075Sobrien
1250290075Sobrien      emit_move_insn (gen_rtx_REG (SImode, 12), mem);
1250390075Sobrien    }
1250490075Sobrien
1250590075Sobrien  /* Set LR here to try to overlap restores below.  */
1250690075Sobrien  if (info->lr_save_p)
1250790075Sobrien    emit_move_insn (gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM),
1250890075Sobrien		    gen_rtx_REG (Pmode, 0));
1250990075Sobrien
1251090075Sobrien  /* Load exception handler data registers, if needed.  */
1251190075Sobrien  if (current_function_calls_eh_return)
1251290075Sobrien    {
1251390075Sobrien      unsigned int i, regno;
1251490075Sobrien
12515132718Skan      if (TARGET_AIX)
12516132718Skan	{
12517132718Skan	  rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
12518132718Skan				   GEN_INT (sp_offset + 5 * reg_size));
12519132718Skan	  rtx mem = gen_rtx_MEM (reg_mode, addr);
12520132718Skan
12521132718Skan	  set_mem_alias_set (mem, rs6000_sr_alias_set);
12522132718Skan
12523132718Skan	  emit_move_insn (gen_rtx_REG (reg_mode, 2), mem);
12524132718Skan	}
12525132718Skan
1252690075Sobrien      for (i = 0; ; ++i)
1252790075Sobrien	{
12528117395Skan	  rtx mem;
1252990075Sobrien
1253090075Sobrien	  regno = EH_RETURN_DATA_REGNO (i);
1253190075Sobrien	  if (regno == INVALID_REGNUM)
1253290075Sobrien	    break;
1253390075Sobrien
12534117395Skan	  mem = gen_frame_mem_offset (reg_mode, frame_reg_rtx,
12535117395Skan				      info->ehrd_offset + sp_offset
12536117395Skan				      + reg_size * (int) i);
1253790075Sobrien	  set_mem_alias_set (mem, rs6000_sr_alias_set);
1253890075Sobrien
1253990075Sobrien	  emit_move_insn (gen_rtx_REG (reg_mode, regno), mem);
1254090075Sobrien	}
1254190075Sobrien    }
1254290075Sobrien
1254390075Sobrien  /* Restore GPRs.  This is done as a PARALLEL if we are using
1254490075Sobrien     the load-multiple instructions.  */
1254590075Sobrien  if (using_load_multiple)
1254690075Sobrien    {
1254790075Sobrien      rtvec p;
1254890075Sobrien      p = rtvec_alloc (32 - info->first_gp_reg_save);
1254990075Sobrien      for (i = 0; i < 32 - info->first_gp_reg_save; i++)
1255090075Sobrien	{
1255190075Sobrien	  rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
1255290075Sobrien				   GEN_INT (info->gp_save_offset
1255390075Sobrien					    + sp_offset
1255490075Sobrien					    + reg_size * i));
1255590075Sobrien	  rtx mem = gen_rtx_MEM (reg_mode, addr);
1255690075Sobrien
1255790075Sobrien	  set_mem_alias_set (mem, rs6000_sr_alias_set);
1255890075Sobrien
1255990075Sobrien	  RTVEC_ELT (p, i) =
1256090075Sobrien	    gen_rtx_SET (VOIDmode,
1256190075Sobrien			 gen_rtx_REG (reg_mode, info->first_gp_reg_save + i),
1256290075Sobrien			 mem);
1256390075Sobrien	}
1256490075Sobrien      emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
1256590075Sobrien    }
1256690075Sobrien  else
1256790075Sobrien    for (i = 0; i < 32 - info->first_gp_reg_save; i++)
1256890075Sobrien      if ((regs_ever_live[info->first_gp_reg_save+i]
1256990075Sobrien	   && ! call_used_regs[info->first_gp_reg_save+i])
1257096263Sobrien	  || (i+info->first_gp_reg_save == RS6000_PIC_OFFSET_TABLE_REGNUM
12571117395Skan	      && ((DEFAULT_ABI == ABI_V4 && flag_pic != 0)
1257290075Sobrien		  || (DEFAULT_ABI == ABI_DARWIN && flag_pic))))
1257390075Sobrien	{
1257490075Sobrien	  rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
1257590075Sobrien				   GEN_INT (info->gp_save_offset
1257690075Sobrien					    + sp_offset
1257790075Sobrien					    + reg_size * i));
1257890075Sobrien	  rtx mem = gen_rtx_MEM (reg_mode, addr);
1257990075Sobrien
12580117395Skan	  /* Restore 64-bit quantities for SPE.  */
12581132718Skan	  if (TARGET_SPE_ABI && info->spe_64bit_regs_used != 0)
12582117395Skan	    {
12583117395Skan	      int offset = info->spe_gp_save_offset + sp_offset + 8 * i;
12584117395Skan	      rtx b;
12585117395Skan
12586117395Skan	      if (!SPE_CONST_OFFSET_OK (offset))
12587117395Skan		{
12588117395Skan		  b = gen_rtx_REG (Pmode, FIXED_SCRATCH);
12589117395Skan		  emit_move_insn (b, GEN_INT (offset));
12590117395Skan		}
12591117395Skan	      else
12592117395Skan		b = GEN_INT (offset);
12593117395Skan
12594117395Skan	      addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, b);
12595117395Skan	      mem = gen_rtx_MEM (V2SImode, addr);
12596117395Skan	    }
12597117395Skan
1259890075Sobrien	  set_mem_alias_set (mem, rs6000_sr_alias_set);
1259990075Sobrien
1260090075Sobrien	  emit_move_insn (gen_rtx_REG (reg_mode,
12601117395Skan				       info->first_gp_reg_save + i), mem);
1260290075Sobrien	}
1260390075Sobrien
1260490075Sobrien  /* Restore fpr's if we need to do it without calling a function.  */
1260590075Sobrien  if (restoring_FPRs_inline)
1260690075Sobrien    for (i = 0; i < 64 - info->first_fp_reg_save; i++)
1260790075Sobrien      if ((regs_ever_live[info->first_fp_reg_save+i]
1260890075Sobrien	   && ! call_used_regs[info->first_fp_reg_save+i]))
1260990075Sobrien	{
1261090075Sobrien	  rtx addr, mem;
1261190075Sobrien	  addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
1261290075Sobrien			       GEN_INT (info->fp_save_offset
1261390075Sobrien					+ sp_offset
1261490075Sobrien					+ 8 * i));
1261590075Sobrien	  mem = gen_rtx_MEM (DFmode, addr);
1261690075Sobrien	  set_mem_alias_set (mem, rs6000_sr_alias_set);
1261790075Sobrien
1261890075Sobrien	  emit_move_insn (gen_rtx_REG (DFmode,
1261990075Sobrien				       info->first_fp_reg_save + i),
1262090075Sobrien			  mem);
1262190075Sobrien	}
1262290075Sobrien
1262390075Sobrien  /* If we saved cr, restore it here.  Just those that were used.  */
1262490075Sobrien  if (info->cr_save_p)
1262590075Sobrien    {
1262690075Sobrien      rtx r12_rtx = gen_rtx_REG (SImode, 12);
1262790075Sobrien      int count = 0;
1262890075Sobrien
1262990075Sobrien      if (using_mfcr_multiple)
1263090075Sobrien	{
1263190075Sobrien	  for (i = 0; i < 8; i++)
1263290075Sobrien	    if (regs_ever_live[CR0_REGNO+i] && ! call_used_regs[CR0_REGNO+i])
1263390075Sobrien	      count++;
1263490075Sobrien	  if (count == 0)
1263590075Sobrien	    abort ();
1263690075Sobrien	}
1263790075Sobrien
1263890075Sobrien      if (using_mfcr_multiple && count > 1)
1263990075Sobrien	{
1264090075Sobrien	  rtvec p;
1264190075Sobrien	  int ndx;
1264290075Sobrien
1264390075Sobrien	  p = rtvec_alloc (count);
1264490075Sobrien
1264590075Sobrien	  ndx = 0;
1264690075Sobrien	  for (i = 0; i < 8; i++)
1264790075Sobrien	    if (regs_ever_live[CR0_REGNO+i] && ! call_used_regs[CR0_REGNO+i])
1264890075Sobrien	      {
1264990075Sobrien		rtvec r = rtvec_alloc (2);
1265090075Sobrien		RTVEC_ELT (r, 0) = r12_rtx;
1265190075Sobrien		RTVEC_ELT (r, 1) = GEN_INT (1 << (7-i));
1265290075Sobrien		RTVEC_ELT (p, ndx) =
1265390075Sobrien		  gen_rtx_SET (VOIDmode, gen_rtx_REG (CCmode, CR0_REGNO+i),
12654132718Skan			       gen_rtx_UNSPEC (CCmode, r, UNSPEC_MOVESI_TO_CR));
1265590075Sobrien		ndx++;
1265690075Sobrien	      }
1265790075Sobrien	  emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
1265890075Sobrien	  if (ndx != count)
1265990075Sobrien	    abort ();
1266090075Sobrien	}
1266190075Sobrien      else
1266290075Sobrien	for (i = 0; i < 8; i++)
1266390075Sobrien	  if (regs_ever_live[CR0_REGNO+i] && ! call_used_regs[CR0_REGNO+i])
1266490075Sobrien	    {
1266590075Sobrien	      emit_insn (gen_movsi_to_cr_one (gen_rtx_REG (CCmode,
1266690075Sobrien							   CR0_REGNO+i),
1266790075Sobrien					      r12_rtx));
1266890075Sobrien	    }
1266990075Sobrien    }
1267090075Sobrien
1267190075Sobrien  /* If this is V.4, unwind the stack pointer after all of the loads
1267290075Sobrien     have been done.  We need to emit a block here so that sched
1267390075Sobrien     doesn't decide to move the sp change before the register restores
1267490075Sobrien     (which may not have any obvious dependency on the stack).  This
1267590075Sobrien     doesn't hurt performance, because there is no scheduling that can
1267690075Sobrien     be done after this point.  */
12677132718Skan  if (DEFAULT_ABI == ABI_V4
12678132718Skan      || current_function_calls_eh_return)
1267990075Sobrien    {
1268090075Sobrien      if (frame_reg_rtx != sp_reg_rtx)
1268190075Sobrien	  rs6000_emit_stack_tie ();
1268290075Sobrien
1268390075Sobrien      if (use_backchain_to_restore_sp)
1268490075Sobrien	{
1268590075Sobrien	  emit_move_insn (sp_reg_rtx, frame_reg_rtx);
1268690075Sobrien	}
1268790075Sobrien      else if (sp_offset != 0)
1268890075Sobrien	{
12689132718Skan	  emit_insn (TARGET_32BIT
1269090075Sobrien		     ? gen_addsi3 (sp_reg_rtx, sp_reg_rtx,
1269190075Sobrien				   GEN_INT (sp_offset))
1269290075Sobrien		     : gen_adddi3 (sp_reg_rtx, sp_reg_rtx,
1269390075Sobrien				   GEN_INT (sp_offset)));
1269490075Sobrien	}
1269590075Sobrien    }
1269690075Sobrien
1269790075Sobrien  if (current_function_calls_eh_return)
1269890075Sobrien    {
1269990075Sobrien      rtx sa = EH_RETURN_STACKADJ_RTX;
12700132718Skan      emit_insn (TARGET_32BIT
1270190075Sobrien		 ? gen_addsi3 (sp_reg_rtx, sp_reg_rtx, sa)
1270290075Sobrien		 : gen_adddi3 (sp_reg_rtx, sp_reg_rtx, sa));
1270390075Sobrien    }
1270490075Sobrien
1270590075Sobrien  if (!sibcall)
1270690075Sobrien    {
1270790075Sobrien      rtvec p;
1270890075Sobrien      if (! restoring_FPRs_inline)
1270990075Sobrien	p = rtvec_alloc (3 + 64 - info->first_fp_reg_save);
1271090075Sobrien      else
1271190075Sobrien	p = rtvec_alloc (2);
1271290075Sobrien
1271390075Sobrien      RTVEC_ELT (p, 0) = gen_rtx_RETURN (VOIDmode);
1271490075Sobrien      RTVEC_ELT (p, 1) = gen_rtx_USE (VOIDmode,
1271590075Sobrien				      gen_rtx_REG (Pmode,
1271690075Sobrien						   LINK_REGISTER_REGNUM));
1271790075Sobrien
1271890075Sobrien      /* If we have to restore more than two FP registers, branch to the
1271990075Sobrien	 restore function.  It will return to our caller.  */
1272090075Sobrien      if (! restoring_FPRs_inline)
1272190075Sobrien	{
1272290075Sobrien	  int i;
1272390075Sobrien	  char rname[30];
1272490075Sobrien	  const char *alloc_rname;
1272590075Sobrien
1272690075Sobrien	  sprintf (rname, "%s%d%s", RESTORE_FP_PREFIX,
1272790075Sobrien		   info->first_fp_reg_save - 32, RESTORE_FP_SUFFIX);
1272890075Sobrien	  alloc_rname = ggc_strdup (rname);
1272990075Sobrien	  RTVEC_ELT (p, 2) = gen_rtx_USE (VOIDmode,
1273090075Sobrien					  gen_rtx_SYMBOL_REF (Pmode,
1273190075Sobrien							      alloc_rname));
1273290075Sobrien
1273390075Sobrien	  for (i = 0; i < 64 - info->first_fp_reg_save; i++)
1273490075Sobrien	    {
1273590075Sobrien	      rtx addr, mem;
1273690075Sobrien	      addr = gen_rtx_PLUS (Pmode, sp_reg_rtx,
1273790075Sobrien				   GEN_INT (info->fp_save_offset + 8*i));
1273890075Sobrien	      mem = gen_rtx_MEM (DFmode, addr);
1273990075Sobrien	      set_mem_alias_set (mem, rs6000_sr_alias_set);
1274090075Sobrien
1274190075Sobrien	      RTVEC_ELT (p, i+3) =
1274290075Sobrien		gen_rtx_SET (VOIDmode,
1274390075Sobrien			     gen_rtx_REG (DFmode, info->first_fp_reg_save + i),
1274490075Sobrien			     mem);
1274590075Sobrien	    }
1274690075Sobrien	}
1274790075Sobrien
1274890075Sobrien      emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, p));
1274990075Sobrien    }
1275090075Sobrien}
1275190075Sobrien
1275290075Sobrien/* Write function epilogue.  */
1275390075Sobrien
1275490075Sobrienstatic void
12755132718Skanrs6000_output_function_epilogue (FILE *file,
12756132718Skan				 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
1275790075Sobrien{
1275890075Sobrien  rs6000_stack_t *info = rs6000_stack_info ();
1275990075Sobrien
1276090075Sobrien  if (! HAVE_epilogue)
1276190075Sobrien    {
1276290075Sobrien      rtx insn = get_last_insn ();
1276390075Sobrien      /* If the last insn was a BARRIER, we don't have to write anything except
1276490075Sobrien	 the trace table.  */
1276590075Sobrien      if (GET_CODE (insn) == NOTE)
1276690075Sobrien	insn = prev_nonnote_insn (insn);
1276790075Sobrien      if (insn == 0 ||  GET_CODE (insn) != BARRIER)
1276890075Sobrien	{
1276990075Sobrien	  /* This is slightly ugly, but at least we don't have two
1277090075Sobrien	     copies of the epilogue-emitting code.  */
1277190075Sobrien	  start_sequence ();
1277290075Sobrien
1277390075Sobrien	  /* A NOTE_INSN_DELETED is supposed to be at the start
1277490075Sobrien	     and end of the "toplevel" insn chain.  */
12775132718Skan	  emit_note (NOTE_INSN_DELETED);
1277690075Sobrien	  rs6000_emit_epilogue (FALSE);
12777132718Skan	  emit_note (NOTE_INSN_DELETED);
1277890075Sobrien
12779132718Skan	  /* Expand INSN_ADDRESSES so final() doesn't crash.  */
1278096263Sobrien	  {
1278196263Sobrien	    rtx insn;
1278296263Sobrien	    unsigned addr = 0;
1278396263Sobrien	    for (insn = get_insns (); insn != 0; insn = NEXT_INSN (insn))
1278496263Sobrien	      {
1278596263Sobrien		INSN_ADDRESSES_NEW (insn, addr);
1278696263Sobrien		addr += 4;
1278796263Sobrien	      }
1278896263Sobrien	  }
1278996263Sobrien
1279090075Sobrien	  if (TARGET_DEBUG_STACK)
1279190075Sobrien	    debug_rtx_list (get_insns (), 100);
1279290075Sobrien	  final (get_insns (), file, FALSE, FALSE);
1279390075Sobrien	  end_sequence ();
1279490075Sobrien	}
1279590075Sobrien    }
1279690075Sobrien
12797132718Skan#if TARGET_MACHO
12798132718Skan  macho_branch_islands ();
12799119256Skan  /* Mach-O doesn't support labels at the end of objects, so if
12800119256Skan     it looks like we might want one, insert a NOP.  */
12801119256Skan  {
12802119256Skan    rtx insn = get_last_insn ();
12803119256Skan    while (insn
12804119256Skan	   && NOTE_P (insn)
12805119256Skan	   && NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED_LABEL)
12806119256Skan      insn = PREV_INSN (insn);
12807119256Skan    if (insn
12808119256Skan	&& (LABEL_P (insn)
12809119256Skan	    || (NOTE_P (insn)
12810119256Skan		&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED_LABEL)))
12811119256Skan      fputs ("\tnop\n", file);
12812119256Skan  }
12813119256Skan#endif
12814119256Skan
1281590075Sobrien  /* Output a traceback table here.  See /usr/include/sys/debug.h for info
1281690075Sobrien     on its format.
1281790075Sobrien
1281890075Sobrien     We don't output a traceback table if -finhibit-size-directive was
1281990075Sobrien     used.  The documentation for -finhibit-size-directive reads
1282090075Sobrien     ``don't output a @code{.size} assembler directive, or anything
1282190075Sobrien     else that would cause trouble if the function is split in the
1282290075Sobrien     middle, and the two halves are placed at locations far apart in
1282390075Sobrien     memory.''  The traceback table has this property, since it
1282490075Sobrien     includes the offset from the start of the function to the
1282590075Sobrien     traceback table itself.
1282690075Sobrien
1282790075Sobrien     System V.4 Powerpc's (and the embedded ABI derived from it) use a
1282890075Sobrien     different traceback table.  */
12829117395Skan  if (DEFAULT_ABI == ABI_AIX && ! flag_inhibit_size_directive
12830117395Skan      && rs6000_traceback != traceback_none)
1283190075Sobrien    {
12832117395Skan      const char *fname = NULL;
1283390075Sobrien      const char *language_string = lang_hooks.name;
1283490075Sobrien      int fixed_parms = 0, float_parms = 0, parm_info = 0;
1283590075Sobrien      int i;
12836117395Skan      int optional_tbtab;
1283790075Sobrien
12838117395Skan      if (rs6000_traceback == traceback_full)
12839117395Skan	optional_tbtab = 1;
12840117395Skan      else if (rs6000_traceback == traceback_part)
12841117395Skan	optional_tbtab = 0;
12842117395Skan      else
12843117395Skan	optional_tbtab = !optimize_size && !TARGET_ELF;
1284490075Sobrien
12845117395Skan      if (optional_tbtab)
12846117395Skan	{
12847117395Skan	  fname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
12848117395Skan	  while (*fname == '.')	/* V.4 encodes . in the name */
12849117395Skan	    fname++;
1285090075Sobrien
12851117395Skan	  /* Need label immediately before tbtab, so we can compute
12852117395Skan	     its offset from the function start.  */
12853117395Skan	  ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "LT");
12854117395Skan	  ASM_OUTPUT_LABEL (file, fname);
12855117395Skan	}
12856117395Skan
1285790075Sobrien      /* The .tbtab pseudo-op can only be used for the first eight
1285890075Sobrien	 expressions, since it can't handle the possibly variable
1285990075Sobrien	 length fields that follow.  However, if you omit the optional
1286090075Sobrien	 fields, the assembler outputs zeros for all optional fields
1286190075Sobrien	 anyways, giving each variable length field is minimum length
1286290075Sobrien	 (as defined in sys/debug.h).  Thus we can not use the .tbtab
1286390075Sobrien	 pseudo-op at all.  */
1286490075Sobrien
1286590075Sobrien      /* An all-zero word flags the start of the tbtab, for debuggers
1286690075Sobrien	 that have to find it by searching forward from the entry
1286790075Sobrien	 point or from the current pc.  */
1286890075Sobrien      fputs ("\t.long 0\n", file);
1286990075Sobrien
1287090075Sobrien      /* Tbtab format type.  Use format type 0.  */
1287190075Sobrien      fputs ("\t.byte 0,", file);
1287290075Sobrien
12873132718Skan      /* Language type.  Unfortunately, there does not seem to be any
12874132718Skan	 official way to discover the language being compiled, so we
12875132718Skan	 use language_string.
12876132718Skan	 C is 0.  Fortran is 1.  Pascal is 2.  Ada is 3.  C++ is 9.
12877132718Skan	 Java is 13.  Objective-C is 14.  */
12878132718Skan      if (! strcmp (language_string, "GNU C"))
1287990075Sobrien	i = 0;
1288090075Sobrien      else if (! strcmp (language_string, "GNU F77"))
1288190075Sobrien	i = 1;
12882132718Skan      else if (! strcmp (language_string, "GNU Pascal"))
12883132718Skan	i = 2;
1288490075Sobrien      else if (! strcmp (language_string, "GNU Ada"))
1288590075Sobrien	i = 3;
1288690075Sobrien      else if (! strcmp (language_string, "GNU C++"))
1288790075Sobrien	i = 9;
1288890075Sobrien      else if (! strcmp (language_string, "GNU Java"))
1288990075Sobrien	i = 13;
12890132718Skan      else if (! strcmp (language_string, "GNU Objective-C"))
12891132718Skan	i = 14;
1289290075Sobrien      else
1289390075Sobrien	abort ();
1289490075Sobrien      fprintf (file, "%d,", i);
1289590075Sobrien
1289690075Sobrien      /* 8 single bit fields: global linkage (not set for C extern linkage,
1289790075Sobrien	 apparently a PL/I convention?), out-of-line epilogue/prologue, offset
1289890075Sobrien	 from start of procedure stored in tbtab, internal function, function
1289990075Sobrien	 has controlled storage, function has no toc, function uses fp,
1290090075Sobrien	 function logs/aborts fp operations.  */
1290190075Sobrien      /* Assume that fp operations are used if any fp reg must be saved.  */
1290290075Sobrien      fprintf (file, "%d,",
1290390075Sobrien	       (optional_tbtab << 5) | ((info->first_fp_reg_save != 64) << 1));
1290490075Sobrien
1290590075Sobrien      /* 6 bitfields: function is interrupt handler, name present in
1290690075Sobrien	 proc table, function calls alloca, on condition directives
1290790075Sobrien	 (controls stack walks, 3 bits), saves condition reg, saves
1290890075Sobrien	 link reg.  */
1290990075Sobrien      /* The `function calls alloca' bit seems to be set whenever reg 31 is
1291090075Sobrien	 set up as a frame pointer, even when there is no alloca call.  */
1291190075Sobrien      fprintf (file, "%d,",
1291290075Sobrien	       ((optional_tbtab << 6)
1291390075Sobrien		| ((optional_tbtab & frame_pointer_needed) << 5)
1291490075Sobrien		| (info->cr_save_p << 1)
1291590075Sobrien		| (info->lr_save_p)));
1291690075Sobrien
1291790075Sobrien      /* 3 bitfields: saves backchain, fixup code, number of fpr saved
1291890075Sobrien	 (6 bits).  */
1291990075Sobrien      fprintf (file, "%d,",
1292090075Sobrien	       (info->push_p << 7) | (64 - info->first_fp_reg_save));
1292190075Sobrien
1292290075Sobrien      /* 2 bitfields: spare bits (2 bits), number of gpr saved (6 bits).  */
1292390075Sobrien      fprintf (file, "%d,", (32 - first_reg_to_save ()));
1292490075Sobrien
1292590075Sobrien      if (optional_tbtab)
1292690075Sobrien	{
1292790075Sobrien	  /* Compute the parameter info from the function decl argument
1292890075Sobrien	     list.  */
1292990075Sobrien	  tree decl;
1293090075Sobrien	  int next_parm_info_bit = 31;
1293190075Sobrien
1293290075Sobrien	  for (decl = DECL_ARGUMENTS (current_function_decl);
1293390075Sobrien	       decl; decl = TREE_CHAIN (decl))
1293490075Sobrien	    {
1293590075Sobrien	      rtx parameter = DECL_INCOMING_RTL (decl);
1293690075Sobrien	      enum machine_mode mode = GET_MODE (parameter);
1293790075Sobrien
1293890075Sobrien	      if (GET_CODE (parameter) == REG)
1293990075Sobrien		{
1294090075Sobrien		  if (GET_MODE_CLASS (mode) == MODE_FLOAT)
1294190075Sobrien		    {
1294290075Sobrien		      int bits;
1294390075Sobrien
1294490075Sobrien		      float_parms++;
1294590075Sobrien
1294690075Sobrien		      if (mode == SFmode)
1294790075Sobrien			bits = 0x2;
12948117395Skan		      else if (mode == DFmode || mode == TFmode)
1294990075Sobrien			bits = 0x3;
1295090075Sobrien		      else
1295190075Sobrien			abort ();
1295290075Sobrien
1295390075Sobrien		      /* If only one bit will fit, don't or in this entry.  */
1295490075Sobrien		      if (next_parm_info_bit > 0)
1295590075Sobrien			parm_info |= (bits << (next_parm_info_bit - 1));
1295690075Sobrien		      next_parm_info_bit -= 2;
1295790075Sobrien		    }
1295890075Sobrien		  else
1295990075Sobrien		    {
1296090075Sobrien		      fixed_parms += ((GET_MODE_SIZE (mode)
1296190075Sobrien				       + (UNITS_PER_WORD - 1))
1296290075Sobrien				      / UNITS_PER_WORD);
1296390075Sobrien		      next_parm_info_bit -= 1;
1296490075Sobrien		    }
1296590075Sobrien		}
1296690075Sobrien	    }
1296790075Sobrien	}
1296890075Sobrien
1296990075Sobrien      /* Number of fixed point parameters.  */
1297090075Sobrien      /* This is actually the number of words of fixed point parameters; thus
1297190075Sobrien	 an 8 byte struct counts as 2; and thus the maximum value is 8.  */
1297290075Sobrien      fprintf (file, "%d,", fixed_parms);
1297390075Sobrien
1297490075Sobrien      /* 2 bitfields: number of floating point parameters (7 bits), parameters
1297590075Sobrien	 all on stack.  */
1297690075Sobrien      /* This is actually the number of fp registers that hold parameters;
1297790075Sobrien	 and thus the maximum value is 13.  */
1297890075Sobrien      /* Set parameters on stack bit if parameters are not in their original
1297990075Sobrien	 registers, regardless of whether they are on the stack?  Xlc
1298090075Sobrien	 seems to set the bit when not optimizing.  */
1298190075Sobrien      fprintf (file, "%d\n", ((float_parms << 1) | (! optimize)));
1298290075Sobrien
1298390075Sobrien      if (! optional_tbtab)
1298490075Sobrien	return;
1298590075Sobrien
1298690075Sobrien      /* Optional fields follow.  Some are variable length.  */
1298790075Sobrien
1298890075Sobrien      /* Parameter types, left adjusted bit fields: 0 fixed, 10 single float,
1298990075Sobrien	 11 double float.  */
1299090075Sobrien      /* There is an entry for each parameter in a register, in the order that
1299190075Sobrien	 they occur in the parameter list.  Any intervening arguments on the
1299290075Sobrien	 stack are ignored.  If the list overflows a long (max possible length
1299390075Sobrien	 34 bits) then completely leave off all elements that don't fit.  */
1299490075Sobrien      /* Only emit this long if there was at least one parameter.  */
1299590075Sobrien      if (fixed_parms || float_parms)
1299690075Sobrien	fprintf (file, "\t.long %d\n", parm_info);
1299790075Sobrien
1299890075Sobrien      /* Offset from start of code to tb table.  */
1299990075Sobrien      fputs ("\t.long ", file);
1300090075Sobrien      ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "LT");
1300190075Sobrien#if TARGET_AIX
1300290075Sobrien      RS6000_OUTPUT_BASENAME (file, fname);
1300390075Sobrien#else
1300490075Sobrien      assemble_name (file, fname);
1300590075Sobrien#endif
1300690075Sobrien      fputs ("-.", file);
1300790075Sobrien#if TARGET_AIX
1300890075Sobrien      RS6000_OUTPUT_BASENAME (file, fname);
1300990075Sobrien#else
1301090075Sobrien      assemble_name (file, fname);
1301190075Sobrien#endif
1301290075Sobrien      putc ('\n', file);
1301390075Sobrien
1301490075Sobrien      /* Interrupt handler mask.  */
1301590075Sobrien      /* Omit this long, since we never set the interrupt handler bit
1301690075Sobrien	 above.  */
1301790075Sobrien
1301890075Sobrien      /* Number of CTL (controlled storage) anchors.  */
1301990075Sobrien      /* Omit this long, since the has_ctl bit is never set above.  */
1302090075Sobrien
1302190075Sobrien      /* Displacement into stack of each CTL anchor.  */
1302290075Sobrien      /* Omit this list of longs, because there are no CTL anchors.  */
1302390075Sobrien
1302490075Sobrien      /* Length of function name.  */
13025117395Skan      if (*fname == '*')
13026117395Skan	++fname;
1302790075Sobrien      fprintf (file, "\t.short %d\n", (int) strlen (fname));
1302890075Sobrien
1302990075Sobrien      /* Function name.  */
1303090075Sobrien      assemble_string (fname, strlen (fname));
1303190075Sobrien
1303290075Sobrien      /* Register for alloca automatic storage; this is always reg 31.
1303390075Sobrien	 Only emit this if the alloca bit was set above.  */
1303490075Sobrien      if (frame_pointer_needed)
1303590075Sobrien	fputs ("\t.byte 31\n", file);
1303696263Sobrien
1303796263Sobrien      fputs ("\t.align 2\n", file);
1303890075Sobrien    }
1303990075Sobrien}
1304090075Sobrien
1304190075Sobrien/* A C compound statement that outputs the assembler code for a thunk
1304290075Sobrien   function, used to implement C++ virtual function calls with
1304390075Sobrien   multiple inheritance.  The thunk acts as a wrapper around a virtual
1304490075Sobrien   function, adjusting the implicit object parameter before handing
1304590075Sobrien   control off to the real function.
1304690075Sobrien
1304790075Sobrien   First, emit code to add the integer DELTA to the location that
1304890075Sobrien   contains the incoming first argument.  Assume that this argument
1304990075Sobrien   contains a pointer, and is the one used to pass the `this' pointer
1305090075Sobrien   in C++.  This is the incoming argument *before* the function
1305190075Sobrien   prologue, e.g. `%o0' on a sparc.  The addition must preserve the
1305290075Sobrien   values of all other incoming arguments.
1305390075Sobrien
1305490075Sobrien   After the addition, emit code to jump to FUNCTION, which is a
1305590075Sobrien   `FUNCTION_DECL'.  This is a direct pure jump, not a call, and does
1305690075Sobrien   not touch the return address.  Hence returning from FUNCTION will
1305790075Sobrien   return to whoever called the current `thunk'.
1305890075Sobrien
1305990075Sobrien   The effect must be as if FUNCTION had been called directly with the
1306090075Sobrien   adjusted first argument.  This macro is responsible for emitting
1306190075Sobrien   all of the code for a thunk function; output_function_prologue()
1306290075Sobrien   and output_function_epilogue() are not invoked.
1306390075Sobrien
1306490075Sobrien   The THUNK_FNDECL is redundant.  (DELTA and FUNCTION have already
1306590075Sobrien   been extracted from it.)  It might possibly be useful on some
1306690075Sobrien   targets, but probably not.
1306790075Sobrien
1306890075Sobrien   If you do not define this macro, the target-independent code in the
1306990075Sobrien   C++ frontend will generate a less efficient heavyweight thunk that
1307090075Sobrien   calls FUNCTION instead of jumping to it.  The generic approach does
1307190075Sobrien   not support varargs.  */
1307290075Sobrien
13073117395Skanstatic void
13074132718Skanrs6000_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
13075132718Skan			HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
13076132718Skan			tree function)
1307790075Sobrien{
13078132718Skan  rtx this, insn, funexp;
1307990075Sobrien
13080132718Skan  reload_completed = 1;
13081132718Skan  epilogue_completed = 1;
13082132718Skan  no_new_pseudos = 1;
1308390075Sobrien
13084132718Skan  /* Mark the end of the (empty) prologue.  */
13085132718Skan  emit_note (NOTE_INSN_PROLOGUE_END);
13086102780Skan
13087132718Skan  /* Find the "this" pointer.  If the function returns a structure,
13088132718Skan     the structure return pointer is in r3.  */
13089132718Skan  if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
13090132718Skan    this = gen_rtx_REG (Pmode, 4);
13091132718Skan  else
13092132718Skan    this = gen_rtx_REG (Pmode, 3);
1309390075Sobrien
13094132718Skan  /* Apply the constant offset, if required.  */
13095132718Skan  if (delta)
1309690075Sobrien    {
13097132718Skan      rtx delta_rtx = GEN_INT (delta);
13098132718Skan      emit_insn (TARGET_32BIT
13099132718Skan		 ? gen_addsi3 (this, this, delta_rtx)
13100132718Skan		 : gen_adddi3 (this, this, delta_rtx));
1310190075Sobrien    }
1310290075Sobrien
13103132718Skan  /* Apply the offset from the vtable, if required.  */
13104132718Skan  if (vcall_offset)
1310590075Sobrien    {
13106132718Skan      rtx vcall_offset_rtx = GEN_INT (vcall_offset);
13107132718Skan      rtx tmp = gen_rtx_REG (Pmode, 12);
1310890075Sobrien
13109132718Skan      emit_move_insn (tmp, gen_rtx_MEM (Pmode, this));
13110132718Skan      if (((unsigned HOST_WIDE_INT) vcall_offset) + 0x8000 >= 0x10000)
13111132718Skan	{
13112132718Skan	  emit_insn (TARGET_32BIT
13113132718Skan		     ? gen_addsi3 (tmp, tmp, vcall_offset_rtx)
13114132718Skan		     : gen_adddi3 (tmp, tmp, vcall_offset_rtx));
13115132718Skan	  emit_move_insn (tmp, gen_rtx_MEM (Pmode, tmp));
13116132718Skan	}
13117132718Skan      else
13118132718Skan	{
13119132718Skan	  rtx loc = gen_rtx_PLUS (Pmode, tmp, vcall_offset_rtx);
1312090075Sobrien
13121132718Skan	  emit_move_insn (tmp, gen_rtx_MEM (Pmode, loc));
13122132718Skan	}
13123132718Skan      emit_insn (TARGET_32BIT
13124132718Skan		 ? gen_addsi3 (this, this, tmp)
13125132718Skan		 : gen_adddi3 (this, this, tmp));
1312690075Sobrien    }
1312790075Sobrien
13128132718Skan  /* Generate a tail call to the target function.  */
13129132718Skan  if (!TREE_USED (function))
1313090075Sobrien    {
13131132718Skan      assemble_external (function);
13132132718Skan      TREE_USED (function) = 1;
1313390075Sobrien    }
13134132718Skan  funexp = XEXP (DECL_RTL (function), 0);
13135132718Skan  funexp = gen_rtx_MEM (FUNCTION_MODE, funexp);
1313690075Sobrien
13137132718Skan#if TARGET_MACHO
13138132718Skan  if (MACHOPIC_INDIRECT)
13139132718Skan    funexp = machopic_indirect_call_target (funexp);
13140132718Skan#endif
1314190075Sobrien
13142132718Skan  /* gen_sibcall expects reload to convert scratch pseudo to LR so we must
13143132718Skan     generate sibcall RTL explicitly to avoid constraint abort.  */
13144132718Skan  insn = emit_call_insn (
13145132718Skan	   gen_rtx_PARALLEL (VOIDmode,
13146132718Skan	     gen_rtvec (4,
13147132718Skan			gen_rtx_CALL (VOIDmode,
13148132718Skan				      funexp, const0_rtx),
13149132718Skan			gen_rtx_USE (VOIDmode, const0_rtx),
13150132718Skan			gen_rtx_USE (VOIDmode,
13151132718Skan				     gen_rtx_REG (SImode,
13152132718Skan						  LINK_REGISTER_REGNUM)),
13153132718Skan			gen_rtx_RETURN (VOIDmode))));
13154132718Skan  SIBLING_CALL_P (insn) = 1;
13155132718Skan  emit_barrier ();
1315690075Sobrien
13157132718Skan  /* Run just enough of rest_of_compilation to get the insns emitted.
13158132718Skan     There's not really enough bulk here to make other passes such as
13159132718Skan     instruction scheduling worth while.  Note that use_thunk calls
13160132718Skan     assemble_start_function and assemble_end_function.  */
13161132718Skan  insn = get_insns ();
13162132718Skan  insn_locators_initialize ();
13163132718Skan  shorten_branches (insn);
13164132718Skan  final_start_function (insn, file, 1);
13165132718Skan  final (insn, file, 1, 0);
13166132718Skan  final_end_function ();
1316790075Sobrien
13168132718Skan  reload_completed = 0;
13169132718Skan  epilogue_completed = 0;
13170132718Skan  no_new_pseudos = 0;
1317190075Sobrien}
1317290075Sobrien
1317390075Sobrien/* A quick summary of the various types of 'constant-pool tables'
1317490075Sobrien   under PowerPC:
1317590075Sobrien
1317690075Sobrien   Target	Flags		Name		One table per
1317790075Sobrien   AIX		(none)		AIX TOC		object file
1317890075Sobrien   AIX		-mfull-toc	AIX TOC		object file
1317990075Sobrien   AIX		-mminimal-toc	AIX minimal TOC	translation unit
1318090075Sobrien   SVR4/EABI	(none)		SVR4 SDATA	object file
1318190075Sobrien   SVR4/EABI	-fpic		SVR4 pic	object file
1318290075Sobrien   SVR4/EABI	-fPIC		SVR4 PIC	translation unit
1318390075Sobrien   SVR4/EABI	-mrelocatable	EABI TOC	function
1318490075Sobrien   SVR4/EABI	-maix		AIX TOC		object file
1318590075Sobrien   SVR4/EABI	-maix -mminimal-toc
1318690075Sobrien				AIX minimal TOC	translation unit
1318790075Sobrien
1318890075Sobrien   Name			Reg.	Set by	entries	      contains:
1318990075Sobrien					made by	 addrs?	fp?	sum?
1319090075Sobrien
1319190075Sobrien   AIX TOC		2	crt0	as	 Y	option	option
1319290075Sobrien   AIX minimal TOC	30	prolog	gcc	 Y	Y	option
1319390075Sobrien   SVR4 SDATA		13	crt0	gcc	 N	Y	N
1319490075Sobrien   SVR4 pic		30	prolog	ld	 Y	not yet	N
1319590075Sobrien   SVR4 PIC		30	prolog	gcc	 Y	option	option
1319690075Sobrien   EABI TOC		30	prolog	gcc	 Y	option	option
1319790075Sobrien
1319890075Sobrien*/
1319990075Sobrien
1320090075Sobrien/* Hash functions for the hash table.  */
1320190075Sobrien
1320290075Sobrienstatic unsigned
13203132718Skanrs6000_hash_constant (rtx k)
1320490075Sobrien{
13205117395Skan  enum rtx_code code = GET_CODE (k);
13206117395Skan  enum machine_mode mode = GET_MODE (k);
13207117395Skan  unsigned result = (code << 3) ^ mode;
13208117395Skan  const char *format;
13209117395Skan  int flen, fidx;
1321090075Sobrien
13211117395Skan  format = GET_RTX_FORMAT (code);
13212117395Skan  flen = strlen (format);
13213117395Skan  fidx = 0;
1321490075Sobrien
13215117395Skan  switch (code)
13216117395Skan    {
13217117395Skan    case LABEL_REF:
13218117395Skan      return result * 1231 + (unsigned) INSN_UID (XEXP (k, 0));
1321990075Sobrien
13220117395Skan    case CONST_DOUBLE:
13221117395Skan      if (mode != VOIDmode)
13222117395Skan	return real_hash (CONST_DOUBLE_REAL_VALUE (k)) * result;
13223117395Skan      flen = 2;
13224117395Skan      break;
13225117395Skan
13226117395Skan    case CODE_LABEL:
13227117395Skan      fidx = 3;
13228117395Skan      break;
13229117395Skan
13230117395Skan    default:
13231117395Skan      break;
13232117395Skan    }
13233117395Skan
1323490075Sobrien  for (; fidx < flen; fidx++)
1323590075Sobrien    switch (format[fidx])
1323690075Sobrien      {
1323790075Sobrien      case 's':
1323890075Sobrien	{
1323990075Sobrien	  unsigned i, len;
1324090075Sobrien	  const char *str = XSTR (k, fidx);
1324190075Sobrien	  len = strlen (str);
1324290075Sobrien	  result = result * 613 + len;
1324390075Sobrien	  for (i = 0; i < len; i++)
1324490075Sobrien	    result = result * 613 + (unsigned) str[i];
1324590075Sobrien	  break;
1324690075Sobrien	}
1324790075Sobrien      case 'u':
1324890075Sobrien      case 'e':
1324990075Sobrien	result = result * 1231 + rs6000_hash_constant (XEXP (k, fidx));
1325090075Sobrien	break;
1325190075Sobrien      case 'i':
1325290075Sobrien      case 'n':
1325390075Sobrien	result = result * 613 + (unsigned) XINT (k, fidx);
1325490075Sobrien	break;
1325590075Sobrien      case 'w':
1325690075Sobrien	if (sizeof (unsigned) >= sizeof (HOST_WIDE_INT))
1325790075Sobrien	  result = result * 613 + (unsigned) XWINT (k, fidx);
1325890075Sobrien	else
1325990075Sobrien	  {
1326090075Sobrien	    size_t i;
1326190075Sobrien	    for (i = 0; i < sizeof(HOST_WIDE_INT)/sizeof(unsigned); i++)
1326290075Sobrien	      result = result * 613 + (unsigned) (XWINT (k, fidx)
1326390075Sobrien						  >> CHAR_BIT * i);
1326490075Sobrien	  }
1326590075Sobrien	break;
13266132718Skan      case '0':
13267132718Skan	break;
1326890075Sobrien      default:
1326990075Sobrien	abort ();
1327090075Sobrien      }
13271117395Skan
1327290075Sobrien  return result;
1327390075Sobrien}
1327490075Sobrien
1327590075Sobrienstatic unsigned
13276132718Skantoc_hash_function (const void *hash_entry)
1327790075Sobrien{
1327890075Sobrien  const struct toc_hash_struct *thc =
1327990075Sobrien    (const struct toc_hash_struct *) hash_entry;
1328090075Sobrien  return rs6000_hash_constant (thc->key) ^ thc->key_mode;
1328190075Sobrien}
1328290075Sobrien
1328390075Sobrien/* Compare H1 and H2 for equivalence.  */
1328490075Sobrien
1328590075Sobrienstatic int
13286132718Skantoc_hash_eq (const void *h1, const void *h2)
1328790075Sobrien{
1328890075Sobrien  rtx r1 = ((const struct toc_hash_struct *) h1)->key;
1328990075Sobrien  rtx r2 = ((const struct toc_hash_struct *) h2)->key;
1329090075Sobrien
1329190075Sobrien  if (((const struct toc_hash_struct *) h1)->key_mode
1329290075Sobrien      != ((const struct toc_hash_struct *) h2)->key_mode)
1329390075Sobrien    return 0;
1329490075Sobrien
13295117395Skan  return rtx_equal_p (r1, r2);
1329690075Sobrien}
1329790075Sobrien
1329890075Sobrien/* These are the names given by the C++ front-end to vtables, and
1329990075Sobrien   vtable-like objects.  Ideally, this logic should not be here;
1330090075Sobrien   instead, there should be some programmatic way of inquiring as
1330190075Sobrien   to whether or not an object is a vtable.  */
1330290075Sobrien
1330390075Sobrien#define VTABLE_NAME_P(NAME)				\
1330490075Sobrien  (strncmp ("_vt.", name, strlen("_vt.")) == 0		\
1330590075Sobrien  || strncmp ("_ZTV", name, strlen ("_ZTV")) == 0	\
1330690075Sobrien  || strncmp ("_ZTT", name, strlen ("_ZTT")) == 0	\
13307132718Skan  || strncmp ("_ZTI", name, strlen ("_ZTI")) == 0	\
1330890075Sobrien  || strncmp ("_ZTC", name, strlen ("_ZTC")) == 0)
1330990075Sobrien
1331090075Sobrienvoid
13311132718Skanrs6000_output_symbol_ref (FILE *file, rtx x)
1331290075Sobrien{
1331390075Sobrien  /* Currently C++ toc references to vtables can be emitted before it
1331490075Sobrien     is decided whether the vtable is public or private.  If this is
1331590075Sobrien     the case, then the linker will eventually complain that there is
1331690075Sobrien     a reference to an unknown section.  Thus, for vtables only,
1331790075Sobrien     we emit the TOC reference to reference the symbol and not the
1331890075Sobrien     section.  */
1331990075Sobrien  const char *name = XSTR (x, 0);
1332090075Sobrien
1332190075Sobrien  if (VTABLE_NAME_P (name))
1332290075Sobrien    {
1332390075Sobrien      RS6000_OUTPUT_BASENAME (file, name);
1332490075Sobrien    }
1332590075Sobrien  else
1332690075Sobrien    assemble_name (file, name);
1332790075Sobrien}
1332890075Sobrien
1332990075Sobrien/* Output a TOC entry.  We derive the entry name from what is being
1333090075Sobrien   written.  */
1333190075Sobrien
1333290075Sobrienvoid
13333132718Skanoutput_toc (FILE *file, rtx x, int labelno, enum machine_mode mode)
1333490075Sobrien{
1333590075Sobrien  char buf[256];
1333690075Sobrien  const char *name = buf;
1333790075Sobrien  const char *real_name;
1333890075Sobrien  rtx base = x;
1333990075Sobrien  int offset = 0;
1334090075Sobrien
1334190075Sobrien  if (TARGET_NO_TOC)
1334290075Sobrien    abort ();
1334390075Sobrien
1334490075Sobrien  /* When the linker won't eliminate them, don't output duplicate
1334590075Sobrien     TOC entries (this happens on AIX if there is any kind of TOC,
13346132718Skan     and on SVR4 under -fPIC or -mrelocatable).  Don't do this for
13347132718Skan     CODE_LABELs.  */
13348132718Skan  if (TARGET_TOC && GET_CODE (x) != LABEL_REF)
1334990075Sobrien    {
1335090075Sobrien      struct toc_hash_struct *h;
1335190075Sobrien      void * * found;
1335290075Sobrien
13353132718Skan      /* Create toc_hash_table.  This can't be done at OVERRIDE_OPTIONS
13354132718Skan         time because GGC is not initialized at that point.  */
13355132718Skan      if (toc_hash_table == NULL)
13356132718Skan	toc_hash_table = htab_create_ggc (1021, toc_hash_function,
13357132718Skan					  toc_hash_eq, NULL);
13358132718Skan
1335990075Sobrien      h = ggc_alloc (sizeof (*h));
1336090075Sobrien      h->key = x;
1336190075Sobrien      h->key_mode = mode;
1336290075Sobrien      h->labelno = labelno;
1336390075Sobrien
1336490075Sobrien      found = htab_find_slot (toc_hash_table, h, 1);
1336590075Sobrien      if (*found == NULL)
1336690075Sobrien	*found = h;
1336790075Sobrien      else  /* This is indeed a duplicate.
1336890075Sobrien	       Set this label equal to that label.  */
1336990075Sobrien	{
1337090075Sobrien	  fputs ("\t.set ", file);
1337190075Sobrien	  ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "LC");
1337290075Sobrien	  fprintf (file, "%d,", labelno);
1337390075Sobrien	  ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "LC");
1337490075Sobrien	  fprintf (file, "%d\n", ((*(const struct toc_hash_struct **)
1337590075Sobrien					      found)->labelno));
1337690075Sobrien	  return;
1337790075Sobrien	}
1337890075Sobrien    }
1337990075Sobrien
1338090075Sobrien  /* If we're going to put a double constant in the TOC, make sure it's
1338190075Sobrien     aligned properly when strict alignment is on.  */
1338290075Sobrien  if (GET_CODE (x) == CONST_DOUBLE
1338390075Sobrien      && STRICT_ALIGNMENT
1338490075Sobrien      && GET_MODE_BITSIZE (mode) >= 64
1338590075Sobrien      && ! (TARGET_NO_FP_IN_TOC && ! TARGET_MINIMAL_TOC)) {
1338690075Sobrien    ASM_OUTPUT_ALIGN (file, 3);
1338790075Sobrien  }
1338890075Sobrien
13389132718Skan  (*targetm.asm_out.internal_label) (file, "LC", labelno);
1339090075Sobrien
1339190075Sobrien  /* Handle FP constants specially.  Note that if we have a minimal
1339290075Sobrien     TOC, things we put here aren't actually in the TOC, so we can allow
1339390075Sobrien     FP constants.  */
13394117395Skan  if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == TFmode)
1339590075Sobrien    {
1339690075Sobrien      REAL_VALUE_TYPE rv;
13397117395Skan      long k[4];
13398117395Skan
13399117395Skan      REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
13400117395Skan      REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, k);
13401117395Skan
13402117395Skan      if (TARGET_64BIT)
13403117395Skan	{
13404117395Skan	  if (TARGET_MINIMAL_TOC)
13405117395Skan	    fputs (DOUBLE_INT_ASM_OP, file);
13406117395Skan	  else
13407117395Skan	    fprintf (file, "\t.tc FT_%lx_%lx_%lx_%lx[TC],",
13408117395Skan		     k[0] & 0xffffffff, k[1] & 0xffffffff,
13409117395Skan		     k[2] & 0xffffffff, k[3] & 0xffffffff);
13410117395Skan	  fprintf (file, "0x%lx%08lx,0x%lx%08lx\n",
13411117395Skan		   k[0] & 0xffffffff, k[1] & 0xffffffff,
13412117395Skan		   k[2] & 0xffffffff, k[3] & 0xffffffff);
13413117395Skan	  return;
13414117395Skan	}
13415117395Skan      else
13416117395Skan	{
13417117395Skan	  if (TARGET_MINIMAL_TOC)
13418117395Skan	    fputs ("\t.long ", file);
13419117395Skan	  else
13420117395Skan	    fprintf (file, "\t.tc FT_%lx_%lx_%lx_%lx[TC],",
13421117395Skan		     k[0] & 0xffffffff, k[1] & 0xffffffff,
13422117395Skan		     k[2] & 0xffffffff, k[3] & 0xffffffff);
13423117395Skan	  fprintf (file, "0x%lx,0x%lx,0x%lx,0x%lx\n",
13424117395Skan		   k[0] & 0xffffffff, k[1] & 0xffffffff,
13425117395Skan		   k[2] & 0xffffffff, k[3] & 0xffffffff);
13426117395Skan	  return;
13427117395Skan	}
13428117395Skan    }
13429117395Skan  else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == DFmode)
13430117395Skan    {
13431117395Skan      REAL_VALUE_TYPE rv;
1343290075Sobrien      long k[2];
1343390075Sobrien
1343490075Sobrien      REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
1343590075Sobrien      REAL_VALUE_TO_TARGET_DOUBLE (rv, k);
1343690075Sobrien
1343790075Sobrien      if (TARGET_64BIT)
1343890075Sobrien	{
1343990075Sobrien	  if (TARGET_MINIMAL_TOC)
1344090075Sobrien	    fputs (DOUBLE_INT_ASM_OP, file);
1344190075Sobrien	  else
13442102780Skan	    fprintf (file, "\t.tc FD_%lx_%lx[TC],",
13443102780Skan		     k[0] & 0xffffffff, k[1] & 0xffffffff);
13444102780Skan	  fprintf (file, "0x%lx%08lx\n",
13445102780Skan		   k[0] & 0xffffffff, k[1] & 0xffffffff);
1344690075Sobrien	  return;
1344790075Sobrien	}
1344890075Sobrien      else
1344990075Sobrien	{
1345090075Sobrien	  if (TARGET_MINIMAL_TOC)
1345190075Sobrien	    fputs ("\t.long ", file);
1345290075Sobrien	  else
13453102780Skan	    fprintf (file, "\t.tc FD_%lx_%lx[TC],",
13454102780Skan		     k[0] & 0xffffffff, k[1] & 0xffffffff);
13455102780Skan	  fprintf (file, "0x%lx,0x%lx\n",
13456102780Skan		   k[0] & 0xffffffff, k[1] & 0xffffffff);
1345790075Sobrien	  return;
1345890075Sobrien	}
1345990075Sobrien    }
1346090075Sobrien  else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == SFmode)
1346190075Sobrien    {
1346290075Sobrien      REAL_VALUE_TYPE rv;
1346390075Sobrien      long l;
1346490075Sobrien
1346590075Sobrien      REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
1346690075Sobrien      REAL_VALUE_TO_TARGET_SINGLE (rv, l);
1346790075Sobrien
1346890075Sobrien      if (TARGET_64BIT)
1346990075Sobrien	{
1347090075Sobrien	  if (TARGET_MINIMAL_TOC)
1347190075Sobrien	    fputs (DOUBLE_INT_ASM_OP, file);
1347290075Sobrien	  else
13473102780Skan	    fprintf (file, "\t.tc FS_%lx[TC],", l & 0xffffffff);
13474102780Skan	  fprintf (file, "0x%lx00000000\n", l & 0xffffffff);
1347590075Sobrien	  return;
1347690075Sobrien	}
1347790075Sobrien      else
1347890075Sobrien	{
1347990075Sobrien	  if (TARGET_MINIMAL_TOC)
1348090075Sobrien	    fputs ("\t.long ", file);
1348190075Sobrien	  else
13482102780Skan	    fprintf (file, "\t.tc FS_%lx[TC],", l & 0xffffffff);
13483102780Skan	  fprintf (file, "0x%lx\n", l & 0xffffffff);
1348490075Sobrien	  return;
1348590075Sobrien	}
1348690075Sobrien    }
1348790075Sobrien  else if (GET_MODE (x) == VOIDmode
1348890075Sobrien	   && (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE))
1348990075Sobrien    {
1349090075Sobrien      unsigned HOST_WIDE_INT low;
1349190075Sobrien      HOST_WIDE_INT high;
1349290075Sobrien
1349390075Sobrien      if (GET_CODE (x) == CONST_DOUBLE)
1349490075Sobrien	{
1349590075Sobrien	  low = CONST_DOUBLE_LOW (x);
1349690075Sobrien	  high = CONST_DOUBLE_HIGH (x);
1349790075Sobrien	}
1349890075Sobrien      else
1349990075Sobrien#if HOST_BITS_PER_WIDE_INT == 32
1350090075Sobrien	{
1350190075Sobrien	  low = INTVAL (x);
1350290075Sobrien	  high = (low & 0x80000000) ? ~0 : 0;
1350390075Sobrien	}
1350490075Sobrien#else
1350590075Sobrien	{
1350690075Sobrien          low = INTVAL (x) & 0xffffffff;
1350790075Sobrien          high = (HOST_WIDE_INT) INTVAL (x) >> 32;
1350890075Sobrien	}
1350990075Sobrien#endif
1351090075Sobrien
1351190075Sobrien      /* TOC entries are always Pmode-sized, but since this
1351290075Sobrien	 is a bigendian machine then if we're putting smaller
1351390075Sobrien	 integer constants in the TOC we have to pad them.
1351490075Sobrien	 (This is still a win over putting the constants in
1351590075Sobrien	 a separate constant pool, because then we'd have
1351690075Sobrien	 to have both a TOC entry _and_ the actual constant.)
1351790075Sobrien
1351890075Sobrien	 For a 32-bit target, CONST_INT values are loaded and shifted
1351990075Sobrien	 entirely within `low' and can be stored in one TOC entry.  */
1352090075Sobrien
1352190075Sobrien      if (TARGET_64BIT && POINTER_SIZE < GET_MODE_BITSIZE (mode))
1352290075Sobrien	abort ();/* It would be easy to make this work, but it doesn't now.  */
1352390075Sobrien
1352490075Sobrien      if (POINTER_SIZE > GET_MODE_BITSIZE (mode))
13525103445Skan	{
13526103445Skan#if HOST_BITS_PER_WIDE_INT == 32
13527103445Skan	  lshift_double (low, high, POINTER_SIZE - GET_MODE_BITSIZE (mode),
13528103445Skan			 POINTER_SIZE, &low, &high, 0);
13529103445Skan#else
13530103445Skan	  low |= high << 32;
13531103445Skan	  low <<= POINTER_SIZE - GET_MODE_BITSIZE (mode);
13532103445Skan	  high = (HOST_WIDE_INT) low >> 32;
13533103445Skan	  low &= 0xffffffff;
13534103445Skan#endif
13535103445Skan	}
1353690075Sobrien
1353790075Sobrien      if (TARGET_64BIT)
1353890075Sobrien	{
1353990075Sobrien	  if (TARGET_MINIMAL_TOC)
1354090075Sobrien	    fputs (DOUBLE_INT_ASM_OP, file);
1354190075Sobrien	  else
13542102780Skan	    fprintf (file, "\t.tc ID_%lx_%lx[TC],",
13543102780Skan		     (long) high & 0xffffffff, (long) low & 0xffffffff);
13544102780Skan	  fprintf (file, "0x%lx%08lx\n",
13545102780Skan		   (long) high & 0xffffffff, (long) low & 0xffffffff);
1354690075Sobrien	  return;
1354790075Sobrien	}
1354890075Sobrien      else
1354990075Sobrien	{
1355090075Sobrien	  if (POINTER_SIZE < GET_MODE_BITSIZE (mode))
1355190075Sobrien	    {
1355290075Sobrien	      if (TARGET_MINIMAL_TOC)
1355390075Sobrien		fputs ("\t.long ", file);
1355490075Sobrien	      else
1355590075Sobrien		fprintf (file, "\t.tc ID_%lx_%lx[TC],",
13556102780Skan			 (long) high & 0xffffffff, (long) low & 0xffffffff);
13557102780Skan	      fprintf (file, "0x%lx,0x%lx\n",
13558102780Skan		       (long) high & 0xffffffff, (long) low & 0xffffffff);
1355990075Sobrien	    }
1356090075Sobrien	  else
1356190075Sobrien	    {
1356290075Sobrien	      if (TARGET_MINIMAL_TOC)
1356390075Sobrien		fputs ("\t.long ", file);
1356490075Sobrien	      else
13565102780Skan		fprintf (file, "\t.tc IS_%lx[TC],", (long) low & 0xffffffff);
13566102780Skan	      fprintf (file, "0x%lx\n", (long) low & 0xffffffff);
1356790075Sobrien	    }
1356890075Sobrien	  return;
1356990075Sobrien	}
1357090075Sobrien    }
1357190075Sobrien
1357290075Sobrien  if (GET_CODE (x) == CONST)
1357390075Sobrien    {
1357490075Sobrien      if (GET_CODE (XEXP (x, 0)) != PLUS)
1357590075Sobrien	abort ();
1357690075Sobrien
1357790075Sobrien      base = XEXP (XEXP (x, 0), 0);
1357890075Sobrien      offset = INTVAL (XEXP (XEXP (x, 0), 1));
1357990075Sobrien    }
1358090075Sobrien
1358190075Sobrien  if (GET_CODE (base) == SYMBOL_REF)
1358290075Sobrien    name = XSTR (base, 0);
1358390075Sobrien  else if (GET_CODE (base) == LABEL_REF)
1358490075Sobrien    ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (XEXP (base, 0)));
1358590075Sobrien  else if (GET_CODE (base) == CODE_LABEL)
1358690075Sobrien    ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (base));
1358790075Sobrien  else
1358890075Sobrien    abort ();
1358990075Sobrien
13590117395Skan  real_name = (*targetm.strip_name_encoding) (name);
1359190075Sobrien  if (TARGET_MINIMAL_TOC)
1359290075Sobrien    fputs (TARGET_32BIT ? "\t.long " : DOUBLE_INT_ASM_OP, file);
1359390075Sobrien  else
1359490075Sobrien    {
1359590075Sobrien      fprintf (file, "\t.tc %s", real_name);
1359690075Sobrien
1359790075Sobrien      if (offset < 0)
1359890075Sobrien	fprintf (file, ".N%d", - offset);
1359990075Sobrien      else if (offset)
1360090075Sobrien	fprintf (file, ".P%d", offset);
1360190075Sobrien
1360290075Sobrien      fputs ("[TC],", file);
1360390075Sobrien    }
1360490075Sobrien
1360590075Sobrien  /* Currently C++ toc references to vtables can be emitted before it
1360690075Sobrien     is decided whether the vtable is public or private.  If this is
1360790075Sobrien     the case, then the linker will eventually complain that there is
1360890075Sobrien     a TOC reference to an unknown section.  Thus, for vtables only,
1360990075Sobrien     we emit the TOC reference to reference the symbol and not the
1361090075Sobrien     section.  */
1361190075Sobrien  if (VTABLE_NAME_P (name))
1361290075Sobrien    {
1361390075Sobrien      RS6000_OUTPUT_BASENAME (file, name);
1361490075Sobrien      if (offset < 0)
1361590075Sobrien	fprintf (file, "%d", offset);
1361690075Sobrien      else if (offset > 0)
1361790075Sobrien	fprintf (file, "+%d", offset);
1361890075Sobrien    }
1361990075Sobrien  else
1362090075Sobrien    output_addr_const (file, x);
1362190075Sobrien  putc ('\n', file);
1362290075Sobrien}
1362390075Sobrien
1362490075Sobrien/* Output an assembler pseudo-op to write an ASCII string of N characters
1362590075Sobrien   starting at P to FILE.
1362690075Sobrien
1362790075Sobrien   On the RS/6000, we have to do this using the .byte operation and
1362890075Sobrien   write out special characters outside the quoted string.
1362990075Sobrien   Also, the assembler is broken; very long strings are truncated,
1363090075Sobrien   so we must artificially break them up early.  */
1363190075Sobrien
1363290075Sobrienvoid
13633132718Skanoutput_ascii (FILE *file, const char *p, int n)
1363490075Sobrien{
1363590075Sobrien  char c;
1363690075Sobrien  int i, count_string;
1363790075Sobrien  const char *for_string = "\t.byte \"";
1363890075Sobrien  const char *for_decimal = "\t.byte ";
1363990075Sobrien  const char *to_close = NULL;
1364090075Sobrien
1364190075Sobrien  count_string = 0;
1364290075Sobrien  for (i = 0; i < n; i++)
1364390075Sobrien    {
1364490075Sobrien      c = *p++;
1364590075Sobrien      if (c >= ' ' && c < 0177)
1364690075Sobrien	{
1364790075Sobrien	  if (for_string)
1364890075Sobrien	    fputs (for_string, file);
1364990075Sobrien	  putc (c, file);
1365090075Sobrien
1365190075Sobrien	  /* Write two quotes to get one.  */
1365290075Sobrien	  if (c == '"')
1365390075Sobrien	    {
1365490075Sobrien	      putc (c, file);
1365590075Sobrien	      ++count_string;
1365690075Sobrien	    }
1365790075Sobrien
1365890075Sobrien	  for_string = NULL;
1365990075Sobrien	  for_decimal = "\"\n\t.byte ";
1366090075Sobrien	  to_close = "\"\n";
1366190075Sobrien	  ++count_string;
1366290075Sobrien
1366390075Sobrien	  if (count_string >= 512)
1366490075Sobrien	    {
1366590075Sobrien	      fputs (to_close, file);
1366690075Sobrien
1366790075Sobrien	      for_string = "\t.byte \"";
1366890075Sobrien	      for_decimal = "\t.byte ";
1366990075Sobrien	      to_close = NULL;
1367090075Sobrien	      count_string = 0;
1367190075Sobrien	    }
1367290075Sobrien	}
1367390075Sobrien      else
1367490075Sobrien	{
1367590075Sobrien	  if (for_decimal)
1367690075Sobrien	    fputs (for_decimal, file);
1367790075Sobrien	  fprintf (file, "%d", c);
1367890075Sobrien
1367990075Sobrien	  for_string = "\n\t.byte \"";
1368090075Sobrien	  for_decimal = ", ";
1368190075Sobrien	  to_close = "\n";
1368290075Sobrien	  count_string = 0;
1368390075Sobrien	}
1368490075Sobrien    }
1368590075Sobrien
1368690075Sobrien  /* Now close the string if we have written one.  Then end the line.  */
1368790075Sobrien  if (to_close)
1368890075Sobrien    fputs (to_close, file);
1368990075Sobrien}
1369090075Sobrien
1369190075Sobrien/* Generate a unique section name for FILENAME for a section type
1369290075Sobrien   represented by SECTION_DESC.  Output goes into BUF.
1369390075Sobrien
1369490075Sobrien   SECTION_DESC can be any string, as long as it is different for each
1369590075Sobrien   possible section type.
1369690075Sobrien
1369790075Sobrien   We name the section in the same manner as xlc.  The name begins with an
1369890075Sobrien   underscore followed by the filename (after stripping any leading directory
1369990075Sobrien   names) with the last period replaced by the string SECTION_DESC.  If
1370090075Sobrien   FILENAME does not contain a period, SECTION_DESC is appended to the end of
1370190075Sobrien   the name.  */
1370290075Sobrien
1370390075Sobrienvoid
13704132718Skanrs6000_gen_section_name (char **buf, const char *filename,
13705132718Skan		         const char *section_desc)
1370690075Sobrien{
1370790075Sobrien  const char *q, *after_last_slash, *last_period = 0;
1370890075Sobrien  char *p;
1370990075Sobrien  int len;
1371090075Sobrien
1371190075Sobrien  after_last_slash = filename;
1371290075Sobrien  for (q = filename; *q; q++)
1371390075Sobrien    {
1371490075Sobrien      if (*q == '/')
1371590075Sobrien	after_last_slash = q + 1;
1371690075Sobrien      else if (*q == '.')
1371790075Sobrien	last_period = q;
1371890075Sobrien    }
1371990075Sobrien
1372090075Sobrien  len = strlen (after_last_slash) + strlen (section_desc) + 2;
13721117395Skan  *buf = (char *) xmalloc (len);
1372290075Sobrien
1372390075Sobrien  p = *buf;
1372490075Sobrien  *p++ = '_';
1372590075Sobrien
1372690075Sobrien  for (q = after_last_slash; *q; q++)
1372790075Sobrien    {
1372890075Sobrien      if (q == last_period)
1372990075Sobrien        {
1373090075Sobrien	  strcpy (p, section_desc);
1373190075Sobrien	  p += strlen (section_desc);
13732132718Skan	  break;
1373390075Sobrien        }
1373490075Sobrien
1373590075Sobrien      else if (ISALNUM (*q))
1373690075Sobrien        *p++ = *q;
1373790075Sobrien    }
1373890075Sobrien
1373990075Sobrien  if (last_period == 0)
1374090075Sobrien    strcpy (p, section_desc);
1374190075Sobrien  else
1374290075Sobrien    *p = '\0';
1374390075Sobrien}
1374490075Sobrien
1374590075Sobrien/* Emit profile function.  */
1374690075Sobrien
1374790075Sobrienvoid
13748132718Skanoutput_profile_hook (int labelno ATTRIBUTE_UNUSED)
1374990075Sobrien{
13750132718Skan  if (TARGET_PROFILE_KERNEL)
13751132718Skan    return;
13752132718Skan
1375390075Sobrien  if (DEFAULT_ABI == ABI_AIX)
1375490075Sobrien    {
13755132718Skan#ifndef NO_PROFILE_COUNTERS
13756132718Skan# define NO_PROFILE_COUNTERS 0
13757132718Skan#endif
13758132718Skan      if (NO_PROFILE_COUNTERS)
13759132718Skan	emit_library_call (init_one_libfunc (RS6000_MCOUNT), 0, VOIDmode, 0);
13760132718Skan      else
13761132718Skan	{
13762132718Skan	  char buf[30];
13763132718Skan	  const char *label_name;
13764132718Skan	  rtx fun;
1376590075Sobrien
13766132718Skan	  ASM_GENERATE_INTERNAL_LABEL (buf, "LP", labelno);
13767132718Skan	  label_name = (*targetm.strip_name_encoding) (ggc_strdup (buf));
13768132718Skan	  fun = gen_rtx_SYMBOL_REF (Pmode, label_name);
1376990075Sobrien
13770132718Skan	  emit_library_call (init_one_libfunc (RS6000_MCOUNT), 0, VOIDmode, 1,
13771132718Skan			     fun, Pmode);
13772132718Skan	}
1377390075Sobrien    }
1377490075Sobrien  else if (DEFAULT_ABI == ABI_DARWIN)
1377590075Sobrien    {
1377690075Sobrien      const char *mcount_name = RS6000_MCOUNT;
1377790075Sobrien      int caller_addr_regno = LINK_REGISTER_REGNUM;
1377890075Sobrien
1377990075Sobrien      /* Be conservative and always set this, at least for now.  */
1378090075Sobrien      current_function_uses_pic_offset_table = 1;
1378190075Sobrien
1378290075Sobrien#if TARGET_MACHO
1378390075Sobrien      /* For PIC code, set up a stub and collect the caller's address
1378490075Sobrien	 from r0, which is where the prologue puts it.  */
13785132718Skan      if (MACHOPIC_INDIRECT)
1378690075Sobrien	{
1378790075Sobrien	  mcount_name = machopic_stub_name (mcount_name);
1378890075Sobrien	  if (current_function_uses_pic_offset_table)
1378990075Sobrien	    caller_addr_regno = 0;
1379090075Sobrien	}
1379190075Sobrien#endif
1379290075Sobrien      emit_library_call (gen_rtx_SYMBOL_REF (Pmode, mcount_name),
1379390075Sobrien			 0, VOIDmode, 1,
1379490075Sobrien			 gen_rtx_REG (Pmode, caller_addr_regno), Pmode);
1379590075Sobrien    }
1379690075Sobrien}
1379790075Sobrien
1379890075Sobrien/* Write function profiler code.  */
1379990075Sobrien
1380090075Sobrienvoid
13801132718Skanoutput_function_profiler (FILE *file, int labelno)
1380290075Sobrien{
1380390075Sobrien  char buf[100];
13804103445Skan  int save_lr = 8;
1380590075Sobrien
1380690075Sobrien  switch (DEFAULT_ABI)
1380790075Sobrien    {
1380890075Sobrien    default:
1380990075Sobrien      abort ();
1381090075Sobrien
1381190075Sobrien    case ABI_V4:
13812103445Skan      save_lr = 4;
13813103445Skan      if (!TARGET_32BIT)
13814103445Skan	{
13815103445Skan	  warning ("no profiling of 64-bit code for this ABI");
13816103445Skan	  return;
13817103445Skan	}
13818132718Skan      ASM_GENERATE_INTERNAL_LABEL (buf, "LP", labelno);
1381990075Sobrien      fprintf (file, "\tmflr %s\n", reg_names[0]);
1382090075Sobrien      if (flag_pic == 1)
1382190075Sobrien	{
1382290075Sobrien	  fputs ("\tbl _GLOBAL_OFFSET_TABLE_@local-4\n", file);
13823103445Skan	  asm_fprintf (file, "\t{st|stw} %s,%d(%s)\n",
13824103445Skan		       reg_names[0], save_lr, reg_names[1]);
1382590075Sobrien	  asm_fprintf (file, "\tmflr %s\n", reg_names[12]);
1382690075Sobrien	  asm_fprintf (file, "\t{l|lwz} %s,", reg_names[0]);
1382790075Sobrien	  assemble_name (file, buf);
1382890075Sobrien	  asm_fprintf (file, "@got(%s)\n", reg_names[12]);
1382990075Sobrien	}
1383090075Sobrien      else if (flag_pic > 1)
1383190075Sobrien	{
13832103445Skan	  asm_fprintf (file, "\t{st|stw} %s,%d(%s)\n",
13833103445Skan		       reg_names[0], save_lr, reg_names[1]);
1383490075Sobrien	  /* Now, we need to get the address of the label.  */
1383590075Sobrien	  fputs ("\tbl 1f\n\t.long ", file);
1383690075Sobrien	  assemble_name (file, buf);
1383790075Sobrien	  fputs ("-.\n1:", file);
1383890075Sobrien	  asm_fprintf (file, "\tmflr %s\n", reg_names[11]);
1383990075Sobrien	  asm_fprintf (file, "\t{l|lwz} %s,0(%s)\n",
1384090075Sobrien		       reg_names[0], reg_names[11]);
1384190075Sobrien	  asm_fprintf (file, "\t{cax|add} %s,%s,%s\n",
1384290075Sobrien		       reg_names[0], reg_names[0], reg_names[11]);
1384390075Sobrien	}
1384490075Sobrien      else
1384590075Sobrien	{
1384690075Sobrien	  asm_fprintf (file, "\t{liu|lis} %s,", reg_names[12]);
1384790075Sobrien	  assemble_name (file, buf);
1384890075Sobrien	  fputs ("@ha\n", file);
13849103445Skan	  asm_fprintf (file, "\t{st|stw} %s,%d(%s)\n",
13850103445Skan		       reg_names[0], save_lr, reg_names[1]);
1385190075Sobrien	  asm_fprintf (file, "\t{cal|la} %s,", reg_names[0]);
1385290075Sobrien	  assemble_name (file, buf);
1385390075Sobrien	  asm_fprintf (file, "@l(%s)\n", reg_names[12]);
1385490075Sobrien	}
1385590075Sobrien
13856132718Skan      /* ABI_V4 saves the static chain reg with ASM_OUTPUT_REG_PUSH.  */
13857132718Skan      fprintf (file, "\tbl %s%s\n",
13858132718Skan	       RS6000_MCOUNT, flag_pic ? "@plt" : "");
13859132718Skan
13860132718Skan      break;
13861132718Skan
13862132718Skan    case ABI_AIX:
13863132718Skan    case ABI_DARWIN:
13864132718Skan      if (!TARGET_PROFILE_KERNEL)
13865103445Skan	{
13866132718Skan	  /* Don't do anything, done in output_profile_hook ().  */
13867103445Skan	}
13868103445Skan      else
13869132718Skan	{
13870132718Skan	  if (TARGET_32BIT)
13871132718Skan	    abort ();
1387290075Sobrien
13873132718Skan	  asm_fprintf (file, "\tmflr %s\n", reg_names[0]);
13874132718Skan	  asm_fprintf (file, "\tstd %s,16(%s)\n", reg_names[0], reg_names[1]);
13875132718Skan
13876132718Skan	  if (current_function_needs_context)
13877132718Skan	    {
13878132718Skan	      asm_fprintf (file, "\tstd %s,24(%s)\n",
13879132718Skan			   reg_names[STATIC_CHAIN_REGNUM], reg_names[1]);
13880132718Skan	      fprintf (file, "\tbl %s\n", RS6000_MCOUNT);
13881132718Skan	      asm_fprintf (file, "\tld %s,24(%s)\n",
13882132718Skan			   reg_names[STATIC_CHAIN_REGNUM], reg_names[1]);
13883132718Skan	    }
13884132718Skan	  else
13885132718Skan	    fprintf (file, "\tbl %s\n", RS6000_MCOUNT);
13886132718Skan	}
1388790075Sobrien      break;
1388890075Sobrien    }
1388990075Sobrien}
1389090075Sobrien
13891132718Skan
13892132718Skanstatic int
13893132718Skanrs6000_use_dfa_pipeline_interface (void)
13894132718Skan{
13895132718Skan  return 1;
13896132718Skan}
13897132718Skan
13898132718Skan/* Power4 load update and store update instructions are cracked into a
13899132718Skan   load or store and an integer insn which are executed in the same cycle.
13900132718Skan   Branches have their own dispatch slot which does not count against the
13901132718Skan   GCC issue rate, but it changes the program flow so there are no other
13902132718Skan   instructions to issue in this cycle.  */
13903132718Skan
13904132718Skanstatic int
13905132718Skanrs6000_variable_issue (FILE *stream ATTRIBUTE_UNUSED,
13906132718Skan		       int verbose ATTRIBUTE_UNUSED,
13907132718Skan		       rtx insn, int more)
13908132718Skan{
13909132718Skan  if (GET_CODE (PATTERN (insn)) == USE
13910132718Skan      || GET_CODE (PATTERN (insn)) == CLOBBER)
13911132718Skan    return more;
13912132718Skan
13913132718Skan  if (rs6000_sched_groups)
13914132718Skan    {
13915132718Skan      if (is_microcoded_insn (insn))
13916132718Skan        return 0;
13917132718Skan      else if (is_cracked_insn (insn))
13918132718Skan        return more > 2 ? more - 2 : 0;
13919132718Skan    }
13920132718Skan
13921132718Skan  return more - 1;
13922132718Skan}
13923132718Skan
1392490075Sobrien/* Adjust the cost of a scheduling dependency.  Return the new cost of
1392590075Sobrien   a dependency LINK or INSN on DEP_INSN.  COST is the current cost.  */
1392690075Sobrien
1392790075Sobrienstatic int
13928132718Skanrs6000_adjust_cost (rtx insn, rtx link, rtx dep_insn ATTRIBUTE_UNUSED,
13929132718Skan		    int cost)
1393090075Sobrien{
1393190075Sobrien  if (! recog_memoized (insn))
1393290075Sobrien    return 0;
1393390075Sobrien
1393490075Sobrien  if (REG_NOTE_KIND (link) != 0)
1393590075Sobrien    return 0;
1393690075Sobrien
1393790075Sobrien  if (REG_NOTE_KIND (link) == 0)
1393890075Sobrien    {
1393990075Sobrien      /* Data dependency; DEP_INSN writes a register that INSN reads
1394090075Sobrien	 some cycles later.  */
1394190075Sobrien      switch (get_attr_type (insn))
1394290075Sobrien	{
1394390075Sobrien	case TYPE_JMPREG:
13944117395Skan	  /* Tell the first scheduling pass about the latency between
1394590075Sobrien	     a mtctr and bctr (and mtlr and br/blr).  The first
1394690075Sobrien	     scheduling pass will not know about this latency since
1394790075Sobrien	     the mtctr instruction, which has the latency associated
1394890075Sobrien	     to it, will be generated by reload.  */
13949117395Skan	  return TARGET_POWER ? 5 : 4;
1395090075Sobrien	case TYPE_BRANCH:
1395190075Sobrien	  /* Leave some extra cycles between a compare and its
1395290075Sobrien	     dependent branch, to inhibit expensive mispredicts.  */
13953117395Skan	  if ((rs6000_cpu_attr == CPU_PPC603
13954117395Skan	       || rs6000_cpu_attr == CPU_PPC604
13955117395Skan	       || rs6000_cpu_attr == CPU_PPC604E
13956117395Skan	       || rs6000_cpu_attr == CPU_PPC620
13957117395Skan	       || rs6000_cpu_attr == CPU_PPC630
13958117395Skan	       || rs6000_cpu_attr == CPU_PPC750
13959117395Skan	       || rs6000_cpu_attr == CPU_PPC7400
13960117395Skan	       || rs6000_cpu_attr == CPU_PPC7450
13961132718Skan	       || rs6000_cpu_attr == CPU_POWER4
13962132718Skan	       || rs6000_cpu_attr == CPU_POWER5)
1396390075Sobrien	      && recog_memoized (dep_insn)
1396490075Sobrien	      && (INSN_CODE (dep_insn) >= 0)
13965132718Skan	      && (get_attr_type (dep_insn) == TYPE_CMP
13966132718Skan		  || get_attr_type (dep_insn) == TYPE_COMPARE
1396790075Sobrien		  || get_attr_type (dep_insn) == TYPE_DELAYED_COMPARE
13968132718Skan		  || get_attr_type (dep_insn) == TYPE_IMUL_COMPARE
13969132718Skan		  || get_attr_type (dep_insn) == TYPE_LMUL_COMPARE
1397090075Sobrien		  || get_attr_type (dep_insn) == TYPE_FPCOMPARE
13971132718Skan		  || get_attr_type (dep_insn) == TYPE_CR_LOGICAL
13972132718Skan		  || get_attr_type (dep_insn) == TYPE_DELAYED_CR))
1397390075Sobrien	    return cost + 2;
1397490075Sobrien	default:
1397590075Sobrien	  break;
1397690075Sobrien	}
1397790075Sobrien      /* Fall out to return default cost.  */
1397890075Sobrien    }
1397990075Sobrien
1398090075Sobrien  return cost;
1398190075Sobrien}
1398290075Sobrien
13983132718Skan/* The function returns a true if INSN is microcoded.
13984132718Skan   Return false otherwise.  */
13985132718Skan
13986132718Skanstatic bool
13987132718Skanis_microcoded_insn (rtx insn)
13988132718Skan{
13989132718Skan  if (!insn || !INSN_P (insn)
13990132718Skan      || GET_CODE (PATTERN (insn)) == USE
13991132718Skan      || GET_CODE (PATTERN (insn)) == CLOBBER)
13992132718Skan    return false;
13993132718Skan
13994132718Skan  if (rs6000_sched_groups)
13995132718Skan    {
13996132718Skan      enum attr_type type = get_attr_type (insn);
13997132718Skan      if (type == TYPE_LOAD_EXT_U
13998132718Skan	  || type == TYPE_LOAD_EXT_UX
13999132718Skan	  || type == TYPE_LOAD_UX
14000132718Skan	  || type == TYPE_STORE_UX
14001132718Skan	  || type == TYPE_MFCR)
14002132718Skan        return true;
14003132718Skan    }
14004132718Skan
14005132718Skan  return false;
14006132718Skan}
14007132718Skan
14008132718Skan/* The function returns a nonzero value if INSN can be scheduled only
14009132718Skan   as the first insn in a dispatch group ("dispatch-slot restricted").
14010132718Skan   In this case, the returned value indicates how many dispatch slots
14011132718Skan   the insn occupies (at the beginning of the group).
14012132718Skan   Return 0 otherwise.  */
14013132718Skan
14014132718Skanstatic int
14015132718Skanis_dispatch_slot_restricted (rtx insn)
14016132718Skan{
14017132718Skan  enum attr_type type;
14018132718Skan
14019132718Skan  if (!rs6000_sched_groups)
14020132718Skan    return 0;
14021132718Skan
14022132718Skan  if (!insn
14023132718Skan      || insn == NULL_RTX
14024132718Skan      || GET_CODE (insn) == NOTE
14025132718Skan      || GET_CODE (PATTERN (insn)) == USE
14026132718Skan      || GET_CODE (PATTERN (insn)) == CLOBBER)
14027132718Skan    return 0;
14028132718Skan
14029132718Skan  type = get_attr_type (insn);
14030132718Skan
14031132718Skan  switch (type)
14032132718Skan    {
14033132718Skan    case TYPE_MFCR:
14034132718Skan    case TYPE_MFCRF:
14035132718Skan    case TYPE_MTCR:
14036132718Skan    case TYPE_DELAYED_CR:
14037132718Skan    case TYPE_CR_LOGICAL:
14038132718Skan    case TYPE_MTJMPR:
14039132718Skan    case TYPE_MFJMPR:
14040132718Skan      return 1;
14041132718Skan    case TYPE_IDIV:
14042132718Skan    case TYPE_LDIV:
14043132718Skan      return 2;
14044132718Skan    default:
14045132718Skan      if (rs6000_cpu == PROCESSOR_POWER5
14046132718Skan	  && is_cracked_insn (insn))
14047132718Skan	return 2;
14048132718Skan      return 0;
14049132718Skan    }
14050132718Skan}
14051132718Skan
14052132718Skan/* The function returns true if INSN is cracked into 2 instructions
14053132718Skan   by the processor (and therefore occupies 2 issue slots).  */
14054132718Skan
14055132718Skanstatic bool
14056132718Skanis_cracked_insn (rtx insn)
14057132718Skan{
14058132718Skan  if (!insn || !INSN_P (insn)
14059132718Skan      || GET_CODE (PATTERN (insn)) == USE
14060132718Skan      || GET_CODE (PATTERN (insn)) == CLOBBER)
14061132718Skan    return false;
14062132718Skan
14063132718Skan  if (rs6000_sched_groups)
14064132718Skan    {
14065132718Skan      enum attr_type type = get_attr_type (insn);
14066132718Skan      if (type == TYPE_LOAD_U || type == TYPE_STORE_U
14067132718Skan	       || type == TYPE_FPLOAD_U || type == TYPE_FPSTORE_U
14068132718Skan	       || type == TYPE_FPLOAD_UX || type == TYPE_FPSTORE_UX
14069132718Skan	       || type == TYPE_LOAD_EXT || type == TYPE_DELAYED_CR
14070132718Skan	       || type == TYPE_COMPARE || type == TYPE_DELAYED_COMPARE
14071132718Skan	       || type == TYPE_IMUL_COMPARE || type == TYPE_LMUL_COMPARE
14072132718Skan	       || type == TYPE_IDIV || type == TYPE_LDIV
14073132718Skan	       || type == TYPE_INSERT_WORD)
14074132718Skan        return true;
14075132718Skan    }
14076132718Skan
14077132718Skan  return false;
14078132718Skan}
14079132718Skan
14080132718Skan/* The function returns true if INSN can be issued only from
14081132718Skan   the branch slot.  */
14082132718Skan
14083132718Skanstatic bool
14084132718Skanis_branch_slot_insn (rtx insn)
14085132718Skan{
14086132718Skan  if (!insn || !INSN_P (insn)
14087132718Skan      || GET_CODE (PATTERN (insn)) == USE
14088132718Skan      || GET_CODE (PATTERN (insn)) == CLOBBER)
14089132718Skan    return false;
14090132718Skan
14091132718Skan  if (rs6000_sched_groups)
14092132718Skan    {
14093132718Skan      enum attr_type type = get_attr_type (insn);
14094132718Skan      if (type == TYPE_BRANCH || type == TYPE_JMPREG)
14095132718Skan	return true;
14096132718Skan      return false;
14097132718Skan    }
14098132718Skan
14099132718Skan  return false;
14100132718Skan}
14101132718Skan
1410290075Sobrien/* A C statement (sans semicolon) to update the integer scheduling
14103132718Skan   priority INSN_PRIORITY (INSN). Increase the priority to execute the
14104132718Skan   INSN earlier, reduce the priority to execute INSN later.  Do not
1410590075Sobrien   define this macro if you do not need to adjust the scheduling
1410690075Sobrien   priorities of insns.  */
1410790075Sobrien
1410890075Sobrienstatic int
14109132718Skanrs6000_adjust_priority (rtx insn ATTRIBUTE_UNUSED, int priority)
1411090075Sobrien{
1411190075Sobrien  /* On machines (like the 750) which have asymmetric integer units,
1411290075Sobrien     where one integer unit can do multiply and divides and the other
1411390075Sobrien     can't, reduce the priority of multiply/divide so it is scheduled
1411490075Sobrien     before other integer operations.  */
1411590075Sobrien
1411690075Sobrien#if 0
1411790075Sobrien  if (! INSN_P (insn))
1411890075Sobrien    return priority;
1411990075Sobrien
1412090075Sobrien  if (GET_CODE (PATTERN (insn)) == USE)
1412190075Sobrien    return priority;
1412290075Sobrien
1412390075Sobrien  switch (rs6000_cpu_attr) {
1412490075Sobrien  case CPU_PPC750:
1412590075Sobrien    switch (get_attr_type (insn))
1412690075Sobrien      {
1412790075Sobrien      default:
1412890075Sobrien	break;
1412990075Sobrien
1413090075Sobrien      case TYPE_IMUL:
1413190075Sobrien      case TYPE_IDIV:
1413290075Sobrien	fprintf (stderr, "priority was %#x (%d) before adjustment\n",
1413390075Sobrien		 priority, priority);
1413490075Sobrien	if (priority >= 0 && priority < 0x01000000)
1413590075Sobrien	  priority >>= 3;
1413690075Sobrien	break;
1413790075Sobrien      }
1413890075Sobrien  }
1413990075Sobrien#endif
1414090075Sobrien
14141132718Skan  if (is_dispatch_slot_restricted (insn)
14142132718Skan      && reload_completed
14143132718Skan      && current_sched_info->sched_max_insns_priority
14144132718Skan      && rs6000_sched_restricted_insns_priority)
14145132718Skan    {
14146132718Skan
14147132718Skan      /* Prioritize insns that can be dispatched only in the first dispatch slot.  */
14148132718Skan      if (rs6000_sched_restricted_insns_priority == 1)
14149132718Skan	/* Attach highest priority to insn. This means that in
14150132718Skan	   haifa-sched.c:ready_sort(), dispatch-slot restriction considerations
14151132718Skan	   precede 'priority' (critical path) considerations.  */
14152132718Skan	return current_sched_info->sched_max_insns_priority;
14153132718Skan      else if (rs6000_sched_restricted_insns_priority == 2)
14154132718Skan	/* Increase priority of insn by a minimal amount. This means that in
14155132718Skan	   haifa-sched.c:ready_sort(), only 'priority' (critical path) considerations
14156132718Skan	   precede dispatch-slot restriction considerations.  */
14157132718Skan	return (priority + 1);
14158132718Skan    }
14159132718Skan
1416090075Sobrien  return priority;
1416190075Sobrien}
1416290075Sobrien
1416390075Sobrien/* Return how many instructions the machine can issue per cycle.  */
1416490075Sobrien
1416590075Sobrienstatic int
14166132718Skanrs6000_issue_rate (void)
1416790075Sobrien{
14168132718Skan  /* Use issue rate of 1 for first scheduling pass to decrease degradation.  */
14169132718Skan  if (!reload_completed)
14170132718Skan    return 1;
14171132718Skan
1417290075Sobrien  switch (rs6000_cpu_attr) {
1417390075Sobrien  case CPU_RIOS1:  /* ? */
1417490075Sobrien  case CPU_RS64A:
1417590075Sobrien  case CPU_PPC601: /* ? */
1417690075Sobrien  case CPU_PPC7450:
1417790075Sobrien    return 3;
14178132718Skan  case CPU_PPC440:
1417990075Sobrien  case CPU_PPC603:
1418090075Sobrien  case CPU_PPC750:
1418190075Sobrien  case CPU_PPC7400:
14182132718Skan  case CPU_PPC8540:
1418390075Sobrien    return 2;
1418490075Sobrien  case CPU_RIOS2:
1418590075Sobrien  case CPU_PPC604:
1418690075Sobrien  case CPU_PPC604E:
1418790075Sobrien  case CPU_PPC620:
1418890075Sobrien  case CPU_PPC630:
14189132718Skan    return 4;
14190117395Skan  case CPU_POWER4:
14191132718Skan  case CPU_POWER5:
14192132718Skan    return 5;
1419390075Sobrien  default:
1419490075Sobrien    return 1;
1419590075Sobrien  }
1419690075Sobrien}
1419790075Sobrien
14198132718Skan/* Return how many instructions to look ahead for better insn
14199132718Skan   scheduling.  */
14200132718Skan
14201132718Skanstatic int
14202132718Skanrs6000_use_sched_lookahead (void)
14203132718Skan{
14204132718Skan  if (rs6000_cpu_attr == CPU_PPC8540)
14205132718Skan    return 4;
14206132718Skan  return 0;
14207132718Skan}
14208132718Skan
14209132718Skan/* Determine is PAT refers to memory.  */
14210132718Skan
14211132718Skanstatic bool
14212132718Skanis_mem_ref (rtx pat)
14213132718Skan{
14214132718Skan  const char * fmt;
14215132718Skan  int i, j;
14216132718Skan  bool ret = false;
14217132718Skan
14218132718Skan  if (GET_CODE (pat) == MEM)
14219132718Skan    return true;
14220132718Skan
14221132718Skan  /* Recursively process the pattern.  */
14222132718Skan  fmt = GET_RTX_FORMAT (GET_CODE (pat));
14223132718Skan
14224132718Skan  for (i = GET_RTX_LENGTH (GET_CODE (pat)) - 1; i >= 0 && !ret; i--)
14225132718Skan    {
14226132718Skan      if (fmt[i] == 'e')
14227132718Skan	ret |= is_mem_ref (XEXP (pat, i));
14228132718Skan      else if (fmt[i] == 'E')
14229132718Skan	for (j = XVECLEN (pat, i) - 1; j >= 0; j--)
14230132718Skan	  ret |= is_mem_ref (XVECEXP (pat, i, j));
14231132718Skan    }
14232132718Skan
14233132718Skan  return ret;
14234132718Skan}
14235132718Skan
14236132718Skan/* Determine if PAT is a PATTERN of a load insn.  */
14237132718Skan
14238132718Skanstatic bool
14239132718Skanis_load_insn1 (rtx pat)
14240132718Skan{
14241132718Skan  if (!pat || pat == NULL_RTX)
14242132718Skan    return false;
14243132718Skan
14244132718Skan  if (GET_CODE (pat) == SET)
14245132718Skan    return is_mem_ref (SET_SRC (pat));
14246132718Skan
14247132718Skan  if (GET_CODE (pat) == PARALLEL)
14248132718Skan    {
14249132718Skan      int i;
14250132718Skan
14251132718Skan      for (i = 0; i < XVECLEN (pat, 0); i++)
14252132718Skan	if (is_load_insn1 (XVECEXP (pat, 0, i)))
14253132718Skan	  return true;
14254132718Skan    }
14255132718Skan
14256132718Skan  return false;
14257132718Skan}
14258132718Skan
14259132718Skan/* Determine if INSN loads from memory.  */
14260132718Skan
14261132718Skanstatic bool
14262132718Skanis_load_insn (rtx insn)
14263132718Skan{
14264132718Skan  if (!insn || !INSN_P (insn))
14265132718Skan    return false;
14266132718Skan
14267132718Skan  if (GET_CODE (insn) == CALL_INSN)
14268132718Skan    return false;
14269132718Skan
14270132718Skan  return is_load_insn1 (PATTERN (insn));
14271132718Skan}
14272132718Skan
14273132718Skan/* Determine if PAT is a PATTERN of a store insn.  */
14274132718Skan
14275132718Skanstatic bool
14276132718Skanis_store_insn1 (rtx pat)
14277132718Skan{
14278132718Skan  if (!pat || pat == NULL_RTX)
14279132718Skan    return false;
14280132718Skan
14281132718Skan  if (GET_CODE (pat) == SET)
14282132718Skan    return is_mem_ref (SET_DEST (pat));
14283132718Skan
14284132718Skan  if (GET_CODE (pat) == PARALLEL)
14285132718Skan    {
14286132718Skan      int i;
14287132718Skan
14288132718Skan      for (i = 0; i < XVECLEN (pat, 0); i++)
14289132718Skan	if (is_store_insn1 (XVECEXP (pat, 0, i)))
14290132718Skan	  return true;
14291132718Skan    }
14292132718Skan
14293132718Skan  return false;
14294132718Skan}
14295132718Skan
14296132718Skan/* Determine if INSN stores to memory.  */
14297132718Skan
14298132718Skanstatic bool
14299132718Skanis_store_insn (rtx insn)
14300132718Skan{
14301132718Skan  if (!insn || !INSN_P (insn))
14302132718Skan    return false;
14303132718Skan
14304132718Skan  return is_store_insn1 (PATTERN (insn));
14305132718Skan}
14306132718Skan
14307132718Skan/* Returns whether the dependence between INSN and NEXT is considered
14308132718Skan   costly by the given target.  */
14309132718Skan
14310132718Skanstatic bool
14311132718Skanrs6000_is_costly_dependence (rtx insn, rtx next, rtx link, int cost, int distance)
14312132718Skan{
14313132718Skan  /* If the flag is not enbled - no dependence is considered costly;
14314132718Skan     allow all dependent insns in the same group.
14315132718Skan     This is the most aggressive option.  */
14316132718Skan  if (rs6000_sched_costly_dep == no_dep_costly)
14317132718Skan    return false;
14318132718Skan
14319132718Skan  /* If the flag is set to 1 - a dependence is always considered costly;
14320132718Skan     do not allow dependent instructions in the same group.
14321132718Skan     This is the most conservative option.  */
14322132718Skan  if (rs6000_sched_costly_dep == all_deps_costly)
14323132718Skan    return true;
14324132718Skan
14325132718Skan  if (rs6000_sched_costly_dep == store_to_load_dep_costly
14326132718Skan      && is_load_insn (next)
14327132718Skan      && is_store_insn (insn))
14328132718Skan    /* Prevent load after store in the same group.  */
14329132718Skan    return true;
14330132718Skan
14331132718Skan  if (rs6000_sched_costly_dep == true_store_to_load_dep_costly
14332132718Skan      && is_load_insn (next)
14333132718Skan      && is_store_insn (insn)
14334132718Skan      && (!link || (int) REG_NOTE_KIND (link) == 0))
14335132718Skan     /* Prevent load after store in the same group if it is a true dependence.  */
14336132718Skan     return true;
14337132718Skan
14338132718Skan  /* The flag is set to X; dependences with latency >= X are considered costly,
14339132718Skan     and will not be scheduled in the same group.  */
14340132718Skan  if (rs6000_sched_costly_dep <= max_dep_latency
14341132718Skan      && ((cost - distance) >= (int)rs6000_sched_costly_dep))
14342132718Skan    return true;
14343132718Skan
14344132718Skan  return false;
14345132718Skan}
14346132718Skan
14347132718Skan/* Return the next insn after INSN that is found before TAIL is reached,
14348132718Skan   skipping any "non-active" insns - insns that will not actually occupy
14349132718Skan   an issue slot.  Return NULL_RTX if such an insn is not found.  */
14350132718Skan
14351132718Skanstatic rtx
14352132718Skanget_next_active_insn (rtx insn, rtx tail)
14353132718Skan{
14354132718Skan  rtx next_insn;
14355132718Skan
14356132718Skan  if (!insn || insn == tail)
14357132718Skan    return NULL_RTX;
14358132718Skan
14359132718Skan  next_insn = NEXT_INSN (insn);
14360132718Skan
14361132718Skan  while (next_insn
14362132718Skan  	 && next_insn != tail
14363132718Skan	 && (GET_CODE(next_insn) == NOTE
14364132718Skan	     || GET_CODE (PATTERN (next_insn)) == USE
14365132718Skan	     || GET_CODE (PATTERN (next_insn)) == CLOBBER))
14366132718Skan    {
14367132718Skan      next_insn = NEXT_INSN (next_insn);
14368132718Skan    }
14369132718Skan
14370132718Skan  if (!next_insn || next_insn == tail)
14371132718Skan    return NULL_RTX;
14372132718Skan
14373132718Skan  return next_insn;
14374132718Skan}
14375132718Skan
14376132718Skan/* Return whether the presence of INSN causes a dispatch group termination
14377132718Skan   of group WHICH_GROUP.
14378132718Skan
14379132718Skan   If WHICH_GROUP == current_group, this function will return true if INSN
14380132718Skan   causes the termination of the current group (i.e, the dispatch group to
14381132718Skan   which INSN belongs). This means that INSN will be the last insn in the
14382132718Skan   group it belongs to.
14383132718Skan
14384132718Skan   If WHICH_GROUP == previous_group, this function will return true if INSN
14385132718Skan   causes the termination of the previous group (i.e, the dispatch group that
14386132718Skan   precedes the group to which INSN belongs).  This means that INSN will be
14387132718Skan   the first insn in the group it belongs to).  */
14388132718Skan
14389132718Skanstatic bool
14390132718Skaninsn_terminates_group_p (rtx insn, enum group_termination which_group)
14391132718Skan{
14392132718Skan  enum attr_type type;
14393132718Skan
14394132718Skan  if (! insn)
14395132718Skan    return false;
14396132718Skan
14397132718Skan  type = get_attr_type (insn);
14398132718Skan
14399132718Skan  if (is_microcoded_insn (insn))
14400132718Skan    return true;
14401132718Skan
14402132718Skan  if (which_group == current_group)
14403132718Skan    {
14404132718Skan      if (is_branch_slot_insn (insn))
14405132718Skan        return true;
14406132718Skan      return false;
14407132718Skan    }
14408132718Skan  else if (which_group == previous_group)
14409132718Skan    {
14410132718Skan      if (is_dispatch_slot_restricted (insn))
14411132718Skan        return true;
14412132718Skan      return false;
14413132718Skan    }
14414132718Skan
14415132718Skan  return false;
14416132718Skan}
14417132718Skan
14418132718Skan/* Return true if it is recommended to keep NEXT_INSN "far" (in a separate
14419132718Skan   dispatch group) from the insns in GROUP_INSNS.  Return false otherwise.  */
14420132718Skan
14421132718Skanstatic bool
14422132718Skanis_costly_group (rtx *group_insns, rtx next_insn)
14423132718Skan{
14424132718Skan  int i;
14425132718Skan  rtx link;
14426132718Skan  int cost;
14427132718Skan  int issue_rate = rs6000_issue_rate ();
14428132718Skan
14429132718Skan  for (i = 0; i < issue_rate; i++)
14430132718Skan    {
14431132718Skan      rtx insn = group_insns[i];
14432132718Skan      if (!insn)
14433132718Skan        continue;
14434132718Skan      for (link = INSN_DEPEND (insn); link != 0; link = XEXP (link, 1))
14435132718Skan        {
14436132718Skan          rtx next = XEXP (link, 0);
14437132718Skan          if (next == next_insn)
14438132718Skan            {
14439132718Skan              cost = insn_cost (insn, link, next_insn);
14440132718Skan              if (rs6000_is_costly_dependence (insn, next_insn, link, cost, 0))
14441132718Skan                return true;
14442132718Skan            }
14443132718Skan        }
14444132718Skan    }
14445132718Skan
14446132718Skan  return false;
14447132718Skan}
14448132718Skan
14449132718Skan/* Utility of the function redefine_groups.
14450132718Skan   Check if it is too costly to schedule NEXT_INSN together with GROUP_INSNS
14451132718Skan   in the same dispatch group.  If so, insert nops before NEXT_INSN, in order
14452132718Skan   to keep it "far" (in a separate group) from GROUP_INSNS, following
14453132718Skan   one of the following schemes, depending on the value of the flag
14454132718Skan   -minsert_sched_nops = X:
14455132718Skan   (1) X == sched_finish_regroup_exact: insert exactly as many nops as needed
14456132718Skan       in order to force NEXT_INSN into a separate group.
14457132718Skan   (2) X < sched_finish_regroup_exact: insert exactly X nops.
14458132718Skan   GROUP_END, CAN_ISSUE_MORE and GROUP_COUNT record the state after nop
14459132718Skan   insertion (has a group just ended, how many vacant issue slots remain in the
14460132718Skan   last group, and how many dispatch groups were encountered so far).  */
14461132718Skan
14462132718Skanstatic int
14463132718Skanforce_new_group (int sched_verbose, FILE *dump, rtx *group_insns, rtx next_insn,
14464132718Skan		 bool *group_end, int can_issue_more, int *group_count)
14465132718Skan{
14466132718Skan  rtx nop;
14467132718Skan  bool force;
14468132718Skan  int issue_rate = rs6000_issue_rate ();
14469132718Skan  bool end = *group_end;
14470132718Skan  int i;
14471132718Skan
14472132718Skan  if (next_insn == NULL_RTX)
14473132718Skan    return can_issue_more;
14474132718Skan
14475132718Skan  if (rs6000_sched_insert_nops > sched_finish_regroup_exact)
14476132718Skan    return can_issue_more;
14477132718Skan
14478132718Skan  force = is_costly_group (group_insns, next_insn);
14479132718Skan  if (!force)
14480132718Skan    return can_issue_more;
14481132718Skan
14482132718Skan  if (sched_verbose > 6)
14483132718Skan    fprintf (dump,"force: group count = %d, can_issue_more = %d\n",
14484132718Skan			*group_count ,can_issue_more);
14485132718Skan
14486132718Skan  if (rs6000_sched_insert_nops == sched_finish_regroup_exact)
14487132718Skan    {
14488132718Skan      if (*group_end)
14489132718Skan        can_issue_more = 0;
14490132718Skan
14491132718Skan      /* Since only a branch can be issued in the last issue_slot, it is
14492132718Skan	 sufficient to insert 'can_issue_more - 1' nops if next_insn is not
14493132718Skan	 a branch. If next_insn is a branch, we insert 'can_issue_more' nops;
14494132718Skan	 in this case the last nop will start a new group and the branch will be
14495132718Skan	 forced to the new group.  */
14496132718Skan      if (can_issue_more && !is_branch_slot_insn (next_insn))
14497132718Skan        can_issue_more--;
14498132718Skan
14499132718Skan      while (can_issue_more > 0)
14500132718Skan        {
14501132718Skan          nop = gen_nop();
14502132718Skan          emit_insn_before (nop, next_insn);
14503132718Skan          can_issue_more--;
14504132718Skan        }
14505132718Skan
14506132718Skan      *group_end = true;
14507132718Skan      return 0;
14508132718Skan    }
14509132718Skan
14510132718Skan  if (rs6000_sched_insert_nops < sched_finish_regroup_exact)
14511132718Skan    {
14512132718Skan      int n_nops = rs6000_sched_insert_nops;
14513132718Skan
14514132718Skan      /* Nops can't be issued from the branch slot, so the effective
14515132718Skan         issue_rate for nops is 'issue_rate - 1'.  */
14516132718Skan      if (can_issue_more == 0)
14517132718Skan        can_issue_more = issue_rate;
14518132718Skan      can_issue_more--;
14519132718Skan      if (can_issue_more == 0)
14520132718Skan        {
14521132718Skan          can_issue_more = issue_rate - 1;
14522132718Skan          (*group_count)++;
14523132718Skan          end = true;
14524132718Skan          for (i = 0; i < issue_rate; i++)
14525132718Skan            {
14526132718Skan              group_insns[i] = 0;
14527132718Skan            }
14528132718Skan        }
14529132718Skan
14530132718Skan      while (n_nops > 0)
14531132718Skan        {
14532132718Skan          nop = gen_nop ();
14533132718Skan          emit_insn_before (nop, next_insn);
14534132718Skan          if (can_issue_more == issue_rate - 1) /* new group begins */
14535132718Skan            end = false;
14536132718Skan          can_issue_more--;
14537132718Skan          if (can_issue_more == 0)
14538132718Skan            {
14539132718Skan              can_issue_more = issue_rate - 1;
14540132718Skan              (*group_count)++;
14541132718Skan              end = true;
14542132718Skan              for (i = 0; i < issue_rate; i++)
14543132718Skan                {
14544132718Skan                  group_insns[i] = 0;
14545132718Skan                }
14546132718Skan            }
14547132718Skan          n_nops--;
14548132718Skan        }
14549132718Skan
14550132718Skan      /* Scale back relative to 'issue_rate' (instead of 'issue_rate - 1').  */
14551132718Skan      can_issue_more++;
14552132718Skan
14553132718Skan      *group_end = /* Is next_insn going to start a new group?  */
14554132718Skan	  (end
14555132718Skan	   || (can_issue_more == 1 && !is_branch_slot_insn (next_insn))
14556132718Skan	   || (can_issue_more <= 2 && is_cracked_insn (next_insn))
14557132718Skan	   || (can_issue_more < issue_rate &&
14558132718Skan	      insn_terminates_group_p (next_insn, previous_group)));
14559132718Skan      if (*group_end && end)
14560132718Skan        (*group_count)--;
14561132718Skan
14562132718Skan      if (sched_verbose > 6)
14563132718Skan        fprintf (dump, "done force: group count = %d, can_issue_more = %d\n",
14564132718Skan			*group_count, can_issue_more);
14565132718Skan      return can_issue_more;
14566132718Skan    }
14567132718Skan
14568132718Skan  return can_issue_more;
14569132718Skan}
14570132718Skan
14571132718Skan/* This function tries to synch the dispatch groups that the compiler "sees"
14572132718Skan   with the dispatch groups that the processor dispatcher is expected to
14573132718Skan   form in practice.  It tries to achieve this synchronization by forcing the
14574132718Skan   estimated processor grouping on the compiler (as opposed to the function
14575132718Skan   'pad_goups' which tries to force the scheduler's grouping on the processor).
14576132718Skan
14577132718Skan   The function scans the insn sequence between PREV_HEAD_INSN and TAIL and
14578132718Skan   examines the (estimated) dispatch groups that will be formed by the processor
14579132718Skan   dispatcher.  It marks these group boundaries to reflect the estimated
14580132718Skan   processor grouping, overriding the grouping that the scheduler had marked.
14581132718Skan   Depending on the value of the flag '-minsert-sched-nops' this function can
14582132718Skan   force certain insns into separate groups or force a certain distance between
14583132718Skan   them by inserting nops, for example, if there exists a "costly dependence"
14584132718Skan   between the insns.
14585132718Skan
14586132718Skan   The function estimates the group boundaries that the processor will form as
14587132718Skan   folllows:  It keeps track of how many vacant issue slots are available after
14588132718Skan   each insn.  A subsequent insn will start a new group if one of the following
14589132718Skan   4 cases applies:
14590132718Skan   - no more vacant issue slots remain in the current dispatch group.
14591132718Skan   - only the last issue slot, which is the branch slot, is vacant, but the next
14592132718Skan     insn is not a branch.
14593132718Skan   - only the last 2 or less issue slots, including the branch slot, are vacant,
14594132718Skan     which means that a cracked insn (which occupies two issue slots) can't be
14595132718Skan     issued in this group.
14596132718Skan   - less than 'issue_rate' slots are vacant, and the next insn always needs to
14597132718Skan     start a new group.  */
14598132718Skan
14599132718Skanstatic int
14600132718Skanredefine_groups (FILE *dump, int sched_verbose, rtx prev_head_insn, rtx tail)
14601132718Skan{
14602132718Skan  rtx insn, next_insn;
14603132718Skan  int issue_rate;
14604132718Skan  int can_issue_more;
14605132718Skan  int slot, i;
14606132718Skan  bool group_end;
14607132718Skan  int group_count = 0;
14608132718Skan  rtx *group_insns;
14609132718Skan
14610132718Skan  /* Initialize.  */
14611132718Skan  issue_rate = rs6000_issue_rate ();
14612132718Skan  group_insns = alloca (issue_rate * sizeof (rtx));
14613132718Skan  for (i = 0; i < issue_rate; i++)
14614132718Skan    {
14615132718Skan      group_insns[i] = 0;
14616132718Skan    }
14617132718Skan  can_issue_more = issue_rate;
14618132718Skan  slot = 0;
14619132718Skan  insn = get_next_active_insn (prev_head_insn, tail);
14620132718Skan  group_end = false;
14621132718Skan
14622132718Skan  while (insn != NULL_RTX)
14623132718Skan    {
14624132718Skan      slot = (issue_rate - can_issue_more);
14625132718Skan      group_insns[slot] = insn;
14626132718Skan      can_issue_more =
14627132718Skan        rs6000_variable_issue (dump, sched_verbose, insn, can_issue_more);
14628132718Skan      if (insn_terminates_group_p (insn, current_group))
14629132718Skan        can_issue_more = 0;
14630132718Skan
14631132718Skan      next_insn = get_next_active_insn (insn, tail);
14632132718Skan      if (next_insn == NULL_RTX)
14633132718Skan        return group_count + 1;
14634132718Skan
14635132718Skan      group_end = /* Is next_insn going to start a new group?  */
14636132718Skan        (can_issue_more == 0
14637132718Skan         || (can_issue_more == 1 && !is_branch_slot_insn (next_insn))
14638132718Skan         || (can_issue_more <= 2 && is_cracked_insn (next_insn))
14639132718Skan         || (can_issue_more < issue_rate &&
14640132718Skan             insn_terminates_group_p (next_insn, previous_group)));
14641132718Skan
14642132718Skan      can_issue_more = force_new_group (sched_verbose, dump, group_insns,
14643132718Skan			next_insn, &group_end, can_issue_more, &group_count);
14644132718Skan
14645132718Skan      if (group_end)
14646132718Skan        {
14647132718Skan          group_count++;
14648132718Skan          can_issue_more = 0;
14649132718Skan          for (i = 0; i < issue_rate; i++)
14650132718Skan            {
14651132718Skan              group_insns[i] = 0;
14652132718Skan            }
14653132718Skan        }
14654132718Skan
14655132718Skan      if (GET_MODE (next_insn) == TImode && can_issue_more)
14656132718Skan        PUT_MODE(next_insn, VOIDmode);
14657132718Skan      else if (!can_issue_more && GET_MODE (next_insn) != TImode)
14658132718Skan        PUT_MODE (next_insn, TImode);
14659132718Skan
14660132718Skan      insn = next_insn;
14661132718Skan      if (can_issue_more == 0)
14662132718Skan        can_issue_more = issue_rate;
14663132718Skan   } /* while */
14664132718Skan
14665132718Skan  return group_count;
14666132718Skan}
14667132718Skan
14668132718Skan/* Scan the insn sequence between PREV_HEAD_INSN and TAIL and examine the
14669132718Skan   dispatch group boundaries that the scheduler had marked.  Pad with nops
14670132718Skan   any dispatch groups which have vacant issue slots, in order to force the
14671132718Skan   scheduler's grouping on the processor dispatcher.  The function
14672132718Skan   returns the number of dispatch groups found.  */
14673132718Skan
14674132718Skanstatic int
14675132718Skanpad_groups (FILE *dump, int sched_verbose, rtx prev_head_insn, rtx tail)
14676132718Skan{
14677132718Skan  rtx insn, next_insn;
14678132718Skan  rtx nop;
14679132718Skan  int issue_rate;
14680132718Skan  int can_issue_more;
14681132718Skan  int group_end;
14682132718Skan  int group_count = 0;
14683132718Skan
14684132718Skan  /* Initialize issue_rate.  */
14685132718Skan  issue_rate = rs6000_issue_rate ();
14686132718Skan  can_issue_more = issue_rate;
14687132718Skan
14688132718Skan  insn = get_next_active_insn (prev_head_insn, tail);
14689132718Skan  next_insn = get_next_active_insn (insn, tail);
14690132718Skan
14691132718Skan  while (insn != NULL_RTX)
14692132718Skan    {
14693132718Skan      can_issue_more =
14694132718Skan      	rs6000_variable_issue (dump, sched_verbose, insn, can_issue_more);
14695132718Skan
14696132718Skan      group_end = (next_insn == NULL_RTX || GET_MODE (next_insn) == TImode);
14697132718Skan
14698132718Skan      if (next_insn == NULL_RTX)
14699132718Skan        break;
14700132718Skan
14701132718Skan      if (group_end)
14702132718Skan        {
14703132718Skan          /* If the scheduler had marked group termination at this location
14704132718Skan             (between insn and next_indn), and neither insn nor next_insn will
14705132718Skan             force group termination, pad the group with nops to force group
14706132718Skan             termination.  */
14707132718Skan          if (can_issue_more
14708132718Skan              && (rs6000_sched_insert_nops == sched_finish_pad_groups)
14709132718Skan              && !insn_terminates_group_p (insn, current_group)
14710132718Skan              && !insn_terminates_group_p (next_insn, previous_group))
14711132718Skan            {
14712132718Skan              if (!is_branch_slot_insn(next_insn))
14713132718Skan                can_issue_more--;
14714132718Skan
14715132718Skan              while (can_issue_more)
14716132718Skan                {
14717132718Skan                  nop = gen_nop ();
14718132718Skan                  emit_insn_before (nop, next_insn);
14719132718Skan                  can_issue_more--;
14720132718Skan                }
14721132718Skan            }
14722132718Skan
14723132718Skan          can_issue_more = issue_rate;
14724132718Skan          group_count++;
14725132718Skan        }
14726132718Skan
14727132718Skan      insn = next_insn;
14728132718Skan      next_insn = get_next_active_insn (insn, tail);
14729132718Skan    }
14730132718Skan
14731132718Skan  return group_count;
14732132718Skan}
14733132718Skan
14734132718Skan/* The following function is called at the end of scheduling BB.
14735132718Skan   After reload, it inserts nops at insn group bundling.  */
14736132718Skan
14737132718Skanstatic void
14738132718Skanrs6000_sched_finish (FILE *dump, int sched_verbose)
14739132718Skan{
14740132718Skan  int n_groups;
14741132718Skan
14742132718Skan  if (sched_verbose)
14743132718Skan    fprintf (dump, "=== Finishing schedule.\n");
14744132718Skan
14745132718Skan  if (reload_completed && rs6000_sched_groups)
14746132718Skan    {
14747132718Skan      if (rs6000_sched_insert_nops == sched_finish_none)
14748132718Skan        return;
14749132718Skan
14750132718Skan      if (rs6000_sched_insert_nops == sched_finish_pad_groups)
14751132718Skan        n_groups = pad_groups (dump, sched_verbose,
14752132718Skan				current_sched_info->prev_head,
14753132718Skan  			   	current_sched_info->next_tail);
14754132718Skan      else
14755132718Skan        n_groups = redefine_groups (dump, sched_verbose,
14756132718Skan				current_sched_info->prev_head,
14757132718Skan  				current_sched_info->next_tail);
14758132718Skan
14759132718Skan      if (sched_verbose >= 6)
14760132718Skan	{
14761132718Skan    	  fprintf (dump, "ngroups = %d\n", n_groups);
14762132718Skan	  print_rtl (dump, current_sched_info->prev_head);
14763132718Skan	  fprintf (dump, "Done finish_sched\n");
14764132718Skan	}
14765132718Skan    }
14766132718Skan}
1476790075Sobrien
1476890075Sobrien/* Length in units of the trampoline for entering a nested function.  */
1476990075Sobrien
1477090075Sobrienint
14771132718Skanrs6000_trampoline_size (void)
1477290075Sobrien{
1477390075Sobrien  int ret = 0;
1477490075Sobrien
1477590075Sobrien  switch (DEFAULT_ABI)
1477690075Sobrien    {
1477790075Sobrien    default:
1477890075Sobrien      abort ();
1477990075Sobrien
1478090075Sobrien    case ABI_AIX:
1478190075Sobrien      ret = (TARGET_32BIT) ? 12 : 24;
1478290075Sobrien      break;
1478390075Sobrien
1478490075Sobrien    case ABI_DARWIN:
1478590075Sobrien    case ABI_V4:
1478690075Sobrien      ret = (TARGET_32BIT) ? 40 : 48;
1478790075Sobrien      break;
1478890075Sobrien    }
1478990075Sobrien
1479090075Sobrien  return ret;
1479190075Sobrien}
1479290075Sobrien
1479390075Sobrien/* Emit RTL insns to initialize the variable parts of a trampoline.
1479490075Sobrien   FNADDR is an RTX for the address of the function's pure code.
1479590075Sobrien   CXT is an RTX for the static chain value for the function.  */
1479690075Sobrien
1479790075Sobrienvoid
14798132718Skanrs6000_initialize_trampoline (rtx addr, rtx fnaddr, rtx cxt)
1479990075Sobrien{
1480090075Sobrien  enum machine_mode pmode = Pmode;
1480190075Sobrien  int regsize = (TARGET_32BIT) ? 4 : 8;
1480290075Sobrien  rtx ctx_reg = force_reg (pmode, cxt);
1480390075Sobrien
1480490075Sobrien  switch (DEFAULT_ABI)
1480590075Sobrien    {
1480690075Sobrien    default:
1480790075Sobrien      abort ();
1480890075Sobrien
1480990075Sobrien/* Macros to shorten the code expansions below.  */
1481090075Sobrien#define MEM_DEREF(addr) gen_rtx_MEM (pmode, memory_address (pmode, addr))
1481190075Sobrien#define MEM_PLUS(addr,offset) \
1481290075Sobrien  gen_rtx_MEM (pmode, memory_address (pmode, plus_constant (addr, offset)))
1481390075Sobrien
1481490075Sobrien    /* Under AIX, just build the 3 word function descriptor */
1481590075Sobrien    case ABI_AIX:
1481690075Sobrien      {
1481790075Sobrien	rtx fn_reg = gen_reg_rtx (pmode);
1481890075Sobrien	rtx toc_reg = gen_reg_rtx (pmode);
1481990075Sobrien	emit_move_insn (fn_reg, MEM_DEREF (fnaddr));
1482090075Sobrien	emit_move_insn (toc_reg, MEM_PLUS (fnaddr, regsize));
1482190075Sobrien	emit_move_insn (MEM_DEREF (addr), fn_reg);
1482290075Sobrien	emit_move_insn (MEM_PLUS (addr, regsize), toc_reg);
1482390075Sobrien	emit_move_insn (MEM_PLUS (addr, 2*regsize), ctx_reg);
1482490075Sobrien      }
1482590075Sobrien      break;
1482690075Sobrien
1482790075Sobrien    /* Under V.4/eabi/darwin, __trampoline_setup does the real work.  */
1482890075Sobrien    case ABI_DARWIN:
1482990075Sobrien    case ABI_V4:
1483090075Sobrien      emit_library_call (gen_rtx_SYMBOL_REF (SImode, "__trampoline_setup"),
1483190075Sobrien			 FALSE, VOIDmode, 4,
1483290075Sobrien			 addr, pmode,
1483390075Sobrien			 GEN_INT (rs6000_trampoline_size ()), SImode,
1483490075Sobrien			 fnaddr, pmode,
1483590075Sobrien			 ctx_reg, pmode);
1483690075Sobrien      break;
1483790075Sobrien    }
1483890075Sobrien
1483990075Sobrien  return;
1484090075Sobrien}
1484190075Sobrien
1484290075Sobrien
1484390075Sobrien/* Table of valid machine attributes.  */
1484490075Sobrien
1484590075Sobrienconst struct attribute_spec rs6000_attribute_table[] =
1484690075Sobrien{
1484790075Sobrien  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
14848117395Skan  { "longcall",  0, 0, false, true,  true,  rs6000_handle_longcall_attribute },
14849117395Skan  { "shortcall", 0, 0, false, true,  true,  rs6000_handle_longcall_attribute },
14850117395Skan  { NULL,        0, 0, false, false, false, NULL }
1485190075Sobrien};
1485290075Sobrien
14853117395Skan/* Handle a "longcall" or "shortcall" attribute; arguments as in
14854117395Skan   struct attribute_spec.handler.  */
1485590075Sobrien
1485690075Sobrienstatic tree
14857132718Skanrs6000_handle_longcall_attribute (tree *node, tree name,
14858132718Skan				  tree args ATTRIBUTE_UNUSED,
14859132718Skan				  int flags ATTRIBUTE_UNUSED,
14860132718Skan				  bool *no_add_attrs)
1486190075Sobrien{
1486290075Sobrien  if (TREE_CODE (*node) != FUNCTION_TYPE
1486390075Sobrien      && TREE_CODE (*node) != FIELD_DECL
1486490075Sobrien      && TREE_CODE (*node) != TYPE_DECL)
1486590075Sobrien    {
1486690075Sobrien      warning ("`%s' attribute only applies to functions",
1486790075Sobrien	       IDENTIFIER_POINTER (name));
1486890075Sobrien      *no_add_attrs = true;
1486990075Sobrien    }
1487090075Sobrien
1487190075Sobrien  return NULL_TREE;
1487290075Sobrien}
1487390075Sobrien
14874117395Skan/* Set longcall attributes on all functions declared when
14875117395Skan   rs6000_default_long_calls is true.  */
14876117395Skanstatic void
14877132718Skanrs6000_set_default_type_attributes (tree type)
14878117395Skan{
14879117395Skan  if (rs6000_default_long_calls
14880117395Skan      && (TREE_CODE (type) == FUNCTION_TYPE
14881117395Skan	  || TREE_CODE (type) == METHOD_TYPE))
14882117395Skan    TYPE_ATTRIBUTES (type) = tree_cons (get_identifier ("longcall"),
14883117395Skan					NULL_TREE,
14884117395Skan					TYPE_ATTRIBUTES (type));
14885117395Skan}
14886117395Skan
1488790075Sobrien/* Return a reference suitable for calling a function with the
1488890075Sobrien   longcall attribute.  */
1488990075Sobrien
1489090075Sobrienstruct rtx_def *
14891132718Skanrs6000_longcall_ref (rtx call_ref)
1489290075Sobrien{
1489390075Sobrien  const char *call_name;
1489490075Sobrien  tree node;
1489590075Sobrien
1489690075Sobrien  if (GET_CODE (call_ref) != SYMBOL_REF)
1489790075Sobrien    return call_ref;
1489890075Sobrien
1489990075Sobrien  /* System V adds '.' to the internal name, so skip them.  */
1490090075Sobrien  call_name = XSTR (call_ref, 0);
1490190075Sobrien  if (*call_name == '.')
1490290075Sobrien    {
1490390075Sobrien      while (*call_name == '.')
1490490075Sobrien	call_name++;
1490590075Sobrien
1490690075Sobrien      node = get_identifier (call_name);
1490790075Sobrien      call_ref = gen_rtx_SYMBOL_REF (VOIDmode, IDENTIFIER_POINTER (node));
1490890075Sobrien    }
1490990075Sobrien
1491090075Sobrien  return force_reg (Pmode, call_ref);
1491190075Sobrien}
1491290075Sobrien
14913117395Skan#ifdef USING_ELFOS_H
14914117395Skan
1491590075Sobrien/* A C statement or statements to switch to the appropriate section
1491690075Sobrien   for output of RTX in mode MODE.  You can assume that RTX is some
1491790075Sobrien   kind of constant in RTL.  The argument MODE is redundant except in
1491890075Sobrien   the case of a `const_int' rtx.  Select the section by calling
1491990075Sobrien   `text_section' or one of the alternatives for other sections.
1492090075Sobrien
1492190075Sobrien   Do not define this macro if you put all constants in the read-only
1492290075Sobrien   data section.  */
1492390075Sobrien
14924117395Skanstatic void
14925132718Skanrs6000_elf_select_rtx_section (enum machine_mode mode, rtx x,
14926132718Skan			       unsigned HOST_WIDE_INT align)
1492790075Sobrien{
1492890075Sobrien  if (ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (x, mode))
1492990075Sobrien    toc_section ();
1493090075Sobrien  else
14931117395Skan    default_elf_select_rtx_section (mode, x, align);
1493290075Sobrien}
1493390075Sobrien
1493490075Sobrien/* A C statement or statements to switch to the appropriate
1493590075Sobrien   section for output of DECL.  DECL is either a `VAR_DECL' node
1493690075Sobrien   or a constant of some sort.  RELOC indicates whether forming
1493790075Sobrien   the initial value of DECL requires link-time relocations.  */
1493890075Sobrien
14939117395Skanstatic void
14940132718Skanrs6000_elf_select_section (tree decl, int reloc,
14941132718Skan			   unsigned HOST_WIDE_INT align)
1494290075Sobrien{
14943132718Skan  /* Pretend that we're always building for a shared library when
14944132718Skan     ABI_AIX, because otherwise we end up with dynamic relocations
14945132718Skan     in read-only sections.  This happens for function pointers,
14946132718Skan     references to vtables in typeinfo, and probably other cases.  */
14947117395Skan  default_elf_select_section_1 (decl, reloc, align,
14948117395Skan				flag_pic || DEFAULT_ABI == ABI_AIX);
1494990075Sobrien}
1495090075Sobrien
1495190075Sobrien/* A C statement to build up a unique section name, expressed as a
1495290075Sobrien   STRING_CST node, and assign it to DECL_SECTION_NAME (decl).
1495390075Sobrien   RELOC indicates whether the initial value of EXP requires
1495490075Sobrien   link-time relocations.  If you do not define this macro, GCC will use
1495590075Sobrien   the symbol name prefixed by `.' as the section name.  Note - this
1495690075Sobrien   macro can now be called for uninitialized data items as well as
14957117395Skan   initialized data and functions.  */
1495890075Sobrien
14959117395Skanstatic void
14960132718Skanrs6000_elf_unique_section (tree decl, int reloc)
1496190075Sobrien{
14962132718Skan  /* As above, pretend that we're always building for a shared library
14963132718Skan     when ABI_AIX, to avoid dynamic relocations in read-only sections.  */
14964117395Skan  default_unique_section_1 (decl, reloc,
14965117395Skan			    flag_pic || DEFAULT_ABI == ABI_AIX);
1496690075Sobrien}
14967117395Skan
14968132718Skan/* For a SYMBOL_REF, set generic flags and then perform some
14969132718Skan   target-specific processing.
1497090075Sobrien
14971132718Skan   When the AIX ABI is requested on a non-AIX system, replace the
14972132718Skan   function name with the real name (with a leading .) rather than the
14973132718Skan   function descriptor name.  This saves a lot of overriding code to
14974132718Skan   read the prefixes.  */
14975132718Skan
14976117395Skanstatic void
14977132718Skanrs6000_elf_encode_section_info (tree decl, rtx rtl, int first)
1497890075Sobrien{
14979132718Skan  default_encode_section_info (decl, rtl, first);
14980117395Skan
14981132718Skan  if (first
14982132718Skan      && TREE_CODE (decl) == FUNCTION_DECL
14983132718Skan      && !TARGET_AIX
14984132718Skan      && DEFAULT_ABI == ABI_AIX)
1498590075Sobrien    {
14986132718Skan      rtx sym_ref = XEXP (rtl, 0);
14987132718Skan      size_t len = strlen (XSTR (sym_ref, 0));
14988132718Skan      char *str = alloca (len + 2);
14989132718Skan      str[0] = '.';
14990132718Skan      memcpy (str + 1, XSTR (sym_ref, 0), len + 1);
14991132718Skan      XSTR (sym_ref, 0) = ggc_alloc_string (str, len + 1);
1499290075Sobrien    }
1499390075Sobrien}
1499490075Sobrien
14995117395Skanstatic bool
14996132718Skanrs6000_elf_in_small_data_p (tree decl)
14997117395Skan{
14998117395Skan  if (rs6000_sdata == SDATA_NONE)
14999117395Skan    return false;
15000117395Skan
15001117395Skan  if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl))
15002117395Skan    {
15003117395Skan      const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
15004117395Skan      if (strcmp (section, ".sdata") == 0
15005117395Skan	  || strcmp (section, ".sdata2") == 0
15006132718Skan	  || strcmp (section, ".sbss") == 0
15007132718Skan	  || strcmp (section, ".sbss2") == 0
15008132718Skan	  || strcmp (section, ".PPC.EMB.sdata0") == 0
15009132718Skan	  || strcmp (section, ".PPC.EMB.sbss0") == 0)
15010117395Skan	return true;
15011117395Skan    }
15012117395Skan  else
15013117395Skan    {
15014117395Skan      HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (decl));
15015117395Skan
15016117395Skan      if (size > 0
15017132718Skan	  && (unsigned HOST_WIDE_INT) size <= g_switch_value
15018132718Skan	  /* If it's not public, and we're not going to reference it there,
15019132718Skan	     there's no need to put it in the small data section.  */
15020117395Skan	  && (rs6000_sdata != SDATA_DATA || TREE_PUBLIC (decl)))
15021117395Skan	return true;
15022117395Skan    }
15023117395Skan
15024117395Skan  return false;
15025117395Skan}
15026117395Skan
1502790075Sobrien#endif /* USING_ELFOS_H */
1502890075Sobrien
1502990075Sobrien
1503090075Sobrien/* Return a REG that occurs in ADDR with coefficient 1.
1503190075Sobrien   ADDR can be effectively incremented by incrementing REG.
1503290075Sobrien
1503390075Sobrien   r0 is special and we must not select it as an address
1503490075Sobrien   register by this routine since our caller will try to
1503590075Sobrien   increment the returned register via an "la" instruction.  */
1503690075Sobrien
1503790075Sobrienstruct rtx_def *
15038132718Skanfind_addr_reg (rtx addr)
1503990075Sobrien{
1504090075Sobrien  while (GET_CODE (addr) == PLUS)
1504190075Sobrien    {
1504290075Sobrien      if (GET_CODE (XEXP (addr, 0)) == REG
1504390075Sobrien	  && REGNO (XEXP (addr, 0)) != 0)
1504490075Sobrien	addr = XEXP (addr, 0);
1504590075Sobrien      else if (GET_CODE (XEXP (addr, 1)) == REG
1504690075Sobrien	       && REGNO (XEXP (addr, 1)) != 0)
1504790075Sobrien	addr = XEXP (addr, 1);
1504890075Sobrien      else if (CONSTANT_P (XEXP (addr, 0)))
1504990075Sobrien	addr = XEXP (addr, 1);
1505090075Sobrien      else if (CONSTANT_P (XEXP (addr, 1)))
1505190075Sobrien	addr = XEXP (addr, 0);
1505290075Sobrien      else
1505390075Sobrien	abort ();
1505490075Sobrien    }
1505590075Sobrien  if (GET_CODE (addr) == REG && REGNO (addr) != 0)
1505690075Sobrien    return addr;
1505790075Sobrien  abort ();
1505890075Sobrien}
1505990075Sobrien
1506090075Sobrienvoid
15061132718Skanrs6000_fatal_bad_address (rtx op)
1506290075Sobrien{
1506390075Sobrien  fatal_insn ("bad address", op);
1506490075Sobrien}
1506590075Sobrien
1506690075Sobrien#if TARGET_MACHO
1506790075Sobrien
1506890075Sobrien#if 0
1506990075Sobrien/* Returns 1 if OP is either a symbol reference or a sum of a symbol
1507090075Sobrien   reference and a constant.  */
1507190075Sobrien
1507290075Sobrienint
15073132718Skansymbolic_operand (rtx op)
1507490075Sobrien{
1507590075Sobrien  switch (GET_CODE (op))
1507690075Sobrien    {
1507790075Sobrien    case SYMBOL_REF:
1507890075Sobrien    case LABEL_REF:
1507990075Sobrien      return 1;
1508090075Sobrien    case CONST:
1508190075Sobrien      op = XEXP (op, 0);
1508290075Sobrien      return (GET_CODE (op) == SYMBOL_REF ||
1508390075Sobrien	      (GET_CODE (XEXP (op, 0)) == SYMBOL_REF
1508490075Sobrien	       || GET_CODE (XEXP (op, 0)) == LABEL_REF)
1508590075Sobrien	      && GET_CODE (XEXP (op, 1)) == CONST_INT);
1508690075Sobrien    default:
1508790075Sobrien      return 0;
1508890075Sobrien    }
1508990075Sobrien}
1509090075Sobrien#endif
1509190075Sobrien
15092132718Skan#if TARGET_MACHO
1509390075Sobrien
15094132718Skanstatic tree branch_island_list = 0;
1509590075Sobrien
15096132718Skan/* Remember to generate a branch island for far calls to the given
15097132718Skan   function.  */
1509890075Sobrien
15099132718Skanstatic void
15100132718Skanadd_compiler_branch_island (tree label_name, tree function_name, int line_number)
1510190075Sobrien{
15102132718Skan  tree branch_island = build_tree_list (function_name, label_name);
15103132718Skan  TREE_TYPE (branch_island) = build_int_2 (line_number, 0);
15104132718Skan  TREE_CHAIN (branch_island) = branch_island_list;
15105132718Skan  branch_island_list = branch_island;
1510690075Sobrien}
1510790075Sobrien
15108132718Skan#define BRANCH_ISLAND_LABEL_NAME(BRANCH_ISLAND)     TREE_VALUE (BRANCH_ISLAND)
15109132718Skan#define BRANCH_ISLAND_FUNCTION_NAME(BRANCH_ISLAND)  TREE_PURPOSE (BRANCH_ISLAND)
15110132718Skan#define BRANCH_ISLAND_LINE_NUMBER(BRANCH_ISLAND)    \
15111132718Skan		TREE_INT_CST_LOW (TREE_TYPE (BRANCH_ISLAND))
1511290075Sobrien
15113132718Skan/* Generate far-jump branch islands for everything on the
15114132718Skan   branch_island_list.  Invoked immediately after the last instruction
15115132718Skan   of the epilogue has been emitted; the branch-islands must be
15116132718Skan   appended to, and contiguous with, the function body.  Mach-O stubs
15117132718Skan   are generated in machopic_output_stub().  */
1511890075Sobrien
15119132718Skanstatic void
15120132718Skanmacho_branch_islands (void)
1512190075Sobrien{
15122132718Skan  char tmp_buf[512];
15123132718Skan  tree branch_island;
1512490075Sobrien
15125132718Skan  for (branch_island = branch_island_list;
15126132718Skan       branch_island;
15127132718Skan       branch_island = TREE_CHAIN (branch_island))
15128132718Skan    {
15129132718Skan      const char *label =
15130132718Skan	IDENTIFIER_POINTER (BRANCH_ISLAND_LABEL_NAME (branch_island));
15131132718Skan      const char *name  =
15132132718Skan	darwin_strip_name_encoding (
15133132718Skan	  IDENTIFIER_POINTER (BRANCH_ISLAND_FUNCTION_NAME (branch_island)));
15134132718Skan      char name_buf[512];
15135132718Skan      /* Cheap copy of the details from the Darwin ASM_OUTPUT_LABELREF().  */
15136132718Skan      if (name[0] == '*' || name[0] == '&')
15137132718Skan	strcpy (name_buf, name+1);
15138132718Skan      else
15139132718Skan	{
15140132718Skan	  name_buf[0] = '_';
15141132718Skan	  strcpy (name_buf+1, name);
15142132718Skan	}
15143132718Skan      strcpy (tmp_buf, "\n");
15144132718Skan      strcat (tmp_buf, label);
1514590075Sobrien#if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO)
15146132718Skan      if (write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG)
15147132718Skan	fprintf (asm_out_file, "\t.stabd 68,0," HOST_WIDE_INT_PRINT_UNSIGNED "\n",
15148132718Skan		 BRANCH_ISLAND_LINE_NUMBER(branch_island));
1514990075Sobrien#endif /* DBX_DEBUGGING_INFO || XCOFF_DEBUGGING_INFO */
15150132718Skan      if (flag_pic)
15151132718Skan	{
15152132718Skan	  strcat (tmp_buf, ":\n\tmflr r0\n\tbcl 20,31,");
15153132718Skan	  strcat (tmp_buf, label);
15154132718Skan	  strcat (tmp_buf, "_pic\n");
15155132718Skan	  strcat (tmp_buf, label);
15156132718Skan	  strcat (tmp_buf, "_pic:\n\tmflr r11\n");
15157132718Skan
15158132718Skan	  strcat (tmp_buf, "\taddis r11,r11,ha16(");
15159132718Skan	  strcat (tmp_buf, name_buf);
15160132718Skan	  strcat (tmp_buf, " - ");
15161132718Skan	  strcat (tmp_buf, label);
15162132718Skan	  strcat (tmp_buf, "_pic)\n");
15163132718Skan
15164132718Skan	  strcat (tmp_buf, "\tmtlr r0\n");
15165132718Skan
15166132718Skan	  strcat (tmp_buf, "\taddi r12,r11,lo16(");
15167132718Skan	  strcat (tmp_buf, name_buf);
15168132718Skan	  strcat (tmp_buf, " - ");
15169132718Skan	  strcat (tmp_buf, label);
15170132718Skan	  strcat (tmp_buf, "_pic)\n");
15171132718Skan
15172132718Skan	  strcat (tmp_buf, "\tmtctr r12\n\tbctr\n");
15173132718Skan	}
15174132718Skan      else
15175132718Skan	{
15176132718Skan	  strcat (tmp_buf, ":\nlis r12,hi16(");
15177132718Skan	  strcat (tmp_buf, name_buf);
15178132718Skan	  strcat (tmp_buf, ")\n\tori r12,r12,lo16(");
15179132718Skan	  strcat (tmp_buf, name_buf);
15180132718Skan	  strcat (tmp_buf, ")\n\tmtctr r12\n\tbctr");
15181132718Skan	}
15182132718Skan      output_asm_insn (tmp_buf, 0);
1518390075Sobrien#if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO)
15184132718Skan      if (write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG)
15185132718Skan	fprintf(asm_out_file, "\t.stabd 68,0," HOST_WIDE_INT_PRINT_UNSIGNED "\n",
15186132718Skan		BRANCH_ISLAND_LINE_NUMBER (branch_island));
1518790075Sobrien#endif /* DBX_DEBUGGING_INFO || XCOFF_DEBUGGING_INFO */
15188132718Skan    }
1518990075Sobrien
15190132718Skan  branch_island_list = 0;
1519190075Sobrien}
1519290075Sobrien
1519390075Sobrien/* NO_PREVIOUS_DEF checks in the link list whether the function name is
1519490075Sobrien   already there or not.  */
1519590075Sobrien
15196132718Skanstatic int
15197132718Skanno_previous_def (tree function_name)
1519890075Sobrien{
15199132718Skan  tree branch_island;
15200132718Skan  for (branch_island = branch_island_list;
15201132718Skan       branch_island;
15202132718Skan       branch_island = TREE_CHAIN (branch_island))
15203132718Skan    if (function_name == BRANCH_ISLAND_FUNCTION_NAME (branch_island))
1520490075Sobrien      return 0;
1520590075Sobrien  return 1;
1520690075Sobrien}
1520790075Sobrien
1520890075Sobrien/* GET_PREV_LABEL gets the label name from the previous definition of
1520990075Sobrien   the function.  */
1521090075Sobrien
15211132718Skanstatic tree
15212132718Skanget_prev_label (tree function_name)
1521390075Sobrien{
15214132718Skan  tree branch_island;
15215132718Skan  for (branch_island = branch_island_list;
15216132718Skan       branch_island;
15217132718Skan       branch_island = TREE_CHAIN (branch_island))
15218132718Skan    if (function_name == BRANCH_ISLAND_FUNCTION_NAME (branch_island))
15219132718Skan      return BRANCH_ISLAND_LABEL_NAME (branch_island);
1522090075Sobrien  return 0;
1522190075Sobrien}
1522290075Sobrien
1522390075Sobrien/* INSN is either a function call or a millicode call.  It may have an
1522490075Sobrien   unconditional jump in its delay slot.
1522590075Sobrien
1522690075Sobrien   CALL_DEST is the routine we are calling.  */
1522790075Sobrien
1522890075Sobrienchar *
15229132718Skanoutput_call (rtx insn, rtx *operands, int dest_operand_number, int cookie_operand_number)
1523090075Sobrien{
1523190075Sobrien  static char buf[256];
15232132718Skan  if (GET_CODE (operands[dest_operand_number]) == SYMBOL_REF
15233132718Skan      && (INTVAL (operands[cookie_operand_number]) & CALL_LONG))
1523490075Sobrien    {
1523590075Sobrien      tree labelname;
15236132718Skan      tree funname = get_identifier (XSTR (operands[dest_operand_number], 0));
1523790075Sobrien
1523890075Sobrien      if (no_previous_def (funname))
1523990075Sobrien	{
15240117395Skan	  int line_number = 0;
1524190075Sobrien	  rtx label_rtx = gen_label_rtx ();
1524290075Sobrien	  char *label_buf, temp_buf[256];
1524390075Sobrien	  ASM_GENERATE_INTERNAL_LABEL (temp_buf, "L",
1524490075Sobrien				       CODE_LABEL_NUMBER (label_rtx));
1524590075Sobrien	  label_buf = temp_buf[0] == '*' ? temp_buf + 1 : temp_buf;
1524690075Sobrien	  labelname = get_identifier (label_buf);
1524790075Sobrien	  for (; insn && GET_CODE (insn) != NOTE; insn = PREV_INSN (insn));
1524890075Sobrien	  if (insn)
1524990075Sobrien	    line_number = NOTE_LINE_NUMBER (insn);
15250132718Skan	  add_compiler_branch_island (labelname, funname, line_number);
1525190075Sobrien	}
1525290075Sobrien      else
1525390075Sobrien	labelname = get_prev_label (funname);
1525490075Sobrien
15255132718Skan      /* "jbsr foo, L42" is Mach-O for "Link as 'bl foo' if a 'bl'
15256132718Skan	 instruction will reach 'foo', otherwise link as 'bl L42'".
15257132718Skan	 "L42" should be a 'branch island', that will do a far jump to
15258132718Skan	 'foo'.  Branch islands are generated in
15259132718Skan	 macho_branch_islands().  */
1526090075Sobrien      sprintf (buf, "jbsr %%z%d,%.246s",
15261132718Skan	       dest_operand_number, IDENTIFIER_POINTER (labelname));
1526290075Sobrien    }
1526390075Sobrien  else
15264132718Skan    sprintf (buf, "bl %%z%d", dest_operand_number);
15265132718Skan  return buf;
1526690075Sobrien}
1526790075Sobrien
15268132718Skan#endif /* TARGET_MACHO */
1526990075Sobrien
1527090075Sobrien/* Generate PIC and indirect symbol stubs.  */
1527190075Sobrien
1527290075Sobrienvoid
15273132718Skanmachopic_output_stub (FILE *file, const char *symb, const char *stub)
1527490075Sobrien{
1527590075Sobrien  unsigned int length;
1527690075Sobrien  char *symbol_name, *lazy_ptr_name;
1527790075Sobrien  char *local_label_0;
1527890075Sobrien  static int label = 0;
1527990075Sobrien
1528090075Sobrien  /* Lose our funky encoding stuff so it doesn't contaminate the stub.  */
15281117395Skan  symb = (*targetm.strip_name_encoding) (symb);
1528290075Sobrien
1528390075Sobrien
1528490075Sobrien  length = strlen (symb);
1528590075Sobrien  symbol_name = alloca (length + 32);
1528690075Sobrien  GEN_SYMBOL_NAME_FOR_SYMBOL (symbol_name, symb, length);
1528790075Sobrien
1528890075Sobrien  lazy_ptr_name = alloca (length + 32);
1528990075Sobrien  GEN_LAZY_PTR_NAME_FOR_SYMBOL (lazy_ptr_name, symb, length);
1529090075Sobrien
1529190075Sobrien  if (flag_pic == 2)
15292132718Skan    machopic_picsymbol_stub1_section ();
1529390075Sobrien  else
15294132718Skan    machopic_symbol_stub1_section ();
15295132718Skan  fprintf (file, "\t.align 2\n");
1529690075Sobrien
1529790075Sobrien  fprintf (file, "%s:\n", stub);
1529890075Sobrien  fprintf (file, "\t.indirect_symbol %s\n", symbol_name);
1529990075Sobrien
1530090075Sobrien  if (flag_pic == 2)
1530190075Sobrien    {
15302132718Skan      label++;
15303132718Skan      local_label_0 = alloca (sizeof("\"L0000000000$spb\""));
15304132718Skan      sprintf (local_label_0, "\"L%011d$spb\"", label);
15305132718Skan
1530690075Sobrien      fprintf (file, "\tmflr r0\n");
1530790075Sobrien      fprintf (file, "\tbcl 20,31,%s\n", local_label_0);
1530890075Sobrien      fprintf (file, "%s:\n\tmflr r11\n", local_label_0);
1530990075Sobrien      fprintf (file, "\taddis r11,r11,ha16(%s-%s)\n",
1531090075Sobrien	       lazy_ptr_name, local_label_0);
1531190075Sobrien      fprintf (file, "\tmtlr r0\n");
15312132718Skan      fprintf (file, "\tlwzu r12,lo16(%s-%s)(r11)\n",
1531390075Sobrien	       lazy_ptr_name, local_label_0);
1531490075Sobrien      fprintf (file, "\tmtctr r12\n");
1531590075Sobrien      fprintf (file, "\tbctr\n");
1531690075Sobrien    }
1531790075Sobrien  else
15318132718Skan   {
15319132718Skan     fprintf (file, "\tlis r11,ha16(%s)\n", lazy_ptr_name);
15320132718Skan     fprintf (file, "\tlwzu r12,lo16(%s)(r11)\n", lazy_ptr_name);
15321132718Skan     fprintf (file, "\tmtctr r12\n");
15322132718Skan     fprintf (file, "\tbctr\n");
15323132718Skan   }
1532490075Sobrien
1532590075Sobrien  machopic_lazy_symbol_ptr_section ();
1532690075Sobrien  fprintf (file, "%s:\n", lazy_ptr_name);
1532790075Sobrien  fprintf (file, "\t.indirect_symbol %s\n", symbol_name);
1532890075Sobrien  fprintf (file, "\t.long dyld_stub_binding_helper\n");
1532990075Sobrien}
1533090075Sobrien
1533190075Sobrien/* Legitimize PIC addresses.  If the address is already
1533290075Sobrien   position-independent, we return ORIG.  Newly generated
1533390075Sobrien   position-independent addresses go into a reg.  This is REG if non
1533490075Sobrien   zero, otherwise we allocate register(s) as necessary.  */
1533590075Sobrien
1533690075Sobrien#define SMALL_INT(X) ((unsigned) (INTVAL(X) + 0x8000) < 0x10000)
1533790075Sobrien
1533890075Sobrienrtx
15339132718Skanrs6000_machopic_legitimize_pic_address (rtx orig, enum machine_mode mode,
15340132718Skan					rtx reg)
1534190075Sobrien{
1534290075Sobrien  rtx base, offset;
1534390075Sobrien
1534490075Sobrien  if (reg == NULL && ! reload_in_progress && ! reload_completed)
1534590075Sobrien    reg = gen_reg_rtx (Pmode);
1534690075Sobrien
1534790075Sobrien  if (GET_CODE (orig) == CONST)
1534890075Sobrien    {
1534990075Sobrien      if (GET_CODE (XEXP (orig, 0)) == PLUS
1535090075Sobrien	  && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx)
1535190075Sobrien	return orig;
1535290075Sobrien
1535390075Sobrien      if (GET_CODE (XEXP (orig, 0)) == PLUS)
1535490075Sobrien	{
15355132718Skan	  /* Use a different reg for the intermediate value, as
15356132718Skan	     it will be marked UNCHANGING.  */
15357132718Skan	  rtx reg_temp = no_new_pseudos ? reg : gen_reg_rtx (Pmode);
15358132718Skan
1535990075Sobrien	  base =
1536090075Sobrien	    rs6000_machopic_legitimize_pic_address (XEXP (XEXP (orig, 0), 0),
15361132718Skan						    Pmode, reg_temp);
1536290075Sobrien	  offset =
1536390075Sobrien	    rs6000_machopic_legitimize_pic_address (XEXP (XEXP (orig, 0), 1),
1536490075Sobrien						    Pmode, reg);
1536590075Sobrien	}
1536690075Sobrien      else
1536790075Sobrien	abort ();
1536890075Sobrien
1536990075Sobrien      if (GET_CODE (offset) == CONST_INT)
1537090075Sobrien	{
1537190075Sobrien	  if (SMALL_INT (offset))
1537290075Sobrien	    return plus_constant (base, INTVAL (offset));
1537390075Sobrien	  else if (! reload_in_progress && ! reload_completed)
1537490075Sobrien	    offset = force_reg (Pmode, offset);
1537590075Sobrien	  else
1537690075Sobrien	    {
1537790075Sobrien 	      rtx mem = force_const_mem (Pmode, orig);
1537890075Sobrien	      return machopic_legitimize_pic_address (mem, Pmode, reg);
1537990075Sobrien	    }
1538090075Sobrien	}
1538190075Sobrien      return gen_rtx (PLUS, Pmode, base, offset);
1538290075Sobrien    }
1538390075Sobrien
1538490075Sobrien  /* Fall back on generic machopic code.  */
1538590075Sobrien  return machopic_legitimize_pic_address (orig, mode, reg);
1538690075Sobrien}
1538790075Sobrien
1538890075Sobrien/* This is just a placeholder to make linking work without having to
1538990075Sobrien   add this to the generic Darwin EXTRA_SECTIONS.  If -mcall-aix is
1539090075Sobrien   ever needed for Darwin (not too likely!) this would have to get a
1539190075Sobrien   real definition.  */
1539290075Sobrien
1539390075Sobrienvoid
15394132718Skantoc_section (void)
1539590075Sobrien{
1539690075Sobrien}
1539790075Sobrien
1539890075Sobrien#endif /* TARGET_MACHO */
1539990075Sobrien
1540090075Sobrien#if TARGET_ELF
1540190075Sobrienstatic unsigned int
15402132718Skanrs6000_elf_section_type_flags (tree decl, const char *name, int reloc)
1540390075Sobrien{
15404132718Skan  return default_section_type_flags_1 (decl, name, reloc,
15405132718Skan				       flag_pic || DEFAULT_ABI == ABI_AIX);
1540690075Sobrien}
1540790075Sobrien
1540890075Sobrien/* Record an element in the table of global constructors.  SYMBOL is
1540990075Sobrien   a SYMBOL_REF of the function to be called; PRIORITY is a number
1541090075Sobrien   between 0 and MAX_INIT_PRIORITY.
1541190075Sobrien
1541290075Sobrien   This differs from default_named_section_asm_out_constructor in
1541390075Sobrien   that we have special handling for -mrelocatable.  */
1541490075Sobrien
1541590075Sobrienstatic void
15416132718Skanrs6000_elf_asm_out_constructor (rtx symbol, int priority)
1541790075Sobrien{
1541890075Sobrien  const char *section = ".ctors";
1541990075Sobrien  char buf[16];
1542090075Sobrien
1542190075Sobrien  if (priority != DEFAULT_INIT_PRIORITY)
1542290075Sobrien    {
1542390075Sobrien      sprintf (buf, ".ctors.%.5u",
1542490075Sobrien               /* Invert the numbering so the linker puts us in the proper
1542590075Sobrien                  order; constructors are run from right to left, and the
1542690075Sobrien                  linker sorts in increasing order.  */
1542790075Sobrien               MAX_INIT_PRIORITY - priority);
1542890075Sobrien      section = buf;
1542990075Sobrien    }
1543090075Sobrien
1543190075Sobrien  named_section_flags (section, SECTION_WRITE);
1543290075Sobrien  assemble_align (POINTER_SIZE);
1543390075Sobrien
1543490075Sobrien  if (TARGET_RELOCATABLE)
1543590075Sobrien    {
1543690075Sobrien      fputs ("\t.long (", asm_out_file);
1543790075Sobrien      output_addr_const (asm_out_file, symbol);
1543890075Sobrien      fputs (")@fixup\n", asm_out_file);
1543990075Sobrien    }
1544090075Sobrien  else
1544190075Sobrien    assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
1544290075Sobrien}
1544390075Sobrien
1544490075Sobrienstatic void
15445132718Skanrs6000_elf_asm_out_destructor (rtx symbol, int priority)
1544690075Sobrien{
1544790075Sobrien  const char *section = ".dtors";
1544890075Sobrien  char buf[16];
1544990075Sobrien
1545090075Sobrien  if (priority != DEFAULT_INIT_PRIORITY)
1545190075Sobrien    {
1545290075Sobrien      sprintf (buf, ".dtors.%.5u",
1545390075Sobrien               /* Invert the numbering so the linker puts us in the proper
1545490075Sobrien                  order; constructors are run from right to left, and the
1545590075Sobrien                  linker sorts in increasing order.  */
1545690075Sobrien               MAX_INIT_PRIORITY - priority);
1545790075Sobrien      section = buf;
1545890075Sobrien    }
1545990075Sobrien
1546090075Sobrien  named_section_flags (section, SECTION_WRITE);
1546190075Sobrien  assemble_align (POINTER_SIZE);
1546290075Sobrien
1546390075Sobrien  if (TARGET_RELOCATABLE)
1546490075Sobrien    {
1546590075Sobrien      fputs ("\t.long (", asm_out_file);
1546690075Sobrien      output_addr_const (asm_out_file, symbol);
1546790075Sobrien      fputs (")@fixup\n", asm_out_file);
1546890075Sobrien    }
1546990075Sobrien  else
1547090075Sobrien    assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
1547190075Sobrien}
15472132718Skan
15473132718Skanvoid
15474132718Skanrs6000_elf_declare_function_name (FILE *file, const char *name, tree decl)
15475132718Skan{
15476132718Skan  if (TARGET_64BIT)
15477132718Skan    {
15478132718Skan      fputs ("\t.section\t\".opd\",\"aw\"\n\t.align 3\n", file);
15479132718Skan      ASM_OUTPUT_LABEL (file, name);
15480132718Skan      fputs (DOUBLE_INT_ASM_OP, file);
15481132718Skan      putc ('.', file);
15482132718Skan      assemble_name (file, name);
15483132718Skan      fputs (",.TOC.@tocbase,0\n\t.previous\n\t.size\t", file);
15484132718Skan      assemble_name (file, name);
15485132718Skan      fputs (",24\n\t.type\t.", file);
15486132718Skan      assemble_name (file, name);
15487132718Skan      fputs (",@function\n", file);
15488132718Skan      if (TREE_PUBLIC (decl) && ! DECL_WEAK (decl))
15489132718Skan	{
15490132718Skan	  fputs ("\t.globl\t.", file);
15491132718Skan	  assemble_name (file, name);
15492132718Skan	  putc ('\n', file);
15493132718Skan	}
15494132718Skan      ASM_DECLARE_RESULT (file, DECL_RESULT (decl));
15495132718Skan      putc ('.', file);
15496132718Skan      ASM_OUTPUT_LABEL (file, name);
15497132718Skan      return;
15498132718Skan    }
15499132718Skan
15500132718Skan  if (TARGET_RELOCATABLE
15501132718Skan      && (get_pool_size () != 0 || current_function_profile)
15502132718Skan      && uses_TOC ())
15503132718Skan    {
15504132718Skan      char buf[256];
15505132718Skan
15506132718Skan      (*targetm.asm_out.internal_label) (file, "LCL", rs6000_pic_labelno);
15507132718Skan
15508132718Skan      ASM_GENERATE_INTERNAL_LABEL (buf, "LCTOC", 1);
15509132718Skan      fprintf (file, "\t.long ");
15510132718Skan      assemble_name (file, buf);
15511132718Skan      putc ('-', file);
15512132718Skan      ASM_GENERATE_INTERNAL_LABEL (buf, "LCF", rs6000_pic_labelno);
15513132718Skan      assemble_name (file, buf);
15514132718Skan      putc ('\n', file);
15515132718Skan    }
15516132718Skan
15517132718Skan  ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function");
15518132718Skan  ASM_DECLARE_RESULT (file, DECL_RESULT (decl));
15519132718Skan
15520132718Skan  if (DEFAULT_ABI == ABI_AIX)
15521132718Skan    {
15522132718Skan      const char *desc_name, *orig_name;
15523132718Skan
15524132718Skan      orig_name = (*targetm.strip_name_encoding) (name);
15525132718Skan      desc_name = orig_name;
15526132718Skan      while (*desc_name == '.')
15527132718Skan	desc_name++;
15528132718Skan
15529132718Skan      if (TREE_PUBLIC (decl))
15530132718Skan	fprintf (file, "\t.globl %s\n", desc_name);
15531132718Skan
15532132718Skan      fprintf (file, "%s\n", MINIMAL_TOC_SECTION_ASM_OP);
15533132718Skan      fprintf (file, "%s:\n", desc_name);
15534132718Skan      fprintf (file, "\t.long %s\n", orig_name);
15535132718Skan      fputs ("\t.long _GLOBAL_OFFSET_TABLE_\n", file);
15536132718Skan      if (DEFAULT_ABI == ABI_AIX)
15537132718Skan	fputs ("\t.long 0\n", file);
15538132718Skan      fprintf (file, "\t.previous\n");
15539132718Skan    }
15540132718Skan  ASM_OUTPUT_LABEL (file, name);
15541132718Skan}
1554290075Sobrien#endif
1554390075Sobrien
15544117395Skan#if TARGET_XCOFF
1554590075Sobrienstatic void
15546132718Skanrs6000_xcoff_asm_globalize_label (FILE *stream, const char *name)
1554790075Sobrien{
15548117395Skan  fputs (GLOBAL_ASM_OP, stream);
15549117395Skan  RS6000_OUTPUT_BASENAME (stream, name);
15550117395Skan  putc ('\n', stream);
1555190075Sobrien}
15552117395Skan
15553117395Skanstatic void
15554132718Skanrs6000_xcoff_asm_named_section (const char *name, unsigned int flags)
15555117395Skan{
15556117395Skan  int smclass;
15557117395Skan  static const char * const suffix[3] = { "PR", "RO", "RW" };
15558117395Skan
15559117395Skan  if (flags & SECTION_CODE)
15560117395Skan    smclass = 0;
15561117395Skan  else if (flags & SECTION_WRITE)
15562117395Skan    smclass = 2;
15563117395Skan  else
15564117395Skan    smclass = 1;
15565117395Skan
15566117395Skan  fprintf (asm_out_file, "\t.csect %s%s[%s],%u\n",
15567117395Skan	   (flags & SECTION_CODE) ? "." : "",
15568117395Skan	   name, suffix[smclass], flags & SECTION_ENTSIZE);
15569117395Skan}
15570117395Skan
15571117395Skanstatic void
15572132718Skanrs6000_xcoff_select_section (tree decl, int reloc,
15573132718Skan			    unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
15574117395Skan{
15575117395Skan  if (decl_readonly_section_1 (decl, reloc, 1))
15576117395Skan    {
15577117395Skan      if (TREE_PUBLIC (decl))
15578117395Skan        read_only_data_section ();
15579117395Skan      else
15580117395Skan        read_only_private_data_section ();
15581117395Skan    }
15582117395Skan  else
15583117395Skan    {
15584117395Skan      if (TREE_PUBLIC (decl))
15585117395Skan        data_section ();
15586117395Skan      else
15587117395Skan        private_data_section ();
15588117395Skan    }
15589117395Skan}
15590117395Skan
15591117395Skanstatic void
15592132718Skanrs6000_xcoff_unique_section (tree decl, int reloc ATTRIBUTE_UNUSED)
15593117395Skan{
15594117395Skan  const char *name;
15595117395Skan
15596117395Skan  /* Use select_section for private and uninitialized data.  */
15597117395Skan  if (!TREE_PUBLIC (decl)
15598117395Skan      || DECL_COMMON (decl)
15599117395Skan      || DECL_INITIAL (decl) == NULL_TREE
15600117395Skan      || DECL_INITIAL (decl) == error_mark_node
15601117395Skan      || (flag_zero_initialized_in_bss
15602117395Skan	  && initializer_zerop (DECL_INITIAL (decl))))
15603117395Skan    return;
15604117395Skan
15605117395Skan  name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
15606117395Skan  name = (*targetm.strip_name_encoding) (name);
15607117395Skan  DECL_SECTION_NAME (decl) = build_string (strlen (name), name);
15608117395Skan}
15609117395Skan
15610117395Skan/* Select section for constant in constant pool.
15611117395Skan
15612117395Skan   On RS/6000, all constants are in the private read-only data area.
15613117395Skan   However, if this is being placed in the TOC it must be output as a
15614117395Skan   toc entry.  */
15615117395Skan
15616117395Skanstatic void
15617132718Skanrs6000_xcoff_select_rtx_section (enum machine_mode mode, rtx x,
15618132718Skan				unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
15619117395Skan{
15620117395Skan  if (ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (x, mode))
15621117395Skan    toc_section ();
15622117395Skan  else
15623117395Skan    read_only_private_data_section ();
15624117395Skan}
15625117395Skan
15626117395Skan/* Remove any trailing [DS] or the like from the symbol name.  */
15627117395Skan
15628117395Skanstatic const char *
15629132718Skanrs6000_xcoff_strip_name_encoding (const char *name)
15630117395Skan{
15631117395Skan  size_t len;
15632117395Skan  if (*name == '*')
15633117395Skan    name++;
15634117395Skan  len = strlen (name);
15635117395Skan  if (name[len - 1] == ']')
15636117395Skan    return ggc_alloc_string (name, len - 4);
15637117395Skan  else
15638117395Skan    return name;
15639117395Skan}
15640117395Skan
15641117395Skan/* Section attributes.  AIX is always PIC.  */
15642117395Skan
15643117395Skanstatic unsigned int
15644132718Skanrs6000_xcoff_section_type_flags (tree decl, const char *name, int reloc)
15645117395Skan{
15646117395Skan  unsigned int align;
15647117395Skan  unsigned int flags = default_section_type_flags_1 (decl, name, reloc, 1);
15648117395Skan
15649117395Skan  /* Align to at least UNIT size.  */
15650117395Skan  if (flags & SECTION_CODE)
15651117395Skan    align = MIN_UNITS_PER_WORD;
15652117395Skan  else
15653117395Skan    /* Increase alignment of large objects if not already stricter.  */
15654117395Skan    align = MAX ((DECL_ALIGN (decl) / BITS_PER_UNIT),
15655117395Skan		 int_size_in_bytes (TREE_TYPE (decl)) > MIN_UNITS_PER_WORD
15656117395Skan		 ? UNITS_PER_FP_WORD : MIN_UNITS_PER_WORD);
15657117395Skan
15658117395Skan  return flags | (exact_log2 (align) & SECTION_ENTSIZE);
15659117395Skan}
15660117395Skan
15661132718Skan/* Output at beginning of assembler file.
15662117395Skan
15663132718Skan   Initialize the section names for the RS/6000 at this point.
15664117395Skan
15665132718Skan   Specify filename, including full path, to assembler.
15666132718Skan
15667132718Skan   We want to go into the TOC section so at least one .toc will be emitted.
15668132718Skan   Also, in order to output proper .bs/.es pairs, we need at least one static
15669132718Skan   [RW] section emitted.
15670132718Skan
15671132718Skan   Finally, declare mcount when profiling to make the assembler happy.  */
15672132718Skan
15673117395Skanstatic void
15674132718Skanrs6000_xcoff_file_start (void)
15675117395Skan{
15676132718Skan  rs6000_gen_section_name (&xcoff_bss_section_name,
15677132718Skan			   main_input_filename, ".bss_");
15678132718Skan  rs6000_gen_section_name (&xcoff_private_data_section_name,
15679132718Skan			   main_input_filename, ".rw_");
15680132718Skan  rs6000_gen_section_name (&xcoff_read_only_section_name,
15681132718Skan			   main_input_filename, ".ro_");
15682132718Skan
15683132718Skan  fputs ("\t.file\t", asm_out_file);
15684132718Skan  output_quoted_string (asm_out_file, main_input_filename);
15685132718Skan  fputc ('\n', asm_out_file);
15686132718Skan  toc_section ();
15687132718Skan  if (write_symbols != NO_DEBUG)
15688132718Skan    private_data_section ();
15689132718Skan  text_section ();
15690132718Skan  if (profile_flag)
15691132718Skan    fprintf (asm_out_file, "\t.extern %s\n", RS6000_MCOUNT);
15692132718Skan  rs6000_file_start ();
15693117395Skan}
15694117395Skan
15695132718Skan/* Output at end of assembler file.
15696132718Skan   On the RS/6000, referencing data should automatically pull in text.  */
15697117395Skan
15698132718Skanstatic void
15699132718Skanrs6000_xcoff_file_end (void)
15700132718Skan{
15701132718Skan  text_section ();
15702132718Skan  fputs ("_section_.text:\n", asm_out_file);
15703132718Skan  data_section ();
15704132718Skan  fputs (TARGET_32BIT
15705132718Skan	 ? "\t.long _section_.text\n" : "\t.llong _section_.text\n",
15706132718Skan	 asm_out_file);
15707132718Skan}
15708132718Skan#endif /* TARGET_XCOFF */
15709132718Skan
15710132718Skan#if TARGET_MACHO
15711132718Skan/* Cross-module name binding.  Darwin does not support overriding
15712132718Skan   functions at dynamic-link time.  */
15713132718Skan
15714117395Skanstatic bool
15715132718Skanrs6000_binds_local_p (tree decl)
15716117395Skan{
15717132718Skan  return default_binds_local_p_1 (decl, 0);
15718117395Skan}
15719132718Skan#endif
15720117395Skan
15721132718Skan/* Compute a (partial) cost for rtx X.  Return true if the complete
15722132718Skan   cost has been computed, and false if subexpressions should be
15723132718Skan   scanned.  In either case, *TOTAL contains the cost result.  */
15724132718Skan
15725132718Skanstatic bool
15726132718Skanrs6000_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED,
15727132718Skan		  int *total)
15728132718Skan{
15729132718Skan  switch (code)
15730132718Skan    {
15731132718Skan      /* On the RS/6000, if it is valid in the insn, it is free.
15732132718Skan	 So this always returns 0.  */
15733132718Skan    case CONST_INT:
15734132718Skan    case CONST:
15735132718Skan    case LABEL_REF:
15736132718Skan    case SYMBOL_REF:
15737132718Skan    case CONST_DOUBLE:
15738132718Skan    case HIGH:
15739132718Skan      *total = 0;
15740132718Skan      return true;
15741132718Skan
15742132718Skan    case PLUS:
15743132718Skan      *total = ((GET_CODE (XEXP (x, 1)) == CONST_INT
15744132718Skan		 && ((unsigned HOST_WIDE_INT) (INTVAL (XEXP (x, 1))
15745132718Skan					       + 0x8000) >= 0x10000)
15746132718Skan		 && ((INTVAL (XEXP (x, 1)) & 0xffff) != 0))
15747132718Skan		? COSTS_N_INSNS (2)
15748132718Skan		: COSTS_N_INSNS (1));
15749132718Skan      return true;
15750132718Skan
15751132718Skan    case AND:
15752132718Skan    case IOR:
15753132718Skan    case XOR:
15754132718Skan      *total = ((GET_CODE (XEXP (x, 1)) == CONST_INT
15755132718Skan		 && (INTVAL (XEXP (x, 1)) & (~ (HOST_WIDE_INT) 0xffff)) != 0
15756132718Skan		 && ((INTVAL (XEXP (x, 1)) & 0xffff) != 0))
15757132718Skan		? COSTS_N_INSNS (2)
15758132718Skan		: COSTS_N_INSNS (1));
15759132718Skan      return true;
15760132718Skan
15761132718Skan    case MULT:
15762132718Skan      if (optimize_size)
15763132718Skan	{
15764132718Skan	  *total = COSTS_N_INSNS (2);
15765132718Skan	  return true;
15766132718Skan	}
15767132718Skan      switch (rs6000_cpu)
15768132718Skan	{
15769132718Skan	case PROCESSOR_RIOS1:
15770132718Skan	case PROCESSOR_PPC405:
15771132718Skan	  *total = (GET_CODE (XEXP (x, 1)) != CONST_INT
15772132718Skan		    ? COSTS_N_INSNS (5)
15773132718Skan		    : (INTVAL (XEXP (x, 1)) >= -256
15774132718Skan		       && INTVAL (XEXP (x, 1)) <= 255)
15775132718Skan		    ? COSTS_N_INSNS (3) : COSTS_N_INSNS (4));
15776132718Skan	  return true;
15777132718Skan
15778132718Skan	case PROCESSOR_PPC440:
15779132718Skan	  *total = (GET_CODE (XEXP (x, 1)) != CONST_INT
15780132718Skan		    ? COSTS_N_INSNS (3)
15781132718Skan		    : COSTS_N_INSNS (2));
15782132718Skan	  return true;
15783132718Skan
15784132718Skan	case PROCESSOR_RS64A:
15785132718Skan	  *total = (GET_CODE (XEXP (x, 1)) != CONST_INT
15786132718Skan		    ? GET_MODE (XEXP (x, 1)) != DImode
15787132718Skan		    ? COSTS_N_INSNS (20) : COSTS_N_INSNS (34)
15788132718Skan		    : (INTVAL (XEXP (x, 1)) >= -256
15789132718Skan		       && INTVAL (XEXP (x, 1)) <= 255)
15790132718Skan		    ? COSTS_N_INSNS (8) : COSTS_N_INSNS (12));
15791132718Skan	  return true;
15792132718Skan
15793132718Skan	case PROCESSOR_RIOS2:
15794132718Skan	case PROCESSOR_MPCCORE:
15795132718Skan	case PROCESSOR_PPC604e:
15796132718Skan	  *total = COSTS_N_INSNS (2);
15797132718Skan	  return true;
15798132718Skan
15799132718Skan	case PROCESSOR_PPC601:
15800132718Skan	  *total = COSTS_N_INSNS (5);
15801132718Skan	  return true;
15802132718Skan
15803132718Skan	case PROCESSOR_PPC603:
15804132718Skan	case PROCESSOR_PPC7400:
15805132718Skan	case PROCESSOR_PPC750:
15806132718Skan	  *total = (GET_CODE (XEXP (x, 1)) != CONST_INT
15807132718Skan		    ? COSTS_N_INSNS (5)
15808132718Skan		    : (INTVAL (XEXP (x, 1)) >= -256
15809132718Skan		       && INTVAL (XEXP (x, 1)) <= 255)
15810132718Skan		    ? COSTS_N_INSNS (2) : COSTS_N_INSNS (3));
15811132718Skan	  return true;
15812132718Skan
15813132718Skan	case PROCESSOR_PPC7450:
15814132718Skan	  *total = (GET_CODE (XEXP (x, 1)) != CONST_INT
15815132718Skan		    ? COSTS_N_INSNS (4)
15816132718Skan		    : COSTS_N_INSNS (3));
15817132718Skan	  return true;
15818132718Skan
15819132718Skan	case PROCESSOR_PPC403:
15820132718Skan	case PROCESSOR_PPC604:
15821132718Skan	case PROCESSOR_PPC8540:
15822132718Skan	  *total = COSTS_N_INSNS (4);
15823132718Skan	  return true;
15824132718Skan
15825132718Skan	case PROCESSOR_PPC620:
15826132718Skan	case PROCESSOR_PPC630:
15827132718Skan	  *total = (GET_CODE (XEXP (x, 1)) != CONST_INT
15828132718Skan		    ? GET_MODE (XEXP (x, 1)) != DImode
15829132718Skan		    ? COSTS_N_INSNS (5) : COSTS_N_INSNS (7)
15830132718Skan		    : (INTVAL (XEXP (x, 1)) >= -256
15831132718Skan		       && INTVAL (XEXP (x, 1)) <= 255)
15832132718Skan		    ? COSTS_N_INSNS (3) : COSTS_N_INSNS (4));
15833132718Skan	  return true;
15834132718Skan
15835132718Skan	case PROCESSOR_POWER4:
15836132718Skan	case PROCESSOR_POWER5:
15837132718Skan	  *total = (GET_CODE (XEXP (x, 1)) != CONST_INT
15838132718Skan		    ? GET_MODE (XEXP (x, 1)) != DImode
15839132718Skan		    ? COSTS_N_INSNS (3) : COSTS_N_INSNS (4)
15840132718Skan		    : COSTS_N_INSNS (2));
15841132718Skan	  return true;
15842132718Skan
15843132718Skan	default:
15844132718Skan	  abort ();
15845132718Skan	}
15846132718Skan
15847132718Skan    case DIV:
15848132718Skan    case MOD:
15849132718Skan      if (GET_CODE (XEXP (x, 1)) == CONST_INT
15850132718Skan	  && exact_log2 (INTVAL (XEXP (x, 1))) >= 0)
15851132718Skan	{
15852132718Skan	  *total = COSTS_N_INSNS (2);
15853132718Skan	  return true;
15854132718Skan	}
15855132718Skan      /* FALLTHRU */
15856132718Skan
15857132718Skan    case UDIV:
15858132718Skan    case UMOD:
15859132718Skan      switch (rs6000_cpu)
15860132718Skan	{
15861132718Skan	case PROCESSOR_RIOS1:
15862132718Skan	  *total = COSTS_N_INSNS (19);
15863132718Skan	  return true;
15864132718Skan
15865132718Skan	case PROCESSOR_RIOS2:
15866132718Skan	  *total = COSTS_N_INSNS (13);
15867132718Skan	  return true;
15868132718Skan
15869132718Skan	case PROCESSOR_RS64A:
15870132718Skan	  *total = (GET_MODE (XEXP (x, 1)) != DImode
15871132718Skan		    ? COSTS_N_INSNS (65)
15872132718Skan		    : COSTS_N_INSNS (67));
15873132718Skan	  return true;
15874132718Skan
15875132718Skan	case PROCESSOR_MPCCORE:
15876132718Skan	  *total = COSTS_N_INSNS (6);
15877132718Skan	  return true;
15878132718Skan
15879132718Skan	case PROCESSOR_PPC403:
15880132718Skan	  *total = COSTS_N_INSNS (33);
15881132718Skan	  return true;
15882132718Skan
15883132718Skan	case PROCESSOR_PPC405:
15884132718Skan	  *total = COSTS_N_INSNS (35);
15885132718Skan	  return true;
15886132718Skan
15887132718Skan	case PROCESSOR_PPC440:
15888132718Skan	  *total = COSTS_N_INSNS (34);
15889132718Skan	  return true;
15890132718Skan
15891132718Skan	case PROCESSOR_PPC601:
15892132718Skan	  *total = COSTS_N_INSNS (36);
15893132718Skan	  return true;
15894132718Skan
15895132718Skan	case PROCESSOR_PPC603:
15896132718Skan	  *total = COSTS_N_INSNS (37);
15897132718Skan	  return true;
15898132718Skan
15899132718Skan	case PROCESSOR_PPC604:
15900132718Skan	case PROCESSOR_PPC604e:
15901132718Skan	  *total = COSTS_N_INSNS (20);
15902132718Skan	  return true;
15903132718Skan
15904132718Skan	case PROCESSOR_PPC620:
15905132718Skan	case PROCESSOR_PPC630:
15906132718Skan	  *total = (GET_MODE (XEXP (x, 1)) != DImode
15907132718Skan		    ? COSTS_N_INSNS (21)
15908132718Skan		    : COSTS_N_INSNS (37));
15909132718Skan	  return true;
15910132718Skan
15911132718Skan	case PROCESSOR_PPC750:
15912132718Skan	case PROCESSOR_PPC8540:
15913132718Skan	case PROCESSOR_PPC7400:
15914132718Skan	  *total = COSTS_N_INSNS (19);
15915132718Skan	  return true;
15916132718Skan
15917132718Skan	case PROCESSOR_PPC7450:
15918132718Skan	  *total = COSTS_N_INSNS (23);
15919132718Skan	  return true;
15920132718Skan
15921132718Skan	case PROCESSOR_POWER4:
15922132718Skan	case PROCESSOR_POWER5:
15923132718Skan	  *total = (GET_MODE (XEXP (x, 1)) != DImode
15924132718Skan		    ? COSTS_N_INSNS (18)
15925132718Skan		    : COSTS_N_INSNS (34));
15926132718Skan	  return true;
15927132718Skan
15928132718Skan	default:
15929132718Skan	  abort ();
15930132718Skan	}
15931132718Skan
15932132718Skan    case FFS:
15933132718Skan      *total = COSTS_N_INSNS (4);
15934132718Skan      return true;
15935132718Skan
15936132718Skan    case MEM:
15937132718Skan      /* MEM should be slightly more expensive than (plus (reg) (const)).  */
15938132718Skan      *total = 5;
15939132718Skan      return true;
15940132718Skan
15941132718Skan    default:
15942132718Skan      return false;
15943132718Skan    }
15944132718Skan}
15945132718Skan
15946117395Skan/* A C expression returning the cost of moving data from a register of class
15947117395Skan   CLASS1 to one of CLASS2.  */
15948117395Skan
15949117395Skanint
15950132718Skanrs6000_register_move_cost (enum machine_mode mode,
15951132718Skan			   enum reg_class from, enum reg_class to)
15952117395Skan{
15953117395Skan  /*  Moves from/to GENERAL_REGS.  */
15954117395Skan  if (reg_classes_intersect_p (to, GENERAL_REGS)
15955117395Skan      || reg_classes_intersect_p (from, GENERAL_REGS))
15956117395Skan    {
15957117395Skan      if (! reg_classes_intersect_p (to, GENERAL_REGS))
15958117395Skan	from = to;
15959117395Skan
15960117395Skan      if (from == FLOAT_REGS || from == ALTIVEC_REGS)
15961117395Skan	return (rs6000_memory_move_cost (mode, from, 0)
15962117395Skan		+ rs6000_memory_move_cost (mode, GENERAL_REGS, 0));
15963117395Skan
15964132718Skan/* It's more expensive to move CR_REGS than CR0_REGS because of the shift....  */
15965117395Skan      else if (from == CR_REGS)
15966117395Skan	return 4;
15967117395Skan
15968117395Skan      else
15969117395Skan/* A move will cost one instruction per GPR moved.  */
15970117395Skan	return 2 * HARD_REGNO_NREGS (0, mode);
15971117395Skan    }
15972117395Skan
15973117395Skan/* Moving between two similar registers is just one instruction.  */
15974117395Skan  else if (reg_classes_intersect_p (to, from))
15975117395Skan    return mode == TFmode ? 4 : 2;
15976117395Skan
15977117395Skan/* Everything else has to go through GENERAL_REGS.  */
15978117395Skan  else
15979117395Skan    return (rs6000_register_move_cost (mode, GENERAL_REGS, to)
15980117395Skan	    + rs6000_register_move_cost (mode, from, GENERAL_REGS));
15981117395Skan}
15982117395Skan
15983117395Skan/* A C expressions returning the cost of moving data of MODE from a register to
15984117395Skan   or from memory.  */
15985117395Skan
15986117395Skanint
15987132718Skanrs6000_memory_move_cost (enum machine_mode mode, enum reg_class class,
15988132718Skan			 int in ATTRIBUTE_UNUSED)
15989117395Skan{
15990117395Skan  if (reg_classes_intersect_p (class, GENERAL_REGS))
15991117395Skan    return 4 * HARD_REGNO_NREGS (0, mode);
15992117395Skan  else if (reg_classes_intersect_p (class, FLOAT_REGS))
15993117395Skan    return 4 * HARD_REGNO_NREGS (32, mode);
15994117395Skan  else if (reg_classes_intersect_p (class, ALTIVEC_REGS))
15995117395Skan    return 4 * HARD_REGNO_NREGS (FIRST_ALTIVEC_REGNO, mode);
15996117395Skan  else
15997117395Skan    return 4 + rs6000_register_move_cost (mode, class, GENERAL_REGS);
15998117395Skan}
15999117395Skan
16000132718Skan/* Return an RTX representing where to find the function value of a
16001132718Skan   function returning MODE.  */
16002132718Skanstatic rtx
16003132718Skanrs6000_complex_function_value (enum machine_mode mode)
16004132718Skan{
16005132718Skan  unsigned int regno;
16006132718Skan  rtx r1, r2;
16007132718Skan  enum machine_mode inner = GET_MODE_INNER (mode);
16008132718Skan  unsigned int inner_bytes = GET_MODE_SIZE (inner);
16009132718Skan
16010132718Skan  if (FLOAT_MODE_P (mode) && TARGET_HARD_FLOAT && TARGET_FPRS)
16011132718Skan    regno = FP_ARG_RETURN;
16012132718Skan  else
16013132718Skan    {
16014132718Skan      regno = GP_ARG_RETURN;
16015132718Skan
16016132718Skan      /* 32-bit is OK since it'll go in r3/r4.  */
16017132718Skan      if (TARGET_32BIT && inner_bytes >= 4)
16018132718Skan	return gen_rtx_REG (mode, regno);
16019132718Skan    }
16020132718Skan
16021132718Skan  if (inner_bytes >= 8)
16022132718Skan    return gen_rtx_REG (mode, regno);
16023132718Skan
16024132718Skan  r1 = gen_rtx_EXPR_LIST (inner, gen_rtx_REG (inner, regno),
16025132718Skan			  const0_rtx);
16026132718Skan  r2 = gen_rtx_EXPR_LIST (inner, gen_rtx_REG (inner, regno + 1),
16027132718Skan			  GEN_INT (inner_bytes));
16028132718Skan  return gen_rtx_PARALLEL (mode, gen_rtvec (2, r1, r2));
16029132718Skan}
16030132718Skan
16031132718Skan/* Define how to find the value returned by a function.
16032132718Skan   VALTYPE is the data type of the value (as a tree).
16033132718Skan   If the precise function being called is known, FUNC is its FUNCTION_DECL;
16034132718Skan   otherwise, FUNC is 0.
16035132718Skan
16036132718Skan   On the SPE, both FPs and vectors are returned in r3.
16037132718Skan
16038132718Skan   On RS/6000 an integer value is in r3 and a floating-point value is in
16039132718Skan   fp1, unless -msoft-float.  */
16040132718Skan
16041132718Skanrtx
16042132718Skanrs6000_function_value (tree valtype, tree func ATTRIBUTE_UNUSED)
16043132718Skan{
16044132718Skan  enum machine_mode mode;
16045132718Skan  unsigned int regno;
16046132718Skan
16047132718Skan  if (TARGET_32BIT && TARGET_POWERPC64 && TYPE_MODE (valtype) == DImode)
16048132718Skan    {
16049132718Skan      /* Long long return value need be split in -mpowerpc64, 32bit ABI.  */
16050132718Skan      return gen_rtx_PARALLEL (DImode,
16051132718Skan	gen_rtvec (2,
16052132718Skan		   gen_rtx_EXPR_LIST (VOIDmode,
16053132718Skan				      gen_rtx_REG (SImode, GP_ARG_RETURN),
16054132718Skan				      const0_rtx),
16055132718Skan		   gen_rtx_EXPR_LIST (VOIDmode,
16056132718Skan				      gen_rtx_REG (SImode,
16057132718Skan						   GP_ARG_RETURN + 1),
16058132718Skan				      GEN_INT (4))));
16059132718Skan    }
16060132718Skan
16061132718Skan  if ((INTEGRAL_TYPE_P (valtype)
16062132718Skan       && TYPE_PRECISION (valtype) < BITS_PER_WORD)
16063132718Skan      || POINTER_TYPE_P (valtype))
16064132718Skan    mode = TARGET_32BIT ? SImode : DImode;
16065132718Skan  else
16066132718Skan    mode = TYPE_MODE (valtype);
16067132718Skan
16068132718Skan  if (SCALAR_FLOAT_TYPE_P (valtype) && TARGET_HARD_FLOAT && TARGET_FPRS)
16069132718Skan    regno = FP_ARG_RETURN;
16070132718Skan  else if (TREE_CODE (valtype) == COMPLEX_TYPE
16071132718Skan	   && targetm.calls.split_complex_arg)
16072132718Skan    return rs6000_complex_function_value (mode);
16073132718Skan  else if (TREE_CODE (valtype) == VECTOR_TYPE
16074132718Skan	   && TARGET_ALTIVEC && TARGET_ALTIVEC_ABI)
16075132718Skan    regno = ALTIVEC_ARG_RETURN;
16076132718Skan  else
16077132718Skan    regno = GP_ARG_RETURN;
16078132718Skan
16079132718Skan  return gen_rtx_REG (mode, regno);
16080132718Skan}
16081132718Skan
16082132718Skan/* Define how to find the value returned by a library function
16083132718Skan   assuming the value has mode MODE.  */
16084132718Skanrtx
16085132718Skanrs6000_libcall_value (enum machine_mode mode)
16086132718Skan{
16087132718Skan  unsigned int regno;
16088132718Skan
16089132718Skan  if (GET_MODE_CLASS (mode) == MODE_FLOAT
16090132718Skan	   && TARGET_HARD_FLOAT && TARGET_FPRS)
16091132718Skan    regno = FP_ARG_RETURN;
16092132718Skan  else if (ALTIVEC_VECTOR_MODE (mode)
16093132718Skan	   && TARGET_ALTIVEC && TARGET_ALTIVEC_ABI)
16094132718Skan    regno = ALTIVEC_ARG_RETURN;
16095132718Skan  else if (COMPLEX_MODE_P (mode) && targetm.calls.split_complex_arg)
16096132718Skan    return rs6000_complex_function_value (mode);
16097132718Skan  else
16098132718Skan    regno = GP_ARG_RETURN;
16099132718Skan
16100132718Skan  return gen_rtx_REG (mode, regno);
16101132718Skan}
16102132718Skan
16103132718Skan/* Define the offset between two registers, FROM to be eliminated and its
16104132718Skan   replacement TO, at the start of a routine.  */
16105132718SkanHOST_WIDE_INT
16106132718Skanrs6000_initial_elimination_offset (int from, int to)
16107132718Skan{
16108132718Skan  rs6000_stack_t *info = rs6000_stack_info ();
16109132718Skan  HOST_WIDE_INT offset;
16110132718Skan
16111132718Skan  if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
16112132718Skan    offset = info->push_p ? 0 : -info->total_size;
16113132718Skan  else if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)
16114132718Skan    offset = info->total_size;
16115132718Skan  else if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
16116132718Skan    offset = info->push_p ? info->total_size : 0;
16117132718Skan  else if (from == RS6000_PIC_OFFSET_TABLE_REGNUM)
16118132718Skan    offset = 0;
16119132718Skan  else
16120132718Skan    abort ();
16121132718Skan
16122132718Skan  return offset;
16123132718Skan}
16124132718Skan
16125132718Skan/* Return true if TYPE is of type __ev64_opaque__.  */
16126132718Skan
16127132718Skanstatic bool
16128132718Skanis_ev64_opaque_type (tree type)
16129132718Skan{
16130132718Skan  return (TARGET_SPE
16131132718Skan	  && (type == opaque_V2SI_type_node
16132132718Skan	      || type == opaque_V2SF_type_node
16133132718Skan	      || type == opaque_p_V2SI_type_node));
16134132718Skan}
16135132718Skan
16136132718Skanstatic rtx
16137132718Skanrs6000_dwarf_register_span (rtx reg)
16138132718Skan{
16139132718Skan  unsigned regno;
16140132718Skan
16141132718Skan  if (!TARGET_SPE || !SPE_VECTOR_MODE (GET_MODE (reg)))
16142132718Skan    return NULL_RTX;
16143132718Skan
16144132718Skan  regno = REGNO (reg);
16145132718Skan
16146132718Skan  /* The duality of the SPE register size wreaks all kinds of havoc.
16147132718Skan     This is a way of distinguishing r0 in 32-bits from r0 in
16148132718Skan     64-bits.  */
16149132718Skan  return
16150132718Skan    gen_rtx_PARALLEL (VOIDmode,
16151132718Skan		      BYTES_BIG_ENDIAN
16152132718Skan		      ? gen_rtvec (2,
16153132718Skan				   gen_rtx_REG (SImode, regno + 1200),
16154132718Skan				   gen_rtx_REG (SImode, regno))
16155132718Skan		      : gen_rtvec (2,
16156132718Skan				   gen_rtx_REG (SImode, regno),
16157132718Skan				   gen_rtx_REG (SImode, regno + 1200)));
16158132718Skan}
16159132718Skan
16160132718Skan/* Map internal gcc register numbers to DWARF2 register numbers.  */
16161132718Skan
16162132718Skanunsigned int
16163132718Skanrs6000_dbx_register_number (unsigned int regno)
16164132718Skan{
16165132718Skan  if (regno <= 63 || write_symbols != DWARF2_DEBUG)
16166132718Skan    return regno;
16167132718Skan  if (regno == MQ_REGNO)
16168132718Skan    return 100;
16169132718Skan  if (regno == LINK_REGISTER_REGNUM)
16170132718Skan    return 108;
16171132718Skan  if (regno == COUNT_REGISTER_REGNUM)
16172132718Skan    return 109;
16173132718Skan  if (CR_REGNO_P (regno))
16174132718Skan    return regno - CR0_REGNO + 86;
16175132718Skan  if (regno == XER_REGNO)
16176132718Skan    return 101;
16177132718Skan  if (ALTIVEC_REGNO_P (regno))
16178132718Skan    return regno - FIRST_ALTIVEC_REGNO + 1124;
16179132718Skan  if (regno == VRSAVE_REGNO)
16180132718Skan    return 356;
16181132718Skan  if (regno == VSCR_REGNO)
16182132718Skan    return 67;
16183132718Skan  if (regno == SPE_ACC_REGNO)
16184132718Skan    return 99;
16185132718Skan  if (regno == SPEFSCR_REGNO)
16186132718Skan    return 612;
16187132718Skan  /* SPE high reg number.  We get these values of regno from
16188132718Skan     rs6000_dwarf_register_span.  */
16189132718Skan  if (regno >= 1200 && regno < 1232)
16190132718Skan    return regno;
16191132718Skan
16192132718Skan  abort ();
16193132718Skan}
16194132718Skan
16195132718Skan#include "gt-rs6000.h"
16196