rs6000.c revision 161651
190075Sobrien/* Subroutines used for code generation on IBM RS/6000.
290075Sobrien   Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
3146895Skan   2000, 2001, 2002, 2003, 2004, 2005 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
223146895Skan/* AltiVec requires a few more basic types in addition to the vector
224146895Skan   types already defined in tree.c.  */
225146895Skanstatic GTY(()) tree bool_char_type_node;	/* __bool char */
226146895Skanstatic GTY(()) tree bool_short_type_node;	/* __bool short */
227146895Skanstatic GTY(()) tree bool_int_type_node;		/* __bool int */
228146895Skanstatic GTY(()) tree pixel_type_node;		/* __pixel */
229146895Skanstatic GTY(()) tree bool_V16QI_type_node;	/* __vector __bool char */
230146895Skanstatic GTY(()) tree bool_V8HI_type_node;	/* __vector __bool short */
231146895Skanstatic GTY(()) tree bool_V4SI_type_node;	/* __vector __bool int */
232146895Skanstatic GTY(()) tree pixel_V8HI_type_node;	/* __vector __pixel */
233146895Skan
234146895Skanint rs6000_warn_altivec_long = 1;		/* On by default. */
235146895Skanconst char *rs6000_warn_altivec_long_switch;
236146895Skan
237117395Skanconst char *rs6000_traceback_name;
238117395Skanstatic enum {
239117395Skan  traceback_default = 0,
240117395Skan  traceback_none,
241117395Skan  traceback_part,
242117395Skan  traceback_full
243117395Skan} rs6000_traceback;
244117395Skan
24590075Sobrien/* Flag to say the TOC is initialized */
24690075Sobrienint toc_initialized;
24790075Sobrienchar toc_label_name[10];
24890075Sobrien
24990075Sobrien/* Alias set for saves and restores from the rs6000 stack.  */
250132718Skanstatic GTY(()) int rs6000_sr_alias_set;
25190075Sobrien
252117395Skan/* Call distance, overridden by -mlongcall and #pragma longcall(1).
253117395Skan   The only place that looks at this is rs6000_set_default_type_attributes;
254117395Skan   everywhere else should rely on the presence or absence of a longcall
255146895Skan   attribute on the function declaration.  Exception: init_cumulative_args
256146895Skan   looks at it too, for libcalls.  */
257117395Skanint rs6000_default_long_calls;
258117395Skanconst char *rs6000_longcall_switch;
259117395Skan
260132718Skan/* Control alignment for fields within structures.  */
261132718Skan/* String from -malign-XXXXX.  */
262132718Skanconst char *rs6000_alignment_string;
263132718Skanint rs6000_alignment_flags;
264132718Skan
265117395Skanstruct builtin_description
266117395Skan{
267117395Skan  /* mask is not const because we're going to alter it below.  This
268117395Skan     nonsense will go away when we rewrite the -march infrastructure
269117395Skan     to give us more target flag bits.  */
270117395Skan  unsigned int mask;
271117395Skan  const enum insn_code icode;
272117395Skan  const char *const name;
273117395Skan  const enum rs6000_builtins code;
274117395Skan};
275117395Skan
276132718Skanstatic bool rs6000_function_ok_for_sibcall (tree, tree);
277132718Skanstatic int num_insns_constant_wide (HOST_WIDE_INT);
278132718Skanstatic void validate_condition_mode (enum rtx_code, enum machine_mode);
279132718Skanstatic rtx rs6000_generate_compare (enum rtx_code);
280132718Skanstatic void rs6000_maybe_dead (rtx);
281132718Skanstatic void rs6000_emit_stack_tie (void);
282132718Skanstatic void rs6000_frame_related (rtx, rtx, HOST_WIDE_INT, rtx, rtx);
283132718Skanstatic rtx spe_synthesize_frame_save (rtx);
284132718Skanstatic bool spe_func_has_64bit_regs_p (void);
285132718Skanstatic void emit_frame_save (rtx, rtx, enum machine_mode, unsigned int,
286132718Skan			     int, HOST_WIDE_INT);
287132718Skanstatic rtx gen_frame_mem_offset (enum machine_mode, rtx, int);
288132718Skanstatic void rs6000_emit_allocate_stack (HOST_WIDE_INT, int);
289132718Skanstatic unsigned rs6000_hash_constant (rtx);
290132718Skanstatic unsigned toc_hash_function (const void *);
291132718Skanstatic int toc_hash_eq (const void *, const void *);
292132718Skanstatic int constant_pool_expr_1 (rtx, int *, int *);
293132718Skanstatic bool constant_pool_expr_p (rtx);
294132718Skanstatic bool toc_relative_expr_p (rtx);
295132718Skanstatic bool legitimate_small_data_p (enum machine_mode, rtx);
296132718Skanstatic bool legitimate_offset_address_p (enum machine_mode, rtx, int);
297132718Skanstatic bool legitimate_indexed_address_p (rtx, int);
298132718Skanstatic bool legitimate_indirect_address_p (rtx, int);
299132718Skanstatic bool macho_lo_sum_memory_operand (rtx x, enum machine_mode mode);
300132718Skanstatic bool legitimate_lo_sum_address_p (enum machine_mode, rtx, int);
301132718Skanstatic struct machine_function * rs6000_init_machine_status (void);
302132718Skanstatic bool rs6000_assemble_integer (rtx, unsigned int, int);
303117395Skan#ifdef HAVE_GAS_HIDDEN
304132718Skanstatic void rs6000_assemble_visibility (tree, int);
305117395Skan#endif
306132718Skanstatic int rs6000_ra_ever_killed (void);
307132718Skanstatic tree rs6000_handle_longcall_attribute (tree *, tree, tree, int, bool *);
308146895Skanstatic tree rs6000_handle_altivec_attribute (tree *, tree, tree, int, bool *);
309146895Skanstatic const char *rs6000_mangle_fundamental_type (tree);
310132718Skanextern const struct attribute_spec rs6000_attribute_table[];
311132718Skanstatic void rs6000_set_default_type_attributes (tree);
312132718Skanstatic void rs6000_output_function_prologue (FILE *, HOST_WIDE_INT);
313132718Skanstatic void rs6000_output_function_epilogue (FILE *, HOST_WIDE_INT);
314132718Skanstatic void rs6000_output_mi_thunk (FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT,
315132718Skan				    tree);
316132718Skanstatic rtx rs6000_emit_set_long_const (rtx, HOST_WIDE_INT, HOST_WIDE_INT);
317132718Skanstatic bool rs6000_return_in_memory (tree, tree);
318132718Skanstatic void rs6000_file_start (void);
31990075Sobrien#if TARGET_ELF
320132718Skanstatic unsigned int rs6000_elf_section_type_flags (tree, const char *, int);
321132718Skanstatic void rs6000_elf_asm_out_constructor (rtx, int);
322132718Skanstatic void rs6000_elf_asm_out_destructor (rtx, int);
323146895Skanstatic void rs6000_elf_end_indicate_exec_stack (void) ATTRIBUTE_UNUSED;
324132718Skanstatic void rs6000_elf_select_section (tree, int, unsigned HOST_WIDE_INT);
325132718Skanstatic void rs6000_elf_unique_section (tree, int);
326132718Skanstatic void rs6000_elf_select_rtx_section (enum machine_mode, rtx,
327132718Skan					   unsigned HOST_WIDE_INT);
328132718Skanstatic void rs6000_elf_encode_section_info (tree, rtx, int)
329117395Skan     ATTRIBUTE_UNUSED;
330132718Skanstatic bool rs6000_elf_in_small_data_p (tree);
33190075Sobrien#endif
332117395Skan#if TARGET_XCOFF
333132718Skanstatic void rs6000_xcoff_asm_globalize_label (FILE *, const char *);
334132718Skanstatic void rs6000_xcoff_asm_named_section (const char *, unsigned int);
335132718Skanstatic void rs6000_xcoff_select_section (tree, int, unsigned HOST_WIDE_INT);
336132718Skanstatic void rs6000_xcoff_unique_section (tree, int);
337132718Skanstatic void rs6000_xcoff_select_rtx_section (enum machine_mode, rtx,
338132718Skan					     unsigned HOST_WIDE_INT);
339132718Skanstatic const char * rs6000_xcoff_strip_name_encoding (const char *);
340132718Skanstatic unsigned int rs6000_xcoff_section_type_flags (tree, const char *, int);
341132718Skanstatic void rs6000_xcoff_file_start (void);
342132718Skanstatic void rs6000_xcoff_file_end (void);
34390075Sobrien#endif
344132718Skan#if TARGET_MACHO
345132718Skanstatic bool rs6000_binds_local_p (tree);
346132718Skan#endif
347132718Skanstatic int rs6000_use_dfa_pipeline_interface (void);
348132718Skanstatic int rs6000_variable_issue (FILE *, int, rtx, int);
349132718Skanstatic bool rs6000_rtx_costs (rtx, int, int, int *);
350132718Skanstatic int rs6000_adjust_cost (rtx, rtx, rtx, int);
351132718Skanstatic bool is_microcoded_insn (rtx);
352132718Skanstatic int is_dispatch_slot_restricted (rtx);
353132718Skanstatic bool is_cracked_insn (rtx);
354132718Skanstatic bool is_branch_slot_insn (rtx);
355132718Skanstatic int rs6000_adjust_priority (rtx, int);
356132718Skanstatic int rs6000_issue_rate (void);
357132718Skanstatic bool rs6000_is_costly_dependence (rtx, rtx, rtx, int, int);
358132718Skanstatic rtx get_next_active_insn (rtx, rtx);
359132718Skanstatic bool insn_terminates_group_p (rtx , enum group_termination);
360132718Skanstatic bool is_costly_group (rtx *, rtx);
361132718Skanstatic int force_new_group (int, FILE *, rtx *, rtx, bool *, int, int *);
362132718Skanstatic int redefine_groups (FILE *, int, rtx, rtx);
363132718Skanstatic int pad_groups (FILE *, int, rtx, rtx);
364132718Skanstatic void rs6000_sched_finish (FILE *, int);
365132718Skanstatic int rs6000_use_sched_lookahead (void);
36690075Sobrien
367132718Skanstatic void rs6000_init_builtins (void);
368132718Skanstatic rtx rs6000_expand_unop_builtin (enum insn_code, tree, rtx);
369132718Skanstatic rtx rs6000_expand_binop_builtin (enum insn_code, tree, rtx);
370132718Skanstatic rtx rs6000_expand_ternop_builtin (enum insn_code, tree, rtx);
371132718Skanstatic rtx rs6000_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
372132718Skanstatic void altivec_init_builtins (void);
373132718Skanstatic void rs6000_common_init_builtins (void);
374132718Skanstatic void rs6000_init_libfuncs (void);
375117395Skan
376132718Skanstatic void enable_mask_for_builtins (struct builtin_description *, int,
377132718Skan				      enum rs6000_builtins,
378132718Skan				      enum rs6000_builtins);
379132718Skanstatic void spe_init_builtins (void);
380132718Skanstatic rtx spe_expand_builtin (tree, rtx, bool *);
381132718Skanstatic rtx spe_expand_stv_builtin (enum insn_code, tree);
382132718Skanstatic rtx spe_expand_predicate_builtin (enum insn_code, tree, rtx);
383132718Skanstatic rtx spe_expand_evsel_builtin (enum insn_code, tree, rtx);
384132718Skanstatic int rs6000_emit_int_cmove (rtx, rtx, rtx, rtx);
385132718Skanstatic rs6000_stack_t *rs6000_stack_info (void);
386132718Skanstatic void debug_stack_info (rs6000_stack_t *);
387117395Skan
388132718Skanstatic rtx altivec_expand_builtin (tree, rtx, bool *);
389132718Skanstatic rtx altivec_expand_ld_builtin (tree, rtx, bool *);
390132718Skanstatic rtx altivec_expand_st_builtin (tree, rtx, bool *);
391132718Skanstatic rtx altivec_expand_dst_builtin (tree, rtx, bool *);
392132718Skanstatic rtx altivec_expand_abs_builtin (enum insn_code, tree, rtx);
393132718Skanstatic rtx altivec_expand_predicate_builtin (enum insn_code,
394132718Skan					    const char *, tree, rtx);
395132718Skanstatic rtx altivec_expand_lv_builtin (enum insn_code, tree, rtx);
396132718Skanstatic rtx altivec_expand_stv_builtin (enum insn_code, tree);
397132718Skanstatic void rs6000_parse_abi_options (void);
398132718Skanstatic void rs6000_parse_alignment_option (void);
399132718Skanstatic void rs6000_parse_tls_size_option (void);
400132718Skanstatic void rs6000_parse_yes_no_option (const char *, const char *, int *);
401132718Skanstatic int first_altivec_reg_to_save (void);
402132718Skanstatic unsigned int compute_vrsave_mask (void);
403132718Skanstatic void is_altivec_return_reg (rtx, void *);
404132718Skanstatic rtx generate_set_vrsave (rtx, rs6000_stack_t *, int);
405132718Skanint easy_vector_constant (rtx, enum machine_mode);
406132718Skanstatic int easy_vector_same (rtx, enum machine_mode);
407132718Skanstatic int easy_vector_splat_const (int, enum machine_mode);
408132718Skanstatic bool is_ev64_opaque_type (tree);
409132718Skanstatic rtx rs6000_dwarf_register_span (rtx);
410132718Skanstatic rtx rs6000_legitimize_tls_address (rtx, enum tls_model);
411132718Skanstatic rtx rs6000_tls_get_addr (void);
412132718Skanstatic rtx rs6000_got_sym (void);
413132718Skanstatic inline int rs6000_tls_symbol_ref_1 (rtx *, void *);
414132718Skanstatic const char *rs6000_get_some_local_dynamic_name (void);
415132718Skanstatic int rs6000_get_some_local_dynamic_name_1 (rtx *, void *);
416132718Skanstatic rtx rs6000_complex_function_value (enum machine_mode);
417132718Skanstatic rtx rs6000_spe_function_arg (CUMULATIVE_ARGS *,
418132718Skan				    enum machine_mode, tree);
419146895Skanstatic rtx rs6000_mixed_function_arg (enum machine_mode, tree, int);
420132718Skanstatic void rs6000_move_block_from_reg (int regno, rtx x, int nregs);
421132718Skanstatic void setup_incoming_varargs (CUMULATIVE_ARGS *,
422132718Skan				    enum machine_mode, tree,
423132718Skan				    int *, int);
424132718Skan#if TARGET_MACHO
425132718Skanstatic void macho_branch_islands (void);
426132718Skanstatic void add_compiler_branch_island (tree, tree, int);
427132718Skanstatic int no_previous_def (tree function_name);
428132718Skanstatic tree get_prev_label (tree function_name);
429132718Skan#endif
430132718Skan
431132718Skanstatic tree rs6000_build_builtin_va_list (void);
432132718Skan
433132718Skan/* Hash table stuff for keeping track of TOC entries.  */
434132718Skan
435132718Skanstruct toc_hash_struct GTY(())
436132718Skan{
437132718Skan  /* `key' will satisfy CONSTANT_P; in fact, it will satisfy
438132718Skan     ASM_OUTPUT_SPECIAL_POOL_ENTRY_P.  */
439132718Skan  rtx key;
440132718Skan  enum machine_mode key_mode;
441132718Skan  int labelno;
442132718Skan};
443132718Skan
444132718Skanstatic GTY ((param_is (struct toc_hash_struct))) htab_t toc_hash_table;
44590075Sobrien
44690075Sobrien/* Default register names.  */
44790075Sobrienchar rs6000_reg_names[][8] =
44890075Sobrien{
44990075Sobrien      "0",  "1",  "2",  "3",  "4",  "5",  "6",  "7",
45090075Sobrien      "8",  "9", "10", "11", "12", "13", "14", "15",
45190075Sobrien     "16", "17", "18", "19", "20", "21", "22", "23",
45290075Sobrien     "24", "25", "26", "27", "28", "29", "30", "31",
45390075Sobrien      "0",  "1",  "2",  "3",  "4",  "5",  "6",  "7",
45490075Sobrien      "8",  "9", "10", "11", "12", "13", "14", "15",
45590075Sobrien     "16", "17", "18", "19", "20", "21", "22", "23",
45690075Sobrien     "24", "25", "26", "27", "28", "29", "30", "31",
45790075Sobrien     "mq", "lr", "ctr","ap",
45890075Sobrien      "0",  "1",  "2",  "3",  "4",  "5",  "6",  "7",
45990075Sobrien      "xer",
46090075Sobrien      /* AltiVec registers.  */
46190075Sobrien      "0",  "1",  "2",  "3",  "4",  "5",  "6", "7",
46290075Sobrien      "8",  "9",  "10", "11", "12", "13", "14", "15",
46390075Sobrien      "16", "17", "18", "19", "20", "21", "22", "23",
46490075Sobrien      "24", "25", "26", "27", "28", "29", "30", "31",
465117395Skan      "vrsave", "vscr",
466117395Skan      /* SPE registers.  */
467117395Skan      "spe_acc", "spefscr"
46890075Sobrien};
46990075Sobrien
47090075Sobrien#ifdef TARGET_REGNAMES
47190075Sobrienstatic const char alt_reg_names[][8] =
47290075Sobrien{
47390075Sobrien   "%r0",   "%r1",  "%r2",  "%r3",  "%r4",  "%r5",  "%r6",  "%r7",
47490075Sobrien   "%r8",   "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15",
47590075Sobrien  "%r16",  "%r17", "%r18", "%r19", "%r20", "%r21", "%r22", "%r23",
47690075Sobrien  "%r24",  "%r25", "%r26", "%r27", "%r28", "%r29", "%r30", "%r31",
47790075Sobrien   "%f0",   "%f1",  "%f2",  "%f3",  "%f4",  "%f5",  "%f6",  "%f7",
47890075Sobrien   "%f8",   "%f9", "%f10", "%f11", "%f12", "%f13", "%f14", "%f15",
47990075Sobrien  "%f16",  "%f17", "%f18", "%f19", "%f20", "%f21", "%f22", "%f23",
48090075Sobrien  "%f24",  "%f25", "%f26", "%f27", "%f28", "%f29", "%f30", "%f31",
48190075Sobrien    "mq",    "lr",  "ctr",   "ap",
48290075Sobrien  "%cr0",  "%cr1", "%cr2", "%cr3", "%cr4", "%cr5", "%cr6", "%cr7",
48390075Sobrien   "xer",
484117395Skan  /* AltiVec registers.  */
48590075Sobrien   "%v0",  "%v1",  "%v2",  "%v3",  "%v4",  "%v5",  "%v6", "%v7",
486117395Skan   "%v8",  "%v9", "%v10", "%v11", "%v12", "%v13", "%v14", "%v15",
487117395Skan  "%v16", "%v17", "%v18", "%v19", "%v20", "%v21", "%v22", "%v23",
488117395Skan  "%v24", "%v25", "%v26", "%v27", "%v28", "%v29", "%v30", "%v31",
489117395Skan  "vrsave", "vscr",
490117395Skan  /* SPE registers.  */
491117395Skan  "spe_acc", "spefscr"
49290075Sobrien};
49390075Sobrien#endif
49490075Sobrien
49590075Sobrien#ifndef MASK_STRICT_ALIGN
49690075Sobrien#define MASK_STRICT_ALIGN 0
49790075Sobrien#endif
498132718Skan#ifndef TARGET_PROFILE_KERNEL
499132718Skan#define TARGET_PROFILE_KERNEL 0
500132718Skan#endif
501117395Skan
502117395Skan/* The VRSAVE bitmask puts bit %v0 as the most significant bit.  */
503117395Skan#define ALTIVEC_REG_BIT(REGNO) (0x80000000 >> ((REGNO) - FIRST_ALTIVEC_REGNO))
504132718Skan
505132718Skan/* Return 1 for a symbol ref for a thread-local storage symbol.  */
506132718Skan#define RS6000_SYMBOL_REF_TLS_P(RTX) \
507132718Skan  (GET_CODE (RTX) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (RTX) != 0)
50890075Sobrien
50990075Sobrien/* Initialize the GCC target structure.  */
51090075Sobrien#undef TARGET_ATTRIBUTE_TABLE
51190075Sobrien#define TARGET_ATTRIBUTE_TABLE rs6000_attribute_table
512117395Skan#undef TARGET_SET_DEFAULT_TYPE_ATTRIBUTES
513117395Skan#define TARGET_SET_DEFAULT_TYPE_ATTRIBUTES rs6000_set_default_type_attributes
51490075Sobrien
51590075Sobrien#undef TARGET_ASM_ALIGNED_DI_OP
51690075Sobrien#define TARGET_ASM_ALIGNED_DI_OP DOUBLE_INT_ASM_OP
51790075Sobrien
51890075Sobrien/* Default unaligned ops are only provided for ELF.  Find the ops needed
51990075Sobrien   for non-ELF systems.  */
52090075Sobrien#ifndef OBJECT_FORMAT_ELF
521117395Skan#if TARGET_XCOFF
52290075Sobrien/* For XCOFF.  rs6000_assemble_integer will handle unaligned DIs on
52390075Sobrien   64-bit targets.  */
52490075Sobrien#undef TARGET_ASM_UNALIGNED_HI_OP
52590075Sobrien#define TARGET_ASM_UNALIGNED_HI_OP "\t.vbyte\t2,"
52690075Sobrien#undef TARGET_ASM_UNALIGNED_SI_OP
52790075Sobrien#define TARGET_ASM_UNALIGNED_SI_OP "\t.vbyte\t4,"
52890075Sobrien#undef TARGET_ASM_UNALIGNED_DI_OP
52990075Sobrien#define TARGET_ASM_UNALIGNED_DI_OP "\t.vbyte\t8,"
53090075Sobrien#else
53190075Sobrien/* For Darwin.  */
53290075Sobrien#undef TARGET_ASM_UNALIGNED_HI_OP
53390075Sobrien#define TARGET_ASM_UNALIGNED_HI_OP "\t.short\t"
53490075Sobrien#undef TARGET_ASM_UNALIGNED_SI_OP
53590075Sobrien#define TARGET_ASM_UNALIGNED_SI_OP "\t.long\t"
53690075Sobrien#endif
53790075Sobrien#endif
53890075Sobrien
53990075Sobrien/* This hook deals with fixups for relocatable code and DI-mode objects
54090075Sobrien   in 64-bit code.  */
54190075Sobrien#undef TARGET_ASM_INTEGER
54290075Sobrien#define TARGET_ASM_INTEGER rs6000_assemble_integer
54390075Sobrien
544117395Skan#ifdef HAVE_GAS_HIDDEN
545117395Skan#undef TARGET_ASM_ASSEMBLE_VISIBILITY
546117395Skan#define TARGET_ASM_ASSEMBLE_VISIBILITY rs6000_assemble_visibility
547117395Skan#endif
548117395Skan
549132718Skan#undef TARGET_HAVE_TLS
550132718Skan#define TARGET_HAVE_TLS HAVE_AS_TLS
551132718Skan
552132718Skan#undef TARGET_CANNOT_FORCE_CONST_MEM
553132718Skan#define TARGET_CANNOT_FORCE_CONST_MEM rs6000_tls_referenced_p
554132718Skan
55590075Sobrien#undef TARGET_ASM_FUNCTION_PROLOGUE
55690075Sobrien#define TARGET_ASM_FUNCTION_PROLOGUE rs6000_output_function_prologue
55790075Sobrien#undef TARGET_ASM_FUNCTION_EPILOGUE
55890075Sobrien#define TARGET_ASM_FUNCTION_EPILOGUE rs6000_output_function_epilogue
55990075Sobrien
560132718Skan#undef  TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE
561132718Skan#define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE rs6000_use_dfa_pipeline_interface
562132718Skan#undef  TARGET_SCHED_VARIABLE_ISSUE
563132718Skan#define TARGET_SCHED_VARIABLE_ISSUE rs6000_variable_issue
564132718Skan
56590075Sobrien#undef TARGET_SCHED_ISSUE_RATE
56690075Sobrien#define TARGET_SCHED_ISSUE_RATE rs6000_issue_rate
56790075Sobrien#undef TARGET_SCHED_ADJUST_COST
56890075Sobrien#define TARGET_SCHED_ADJUST_COST rs6000_adjust_cost
56990075Sobrien#undef TARGET_SCHED_ADJUST_PRIORITY
57090075Sobrien#define TARGET_SCHED_ADJUST_PRIORITY rs6000_adjust_priority
571132718Skan#undef TARGET_SCHED_IS_COSTLY_DEPENDENCE
572132718Skan#define TARGET_SCHED_IS_COSTLY_DEPENDENCE rs6000_is_costly_dependence
573132718Skan#undef TARGET_SCHED_FINISH
574132718Skan#define TARGET_SCHED_FINISH rs6000_sched_finish
57590075Sobrien
576132718Skan#undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD
577132718Skan#define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD rs6000_use_sched_lookahead
578132718Skan
57990075Sobrien#undef TARGET_INIT_BUILTINS
58090075Sobrien#define TARGET_INIT_BUILTINS rs6000_init_builtins
58190075Sobrien
58290075Sobrien#undef TARGET_EXPAND_BUILTIN
58390075Sobrien#define TARGET_EXPAND_BUILTIN rs6000_expand_builtin
58490075Sobrien
585146895Skan#undef TARGET_MANGLE_FUNDAMENTAL_TYPE
586146895Skan#define TARGET_MANGLE_FUNDAMENTAL_TYPE rs6000_mangle_fundamental_type
587146895Skan
588132718Skan#undef TARGET_INIT_LIBFUNCS
589132718Skan#define TARGET_INIT_LIBFUNCS rs6000_init_libfuncs
590132718Skan
591132718Skan#if TARGET_MACHO
592117395Skan#undef TARGET_BINDS_LOCAL_P
593117395Skan#define TARGET_BINDS_LOCAL_P rs6000_binds_local_p
594132718Skan#endif
59590075Sobrien
596117395Skan#undef TARGET_ASM_OUTPUT_MI_THUNK
597117395Skan#define TARGET_ASM_OUTPUT_MI_THUNK rs6000_output_mi_thunk
598117395Skan
599117395Skan#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
600132718Skan#define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_tree_hwi_hwi_tree_true
601117395Skan
602132718Skan#undef TARGET_FUNCTION_OK_FOR_SIBCALL
603132718Skan#define TARGET_FUNCTION_OK_FOR_SIBCALL rs6000_function_ok_for_sibcall
604132718Skan
605132718Skan#undef TARGET_RTX_COSTS
606132718Skan#define TARGET_RTX_COSTS rs6000_rtx_costs
607132718Skan#undef TARGET_ADDRESS_COST
608132718Skan#define TARGET_ADDRESS_COST hook_int_rtx_0
609132718Skan
610132718Skan#undef TARGET_VECTOR_OPAQUE_P
611132718Skan#define TARGET_VECTOR_OPAQUE_P is_ev64_opaque_type
612132718Skan
613132718Skan#undef TARGET_DWARF_REGISTER_SPAN
614132718Skan#define TARGET_DWARF_REGISTER_SPAN rs6000_dwarf_register_span
615132718Skan
616132718Skan/* On rs6000, function arguments are promoted, as are function return
617132718Skan   values.  */
618132718Skan#undef TARGET_PROMOTE_FUNCTION_ARGS
619132718Skan#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true
620132718Skan#undef TARGET_PROMOTE_FUNCTION_RETURN
621132718Skan#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
622132718Skan
623132718Skan/* Structure return values are passed as an extra parameter.  */
624132718Skan#undef TARGET_STRUCT_VALUE_RTX
625132718Skan#define TARGET_STRUCT_VALUE_RTX hook_rtx_tree_int_null
626132718Skan
627132718Skan#undef TARGET_RETURN_IN_MEMORY
628132718Skan#define TARGET_RETURN_IN_MEMORY rs6000_return_in_memory
629132718Skan
630132718Skan#undef TARGET_SETUP_INCOMING_VARARGS
631132718Skan#define TARGET_SETUP_INCOMING_VARARGS setup_incoming_varargs
632132718Skan
633132718Skan/* Always strict argument naming on rs6000.  */
634132718Skan#undef TARGET_STRICT_ARGUMENT_NAMING
635132718Skan#define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true
636132718Skan#undef TARGET_PRETEND_OUTGOING_VARARGS_NAMED
637132718Skan#define TARGET_PRETEND_OUTGOING_VARARGS_NAMED hook_bool_CUMULATIVE_ARGS_true
638132718Skan#undef TARGET_SPLIT_COMPLEX_ARG
639132718Skan#define TARGET_SPLIT_COMPLEX_ARG hook_bool_tree_true
640132718Skan
641132718Skan#undef TARGET_BUILD_BUILTIN_VA_LIST
642132718Skan#define TARGET_BUILD_BUILTIN_VA_LIST rs6000_build_builtin_va_list
643132718Skan
64490075Sobrienstruct gcc_target targetm = TARGET_INITIALIZER;
64590075Sobrien
64690075Sobrien/* Override command line options.  Mostly we process the processor
64790075Sobrien   type and sometimes adjust other TARGET_ options.  */
64890075Sobrien
64990075Sobrienvoid
650132718Skanrs6000_override_options (const char *default_cpu)
65190075Sobrien{
65290075Sobrien  size_t i, j;
65390075Sobrien  struct rs6000_cpu_select *ptr;
654132718Skan  int set_masks;
65590075Sobrien
656132718Skan  /* Simplifications for entries below.  */
65790075Sobrien
658132718Skan  enum {
659132718Skan    POWERPC_BASE_MASK = MASK_POWERPC | MASK_NEW_MNEMONICS,
660132718Skan    POWERPC_7400_MASK = POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_ALTIVEC
661132718Skan  };
66290075Sobrien
663132718Skan  /* This table occasionally claims that a processor does not support
664132718Skan     a particular feature even though it does, but the feature is slower
665132718Skan     than the alternative.  Thus, it shouldn't be relied on as a
666132718Skan     complete description of the processor's support.
667132718Skan
668132718Skan     Please keep this list in order, and don't forget to update the
669132718Skan     documentation in invoke.texi when adding a new processor or
670132718Skan     flag.  */
67190075Sobrien  static struct ptt
67290075Sobrien    {
67390075Sobrien      const char *const name;		/* Canonical processor name.  */
67490075Sobrien      const enum processor_type processor; /* Processor type enum value.  */
67590075Sobrien      const int target_enable;	/* Target flags to enable.  */
67690075Sobrien    } const processor_target_table[]
677132718Skan      = {{"401", PROCESSOR_PPC403, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
678132718Skan	 {"403", PROCESSOR_PPC403,
679132718Skan	  POWERPC_BASE_MASK | MASK_SOFT_FLOAT | MASK_STRICT_ALIGN},
680132718Skan	 {"405", PROCESSOR_PPC405, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
681132718Skan	 {"405fp", PROCESSOR_PPC405, POWERPC_BASE_MASK},
682132718Skan	 {"440", PROCESSOR_PPC440, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
683132718Skan	 {"440fp", PROCESSOR_PPC440, POWERPC_BASE_MASK},
684132718Skan	 {"505", PROCESSOR_MPCCORE, POWERPC_BASE_MASK},
685132718Skan	 {"601", PROCESSOR_PPC601,
686132718Skan	  MASK_POWER | POWERPC_BASE_MASK | MASK_MULTIPLE | MASK_STRING},
687132718Skan	 {"602", PROCESSOR_PPC603, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
688132718Skan	 {"603", PROCESSOR_PPC603, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
689132718Skan	 {"603e", PROCESSOR_PPC603, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
690132718Skan	 {"604", PROCESSOR_PPC604, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
691132718Skan	 {"604e", PROCESSOR_PPC604e, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
692132718Skan	 {"620", PROCESSOR_PPC620,
693132718Skan	  POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64},
694132718Skan	 {"630", PROCESSOR_PPC630,
695132718Skan	  POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64},
696132718Skan	 {"740", PROCESSOR_PPC750, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
697132718Skan	 {"7400", PROCESSOR_PPC7400, POWERPC_7400_MASK},
698132718Skan	 {"7450", PROCESSOR_PPC7450, POWERPC_7400_MASK},
699132718Skan	 {"750", PROCESSOR_PPC750, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
700132718Skan	 {"801", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
701132718Skan	 {"821", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
702132718Skan	 {"823", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
703132718Skan	 {"8540", PROCESSOR_PPC8540, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
704132718Skan	 {"860", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
705132718Skan	 {"970", PROCESSOR_POWER4,
706132718Skan	  POWERPC_7400_MASK | MASK_PPC_GPOPT | MASK_MFCRF | MASK_POWERPC64},
707132718Skan	 {"common", PROCESSOR_COMMON, MASK_NEW_MNEMONICS},
708132718Skan	 {"ec603e", PROCESSOR_PPC603, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
709132718Skan	 {"G3", PROCESSOR_PPC750, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
710132718Skan	 {"G4",  PROCESSOR_PPC7450, POWERPC_7400_MASK},
711132718Skan	 {"G5", PROCESSOR_POWER4,
712132718Skan	  POWERPC_7400_MASK | MASK_PPC_GPOPT | MASK_MFCRF | MASK_POWERPC64},
713132718Skan	 {"power", PROCESSOR_POWER, MASK_POWER | MASK_MULTIPLE | MASK_STRING},
71490075Sobrien	 {"power2", PROCESSOR_POWER,
715132718Skan	  MASK_POWER | MASK_POWER2 | MASK_MULTIPLE | MASK_STRING},
71690075Sobrien	 {"power3", PROCESSOR_PPC630,
717132718Skan	  POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64},
718117395Skan	 {"power4", PROCESSOR_POWER4,
719132718Skan	  POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_MFCRF | MASK_POWERPC64},
720132718Skan	 {"power5", PROCESSOR_POWER5,
721132718Skan	  POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_MFCRF | MASK_POWERPC64},
722132718Skan	 {"powerpc", PROCESSOR_POWERPC, POWERPC_BASE_MASK},
72390075Sobrien	 {"powerpc64", PROCESSOR_POWERPC64,
724132718Skan	  POWERPC_BASE_MASK | MASK_POWERPC64},
725132718Skan	 {"rios", PROCESSOR_RIOS1, MASK_POWER | MASK_MULTIPLE | MASK_STRING},
726132718Skan	 {"rios1", PROCESSOR_RIOS1, MASK_POWER | MASK_MULTIPLE | MASK_STRING},
72790075Sobrien	 {"rios2", PROCESSOR_RIOS2,
728132718Skan	  MASK_POWER | MASK_POWER2 | MASK_MULTIPLE | MASK_STRING},
729132718Skan	 {"rsc", PROCESSOR_PPC601, MASK_POWER | MASK_MULTIPLE | MASK_STRING},
730132718Skan	 {"rsc1", PROCESSOR_PPC601, MASK_POWER | MASK_MULTIPLE | MASK_STRING},
731132718Skan	 {"rs64a", PROCESSOR_RS64A, POWERPC_BASE_MASK | MASK_POWERPC64},
732132718Skan      };
73390075Sobrien
734117395Skan  const size_t ptt_size = ARRAY_SIZE (processor_target_table);
73590075Sobrien
736132718Skan  /* Some OSs don't support saving the high part of 64-bit registers on
737132718Skan     context switch.  Other OSs don't support saving Altivec registers.
738132718Skan     On those OSs, we don't touch the MASK_POWERPC64 or MASK_ALTIVEC
739132718Skan     settings; if the user wants either, the user must explicitly specify
740132718Skan     them and we won't interfere with the user's specification.  */
74190075Sobrien
742132718Skan  enum {
743132718Skan    POWER_MASKS = MASK_POWER | MASK_POWER2 | MASK_MULTIPLE | MASK_STRING,
744132718Skan    POWERPC_MASKS = (POWERPC_BASE_MASK | MASK_PPC_GPOPT
745132718Skan		     | MASK_PPC_GFXOPT | MASK_POWERPC64 | MASK_ALTIVEC
746132718Skan		     | MASK_MFCRF)
747132718Skan  };
748132718Skan set_masks = POWER_MASKS | POWERPC_MASKS | MASK_SOFT_FLOAT;
749132718Skan#ifdef OS_MISSING_POWERPC64
750132718Skan  if (OS_MISSING_POWERPC64)
751132718Skan    set_masks &= ~MASK_POWERPC64;
752132718Skan#endif
753132718Skan#ifdef OS_MISSING_ALTIVEC
754132718Skan  if (OS_MISSING_ALTIVEC)
755132718Skan    set_masks &= ~MASK_ALTIVEC;
756132718Skan#endif
757132718Skan
758146895Skan  /* Don't override by the processor default if given explicitly.  */
759146895Skan  set_masks &= ~target_flags_explicit;
760132718Skan
76190075Sobrien  /* Identify the processor type.  */
76290075Sobrien  rs6000_select[0].string = default_cpu;
76390075Sobrien  rs6000_cpu = TARGET_POWERPC64 ? PROCESSOR_DEFAULT64 : PROCESSOR_DEFAULT;
76490075Sobrien
76590075Sobrien  for (i = 0; i < ARRAY_SIZE (rs6000_select); i++)
76690075Sobrien    {
76790075Sobrien      ptr = &rs6000_select[i];
76890075Sobrien      if (ptr->string != (char *)0 && ptr->string[0] != '\0')
76990075Sobrien	{
77090075Sobrien	  for (j = 0; j < ptt_size; j++)
77190075Sobrien	    if (! strcmp (ptr->string, processor_target_table[j].name))
77290075Sobrien	      {
77390075Sobrien		if (ptr->set_tune_p)
77490075Sobrien		  rs6000_cpu = processor_target_table[j].processor;
77590075Sobrien
77690075Sobrien		if (ptr->set_arch_p)
77790075Sobrien		  {
778132718Skan		    target_flags &= ~set_masks;
779132718Skan		    target_flags |= (processor_target_table[j].target_enable
780132718Skan				     & set_masks);
78190075Sobrien		  }
78290075Sobrien		break;
78390075Sobrien	      }
78490075Sobrien
78590075Sobrien	  if (j == ptt_size)
78690075Sobrien	    error ("bad value (%s) for %s switch", ptr->string, ptr->name);
78790075Sobrien	}
78890075Sobrien    }
78990075Sobrien
790132718Skan  if (TARGET_E500)
791117395Skan    rs6000_isel = 1;
792117395Skan
793117395Skan  /* If we are optimizing big endian systems for space, use the load/store
794117395Skan     multiple and string instructions.  */
79590075Sobrien  if (BYTES_BIG_ENDIAN && optimize_size)
796132718Skan    target_flags |= ~target_flags_explicit & (MASK_MULTIPLE | MASK_STRING);
79790075Sobrien
79890075Sobrien  /* Don't allow -mmultiple or -mstring on little endian systems
79990075Sobrien     unless the cpu is a 750, because the hardware doesn't support the
80090075Sobrien     instructions used in little endian mode, and causes an alignment
80190075Sobrien     trap.  The 750 does not cause an alignment trap (except when the
80290075Sobrien     target is unaligned).  */
80390075Sobrien
804132718Skan  if (!BYTES_BIG_ENDIAN && rs6000_cpu != PROCESSOR_PPC750)
80590075Sobrien    {
80690075Sobrien      if (TARGET_MULTIPLE)
80790075Sobrien	{
80890075Sobrien	  target_flags &= ~MASK_MULTIPLE;
809132718Skan	  if ((target_flags_explicit & MASK_MULTIPLE) != 0)
81090075Sobrien	    warning ("-mmultiple is not supported on little endian systems");
81190075Sobrien	}
81290075Sobrien
81390075Sobrien      if (TARGET_STRING)
81490075Sobrien	{
81590075Sobrien	  target_flags &= ~MASK_STRING;
816132718Skan	  if ((target_flags_explicit & MASK_STRING) != 0)
81790075Sobrien	    warning ("-mstring is not supported on little endian systems");
81890075Sobrien	}
81990075Sobrien    }
82090075Sobrien
82190075Sobrien  /* Set debug flags */
82290075Sobrien  if (rs6000_debug_name)
82390075Sobrien    {
82490075Sobrien      if (! strcmp (rs6000_debug_name, "all"))
82590075Sobrien	rs6000_debug_stack = rs6000_debug_arg = 1;
82690075Sobrien      else if (! strcmp (rs6000_debug_name, "stack"))
82790075Sobrien	rs6000_debug_stack = 1;
82890075Sobrien      else if (! strcmp (rs6000_debug_name, "arg"))
82990075Sobrien	rs6000_debug_arg = 1;
83090075Sobrien      else
83190075Sobrien	error ("unknown -mdebug-%s switch", rs6000_debug_name);
83290075Sobrien    }
83390075Sobrien
834117395Skan  if (rs6000_traceback_name)
835117395Skan    {
836117395Skan      if (! strncmp (rs6000_traceback_name, "full", 4))
837117395Skan	rs6000_traceback = traceback_full;
838117395Skan      else if (! strncmp (rs6000_traceback_name, "part", 4))
839117395Skan	rs6000_traceback = traceback_part;
840117395Skan      else if (! strncmp (rs6000_traceback_name, "no", 2))
841117395Skan	rs6000_traceback = traceback_none;
842117395Skan      else
843117395Skan	error ("unknown -mtraceback arg `%s'; expecting `full', `partial' or `none'",
844117395Skan	       rs6000_traceback_name);
845117395Skan    }
846117395Skan
84790075Sobrien  /* Set size of long double */
84890075Sobrien  rs6000_long_double_type_size = 64;
84990075Sobrien  if (rs6000_long_double_size_string)
85090075Sobrien    {
85190075Sobrien      char *tail;
85290075Sobrien      int size = strtol (rs6000_long_double_size_string, &tail, 10);
85390075Sobrien      if (*tail != '\0' || (size != 64 && size != 128))
85490075Sobrien	error ("Unknown switch -mlong-double-%s",
85590075Sobrien	       rs6000_long_double_size_string);
85690075Sobrien      else
85790075Sobrien	rs6000_long_double_type_size = size;
85890075Sobrien    }
85990075Sobrien
860132718Skan  /* Set Altivec ABI as default for powerpc64 linux.  */
861132718Skan  if (TARGET_ELF && TARGET_64BIT)
862132718Skan    {
863132718Skan      rs6000_altivec_abi = 1;
864132718Skan      rs6000_altivec_vrsave = 1;
865132718Skan    }
866132718Skan
86790075Sobrien  /* Handle -mabi= options.  */
86890075Sobrien  rs6000_parse_abi_options ();
86990075Sobrien
870132718Skan  /* Handle -malign-XXXXX option.  */
871132718Skan  rs6000_parse_alignment_option ();
87290075Sobrien
873132718Skan  /* Handle generic -mFOO=YES/NO options.  */
874132718Skan  rs6000_parse_yes_no_option ("vrsave", rs6000_altivec_vrsave_string,
875132718Skan			      &rs6000_altivec_vrsave);
876132718Skan  rs6000_parse_yes_no_option ("isel", rs6000_isel_string,
877132718Skan			      &rs6000_isel);
878132718Skan  rs6000_parse_yes_no_option ("spe", rs6000_spe_string, &rs6000_spe);
879132718Skan  rs6000_parse_yes_no_option ("float-gprs", rs6000_float_gprs_string,
880132718Skan			      &rs6000_float_gprs);
881117395Skan
882132718Skan  /* Handle -mtls-size option.  */
883132718Skan  rs6000_parse_tls_size_option ();
884132718Skan
88590075Sobrien#ifdef SUBTARGET_OVERRIDE_OPTIONS
88690075Sobrien  SUBTARGET_OVERRIDE_OPTIONS;
88790075Sobrien#endif
88890075Sobrien#ifdef SUBSUBTARGET_OVERRIDE_OPTIONS
88990075Sobrien  SUBSUBTARGET_OVERRIDE_OPTIONS;
89090075Sobrien#endif
89190075Sobrien
892132718Skan  if (TARGET_E500)
893132718Skan    {
894132718Skan      if (TARGET_ALTIVEC)
895132718Skan      error ("AltiVec and E500 instructions cannot coexist");
896132718Skan
897132718Skan      /* The e500 does not have string instructions, and we set
898132718Skan	 MASK_STRING above when optimizing for size.  */
899132718Skan      if ((target_flags & MASK_STRING) != 0)
900132718Skan	target_flags = target_flags & ~MASK_STRING;
901132718Skan
902132718Skan      /* No SPE means 64-bit long doubles, even if an E500.  */
903132718Skan      if (rs6000_spe_string != 0
904132718Skan          && !strcmp (rs6000_spe_string, "no"))
905132718Skan	rs6000_long_double_type_size = 64;
906132718Skan    }
907132718Skan  else if (rs6000_select[1].string != NULL)
908132718Skan    {
909132718Skan      /* For the powerpc-eabispe configuration, we set all these by
910132718Skan	 default, so let's unset them if we manually set another
911132718Skan	 CPU that is not the E500.  */
912132718Skan      if (rs6000_abi_string == 0)
913132718Skan	rs6000_spe_abi = 0;
914132718Skan      if (rs6000_spe_string == 0)
915132718Skan	rs6000_spe = 0;
916132718Skan      if (rs6000_float_gprs_string == 0)
917132718Skan	rs6000_float_gprs = 0;
918132718Skan      if (rs6000_isel_string == 0)
919132718Skan	rs6000_isel = 0;
920132718Skan      if (rs6000_long_double_size_string == 0)
921132718Skan	rs6000_long_double_type_size = 64;
922132718Skan    }
923132718Skan
924132718Skan  rs6000_always_hint = (rs6000_cpu != PROCESSOR_POWER4
925132718Skan			&& rs6000_cpu != PROCESSOR_POWER5);
926132718Skan  rs6000_sched_groups = (rs6000_cpu == PROCESSOR_POWER4
927132718Skan			 || rs6000_cpu == PROCESSOR_POWER5);
928132718Skan
929117395Skan  /* Handle -m(no-)longcall option.  This is a bit of a cheap hack,
930117395Skan     using TARGET_OPTIONS to handle a toggle switch, but we're out of
931117395Skan     bits in target_flags so TARGET_SWITCHES cannot be used.
932117395Skan     Assumption here is that rs6000_longcall_switch points into the
933117395Skan     text of the complete option, rather than being a copy, so we can
934117395Skan     scan back for the presence or absence of the no- modifier.  */
935117395Skan  if (rs6000_longcall_switch)
936117395Skan    {
937117395Skan      const char *base = rs6000_longcall_switch;
938117395Skan      while (base[-1] != 'm') base--;
939117395Skan
940117395Skan      if (*rs6000_longcall_switch != '\0')
941117395Skan	error ("invalid option `%s'", base);
942117395Skan      rs6000_default_long_calls = (base[0] != 'n');
943117395Skan    }
944117395Skan
945146895Skan  /* Handle -m(no-)warn-altivec-long similarly.  */
946146895Skan  if (rs6000_warn_altivec_long_switch)
947146895Skan    {
948146895Skan      const char *base = rs6000_warn_altivec_long_switch;
949146895Skan      while (base[-1] != 'm') base--;
950146895Skan
951146895Skan      if (*rs6000_warn_altivec_long_switch != '\0')
952146895Skan       error ("invalid option `%s'", base);
953146895Skan      rs6000_warn_altivec_long = (base[0] != 'n');
954146895Skan    }
955146895Skan
956132718Skan  /* Handle -mprioritize-restricted-insns option.  */
957132718Skan  rs6000_sched_restricted_insns_priority
958132718Skan    = (rs6000_sched_groups ? 1 : 0);
959132718Skan  if (rs6000_sched_restricted_insns_priority_str)
960132718Skan    rs6000_sched_restricted_insns_priority =
961132718Skan      atoi (rs6000_sched_restricted_insns_priority_str);
962132718Skan
963132718Skan  /* Handle -msched-costly-dep option.  */
964132718Skan  rs6000_sched_costly_dep
965132718Skan    = (rs6000_sched_groups ? store_to_load_dep_costly : no_dep_costly);
966132718Skan  if (rs6000_sched_costly_dep_str)
967132718Skan    {
968132718Skan      if (! strcmp (rs6000_sched_costly_dep_str, "no"))
969132718Skan        rs6000_sched_costly_dep = no_dep_costly;
970132718Skan      else if (! strcmp (rs6000_sched_costly_dep_str, "all"))
971132718Skan        rs6000_sched_costly_dep = all_deps_costly;
972132718Skan      else if (! strcmp (rs6000_sched_costly_dep_str, "true_store_to_load"))
973132718Skan        rs6000_sched_costly_dep = true_store_to_load_dep_costly;
974132718Skan      else if (! strcmp (rs6000_sched_costly_dep_str, "store_to_load"))
975132718Skan        rs6000_sched_costly_dep = store_to_load_dep_costly;
976132718Skan      else
977132718Skan        rs6000_sched_costly_dep = atoi (rs6000_sched_costly_dep_str);
978132718Skan    }
979132718Skan
980132718Skan  /* Handle -minsert-sched-nops option.  */
981132718Skan  rs6000_sched_insert_nops
982132718Skan    = (rs6000_sched_groups ? sched_finish_regroup_exact : sched_finish_none);
983132718Skan  if (rs6000_sched_insert_nops_str)
984132718Skan    {
985132718Skan      if (! strcmp (rs6000_sched_insert_nops_str, "no"))
986132718Skan        rs6000_sched_insert_nops = sched_finish_none;
987132718Skan      else if (! strcmp (rs6000_sched_insert_nops_str, "pad"))
988132718Skan        rs6000_sched_insert_nops = sched_finish_pad_groups;
989132718Skan      else if (! strcmp (rs6000_sched_insert_nops_str, "regroup_exact"))
990132718Skan        rs6000_sched_insert_nops = sched_finish_regroup_exact;
991132718Skan      else
992132718Skan        rs6000_sched_insert_nops = atoi (rs6000_sched_insert_nops_str);
993132718Skan    }
994132718Skan
995117395Skan#ifdef TARGET_REGNAMES
996117395Skan  /* If the user desires alternate register names, copy in the
997117395Skan     alternate names now.  */
998117395Skan  if (TARGET_REGNAMES)
999117395Skan    memcpy (rs6000_reg_names, alt_reg_names, sizeof (rs6000_reg_names));
1000117395Skan#endif
1001117395Skan
100290075Sobrien  /* Set TARGET_AIX_STRUCT_RET last, after the ABI is determined.
100390075Sobrien     If -maix-struct-return or -msvr4-struct-return was explicitly
100490075Sobrien     used, don't override with the ABI default.  */
1005132718Skan  if ((target_flags_explicit & MASK_AIX_STRUCT_RET) == 0)
100690075Sobrien    {
100790075Sobrien      if (DEFAULT_ABI == ABI_V4 && !DRAFT_V4_STRUCT_RET)
100890075Sobrien	target_flags = (target_flags & ~MASK_AIX_STRUCT_RET);
100990075Sobrien      else
101090075Sobrien	target_flags |= MASK_AIX_STRUCT_RET;
101190075Sobrien    }
101290075Sobrien
1013117395Skan  if (TARGET_LONG_DOUBLE_128
1014117395Skan      && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_DARWIN))
1015132718Skan    REAL_MODE_FORMAT (TFmode) = &ibm_extended_format;
1016117395Skan
101790075Sobrien  /* Allocate an alias set for register saves & restores from stack.  */
101890075Sobrien  rs6000_sr_alias_set = new_alias_set ();
101990075Sobrien
102090075Sobrien  if (TARGET_TOC)
102190075Sobrien    ASM_GENERATE_INTERNAL_LABEL (toc_label_name, "LCTOC", 1);
102290075Sobrien
102390075Sobrien  /* We can only guarantee the availability of DI pseudo-ops when
102490075Sobrien     assembling for 64-bit targets.  */
102590075Sobrien  if (!TARGET_64BIT)
102690075Sobrien    {
102790075Sobrien      targetm.asm_out.aligned_op.di = NULL;
102890075Sobrien      targetm.asm_out.unaligned_op.di = NULL;
102990075Sobrien    }
103090075Sobrien
1031132718Skan  /* Set maximum branch target alignment at two instructions, eight bytes.  */
1032132718Skan  align_jumps_max_skip = 8;
1033132718Skan  align_loops_max_skip = 8;
1034132718Skan
103590075Sobrien  /* Arrange to save and restore machine status around nested functions.  */
103690075Sobrien  init_machine_status = rs6000_init_machine_status;
1037132718Skan
1038132718Skan  /* We should always be splitting complex arguments, but we can't break
1039132718Skan     Linux and Darwin ABIs at the moment.  For now, only AIX is fixed.  */
1040132718Skan  if (DEFAULT_ABI != ABI_AIX)
1041132718Skan    targetm.calls.split_complex_arg = NULL;
104290075Sobrien}
104390075Sobrien
1044132718Skan/* Handle generic options of the form -mfoo=yes/no.
1045132718Skan   NAME is the option name.
1046132718Skan   VALUE is the option value.
1047132718Skan   FLAG is the pointer to the flag where to store a 1 or 0, depending on
1048132718Skan   whether the option value is 'yes' or 'no' respectively.  */
1049117395Skanstatic void
1050132718Skanrs6000_parse_yes_no_option (const char *name, const char *value, int *flag)
1051117395Skan{
1052132718Skan  if (value == 0)
1053117395Skan    return;
1054132718Skan  else if (!strcmp (value, "yes"))
1055132718Skan    *flag = 1;
1056132718Skan  else if (!strcmp (value, "no"))
1057132718Skan    *flag = 0;
1058117395Skan  else
1059132718Skan    error ("unknown -m%s= option specified: '%s'", name, value);
1060117395Skan}
1061117395Skan
106290075Sobrien/* Handle -mabi= options.  */
106390075Sobrienstatic void
1064132718Skanrs6000_parse_abi_options (void)
106590075Sobrien{
106690075Sobrien  if (rs6000_abi_string == 0)
106790075Sobrien    return;
106890075Sobrien  else if (! strcmp (rs6000_abi_string, "altivec"))
1069132718Skan    {
1070132718Skan      rs6000_altivec_abi = 1;
1071132718Skan      rs6000_spe_abi = 0;
1072132718Skan    }
107396263Sobrien  else if (! strcmp (rs6000_abi_string, "no-altivec"))
107496263Sobrien    rs6000_altivec_abi = 0;
1075117395Skan  else if (! strcmp (rs6000_abi_string, "spe"))
1076132718Skan    {
1077132718Skan      rs6000_spe_abi = 1;
1078132718Skan      rs6000_altivec_abi = 0;
1079132718Skan      if (!TARGET_SPE_ABI)
1080132718Skan	error ("not configured for ABI: '%s'", rs6000_abi_string);
1081132718Skan    }
1082132718Skan
1083117395Skan  else if (! strcmp (rs6000_abi_string, "no-spe"))
1084117395Skan    rs6000_spe_abi = 0;
108590075Sobrien  else
108690075Sobrien    error ("unknown ABI specified: '%s'", rs6000_abi_string);
108790075Sobrien}
108890075Sobrien
1089132718Skan/* Handle -malign-XXXXXX options.  */
1090132718Skanstatic void
1091132718Skanrs6000_parse_alignment_option (void)
1092132718Skan{
1093132718Skan  if (rs6000_alignment_string == 0)
1094132718Skan    return;
1095132718Skan  else if (! strcmp (rs6000_alignment_string, "power"))
1096132718Skan    rs6000_alignment_flags = MASK_ALIGN_POWER;
1097132718Skan  else if (! strcmp (rs6000_alignment_string, "natural"))
1098132718Skan    rs6000_alignment_flags = MASK_ALIGN_NATURAL;
1099132718Skan  else
1100132718Skan    error ("unknown -malign-XXXXX option specified: '%s'",
1101132718Skan	   rs6000_alignment_string);
1102132718Skan}
1103132718Skan
1104132718Skan/* Validate and record the size specified with the -mtls-size option.  */
1105132718Skan
1106132718Skanstatic void
1107132718Skanrs6000_parse_tls_size_option (void)
1108132718Skan{
1109132718Skan  if (rs6000_tls_size_string == 0)
1110132718Skan    return;
1111132718Skan  else if (strcmp (rs6000_tls_size_string, "16") == 0)
1112132718Skan    rs6000_tls_size = 16;
1113132718Skan  else if (strcmp (rs6000_tls_size_string, "32") == 0)
1114132718Skan    rs6000_tls_size = 32;
1115132718Skan  else if (strcmp (rs6000_tls_size_string, "64") == 0)
1116132718Skan    rs6000_tls_size = 64;
1117132718Skan  else
1118132718Skan    error ("bad value `%s' for -mtls-size switch", rs6000_tls_size_string);
1119132718Skan}
1120132718Skan
112190075Sobrienvoid
1122132718Skanoptimization_options (int level ATTRIBUTE_UNUSED, int size ATTRIBUTE_UNUSED)
112390075Sobrien{
112490075Sobrien}
112590075Sobrien
112690075Sobrien/* Do anything needed at the start of the asm file.  */
112790075Sobrien
1128132718Skanstatic void
1129132718Skanrs6000_file_start (void)
113090075Sobrien{
113190075Sobrien  size_t i;
113290075Sobrien  char buffer[80];
113390075Sobrien  const char *start = buffer;
113490075Sobrien  struct rs6000_cpu_select *ptr;
1135132718Skan  const char *default_cpu = TARGET_CPU_DEFAULT;
1136132718Skan  FILE *file = asm_out_file;
113790075Sobrien
1138132718Skan  default_file_start ();
1139132718Skan
1140132718Skan#ifdef TARGET_BI_ARCH
1141132718Skan  if ((TARGET_DEFAULT ^ target_flags) & MASK_64BIT)
1142132718Skan    default_cpu = 0;
1143132718Skan#endif
1144132718Skan
114590075Sobrien  if (flag_verbose_asm)
114690075Sobrien    {
114790075Sobrien      sprintf (buffer, "\n%s rs6000/powerpc options:", ASM_COMMENT_START);
114890075Sobrien      rs6000_select[0].string = default_cpu;
114990075Sobrien
115090075Sobrien      for (i = 0; i < ARRAY_SIZE (rs6000_select); i++)
115190075Sobrien	{
115290075Sobrien	  ptr = &rs6000_select[i];
115390075Sobrien	  if (ptr->string != (char *)0 && ptr->string[0] != '\0')
115490075Sobrien	    {
115590075Sobrien	      fprintf (file, "%s %s%s", start, ptr->name, ptr->string);
115690075Sobrien	      start = "";
115790075Sobrien	    }
115890075Sobrien	}
115990075Sobrien
116090075Sobrien#ifdef USING_ELFOS_H
116190075Sobrien      switch (rs6000_sdata)
116290075Sobrien	{
116390075Sobrien	case SDATA_NONE: fprintf (file, "%s -msdata=none", start); start = ""; break;
116490075Sobrien	case SDATA_DATA: fprintf (file, "%s -msdata=data", start); start = ""; break;
116590075Sobrien	case SDATA_SYSV: fprintf (file, "%s -msdata=sysv", start); start = ""; break;
116690075Sobrien	case SDATA_EABI: fprintf (file, "%s -msdata=eabi", start); start = ""; break;
116790075Sobrien	}
116890075Sobrien
116990075Sobrien      if (rs6000_sdata && g_switch_value)
117090075Sobrien	{
1171132718Skan	  fprintf (file, "%s -G " HOST_WIDE_INT_PRINT_UNSIGNED, start,
1172132718Skan		   g_switch_value);
117390075Sobrien	  start = "";
117490075Sobrien	}
117590075Sobrien#endif
117690075Sobrien
117790075Sobrien      if (*start == '\0')
117890075Sobrien	putc ('\n', file);
117990075Sobrien    }
118090075Sobrien}
118190075Sobrien
1182117395Skan/* Return nonzero if this function is known to have a null epilogue.  */
118390075Sobrien
118490075Sobrienint
1185132718Skandirect_return (void)
118690075Sobrien{
118790075Sobrien  if (reload_completed)
118890075Sobrien    {
118990075Sobrien      rs6000_stack_t *info = rs6000_stack_info ();
119090075Sobrien
119190075Sobrien      if (info->first_gp_reg_save == 32
119290075Sobrien	  && info->first_fp_reg_save == 64
119390075Sobrien	  && info->first_altivec_reg_save == LAST_ALTIVEC_REGNO + 1
119490075Sobrien	  && ! info->lr_save_p
119590075Sobrien	  && ! info->cr_save_p
119690075Sobrien	  && info->vrsave_mask == 0
119790075Sobrien	  && ! info->push_p)
119890075Sobrien	return 1;
119990075Sobrien    }
120090075Sobrien
120190075Sobrien  return 0;
120290075Sobrien}
120390075Sobrien
120490075Sobrien/* Returns 1 always.  */
120590075Sobrien
120690075Sobrienint
1207132718Skanany_operand (rtx op ATTRIBUTE_UNUSED,
1208132718Skan	     enum machine_mode mode ATTRIBUTE_UNUSED)
120990075Sobrien{
121090075Sobrien  return 1;
121190075Sobrien}
121290075Sobrien
121390075Sobrien/* Returns 1 if op is the count register.  */
121490075Sobrienint
1215132718Skancount_register_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
121690075Sobrien{
121790075Sobrien  if (GET_CODE (op) != REG)
121890075Sobrien    return 0;
121990075Sobrien
122090075Sobrien  if (REGNO (op) == COUNT_REGISTER_REGNUM)
122190075Sobrien    return 1;
122290075Sobrien
122390075Sobrien  if (REGNO (op) > FIRST_PSEUDO_REGISTER)
122490075Sobrien    return 1;
122590075Sobrien
122690075Sobrien  return 0;
122790075Sobrien}
122890075Sobrien
122996263Sobrien/* Returns 1 if op is an altivec register.  */
123090075Sobrienint
1231132718Skanaltivec_register_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
123296263Sobrien{
123396263Sobrien
123496263Sobrien  return (register_operand (op, mode)
123596263Sobrien	  && (GET_CODE (op) != REG
123696263Sobrien	      || REGNO (op) > FIRST_PSEUDO_REGISTER
123796263Sobrien	      || ALTIVEC_REGNO_P (REGNO (op))));
123896263Sobrien}
123996263Sobrien
124096263Sobrienint
1241132718Skanxer_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
124290075Sobrien{
124390075Sobrien  if (GET_CODE (op) != REG)
124490075Sobrien    return 0;
124590075Sobrien
124690075Sobrien  if (XER_REGNO_P (REGNO (op)))
124790075Sobrien    return 1;
124890075Sobrien
124990075Sobrien  return 0;
125090075Sobrien}
125190075Sobrien
125290075Sobrien/* Return 1 if OP is a signed 8-bit constant.  Int multiplication
125390075Sobrien   by such constants completes more quickly.  */
125490075Sobrien
125590075Sobrienint
1256132718Skans8bit_cint_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
125790075Sobrien{
125890075Sobrien  return ( GET_CODE (op) == CONST_INT
125990075Sobrien	  && (INTVAL (op) >= -128 && INTVAL (op) <= 127));
126090075Sobrien}
126190075Sobrien
126290075Sobrien/* Return 1 if OP is a constant that can fit in a D field.  */
126390075Sobrien
126490075Sobrienint
1265132718Skanshort_cint_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
126690075Sobrien{
126790075Sobrien  return (GET_CODE (op) == CONST_INT
126890075Sobrien	  && CONST_OK_FOR_LETTER_P (INTVAL (op), 'I'));
126990075Sobrien}
127090075Sobrien
127190075Sobrien/* Similar for an unsigned D field.  */
127290075Sobrien
127390075Sobrienint
1274132718Skanu_short_cint_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
127590075Sobrien{
127690075Sobrien  return (GET_CODE (op) == CONST_INT
127796263Sobrien	  && CONST_OK_FOR_LETTER_P (INTVAL (op) & GET_MODE_MASK (mode), 'K'));
127890075Sobrien}
127990075Sobrien
128090075Sobrien/* Return 1 if OP is a CONST_INT that cannot fit in a signed D field.  */
128190075Sobrien
128290075Sobrienint
1283132718Skannon_short_cint_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
128490075Sobrien{
128590075Sobrien  return (GET_CODE (op) == CONST_INT
128690075Sobrien	  && (unsigned HOST_WIDE_INT) (INTVAL (op) + 0x8000) >= 0x10000);
128790075Sobrien}
128890075Sobrien
128990075Sobrien/* Returns 1 if OP is a CONST_INT that is a positive value
129090075Sobrien   and an exact power of 2.  */
129190075Sobrien
129290075Sobrienint
1293132718Skanexact_log2_cint_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
129490075Sobrien{
129590075Sobrien  return (GET_CODE (op) == CONST_INT
129690075Sobrien	  && INTVAL (op) > 0
129790075Sobrien	  && exact_log2 (INTVAL (op)) >= 0);
129890075Sobrien}
129990075Sobrien
130090075Sobrien/* Returns 1 if OP is a register that is not special (i.e., not MQ,
130190075Sobrien   ctr, or lr).  */
130290075Sobrien
130390075Sobrienint
1304132718Skangpc_reg_operand (rtx op, enum machine_mode mode)
130590075Sobrien{
130690075Sobrien  return (register_operand (op, mode)
130790075Sobrien	  && (GET_CODE (op) != REG
130890075Sobrien	      || (REGNO (op) >= ARG_POINTER_REGNUM
130990075Sobrien		  && !XER_REGNO_P (REGNO (op)))
131090075Sobrien	      || REGNO (op) < MQ_REGNO));
131190075Sobrien}
131290075Sobrien
131390075Sobrien/* Returns 1 if OP is either a pseudo-register or a register denoting a
131490075Sobrien   CR field.  */
131590075Sobrien
131690075Sobrienint
1317132718Skancc_reg_operand (rtx op, enum machine_mode mode)
131890075Sobrien{
131990075Sobrien  return (register_operand (op, mode)
132090075Sobrien	  && (GET_CODE (op) != REG
132190075Sobrien	      || REGNO (op) >= FIRST_PSEUDO_REGISTER
132290075Sobrien	      || CR_REGNO_P (REGNO (op))));
132390075Sobrien}
132490075Sobrien
132590075Sobrien/* Returns 1 if OP is either a pseudo-register or a register denoting a
132690075Sobrien   CR field that isn't CR0.  */
132790075Sobrien
132890075Sobrienint
1329132718Skancc_reg_not_cr0_operand (rtx op, enum machine_mode mode)
133090075Sobrien{
133190075Sobrien  return (register_operand (op, mode)
133290075Sobrien	  && (GET_CODE (op) != REG
133390075Sobrien	      || REGNO (op) >= FIRST_PSEUDO_REGISTER
133490075Sobrien	      || CR_REGNO_NOT_CR0_P (REGNO (op))));
133590075Sobrien}
133690075Sobrien
133790075Sobrien/* Returns 1 if OP is either a constant integer valid for a D-field or
133890075Sobrien   a non-special register.  If a register, it must be in the proper
133990075Sobrien   mode unless MODE is VOIDmode.  */
134090075Sobrien
134190075Sobrienint
1342132718Skanreg_or_short_operand (rtx op, enum machine_mode mode)
134390075Sobrien{
134490075Sobrien  return short_cint_operand (op, mode) || gpc_reg_operand (op, mode);
134590075Sobrien}
134690075Sobrien
134790075Sobrien/* Similar, except check if the negation of the constant would be
1348132718Skan   valid for a D-field.  Don't allow a constant zero, since all the
1349132718Skan   patterns that call this predicate use "addic r1,r2,-constant" on
1350132718Skan   a constant value to set a carry when r2 is greater or equal to
1351132718Skan   "constant".  That doesn't work for zero.  */
135290075Sobrien
135390075Sobrienint
1354132718Skanreg_or_neg_short_operand (rtx op, enum machine_mode mode)
135590075Sobrien{
135690075Sobrien  if (GET_CODE (op) == CONST_INT)
1357132718Skan    return CONST_OK_FOR_LETTER_P (INTVAL (op), 'P') && INTVAL (op) != 0;
135890075Sobrien
135990075Sobrien  return gpc_reg_operand (op, mode);
136090075Sobrien}
136190075Sobrien
136296263Sobrien/* Returns 1 if OP is either a constant integer valid for a DS-field or
136396263Sobrien   a non-special register.  If a register, it must be in the proper
136496263Sobrien   mode unless MODE is VOIDmode.  */
136596263Sobrien
136696263Sobrienint
1367132718Skanreg_or_aligned_short_operand (rtx op, enum machine_mode mode)
136896263Sobrien{
136996263Sobrien  if (gpc_reg_operand (op, mode))
137096263Sobrien    return 1;
137196263Sobrien  else if (short_cint_operand (op, mode) && !(INTVAL (op) & 3))
137296263Sobrien    return 1;
137396263Sobrien
137496263Sobrien  return 0;
137596263Sobrien}
137696263Sobrien
137796263Sobrien
137890075Sobrien/* Return 1 if the operand is either a register or an integer whose
137990075Sobrien   high-order 16 bits are zero.  */
138090075Sobrien
138190075Sobrienint
1382132718Skanreg_or_u_short_operand (rtx op, enum machine_mode mode)
138390075Sobrien{
138490075Sobrien  return u_short_cint_operand (op, mode) || gpc_reg_operand (op, mode);
138590075Sobrien}
138690075Sobrien
138790075Sobrien/* Return 1 is the operand is either a non-special register or ANY
138890075Sobrien   constant integer.  */
138990075Sobrien
139090075Sobrienint
1391132718Skanreg_or_cint_operand (rtx op, enum machine_mode mode)
139290075Sobrien{
139390075Sobrien  return (GET_CODE (op) == CONST_INT || gpc_reg_operand (op, mode));
139490075Sobrien}
139590075Sobrien
139690075Sobrien/* Return 1 is the operand is either a non-special register or ANY
139790075Sobrien   32-bit signed constant integer.  */
139890075Sobrien
139990075Sobrienint
1400132718Skanreg_or_arith_cint_operand (rtx op, enum machine_mode mode)
140190075Sobrien{
140290075Sobrien  return (gpc_reg_operand (op, mode)
140390075Sobrien	  || (GET_CODE (op) == CONST_INT
140490075Sobrien#if HOST_BITS_PER_WIDE_INT != 32
140590075Sobrien	      && ((unsigned HOST_WIDE_INT) (INTVAL (op) + 0x80000000)
140690075Sobrien		  < (unsigned HOST_WIDE_INT) 0x100000000ll)
140790075Sobrien#endif
140890075Sobrien	      ));
140990075Sobrien}
141090075Sobrien
141190075Sobrien/* Return 1 is the operand is either a non-special register or a 32-bit
141290075Sobrien   signed constant integer valid for 64-bit addition.  */
141390075Sobrien
141490075Sobrienint
1415132718Skanreg_or_add_cint64_operand (rtx op, enum machine_mode mode)
141690075Sobrien{
141790075Sobrien  return (gpc_reg_operand (op, mode)
141890075Sobrien	  || (GET_CODE (op) == CONST_INT
1419117395Skan#if HOST_BITS_PER_WIDE_INT == 32
142090075Sobrien	      && INTVAL (op) < 0x7fff8000
1421117395Skan#else
142290075Sobrien	      && ((unsigned HOST_WIDE_INT) (INTVAL (op) + 0x80008000)
142390075Sobrien		  < 0x100000000ll)
142490075Sobrien#endif
142590075Sobrien	      ));
142690075Sobrien}
142790075Sobrien
142890075Sobrien/* Return 1 is the operand is either a non-special register or a 32-bit
142990075Sobrien   signed constant integer valid for 64-bit subtraction.  */
143090075Sobrien
143190075Sobrienint
1432132718Skanreg_or_sub_cint64_operand (rtx op, enum machine_mode mode)
143390075Sobrien{
143490075Sobrien  return (gpc_reg_operand (op, mode)
143590075Sobrien	  || (GET_CODE (op) == CONST_INT
1436117395Skan#if HOST_BITS_PER_WIDE_INT == 32
143790075Sobrien	      && (- INTVAL (op)) < 0x7fff8000
1438117395Skan#else
143990075Sobrien	      && ((unsigned HOST_WIDE_INT) ((- INTVAL (op)) + 0x80008000)
144090075Sobrien		  < 0x100000000ll)
144190075Sobrien#endif
144290075Sobrien	      ));
144390075Sobrien}
144490075Sobrien
144590075Sobrien/* Return 1 is the operand is either a non-special register or ANY
144690075Sobrien   32-bit unsigned constant integer.  */
144790075Sobrien
144890075Sobrienint
1449132718Skanreg_or_logical_cint_operand (rtx op, enum machine_mode mode)
145090075Sobrien{
145190075Sobrien  if (GET_CODE (op) == CONST_INT)
145290075Sobrien    {
145390075Sobrien      if (GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT)
145490075Sobrien	{
145590075Sobrien	  if (GET_MODE_BITSIZE (mode) <= 32)
145690075Sobrien	    abort ();
145790075Sobrien
145890075Sobrien	  if (INTVAL (op) < 0)
145990075Sobrien	    return 0;
146090075Sobrien	}
146190075Sobrien
146290075Sobrien      return ((INTVAL (op) & GET_MODE_MASK (mode)
146390075Sobrien	       & (~ (unsigned HOST_WIDE_INT) 0xffffffff)) == 0);
146490075Sobrien    }
146590075Sobrien  else if (GET_CODE (op) == CONST_DOUBLE)
146690075Sobrien    {
146790075Sobrien      if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
146890075Sobrien	  || mode != DImode)
146990075Sobrien	abort ();
147090075Sobrien
147190075Sobrien      return CONST_DOUBLE_HIGH (op) == 0;
147290075Sobrien    }
147390075Sobrien  else
147490075Sobrien    return gpc_reg_operand (op, mode);
147590075Sobrien}
147690075Sobrien
147790075Sobrien/* Return 1 if the operand is an operand that can be loaded via the GOT.  */
147890075Sobrien
147990075Sobrienint
1480132718Skangot_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
148190075Sobrien{
148290075Sobrien  return (GET_CODE (op) == SYMBOL_REF
148390075Sobrien	  || GET_CODE (op) == CONST
148490075Sobrien	  || GET_CODE (op) == LABEL_REF);
148590075Sobrien}
148690075Sobrien
148790075Sobrien/* Return 1 if the operand is a simple references that can be loaded via
148890075Sobrien   the GOT (labels involving addition aren't allowed).  */
148990075Sobrien
149090075Sobrienint
1491132718Skangot_no_const_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
149290075Sobrien{
149390075Sobrien  return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF);
149490075Sobrien}
149590075Sobrien
149690075Sobrien/* Return the number of instructions it takes to form a constant in an
149790075Sobrien   integer register.  */
149890075Sobrien
149990075Sobrienstatic int
1500132718Skannum_insns_constant_wide (HOST_WIDE_INT value)
150190075Sobrien{
150290075Sobrien  /* signed constant loadable with {cal|addi} */
150390075Sobrien  if (CONST_OK_FOR_LETTER_P (value, 'I'))
150490075Sobrien    return 1;
150590075Sobrien
150690075Sobrien  /* constant loadable with {cau|addis} */
150790075Sobrien  else if (CONST_OK_FOR_LETTER_P (value, 'L'))
150890075Sobrien    return 1;
150990075Sobrien
151090075Sobrien#if HOST_BITS_PER_WIDE_INT == 64
151190075Sobrien  else if (TARGET_POWERPC64)
151290075Sobrien    {
1513117395Skan      HOST_WIDE_INT low  = ((value & 0xffffffff) ^ 0x80000000) - 0x80000000;
1514117395Skan      HOST_WIDE_INT high = value >> 31;
151590075Sobrien
1516117395Skan      if (high == 0 || high == -1)
151790075Sobrien	return 2;
151890075Sobrien
1519117395Skan      high >>= 1;
152090075Sobrien
1521117395Skan      if (low == 0)
152290075Sobrien	return num_insns_constant_wide (high) + 1;
152390075Sobrien      else
152490075Sobrien	return (num_insns_constant_wide (high)
152590075Sobrien		+ num_insns_constant_wide (low) + 1);
152690075Sobrien    }
152790075Sobrien#endif
152890075Sobrien
152990075Sobrien  else
153090075Sobrien    return 2;
153190075Sobrien}
153290075Sobrien
153390075Sobrienint
1534132718Skannum_insns_constant (rtx op, enum machine_mode mode)
153590075Sobrien{
153690075Sobrien  if (GET_CODE (op) == CONST_INT)
153790075Sobrien    {
153890075Sobrien#if HOST_BITS_PER_WIDE_INT == 64
153990075Sobrien      if ((INTVAL (op) >> 31) != 0 && (INTVAL (op) >> 31) != -1
154090075Sobrien	  && mask64_operand (op, mode))
154190075Sobrien	    return 2;
154290075Sobrien      else
154390075Sobrien#endif
154490075Sobrien	return num_insns_constant_wide (INTVAL (op));
154590075Sobrien    }
154690075Sobrien
154790075Sobrien  else if (GET_CODE (op) == CONST_DOUBLE && mode == SFmode)
154890075Sobrien    {
154990075Sobrien      long l;
155090075Sobrien      REAL_VALUE_TYPE rv;
155190075Sobrien
155290075Sobrien      REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
155390075Sobrien      REAL_VALUE_TO_TARGET_SINGLE (rv, l);
155496263Sobrien      return num_insns_constant_wide ((HOST_WIDE_INT) l);
155590075Sobrien    }
155690075Sobrien
155790075Sobrien  else if (GET_CODE (op) == CONST_DOUBLE)
155890075Sobrien    {
155990075Sobrien      HOST_WIDE_INT low;
156090075Sobrien      HOST_WIDE_INT high;
156190075Sobrien      long l[2];
156290075Sobrien      REAL_VALUE_TYPE rv;
156390075Sobrien      int endian = (WORDS_BIG_ENDIAN == 0);
156490075Sobrien
156590075Sobrien      if (mode == VOIDmode || mode == DImode)
156690075Sobrien	{
156790075Sobrien	  high = CONST_DOUBLE_HIGH (op);
156890075Sobrien	  low  = CONST_DOUBLE_LOW (op);
156990075Sobrien	}
157090075Sobrien      else
157190075Sobrien	{
157290075Sobrien	  REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
157390075Sobrien	  REAL_VALUE_TO_TARGET_DOUBLE (rv, l);
157490075Sobrien	  high = l[endian];
157590075Sobrien	  low  = l[1 - endian];
157690075Sobrien	}
157790075Sobrien
157890075Sobrien      if (TARGET_32BIT)
157990075Sobrien	return (num_insns_constant_wide (low)
158090075Sobrien		+ num_insns_constant_wide (high));
158190075Sobrien
158290075Sobrien      else
158390075Sobrien	{
158496263Sobrien	  if (high == 0 && low >= 0)
158590075Sobrien	    return num_insns_constant_wide (low);
158690075Sobrien
158796263Sobrien	  else if (high == -1 && low < 0)
158890075Sobrien	    return num_insns_constant_wide (low);
158990075Sobrien
159090075Sobrien	  else if (mask64_operand (op, mode))
159190075Sobrien	    return 2;
159290075Sobrien
159390075Sobrien	  else if (low == 0)
159490075Sobrien	    return num_insns_constant_wide (high) + 1;
159590075Sobrien
159690075Sobrien	  else
159790075Sobrien	    return (num_insns_constant_wide (high)
159890075Sobrien		    + num_insns_constant_wide (low) + 1);
159990075Sobrien	}
160090075Sobrien    }
160190075Sobrien
160290075Sobrien  else
160390075Sobrien    abort ();
160490075Sobrien}
160590075Sobrien
160690075Sobrien/* Return 1 if the operand is a CONST_DOUBLE and it can be put into a
160790075Sobrien   register with one instruction per word.  We only do this if we can
160890075Sobrien   safely read CONST_DOUBLE_{LOW,HIGH}.  */
160990075Sobrien
161090075Sobrienint
1611132718Skaneasy_fp_constant (rtx op, enum machine_mode mode)
161290075Sobrien{
161390075Sobrien  if (GET_CODE (op) != CONST_DOUBLE
161490075Sobrien      || GET_MODE (op) != mode
161590075Sobrien      || (GET_MODE_CLASS (mode) != MODE_FLOAT && mode != DImode))
161690075Sobrien    return 0;
161790075Sobrien
161890075Sobrien  /* Consider all constants with -msoft-float to be easy.  */
1619117395Skan  if ((TARGET_SOFT_FLOAT || !TARGET_FPRS)
1620117395Skan      && mode != DImode)
162190075Sobrien    return 1;
162290075Sobrien
162390075Sobrien  /* If we are using V.4 style PIC, consider all constants to be hard.  */
162490075Sobrien  if (flag_pic && DEFAULT_ABI == ABI_V4)
162590075Sobrien    return 0;
162690075Sobrien
162790075Sobrien#ifdef TARGET_RELOCATABLE
162890075Sobrien  /* Similarly if we are using -mrelocatable, consider all constants
162990075Sobrien     to be hard.  */
163090075Sobrien  if (TARGET_RELOCATABLE)
163190075Sobrien    return 0;
163290075Sobrien#endif
163390075Sobrien
1634117395Skan  if (mode == TFmode)
163590075Sobrien    {
1636117395Skan      long k[4];
1637117395Skan      REAL_VALUE_TYPE rv;
1638117395Skan
1639117395Skan      REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
1640117395Skan      REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, k);
1641117395Skan
1642117395Skan      return (num_insns_constant_wide ((HOST_WIDE_INT) k[0]) == 1
1643117395Skan	      && num_insns_constant_wide ((HOST_WIDE_INT) k[1]) == 1
1644117395Skan	      && num_insns_constant_wide ((HOST_WIDE_INT) k[2]) == 1
1645117395Skan	      && num_insns_constant_wide ((HOST_WIDE_INT) k[3]) == 1);
1646117395Skan    }
1647117395Skan
1648117395Skan  else if (mode == DFmode)
1649117395Skan    {
165090075Sobrien      long k[2];
165190075Sobrien      REAL_VALUE_TYPE rv;
165290075Sobrien
165390075Sobrien      REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
165490075Sobrien      REAL_VALUE_TO_TARGET_DOUBLE (rv, k);
165590075Sobrien
1656117395Skan      return (num_insns_constant_wide ((HOST_WIDE_INT) k[0]) == 1
1657117395Skan	      && num_insns_constant_wide ((HOST_WIDE_INT) k[1]) == 1);
165890075Sobrien    }
165990075Sobrien
166090075Sobrien  else if (mode == SFmode)
166190075Sobrien    {
166290075Sobrien      long l;
166390075Sobrien      REAL_VALUE_TYPE rv;
166490075Sobrien
166590075Sobrien      REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
166690075Sobrien      REAL_VALUE_TO_TARGET_SINGLE (rv, l);
166790075Sobrien
166890075Sobrien      return num_insns_constant_wide (l) == 1;
166990075Sobrien    }
167090075Sobrien
167190075Sobrien  else if (mode == DImode)
167290075Sobrien    return ((TARGET_POWERPC64
167390075Sobrien	     && GET_CODE (op) == CONST_DOUBLE && CONST_DOUBLE_LOW (op) == 0)
167490075Sobrien	    || (num_insns_constant (op, DImode) <= 2));
167590075Sobrien
167690075Sobrien  else if (mode == SImode)
167790075Sobrien    return 1;
167890075Sobrien  else
167990075Sobrien    abort ();
168090075Sobrien}
168190075Sobrien
1682132718Skan/* Returns the constant for the splat instrunction, if exists.  */
168396263Sobrien
168496263Sobrienstatic int
1685132718Skaneasy_vector_splat_const (int cst, enum machine_mode mode)
168696263Sobrien{
1687132718Skan  switch (mode)
1688132718Skan    {
1689132718Skan    case V4SImode:
1690132718Skan      if (EASY_VECTOR_15 (cst)
1691132718Skan	  || EASY_VECTOR_15_ADD_SELF (cst))
1692132718Skan	return cst;
1693132718Skan      if ((cst & 0xffff) != ((cst >> 16) & 0xffff))
1694132718Skan	break;
1695132718Skan      cst = cst >> 16;
1696132718Skan    case V8HImode:
1697132718Skan      if (EASY_VECTOR_15 (cst)
1698132718Skan	  || EASY_VECTOR_15_ADD_SELF (cst))
1699132718Skan	return cst;
1700132718Skan      if ((cst & 0xff) != ((cst >> 8) & 0xff))
1701132718Skan	break;
1702132718Skan      cst = cst >> 8;
1703132718Skan    case V16QImode:
1704132718Skan	  if (EASY_VECTOR_15 (cst)
1705132718Skan	      || EASY_VECTOR_15_ADD_SELF (cst))
1706132718Skan	    return cst;
1707132718Skan    default:
1708132718Skan      break;
1709132718Skan    }
1710132718Skan  return 0;
1711132718Skan}
171296263Sobrien
171396263Sobrien
1714132718Skan/* Return nonzero if all elements of a vector have the same value.  */
1715132718Skan
1716132718Skanstatic int
1717132718Skaneasy_vector_same (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
1718132718Skan{
1719132718Skan  int units, i, cst;
1720132718Skan
172196263Sobrien  units = CONST_VECTOR_NUNITS (op);
172296263Sobrien
1723132718Skan  cst = INTVAL (CONST_VECTOR_ELT (op, 0));
1724132718Skan  for (i = 1; i < units; ++i)
1725132718Skan    if (INTVAL (CONST_VECTOR_ELT (op, i)) != cst)
1726132718Skan      break;
1727132718Skan  if (i == units && easy_vector_splat_const (cst, mode))
1728132718Skan    return 1;
1729132718Skan  return 0;
1730132718Skan}
1731132718Skan
1732132718Skan/* Return 1 if the operand is a CONST_INT and can be put into a
1733132718Skan   register without using memory.  */
1734132718Skan
1735132718Skanint
1736132718Skaneasy_vector_constant (rtx op, enum machine_mode mode)
1737132718Skan{
1738132718Skan  int cst, cst2;
1739132718Skan
1740132718Skan  if (GET_CODE (op) != CONST_VECTOR
1741132718Skan      || (!TARGET_ALTIVEC
1742132718Skan	  && !TARGET_SPE))
1743132718Skan    return 0;
1744132718Skan
1745132718Skan  if (zero_constant (op, mode)
1746132718Skan      && ((TARGET_ALTIVEC && ALTIVEC_VECTOR_MODE (mode))
1747132718Skan	  || (TARGET_SPE && SPE_VECTOR_MODE (mode))))
1748132718Skan    return 1;
1749132718Skan
1750132718Skan  if (GET_MODE_CLASS (mode) != MODE_VECTOR_INT)
1751132718Skan    return 0;
1752132718Skan
1753132718Skan  if (TARGET_SPE && mode == V1DImode)
1754132718Skan    return 0;
1755132718Skan
1756132718Skan  cst  = INTVAL (CONST_VECTOR_ELT (op, 0));
1757132718Skan  cst2 = INTVAL (CONST_VECTOR_ELT (op, 1));
1758132718Skan
1759132718Skan  /* Limit SPE vectors to 15 bits signed.  These we can generate with:
1760132718Skan       li r0, CONSTANT1
1761132718Skan       evmergelo r0, r0, r0
1762132718Skan       li r0, CONSTANT2
1763132718Skan
1764132718Skan     I don't know how efficient it would be to allow bigger constants,
1765132718Skan     considering we'll have an extra 'ori' for every 'li'.  I doubt 5
1766132718Skan     instructions is better than a 64-bit memory load, but I don't
1767132718Skan     have the e500 timing specs.  */
1768132718Skan  if (TARGET_SPE && mode == V2SImode
1769132718Skan      && cst  >= -0x7fff && cst <= 0x7fff
1770132718Skan      && cst2 >= -0x7fff && cst2 <= 0x7fff)
1771132718Skan    return 1;
1772132718Skan
1773132718Skan  if (TARGET_ALTIVEC
1774132718Skan      && easy_vector_same (op, mode))
177596263Sobrien    {
1776132718Skan      cst = easy_vector_splat_const (cst, mode);
1777132718Skan      if (EASY_VECTOR_15_ADD_SELF (cst)
1778132718Skan	  || EASY_VECTOR_15 (cst))
1779132718Skan	return 1;
1780132718Skan    }
1781132718Skan  return 0;
1782132718Skan}
178396263Sobrien
1784132718Skan/* Same as easy_vector_constant but only for EASY_VECTOR_15_ADD_SELF.  */
178596263Sobrien
1786132718Skanint
1787132718Skaneasy_vector_constant_add_self (rtx op, enum machine_mode mode)
1788132718Skan{
1789132718Skan  int cst;
1790132718Skan  if (TARGET_ALTIVEC
1791132718Skan      && GET_CODE (op) == CONST_VECTOR
1792132718Skan      && easy_vector_same (op, mode))
1793132718Skan    {
1794132718Skan      cst = easy_vector_splat_const (INTVAL (CONST_VECTOR_ELT (op, 0)), mode);
1795132718Skan      if (EASY_VECTOR_15_ADD_SELF (cst))
1796132718Skan	return 1;
1797132718Skan    }
1798132718Skan  return 0;
1799132718Skan}
1800132718Skan
1801132718Skan/* Generate easy_vector_constant out of a easy_vector_constant_add_self.  */
1802132718Skan
1803132718Skanrtx
1804132718Skangen_easy_vector_constant_add_self (rtx op)
1805132718Skan{
1806132718Skan  int i, units;
1807132718Skan  rtvec v;
1808132718Skan  units = GET_MODE_NUNITS (GET_MODE (op));
1809132718Skan  v = rtvec_alloc (units);
1810132718Skan
1811132718Skan  for (i = 0; i < units; i++)
1812132718Skan    RTVEC_ELT (v, i) =
1813132718Skan      GEN_INT (INTVAL (CONST_VECTOR_ELT (op, i)) >> 1);
1814132718Skan  return gen_rtx_raw_CONST_VECTOR (GET_MODE (op), v);
1815132718Skan}
1816132718Skan
1817132718Skanconst char *
1818132718Skanoutput_vec_const_move (rtx *operands)
1819132718Skan{
1820132718Skan  int cst, cst2;
1821132718Skan  enum machine_mode mode;
1822132718Skan  rtx dest, vec;
1823132718Skan
1824132718Skan  dest = operands[0];
1825132718Skan  vec = operands[1];
1826132718Skan
1827132718Skan  cst = INTVAL (CONST_VECTOR_ELT (vec, 0));
1828132718Skan  cst2 = INTVAL (CONST_VECTOR_ELT (vec, 1));
1829132718Skan  mode = GET_MODE (dest);
1830132718Skan
1831132718Skan  if (TARGET_ALTIVEC)
1832132718Skan    {
1833132718Skan      if (zero_constant (vec, mode))
1834132718Skan	return "vxor %0,%0,%0";
1835132718Skan      else if (easy_vector_constant (vec, mode))
183696263Sobrien	{
1837132718Skan	  operands[1] = GEN_INT (cst);
1838132718Skan	  switch (mode)
1839132718Skan	    {
1840132718Skan	    case V4SImode:
1841132718Skan	      if (EASY_VECTOR_15 (cst))
1842132718Skan		{
1843132718Skan		  operands[1] = GEN_INT (cst);
1844132718Skan		  return "vspltisw %0,%1";
1845132718Skan		}
1846132718Skan	      else if (EASY_VECTOR_15_ADD_SELF (cst))
1847132718Skan		return "#";
1848132718Skan	      cst = cst >> 16;
1849132718Skan	    case V8HImode:
1850132718Skan	      if (EASY_VECTOR_15 (cst))
1851132718Skan		{
1852132718Skan		  operands[1] = GEN_INT (cst);
1853132718Skan		  return "vspltish %0,%1";
1854132718Skan		}
1855132718Skan	      else if (EASY_VECTOR_15_ADD_SELF (cst))
1856132718Skan		return "#";
1857132718Skan	      cst = cst >> 8;
1858132718Skan	    case V16QImode:
1859132718Skan	      if (EASY_VECTOR_15 (cst))
1860132718Skan		{
1861132718Skan		  operands[1] = GEN_INT (cst);
1862132718Skan		  return "vspltisb %0,%1";
1863132718Skan		}
1864132718Skan	      else if (EASY_VECTOR_15_ADD_SELF (cst))
1865132718Skan		return "#";
1866132718Skan	    default:
1867132718Skan	      abort ();
1868132718Skan	    }
186996263Sobrien	}
1870132718Skan      else
1871132718Skan	abort ();
187296263Sobrien    }
187396263Sobrien
1874132718Skan  if (TARGET_SPE)
1875132718Skan    {
1876132718Skan      /* Vector constant 0 is handled as a splitter of V2SI, and in the
1877132718Skan	 pattern of V1DI, V4HI, and V2SF.
1878132718Skan
1879132718Skan	 FIXME: We should probably return # and add post reload
1880132718Skan	 splitters for these, but this way is so easy ;-).
1881132718Skan      */
1882132718Skan      operands[1] = GEN_INT (cst);
1883132718Skan      operands[2] = GEN_INT (cst2);
1884132718Skan      if (cst == cst2)
1885132718Skan	return "li %0,%1\n\tevmergelo %0,%0,%0";
1886132718Skan      else
1887132718Skan	return "li %0,%1\n\tevmergelo %0,%0,%0\n\tli %0,%2";
1888132718Skan    }
1889132718Skan
1890132718Skan  abort ();
189196263Sobrien}
189296263Sobrien
189396263Sobrien/* Return 1 if the operand is the constant 0.  This works for scalars
189496263Sobrien   as well as vectors.  */
189596263Sobrienint
1896132718Skanzero_constant (rtx op, enum machine_mode mode)
189796263Sobrien{
189896263Sobrien  return op == CONST0_RTX (mode);
189996263Sobrien}
190096263Sobrien
190190075Sobrien/* Return 1 if the operand is 0.0.  */
190290075Sobrienint
1903132718Skanzero_fp_constant (rtx op, enum machine_mode mode)
190490075Sobrien{
190590075Sobrien  return GET_MODE_CLASS (mode) == MODE_FLOAT && op == CONST0_RTX (mode);
190690075Sobrien}
190790075Sobrien
190890075Sobrien/* Return 1 if the operand is in volatile memory.  Note that during
190990075Sobrien   the RTL generation phase, memory_operand does not return TRUE for
191090075Sobrien   volatile memory references.  So this function allows us to
191190075Sobrien   recognize volatile references where its safe.  */
191290075Sobrien
191390075Sobrienint
1914132718Skanvolatile_mem_operand (rtx op, enum machine_mode mode)
191590075Sobrien{
191690075Sobrien  if (GET_CODE (op) != MEM)
191790075Sobrien    return 0;
191890075Sobrien
191990075Sobrien  if (!MEM_VOLATILE_P (op))
192090075Sobrien    return 0;
192190075Sobrien
192290075Sobrien  if (mode != GET_MODE (op))
192390075Sobrien    return 0;
192490075Sobrien
192590075Sobrien  if (reload_completed)
192690075Sobrien    return memory_operand (op, mode);
192790075Sobrien
192890075Sobrien  if (reload_in_progress)
192990075Sobrien    return strict_memory_address_p (mode, XEXP (op, 0));
193090075Sobrien
193190075Sobrien  return memory_address_p (mode, XEXP (op, 0));
193290075Sobrien}
193390075Sobrien
193490075Sobrien/* Return 1 if the operand is an offsettable memory operand.  */
193590075Sobrien
193690075Sobrienint
1937132718Skanoffsettable_mem_operand (rtx op, enum machine_mode mode)
193890075Sobrien{
193990075Sobrien  return ((GET_CODE (op) == MEM)
194090075Sobrien	  && offsettable_address_p (reload_completed || reload_in_progress,
194190075Sobrien				    mode, XEXP (op, 0)));
194290075Sobrien}
194390075Sobrien
194490075Sobrien/* Return 1 if the operand is either an easy FP constant (see above) or
194590075Sobrien   memory.  */
194690075Sobrien
194790075Sobrienint
1948132718Skanmem_or_easy_const_operand (rtx op, enum machine_mode mode)
194990075Sobrien{
195090075Sobrien  return memory_operand (op, mode) || easy_fp_constant (op, mode);
195190075Sobrien}
195290075Sobrien
195390075Sobrien/* Return 1 if the operand is either a non-special register or an item
195490075Sobrien   that can be used as the operand of a `mode' add insn.  */
195590075Sobrien
195690075Sobrienint
1957132718Skanadd_operand (rtx op, enum machine_mode mode)
195890075Sobrien{
195990075Sobrien  if (GET_CODE (op) == CONST_INT)
196096263Sobrien    return (CONST_OK_FOR_LETTER_P (INTVAL (op), 'I')
196196263Sobrien	    || CONST_OK_FOR_LETTER_P (INTVAL (op), 'L'));
196290075Sobrien
196390075Sobrien  return gpc_reg_operand (op, mode);
196490075Sobrien}
196590075Sobrien
196690075Sobrien/* Return 1 if OP is a constant but not a valid add_operand.  */
196790075Sobrien
196890075Sobrienint
1969132718Skannon_add_cint_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
197090075Sobrien{
197190075Sobrien  return (GET_CODE (op) == CONST_INT
197296263Sobrien	  && !CONST_OK_FOR_LETTER_P (INTVAL (op), 'I')
197396263Sobrien	  && !CONST_OK_FOR_LETTER_P (INTVAL (op), 'L'));
197490075Sobrien}
197590075Sobrien
197690075Sobrien/* Return 1 if the operand is a non-special register or a constant that
197790075Sobrien   can be used as the operand of an OR or XOR insn on the RS/6000.  */
197890075Sobrien
197990075Sobrienint
1980132718Skanlogical_operand (rtx op, enum machine_mode mode)
198190075Sobrien{
198290075Sobrien  HOST_WIDE_INT opl, oph;
198390075Sobrien
198490075Sobrien  if (gpc_reg_operand (op, mode))
198590075Sobrien    return 1;
198690075Sobrien
198790075Sobrien  if (GET_CODE (op) == CONST_INT)
198890075Sobrien    {
198990075Sobrien      opl = INTVAL (op) & GET_MODE_MASK (mode);
199090075Sobrien
199190075Sobrien#if HOST_BITS_PER_WIDE_INT <= 32
199290075Sobrien      if (GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT && opl < 0)
199390075Sobrien	return 0;
199490075Sobrien#endif
199590075Sobrien    }
199690075Sobrien  else if (GET_CODE (op) == CONST_DOUBLE)
199790075Sobrien    {
199890075Sobrien      if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
199990075Sobrien	abort ();
200090075Sobrien
200190075Sobrien      opl = CONST_DOUBLE_LOW (op);
200290075Sobrien      oph = CONST_DOUBLE_HIGH (op);
200390075Sobrien      if (oph != 0)
200490075Sobrien	return 0;
200590075Sobrien    }
200690075Sobrien  else
200790075Sobrien    return 0;
200890075Sobrien
200990075Sobrien  return ((opl & ~ (unsigned HOST_WIDE_INT) 0xffff) == 0
201090075Sobrien	  || (opl & ~ (unsigned HOST_WIDE_INT) 0xffff0000) == 0);
201190075Sobrien}
201290075Sobrien
201390075Sobrien/* Return 1 if C is a constant that is not a logical operand (as
201490075Sobrien   above), but could be split into one.  */
201590075Sobrien
201690075Sobrienint
2017132718Skannon_logical_cint_operand (rtx op, enum machine_mode mode)
201890075Sobrien{
201990075Sobrien  return ((GET_CODE (op) == CONST_INT || GET_CODE (op) == CONST_DOUBLE)
202090075Sobrien	  && ! logical_operand (op, mode)
202190075Sobrien	  && reg_or_logical_cint_operand (op, mode));
202290075Sobrien}
202390075Sobrien
202490075Sobrien/* Return 1 if C is a constant that can be encoded in a 32-bit mask on the
202590075Sobrien   RS/6000.  It is if there are no more than two 1->0 or 0->1 transitions.
202690075Sobrien   Reject all ones and all zeros, since these should have been optimized
202790075Sobrien   away and confuse the making of MB and ME.  */
202890075Sobrien
202990075Sobrienint
2030132718Skanmask_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
203190075Sobrien{
203290075Sobrien  HOST_WIDE_INT c, lsb;
203390075Sobrien
203490075Sobrien  if (GET_CODE (op) != CONST_INT)
203590075Sobrien    return 0;
203690075Sobrien
203790075Sobrien  c = INTVAL (op);
203890075Sobrien
203996263Sobrien  /* Fail in 64-bit mode if the mask wraps around because the upper
204096263Sobrien     32-bits of the mask will all be 1s, contrary to GCC's internal view.  */
204196263Sobrien  if (TARGET_POWERPC64 && (c & 0x80000001) == 0x80000001)
204296263Sobrien    return 0;
204396263Sobrien
204490075Sobrien  /* We don't change the number of transitions by inverting,
204590075Sobrien     so make sure we start with the LS bit zero.  */
204690075Sobrien  if (c & 1)
204790075Sobrien    c = ~c;
204890075Sobrien
204990075Sobrien  /* Reject all zeros or all ones.  */
205090075Sobrien  if (c == 0)
205190075Sobrien    return 0;
205290075Sobrien
205390075Sobrien  /* Find the first transition.  */
205490075Sobrien  lsb = c & -c;
205590075Sobrien
205690075Sobrien  /* Invert to look for a second transition.  */
205790075Sobrien  c = ~c;
205890075Sobrien
205990075Sobrien  /* Erase first transition.  */
206090075Sobrien  c &= -lsb;
206190075Sobrien
206290075Sobrien  /* Find the second transition (if any).  */
206390075Sobrien  lsb = c & -c;
206490075Sobrien
206590075Sobrien  /* Match if all the bits above are 1's (or c is zero).  */
206690075Sobrien  return c == -lsb;
206790075Sobrien}
206890075Sobrien
2069117395Skan/* Return 1 for the PowerPC64 rlwinm corner case.  */
2070117395Skan
2071117395Skanint
2072132718Skanmask_operand_wrap (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
2073117395Skan{
2074117395Skan  HOST_WIDE_INT c, lsb;
2075117395Skan
2076117395Skan  if (GET_CODE (op) != CONST_INT)
2077117395Skan    return 0;
2078117395Skan
2079117395Skan  c = INTVAL (op);
2080117395Skan
2081117395Skan  if ((c & 0x80000001) != 0x80000001)
2082117395Skan    return 0;
2083117395Skan
2084117395Skan  c = ~c;
2085117395Skan  if (c == 0)
2086117395Skan    return 0;
2087117395Skan
2088117395Skan  lsb = c & -c;
2089117395Skan  c = ~c;
2090117395Skan  c &= -lsb;
2091117395Skan  lsb = c & -c;
2092117395Skan  return c == -lsb;
2093117395Skan}
2094117395Skan
209590075Sobrien/* Return 1 if the operand is a constant that is a PowerPC64 mask.
209690075Sobrien   It is if there are no more than one 1->0 or 0->1 transitions.
2097117395Skan   Reject all zeros, since zero should have been optimized away and
2098117395Skan   confuses the making of MB and ME.  */
209990075Sobrien
210090075Sobrienint
2101132718Skanmask64_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
210290075Sobrien{
210390075Sobrien  if (GET_CODE (op) == CONST_INT)
210490075Sobrien    {
210590075Sobrien      HOST_WIDE_INT c, lsb;
210690075Sobrien
2107117395Skan      c = INTVAL (op);
2108117395Skan
2109117395Skan      /* Reject all zeros.  */
2110117395Skan      if (c == 0)
2111117395Skan	return 0;
2112117395Skan
211390075Sobrien      /* We don't change the number of transitions by inverting,
211490075Sobrien	 so make sure we start with the LS bit zero.  */
211590075Sobrien      if (c & 1)
211690075Sobrien	c = ~c;
211790075Sobrien
211890075Sobrien      /* Find the transition, and check that all bits above are 1's.  */
211990075Sobrien      lsb = c & -c;
2120132718Skan
2121132718Skan      /* Match if all the bits above are 1's (or c is zero).  */
212290075Sobrien      return c == -lsb;
212390075Sobrien    }
2124117395Skan  return 0;
2125117395Skan}
2126117395Skan
2127117395Skan/* Like mask64_operand, but allow up to three transitions.  This
2128117395Skan   predicate is used by insn patterns that generate two rldicl or
2129117395Skan   rldicr machine insns.  */
2130117395Skan
2131117395Skanint
2132132718Skanmask64_2_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
2133117395Skan{
2134117395Skan  if (GET_CODE (op) == CONST_INT)
213590075Sobrien    {
2136117395Skan      HOST_WIDE_INT c, lsb;
213790075Sobrien
2138117395Skan      c = INTVAL (op);
213990075Sobrien
2140117395Skan      /* Disallow all zeros.  */
2141117395Skan      if (c == 0)
2142117395Skan	return 0;
214390075Sobrien
2144117395Skan      /* We don't change the number of transitions by inverting,
2145117395Skan	 so make sure we start with the LS bit zero.  */
2146117395Skan      if (c & 1)
2147117395Skan	c = ~c;
214890075Sobrien
2149117395Skan      /* Find the first transition.  */
2150117395Skan      lsb = c & -c;
215190075Sobrien
2152117395Skan      /* Invert to look for a second transition.  */
2153117395Skan      c = ~c;
2154117395Skan
2155117395Skan      /* Erase first transition.  */
2156117395Skan      c &= -lsb;
2157117395Skan
2158117395Skan      /* Find the second transition.  */
2159117395Skan      lsb = c & -c;
2160117395Skan
2161117395Skan      /* Invert to look for a third transition.  */
2162117395Skan      c = ~c;
2163117395Skan
2164117395Skan      /* Erase second transition.  */
2165117395Skan      c &= -lsb;
2166117395Skan
2167117395Skan      /* Find the third transition (if any).  */
2168117395Skan      lsb = c & -c;
2169117395Skan
2170117395Skan      /* Match if all the bits above are 1's (or c is zero).  */
2171117395Skan      return c == -lsb;
217290075Sobrien    }
2173117395Skan  return 0;
2174117395Skan}
2175117395Skan
2176117395Skan/* Generates shifts and masks for a pair of rldicl or rldicr insns to
2177117395Skan   implement ANDing by the mask IN.  */
2178117395Skanvoid
2179132718Skanbuild_mask64_2_operands (rtx in, rtx *out)
2180117395Skan{
2181117395Skan#if HOST_BITS_PER_WIDE_INT >= 64
2182117395Skan  unsigned HOST_WIDE_INT c, lsb, m1, m2;
2183117395Skan  int shift;
2184117395Skan
2185117395Skan  if (GET_CODE (in) != CONST_INT)
2186117395Skan    abort ();
2187117395Skan
2188117395Skan  c = INTVAL (in);
2189117395Skan  if (c & 1)
2190117395Skan    {
2191117395Skan      /* Assume c initially something like 0x00fff000000fffff.  The idea
2192117395Skan	 is to rotate the word so that the middle ^^^^^^ group of zeros
2193117395Skan	 is at the MS end and can be cleared with an rldicl mask.  We then
2194117395Skan	 rotate back and clear off the MS    ^^ group of zeros with a
2195117395Skan	 second rldicl.  */
2196117395Skan      c = ~c;			/*   c == 0xff000ffffff00000 */
2197117395Skan      lsb = c & -c;		/* lsb == 0x0000000000100000 */
2198117395Skan      m1 = -lsb;		/*  m1 == 0xfffffffffff00000 */
2199117395Skan      c = ~c;			/*   c == 0x00fff000000fffff */
2200117395Skan      c &= -lsb;		/*   c == 0x00fff00000000000 */
2201117395Skan      lsb = c & -c;		/* lsb == 0x0000100000000000 */
2202117395Skan      c = ~c;			/*   c == 0xff000fffffffffff */
2203117395Skan      c &= -lsb;		/*   c == 0xff00000000000000 */
2204117395Skan      shift = 0;
2205117395Skan      while ((lsb >>= 1) != 0)
2206117395Skan	shift++;		/* shift == 44 on exit from loop */
2207117395Skan      m1 <<= 64 - shift;	/*  m1 == 0xffffff0000000000 */
2208117395Skan      m1 = ~m1;			/*  m1 == 0x000000ffffffffff */
2209117395Skan      m2 = ~c;			/*  m2 == 0x00ffffffffffffff */
2210117395Skan    }
221190075Sobrien  else
2212117395Skan    {
2213117395Skan      /* Assume c initially something like 0xff000f0000000000.  The idea
2214117395Skan	 is to rotate the word so that the     ^^^  middle group of zeros
2215117395Skan	 is at the LS end and can be cleared with an rldicr mask.  We then
2216117395Skan	 rotate back and clear off the LS group of ^^^^^^^^^^ zeros with
2217117395Skan	 a second rldicr.  */
2218117395Skan      lsb = c & -c;		/* lsb == 0x0000010000000000 */
2219117395Skan      m2 = -lsb;		/*  m2 == 0xffffff0000000000 */
2220117395Skan      c = ~c;			/*   c == 0x00fff0ffffffffff */
2221117395Skan      c &= -lsb;		/*   c == 0x00fff00000000000 */
2222117395Skan      lsb = c & -c;		/* lsb == 0x0000100000000000 */
2223117395Skan      c = ~c;			/*   c == 0xff000fffffffffff */
2224117395Skan      c &= -lsb;		/*   c == 0xff00000000000000 */
2225117395Skan      shift = 0;
2226117395Skan      while ((lsb >>= 1) != 0)
2227117395Skan	shift++;		/* shift == 44 on exit from loop */
2228117395Skan      m1 = ~c;			/*  m1 == 0x00ffffffffffffff */
2229117395Skan      m1 >>= shift;		/*  m1 == 0x0000000000000fff */
2230117395Skan      m1 = ~m1;			/*  m1 == 0xfffffffffffff000 */
2231117395Skan    }
2232117395Skan
2233117395Skan  /* Note that when we only have two 0->1 and 1->0 transitions, one of the
2234117395Skan     masks will be all 1's.  We are guaranteed more than one transition.  */
2235117395Skan  out[0] = GEN_INT (64 - shift);
2236117395Skan  out[1] = GEN_INT (m1);
2237117395Skan  out[2] = GEN_INT (shift);
2238117395Skan  out[3] = GEN_INT (m2);
2239117395Skan#else
2240117395Skan  (void)in;
2241117395Skan  (void)out;
2242117395Skan  abort ();
2243117395Skan#endif
224490075Sobrien}
224590075Sobrien
224690075Sobrien/* Return 1 if the operand is either a non-special register or a constant
224790075Sobrien   that can be used as the operand of a PowerPC64 logical AND insn.  */
224890075Sobrien
224990075Sobrienint
2250132718Skanand64_operand (rtx op, enum machine_mode mode)
225190075Sobrien{
225290075Sobrien  if (fixed_regs[CR0_REGNO])	/* CR0 not available, don't do andi./andis.  */
225390075Sobrien    return (gpc_reg_operand (op, mode) || mask64_operand (op, mode));
225490075Sobrien
225590075Sobrien  return (logical_operand (op, mode) || mask64_operand (op, mode));
225690075Sobrien}
225790075Sobrien
2258117395Skan/* Like the above, but also match constants that can be implemented
2259117395Skan   with two rldicl or rldicr insns.  */
2260117395Skan
2261117395Skanint
2262132718Skanand64_2_operand (rtx op, enum machine_mode mode)
2263117395Skan{
2264132718Skan  if (fixed_regs[CR0_REGNO])	/* CR0 not available, don't do andi./andis.  */
2265117395Skan    return gpc_reg_operand (op, mode) || mask64_2_operand (op, mode);
2266117395Skan
2267117395Skan  return logical_operand (op, mode) || mask64_2_operand (op, mode);
2268117395Skan}
2269117395Skan
227090075Sobrien/* Return 1 if the operand is either a non-special register or a
227190075Sobrien   constant that can be used as the operand of an RS/6000 logical AND insn.  */
227290075Sobrien
227390075Sobrienint
2274132718Skanand_operand (rtx op, enum machine_mode mode)
227590075Sobrien{
227690075Sobrien  if (fixed_regs[CR0_REGNO])	/* CR0 not available, don't do andi./andis.  */
227790075Sobrien    return (gpc_reg_operand (op, mode) || mask_operand (op, mode));
227890075Sobrien
227990075Sobrien  return (logical_operand (op, mode) || mask_operand (op, mode));
228090075Sobrien}
228190075Sobrien
228290075Sobrien/* Return 1 if the operand is a general register or memory operand.  */
228390075Sobrien
228490075Sobrienint
2285132718Skanreg_or_mem_operand (rtx op, enum machine_mode mode)
228690075Sobrien{
228790075Sobrien  return (gpc_reg_operand (op, mode)
228890075Sobrien	  || memory_operand (op, mode)
2289132718Skan	  || macho_lo_sum_memory_operand (op, mode)
229090075Sobrien	  || volatile_mem_operand (op, mode));
229190075Sobrien}
229290075Sobrien
229390075Sobrien/* Return 1 if the operand is a general register or memory operand without
229490075Sobrien   pre_inc or pre_dec which produces invalid form of PowerPC lwa
229590075Sobrien   instruction.  */
229690075Sobrien
229790075Sobrienint
2298132718Skanlwa_operand (rtx op, enum machine_mode mode)
229990075Sobrien{
230090075Sobrien  rtx inner = op;
230190075Sobrien
230290075Sobrien  if (reload_completed && GET_CODE (inner) == SUBREG)
230390075Sobrien    inner = SUBREG_REG (inner);
230490075Sobrien
230590075Sobrien  return gpc_reg_operand (inner, mode)
230690075Sobrien    || (memory_operand (inner, mode)
230790075Sobrien	&& GET_CODE (XEXP (inner, 0)) != PRE_INC
230890075Sobrien	&& GET_CODE (XEXP (inner, 0)) != PRE_DEC
230990075Sobrien	&& (GET_CODE (XEXP (inner, 0)) != PLUS
231090075Sobrien	    || GET_CODE (XEXP (XEXP (inner, 0), 1)) != CONST_INT
231190075Sobrien	    || INTVAL (XEXP (XEXP (inner, 0), 1)) % 4 == 0));
231290075Sobrien}
231390075Sobrien
2314117395Skan/* Return 1 if the operand, used inside a MEM, is a SYMBOL_REF.  */
2315117395Skan
2316117395Skanint
2317132718Skansymbol_ref_operand (rtx op, enum machine_mode mode)
2318117395Skan{
2319117395Skan  if (mode != VOIDmode && GET_MODE (op) != mode)
2320117395Skan    return 0;
2321117395Skan
2322132718Skan  return (GET_CODE (op) == SYMBOL_REF
2323132718Skan	  && (DEFAULT_ABI != ABI_AIX || SYMBOL_REF_FUNCTION_P (op)));
2324117395Skan}
2325117395Skan
232690075Sobrien/* Return 1 if the operand, used inside a MEM, is a valid first argument
2327117395Skan   to CALL.  This is a SYMBOL_REF, a pseudo-register, LR or CTR.  */
232890075Sobrien
232990075Sobrienint
2330132718Skancall_operand (rtx op, enum machine_mode mode)
233190075Sobrien{
233290075Sobrien  if (mode != VOIDmode && GET_MODE (op) != mode)
233390075Sobrien    return 0;
233490075Sobrien
233590075Sobrien  return (GET_CODE (op) == SYMBOL_REF
2336117395Skan	  || (GET_CODE (op) == REG
2337117395Skan	      && (REGNO (op) == LINK_REGISTER_REGNUM
2338117395Skan		  || REGNO (op) == COUNT_REGISTER_REGNUM
2339117395Skan		  || REGNO (op) >= FIRST_PSEUDO_REGISTER)));
234090075Sobrien}
234190075Sobrien
234290075Sobrien/* Return 1 if the operand is a SYMBOL_REF for a function known to be in
2343132718Skan   this file.  */
234490075Sobrien
234590075Sobrienint
2346132718Skancurrent_file_function_operand (rtx op,
2347132718Skan                              enum machine_mode mode ATTRIBUTE_UNUSED)
234890075Sobrien{
234990075Sobrien  return (GET_CODE (op) == SYMBOL_REF
2350132718Skan	  && (DEFAULT_ABI != ABI_AIX || SYMBOL_REF_FUNCTION_P (op))
2351132718Skan	  && (SYMBOL_REF_LOCAL_P (op)
2352132718Skan	      || (op == XEXP (DECL_RTL (current_function_decl), 0))));
235390075Sobrien}
235490075Sobrien
235590075Sobrien/* Return 1 if this operand is a valid input for a move insn.  */
235690075Sobrien
235790075Sobrienint
2358132718Skaninput_operand (rtx op, enum machine_mode mode)
235990075Sobrien{
236090075Sobrien  /* Memory is always valid.  */
236190075Sobrien  if (memory_operand (op, mode))
236290075Sobrien    return 1;
236390075Sobrien
236490075Sobrien  /* Only a tiny bit of handling for CONSTANT_P_RTX is necessary.  */
236590075Sobrien  if (GET_CODE (op) == CONSTANT_P_RTX)
236690075Sobrien    return 1;
236790075Sobrien
236890075Sobrien  /* For floating-point, easy constants are valid.  */
236990075Sobrien  if (GET_MODE_CLASS (mode) == MODE_FLOAT
237090075Sobrien      && CONSTANT_P (op)
237190075Sobrien      && easy_fp_constant (op, mode))
237290075Sobrien    return 1;
237390075Sobrien
237490075Sobrien  /* Allow any integer constant.  */
237590075Sobrien  if (GET_MODE_CLASS (mode) == MODE_INT
237690075Sobrien      && (GET_CODE (op) == CONST_INT
237790075Sobrien	  || GET_CODE (op) == CONST_DOUBLE))
237890075Sobrien    return 1;
237990075Sobrien
2380132718Skan  /* Allow easy vector constants.  */
2381132718Skan  if (GET_CODE (op) == CONST_VECTOR
2382132718Skan      && easy_vector_constant (op, mode))
2383132718Skan    return 1;
2384132718Skan
238590075Sobrien  /* For floating-point or multi-word mode, the only remaining valid type
238690075Sobrien     is a register.  */
238790075Sobrien  if (GET_MODE_CLASS (mode) == MODE_FLOAT
238890075Sobrien      || GET_MODE_SIZE (mode) > UNITS_PER_WORD)
238990075Sobrien    return register_operand (op, mode);
239090075Sobrien
239190075Sobrien  /* The only cases left are integral modes one word or smaller (we
239290075Sobrien     do not get called for MODE_CC values).  These can be in any
239390075Sobrien     register.  */
239490075Sobrien  if (register_operand (op, mode))
239590075Sobrien    return 1;
239690075Sobrien
239790075Sobrien  /* A SYMBOL_REF referring to the TOC is valid.  */
2398132718Skan  if (legitimate_constant_pool_address_p (op))
239990075Sobrien    return 1;
240090075Sobrien
240190075Sobrien  /* A constant pool expression (relative to the TOC) is valid */
2402132718Skan  if (toc_relative_expr_p (op))
240390075Sobrien    return 1;
240490075Sobrien
240590075Sobrien  /* V.4 allows SYMBOL_REFs and CONSTs that are in the small data region
240690075Sobrien     to be valid.  */
240790075Sobrien  if (DEFAULT_ABI == ABI_V4
240890075Sobrien      && (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == CONST)
240990075Sobrien      && small_data_operand (op, Pmode))
241090075Sobrien    return 1;
241190075Sobrien
241290075Sobrien  return 0;
241390075Sobrien}
241490075Sobrien
2415132718Skan
2416132718Skan/* Darwin, AIX increases natural record alignment to doubleword if the first
2417132718Skan   field is an FP double while the FP fields remain word aligned.  */
2418132718Skan
2419132718Skanunsigned int
2420132718Skanrs6000_special_round_type_align (tree type, int computed, int specified)
2421132718Skan{
2422132718Skan  tree field = TYPE_FIELDS (type);
2423132718Skan
2424132718Skan  /* Skip all the static variables only if ABI is greater than
2425132718Skan     1 or equal to 0.   */
2426132718Skan  while (field != NULL && TREE_CODE (field) == VAR_DECL)
2427132718Skan    field = TREE_CHAIN (field);
2428132718Skan
2429132718Skan  if (field == NULL || field == type || DECL_MODE (field) != DFmode)
2430132718Skan    return MAX (computed, specified);
2431132718Skan
2432132718Skan  return MAX (MAX (computed, specified), 64);
2433132718Skan}
2434132718Skan
243590075Sobrien/* Return 1 for an operand in small memory on V.4/eabi.  */
243690075Sobrien
243790075Sobrienint
2438132718Skansmall_data_operand (rtx op ATTRIBUTE_UNUSED,
2439132718Skan		    enum machine_mode mode ATTRIBUTE_UNUSED)
244090075Sobrien{
244190075Sobrien#if TARGET_ELF
244290075Sobrien  rtx sym_ref;
244390075Sobrien
244490075Sobrien  if (rs6000_sdata == SDATA_NONE || rs6000_sdata == SDATA_DATA)
244590075Sobrien    return 0;
244690075Sobrien
244790075Sobrien  if (DEFAULT_ABI != ABI_V4)
244890075Sobrien    return 0;
244990075Sobrien
245090075Sobrien  if (GET_CODE (op) == SYMBOL_REF)
245190075Sobrien    sym_ref = op;
245290075Sobrien
245390075Sobrien  else if (GET_CODE (op) != CONST
245490075Sobrien	   || GET_CODE (XEXP (op, 0)) != PLUS
245590075Sobrien	   || GET_CODE (XEXP (XEXP (op, 0), 0)) != SYMBOL_REF
245690075Sobrien	   || GET_CODE (XEXP (XEXP (op, 0), 1)) != CONST_INT)
245790075Sobrien    return 0;
245890075Sobrien
245990075Sobrien  else
246090075Sobrien    {
246190075Sobrien      rtx sum = XEXP (op, 0);
246290075Sobrien      HOST_WIDE_INT summand;
246390075Sobrien
246490075Sobrien      /* We have to be careful here, because it is the referenced address
246590075Sobrien        that must be 32k from _SDA_BASE_, not just the symbol.  */
246690075Sobrien      summand = INTVAL (XEXP (sum, 1));
2467132718Skan      if (summand < 0 || (unsigned HOST_WIDE_INT) summand > g_switch_value)
246890075Sobrien       return 0;
246990075Sobrien
247090075Sobrien      sym_ref = XEXP (sum, 0);
247190075Sobrien    }
247290075Sobrien
2473132718Skan  return SYMBOL_REF_SMALL_P (sym_ref);
247490075Sobrien#else
247590075Sobrien  return 0;
247690075Sobrien#endif
247790075Sobrien}
2478132718Skan
2479132718Skan/* Return true, if operand is a memory operand and has a
2480132718Skan   displacement divisible by 4.  */
2481132718Skan
2482132718Skanint
2483132718Skanword_offset_memref_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
2484132718Skan{
2485132718Skan  rtx addr;
2486132718Skan  int off = 0;
2487132718Skan
2488132718Skan  if (!memory_operand (op, mode))
2489132718Skan    return 0;
2490132718Skan
2491132718Skan  addr = XEXP (op, 0);
2492132718Skan  if (GET_CODE (addr) == PLUS
2493132718Skan      && GET_CODE (XEXP (addr, 0)) == REG
2494132718Skan      && GET_CODE (XEXP (addr, 1)) == CONST_INT)
2495132718Skan    off = INTVAL (XEXP (addr, 1));
2496132718Skan
2497132718Skan  return (off % 4) == 0;
2498132718Skan}
2499132718Skan
2500132718Skan/* Return true if either operand is a general purpose register.  */
2501132718Skan
2502132718Skanbool
2503132718Skangpr_or_gpr_p (rtx op0, rtx op1)
2504132718Skan{
2505132718Skan  return ((REG_P (op0) && INT_REGNO_P (REGNO (op0)))
2506132718Skan	  || (REG_P (op1) && INT_REGNO_P (REGNO (op1))));
2507132718Skan}
2508132718Skan
250990075Sobrien
2510132718Skan/* Subroutines of rs6000_legitimize_address and rs6000_legitimate_address.  */
2511132718Skan
251290075Sobrienstatic int
2513132718Skanconstant_pool_expr_1 (rtx op, int *have_sym, int *have_toc)
251490075Sobrien{
251590075Sobrien  switch (GET_CODE(op))
251690075Sobrien    {
251790075Sobrien    case SYMBOL_REF:
2518132718Skan      if (RS6000_SYMBOL_REF_TLS_P (op))
2519132718Skan	return 0;
2520132718Skan      else if (CONSTANT_POOL_ADDRESS_P (op))
252190075Sobrien	{
252290075Sobrien	  if (ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (op), Pmode))
252390075Sobrien	    {
252490075Sobrien	      *have_sym = 1;
252590075Sobrien	      return 1;
252690075Sobrien	    }
252790075Sobrien	  else
252890075Sobrien	    return 0;
252990075Sobrien	}
253090075Sobrien      else if (! strcmp (XSTR (op, 0), toc_label_name))
253190075Sobrien	{
253290075Sobrien	  *have_toc = 1;
253390075Sobrien	  return 1;
253490075Sobrien	}
253590075Sobrien      else
253690075Sobrien	return 0;
253790075Sobrien    case PLUS:
253890075Sobrien    case MINUS:
253996263Sobrien      return (constant_pool_expr_1 (XEXP (op, 0), have_sym, have_toc)
254096263Sobrien	      && constant_pool_expr_1 (XEXP (op, 1), have_sym, have_toc));
254190075Sobrien    case CONST:
254290075Sobrien      return constant_pool_expr_1 (XEXP (op, 0), have_sym, have_toc);
254390075Sobrien    case CONST_INT:
254490075Sobrien      return 1;
254590075Sobrien    default:
254690075Sobrien      return 0;
254790075Sobrien    }
254890075Sobrien}
254990075Sobrien
2550132718Skanstatic bool
2551132718Skanconstant_pool_expr_p (rtx op)
255290075Sobrien{
255390075Sobrien  int have_sym = 0;
255490075Sobrien  int have_toc = 0;
255590075Sobrien  return constant_pool_expr_1 (op, &have_sym, &have_toc) && have_sym;
255690075Sobrien}
255790075Sobrien
2558132718Skanstatic bool
2559132718Skantoc_relative_expr_p (rtx op)
256090075Sobrien{
2561132718Skan  int have_sym = 0;
2562132718Skan  int have_toc = 0;
2563132718Skan  return constant_pool_expr_1 (op, &have_sym, &have_toc) && have_toc;
256490075Sobrien}
256590075Sobrien
2566132718Skan/* SPE offset addressing is limited to 5-bits worth of double words.  */
2567132718Skan#define SPE_CONST_OFFSET_OK(x) (((x) & ~0xf8) == 0)
2568132718Skan
2569132718Skanbool
2570132718Skanlegitimate_constant_pool_address_p (rtx x)
2571132718Skan{
2572132718Skan  return (TARGET_TOC
2573132718Skan	  && GET_CODE (x) == PLUS
2574132718Skan	  && GET_CODE (XEXP (x, 0)) == REG
2575132718Skan	  && (TARGET_MINIMAL_TOC || REGNO (XEXP (x, 0)) == TOC_REGISTER)
2576132718Skan	  && constant_pool_expr_p (XEXP (x, 1)));
2577132718Skan}
2578132718Skan
2579132718Skanstatic bool
2580132718Skanlegitimate_small_data_p (enum machine_mode mode, rtx x)
2581132718Skan{
2582132718Skan  return (DEFAULT_ABI == ABI_V4
2583132718Skan	  && !flag_pic && !TARGET_TOC
2584132718Skan	  && (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == CONST)
2585132718Skan	  && small_data_operand (x, mode));
2586132718Skan}
2587132718Skan
2588132718Skanstatic bool
2589132718Skanlegitimate_offset_address_p (enum machine_mode mode, rtx x, int strict)
2590132718Skan{
2591132718Skan  unsigned HOST_WIDE_INT offset, extra;
2592132718Skan
2593132718Skan  if (GET_CODE (x) != PLUS)
2594132718Skan    return false;
2595132718Skan  if (GET_CODE (XEXP (x, 0)) != REG)
2596132718Skan    return false;
2597132718Skan  if (!INT_REG_OK_FOR_BASE_P (XEXP (x, 0), strict))
2598132718Skan    return false;
2599132718Skan  if (GET_CODE (XEXP (x, 1)) != CONST_INT)
2600132718Skan    return false;
2601132718Skan
2602132718Skan  offset = INTVAL (XEXP (x, 1));
2603132718Skan  extra = 0;
2604132718Skan  switch (mode)
2605132718Skan    {
2606132718Skan    case V16QImode:
2607132718Skan    case V8HImode:
2608132718Skan    case V4SFmode:
2609132718Skan    case V4SImode:
2610132718Skan      /* AltiVec vector modes.  Only reg+reg addressing is valid here,
2611132718Skan	 which leaves the only valid constant offset of zero, which by
2612132718Skan	 canonicalization rules is also invalid.  */
2613132718Skan      return false;
2614132718Skan
2615132718Skan    case V4HImode:
2616132718Skan    case V2SImode:
2617132718Skan    case V1DImode:
2618132718Skan    case V2SFmode:
2619132718Skan      /* SPE vector modes.  */
2620132718Skan      return SPE_CONST_OFFSET_OK (offset);
2621132718Skan
2622132718Skan    case DFmode:
2623132718Skan    case DImode:
2624161651Skan      if (mode == DFmode || !TARGET_POWERPC64)
2625132718Skan	extra = 4;
2626161651Skan      else if (offset & 3)
2627161651Skan	return false;
2628132718Skan      break;
2629132718Skan
2630132718Skan    case TFmode:
2631132718Skan    case TImode:
2632161651Skan      if (mode == TFmode || !TARGET_POWERPC64)
2633132718Skan	extra = 12;
2634161651Skan      else if (offset & 3)
2635161651Skan	return false;
2636132718Skan      else
2637132718Skan	extra = 8;
2638132718Skan      break;
2639132718Skan
2640132718Skan    default:
2641132718Skan      break;
2642132718Skan    }
2643132718Skan
2644132718Skan  offset += 0x8000;
2645132718Skan  return (offset < 0x10000) && (offset + extra < 0x10000);
2646132718Skan}
2647132718Skan
2648132718Skanstatic bool
2649132718Skanlegitimate_indexed_address_p (rtx x, int strict)
2650132718Skan{
2651132718Skan  rtx op0, op1;
2652132718Skan
2653132718Skan  if (GET_CODE (x) != PLUS)
2654132718Skan    return false;
2655132718Skan  op0 = XEXP (x, 0);
2656132718Skan  op1 = XEXP (x, 1);
2657132718Skan
2658132718Skan  if (!REG_P (op0) || !REG_P (op1))
2659132718Skan    return false;
2660132718Skan
2661132718Skan  return ((INT_REG_OK_FOR_BASE_P (op0, strict)
2662132718Skan	   && INT_REG_OK_FOR_INDEX_P (op1, strict))
2663132718Skan	  || (INT_REG_OK_FOR_BASE_P (op1, strict)
2664132718Skan	      && INT_REG_OK_FOR_INDEX_P (op0, strict)));
2665132718Skan}
2666132718Skan
2667132718Skanstatic inline bool
2668132718Skanlegitimate_indirect_address_p (rtx x, int strict)
2669132718Skan{
2670132718Skan  return GET_CODE (x) == REG && INT_REG_OK_FOR_BASE_P (x, strict);
2671132718Skan}
2672132718Skan
2673132718Skanstatic bool
2674132718Skanmacho_lo_sum_memory_operand (rtx x, enum machine_mode mode)
2675132718Skan{
2676132718Skan    if (!TARGET_MACHO || !flag_pic
2677132718Skan        || mode != SImode || GET_CODE(x) != MEM)
2678132718Skan      return false;
2679132718Skan    x = XEXP (x, 0);
2680132718Skan
2681132718Skan  if (GET_CODE (x) != LO_SUM)
2682132718Skan    return false;
2683132718Skan  if (GET_CODE (XEXP (x, 0)) != REG)
2684132718Skan    return false;
2685132718Skan  if (!INT_REG_OK_FOR_BASE_P (XEXP (x, 0), 0))
2686132718Skan    return false;
2687132718Skan  x = XEXP (x, 1);
2688132718Skan
2689132718Skan  return CONSTANT_P (x);
2690132718Skan}
2691132718Skan
2692132718Skanstatic bool
2693132718Skanlegitimate_lo_sum_address_p (enum machine_mode mode, rtx x, int strict)
2694132718Skan{
2695132718Skan  if (GET_CODE (x) != LO_SUM)
2696132718Skan    return false;
2697132718Skan  if (GET_CODE (XEXP (x, 0)) != REG)
2698132718Skan    return false;
2699132718Skan  if (!INT_REG_OK_FOR_BASE_P (XEXP (x, 0), strict))
2700132718Skan    return false;
2701132718Skan  x = XEXP (x, 1);
2702132718Skan
2703132718Skan  if (TARGET_ELF || TARGET_MACHO)
2704132718Skan    {
2705132718Skan      if (DEFAULT_ABI != ABI_AIX && DEFAULT_ABI != ABI_DARWIN && flag_pic)
2706132718Skan	return false;
2707132718Skan      if (TARGET_TOC)
2708132718Skan	return false;
2709132718Skan      if (GET_MODE_NUNITS (mode) != 1)
2710132718Skan	return false;
2711132718Skan      if (GET_MODE_BITSIZE (mode) > 32
2712132718Skan	  && !(TARGET_HARD_FLOAT && TARGET_FPRS && mode == DFmode))
2713132718Skan	return false;
2714132718Skan
2715132718Skan      return CONSTANT_P (x);
2716132718Skan    }
2717132718Skan
2718132718Skan  return false;
2719132718Skan}
2720132718Skan
2721132718Skan
272290075Sobrien/* Try machine-dependent ways of modifying an illegitimate address
272390075Sobrien   to be legitimate.  If we find one, return the new, valid address.
272490075Sobrien   This is used from only one place: `memory_address' in explow.c.
272590075Sobrien
272690075Sobrien   OLDX is the address as it was before break_out_memory_refs was
272790075Sobrien   called.  In some cases it is useful to look at this to decide what
272890075Sobrien   needs to be done.
272990075Sobrien
273090075Sobrien   MODE is passed so that this function can use GO_IF_LEGITIMATE_ADDRESS.
273190075Sobrien
273290075Sobrien   It is always safe for this function to do nothing.  It exists to
273390075Sobrien   recognize opportunities to optimize the output.
273490075Sobrien
273590075Sobrien   On RS/6000, first check for the sum of a register with a constant
273690075Sobrien   integer that is out of range.  If so, generate code to add the
273790075Sobrien   constant with the low-order 16 bits masked to the register and force
273890075Sobrien   this result into another register (this can be done with `cau').
273990075Sobrien   Then generate an address of REG+(CONST&0xffff), allowing for the
274090075Sobrien   possibility of bit 16 being a one.
274190075Sobrien
274290075Sobrien   Then check for the sum of a register and something not constant, try to
274390075Sobrien   load the other things into a register and return the sum.  */
2744132718Skan
274590075Sobrienrtx
2746132718Skanrs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
2747132718Skan			   enum machine_mode mode)
274890075Sobrien{
2749132718Skan  if (GET_CODE (x) == SYMBOL_REF)
2750132718Skan    {
2751132718Skan      enum tls_model model = SYMBOL_REF_TLS_MODEL (x);
2752132718Skan      if (model != 0)
2753132718Skan	return rs6000_legitimize_tls_address (x, model);
2754132718Skan    }
2755132718Skan
275690075Sobrien  if (GET_CODE (x) == PLUS
275790075Sobrien      && GET_CODE (XEXP (x, 0)) == REG
275890075Sobrien      && GET_CODE (XEXP (x, 1)) == CONST_INT
275990075Sobrien      && (unsigned HOST_WIDE_INT) (INTVAL (XEXP (x, 1)) + 0x8000) >= 0x10000)
276090075Sobrien    {
276190075Sobrien      HOST_WIDE_INT high_int, low_int;
276290075Sobrien      rtx sum;
2763117395Skan      low_int = ((INTVAL (XEXP (x, 1)) & 0xffff) ^ 0x8000) - 0x8000;
2764117395Skan      high_int = INTVAL (XEXP (x, 1)) - low_int;
276590075Sobrien      sum = force_operand (gen_rtx_PLUS (Pmode, XEXP (x, 0),
276690075Sobrien					 GEN_INT (high_int)), 0);
276790075Sobrien      return gen_rtx_PLUS (Pmode, sum, GEN_INT (low_int));
276890075Sobrien    }
276990075Sobrien  else if (GET_CODE (x) == PLUS
277090075Sobrien	   && GET_CODE (XEXP (x, 0)) == REG
277190075Sobrien	   && GET_CODE (XEXP (x, 1)) != CONST_INT
277290075Sobrien	   && GET_MODE_NUNITS (mode) == 1
2773117395Skan	   && ((TARGET_HARD_FLOAT && TARGET_FPRS)
2774117395Skan	       || TARGET_POWERPC64
2775117395Skan	       || (mode != DFmode && mode != TFmode))
277690075Sobrien	   && (TARGET_POWERPC64 || mode != DImode)
277790075Sobrien	   && mode != TImode)
277890075Sobrien    {
277990075Sobrien      return gen_rtx_PLUS (Pmode, XEXP (x, 0),
278090075Sobrien			   force_reg (Pmode, force_operand (XEXP (x, 1), 0)));
278190075Sobrien    }
278290075Sobrien  else if (ALTIVEC_VECTOR_MODE (mode))
278390075Sobrien    {
278490075Sobrien      rtx reg;
278590075Sobrien
278690075Sobrien      /* Make sure both operands are registers.  */
278790075Sobrien      if (GET_CODE (x) == PLUS)
278890075Sobrien	return gen_rtx_PLUS (Pmode, force_reg (Pmode, XEXP (x, 0)),
278990075Sobrien			     force_reg (Pmode, XEXP (x, 1)));
279090075Sobrien
279190075Sobrien      reg = force_reg (Pmode, x);
279290075Sobrien      return reg;
279390075Sobrien    }
2794117395Skan  else if (SPE_VECTOR_MODE (mode))
2795117395Skan    {
2796117395Skan      /* We accept [reg + reg] and [reg + OFFSET].  */
2797117395Skan
2798117395Skan      if (GET_CODE (x) == PLUS)
2799117395Skan      {
2800117395Skan        rtx op1 = XEXP (x, 0);
2801117395Skan        rtx op2 = XEXP (x, 1);
2802117395Skan
2803117395Skan        op1 = force_reg (Pmode, op1);
2804117395Skan
2805117395Skan        if (GET_CODE (op2) != REG
2806117395Skan            && (GET_CODE (op2) != CONST_INT
2807117395Skan                || !SPE_CONST_OFFSET_OK (INTVAL (op2))))
2808117395Skan          op2 = force_reg (Pmode, op2);
2809117395Skan
2810117395Skan        return gen_rtx_PLUS (Pmode, op1, op2);
2811117395Skan      }
2812117395Skan
2813117395Skan      return force_reg (Pmode, x);
2814117395Skan    }
2815132718Skan  else if (TARGET_ELF
2816132718Skan	   && TARGET_32BIT
2817132718Skan	   && TARGET_NO_TOC
2818132718Skan	   && ! flag_pic
281990075Sobrien	   && GET_CODE (x) != CONST_INT
282090075Sobrien	   && GET_CODE (x) != CONST_DOUBLE
282190075Sobrien	   && CONSTANT_P (x)
282290075Sobrien	   && GET_MODE_NUNITS (mode) == 1
282390075Sobrien	   && (GET_MODE_BITSIZE (mode) <= 32
2824117395Skan	       || ((TARGET_HARD_FLOAT && TARGET_FPRS) && mode == DFmode)))
282590075Sobrien    {
282690075Sobrien      rtx reg = gen_reg_rtx (Pmode);
2827132718Skan      emit_insn (gen_elf_high (reg, x));
2828132718Skan      return gen_rtx_LO_SUM (Pmode, reg, x);
282990075Sobrien    }
283090075Sobrien  else if (TARGET_MACHO && TARGET_32BIT && TARGET_NO_TOC
283190075Sobrien	   && ! flag_pic
2832132718Skan#if TARGET_MACHO
2833132718Skan	   && ! MACHO_DYNAMIC_NO_PIC_P
2834132718Skan#endif
283590075Sobrien	   && GET_CODE (x) != CONST_INT
283690075Sobrien	   && GET_CODE (x) != CONST_DOUBLE
283790075Sobrien	   && CONSTANT_P (x)
2838117395Skan	   && ((TARGET_HARD_FLOAT && TARGET_FPRS) || mode != DFmode)
283990075Sobrien	   && mode != DImode
284090075Sobrien	   && mode != TImode)
284190075Sobrien    {
284290075Sobrien      rtx reg = gen_reg_rtx (Pmode);
2843132718Skan      emit_insn (gen_macho_high (reg, x));
2844132718Skan      return gen_rtx_LO_SUM (Pmode, reg, x);
284590075Sobrien    }
284690075Sobrien  else if (TARGET_TOC
2847132718Skan	   && constant_pool_expr_p (x)
284890075Sobrien	   && ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (x), Pmode))
284990075Sobrien    {
285090075Sobrien      return create_TOC_reference (x);
285190075Sobrien    }
285290075Sobrien  else
285390075Sobrien    return NULL_RTX;
285490075Sobrien}
285590075Sobrien
2856132718Skan/* This is called from dwarf2out.c via ASM_OUTPUT_DWARF_DTPREL.
2857132718Skan   We need to emit DTP-relative relocations.  */
2858132718Skan
2859132718Skanvoid
2860132718Skanrs6000_output_dwarf_dtprel (FILE *file, int size, rtx x)
2861132718Skan{
2862132718Skan  switch (size)
2863132718Skan    {
2864132718Skan    case 4:
2865132718Skan      fputs ("\t.long\t", file);
2866132718Skan      break;
2867132718Skan    case 8:
2868132718Skan      fputs (DOUBLE_INT_ASM_OP, file);
2869132718Skan      break;
2870132718Skan    default:
2871132718Skan      abort ();
2872132718Skan    }
2873132718Skan  output_addr_const (file, x);
2874132718Skan  fputs ("@dtprel+0x8000", file);
2875132718Skan}
2876132718Skan
2877132718Skan/* Construct the SYMBOL_REF for the tls_get_addr function.  */
2878132718Skan
2879132718Skanstatic GTY(()) rtx rs6000_tls_symbol;
2880132718Skanstatic rtx
2881132718Skanrs6000_tls_get_addr (void)
2882132718Skan{
2883132718Skan  if (!rs6000_tls_symbol)
2884132718Skan    rs6000_tls_symbol = init_one_libfunc ("__tls_get_addr");
2885132718Skan
2886132718Skan  return rs6000_tls_symbol;
2887132718Skan}
2888132718Skan
2889132718Skan/* Construct the SYMBOL_REF for TLS GOT references.  */
2890132718Skan
2891132718Skanstatic GTY(()) rtx rs6000_got_symbol;
2892132718Skanstatic rtx
2893132718Skanrs6000_got_sym (void)
2894132718Skan{
2895132718Skan  if (!rs6000_got_symbol)
2896132718Skan    {
2897132718Skan      rs6000_got_symbol = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
2898132718Skan      SYMBOL_REF_FLAGS (rs6000_got_symbol) |= SYMBOL_FLAG_LOCAL;
2899132718Skan      SYMBOL_REF_FLAGS (rs6000_got_symbol) |= SYMBOL_FLAG_EXTERNAL;
2900132718Skan    }
2901132718Skan
2902132718Skan  return rs6000_got_symbol;
2903132718Skan}
2904132718Skan
2905132718Skan/* ADDR contains a thread-local SYMBOL_REF.  Generate code to compute
2906132718Skan   this (thread-local) address.  */
2907132718Skan
2908132718Skanstatic rtx
2909132718Skanrs6000_legitimize_tls_address (rtx addr, enum tls_model model)
2910132718Skan{
2911132718Skan  rtx dest, insn;
2912132718Skan
2913132718Skan  dest = gen_reg_rtx (Pmode);
2914132718Skan  if (model == TLS_MODEL_LOCAL_EXEC && rs6000_tls_size == 16)
2915132718Skan    {
2916132718Skan      rtx tlsreg;
2917132718Skan
2918132718Skan      if (TARGET_64BIT)
2919132718Skan	{
2920132718Skan	  tlsreg = gen_rtx_REG (Pmode, 13);
2921132718Skan	  insn = gen_tls_tprel_64 (dest, tlsreg, addr);
2922132718Skan	}
2923132718Skan      else
2924132718Skan	{
2925132718Skan	  tlsreg = gen_rtx_REG (Pmode, 2);
2926132718Skan	  insn = gen_tls_tprel_32 (dest, tlsreg, addr);
2927132718Skan	}
2928132718Skan      emit_insn (insn);
2929132718Skan    }
2930132718Skan  else if (model == TLS_MODEL_LOCAL_EXEC && rs6000_tls_size == 32)
2931132718Skan    {
2932132718Skan      rtx tlsreg, tmp;
2933132718Skan
2934132718Skan      tmp = gen_reg_rtx (Pmode);
2935132718Skan      if (TARGET_64BIT)
2936132718Skan	{
2937132718Skan	  tlsreg = gen_rtx_REG (Pmode, 13);
2938132718Skan	  insn = gen_tls_tprel_ha_64 (tmp, tlsreg, addr);
2939132718Skan	}
2940132718Skan      else
2941132718Skan	{
2942132718Skan	  tlsreg = gen_rtx_REG (Pmode, 2);
2943132718Skan	  insn = gen_tls_tprel_ha_32 (tmp, tlsreg, addr);
2944132718Skan	}
2945132718Skan      emit_insn (insn);
2946132718Skan      if (TARGET_64BIT)
2947132718Skan	insn = gen_tls_tprel_lo_64 (dest, tmp, addr);
2948132718Skan      else
2949132718Skan	insn = gen_tls_tprel_lo_32 (dest, tmp, addr);
2950132718Skan      emit_insn (insn);
2951132718Skan    }
2952132718Skan  else
2953132718Skan    {
2954132718Skan      rtx r3, got, tga, tmp1, tmp2, eqv;
2955132718Skan
2956132718Skan      if (TARGET_64BIT)
2957161651Skan	got = gen_rtx_REG (Pmode, 2);
2958132718Skan      else
2959132718Skan	{
2960132718Skan	  if (flag_pic == 1)
2961132718Skan	    got = gen_rtx_REG (Pmode, RS6000_PIC_OFFSET_TABLE_REGNUM);
2962132718Skan	  else
2963132718Skan	    {
2964132718Skan	      rtx gsym = rs6000_got_sym ();
2965132718Skan	      got = gen_reg_rtx (Pmode);
2966132718Skan	      if (flag_pic == 0)
2967132718Skan		rs6000_emit_move (got, gsym, Pmode);
2968132718Skan	      else
2969132718Skan		{
2970146895Skan		  rtx tempLR, tmp3, mem;
2971132718Skan		  rtx first, last;
2972132718Skan
2973132718Skan		  tempLR = gen_reg_rtx (Pmode);
2974132718Skan		  tmp1 = gen_reg_rtx (Pmode);
2975132718Skan		  tmp2 = gen_reg_rtx (Pmode);
2976132718Skan		  tmp3 = gen_reg_rtx (Pmode);
2977132718Skan		  mem = gen_rtx_MEM (Pmode, tmp1);
2978132718Skan		  RTX_UNCHANGING_P (mem) = 1;
2979132718Skan
2980146895Skan		  first = emit_insn (gen_load_toc_v4_PIC_1b (tempLR, gsym));
2981132718Skan		  emit_move_insn (tmp1, tempLR);
2982132718Skan		  emit_move_insn (tmp2, mem);
2983132718Skan		  emit_insn (gen_addsi3 (tmp3, tmp1, tmp2));
2984132718Skan		  last = emit_move_insn (got, tmp3);
2985132718Skan		  REG_NOTES (last) = gen_rtx_EXPR_LIST (REG_EQUAL, gsym,
2986132718Skan							REG_NOTES (last));
2987132718Skan		  REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last,
2988132718Skan							 REG_NOTES (first));
2989132718Skan		  REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first,
2990132718Skan							REG_NOTES (last));
2991132718Skan		}
2992132718Skan	    }
2993132718Skan	}
2994132718Skan
2995132718Skan      if (model == TLS_MODEL_GLOBAL_DYNAMIC)
2996132718Skan	{
2997132718Skan	  r3 = gen_rtx_REG (Pmode, 3);
2998132718Skan	  if (TARGET_64BIT)
2999132718Skan	    insn = gen_tls_gd_64 (r3, got, addr);
3000132718Skan	  else
3001132718Skan	    insn = gen_tls_gd_32 (r3, got, addr);
3002132718Skan	  start_sequence ();
3003132718Skan	  emit_insn (insn);
3004132718Skan	  tga = gen_rtx_MEM (Pmode, rs6000_tls_get_addr ());
3005132718Skan	  insn = gen_call_value (r3, tga, const0_rtx, const0_rtx);
3006132718Skan	  insn = emit_call_insn (insn);
3007132718Skan	  CONST_OR_PURE_CALL_P (insn) = 1;
3008132718Skan	  use_reg (&CALL_INSN_FUNCTION_USAGE (insn), r3);
3009132718Skan	  insn = get_insns ();
3010132718Skan	  end_sequence ();
3011132718Skan	  emit_libcall_block (insn, dest, r3, addr);
3012132718Skan	}
3013132718Skan      else if (model == TLS_MODEL_LOCAL_DYNAMIC)
3014132718Skan	{
3015132718Skan	  r3 = gen_rtx_REG (Pmode, 3);
3016132718Skan	  if (TARGET_64BIT)
3017132718Skan	    insn = gen_tls_ld_64 (r3, got);
3018132718Skan	  else
3019132718Skan	    insn = gen_tls_ld_32 (r3, got);
3020132718Skan	  start_sequence ();
3021132718Skan	  emit_insn (insn);
3022132718Skan	  tga = gen_rtx_MEM (Pmode, rs6000_tls_get_addr ());
3023132718Skan	  insn = gen_call_value (r3, tga, const0_rtx, const0_rtx);
3024132718Skan	  insn = emit_call_insn (insn);
3025132718Skan	  CONST_OR_PURE_CALL_P (insn) = 1;
3026132718Skan	  use_reg (&CALL_INSN_FUNCTION_USAGE (insn), r3);
3027132718Skan	  insn = get_insns ();
3028132718Skan	  end_sequence ();
3029132718Skan	  tmp1 = gen_reg_rtx (Pmode);
3030132718Skan	  eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx),
3031132718Skan				UNSPEC_TLSLD);
3032132718Skan	  emit_libcall_block (insn, tmp1, r3, eqv);
3033132718Skan	  if (rs6000_tls_size == 16)
3034132718Skan	    {
3035132718Skan	      if (TARGET_64BIT)
3036132718Skan		insn = gen_tls_dtprel_64 (dest, tmp1, addr);
3037132718Skan	      else
3038132718Skan		insn = gen_tls_dtprel_32 (dest, tmp1, addr);
3039132718Skan	    }
3040132718Skan	  else if (rs6000_tls_size == 32)
3041132718Skan	    {
3042132718Skan	      tmp2 = gen_reg_rtx (Pmode);
3043132718Skan	      if (TARGET_64BIT)
3044132718Skan		insn = gen_tls_dtprel_ha_64 (tmp2, tmp1, addr);
3045132718Skan	      else
3046132718Skan		insn = gen_tls_dtprel_ha_32 (tmp2, tmp1, addr);
3047132718Skan	      emit_insn (insn);
3048132718Skan	      if (TARGET_64BIT)
3049132718Skan		insn = gen_tls_dtprel_lo_64 (dest, tmp2, addr);
3050132718Skan	      else
3051132718Skan		insn = gen_tls_dtprel_lo_32 (dest, tmp2, addr);
3052132718Skan	    }
3053132718Skan	  else
3054132718Skan	    {
3055132718Skan	      tmp2 = gen_reg_rtx (Pmode);
3056132718Skan	      if (TARGET_64BIT)
3057132718Skan		insn = gen_tls_got_dtprel_64 (tmp2, got, addr);
3058132718Skan	      else
3059132718Skan		insn = gen_tls_got_dtprel_32 (tmp2, got, addr);
3060132718Skan	      emit_insn (insn);
3061132718Skan	      insn = gen_rtx_SET (Pmode, dest,
3062132718Skan				  gen_rtx_PLUS (Pmode, tmp2, tmp1));
3063132718Skan	    }
3064132718Skan	  emit_insn (insn);
3065132718Skan	}
3066132718Skan      else
3067132718Skan	{
3068132718Skan	  /* IE, or 64 bit offset LE.  */
3069132718Skan	  tmp2 = gen_reg_rtx (Pmode);
3070132718Skan	  if (TARGET_64BIT)
3071132718Skan	    insn = gen_tls_got_tprel_64 (tmp2, got, addr);
3072132718Skan	  else
3073132718Skan	    insn = gen_tls_got_tprel_32 (tmp2, got, addr);
3074132718Skan	  emit_insn (insn);
3075132718Skan	  if (TARGET_64BIT)
3076132718Skan	    insn = gen_tls_tls_64 (dest, tmp2, addr);
3077132718Skan	  else
3078132718Skan	    insn = gen_tls_tls_32 (dest, tmp2, addr);
3079132718Skan	  emit_insn (insn);
3080132718Skan	}
3081132718Skan    }
3082132718Skan
3083132718Skan  return dest;
3084132718Skan}
3085132718Skan
3086132718Skan/* Return 1 if X is a SYMBOL_REF for a TLS symbol.  This is used in
3087132718Skan   instruction definitions.  */
3088132718Skan
3089132718Skanint
3090132718Skanrs6000_tls_symbol_ref (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
3091132718Skan{
3092132718Skan  return RS6000_SYMBOL_REF_TLS_P (x);
3093132718Skan}
3094132718Skan
3095132718Skan/* Return 1 if X contains a thread-local symbol.  */
3096132718Skan
3097132718Skanbool
3098132718Skanrs6000_tls_referenced_p (rtx x)
3099132718Skan{
3100132718Skan  if (! TARGET_HAVE_TLS)
3101132718Skan    return false;
3102132718Skan
3103132718Skan  return for_each_rtx (&x, &rs6000_tls_symbol_ref_1, 0);
3104132718Skan}
3105132718Skan
3106132718Skan/* Return 1 if *X is a thread-local symbol.  This is the same as
3107132718Skan   rs6000_tls_symbol_ref except for the type of the unused argument.  */
3108132718Skan
3109132718Skanstatic inline int
3110132718Skanrs6000_tls_symbol_ref_1 (rtx *x, void *data ATTRIBUTE_UNUSED)
3111132718Skan{
3112132718Skan  return RS6000_SYMBOL_REF_TLS_P (*x);
3113132718Skan}
3114132718Skan
311590075Sobrien/* The convention appears to be to define this wherever it is used.
311690075Sobrien   With legitimize_reload_address now defined here, REG_MODE_OK_FOR_BASE_P
311790075Sobrien   is now used here.  */
311890075Sobrien#ifndef REG_MODE_OK_FOR_BASE_P
311990075Sobrien#define REG_MODE_OK_FOR_BASE_P(REGNO, MODE) REG_OK_FOR_BASE_P (REGNO)
312090075Sobrien#endif
312190075Sobrien
312290075Sobrien/* Our implementation of LEGITIMIZE_RELOAD_ADDRESS.  Returns a value to
312390075Sobrien   replace the input X, or the original X if no replacement is called for.
312490075Sobrien   The output parameter *WIN is 1 if the calling macro should goto WIN,
312590075Sobrien   0 if it should not.
312690075Sobrien
312790075Sobrien   For RS/6000, we wish to handle large displacements off a base
312890075Sobrien   register by splitting the addend across an addiu/addis and the mem insn.
312990075Sobrien   This cuts number of extra insns needed from 3 to 1.
313090075Sobrien
313190075Sobrien   On Darwin, we use this to generate code for floating point constants.
313290075Sobrien   A movsf_low is generated so we wind up with 2 instructions rather than 3.
313390075Sobrien   The Darwin code is inside #if TARGET_MACHO because only then is
313490075Sobrien   machopic_function_base_name() defined.  */
313590075Sobrienrtx
3136132718Skanrs6000_legitimize_reload_address (rtx x, enum machine_mode mode,
3137132718Skan	int opnum, int type, int ind_levels ATTRIBUTE_UNUSED, int *win)
313890075Sobrien{
313990075Sobrien  /* We must recognize output that we have already generated ourselves.  */
314090075Sobrien  if (GET_CODE (x) == PLUS
314190075Sobrien      && GET_CODE (XEXP (x, 0)) == PLUS
314290075Sobrien      && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG
314390075Sobrien      && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
314490075Sobrien      && GET_CODE (XEXP (x, 1)) == CONST_INT)
314590075Sobrien    {
314690075Sobrien      push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
314790075Sobrien                   BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0,
314890075Sobrien                   opnum, (enum reload_type)type);
314990075Sobrien      *win = 1;
315090075Sobrien      return x;
315190075Sobrien    }
315296263Sobrien
315390075Sobrien#if TARGET_MACHO
315490075Sobrien  if (DEFAULT_ABI == ABI_DARWIN && flag_pic
315590075Sobrien      && GET_CODE (x) == LO_SUM
315690075Sobrien      && GET_CODE (XEXP (x, 0)) == PLUS
315790075Sobrien      && XEXP (XEXP (x, 0), 0) == pic_offset_table_rtx
315890075Sobrien      && GET_CODE (XEXP (XEXP (x, 0), 1)) == HIGH
315990075Sobrien      && GET_CODE (XEXP (XEXP (XEXP (x, 0), 1), 0)) == CONST
316090075Sobrien      && XEXP (XEXP (XEXP (x, 0), 1), 0) == XEXP (x, 1)
316190075Sobrien      && GET_CODE (XEXP (XEXP (x, 1), 0)) == MINUS
316290075Sobrien      && GET_CODE (XEXP (XEXP (XEXP (x, 1), 0), 0)) == SYMBOL_REF
316390075Sobrien      && GET_CODE (XEXP (XEXP (XEXP (x, 1), 0), 1)) == SYMBOL_REF)
316490075Sobrien    {
316590075Sobrien      /* Result of previous invocation of this function on Darwin
316690075Sobrien	 floating point constant.  */
316790075Sobrien      push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
316890075Sobrien		BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
316990075Sobrien		opnum, (enum reload_type)type);
317090075Sobrien      *win = 1;
317190075Sobrien      return x;
317290075Sobrien    }
317390075Sobrien#endif
3174161651Skan
3175161651Skan  /* Force ld/std non-word aligned offset into base register by wrapping
3176161651Skan     in offset 0.  */
317790075Sobrien  if (GET_CODE (x) == PLUS
317890075Sobrien      && GET_CODE (XEXP (x, 0)) == REG
3179161651Skan      && REGNO (XEXP (x, 0)) < 32
3180161651Skan      && REG_MODE_OK_FOR_BASE_P (XEXP (x, 0), mode)
3181161651Skan      && GET_CODE (XEXP (x, 1)) == CONST_INT
3182161651Skan      && (INTVAL (XEXP (x, 1)) & 3) != 0
3183161651Skan      && GET_MODE_SIZE (mode) >= UNITS_PER_WORD
3184161651Skan      && TARGET_POWERPC64)
3185161651Skan    {
3186161651Skan      x = gen_rtx_PLUS (GET_MODE (x), x, GEN_INT (0));
3187161651Skan      push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
3188161651Skan		   BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0,
3189161651Skan		   opnum, (enum reload_type) type);
3190161651Skan      *win = 1;
3191161651Skan      return x;
3192161651Skan    }
3193161651Skan
3194161651Skan  if (GET_CODE (x) == PLUS
3195161651Skan      && GET_CODE (XEXP (x, 0)) == REG
319690075Sobrien      && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER
319790075Sobrien      && REG_MODE_OK_FOR_BASE_P (XEXP (x, 0), mode)
319896263Sobrien      && GET_CODE (XEXP (x, 1)) == CONST_INT
3199117395Skan      && !SPE_VECTOR_MODE (mode)
320096263Sobrien      && !ALTIVEC_VECTOR_MODE (mode))
320190075Sobrien    {
320290075Sobrien      HOST_WIDE_INT val = INTVAL (XEXP (x, 1));
320390075Sobrien      HOST_WIDE_INT low = ((val & 0xffff) ^ 0x8000) - 0x8000;
320490075Sobrien      HOST_WIDE_INT high
320590075Sobrien        = (((val - low) & 0xffffffff) ^ 0x80000000) - 0x80000000;
320690075Sobrien
320790075Sobrien      /* Check for 32-bit overflow.  */
320890075Sobrien      if (high + low != val)
320990075Sobrien        {
321090075Sobrien	  *win = 0;
321190075Sobrien	  return x;
321290075Sobrien	}
321390075Sobrien
321490075Sobrien      /* Reload the high part into a base reg; leave the low part
321590075Sobrien         in the mem directly.  */
321690075Sobrien
321790075Sobrien      x = gen_rtx_PLUS (GET_MODE (x),
321890075Sobrien                        gen_rtx_PLUS (GET_MODE (x), XEXP (x, 0),
321990075Sobrien                                      GEN_INT (high)),
322090075Sobrien                        GEN_INT (low));
322190075Sobrien
322290075Sobrien      push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
322390075Sobrien                   BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0,
322490075Sobrien                   opnum, (enum reload_type)type);
322590075Sobrien      *win = 1;
322690075Sobrien      return x;
322790075Sobrien    }
3228161651Skan
322990075Sobrien#if TARGET_MACHO
323090075Sobrien  if (GET_CODE (x) == SYMBOL_REF
323190075Sobrien      && DEFAULT_ABI == ABI_DARWIN
323296263Sobrien      && !ALTIVEC_VECTOR_MODE (mode)
3233132718Skan      && (flag_pic || MACHO_DYNAMIC_NO_PIC_P)
3234132718Skan      /* Don't do this for TFmode, since the result isn't offsettable.  */
3235132718Skan      && mode != TFmode)
323690075Sobrien    {
3237132718Skan      if (flag_pic)
3238132718Skan	{
3239132718Skan	  rtx offset = gen_rtx_CONST (Pmode,
3240132718Skan			 gen_rtx_MINUS (Pmode, x,
3241132718Skan			   gen_rtx_SYMBOL_REF (Pmode,
3242132718Skan			     machopic_function_base_name ())));
3243132718Skan	  x = gen_rtx_LO_SUM (GET_MODE (x),
3244132718Skan		gen_rtx_PLUS (Pmode, pic_offset_table_rtx,
3245132718Skan		  gen_rtx_HIGH (Pmode, offset)), offset);
3246132718Skan	}
3247132718Skan      else
3248132718Skan	x = gen_rtx_LO_SUM (GET_MODE (x),
3249132718Skan              gen_rtx_HIGH (Pmode, x), x);
3250132718Skan
325190075Sobrien      push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
3252132718Skan		   BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
3253132718Skan		   opnum, (enum reload_type)type);
325490075Sobrien      *win = 1;
325590075Sobrien      return x;
325690075Sobrien    }
325790075Sobrien#endif
3258161651Skan
325990075Sobrien  if (TARGET_TOC
3260132718Skan      && constant_pool_expr_p (x)
326196263Sobrien      && ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (x), mode))
326290075Sobrien    {
326390075Sobrien      (x) = create_TOC_reference (x);
326490075Sobrien      *win = 1;
326590075Sobrien      return x;
326690075Sobrien    }
326790075Sobrien  *win = 0;
326890075Sobrien  return x;
326990075Sobrien}
327090075Sobrien
327190075Sobrien/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression
327290075Sobrien   that is a valid memory address for an instruction.
327390075Sobrien   The MODE argument is the machine mode for the MEM expression
327490075Sobrien   that wants to use this address.
327590075Sobrien
327690075Sobrien   On the RS/6000, there are four valid address: a SYMBOL_REF that
327790075Sobrien   refers to a constant pool entry of an address (or the sum of it
327890075Sobrien   plus a constant), a short (16-bit signed) constant plus a register,
327990075Sobrien   the sum of two registers, or a register indirect, possibly with an
3280132718Skan   auto-increment.  For DFmode and DImode with a constant plus register,
328190075Sobrien   we must ensure that both words are addressable or PowerPC64 with offset
328290075Sobrien   word aligned.
328390075Sobrien
328490075Sobrien   For modes spanning multiple registers (DFmode in 32-bit GPRs,
328590075Sobrien   32-bit DImode, TImode), indexed addressing cannot be used because
328690075Sobrien   adjacent memory cells are accessed by adding word-sized offsets
328790075Sobrien   during assembly output.  */
328890075Sobrienint
3289132718Skanrs6000_legitimate_address (enum machine_mode mode, rtx x, int reg_ok_strict)
329090075Sobrien{
3291132718Skan  if (RS6000_SYMBOL_REF_TLS_P (x))
3292132718Skan    return 0;
3293132718Skan  if (legitimate_indirect_address_p (x, reg_ok_strict))
329490075Sobrien    return 1;
329590075Sobrien  if ((GET_CODE (x) == PRE_INC || GET_CODE (x) == PRE_DEC)
3296107590Sobrien      && !ALTIVEC_VECTOR_MODE (mode)
3297117395Skan      && !SPE_VECTOR_MODE (mode)
329890075Sobrien      && TARGET_UPDATE
3299132718Skan      && legitimate_indirect_address_p (XEXP (x, 0), reg_ok_strict))
330090075Sobrien    return 1;
3301132718Skan  if (legitimate_small_data_p (mode, x))
330290075Sobrien    return 1;
3303132718Skan  if (legitimate_constant_pool_address_p (x))
330490075Sobrien    return 1;
330590075Sobrien  /* If not REG_OK_STRICT (before reload) let pass any stack offset.  */
330690075Sobrien  if (! reg_ok_strict
330790075Sobrien      && GET_CODE (x) == PLUS
330890075Sobrien      && GET_CODE (XEXP (x, 0)) == REG
3309132718Skan      && (XEXP (x, 0) == virtual_stack_vars_rtx
3310132718Skan	  || XEXP (x, 0) == arg_pointer_rtx)
331190075Sobrien      && GET_CODE (XEXP (x, 1)) == CONST_INT)
331290075Sobrien    return 1;
3313132718Skan  if (legitimate_offset_address_p (mode, x, reg_ok_strict))
331490075Sobrien    return 1;
331590075Sobrien  if (mode != TImode
3316117395Skan      && ((TARGET_HARD_FLOAT && TARGET_FPRS)
3317117395Skan	  || TARGET_POWERPC64
3318117395Skan	  || (mode != DFmode && mode != TFmode))
331990075Sobrien      && (TARGET_POWERPC64 || mode != DImode)
3320132718Skan      && legitimate_indexed_address_p (x, reg_ok_strict))
332190075Sobrien    return 1;
3322132718Skan  if (legitimate_lo_sum_address_p (mode, x, reg_ok_strict))
332390075Sobrien    return 1;
332490075Sobrien  return 0;
332590075Sobrien}
3326132718Skan
3327132718Skan/* Go to LABEL if ADDR (a legitimate address expression)
3328132718Skan   has an effect that depends on the machine mode it is used for.
3329132718Skan
3330132718Skan   On the RS/6000 this is true of all integral offsets (since AltiVec
3331132718Skan   modes don't allow them) or is a pre-increment or decrement.
3332132718Skan
3333132718Skan   ??? Except that due to conceptual problems in offsettable_address_p
3334132718Skan   we can't really report the problems of integral offsets.  So leave
3335132718Skan   this assuming that the adjustable offset must be valid for the
3336132718Skan   sub-words of a TFmode operand, which is what we had before.  */
3337132718Skan
3338132718Skanbool
3339132718Skanrs6000_mode_dependent_address (rtx addr)
3340132718Skan{
3341132718Skan  switch (GET_CODE (addr))
3342132718Skan    {
3343132718Skan    case PLUS:
3344132718Skan      if (GET_CODE (XEXP (addr, 1)) == CONST_INT)
3345132718Skan	{
3346132718Skan	  unsigned HOST_WIDE_INT val = INTVAL (XEXP (addr, 1));
3347132718Skan	  return val + 12 + 0x8000 >= 0x10000;
3348132718Skan	}
3349132718Skan      break;
3350132718Skan
3351132718Skan    case LO_SUM:
3352132718Skan      return true;
3353132718Skan
3354132718Skan    case PRE_INC:
3355132718Skan    case PRE_DEC:
3356132718Skan      return TARGET_UPDATE;
3357132718Skan
3358132718Skan    default:
3359132718Skan      break;
3360132718Skan    }
3361132718Skan
3362132718Skan  return false;
3363132718Skan}
336490075Sobrien
336590075Sobrien/* Try to output insns to set TARGET equal to the constant C if it can
336690075Sobrien   be done in less than N insns.  Do all computations in MODE.
336790075Sobrien   Returns the place where the output has been placed if it can be
336890075Sobrien   done and the insns have been emitted.  If it would take more than N
336990075Sobrien   insns, zero is returned and no insns and emitted.  */
337090075Sobrien
337190075Sobrienrtx
3372132718Skanrs6000_emit_set_const (rtx dest, enum machine_mode mode,
3373132718Skan		       rtx source, int n ATTRIBUTE_UNUSED)
337490075Sobrien{
3375117395Skan  rtx result, insn, set;
337690075Sobrien  HOST_WIDE_INT c0, c1;
337790075Sobrien
3378117395Skan  if (mode == QImode || mode == HImode)
337990075Sobrien    {
338090075Sobrien      if (dest == NULL)
338190075Sobrien        dest = gen_reg_rtx (mode);
338290075Sobrien      emit_insn (gen_rtx_SET (VOIDmode, dest, source));
338390075Sobrien      return dest;
338490075Sobrien    }
3385117395Skan  else if (mode == SImode)
3386117395Skan    {
3387117395Skan      result = no_new_pseudos ? dest : gen_reg_rtx (SImode);
338890075Sobrien
3389117395Skan      emit_insn (gen_rtx_SET (VOIDmode, result,
3390117395Skan			      GEN_INT (INTVAL (source)
3391117395Skan				       & (~ (HOST_WIDE_INT) 0xffff))));
3392117395Skan      emit_insn (gen_rtx_SET (VOIDmode, dest,
3393117395Skan			      gen_rtx_IOR (SImode, result,
3394117395Skan					   GEN_INT (INTVAL (source) & 0xffff))));
3395117395Skan      result = dest;
339690075Sobrien    }
3397117395Skan  else if (mode == DImode)
339890075Sobrien    {
3399117395Skan      if (GET_CODE (source) == CONST_INT)
3400117395Skan	{
3401117395Skan	  c0 = INTVAL (source);
3402117395Skan	  c1 = -(c0 < 0);
3403117395Skan	}
3404117395Skan      else if (GET_CODE (source) == CONST_DOUBLE)
3405117395Skan	{
340690075Sobrien#if HOST_BITS_PER_WIDE_INT >= 64
3407117395Skan	  c0 = CONST_DOUBLE_LOW (source);
3408117395Skan	  c1 = -(c0 < 0);
340990075Sobrien#else
3410117395Skan	  c0 = CONST_DOUBLE_LOW (source);
3411117395Skan	  c1 = CONST_DOUBLE_HIGH (source);
341290075Sobrien#endif
3413117395Skan	}
3414117395Skan      else
3415117395Skan	abort ();
3416117395Skan
3417117395Skan      result = rs6000_emit_set_long_const (dest, c0, c1);
341890075Sobrien    }
341990075Sobrien  else
342090075Sobrien    abort ();
342190075Sobrien
3422117395Skan  insn = get_last_insn ();
3423117395Skan  set = single_set (insn);
3424117395Skan  if (! CONSTANT_P (SET_SRC (set)))
3425117395Skan    set_unique_reg_note (insn, REG_EQUAL, source);
3426117395Skan
3427117395Skan  return result;
342890075Sobrien}
342990075Sobrien
343090075Sobrien/* Having failed to find a 3 insn sequence in rs6000_emit_set_const,
343190075Sobrien   fall back to a straight forward decomposition.  We do this to avoid
343290075Sobrien   exponential run times encountered when looking for longer sequences
343390075Sobrien   with rs6000_emit_set_const.  */
343490075Sobrienstatic rtx
3435132718Skanrs6000_emit_set_long_const (rtx dest, HOST_WIDE_INT c1, HOST_WIDE_INT c2)
343690075Sobrien{
343790075Sobrien  if (!TARGET_POWERPC64)
343890075Sobrien    {
343990075Sobrien      rtx operand1, operand2;
344090075Sobrien
344190075Sobrien      operand1 = operand_subword_force (dest, WORDS_BIG_ENDIAN == 0,
344290075Sobrien					DImode);
344390075Sobrien      operand2 = operand_subword_force (dest, WORDS_BIG_ENDIAN != 0,
344490075Sobrien					DImode);
344590075Sobrien      emit_move_insn (operand1, GEN_INT (c1));
344690075Sobrien      emit_move_insn (operand2, GEN_INT (c2));
344790075Sobrien    }
344890075Sobrien  else
344990075Sobrien    {
345090075Sobrien      HOST_WIDE_INT ud1, ud2, ud3, ud4;
345190075Sobrien
345290075Sobrien      ud1 = c1 & 0xffff;
345390075Sobrien      ud2 = (c1 & 0xffff0000) >> 16;
345490075Sobrien#if HOST_BITS_PER_WIDE_INT >= 64
345590075Sobrien      c2 = c1 >> 32;
345690075Sobrien#endif
345790075Sobrien      ud3 = c2 & 0xffff;
345890075Sobrien      ud4 = (c2 & 0xffff0000) >> 16;
345990075Sobrien
346090075Sobrien      if ((ud4 == 0xffff && ud3 == 0xffff && ud2 == 0xffff && (ud1 & 0x8000))
346190075Sobrien	  || (ud4 == 0 && ud3 == 0 && ud2 == 0 && ! (ud1 & 0x8000)))
346290075Sobrien	{
346390075Sobrien	  if (ud1 & 0x8000)
3464132718Skan	    emit_move_insn (dest, GEN_INT (((ud1 ^ 0x8000) -  0x8000)));
346590075Sobrien	  else
346690075Sobrien	    emit_move_insn (dest, GEN_INT (ud1));
346790075Sobrien	}
346890075Sobrien
346990075Sobrien      else if ((ud4 == 0xffff && ud3 == 0xffff && (ud2 & 0x8000))
347090075Sobrien	       || (ud4 == 0 && ud3 == 0 && ! (ud2 & 0x8000)))
347190075Sobrien	{
347290075Sobrien	  if (ud2 & 0x8000)
347390075Sobrien	    emit_move_insn (dest, GEN_INT (((ud2 << 16) ^ 0x80000000)
347490075Sobrien					   - 0x80000000));
347590075Sobrien	  else
347690075Sobrien	    emit_move_insn (dest, GEN_INT (ud2 << 16));
347790075Sobrien	  if (ud1 != 0)
347890075Sobrien	    emit_move_insn (dest, gen_rtx_IOR (DImode, dest, GEN_INT (ud1)));
347990075Sobrien	}
348090075Sobrien      else if ((ud4 == 0xffff && (ud3 & 0x8000))
348190075Sobrien	       || (ud4 == 0 && ! (ud3 & 0x8000)))
348290075Sobrien	{
348390075Sobrien	  if (ud3 & 0x8000)
348490075Sobrien	    emit_move_insn (dest, GEN_INT (((ud3 << 16) ^ 0x80000000)
348590075Sobrien					   - 0x80000000));
348690075Sobrien	  else
348790075Sobrien	    emit_move_insn (dest, GEN_INT (ud3 << 16));
348890075Sobrien
348990075Sobrien	  if (ud2 != 0)
349090075Sobrien	    emit_move_insn (dest, gen_rtx_IOR (DImode, dest, GEN_INT (ud2)));
349190075Sobrien	  emit_move_insn (dest, gen_rtx_ASHIFT (DImode, dest, GEN_INT (16)));
349290075Sobrien	  if (ud1 != 0)
349390075Sobrien	    emit_move_insn (dest, gen_rtx_IOR (DImode, dest, GEN_INT (ud1)));
349490075Sobrien	}
349590075Sobrien      else
349690075Sobrien	{
349790075Sobrien	  if (ud4 & 0x8000)
349890075Sobrien	    emit_move_insn (dest, GEN_INT (((ud4 << 16) ^ 0x80000000)
349990075Sobrien					   - 0x80000000));
350090075Sobrien	  else
350190075Sobrien	    emit_move_insn (dest, GEN_INT (ud4 << 16));
350290075Sobrien
350390075Sobrien	  if (ud3 != 0)
350490075Sobrien	    emit_move_insn (dest, gen_rtx_IOR (DImode, dest, GEN_INT (ud3)));
350590075Sobrien
350690075Sobrien	  emit_move_insn (dest, gen_rtx_ASHIFT (DImode, dest, GEN_INT (32)));
350790075Sobrien	  if (ud2 != 0)
350890075Sobrien	    emit_move_insn (dest, gen_rtx_IOR (DImode, dest,
350990075Sobrien					       GEN_INT (ud2 << 16)));
351090075Sobrien	  if (ud1 != 0)
351190075Sobrien	    emit_move_insn (dest, gen_rtx_IOR (DImode, dest, GEN_INT (ud1)));
351290075Sobrien	}
351390075Sobrien    }
351490075Sobrien  return dest;
351590075Sobrien}
351690075Sobrien
351790075Sobrien/* Emit a move from SOURCE to DEST in mode MODE.  */
351890075Sobrienvoid
3519132718Skanrs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
352090075Sobrien{
352190075Sobrien  rtx operands[2];
352290075Sobrien  operands[0] = dest;
352390075Sobrien  operands[1] = source;
352490075Sobrien
352590075Sobrien  /* Sanity checks.  Check that we get CONST_DOUBLE only when we should.  */
352690075Sobrien  if (GET_CODE (operands[1]) == CONST_DOUBLE
352790075Sobrien      && ! FLOAT_MODE_P (mode)
352890075Sobrien      && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
352990075Sobrien    {
353090075Sobrien      /* FIXME.  This should never happen.  */
353190075Sobrien      /* Since it seems that it does, do the safe thing and convert
353290075Sobrien	 to a CONST_INT.  */
3533117395Skan      operands[1] = gen_int_mode (CONST_DOUBLE_LOW (operands[1]), mode);
353490075Sobrien    }
353590075Sobrien  if (GET_CODE (operands[1]) == CONST_DOUBLE
353690075Sobrien      && ! FLOAT_MODE_P (mode)
353790075Sobrien      && ((CONST_DOUBLE_HIGH (operands[1]) == 0
353890075Sobrien	   && CONST_DOUBLE_LOW (operands[1]) >= 0)
353990075Sobrien	  || (CONST_DOUBLE_HIGH (operands[1]) == -1
354090075Sobrien	      && CONST_DOUBLE_LOW (operands[1]) < 0)))
354190075Sobrien    abort ();
354290075Sobrien
354390075Sobrien  /* Check if GCC is setting up a block move that will end up using FP
354490075Sobrien     registers as temporaries.  We must make sure this is acceptable.  */
354590075Sobrien  if (GET_CODE (operands[0]) == MEM
354690075Sobrien      && GET_CODE (operands[1]) == MEM
354790075Sobrien      && mode == DImode
354890075Sobrien      && (SLOW_UNALIGNED_ACCESS (DImode, MEM_ALIGN (operands[0]))
354990075Sobrien	  || SLOW_UNALIGNED_ACCESS (DImode, MEM_ALIGN (operands[1])))
355090075Sobrien      && ! (SLOW_UNALIGNED_ACCESS (SImode, (MEM_ALIGN (operands[0]) > 32
355190075Sobrien					    ? 32 : MEM_ALIGN (operands[0])))
355290075Sobrien	    || SLOW_UNALIGNED_ACCESS (SImode, (MEM_ALIGN (operands[1]) > 32
355390075Sobrien					       ? 32
355490075Sobrien					       : MEM_ALIGN (operands[1]))))
355590075Sobrien      && ! MEM_VOLATILE_P (operands [0])
355690075Sobrien      && ! MEM_VOLATILE_P (operands [1]))
355790075Sobrien    {
355890075Sobrien      emit_move_insn (adjust_address (operands[0], SImode, 0),
355990075Sobrien		      adjust_address (operands[1], SImode, 0));
356090075Sobrien      emit_move_insn (adjust_address (operands[0], SImode, 4),
356190075Sobrien		      adjust_address (operands[1], SImode, 4));
356290075Sobrien      return;
356390075Sobrien    }
356490075Sobrien
3565117395Skan  if (!no_new_pseudos)
3566117395Skan    {
3567117395Skan      if (GET_CODE (operands[1]) == MEM && optimize > 0
3568117395Skan	  && (mode == QImode || mode == HImode || mode == SImode)
3569117395Skan	  && GET_MODE_SIZE (mode) < GET_MODE_SIZE (word_mode))
3570117395Skan	{
3571117395Skan	  rtx reg = gen_reg_rtx (word_mode);
357290075Sobrien
3573117395Skan	  emit_insn (gen_rtx_SET (word_mode, reg,
3574117395Skan				  gen_rtx_ZERO_EXTEND (word_mode,
3575117395Skan						       operands[1])));
3576117395Skan	  operands[1] = gen_lowpart (mode, reg);
3577117395Skan	}
3578117395Skan      if (GET_CODE (operands[0]) != REG)
3579117395Skan	operands[1] = force_reg (mode, operands[1]);
3580117395Skan    }
3581117395Skan
3582117395Skan  if (mode == SFmode && ! TARGET_POWERPC
3583117395Skan      && TARGET_HARD_FLOAT && TARGET_FPRS
358490075Sobrien      && GET_CODE (operands[0]) == MEM)
358590075Sobrien    {
358690075Sobrien      int regnum;
358790075Sobrien
358890075Sobrien      if (reload_in_progress || reload_completed)
358990075Sobrien	regnum = true_regnum (operands[1]);
359090075Sobrien      else if (GET_CODE (operands[1]) == REG)
359190075Sobrien	regnum = REGNO (operands[1]);
359290075Sobrien      else
359390075Sobrien	regnum = -1;
359490075Sobrien
359590075Sobrien      /* If operands[1] is a register, on POWER it may have
359690075Sobrien	 double-precision data in it, so truncate it to single
359790075Sobrien	 precision.  */
359890075Sobrien      if (FP_REGNO_P (regnum) || regnum >= FIRST_PSEUDO_REGISTER)
359990075Sobrien	{
360090075Sobrien	  rtx newreg;
360190075Sobrien	  newreg = (no_new_pseudos ? operands[1] : gen_reg_rtx (mode));
360290075Sobrien	  emit_insn (gen_aux_truncdfsf2 (newreg, operands[1]));
360390075Sobrien	  operands[1] = newreg;
360490075Sobrien	}
360590075Sobrien    }
360690075Sobrien
3607132718Skan  /* Recognize the case where operand[1] is a reference to thread-local
3608132718Skan     data and load its address to a register.  */
3609132718Skan  if (GET_CODE (operands[1]) == SYMBOL_REF)
3610132718Skan    {
3611132718Skan      enum tls_model model = SYMBOL_REF_TLS_MODEL (operands[1]);
3612132718Skan      if (model != 0)
3613132718Skan	operands[1] = rs6000_legitimize_tls_address (operands[1], model);
3614132718Skan    }
3615132718Skan
3616117395Skan  /* Handle the case where reload calls us with an invalid address.  */
3617117395Skan  if (reload_in_progress && mode == Pmode
361896263Sobrien      && (! general_operand (operands[1], mode)
3619117395Skan	  || ! nonimmediate_operand (operands[0], mode)))
3620117395Skan    goto emit_set;
3621117395Skan
3622117395Skan  /* Handle the case of CONSTANT_P_RTX.  */
3623117395Skan  if (GET_CODE (operands[1]) == CONSTANT_P_RTX)
3624117395Skan    goto emit_set;
3625132718Skan
3626132718Skan  /* 128-bit constant floating-point values on Darwin should really be
3627132718Skan     loaded as two parts.  */
3628132718Skan  if ((DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_DARWIN)
3629132718Skan      && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128
3630132718Skan      && mode == TFmode && GET_CODE (operands[1]) == CONST_DOUBLE)
3631132718Skan    {
3632132718Skan      /* DImode is used, not DFmode, because simplify_gen_subreg doesn't
3633132718Skan	 know how to get a DFmode SUBREG of a TFmode.  */
3634132718Skan      rs6000_emit_move (simplify_gen_subreg (DImode, operands[0], mode, 0),
3635132718Skan			simplify_gen_subreg (DImode, operands[1], mode, 0),
3636132718Skan			DImode);
3637132718Skan      rs6000_emit_move (simplify_gen_subreg (DImode, operands[0], mode,
3638132718Skan					     GET_MODE_SIZE (DImode)),
3639132718Skan			simplify_gen_subreg (DImode, operands[1], mode,
3640132718Skan					     GET_MODE_SIZE (DImode)),
3641132718Skan			DImode);
3642132718Skan      return;
3643132718Skan    }
3644132718Skan
364590075Sobrien  /* FIXME:  In the long term, this switch statement should go away
364690075Sobrien     and be replaced by a sequence of tests based on things like
364790075Sobrien     mode == Pmode.  */
364890075Sobrien  switch (mode)
364990075Sobrien    {
365090075Sobrien    case HImode:
365190075Sobrien    case QImode:
365290075Sobrien      if (CONSTANT_P (operands[1])
365390075Sobrien	  && GET_CODE (operands[1]) != CONST_INT)
365490075Sobrien	operands[1] = force_const_mem (mode, operands[1]);
365590075Sobrien      break;
365690075Sobrien
365790075Sobrien    case TFmode:
365890075Sobrien    case DFmode:
365990075Sobrien    case SFmode:
366090075Sobrien      if (CONSTANT_P (operands[1])
366190075Sobrien	  && ! easy_fp_constant (operands[1], mode))
366290075Sobrien	operands[1] = force_const_mem (mode, operands[1]);
366390075Sobrien      break;
366490075Sobrien
366590075Sobrien    case V16QImode:
366690075Sobrien    case V8HImode:
366790075Sobrien    case V4SFmode:
366890075Sobrien    case V4SImode:
3669117395Skan    case V4HImode:
3670117395Skan    case V2SFmode:
3671117395Skan    case V2SImode:
3672117395Skan    case V1DImode:
367396263Sobrien      if (CONSTANT_P (operands[1])
3674132718Skan	  && !easy_vector_constant (operands[1], mode))
367590075Sobrien	operands[1] = force_const_mem (mode, operands[1]);
367690075Sobrien      break;
367790075Sobrien
367890075Sobrien    case SImode:
367990075Sobrien    case DImode:
368090075Sobrien      /* Use default pattern for address of ELF small data */
368190075Sobrien      if (TARGET_ELF
368290075Sobrien	  && mode == Pmode
368390075Sobrien	  && DEFAULT_ABI == ABI_V4
368490075Sobrien	  && (GET_CODE (operands[1]) == SYMBOL_REF
368590075Sobrien	      || GET_CODE (operands[1]) == CONST)
368690075Sobrien	  && small_data_operand (operands[1], mode))
368790075Sobrien	{
368890075Sobrien	  emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
368990075Sobrien	  return;
369090075Sobrien	}
369190075Sobrien
369290075Sobrien      if (DEFAULT_ABI == ABI_V4
369390075Sobrien	  && mode == Pmode && mode == SImode
369490075Sobrien	  && flag_pic == 1 && got_operand (operands[1], mode))
369590075Sobrien	{
369690075Sobrien	  emit_insn (gen_movsi_got (operands[0], operands[1]));
369790075Sobrien	  return;
369890075Sobrien	}
369990075Sobrien
370090075Sobrien      if ((TARGET_ELF || DEFAULT_ABI == ABI_DARWIN)
3701132718Skan	  && TARGET_NO_TOC
3702132718Skan	  && ! flag_pic
370390075Sobrien	  && mode == Pmode
370490075Sobrien	  && CONSTANT_P (operands[1])
370590075Sobrien	  && GET_CODE (operands[1]) != HIGH
370690075Sobrien	  && GET_CODE (operands[1]) != CONST_INT)
370790075Sobrien	{
370890075Sobrien	  rtx target = (no_new_pseudos ? operands[0] : gen_reg_rtx (mode));
370990075Sobrien
371090075Sobrien	  /* If this is a function address on -mcall-aixdesc,
371190075Sobrien	     convert it to the address of the descriptor.  */
371290075Sobrien	  if (DEFAULT_ABI == ABI_AIX
371390075Sobrien	      && GET_CODE (operands[1]) == SYMBOL_REF
371490075Sobrien	      && XSTR (operands[1], 0)[0] == '.')
371590075Sobrien	    {
371690075Sobrien	      const char *name = XSTR (operands[1], 0);
371790075Sobrien	      rtx new_ref;
371890075Sobrien	      while (*name == '.')
371990075Sobrien		name++;
372090075Sobrien	      new_ref = gen_rtx_SYMBOL_REF (Pmode, name);
372190075Sobrien	      CONSTANT_POOL_ADDRESS_P (new_ref)
372290075Sobrien		= CONSTANT_POOL_ADDRESS_P (operands[1]);
3723132718Skan	      SYMBOL_REF_FLAGS (new_ref) = SYMBOL_REF_FLAGS (operands[1]);
372490075Sobrien	      SYMBOL_REF_USED (new_ref) = SYMBOL_REF_USED (operands[1]);
3725132718Skan	      SYMBOL_REF_DECL (new_ref) = SYMBOL_REF_DECL (operands[1]);
372690075Sobrien	      operands[1] = new_ref;
372790075Sobrien	    }
372890075Sobrien
372990075Sobrien	  if (DEFAULT_ABI == ABI_DARWIN)
373090075Sobrien	    {
3731132718Skan#if TARGET_MACHO
3732132718Skan	      if (MACHO_DYNAMIC_NO_PIC_P)
3733132718Skan		{
3734132718Skan		  /* Take care of any required data indirection.  */
3735132718Skan		  operands[1] = rs6000_machopic_legitimize_pic_address (
3736132718Skan				  operands[1], mode, operands[0]);
3737132718Skan		  if (operands[0] != operands[1])
3738132718Skan		    emit_insn (gen_rtx_SET (VOIDmode,
3739132718Skan				            operands[0], operands[1]));
3740132718Skan		  return;
3741132718Skan		}
3742132718Skan#endif
374390075Sobrien	      emit_insn (gen_macho_high (target, operands[1]));
374490075Sobrien	      emit_insn (gen_macho_low (operands[0], target, operands[1]));
374590075Sobrien	      return;
374690075Sobrien	    }
374790075Sobrien
374890075Sobrien	  emit_insn (gen_elf_high (target, operands[1]));
374990075Sobrien	  emit_insn (gen_elf_low (operands[0], target, operands[1]));
375090075Sobrien	  return;
375190075Sobrien	}
375290075Sobrien
375390075Sobrien      /* If this is a SYMBOL_REF that refers to a constant pool entry,
375490075Sobrien	 and we have put it in the TOC, we just need to make a TOC-relative
375590075Sobrien	 reference to it.  */
375690075Sobrien      if (TARGET_TOC
375790075Sobrien	  && GET_CODE (operands[1]) == SYMBOL_REF
3758132718Skan	  && constant_pool_expr_p (operands[1])
375990075Sobrien	  && ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (operands[1]),
376090075Sobrien					      get_pool_mode (operands[1])))
376190075Sobrien	{
376290075Sobrien	  operands[1] = create_TOC_reference (operands[1]);
376390075Sobrien	}
376490075Sobrien      else if (mode == Pmode
376590075Sobrien	       && CONSTANT_P (operands[1])
376690075Sobrien	       && ((GET_CODE (operands[1]) != CONST_INT
376790075Sobrien		    && ! easy_fp_constant (operands[1], mode))
376890075Sobrien		   || (GET_CODE (operands[1]) == CONST_INT
376990075Sobrien		       && num_insns_constant (operands[1], mode) > 2)
377090075Sobrien		   || (GET_CODE (operands[0]) == REG
377190075Sobrien		       && FP_REGNO_P (REGNO (operands[0]))))
377290075Sobrien	       && GET_CODE (operands[1]) != HIGH
3773132718Skan	       && ! legitimate_constant_pool_address_p (operands[1])
3774132718Skan	       && ! toc_relative_expr_p (operands[1]))
377590075Sobrien	{
377690075Sobrien	  /* Emit a USE operation so that the constant isn't deleted if
377790075Sobrien	     expensive optimizations are turned on because nobody
377890075Sobrien	     references it.  This should only be done for operands that
377990075Sobrien	     contain SYMBOL_REFs with CONSTANT_POOL_ADDRESS_P set.
378090075Sobrien	     This should not be done for operands that contain LABEL_REFs.
378190075Sobrien	     For now, we just handle the obvious case.  */
378290075Sobrien	  if (GET_CODE (operands[1]) != LABEL_REF)
378390075Sobrien	    emit_insn (gen_rtx_USE (VOIDmode, operands[1]));
378490075Sobrien
378590075Sobrien#if TARGET_MACHO
378690075Sobrien	  /* Darwin uses a special PIC legitimizer.  */
3787132718Skan	  if (DEFAULT_ABI == ABI_DARWIN && MACHOPIC_INDIRECT)
378890075Sobrien	    {
378990075Sobrien	      operands[1] =
379090075Sobrien		rs6000_machopic_legitimize_pic_address (operands[1], mode,
379190075Sobrien							operands[0]);
379290075Sobrien	      if (operands[0] != operands[1])
379390075Sobrien		emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
379490075Sobrien	      return;
379590075Sobrien	    }
379690075Sobrien#endif
379790075Sobrien
379890075Sobrien	  /* If we are to limit the number of things we put in the TOC and
379990075Sobrien	     this is a symbol plus a constant we can add in one insn,
380090075Sobrien	     just put the symbol in the TOC and add the constant.  Don't do
380190075Sobrien	     this if reload is in progress.  */
380290075Sobrien	  if (GET_CODE (operands[1]) == CONST
380390075Sobrien	      && TARGET_NO_SUM_IN_TOC && ! reload_in_progress
380490075Sobrien	      && GET_CODE (XEXP (operands[1], 0)) == PLUS
380590075Sobrien	      && add_operand (XEXP (XEXP (operands[1], 0), 1), mode)
380690075Sobrien	      && (GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == LABEL_REF
380790075Sobrien		  || GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == SYMBOL_REF)
380890075Sobrien	      && ! side_effects_p (operands[0]))
380990075Sobrien	    {
381090075Sobrien	      rtx sym =
381190075Sobrien		force_const_mem (mode, XEXP (XEXP (operands[1], 0), 0));
381290075Sobrien	      rtx other = XEXP (XEXP (operands[1], 0), 1);
381390075Sobrien
381490075Sobrien	      sym = force_reg (mode, sym);
381590075Sobrien	      if (mode == SImode)
381690075Sobrien		emit_insn (gen_addsi3 (operands[0], sym, other));
381790075Sobrien	      else
381890075Sobrien		emit_insn (gen_adddi3 (operands[0], sym, other));
381990075Sobrien	      return;
382090075Sobrien	    }
382190075Sobrien
382290075Sobrien	  operands[1] = force_const_mem (mode, operands[1]);
382390075Sobrien
382490075Sobrien	  if (TARGET_TOC
3825132718Skan	      && constant_pool_expr_p (XEXP (operands[1], 0))
382690075Sobrien	      && ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (
382790075Sobrien			get_pool_constant (XEXP (operands[1], 0)),
382890075Sobrien			get_pool_mode (XEXP (operands[1], 0))))
382990075Sobrien	    {
383090075Sobrien	      operands[1]
383190075Sobrien		= gen_rtx_MEM (mode,
383290075Sobrien			       create_TOC_reference (XEXP (operands[1], 0)));
383390075Sobrien	      set_mem_alias_set (operands[1], get_TOC_alias_set ());
383490075Sobrien	      RTX_UNCHANGING_P (operands[1]) = 1;
383590075Sobrien	    }
383690075Sobrien	}
383790075Sobrien      break;
383890075Sobrien
383990075Sobrien    case TImode:
384090075Sobrien      if (GET_CODE (operands[0]) == MEM
384190075Sobrien	  && GET_CODE (XEXP (operands[0], 0)) != REG
384290075Sobrien	  && ! reload_in_progress)
384390075Sobrien	operands[0]
384490075Sobrien	  = replace_equiv_address (operands[0],
384590075Sobrien				   copy_addr_to_reg (XEXP (operands[0], 0)));
384690075Sobrien
384790075Sobrien      if (GET_CODE (operands[1]) == MEM
384890075Sobrien	  && GET_CODE (XEXP (operands[1], 0)) != REG
384990075Sobrien	  && ! reload_in_progress)
385090075Sobrien	operands[1]
385190075Sobrien	  = replace_equiv_address (operands[1],
385290075Sobrien				   copy_addr_to_reg (XEXP (operands[1], 0)));
3853117395Skan      if (TARGET_POWER)
3854132718Skan	{
3855117395Skan	  emit_insn (gen_rtx_PARALLEL (VOIDmode,
3856117395Skan		       gen_rtvec (2,
3857117395Skan				  gen_rtx_SET (VOIDmode,
3858117395Skan					       operands[0], operands[1]),
3859117395Skan				  gen_rtx_CLOBBER (VOIDmode,
3860117395Skan						   gen_rtx_SCRATCH (SImode)))));
3861117395Skan	  return;
3862117395Skan	}
386390075Sobrien      break;
386490075Sobrien
386590075Sobrien    default:
386690075Sobrien      abort ();
386790075Sobrien    }
386890075Sobrien
386990075Sobrien  /* Above, we may have called force_const_mem which may have returned
387090075Sobrien     an invalid address.  If we can, fix this up; otherwise, reload will
387190075Sobrien     have to deal with it.  */
3872117395Skan  if (GET_CODE (operands[1]) == MEM && ! reload_in_progress)
3873117395Skan    operands[1] = validize_mem (operands[1]);
387490075Sobrien
3875117395Skan emit_set:
387690075Sobrien  emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
387790075Sobrien}
387890075Sobrien
3879132718Skan/* Nonzero if we can use a floating-point register to pass this arg.  */
3880132718Skan#define USE_FP_FOR_ARG_P(CUM,MODE,TYPE)		\
3881132718Skan  (GET_MODE_CLASS (MODE) == MODE_FLOAT		\
3882132718Skan   && (CUM)->fregno <= FP_ARG_MAX_REG		\
3883132718Skan   && TARGET_HARD_FLOAT && TARGET_FPRS)
3884132718Skan
3885132718Skan/* Nonzero if we can use an AltiVec register to pass this arg.  */
3886132718Skan#define USE_ALTIVEC_FOR_ARG_P(CUM,MODE,TYPE,NAMED)	\
3887132718Skan  (ALTIVEC_VECTOR_MODE (MODE)				\
3888132718Skan   && (CUM)->vregno <= ALTIVEC_ARG_MAX_REG		\
3889132718Skan   && TARGET_ALTIVEC_ABI				\
3890132718Skan   && (NAMED))
3891132718Skan
3892132718Skan/* Return a nonzero value to say to return the function value in
3893132718Skan   memory, just as large structures are always returned.  TYPE will be
3894132718Skan   the data type of the value, and FNTYPE will be the type of the
3895132718Skan   function doing the returning, or @code{NULL} for libcalls.
3896132718Skan
3897132718Skan   The AIX ABI for the RS/6000 specifies that all structures are
3898132718Skan   returned in memory.  The Darwin ABI does the same.  The SVR4 ABI
3899132718Skan   specifies that structures <= 8 bytes are returned in r3/r4, but a
3900132718Skan   draft put them in memory, and GCC used to implement the draft
3901132718Skan   instead of the final standard.  Therefore, TARGET_AIX_STRUCT_RET
3902132718Skan   controls this instead of DEFAULT_ABI; V.4 targets needing backward
3903132718Skan   compatibility can change DRAFT_V4_STRUCT_RET to override the
3904132718Skan   default, and -m switches get the final word.  See
3905132718Skan   rs6000_override_options for more details.
3906132718Skan
3907132718Skan   The PPC32 SVR4 ABI uses IEEE double extended for long double, if 128-bit
3908132718Skan   long double support is enabled.  These values are returned in memory.
3909132718Skan
3910132718Skan   int_size_in_bytes returns -1 for variable size objects, which go in
3911132718Skan   memory always.  The cast to unsigned makes -1 > 8.  */
3912132718Skan
3913132718Skanstatic bool
3914132718Skanrs6000_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
3915132718Skan{
3916132718Skan  if (AGGREGATE_TYPE_P (type)
3917132718Skan      && (TARGET_AIX_STRUCT_RET
3918132718Skan	  || (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 8))
3919132718Skan    return true;
3920132718Skan  if (DEFAULT_ABI == ABI_V4 && TYPE_MODE (type) == TFmode)
3921132718Skan    return true;
3922132718Skan  return false;
3923132718Skan}
3924132718Skan
392590075Sobrien/* Initialize a variable CUM of type CUMULATIVE_ARGS
392690075Sobrien   for a call to a function whose data type is FNTYPE.
392790075Sobrien   For a library call, FNTYPE is 0.
392890075Sobrien
392990075Sobrien   For incoming args we set the number of arguments in the prototype large
393090075Sobrien   so we never return a PARALLEL.  */
393190075Sobrien
393290075Sobrienvoid
3933132718Skaninit_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
3934132718Skan		      rtx libname ATTRIBUTE_UNUSED, int incoming,
3935132718Skan		      int libcall, int n_named_args)
393690075Sobrien{
393790075Sobrien  static CUMULATIVE_ARGS zero_cumulative;
393890075Sobrien
393990075Sobrien  *cum = zero_cumulative;
394090075Sobrien  cum->words = 0;
394190075Sobrien  cum->fregno = FP_ARG_MIN_REG;
394290075Sobrien  cum->vregno = ALTIVEC_ARG_MIN_REG;
394390075Sobrien  cum->prototype = (fntype && TYPE_ARG_TYPES (fntype));
3944117395Skan  cum->call_cookie = ((DEFAULT_ABI == ABI_V4 && libcall)
3945117395Skan		      ? CALL_LIBCALL : CALL_NORMAL);
394690075Sobrien  cum->sysv_gregno = GP_ARG_MIN_REG;
3947132718Skan  cum->stdarg = fntype
3948132718Skan    && (TYPE_ARG_TYPES (fntype) != 0
3949132718Skan	&& (TREE_VALUE (tree_last  (TYPE_ARG_TYPES (fntype)))
3950132718Skan	    != void_type_node));
395190075Sobrien
3952132718Skan  cum->nargs_prototype = 0;
3953132718Skan  if (incoming || cum->prototype)
3954132718Skan    cum->nargs_prototype = n_named_args;
395590075Sobrien
3956117395Skan  /* Check for a longcall attribute.  */
3957146895Skan  if ((!fntype && rs6000_default_long_calls)
3958146895Skan      || (fntype
3959146895Skan	  && lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype))
3960146895Skan	  && !lookup_attribute ("shortcall", TYPE_ATTRIBUTES (fntype))))
3961146895Skan    cum->call_cookie |= CALL_LONG;
396290075Sobrien
396390075Sobrien  if (TARGET_DEBUG_ARG)
396490075Sobrien    {
396590075Sobrien      fprintf (stderr, "\ninit_cumulative_args:");
396690075Sobrien      if (fntype)
396790075Sobrien	{
396890075Sobrien	  tree ret_type = TREE_TYPE (fntype);
396990075Sobrien	  fprintf (stderr, " ret code = %s,",
397090075Sobrien		   tree_code_name[ (int)TREE_CODE (ret_type) ]);
397190075Sobrien	}
397290075Sobrien
397390075Sobrien      if (cum->call_cookie & CALL_LONG)
397490075Sobrien	fprintf (stderr, " longcall,");
397590075Sobrien
397690075Sobrien      fprintf (stderr, " proto = %d, nargs = %d\n",
397790075Sobrien	       cum->prototype, cum->nargs_prototype);
397890075Sobrien    }
3979132718Skan
3980132718Skan    if (fntype
3981132718Skan	&& !TARGET_ALTIVEC
3982132718Skan	&& TARGET_ALTIVEC_ABI
3983132718Skan        && ALTIVEC_VECTOR_MODE (TYPE_MODE (TREE_TYPE (fntype))))
3984132718Skan      {
3985132718Skan	error ("Cannot return value in vector register because"
3986132718Skan	       " altivec instructions are disabled, use -maltivec"
3987132718Skan	       " to enable them.");
3988132718Skan      }
398990075Sobrien}
399090075Sobrien
399190075Sobrien/* If defined, a C expression which determines whether, and in which
399290075Sobrien   direction, to pad out an argument with extra space.  The value
399390075Sobrien   should be of type `enum direction': either `upward' to pad above
399490075Sobrien   the argument, `downward' to pad below, or `none' to inhibit
399590075Sobrien   padding.
399690075Sobrien
399790075Sobrien   For the AIX ABI structs are always stored left shifted in their
399890075Sobrien   argument slot.  */
399990075Sobrien
400090075Sobrienenum direction
4001132718Skanfunction_arg_padding (enum machine_mode mode, tree type)
400290075Sobrien{
4003132718Skan#ifndef AGGREGATE_PADDING_FIXED
4004132718Skan#define AGGREGATE_PADDING_FIXED 0
4005132718Skan#endif
4006132718Skan#ifndef AGGREGATES_PAD_UPWARD_ALWAYS
4007132718Skan#define AGGREGATES_PAD_UPWARD_ALWAYS 0
4008132718Skan#endif
400990075Sobrien
4010132718Skan  if (!AGGREGATE_PADDING_FIXED)
4011132718Skan    {
4012132718Skan      /* GCC used to pass structures of the same size as integer types as
4013132718Skan	 if they were in fact integers, ignoring FUNCTION_ARG_PADDING.
4014132718Skan	 ie. Structures of size 1 or 2 (or 4 when TARGET_64BIT) were
4015132718Skan	 passed padded downward, except that -mstrict-align further
4016132718Skan	 muddied the water in that multi-component structures of 2 and 4
4017132718Skan	 bytes in size were passed padded upward.
4018132718Skan
4019132718Skan	 The following arranges for best compatibility with previous
4020132718Skan	 versions of gcc, but removes the -mstrict-align dependency.  */
4021132718Skan      if (BYTES_BIG_ENDIAN)
4022132718Skan	{
4023132718Skan	  HOST_WIDE_INT size = 0;
4024132718Skan
4025132718Skan	  if (mode == BLKmode)
4026132718Skan	    {
4027132718Skan	      if (type && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST)
4028132718Skan		size = int_size_in_bytes (type);
4029132718Skan	    }
4030132718Skan	  else
4031132718Skan	    size = GET_MODE_SIZE (mode);
4032132718Skan
4033132718Skan	  if (size == 1 || size == 2 || size == 4)
4034132718Skan	    return downward;
4035132718Skan	}
4036132718Skan      return upward;
4037132718Skan    }
4038132718Skan
4039132718Skan  if (AGGREGATES_PAD_UPWARD_ALWAYS)
4040132718Skan    {
4041132718Skan      if (type != 0 && AGGREGATE_TYPE_P (type))
4042132718Skan	return upward;
4043132718Skan    }
4044132718Skan
4045132718Skan  /* Fall back to the default.  */
4046132718Skan  return DEFAULT_FUNCTION_ARG_PADDING (mode, type);
404790075Sobrien}
404890075Sobrien
404990075Sobrien/* If defined, a C expression that gives the alignment boundary, in bits,
405090075Sobrien   of an argument with the specified mode and type.  If it is not defined,
405190075Sobrien   PARM_BOUNDARY is used for all arguments.
405290075Sobrien
405390075Sobrien   V.4 wants long longs to be double word aligned.  */
405490075Sobrien
405590075Sobrienint
4056132718Skanfunction_arg_boundary (enum machine_mode mode, tree type ATTRIBUTE_UNUSED)
405790075Sobrien{
4058132718Skan  if (DEFAULT_ABI == ABI_V4 && GET_MODE_SIZE (mode) == 8)
405990075Sobrien    return 64;
4060132718Skan  else if (SPE_VECTOR_MODE (mode))
4061132718Skan    return 64;
4062132718Skan  else if (ALTIVEC_VECTOR_MODE (mode))
406390075Sobrien    return 128;
406490075Sobrien  else
406590075Sobrien    return PARM_BOUNDARY;
406690075Sobrien}
4067132718Skan
4068132718Skan/* Compute the size (in words) of a function argument.  */
4069132718Skan
4070132718Skanstatic unsigned long
4071132718Skanrs6000_arg_size (enum machine_mode mode, tree type)
4072132718Skan{
4073132718Skan  unsigned long size;
4074132718Skan
4075132718Skan  if (mode != BLKmode)
4076132718Skan    size = GET_MODE_SIZE (mode);
4077132718Skan  else
4078132718Skan    size = int_size_in_bytes (type);
4079132718Skan
4080132718Skan  if (TARGET_32BIT)
4081132718Skan    return (size + 3) >> 2;
4082132718Skan  else
4083132718Skan    return (size + 7) >> 3;
4084132718Skan}
408590075Sobrien
408690075Sobrien/* Update the data in CUM to advance over an argument
408790075Sobrien   of mode MODE and data type TYPE.
4088132718Skan   (TYPE is null for libcalls where that information may not be available.)
408990075Sobrien
4090132718Skan   Note that for args passed by reference, function_arg will be called
4091132718Skan   with MODE and TYPE set to that of the pointer to the arg, not the arg
4092132718Skan   itself.  */
4093132718Skan
409490075Sobrienvoid
4095132718Skanfunction_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
4096132718Skan		      tree type, int named)
409790075Sobrien{
409890075Sobrien  cum->nargs_prototype--;
409990075Sobrien
410090075Sobrien  if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
410190075Sobrien    {
4102132718Skan      bool stack = false;
4103132718Skan
4104132718Skan      if (USE_ALTIVEC_FOR_ARG_P (cum, mode, type, named))
4105132718Skan        {
4106132718Skan	  cum->vregno++;
4107132718Skan	  if (!TARGET_ALTIVEC)
4108132718Skan	    error ("Cannot pass argument in vector register because"
4109132718Skan		   " altivec instructions are disabled, use -maltivec"
4110132718Skan		   " to enable them.");
4111132718Skan
4112132718Skan	  /* PowerPC64 Linux and AIX allocate GPRs for a vector argument
4113132718Skan	     even if it is going to be passed in a vector register.
4114132718Skan	     Darwin does the same for variable-argument functions.  */
4115132718Skan	  if ((DEFAULT_ABI == ABI_AIX && TARGET_64BIT)
4116132718Skan	      || (cum->stdarg && DEFAULT_ABI != ABI_V4))
4117132718Skan	    stack = true;
4118132718Skan	}
411990075Sobrien      else
4120132718Skan	stack = true;
4121132718Skan
4122132718Skan      if (stack)
4123132718Skan        {
4124132718Skan	  int align;
4125132718Skan
4126132718Skan	  /* Vector parameters must be 16-byte aligned.  This places
4127132718Skan	     them at 2 mod 4 in terms of words in 32-bit mode, since
4128132718Skan	     the parameter save area starts at offset 24 from the
4129132718Skan	     stack.  In 64-bit mode, they just have to start on an
4130132718Skan	     even word, since the parameter save area is 16-byte
4131132718Skan	     aligned.  Space for GPRs is reserved even if the argument
4132132718Skan	     will be passed in memory.  */
4133132718Skan	  if (TARGET_32BIT)
4134132718Skan	    align = (2 - cum->words) & 3;
4135132718Skan	  else
4136132718Skan	    align = cum->words & 1;
4137132718Skan	  cum->words += align + rs6000_arg_size (mode, type);
4138132718Skan
4139132718Skan	  if (TARGET_DEBUG_ARG)
4140132718Skan	    {
4141132718Skan	      fprintf (stderr, "function_adv: words = %2d, align=%d, ",
4142132718Skan		       cum->words, align);
4143132718Skan	      fprintf (stderr, "nargs = %4d, proto = %d, mode = %4s\n",
4144132718Skan		       cum->nargs_prototype, cum->prototype,
4145132718Skan		       GET_MODE_NAME (mode));
4146132718Skan	    }
4147132718Skan	}
414890075Sobrien    }
4149117395Skan  else if (TARGET_SPE_ABI && TARGET_SPE && SPE_VECTOR_MODE (mode)
4150132718Skan	   && !cum->stdarg
4151132718Skan	   && cum->sysv_gregno <= GP_ARG_MAX_REG)
4152117395Skan    cum->sysv_gregno++;
415390075Sobrien  else if (DEFAULT_ABI == ABI_V4)
415490075Sobrien    {
4155117395Skan      if (TARGET_HARD_FLOAT && TARGET_FPRS
415690075Sobrien	  && (mode == SFmode || mode == DFmode))
415790075Sobrien	{
415890075Sobrien	  if (cum->fregno <= FP_ARG_V4_MAX_REG)
415990075Sobrien	    cum->fregno++;
416090075Sobrien	  else
416190075Sobrien	    {
416290075Sobrien	      if (mode == DFmode)
416390075Sobrien	        cum->words += cum->words & 1;
4164132718Skan	      cum->words += rs6000_arg_size (mode, type);
416590075Sobrien	    }
416690075Sobrien	}
416790075Sobrien      else
416890075Sobrien	{
4169132718Skan	  int n_words = rs6000_arg_size (mode, type);
417090075Sobrien	  int gregno = cum->sysv_gregno;
417190075Sobrien
4172132718Skan	  /* Long long and SPE vectors are put in (r3,r4), (r5,r6),
4173132718Skan	     (r7,r8) or (r9,r10).  As does any other 2 word item such
4174132718Skan	     as complex int due to a historical mistake.  */
4175132718Skan	  if (n_words == 2)
4176132718Skan	    gregno += (1 - gregno) & 1;
417790075Sobrien
4178132718Skan	  /* Multi-reg args are not split between registers and stack.  */
417990075Sobrien	  if (gregno + n_words - 1 > GP_ARG_MAX_REG)
418090075Sobrien	    {
4181132718Skan	      /* Long long and SPE vectors are aligned on the stack.
4182132718Skan		 So are other 2 word items such as complex int due to
4183132718Skan		 a historical mistake.  */
418490075Sobrien	      if (n_words == 2)
418590075Sobrien		cum->words += cum->words & 1;
418690075Sobrien	      cum->words += n_words;
418790075Sobrien	    }
418890075Sobrien
418990075Sobrien	  /* Note: continuing to accumulate gregno past when we've started
419090075Sobrien	     spilling to the stack indicates the fact that we've started
419190075Sobrien	     spilling to the stack to expand_builtin_saveregs.  */
419290075Sobrien	  cum->sysv_gregno = gregno + n_words;
419390075Sobrien	}
419490075Sobrien
419590075Sobrien      if (TARGET_DEBUG_ARG)
419690075Sobrien	{
419790075Sobrien	  fprintf (stderr, "function_adv: words = %2d, fregno = %2d, ",
419890075Sobrien		   cum->words, cum->fregno);
419990075Sobrien	  fprintf (stderr, "gregno = %2d, nargs = %4d, proto = %d, ",
420090075Sobrien		   cum->sysv_gregno, cum->nargs_prototype, cum->prototype);
420190075Sobrien	  fprintf (stderr, "mode = %4s, named = %d\n",
420290075Sobrien		   GET_MODE_NAME (mode), named);
420390075Sobrien	}
420490075Sobrien    }
420590075Sobrien  else
420690075Sobrien    {
4207132718Skan      int n_words = rs6000_arg_size (mode, type);
4208132718Skan      int align = function_arg_boundary (mode, type) / PARM_BOUNDARY - 1;
420990075Sobrien
4210132718Skan      /* The simple alignment calculation here works because
4211132718Skan	 function_arg_boundary / PARM_BOUNDARY will only be 1 or 2.
4212132718Skan	 If we ever want to handle alignments larger than 8 bytes for
4213132718Skan	 32-bit or 16 bytes for 64-bit, then we'll need to take into
4214132718Skan	 account the offset to the start of the parm save area.  */
4215132718Skan      align &= cum->words;
4216132718Skan      cum->words += align + n_words;
421790075Sobrien
4218117395Skan      if (GET_MODE_CLASS (mode) == MODE_FLOAT
4219117395Skan	  && TARGET_HARD_FLOAT && TARGET_FPRS)
4220132718Skan	cum->fregno += (GET_MODE_SIZE (mode) + 7) >> 3;
422190075Sobrien
422290075Sobrien      if (TARGET_DEBUG_ARG)
422390075Sobrien	{
422490075Sobrien	  fprintf (stderr, "function_adv: words = %2d, fregno = %2d, ",
422590075Sobrien		   cum->words, cum->fregno);
422690075Sobrien	  fprintf (stderr, "nargs = %4d, proto = %d, mode = %4s, ",
422790075Sobrien		   cum->nargs_prototype, cum->prototype, GET_MODE_NAME (mode));
422890075Sobrien	  fprintf (stderr, "named = %d, align = %d\n", named, align);
422990075Sobrien	}
423090075Sobrien    }
423190075Sobrien}
4232132718Skan
4233132718Skan/* Determine where to put a SIMD argument on the SPE.  */
4234132718Skan
4235132718Skanstatic rtx
4236132718Skanrs6000_spe_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
4237132718Skan			 tree type)
4238132718Skan{
4239132718Skan  if (cum->stdarg)
4240132718Skan    {
4241132718Skan      int gregno = cum->sysv_gregno;
4242132718Skan      int n_words = rs6000_arg_size (mode, type);
4243132718Skan
4244132718Skan      /* SPE vectors are put in odd registers.  */
4245132718Skan      if (n_words == 2 && (gregno & 1) == 0)
4246132718Skan	gregno += 1;
4247132718Skan
4248132718Skan      if (gregno + n_words - 1 <= GP_ARG_MAX_REG)
4249132718Skan	{
4250132718Skan	  rtx r1, r2;
4251132718Skan	  enum machine_mode m = SImode;
4252132718Skan
4253132718Skan	  r1 = gen_rtx_REG (m, gregno);
4254132718Skan	  r1 = gen_rtx_EXPR_LIST (m, r1, const0_rtx);
4255132718Skan	  r2 = gen_rtx_REG (m, gregno + 1);
4256132718Skan	  r2 = gen_rtx_EXPR_LIST (m, r2, GEN_INT (4));
4257132718Skan	  return gen_rtx_PARALLEL (mode, gen_rtvec (2, r1, r2));
4258132718Skan	}
4259132718Skan      else
4260132718Skan	return NULL_RTX;
4261132718Skan    }
4262132718Skan  else
4263132718Skan    {
4264132718Skan      if (cum->sysv_gregno <= GP_ARG_MAX_REG)
4265132718Skan	return gen_rtx_REG (mode, cum->sysv_gregno);
4266132718Skan      else
4267132718Skan	return NULL_RTX;
4268132718Skan    }
4269132718Skan}
4270132718Skan
4271132718Skan/* Determine where to place an argument in 64-bit mode with 32-bit ABI.  */
4272132718Skan
4273132718Skanstatic rtx
4274146895Skanrs6000_mixed_function_arg (enum machine_mode mode, tree type, int align_words)
4275132718Skan{
4276146895Skan  int n_units;
4277146895Skan  int i, k;
4278146895Skan  rtx rvec[GP_ARG_NUM_REG + 1];
4279132718Skan
4280146895Skan  if (align_words >= GP_ARG_NUM_REG)
4281146895Skan    return NULL_RTX;
4282132718Skan
4283146895Skan  n_units = rs6000_arg_size (mode, type);
4284132718Skan
4285146895Skan  /* Optimize the simple case where the arg fits in one gpr, except in
4286146895Skan     the case of BLKmode due to assign_parms assuming that registers are
4287146895Skan     BITS_PER_WORD wide.  */
4288146895Skan  if (n_units == 0
4289146895Skan      || (n_units == 1 && mode != BLKmode))
4290146895Skan    return gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
4291132718Skan
4292146895Skan  k = 0;
4293146895Skan  if (align_words + n_units > GP_ARG_NUM_REG)
4294146895Skan    /* Not all of the arg fits in gprs.  Say that it goes in memory too,
4295146895Skan       using a magic NULL_RTX component.
4296146895Skan       FIXME: This is not strictly correct.  Only some of the arg
4297146895Skan       belongs in memory, not all of it.  However, there isn't any way
4298146895Skan       to do this currently, apart from building rtx descriptions for
4299146895Skan       the pieces of memory we want stored.  Due to bugs in the generic
4300146895Skan       code we can't use the normal function_arg_partial_nregs scheme
4301146895Skan       with the PARALLEL arg description we emit here.
4302146895Skan       In any case, the code to store the whole arg to memory is often
4303146895Skan       more efficient than code to store pieces, and we know that space
4304146895Skan       is available in the right place for the whole arg.  */
4305146895Skan    rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX, const0_rtx);
4306132718Skan
4307146895Skan  i = 0;
4308146895Skan  do
4309146895Skan    {
4310146895Skan      rtx r = gen_rtx_REG (SImode, GP_ARG_MIN_REG + align_words);
4311146895Skan      rtx off = GEN_INT (i++ * 4);
4312146895Skan      rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, off);
4313146895Skan    }
4314146895Skan  while (++align_words < GP_ARG_NUM_REG && --n_units != 0);
4315146895Skan
4316146895Skan  return gen_rtx_PARALLEL (mode, gen_rtvec_v (k, rvec));
4317132718Skan}
4318132718Skan
431990075Sobrien/* Determine where to put an argument to a function.
432090075Sobrien   Value is zero to push the argument on the stack,
432190075Sobrien   or a hard register in which to store the argument.
432290075Sobrien
432390075Sobrien   MODE is the argument's machine mode.
432490075Sobrien   TYPE is the data type of the argument (as a tree).
432590075Sobrien    This is null for libcalls where that information may
432690075Sobrien    not be available.
432790075Sobrien   CUM is a variable of type CUMULATIVE_ARGS which gives info about
432890075Sobrien    the preceding args and about the function being called.
432990075Sobrien   NAMED is nonzero if this argument is a named parameter
433090075Sobrien    (otherwise it is an extra parameter matching an ellipsis).
433190075Sobrien
433290075Sobrien   On RS/6000 the first eight words of non-FP are normally in registers
433390075Sobrien   and the rest are pushed.  Under AIX, the first 13 FP args are in registers.
433490075Sobrien   Under V.4, the first 8 FP args are in registers.
433590075Sobrien
433690075Sobrien   If this is floating-point and no prototype is specified, we use
433790075Sobrien   both an FP and integer register (or possibly FP reg and stack).  Library
4338117395Skan   functions (when CALL_LIBCALL is set) always have the proper types for args,
433990075Sobrien   so we can pass the FP value just in one register.  emit_library_function
4340132718Skan   doesn't support PARALLEL anyway.
434190075Sobrien
4342132718Skan   Note that for args passed by reference, function_arg will be called
4343132718Skan   with MODE and TYPE set to that of the pointer to the arg, not the arg
4344132718Skan   itself.  */
4345132718Skan
434690075Sobrienstruct rtx_def *
4347132718Skanfunction_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
4348132718Skan	      tree type, int named)
434990075Sobrien{
435090075Sobrien  enum rs6000_abi abi = DEFAULT_ABI;
435190075Sobrien
435290075Sobrien  /* Return a marker to indicate whether CR1 needs to set or clear the
435390075Sobrien     bit that V.4 uses to say fp args were passed in registers.
435490075Sobrien     Assume that we don't need the marker for software floating point,
435590075Sobrien     or compiler generated library calls.  */
435690075Sobrien  if (mode == VOIDmode)
435790075Sobrien    {
435890075Sobrien      if (abi == ABI_V4
4359117395Skan	  && (cum->call_cookie & CALL_LIBCALL) == 0
4360161651Skan	  && (cum->stdarg
4361161651Skan	      || (cum->nargs_prototype < 0
4362161651Skan		  && (cum->prototype || TARGET_NO_PROTOTYPE))))
436390075Sobrien	{
4364117395Skan	  /* For the SPE, we need to crxor CR6 always.  */
4365117395Skan	  if (TARGET_SPE_ABI)
4366117395Skan	    return GEN_INT (cum->call_cookie | CALL_V4_SET_FP_ARGS);
4367117395Skan	  else if (TARGET_HARD_FLOAT && TARGET_FPRS)
4368117395Skan	    return GEN_INT (cum->call_cookie
4369117395Skan			    | ((cum->fregno == FP_ARG_MIN_REG)
4370117395Skan			       ? CALL_V4_SET_FP_ARGS
4371117395Skan			       : CALL_V4_CLEAR_FP_ARGS));
437290075Sobrien	}
437390075Sobrien
437490075Sobrien      return GEN_INT (cum->call_cookie);
437590075Sobrien    }
437690075Sobrien
4377132718Skan  if (USE_ALTIVEC_FOR_ARG_P (cum, mode, type, named))
4378132718Skan    if (TARGET_64BIT && ! cum->prototype)
4379132718Skan      {
4380132718Skan       /* Vector parameters get passed in vector register
4381132718Skan          and also in GPRs or memory, in absence of prototype.  */
4382132718Skan       int align_words;
4383132718Skan       rtx slot;
4384132718Skan       align_words = (cum->words + 1) & ~1;
4385132718Skan
4386132718Skan       if (align_words >= GP_ARG_NUM_REG)
4387132718Skan         {
4388132718Skan           slot = NULL_RTX;
4389132718Skan         }
4390132718Skan       else
4391132718Skan         {
4392132718Skan           slot = gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
4393132718Skan         }
4394132718Skan       return gen_rtx_PARALLEL (mode,
4395132718Skan                gen_rtvec (2,
4396132718Skan                           gen_rtx_EXPR_LIST (VOIDmode,
4397132718Skan                                              slot, const0_rtx),
4398132718Skan                           gen_rtx_EXPR_LIST (VOIDmode,
4399132718Skan                                              gen_rtx_REG (mode, cum->vregno),
4400132718Skan                                              const0_rtx)));
4401132718Skan      }
4402132718Skan    else
4403132718Skan      return gen_rtx_REG (mode, cum->vregno);
4404132718Skan  else if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
440590075Sobrien    {
4406132718Skan      if (named || abi == ABI_V4)
4407132718Skan	return NULL_RTX;
440890075Sobrien      else
4409132718Skan	{
4410132718Skan	  /* Vector parameters to varargs functions under AIX or Darwin
4411132718Skan	     get passed in memory and possibly also in GPRs.  */
4412146895Skan	  int align, align_words, n_words;
4413146895Skan	  enum machine_mode part_mode;
4414132718Skan
4415132718Skan	  /* Vector parameters must be 16-byte aligned.  This places them at
4416132718Skan	     2 mod 4 in terms of words in 32-bit mode, since the parameter
4417132718Skan	     save area starts at offset 24 from the stack.  In 64-bit mode,
4418132718Skan	     they just have to start on an even word, since the parameter
4419132718Skan	     save area is 16-byte aligned.  */
4420132718Skan	  if (TARGET_32BIT)
4421132718Skan	    align = (2 - cum->words) & 3;
4422132718Skan	  else
4423132718Skan	    align = cum->words & 1;
4424132718Skan	  align_words = cum->words + align;
4425132718Skan
4426132718Skan	  /* Out of registers?  Memory, then.  */
4427132718Skan	  if (align_words >= GP_ARG_NUM_REG)
4428132718Skan	    return NULL_RTX;
4429146895Skan
4430146895Skan	  if (TARGET_32BIT && TARGET_POWERPC64)
4431146895Skan	    return rs6000_mixed_function_arg (mode, type, align_words);
4432146895Skan
4433132718Skan	  /* The vector value goes in GPRs.  Only the part of the
4434132718Skan	     value in GPRs is reported here.  */
4435146895Skan	  part_mode = mode;
4436146895Skan	  n_words = rs6000_arg_size (mode, type);
4437146895Skan	  if (align_words + n_words > GP_ARG_NUM_REG)
4438132718Skan	    /* Fortunately, there are only two possibilities, the value
4439132718Skan	       is either wholly in GPRs or half in GPRs and half not.  */
4440132718Skan	    part_mode = DImode;
4441146895Skan
4442132718Skan	  return gen_rtx_REG (part_mode, GP_ARG_MIN_REG + align_words);
4443132718Skan	}
444490075Sobrien    }
4445132718Skan  else if (TARGET_SPE_ABI && TARGET_SPE && SPE_VECTOR_MODE (mode))
4446132718Skan    return rs6000_spe_function_arg (cum, mode, type);
444790075Sobrien  else if (abi == ABI_V4)
444890075Sobrien    {
4449117395Skan      if (TARGET_HARD_FLOAT && TARGET_FPRS
445090075Sobrien	  && (mode == SFmode || mode == DFmode))
445190075Sobrien	{
445290075Sobrien	  if (cum->fregno <= FP_ARG_V4_MAX_REG)
445390075Sobrien	    return gen_rtx_REG (mode, cum->fregno);
445490075Sobrien	  else
4455132718Skan	    return NULL_RTX;
445690075Sobrien	}
445790075Sobrien      else
445890075Sobrien	{
4459132718Skan	  int n_words = rs6000_arg_size (mode, type);
446090075Sobrien	  int gregno = cum->sysv_gregno;
446190075Sobrien
4462132718Skan	  /* Long long and SPE vectors are put in (r3,r4), (r5,r6),
4463132718Skan	     (r7,r8) or (r9,r10).  As does any other 2 word item such
4464132718Skan	     as complex int due to a historical mistake.  */
4465132718Skan	  if (n_words == 2)
4466132718Skan	    gregno += (1 - gregno) & 1;
446790075Sobrien
4468132718Skan	  /* Multi-reg args are not split between registers and stack.  */
4469146895Skan	  if (gregno + n_words - 1 > GP_ARG_MAX_REG)
4470132718Skan	    return NULL_RTX;
4471146895Skan
4472146895Skan	  if (TARGET_32BIT && TARGET_POWERPC64)
4473146895Skan	    return rs6000_mixed_function_arg (mode, type,
4474146895Skan					      gregno - GP_ARG_MIN_REG);
4475146895Skan	  return gen_rtx_REG (mode, gregno);
447690075Sobrien	}
447790075Sobrien    }
447890075Sobrien  else
447990075Sobrien    {
4480132718Skan      int align = function_arg_boundary (mode, type) / PARM_BOUNDARY - 1;
4481132718Skan      int align_words = cum->words + (cum->words & align);
448290075Sobrien
4483132718Skan      if (USE_FP_FOR_ARG_P (cum, mode, type))
4484132718Skan	{
4485146895Skan	  rtx rvec[GP_ARG_NUM_REG + 1];
4486146895Skan	  rtx r;
4487146895Skan	  int k;
4488132718Skan	  bool needs_psave;
4489132718Skan	  enum machine_mode fmode = mode;
4490132718Skan	  unsigned long n_fpreg = (GET_MODE_SIZE (mode) + 7) >> 3;
449190075Sobrien
4492132718Skan	  if (cum->fregno + n_fpreg > FP_ARG_MAX_REG + 1)
4493132718Skan	    {
4494132718Skan	      /* Currently, we only ever need one reg here because complex
4495132718Skan		 doubles are split.  */
4496146895Skan	      if (cum->fregno != FP_ARG_MAX_REG || fmode != TFmode)
4497132718Skan		abort ();
4498146895Skan
4499146895Skan	      /* Long double split over regs and memory.  */
4500146895Skan	      fmode = DFmode;
4501132718Skan	    }
4502132718Skan
4503132718Skan	  /* Do we also need to pass this arg in the parameter save
4504132718Skan	     area?  */
4505132718Skan	  needs_psave = (type
4506132718Skan			 && (cum->nargs_prototype <= 0
4507132718Skan			     || (DEFAULT_ABI == ABI_AIX
4508146895Skan				 && TARGET_XL_COMPAT
4509132718Skan				 && align_words >= GP_ARG_NUM_REG)));
4510132718Skan
4511132718Skan	  if (!needs_psave && mode == fmode)
4512146895Skan	    return gen_rtx_REG (fmode, cum->fregno);
4513132718Skan
4514146895Skan	  k = 0;
4515132718Skan	  if (needs_psave)
4516132718Skan	    {
4517146895Skan	      /* Describe the part that goes in gprs or the stack.
4518132718Skan		 This piece must come first, before the fprs.  */
4519132718Skan	      if (align_words < GP_ARG_NUM_REG)
4520132718Skan		{
4521132718Skan		  unsigned long n_words = rs6000_arg_size (mode, type);
4522132718Skan
4523146895Skan		  if (align_words + n_words > GP_ARG_NUM_REG
4524146895Skan		      || (TARGET_32BIT && TARGET_POWERPC64))
4525146895Skan		    {
4526146895Skan		      /* If this is partially on the stack, then we only
4527146895Skan			 include the portion actually in registers here.  */
4528146895Skan		      enum machine_mode rmode = TARGET_32BIT ? SImode : DImode;
4529146895Skan		      rtx off;
4530146895Skan		      do
4531146895Skan			{
4532146895Skan			  r = gen_rtx_REG (rmode,
4533146895Skan					   GP_ARG_MIN_REG + align_words);
4534146895Skan			  off = GEN_INT (k * GET_MODE_SIZE (rmode));
4535146895Skan			  rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, off);
4536146895Skan			}
4537146895Skan		      while (++align_words < GP_ARG_NUM_REG && --n_words != 0);
4538146895Skan		    }
4539146895Skan		  else
4540146895Skan		    {
4541146895Skan		      /* The whole arg fits in gprs.  */
4542146895Skan		      r = gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
4543146895Skan		      rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, const0_rtx);
4544146895Skan		    }
4545132718Skan		}
4546146895Skan	      else
4547146895Skan		/* It's entirely in memory.  */
4548146895Skan		rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX, const0_rtx);
4549132718Skan	    }
4550132718Skan
4551146895Skan	  /* Describe where this piece goes in the fprs.  */
4552146895Skan	  r = gen_rtx_REG (fmode, cum->fregno);
4553146895Skan	  rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, const0_rtx);
4554146895Skan
4555146895Skan	  return gen_rtx_PARALLEL (mode, gen_rtvec_v (k, rvec));
4556132718Skan	}
4557132718Skan      else if (align_words < GP_ARG_NUM_REG)
455890075Sobrien	{
4559146895Skan	  if (TARGET_32BIT && TARGET_POWERPC64)
4560146895Skan	    return rs6000_mixed_function_arg (mode, type, align_words);
456190075Sobrien
4562132718Skan	  return gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
456390075Sobrien	}
456490075Sobrien      else
456590075Sobrien	return NULL_RTX;
456690075Sobrien    }
456790075Sobrien}
456890075Sobrien
4569146895Skan/* For an arg passed partly in registers and partly in memory, this is
4570146895Skan   the number of registers used.  For args passed entirely in registers
4571146895Skan   or entirely in memory, zero.  When an arg is described by a PARALLEL,
4572146895Skan   perhaps using more than one register type, this function returns the
4573146895Skan   number of registers used by the first element of the PARALLEL.  */
457490075Sobrien
457590075Sobrienint
4576132718Skanfunction_arg_partial_nregs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
4577132718Skan			    tree type, int named)
457890075Sobrien{
4579132718Skan  int ret = 0;
4580146895Skan  int align;
4581146895Skan  int parm_offset;
4582146895Skan  int align_words;
4583132718Skan
458490075Sobrien  if (DEFAULT_ABI == ABI_V4)
458590075Sobrien    return 0;
458690075Sobrien
4587132718Skan  if (USE_ALTIVEC_FOR_ARG_P (cum, mode, type, named)
4588132718Skan      && cum->nargs_prototype >= 0)
4589132718Skan    return 0;
4590132718Skan
4591146895Skan  align = function_arg_boundary (mode, type) / PARM_BOUNDARY - 1;
4592146895Skan  parm_offset = TARGET_32BIT ? 2 : 0;
4593146895Skan  align_words = cum->words + ((parm_offset - cum->words) & align);
4594146895Skan
4595146895Skan  if (USE_FP_FOR_ARG_P (cum, mode, type)
4596146895Skan      /* If we are passing this arg in gprs as well, then this function
4597146895Skan	 should return the number of gprs (or memory) partially passed,
4598146895Skan	 *not* the number of fprs.  */
4599146895Skan      && !(type
4600146895Skan	   && (cum->nargs_prototype <= 0
4601146895Skan	       || (DEFAULT_ABI == ABI_AIX
4602146895Skan		   && TARGET_XL_COMPAT
4603146895Skan		   && align_words >= GP_ARG_NUM_REG))))
460490075Sobrien    {
4605132718Skan      if (cum->fregno + ((GET_MODE_SIZE (mode) + 7) >> 3) > FP_ARG_MAX_REG + 1)
4606146895Skan	ret = FP_ARG_MAX_REG + 1 - cum->fregno;
4607132718Skan      else if (cum->nargs_prototype >= 0)
460890075Sobrien	return 0;
460990075Sobrien    }
461090075Sobrien
4611146895Skan  if (align_words < GP_ARG_NUM_REG
4612146895Skan      && GP_ARG_NUM_REG < align_words + rs6000_arg_size (mode, type))
4613146895Skan    ret = GP_ARG_NUM_REG - align_words;
461490075Sobrien
4615132718Skan  if (ret != 0 && TARGET_DEBUG_ARG)
4616132718Skan    fprintf (stderr, "function_arg_partial_nregs: %d\n", ret);
461790075Sobrien
4618132718Skan  return ret;
461990075Sobrien}
462090075Sobrien
462190075Sobrien/* A C expression that indicates when an argument must be passed by
462290075Sobrien   reference.  If nonzero for an argument, a copy of that argument is
462390075Sobrien   made in memory and a pointer to the argument is passed instead of
462490075Sobrien   the argument itself.  The pointer is passed in whatever way is
462590075Sobrien   appropriate for passing a pointer to that type.
462690075Sobrien
4627132718Skan   Under V.4, aggregates and long double are passed by reference.
462890075Sobrien
4629132718Skan   As an extension to all 32-bit ABIs, AltiVec vectors are passed by
4630132718Skan   reference unless the AltiVec vector extension ABI is in force.
4631132718Skan
4632117395Skan   As an extension to all ABIs, variable sized types are passed by
4633117395Skan   reference.  */
4634117395Skan
463590075Sobrienint
4636132718Skanfunction_arg_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
4637132718Skan				enum machine_mode mode ATTRIBUTE_UNUSED,
4638132718Skan				tree type, int named ATTRIBUTE_UNUSED)
463990075Sobrien{
4640132718Skan  if ((DEFAULT_ABI == ABI_V4
4641132718Skan       && ((type && AGGREGATE_TYPE_P (type))
4642132718Skan	   || mode == TFmode))
4643132718Skan      || (TARGET_32BIT && !TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
4644132718Skan      || (type && int_size_in_bytes (type) < 0))
464590075Sobrien    {
464690075Sobrien      if (TARGET_DEBUG_ARG)
4647132718Skan	fprintf (stderr, "function_arg_pass_by_reference\n");
464890075Sobrien
464990075Sobrien      return 1;
465090075Sobrien    }
4651132718Skan  return 0;
465290075Sobrien}
4653132718Skan
4654132718Skanstatic void
4655132718Skanrs6000_move_block_from_reg (int regno, rtx x, int nregs)
4656132718Skan{
4657132718Skan  int i;
4658132718Skan  enum machine_mode reg_mode = TARGET_32BIT ? SImode : DImode;
4659132718Skan
4660132718Skan  if (nregs == 0)
4661132718Skan    return;
4662132718Skan
4663132718Skan    for (i = 0; i < nregs; i++)
4664132718Skan    {
4665132718Skan      rtx tem = adjust_address_nv (x, reg_mode, i*GET_MODE_SIZE(reg_mode));
4666132718Skan      if (reload_completed)
4667132718Skan      {
4668132718Skan	if (! strict_memory_address_p (reg_mode, XEXP (tem, 0)))
4669132718Skan	  tem = NULL_RTX;
4670132718Skan	else
4671132718Skan	  tem = simplify_gen_subreg (reg_mode, x, BLKmode,
4672132718Skan				     i * GET_MODE_SIZE(reg_mode));
4673132718Skan      }
4674132718Skan      else
4675132718Skan	tem = replace_equiv_address (tem, XEXP (tem, 0));
4676132718Skan
4677132718Skan      if (tem == NULL_RTX)
4678132718Skan        abort ();
4679132718Skan
4680132718Skan      emit_move_insn (tem, gen_rtx_REG (reg_mode, regno + i));
4681132718Skan    }
4682132718Skan}
4683132718Skan
468490075Sobrien
468590075Sobrien/* Perform any needed actions needed for a function that is receiving a
468690075Sobrien   variable number of arguments.
468790075Sobrien
468890075Sobrien   CUM is as above.
468990075Sobrien
469090075Sobrien   MODE and TYPE are the mode and type of the current parameter.
469190075Sobrien
469290075Sobrien   PRETEND_SIZE is a variable that should be set to the amount of stack
469390075Sobrien   that must be pushed by the prolog to pretend that our caller pushed
469490075Sobrien   it.
469590075Sobrien
469690075Sobrien   Normally, this macro will push all remaining incoming registers on the
469790075Sobrien   stack and set PRETEND_SIZE to the length of the registers pushed.  */
469890075Sobrien
4699132718Skanstatic void
4700132718Skansetup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
4701132718Skan		tree type, int *pretend_size ATTRIBUTE_UNUSED, int no_rtl)
470290075Sobrien{
470390075Sobrien  CUMULATIVE_ARGS next_cum;
470490075Sobrien  int reg_size = TARGET_32BIT ? 4 : 8;
470590075Sobrien  rtx save_area = NULL_RTX, mem;
470690075Sobrien  int first_reg_offset, set;
470790075Sobrien
4708132718Skan  /* Skip the last named argument.  */
470990075Sobrien  next_cum = *cum;
4710132718Skan  function_arg_advance (&next_cum, mode, type, 1);
471190075Sobrien
471290075Sobrien  if (DEFAULT_ABI == ABI_V4)
471390075Sobrien    {
471490075Sobrien      /* Indicate to allocate space on the stack for varargs save area.  */
471590075Sobrien      cfun->machine->sysv_varargs_p = 1;
471690075Sobrien      if (! no_rtl)
471790075Sobrien	save_area = plus_constant (virtual_stack_vars_rtx,
471890075Sobrien				   - RS6000_VARARGS_SIZE);
471990075Sobrien
472090075Sobrien      first_reg_offset = next_cum.sysv_gregno - GP_ARG_MIN_REG;
472190075Sobrien    }
472290075Sobrien  else
472390075Sobrien    {
472490075Sobrien      first_reg_offset = next_cum.words;
472590075Sobrien      save_area = virtual_incoming_args_rtx;
472690075Sobrien      cfun->machine->sysv_varargs_p = 0;
472790075Sobrien
472890075Sobrien      if (MUST_PASS_IN_STACK (mode, type))
4729132718Skan	first_reg_offset += rs6000_arg_size (TYPE_MODE (type), type);
473090075Sobrien    }
473190075Sobrien
473290075Sobrien  set = get_varargs_alias_set ();
473390075Sobrien  if (! no_rtl && first_reg_offset < GP_ARG_NUM_REG)
473490075Sobrien    {
473590075Sobrien      mem = gen_rtx_MEM (BLKmode,
473690075Sobrien		         plus_constant (save_area,
473790075Sobrien					first_reg_offset * reg_size)),
473890075Sobrien      set_mem_alias_set (mem, set);
473990075Sobrien      set_mem_align (mem, BITS_PER_WORD);
474090075Sobrien
4741132718Skan      rs6000_move_block_from_reg (GP_ARG_MIN_REG + first_reg_offset, mem,
4742132718Skan			          GP_ARG_NUM_REG - first_reg_offset);
474390075Sobrien    }
474490075Sobrien
474590075Sobrien  /* Save FP registers if needed.  */
474690075Sobrien  if (DEFAULT_ABI == ABI_V4
4747117395Skan      && TARGET_HARD_FLOAT && TARGET_FPRS
4748117395Skan      && ! no_rtl
474990075Sobrien      && next_cum.fregno <= FP_ARG_V4_MAX_REG)
475090075Sobrien    {
475190075Sobrien      int fregno = next_cum.fregno;
475290075Sobrien      rtx cr1 = gen_rtx_REG (CCmode, CR1_REGNO);
475390075Sobrien      rtx lab = gen_label_rtx ();
475490075Sobrien      int off = (GP_ARG_NUM_REG * reg_size) + ((fregno - FP_ARG_MIN_REG) * 8);
475590075Sobrien
475690075Sobrien      emit_jump_insn (gen_rtx_SET (VOIDmode,
475790075Sobrien				   pc_rtx,
475890075Sobrien				   gen_rtx_IF_THEN_ELSE (VOIDmode,
475990075Sobrien					    gen_rtx_NE (VOIDmode, cr1,
476090075Sobrien						        const0_rtx),
476190075Sobrien					    gen_rtx_LABEL_REF (VOIDmode, lab),
476290075Sobrien					    pc_rtx)));
476390075Sobrien
476490075Sobrien      while (fregno <= FP_ARG_V4_MAX_REG)
476590075Sobrien	{
476690075Sobrien	  mem = gen_rtx_MEM (DFmode, plus_constant (save_area, off));
476790075Sobrien          set_mem_alias_set (mem, set);
4768146895Skan	  set_mem_align (mem, GET_MODE_ALIGNMENT (DFmode));
476990075Sobrien	  emit_move_insn (mem, gen_rtx_REG (DFmode, fregno));
477090075Sobrien	  fregno++;
477190075Sobrien	  off += 8;
477290075Sobrien	}
477390075Sobrien
477490075Sobrien      emit_label (lab);
477590075Sobrien    }
477690075Sobrien}
477790075Sobrien
477890075Sobrien/* Create the va_list data type.  */
477990075Sobrien
4780132718Skanstatic tree
4781132718Skanrs6000_build_builtin_va_list (void)
478290075Sobrien{
4783132718Skan  tree f_gpr, f_fpr, f_res, f_ovf, f_sav, record, type_decl;
478490075Sobrien
478590075Sobrien  /* For AIX, prefer 'char *' because that's what the system
478690075Sobrien     header files like.  */
478790075Sobrien  if (DEFAULT_ABI != ABI_V4)
478890075Sobrien    return build_pointer_type (char_type_node);
478990075Sobrien
4790117395Skan  record = (*lang_hooks.types.make_type) (RECORD_TYPE);
479190075Sobrien  type_decl = build_decl (TYPE_DECL, get_identifier ("__va_list_tag"), record);
479290075Sobrien
479390075Sobrien  f_gpr = build_decl (FIELD_DECL, get_identifier ("gpr"),
479490075Sobrien		      unsigned_char_type_node);
479590075Sobrien  f_fpr = build_decl (FIELD_DECL, get_identifier ("fpr"),
479690075Sobrien		      unsigned_char_type_node);
4797132718Skan  /* Give the two bytes of padding a name, so that -Wpadded won't warn on
4798132718Skan     every user file.  */
4799132718Skan  f_res = build_decl (FIELD_DECL, get_identifier ("reserved"),
4800132718Skan		      short_unsigned_type_node);
480190075Sobrien  f_ovf = build_decl (FIELD_DECL, get_identifier ("overflow_arg_area"),
480290075Sobrien		      ptr_type_node);
480390075Sobrien  f_sav = build_decl (FIELD_DECL, get_identifier ("reg_save_area"),
480490075Sobrien		      ptr_type_node);
480590075Sobrien
480690075Sobrien  DECL_FIELD_CONTEXT (f_gpr) = record;
480790075Sobrien  DECL_FIELD_CONTEXT (f_fpr) = record;
4808132718Skan  DECL_FIELD_CONTEXT (f_res) = record;
480990075Sobrien  DECL_FIELD_CONTEXT (f_ovf) = record;
481090075Sobrien  DECL_FIELD_CONTEXT (f_sav) = record;
481190075Sobrien
481290075Sobrien  TREE_CHAIN (record) = type_decl;
481390075Sobrien  TYPE_NAME (record) = type_decl;
481490075Sobrien  TYPE_FIELDS (record) = f_gpr;
481590075Sobrien  TREE_CHAIN (f_gpr) = f_fpr;
4816132718Skan  TREE_CHAIN (f_fpr) = f_res;
4817132718Skan  TREE_CHAIN (f_res) = f_ovf;
481890075Sobrien  TREE_CHAIN (f_ovf) = f_sav;
481990075Sobrien
482090075Sobrien  layout_type (record);
482190075Sobrien
482290075Sobrien  /* The correct type is an array type of one element.  */
482390075Sobrien  return build_array_type (record, build_index_type (size_zero_node));
482490075Sobrien}
482590075Sobrien
482690075Sobrien/* Implement va_start.  */
482790075Sobrien
482890075Sobrienvoid
4829132718Skanrs6000_va_start (tree valist, rtx nextarg)
483090075Sobrien{
483190075Sobrien  HOST_WIDE_INT words, n_gpr, n_fpr;
4832132718Skan  tree f_gpr, f_fpr, f_res, f_ovf, f_sav;
483390075Sobrien  tree gpr, fpr, ovf, sav, t;
483490075Sobrien
483590075Sobrien  /* Only SVR4 needs something special.  */
483690075Sobrien  if (DEFAULT_ABI != ABI_V4)
483790075Sobrien    {
4838117395Skan      std_expand_builtin_va_start (valist, nextarg);
483990075Sobrien      return;
484090075Sobrien    }
484190075Sobrien
484290075Sobrien  f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
484390075Sobrien  f_fpr = TREE_CHAIN (f_gpr);
4844132718Skan  f_res = TREE_CHAIN (f_fpr);
4845132718Skan  f_ovf = TREE_CHAIN (f_res);
484690075Sobrien  f_sav = TREE_CHAIN (f_ovf);
484790075Sobrien
484890075Sobrien  valist = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)), valist);
484990075Sobrien  gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
485090075Sobrien  fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
485190075Sobrien  ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf);
485290075Sobrien  sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav);
485390075Sobrien
485490075Sobrien  /* Count number of gp and fp argument registers used.  */
485590075Sobrien  words = current_function_args_info.words;
485690075Sobrien  n_gpr = current_function_args_info.sysv_gregno - GP_ARG_MIN_REG;
485790075Sobrien  n_fpr = current_function_args_info.fregno - FP_ARG_MIN_REG;
485890075Sobrien
485990075Sobrien  if (TARGET_DEBUG_ARG)
4860132718Skan    fprintf (stderr, "va_start: words = "HOST_WIDE_INT_PRINT_DEC", n_gpr = "
4861132718Skan	     HOST_WIDE_INT_PRINT_DEC", n_fpr = "HOST_WIDE_INT_PRINT_DEC"\n",
4862132718Skan	     words, n_gpr, n_fpr);
486390075Sobrien
486490075Sobrien  t = build (MODIFY_EXPR, TREE_TYPE (gpr), gpr, build_int_2 (n_gpr, 0));
486590075Sobrien  TREE_SIDE_EFFECTS (t) = 1;
486690075Sobrien  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
486790075Sobrien
486890075Sobrien  t = build (MODIFY_EXPR, TREE_TYPE (fpr), fpr, build_int_2 (n_fpr, 0));
486990075Sobrien  TREE_SIDE_EFFECTS (t) = 1;
487090075Sobrien  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
487190075Sobrien
487290075Sobrien  /* Find the overflow area.  */
487390075Sobrien  t = make_tree (TREE_TYPE (ovf), virtual_incoming_args_rtx);
487490075Sobrien  if (words != 0)
487590075Sobrien    t = build (PLUS_EXPR, TREE_TYPE (ovf), t,
487690075Sobrien	       build_int_2 (words * UNITS_PER_WORD, 0));
487790075Sobrien  t = build (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t);
487890075Sobrien  TREE_SIDE_EFFECTS (t) = 1;
487990075Sobrien  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
488090075Sobrien
488190075Sobrien  /* Find the register save area.  */
488290075Sobrien  t = make_tree (TREE_TYPE (sav), virtual_stack_vars_rtx);
488390075Sobrien  t = build (PLUS_EXPR, TREE_TYPE (sav), t,
488490075Sobrien	     build_int_2 (-RS6000_VARARGS_SIZE, -1));
488590075Sobrien  t = build (MODIFY_EXPR, TREE_TYPE (sav), sav, t);
488690075Sobrien  TREE_SIDE_EFFECTS (t) = 1;
488790075Sobrien  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
488890075Sobrien}
488990075Sobrien
489090075Sobrien/* Implement va_arg.  */
489190075Sobrien
489290075Sobrienrtx
4893132718Skanrs6000_va_arg (tree valist, tree type)
489490075Sobrien{
4895132718Skan  tree f_gpr, f_fpr, f_res, f_ovf, f_sav;
489690075Sobrien  tree gpr, fpr, ovf, sav, reg, t, u;
489790075Sobrien  int indirect_p, size, rsize, n_reg, sav_ofs, sav_scale;
489890075Sobrien  rtx lab_false, lab_over, addr_rtx, r;
4899132718Skan  int align;
490090075Sobrien
490190075Sobrien  if (DEFAULT_ABI != ABI_V4)
4902117395Skan    {
4903132718Skan      /* Variable sized types are passed by reference, as are AltiVec
4904132718Skan	 vectors when 32-bit and not using the AltiVec ABI extension.  */
4905132718Skan      if (int_size_in_bytes (type) < 0
4906132718Skan	  || (TARGET_32BIT
4907132718Skan	      && !TARGET_ALTIVEC_ABI
4908132718Skan	      && ALTIVEC_VECTOR_MODE (TYPE_MODE (type))))
4909117395Skan	{
4910117395Skan	  u = build_pointer_type (type);
491190075Sobrien
4912117395Skan	  /* Args grow upward.  */
4913117395Skan	  t = build (POSTINCREMENT_EXPR, TREE_TYPE (valist), valist,
4914117395Skan		     build_int_2 (POINTER_SIZE / BITS_PER_UNIT, 0));
4915117395Skan	  TREE_SIDE_EFFECTS (t) = 1;
4916117395Skan
4917117395Skan	  t = build1 (NOP_EXPR, build_pointer_type (u), t);
4918117395Skan	  TREE_SIDE_EFFECTS (t) = 1;
4919117395Skan
4920117395Skan	  t = build1 (INDIRECT_REF, u, t);
4921117395Skan	  TREE_SIDE_EFFECTS (t) = 1;
4922117395Skan
4923117395Skan	  return expand_expr (t, NULL_RTX, VOIDmode, EXPAND_NORMAL);
4924117395Skan	}
4925132718Skan      if (targetm.calls.split_complex_arg
4926132718Skan	  && TREE_CODE (type) == COMPLEX_TYPE)
4927132718Skan	{
4928132718Skan	  tree elem_type = TREE_TYPE (type);
4929132718Skan	  enum machine_mode elem_mode = TYPE_MODE (elem_type);
4930132718Skan	  int elem_size = GET_MODE_SIZE (elem_mode);
4931132718Skan
4932132718Skan	  if (elem_size < UNITS_PER_WORD)
4933132718Skan	    {
4934132718Skan	      rtx real_part, imag_part, dest_real, rr;
4935132718Skan
4936132718Skan	      real_part = rs6000_va_arg (valist, elem_type);
4937132718Skan	      imag_part = rs6000_va_arg (valist, elem_type);
4938132718Skan
4939132718Skan	      /* We're not returning the value here, but the address.
4940132718Skan		 real_part and imag_part are not contiguous, and we know
4941132718Skan		 there is space available to pack real_part next to
4942132718Skan		 imag_part.  float _Complex is not promoted to
4943132718Skan		 double _Complex by the default promotion rules that
4944132718Skan		 promote float to double.  */
4945132718Skan	      if (2 * elem_size > UNITS_PER_WORD)
4946132718Skan		abort ();
4947132718Skan
4948132718Skan	      real_part = gen_rtx_MEM (elem_mode, real_part);
4949132718Skan	      imag_part = gen_rtx_MEM (elem_mode, imag_part);
4950132718Skan
4951132718Skan	      dest_real = adjust_address (imag_part, elem_mode, -elem_size);
4952132718Skan	      rr = gen_reg_rtx (elem_mode);
4953132718Skan	      emit_move_insn (rr, real_part);
4954132718Skan	      emit_move_insn (dest_real, rr);
4955132718Skan
4956132718Skan	      return XEXP (dest_real, 0);
4957132718Skan	    }
4958132718Skan	}
4959132718Skan
4960132718Skan      return std_expand_builtin_va_arg (valist, type);
4961117395Skan    }
4962117395Skan
496390075Sobrien  f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
496490075Sobrien  f_fpr = TREE_CHAIN (f_gpr);
4965132718Skan  f_res = TREE_CHAIN (f_fpr);
4966132718Skan  f_ovf = TREE_CHAIN (f_res);
496790075Sobrien  f_sav = TREE_CHAIN (f_ovf);
496890075Sobrien
496990075Sobrien  valist = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)), valist);
497090075Sobrien  gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
497190075Sobrien  fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
497290075Sobrien  ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf);
497390075Sobrien  sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav);
497490075Sobrien
497590075Sobrien  size = int_size_in_bytes (type);
4976132718Skan  rsize = (size + 3) / 4;
4977132718Skan  align = 1;
497890075Sobrien
4979132718Skan  if (AGGREGATE_TYPE_P (type)
4980132718Skan      || TYPE_MODE (type) == TFmode
4981132718Skan      || (!TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (TYPE_MODE (type))))
498290075Sobrien    {
4983132718Skan      /* Aggregates, long doubles, and AltiVec vectors are passed by
4984132718Skan	 reference.  */
498590075Sobrien      indirect_p = 1;
498690075Sobrien      reg = gpr;
498790075Sobrien      n_reg = 1;
498890075Sobrien      sav_ofs = 0;
498990075Sobrien      sav_scale = 4;
4990132718Skan      size = 4;
499196263Sobrien      rsize = 1;
499290075Sobrien    }
4993132718Skan  else if (TARGET_HARD_FLOAT && TARGET_FPRS
4994132718Skan	   && (TYPE_MODE (type) == SFmode || TYPE_MODE (type) == DFmode))
499590075Sobrien    {
499690075Sobrien      /* FP args go in FP registers, if present.  */
499790075Sobrien      indirect_p = 0;
499890075Sobrien      reg = fpr;
499990075Sobrien      n_reg = 1;
500090075Sobrien      sav_ofs = 8*4;
500190075Sobrien      sav_scale = 8;
5002132718Skan      if (TYPE_MODE (type) == DFmode)
5003132718Skan	align = 8;
500490075Sobrien    }
500590075Sobrien  else
500690075Sobrien    {
500790075Sobrien      /* Otherwise into GP registers.  */
500890075Sobrien      indirect_p = 0;
500990075Sobrien      reg = gpr;
501090075Sobrien      n_reg = rsize;
501190075Sobrien      sav_ofs = 0;
501290075Sobrien      sav_scale = 4;
5013132718Skan      if (n_reg == 2)
5014132718Skan	align = 8;
501590075Sobrien    }
501690075Sobrien
5017132718Skan  /* Pull the value out of the saved registers....  */
501890075Sobrien
5019132718Skan  lab_over = NULL_RTX;
502090075Sobrien  addr_rtx = gen_reg_rtx (Pmode);
502190075Sobrien
5022132718Skan  /*  AltiVec vectors never go in registers when -mabi=altivec.  */
5023132718Skan  if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (TYPE_MODE (type)))
5024132718Skan    align = 16;
5025132718Skan  else
502696263Sobrien    {
5027132718Skan      lab_false = gen_label_rtx ();
5028132718Skan      lab_over = gen_label_rtx ();
502990075Sobrien
5030132718Skan      /* Long long and SPE vectors are aligned in the registers.
5031132718Skan	 As are any other 2 gpr item such as complex int due to a
5032132718Skan	 historical mistake.  */
5033132718Skan      u = reg;
5034132718Skan      if (n_reg == 2)
503596263Sobrien	{
503696263Sobrien	  u = build (BIT_AND_EXPR, TREE_TYPE (reg), reg,
503796263Sobrien		     build_int_2 (n_reg - 1, 0));
5038132718Skan	  u = build (POSTINCREMENT_EXPR, TREE_TYPE (reg), reg, u);
503996263Sobrien	  TREE_SIDE_EFFECTS (u) = 1;
504096263Sobrien	}
504196263Sobrien
5042132718Skan      emit_cmp_and_jump_insns
5043132718Skan	(expand_expr (u, NULL_RTX, QImode, EXPAND_NORMAL),
5044132718Skan	 GEN_INT (8 - n_reg + 1), GE, const1_rtx, QImode, 1,
5045132718Skan	 lab_false);
5046132718Skan
5047132718Skan      t = sav;
504896263Sobrien      if (sav_ofs)
504996263Sobrien	t = build (PLUS_EXPR, ptr_type_node, sav, build_int_2 (sav_ofs, 0));
505096263Sobrien
505196263Sobrien      u = build (POSTINCREMENT_EXPR, TREE_TYPE (reg), reg,
505296263Sobrien		 build_int_2 (n_reg, 0));
505390075Sobrien      TREE_SIDE_EFFECTS (u) = 1;
505490075Sobrien
505596263Sobrien      u = build1 (CONVERT_EXPR, integer_type_node, u);
505696263Sobrien      TREE_SIDE_EFFECTS (u) = 1;
505790075Sobrien
505896263Sobrien      u = build (MULT_EXPR, integer_type_node, u, build_int_2 (sav_scale, 0));
505996263Sobrien      TREE_SIDE_EFFECTS (u) = 1;
506090075Sobrien
506196263Sobrien      t = build (PLUS_EXPR, ptr_type_node, t, u);
506296263Sobrien      TREE_SIDE_EFFECTS (t) = 1;
506390075Sobrien
506496263Sobrien      r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
506596263Sobrien      if (r != addr_rtx)
506696263Sobrien	emit_move_insn (addr_rtx, r);
506790075Sobrien
506896263Sobrien      emit_jump_insn (gen_jump (lab_over));
506996263Sobrien      emit_barrier ();
5070132718Skan
5071132718Skan      emit_label (lab_false);
5072132718Skan      if (n_reg > 2)
5073132718Skan	{
5074132718Skan	  /* Ensure that we don't find any more args in regs.
5075132718Skan	     Alignment has taken care of the n_reg == 2 case.  */
5076132718Skan	  t = build (MODIFY_EXPR, TREE_TYPE (reg), reg, build_int_2 (8, 0));
5077132718Skan	  TREE_SIDE_EFFECTS (t) = 1;
5078132718Skan	  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
5079132718Skan	}
508096263Sobrien    }
508190075Sobrien
508290075Sobrien  /* ... otherwise out of the overflow area.  */
508390075Sobrien
508490075Sobrien  /* Care for on-stack alignment if needed.  */
5085132718Skan  t = ovf;
5086132718Skan  if (align != 1)
508790075Sobrien    {
5088132718Skan      t = build (PLUS_EXPR, TREE_TYPE (t), t, build_int_2 (align - 1, 0));
5089132718Skan      t = build (BIT_AND_EXPR, TREE_TYPE (t), t, build_int_2 (-align, -1));
509090075Sobrien    }
509190075Sobrien  t = save_expr (t);
509290075Sobrien
509390075Sobrien  r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
509490075Sobrien  if (r != addr_rtx)
509590075Sobrien    emit_move_insn (addr_rtx, r);
509690075Sobrien
509790075Sobrien  t = build (PLUS_EXPR, TREE_TYPE (t), t, build_int_2 (size, 0));
509890075Sobrien  t = build (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t);
509990075Sobrien  TREE_SIDE_EFFECTS (t) = 1;
510090075Sobrien  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
510190075Sobrien
5102132718Skan  if (lab_over)
5103132718Skan    emit_label (lab_over);
510490075Sobrien
510590075Sobrien  if (indirect_p)
510690075Sobrien    {
510790075Sobrien      r = gen_rtx_MEM (Pmode, addr_rtx);
510890075Sobrien      set_mem_alias_set (r, get_varargs_alias_set ());
510990075Sobrien      emit_move_insn (addr_rtx, r);
511090075Sobrien    }
511190075Sobrien
511290075Sobrien  return addr_rtx;
511390075Sobrien}
511490075Sobrien
511590075Sobrien/* Builtins.  */
511690075Sobrien
5117117395Skan#define def_builtin(MASK, NAME, TYPE, CODE)			\
5118117395Skando {								\
5119117395Skan  if ((MASK) & target_flags)					\
5120117395Skan    builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD,	\
5121117395Skan		      NULL, NULL_TREE);				\
512290075Sobrien} while (0)
512390075Sobrien
512490075Sobrien/* Simple ternary operations: VECd = foo (VECa, VECb, VECc).  */
512590075Sobrien
512690075Sobrienstatic const struct builtin_description bdesc_3arg[] =
512790075Sobrien{
512890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmaddfp, "__builtin_altivec_vmaddfp", ALTIVEC_BUILTIN_VMADDFP },
512990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmhaddshs, "__builtin_altivec_vmhaddshs", ALTIVEC_BUILTIN_VMHADDSHS },
513090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmhraddshs, "__builtin_altivec_vmhraddshs", ALTIVEC_BUILTIN_VMHRADDSHS },
513190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmladduhm, "__builtin_altivec_vmladduhm", ALTIVEC_BUILTIN_VMLADDUHM},
513290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmsumubm, "__builtin_altivec_vmsumubm", ALTIVEC_BUILTIN_VMSUMUBM },
513390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmsummbm, "__builtin_altivec_vmsummbm", ALTIVEC_BUILTIN_VMSUMMBM },
513490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmsumuhm, "__builtin_altivec_vmsumuhm", ALTIVEC_BUILTIN_VMSUMUHM },
513590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmsumshm, "__builtin_altivec_vmsumshm", ALTIVEC_BUILTIN_VMSUMSHM },
513690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmsumuhs, "__builtin_altivec_vmsumuhs", ALTIVEC_BUILTIN_VMSUMUHS },
513790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmsumshs, "__builtin_altivec_vmsumshs", ALTIVEC_BUILTIN_VMSUMSHS },
513890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vnmsubfp, "__builtin_altivec_vnmsubfp", ALTIVEC_BUILTIN_VNMSUBFP },
513990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vperm_4sf, "__builtin_altivec_vperm_4sf", ALTIVEC_BUILTIN_VPERM_4SF },
514090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vperm_4si, "__builtin_altivec_vperm_4si", ALTIVEC_BUILTIN_VPERM_4SI },
514190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vperm_8hi, "__builtin_altivec_vperm_8hi", ALTIVEC_BUILTIN_VPERM_8HI },
514290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vperm_16qi, "__builtin_altivec_vperm_16qi", ALTIVEC_BUILTIN_VPERM_16QI },
514390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsel_4sf, "__builtin_altivec_vsel_4sf", ALTIVEC_BUILTIN_VSEL_4SF },
514490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsel_4si, "__builtin_altivec_vsel_4si", ALTIVEC_BUILTIN_VSEL_4SI },
514590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsel_8hi, "__builtin_altivec_vsel_8hi", ALTIVEC_BUILTIN_VSEL_8HI },
514690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsel_16qi, "__builtin_altivec_vsel_16qi", ALTIVEC_BUILTIN_VSEL_16QI },
514790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsldoi_16qi, "__builtin_altivec_vsldoi_16qi", ALTIVEC_BUILTIN_VSLDOI_16QI },
514890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsldoi_8hi, "__builtin_altivec_vsldoi_8hi", ALTIVEC_BUILTIN_VSLDOI_8HI },
514990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsldoi_4si, "__builtin_altivec_vsldoi_4si", ALTIVEC_BUILTIN_VSLDOI_4SI },
515090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsldoi_4sf, "__builtin_altivec_vsldoi_4sf", ALTIVEC_BUILTIN_VSLDOI_4SF },
515190075Sobrien};
515290075Sobrien
515390075Sobrien/* DST operations: void foo (void *, const int, const char).  */
515490075Sobrien
515590075Sobrienstatic const struct builtin_description bdesc_dst[] =
515690075Sobrien{
515790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_dst, "__builtin_altivec_dst", ALTIVEC_BUILTIN_DST },
515890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_dstt, "__builtin_altivec_dstt", ALTIVEC_BUILTIN_DSTT },
515990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_dstst, "__builtin_altivec_dstst", ALTIVEC_BUILTIN_DSTST },
516090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_dststt, "__builtin_altivec_dststt", ALTIVEC_BUILTIN_DSTSTT }
516190075Sobrien};
516290075Sobrien
516390075Sobrien/* Simple binary operations: VECc = foo (VECa, VECb).  */
516490075Sobrien
5165117395Skanstatic struct builtin_description bdesc_2arg[] =
516690075Sobrien{
516790075Sobrien  { MASK_ALTIVEC, CODE_FOR_addv16qi3, "__builtin_altivec_vaddubm", ALTIVEC_BUILTIN_VADDUBM },
516890075Sobrien  { MASK_ALTIVEC, CODE_FOR_addv8hi3, "__builtin_altivec_vadduhm", ALTIVEC_BUILTIN_VADDUHM },
516990075Sobrien  { MASK_ALTIVEC, CODE_FOR_addv4si3, "__builtin_altivec_vadduwm", ALTIVEC_BUILTIN_VADDUWM },
517090075Sobrien  { MASK_ALTIVEC, CODE_FOR_addv4sf3, "__builtin_altivec_vaddfp", ALTIVEC_BUILTIN_VADDFP },
517190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vaddcuw, "__builtin_altivec_vaddcuw", ALTIVEC_BUILTIN_VADDCUW },
517290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vaddubs, "__builtin_altivec_vaddubs", ALTIVEC_BUILTIN_VADDUBS },
517390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vaddsbs, "__builtin_altivec_vaddsbs", ALTIVEC_BUILTIN_VADDSBS },
517490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vadduhs, "__builtin_altivec_vadduhs", ALTIVEC_BUILTIN_VADDUHS },
517590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vaddshs, "__builtin_altivec_vaddshs", ALTIVEC_BUILTIN_VADDSHS },
517690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vadduws, "__builtin_altivec_vadduws", ALTIVEC_BUILTIN_VADDUWS },
517790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vaddsws, "__builtin_altivec_vaddsws", ALTIVEC_BUILTIN_VADDSWS },
517890075Sobrien  { MASK_ALTIVEC, CODE_FOR_andv4si3, "__builtin_altivec_vand", ALTIVEC_BUILTIN_VAND },
517990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vandc, "__builtin_altivec_vandc", ALTIVEC_BUILTIN_VANDC },
518090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vavgub, "__builtin_altivec_vavgub", ALTIVEC_BUILTIN_VAVGUB },
518190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vavgsb, "__builtin_altivec_vavgsb", ALTIVEC_BUILTIN_VAVGSB },
518290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vavguh, "__builtin_altivec_vavguh", ALTIVEC_BUILTIN_VAVGUH },
518390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vavgsh, "__builtin_altivec_vavgsh", ALTIVEC_BUILTIN_VAVGSH },
518490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vavguw, "__builtin_altivec_vavguw", ALTIVEC_BUILTIN_VAVGUW },
518590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vavgsw, "__builtin_altivec_vavgsw", ALTIVEC_BUILTIN_VAVGSW },
518690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcfux, "__builtin_altivec_vcfux", ALTIVEC_BUILTIN_VCFUX },
518790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcfsx, "__builtin_altivec_vcfsx", ALTIVEC_BUILTIN_VCFSX },
518890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpbfp, "__builtin_altivec_vcmpbfp", ALTIVEC_BUILTIN_VCMPBFP },
518990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpequb, "__builtin_altivec_vcmpequb", ALTIVEC_BUILTIN_VCMPEQUB },
519090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpequh, "__builtin_altivec_vcmpequh", ALTIVEC_BUILTIN_VCMPEQUH },
519190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpequw, "__builtin_altivec_vcmpequw", ALTIVEC_BUILTIN_VCMPEQUW },
519290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpeqfp, "__builtin_altivec_vcmpeqfp", ALTIVEC_BUILTIN_VCMPEQFP },
519390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpgefp, "__builtin_altivec_vcmpgefp", ALTIVEC_BUILTIN_VCMPGEFP },
519490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpgtub, "__builtin_altivec_vcmpgtub", ALTIVEC_BUILTIN_VCMPGTUB },
519590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpgtsb, "__builtin_altivec_vcmpgtsb", ALTIVEC_BUILTIN_VCMPGTSB },
519690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpgtuh, "__builtin_altivec_vcmpgtuh", ALTIVEC_BUILTIN_VCMPGTUH },
519790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpgtsh, "__builtin_altivec_vcmpgtsh", ALTIVEC_BUILTIN_VCMPGTSH },
519890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpgtuw, "__builtin_altivec_vcmpgtuw", ALTIVEC_BUILTIN_VCMPGTUW },
519990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpgtsw, "__builtin_altivec_vcmpgtsw", ALTIVEC_BUILTIN_VCMPGTSW },
520090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpgtfp, "__builtin_altivec_vcmpgtfp", ALTIVEC_BUILTIN_VCMPGTFP },
520190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vctsxs, "__builtin_altivec_vctsxs", ALTIVEC_BUILTIN_VCTSXS },
520290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vctuxs, "__builtin_altivec_vctuxs", ALTIVEC_BUILTIN_VCTUXS },
520390075Sobrien  { MASK_ALTIVEC, CODE_FOR_umaxv16qi3, "__builtin_altivec_vmaxub", ALTIVEC_BUILTIN_VMAXUB },
520490075Sobrien  { MASK_ALTIVEC, CODE_FOR_smaxv16qi3, "__builtin_altivec_vmaxsb", ALTIVEC_BUILTIN_VMAXSB },
5205117395Skan  { MASK_ALTIVEC, CODE_FOR_umaxv8hi3, "__builtin_altivec_vmaxuh", ALTIVEC_BUILTIN_VMAXUH },
5206117395Skan  { MASK_ALTIVEC, CODE_FOR_smaxv8hi3, "__builtin_altivec_vmaxsh", ALTIVEC_BUILTIN_VMAXSH },
5207117395Skan  { MASK_ALTIVEC, CODE_FOR_umaxv4si3, "__builtin_altivec_vmaxuw", ALTIVEC_BUILTIN_VMAXUW },
5208117395Skan  { MASK_ALTIVEC, CODE_FOR_smaxv4si3, "__builtin_altivec_vmaxsw", ALTIVEC_BUILTIN_VMAXSW },
5209117395Skan  { MASK_ALTIVEC, CODE_FOR_smaxv4sf3, "__builtin_altivec_vmaxfp", ALTIVEC_BUILTIN_VMAXFP },
521090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmrghb, "__builtin_altivec_vmrghb", ALTIVEC_BUILTIN_VMRGHB },
521190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmrghh, "__builtin_altivec_vmrghh", ALTIVEC_BUILTIN_VMRGHH },
521290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmrghw, "__builtin_altivec_vmrghw", ALTIVEC_BUILTIN_VMRGHW },
521390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmrglb, "__builtin_altivec_vmrglb", ALTIVEC_BUILTIN_VMRGLB },
521490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmrglh, "__builtin_altivec_vmrglh", ALTIVEC_BUILTIN_VMRGLH },
521590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmrglw, "__builtin_altivec_vmrglw", ALTIVEC_BUILTIN_VMRGLW },
521690075Sobrien  { MASK_ALTIVEC, CODE_FOR_uminv16qi3, "__builtin_altivec_vminub", ALTIVEC_BUILTIN_VMINUB },
521790075Sobrien  { MASK_ALTIVEC, CODE_FOR_sminv16qi3, "__builtin_altivec_vminsb", ALTIVEC_BUILTIN_VMINSB },
521890075Sobrien  { MASK_ALTIVEC, CODE_FOR_uminv8hi3, "__builtin_altivec_vminuh", ALTIVEC_BUILTIN_VMINUH },
521990075Sobrien  { MASK_ALTIVEC, CODE_FOR_sminv8hi3, "__builtin_altivec_vminsh", ALTIVEC_BUILTIN_VMINSH },
522090075Sobrien  { MASK_ALTIVEC, CODE_FOR_uminv4si3, "__builtin_altivec_vminuw", ALTIVEC_BUILTIN_VMINUW },
522190075Sobrien  { MASK_ALTIVEC, CODE_FOR_sminv4si3, "__builtin_altivec_vminsw", ALTIVEC_BUILTIN_VMINSW },
522290075Sobrien  { MASK_ALTIVEC, CODE_FOR_sminv4sf3, "__builtin_altivec_vminfp", ALTIVEC_BUILTIN_VMINFP },
522390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmuleub, "__builtin_altivec_vmuleub", ALTIVEC_BUILTIN_VMULEUB },
522490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmulesb, "__builtin_altivec_vmulesb", ALTIVEC_BUILTIN_VMULESB },
522590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmuleuh, "__builtin_altivec_vmuleuh", ALTIVEC_BUILTIN_VMULEUH },
522690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmulesh, "__builtin_altivec_vmulesh", ALTIVEC_BUILTIN_VMULESH },
522790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmuloub, "__builtin_altivec_vmuloub", ALTIVEC_BUILTIN_VMULOUB },
522890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmulosb, "__builtin_altivec_vmulosb", ALTIVEC_BUILTIN_VMULOSB },
522990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmulouh, "__builtin_altivec_vmulouh", ALTIVEC_BUILTIN_VMULOUH },
523090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmulosh, "__builtin_altivec_vmulosh", ALTIVEC_BUILTIN_VMULOSH },
523190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vnor, "__builtin_altivec_vnor", ALTIVEC_BUILTIN_VNOR },
523290075Sobrien  { MASK_ALTIVEC, CODE_FOR_iorv4si3, "__builtin_altivec_vor", ALTIVEC_BUILTIN_VOR },
523390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkuhum, "__builtin_altivec_vpkuhum", ALTIVEC_BUILTIN_VPKUHUM },
523490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkuwum, "__builtin_altivec_vpkuwum", ALTIVEC_BUILTIN_VPKUWUM },
523590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkpx, "__builtin_altivec_vpkpx", ALTIVEC_BUILTIN_VPKPX },
523690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkuhss, "__builtin_altivec_vpkuhss", ALTIVEC_BUILTIN_VPKUHSS },
523790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkshss, "__builtin_altivec_vpkshss", ALTIVEC_BUILTIN_VPKSHSS },
523890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkuwss, "__builtin_altivec_vpkuwss", ALTIVEC_BUILTIN_VPKUWSS },
523990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkswss, "__builtin_altivec_vpkswss", ALTIVEC_BUILTIN_VPKSWSS },
524090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkuhus, "__builtin_altivec_vpkuhus", ALTIVEC_BUILTIN_VPKUHUS },
524190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkshus, "__builtin_altivec_vpkshus", ALTIVEC_BUILTIN_VPKSHUS },
524290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkuwus, "__builtin_altivec_vpkuwus", ALTIVEC_BUILTIN_VPKUWUS },
524390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkswus, "__builtin_altivec_vpkswus", ALTIVEC_BUILTIN_VPKSWUS },
524490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vrlb, "__builtin_altivec_vrlb", ALTIVEC_BUILTIN_VRLB },
524590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vrlh, "__builtin_altivec_vrlh", ALTIVEC_BUILTIN_VRLH },
524690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vrlw, "__builtin_altivec_vrlw", ALTIVEC_BUILTIN_VRLW },
524790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vslb, "__builtin_altivec_vslb", ALTIVEC_BUILTIN_VSLB },
524890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vslh, "__builtin_altivec_vslh", ALTIVEC_BUILTIN_VSLH },
524990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vslw, "__builtin_altivec_vslw", ALTIVEC_BUILTIN_VSLW },
525090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsl, "__builtin_altivec_vsl", ALTIVEC_BUILTIN_VSL },
525190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vslo, "__builtin_altivec_vslo", ALTIVEC_BUILTIN_VSLO },
525290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vspltb, "__builtin_altivec_vspltb", ALTIVEC_BUILTIN_VSPLTB },
525390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsplth, "__builtin_altivec_vsplth", ALTIVEC_BUILTIN_VSPLTH },
525490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vspltw, "__builtin_altivec_vspltw", ALTIVEC_BUILTIN_VSPLTW },
525590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsrb, "__builtin_altivec_vsrb", ALTIVEC_BUILTIN_VSRB },
525690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsrh, "__builtin_altivec_vsrh", ALTIVEC_BUILTIN_VSRH },
525790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsrw, "__builtin_altivec_vsrw", ALTIVEC_BUILTIN_VSRW },
525890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsrab, "__builtin_altivec_vsrab", ALTIVEC_BUILTIN_VSRAB },
525990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsrah, "__builtin_altivec_vsrah", ALTIVEC_BUILTIN_VSRAH },
526090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsraw, "__builtin_altivec_vsraw", ALTIVEC_BUILTIN_VSRAW },
526190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsr, "__builtin_altivec_vsr", ALTIVEC_BUILTIN_VSR },
526290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsro, "__builtin_altivec_vsro", ALTIVEC_BUILTIN_VSRO },
526390075Sobrien  { MASK_ALTIVEC, CODE_FOR_subv16qi3, "__builtin_altivec_vsububm", ALTIVEC_BUILTIN_VSUBUBM },
526490075Sobrien  { MASK_ALTIVEC, CODE_FOR_subv8hi3, "__builtin_altivec_vsubuhm", ALTIVEC_BUILTIN_VSUBUHM },
526590075Sobrien  { MASK_ALTIVEC, CODE_FOR_subv4si3, "__builtin_altivec_vsubuwm", ALTIVEC_BUILTIN_VSUBUWM },
526690075Sobrien  { MASK_ALTIVEC, CODE_FOR_subv4sf3, "__builtin_altivec_vsubfp", ALTIVEC_BUILTIN_VSUBFP },
526790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsubcuw, "__builtin_altivec_vsubcuw", ALTIVEC_BUILTIN_VSUBCUW },
526890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsububs, "__builtin_altivec_vsububs", ALTIVEC_BUILTIN_VSUBUBS },
526990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsubsbs, "__builtin_altivec_vsubsbs", ALTIVEC_BUILTIN_VSUBSBS },
527090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsubuhs, "__builtin_altivec_vsubuhs", ALTIVEC_BUILTIN_VSUBUHS },
527190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsubshs, "__builtin_altivec_vsubshs", ALTIVEC_BUILTIN_VSUBSHS },
527290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsubuws, "__builtin_altivec_vsubuws", ALTIVEC_BUILTIN_VSUBUWS },
527390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsubsws, "__builtin_altivec_vsubsws", ALTIVEC_BUILTIN_VSUBSWS },
527490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsum4ubs, "__builtin_altivec_vsum4ubs", ALTIVEC_BUILTIN_VSUM4UBS },
527590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsum4sbs, "__builtin_altivec_vsum4sbs", ALTIVEC_BUILTIN_VSUM4SBS },
527690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsum4shs, "__builtin_altivec_vsum4shs", ALTIVEC_BUILTIN_VSUM4SHS },
527790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsum2sws, "__builtin_altivec_vsum2sws", ALTIVEC_BUILTIN_VSUM2SWS },
527890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsumsws, "__builtin_altivec_vsumsws", ALTIVEC_BUILTIN_VSUMSWS },
527990075Sobrien  { MASK_ALTIVEC, CODE_FOR_xorv4si3, "__builtin_altivec_vxor", ALTIVEC_BUILTIN_VXOR },
5280117395Skan
5281117395Skan  /* Place holder, leave as first spe builtin.  */
5282117395Skan  { 0, CODE_FOR_spe_evaddw, "__builtin_spe_evaddw", SPE_BUILTIN_EVADDW },
5283117395Skan  { 0, CODE_FOR_spe_evand, "__builtin_spe_evand", SPE_BUILTIN_EVAND },
5284117395Skan  { 0, CODE_FOR_spe_evandc, "__builtin_spe_evandc", SPE_BUILTIN_EVANDC },
5285117395Skan  { 0, CODE_FOR_spe_evdivws, "__builtin_spe_evdivws", SPE_BUILTIN_EVDIVWS },
5286117395Skan  { 0, CODE_FOR_spe_evdivwu, "__builtin_spe_evdivwu", SPE_BUILTIN_EVDIVWU },
5287117395Skan  { 0, CODE_FOR_spe_eveqv, "__builtin_spe_eveqv", SPE_BUILTIN_EVEQV },
5288117395Skan  { 0, CODE_FOR_spe_evfsadd, "__builtin_spe_evfsadd", SPE_BUILTIN_EVFSADD },
5289117395Skan  { 0, CODE_FOR_spe_evfsdiv, "__builtin_spe_evfsdiv", SPE_BUILTIN_EVFSDIV },
5290117395Skan  { 0, CODE_FOR_spe_evfsmul, "__builtin_spe_evfsmul", SPE_BUILTIN_EVFSMUL },
5291117395Skan  { 0, CODE_FOR_spe_evfssub, "__builtin_spe_evfssub", SPE_BUILTIN_EVFSSUB },
5292117395Skan  { 0, CODE_FOR_spe_evmergehi, "__builtin_spe_evmergehi", SPE_BUILTIN_EVMERGEHI },
5293117395Skan  { 0, CODE_FOR_spe_evmergehilo, "__builtin_spe_evmergehilo", SPE_BUILTIN_EVMERGEHILO },
5294117395Skan  { 0, CODE_FOR_spe_evmergelo, "__builtin_spe_evmergelo", SPE_BUILTIN_EVMERGELO },
5295117395Skan  { 0, CODE_FOR_spe_evmergelohi, "__builtin_spe_evmergelohi", SPE_BUILTIN_EVMERGELOHI },
5296117395Skan  { 0, CODE_FOR_spe_evmhegsmfaa, "__builtin_spe_evmhegsmfaa", SPE_BUILTIN_EVMHEGSMFAA },
5297117395Skan  { 0, CODE_FOR_spe_evmhegsmfan, "__builtin_spe_evmhegsmfan", SPE_BUILTIN_EVMHEGSMFAN },
5298117395Skan  { 0, CODE_FOR_spe_evmhegsmiaa, "__builtin_spe_evmhegsmiaa", SPE_BUILTIN_EVMHEGSMIAA },
5299117395Skan  { 0, CODE_FOR_spe_evmhegsmian, "__builtin_spe_evmhegsmian", SPE_BUILTIN_EVMHEGSMIAN },
5300117395Skan  { 0, CODE_FOR_spe_evmhegumiaa, "__builtin_spe_evmhegumiaa", SPE_BUILTIN_EVMHEGUMIAA },
5301117395Skan  { 0, CODE_FOR_spe_evmhegumian, "__builtin_spe_evmhegumian", SPE_BUILTIN_EVMHEGUMIAN },
5302117395Skan  { 0, CODE_FOR_spe_evmhesmf, "__builtin_spe_evmhesmf", SPE_BUILTIN_EVMHESMF },
5303117395Skan  { 0, CODE_FOR_spe_evmhesmfa, "__builtin_spe_evmhesmfa", SPE_BUILTIN_EVMHESMFA },
5304117395Skan  { 0, CODE_FOR_spe_evmhesmfaaw, "__builtin_spe_evmhesmfaaw", SPE_BUILTIN_EVMHESMFAAW },
5305117395Skan  { 0, CODE_FOR_spe_evmhesmfanw, "__builtin_spe_evmhesmfanw", SPE_BUILTIN_EVMHESMFANW },
5306117395Skan  { 0, CODE_FOR_spe_evmhesmi, "__builtin_spe_evmhesmi", SPE_BUILTIN_EVMHESMI },
5307117395Skan  { 0, CODE_FOR_spe_evmhesmia, "__builtin_spe_evmhesmia", SPE_BUILTIN_EVMHESMIA },
5308117395Skan  { 0, CODE_FOR_spe_evmhesmiaaw, "__builtin_spe_evmhesmiaaw", SPE_BUILTIN_EVMHESMIAAW },
5309117395Skan  { 0, CODE_FOR_spe_evmhesmianw, "__builtin_spe_evmhesmianw", SPE_BUILTIN_EVMHESMIANW },
5310117395Skan  { 0, CODE_FOR_spe_evmhessf, "__builtin_spe_evmhessf", SPE_BUILTIN_EVMHESSF },
5311117395Skan  { 0, CODE_FOR_spe_evmhessfa, "__builtin_spe_evmhessfa", SPE_BUILTIN_EVMHESSFA },
5312117395Skan  { 0, CODE_FOR_spe_evmhessfaaw, "__builtin_spe_evmhessfaaw", SPE_BUILTIN_EVMHESSFAAW },
5313117395Skan  { 0, CODE_FOR_spe_evmhessfanw, "__builtin_spe_evmhessfanw", SPE_BUILTIN_EVMHESSFANW },
5314117395Skan  { 0, CODE_FOR_spe_evmhessiaaw, "__builtin_spe_evmhessiaaw", SPE_BUILTIN_EVMHESSIAAW },
5315117395Skan  { 0, CODE_FOR_spe_evmhessianw, "__builtin_spe_evmhessianw", SPE_BUILTIN_EVMHESSIANW },
5316117395Skan  { 0, CODE_FOR_spe_evmheumi, "__builtin_spe_evmheumi", SPE_BUILTIN_EVMHEUMI },
5317117395Skan  { 0, CODE_FOR_spe_evmheumia, "__builtin_spe_evmheumia", SPE_BUILTIN_EVMHEUMIA },
5318117395Skan  { 0, CODE_FOR_spe_evmheumiaaw, "__builtin_spe_evmheumiaaw", SPE_BUILTIN_EVMHEUMIAAW },
5319117395Skan  { 0, CODE_FOR_spe_evmheumianw, "__builtin_spe_evmheumianw", SPE_BUILTIN_EVMHEUMIANW },
5320117395Skan  { 0, CODE_FOR_spe_evmheusiaaw, "__builtin_spe_evmheusiaaw", SPE_BUILTIN_EVMHEUSIAAW },
5321117395Skan  { 0, CODE_FOR_spe_evmheusianw, "__builtin_spe_evmheusianw", SPE_BUILTIN_EVMHEUSIANW },
5322117395Skan  { 0, CODE_FOR_spe_evmhogsmfaa, "__builtin_spe_evmhogsmfaa", SPE_BUILTIN_EVMHOGSMFAA },
5323117395Skan  { 0, CODE_FOR_spe_evmhogsmfan, "__builtin_spe_evmhogsmfan", SPE_BUILTIN_EVMHOGSMFAN },
5324117395Skan  { 0, CODE_FOR_spe_evmhogsmiaa, "__builtin_spe_evmhogsmiaa", SPE_BUILTIN_EVMHOGSMIAA },
5325117395Skan  { 0, CODE_FOR_spe_evmhogsmian, "__builtin_spe_evmhogsmian", SPE_BUILTIN_EVMHOGSMIAN },
5326117395Skan  { 0, CODE_FOR_spe_evmhogumiaa, "__builtin_spe_evmhogumiaa", SPE_BUILTIN_EVMHOGUMIAA },
5327117395Skan  { 0, CODE_FOR_spe_evmhogumian, "__builtin_spe_evmhogumian", SPE_BUILTIN_EVMHOGUMIAN },
5328117395Skan  { 0, CODE_FOR_spe_evmhosmf, "__builtin_spe_evmhosmf", SPE_BUILTIN_EVMHOSMF },
5329117395Skan  { 0, CODE_FOR_spe_evmhosmfa, "__builtin_spe_evmhosmfa", SPE_BUILTIN_EVMHOSMFA },
5330117395Skan  { 0, CODE_FOR_spe_evmhosmfaaw, "__builtin_spe_evmhosmfaaw", SPE_BUILTIN_EVMHOSMFAAW },
5331117395Skan  { 0, CODE_FOR_spe_evmhosmfanw, "__builtin_spe_evmhosmfanw", SPE_BUILTIN_EVMHOSMFANW },
5332117395Skan  { 0, CODE_FOR_spe_evmhosmi, "__builtin_spe_evmhosmi", SPE_BUILTIN_EVMHOSMI },
5333117395Skan  { 0, CODE_FOR_spe_evmhosmia, "__builtin_spe_evmhosmia", SPE_BUILTIN_EVMHOSMIA },
5334117395Skan  { 0, CODE_FOR_spe_evmhosmiaaw, "__builtin_spe_evmhosmiaaw", SPE_BUILTIN_EVMHOSMIAAW },
5335117395Skan  { 0, CODE_FOR_spe_evmhosmianw, "__builtin_spe_evmhosmianw", SPE_BUILTIN_EVMHOSMIANW },
5336117395Skan  { 0, CODE_FOR_spe_evmhossf, "__builtin_spe_evmhossf", SPE_BUILTIN_EVMHOSSF },
5337117395Skan  { 0, CODE_FOR_spe_evmhossfa, "__builtin_spe_evmhossfa", SPE_BUILTIN_EVMHOSSFA },
5338117395Skan  { 0, CODE_FOR_spe_evmhossfaaw, "__builtin_spe_evmhossfaaw", SPE_BUILTIN_EVMHOSSFAAW },
5339117395Skan  { 0, CODE_FOR_spe_evmhossfanw, "__builtin_spe_evmhossfanw", SPE_BUILTIN_EVMHOSSFANW },
5340117395Skan  { 0, CODE_FOR_spe_evmhossiaaw, "__builtin_spe_evmhossiaaw", SPE_BUILTIN_EVMHOSSIAAW },
5341117395Skan  { 0, CODE_FOR_spe_evmhossianw, "__builtin_spe_evmhossianw", SPE_BUILTIN_EVMHOSSIANW },
5342117395Skan  { 0, CODE_FOR_spe_evmhoumi, "__builtin_spe_evmhoumi", SPE_BUILTIN_EVMHOUMI },
5343117395Skan  { 0, CODE_FOR_spe_evmhoumia, "__builtin_spe_evmhoumia", SPE_BUILTIN_EVMHOUMIA },
5344117395Skan  { 0, CODE_FOR_spe_evmhoumiaaw, "__builtin_spe_evmhoumiaaw", SPE_BUILTIN_EVMHOUMIAAW },
5345117395Skan  { 0, CODE_FOR_spe_evmhoumianw, "__builtin_spe_evmhoumianw", SPE_BUILTIN_EVMHOUMIANW },
5346117395Skan  { 0, CODE_FOR_spe_evmhousiaaw, "__builtin_spe_evmhousiaaw", SPE_BUILTIN_EVMHOUSIAAW },
5347117395Skan  { 0, CODE_FOR_spe_evmhousianw, "__builtin_spe_evmhousianw", SPE_BUILTIN_EVMHOUSIANW },
5348117395Skan  { 0, CODE_FOR_spe_evmwhsmf, "__builtin_spe_evmwhsmf", SPE_BUILTIN_EVMWHSMF },
5349117395Skan  { 0, CODE_FOR_spe_evmwhsmfa, "__builtin_spe_evmwhsmfa", SPE_BUILTIN_EVMWHSMFA },
5350117395Skan  { 0, CODE_FOR_spe_evmwhsmi, "__builtin_spe_evmwhsmi", SPE_BUILTIN_EVMWHSMI },
5351117395Skan  { 0, CODE_FOR_spe_evmwhsmia, "__builtin_spe_evmwhsmia", SPE_BUILTIN_EVMWHSMIA },
5352117395Skan  { 0, CODE_FOR_spe_evmwhssf, "__builtin_spe_evmwhssf", SPE_BUILTIN_EVMWHSSF },
5353117395Skan  { 0, CODE_FOR_spe_evmwhssfa, "__builtin_spe_evmwhssfa", SPE_BUILTIN_EVMWHSSFA },
5354117395Skan  { 0, CODE_FOR_spe_evmwhumi, "__builtin_spe_evmwhumi", SPE_BUILTIN_EVMWHUMI },
5355117395Skan  { 0, CODE_FOR_spe_evmwhumia, "__builtin_spe_evmwhumia", SPE_BUILTIN_EVMWHUMIA },
5356117395Skan  { 0, CODE_FOR_spe_evmwlsmiaaw, "__builtin_spe_evmwlsmiaaw", SPE_BUILTIN_EVMWLSMIAAW },
5357117395Skan  { 0, CODE_FOR_spe_evmwlsmianw, "__builtin_spe_evmwlsmianw", SPE_BUILTIN_EVMWLSMIANW },
5358117395Skan  { 0, CODE_FOR_spe_evmwlssiaaw, "__builtin_spe_evmwlssiaaw", SPE_BUILTIN_EVMWLSSIAAW },
5359117395Skan  { 0, CODE_FOR_spe_evmwlssianw, "__builtin_spe_evmwlssianw", SPE_BUILTIN_EVMWLSSIANW },
5360117395Skan  { 0, CODE_FOR_spe_evmwlumi, "__builtin_spe_evmwlumi", SPE_BUILTIN_EVMWLUMI },
5361117395Skan  { 0, CODE_FOR_spe_evmwlumia, "__builtin_spe_evmwlumia", SPE_BUILTIN_EVMWLUMIA },
5362117395Skan  { 0, CODE_FOR_spe_evmwlumiaaw, "__builtin_spe_evmwlumiaaw", SPE_BUILTIN_EVMWLUMIAAW },
5363117395Skan  { 0, CODE_FOR_spe_evmwlumianw, "__builtin_spe_evmwlumianw", SPE_BUILTIN_EVMWLUMIANW },
5364117395Skan  { 0, CODE_FOR_spe_evmwlusiaaw, "__builtin_spe_evmwlusiaaw", SPE_BUILTIN_EVMWLUSIAAW },
5365117395Skan  { 0, CODE_FOR_spe_evmwlusianw, "__builtin_spe_evmwlusianw", SPE_BUILTIN_EVMWLUSIANW },
5366117395Skan  { 0, CODE_FOR_spe_evmwsmf, "__builtin_spe_evmwsmf", SPE_BUILTIN_EVMWSMF },
5367117395Skan  { 0, CODE_FOR_spe_evmwsmfa, "__builtin_spe_evmwsmfa", SPE_BUILTIN_EVMWSMFA },
5368117395Skan  { 0, CODE_FOR_spe_evmwsmfaa, "__builtin_spe_evmwsmfaa", SPE_BUILTIN_EVMWSMFAA },
5369117395Skan  { 0, CODE_FOR_spe_evmwsmfan, "__builtin_spe_evmwsmfan", SPE_BUILTIN_EVMWSMFAN },
5370117395Skan  { 0, CODE_FOR_spe_evmwsmi, "__builtin_spe_evmwsmi", SPE_BUILTIN_EVMWSMI },
5371117395Skan  { 0, CODE_FOR_spe_evmwsmia, "__builtin_spe_evmwsmia", SPE_BUILTIN_EVMWSMIA },
5372117395Skan  { 0, CODE_FOR_spe_evmwsmiaa, "__builtin_spe_evmwsmiaa", SPE_BUILTIN_EVMWSMIAA },
5373117395Skan  { 0, CODE_FOR_spe_evmwsmian, "__builtin_spe_evmwsmian", SPE_BUILTIN_EVMWSMIAN },
5374117395Skan  { 0, CODE_FOR_spe_evmwssf, "__builtin_spe_evmwssf", SPE_BUILTIN_EVMWSSF },
5375117395Skan  { 0, CODE_FOR_spe_evmwssfa, "__builtin_spe_evmwssfa", SPE_BUILTIN_EVMWSSFA },
5376117395Skan  { 0, CODE_FOR_spe_evmwssfaa, "__builtin_spe_evmwssfaa", SPE_BUILTIN_EVMWSSFAA },
5377117395Skan  { 0, CODE_FOR_spe_evmwssfan, "__builtin_spe_evmwssfan", SPE_BUILTIN_EVMWSSFAN },
5378117395Skan  { 0, CODE_FOR_spe_evmwumi, "__builtin_spe_evmwumi", SPE_BUILTIN_EVMWUMI },
5379117395Skan  { 0, CODE_FOR_spe_evmwumia, "__builtin_spe_evmwumia", SPE_BUILTIN_EVMWUMIA },
5380117395Skan  { 0, CODE_FOR_spe_evmwumiaa, "__builtin_spe_evmwumiaa", SPE_BUILTIN_EVMWUMIAA },
5381117395Skan  { 0, CODE_FOR_spe_evmwumian, "__builtin_spe_evmwumian", SPE_BUILTIN_EVMWUMIAN },
5382117395Skan  { 0, CODE_FOR_spe_evnand, "__builtin_spe_evnand", SPE_BUILTIN_EVNAND },
5383117395Skan  { 0, CODE_FOR_spe_evnor, "__builtin_spe_evnor", SPE_BUILTIN_EVNOR },
5384117395Skan  { 0, CODE_FOR_spe_evor, "__builtin_spe_evor", SPE_BUILTIN_EVOR },
5385117395Skan  { 0, CODE_FOR_spe_evorc, "__builtin_spe_evorc", SPE_BUILTIN_EVORC },
5386117395Skan  { 0, CODE_FOR_spe_evrlw, "__builtin_spe_evrlw", SPE_BUILTIN_EVRLW },
5387117395Skan  { 0, CODE_FOR_spe_evslw, "__builtin_spe_evslw", SPE_BUILTIN_EVSLW },
5388117395Skan  { 0, CODE_FOR_spe_evsrws, "__builtin_spe_evsrws", SPE_BUILTIN_EVSRWS },
5389117395Skan  { 0, CODE_FOR_spe_evsrwu, "__builtin_spe_evsrwu", SPE_BUILTIN_EVSRWU },
5390117395Skan  { 0, CODE_FOR_spe_evsubfw, "__builtin_spe_evsubfw", SPE_BUILTIN_EVSUBFW },
5391117395Skan
5392117395Skan  /* SPE binary operations expecting a 5-bit unsigned literal.  */
5393117395Skan  { 0, CODE_FOR_spe_evaddiw, "__builtin_spe_evaddiw", SPE_BUILTIN_EVADDIW },
5394117395Skan
5395117395Skan  { 0, CODE_FOR_spe_evrlwi, "__builtin_spe_evrlwi", SPE_BUILTIN_EVRLWI },
5396117395Skan  { 0, CODE_FOR_spe_evslwi, "__builtin_spe_evslwi", SPE_BUILTIN_EVSLWI },
5397117395Skan  { 0, CODE_FOR_spe_evsrwis, "__builtin_spe_evsrwis", SPE_BUILTIN_EVSRWIS },
5398117395Skan  { 0, CODE_FOR_spe_evsrwiu, "__builtin_spe_evsrwiu", SPE_BUILTIN_EVSRWIU },
5399117395Skan  { 0, CODE_FOR_spe_evsubifw, "__builtin_spe_evsubifw", SPE_BUILTIN_EVSUBIFW },
5400117395Skan  { 0, CODE_FOR_spe_evmwhssfaa, "__builtin_spe_evmwhssfaa", SPE_BUILTIN_EVMWHSSFAA },
5401117395Skan  { 0, CODE_FOR_spe_evmwhssmaa, "__builtin_spe_evmwhssmaa", SPE_BUILTIN_EVMWHSSMAA },
5402117395Skan  { 0, CODE_FOR_spe_evmwhsmfaa, "__builtin_spe_evmwhsmfaa", SPE_BUILTIN_EVMWHSMFAA },
5403117395Skan  { 0, CODE_FOR_spe_evmwhsmiaa, "__builtin_spe_evmwhsmiaa", SPE_BUILTIN_EVMWHSMIAA },
5404117395Skan  { 0, CODE_FOR_spe_evmwhusiaa, "__builtin_spe_evmwhusiaa", SPE_BUILTIN_EVMWHUSIAA },
5405117395Skan  { 0, CODE_FOR_spe_evmwhumiaa, "__builtin_spe_evmwhumiaa", SPE_BUILTIN_EVMWHUMIAA },
5406117395Skan  { 0, CODE_FOR_spe_evmwhssfan, "__builtin_spe_evmwhssfan", SPE_BUILTIN_EVMWHSSFAN },
5407117395Skan  { 0, CODE_FOR_spe_evmwhssian, "__builtin_spe_evmwhssian", SPE_BUILTIN_EVMWHSSIAN },
5408117395Skan  { 0, CODE_FOR_spe_evmwhsmfan, "__builtin_spe_evmwhsmfan", SPE_BUILTIN_EVMWHSMFAN },
5409117395Skan  { 0, CODE_FOR_spe_evmwhsmian, "__builtin_spe_evmwhsmian", SPE_BUILTIN_EVMWHSMIAN },
5410117395Skan  { 0, CODE_FOR_spe_evmwhusian, "__builtin_spe_evmwhusian", SPE_BUILTIN_EVMWHUSIAN },
5411117395Skan  { 0, CODE_FOR_spe_evmwhumian, "__builtin_spe_evmwhumian", SPE_BUILTIN_EVMWHUMIAN },
5412117395Skan  { 0, CODE_FOR_spe_evmwhgssfaa, "__builtin_spe_evmwhgssfaa", SPE_BUILTIN_EVMWHGSSFAA },
5413117395Skan  { 0, CODE_FOR_spe_evmwhgsmfaa, "__builtin_spe_evmwhgsmfaa", SPE_BUILTIN_EVMWHGSMFAA },
5414117395Skan  { 0, CODE_FOR_spe_evmwhgsmiaa, "__builtin_spe_evmwhgsmiaa", SPE_BUILTIN_EVMWHGSMIAA },
5415117395Skan  { 0, CODE_FOR_spe_evmwhgumiaa, "__builtin_spe_evmwhgumiaa", SPE_BUILTIN_EVMWHGUMIAA },
5416117395Skan  { 0, CODE_FOR_spe_evmwhgssfan, "__builtin_spe_evmwhgssfan", SPE_BUILTIN_EVMWHGSSFAN },
5417117395Skan  { 0, CODE_FOR_spe_evmwhgsmfan, "__builtin_spe_evmwhgsmfan", SPE_BUILTIN_EVMWHGSMFAN },
5418117395Skan  { 0, CODE_FOR_spe_evmwhgsmian, "__builtin_spe_evmwhgsmian", SPE_BUILTIN_EVMWHGSMIAN },
5419117395Skan  { 0, CODE_FOR_spe_evmwhgumian, "__builtin_spe_evmwhgumian", SPE_BUILTIN_EVMWHGUMIAN },
5420117395Skan  { 0, CODE_FOR_spe_brinc, "__builtin_spe_brinc", SPE_BUILTIN_BRINC },
5421117395Skan
5422117395Skan  /* Place-holder.  Leave as last binary SPE builtin.  */
5423132718Skan  { 0, CODE_FOR_xorv2si3, "__builtin_spe_evxor", SPE_BUILTIN_EVXOR },
542490075Sobrien};
542590075Sobrien
542696263Sobrien/* AltiVec predicates.  */
542796263Sobrien
542896263Sobrienstruct builtin_description_predicates
542996263Sobrien{
543096263Sobrien  const unsigned int mask;
543196263Sobrien  const enum insn_code icode;
543296263Sobrien  const char *opcode;
543396263Sobrien  const char *const name;
543496263Sobrien  const enum rs6000_builtins code;
543596263Sobrien};
543696263Sobrien
543796263Sobrienstatic const struct builtin_description_predicates bdesc_altivec_preds[] =
543896263Sobrien{
543996263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v4sf, "*vcmpbfp.", "__builtin_altivec_vcmpbfp_p", ALTIVEC_BUILTIN_VCMPBFP_P },
544096263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v4sf, "*vcmpeqfp.", "__builtin_altivec_vcmpeqfp_p", ALTIVEC_BUILTIN_VCMPEQFP_P },
544196263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v4sf, "*vcmpgefp.", "__builtin_altivec_vcmpgefp_p", ALTIVEC_BUILTIN_VCMPGEFP_P },
544296263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v4sf, "*vcmpgtfp.", "__builtin_altivec_vcmpgtfp_p", ALTIVEC_BUILTIN_VCMPGTFP_P },
544396263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v4si, "*vcmpequw.", "__builtin_altivec_vcmpequw_p", ALTIVEC_BUILTIN_VCMPEQUW_P },
544496263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v4si, "*vcmpgtsw.", "__builtin_altivec_vcmpgtsw_p", ALTIVEC_BUILTIN_VCMPGTSW_P },
544596263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v4si, "*vcmpgtuw.", "__builtin_altivec_vcmpgtuw_p", ALTIVEC_BUILTIN_VCMPGTUW_P },
544696263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v8hi, "*vcmpgtuh.", "__builtin_altivec_vcmpgtuh_p", ALTIVEC_BUILTIN_VCMPGTUH_P },
544796263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v8hi, "*vcmpgtsh.", "__builtin_altivec_vcmpgtsh_p", ALTIVEC_BUILTIN_VCMPGTSH_P },
544896263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v8hi, "*vcmpequh.", "__builtin_altivec_vcmpequh_p", ALTIVEC_BUILTIN_VCMPEQUH_P },
544996263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v16qi, "*vcmpequb.", "__builtin_altivec_vcmpequb_p", ALTIVEC_BUILTIN_VCMPEQUB_P },
545096263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v16qi, "*vcmpgtsb.", "__builtin_altivec_vcmpgtsb_p", ALTIVEC_BUILTIN_VCMPGTSB_P },
545196263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v16qi, "*vcmpgtub.", "__builtin_altivec_vcmpgtub_p", ALTIVEC_BUILTIN_VCMPGTUB_P }
545296263Sobrien};
545396263Sobrien
5454117395Skan/* SPE predicates.  */
5455117395Skanstatic struct builtin_description bdesc_spe_predicates[] =
5456117395Skan{
5457117395Skan  /* Place-holder.  Leave as first.  */
5458117395Skan  { 0, CODE_FOR_spe_evcmpeq, "__builtin_spe_evcmpeq", SPE_BUILTIN_EVCMPEQ },
5459117395Skan  { 0, CODE_FOR_spe_evcmpgts, "__builtin_spe_evcmpgts", SPE_BUILTIN_EVCMPGTS },
5460117395Skan  { 0, CODE_FOR_spe_evcmpgtu, "__builtin_spe_evcmpgtu", SPE_BUILTIN_EVCMPGTU },
5461117395Skan  { 0, CODE_FOR_spe_evcmplts, "__builtin_spe_evcmplts", SPE_BUILTIN_EVCMPLTS },
5462117395Skan  { 0, CODE_FOR_spe_evcmpltu, "__builtin_spe_evcmpltu", SPE_BUILTIN_EVCMPLTU },
5463117395Skan  { 0, CODE_FOR_spe_evfscmpeq, "__builtin_spe_evfscmpeq", SPE_BUILTIN_EVFSCMPEQ },
5464117395Skan  { 0, CODE_FOR_spe_evfscmpgt, "__builtin_spe_evfscmpgt", SPE_BUILTIN_EVFSCMPGT },
5465117395Skan  { 0, CODE_FOR_spe_evfscmplt, "__builtin_spe_evfscmplt", SPE_BUILTIN_EVFSCMPLT },
5466117395Skan  { 0, CODE_FOR_spe_evfststeq, "__builtin_spe_evfststeq", SPE_BUILTIN_EVFSTSTEQ },
5467117395Skan  { 0, CODE_FOR_spe_evfststgt, "__builtin_spe_evfststgt", SPE_BUILTIN_EVFSTSTGT },
5468117395Skan  /* Place-holder.  Leave as last.  */
5469117395Skan  { 0, CODE_FOR_spe_evfststlt, "__builtin_spe_evfststlt", SPE_BUILTIN_EVFSTSTLT },
5470117395Skan};
5471117395Skan
5472117395Skan/* SPE evsel predicates.  */
5473117395Skanstatic struct builtin_description bdesc_spe_evsel[] =
5474117395Skan{
5475117395Skan  /* Place-holder.  Leave as first.  */
5476117395Skan  { 0, CODE_FOR_spe_evcmpgts, "__builtin_spe_evsel_gts", SPE_BUILTIN_EVSEL_CMPGTS },
5477117395Skan  { 0, CODE_FOR_spe_evcmpgtu, "__builtin_spe_evsel_gtu", SPE_BUILTIN_EVSEL_CMPGTU },
5478117395Skan  { 0, CODE_FOR_spe_evcmplts, "__builtin_spe_evsel_lts", SPE_BUILTIN_EVSEL_CMPLTS },
5479117395Skan  { 0, CODE_FOR_spe_evcmpltu, "__builtin_spe_evsel_ltu", SPE_BUILTIN_EVSEL_CMPLTU },
5480117395Skan  { 0, CODE_FOR_spe_evcmpeq, "__builtin_spe_evsel_eq", SPE_BUILTIN_EVSEL_CMPEQ },
5481117395Skan  { 0, CODE_FOR_spe_evfscmpgt, "__builtin_spe_evsel_fsgt", SPE_BUILTIN_EVSEL_FSCMPGT },
5482117395Skan  { 0, CODE_FOR_spe_evfscmplt, "__builtin_spe_evsel_fslt", SPE_BUILTIN_EVSEL_FSCMPLT },
5483117395Skan  { 0, CODE_FOR_spe_evfscmpeq, "__builtin_spe_evsel_fseq", SPE_BUILTIN_EVSEL_FSCMPEQ },
5484117395Skan  { 0, CODE_FOR_spe_evfststgt, "__builtin_spe_evsel_fststgt", SPE_BUILTIN_EVSEL_FSTSTGT },
5485117395Skan  { 0, CODE_FOR_spe_evfststlt, "__builtin_spe_evsel_fststlt", SPE_BUILTIN_EVSEL_FSTSTLT },
5486117395Skan  /* Place-holder.  Leave as last.  */
5487117395Skan  { 0, CODE_FOR_spe_evfststeq, "__builtin_spe_evsel_fststeq", SPE_BUILTIN_EVSEL_FSTSTEQ },
5488117395Skan};
5489117395Skan
5490132718Skan/* ABS* operations.  */
549196263Sobrien
549296263Sobrienstatic const struct builtin_description bdesc_abs[] =
549396263Sobrien{
549496263Sobrien  { MASK_ALTIVEC, CODE_FOR_absv4si2, "__builtin_altivec_abs_v4si", ALTIVEC_BUILTIN_ABS_V4SI },
549596263Sobrien  { MASK_ALTIVEC, CODE_FOR_absv8hi2, "__builtin_altivec_abs_v8hi", ALTIVEC_BUILTIN_ABS_V8HI },
549696263Sobrien  { MASK_ALTIVEC, CODE_FOR_absv4sf2, "__builtin_altivec_abs_v4sf", ALTIVEC_BUILTIN_ABS_V4SF },
549796263Sobrien  { MASK_ALTIVEC, CODE_FOR_absv16qi2, "__builtin_altivec_abs_v16qi", ALTIVEC_BUILTIN_ABS_V16QI },
549896263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_abss_v4si, "__builtin_altivec_abss_v4si", ALTIVEC_BUILTIN_ABSS_V4SI },
549996263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_abss_v8hi, "__builtin_altivec_abss_v8hi", ALTIVEC_BUILTIN_ABSS_V8HI },
550096263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_abss_v16qi, "__builtin_altivec_abss_v16qi", ALTIVEC_BUILTIN_ABSS_V16QI }
550196263Sobrien};
550296263Sobrien
550390075Sobrien/* Simple unary operations: VECb = foo (unsigned literal) or VECb =
550490075Sobrien   foo (VECa).  */
550590075Sobrien
5506117395Skanstatic struct builtin_description bdesc_1arg[] =
550790075Sobrien{
550890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vexptefp, "__builtin_altivec_vexptefp", ALTIVEC_BUILTIN_VEXPTEFP },
550990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vlogefp, "__builtin_altivec_vlogefp", ALTIVEC_BUILTIN_VLOGEFP },
551090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vrefp, "__builtin_altivec_vrefp", ALTIVEC_BUILTIN_VREFP },
551190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vrfim, "__builtin_altivec_vrfim", ALTIVEC_BUILTIN_VRFIM },
551290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vrfin, "__builtin_altivec_vrfin", ALTIVEC_BUILTIN_VRFIN },
551390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vrfip, "__builtin_altivec_vrfip", ALTIVEC_BUILTIN_VRFIP },
551490075Sobrien  { MASK_ALTIVEC, CODE_FOR_ftruncv4sf2, "__builtin_altivec_vrfiz", ALTIVEC_BUILTIN_VRFIZ },
551590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vrsqrtefp, "__builtin_altivec_vrsqrtefp", ALTIVEC_BUILTIN_VRSQRTEFP },
551690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vspltisb, "__builtin_altivec_vspltisb", ALTIVEC_BUILTIN_VSPLTISB },
551790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vspltish, "__builtin_altivec_vspltish", ALTIVEC_BUILTIN_VSPLTISH },
551890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vspltisw, "__builtin_altivec_vspltisw", ALTIVEC_BUILTIN_VSPLTISW },
551990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vupkhsb, "__builtin_altivec_vupkhsb", ALTIVEC_BUILTIN_VUPKHSB },
552090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vupkhpx, "__builtin_altivec_vupkhpx", ALTIVEC_BUILTIN_VUPKHPX },
552190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vupkhsh, "__builtin_altivec_vupkhsh", ALTIVEC_BUILTIN_VUPKHSH },
552290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vupklsb, "__builtin_altivec_vupklsb", ALTIVEC_BUILTIN_VUPKLSB },
552390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vupklpx, "__builtin_altivec_vupklpx", ALTIVEC_BUILTIN_VUPKLPX },
552490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vupklsh, "__builtin_altivec_vupklsh", ALTIVEC_BUILTIN_VUPKLSH },
5525117395Skan
5526117395Skan  /* The SPE unary builtins must start with SPE_BUILTIN_EVABS and
5527117395Skan     end with SPE_BUILTIN_EVSUBFUSIAAW.  */
5528117395Skan  { 0, CODE_FOR_spe_evabs, "__builtin_spe_evabs", SPE_BUILTIN_EVABS },
5529117395Skan  { 0, CODE_FOR_spe_evaddsmiaaw, "__builtin_spe_evaddsmiaaw", SPE_BUILTIN_EVADDSMIAAW },
5530117395Skan  { 0, CODE_FOR_spe_evaddssiaaw, "__builtin_spe_evaddssiaaw", SPE_BUILTIN_EVADDSSIAAW },
5531117395Skan  { 0, CODE_FOR_spe_evaddumiaaw, "__builtin_spe_evaddumiaaw", SPE_BUILTIN_EVADDUMIAAW },
5532117395Skan  { 0, CODE_FOR_spe_evaddusiaaw, "__builtin_spe_evaddusiaaw", SPE_BUILTIN_EVADDUSIAAW },
5533117395Skan  { 0, CODE_FOR_spe_evcntlsw, "__builtin_spe_evcntlsw", SPE_BUILTIN_EVCNTLSW },
5534117395Skan  { 0, CODE_FOR_spe_evcntlzw, "__builtin_spe_evcntlzw", SPE_BUILTIN_EVCNTLZW },
5535117395Skan  { 0, CODE_FOR_spe_evextsb, "__builtin_spe_evextsb", SPE_BUILTIN_EVEXTSB },
5536117395Skan  { 0, CODE_FOR_spe_evextsh, "__builtin_spe_evextsh", SPE_BUILTIN_EVEXTSH },
5537117395Skan  { 0, CODE_FOR_spe_evfsabs, "__builtin_spe_evfsabs", SPE_BUILTIN_EVFSABS },
5538117395Skan  { 0, CODE_FOR_spe_evfscfsf, "__builtin_spe_evfscfsf", SPE_BUILTIN_EVFSCFSF },
5539117395Skan  { 0, CODE_FOR_spe_evfscfsi, "__builtin_spe_evfscfsi", SPE_BUILTIN_EVFSCFSI },
5540117395Skan  { 0, CODE_FOR_spe_evfscfuf, "__builtin_spe_evfscfuf", SPE_BUILTIN_EVFSCFUF },
5541117395Skan  { 0, CODE_FOR_spe_evfscfui, "__builtin_spe_evfscfui", SPE_BUILTIN_EVFSCFUI },
5542117395Skan  { 0, CODE_FOR_spe_evfsctsf, "__builtin_spe_evfsctsf", SPE_BUILTIN_EVFSCTSF },
5543117395Skan  { 0, CODE_FOR_spe_evfsctsi, "__builtin_spe_evfsctsi", SPE_BUILTIN_EVFSCTSI },
5544117395Skan  { 0, CODE_FOR_spe_evfsctsiz, "__builtin_spe_evfsctsiz", SPE_BUILTIN_EVFSCTSIZ },
5545117395Skan  { 0, CODE_FOR_spe_evfsctuf, "__builtin_spe_evfsctuf", SPE_BUILTIN_EVFSCTUF },
5546117395Skan  { 0, CODE_FOR_spe_evfsctui, "__builtin_spe_evfsctui", SPE_BUILTIN_EVFSCTUI },
5547117395Skan  { 0, CODE_FOR_spe_evfsctuiz, "__builtin_spe_evfsctuiz", SPE_BUILTIN_EVFSCTUIZ },
5548117395Skan  { 0, CODE_FOR_spe_evfsnabs, "__builtin_spe_evfsnabs", SPE_BUILTIN_EVFSNABS },
5549117395Skan  { 0, CODE_FOR_spe_evfsneg, "__builtin_spe_evfsneg", SPE_BUILTIN_EVFSNEG },
5550117395Skan  { 0, CODE_FOR_spe_evmra, "__builtin_spe_evmra", SPE_BUILTIN_EVMRA },
5551132718Skan  { 0, CODE_FOR_negv2si2, "__builtin_spe_evneg", SPE_BUILTIN_EVNEG },
5552117395Skan  { 0, CODE_FOR_spe_evrndw, "__builtin_spe_evrndw", SPE_BUILTIN_EVRNDW },
5553117395Skan  { 0, CODE_FOR_spe_evsubfsmiaaw, "__builtin_spe_evsubfsmiaaw", SPE_BUILTIN_EVSUBFSMIAAW },
5554117395Skan  { 0, CODE_FOR_spe_evsubfssiaaw, "__builtin_spe_evsubfssiaaw", SPE_BUILTIN_EVSUBFSSIAAW },
5555117395Skan  { 0, CODE_FOR_spe_evsubfumiaaw, "__builtin_spe_evsubfumiaaw", SPE_BUILTIN_EVSUBFUMIAAW },
5556117395Skan
5557117395Skan  /* Place-holder.  Leave as last unary SPE builtin.  */
5558117395Skan  { 0, CODE_FOR_spe_evsubfusiaaw, "__builtin_spe_evsubfusiaaw", SPE_BUILTIN_EVSUBFUSIAAW },
555990075Sobrien};
556090075Sobrien
556190075Sobrienstatic rtx
5562132718Skanrs6000_expand_unop_builtin (enum insn_code icode, tree arglist, rtx target)
556390075Sobrien{
556490075Sobrien  rtx pat;
556590075Sobrien  tree arg0 = TREE_VALUE (arglist);
556690075Sobrien  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
556790075Sobrien  enum machine_mode tmode = insn_data[icode].operand[0].mode;
556890075Sobrien  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
556990075Sobrien
5570117395Skan  if (icode == CODE_FOR_nothing)
5571117395Skan    /* Builtin not supported on this processor.  */
5572117395Skan    return 0;
5573117395Skan
557490075Sobrien  /* If we got invalid arguments bail out before generating bad rtl.  */
557590075Sobrien  if (arg0 == error_mark_node)
5576117395Skan    return const0_rtx;
557790075Sobrien
5578117395Skan  if (icode == CODE_FOR_altivec_vspltisb
5579117395Skan      || icode == CODE_FOR_altivec_vspltish
5580117395Skan      || icode == CODE_FOR_altivec_vspltisw
5581117395Skan      || icode == CODE_FOR_spe_evsplatfi
5582117395Skan      || icode == CODE_FOR_spe_evsplati)
5583117395Skan    {
5584117395Skan      /* Only allow 5-bit *signed* literals.  */
5585117395Skan      if (GET_CODE (op0) != CONST_INT
5586117395Skan	  || INTVAL (op0) > 0x1f
5587117395Skan	  || INTVAL (op0) < -0x1f)
5588117395Skan	{
5589117395Skan	  error ("argument 1 must be a 5-bit signed literal");
5590117395Skan	  return const0_rtx;
5591117395Skan	}
5592117395Skan    }
5593117395Skan
559490075Sobrien  if (target == 0
559590075Sobrien      || GET_MODE (target) != tmode
559690075Sobrien      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
559790075Sobrien    target = gen_reg_rtx (tmode);
559890075Sobrien
559990075Sobrien  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
560090075Sobrien    op0 = copy_to_mode_reg (mode0, op0);
560190075Sobrien
560290075Sobrien  pat = GEN_FCN (icode) (target, op0);
560390075Sobrien  if (! pat)
560490075Sobrien    return 0;
560590075Sobrien  emit_insn (pat);
560690075Sobrien
560790075Sobrien  return target;
560890075Sobrien}
560996263Sobrien
561090075Sobrienstatic rtx
5611132718Skanaltivec_expand_abs_builtin (enum insn_code icode, tree arglist, rtx target)
561296263Sobrien{
561396263Sobrien  rtx pat, scratch1, scratch2;
561496263Sobrien  tree arg0 = TREE_VALUE (arglist);
561596263Sobrien  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
561696263Sobrien  enum machine_mode tmode = insn_data[icode].operand[0].mode;
561796263Sobrien  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
561896263Sobrien
561996263Sobrien  /* If we have invalid arguments, bail out before generating bad rtl.  */
562096263Sobrien  if (arg0 == error_mark_node)
5621117395Skan    return const0_rtx;
562296263Sobrien
562396263Sobrien  if (target == 0
562496263Sobrien      || GET_MODE (target) != tmode
562596263Sobrien      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
562696263Sobrien    target = gen_reg_rtx (tmode);
562796263Sobrien
562896263Sobrien  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
562996263Sobrien    op0 = copy_to_mode_reg (mode0, op0);
563096263Sobrien
563196263Sobrien  scratch1 = gen_reg_rtx (mode0);
563296263Sobrien  scratch2 = gen_reg_rtx (mode0);
563396263Sobrien
563496263Sobrien  pat = GEN_FCN (icode) (target, op0, scratch1, scratch2);
563596263Sobrien  if (! pat)
563696263Sobrien    return 0;
563796263Sobrien  emit_insn (pat);
563896263Sobrien
563996263Sobrien  return target;
564096263Sobrien}
564196263Sobrien
564296263Sobrienstatic rtx
5643132718Skanrs6000_expand_binop_builtin (enum insn_code icode, tree arglist, rtx target)
564490075Sobrien{
564590075Sobrien  rtx pat;
564690075Sobrien  tree arg0 = TREE_VALUE (arglist);
564790075Sobrien  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
564890075Sobrien  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
564990075Sobrien  rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
565090075Sobrien  enum machine_mode tmode = insn_data[icode].operand[0].mode;
565190075Sobrien  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
565290075Sobrien  enum machine_mode mode1 = insn_data[icode].operand[2].mode;
565390075Sobrien
5654117395Skan  if (icode == CODE_FOR_nothing)
5655117395Skan    /* Builtin not supported on this processor.  */
5656117395Skan    return 0;
5657117395Skan
565890075Sobrien  /* If we got invalid arguments bail out before generating bad rtl.  */
565990075Sobrien  if (arg0 == error_mark_node || arg1 == error_mark_node)
5660117395Skan    return const0_rtx;
566190075Sobrien
5662117395Skan  if (icode == CODE_FOR_altivec_vcfux
5663117395Skan      || icode == CODE_FOR_altivec_vcfsx
5664117395Skan      || icode == CODE_FOR_altivec_vctsxs
5665117395Skan      || icode == CODE_FOR_altivec_vctuxs
5666117395Skan      || icode == CODE_FOR_altivec_vspltb
5667117395Skan      || icode == CODE_FOR_altivec_vsplth
5668117395Skan      || icode == CODE_FOR_altivec_vspltw
5669117395Skan      || icode == CODE_FOR_spe_evaddiw
5670117395Skan      || icode == CODE_FOR_spe_evldd
5671117395Skan      || icode == CODE_FOR_spe_evldh
5672117395Skan      || icode == CODE_FOR_spe_evldw
5673117395Skan      || icode == CODE_FOR_spe_evlhhesplat
5674117395Skan      || icode == CODE_FOR_spe_evlhhossplat
5675117395Skan      || icode == CODE_FOR_spe_evlhhousplat
5676117395Skan      || icode == CODE_FOR_spe_evlwhe
5677117395Skan      || icode == CODE_FOR_spe_evlwhos
5678117395Skan      || icode == CODE_FOR_spe_evlwhou
5679117395Skan      || icode == CODE_FOR_spe_evlwhsplat
5680117395Skan      || icode == CODE_FOR_spe_evlwwsplat
5681117395Skan      || icode == CODE_FOR_spe_evrlwi
5682117395Skan      || icode == CODE_FOR_spe_evslwi
5683117395Skan      || icode == CODE_FOR_spe_evsrwis
5684132718Skan      || icode == CODE_FOR_spe_evsubifw
5685117395Skan      || icode == CODE_FOR_spe_evsrwiu)
5686117395Skan    {
5687117395Skan      /* Only allow 5-bit unsigned literals.  */
5688146895Skan      STRIP_NOPS (arg1);
5689117395Skan      if (TREE_CODE (arg1) != INTEGER_CST
5690117395Skan	  || TREE_INT_CST_LOW (arg1) & ~0x1f)
5691117395Skan	{
5692117395Skan	  error ("argument 2 must be a 5-bit unsigned literal");
5693117395Skan	  return const0_rtx;
5694117395Skan	}
5695117395Skan    }
5696117395Skan
569790075Sobrien  if (target == 0
569890075Sobrien      || GET_MODE (target) != tmode
569990075Sobrien      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
570090075Sobrien    target = gen_reg_rtx (tmode);
570190075Sobrien
570290075Sobrien  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
570390075Sobrien    op0 = copy_to_mode_reg (mode0, op0);
570490075Sobrien  if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
570590075Sobrien    op1 = copy_to_mode_reg (mode1, op1);
570690075Sobrien
570790075Sobrien  pat = GEN_FCN (icode) (target, op0, op1);
570890075Sobrien  if (! pat)
570990075Sobrien    return 0;
571090075Sobrien  emit_insn (pat);
571190075Sobrien
571290075Sobrien  return target;
571390075Sobrien}
571490075Sobrien
571590075Sobrienstatic rtx
5716132718Skanaltivec_expand_predicate_builtin (enum insn_code icode, const char *opcode,
5717132718Skan				  tree arglist, rtx target)
571896263Sobrien{
571996263Sobrien  rtx pat, scratch;
572096263Sobrien  tree cr6_form = TREE_VALUE (arglist);
572196263Sobrien  tree arg0 = TREE_VALUE (TREE_CHAIN (arglist));
572296263Sobrien  tree arg1 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
572396263Sobrien  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
572496263Sobrien  rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
572596263Sobrien  enum machine_mode tmode = SImode;
572696263Sobrien  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
572796263Sobrien  enum machine_mode mode1 = insn_data[icode].operand[2].mode;
572896263Sobrien  int cr6_form_int;
572996263Sobrien
573096263Sobrien  if (TREE_CODE (cr6_form) != INTEGER_CST)
573196263Sobrien    {
573296263Sobrien      error ("argument 1 of __builtin_altivec_predicate must be a constant");
5733117395Skan      return const0_rtx;
573496263Sobrien    }
573596263Sobrien  else
573696263Sobrien    cr6_form_int = TREE_INT_CST_LOW (cr6_form);
573796263Sobrien
573896263Sobrien  if (mode0 != mode1)
573996263Sobrien    abort ();
574096263Sobrien
574196263Sobrien  /* If we have invalid arguments, bail out before generating bad rtl.  */
574296263Sobrien  if (arg0 == error_mark_node || arg1 == error_mark_node)
5743117395Skan    return const0_rtx;
574496263Sobrien
574596263Sobrien  if (target == 0
574696263Sobrien      || GET_MODE (target) != tmode
574796263Sobrien      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
574896263Sobrien    target = gen_reg_rtx (tmode);
574996263Sobrien
575096263Sobrien  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
575196263Sobrien    op0 = copy_to_mode_reg (mode0, op0);
575296263Sobrien  if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
575396263Sobrien    op1 = copy_to_mode_reg (mode1, op1);
575496263Sobrien
575596263Sobrien  scratch = gen_reg_rtx (mode0);
575696263Sobrien
575796263Sobrien  pat = GEN_FCN (icode) (scratch, op0, op1,
575896263Sobrien			 gen_rtx (SYMBOL_REF, Pmode, opcode));
575996263Sobrien  if (! pat)
576096263Sobrien    return 0;
576196263Sobrien  emit_insn (pat);
576296263Sobrien
576396263Sobrien  /* The vec_any* and vec_all* predicates use the same opcodes for two
576496263Sobrien     different operations, but the bits in CR6 will be different
576596263Sobrien     depending on what information we want.  So we have to play tricks
576696263Sobrien     with CR6 to get the right bits out.
576796263Sobrien
576896263Sobrien     If you think this is disgusting, look at the specs for the
576996263Sobrien     AltiVec predicates.  */
577096263Sobrien
577196263Sobrien     switch (cr6_form_int)
577296263Sobrien       {
577396263Sobrien       case 0:
577496263Sobrien	 emit_insn (gen_cr6_test_for_zero (target));
577596263Sobrien	 break;
577696263Sobrien       case 1:
577796263Sobrien	 emit_insn (gen_cr6_test_for_zero_reverse (target));
577896263Sobrien	 break;
577996263Sobrien       case 2:
578096263Sobrien	 emit_insn (gen_cr6_test_for_lt (target));
578196263Sobrien	 break;
578296263Sobrien       case 3:
578396263Sobrien	 emit_insn (gen_cr6_test_for_lt_reverse (target));
578496263Sobrien	 break;
578596263Sobrien       default:
578696263Sobrien	 error ("argument 1 of __builtin_altivec_predicate is out of range");
578796263Sobrien	 break;
578896263Sobrien       }
578996263Sobrien
579096263Sobrien  return target;
579196263Sobrien}
579296263Sobrien
579396263Sobrienstatic rtx
5794132718Skanaltivec_expand_lv_builtin (enum insn_code icode, tree arglist, rtx target)
579590075Sobrien{
5796132718Skan  rtx pat, addr;
579790075Sobrien  tree arg0 = TREE_VALUE (arglist);
579890075Sobrien  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
5799132718Skan  enum machine_mode tmode = insn_data[icode].operand[0].mode;
5800132718Skan  enum machine_mode mode0 = Pmode;
5801132718Skan  enum machine_mode mode1 = Pmode;
5802132718Skan  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
5803132718Skan  rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
5804132718Skan
5805132718Skan  if (icode == CODE_FOR_nothing)
5806132718Skan    /* Builtin not supported on this processor.  */
5807132718Skan    return 0;
5808132718Skan
5809132718Skan  /* If we got invalid arguments bail out before generating bad rtl.  */
5810132718Skan  if (arg0 == error_mark_node || arg1 == error_mark_node)
5811132718Skan    return const0_rtx;
5812132718Skan
5813132718Skan  if (target == 0
5814132718Skan      || GET_MODE (target) != tmode
5815132718Skan      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
5816132718Skan    target = gen_reg_rtx (tmode);
5817132718Skan
5818132718Skan  op1 = copy_to_mode_reg (mode1, op1);
5819132718Skan
5820132718Skan  if (op0 == const0_rtx)
5821132718Skan    {
5822132718Skan      addr = gen_rtx_MEM (tmode, op1);
5823132718Skan    }
5824132718Skan  else
5825132718Skan    {
5826132718Skan      op0 = copy_to_mode_reg (mode0, op0);
5827132718Skan      addr = gen_rtx_MEM (tmode, gen_rtx_PLUS (Pmode, op0, op1));
5828132718Skan    }
5829132718Skan
5830132718Skan  pat = GEN_FCN (icode) (target, addr);
5831132718Skan
5832132718Skan  if (! pat)
5833132718Skan    return 0;
5834132718Skan  emit_insn (pat);
5835132718Skan
5836132718Skan  return target;
5837132718Skan}
5838132718Skan
5839132718Skanstatic rtx
5840132718Skanspe_expand_stv_builtin (enum insn_code icode, tree arglist)
5841132718Skan{
5842132718Skan  tree arg0 = TREE_VALUE (arglist);
5843132718Skan  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
584490075Sobrien  tree arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
584590075Sobrien  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
584690075Sobrien  rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
584790075Sobrien  rtx op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
584890075Sobrien  rtx pat;
584990075Sobrien  enum machine_mode mode0 = insn_data[icode].operand[0].mode;
585090075Sobrien  enum machine_mode mode1 = insn_data[icode].operand[1].mode;
585190075Sobrien  enum machine_mode mode2 = insn_data[icode].operand[2].mode;
585290075Sobrien
585390075Sobrien  /* Invalid arguments.  Bail before doing anything stoopid!  */
585490075Sobrien  if (arg0 == error_mark_node
585590075Sobrien      || arg1 == error_mark_node
585690075Sobrien      || arg2 == error_mark_node)
5857117395Skan    return const0_rtx;
585890075Sobrien
585990075Sobrien  if (! (*insn_data[icode].operand[2].predicate) (op0, mode2))
586090075Sobrien    op0 = copy_to_mode_reg (mode2, op0);
586190075Sobrien  if (! (*insn_data[icode].operand[0].predicate) (op1, mode0))
586290075Sobrien    op1 = copy_to_mode_reg (mode0, op1);
586390075Sobrien  if (! (*insn_data[icode].operand[1].predicate) (op2, mode1))
586490075Sobrien    op2 = copy_to_mode_reg (mode1, op2);
586590075Sobrien
586690075Sobrien  pat = GEN_FCN (icode) (op1, op2, op0);
586790075Sobrien  if (pat)
586890075Sobrien    emit_insn (pat);
586990075Sobrien  return NULL_RTX;
587090075Sobrien}
587190075Sobrien
587290075Sobrienstatic rtx
5873132718Skanaltivec_expand_stv_builtin (enum insn_code icode, tree arglist)
587490075Sobrien{
5875132718Skan  tree arg0 = TREE_VALUE (arglist);
5876132718Skan  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
5877132718Skan  tree arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
5878132718Skan  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
5879132718Skan  rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
5880132718Skan  rtx op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
5881132718Skan  rtx pat, addr;
5882132718Skan  enum machine_mode tmode = insn_data[icode].operand[0].mode;
5883132718Skan  enum machine_mode mode1 = Pmode;
5884132718Skan  enum machine_mode mode2 = Pmode;
5885132718Skan
5886132718Skan  /* Invalid arguments.  Bail before doing anything stoopid!  */
5887132718Skan  if (arg0 == error_mark_node
5888132718Skan      || arg1 == error_mark_node
5889132718Skan      || arg2 == error_mark_node)
5890132718Skan    return const0_rtx;
5891132718Skan
5892132718Skan  if (! (*insn_data[icode].operand[1].predicate) (op0, tmode))
5893132718Skan    op0 = copy_to_mode_reg (tmode, op0);
5894132718Skan
5895132718Skan  op2 = copy_to_mode_reg (mode2, op2);
5896132718Skan
5897132718Skan  if (op1 == const0_rtx)
5898132718Skan    {
5899132718Skan      addr = gen_rtx_MEM (tmode, op2);
5900132718Skan    }
5901132718Skan  else
5902132718Skan    {
5903132718Skan      op1 = copy_to_mode_reg (mode1, op1);
5904132718Skan      addr = gen_rtx_MEM (tmode, gen_rtx_PLUS (Pmode, op1, op2));
5905132718Skan    }
5906132718Skan
5907132718Skan  pat = GEN_FCN (icode) (addr, op0);
5908132718Skan  if (pat)
5909132718Skan    emit_insn (pat);
5910132718Skan  return NULL_RTX;
5911132718Skan}
5912132718Skan
5913132718Skanstatic rtx
5914132718Skanrs6000_expand_ternop_builtin (enum insn_code icode, tree arglist, rtx target)
5915132718Skan{
591690075Sobrien  rtx pat;
591790075Sobrien  tree arg0 = TREE_VALUE (arglist);
591890075Sobrien  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
591990075Sobrien  tree arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
592090075Sobrien  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
592190075Sobrien  rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
592290075Sobrien  rtx op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
592390075Sobrien  enum machine_mode tmode = insn_data[icode].operand[0].mode;
592490075Sobrien  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
592590075Sobrien  enum machine_mode mode1 = insn_data[icode].operand[2].mode;
592690075Sobrien  enum machine_mode mode2 = insn_data[icode].operand[3].mode;
592790075Sobrien
5928117395Skan  if (icode == CODE_FOR_nothing)
5929117395Skan    /* Builtin not supported on this processor.  */
5930117395Skan    return 0;
5931117395Skan
593290075Sobrien  /* If we got invalid arguments bail out before generating bad rtl.  */
593390075Sobrien  if (arg0 == error_mark_node
593490075Sobrien      || arg1 == error_mark_node
593590075Sobrien      || arg2 == error_mark_node)
5936117395Skan    return const0_rtx;
593790075Sobrien
5938117395Skan  if (icode == CODE_FOR_altivec_vsldoi_4sf
5939117395Skan      || icode == CODE_FOR_altivec_vsldoi_4si
5940117395Skan      || icode == CODE_FOR_altivec_vsldoi_8hi
5941117395Skan      || icode == CODE_FOR_altivec_vsldoi_16qi)
5942117395Skan    {
5943117395Skan      /* Only allow 4-bit unsigned literals.  */
5944117395Skan      if (TREE_CODE (arg2) != INTEGER_CST
5945117395Skan	  || TREE_INT_CST_LOW (arg2) & ~0xf)
5946117395Skan	{
5947117395Skan	  error ("argument 3 must be a 4-bit unsigned literal");
5948117395Skan	  return const0_rtx;
5949117395Skan	}
5950117395Skan    }
5951117395Skan
595290075Sobrien  if (target == 0
595390075Sobrien      || GET_MODE (target) != tmode
595490075Sobrien      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
595590075Sobrien    target = gen_reg_rtx (tmode);
595690075Sobrien
595790075Sobrien  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
595890075Sobrien    op0 = copy_to_mode_reg (mode0, op0);
595990075Sobrien  if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
596090075Sobrien    op1 = copy_to_mode_reg (mode1, op1);
596190075Sobrien  if (! (*insn_data[icode].operand[3].predicate) (op2, mode2))
596290075Sobrien    op2 = copy_to_mode_reg (mode2, op2);
596390075Sobrien
596490075Sobrien  pat = GEN_FCN (icode) (target, op0, op1, op2);
596590075Sobrien  if (! pat)
596690075Sobrien    return 0;
596790075Sobrien  emit_insn (pat);
596890075Sobrien
596990075Sobrien  return target;
597090075Sobrien}
5971117395Skan
5972117395Skan/* Expand the lvx builtins.  */
597390075Sobrienstatic rtx
5974132718Skanaltivec_expand_ld_builtin (tree exp, rtx target, bool *expandedp)
597590075Sobrien{
597690075Sobrien  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
597790075Sobrien  tree arglist = TREE_OPERAND (exp, 1);
597890075Sobrien  unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
5979117395Skan  tree arg0;
5980117395Skan  enum machine_mode tmode, mode0;
5981117395Skan  rtx pat, op0;
5982117395Skan  enum insn_code icode;
5983117395Skan
598490075Sobrien  switch (fcode)
598590075Sobrien    {
598690075Sobrien    case ALTIVEC_BUILTIN_LD_INTERNAL_16qi:
598790075Sobrien      icode = CODE_FOR_altivec_lvx_16qi;
5988117395Skan      break;
5989117395Skan    case ALTIVEC_BUILTIN_LD_INTERNAL_8hi:
5990117395Skan      icode = CODE_FOR_altivec_lvx_8hi;
5991117395Skan      break;
5992117395Skan    case ALTIVEC_BUILTIN_LD_INTERNAL_4si:
5993117395Skan      icode = CODE_FOR_altivec_lvx_4si;
5994117395Skan      break;
5995117395Skan    case ALTIVEC_BUILTIN_LD_INTERNAL_4sf:
5996117395Skan      icode = CODE_FOR_altivec_lvx_4sf;
5997117395Skan      break;
5998117395Skan    default:
5999117395Skan      *expandedp = false;
6000117395Skan      return NULL_RTX;
6001117395Skan    }
600290075Sobrien
6003117395Skan  *expandedp = true;
600490075Sobrien
6005117395Skan  arg0 = TREE_VALUE (arglist);
6006117395Skan  op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6007117395Skan  tmode = insn_data[icode].operand[0].mode;
6008117395Skan  mode0 = insn_data[icode].operand[1].mode;
600990075Sobrien
6010117395Skan  if (target == 0
6011117395Skan      || GET_MODE (target) != tmode
6012117395Skan      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
6013117395Skan    target = gen_reg_rtx (tmode);
601490075Sobrien
6015117395Skan  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
6016117395Skan    op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
601790075Sobrien
6018117395Skan  pat = GEN_FCN (icode) (target, op0);
6019117395Skan  if (! pat)
6020117395Skan    return 0;
6021117395Skan  emit_insn (pat);
6022117395Skan  return target;
6023117395Skan}
602490075Sobrien
6025117395Skan/* Expand the stvx builtins.  */
6026117395Skanstatic rtx
6027132718Skanaltivec_expand_st_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
6028132718Skan			   bool *expandedp)
6029117395Skan{
6030117395Skan  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
6031117395Skan  tree arglist = TREE_OPERAND (exp, 1);
6032117395Skan  unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
6033117395Skan  tree arg0, arg1;
6034117395Skan  enum machine_mode mode0, mode1;
6035117395Skan  rtx pat, op0, op1;
6036117395Skan  enum insn_code icode;
603790075Sobrien
6038117395Skan  switch (fcode)
6039117395Skan    {
6040117395Skan    case ALTIVEC_BUILTIN_ST_INTERNAL_16qi:
6041117395Skan      icode = CODE_FOR_altivec_stvx_16qi;
6042117395Skan      break;
6043117395Skan    case ALTIVEC_BUILTIN_ST_INTERNAL_8hi:
6044117395Skan      icode = CODE_FOR_altivec_stvx_8hi;
6045117395Skan      break;
6046117395Skan    case ALTIVEC_BUILTIN_ST_INTERNAL_4si:
6047117395Skan      icode = CODE_FOR_altivec_stvx_4si;
6048117395Skan      break;
6049117395Skan    case ALTIVEC_BUILTIN_ST_INTERNAL_4sf:
6050117395Skan      icode = CODE_FOR_altivec_stvx_4sf;
6051117395Skan      break;
6052117395Skan    default:
6053117395Skan      *expandedp = false;
6054117395Skan      return NULL_RTX;
6055117395Skan    }
605690075Sobrien
6057117395Skan  arg0 = TREE_VALUE (arglist);
6058117395Skan  arg1 = TREE_VALUE (TREE_CHAIN (arglist));
6059117395Skan  op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6060117395Skan  op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
6061117395Skan  mode0 = insn_data[icode].operand[0].mode;
6062117395Skan  mode1 = insn_data[icode].operand[1].mode;
606390075Sobrien
6064117395Skan  if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
6065117395Skan    op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
6066117395Skan  if (! (*insn_data[icode].operand[1].predicate) (op1, mode1))
6067117395Skan    op1 = copy_to_mode_reg (mode1, op1);
606890075Sobrien
6069117395Skan  pat = GEN_FCN (icode) (op0, op1);
6070117395Skan  if (pat)
6071117395Skan    emit_insn (pat);
607290075Sobrien
6073117395Skan  *expandedp = true;
6074117395Skan  return NULL_RTX;
6075117395Skan}
607690075Sobrien
6077117395Skan/* Expand the dst builtins.  */
6078117395Skanstatic rtx
6079132718Skanaltivec_expand_dst_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
6080132718Skan			    bool *expandedp)
6081117395Skan{
6082117395Skan  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
6083117395Skan  tree arglist = TREE_OPERAND (exp, 1);
6084117395Skan  unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
6085117395Skan  tree arg0, arg1, arg2;
6086117395Skan  enum machine_mode mode0, mode1, mode2;
6087117395Skan  rtx pat, op0, op1, op2;
6088117395Skan  struct builtin_description *d;
6089117395Skan  size_t i;
609090075Sobrien
6091117395Skan  *expandedp = false;
609290075Sobrien
6093117395Skan  /* Handle DST variants.  */
6094117395Skan  d = (struct builtin_description *) bdesc_dst;
6095117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_dst); i++, d++)
6096117395Skan    if (d->code == fcode)
6097117395Skan      {
6098117395Skan	arg0 = TREE_VALUE (arglist);
6099117395Skan	arg1 = TREE_VALUE (TREE_CHAIN (arglist));
6100117395Skan	arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
6101117395Skan	op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6102117395Skan	op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
6103117395Skan	op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
6104117395Skan	mode0 = insn_data[d->icode].operand[0].mode;
6105117395Skan	mode1 = insn_data[d->icode].operand[1].mode;
6106117395Skan	mode2 = insn_data[d->icode].operand[2].mode;
610790075Sobrien
6108117395Skan	/* Invalid arguments, bail out before generating bad rtl.  */
6109117395Skan	if (arg0 == error_mark_node
6110117395Skan	    || arg1 == error_mark_node
6111117395Skan	    || arg2 == error_mark_node)
6112117395Skan	  return const0_rtx;
611390075Sobrien
6114146895Skan	*expandedp = true;
6115146895Skan	STRIP_NOPS (arg2);
6116117395Skan	if (TREE_CODE (arg2) != INTEGER_CST
6117117395Skan	    || TREE_INT_CST_LOW (arg2) & ~0x3)
6118117395Skan	  {
6119117395Skan	    error ("argument to `%s' must be a 2-bit unsigned literal", d->name);
6120117395Skan	    return const0_rtx;
6121117395Skan	  }
612290075Sobrien
6123117395Skan	if (! (*insn_data[d->icode].operand[0].predicate) (op0, mode0))
6124132718Skan	  op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
6125117395Skan	if (! (*insn_data[d->icode].operand[1].predicate) (op1, mode1))
6126117395Skan	  op1 = copy_to_mode_reg (mode1, op1);
612790075Sobrien
6128117395Skan	pat = GEN_FCN (d->icode) (op0, op1, op2);
6129117395Skan	if (pat != 0)
6130117395Skan	  emit_insn (pat);
613190075Sobrien
6132117395Skan	return NULL_RTX;
6133117395Skan      }
613490075Sobrien
6135117395Skan  return NULL_RTX;
6136117395Skan}
613790075Sobrien
6138117395Skan/* Expand the builtin in EXP and store the result in TARGET.  Store
6139117395Skan   true in *EXPANDEDP if we found a builtin to expand.  */
6140117395Skanstatic rtx
6141132718Skanaltivec_expand_builtin (tree exp, rtx target, bool *expandedp)
6142117395Skan{
6143117395Skan  struct builtin_description *d;
6144117395Skan  struct builtin_description_predicates *dp;
6145117395Skan  size_t i;
6146117395Skan  enum insn_code icode;
6147117395Skan  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
6148117395Skan  tree arglist = TREE_OPERAND (exp, 1);
6149117395Skan  tree arg0;
6150117395Skan  rtx op0, pat;
6151117395Skan  enum machine_mode tmode, mode0;
6152117395Skan  unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
615390075Sobrien
6154117395Skan  target = altivec_expand_ld_builtin (exp, target, expandedp);
6155117395Skan  if (*expandedp)
6156117395Skan    return target;
615790075Sobrien
6158117395Skan  target = altivec_expand_st_builtin (exp, target, expandedp);
6159117395Skan  if (*expandedp)
6160117395Skan    return target;
616190075Sobrien
6162117395Skan  target = altivec_expand_dst_builtin (exp, target, expandedp);
6163117395Skan  if (*expandedp)
6164117395Skan    return target;
616590075Sobrien
6166117395Skan  *expandedp = true;
616790075Sobrien
6168117395Skan  switch (fcode)
6169117395Skan    {
617090075Sobrien    case ALTIVEC_BUILTIN_STVX:
617190075Sobrien      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvx, arglist);
617290075Sobrien    case ALTIVEC_BUILTIN_STVEBX:
617390075Sobrien      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvebx, arglist);
617490075Sobrien    case ALTIVEC_BUILTIN_STVEHX:
617590075Sobrien      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvehx, arglist);
617690075Sobrien    case ALTIVEC_BUILTIN_STVEWX:
617790075Sobrien      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvewx, arglist);
617890075Sobrien    case ALTIVEC_BUILTIN_STVXL:
617990075Sobrien      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvxl, arglist);
6180117395Skan
618190075Sobrien    case ALTIVEC_BUILTIN_MFVSCR:
618290075Sobrien      icode = CODE_FOR_altivec_mfvscr;
618390075Sobrien      tmode = insn_data[icode].operand[0].mode;
618490075Sobrien
618590075Sobrien      if (target == 0
618690075Sobrien	  || GET_MODE (target) != tmode
618790075Sobrien	  || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
618890075Sobrien	target = gen_reg_rtx (tmode);
618990075Sobrien
619090075Sobrien      pat = GEN_FCN (icode) (target);
619190075Sobrien      if (! pat)
619290075Sobrien	return 0;
619390075Sobrien      emit_insn (pat);
619490075Sobrien      return target;
619590075Sobrien
619690075Sobrien    case ALTIVEC_BUILTIN_MTVSCR:
619790075Sobrien      icode = CODE_FOR_altivec_mtvscr;
619890075Sobrien      arg0 = TREE_VALUE (arglist);
619990075Sobrien      op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
620090075Sobrien      mode0 = insn_data[icode].operand[0].mode;
620190075Sobrien
620290075Sobrien      /* If we got invalid arguments bail out before generating bad rtl.  */
620390075Sobrien      if (arg0 == error_mark_node)
6204117395Skan	return const0_rtx;
620590075Sobrien
620690075Sobrien      if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
620790075Sobrien	op0 = copy_to_mode_reg (mode0, op0);
620890075Sobrien
620990075Sobrien      pat = GEN_FCN (icode) (op0);
621090075Sobrien      if (pat)
621190075Sobrien	emit_insn (pat);
621290075Sobrien      return NULL_RTX;
6213117395Skan
621490075Sobrien    case ALTIVEC_BUILTIN_DSSALL:
621590075Sobrien      emit_insn (gen_altivec_dssall ());
621690075Sobrien      return NULL_RTX;
621790075Sobrien
621890075Sobrien    case ALTIVEC_BUILTIN_DSS:
621990075Sobrien      icode = CODE_FOR_altivec_dss;
622090075Sobrien      arg0 = TREE_VALUE (arglist);
6221146895Skan      STRIP_NOPS (arg0);
622290075Sobrien      op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
622390075Sobrien      mode0 = insn_data[icode].operand[0].mode;
622490075Sobrien
622590075Sobrien      /* If we got invalid arguments bail out before generating bad rtl.  */
622690075Sobrien      if (arg0 == error_mark_node)
6227117395Skan	return const0_rtx;
622890075Sobrien
6229117395Skan      if (TREE_CODE (arg0) != INTEGER_CST
6230117395Skan	  || TREE_INT_CST_LOW (arg0) & ~0x3)
6231117395Skan	{
6232117395Skan	  error ("argument to dss must be a 2-bit unsigned literal");
6233117395Skan	  return const0_rtx;
6234117395Skan	}
6235117395Skan
623690075Sobrien      if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
623790075Sobrien	op0 = copy_to_mode_reg (mode0, op0);
623890075Sobrien
623990075Sobrien      emit_insn (gen_altivec_dss (op0));
624090075Sobrien      return NULL_RTX;
6241146895Skan
6242146895Skan    case ALTIVEC_BUILTIN_COMPILETIME_ERROR:
6243146895Skan      arg0 = TREE_VALUE (arglist);
6244146895Skan      while (TREE_CODE (arg0) == NOP_EXPR || TREE_CODE (arg0) == ADDR_EXPR)
6245146895Skan	arg0 = TREE_OPERAND (arg0, 0);
6246146895Skan      error ("invalid parameter combination for `%s' AltiVec intrinsic",
6247146895Skan	     TREE_STRING_POINTER (arg0));
6248146895Skan
6249146895Skan      return const0_rtx;
625090075Sobrien    }
625190075Sobrien
625296263Sobrien  /* Expand abs* operations.  */
625396263Sobrien  d = (struct builtin_description *) bdesc_abs;
6254117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_abs); i++, d++)
625596263Sobrien    if (d->code == fcode)
625696263Sobrien      return altivec_expand_abs_builtin (d->icode, arglist, target);
625796263Sobrien
625896263Sobrien  /* Expand the AltiVec predicates.  */
625996263Sobrien  dp = (struct builtin_description_predicates *) bdesc_altivec_preds;
6260117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_altivec_preds); i++, dp++)
626196263Sobrien    if (dp->code == fcode)
626296263Sobrien      return altivec_expand_predicate_builtin (dp->icode, dp->opcode, arglist, target);
626396263Sobrien
626490075Sobrien  /* LV* are funky.  We initialized them differently.  */
626590075Sobrien  switch (fcode)
626690075Sobrien    {
626790075Sobrien    case ALTIVEC_BUILTIN_LVSL:
6268132718Skan      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvsl,
626990075Sobrien					   arglist, target);
627090075Sobrien    case ALTIVEC_BUILTIN_LVSR:
6271132718Skan      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvsr,
6272117395Skan					  arglist, target);
627390075Sobrien    case ALTIVEC_BUILTIN_LVEBX:
6274132718Skan      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvebx,
6275117395Skan					  arglist, target);
627690075Sobrien    case ALTIVEC_BUILTIN_LVEHX:
6277132718Skan      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvehx,
6278117395Skan					  arglist, target);
627990075Sobrien    case ALTIVEC_BUILTIN_LVEWX:
6280132718Skan      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvewx,
6281117395Skan					  arglist, target);
628290075Sobrien    case ALTIVEC_BUILTIN_LVXL:
6283132718Skan      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvxl,
6284117395Skan					  arglist, target);
628590075Sobrien    case ALTIVEC_BUILTIN_LVX:
6286132718Skan      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvx,
6287117395Skan					  arglist, target);
628890075Sobrien    default:
628990075Sobrien      break;
629090075Sobrien      /* Fall through.  */
629190075Sobrien    }
629290075Sobrien
6293117395Skan  *expandedp = false;
6294117395Skan  return NULL_RTX;
6295117395Skan}
6296117395Skan
6297117395Skan/* Binops that need to be initialized manually, but can be expanded
6298117395Skan   automagically by rs6000_expand_binop_builtin.  */
6299117395Skanstatic struct builtin_description bdesc_2arg_spe[] =
6300117395Skan{
6301117395Skan  { 0, CODE_FOR_spe_evlddx, "__builtin_spe_evlddx", SPE_BUILTIN_EVLDDX },
6302117395Skan  { 0, CODE_FOR_spe_evldwx, "__builtin_spe_evldwx", SPE_BUILTIN_EVLDWX },
6303117395Skan  { 0, CODE_FOR_spe_evldhx, "__builtin_spe_evldhx", SPE_BUILTIN_EVLDHX },
6304117395Skan  { 0, CODE_FOR_spe_evlwhex, "__builtin_spe_evlwhex", SPE_BUILTIN_EVLWHEX },
6305117395Skan  { 0, CODE_FOR_spe_evlwhoux, "__builtin_spe_evlwhoux", SPE_BUILTIN_EVLWHOUX },
6306117395Skan  { 0, CODE_FOR_spe_evlwhosx, "__builtin_spe_evlwhosx", SPE_BUILTIN_EVLWHOSX },
6307117395Skan  { 0, CODE_FOR_spe_evlwwsplatx, "__builtin_spe_evlwwsplatx", SPE_BUILTIN_EVLWWSPLATX },
6308117395Skan  { 0, CODE_FOR_spe_evlwhsplatx, "__builtin_spe_evlwhsplatx", SPE_BUILTIN_EVLWHSPLATX },
6309117395Skan  { 0, CODE_FOR_spe_evlhhesplatx, "__builtin_spe_evlhhesplatx", SPE_BUILTIN_EVLHHESPLATX },
6310117395Skan  { 0, CODE_FOR_spe_evlhhousplatx, "__builtin_spe_evlhhousplatx", SPE_BUILTIN_EVLHHOUSPLATX },
6311117395Skan  { 0, CODE_FOR_spe_evlhhossplatx, "__builtin_spe_evlhhossplatx", SPE_BUILTIN_EVLHHOSSPLATX },
6312117395Skan  { 0, CODE_FOR_spe_evldd, "__builtin_spe_evldd", SPE_BUILTIN_EVLDD },
6313117395Skan  { 0, CODE_FOR_spe_evldw, "__builtin_spe_evldw", SPE_BUILTIN_EVLDW },
6314117395Skan  { 0, CODE_FOR_spe_evldh, "__builtin_spe_evldh", SPE_BUILTIN_EVLDH },
6315117395Skan  { 0, CODE_FOR_spe_evlwhe, "__builtin_spe_evlwhe", SPE_BUILTIN_EVLWHE },
6316117395Skan  { 0, CODE_FOR_spe_evlwhou, "__builtin_spe_evlwhou", SPE_BUILTIN_EVLWHOU },
6317117395Skan  { 0, CODE_FOR_spe_evlwhos, "__builtin_spe_evlwhos", SPE_BUILTIN_EVLWHOS },
6318117395Skan  { 0, CODE_FOR_spe_evlwwsplat, "__builtin_spe_evlwwsplat", SPE_BUILTIN_EVLWWSPLAT },
6319117395Skan  { 0, CODE_FOR_spe_evlwhsplat, "__builtin_spe_evlwhsplat", SPE_BUILTIN_EVLWHSPLAT },
6320117395Skan  { 0, CODE_FOR_spe_evlhhesplat, "__builtin_spe_evlhhesplat", SPE_BUILTIN_EVLHHESPLAT },
6321117395Skan  { 0, CODE_FOR_spe_evlhhousplat, "__builtin_spe_evlhhousplat", SPE_BUILTIN_EVLHHOUSPLAT },
6322117395Skan  { 0, CODE_FOR_spe_evlhhossplat, "__builtin_spe_evlhhossplat", SPE_BUILTIN_EVLHHOSSPLAT }
6323117395Skan};
6324117395Skan
6325117395Skan/* Expand the builtin in EXP and store the result in TARGET.  Store
6326117395Skan   true in *EXPANDEDP if we found a builtin to expand.
6327117395Skan
6328117395Skan   This expands the SPE builtins that are not simple unary and binary
6329117395Skan   operations.  */
6330117395Skanstatic rtx
6331132718Skanspe_expand_builtin (tree exp, rtx target, bool *expandedp)
6332117395Skan{
6333117395Skan  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
6334117395Skan  tree arglist = TREE_OPERAND (exp, 1);
6335117395Skan  tree arg1, arg0;
6336117395Skan  unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
6337117395Skan  enum insn_code icode;
6338117395Skan  enum machine_mode tmode, mode0;
6339117395Skan  rtx pat, op0;
6340117395Skan  struct builtin_description *d;
6341117395Skan  size_t i;
6342117395Skan
6343117395Skan  *expandedp = true;
6344117395Skan
6345117395Skan  /* Syntax check for a 5-bit unsigned immediate.  */
6346117395Skan  switch (fcode)
6347117395Skan    {
6348117395Skan    case SPE_BUILTIN_EVSTDD:
6349117395Skan    case SPE_BUILTIN_EVSTDH:
6350117395Skan    case SPE_BUILTIN_EVSTDW:
6351117395Skan    case SPE_BUILTIN_EVSTWHE:
6352117395Skan    case SPE_BUILTIN_EVSTWHO:
6353117395Skan    case SPE_BUILTIN_EVSTWWE:
6354117395Skan    case SPE_BUILTIN_EVSTWWO:
6355117395Skan      arg1 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
6356117395Skan      if (TREE_CODE (arg1) != INTEGER_CST
6357117395Skan	  || TREE_INT_CST_LOW (arg1) & ~0x1f)
6358117395Skan	{
6359117395Skan	  error ("argument 2 must be a 5-bit unsigned literal");
6360117395Skan	  return const0_rtx;
6361117395Skan	}
6362117395Skan      break;
6363117395Skan    default:
6364117395Skan      break;
6365117395Skan    }
6366117395Skan
6367132718Skan  /* The evsplat*i instructions are not quite generic.  */
6368132718Skan  switch (fcode)
6369132718Skan    {
6370132718Skan    case SPE_BUILTIN_EVSPLATFI:
6371132718Skan      return rs6000_expand_unop_builtin (CODE_FOR_spe_evsplatfi,
6372132718Skan					 arglist, target);
6373132718Skan    case SPE_BUILTIN_EVSPLATI:
6374132718Skan      return rs6000_expand_unop_builtin (CODE_FOR_spe_evsplati,
6375132718Skan					 arglist, target);
6376132718Skan    default:
6377132718Skan      break;
6378132718Skan    }
6379132718Skan
6380117395Skan  d = (struct builtin_description *) bdesc_2arg_spe;
6381117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_2arg_spe); ++i, ++d)
638290075Sobrien    if (d->code == fcode)
6383117395Skan      return rs6000_expand_binop_builtin (d->icode, arglist, target);
638490075Sobrien
6385117395Skan  d = (struct builtin_description *) bdesc_spe_predicates;
6386117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_spe_predicates); ++i, ++d)
6387117395Skan    if (d->code == fcode)
6388117395Skan      return spe_expand_predicate_builtin (d->icode, arglist, target);
6389117395Skan
6390117395Skan  d = (struct builtin_description *) bdesc_spe_evsel;
6391117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_spe_evsel); ++i, ++d)
6392117395Skan    if (d->code == fcode)
6393117395Skan      return spe_expand_evsel_builtin (d->icode, arglist, target);
6394117395Skan
6395117395Skan  switch (fcode)
6396117395Skan    {
6397117395Skan    case SPE_BUILTIN_EVSTDDX:
6398132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstddx, arglist);
6399117395Skan    case SPE_BUILTIN_EVSTDHX:
6400132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstdhx, arglist);
6401117395Skan    case SPE_BUILTIN_EVSTDWX:
6402132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstdwx, arglist);
6403117395Skan    case SPE_BUILTIN_EVSTWHEX:
6404132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstwhex, arglist);
6405117395Skan    case SPE_BUILTIN_EVSTWHOX:
6406132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstwhox, arglist);
6407117395Skan    case SPE_BUILTIN_EVSTWWEX:
6408132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstwwex, arglist);
6409117395Skan    case SPE_BUILTIN_EVSTWWOX:
6410132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstwwox, arglist);
6411117395Skan    case SPE_BUILTIN_EVSTDD:
6412132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstdd, arglist);
6413117395Skan    case SPE_BUILTIN_EVSTDH:
6414132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstdh, arglist);
6415117395Skan    case SPE_BUILTIN_EVSTDW:
6416132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstdw, arglist);
6417117395Skan    case SPE_BUILTIN_EVSTWHE:
6418132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstwhe, arglist);
6419117395Skan    case SPE_BUILTIN_EVSTWHO:
6420132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstwho, arglist);
6421117395Skan    case SPE_BUILTIN_EVSTWWE:
6422132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstwwe, arglist);
6423117395Skan    case SPE_BUILTIN_EVSTWWO:
6424132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstwwo, arglist);
6425117395Skan    case SPE_BUILTIN_MFSPEFSCR:
6426117395Skan      icode = CODE_FOR_spe_mfspefscr;
6427117395Skan      tmode = insn_data[icode].operand[0].mode;
6428117395Skan
6429117395Skan      if (target == 0
6430117395Skan	  || GET_MODE (target) != tmode
6431117395Skan	  || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
6432117395Skan	target = gen_reg_rtx (tmode);
6433117395Skan
6434117395Skan      pat = GEN_FCN (icode) (target);
6435117395Skan      if (! pat)
6436117395Skan	return 0;
6437117395Skan      emit_insn (pat);
6438117395Skan      return target;
6439117395Skan    case SPE_BUILTIN_MTSPEFSCR:
6440117395Skan      icode = CODE_FOR_spe_mtspefscr;
6441117395Skan      arg0 = TREE_VALUE (arglist);
6442117395Skan      op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6443117395Skan      mode0 = insn_data[icode].operand[0].mode;
6444117395Skan
6445117395Skan      if (arg0 == error_mark_node)
6446117395Skan	return const0_rtx;
6447117395Skan
6448117395Skan      if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
6449117395Skan	op0 = copy_to_mode_reg (mode0, op0);
6450117395Skan
6451117395Skan      pat = GEN_FCN (icode) (op0);
6452117395Skan      if (pat)
6453117395Skan	emit_insn (pat);
6454117395Skan      return NULL_RTX;
6455117395Skan    default:
6456117395Skan      break;
6457117395Skan    }
6458117395Skan
6459117395Skan  *expandedp = false;
646090075Sobrien  return NULL_RTX;
646190075Sobrien}
646290075Sobrien
6463117395Skanstatic rtx
6464132718Skanspe_expand_predicate_builtin (enum insn_code icode, tree arglist, rtx target)
6465117395Skan{
6466117395Skan  rtx pat, scratch, tmp;
6467117395Skan  tree form = TREE_VALUE (arglist);
6468117395Skan  tree arg0 = TREE_VALUE (TREE_CHAIN (arglist));
6469117395Skan  tree arg1 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
6470117395Skan  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6471117395Skan  rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
6472117395Skan  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
6473117395Skan  enum machine_mode mode1 = insn_data[icode].operand[2].mode;
6474117395Skan  int form_int;
6475117395Skan  enum rtx_code code;
6476117395Skan
6477117395Skan  if (TREE_CODE (form) != INTEGER_CST)
6478117395Skan    {
6479117395Skan      error ("argument 1 of __builtin_spe_predicate must be a constant");
6480117395Skan      return const0_rtx;
6481117395Skan    }
6482117395Skan  else
6483117395Skan    form_int = TREE_INT_CST_LOW (form);
6484117395Skan
6485117395Skan  if (mode0 != mode1)
6486117395Skan    abort ();
6487117395Skan
6488117395Skan  if (arg0 == error_mark_node || arg1 == error_mark_node)
6489117395Skan    return const0_rtx;
6490117395Skan
6491117395Skan  if (target == 0
6492117395Skan      || GET_MODE (target) != SImode
6493117395Skan      || ! (*insn_data[icode].operand[0].predicate) (target, SImode))
6494117395Skan    target = gen_reg_rtx (SImode);
6495117395Skan
6496117395Skan  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
6497117395Skan    op0 = copy_to_mode_reg (mode0, op0);
6498117395Skan  if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
6499117395Skan    op1 = copy_to_mode_reg (mode1, op1);
6500117395Skan
6501117395Skan  scratch = gen_reg_rtx (CCmode);
6502117395Skan
6503117395Skan  pat = GEN_FCN (icode) (scratch, op0, op1);
6504117395Skan  if (! pat)
6505117395Skan    return const0_rtx;
6506117395Skan  emit_insn (pat);
6507117395Skan
6508117395Skan  /* There are 4 variants for each predicate: _any_, _all_, _upper_,
6509117395Skan     _lower_.  We use one compare, but look in different bits of the
6510117395Skan     CR for each variant.
6511117395Skan
6512117395Skan     There are 2 elements in each SPE simd type (upper/lower).  The CR
6513117395Skan     bits are set as follows:
6514117395Skan
6515117395Skan     BIT0  | BIT 1  | BIT 2   | BIT 3
6516117395Skan     U     |   L    | (U | L) | (U & L)
6517117395Skan
6518117395Skan     So, for an "all" relationship, BIT 3 would be set.
6519117395Skan     For an "any" relationship, BIT 2 would be set.  Etc.
6520117395Skan
6521117395Skan     Following traditional nomenclature, these bits map to:
6522117395Skan
6523117395Skan     BIT0  | BIT 1  | BIT 2   | BIT 3
6524117395Skan     LT    | GT     | EQ      | OV
6525117395Skan
6526117395Skan     Later, we will generate rtl to look in the LT/EQ/EQ/OV bits.
6527117395Skan  */
6528117395Skan
6529117395Skan  switch (form_int)
6530117395Skan    {
6531117395Skan      /* All variant.  OV bit.  */
6532117395Skan    case 0:
6533117395Skan      /* We need to get to the OV bit, which is the ORDERED bit.  We
6534117395Skan	 could generate (ordered:SI (reg:CC xx) (const_int 0)), but
6535117395Skan	 that's ugly and will trigger a validate_condition_mode abort.
6536117395Skan	 So let's just use another pattern.  */
6537117395Skan      emit_insn (gen_move_from_CR_ov_bit (target, scratch));
6538117395Skan      return target;
6539117395Skan      /* Any variant.  EQ bit.  */
6540117395Skan    case 1:
6541117395Skan      code = EQ;
6542117395Skan      break;
6543117395Skan      /* Upper variant.  LT bit.  */
6544117395Skan    case 2:
6545117395Skan      code = LT;
6546117395Skan      break;
6547117395Skan      /* Lower variant.  GT bit.  */
6548117395Skan    case 3:
6549117395Skan      code = GT;
6550117395Skan      break;
6551117395Skan    default:
6552117395Skan      error ("argument 1 of __builtin_spe_predicate is out of range");
6553117395Skan      return const0_rtx;
6554117395Skan    }
6555117395Skan
6556117395Skan  tmp = gen_rtx_fmt_ee (code, SImode, scratch, const0_rtx);
6557117395Skan  emit_move_insn (target, tmp);
6558117395Skan
6559117395Skan  return target;
6560117395Skan}
6561117395Skan
6562117395Skan/* The evsel builtins look like this:
6563117395Skan
6564117395Skan     e = __builtin_spe_evsel_OP (a, b, c, d);
6565117395Skan
6566117395Skan   and work like this:
6567117395Skan
6568117395Skan     e[upper] = a[upper] *OP* b[upper] ? c[upper] : d[upper];
6569117395Skan     e[lower] = a[lower] *OP* b[lower] ? c[lower] : d[lower];
6570117395Skan*/
6571117395Skan
6572117395Skanstatic rtx
6573132718Skanspe_expand_evsel_builtin (enum insn_code icode, tree arglist, rtx target)
6574117395Skan{
6575117395Skan  rtx pat, scratch;
6576117395Skan  tree arg0 = TREE_VALUE (arglist);
6577117395Skan  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
6578117395Skan  tree arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
6579117395Skan  tree arg3 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (arglist))));
6580117395Skan  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6581117395Skan  rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
6582117395Skan  rtx op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
6583117395Skan  rtx op3 = expand_expr (arg3, NULL_RTX, VOIDmode, 0);
6584117395Skan  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
6585117395Skan  enum machine_mode mode1 = insn_data[icode].operand[2].mode;
6586117395Skan
6587117395Skan  if (mode0 != mode1)
6588117395Skan    abort ();
6589117395Skan
6590117395Skan  if (arg0 == error_mark_node || arg1 == error_mark_node
6591117395Skan      || arg2 == error_mark_node || arg3 == error_mark_node)
6592117395Skan    return const0_rtx;
6593117395Skan
6594117395Skan  if (target == 0
6595117395Skan      || GET_MODE (target) != mode0
6596117395Skan      || ! (*insn_data[icode].operand[0].predicate) (target, mode0))
6597117395Skan    target = gen_reg_rtx (mode0);
6598117395Skan
6599117395Skan  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
6600117395Skan    op0 = copy_to_mode_reg (mode0, op0);
6601117395Skan  if (! (*insn_data[icode].operand[1].predicate) (op1, mode1))
6602117395Skan    op1 = copy_to_mode_reg (mode0, op1);
6603117395Skan  if (! (*insn_data[icode].operand[1].predicate) (op2, mode1))
6604117395Skan    op2 = copy_to_mode_reg (mode0, op2);
6605117395Skan  if (! (*insn_data[icode].operand[1].predicate) (op3, mode1))
6606117395Skan    op3 = copy_to_mode_reg (mode0, op3);
6607117395Skan
6608117395Skan  /* Generate the compare.  */
6609117395Skan  scratch = gen_reg_rtx (CCmode);
6610117395Skan  pat = GEN_FCN (icode) (scratch, op0, op1);
6611117395Skan  if (! pat)
6612117395Skan    return const0_rtx;
6613117395Skan  emit_insn (pat);
6614117395Skan
6615117395Skan  if (mode0 == V2SImode)
6616117395Skan    emit_insn (gen_spe_evsel (target, op2, op3, scratch));
6617117395Skan  else
6618117395Skan    emit_insn (gen_spe_evsel_fs (target, op2, op3, scratch));
6619117395Skan
6620117395Skan  return target;
6621117395Skan}
6622117395Skan
662390075Sobrien/* Expand an expression EXP that calls a built-in function,
662490075Sobrien   with result going to TARGET if that's convenient
662590075Sobrien   (and in mode MODE if that's convenient).
662690075Sobrien   SUBTARGET may be used as the target for computing one of EXP's operands.
662790075Sobrien   IGNORE is nonzero if the value is to be ignored.  */
662890075Sobrien
662990075Sobrienstatic rtx
6630132718Skanrs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
6631132718Skan		      enum machine_mode mode ATTRIBUTE_UNUSED,
6632132718Skan		      int ignore ATTRIBUTE_UNUSED)
663390075Sobrien{
6634117395Skan  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
6635117395Skan  tree arglist = TREE_OPERAND (exp, 1);
6636117395Skan  unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
6637117395Skan  struct builtin_description *d;
6638117395Skan  size_t i;
6639117395Skan  rtx ret;
6640117395Skan  bool success;
6641117395Skan
664290075Sobrien  if (TARGET_ALTIVEC)
6643117395Skan    {
6644117395Skan      ret = altivec_expand_builtin (exp, target, &success);
664590075Sobrien
6646117395Skan      if (success)
6647117395Skan	return ret;
6648117395Skan    }
6649117395Skan  if (TARGET_SPE)
6650117395Skan    {
6651117395Skan      ret = spe_expand_builtin (exp, target, &success);
6652117395Skan
6653117395Skan      if (success)
6654117395Skan	return ret;
6655117395Skan    }
6656117395Skan
6657117395Skan  if (TARGET_ALTIVEC || TARGET_SPE)
6658117395Skan    {
6659117395Skan      /* Handle simple unary operations.  */
6660117395Skan      d = (struct builtin_description *) bdesc_1arg;
6661117395Skan      for (i = 0; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
6662117395Skan	if (d->code == fcode)
6663117395Skan	  return rs6000_expand_unop_builtin (d->icode, arglist, target);
6664117395Skan
6665117395Skan      /* Handle simple binary operations.  */
6666117395Skan      d = (struct builtin_description *) bdesc_2arg;
6667117395Skan      for (i = 0; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
6668117395Skan	if (d->code == fcode)
6669117395Skan	  return rs6000_expand_binop_builtin (d->icode, arglist, target);
6670117395Skan
6671117395Skan      /* Handle simple ternary operations.  */
6672117395Skan      d = (struct builtin_description *) bdesc_3arg;
6673117395Skan      for (i = 0; i < ARRAY_SIZE  (bdesc_3arg); i++, d++)
6674117395Skan	if (d->code == fcode)
6675117395Skan	  return rs6000_expand_ternop_builtin (d->icode, arglist, target);
6676117395Skan    }
6677117395Skan
667890075Sobrien  abort ();
6679117395Skan  return NULL_RTX;
668090075Sobrien}
668190075Sobrien
668290075Sobrienstatic void
6683132718Skanrs6000_init_builtins (void)
668490075Sobrien{
6685132718Skan  opaque_V2SI_type_node = copy_node (V2SI_type_node);
6686132718Skan  opaque_V2SF_type_node = copy_node (V2SF_type_node);
6687132718Skan  opaque_p_V2SI_type_node = build_pointer_type (opaque_V2SI_type_node);
6688132718Skan
6689146895Skan  /* The 'vector bool ...' types must be kept distinct from 'vector unsigned ...'
6690146895Skan     types, especially in C++ land.  Similarly, 'vector pixel' is distinct from+     'vector unsigned short'.  */
6691146895Skan
6692146895Skan  bool_char_type_node = copy_node (unsigned_intQI_type_node);
6693146895Skan  TYPE_MAIN_VARIANT (bool_char_type_node) = bool_char_type_node;
6694146895Skan  bool_short_type_node = copy_node (unsigned_intHI_type_node);
6695146895Skan  TYPE_MAIN_VARIANT (bool_short_type_node) = bool_short_type_node;
6696146895Skan  bool_int_type_node = copy_node (unsigned_intSI_type_node);
6697146895Skan  TYPE_MAIN_VARIANT (bool_int_type_node) = bool_int_type_node;
6698146895Skan  pixel_type_node = copy_node (unsigned_intHI_type_node);
6699146895Skan  TYPE_MAIN_VARIANT (pixel_type_node) = pixel_type_node;
6700146895Skan
6701146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
6702146895Skan					    get_identifier ("__bool char"),
6703146895Skan					    bool_char_type_node));
6704146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
6705146895Skan					    get_identifier ("__bool short"),
6706146895Skan					    bool_short_type_node));
6707146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
6708146895Skan					    get_identifier ("__bool int"),
6709146895Skan					    bool_int_type_node));
6710146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
6711146895Skan					    get_identifier ("__pixel"),
6712146895Skan					    pixel_type_node));
6713146895Skan
6714146895Skan  bool_V16QI_type_node = make_vector (V16QImode, bool_char_type_node, 1);
6715146895Skan  bool_V8HI_type_node = make_vector (V8HImode, bool_short_type_node, 1);
6716146895Skan  bool_V4SI_type_node = make_vector (V4SImode, bool_int_type_node, 1);
6717146895Skan  pixel_V8HI_type_node = make_vector (V8HImode, pixel_type_node, 1);
6718146895Skan
6719146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
6720146895Skan					    get_identifier ("__vector unsigned char"),
6721146895Skan					    unsigned_V16QI_type_node));
6722146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
6723146895Skan					    get_identifier ("__vector signed char"),
6724146895Skan					    V16QI_type_node));
6725146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
6726146895Skan					    get_identifier ("__vector __bool char"),
6727146895Skan					    bool_V16QI_type_node));
6728146895Skan
6729146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
6730146895Skan					    get_identifier ("__vector unsigned short"),
6731146895Skan					    unsigned_V8HI_type_node));
6732146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
6733146895Skan					    get_identifier ("__vector signed short"),
6734146895Skan					    V8HI_type_node));
6735146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
6736146895Skan					    get_identifier ("__vector __bool short"),
6737146895Skan					    bool_V8HI_type_node));
6738146895Skan
6739146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
6740146895Skan					    get_identifier ("__vector unsigned int"),
6741146895Skan					    unsigned_V4SI_type_node));
6742146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
6743146895Skan					    get_identifier ("__vector signed int"),
6744146895Skan					    V4SI_type_node));
6745146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
6746146895Skan					    get_identifier ("__vector __bool int"),
6747146895Skan					    bool_V4SI_type_node));
6748146895Skan
6749146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
6750146895Skan					    get_identifier ("__vector float"),
6751146895Skan					    V4SF_type_node));
6752146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
6753146895Skan					    get_identifier ("__vector __pixel"),
6754146895Skan					    pixel_V8HI_type_node));
6755146895Skan
6756117395Skan  if (TARGET_SPE)
6757117395Skan    spe_init_builtins ();
675890075Sobrien  if (TARGET_ALTIVEC)
675990075Sobrien    altivec_init_builtins ();
6760117395Skan  if (TARGET_ALTIVEC || TARGET_SPE)
6761117395Skan    rs6000_common_init_builtins ();
676290075Sobrien}
676390075Sobrien
6764117395Skan/* Search through a set of builtins and enable the mask bits.
6765117395Skan   DESC is an array of builtins.
6766132718Skan   SIZE is the total number of builtins.
6767117395Skan   START is the builtin enum at which to start.
6768117395Skan   END is the builtin enum at which to end.  */
676990075Sobrienstatic void
6770132718Skanenable_mask_for_builtins (struct builtin_description *desc, int size,
6771132718Skan			  enum rs6000_builtins start,
6772132718Skan			  enum rs6000_builtins end)
677390075Sobrien{
6774117395Skan  int i;
677590075Sobrien
6776117395Skan  for (i = 0; i < size; ++i)
6777117395Skan    if (desc[i].code == start)
6778117395Skan      break;
677990075Sobrien
6780117395Skan  if (i == size)
6781117395Skan    return;
678290075Sobrien
6783117395Skan  for (; i < size; ++i)
6784117395Skan    {
6785117395Skan      /* Flip all the bits on.  */
6786117395Skan      desc[i].mask = target_flags;
6787117395Skan      if (desc[i].code == end)
6788117395Skan	break;
6789117395Skan    }
6790117395Skan}
679190075Sobrien
6792117395Skanstatic void
6793132718Skanspe_init_builtins (void)
6794117395Skan{
6795117395Skan  tree endlink = void_list_node;
6796117395Skan  tree puint_type_node = build_pointer_type (unsigned_type_node);
6797117395Skan  tree pushort_type_node = build_pointer_type (short_unsigned_type_node);
6798117395Skan  struct builtin_description *d;
6799117395Skan  size_t i;
680090075Sobrien
6801117395Skan  tree v2si_ftype_4_v2si
6802117395Skan    = build_function_type
6803132718Skan    (opaque_V2SI_type_node,
6804132718Skan     tree_cons (NULL_TREE, opaque_V2SI_type_node,
6805132718Skan		tree_cons (NULL_TREE, opaque_V2SI_type_node,
6806132718Skan			   tree_cons (NULL_TREE, opaque_V2SI_type_node,
6807132718Skan				      tree_cons (NULL_TREE, opaque_V2SI_type_node,
6808117395Skan						 endlink)))));
680990075Sobrien
6810117395Skan  tree v2sf_ftype_4_v2sf
6811117395Skan    = build_function_type
6812132718Skan    (opaque_V2SF_type_node,
6813132718Skan     tree_cons (NULL_TREE, opaque_V2SF_type_node,
6814132718Skan		tree_cons (NULL_TREE, opaque_V2SF_type_node,
6815132718Skan			   tree_cons (NULL_TREE, opaque_V2SF_type_node,
6816132718Skan				      tree_cons (NULL_TREE, opaque_V2SF_type_node,
6817117395Skan						 endlink)))));
681890075Sobrien
6819117395Skan  tree int_ftype_int_v2si_v2si
6820117395Skan    = build_function_type
6821117395Skan    (integer_type_node,
6822117395Skan     tree_cons (NULL_TREE, integer_type_node,
6823132718Skan		tree_cons (NULL_TREE, opaque_V2SI_type_node,
6824132718Skan			   tree_cons (NULL_TREE, opaque_V2SI_type_node,
6825117395Skan				      endlink))));
682690075Sobrien
6827117395Skan  tree int_ftype_int_v2sf_v2sf
6828117395Skan    = build_function_type
6829117395Skan    (integer_type_node,
6830117395Skan     tree_cons (NULL_TREE, integer_type_node,
6831132718Skan		tree_cons (NULL_TREE, opaque_V2SF_type_node,
6832132718Skan			   tree_cons (NULL_TREE, opaque_V2SF_type_node,
6833117395Skan				      endlink))));
683490075Sobrien
6835117395Skan  tree void_ftype_v2si_puint_int
683690075Sobrien    = build_function_type (void_type_node,
6837132718Skan			   tree_cons (NULL_TREE, opaque_V2SI_type_node,
6838117395Skan				      tree_cons (NULL_TREE, puint_type_node,
683990075Sobrien						 tree_cons (NULL_TREE,
6840117395Skan							    integer_type_node,
684190075Sobrien							    endlink))));
684290075Sobrien
6843117395Skan  tree void_ftype_v2si_puint_char
684490075Sobrien    = build_function_type (void_type_node,
6845132718Skan			   tree_cons (NULL_TREE, opaque_V2SI_type_node,
6846117395Skan				      tree_cons (NULL_TREE, puint_type_node,
684790075Sobrien						 tree_cons (NULL_TREE,
6848117395Skan							    char_type_node,
684990075Sobrien							    endlink))));
685090075Sobrien
6851117395Skan  tree void_ftype_v2si_pv2si_int
685290075Sobrien    = build_function_type (void_type_node,
6853132718Skan			   tree_cons (NULL_TREE, opaque_V2SI_type_node,
6854132718Skan				      tree_cons (NULL_TREE, opaque_p_V2SI_type_node,
685590075Sobrien						 tree_cons (NULL_TREE,
6856117395Skan							    integer_type_node,
685790075Sobrien							    endlink))));
685890075Sobrien
6859117395Skan  tree void_ftype_v2si_pv2si_char
686090075Sobrien    = build_function_type (void_type_node,
6861132718Skan			   tree_cons (NULL_TREE, opaque_V2SI_type_node,
6862132718Skan				      tree_cons (NULL_TREE, opaque_p_V2SI_type_node,
686390075Sobrien						 tree_cons (NULL_TREE,
6864117395Skan							    char_type_node,
686590075Sobrien							    endlink))));
686690075Sobrien
6867117395Skan  tree void_ftype_int
686890075Sobrien    = build_function_type (void_type_node,
6869117395Skan			   tree_cons (NULL_TREE, integer_type_node, endlink));
687090075Sobrien
6871117395Skan  tree int_ftype_void
6872132718Skan    = build_function_type (integer_type_node, endlink);
687390075Sobrien
6874117395Skan  tree v2si_ftype_pv2si_int
6875132718Skan    = build_function_type (opaque_V2SI_type_node,
6876132718Skan			   tree_cons (NULL_TREE, opaque_p_V2SI_type_node,
6877117395Skan				      tree_cons (NULL_TREE, integer_type_node,
6878117395Skan						 endlink)));
6879117395Skan
6880117395Skan  tree v2si_ftype_puint_int
6881132718Skan    = build_function_type (opaque_V2SI_type_node,
6882117395Skan			   tree_cons (NULL_TREE, puint_type_node,
6883117395Skan				      tree_cons (NULL_TREE, integer_type_node,
6884117395Skan						 endlink)));
6885117395Skan
6886117395Skan  tree v2si_ftype_pushort_int
6887132718Skan    = build_function_type (opaque_V2SI_type_node,
6888117395Skan			   tree_cons (NULL_TREE, pushort_type_node,
6889117395Skan				      tree_cons (NULL_TREE, integer_type_node,
6890117395Skan						 endlink)));
6891117395Skan
6892132718Skan  tree v2si_ftype_signed_char
6893132718Skan    = build_function_type (opaque_V2SI_type_node,
6894132718Skan			   tree_cons (NULL_TREE, signed_char_type_node,
6895132718Skan				      endlink));
6896132718Skan
6897117395Skan  /* The initialization of the simple binary and unary builtins is
6898117395Skan     done in rs6000_common_init_builtins, but we have to enable the
6899117395Skan     mask bits here manually because we have run out of `target_flags'
6900117395Skan     bits.  We really need to redesign this mask business.  */
6901117395Skan
6902117395Skan  enable_mask_for_builtins ((struct builtin_description *) bdesc_2arg,
6903117395Skan			    ARRAY_SIZE (bdesc_2arg),
6904117395Skan			    SPE_BUILTIN_EVADDW,
6905117395Skan			    SPE_BUILTIN_EVXOR);
6906117395Skan  enable_mask_for_builtins ((struct builtin_description *) bdesc_1arg,
6907117395Skan			    ARRAY_SIZE (bdesc_1arg),
6908117395Skan			    SPE_BUILTIN_EVABS,
6909117395Skan			    SPE_BUILTIN_EVSUBFUSIAAW);
6910117395Skan  enable_mask_for_builtins ((struct builtin_description *) bdesc_spe_predicates,
6911117395Skan			    ARRAY_SIZE (bdesc_spe_predicates),
6912117395Skan			    SPE_BUILTIN_EVCMPEQ,
6913117395Skan			    SPE_BUILTIN_EVFSTSTLT);
6914117395Skan  enable_mask_for_builtins ((struct builtin_description *) bdesc_spe_evsel,
6915117395Skan			    ARRAY_SIZE (bdesc_spe_evsel),
6916117395Skan			    SPE_BUILTIN_EVSEL_CMPGTS,
6917117395Skan			    SPE_BUILTIN_EVSEL_FSTSTEQ);
6918117395Skan
6919132718Skan  (*lang_hooks.decls.pushdecl)
6920132718Skan    (build_decl (TYPE_DECL, get_identifier ("__ev64_opaque__"),
6921132718Skan		 opaque_V2SI_type_node));
6922132718Skan
6923117395Skan  /* Initialize irregular SPE builtins.  */
6924117395Skan
6925117395Skan  def_builtin (target_flags, "__builtin_spe_mtspefscr", void_ftype_int, SPE_BUILTIN_MTSPEFSCR);
6926117395Skan  def_builtin (target_flags, "__builtin_spe_mfspefscr", int_ftype_void, SPE_BUILTIN_MFSPEFSCR);
6927117395Skan  def_builtin (target_flags, "__builtin_spe_evstddx", void_ftype_v2si_pv2si_int, SPE_BUILTIN_EVSTDDX);
6928117395Skan  def_builtin (target_flags, "__builtin_spe_evstdhx", void_ftype_v2si_pv2si_int, SPE_BUILTIN_EVSTDHX);
6929117395Skan  def_builtin (target_flags, "__builtin_spe_evstdwx", void_ftype_v2si_pv2si_int, SPE_BUILTIN_EVSTDWX);
6930117395Skan  def_builtin (target_flags, "__builtin_spe_evstwhex", void_ftype_v2si_puint_int, SPE_BUILTIN_EVSTWHEX);
6931117395Skan  def_builtin (target_flags, "__builtin_spe_evstwhox", void_ftype_v2si_puint_int, SPE_BUILTIN_EVSTWHOX);
6932117395Skan  def_builtin (target_flags, "__builtin_spe_evstwwex", void_ftype_v2si_puint_int, SPE_BUILTIN_EVSTWWEX);
6933117395Skan  def_builtin (target_flags, "__builtin_spe_evstwwox", void_ftype_v2si_puint_int, SPE_BUILTIN_EVSTWWOX);
6934117395Skan  def_builtin (target_flags, "__builtin_spe_evstdd", void_ftype_v2si_pv2si_char, SPE_BUILTIN_EVSTDD);
6935117395Skan  def_builtin (target_flags, "__builtin_spe_evstdh", void_ftype_v2si_pv2si_char, SPE_BUILTIN_EVSTDH);
6936117395Skan  def_builtin (target_flags, "__builtin_spe_evstdw", void_ftype_v2si_pv2si_char, SPE_BUILTIN_EVSTDW);
6937117395Skan  def_builtin (target_flags, "__builtin_spe_evstwhe", void_ftype_v2si_puint_char, SPE_BUILTIN_EVSTWHE);
6938117395Skan  def_builtin (target_flags, "__builtin_spe_evstwho", void_ftype_v2si_puint_char, SPE_BUILTIN_EVSTWHO);
6939117395Skan  def_builtin (target_flags, "__builtin_spe_evstwwe", void_ftype_v2si_puint_char, SPE_BUILTIN_EVSTWWE);
6940117395Skan  def_builtin (target_flags, "__builtin_spe_evstwwo", void_ftype_v2si_puint_char, SPE_BUILTIN_EVSTWWO);
6941132718Skan  def_builtin (target_flags, "__builtin_spe_evsplatfi", v2si_ftype_signed_char, SPE_BUILTIN_EVSPLATFI);
6942132718Skan  def_builtin (target_flags, "__builtin_spe_evsplati", v2si_ftype_signed_char, SPE_BUILTIN_EVSPLATI);
6943117395Skan
6944117395Skan  /* Loads.  */
6945117395Skan  def_builtin (target_flags, "__builtin_spe_evlddx", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDDX);
6946117395Skan  def_builtin (target_flags, "__builtin_spe_evldwx", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDWX);
6947117395Skan  def_builtin (target_flags, "__builtin_spe_evldhx", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDHX);
6948117395Skan  def_builtin (target_flags, "__builtin_spe_evlwhex", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHEX);
6949117395Skan  def_builtin (target_flags, "__builtin_spe_evlwhoux", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHOUX);
6950117395Skan  def_builtin (target_flags, "__builtin_spe_evlwhosx", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHOSX);
6951117395Skan  def_builtin (target_flags, "__builtin_spe_evlwwsplatx", v2si_ftype_puint_int, SPE_BUILTIN_EVLWWSPLATX);
6952117395Skan  def_builtin (target_flags, "__builtin_spe_evlwhsplatx", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHSPLATX);
6953117395Skan  def_builtin (target_flags, "__builtin_spe_evlhhesplatx", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHESPLATX);
6954117395Skan  def_builtin (target_flags, "__builtin_spe_evlhhousplatx", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHOUSPLATX);
6955117395Skan  def_builtin (target_flags, "__builtin_spe_evlhhossplatx", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHOSSPLATX);
6956117395Skan  def_builtin (target_flags, "__builtin_spe_evldd", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDD);
6957117395Skan  def_builtin (target_flags, "__builtin_spe_evldw", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDW);
6958117395Skan  def_builtin (target_flags, "__builtin_spe_evldh", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDH);
6959117395Skan  def_builtin (target_flags, "__builtin_spe_evlhhesplat", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHESPLAT);
6960117395Skan  def_builtin (target_flags, "__builtin_spe_evlhhossplat", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHOSSPLAT);
6961117395Skan  def_builtin (target_flags, "__builtin_spe_evlhhousplat", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHOUSPLAT);
6962117395Skan  def_builtin (target_flags, "__builtin_spe_evlwhe", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHE);
6963117395Skan  def_builtin (target_flags, "__builtin_spe_evlwhos", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHOS);
6964117395Skan  def_builtin (target_flags, "__builtin_spe_evlwhou", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHOU);
6965117395Skan  def_builtin (target_flags, "__builtin_spe_evlwhsplat", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHSPLAT);
6966117395Skan  def_builtin (target_flags, "__builtin_spe_evlwwsplat", v2si_ftype_puint_int, SPE_BUILTIN_EVLWWSPLAT);
6967117395Skan
6968117395Skan  /* Predicates.  */
6969117395Skan  d = (struct builtin_description *) bdesc_spe_predicates;
6970117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_spe_predicates); ++i, d++)
6971117395Skan    {
6972117395Skan      tree type;
6973117395Skan
6974117395Skan      switch (insn_data[d->icode].operand[1].mode)
6975117395Skan	{
6976117395Skan	case V2SImode:
6977117395Skan	  type = int_ftype_int_v2si_v2si;
6978117395Skan	  break;
6979117395Skan	case V2SFmode:
6980117395Skan	  type = int_ftype_int_v2sf_v2sf;
6981117395Skan	  break;
6982117395Skan	default:
6983117395Skan	  abort ();
6984117395Skan	}
6985117395Skan
6986117395Skan      def_builtin (d->mask, d->name, type, d->code);
6987117395Skan    }
6988117395Skan
6989117395Skan  /* Evsel predicates.  */
6990117395Skan  d = (struct builtin_description *) bdesc_spe_evsel;
6991117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_spe_evsel); ++i, d++)
6992117395Skan    {
6993117395Skan      tree type;
6994117395Skan
6995117395Skan      switch (insn_data[d->icode].operand[1].mode)
6996117395Skan	{
6997117395Skan	case V2SImode:
6998117395Skan	  type = v2si_ftype_4_v2si;
6999117395Skan	  break;
7000117395Skan	case V2SFmode:
7001117395Skan	  type = v2sf_ftype_4_v2sf;
7002117395Skan	  break;
7003117395Skan	default:
7004117395Skan	  abort ();
7005117395Skan	}
7006117395Skan
7007117395Skan      def_builtin (d->mask, d->name, type, d->code);
7008117395Skan    }
7009117395Skan}
7010117395Skan
7011117395Skanstatic void
7012132718Skanaltivec_init_builtins (void)
7013117395Skan{
7014117395Skan  struct builtin_description *d;
7015117395Skan  struct builtin_description_predicates *dp;
7016117395Skan  size_t i;
7017117395Skan  tree pfloat_type_node = build_pointer_type (float_type_node);
7018117395Skan  tree pint_type_node = build_pointer_type (integer_type_node);
7019117395Skan  tree pshort_type_node = build_pointer_type (short_integer_type_node);
7020117395Skan  tree pchar_type_node = build_pointer_type (char_type_node);
7021117395Skan
7022117395Skan  tree pvoid_type_node = build_pointer_type (void_type_node);
7023117395Skan
7024117395Skan  tree pcfloat_type_node = build_pointer_type (build_qualified_type (float_type_node, TYPE_QUAL_CONST));
7025117395Skan  tree pcint_type_node = build_pointer_type (build_qualified_type (integer_type_node, TYPE_QUAL_CONST));
7026117395Skan  tree pcshort_type_node = build_pointer_type (build_qualified_type (short_integer_type_node, TYPE_QUAL_CONST));
7027117395Skan  tree pcchar_type_node = build_pointer_type (build_qualified_type (char_type_node, TYPE_QUAL_CONST));
7028117395Skan
7029117395Skan  tree pcvoid_type_node = build_pointer_type (build_qualified_type (void_type_node, TYPE_QUAL_CONST));
7030117395Skan
7031117395Skan  tree int_ftype_int_v4si_v4si
7032117395Skan    = build_function_type_list (integer_type_node,
7033117395Skan				integer_type_node, V4SI_type_node,
7034117395Skan				V4SI_type_node, NULL_TREE);
7035117395Skan  tree v4sf_ftype_pcfloat
7036117395Skan    = build_function_type_list (V4SF_type_node, pcfloat_type_node, NULL_TREE);
7037117395Skan  tree void_ftype_pfloat_v4sf
7038117395Skan    = build_function_type_list (void_type_node,
7039117395Skan				pfloat_type_node, V4SF_type_node, NULL_TREE);
7040117395Skan  tree v4si_ftype_pcint
7041117395Skan    = build_function_type_list (V4SI_type_node, pcint_type_node, NULL_TREE);
7042117395Skan  tree void_ftype_pint_v4si
7043117395Skan    = build_function_type_list (void_type_node,
7044117395Skan				pint_type_node, V4SI_type_node, NULL_TREE);
7045117395Skan  tree v8hi_ftype_pcshort
7046117395Skan    = build_function_type_list (V8HI_type_node, pcshort_type_node, NULL_TREE);
7047117395Skan  tree void_ftype_pshort_v8hi
7048117395Skan    = build_function_type_list (void_type_node,
7049117395Skan				pshort_type_node, V8HI_type_node, NULL_TREE);
7050117395Skan  tree v16qi_ftype_pcchar
7051117395Skan    = build_function_type_list (V16QI_type_node, pcchar_type_node, NULL_TREE);
7052117395Skan  tree void_ftype_pchar_v16qi
7053117395Skan    = build_function_type_list (void_type_node,
7054117395Skan				pchar_type_node, V16QI_type_node, NULL_TREE);
7055117395Skan  tree void_ftype_v4si
7056117395Skan    = build_function_type_list (void_type_node, V4SI_type_node, NULL_TREE);
705790075Sobrien  tree v8hi_ftype_void
705896263Sobrien    = build_function_type (V8HI_type_node, void_list_node);
7059117395Skan  tree void_ftype_void
7060117395Skan    = build_function_type (void_type_node, void_list_node);
7061146895Skan  tree void_ftype_int
7062146895Skan    = build_function_type_list (void_type_node, integer_type_node, NULL_TREE);
706390075Sobrien
7064132718Skan  tree v16qi_ftype_long_pcvoid
7065117395Skan    = build_function_type_list (V16QI_type_node,
7066132718Skan				long_integer_type_node, pcvoid_type_node, NULL_TREE);
7067132718Skan  tree v8hi_ftype_long_pcvoid
7068117395Skan    = build_function_type_list (V8HI_type_node,
7069132718Skan				long_integer_type_node, pcvoid_type_node, NULL_TREE);
7070132718Skan  tree v4si_ftype_long_pcvoid
7071117395Skan    = build_function_type_list (V4SI_type_node,
7072132718Skan				long_integer_type_node, pcvoid_type_node, NULL_TREE);
707390075Sobrien
7074132718Skan  tree void_ftype_v4si_long_pvoid
7075117395Skan    = build_function_type_list (void_type_node,
7076132718Skan				V4SI_type_node, long_integer_type_node,
7077117395Skan				pvoid_type_node, NULL_TREE);
7078132718Skan  tree void_ftype_v16qi_long_pvoid
7079117395Skan    = build_function_type_list (void_type_node,
7080132718Skan				V16QI_type_node, long_integer_type_node,
7081117395Skan				pvoid_type_node, NULL_TREE);
7082132718Skan  tree void_ftype_v8hi_long_pvoid
7083117395Skan    = build_function_type_list (void_type_node,
7084132718Skan				V8HI_type_node, long_integer_type_node,
7085117395Skan				pvoid_type_node, NULL_TREE);
7086117395Skan  tree int_ftype_int_v8hi_v8hi
7087117395Skan    = build_function_type_list (integer_type_node,
7088117395Skan				integer_type_node, V8HI_type_node,
7089117395Skan				V8HI_type_node, NULL_TREE);
7090117395Skan  tree int_ftype_int_v16qi_v16qi
7091117395Skan    = build_function_type_list (integer_type_node,
7092117395Skan				integer_type_node, V16QI_type_node,
7093117395Skan				V16QI_type_node, NULL_TREE);
7094117395Skan  tree int_ftype_int_v4sf_v4sf
7095117395Skan    = build_function_type_list (integer_type_node,
7096117395Skan				integer_type_node, V4SF_type_node,
7097117395Skan				V4SF_type_node, NULL_TREE);
7098117395Skan  tree v4si_ftype_v4si
7099117395Skan    = build_function_type_list (V4SI_type_node, V4SI_type_node, NULL_TREE);
7100117395Skan  tree v8hi_ftype_v8hi
7101117395Skan    = build_function_type_list (V8HI_type_node, V8HI_type_node, NULL_TREE);
7102117395Skan  tree v16qi_ftype_v16qi
7103117395Skan    = build_function_type_list (V16QI_type_node, V16QI_type_node, NULL_TREE);
7104117395Skan  tree v4sf_ftype_v4sf
7105117395Skan    = build_function_type_list (V4SF_type_node, V4SF_type_node, NULL_TREE);
7106146895Skan  tree void_ftype_pcvoid_int_int
7107117395Skan    = build_function_type_list (void_type_node,
7108117395Skan				pcvoid_type_node, integer_type_node,
7109146895Skan				integer_type_node, NULL_TREE);
7110146895Skan  tree int_ftype_pcchar
7111146895Skan    = build_function_type_list (integer_type_node,
7112146895Skan				pcchar_type_node, NULL_TREE);
7113117395Skan
7114117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_4sf", v4sf_ftype_pcfloat,
7115117395Skan	       ALTIVEC_BUILTIN_LD_INTERNAL_4sf);
7116117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_4sf", void_ftype_pfloat_v4sf,
7117117395Skan	       ALTIVEC_BUILTIN_ST_INTERNAL_4sf);
7118117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_4si", v4si_ftype_pcint,
7119117395Skan	       ALTIVEC_BUILTIN_LD_INTERNAL_4si);
7120117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_4si", void_ftype_pint_v4si,
7121117395Skan	       ALTIVEC_BUILTIN_ST_INTERNAL_4si);
7122117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_8hi", v8hi_ftype_pcshort,
7123117395Skan	       ALTIVEC_BUILTIN_LD_INTERNAL_8hi);
7124117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_8hi", void_ftype_pshort_v8hi,
7125117395Skan	       ALTIVEC_BUILTIN_ST_INTERNAL_8hi);
7126117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_16qi", v16qi_ftype_pcchar,
7127117395Skan	       ALTIVEC_BUILTIN_LD_INTERNAL_16qi);
7128117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_16qi", void_ftype_pchar_v16qi,
7129117395Skan	       ALTIVEC_BUILTIN_ST_INTERNAL_16qi);
7130117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_mtvscr", void_ftype_v4si, ALTIVEC_BUILTIN_MTVSCR);
7131117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_mfvscr", v8hi_ftype_void, ALTIVEC_BUILTIN_MFVSCR);
7132117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_dssall", void_ftype_void, ALTIVEC_BUILTIN_DSSALL);
7133146895Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_dss", void_ftype_int, ALTIVEC_BUILTIN_DSS);
7134132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvsl", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVSL);
7135132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvsr", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVSR);
7136132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvebx", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVEBX);
7137132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvehx", v8hi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVEHX);
7138132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvewx", v4si_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVEWX);
7139132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvxl", v4si_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVXL);
7140132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvx", v4si_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVX);
7141132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvx", void_ftype_v4si_long_pvoid, ALTIVEC_BUILTIN_STVX);
7142132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvewx", void_ftype_v4si_long_pvoid, ALTIVEC_BUILTIN_STVEWX);
7143132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvxl", void_ftype_v4si_long_pvoid, ALTIVEC_BUILTIN_STVXL);
7144132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvebx", void_ftype_v16qi_long_pvoid, ALTIVEC_BUILTIN_STVEBX);
7145132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvehx", void_ftype_v8hi_long_pvoid, ALTIVEC_BUILTIN_STVEHX);
714690075Sobrien
7147146895Skan  /* See altivec.h for usage of "__builtin_altivec_compiletime_error".  */
7148146895Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_compiletime_error", int_ftype_pcchar,
7149146895Skan	       ALTIVEC_BUILTIN_COMPILETIME_ERROR);
7150146895Skan
7151117395Skan  /* Add the DST variants.  */
7152117395Skan  d = (struct builtin_description *) bdesc_dst;
7153117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_dst); i++, d++)
7154146895Skan    def_builtin (d->mask, d->name, void_ftype_pcvoid_int_int, d->code);
7155117395Skan
7156117395Skan  /* Initialize the predicates.  */
7157117395Skan  dp = (struct builtin_description_predicates *) bdesc_altivec_preds;
7158117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_altivec_preds); i++, dp++)
7159117395Skan    {
7160117395Skan      enum machine_mode mode1;
7161117395Skan      tree type;
7162117395Skan
7163117395Skan      mode1 = insn_data[dp->icode].operand[1].mode;
7164117395Skan
7165117395Skan      switch (mode1)
7166117395Skan	{
7167117395Skan	case V4SImode:
7168117395Skan	  type = int_ftype_int_v4si_v4si;
7169117395Skan	  break;
7170117395Skan	case V8HImode:
7171117395Skan	  type = int_ftype_int_v8hi_v8hi;
7172117395Skan	  break;
7173117395Skan	case V16QImode:
7174117395Skan	  type = int_ftype_int_v16qi_v16qi;
7175117395Skan	  break;
7176117395Skan	case V4SFmode:
7177117395Skan	  type = int_ftype_int_v4sf_v4sf;
7178117395Skan	  break;
7179117395Skan	default:
7180117395Skan	  abort ();
7181117395Skan	}
7182117395Skan
7183117395Skan      def_builtin (dp->mask, dp->name, type, dp->code);
7184117395Skan    }
7185117395Skan
7186117395Skan  /* Initialize the abs* operators.  */
7187117395Skan  d = (struct builtin_description *) bdesc_abs;
7188117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_abs); i++, d++)
7189117395Skan    {
7190117395Skan      enum machine_mode mode0;
7191117395Skan      tree type;
7192117395Skan
7193117395Skan      mode0 = insn_data[d->icode].operand[0].mode;
7194117395Skan
7195117395Skan      switch (mode0)
7196117395Skan	{
7197117395Skan	case V4SImode:
7198117395Skan	  type = v4si_ftype_v4si;
7199117395Skan	  break;
7200117395Skan	case V8HImode:
7201117395Skan	  type = v8hi_ftype_v8hi;
7202117395Skan	  break;
7203117395Skan	case V16QImode:
7204117395Skan	  type = v16qi_ftype_v16qi;
7205117395Skan	  break;
7206117395Skan	case V4SFmode:
7207117395Skan	  type = v4sf_ftype_v4sf;
7208117395Skan	  break;
7209117395Skan	default:
7210117395Skan	  abort ();
7211117395Skan	}
7212117395Skan
7213117395Skan      def_builtin (d->mask, d->name, type, d->code);
7214117395Skan    }
7215117395Skan}
7216117395Skan
7217117395Skanstatic void
7218132718Skanrs6000_common_init_builtins (void)
7219117395Skan{
7220117395Skan  struct builtin_description *d;
7221117395Skan  size_t i;
7222117395Skan
7223117395Skan  tree v4sf_ftype_v4sf_v4sf_v16qi
7224117395Skan    = build_function_type_list (V4SF_type_node,
7225117395Skan				V4SF_type_node, V4SF_type_node,
7226117395Skan				V16QI_type_node, NULL_TREE);
7227117395Skan  tree v4si_ftype_v4si_v4si_v16qi
7228117395Skan    = build_function_type_list (V4SI_type_node,
7229117395Skan				V4SI_type_node, V4SI_type_node,
7230117395Skan				V16QI_type_node, NULL_TREE);
7231117395Skan  tree v8hi_ftype_v8hi_v8hi_v16qi
7232117395Skan    = build_function_type_list (V8HI_type_node,
7233117395Skan				V8HI_type_node, V8HI_type_node,
7234117395Skan				V16QI_type_node, NULL_TREE);
7235117395Skan  tree v16qi_ftype_v16qi_v16qi_v16qi
7236117395Skan    = build_function_type_list (V16QI_type_node,
7237117395Skan				V16QI_type_node, V16QI_type_node,
7238117395Skan				V16QI_type_node, NULL_TREE);
7239146895Skan  tree v4si_ftype_int
7240146895Skan    = build_function_type_list (V4SI_type_node, integer_type_node, NULL_TREE);
7241146895Skan  tree v8hi_ftype_int
7242146895Skan    = build_function_type_list (V8HI_type_node, integer_type_node, NULL_TREE);
7243146895Skan  tree v16qi_ftype_int
7244146895Skan    = build_function_type_list (V16QI_type_node, integer_type_node, NULL_TREE);
7245117395Skan  tree v8hi_ftype_v16qi
7246117395Skan    = build_function_type_list (V8HI_type_node, V16QI_type_node, NULL_TREE);
7247117395Skan  tree v4sf_ftype_v4sf
7248117395Skan    = build_function_type_list (V4SF_type_node, V4SF_type_node, NULL_TREE);
7249117395Skan
7250117395Skan  tree v2si_ftype_v2si_v2si
7251132718Skan    = build_function_type_list (opaque_V2SI_type_node,
7252132718Skan				opaque_V2SI_type_node,
7253132718Skan				opaque_V2SI_type_node, NULL_TREE);
7254117395Skan
7255117395Skan  tree v2sf_ftype_v2sf_v2sf
7256132718Skan    = build_function_type_list (opaque_V2SF_type_node,
7257132718Skan				opaque_V2SF_type_node,
7258132718Skan				opaque_V2SF_type_node, NULL_TREE);
7259117395Skan
7260117395Skan  tree v2si_ftype_int_int
7261132718Skan    = build_function_type_list (opaque_V2SI_type_node,
7262117395Skan				integer_type_node, integer_type_node,
7263117395Skan				NULL_TREE);
7264117395Skan
7265117395Skan  tree v2si_ftype_v2si
7266132718Skan    = build_function_type_list (opaque_V2SI_type_node,
7267132718Skan				opaque_V2SI_type_node, NULL_TREE);
7268117395Skan
7269117395Skan  tree v2sf_ftype_v2sf
7270132718Skan    = build_function_type_list (opaque_V2SF_type_node,
7271132718Skan				opaque_V2SF_type_node, NULL_TREE);
7272117395Skan
7273117395Skan  tree v2sf_ftype_v2si
7274132718Skan    = build_function_type_list (opaque_V2SF_type_node,
7275132718Skan				opaque_V2SI_type_node, NULL_TREE);
7276117395Skan
7277117395Skan  tree v2si_ftype_v2sf
7278132718Skan    = build_function_type_list (opaque_V2SI_type_node,
7279132718Skan				opaque_V2SF_type_node, NULL_TREE);
7280117395Skan
7281117395Skan  tree v2si_ftype_v2si_char
7282132718Skan    = build_function_type_list (opaque_V2SI_type_node,
7283132718Skan				opaque_V2SI_type_node,
7284132718Skan				char_type_node, NULL_TREE);
7285117395Skan
7286117395Skan  tree v2si_ftype_int_char
7287132718Skan    = build_function_type_list (opaque_V2SI_type_node,
7288117395Skan				integer_type_node, char_type_node, NULL_TREE);
7289117395Skan
7290117395Skan  tree v2si_ftype_char
7291132718Skan    = build_function_type_list (opaque_V2SI_type_node,
7292132718Skan				char_type_node, NULL_TREE);
7293117395Skan
7294117395Skan  tree int_ftype_int_int
7295117395Skan    = build_function_type_list (integer_type_node,
7296117395Skan				integer_type_node, integer_type_node,
7297117395Skan				NULL_TREE);
7298117395Skan
7299117395Skan  tree v4si_ftype_v4si_v4si
7300117395Skan    = build_function_type_list (V4SI_type_node,
7301117395Skan				V4SI_type_node, V4SI_type_node, NULL_TREE);
7302146895Skan  tree v4sf_ftype_v4si_int
7303117395Skan    = build_function_type_list (V4SF_type_node,
7304146895Skan				V4SI_type_node, integer_type_node, NULL_TREE);
7305146895Skan  tree v4si_ftype_v4sf_int
7306117395Skan    = build_function_type_list (V4SI_type_node,
7307146895Skan				V4SF_type_node, integer_type_node, NULL_TREE);
7308146895Skan  tree v4si_ftype_v4si_int
7309117395Skan    = build_function_type_list (V4SI_type_node,
7310146895Skan				V4SI_type_node, integer_type_node, NULL_TREE);
7311146895Skan  tree v8hi_ftype_v8hi_int
7312117395Skan    = build_function_type_list (V8HI_type_node,
7313146895Skan				V8HI_type_node, integer_type_node, NULL_TREE);
7314146895Skan  tree v16qi_ftype_v16qi_int
7315117395Skan    = build_function_type_list (V16QI_type_node,
7316146895Skan				V16QI_type_node, integer_type_node, NULL_TREE);
7317146895Skan  tree v16qi_ftype_v16qi_v16qi_int
7318117395Skan    = build_function_type_list (V16QI_type_node,
7319117395Skan				V16QI_type_node, V16QI_type_node,
7320146895Skan				integer_type_node, NULL_TREE);
7321146895Skan  tree v8hi_ftype_v8hi_v8hi_int
7322117395Skan    = build_function_type_list (V8HI_type_node,
7323117395Skan				V8HI_type_node, V8HI_type_node,
7324146895Skan				integer_type_node, NULL_TREE);
7325146895Skan  tree v4si_ftype_v4si_v4si_int
7326117395Skan    = build_function_type_list (V4SI_type_node,
7327117395Skan				V4SI_type_node, V4SI_type_node,
7328146895Skan				integer_type_node, NULL_TREE);
7329146895Skan  tree v4sf_ftype_v4sf_v4sf_int
7330117395Skan    = build_function_type_list (V4SF_type_node,
7331117395Skan				V4SF_type_node, V4SF_type_node,
7332146895Skan				integer_type_node, NULL_TREE);
733390075Sobrien  tree v4sf_ftype_v4sf_v4sf
7334117395Skan    = build_function_type_list (V4SF_type_node,
7335117395Skan				V4SF_type_node, V4SF_type_node, NULL_TREE);
733690075Sobrien  tree v4sf_ftype_v4sf_v4sf_v4si
7337117395Skan    = build_function_type_list (V4SF_type_node,
7338117395Skan				V4SF_type_node, V4SF_type_node,
7339117395Skan				V4SI_type_node, NULL_TREE);
734090075Sobrien  tree v4sf_ftype_v4sf_v4sf_v4sf
7341117395Skan    = build_function_type_list (V4SF_type_node,
7342117395Skan				V4SF_type_node, V4SF_type_node,
7343117395Skan				V4SF_type_node, NULL_TREE);
734490075Sobrien  tree v4si_ftype_v4si_v4si_v4si
7345117395Skan    = build_function_type_list (V4SI_type_node,
7346117395Skan				V4SI_type_node, V4SI_type_node,
7347117395Skan				V4SI_type_node, NULL_TREE);
734890075Sobrien  tree v8hi_ftype_v8hi_v8hi
7349117395Skan    = build_function_type_list (V8HI_type_node,
7350117395Skan				V8HI_type_node, V8HI_type_node, NULL_TREE);
735190075Sobrien  tree v8hi_ftype_v8hi_v8hi_v8hi
7352117395Skan    = build_function_type_list (V8HI_type_node,
7353117395Skan				V8HI_type_node, V8HI_type_node,
7354117395Skan				V8HI_type_node, NULL_TREE);
735590075Sobrien tree v4si_ftype_v8hi_v8hi_v4si
7356117395Skan    = build_function_type_list (V4SI_type_node,
7357117395Skan				V8HI_type_node, V8HI_type_node,
7358117395Skan				V4SI_type_node, NULL_TREE);
735990075Sobrien tree v4si_ftype_v16qi_v16qi_v4si
7360117395Skan    = build_function_type_list (V4SI_type_node,
7361117395Skan				V16QI_type_node, V16QI_type_node,
7362117395Skan				V4SI_type_node, NULL_TREE);
736390075Sobrien  tree v16qi_ftype_v16qi_v16qi
7364117395Skan    = build_function_type_list (V16QI_type_node,
7365117395Skan				V16QI_type_node, V16QI_type_node, NULL_TREE);
736690075Sobrien  tree v4si_ftype_v4sf_v4sf
7367117395Skan    = build_function_type_list (V4SI_type_node,
7368117395Skan				V4SF_type_node, V4SF_type_node, NULL_TREE);
736990075Sobrien  tree v8hi_ftype_v16qi_v16qi
7370117395Skan    = build_function_type_list (V8HI_type_node,
7371117395Skan				V16QI_type_node, V16QI_type_node, NULL_TREE);
737290075Sobrien  tree v4si_ftype_v8hi_v8hi
7373117395Skan    = build_function_type_list (V4SI_type_node,
7374117395Skan				V8HI_type_node, V8HI_type_node, NULL_TREE);
737590075Sobrien  tree v8hi_ftype_v4si_v4si
7376117395Skan    = build_function_type_list (V8HI_type_node,
7377117395Skan				V4SI_type_node, V4SI_type_node, NULL_TREE);
737890075Sobrien  tree v16qi_ftype_v8hi_v8hi
7379117395Skan    = build_function_type_list (V16QI_type_node,
7380117395Skan				V8HI_type_node, V8HI_type_node, NULL_TREE);
738190075Sobrien  tree v4si_ftype_v16qi_v4si
7382117395Skan    = build_function_type_list (V4SI_type_node,
7383117395Skan				V16QI_type_node, V4SI_type_node, NULL_TREE);
738490075Sobrien  tree v4si_ftype_v16qi_v16qi
7385117395Skan    = build_function_type_list (V4SI_type_node,
7386117395Skan				V16QI_type_node, V16QI_type_node, NULL_TREE);
738790075Sobrien  tree v4si_ftype_v8hi_v4si
7388117395Skan    = build_function_type_list (V4SI_type_node,
7389117395Skan				V8HI_type_node, V4SI_type_node, NULL_TREE);
739090075Sobrien  tree v4si_ftype_v8hi
7391117395Skan    = build_function_type_list (V4SI_type_node, V8HI_type_node, NULL_TREE);
739290075Sobrien  tree int_ftype_v4si_v4si
7393117395Skan    = build_function_type_list (integer_type_node,
7394117395Skan				V4SI_type_node, V4SI_type_node, NULL_TREE);
739590075Sobrien  tree int_ftype_v4sf_v4sf
7396117395Skan    = build_function_type_list (integer_type_node,
7397117395Skan				V4SF_type_node, V4SF_type_node, NULL_TREE);
739890075Sobrien  tree int_ftype_v16qi_v16qi
7399117395Skan    = build_function_type_list (integer_type_node,
7400117395Skan				V16QI_type_node, V16QI_type_node, NULL_TREE);
740190075Sobrien  tree int_ftype_v8hi_v8hi
7402117395Skan    = build_function_type_list (integer_type_node,
7403117395Skan				V8HI_type_node, V8HI_type_node, NULL_TREE);
740490075Sobrien
740590075Sobrien  /* Add the simple ternary operators.  */
740690075Sobrien  d = (struct builtin_description *) bdesc_3arg;
7407117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_3arg); i++, d++)
740890075Sobrien    {
740990075Sobrien
741090075Sobrien      enum machine_mode mode0, mode1, mode2, mode3;
741190075Sobrien      tree type;
741290075Sobrien
7413117395Skan      if (d->name == 0 || d->icode == CODE_FOR_nothing)
741490075Sobrien	continue;
741590075Sobrien
741690075Sobrien      mode0 = insn_data[d->icode].operand[0].mode;
741790075Sobrien      mode1 = insn_data[d->icode].operand[1].mode;
741890075Sobrien      mode2 = insn_data[d->icode].operand[2].mode;
741990075Sobrien      mode3 = insn_data[d->icode].operand[3].mode;
742090075Sobrien
742190075Sobrien      /* When all four are of the same mode.  */
742290075Sobrien      if (mode0 == mode1 && mode1 == mode2 && mode2 == mode3)
742390075Sobrien	{
742490075Sobrien	  switch (mode0)
742590075Sobrien	    {
742690075Sobrien	    case V4SImode:
742790075Sobrien	      type = v4si_ftype_v4si_v4si_v4si;
742890075Sobrien	      break;
742990075Sobrien	    case V4SFmode:
743090075Sobrien	      type = v4sf_ftype_v4sf_v4sf_v4sf;
743190075Sobrien	      break;
743290075Sobrien	    case V8HImode:
743390075Sobrien	      type = v8hi_ftype_v8hi_v8hi_v8hi;
743490075Sobrien	      break;
743590075Sobrien	    case V16QImode:
743690075Sobrien	      type = v16qi_ftype_v16qi_v16qi_v16qi;
743790075Sobrien	      break;
743890075Sobrien	    default:
743990075Sobrien	      abort();
744090075Sobrien	    }
744190075Sobrien	}
744290075Sobrien      else if (mode0 == mode1 && mode1 == mode2 && mode3 == V16QImode)
744390075Sobrien        {
744490075Sobrien	  switch (mode0)
744590075Sobrien	    {
744690075Sobrien	    case V4SImode:
744790075Sobrien	      type = v4si_ftype_v4si_v4si_v16qi;
744890075Sobrien	      break;
744990075Sobrien	    case V4SFmode:
745090075Sobrien	      type = v4sf_ftype_v4sf_v4sf_v16qi;
745190075Sobrien	      break;
745290075Sobrien	    case V8HImode:
745390075Sobrien	      type = v8hi_ftype_v8hi_v8hi_v16qi;
745490075Sobrien	      break;
745590075Sobrien	    case V16QImode:
745690075Sobrien	      type = v16qi_ftype_v16qi_v16qi_v16qi;
745790075Sobrien	      break;
745890075Sobrien	    default:
745990075Sobrien	      abort();
746090075Sobrien	    }
746190075Sobrien	}
746290075Sobrien      else if (mode0 == V4SImode && mode1 == V16QImode && mode2 == V16QImode
746390075Sobrien	       && mode3 == V4SImode)
746490075Sobrien	type = v4si_ftype_v16qi_v16qi_v4si;
746590075Sobrien      else if (mode0 == V4SImode && mode1 == V8HImode && mode2 == V8HImode
746690075Sobrien	       && mode3 == V4SImode)
746790075Sobrien	type = v4si_ftype_v8hi_v8hi_v4si;
746890075Sobrien      else if (mode0 == V4SFmode && mode1 == V4SFmode && mode2 == V4SFmode
746990075Sobrien	       && mode3 == V4SImode)
747090075Sobrien	type = v4sf_ftype_v4sf_v4sf_v4si;
747190075Sobrien
747290075Sobrien      /* vchar, vchar, vchar, 4 bit literal.  */
747390075Sobrien      else if (mode0 == V16QImode && mode1 == mode0 && mode2 == mode0
747490075Sobrien	       && mode3 == QImode)
7475146895Skan	type = v16qi_ftype_v16qi_v16qi_int;
747690075Sobrien
747790075Sobrien      /* vshort, vshort, vshort, 4 bit literal.  */
747890075Sobrien      else if (mode0 == V8HImode && mode1 == mode0 && mode2 == mode0
747990075Sobrien	       && mode3 == QImode)
7480146895Skan	type = v8hi_ftype_v8hi_v8hi_int;
748190075Sobrien
748290075Sobrien      /* vint, vint, vint, 4 bit literal.  */
748390075Sobrien      else if (mode0 == V4SImode && mode1 == mode0 && mode2 == mode0
748490075Sobrien	       && mode3 == QImode)
7485146895Skan	type = v4si_ftype_v4si_v4si_int;
748690075Sobrien
748790075Sobrien      /* vfloat, vfloat, vfloat, 4 bit literal.  */
748890075Sobrien      else if (mode0 == V4SFmode && mode1 == mode0 && mode2 == mode0
748990075Sobrien	       && mode3 == QImode)
7490146895Skan	type = v4sf_ftype_v4sf_v4sf_int;
749190075Sobrien
749290075Sobrien      else
749390075Sobrien	abort ();
749490075Sobrien
749590075Sobrien      def_builtin (d->mask, d->name, type, d->code);
749690075Sobrien    }
749790075Sobrien
749890075Sobrien  /* Add the simple binary operators.  */
749990075Sobrien  d = (struct builtin_description *) bdesc_2arg;
7500117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
750190075Sobrien    {
750290075Sobrien      enum machine_mode mode0, mode1, mode2;
750390075Sobrien      tree type;
750490075Sobrien
7505117395Skan      if (d->name == 0 || d->icode == CODE_FOR_nothing)
750690075Sobrien	continue;
750790075Sobrien
750890075Sobrien      mode0 = insn_data[d->icode].operand[0].mode;
750990075Sobrien      mode1 = insn_data[d->icode].operand[1].mode;
751090075Sobrien      mode2 = insn_data[d->icode].operand[2].mode;
751190075Sobrien
751290075Sobrien      /* When all three operands are of the same mode.  */
751390075Sobrien      if (mode0 == mode1 && mode1 == mode2)
751490075Sobrien	{
751590075Sobrien	  switch (mode0)
751690075Sobrien	    {
751790075Sobrien	    case V4SFmode:
751890075Sobrien	      type = v4sf_ftype_v4sf_v4sf;
751990075Sobrien	      break;
752090075Sobrien	    case V4SImode:
752190075Sobrien	      type = v4si_ftype_v4si_v4si;
752290075Sobrien	      break;
752390075Sobrien	    case V16QImode:
752490075Sobrien	      type = v16qi_ftype_v16qi_v16qi;
752590075Sobrien	      break;
752690075Sobrien	    case V8HImode:
752790075Sobrien	      type = v8hi_ftype_v8hi_v8hi;
752890075Sobrien	      break;
7529117395Skan	    case V2SImode:
7530117395Skan	      type = v2si_ftype_v2si_v2si;
7531117395Skan	      break;
7532117395Skan	    case V2SFmode:
7533117395Skan	      type = v2sf_ftype_v2sf_v2sf;
7534117395Skan	      break;
7535117395Skan	    case SImode:
7536117395Skan	      type = int_ftype_int_int;
7537117395Skan	      break;
753890075Sobrien	    default:
753990075Sobrien	      abort ();
754090075Sobrien	    }
754190075Sobrien	}
754290075Sobrien
754390075Sobrien      /* A few other combos we really don't want to do manually.  */
754490075Sobrien
754590075Sobrien      /* vint, vfloat, vfloat.  */
754690075Sobrien      else if (mode0 == V4SImode && mode1 == V4SFmode && mode2 == V4SFmode)
754790075Sobrien	type = v4si_ftype_v4sf_v4sf;
754890075Sobrien
754990075Sobrien      /* vshort, vchar, vchar.  */
755090075Sobrien      else if (mode0 == V8HImode && mode1 == V16QImode && mode2 == V16QImode)
755190075Sobrien	type = v8hi_ftype_v16qi_v16qi;
755290075Sobrien
755390075Sobrien      /* vint, vshort, vshort.  */
755490075Sobrien      else if (mode0 == V4SImode && mode1 == V8HImode && mode2 == V8HImode)
755590075Sobrien	type = v4si_ftype_v8hi_v8hi;
755690075Sobrien
755790075Sobrien      /* vshort, vint, vint.  */
755890075Sobrien      else if (mode0 == V8HImode && mode1 == V4SImode && mode2 == V4SImode)
755990075Sobrien	type = v8hi_ftype_v4si_v4si;
756090075Sobrien
756190075Sobrien      /* vchar, vshort, vshort.  */
756290075Sobrien      else if (mode0 == V16QImode && mode1 == V8HImode && mode2 == V8HImode)
756390075Sobrien	type = v16qi_ftype_v8hi_v8hi;
756490075Sobrien
756590075Sobrien      /* vint, vchar, vint.  */
756690075Sobrien      else if (mode0 == V4SImode && mode1 == V16QImode && mode2 == V4SImode)
756790075Sobrien	type = v4si_ftype_v16qi_v4si;
756890075Sobrien
756990075Sobrien      /* vint, vchar, vchar.  */
757090075Sobrien      else if (mode0 == V4SImode && mode1 == V16QImode && mode2 == V16QImode)
757190075Sobrien	type = v4si_ftype_v16qi_v16qi;
757290075Sobrien
757390075Sobrien      /* vint, vshort, vint.  */
757490075Sobrien      else if (mode0 == V4SImode && mode1 == V8HImode && mode2 == V4SImode)
757590075Sobrien	type = v4si_ftype_v8hi_v4si;
757690075Sobrien
757790075Sobrien      /* vint, vint, 5 bit literal.  */
757890075Sobrien      else if (mode0 == V4SImode && mode1 == V4SImode && mode2 == QImode)
7579146895Skan	type = v4si_ftype_v4si_int;
758090075Sobrien
758190075Sobrien      /* vshort, vshort, 5 bit literal.  */
758290075Sobrien      else if (mode0 == V8HImode && mode1 == V8HImode && mode2 == QImode)
7583146895Skan	type = v8hi_ftype_v8hi_int;
758490075Sobrien
758590075Sobrien      /* vchar, vchar, 5 bit literal.  */
758690075Sobrien      else if (mode0 == V16QImode && mode1 == V16QImode && mode2 == QImode)
7587146895Skan	type = v16qi_ftype_v16qi_int;
758890075Sobrien
758990075Sobrien      /* vfloat, vint, 5 bit literal.  */
759090075Sobrien      else if (mode0 == V4SFmode && mode1 == V4SImode && mode2 == QImode)
7591146895Skan	type = v4sf_ftype_v4si_int;
759290075Sobrien
759390075Sobrien      /* vint, vfloat, 5 bit literal.  */
759490075Sobrien      else if (mode0 == V4SImode && mode1 == V4SFmode && mode2 == QImode)
7595146895Skan	type = v4si_ftype_v4sf_int;
759690075Sobrien
7597117395Skan      else if (mode0 == V2SImode && mode1 == SImode && mode2 == SImode)
7598117395Skan	type = v2si_ftype_int_int;
7599117395Skan
7600117395Skan      else if (mode0 == V2SImode && mode1 == V2SImode && mode2 == QImode)
7601117395Skan	type = v2si_ftype_v2si_char;
7602117395Skan
7603117395Skan      else if (mode0 == V2SImode && mode1 == SImode && mode2 == QImode)
7604117395Skan	type = v2si_ftype_int_char;
7605117395Skan
760690075Sobrien      /* int, x, x.  */
760790075Sobrien      else if (mode0 == SImode)
760890075Sobrien	{
760990075Sobrien	  switch (mode1)
761090075Sobrien	    {
761190075Sobrien	    case V4SImode:
761290075Sobrien	      type = int_ftype_v4si_v4si;
761390075Sobrien	      break;
761490075Sobrien	    case V4SFmode:
761590075Sobrien	      type = int_ftype_v4sf_v4sf;
761690075Sobrien	      break;
761790075Sobrien	    case V16QImode:
761890075Sobrien	      type = int_ftype_v16qi_v16qi;
761990075Sobrien	      break;
762090075Sobrien	    case V8HImode:
762190075Sobrien	      type = int_ftype_v8hi_v8hi;
762290075Sobrien	      break;
762390075Sobrien	    default:
762490075Sobrien	      abort ();
762590075Sobrien	    }
762690075Sobrien	}
762790075Sobrien
762890075Sobrien      else
762990075Sobrien	abort ();
763090075Sobrien
763190075Sobrien      def_builtin (d->mask, d->name, type, d->code);
763290075Sobrien    }
763390075Sobrien
763490075Sobrien  /* Add the simple unary operators.  */
763590075Sobrien  d = (struct builtin_description *) bdesc_1arg;
7636117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
763790075Sobrien    {
763890075Sobrien      enum machine_mode mode0, mode1;
763990075Sobrien      tree type;
764090075Sobrien
7641117395Skan      if (d->name == 0 || d->icode == CODE_FOR_nothing)
764290075Sobrien	continue;
764390075Sobrien
764490075Sobrien      mode0 = insn_data[d->icode].operand[0].mode;
764590075Sobrien      mode1 = insn_data[d->icode].operand[1].mode;
764690075Sobrien
764790075Sobrien      if (mode0 == V4SImode && mode1 == QImode)
7648146895Skan        type = v4si_ftype_int;
764990075Sobrien      else if (mode0 == V8HImode && mode1 == QImode)
7650146895Skan        type = v8hi_ftype_int;
765190075Sobrien      else if (mode0 == V16QImode && mode1 == QImode)
7652146895Skan        type = v16qi_ftype_int;
765390075Sobrien      else if (mode0 == V4SFmode && mode1 == V4SFmode)
765490075Sobrien	type = v4sf_ftype_v4sf;
765590075Sobrien      else if (mode0 == V8HImode && mode1 == V16QImode)
765690075Sobrien	type = v8hi_ftype_v16qi;
765790075Sobrien      else if (mode0 == V4SImode && mode1 == V8HImode)
765890075Sobrien	type = v4si_ftype_v8hi;
7659117395Skan      else if (mode0 == V2SImode && mode1 == V2SImode)
7660117395Skan	type = v2si_ftype_v2si;
7661117395Skan      else if (mode0 == V2SFmode && mode1 == V2SFmode)
7662117395Skan	type = v2sf_ftype_v2sf;
7663117395Skan      else if (mode0 == V2SFmode && mode1 == V2SImode)
7664117395Skan	type = v2sf_ftype_v2si;
7665117395Skan      else if (mode0 == V2SImode && mode1 == V2SFmode)
7666117395Skan	type = v2si_ftype_v2sf;
7667117395Skan      else if (mode0 == V2SImode && mode1 == QImode)
7668117395Skan	type = v2si_ftype_char;
766990075Sobrien      else
767090075Sobrien	abort ();
767190075Sobrien
767290075Sobrien      def_builtin (d->mask, d->name, type, d->code);
767390075Sobrien    }
767490075Sobrien}
767590075Sobrien
7676132718Skanstatic void
7677132718Skanrs6000_init_libfuncs (void)
7678132718Skan{
7679132718Skan  if (!TARGET_HARD_FLOAT)
7680132718Skan    return;
7681132718Skan
7682132718Skan  if (DEFAULT_ABI != ABI_V4)
7683132718Skan    {
7684132718Skan      if (TARGET_XCOFF && ! TARGET_POWER2 && ! TARGET_POWERPC)
7685132718Skan	{
7686132718Skan	  /* AIX library routines for float->int conversion.  */
7687132718Skan	  set_conv_libfunc (sfix_optab, SImode, DFmode, "__itrunc");
7688132718Skan	  set_conv_libfunc (ufix_optab, SImode, DFmode, "__uitrunc");
7689132718Skan	  set_conv_libfunc (sfix_optab, SImode, TFmode, "_qitrunc");
7690132718Skan	  set_conv_libfunc (ufix_optab, SImode, TFmode, "_quitrunc");
7691132718Skan	}
7692132718Skan
7693146895Skan      /* AIX/Darwin/64-bit Linux quad floating point routines.  */
7694146895Skan      if (!TARGET_XL_COMPAT)
7695146895Skan	{
7696146895Skan	  set_optab_libfunc (add_optab, TFmode, "__gcc_qadd");
7697146895Skan	  set_optab_libfunc (sub_optab, TFmode, "__gcc_qsub");
7698146895Skan	  set_optab_libfunc (smul_optab, TFmode, "__gcc_qmul");
7699146895Skan	  set_optab_libfunc (sdiv_optab, TFmode, "__gcc_qdiv");
7700146895Skan	}
7701146895Skan      else
7702146895Skan	{
7703146895Skan	  set_optab_libfunc (add_optab, TFmode, "_xlqadd");
7704146895Skan	  set_optab_libfunc (sub_optab, TFmode, "_xlqsub");
7705146895Skan	  set_optab_libfunc (smul_optab, TFmode, "_xlqmul");
7706146895Skan	  set_optab_libfunc (sdiv_optab, TFmode, "_xlqdiv");
7707146895Skan	}
7708132718Skan    }
7709132718Skan  else
7710132718Skan    {
7711132718Skan      /* 32-bit SVR4 quad floating point routines.  */
7712132718Skan
7713132718Skan      set_optab_libfunc (add_optab, TFmode, "_q_add");
7714132718Skan      set_optab_libfunc (sub_optab, TFmode, "_q_sub");
7715132718Skan      set_optab_libfunc (neg_optab, TFmode, "_q_neg");
7716132718Skan      set_optab_libfunc (smul_optab, TFmode, "_q_mul");
7717132718Skan      set_optab_libfunc (sdiv_optab, TFmode, "_q_div");
7718132718Skan      if (TARGET_PPC_GPOPT || TARGET_POWER2)
7719132718Skan	set_optab_libfunc (sqrt_optab, TFmode, "_q_sqrt");
7720132718Skan
7721132718Skan      set_optab_libfunc (eq_optab, TFmode, "_q_feq");
7722132718Skan      set_optab_libfunc (ne_optab, TFmode, "_q_fne");
7723132718Skan      set_optab_libfunc (gt_optab, TFmode, "_q_fgt");
7724132718Skan      set_optab_libfunc (ge_optab, TFmode, "_q_fge");
7725132718Skan      set_optab_libfunc (lt_optab, TFmode, "_q_flt");
7726132718Skan      set_optab_libfunc (le_optab, TFmode, "_q_fle");
7727132718Skan
7728132718Skan      set_conv_libfunc (sext_optab, TFmode, SFmode, "_q_stoq");
7729132718Skan      set_conv_libfunc (sext_optab, TFmode, DFmode, "_q_dtoq");
7730132718Skan      set_conv_libfunc (trunc_optab, SFmode, TFmode, "_q_qtos");
7731132718Skan      set_conv_libfunc (trunc_optab, DFmode, TFmode, "_q_qtod");
7732132718Skan      set_conv_libfunc (sfix_optab, SImode, TFmode, "_q_qtoi");
7733132718Skan      set_conv_libfunc (ufix_optab, SImode, TFmode, "_q_qtou");
7734132718Skan      set_conv_libfunc (sfloat_optab, TFmode, SImode, "_q_itoq");
7735132718Skan    }
7736132718Skan}
773790075Sobrien
773890075Sobrien/* Expand a block move operation, and return 1 if successful.  Return 0
773990075Sobrien   if we should let the compiler generate normal code.
774090075Sobrien
774190075Sobrien   operands[0] is the destination
774290075Sobrien   operands[1] is the source
774390075Sobrien   operands[2] is the length
774490075Sobrien   operands[3] is the alignment */
774590075Sobrien
774690075Sobrien#define MAX_MOVE_REG 4
774790075Sobrien
774890075Sobrienint
7749132718Skanexpand_block_move (rtx operands[])
775090075Sobrien{
775190075Sobrien  rtx orig_dest = operands[0];
775290075Sobrien  rtx orig_src	= operands[1];
775390075Sobrien  rtx bytes_rtx	= operands[2];
775490075Sobrien  rtx align_rtx = operands[3];
775590075Sobrien  int constp	= (GET_CODE (bytes_rtx) == CONST_INT);
775690075Sobrien  int align;
775790075Sobrien  int bytes;
775890075Sobrien  int offset;
775990075Sobrien  int move_bytes;
7760132718Skan  rtx stores[MAX_MOVE_REG];
7761132718Skan  int num_reg = 0;
776290075Sobrien
776390075Sobrien  /* If this is not a fixed size move, just call memcpy */
776490075Sobrien  if (! constp)
776590075Sobrien    return 0;
776690075Sobrien
776790075Sobrien  /* If this is not a fixed size alignment, abort */
776890075Sobrien  if (GET_CODE (align_rtx) != CONST_INT)
776990075Sobrien    abort ();
777090075Sobrien  align = INTVAL (align_rtx);
777190075Sobrien
777290075Sobrien  /* Anything to move? */
777390075Sobrien  bytes = INTVAL (bytes_rtx);
777490075Sobrien  if (bytes <= 0)
777590075Sobrien    return 1;
777690075Sobrien
777790075Sobrien  /* store_one_arg depends on expand_block_move to handle at least the size of
777890075Sobrien     reg_parm_stack_space.  */
777990075Sobrien  if (bytes > (TARGET_POWERPC64 ? 64 : 32))
778090075Sobrien    return 0;
778190075Sobrien
7782132718Skan  for (offset = 0; bytes > 0; offset += move_bytes, bytes -= move_bytes)
778390075Sobrien    {
7784132718Skan      union {
7785132718Skan	rtx (*movstrsi) (rtx, rtx, rtx, rtx);
7786132718Skan	rtx (*mov) (rtx, rtx);
7787132718Skan      } gen_func;
7788132718Skan      enum machine_mode mode = BLKmode;
7789132718Skan      rtx src, dest;
7790132718Skan
7791132718Skan      if (TARGET_STRING
7792132718Skan	  && bytes > 24		/* move up to 32 bytes at a time */
7793132718Skan	  && ! fixed_regs[5]
7794132718Skan	  && ! fixed_regs[6]
7795132718Skan	  && ! fixed_regs[7]
7796132718Skan	  && ! fixed_regs[8]
7797132718Skan	  && ! fixed_regs[9]
7798132718Skan	  && ! fixed_regs[10]
7799132718Skan	  && ! fixed_regs[11]
7800132718Skan	  && ! fixed_regs[12])
780190075Sobrien	{
7802132718Skan	  move_bytes = (bytes > 32) ? 32 : bytes;
7803132718Skan	  gen_func.movstrsi = gen_movstrsi_8reg;
7804132718Skan	}
7805132718Skan      else if (TARGET_STRING
7806132718Skan	       && bytes > 16	/* move up to 24 bytes at a time */
7807132718Skan	       && ! fixed_regs[5]
7808132718Skan	       && ! fixed_regs[6]
7809132718Skan	       && ! fixed_regs[7]
7810132718Skan	       && ! fixed_regs[8]
7811132718Skan	       && ! fixed_regs[9]
7812132718Skan	       && ! fixed_regs[10])
7813132718Skan	{
7814132718Skan	  move_bytes = (bytes > 24) ? 24 : bytes;
7815132718Skan	  gen_func.movstrsi = gen_movstrsi_6reg;
7816132718Skan	}
7817132718Skan      else if (TARGET_STRING
7818132718Skan	       && bytes > 8	/* move up to 16 bytes at a time */
7819132718Skan	       && ! fixed_regs[5]
7820132718Skan	       && ! fixed_regs[6]
7821132718Skan	       && ! fixed_regs[7]
7822132718Skan	       && ! fixed_regs[8])
7823132718Skan	{
7824132718Skan	  move_bytes = (bytes > 16) ? 16 : bytes;
7825132718Skan	  gen_func.movstrsi = gen_movstrsi_4reg;
7826132718Skan	}
7827132718Skan      else if (bytes >= 8 && TARGET_POWERPC64
7828132718Skan	       /* 64-bit loads and stores require word-aligned
7829132718Skan		  displacements.  */
7830132718Skan	       && (align >= 8 || (! STRICT_ALIGNMENT && align >= 4)))
7831132718Skan	{
7832132718Skan	  move_bytes = 8;
7833132718Skan	  mode = DImode;
7834132718Skan	  gen_func.mov = gen_movdi;
7835132718Skan	}
7836132718Skan      else if (TARGET_STRING && bytes > 4 && !TARGET_POWERPC64)
7837132718Skan	{			/* move up to 8 bytes at a time */
7838132718Skan	  move_bytes = (bytes > 8) ? 8 : bytes;
7839132718Skan	  gen_func.movstrsi = gen_movstrsi_2reg;
7840132718Skan	}
7841132718Skan      else if (bytes >= 4 && (align >= 4 || ! STRICT_ALIGNMENT))
7842132718Skan	{			/* move 4 bytes */
7843132718Skan	  move_bytes = 4;
7844132718Skan	  mode = SImode;
7845132718Skan	  gen_func.mov = gen_movsi;
7846132718Skan	}
7847161651Skan      else if (bytes >= 2 && (align >= 2 || ! STRICT_ALIGNMENT))
7848132718Skan	{			/* move 2 bytes */
7849132718Skan	  move_bytes = 2;
7850132718Skan	  mode = HImode;
7851132718Skan	  gen_func.mov = gen_movhi;
7852132718Skan	}
7853132718Skan      else if (TARGET_STRING && bytes > 1)
7854132718Skan	{			/* move up to 4 bytes at a time */
7855132718Skan	  move_bytes = (bytes > 4) ? 4 : bytes;
7856132718Skan	  gen_func.movstrsi = gen_movstrsi_1reg;
7857132718Skan	}
7858132718Skan      else /* move 1 byte at a time */
7859132718Skan	{
7860132718Skan	  move_bytes = 1;
7861132718Skan	  mode = QImode;
7862132718Skan	  gen_func.mov = gen_movqi;
7863132718Skan	}
7864132718Skan
7865132718Skan      src = adjust_address (orig_src, mode, offset);
7866132718Skan      dest = adjust_address (orig_dest, mode, offset);
7867132718Skan
7868132718Skan      if (mode != BLKmode)
7869132718Skan	{
7870132718Skan	  rtx tmp_reg = gen_reg_rtx (mode);
7871132718Skan
7872132718Skan	  emit_insn ((*gen_func.mov) (tmp_reg, src));
7873132718Skan	  stores[num_reg++] = (*gen_func.mov) (dest, tmp_reg);
7874132718Skan	}
7875103445Skan
7876132718Skan      if (mode == BLKmode || num_reg >= MAX_MOVE_REG || bytes == move_bytes)
7877132718Skan	{
7878132718Skan	  int i;
7879132718Skan	  for (i = 0; i < num_reg; i++)
7880132718Skan	    emit_insn (stores[i]);
7881132718Skan	  num_reg = 0;
788290075Sobrien	}
788390075Sobrien
7884132718Skan      if (mode == BLKmode)
788590075Sobrien	{
7886132718Skan	  /* Move the address into scratch registers.  The movstrsi
7887132718Skan	     patterns require zero offset.  */
7888132718Skan	  if (!REG_P (XEXP (src, 0)))
788990075Sobrien	    {
7890132718Skan	      rtx src_reg = copy_addr_to_reg (XEXP (src, 0));
7891132718Skan	      src = replace_equiv_address (src, src_reg);
789290075Sobrien	    }
7893132718Skan	  set_mem_size (src, GEN_INT (move_bytes));
7894132718Skan
7895132718Skan	  if (!REG_P (XEXP (dest, 0)))
789690075Sobrien	    {
7897132718Skan	      rtx dest_reg = copy_addr_to_reg (XEXP (dest, 0));
7898132718Skan	      dest = replace_equiv_address (dest, dest_reg);
789990075Sobrien	    }
7900132718Skan	  set_mem_size (dest, GEN_INT (move_bytes));
7901132718Skan
7902132718Skan	  emit_insn ((*gen_func.movstrsi) (dest, src,
7903132718Skan					   GEN_INT (move_bytes & 31),
7904132718Skan					   align_rtx));
790590075Sobrien	}
790690075Sobrien    }
790790075Sobrien
790890075Sobrien  return 1;
790990075Sobrien}
791090075Sobrien
791190075Sobrien
791290075Sobrien/* Return 1 if OP is a load multiple operation.  It is known to be a
791390075Sobrien   PARALLEL and the first section will be tested.  */
791490075Sobrien
791590075Sobrienint
7916132718Skanload_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
791790075Sobrien{
791890075Sobrien  int count = XVECLEN (op, 0);
791990075Sobrien  unsigned int dest_regno;
792090075Sobrien  rtx src_addr;
792190075Sobrien  int i;
792290075Sobrien
792390075Sobrien  /* Perform a quick check so we don't blow up below.  */
792490075Sobrien  if (count <= 1
792590075Sobrien      || GET_CODE (XVECEXP (op, 0, 0)) != SET
792690075Sobrien      || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != REG
792790075Sobrien      || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != MEM)
792890075Sobrien    return 0;
792990075Sobrien
793090075Sobrien  dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, 0)));
793190075Sobrien  src_addr = XEXP (SET_SRC (XVECEXP (op, 0, 0)), 0);
793290075Sobrien
793390075Sobrien  for (i = 1; i < count; i++)
793490075Sobrien    {
793590075Sobrien      rtx elt = XVECEXP (op, 0, i);
793690075Sobrien
793790075Sobrien      if (GET_CODE (elt) != SET
793890075Sobrien	  || GET_CODE (SET_DEST (elt)) != REG
793990075Sobrien	  || GET_MODE (SET_DEST (elt)) != SImode
794090075Sobrien	  || REGNO (SET_DEST (elt)) != dest_regno + i
794190075Sobrien	  || GET_CODE (SET_SRC (elt)) != MEM
794290075Sobrien	  || GET_MODE (SET_SRC (elt)) != SImode
794390075Sobrien	  || GET_CODE (XEXP (SET_SRC (elt), 0)) != PLUS
794490075Sobrien	  || ! rtx_equal_p (XEXP (XEXP (SET_SRC (elt), 0), 0), src_addr)
794590075Sobrien	  || GET_CODE (XEXP (XEXP (SET_SRC (elt), 0), 1)) != CONST_INT
794690075Sobrien	  || INTVAL (XEXP (XEXP (SET_SRC (elt), 0), 1)) != i * 4)
794790075Sobrien	return 0;
794890075Sobrien    }
794990075Sobrien
795090075Sobrien  return 1;
795190075Sobrien}
795290075Sobrien
795390075Sobrien/* Similar, but tests for store multiple.  Here, the second vector element
795490075Sobrien   is a CLOBBER.  It will be tested later.  */
795590075Sobrien
795690075Sobrienint
7957132718Skanstore_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
795890075Sobrien{
795990075Sobrien  int count = XVECLEN (op, 0) - 1;
796090075Sobrien  unsigned int src_regno;
796190075Sobrien  rtx dest_addr;
796290075Sobrien  int i;
796390075Sobrien
796490075Sobrien  /* Perform a quick check so we don't blow up below.  */
796590075Sobrien  if (count <= 1
796690075Sobrien      || GET_CODE (XVECEXP (op, 0, 0)) != SET
796790075Sobrien      || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != MEM
796890075Sobrien      || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != REG)
796990075Sobrien    return 0;
797090075Sobrien
797190075Sobrien  src_regno = REGNO (SET_SRC (XVECEXP (op, 0, 0)));
797290075Sobrien  dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, 0)), 0);
797390075Sobrien
797490075Sobrien  for (i = 1; i < count; i++)
797590075Sobrien    {
797690075Sobrien      rtx elt = XVECEXP (op, 0, i + 1);
797790075Sobrien
797890075Sobrien      if (GET_CODE (elt) != SET
797990075Sobrien	  || GET_CODE (SET_SRC (elt)) != REG
798090075Sobrien	  || GET_MODE (SET_SRC (elt)) != SImode
798190075Sobrien	  || REGNO (SET_SRC (elt)) != src_regno + i
798290075Sobrien	  || GET_CODE (SET_DEST (elt)) != MEM
798390075Sobrien	  || GET_MODE (SET_DEST (elt)) != SImode
798490075Sobrien	  || GET_CODE (XEXP (SET_DEST (elt), 0)) != PLUS
798590075Sobrien	  || ! rtx_equal_p (XEXP (XEXP (SET_DEST (elt), 0), 0), dest_addr)
798690075Sobrien	  || GET_CODE (XEXP (XEXP (SET_DEST (elt), 0), 1)) != CONST_INT
798790075Sobrien	  || INTVAL (XEXP (XEXP (SET_DEST (elt), 0), 1)) != i * 4)
798890075Sobrien	return 0;
798990075Sobrien    }
799090075Sobrien
799190075Sobrien  return 1;
799290075Sobrien}
799390075Sobrien
7994110611Skan/* Return a string to perform a load_multiple operation.
7995110611Skan   operands[0] is the vector.
7996110611Skan   operands[1] is the source address.
7997110611Skan   operands[2] is the first destination register.  */
7998110611Skan
7999110611Skanconst char *
8000132718Skanrs6000_output_load_multiple (rtx operands[3])
8001110611Skan{
8002110611Skan  /* We have to handle the case where the pseudo used to contain the address
8003110611Skan     is assigned to one of the output registers.  */
8004110611Skan  int i, j;
8005110611Skan  int words = XVECLEN (operands[0], 0);
8006110611Skan  rtx xop[10];
8007110611Skan
8008110611Skan  if (XVECLEN (operands[0], 0) == 1)
8009110611Skan    return "{l|lwz} %2,0(%1)";
8010110611Skan
8011110611Skan  for (i = 0; i < words; i++)
8012110611Skan    if (refers_to_regno_p (REGNO (operands[2]) + i,
8013110611Skan			   REGNO (operands[2]) + i + 1, operands[1], 0))
8014110611Skan      {
8015110611Skan	if (i == words-1)
8016110611Skan	  {
8017110611Skan	    xop[0] = GEN_INT (4 * (words-1));
8018110611Skan	    xop[1] = operands[1];
8019110611Skan	    xop[2] = operands[2];
8020110611Skan	    output_asm_insn ("{lsi|lswi} %2,%1,%0\n\t{l|lwz} %1,%0(%1)", xop);
8021110611Skan	    return "";
8022110611Skan	  }
8023110611Skan	else if (i == 0)
8024110611Skan	  {
8025110611Skan	    xop[0] = GEN_INT (4 * (words-1));
8026110611Skan	    xop[1] = operands[1];
8027110611Skan	    xop[2] = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
8028110611Skan	    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);
8029110611Skan	    return "";
8030110611Skan	  }
8031110611Skan	else
8032110611Skan	  {
8033110611Skan	    for (j = 0; j < words; j++)
8034110611Skan	      if (j != i)
8035110611Skan		{
8036110611Skan		  xop[0] = GEN_INT (j * 4);
8037110611Skan		  xop[1] = operands[1];
8038110611Skan		  xop[2] = gen_rtx_REG (SImode, REGNO (operands[2]) + j);
8039110611Skan		  output_asm_insn ("{l|lwz} %2,%0(%1)", xop);
8040110611Skan		}
8041110611Skan	    xop[0] = GEN_INT (i * 4);
8042110611Skan	    xop[1] = operands[1];
8043110611Skan	    output_asm_insn ("{l|lwz} %1,%0(%1)", xop);
8044110611Skan	    return "";
8045110611Skan	  }
8046110611Skan      }
8047110611Skan
8048110611Skan  return "{lsi|lswi} %2,%1,%N0";
8049110611Skan}
8050110611Skan
805190075Sobrien/* Return 1 for a parallel vrsave operation.  */
805290075Sobrien
805390075Sobrienint
8054132718Skanvrsave_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
805590075Sobrien{
805690075Sobrien  int count = XVECLEN (op, 0);
805790075Sobrien  unsigned int dest_regno, src_regno;
805890075Sobrien  int i;
805990075Sobrien
806090075Sobrien  if (count <= 1
806190075Sobrien      || GET_CODE (XVECEXP (op, 0, 0)) != SET
806290075Sobrien      || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != REG
806390075Sobrien      || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != UNSPEC_VOLATILE)
806490075Sobrien    return 0;
806590075Sobrien
806690075Sobrien  dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, 0)));
806790075Sobrien  src_regno  = REGNO (SET_SRC (XVECEXP (op, 0, 0)));
806890075Sobrien
806990075Sobrien  if (dest_regno != VRSAVE_REGNO
807090075Sobrien      && src_regno != VRSAVE_REGNO)
807190075Sobrien    return 0;
807290075Sobrien
807390075Sobrien  for (i = 1; i < count; i++)
807490075Sobrien    {
807590075Sobrien      rtx elt = XVECEXP (op, 0, i);
807690075Sobrien
807790075Sobrien      if (GET_CODE (elt) != CLOBBER
807890075Sobrien	  && GET_CODE (elt) != SET)
807990075Sobrien	return 0;
808090075Sobrien    }
808190075Sobrien
808290075Sobrien  return 1;
808390075Sobrien}
808490075Sobrien
8085132718Skan/* Return 1 for an PARALLEL suitable for mfcr.  */
8086132718Skan
8087132718Skanint
8088132718Skanmfcr_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
8089132718Skan{
8090132718Skan  int count = XVECLEN (op, 0);
8091132718Skan  int i;
8092132718Skan
8093132718Skan  /* Perform a quick check so we don't blow up below.  */
8094132718Skan  if (count < 1
8095132718Skan      || GET_CODE (XVECEXP (op, 0, 0)) != SET
8096132718Skan      || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != UNSPEC
8097132718Skan      || XVECLEN (SET_SRC (XVECEXP (op, 0, 0)), 0) != 2)
8098132718Skan    return 0;
8099132718Skan
8100132718Skan  for (i = 0; i < count; i++)
8101132718Skan    {
8102132718Skan      rtx exp = XVECEXP (op, 0, i);
8103132718Skan      rtx unspec;
8104132718Skan      int maskval;
8105132718Skan      rtx src_reg;
8106132718Skan
8107132718Skan      src_reg = XVECEXP (SET_SRC (exp), 0, 0);
8108132718Skan
8109132718Skan      if (GET_CODE (src_reg) != REG
8110132718Skan	  || GET_MODE (src_reg) != CCmode
8111132718Skan	  || ! CR_REGNO_P (REGNO (src_reg)))
8112132718Skan	return 0;
8113132718Skan
8114132718Skan      if (GET_CODE (exp) != SET
8115132718Skan	  || GET_CODE (SET_DEST (exp)) != REG
8116132718Skan	  || GET_MODE (SET_DEST (exp)) != SImode
8117132718Skan	  || ! INT_REGNO_P (REGNO (SET_DEST (exp))))
8118132718Skan	return 0;
8119132718Skan      unspec = SET_SRC (exp);
8120132718Skan      maskval = 1 << (MAX_CR_REGNO - REGNO (src_reg));
8121132718Skan
8122132718Skan      if (GET_CODE (unspec) != UNSPEC
8123132718Skan	  || XINT (unspec, 1) != UNSPEC_MOVESI_FROM_CR
8124132718Skan	  || XVECLEN (unspec, 0) != 2
8125132718Skan	  || XVECEXP (unspec, 0, 0) != src_reg
8126132718Skan	  || GET_CODE (XVECEXP (unspec, 0, 1)) != CONST_INT
8127132718Skan	  || INTVAL (XVECEXP (unspec, 0, 1)) != maskval)
8128132718Skan	return 0;
8129132718Skan    }
8130132718Skan  return 1;
8131132718Skan}
8132132718Skan
813390075Sobrien/* Return 1 for an PARALLEL suitable for mtcrf.  */
813490075Sobrien
813590075Sobrienint
8136132718Skanmtcrf_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
813790075Sobrien{
813890075Sobrien  int count = XVECLEN (op, 0);
813990075Sobrien  int i;
814090075Sobrien  rtx src_reg;
814190075Sobrien
814290075Sobrien  /* Perform a quick check so we don't blow up below.  */
814390075Sobrien  if (count < 1
814490075Sobrien      || GET_CODE (XVECEXP (op, 0, 0)) != SET
814590075Sobrien      || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != UNSPEC
814690075Sobrien      || XVECLEN (SET_SRC (XVECEXP (op, 0, 0)), 0) != 2)
814790075Sobrien    return 0;
814890075Sobrien  src_reg = XVECEXP (SET_SRC (XVECEXP (op, 0, 0)), 0, 0);
814990075Sobrien
815090075Sobrien  if (GET_CODE (src_reg) != REG
815190075Sobrien      || GET_MODE (src_reg) != SImode
815290075Sobrien      || ! INT_REGNO_P (REGNO (src_reg)))
815390075Sobrien    return 0;
815490075Sobrien
815590075Sobrien  for (i = 0; i < count; i++)
815690075Sobrien    {
815790075Sobrien      rtx exp = XVECEXP (op, 0, i);
815890075Sobrien      rtx unspec;
815990075Sobrien      int maskval;
816090075Sobrien
816190075Sobrien      if (GET_CODE (exp) != SET
816290075Sobrien	  || GET_CODE (SET_DEST (exp)) != REG
816390075Sobrien	  || GET_MODE (SET_DEST (exp)) != CCmode
816490075Sobrien	  || ! CR_REGNO_P (REGNO (SET_DEST (exp))))
816590075Sobrien	return 0;
816690075Sobrien      unspec = SET_SRC (exp);
816790075Sobrien      maskval = 1 << (MAX_CR_REGNO - REGNO (SET_DEST (exp)));
816890075Sobrien
816990075Sobrien      if (GET_CODE (unspec) != UNSPEC
8170132718Skan	  || XINT (unspec, 1) != UNSPEC_MOVESI_TO_CR
817190075Sobrien	  || XVECLEN (unspec, 0) != 2
817290075Sobrien	  || XVECEXP (unspec, 0, 0) != src_reg
817390075Sobrien	  || GET_CODE (XVECEXP (unspec, 0, 1)) != CONST_INT
817490075Sobrien	  || INTVAL (XVECEXP (unspec, 0, 1)) != maskval)
817590075Sobrien	return 0;
817690075Sobrien    }
817790075Sobrien  return 1;
817890075Sobrien}
817990075Sobrien
818090075Sobrien/* Return 1 for an PARALLEL suitable for lmw.  */
818190075Sobrien
818290075Sobrienint
8183132718Skanlmw_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
818490075Sobrien{
818590075Sobrien  int count = XVECLEN (op, 0);
818690075Sobrien  unsigned int dest_regno;
818790075Sobrien  rtx src_addr;
818890075Sobrien  unsigned int base_regno;
818990075Sobrien  HOST_WIDE_INT offset;
819090075Sobrien  int i;
819190075Sobrien
819290075Sobrien  /* Perform a quick check so we don't blow up below.  */
819390075Sobrien  if (count <= 1
819490075Sobrien      || GET_CODE (XVECEXP (op, 0, 0)) != SET
819590075Sobrien      || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != REG
819690075Sobrien      || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != MEM)
819790075Sobrien    return 0;
819890075Sobrien
819990075Sobrien  dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, 0)));
820090075Sobrien  src_addr = XEXP (SET_SRC (XVECEXP (op, 0, 0)), 0);
820190075Sobrien
820290075Sobrien  if (dest_regno > 31
820390075Sobrien      || count != 32 - (int) dest_regno)
820490075Sobrien    return 0;
820590075Sobrien
8206132718Skan  if (legitimate_indirect_address_p (src_addr, 0))
820790075Sobrien    {
820890075Sobrien      offset = 0;
820990075Sobrien      base_regno = REGNO (src_addr);
821090075Sobrien      if (base_regno == 0)
821190075Sobrien	return 0;
821290075Sobrien    }
8213132718Skan  else if (legitimate_offset_address_p (SImode, src_addr, 0))
821490075Sobrien    {
821590075Sobrien      offset = INTVAL (XEXP (src_addr, 1));
821690075Sobrien      base_regno = REGNO (XEXP (src_addr, 0));
821790075Sobrien    }
821890075Sobrien  else
821990075Sobrien    return 0;
822090075Sobrien
822190075Sobrien  for (i = 0; i < count; i++)
822290075Sobrien    {
822390075Sobrien      rtx elt = XVECEXP (op, 0, i);
822490075Sobrien      rtx newaddr;
822590075Sobrien      rtx addr_reg;
822690075Sobrien      HOST_WIDE_INT newoffset;
822790075Sobrien
822890075Sobrien      if (GET_CODE (elt) != SET
822990075Sobrien	  || GET_CODE (SET_DEST (elt)) != REG
823090075Sobrien	  || GET_MODE (SET_DEST (elt)) != SImode
823190075Sobrien	  || REGNO (SET_DEST (elt)) != dest_regno + i
823290075Sobrien	  || GET_CODE (SET_SRC (elt)) != MEM
823390075Sobrien	  || GET_MODE (SET_SRC (elt)) != SImode)
823490075Sobrien	return 0;
823590075Sobrien      newaddr = XEXP (SET_SRC (elt), 0);
8236132718Skan      if (legitimate_indirect_address_p (newaddr, 0))
823790075Sobrien	{
823890075Sobrien	  newoffset = 0;
823990075Sobrien	  addr_reg = newaddr;
824090075Sobrien	}
8241132718Skan      else if (legitimate_offset_address_p (SImode, newaddr, 0))
824290075Sobrien	{
824390075Sobrien	  addr_reg = XEXP (newaddr, 0);
824490075Sobrien	  newoffset = INTVAL (XEXP (newaddr, 1));
824590075Sobrien	}
824690075Sobrien      else
824790075Sobrien	return 0;
824890075Sobrien      if (REGNO (addr_reg) != base_regno
824990075Sobrien	  || newoffset != offset + 4 * i)
825090075Sobrien	return 0;
825190075Sobrien    }
825290075Sobrien
825390075Sobrien  return 1;
825490075Sobrien}
825590075Sobrien
825690075Sobrien/* Return 1 for an PARALLEL suitable for stmw.  */
825790075Sobrien
825890075Sobrienint
8259132718Skanstmw_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
826090075Sobrien{
826190075Sobrien  int count = XVECLEN (op, 0);
826290075Sobrien  unsigned int src_regno;
826390075Sobrien  rtx dest_addr;
826490075Sobrien  unsigned int base_regno;
826590075Sobrien  HOST_WIDE_INT offset;
826690075Sobrien  int i;
826790075Sobrien
826890075Sobrien  /* Perform a quick check so we don't blow up below.  */
826990075Sobrien  if (count <= 1
827090075Sobrien      || GET_CODE (XVECEXP (op, 0, 0)) != SET
827190075Sobrien      || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != MEM
827290075Sobrien      || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != REG)
827390075Sobrien    return 0;
827490075Sobrien
827590075Sobrien  src_regno = REGNO (SET_SRC (XVECEXP (op, 0, 0)));
827690075Sobrien  dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, 0)), 0);
827790075Sobrien
827890075Sobrien  if (src_regno > 31
827990075Sobrien      || count != 32 - (int) src_regno)
828090075Sobrien    return 0;
828190075Sobrien
8282132718Skan  if (legitimate_indirect_address_p (dest_addr, 0))
828390075Sobrien    {
828490075Sobrien      offset = 0;
828590075Sobrien      base_regno = REGNO (dest_addr);
828690075Sobrien      if (base_regno == 0)
828790075Sobrien	return 0;
828890075Sobrien    }
8289132718Skan  else if (legitimate_offset_address_p (SImode, dest_addr, 0))
829090075Sobrien    {
829190075Sobrien      offset = INTVAL (XEXP (dest_addr, 1));
829290075Sobrien      base_regno = REGNO (XEXP (dest_addr, 0));
829390075Sobrien    }
829490075Sobrien  else
829590075Sobrien    return 0;
829690075Sobrien
829790075Sobrien  for (i = 0; i < count; i++)
829890075Sobrien    {
829990075Sobrien      rtx elt = XVECEXP (op, 0, i);
830090075Sobrien      rtx newaddr;
830190075Sobrien      rtx addr_reg;
830290075Sobrien      HOST_WIDE_INT newoffset;
830390075Sobrien
830490075Sobrien      if (GET_CODE (elt) != SET
830590075Sobrien	  || GET_CODE (SET_SRC (elt)) != REG
830690075Sobrien	  || GET_MODE (SET_SRC (elt)) != SImode
830790075Sobrien	  || REGNO (SET_SRC (elt)) != src_regno + i
830890075Sobrien	  || GET_CODE (SET_DEST (elt)) != MEM
830990075Sobrien	  || GET_MODE (SET_DEST (elt)) != SImode)
831090075Sobrien	return 0;
831190075Sobrien      newaddr = XEXP (SET_DEST (elt), 0);
8312132718Skan      if (legitimate_indirect_address_p (newaddr, 0))
831390075Sobrien	{
831490075Sobrien	  newoffset = 0;
831590075Sobrien	  addr_reg = newaddr;
831690075Sobrien	}
8317132718Skan      else if (legitimate_offset_address_p (SImode, newaddr, 0))
831890075Sobrien	{
831990075Sobrien	  addr_reg = XEXP (newaddr, 0);
832090075Sobrien	  newoffset = INTVAL (XEXP (newaddr, 1));
832190075Sobrien	}
832290075Sobrien      else
832390075Sobrien	return 0;
832490075Sobrien      if (REGNO (addr_reg) != base_regno
832590075Sobrien	  || newoffset != offset + 4 * i)
832690075Sobrien	return 0;
832790075Sobrien    }
832890075Sobrien
832990075Sobrien  return 1;
833090075Sobrien}
833190075Sobrien
833290075Sobrien/* A validation routine: say whether CODE, a condition code, and MODE
833390075Sobrien   match.  The other alternatives either don't make sense or should
833490075Sobrien   never be generated.  */
833590075Sobrien
833690075Sobrienstatic void
8337132718Skanvalidate_condition_mode (enum rtx_code code, enum machine_mode mode)
833890075Sobrien{
833990075Sobrien  if (GET_RTX_CLASS (code) != '<'
834090075Sobrien      || GET_MODE_CLASS (mode) != MODE_CC)
834190075Sobrien    abort ();
834290075Sobrien
834390075Sobrien  /* These don't make sense.  */
834490075Sobrien  if ((code == GT || code == LT || code == GE || code == LE)
834590075Sobrien      && mode == CCUNSmode)
834690075Sobrien    abort ();
834790075Sobrien
834890075Sobrien  if ((code == GTU || code == LTU || code == GEU || code == LEU)
834990075Sobrien      && mode != CCUNSmode)
835090075Sobrien    abort ();
835190075Sobrien
835290075Sobrien  if (mode != CCFPmode
835390075Sobrien      && (code == ORDERED || code == UNORDERED
835490075Sobrien	  || code == UNEQ || code == LTGT
835590075Sobrien	  || code == UNGT || code == UNLT
835690075Sobrien	  || code == UNGE || code == UNLE))
835790075Sobrien    abort ();
835890075Sobrien
835990075Sobrien  /* These should never be generated except for
8360132718Skan     flag_finite_math_only.  */
836190075Sobrien  if (mode == CCFPmode
8362117395Skan      && ! flag_finite_math_only
836390075Sobrien      && (code == LE || code == GE
836490075Sobrien	  || code == UNEQ || code == LTGT
836590075Sobrien	  || code == UNGT || code == UNLT))
836690075Sobrien    abort ();
836790075Sobrien
836890075Sobrien  /* These are invalid; the information is not there.  */
836990075Sobrien  if (mode == CCEQmode
837090075Sobrien      && code != EQ && code != NE)
837190075Sobrien    abort ();
837290075Sobrien}
837390075Sobrien
837490075Sobrien/* Return 1 if OP is a comparison operation that is valid for a branch insn.
837590075Sobrien   We only check the opcode against the mode of the CC value here.  */
837690075Sobrien
837790075Sobrienint
8378132718Skanbranch_comparison_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
837990075Sobrien{
838090075Sobrien  enum rtx_code code = GET_CODE (op);
838190075Sobrien  enum machine_mode cc_mode;
838290075Sobrien
838390075Sobrien  if (GET_RTX_CLASS (code) != '<')
838490075Sobrien    return 0;
838590075Sobrien
838690075Sobrien  cc_mode = GET_MODE (XEXP (op, 0));
838790075Sobrien  if (GET_MODE_CLASS (cc_mode) != MODE_CC)
838890075Sobrien    return 0;
838990075Sobrien
839090075Sobrien  validate_condition_mode (code, cc_mode);
839190075Sobrien
839290075Sobrien  return 1;
839390075Sobrien}
839490075Sobrien
839590075Sobrien/* Return 1 if OP is a comparison operation that is valid for a branch
839690075Sobrien   insn and which is true if the corresponding bit in the CC register
839790075Sobrien   is set.  */
839890075Sobrien
839990075Sobrienint
8400132718Skanbranch_positive_comparison_operator (rtx op, enum machine_mode mode)
840190075Sobrien{
840290075Sobrien  enum rtx_code code;
840390075Sobrien
840490075Sobrien  if (! branch_comparison_operator (op, mode))
840590075Sobrien    return 0;
840690075Sobrien
840790075Sobrien  code = GET_CODE (op);
840890075Sobrien  return (code == EQ || code == LT || code == GT
840990075Sobrien	  || code == LTU || code == GTU
841090075Sobrien	  || code == UNORDERED);
841190075Sobrien}
841290075Sobrien
8413132718Skan/* Return 1 if OP is a comparison operation that is valid for an scc
8414132718Skan   insn: it must be a positive comparison.  */
841590075Sobrien
841690075Sobrienint
8417132718Skanscc_comparison_operator (rtx op, enum machine_mode mode)
841890075Sobrien{
8419132718Skan  return branch_positive_comparison_operator (op, mode);
842090075Sobrien}
842190075Sobrien
842290075Sobrienint
8423132718Skantrap_comparison_operator (rtx op, enum machine_mode mode)
842490075Sobrien{
842590075Sobrien  if (mode != VOIDmode && mode != GET_MODE (op))
842690075Sobrien    return 0;
842790075Sobrien  return GET_RTX_CLASS (GET_CODE (op)) == '<';
842890075Sobrien}
842990075Sobrien
843090075Sobrienint
8431132718Skanboolean_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
843290075Sobrien{
843390075Sobrien  enum rtx_code code = GET_CODE (op);
843490075Sobrien  return (code == AND || code == IOR || code == XOR);
843590075Sobrien}
843690075Sobrien
843790075Sobrienint
8438132718Skanboolean_or_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
843990075Sobrien{
844090075Sobrien  enum rtx_code code = GET_CODE (op);
844190075Sobrien  return (code == IOR || code == XOR);
844290075Sobrien}
844390075Sobrien
844490075Sobrienint
8445132718Skanmin_max_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
844690075Sobrien{
844790075Sobrien  enum rtx_code code = GET_CODE (op);
844890075Sobrien  return (code == SMIN || code == SMAX || code == UMIN || code == UMAX);
844990075Sobrien}
845090075Sobrien
845190075Sobrien/* Return 1 if ANDOP is a mask that has no bits on that are not in the
845290075Sobrien   mask required to convert the result of a rotate insn into a shift
845396263Sobrien   left insn of SHIFTOP bits.  Both are known to be SImode CONST_INT.  */
845490075Sobrien
845590075Sobrienint
8456132718Skanincludes_lshift_p (rtx shiftop, rtx andop)
845790075Sobrien{
845890075Sobrien  unsigned HOST_WIDE_INT shift_mask = ~(unsigned HOST_WIDE_INT) 0;
845990075Sobrien
846090075Sobrien  shift_mask <<= INTVAL (shiftop);
846190075Sobrien
846296263Sobrien  return (INTVAL (andop) & 0xffffffff & ~shift_mask) == 0;
846390075Sobrien}
846490075Sobrien
846590075Sobrien/* Similar, but for right shift.  */
846690075Sobrien
846790075Sobrienint
8468132718Skanincludes_rshift_p (rtx shiftop, rtx andop)
846990075Sobrien{
847090075Sobrien  unsigned HOST_WIDE_INT shift_mask = ~(unsigned HOST_WIDE_INT) 0;
847190075Sobrien
847290075Sobrien  shift_mask >>= INTVAL (shiftop);
847390075Sobrien
847496263Sobrien  return (INTVAL (andop) & 0xffffffff & ~shift_mask) == 0;
847590075Sobrien}
847690075Sobrien
847790075Sobrien/* Return 1 if ANDOP is a mask suitable for use with an rldic insn
847890075Sobrien   to perform a left shift.  It must have exactly SHIFTOP least
8479132718Skan   significant 0's, then one or more 1's, then zero or more 0's.  */
848090075Sobrien
848190075Sobrienint
8482132718Skanincludes_rldic_lshift_p (rtx shiftop, rtx andop)
848390075Sobrien{
848490075Sobrien  if (GET_CODE (andop) == CONST_INT)
848590075Sobrien    {
848690075Sobrien      HOST_WIDE_INT c, lsb, shift_mask;
848790075Sobrien
848890075Sobrien      c = INTVAL (andop);
848990075Sobrien      if (c == 0 || c == ~0)
849090075Sobrien	return 0;
849190075Sobrien
849290075Sobrien      shift_mask = ~0;
849390075Sobrien      shift_mask <<= INTVAL (shiftop);
849490075Sobrien
8495132718Skan      /* Find the least significant one bit.  */
849690075Sobrien      lsb = c & -c;
849790075Sobrien
849890075Sobrien      /* It must coincide with the LSB of the shift mask.  */
849990075Sobrien      if (-lsb != shift_mask)
850090075Sobrien	return 0;
850190075Sobrien
850290075Sobrien      /* Invert to look for the next transition (if any).  */
850390075Sobrien      c = ~c;
850490075Sobrien
850590075Sobrien      /* Remove the low group of ones (originally low group of zeros).  */
850690075Sobrien      c &= -lsb;
850790075Sobrien
850890075Sobrien      /* Again find the lsb, and check we have all 1's above.  */
850990075Sobrien      lsb = c & -c;
851090075Sobrien      return c == -lsb;
851190075Sobrien    }
851290075Sobrien  else if (GET_CODE (andop) == CONST_DOUBLE
851390075Sobrien	   && (GET_MODE (andop) == VOIDmode || GET_MODE (andop) == DImode))
851490075Sobrien    {
851590075Sobrien      HOST_WIDE_INT low, high, lsb;
851690075Sobrien      HOST_WIDE_INT shift_mask_low, shift_mask_high;
851790075Sobrien
851890075Sobrien      low = CONST_DOUBLE_LOW (andop);
851990075Sobrien      if (HOST_BITS_PER_WIDE_INT < 64)
852090075Sobrien	high = CONST_DOUBLE_HIGH (andop);
852190075Sobrien
852290075Sobrien      if ((low == 0 && (HOST_BITS_PER_WIDE_INT >= 64 || high == 0))
852390075Sobrien	  || (low == ~0 && (HOST_BITS_PER_WIDE_INT >= 64 || high == ~0)))
852490075Sobrien	return 0;
852590075Sobrien
852690075Sobrien      if (HOST_BITS_PER_WIDE_INT < 64 && low == 0)
852790075Sobrien	{
852890075Sobrien	  shift_mask_high = ~0;
852990075Sobrien	  if (INTVAL (shiftop) > 32)
853090075Sobrien	    shift_mask_high <<= INTVAL (shiftop) - 32;
853190075Sobrien
853290075Sobrien	  lsb = high & -high;
853390075Sobrien
853490075Sobrien	  if (-lsb != shift_mask_high || INTVAL (shiftop) < 32)
853590075Sobrien	    return 0;
853690075Sobrien
853790075Sobrien	  high = ~high;
853890075Sobrien	  high &= -lsb;
853990075Sobrien
854090075Sobrien	  lsb = high & -high;
854190075Sobrien	  return high == -lsb;
854290075Sobrien	}
854390075Sobrien
854490075Sobrien      shift_mask_low = ~0;
854590075Sobrien      shift_mask_low <<= INTVAL (shiftop);
854690075Sobrien
854790075Sobrien      lsb = low & -low;
854890075Sobrien
854990075Sobrien      if (-lsb != shift_mask_low)
855090075Sobrien	return 0;
855190075Sobrien
855290075Sobrien      if (HOST_BITS_PER_WIDE_INT < 64)
855390075Sobrien	high = ~high;
855490075Sobrien      low = ~low;
855590075Sobrien      low &= -lsb;
855690075Sobrien
855790075Sobrien      if (HOST_BITS_PER_WIDE_INT < 64 && low == 0)
855890075Sobrien	{
855990075Sobrien	  lsb = high & -high;
856090075Sobrien	  return high == -lsb;
856190075Sobrien	}
856290075Sobrien
856390075Sobrien      lsb = low & -low;
856490075Sobrien      return low == -lsb && (HOST_BITS_PER_WIDE_INT >= 64 || high == ~0);
856590075Sobrien    }
856690075Sobrien  else
856790075Sobrien    return 0;
856890075Sobrien}
856990075Sobrien
857090075Sobrien/* Return 1 if ANDOP is a mask suitable for use with an rldicr insn
857190075Sobrien   to perform a left shift.  It must have SHIFTOP or more least
8572132718Skan   significant 0's, with the remainder of the word 1's.  */
857390075Sobrien
857490075Sobrienint
8575132718Skanincludes_rldicr_lshift_p (rtx shiftop, rtx andop)
857690075Sobrien{
857790075Sobrien  if (GET_CODE (andop) == CONST_INT)
857890075Sobrien    {
857990075Sobrien      HOST_WIDE_INT c, lsb, shift_mask;
858090075Sobrien
858190075Sobrien      shift_mask = ~0;
858290075Sobrien      shift_mask <<= INTVAL (shiftop);
858390075Sobrien      c = INTVAL (andop);
858490075Sobrien
8585132718Skan      /* Find the least significant one bit.  */
858690075Sobrien      lsb = c & -c;
858790075Sobrien
858890075Sobrien      /* It must be covered by the shift mask.
858990075Sobrien	 This test also rejects c == 0.  */
859090075Sobrien      if ((lsb & shift_mask) == 0)
859190075Sobrien	return 0;
859290075Sobrien
859390075Sobrien      /* Check we have all 1's above the transition, and reject all 1's.  */
859490075Sobrien      return c == -lsb && lsb != 1;
859590075Sobrien    }
859690075Sobrien  else if (GET_CODE (andop) == CONST_DOUBLE
859790075Sobrien	   && (GET_MODE (andop) == VOIDmode || GET_MODE (andop) == DImode))
859890075Sobrien    {
859990075Sobrien      HOST_WIDE_INT low, lsb, shift_mask_low;
860090075Sobrien
860190075Sobrien      low = CONST_DOUBLE_LOW (andop);
860290075Sobrien
860390075Sobrien      if (HOST_BITS_PER_WIDE_INT < 64)
860490075Sobrien	{
860590075Sobrien	  HOST_WIDE_INT high, shift_mask_high;
860690075Sobrien
860790075Sobrien	  high = CONST_DOUBLE_HIGH (andop);
860890075Sobrien
860990075Sobrien	  if (low == 0)
861090075Sobrien	    {
861190075Sobrien	      shift_mask_high = ~0;
861290075Sobrien	      if (INTVAL (shiftop) > 32)
861390075Sobrien		shift_mask_high <<= INTVAL (shiftop) - 32;
861490075Sobrien
861590075Sobrien	      lsb = high & -high;
861690075Sobrien
861790075Sobrien	      if ((lsb & shift_mask_high) == 0)
861890075Sobrien		return 0;
861990075Sobrien
862090075Sobrien	      return high == -lsb;
862190075Sobrien	    }
862290075Sobrien	  if (high != ~0)
862390075Sobrien	    return 0;
862490075Sobrien	}
862590075Sobrien
862690075Sobrien      shift_mask_low = ~0;
862790075Sobrien      shift_mask_low <<= INTVAL (shiftop);
862890075Sobrien
862990075Sobrien      lsb = low & -low;
863090075Sobrien
863190075Sobrien      if ((lsb & shift_mask_low) == 0)
863290075Sobrien	return 0;
863390075Sobrien
863490075Sobrien      return low == -lsb && lsb != 1;
863590075Sobrien    }
863690075Sobrien  else
863790075Sobrien    return 0;
863890075Sobrien}
863990075Sobrien
864090075Sobrien/* Return 1 if REGNO (reg1) == REGNO (reg2) - 1 making them candidates
864190075Sobrien   for lfq and stfq insns.
864290075Sobrien
864390075Sobrien   Note reg1 and reg2 *must* be hard registers.  To be sure we will
864490075Sobrien   abort if we are passed pseudo registers.  */
864590075Sobrien
864690075Sobrienint
8647132718Skanregisters_ok_for_quad_peep (rtx reg1, rtx reg2)
864890075Sobrien{
864990075Sobrien  /* We might have been passed a SUBREG.  */
865090075Sobrien  if (GET_CODE (reg1) != REG || GET_CODE (reg2) != REG)
865190075Sobrien    return 0;
865290075Sobrien
865390075Sobrien  return (REGNO (reg1) == REGNO (reg2) - 1);
865490075Sobrien}
865590075Sobrien
865690075Sobrien/* Return 1 if addr1 and addr2 are suitable for lfq or stfq insn.
865790075Sobrien   addr1 and addr2 must be in consecutive memory locations
865890075Sobrien   (addr2 == addr1 + 8).  */
865990075Sobrien
866090075Sobrienint
8661132718Skanaddrs_ok_for_quad_peep (rtx addr1, rtx addr2)
866290075Sobrien{
866390075Sobrien  unsigned int reg1;
866490075Sobrien  int offset1;
866590075Sobrien
866690075Sobrien  /* Extract an offset (if used) from the first addr.  */
866790075Sobrien  if (GET_CODE (addr1) == PLUS)
866890075Sobrien    {
866990075Sobrien      /* If not a REG, return zero.  */
867090075Sobrien      if (GET_CODE (XEXP (addr1, 0)) != REG)
867190075Sobrien	return 0;
867290075Sobrien      else
867390075Sobrien	{
867490075Sobrien          reg1 = REGNO (XEXP (addr1, 0));
867590075Sobrien	  /* The offset must be constant!  */
867690075Sobrien	  if (GET_CODE (XEXP (addr1, 1)) != CONST_INT)
867790075Sobrien            return 0;
867890075Sobrien          offset1 = INTVAL (XEXP (addr1, 1));
867990075Sobrien	}
868090075Sobrien    }
868190075Sobrien  else if (GET_CODE (addr1) != REG)
868290075Sobrien    return 0;
868390075Sobrien  else
868490075Sobrien    {
868590075Sobrien      reg1 = REGNO (addr1);
868690075Sobrien      /* This was a simple (mem (reg)) expression.  Offset is 0.  */
868790075Sobrien      offset1 = 0;
868890075Sobrien    }
868990075Sobrien
8690132718Skan  /* Make sure the second address is a (mem (plus (reg) (const_int)))
8691132718Skan      or if it is (mem (reg)) then make sure that offset1 is -8 and the same
8692132718Skan      register as addr1.  */
8693132718Skan  if (offset1 == -8 && GET_CODE (addr2) == REG && reg1 == REGNO (addr2))
8694132718Skan   return 1;
869590075Sobrien  if (GET_CODE (addr2) != PLUS)
869690075Sobrien    return 0;
869790075Sobrien
869890075Sobrien  if (GET_CODE (XEXP (addr2, 0)) != REG
869990075Sobrien      || GET_CODE (XEXP (addr2, 1)) != CONST_INT)
870090075Sobrien    return 0;
870190075Sobrien
870290075Sobrien  if (reg1 != REGNO (XEXP (addr2, 0)))
870390075Sobrien    return 0;
870490075Sobrien
870590075Sobrien  /* The offset for the second addr must be 8 more than the first addr.  */
870690075Sobrien  if (INTVAL (XEXP (addr2, 1)) != offset1 + 8)
870790075Sobrien    return 0;
870890075Sobrien
870990075Sobrien  /* All the tests passed.  addr1 and addr2 are valid for lfq or stfq
871090075Sobrien     instructions.  */
871190075Sobrien  return 1;
871290075Sobrien}
871390075Sobrien
871490075Sobrien/* Return the register class of a scratch register needed to copy IN into
871590075Sobrien   or out of a register in CLASS in MODE.  If it can be done directly,
8716161651Skan   NO_REGS is returned.  */
871790075Sobrien
871890075Sobrienenum reg_class
8719132718Skansecondary_reload_class (enum reg_class class,
8720132718Skan			enum machine_mode mode,
8721161651Skan			rtx in)
872290075Sobrien{
872390075Sobrien  int regno;
872490075Sobrien
8725132718Skan  if (TARGET_ELF || (DEFAULT_ABI == ABI_DARWIN
8726132718Skan#if TARGET_MACHO
8727132718Skan                    && MACHOPIC_INDIRECT
8728132718Skan#endif
8729132718Skan                    ))
873090075Sobrien    {
873190075Sobrien      /* We cannot copy a symbolic operand directly into anything
873290075Sobrien         other than BASE_REGS for TARGET_ELF.  So indicate that a
873390075Sobrien         register from BASE_REGS is needed as an intermediate
873490075Sobrien         register.
873590075Sobrien
873690075Sobrien	 On Darwin, pic addresses require a load from memory, which
873790075Sobrien	 needs a base register.  */
873890075Sobrien      if (class != BASE_REGS
873990075Sobrien          && (GET_CODE (in) == SYMBOL_REF
874090075Sobrien              || GET_CODE (in) == HIGH
874190075Sobrien              || GET_CODE (in) == LABEL_REF
874290075Sobrien              || GET_CODE (in) == CONST))
874390075Sobrien        return BASE_REGS;
874490075Sobrien    }
874590075Sobrien
874690075Sobrien  if (GET_CODE (in) == REG)
874790075Sobrien    {
874890075Sobrien      regno = REGNO (in);
874990075Sobrien      if (regno >= FIRST_PSEUDO_REGISTER)
875090075Sobrien	{
875190075Sobrien	  regno = true_regnum (in);
875290075Sobrien	  if (regno >= FIRST_PSEUDO_REGISTER)
875390075Sobrien	    regno = -1;
875490075Sobrien	}
875590075Sobrien    }
875690075Sobrien  else if (GET_CODE (in) == SUBREG)
875790075Sobrien    {
875890075Sobrien      regno = true_regnum (in);
875990075Sobrien      if (regno >= FIRST_PSEUDO_REGISTER)
876090075Sobrien	regno = -1;
876190075Sobrien    }
876290075Sobrien  else
876390075Sobrien    regno = -1;
876490075Sobrien
876590075Sobrien  /* We can place anything into GENERAL_REGS and can put GENERAL_REGS
876690075Sobrien     into anything.  */
876790075Sobrien  if (class == GENERAL_REGS || class == BASE_REGS
876890075Sobrien      || (regno >= 0 && INT_REGNO_P (regno)))
876990075Sobrien    return NO_REGS;
877090075Sobrien
877190075Sobrien  /* Constants, memory, and FP registers can go into FP registers.  */
877290075Sobrien  if ((regno == -1 || FP_REGNO_P (regno))
877390075Sobrien      && (class == FLOAT_REGS || class == NON_SPECIAL_REGS))
877490075Sobrien    return NO_REGS;
877590075Sobrien
877690075Sobrien  /* Memory, and AltiVec registers can go into AltiVec registers.  */
877790075Sobrien  if ((regno == -1 || ALTIVEC_REGNO_P (regno))
877890075Sobrien      && class == ALTIVEC_REGS)
877990075Sobrien    return NO_REGS;
878090075Sobrien
878190075Sobrien  /* We can copy among the CR registers.  */
878290075Sobrien  if ((class == CR_REGS || class == CR0_REGS)
878390075Sobrien      && regno >= 0 && CR_REGNO_P (regno))
878490075Sobrien    return NO_REGS;
878590075Sobrien
878690075Sobrien  /* Otherwise, we need GENERAL_REGS.  */
878790075Sobrien  return GENERAL_REGS;
878890075Sobrien}
878990075Sobrien
879090075Sobrien/* Given a comparison operation, return the bit number in CCR to test.  We
879190075Sobrien   know this is a valid comparison.
879290075Sobrien
879390075Sobrien   SCC_P is 1 if this is for an scc.  That means that %D will have been
879490075Sobrien   used instead of %C, so the bits will be in different places.
879590075Sobrien
879690075Sobrien   Return -1 if OP isn't a valid comparison for some reason.  */
879790075Sobrien
879890075Sobrienint
8799132718Skanccr_bit (rtx op, int scc_p)
880090075Sobrien{
880190075Sobrien  enum rtx_code code = GET_CODE (op);
880290075Sobrien  enum machine_mode cc_mode;
880390075Sobrien  int cc_regnum;
880490075Sobrien  int base_bit;
880590075Sobrien  rtx reg;
880690075Sobrien
880790075Sobrien  if (GET_RTX_CLASS (code) != '<')
880890075Sobrien    return -1;
880990075Sobrien
881090075Sobrien  reg = XEXP (op, 0);
881190075Sobrien
881290075Sobrien  if (GET_CODE (reg) != REG
881390075Sobrien      || ! CR_REGNO_P (REGNO (reg)))
881490075Sobrien    abort ();
881590075Sobrien
881690075Sobrien  cc_mode = GET_MODE (reg);
881790075Sobrien  cc_regnum = REGNO (reg);
881890075Sobrien  base_bit = 4 * (cc_regnum - CR0_REGNO);
881990075Sobrien
882090075Sobrien  validate_condition_mode (code, cc_mode);
882190075Sobrien
8822132718Skan  /* When generating a sCOND operation, only positive conditions are
8823132718Skan     allowed.  */
8824132718Skan  if (scc_p && code != EQ && code != GT && code != LT && code != UNORDERED
8825132718Skan      && code != GTU && code != LTU)
8826132718Skan    abort ();
8827132718Skan
882890075Sobrien  switch (code)
882990075Sobrien    {
883090075Sobrien    case NE:
883190075Sobrien      return scc_p ? base_bit + 3 : base_bit + 2;
883290075Sobrien    case EQ:
883390075Sobrien      return base_bit + 2;
883490075Sobrien    case GT:  case GTU:  case UNLE:
883590075Sobrien      return base_bit + 1;
883690075Sobrien    case LT:  case LTU:  case UNGE:
883790075Sobrien      return base_bit;
883890075Sobrien    case ORDERED:  case UNORDERED:
883990075Sobrien      return base_bit + 3;
884090075Sobrien
884190075Sobrien    case GE:  case GEU:
884290075Sobrien      /* If scc, we will have done a cror to put the bit in the
884390075Sobrien	 unordered position.  So test that bit.  For integer, this is ! LT
884490075Sobrien	 unless this is an scc insn.  */
884590075Sobrien      return scc_p ? base_bit + 3 : base_bit;
884690075Sobrien
884790075Sobrien    case LE:  case LEU:
884890075Sobrien      return scc_p ? base_bit + 3 : base_bit + 1;
884990075Sobrien
885090075Sobrien    default:
885190075Sobrien      abort ();
885290075Sobrien    }
885390075Sobrien}
885490075Sobrien
885590075Sobrien/* Return the GOT register.  */
885690075Sobrien
885790075Sobrienstruct rtx_def *
8858132718Skanrs6000_got_register (rtx value ATTRIBUTE_UNUSED)
885990075Sobrien{
886090075Sobrien  /* The second flow pass currently (June 1999) can't update
886190075Sobrien     regs_ever_live without disturbing other parts of the compiler, so
886290075Sobrien     update it here to make the prolog/epilogue code happy.  */
886396263Sobrien  if (no_new_pseudos && ! regs_ever_live[RS6000_PIC_OFFSET_TABLE_REGNUM])
886496263Sobrien    regs_ever_live[RS6000_PIC_OFFSET_TABLE_REGNUM] = 1;
886590075Sobrien
886690075Sobrien  current_function_uses_pic_offset_table = 1;
886790075Sobrien
886890075Sobrien  return pic_offset_table_rtx;
886990075Sobrien}
887090075Sobrien
8871117395Skan/* Function to init struct machine_function.
8872117395Skan   This will be called, via a pointer variable,
8873117395Skan   from push_function_context.  */
887490075Sobrien
8875117395Skanstatic struct machine_function *
8876132718Skanrs6000_init_machine_status (void)
887790075Sobrien{
8878117395Skan  return ggc_alloc_cleared (sizeof (machine_function));
887990075Sobrien}
8880117395Skan
8881117395Skan/* These macros test for integers and extract the low-order bits.  */
8882117395Skan#define INT_P(X)  \
8883117395Skan((GET_CODE (X) == CONST_INT || GET_CODE (X) == CONST_DOUBLE)	\
8884117395Skan && GET_MODE (X) == VOIDmode)
888590075Sobrien
8886117395Skan#define INT_LOWPART(X) \
8887117395Skan  (GET_CODE (X) == CONST_INT ? INTVAL (X) : CONST_DOUBLE_LOW (X))
8888117395Skan
8889117395Skanint
8890132718Skanextract_MB (rtx op)
889190075Sobrien{
8892117395Skan  int i;
8893117395Skan  unsigned long val = INT_LOWPART (op);
889490075Sobrien
8895117395Skan  /* If the high bit is zero, the value is the first 1 bit we find
8896117395Skan     from the left.  */
8897117395Skan  if ((val & 0x80000000) == 0)
8898117395Skan    {
8899117395Skan      if ((val & 0xffffffff) == 0)
8900117395Skan	abort ();
8901117395Skan
8902117395Skan      i = 1;
8903117395Skan      while (((val <<= 1) & 0x80000000) == 0)
8904117395Skan	++i;
8905117395Skan      return i;
8906117395Skan    }
8907117395Skan
8908117395Skan  /* If the high bit is set and the low bit is not, or the mask is all
8909117395Skan     1's, the value is zero.  */
8910117395Skan  if ((val & 1) == 0 || (val & 0xffffffff) == 0xffffffff)
8911117395Skan    return 0;
8912117395Skan
8913117395Skan  /* Otherwise we have a wrap-around mask.  Look for the first 0 bit
8914117395Skan     from the right.  */
8915117395Skan  i = 31;
8916117395Skan  while (((val >>= 1) & 1) != 0)
8917117395Skan    --i;
8918117395Skan
8919117395Skan  return i;
892090075Sobrien}
892190075Sobrien
8922117395Skanint
8923132718Skanextract_ME (rtx op)
8924117395Skan{
8925117395Skan  int i;
8926117395Skan  unsigned long val = INT_LOWPART (op);
8927117395Skan
8928117395Skan  /* If the low bit is zero, the value is the first 1 bit we find from
8929117395Skan     the right.  */
8930117395Skan  if ((val & 1) == 0)
8931117395Skan    {
8932117395Skan      if ((val & 0xffffffff) == 0)
8933117395Skan	abort ();
8934117395Skan
8935117395Skan      i = 30;
8936117395Skan      while (((val >>= 1) & 1) == 0)
8937117395Skan	--i;
8938117395Skan
8939117395Skan      return i;
8940117395Skan    }
8941117395Skan
8942117395Skan  /* If the low bit is set and the high bit is not, or the mask is all
8943117395Skan     1's, the value is 31.  */
8944117395Skan  if ((val & 0x80000000) == 0 || (val & 0xffffffff) == 0xffffffff)
8945117395Skan    return 31;
8946117395Skan
8947117395Skan  /* Otherwise we have a wrap-around mask.  Look for the first 0 bit
8948117395Skan     from the left.  */
8949117395Skan  i = 0;
8950117395Skan  while (((val <<= 1) & 0x80000000) != 0)
8951117395Skan    ++i;
8952117395Skan
8953117395Skan  return i;
8954117395Skan}
8955117395Skan
8956132718Skan/* Locate some local-dynamic symbol still in use by this function
8957132718Skan   so that we can print its name in some tls_ld pattern.  */
8958132718Skan
8959132718Skanstatic const char *
8960132718Skanrs6000_get_some_local_dynamic_name (void)
8961132718Skan{
8962132718Skan  rtx insn;
8963132718Skan
8964132718Skan  if (cfun->machine->some_ld_name)
8965132718Skan    return cfun->machine->some_ld_name;
8966132718Skan
8967132718Skan  for (insn = get_insns (); insn ; insn = NEXT_INSN (insn))
8968132718Skan    if (INSN_P (insn)
8969132718Skan	&& for_each_rtx (&PATTERN (insn),
8970132718Skan			 rs6000_get_some_local_dynamic_name_1, 0))
8971132718Skan      return cfun->machine->some_ld_name;
8972132718Skan
8973132718Skan  abort ();
8974132718Skan}
8975132718Skan
8976132718Skan/* Helper function for rs6000_get_some_local_dynamic_name.  */
8977132718Skan
8978132718Skanstatic int
8979132718Skanrs6000_get_some_local_dynamic_name_1 (rtx *px, void *data ATTRIBUTE_UNUSED)
8980132718Skan{
8981132718Skan  rtx x = *px;
8982132718Skan
8983132718Skan  if (GET_CODE (x) == SYMBOL_REF)
8984132718Skan    {
8985132718Skan      const char *str = XSTR (x, 0);
8986132718Skan      if (SYMBOL_REF_TLS_MODEL (x) == TLS_MODEL_LOCAL_DYNAMIC)
8987132718Skan	{
8988132718Skan	  cfun->machine->some_ld_name = str;
8989132718Skan	  return 1;
8990132718Skan	}
8991132718Skan    }
8992132718Skan
8993132718Skan  return 0;
8994132718Skan}
8995132718Skan
899690075Sobrien/* Print an operand.  Recognize special options, documented below.  */
899790075Sobrien
899890075Sobrien#if TARGET_ELF
899990075Sobrien#define SMALL_DATA_RELOC ((rs6000_sdata == SDATA_EABI) ? "sda21" : "sdarel")
900090075Sobrien#define SMALL_DATA_REG ((rs6000_sdata == SDATA_EABI) ? 0 : 13)
900190075Sobrien#else
900290075Sobrien#define SMALL_DATA_RELOC "sda21"
900390075Sobrien#define SMALL_DATA_REG 0
900490075Sobrien#endif
900590075Sobrien
900690075Sobrienvoid
9007132718Skanprint_operand (FILE *file, rtx x, int code)
900890075Sobrien{
900990075Sobrien  int i;
901090075Sobrien  HOST_WIDE_INT val;
9011117395Skan  unsigned HOST_WIDE_INT uval;
901290075Sobrien
901390075Sobrien  switch (code)
901490075Sobrien    {
901590075Sobrien    case '.':
901690075Sobrien      /* Write out an instruction after the call which may be replaced
901790075Sobrien	 with glue code by the loader.  This depends on the AIX version.  */
901890075Sobrien      asm_fprintf (file, RS6000_CALL_GLUE);
901990075Sobrien      return;
902090075Sobrien
902190075Sobrien      /* %a is output_address.  */
902290075Sobrien
902390075Sobrien    case 'A':
902490075Sobrien      /* If X is a constant integer whose low-order 5 bits are zero,
902590075Sobrien	 write 'l'.  Otherwise, write 'r'.  This is a kludge to fix a bug
902690075Sobrien	 in the AIX assembler where "sri" with a zero shift count
902790075Sobrien	 writes a trash instruction.  */
902890075Sobrien      if (GET_CODE (x) == CONST_INT && (INTVAL (x) & 31) == 0)
902990075Sobrien	putc ('l', file);
903090075Sobrien      else
903190075Sobrien	putc ('r', file);
903290075Sobrien      return;
903390075Sobrien
903490075Sobrien    case 'b':
903590075Sobrien      /* If constant, low-order 16 bits of constant, unsigned.
903690075Sobrien	 Otherwise, write normally.  */
903790075Sobrien      if (INT_P (x))
903890075Sobrien	fprintf (file, HOST_WIDE_INT_PRINT_DEC, INT_LOWPART (x) & 0xffff);
903990075Sobrien      else
904090075Sobrien	print_operand (file, x, 0);
904190075Sobrien      return;
904290075Sobrien
904390075Sobrien    case 'B':
904490075Sobrien      /* If the low-order bit is zero, write 'r'; otherwise, write 'l'
904590075Sobrien	 for 64-bit mask direction.  */
904690075Sobrien      putc (((INT_LOWPART(x) & 1) == 0 ? 'r' : 'l'), file);
904790075Sobrien      return;
904890075Sobrien
904990075Sobrien      /* %c is output_addr_const if a CONSTANT_ADDRESS_P, otherwise
905090075Sobrien	 output_operand.  */
905190075Sobrien
9052132718Skan    case 'c':
9053132718Skan      /* X is a CR register.  Print the number of the GT bit of the CR.  */
9054132718Skan      if (GET_CODE (x) != REG || ! CR_REGNO_P (REGNO (x)))
9055132718Skan       output_operand_lossage ("invalid %%E value");
9056132718Skan      else
9057132718Skan       fprintf (file, "%d", 4 * (REGNO (x) - CR0_REGNO) + 1);
9058132718Skan      return;
9059132718Skan
906090075Sobrien    case 'D':
9061146895Skan      /* Like 'J' but get to the EQ bit.  */
9062132718Skan      if (GET_CODE (x) != REG)
9063132718Skan       abort ();
906490075Sobrien
9065146895Skan      /* Bit 1 is EQ bit.  */
9066146895Skan      i = 4 * (REGNO (x) - CR0_REGNO) + 2;
906790075Sobrien
9068132718Skan      /* If we want bit 31, write a shift count of zero, not 32.  */
9069132718Skan      fprintf (file, "%d", i == 31 ? 0 : i + 1);
907090075Sobrien      return;
907190075Sobrien
907290075Sobrien    case 'E':
907390075Sobrien      /* X is a CR register.  Print the number of the EQ bit of the CR */
907490075Sobrien      if (GET_CODE (x) != REG || ! CR_REGNO_P (REGNO (x)))
907590075Sobrien	output_operand_lossage ("invalid %%E value");
907690075Sobrien      else
907790075Sobrien	fprintf (file, "%d", 4 * (REGNO (x) - CR0_REGNO) + 2);
907890075Sobrien      return;
907990075Sobrien
908090075Sobrien    case 'f':
908190075Sobrien      /* X is a CR register.  Print the shift count needed to move it
908290075Sobrien	 to the high-order four bits.  */
908390075Sobrien      if (GET_CODE (x) != REG || ! CR_REGNO_P (REGNO (x)))
908490075Sobrien	output_operand_lossage ("invalid %%f value");
908590075Sobrien      else
908690075Sobrien	fprintf (file, "%d", 4 * (REGNO (x) - CR0_REGNO));
908790075Sobrien      return;
908890075Sobrien
908990075Sobrien    case 'F':
909090075Sobrien      /* Similar, but print the count for the rotate in the opposite
909190075Sobrien	 direction.  */
909290075Sobrien      if (GET_CODE (x) != REG || ! CR_REGNO_P (REGNO (x)))
909390075Sobrien	output_operand_lossage ("invalid %%F value");
909490075Sobrien      else
909590075Sobrien	fprintf (file, "%d", 32 - 4 * (REGNO (x) - CR0_REGNO));
909690075Sobrien      return;
909790075Sobrien
909890075Sobrien    case 'G':
909990075Sobrien      /* X is a constant integer.  If it is negative, print "m",
9100117395Skan	 otherwise print "z".  This is to make an aze or ame insn.  */
910190075Sobrien      if (GET_CODE (x) != CONST_INT)
910290075Sobrien	output_operand_lossage ("invalid %%G value");
910390075Sobrien      else if (INTVAL (x) >= 0)
910490075Sobrien	putc ('z', file);
910590075Sobrien      else
910690075Sobrien	putc ('m', file);
910790075Sobrien      return;
910890075Sobrien
910990075Sobrien    case 'h':
911090075Sobrien      /* If constant, output low-order five bits.  Otherwise, write
911190075Sobrien	 normally.  */
911290075Sobrien      if (INT_P (x))
911390075Sobrien	fprintf (file, HOST_WIDE_INT_PRINT_DEC, INT_LOWPART (x) & 31);
911490075Sobrien      else
911590075Sobrien	print_operand (file, x, 0);
911690075Sobrien      return;
911790075Sobrien
911890075Sobrien    case 'H':
911990075Sobrien      /* If constant, output low-order six bits.  Otherwise, write
912090075Sobrien	 normally.  */
912190075Sobrien      if (INT_P (x))
912290075Sobrien	fprintf (file, HOST_WIDE_INT_PRINT_DEC, INT_LOWPART (x) & 63);
912390075Sobrien      else
912490075Sobrien	print_operand (file, x, 0);
912590075Sobrien      return;
912690075Sobrien
912790075Sobrien    case 'I':
912890075Sobrien      /* Print `i' if this is a constant, else nothing.  */
912990075Sobrien      if (INT_P (x))
913090075Sobrien	putc ('i', file);
913190075Sobrien      return;
913290075Sobrien
913390075Sobrien    case 'j':
913490075Sobrien      /* Write the bit number in CCR for jump.  */
913590075Sobrien      i = ccr_bit (x, 0);
913690075Sobrien      if (i == -1)
913790075Sobrien	output_operand_lossage ("invalid %%j code");
913890075Sobrien      else
913990075Sobrien	fprintf (file, "%d", i);
914090075Sobrien      return;
914190075Sobrien
914290075Sobrien    case 'J':
914390075Sobrien      /* Similar, but add one for shift count in rlinm for scc and pass
914490075Sobrien	 scc flag to `ccr_bit'.  */
914590075Sobrien      i = ccr_bit (x, 1);
914690075Sobrien      if (i == -1)
914790075Sobrien	output_operand_lossage ("invalid %%J code");
914890075Sobrien      else
914990075Sobrien	/* If we want bit 31, write a shift count of zero, not 32.  */
915090075Sobrien	fprintf (file, "%d", i == 31 ? 0 : i + 1);
915190075Sobrien      return;
915290075Sobrien
915390075Sobrien    case 'k':
915490075Sobrien      /* X must be a constant.  Write the 1's complement of the
915590075Sobrien	 constant.  */
915690075Sobrien      if (! INT_P (x))
915790075Sobrien	output_operand_lossage ("invalid %%k value");
915890075Sobrien      else
915990075Sobrien	fprintf (file, HOST_WIDE_INT_PRINT_DEC, ~ INT_LOWPART (x));
916090075Sobrien      return;
916190075Sobrien
916290075Sobrien    case 'K':
916390075Sobrien      /* X must be a symbolic constant on ELF.  Write an
916490075Sobrien	 expression suitable for an 'addi' that adds in the low 16
916590075Sobrien	 bits of the MEM.  */
916690075Sobrien      if (GET_CODE (x) != CONST)
916790075Sobrien	{
916890075Sobrien	  print_operand_address (file, x);
916990075Sobrien	  fputs ("@l", file);
917090075Sobrien	}
917190075Sobrien      else
917290075Sobrien	{
917390075Sobrien	  if (GET_CODE (XEXP (x, 0)) != PLUS
917490075Sobrien	      || (GET_CODE (XEXP (XEXP (x, 0), 0)) != SYMBOL_REF
917590075Sobrien		  && GET_CODE (XEXP (XEXP (x, 0), 0)) != LABEL_REF)
917690075Sobrien	      || GET_CODE (XEXP (XEXP (x, 0), 1)) != CONST_INT)
917790075Sobrien	    output_operand_lossage ("invalid %%K value");
917890075Sobrien	  print_operand_address (file, XEXP (XEXP (x, 0), 0));
917990075Sobrien	  fputs ("@l", file);
9180117395Skan	  /* For GNU as, there must be a non-alphanumeric character
9181117395Skan	     between 'l' and the number.  The '-' is added by
9182117395Skan	     print_operand() already.  */
9183117395Skan	  if (INTVAL (XEXP (XEXP (x, 0), 1)) >= 0)
9184117395Skan	    fputs ("+", file);
918590075Sobrien	  print_operand (file, XEXP (XEXP (x, 0), 1), 0);
918690075Sobrien	}
918790075Sobrien      return;
918890075Sobrien
918990075Sobrien      /* %l is output_asm_label.  */
919090075Sobrien
919190075Sobrien    case 'L':
919290075Sobrien      /* Write second word of DImode or DFmode reference.  Works on register
919390075Sobrien	 or non-indexed memory only.  */
919490075Sobrien      if (GET_CODE (x) == REG)
919590075Sobrien	fprintf (file, "%s", reg_names[REGNO (x) + 1]);
919690075Sobrien      else if (GET_CODE (x) == MEM)
919790075Sobrien	{
919890075Sobrien	  /* Handle possible auto-increment.  Since it is pre-increment and
919990075Sobrien	     we have already done it, we can just use an offset of word.  */
920090075Sobrien	  if (GET_CODE (XEXP (x, 0)) == PRE_INC
920190075Sobrien	      || GET_CODE (XEXP (x, 0)) == PRE_DEC)
920290075Sobrien	    output_address (plus_constant (XEXP (XEXP (x, 0), 0),
920390075Sobrien					   UNITS_PER_WORD));
920490075Sobrien	  else
920590075Sobrien	    output_address (XEXP (adjust_address_nv (x, SImode,
920690075Sobrien						     UNITS_PER_WORD),
920790075Sobrien				  0));
920890075Sobrien
920990075Sobrien	  if (small_data_operand (x, GET_MODE (x)))
921090075Sobrien	    fprintf (file, "@%s(%s)", SMALL_DATA_RELOC,
921190075Sobrien		     reg_names[SMALL_DATA_REG]);
921290075Sobrien	}
921390075Sobrien      return;
921490075Sobrien
921590075Sobrien    case 'm':
921690075Sobrien      /* MB value for a mask operand.  */
921796263Sobrien      if (! mask_operand (x, SImode))
921890075Sobrien	output_operand_lossage ("invalid %%m value");
921990075Sobrien
9220117395Skan      fprintf (file, "%d", extract_MB (x));
922190075Sobrien      return;
922290075Sobrien
922390075Sobrien    case 'M':
922490075Sobrien      /* ME value for a mask operand.  */
922596263Sobrien      if (! mask_operand (x, SImode))
922690075Sobrien	output_operand_lossage ("invalid %%M value");
922790075Sobrien
9228117395Skan      fprintf (file, "%d", extract_ME (x));
922990075Sobrien      return;
923090075Sobrien
923190075Sobrien      /* %n outputs the negative of its operand.  */
923290075Sobrien
923390075Sobrien    case 'N':
923490075Sobrien      /* Write the number of elements in the vector times 4.  */
923590075Sobrien      if (GET_CODE (x) != PARALLEL)
923690075Sobrien	output_operand_lossage ("invalid %%N value");
923790075Sobrien      else
923890075Sobrien	fprintf (file, "%d", XVECLEN (x, 0) * 4);
923990075Sobrien      return;
924090075Sobrien
924190075Sobrien    case 'O':
924290075Sobrien      /* Similar, but subtract 1 first.  */
924390075Sobrien      if (GET_CODE (x) != PARALLEL)
924490075Sobrien	output_operand_lossage ("invalid %%O value");
924590075Sobrien      else
924690075Sobrien	fprintf (file, "%d", (XVECLEN (x, 0) - 1) * 4);
924790075Sobrien      return;
924890075Sobrien
924990075Sobrien    case 'p':
925090075Sobrien      /* X is a CONST_INT that is a power of two.  Output the logarithm.  */
925190075Sobrien      if (! INT_P (x)
925290075Sobrien	  || INT_LOWPART (x) < 0
925390075Sobrien	  || (i = exact_log2 (INT_LOWPART (x))) < 0)
925490075Sobrien	output_operand_lossage ("invalid %%p value");
925590075Sobrien      else
925690075Sobrien	fprintf (file, "%d", i);
925790075Sobrien      return;
925890075Sobrien
925990075Sobrien    case 'P':
926090075Sobrien      /* The operand must be an indirect memory reference.  The result
9261146895Skan	 is the register name.  */
926290075Sobrien      if (GET_CODE (x) != MEM || GET_CODE (XEXP (x, 0)) != REG
926390075Sobrien	  || REGNO (XEXP (x, 0)) >= 32)
926490075Sobrien	output_operand_lossage ("invalid %%P value");
926590075Sobrien      else
9266146895Skan	fprintf (file, "%s", reg_names[REGNO (XEXP (x, 0))]);
926790075Sobrien      return;
926890075Sobrien
926990075Sobrien    case 'q':
927090075Sobrien      /* This outputs the logical code corresponding to a boolean
927190075Sobrien	 expression.  The expression may have one or both operands
927290075Sobrien	 negated (if one, only the first one).  For condition register
927390075Sobrien         logical operations, it will also treat the negated
927490075Sobrien         CR codes as NOTs, but not handle NOTs of them.  */
927590075Sobrien      {
927690075Sobrien	const char *const *t = 0;
927790075Sobrien	const char *s;
927890075Sobrien	enum rtx_code code = GET_CODE (x);
927990075Sobrien	static const char * const tbl[3][3] = {
928090075Sobrien	  { "and", "andc", "nor" },
928190075Sobrien	  { "or", "orc", "nand" },
928290075Sobrien	  { "xor", "eqv", "xor" } };
928390075Sobrien
928490075Sobrien	if (code == AND)
928590075Sobrien	  t = tbl[0];
928690075Sobrien	else if (code == IOR)
928790075Sobrien	  t = tbl[1];
928890075Sobrien	else if (code == XOR)
928990075Sobrien	  t = tbl[2];
929090075Sobrien	else
929190075Sobrien	  output_operand_lossage ("invalid %%q value");
929290075Sobrien
929390075Sobrien	if (GET_CODE (XEXP (x, 0)) != NOT)
929490075Sobrien	  s = t[0];
929590075Sobrien	else
929690075Sobrien	  {
929790075Sobrien	    if (GET_CODE (XEXP (x, 1)) == NOT)
929890075Sobrien	      s = t[2];
929990075Sobrien	    else
930090075Sobrien	      s = t[1];
930190075Sobrien	  }
930290075Sobrien
930390075Sobrien	fputs (s, file);
930490075Sobrien      }
930590075Sobrien      return;
930690075Sobrien
9307132718Skan    case 'Q':
9308132718Skan      if (TARGET_MFCRF)
9309132718Skan	fputc (',',file);
9310132718Skan        /* FALLTHRU */
9311132718Skan      else
9312132718Skan	return;
9313132718Skan
931490075Sobrien    case 'R':
931590075Sobrien      /* X is a CR register.  Print the mask for `mtcrf'.  */
931690075Sobrien      if (GET_CODE (x) != REG || ! CR_REGNO_P (REGNO (x)))
931790075Sobrien	output_operand_lossage ("invalid %%R value");
931890075Sobrien      else
931990075Sobrien	fprintf (file, "%d", 128 >> (REGNO (x) - CR0_REGNO));
932090075Sobrien      return;
932190075Sobrien
932290075Sobrien    case 's':
932390075Sobrien      /* Low 5 bits of 32 - value */
932490075Sobrien      if (! INT_P (x))
932590075Sobrien	output_operand_lossage ("invalid %%s value");
932690075Sobrien      else
932790075Sobrien	fprintf (file, HOST_WIDE_INT_PRINT_DEC, (32 - INT_LOWPART (x)) & 31);
932890075Sobrien      return;
932990075Sobrien
933090075Sobrien    case 'S':
9331117395Skan      /* PowerPC64 mask position.  All 0's is excluded.
933290075Sobrien	 CONST_INT 32-bit mask is considered sign-extended so any
933390075Sobrien	 transition must occur within the CONST_INT, not on the boundary.  */
933496263Sobrien      if (! mask64_operand (x, DImode))
933590075Sobrien	output_operand_lossage ("invalid %%S value");
933690075Sobrien
9337117395Skan      uval = INT_LOWPART (x);
933890075Sobrien
9339117395Skan      if (uval & 1)	/* Clear Left */
934090075Sobrien	{
9341132718Skan#if HOST_BITS_PER_WIDE_INT > 64
9342132718Skan	  uval &= ((unsigned HOST_WIDE_INT) 1 << 64) - 1;
9343132718Skan#endif
9344117395Skan	  i = 64;
934590075Sobrien	}
9346117395Skan      else		/* Clear Right */
934790075Sobrien	{
9348117395Skan	  uval = ~uval;
9349132718Skan#if HOST_BITS_PER_WIDE_INT > 64
9350132718Skan	  uval &= ((unsigned HOST_WIDE_INT) 1 << 64) - 1;
9351132718Skan#endif
9352117395Skan	  i = 63;
9353117395Skan	}
9354117395Skan      while (uval != 0)
9355117395Skan	--i, uval >>= 1;
9356117395Skan      if (i < 0)
9357117395Skan	abort ();
9358117395Skan      fprintf (file, "%d", i);
9359117395Skan      return;
936090075Sobrien
9361117395Skan    case 't':
9362117395Skan      /* Like 'J' but get to the OVERFLOW/UNORDERED bit.  */
9363117395Skan      if (GET_CODE (x) != REG || GET_MODE (x) != CCmode)
9364117395Skan	abort ();
936590075Sobrien
9366117395Skan      /* Bit 3 is OV bit.  */
9367117395Skan      i = 4 * (REGNO (x) - CR0_REGNO) + 3;
936890075Sobrien
9369117395Skan      /* If we want bit 31, write a shift count of zero, not 32.  */
9370117395Skan      fprintf (file, "%d", i == 31 ? 0 : i + 1);
9371117395Skan      return;
937290075Sobrien
937390075Sobrien    case 'T':
937490075Sobrien      /* Print the symbolic name of a branch target register.  */
937590075Sobrien      if (GET_CODE (x) != REG || (REGNO (x) != LINK_REGISTER_REGNUM
937690075Sobrien				  && REGNO (x) != COUNT_REGISTER_REGNUM))
937790075Sobrien	output_operand_lossage ("invalid %%T value");
937890075Sobrien      else if (REGNO (x) == LINK_REGISTER_REGNUM)
937990075Sobrien	fputs (TARGET_NEW_MNEMONICS ? "lr" : "r", file);
938090075Sobrien      else
938190075Sobrien	fputs ("ctr", file);
938290075Sobrien      return;
938390075Sobrien
938490075Sobrien    case 'u':
938590075Sobrien      /* High-order 16 bits of constant for use in unsigned operand.  */
938690075Sobrien      if (! INT_P (x))
938790075Sobrien	output_operand_lossage ("invalid %%u value");
938890075Sobrien      else
938990075Sobrien	fprintf (file, HOST_WIDE_INT_PRINT_HEX,
939090075Sobrien		 (INT_LOWPART (x) >> 16) & 0xffff);
939190075Sobrien      return;
939290075Sobrien
939390075Sobrien    case 'v':
939490075Sobrien      /* High-order 16 bits of constant for use in signed operand.  */
939590075Sobrien      if (! INT_P (x))
939690075Sobrien	output_operand_lossage ("invalid %%v value");
939790075Sobrien      else
939890075Sobrien	fprintf (file, HOST_WIDE_INT_PRINT_HEX,
939990075Sobrien		 (INT_LOWPART (x) >> 16) & 0xffff);
940090075Sobrien      return;
940190075Sobrien
940290075Sobrien    case 'U':
940390075Sobrien      /* Print `u' if this has an auto-increment or auto-decrement.  */
940490075Sobrien      if (GET_CODE (x) == MEM
940590075Sobrien	  && (GET_CODE (XEXP (x, 0)) == PRE_INC
940690075Sobrien	      || GET_CODE (XEXP (x, 0)) == PRE_DEC))
940790075Sobrien	putc ('u', file);
940890075Sobrien      return;
940990075Sobrien
941090075Sobrien    case 'V':
941190075Sobrien      /* Print the trap code for this operand.  */
941290075Sobrien      switch (GET_CODE (x))
941390075Sobrien	{
941490075Sobrien	case EQ:
941590075Sobrien	  fputs ("eq", file);   /* 4 */
941690075Sobrien	  break;
941790075Sobrien	case NE:
941890075Sobrien	  fputs ("ne", file);   /* 24 */
941990075Sobrien	  break;
942090075Sobrien	case LT:
942190075Sobrien	  fputs ("lt", file);   /* 16 */
942290075Sobrien	  break;
942390075Sobrien	case LE:
942490075Sobrien	  fputs ("le", file);   /* 20 */
942590075Sobrien	  break;
942690075Sobrien	case GT:
942790075Sobrien	  fputs ("gt", file);   /* 8 */
942890075Sobrien	  break;
942990075Sobrien	case GE:
943090075Sobrien	  fputs ("ge", file);   /* 12 */
943190075Sobrien	  break;
943290075Sobrien	case LTU:
943390075Sobrien	  fputs ("llt", file);  /* 2 */
943490075Sobrien	  break;
943590075Sobrien	case LEU:
943690075Sobrien	  fputs ("lle", file);  /* 6 */
943790075Sobrien	  break;
943890075Sobrien	case GTU:
943990075Sobrien	  fputs ("lgt", file);  /* 1 */
944090075Sobrien	  break;
944190075Sobrien	case GEU:
944290075Sobrien	  fputs ("lge", file);  /* 5 */
944390075Sobrien	  break;
944490075Sobrien	default:
944590075Sobrien	  abort ();
944690075Sobrien	}
944790075Sobrien      break;
944890075Sobrien
944990075Sobrien    case 'w':
945090075Sobrien      /* If constant, low-order 16 bits of constant, signed.  Otherwise, write
945190075Sobrien	 normally.  */
945290075Sobrien      if (INT_P (x))
945390075Sobrien	fprintf (file, HOST_WIDE_INT_PRINT_DEC,
945490075Sobrien		 ((INT_LOWPART (x) & 0xffff) ^ 0x8000) - 0x8000);
945590075Sobrien      else
945690075Sobrien	print_operand (file, x, 0);
945790075Sobrien      return;
945890075Sobrien
945990075Sobrien    case 'W':
946090075Sobrien      /* MB value for a PowerPC64 rldic operand.  */
946190075Sobrien      val = (GET_CODE (x) == CONST_INT
946290075Sobrien	     ? INTVAL (x) : CONST_DOUBLE_HIGH (x));
946390075Sobrien
946490075Sobrien      if (val < 0)
946590075Sobrien	i = -1;
946690075Sobrien      else
946790075Sobrien	for (i = 0; i < HOST_BITS_PER_WIDE_INT; i++)
946890075Sobrien	  if ((val <<= 1) < 0)
946990075Sobrien	    break;
947090075Sobrien
947190075Sobrien#if HOST_BITS_PER_WIDE_INT == 32
947290075Sobrien      if (GET_CODE (x) == CONST_INT && i >= 0)
947390075Sobrien	i += 32;  /* zero-extend high-part was all 0's */
947490075Sobrien      else if (GET_CODE (x) == CONST_DOUBLE && i == 32)
947590075Sobrien	{
947690075Sobrien	  val = CONST_DOUBLE_LOW (x);
947790075Sobrien
947890075Sobrien	  if (val == 0)
947990075Sobrien	    abort ();
948090075Sobrien	  else if (val < 0)
948190075Sobrien	    --i;
948290075Sobrien	  else
948390075Sobrien	    for ( ; i < 64; i++)
948490075Sobrien	      if ((val <<= 1) < 0)
948590075Sobrien		break;
948690075Sobrien	}
948790075Sobrien#endif
948890075Sobrien
948990075Sobrien      fprintf (file, "%d", i + 1);
949090075Sobrien      return;
949190075Sobrien
949290075Sobrien    case 'X':
949390075Sobrien      if (GET_CODE (x) == MEM
9494132718Skan	  && legitimate_indexed_address_p (XEXP (x, 0), 0))
949590075Sobrien	putc ('x', file);
949690075Sobrien      return;
949790075Sobrien
949890075Sobrien    case 'Y':
949990075Sobrien      /* Like 'L', for third word of TImode  */
950090075Sobrien      if (GET_CODE (x) == REG)
950190075Sobrien	fprintf (file, "%s", reg_names[REGNO (x) + 2]);
950290075Sobrien      else if (GET_CODE (x) == MEM)
950390075Sobrien	{
950490075Sobrien	  if (GET_CODE (XEXP (x, 0)) == PRE_INC
950590075Sobrien	      || GET_CODE (XEXP (x, 0)) == PRE_DEC)
950690075Sobrien	    output_address (plus_constant (XEXP (XEXP (x, 0), 0), 8));
950790075Sobrien	  else
950890075Sobrien	    output_address (XEXP (adjust_address_nv (x, SImode, 8), 0));
950990075Sobrien	  if (small_data_operand (x, GET_MODE (x)))
951090075Sobrien	    fprintf (file, "@%s(%s)", SMALL_DATA_RELOC,
951190075Sobrien		     reg_names[SMALL_DATA_REG]);
951290075Sobrien	}
951390075Sobrien      return;
951490075Sobrien
951590075Sobrien    case 'z':
951690075Sobrien      /* X is a SYMBOL_REF.  Write out the name preceded by a
951790075Sobrien	 period and without any trailing data in brackets.  Used for function
951890075Sobrien	 names.  If we are configured for System V (or the embedded ABI) on
951990075Sobrien	 the PowerPC, do not emit the period, since those systems do not use
952090075Sobrien	 TOCs and the like.  */
952190075Sobrien      if (GET_CODE (x) != SYMBOL_REF)
952290075Sobrien	abort ();
952390075Sobrien
952490075Sobrien      if (XSTR (x, 0)[0] != '.')
952590075Sobrien	{
952690075Sobrien	  switch (DEFAULT_ABI)
952790075Sobrien	    {
952890075Sobrien	    default:
952990075Sobrien	      abort ();
953090075Sobrien
953190075Sobrien	    case ABI_AIX:
953290075Sobrien	      putc ('.', file);
953390075Sobrien	      break;
953490075Sobrien
953590075Sobrien	    case ABI_V4:
953690075Sobrien	    case ABI_DARWIN:
953790075Sobrien	      break;
953890075Sobrien	    }
953990075Sobrien	}
9540132718Skan      if (TARGET_AIX)
9541132718Skan	RS6000_OUTPUT_BASENAME (file, XSTR (x, 0));
9542132718Skan      else
9543132718Skan	assemble_name (file, XSTR (x, 0));
954490075Sobrien      return;
954590075Sobrien
954690075Sobrien    case 'Z':
954790075Sobrien      /* Like 'L', for last word of TImode.  */
954890075Sobrien      if (GET_CODE (x) == REG)
954990075Sobrien	fprintf (file, "%s", reg_names[REGNO (x) + 3]);
955090075Sobrien      else if (GET_CODE (x) == MEM)
955190075Sobrien	{
955290075Sobrien	  if (GET_CODE (XEXP (x, 0)) == PRE_INC
955390075Sobrien	      || GET_CODE (XEXP (x, 0)) == PRE_DEC)
955490075Sobrien	    output_address (plus_constant (XEXP (XEXP (x, 0), 0), 12));
955590075Sobrien	  else
955690075Sobrien	    output_address (XEXP (adjust_address_nv (x, SImode, 12), 0));
955790075Sobrien	  if (small_data_operand (x, GET_MODE (x)))
955890075Sobrien	    fprintf (file, "@%s(%s)", SMALL_DATA_RELOC,
955990075Sobrien		     reg_names[SMALL_DATA_REG]);
956090075Sobrien	}
956190075Sobrien      return;
956290075Sobrien
9563117395Skan      /* Print AltiVec or SPE memory operand.  */
956490075Sobrien    case 'y':
956590075Sobrien      {
956690075Sobrien	rtx tmp;
956790075Sobrien
956890075Sobrien	if (GET_CODE (x) != MEM)
956990075Sobrien	  abort ();
957090075Sobrien
957190075Sobrien	tmp = XEXP (x, 0);
957290075Sobrien
9573132718Skan	if (TARGET_E500)
9574117395Skan	  {
9575117395Skan	    /* Handle [reg].  */
9576117395Skan	    if (GET_CODE (tmp) == REG)
9577117395Skan	      {
9578117395Skan		fprintf (file, "0(%s)", reg_names[REGNO (tmp)]);
9579117395Skan		break;
9580117395Skan	      }
9581117395Skan	    /* Handle [reg+UIMM].  */
9582117395Skan	    else if (GET_CODE (tmp) == PLUS &&
9583117395Skan		     GET_CODE (XEXP (tmp, 1)) == CONST_INT)
9584117395Skan	      {
9585117395Skan		int x;
9586117395Skan
9587117395Skan		if (GET_CODE (XEXP (tmp, 0)) != REG)
9588117395Skan		  abort ();
9589117395Skan
9590117395Skan		x = INTVAL (XEXP (tmp, 1));
9591117395Skan		fprintf (file, "%d(%s)", x, reg_names[REGNO (XEXP (tmp, 0))]);
9592117395Skan		break;
9593117395Skan	      }
9594117395Skan
9595117395Skan	    /* Fall through.  Must be [reg+reg].  */
9596117395Skan	  }
959790075Sobrien	if (GET_CODE (tmp) == REG)
959890075Sobrien	  fprintf (file, "0,%s", reg_names[REGNO (tmp)]);
959990075Sobrien	else if (GET_CODE (tmp) == PLUS && GET_CODE (XEXP (tmp, 1)) == REG)
960090075Sobrien	  {
960190075Sobrien	    if (REGNO (XEXP (tmp, 0)) == 0)
960290075Sobrien	      fprintf (file, "%s,%s", reg_names[ REGNO (XEXP (tmp, 1)) ],
960390075Sobrien		       reg_names[ REGNO (XEXP (tmp, 0)) ]);
960490075Sobrien	    else
960590075Sobrien	      fprintf (file, "%s,%s", reg_names[ REGNO (XEXP (tmp, 0)) ],
960690075Sobrien		       reg_names[ REGNO (XEXP (tmp, 1)) ]);
960790075Sobrien	  }
960890075Sobrien	else
960990075Sobrien	  abort ();
961090075Sobrien	break;
961190075Sobrien      }
961290075Sobrien
961390075Sobrien    case 0:
961490075Sobrien      if (GET_CODE (x) == REG)
961590075Sobrien	fprintf (file, "%s", reg_names[REGNO (x)]);
961690075Sobrien      else if (GET_CODE (x) == MEM)
961790075Sobrien	{
961890075Sobrien	  /* We need to handle PRE_INC and PRE_DEC here, since we need to
961990075Sobrien	     know the width from the mode.  */
962090075Sobrien	  if (GET_CODE (XEXP (x, 0)) == PRE_INC)
962190075Sobrien	    fprintf (file, "%d(%s)", GET_MODE_SIZE (GET_MODE (x)),
962290075Sobrien		     reg_names[REGNO (XEXP (XEXP (x, 0), 0))]);
962390075Sobrien	  else if (GET_CODE (XEXP (x, 0)) == PRE_DEC)
962490075Sobrien	    fprintf (file, "%d(%s)", - GET_MODE_SIZE (GET_MODE (x)),
962590075Sobrien		     reg_names[REGNO (XEXP (XEXP (x, 0), 0))]);
962690075Sobrien	  else
962790075Sobrien	    output_address (XEXP (x, 0));
962890075Sobrien	}
962990075Sobrien      else
963090075Sobrien	output_addr_const (file, x);
963190075Sobrien      return;
963290075Sobrien
9633132718Skan    case '&':
9634132718Skan      assemble_name (file, rs6000_get_some_local_dynamic_name ());
9635132718Skan      return;
9636132718Skan
963790075Sobrien    default:
963890075Sobrien      output_operand_lossage ("invalid %%xn code");
963990075Sobrien    }
964090075Sobrien}
964190075Sobrien
964290075Sobrien/* Print the address of an operand.  */
964390075Sobrien
964490075Sobrienvoid
9645132718Skanprint_operand_address (FILE *file, rtx x)
964690075Sobrien{
964790075Sobrien  if (GET_CODE (x) == REG)
964890075Sobrien    fprintf (file, "0(%s)", reg_names[ REGNO (x) ]);
964990075Sobrien  else if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == CONST
965090075Sobrien	   || GET_CODE (x) == LABEL_REF)
965190075Sobrien    {
965290075Sobrien      output_addr_const (file, x);
965390075Sobrien      if (small_data_operand (x, GET_MODE (x)))
965490075Sobrien	fprintf (file, "@%s(%s)", SMALL_DATA_RELOC,
965590075Sobrien		 reg_names[SMALL_DATA_REG]);
965690075Sobrien      else if (TARGET_TOC)
965790075Sobrien	abort ();
965890075Sobrien    }
965990075Sobrien  else if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == REG)
966090075Sobrien    {
966190075Sobrien      if (REGNO (XEXP (x, 0)) == 0)
966290075Sobrien	fprintf (file, "%s,%s", reg_names[ REGNO (XEXP (x, 1)) ],
966390075Sobrien		 reg_names[ REGNO (XEXP (x, 0)) ]);
966490075Sobrien      else
966590075Sobrien	fprintf (file, "%s,%s", reg_names[ REGNO (XEXP (x, 0)) ],
966690075Sobrien		 reg_names[ REGNO (XEXP (x, 1)) ]);
966790075Sobrien    }
966890075Sobrien  else if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
9669132718Skan    fprintf (file, HOST_WIDE_INT_PRINT_DEC "(%s)",
9670132718Skan	     INTVAL (XEXP (x, 1)), reg_names[ REGNO (XEXP (x, 0)) ]);
967190075Sobrien#if TARGET_ELF
967290075Sobrien  else if (GET_CODE (x) == LO_SUM && GET_CODE (XEXP (x, 0)) == REG
967390075Sobrien           && CONSTANT_P (XEXP (x, 1)))
967490075Sobrien    {
967590075Sobrien      output_addr_const (file, XEXP (x, 1));
967690075Sobrien      fprintf (file, "@l(%s)", reg_names[ REGNO (XEXP (x, 0)) ]);
967790075Sobrien    }
967890075Sobrien#endif
967990075Sobrien#if TARGET_MACHO
968090075Sobrien  else if (GET_CODE (x) == LO_SUM && GET_CODE (XEXP (x, 0)) == REG
968190075Sobrien           && CONSTANT_P (XEXP (x, 1)))
968290075Sobrien    {
968390075Sobrien      fprintf (file, "lo16(");
968490075Sobrien      output_addr_const (file, XEXP (x, 1));
968590075Sobrien      fprintf (file, ")(%s)", reg_names[ REGNO (XEXP (x, 0)) ]);
968690075Sobrien    }
968790075Sobrien#endif
9688132718Skan  else if (legitimate_constant_pool_address_p (x))
968990075Sobrien    {
969090075Sobrien      if (TARGET_AIX && (!TARGET_ELF || !TARGET_MINIMAL_TOC))
969190075Sobrien	{
969290075Sobrien	  rtx contains_minus = XEXP (x, 1);
969390075Sobrien	  rtx minus, symref;
969490075Sobrien	  const char *name;
969590075Sobrien
969690075Sobrien	  /* Find the (minus (sym) (toc)) buried in X, and temporarily
969790075Sobrien	     turn it into (sym) for output_addr_const.  */
969890075Sobrien	  while (GET_CODE (XEXP (contains_minus, 0)) != MINUS)
969990075Sobrien	    contains_minus = XEXP (contains_minus, 0);
970090075Sobrien
970190075Sobrien	  minus = XEXP (contains_minus, 0);
970290075Sobrien	  symref = XEXP (minus, 0);
970390075Sobrien	  XEXP (contains_minus, 0) = symref;
970490075Sobrien	  if (TARGET_ELF)
970590075Sobrien	    {
970690075Sobrien	      char *newname;
970790075Sobrien
970890075Sobrien	      name = XSTR (symref, 0);
970990075Sobrien	      newname = alloca (strlen (name) + sizeof ("@toc"));
971090075Sobrien	      strcpy (newname, name);
971190075Sobrien	      strcat (newname, "@toc");
971290075Sobrien	      XSTR (symref, 0) = newname;
971390075Sobrien	    }
971490075Sobrien	  output_addr_const (file, XEXP (x, 1));
971590075Sobrien	  if (TARGET_ELF)
971690075Sobrien	    XSTR (symref, 0) = name;
971790075Sobrien	  XEXP (contains_minus, 0) = minus;
971890075Sobrien	}
971990075Sobrien      else
972090075Sobrien	output_addr_const (file, XEXP (x, 1));
972190075Sobrien
972290075Sobrien      fprintf (file, "(%s)", reg_names[REGNO (XEXP (x, 0))]);
972390075Sobrien    }
972490075Sobrien  else
972590075Sobrien    abort ();
972690075Sobrien}
972790075Sobrien
9728117395Skan/* Target hook for assembling integer objects.  The PowerPC version has
972990075Sobrien   to handle fixup entries for relocatable code if RELOCATABLE_NEEDS_FIXUP
973090075Sobrien   is defined.  It also needs to handle DI-mode objects on 64-bit
973190075Sobrien   targets.  */
973290075Sobrien
973390075Sobrienstatic bool
9734132718Skanrs6000_assemble_integer (rtx x, unsigned int size, int aligned_p)
973590075Sobrien{
973690075Sobrien#ifdef RELOCATABLE_NEEDS_FIXUP
973790075Sobrien  /* Special handling for SI values.  */
9738146895Skan  if (RELOCATABLE_NEEDS_FIXUP && size == 4 && aligned_p)
973990075Sobrien    {
9740132718Skan      extern int in_toc_section (void);
974190075Sobrien      static int recurse = 0;
974290075Sobrien
974390075Sobrien      /* For -mrelocatable, we mark all addresses that need to be fixed up
974490075Sobrien	 in the .fixup section.  */
974590075Sobrien      if (TARGET_RELOCATABLE
974690075Sobrien	  && !in_toc_section ()
974790075Sobrien	  && !in_text_section ()
974890075Sobrien	  && !recurse
974990075Sobrien	  && GET_CODE (x) != CONST_INT
975090075Sobrien	  && GET_CODE (x) != CONST_DOUBLE
975190075Sobrien	  && CONSTANT_P (x))
975290075Sobrien	{
975390075Sobrien	  char buf[256];
975490075Sobrien
975590075Sobrien	  recurse = 1;
975690075Sobrien	  ASM_GENERATE_INTERNAL_LABEL (buf, "LCP", fixuplabelno);
975790075Sobrien	  fixuplabelno++;
975890075Sobrien	  ASM_OUTPUT_LABEL (asm_out_file, buf);
975990075Sobrien	  fprintf (asm_out_file, "\t.long\t(");
976090075Sobrien	  output_addr_const (asm_out_file, x);
976190075Sobrien	  fprintf (asm_out_file, ")@fixup\n");
976290075Sobrien	  fprintf (asm_out_file, "\t.section\t\".fixup\",\"aw\"\n");
976390075Sobrien	  ASM_OUTPUT_ALIGN (asm_out_file, 2);
976490075Sobrien	  fprintf (asm_out_file, "\t.long\t");
976590075Sobrien	  assemble_name (asm_out_file, buf);
976690075Sobrien	  fprintf (asm_out_file, "\n\t.previous\n");
976790075Sobrien	  recurse = 0;
976890075Sobrien	  return true;
976990075Sobrien	}
977090075Sobrien      /* Remove initial .'s to turn a -mcall-aixdesc function
977190075Sobrien	 address into the address of the descriptor, not the function
977290075Sobrien	 itself.  */
977390075Sobrien      else if (GET_CODE (x) == SYMBOL_REF
977490075Sobrien	       && XSTR (x, 0)[0] == '.'
977590075Sobrien	       && DEFAULT_ABI == ABI_AIX)
977690075Sobrien	{
977790075Sobrien	  const char *name = XSTR (x, 0);
977890075Sobrien	  while (*name == '.')
977990075Sobrien	    name++;
978090075Sobrien
978190075Sobrien	  fprintf (asm_out_file, "\t.long\t%s\n", name);
978290075Sobrien	  return true;
978390075Sobrien	}
978490075Sobrien    }
978590075Sobrien#endif /* RELOCATABLE_NEEDS_FIXUP */
978690075Sobrien  return default_assemble_integer (x, size, aligned_p);
978790075Sobrien}
9788117395Skan
9789117395Skan#ifdef HAVE_GAS_HIDDEN
9790117395Skan/* Emit an assembler directive to set symbol visibility for DECL to
9791117395Skan   VISIBILITY_TYPE.  */
9792117395Skan
9793117395Skanstatic void
9794132718Skanrs6000_assemble_visibility (tree decl, int vis)
9795117395Skan{
9796117395Skan  /* Functions need to have their entry point symbol visibility set as
9797117395Skan     well as their descriptor symbol visibility.  */
9798117395Skan  if (DEFAULT_ABI == ABI_AIX && TREE_CODE (decl) == FUNCTION_DECL)
9799117395Skan    {
9800117395Skan      static const char * const visibility_types[] = {
9801117395Skan        NULL, "internal", "hidden", "protected"
9802117395Skan      };
9803117395Skan
9804117395Skan      const char *name, *type;
9805117395Skan
9806117395Skan      name = ((* targetm.strip_name_encoding)
9807117395Skan	      (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl))));
9808117395Skan      type = visibility_types[vis];
9809117395Skan
9810117395Skan      fprintf (asm_out_file, "\t.%s\t%s\n", type, name);
9811117395Skan      fprintf (asm_out_file, "\t.%s\t.%s\n", type, name);
9812117395Skan    }
9813117395Skan  else
9814117395Skan    default_assemble_visibility (decl, vis);
9815117395Skan}
9816117395Skan#endif
981790075Sobrien
981890075Sobrienenum rtx_code
9819132718Skanrs6000_reverse_condition (enum machine_mode mode, enum rtx_code code)
982090075Sobrien{
982190075Sobrien  /* Reversal of FP compares takes care -- an ordered compare
982290075Sobrien     becomes an unordered compare and vice versa.  */
9823132718Skan  if (mode == CCFPmode
9824132718Skan      && (!flag_finite_math_only
9825132718Skan	  || code == UNLT || code == UNLE || code == UNGT || code == UNGE
9826132718Skan	  || code == UNEQ || code == LTGT))
982790075Sobrien    return reverse_condition_maybe_unordered (code);
982890075Sobrien  else
982990075Sobrien    return reverse_condition (code);
983090075Sobrien}
983190075Sobrien
983290075Sobrien/* Generate a compare for CODE.  Return a brand-new rtx that
983390075Sobrien   represents the result of the compare.  */
983490075Sobrien
983590075Sobrienstatic rtx
9836132718Skanrs6000_generate_compare (enum rtx_code code)
983790075Sobrien{
983890075Sobrien  enum machine_mode comp_mode;
983990075Sobrien  rtx compare_result;
984090075Sobrien
984190075Sobrien  if (rs6000_compare_fp_p)
984290075Sobrien    comp_mode = CCFPmode;
984390075Sobrien  else if (code == GTU || code == LTU
984490075Sobrien	  || code == GEU || code == LEU)
984590075Sobrien    comp_mode = CCUNSmode;
984690075Sobrien  else
984790075Sobrien    comp_mode = CCmode;
984890075Sobrien
984990075Sobrien  /* First, the compare.  */
985090075Sobrien  compare_result = gen_reg_rtx (comp_mode);
9851117395Skan
9852117395Skan  /* SPE FP compare instructions on the GPRs.  Yuck!  */
9853132718Skan  if ((TARGET_E500 && !TARGET_FPRS && TARGET_HARD_FLOAT)
9854132718Skan      && rs6000_compare_fp_p)
9855117395Skan    {
9856117395Skan      rtx cmp, or1, or2, or_result, compare_result2;
9857117395Skan
9858132718Skan      /* Note: The E500 comparison instructions set the GT bit (x +
9859132718Skan        1), on success.  This explains the mess.  */
9860132718Skan
9861117395Skan      switch (code)
9862117395Skan	{
9863132718Skan       case EQ: case UNEQ: case NE: case LTGT:
9864132718Skan	  cmp = flag_finite_math_only
9865117395Skan	    ? gen_tstsfeq_gpr (compare_result, rs6000_compare_op0,
9866117395Skan			       rs6000_compare_op1)
9867117395Skan	    : gen_cmpsfeq_gpr (compare_result, rs6000_compare_op0,
9868117395Skan			       rs6000_compare_op1);
9869117395Skan	  break;
9870132718Skan       case GT: case GTU: case UNGT: case UNGE: case GE: case GEU:
9871132718Skan	  cmp = flag_finite_math_only
9872117395Skan	    ? gen_tstsfgt_gpr (compare_result, rs6000_compare_op0,
9873117395Skan			       rs6000_compare_op1)
9874117395Skan	    : gen_cmpsfgt_gpr (compare_result, rs6000_compare_op0,
9875117395Skan			       rs6000_compare_op1);
9876117395Skan	  break;
9877132718Skan       case LT: case LTU: case UNLT: case UNLE: case LE: case LEU:
9878132718Skan	  cmp = flag_finite_math_only
9879117395Skan	    ? gen_tstsflt_gpr (compare_result, rs6000_compare_op0,
9880117395Skan			       rs6000_compare_op1)
9881117395Skan	    : gen_cmpsflt_gpr (compare_result, rs6000_compare_op0,
9882117395Skan			       rs6000_compare_op1);
9883117395Skan	  break;
9884117395Skan	default:
9885117395Skan	  abort ();
9886117395Skan	}
9887117395Skan
9888117395Skan      /* Synthesize LE and GE from LT/GT || EQ.  */
9889117395Skan      if (code == LE || code == GE || code == LEU || code == GEU)
9890117395Skan	{
9891117395Skan	  emit_insn (cmp);
9892117395Skan
9893117395Skan	  switch (code)
9894117395Skan	    {
9895117395Skan	    case LE: code = LT; break;
9896117395Skan	    case GE: code = GT; break;
9897117395Skan	    case LEU: code = LT; break;
9898117395Skan	    case GEU: code = GT; break;
9899117395Skan	    default: abort ();
9900117395Skan	    }
9901117395Skan
9902117395Skan	  or1 = gen_reg_rtx (SImode);
9903117395Skan	  or2 = gen_reg_rtx (SImode);
9904117395Skan	  or_result = gen_reg_rtx (CCEQmode);
9905117395Skan	  compare_result2 = gen_reg_rtx (CCFPmode);
9906117395Skan
9907117395Skan	  /* Do the EQ.  */
9908132718Skan	  cmp = flag_finite_math_only
9909117395Skan	    ? gen_tstsfeq_gpr (compare_result2, rs6000_compare_op0,
9910117395Skan			       rs6000_compare_op1)
9911117395Skan	    : gen_cmpsfeq_gpr (compare_result2, rs6000_compare_op0,
9912117395Skan			       rs6000_compare_op1);
9913117395Skan	  emit_insn (cmp);
9914117395Skan
9915132718Skan	  or1 = gen_rtx_GT (SImode, compare_result, const0_rtx);
9916132718Skan	  or2 = gen_rtx_GT (SImode, compare_result2, const0_rtx);
9917117395Skan
9918117395Skan	  /* OR them together.  */
9919117395Skan	  cmp = gen_rtx_SET (VOIDmode, or_result,
9920117395Skan			     gen_rtx_COMPARE (CCEQmode,
9921117395Skan					      gen_rtx_IOR (SImode, or1, or2),
9922117395Skan					      const_true_rtx));
9923117395Skan	  compare_result = or_result;
9924117395Skan	  code = EQ;
9925117395Skan	}
9926117395Skan      else
9927117395Skan	{
9928117395Skan	  if (code == NE || code == LTGT)
9929117395Skan	    code = NE;
9930132718Skan         else
9931132718Skan           code = EQ;
9932117395Skan	}
9933117395Skan
9934117395Skan      emit_insn (cmp);
9935117395Skan    }
9936117395Skan  else
9937146895Skan    {
9938146895Skan      /* Generate XLC-compatible TFmode compare as PARALLEL with extra
9939146895Skan         CLOBBERs to match cmptf_internal2 pattern.  */
9940146895Skan      if (comp_mode == CCFPmode && TARGET_XL_COMPAT
9941146895Skan          && GET_MODE (rs6000_compare_op0) == TFmode
9942146895Skan          && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_DARWIN)
9943146895Skan          && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128)
9944146895Skan        emit_insn (gen_rtx_PARALLEL (VOIDmode,
9945146895Skan          gen_rtvec (9,
9946146895Skan		     gen_rtx_SET (VOIDmode,
9947146895Skan				  compare_result,
9948146895Skan				  gen_rtx_COMPARE (comp_mode,
9949146895Skan						   rs6000_compare_op0,
9950146895Skan						   rs6000_compare_op1)),
9951146895Skan		     gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
9952146895Skan		     gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
9953146895Skan		     gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
9954146895Skan		     gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
9955146895Skan		     gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
9956146895Skan		     gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
9957146895Skan		     gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
9958146895Skan		     gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)))));
9959146895Skan      else
9960146895Skan	emit_insn (gen_rtx_SET (VOIDmode, compare_result,
9961146895Skan				gen_rtx_COMPARE (comp_mode,
9962146895Skan						 rs6000_compare_op0,
9963146895Skan						 rs6000_compare_op1)));
9964146895Skan    }
996590075Sobrien
996690075Sobrien  /* Some kinds of FP comparisons need an OR operation;
9967132718Skan     under flag_finite_math_only we don't bother.  */
996890075Sobrien  if (rs6000_compare_fp_p
9969132718Skan      && ! flag_finite_math_only
9970132718Skan      && ! (TARGET_HARD_FLOAT && TARGET_E500 && !TARGET_FPRS)
997190075Sobrien      && (code == LE || code == GE
997290075Sobrien	  || code == UNEQ || code == LTGT
997390075Sobrien	  || code == UNGT || code == UNLT))
997490075Sobrien    {
997590075Sobrien      enum rtx_code or1, or2;
997690075Sobrien      rtx or1_rtx, or2_rtx, compare2_rtx;
997790075Sobrien      rtx or_result = gen_reg_rtx (CCEQmode);
997890075Sobrien
997990075Sobrien      switch (code)
998090075Sobrien	{
998190075Sobrien	case LE: or1 = LT;  or2 = EQ;  break;
998290075Sobrien	case GE: or1 = GT;  or2 = EQ;  break;
998390075Sobrien	case UNEQ: or1 = UNORDERED;  or2 = EQ;  break;
998490075Sobrien	case LTGT: or1 = LT;  or2 = GT;  break;
998590075Sobrien	case UNGT: or1 = UNORDERED;  or2 = GT;  break;
998690075Sobrien	case UNLT: or1 = UNORDERED;  or2 = LT;  break;
998790075Sobrien	default:  abort ();
998890075Sobrien	}
998990075Sobrien      validate_condition_mode (or1, comp_mode);
999090075Sobrien      validate_condition_mode (or2, comp_mode);
999190075Sobrien      or1_rtx = gen_rtx (or1, SImode, compare_result, const0_rtx);
999290075Sobrien      or2_rtx = gen_rtx (or2, SImode, compare_result, const0_rtx);
999390075Sobrien      compare2_rtx = gen_rtx_COMPARE (CCEQmode,
999490075Sobrien				      gen_rtx_IOR (SImode, or1_rtx, or2_rtx),
999590075Sobrien				      const_true_rtx);
999690075Sobrien      emit_insn (gen_rtx_SET (VOIDmode, or_result, compare2_rtx));
999790075Sobrien
999890075Sobrien      compare_result = or_result;
999990075Sobrien      code = EQ;
1000090075Sobrien    }
1000190075Sobrien
1000290075Sobrien  validate_condition_mode (code, GET_MODE (compare_result));
1000390075Sobrien
1000490075Sobrien  return gen_rtx (code, VOIDmode, compare_result, const0_rtx);
1000590075Sobrien}
1000690075Sobrien
1000790075Sobrien
1000890075Sobrien/* Emit the RTL for an sCOND pattern.  */
1000990075Sobrien
1001090075Sobrienvoid
10011132718Skanrs6000_emit_sCOND (enum rtx_code code, rtx result)
1001290075Sobrien{
1001390075Sobrien  rtx condition_rtx;
1001490075Sobrien  enum machine_mode op_mode;
10015132718Skan  enum rtx_code cond_code;
1001690075Sobrien
1001790075Sobrien  condition_rtx = rs6000_generate_compare (code);
10018132718Skan  cond_code = GET_CODE (condition_rtx);
1001990075Sobrien
10020132718Skan  if (TARGET_E500 && rs6000_compare_fp_p
10021132718Skan      && !TARGET_FPRS && TARGET_HARD_FLOAT)
10022132718Skan    {
10023132718Skan      rtx t;
10024132718Skan
10025132718Skan      PUT_MODE (condition_rtx, SImode);
10026132718Skan      t = XEXP (condition_rtx, 0);
10027132718Skan
10028132718Skan      if (cond_code != NE && cond_code != EQ)
10029132718Skan       abort ();
10030132718Skan
10031132718Skan      if (cond_code == NE)
10032146895Skan       emit_insn (gen_e500_flip_eq_bit (t, t));
10033132718Skan
10034146895Skan      emit_insn (gen_move_from_CR_eq_bit (result, t));
10035132718Skan      return;
10036132718Skan    }
10037132718Skan
10038132718Skan  if (cond_code == NE
10039132718Skan      || cond_code == GE || cond_code == LE
10040132718Skan      || cond_code == GEU || cond_code == LEU
10041132718Skan      || cond_code == ORDERED || cond_code == UNGE || cond_code == UNLE)
10042132718Skan    {
10043132718Skan      rtx not_result = gen_reg_rtx (CCEQmode);
10044132718Skan      rtx not_op, rev_cond_rtx;
10045132718Skan      enum machine_mode cc_mode;
10046132718Skan
10047132718Skan      cc_mode = GET_MODE (XEXP (condition_rtx, 0));
10048132718Skan
10049132718Skan      rev_cond_rtx = gen_rtx (rs6000_reverse_condition (cc_mode, cond_code),
10050132718Skan			      SImode, XEXP (condition_rtx, 0), const0_rtx);
10051132718Skan      not_op = gen_rtx_COMPARE (CCEQmode, rev_cond_rtx, const0_rtx);
10052132718Skan      emit_insn (gen_rtx_SET (VOIDmode, not_result, not_op));
10053132718Skan      condition_rtx = gen_rtx_EQ (VOIDmode, not_result, const0_rtx);
10054132718Skan    }
10055132718Skan
1005690075Sobrien  op_mode = GET_MODE (rs6000_compare_op0);
1005790075Sobrien  if (op_mode == VOIDmode)
1005890075Sobrien    op_mode = GET_MODE (rs6000_compare_op1);
1005990075Sobrien
1006090075Sobrien  if (TARGET_POWERPC64 && (op_mode == DImode || rs6000_compare_fp_p))
1006190075Sobrien    {
1006290075Sobrien      PUT_MODE (condition_rtx, DImode);
1006390075Sobrien      convert_move (result, condition_rtx, 0);
1006490075Sobrien    }
1006590075Sobrien  else
1006690075Sobrien    {
1006790075Sobrien      PUT_MODE (condition_rtx, SImode);
1006890075Sobrien      emit_insn (gen_rtx_SET (VOIDmode, result, condition_rtx));
1006990075Sobrien    }
1007090075Sobrien}
1007190075Sobrien
1007290075Sobrien/* Emit a branch of kind CODE to location LOC.  */
1007390075Sobrien
1007490075Sobrienvoid
10075132718Skanrs6000_emit_cbranch (enum rtx_code code, rtx loc)
1007690075Sobrien{
1007790075Sobrien  rtx condition_rtx, loc_ref;
1007890075Sobrien
1007990075Sobrien  condition_rtx = rs6000_generate_compare (code);
1008090075Sobrien  loc_ref = gen_rtx_LABEL_REF (VOIDmode, loc);
1008190075Sobrien  emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx,
1008290075Sobrien			       gen_rtx_IF_THEN_ELSE (VOIDmode, condition_rtx,
1008390075Sobrien						     loc_ref, pc_rtx)));
1008490075Sobrien}
1008590075Sobrien
1008690075Sobrien/* Return the string to output a conditional branch to LABEL, which is
1008790075Sobrien   the operand number of the label, or -1 if the branch is really a
1008890075Sobrien   conditional return.
1008990075Sobrien
1009090075Sobrien   OP is the conditional expression.  XEXP (OP, 0) is assumed to be a
1009190075Sobrien   condition code register and its mode specifies what kind of
1009290075Sobrien   comparison we made.
1009390075Sobrien
10094117395Skan   REVERSED is nonzero if we should reverse the sense of the comparison.
1009590075Sobrien
1009690075Sobrien   INSN is the insn.  */
1009790075Sobrien
1009890075Sobrienchar *
10099132718Skanoutput_cbranch (rtx op, const char *label, int reversed, rtx insn)
1010090075Sobrien{
1010190075Sobrien  static char string[64];
1010290075Sobrien  enum rtx_code code = GET_CODE (op);
1010390075Sobrien  rtx cc_reg = XEXP (op, 0);
1010490075Sobrien  enum machine_mode mode = GET_MODE (cc_reg);
1010590075Sobrien  int cc_regno = REGNO (cc_reg) - CR0_REGNO;
1010690075Sobrien  int need_longbranch = label != NULL && get_attr_length (insn) == 8;
1010790075Sobrien  int really_reversed = reversed ^ need_longbranch;
1010890075Sobrien  char *s = string;
1010990075Sobrien  const char *ccode;
1011090075Sobrien  const char *pred;
1011190075Sobrien  rtx note;
1011290075Sobrien
1011390075Sobrien  validate_condition_mode (code, mode);
1011490075Sobrien
1011590075Sobrien  /* Work out which way this really branches.  We could use
1011690075Sobrien     reverse_condition_maybe_unordered here always but this
1011790075Sobrien     makes the resulting assembler clearer.  */
1011890075Sobrien  if (really_reversed)
10119107590Sobrien    {
10120107590Sobrien      /* Reversal of FP compares takes care -- an ordered compare
10121107590Sobrien	 becomes an unordered compare and vice versa.  */
10122107590Sobrien      if (mode == CCFPmode)
10123107590Sobrien	code = reverse_condition_maybe_unordered (code);
10124107590Sobrien      else
10125107590Sobrien	code = reverse_condition (code);
10126107590Sobrien    }
1012790075Sobrien
10128132718Skan  if ((TARGET_E500 && !TARGET_FPRS && TARGET_HARD_FLOAT) && mode == CCFPmode)
10129117395Skan    {
10130117395Skan      /* The efscmp/tst* instructions twiddle bit 2, which maps nicely
10131117395Skan	 to the GT bit.  */
10132117395Skan      if (code == EQ)
10133117395Skan	/* Opposite of GT.  */
10134132718Skan	code = GT;
10135117395Skan      else if (code == NE)
10136132718Skan       code = UNLE;
10137117395Skan      else
10138117395Skan	abort ();
10139117395Skan    }
10140117395Skan
1014190075Sobrien  switch (code)
1014290075Sobrien    {
1014390075Sobrien      /* Not all of these are actually distinct opcodes, but
1014490075Sobrien	 we distinguish them for clarity of the resulting assembler.  */
1014590075Sobrien    case NE: case LTGT:
1014690075Sobrien      ccode = "ne"; break;
1014790075Sobrien    case EQ: case UNEQ:
1014890075Sobrien      ccode = "eq"; break;
1014990075Sobrien    case GE: case GEU:
1015090075Sobrien      ccode = "ge"; break;
1015190075Sobrien    case GT: case GTU: case UNGT:
1015290075Sobrien      ccode = "gt"; break;
1015390075Sobrien    case LE: case LEU:
1015490075Sobrien      ccode = "le"; break;
1015590075Sobrien    case LT: case LTU: case UNLT:
1015690075Sobrien      ccode = "lt"; break;
1015790075Sobrien    case UNORDERED: ccode = "un"; break;
1015890075Sobrien    case ORDERED: ccode = "nu"; break;
1015990075Sobrien    case UNGE: ccode = "nl"; break;
1016090075Sobrien    case UNLE: ccode = "ng"; break;
1016190075Sobrien    default:
1016290075Sobrien      abort ();
1016390075Sobrien    }
1016490075Sobrien
1016590075Sobrien  /* Maybe we have a guess as to how likely the branch is.
1016690075Sobrien     The old mnemonics don't have a way to specify this information.  */
10167117395Skan  pred = "";
1016890075Sobrien  note = find_reg_note (insn, REG_BR_PROB, NULL_RTX);
1016990075Sobrien  if (note != NULL_RTX)
1017090075Sobrien    {
1017190075Sobrien      /* PROB is the difference from 50%.  */
1017290075Sobrien      int prob = INTVAL (XEXP (note, 0)) - REG_BR_PROB_BASE / 2;
10173117395Skan
10174117395Skan      /* Only hint for highly probable/improbable branches on newer
10175117395Skan	 cpus as static prediction overrides processor dynamic
10176117395Skan	 prediction.  For older cpus we may as well always hint, but
10177117395Skan	 assume not taken for branches that are very close to 50% as a
10178117395Skan	 mispredicted taken branch is more expensive than a
10179117395Skan	 mispredicted not-taken branch.  */
10180132718Skan      if (rs6000_always_hint
10181117395Skan	  || abs (prob) > REG_BR_PROB_BASE / 100 * 48)
10182117395Skan	{
10183117395Skan	  if (abs (prob) > REG_BR_PROB_BASE / 20
10184117395Skan	      && ((prob > 0) ^ need_longbranch))
10185132718Skan              pred = "+";
10186117395Skan	  else
10187117395Skan	    pred = "-";
10188117395Skan	}
1018990075Sobrien    }
1019090075Sobrien
1019190075Sobrien  if (label == NULL)
1019290075Sobrien    s += sprintf (s, "{b%sr|b%slr%s} ", ccode, ccode, pred);
1019390075Sobrien  else
1019490075Sobrien    s += sprintf (s, "{b%s|b%s%s} ", ccode, ccode, pred);
1019590075Sobrien
1019690075Sobrien  /* We need to escape any '%' characters in the reg_names string.
10197132718Skan     Assume they'd only be the first character....  */
1019890075Sobrien  if (reg_names[cc_regno + CR0_REGNO][0] == '%')
1019990075Sobrien    *s++ = '%';
1020090075Sobrien  s += sprintf (s, "%s", reg_names[cc_regno + CR0_REGNO]);
1020190075Sobrien
1020290075Sobrien  if (label != NULL)
1020390075Sobrien    {
1020490075Sobrien      /* If the branch distance was too far, we may have to use an
1020590075Sobrien	 unconditional branch to go the distance.  */
1020690075Sobrien      if (need_longbranch)
1020790075Sobrien	s += sprintf (s, ",$+8\n\tb %s", label);
1020890075Sobrien      else
1020990075Sobrien	s += sprintf (s, ",%s", label);
1021090075Sobrien    }
1021190075Sobrien
1021290075Sobrien  return string;
1021390075Sobrien}
1021490075Sobrien
10215146895Skan/* Return the string to flip the EQ bit on a CR.  */
10216132718Skanchar *
10217146895Skanoutput_e500_flip_eq_bit (rtx dst, rtx src)
10218132718Skan{
10219132718Skan  static char string[64];
10220132718Skan  int a, b;
10221132718Skan
10222132718Skan  if (GET_CODE (dst) != REG || ! CR_REGNO_P (REGNO (dst))
10223132718Skan      || GET_CODE (src) != REG || ! CR_REGNO_P (REGNO (src)))
10224132718Skan    abort ();
10225132718Skan
10226146895Skan  /* EQ bit.  */
10227146895Skan  a = 4 * (REGNO (dst) - CR0_REGNO) + 2;
10228146895Skan  b = 4 * (REGNO (src) - CR0_REGNO) + 2;
10229132718Skan
10230132718Skan  sprintf (string, "crnot %d,%d", a, b);
10231132718Skan  return string;
10232132718Skan}
10233132718Skan
1023490075Sobrien/* Emit a conditional move: move TRUE_COND to DEST if OP of the
1023590075Sobrien   operands of the last comparison is nonzero/true, FALSE_COND if it
1023690075Sobrien   is zero/false.  Return 0 if the hardware has no such operation.  */
1023790075Sobrien
1023890075Sobrienint
10239132718Skanrs6000_emit_cmove (rtx dest, rtx op, rtx true_cond, rtx false_cond)
1024090075Sobrien{
1024190075Sobrien  enum rtx_code code = GET_CODE (op);
1024290075Sobrien  rtx op0 = rs6000_compare_op0;
1024390075Sobrien  rtx op1 = rs6000_compare_op1;
1024490075Sobrien  REAL_VALUE_TYPE c1;
1024596263Sobrien  enum machine_mode compare_mode = GET_MODE (op0);
1024696263Sobrien  enum machine_mode result_mode = GET_MODE (dest);
1024790075Sobrien  rtx temp;
1024890075Sobrien
10249132718Skan  /* These modes should always match.  */
10250117395Skan  if (GET_MODE (op1) != compare_mode
10251117395Skan      /* In the isel case however, we can use a compare immediate, so
10252117395Skan	 op1 may be a small constant.  */
10253117395Skan      && (!TARGET_ISEL || !short_cint_operand (op1, VOIDmode)))
1025496263Sobrien    return 0;
1025596263Sobrien  if (GET_MODE (true_cond) != result_mode)
1025696263Sobrien    return 0;
1025796263Sobrien  if (GET_MODE (false_cond) != result_mode)
1025896263Sobrien    return 0;
1025996263Sobrien
1026090075Sobrien  /* First, work out if the hardware can do this at all, or
10261132718Skan     if it's too slow....  */
1026290075Sobrien  if (! rs6000_compare_fp_p)
10263117395Skan    {
10264117395Skan      if (TARGET_ISEL)
10265117395Skan	return rs6000_emit_int_cmove (dest, op, true_cond, false_cond);
10266117395Skan      return 0;
10267117395Skan    }
10268132718Skan  else if (TARGET_E500 && TARGET_HARD_FLOAT && !TARGET_FPRS
10269132718Skan	   && GET_MODE_CLASS (compare_mode) == MODE_FLOAT)
10270132718Skan    return 0;
1027190075Sobrien
1027290075Sobrien  /* Eliminate half of the comparisons by switching operands, this
1027390075Sobrien     makes the remaining code simpler.  */
1027490075Sobrien  if (code == UNLT || code == UNGT || code == UNORDERED || code == NE
10275132718Skan      || code == LTGT || code == LT || code == UNLE)
1027690075Sobrien    {
1027790075Sobrien      code = reverse_condition_maybe_unordered (code);
1027890075Sobrien      temp = true_cond;
1027990075Sobrien      true_cond = false_cond;
1028090075Sobrien      false_cond = temp;
1028190075Sobrien    }
1028290075Sobrien
1028390075Sobrien  /* UNEQ and LTGT take four instructions for a comparison with zero,
1028490075Sobrien     it'll probably be faster to use a branch here too.  */
10285132718Skan  if (code == UNEQ && HONOR_NANS (compare_mode))
1028690075Sobrien    return 0;
1028790075Sobrien
1028890075Sobrien  if (GET_CODE (op1) == CONST_DOUBLE)
1028990075Sobrien    REAL_VALUE_FROM_CONST_DOUBLE (c1, op1);
1029090075Sobrien
10291132718Skan  /* We're going to try to implement comparisons by performing
1029290075Sobrien     a subtract, then comparing against zero.  Unfortunately,
1029390075Sobrien     Inf - Inf is NaN which is not zero, and so if we don't
10294117395Skan     know that the operand is finite and the comparison
1029590075Sobrien     would treat EQ different to UNORDERED, we can't do it.  */
10296132718Skan  if (HONOR_INFINITIES (compare_mode)
1029790075Sobrien      && code != GT && code != UNGE
10298117395Skan      && (GET_CODE (op1) != CONST_DOUBLE || real_isinf (&c1))
1029990075Sobrien      /* Constructs of the form (a OP b ? a : b) are safe.  */
1030090075Sobrien      && ((! rtx_equal_p (op0, false_cond) && ! rtx_equal_p (op1, false_cond))
1030190075Sobrien	  || (! rtx_equal_p (op0, true_cond)
1030290075Sobrien	      && ! rtx_equal_p (op1, true_cond))))
1030390075Sobrien    return 0;
1030490075Sobrien  /* At this point we know we can use fsel.  */
1030590075Sobrien
1030690075Sobrien  /* Reduce the comparison to a comparison against zero.  */
1030796263Sobrien  temp = gen_reg_rtx (compare_mode);
1030890075Sobrien  emit_insn (gen_rtx_SET (VOIDmode, temp,
1030996263Sobrien			  gen_rtx_MINUS (compare_mode, op0, op1)));
1031090075Sobrien  op0 = temp;
1031196263Sobrien  op1 = CONST0_RTX (compare_mode);
1031290075Sobrien
1031390075Sobrien  /* If we don't care about NaNs we can reduce some of the comparisons
1031490075Sobrien     down to faster ones.  */
10315132718Skan  if (! HONOR_NANS (compare_mode))
1031690075Sobrien    switch (code)
1031790075Sobrien      {
1031890075Sobrien      case GT:
1031990075Sobrien	code = LE;
1032090075Sobrien	temp = true_cond;
1032190075Sobrien	true_cond = false_cond;
1032290075Sobrien	false_cond = temp;
1032390075Sobrien	break;
1032490075Sobrien      case UNGE:
1032590075Sobrien	code = GE;
1032690075Sobrien	break;
1032790075Sobrien      case UNEQ:
1032890075Sobrien	code = EQ;
1032990075Sobrien	break;
1033090075Sobrien      default:
1033190075Sobrien	break;
1033290075Sobrien      }
1033390075Sobrien
1033490075Sobrien  /* Now, reduce everything down to a GE.  */
1033590075Sobrien  switch (code)
1033690075Sobrien    {
1033790075Sobrien    case GE:
1033890075Sobrien      break;
1033990075Sobrien
1034090075Sobrien    case LE:
1034196263Sobrien      temp = gen_reg_rtx (compare_mode);
1034296263Sobrien      emit_insn (gen_rtx_SET (VOIDmode, temp, gen_rtx_NEG (compare_mode, op0)));
1034390075Sobrien      op0 = temp;
1034490075Sobrien      break;
1034590075Sobrien
1034690075Sobrien    case ORDERED:
1034796263Sobrien      temp = gen_reg_rtx (compare_mode);
1034896263Sobrien      emit_insn (gen_rtx_SET (VOIDmode, temp, gen_rtx_ABS (compare_mode, op0)));
1034990075Sobrien      op0 = temp;
1035090075Sobrien      break;
1035190075Sobrien
1035290075Sobrien    case EQ:
1035396263Sobrien      temp = gen_reg_rtx (compare_mode);
1035490075Sobrien      emit_insn (gen_rtx_SET (VOIDmode, temp,
1035596263Sobrien			      gen_rtx_NEG (compare_mode,
1035696263Sobrien					   gen_rtx_ABS (compare_mode, op0))));
1035790075Sobrien      op0 = temp;
1035890075Sobrien      break;
1035990075Sobrien
1036090075Sobrien    case UNGE:
10361132718Skan      /* a UNGE 0 <-> (a GE 0 || -a UNLT 0) */
1036296263Sobrien      temp = gen_reg_rtx (result_mode);
1036390075Sobrien      emit_insn (gen_rtx_SET (VOIDmode, temp,
1036496263Sobrien			      gen_rtx_IF_THEN_ELSE (result_mode,
1036590075Sobrien						    gen_rtx_GE (VOIDmode,
1036690075Sobrien								op0, op1),
1036790075Sobrien						    true_cond, false_cond)));
10368132718Skan      false_cond = true_cond;
10369132718Skan      true_cond = temp;
1037090075Sobrien
1037196263Sobrien      temp = gen_reg_rtx (compare_mode);
1037296263Sobrien      emit_insn (gen_rtx_SET (VOIDmode, temp, gen_rtx_NEG (compare_mode, op0)));
1037390075Sobrien      op0 = temp;
1037490075Sobrien      break;
1037590075Sobrien
1037690075Sobrien    case GT:
10377132718Skan      /* a GT 0 <-> (a GE 0 && -a UNLT 0) */
1037896263Sobrien      temp = gen_reg_rtx (result_mode);
1037990075Sobrien      emit_insn (gen_rtx_SET (VOIDmode, temp,
1038096263Sobrien			      gen_rtx_IF_THEN_ELSE (result_mode,
1038190075Sobrien						    gen_rtx_GE (VOIDmode,
1038290075Sobrien								op0, op1),
1038390075Sobrien						    true_cond, false_cond)));
10384132718Skan      true_cond = false_cond;
10385132718Skan      false_cond = temp;
1038690075Sobrien
1038796263Sobrien      temp = gen_reg_rtx (compare_mode);
1038896263Sobrien      emit_insn (gen_rtx_SET (VOIDmode, temp, gen_rtx_NEG (compare_mode, op0)));
1038990075Sobrien      op0 = temp;
1039090075Sobrien      break;
1039190075Sobrien
1039290075Sobrien    default:
1039390075Sobrien      abort ();
1039490075Sobrien    }
1039590075Sobrien
1039690075Sobrien  emit_insn (gen_rtx_SET (VOIDmode, dest,
1039796263Sobrien			  gen_rtx_IF_THEN_ELSE (result_mode,
1039890075Sobrien						gen_rtx_GE (VOIDmode,
1039990075Sobrien							    op0, op1),
1040090075Sobrien						true_cond, false_cond)));
1040190075Sobrien  return 1;
1040290075Sobrien}
1040390075Sobrien
10404117395Skan/* Same as above, but for ints (isel).  */
10405117395Skan
10406117395Skanstatic int
10407132718Skanrs6000_emit_int_cmove (rtx dest, rtx op, rtx true_cond, rtx false_cond)
10408117395Skan{
10409117395Skan  rtx condition_rtx, cr;
10410117395Skan
10411117395Skan  /* All isel implementations thus far are 32-bits.  */
10412117395Skan  if (GET_MODE (rs6000_compare_op0) != SImode)
10413117395Skan    return 0;
10414117395Skan
10415117395Skan  /* We still have to do the compare, because isel doesn't do a
10416117395Skan     compare, it just looks at the CRx bits set by a previous compare
10417117395Skan     instruction.  */
10418117395Skan  condition_rtx = rs6000_generate_compare (GET_CODE (op));
10419117395Skan  cr = XEXP (condition_rtx, 0);
10420117395Skan
10421117395Skan  if (GET_MODE (cr) == CCmode)
10422117395Skan    emit_insn (gen_isel_signed (dest, condition_rtx,
10423117395Skan				true_cond, false_cond, cr));
10424117395Skan  else
10425117395Skan    emit_insn (gen_isel_unsigned (dest, condition_rtx,
10426117395Skan				  true_cond, false_cond, cr));
10427117395Skan
10428117395Skan  return 1;
10429117395Skan}
10430117395Skan
10431117395Skanconst char *
10432132718Skanoutput_isel (rtx *operands)
10433117395Skan{
10434117395Skan  enum rtx_code code;
10435117395Skan
10436117395Skan  code = GET_CODE (operands[1]);
10437117395Skan  if (code == GE || code == GEU || code == LE || code == LEU || code == NE)
10438117395Skan    {
10439117395Skan      PUT_CODE (operands[1], reverse_condition (code));
10440117395Skan      return "isel %0,%3,%2,%j1";
10441117395Skan    }
10442117395Skan  else
10443117395Skan    return "isel %0,%2,%3,%j1";
10444117395Skan}
10445117395Skan
1044690075Sobrienvoid
10447132718Skanrs6000_emit_minmax (rtx dest, enum rtx_code code, rtx op0, rtx op1)
1044890075Sobrien{
1044990075Sobrien  enum machine_mode mode = GET_MODE (op0);
10450117395Skan  enum rtx_code c;
1045190075Sobrien  rtx target;
10452117395Skan
10453117395Skan  if (code == SMAX || code == SMIN)
10454117395Skan    c = GE;
10455117395Skan  else
10456117395Skan    c = GEU;
10457117395Skan
1045890075Sobrien  if (code == SMAX || code == UMAX)
10459117395Skan    target = emit_conditional_move (dest, c, op0, op1, mode,
1046090075Sobrien				    op0, op1, mode, 0);
1046190075Sobrien  else
10462117395Skan    target = emit_conditional_move (dest, c, op0, op1, mode,
1046390075Sobrien				    op1, op0, mode, 0);
1046490075Sobrien  if (target == NULL_RTX)
1046590075Sobrien    abort ();
1046690075Sobrien  if (target != dest)
1046790075Sobrien    emit_move_insn (dest, target);
1046890075Sobrien}
10469132718Skan
10470132718Skan/* Emit instructions to move SRC to DST.  Called by splitters for
10471132718Skan   multi-register moves.  It will emit at most one instruction for
10472132718Skan   each register that is accessed; that is, it won't emit li/lis pairs
10473132718Skan   (or equivalent for 64-bit code).  One of SRC or DST must be a hard
10474132718Skan   register.  */
10475132718Skan
10476132718Skanvoid
10477132718Skanrs6000_split_multireg_move (rtx dst, rtx src)
10478132718Skan{
10479132718Skan  /* The register number of the first register being moved.  */
10480132718Skan  int reg;
10481132718Skan  /* The mode that is to be moved.  */
10482132718Skan  enum machine_mode mode;
10483132718Skan  /* The mode that the move is being done in, and its size.  */
10484132718Skan  enum machine_mode reg_mode;
10485132718Skan  int reg_mode_size;
10486132718Skan  /* The number of registers that will be moved.  */
10487132718Skan  int nregs;
10488132718Skan
10489132718Skan  reg = REG_P (dst) ? REGNO (dst) : REGNO (src);
10490132718Skan  mode = GET_MODE (dst);
10491132718Skan  nregs = HARD_REGNO_NREGS (reg, mode);
10492132718Skan  if (FP_REGNO_P (reg))
10493132718Skan    reg_mode = DFmode;
10494132718Skan  else if (ALTIVEC_REGNO_P (reg))
10495132718Skan    reg_mode = V16QImode;
10496132718Skan  else
10497132718Skan    reg_mode = word_mode;
10498132718Skan  reg_mode_size = GET_MODE_SIZE (reg_mode);
10499132718Skan
10500132718Skan  if (reg_mode_size * nregs != GET_MODE_SIZE (mode))
10501132718Skan    abort ();
10502132718Skan
10503132718Skan  if (REG_P (src) && REG_P (dst) && (REGNO (src) < REGNO (dst)))
10504132718Skan    {
10505132718Skan      /* Move register range backwards, if we might have destructive
10506132718Skan	 overlap.  */
10507132718Skan      int i;
10508132718Skan      for (i = nregs - 1; i >= 0; i--)
10509132718Skan	emit_insn (gen_rtx_SET (VOIDmode,
10510132718Skan				simplify_gen_subreg (reg_mode, dst, mode,
10511132718Skan						     i * reg_mode_size),
10512132718Skan				simplify_gen_subreg (reg_mode, src, mode,
10513132718Skan						     i * reg_mode_size)));
10514132718Skan    }
10515132718Skan  else
10516132718Skan    {
10517132718Skan      int i;
10518132718Skan      int j = -1;
10519132718Skan      bool used_update = false;
10520132718Skan
10521132718Skan      if (GET_CODE (src) == MEM && INT_REGNO_P (reg))
10522132718Skan        {
10523132718Skan          rtx breg;
10524132718Skan
10525132718Skan	  if (GET_CODE (XEXP (src, 0)) == PRE_INC
10526132718Skan	      || GET_CODE (XEXP (src, 0)) == PRE_DEC)
10527132718Skan	    {
10528132718Skan	      rtx delta_rtx;
10529132718Skan	      breg = XEXP (XEXP (src, 0), 0);
10530132718Skan	      delta_rtx =  GET_CODE (XEXP (src, 0)) == PRE_INC
10531132718Skan		  ? GEN_INT (GET_MODE_SIZE (GET_MODE (src)))
10532132718Skan		  : GEN_INT (-GET_MODE_SIZE (GET_MODE (src)));
10533132718Skan	      emit_insn (TARGET_32BIT
10534132718Skan			 ? gen_addsi3 (breg, breg, delta_rtx)
10535132718Skan			 : gen_adddi3 (breg, breg, delta_rtx));
10536132718Skan	      src = gen_rtx_MEM (mode, breg);
10537132718Skan	    }
10538146895Skan	  else if (! offsettable_memref_p (src))
10539146895Skan	    {
10540146895Skan	      rtx newsrc, basereg;
10541146895Skan	      basereg = gen_rtx_REG (Pmode, reg);
10542146895Skan	      emit_insn (gen_rtx_SET (VOIDmode, basereg, XEXP (src, 0)));
10543146895Skan	      newsrc = gen_rtx_MEM (GET_MODE (src), basereg);
10544146895Skan	      MEM_COPY_ATTRIBUTES (newsrc, src);
10545146895Skan	      src = newsrc;
10546146895Skan	    }
10547132718Skan
10548146895Skan	  breg = XEXP (src, 0);
10549146895Skan	  if (GET_CODE (breg) == PLUS || GET_CODE (breg) == LO_SUM)
10550146895Skan	    breg = XEXP (breg, 0);
10551132718Skan
10552146895Skan	  /* If the base register we are using to address memory is
10553146895Skan	     also a destination reg, then change that register last.  */
10554146895Skan	  if (REG_P (breg)
10555146895Skan	      && REGNO (breg) >= REGNO (dst)
10556132718Skan	      && REGNO (breg) < REGNO (dst) + nregs)
10557132718Skan	    j = REGNO (breg) - REGNO (dst);
10558146895Skan	}
10559132718Skan
10560132718Skan      if (GET_CODE (dst) == MEM && INT_REGNO_P (reg))
10561132718Skan	{
10562132718Skan	  rtx breg;
10563132718Skan
10564132718Skan	  if (GET_CODE (XEXP (dst, 0)) == PRE_INC
10565132718Skan	      || GET_CODE (XEXP (dst, 0)) == PRE_DEC)
10566132718Skan	    {
10567132718Skan	      rtx delta_rtx;
10568132718Skan	      breg = XEXP (XEXP (dst, 0), 0);
10569132718Skan	      delta_rtx = GET_CODE (XEXP (dst, 0)) == PRE_INC
10570132718Skan		? GEN_INT (GET_MODE_SIZE (GET_MODE (dst)))
10571132718Skan		: GEN_INT (-GET_MODE_SIZE (GET_MODE (dst)));
10572132718Skan
10573132718Skan	      /* We have to update the breg before doing the store.
10574132718Skan		 Use store with update, if available.  */
10575132718Skan
10576132718Skan	      if (TARGET_UPDATE)
10577132718Skan		{
10578132718Skan		  rtx nsrc = simplify_gen_subreg (reg_mode, src, mode, 0);
10579132718Skan		  emit_insn (TARGET_32BIT
10580132718Skan			     ? gen_movsi_update (breg, breg, delta_rtx, nsrc)
10581132718Skan			     : gen_movdi_update (breg, breg, delta_rtx, nsrc));
10582132718Skan		  used_update = true;
10583132718Skan		}
10584132718Skan	      else
10585132718Skan		emit_insn (TARGET_32BIT
10586132718Skan			   ? gen_addsi3 (breg, breg, delta_rtx)
10587132718Skan			   : gen_adddi3 (breg, breg, delta_rtx));
10588132718Skan	      dst = gen_rtx_MEM (mode, breg);
10589132718Skan	    }
10590146895Skan	  else if (! offsettable_memref_p (dst))
10591146895Skan	    abort ();
10592132718Skan	}
10593132718Skan
10594132718Skan      for (i = 0; i < nregs; i++)
10595132718Skan	{
10596132718Skan	  /* Calculate index to next subword.  */
10597132718Skan	  ++j;
10598132718Skan	  if (j == nregs)
10599132718Skan	    j = 0;
10600132718Skan
10601146895Skan	  /* If compiler already emitted move of first word by
10602132718Skan	     store with update, no need to do anything.  */
10603132718Skan	  if (j == 0 && used_update)
10604132718Skan	    continue;
10605132718Skan
10606132718Skan	  emit_insn (gen_rtx_SET (VOIDmode,
10607132718Skan				  simplify_gen_subreg (reg_mode, dst, mode,
10608132718Skan						       j * reg_mode_size),
10609132718Skan				  simplify_gen_subreg (reg_mode, src, mode,
10610132718Skan						       j * reg_mode_size)));
10611132718Skan	}
10612132718Skan    }
10613132718Skan}
10614132718Skan
1061590075Sobrien
1061690075Sobrien/* This page contains routines that are used to determine what the
1061790075Sobrien   function prologue and epilogue code will do and write them out.  */
1061890075Sobrien
1061990075Sobrien/* Return the first fixed-point register that is required to be
1062090075Sobrien   saved. 32 if none.  */
1062190075Sobrien
1062290075Sobrienint
10623132718Skanfirst_reg_to_save (void)
1062490075Sobrien{
1062590075Sobrien  int first_reg;
1062690075Sobrien
1062790075Sobrien  /* Find lowest numbered live register.  */
1062890075Sobrien  for (first_reg = 13; first_reg <= 31; first_reg++)
1062990075Sobrien    if (regs_ever_live[first_reg]
1063090075Sobrien	&& (! call_used_regs[first_reg]
1063196263Sobrien	    || (first_reg == RS6000_PIC_OFFSET_TABLE_REGNUM
10632117395Skan		&& ((DEFAULT_ABI == ABI_V4 && flag_pic != 0)
10633146895Skan		    || (DEFAULT_ABI == ABI_DARWIN && flag_pic)
10634146895Skan		    || (TARGET_TOC && TARGET_MINIMAL_TOC)))))
1063590075Sobrien      break;
1063690075Sobrien
1063790075Sobrien#if TARGET_MACHO
10638117395Skan  if (flag_pic
10639117395Skan      && current_function_uses_pic_offset_table
10640117395Skan      && first_reg > RS6000_PIC_OFFSET_TABLE_REGNUM)
1064196263Sobrien    return RS6000_PIC_OFFSET_TABLE_REGNUM;
1064290075Sobrien#endif
1064390075Sobrien
1064490075Sobrien  return first_reg;
1064590075Sobrien}
1064690075Sobrien
1064790075Sobrien/* Similar, for FP regs.  */
1064890075Sobrien
1064990075Sobrienint
10650132718Skanfirst_fp_reg_to_save (void)
1065190075Sobrien{
1065290075Sobrien  int first_reg;
1065390075Sobrien
1065490075Sobrien  /* Find lowest numbered live register.  */
1065590075Sobrien  for (first_reg = 14 + 32; first_reg <= 63; first_reg++)
1065690075Sobrien    if (regs_ever_live[first_reg])
1065790075Sobrien      break;
1065890075Sobrien
1065990075Sobrien  return first_reg;
1066090075Sobrien}
1066190075Sobrien
1066290075Sobrien/* Similar, for AltiVec regs.  */
1066390075Sobrien
1066490075Sobrienstatic int
10665132718Skanfirst_altivec_reg_to_save (void)
1066690075Sobrien{
1066790075Sobrien  int i;
1066890075Sobrien
1066990075Sobrien  /* Stack frame remains as is unless we are in AltiVec ABI.  */
1067090075Sobrien  if (! TARGET_ALTIVEC_ABI)
1067190075Sobrien    return LAST_ALTIVEC_REGNO + 1;
1067290075Sobrien
1067390075Sobrien  /* Find lowest numbered live register.  */
1067490075Sobrien  for (i = FIRST_ALTIVEC_REGNO + 20; i <= LAST_ALTIVEC_REGNO; ++i)
1067590075Sobrien    if (regs_ever_live[i])
1067690075Sobrien      break;
1067790075Sobrien
1067890075Sobrien  return i;
1067990075Sobrien}
1068090075Sobrien
1068190075Sobrien/* Return a 32-bit mask of the AltiVec registers we need to set in
1068290075Sobrien   VRSAVE.  Bit n of the return value is 1 if Vn is live.  The MSB in
1068390075Sobrien   the 32-bit word is 0.  */
1068490075Sobrien
1068590075Sobrienstatic unsigned int
10686132718Skancompute_vrsave_mask (void)
1068790075Sobrien{
1068890075Sobrien  unsigned int i, mask = 0;
1068990075Sobrien
1069090075Sobrien  /* First, find out if we use _any_ altivec registers.  */
1069190075Sobrien  for (i = FIRST_ALTIVEC_REGNO; i <= LAST_ALTIVEC_REGNO; ++i)
1069290075Sobrien    if (regs_ever_live[i])
1069390075Sobrien      mask |= ALTIVEC_REG_BIT (i);
1069490075Sobrien
1069590075Sobrien  if (mask == 0)
1069690075Sobrien    return mask;
1069790075Sobrien
1069890075Sobrien  /* Next, remove the argument registers from the set.  These must
1069990075Sobrien     be in the VRSAVE mask set by the caller, so we don't need to add
1070090075Sobrien     them in again.  More importantly, the mask we compute here is
1070190075Sobrien     used to generate CLOBBERs in the set_vrsave insn, and we do not
1070290075Sobrien     wish the argument registers to die.  */
10703132718Skan  for (i = cfun->args_info.vregno - 1; i >= ALTIVEC_ARG_MIN_REG; --i)
1070490075Sobrien    mask &= ~ALTIVEC_REG_BIT (i);
1070590075Sobrien
1070690075Sobrien  /* Similarly, remove the return value from the set.  */
1070790075Sobrien  {
1070890075Sobrien    bool yes = false;
1070990075Sobrien    diddle_return_value (is_altivec_return_reg, &yes);
1071090075Sobrien    if (yes)
1071190075Sobrien      mask &= ~ALTIVEC_REG_BIT (ALTIVEC_ARG_RETURN);
1071290075Sobrien  }
1071390075Sobrien
1071490075Sobrien  return mask;
1071590075Sobrien}
1071690075Sobrien
1071790075Sobrienstatic void
10718132718Skanis_altivec_return_reg (rtx reg, void *xyes)
1071990075Sobrien{
1072090075Sobrien  bool *yes = (bool *) xyes;
1072190075Sobrien  if (REGNO (reg) == ALTIVEC_ARG_RETURN)
1072290075Sobrien    *yes = true;
1072390075Sobrien}
1072490075Sobrien
1072590075Sobrien
1072690075Sobrien/* Calculate the stack information for the current function.  This is
1072790075Sobrien   complicated by having two separate calling sequences, the AIX calling
1072890075Sobrien   sequence and the V.4 calling sequence.
1072990075Sobrien
1073090075Sobrien   AIX (and Darwin/Mac OS X) stack frames look like:
1073190075Sobrien							  32-bit  64-bit
1073290075Sobrien	SP---->	+---------------------------------------+
1073390075Sobrien		| back chain to caller			| 0	  0
1073490075Sobrien		+---------------------------------------+
1073590075Sobrien		| saved CR				| 4       8 (8-11)
1073690075Sobrien		+---------------------------------------+
1073790075Sobrien		| saved LR				| 8       16
1073890075Sobrien		+---------------------------------------+
1073990075Sobrien		| reserved for compilers		| 12      24
1074090075Sobrien		+---------------------------------------+
1074190075Sobrien		| reserved for binders			| 16      32
1074290075Sobrien		+---------------------------------------+
1074390075Sobrien		| saved TOC pointer			| 20      40
1074490075Sobrien		+---------------------------------------+
1074590075Sobrien		| Parameter save area (P)		| 24      48
1074690075Sobrien		+---------------------------------------+
1074790075Sobrien		| Alloca space (A)			| 24+P    etc.
1074890075Sobrien		+---------------------------------------+
1074990075Sobrien		| Local variable space (L)		| 24+P+A
1075090075Sobrien		+---------------------------------------+
1075190075Sobrien		| Float/int conversion temporary (X)	| 24+P+A+L
1075290075Sobrien		+---------------------------------------+
1075390075Sobrien		| Save area for AltiVec registers (W)	| 24+P+A+L+X
1075490075Sobrien		+---------------------------------------+
1075590075Sobrien		| AltiVec alignment padding (Y)		| 24+P+A+L+X+W
1075690075Sobrien		+---------------------------------------+
1075790075Sobrien		| Save area for VRSAVE register (Z)	| 24+P+A+L+X+W+Y
1075890075Sobrien		+---------------------------------------+
1075990075Sobrien		| Save area for GP registers (G)	| 24+P+A+X+L+X+W+Y+Z
1076090075Sobrien		+---------------------------------------+
1076190075Sobrien		| Save area for FP registers (F)	| 24+P+A+X+L+X+W+Y+Z+G
1076290075Sobrien		+---------------------------------------+
1076390075Sobrien	old SP->| back chain to caller's caller		|
1076490075Sobrien		+---------------------------------------+
1076590075Sobrien
1076690075Sobrien   The required alignment for AIX configurations is two words (i.e., 8
1076790075Sobrien   or 16 bytes).
1076890075Sobrien
1076990075Sobrien
1077090075Sobrien   V.4 stack frames look like:
1077190075Sobrien
1077290075Sobrien	SP---->	+---------------------------------------+
1077390075Sobrien		| back chain to caller			| 0
1077490075Sobrien		+---------------------------------------+
1077590075Sobrien		| caller's saved LR			| 4
1077690075Sobrien		+---------------------------------------+
1077790075Sobrien		| Parameter save area (P)		| 8
1077890075Sobrien		+---------------------------------------+
1077990075Sobrien		| Alloca space (A)			| 8+P
1078090075Sobrien		+---------------------------------------+
1078190075Sobrien		| Varargs save area (V)			| 8+P+A
1078290075Sobrien		+---------------------------------------+
1078390075Sobrien		| Local variable space (L)		| 8+P+A+V
1078490075Sobrien		+---------------------------------------+
1078590075Sobrien		| Float/int conversion temporary (X)	| 8+P+A+V+L
1078690075Sobrien		+---------------------------------------+
1078790075Sobrien		| Save area for AltiVec registers (W)	| 8+P+A+V+L+X
1078890075Sobrien		+---------------------------------------+
1078990075Sobrien		| AltiVec alignment padding (Y)		| 8+P+A+V+L+X+W
1079090075Sobrien		+---------------------------------------+
1079190075Sobrien		| Save area for VRSAVE register (Z)	| 8+P+A+V+L+X+W+Y
1079290075Sobrien		+---------------------------------------+
10793117395Skan                | SPE: area for 64-bit GP registers     |
10794117395Skan                +---------------------------------------+
10795117395Skan                | SPE alignment padding                 |
10796117395Skan                +---------------------------------------+
1079790075Sobrien		| saved CR (C)				| 8+P+A+V+L+X+W+Y+Z
1079890075Sobrien		+---------------------------------------+
1079990075Sobrien		| Save area for GP registers (G)	| 8+P+A+V+L+X+W+Y+Z+C
1080090075Sobrien		+---------------------------------------+
1080190075Sobrien		| Save area for FP registers (F)	| 8+P+A+V+L+X+W+Y+Z+C+G
1080290075Sobrien		+---------------------------------------+
1080390075Sobrien	old SP->| back chain to caller's caller		|
1080490075Sobrien		+---------------------------------------+
1080590075Sobrien
1080690075Sobrien   The required alignment for V.4 is 16 bytes, or 8 bytes if -meabi is
1080790075Sobrien   given.  (But note below and in sysv4.h that we require only 8 and
1080890075Sobrien   may round up the size of our stack frame anyways.  The historical
1080990075Sobrien   reason is early versions of powerpc-linux which didn't properly
1081090075Sobrien   align the stack at program startup.  A happy side-effect is that
1081190075Sobrien   -mno-eabi libraries can be used with -meabi programs.)
1081290075Sobrien
10813132718Skan   The EABI configuration defaults to the V.4 layout.  However,
1081490075Sobrien   the stack alignment requirements may differ.  If -mno-eabi is not
1081590075Sobrien   given, the required stack alignment is 8 bytes; if -mno-eabi is
1081690075Sobrien   given, the required alignment is 16 bytes.  (But see V.4 comment
1081790075Sobrien   above.)  */
1081890075Sobrien
1081990075Sobrien#ifndef ABI_STACK_BOUNDARY
1082090075Sobrien#define ABI_STACK_BOUNDARY STACK_BOUNDARY
1082190075Sobrien#endif
1082290075Sobrien
10823132718Skanstatic rs6000_stack_t *
10824132718Skanrs6000_stack_info (void)
1082590075Sobrien{
1082690075Sobrien  static rs6000_stack_t info, zero_info;
1082790075Sobrien  rs6000_stack_t *info_ptr = &info;
10828132718Skan  int reg_size = TARGET_32BIT ? 4 : 8;
1082990075Sobrien  int ehrd_size;
10830146895Skan  int save_align;
10831132718Skan  HOST_WIDE_INT non_fixed_size;
1083290075Sobrien
1083390075Sobrien  /* Zero all fields portably.  */
1083490075Sobrien  info = zero_info;
1083590075Sobrien
10836132718Skan  if (TARGET_SPE)
10837132718Skan    {
10838132718Skan      /* Cache value so we don't rescan instruction chain over and over.  */
10839132718Skan      if (cfun->machine->insn_chain_scanned_p == 0)
10840132718Skan	{
10841132718Skan	  cfun->machine->insn_chain_scanned_p = 1;
10842132718Skan	  info_ptr->spe_64bit_regs_used = (int) spe_func_has_64bit_regs_p ();
10843132718Skan	}
10844132718Skan    }
10845132718Skan
1084690075Sobrien  /* Select which calling sequence.  */
10847132718Skan  info_ptr->abi = DEFAULT_ABI;
1084890075Sobrien
1084990075Sobrien  /* Calculate which registers need to be saved & save area size.  */
1085090075Sobrien  info_ptr->first_gp_reg_save = first_reg_to_save ();
1085196263Sobrien  /* Assume that we will have to save RS6000_PIC_OFFSET_TABLE_REGNUM,
1085290075Sobrien     even if it currently looks like we won't.  */
1085390075Sobrien  if (((TARGET_TOC && TARGET_MINIMAL_TOC)
10854132718Skan       || (flag_pic == 1 && DEFAULT_ABI == ABI_V4)
10855132718Skan       || (flag_pic && DEFAULT_ABI == ABI_DARWIN))
1085696263Sobrien      && info_ptr->first_gp_reg_save > RS6000_PIC_OFFSET_TABLE_REGNUM)
1085796263Sobrien    info_ptr->gp_size = reg_size * (32 - RS6000_PIC_OFFSET_TABLE_REGNUM);
1085890075Sobrien  else
1085990075Sobrien    info_ptr->gp_size = reg_size * (32 - info_ptr->first_gp_reg_save);
1086090075Sobrien
10861117395Skan  /* For the SPE, we have an additional upper 32-bits on each GPR.
10862117395Skan     Ideally we should save the entire 64-bits only when the upper
10863117395Skan     half is used in SIMD instructions.  Since we only record
10864117395Skan     registers live (not the size they are used in), this proves
10865117395Skan     difficult because we'd have to traverse the instruction chain at
10866117395Skan     the right time, taking reload into account.  This is a real pain,
10867132718Skan     so we opt to save the GPRs in 64-bits always if but one register
10868132718Skan     gets used in 64-bits.  Otherwise, all the registers in the frame
10869132718Skan     get saved in 32-bits.
10870117395Skan
10871132718Skan     So... since when we save all GPRs (except the SP) in 64-bits, the
10872117395Skan     traditional GP save area will be empty.  */
10873132718Skan  if (TARGET_SPE_ABI && info_ptr->spe_64bit_regs_used != 0)
10874117395Skan    info_ptr->gp_size = 0;
10875117395Skan
1087690075Sobrien  info_ptr->first_fp_reg_save = first_fp_reg_to_save ();
1087790075Sobrien  info_ptr->fp_size = 8 * (64 - info_ptr->first_fp_reg_save);
1087890075Sobrien
1087990075Sobrien  info_ptr->first_altivec_reg_save = first_altivec_reg_to_save ();
1088090075Sobrien  info_ptr->altivec_size = 16 * (LAST_ALTIVEC_REGNO + 1
1088190075Sobrien				 - info_ptr->first_altivec_reg_save);
1088290075Sobrien
1088390075Sobrien  /* Does this function call anything?  */
1088490075Sobrien  info_ptr->calls_p = (! current_function_is_leaf
1088590075Sobrien		       || cfun->machine->ra_needs_full_frame);
1088690075Sobrien
1088790075Sobrien  /* Determine if we need to save the link register.  */
1088890075Sobrien  if (rs6000_ra_ever_killed ()
10889132718Skan      || (DEFAULT_ABI == ABI_AIX
10890132718Skan	  && current_function_profile
10891132718Skan	  && !TARGET_PROFILE_KERNEL)
1089290075Sobrien#ifdef TARGET_RELOCATABLE
1089390075Sobrien      || (TARGET_RELOCATABLE && (get_pool_size () != 0))
1089490075Sobrien#endif
1089590075Sobrien      || (info_ptr->first_fp_reg_save != 64
1089690075Sobrien	  && !FP_SAVE_INLINE (info_ptr->first_fp_reg_save))
1089790075Sobrien      || info_ptr->first_altivec_reg_save <= LAST_ALTIVEC_REGNO
10898132718Skan      || (DEFAULT_ABI == ABI_V4 && current_function_calls_alloca)
1089990075Sobrien      || (DEFAULT_ABI == ABI_DARWIN
1090090075Sobrien	  && flag_pic
1090190075Sobrien	  && current_function_uses_pic_offset_table)
1090290075Sobrien      || info_ptr->calls_p)
1090390075Sobrien    {
1090490075Sobrien      info_ptr->lr_save_p = 1;
1090590075Sobrien      regs_ever_live[LINK_REGISTER_REGNUM] = 1;
1090690075Sobrien    }
1090790075Sobrien
1090890075Sobrien  /* Determine if we need to save the condition code registers.  */
1090990075Sobrien  if (regs_ever_live[CR2_REGNO]
1091090075Sobrien      || regs_ever_live[CR3_REGNO]
1091190075Sobrien      || regs_ever_live[CR4_REGNO])
1091290075Sobrien    {
1091390075Sobrien      info_ptr->cr_save_p = 1;
10914132718Skan      if (DEFAULT_ABI == ABI_V4)
1091590075Sobrien	info_ptr->cr_size = reg_size;
1091690075Sobrien    }
1091790075Sobrien
1091890075Sobrien  /* If the current function calls __builtin_eh_return, then we need
1091990075Sobrien     to allocate stack space for registers that will hold data for
1092090075Sobrien     the exception handler.  */
1092190075Sobrien  if (current_function_calls_eh_return)
1092290075Sobrien    {
1092390075Sobrien      unsigned int i;
1092490075Sobrien      for (i = 0; EH_RETURN_DATA_REGNO (i) != INVALID_REGNUM; ++i)
1092590075Sobrien	continue;
10926117395Skan
10927117395Skan      /* SPE saves EH registers in 64-bits.  */
10928132718Skan      ehrd_size = i * (TARGET_SPE_ABI
10929132718Skan		       && info_ptr->spe_64bit_regs_used != 0
10930132718Skan		       ? UNITS_PER_SPE_WORD : UNITS_PER_WORD);
1093190075Sobrien    }
1093290075Sobrien  else
1093390075Sobrien    ehrd_size = 0;
1093490075Sobrien
1093590075Sobrien  /* Determine various sizes.  */
1093690075Sobrien  info_ptr->reg_size     = reg_size;
1093790075Sobrien  info_ptr->fixed_size   = RS6000_SAVE_AREA;
1093890075Sobrien  info_ptr->varargs_size = RS6000_VARARGS_AREA;
1093990075Sobrien  info_ptr->vars_size    = RS6000_ALIGN (get_frame_size (), 8);
1094090075Sobrien  info_ptr->parm_size    = RS6000_ALIGN (current_function_outgoing_args_size,
10941132718Skan					 TARGET_ALTIVEC ? 16 : 8);
1094290075Sobrien
10943132718Skan  if (TARGET_SPE_ABI && info_ptr->spe_64bit_regs_used != 0)
10944117395Skan    info_ptr->spe_gp_size = 8 * (32 - info_ptr->first_gp_reg_save);
10945117395Skan  else
10946117395Skan    info_ptr->spe_gp_size = 0;
10947117395Skan
10948132718Skan  if (TARGET_ALTIVEC_ABI)
10949132718Skan    info_ptr->vrsave_mask = compute_vrsave_mask ();
1095090075Sobrien  else
10951132718Skan    info_ptr->vrsave_mask = 0;
1095290075Sobrien
10953132718Skan  if (TARGET_ALTIVEC_VRSAVE && info_ptr->vrsave_mask)
10954132718Skan    info_ptr->vrsave_size  = 4;
10955132718Skan  else
10956132718Skan    info_ptr->vrsave_size  = 0;
10957132718Skan
1095890075Sobrien  /* Calculate the offsets.  */
10959132718Skan  switch (DEFAULT_ABI)
1096090075Sobrien    {
1096190075Sobrien    case ABI_NONE:
1096290075Sobrien    default:
1096390075Sobrien      abort ();
1096490075Sobrien
1096590075Sobrien    case ABI_AIX:
1096690075Sobrien    case ABI_DARWIN:
1096790075Sobrien      info_ptr->fp_save_offset   = - info_ptr->fp_size;
1096890075Sobrien      info_ptr->gp_save_offset   = info_ptr->fp_save_offset - info_ptr->gp_size;
1096990075Sobrien
1097090075Sobrien      if (TARGET_ALTIVEC_ABI)
1097190075Sobrien	{
1097290075Sobrien	  info_ptr->vrsave_save_offset
1097390075Sobrien	    = info_ptr->gp_save_offset - info_ptr->vrsave_size;
1097490075Sobrien
1097590075Sobrien	  /* Align stack so vector save area is on a quadword boundary.  */
1097690075Sobrien	  if (info_ptr->altivec_size != 0)
1097790075Sobrien	    info_ptr->altivec_padding_size
1097890075Sobrien	      = 16 - (-info_ptr->vrsave_save_offset % 16);
1097990075Sobrien	  else
1098090075Sobrien	    info_ptr->altivec_padding_size = 0;
1098190075Sobrien
1098290075Sobrien	  info_ptr->altivec_save_offset
1098390075Sobrien	    = info_ptr->vrsave_save_offset
1098490075Sobrien	    - info_ptr->altivec_padding_size
1098590075Sobrien	    - info_ptr->altivec_size;
1098690075Sobrien
1098790075Sobrien	  /* Adjust for AltiVec case.  */
1098890075Sobrien	  info_ptr->ehrd_offset = info_ptr->altivec_save_offset - ehrd_size;
1098990075Sobrien	}
1099090075Sobrien      else
1099190075Sobrien	info_ptr->ehrd_offset      = info_ptr->gp_save_offset - ehrd_size;
1099290075Sobrien      info_ptr->cr_save_offset   = reg_size; /* first word when 64-bit.  */
1099390075Sobrien      info_ptr->lr_save_offset   = 2*reg_size;
1099490075Sobrien      break;
1099590075Sobrien
1099690075Sobrien    case ABI_V4:
1099790075Sobrien      info_ptr->fp_save_offset   = - info_ptr->fp_size;
1099890075Sobrien      info_ptr->gp_save_offset   = info_ptr->fp_save_offset - info_ptr->gp_size;
1099990075Sobrien      info_ptr->cr_save_offset   = info_ptr->gp_save_offset - info_ptr->cr_size;
1100090075Sobrien
11001132718Skan      if (TARGET_SPE_ABI && info_ptr->spe_64bit_regs_used != 0)
11002117395Skan      {
11003117395Skan        /* Align stack so SPE GPR save area is aligned on a
11004117395Skan           double-word boundary.  */
11005117395Skan        if (info_ptr->spe_gp_size != 0)
11006117395Skan          info_ptr->spe_padding_size
11007117395Skan            = 8 - (-info_ptr->cr_save_offset % 8);
11008117395Skan        else
11009117395Skan          info_ptr->spe_padding_size = 0;
11010117395Skan
11011117395Skan        info_ptr->spe_gp_save_offset
11012117395Skan          = info_ptr->cr_save_offset
11013117395Skan          - info_ptr->spe_padding_size
11014117395Skan          - info_ptr->spe_gp_size;
11015117395Skan
11016117395Skan        /* Adjust for SPE case.  */
11017117395Skan        info_ptr->toc_save_offset
11018117395Skan          = info_ptr->spe_gp_save_offset - info_ptr->toc_size;
11019117395Skan      }
11020117395Skan      else if (TARGET_ALTIVEC_ABI)
1102190075Sobrien	{
1102290075Sobrien	  info_ptr->vrsave_save_offset
1102390075Sobrien	    = info_ptr->cr_save_offset - info_ptr->vrsave_size;
1102490075Sobrien
1102590075Sobrien	  /* Align stack so vector save area is on a quadword boundary.  */
1102690075Sobrien	  if (info_ptr->altivec_size != 0)
1102790075Sobrien	    info_ptr->altivec_padding_size
1102890075Sobrien	      = 16 - (-info_ptr->vrsave_save_offset % 16);
1102990075Sobrien	  else
1103090075Sobrien	    info_ptr->altivec_padding_size = 0;
1103190075Sobrien
1103290075Sobrien	  info_ptr->altivec_save_offset
1103390075Sobrien	    = info_ptr->vrsave_save_offset
1103490075Sobrien	    - info_ptr->altivec_padding_size
1103590075Sobrien	    - info_ptr->altivec_size;
1103690075Sobrien
1103790075Sobrien	  /* Adjust for AltiVec case.  */
1103890075Sobrien	  info_ptr->toc_save_offset
1103990075Sobrien	    = info_ptr->altivec_save_offset - info_ptr->toc_size;
1104090075Sobrien	}
1104190075Sobrien      else
1104290075Sobrien	info_ptr->toc_save_offset  = info_ptr->cr_save_offset - info_ptr->toc_size;
1104390075Sobrien      info_ptr->ehrd_offset      = info_ptr->toc_save_offset - ehrd_size;
1104490075Sobrien      info_ptr->lr_save_offset   = reg_size;
1104590075Sobrien      break;
1104690075Sobrien    }
1104790075Sobrien
11048146895Skan  save_align = (TARGET_ALTIVEC_ABI || DEFAULT_ABI == ABI_DARWIN) ? 16 : 8;
1104990075Sobrien  info_ptr->save_size    = RS6000_ALIGN (info_ptr->fp_size
1105090075Sobrien					 + info_ptr->gp_size
1105190075Sobrien					 + info_ptr->altivec_size
1105290075Sobrien					 + info_ptr->altivec_padding_size
11053117395Skan					 + info_ptr->spe_gp_size
11054117395Skan					 + info_ptr->spe_padding_size
1105590075Sobrien					 + ehrd_size
1105690075Sobrien					 + info_ptr->cr_size
1105790075Sobrien					 + info_ptr->lr_size
11058132718Skan					 + info_ptr->vrsave_size
1105990075Sobrien					 + info_ptr->toc_size,
11060146895Skan					 save_align);
1106190075Sobrien
11062132718Skan  non_fixed_size	 = (info_ptr->vars_size
1106390075Sobrien			    + info_ptr->parm_size
1106490075Sobrien			    + info_ptr->save_size
11065132718Skan			    + info_ptr->varargs_size);
1106690075Sobrien
11067132718Skan  info_ptr->total_size = RS6000_ALIGN (non_fixed_size + info_ptr->fixed_size,
11068132718Skan				       ABI_STACK_BOUNDARY / BITS_PER_UNIT);
1106990075Sobrien
1107090075Sobrien  /* Determine if we need to allocate any stack frame:
1107190075Sobrien
1107290075Sobrien     For AIX we need to push the stack if a frame pointer is needed
1107390075Sobrien     (because the stack might be dynamically adjusted), if we are
1107490075Sobrien     debugging, if we make calls, or if the sum of fp_save, gp_save,
1107590075Sobrien     and local variables are more than the space needed to save all
1107690075Sobrien     non-volatile registers: 32-bit: 18*8 + 19*4 = 220 or 64-bit: 18*8
1107790075Sobrien     + 18*8 = 288 (GPR13 reserved).
1107890075Sobrien
1107990075Sobrien     For V.4 we don't have the stack cushion that AIX uses, but assume
1108090075Sobrien     that the debugger can handle stackless frames.  */
1108190075Sobrien
1108290075Sobrien  if (info_ptr->calls_p)
1108390075Sobrien    info_ptr->push_p = 1;
1108490075Sobrien
11085132718Skan  else if (DEFAULT_ABI == ABI_V4)
11086132718Skan    info_ptr->push_p = non_fixed_size != 0;
1108790075Sobrien
11088132718Skan  else if (frame_pointer_needed)
11089132718Skan    info_ptr->push_p = 1;
11090132718Skan
11091132718Skan  else if (TARGET_XCOFF && write_symbols != NO_DEBUG)
11092132718Skan    info_ptr->push_p = 1;
11093132718Skan
1109490075Sobrien  else
11095132718Skan    info_ptr->push_p = non_fixed_size > (TARGET_32BIT ? 220 : 288);
1109690075Sobrien
1109790075Sobrien  /* Zero offsets if we're not saving those registers.  */
1109890075Sobrien  if (info_ptr->fp_size == 0)
1109990075Sobrien    info_ptr->fp_save_offset = 0;
1110090075Sobrien
1110190075Sobrien  if (info_ptr->gp_size == 0)
1110290075Sobrien    info_ptr->gp_save_offset = 0;
1110390075Sobrien
1110490075Sobrien  if (! TARGET_ALTIVEC_ABI || info_ptr->altivec_size == 0)
1110590075Sobrien    info_ptr->altivec_save_offset = 0;
1110690075Sobrien
1110790075Sobrien  if (! TARGET_ALTIVEC_ABI || info_ptr->vrsave_mask == 0)
1110890075Sobrien    info_ptr->vrsave_save_offset = 0;
1110990075Sobrien
11110132718Skan  if (! TARGET_SPE_ABI
11111132718Skan      || info_ptr->spe_64bit_regs_used == 0
11112132718Skan      || info_ptr->spe_gp_size == 0)
11113117395Skan    info_ptr->spe_gp_save_offset = 0;
11114117395Skan
1111590075Sobrien  if (! info_ptr->lr_save_p)
1111690075Sobrien    info_ptr->lr_save_offset = 0;
1111790075Sobrien
1111890075Sobrien  if (! info_ptr->cr_save_p)
1111990075Sobrien    info_ptr->cr_save_offset = 0;
1112090075Sobrien
1112190075Sobrien  if (! info_ptr->toc_save_p)
1112290075Sobrien    info_ptr->toc_save_offset = 0;
1112390075Sobrien
1112490075Sobrien  return info_ptr;
1112590075Sobrien}
1112690075Sobrien
11127132718Skan/* Return true if the current function uses any GPRs in 64-bit SIMD
11128132718Skan   mode.  */
11129132718Skan
11130132718Skanstatic bool
11131132718Skanspe_func_has_64bit_regs_p (void)
1113290075Sobrien{
11133132718Skan  rtx insns, insn;
11134132718Skan
11135132718Skan  /* Functions that save and restore all the call-saved registers will
11136132718Skan     need to save/restore the registers in 64-bits.  */
11137132718Skan  if (current_function_calls_eh_return
11138132718Skan      || current_function_calls_setjmp
11139132718Skan      || current_function_has_nonlocal_goto)
11140132718Skan    return true;
11141132718Skan
11142132718Skan  insns = get_insns ();
11143132718Skan
11144132718Skan  for (insn = NEXT_INSN (insns); insn != NULL_RTX; insn = NEXT_INSN (insn))
11145132718Skan    {
11146132718Skan      if (INSN_P (insn))
11147132718Skan	{
11148132718Skan	  rtx i;
11149132718Skan
11150132718Skan	  i = PATTERN (insn);
11151132718Skan	  if (GET_CODE (i) == SET
11152132718Skan	      && SPE_VECTOR_MODE (GET_MODE (SET_SRC (i))))
11153132718Skan	    return true;
11154132718Skan	}
11155132718Skan    }
11156132718Skan
11157132718Skan  return false;
11158132718Skan}
11159132718Skan
11160132718Skanstatic void
11161132718Skandebug_stack_info (rs6000_stack_t *info)
11162132718Skan{
1116390075Sobrien  const char *abi_string;
1116490075Sobrien
1116590075Sobrien  if (! info)
1116690075Sobrien    info = rs6000_stack_info ();
1116790075Sobrien
1116890075Sobrien  fprintf (stderr, "\nStack information for function %s:\n",
1116990075Sobrien	   ((current_function_decl && DECL_NAME (current_function_decl))
1117090075Sobrien	    ? IDENTIFIER_POINTER (DECL_NAME (current_function_decl))
1117190075Sobrien	    : "<unknown>"));
1117290075Sobrien
1117390075Sobrien  switch (info->abi)
1117490075Sobrien    {
1117590075Sobrien    default:		 abi_string = "Unknown";	break;
1117690075Sobrien    case ABI_NONE:	 abi_string = "NONE";		break;
11177132718Skan    case ABI_AIX:	 abi_string = "AIX";		break;
1117890075Sobrien    case ABI_DARWIN:	 abi_string = "Darwin";		break;
1117990075Sobrien    case ABI_V4:	 abi_string = "V.4";		break;
1118090075Sobrien    }
1118190075Sobrien
1118290075Sobrien  fprintf (stderr, "\tABI                 = %5s\n", abi_string);
1118390075Sobrien
1118490075Sobrien  if (TARGET_ALTIVEC_ABI)
1118590075Sobrien    fprintf (stderr, "\tALTIVEC ABI extensions enabled.\n");
1118690075Sobrien
11187117395Skan  if (TARGET_SPE_ABI)
11188117395Skan    fprintf (stderr, "\tSPE ABI extensions enabled.\n");
11189117395Skan
1119090075Sobrien  if (info->first_gp_reg_save != 32)
1119190075Sobrien    fprintf (stderr, "\tfirst_gp_reg_save   = %5d\n", info->first_gp_reg_save);
1119290075Sobrien
1119390075Sobrien  if (info->first_fp_reg_save != 64)
1119490075Sobrien    fprintf (stderr, "\tfirst_fp_reg_save   = %5d\n", info->first_fp_reg_save);
1119590075Sobrien
1119690075Sobrien  if (info->first_altivec_reg_save <= LAST_ALTIVEC_REGNO)
1119790075Sobrien    fprintf (stderr, "\tfirst_altivec_reg_save = %5d\n",
1119890075Sobrien	     info->first_altivec_reg_save);
1119990075Sobrien
1120090075Sobrien  if (info->lr_save_p)
1120190075Sobrien    fprintf (stderr, "\tlr_save_p           = %5d\n", info->lr_save_p);
1120290075Sobrien
1120390075Sobrien  if (info->cr_save_p)
1120490075Sobrien    fprintf (stderr, "\tcr_save_p           = %5d\n", info->cr_save_p);
1120590075Sobrien
1120690075Sobrien  if (info->toc_save_p)
1120790075Sobrien    fprintf (stderr, "\ttoc_save_p          = %5d\n", info->toc_save_p);
1120890075Sobrien
1120990075Sobrien  if (info->vrsave_mask)
1121090075Sobrien    fprintf (stderr, "\tvrsave_mask         = 0x%x\n", info->vrsave_mask);
1121190075Sobrien
1121290075Sobrien  if (info->push_p)
1121390075Sobrien    fprintf (stderr, "\tpush_p              = %5d\n", info->push_p);
1121490075Sobrien
1121590075Sobrien  if (info->calls_p)
1121690075Sobrien    fprintf (stderr, "\tcalls_p             = %5d\n", info->calls_p);
1121790075Sobrien
1121890075Sobrien  if (info->gp_save_offset)
1121990075Sobrien    fprintf (stderr, "\tgp_save_offset      = %5d\n", info->gp_save_offset);
1122090075Sobrien
1122190075Sobrien  if (info->fp_save_offset)
1122290075Sobrien    fprintf (stderr, "\tfp_save_offset      = %5d\n", info->fp_save_offset);
1122390075Sobrien
1122490075Sobrien  if (info->altivec_save_offset)
1122590075Sobrien    fprintf (stderr, "\taltivec_save_offset = %5d\n",
1122690075Sobrien	     info->altivec_save_offset);
1122790075Sobrien
11228117395Skan  if (info->spe_gp_save_offset)
11229117395Skan    fprintf (stderr, "\tspe_gp_save_offset  = %5d\n",
11230117395Skan	     info->spe_gp_save_offset);
11231117395Skan
1123290075Sobrien  if (info->vrsave_save_offset)
1123390075Sobrien    fprintf (stderr, "\tvrsave_save_offset  = %5d\n",
1123490075Sobrien	     info->vrsave_save_offset);
1123590075Sobrien
1123690075Sobrien  if (info->lr_save_offset)
1123790075Sobrien    fprintf (stderr, "\tlr_save_offset      = %5d\n", info->lr_save_offset);
1123890075Sobrien
1123990075Sobrien  if (info->cr_save_offset)
1124090075Sobrien    fprintf (stderr, "\tcr_save_offset      = %5d\n", info->cr_save_offset);
1124190075Sobrien
1124290075Sobrien  if (info->toc_save_offset)
1124390075Sobrien    fprintf (stderr, "\ttoc_save_offset     = %5d\n", info->toc_save_offset);
1124490075Sobrien
1124590075Sobrien  if (info->varargs_save_offset)
1124690075Sobrien    fprintf (stderr, "\tvarargs_save_offset = %5d\n", info->varargs_save_offset);
1124790075Sobrien
1124890075Sobrien  if (info->total_size)
11249132718Skan    fprintf (stderr, "\ttotal_size          = "HOST_WIDE_INT_PRINT_DEC"\n",
11250132718Skan	     info->total_size);
1125190075Sobrien
1125290075Sobrien  if (info->varargs_size)
1125390075Sobrien    fprintf (stderr, "\tvarargs_size        = %5d\n", info->varargs_size);
1125490075Sobrien
1125590075Sobrien  if (info->vars_size)
11256132718Skan    fprintf (stderr, "\tvars_size           = "HOST_WIDE_INT_PRINT_DEC"\n",
11257132718Skan	     info->vars_size);
1125890075Sobrien
1125990075Sobrien  if (info->parm_size)
1126090075Sobrien    fprintf (stderr, "\tparm_size           = %5d\n", info->parm_size);
1126190075Sobrien
1126290075Sobrien  if (info->fixed_size)
1126390075Sobrien    fprintf (stderr, "\tfixed_size          = %5d\n", info->fixed_size);
1126490075Sobrien
1126590075Sobrien  if (info->gp_size)
1126690075Sobrien    fprintf (stderr, "\tgp_size             = %5d\n", info->gp_size);
1126790075Sobrien
11268117395Skan  if (info->spe_gp_size)
11269117395Skan    fprintf (stderr, "\tspe_gp_size         = %5d\n", info->spe_gp_size);
11270117395Skan
1127190075Sobrien  if (info->fp_size)
1127290075Sobrien    fprintf (stderr, "\tfp_size             = %5d\n", info->fp_size);
1127390075Sobrien
1127490075Sobrien  if (info->altivec_size)
1127590075Sobrien    fprintf (stderr, "\taltivec_size        = %5d\n", info->altivec_size);
1127690075Sobrien
1127790075Sobrien  if (info->vrsave_size)
1127890075Sobrien    fprintf (stderr, "\tvrsave_size         = %5d\n", info->vrsave_size);
1127990075Sobrien
1128090075Sobrien  if (info->altivec_padding_size)
1128190075Sobrien    fprintf (stderr, "\taltivec_padding_size= %5d\n",
1128290075Sobrien	     info->altivec_padding_size);
1128390075Sobrien
11284117395Skan  if (info->spe_padding_size)
11285117395Skan    fprintf (stderr, "\tspe_padding_size    = %5d\n",
11286117395Skan	     info->spe_padding_size);
11287117395Skan
1128890075Sobrien  if (info->lr_size)
1128990075Sobrien    fprintf (stderr, "\tlr_size             = %5d\n", info->lr_size);
1129090075Sobrien
1129190075Sobrien  if (info->cr_size)
1129290075Sobrien    fprintf (stderr, "\tcr_size             = %5d\n", info->cr_size);
1129390075Sobrien
1129490075Sobrien  if (info->toc_size)
1129590075Sobrien    fprintf (stderr, "\ttoc_size            = %5d\n", info->toc_size);
1129690075Sobrien
1129790075Sobrien  if (info->save_size)
1129890075Sobrien    fprintf (stderr, "\tsave_size           = %5d\n", info->save_size);
1129990075Sobrien
1130090075Sobrien  if (info->reg_size != 4)
1130190075Sobrien    fprintf (stderr, "\treg_size            = %5d\n", info->reg_size);
1130290075Sobrien
1130390075Sobrien  fprintf (stderr, "\n");
1130490075Sobrien}
1130590075Sobrien
1130690075Sobrienrtx
11307132718Skanrs6000_return_addr (int count, rtx frame)
1130890075Sobrien{
1130990075Sobrien  /* Currently we don't optimize very well between prolog and body
1131090075Sobrien     code and for PIC code the code can be actually quite bad, so
1131190075Sobrien     don't try to be too clever here.  */
11312132718Skan  if (count != 0 || (DEFAULT_ABI != ABI_AIX && flag_pic))
1131390075Sobrien    {
1131490075Sobrien      cfun->machine->ra_needs_full_frame = 1;
1131590075Sobrien
1131690075Sobrien      return
1131790075Sobrien	gen_rtx_MEM
1131890075Sobrien	  (Pmode,
1131990075Sobrien	   memory_address
1132090075Sobrien	   (Pmode,
1132190075Sobrien	    plus_constant (copy_to_reg
1132290075Sobrien			   (gen_rtx_MEM (Pmode,
1132390075Sobrien					 memory_address (Pmode, frame))),
1132490075Sobrien			   RETURN_ADDRESS_OFFSET)));
1132590075Sobrien    }
1132690075Sobrien
11327132718Skan  cfun->machine->ra_need_lr = 1;
1132890075Sobrien  return get_hard_reg_initial_val (Pmode, LINK_REGISTER_REGNUM);
1132990075Sobrien}
1133090075Sobrien
11331117395Skan/* Say whether a function is a candidate for sibcall handling or not.
11332117395Skan   We do not allow indirect calls to be optimized into sibling calls.
11333117395Skan   Also, we can't do it if there are any vector parameters; there's
11334117395Skan   nowhere to put the VRsave code so it works; note that functions with
11335117395Skan   vector parameters are required to have a prototype, so the argument
11336117395Skan   type info must be available here.  (The tail recursion case can work
11337117395Skan   with vector parameters, but there's no way to distinguish here.) */
11338132718Skanstatic bool
11339132718Skanrs6000_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
11340117395Skan{
11341117395Skan  tree type;
11342132718Skan  if (decl)
11343117395Skan    {
11344117395Skan      if (TARGET_ALTIVEC_VRSAVE)
11345117395Skan        {
11346132718Skan	  for (type = TYPE_ARG_TYPES (TREE_TYPE (decl));
11347117395Skan	       type; type = TREE_CHAIN (type))
11348117395Skan	    {
11349117395Skan	      if (TREE_CODE (TREE_VALUE (type)) == VECTOR_TYPE)
11350132718Skan		return false;
11351117395Skan	    }
11352117395Skan        }
11353117395Skan      if (DEFAULT_ABI == ABI_DARWIN
11354132718Skan	  || (*targetm.binds_local_p) (decl))
11355117395Skan	{
11356132718Skan	  tree attr_list = TYPE_ATTRIBUTES (TREE_TYPE (decl));
11357117395Skan
11358117395Skan	  if (!lookup_attribute ("longcall", attr_list)
11359117395Skan	      || lookup_attribute ("shortcall", attr_list))
11360132718Skan	    return true;
11361117395Skan	}
11362117395Skan    }
11363132718Skan  return false;
11364117395Skan}
11365117395Skan
1136690075Sobrienstatic int
11367132718Skanrs6000_ra_ever_killed (void)
1136890075Sobrien{
1136990075Sobrien  rtx top;
11370117395Skan  rtx reg;
11371117395Skan  rtx insn;
1137290075Sobrien
11373132718Skan  if (current_function_is_thunk)
1137490075Sobrien    return 0;
1137590075Sobrien
11376117395Skan  /* regs_ever_live has LR marked as used if any sibcalls are present,
11377117395Skan     but this should not force saving and restoring in the
11378117395Skan     pro/epilogue.  Likewise, reg_set_between_p thinks a sibcall
11379132718Skan     clobbers LR, so that is inappropriate.  */
11380117395Skan
11381117395Skan  /* Also, the prologue can generate a store into LR that
11382117395Skan     doesn't really count, like this:
11383117395Skan
11384117395Skan        move LR->R0
11385117395Skan        bcl to set PIC register
11386117395Skan        move LR->R31
11387117395Skan        move R0->LR
11388117395Skan
11389117395Skan     When we're called from the epilogue, we need to avoid counting
11390117395Skan     this as a store.  */
11391117395Skan
1139290075Sobrien  push_topmost_sequence ();
1139390075Sobrien  top = get_insns ();
1139490075Sobrien  pop_topmost_sequence ();
11395117395Skan  reg = gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM);
1139690075Sobrien
11397117395Skan  for (insn = NEXT_INSN (top); insn != NULL_RTX; insn = NEXT_INSN (insn))
11398117395Skan    {
11399117395Skan      if (INSN_P (insn))
11400117395Skan	{
11401117395Skan	  if (FIND_REG_INC_NOTE (insn, reg))
11402117395Skan	    return 1;
11403117395Skan	  else if (GET_CODE (insn) == CALL_INSN
11404117395Skan		   && !SIBLING_CALL_P (insn))
11405117395Skan	    return 1;
11406117395Skan	  else if (set_of (reg, insn) != NULL_RTX
11407117395Skan		   && !prologue_epilogue_contains (insn))
11408117395Skan	    return 1;
11409117395Skan    	}
11410117395Skan    }
11411117395Skan  return 0;
1141290075Sobrien}
1141390075Sobrien
1141490075Sobrien/* Add a REG_MAYBE_DEAD note to the insn.  */
1141590075Sobrienstatic void
11416132718Skanrs6000_maybe_dead (rtx insn)
1141790075Sobrien{
1141890075Sobrien  REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD,
1141990075Sobrien					const0_rtx,
1142090075Sobrien					REG_NOTES (insn));
1142190075Sobrien}
1142290075Sobrien
1142390075Sobrien/* Emit instructions needed to load the TOC register.
1142490075Sobrien   This is only needed when TARGET_TOC, TARGET_MINIMAL_TOC, and there is
1142590075Sobrien   a constant pool; or for SVR4 -fpic.  */
1142690075Sobrien
1142790075Sobrienvoid
11428132718Skanrs6000_emit_load_toc_table (int fromprolog)
1142990075Sobrien{
11430117395Skan  rtx dest, insn;
1143196263Sobrien  dest = gen_rtx_REG (Pmode, RS6000_PIC_OFFSET_TABLE_REGNUM);
1143290075Sobrien
11433103445Skan  if (TARGET_ELF && DEFAULT_ABI == ABI_V4 && flag_pic == 1)
1143490075Sobrien    {
11435103445Skan      rtx temp = (fromprolog
11436103445Skan		  ? gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM)
11437103445Skan		  : gen_reg_rtx (Pmode));
11438117395Skan      insn = emit_insn (gen_load_toc_v4_pic_si (temp));
11439117395Skan      if (fromprolog)
11440117395Skan	rs6000_maybe_dead (insn);
11441117395Skan      insn = emit_move_insn (dest, temp);
11442117395Skan      if (fromprolog)
11443117395Skan	rs6000_maybe_dead (insn);
11444103445Skan    }
11445103445Skan  else if (TARGET_ELF && DEFAULT_ABI != ABI_AIX && flag_pic == 2)
11446103445Skan    {
11447103445Skan      char buf[30];
11448103445Skan      rtx tempLR = (fromprolog
11449103445Skan		    ? gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM)
11450103445Skan		    : gen_reg_rtx (Pmode));
11451103445Skan      rtx temp0 = (fromprolog
11452103445Skan		   ? gen_rtx_REG (Pmode, 0)
11453103445Skan		   : gen_reg_rtx (Pmode));
11454103445Skan
11455103445Skan      /* possibly create the toc section */
11456103445Skan      if (! toc_initialized)
1145790075Sobrien	{
11458103445Skan	  toc_section ();
11459103445Skan	  function_section (current_function_decl);
1146090075Sobrien	}
1146190075Sobrien
11462103445Skan      if (fromprolog)
11463103445Skan	{
11464146895Skan	  rtx symF, symL;
1146590075Sobrien
11466103445Skan	  ASM_GENERATE_INTERNAL_LABEL (buf, "LCF", rs6000_pic_labelno);
11467103445Skan	  symF = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
1146890075Sobrien
11469103445Skan	  ASM_GENERATE_INTERNAL_LABEL (buf, "LCL", rs6000_pic_labelno);
11470103445Skan	  symL = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
1147190075Sobrien
11472103445Skan	  rs6000_maybe_dead (emit_insn (gen_load_toc_v4_PIC_1 (tempLR,
11473103445Skan							       symF)));
11474103445Skan	  rs6000_maybe_dead (emit_move_insn (dest, tempLR));
11475103445Skan	  rs6000_maybe_dead (emit_insn (gen_load_toc_v4_PIC_2 (temp0, dest,
11476103445Skan							       symL,
11477103445Skan							       symF)));
11478103445Skan	}
11479103445Skan      else
11480103445Skan	{
11481103445Skan	  rtx tocsym;
1148290075Sobrien
11483103445Skan	  tocsym = gen_rtx_SYMBOL_REF (Pmode, toc_label_name);
11484146895Skan	  emit_insn (gen_load_toc_v4_PIC_1b (tempLR, tocsym));
11485117395Skan	  emit_move_insn (dest, tempLR);
11486117395Skan	  emit_move_insn (temp0, gen_rtx_MEM (Pmode, dest));
1148790075Sobrien	}
11488117395Skan      insn = emit_insn (gen_addsi3 (dest, temp0, dest));
11489117395Skan      if (fromprolog)
11490117395Skan	rs6000_maybe_dead (insn);
1149190075Sobrien    }
11492103445Skan  else if (TARGET_ELF && !TARGET_AIX && flag_pic == 0 && TARGET_MINIMAL_TOC)
1149390075Sobrien    {
11494103445Skan      /* This is for AIX code running in non-PIC ELF32.  */
11495103445Skan      char buf[30];
11496103445Skan      rtx realsym;
11497103445Skan      ASM_GENERATE_INTERNAL_LABEL (buf, "LCTOC", 1);
11498103445Skan      realsym = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
11499103445Skan
11500117395Skan      insn = emit_insn (gen_elf_high (dest, realsym));
11501117395Skan      if (fromprolog)
11502117395Skan	rs6000_maybe_dead (insn);
11503117395Skan      insn = emit_insn (gen_elf_low (dest, dest, realsym));
11504117395Skan      if (fromprolog)
11505117395Skan	rs6000_maybe_dead (insn);
11506103445Skan    }
11507103445Skan  else if (DEFAULT_ABI == ABI_AIX)
11508103445Skan    {
1150990075Sobrien      if (TARGET_32BIT)
11510117395Skan	insn = emit_insn (gen_load_toc_aix_si (dest));
1151190075Sobrien      else
11512117395Skan	insn = emit_insn (gen_load_toc_aix_di (dest));
11513117395Skan      if (fromprolog)
11514117395Skan	rs6000_maybe_dead (insn);
1151590075Sobrien    }
11516103445Skan  else
11517103445Skan    abort ();
1151890075Sobrien}
1151990075Sobrien
11520132718Skan/* Emit instructions to restore the link register after determining where
11521132718Skan   its value has been stored.  */
11522132718Skan
11523132718Skanvoid
11524132718Skanrs6000_emit_eh_reg_restore (rtx source, rtx scratch)
11525132718Skan{
11526132718Skan  rs6000_stack_t *info = rs6000_stack_info ();
11527132718Skan  rtx operands[2];
11528132718Skan
11529132718Skan  operands[0] = source;
11530132718Skan  operands[1] = scratch;
11531132718Skan
11532132718Skan  if (info->lr_save_p)
11533132718Skan    {
11534132718Skan      rtx frame_rtx = stack_pointer_rtx;
11535132718Skan      HOST_WIDE_INT sp_offset = 0;
11536132718Skan      rtx tmp;
11537132718Skan
11538132718Skan      if (frame_pointer_needed
11539132718Skan	  || current_function_calls_alloca
11540132718Skan	  || info->total_size > 32767)
11541132718Skan	{
11542132718Skan	  emit_move_insn (operands[1], gen_rtx_MEM (Pmode, frame_rtx));
11543132718Skan	  frame_rtx = operands[1];
11544132718Skan	}
11545132718Skan      else if (info->push_p)
11546132718Skan	sp_offset = info->total_size;
11547132718Skan
11548132718Skan      tmp = plus_constant (frame_rtx, info->lr_save_offset + sp_offset);
11549132718Skan      tmp = gen_rtx_MEM (Pmode, tmp);
11550132718Skan      emit_move_insn (tmp, operands[0]);
11551132718Skan    }
11552132718Skan  else
11553132718Skan    emit_move_insn (gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM), operands[0]);
11554132718Skan}
11555132718Skan
11556132718Skanstatic GTY(()) int set = -1;
11557132718Skan
1155890075Sobrienint
11559132718Skanget_TOC_alias_set (void)
1156090075Sobrien{
11561132718Skan  if (set == -1)
11562132718Skan    set = new_alias_set ();
11563132718Skan  return set;
1156490075Sobrien}
1156590075Sobrien
11566132718Skan/* This returns nonzero if the current function uses the TOC.  This is
11567132718Skan   determined by the presence of (use (unspec ... UNSPEC_TOC)), which
11568132718Skan   is generated by the ABI_V4 load_toc_* patterns.  */
11569132718Skan#if TARGET_ELF
11570132718Skanstatic int
11571132718Skanuses_TOC (void)
1157290075Sobrien{
11573132718Skan  rtx insn;
1157490075Sobrien
11575132718Skan  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
11576132718Skan    if (INSN_P (insn))
11577132718Skan      {
11578132718Skan	rtx pat = PATTERN (insn);
11579132718Skan	int i;
1158090075Sobrien
11581132718Skan	if (GET_CODE (pat) == PARALLEL)
11582132718Skan	  for (i = 0; i < XVECLEN (pat, 0); i++)
11583132718Skan	    {
11584132718Skan	      rtx sub = XVECEXP (pat, 0, i);
11585132718Skan	      if (GET_CODE (sub) == USE)
11586132718Skan		{
11587132718Skan		  sub = XEXP (sub, 0);
11588132718Skan		  if (GET_CODE (sub) == UNSPEC
11589132718Skan		      && XINT (sub, 1) == UNSPEC_TOC)
11590132718Skan		    return 1;
11591132718Skan		}
11592132718Skan	    }
11593132718Skan      }
11594132718Skan  return 0;
1159590075Sobrien}
11596132718Skan#endif
1159790075Sobrien
1159890075Sobrienrtx
11599132718Skancreate_TOC_reference (rtx symbol)
1160090075Sobrien{
11601161651Skan  if (no_new_pseudos)
11602161651Skan    regs_ever_live[TOC_REGISTER] = 1;
1160390075Sobrien  return gen_rtx_PLUS (Pmode,
1160490075Sobrien	   gen_rtx_REG (Pmode, TOC_REGISTER),
1160590075Sobrien	     gen_rtx_CONST (Pmode,
1160690075Sobrien	       gen_rtx_MINUS (Pmode, symbol,
1160790075Sobrien		 gen_rtx_SYMBOL_REF (Pmode, toc_label_name))));
1160890075Sobrien}
1160990075Sobrien
11610132718Skan/* If _Unwind_* has been called from within the same module,
11611132718Skan   toc register is not guaranteed to be saved to 40(1) on function
11612132718Skan   entry.  Save it there in that case.  */
1161390075Sobrien
1161490075Sobrienvoid
11615132718Skanrs6000_aix_emit_builtin_unwind_init (void)
1161690075Sobrien{
1161790075Sobrien  rtx mem;
1161890075Sobrien  rtx stack_top = gen_reg_rtx (Pmode);
1161990075Sobrien  rtx opcode_addr = gen_reg_rtx (Pmode);
11620132718Skan  rtx opcode = gen_reg_rtx (SImode);
11621132718Skan  rtx tocompare = gen_reg_rtx (SImode);
11622132718Skan  rtx no_toc_save_needed = gen_label_rtx ();
1162390075Sobrien
1162490075Sobrien  mem = gen_rtx_MEM (Pmode, hard_frame_pointer_rtx);
1162590075Sobrien  emit_move_insn (stack_top, mem);
1162690075Sobrien
11627132718Skan  mem = gen_rtx_MEM (Pmode,
11628132718Skan		     gen_rtx_PLUS (Pmode, stack_top,
1162990075Sobrien				   GEN_INT (2 * GET_MODE_SIZE (Pmode))));
1163090075Sobrien  emit_move_insn (opcode_addr, mem);
11631132718Skan  emit_move_insn (opcode, gen_rtx_MEM (SImode, opcode_addr));
11632132718Skan  emit_move_insn (tocompare, gen_int_mode (TARGET_32BIT ? 0x80410014
11633117395Skan					   : 0xE8410028, SImode));
1163490075Sobrien
11635132718Skan  do_compare_rtx_and_jump (opcode, tocompare, EQ, 1,
1163690075Sobrien			   SImode, NULL_RTX, NULL_RTX,
11637132718Skan			   no_toc_save_needed);
11638132718Skan
11639132718Skan  mem = gen_rtx_MEM (Pmode,
11640132718Skan		     gen_rtx_PLUS (Pmode, stack_top,
1164190075Sobrien				   GEN_INT (5 * GET_MODE_SIZE (Pmode))));
11642132718Skan  emit_move_insn (mem, gen_rtx_REG (Pmode, 2));
11643132718Skan  emit_label (no_toc_save_needed);
1164490075Sobrien}
1164590075Sobrien
1164690075Sobrien/* This ties together stack memory (MEM with an alias set of
1164790075Sobrien   rs6000_sr_alias_set) and the change to the stack pointer.  */
1164890075Sobrien
1164990075Sobrienstatic void
11650132718Skanrs6000_emit_stack_tie (void)
1165190075Sobrien{
1165290075Sobrien  rtx mem = gen_rtx_MEM (BLKmode, gen_rtx_REG (Pmode, STACK_POINTER_REGNUM));
1165390075Sobrien
1165490075Sobrien  set_mem_alias_set (mem, rs6000_sr_alias_set);
1165590075Sobrien  emit_insn (gen_stack_tie (mem));
1165690075Sobrien}
1165790075Sobrien
1165890075Sobrien/* Emit the correct code for allocating stack space, as insns.
1165990075Sobrien   If COPY_R12, make sure a copy of the old frame is left in r12.
1166090075Sobrien   The generated code may use hard register 0 as a temporary.  */
1166190075Sobrien
1166290075Sobrienstatic void
11663132718Skanrs6000_emit_allocate_stack (HOST_WIDE_INT size, int copy_r12)
1166490075Sobrien{
1166590075Sobrien  rtx insn;
1166690075Sobrien  rtx stack_reg = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
1166790075Sobrien  rtx tmp_reg = gen_rtx_REG (Pmode, 0);
1166890075Sobrien  rtx todec = GEN_INT (-size);
1166990075Sobrien
1167090075Sobrien  if (current_function_limit_stack)
1167190075Sobrien    {
1167290075Sobrien      if (REG_P (stack_limit_rtx)
1167390075Sobrien	  && REGNO (stack_limit_rtx) > 1
1167490075Sobrien	  && REGNO (stack_limit_rtx) <= 31)
1167590075Sobrien	{
11676132718Skan	  emit_insn (TARGET_32BIT
1167790075Sobrien		     ? gen_addsi3 (tmp_reg,
1167890075Sobrien				   stack_limit_rtx,
1167990075Sobrien				   GEN_INT (size))
1168090075Sobrien		     : gen_adddi3 (tmp_reg,
1168190075Sobrien				   stack_limit_rtx,
1168290075Sobrien				   GEN_INT (size)));
11683132718Skan
1168490075Sobrien	  emit_insn (gen_cond_trap (LTU, stack_reg, tmp_reg,
1168590075Sobrien				    const0_rtx));
1168690075Sobrien	}
1168790075Sobrien      else if (GET_CODE (stack_limit_rtx) == SYMBOL_REF
1168890075Sobrien	       && TARGET_32BIT
1168990075Sobrien	       && DEFAULT_ABI == ABI_V4)
1169090075Sobrien	{
1169190075Sobrien	  rtx toload = gen_rtx_CONST (VOIDmode,
1169290075Sobrien				      gen_rtx_PLUS (Pmode,
1169390075Sobrien						    stack_limit_rtx,
1169490075Sobrien						    GEN_INT (size)));
11695132718Skan
1169690075Sobrien	  emit_insn (gen_elf_high (tmp_reg, toload));
1169790075Sobrien	  emit_insn (gen_elf_low (tmp_reg, tmp_reg, toload));
1169890075Sobrien	  emit_insn (gen_cond_trap (LTU, stack_reg, tmp_reg,
1169990075Sobrien				    const0_rtx));
1170090075Sobrien	}
1170190075Sobrien      else
1170290075Sobrien	warning ("stack limit expression is not supported");
1170390075Sobrien    }
1170490075Sobrien
1170590075Sobrien  if (copy_r12 || ! TARGET_UPDATE)
1170690075Sobrien    emit_move_insn (gen_rtx_REG (Pmode, 12), stack_reg);
1170790075Sobrien
1170890075Sobrien  if (TARGET_UPDATE)
1170990075Sobrien    {
1171090075Sobrien      if (size > 32767)
1171190075Sobrien	{
1171290075Sobrien	  /* Need a note here so that try_split doesn't get confused.  */
1171390075Sobrien	  if (get_last_insn() == NULL_RTX)
11714132718Skan	    emit_note (NOTE_INSN_DELETED);
1171590075Sobrien	  insn = emit_move_insn (tmp_reg, todec);
1171690075Sobrien	  try_split (PATTERN (insn), insn, 0);
1171790075Sobrien	  todec = tmp_reg;
1171890075Sobrien	}
11719132718Skan
11720132718Skan      insn = emit_insn (TARGET_32BIT
11721132718Skan			? gen_movsi_update (stack_reg, stack_reg,
11722132718Skan					    todec, stack_reg)
11723132718Skan			: gen_movdi_update (stack_reg, stack_reg,
1172490075Sobrien					    todec, stack_reg));
1172590075Sobrien    }
1172690075Sobrien  else
1172790075Sobrien    {
11728132718Skan      insn = emit_insn (TARGET_32BIT
11729132718Skan			? gen_addsi3 (stack_reg, stack_reg, todec)
11730132718Skan			: gen_adddi3 (stack_reg, stack_reg, todec));
1173190075Sobrien      emit_move_insn (gen_rtx_MEM (Pmode, stack_reg),
1173290075Sobrien		      gen_rtx_REG (Pmode, 12));
1173390075Sobrien    }
11734132718Skan
1173590075Sobrien  RTX_FRAME_RELATED_P (insn) = 1;
1173690075Sobrien  REG_NOTES (insn) =
1173790075Sobrien    gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
1173890075Sobrien		       gen_rtx_SET (VOIDmode, stack_reg,
1173990075Sobrien				    gen_rtx_PLUS (Pmode, stack_reg,
1174090075Sobrien						  GEN_INT (-size))),
1174190075Sobrien		       REG_NOTES (insn));
1174290075Sobrien}
1174390075Sobrien
1174490075Sobrien/* Add to 'insn' a note which is PATTERN (INSN) but with REG replaced
1174590075Sobrien   with (plus:P (reg 1) VAL), and with REG2 replaced with RREG if REG2
1174690075Sobrien   is not NULL.  It would be nice if dwarf2out_frame_debug_expr could
1174790075Sobrien   deduce these equivalences by itself so it wasn't necessary to hold
1174890075Sobrien   its hand so much.  */
1174990075Sobrien
1175090075Sobrienstatic void
11751132718Skanrs6000_frame_related (rtx insn, rtx reg, HOST_WIDE_INT val,
11752132718Skan		      rtx reg2, rtx rreg)
1175390075Sobrien{
1175490075Sobrien  rtx real, temp;
1175590075Sobrien
11756117395Skan  /* copy_rtx will not make unique copies of registers, so we need to
11757117395Skan     ensure we don't have unwanted sharing here.  */
11758117395Skan  if (reg == reg2)
11759117395Skan    reg = gen_raw_REG (GET_MODE (reg), REGNO (reg));
11760117395Skan
11761117395Skan  if (reg == rreg)
11762117395Skan    reg = gen_raw_REG (GET_MODE (reg), REGNO (reg));
11763117395Skan
1176490075Sobrien  real = copy_rtx (PATTERN (insn));
1176590075Sobrien
11766117395Skan  if (reg2 != NULL_RTX)
11767117395Skan    real = replace_rtx (real, reg2, rreg);
11768117395Skan
1176990075Sobrien  real = replace_rtx (real, reg,
1177090075Sobrien		      gen_rtx_PLUS (Pmode, gen_rtx_REG (Pmode,
1177190075Sobrien							STACK_POINTER_REGNUM),
1177290075Sobrien				    GEN_INT (val)));
1177390075Sobrien
1177490075Sobrien  /* We expect that 'real' is either a SET or a PARALLEL containing
1177590075Sobrien     SETs (and possibly other stuff).  In a PARALLEL, all the SETs
1177690075Sobrien     are important so they all have to be marked RTX_FRAME_RELATED_P.  */
1177790075Sobrien
1177890075Sobrien  if (GET_CODE (real) == SET)
1177990075Sobrien    {
1178090075Sobrien      rtx set = real;
1178190075Sobrien
1178290075Sobrien      temp = simplify_rtx (SET_SRC (set));
1178390075Sobrien      if (temp)
1178490075Sobrien	SET_SRC (set) = temp;
1178590075Sobrien      temp = simplify_rtx (SET_DEST (set));
1178690075Sobrien      if (temp)
1178790075Sobrien	SET_DEST (set) = temp;
1178890075Sobrien      if (GET_CODE (SET_DEST (set)) == MEM)
1178990075Sobrien	{
1179090075Sobrien	  temp = simplify_rtx (XEXP (SET_DEST (set), 0));
1179190075Sobrien	  if (temp)
1179290075Sobrien	    XEXP (SET_DEST (set), 0) = temp;
1179390075Sobrien	}
1179490075Sobrien    }
1179590075Sobrien  else if (GET_CODE (real) == PARALLEL)
1179690075Sobrien    {
1179790075Sobrien      int i;
1179890075Sobrien      for (i = 0; i < XVECLEN (real, 0); i++)
1179990075Sobrien	if (GET_CODE (XVECEXP (real, 0, i)) == SET)
1180090075Sobrien	  {
1180190075Sobrien	    rtx set = XVECEXP (real, 0, i);
1180290075Sobrien
1180390075Sobrien	    temp = simplify_rtx (SET_SRC (set));
1180490075Sobrien	    if (temp)
1180590075Sobrien	      SET_SRC (set) = temp;
1180690075Sobrien	    temp = simplify_rtx (SET_DEST (set));
1180790075Sobrien	    if (temp)
1180890075Sobrien	      SET_DEST (set) = temp;
1180990075Sobrien	    if (GET_CODE (SET_DEST (set)) == MEM)
1181090075Sobrien	      {
1181190075Sobrien		temp = simplify_rtx (XEXP (SET_DEST (set), 0));
1181290075Sobrien		if (temp)
1181390075Sobrien		  XEXP (SET_DEST (set), 0) = temp;
1181490075Sobrien	      }
1181590075Sobrien	    RTX_FRAME_RELATED_P (set) = 1;
1181690075Sobrien	  }
1181790075Sobrien    }
1181890075Sobrien  else
1181990075Sobrien    abort ();
11820132718Skan
11821132718Skan  if (TARGET_SPE)
11822132718Skan    real = spe_synthesize_frame_save (real);
11823132718Skan
1182490075Sobrien  RTX_FRAME_RELATED_P (insn) = 1;
1182590075Sobrien  REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
1182690075Sobrien					real,
1182790075Sobrien					REG_NOTES (insn));
1182890075Sobrien}
1182990075Sobrien
11830132718Skan/* Given an SPE frame note, return a PARALLEL of SETs with the
11831132718Skan   original note, plus a synthetic register save.  */
11832132718Skan
11833132718Skanstatic rtx
11834132718Skanspe_synthesize_frame_save (rtx real)
11835132718Skan{
11836132718Skan  rtx synth, offset, reg, real2;
11837132718Skan
11838132718Skan  if (GET_CODE (real) != SET
11839132718Skan      || GET_MODE (SET_SRC (real)) != V2SImode)
11840132718Skan    return real;
11841132718Skan
11842132718Skan  /* For the SPE, registers saved in 64-bits, get a PARALLEL for their
11843132718Skan     frame related note.  The parallel contains a set of the register
11844132718Skan     being saved, and another set to a synthetic register (n+1200).
11845132718Skan     This is so we can differentiate between 64-bit and 32-bit saves.
11846132718Skan     Words cannot describe this nastiness.  */
11847132718Skan
11848132718Skan  if (GET_CODE (SET_DEST (real)) != MEM
11849132718Skan      || GET_CODE (XEXP (SET_DEST (real), 0)) != PLUS
11850132718Skan      || GET_CODE (SET_SRC (real)) != REG)
11851132718Skan    abort ();
11852132718Skan
11853132718Skan  /* Transform:
11854132718Skan       (set (mem (plus (reg x) (const y)))
11855132718Skan            (reg z))
11856132718Skan     into:
11857132718Skan       (set (mem (plus (reg x) (const y+4)))
11858132718Skan            (reg z+1200))
11859132718Skan  */
11860132718Skan
11861132718Skan  real2 = copy_rtx (real);
11862132718Skan  PUT_MODE (SET_DEST (real2), SImode);
11863132718Skan  reg = SET_SRC (real2);
11864132718Skan  real2 = replace_rtx (real2, reg, gen_rtx_REG (SImode, REGNO (reg)));
11865132718Skan  synth = copy_rtx (real2);
11866132718Skan
11867132718Skan  if (BYTES_BIG_ENDIAN)
11868132718Skan    {
11869132718Skan      offset = XEXP (XEXP (SET_DEST (real2), 0), 1);
11870132718Skan      real2 = replace_rtx (real2, offset, GEN_INT (INTVAL (offset) + 4));
11871132718Skan    }
11872132718Skan
11873132718Skan  reg = SET_SRC (synth);
11874132718Skan
11875132718Skan  synth = replace_rtx (synth, reg,
11876132718Skan		       gen_rtx_REG (SImode, REGNO (reg) + 1200));
11877132718Skan
11878132718Skan  offset = XEXP (XEXP (SET_DEST (synth), 0), 1);
11879132718Skan  synth = replace_rtx (synth, offset,
11880132718Skan		       GEN_INT (INTVAL (offset)
11881132718Skan				+ (BYTES_BIG_ENDIAN ? 0 : 4)));
11882132718Skan
11883132718Skan  RTX_FRAME_RELATED_P (synth) = 1;
11884132718Skan  RTX_FRAME_RELATED_P (real2) = 1;
11885132718Skan  if (BYTES_BIG_ENDIAN)
11886132718Skan    real = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, synth, real2));
11887132718Skan  else
11888132718Skan    real = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, real2, synth));
11889132718Skan
11890132718Skan  return real;
11891132718Skan}
11892132718Skan
1189390075Sobrien/* Returns an insn that has a vrsave set operation with the
1189490075Sobrien   appropriate CLOBBERs.  */
1189590075Sobrien
1189690075Sobrienstatic rtx
11897132718Skangenerate_set_vrsave (rtx reg, rs6000_stack_t *info, int epiloguep)
1189890075Sobrien{
1189990075Sobrien  int nclobs, i;
1190090075Sobrien  rtx insn, clobs[TOTAL_ALTIVEC_REGS + 1];
1190190075Sobrien  rtx vrsave = gen_rtx_REG (SImode, VRSAVE_REGNO);
1190290075Sobrien
1190390075Sobrien  clobs[0]
1190490075Sobrien    = gen_rtx_SET (VOIDmode,
1190590075Sobrien		   vrsave,
1190690075Sobrien		   gen_rtx_UNSPEC_VOLATILE (SImode,
1190790075Sobrien					    gen_rtvec (2, reg, vrsave),
1190890075Sobrien					    30));
1190990075Sobrien
1191090075Sobrien  nclobs = 1;
1191190075Sobrien
1191290075Sobrien  /* We need to clobber the registers in the mask so the scheduler
1191390075Sobrien     does not move sets to VRSAVE before sets of AltiVec registers.
1191490075Sobrien
1191590075Sobrien     However, if the function receives nonlocal gotos, reload will set
1191690075Sobrien     all call saved registers live.  We will end up with:
1191790075Sobrien
1191890075Sobrien     	(set (reg 999) (mem))
1191990075Sobrien	(parallel [ (set (reg vrsave) (unspec blah))
1192090075Sobrien		    (clobber (reg 999))])
1192190075Sobrien
1192290075Sobrien     The clobber will cause the store into reg 999 to be dead, and
1192390075Sobrien     flow will attempt to delete an epilogue insn.  In this case, we
1192490075Sobrien     need an unspec use/set of the register.  */
1192590075Sobrien
1192690075Sobrien  for (i = FIRST_ALTIVEC_REGNO; i <= LAST_ALTIVEC_REGNO; ++i)
11927132718Skan    if (info->vrsave_mask & ALTIVEC_REG_BIT (i))
1192890075Sobrien      {
1192990075Sobrien	if (!epiloguep || call_used_regs [i])
1193090075Sobrien	  clobs[nclobs++] = gen_rtx_CLOBBER (VOIDmode,
1193190075Sobrien					     gen_rtx_REG (V4SImode, i));
1193290075Sobrien	else
1193390075Sobrien	  {
1193490075Sobrien	    rtx reg = gen_rtx_REG (V4SImode, i);
1193590075Sobrien
1193690075Sobrien	    clobs[nclobs++]
1193790075Sobrien	      = gen_rtx_SET (VOIDmode,
1193890075Sobrien			     reg,
1193990075Sobrien			     gen_rtx_UNSPEC (V4SImode,
1194090075Sobrien					     gen_rtvec (1, reg), 27));
1194190075Sobrien	  }
1194290075Sobrien      }
1194390075Sobrien
1194490075Sobrien  insn = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (nclobs));
1194590075Sobrien
1194690075Sobrien  for (i = 0; i < nclobs; ++i)
1194790075Sobrien    XVECEXP (insn, 0, i) = clobs[i];
1194890075Sobrien
1194990075Sobrien  return insn;
1195090075Sobrien}
1195190075Sobrien
11952117395Skan/* Save a register into the frame, and emit RTX_FRAME_RELATED_P notes.
11953117395Skan   Save REGNO into [FRAME_REG + OFFSET] in mode MODE.  */
11954117395Skan
11955117395Skanstatic void
11956132718Skanemit_frame_save (rtx frame_reg, rtx frame_ptr, enum machine_mode mode,
11957132718Skan		 unsigned int regno, int offset, HOST_WIDE_INT total_size)
11958117395Skan{
11959117395Skan  rtx reg, offset_rtx, insn, mem, addr, int_rtx;
11960117395Skan  rtx replacea, replaceb;
11961117395Skan
11962117395Skan  int_rtx = GEN_INT (offset);
11963117395Skan
11964117395Skan  /* Some cases that need register indexed addressing.  */
11965117395Skan  if ((TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
11966117395Skan      || (TARGET_SPE_ABI
11967117395Skan	  && SPE_VECTOR_MODE (mode)
11968117395Skan	  && !SPE_CONST_OFFSET_OK (offset)))
11969117395Skan    {
11970117395Skan      /* Whomever calls us must make sure r11 is available in the
11971117395Skan         flow path of instructions in the prologue.  */
11972117395Skan      offset_rtx = gen_rtx_REG (Pmode, 11);
11973117395Skan      emit_move_insn (offset_rtx, int_rtx);
11974117395Skan
11975117395Skan      replacea = offset_rtx;
11976117395Skan      replaceb = int_rtx;
11977117395Skan    }
11978117395Skan  else
11979117395Skan    {
11980117395Skan      offset_rtx = int_rtx;
11981117395Skan      replacea = NULL_RTX;
11982117395Skan      replaceb = NULL_RTX;
11983117395Skan    }
11984117395Skan
11985117395Skan  reg = gen_rtx_REG (mode, regno);
11986117395Skan  addr = gen_rtx_PLUS (Pmode, frame_reg, offset_rtx);
11987117395Skan  mem = gen_rtx_MEM (mode, addr);
11988117395Skan  set_mem_alias_set (mem, rs6000_sr_alias_set);
11989117395Skan
11990117395Skan  insn = emit_move_insn (mem, reg);
11991117395Skan
11992117395Skan  rs6000_frame_related (insn, frame_ptr, total_size, replacea, replaceb);
11993117395Skan}
11994117395Skan
11995117395Skan/* Emit an offset memory reference suitable for a frame store, while
11996117395Skan   converting to a valid addressing mode.  */
11997117395Skan
11998117395Skanstatic rtx
11999132718Skangen_frame_mem_offset (enum machine_mode mode, rtx reg, int offset)
12000117395Skan{
12001117395Skan  rtx int_rtx, offset_rtx;
12002117395Skan
12003117395Skan  int_rtx = GEN_INT (offset);
12004117395Skan
12005117395Skan  if (TARGET_SPE_ABI && SPE_VECTOR_MODE (mode))
12006117395Skan    {
12007117395Skan      offset_rtx = gen_rtx_REG (Pmode, FIXED_SCRATCH);
12008117395Skan      emit_move_insn (offset_rtx, int_rtx);
12009117395Skan    }
12010117395Skan  else
12011117395Skan    offset_rtx = int_rtx;
12012117395Skan
12013117395Skan  return gen_rtx_MEM (mode, gen_rtx_PLUS (Pmode, reg, offset_rtx));
12014117395Skan}
12015117395Skan
1201690075Sobrien/* Emit function prologue as insns.  */
1201790075Sobrien
1201890075Sobrienvoid
12019132718Skanrs6000_emit_prologue (void)
1202090075Sobrien{
1202190075Sobrien  rs6000_stack_t *info = rs6000_stack_info ();
12022132718Skan  enum machine_mode reg_mode = Pmode;
12023132718Skan  int reg_size = TARGET_32BIT ? 4 : 8;
1202490075Sobrien  rtx sp_reg_rtx = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
1202590075Sobrien  rtx frame_ptr_rtx = gen_rtx_REG (Pmode, 12);
1202690075Sobrien  rtx frame_reg_rtx = sp_reg_rtx;
12027132718Skan  rtx cr_save_rtx = NULL_RTX;
1202890075Sobrien  rtx insn;
1202990075Sobrien  int saving_FPRs_inline;
1203090075Sobrien  int using_store_multiple;
1203190075Sobrien  HOST_WIDE_INT sp_offset = 0;
1203290075Sobrien
12033132718Skan   if (TARGET_SPE_ABI && info->spe_64bit_regs_used != 0)
12034117395Skan     {
12035117395Skan       reg_mode = V2SImode;
12036117395Skan       reg_size = 8;
12037117395Skan     }
12038117395Skan
1203990075Sobrien  using_store_multiple = (TARGET_MULTIPLE && ! TARGET_POWERPC64
12040132718Skan			  && (!TARGET_SPE_ABI
12041132718Skan			      || info->spe_64bit_regs_used == 0)
1204290075Sobrien			  && info->first_gp_reg_save < 31);
1204390075Sobrien  saving_FPRs_inline = (info->first_fp_reg_save == 64
12044132718Skan			|| FP_SAVE_INLINE (info->first_fp_reg_save)
12045132718Skan			|| current_function_calls_eh_return
12046132718Skan			|| cfun->machine->ra_need_lr);
1204790075Sobrien
1204890075Sobrien  /* For V.4, update stack before we do any saving and set back pointer.  */
12049132718Skan  if (info->push_p
12050132718Skan      && (DEFAULT_ABI == ABI_V4
12051132718Skan	  || current_function_calls_eh_return))
1205290075Sobrien    {
1205390075Sobrien      if (info->total_size < 32767)
1205490075Sobrien	sp_offset = info->total_size;
1205590075Sobrien      else
1205690075Sobrien	frame_reg_rtx = frame_ptr_rtx;
1205790075Sobrien      rs6000_emit_allocate_stack (info->total_size,
1205890075Sobrien				  (frame_reg_rtx != sp_reg_rtx
1205990075Sobrien				   && (info->cr_save_p
1206090075Sobrien				       || info->lr_save_p
1206190075Sobrien				       || info->first_fp_reg_save < 64
1206290075Sobrien				       || info->first_gp_reg_save < 32
1206390075Sobrien				       )));
1206490075Sobrien      if (frame_reg_rtx != sp_reg_rtx)
1206590075Sobrien	rs6000_emit_stack_tie ();
1206690075Sobrien    }
1206790075Sobrien
1206890075Sobrien  /* Save AltiVec registers if needed.  */
1206990075Sobrien  if (TARGET_ALTIVEC_ABI && info->altivec_size != 0)
1207090075Sobrien    {
1207190075Sobrien      int i;
1207290075Sobrien
1207390075Sobrien      /* There should be a non inline version of this, for when we
1207490075Sobrien	 are saving lots of vector registers.  */
1207590075Sobrien      for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i)
1207690075Sobrien	if (info->vrsave_mask & ALTIVEC_REG_BIT (i))
1207790075Sobrien	  {
1207890075Sobrien	    rtx areg, savereg, mem;
1207990075Sobrien	    int offset;
1208090075Sobrien
1208190075Sobrien	    offset = info->altivec_save_offset + sp_offset
1208290075Sobrien	      + 16 * (i - info->first_altivec_reg_save);
1208390075Sobrien
1208490075Sobrien	    savereg = gen_rtx_REG (V4SImode, i);
1208590075Sobrien
1208690075Sobrien	    areg = gen_rtx_REG (Pmode, 0);
1208790075Sobrien	    emit_move_insn (areg, GEN_INT (offset));
1208890075Sobrien
1208990075Sobrien	    /* AltiVec addressing mode is [reg+reg].  */
1209090075Sobrien	    mem = gen_rtx_MEM (V4SImode,
1209190075Sobrien			       gen_rtx_PLUS (Pmode, frame_reg_rtx, areg));
1209290075Sobrien
1209390075Sobrien	    set_mem_alias_set (mem, rs6000_sr_alias_set);
1209490075Sobrien
1209590075Sobrien	    insn = emit_move_insn (mem, savereg);
1209690075Sobrien
12097132718Skan	    rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
12098132718Skan				  areg, GEN_INT (offset));
1209990075Sobrien	  }
1210090075Sobrien    }
1210190075Sobrien
1210290075Sobrien  /* VRSAVE is a bit vector representing which AltiVec registers
1210390075Sobrien     are used.  The OS uses this to determine which vector
1210490075Sobrien     registers to save on a context switch.  We need to save
1210590075Sobrien     VRSAVE on the stack frame, add whatever AltiVec registers we
1210690075Sobrien     used in this function, and do the corresponding magic in the
1210790075Sobrien     epilogue.  */
1210890075Sobrien
12109132718Skan  if (TARGET_ALTIVEC && TARGET_ALTIVEC_VRSAVE
12110132718Skan      && info->vrsave_mask != 0)
1211190075Sobrien    {
1211290075Sobrien      rtx reg, mem, vrsave;
1211390075Sobrien      int offset;
1211490075Sobrien
12115146895Skan      /* Get VRSAVE onto a GPR.  Note that ABI_V4 might be using r12
12116146895Skan	 as frame_reg_rtx and r11 as the static chain pointer for
12117146895Skan	 nested functions.  */
12118146895Skan      reg = gen_rtx_REG (SImode, 0);
1211990075Sobrien      vrsave = gen_rtx_REG (SImode, VRSAVE_REGNO);
1212096263Sobrien      if (TARGET_MACHO)
1212196263Sobrien	emit_insn (gen_get_vrsave_internal (reg));
1212296263Sobrien      else
1212396263Sobrien	emit_insn (gen_rtx_SET (VOIDmode, reg, vrsave));
1212490075Sobrien
1212590075Sobrien      /* Save VRSAVE.  */
1212690075Sobrien      offset = info->vrsave_save_offset + sp_offset;
1212790075Sobrien      mem
1212890075Sobrien	= gen_rtx_MEM (SImode,
1212990075Sobrien		       gen_rtx_PLUS (Pmode, frame_reg_rtx, GEN_INT (offset)));
1213090075Sobrien      set_mem_alias_set (mem, rs6000_sr_alias_set);
1213190075Sobrien      insn = emit_move_insn (mem, reg);
1213290075Sobrien
1213390075Sobrien      /* Include the registers in the mask.  */
1213490075Sobrien      emit_insn (gen_iorsi3 (reg, reg, GEN_INT ((int) info->vrsave_mask)));
1213590075Sobrien
1213690075Sobrien      insn = emit_insn (generate_set_vrsave (reg, info, 0));
1213790075Sobrien    }
1213890075Sobrien
1213990075Sobrien  /* If we use the link register, get it into r0.  */
1214090075Sobrien  if (info->lr_save_p)
1214190075Sobrien    emit_move_insn (gen_rtx_REG (Pmode, 0),
1214290075Sobrien		    gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM));
1214390075Sobrien
1214490075Sobrien  /* If we need to save CR, put it into r12.  */
1214590075Sobrien  if (info->cr_save_p && frame_reg_rtx != frame_ptr_rtx)
1214690075Sobrien    {
1214790075Sobrien      cr_save_rtx = gen_rtx_REG (SImode, 12);
1214890075Sobrien      emit_insn (gen_movesi_from_cr (cr_save_rtx));
1214990075Sobrien    }
1215090075Sobrien
1215190075Sobrien  /* Do any required saving of fpr's.  If only one or two to save, do
1215290075Sobrien     it ourselves.  Otherwise, call function.  */
1215390075Sobrien  if (saving_FPRs_inline)
1215490075Sobrien    {
1215590075Sobrien      int i;
1215690075Sobrien      for (i = 0; i < 64 - info->first_fp_reg_save; i++)
1215790075Sobrien	if ((regs_ever_live[info->first_fp_reg_save+i]
1215890075Sobrien	     && ! call_used_regs[info->first_fp_reg_save+i]))
12159117395Skan	  emit_frame_save (frame_reg_rtx, frame_ptr_rtx, DFmode,
12160117395Skan			   info->first_fp_reg_save + i,
12161117395Skan			   info->fp_save_offset + sp_offset + 8 * i,
12162117395Skan			   info->total_size);
1216390075Sobrien    }
1216490075Sobrien  else if (info->first_fp_reg_save != 64)
1216590075Sobrien    {
1216690075Sobrien      int i;
1216790075Sobrien      char rname[30];
1216890075Sobrien      const char *alloc_rname;
1216990075Sobrien      rtvec p;
1217090075Sobrien      p = rtvec_alloc (2 + 64 - info->first_fp_reg_save);
1217190075Sobrien
1217290075Sobrien      RTVEC_ELT (p, 0) = gen_rtx_CLOBBER (VOIDmode,
1217390075Sobrien					  gen_rtx_REG (Pmode,
1217490075Sobrien						       LINK_REGISTER_REGNUM));
1217590075Sobrien      sprintf (rname, "%s%d%s", SAVE_FP_PREFIX,
1217690075Sobrien	       info->first_fp_reg_save - 32, SAVE_FP_SUFFIX);
1217790075Sobrien      alloc_rname = ggc_strdup (rname);
1217890075Sobrien      RTVEC_ELT (p, 1) = gen_rtx_USE (VOIDmode,
1217990075Sobrien				      gen_rtx_SYMBOL_REF (Pmode,
1218090075Sobrien							  alloc_rname));
1218190075Sobrien      for (i = 0; i < 64 - info->first_fp_reg_save; i++)
1218290075Sobrien	{
1218390075Sobrien	  rtx addr, reg, mem;
1218490075Sobrien	  reg = gen_rtx_REG (DFmode, info->first_fp_reg_save + i);
1218590075Sobrien	  addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
1218690075Sobrien			       GEN_INT (info->fp_save_offset
1218790075Sobrien					+ sp_offset + 8*i));
1218890075Sobrien	  mem = gen_rtx_MEM (DFmode, addr);
1218990075Sobrien	  set_mem_alias_set (mem, rs6000_sr_alias_set);
1219090075Sobrien
1219190075Sobrien	  RTVEC_ELT (p, i + 2) = gen_rtx_SET (VOIDmode, mem, reg);
1219290075Sobrien	}
1219390075Sobrien      insn = emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
1219490075Sobrien      rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
1219590075Sobrien			    NULL_RTX, NULL_RTX);
1219690075Sobrien    }
1219790075Sobrien
1219890075Sobrien  /* Save GPRs.  This is done as a PARALLEL if we are using
1219990075Sobrien     the store-multiple instructions.  */
1220090075Sobrien  if (using_store_multiple)
1220190075Sobrien    {
12202117395Skan      rtvec p;
1220390075Sobrien      int i;
1220490075Sobrien      p = rtvec_alloc (32 - info->first_gp_reg_save);
1220590075Sobrien      for (i = 0; i < 32 - info->first_gp_reg_save; i++)
1220690075Sobrien	{
1220790075Sobrien	  rtx addr, reg, mem;
1220890075Sobrien	  reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
1220990075Sobrien	  addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
1221090075Sobrien			       GEN_INT (info->gp_save_offset
1221190075Sobrien					+ sp_offset
1221290075Sobrien					+ reg_size * i));
1221390075Sobrien	  mem = gen_rtx_MEM (reg_mode, addr);
1221490075Sobrien	  set_mem_alias_set (mem, rs6000_sr_alias_set);
1221590075Sobrien
1221690075Sobrien	  RTVEC_ELT (p, i) = gen_rtx_SET (VOIDmode, mem, reg);
1221790075Sobrien	}
1221890075Sobrien      insn = emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
1221990075Sobrien      rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
1222090075Sobrien			    NULL_RTX, NULL_RTX);
1222190075Sobrien    }
1222290075Sobrien  else
1222390075Sobrien    {
1222490075Sobrien      int i;
1222590075Sobrien      for (i = 0; i < 32 - info->first_gp_reg_save; i++)
1222690075Sobrien	if ((regs_ever_live[info->first_gp_reg_save+i]
12227146895Skan	     && (! call_used_regs[info->first_gp_reg_save+i]
12228146895Skan		 || (i+info->first_gp_reg_save
12229146895Skan		     == RS6000_PIC_OFFSET_TABLE_REGNUM
12230146895Skan		     && TARGET_TOC && TARGET_MINIMAL_TOC)))
1223196263Sobrien	    || (i+info->first_gp_reg_save == RS6000_PIC_OFFSET_TABLE_REGNUM
12232117395Skan		&& ((DEFAULT_ABI == ABI_V4 && flag_pic != 0)
1223390075Sobrien		    || (DEFAULT_ABI == ABI_DARWIN && flag_pic))))
1223490075Sobrien	  {
1223590075Sobrien	    rtx addr, reg, mem;
1223690075Sobrien	    reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
1223790075Sobrien
12238132718Skan	    if (TARGET_SPE_ABI && info->spe_64bit_regs_used != 0)
12239117395Skan	      {
12240117395Skan		int offset = info->spe_gp_save_offset + sp_offset + 8 * i;
12241117395Skan		rtx b;
12242117395Skan
12243117395Skan		if (!SPE_CONST_OFFSET_OK (offset))
12244117395Skan		  {
12245117395Skan		    b = gen_rtx_REG (Pmode, FIXED_SCRATCH);
12246117395Skan		    emit_move_insn (b, GEN_INT (offset));
12247117395Skan		  }
12248117395Skan		else
12249117395Skan		  b = GEN_INT (offset);
12250117395Skan
12251117395Skan		addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, b);
12252117395Skan		mem = gen_rtx_MEM (V2SImode, addr);
12253117395Skan		set_mem_alias_set (mem, rs6000_sr_alias_set);
12254117395Skan		insn = emit_move_insn (mem, reg);
12255117395Skan
12256117395Skan		if (GET_CODE (b) == CONST_INT)
12257117395Skan		  rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
12258117395Skan					NULL_RTX, NULL_RTX);
12259117395Skan		else
12260117395Skan		  rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
12261117395Skan					b, GEN_INT (offset));
12262117395Skan	      }
12263117395Skan	    else
12264117395Skan	      {
12265117395Skan		addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
12266117395Skan				     GEN_INT (info->gp_save_offset
12267117395Skan					      + sp_offset
12268117395Skan					      + reg_size * i));
12269117395Skan		mem = gen_rtx_MEM (reg_mode, addr);
12270117395Skan		set_mem_alias_set (mem, rs6000_sr_alias_set);
12271117395Skan
12272117395Skan		insn = emit_move_insn (mem, reg);
12273117395Skan		rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
12274117395Skan				      NULL_RTX, NULL_RTX);
12275117395Skan	      }
1227690075Sobrien	  }
1227790075Sobrien    }
1227890075Sobrien
1227990075Sobrien  /* ??? There's no need to emit actual instructions here, but it's the
1228090075Sobrien     easiest way to get the frame unwind information emitted.  */
1228190075Sobrien  if (current_function_calls_eh_return)
1228290075Sobrien    {
1228390075Sobrien      unsigned int i, regno;
1228490075Sobrien
12285132718Skan      /* In AIX ABI we need to pretend we save r2 here.  */
12286132718Skan      if (TARGET_AIX)
12287132718Skan	{
12288132718Skan	  rtx addr, reg, mem;
12289132718Skan
12290132718Skan	  reg = gen_rtx_REG (reg_mode, 2);
12291132718Skan	  addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
12292132718Skan			       GEN_INT (sp_offset + 5 * reg_size));
12293132718Skan	  mem = gen_rtx_MEM (reg_mode, addr);
12294132718Skan	  set_mem_alias_set (mem, rs6000_sr_alias_set);
12295132718Skan
12296132718Skan	  insn = emit_move_insn (mem, reg);
12297132718Skan	  rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
12298132718Skan				NULL_RTX, NULL_RTX);
12299132718Skan	  PATTERN (insn) = gen_blockage ();
12300132718Skan	}
12301132718Skan
1230290075Sobrien      for (i = 0; ; ++i)
1230390075Sobrien	{
1230490075Sobrien	  regno = EH_RETURN_DATA_REGNO (i);
1230590075Sobrien	  if (regno == INVALID_REGNUM)
1230690075Sobrien	    break;
1230790075Sobrien
12308117395Skan	  emit_frame_save (frame_reg_rtx, frame_ptr_rtx, reg_mode, regno,
12309117395Skan			   info->ehrd_offset + sp_offset
12310117395Skan			   + reg_size * (int) i,
12311117395Skan			   info->total_size);
1231290075Sobrien	}
1231390075Sobrien    }
1231490075Sobrien
1231590075Sobrien  /* Save lr if we used it.  */
1231690075Sobrien  if (info->lr_save_p)
1231790075Sobrien    {
1231890075Sobrien      rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
1231990075Sobrien			       GEN_INT (info->lr_save_offset + sp_offset));
1232090075Sobrien      rtx reg = gen_rtx_REG (Pmode, 0);
1232190075Sobrien      rtx mem = gen_rtx_MEM (Pmode, addr);
1232290075Sobrien      /* This should not be of rs6000_sr_alias_set, because of
1232390075Sobrien	 __builtin_return_address.  */
1232490075Sobrien
1232590075Sobrien      insn = emit_move_insn (mem, reg);
1232690075Sobrien      rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
1232790075Sobrien			    reg, gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM));
1232890075Sobrien    }
1232990075Sobrien
1233090075Sobrien  /* Save CR if we use any that must be preserved.  */
1233190075Sobrien  if (info->cr_save_p)
1233290075Sobrien    {
1233390075Sobrien      rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
1233490075Sobrien			       GEN_INT (info->cr_save_offset + sp_offset));
1233590075Sobrien      rtx mem = gen_rtx_MEM (SImode, addr);
1233690075Sobrien
1233790075Sobrien      set_mem_alias_set (mem, rs6000_sr_alias_set);
1233890075Sobrien
1233990075Sobrien      /* If r12 was used to hold the original sp, copy cr into r0 now
1234090075Sobrien	 that it's free.  */
1234190075Sobrien      if (REGNO (frame_reg_rtx) == 12)
1234290075Sobrien	{
1234390075Sobrien	  cr_save_rtx = gen_rtx_REG (SImode, 0);
1234490075Sobrien	  emit_insn (gen_movesi_from_cr (cr_save_rtx));
1234590075Sobrien	}
1234690075Sobrien      insn = emit_move_insn (mem, cr_save_rtx);
1234790075Sobrien
1234890075Sobrien      /* Now, there's no way that dwarf2out_frame_debug_expr is going
12349132718Skan	 to understand '(unspec:SI [(reg:CC 68) ...] UNSPEC_MOVESI_FROM_CR)'.
12350132718Skan	 But that's OK.  All we have to do is specify that _one_ condition
12351132718Skan	 code register is saved in this stack slot.  The thrower's epilogue
1235290075Sobrien	 will then restore all the call-saved registers.
1235390075Sobrien	 We use CR2_REGNO (70) to be compatible with gcc-2.95 on Linux.  */
1235490075Sobrien      rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
1235590075Sobrien			    cr_save_rtx, gen_rtx_REG (SImode, CR2_REGNO));
1235690075Sobrien    }
1235790075Sobrien
1235890075Sobrien  /* Update stack and set back pointer unless this is V.4,
1235990075Sobrien     for which it was done previously.  */
12360132718Skan  if (info->push_p
12361132718Skan      && !(DEFAULT_ABI == ABI_V4 || current_function_calls_eh_return))
1236290075Sobrien    rs6000_emit_allocate_stack (info->total_size, FALSE);
1236390075Sobrien
1236490075Sobrien  /* Set frame pointer, if needed.  */
1236590075Sobrien  if (frame_pointer_needed)
1236690075Sobrien    {
12367117395Skan      insn = emit_move_insn (gen_rtx_REG (Pmode, FRAME_POINTER_REGNUM),
1236890075Sobrien			     sp_reg_rtx);
1236990075Sobrien      RTX_FRAME_RELATED_P (insn) = 1;
1237090075Sobrien    }
1237190075Sobrien
1237296263Sobrien  /* If we are using RS6000_PIC_OFFSET_TABLE_REGNUM, we need to set it up.  */
1237390075Sobrien  if ((TARGET_TOC && TARGET_MINIMAL_TOC && get_pool_size () != 0)
1237490075Sobrien      || (DEFAULT_ABI == ABI_V4 && flag_pic == 1
1237596263Sobrien	  && regs_ever_live[RS6000_PIC_OFFSET_TABLE_REGNUM]))
1237690075Sobrien  {
1237790075Sobrien    /* If emit_load_toc_table will use the link register, we need to save
12378132718Skan       it.  We use R12 for this purpose because emit_load_toc_table
1237990075Sobrien       can use register 0.  This allows us to use a plain 'blr' to return
1238090075Sobrien       from the procedure more often.  */
12381132718Skan    int save_LR_around_toc_setup = (TARGET_ELF
12382132718Skan				    && DEFAULT_ABI != ABI_AIX
12383132718Skan				    && flag_pic
1238490075Sobrien				    && ! info->lr_save_p
1238590075Sobrien				    && EXIT_BLOCK_PTR->pred != NULL);
1238690075Sobrien    if (save_LR_around_toc_setup)
12387132718Skan      {
12388132718Skan	rtx lr = gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM);
12389132718Skan	rs6000_maybe_dead (emit_move_insn (frame_ptr_rtx, lr));
12390132718Skan	rs6000_emit_load_toc_table (TRUE);
12391132718Skan	rs6000_maybe_dead (emit_move_insn (lr, frame_ptr_rtx));
12392132718Skan      }
12393132718Skan    else
12394132718Skan      rs6000_emit_load_toc_table (TRUE);
1239590075Sobrien  }
1239690075Sobrien
12397117395Skan#if TARGET_MACHO
1239890075Sobrien  if (DEFAULT_ABI == ABI_DARWIN
1239990075Sobrien      && flag_pic && current_function_uses_pic_offset_table)
1240090075Sobrien    {
1240190075Sobrien      rtx dest = gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM);
12402132718Skan      const char *picbase = machopic_function_base_name ();
12403132718Skan      rtx src = gen_rtx_SYMBOL_REF (Pmode, picbase);
1240490075Sobrien
12405117395Skan      rs6000_maybe_dead (emit_insn (gen_load_macho_picbase (dest, src)));
1240690075Sobrien
1240790075Sobrien      rs6000_maybe_dead (
1240896263Sobrien	emit_move_insn (gen_rtx_REG (Pmode, RS6000_PIC_OFFSET_TABLE_REGNUM),
1240990075Sobrien			gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM)));
1241090075Sobrien    }
12411117395Skan#endif
1241290075Sobrien}
1241390075Sobrien
1241490075Sobrien/* Write function prologue.  */
1241590075Sobrien
1241690075Sobrienstatic void
12417132718Skanrs6000_output_function_prologue (FILE *file,
12418132718Skan				 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
1241990075Sobrien{
1242090075Sobrien  rs6000_stack_t *info = rs6000_stack_info ();
1242190075Sobrien
1242290075Sobrien  if (TARGET_DEBUG_STACK)
1242390075Sobrien    debug_stack_info (info);
1242490075Sobrien
1242590075Sobrien  /* Write .extern for any function we will call to save and restore
1242690075Sobrien     fp values.  */
1242790075Sobrien  if (info->first_fp_reg_save < 64
1242890075Sobrien      && !FP_SAVE_INLINE (info->first_fp_reg_save))
1242990075Sobrien    fprintf (file, "\t.extern %s%d%s\n\t.extern %s%d%s\n",
1243090075Sobrien	     SAVE_FP_PREFIX, info->first_fp_reg_save - 32, SAVE_FP_SUFFIX,
1243190075Sobrien	     RESTORE_FP_PREFIX, info->first_fp_reg_save - 32,
1243290075Sobrien	     RESTORE_FP_SUFFIX);
1243390075Sobrien
1243490075Sobrien  /* Write .extern for AIX common mode routines, if needed.  */
1243590075Sobrien  if (! TARGET_POWER && ! TARGET_POWERPC && ! common_mode_defined)
1243690075Sobrien    {
1243790075Sobrien      fputs ("\t.extern __mulh\n", file);
1243890075Sobrien      fputs ("\t.extern __mull\n", file);
1243990075Sobrien      fputs ("\t.extern __divss\n", file);
1244090075Sobrien      fputs ("\t.extern __divus\n", file);
1244190075Sobrien      fputs ("\t.extern __quoss\n", file);
1244290075Sobrien      fputs ("\t.extern __quous\n", file);
1244390075Sobrien      common_mode_defined = 1;
1244490075Sobrien    }
1244590075Sobrien
1244690075Sobrien  if (! HAVE_prologue)
1244790075Sobrien    {
1244890075Sobrien      start_sequence ();
1244996263Sobrien
1245090075Sobrien      /* A NOTE_INSN_DELETED is supposed to be at the start and end of
1245190075Sobrien	 the "toplevel" insn chain.  */
12452132718Skan      emit_note (NOTE_INSN_DELETED);
1245390075Sobrien      rs6000_emit_prologue ();
12454132718Skan      emit_note (NOTE_INSN_DELETED);
1245596263Sobrien
12456132718Skan      /* Expand INSN_ADDRESSES so final() doesn't crash.  */
1245796263Sobrien      {
1245896263Sobrien	rtx insn;
1245996263Sobrien	unsigned addr = 0;
1246096263Sobrien	for (insn = get_insns (); insn != 0; insn = NEXT_INSN (insn))
1246196263Sobrien	  {
1246296263Sobrien	    INSN_ADDRESSES_NEW (insn, addr);
1246396263Sobrien	    addr += 4;
1246496263Sobrien	  }
1246596263Sobrien      }
1246696263Sobrien
1246790075Sobrien      if (TARGET_DEBUG_STACK)
1246890075Sobrien	debug_rtx_list (get_insns (), 100);
1246990075Sobrien      final (get_insns (), file, FALSE, FALSE);
1247090075Sobrien      end_sequence ();
1247190075Sobrien    }
1247290075Sobrien
1247390075Sobrien  rs6000_pic_labelno++;
1247490075Sobrien}
1247590075Sobrien
1247690075Sobrien/* Emit function epilogue as insns.
1247790075Sobrien
1247890075Sobrien   At present, dwarf2out_frame_debug_expr doesn't understand
1247990075Sobrien   register restores, so we don't bother setting RTX_FRAME_RELATED_P
1248090075Sobrien   anywhere in the epilogue.  Most of the insns below would in any case
1248190075Sobrien   need special notes to explain where r11 is in relation to the stack.  */
1248290075Sobrien
1248390075Sobrienvoid
12484132718Skanrs6000_emit_epilogue (int sibcall)
1248590075Sobrien{
1248690075Sobrien  rs6000_stack_t *info;
1248790075Sobrien  int restoring_FPRs_inline;
1248890075Sobrien  int using_load_multiple;
1248990075Sobrien  int using_mfcr_multiple;
1249090075Sobrien  int use_backchain_to_restore_sp;
1249190075Sobrien  int sp_offset = 0;
1249290075Sobrien  rtx sp_reg_rtx = gen_rtx_REG (Pmode, 1);
1249390075Sobrien  rtx frame_reg_rtx = sp_reg_rtx;
12494132718Skan  enum machine_mode reg_mode = Pmode;
12495132718Skan  int reg_size = TARGET_32BIT ? 4 : 8;
1249690075Sobrien  int i;
1249790075Sobrien
12498132718Skan  info = rs6000_stack_info ();
12499132718Skan
12500132718Skan  if (TARGET_SPE_ABI && info->spe_64bit_regs_used != 0)
12501117395Skan    {
12502117395Skan      reg_mode = V2SImode;
12503117395Skan      reg_size = 8;
12504117395Skan    }
12505117395Skan
1250690075Sobrien  using_load_multiple = (TARGET_MULTIPLE && ! TARGET_POWERPC64
12507132718Skan			 && (!TARGET_SPE_ABI
12508132718Skan			     || info->spe_64bit_regs_used == 0)
1250990075Sobrien			 && info->first_gp_reg_save < 31);
1251090075Sobrien  restoring_FPRs_inline = (sibcall
1251190075Sobrien			   || current_function_calls_eh_return
1251290075Sobrien			   || info->first_fp_reg_save == 64
1251390075Sobrien			   || FP_SAVE_INLINE (info->first_fp_reg_save));
1251490075Sobrien  use_backchain_to_restore_sp = (frame_pointer_needed
1251590075Sobrien				 || current_function_calls_alloca
1251690075Sobrien				 || info->total_size > 32767);
1251790075Sobrien  using_mfcr_multiple = (rs6000_cpu == PROCESSOR_PPC601
1251890075Sobrien			 || rs6000_cpu == PROCESSOR_PPC603
1251990075Sobrien			 || rs6000_cpu == PROCESSOR_PPC750
1252090075Sobrien			 || optimize_size);
1252190075Sobrien
1252290075Sobrien  /* If we have a frame pointer, a call to alloca,  or a large stack
1252390075Sobrien     frame, restore the old stack pointer using the backchain.  Otherwise,
1252490075Sobrien     we know what size to update it with.  */
1252590075Sobrien  if (use_backchain_to_restore_sp)
1252690075Sobrien    {
1252790075Sobrien      /* Under V.4, don't reset the stack pointer until after we're done
1252890075Sobrien	 loading the saved registers.  */
1252990075Sobrien      if (DEFAULT_ABI == ABI_V4)
1253090075Sobrien	frame_reg_rtx = gen_rtx_REG (Pmode, 11);
1253190075Sobrien
1253290075Sobrien      emit_move_insn (frame_reg_rtx,
1253390075Sobrien		      gen_rtx_MEM (Pmode, sp_reg_rtx));
1253490075Sobrien
1253590075Sobrien    }
1253690075Sobrien  else if (info->push_p)
1253790075Sobrien    {
12538132718Skan      if (DEFAULT_ABI == ABI_V4
12539132718Skan	  || current_function_calls_eh_return)
1254090075Sobrien	sp_offset = info->total_size;
1254190075Sobrien      else
1254290075Sobrien	{
1254390075Sobrien	  emit_insn (TARGET_32BIT
1254490075Sobrien		     ? gen_addsi3 (sp_reg_rtx, sp_reg_rtx,
1254590075Sobrien				   GEN_INT (info->total_size))
1254690075Sobrien		     : gen_adddi3 (sp_reg_rtx, sp_reg_rtx,
1254790075Sobrien				   GEN_INT (info->total_size)));
1254890075Sobrien	}
1254990075Sobrien    }
1255090075Sobrien
1255190075Sobrien  /* Restore AltiVec registers if needed.  */
1255290075Sobrien  if (TARGET_ALTIVEC_ABI && info->altivec_size != 0)
1255390075Sobrien    {
1255490075Sobrien      int i;
1255590075Sobrien
1255690075Sobrien      for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i)
1255790075Sobrien	if (info->vrsave_mask & ALTIVEC_REG_BIT (i))
1255890075Sobrien	  {
1255990075Sobrien	    rtx addr, areg, mem;
1256090075Sobrien
1256190075Sobrien	    areg = gen_rtx_REG (Pmode, 0);
1256290075Sobrien	    emit_move_insn
1256390075Sobrien	      (areg, GEN_INT (info->altivec_save_offset
1256490075Sobrien			      + sp_offset
1256590075Sobrien			      + 16 * (i - info->first_altivec_reg_save)));
1256690075Sobrien
1256790075Sobrien	    /* AltiVec addressing mode is [reg+reg].  */
1256890075Sobrien	    addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, areg);
1256990075Sobrien	    mem = gen_rtx_MEM (V4SImode, addr);
1257090075Sobrien	    set_mem_alias_set (mem, rs6000_sr_alias_set);
1257190075Sobrien
1257290075Sobrien	    emit_move_insn (gen_rtx_REG (V4SImode, i), mem);
1257390075Sobrien	  }
1257490075Sobrien    }
1257590075Sobrien
1257690075Sobrien  /* Restore VRSAVE if needed.  */
12577132718Skan  if (TARGET_ALTIVEC && TARGET_ALTIVEC_VRSAVE
12578132718Skan      && info->vrsave_mask != 0)
1257990075Sobrien    {
1258090075Sobrien      rtx addr, mem, reg;
1258190075Sobrien
1258290075Sobrien      addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
1258390075Sobrien			   GEN_INT (info->vrsave_save_offset + sp_offset));
1258490075Sobrien      mem = gen_rtx_MEM (SImode, addr);
1258590075Sobrien      set_mem_alias_set (mem, rs6000_sr_alias_set);
1258690075Sobrien      reg = gen_rtx_REG (SImode, 12);
1258790075Sobrien      emit_move_insn (reg, mem);
1258890075Sobrien
1258990075Sobrien      emit_insn (generate_set_vrsave (reg, info, 1));
1259090075Sobrien    }
1259190075Sobrien
1259290075Sobrien  /* Get the old lr if we saved it.  */
1259390075Sobrien  if (info->lr_save_p)
1259490075Sobrien    {
12595117395Skan      rtx mem = gen_frame_mem_offset (Pmode, frame_reg_rtx,
12596117395Skan				      info->lr_save_offset + sp_offset);
1259790075Sobrien
1259890075Sobrien      set_mem_alias_set (mem, rs6000_sr_alias_set);
1259990075Sobrien
1260090075Sobrien      emit_move_insn (gen_rtx_REG (Pmode, 0), mem);
1260190075Sobrien    }
1260290075Sobrien
1260390075Sobrien  /* Get the old cr if we saved it.  */
1260490075Sobrien  if (info->cr_save_p)
1260590075Sobrien    {
1260690075Sobrien      rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
1260790075Sobrien			       GEN_INT (info->cr_save_offset + sp_offset));
1260890075Sobrien      rtx mem = gen_rtx_MEM (SImode, addr);
1260990075Sobrien
1261090075Sobrien      set_mem_alias_set (mem, rs6000_sr_alias_set);
1261190075Sobrien
1261290075Sobrien      emit_move_insn (gen_rtx_REG (SImode, 12), mem);
1261390075Sobrien    }
1261490075Sobrien
1261590075Sobrien  /* Set LR here to try to overlap restores below.  */
1261690075Sobrien  if (info->lr_save_p)
1261790075Sobrien    emit_move_insn (gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM),
1261890075Sobrien		    gen_rtx_REG (Pmode, 0));
1261990075Sobrien
1262090075Sobrien  /* Load exception handler data registers, if needed.  */
1262190075Sobrien  if (current_function_calls_eh_return)
1262290075Sobrien    {
1262390075Sobrien      unsigned int i, regno;
1262490075Sobrien
12625132718Skan      if (TARGET_AIX)
12626132718Skan	{
12627132718Skan	  rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
12628132718Skan				   GEN_INT (sp_offset + 5 * reg_size));
12629132718Skan	  rtx mem = gen_rtx_MEM (reg_mode, addr);
12630132718Skan
12631132718Skan	  set_mem_alias_set (mem, rs6000_sr_alias_set);
12632132718Skan
12633132718Skan	  emit_move_insn (gen_rtx_REG (reg_mode, 2), mem);
12634132718Skan	}
12635132718Skan
1263690075Sobrien      for (i = 0; ; ++i)
1263790075Sobrien	{
12638117395Skan	  rtx mem;
1263990075Sobrien
1264090075Sobrien	  regno = EH_RETURN_DATA_REGNO (i);
1264190075Sobrien	  if (regno == INVALID_REGNUM)
1264290075Sobrien	    break;
1264390075Sobrien
12644117395Skan	  mem = gen_frame_mem_offset (reg_mode, frame_reg_rtx,
12645117395Skan				      info->ehrd_offset + sp_offset
12646117395Skan				      + reg_size * (int) i);
1264790075Sobrien	  set_mem_alias_set (mem, rs6000_sr_alias_set);
1264890075Sobrien
1264990075Sobrien	  emit_move_insn (gen_rtx_REG (reg_mode, regno), mem);
1265090075Sobrien	}
1265190075Sobrien    }
1265290075Sobrien
1265390075Sobrien  /* Restore GPRs.  This is done as a PARALLEL if we are using
1265490075Sobrien     the load-multiple instructions.  */
1265590075Sobrien  if (using_load_multiple)
1265690075Sobrien    {
1265790075Sobrien      rtvec p;
1265890075Sobrien      p = rtvec_alloc (32 - info->first_gp_reg_save);
1265990075Sobrien      for (i = 0; i < 32 - info->first_gp_reg_save; i++)
1266090075Sobrien	{
1266190075Sobrien	  rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
1266290075Sobrien				   GEN_INT (info->gp_save_offset
1266390075Sobrien					    + sp_offset
1266490075Sobrien					    + reg_size * i));
1266590075Sobrien	  rtx mem = gen_rtx_MEM (reg_mode, addr);
1266690075Sobrien
1266790075Sobrien	  set_mem_alias_set (mem, rs6000_sr_alias_set);
1266890075Sobrien
1266990075Sobrien	  RTVEC_ELT (p, i) =
1267090075Sobrien	    gen_rtx_SET (VOIDmode,
1267190075Sobrien			 gen_rtx_REG (reg_mode, info->first_gp_reg_save + i),
1267290075Sobrien			 mem);
1267390075Sobrien	}
1267490075Sobrien      emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
1267590075Sobrien    }
1267690075Sobrien  else
1267790075Sobrien    for (i = 0; i < 32 - info->first_gp_reg_save; i++)
1267890075Sobrien      if ((regs_ever_live[info->first_gp_reg_save+i]
12679146895Skan	   && (! call_used_regs[info->first_gp_reg_save+i]
12680146895Skan	       || (i+info->first_gp_reg_save == RS6000_PIC_OFFSET_TABLE_REGNUM
12681146895Skan		   && TARGET_TOC && TARGET_MINIMAL_TOC)))
1268296263Sobrien	  || (i+info->first_gp_reg_save == RS6000_PIC_OFFSET_TABLE_REGNUM
12683117395Skan	      && ((DEFAULT_ABI == ABI_V4 && flag_pic != 0)
1268490075Sobrien		  || (DEFAULT_ABI == ABI_DARWIN && flag_pic))))
1268590075Sobrien	{
1268690075Sobrien	  rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
1268790075Sobrien				   GEN_INT (info->gp_save_offset
1268890075Sobrien					    + sp_offset
1268990075Sobrien					    + reg_size * i));
1269090075Sobrien	  rtx mem = gen_rtx_MEM (reg_mode, addr);
1269190075Sobrien
12692117395Skan	  /* Restore 64-bit quantities for SPE.  */
12693132718Skan	  if (TARGET_SPE_ABI && info->spe_64bit_regs_used != 0)
12694117395Skan	    {
12695117395Skan	      int offset = info->spe_gp_save_offset + sp_offset + 8 * i;
12696117395Skan	      rtx b;
12697117395Skan
12698117395Skan	      if (!SPE_CONST_OFFSET_OK (offset))
12699117395Skan		{
12700117395Skan		  b = gen_rtx_REG (Pmode, FIXED_SCRATCH);
12701117395Skan		  emit_move_insn (b, GEN_INT (offset));
12702117395Skan		}
12703117395Skan	      else
12704117395Skan		b = GEN_INT (offset);
12705117395Skan
12706117395Skan	      addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, b);
12707117395Skan	      mem = gen_rtx_MEM (V2SImode, addr);
12708117395Skan	    }
12709117395Skan
1271090075Sobrien	  set_mem_alias_set (mem, rs6000_sr_alias_set);
1271190075Sobrien
1271290075Sobrien	  emit_move_insn (gen_rtx_REG (reg_mode,
12713117395Skan				       info->first_gp_reg_save + i), mem);
1271490075Sobrien	}
1271590075Sobrien
1271690075Sobrien  /* Restore fpr's if we need to do it without calling a function.  */
1271790075Sobrien  if (restoring_FPRs_inline)
1271890075Sobrien    for (i = 0; i < 64 - info->first_fp_reg_save; i++)
1271990075Sobrien      if ((regs_ever_live[info->first_fp_reg_save+i]
1272090075Sobrien	   && ! call_used_regs[info->first_fp_reg_save+i]))
1272190075Sobrien	{
1272290075Sobrien	  rtx addr, mem;
1272390075Sobrien	  addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
1272490075Sobrien			       GEN_INT (info->fp_save_offset
1272590075Sobrien					+ sp_offset
1272690075Sobrien					+ 8 * i));
1272790075Sobrien	  mem = gen_rtx_MEM (DFmode, addr);
1272890075Sobrien	  set_mem_alias_set (mem, rs6000_sr_alias_set);
1272990075Sobrien
1273090075Sobrien	  emit_move_insn (gen_rtx_REG (DFmode,
1273190075Sobrien				       info->first_fp_reg_save + i),
1273290075Sobrien			  mem);
1273390075Sobrien	}
1273490075Sobrien
1273590075Sobrien  /* If we saved cr, restore it here.  Just those that were used.  */
1273690075Sobrien  if (info->cr_save_p)
1273790075Sobrien    {
1273890075Sobrien      rtx r12_rtx = gen_rtx_REG (SImode, 12);
1273990075Sobrien      int count = 0;
1274090075Sobrien
1274190075Sobrien      if (using_mfcr_multiple)
1274290075Sobrien	{
1274390075Sobrien	  for (i = 0; i < 8; i++)
1274490075Sobrien	    if (regs_ever_live[CR0_REGNO+i] && ! call_used_regs[CR0_REGNO+i])
1274590075Sobrien	      count++;
1274690075Sobrien	  if (count == 0)
1274790075Sobrien	    abort ();
1274890075Sobrien	}
1274990075Sobrien
1275090075Sobrien      if (using_mfcr_multiple && count > 1)
1275190075Sobrien	{
1275290075Sobrien	  rtvec p;
1275390075Sobrien	  int ndx;
1275490075Sobrien
1275590075Sobrien	  p = rtvec_alloc (count);
1275690075Sobrien
1275790075Sobrien	  ndx = 0;
1275890075Sobrien	  for (i = 0; i < 8; i++)
1275990075Sobrien	    if (regs_ever_live[CR0_REGNO+i] && ! call_used_regs[CR0_REGNO+i])
1276090075Sobrien	      {
1276190075Sobrien		rtvec r = rtvec_alloc (2);
1276290075Sobrien		RTVEC_ELT (r, 0) = r12_rtx;
1276390075Sobrien		RTVEC_ELT (r, 1) = GEN_INT (1 << (7-i));
1276490075Sobrien		RTVEC_ELT (p, ndx) =
1276590075Sobrien		  gen_rtx_SET (VOIDmode, gen_rtx_REG (CCmode, CR0_REGNO+i),
12766132718Skan			       gen_rtx_UNSPEC (CCmode, r, UNSPEC_MOVESI_TO_CR));
1276790075Sobrien		ndx++;
1276890075Sobrien	      }
1276990075Sobrien	  emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
1277090075Sobrien	  if (ndx != count)
1277190075Sobrien	    abort ();
1277290075Sobrien	}
1277390075Sobrien      else
1277490075Sobrien	for (i = 0; i < 8; i++)
1277590075Sobrien	  if (regs_ever_live[CR0_REGNO+i] && ! call_used_regs[CR0_REGNO+i])
1277690075Sobrien	    {
1277790075Sobrien	      emit_insn (gen_movsi_to_cr_one (gen_rtx_REG (CCmode,
1277890075Sobrien							   CR0_REGNO+i),
1277990075Sobrien					      r12_rtx));
1278090075Sobrien	    }
1278190075Sobrien    }
1278290075Sobrien
1278390075Sobrien  /* If this is V.4, unwind the stack pointer after all of the loads
1278490075Sobrien     have been done.  We need to emit a block here so that sched
1278590075Sobrien     doesn't decide to move the sp change before the register restores
1278690075Sobrien     (which may not have any obvious dependency on the stack).  This
1278790075Sobrien     doesn't hurt performance, because there is no scheduling that can
1278890075Sobrien     be done after this point.  */
12789132718Skan  if (DEFAULT_ABI == ABI_V4
12790132718Skan      || current_function_calls_eh_return)
1279190075Sobrien    {
1279290075Sobrien      if (frame_reg_rtx != sp_reg_rtx)
1279390075Sobrien	  rs6000_emit_stack_tie ();
1279490075Sobrien
1279590075Sobrien      if (use_backchain_to_restore_sp)
1279690075Sobrien	{
1279790075Sobrien	  emit_move_insn (sp_reg_rtx, frame_reg_rtx);
1279890075Sobrien	}
1279990075Sobrien      else if (sp_offset != 0)
1280090075Sobrien	{
12801132718Skan	  emit_insn (TARGET_32BIT
1280290075Sobrien		     ? gen_addsi3 (sp_reg_rtx, sp_reg_rtx,
1280390075Sobrien				   GEN_INT (sp_offset))
1280490075Sobrien		     : gen_adddi3 (sp_reg_rtx, sp_reg_rtx,
1280590075Sobrien				   GEN_INT (sp_offset)));
1280690075Sobrien	}
1280790075Sobrien    }
1280890075Sobrien
1280990075Sobrien  if (current_function_calls_eh_return)
1281090075Sobrien    {
1281190075Sobrien      rtx sa = EH_RETURN_STACKADJ_RTX;
12812132718Skan      emit_insn (TARGET_32BIT
1281390075Sobrien		 ? gen_addsi3 (sp_reg_rtx, sp_reg_rtx, sa)
1281490075Sobrien		 : gen_adddi3 (sp_reg_rtx, sp_reg_rtx, sa));
1281590075Sobrien    }
1281690075Sobrien
1281790075Sobrien  if (!sibcall)
1281890075Sobrien    {
1281990075Sobrien      rtvec p;
1282090075Sobrien      if (! restoring_FPRs_inline)
1282190075Sobrien	p = rtvec_alloc (3 + 64 - info->first_fp_reg_save);
1282290075Sobrien      else
1282390075Sobrien	p = rtvec_alloc (2);
1282490075Sobrien
1282590075Sobrien      RTVEC_ELT (p, 0) = gen_rtx_RETURN (VOIDmode);
1282690075Sobrien      RTVEC_ELT (p, 1) = gen_rtx_USE (VOIDmode,
1282790075Sobrien				      gen_rtx_REG (Pmode,
1282890075Sobrien						   LINK_REGISTER_REGNUM));
1282990075Sobrien
1283090075Sobrien      /* If we have to restore more than two FP registers, branch to the
1283190075Sobrien	 restore function.  It will return to our caller.  */
1283290075Sobrien      if (! restoring_FPRs_inline)
1283390075Sobrien	{
1283490075Sobrien	  int i;
1283590075Sobrien	  char rname[30];
1283690075Sobrien	  const char *alloc_rname;
1283790075Sobrien
1283890075Sobrien	  sprintf (rname, "%s%d%s", RESTORE_FP_PREFIX,
1283990075Sobrien		   info->first_fp_reg_save - 32, RESTORE_FP_SUFFIX);
1284090075Sobrien	  alloc_rname = ggc_strdup (rname);
1284190075Sobrien	  RTVEC_ELT (p, 2) = gen_rtx_USE (VOIDmode,
1284290075Sobrien					  gen_rtx_SYMBOL_REF (Pmode,
1284390075Sobrien							      alloc_rname));
1284490075Sobrien
1284590075Sobrien	  for (i = 0; i < 64 - info->first_fp_reg_save; i++)
1284690075Sobrien	    {
1284790075Sobrien	      rtx addr, mem;
1284890075Sobrien	      addr = gen_rtx_PLUS (Pmode, sp_reg_rtx,
1284990075Sobrien				   GEN_INT (info->fp_save_offset + 8*i));
1285090075Sobrien	      mem = gen_rtx_MEM (DFmode, addr);
1285190075Sobrien	      set_mem_alias_set (mem, rs6000_sr_alias_set);
1285290075Sobrien
1285390075Sobrien	      RTVEC_ELT (p, i+3) =
1285490075Sobrien		gen_rtx_SET (VOIDmode,
1285590075Sobrien			     gen_rtx_REG (DFmode, info->first_fp_reg_save + i),
1285690075Sobrien			     mem);
1285790075Sobrien	    }
1285890075Sobrien	}
1285990075Sobrien
1286090075Sobrien      emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, p));
1286190075Sobrien    }
1286290075Sobrien}
1286390075Sobrien
1286490075Sobrien/* Write function epilogue.  */
1286590075Sobrien
1286690075Sobrienstatic void
12867132718Skanrs6000_output_function_epilogue (FILE *file,
12868132718Skan				 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
1286990075Sobrien{
1287090075Sobrien  rs6000_stack_t *info = rs6000_stack_info ();
1287190075Sobrien
1287290075Sobrien  if (! HAVE_epilogue)
1287390075Sobrien    {
1287490075Sobrien      rtx insn = get_last_insn ();
1287590075Sobrien      /* If the last insn was a BARRIER, we don't have to write anything except
1287690075Sobrien	 the trace table.  */
1287790075Sobrien      if (GET_CODE (insn) == NOTE)
1287890075Sobrien	insn = prev_nonnote_insn (insn);
1287990075Sobrien      if (insn == 0 ||  GET_CODE (insn) != BARRIER)
1288090075Sobrien	{
1288190075Sobrien	  /* This is slightly ugly, but at least we don't have two
1288290075Sobrien	     copies of the epilogue-emitting code.  */
1288390075Sobrien	  start_sequence ();
1288490075Sobrien
1288590075Sobrien	  /* A NOTE_INSN_DELETED is supposed to be at the start
1288690075Sobrien	     and end of the "toplevel" insn chain.  */
12887132718Skan	  emit_note (NOTE_INSN_DELETED);
1288890075Sobrien	  rs6000_emit_epilogue (FALSE);
12889132718Skan	  emit_note (NOTE_INSN_DELETED);
1289090075Sobrien
12891132718Skan	  /* Expand INSN_ADDRESSES so final() doesn't crash.  */
1289296263Sobrien	  {
1289396263Sobrien	    rtx insn;
1289496263Sobrien	    unsigned addr = 0;
1289596263Sobrien	    for (insn = get_insns (); insn != 0; insn = NEXT_INSN (insn))
1289696263Sobrien	      {
1289796263Sobrien		INSN_ADDRESSES_NEW (insn, addr);
1289896263Sobrien		addr += 4;
1289996263Sobrien	      }
1290096263Sobrien	  }
1290196263Sobrien
1290290075Sobrien	  if (TARGET_DEBUG_STACK)
1290390075Sobrien	    debug_rtx_list (get_insns (), 100);
1290490075Sobrien	  final (get_insns (), file, FALSE, FALSE);
1290590075Sobrien	  end_sequence ();
1290690075Sobrien	}
1290790075Sobrien    }
1290890075Sobrien
12909132718Skan#if TARGET_MACHO
12910132718Skan  macho_branch_islands ();
12911119256Skan  /* Mach-O doesn't support labels at the end of objects, so if
12912119256Skan     it looks like we might want one, insert a NOP.  */
12913119256Skan  {
12914119256Skan    rtx insn = get_last_insn ();
12915119256Skan    while (insn
12916119256Skan	   && NOTE_P (insn)
12917119256Skan	   && NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED_LABEL)
12918119256Skan      insn = PREV_INSN (insn);
12919119256Skan    if (insn
12920119256Skan	&& (LABEL_P (insn)
12921119256Skan	    || (NOTE_P (insn)
12922119256Skan		&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED_LABEL)))
12923119256Skan      fputs ("\tnop\n", file);
12924119256Skan  }
12925119256Skan#endif
12926119256Skan
1292790075Sobrien  /* Output a traceback table here.  See /usr/include/sys/debug.h for info
1292890075Sobrien     on its format.
1292990075Sobrien
1293090075Sobrien     We don't output a traceback table if -finhibit-size-directive was
1293190075Sobrien     used.  The documentation for -finhibit-size-directive reads
1293290075Sobrien     ``don't output a @code{.size} assembler directive, or anything
1293390075Sobrien     else that would cause trouble if the function is split in the
1293490075Sobrien     middle, and the two halves are placed at locations far apart in
1293590075Sobrien     memory.''  The traceback table has this property, since it
1293690075Sobrien     includes the offset from the start of the function to the
1293790075Sobrien     traceback table itself.
1293890075Sobrien
1293990075Sobrien     System V.4 Powerpc's (and the embedded ABI derived from it) use a
1294090075Sobrien     different traceback table.  */
12941117395Skan  if (DEFAULT_ABI == ABI_AIX && ! flag_inhibit_size_directive
12942117395Skan      && rs6000_traceback != traceback_none)
1294390075Sobrien    {
12944117395Skan      const char *fname = NULL;
1294590075Sobrien      const char *language_string = lang_hooks.name;
1294690075Sobrien      int fixed_parms = 0, float_parms = 0, parm_info = 0;
1294790075Sobrien      int i;
12948117395Skan      int optional_tbtab;
1294990075Sobrien
12950117395Skan      if (rs6000_traceback == traceback_full)
12951117395Skan	optional_tbtab = 1;
12952117395Skan      else if (rs6000_traceback == traceback_part)
12953117395Skan	optional_tbtab = 0;
12954117395Skan      else
12955117395Skan	optional_tbtab = !optimize_size && !TARGET_ELF;
1295690075Sobrien
12957117395Skan      if (optional_tbtab)
12958117395Skan	{
12959117395Skan	  fname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
12960117395Skan	  while (*fname == '.')	/* V.4 encodes . in the name */
12961117395Skan	    fname++;
1296290075Sobrien
12963117395Skan	  /* Need label immediately before tbtab, so we can compute
12964117395Skan	     its offset from the function start.  */
12965117395Skan	  ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "LT");
12966117395Skan	  ASM_OUTPUT_LABEL (file, fname);
12967117395Skan	}
12968117395Skan
1296990075Sobrien      /* The .tbtab pseudo-op can only be used for the first eight
1297090075Sobrien	 expressions, since it can't handle the possibly variable
1297190075Sobrien	 length fields that follow.  However, if you omit the optional
1297290075Sobrien	 fields, the assembler outputs zeros for all optional fields
1297390075Sobrien	 anyways, giving each variable length field is minimum length
1297490075Sobrien	 (as defined in sys/debug.h).  Thus we can not use the .tbtab
1297590075Sobrien	 pseudo-op at all.  */
1297690075Sobrien
1297790075Sobrien      /* An all-zero word flags the start of the tbtab, for debuggers
1297890075Sobrien	 that have to find it by searching forward from the entry
1297990075Sobrien	 point or from the current pc.  */
1298090075Sobrien      fputs ("\t.long 0\n", file);
1298190075Sobrien
1298290075Sobrien      /* Tbtab format type.  Use format type 0.  */
1298390075Sobrien      fputs ("\t.byte 0,", file);
1298490075Sobrien
12985132718Skan      /* Language type.  Unfortunately, there does not seem to be any
12986132718Skan	 official way to discover the language being compiled, so we
12987132718Skan	 use language_string.
12988132718Skan	 C is 0.  Fortran is 1.  Pascal is 2.  Ada is 3.  C++ is 9.
12989132718Skan	 Java is 13.  Objective-C is 14.  */
12990132718Skan      if (! strcmp (language_string, "GNU C"))
1299190075Sobrien	i = 0;
1299290075Sobrien      else if (! strcmp (language_string, "GNU F77"))
1299390075Sobrien	i = 1;
12994132718Skan      else if (! strcmp (language_string, "GNU Pascal"))
12995132718Skan	i = 2;
1299690075Sobrien      else if (! strcmp (language_string, "GNU Ada"))
1299790075Sobrien	i = 3;
1299890075Sobrien      else if (! strcmp (language_string, "GNU C++"))
1299990075Sobrien	i = 9;
1300090075Sobrien      else if (! strcmp (language_string, "GNU Java"))
1300190075Sobrien	i = 13;
13002132718Skan      else if (! strcmp (language_string, "GNU Objective-C"))
13003132718Skan	i = 14;
1300490075Sobrien      else
1300590075Sobrien	abort ();
1300690075Sobrien      fprintf (file, "%d,", i);
1300790075Sobrien
1300890075Sobrien      /* 8 single bit fields: global linkage (not set for C extern linkage,
1300990075Sobrien	 apparently a PL/I convention?), out-of-line epilogue/prologue, offset
1301090075Sobrien	 from start of procedure stored in tbtab, internal function, function
1301190075Sobrien	 has controlled storage, function has no toc, function uses fp,
1301290075Sobrien	 function logs/aborts fp operations.  */
1301390075Sobrien      /* Assume that fp operations are used if any fp reg must be saved.  */
1301490075Sobrien      fprintf (file, "%d,",
1301590075Sobrien	       (optional_tbtab << 5) | ((info->first_fp_reg_save != 64) << 1));
1301690075Sobrien
1301790075Sobrien      /* 6 bitfields: function is interrupt handler, name present in
1301890075Sobrien	 proc table, function calls alloca, on condition directives
1301990075Sobrien	 (controls stack walks, 3 bits), saves condition reg, saves
1302090075Sobrien	 link reg.  */
1302190075Sobrien      /* The `function calls alloca' bit seems to be set whenever reg 31 is
1302290075Sobrien	 set up as a frame pointer, even when there is no alloca call.  */
1302390075Sobrien      fprintf (file, "%d,",
1302490075Sobrien	       ((optional_tbtab << 6)
1302590075Sobrien		| ((optional_tbtab & frame_pointer_needed) << 5)
1302690075Sobrien		| (info->cr_save_p << 1)
1302790075Sobrien		| (info->lr_save_p)));
1302890075Sobrien
1302990075Sobrien      /* 3 bitfields: saves backchain, fixup code, number of fpr saved
1303090075Sobrien	 (6 bits).  */
1303190075Sobrien      fprintf (file, "%d,",
1303290075Sobrien	       (info->push_p << 7) | (64 - info->first_fp_reg_save));
1303390075Sobrien
1303490075Sobrien      /* 2 bitfields: spare bits (2 bits), number of gpr saved (6 bits).  */
1303590075Sobrien      fprintf (file, "%d,", (32 - first_reg_to_save ()));
1303690075Sobrien
1303790075Sobrien      if (optional_tbtab)
1303890075Sobrien	{
1303990075Sobrien	  /* Compute the parameter info from the function decl argument
1304090075Sobrien	     list.  */
1304190075Sobrien	  tree decl;
1304290075Sobrien	  int next_parm_info_bit = 31;
1304390075Sobrien
1304490075Sobrien	  for (decl = DECL_ARGUMENTS (current_function_decl);
1304590075Sobrien	       decl; decl = TREE_CHAIN (decl))
1304690075Sobrien	    {
1304790075Sobrien	      rtx parameter = DECL_INCOMING_RTL (decl);
1304890075Sobrien	      enum machine_mode mode = GET_MODE (parameter);
1304990075Sobrien
1305090075Sobrien	      if (GET_CODE (parameter) == REG)
1305190075Sobrien		{
1305290075Sobrien		  if (GET_MODE_CLASS (mode) == MODE_FLOAT)
1305390075Sobrien		    {
1305490075Sobrien		      int bits;
1305590075Sobrien
1305690075Sobrien		      float_parms++;
1305790075Sobrien
1305890075Sobrien		      if (mode == SFmode)
1305990075Sobrien			bits = 0x2;
13060117395Skan		      else if (mode == DFmode || mode == TFmode)
1306190075Sobrien			bits = 0x3;
1306290075Sobrien		      else
1306390075Sobrien			abort ();
1306490075Sobrien
1306590075Sobrien		      /* If only one bit will fit, don't or in this entry.  */
1306690075Sobrien		      if (next_parm_info_bit > 0)
1306790075Sobrien			parm_info |= (bits << (next_parm_info_bit - 1));
1306890075Sobrien		      next_parm_info_bit -= 2;
1306990075Sobrien		    }
1307090075Sobrien		  else
1307190075Sobrien		    {
1307290075Sobrien		      fixed_parms += ((GET_MODE_SIZE (mode)
1307390075Sobrien				       + (UNITS_PER_WORD - 1))
1307490075Sobrien				      / UNITS_PER_WORD);
1307590075Sobrien		      next_parm_info_bit -= 1;
1307690075Sobrien		    }
1307790075Sobrien		}
1307890075Sobrien	    }
1307990075Sobrien	}
1308090075Sobrien
1308190075Sobrien      /* Number of fixed point parameters.  */
1308290075Sobrien      /* This is actually the number of words of fixed point parameters; thus
1308390075Sobrien	 an 8 byte struct counts as 2; and thus the maximum value is 8.  */
1308490075Sobrien      fprintf (file, "%d,", fixed_parms);
1308590075Sobrien
1308690075Sobrien      /* 2 bitfields: number of floating point parameters (7 bits), parameters
1308790075Sobrien	 all on stack.  */
1308890075Sobrien      /* This is actually the number of fp registers that hold parameters;
1308990075Sobrien	 and thus the maximum value is 13.  */
1309090075Sobrien      /* Set parameters on stack bit if parameters are not in their original
1309190075Sobrien	 registers, regardless of whether they are on the stack?  Xlc
1309290075Sobrien	 seems to set the bit when not optimizing.  */
1309390075Sobrien      fprintf (file, "%d\n", ((float_parms << 1) | (! optimize)));
1309490075Sobrien
1309590075Sobrien      if (! optional_tbtab)
1309690075Sobrien	return;
1309790075Sobrien
1309890075Sobrien      /* Optional fields follow.  Some are variable length.  */
1309990075Sobrien
1310090075Sobrien      /* Parameter types, left adjusted bit fields: 0 fixed, 10 single float,
1310190075Sobrien	 11 double float.  */
1310290075Sobrien      /* There is an entry for each parameter in a register, in the order that
1310390075Sobrien	 they occur in the parameter list.  Any intervening arguments on the
1310490075Sobrien	 stack are ignored.  If the list overflows a long (max possible length
1310590075Sobrien	 34 bits) then completely leave off all elements that don't fit.  */
1310690075Sobrien      /* Only emit this long if there was at least one parameter.  */
1310790075Sobrien      if (fixed_parms || float_parms)
1310890075Sobrien	fprintf (file, "\t.long %d\n", parm_info);
1310990075Sobrien
1311090075Sobrien      /* Offset from start of code to tb table.  */
1311190075Sobrien      fputs ("\t.long ", file);
1311290075Sobrien      ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "LT");
1311390075Sobrien#if TARGET_AIX
1311490075Sobrien      RS6000_OUTPUT_BASENAME (file, fname);
1311590075Sobrien#else
1311690075Sobrien      assemble_name (file, fname);
1311790075Sobrien#endif
1311890075Sobrien      fputs ("-.", file);
1311990075Sobrien#if TARGET_AIX
1312090075Sobrien      RS6000_OUTPUT_BASENAME (file, fname);
1312190075Sobrien#else
1312290075Sobrien      assemble_name (file, fname);
1312390075Sobrien#endif
1312490075Sobrien      putc ('\n', file);
1312590075Sobrien
1312690075Sobrien      /* Interrupt handler mask.  */
1312790075Sobrien      /* Omit this long, since we never set the interrupt handler bit
1312890075Sobrien	 above.  */
1312990075Sobrien
1313090075Sobrien      /* Number of CTL (controlled storage) anchors.  */
1313190075Sobrien      /* Omit this long, since the has_ctl bit is never set above.  */
1313290075Sobrien
1313390075Sobrien      /* Displacement into stack of each CTL anchor.  */
1313490075Sobrien      /* Omit this list of longs, because there are no CTL anchors.  */
1313590075Sobrien
1313690075Sobrien      /* Length of function name.  */
13137117395Skan      if (*fname == '*')
13138117395Skan	++fname;
1313990075Sobrien      fprintf (file, "\t.short %d\n", (int) strlen (fname));
1314090075Sobrien
1314190075Sobrien      /* Function name.  */
1314290075Sobrien      assemble_string (fname, strlen (fname));
1314390075Sobrien
1314490075Sobrien      /* Register for alloca automatic storage; this is always reg 31.
1314590075Sobrien	 Only emit this if the alloca bit was set above.  */
1314690075Sobrien      if (frame_pointer_needed)
1314790075Sobrien	fputs ("\t.byte 31\n", file);
1314896263Sobrien
1314996263Sobrien      fputs ("\t.align 2\n", file);
1315090075Sobrien    }
1315190075Sobrien}
1315290075Sobrien
1315390075Sobrien/* A C compound statement that outputs the assembler code for a thunk
1315490075Sobrien   function, used to implement C++ virtual function calls with
1315590075Sobrien   multiple inheritance.  The thunk acts as a wrapper around a virtual
1315690075Sobrien   function, adjusting the implicit object parameter before handing
1315790075Sobrien   control off to the real function.
1315890075Sobrien
1315990075Sobrien   First, emit code to add the integer DELTA to the location that
1316090075Sobrien   contains the incoming first argument.  Assume that this argument
1316190075Sobrien   contains a pointer, and is the one used to pass the `this' pointer
1316290075Sobrien   in C++.  This is the incoming argument *before* the function
1316390075Sobrien   prologue, e.g. `%o0' on a sparc.  The addition must preserve the
1316490075Sobrien   values of all other incoming arguments.
1316590075Sobrien
1316690075Sobrien   After the addition, emit code to jump to FUNCTION, which is a
1316790075Sobrien   `FUNCTION_DECL'.  This is a direct pure jump, not a call, and does
1316890075Sobrien   not touch the return address.  Hence returning from FUNCTION will
1316990075Sobrien   return to whoever called the current `thunk'.
1317090075Sobrien
1317190075Sobrien   The effect must be as if FUNCTION had been called directly with the
1317290075Sobrien   adjusted first argument.  This macro is responsible for emitting
1317390075Sobrien   all of the code for a thunk function; output_function_prologue()
1317490075Sobrien   and output_function_epilogue() are not invoked.
1317590075Sobrien
1317690075Sobrien   The THUNK_FNDECL is redundant.  (DELTA and FUNCTION have already
1317790075Sobrien   been extracted from it.)  It might possibly be useful on some
1317890075Sobrien   targets, but probably not.
1317990075Sobrien
1318090075Sobrien   If you do not define this macro, the target-independent code in the
1318190075Sobrien   C++ frontend will generate a less efficient heavyweight thunk that
1318290075Sobrien   calls FUNCTION instead of jumping to it.  The generic approach does
1318390075Sobrien   not support varargs.  */
1318490075Sobrien
13185117395Skanstatic void
13186132718Skanrs6000_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
13187132718Skan			HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
13188132718Skan			tree function)
1318990075Sobrien{
13190132718Skan  rtx this, insn, funexp;
1319190075Sobrien
13192132718Skan  reload_completed = 1;
13193132718Skan  epilogue_completed = 1;
13194132718Skan  no_new_pseudos = 1;
1319590075Sobrien
13196132718Skan  /* Mark the end of the (empty) prologue.  */
13197132718Skan  emit_note (NOTE_INSN_PROLOGUE_END);
13198102780Skan
13199132718Skan  /* Find the "this" pointer.  If the function returns a structure,
13200132718Skan     the structure return pointer is in r3.  */
13201132718Skan  if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
13202132718Skan    this = gen_rtx_REG (Pmode, 4);
13203132718Skan  else
13204132718Skan    this = gen_rtx_REG (Pmode, 3);
1320590075Sobrien
13206132718Skan  /* Apply the constant offset, if required.  */
13207132718Skan  if (delta)
1320890075Sobrien    {
13209132718Skan      rtx delta_rtx = GEN_INT (delta);
13210132718Skan      emit_insn (TARGET_32BIT
13211132718Skan		 ? gen_addsi3 (this, this, delta_rtx)
13212132718Skan		 : gen_adddi3 (this, this, delta_rtx));
1321390075Sobrien    }
1321490075Sobrien
13215132718Skan  /* Apply the offset from the vtable, if required.  */
13216132718Skan  if (vcall_offset)
1321790075Sobrien    {
13218132718Skan      rtx vcall_offset_rtx = GEN_INT (vcall_offset);
13219132718Skan      rtx tmp = gen_rtx_REG (Pmode, 12);
1322090075Sobrien
13221132718Skan      emit_move_insn (tmp, gen_rtx_MEM (Pmode, this));
13222132718Skan      if (((unsigned HOST_WIDE_INT) vcall_offset) + 0x8000 >= 0x10000)
13223132718Skan	{
13224132718Skan	  emit_insn (TARGET_32BIT
13225132718Skan		     ? gen_addsi3 (tmp, tmp, vcall_offset_rtx)
13226132718Skan		     : gen_adddi3 (tmp, tmp, vcall_offset_rtx));
13227132718Skan	  emit_move_insn (tmp, gen_rtx_MEM (Pmode, tmp));
13228132718Skan	}
13229132718Skan      else
13230132718Skan	{
13231132718Skan	  rtx loc = gen_rtx_PLUS (Pmode, tmp, vcall_offset_rtx);
1323290075Sobrien
13233132718Skan	  emit_move_insn (tmp, gen_rtx_MEM (Pmode, loc));
13234132718Skan	}
13235132718Skan      emit_insn (TARGET_32BIT
13236132718Skan		 ? gen_addsi3 (this, this, tmp)
13237132718Skan		 : gen_adddi3 (this, this, tmp));
1323890075Sobrien    }
1323990075Sobrien
13240132718Skan  /* Generate a tail call to the target function.  */
13241132718Skan  if (!TREE_USED (function))
1324290075Sobrien    {
13243132718Skan      assemble_external (function);
13244132718Skan      TREE_USED (function) = 1;
1324590075Sobrien    }
13246132718Skan  funexp = XEXP (DECL_RTL (function), 0);
13247132718Skan  funexp = gen_rtx_MEM (FUNCTION_MODE, funexp);
1324890075Sobrien
13249132718Skan#if TARGET_MACHO
13250132718Skan  if (MACHOPIC_INDIRECT)
13251132718Skan    funexp = machopic_indirect_call_target (funexp);
13252132718Skan#endif
1325390075Sobrien
13254132718Skan  /* gen_sibcall expects reload to convert scratch pseudo to LR so we must
13255132718Skan     generate sibcall RTL explicitly to avoid constraint abort.  */
13256132718Skan  insn = emit_call_insn (
13257132718Skan	   gen_rtx_PARALLEL (VOIDmode,
13258132718Skan	     gen_rtvec (4,
13259132718Skan			gen_rtx_CALL (VOIDmode,
13260132718Skan				      funexp, const0_rtx),
13261132718Skan			gen_rtx_USE (VOIDmode, const0_rtx),
13262132718Skan			gen_rtx_USE (VOIDmode,
13263132718Skan				     gen_rtx_REG (SImode,
13264132718Skan						  LINK_REGISTER_REGNUM)),
13265132718Skan			gen_rtx_RETURN (VOIDmode))));
13266132718Skan  SIBLING_CALL_P (insn) = 1;
13267132718Skan  emit_barrier ();
1326890075Sobrien
13269132718Skan  /* Run just enough of rest_of_compilation to get the insns emitted.
13270132718Skan     There's not really enough bulk here to make other passes such as
13271132718Skan     instruction scheduling worth while.  Note that use_thunk calls
13272132718Skan     assemble_start_function and assemble_end_function.  */
13273132718Skan  insn = get_insns ();
13274132718Skan  insn_locators_initialize ();
13275132718Skan  shorten_branches (insn);
13276132718Skan  final_start_function (insn, file, 1);
13277132718Skan  final (insn, file, 1, 0);
13278132718Skan  final_end_function ();
1327990075Sobrien
13280132718Skan  reload_completed = 0;
13281132718Skan  epilogue_completed = 0;
13282132718Skan  no_new_pseudos = 0;
1328390075Sobrien}
1328490075Sobrien
1328590075Sobrien/* A quick summary of the various types of 'constant-pool tables'
1328690075Sobrien   under PowerPC:
1328790075Sobrien
1328890075Sobrien   Target	Flags		Name		One table per
1328990075Sobrien   AIX		(none)		AIX TOC		object file
1329090075Sobrien   AIX		-mfull-toc	AIX TOC		object file
1329190075Sobrien   AIX		-mminimal-toc	AIX minimal TOC	translation unit
1329290075Sobrien   SVR4/EABI	(none)		SVR4 SDATA	object file
1329390075Sobrien   SVR4/EABI	-fpic		SVR4 pic	object file
1329490075Sobrien   SVR4/EABI	-fPIC		SVR4 PIC	translation unit
1329590075Sobrien   SVR4/EABI	-mrelocatable	EABI TOC	function
1329690075Sobrien   SVR4/EABI	-maix		AIX TOC		object file
1329790075Sobrien   SVR4/EABI	-maix -mminimal-toc
1329890075Sobrien				AIX minimal TOC	translation unit
1329990075Sobrien
1330090075Sobrien   Name			Reg.	Set by	entries	      contains:
1330190075Sobrien					made by	 addrs?	fp?	sum?
1330290075Sobrien
1330390075Sobrien   AIX TOC		2	crt0	as	 Y	option	option
1330490075Sobrien   AIX minimal TOC	30	prolog	gcc	 Y	Y	option
1330590075Sobrien   SVR4 SDATA		13	crt0	gcc	 N	Y	N
1330690075Sobrien   SVR4 pic		30	prolog	ld	 Y	not yet	N
1330790075Sobrien   SVR4 PIC		30	prolog	gcc	 Y	option	option
1330890075Sobrien   EABI TOC		30	prolog	gcc	 Y	option	option
1330990075Sobrien
1331090075Sobrien*/
1331190075Sobrien
1331290075Sobrien/* Hash functions for the hash table.  */
1331390075Sobrien
1331490075Sobrienstatic unsigned
13315132718Skanrs6000_hash_constant (rtx k)
1331690075Sobrien{
13317117395Skan  enum rtx_code code = GET_CODE (k);
13318117395Skan  enum machine_mode mode = GET_MODE (k);
13319117395Skan  unsigned result = (code << 3) ^ mode;
13320117395Skan  const char *format;
13321117395Skan  int flen, fidx;
1332290075Sobrien
13323117395Skan  format = GET_RTX_FORMAT (code);
13324117395Skan  flen = strlen (format);
13325117395Skan  fidx = 0;
1332690075Sobrien
13327117395Skan  switch (code)
13328117395Skan    {
13329117395Skan    case LABEL_REF:
13330117395Skan      return result * 1231 + (unsigned) INSN_UID (XEXP (k, 0));
1333190075Sobrien
13332117395Skan    case CONST_DOUBLE:
13333117395Skan      if (mode != VOIDmode)
13334117395Skan	return real_hash (CONST_DOUBLE_REAL_VALUE (k)) * result;
13335117395Skan      flen = 2;
13336117395Skan      break;
13337117395Skan
13338117395Skan    case CODE_LABEL:
13339117395Skan      fidx = 3;
13340117395Skan      break;
13341117395Skan
13342117395Skan    default:
13343117395Skan      break;
13344117395Skan    }
13345117395Skan
1334690075Sobrien  for (; fidx < flen; fidx++)
1334790075Sobrien    switch (format[fidx])
1334890075Sobrien      {
1334990075Sobrien      case 's':
1335090075Sobrien	{
1335190075Sobrien	  unsigned i, len;
1335290075Sobrien	  const char *str = XSTR (k, fidx);
1335390075Sobrien	  len = strlen (str);
1335490075Sobrien	  result = result * 613 + len;
1335590075Sobrien	  for (i = 0; i < len; i++)
1335690075Sobrien	    result = result * 613 + (unsigned) str[i];
1335790075Sobrien	  break;
1335890075Sobrien	}
1335990075Sobrien      case 'u':
1336090075Sobrien      case 'e':
1336190075Sobrien	result = result * 1231 + rs6000_hash_constant (XEXP (k, fidx));
1336290075Sobrien	break;
1336390075Sobrien      case 'i':
1336490075Sobrien      case 'n':
1336590075Sobrien	result = result * 613 + (unsigned) XINT (k, fidx);
1336690075Sobrien	break;
1336790075Sobrien      case 'w':
1336890075Sobrien	if (sizeof (unsigned) >= sizeof (HOST_WIDE_INT))
1336990075Sobrien	  result = result * 613 + (unsigned) XWINT (k, fidx);
1337090075Sobrien	else
1337190075Sobrien	  {
1337290075Sobrien	    size_t i;
1337390075Sobrien	    for (i = 0; i < sizeof(HOST_WIDE_INT)/sizeof(unsigned); i++)
1337490075Sobrien	      result = result * 613 + (unsigned) (XWINT (k, fidx)
1337590075Sobrien						  >> CHAR_BIT * i);
1337690075Sobrien	  }
1337790075Sobrien	break;
13378132718Skan      case '0':
13379132718Skan	break;
1338090075Sobrien      default:
1338190075Sobrien	abort ();
1338290075Sobrien      }
13383117395Skan
1338490075Sobrien  return result;
1338590075Sobrien}
1338690075Sobrien
1338790075Sobrienstatic unsigned
13388132718Skantoc_hash_function (const void *hash_entry)
1338990075Sobrien{
1339090075Sobrien  const struct toc_hash_struct *thc =
1339190075Sobrien    (const struct toc_hash_struct *) hash_entry;
1339290075Sobrien  return rs6000_hash_constant (thc->key) ^ thc->key_mode;
1339390075Sobrien}
1339490075Sobrien
1339590075Sobrien/* Compare H1 and H2 for equivalence.  */
1339690075Sobrien
1339790075Sobrienstatic int
13398132718Skantoc_hash_eq (const void *h1, const void *h2)
1339990075Sobrien{
1340090075Sobrien  rtx r1 = ((const struct toc_hash_struct *) h1)->key;
1340190075Sobrien  rtx r2 = ((const struct toc_hash_struct *) h2)->key;
1340290075Sobrien
1340390075Sobrien  if (((const struct toc_hash_struct *) h1)->key_mode
1340490075Sobrien      != ((const struct toc_hash_struct *) h2)->key_mode)
1340590075Sobrien    return 0;
1340690075Sobrien
13407117395Skan  return rtx_equal_p (r1, r2);
1340890075Sobrien}
1340990075Sobrien
1341090075Sobrien/* These are the names given by the C++ front-end to vtables, and
1341190075Sobrien   vtable-like objects.  Ideally, this logic should not be here;
1341290075Sobrien   instead, there should be some programmatic way of inquiring as
1341390075Sobrien   to whether or not an object is a vtable.  */
1341490075Sobrien
1341590075Sobrien#define VTABLE_NAME_P(NAME)				\
1341690075Sobrien  (strncmp ("_vt.", name, strlen("_vt.")) == 0		\
1341790075Sobrien  || strncmp ("_ZTV", name, strlen ("_ZTV")) == 0	\
1341890075Sobrien  || strncmp ("_ZTT", name, strlen ("_ZTT")) == 0	\
13419132718Skan  || strncmp ("_ZTI", name, strlen ("_ZTI")) == 0	\
1342090075Sobrien  || strncmp ("_ZTC", name, strlen ("_ZTC")) == 0)
1342190075Sobrien
1342290075Sobrienvoid
13423132718Skanrs6000_output_symbol_ref (FILE *file, rtx x)
1342490075Sobrien{
1342590075Sobrien  /* Currently C++ toc references to vtables can be emitted before it
1342690075Sobrien     is decided whether the vtable is public or private.  If this is
1342790075Sobrien     the case, then the linker will eventually complain that there is
1342890075Sobrien     a reference to an unknown section.  Thus, for vtables only,
1342990075Sobrien     we emit the TOC reference to reference the symbol and not the
1343090075Sobrien     section.  */
1343190075Sobrien  const char *name = XSTR (x, 0);
1343290075Sobrien
1343390075Sobrien  if (VTABLE_NAME_P (name))
1343490075Sobrien    {
1343590075Sobrien      RS6000_OUTPUT_BASENAME (file, name);
1343690075Sobrien    }
1343790075Sobrien  else
1343890075Sobrien    assemble_name (file, name);
1343990075Sobrien}
1344090075Sobrien
1344190075Sobrien/* Output a TOC entry.  We derive the entry name from what is being
1344290075Sobrien   written.  */
1344390075Sobrien
1344490075Sobrienvoid
13445132718Skanoutput_toc (FILE *file, rtx x, int labelno, enum machine_mode mode)
1344690075Sobrien{
1344790075Sobrien  char buf[256];
1344890075Sobrien  const char *name = buf;
1344990075Sobrien  const char *real_name;
1345090075Sobrien  rtx base = x;
1345190075Sobrien  int offset = 0;
1345290075Sobrien
1345390075Sobrien  if (TARGET_NO_TOC)
1345490075Sobrien    abort ();
1345590075Sobrien
1345690075Sobrien  /* When the linker won't eliminate them, don't output duplicate
1345790075Sobrien     TOC entries (this happens on AIX if there is any kind of TOC,
13458132718Skan     and on SVR4 under -fPIC or -mrelocatable).  Don't do this for
13459132718Skan     CODE_LABELs.  */
13460132718Skan  if (TARGET_TOC && GET_CODE (x) != LABEL_REF)
1346190075Sobrien    {
1346290075Sobrien      struct toc_hash_struct *h;
1346390075Sobrien      void * * found;
1346490075Sobrien
13465132718Skan      /* Create toc_hash_table.  This can't be done at OVERRIDE_OPTIONS
13466132718Skan         time because GGC is not initialized at that point.  */
13467132718Skan      if (toc_hash_table == NULL)
13468132718Skan	toc_hash_table = htab_create_ggc (1021, toc_hash_function,
13469132718Skan					  toc_hash_eq, NULL);
13470132718Skan
1347190075Sobrien      h = ggc_alloc (sizeof (*h));
1347290075Sobrien      h->key = x;
1347390075Sobrien      h->key_mode = mode;
1347490075Sobrien      h->labelno = labelno;
1347590075Sobrien
1347690075Sobrien      found = htab_find_slot (toc_hash_table, h, 1);
1347790075Sobrien      if (*found == NULL)
1347890075Sobrien	*found = h;
1347990075Sobrien      else  /* This is indeed a duplicate.
1348090075Sobrien	       Set this label equal to that label.  */
1348190075Sobrien	{
1348290075Sobrien	  fputs ("\t.set ", file);
1348390075Sobrien	  ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "LC");
1348490075Sobrien	  fprintf (file, "%d,", labelno);
1348590075Sobrien	  ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "LC");
1348690075Sobrien	  fprintf (file, "%d\n", ((*(const struct toc_hash_struct **)
1348790075Sobrien					      found)->labelno));
1348890075Sobrien	  return;
1348990075Sobrien	}
1349090075Sobrien    }
1349190075Sobrien
1349290075Sobrien  /* If we're going to put a double constant in the TOC, make sure it's
1349390075Sobrien     aligned properly when strict alignment is on.  */
1349490075Sobrien  if (GET_CODE (x) == CONST_DOUBLE
1349590075Sobrien      && STRICT_ALIGNMENT
1349690075Sobrien      && GET_MODE_BITSIZE (mode) >= 64
1349790075Sobrien      && ! (TARGET_NO_FP_IN_TOC && ! TARGET_MINIMAL_TOC)) {
1349890075Sobrien    ASM_OUTPUT_ALIGN (file, 3);
1349990075Sobrien  }
1350090075Sobrien
13501132718Skan  (*targetm.asm_out.internal_label) (file, "LC", labelno);
1350290075Sobrien
1350390075Sobrien  /* Handle FP constants specially.  Note that if we have a minimal
1350490075Sobrien     TOC, things we put here aren't actually in the TOC, so we can allow
1350590075Sobrien     FP constants.  */
13506117395Skan  if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == TFmode)
1350790075Sobrien    {
1350890075Sobrien      REAL_VALUE_TYPE rv;
13509117395Skan      long k[4];
13510117395Skan
13511117395Skan      REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
13512117395Skan      REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, k);
13513117395Skan
13514117395Skan      if (TARGET_64BIT)
13515117395Skan	{
13516117395Skan	  if (TARGET_MINIMAL_TOC)
13517117395Skan	    fputs (DOUBLE_INT_ASM_OP, file);
13518117395Skan	  else
13519117395Skan	    fprintf (file, "\t.tc FT_%lx_%lx_%lx_%lx[TC],",
13520117395Skan		     k[0] & 0xffffffff, k[1] & 0xffffffff,
13521117395Skan		     k[2] & 0xffffffff, k[3] & 0xffffffff);
13522117395Skan	  fprintf (file, "0x%lx%08lx,0x%lx%08lx\n",
13523117395Skan		   k[0] & 0xffffffff, k[1] & 0xffffffff,
13524117395Skan		   k[2] & 0xffffffff, k[3] & 0xffffffff);
13525117395Skan	  return;
13526117395Skan	}
13527117395Skan      else
13528117395Skan	{
13529117395Skan	  if (TARGET_MINIMAL_TOC)
13530117395Skan	    fputs ("\t.long ", file);
13531117395Skan	  else
13532117395Skan	    fprintf (file, "\t.tc FT_%lx_%lx_%lx_%lx[TC],",
13533117395Skan		     k[0] & 0xffffffff, k[1] & 0xffffffff,
13534117395Skan		     k[2] & 0xffffffff, k[3] & 0xffffffff);
13535117395Skan	  fprintf (file, "0x%lx,0x%lx,0x%lx,0x%lx\n",
13536117395Skan		   k[0] & 0xffffffff, k[1] & 0xffffffff,
13537117395Skan		   k[2] & 0xffffffff, k[3] & 0xffffffff);
13538117395Skan	  return;
13539117395Skan	}
13540117395Skan    }
13541117395Skan  else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == DFmode)
13542117395Skan    {
13543117395Skan      REAL_VALUE_TYPE rv;
1354490075Sobrien      long k[2];
1354590075Sobrien
1354690075Sobrien      REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
1354790075Sobrien      REAL_VALUE_TO_TARGET_DOUBLE (rv, k);
1354890075Sobrien
1354990075Sobrien      if (TARGET_64BIT)
1355090075Sobrien	{
1355190075Sobrien	  if (TARGET_MINIMAL_TOC)
1355290075Sobrien	    fputs (DOUBLE_INT_ASM_OP, file);
1355390075Sobrien	  else
13554102780Skan	    fprintf (file, "\t.tc FD_%lx_%lx[TC],",
13555102780Skan		     k[0] & 0xffffffff, k[1] & 0xffffffff);
13556102780Skan	  fprintf (file, "0x%lx%08lx\n",
13557102780Skan		   k[0] & 0xffffffff, k[1] & 0xffffffff);
1355890075Sobrien	  return;
1355990075Sobrien	}
1356090075Sobrien      else
1356190075Sobrien	{
1356290075Sobrien	  if (TARGET_MINIMAL_TOC)
1356390075Sobrien	    fputs ("\t.long ", file);
1356490075Sobrien	  else
13565102780Skan	    fprintf (file, "\t.tc FD_%lx_%lx[TC],",
13566102780Skan		     k[0] & 0xffffffff, k[1] & 0xffffffff);
13567102780Skan	  fprintf (file, "0x%lx,0x%lx\n",
13568102780Skan		   k[0] & 0xffffffff, k[1] & 0xffffffff);
1356990075Sobrien	  return;
1357090075Sobrien	}
1357190075Sobrien    }
1357290075Sobrien  else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == SFmode)
1357390075Sobrien    {
1357490075Sobrien      REAL_VALUE_TYPE rv;
1357590075Sobrien      long l;
1357690075Sobrien
1357790075Sobrien      REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
1357890075Sobrien      REAL_VALUE_TO_TARGET_SINGLE (rv, l);
1357990075Sobrien
1358090075Sobrien      if (TARGET_64BIT)
1358190075Sobrien	{
1358290075Sobrien	  if (TARGET_MINIMAL_TOC)
1358390075Sobrien	    fputs (DOUBLE_INT_ASM_OP, file);
1358490075Sobrien	  else
13585102780Skan	    fprintf (file, "\t.tc FS_%lx[TC],", l & 0xffffffff);
13586102780Skan	  fprintf (file, "0x%lx00000000\n", l & 0xffffffff);
1358790075Sobrien	  return;
1358890075Sobrien	}
1358990075Sobrien      else
1359090075Sobrien	{
1359190075Sobrien	  if (TARGET_MINIMAL_TOC)
1359290075Sobrien	    fputs ("\t.long ", file);
1359390075Sobrien	  else
13594102780Skan	    fprintf (file, "\t.tc FS_%lx[TC],", l & 0xffffffff);
13595102780Skan	  fprintf (file, "0x%lx\n", l & 0xffffffff);
1359690075Sobrien	  return;
1359790075Sobrien	}
1359890075Sobrien    }
1359990075Sobrien  else if (GET_MODE (x) == VOIDmode
1360090075Sobrien	   && (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE))
1360190075Sobrien    {
1360290075Sobrien      unsigned HOST_WIDE_INT low;
1360390075Sobrien      HOST_WIDE_INT high;
1360490075Sobrien
1360590075Sobrien      if (GET_CODE (x) == CONST_DOUBLE)
1360690075Sobrien	{
1360790075Sobrien	  low = CONST_DOUBLE_LOW (x);
1360890075Sobrien	  high = CONST_DOUBLE_HIGH (x);
1360990075Sobrien	}
1361090075Sobrien      else
1361190075Sobrien#if HOST_BITS_PER_WIDE_INT == 32
1361290075Sobrien	{
1361390075Sobrien	  low = INTVAL (x);
1361490075Sobrien	  high = (low & 0x80000000) ? ~0 : 0;
1361590075Sobrien	}
1361690075Sobrien#else
1361790075Sobrien	{
1361890075Sobrien          low = INTVAL (x) & 0xffffffff;
1361990075Sobrien          high = (HOST_WIDE_INT) INTVAL (x) >> 32;
1362090075Sobrien	}
1362190075Sobrien#endif
1362290075Sobrien
1362390075Sobrien      /* TOC entries are always Pmode-sized, but since this
1362490075Sobrien	 is a bigendian machine then if we're putting smaller
1362590075Sobrien	 integer constants in the TOC we have to pad them.
1362690075Sobrien	 (This is still a win over putting the constants in
1362790075Sobrien	 a separate constant pool, because then we'd have
1362890075Sobrien	 to have both a TOC entry _and_ the actual constant.)
1362990075Sobrien
1363090075Sobrien	 For a 32-bit target, CONST_INT values are loaded and shifted
1363190075Sobrien	 entirely within `low' and can be stored in one TOC entry.  */
1363290075Sobrien
1363390075Sobrien      if (TARGET_64BIT && POINTER_SIZE < GET_MODE_BITSIZE (mode))
1363490075Sobrien	abort ();/* It would be easy to make this work, but it doesn't now.  */
1363590075Sobrien
1363690075Sobrien      if (POINTER_SIZE > GET_MODE_BITSIZE (mode))
13637103445Skan	{
13638103445Skan#if HOST_BITS_PER_WIDE_INT == 32
13639103445Skan	  lshift_double (low, high, POINTER_SIZE - GET_MODE_BITSIZE (mode),
13640103445Skan			 POINTER_SIZE, &low, &high, 0);
13641103445Skan#else
13642103445Skan	  low |= high << 32;
13643103445Skan	  low <<= POINTER_SIZE - GET_MODE_BITSIZE (mode);
13644103445Skan	  high = (HOST_WIDE_INT) low >> 32;
13645103445Skan	  low &= 0xffffffff;
13646103445Skan#endif
13647103445Skan	}
1364890075Sobrien
1364990075Sobrien      if (TARGET_64BIT)
1365090075Sobrien	{
1365190075Sobrien	  if (TARGET_MINIMAL_TOC)
1365290075Sobrien	    fputs (DOUBLE_INT_ASM_OP, file);
1365390075Sobrien	  else
13654102780Skan	    fprintf (file, "\t.tc ID_%lx_%lx[TC],",
13655102780Skan		     (long) high & 0xffffffff, (long) low & 0xffffffff);
13656102780Skan	  fprintf (file, "0x%lx%08lx\n",
13657102780Skan		   (long) high & 0xffffffff, (long) low & 0xffffffff);
1365890075Sobrien	  return;
1365990075Sobrien	}
1366090075Sobrien      else
1366190075Sobrien	{
1366290075Sobrien	  if (POINTER_SIZE < GET_MODE_BITSIZE (mode))
1366390075Sobrien	    {
1366490075Sobrien	      if (TARGET_MINIMAL_TOC)
1366590075Sobrien		fputs ("\t.long ", file);
1366690075Sobrien	      else
1366790075Sobrien		fprintf (file, "\t.tc ID_%lx_%lx[TC],",
13668102780Skan			 (long) high & 0xffffffff, (long) low & 0xffffffff);
13669102780Skan	      fprintf (file, "0x%lx,0x%lx\n",
13670102780Skan		       (long) high & 0xffffffff, (long) low & 0xffffffff);
1367190075Sobrien	    }
1367290075Sobrien	  else
1367390075Sobrien	    {
1367490075Sobrien	      if (TARGET_MINIMAL_TOC)
1367590075Sobrien		fputs ("\t.long ", file);
1367690075Sobrien	      else
13677102780Skan		fprintf (file, "\t.tc IS_%lx[TC],", (long) low & 0xffffffff);
13678102780Skan	      fprintf (file, "0x%lx\n", (long) low & 0xffffffff);
1367990075Sobrien	    }
1368090075Sobrien	  return;
1368190075Sobrien	}
1368290075Sobrien    }
1368390075Sobrien
1368490075Sobrien  if (GET_CODE (x) == CONST)
1368590075Sobrien    {
1368690075Sobrien      if (GET_CODE (XEXP (x, 0)) != PLUS)
1368790075Sobrien	abort ();
1368890075Sobrien
1368990075Sobrien      base = XEXP (XEXP (x, 0), 0);
1369090075Sobrien      offset = INTVAL (XEXP (XEXP (x, 0), 1));
1369190075Sobrien    }
1369290075Sobrien
1369390075Sobrien  if (GET_CODE (base) == SYMBOL_REF)
1369490075Sobrien    name = XSTR (base, 0);
1369590075Sobrien  else if (GET_CODE (base) == LABEL_REF)
1369690075Sobrien    ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (XEXP (base, 0)));
1369790075Sobrien  else if (GET_CODE (base) == CODE_LABEL)
1369890075Sobrien    ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (base));
1369990075Sobrien  else
1370090075Sobrien    abort ();
1370190075Sobrien
13702117395Skan  real_name = (*targetm.strip_name_encoding) (name);
1370390075Sobrien  if (TARGET_MINIMAL_TOC)
1370490075Sobrien    fputs (TARGET_32BIT ? "\t.long " : DOUBLE_INT_ASM_OP, file);
1370590075Sobrien  else
1370690075Sobrien    {
1370790075Sobrien      fprintf (file, "\t.tc %s", real_name);
1370890075Sobrien
1370990075Sobrien      if (offset < 0)
1371090075Sobrien	fprintf (file, ".N%d", - offset);
1371190075Sobrien      else if (offset)
1371290075Sobrien	fprintf (file, ".P%d", offset);
1371390075Sobrien
1371490075Sobrien      fputs ("[TC],", file);
1371590075Sobrien    }
1371690075Sobrien
1371790075Sobrien  /* Currently C++ toc references to vtables can be emitted before it
1371890075Sobrien     is decided whether the vtable is public or private.  If this is
1371990075Sobrien     the case, then the linker will eventually complain that there is
1372090075Sobrien     a TOC reference to an unknown section.  Thus, for vtables only,
1372190075Sobrien     we emit the TOC reference to reference the symbol and not the
1372290075Sobrien     section.  */
1372390075Sobrien  if (VTABLE_NAME_P (name))
1372490075Sobrien    {
1372590075Sobrien      RS6000_OUTPUT_BASENAME (file, name);
1372690075Sobrien      if (offset < 0)
1372790075Sobrien	fprintf (file, "%d", offset);
1372890075Sobrien      else if (offset > 0)
1372990075Sobrien	fprintf (file, "+%d", offset);
1373090075Sobrien    }
1373190075Sobrien  else
1373290075Sobrien    output_addr_const (file, x);
1373390075Sobrien  putc ('\n', file);
1373490075Sobrien}
1373590075Sobrien
1373690075Sobrien/* Output an assembler pseudo-op to write an ASCII string of N characters
1373790075Sobrien   starting at P to FILE.
1373890075Sobrien
1373990075Sobrien   On the RS/6000, we have to do this using the .byte operation and
1374090075Sobrien   write out special characters outside the quoted string.
1374190075Sobrien   Also, the assembler is broken; very long strings are truncated,
1374290075Sobrien   so we must artificially break them up early.  */
1374390075Sobrien
1374490075Sobrienvoid
13745132718Skanoutput_ascii (FILE *file, const char *p, int n)
1374690075Sobrien{
1374790075Sobrien  char c;
1374890075Sobrien  int i, count_string;
1374990075Sobrien  const char *for_string = "\t.byte \"";
1375090075Sobrien  const char *for_decimal = "\t.byte ";
1375190075Sobrien  const char *to_close = NULL;
1375290075Sobrien
1375390075Sobrien  count_string = 0;
1375490075Sobrien  for (i = 0; i < n; i++)
1375590075Sobrien    {
1375690075Sobrien      c = *p++;
1375790075Sobrien      if (c >= ' ' && c < 0177)
1375890075Sobrien	{
1375990075Sobrien	  if (for_string)
1376090075Sobrien	    fputs (for_string, file);
1376190075Sobrien	  putc (c, file);
1376290075Sobrien
1376390075Sobrien	  /* Write two quotes to get one.  */
1376490075Sobrien	  if (c == '"')
1376590075Sobrien	    {
1376690075Sobrien	      putc (c, file);
1376790075Sobrien	      ++count_string;
1376890075Sobrien	    }
1376990075Sobrien
1377090075Sobrien	  for_string = NULL;
1377190075Sobrien	  for_decimal = "\"\n\t.byte ";
1377290075Sobrien	  to_close = "\"\n";
1377390075Sobrien	  ++count_string;
1377490075Sobrien
1377590075Sobrien	  if (count_string >= 512)
1377690075Sobrien	    {
1377790075Sobrien	      fputs (to_close, file);
1377890075Sobrien
1377990075Sobrien	      for_string = "\t.byte \"";
1378090075Sobrien	      for_decimal = "\t.byte ";
1378190075Sobrien	      to_close = NULL;
1378290075Sobrien	      count_string = 0;
1378390075Sobrien	    }
1378490075Sobrien	}
1378590075Sobrien      else
1378690075Sobrien	{
1378790075Sobrien	  if (for_decimal)
1378890075Sobrien	    fputs (for_decimal, file);
1378990075Sobrien	  fprintf (file, "%d", c);
1379090075Sobrien
1379190075Sobrien	  for_string = "\n\t.byte \"";
1379290075Sobrien	  for_decimal = ", ";
1379390075Sobrien	  to_close = "\n";
1379490075Sobrien	  count_string = 0;
1379590075Sobrien	}
1379690075Sobrien    }
1379790075Sobrien
1379890075Sobrien  /* Now close the string if we have written one.  Then end the line.  */
1379990075Sobrien  if (to_close)
1380090075Sobrien    fputs (to_close, file);
1380190075Sobrien}
1380290075Sobrien
1380390075Sobrien/* Generate a unique section name for FILENAME for a section type
1380490075Sobrien   represented by SECTION_DESC.  Output goes into BUF.
1380590075Sobrien
1380690075Sobrien   SECTION_DESC can be any string, as long as it is different for each
1380790075Sobrien   possible section type.
1380890075Sobrien
1380990075Sobrien   We name the section in the same manner as xlc.  The name begins with an
1381090075Sobrien   underscore followed by the filename (after stripping any leading directory
1381190075Sobrien   names) with the last period replaced by the string SECTION_DESC.  If
1381290075Sobrien   FILENAME does not contain a period, SECTION_DESC is appended to the end of
1381390075Sobrien   the name.  */
1381490075Sobrien
1381590075Sobrienvoid
13816132718Skanrs6000_gen_section_name (char **buf, const char *filename,
13817132718Skan		         const char *section_desc)
1381890075Sobrien{
1381990075Sobrien  const char *q, *after_last_slash, *last_period = 0;
1382090075Sobrien  char *p;
1382190075Sobrien  int len;
1382290075Sobrien
1382390075Sobrien  after_last_slash = filename;
1382490075Sobrien  for (q = filename; *q; q++)
1382590075Sobrien    {
1382690075Sobrien      if (*q == '/')
1382790075Sobrien	after_last_slash = q + 1;
1382890075Sobrien      else if (*q == '.')
1382990075Sobrien	last_period = q;
1383090075Sobrien    }
1383190075Sobrien
1383290075Sobrien  len = strlen (after_last_slash) + strlen (section_desc) + 2;
13833117395Skan  *buf = (char *) xmalloc (len);
1383490075Sobrien
1383590075Sobrien  p = *buf;
1383690075Sobrien  *p++ = '_';
1383790075Sobrien
1383890075Sobrien  for (q = after_last_slash; *q; q++)
1383990075Sobrien    {
1384090075Sobrien      if (q == last_period)
1384190075Sobrien        {
1384290075Sobrien	  strcpy (p, section_desc);
1384390075Sobrien	  p += strlen (section_desc);
13844132718Skan	  break;
1384590075Sobrien        }
1384690075Sobrien
1384790075Sobrien      else if (ISALNUM (*q))
1384890075Sobrien        *p++ = *q;
1384990075Sobrien    }
1385090075Sobrien
1385190075Sobrien  if (last_period == 0)
1385290075Sobrien    strcpy (p, section_desc);
1385390075Sobrien  else
1385490075Sobrien    *p = '\0';
1385590075Sobrien}
1385690075Sobrien
1385790075Sobrien/* Emit profile function.  */
1385890075Sobrien
1385990075Sobrienvoid
13860132718Skanoutput_profile_hook (int labelno ATTRIBUTE_UNUSED)
1386190075Sobrien{
13862132718Skan  if (TARGET_PROFILE_KERNEL)
13863132718Skan    return;
13864132718Skan
1386590075Sobrien  if (DEFAULT_ABI == ABI_AIX)
1386690075Sobrien    {
13867132718Skan#ifndef NO_PROFILE_COUNTERS
13868132718Skan# define NO_PROFILE_COUNTERS 0
13869132718Skan#endif
13870132718Skan      if (NO_PROFILE_COUNTERS)
13871132718Skan	emit_library_call (init_one_libfunc (RS6000_MCOUNT), 0, VOIDmode, 0);
13872132718Skan      else
13873132718Skan	{
13874132718Skan	  char buf[30];
13875132718Skan	  const char *label_name;
13876132718Skan	  rtx fun;
1387790075Sobrien
13878132718Skan	  ASM_GENERATE_INTERNAL_LABEL (buf, "LP", labelno);
13879132718Skan	  label_name = (*targetm.strip_name_encoding) (ggc_strdup (buf));
13880132718Skan	  fun = gen_rtx_SYMBOL_REF (Pmode, label_name);
1388190075Sobrien
13882132718Skan	  emit_library_call (init_one_libfunc (RS6000_MCOUNT), 0, VOIDmode, 1,
13883132718Skan			     fun, Pmode);
13884132718Skan	}
1388590075Sobrien    }
1388690075Sobrien  else if (DEFAULT_ABI == ABI_DARWIN)
1388790075Sobrien    {
1388890075Sobrien      const char *mcount_name = RS6000_MCOUNT;
1388990075Sobrien      int caller_addr_regno = LINK_REGISTER_REGNUM;
1389090075Sobrien
1389190075Sobrien      /* Be conservative and always set this, at least for now.  */
1389290075Sobrien      current_function_uses_pic_offset_table = 1;
1389390075Sobrien
1389490075Sobrien#if TARGET_MACHO
1389590075Sobrien      /* For PIC code, set up a stub and collect the caller's address
1389690075Sobrien	 from r0, which is where the prologue puts it.  */
13897132718Skan      if (MACHOPIC_INDIRECT)
1389890075Sobrien	{
1389990075Sobrien	  mcount_name = machopic_stub_name (mcount_name);
1390090075Sobrien	  if (current_function_uses_pic_offset_table)
1390190075Sobrien	    caller_addr_regno = 0;
1390290075Sobrien	}
1390390075Sobrien#endif
1390490075Sobrien      emit_library_call (gen_rtx_SYMBOL_REF (Pmode, mcount_name),
1390590075Sobrien			 0, VOIDmode, 1,
1390690075Sobrien			 gen_rtx_REG (Pmode, caller_addr_regno), Pmode);
1390790075Sobrien    }
1390890075Sobrien}
1390990075Sobrien
1391090075Sobrien/* Write function profiler code.  */
1391190075Sobrien
1391290075Sobrienvoid
13913132718Skanoutput_function_profiler (FILE *file, int labelno)
1391490075Sobrien{
1391590075Sobrien  char buf[100];
13916103445Skan  int save_lr = 8;
1391790075Sobrien
1391890075Sobrien  switch (DEFAULT_ABI)
1391990075Sobrien    {
1392090075Sobrien    default:
1392190075Sobrien      abort ();
1392290075Sobrien
1392390075Sobrien    case ABI_V4:
13924103445Skan      save_lr = 4;
13925103445Skan      if (!TARGET_32BIT)
13926103445Skan	{
13927103445Skan	  warning ("no profiling of 64-bit code for this ABI");
13928103445Skan	  return;
13929103445Skan	}
13930132718Skan      ASM_GENERATE_INTERNAL_LABEL (buf, "LP", labelno);
1393190075Sobrien      fprintf (file, "\tmflr %s\n", reg_names[0]);
1393290075Sobrien      if (flag_pic == 1)
1393390075Sobrien	{
1393490075Sobrien	  fputs ("\tbl _GLOBAL_OFFSET_TABLE_@local-4\n", file);
13935103445Skan	  asm_fprintf (file, "\t{st|stw} %s,%d(%s)\n",
13936103445Skan		       reg_names[0], save_lr, reg_names[1]);
1393790075Sobrien	  asm_fprintf (file, "\tmflr %s\n", reg_names[12]);
1393890075Sobrien	  asm_fprintf (file, "\t{l|lwz} %s,", reg_names[0]);
1393990075Sobrien	  assemble_name (file, buf);
1394090075Sobrien	  asm_fprintf (file, "@got(%s)\n", reg_names[12]);
1394190075Sobrien	}
1394290075Sobrien      else if (flag_pic > 1)
1394390075Sobrien	{
13944103445Skan	  asm_fprintf (file, "\t{st|stw} %s,%d(%s)\n",
13945103445Skan		       reg_names[0], save_lr, reg_names[1]);
1394690075Sobrien	  /* Now, we need to get the address of the label.  */
1394790075Sobrien	  fputs ("\tbl 1f\n\t.long ", file);
1394890075Sobrien	  assemble_name (file, buf);
1394990075Sobrien	  fputs ("-.\n1:", file);
1395090075Sobrien	  asm_fprintf (file, "\tmflr %s\n", reg_names[11]);
1395190075Sobrien	  asm_fprintf (file, "\t{l|lwz} %s,0(%s)\n",
1395290075Sobrien		       reg_names[0], reg_names[11]);
1395390075Sobrien	  asm_fprintf (file, "\t{cax|add} %s,%s,%s\n",
1395490075Sobrien		       reg_names[0], reg_names[0], reg_names[11]);
1395590075Sobrien	}
1395690075Sobrien      else
1395790075Sobrien	{
1395890075Sobrien	  asm_fprintf (file, "\t{liu|lis} %s,", reg_names[12]);
1395990075Sobrien	  assemble_name (file, buf);
1396090075Sobrien	  fputs ("@ha\n", file);
13961103445Skan	  asm_fprintf (file, "\t{st|stw} %s,%d(%s)\n",
13962103445Skan		       reg_names[0], save_lr, reg_names[1]);
1396390075Sobrien	  asm_fprintf (file, "\t{cal|la} %s,", reg_names[0]);
1396490075Sobrien	  assemble_name (file, buf);
1396590075Sobrien	  asm_fprintf (file, "@l(%s)\n", reg_names[12]);
1396690075Sobrien	}
1396790075Sobrien
13968132718Skan      /* ABI_V4 saves the static chain reg with ASM_OUTPUT_REG_PUSH.  */
13969132718Skan      fprintf (file, "\tbl %s%s\n",
13970132718Skan	       RS6000_MCOUNT, flag_pic ? "@plt" : "");
13971132718Skan
13972132718Skan      break;
13973132718Skan
13974132718Skan    case ABI_AIX:
13975132718Skan    case ABI_DARWIN:
13976132718Skan      if (!TARGET_PROFILE_KERNEL)
13977103445Skan	{
13978132718Skan	  /* Don't do anything, done in output_profile_hook ().  */
13979103445Skan	}
13980103445Skan      else
13981132718Skan	{
13982132718Skan	  if (TARGET_32BIT)
13983132718Skan	    abort ();
1398490075Sobrien
13985132718Skan	  asm_fprintf (file, "\tmflr %s\n", reg_names[0]);
13986132718Skan	  asm_fprintf (file, "\tstd %s,16(%s)\n", reg_names[0], reg_names[1]);
13987132718Skan
13988132718Skan	  if (current_function_needs_context)
13989132718Skan	    {
13990132718Skan	      asm_fprintf (file, "\tstd %s,24(%s)\n",
13991132718Skan			   reg_names[STATIC_CHAIN_REGNUM], reg_names[1]);
13992132718Skan	      fprintf (file, "\tbl %s\n", RS6000_MCOUNT);
13993132718Skan	      asm_fprintf (file, "\tld %s,24(%s)\n",
13994132718Skan			   reg_names[STATIC_CHAIN_REGNUM], reg_names[1]);
13995132718Skan	    }
13996132718Skan	  else
13997132718Skan	    fprintf (file, "\tbl %s\n", RS6000_MCOUNT);
13998132718Skan	}
1399990075Sobrien      break;
1400090075Sobrien    }
1400190075Sobrien}
1400290075Sobrien
14003132718Skan
14004132718Skanstatic int
14005132718Skanrs6000_use_dfa_pipeline_interface (void)
14006132718Skan{
14007132718Skan  return 1;
14008132718Skan}
14009132718Skan
14010132718Skan/* Power4 load update and store update instructions are cracked into a
14011132718Skan   load or store and an integer insn which are executed in the same cycle.
14012132718Skan   Branches have their own dispatch slot which does not count against the
14013132718Skan   GCC issue rate, but it changes the program flow so there are no other
14014132718Skan   instructions to issue in this cycle.  */
14015132718Skan
14016132718Skanstatic int
14017132718Skanrs6000_variable_issue (FILE *stream ATTRIBUTE_UNUSED,
14018132718Skan		       int verbose ATTRIBUTE_UNUSED,
14019132718Skan		       rtx insn, int more)
14020132718Skan{
14021132718Skan  if (GET_CODE (PATTERN (insn)) == USE
14022132718Skan      || GET_CODE (PATTERN (insn)) == CLOBBER)
14023132718Skan    return more;
14024132718Skan
14025132718Skan  if (rs6000_sched_groups)
14026132718Skan    {
14027132718Skan      if (is_microcoded_insn (insn))
14028132718Skan        return 0;
14029132718Skan      else if (is_cracked_insn (insn))
14030132718Skan        return more > 2 ? more - 2 : 0;
14031132718Skan    }
14032132718Skan
14033132718Skan  return more - 1;
14034132718Skan}
14035132718Skan
1403690075Sobrien/* Adjust the cost of a scheduling dependency.  Return the new cost of
1403790075Sobrien   a dependency LINK or INSN on DEP_INSN.  COST is the current cost.  */
1403890075Sobrien
1403990075Sobrienstatic int
14040132718Skanrs6000_adjust_cost (rtx insn, rtx link, rtx dep_insn ATTRIBUTE_UNUSED,
14041132718Skan		    int cost)
1404290075Sobrien{
1404390075Sobrien  if (! recog_memoized (insn))
1404490075Sobrien    return 0;
1404590075Sobrien
1404690075Sobrien  if (REG_NOTE_KIND (link) != 0)
1404790075Sobrien    return 0;
1404890075Sobrien
1404990075Sobrien  if (REG_NOTE_KIND (link) == 0)
1405090075Sobrien    {
1405190075Sobrien      /* Data dependency; DEP_INSN writes a register that INSN reads
1405290075Sobrien	 some cycles later.  */
1405390075Sobrien      switch (get_attr_type (insn))
1405490075Sobrien	{
1405590075Sobrien	case TYPE_JMPREG:
14056117395Skan	  /* Tell the first scheduling pass about the latency between
1405790075Sobrien	     a mtctr and bctr (and mtlr and br/blr).  The first
1405890075Sobrien	     scheduling pass will not know about this latency since
1405990075Sobrien	     the mtctr instruction, which has the latency associated
1406090075Sobrien	     to it, will be generated by reload.  */
14061117395Skan	  return TARGET_POWER ? 5 : 4;
1406290075Sobrien	case TYPE_BRANCH:
1406390075Sobrien	  /* Leave some extra cycles between a compare and its
1406490075Sobrien	     dependent branch, to inhibit expensive mispredicts.  */
14065117395Skan	  if ((rs6000_cpu_attr == CPU_PPC603
14066117395Skan	       || rs6000_cpu_attr == CPU_PPC604
14067117395Skan	       || rs6000_cpu_attr == CPU_PPC604E
14068117395Skan	       || rs6000_cpu_attr == CPU_PPC620
14069117395Skan	       || rs6000_cpu_attr == CPU_PPC630
14070117395Skan	       || rs6000_cpu_attr == CPU_PPC750
14071117395Skan	       || rs6000_cpu_attr == CPU_PPC7400
14072117395Skan	       || rs6000_cpu_attr == CPU_PPC7450
14073132718Skan	       || rs6000_cpu_attr == CPU_POWER4
14074132718Skan	       || rs6000_cpu_attr == CPU_POWER5)
1407590075Sobrien	      && recog_memoized (dep_insn)
1407690075Sobrien	      && (INSN_CODE (dep_insn) >= 0)
14077132718Skan	      && (get_attr_type (dep_insn) == TYPE_CMP
14078132718Skan		  || get_attr_type (dep_insn) == TYPE_COMPARE
1407990075Sobrien		  || get_attr_type (dep_insn) == TYPE_DELAYED_COMPARE
14080132718Skan		  || get_attr_type (dep_insn) == TYPE_IMUL_COMPARE
14081132718Skan		  || get_attr_type (dep_insn) == TYPE_LMUL_COMPARE
1408290075Sobrien		  || get_attr_type (dep_insn) == TYPE_FPCOMPARE
14083132718Skan		  || get_attr_type (dep_insn) == TYPE_CR_LOGICAL
14084132718Skan		  || get_attr_type (dep_insn) == TYPE_DELAYED_CR))
1408590075Sobrien	    return cost + 2;
1408690075Sobrien	default:
1408790075Sobrien	  break;
1408890075Sobrien	}
1408990075Sobrien      /* Fall out to return default cost.  */
1409090075Sobrien    }
1409190075Sobrien
1409290075Sobrien  return cost;
1409390075Sobrien}
1409490075Sobrien
14095132718Skan/* The function returns a true if INSN is microcoded.
14096132718Skan   Return false otherwise.  */
14097132718Skan
14098132718Skanstatic bool
14099132718Skanis_microcoded_insn (rtx insn)
14100132718Skan{
14101132718Skan  if (!insn || !INSN_P (insn)
14102132718Skan      || GET_CODE (PATTERN (insn)) == USE
14103132718Skan      || GET_CODE (PATTERN (insn)) == CLOBBER)
14104132718Skan    return false;
14105132718Skan
14106132718Skan  if (rs6000_sched_groups)
14107132718Skan    {
14108132718Skan      enum attr_type type = get_attr_type (insn);
14109132718Skan      if (type == TYPE_LOAD_EXT_U
14110132718Skan	  || type == TYPE_LOAD_EXT_UX
14111132718Skan	  || type == TYPE_LOAD_UX
14112132718Skan	  || type == TYPE_STORE_UX
14113132718Skan	  || type == TYPE_MFCR)
14114132718Skan        return true;
14115132718Skan    }
14116132718Skan
14117132718Skan  return false;
14118132718Skan}
14119132718Skan
14120132718Skan/* The function returns a nonzero value if INSN can be scheduled only
14121132718Skan   as the first insn in a dispatch group ("dispatch-slot restricted").
14122132718Skan   In this case, the returned value indicates how many dispatch slots
14123132718Skan   the insn occupies (at the beginning of the group).
14124132718Skan   Return 0 otherwise.  */
14125132718Skan
14126132718Skanstatic int
14127132718Skanis_dispatch_slot_restricted (rtx insn)
14128132718Skan{
14129132718Skan  enum attr_type type;
14130132718Skan
14131132718Skan  if (!rs6000_sched_groups)
14132132718Skan    return 0;
14133132718Skan
14134132718Skan  if (!insn
14135132718Skan      || insn == NULL_RTX
14136132718Skan      || GET_CODE (insn) == NOTE
14137132718Skan      || GET_CODE (PATTERN (insn)) == USE
14138132718Skan      || GET_CODE (PATTERN (insn)) == CLOBBER)
14139132718Skan    return 0;
14140132718Skan
14141132718Skan  type = get_attr_type (insn);
14142132718Skan
14143132718Skan  switch (type)
14144132718Skan    {
14145132718Skan    case TYPE_MFCR:
14146132718Skan    case TYPE_MFCRF:
14147132718Skan    case TYPE_MTCR:
14148132718Skan    case TYPE_DELAYED_CR:
14149132718Skan    case TYPE_CR_LOGICAL:
14150132718Skan    case TYPE_MTJMPR:
14151132718Skan    case TYPE_MFJMPR:
14152132718Skan      return 1;
14153132718Skan    case TYPE_IDIV:
14154132718Skan    case TYPE_LDIV:
14155132718Skan      return 2;
14156132718Skan    default:
14157132718Skan      if (rs6000_cpu == PROCESSOR_POWER5
14158132718Skan	  && is_cracked_insn (insn))
14159132718Skan	return 2;
14160132718Skan      return 0;
14161132718Skan    }
14162132718Skan}
14163132718Skan
14164132718Skan/* The function returns true if INSN is cracked into 2 instructions
14165132718Skan   by the processor (and therefore occupies 2 issue slots).  */
14166132718Skan
14167132718Skanstatic bool
14168132718Skanis_cracked_insn (rtx insn)
14169132718Skan{
14170132718Skan  if (!insn || !INSN_P (insn)
14171132718Skan      || GET_CODE (PATTERN (insn)) == USE
14172132718Skan      || GET_CODE (PATTERN (insn)) == CLOBBER)
14173132718Skan    return false;
14174132718Skan
14175132718Skan  if (rs6000_sched_groups)
14176132718Skan    {
14177132718Skan      enum attr_type type = get_attr_type (insn);
14178132718Skan      if (type == TYPE_LOAD_U || type == TYPE_STORE_U
14179132718Skan	       || type == TYPE_FPLOAD_U || type == TYPE_FPSTORE_U
14180132718Skan	       || type == TYPE_FPLOAD_UX || type == TYPE_FPSTORE_UX
14181132718Skan	       || type == TYPE_LOAD_EXT || type == TYPE_DELAYED_CR
14182132718Skan	       || type == TYPE_COMPARE || type == TYPE_DELAYED_COMPARE
14183132718Skan	       || type == TYPE_IMUL_COMPARE || type == TYPE_LMUL_COMPARE
14184132718Skan	       || type == TYPE_IDIV || type == TYPE_LDIV
14185132718Skan	       || type == TYPE_INSERT_WORD)
14186132718Skan        return true;
14187132718Skan    }
14188132718Skan
14189132718Skan  return false;
14190132718Skan}
14191132718Skan
14192132718Skan/* The function returns true if INSN can be issued only from
14193132718Skan   the branch slot.  */
14194132718Skan
14195132718Skanstatic bool
14196132718Skanis_branch_slot_insn (rtx insn)
14197132718Skan{
14198132718Skan  if (!insn || !INSN_P (insn)
14199132718Skan      || GET_CODE (PATTERN (insn)) == USE
14200132718Skan      || GET_CODE (PATTERN (insn)) == CLOBBER)
14201132718Skan    return false;
14202132718Skan
14203132718Skan  if (rs6000_sched_groups)
14204132718Skan    {
14205132718Skan      enum attr_type type = get_attr_type (insn);
14206132718Skan      if (type == TYPE_BRANCH || type == TYPE_JMPREG)
14207132718Skan	return true;
14208132718Skan      return false;
14209132718Skan    }
14210132718Skan
14211132718Skan  return false;
14212132718Skan}
14213132718Skan
1421490075Sobrien/* A C statement (sans semicolon) to update the integer scheduling
14215132718Skan   priority INSN_PRIORITY (INSN). Increase the priority to execute the
14216132718Skan   INSN earlier, reduce the priority to execute INSN later.  Do not
1421790075Sobrien   define this macro if you do not need to adjust the scheduling
1421890075Sobrien   priorities of insns.  */
1421990075Sobrien
1422090075Sobrienstatic int
14221132718Skanrs6000_adjust_priority (rtx insn ATTRIBUTE_UNUSED, int priority)
1422290075Sobrien{
1422390075Sobrien  /* On machines (like the 750) which have asymmetric integer units,
1422490075Sobrien     where one integer unit can do multiply and divides and the other
1422590075Sobrien     can't, reduce the priority of multiply/divide so it is scheduled
1422690075Sobrien     before other integer operations.  */
1422790075Sobrien
1422890075Sobrien#if 0
1422990075Sobrien  if (! INSN_P (insn))
1423090075Sobrien    return priority;
1423190075Sobrien
1423290075Sobrien  if (GET_CODE (PATTERN (insn)) == USE)
1423390075Sobrien    return priority;
1423490075Sobrien
1423590075Sobrien  switch (rs6000_cpu_attr) {
1423690075Sobrien  case CPU_PPC750:
1423790075Sobrien    switch (get_attr_type (insn))
1423890075Sobrien      {
1423990075Sobrien      default:
1424090075Sobrien	break;
1424190075Sobrien
1424290075Sobrien      case TYPE_IMUL:
1424390075Sobrien      case TYPE_IDIV:
1424490075Sobrien	fprintf (stderr, "priority was %#x (%d) before adjustment\n",
1424590075Sobrien		 priority, priority);
1424690075Sobrien	if (priority >= 0 && priority < 0x01000000)
1424790075Sobrien	  priority >>= 3;
1424890075Sobrien	break;
1424990075Sobrien      }
1425090075Sobrien  }
1425190075Sobrien#endif
1425290075Sobrien
14253132718Skan  if (is_dispatch_slot_restricted (insn)
14254132718Skan      && reload_completed
14255132718Skan      && current_sched_info->sched_max_insns_priority
14256132718Skan      && rs6000_sched_restricted_insns_priority)
14257132718Skan    {
14258132718Skan
14259132718Skan      /* Prioritize insns that can be dispatched only in the first dispatch slot.  */
14260132718Skan      if (rs6000_sched_restricted_insns_priority == 1)
14261132718Skan	/* Attach highest priority to insn. This means that in
14262132718Skan	   haifa-sched.c:ready_sort(), dispatch-slot restriction considerations
14263132718Skan	   precede 'priority' (critical path) considerations.  */
14264132718Skan	return current_sched_info->sched_max_insns_priority;
14265132718Skan      else if (rs6000_sched_restricted_insns_priority == 2)
14266132718Skan	/* Increase priority of insn by a minimal amount. This means that in
14267132718Skan	   haifa-sched.c:ready_sort(), only 'priority' (critical path) considerations
14268132718Skan	   precede dispatch-slot restriction considerations.  */
14269132718Skan	return (priority + 1);
14270132718Skan    }
14271132718Skan
1427290075Sobrien  return priority;
1427390075Sobrien}
1427490075Sobrien
1427590075Sobrien/* Return how many instructions the machine can issue per cycle.  */
1427690075Sobrien
1427790075Sobrienstatic int
14278132718Skanrs6000_issue_rate (void)
1427990075Sobrien{
14280132718Skan  /* Use issue rate of 1 for first scheduling pass to decrease degradation.  */
14281132718Skan  if (!reload_completed)
14282132718Skan    return 1;
14283132718Skan
1428490075Sobrien  switch (rs6000_cpu_attr) {
1428590075Sobrien  case CPU_RIOS1:  /* ? */
1428690075Sobrien  case CPU_RS64A:
1428790075Sobrien  case CPU_PPC601: /* ? */
1428890075Sobrien  case CPU_PPC7450:
1428990075Sobrien    return 3;
14290132718Skan  case CPU_PPC440:
1429190075Sobrien  case CPU_PPC603:
1429290075Sobrien  case CPU_PPC750:
1429390075Sobrien  case CPU_PPC7400:
14294132718Skan  case CPU_PPC8540:
1429590075Sobrien    return 2;
1429690075Sobrien  case CPU_RIOS2:
1429790075Sobrien  case CPU_PPC604:
1429890075Sobrien  case CPU_PPC604E:
1429990075Sobrien  case CPU_PPC620:
1430090075Sobrien  case CPU_PPC630:
14301132718Skan    return 4;
14302117395Skan  case CPU_POWER4:
14303132718Skan  case CPU_POWER5:
14304132718Skan    return 5;
1430590075Sobrien  default:
1430690075Sobrien    return 1;
1430790075Sobrien  }
1430890075Sobrien}
1430990075Sobrien
14310132718Skan/* Return how many instructions to look ahead for better insn
14311132718Skan   scheduling.  */
14312132718Skan
14313132718Skanstatic int
14314132718Skanrs6000_use_sched_lookahead (void)
14315132718Skan{
14316132718Skan  if (rs6000_cpu_attr == CPU_PPC8540)
14317132718Skan    return 4;
14318132718Skan  return 0;
14319132718Skan}
14320132718Skan
14321132718Skan/* Determine is PAT refers to memory.  */
14322132718Skan
14323132718Skanstatic bool
14324132718Skanis_mem_ref (rtx pat)
14325132718Skan{
14326132718Skan  const char * fmt;
14327132718Skan  int i, j;
14328132718Skan  bool ret = false;
14329132718Skan
14330132718Skan  if (GET_CODE (pat) == MEM)
14331132718Skan    return true;
14332132718Skan
14333132718Skan  /* Recursively process the pattern.  */
14334132718Skan  fmt = GET_RTX_FORMAT (GET_CODE (pat));
14335132718Skan
14336132718Skan  for (i = GET_RTX_LENGTH (GET_CODE (pat)) - 1; i >= 0 && !ret; i--)
14337132718Skan    {
14338132718Skan      if (fmt[i] == 'e')
14339132718Skan	ret |= is_mem_ref (XEXP (pat, i));
14340132718Skan      else if (fmt[i] == 'E')
14341132718Skan	for (j = XVECLEN (pat, i) - 1; j >= 0; j--)
14342132718Skan	  ret |= is_mem_ref (XVECEXP (pat, i, j));
14343132718Skan    }
14344132718Skan
14345132718Skan  return ret;
14346132718Skan}
14347132718Skan
14348132718Skan/* Determine if PAT is a PATTERN of a load insn.  */
14349132718Skan
14350132718Skanstatic bool
14351132718Skanis_load_insn1 (rtx pat)
14352132718Skan{
14353132718Skan  if (!pat || pat == NULL_RTX)
14354132718Skan    return false;
14355132718Skan
14356132718Skan  if (GET_CODE (pat) == SET)
14357132718Skan    return is_mem_ref (SET_SRC (pat));
14358132718Skan
14359132718Skan  if (GET_CODE (pat) == PARALLEL)
14360132718Skan    {
14361132718Skan      int i;
14362132718Skan
14363132718Skan      for (i = 0; i < XVECLEN (pat, 0); i++)
14364132718Skan	if (is_load_insn1 (XVECEXP (pat, 0, i)))
14365132718Skan	  return true;
14366132718Skan    }
14367132718Skan
14368132718Skan  return false;
14369132718Skan}
14370132718Skan
14371132718Skan/* Determine if INSN loads from memory.  */
14372132718Skan
14373132718Skanstatic bool
14374132718Skanis_load_insn (rtx insn)
14375132718Skan{
14376132718Skan  if (!insn || !INSN_P (insn))
14377132718Skan    return false;
14378132718Skan
14379132718Skan  if (GET_CODE (insn) == CALL_INSN)
14380132718Skan    return false;
14381132718Skan
14382132718Skan  return is_load_insn1 (PATTERN (insn));
14383132718Skan}
14384132718Skan
14385132718Skan/* Determine if PAT is a PATTERN of a store insn.  */
14386132718Skan
14387132718Skanstatic bool
14388132718Skanis_store_insn1 (rtx pat)
14389132718Skan{
14390132718Skan  if (!pat || pat == NULL_RTX)
14391132718Skan    return false;
14392132718Skan
14393132718Skan  if (GET_CODE (pat) == SET)
14394132718Skan    return is_mem_ref (SET_DEST (pat));
14395132718Skan
14396132718Skan  if (GET_CODE (pat) == PARALLEL)
14397132718Skan    {
14398132718Skan      int i;
14399132718Skan
14400132718Skan      for (i = 0; i < XVECLEN (pat, 0); i++)
14401132718Skan	if (is_store_insn1 (XVECEXP (pat, 0, i)))
14402132718Skan	  return true;
14403132718Skan    }
14404132718Skan
14405132718Skan  return false;
14406132718Skan}
14407132718Skan
14408132718Skan/* Determine if INSN stores to memory.  */
14409132718Skan
14410132718Skanstatic bool
14411132718Skanis_store_insn (rtx insn)
14412132718Skan{
14413132718Skan  if (!insn || !INSN_P (insn))
14414132718Skan    return false;
14415132718Skan
14416132718Skan  return is_store_insn1 (PATTERN (insn));
14417132718Skan}
14418132718Skan
14419132718Skan/* Returns whether the dependence between INSN and NEXT is considered
14420132718Skan   costly by the given target.  */
14421132718Skan
14422132718Skanstatic bool
14423132718Skanrs6000_is_costly_dependence (rtx insn, rtx next, rtx link, int cost, int distance)
14424132718Skan{
14425132718Skan  /* If the flag is not enbled - no dependence is considered costly;
14426132718Skan     allow all dependent insns in the same group.
14427132718Skan     This is the most aggressive option.  */
14428132718Skan  if (rs6000_sched_costly_dep == no_dep_costly)
14429132718Skan    return false;
14430132718Skan
14431132718Skan  /* If the flag is set to 1 - a dependence is always considered costly;
14432132718Skan     do not allow dependent instructions in the same group.
14433132718Skan     This is the most conservative option.  */
14434132718Skan  if (rs6000_sched_costly_dep == all_deps_costly)
14435132718Skan    return true;
14436132718Skan
14437132718Skan  if (rs6000_sched_costly_dep == store_to_load_dep_costly
14438132718Skan      && is_load_insn (next)
14439132718Skan      && is_store_insn (insn))
14440132718Skan    /* Prevent load after store in the same group.  */
14441132718Skan    return true;
14442132718Skan
14443132718Skan  if (rs6000_sched_costly_dep == true_store_to_load_dep_costly
14444132718Skan      && is_load_insn (next)
14445132718Skan      && is_store_insn (insn)
14446132718Skan      && (!link || (int) REG_NOTE_KIND (link) == 0))
14447132718Skan     /* Prevent load after store in the same group if it is a true dependence.  */
14448132718Skan     return true;
14449132718Skan
14450132718Skan  /* The flag is set to X; dependences with latency >= X are considered costly,
14451132718Skan     and will not be scheduled in the same group.  */
14452132718Skan  if (rs6000_sched_costly_dep <= max_dep_latency
14453132718Skan      && ((cost - distance) >= (int)rs6000_sched_costly_dep))
14454132718Skan    return true;
14455132718Skan
14456132718Skan  return false;
14457132718Skan}
14458132718Skan
14459132718Skan/* Return the next insn after INSN that is found before TAIL is reached,
14460132718Skan   skipping any "non-active" insns - insns that will not actually occupy
14461132718Skan   an issue slot.  Return NULL_RTX if such an insn is not found.  */
14462132718Skan
14463132718Skanstatic rtx
14464132718Skanget_next_active_insn (rtx insn, rtx tail)
14465132718Skan{
14466132718Skan  rtx next_insn;
14467132718Skan
14468132718Skan  if (!insn || insn == tail)
14469132718Skan    return NULL_RTX;
14470132718Skan
14471132718Skan  next_insn = NEXT_INSN (insn);
14472132718Skan
14473132718Skan  while (next_insn
14474132718Skan  	 && next_insn != tail
14475132718Skan	 && (GET_CODE(next_insn) == NOTE
14476132718Skan	     || GET_CODE (PATTERN (next_insn)) == USE
14477132718Skan	     || GET_CODE (PATTERN (next_insn)) == CLOBBER))
14478132718Skan    {
14479132718Skan      next_insn = NEXT_INSN (next_insn);
14480132718Skan    }
14481132718Skan
14482132718Skan  if (!next_insn || next_insn == tail)
14483132718Skan    return NULL_RTX;
14484132718Skan
14485132718Skan  return next_insn;
14486132718Skan}
14487132718Skan
14488132718Skan/* Return whether the presence of INSN causes a dispatch group termination
14489132718Skan   of group WHICH_GROUP.
14490132718Skan
14491132718Skan   If WHICH_GROUP == current_group, this function will return true if INSN
14492132718Skan   causes the termination of the current group (i.e, the dispatch group to
14493132718Skan   which INSN belongs). This means that INSN will be the last insn in the
14494132718Skan   group it belongs to.
14495132718Skan
14496132718Skan   If WHICH_GROUP == previous_group, this function will return true if INSN
14497132718Skan   causes the termination of the previous group (i.e, the dispatch group that
14498132718Skan   precedes the group to which INSN belongs).  This means that INSN will be
14499132718Skan   the first insn in the group it belongs to).  */
14500132718Skan
14501132718Skanstatic bool
14502132718Skaninsn_terminates_group_p (rtx insn, enum group_termination which_group)
14503132718Skan{
14504132718Skan  enum attr_type type;
14505132718Skan
14506132718Skan  if (! insn)
14507132718Skan    return false;
14508132718Skan
14509132718Skan  type = get_attr_type (insn);
14510132718Skan
14511132718Skan  if (is_microcoded_insn (insn))
14512132718Skan    return true;
14513132718Skan
14514132718Skan  if (which_group == current_group)
14515132718Skan    {
14516132718Skan      if (is_branch_slot_insn (insn))
14517132718Skan        return true;
14518132718Skan      return false;
14519132718Skan    }
14520132718Skan  else if (which_group == previous_group)
14521132718Skan    {
14522132718Skan      if (is_dispatch_slot_restricted (insn))
14523132718Skan        return true;
14524132718Skan      return false;
14525132718Skan    }
14526132718Skan
14527132718Skan  return false;
14528132718Skan}
14529132718Skan
14530132718Skan/* Return true if it is recommended to keep NEXT_INSN "far" (in a separate
14531132718Skan   dispatch group) from the insns in GROUP_INSNS.  Return false otherwise.  */
14532132718Skan
14533132718Skanstatic bool
14534132718Skanis_costly_group (rtx *group_insns, rtx next_insn)
14535132718Skan{
14536132718Skan  int i;
14537132718Skan  rtx link;
14538132718Skan  int cost;
14539132718Skan  int issue_rate = rs6000_issue_rate ();
14540132718Skan
14541132718Skan  for (i = 0; i < issue_rate; i++)
14542132718Skan    {
14543132718Skan      rtx insn = group_insns[i];
14544132718Skan      if (!insn)
14545132718Skan        continue;
14546132718Skan      for (link = INSN_DEPEND (insn); link != 0; link = XEXP (link, 1))
14547132718Skan        {
14548132718Skan          rtx next = XEXP (link, 0);
14549132718Skan          if (next == next_insn)
14550132718Skan            {
14551132718Skan              cost = insn_cost (insn, link, next_insn);
14552132718Skan              if (rs6000_is_costly_dependence (insn, next_insn, link, cost, 0))
14553132718Skan                return true;
14554132718Skan            }
14555132718Skan        }
14556132718Skan    }
14557132718Skan
14558132718Skan  return false;
14559132718Skan}
14560132718Skan
14561132718Skan/* Utility of the function redefine_groups.
14562132718Skan   Check if it is too costly to schedule NEXT_INSN together with GROUP_INSNS
14563132718Skan   in the same dispatch group.  If so, insert nops before NEXT_INSN, in order
14564132718Skan   to keep it "far" (in a separate group) from GROUP_INSNS, following
14565132718Skan   one of the following schemes, depending on the value of the flag
14566132718Skan   -minsert_sched_nops = X:
14567132718Skan   (1) X == sched_finish_regroup_exact: insert exactly as many nops as needed
14568132718Skan       in order to force NEXT_INSN into a separate group.
14569132718Skan   (2) X < sched_finish_regroup_exact: insert exactly X nops.
14570132718Skan   GROUP_END, CAN_ISSUE_MORE and GROUP_COUNT record the state after nop
14571132718Skan   insertion (has a group just ended, how many vacant issue slots remain in the
14572132718Skan   last group, and how many dispatch groups were encountered so far).  */
14573132718Skan
14574132718Skanstatic int
14575132718Skanforce_new_group (int sched_verbose, FILE *dump, rtx *group_insns, rtx next_insn,
14576132718Skan		 bool *group_end, int can_issue_more, int *group_count)
14577132718Skan{
14578132718Skan  rtx nop;
14579132718Skan  bool force;
14580132718Skan  int issue_rate = rs6000_issue_rate ();
14581132718Skan  bool end = *group_end;
14582132718Skan  int i;
14583132718Skan
14584132718Skan  if (next_insn == NULL_RTX)
14585132718Skan    return can_issue_more;
14586132718Skan
14587132718Skan  if (rs6000_sched_insert_nops > sched_finish_regroup_exact)
14588132718Skan    return can_issue_more;
14589132718Skan
14590132718Skan  force = is_costly_group (group_insns, next_insn);
14591132718Skan  if (!force)
14592132718Skan    return can_issue_more;
14593132718Skan
14594132718Skan  if (sched_verbose > 6)
14595132718Skan    fprintf (dump,"force: group count = %d, can_issue_more = %d\n",
14596132718Skan			*group_count ,can_issue_more);
14597132718Skan
14598132718Skan  if (rs6000_sched_insert_nops == sched_finish_regroup_exact)
14599132718Skan    {
14600132718Skan      if (*group_end)
14601132718Skan        can_issue_more = 0;
14602132718Skan
14603132718Skan      /* Since only a branch can be issued in the last issue_slot, it is
14604132718Skan	 sufficient to insert 'can_issue_more - 1' nops if next_insn is not
14605132718Skan	 a branch. If next_insn is a branch, we insert 'can_issue_more' nops;
14606132718Skan	 in this case the last nop will start a new group and the branch will be
14607132718Skan	 forced to the new group.  */
14608132718Skan      if (can_issue_more && !is_branch_slot_insn (next_insn))
14609132718Skan        can_issue_more--;
14610132718Skan
14611132718Skan      while (can_issue_more > 0)
14612132718Skan        {
14613132718Skan          nop = gen_nop();
14614132718Skan          emit_insn_before (nop, next_insn);
14615132718Skan          can_issue_more--;
14616132718Skan        }
14617132718Skan
14618132718Skan      *group_end = true;
14619132718Skan      return 0;
14620132718Skan    }
14621132718Skan
14622132718Skan  if (rs6000_sched_insert_nops < sched_finish_regroup_exact)
14623132718Skan    {
14624132718Skan      int n_nops = rs6000_sched_insert_nops;
14625132718Skan
14626132718Skan      /* Nops can't be issued from the branch slot, so the effective
14627132718Skan         issue_rate for nops is 'issue_rate - 1'.  */
14628132718Skan      if (can_issue_more == 0)
14629132718Skan        can_issue_more = issue_rate;
14630132718Skan      can_issue_more--;
14631132718Skan      if (can_issue_more == 0)
14632132718Skan        {
14633132718Skan          can_issue_more = issue_rate - 1;
14634132718Skan          (*group_count)++;
14635132718Skan          end = true;
14636132718Skan          for (i = 0; i < issue_rate; i++)
14637132718Skan            {
14638132718Skan              group_insns[i] = 0;
14639132718Skan            }
14640132718Skan        }
14641132718Skan
14642132718Skan      while (n_nops > 0)
14643132718Skan        {
14644132718Skan          nop = gen_nop ();
14645132718Skan          emit_insn_before (nop, next_insn);
14646132718Skan          if (can_issue_more == issue_rate - 1) /* new group begins */
14647132718Skan            end = false;
14648132718Skan          can_issue_more--;
14649132718Skan          if (can_issue_more == 0)
14650132718Skan            {
14651132718Skan              can_issue_more = issue_rate - 1;
14652132718Skan              (*group_count)++;
14653132718Skan              end = true;
14654132718Skan              for (i = 0; i < issue_rate; i++)
14655132718Skan                {
14656132718Skan                  group_insns[i] = 0;
14657132718Skan                }
14658132718Skan            }
14659132718Skan          n_nops--;
14660132718Skan        }
14661132718Skan
14662132718Skan      /* Scale back relative to 'issue_rate' (instead of 'issue_rate - 1').  */
14663132718Skan      can_issue_more++;
14664132718Skan
14665132718Skan      *group_end = /* Is next_insn going to start a new group?  */
14666132718Skan	  (end
14667132718Skan	   || (can_issue_more == 1 && !is_branch_slot_insn (next_insn))
14668132718Skan	   || (can_issue_more <= 2 && is_cracked_insn (next_insn))
14669132718Skan	   || (can_issue_more < issue_rate &&
14670132718Skan	      insn_terminates_group_p (next_insn, previous_group)));
14671132718Skan      if (*group_end && end)
14672132718Skan        (*group_count)--;
14673132718Skan
14674132718Skan      if (sched_verbose > 6)
14675132718Skan        fprintf (dump, "done force: group count = %d, can_issue_more = %d\n",
14676132718Skan			*group_count, can_issue_more);
14677132718Skan      return can_issue_more;
14678132718Skan    }
14679132718Skan
14680132718Skan  return can_issue_more;
14681132718Skan}
14682132718Skan
14683132718Skan/* This function tries to synch the dispatch groups that the compiler "sees"
14684132718Skan   with the dispatch groups that the processor dispatcher is expected to
14685132718Skan   form in practice.  It tries to achieve this synchronization by forcing the
14686132718Skan   estimated processor grouping on the compiler (as opposed to the function
14687132718Skan   'pad_goups' which tries to force the scheduler's grouping on the processor).
14688132718Skan
14689132718Skan   The function scans the insn sequence between PREV_HEAD_INSN and TAIL and
14690132718Skan   examines the (estimated) dispatch groups that will be formed by the processor
14691132718Skan   dispatcher.  It marks these group boundaries to reflect the estimated
14692132718Skan   processor grouping, overriding the grouping that the scheduler had marked.
14693132718Skan   Depending on the value of the flag '-minsert-sched-nops' this function can
14694132718Skan   force certain insns into separate groups or force a certain distance between
14695132718Skan   them by inserting nops, for example, if there exists a "costly dependence"
14696132718Skan   between the insns.
14697132718Skan
14698132718Skan   The function estimates the group boundaries that the processor will form as
14699132718Skan   folllows:  It keeps track of how many vacant issue slots are available after
14700132718Skan   each insn.  A subsequent insn will start a new group if one of the following
14701132718Skan   4 cases applies:
14702132718Skan   - no more vacant issue slots remain in the current dispatch group.
14703132718Skan   - only the last issue slot, which is the branch slot, is vacant, but the next
14704132718Skan     insn is not a branch.
14705132718Skan   - only the last 2 or less issue slots, including the branch slot, are vacant,
14706132718Skan     which means that a cracked insn (which occupies two issue slots) can't be
14707132718Skan     issued in this group.
14708132718Skan   - less than 'issue_rate' slots are vacant, and the next insn always needs to
14709132718Skan     start a new group.  */
14710132718Skan
14711132718Skanstatic int
14712132718Skanredefine_groups (FILE *dump, int sched_verbose, rtx prev_head_insn, rtx tail)
14713132718Skan{
14714132718Skan  rtx insn, next_insn;
14715132718Skan  int issue_rate;
14716132718Skan  int can_issue_more;
14717132718Skan  int slot, i;
14718132718Skan  bool group_end;
14719132718Skan  int group_count = 0;
14720132718Skan  rtx *group_insns;
14721132718Skan
14722132718Skan  /* Initialize.  */
14723132718Skan  issue_rate = rs6000_issue_rate ();
14724132718Skan  group_insns = alloca (issue_rate * sizeof (rtx));
14725132718Skan  for (i = 0; i < issue_rate; i++)
14726132718Skan    {
14727132718Skan      group_insns[i] = 0;
14728132718Skan    }
14729132718Skan  can_issue_more = issue_rate;
14730132718Skan  slot = 0;
14731132718Skan  insn = get_next_active_insn (prev_head_insn, tail);
14732132718Skan  group_end = false;
14733132718Skan
14734132718Skan  while (insn != NULL_RTX)
14735132718Skan    {
14736132718Skan      slot = (issue_rate - can_issue_more);
14737132718Skan      group_insns[slot] = insn;
14738132718Skan      can_issue_more =
14739132718Skan        rs6000_variable_issue (dump, sched_verbose, insn, can_issue_more);
14740132718Skan      if (insn_terminates_group_p (insn, current_group))
14741132718Skan        can_issue_more = 0;
14742132718Skan
14743132718Skan      next_insn = get_next_active_insn (insn, tail);
14744132718Skan      if (next_insn == NULL_RTX)
14745132718Skan        return group_count + 1;
14746132718Skan
14747132718Skan      group_end = /* Is next_insn going to start a new group?  */
14748132718Skan        (can_issue_more == 0
14749132718Skan         || (can_issue_more == 1 && !is_branch_slot_insn (next_insn))
14750132718Skan         || (can_issue_more <= 2 && is_cracked_insn (next_insn))
14751132718Skan         || (can_issue_more < issue_rate &&
14752132718Skan             insn_terminates_group_p (next_insn, previous_group)));
14753132718Skan
14754132718Skan      can_issue_more = force_new_group (sched_verbose, dump, group_insns,
14755132718Skan			next_insn, &group_end, can_issue_more, &group_count);
14756132718Skan
14757132718Skan      if (group_end)
14758132718Skan        {
14759132718Skan          group_count++;
14760132718Skan          can_issue_more = 0;
14761132718Skan          for (i = 0; i < issue_rate; i++)
14762132718Skan            {
14763132718Skan              group_insns[i] = 0;
14764132718Skan            }
14765132718Skan        }
14766132718Skan
14767132718Skan      if (GET_MODE (next_insn) == TImode && can_issue_more)
14768132718Skan        PUT_MODE(next_insn, VOIDmode);
14769132718Skan      else if (!can_issue_more && GET_MODE (next_insn) != TImode)
14770132718Skan        PUT_MODE (next_insn, TImode);
14771132718Skan
14772132718Skan      insn = next_insn;
14773132718Skan      if (can_issue_more == 0)
14774132718Skan        can_issue_more = issue_rate;
14775132718Skan   } /* while */
14776132718Skan
14777132718Skan  return group_count;
14778132718Skan}
14779132718Skan
14780132718Skan/* Scan the insn sequence between PREV_HEAD_INSN and TAIL and examine the
14781132718Skan   dispatch group boundaries that the scheduler had marked.  Pad with nops
14782132718Skan   any dispatch groups which have vacant issue slots, in order to force the
14783132718Skan   scheduler's grouping on the processor dispatcher.  The function
14784132718Skan   returns the number of dispatch groups found.  */
14785132718Skan
14786132718Skanstatic int
14787132718Skanpad_groups (FILE *dump, int sched_verbose, rtx prev_head_insn, rtx tail)
14788132718Skan{
14789132718Skan  rtx insn, next_insn;
14790132718Skan  rtx nop;
14791132718Skan  int issue_rate;
14792132718Skan  int can_issue_more;
14793132718Skan  int group_end;
14794132718Skan  int group_count = 0;
14795132718Skan
14796132718Skan  /* Initialize issue_rate.  */
14797132718Skan  issue_rate = rs6000_issue_rate ();
14798132718Skan  can_issue_more = issue_rate;
14799132718Skan
14800132718Skan  insn = get_next_active_insn (prev_head_insn, tail);
14801132718Skan  next_insn = get_next_active_insn (insn, tail);
14802132718Skan
14803132718Skan  while (insn != NULL_RTX)
14804132718Skan    {
14805132718Skan      can_issue_more =
14806132718Skan      	rs6000_variable_issue (dump, sched_verbose, insn, can_issue_more);
14807132718Skan
14808132718Skan      group_end = (next_insn == NULL_RTX || GET_MODE (next_insn) == TImode);
14809132718Skan
14810132718Skan      if (next_insn == NULL_RTX)
14811132718Skan        break;
14812132718Skan
14813132718Skan      if (group_end)
14814132718Skan        {
14815132718Skan          /* If the scheduler had marked group termination at this location
14816132718Skan             (between insn and next_indn), and neither insn nor next_insn will
14817132718Skan             force group termination, pad the group with nops to force group
14818132718Skan             termination.  */
14819132718Skan          if (can_issue_more
14820132718Skan              && (rs6000_sched_insert_nops == sched_finish_pad_groups)
14821132718Skan              && !insn_terminates_group_p (insn, current_group)
14822132718Skan              && !insn_terminates_group_p (next_insn, previous_group))
14823132718Skan            {
14824132718Skan              if (!is_branch_slot_insn(next_insn))
14825132718Skan                can_issue_more--;
14826132718Skan
14827132718Skan              while (can_issue_more)
14828132718Skan                {
14829132718Skan                  nop = gen_nop ();
14830132718Skan                  emit_insn_before (nop, next_insn);
14831132718Skan                  can_issue_more--;
14832132718Skan                }
14833132718Skan            }
14834132718Skan
14835132718Skan          can_issue_more = issue_rate;
14836132718Skan          group_count++;
14837132718Skan        }
14838132718Skan
14839132718Skan      insn = next_insn;
14840132718Skan      next_insn = get_next_active_insn (insn, tail);
14841132718Skan    }
14842132718Skan
14843132718Skan  return group_count;
14844132718Skan}
14845132718Skan
14846132718Skan/* The following function is called at the end of scheduling BB.
14847132718Skan   After reload, it inserts nops at insn group bundling.  */
14848132718Skan
14849132718Skanstatic void
14850132718Skanrs6000_sched_finish (FILE *dump, int sched_verbose)
14851132718Skan{
14852132718Skan  int n_groups;
14853132718Skan
14854132718Skan  if (sched_verbose)
14855132718Skan    fprintf (dump, "=== Finishing schedule.\n");
14856132718Skan
14857132718Skan  if (reload_completed && rs6000_sched_groups)
14858132718Skan    {
14859132718Skan      if (rs6000_sched_insert_nops == sched_finish_none)
14860132718Skan        return;
14861132718Skan
14862132718Skan      if (rs6000_sched_insert_nops == sched_finish_pad_groups)
14863132718Skan        n_groups = pad_groups (dump, sched_verbose,
14864132718Skan				current_sched_info->prev_head,
14865132718Skan  			   	current_sched_info->next_tail);
14866132718Skan      else
14867132718Skan        n_groups = redefine_groups (dump, sched_verbose,
14868132718Skan				current_sched_info->prev_head,
14869132718Skan  				current_sched_info->next_tail);
14870132718Skan
14871132718Skan      if (sched_verbose >= 6)
14872132718Skan	{
14873132718Skan    	  fprintf (dump, "ngroups = %d\n", n_groups);
14874132718Skan	  print_rtl (dump, current_sched_info->prev_head);
14875132718Skan	  fprintf (dump, "Done finish_sched\n");
14876132718Skan	}
14877132718Skan    }
14878132718Skan}
1487990075Sobrien
1488090075Sobrien/* Length in units of the trampoline for entering a nested function.  */
1488190075Sobrien
1488290075Sobrienint
14883132718Skanrs6000_trampoline_size (void)
1488490075Sobrien{
1488590075Sobrien  int ret = 0;
1488690075Sobrien
1488790075Sobrien  switch (DEFAULT_ABI)
1488890075Sobrien    {
1488990075Sobrien    default:
1489090075Sobrien      abort ();
1489190075Sobrien
1489290075Sobrien    case ABI_AIX:
1489390075Sobrien      ret = (TARGET_32BIT) ? 12 : 24;
1489490075Sobrien      break;
1489590075Sobrien
1489690075Sobrien    case ABI_DARWIN:
1489790075Sobrien    case ABI_V4:
1489890075Sobrien      ret = (TARGET_32BIT) ? 40 : 48;
1489990075Sobrien      break;
1490090075Sobrien    }
1490190075Sobrien
1490290075Sobrien  return ret;
1490390075Sobrien}
1490490075Sobrien
1490590075Sobrien/* Emit RTL insns to initialize the variable parts of a trampoline.
1490690075Sobrien   FNADDR is an RTX for the address of the function's pure code.
1490790075Sobrien   CXT is an RTX for the static chain value for the function.  */
1490890075Sobrien
1490990075Sobrienvoid
14910132718Skanrs6000_initialize_trampoline (rtx addr, rtx fnaddr, rtx cxt)
1491190075Sobrien{
1491290075Sobrien  enum machine_mode pmode = Pmode;
1491390075Sobrien  int regsize = (TARGET_32BIT) ? 4 : 8;
1491490075Sobrien  rtx ctx_reg = force_reg (pmode, cxt);
1491590075Sobrien
1491690075Sobrien  switch (DEFAULT_ABI)
1491790075Sobrien    {
1491890075Sobrien    default:
1491990075Sobrien      abort ();
1492090075Sobrien
1492190075Sobrien/* Macros to shorten the code expansions below.  */
1492290075Sobrien#define MEM_DEREF(addr) gen_rtx_MEM (pmode, memory_address (pmode, addr))
1492390075Sobrien#define MEM_PLUS(addr,offset) \
1492490075Sobrien  gen_rtx_MEM (pmode, memory_address (pmode, plus_constant (addr, offset)))
1492590075Sobrien
1492690075Sobrien    /* Under AIX, just build the 3 word function descriptor */
1492790075Sobrien    case ABI_AIX:
1492890075Sobrien      {
1492990075Sobrien	rtx fn_reg = gen_reg_rtx (pmode);
1493090075Sobrien	rtx toc_reg = gen_reg_rtx (pmode);
1493190075Sobrien	emit_move_insn (fn_reg, MEM_DEREF (fnaddr));
1493290075Sobrien	emit_move_insn (toc_reg, MEM_PLUS (fnaddr, regsize));
1493390075Sobrien	emit_move_insn (MEM_DEREF (addr), fn_reg);
1493490075Sobrien	emit_move_insn (MEM_PLUS (addr, regsize), toc_reg);
1493590075Sobrien	emit_move_insn (MEM_PLUS (addr, 2*regsize), ctx_reg);
1493690075Sobrien      }
1493790075Sobrien      break;
1493890075Sobrien
1493990075Sobrien    /* Under V.4/eabi/darwin, __trampoline_setup does the real work.  */
1494090075Sobrien    case ABI_DARWIN:
1494190075Sobrien    case ABI_V4:
1494290075Sobrien      emit_library_call (gen_rtx_SYMBOL_REF (SImode, "__trampoline_setup"),
1494390075Sobrien			 FALSE, VOIDmode, 4,
1494490075Sobrien			 addr, pmode,
1494590075Sobrien			 GEN_INT (rs6000_trampoline_size ()), SImode,
1494690075Sobrien			 fnaddr, pmode,
1494790075Sobrien			 ctx_reg, pmode);
1494890075Sobrien      break;
1494990075Sobrien    }
1495090075Sobrien
1495190075Sobrien  return;
1495290075Sobrien}
1495390075Sobrien
1495490075Sobrien
1495590075Sobrien/* Table of valid machine attributes.  */
1495690075Sobrien
1495790075Sobrienconst struct attribute_spec rs6000_attribute_table[] =
1495890075Sobrien{
1495990075Sobrien  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
14960146895Skan  { "altivec",   1, 1, false, true,  false, rs6000_handle_altivec_attribute },
14961117395Skan  { "longcall",  0, 0, false, true,  true,  rs6000_handle_longcall_attribute },
14962117395Skan  { "shortcall", 0, 0, false, true,  true,  rs6000_handle_longcall_attribute },
14963117395Skan  { NULL,        0, 0, false, false, false, NULL }
1496490075Sobrien};
1496590075Sobrien
14966146895Skan/* Handle the "altivec" attribute.  The attribute may have
14967146895Skan   arguments as follows:
14968146895Skan
14969146895Skan       __attribute__((altivec(vector__)))
14970146895Skan       __attribute__((altivec(pixel__)))       (always followed by 'unsigned short')
14971146895Skan       __attribute__((altivec(bool__)))        (always followed by 'unsigned')
14972146895Skan
14973146895Skan  and may appear more than once (e.g., 'vector bool char') in a
14974146895Skan  given declaration.  */
14975146895Skan
14976146895Skanstatic tree
14977146895Skanrs6000_handle_altivec_attribute (tree *node, tree name, tree args,
14978146895Skan				 int flags ATTRIBUTE_UNUSED,
14979146895Skan				 bool *no_add_attrs)
14980146895Skan{
14981146895Skan  tree type = *node, result = NULL_TREE;
14982146895Skan  enum machine_mode mode;
14983146895Skan  int unsigned_p;
14984146895Skan  char altivec_type
14985146895Skan    = ((args && TREE_CODE (args) == TREE_LIST && TREE_VALUE (args)
14986146895Skan       && TREE_CODE (TREE_VALUE (args)) == IDENTIFIER_NODE)
14987146895Skan       ? *IDENTIFIER_POINTER (TREE_VALUE (args))
14988146895Skan       : '?');
14989146895Skan
14990146895Skan  while (POINTER_TYPE_P (type)
14991146895Skan	 || TREE_CODE (type) == FUNCTION_TYPE
14992146895Skan	 || TREE_CODE (type) == METHOD_TYPE
14993146895Skan	 || TREE_CODE (type) == ARRAY_TYPE)
14994146895Skan    type = TREE_TYPE (type);
14995146895Skan
14996146895Skan  mode = TYPE_MODE (type);
14997146895Skan
14998146895Skan  if (rs6000_warn_altivec_long
14999146895Skan      && (type == long_unsigned_type_node || type == long_integer_type_node))
15000146895Skan    warning ("use of 'long' in AltiVec types is deprecated; use 'int'");
15001146895Skan
15002146895Skan  switch (altivec_type)
15003146895Skan    {
15004146895Skan    case 'v':
15005146895Skan      unsigned_p = TREE_UNSIGNED (type);
15006146895Skan      switch (mode)
15007146895Skan	{
15008146895Skan	  case SImode:
15009146895Skan	    result = (unsigned_p ? unsigned_V4SI_type_node : V4SI_type_node);
15010146895Skan	    break;
15011146895Skan	  case HImode:
15012146895Skan	    result = (unsigned_p ? unsigned_V8HI_type_node : V8HI_type_node);
15013146895Skan	    break;
15014146895Skan	  case QImode:
15015146895Skan	    result = (unsigned_p ? unsigned_V16QI_type_node : V16QI_type_node);
15016146895Skan	    break;
15017146895Skan	  case SFmode: result = V4SF_type_node; break;
15018146895Skan	    /* If the user says 'vector int bool', we may be handed the 'bool'
15019146895Skan	       attribute _before_ the 'vector' attribute, and so select the proper
15020146895Skan	       type in the 'b' case below.  */
15021146895Skan	  case V4SImode: case V8HImode: case V16QImode: result = type;
15022146895Skan	  default: break;
15023146895Skan	}
15024146895Skan      break;
15025146895Skan    case 'b':
15026146895Skan      switch (mode)
15027146895Skan	{
15028146895Skan	  case SImode: case V4SImode: result = bool_V4SI_type_node; break;
15029146895Skan	  case HImode: case V8HImode: result = bool_V8HI_type_node; break;
15030146895Skan	  case QImode: case V16QImode: result = bool_V16QI_type_node;
15031146895Skan	  default: break;
15032146895Skan	}
15033146895Skan      break;
15034146895Skan    case 'p':
15035146895Skan      switch (mode)
15036146895Skan	{
15037146895Skan	  case V8HImode: result = pixel_V8HI_type_node;
15038146895Skan	  default: break;
15039146895Skan	}
15040146895Skan    default: break;
15041146895Skan    }
15042146895Skan
15043146895Skan  if (result && result != type && TYPE_READONLY (type))
15044146895Skan    result = build_qualified_type (result, TYPE_QUAL_CONST);
15045146895Skan
15046146895Skan  *no_add_attrs = true;  /* No need to hang on to the attribute.  */
15047146895Skan
15048146895Skan  if (!result)
15049146895Skan    warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
15050146895Skan  else
15051146895Skan    *node = reconstruct_complex_type (*node, result);
15052146895Skan
15053146895Skan  return NULL_TREE;
15054146895Skan}
15055146895Skan
15056146895Skan/* AltiVec defines four built-in scalar types that serve as vector
15057146895Skan   elements; we must teach the compiler how to mangle them.  */
15058146895Skan
15059146895Skanstatic const char *
15060146895Skanrs6000_mangle_fundamental_type (tree type)
15061146895Skan{
15062146895Skan  if (type == bool_char_type_node) return "U6__boolc";
15063146895Skan  if (type == bool_short_type_node) return "U6__bools";
15064146895Skan  if (type == pixel_type_node) return "u7__pixel";
15065146895Skan  if (type == bool_int_type_node) return "U6__booli";
15066146895Skan
15067146895Skan  /* For all other types, use normal C++ mangling.  */
15068146895Skan  return NULL;
15069146895Skan}
15070146895Skan
15071117395Skan/* Handle a "longcall" or "shortcall" attribute; arguments as in
15072117395Skan   struct attribute_spec.handler.  */
1507390075Sobrien
1507490075Sobrienstatic tree
15075132718Skanrs6000_handle_longcall_attribute (tree *node, tree name,
15076132718Skan				  tree args ATTRIBUTE_UNUSED,
15077132718Skan				  int flags ATTRIBUTE_UNUSED,
15078132718Skan				  bool *no_add_attrs)
1507990075Sobrien{
1508090075Sobrien  if (TREE_CODE (*node) != FUNCTION_TYPE
1508190075Sobrien      && TREE_CODE (*node) != FIELD_DECL
1508290075Sobrien      && TREE_CODE (*node) != TYPE_DECL)
1508390075Sobrien    {
1508490075Sobrien      warning ("`%s' attribute only applies to functions",
1508590075Sobrien	       IDENTIFIER_POINTER (name));
1508690075Sobrien      *no_add_attrs = true;
1508790075Sobrien    }
1508890075Sobrien
1508990075Sobrien  return NULL_TREE;
1509090075Sobrien}
1509190075Sobrien
15092117395Skan/* Set longcall attributes on all functions declared when
15093117395Skan   rs6000_default_long_calls is true.  */
15094117395Skanstatic void
15095132718Skanrs6000_set_default_type_attributes (tree type)
15096117395Skan{
15097117395Skan  if (rs6000_default_long_calls
15098117395Skan      && (TREE_CODE (type) == FUNCTION_TYPE
15099117395Skan	  || TREE_CODE (type) == METHOD_TYPE))
15100117395Skan    TYPE_ATTRIBUTES (type) = tree_cons (get_identifier ("longcall"),
15101117395Skan					NULL_TREE,
15102117395Skan					TYPE_ATTRIBUTES (type));
15103117395Skan}
15104117395Skan
1510590075Sobrien/* Return a reference suitable for calling a function with the
1510690075Sobrien   longcall attribute.  */
1510790075Sobrien
1510890075Sobrienstruct rtx_def *
15109132718Skanrs6000_longcall_ref (rtx call_ref)
1511090075Sobrien{
1511190075Sobrien  const char *call_name;
1511290075Sobrien  tree node;
1511390075Sobrien
1511490075Sobrien  if (GET_CODE (call_ref) != SYMBOL_REF)
1511590075Sobrien    return call_ref;
1511690075Sobrien
1511790075Sobrien  /* System V adds '.' to the internal name, so skip them.  */
1511890075Sobrien  call_name = XSTR (call_ref, 0);
1511990075Sobrien  if (*call_name == '.')
1512090075Sobrien    {
1512190075Sobrien      while (*call_name == '.')
1512290075Sobrien	call_name++;
1512390075Sobrien
1512490075Sobrien      node = get_identifier (call_name);
1512590075Sobrien      call_ref = gen_rtx_SYMBOL_REF (VOIDmode, IDENTIFIER_POINTER (node));
1512690075Sobrien    }
1512790075Sobrien
1512890075Sobrien  return force_reg (Pmode, call_ref);
1512990075Sobrien}
1513090075Sobrien
15131117395Skan#ifdef USING_ELFOS_H
15132117395Skan
1513390075Sobrien/* A C statement or statements to switch to the appropriate section
1513490075Sobrien   for output of RTX in mode MODE.  You can assume that RTX is some
1513590075Sobrien   kind of constant in RTL.  The argument MODE is redundant except in
1513690075Sobrien   the case of a `const_int' rtx.  Select the section by calling
1513790075Sobrien   `text_section' or one of the alternatives for other sections.
1513890075Sobrien
1513990075Sobrien   Do not define this macro if you put all constants in the read-only
1514090075Sobrien   data section.  */
1514190075Sobrien
15142117395Skanstatic void
15143132718Skanrs6000_elf_select_rtx_section (enum machine_mode mode, rtx x,
15144132718Skan			       unsigned HOST_WIDE_INT align)
1514590075Sobrien{
1514690075Sobrien  if (ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (x, mode))
1514790075Sobrien    toc_section ();
1514890075Sobrien  else
15149117395Skan    default_elf_select_rtx_section (mode, x, align);
1515090075Sobrien}
1515190075Sobrien
1515290075Sobrien/* A C statement or statements to switch to the appropriate
1515390075Sobrien   section for output of DECL.  DECL is either a `VAR_DECL' node
1515490075Sobrien   or a constant of some sort.  RELOC indicates whether forming
1515590075Sobrien   the initial value of DECL requires link-time relocations.  */
1515690075Sobrien
15157117395Skanstatic void
15158132718Skanrs6000_elf_select_section (tree decl, int reloc,
15159132718Skan			   unsigned HOST_WIDE_INT align)
1516090075Sobrien{
15161132718Skan  /* Pretend that we're always building for a shared library when
15162132718Skan     ABI_AIX, because otherwise we end up with dynamic relocations
15163132718Skan     in read-only sections.  This happens for function pointers,
15164132718Skan     references to vtables in typeinfo, and probably other cases.  */
15165117395Skan  default_elf_select_section_1 (decl, reloc, align,
15166117395Skan				flag_pic || DEFAULT_ABI == ABI_AIX);
1516790075Sobrien}
1516890075Sobrien
1516990075Sobrien/* A C statement to build up a unique section name, expressed as a
1517090075Sobrien   STRING_CST node, and assign it to DECL_SECTION_NAME (decl).
1517190075Sobrien   RELOC indicates whether the initial value of EXP requires
1517290075Sobrien   link-time relocations.  If you do not define this macro, GCC will use
1517390075Sobrien   the symbol name prefixed by `.' as the section name.  Note - this
1517490075Sobrien   macro can now be called for uninitialized data items as well as
15175117395Skan   initialized data and functions.  */
1517690075Sobrien
15177117395Skanstatic void
15178132718Skanrs6000_elf_unique_section (tree decl, int reloc)
1517990075Sobrien{
15180132718Skan  /* As above, pretend that we're always building for a shared library
15181132718Skan     when ABI_AIX, to avoid dynamic relocations in read-only sections.  */
15182117395Skan  default_unique_section_1 (decl, reloc,
15183117395Skan			    flag_pic || DEFAULT_ABI == ABI_AIX);
1518490075Sobrien}
15185117395Skan
15186132718Skan/* For a SYMBOL_REF, set generic flags and then perform some
15187132718Skan   target-specific processing.
1518890075Sobrien
15189132718Skan   When the AIX ABI is requested on a non-AIX system, replace the
15190132718Skan   function name with the real name (with a leading .) rather than the
15191132718Skan   function descriptor name.  This saves a lot of overriding code to
15192132718Skan   read the prefixes.  */
15193132718Skan
15194117395Skanstatic void
15195132718Skanrs6000_elf_encode_section_info (tree decl, rtx rtl, int first)
1519690075Sobrien{
15197132718Skan  default_encode_section_info (decl, rtl, first);
15198117395Skan
15199132718Skan  if (first
15200132718Skan      && TREE_CODE (decl) == FUNCTION_DECL
15201132718Skan      && !TARGET_AIX
15202132718Skan      && DEFAULT_ABI == ABI_AIX)
1520390075Sobrien    {
15204132718Skan      rtx sym_ref = XEXP (rtl, 0);
15205132718Skan      size_t len = strlen (XSTR (sym_ref, 0));
15206132718Skan      char *str = alloca (len + 2);
15207132718Skan      str[0] = '.';
15208132718Skan      memcpy (str + 1, XSTR (sym_ref, 0), len + 1);
15209132718Skan      XSTR (sym_ref, 0) = ggc_alloc_string (str, len + 1);
1521090075Sobrien    }
1521190075Sobrien}
1521290075Sobrien
15213117395Skanstatic bool
15214132718Skanrs6000_elf_in_small_data_p (tree decl)
15215117395Skan{
15216117395Skan  if (rs6000_sdata == SDATA_NONE)
15217117395Skan    return false;
15218117395Skan
15219146895Skan  /* We want to merge strings, so we never consider them small data.  */
15220146895Skan  if (TREE_CODE (decl) == STRING_CST)
15221146895Skan    return false;
15222146895Skan
15223146895Skan  /* Functions are never in the small data area.  */
15224146895Skan  if (TREE_CODE (decl) == FUNCTION_DECL)
15225146895Skan    return false;
15226146895Skan
15227146895Skan  /* Thread-local vars can't go in the small data area.  */
15228146895Skan  if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl))
15229146895Skan    return false;
15230146895Skan
15231117395Skan  if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl))
15232117395Skan    {
15233117395Skan      const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
15234117395Skan      if (strcmp (section, ".sdata") == 0
15235117395Skan	  || strcmp (section, ".sdata2") == 0
15236132718Skan	  || strcmp (section, ".sbss") == 0
15237132718Skan	  || strcmp (section, ".sbss2") == 0
15238132718Skan	  || strcmp (section, ".PPC.EMB.sdata0") == 0
15239132718Skan	  || strcmp (section, ".PPC.EMB.sbss0") == 0)
15240117395Skan	return true;
15241117395Skan    }
15242117395Skan  else
15243117395Skan    {
15244117395Skan      HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (decl));
15245117395Skan
15246117395Skan      if (size > 0
15247132718Skan	  && (unsigned HOST_WIDE_INT) size <= g_switch_value
15248132718Skan	  /* If it's not public, and we're not going to reference it there,
15249132718Skan	     there's no need to put it in the small data section.  */
15250117395Skan	  && (rs6000_sdata != SDATA_DATA || TREE_PUBLIC (decl)))
15251117395Skan	return true;
15252117395Skan    }
15253117395Skan
15254117395Skan  return false;
15255117395Skan}
15256117395Skan
1525790075Sobrien#endif /* USING_ELFOS_H */
1525890075Sobrien
1525990075Sobrien
1526090075Sobrien/* Return a REG that occurs in ADDR with coefficient 1.
1526190075Sobrien   ADDR can be effectively incremented by incrementing REG.
1526290075Sobrien
1526390075Sobrien   r0 is special and we must not select it as an address
1526490075Sobrien   register by this routine since our caller will try to
1526590075Sobrien   increment the returned register via an "la" instruction.  */
1526690075Sobrien
1526790075Sobrienstruct rtx_def *
15268132718Skanfind_addr_reg (rtx addr)
1526990075Sobrien{
1527090075Sobrien  while (GET_CODE (addr) == PLUS)
1527190075Sobrien    {
1527290075Sobrien      if (GET_CODE (XEXP (addr, 0)) == REG
1527390075Sobrien	  && REGNO (XEXP (addr, 0)) != 0)
1527490075Sobrien	addr = XEXP (addr, 0);
1527590075Sobrien      else if (GET_CODE (XEXP (addr, 1)) == REG
1527690075Sobrien	       && REGNO (XEXP (addr, 1)) != 0)
1527790075Sobrien	addr = XEXP (addr, 1);
1527890075Sobrien      else if (CONSTANT_P (XEXP (addr, 0)))
1527990075Sobrien	addr = XEXP (addr, 1);
1528090075Sobrien      else if (CONSTANT_P (XEXP (addr, 1)))
1528190075Sobrien	addr = XEXP (addr, 0);
1528290075Sobrien      else
1528390075Sobrien	abort ();
1528490075Sobrien    }
1528590075Sobrien  if (GET_CODE (addr) == REG && REGNO (addr) != 0)
1528690075Sobrien    return addr;
1528790075Sobrien  abort ();
1528890075Sobrien}
1528990075Sobrien
1529090075Sobrienvoid
15291132718Skanrs6000_fatal_bad_address (rtx op)
1529290075Sobrien{
1529390075Sobrien  fatal_insn ("bad address", op);
1529490075Sobrien}
1529590075Sobrien
1529690075Sobrien#if TARGET_MACHO
1529790075Sobrien
1529890075Sobrien#if 0
1529990075Sobrien/* Returns 1 if OP is either a symbol reference or a sum of a symbol
1530090075Sobrien   reference and a constant.  */
1530190075Sobrien
1530290075Sobrienint
15303132718Skansymbolic_operand (rtx op)
1530490075Sobrien{
1530590075Sobrien  switch (GET_CODE (op))
1530690075Sobrien    {
1530790075Sobrien    case SYMBOL_REF:
1530890075Sobrien    case LABEL_REF:
1530990075Sobrien      return 1;
1531090075Sobrien    case CONST:
1531190075Sobrien      op = XEXP (op, 0);
1531290075Sobrien      return (GET_CODE (op) == SYMBOL_REF ||
1531390075Sobrien	      (GET_CODE (XEXP (op, 0)) == SYMBOL_REF
1531490075Sobrien	       || GET_CODE (XEXP (op, 0)) == LABEL_REF)
1531590075Sobrien	      && GET_CODE (XEXP (op, 1)) == CONST_INT);
1531690075Sobrien    default:
1531790075Sobrien      return 0;
1531890075Sobrien    }
1531990075Sobrien}
1532090075Sobrien#endif
1532190075Sobrien
15322132718Skan#if TARGET_MACHO
1532390075Sobrien
15324132718Skanstatic tree branch_island_list = 0;
1532590075Sobrien
15326132718Skan/* Remember to generate a branch island for far calls to the given
15327132718Skan   function.  */
1532890075Sobrien
15329132718Skanstatic void
15330132718Skanadd_compiler_branch_island (tree label_name, tree function_name, int line_number)
1533190075Sobrien{
15332132718Skan  tree branch_island = build_tree_list (function_name, label_name);
15333132718Skan  TREE_TYPE (branch_island) = build_int_2 (line_number, 0);
15334132718Skan  TREE_CHAIN (branch_island) = branch_island_list;
15335132718Skan  branch_island_list = branch_island;
1533690075Sobrien}
1533790075Sobrien
15338132718Skan#define BRANCH_ISLAND_LABEL_NAME(BRANCH_ISLAND)     TREE_VALUE (BRANCH_ISLAND)
15339132718Skan#define BRANCH_ISLAND_FUNCTION_NAME(BRANCH_ISLAND)  TREE_PURPOSE (BRANCH_ISLAND)
15340132718Skan#define BRANCH_ISLAND_LINE_NUMBER(BRANCH_ISLAND)    \
15341132718Skan		TREE_INT_CST_LOW (TREE_TYPE (BRANCH_ISLAND))
1534290075Sobrien
15343132718Skan/* Generate far-jump branch islands for everything on the
15344132718Skan   branch_island_list.  Invoked immediately after the last instruction
15345132718Skan   of the epilogue has been emitted; the branch-islands must be
15346132718Skan   appended to, and contiguous with, the function body.  Mach-O stubs
15347132718Skan   are generated in machopic_output_stub().  */
1534890075Sobrien
15349132718Skanstatic void
15350132718Skanmacho_branch_islands (void)
1535190075Sobrien{
15352132718Skan  char tmp_buf[512];
15353132718Skan  tree branch_island;
1535490075Sobrien
15355132718Skan  for (branch_island = branch_island_list;
15356132718Skan       branch_island;
15357132718Skan       branch_island = TREE_CHAIN (branch_island))
15358132718Skan    {
15359132718Skan      const char *label =
15360132718Skan	IDENTIFIER_POINTER (BRANCH_ISLAND_LABEL_NAME (branch_island));
15361132718Skan      const char *name  =
15362132718Skan	darwin_strip_name_encoding (
15363132718Skan	  IDENTIFIER_POINTER (BRANCH_ISLAND_FUNCTION_NAME (branch_island)));
15364132718Skan      char name_buf[512];
15365132718Skan      /* Cheap copy of the details from the Darwin ASM_OUTPUT_LABELREF().  */
15366132718Skan      if (name[0] == '*' || name[0] == '&')
15367132718Skan	strcpy (name_buf, name+1);
15368132718Skan      else
15369132718Skan	{
15370132718Skan	  name_buf[0] = '_';
15371132718Skan	  strcpy (name_buf+1, name);
15372132718Skan	}
15373132718Skan      strcpy (tmp_buf, "\n");
15374132718Skan      strcat (tmp_buf, label);
1537590075Sobrien#if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO)
15376132718Skan      if (write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG)
15377132718Skan	fprintf (asm_out_file, "\t.stabd 68,0," HOST_WIDE_INT_PRINT_UNSIGNED "\n",
15378132718Skan		 BRANCH_ISLAND_LINE_NUMBER(branch_island));
1537990075Sobrien#endif /* DBX_DEBUGGING_INFO || XCOFF_DEBUGGING_INFO */
15380132718Skan      if (flag_pic)
15381132718Skan	{
15382132718Skan	  strcat (tmp_buf, ":\n\tmflr r0\n\tbcl 20,31,");
15383132718Skan	  strcat (tmp_buf, label);
15384132718Skan	  strcat (tmp_buf, "_pic\n");
15385132718Skan	  strcat (tmp_buf, label);
15386132718Skan	  strcat (tmp_buf, "_pic:\n\tmflr r11\n");
15387132718Skan
15388132718Skan	  strcat (tmp_buf, "\taddis r11,r11,ha16(");
15389132718Skan	  strcat (tmp_buf, name_buf);
15390132718Skan	  strcat (tmp_buf, " - ");
15391132718Skan	  strcat (tmp_buf, label);
15392132718Skan	  strcat (tmp_buf, "_pic)\n");
15393132718Skan
15394132718Skan	  strcat (tmp_buf, "\tmtlr r0\n");
15395132718Skan
15396132718Skan	  strcat (tmp_buf, "\taddi r12,r11,lo16(");
15397132718Skan	  strcat (tmp_buf, name_buf);
15398132718Skan	  strcat (tmp_buf, " - ");
15399132718Skan	  strcat (tmp_buf, label);
15400132718Skan	  strcat (tmp_buf, "_pic)\n");
15401132718Skan
15402132718Skan	  strcat (tmp_buf, "\tmtctr r12\n\tbctr\n");
15403132718Skan	}
15404132718Skan      else
15405132718Skan	{
15406132718Skan	  strcat (tmp_buf, ":\nlis r12,hi16(");
15407132718Skan	  strcat (tmp_buf, name_buf);
15408132718Skan	  strcat (tmp_buf, ")\n\tori r12,r12,lo16(");
15409132718Skan	  strcat (tmp_buf, name_buf);
15410132718Skan	  strcat (tmp_buf, ")\n\tmtctr r12\n\tbctr");
15411132718Skan	}
15412132718Skan      output_asm_insn (tmp_buf, 0);
1541390075Sobrien#if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO)
15414132718Skan      if (write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG)
15415132718Skan	fprintf(asm_out_file, "\t.stabd 68,0," HOST_WIDE_INT_PRINT_UNSIGNED "\n",
15416132718Skan		BRANCH_ISLAND_LINE_NUMBER (branch_island));
1541790075Sobrien#endif /* DBX_DEBUGGING_INFO || XCOFF_DEBUGGING_INFO */
15418132718Skan    }
1541990075Sobrien
15420132718Skan  branch_island_list = 0;
1542190075Sobrien}
1542290075Sobrien
1542390075Sobrien/* NO_PREVIOUS_DEF checks in the link list whether the function name is
1542490075Sobrien   already there or not.  */
1542590075Sobrien
15426132718Skanstatic int
15427132718Skanno_previous_def (tree function_name)
1542890075Sobrien{
15429132718Skan  tree branch_island;
15430132718Skan  for (branch_island = branch_island_list;
15431132718Skan       branch_island;
15432132718Skan       branch_island = TREE_CHAIN (branch_island))
15433132718Skan    if (function_name == BRANCH_ISLAND_FUNCTION_NAME (branch_island))
1543490075Sobrien      return 0;
1543590075Sobrien  return 1;
1543690075Sobrien}
1543790075Sobrien
1543890075Sobrien/* GET_PREV_LABEL gets the label name from the previous definition of
1543990075Sobrien   the function.  */
1544090075Sobrien
15441132718Skanstatic tree
15442132718Skanget_prev_label (tree function_name)
1544390075Sobrien{
15444132718Skan  tree branch_island;
15445132718Skan  for (branch_island = branch_island_list;
15446132718Skan       branch_island;
15447132718Skan       branch_island = TREE_CHAIN (branch_island))
15448132718Skan    if (function_name == BRANCH_ISLAND_FUNCTION_NAME (branch_island))
15449132718Skan      return BRANCH_ISLAND_LABEL_NAME (branch_island);
1545090075Sobrien  return 0;
1545190075Sobrien}
1545290075Sobrien
1545390075Sobrien/* INSN is either a function call or a millicode call.  It may have an
1545490075Sobrien   unconditional jump in its delay slot.
1545590075Sobrien
1545690075Sobrien   CALL_DEST is the routine we are calling.  */
1545790075Sobrien
1545890075Sobrienchar *
15459132718Skanoutput_call (rtx insn, rtx *operands, int dest_operand_number, int cookie_operand_number)
1546090075Sobrien{
1546190075Sobrien  static char buf[256];
15462132718Skan  if (GET_CODE (operands[dest_operand_number]) == SYMBOL_REF
15463132718Skan      && (INTVAL (operands[cookie_operand_number]) & CALL_LONG))
1546490075Sobrien    {
1546590075Sobrien      tree labelname;
15466132718Skan      tree funname = get_identifier (XSTR (operands[dest_operand_number], 0));
1546790075Sobrien
1546890075Sobrien      if (no_previous_def (funname))
1546990075Sobrien	{
15470117395Skan	  int line_number = 0;
1547190075Sobrien	  rtx label_rtx = gen_label_rtx ();
1547290075Sobrien	  char *label_buf, temp_buf[256];
1547390075Sobrien	  ASM_GENERATE_INTERNAL_LABEL (temp_buf, "L",
1547490075Sobrien				       CODE_LABEL_NUMBER (label_rtx));
1547590075Sobrien	  label_buf = temp_buf[0] == '*' ? temp_buf + 1 : temp_buf;
1547690075Sobrien	  labelname = get_identifier (label_buf);
1547790075Sobrien	  for (; insn && GET_CODE (insn) != NOTE; insn = PREV_INSN (insn));
1547890075Sobrien	  if (insn)
1547990075Sobrien	    line_number = NOTE_LINE_NUMBER (insn);
15480132718Skan	  add_compiler_branch_island (labelname, funname, line_number);
1548190075Sobrien	}
1548290075Sobrien      else
1548390075Sobrien	labelname = get_prev_label (funname);
1548490075Sobrien
15485132718Skan      /* "jbsr foo, L42" is Mach-O for "Link as 'bl foo' if a 'bl'
15486132718Skan	 instruction will reach 'foo', otherwise link as 'bl L42'".
15487132718Skan	 "L42" should be a 'branch island', that will do a far jump to
15488132718Skan	 'foo'.  Branch islands are generated in
15489132718Skan	 macho_branch_islands().  */
1549090075Sobrien      sprintf (buf, "jbsr %%z%d,%.246s",
15491132718Skan	       dest_operand_number, IDENTIFIER_POINTER (labelname));
1549290075Sobrien    }
1549390075Sobrien  else
15494132718Skan    sprintf (buf, "bl %%z%d", dest_operand_number);
15495132718Skan  return buf;
1549690075Sobrien}
1549790075Sobrien
15498132718Skan#endif /* TARGET_MACHO */
1549990075Sobrien
1550090075Sobrien/* Generate PIC and indirect symbol stubs.  */
1550190075Sobrien
1550290075Sobrienvoid
15503132718Skanmachopic_output_stub (FILE *file, const char *symb, const char *stub)
1550490075Sobrien{
1550590075Sobrien  unsigned int length;
1550690075Sobrien  char *symbol_name, *lazy_ptr_name;
1550790075Sobrien  char *local_label_0;
1550890075Sobrien  static int label = 0;
1550990075Sobrien
1551090075Sobrien  /* Lose our funky encoding stuff so it doesn't contaminate the stub.  */
15511117395Skan  symb = (*targetm.strip_name_encoding) (symb);
1551290075Sobrien
1551390075Sobrien
1551490075Sobrien  length = strlen (symb);
1551590075Sobrien  symbol_name = alloca (length + 32);
1551690075Sobrien  GEN_SYMBOL_NAME_FOR_SYMBOL (symbol_name, symb, length);
1551790075Sobrien
1551890075Sobrien  lazy_ptr_name = alloca (length + 32);
1551990075Sobrien  GEN_LAZY_PTR_NAME_FOR_SYMBOL (lazy_ptr_name, symb, length);
1552090075Sobrien
1552190075Sobrien  if (flag_pic == 2)
15522132718Skan    machopic_picsymbol_stub1_section ();
1552390075Sobrien  else
15524132718Skan    machopic_symbol_stub1_section ();
15525132718Skan  fprintf (file, "\t.align 2\n");
1552690075Sobrien
1552790075Sobrien  fprintf (file, "%s:\n", stub);
1552890075Sobrien  fprintf (file, "\t.indirect_symbol %s\n", symbol_name);
1552990075Sobrien
1553090075Sobrien  if (flag_pic == 2)
1553190075Sobrien    {
15532132718Skan      label++;
15533132718Skan      local_label_0 = alloca (sizeof("\"L0000000000$spb\""));
15534132718Skan      sprintf (local_label_0, "\"L%011d$spb\"", label);
15535132718Skan
1553690075Sobrien      fprintf (file, "\tmflr r0\n");
1553790075Sobrien      fprintf (file, "\tbcl 20,31,%s\n", local_label_0);
1553890075Sobrien      fprintf (file, "%s:\n\tmflr r11\n", local_label_0);
1553990075Sobrien      fprintf (file, "\taddis r11,r11,ha16(%s-%s)\n",
1554090075Sobrien	       lazy_ptr_name, local_label_0);
1554190075Sobrien      fprintf (file, "\tmtlr r0\n");
15542132718Skan      fprintf (file, "\tlwzu r12,lo16(%s-%s)(r11)\n",
1554390075Sobrien	       lazy_ptr_name, local_label_0);
1554490075Sobrien      fprintf (file, "\tmtctr r12\n");
1554590075Sobrien      fprintf (file, "\tbctr\n");
1554690075Sobrien    }
1554790075Sobrien  else
15548132718Skan   {
15549132718Skan     fprintf (file, "\tlis r11,ha16(%s)\n", lazy_ptr_name);
15550132718Skan     fprintf (file, "\tlwzu r12,lo16(%s)(r11)\n", lazy_ptr_name);
15551132718Skan     fprintf (file, "\tmtctr r12\n");
15552132718Skan     fprintf (file, "\tbctr\n");
15553132718Skan   }
1555490075Sobrien
1555590075Sobrien  machopic_lazy_symbol_ptr_section ();
1555690075Sobrien  fprintf (file, "%s:\n", lazy_ptr_name);
1555790075Sobrien  fprintf (file, "\t.indirect_symbol %s\n", symbol_name);
1555890075Sobrien  fprintf (file, "\t.long dyld_stub_binding_helper\n");
1555990075Sobrien}
1556090075Sobrien
1556190075Sobrien/* Legitimize PIC addresses.  If the address is already
1556290075Sobrien   position-independent, we return ORIG.  Newly generated
1556390075Sobrien   position-independent addresses go into a reg.  This is REG if non
1556490075Sobrien   zero, otherwise we allocate register(s) as necessary.  */
1556590075Sobrien
1556690075Sobrien#define SMALL_INT(X) ((unsigned) (INTVAL(X) + 0x8000) < 0x10000)
1556790075Sobrien
1556890075Sobrienrtx
15569132718Skanrs6000_machopic_legitimize_pic_address (rtx orig, enum machine_mode mode,
15570132718Skan					rtx reg)
1557190075Sobrien{
1557290075Sobrien  rtx base, offset;
1557390075Sobrien
1557490075Sobrien  if (reg == NULL && ! reload_in_progress && ! reload_completed)
1557590075Sobrien    reg = gen_reg_rtx (Pmode);
1557690075Sobrien
1557790075Sobrien  if (GET_CODE (orig) == CONST)
1557890075Sobrien    {
1557990075Sobrien      if (GET_CODE (XEXP (orig, 0)) == PLUS
1558090075Sobrien	  && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx)
1558190075Sobrien	return orig;
1558290075Sobrien
1558390075Sobrien      if (GET_CODE (XEXP (orig, 0)) == PLUS)
1558490075Sobrien	{
15585132718Skan	  /* Use a different reg for the intermediate value, as
15586132718Skan	     it will be marked UNCHANGING.  */
15587132718Skan	  rtx reg_temp = no_new_pseudos ? reg : gen_reg_rtx (Pmode);
15588132718Skan
1558990075Sobrien	  base =
1559090075Sobrien	    rs6000_machopic_legitimize_pic_address (XEXP (XEXP (orig, 0), 0),
15591132718Skan						    Pmode, reg_temp);
1559290075Sobrien	  offset =
1559390075Sobrien	    rs6000_machopic_legitimize_pic_address (XEXP (XEXP (orig, 0), 1),
1559490075Sobrien						    Pmode, reg);
1559590075Sobrien	}
1559690075Sobrien      else
1559790075Sobrien	abort ();
1559890075Sobrien
1559990075Sobrien      if (GET_CODE (offset) == CONST_INT)
1560090075Sobrien	{
1560190075Sobrien	  if (SMALL_INT (offset))
1560290075Sobrien	    return plus_constant (base, INTVAL (offset));
1560390075Sobrien	  else if (! reload_in_progress && ! reload_completed)
1560490075Sobrien	    offset = force_reg (Pmode, offset);
1560590075Sobrien	  else
1560690075Sobrien	    {
1560790075Sobrien 	      rtx mem = force_const_mem (Pmode, orig);
1560890075Sobrien	      return machopic_legitimize_pic_address (mem, Pmode, reg);
1560990075Sobrien	    }
1561090075Sobrien	}
1561190075Sobrien      return gen_rtx (PLUS, Pmode, base, offset);
1561290075Sobrien    }
1561390075Sobrien
1561490075Sobrien  /* Fall back on generic machopic code.  */
1561590075Sobrien  return machopic_legitimize_pic_address (orig, mode, reg);
1561690075Sobrien}
1561790075Sobrien
1561890075Sobrien/* This is just a placeholder to make linking work without having to
1561990075Sobrien   add this to the generic Darwin EXTRA_SECTIONS.  If -mcall-aix is
1562090075Sobrien   ever needed for Darwin (not too likely!) this would have to get a
1562190075Sobrien   real definition.  */
1562290075Sobrien
1562390075Sobrienvoid
15624132718Skantoc_section (void)
1562590075Sobrien{
1562690075Sobrien}
1562790075Sobrien
1562890075Sobrien#endif /* TARGET_MACHO */
1562990075Sobrien
1563090075Sobrien#if TARGET_ELF
1563190075Sobrienstatic unsigned int
15632132718Skanrs6000_elf_section_type_flags (tree decl, const char *name, int reloc)
1563390075Sobrien{
15634132718Skan  return default_section_type_flags_1 (decl, name, reloc,
15635132718Skan				       flag_pic || DEFAULT_ABI == ABI_AIX);
1563690075Sobrien}
1563790075Sobrien
1563890075Sobrien/* Record an element in the table of global constructors.  SYMBOL is
1563990075Sobrien   a SYMBOL_REF of the function to be called; PRIORITY is a number
1564090075Sobrien   between 0 and MAX_INIT_PRIORITY.
1564190075Sobrien
1564290075Sobrien   This differs from default_named_section_asm_out_constructor in
1564390075Sobrien   that we have special handling for -mrelocatable.  */
1564490075Sobrien
1564590075Sobrienstatic void
15646132718Skanrs6000_elf_asm_out_constructor (rtx symbol, int priority)
1564790075Sobrien{
1564890075Sobrien  const char *section = ".ctors";
1564990075Sobrien  char buf[16];
1565090075Sobrien
1565190075Sobrien  if (priority != DEFAULT_INIT_PRIORITY)
1565290075Sobrien    {
1565390075Sobrien      sprintf (buf, ".ctors.%.5u",
1565490075Sobrien               /* Invert the numbering so the linker puts us in the proper
1565590075Sobrien                  order; constructors are run from right to left, and the
1565690075Sobrien                  linker sorts in increasing order.  */
1565790075Sobrien               MAX_INIT_PRIORITY - priority);
1565890075Sobrien      section = buf;
1565990075Sobrien    }
1566090075Sobrien
1566190075Sobrien  named_section_flags (section, SECTION_WRITE);
1566290075Sobrien  assemble_align (POINTER_SIZE);
1566390075Sobrien
1566490075Sobrien  if (TARGET_RELOCATABLE)
1566590075Sobrien    {
1566690075Sobrien      fputs ("\t.long (", asm_out_file);
1566790075Sobrien      output_addr_const (asm_out_file, symbol);
1566890075Sobrien      fputs (")@fixup\n", asm_out_file);
1566990075Sobrien    }
1567090075Sobrien  else
1567190075Sobrien    assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
1567290075Sobrien}
1567390075Sobrien
1567490075Sobrienstatic void
15675132718Skanrs6000_elf_asm_out_destructor (rtx symbol, int priority)
1567690075Sobrien{
1567790075Sobrien  const char *section = ".dtors";
1567890075Sobrien  char buf[16];
1567990075Sobrien
1568090075Sobrien  if (priority != DEFAULT_INIT_PRIORITY)
1568190075Sobrien    {
1568290075Sobrien      sprintf (buf, ".dtors.%.5u",
1568390075Sobrien               /* Invert the numbering so the linker puts us in the proper
1568490075Sobrien                  order; constructors are run from right to left, and the
1568590075Sobrien                  linker sorts in increasing order.  */
1568690075Sobrien               MAX_INIT_PRIORITY - priority);
1568790075Sobrien      section = buf;
1568890075Sobrien    }
1568990075Sobrien
1569090075Sobrien  named_section_flags (section, SECTION_WRITE);
1569190075Sobrien  assemble_align (POINTER_SIZE);
1569290075Sobrien
1569390075Sobrien  if (TARGET_RELOCATABLE)
1569490075Sobrien    {
1569590075Sobrien      fputs ("\t.long (", asm_out_file);
1569690075Sobrien      output_addr_const (asm_out_file, symbol);
1569790075Sobrien      fputs (")@fixup\n", asm_out_file);
1569890075Sobrien    }
1569990075Sobrien  else
1570090075Sobrien    assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
1570190075Sobrien}
15702132718Skan
15703132718Skanvoid
15704132718Skanrs6000_elf_declare_function_name (FILE *file, const char *name, tree decl)
15705132718Skan{
15706132718Skan  if (TARGET_64BIT)
15707132718Skan    {
15708132718Skan      fputs ("\t.section\t\".opd\",\"aw\"\n\t.align 3\n", file);
15709132718Skan      ASM_OUTPUT_LABEL (file, name);
15710132718Skan      fputs (DOUBLE_INT_ASM_OP, file);
15711132718Skan      putc ('.', file);
15712132718Skan      assemble_name (file, name);
15713132718Skan      fputs (",.TOC.@tocbase,0\n\t.previous\n\t.size\t", file);
15714132718Skan      assemble_name (file, name);
15715132718Skan      fputs (",24\n\t.type\t.", file);
15716132718Skan      assemble_name (file, name);
15717132718Skan      fputs (",@function\n", file);
15718132718Skan      if (TREE_PUBLIC (decl) && ! DECL_WEAK (decl))
15719132718Skan	{
15720132718Skan	  fputs ("\t.globl\t.", file);
15721132718Skan	  assemble_name (file, name);
15722132718Skan	  putc ('\n', file);
15723132718Skan	}
15724132718Skan      ASM_DECLARE_RESULT (file, DECL_RESULT (decl));
15725132718Skan      putc ('.', file);
15726132718Skan      ASM_OUTPUT_LABEL (file, name);
15727132718Skan      return;
15728132718Skan    }
15729132718Skan
15730132718Skan  if (TARGET_RELOCATABLE
15731132718Skan      && (get_pool_size () != 0 || current_function_profile)
15732132718Skan      && uses_TOC ())
15733132718Skan    {
15734132718Skan      char buf[256];
15735132718Skan
15736132718Skan      (*targetm.asm_out.internal_label) (file, "LCL", rs6000_pic_labelno);
15737132718Skan
15738132718Skan      ASM_GENERATE_INTERNAL_LABEL (buf, "LCTOC", 1);
15739132718Skan      fprintf (file, "\t.long ");
15740132718Skan      assemble_name (file, buf);
15741132718Skan      putc ('-', file);
15742132718Skan      ASM_GENERATE_INTERNAL_LABEL (buf, "LCF", rs6000_pic_labelno);
15743132718Skan      assemble_name (file, buf);
15744132718Skan      putc ('\n', file);
15745132718Skan    }
15746132718Skan
15747132718Skan  ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function");
15748132718Skan  ASM_DECLARE_RESULT (file, DECL_RESULT (decl));
15749132718Skan
15750132718Skan  if (DEFAULT_ABI == ABI_AIX)
15751132718Skan    {
15752132718Skan      const char *desc_name, *orig_name;
15753132718Skan
15754132718Skan      orig_name = (*targetm.strip_name_encoding) (name);
15755132718Skan      desc_name = orig_name;
15756132718Skan      while (*desc_name == '.')
15757132718Skan	desc_name++;
15758132718Skan
15759132718Skan      if (TREE_PUBLIC (decl))
15760132718Skan	fprintf (file, "\t.globl %s\n", desc_name);
15761132718Skan
15762132718Skan      fprintf (file, "%s\n", MINIMAL_TOC_SECTION_ASM_OP);
15763132718Skan      fprintf (file, "%s:\n", desc_name);
15764132718Skan      fprintf (file, "\t.long %s\n", orig_name);
15765132718Skan      fputs ("\t.long _GLOBAL_OFFSET_TABLE_\n", file);
15766132718Skan      if (DEFAULT_ABI == ABI_AIX)
15767132718Skan	fputs ("\t.long 0\n", file);
15768132718Skan      fprintf (file, "\t.previous\n");
15769132718Skan    }
15770132718Skan  ASM_OUTPUT_LABEL (file, name);
15771132718Skan}
15772146895Skan
15773146895Skanstatic void
15774146895Skanrs6000_elf_end_indicate_exec_stack (void)
15775146895Skan{
15776146895Skan  if (TARGET_32BIT)
15777146895Skan    file_end_indicate_exec_stack ();
15778146895Skan}
1577990075Sobrien#endif
1578090075Sobrien
15781117395Skan#if TARGET_XCOFF
1578290075Sobrienstatic void
15783132718Skanrs6000_xcoff_asm_globalize_label (FILE *stream, const char *name)
1578490075Sobrien{
15785117395Skan  fputs (GLOBAL_ASM_OP, stream);
15786117395Skan  RS6000_OUTPUT_BASENAME (stream, name);
15787117395Skan  putc ('\n', stream);
1578890075Sobrien}
15789117395Skan
15790117395Skanstatic void
15791132718Skanrs6000_xcoff_asm_named_section (const char *name, unsigned int flags)
15792117395Skan{
15793117395Skan  int smclass;
15794117395Skan  static const char * const suffix[3] = { "PR", "RO", "RW" };
15795117395Skan
15796117395Skan  if (flags & SECTION_CODE)
15797117395Skan    smclass = 0;
15798117395Skan  else if (flags & SECTION_WRITE)
15799117395Skan    smclass = 2;
15800117395Skan  else
15801117395Skan    smclass = 1;
15802117395Skan
15803117395Skan  fprintf (asm_out_file, "\t.csect %s%s[%s],%u\n",
15804117395Skan	   (flags & SECTION_CODE) ? "." : "",
15805117395Skan	   name, suffix[smclass], flags & SECTION_ENTSIZE);
15806117395Skan}
15807117395Skan
15808117395Skanstatic void
15809132718Skanrs6000_xcoff_select_section (tree decl, int reloc,
15810132718Skan			    unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
15811117395Skan{
15812117395Skan  if (decl_readonly_section_1 (decl, reloc, 1))
15813117395Skan    {
15814117395Skan      if (TREE_PUBLIC (decl))
15815117395Skan        read_only_data_section ();
15816117395Skan      else
15817117395Skan        read_only_private_data_section ();
15818117395Skan    }
15819117395Skan  else
15820117395Skan    {
15821117395Skan      if (TREE_PUBLIC (decl))
15822117395Skan        data_section ();
15823117395Skan      else
15824117395Skan        private_data_section ();
15825117395Skan    }
15826117395Skan}
15827117395Skan
15828117395Skanstatic void
15829132718Skanrs6000_xcoff_unique_section (tree decl, int reloc ATTRIBUTE_UNUSED)
15830117395Skan{
15831117395Skan  const char *name;
15832117395Skan
15833117395Skan  /* Use select_section for private and uninitialized data.  */
15834117395Skan  if (!TREE_PUBLIC (decl)
15835117395Skan      || DECL_COMMON (decl)
15836117395Skan      || DECL_INITIAL (decl) == NULL_TREE
15837117395Skan      || DECL_INITIAL (decl) == error_mark_node
15838117395Skan      || (flag_zero_initialized_in_bss
15839117395Skan	  && initializer_zerop (DECL_INITIAL (decl))))
15840117395Skan    return;
15841117395Skan
15842117395Skan  name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
15843117395Skan  name = (*targetm.strip_name_encoding) (name);
15844117395Skan  DECL_SECTION_NAME (decl) = build_string (strlen (name), name);
15845117395Skan}
15846117395Skan
15847117395Skan/* Select section for constant in constant pool.
15848117395Skan
15849117395Skan   On RS/6000, all constants are in the private read-only data area.
15850117395Skan   However, if this is being placed in the TOC it must be output as a
15851117395Skan   toc entry.  */
15852117395Skan
15853117395Skanstatic void
15854132718Skanrs6000_xcoff_select_rtx_section (enum machine_mode mode, rtx x,
15855132718Skan				unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
15856117395Skan{
15857117395Skan  if (ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (x, mode))
15858117395Skan    toc_section ();
15859117395Skan  else
15860117395Skan    read_only_private_data_section ();
15861117395Skan}
15862117395Skan
15863117395Skan/* Remove any trailing [DS] or the like from the symbol name.  */
15864117395Skan
15865117395Skanstatic const char *
15866132718Skanrs6000_xcoff_strip_name_encoding (const char *name)
15867117395Skan{
15868117395Skan  size_t len;
15869117395Skan  if (*name == '*')
15870117395Skan    name++;
15871117395Skan  len = strlen (name);
15872117395Skan  if (name[len - 1] == ']')
15873117395Skan    return ggc_alloc_string (name, len - 4);
15874117395Skan  else
15875117395Skan    return name;
15876117395Skan}
15877117395Skan
15878117395Skan/* Section attributes.  AIX is always PIC.  */
15879117395Skan
15880117395Skanstatic unsigned int
15881132718Skanrs6000_xcoff_section_type_flags (tree decl, const char *name, int reloc)
15882117395Skan{
15883117395Skan  unsigned int align;
15884117395Skan  unsigned int flags = default_section_type_flags_1 (decl, name, reloc, 1);
15885117395Skan
15886117395Skan  /* Align to at least UNIT size.  */
15887117395Skan  if (flags & SECTION_CODE)
15888117395Skan    align = MIN_UNITS_PER_WORD;
15889117395Skan  else
15890117395Skan    /* Increase alignment of large objects if not already stricter.  */
15891117395Skan    align = MAX ((DECL_ALIGN (decl) / BITS_PER_UNIT),
15892117395Skan		 int_size_in_bytes (TREE_TYPE (decl)) > MIN_UNITS_PER_WORD
15893117395Skan		 ? UNITS_PER_FP_WORD : MIN_UNITS_PER_WORD);
15894117395Skan
15895117395Skan  return flags | (exact_log2 (align) & SECTION_ENTSIZE);
15896117395Skan}
15897117395Skan
15898132718Skan/* Output at beginning of assembler file.
15899117395Skan
15900132718Skan   Initialize the section names for the RS/6000 at this point.
15901117395Skan
15902132718Skan   Specify filename, including full path, to assembler.
15903132718Skan
15904132718Skan   We want to go into the TOC section so at least one .toc will be emitted.
15905132718Skan   Also, in order to output proper .bs/.es pairs, we need at least one static
15906132718Skan   [RW] section emitted.
15907132718Skan
15908132718Skan   Finally, declare mcount when profiling to make the assembler happy.  */
15909132718Skan
15910117395Skanstatic void
15911132718Skanrs6000_xcoff_file_start (void)
15912117395Skan{
15913132718Skan  rs6000_gen_section_name (&xcoff_bss_section_name,
15914132718Skan			   main_input_filename, ".bss_");
15915132718Skan  rs6000_gen_section_name (&xcoff_private_data_section_name,
15916132718Skan			   main_input_filename, ".rw_");
15917132718Skan  rs6000_gen_section_name (&xcoff_read_only_section_name,
15918132718Skan			   main_input_filename, ".ro_");
15919132718Skan
15920132718Skan  fputs ("\t.file\t", asm_out_file);
15921132718Skan  output_quoted_string (asm_out_file, main_input_filename);
15922132718Skan  fputc ('\n', asm_out_file);
15923132718Skan  toc_section ();
15924132718Skan  if (write_symbols != NO_DEBUG)
15925132718Skan    private_data_section ();
15926132718Skan  text_section ();
15927132718Skan  if (profile_flag)
15928132718Skan    fprintf (asm_out_file, "\t.extern %s\n", RS6000_MCOUNT);
15929132718Skan  rs6000_file_start ();
15930117395Skan}
15931117395Skan
15932132718Skan/* Output at end of assembler file.
15933132718Skan   On the RS/6000, referencing data should automatically pull in text.  */
15934117395Skan
15935132718Skanstatic void
15936132718Skanrs6000_xcoff_file_end (void)
15937132718Skan{
15938132718Skan  text_section ();
15939132718Skan  fputs ("_section_.text:\n", asm_out_file);
15940132718Skan  data_section ();
15941132718Skan  fputs (TARGET_32BIT
15942132718Skan	 ? "\t.long _section_.text\n" : "\t.llong _section_.text\n",
15943132718Skan	 asm_out_file);
15944132718Skan}
15945132718Skan#endif /* TARGET_XCOFF */
15946132718Skan
15947132718Skan#if TARGET_MACHO
15948132718Skan/* Cross-module name binding.  Darwin does not support overriding
15949132718Skan   functions at dynamic-link time.  */
15950132718Skan
15951117395Skanstatic bool
15952132718Skanrs6000_binds_local_p (tree decl)
15953117395Skan{
15954132718Skan  return default_binds_local_p_1 (decl, 0);
15955117395Skan}
15956132718Skan#endif
15957117395Skan
15958132718Skan/* Compute a (partial) cost for rtx X.  Return true if the complete
15959132718Skan   cost has been computed, and false if subexpressions should be
15960132718Skan   scanned.  In either case, *TOTAL contains the cost result.  */
15961132718Skan
15962132718Skanstatic bool
15963132718Skanrs6000_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED,
15964132718Skan		  int *total)
15965132718Skan{
15966132718Skan  switch (code)
15967132718Skan    {
15968132718Skan      /* On the RS/6000, if it is valid in the insn, it is free.
15969132718Skan	 So this always returns 0.  */
15970132718Skan    case CONST_INT:
15971132718Skan    case CONST:
15972132718Skan    case LABEL_REF:
15973132718Skan    case SYMBOL_REF:
15974132718Skan    case CONST_DOUBLE:
15975132718Skan    case HIGH:
15976132718Skan      *total = 0;
15977132718Skan      return true;
15978132718Skan
15979132718Skan    case PLUS:
15980132718Skan      *total = ((GET_CODE (XEXP (x, 1)) == CONST_INT
15981132718Skan		 && ((unsigned HOST_WIDE_INT) (INTVAL (XEXP (x, 1))
15982132718Skan					       + 0x8000) >= 0x10000)
15983132718Skan		 && ((INTVAL (XEXP (x, 1)) & 0xffff) != 0))
15984132718Skan		? COSTS_N_INSNS (2)
15985132718Skan		: COSTS_N_INSNS (1));
15986132718Skan      return true;
15987132718Skan
15988132718Skan    case AND:
15989132718Skan    case IOR:
15990132718Skan    case XOR:
15991132718Skan      *total = ((GET_CODE (XEXP (x, 1)) == CONST_INT
15992132718Skan		 && (INTVAL (XEXP (x, 1)) & (~ (HOST_WIDE_INT) 0xffff)) != 0
15993132718Skan		 && ((INTVAL (XEXP (x, 1)) & 0xffff) != 0))
15994132718Skan		? COSTS_N_INSNS (2)
15995132718Skan		: COSTS_N_INSNS (1));
15996132718Skan      return true;
15997132718Skan
15998132718Skan    case MULT:
15999132718Skan      if (optimize_size)
16000132718Skan	{
16001132718Skan	  *total = COSTS_N_INSNS (2);
16002132718Skan	  return true;
16003132718Skan	}
16004132718Skan      switch (rs6000_cpu)
16005132718Skan	{
16006132718Skan	case PROCESSOR_RIOS1:
16007132718Skan	case PROCESSOR_PPC405:
16008132718Skan	  *total = (GET_CODE (XEXP (x, 1)) != CONST_INT
16009132718Skan		    ? COSTS_N_INSNS (5)
16010132718Skan		    : (INTVAL (XEXP (x, 1)) >= -256
16011132718Skan		       && INTVAL (XEXP (x, 1)) <= 255)
16012132718Skan		    ? COSTS_N_INSNS (3) : COSTS_N_INSNS (4));
16013132718Skan	  return true;
16014132718Skan
16015132718Skan	case PROCESSOR_PPC440:
16016132718Skan	  *total = (GET_CODE (XEXP (x, 1)) != CONST_INT
16017132718Skan		    ? COSTS_N_INSNS (3)
16018132718Skan		    : COSTS_N_INSNS (2));
16019132718Skan	  return true;
16020132718Skan
16021132718Skan	case PROCESSOR_RS64A:
16022132718Skan	  *total = (GET_CODE (XEXP (x, 1)) != CONST_INT
16023132718Skan		    ? GET_MODE (XEXP (x, 1)) != DImode
16024132718Skan		    ? COSTS_N_INSNS (20) : COSTS_N_INSNS (34)
16025132718Skan		    : (INTVAL (XEXP (x, 1)) >= -256
16026132718Skan		       && INTVAL (XEXP (x, 1)) <= 255)
16027132718Skan		    ? COSTS_N_INSNS (8) : COSTS_N_INSNS (12));
16028132718Skan	  return true;
16029132718Skan
16030132718Skan	case PROCESSOR_RIOS2:
16031132718Skan	case PROCESSOR_MPCCORE:
16032132718Skan	case PROCESSOR_PPC604e:
16033132718Skan	  *total = COSTS_N_INSNS (2);
16034132718Skan	  return true;
16035132718Skan
16036132718Skan	case PROCESSOR_PPC601:
16037132718Skan	  *total = COSTS_N_INSNS (5);
16038132718Skan	  return true;
16039132718Skan
16040132718Skan	case PROCESSOR_PPC603:
16041132718Skan	case PROCESSOR_PPC7400:
16042132718Skan	case PROCESSOR_PPC750:
16043132718Skan	  *total = (GET_CODE (XEXP (x, 1)) != CONST_INT
16044132718Skan		    ? COSTS_N_INSNS (5)
16045132718Skan		    : (INTVAL (XEXP (x, 1)) >= -256
16046132718Skan		       && INTVAL (XEXP (x, 1)) <= 255)
16047132718Skan		    ? COSTS_N_INSNS (2) : COSTS_N_INSNS (3));
16048132718Skan	  return true;
16049132718Skan
16050132718Skan	case PROCESSOR_PPC7450:
16051132718Skan	  *total = (GET_CODE (XEXP (x, 1)) != CONST_INT
16052132718Skan		    ? COSTS_N_INSNS (4)
16053132718Skan		    : COSTS_N_INSNS (3));
16054132718Skan	  return true;
16055132718Skan
16056132718Skan	case PROCESSOR_PPC403:
16057132718Skan	case PROCESSOR_PPC604:
16058132718Skan	case PROCESSOR_PPC8540:
16059132718Skan	  *total = COSTS_N_INSNS (4);
16060132718Skan	  return true;
16061132718Skan
16062132718Skan	case PROCESSOR_PPC620:
16063132718Skan	case PROCESSOR_PPC630:
16064132718Skan	  *total = (GET_CODE (XEXP (x, 1)) != CONST_INT
16065132718Skan		    ? GET_MODE (XEXP (x, 1)) != DImode
16066132718Skan		    ? COSTS_N_INSNS (5) : COSTS_N_INSNS (7)
16067132718Skan		    : (INTVAL (XEXP (x, 1)) >= -256
16068132718Skan		       && INTVAL (XEXP (x, 1)) <= 255)
16069132718Skan		    ? COSTS_N_INSNS (3) : COSTS_N_INSNS (4));
16070132718Skan	  return true;
16071132718Skan
16072132718Skan	case PROCESSOR_POWER4:
16073132718Skan	case PROCESSOR_POWER5:
16074132718Skan	  *total = (GET_CODE (XEXP (x, 1)) != CONST_INT
16075132718Skan		    ? GET_MODE (XEXP (x, 1)) != DImode
16076132718Skan		    ? COSTS_N_INSNS (3) : COSTS_N_INSNS (4)
16077132718Skan		    : COSTS_N_INSNS (2));
16078132718Skan	  return true;
16079132718Skan
16080132718Skan	default:
16081132718Skan	  abort ();
16082132718Skan	}
16083132718Skan
16084132718Skan    case DIV:
16085132718Skan    case MOD:
16086132718Skan      if (GET_CODE (XEXP (x, 1)) == CONST_INT
16087132718Skan	  && exact_log2 (INTVAL (XEXP (x, 1))) >= 0)
16088132718Skan	{
16089132718Skan	  *total = COSTS_N_INSNS (2);
16090132718Skan	  return true;
16091132718Skan	}
16092132718Skan      /* FALLTHRU */
16093132718Skan
16094132718Skan    case UDIV:
16095132718Skan    case UMOD:
16096132718Skan      switch (rs6000_cpu)
16097132718Skan	{
16098132718Skan	case PROCESSOR_RIOS1:
16099132718Skan	  *total = COSTS_N_INSNS (19);
16100132718Skan	  return true;
16101132718Skan
16102132718Skan	case PROCESSOR_RIOS2:
16103132718Skan	  *total = COSTS_N_INSNS (13);
16104132718Skan	  return true;
16105132718Skan
16106132718Skan	case PROCESSOR_RS64A:
16107132718Skan	  *total = (GET_MODE (XEXP (x, 1)) != DImode
16108132718Skan		    ? COSTS_N_INSNS (65)
16109132718Skan		    : COSTS_N_INSNS (67));
16110132718Skan	  return true;
16111132718Skan
16112132718Skan	case PROCESSOR_MPCCORE:
16113132718Skan	  *total = COSTS_N_INSNS (6);
16114132718Skan	  return true;
16115132718Skan
16116132718Skan	case PROCESSOR_PPC403:
16117132718Skan	  *total = COSTS_N_INSNS (33);
16118132718Skan	  return true;
16119132718Skan
16120132718Skan	case PROCESSOR_PPC405:
16121132718Skan	  *total = COSTS_N_INSNS (35);
16122132718Skan	  return true;
16123132718Skan
16124132718Skan	case PROCESSOR_PPC440:
16125132718Skan	  *total = COSTS_N_INSNS (34);
16126132718Skan	  return true;
16127132718Skan
16128132718Skan	case PROCESSOR_PPC601:
16129132718Skan	  *total = COSTS_N_INSNS (36);
16130132718Skan	  return true;
16131132718Skan
16132132718Skan	case PROCESSOR_PPC603:
16133132718Skan	  *total = COSTS_N_INSNS (37);
16134132718Skan	  return true;
16135132718Skan
16136132718Skan	case PROCESSOR_PPC604:
16137132718Skan	case PROCESSOR_PPC604e:
16138132718Skan	  *total = COSTS_N_INSNS (20);
16139132718Skan	  return true;
16140132718Skan
16141132718Skan	case PROCESSOR_PPC620:
16142132718Skan	case PROCESSOR_PPC630:
16143132718Skan	  *total = (GET_MODE (XEXP (x, 1)) != DImode
16144132718Skan		    ? COSTS_N_INSNS (21)
16145132718Skan		    : COSTS_N_INSNS (37));
16146132718Skan	  return true;
16147132718Skan
16148132718Skan	case PROCESSOR_PPC750:
16149132718Skan	case PROCESSOR_PPC8540:
16150132718Skan	case PROCESSOR_PPC7400:
16151132718Skan	  *total = COSTS_N_INSNS (19);
16152132718Skan	  return true;
16153132718Skan
16154132718Skan	case PROCESSOR_PPC7450:
16155132718Skan	  *total = COSTS_N_INSNS (23);
16156132718Skan	  return true;
16157132718Skan
16158132718Skan	case PROCESSOR_POWER4:
16159132718Skan	case PROCESSOR_POWER5:
16160132718Skan	  *total = (GET_MODE (XEXP (x, 1)) != DImode
16161132718Skan		    ? COSTS_N_INSNS (18)
16162132718Skan		    : COSTS_N_INSNS (34));
16163132718Skan	  return true;
16164132718Skan
16165132718Skan	default:
16166132718Skan	  abort ();
16167132718Skan	}
16168132718Skan
16169132718Skan    case FFS:
16170132718Skan      *total = COSTS_N_INSNS (4);
16171132718Skan      return true;
16172132718Skan
16173132718Skan    case MEM:
16174132718Skan      /* MEM should be slightly more expensive than (plus (reg) (const)).  */
16175132718Skan      *total = 5;
16176132718Skan      return true;
16177132718Skan
16178132718Skan    default:
16179132718Skan      return false;
16180132718Skan    }
16181132718Skan}
16182132718Skan
16183117395Skan/* A C expression returning the cost of moving data from a register of class
16184117395Skan   CLASS1 to one of CLASS2.  */
16185117395Skan
16186117395Skanint
16187132718Skanrs6000_register_move_cost (enum machine_mode mode,
16188132718Skan			   enum reg_class from, enum reg_class to)
16189117395Skan{
16190117395Skan  /*  Moves from/to GENERAL_REGS.  */
16191117395Skan  if (reg_classes_intersect_p (to, GENERAL_REGS)
16192117395Skan      || reg_classes_intersect_p (from, GENERAL_REGS))
16193117395Skan    {
16194117395Skan      if (! reg_classes_intersect_p (to, GENERAL_REGS))
16195117395Skan	from = to;
16196117395Skan
16197117395Skan      if (from == FLOAT_REGS || from == ALTIVEC_REGS)
16198117395Skan	return (rs6000_memory_move_cost (mode, from, 0)
16199117395Skan		+ rs6000_memory_move_cost (mode, GENERAL_REGS, 0));
16200117395Skan
16201132718Skan/* It's more expensive to move CR_REGS than CR0_REGS because of the shift....  */
16202117395Skan      else if (from == CR_REGS)
16203117395Skan	return 4;
16204117395Skan
16205117395Skan      else
16206117395Skan/* A move will cost one instruction per GPR moved.  */
16207117395Skan	return 2 * HARD_REGNO_NREGS (0, mode);
16208117395Skan    }
16209117395Skan
16210117395Skan/* Moving between two similar registers is just one instruction.  */
16211117395Skan  else if (reg_classes_intersect_p (to, from))
16212117395Skan    return mode == TFmode ? 4 : 2;
16213117395Skan
16214117395Skan/* Everything else has to go through GENERAL_REGS.  */
16215117395Skan  else
16216117395Skan    return (rs6000_register_move_cost (mode, GENERAL_REGS, to)
16217117395Skan	    + rs6000_register_move_cost (mode, from, GENERAL_REGS));
16218117395Skan}
16219117395Skan
16220117395Skan/* A C expressions returning the cost of moving data of MODE from a register to
16221117395Skan   or from memory.  */
16222117395Skan
16223117395Skanint
16224132718Skanrs6000_memory_move_cost (enum machine_mode mode, enum reg_class class,
16225132718Skan			 int in ATTRIBUTE_UNUSED)
16226117395Skan{
16227117395Skan  if (reg_classes_intersect_p (class, GENERAL_REGS))
16228117395Skan    return 4 * HARD_REGNO_NREGS (0, mode);
16229117395Skan  else if (reg_classes_intersect_p (class, FLOAT_REGS))
16230117395Skan    return 4 * HARD_REGNO_NREGS (32, mode);
16231117395Skan  else if (reg_classes_intersect_p (class, ALTIVEC_REGS))
16232117395Skan    return 4 * HARD_REGNO_NREGS (FIRST_ALTIVEC_REGNO, mode);
16233117395Skan  else
16234117395Skan    return 4 + rs6000_register_move_cost (mode, class, GENERAL_REGS);
16235117395Skan}
16236117395Skan
16237132718Skan/* Return an RTX representing where to find the function value of a
16238132718Skan   function returning MODE.  */
16239132718Skanstatic rtx
16240132718Skanrs6000_complex_function_value (enum machine_mode mode)
16241132718Skan{
16242132718Skan  unsigned int regno;
16243132718Skan  rtx r1, r2;
16244132718Skan  enum machine_mode inner = GET_MODE_INNER (mode);
16245132718Skan  unsigned int inner_bytes = GET_MODE_SIZE (inner);
16246132718Skan
16247132718Skan  if (FLOAT_MODE_P (mode) && TARGET_HARD_FLOAT && TARGET_FPRS)
16248132718Skan    regno = FP_ARG_RETURN;
16249132718Skan  else
16250132718Skan    {
16251132718Skan      regno = GP_ARG_RETURN;
16252132718Skan
16253132718Skan      /* 32-bit is OK since it'll go in r3/r4.  */
16254132718Skan      if (TARGET_32BIT && inner_bytes >= 4)
16255132718Skan	return gen_rtx_REG (mode, regno);
16256132718Skan    }
16257132718Skan
16258132718Skan  if (inner_bytes >= 8)
16259132718Skan    return gen_rtx_REG (mode, regno);
16260132718Skan
16261132718Skan  r1 = gen_rtx_EXPR_LIST (inner, gen_rtx_REG (inner, regno),
16262132718Skan			  const0_rtx);
16263132718Skan  r2 = gen_rtx_EXPR_LIST (inner, gen_rtx_REG (inner, regno + 1),
16264132718Skan			  GEN_INT (inner_bytes));
16265132718Skan  return gen_rtx_PARALLEL (mode, gen_rtvec (2, r1, r2));
16266132718Skan}
16267132718Skan
16268132718Skan/* Define how to find the value returned by a function.
16269132718Skan   VALTYPE is the data type of the value (as a tree).
16270132718Skan   If the precise function being called is known, FUNC is its FUNCTION_DECL;
16271132718Skan   otherwise, FUNC is 0.
16272132718Skan
16273132718Skan   On the SPE, both FPs and vectors are returned in r3.
16274132718Skan
16275132718Skan   On RS/6000 an integer value is in r3 and a floating-point value is in
16276132718Skan   fp1, unless -msoft-float.  */
16277132718Skan
16278132718Skanrtx
16279132718Skanrs6000_function_value (tree valtype, tree func ATTRIBUTE_UNUSED)
16280132718Skan{
16281132718Skan  enum machine_mode mode;
16282132718Skan  unsigned int regno;
16283132718Skan
16284132718Skan  if (TARGET_32BIT && TARGET_POWERPC64 && TYPE_MODE (valtype) == DImode)
16285132718Skan    {
16286132718Skan      /* Long long return value need be split in -mpowerpc64, 32bit ABI.  */
16287132718Skan      return gen_rtx_PARALLEL (DImode,
16288132718Skan	gen_rtvec (2,
16289132718Skan		   gen_rtx_EXPR_LIST (VOIDmode,
16290132718Skan				      gen_rtx_REG (SImode, GP_ARG_RETURN),
16291132718Skan				      const0_rtx),
16292132718Skan		   gen_rtx_EXPR_LIST (VOIDmode,
16293132718Skan				      gen_rtx_REG (SImode,
16294132718Skan						   GP_ARG_RETURN + 1),
16295132718Skan				      GEN_INT (4))));
16296132718Skan    }
16297132718Skan
16298132718Skan  if ((INTEGRAL_TYPE_P (valtype)
16299132718Skan       && TYPE_PRECISION (valtype) < BITS_PER_WORD)
16300132718Skan      || POINTER_TYPE_P (valtype))
16301132718Skan    mode = TARGET_32BIT ? SImode : DImode;
16302132718Skan  else
16303132718Skan    mode = TYPE_MODE (valtype);
16304132718Skan
16305132718Skan  if (SCALAR_FLOAT_TYPE_P (valtype) && TARGET_HARD_FLOAT && TARGET_FPRS)
16306132718Skan    regno = FP_ARG_RETURN;
16307132718Skan  else if (TREE_CODE (valtype) == COMPLEX_TYPE
16308132718Skan	   && targetm.calls.split_complex_arg)
16309132718Skan    return rs6000_complex_function_value (mode);
16310132718Skan  else if (TREE_CODE (valtype) == VECTOR_TYPE
16311132718Skan	   && TARGET_ALTIVEC && TARGET_ALTIVEC_ABI)
16312132718Skan    regno = ALTIVEC_ARG_RETURN;
16313132718Skan  else
16314132718Skan    regno = GP_ARG_RETURN;
16315132718Skan
16316132718Skan  return gen_rtx_REG (mode, regno);
16317132718Skan}
16318132718Skan
16319132718Skan/* Define how to find the value returned by a library function
16320132718Skan   assuming the value has mode MODE.  */
16321132718Skanrtx
16322132718Skanrs6000_libcall_value (enum machine_mode mode)
16323132718Skan{
16324132718Skan  unsigned int regno;
16325132718Skan
16326132718Skan  if (GET_MODE_CLASS (mode) == MODE_FLOAT
16327132718Skan	   && TARGET_HARD_FLOAT && TARGET_FPRS)
16328132718Skan    regno = FP_ARG_RETURN;
16329132718Skan  else if (ALTIVEC_VECTOR_MODE (mode)
16330132718Skan	   && TARGET_ALTIVEC && TARGET_ALTIVEC_ABI)
16331132718Skan    regno = ALTIVEC_ARG_RETURN;
16332132718Skan  else if (COMPLEX_MODE_P (mode) && targetm.calls.split_complex_arg)
16333132718Skan    return rs6000_complex_function_value (mode);
16334132718Skan  else
16335132718Skan    regno = GP_ARG_RETURN;
16336132718Skan
16337132718Skan  return gen_rtx_REG (mode, regno);
16338132718Skan}
16339132718Skan
16340132718Skan/* Define the offset between two registers, FROM to be eliminated and its
16341132718Skan   replacement TO, at the start of a routine.  */
16342132718SkanHOST_WIDE_INT
16343132718Skanrs6000_initial_elimination_offset (int from, int to)
16344132718Skan{
16345132718Skan  rs6000_stack_t *info = rs6000_stack_info ();
16346132718Skan  HOST_WIDE_INT offset;
16347132718Skan
16348132718Skan  if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
16349132718Skan    offset = info->push_p ? 0 : -info->total_size;
16350132718Skan  else if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)
16351132718Skan    offset = info->total_size;
16352132718Skan  else if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
16353132718Skan    offset = info->push_p ? info->total_size : 0;
16354132718Skan  else if (from == RS6000_PIC_OFFSET_TABLE_REGNUM)
16355132718Skan    offset = 0;
16356132718Skan  else
16357132718Skan    abort ();
16358132718Skan
16359132718Skan  return offset;
16360132718Skan}
16361132718Skan
16362132718Skan/* Return true if TYPE is of type __ev64_opaque__.  */
16363132718Skan
16364132718Skanstatic bool
16365132718Skanis_ev64_opaque_type (tree type)
16366132718Skan{
16367132718Skan  return (TARGET_SPE
16368132718Skan	  && (type == opaque_V2SI_type_node
16369132718Skan	      || type == opaque_V2SF_type_node
16370132718Skan	      || type == opaque_p_V2SI_type_node));
16371132718Skan}
16372132718Skan
16373132718Skanstatic rtx
16374132718Skanrs6000_dwarf_register_span (rtx reg)
16375132718Skan{
16376132718Skan  unsigned regno;
16377132718Skan
16378132718Skan  if (!TARGET_SPE || !SPE_VECTOR_MODE (GET_MODE (reg)))
16379132718Skan    return NULL_RTX;
16380132718Skan
16381132718Skan  regno = REGNO (reg);
16382132718Skan
16383132718Skan  /* The duality of the SPE register size wreaks all kinds of havoc.
16384132718Skan     This is a way of distinguishing r0 in 32-bits from r0 in
16385132718Skan     64-bits.  */
16386132718Skan  return
16387132718Skan    gen_rtx_PARALLEL (VOIDmode,
16388132718Skan		      BYTES_BIG_ENDIAN
16389132718Skan		      ? gen_rtvec (2,
16390132718Skan				   gen_rtx_REG (SImode, regno + 1200),
16391132718Skan				   gen_rtx_REG (SImode, regno))
16392132718Skan		      : gen_rtvec (2,
16393132718Skan				   gen_rtx_REG (SImode, regno),
16394132718Skan				   gen_rtx_REG (SImode, regno + 1200)));
16395132718Skan}
16396132718Skan
16397132718Skan/* Map internal gcc register numbers to DWARF2 register numbers.  */
16398132718Skan
16399132718Skanunsigned int
16400132718Skanrs6000_dbx_register_number (unsigned int regno)
16401132718Skan{
16402132718Skan  if (regno <= 63 || write_symbols != DWARF2_DEBUG)
16403132718Skan    return regno;
16404132718Skan  if (regno == MQ_REGNO)
16405132718Skan    return 100;
16406132718Skan  if (regno == LINK_REGISTER_REGNUM)
16407132718Skan    return 108;
16408132718Skan  if (regno == COUNT_REGISTER_REGNUM)
16409132718Skan    return 109;
16410132718Skan  if (CR_REGNO_P (regno))
16411132718Skan    return regno - CR0_REGNO + 86;
16412132718Skan  if (regno == XER_REGNO)
16413132718Skan    return 101;
16414132718Skan  if (ALTIVEC_REGNO_P (regno))
16415132718Skan    return regno - FIRST_ALTIVEC_REGNO + 1124;
16416132718Skan  if (regno == VRSAVE_REGNO)
16417132718Skan    return 356;
16418132718Skan  if (regno == VSCR_REGNO)
16419132718Skan    return 67;
16420132718Skan  if (regno == SPE_ACC_REGNO)
16421132718Skan    return 99;
16422132718Skan  if (regno == SPEFSCR_REGNO)
16423132718Skan    return 612;
16424132718Skan  /* SPE high reg number.  We get these values of regno from
16425132718Skan     rs6000_dwarf_register_span.  */
16426132718Skan  if (regno >= 1200 && regno < 1232)
16427132718Skan    return regno;
16428132718Skan
16429132718Skan  abort ();
16430132718Skan}
16431132718Skan
16432132718Skan#include "gt-rs6000.h"
16433