rs6000.c revision 146895
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 operand is a (MEM (PLUS (REG) (offset))) where offset
2501132718Skan   is not divisible by four.  */
2502132718Skan
2503132718Skanint
2504132718Skaninvalid_gpr_mem (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
2505132718Skan{
2506132718Skan  rtx addr;
2507132718Skan  long off;
2508132718Skan
2509132718Skan  if (GET_CODE (op) != MEM)
2510132718Skan    return 0;
2511132718Skan
2512132718Skan  addr = XEXP (op, 0);
2513132718Skan  if (GET_CODE (addr) != PLUS
2514132718Skan      || GET_CODE (XEXP (addr, 0)) != REG
2515132718Skan      || GET_CODE (XEXP (addr, 1)) != CONST_INT)
2516132718Skan    return 0;
2517132718Skan
2518132718Skan  off = INTVAL (XEXP (addr, 1));
2519132718Skan  return (off & 3) != 0;
2520132718Skan}
2521132718Skan
2522132718Skan/* Return true if operand is a hard register that can be used as a base
2523132718Skan   register.  */
2524132718Skan
2525132718Skanint
2526132718Skanbase_reg_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
2527132718Skan{
2528132718Skan  unsigned int regno;
2529132718Skan
2530132718Skan  if (!REG_P (op))
2531132718Skan    return 0;
2532132718Skan
2533132718Skan  regno = REGNO (op);
2534132718Skan  return regno != 0 && regno <= 31;
2535132718Skan}
2536132718Skan
2537132718Skan/* Return true if either operand is a general purpose register.  */
2538132718Skan
2539132718Skanbool
2540132718Skangpr_or_gpr_p (rtx op0, rtx op1)
2541132718Skan{
2542132718Skan  return ((REG_P (op0) && INT_REGNO_P (REGNO (op0)))
2543132718Skan	  || (REG_P (op1) && INT_REGNO_P (REGNO (op1))));
2544132718Skan}
2545132718Skan
254690075Sobrien
2547132718Skan/* Subroutines of rs6000_legitimize_address and rs6000_legitimate_address.  */
2548132718Skan
254990075Sobrienstatic int
2550132718Skanconstant_pool_expr_1 (rtx op, int *have_sym, int *have_toc)
255190075Sobrien{
255290075Sobrien  switch (GET_CODE(op))
255390075Sobrien    {
255490075Sobrien    case SYMBOL_REF:
2555132718Skan      if (RS6000_SYMBOL_REF_TLS_P (op))
2556132718Skan	return 0;
2557132718Skan      else if (CONSTANT_POOL_ADDRESS_P (op))
255890075Sobrien	{
255990075Sobrien	  if (ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (op), Pmode))
256090075Sobrien	    {
256190075Sobrien	      *have_sym = 1;
256290075Sobrien	      return 1;
256390075Sobrien	    }
256490075Sobrien	  else
256590075Sobrien	    return 0;
256690075Sobrien	}
256790075Sobrien      else if (! strcmp (XSTR (op, 0), toc_label_name))
256890075Sobrien	{
256990075Sobrien	  *have_toc = 1;
257090075Sobrien	  return 1;
257190075Sobrien	}
257290075Sobrien      else
257390075Sobrien	return 0;
257490075Sobrien    case PLUS:
257590075Sobrien    case MINUS:
257696263Sobrien      return (constant_pool_expr_1 (XEXP (op, 0), have_sym, have_toc)
257796263Sobrien	      && constant_pool_expr_1 (XEXP (op, 1), have_sym, have_toc));
257890075Sobrien    case CONST:
257990075Sobrien      return constant_pool_expr_1 (XEXP (op, 0), have_sym, have_toc);
258090075Sobrien    case CONST_INT:
258190075Sobrien      return 1;
258290075Sobrien    default:
258390075Sobrien      return 0;
258490075Sobrien    }
258590075Sobrien}
258690075Sobrien
2587132718Skanstatic bool
2588132718Skanconstant_pool_expr_p (rtx op)
258990075Sobrien{
259090075Sobrien  int have_sym = 0;
259190075Sobrien  int have_toc = 0;
259290075Sobrien  return constant_pool_expr_1 (op, &have_sym, &have_toc) && have_sym;
259390075Sobrien}
259490075Sobrien
2595132718Skanstatic bool
2596132718Skantoc_relative_expr_p (rtx op)
259790075Sobrien{
2598132718Skan  int have_sym = 0;
2599132718Skan  int have_toc = 0;
2600132718Skan  return constant_pool_expr_1 (op, &have_sym, &have_toc) && have_toc;
260190075Sobrien}
260290075Sobrien
2603132718Skan/* SPE offset addressing is limited to 5-bits worth of double words.  */
2604132718Skan#define SPE_CONST_OFFSET_OK(x) (((x) & ~0xf8) == 0)
2605132718Skan
2606132718Skanbool
2607132718Skanlegitimate_constant_pool_address_p (rtx x)
2608132718Skan{
2609132718Skan  return (TARGET_TOC
2610132718Skan	  && GET_CODE (x) == PLUS
2611132718Skan	  && GET_CODE (XEXP (x, 0)) == REG
2612132718Skan	  && (TARGET_MINIMAL_TOC || REGNO (XEXP (x, 0)) == TOC_REGISTER)
2613132718Skan	  && constant_pool_expr_p (XEXP (x, 1)));
2614132718Skan}
2615132718Skan
2616132718Skanstatic bool
2617132718Skanlegitimate_small_data_p (enum machine_mode mode, rtx x)
2618132718Skan{
2619132718Skan  return (DEFAULT_ABI == ABI_V4
2620132718Skan	  && !flag_pic && !TARGET_TOC
2621132718Skan	  && (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == CONST)
2622132718Skan	  && small_data_operand (x, mode));
2623132718Skan}
2624132718Skan
2625132718Skanstatic bool
2626132718Skanlegitimate_offset_address_p (enum machine_mode mode, rtx x, int strict)
2627132718Skan{
2628132718Skan  unsigned HOST_WIDE_INT offset, extra;
2629132718Skan
2630132718Skan  if (GET_CODE (x) != PLUS)
2631132718Skan    return false;
2632132718Skan  if (GET_CODE (XEXP (x, 0)) != REG)
2633132718Skan    return false;
2634132718Skan  if (!INT_REG_OK_FOR_BASE_P (XEXP (x, 0), strict))
2635132718Skan    return false;
2636132718Skan  if (GET_CODE (XEXP (x, 1)) != CONST_INT)
2637132718Skan    return false;
2638132718Skan
2639132718Skan  offset = INTVAL (XEXP (x, 1));
2640132718Skan  extra = 0;
2641132718Skan  switch (mode)
2642132718Skan    {
2643132718Skan    case V16QImode:
2644132718Skan    case V8HImode:
2645132718Skan    case V4SFmode:
2646132718Skan    case V4SImode:
2647132718Skan      /* AltiVec vector modes.  Only reg+reg addressing is valid here,
2648132718Skan	 which leaves the only valid constant offset of zero, which by
2649132718Skan	 canonicalization rules is also invalid.  */
2650132718Skan      return false;
2651132718Skan
2652132718Skan    case V4HImode:
2653132718Skan    case V2SImode:
2654132718Skan    case V1DImode:
2655132718Skan    case V2SFmode:
2656132718Skan      /* SPE vector modes.  */
2657132718Skan      return SPE_CONST_OFFSET_OK (offset);
2658132718Skan
2659132718Skan    case DFmode:
2660132718Skan    case DImode:
2661132718Skan      /* Both DFmode and DImode may end up in gprs.  If gprs are 32-bit,
2662132718Skan	 then we need to load/store at both offset and offset+4.  */
2663132718Skan      if (!TARGET_POWERPC64)
2664132718Skan	extra = 4;
2665132718Skan      break;
2666132718Skan
2667132718Skan    case TFmode:
2668132718Skan    case TImode:
2669132718Skan      if (!TARGET_POWERPC64)
2670132718Skan	extra = 12;
2671132718Skan      else
2672132718Skan	extra = 8;
2673132718Skan      break;
2674132718Skan
2675132718Skan    default:
2676132718Skan      break;
2677132718Skan    }
2678132718Skan
2679132718Skan  offset += 0x8000;
2680132718Skan  return (offset < 0x10000) && (offset + extra < 0x10000);
2681132718Skan}
2682132718Skan
2683132718Skanstatic bool
2684132718Skanlegitimate_indexed_address_p (rtx x, int strict)
2685132718Skan{
2686132718Skan  rtx op0, op1;
2687132718Skan
2688132718Skan  if (GET_CODE (x) != PLUS)
2689132718Skan    return false;
2690132718Skan  op0 = XEXP (x, 0);
2691132718Skan  op1 = XEXP (x, 1);
2692132718Skan
2693132718Skan  if (!REG_P (op0) || !REG_P (op1))
2694132718Skan    return false;
2695132718Skan
2696132718Skan  return ((INT_REG_OK_FOR_BASE_P (op0, strict)
2697132718Skan	   && INT_REG_OK_FOR_INDEX_P (op1, strict))
2698132718Skan	  || (INT_REG_OK_FOR_BASE_P (op1, strict)
2699132718Skan	      && INT_REG_OK_FOR_INDEX_P (op0, strict)));
2700132718Skan}
2701132718Skan
2702132718Skanstatic inline bool
2703132718Skanlegitimate_indirect_address_p (rtx x, int strict)
2704132718Skan{
2705132718Skan  return GET_CODE (x) == REG && INT_REG_OK_FOR_BASE_P (x, strict);
2706132718Skan}
2707132718Skan
2708132718Skanstatic bool
2709132718Skanmacho_lo_sum_memory_operand (rtx x, enum machine_mode mode)
2710132718Skan{
2711132718Skan    if (!TARGET_MACHO || !flag_pic
2712132718Skan        || mode != SImode || GET_CODE(x) != MEM)
2713132718Skan      return false;
2714132718Skan    x = XEXP (x, 0);
2715132718Skan
2716132718Skan  if (GET_CODE (x) != LO_SUM)
2717132718Skan    return false;
2718132718Skan  if (GET_CODE (XEXP (x, 0)) != REG)
2719132718Skan    return false;
2720132718Skan  if (!INT_REG_OK_FOR_BASE_P (XEXP (x, 0), 0))
2721132718Skan    return false;
2722132718Skan  x = XEXP (x, 1);
2723132718Skan
2724132718Skan  return CONSTANT_P (x);
2725132718Skan}
2726132718Skan
2727132718Skanstatic bool
2728132718Skanlegitimate_lo_sum_address_p (enum machine_mode mode, rtx x, int strict)
2729132718Skan{
2730132718Skan  if (GET_CODE (x) != LO_SUM)
2731132718Skan    return false;
2732132718Skan  if (GET_CODE (XEXP (x, 0)) != REG)
2733132718Skan    return false;
2734132718Skan  if (!INT_REG_OK_FOR_BASE_P (XEXP (x, 0), strict))
2735132718Skan    return false;
2736132718Skan  x = XEXP (x, 1);
2737132718Skan
2738132718Skan  if (TARGET_ELF || TARGET_MACHO)
2739132718Skan    {
2740132718Skan      if (DEFAULT_ABI != ABI_AIX && DEFAULT_ABI != ABI_DARWIN && flag_pic)
2741132718Skan	return false;
2742132718Skan      if (TARGET_TOC)
2743132718Skan	return false;
2744132718Skan      if (GET_MODE_NUNITS (mode) != 1)
2745132718Skan	return false;
2746132718Skan      if (GET_MODE_BITSIZE (mode) > 32
2747132718Skan	  && !(TARGET_HARD_FLOAT && TARGET_FPRS && mode == DFmode))
2748132718Skan	return false;
2749132718Skan
2750132718Skan      return CONSTANT_P (x);
2751132718Skan    }
2752132718Skan
2753132718Skan  return false;
2754132718Skan}
2755132718Skan
2756132718Skan
275790075Sobrien/* Try machine-dependent ways of modifying an illegitimate address
275890075Sobrien   to be legitimate.  If we find one, return the new, valid address.
275990075Sobrien   This is used from only one place: `memory_address' in explow.c.
276090075Sobrien
276190075Sobrien   OLDX is the address as it was before break_out_memory_refs was
276290075Sobrien   called.  In some cases it is useful to look at this to decide what
276390075Sobrien   needs to be done.
276490075Sobrien
276590075Sobrien   MODE is passed so that this function can use GO_IF_LEGITIMATE_ADDRESS.
276690075Sobrien
276790075Sobrien   It is always safe for this function to do nothing.  It exists to
276890075Sobrien   recognize opportunities to optimize the output.
276990075Sobrien
277090075Sobrien   On RS/6000, first check for the sum of a register with a constant
277190075Sobrien   integer that is out of range.  If so, generate code to add the
277290075Sobrien   constant with the low-order 16 bits masked to the register and force
277390075Sobrien   this result into another register (this can be done with `cau').
277490075Sobrien   Then generate an address of REG+(CONST&0xffff), allowing for the
277590075Sobrien   possibility of bit 16 being a one.
277690075Sobrien
277790075Sobrien   Then check for the sum of a register and something not constant, try to
277890075Sobrien   load the other things into a register and return the sum.  */
2779132718Skan
278090075Sobrienrtx
2781132718Skanrs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
2782132718Skan			   enum machine_mode mode)
278390075Sobrien{
2784132718Skan  if (GET_CODE (x) == SYMBOL_REF)
2785132718Skan    {
2786132718Skan      enum tls_model model = SYMBOL_REF_TLS_MODEL (x);
2787132718Skan      if (model != 0)
2788132718Skan	return rs6000_legitimize_tls_address (x, model);
2789132718Skan    }
2790132718Skan
279190075Sobrien  if (GET_CODE (x) == PLUS
279290075Sobrien      && GET_CODE (XEXP (x, 0)) == REG
279390075Sobrien      && GET_CODE (XEXP (x, 1)) == CONST_INT
279490075Sobrien      && (unsigned HOST_WIDE_INT) (INTVAL (XEXP (x, 1)) + 0x8000) >= 0x10000)
279590075Sobrien    {
279690075Sobrien      HOST_WIDE_INT high_int, low_int;
279790075Sobrien      rtx sum;
2798117395Skan      low_int = ((INTVAL (XEXP (x, 1)) & 0xffff) ^ 0x8000) - 0x8000;
2799117395Skan      high_int = INTVAL (XEXP (x, 1)) - low_int;
280090075Sobrien      sum = force_operand (gen_rtx_PLUS (Pmode, XEXP (x, 0),
280190075Sobrien					 GEN_INT (high_int)), 0);
280290075Sobrien      return gen_rtx_PLUS (Pmode, sum, GEN_INT (low_int));
280390075Sobrien    }
280490075Sobrien  else if (GET_CODE (x) == PLUS
280590075Sobrien	   && GET_CODE (XEXP (x, 0)) == REG
280690075Sobrien	   && GET_CODE (XEXP (x, 1)) != CONST_INT
280790075Sobrien	   && GET_MODE_NUNITS (mode) == 1
2808117395Skan	   && ((TARGET_HARD_FLOAT && TARGET_FPRS)
2809117395Skan	       || TARGET_POWERPC64
2810117395Skan	       || (mode != DFmode && mode != TFmode))
281190075Sobrien	   && (TARGET_POWERPC64 || mode != DImode)
281290075Sobrien	   && mode != TImode)
281390075Sobrien    {
281490075Sobrien      return gen_rtx_PLUS (Pmode, XEXP (x, 0),
281590075Sobrien			   force_reg (Pmode, force_operand (XEXP (x, 1), 0)));
281690075Sobrien    }
281790075Sobrien  else if (ALTIVEC_VECTOR_MODE (mode))
281890075Sobrien    {
281990075Sobrien      rtx reg;
282090075Sobrien
282190075Sobrien      /* Make sure both operands are registers.  */
282290075Sobrien      if (GET_CODE (x) == PLUS)
282390075Sobrien	return gen_rtx_PLUS (Pmode, force_reg (Pmode, XEXP (x, 0)),
282490075Sobrien			     force_reg (Pmode, XEXP (x, 1)));
282590075Sobrien
282690075Sobrien      reg = force_reg (Pmode, x);
282790075Sobrien      return reg;
282890075Sobrien    }
2829117395Skan  else if (SPE_VECTOR_MODE (mode))
2830117395Skan    {
2831117395Skan      /* We accept [reg + reg] and [reg + OFFSET].  */
2832117395Skan
2833117395Skan      if (GET_CODE (x) == PLUS)
2834117395Skan      {
2835117395Skan        rtx op1 = XEXP (x, 0);
2836117395Skan        rtx op2 = XEXP (x, 1);
2837117395Skan
2838117395Skan        op1 = force_reg (Pmode, op1);
2839117395Skan
2840117395Skan        if (GET_CODE (op2) != REG
2841117395Skan            && (GET_CODE (op2) != CONST_INT
2842117395Skan                || !SPE_CONST_OFFSET_OK (INTVAL (op2))))
2843117395Skan          op2 = force_reg (Pmode, op2);
2844117395Skan
2845117395Skan        return gen_rtx_PLUS (Pmode, op1, op2);
2846117395Skan      }
2847117395Skan
2848117395Skan      return force_reg (Pmode, x);
2849117395Skan    }
2850132718Skan  else if (TARGET_ELF
2851132718Skan	   && TARGET_32BIT
2852132718Skan	   && TARGET_NO_TOC
2853132718Skan	   && ! flag_pic
285490075Sobrien	   && GET_CODE (x) != CONST_INT
285590075Sobrien	   && GET_CODE (x) != CONST_DOUBLE
285690075Sobrien	   && CONSTANT_P (x)
285790075Sobrien	   && GET_MODE_NUNITS (mode) == 1
285890075Sobrien	   && (GET_MODE_BITSIZE (mode) <= 32
2859117395Skan	       || ((TARGET_HARD_FLOAT && TARGET_FPRS) && mode == DFmode)))
286090075Sobrien    {
286190075Sobrien      rtx reg = gen_reg_rtx (Pmode);
2862132718Skan      emit_insn (gen_elf_high (reg, x));
2863132718Skan      return gen_rtx_LO_SUM (Pmode, reg, x);
286490075Sobrien    }
286590075Sobrien  else if (TARGET_MACHO && TARGET_32BIT && TARGET_NO_TOC
286690075Sobrien	   && ! flag_pic
2867132718Skan#if TARGET_MACHO
2868132718Skan	   && ! MACHO_DYNAMIC_NO_PIC_P
2869132718Skan#endif
287090075Sobrien	   && GET_CODE (x) != CONST_INT
287190075Sobrien	   && GET_CODE (x) != CONST_DOUBLE
287290075Sobrien	   && CONSTANT_P (x)
2873117395Skan	   && ((TARGET_HARD_FLOAT && TARGET_FPRS) || mode != DFmode)
287490075Sobrien	   && mode != DImode
287590075Sobrien	   && mode != TImode)
287690075Sobrien    {
287790075Sobrien      rtx reg = gen_reg_rtx (Pmode);
2878132718Skan      emit_insn (gen_macho_high (reg, x));
2879132718Skan      return gen_rtx_LO_SUM (Pmode, reg, x);
288090075Sobrien    }
288190075Sobrien  else if (TARGET_TOC
2882132718Skan	   && constant_pool_expr_p (x)
288390075Sobrien	   && ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (x), Pmode))
288490075Sobrien    {
288590075Sobrien      return create_TOC_reference (x);
288690075Sobrien    }
288790075Sobrien  else
288890075Sobrien    return NULL_RTX;
288990075Sobrien}
289090075Sobrien
2891132718Skan/* This is called from dwarf2out.c via ASM_OUTPUT_DWARF_DTPREL.
2892132718Skan   We need to emit DTP-relative relocations.  */
2893132718Skan
2894132718Skanvoid
2895132718Skanrs6000_output_dwarf_dtprel (FILE *file, int size, rtx x)
2896132718Skan{
2897132718Skan  switch (size)
2898132718Skan    {
2899132718Skan    case 4:
2900132718Skan      fputs ("\t.long\t", file);
2901132718Skan      break;
2902132718Skan    case 8:
2903132718Skan      fputs (DOUBLE_INT_ASM_OP, file);
2904132718Skan      break;
2905132718Skan    default:
2906132718Skan      abort ();
2907132718Skan    }
2908132718Skan  output_addr_const (file, x);
2909132718Skan  fputs ("@dtprel+0x8000", file);
2910132718Skan}
2911132718Skan
2912132718Skan/* Construct the SYMBOL_REF for the tls_get_addr function.  */
2913132718Skan
2914132718Skanstatic GTY(()) rtx rs6000_tls_symbol;
2915132718Skanstatic rtx
2916132718Skanrs6000_tls_get_addr (void)
2917132718Skan{
2918132718Skan  if (!rs6000_tls_symbol)
2919132718Skan    rs6000_tls_symbol = init_one_libfunc ("__tls_get_addr");
2920132718Skan
2921132718Skan  return rs6000_tls_symbol;
2922132718Skan}
2923132718Skan
2924132718Skan/* Construct the SYMBOL_REF for TLS GOT references.  */
2925132718Skan
2926132718Skanstatic GTY(()) rtx rs6000_got_symbol;
2927132718Skanstatic rtx
2928132718Skanrs6000_got_sym (void)
2929132718Skan{
2930132718Skan  if (!rs6000_got_symbol)
2931132718Skan    {
2932132718Skan      rs6000_got_symbol = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
2933132718Skan      SYMBOL_REF_FLAGS (rs6000_got_symbol) |= SYMBOL_FLAG_LOCAL;
2934132718Skan      SYMBOL_REF_FLAGS (rs6000_got_symbol) |= SYMBOL_FLAG_EXTERNAL;
2935132718Skan    }
2936132718Skan
2937132718Skan  return rs6000_got_symbol;
2938132718Skan}
2939132718Skan
2940132718Skan/* ADDR contains a thread-local SYMBOL_REF.  Generate code to compute
2941132718Skan   this (thread-local) address.  */
2942132718Skan
2943132718Skanstatic rtx
2944132718Skanrs6000_legitimize_tls_address (rtx addr, enum tls_model model)
2945132718Skan{
2946132718Skan  rtx dest, insn;
2947132718Skan
2948132718Skan  dest = gen_reg_rtx (Pmode);
2949132718Skan  if (model == TLS_MODEL_LOCAL_EXEC && rs6000_tls_size == 16)
2950132718Skan    {
2951132718Skan      rtx tlsreg;
2952132718Skan
2953132718Skan      if (TARGET_64BIT)
2954132718Skan	{
2955132718Skan	  tlsreg = gen_rtx_REG (Pmode, 13);
2956132718Skan	  insn = gen_tls_tprel_64 (dest, tlsreg, addr);
2957132718Skan	}
2958132718Skan      else
2959132718Skan	{
2960132718Skan	  tlsreg = gen_rtx_REG (Pmode, 2);
2961132718Skan	  insn = gen_tls_tprel_32 (dest, tlsreg, addr);
2962132718Skan	}
2963132718Skan      emit_insn (insn);
2964132718Skan    }
2965132718Skan  else if (model == TLS_MODEL_LOCAL_EXEC && rs6000_tls_size == 32)
2966132718Skan    {
2967132718Skan      rtx tlsreg, tmp;
2968132718Skan
2969132718Skan      tmp = gen_reg_rtx (Pmode);
2970132718Skan      if (TARGET_64BIT)
2971132718Skan	{
2972132718Skan	  tlsreg = gen_rtx_REG (Pmode, 13);
2973132718Skan	  insn = gen_tls_tprel_ha_64 (tmp, tlsreg, addr);
2974132718Skan	}
2975132718Skan      else
2976132718Skan	{
2977132718Skan	  tlsreg = gen_rtx_REG (Pmode, 2);
2978132718Skan	  insn = gen_tls_tprel_ha_32 (tmp, tlsreg, addr);
2979132718Skan	}
2980132718Skan      emit_insn (insn);
2981132718Skan      if (TARGET_64BIT)
2982132718Skan	insn = gen_tls_tprel_lo_64 (dest, tmp, addr);
2983132718Skan      else
2984132718Skan	insn = gen_tls_tprel_lo_32 (dest, tmp, addr);
2985132718Skan      emit_insn (insn);
2986132718Skan    }
2987132718Skan  else
2988132718Skan    {
2989132718Skan      rtx r3, got, tga, tmp1, tmp2, eqv;
2990132718Skan
2991132718Skan      if (TARGET_64BIT)
2992132718Skan	got = gen_rtx_REG (Pmode, TOC_REGISTER);
2993132718Skan      else
2994132718Skan	{
2995132718Skan	  if (flag_pic == 1)
2996132718Skan	    got = gen_rtx_REG (Pmode, RS6000_PIC_OFFSET_TABLE_REGNUM);
2997132718Skan	  else
2998132718Skan	    {
2999132718Skan	      rtx gsym = rs6000_got_sym ();
3000132718Skan	      got = gen_reg_rtx (Pmode);
3001132718Skan	      if (flag_pic == 0)
3002132718Skan		rs6000_emit_move (got, gsym, Pmode);
3003132718Skan	      else
3004132718Skan		{
3005146895Skan		  rtx tempLR, tmp3, mem;
3006132718Skan		  rtx first, last;
3007132718Skan
3008132718Skan		  tempLR = gen_reg_rtx (Pmode);
3009132718Skan		  tmp1 = gen_reg_rtx (Pmode);
3010132718Skan		  tmp2 = gen_reg_rtx (Pmode);
3011132718Skan		  tmp3 = gen_reg_rtx (Pmode);
3012132718Skan		  mem = gen_rtx_MEM (Pmode, tmp1);
3013132718Skan		  RTX_UNCHANGING_P (mem) = 1;
3014132718Skan
3015146895Skan		  first = emit_insn (gen_load_toc_v4_PIC_1b (tempLR, gsym));
3016132718Skan		  emit_move_insn (tmp1, tempLR);
3017132718Skan		  emit_move_insn (tmp2, mem);
3018132718Skan		  emit_insn (gen_addsi3 (tmp3, tmp1, tmp2));
3019132718Skan		  last = emit_move_insn (got, tmp3);
3020132718Skan		  REG_NOTES (last) = gen_rtx_EXPR_LIST (REG_EQUAL, gsym,
3021132718Skan							REG_NOTES (last));
3022132718Skan		  REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last,
3023132718Skan							 REG_NOTES (first));
3024132718Skan		  REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first,
3025132718Skan							REG_NOTES (last));
3026132718Skan		}
3027132718Skan	    }
3028132718Skan	}
3029132718Skan
3030132718Skan      if (model == TLS_MODEL_GLOBAL_DYNAMIC)
3031132718Skan	{
3032132718Skan	  r3 = gen_rtx_REG (Pmode, 3);
3033132718Skan	  if (TARGET_64BIT)
3034132718Skan	    insn = gen_tls_gd_64 (r3, got, addr);
3035132718Skan	  else
3036132718Skan	    insn = gen_tls_gd_32 (r3, got, addr);
3037132718Skan	  start_sequence ();
3038132718Skan	  emit_insn (insn);
3039132718Skan	  tga = gen_rtx_MEM (Pmode, rs6000_tls_get_addr ());
3040132718Skan	  insn = gen_call_value (r3, tga, const0_rtx, const0_rtx);
3041132718Skan	  insn = emit_call_insn (insn);
3042132718Skan	  CONST_OR_PURE_CALL_P (insn) = 1;
3043132718Skan	  use_reg (&CALL_INSN_FUNCTION_USAGE (insn), r3);
3044132718Skan	  insn = get_insns ();
3045132718Skan	  end_sequence ();
3046132718Skan	  emit_libcall_block (insn, dest, r3, addr);
3047132718Skan	}
3048132718Skan      else if (model == TLS_MODEL_LOCAL_DYNAMIC)
3049132718Skan	{
3050132718Skan	  r3 = gen_rtx_REG (Pmode, 3);
3051132718Skan	  if (TARGET_64BIT)
3052132718Skan	    insn = gen_tls_ld_64 (r3, got);
3053132718Skan	  else
3054132718Skan	    insn = gen_tls_ld_32 (r3, got);
3055132718Skan	  start_sequence ();
3056132718Skan	  emit_insn (insn);
3057132718Skan	  tga = gen_rtx_MEM (Pmode, rs6000_tls_get_addr ());
3058132718Skan	  insn = gen_call_value (r3, tga, const0_rtx, const0_rtx);
3059132718Skan	  insn = emit_call_insn (insn);
3060132718Skan	  CONST_OR_PURE_CALL_P (insn) = 1;
3061132718Skan	  use_reg (&CALL_INSN_FUNCTION_USAGE (insn), r3);
3062132718Skan	  insn = get_insns ();
3063132718Skan	  end_sequence ();
3064132718Skan	  tmp1 = gen_reg_rtx (Pmode);
3065132718Skan	  eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx),
3066132718Skan				UNSPEC_TLSLD);
3067132718Skan	  emit_libcall_block (insn, tmp1, r3, eqv);
3068132718Skan	  if (rs6000_tls_size == 16)
3069132718Skan	    {
3070132718Skan	      if (TARGET_64BIT)
3071132718Skan		insn = gen_tls_dtprel_64 (dest, tmp1, addr);
3072132718Skan	      else
3073132718Skan		insn = gen_tls_dtprel_32 (dest, tmp1, addr);
3074132718Skan	    }
3075132718Skan	  else if (rs6000_tls_size == 32)
3076132718Skan	    {
3077132718Skan	      tmp2 = gen_reg_rtx (Pmode);
3078132718Skan	      if (TARGET_64BIT)
3079132718Skan		insn = gen_tls_dtprel_ha_64 (tmp2, tmp1, addr);
3080132718Skan	      else
3081132718Skan		insn = gen_tls_dtprel_ha_32 (tmp2, tmp1, addr);
3082132718Skan	      emit_insn (insn);
3083132718Skan	      if (TARGET_64BIT)
3084132718Skan		insn = gen_tls_dtprel_lo_64 (dest, tmp2, addr);
3085132718Skan	      else
3086132718Skan		insn = gen_tls_dtprel_lo_32 (dest, tmp2, addr);
3087132718Skan	    }
3088132718Skan	  else
3089132718Skan	    {
3090132718Skan	      tmp2 = gen_reg_rtx (Pmode);
3091132718Skan	      if (TARGET_64BIT)
3092132718Skan		insn = gen_tls_got_dtprel_64 (tmp2, got, addr);
3093132718Skan	      else
3094132718Skan		insn = gen_tls_got_dtprel_32 (tmp2, got, addr);
3095132718Skan	      emit_insn (insn);
3096132718Skan	      insn = gen_rtx_SET (Pmode, dest,
3097132718Skan				  gen_rtx_PLUS (Pmode, tmp2, tmp1));
3098132718Skan	    }
3099132718Skan	  emit_insn (insn);
3100132718Skan	}
3101132718Skan      else
3102132718Skan	{
3103132718Skan	  /* IE, or 64 bit offset LE.  */
3104132718Skan	  tmp2 = gen_reg_rtx (Pmode);
3105132718Skan	  if (TARGET_64BIT)
3106132718Skan	    insn = gen_tls_got_tprel_64 (tmp2, got, addr);
3107132718Skan	  else
3108132718Skan	    insn = gen_tls_got_tprel_32 (tmp2, got, addr);
3109132718Skan	  emit_insn (insn);
3110132718Skan	  if (TARGET_64BIT)
3111132718Skan	    insn = gen_tls_tls_64 (dest, tmp2, addr);
3112132718Skan	  else
3113132718Skan	    insn = gen_tls_tls_32 (dest, tmp2, addr);
3114132718Skan	  emit_insn (insn);
3115132718Skan	}
3116132718Skan    }
3117132718Skan
3118132718Skan  return dest;
3119132718Skan}
3120132718Skan
3121132718Skan/* Return 1 if X is a SYMBOL_REF for a TLS symbol.  This is used in
3122132718Skan   instruction definitions.  */
3123132718Skan
3124132718Skanint
3125132718Skanrs6000_tls_symbol_ref (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
3126132718Skan{
3127132718Skan  return RS6000_SYMBOL_REF_TLS_P (x);
3128132718Skan}
3129132718Skan
3130132718Skan/* Return 1 if X contains a thread-local symbol.  */
3131132718Skan
3132132718Skanbool
3133132718Skanrs6000_tls_referenced_p (rtx x)
3134132718Skan{
3135132718Skan  if (! TARGET_HAVE_TLS)
3136132718Skan    return false;
3137132718Skan
3138132718Skan  return for_each_rtx (&x, &rs6000_tls_symbol_ref_1, 0);
3139132718Skan}
3140132718Skan
3141132718Skan/* Return 1 if *X is a thread-local symbol.  This is the same as
3142132718Skan   rs6000_tls_symbol_ref except for the type of the unused argument.  */
3143132718Skan
3144132718Skanstatic inline int
3145132718Skanrs6000_tls_symbol_ref_1 (rtx *x, void *data ATTRIBUTE_UNUSED)
3146132718Skan{
3147132718Skan  return RS6000_SYMBOL_REF_TLS_P (*x);
3148132718Skan}
3149132718Skan
315090075Sobrien/* The convention appears to be to define this wherever it is used.
315190075Sobrien   With legitimize_reload_address now defined here, REG_MODE_OK_FOR_BASE_P
315290075Sobrien   is now used here.  */
315390075Sobrien#ifndef REG_MODE_OK_FOR_BASE_P
315490075Sobrien#define REG_MODE_OK_FOR_BASE_P(REGNO, MODE) REG_OK_FOR_BASE_P (REGNO)
315590075Sobrien#endif
315690075Sobrien
315790075Sobrien/* Our implementation of LEGITIMIZE_RELOAD_ADDRESS.  Returns a value to
315890075Sobrien   replace the input X, or the original X if no replacement is called for.
315990075Sobrien   The output parameter *WIN is 1 if the calling macro should goto WIN,
316090075Sobrien   0 if it should not.
316190075Sobrien
316290075Sobrien   For RS/6000, we wish to handle large displacements off a base
316390075Sobrien   register by splitting the addend across an addiu/addis and the mem insn.
316490075Sobrien   This cuts number of extra insns needed from 3 to 1.
316590075Sobrien
316690075Sobrien   On Darwin, we use this to generate code for floating point constants.
316790075Sobrien   A movsf_low is generated so we wind up with 2 instructions rather than 3.
316890075Sobrien   The Darwin code is inside #if TARGET_MACHO because only then is
316990075Sobrien   machopic_function_base_name() defined.  */
317090075Sobrienrtx
3171132718Skanrs6000_legitimize_reload_address (rtx x, enum machine_mode mode,
3172132718Skan	int opnum, int type, int ind_levels ATTRIBUTE_UNUSED, int *win)
317390075Sobrien{
317490075Sobrien  /* We must recognize output that we have already generated ourselves.  */
317590075Sobrien  if (GET_CODE (x) == PLUS
317690075Sobrien      && GET_CODE (XEXP (x, 0)) == PLUS
317790075Sobrien      && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG
317890075Sobrien      && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
317990075Sobrien      && GET_CODE (XEXP (x, 1)) == CONST_INT)
318090075Sobrien    {
318190075Sobrien      push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
318290075Sobrien                   BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0,
318390075Sobrien                   opnum, (enum reload_type)type);
318490075Sobrien      *win = 1;
318590075Sobrien      return x;
318690075Sobrien    }
318796263Sobrien
318890075Sobrien#if TARGET_MACHO
318990075Sobrien  if (DEFAULT_ABI == ABI_DARWIN && flag_pic
319090075Sobrien      && GET_CODE (x) == LO_SUM
319190075Sobrien      && GET_CODE (XEXP (x, 0)) == PLUS
319290075Sobrien      && XEXP (XEXP (x, 0), 0) == pic_offset_table_rtx
319390075Sobrien      && GET_CODE (XEXP (XEXP (x, 0), 1)) == HIGH
319490075Sobrien      && GET_CODE (XEXP (XEXP (XEXP (x, 0), 1), 0)) == CONST
319590075Sobrien      && XEXP (XEXP (XEXP (x, 0), 1), 0) == XEXP (x, 1)
319690075Sobrien      && GET_CODE (XEXP (XEXP (x, 1), 0)) == MINUS
319790075Sobrien      && GET_CODE (XEXP (XEXP (XEXP (x, 1), 0), 0)) == SYMBOL_REF
319890075Sobrien      && GET_CODE (XEXP (XEXP (XEXP (x, 1), 0), 1)) == SYMBOL_REF)
319990075Sobrien    {
320090075Sobrien      /* Result of previous invocation of this function on Darwin
320190075Sobrien	 floating point constant.  */
320290075Sobrien      push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
320390075Sobrien		BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
320490075Sobrien		opnum, (enum reload_type)type);
320590075Sobrien      *win = 1;
320690075Sobrien      return x;
320790075Sobrien    }
320890075Sobrien#endif
320990075Sobrien  if (GET_CODE (x) == PLUS
321090075Sobrien      && GET_CODE (XEXP (x, 0)) == REG
321190075Sobrien      && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER
321290075Sobrien      && REG_MODE_OK_FOR_BASE_P (XEXP (x, 0), mode)
321396263Sobrien      && GET_CODE (XEXP (x, 1)) == CONST_INT
3214117395Skan      && !SPE_VECTOR_MODE (mode)
321596263Sobrien      && !ALTIVEC_VECTOR_MODE (mode))
321690075Sobrien    {
321790075Sobrien      HOST_WIDE_INT val = INTVAL (XEXP (x, 1));
321890075Sobrien      HOST_WIDE_INT low = ((val & 0xffff) ^ 0x8000) - 0x8000;
321990075Sobrien      HOST_WIDE_INT high
322090075Sobrien        = (((val - low) & 0xffffffff) ^ 0x80000000) - 0x80000000;
322190075Sobrien
322290075Sobrien      /* Check for 32-bit overflow.  */
322390075Sobrien      if (high + low != val)
322490075Sobrien        {
322590075Sobrien	  *win = 0;
322690075Sobrien	  return x;
322790075Sobrien	}
322890075Sobrien
322990075Sobrien      /* Reload the high part into a base reg; leave the low part
323090075Sobrien         in the mem directly.  */
323190075Sobrien
323290075Sobrien      x = gen_rtx_PLUS (GET_MODE (x),
323390075Sobrien                        gen_rtx_PLUS (GET_MODE (x), XEXP (x, 0),
323490075Sobrien                                      GEN_INT (high)),
323590075Sobrien                        GEN_INT (low));
323690075Sobrien
323790075Sobrien      push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
323890075Sobrien                   BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0,
323990075Sobrien                   opnum, (enum reload_type)type);
324090075Sobrien      *win = 1;
324190075Sobrien      return x;
324290075Sobrien    }
324390075Sobrien#if TARGET_MACHO
324490075Sobrien  if (GET_CODE (x) == SYMBOL_REF
324590075Sobrien      && DEFAULT_ABI == ABI_DARWIN
324696263Sobrien      && !ALTIVEC_VECTOR_MODE (mode)
3247132718Skan      && (flag_pic || MACHO_DYNAMIC_NO_PIC_P)
3248132718Skan      /* Don't do this for TFmode, since the result isn't offsettable.  */
3249132718Skan      && mode != TFmode)
325090075Sobrien    {
3251132718Skan      if (flag_pic)
3252132718Skan	{
3253132718Skan	  rtx offset = gen_rtx_CONST (Pmode,
3254132718Skan			 gen_rtx_MINUS (Pmode, x,
3255132718Skan			   gen_rtx_SYMBOL_REF (Pmode,
3256132718Skan			     machopic_function_base_name ())));
3257132718Skan	  x = gen_rtx_LO_SUM (GET_MODE (x),
3258132718Skan		gen_rtx_PLUS (Pmode, pic_offset_table_rtx,
3259132718Skan		  gen_rtx_HIGH (Pmode, offset)), offset);
3260132718Skan	}
3261132718Skan      else
3262132718Skan	x = gen_rtx_LO_SUM (GET_MODE (x),
3263132718Skan              gen_rtx_HIGH (Pmode, x), x);
3264132718Skan
326590075Sobrien      push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
3266132718Skan		   BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
3267132718Skan		   opnum, (enum reload_type)type);
326890075Sobrien      *win = 1;
326990075Sobrien      return x;
327090075Sobrien    }
327190075Sobrien#endif
327290075Sobrien  if (TARGET_TOC
3273132718Skan      && constant_pool_expr_p (x)
327496263Sobrien      && ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (x), mode))
327590075Sobrien    {
327690075Sobrien      (x) = create_TOC_reference (x);
327790075Sobrien      *win = 1;
327890075Sobrien      return x;
327990075Sobrien    }
328090075Sobrien  *win = 0;
328190075Sobrien  return x;
328290075Sobrien}
328390075Sobrien
328490075Sobrien/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression
328590075Sobrien   that is a valid memory address for an instruction.
328690075Sobrien   The MODE argument is the machine mode for the MEM expression
328790075Sobrien   that wants to use this address.
328890075Sobrien
328990075Sobrien   On the RS/6000, there are four valid address: a SYMBOL_REF that
329090075Sobrien   refers to a constant pool entry of an address (or the sum of it
329190075Sobrien   plus a constant), a short (16-bit signed) constant plus a register,
329290075Sobrien   the sum of two registers, or a register indirect, possibly with an
3293132718Skan   auto-increment.  For DFmode and DImode with a constant plus register,
329490075Sobrien   we must ensure that both words are addressable or PowerPC64 with offset
329590075Sobrien   word aligned.
329690075Sobrien
329790075Sobrien   For modes spanning multiple registers (DFmode in 32-bit GPRs,
329890075Sobrien   32-bit DImode, TImode), indexed addressing cannot be used because
329990075Sobrien   adjacent memory cells are accessed by adding word-sized offsets
330090075Sobrien   during assembly output.  */
330190075Sobrienint
3302132718Skanrs6000_legitimate_address (enum machine_mode mode, rtx x, int reg_ok_strict)
330390075Sobrien{
3304132718Skan  if (RS6000_SYMBOL_REF_TLS_P (x))
3305132718Skan    return 0;
3306132718Skan  if (legitimate_indirect_address_p (x, reg_ok_strict))
330790075Sobrien    return 1;
330890075Sobrien  if ((GET_CODE (x) == PRE_INC || GET_CODE (x) == PRE_DEC)
3309107590Sobrien      && !ALTIVEC_VECTOR_MODE (mode)
3310117395Skan      && !SPE_VECTOR_MODE (mode)
331190075Sobrien      && TARGET_UPDATE
3312132718Skan      && legitimate_indirect_address_p (XEXP (x, 0), reg_ok_strict))
331390075Sobrien    return 1;
3314132718Skan  if (legitimate_small_data_p (mode, x))
331590075Sobrien    return 1;
3316132718Skan  if (legitimate_constant_pool_address_p (x))
331790075Sobrien    return 1;
331890075Sobrien  /* If not REG_OK_STRICT (before reload) let pass any stack offset.  */
331990075Sobrien  if (! reg_ok_strict
332090075Sobrien      && GET_CODE (x) == PLUS
332190075Sobrien      && GET_CODE (XEXP (x, 0)) == REG
3322132718Skan      && (XEXP (x, 0) == virtual_stack_vars_rtx
3323132718Skan	  || XEXP (x, 0) == arg_pointer_rtx)
332490075Sobrien      && GET_CODE (XEXP (x, 1)) == CONST_INT)
332590075Sobrien    return 1;
3326132718Skan  if (legitimate_offset_address_p (mode, x, reg_ok_strict))
332790075Sobrien    return 1;
332890075Sobrien  if (mode != TImode
3329117395Skan      && ((TARGET_HARD_FLOAT && TARGET_FPRS)
3330117395Skan	  || TARGET_POWERPC64
3331117395Skan	  || (mode != DFmode && mode != TFmode))
333290075Sobrien      && (TARGET_POWERPC64 || mode != DImode)
3333132718Skan      && legitimate_indexed_address_p (x, reg_ok_strict))
333490075Sobrien    return 1;
3335132718Skan  if (legitimate_lo_sum_address_p (mode, x, reg_ok_strict))
333690075Sobrien    return 1;
333790075Sobrien  return 0;
333890075Sobrien}
3339132718Skan
3340132718Skan/* Go to LABEL if ADDR (a legitimate address expression)
3341132718Skan   has an effect that depends on the machine mode it is used for.
3342132718Skan
3343132718Skan   On the RS/6000 this is true of all integral offsets (since AltiVec
3344132718Skan   modes don't allow them) or is a pre-increment or decrement.
3345132718Skan
3346132718Skan   ??? Except that due to conceptual problems in offsettable_address_p
3347132718Skan   we can't really report the problems of integral offsets.  So leave
3348132718Skan   this assuming that the adjustable offset must be valid for the
3349132718Skan   sub-words of a TFmode operand, which is what we had before.  */
3350132718Skan
3351132718Skanbool
3352132718Skanrs6000_mode_dependent_address (rtx addr)
3353132718Skan{
3354132718Skan  switch (GET_CODE (addr))
3355132718Skan    {
3356132718Skan    case PLUS:
3357132718Skan      if (GET_CODE (XEXP (addr, 1)) == CONST_INT)
3358132718Skan	{
3359132718Skan	  unsigned HOST_WIDE_INT val = INTVAL (XEXP (addr, 1));
3360132718Skan	  return val + 12 + 0x8000 >= 0x10000;
3361132718Skan	}
3362132718Skan      break;
3363132718Skan
3364132718Skan    case LO_SUM:
3365132718Skan      return true;
3366132718Skan
3367132718Skan    case PRE_INC:
3368132718Skan    case PRE_DEC:
3369132718Skan      return TARGET_UPDATE;
3370132718Skan
3371132718Skan    default:
3372132718Skan      break;
3373132718Skan    }
3374132718Skan
3375132718Skan  return false;
3376132718Skan}
337790075Sobrien
337890075Sobrien/* Try to output insns to set TARGET equal to the constant C if it can
337990075Sobrien   be done in less than N insns.  Do all computations in MODE.
338090075Sobrien   Returns the place where the output has been placed if it can be
338190075Sobrien   done and the insns have been emitted.  If it would take more than N
338290075Sobrien   insns, zero is returned and no insns and emitted.  */
338390075Sobrien
338490075Sobrienrtx
3385132718Skanrs6000_emit_set_const (rtx dest, enum machine_mode mode,
3386132718Skan		       rtx source, int n ATTRIBUTE_UNUSED)
338790075Sobrien{
3388117395Skan  rtx result, insn, set;
338990075Sobrien  HOST_WIDE_INT c0, c1;
339090075Sobrien
3391117395Skan  if (mode == QImode || mode == HImode)
339290075Sobrien    {
339390075Sobrien      if (dest == NULL)
339490075Sobrien        dest = gen_reg_rtx (mode);
339590075Sobrien      emit_insn (gen_rtx_SET (VOIDmode, dest, source));
339690075Sobrien      return dest;
339790075Sobrien    }
3398117395Skan  else if (mode == SImode)
3399117395Skan    {
3400117395Skan      result = no_new_pseudos ? dest : gen_reg_rtx (SImode);
340190075Sobrien
3402117395Skan      emit_insn (gen_rtx_SET (VOIDmode, result,
3403117395Skan			      GEN_INT (INTVAL (source)
3404117395Skan				       & (~ (HOST_WIDE_INT) 0xffff))));
3405117395Skan      emit_insn (gen_rtx_SET (VOIDmode, dest,
3406117395Skan			      gen_rtx_IOR (SImode, result,
3407117395Skan					   GEN_INT (INTVAL (source) & 0xffff))));
3408117395Skan      result = dest;
340990075Sobrien    }
3410117395Skan  else if (mode == DImode)
341190075Sobrien    {
3412117395Skan      if (GET_CODE (source) == CONST_INT)
3413117395Skan	{
3414117395Skan	  c0 = INTVAL (source);
3415117395Skan	  c1 = -(c0 < 0);
3416117395Skan	}
3417117395Skan      else if (GET_CODE (source) == CONST_DOUBLE)
3418117395Skan	{
341990075Sobrien#if HOST_BITS_PER_WIDE_INT >= 64
3420117395Skan	  c0 = CONST_DOUBLE_LOW (source);
3421117395Skan	  c1 = -(c0 < 0);
342290075Sobrien#else
3423117395Skan	  c0 = CONST_DOUBLE_LOW (source);
3424117395Skan	  c1 = CONST_DOUBLE_HIGH (source);
342590075Sobrien#endif
3426117395Skan	}
3427117395Skan      else
3428117395Skan	abort ();
3429117395Skan
3430117395Skan      result = rs6000_emit_set_long_const (dest, c0, c1);
343190075Sobrien    }
343290075Sobrien  else
343390075Sobrien    abort ();
343490075Sobrien
3435117395Skan  insn = get_last_insn ();
3436117395Skan  set = single_set (insn);
3437117395Skan  if (! CONSTANT_P (SET_SRC (set)))
3438117395Skan    set_unique_reg_note (insn, REG_EQUAL, source);
3439117395Skan
3440117395Skan  return result;
344190075Sobrien}
344290075Sobrien
344390075Sobrien/* Having failed to find a 3 insn sequence in rs6000_emit_set_const,
344490075Sobrien   fall back to a straight forward decomposition.  We do this to avoid
344590075Sobrien   exponential run times encountered when looking for longer sequences
344690075Sobrien   with rs6000_emit_set_const.  */
344790075Sobrienstatic rtx
3448132718Skanrs6000_emit_set_long_const (rtx dest, HOST_WIDE_INT c1, HOST_WIDE_INT c2)
344990075Sobrien{
345090075Sobrien  if (!TARGET_POWERPC64)
345190075Sobrien    {
345290075Sobrien      rtx operand1, operand2;
345390075Sobrien
345490075Sobrien      operand1 = operand_subword_force (dest, WORDS_BIG_ENDIAN == 0,
345590075Sobrien					DImode);
345690075Sobrien      operand2 = operand_subword_force (dest, WORDS_BIG_ENDIAN != 0,
345790075Sobrien					DImode);
345890075Sobrien      emit_move_insn (operand1, GEN_INT (c1));
345990075Sobrien      emit_move_insn (operand2, GEN_INT (c2));
346090075Sobrien    }
346190075Sobrien  else
346290075Sobrien    {
346390075Sobrien      HOST_WIDE_INT ud1, ud2, ud3, ud4;
346490075Sobrien
346590075Sobrien      ud1 = c1 & 0xffff;
346690075Sobrien      ud2 = (c1 & 0xffff0000) >> 16;
346790075Sobrien#if HOST_BITS_PER_WIDE_INT >= 64
346890075Sobrien      c2 = c1 >> 32;
346990075Sobrien#endif
347090075Sobrien      ud3 = c2 & 0xffff;
347190075Sobrien      ud4 = (c2 & 0xffff0000) >> 16;
347290075Sobrien
347390075Sobrien      if ((ud4 == 0xffff && ud3 == 0xffff && ud2 == 0xffff && (ud1 & 0x8000))
347490075Sobrien	  || (ud4 == 0 && ud3 == 0 && ud2 == 0 && ! (ud1 & 0x8000)))
347590075Sobrien	{
347690075Sobrien	  if (ud1 & 0x8000)
3477132718Skan	    emit_move_insn (dest, GEN_INT (((ud1 ^ 0x8000) -  0x8000)));
347890075Sobrien	  else
347990075Sobrien	    emit_move_insn (dest, GEN_INT (ud1));
348090075Sobrien	}
348190075Sobrien
348290075Sobrien      else if ((ud4 == 0xffff && ud3 == 0xffff && (ud2 & 0x8000))
348390075Sobrien	       || (ud4 == 0 && ud3 == 0 && ! (ud2 & 0x8000)))
348490075Sobrien	{
348590075Sobrien	  if (ud2 & 0x8000)
348690075Sobrien	    emit_move_insn (dest, GEN_INT (((ud2 << 16) ^ 0x80000000)
348790075Sobrien					   - 0x80000000));
348890075Sobrien	  else
348990075Sobrien	    emit_move_insn (dest, GEN_INT (ud2 << 16));
349090075Sobrien	  if (ud1 != 0)
349190075Sobrien	    emit_move_insn (dest, gen_rtx_IOR (DImode, dest, GEN_INT (ud1)));
349290075Sobrien	}
349390075Sobrien      else if ((ud4 == 0xffff && (ud3 & 0x8000))
349490075Sobrien	       || (ud4 == 0 && ! (ud3 & 0x8000)))
349590075Sobrien	{
349690075Sobrien	  if (ud3 & 0x8000)
349790075Sobrien	    emit_move_insn (dest, GEN_INT (((ud3 << 16) ^ 0x80000000)
349890075Sobrien					   - 0x80000000));
349990075Sobrien	  else
350090075Sobrien	    emit_move_insn (dest, GEN_INT (ud3 << 16));
350190075Sobrien
350290075Sobrien	  if (ud2 != 0)
350390075Sobrien	    emit_move_insn (dest, gen_rtx_IOR (DImode, dest, GEN_INT (ud2)));
350490075Sobrien	  emit_move_insn (dest, gen_rtx_ASHIFT (DImode, dest, GEN_INT (16)));
350590075Sobrien	  if (ud1 != 0)
350690075Sobrien	    emit_move_insn (dest, gen_rtx_IOR (DImode, dest, GEN_INT (ud1)));
350790075Sobrien	}
350890075Sobrien      else
350990075Sobrien	{
351090075Sobrien	  if (ud4 & 0x8000)
351190075Sobrien	    emit_move_insn (dest, GEN_INT (((ud4 << 16) ^ 0x80000000)
351290075Sobrien					   - 0x80000000));
351390075Sobrien	  else
351490075Sobrien	    emit_move_insn (dest, GEN_INT (ud4 << 16));
351590075Sobrien
351690075Sobrien	  if (ud3 != 0)
351790075Sobrien	    emit_move_insn (dest, gen_rtx_IOR (DImode, dest, GEN_INT (ud3)));
351890075Sobrien
351990075Sobrien	  emit_move_insn (dest, gen_rtx_ASHIFT (DImode, dest, GEN_INT (32)));
352090075Sobrien	  if (ud2 != 0)
352190075Sobrien	    emit_move_insn (dest, gen_rtx_IOR (DImode, dest,
352290075Sobrien					       GEN_INT (ud2 << 16)));
352390075Sobrien	  if (ud1 != 0)
352490075Sobrien	    emit_move_insn (dest, gen_rtx_IOR (DImode, dest, GEN_INT (ud1)));
352590075Sobrien	}
352690075Sobrien    }
352790075Sobrien  return dest;
352890075Sobrien}
352990075Sobrien
353090075Sobrien/* Emit a move from SOURCE to DEST in mode MODE.  */
353190075Sobrienvoid
3532132718Skanrs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
353390075Sobrien{
353490075Sobrien  rtx operands[2];
353590075Sobrien  operands[0] = dest;
353690075Sobrien  operands[1] = source;
353790075Sobrien
353890075Sobrien  /* Sanity checks.  Check that we get CONST_DOUBLE only when we should.  */
353990075Sobrien  if (GET_CODE (operands[1]) == CONST_DOUBLE
354090075Sobrien      && ! FLOAT_MODE_P (mode)
354190075Sobrien      && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
354290075Sobrien    {
354390075Sobrien      /* FIXME.  This should never happen.  */
354490075Sobrien      /* Since it seems that it does, do the safe thing and convert
354590075Sobrien	 to a CONST_INT.  */
3546117395Skan      operands[1] = gen_int_mode (CONST_DOUBLE_LOW (operands[1]), mode);
354790075Sobrien    }
354890075Sobrien  if (GET_CODE (operands[1]) == CONST_DOUBLE
354990075Sobrien      && ! FLOAT_MODE_P (mode)
355090075Sobrien      && ((CONST_DOUBLE_HIGH (operands[1]) == 0
355190075Sobrien	   && CONST_DOUBLE_LOW (operands[1]) >= 0)
355290075Sobrien	  || (CONST_DOUBLE_HIGH (operands[1]) == -1
355390075Sobrien	      && CONST_DOUBLE_LOW (operands[1]) < 0)))
355490075Sobrien    abort ();
355590075Sobrien
355690075Sobrien  /* Check if GCC is setting up a block move that will end up using FP
355790075Sobrien     registers as temporaries.  We must make sure this is acceptable.  */
355890075Sobrien  if (GET_CODE (operands[0]) == MEM
355990075Sobrien      && GET_CODE (operands[1]) == MEM
356090075Sobrien      && mode == DImode
356190075Sobrien      && (SLOW_UNALIGNED_ACCESS (DImode, MEM_ALIGN (operands[0]))
356290075Sobrien	  || SLOW_UNALIGNED_ACCESS (DImode, MEM_ALIGN (operands[1])))
356390075Sobrien      && ! (SLOW_UNALIGNED_ACCESS (SImode, (MEM_ALIGN (operands[0]) > 32
356490075Sobrien					    ? 32 : MEM_ALIGN (operands[0])))
356590075Sobrien	    || SLOW_UNALIGNED_ACCESS (SImode, (MEM_ALIGN (operands[1]) > 32
356690075Sobrien					       ? 32
356790075Sobrien					       : MEM_ALIGN (operands[1]))))
356890075Sobrien      && ! MEM_VOLATILE_P (operands [0])
356990075Sobrien      && ! MEM_VOLATILE_P (operands [1]))
357090075Sobrien    {
357190075Sobrien      emit_move_insn (adjust_address (operands[0], SImode, 0),
357290075Sobrien		      adjust_address (operands[1], SImode, 0));
357390075Sobrien      emit_move_insn (adjust_address (operands[0], SImode, 4),
357490075Sobrien		      adjust_address (operands[1], SImode, 4));
357590075Sobrien      return;
357690075Sobrien    }
357790075Sobrien
3578117395Skan  if (!no_new_pseudos)
3579117395Skan    {
3580117395Skan      if (GET_CODE (operands[1]) == MEM && optimize > 0
3581117395Skan	  && (mode == QImode || mode == HImode || mode == SImode)
3582117395Skan	  && GET_MODE_SIZE (mode) < GET_MODE_SIZE (word_mode))
3583117395Skan	{
3584117395Skan	  rtx reg = gen_reg_rtx (word_mode);
358590075Sobrien
3586117395Skan	  emit_insn (gen_rtx_SET (word_mode, reg,
3587117395Skan				  gen_rtx_ZERO_EXTEND (word_mode,
3588117395Skan						       operands[1])));
3589117395Skan	  operands[1] = gen_lowpart (mode, reg);
3590117395Skan	}
3591117395Skan      if (GET_CODE (operands[0]) != REG)
3592117395Skan	operands[1] = force_reg (mode, operands[1]);
3593117395Skan    }
3594117395Skan
3595117395Skan  if (mode == SFmode && ! TARGET_POWERPC
3596117395Skan      && TARGET_HARD_FLOAT && TARGET_FPRS
359790075Sobrien      && GET_CODE (operands[0]) == MEM)
359890075Sobrien    {
359990075Sobrien      int regnum;
360090075Sobrien
360190075Sobrien      if (reload_in_progress || reload_completed)
360290075Sobrien	regnum = true_regnum (operands[1]);
360390075Sobrien      else if (GET_CODE (operands[1]) == REG)
360490075Sobrien	regnum = REGNO (operands[1]);
360590075Sobrien      else
360690075Sobrien	regnum = -1;
360790075Sobrien
360890075Sobrien      /* If operands[1] is a register, on POWER it may have
360990075Sobrien	 double-precision data in it, so truncate it to single
361090075Sobrien	 precision.  */
361190075Sobrien      if (FP_REGNO_P (regnum) || regnum >= FIRST_PSEUDO_REGISTER)
361290075Sobrien	{
361390075Sobrien	  rtx newreg;
361490075Sobrien	  newreg = (no_new_pseudos ? operands[1] : gen_reg_rtx (mode));
361590075Sobrien	  emit_insn (gen_aux_truncdfsf2 (newreg, operands[1]));
361690075Sobrien	  operands[1] = newreg;
361790075Sobrien	}
361890075Sobrien    }
361990075Sobrien
3620132718Skan  /* Recognize the case where operand[1] is a reference to thread-local
3621132718Skan     data and load its address to a register.  */
3622132718Skan  if (GET_CODE (operands[1]) == SYMBOL_REF)
3623132718Skan    {
3624132718Skan      enum tls_model model = SYMBOL_REF_TLS_MODEL (operands[1]);
3625132718Skan      if (model != 0)
3626132718Skan	operands[1] = rs6000_legitimize_tls_address (operands[1], model);
3627132718Skan    }
3628132718Skan
3629117395Skan  /* Handle the case where reload calls us with an invalid address.  */
3630117395Skan  if (reload_in_progress && mode == Pmode
363196263Sobrien      && (! general_operand (operands[1], mode)
3632117395Skan	  || ! nonimmediate_operand (operands[0], mode)))
3633117395Skan    goto emit_set;
3634117395Skan
3635117395Skan  /* Handle the case of CONSTANT_P_RTX.  */
3636117395Skan  if (GET_CODE (operands[1]) == CONSTANT_P_RTX)
3637117395Skan    goto emit_set;
3638132718Skan
3639132718Skan  /* 128-bit constant floating-point values on Darwin should really be
3640132718Skan     loaded as two parts.  */
3641132718Skan  if ((DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_DARWIN)
3642132718Skan      && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128
3643132718Skan      && mode == TFmode && GET_CODE (operands[1]) == CONST_DOUBLE)
3644132718Skan    {
3645132718Skan      /* DImode is used, not DFmode, because simplify_gen_subreg doesn't
3646132718Skan	 know how to get a DFmode SUBREG of a TFmode.  */
3647132718Skan      rs6000_emit_move (simplify_gen_subreg (DImode, operands[0], mode, 0),
3648132718Skan			simplify_gen_subreg (DImode, operands[1], mode, 0),
3649132718Skan			DImode);
3650132718Skan      rs6000_emit_move (simplify_gen_subreg (DImode, operands[0], mode,
3651132718Skan					     GET_MODE_SIZE (DImode)),
3652132718Skan			simplify_gen_subreg (DImode, operands[1], mode,
3653132718Skan					     GET_MODE_SIZE (DImode)),
3654132718Skan			DImode);
3655132718Skan      return;
3656132718Skan    }
3657132718Skan
365890075Sobrien  /* FIXME:  In the long term, this switch statement should go away
365990075Sobrien     and be replaced by a sequence of tests based on things like
366090075Sobrien     mode == Pmode.  */
366190075Sobrien  switch (mode)
366290075Sobrien    {
366390075Sobrien    case HImode:
366490075Sobrien    case QImode:
366590075Sobrien      if (CONSTANT_P (operands[1])
366690075Sobrien	  && GET_CODE (operands[1]) != CONST_INT)
366790075Sobrien	operands[1] = force_const_mem (mode, operands[1]);
366890075Sobrien      break;
366990075Sobrien
367090075Sobrien    case TFmode:
367190075Sobrien    case DFmode:
367290075Sobrien    case SFmode:
367390075Sobrien      if (CONSTANT_P (operands[1])
367490075Sobrien	  && ! easy_fp_constant (operands[1], mode))
367590075Sobrien	operands[1] = force_const_mem (mode, operands[1]);
367690075Sobrien      break;
367790075Sobrien
367890075Sobrien    case V16QImode:
367990075Sobrien    case V8HImode:
368090075Sobrien    case V4SFmode:
368190075Sobrien    case V4SImode:
3682117395Skan    case V4HImode:
3683117395Skan    case V2SFmode:
3684117395Skan    case V2SImode:
3685117395Skan    case V1DImode:
368696263Sobrien      if (CONSTANT_P (operands[1])
3687132718Skan	  && !easy_vector_constant (operands[1], mode))
368890075Sobrien	operands[1] = force_const_mem (mode, operands[1]);
368990075Sobrien      break;
369090075Sobrien
369190075Sobrien    case SImode:
369290075Sobrien    case DImode:
369390075Sobrien      /* Use default pattern for address of ELF small data */
369490075Sobrien      if (TARGET_ELF
369590075Sobrien	  && mode == Pmode
369690075Sobrien	  && DEFAULT_ABI == ABI_V4
369790075Sobrien	  && (GET_CODE (operands[1]) == SYMBOL_REF
369890075Sobrien	      || GET_CODE (operands[1]) == CONST)
369990075Sobrien	  && small_data_operand (operands[1], mode))
370090075Sobrien	{
370190075Sobrien	  emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
370290075Sobrien	  return;
370390075Sobrien	}
370490075Sobrien
370590075Sobrien      if (DEFAULT_ABI == ABI_V4
370690075Sobrien	  && mode == Pmode && mode == SImode
370790075Sobrien	  && flag_pic == 1 && got_operand (operands[1], mode))
370890075Sobrien	{
370990075Sobrien	  emit_insn (gen_movsi_got (operands[0], operands[1]));
371090075Sobrien	  return;
371190075Sobrien	}
371290075Sobrien
371390075Sobrien      if ((TARGET_ELF || DEFAULT_ABI == ABI_DARWIN)
3714132718Skan	  && TARGET_NO_TOC
3715132718Skan	  && ! flag_pic
371690075Sobrien	  && mode == Pmode
371790075Sobrien	  && CONSTANT_P (operands[1])
371890075Sobrien	  && GET_CODE (operands[1]) != HIGH
371990075Sobrien	  && GET_CODE (operands[1]) != CONST_INT)
372090075Sobrien	{
372190075Sobrien	  rtx target = (no_new_pseudos ? operands[0] : gen_reg_rtx (mode));
372290075Sobrien
372390075Sobrien	  /* If this is a function address on -mcall-aixdesc,
372490075Sobrien	     convert it to the address of the descriptor.  */
372590075Sobrien	  if (DEFAULT_ABI == ABI_AIX
372690075Sobrien	      && GET_CODE (operands[1]) == SYMBOL_REF
372790075Sobrien	      && XSTR (operands[1], 0)[0] == '.')
372890075Sobrien	    {
372990075Sobrien	      const char *name = XSTR (operands[1], 0);
373090075Sobrien	      rtx new_ref;
373190075Sobrien	      while (*name == '.')
373290075Sobrien		name++;
373390075Sobrien	      new_ref = gen_rtx_SYMBOL_REF (Pmode, name);
373490075Sobrien	      CONSTANT_POOL_ADDRESS_P (new_ref)
373590075Sobrien		= CONSTANT_POOL_ADDRESS_P (operands[1]);
3736132718Skan	      SYMBOL_REF_FLAGS (new_ref) = SYMBOL_REF_FLAGS (operands[1]);
373790075Sobrien	      SYMBOL_REF_USED (new_ref) = SYMBOL_REF_USED (operands[1]);
3738132718Skan	      SYMBOL_REF_DECL (new_ref) = SYMBOL_REF_DECL (operands[1]);
373990075Sobrien	      operands[1] = new_ref;
374090075Sobrien	    }
374190075Sobrien
374290075Sobrien	  if (DEFAULT_ABI == ABI_DARWIN)
374390075Sobrien	    {
3744132718Skan#if TARGET_MACHO
3745132718Skan	      if (MACHO_DYNAMIC_NO_PIC_P)
3746132718Skan		{
3747132718Skan		  /* Take care of any required data indirection.  */
3748132718Skan		  operands[1] = rs6000_machopic_legitimize_pic_address (
3749132718Skan				  operands[1], mode, operands[0]);
3750132718Skan		  if (operands[0] != operands[1])
3751132718Skan		    emit_insn (gen_rtx_SET (VOIDmode,
3752132718Skan				            operands[0], operands[1]));
3753132718Skan		  return;
3754132718Skan		}
3755132718Skan#endif
375690075Sobrien	      emit_insn (gen_macho_high (target, operands[1]));
375790075Sobrien	      emit_insn (gen_macho_low (operands[0], target, operands[1]));
375890075Sobrien	      return;
375990075Sobrien	    }
376090075Sobrien
376190075Sobrien	  emit_insn (gen_elf_high (target, operands[1]));
376290075Sobrien	  emit_insn (gen_elf_low (operands[0], target, operands[1]));
376390075Sobrien	  return;
376490075Sobrien	}
376590075Sobrien
376690075Sobrien      /* If this is a SYMBOL_REF that refers to a constant pool entry,
376790075Sobrien	 and we have put it in the TOC, we just need to make a TOC-relative
376890075Sobrien	 reference to it.  */
376990075Sobrien      if (TARGET_TOC
377090075Sobrien	  && GET_CODE (operands[1]) == SYMBOL_REF
3771132718Skan	  && constant_pool_expr_p (operands[1])
377290075Sobrien	  && ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (operands[1]),
377390075Sobrien					      get_pool_mode (operands[1])))
377490075Sobrien	{
377590075Sobrien	  operands[1] = create_TOC_reference (operands[1]);
377690075Sobrien	}
377790075Sobrien      else if (mode == Pmode
377890075Sobrien	       && CONSTANT_P (operands[1])
377990075Sobrien	       && ((GET_CODE (operands[1]) != CONST_INT
378090075Sobrien		    && ! easy_fp_constant (operands[1], mode))
378190075Sobrien		   || (GET_CODE (operands[1]) == CONST_INT
378290075Sobrien		       && num_insns_constant (operands[1], mode) > 2)
378390075Sobrien		   || (GET_CODE (operands[0]) == REG
378490075Sobrien		       && FP_REGNO_P (REGNO (operands[0]))))
378590075Sobrien	       && GET_CODE (operands[1]) != HIGH
3786132718Skan	       && ! legitimate_constant_pool_address_p (operands[1])
3787132718Skan	       && ! toc_relative_expr_p (operands[1]))
378890075Sobrien	{
378990075Sobrien	  /* Emit a USE operation so that the constant isn't deleted if
379090075Sobrien	     expensive optimizations are turned on because nobody
379190075Sobrien	     references it.  This should only be done for operands that
379290075Sobrien	     contain SYMBOL_REFs with CONSTANT_POOL_ADDRESS_P set.
379390075Sobrien	     This should not be done for operands that contain LABEL_REFs.
379490075Sobrien	     For now, we just handle the obvious case.  */
379590075Sobrien	  if (GET_CODE (operands[1]) != LABEL_REF)
379690075Sobrien	    emit_insn (gen_rtx_USE (VOIDmode, operands[1]));
379790075Sobrien
379890075Sobrien#if TARGET_MACHO
379990075Sobrien	  /* Darwin uses a special PIC legitimizer.  */
3800132718Skan	  if (DEFAULT_ABI == ABI_DARWIN && MACHOPIC_INDIRECT)
380190075Sobrien	    {
380290075Sobrien	      operands[1] =
380390075Sobrien		rs6000_machopic_legitimize_pic_address (operands[1], mode,
380490075Sobrien							operands[0]);
380590075Sobrien	      if (operands[0] != operands[1])
380690075Sobrien		emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
380790075Sobrien	      return;
380890075Sobrien	    }
380990075Sobrien#endif
381090075Sobrien
381190075Sobrien	  /* If we are to limit the number of things we put in the TOC and
381290075Sobrien	     this is a symbol plus a constant we can add in one insn,
381390075Sobrien	     just put the symbol in the TOC and add the constant.  Don't do
381490075Sobrien	     this if reload is in progress.  */
381590075Sobrien	  if (GET_CODE (operands[1]) == CONST
381690075Sobrien	      && TARGET_NO_SUM_IN_TOC && ! reload_in_progress
381790075Sobrien	      && GET_CODE (XEXP (operands[1], 0)) == PLUS
381890075Sobrien	      && add_operand (XEXP (XEXP (operands[1], 0), 1), mode)
381990075Sobrien	      && (GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == LABEL_REF
382090075Sobrien		  || GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == SYMBOL_REF)
382190075Sobrien	      && ! side_effects_p (operands[0]))
382290075Sobrien	    {
382390075Sobrien	      rtx sym =
382490075Sobrien		force_const_mem (mode, XEXP (XEXP (operands[1], 0), 0));
382590075Sobrien	      rtx other = XEXP (XEXP (operands[1], 0), 1);
382690075Sobrien
382790075Sobrien	      sym = force_reg (mode, sym);
382890075Sobrien	      if (mode == SImode)
382990075Sobrien		emit_insn (gen_addsi3 (operands[0], sym, other));
383090075Sobrien	      else
383190075Sobrien		emit_insn (gen_adddi3 (operands[0], sym, other));
383290075Sobrien	      return;
383390075Sobrien	    }
383490075Sobrien
383590075Sobrien	  operands[1] = force_const_mem (mode, operands[1]);
383690075Sobrien
383790075Sobrien	  if (TARGET_TOC
3838132718Skan	      && constant_pool_expr_p (XEXP (operands[1], 0))
383990075Sobrien	      && ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (
384090075Sobrien			get_pool_constant (XEXP (operands[1], 0)),
384190075Sobrien			get_pool_mode (XEXP (operands[1], 0))))
384290075Sobrien	    {
384390075Sobrien	      operands[1]
384490075Sobrien		= gen_rtx_MEM (mode,
384590075Sobrien			       create_TOC_reference (XEXP (operands[1], 0)));
384690075Sobrien	      set_mem_alias_set (operands[1], get_TOC_alias_set ());
384790075Sobrien	      RTX_UNCHANGING_P (operands[1]) = 1;
384890075Sobrien	    }
384990075Sobrien	}
385090075Sobrien      break;
385190075Sobrien
385290075Sobrien    case TImode:
385390075Sobrien      if (GET_CODE (operands[0]) == MEM
385490075Sobrien	  && GET_CODE (XEXP (operands[0], 0)) != REG
385590075Sobrien	  && ! reload_in_progress)
385690075Sobrien	operands[0]
385790075Sobrien	  = replace_equiv_address (operands[0],
385890075Sobrien				   copy_addr_to_reg (XEXP (operands[0], 0)));
385990075Sobrien
386090075Sobrien      if (GET_CODE (operands[1]) == MEM
386190075Sobrien	  && GET_CODE (XEXP (operands[1], 0)) != REG
386290075Sobrien	  && ! reload_in_progress)
386390075Sobrien	operands[1]
386490075Sobrien	  = replace_equiv_address (operands[1],
386590075Sobrien				   copy_addr_to_reg (XEXP (operands[1], 0)));
3866117395Skan      if (TARGET_POWER)
3867132718Skan	{
3868117395Skan	  emit_insn (gen_rtx_PARALLEL (VOIDmode,
3869117395Skan		       gen_rtvec (2,
3870117395Skan				  gen_rtx_SET (VOIDmode,
3871117395Skan					       operands[0], operands[1]),
3872117395Skan				  gen_rtx_CLOBBER (VOIDmode,
3873117395Skan						   gen_rtx_SCRATCH (SImode)))));
3874117395Skan	  return;
3875117395Skan	}
387690075Sobrien      break;
387790075Sobrien
387890075Sobrien    default:
387990075Sobrien      abort ();
388090075Sobrien    }
388190075Sobrien
388290075Sobrien  /* Above, we may have called force_const_mem which may have returned
388390075Sobrien     an invalid address.  If we can, fix this up; otherwise, reload will
388490075Sobrien     have to deal with it.  */
3885117395Skan  if (GET_CODE (operands[1]) == MEM && ! reload_in_progress)
3886117395Skan    operands[1] = validize_mem (operands[1]);
388790075Sobrien
3888117395Skan emit_set:
388990075Sobrien  emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
389090075Sobrien}
389190075Sobrien
3892132718Skan/* Nonzero if we can use a floating-point register to pass this arg.  */
3893132718Skan#define USE_FP_FOR_ARG_P(CUM,MODE,TYPE)		\
3894132718Skan  (GET_MODE_CLASS (MODE) == MODE_FLOAT		\
3895132718Skan   && (CUM)->fregno <= FP_ARG_MAX_REG		\
3896132718Skan   && TARGET_HARD_FLOAT && TARGET_FPRS)
3897132718Skan
3898132718Skan/* Nonzero if we can use an AltiVec register to pass this arg.  */
3899132718Skan#define USE_ALTIVEC_FOR_ARG_P(CUM,MODE,TYPE,NAMED)	\
3900132718Skan  (ALTIVEC_VECTOR_MODE (MODE)				\
3901132718Skan   && (CUM)->vregno <= ALTIVEC_ARG_MAX_REG		\
3902132718Skan   && TARGET_ALTIVEC_ABI				\
3903132718Skan   && (NAMED))
3904132718Skan
3905132718Skan/* Return a nonzero value to say to return the function value in
3906132718Skan   memory, just as large structures are always returned.  TYPE will be
3907132718Skan   the data type of the value, and FNTYPE will be the type of the
3908132718Skan   function doing the returning, or @code{NULL} for libcalls.
3909132718Skan
3910132718Skan   The AIX ABI for the RS/6000 specifies that all structures are
3911132718Skan   returned in memory.  The Darwin ABI does the same.  The SVR4 ABI
3912132718Skan   specifies that structures <= 8 bytes are returned in r3/r4, but a
3913132718Skan   draft put them in memory, and GCC used to implement the draft
3914132718Skan   instead of the final standard.  Therefore, TARGET_AIX_STRUCT_RET
3915132718Skan   controls this instead of DEFAULT_ABI; V.4 targets needing backward
3916132718Skan   compatibility can change DRAFT_V4_STRUCT_RET to override the
3917132718Skan   default, and -m switches get the final word.  See
3918132718Skan   rs6000_override_options for more details.
3919132718Skan
3920132718Skan   The PPC32 SVR4 ABI uses IEEE double extended for long double, if 128-bit
3921132718Skan   long double support is enabled.  These values are returned in memory.
3922132718Skan
3923132718Skan   int_size_in_bytes returns -1 for variable size objects, which go in
3924132718Skan   memory always.  The cast to unsigned makes -1 > 8.  */
3925132718Skan
3926132718Skanstatic bool
3927132718Skanrs6000_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
3928132718Skan{
3929132718Skan  if (AGGREGATE_TYPE_P (type)
3930132718Skan      && (TARGET_AIX_STRUCT_RET
3931132718Skan	  || (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 8))
3932132718Skan    return true;
3933132718Skan  if (DEFAULT_ABI == ABI_V4 && TYPE_MODE (type) == TFmode)
3934132718Skan    return true;
3935132718Skan  return false;
3936132718Skan}
3937132718Skan
393890075Sobrien/* Initialize a variable CUM of type CUMULATIVE_ARGS
393990075Sobrien   for a call to a function whose data type is FNTYPE.
394090075Sobrien   For a library call, FNTYPE is 0.
394190075Sobrien
394290075Sobrien   For incoming args we set the number of arguments in the prototype large
394390075Sobrien   so we never return a PARALLEL.  */
394490075Sobrien
394590075Sobrienvoid
3946132718Skaninit_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
3947132718Skan		      rtx libname ATTRIBUTE_UNUSED, int incoming,
3948132718Skan		      int libcall, int n_named_args)
394990075Sobrien{
395090075Sobrien  static CUMULATIVE_ARGS zero_cumulative;
395190075Sobrien
395290075Sobrien  *cum = zero_cumulative;
395390075Sobrien  cum->words = 0;
395490075Sobrien  cum->fregno = FP_ARG_MIN_REG;
395590075Sobrien  cum->vregno = ALTIVEC_ARG_MIN_REG;
395690075Sobrien  cum->prototype = (fntype && TYPE_ARG_TYPES (fntype));
3957117395Skan  cum->call_cookie = ((DEFAULT_ABI == ABI_V4 && libcall)
3958117395Skan		      ? CALL_LIBCALL : CALL_NORMAL);
395990075Sobrien  cum->sysv_gregno = GP_ARG_MIN_REG;
3960132718Skan  cum->stdarg = fntype
3961132718Skan    && (TYPE_ARG_TYPES (fntype) != 0
3962132718Skan	&& (TREE_VALUE (tree_last  (TYPE_ARG_TYPES (fntype)))
3963132718Skan	    != void_type_node));
396490075Sobrien
3965132718Skan  cum->nargs_prototype = 0;
3966132718Skan  if (incoming || cum->prototype)
3967132718Skan    cum->nargs_prototype = n_named_args;
396890075Sobrien
3969117395Skan  /* Check for a longcall attribute.  */
3970146895Skan  if ((!fntype && rs6000_default_long_calls)
3971146895Skan      || (fntype
3972146895Skan	  && lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype))
3973146895Skan	  && !lookup_attribute ("shortcall", TYPE_ATTRIBUTES (fntype))))
3974146895Skan    cum->call_cookie |= CALL_LONG;
397590075Sobrien
397690075Sobrien  if (TARGET_DEBUG_ARG)
397790075Sobrien    {
397890075Sobrien      fprintf (stderr, "\ninit_cumulative_args:");
397990075Sobrien      if (fntype)
398090075Sobrien	{
398190075Sobrien	  tree ret_type = TREE_TYPE (fntype);
398290075Sobrien	  fprintf (stderr, " ret code = %s,",
398390075Sobrien		   tree_code_name[ (int)TREE_CODE (ret_type) ]);
398490075Sobrien	}
398590075Sobrien
398690075Sobrien      if (cum->call_cookie & CALL_LONG)
398790075Sobrien	fprintf (stderr, " longcall,");
398890075Sobrien
398990075Sobrien      fprintf (stderr, " proto = %d, nargs = %d\n",
399090075Sobrien	       cum->prototype, cum->nargs_prototype);
399190075Sobrien    }
3992132718Skan
3993132718Skan    if (fntype
3994132718Skan	&& !TARGET_ALTIVEC
3995132718Skan	&& TARGET_ALTIVEC_ABI
3996132718Skan        && ALTIVEC_VECTOR_MODE (TYPE_MODE (TREE_TYPE (fntype))))
3997132718Skan      {
3998132718Skan	error ("Cannot return value in vector register because"
3999132718Skan	       " altivec instructions are disabled, use -maltivec"
4000132718Skan	       " to enable them.");
4001132718Skan      }
400290075Sobrien}
400390075Sobrien
400490075Sobrien/* If defined, a C expression which determines whether, and in which
400590075Sobrien   direction, to pad out an argument with extra space.  The value
400690075Sobrien   should be of type `enum direction': either `upward' to pad above
400790075Sobrien   the argument, `downward' to pad below, or `none' to inhibit
400890075Sobrien   padding.
400990075Sobrien
401090075Sobrien   For the AIX ABI structs are always stored left shifted in their
401190075Sobrien   argument slot.  */
401290075Sobrien
401390075Sobrienenum direction
4014132718Skanfunction_arg_padding (enum machine_mode mode, tree type)
401590075Sobrien{
4016132718Skan#ifndef AGGREGATE_PADDING_FIXED
4017132718Skan#define AGGREGATE_PADDING_FIXED 0
4018132718Skan#endif
4019132718Skan#ifndef AGGREGATES_PAD_UPWARD_ALWAYS
4020132718Skan#define AGGREGATES_PAD_UPWARD_ALWAYS 0
4021132718Skan#endif
402290075Sobrien
4023132718Skan  if (!AGGREGATE_PADDING_FIXED)
4024132718Skan    {
4025132718Skan      /* GCC used to pass structures of the same size as integer types as
4026132718Skan	 if they were in fact integers, ignoring FUNCTION_ARG_PADDING.
4027132718Skan	 ie. Structures of size 1 or 2 (or 4 when TARGET_64BIT) were
4028132718Skan	 passed padded downward, except that -mstrict-align further
4029132718Skan	 muddied the water in that multi-component structures of 2 and 4
4030132718Skan	 bytes in size were passed padded upward.
4031132718Skan
4032132718Skan	 The following arranges for best compatibility with previous
4033132718Skan	 versions of gcc, but removes the -mstrict-align dependency.  */
4034132718Skan      if (BYTES_BIG_ENDIAN)
4035132718Skan	{
4036132718Skan	  HOST_WIDE_INT size = 0;
4037132718Skan
4038132718Skan	  if (mode == BLKmode)
4039132718Skan	    {
4040132718Skan	      if (type && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST)
4041132718Skan		size = int_size_in_bytes (type);
4042132718Skan	    }
4043132718Skan	  else
4044132718Skan	    size = GET_MODE_SIZE (mode);
4045132718Skan
4046132718Skan	  if (size == 1 || size == 2 || size == 4)
4047132718Skan	    return downward;
4048132718Skan	}
4049132718Skan      return upward;
4050132718Skan    }
4051132718Skan
4052132718Skan  if (AGGREGATES_PAD_UPWARD_ALWAYS)
4053132718Skan    {
4054132718Skan      if (type != 0 && AGGREGATE_TYPE_P (type))
4055132718Skan	return upward;
4056132718Skan    }
4057132718Skan
4058132718Skan  /* Fall back to the default.  */
4059132718Skan  return DEFAULT_FUNCTION_ARG_PADDING (mode, type);
406090075Sobrien}
406190075Sobrien
406290075Sobrien/* If defined, a C expression that gives the alignment boundary, in bits,
406390075Sobrien   of an argument with the specified mode and type.  If it is not defined,
406490075Sobrien   PARM_BOUNDARY is used for all arguments.
406590075Sobrien
406690075Sobrien   V.4 wants long longs to be double word aligned.  */
406790075Sobrien
406890075Sobrienint
4069132718Skanfunction_arg_boundary (enum machine_mode mode, tree type ATTRIBUTE_UNUSED)
407090075Sobrien{
4071132718Skan  if (DEFAULT_ABI == ABI_V4 && GET_MODE_SIZE (mode) == 8)
407290075Sobrien    return 64;
4073132718Skan  else if (SPE_VECTOR_MODE (mode))
4074132718Skan    return 64;
4075132718Skan  else if (ALTIVEC_VECTOR_MODE (mode))
407690075Sobrien    return 128;
407790075Sobrien  else
407890075Sobrien    return PARM_BOUNDARY;
407990075Sobrien}
4080132718Skan
4081132718Skan/* Compute the size (in words) of a function argument.  */
4082132718Skan
4083132718Skanstatic unsigned long
4084132718Skanrs6000_arg_size (enum machine_mode mode, tree type)
4085132718Skan{
4086132718Skan  unsigned long size;
4087132718Skan
4088132718Skan  if (mode != BLKmode)
4089132718Skan    size = GET_MODE_SIZE (mode);
4090132718Skan  else
4091132718Skan    size = int_size_in_bytes (type);
4092132718Skan
4093132718Skan  if (TARGET_32BIT)
4094132718Skan    return (size + 3) >> 2;
4095132718Skan  else
4096132718Skan    return (size + 7) >> 3;
4097132718Skan}
409890075Sobrien
409990075Sobrien/* Update the data in CUM to advance over an argument
410090075Sobrien   of mode MODE and data type TYPE.
4101132718Skan   (TYPE is null for libcalls where that information may not be available.)
410290075Sobrien
4103132718Skan   Note that for args passed by reference, function_arg will be called
4104132718Skan   with MODE and TYPE set to that of the pointer to the arg, not the arg
4105132718Skan   itself.  */
4106132718Skan
410790075Sobrienvoid
4108132718Skanfunction_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
4109132718Skan		      tree type, int named)
411090075Sobrien{
411190075Sobrien  cum->nargs_prototype--;
411290075Sobrien
411390075Sobrien  if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
411490075Sobrien    {
4115132718Skan      bool stack = false;
4116132718Skan
4117132718Skan      if (USE_ALTIVEC_FOR_ARG_P (cum, mode, type, named))
4118132718Skan        {
4119132718Skan	  cum->vregno++;
4120132718Skan	  if (!TARGET_ALTIVEC)
4121132718Skan	    error ("Cannot pass argument in vector register because"
4122132718Skan		   " altivec instructions are disabled, use -maltivec"
4123132718Skan		   " to enable them.");
4124132718Skan
4125132718Skan	  /* PowerPC64 Linux and AIX allocate GPRs for a vector argument
4126132718Skan	     even if it is going to be passed in a vector register.
4127132718Skan	     Darwin does the same for variable-argument functions.  */
4128132718Skan	  if ((DEFAULT_ABI == ABI_AIX && TARGET_64BIT)
4129132718Skan	      || (cum->stdarg && DEFAULT_ABI != ABI_V4))
4130132718Skan	    stack = true;
4131132718Skan	}
413290075Sobrien      else
4133132718Skan	stack = true;
4134132718Skan
4135132718Skan      if (stack)
4136132718Skan        {
4137132718Skan	  int align;
4138132718Skan
4139132718Skan	  /* Vector parameters must be 16-byte aligned.  This places
4140132718Skan	     them at 2 mod 4 in terms of words in 32-bit mode, since
4141132718Skan	     the parameter save area starts at offset 24 from the
4142132718Skan	     stack.  In 64-bit mode, they just have to start on an
4143132718Skan	     even word, since the parameter save area is 16-byte
4144132718Skan	     aligned.  Space for GPRs is reserved even if the argument
4145132718Skan	     will be passed in memory.  */
4146132718Skan	  if (TARGET_32BIT)
4147132718Skan	    align = (2 - cum->words) & 3;
4148132718Skan	  else
4149132718Skan	    align = cum->words & 1;
4150132718Skan	  cum->words += align + rs6000_arg_size (mode, type);
4151132718Skan
4152132718Skan	  if (TARGET_DEBUG_ARG)
4153132718Skan	    {
4154132718Skan	      fprintf (stderr, "function_adv: words = %2d, align=%d, ",
4155132718Skan		       cum->words, align);
4156132718Skan	      fprintf (stderr, "nargs = %4d, proto = %d, mode = %4s\n",
4157132718Skan		       cum->nargs_prototype, cum->prototype,
4158132718Skan		       GET_MODE_NAME (mode));
4159132718Skan	    }
4160132718Skan	}
416190075Sobrien    }
4162117395Skan  else if (TARGET_SPE_ABI && TARGET_SPE && SPE_VECTOR_MODE (mode)
4163132718Skan	   && !cum->stdarg
4164132718Skan	   && cum->sysv_gregno <= GP_ARG_MAX_REG)
4165117395Skan    cum->sysv_gregno++;
416690075Sobrien  else if (DEFAULT_ABI == ABI_V4)
416790075Sobrien    {
4168117395Skan      if (TARGET_HARD_FLOAT && TARGET_FPRS
416990075Sobrien	  && (mode == SFmode || mode == DFmode))
417090075Sobrien	{
417190075Sobrien	  if (cum->fregno <= FP_ARG_V4_MAX_REG)
417290075Sobrien	    cum->fregno++;
417390075Sobrien	  else
417490075Sobrien	    {
417590075Sobrien	      if (mode == DFmode)
417690075Sobrien	        cum->words += cum->words & 1;
4177132718Skan	      cum->words += rs6000_arg_size (mode, type);
417890075Sobrien	    }
417990075Sobrien	}
418090075Sobrien      else
418190075Sobrien	{
4182132718Skan	  int n_words = rs6000_arg_size (mode, type);
418390075Sobrien	  int gregno = cum->sysv_gregno;
418490075Sobrien
4185132718Skan	  /* Long long and SPE vectors are put in (r3,r4), (r5,r6),
4186132718Skan	     (r7,r8) or (r9,r10).  As does any other 2 word item such
4187132718Skan	     as complex int due to a historical mistake.  */
4188132718Skan	  if (n_words == 2)
4189132718Skan	    gregno += (1 - gregno) & 1;
419090075Sobrien
4191132718Skan	  /* Multi-reg args are not split between registers and stack.  */
419290075Sobrien	  if (gregno + n_words - 1 > GP_ARG_MAX_REG)
419390075Sobrien	    {
4194132718Skan	      /* Long long and SPE vectors are aligned on the stack.
4195132718Skan		 So are other 2 word items such as complex int due to
4196132718Skan		 a historical mistake.  */
419790075Sobrien	      if (n_words == 2)
419890075Sobrien		cum->words += cum->words & 1;
419990075Sobrien	      cum->words += n_words;
420090075Sobrien	    }
420190075Sobrien
420290075Sobrien	  /* Note: continuing to accumulate gregno past when we've started
420390075Sobrien	     spilling to the stack indicates the fact that we've started
420490075Sobrien	     spilling to the stack to expand_builtin_saveregs.  */
420590075Sobrien	  cum->sysv_gregno = gregno + n_words;
420690075Sobrien	}
420790075Sobrien
420890075Sobrien      if (TARGET_DEBUG_ARG)
420990075Sobrien	{
421090075Sobrien	  fprintf (stderr, "function_adv: words = %2d, fregno = %2d, ",
421190075Sobrien		   cum->words, cum->fregno);
421290075Sobrien	  fprintf (stderr, "gregno = %2d, nargs = %4d, proto = %d, ",
421390075Sobrien		   cum->sysv_gregno, cum->nargs_prototype, cum->prototype);
421490075Sobrien	  fprintf (stderr, "mode = %4s, named = %d\n",
421590075Sobrien		   GET_MODE_NAME (mode), named);
421690075Sobrien	}
421790075Sobrien    }
421890075Sobrien  else
421990075Sobrien    {
4220132718Skan      int n_words = rs6000_arg_size (mode, type);
4221132718Skan      int align = function_arg_boundary (mode, type) / PARM_BOUNDARY - 1;
422290075Sobrien
4223132718Skan      /* The simple alignment calculation here works because
4224132718Skan	 function_arg_boundary / PARM_BOUNDARY will only be 1 or 2.
4225132718Skan	 If we ever want to handle alignments larger than 8 bytes for
4226132718Skan	 32-bit or 16 bytes for 64-bit, then we'll need to take into
4227132718Skan	 account the offset to the start of the parm save area.  */
4228132718Skan      align &= cum->words;
4229132718Skan      cum->words += align + n_words;
423090075Sobrien
4231117395Skan      if (GET_MODE_CLASS (mode) == MODE_FLOAT
4232117395Skan	  && TARGET_HARD_FLOAT && TARGET_FPRS)
4233132718Skan	cum->fregno += (GET_MODE_SIZE (mode) + 7) >> 3;
423490075Sobrien
423590075Sobrien      if (TARGET_DEBUG_ARG)
423690075Sobrien	{
423790075Sobrien	  fprintf (stderr, "function_adv: words = %2d, fregno = %2d, ",
423890075Sobrien		   cum->words, cum->fregno);
423990075Sobrien	  fprintf (stderr, "nargs = %4d, proto = %d, mode = %4s, ",
424090075Sobrien		   cum->nargs_prototype, cum->prototype, GET_MODE_NAME (mode));
424190075Sobrien	  fprintf (stderr, "named = %d, align = %d\n", named, align);
424290075Sobrien	}
424390075Sobrien    }
424490075Sobrien}
4245132718Skan
4246132718Skan/* Determine where to put a SIMD argument on the SPE.  */
4247132718Skan
4248132718Skanstatic rtx
4249132718Skanrs6000_spe_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
4250132718Skan			 tree type)
4251132718Skan{
4252132718Skan  if (cum->stdarg)
4253132718Skan    {
4254132718Skan      int gregno = cum->sysv_gregno;
4255132718Skan      int n_words = rs6000_arg_size (mode, type);
4256132718Skan
4257132718Skan      /* SPE vectors are put in odd registers.  */
4258132718Skan      if (n_words == 2 && (gregno & 1) == 0)
4259132718Skan	gregno += 1;
4260132718Skan
4261132718Skan      if (gregno + n_words - 1 <= GP_ARG_MAX_REG)
4262132718Skan	{
4263132718Skan	  rtx r1, r2;
4264132718Skan	  enum machine_mode m = SImode;
4265132718Skan
4266132718Skan	  r1 = gen_rtx_REG (m, gregno);
4267132718Skan	  r1 = gen_rtx_EXPR_LIST (m, r1, const0_rtx);
4268132718Skan	  r2 = gen_rtx_REG (m, gregno + 1);
4269132718Skan	  r2 = gen_rtx_EXPR_LIST (m, r2, GEN_INT (4));
4270132718Skan	  return gen_rtx_PARALLEL (mode, gen_rtvec (2, r1, r2));
4271132718Skan	}
4272132718Skan      else
4273132718Skan	return NULL_RTX;
4274132718Skan    }
4275132718Skan  else
4276132718Skan    {
4277132718Skan      if (cum->sysv_gregno <= GP_ARG_MAX_REG)
4278132718Skan	return gen_rtx_REG (mode, cum->sysv_gregno);
4279132718Skan      else
4280132718Skan	return NULL_RTX;
4281132718Skan    }
4282132718Skan}
4283132718Skan
4284132718Skan/* Determine where to place an argument in 64-bit mode with 32-bit ABI.  */
4285132718Skan
4286132718Skanstatic rtx
4287146895Skanrs6000_mixed_function_arg (enum machine_mode mode, tree type, int align_words)
4288132718Skan{
4289146895Skan  int n_units;
4290146895Skan  int i, k;
4291146895Skan  rtx rvec[GP_ARG_NUM_REG + 1];
4292132718Skan
4293146895Skan  if (align_words >= GP_ARG_NUM_REG)
4294146895Skan    return NULL_RTX;
4295132718Skan
4296146895Skan  n_units = rs6000_arg_size (mode, type);
4297132718Skan
4298146895Skan  /* Optimize the simple case where the arg fits in one gpr, except in
4299146895Skan     the case of BLKmode due to assign_parms assuming that registers are
4300146895Skan     BITS_PER_WORD wide.  */
4301146895Skan  if (n_units == 0
4302146895Skan      || (n_units == 1 && mode != BLKmode))
4303146895Skan    return gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
4304132718Skan
4305146895Skan  k = 0;
4306146895Skan  if (align_words + n_units > GP_ARG_NUM_REG)
4307146895Skan    /* Not all of the arg fits in gprs.  Say that it goes in memory too,
4308146895Skan       using a magic NULL_RTX component.
4309146895Skan       FIXME: This is not strictly correct.  Only some of the arg
4310146895Skan       belongs in memory, not all of it.  However, there isn't any way
4311146895Skan       to do this currently, apart from building rtx descriptions for
4312146895Skan       the pieces of memory we want stored.  Due to bugs in the generic
4313146895Skan       code we can't use the normal function_arg_partial_nregs scheme
4314146895Skan       with the PARALLEL arg description we emit here.
4315146895Skan       In any case, the code to store the whole arg to memory is often
4316146895Skan       more efficient than code to store pieces, and we know that space
4317146895Skan       is available in the right place for the whole arg.  */
4318146895Skan    rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX, const0_rtx);
4319132718Skan
4320146895Skan  i = 0;
4321146895Skan  do
4322146895Skan    {
4323146895Skan      rtx r = gen_rtx_REG (SImode, GP_ARG_MIN_REG + align_words);
4324146895Skan      rtx off = GEN_INT (i++ * 4);
4325146895Skan      rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, off);
4326146895Skan    }
4327146895Skan  while (++align_words < GP_ARG_NUM_REG && --n_units != 0);
4328146895Skan
4329146895Skan  return gen_rtx_PARALLEL (mode, gen_rtvec_v (k, rvec));
4330132718Skan}
4331132718Skan
433290075Sobrien/* Determine where to put an argument to a function.
433390075Sobrien   Value is zero to push the argument on the stack,
433490075Sobrien   or a hard register in which to store the argument.
433590075Sobrien
433690075Sobrien   MODE is the argument's machine mode.
433790075Sobrien   TYPE is the data type of the argument (as a tree).
433890075Sobrien    This is null for libcalls where that information may
433990075Sobrien    not be available.
434090075Sobrien   CUM is a variable of type CUMULATIVE_ARGS which gives info about
434190075Sobrien    the preceding args and about the function being called.
434290075Sobrien   NAMED is nonzero if this argument is a named parameter
434390075Sobrien    (otherwise it is an extra parameter matching an ellipsis).
434490075Sobrien
434590075Sobrien   On RS/6000 the first eight words of non-FP are normally in registers
434690075Sobrien   and the rest are pushed.  Under AIX, the first 13 FP args are in registers.
434790075Sobrien   Under V.4, the first 8 FP args are in registers.
434890075Sobrien
434990075Sobrien   If this is floating-point and no prototype is specified, we use
435090075Sobrien   both an FP and integer register (or possibly FP reg and stack).  Library
4351117395Skan   functions (when CALL_LIBCALL is set) always have the proper types for args,
435290075Sobrien   so we can pass the FP value just in one register.  emit_library_function
4353132718Skan   doesn't support PARALLEL anyway.
435490075Sobrien
4355132718Skan   Note that for args passed by reference, function_arg will be called
4356132718Skan   with MODE and TYPE set to that of the pointer to the arg, not the arg
4357132718Skan   itself.  */
4358132718Skan
435990075Sobrienstruct rtx_def *
4360132718Skanfunction_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
4361132718Skan	      tree type, int named)
436290075Sobrien{
436390075Sobrien  enum rs6000_abi abi = DEFAULT_ABI;
436490075Sobrien
436590075Sobrien  /* Return a marker to indicate whether CR1 needs to set or clear the
436690075Sobrien     bit that V.4 uses to say fp args were passed in registers.
436790075Sobrien     Assume that we don't need the marker for software floating point,
436890075Sobrien     or compiler generated library calls.  */
436990075Sobrien  if (mode == VOIDmode)
437090075Sobrien    {
437190075Sobrien      if (abi == ABI_V4
437290075Sobrien	  && cum->nargs_prototype < 0
4373117395Skan	  && (cum->call_cookie & CALL_LIBCALL) == 0
4374117395Skan	  && (cum->prototype || TARGET_NO_PROTOTYPE))
437590075Sobrien	{
4376117395Skan	  /* For the SPE, we need to crxor CR6 always.  */
4377117395Skan	  if (TARGET_SPE_ABI)
4378117395Skan	    return GEN_INT (cum->call_cookie | CALL_V4_SET_FP_ARGS);
4379117395Skan	  else if (TARGET_HARD_FLOAT && TARGET_FPRS)
4380117395Skan	    return GEN_INT (cum->call_cookie
4381117395Skan			    | ((cum->fregno == FP_ARG_MIN_REG)
4382117395Skan			       ? CALL_V4_SET_FP_ARGS
4383117395Skan			       : CALL_V4_CLEAR_FP_ARGS));
438490075Sobrien	}
438590075Sobrien
438690075Sobrien      return GEN_INT (cum->call_cookie);
438790075Sobrien    }
438890075Sobrien
4389132718Skan  if (USE_ALTIVEC_FOR_ARG_P (cum, mode, type, named))
4390132718Skan    if (TARGET_64BIT && ! cum->prototype)
4391132718Skan      {
4392132718Skan       /* Vector parameters get passed in vector register
4393132718Skan          and also in GPRs or memory, in absence of prototype.  */
4394132718Skan       int align_words;
4395132718Skan       rtx slot;
4396132718Skan       align_words = (cum->words + 1) & ~1;
4397132718Skan
4398132718Skan       if (align_words >= GP_ARG_NUM_REG)
4399132718Skan         {
4400132718Skan           slot = NULL_RTX;
4401132718Skan         }
4402132718Skan       else
4403132718Skan         {
4404132718Skan           slot = gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
4405132718Skan         }
4406132718Skan       return gen_rtx_PARALLEL (mode,
4407132718Skan                gen_rtvec (2,
4408132718Skan                           gen_rtx_EXPR_LIST (VOIDmode,
4409132718Skan                                              slot, const0_rtx),
4410132718Skan                           gen_rtx_EXPR_LIST (VOIDmode,
4411132718Skan                                              gen_rtx_REG (mode, cum->vregno),
4412132718Skan                                              const0_rtx)));
4413132718Skan      }
4414132718Skan    else
4415132718Skan      return gen_rtx_REG (mode, cum->vregno);
4416132718Skan  else if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
441790075Sobrien    {
4418132718Skan      if (named || abi == ABI_V4)
4419132718Skan	return NULL_RTX;
442090075Sobrien      else
4421132718Skan	{
4422132718Skan	  /* Vector parameters to varargs functions under AIX or Darwin
4423132718Skan	     get passed in memory and possibly also in GPRs.  */
4424146895Skan	  int align, align_words, n_words;
4425146895Skan	  enum machine_mode part_mode;
4426132718Skan
4427132718Skan	  /* Vector parameters must be 16-byte aligned.  This places them at
4428132718Skan	     2 mod 4 in terms of words in 32-bit mode, since the parameter
4429132718Skan	     save area starts at offset 24 from the stack.  In 64-bit mode,
4430132718Skan	     they just have to start on an even word, since the parameter
4431132718Skan	     save area is 16-byte aligned.  */
4432132718Skan	  if (TARGET_32BIT)
4433132718Skan	    align = (2 - cum->words) & 3;
4434132718Skan	  else
4435132718Skan	    align = cum->words & 1;
4436132718Skan	  align_words = cum->words + align;
4437132718Skan
4438132718Skan	  /* Out of registers?  Memory, then.  */
4439132718Skan	  if (align_words >= GP_ARG_NUM_REG)
4440132718Skan	    return NULL_RTX;
4441146895Skan
4442146895Skan	  if (TARGET_32BIT && TARGET_POWERPC64)
4443146895Skan	    return rs6000_mixed_function_arg (mode, type, align_words);
4444146895Skan
4445132718Skan	  /* The vector value goes in GPRs.  Only the part of the
4446132718Skan	     value in GPRs is reported here.  */
4447146895Skan	  part_mode = mode;
4448146895Skan	  n_words = rs6000_arg_size (mode, type);
4449146895Skan	  if (align_words + n_words > GP_ARG_NUM_REG)
4450132718Skan	    /* Fortunately, there are only two possibilities, the value
4451132718Skan	       is either wholly in GPRs or half in GPRs and half not.  */
4452132718Skan	    part_mode = DImode;
4453146895Skan
4454132718Skan	  return gen_rtx_REG (part_mode, GP_ARG_MIN_REG + align_words);
4455132718Skan	}
445690075Sobrien    }
4457132718Skan  else if (TARGET_SPE_ABI && TARGET_SPE && SPE_VECTOR_MODE (mode))
4458132718Skan    return rs6000_spe_function_arg (cum, mode, type);
445990075Sobrien  else if (abi == ABI_V4)
446090075Sobrien    {
4461117395Skan      if (TARGET_HARD_FLOAT && TARGET_FPRS
446290075Sobrien	  && (mode == SFmode || mode == DFmode))
446390075Sobrien	{
446490075Sobrien	  if (cum->fregno <= FP_ARG_V4_MAX_REG)
446590075Sobrien	    return gen_rtx_REG (mode, cum->fregno);
446690075Sobrien	  else
4467132718Skan	    return NULL_RTX;
446890075Sobrien	}
446990075Sobrien      else
447090075Sobrien	{
4471132718Skan	  int n_words = rs6000_arg_size (mode, type);
447290075Sobrien	  int gregno = cum->sysv_gregno;
447390075Sobrien
4474132718Skan	  /* Long long and SPE vectors are put in (r3,r4), (r5,r6),
4475132718Skan	     (r7,r8) or (r9,r10).  As does any other 2 word item such
4476132718Skan	     as complex int due to a historical mistake.  */
4477132718Skan	  if (n_words == 2)
4478132718Skan	    gregno += (1 - gregno) & 1;
447990075Sobrien
4480132718Skan	  /* Multi-reg args are not split between registers and stack.  */
4481146895Skan	  if (gregno + n_words - 1 > GP_ARG_MAX_REG)
4482132718Skan	    return NULL_RTX;
4483146895Skan
4484146895Skan	  if (TARGET_32BIT && TARGET_POWERPC64)
4485146895Skan	    return rs6000_mixed_function_arg (mode, type,
4486146895Skan					      gregno - GP_ARG_MIN_REG);
4487146895Skan	  return gen_rtx_REG (mode, gregno);
448890075Sobrien	}
448990075Sobrien    }
449090075Sobrien  else
449190075Sobrien    {
4492132718Skan      int align = function_arg_boundary (mode, type) / PARM_BOUNDARY - 1;
4493132718Skan      int align_words = cum->words + (cum->words & align);
449490075Sobrien
4495132718Skan      if (USE_FP_FOR_ARG_P (cum, mode, type))
4496132718Skan	{
4497146895Skan	  rtx rvec[GP_ARG_NUM_REG + 1];
4498146895Skan	  rtx r;
4499146895Skan	  int k;
4500132718Skan	  bool needs_psave;
4501132718Skan	  enum machine_mode fmode = mode;
4502132718Skan	  unsigned long n_fpreg = (GET_MODE_SIZE (mode) + 7) >> 3;
450390075Sobrien
4504132718Skan	  if (cum->fregno + n_fpreg > FP_ARG_MAX_REG + 1)
4505132718Skan	    {
4506132718Skan	      /* Currently, we only ever need one reg here because complex
4507132718Skan		 doubles are split.  */
4508146895Skan	      if (cum->fregno != FP_ARG_MAX_REG || fmode != TFmode)
4509132718Skan		abort ();
4510146895Skan
4511146895Skan	      /* Long double split over regs and memory.  */
4512146895Skan	      fmode = DFmode;
4513132718Skan	    }
4514132718Skan
4515132718Skan	  /* Do we also need to pass this arg in the parameter save
4516132718Skan	     area?  */
4517132718Skan	  needs_psave = (type
4518132718Skan			 && (cum->nargs_prototype <= 0
4519132718Skan			     || (DEFAULT_ABI == ABI_AIX
4520146895Skan				 && TARGET_XL_COMPAT
4521132718Skan				 && align_words >= GP_ARG_NUM_REG)));
4522132718Skan
4523132718Skan	  if (!needs_psave && mode == fmode)
4524146895Skan	    return gen_rtx_REG (fmode, cum->fregno);
4525132718Skan
4526146895Skan	  k = 0;
4527132718Skan	  if (needs_psave)
4528132718Skan	    {
4529146895Skan	      /* Describe the part that goes in gprs or the stack.
4530132718Skan		 This piece must come first, before the fprs.  */
4531132718Skan	      if (align_words < GP_ARG_NUM_REG)
4532132718Skan		{
4533132718Skan		  unsigned long n_words = rs6000_arg_size (mode, type);
4534132718Skan
4535146895Skan		  if (align_words + n_words > GP_ARG_NUM_REG
4536146895Skan		      || (TARGET_32BIT && TARGET_POWERPC64))
4537146895Skan		    {
4538146895Skan		      /* If this is partially on the stack, then we only
4539146895Skan			 include the portion actually in registers here.  */
4540146895Skan		      enum machine_mode rmode = TARGET_32BIT ? SImode : DImode;
4541146895Skan		      rtx off;
4542146895Skan		      do
4543146895Skan			{
4544146895Skan			  r = gen_rtx_REG (rmode,
4545146895Skan					   GP_ARG_MIN_REG + align_words);
4546146895Skan			  off = GEN_INT (k * GET_MODE_SIZE (rmode));
4547146895Skan			  rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, off);
4548146895Skan			}
4549146895Skan		      while (++align_words < GP_ARG_NUM_REG && --n_words != 0);
4550146895Skan		    }
4551146895Skan		  else
4552146895Skan		    {
4553146895Skan		      /* The whole arg fits in gprs.  */
4554146895Skan		      r = gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
4555146895Skan		      rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, const0_rtx);
4556146895Skan		    }
4557132718Skan		}
4558146895Skan	      else
4559146895Skan		/* It's entirely in memory.  */
4560146895Skan		rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX, const0_rtx);
4561132718Skan	    }
4562132718Skan
4563146895Skan	  /* Describe where this piece goes in the fprs.  */
4564146895Skan	  r = gen_rtx_REG (fmode, cum->fregno);
4565146895Skan	  rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, const0_rtx);
4566146895Skan
4567146895Skan	  return gen_rtx_PARALLEL (mode, gen_rtvec_v (k, rvec));
4568132718Skan	}
4569132718Skan      else if (align_words < GP_ARG_NUM_REG)
457090075Sobrien	{
4571146895Skan	  if (TARGET_32BIT && TARGET_POWERPC64)
4572146895Skan	    return rs6000_mixed_function_arg (mode, type, align_words);
457390075Sobrien
4574132718Skan	  return gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
457590075Sobrien	}
457690075Sobrien      else
457790075Sobrien	return NULL_RTX;
457890075Sobrien    }
457990075Sobrien}
458090075Sobrien
4581146895Skan/* For an arg passed partly in registers and partly in memory, this is
4582146895Skan   the number of registers used.  For args passed entirely in registers
4583146895Skan   or entirely in memory, zero.  When an arg is described by a PARALLEL,
4584146895Skan   perhaps using more than one register type, this function returns the
4585146895Skan   number of registers used by the first element of the PARALLEL.  */
458690075Sobrien
458790075Sobrienint
4588132718Skanfunction_arg_partial_nregs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
4589132718Skan			    tree type, int named)
459090075Sobrien{
4591132718Skan  int ret = 0;
4592146895Skan  int align;
4593146895Skan  int parm_offset;
4594146895Skan  int align_words;
4595132718Skan
459690075Sobrien  if (DEFAULT_ABI == ABI_V4)
459790075Sobrien    return 0;
459890075Sobrien
4599132718Skan  if (USE_ALTIVEC_FOR_ARG_P (cum, mode, type, named)
4600132718Skan      && cum->nargs_prototype >= 0)
4601132718Skan    return 0;
4602132718Skan
4603146895Skan  align = function_arg_boundary (mode, type) / PARM_BOUNDARY - 1;
4604146895Skan  parm_offset = TARGET_32BIT ? 2 : 0;
4605146895Skan  align_words = cum->words + ((parm_offset - cum->words) & align);
4606146895Skan
4607146895Skan  if (USE_FP_FOR_ARG_P (cum, mode, type)
4608146895Skan      /* If we are passing this arg in gprs as well, then this function
4609146895Skan	 should return the number of gprs (or memory) partially passed,
4610146895Skan	 *not* the number of fprs.  */
4611146895Skan      && !(type
4612146895Skan	   && (cum->nargs_prototype <= 0
4613146895Skan	       || (DEFAULT_ABI == ABI_AIX
4614146895Skan		   && TARGET_XL_COMPAT
4615146895Skan		   && align_words >= GP_ARG_NUM_REG))))
461690075Sobrien    {
4617132718Skan      if (cum->fregno + ((GET_MODE_SIZE (mode) + 7) >> 3) > FP_ARG_MAX_REG + 1)
4618146895Skan	ret = FP_ARG_MAX_REG + 1 - cum->fregno;
4619132718Skan      else if (cum->nargs_prototype >= 0)
462090075Sobrien	return 0;
462190075Sobrien    }
462290075Sobrien
4623146895Skan  if (align_words < GP_ARG_NUM_REG
4624146895Skan      && GP_ARG_NUM_REG < align_words + rs6000_arg_size (mode, type))
4625146895Skan    ret = GP_ARG_NUM_REG - align_words;
462690075Sobrien
4627132718Skan  if (ret != 0 && TARGET_DEBUG_ARG)
4628132718Skan    fprintf (stderr, "function_arg_partial_nregs: %d\n", ret);
462990075Sobrien
4630132718Skan  return ret;
463190075Sobrien}
463290075Sobrien
463390075Sobrien/* A C expression that indicates when an argument must be passed by
463490075Sobrien   reference.  If nonzero for an argument, a copy of that argument is
463590075Sobrien   made in memory and a pointer to the argument is passed instead of
463690075Sobrien   the argument itself.  The pointer is passed in whatever way is
463790075Sobrien   appropriate for passing a pointer to that type.
463890075Sobrien
4639132718Skan   Under V.4, aggregates and long double are passed by reference.
464090075Sobrien
4641132718Skan   As an extension to all 32-bit ABIs, AltiVec vectors are passed by
4642132718Skan   reference unless the AltiVec vector extension ABI is in force.
4643132718Skan
4644117395Skan   As an extension to all ABIs, variable sized types are passed by
4645117395Skan   reference.  */
4646117395Skan
464790075Sobrienint
4648132718Skanfunction_arg_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
4649132718Skan				enum machine_mode mode ATTRIBUTE_UNUSED,
4650132718Skan				tree type, int named ATTRIBUTE_UNUSED)
465190075Sobrien{
4652132718Skan  if ((DEFAULT_ABI == ABI_V4
4653132718Skan       && ((type && AGGREGATE_TYPE_P (type))
4654132718Skan	   || mode == TFmode))
4655132718Skan      || (TARGET_32BIT && !TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
4656132718Skan      || (type && int_size_in_bytes (type) < 0))
465790075Sobrien    {
465890075Sobrien      if (TARGET_DEBUG_ARG)
4659132718Skan	fprintf (stderr, "function_arg_pass_by_reference\n");
466090075Sobrien
466190075Sobrien      return 1;
466290075Sobrien    }
4663132718Skan  return 0;
466490075Sobrien}
4665132718Skan
4666132718Skanstatic void
4667132718Skanrs6000_move_block_from_reg (int regno, rtx x, int nregs)
4668132718Skan{
4669132718Skan  int i;
4670132718Skan  enum machine_mode reg_mode = TARGET_32BIT ? SImode : DImode;
4671132718Skan
4672132718Skan  if (nregs == 0)
4673132718Skan    return;
4674132718Skan
4675132718Skan    for (i = 0; i < nregs; i++)
4676132718Skan    {
4677132718Skan      rtx tem = adjust_address_nv (x, reg_mode, i*GET_MODE_SIZE(reg_mode));
4678132718Skan      if (reload_completed)
4679132718Skan      {
4680132718Skan	if (! strict_memory_address_p (reg_mode, XEXP (tem, 0)))
4681132718Skan	  tem = NULL_RTX;
4682132718Skan	else
4683132718Skan	  tem = simplify_gen_subreg (reg_mode, x, BLKmode,
4684132718Skan				     i * GET_MODE_SIZE(reg_mode));
4685132718Skan      }
4686132718Skan      else
4687132718Skan	tem = replace_equiv_address (tem, XEXP (tem, 0));
4688132718Skan
4689132718Skan      if (tem == NULL_RTX)
4690132718Skan        abort ();
4691132718Skan
4692132718Skan      emit_move_insn (tem, gen_rtx_REG (reg_mode, regno + i));
4693132718Skan    }
4694132718Skan}
4695132718Skan
469690075Sobrien
469790075Sobrien/* Perform any needed actions needed for a function that is receiving a
469890075Sobrien   variable number of arguments.
469990075Sobrien
470090075Sobrien   CUM is as above.
470190075Sobrien
470290075Sobrien   MODE and TYPE are the mode and type of the current parameter.
470390075Sobrien
470490075Sobrien   PRETEND_SIZE is a variable that should be set to the amount of stack
470590075Sobrien   that must be pushed by the prolog to pretend that our caller pushed
470690075Sobrien   it.
470790075Sobrien
470890075Sobrien   Normally, this macro will push all remaining incoming registers on the
470990075Sobrien   stack and set PRETEND_SIZE to the length of the registers pushed.  */
471090075Sobrien
4711132718Skanstatic void
4712132718Skansetup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
4713132718Skan		tree type, int *pretend_size ATTRIBUTE_UNUSED, int no_rtl)
471490075Sobrien{
471590075Sobrien  CUMULATIVE_ARGS next_cum;
471690075Sobrien  int reg_size = TARGET_32BIT ? 4 : 8;
471790075Sobrien  rtx save_area = NULL_RTX, mem;
471890075Sobrien  int first_reg_offset, set;
471990075Sobrien
4720132718Skan  /* Skip the last named argument.  */
472190075Sobrien  next_cum = *cum;
4722132718Skan  function_arg_advance (&next_cum, mode, type, 1);
472390075Sobrien
472490075Sobrien  if (DEFAULT_ABI == ABI_V4)
472590075Sobrien    {
472690075Sobrien      /* Indicate to allocate space on the stack for varargs save area.  */
472790075Sobrien      cfun->machine->sysv_varargs_p = 1;
472890075Sobrien      if (! no_rtl)
472990075Sobrien	save_area = plus_constant (virtual_stack_vars_rtx,
473090075Sobrien				   - RS6000_VARARGS_SIZE);
473190075Sobrien
473290075Sobrien      first_reg_offset = next_cum.sysv_gregno - GP_ARG_MIN_REG;
473390075Sobrien    }
473490075Sobrien  else
473590075Sobrien    {
473690075Sobrien      first_reg_offset = next_cum.words;
473790075Sobrien      save_area = virtual_incoming_args_rtx;
473890075Sobrien      cfun->machine->sysv_varargs_p = 0;
473990075Sobrien
474090075Sobrien      if (MUST_PASS_IN_STACK (mode, type))
4741132718Skan	first_reg_offset += rs6000_arg_size (TYPE_MODE (type), type);
474290075Sobrien    }
474390075Sobrien
474490075Sobrien  set = get_varargs_alias_set ();
474590075Sobrien  if (! no_rtl && first_reg_offset < GP_ARG_NUM_REG)
474690075Sobrien    {
474790075Sobrien      mem = gen_rtx_MEM (BLKmode,
474890075Sobrien		         plus_constant (save_area,
474990075Sobrien					first_reg_offset * reg_size)),
475090075Sobrien      set_mem_alias_set (mem, set);
475190075Sobrien      set_mem_align (mem, BITS_PER_WORD);
475290075Sobrien
4753132718Skan      rs6000_move_block_from_reg (GP_ARG_MIN_REG + first_reg_offset, mem,
4754132718Skan			          GP_ARG_NUM_REG - first_reg_offset);
475590075Sobrien    }
475690075Sobrien
475790075Sobrien  /* Save FP registers if needed.  */
475890075Sobrien  if (DEFAULT_ABI == ABI_V4
4759117395Skan      && TARGET_HARD_FLOAT && TARGET_FPRS
4760117395Skan      && ! no_rtl
476190075Sobrien      && next_cum.fregno <= FP_ARG_V4_MAX_REG)
476290075Sobrien    {
476390075Sobrien      int fregno = next_cum.fregno;
476490075Sobrien      rtx cr1 = gen_rtx_REG (CCmode, CR1_REGNO);
476590075Sobrien      rtx lab = gen_label_rtx ();
476690075Sobrien      int off = (GP_ARG_NUM_REG * reg_size) + ((fregno - FP_ARG_MIN_REG) * 8);
476790075Sobrien
476890075Sobrien      emit_jump_insn (gen_rtx_SET (VOIDmode,
476990075Sobrien				   pc_rtx,
477090075Sobrien				   gen_rtx_IF_THEN_ELSE (VOIDmode,
477190075Sobrien					    gen_rtx_NE (VOIDmode, cr1,
477290075Sobrien						        const0_rtx),
477390075Sobrien					    gen_rtx_LABEL_REF (VOIDmode, lab),
477490075Sobrien					    pc_rtx)));
477590075Sobrien
477690075Sobrien      while (fregno <= FP_ARG_V4_MAX_REG)
477790075Sobrien	{
477890075Sobrien	  mem = gen_rtx_MEM (DFmode, plus_constant (save_area, off));
477990075Sobrien          set_mem_alias_set (mem, set);
4780146895Skan	  set_mem_align (mem, GET_MODE_ALIGNMENT (DFmode));
478190075Sobrien	  emit_move_insn (mem, gen_rtx_REG (DFmode, fregno));
478290075Sobrien	  fregno++;
478390075Sobrien	  off += 8;
478490075Sobrien	}
478590075Sobrien
478690075Sobrien      emit_label (lab);
478790075Sobrien    }
478890075Sobrien}
478990075Sobrien
479090075Sobrien/* Create the va_list data type.  */
479190075Sobrien
4792132718Skanstatic tree
4793132718Skanrs6000_build_builtin_va_list (void)
479490075Sobrien{
4795132718Skan  tree f_gpr, f_fpr, f_res, f_ovf, f_sav, record, type_decl;
479690075Sobrien
479790075Sobrien  /* For AIX, prefer 'char *' because that's what the system
479890075Sobrien     header files like.  */
479990075Sobrien  if (DEFAULT_ABI != ABI_V4)
480090075Sobrien    return build_pointer_type (char_type_node);
480190075Sobrien
4802117395Skan  record = (*lang_hooks.types.make_type) (RECORD_TYPE);
480390075Sobrien  type_decl = build_decl (TYPE_DECL, get_identifier ("__va_list_tag"), record);
480490075Sobrien
480590075Sobrien  f_gpr = build_decl (FIELD_DECL, get_identifier ("gpr"),
480690075Sobrien		      unsigned_char_type_node);
480790075Sobrien  f_fpr = build_decl (FIELD_DECL, get_identifier ("fpr"),
480890075Sobrien		      unsigned_char_type_node);
4809132718Skan  /* Give the two bytes of padding a name, so that -Wpadded won't warn on
4810132718Skan     every user file.  */
4811132718Skan  f_res = build_decl (FIELD_DECL, get_identifier ("reserved"),
4812132718Skan		      short_unsigned_type_node);
481390075Sobrien  f_ovf = build_decl (FIELD_DECL, get_identifier ("overflow_arg_area"),
481490075Sobrien		      ptr_type_node);
481590075Sobrien  f_sav = build_decl (FIELD_DECL, get_identifier ("reg_save_area"),
481690075Sobrien		      ptr_type_node);
481790075Sobrien
481890075Sobrien  DECL_FIELD_CONTEXT (f_gpr) = record;
481990075Sobrien  DECL_FIELD_CONTEXT (f_fpr) = record;
4820132718Skan  DECL_FIELD_CONTEXT (f_res) = record;
482190075Sobrien  DECL_FIELD_CONTEXT (f_ovf) = record;
482290075Sobrien  DECL_FIELD_CONTEXT (f_sav) = record;
482390075Sobrien
482490075Sobrien  TREE_CHAIN (record) = type_decl;
482590075Sobrien  TYPE_NAME (record) = type_decl;
482690075Sobrien  TYPE_FIELDS (record) = f_gpr;
482790075Sobrien  TREE_CHAIN (f_gpr) = f_fpr;
4828132718Skan  TREE_CHAIN (f_fpr) = f_res;
4829132718Skan  TREE_CHAIN (f_res) = f_ovf;
483090075Sobrien  TREE_CHAIN (f_ovf) = f_sav;
483190075Sobrien
483290075Sobrien  layout_type (record);
483390075Sobrien
483490075Sobrien  /* The correct type is an array type of one element.  */
483590075Sobrien  return build_array_type (record, build_index_type (size_zero_node));
483690075Sobrien}
483790075Sobrien
483890075Sobrien/* Implement va_start.  */
483990075Sobrien
484090075Sobrienvoid
4841132718Skanrs6000_va_start (tree valist, rtx nextarg)
484290075Sobrien{
484390075Sobrien  HOST_WIDE_INT words, n_gpr, n_fpr;
4844132718Skan  tree f_gpr, f_fpr, f_res, f_ovf, f_sav;
484590075Sobrien  tree gpr, fpr, ovf, sav, t;
484690075Sobrien
484790075Sobrien  /* Only SVR4 needs something special.  */
484890075Sobrien  if (DEFAULT_ABI != ABI_V4)
484990075Sobrien    {
4850117395Skan      std_expand_builtin_va_start (valist, nextarg);
485190075Sobrien      return;
485290075Sobrien    }
485390075Sobrien
485490075Sobrien  f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
485590075Sobrien  f_fpr = TREE_CHAIN (f_gpr);
4856132718Skan  f_res = TREE_CHAIN (f_fpr);
4857132718Skan  f_ovf = TREE_CHAIN (f_res);
485890075Sobrien  f_sav = TREE_CHAIN (f_ovf);
485990075Sobrien
486090075Sobrien  valist = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)), valist);
486190075Sobrien  gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
486290075Sobrien  fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
486390075Sobrien  ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf);
486490075Sobrien  sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav);
486590075Sobrien
486690075Sobrien  /* Count number of gp and fp argument registers used.  */
486790075Sobrien  words = current_function_args_info.words;
486890075Sobrien  n_gpr = current_function_args_info.sysv_gregno - GP_ARG_MIN_REG;
486990075Sobrien  n_fpr = current_function_args_info.fregno - FP_ARG_MIN_REG;
487090075Sobrien
487190075Sobrien  if (TARGET_DEBUG_ARG)
4872132718Skan    fprintf (stderr, "va_start: words = "HOST_WIDE_INT_PRINT_DEC", n_gpr = "
4873132718Skan	     HOST_WIDE_INT_PRINT_DEC", n_fpr = "HOST_WIDE_INT_PRINT_DEC"\n",
4874132718Skan	     words, n_gpr, n_fpr);
487590075Sobrien
487690075Sobrien  t = build (MODIFY_EXPR, TREE_TYPE (gpr), gpr, build_int_2 (n_gpr, 0));
487790075Sobrien  TREE_SIDE_EFFECTS (t) = 1;
487890075Sobrien  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
487990075Sobrien
488090075Sobrien  t = build (MODIFY_EXPR, TREE_TYPE (fpr), fpr, build_int_2 (n_fpr, 0));
488190075Sobrien  TREE_SIDE_EFFECTS (t) = 1;
488290075Sobrien  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
488390075Sobrien
488490075Sobrien  /* Find the overflow area.  */
488590075Sobrien  t = make_tree (TREE_TYPE (ovf), virtual_incoming_args_rtx);
488690075Sobrien  if (words != 0)
488790075Sobrien    t = build (PLUS_EXPR, TREE_TYPE (ovf), t,
488890075Sobrien	       build_int_2 (words * UNITS_PER_WORD, 0));
488990075Sobrien  t = build (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t);
489090075Sobrien  TREE_SIDE_EFFECTS (t) = 1;
489190075Sobrien  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
489290075Sobrien
489390075Sobrien  /* Find the register save area.  */
489490075Sobrien  t = make_tree (TREE_TYPE (sav), virtual_stack_vars_rtx);
489590075Sobrien  t = build (PLUS_EXPR, TREE_TYPE (sav), t,
489690075Sobrien	     build_int_2 (-RS6000_VARARGS_SIZE, -1));
489790075Sobrien  t = build (MODIFY_EXPR, TREE_TYPE (sav), sav, t);
489890075Sobrien  TREE_SIDE_EFFECTS (t) = 1;
489990075Sobrien  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
490090075Sobrien}
490190075Sobrien
490290075Sobrien/* Implement va_arg.  */
490390075Sobrien
490490075Sobrienrtx
4905132718Skanrs6000_va_arg (tree valist, tree type)
490690075Sobrien{
4907132718Skan  tree f_gpr, f_fpr, f_res, f_ovf, f_sav;
490890075Sobrien  tree gpr, fpr, ovf, sav, reg, t, u;
490990075Sobrien  int indirect_p, size, rsize, n_reg, sav_ofs, sav_scale;
491090075Sobrien  rtx lab_false, lab_over, addr_rtx, r;
4911132718Skan  int align;
491290075Sobrien
491390075Sobrien  if (DEFAULT_ABI != ABI_V4)
4914117395Skan    {
4915132718Skan      /* Variable sized types are passed by reference, as are AltiVec
4916132718Skan	 vectors when 32-bit and not using the AltiVec ABI extension.  */
4917132718Skan      if (int_size_in_bytes (type) < 0
4918132718Skan	  || (TARGET_32BIT
4919132718Skan	      && !TARGET_ALTIVEC_ABI
4920132718Skan	      && ALTIVEC_VECTOR_MODE (TYPE_MODE (type))))
4921117395Skan	{
4922117395Skan	  u = build_pointer_type (type);
492390075Sobrien
4924117395Skan	  /* Args grow upward.  */
4925117395Skan	  t = build (POSTINCREMENT_EXPR, TREE_TYPE (valist), valist,
4926117395Skan		     build_int_2 (POINTER_SIZE / BITS_PER_UNIT, 0));
4927117395Skan	  TREE_SIDE_EFFECTS (t) = 1;
4928117395Skan
4929117395Skan	  t = build1 (NOP_EXPR, build_pointer_type (u), t);
4930117395Skan	  TREE_SIDE_EFFECTS (t) = 1;
4931117395Skan
4932117395Skan	  t = build1 (INDIRECT_REF, u, t);
4933117395Skan	  TREE_SIDE_EFFECTS (t) = 1;
4934117395Skan
4935117395Skan	  return expand_expr (t, NULL_RTX, VOIDmode, EXPAND_NORMAL);
4936117395Skan	}
4937132718Skan      if (targetm.calls.split_complex_arg
4938132718Skan	  && TREE_CODE (type) == COMPLEX_TYPE)
4939132718Skan	{
4940132718Skan	  tree elem_type = TREE_TYPE (type);
4941132718Skan	  enum machine_mode elem_mode = TYPE_MODE (elem_type);
4942132718Skan	  int elem_size = GET_MODE_SIZE (elem_mode);
4943132718Skan
4944132718Skan	  if (elem_size < UNITS_PER_WORD)
4945132718Skan	    {
4946132718Skan	      rtx real_part, imag_part, dest_real, rr;
4947132718Skan
4948132718Skan	      real_part = rs6000_va_arg (valist, elem_type);
4949132718Skan	      imag_part = rs6000_va_arg (valist, elem_type);
4950132718Skan
4951132718Skan	      /* We're not returning the value here, but the address.
4952132718Skan		 real_part and imag_part are not contiguous, and we know
4953132718Skan		 there is space available to pack real_part next to
4954132718Skan		 imag_part.  float _Complex is not promoted to
4955132718Skan		 double _Complex by the default promotion rules that
4956132718Skan		 promote float to double.  */
4957132718Skan	      if (2 * elem_size > UNITS_PER_WORD)
4958132718Skan		abort ();
4959132718Skan
4960132718Skan	      real_part = gen_rtx_MEM (elem_mode, real_part);
4961132718Skan	      imag_part = gen_rtx_MEM (elem_mode, imag_part);
4962132718Skan
4963132718Skan	      dest_real = adjust_address (imag_part, elem_mode, -elem_size);
4964132718Skan	      rr = gen_reg_rtx (elem_mode);
4965132718Skan	      emit_move_insn (rr, real_part);
4966132718Skan	      emit_move_insn (dest_real, rr);
4967132718Skan
4968132718Skan	      return XEXP (dest_real, 0);
4969132718Skan	    }
4970132718Skan	}
4971132718Skan
4972132718Skan      return std_expand_builtin_va_arg (valist, type);
4973117395Skan    }
4974117395Skan
497590075Sobrien  f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
497690075Sobrien  f_fpr = TREE_CHAIN (f_gpr);
4977132718Skan  f_res = TREE_CHAIN (f_fpr);
4978132718Skan  f_ovf = TREE_CHAIN (f_res);
497990075Sobrien  f_sav = TREE_CHAIN (f_ovf);
498090075Sobrien
498190075Sobrien  valist = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)), valist);
498290075Sobrien  gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
498390075Sobrien  fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
498490075Sobrien  ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf);
498590075Sobrien  sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav);
498690075Sobrien
498790075Sobrien  size = int_size_in_bytes (type);
4988132718Skan  rsize = (size + 3) / 4;
4989132718Skan  align = 1;
499090075Sobrien
4991132718Skan  if (AGGREGATE_TYPE_P (type)
4992132718Skan      || TYPE_MODE (type) == TFmode
4993132718Skan      || (!TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (TYPE_MODE (type))))
499490075Sobrien    {
4995132718Skan      /* Aggregates, long doubles, and AltiVec vectors are passed by
4996132718Skan	 reference.  */
499790075Sobrien      indirect_p = 1;
499890075Sobrien      reg = gpr;
499990075Sobrien      n_reg = 1;
500090075Sobrien      sav_ofs = 0;
500190075Sobrien      sav_scale = 4;
5002132718Skan      size = 4;
500396263Sobrien      rsize = 1;
500490075Sobrien    }
5005132718Skan  else if (TARGET_HARD_FLOAT && TARGET_FPRS
5006132718Skan	   && (TYPE_MODE (type) == SFmode || TYPE_MODE (type) == DFmode))
500790075Sobrien    {
500890075Sobrien      /* FP args go in FP registers, if present.  */
500990075Sobrien      indirect_p = 0;
501090075Sobrien      reg = fpr;
501190075Sobrien      n_reg = 1;
501290075Sobrien      sav_ofs = 8*4;
501390075Sobrien      sav_scale = 8;
5014132718Skan      if (TYPE_MODE (type) == DFmode)
5015132718Skan	align = 8;
501690075Sobrien    }
501790075Sobrien  else
501890075Sobrien    {
501990075Sobrien      /* Otherwise into GP registers.  */
502090075Sobrien      indirect_p = 0;
502190075Sobrien      reg = gpr;
502290075Sobrien      n_reg = rsize;
502390075Sobrien      sav_ofs = 0;
502490075Sobrien      sav_scale = 4;
5025132718Skan      if (n_reg == 2)
5026132718Skan	align = 8;
502790075Sobrien    }
502890075Sobrien
5029132718Skan  /* Pull the value out of the saved registers....  */
503090075Sobrien
5031132718Skan  lab_over = NULL_RTX;
503290075Sobrien  addr_rtx = gen_reg_rtx (Pmode);
503390075Sobrien
5034132718Skan  /*  AltiVec vectors never go in registers when -mabi=altivec.  */
5035132718Skan  if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (TYPE_MODE (type)))
5036132718Skan    align = 16;
5037132718Skan  else
503896263Sobrien    {
5039132718Skan      lab_false = gen_label_rtx ();
5040132718Skan      lab_over = gen_label_rtx ();
504190075Sobrien
5042132718Skan      /* Long long and SPE vectors are aligned in the registers.
5043132718Skan	 As are any other 2 gpr item such as complex int due to a
5044132718Skan	 historical mistake.  */
5045132718Skan      u = reg;
5046132718Skan      if (n_reg == 2)
504796263Sobrien	{
504896263Sobrien	  u = build (BIT_AND_EXPR, TREE_TYPE (reg), reg,
504996263Sobrien		     build_int_2 (n_reg - 1, 0));
5050132718Skan	  u = build (POSTINCREMENT_EXPR, TREE_TYPE (reg), reg, u);
505196263Sobrien	  TREE_SIDE_EFFECTS (u) = 1;
505296263Sobrien	}
505396263Sobrien
5054132718Skan      emit_cmp_and_jump_insns
5055132718Skan	(expand_expr (u, NULL_RTX, QImode, EXPAND_NORMAL),
5056132718Skan	 GEN_INT (8 - n_reg + 1), GE, const1_rtx, QImode, 1,
5057132718Skan	 lab_false);
5058132718Skan
5059132718Skan      t = sav;
506096263Sobrien      if (sav_ofs)
506196263Sobrien	t = build (PLUS_EXPR, ptr_type_node, sav, build_int_2 (sav_ofs, 0));
506296263Sobrien
506396263Sobrien      u = build (POSTINCREMENT_EXPR, TREE_TYPE (reg), reg,
506496263Sobrien		 build_int_2 (n_reg, 0));
506590075Sobrien      TREE_SIDE_EFFECTS (u) = 1;
506690075Sobrien
506796263Sobrien      u = build1 (CONVERT_EXPR, integer_type_node, u);
506896263Sobrien      TREE_SIDE_EFFECTS (u) = 1;
506990075Sobrien
507096263Sobrien      u = build (MULT_EXPR, integer_type_node, u, build_int_2 (sav_scale, 0));
507196263Sobrien      TREE_SIDE_EFFECTS (u) = 1;
507290075Sobrien
507396263Sobrien      t = build (PLUS_EXPR, ptr_type_node, t, u);
507496263Sobrien      TREE_SIDE_EFFECTS (t) = 1;
507590075Sobrien
507696263Sobrien      r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
507796263Sobrien      if (r != addr_rtx)
507896263Sobrien	emit_move_insn (addr_rtx, r);
507990075Sobrien
508096263Sobrien      emit_jump_insn (gen_jump (lab_over));
508196263Sobrien      emit_barrier ();
5082132718Skan
5083132718Skan      emit_label (lab_false);
5084132718Skan      if (n_reg > 2)
5085132718Skan	{
5086132718Skan	  /* Ensure that we don't find any more args in regs.
5087132718Skan	     Alignment has taken care of the n_reg == 2 case.  */
5088132718Skan	  t = build (MODIFY_EXPR, TREE_TYPE (reg), reg, build_int_2 (8, 0));
5089132718Skan	  TREE_SIDE_EFFECTS (t) = 1;
5090132718Skan	  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
5091132718Skan	}
509296263Sobrien    }
509390075Sobrien
509490075Sobrien  /* ... otherwise out of the overflow area.  */
509590075Sobrien
509690075Sobrien  /* Care for on-stack alignment if needed.  */
5097132718Skan  t = ovf;
5098132718Skan  if (align != 1)
509990075Sobrien    {
5100132718Skan      t = build (PLUS_EXPR, TREE_TYPE (t), t, build_int_2 (align - 1, 0));
5101132718Skan      t = build (BIT_AND_EXPR, TREE_TYPE (t), t, build_int_2 (-align, -1));
510290075Sobrien    }
510390075Sobrien  t = save_expr (t);
510490075Sobrien
510590075Sobrien  r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
510690075Sobrien  if (r != addr_rtx)
510790075Sobrien    emit_move_insn (addr_rtx, r);
510890075Sobrien
510990075Sobrien  t = build (PLUS_EXPR, TREE_TYPE (t), t, build_int_2 (size, 0));
511090075Sobrien  t = build (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t);
511190075Sobrien  TREE_SIDE_EFFECTS (t) = 1;
511290075Sobrien  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
511390075Sobrien
5114132718Skan  if (lab_over)
5115132718Skan    emit_label (lab_over);
511690075Sobrien
511790075Sobrien  if (indirect_p)
511890075Sobrien    {
511990075Sobrien      r = gen_rtx_MEM (Pmode, addr_rtx);
512090075Sobrien      set_mem_alias_set (r, get_varargs_alias_set ());
512190075Sobrien      emit_move_insn (addr_rtx, r);
512290075Sobrien    }
512390075Sobrien
512490075Sobrien  return addr_rtx;
512590075Sobrien}
512690075Sobrien
512790075Sobrien/* Builtins.  */
512890075Sobrien
5129117395Skan#define def_builtin(MASK, NAME, TYPE, CODE)			\
5130117395Skando {								\
5131117395Skan  if ((MASK) & target_flags)					\
5132117395Skan    builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD,	\
5133117395Skan		      NULL, NULL_TREE);				\
513490075Sobrien} while (0)
513590075Sobrien
513690075Sobrien/* Simple ternary operations: VECd = foo (VECa, VECb, VECc).  */
513790075Sobrien
513890075Sobrienstatic const struct builtin_description bdesc_3arg[] =
513990075Sobrien{
514090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmaddfp, "__builtin_altivec_vmaddfp", ALTIVEC_BUILTIN_VMADDFP },
514190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmhaddshs, "__builtin_altivec_vmhaddshs", ALTIVEC_BUILTIN_VMHADDSHS },
514290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmhraddshs, "__builtin_altivec_vmhraddshs", ALTIVEC_BUILTIN_VMHRADDSHS },
514390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmladduhm, "__builtin_altivec_vmladduhm", ALTIVEC_BUILTIN_VMLADDUHM},
514490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmsumubm, "__builtin_altivec_vmsumubm", ALTIVEC_BUILTIN_VMSUMUBM },
514590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmsummbm, "__builtin_altivec_vmsummbm", ALTIVEC_BUILTIN_VMSUMMBM },
514690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmsumuhm, "__builtin_altivec_vmsumuhm", ALTIVEC_BUILTIN_VMSUMUHM },
514790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmsumshm, "__builtin_altivec_vmsumshm", ALTIVEC_BUILTIN_VMSUMSHM },
514890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmsumuhs, "__builtin_altivec_vmsumuhs", ALTIVEC_BUILTIN_VMSUMUHS },
514990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmsumshs, "__builtin_altivec_vmsumshs", ALTIVEC_BUILTIN_VMSUMSHS },
515090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vnmsubfp, "__builtin_altivec_vnmsubfp", ALTIVEC_BUILTIN_VNMSUBFP },
515190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vperm_4sf, "__builtin_altivec_vperm_4sf", ALTIVEC_BUILTIN_VPERM_4SF },
515290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vperm_4si, "__builtin_altivec_vperm_4si", ALTIVEC_BUILTIN_VPERM_4SI },
515390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vperm_8hi, "__builtin_altivec_vperm_8hi", ALTIVEC_BUILTIN_VPERM_8HI },
515490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vperm_16qi, "__builtin_altivec_vperm_16qi", ALTIVEC_BUILTIN_VPERM_16QI },
515590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsel_4sf, "__builtin_altivec_vsel_4sf", ALTIVEC_BUILTIN_VSEL_4SF },
515690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsel_4si, "__builtin_altivec_vsel_4si", ALTIVEC_BUILTIN_VSEL_4SI },
515790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsel_8hi, "__builtin_altivec_vsel_8hi", ALTIVEC_BUILTIN_VSEL_8HI },
515890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsel_16qi, "__builtin_altivec_vsel_16qi", ALTIVEC_BUILTIN_VSEL_16QI },
515990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsldoi_16qi, "__builtin_altivec_vsldoi_16qi", ALTIVEC_BUILTIN_VSLDOI_16QI },
516090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsldoi_8hi, "__builtin_altivec_vsldoi_8hi", ALTIVEC_BUILTIN_VSLDOI_8HI },
516190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsldoi_4si, "__builtin_altivec_vsldoi_4si", ALTIVEC_BUILTIN_VSLDOI_4SI },
516290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsldoi_4sf, "__builtin_altivec_vsldoi_4sf", ALTIVEC_BUILTIN_VSLDOI_4SF },
516390075Sobrien};
516490075Sobrien
516590075Sobrien/* DST operations: void foo (void *, const int, const char).  */
516690075Sobrien
516790075Sobrienstatic const struct builtin_description bdesc_dst[] =
516890075Sobrien{
516990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_dst, "__builtin_altivec_dst", ALTIVEC_BUILTIN_DST },
517090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_dstt, "__builtin_altivec_dstt", ALTIVEC_BUILTIN_DSTT },
517190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_dstst, "__builtin_altivec_dstst", ALTIVEC_BUILTIN_DSTST },
517290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_dststt, "__builtin_altivec_dststt", ALTIVEC_BUILTIN_DSTSTT }
517390075Sobrien};
517490075Sobrien
517590075Sobrien/* Simple binary operations: VECc = foo (VECa, VECb).  */
517690075Sobrien
5177117395Skanstatic struct builtin_description bdesc_2arg[] =
517890075Sobrien{
517990075Sobrien  { MASK_ALTIVEC, CODE_FOR_addv16qi3, "__builtin_altivec_vaddubm", ALTIVEC_BUILTIN_VADDUBM },
518090075Sobrien  { MASK_ALTIVEC, CODE_FOR_addv8hi3, "__builtin_altivec_vadduhm", ALTIVEC_BUILTIN_VADDUHM },
518190075Sobrien  { MASK_ALTIVEC, CODE_FOR_addv4si3, "__builtin_altivec_vadduwm", ALTIVEC_BUILTIN_VADDUWM },
518290075Sobrien  { MASK_ALTIVEC, CODE_FOR_addv4sf3, "__builtin_altivec_vaddfp", ALTIVEC_BUILTIN_VADDFP },
518390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vaddcuw, "__builtin_altivec_vaddcuw", ALTIVEC_BUILTIN_VADDCUW },
518490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vaddubs, "__builtin_altivec_vaddubs", ALTIVEC_BUILTIN_VADDUBS },
518590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vaddsbs, "__builtin_altivec_vaddsbs", ALTIVEC_BUILTIN_VADDSBS },
518690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vadduhs, "__builtin_altivec_vadduhs", ALTIVEC_BUILTIN_VADDUHS },
518790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vaddshs, "__builtin_altivec_vaddshs", ALTIVEC_BUILTIN_VADDSHS },
518890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vadduws, "__builtin_altivec_vadduws", ALTIVEC_BUILTIN_VADDUWS },
518990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vaddsws, "__builtin_altivec_vaddsws", ALTIVEC_BUILTIN_VADDSWS },
519090075Sobrien  { MASK_ALTIVEC, CODE_FOR_andv4si3, "__builtin_altivec_vand", ALTIVEC_BUILTIN_VAND },
519190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vandc, "__builtin_altivec_vandc", ALTIVEC_BUILTIN_VANDC },
519290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vavgub, "__builtin_altivec_vavgub", ALTIVEC_BUILTIN_VAVGUB },
519390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vavgsb, "__builtin_altivec_vavgsb", ALTIVEC_BUILTIN_VAVGSB },
519490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vavguh, "__builtin_altivec_vavguh", ALTIVEC_BUILTIN_VAVGUH },
519590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vavgsh, "__builtin_altivec_vavgsh", ALTIVEC_BUILTIN_VAVGSH },
519690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vavguw, "__builtin_altivec_vavguw", ALTIVEC_BUILTIN_VAVGUW },
519790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vavgsw, "__builtin_altivec_vavgsw", ALTIVEC_BUILTIN_VAVGSW },
519890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcfux, "__builtin_altivec_vcfux", ALTIVEC_BUILTIN_VCFUX },
519990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcfsx, "__builtin_altivec_vcfsx", ALTIVEC_BUILTIN_VCFSX },
520090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpbfp, "__builtin_altivec_vcmpbfp", ALTIVEC_BUILTIN_VCMPBFP },
520190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpequb, "__builtin_altivec_vcmpequb", ALTIVEC_BUILTIN_VCMPEQUB },
520290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpequh, "__builtin_altivec_vcmpequh", ALTIVEC_BUILTIN_VCMPEQUH },
520390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpequw, "__builtin_altivec_vcmpequw", ALTIVEC_BUILTIN_VCMPEQUW },
520490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpeqfp, "__builtin_altivec_vcmpeqfp", ALTIVEC_BUILTIN_VCMPEQFP },
520590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpgefp, "__builtin_altivec_vcmpgefp", ALTIVEC_BUILTIN_VCMPGEFP },
520690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpgtub, "__builtin_altivec_vcmpgtub", ALTIVEC_BUILTIN_VCMPGTUB },
520790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpgtsb, "__builtin_altivec_vcmpgtsb", ALTIVEC_BUILTIN_VCMPGTSB },
520890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpgtuh, "__builtin_altivec_vcmpgtuh", ALTIVEC_BUILTIN_VCMPGTUH },
520990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpgtsh, "__builtin_altivec_vcmpgtsh", ALTIVEC_BUILTIN_VCMPGTSH },
521090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpgtuw, "__builtin_altivec_vcmpgtuw", ALTIVEC_BUILTIN_VCMPGTUW },
521190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpgtsw, "__builtin_altivec_vcmpgtsw", ALTIVEC_BUILTIN_VCMPGTSW },
521290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpgtfp, "__builtin_altivec_vcmpgtfp", ALTIVEC_BUILTIN_VCMPGTFP },
521390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vctsxs, "__builtin_altivec_vctsxs", ALTIVEC_BUILTIN_VCTSXS },
521490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vctuxs, "__builtin_altivec_vctuxs", ALTIVEC_BUILTIN_VCTUXS },
521590075Sobrien  { MASK_ALTIVEC, CODE_FOR_umaxv16qi3, "__builtin_altivec_vmaxub", ALTIVEC_BUILTIN_VMAXUB },
521690075Sobrien  { MASK_ALTIVEC, CODE_FOR_smaxv16qi3, "__builtin_altivec_vmaxsb", ALTIVEC_BUILTIN_VMAXSB },
5217117395Skan  { MASK_ALTIVEC, CODE_FOR_umaxv8hi3, "__builtin_altivec_vmaxuh", ALTIVEC_BUILTIN_VMAXUH },
5218117395Skan  { MASK_ALTIVEC, CODE_FOR_smaxv8hi3, "__builtin_altivec_vmaxsh", ALTIVEC_BUILTIN_VMAXSH },
5219117395Skan  { MASK_ALTIVEC, CODE_FOR_umaxv4si3, "__builtin_altivec_vmaxuw", ALTIVEC_BUILTIN_VMAXUW },
5220117395Skan  { MASK_ALTIVEC, CODE_FOR_smaxv4si3, "__builtin_altivec_vmaxsw", ALTIVEC_BUILTIN_VMAXSW },
5221117395Skan  { MASK_ALTIVEC, CODE_FOR_smaxv4sf3, "__builtin_altivec_vmaxfp", ALTIVEC_BUILTIN_VMAXFP },
522290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmrghb, "__builtin_altivec_vmrghb", ALTIVEC_BUILTIN_VMRGHB },
522390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmrghh, "__builtin_altivec_vmrghh", ALTIVEC_BUILTIN_VMRGHH },
522490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmrghw, "__builtin_altivec_vmrghw", ALTIVEC_BUILTIN_VMRGHW },
522590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmrglb, "__builtin_altivec_vmrglb", ALTIVEC_BUILTIN_VMRGLB },
522690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmrglh, "__builtin_altivec_vmrglh", ALTIVEC_BUILTIN_VMRGLH },
522790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmrglw, "__builtin_altivec_vmrglw", ALTIVEC_BUILTIN_VMRGLW },
522890075Sobrien  { MASK_ALTIVEC, CODE_FOR_uminv16qi3, "__builtin_altivec_vminub", ALTIVEC_BUILTIN_VMINUB },
522990075Sobrien  { MASK_ALTIVEC, CODE_FOR_sminv16qi3, "__builtin_altivec_vminsb", ALTIVEC_BUILTIN_VMINSB },
523090075Sobrien  { MASK_ALTIVEC, CODE_FOR_uminv8hi3, "__builtin_altivec_vminuh", ALTIVEC_BUILTIN_VMINUH },
523190075Sobrien  { MASK_ALTIVEC, CODE_FOR_sminv8hi3, "__builtin_altivec_vminsh", ALTIVEC_BUILTIN_VMINSH },
523290075Sobrien  { MASK_ALTIVEC, CODE_FOR_uminv4si3, "__builtin_altivec_vminuw", ALTIVEC_BUILTIN_VMINUW },
523390075Sobrien  { MASK_ALTIVEC, CODE_FOR_sminv4si3, "__builtin_altivec_vminsw", ALTIVEC_BUILTIN_VMINSW },
523490075Sobrien  { MASK_ALTIVEC, CODE_FOR_sminv4sf3, "__builtin_altivec_vminfp", ALTIVEC_BUILTIN_VMINFP },
523590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmuleub, "__builtin_altivec_vmuleub", ALTIVEC_BUILTIN_VMULEUB },
523690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmulesb, "__builtin_altivec_vmulesb", ALTIVEC_BUILTIN_VMULESB },
523790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmuleuh, "__builtin_altivec_vmuleuh", ALTIVEC_BUILTIN_VMULEUH },
523890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmulesh, "__builtin_altivec_vmulesh", ALTIVEC_BUILTIN_VMULESH },
523990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmuloub, "__builtin_altivec_vmuloub", ALTIVEC_BUILTIN_VMULOUB },
524090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmulosb, "__builtin_altivec_vmulosb", ALTIVEC_BUILTIN_VMULOSB },
524190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmulouh, "__builtin_altivec_vmulouh", ALTIVEC_BUILTIN_VMULOUH },
524290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmulosh, "__builtin_altivec_vmulosh", ALTIVEC_BUILTIN_VMULOSH },
524390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vnor, "__builtin_altivec_vnor", ALTIVEC_BUILTIN_VNOR },
524490075Sobrien  { MASK_ALTIVEC, CODE_FOR_iorv4si3, "__builtin_altivec_vor", ALTIVEC_BUILTIN_VOR },
524590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkuhum, "__builtin_altivec_vpkuhum", ALTIVEC_BUILTIN_VPKUHUM },
524690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkuwum, "__builtin_altivec_vpkuwum", ALTIVEC_BUILTIN_VPKUWUM },
524790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkpx, "__builtin_altivec_vpkpx", ALTIVEC_BUILTIN_VPKPX },
524890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkuhss, "__builtin_altivec_vpkuhss", ALTIVEC_BUILTIN_VPKUHSS },
524990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkshss, "__builtin_altivec_vpkshss", ALTIVEC_BUILTIN_VPKSHSS },
525090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkuwss, "__builtin_altivec_vpkuwss", ALTIVEC_BUILTIN_VPKUWSS },
525190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkswss, "__builtin_altivec_vpkswss", ALTIVEC_BUILTIN_VPKSWSS },
525290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkuhus, "__builtin_altivec_vpkuhus", ALTIVEC_BUILTIN_VPKUHUS },
525390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkshus, "__builtin_altivec_vpkshus", ALTIVEC_BUILTIN_VPKSHUS },
525490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkuwus, "__builtin_altivec_vpkuwus", ALTIVEC_BUILTIN_VPKUWUS },
525590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkswus, "__builtin_altivec_vpkswus", ALTIVEC_BUILTIN_VPKSWUS },
525690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vrlb, "__builtin_altivec_vrlb", ALTIVEC_BUILTIN_VRLB },
525790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vrlh, "__builtin_altivec_vrlh", ALTIVEC_BUILTIN_VRLH },
525890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vrlw, "__builtin_altivec_vrlw", ALTIVEC_BUILTIN_VRLW },
525990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vslb, "__builtin_altivec_vslb", ALTIVEC_BUILTIN_VSLB },
526090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vslh, "__builtin_altivec_vslh", ALTIVEC_BUILTIN_VSLH },
526190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vslw, "__builtin_altivec_vslw", ALTIVEC_BUILTIN_VSLW },
526290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsl, "__builtin_altivec_vsl", ALTIVEC_BUILTIN_VSL },
526390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vslo, "__builtin_altivec_vslo", ALTIVEC_BUILTIN_VSLO },
526490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vspltb, "__builtin_altivec_vspltb", ALTIVEC_BUILTIN_VSPLTB },
526590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsplth, "__builtin_altivec_vsplth", ALTIVEC_BUILTIN_VSPLTH },
526690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vspltw, "__builtin_altivec_vspltw", ALTIVEC_BUILTIN_VSPLTW },
526790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsrb, "__builtin_altivec_vsrb", ALTIVEC_BUILTIN_VSRB },
526890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsrh, "__builtin_altivec_vsrh", ALTIVEC_BUILTIN_VSRH },
526990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsrw, "__builtin_altivec_vsrw", ALTIVEC_BUILTIN_VSRW },
527090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsrab, "__builtin_altivec_vsrab", ALTIVEC_BUILTIN_VSRAB },
527190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsrah, "__builtin_altivec_vsrah", ALTIVEC_BUILTIN_VSRAH },
527290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsraw, "__builtin_altivec_vsraw", ALTIVEC_BUILTIN_VSRAW },
527390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsr, "__builtin_altivec_vsr", ALTIVEC_BUILTIN_VSR },
527490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsro, "__builtin_altivec_vsro", ALTIVEC_BUILTIN_VSRO },
527590075Sobrien  { MASK_ALTIVEC, CODE_FOR_subv16qi3, "__builtin_altivec_vsububm", ALTIVEC_BUILTIN_VSUBUBM },
527690075Sobrien  { MASK_ALTIVEC, CODE_FOR_subv8hi3, "__builtin_altivec_vsubuhm", ALTIVEC_BUILTIN_VSUBUHM },
527790075Sobrien  { MASK_ALTIVEC, CODE_FOR_subv4si3, "__builtin_altivec_vsubuwm", ALTIVEC_BUILTIN_VSUBUWM },
527890075Sobrien  { MASK_ALTIVEC, CODE_FOR_subv4sf3, "__builtin_altivec_vsubfp", ALTIVEC_BUILTIN_VSUBFP },
527990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsubcuw, "__builtin_altivec_vsubcuw", ALTIVEC_BUILTIN_VSUBCUW },
528090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsububs, "__builtin_altivec_vsububs", ALTIVEC_BUILTIN_VSUBUBS },
528190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsubsbs, "__builtin_altivec_vsubsbs", ALTIVEC_BUILTIN_VSUBSBS },
528290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsubuhs, "__builtin_altivec_vsubuhs", ALTIVEC_BUILTIN_VSUBUHS },
528390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsubshs, "__builtin_altivec_vsubshs", ALTIVEC_BUILTIN_VSUBSHS },
528490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsubuws, "__builtin_altivec_vsubuws", ALTIVEC_BUILTIN_VSUBUWS },
528590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsubsws, "__builtin_altivec_vsubsws", ALTIVEC_BUILTIN_VSUBSWS },
528690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsum4ubs, "__builtin_altivec_vsum4ubs", ALTIVEC_BUILTIN_VSUM4UBS },
528790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsum4sbs, "__builtin_altivec_vsum4sbs", ALTIVEC_BUILTIN_VSUM4SBS },
528890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsum4shs, "__builtin_altivec_vsum4shs", ALTIVEC_BUILTIN_VSUM4SHS },
528990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsum2sws, "__builtin_altivec_vsum2sws", ALTIVEC_BUILTIN_VSUM2SWS },
529090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsumsws, "__builtin_altivec_vsumsws", ALTIVEC_BUILTIN_VSUMSWS },
529190075Sobrien  { MASK_ALTIVEC, CODE_FOR_xorv4si3, "__builtin_altivec_vxor", ALTIVEC_BUILTIN_VXOR },
5292117395Skan
5293117395Skan  /* Place holder, leave as first spe builtin.  */
5294117395Skan  { 0, CODE_FOR_spe_evaddw, "__builtin_spe_evaddw", SPE_BUILTIN_EVADDW },
5295117395Skan  { 0, CODE_FOR_spe_evand, "__builtin_spe_evand", SPE_BUILTIN_EVAND },
5296117395Skan  { 0, CODE_FOR_spe_evandc, "__builtin_spe_evandc", SPE_BUILTIN_EVANDC },
5297117395Skan  { 0, CODE_FOR_spe_evdivws, "__builtin_spe_evdivws", SPE_BUILTIN_EVDIVWS },
5298117395Skan  { 0, CODE_FOR_spe_evdivwu, "__builtin_spe_evdivwu", SPE_BUILTIN_EVDIVWU },
5299117395Skan  { 0, CODE_FOR_spe_eveqv, "__builtin_spe_eveqv", SPE_BUILTIN_EVEQV },
5300117395Skan  { 0, CODE_FOR_spe_evfsadd, "__builtin_spe_evfsadd", SPE_BUILTIN_EVFSADD },
5301117395Skan  { 0, CODE_FOR_spe_evfsdiv, "__builtin_spe_evfsdiv", SPE_BUILTIN_EVFSDIV },
5302117395Skan  { 0, CODE_FOR_spe_evfsmul, "__builtin_spe_evfsmul", SPE_BUILTIN_EVFSMUL },
5303117395Skan  { 0, CODE_FOR_spe_evfssub, "__builtin_spe_evfssub", SPE_BUILTIN_EVFSSUB },
5304117395Skan  { 0, CODE_FOR_spe_evmergehi, "__builtin_spe_evmergehi", SPE_BUILTIN_EVMERGEHI },
5305117395Skan  { 0, CODE_FOR_spe_evmergehilo, "__builtin_spe_evmergehilo", SPE_BUILTIN_EVMERGEHILO },
5306117395Skan  { 0, CODE_FOR_spe_evmergelo, "__builtin_spe_evmergelo", SPE_BUILTIN_EVMERGELO },
5307117395Skan  { 0, CODE_FOR_spe_evmergelohi, "__builtin_spe_evmergelohi", SPE_BUILTIN_EVMERGELOHI },
5308117395Skan  { 0, CODE_FOR_spe_evmhegsmfaa, "__builtin_spe_evmhegsmfaa", SPE_BUILTIN_EVMHEGSMFAA },
5309117395Skan  { 0, CODE_FOR_spe_evmhegsmfan, "__builtin_spe_evmhegsmfan", SPE_BUILTIN_EVMHEGSMFAN },
5310117395Skan  { 0, CODE_FOR_spe_evmhegsmiaa, "__builtin_spe_evmhegsmiaa", SPE_BUILTIN_EVMHEGSMIAA },
5311117395Skan  { 0, CODE_FOR_spe_evmhegsmian, "__builtin_spe_evmhegsmian", SPE_BUILTIN_EVMHEGSMIAN },
5312117395Skan  { 0, CODE_FOR_spe_evmhegumiaa, "__builtin_spe_evmhegumiaa", SPE_BUILTIN_EVMHEGUMIAA },
5313117395Skan  { 0, CODE_FOR_spe_evmhegumian, "__builtin_spe_evmhegumian", SPE_BUILTIN_EVMHEGUMIAN },
5314117395Skan  { 0, CODE_FOR_spe_evmhesmf, "__builtin_spe_evmhesmf", SPE_BUILTIN_EVMHESMF },
5315117395Skan  { 0, CODE_FOR_spe_evmhesmfa, "__builtin_spe_evmhesmfa", SPE_BUILTIN_EVMHESMFA },
5316117395Skan  { 0, CODE_FOR_spe_evmhesmfaaw, "__builtin_spe_evmhesmfaaw", SPE_BUILTIN_EVMHESMFAAW },
5317117395Skan  { 0, CODE_FOR_spe_evmhesmfanw, "__builtin_spe_evmhesmfanw", SPE_BUILTIN_EVMHESMFANW },
5318117395Skan  { 0, CODE_FOR_spe_evmhesmi, "__builtin_spe_evmhesmi", SPE_BUILTIN_EVMHESMI },
5319117395Skan  { 0, CODE_FOR_spe_evmhesmia, "__builtin_spe_evmhesmia", SPE_BUILTIN_EVMHESMIA },
5320117395Skan  { 0, CODE_FOR_spe_evmhesmiaaw, "__builtin_spe_evmhesmiaaw", SPE_BUILTIN_EVMHESMIAAW },
5321117395Skan  { 0, CODE_FOR_spe_evmhesmianw, "__builtin_spe_evmhesmianw", SPE_BUILTIN_EVMHESMIANW },
5322117395Skan  { 0, CODE_FOR_spe_evmhessf, "__builtin_spe_evmhessf", SPE_BUILTIN_EVMHESSF },
5323117395Skan  { 0, CODE_FOR_spe_evmhessfa, "__builtin_spe_evmhessfa", SPE_BUILTIN_EVMHESSFA },
5324117395Skan  { 0, CODE_FOR_spe_evmhessfaaw, "__builtin_spe_evmhessfaaw", SPE_BUILTIN_EVMHESSFAAW },
5325117395Skan  { 0, CODE_FOR_spe_evmhessfanw, "__builtin_spe_evmhessfanw", SPE_BUILTIN_EVMHESSFANW },
5326117395Skan  { 0, CODE_FOR_spe_evmhessiaaw, "__builtin_spe_evmhessiaaw", SPE_BUILTIN_EVMHESSIAAW },
5327117395Skan  { 0, CODE_FOR_spe_evmhessianw, "__builtin_spe_evmhessianw", SPE_BUILTIN_EVMHESSIANW },
5328117395Skan  { 0, CODE_FOR_spe_evmheumi, "__builtin_spe_evmheumi", SPE_BUILTIN_EVMHEUMI },
5329117395Skan  { 0, CODE_FOR_spe_evmheumia, "__builtin_spe_evmheumia", SPE_BUILTIN_EVMHEUMIA },
5330117395Skan  { 0, CODE_FOR_spe_evmheumiaaw, "__builtin_spe_evmheumiaaw", SPE_BUILTIN_EVMHEUMIAAW },
5331117395Skan  { 0, CODE_FOR_spe_evmheumianw, "__builtin_spe_evmheumianw", SPE_BUILTIN_EVMHEUMIANW },
5332117395Skan  { 0, CODE_FOR_spe_evmheusiaaw, "__builtin_spe_evmheusiaaw", SPE_BUILTIN_EVMHEUSIAAW },
5333117395Skan  { 0, CODE_FOR_spe_evmheusianw, "__builtin_spe_evmheusianw", SPE_BUILTIN_EVMHEUSIANW },
5334117395Skan  { 0, CODE_FOR_spe_evmhogsmfaa, "__builtin_spe_evmhogsmfaa", SPE_BUILTIN_EVMHOGSMFAA },
5335117395Skan  { 0, CODE_FOR_spe_evmhogsmfan, "__builtin_spe_evmhogsmfan", SPE_BUILTIN_EVMHOGSMFAN },
5336117395Skan  { 0, CODE_FOR_spe_evmhogsmiaa, "__builtin_spe_evmhogsmiaa", SPE_BUILTIN_EVMHOGSMIAA },
5337117395Skan  { 0, CODE_FOR_spe_evmhogsmian, "__builtin_spe_evmhogsmian", SPE_BUILTIN_EVMHOGSMIAN },
5338117395Skan  { 0, CODE_FOR_spe_evmhogumiaa, "__builtin_spe_evmhogumiaa", SPE_BUILTIN_EVMHOGUMIAA },
5339117395Skan  { 0, CODE_FOR_spe_evmhogumian, "__builtin_spe_evmhogumian", SPE_BUILTIN_EVMHOGUMIAN },
5340117395Skan  { 0, CODE_FOR_spe_evmhosmf, "__builtin_spe_evmhosmf", SPE_BUILTIN_EVMHOSMF },
5341117395Skan  { 0, CODE_FOR_spe_evmhosmfa, "__builtin_spe_evmhosmfa", SPE_BUILTIN_EVMHOSMFA },
5342117395Skan  { 0, CODE_FOR_spe_evmhosmfaaw, "__builtin_spe_evmhosmfaaw", SPE_BUILTIN_EVMHOSMFAAW },
5343117395Skan  { 0, CODE_FOR_spe_evmhosmfanw, "__builtin_spe_evmhosmfanw", SPE_BUILTIN_EVMHOSMFANW },
5344117395Skan  { 0, CODE_FOR_spe_evmhosmi, "__builtin_spe_evmhosmi", SPE_BUILTIN_EVMHOSMI },
5345117395Skan  { 0, CODE_FOR_spe_evmhosmia, "__builtin_spe_evmhosmia", SPE_BUILTIN_EVMHOSMIA },
5346117395Skan  { 0, CODE_FOR_spe_evmhosmiaaw, "__builtin_spe_evmhosmiaaw", SPE_BUILTIN_EVMHOSMIAAW },
5347117395Skan  { 0, CODE_FOR_spe_evmhosmianw, "__builtin_spe_evmhosmianw", SPE_BUILTIN_EVMHOSMIANW },
5348117395Skan  { 0, CODE_FOR_spe_evmhossf, "__builtin_spe_evmhossf", SPE_BUILTIN_EVMHOSSF },
5349117395Skan  { 0, CODE_FOR_spe_evmhossfa, "__builtin_spe_evmhossfa", SPE_BUILTIN_EVMHOSSFA },
5350117395Skan  { 0, CODE_FOR_spe_evmhossfaaw, "__builtin_spe_evmhossfaaw", SPE_BUILTIN_EVMHOSSFAAW },
5351117395Skan  { 0, CODE_FOR_spe_evmhossfanw, "__builtin_spe_evmhossfanw", SPE_BUILTIN_EVMHOSSFANW },
5352117395Skan  { 0, CODE_FOR_spe_evmhossiaaw, "__builtin_spe_evmhossiaaw", SPE_BUILTIN_EVMHOSSIAAW },
5353117395Skan  { 0, CODE_FOR_spe_evmhossianw, "__builtin_spe_evmhossianw", SPE_BUILTIN_EVMHOSSIANW },
5354117395Skan  { 0, CODE_FOR_spe_evmhoumi, "__builtin_spe_evmhoumi", SPE_BUILTIN_EVMHOUMI },
5355117395Skan  { 0, CODE_FOR_spe_evmhoumia, "__builtin_spe_evmhoumia", SPE_BUILTIN_EVMHOUMIA },
5356117395Skan  { 0, CODE_FOR_spe_evmhoumiaaw, "__builtin_spe_evmhoumiaaw", SPE_BUILTIN_EVMHOUMIAAW },
5357117395Skan  { 0, CODE_FOR_spe_evmhoumianw, "__builtin_spe_evmhoumianw", SPE_BUILTIN_EVMHOUMIANW },
5358117395Skan  { 0, CODE_FOR_spe_evmhousiaaw, "__builtin_spe_evmhousiaaw", SPE_BUILTIN_EVMHOUSIAAW },
5359117395Skan  { 0, CODE_FOR_spe_evmhousianw, "__builtin_spe_evmhousianw", SPE_BUILTIN_EVMHOUSIANW },
5360117395Skan  { 0, CODE_FOR_spe_evmwhsmf, "__builtin_spe_evmwhsmf", SPE_BUILTIN_EVMWHSMF },
5361117395Skan  { 0, CODE_FOR_spe_evmwhsmfa, "__builtin_spe_evmwhsmfa", SPE_BUILTIN_EVMWHSMFA },
5362117395Skan  { 0, CODE_FOR_spe_evmwhsmi, "__builtin_spe_evmwhsmi", SPE_BUILTIN_EVMWHSMI },
5363117395Skan  { 0, CODE_FOR_spe_evmwhsmia, "__builtin_spe_evmwhsmia", SPE_BUILTIN_EVMWHSMIA },
5364117395Skan  { 0, CODE_FOR_spe_evmwhssf, "__builtin_spe_evmwhssf", SPE_BUILTIN_EVMWHSSF },
5365117395Skan  { 0, CODE_FOR_spe_evmwhssfa, "__builtin_spe_evmwhssfa", SPE_BUILTIN_EVMWHSSFA },
5366117395Skan  { 0, CODE_FOR_spe_evmwhumi, "__builtin_spe_evmwhumi", SPE_BUILTIN_EVMWHUMI },
5367117395Skan  { 0, CODE_FOR_spe_evmwhumia, "__builtin_spe_evmwhumia", SPE_BUILTIN_EVMWHUMIA },
5368117395Skan  { 0, CODE_FOR_spe_evmwlsmiaaw, "__builtin_spe_evmwlsmiaaw", SPE_BUILTIN_EVMWLSMIAAW },
5369117395Skan  { 0, CODE_FOR_spe_evmwlsmianw, "__builtin_spe_evmwlsmianw", SPE_BUILTIN_EVMWLSMIANW },
5370117395Skan  { 0, CODE_FOR_spe_evmwlssiaaw, "__builtin_spe_evmwlssiaaw", SPE_BUILTIN_EVMWLSSIAAW },
5371117395Skan  { 0, CODE_FOR_spe_evmwlssianw, "__builtin_spe_evmwlssianw", SPE_BUILTIN_EVMWLSSIANW },
5372117395Skan  { 0, CODE_FOR_spe_evmwlumi, "__builtin_spe_evmwlumi", SPE_BUILTIN_EVMWLUMI },
5373117395Skan  { 0, CODE_FOR_spe_evmwlumia, "__builtin_spe_evmwlumia", SPE_BUILTIN_EVMWLUMIA },
5374117395Skan  { 0, CODE_FOR_spe_evmwlumiaaw, "__builtin_spe_evmwlumiaaw", SPE_BUILTIN_EVMWLUMIAAW },
5375117395Skan  { 0, CODE_FOR_spe_evmwlumianw, "__builtin_spe_evmwlumianw", SPE_BUILTIN_EVMWLUMIANW },
5376117395Skan  { 0, CODE_FOR_spe_evmwlusiaaw, "__builtin_spe_evmwlusiaaw", SPE_BUILTIN_EVMWLUSIAAW },
5377117395Skan  { 0, CODE_FOR_spe_evmwlusianw, "__builtin_spe_evmwlusianw", SPE_BUILTIN_EVMWLUSIANW },
5378117395Skan  { 0, CODE_FOR_spe_evmwsmf, "__builtin_spe_evmwsmf", SPE_BUILTIN_EVMWSMF },
5379117395Skan  { 0, CODE_FOR_spe_evmwsmfa, "__builtin_spe_evmwsmfa", SPE_BUILTIN_EVMWSMFA },
5380117395Skan  { 0, CODE_FOR_spe_evmwsmfaa, "__builtin_spe_evmwsmfaa", SPE_BUILTIN_EVMWSMFAA },
5381117395Skan  { 0, CODE_FOR_spe_evmwsmfan, "__builtin_spe_evmwsmfan", SPE_BUILTIN_EVMWSMFAN },
5382117395Skan  { 0, CODE_FOR_spe_evmwsmi, "__builtin_spe_evmwsmi", SPE_BUILTIN_EVMWSMI },
5383117395Skan  { 0, CODE_FOR_spe_evmwsmia, "__builtin_spe_evmwsmia", SPE_BUILTIN_EVMWSMIA },
5384117395Skan  { 0, CODE_FOR_spe_evmwsmiaa, "__builtin_spe_evmwsmiaa", SPE_BUILTIN_EVMWSMIAA },
5385117395Skan  { 0, CODE_FOR_spe_evmwsmian, "__builtin_spe_evmwsmian", SPE_BUILTIN_EVMWSMIAN },
5386117395Skan  { 0, CODE_FOR_spe_evmwssf, "__builtin_spe_evmwssf", SPE_BUILTIN_EVMWSSF },
5387117395Skan  { 0, CODE_FOR_spe_evmwssfa, "__builtin_spe_evmwssfa", SPE_BUILTIN_EVMWSSFA },
5388117395Skan  { 0, CODE_FOR_spe_evmwssfaa, "__builtin_spe_evmwssfaa", SPE_BUILTIN_EVMWSSFAA },
5389117395Skan  { 0, CODE_FOR_spe_evmwssfan, "__builtin_spe_evmwssfan", SPE_BUILTIN_EVMWSSFAN },
5390117395Skan  { 0, CODE_FOR_spe_evmwumi, "__builtin_spe_evmwumi", SPE_BUILTIN_EVMWUMI },
5391117395Skan  { 0, CODE_FOR_spe_evmwumia, "__builtin_spe_evmwumia", SPE_BUILTIN_EVMWUMIA },
5392117395Skan  { 0, CODE_FOR_spe_evmwumiaa, "__builtin_spe_evmwumiaa", SPE_BUILTIN_EVMWUMIAA },
5393117395Skan  { 0, CODE_FOR_spe_evmwumian, "__builtin_spe_evmwumian", SPE_BUILTIN_EVMWUMIAN },
5394117395Skan  { 0, CODE_FOR_spe_evnand, "__builtin_spe_evnand", SPE_BUILTIN_EVNAND },
5395117395Skan  { 0, CODE_FOR_spe_evnor, "__builtin_spe_evnor", SPE_BUILTIN_EVNOR },
5396117395Skan  { 0, CODE_FOR_spe_evor, "__builtin_spe_evor", SPE_BUILTIN_EVOR },
5397117395Skan  { 0, CODE_FOR_spe_evorc, "__builtin_spe_evorc", SPE_BUILTIN_EVORC },
5398117395Skan  { 0, CODE_FOR_spe_evrlw, "__builtin_spe_evrlw", SPE_BUILTIN_EVRLW },
5399117395Skan  { 0, CODE_FOR_spe_evslw, "__builtin_spe_evslw", SPE_BUILTIN_EVSLW },
5400117395Skan  { 0, CODE_FOR_spe_evsrws, "__builtin_spe_evsrws", SPE_BUILTIN_EVSRWS },
5401117395Skan  { 0, CODE_FOR_spe_evsrwu, "__builtin_spe_evsrwu", SPE_BUILTIN_EVSRWU },
5402117395Skan  { 0, CODE_FOR_spe_evsubfw, "__builtin_spe_evsubfw", SPE_BUILTIN_EVSUBFW },
5403117395Skan
5404117395Skan  /* SPE binary operations expecting a 5-bit unsigned literal.  */
5405117395Skan  { 0, CODE_FOR_spe_evaddiw, "__builtin_spe_evaddiw", SPE_BUILTIN_EVADDIW },
5406117395Skan
5407117395Skan  { 0, CODE_FOR_spe_evrlwi, "__builtin_spe_evrlwi", SPE_BUILTIN_EVRLWI },
5408117395Skan  { 0, CODE_FOR_spe_evslwi, "__builtin_spe_evslwi", SPE_BUILTIN_EVSLWI },
5409117395Skan  { 0, CODE_FOR_spe_evsrwis, "__builtin_spe_evsrwis", SPE_BUILTIN_EVSRWIS },
5410117395Skan  { 0, CODE_FOR_spe_evsrwiu, "__builtin_spe_evsrwiu", SPE_BUILTIN_EVSRWIU },
5411117395Skan  { 0, CODE_FOR_spe_evsubifw, "__builtin_spe_evsubifw", SPE_BUILTIN_EVSUBIFW },
5412117395Skan  { 0, CODE_FOR_spe_evmwhssfaa, "__builtin_spe_evmwhssfaa", SPE_BUILTIN_EVMWHSSFAA },
5413117395Skan  { 0, CODE_FOR_spe_evmwhssmaa, "__builtin_spe_evmwhssmaa", SPE_BUILTIN_EVMWHSSMAA },
5414117395Skan  { 0, CODE_FOR_spe_evmwhsmfaa, "__builtin_spe_evmwhsmfaa", SPE_BUILTIN_EVMWHSMFAA },
5415117395Skan  { 0, CODE_FOR_spe_evmwhsmiaa, "__builtin_spe_evmwhsmiaa", SPE_BUILTIN_EVMWHSMIAA },
5416117395Skan  { 0, CODE_FOR_spe_evmwhusiaa, "__builtin_spe_evmwhusiaa", SPE_BUILTIN_EVMWHUSIAA },
5417117395Skan  { 0, CODE_FOR_spe_evmwhumiaa, "__builtin_spe_evmwhumiaa", SPE_BUILTIN_EVMWHUMIAA },
5418117395Skan  { 0, CODE_FOR_spe_evmwhssfan, "__builtin_spe_evmwhssfan", SPE_BUILTIN_EVMWHSSFAN },
5419117395Skan  { 0, CODE_FOR_spe_evmwhssian, "__builtin_spe_evmwhssian", SPE_BUILTIN_EVMWHSSIAN },
5420117395Skan  { 0, CODE_FOR_spe_evmwhsmfan, "__builtin_spe_evmwhsmfan", SPE_BUILTIN_EVMWHSMFAN },
5421117395Skan  { 0, CODE_FOR_spe_evmwhsmian, "__builtin_spe_evmwhsmian", SPE_BUILTIN_EVMWHSMIAN },
5422117395Skan  { 0, CODE_FOR_spe_evmwhusian, "__builtin_spe_evmwhusian", SPE_BUILTIN_EVMWHUSIAN },
5423117395Skan  { 0, CODE_FOR_spe_evmwhumian, "__builtin_spe_evmwhumian", SPE_BUILTIN_EVMWHUMIAN },
5424117395Skan  { 0, CODE_FOR_spe_evmwhgssfaa, "__builtin_spe_evmwhgssfaa", SPE_BUILTIN_EVMWHGSSFAA },
5425117395Skan  { 0, CODE_FOR_spe_evmwhgsmfaa, "__builtin_spe_evmwhgsmfaa", SPE_BUILTIN_EVMWHGSMFAA },
5426117395Skan  { 0, CODE_FOR_spe_evmwhgsmiaa, "__builtin_spe_evmwhgsmiaa", SPE_BUILTIN_EVMWHGSMIAA },
5427117395Skan  { 0, CODE_FOR_spe_evmwhgumiaa, "__builtin_spe_evmwhgumiaa", SPE_BUILTIN_EVMWHGUMIAA },
5428117395Skan  { 0, CODE_FOR_spe_evmwhgssfan, "__builtin_spe_evmwhgssfan", SPE_BUILTIN_EVMWHGSSFAN },
5429117395Skan  { 0, CODE_FOR_spe_evmwhgsmfan, "__builtin_spe_evmwhgsmfan", SPE_BUILTIN_EVMWHGSMFAN },
5430117395Skan  { 0, CODE_FOR_spe_evmwhgsmian, "__builtin_spe_evmwhgsmian", SPE_BUILTIN_EVMWHGSMIAN },
5431117395Skan  { 0, CODE_FOR_spe_evmwhgumian, "__builtin_spe_evmwhgumian", SPE_BUILTIN_EVMWHGUMIAN },
5432117395Skan  { 0, CODE_FOR_spe_brinc, "__builtin_spe_brinc", SPE_BUILTIN_BRINC },
5433117395Skan
5434117395Skan  /* Place-holder.  Leave as last binary SPE builtin.  */
5435132718Skan  { 0, CODE_FOR_xorv2si3, "__builtin_spe_evxor", SPE_BUILTIN_EVXOR },
543690075Sobrien};
543790075Sobrien
543896263Sobrien/* AltiVec predicates.  */
543996263Sobrien
544096263Sobrienstruct builtin_description_predicates
544196263Sobrien{
544296263Sobrien  const unsigned int mask;
544396263Sobrien  const enum insn_code icode;
544496263Sobrien  const char *opcode;
544596263Sobrien  const char *const name;
544696263Sobrien  const enum rs6000_builtins code;
544796263Sobrien};
544896263Sobrien
544996263Sobrienstatic const struct builtin_description_predicates bdesc_altivec_preds[] =
545096263Sobrien{
545196263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v4sf, "*vcmpbfp.", "__builtin_altivec_vcmpbfp_p", ALTIVEC_BUILTIN_VCMPBFP_P },
545296263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v4sf, "*vcmpeqfp.", "__builtin_altivec_vcmpeqfp_p", ALTIVEC_BUILTIN_VCMPEQFP_P },
545396263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v4sf, "*vcmpgefp.", "__builtin_altivec_vcmpgefp_p", ALTIVEC_BUILTIN_VCMPGEFP_P },
545496263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v4sf, "*vcmpgtfp.", "__builtin_altivec_vcmpgtfp_p", ALTIVEC_BUILTIN_VCMPGTFP_P },
545596263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v4si, "*vcmpequw.", "__builtin_altivec_vcmpequw_p", ALTIVEC_BUILTIN_VCMPEQUW_P },
545696263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v4si, "*vcmpgtsw.", "__builtin_altivec_vcmpgtsw_p", ALTIVEC_BUILTIN_VCMPGTSW_P },
545796263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v4si, "*vcmpgtuw.", "__builtin_altivec_vcmpgtuw_p", ALTIVEC_BUILTIN_VCMPGTUW_P },
545896263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v8hi, "*vcmpgtuh.", "__builtin_altivec_vcmpgtuh_p", ALTIVEC_BUILTIN_VCMPGTUH_P },
545996263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v8hi, "*vcmpgtsh.", "__builtin_altivec_vcmpgtsh_p", ALTIVEC_BUILTIN_VCMPGTSH_P },
546096263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v8hi, "*vcmpequh.", "__builtin_altivec_vcmpequh_p", ALTIVEC_BUILTIN_VCMPEQUH_P },
546196263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v16qi, "*vcmpequb.", "__builtin_altivec_vcmpequb_p", ALTIVEC_BUILTIN_VCMPEQUB_P },
546296263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v16qi, "*vcmpgtsb.", "__builtin_altivec_vcmpgtsb_p", ALTIVEC_BUILTIN_VCMPGTSB_P },
546396263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v16qi, "*vcmpgtub.", "__builtin_altivec_vcmpgtub_p", ALTIVEC_BUILTIN_VCMPGTUB_P }
546496263Sobrien};
546596263Sobrien
5466117395Skan/* SPE predicates.  */
5467117395Skanstatic struct builtin_description bdesc_spe_predicates[] =
5468117395Skan{
5469117395Skan  /* Place-holder.  Leave as first.  */
5470117395Skan  { 0, CODE_FOR_spe_evcmpeq, "__builtin_spe_evcmpeq", SPE_BUILTIN_EVCMPEQ },
5471117395Skan  { 0, CODE_FOR_spe_evcmpgts, "__builtin_spe_evcmpgts", SPE_BUILTIN_EVCMPGTS },
5472117395Skan  { 0, CODE_FOR_spe_evcmpgtu, "__builtin_spe_evcmpgtu", SPE_BUILTIN_EVCMPGTU },
5473117395Skan  { 0, CODE_FOR_spe_evcmplts, "__builtin_spe_evcmplts", SPE_BUILTIN_EVCMPLTS },
5474117395Skan  { 0, CODE_FOR_spe_evcmpltu, "__builtin_spe_evcmpltu", SPE_BUILTIN_EVCMPLTU },
5475117395Skan  { 0, CODE_FOR_spe_evfscmpeq, "__builtin_spe_evfscmpeq", SPE_BUILTIN_EVFSCMPEQ },
5476117395Skan  { 0, CODE_FOR_spe_evfscmpgt, "__builtin_spe_evfscmpgt", SPE_BUILTIN_EVFSCMPGT },
5477117395Skan  { 0, CODE_FOR_spe_evfscmplt, "__builtin_spe_evfscmplt", SPE_BUILTIN_EVFSCMPLT },
5478117395Skan  { 0, CODE_FOR_spe_evfststeq, "__builtin_spe_evfststeq", SPE_BUILTIN_EVFSTSTEQ },
5479117395Skan  { 0, CODE_FOR_spe_evfststgt, "__builtin_spe_evfststgt", SPE_BUILTIN_EVFSTSTGT },
5480117395Skan  /* Place-holder.  Leave as last.  */
5481117395Skan  { 0, CODE_FOR_spe_evfststlt, "__builtin_spe_evfststlt", SPE_BUILTIN_EVFSTSTLT },
5482117395Skan};
5483117395Skan
5484117395Skan/* SPE evsel predicates.  */
5485117395Skanstatic struct builtin_description bdesc_spe_evsel[] =
5486117395Skan{
5487117395Skan  /* Place-holder.  Leave as first.  */
5488117395Skan  { 0, CODE_FOR_spe_evcmpgts, "__builtin_spe_evsel_gts", SPE_BUILTIN_EVSEL_CMPGTS },
5489117395Skan  { 0, CODE_FOR_spe_evcmpgtu, "__builtin_spe_evsel_gtu", SPE_BUILTIN_EVSEL_CMPGTU },
5490117395Skan  { 0, CODE_FOR_spe_evcmplts, "__builtin_spe_evsel_lts", SPE_BUILTIN_EVSEL_CMPLTS },
5491117395Skan  { 0, CODE_FOR_spe_evcmpltu, "__builtin_spe_evsel_ltu", SPE_BUILTIN_EVSEL_CMPLTU },
5492117395Skan  { 0, CODE_FOR_spe_evcmpeq, "__builtin_spe_evsel_eq", SPE_BUILTIN_EVSEL_CMPEQ },
5493117395Skan  { 0, CODE_FOR_spe_evfscmpgt, "__builtin_spe_evsel_fsgt", SPE_BUILTIN_EVSEL_FSCMPGT },
5494117395Skan  { 0, CODE_FOR_spe_evfscmplt, "__builtin_spe_evsel_fslt", SPE_BUILTIN_EVSEL_FSCMPLT },
5495117395Skan  { 0, CODE_FOR_spe_evfscmpeq, "__builtin_spe_evsel_fseq", SPE_BUILTIN_EVSEL_FSCMPEQ },
5496117395Skan  { 0, CODE_FOR_spe_evfststgt, "__builtin_spe_evsel_fststgt", SPE_BUILTIN_EVSEL_FSTSTGT },
5497117395Skan  { 0, CODE_FOR_spe_evfststlt, "__builtin_spe_evsel_fststlt", SPE_BUILTIN_EVSEL_FSTSTLT },
5498117395Skan  /* Place-holder.  Leave as last.  */
5499117395Skan  { 0, CODE_FOR_spe_evfststeq, "__builtin_spe_evsel_fststeq", SPE_BUILTIN_EVSEL_FSTSTEQ },
5500117395Skan};
5501117395Skan
5502132718Skan/* ABS* operations.  */
550396263Sobrien
550496263Sobrienstatic const struct builtin_description bdesc_abs[] =
550596263Sobrien{
550696263Sobrien  { MASK_ALTIVEC, CODE_FOR_absv4si2, "__builtin_altivec_abs_v4si", ALTIVEC_BUILTIN_ABS_V4SI },
550796263Sobrien  { MASK_ALTIVEC, CODE_FOR_absv8hi2, "__builtin_altivec_abs_v8hi", ALTIVEC_BUILTIN_ABS_V8HI },
550896263Sobrien  { MASK_ALTIVEC, CODE_FOR_absv4sf2, "__builtin_altivec_abs_v4sf", ALTIVEC_BUILTIN_ABS_V4SF },
550996263Sobrien  { MASK_ALTIVEC, CODE_FOR_absv16qi2, "__builtin_altivec_abs_v16qi", ALTIVEC_BUILTIN_ABS_V16QI },
551096263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_abss_v4si, "__builtin_altivec_abss_v4si", ALTIVEC_BUILTIN_ABSS_V4SI },
551196263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_abss_v8hi, "__builtin_altivec_abss_v8hi", ALTIVEC_BUILTIN_ABSS_V8HI },
551296263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_abss_v16qi, "__builtin_altivec_abss_v16qi", ALTIVEC_BUILTIN_ABSS_V16QI }
551396263Sobrien};
551496263Sobrien
551590075Sobrien/* Simple unary operations: VECb = foo (unsigned literal) or VECb =
551690075Sobrien   foo (VECa).  */
551790075Sobrien
5518117395Skanstatic struct builtin_description bdesc_1arg[] =
551990075Sobrien{
552090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vexptefp, "__builtin_altivec_vexptefp", ALTIVEC_BUILTIN_VEXPTEFP },
552190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vlogefp, "__builtin_altivec_vlogefp", ALTIVEC_BUILTIN_VLOGEFP },
552290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vrefp, "__builtin_altivec_vrefp", ALTIVEC_BUILTIN_VREFP },
552390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vrfim, "__builtin_altivec_vrfim", ALTIVEC_BUILTIN_VRFIM },
552490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vrfin, "__builtin_altivec_vrfin", ALTIVEC_BUILTIN_VRFIN },
552590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vrfip, "__builtin_altivec_vrfip", ALTIVEC_BUILTIN_VRFIP },
552690075Sobrien  { MASK_ALTIVEC, CODE_FOR_ftruncv4sf2, "__builtin_altivec_vrfiz", ALTIVEC_BUILTIN_VRFIZ },
552790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vrsqrtefp, "__builtin_altivec_vrsqrtefp", ALTIVEC_BUILTIN_VRSQRTEFP },
552890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vspltisb, "__builtin_altivec_vspltisb", ALTIVEC_BUILTIN_VSPLTISB },
552990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vspltish, "__builtin_altivec_vspltish", ALTIVEC_BUILTIN_VSPLTISH },
553090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vspltisw, "__builtin_altivec_vspltisw", ALTIVEC_BUILTIN_VSPLTISW },
553190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vupkhsb, "__builtin_altivec_vupkhsb", ALTIVEC_BUILTIN_VUPKHSB },
553290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vupkhpx, "__builtin_altivec_vupkhpx", ALTIVEC_BUILTIN_VUPKHPX },
553390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vupkhsh, "__builtin_altivec_vupkhsh", ALTIVEC_BUILTIN_VUPKHSH },
553490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vupklsb, "__builtin_altivec_vupklsb", ALTIVEC_BUILTIN_VUPKLSB },
553590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vupklpx, "__builtin_altivec_vupklpx", ALTIVEC_BUILTIN_VUPKLPX },
553690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vupklsh, "__builtin_altivec_vupklsh", ALTIVEC_BUILTIN_VUPKLSH },
5537117395Skan
5538117395Skan  /* The SPE unary builtins must start with SPE_BUILTIN_EVABS and
5539117395Skan     end with SPE_BUILTIN_EVSUBFUSIAAW.  */
5540117395Skan  { 0, CODE_FOR_spe_evabs, "__builtin_spe_evabs", SPE_BUILTIN_EVABS },
5541117395Skan  { 0, CODE_FOR_spe_evaddsmiaaw, "__builtin_spe_evaddsmiaaw", SPE_BUILTIN_EVADDSMIAAW },
5542117395Skan  { 0, CODE_FOR_spe_evaddssiaaw, "__builtin_spe_evaddssiaaw", SPE_BUILTIN_EVADDSSIAAW },
5543117395Skan  { 0, CODE_FOR_spe_evaddumiaaw, "__builtin_spe_evaddumiaaw", SPE_BUILTIN_EVADDUMIAAW },
5544117395Skan  { 0, CODE_FOR_spe_evaddusiaaw, "__builtin_spe_evaddusiaaw", SPE_BUILTIN_EVADDUSIAAW },
5545117395Skan  { 0, CODE_FOR_spe_evcntlsw, "__builtin_spe_evcntlsw", SPE_BUILTIN_EVCNTLSW },
5546117395Skan  { 0, CODE_FOR_spe_evcntlzw, "__builtin_spe_evcntlzw", SPE_BUILTIN_EVCNTLZW },
5547117395Skan  { 0, CODE_FOR_spe_evextsb, "__builtin_spe_evextsb", SPE_BUILTIN_EVEXTSB },
5548117395Skan  { 0, CODE_FOR_spe_evextsh, "__builtin_spe_evextsh", SPE_BUILTIN_EVEXTSH },
5549117395Skan  { 0, CODE_FOR_spe_evfsabs, "__builtin_spe_evfsabs", SPE_BUILTIN_EVFSABS },
5550117395Skan  { 0, CODE_FOR_spe_evfscfsf, "__builtin_spe_evfscfsf", SPE_BUILTIN_EVFSCFSF },
5551117395Skan  { 0, CODE_FOR_spe_evfscfsi, "__builtin_spe_evfscfsi", SPE_BUILTIN_EVFSCFSI },
5552117395Skan  { 0, CODE_FOR_spe_evfscfuf, "__builtin_spe_evfscfuf", SPE_BUILTIN_EVFSCFUF },
5553117395Skan  { 0, CODE_FOR_spe_evfscfui, "__builtin_spe_evfscfui", SPE_BUILTIN_EVFSCFUI },
5554117395Skan  { 0, CODE_FOR_spe_evfsctsf, "__builtin_spe_evfsctsf", SPE_BUILTIN_EVFSCTSF },
5555117395Skan  { 0, CODE_FOR_spe_evfsctsi, "__builtin_spe_evfsctsi", SPE_BUILTIN_EVFSCTSI },
5556117395Skan  { 0, CODE_FOR_spe_evfsctsiz, "__builtin_spe_evfsctsiz", SPE_BUILTIN_EVFSCTSIZ },
5557117395Skan  { 0, CODE_FOR_spe_evfsctuf, "__builtin_spe_evfsctuf", SPE_BUILTIN_EVFSCTUF },
5558117395Skan  { 0, CODE_FOR_spe_evfsctui, "__builtin_spe_evfsctui", SPE_BUILTIN_EVFSCTUI },
5559117395Skan  { 0, CODE_FOR_spe_evfsctuiz, "__builtin_spe_evfsctuiz", SPE_BUILTIN_EVFSCTUIZ },
5560117395Skan  { 0, CODE_FOR_spe_evfsnabs, "__builtin_spe_evfsnabs", SPE_BUILTIN_EVFSNABS },
5561117395Skan  { 0, CODE_FOR_spe_evfsneg, "__builtin_spe_evfsneg", SPE_BUILTIN_EVFSNEG },
5562117395Skan  { 0, CODE_FOR_spe_evmra, "__builtin_spe_evmra", SPE_BUILTIN_EVMRA },
5563132718Skan  { 0, CODE_FOR_negv2si2, "__builtin_spe_evneg", SPE_BUILTIN_EVNEG },
5564117395Skan  { 0, CODE_FOR_spe_evrndw, "__builtin_spe_evrndw", SPE_BUILTIN_EVRNDW },
5565117395Skan  { 0, CODE_FOR_spe_evsubfsmiaaw, "__builtin_spe_evsubfsmiaaw", SPE_BUILTIN_EVSUBFSMIAAW },
5566117395Skan  { 0, CODE_FOR_spe_evsubfssiaaw, "__builtin_spe_evsubfssiaaw", SPE_BUILTIN_EVSUBFSSIAAW },
5567117395Skan  { 0, CODE_FOR_spe_evsubfumiaaw, "__builtin_spe_evsubfumiaaw", SPE_BUILTIN_EVSUBFUMIAAW },
5568117395Skan
5569117395Skan  /* Place-holder.  Leave as last unary SPE builtin.  */
5570117395Skan  { 0, CODE_FOR_spe_evsubfusiaaw, "__builtin_spe_evsubfusiaaw", SPE_BUILTIN_EVSUBFUSIAAW },
557190075Sobrien};
557290075Sobrien
557390075Sobrienstatic rtx
5574132718Skanrs6000_expand_unop_builtin (enum insn_code icode, tree arglist, rtx target)
557590075Sobrien{
557690075Sobrien  rtx pat;
557790075Sobrien  tree arg0 = TREE_VALUE (arglist);
557890075Sobrien  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
557990075Sobrien  enum machine_mode tmode = insn_data[icode].operand[0].mode;
558090075Sobrien  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
558190075Sobrien
5582117395Skan  if (icode == CODE_FOR_nothing)
5583117395Skan    /* Builtin not supported on this processor.  */
5584117395Skan    return 0;
5585117395Skan
558690075Sobrien  /* If we got invalid arguments bail out before generating bad rtl.  */
558790075Sobrien  if (arg0 == error_mark_node)
5588117395Skan    return const0_rtx;
558990075Sobrien
5590117395Skan  if (icode == CODE_FOR_altivec_vspltisb
5591117395Skan      || icode == CODE_FOR_altivec_vspltish
5592117395Skan      || icode == CODE_FOR_altivec_vspltisw
5593117395Skan      || icode == CODE_FOR_spe_evsplatfi
5594117395Skan      || icode == CODE_FOR_spe_evsplati)
5595117395Skan    {
5596117395Skan      /* Only allow 5-bit *signed* literals.  */
5597117395Skan      if (GET_CODE (op0) != CONST_INT
5598117395Skan	  || INTVAL (op0) > 0x1f
5599117395Skan	  || INTVAL (op0) < -0x1f)
5600117395Skan	{
5601117395Skan	  error ("argument 1 must be a 5-bit signed literal");
5602117395Skan	  return const0_rtx;
5603117395Skan	}
5604117395Skan    }
5605117395Skan
560690075Sobrien  if (target == 0
560790075Sobrien      || GET_MODE (target) != tmode
560890075Sobrien      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
560990075Sobrien    target = gen_reg_rtx (tmode);
561090075Sobrien
561190075Sobrien  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
561290075Sobrien    op0 = copy_to_mode_reg (mode0, op0);
561390075Sobrien
561490075Sobrien  pat = GEN_FCN (icode) (target, op0);
561590075Sobrien  if (! pat)
561690075Sobrien    return 0;
561790075Sobrien  emit_insn (pat);
561890075Sobrien
561990075Sobrien  return target;
562090075Sobrien}
562196263Sobrien
562290075Sobrienstatic rtx
5623132718Skanaltivec_expand_abs_builtin (enum insn_code icode, tree arglist, rtx target)
562496263Sobrien{
562596263Sobrien  rtx pat, scratch1, scratch2;
562696263Sobrien  tree arg0 = TREE_VALUE (arglist);
562796263Sobrien  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
562896263Sobrien  enum machine_mode tmode = insn_data[icode].operand[0].mode;
562996263Sobrien  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
563096263Sobrien
563196263Sobrien  /* If we have invalid arguments, bail out before generating bad rtl.  */
563296263Sobrien  if (arg0 == error_mark_node)
5633117395Skan    return const0_rtx;
563496263Sobrien
563596263Sobrien  if (target == 0
563696263Sobrien      || GET_MODE (target) != tmode
563796263Sobrien      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
563896263Sobrien    target = gen_reg_rtx (tmode);
563996263Sobrien
564096263Sobrien  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
564196263Sobrien    op0 = copy_to_mode_reg (mode0, op0);
564296263Sobrien
564396263Sobrien  scratch1 = gen_reg_rtx (mode0);
564496263Sobrien  scratch2 = gen_reg_rtx (mode0);
564596263Sobrien
564696263Sobrien  pat = GEN_FCN (icode) (target, op0, scratch1, scratch2);
564796263Sobrien  if (! pat)
564896263Sobrien    return 0;
564996263Sobrien  emit_insn (pat);
565096263Sobrien
565196263Sobrien  return target;
565296263Sobrien}
565396263Sobrien
565496263Sobrienstatic rtx
5655132718Skanrs6000_expand_binop_builtin (enum insn_code icode, tree arglist, rtx target)
565690075Sobrien{
565790075Sobrien  rtx pat;
565890075Sobrien  tree arg0 = TREE_VALUE (arglist);
565990075Sobrien  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
566090075Sobrien  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
566190075Sobrien  rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
566290075Sobrien  enum machine_mode tmode = insn_data[icode].operand[0].mode;
566390075Sobrien  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
566490075Sobrien  enum machine_mode mode1 = insn_data[icode].operand[2].mode;
566590075Sobrien
5666117395Skan  if (icode == CODE_FOR_nothing)
5667117395Skan    /* Builtin not supported on this processor.  */
5668117395Skan    return 0;
5669117395Skan
567090075Sobrien  /* If we got invalid arguments bail out before generating bad rtl.  */
567190075Sobrien  if (arg0 == error_mark_node || arg1 == error_mark_node)
5672117395Skan    return const0_rtx;
567390075Sobrien
5674117395Skan  if (icode == CODE_FOR_altivec_vcfux
5675117395Skan      || icode == CODE_FOR_altivec_vcfsx
5676117395Skan      || icode == CODE_FOR_altivec_vctsxs
5677117395Skan      || icode == CODE_FOR_altivec_vctuxs
5678117395Skan      || icode == CODE_FOR_altivec_vspltb
5679117395Skan      || icode == CODE_FOR_altivec_vsplth
5680117395Skan      || icode == CODE_FOR_altivec_vspltw
5681117395Skan      || icode == CODE_FOR_spe_evaddiw
5682117395Skan      || icode == CODE_FOR_spe_evldd
5683117395Skan      || icode == CODE_FOR_spe_evldh
5684117395Skan      || icode == CODE_FOR_spe_evldw
5685117395Skan      || icode == CODE_FOR_spe_evlhhesplat
5686117395Skan      || icode == CODE_FOR_spe_evlhhossplat
5687117395Skan      || icode == CODE_FOR_spe_evlhhousplat
5688117395Skan      || icode == CODE_FOR_spe_evlwhe
5689117395Skan      || icode == CODE_FOR_spe_evlwhos
5690117395Skan      || icode == CODE_FOR_spe_evlwhou
5691117395Skan      || icode == CODE_FOR_spe_evlwhsplat
5692117395Skan      || icode == CODE_FOR_spe_evlwwsplat
5693117395Skan      || icode == CODE_FOR_spe_evrlwi
5694117395Skan      || icode == CODE_FOR_spe_evslwi
5695117395Skan      || icode == CODE_FOR_spe_evsrwis
5696132718Skan      || icode == CODE_FOR_spe_evsubifw
5697117395Skan      || icode == CODE_FOR_spe_evsrwiu)
5698117395Skan    {
5699117395Skan      /* Only allow 5-bit unsigned literals.  */
5700146895Skan      STRIP_NOPS (arg1);
5701117395Skan      if (TREE_CODE (arg1) != INTEGER_CST
5702117395Skan	  || TREE_INT_CST_LOW (arg1) & ~0x1f)
5703117395Skan	{
5704117395Skan	  error ("argument 2 must be a 5-bit unsigned literal");
5705117395Skan	  return const0_rtx;
5706117395Skan	}
5707117395Skan    }
5708117395Skan
570990075Sobrien  if (target == 0
571090075Sobrien      || GET_MODE (target) != tmode
571190075Sobrien      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
571290075Sobrien    target = gen_reg_rtx (tmode);
571390075Sobrien
571490075Sobrien  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
571590075Sobrien    op0 = copy_to_mode_reg (mode0, op0);
571690075Sobrien  if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
571790075Sobrien    op1 = copy_to_mode_reg (mode1, op1);
571890075Sobrien
571990075Sobrien  pat = GEN_FCN (icode) (target, op0, op1);
572090075Sobrien  if (! pat)
572190075Sobrien    return 0;
572290075Sobrien  emit_insn (pat);
572390075Sobrien
572490075Sobrien  return target;
572590075Sobrien}
572690075Sobrien
572790075Sobrienstatic rtx
5728132718Skanaltivec_expand_predicate_builtin (enum insn_code icode, const char *opcode,
5729132718Skan				  tree arglist, rtx target)
573096263Sobrien{
573196263Sobrien  rtx pat, scratch;
573296263Sobrien  tree cr6_form = TREE_VALUE (arglist);
573396263Sobrien  tree arg0 = TREE_VALUE (TREE_CHAIN (arglist));
573496263Sobrien  tree arg1 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
573596263Sobrien  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
573696263Sobrien  rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
573796263Sobrien  enum machine_mode tmode = SImode;
573896263Sobrien  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
573996263Sobrien  enum machine_mode mode1 = insn_data[icode].operand[2].mode;
574096263Sobrien  int cr6_form_int;
574196263Sobrien
574296263Sobrien  if (TREE_CODE (cr6_form) != INTEGER_CST)
574396263Sobrien    {
574496263Sobrien      error ("argument 1 of __builtin_altivec_predicate must be a constant");
5745117395Skan      return const0_rtx;
574696263Sobrien    }
574796263Sobrien  else
574896263Sobrien    cr6_form_int = TREE_INT_CST_LOW (cr6_form);
574996263Sobrien
575096263Sobrien  if (mode0 != mode1)
575196263Sobrien    abort ();
575296263Sobrien
575396263Sobrien  /* If we have invalid arguments, bail out before generating bad rtl.  */
575496263Sobrien  if (arg0 == error_mark_node || arg1 == error_mark_node)
5755117395Skan    return const0_rtx;
575696263Sobrien
575796263Sobrien  if (target == 0
575896263Sobrien      || GET_MODE (target) != tmode
575996263Sobrien      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
576096263Sobrien    target = gen_reg_rtx (tmode);
576196263Sobrien
576296263Sobrien  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
576396263Sobrien    op0 = copy_to_mode_reg (mode0, op0);
576496263Sobrien  if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
576596263Sobrien    op1 = copy_to_mode_reg (mode1, op1);
576696263Sobrien
576796263Sobrien  scratch = gen_reg_rtx (mode0);
576896263Sobrien
576996263Sobrien  pat = GEN_FCN (icode) (scratch, op0, op1,
577096263Sobrien			 gen_rtx (SYMBOL_REF, Pmode, opcode));
577196263Sobrien  if (! pat)
577296263Sobrien    return 0;
577396263Sobrien  emit_insn (pat);
577496263Sobrien
577596263Sobrien  /* The vec_any* and vec_all* predicates use the same opcodes for two
577696263Sobrien     different operations, but the bits in CR6 will be different
577796263Sobrien     depending on what information we want.  So we have to play tricks
577896263Sobrien     with CR6 to get the right bits out.
577996263Sobrien
578096263Sobrien     If you think this is disgusting, look at the specs for the
578196263Sobrien     AltiVec predicates.  */
578296263Sobrien
578396263Sobrien     switch (cr6_form_int)
578496263Sobrien       {
578596263Sobrien       case 0:
578696263Sobrien	 emit_insn (gen_cr6_test_for_zero (target));
578796263Sobrien	 break;
578896263Sobrien       case 1:
578996263Sobrien	 emit_insn (gen_cr6_test_for_zero_reverse (target));
579096263Sobrien	 break;
579196263Sobrien       case 2:
579296263Sobrien	 emit_insn (gen_cr6_test_for_lt (target));
579396263Sobrien	 break;
579496263Sobrien       case 3:
579596263Sobrien	 emit_insn (gen_cr6_test_for_lt_reverse (target));
579696263Sobrien	 break;
579796263Sobrien       default:
579896263Sobrien	 error ("argument 1 of __builtin_altivec_predicate is out of range");
579996263Sobrien	 break;
580096263Sobrien       }
580196263Sobrien
580296263Sobrien  return target;
580396263Sobrien}
580496263Sobrien
580596263Sobrienstatic rtx
5806132718Skanaltivec_expand_lv_builtin (enum insn_code icode, tree arglist, rtx target)
580790075Sobrien{
5808132718Skan  rtx pat, addr;
580990075Sobrien  tree arg0 = TREE_VALUE (arglist);
581090075Sobrien  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
5811132718Skan  enum machine_mode tmode = insn_data[icode].operand[0].mode;
5812132718Skan  enum machine_mode mode0 = Pmode;
5813132718Skan  enum machine_mode mode1 = Pmode;
5814132718Skan  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
5815132718Skan  rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
5816132718Skan
5817132718Skan  if (icode == CODE_FOR_nothing)
5818132718Skan    /* Builtin not supported on this processor.  */
5819132718Skan    return 0;
5820132718Skan
5821132718Skan  /* If we got invalid arguments bail out before generating bad rtl.  */
5822132718Skan  if (arg0 == error_mark_node || arg1 == error_mark_node)
5823132718Skan    return const0_rtx;
5824132718Skan
5825132718Skan  if (target == 0
5826132718Skan      || GET_MODE (target) != tmode
5827132718Skan      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
5828132718Skan    target = gen_reg_rtx (tmode);
5829132718Skan
5830132718Skan  op1 = copy_to_mode_reg (mode1, op1);
5831132718Skan
5832132718Skan  if (op0 == const0_rtx)
5833132718Skan    {
5834132718Skan      addr = gen_rtx_MEM (tmode, op1);
5835132718Skan    }
5836132718Skan  else
5837132718Skan    {
5838132718Skan      op0 = copy_to_mode_reg (mode0, op0);
5839132718Skan      addr = gen_rtx_MEM (tmode, gen_rtx_PLUS (Pmode, op0, op1));
5840132718Skan    }
5841132718Skan
5842132718Skan  pat = GEN_FCN (icode) (target, addr);
5843132718Skan
5844132718Skan  if (! pat)
5845132718Skan    return 0;
5846132718Skan  emit_insn (pat);
5847132718Skan
5848132718Skan  return target;
5849132718Skan}
5850132718Skan
5851132718Skanstatic rtx
5852132718Skanspe_expand_stv_builtin (enum insn_code icode, tree arglist)
5853132718Skan{
5854132718Skan  tree arg0 = TREE_VALUE (arglist);
5855132718Skan  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
585690075Sobrien  tree arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
585790075Sobrien  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
585890075Sobrien  rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
585990075Sobrien  rtx op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
586090075Sobrien  rtx pat;
586190075Sobrien  enum machine_mode mode0 = insn_data[icode].operand[0].mode;
586290075Sobrien  enum machine_mode mode1 = insn_data[icode].operand[1].mode;
586390075Sobrien  enum machine_mode mode2 = insn_data[icode].operand[2].mode;
586490075Sobrien
586590075Sobrien  /* Invalid arguments.  Bail before doing anything stoopid!  */
586690075Sobrien  if (arg0 == error_mark_node
586790075Sobrien      || arg1 == error_mark_node
586890075Sobrien      || arg2 == error_mark_node)
5869117395Skan    return const0_rtx;
587090075Sobrien
587190075Sobrien  if (! (*insn_data[icode].operand[2].predicate) (op0, mode2))
587290075Sobrien    op0 = copy_to_mode_reg (mode2, op0);
587390075Sobrien  if (! (*insn_data[icode].operand[0].predicate) (op1, mode0))
587490075Sobrien    op1 = copy_to_mode_reg (mode0, op1);
587590075Sobrien  if (! (*insn_data[icode].operand[1].predicate) (op2, mode1))
587690075Sobrien    op2 = copy_to_mode_reg (mode1, op2);
587790075Sobrien
587890075Sobrien  pat = GEN_FCN (icode) (op1, op2, op0);
587990075Sobrien  if (pat)
588090075Sobrien    emit_insn (pat);
588190075Sobrien  return NULL_RTX;
588290075Sobrien}
588390075Sobrien
588490075Sobrienstatic rtx
5885132718Skanaltivec_expand_stv_builtin (enum insn_code icode, tree arglist)
588690075Sobrien{
5887132718Skan  tree arg0 = TREE_VALUE (arglist);
5888132718Skan  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
5889132718Skan  tree arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
5890132718Skan  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
5891132718Skan  rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
5892132718Skan  rtx op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
5893132718Skan  rtx pat, addr;
5894132718Skan  enum machine_mode tmode = insn_data[icode].operand[0].mode;
5895132718Skan  enum machine_mode mode1 = Pmode;
5896132718Skan  enum machine_mode mode2 = Pmode;
5897132718Skan
5898132718Skan  /* Invalid arguments.  Bail before doing anything stoopid!  */
5899132718Skan  if (arg0 == error_mark_node
5900132718Skan      || arg1 == error_mark_node
5901132718Skan      || arg2 == error_mark_node)
5902132718Skan    return const0_rtx;
5903132718Skan
5904132718Skan  if (! (*insn_data[icode].operand[1].predicate) (op0, tmode))
5905132718Skan    op0 = copy_to_mode_reg (tmode, op0);
5906132718Skan
5907132718Skan  op2 = copy_to_mode_reg (mode2, op2);
5908132718Skan
5909132718Skan  if (op1 == const0_rtx)
5910132718Skan    {
5911132718Skan      addr = gen_rtx_MEM (tmode, op2);
5912132718Skan    }
5913132718Skan  else
5914132718Skan    {
5915132718Skan      op1 = copy_to_mode_reg (mode1, op1);
5916132718Skan      addr = gen_rtx_MEM (tmode, gen_rtx_PLUS (Pmode, op1, op2));
5917132718Skan    }
5918132718Skan
5919132718Skan  pat = GEN_FCN (icode) (addr, op0);
5920132718Skan  if (pat)
5921132718Skan    emit_insn (pat);
5922132718Skan  return NULL_RTX;
5923132718Skan}
5924132718Skan
5925132718Skanstatic rtx
5926132718Skanrs6000_expand_ternop_builtin (enum insn_code icode, tree arglist, rtx target)
5927132718Skan{
592890075Sobrien  rtx pat;
592990075Sobrien  tree arg0 = TREE_VALUE (arglist);
593090075Sobrien  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
593190075Sobrien  tree arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
593290075Sobrien  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
593390075Sobrien  rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
593490075Sobrien  rtx op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
593590075Sobrien  enum machine_mode tmode = insn_data[icode].operand[0].mode;
593690075Sobrien  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
593790075Sobrien  enum machine_mode mode1 = insn_data[icode].operand[2].mode;
593890075Sobrien  enum machine_mode mode2 = insn_data[icode].operand[3].mode;
593990075Sobrien
5940117395Skan  if (icode == CODE_FOR_nothing)
5941117395Skan    /* Builtin not supported on this processor.  */
5942117395Skan    return 0;
5943117395Skan
594490075Sobrien  /* If we got invalid arguments bail out before generating bad rtl.  */
594590075Sobrien  if (arg0 == error_mark_node
594690075Sobrien      || arg1 == error_mark_node
594790075Sobrien      || arg2 == error_mark_node)
5948117395Skan    return const0_rtx;
594990075Sobrien
5950117395Skan  if (icode == CODE_FOR_altivec_vsldoi_4sf
5951117395Skan      || icode == CODE_FOR_altivec_vsldoi_4si
5952117395Skan      || icode == CODE_FOR_altivec_vsldoi_8hi
5953117395Skan      || icode == CODE_FOR_altivec_vsldoi_16qi)
5954117395Skan    {
5955117395Skan      /* Only allow 4-bit unsigned literals.  */
5956117395Skan      if (TREE_CODE (arg2) != INTEGER_CST
5957117395Skan	  || TREE_INT_CST_LOW (arg2) & ~0xf)
5958117395Skan	{
5959117395Skan	  error ("argument 3 must be a 4-bit unsigned literal");
5960117395Skan	  return const0_rtx;
5961117395Skan	}
5962117395Skan    }
5963117395Skan
596490075Sobrien  if (target == 0
596590075Sobrien      || GET_MODE (target) != tmode
596690075Sobrien      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
596790075Sobrien    target = gen_reg_rtx (tmode);
596890075Sobrien
596990075Sobrien  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
597090075Sobrien    op0 = copy_to_mode_reg (mode0, op0);
597190075Sobrien  if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
597290075Sobrien    op1 = copy_to_mode_reg (mode1, op1);
597390075Sobrien  if (! (*insn_data[icode].operand[3].predicate) (op2, mode2))
597490075Sobrien    op2 = copy_to_mode_reg (mode2, op2);
597590075Sobrien
597690075Sobrien  pat = GEN_FCN (icode) (target, op0, op1, op2);
597790075Sobrien  if (! pat)
597890075Sobrien    return 0;
597990075Sobrien  emit_insn (pat);
598090075Sobrien
598190075Sobrien  return target;
598290075Sobrien}
5983117395Skan
5984117395Skan/* Expand the lvx builtins.  */
598590075Sobrienstatic rtx
5986132718Skanaltivec_expand_ld_builtin (tree exp, rtx target, bool *expandedp)
598790075Sobrien{
598890075Sobrien  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
598990075Sobrien  tree arglist = TREE_OPERAND (exp, 1);
599090075Sobrien  unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
5991117395Skan  tree arg0;
5992117395Skan  enum machine_mode tmode, mode0;
5993117395Skan  rtx pat, op0;
5994117395Skan  enum insn_code icode;
5995117395Skan
599690075Sobrien  switch (fcode)
599790075Sobrien    {
599890075Sobrien    case ALTIVEC_BUILTIN_LD_INTERNAL_16qi:
599990075Sobrien      icode = CODE_FOR_altivec_lvx_16qi;
6000117395Skan      break;
6001117395Skan    case ALTIVEC_BUILTIN_LD_INTERNAL_8hi:
6002117395Skan      icode = CODE_FOR_altivec_lvx_8hi;
6003117395Skan      break;
6004117395Skan    case ALTIVEC_BUILTIN_LD_INTERNAL_4si:
6005117395Skan      icode = CODE_FOR_altivec_lvx_4si;
6006117395Skan      break;
6007117395Skan    case ALTIVEC_BUILTIN_LD_INTERNAL_4sf:
6008117395Skan      icode = CODE_FOR_altivec_lvx_4sf;
6009117395Skan      break;
6010117395Skan    default:
6011117395Skan      *expandedp = false;
6012117395Skan      return NULL_RTX;
6013117395Skan    }
601490075Sobrien
6015117395Skan  *expandedp = true;
601690075Sobrien
6017117395Skan  arg0 = TREE_VALUE (arglist);
6018117395Skan  op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6019117395Skan  tmode = insn_data[icode].operand[0].mode;
6020117395Skan  mode0 = insn_data[icode].operand[1].mode;
602190075Sobrien
6022117395Skan  if (target == 0
6023117395Skan      || GET_MODE (target) != tmode
6024117395Skan      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
6025117395Skan    target = gen_reg_rtx (tmode);
602690075Sobrien
6027117395Skan  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
6028117395Skan    op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
602990075Sobrien
6030117395Skan  pat = GEN_FCN (icode) (target, op0);
6031117395Skan  if (! pat)
6032117395Skan    return 0;
6033117395Skan  emit_insn (pat);
6034117395Skan  return target;
6035117395Skan}
603690075Sobrien
6037117395Skan/* Expand the stvx builtins.  */
6038117395Skanstatic rtx
6039132718Skanaltivec_expand_st_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
6040132718Skan			   bool *expandedp)
6041117395Skan{
6042117395Skan  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
6043117395Skan  tree arglist = TREE_OPERAND (exp, 1);
6044117395Skan  unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
6045117395Skan  tree arg0, arg1;
6046117395Skan  enum machine_mode mode0, mode1;
6047117395Skan  rtx pat, op0, op1;
6048117395Skan  enum insn_code icode;
604990075Sobrien
6050117395Skan  switch (fcode)
6051117395Skan    {
6052117395Skan    case ALTIVEC_BUILTIN_ST_INTERNAL_16qi:
6053117395Skan      icode = CODE_FOR_altivec_stvx_16qi;
6054117395Skan      break;
6055117395Skan    case ALTIVEC_BUILTIN_ST_INTERNAL_8hi:
6056117395Skan      icode = CODE_FOR_altivec_stvx_8hi;
6057117395Skan      break;
6058117395Skan    case ALTIVEC_BUILTIN_ST_INTERNAL_4si:
6059117395Skan      icode = CODE_FOR_altivec_stvx_4si;
6060117395Skan      break;
6061117395Skan    case ALTIVEC_BUILTIN_ST_INTERNAL_4sf:
6062117395Skan      icode = CODE_FOR_altivec_stvx_4sf;
6063117395Skan      break;
6064117395Skan    default:
6065117395Skan      *expandedp = false;
6066117395Skan      return NULL_RTX;
6067117395Skan    }
606890075Sobrien
6069117395Skan  arg0 = TREE_VALUE (arglist);
6070117395Skan  arg1 = TREE_VALUE (TREE_CHAIN (arglist));
6071117395Skan  op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6072117395Skan  op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
6073117395Skan  mode0 = insn_data[icode].operand[0].mode;
6074117395Skan  mode1 = insn_data[icode].operand[1].mode;
607590075Sobrien
6076117395Skan  if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
6077117395Skan    op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
6078117395Skan  if (! (*insn_data[icode].operand[1].predicate) (op1, mode1))
6079117395Skan    op1 = copy_to_mode_reg (mode1, op1);
608090075Sobrien
6081117395Skan  pat = GEN_FCN (icode) (op0, op1);
6082117395Skan  if (pat)
6083117395Skan    emit_insn (pat);
608490075Sobrien
6085117395Skan  *expandedp = true;
6086117395Skan  return NULL_RTX;
6087117395Skan}
608890075Sobrien
6089117395Skan/* Expand the dst builtins.  */
6090117395Skanstatic rtx
6091132718Skanaltivec_expand_dst_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
6092132718Skan			    bool *expandedp)
6093117395Skan{
6094117395Skan  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
6095117395Skan  tree arglist = TREE_OPERAND (exp, 1);
6096117395Skan  unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
6097117395Skan  tree arg0, arg1, arg2;
6098117395Skan  enum machine_mode mode0, mode1, mode2;
6099117395Skan  rtx pat, op0, op1, op2;
6100117395Skan  struct builtin_description *d;
6101117395Skan  size_t i;
610290075Sobrien
6103117395Skan  *expandedp = false;
610490075Sobrien
6105117395Skan  /* Handle DST variants.  */
6106117395Skan  d = (struct builtin_description *) bdesc_dst;
6107117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_dst); i++, d++)
6108117395Skan    if (d->code == fcode)
6109117395Skan      {
6110117395Skan	arg0 = TREE_VALUE (arglist);
6111117395Skan	arg1 = TREE_VALUE (TREE_CHAIN (arglist));
6112117395Skan	arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
6113117395Skan	op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6114117395Skan	op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
6115117395Skan	op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
6116117395Skan	mode0 = insn_data[d->icode].operand[0].mode;
6117117395Skan	mode1 = insn_data[d->icode].operand[1].mode;
6118117395Skan	mode2 = insn_data[d->icode].operand[2].mode;
611990075Sobrien
6120117395Skan	/* Invalid arguments, bail out before generating bad rtl.  */
6121117395Skan	if (arg0 == error_mark_node
6122117395Skan	    || arg1 == error_mark_node
6123117395Skan	    || arg2 == error_mark_node)
6124117395Skan	  return const0_rtx;
612590075Sobrien
6126146895Skan	*expandedp = true;
6127146895Skan	STRIP_NOPS (arg2);
6128117395Skan	if (TREE_CODE (arg2) != INTEGER_CST
6129117395Skan	    || TREE_INT_CST_LOW (arg2) & ~0x3)
6130117395Skan	  {
6131117395Skan	    error ("argument to `%s' must be a 2-bit unsigned literal", d->name);
6132117395Skan	    return const0_rtx;
6133117395Skan	  }
613490075Sobrien
6135117395Skan	if (! (*insn_data[d->icode].operand[0].predicate) (op0, mode0))
6136132718Skan	  op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
6137117395Skan	if (! (*insn_data[d->icode].operand[1].predicate) (op1, mode1))
6138117395Skan	  op1 = copy_to_mode_reg (mode1, op1);
613990075Sobrien
6140117395Skan	pat = GEN_FCN (d->icode) (op0, op1, op2);
6141117395Skan	if (pat != 0)
6142117395Skan	  emit_insn (pat);
614390075Sobrien
6144117395Skan	return NULL_RTX;
6145117395Skan      }
614690075Sobrien
6147117395Skan  return NULL_RTX;
6148117395Skan}
614990075Sobrien
6150117395Skan/* Expand the builtin in EXP and store the result in TARGET.  Store
6151117395Skan   true in *EXPANDEDP if we found a builtin to expand.  */
6152117395Skanstatic rtx
6153132718Skanaltivec_expand_builtin (tree exp, rtx target, bool *expandedp)
6154117395Skan{
6155117395Skan  struct builtin_description *d;
6156117395Skan  struct builtin_description_predicates *dp;
6157117395Skan  size_t i;
6158117395Skan  enum insn_code icode;
6159117395Skan  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
6160117395Skan  tree arglist = TREE_OPERAND (exp, 1);
6161117395Skan  tree arg0;
6162117395Skan  rtx op0, pat;
6163117395Skan  enum machine_mode tmode, mode0;
6164117395Skan  unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
616590075Sobrien
6166117395Skan  target = altivec_expand_ld_builtin (exp, target, expandedp);
6167117395Skan  if (*expandedp)
6168117395Skan    return target;
616990075Sobrien
6170117395Skan  target = altivec_expand_st_builtin (exp, target, expandedp);
6171117395Skan  if (*expandedp)
6172117395Skan    return target;
617390075Sobrien
6174117395Skan  target = altivec_expand_dst_builtin (exp, target, expandedp);
6175117395Skan  if (*expandedp)
6176117395Skan    return target;
617790075Sobrien
6178117395Skan  *expandedp = true;
617990075Sobrien
6180117395Skan  switch (fcode)
6181117395Skan    {
618290075Sobrien    case ALTIVEC_BUILTIN_STVX:
618390075Sobrien      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvx, arglist);
618490075Sobrien    case ALTIVEC_BUILTIN_STVEBX:
618590075Sobrien      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvebx, arglist);
618690075Sobrien    case ALTIVEC_BUILTIN_STVEHX:
618790075Sobrien      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvehx, arglist);
618890075Sobrien    case ALTIVEC_BUILTIN_STVEWX:
618990075Sobrien      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvewx, arglist);
619090075Sobrien    case ALTIVEC_BUILTIN_STVXL:
619190075Sobrien      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvxl, arglist);
6192117395Skan
619390075Sobrien    case ALTIVEC_BUILTIN_MFVSCR:
619490075Sobrien      icode = CODE_FOR_altivec_mfvscr;
619590075Sobrien      tmode = insn_data[icode].operand[0].mode;
619690075Sobrien
619790075Sobrien      if (target == 0
619890075Sobrien	  || GET_MODE (target) != tmode
619990075Sobrien	  || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
620090075Sobrien	target = gen_reg_rtx (tmode);
620190075Sobrien
620290075Sobrien      pat = GEN_FCN (icode) (target);
620390075Sobrien      if (! pat)
620490075Sobrien	return 0;
620590075Sobrien      emit_insn (pat);
620690075Sobrien      return target;
620790075Sobrien
620890075Sobrien    case ALTIVEC_BUILTIN_MTVSCR:
620990075Sobrien      icode = CODE_FOR_altivec_mtvscr;
621090075Sobrien      arg0 = TREE_VALUE (arglist);
621190075Sobrien      op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
621290075Sobrien      mode0 = insn_data[icode].operand[0].mode;
621390075Sobrien
621490075Sobrien      /* If we got invalid arguments bail out before generating bad rtl.  */
621590075Sobrien      if (arg0 == error_mark_node)
6216117395Skan	return const0_rtx;
621790075Sobrien
621890075Sobrien      if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
621990075Sobrien	op0 = copy_to_mode_reg (mode0, op0);
622090075Sobrien
622190075Sobrien      pat = GEN_FCN (icode) (op0);
622290075Sobrien      if (pat)
622390075Sobrien	emit_insn (pat);
622490075Sobrien      return NULL_RTX;
6225117395Skan
622690075Sobrien    case ALTIVEC_BUILTIN_DSSALL:
622790075Sobrien      emit_insn (gen_altivec_dssall ());
622890075Sobrien      return NULL_RTX;
622990075Sobrien
623090075Sobrien    case ALTIVEC_BUILTIN_DSS:
623190075Sobrien      icode = CODE_FOR_altivec_dss;
623290075Sobrien      arg0 = TREE_VALUE (arglist);
6233146895Skan      STRIP_NOPS (arg0);
623490075Sobrien      op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
623590075Sobrien      mode0 = insn_data[icode].operand[0].mode;
623690075Sobrien
623790075Sobrien      /* If we got invalid arguments bail out before generating bad rtl.  */
623890075Sobrien      if (arg0 == error_mark_node)
6239117395Skan	return const0_rtx;
624090075Sobrien
6241117395Skan      if (TREE_CODE (arg0) != INTEGER_CST
6242117395Skan	  || TREE_INT_CST_LOW (arg0) & ~0x3)
6243117395Skan	{
6244117395Skan	  error ("argument to dss must be a 2-bit unsigned literal");
6245117395Skan	  return const0_rtx;
6246117395Skan	}
6247117395Skan
624890075Sobrien      if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
624990075Sobrien	op0 = copy_to_mode_reg (mode0, op0);
625090075Sobrien
625190075Sobrien      emit_insn (gen_altivec_dss (op0));
625290075Sobrien      return NULL_RTX;
6253146895Skan
6254146895Skan    case ALTIVEC_BUILTIN_COMPILETIME_ERROR:
6255146895Skan      arg0 = TREE_VALUE (arglist);
6256146895Skan      while (TREE_CODE (arg0) == NOP_EXPR || TREE_CODE (arg0) == ADDR_EXPR)
6257146895Skan	arg0 = TREE_OPERAND (arg0, 0);
6258146895Skan      error ("invalid parameter combination for `%s' AltiVec intrinsic",
6259146895Skan	     TREE_STRING_POINTER (arg0));
6260146895Skan
6261146895Skan      return const0_rtx;
626290075Sobrien    }
626390075Sobrien
626496263Sobrien  /* Expand abs* operations.  */
626596263Sobrien  d = (struct builtin_description *) bdesc_abs;
6266117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_abs); i++, d++)
626796263Sobrien    if (d->code == fcode)
626896263Sobrien      return altivec_expand_abs_builtin (d->icode, arglist, target);
626996263Sobrien
627096263Sobrien  /* Expand the AltiVec predicates.  */
627196263Sobrien  dp = (struct builtin_description_predicates *) bdesc_altivec_preds;
6272117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_altivec_preds); i++, dp++)
627396263Sobrien    if (dp->code == fcode)
627496263Sobrien      return altivec_expand_predicate_builtin (dp->icode, dp->opcode, arglist, target);
627596263Sobrien
627690075Sobrien  /* LV* are funky.  We initialized them differently.  */
627790075Sobrien  switch (fcode)
627890075Sobrien    {
627990075Sobrien    case ALTIVEC_BUILTIN_LVSL:
6280132718Skan      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvsl,
628190075Sobrien					   arglist, target);
628290075Sobrien    case ALTIVEC_BUILTIN_LVSR:
6283132718Skan      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvsr,
6284117395Skan					  arglist, target);
628590075Sobrien    case ALTIVEC_BUILTIN_LVEBX:
6286132718Skan      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvebx,
6287117395Skan					  arglist, target);
628890075Sobrien    case ALTIVEC_BUILTIN_LVEHX:
6289132718Skan      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvehx,
6290117395Skan					  arglist, target);
629190075Sobrien    case ALTIVEC_BUILTIN_LVEWX:
6292132718Skan      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvewx,
6293117395Skan					  arglist, target);
629490075Sobrien    case ALTIVEC_BUILTIN_LVXL:
6295132718Skan      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvxl,
6296117395Skan					  arglist, target);
629790075Sobrien    case ALTIVEC_BUILTIN_LVX:
6298132718Skan      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvx,
6299117395Skan					  arglist, target);
630090075Sobrien    default:
630190075Sobrien      break;
630290075Sobrien      /* Fall through.  */
630390075Sobrien    }
630490075Sobrien
6305117395Skan  *expandedp = false;
6306117395Skan  return NULL_RTX;
6307117395Skan}
6308117395Skan
6309117395Skan/* Binops that need to be initialized manually, but can be expanded
6310117395Skan   automagically by rs6000_expand_binop_builtin.  */
6311117395Skanstatic struct builtin_description bdesc_2arg_spe[] =
6312117395Skan{
6313117395Skan  { 0, CODE_FOR_spe_evlddx, "__builtin_spe_evlddx", SPE_BUILTIN_EVLDDX },
6314117395Skan  { 0, CODE_FOR_spe_evldwx, "__builtin_spe_evldwx", SPE_BUILTIN_EVLDWX },
6315117395Skan  { 0, CODE_FOR_spe_evldhx, "__builtin_spe_evldhx", SPE_BUILTIN_EVLDHX },
6316117395Skan  { 0, CODE_FOR_spe_evlwhex, "__builtin_spe_evlwhex", SPE_BUILTIN_EVLWHEX },
6317117395Skan  { 0, CODE_FOR_spe_evlwhoux, "__builtin_spe_evlwhoux", SPE_BUILTIN_EVLWHOUX },
6318117395Skan  { 0, CODE_FOR_spe_evlwhosx, "__builtin_spe_evlwhosx", SPE_BUILTIN_EVLWHOSX },
6319117395Skan  { 0, CODE_FOR_spe_evlwwsplatx, "__builtin_spe_evlwwsplatx", SPE_BUILTIN_EVLWWSPLATX },
6320117395Skan  { 0, CODE_FOR_spe_evlwhsplatx, "__builtin_spe_evlwhsplatx", SPE_BUILTIN_EVLWHSPLATX },
6321117395Skan  { 0, CODE_FOR_spe_evlhhesplatx, "__builtin_spe_evlhhesplatx", SPE_BUILTIN_EVLHHESPLATX },
6322117395Skan  { 0, CODE_FOR_spe_evlhhousplatx, "__builtin_spe_evlhhousplatx", SPE_BUILTIN_EVLHHOUSPLATX },
6323117395Skan  { 0, CODE_FOR_spe_evlhhossplatx, "__builtin_spe_evlhhossplatx", SPE_BUILTIN_EVLHHOSSPLATX },
6324117395Skan  { 0, CODE_FOR_spe_evldd, "__builtin_spe_evldd", SPE_BUILTIN_EVLDD },
6325117395Skan  { 0, CODE_FOR_spe_evldw, "__builtin_spe_evldw", SPE_BUILTIN_EVLDW },
6326117395Skan  { 0, CODE_FOR_spe_evldh, "__builtin_spe_evldh", SPE_BUILTIN_EVLDH },
6327117395Skan  { 0, CODE_FOR_spe_evlwhe, "__builtin_spe_evlwhe", SPE_BUILTIN_EVLWHE },
6328117395Skan  { 0, CODE_FOR_spe_evlwhou, "__builtin_spe_evlwhou", SPE_BUILTIN_EVLWHOU },
6329117395Skan  { 0, CODE_FOR_spe_evlwhos, "__builtin_spe_evlwhos", SPE_BUILTIN_EVLWHOS },
6330117395Skan  { 0, CODE_FOR_spe_evlwwsplat, "__builtin_spe_evlwwsplat", SPE_BUILTIN_EVLWWSPLAT },
6331117395Skan  { 0, CODE_FOR_spe_evlwhsplat, "__builtin_spe_evlwhsplat", SPE_BUILTIN_EVLWHSPLAT },
6332117395Skan  { 0, CODE_FOR_spe_evlhhesplat, "__builtin_spe_evlhhesplat", SPE_BUILTIN_EVLHHESPLAT },
6333117395Skan  { 0, CODE_FOR_spe_evlhhousplat, "__builtin_spe_evlhhousplat", SPE_BUILTIN_EVLHHOUSPLAT },
6334117395Skan  { 0, CODE_FOR_spe_evlhhossplat, "__builtin_spe_evlhhossplat", SPE_BUILTIN_EVLHHOSSPLAT }
6335117395Skan};
6336117395Skan
6337117395Skan/* Expand the builtin in EXP and store the result in TARGET.  Store
6338117395Skan   true in *EXPANDEDP if we found a builtin to expand.
6339117395Skan
6340117395Skan   This expands the SPE builtins that are not simple unary and binary
6341117395Skan   operations.  */
6342117395Skanstatic rtx
6343132718Skanspe_expand_builtin (tree exp, rtx target, bool *expandedp)
6344117395Skan{
6345117395Skan  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
6346117395Skan  tree arglist = TREE_OPERAND (exp, 1);
6347117395Skan  tree arg1, arg0;
6348117395Skan  unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
6349117395Skan  enum insn_code icode;
6350117395Skan  enum machine_mode tmode, mode0;
6351117395Skan  rtx pat, op0;
6352117395Skan  struct builtin_description *d;
6353117395Skan  size_t i;
6354117395Skan
6355117395Skan  *expandedp = true;
6356117395Skan
6357117395Skan  /* Syntax check for a 5-bit unsigned immediate.  */
6358117395Skan  switch (fcode)
6359117395Skan    {
6360117395Skan    case SPE_BUILTIN_EVSTDD:
6361117395Skan    case SPE_BUILTIN_EVSTDH:
6362117395Skan    case SPE_BUILTIN_EVSTDW:
6363117395Skan    case SPE_BUILTIN_EVSTWHE:
6364117395Skan    case SPE_BUILTIN_EVSTWHO:
6365117395Skan    case SPE_BUILTIN_EVSTWWE:
6366117395Skan    case SPE_BUILTIN_EVSTWWO:
6367117395Skan      arg1 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
6368117395Skan      if (TREE_CODE (arg1) != INTEGER_CST
6369117395Skan	  || TREE_INT_CST_LOW (arg1) & ~0x1f)
6370117395Skan	{
6371117395Skan	  error ("argument 2 must be a 5-bit unsigned literal");
6372117395Skan	  return const0_rtx;
6373117395Skan	}
6374117395Skan      break;
6375117395Skan    default:
6376117395Skan      break;
6377117395Skan    }
6378117395Skan
6379132718Skan  /* The evsplat*i instructions are not quite generic.  */
6380132718Skan  switch (fcode)
6381132718Skan    {
6382132718Skan    case SPE_BUILTIN_EVSPLATFI:
6383132718Skan      return rs6000_expand_unop_builtin (CODE_FOR_spe_evsplatfi,
6384132718Skan					 arglist, target);
6385132718Skan    case SPE_BUILTIN_EVSPLATI:
6386132718Skan      return rs6000_expand_unop_builtin (CODE_FOR_spe_evsplati,
6387132718Skan					 arglist, target);
6388132718Skan    default:
6389132718Skan      break;
6390132718Skan    }
6391132718Skan
6392117395Skan  d = (struct builtin_description *) bdesc_2arg_spe;
6393117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_2arg_spe); ++i, ++d)
639490075Sobrien    if (d->code == fcode)
6395117395Skan      return rs6000_expand_binop_builtin (d->icode, arglist, target);
639690075Sobrien
6397117395Skan  d = (struct builtin_description *) bdesc_spe_predicates;
6398117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_spe_predicates); ++i, ++d)
6399117395Skan    if (d->code == fcode)
6400117395Skan      return spe_expand_predicate_builtin (d->icode, arglist, target);
6401117395Skan
6402117395Skan  d = (struct builtin_description *) bdesc_spe_evsel;
6403117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_spe_evsel); ++i, ++d)
6404117395Skan    if (d->code == fcode)
6405117395Skan      return spe_expand_evsel_builtin (d->icode, arglist, target);
6406117395Skan
6407117395Skan  switch (fcode)
6408117395Skan    {
6409117395Skan    case SPE_BUILTIN_EVSTDDX:
6410132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstddx, arglist);
6411117395Skan    case SPE_BUILTIN_EVSTDHX:
6412132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstdhx, arglist);
6413117395Skan    case SPE_BUILTIN_EVSTDWX:
6414132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstdwx, arglist);
6415117395Skan    case SPE_BUILTIN_EVSTWHEX:
6416132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstwhex, arglist);
6417117395Skan    case SPE_BUILTIN_EVSTWHOX:
6418132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstwhox, arglist);
6419117395Skan    case SPE_BUILTIN_EVSTWWEX:
6420132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstwwex, arglist);
6421117395Skan    case SPE_BUILTIN_EVSTWWOX:
6422132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstwwox, arglist);
6423117395Skan    case SPE_BUILTIN_EVSTDD:
6424132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstdd, arglist);
6425117395Skan    case SPE_BUILTIN_EVSTDH:
6426132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstdh, arglist);
6427117395Skan    case SPE_BUILTIN_EVSTDW:
6428132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstdw, arglist);
6429117395Skan    case SPE_BUILTIN_EVSTWHE:
6430132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstwhe, arglist);
6431117395Skan    case SPE_BUILTIN_EVSTWHO:
6432132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstwho, arglist);
6433117395Skan    case SPE_BUILTIN_EVSTWWE:
6434132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstwwe, arglist);
6435117395Skan    case SPE_BUILTIN_EVSTWWO:
6436132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstwwo, arglist);
6437117395Skan    case SPE_BUILTIN_MFSPEFSCR:
6438117395Skan      icode = CODE_FOR_spe_mfspefscr;
6439117395Skan      tmode = insn_data[icode].operand[0].mode;
6440117395Skan
6441117395Skan      if (target == 0
6442117395Skan	  || GET_MODE (target) != tmode
6443117395Skan	  || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
6444117395Skan	target = gen_reg_rtx (tmode);
6445117395Skan
6446117395Skan      pat = GEN_FCN (icode) (target);
6447117395Skan      if (! pat)
6448117395Skan	return 0;
6449117395Skan      emit_insn (pat);
6450117395Skan      return target;
6451117395Skan    case SPE_BUILTIN_MTSPEFSCR:
6452117395Skan      icode = CODE_FOR_spe_mtspefscr;
6453117395Skan      arg0 = TREE_VALUE (arglist);
6454117395Skan      op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6455117395Skan      mode0 = insn_data[icode].operand[0].mode;
6456117395Skan
6457117395Skan      if (arg0 == error_mark_node)
6458117395Skan	return const0_rtx;
6459117395Skan
6460117395Skan      if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
6461117395Skan	op0 = copy_to_mode_reg (mode0, op0);
6462117395Skan
6463117395Skan      pat = GEN_FCN (icode) (op0);
6464117395Skan      if (pat)
6465117395Skan	emit_insn (pat);
6466117395Skan      return NULL_RTX;
6467117395Skan    default:
6468117395Skan      break;
6469117395Skan    }
6470117395Skan
6471117395Skan  *expandedp = false;
647290075Sobrien  return NULL_RTX;
647390075Sobrien}
647490075Sobrien
6475117395Skanstatic rtx
6476132718Skanspe_expand_predicate_builtin (enum insn_code icode, tree arglist, rtx target)
6477117395Skan{
6478117395Skan  rtx pat, scratch, tmp;
6479117395Skan  tree form = TREE_VALUE (arglist);
6480117395Skan  tree arg0 = TREE_VALUE (TREE_CHAIN (arglist));
6481117395Skan  tree arg1 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
6482117395Skan  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6483117395Skan  rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
6484117395Skan  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
6485117395Skan  enum machine_mode mode1 = insn_data[icode].operand[2].mode;
6486117395Skan  int form_int;
6487117395Skan  enum rtx_code code;
6488117395Skan
6489117395Skan  if (TREE_CODE (form) != INTEGER_CST)
6490117395Skan    {
6491117395Skan      error ("argument 1 of __builtin_spe_predicate must be a constant");
6492117395Skan      return const0_rtx;
6493117395Skan    }
6494117395Skan  else
6495117395Skan    form_int = TREE_INT_CST_LOW (form);
6496117395Skan
6497117395Skan  if (mode0 != mode1)
6498117395Skan    abort ();
6499117395Skan
6500117395Skan  if (arg0 == error_mark_node || arg1 == error_mark_node)
6501117395Skan    return const0_rtx;
6502117395Skan
6503117395Skan  if (target == 0
6504117395Skan      || GET_MODE (target) != SImode
6505117395Skan      || ! (*insn_data[icode].operand[0].predicate) (target, SImode))
6506117395Skan    target = gen_reg_rtx (SImode);
6507117395Skan
6508117395Skan  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
6509117395Skan    op0 = copy_to_mode_reg (mode0, op0);
6510117395Skan  if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
6511117395Skan    op1 = copy_to_mode_reg (mode1, op1);
6512117395Skan
6513117395Skan  scratch = gen_reg_rtx (CCmode);
6514117395Skan
6515117395Skan  pat = GEN_FCN (icode) (scratch, op0, op1);
6516117395Skan  if (! pat)
6517117395Skan    return const0_rtx;
6518117395Skan  emit_insn (pat);
6519117395Skan
6520117395Skan  /* There are 4 variants for each predicate: _any_, _all_, _upper_,
6521117395Skan     _lower_.  We use one compare, but look in different bits of the
6522117395Skan     CR for each variant.
6523117395Skan
6524117395Skan     There are 2 elements in each SPE simd type (upper/lower).  The CR
6525117395Skan     bits are set as follows:
6526117395Skan
6527117395Skan     BIT0  | BIT 1  | BIT 2   | BIT 3
6528117395Skan     U     |   L    | (U | L) | (U & L)
6529117395Skan
6530117395Skan     So, for an "all" relationship, BIT 3 would be set.
6531117395Skan     For an "any" relationship, BIT 2 would be set.  Etc.
6532117395Skan
6533117395Skan     Following traditional nomenclature, these bits map to:
6534117395Skan
6535117395Skan     BIT0  | BIT 1  | BIT 2   | BIT 3
6536117395Skan     LT    | GT     | EQ      | OV
6537117395Skan
6538117395Skan     Later, we will generate rtl to look in the LT/EQ/EQ/OV bits.
6539117395Skan  */
6540117395Skan
6541117395Skan  switch (form_int)
6542117395Skan    {
6543117395Skan      /* All variant.  OV bit.  */
6544117395Skan    case 0:
6545117395Skan      /* We need to get to the OV bit, which is the ORDERED bit.  We
6546117395Skan	 could generate (ordered:SI (reg:CC xx) (const_int 0)), but
6547117395Skan	 that's ugly and will trigger a validate_condition_mode abort.
6548117395Skan	 So let's just use another pattern.  */
6549117395Skan      emit_insn (gen_move_from_CR_ov_bit (target, scratch));
6550117395Skan      return target;
6551117395Skan      /* Any variant.  EQ bit.  */
6552117395Skan    case 1:
6553117395Skan      code = EQ;
6554117395Skan      break;
6555117395Skan      /* Upper variant.  LT bit.  */
6556117395Skan    case 2:
6557117395Skan      code = LT;
6558117395Skan      break;
6559117395Skan      /* Lower variant.  GT bit.  */
6560117395Skan    case 3:
6561117395Skan      code = GT;
6562117395Skan      break;
6563117395Skan    default:
6564117395Skan      error ("argument 1 of __builtin_spe_predicate is out of range");
6565117395Skan      return const0_rtx;
6566117395Skan    }
6567117395Skan
6568117395Skan  tmp = gen_rtx_fmt_ee (code, SImode, scratch, const0_rtx);
6569117395Skan  emit_move_insn (target, tmp);
6570117395Skan
6571117395Skan  return target;
6572117395Skan}
6573117395Skan
6574117395Skan/* The evsel builtins look like this:
6575117395Skan
6576117395Skan     e = __builtin_spe_evsel_OP (a, b, c, d);
6577117395Skan
6578117395Skan   and work like this:
6579117395Skan
6580117395Skan     e[upper] = a[upper] *OP* b[upper] ? c[upper] : d[upper];
6581117395Skan     e[lower] = a[lower] *OP* b[lower] ? c[lower] : d[lower];
6582117395Skan*/
6583117395Skan
6584117395Skanstatic rtx
6585132718Skanspe_expand_evsel_builtin (enum insn_code icode, tree arglist, rtx target)
6586117395Skan{
6587117395Skan  rtx pat, scratch;
6588117395Skan  tree arg0 = TREE_VALUE (arglist);
6589117395Skan  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
6590117395Skan  tree arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
6591117395Skan  tree arg3 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (arglist))));
6592117395Skan  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6593117395Skan  rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
6594117395Skan  rtx op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
6595117395Skan  rtx op3 = expand_expr (arg3, NULL_RTX, VOIDmode, 0);
6596117395Skan  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
6597117395Skan  enum machine_mode mode1 = insn_data[icode].operand[2].mode;
6598117395Skan
6599117395Skan  if (mode0 != mode1)
6600117395Skan    abort ();
6601117395Skan
6602117395Skan  if (arg0 == error_mark_node || arg1 == error_mark_node
6603117395Skan      || arg2 == error_mark_node || arg3 == error_mark_node)
6604117395Skan    return const0_rtx;
6605117395Skan
6606117395Skan  if (target == 0
6607117395Skan      || GET_MODE (target) != mode0
6608117395Skan      || ! (*insn_data[icode].operand[0].predicate) (target, mode0))
6609117395Skan    target = gen_reg_rtx (mode0);
6610117395Skan
6611117395Skan  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
6612117395Skan    op0 = copy_to_mode_reg (mode0, op0);
6613117395Skan  if (! (*insn_data[icode].operand[1].predicate) (op1, mode1))
6614117395Skan    op1 = copy_to_mode_reg (mode0, op1);
6615117395Skan  if (! (*insn_data[icode].operand[1].predicate) (op2, mode1))
6616117395Skan    op2 = copy_to_mode_reg (mode0, op2);
6617117395Skan  if (! (*insn_data[icode].operand[1].predicate) (op3, mode1))
6618117395Skan    op3 = copy_to_mode_reg (mode0, op3);
6619117395Skan
6620117395Skan  /* Generate the compare.  */
6621117395Skan  scratch = gen_reg_rtx (CCmode);
6622117395Skan  pat = GEN_FCN (icode) (scratch, op0, op1);
6623117395Skan  if (! pat)
6624117395Skan    return const0_rtx;
6625117395Skan  emit_insn (pat);
6626117395Skan
6627117395Skan  if (mode0 == V2SImode)
6628117395Skan    emit_insn (gen_spe_evsel (target, op2, op3, scratch));
6629117395Skan  else
6630117395Skan    emit_insn (gen_spe_evsel_fs (target, op2, op3, scratch));
6631117395Skan
6632117395Skan  return target;
6633117395Skan}
6634117395Skan
663590075Sobrien/* Expand an expression EXP that calls a built-in function,
663690075Sobrien   with result going to TARGET if that's convenient
663790075Sobrien   (and in mode MODE if that's convenient).
663890075Sobrien   SUBTARGET may be used as the target for computing one of EXP's operands.
663990075Sobrien   IGNORE is nonzero if the value is to be ignored.  */
664090075Sobrien
664190075Sobrienstatic rtx
6642132718Skanrs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
6643132718Skan		      enum machine_mode mode ATTRIBUTE_UNUSED,
6644132718Skan		      int ignore ATTRIBUTE_UNUSED)
664590075Sobrien{
6646117395Skan  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
6647117395Skan  tree arglist = TREE_OPERAND (exp, 1);
6648117395Skan  unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
6649117395Skan  struct builtin_description *d;
6650117395Skan  size_t i;
6651117395Skan  rtx ret;
6652117395Skan  bool success;
6653117395Skan
665490075Sobrien  if (TARGET_ALTIVEC)
6655117395Skan    {
6656117395Skan      ret = altivec_expand_builtin (exp, target, &success);
665790075Sobrien
6658117395Skan      if (success)
6659117395Skan	return ret;
6660117395Skan    }
6661117395Skan  if (TARGET_SPE)
6662117395Skan    {
6663117395Skan      ret = spe_expand_builtin (exp, target, &success);
6664117395Skan
6665117395Skan      if (success)
6666117395Skan	return ret;
6667117395Skan    }
6668117395Skan
6669117395Skan  if (TARGET_ALTIVEC || TARGET_SPE)
6670117395Skan    {
6671117395Skan      /* Handle simple unary operations.  */
6672117395Skan      d = (struct builtin_description *) bdesc_1arg;
6673117395Skan      for (i = 0; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
6674117395Skan	if (d->code == fcode)
6675117395Skan	  return rs6000_expand_unop_builtin (d->icode, arglist, target);
6676117395Skan
6677117395Skan      /* Handle simple binary operations.  */
6678117395Skan      d = (struct builtin_description *) bdesc_2arg;
6679117395Skan      for (i = 0; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
6680117395Skan	if (d->code == fcode)
6681117395Skan	  return rs6000_expand_binop_builtin (d->icode, arglist, target);
6682117395Skan
6683117395Skan      /* Handle simple ternary operations.  */
6684117395Skan      d = (struct builtin_description *) bdesc_3arg;
6685117395Skan      for (i = 0; i < ARRAY_SIZE  (bdesc_3arg); i++, d++)
6686117395Skan	if (d->code == fcode)
6687117395Skan	  return rs6000_expand_ternop_builtin (d->icode, arglist, target);
6688117395Skan    }
6689117395Skan
669090075Sobrien  abort ();
6691117395Skan  return NULL_RTX;
669290075Sobrien}
669390075Sobrien
669490075Sobrienstatic void
6695132718Skanrs6000_init_builtins (void)
669690075Sobrien{
6697132718Skan  opaque_V2SI_type_node = copy_node (V2SI_type_node);
6698132718Skan  opaque_V2SF_type_node = copy_node (V2SF_type_node);
6699132718Skan  opaque_p_V2SI_type_node = build_pointer_type (opaque_V2SI_type_node);
6700132718Skan
6701146895Skan  /* The 'vector bool ...' types must be kept distinct from 'vector unsigned ...'
6702146895Skan     types, especially in C++ land.  Similarly, 'vector pixel' is distinct from+     'vector unsigned short'.  */
6703146895Skan
6704146895Skan  bool_char_type_node = copy_node (unsigned_intQI_type_node);
6705146895Skan  TYPE_MAIN_VARIANT (bool_char_type_node) = bool_char_type_node;
6706146895Skan  bool_short_type_node = copy_node (unsigned_intHI_type_node);
6707146895Skan  TYPE_MAIN_VARIANT (bool_short_type_node) = bool_short_type_node;
6708146895Skan  bool_int_type_node = copy_node (unsigned_intSI_type_node);
6709146895Skan  TYPE_MAIN_VARIANT (bool_int_type_node) = bool_int_type_node;
6710146895Skan  pixel_type_node = copy_node (unsigned_intHI_type_node);
6711146895Skan  TYPE_MAIN_VARIANT (pixel_type_node) = pixel_type_node;
6712146895Skan
6713146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
6714146895Skan					    get_identifier ("__bool char"),
6715146895Skan					    bool_char_type_node));
6716146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
6717146895Skan					    get_identifier ("__bool short"),
6718146895Skan					    bool_short_type_node));
6719146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
6720146895Skan					    get_identifier ("__bool int"),
6721146895Skan					    bool_int_type_node));
6722146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
6723146895Skan					    get_identifier ("__pixel"),
6724146895Skan					    pixel_type_node));
6725146895Skan
6726146895Skan  bool_V16QI_type_node = make_vector (V16QImode, bool_char_type_node, 1);
6727146895Skan  bool_V8HI_type_node = make_vector (V8HImode, bool_short_type_node, 1);
6728146895Skan  bool_V4SI_type_node = make_vector (V4SImode, bool_int_type_node, 1);
6729146895Skan  pixel_V8HI_type_node = make_vector (V8HImode, pixel_type_node, 1);
6730146895Skan
6731146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
6732146895Skan					    get_identifier ("__vector unsigned char"),
6733146895Skan					    unsigned_V16QI_type_node));
6734146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
6735146895Skan					    get_identifier ("__vector signed char"),
6736146895Skan					    V16QI_type_node));
6737146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
6738146895Skan					    get_identifier ("__vector __bool char"),
6739146895Skan					    bool_V16QI_type_node));
6740146895Skan
6741146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
6742146895Skan					    get_identifier ("__vector unsigned short"),
6743146895Skan					    unsigned_V8HI_type_node));
6744146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
6745146895Skan					    get_identifier ("__vector signed short"),
6746146895Skan					    V8HI_type_node));
6747146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
6748146895Skan					    get_identifier ("__vector __bool short"),
6749146895Skan					    bool_V8HI_type_node));
6750146895Skan
6751146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
6752146895Skan					    get_identifier ("__vector unsigned int"),
6753146895Skan					    unsigned_V4SI_type_node));
6754146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
6755146895Skan					    get_identifier ("__vector signed int"),
6756146895Skan					    V4SI_type_node));
6757146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
6758146895Skan					    get_identifier ("__vector __bool int"),
6759146895Skan					    bool_V4SI_type_node));
6760146895Skan
6761146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
6762146895Skan					    get_identifier ("__vector float"),
6763146895Skan					    V4SF_type_node));
6764146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
6765146895Skan					    get_identifier ("__vector __pixel"),
6766146895Skan					    pixel_V8HI_type_node));
6767146895Skan
6768117395Skan  if (TARGET_SPE)
6769117395Skan    spe_init_builtins ();
677090075Sobrien  if (TARGET_ALTIVEC)
677190075Sobrien    altivec_init_builtins ();
6772117395Skan  if (TARGET_ALTIVEC || TARGET_SPE)
6773117395Skan    rs6000_common_init_builtins ();
677490075Sobrien}
677590075Sobrien
6776117395Skan/* Search through a set of builtins and enable the mask bits.
6777117395Skan   DESC is an array of builtins.
6778132718Skan   SIZE is the total number of builtins.
6779117395Skan   START is the builtin enum at which to start.
6780117395Skan   END is the builtin enum at which to end.  */
678190075Sobrienstatic void
6782132718Skanenable_mask_for_builtins (struct builtin_description *desc, int size,
6783132718Skan			  enum rs6000_builtins start,
6784132718Skan			  enum rs6000_builtins end)
678590075Sobrien{
6786117395Skan  int i;
678790075Sobrien
6788117395Skan  for (i = 0; i < size; ++i)
6789117395Skan    if (desc[i].code == start)
6790117395Skan      break;
679190075Sobrien
6792117395Skan  if (i == size)
6793117395Skan    return;
679490075Sobrien
6795117395Skan  for (; i < size; ++i)
6796117395Skan    {
6797117395Skan      /* Flip all the bits on.  */
6798117395Skan      desc[i].mask = target_flags;
6799117395Skan      if (desc[i].code == end)
6800117395Skan	break;
6801117395Skan    }
6802117395Skan}
680390075Sobrien
6804117395Skanstatic void
6805132718Skanspe_init_builtins (void)
6806117395Skan{
6807117395Skan  tree endlink = void_list_node;
6808117395Skan  tree puint_type_node = build_pointer_type (unsigned_type_node);
6809117395Skan  tree pushort_type_node = build_pointer_type (short_unsigned_type_node);
6810117395Skan  struct builtin_description *d;
6811117395Skan  size_t i;
681290075Sobrien
6813117395Skan  tree v2si_ftype_4_v2si
6814117395Skan    = build_function_type
6815132718Skan    (opaque_V2SI_type_node,
6816132718Skan     tree_cons (NULL_TREE, opaque_V2SI_type_node,
6817132718Skan		tree_cons (NULL_TREE, opaque_V2SI_type_node,
6818132718Skan			   tree_cons (NULL_TREE, opaque_V2SI_type_node,
6819132718Skan				      tree_cons (NULL_TREE, opaque_V2SI_type_node,
6820117395Skan						 endlink)))));
682190075Sobrien
6822117395Skan  tree v2sf_ftype_4_v2sf
6823117395Skan    = build_function_type
6824132718Skan    (opaque_V2SF_type_node,
6825132718Skan     tree_cons (NULL_TREE, opaque_V2SF_type_node,
6826132718Skan		tree_cons (NULL_TREE, opaque_V2SF_type_node,
6827132718Skan			   tree_cons (NULL_TREE, opaque_V2SF_type_node,
6828132718Skan				      tree_cons (NULL_TREE, opaque_V2SF_type_node,
6829117395Skan						 endlink)))));
683090075Sobrien
6831117395Skan  tree int_ftype_int_v2si_v2si
6832117395Skan    = build_function_type
6833117395Skan    (integer_type_node,
6834117395Skan     tree_cons (NULL_TREE, integer_type_node,
6835132718Skan		tree_cons (NULL_TREE, opaque_V2SI_type_node,
6836132718Skan			   tree_cons (NULL_TREE, opaque_V2SI_type_node,
6837117395Skan				      endlink))));
683890075Sobrien
6839117395Skan  tree int_ftype_int_v2sf_v2sf
6840117395Skan    = build_function_type
6841117395Skan    (integer_type_node,
6842117395Skan     tree_cons (NULL_TREE, integer_type_node,
6843132718Skan		tree_cons (NULL_TREE, opaque_V2SF_type_node,
6844132718Skan			   tree_cons (NULL_TREE, opaque_V2SF_type_node,
6845117395Skan				      endlink))));
684690075Sobrien
6847117395Skan  tree void_ftype_v2si_puint_int
684890075Sobrien    = build_function_type (void_type_node,
6849132718Skan			   tree_cons (NULL_TREE, opaque_V2SI_type_node,
6850117395Skan				      tree_cons (NULL_TREE, puint_type_node,
685190075Sobrien						 tree_cons (NULL_TREE,
6852117395Skan							    integer_type_node,
685390075Sobrien							    endlink))));
685490075Sobrien
6855117395Skan  tree void_ftype_v2si_puint_char
685690075Sobrien    = build_function_type (void_type_node,
6857132718Skan			   tree_cons (NULL_TREE, opaque_V2SI_type_node,
6858117395Skan				      tree_cons (NULL_TREE, puint_type_node,
685990075Sobrien						 tree_cons (NULL_TREE,
6860117395Skan							    char_type_node,
686190075Sobrien							    endlink))));
686290075Sobrien
6863117395Skan  tree void_ftype_v2si_pv2si_int
686490075Sobrien    = build_function_type (void_type_node,
6865132718Skan			   tree_cons (NULL_TREE, opaque_V2SI_type_node,
6866132718Skan				      tree_cons (NULL_TREE, opaque_p_V2SI_type_node,
686790075Sobrien						 tree_cons (NULL_TREE,
6868117395Skan							    integer_type_node,
686990075Sobrien							    endlink))));
687090075Sobrien
6871117395Skan  tree void_ftype_v2si_pv2si_char
687290075Sobrien    = build_function_type (void_type_node,
6873132718Skan			   tree_cons (NULL_TREE, opaque_V2SI_type_node,
6874132718Skan				      tree_cons (NULL_TREE, opaque_p_V2SI_type_node,
687590075Sobrien						 tree_cons (NULL_TREE,
6876117395Skan							    char_type_node,
687790075Sobrien							    endlink))));
687890075Sobrien
6879117395Skan  tree void_ftype_int
688090075Sobrien    = build_function_type (void_type_node,
6881117395Skan			   tree_cons (NULL_TREE, integer_type_node, endlink));
688290075Sobrien
6883117395Skan  tree int_ftype_void
6884132718Skan    = build_function_type (integer_type_node, endlink);
688590075Sobrien
6886117395Skan  tree v2si_ftype_pv2si_int
6887132718Skan    = build_function_type (opaque_V2SI_type_node,
6888132718Skan			   tree_cons (NULL_TREE, opaque_p_V2SI_type_node,
6889117395Skan				      tree_cons (NULL_TREE, integer_type_node,
6890117395Skan						 endlink)));
6891117395Skan
6892117395Skan  tree v2si_ftype_puint_int
6893132718Skan    = build_function_type (opaque_V2SI_type_node,
6894117395Skan			   tree_cons (NULL_TREE, puint_type_node,
6895117395Skan				      tree_cons (NULL_TREE, integer_type_node,
6896117395Skan						 endlink)));
6897117395Skan
6898117395Skan  tree v2si_ftype_pushort_int
6899132718Skan    = build_function_type (opaque_V2SI_type_node,
6900117395Skan			   tree_cons (NULL_TREE, pushort_type_node,
6901117395Skan				      tree_cons (NULL_TREE, integer_type_node,
6902117395Skan						 endlink)));
6903117395Skan
6904132718Skan  tree v2si_ftype_signed_char
6905132718Skan    = build_function_type (opaque_V2SI_type_node,
6906132718Skan			   tree_cons (NULL_TREE, signed_char_type_node,
6907132718Skan				      endlink));
6908132718Skan
6909117395Skan  /* The initialization of the simple binary and unary builtins is
6910117395Skan     done in rs6000_common_init_builtins, but we have to enable the
6911117395Skan     mask bits here manually because we have run out of `target_flags'
6912117395Skan     bits.  We really need to redesign this mask business.  */
6913117395Skan
6914117395Skan  enable_mask_for_builtins ((struct builtin_description *) bdesc_2arg,
6915117395Skan			    ARRAY_SIZE (bdesc_2arg),
6916117395Skan			    SPE_BUILTIN_EVADDW,
6917117395Skan			    SPE_BUILTIN_EVXOR);
6918117395Skan  enable_mask_for_builtins ((struct builtin_description *) bdesc_1arg,
6919117395Skan			    ARRAY_SIZE (bdesc_1arg),
6920117395Skan			    SPE_BUILTIN_EVABS,
6921117395Skan			    SPE_BUILTIN_EVSUBFUSIAAW);
6922117395Skan  enable_mask_for_builtins ((struct builtin_description *) bdesc_spe_predicates,
6923117395Skan			    ARRAY_SIZE (bdesc_spe_predicates),
6924117395Skan			    SPE_BUILTIN_EVCMPEQ,
6925117395Skan			    SPE_BUILTIN_EVFSTSTLT);
6926117395Skan  enable_mask_for_builtins ((struct builtin_description *) bdesc_spe_evsel,
6927117395Skan			    ARRAY_SIZE (bdesc_spe_evsel),
6928117395Skan			    SPE_BUILTIN_EVSEL_CMPGTS,
6929117395Skan			    SPE_BUILTIN_EVSEL_FSTSTEQ);
6930117395Skan
6931132718Skan  (*lang_hooks.decls.pushdecl)
6932132718Skan    (build_decl (TYPE_DECL, get_identifier ("__ev64_opaque__"),
6933132718Skan		 opaque_V2SI_type_node));
6934132718Skan
6935117395Skan  /* Initialize irregular SPE builtins.  */
6936117395Skan
6937117395Skan  def_builtin (target_flags, "__builtin_spe_mtspefscr", void_ftype_int, SPE_BUILTIN_MTSPEFSCR);
6938117395Skan  def_builtin (target_flags, "__builtin_spe_mfspefscr", int_ftype_void, SPE_BUILTIN_MFSPEFSCR);
6939117395Skan  def_builtin (target_flags, "__builtin_spe_evstddx", void_ftype_v2si_pv2si_int, SPE_BUILTIN_EVSTDDX);
6940117395Skan  def_builtin (target_flags, "__builtin_spe_evstdhx", void_ftype_v2si_pv2si_int, SPE_BUILTIN_EVSTDHX);
6941117395Skan  def_builtin (target_flags, "__builtin_spe_evstdwx", void_ftype_v2si_pv2si_int, SPE_BUILTIN_EVSTDWX);
6942117395Skan  def_builtin (target_flags, "__builtin_spe_evstwhex", void_ftype_v2si_puint_int, SPE_BUILTIN_EVSTWHEX);
6943117395Skan  def_builtin (target_flags, "__builtin_spe_evstwhox", void_ftype_v2si_puint_int, SPE_BUILTIN_EVSTWHOX);
6944117395Skan  def_builtin (target_flags, "__builtin_spe_evstwwex", void_ftype_v2si_puint_int, SPE_BUILTIN_EVSTWWEX);
6945117395Skan  def_builtin (target_flags, "__builtin_spe_evstwwox", void_ftype_v2si_puint_int, SPE_BUILTIN_EVSTWWOX);
6946117395Skan  def_builtin (target_flags, "__builtin_spe_evstdd", void_ftype_v2si_pv2si_char, SPE_BUILTIN_EVSTDD);
6947117395Skan  def_builtin (target_flags, "__builtin_spe_evstdh", void_ftype_v2si_pv2si_char, SPE_BUILTIN_EVSTDH);
6948117395Skan  def_builtin (target_flags, "__builtin_spe_evstdw", void_ftype_v2si_pv2si_char, SPE_BUILTIN_EVSTDW);
6949117395Skan  def_builtin (target_flags, "__builtin_spe_evstwhe", void_ftype_v2si_puint_char, SPE_BUILTIN_EVSTWHE);
6950117395Skan  def_builtin (target_flags, "__builtin_spe_evstwho", void_ftype_v2si_puint_char, SPE_BUILTIN_EVSTWHO);
6951117395Skan  def_builtin (target_flags, "__builtin_spe_evstwwe", void_ftype_v2si_puint_char, SPE_BUILTIN_EVSTWWE);
6952117395Skan  def_builtin (target_flags, "__builtin_spe_evstwwo", void_ftype_v2si_puint_char, SPE_BUILTIN_EVSTWWO);
6953132718Skan  def_builtin (target_flags, "__builtin_spe_evsplatfi", v2si_ftype_signed_char, SPE_BUILTIN_EVSPLATFI);
6954132718Skan  def_builtin (target_flags, "__builtin_spe_evsplati", v2si_ftype_signed_char, SPE_BUILTIN_EVSPLATI);
6955117395Skan
6956117395Skan  /* Loads.  */
6957117395Skan  def_builtin (target_flags, "__builtin_spe_evlddx", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDDX);
6958117395Skan  def_builtin (target_flags, "__builtin_spe_evldwx", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDWX);
6959117395Skan  def_builtin (target_flags, "__builtin_spe_evldhx", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDHX);
6960117395Skan  def_builtin (target_flags, "__builtin_spe_evlwhex", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHEX);
6961117395Skan  def_builtin (target_flags, "__builtin_spe_evlwhoux", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHOUX);
6962117395Skan  def_builtin (target_flags, "__builtin_spe_evlwhosx", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHOSX);
6963117395Skan  def_builtin (target_flags, "__builtin_spe_evlwwsplatx", v2si_ftype_puint_int, SPE_BUILTIN_EVLWWSPLATX);
6964117395Skan  def_builtin (target_flags, "__builtin_spe_evlwhsplatx", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHSPLATX);
6965117395Skan  def_builtin (target_flags, "__builtin_spe_evlhhesplatx", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHESPLATX);
6966117395Skan  def_builtin (target_flags, "__builtin_spe_evlhhousplatx", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHOUSPLATX);
6967117395Skan  def_builtin (target_flags, "__builtin_spe_evlhhossplatx", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHOSSPLATX);
6968117395Skan  def_builtin (target_flags, "__builtin_spe_evldd", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDD);
6969117395Skan  def_builtin (target_flags, "__builtin_spe_evldw", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDW);
6970117395Skan  def_builtin (target_flags, "__builtin_spe_evldh", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDH);
6971117395Skan  def_builtin (target_flags, "__builtin_spe_evlhhesplat", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHESPLAT);
6972117395Skan  def_builtin (target_flags, "__builtin_spe_evlhhossplat", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHOSSPLAT);
6973117395Skan  def_builtin (target_flags, "__builtin_spe_evlhhousplat", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHOUSPLAT);
6974117395Skan  def_builtin (target_flags, "__builtin_spe_evlwhe", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHE);
6975117395Skan  def_builtin (target_flags, "__builtin_spe_evlwhos", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHOS);
6976117395Skan  def_builtin (target_flags, "__builtin_spe_evlwhou", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHOU);
6977117395Skan  def_builtin (target_flags, "__builtin_spe_evlwhsplat", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHSPLAT);
6978117395Skan  def_builtin (target_flags, "__builtin_spe_evlwwsplat", v2si_ftype_puint_int, SPE_BUILTIN_EVLWWSPLAT);
6979117395Skan
6980117395Skan  /* Predicates.  */
6981117395Skan  d = (struct builtin_description *) bdesc_spe_predicates;
6982117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_spe_predicates); ++i, d++)
6983117395Skan    {
6984117395Skan      tree type;
6985117395Skan
6986117395Skan      switch (insn_data[d->icode].operand[1].mode)
6987117395Skan	{
6988117395Skan	case V2SImode:
6989117395Skan	  type = int_ftype_int_v2si_v2si;
6990117395Skan	  break;
6991117395Skan	case V2SFmode:
6992117395Skan	  type = int_ftype_int_v2sf_v2sf;
6993117395Skan	  break;
6994117395Skan	default:
6995117395Skan	  abort ();
6996117395Skan	}
6997117395Skan
6998117395Skan      def_builtin (d->mask, d->name, type, d->code);
6999117395Skan    }
7000117395Skan
7001117395Skan  /* Evsel predicates.  */
7002117395Skan  d = (struct builtin_description *) bdesc_spe_evsel;
7003117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_spe_evsel); ++i, d++)
7004117395Skan    {
7005117395Skan      tree type;
7006117395Skan
7007117395Skan      switch (insn_data[d->icode].operand[1].mode)
7008117395Skan	{
7009117395Skan	case V2SImode:
7010117395Skan	  type = v2si_ftype_4_v2si;
7011117395Skan	  break;
7012117395Skan	case V2SFmode:
7013117395Skan	  type = v2sf_ftype_4_v2sf;
7014117395Skan	  break;
7015117395Skan	default:
7016117395Skan	  abort ();
7017117395Skan	}
7018117395Skan
7019117395Skan      def_builtin (d->mask, d->name, type, d->code);
7020117395Skan    }
7021117395Skan}
7022117395Skan
7023117395Skanstatic void
7024132718Skanaltivec_init_builtins (void)
7025117395Skan{
7026117395Skan  struct builtin_description *d;
7027117395Skan  struct builtin_description_predicates *dp;
7028117395Skan  size_t i;
7029117395Skan  tree pfloat_type_node = build_pointer_type (float_type_node);
7030117395Skan  tree pint_type_node = build_pointer_type (integer_type_node);
7031117395Skan  tree pshort_type_node = build_pointer_type (short_integer_type_node);
7032117395Skan  tree pchar_type_node = build_pointer_type (char_type_node);
7033117395Skan
7034117395Skan  tree pvoid_type_node = build_pointer_type (void_type_node);
7035117395Skan
7036117395Skan  tree pcfloat_type_node = build_pointer_type (build_qualified_type (float_type_node, TYPE_QUAL_CONST));
7037117395Skan  tree pcint_type_node = build_pointer_type (build_qualified_type (integer_type_node, TYPE_QUAL_CONST));
7038117395Skan  tree pcshort_type_node = build_pointer_type (build_qualified_type (short_integer_type_node, TYPE_QUAL_CONST));
7039117395Skan  tree pcchar_type_node = build_pointer_type (build_qualified_type (char_type_node, TYPE_QUAL_CONST));
7040117395Skan
7041117395Skan  tree pcvoid_type_node = build_pointer_type (build_qualified_type (void_type_node, TYPE_QUAL_CONST));
7042117395Skan
7043117395Skan  tree int_ftype_int_v4si_v4si
7044117395Skan    = build_function_type_list (integer_type_node,
7045117395Skan				integer_type_node, V4SI_type_node,
7046117395Skan				V4SI_type_node, NULL_TREE);
7047117395Skan  tree v4sf_ftype_pcfloat
7048117395Skan    = build_function_type_list (V4SF_type_node, pcfloat_type_node, NULL_TREE);
7049117395Skan  tree void_ftype_pfloat_v4sf
7050117395Skan    = build_function_type_list (void_type_node,
7051117395Skan				pfloat_type_node, V4SF_type_node, NULL_TREE);
7052117395Skan  tree v4si_ftype_pcint
7053117395Skan    = build_function_type_list (V4SI_type_node, pcint_type_node, NULL_TREE);
7054117395Skan  tree void_ftype_pint_v4si
7055117395Skan    = build_function_type_list (void_type_node,
7056117395Skan				pint_type_node, V4SI_type_node, NULL_TREE);
7057117395Skan  tree v8hi_ftype_pcshort
7058117395Skan    = build_function_type_list (V8HI_type_node, pcshort_type_node, NULL_TREE);
7059117395Skan  tree void_ftype_pshort_v8hi
7060117395Skan    = build_function_type_list (void_type_node,
7061117395Skan				pshort_type_node, V8HI_type_node, NULL_TREE);
7062117395Skan  tree v16qi_ftype_pcchar
7063117395Skan    = build_function_type_list (V16QI_type_node, pcchar_type_node, NULL_TREE);
7064117395Skan  tree void_ftype_pchar_v16qi
7065117395Skan    = build_function_type_list (void_type_node,
7066117395Skan				pchar_type_node, V16QI_type_node, NULL_TREE);
7067117395Skan  tree void_ftype_v4si
7068117395Skan    = build_function_type_list (void_type_node, V4SI_type_node, NULL_TREE);
706990075Sobrien  tree v8hi_ftype_void
707096263Sobrien    = build_function_type (V8HI_type_node, void_list_node);
7071117395Skan  tree void_ftype_void
7072117395Skan    = build_function_type (void_type_node, void_list_node);
7073146895Skan  tree void_ftype_int
7074146895Skan    = build_function_type_list (void_type_node, integer_type_node, NULL_TREE);
707590075Sobrien
7076132718Skan  tree v16qi_ftype_long_pcvoid
7077117395Skan    = build_function_type_list (V16QI_type_node,
7078132718Skan				long_integer_type_node, pcvoid_type_node, NULL_TREE);
7079132718Skan  tree v8hi_ftype_long_pcvoid
7080117395Skan    = build_function_type_list (V8HI_type_node,
7081132718Skan				long_integer_type_node, pcvoid_type_node, NULL_TREE);
7082132718Skan  tree v4si_ftype_long_pcvoid
7083117395Skan    = build_function_type_list (V4SI_type_node,
7084132718Skan				long_integer_type_node, pcvoid_type_node, NULL_TREE);
708590075Sobrien
7086132718Skan  tree void_ftype_v4si_long_pvoid
7087117395Skan    = build_function_type_list (void_type_node,
7088132718Skan				V4SI_type_node, long_integer_type_node,
7089117395Skan				pvoid_type_node, NULL_TREE);
7090132718Skan  tree void_ftype_v16qi_long_pvoid
7091117395Skan    = build_function_type_list (void_type_node,
7092132718Skan				V16QI_type_node, long_integer_type_node,
7093117395Skan				pvoid_type_node, NULL_TREE);
7094132718Skan  tree void_ftype_v8hi_long_pvoid
7095117395Skan    = build_function_type_list (void_type_node,
7096132718Skan				V8HI_type_node, long_integer_type_node,
7097117395Skan				pvoid_type_node, NULL_TREE);
7098117395Skan  tree int_ftype_int_v8hi_v8hi
7099117395Skan    = build_function_type_list (integer_type_node,
7100117395Skan				integer_type_node, V8HI_type_node,
7101117395Skan				V8HI_type_node, NULL_TREE);
7102117395Skan  tree int_ftype_int_v16qi_v16qi
7103117395Skan    = build_function_type_list (integer_type_node,
7104117395Skan				integer_type_node, V16QI_type_node,
7105117395Skan				V16QI_type_node, NULL_TREE);
7106117395Skan  tree int_ftype_int_v4sf_v4sf
7107117395Skan    = build_function_type_list (integer_type_node,
7108117395Skan				integer_type_node, V4SF_type_node,
7109117395Skan				V4SF_type_node, NULL_TREE);
7110117395Skan  tree v4si_ftype_v4si
7111117395Skan    = build_function_type_list (V4SI_type_node, V4SI_type_node, NULL_TREE);
7112117395Skan  tree v8hi_ftype_v8hi
7113117395Skan    = build_function_type_list (V8HI_type_node, V8HI_type_node, NULL_TREE);
7114117395Skan  tree v16qi_ftype_v16qi
7115117395Skan    = build_function_type_list (V16QI_type_node, V16QI_type_node, NULL_TREE);
7116117395Skan  tree v4sf_ftype_v4sf
7117117395Skan    = build_function_type_list (V4SF_type_node, V4SF_type_node, NULL_TREE);
7118146895Skan  tree void_ftype_pcvoid_int_int
7119117395Skan    = build_function_type_list (void_type_node,
7120117395Skan				pcvoid_type_node, integer_type_node,
7121146895Skan				integer_type_node, NULL_TREE);
7122146895Skan  tree int_ftype_pcchar
7123146895Skan    = build_function_type_list (integer_type_node,
7124146895Skan				pcchar_type_node, NULL_TREE);
7125117395Skan
7126117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_4sf", v4sf_ftype_pcfloat,
7127117395Skan	       ALTIVEC_BUILTIN_LD_INTERNAL_4sf);
7128117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_4sf", void_ftype_pfloat_v4sf,
7129117395Skan	       ALTIVEC_BUILTIN_ST_INTERNAL_4sf);
7130117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_4si", v4si_ftype_pcint,
7131117395Skan	       ALTIVEC_BUILTIN_LD_INTERNAL_4si);
7132117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_4si", void_ftype_pint_v4si,
7133117395Skan	       ALTIVEC_BUILTIN_ST_INTERNAL_4si);
7134117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_8hi", v8hi_ftype_pcshort,
7135117395Skan	       ALTIVEC_BUILTIN_LD_INTERNAL_8hi);
7136117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_8hi", void_ftype_pshort_v8hi,
7137117395Skan	       ALTIVEC_BUILTIN_ST_INTERNAL_8hi);
7138117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_16qi", v16qi_ftype_pcchar,
7139117395Skan	       ALTIVEC_BUILTIN_LD_INTERNAL_16qi);
7140117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_16qi", void_ftype_pchar_v16qi,
7141117395Skan	       ALTIVEC_BUILTIN_ST_INTERNAL_16qi);
7142117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_mtvscr", void_ftype_v4si, ALTIVEC_BUILTIN_MTVSCR);
7143117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_mfvscr", v8hi_ftype_void, ALTIVEC_BUILTIN_MFVSCR);
7144117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_dssall", void_ftype_void, ALTIVEC_BUILTIN_DSSALL);
7145146895Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_dss", void_ftype_int, ALTIVEC_BUILTIN_DSS);
7146132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvsl", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVSL);
7147132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvsr", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVSR);
7148132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvebx", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVEBX);
7149132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvehx", v8hi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVEHX);
7150132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvewx", v4si_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVEWX);
7151132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvxl", v4si_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVXL);
7152132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvx", v4si_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVX);
7153132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvx", void_ftype_v4si_long_pvoid, ALTIVEC_BUILTIN_STVX);
7154132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvewx", void_ftype_v4si_long_pvoid, ALTIVEC_BUILTIN_STVEWX);
7155132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvxl", void_ftype_v4si_long_pvoid, ALTIVEC_BUILTIN_STVXL);
7156132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvebx", void_ftype_v16qi_long_pvoid, ALTIVEC_BUILTIN_STVEBX);
7157132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvehx", void_ftype_v8hi_long_pvoid, ALTIVEC_BUILTIN_STVEHX);
715890075Sobrien
7159146895Skan  /* See altivec.h for usage of "__builtin_altivec_compiletime_error".  */
7160146895Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_compiletime_error", int_ftype_pcchar,
7161146895Skan	       ALTIVEC_BUILTIN_COMPILETIME_ERROR);
7162146895Skan
7163117395Skan  /* Add the DST variants.  */
7164117395Skan  d = (struct builtin_description *) bdesc_dst;
7165117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_dst); i++, d++)
7166146895Skan    def_builtin (d->mask, d->name, void_ftype_pcvoid_int_int, d->code);
7167117395Skan
7168117395Skan  /* Initialize the predicates.  */
7169117395Skan  dp = (struct builtin_description_predicates *) bdesc_altivec_preds;
7170117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_altivec_preds); i++, dp++)
7171117395Skan    {
7172117395Skan      enum machine_mode mode1;
7173117395Skan      tree type;
7174117395Skan
7175117395Skan      mode1 = insn_data[dp->icode].operand[1].mode;
7176117395Skan
7177117395Skan      switch (mode1)
7178117395Skan	{
7179117395Skan	case V4SImode:
7180117395Skan	  type = int_ftype_int_v4si_v4si;
7181117395Skan	  break;
7182117395Skan	case V8HImode:
7183117395Skan	  type = int_ftype_int_v8hi_v8hi;
7184117395Skan	  break;
7185117395Skan	case V16QImode:
7186117395Skan	  type = int_ftype_int_v16qi_v16qi;
7187117395Skan	  break;
7188117395Skan	case V4SFmode:
7189117395Skan	  type = int_ftype_int_v4sf_v4sf;
7190117395Skan	  break;
7191117395Skan	default:
7192117395Skan	  abort ();
7193117395Skan	}
7194117395Skan
7195117395Skan      def_builtin (dp->mask, dp->name, type, dp->code);
7196117395Skan    }
7197117395Skan
7198117395Skan  /* Initialize the abs* operators.  */
7199117395Skan  d = (struct builtin_description *) bdesc_abs;
7200117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_abs); i++, d++)
7201117395Skan    {
7202117395Skan      enum machine_mode mode0;
7203117395Skan      tree type;
7204117395Skan
7205117395Skan      mode0 = insn_data[d->icode].operand[0].mode;
7206117395Skan
7207117395Skan      switch (mode0)
7208117395Skan	{
7209117395Skan	case V4SImode:
7210117395Skan	  type = v4si_ftype_v4si;
7211117395Skan	  break;
7212117395Skan	case V8HImode:
7213117395Skan	  type = v8hi_ftype_v8hi;
7214117395Skan	  break;
7215117395Skan	case V16QImode:
7216117395Skan	  type = v16qi_ftype_v16qi;
7217117395Skan	  break;
7218117395Skan	case V4SFmode:
7219117395Skan	  type = v4sf_ftype_v4sf;
7220117395Skan	  break;
7221117395Skan	default:
7222117395Skan	  abort ();
7223117395Skan	}
7224117395Skan
7225117395Skan      def_builtin (d->mask, d->name, type, d->code);
7226117395Skan    }
7227117395Skan}
7228117395Skan
7229117395Skanstatic void
7230132718Skanrs6000_common_init_builtins (void)
7231117395Skan{
7232117395Skan  struct builtin_description *d;
7233117395Skan  size_t i;
7234117395Skan
7235117395Skan  tree v4sf_ftype_v4sf_v4sf_v16qi
7236117395Skan    = build_function_type_list (V4SF_type_node,
7237117395Skan				V4SF_type_node, V4SF_type_node,
7238117395Skan				V16QI_type_node, NULL_TREE);
7239117395Skan  tree v4si_ftype_v4si_v4si_v16qi
7240117395Skan    = build_function_type_list (V4SI_type_node,
7241117395Skan				V4SI_type_node, V4SI_type_node,
7242117395Skan				V16QI_type_node, NULL_TREE);
7243117395Skan  tree v8hi_ftype_v8hi_v8hi_v16qi
7244117395Skan    = build_function_type_list (V8HI_type_node,
7245117395Skan				V8HI_type_node, V8HI_type_node,
7246117395Skan				V16QI_type_node, NULL_TREE);
7247117395Skan  tree v16qi_ftype_v16qi_v16qi_v16qi
7248117395Skan    = build_function_type_list (V16QI_type_node,
7249117395Skan				V16QI_type_node, V16QI_type_node,
7250117395Skan				V16QI_type_node, NULL_TREE);
7251146895Skan  tree v4si_ftype_int
7252146895Skan    = build_function_type_list (V4SI_type_node, integer_type_node, NULL_TREE);
7253146895Skan  tree v8hi_ftype_int
7254146895Skan    = build_function_type_list (V8HI_type_node, integer_type_node, NULL_TREE);
7255146895Skan  tree v16qi_ftype_int
7256146895Skan    = build_function_type_list (V16QI_type_node, integer_type_node, NULL_TREE);
7257117395Skan  tree v8hi_ftype_v16qi
7258117395Skan    = build_function_type_list (V8HI_type_node, V16QI_type_node, NULL_TREE);
7259117395Skan  tree v4sf_ftype_v4sf
7260117395Skan    = build_function_type_list (V4SF_type_node, V4SF_type_node, NULL_TREE);
7261117395Skan
7262117395Skan  tree v2si_ftype_v2si_v2si
7263132718Skan    = build_function_type_list (opaque_V2SI_type_node,
7264132718Skan				opaque_V2SI_type_node,
7265132718Skan				opaque_V2SI_type_node, NULL_TREE);
7266117395Skan
7267117395Skan  tree v2sf_ftype_v2sf_v2sf
7268132718Skan    = build_function_type_list (opaque_V2SF_type_node,
7269132718Skan				opaque_V2SF_type_node,
7270132718Skan				opaque_V2SF_type_node, NULL_TREE);
7271117395Skan
7272117395Skan  tree v2si_ftype_int_int
7273132718Skan    = build_function_type_list (opaque_V2SI_type_node,
7274117395Skan				integer_type_node, integer_type_node,
7275117395Skan				NULL_TREE);
7276117395Skan
7277117395Skan  tree v2si_ftype_v2si
7278132718Skan    = build_function_type_list (opaque_V2SI_type_node,
7279132718Skan				opaque_V2SI_type_node, NULL_TREE);
7280117395Skan
7281117395Skan  tree v2sf_ftype_v2sf
7282132718Skan    = build_function_type_list (opaque_V2SF_type_node,
7283132718Skan				opaque_V2SF_type_node, NULL_TREE);
7284117395Skan
7285117395Skan  tree v2sf_ftype_v2si
7286132718Skan    = build_function_type_list (opaque_V2SF_type_node,
7287132718Skan				opaque_V2SI_type_node, NULL_TREE);
7288117395Skan
7289117395Skan  tree v2si_ftype_v2sf
7290132718Skan    = build_function_type_list (opaque_V2SI_type_node,
7291132718Skan				opaque_V2SF_type_node, NULL_TREE);
7292117395Skan
7293117395Skan  tree v2si_ftype_v2si_char
7294132718Skan    = build_function_type_list (opaque_V2SI_type_node,
7295132718Skan				opaque_V2SI_type_node,
7296132718Skan				char_type_node, NULL_TREE);
7297117395Skan
7298117395Skan  tree v2si_ftype_int_char
7299132718Skan    = build_function_type_list (opaque_V2SI_type_node,
7300117395Skan				integer_type_node, char_type_node, NULL_TREE);
7301117395Skan
7302117395Skan  tree v2si_ftype_char
7303132718Skan    = build_function_type_list (opaque_V2SI_type_node,
7304132718Skan				char_type_node, NULL_TREE);
7305117395Skan
7306117395Skan  tree int_ftype_int_int
7307117395Skan    = build_function_type_list (integer_type_node,
7308117395Skan				integer_type_node, integer_type_node,
7309117395Skan				NULL_TREE);
7310117395Skan
7311117395Skan  tree v4si_ftype_v4si_v4si
7312117395Skan    = build_function_type_list (V4SI_type_node,
7313117395Skan				V4SI_type_node, V4SI_type_node, NULL_TREE);
7314146895Skan  tree v4sf_ftype_v4si_int
7315117395Skan    = build_function_type_list (V4SF_type_node,
7316146895Skan				V4SI_type_node, integer_type_node, NULL_TREE);
7317146895Skan  tree v4si_ftype_v4sf_int
7318117395Skan    = build_function_type_list (V4SI_type_node,
7319146895Skan				V4SF_type_node, integer_type_node, NULL_TREE);
7320146895Skan  tree v4si_ftype_v4si_int
7321117395Skan    = build_function_type_list (V4SI_type_node,
7322146895Skan				V4SI_type_node, integer_type_node, NULL_TREE);
7323146895Skan  tree v8hi_ftype_v8hi_int
7324117395Skan    = build_function_type_list (V8HI_type_node,
7325146895Skan				V8HI_type_node, integer_type_node, NULL_TREE);
7326146895Skan  tree v16qi_ftype_v16qi_int
7327117395Skan    = build_function_type_list (V16QI_type_node,
7328146895Skan				V16QI_type_node, integer_type_node, NULL_TREE);
7329146895Skan  tree v16qi_ftype_v16qi_v16qi_int
7330117395Skan    = build_function_type_list (V16QI_type_node,
7331117395Skan				V16QI_type_node, V16QI_type_node,
7332146895Skan				integer_type_node, NULL_TREE);
7333146895Skan  tree v8hi_ftype_v8hi_v8hi_int
7334117395Skan    = build_function_type_list (V8HI_type_node,
7335117395Skan				V8HI_type_node, V8HI_type_node,
7336146895Skan				integer_type_node, NULL_TREE);
7337146895Skan  tree v4si_ftype_v4si_v4si_int
7338117395Skan    = build_function_type_list (V4SI_type_node,
7339117395Skan				V4SI_type_node, V4SI_type_node,
7340146895Skan				integer_type_node, NULL_TREE);
7341146895Skan  tree v4sf_ftype_v4sf_v4sf_int
7342117395Skan    = build_function_type_list (V4SF_type_node,
7343117395Skan				V4SF_type_node, V4SF_type_node,
7344146895Skan				integer_type_node, NULL_TREE);
734590075Sobrien  tree v4sf_ftype_v4sf_v4sf
7346117395Skan    = build_function_type_list (V4SF_type_node,
7347117395Skan				V4SF_type_node, V4SF_type_node, NULL_TREE);
734890075Sobrien  tree v4sf_ftype_v4sf_v4sf_v4si
7349117395Skan    = build_function_type_list (V4SF_type_node,
7350117395Skan				V4SF_type_node, V4SF_type_node,
7351117395Skan				V4SI_type_node, NULL_TREE);
735290075Sobrien  tree v4sf_ftype_v4sf_v4sf_v4sf
7353117395Skan    = build_function_type_list (V4SF_type_node,
7354117395Skan				V4SF_type_node, V4SF_type_node,
7355117395Skan				V4SF_type_node, NULL_TREE);
735690075Sobrien  tree v4si_ftype_v4si_v4si_v4si
7357117395Skan    = build_function_type_list (V4SI_type_node,
7358117395Skan				V4SI_type_node, V4SI_type_node,
7359117395Skan				V4SI_type_node, NULL_TREE);
736090075Sobrien  tree v8hi_ftype_v8hi_v8hi
7361117395Skan    = build_function_type_list (V8HI_type_node,
7362117395Skan				V8HI_type_node, V8HI_type_node, NULL_TREE);
736390075Sobrien  tree v8hi_ftype_v8hi_v8hi_v8hi
7364117395Skan    = build_function_type_list (V8HI_type_node,
7365117395Skan				V8HI_type_node, V8HI_type_node,
7366117395Skan				V8HI_type_node, NULL_TREE);
736790075Sobrien tree v4si_ftype_v8hi_v8hi_v4si
7368117395Skan    = build_function_type_list (V4SI_type_node,
7369117395Skan				V8HI_type_node, V8HI_type_node,
7370117395Skan				V4SI_type_node, NULL_TREE);
737190075Sobrien tree v4si_ftype_v16qi_v16qi_v4si
7372117395Skan    = build_function_type_list (V4SI_type_node,
7373117395Skan				V16QI_type_node, V16QI_type_node,
7374117395Skan				V4SI_type_node, NULL_TREE);
737590075Sobrien  tree v16qi_ftype_v16qi_v16qi
7376117395Skan    = build_function_type_list (V16QI_type_node,
7377117395Skan				V16QI_type_node, V16QI_type_node, NULL_TREE);
737890075Sobrien  tree v4si_ftype_v4sf_v4sf
7379117395Skan    = build_function_type_list (V4SI_type_node,
7380117395Skan				V4SF_type_node, V4SF_type_node, NULL_TREE);
738190075Sobrien  tree v8hi_ftype_v16qi_v16qi
7382117395Skan    = build_function_type_list (V8HI_type_node,
7383117395Skan				V16QI_type_node, V16QI_type_node, NULL_TREE);
738490075Sobrien  tree v4si_ftype_v8hi_v8hi
7385117395Skan    = build_function_type_list (V4SI_type_node,
7386117395Skan				V8HI_type_node, V8HI_type_node, NULL_TREE);
738790075Sobrien  tree v8hi_ftype_v4si_v4si
7388117395Skan    = build_function_type_list (V8HI_type_node,
7389117395Skan				V4SI_type_node, V4SI_type_node, NULL_TREE);
739090075Sobrien  tree v16qi_ftype_v8hi_v8hi
7391117395Skan    = build_function_type_list (V16QI_type_node,
7392117395Skan				V8HI_type_node, V8HI_type_node, NULL_TREE);
739390075Sobrien  tree v4si_ftype_v16qi_v4si
7394117395Skan    = build_function_type_list (V4SI_type_node,
7395117395Skan				V16QI_type_node, V4SI_type_node, NULL_TREE);
739690075Sobrien  tree v4si_ftype_v16qi_v16qi
7397117395Skan    = build_function_type_list (V4SI_type_node,
7398117395Skan				V16QI_type_node, V16QI_type_node, NULL_TREE);
739990075Sobrien  tree v4si_ftype_v8hi_v4si
7400117395Skan    = build_function_type_list (V4SI_type_node,
7401117395Skan				V8HI_type_node, V4SI_type_node, NULL_TREE);
740290075Sobrien  tree v4si_ftype_v8hi
7403117395Skan    = build_function_type_list (V4SI_type_node, V8HI_type_node, NULL_TREE);
740490075Sobrien  tree int_ftype_v4si_v4si
7405117395Skan    = build_function_type_list (integer_type_node,
7406117395Skan				V4SI_type_node, V4SI_type_node, NULL_TREE);
740790075Sobrien  tree int_ftype_v4sf_v4sf
7408117395Skan    = build_function_type_list (integer_type_node,
7409117395Skan				V4SF_type_node, V4SF_type_node, NULL_TREE);
741090075Sobrien  tree int_ftype_v16qi_v16qi
7411117395Skan    = build_function_type_list (integer_type_node,
7412117395Skan				V16QI_type_node, V16QI_type_node, NULL_TREE);
741390075Sobrien  tree int_ftype_v8hi_v8hi
7414117395Skan    = build_function_type_list (integer_type_node,
7415117395Skan				V8HI_type_node, V8HI_type_node, NULL_TREE);
741690075Sobrien
741790075Sobrien  /* Add the simple ternary operators.  */
741890075Sobrien  d = (struct builtin_description *) bdesc_3arg;
7419117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_3arg); i++, d++)
742090075Sobrien    {
742190075Sobrien
742290075Sobrien      enum machine_mode mode0, mode1, mode2, mode3;
742390075Sobrien      tree type;
742490075Sobrien
7425117395Skan      if (d->name == 0 || d->icode == CODE_FOR_nothing)
742690075Sobrien	continue;
742790075Sobrien
742890075Sobrien      mode0 = insn_data[d->icode].operand[0].mode;
742990075Sobrien      mode1 = insn_data[d->icode].operand[1].mode;
743090075Sobrien      mode2 = insn_data[d->icode].operand[2].mode;
743190075Sobrien      mode3 = insn_data[d->icode].operand[3].mode;
743290075Sobrien
743390075Sobrien      /* When all four are of the same mode.  */
743490075Sobrien      if (mode0 == mode1 && mode1 == mode2 && mode2 == mode3)
743590075Sobrien	{
743690075Sobrien	  switch (mode0)
743790075Sobrien	    {
743890075Sobrien	    case V4SImode:
743990075Sobrien	      type = v4si_ftype_v4si_v4si_v4si;
744090075Sobrien	      break;
744190075Sobrien	    case V4SFmode:
744290075Sobrien	      type = v4sf_ftype_v4sf_v4sf_v4sf;
744390075Sobrien	      break;
744490075Sobrien	    case V8HImode:
744590075Sobrien	      type = v8hi_ftype_v8hi_v8hi_v8hi;
744690075Sobrien	      break;
744790075Sobrien	    case V16QImode:
744890075Sobrien	      type = v16qi_ftype_v16qi_v16qi_v16qi;
744990075Sobrien	      break;
745090075Sobrien	    default:
745190075Sobrien	      abort();
745290075Sobrien	    }
745390075Sobrien	}
745490075Sobrien      else if (mode0 == mode1 && mode1 == mode2 && mode3 == V16QImode)
745590075Sobrien        {
745690075Sobrien	  switch (mode0)
745790075Sobrien	    {
745890075Sobrien	    case V4SImode:
745990075Sobrien	      type = v4si_ftype_v4si_v4si_v16qi;
746090075Sobrien	      break;
746190075Sobrien	    case V4SFmode:
746290075Sobrien	      type = v4sf_ftype_v4sf_v4sf_v16qi;
746390075Sobrien	      break;
746490075Sobrien	    case V8HImode:
746590075Sobrien	      type = v8hi_ftype_v8hi_v8hi_v16qi;
746690075Sobrien	      break;
746790075Sobrien	    case V16QImode:
746890075Sobrien	      type = v16qi_ftype_v16qi_v16qi_v16qi;
746990075Sobrien	      break;
747090075Sobrien	    default:
747190075Sobrien	      abort();
747290075Sobrien	    }
747390075Sobrien	}
747490075Sobrien      else if (mode0 == V4SImode && mode1 == V16QImode && mode2 == V16QImode
747590075Sobrien	       && mode3 == V4SImode)
747690075Sobrien	type = v4si_ftype_v16qi_v16qi_v4si;
747790075Sobrien      else if (mode0 == V4SImode && mode1 == V8HImode && mode2 == V8HImode
747890075Sobrien	       && mode3 == V4SImode)
747990075Sobrien	type = v4si_ftype_v8hi_v8hi_v4si;
748090075Sobrien      else if (mode0 == V4SFmode && mode1 == V4SFmode && mode2 == V4SFmode
748190075Sobrien	       && mode3 == V4SImode)
748290075Sobrien	type = v4sf_ftype_v4sf_v4sf_v4si;
748390075Sobrien
748490075Sobrien      /* vchar, vchar, vchar, 4 bit literal.  */
748590075Sobrien      else if (mode0 == V16QImode && mode1 == mode0 && mode2 == mode0
748690075Sobrien	       && mode3 == QImode)
7487146895Skan	type = v16qi_ftype_v16qi_v16qi_int;
748890075Sobrien
748990075Sobrien      /* vshort, vshort, vshort, 4 bit literal.  */
749090075Sobrien      else if (mode0 == V8HImode && mode1 == mode0 && mode2 == mode0
749190075Sobrien	       && mode3 == QImode)
7492146895Skan	type = v8hi_ftype_v8hi_v8hi_int;
749390075Sobrien
749490075Sobrien      /* vint, vint, vint, 4 bit literal.  */
749590075Sobrien      else if (mode0 == V4SImode && mode1 == mode0 && mode2 == mode0
749690075Sobrien	       && mode3 == QImode)
7497146895Skan	type = v4si_ftype_v4si_v4si_int;
749890075Sobrien
749990075Sobrien      /* vfloat, vfloat, vfloat, 4 bit literal.  */
750090075Sobrien      else if (mode0 == V4SFmode && mode1 == mode0 && mode2 == mode0
750190075Sobrien	       && mode3 == QImode)
7502146895Skan	type = v4sf_ftype_v4sf_v4sf_int;
750390075Sobrien
750490075Sobrien      else
750590075Sobrien	abort ();
750690075Sobrien
750790075Sobrien      def_builtin (d->mask, d->name, type, d->code);
750890075Sobrien    }
750990075Sobrien
751090075Sobrien  /* Add the simple binary operators.  */
751190075Sobrien  d = (struct builtin_description *) bdesc_2arg;
7512117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
751390075Sobrien    {
751490075Sobrien      enum machine_mode mode0, mode1, mode2;
751590075Sobrien      tree type;
751690075Sobrien
7517117395Skan      if (d->name == 0 || d->icode == CODE_FOR_nothing)
751890075Sobrien	continue;
751990075Sobrien
752090075Sobrien      mode0 = insn_data[d->icode].operand[0].mode;
752190075Sobrien      mode1 = insn_data[d->icode].operand[1].mode;
752290075Sobrien      mode2 = insn_data[d->icode].operand[2].mode;
752390075Sobrien
752490075Sobrien      /* When all three operands are of the same mode.  */
752590075Sobrien      if (mode0 == mode1 && mode1 == mode2)
752690075Sobrien	{
752790075Sobrien	  switch (mode0)
752890075Sobrien	    {
752990075Sobrien	    case V4SFmode:
753090075Sobrien	      type = v4sf_ftype_v4sf_v4sf;
753190075Sobrien	      break;
753290075Sobrien	    case V4SImode:
753390075Sobrien	      type = v4si_ftype_v4si_v4si;
753490075Sobrien	      break;
753590075Sobrien	    case V16QImode:
753690075Sobrien	      type = v16qi_ftype_v16qi_v16qi;
753790075Sobrien	      break;
753890075Sobrien	    case V8HImode:
753990075Sobrien	      type = v8hi_ftype_v8hi_v8hi;
754090075Sobrien	      break;
7541117395Skan	    case V2SImode:
7542117395Skan	      type = v2si_ftype_v2si_v2si;
7543117395Skan	      break;
7544117395Skan	    case V2SFmode:
7545117395Skan	      type = v2sf_ftype_v2sf_v2sf;
7546117395Skan	      break;
7547117395Skan	    case SImode:
7548117395Skan	      type = int_ftype_int_int;
7549117395Skan	      break;
755090075Sobrien	    default:
755190075Sobrien	      abort ();
755290075Sobrien	    }
755390075Sobrien	}
755490075Sobrien
755590075Sobrien      /* A few other combos we really don't want to do manually.  */
755690075Sobrien
755790075Sobrien      /* vint, vfloat, vfloat.  */
755890075Sobrien      else if (mode0 == V4SImode && mode1 == V4SFmode && mode2 == V4SFmode)
755990075Sobrien	type = v4si_ftype_v4sf_v4sf;
756090075Sobrien
756190075Sobrien      /* vshort, vchar, vchar.  */
756290075Sobrien      else if (mode0 == V8HImode && mode1 == V16QImode && mode2 == V16QImode)
756390075Sobrien	type = v8hi_ftype_v16qi_v16qi;
756490075Sobrien
756590075Sobrien      /* vint, vshort, vshort.  */
756690075Sobrien      else if (mode0 == V4SImode && mode1 == V8HImode && mode2 == V8HImode)
756790075Sobrien	type = v4si_ftype_v8hi_v8hi;
756890075Sobrien
756990075Sobrien      /* vshort, vint, vint.  */
757090075Sobrien      else if (mode0 == V8HImode && mode1 == V4SImode && mode2 == V4SImode)
757190075Sobrien	type = v8hi_ftype_v4si_v4si;
757290075Sobrien
757390075Sobrien      /* vchar, vshort, vshort.  */
757490075Sobrien      else if (mode0 == V16QImode && mode1 == V8HImode && mode2 == V8HImode)
757590075Sobrien	type = v16qi_ftype_v8hi_v8hi;
757690075Sobrien
757790075Sobrien      /* vint, vchar, vint.  */
757890075Sobrien      else if (mode0 == V4SImode && mode1 == V16QImode && mode2 == V4SImode)
757990075Sobrien	type = v4si_ftype_v16qi_v4si;
758090075Sobrien
758190075Sobrien      /* vint, vchar, vchar.  */
758290075Sobrien      else if (mode0 == V4SImode && mode1 == V16QImode && mode2 == V16QImode)
758390075Sobrien	type = v4si_ftype_v16qi_v16qi;
758490075Sobrien
758590075Sobrien      /* vint, vshort, vint.  */
758690075Sobrien      else if (mode0 == V4SImode && mode1 == V8HImode && mode2 == V4SImode)
758790075Sobrien	type = v4si_ftype_v8hi_v4si;
758890075Sobrien
758990075Sobrien      /* vint, vint, 5 bit literal.  */
759090075Sobrien      else if (mode0 == V4SImode && mode1 == V4SImode && mode2 == QImode)
7591146895Skan	type = v4si_ftype_v4si_int;
759290075Sobrien
759390075Sobrien      /* vshort, vshort, 5 bit literal.  */
759490075Sobrien      else if (mode0 == V8HImode && mode1 == V8HImode && mode2 == QImode)
7595146895Skan	type = v8hi_ftype_v8hi_int;
759690075Sobrien
759790075Sobrien      /* vchar, vchar, 5 bit literal.  */
759890075Sobrien      else if (mode0 == V16QImode && mode1 == V16QImode && mode2 == QImode)
7599146895Skan	type = v16qi_ftype_v16qi_int;
760090075Sobrien
760190075Sobrien      /* vfloat, vint, 5 bit literal.  */
760290075Sobrien      else if (mode0 == V4SFmode && mode1 == V4SImode && mode2 == QImode)
7603146895Skan	type = v4sf_ftype_v4si_int;
760490075Sobrien
760590075Sobrien      /* vint, vfloat, 5 bit literal.  */
760690075Sobrien      else if (mode0 == V4SImode && mode1 == V4SFmode && mode2 == QImode)
7607146895Skan	type = v4si_ftype_v4sf_int;
760890075Sobrien
7609117395Skan      else if (mode0 == V2SImode && mode1 == SImode && mode2 == SImode)
7610117395Skan	type = v2si_ftype_int_int;
7611117395Skan
7612117395Skan      else if (mode0 == V2SImode && mode1 == V2SImode && mode2 == QImode)
7613117395Skan	type = v2si_ftype_v2si_char;
7614117395Skan
7615117395Skan      else if (mode0 == V2SImode && mode1 == SImode && mode2 == QImode)
7616117395Skan	type = v2si_ftype_int_char;
7617117395Skan
761890075Sobrien      /* int, x, x.  */
761990075Sobrien      else if (mode0 == SImode)
762090075Sobrien	{
762190075Sobrien	  switch (mode1)
762290075Sobrien	    {
762390075Sobrien	    case V4SImode:
762490075Sobrien	      type = int_ftype_v4si_v4si;
762590075Sobrien	      break;
762690075Sobrien	    case V4SFmode:
762790075Sobrien	      type = int_ftype_v4sf_v4sf;
762890075Sobrien	      break;
762990075Sobrien	    case V16QImode:
763090075Sobrien	      type = int_ftype_v16qi_v16qi;
763190075Sobrien	      break;
763290075Sobrien	    case V8HImode:
763390075Sobrien	      type = int_ftype_v8hi_v8hi;
763490075Sobrien	      break;
763590075Sobrien	    default:
763690075Sobrien	      abort ();
763790075Sobrien	    }
763890075Sobrien	}
763990075Sobrien
764090075Sobrien      else
764190075Sobrien	abort ();
764290075Sobrien
764390075Sobrien      def_builtin (d->mask, d->name, type, d->code);
764490075Sobrien    }
764590075Sobrien
764690075Sobrien  /* Add the simple unary operators.  */
764790075Sobrien  d = (struct builtin_description *) bdesc_1arg;
7648117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
764990075Sobrien    {
765090075Sobrien      enum machine_mode mode0, mode1;
765190075Sobrien      tree type;
765290075Sobrien
7653117395Skan      if (d->name == 0 || d->icode == CODE_FOR_nothing)
765490075Sobrien	continue;
765590075Sobrien
765690075Sobrien      mode0 = insn_data[d->icode].operand[0].mode;
765790075Sobrien      mode1 = insn_data[d->icode].operand[1].mode;
765890075Sobrien
765990075Sobrien      if (mode0 == V4SImode && mode1 == QImode)
7660146895Skan        type = v4si_ftype_int;
766190075Sobrien      else if (mode0 == V8HImode && mode1 == QImode)
7662146895Skan        type = v8hi_ftype_int;
766390075Sobrien      else if (mode0 == V16QImode && mode1 == QImode)
7664146895Skan        type = v16qi_ftype_int;
766590075Sobrien      else if (mode0 == V4SFmode && mode1 == V4SFmode)
766690075Sobrien	type = v4sf_ftype_v4sf;
766790075Sobrien      else if (mode0 == V8HImode && mode1 == V16QImode)
766890075Sobrien	type = v8hi_ftype_v16qi;
766990075Sobrien      else if (mode0 == V4SImode && mode1 == V8HImode)
767090075Sobrien	type = v4si_ftype_v8hi;
7671117395Skan      else if (mode0 == V2SImode && mode1 == V2SImode)
7672117395Skan	type = v2si_ftype_v2si;
7673117395Skan      else if (mode0 == V2SFmode && mode1 == V2SFmode)
7674117395Skan	type = v2sf_ftype_v2sf;
7675117395Skan      else if (mode0 == V2SFmode && mode1 == V2SImode)
7676117395Skan	type = v2sf_ftype_v2si;
7677117395Skan      else if (mode0 == V2SImode && mode1 == V2SFmode)
7678117395Skan	type = v2si_ftype_v2sf;
7679117395Skan      else if (mode0 == V2SImode && mode1 == QImode)
7680117395Skan	type = v2si_ftype_char;
768190075Sobrien      else
768290075Sobrien	abort ();
768390075Sobrien
768490075Sobrien      def_builtin (d->mask, d->name, type, d->code);
768590075Sobrien    }
768690075Sobrien}
768790075Sobrien
7688132718Skanstatic void
7689132718Skanrs6000_init_libfuncs (void)
7690132718Skan{
7691132718Skan  if (!TARGET_HARD_FLOAT)
7692132718Skan    return;
7693132718Skan
7694132718Skan  if (DEFAULT_ABI != ABI_V4)
7695132718Skan    {
7696132718Skan      if (TARGET_XCOFF && ! TARGET_POWER2 && ! TARGET_POWERPC)
7697132718Skan	{
7698132718Skan	  /* AIX library routines for float->int conversion.  */
7699132718Skan	  set_conv_libfunc (sfix_optab, SImode, DFmode, "__itrunc");
7700132718Skan	  set_conv_libfunc (ufix_optab, SImode, DFmode, "__uitrunc");
7701132718Skan	  set_conv_libfunc (sfix_optab, SImode, TFmode, "_qitrunc");
7702132718Skan	  set_conv_libfunc (ufix_optab, SImode, TFmode, "_quitrunc");
7703132718Skan	}
7704132718Skan
7705146895Skan      /* AIX/Darwin/64-bit Linux quad floating point routines.  */
7706146895Skan      if (!TARGET_XL_COMPAT)
7707146895Skan	{
7708146895Skan	  set_optab_libfunc (add_optab, TFmode, "__gcc_qadd");
7709146895Skan	  set_optab_libfunc (sub_optab, TFmode, "__gcc_qsub");
7710146895Skan	  set_optab_libfunc (smul_optab, TFmode, "__gcc_qmul");
7711146895Skan	  set_optab_libfunc (sdiv_optab, TFmode, "__gcc_qdiv");
7712146895Skan	}
7713146895Skan      else
7714146895Skan	{
7715146895Skan	  set_optab_libfunc (add_optab, TFmode, "_xlqadd");
7716146895Skan	  set_optab_libfunc (sub_optab, TFmode, "_xlqsub");
7717146895Skan	  set_optab_libfunc (smul_optab, TFmode, "_xlqmul");
7718146895Skan	  set_optab_libfunc (sdiv_optab, TFmode, "_xlqdiv");
7719146895Skan	}
7720132718Skan    }
7721132718Skan  else
7722132718Skan    {
7723132718Skan      /* 32-bit SVR4 quad floating point routines.  */
7724132718Skan
7725132718Skan      set_optab_libfunc (add_optab, TFmode, "_q_add");
7726132718Skan      set_optab_libfunc (sub_optab, TFmode, "_q_sub");
7727132718Skan      set_optab_libfunc (neg_optab, TFmode, "_q_neg");
7728132718Skan      set_optab_libfunc (smul_optab, TFmode, "_q_mul");
7729132718Skan      set_optab_libfunc (sdiv_optab, TFmode, "_q_div");
7730132718Skan      if (TARGET_PPC_GPOPT || TARGET_POWER2)
7731132718Skan	set_optab_libfunc (sqrt_optab, TFmode, "_q_sqrt");
7732132718Skan
7733132718Skan      set_optab_libfunc (eq_optab, TFmode, "_q_feq");
7734132718Skan      set_optab_libfunc (ne_optab, TFmode, "_q_fne");
7735132718Skan      set_optab_libfunc (gt_optab, TFmode, "_q_fgt");
7736132718Skan      set_optab_libfunc (ge_optab, TFmode, "_q_fge");
7737132718Skan      set_optab_libfunc (lt_optab, TFmode, "_q_flt");
7738132718Skan      set_optab_libfunc (le_optab, TFmode, "_q_fle");
7739132718Skan
7740132718Skan      set_conv_libfunc (sext_optab, TFmode, SFmode, "_q_stoq");
7741132718Skan      set_conv_libfunc (sext_optab, TFmode, DFmode, "_q_dtoq");
7742132718Skan      set_conv_libfunc (trunc_optab, SFmode, TFmode, "_q_qtos");
7743132718Skan      set_conv_libfunc (trunc_optab, DFmode, TFmode, "_q_qtod");
7744132718Skan      set_conv_libfunc (sfix_optab, SImode, TFmode, "_q_qtoi");
7745132718Skan      set_conv_libfunc (ufix_optab, SImode, TFmode, "_q_qtou");
7746132718Skan      set_conv_libfunc (sfloat_optab, TFmode, SImode, "_q_itoq");
7747132718Skan    }
7748132718Skan}
774990075Sobrien
775090075Sobrien/* Expand a block move operation, and return 1 if successful.  Return 0
775190075Sobrien   if we should let the compiler generate normal code.
775290075Sobrien
775390075Sobrien   operands[0] is the destination
775490075Sobrien   operands[1] is the source
775590075Sobrien   operands[2] is the length
775690075Sobrien   operands[3] is the alignment */
775790075Sobrien
775890075Sobrien#define MAX_MOVE_REG 4
775990075Sobrien
776090075Sobrienint
7761132718Skanexpand_block_move (rtx operands[])
776290075Sobrien{
776390075Sobrien  rtx orig_dest = operands[0];
776490075Sobrien  rtx orig_src	= operands[1];
776590075Sobrien  rtx bytes_rtx	= operands[2];
776690075Sobrien  rtx align_rtx = operands[3];
776790075Sobrien  int constp	= (GET_CODE (bytes_rtx) == CONST_INT);
776890075Sobrien  int align;
776990075Sobrien  int bytes;
777090075Sobrien  int offset;
777190075Sobrien  int move_bytes;
7772132718Skan  rtx stores[MAX_MOVE_REG];
7773132718Skan  int num_reg = 0;
777490075Sobrien
777590075Sobrien  /* If this is not a fixed size move, just call memcpy */
777690075Sobrien  if (! constp)
777790075Sobrien    return 0;
777890075Sobrien
777990075Sobrien  /* If this is not a fixed size alignment, abort */
778090075Sobrien  if (GET_CODE (align_rtx) != CONST_INT)
778190075Sobrien    abort ();
778290075Sobrien  align = INTVAL (align_rtx);
778390075Sobrien
778490075Sobrien  /* Anything to move? */
778590075Sobrien  bytes = INTVAL (bytes_rtx);
778690075Sobrien  if (bytes <= 0)
778790075Sobrien    return 1;
778890075Sobrien
778990075Sobrien  /* store_one_arg depends on expand_block_move to handle at least the size of
779090075Sobrien     reg_parm_stack_space.  */
779190075Sobrien  if (bytes > (TARGET_POWERPC64 ? 64 : 32))
779290075Sobrien    return 0;
779390075Sobrien
7794132718Skan  for (offset = 0; bytes > 0; offset += move_bytes, bytes -= move_bytes)
779590075Sobrien    {
7796132718Skan      union {
7797132718Skan	rtx (*movstrsi) (rtx, rtx, rtx, rtx);
7798132718Skan	rtx (*mov) (rtx, rtx);
7799132718Skan      } gen_func;
7800132718Skan      enum machine_mode mode = BLKmode;
7801132718Skan      rtx src, dest;
7802132718Skan
7803132718Skan      if (TARGET_STRING
7804132718Skan	  && bytes > 24		/* move up to 32 bytes at a time */
7805132718Skan	  && ! fixed_regs[5]
7806132718Skan	  && ! fixed_regs[6]
7807132718Skan	  && ! fixed_regs[7]
7808132718Skan	  && ! fixed_regs[8]
7809132718Skan	  && ! fixed_regs[9]
7810132718Skan	  && ! fixed_regs[10]
7811132718Skan	  && ! fixed_regs[11]
7812132718Skan	  && ! fixed_regs[12])
781390075Sobrien	{
7814132718Skan	  move_bytes = (bytes > 32) ? 32 : bytes;
7815132718Skan	  gen_func.movstrsi = gen_movstrsi_8reg;
7816132718Skan	}
7817132718Skan      else if (TARGET_STRING
7818132718Skan	       && bytes > 16	/* move up to 24 bytes at a time */
7819132718Skan	       && ! fixed_regs[5]
7820132718Skan	       && ! fixed_regs[6]
7821132718Skan	       && ! fixed_regs[7]
7822132718Skan	       && ! fixed_regs[8]
7823132718Skan	       && ! fixed_regs[9]
7824132718Skan	       && ! fixed_regs[10])
7825132718Skan	{
7826132718Skan	  move_bytes = (bytes > 24) ? 24 : bytes;
7827132718Skan	  gen_func.movstrsi = gen_movstrsi_6reg;
7828132718Skan	}
7829132718Skan      else if (TARGET_STRING
7830132718Skan	       && bytes > 8	/* move up to 16 bytes at a time */
7831132718Skan	       && ! fixed_regs[5]
7832132718Skan	       && ! fixed_regs[6]
7833132718Skan	       && ! fixed_regs[7]
7834132718Skan	       && ! fixed_regs[8])
7835132718Skan	{
7836132718Skan	  move_bytes = (bytes > 16) ? 16 : bytes;
7837132718Skan	  gen_func.movstrsi = gen_movstrsi_4reg;
7838132718Skan	}
7839132718Skan      else if (bytes >= 8 && TARGET_POWERPC64
7840132718Skan	       /* 64-bit loads and stores require word-aligned
7841132718Skan		  displacements.  */
7842132718Skan	       && (align >= 8 || (! STRICT_ALIGNMENT && align >= 4)))
7843132718Skan	{
7844132718Skan	  move_bytes = 8;
7845132718Skan	  mode = DImode;
7846132718Skan	  gen_func.mov = gen_movdi;
7847132718Skan	}
7848132718Skan      else if (TARGET_STRING && bytes > 4 && !TARGET_POWERPC64)
7849132718Skan	{			/* move up to 8 bytes at a time */
7850132718Skan	  move_bytes = (bytes > 8) ? 8 : bytes;
7851132718Skan	  gen_func.movstrsi = gen_movstrsi_2reg;
7852132718Skan	}
7853132718Skan      else if (bytes >= 4 && (align >= 4 || ! STRICT_ALIGNMENT))
7854132718Skan	{			/* move 4 bytes */
7855132718Skan	  move_bytes = 4;
7856132718Skan	  mode = SImode;
7857132718Skan	  gen_func.mov = gen_movsi;
7858132718Skan	}
7859132718Skan      else if (bytes == 2 && (align >= 2 || ! STRICT_ALIGNMENT))
7860132718Skan	{			/* move 2 bytes */
7861132718Skan	  move_bytes = 2;
7862132718Skan	  mode = HImode;
7863132718Skan	  gen_func.mov = gen_movhi;
7864132718Skan	}
7865132718Skan      else if (TARGET_STRING && bytes > 1)
7866132718Skan	{			/* move up to 4 bytes at a time */
7867132718Skan	  move_bytes = (bytes > 4) ? 4 : bytes;
7868132718Skan	  gen_func.movstrsi = gen_movstrsi_1reg;
7869132718Skan	}
7870132718Skan      else /* move 1 byte at a time */
7871132718Skan	{
7872132718Skan	  move_bytes = 1;
7873132718Skan	  mode = QImode;
7874132718Skan	  gen_func.mov = gen_movqi;
7875132718Skan	}
7876132718Skan
7877132718Skan      src = adjust_address (orig_src, mode, offset);
7878132718Skan      dest = adjust_address (orig_dest, mode, offset);
7879132718Skan
7880132718Skan      if (mode != BLKmode)
7881132718Skan	{
7882132718Skan	  rtx tmp_reg = gen_reg_rtx (mode);
7883132718Skan
7884132718Skan	  emit_insn ((*gen_func.mov) (tmp_reg, src));
7885132718Skan	  stores[num_reg++] = (*gen_func.mov) (dest, tmp_reg);
7886132718Skan	}
7887103445Skan
7888132718Skan      if (mode == BLKmode || num_reg >= MAX_MOVE_REG || bytes == move_bytes)
7889132718Skan	{
7890132718Skan	  int i;
7891132718Skan	  for (i = 0; i < num_reg; i++)
7892132718Skan	    emit_insn (stores[i]);
7893132718Skan	  num_reg = 0;
789490075Sobrien	}
789590075Sobrien
7896132718Skan      if (mode == BLKmode)
789790075Sobrien	{
7898132718Skan	  /* Move the address into scratch registers.  The movstrsi
7899132718Skan	     patterns require zero offset.  */
7900132718Skan	  if (!REG_P (XEXP (src, 0)))
790190075Sobrien	    {
7902132718Skan	      rtx src_reg = copy_addr_to_reg (XEXP (src, 0));
7903132718Skan	      src = replace_equiv_address (src, src_reg);
790490075Sobrien	    }
7905132718Skan	  set_mem_size (src, GEN_INT (move_bytes));
7906132718Skan
7907132718Skan	  if (!REG_P (XEXP (dest, 0)))
790890075Sobrien	    {
7909132718Skan	      rtx dest_reg = copy_addr_to_reg (XEXP (dest, 0));
7910132718Skan	      dest = replace_equiv_address (dest, dest_reg);
791190075Sobrien	    }
7912132718Skan	  set_mem_size (dest, GEN_INT (move_bytes));
7913132718Skan
7914132718Skan	  emit_insn ((*gen_func.movstrsi) (dest, src,
7915132718Skan					   GEN_INT (move_bytes & 31),
7916132718Skan					   align_rtx));
791790075Sobrien	}
791890075Sobrien    }
791990075Sobrien
792090075Sobrien  return 1;
792190075Sobrien}
792290075Sobrien
792390075Sobrien
792490075Sobrien/* Return 1 if OP is a load multiple operation.  It is known to be a
792590075Sobrien   PARALLEL and the first section will be tested.  */
792690075Sobrien
792790075Sobrienint
7928132718Skanload_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
792990075Sobrien{
793090075Sobrien  int count = XVECLEN (op, 0);
793190075Sobrien  unsigned int dest_regno;
793290075Sobrien  rtx src_addr;
793390075Sobrien  int i;
793490075Sobrien
793590075Sobrien  /* Perform a quick check so we don't blow up below.  */
793690075Sobrien  if (count <= 1
793790075Sobrien      || GET_CODE (XVECEXP (op, 0, 0)) != SET
793890075Sobrien      || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != REG
793990075Sobrien      || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != MEM)
794090075Sobrien    return 0;
794190075Sobrien
794290075Sobrien  dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, 0)));
794390075Sobrien  src_addr = XEXP (SET_SRC (XVECEXP (op, 0, 0)), 0);
794490075Sobrien
794590075Sobrien  for (i = 1; i < count; i++)
794690075Sobrien    {
794790075Sobrien      rtx elt = XVECEXP (op, 0, i);
794890075Sobrien
794990075Sobrien      if (GET_CODE (elt) != SET
795090075Sobrien	  || GET_CODE (SET_DEST (elt)) != REG
795190075Sobrien	  || GET_MODE (SET_DEST (elt)) != SImode
795290075Sobrien	  || REGNO (SET_DEST (elt)) != dest_regno + i
795390075Sobrien	  || GET_CODE (SET_SRC (elt)) != MEM
795490075Sobrien	  || GET_MODE (SET_SRC (elt)) != SImode
795590075Sobrien	  || GET_CODE (XEXP (SET_SRC (elt), 0)) != PLUS
795690075Sobrien	  || ! rtx_equal_p (XEXP (XEXP (SET_SRC (elt), 0), 0), src_addr)
795790075Sobrien	  || GET_CODE (XEXP (XEXP (SET_SRC (elt), 0), 1)) != CONST_INT
795890075Sobrien	  || INTVAL (XEXP (XEXP (SET_SRC (elt), 0), 1)) != i * 4)
795990075Sobrien	return 0;
796090075Sobrien    }
796190075Sobrien
796290075Sobrien  return 1;
796390075Sobrien}
796490075Sobrien
796590075Sobrien/* Similar, but tests for store multiple.  Here, the second vector element
796690075Sobrien   is a CLOBBER.  It will be tested later.  */
796790075Sobrien
796890075Sobrienint
7969132718Skanstore_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
797090075Sobrien{
797190075Sobrien  int count = XVECLEN (op, 0) - 1;
797290075Sobrien  unsigned int src_regno;
797390075Sobrien  rtx dest_addr;
797490075Sobrien  int i;
797590075Sobrien
797690075Sobrien  /* Perform a quick check so we don't blow up below.  */
797790075Sobrien  if (count <= 1
797890075Sobrien      || GET_CODE (XVECEXP (op, 0, 0)) != SET
797990075Sobrien      || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != MEM
798090075Sobrien      || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != REG)
798190075Sobrien    return 0;
798290075Sobrien
798390075Sobrien  src_regno = REGNO (SET_SRC (XVECEXP (op, 0, 0)));
798490075Sobrien  dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, 0)), 0);
798590075Sobrien
798690075Sobrien  for (i = 1; i < count; i++)
798790075Sobrien    {
798890075Sobrien      rtx elt = XVECEXP (op, 0, i + 1);
798990075Sobrien
799090075Sobrien      if (GET_CODE (elt) != SET
799190075Sobrien	  || GET_CODE (SET_SRC (elt)) != REG
799290075Sobrien	  || GET_MODE (SET_SRC (elt)) != SImode
799390075Sobrien	  || REGNO (SET_SRC (elt)) != src_regno + i
799490075Sobrien	  || GET_CODE (SET_DEST (elt)) != MEM
799590075Sobrien	  || GET_MODE (SET_DEST (elt)) != SImode
799690075Sobrien	  || GET_CODE (XEXP (SET_DEST (elt), 0)) != PLUS
799790075Sobrien	  || ! rtx_equal_p (XEXP (XEXP (SET_DEST (elt), 0), 0), dest_addr)
799890075Sobrien	  || GET_CODE (XEXP (XEXP (SET_DEST (elt), 0), 1)) != CONST_INT
799990075Sobrien	  || INTVAL (XEXP (XEXP (SET_DEST (elt), 0), 1)) != i * 4)
800090075Sobrien	return 0;
800190075Sobrien    }
800290075Sobrien
800390075Sobrien  return 1;
800490075Sobrien}
800590075Sobrien
8006110611Skan/* Return a string to perform a load_multiple operation.
8007110611Skan   operands[0] is the vector.
8008110611Skan   operands[1] is the source address.
8009110611Skan   operands[2] is the first destination register.  */
8010110611Skan
8011110611Skanconst char *
8012132718Skanrs6000_output_load_multiple (rtx operands[3])
8013110611Skan{
8014110611Skan  /* We have to handle the case where the pseudo used to contain the address
8015110611Skan     is assigned to one of the output registers.  */
8016110611Skan  int i, j;
8017110611Skan  int words = XVECLEN (operands[0], 0);
8018110611Skan  rtx xop[10];
8019110611Skan
8020110611Skan  if (XVECLEN (operands[0], 0) == 1)
8021110611Skan    return "{l|lwz} %2,0(%1)";
8022110611Skan
8023110611Skan  for (i = 0; i < words; i++)
8024110611Skan    if (refers_to_regno_p (REGNO (operands[2]) + i,
8025110611Skan			   REGNO (operands[2]) + i + 1, operands[1], 0))
8026110611Skan      {
8027110611Skan	if (i == words-1)
8028110611Skan	  {
8029110611Skan	    xop[0] = GEN_INT (4 * (words-1));
8030110611Skan	    xop[1] = operands[1];
8031110611Skan	    xop[2] = operands[2];
8032110611Skan	    output_asm_insn ("{lsi|lswi} %2,%1,%0\n\t{l|lwz} %1,%0(%1)", xop);
8033110611Skan	    return "";
8034110611Skan	  }
8035110611Skan	else if (i == 0)
8036110611Skan	  {
8037110611Skan	    xop[0] = GEN_INT (4 * (words-1));
8038110611Skan	    xop[1] = operands[1];
8039110611Skan	    xop[2] = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
8040110611Skan	    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);
8041110611Skan	    return "";
8042110611Skan	  }
8043110611Skan	else
8044110611Skan	  {
8045110611Skan	    for (j = 0; j < words; j++)
8046110611Skan	      if (j != i)
8047110611Skan		{
8048110611Skan		  xop[0] = GEN_INT (j * 4);
8049110611Skan		  xop[1] = operands[1];
8050110611Skan		  xop[2] = gen_rtx_REG (SImode, REGNO (operands[2]) + j);
8051110611Skan		  output_asm_insn ("{l|lwz} %2,%0(%1)", xop);
8052110611Skan		}
8053110611Skan	    xop[0] = GEN_INT (i * 4);
8054110611Skan	    xop[1] = operands[1];
8055110611Skan	    output_asm_insn ("{l|lwz} %1,%0(%1)", xop);
8056110611Skan	    return "";
8057110611Skan	  }
8058110611Skan      }
8059110611Skan
8060110611Skan  return "{lsi|lswi} %2,%1,%N0";
8061110611Skan}
8062110611Skan
806390075Sobrien/* Return 1 for a parallel vrsave operation.  */
806490075Sobrien
806590075Sobrienint
8066132718Skanvrsave_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
806790075Sobrien{
806890075Sobrien  int count = XVECLEN (op, 0);
806990075Sobrien  unsigned int dest_regno, src_regno;
807090075Sobrien  int i;
807190075Sobrien
807290075Sobrien  if (count <= 1
807390075Sobrien      || GET_CODE (XVECEXP (op, 0, 0)) != SET
807490075Sobrien      || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != REG
807590075Sobrien      || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != UNSPEC_VOLATILE)
807690075Sobrien    return 0;
807790075Sobrien
807890075Sobrien  dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, 0)));
807990075Sobrien  src_regno  = REGNO (SET_SRC (XVECEXP (op, 0, 0)));
808090075Sobrien
808190075Sobrien  if (dest_regno != VRSAVE_REGNO
808290075Sobrien      && src_regno != VRSAVE_REGNO)
808390075Sobrien    return 0;
808490075Sobrien
808590075Sobrien  for (i = 1; i < count; i++)
808690075Sobrien    {
808790075Sobrien      rtx elt = XVECEXP (op, 0, i);
808890075Sobrien
808990075Sobrien      if (GET_CODE (elt) != CLOBBER
809090075Sobrien	  && GET_CODE (elt) != SET)
809190075Sobrien	return 0;
809290075Sobrien    }
809390075Sobrien
809490075Sobrien  return 1;
809590075Sobrien}
809690075Sobrien
8097132718Skan/* Return 1 for an PARALLEL suitable for mfcr.  */
8098132718Skan
8099132718Skanint
8100132718Skanmfcr_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
8101132718Skan{
8102132718Skan  int count = XVECLEN (op, 0);
8103132718Skan  int i;
8104132718Skan
8105132718Skan  /* Perform a quick check so we don't blow up below.  */
8106132718Skan  if (count < 1
8107132718Skan      || GET_CODE (XVECEXP (op, 0, 0)) != SET
8108132718Skan      || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != UNSPEC
8109132718Skan      || XVECLEN (SET_SRC (XVECEXP (op, 0, 0)), 0) != 2)
8110132718Skan    return 0;
8111132718Skan
8112132718Skan  for (i = 0; i < count; i++)
8113132718Skan    {
8114132718Skan      rtx exp = XVECEXP (op, 0, i);
8115132718Skan      rtx unspec;
8116132718Skan      int maskval;
8117132718Skan      rtx src_reg;
8118132718Skan
8119132718Skan      src_reg = XVECEXP (SET_SRC (exp), 0, 0);
8120132718Skan
8121132718Skan      if (GET_CODE (src_reg) != REG
8122132718Skan	  || GET_MODE (src_reg) != CCmode
8123132718Skan	  || ! CR_REGNO_P (REGNO (src_reg)))
8124132718Skan	return 0;
8125132718Skan
8126132718Skan      if (GET_CODE (exp) != SET
8127132718Skan	  || GET_CODE (SET_DEST (exp)) != REG
8128132718Skan	  || GET_MODE (SET_DEST (exp)) != SImode
8129132718Skan	  || ! INT_REGNO_P (REGNO (SET_DEST (exp))))
8130132718Skan	return 0;
8131132718Skan      unspec = SET_SRC (exp);
8132132718Skan      maskval = 1 << (MAX_CR_REGNO - REGNO (src_reg));
8133132718Skan
8134132718Skan      if (GET_CODE (unspec) != UNSPEC
8135132718Skan	  || XINT (unspec, 1) != UNSPEC_MOVESI_FROM_CR
8136132718Skan	  || XVECLEN (unspec, 0) != 2
8137132718Skan	  || XVECEXP (unspec, 0, 0) != src_reg
8138132718Skan	  || GET_CODE (XVECEXP (unspec, 0, 1)) != CONST_INT
8139132718Skan	  || INTVAL (XVECEXP (unspec, 0, 1)) != maskval)
8140132718Skan	return 0;
8141132718Skan    }
8142132718Skan  return 1;
8143132718Skan}
8144132718Skan
814590075Sobrien/* Return 1 for an PARALLEL suitable for mtcrf.  */
814690075Sobrien
814790075Sobrienint
8148132718Skanmtcrf_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
814990075Sobrien{
815090075Sobrien  int count = XVECLEN (op, 0);
815190075Sobrien  int i;
815290075Sobrien  rtx src_reg;
815390075Sobrien
815490075Sobrien  /* Perform a quick check so we don't blow up below.  */
815590075Sobrien  if (count < 1
815690075Sobrien      || GET_CODE (XVECEXP (op, 0, 0)) != SET
815790075Sobrien      || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != UNSPEC
815890075Sobrien      || XVECLEN (SET_SRC (XVECEXP (op, 0, 0)), 0) != 2)
815990075Sobrien    return 0;
816090075Sobrien  src_reg = XVECEXP (SET_SRC (XVECEXP (op, 0, 0)), 0, 0);
816190075Sobrien
816290075Sobrien  if (GET_CODE (src_reg) != REG
816390075Sobrien      || GET_MODE (src_reg) != SImode
816490075Sobrien      || ! INT_REGNO_P (REGNO (src_reg)))
816590075Sobrien    return 0;
816690075Sobrien
816790075Sobrien  for (i = 0; i < count; i++)
816890075Sobrien    {
816990075Sobrien      rtx exp = XVECEXP (op, 0, i);
817090075Sobrien      rtx unspec;
817190075Sobrien      int maskval;
817290075Sobrien
817390075Sobrien      if (GET_CODE (exp) != SET
817490075Sobrien	  || GET_CODE (SET_DEST (exp)) != REG
817590075Sobrien	  || GET_MODE (SET_DEST (exp)) != CCmode
817690075Sobrien	  || ! CR_REGNO_P (REGNO (SET_DEST (exp))))
817790075Sobrien	return 0;
817890075Sobrien      unspec = SET_SRC (exp);
817990075Sobrien      maskval = 1 << (MAX_CR_REGNO - REGNO (SET_DEST (exp)));
818090075Sobrien
818190075Sobrien      if (GET_CODE (unspec) != UNSPEC
8182132718Skan	  || XINT (unspec, 1) != UNSPEC_MOVESI_TO_CR
818390075Sobrien	  || XVECLEN (unspec, 0) != 2
818490075Sobrien	  || XVECEXP (unspec, 0, 0) != src_reg
818590075Sobrien	  || GET_CODE (XVECEXP (unspec, 0, 1)) != CONST_INT
818690075Sobrien	  || INTVAL (XVECEXP (unspec, 0, 1)) != maskval)
818790075Sobrien	return 0;
818890075Sobrien    }
818990075Sobrien  return 1;
819090075Sobrien}
819190075Sobrien
819290075Sobrien/* Return 1 for an PARALLEL suitable for lmw.  */
819390075Sobrien
819490075Sobrienint
8195132718Skanlmw_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
819690075Sobrien{
819790075Sobrien  int count = XVECLEN (op, 0);
819890075Sobrien  unsigned int dest_regno;
819990075Sobrien  rtx src_addr;
820090075Sobrien  unsigned int base_regno;
820190075Sobrien  HOST_WIDE_INT offset;
820290075Sobrien  int i;
820390075Sobrien
820490075Sobrien  /* Perform a quick check so we don't blow up below.  */
820590075Sobrien  if (count <= 1
820690075Sobrien      || GET_CODE (XVECEXP (op, 0, 0)) != SET
820790075Sobrien      || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != REG
820890075Sobrien      || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != MEM)
820990075Sobrien    return 0;
821090075Sobrien
821190075Sobrien  dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, 0)));
821290075Sobrien  src_addr = XEXP (SET_SRC (XVECEXP (op, 0, 0)), 0);
821390075Sobrien
821490075Sobrien  if (dest_regno > 31
821590075Sobrien      || count != 32 - (int) dest_regno)
821690075Sobrien    return 0;
821790075Sobrien
8218132718Skan  if (legitimate_indirect_address_p (src_addr, 0))
821990075Sobrien    {
822090075Sobrien      offset = 0;
822190075Sobrien      base_regno = REGNO (src_addr);
822290075Sobrien      if (base_regno == 0)
822390075Sobrien	return 0;
822490075Sobrien    }
8225132718Skan  else if (legitimate_offset_address_p (SImode, src_addr, 0))
822690075Sobrien    {
822790075Sobrien      offset = INTVAL (XEXP (src_addr, 1));
822890075Sobrien      base_regno = REGNO (XEXP (src_addr, 0));
822990075Sobrien    }
823090075Sobrien  else
823190075Sobrien    return 0;
823290075Sobrien
823390075Sobrien  for (i = 0; i < count; i++)
823490075Sobrien    {
823590075Sobrien      rtx elt = XVECEXP (op, 0, i);
823690075Sobrien      rtx newaddr;
823790075Sobrien      rtx addr_reg;
823890075Sobrien      HOST_WIDE_INT newoffset;
823990075Sobrien
824090075Sobrien      if (GET_CODE (elt) != SET
824190075Sobrien	  || GET_CODE (SET_DEST (elt)) != REG
824290075Sobrien	  || GET_MODE (SET_DEST (elt)) != SImode
824390075Sobrien	  || REGNO (SET_DEST (elt)) != dest_regno + i
824490075Sobrien	  || GET_CODE (SET_SRC (elt)) != MEM
824590075Sobrien	  || GET_MODE (SET_SRC (elt)) != SImode)
824690075Sobrien	return 0;
824790075Sobrien      newaddr = XEXP (SET_SRC (elt), 0);
8248132718Skan      if (legitimate_indirect_address_p (newaddr, 0))
824990075Sobrien	{
825090075Sobrien	  newoffset = 0;
825190075Sobrien	  addr_reg = newaddr;
825290075Sobrien	}
8253132718Skan      else if (legitimate_offset_address_p (SImode, newaddr, 0))
825490075Sobrien	{
825590075Sobrien	  addr_reg = XEXP (newaddr, 0);
825690075Sobrien	  newoffset = INTVAL (XEXP (newaddr, 1));
825790075Sobrien	}
825890075Sobrien      else
825990075Sobrien	return 0;
826090075Sobrien      if (REGNO (addr_reg) != base_regno
826190075Sobrien	  || newoffset != offset + 4 * i)
826290075Sobrien	return 0;
826390075Sobrien    }
826490075Sobrien
826590075Sobrien  return 1;
826690075Sobrien}
826790075Sobrien
826890075Sobrien/* Return 1 for an PARALLEL suitable for stmw.  */
826990075Sobrien
827090075Sobrienint
8271132718Skanstmw_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
827290075Sobrien{
827390075Sobrien  int count = XVECLEN (op, 0);
827490075Sobrien  unsigned int src_regno;
827590075Sobrien  rtx dest_addr;
827690075Sobrien  unsigned int base_regno;
827790075Sobrien  HOST_WIDE_INT offset;
827890075Sobrien  int i;
827990075Sobrien
828090075Sobrien  /* Perform a quick check so we don't blow up below.  */
828190075Sobrien  if (count <= 1
828290075Sobrien      || GET_CODE (XVECEXP (op, 0, 0)) != SET
828390075Sobrien      || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != MEM
828490075Sobrien      || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != REG)
828590075Sobrien    return 0;
828690075Sobrien
828790075Sobrien  src_regno = REGNO (SET_SRC (XVECEXP (op, 0, 0)));
828890075Sobrien  dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, 0)), 0);
828990075Sobrien
829090075Sobrien  if (src_regno > 31
829190075Sobrien      || count != 32 - (int) src_regno)
829290075Sobrien    return 0;
829390075Sobrien
8294132718Skan  if (legitimate_indirect_address_p (dest_addr, 0))
829590075Sobrien    {
829690075Sobrien      offset = 0;
829790075Sobrien      base_regno = REGNO (dest_addr);
829890075Sobrien      if (base_regno == 0)
829990075Sobrien	return 0;
830090075Sobrien    }
8301132718Skan  else if (legitimate_offset_address_p (SImode, dest_addr, 0))
830290075Sobrien    {
830390075Sobrien      offset = INTVAL (XEXP (dest_addr, 1));
830490075Sobrien      base_regno = REGNO (XEXP (dest_addr, 0));
830590075Sobrien    }
830690075Sobrien  else
830790075Sobrien    return 0;
830890075Sobrien
830990075Sobrien  for (i = 0; i < count; i++)
831090075Sobrien    {
831190075Sobrien      rtx elt = XVECEXP (op, 0, i);
831290075Sobrien      rtx newaddr;
831390075Sobrien      rtx addr_reg;
831490075Sobrien      HOST_WIDE_INT newoffset;
831590075Sobrien
831690075Sobrien      if (GET_CODE (elt) != SET
831790075Sobrien	  || GET_CODE (SET_SRC (elt)) != REG
831890075Sobrien	  || GET_MODE (SET_SRC (elt)) != SImode
831990075Sobrien	  || REGNO (SET_SRC (elt)) != src_regno + i
832090075Sobrien	  || GET_CODE (SET_DEST (elt)) != MEM
832190075Sobrien	  || GET_MODE (SET_DEST (elt)) != SImode)
832290075Sobrien	return 0;
832390075Sobrien      newaddr = XEXP (SET_DEST (elt), 0);
8324132718Skan      if (legitimate_indirect_address_p (newaddr, 0))
832590075Sobrien	{
832690075Sobrien	  newoffset = 0;
832790075Sobrien	  addr_reg = newaddr;
832890075Sobrien	}
8329132718Skan      else if (legitimate_offset_address_p (SImode, newaddr, 0))
833090075Sobrien	{
833190075Sobrien	  addr_reg = XEXP (newaddr, 0);
833290075Sobrien	  newoffset = INTVAL (XEXP (newaddr, 1));
833390075Sobrien	}
833490075Sobrien      else
833590075Sobrien	return 0;
833690075Sobrien      if (REGNO (addr_reg) != base_regno
833790075Sobrien	  || newoffset != offset + 4 * i)
833890075Sobrien	return 0;
833990075Sobrien    }
834090075Sobrien
834190075Sobrien  return 1;
834290075Sobrien}
834390075Sobrien
834490075Sobrien/* A validation routine: say whether CODE, a condition code, and MODE
834590075Sobrien   match.  The other alternatives either don't make sense or should
834690075Sobrien   never be generated.  */
834790075Sobrien
834890075Sobrienstatic void
8349132718Skanvalidate_condition_mode (enum rtx_code code, enum machine_mode mode)
835090075Sobrien{
835190075Sobrien  if (GET_RTX_CLASS (code) != '<'
835290075Sobrien      || GET_MODE_CLASS (mode) != MODE_CC)
835390075Sobrien    abort ();
835490075Sobrien
835590075Sobrien  /* These don't make sense.  */
835690075Sobrien  if ((code == GT || code == LT || code == GE || code == LE)
835790075Sobrien      && mode == CCUNSmode)
835890075Sobrien    abort ();
835990075Sobrien
836090075Sobrien  if ((code == GTU || code == LTU || code == GEU || code == LEU)
836190075Sobrien      && mode != CCUNSmode)
836290075Sobrien    abort ();
836390075Sobrien
836490075Sobrien  if (mode != CCFPmode
836590075Sobrien      && (code == ORDERED || code == UNORDERED
836690075Sobrien	  || code == UNEQ || code == LTGT
836790075Sobrien	  || code == UNGT || code == UNLT
836890075Sobrien	  || code == UNGE || code == UNLE))
836990075Sobrien    abort ();
837090075Sobrien
837190075Sobrien  /* These should never be generated except for
8372132718Skan     flag_finite_math_only.  */
837390075Sobrien  if (mode == CCFPmode
8374117395Skan      && ! flag_finite_math_only
837590075Sobrien      && (code == LE || code == GE
837690075Sobrien	  || code == UNEQ || code == LTGT
837790075Sobrien	  || code == UNGT || code == UNLT))
837890075Sobrien    abort ();
837990075Sobrien
838090075Sobrien  /* These are invalid; the information is not there.  */
838190075Sobrien  if (mode == CCEQmode
838290075Sobrien      && code != EQ && code != NE)
838390075Sobrien    abort ();
838490075Sobrien}
838590075Sobrien
838690075Sobrien/* Return 1 if OP is a comparison operation that is valid for a branch insn.
838790075Sobrien   We only check the opcode against the mode of the CC value here.  */
838890075Sobrien
838990075Sobrienint
8390132718Skanbranch_comparison_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
839190075Sobrien{
839290075Sobrien  enum rtx_code code = GET_CODE (op);
839390075Sobrien  enum machine_mode cc_mode;
839490075Sobrien
839590075Sobrien  if (GET_RTX_CLASS (code) != '<')
839690075Sobrien    return 0;
839790075Sobrien
839890075Sobrien  cc_mode = GET_MODE (XEXP (op, 0));
839990075Sobrien  if (GET_MODE_CLASS (cc_mode) != MODE_CC)
840090075Sobrien    return 0;
840190075Sobrien
840290075Sobrien  validate_condition_mode (code, cc_mode);
840390075Sobrien
840490075Sobrien  return 1;
840590075Sobrien}
840690075Sobrien
840790075Sobrien/* Return 1 if OP is a comparison operation that is valid for a branch
840890075Sobrien   insn and which is true if the corresponding bit in the CC register
840990075Sobrien   is set.  */
841090075Sobrien
841190075Sobrienint
8412132718Skanbranch_positive_comparison_operator (rtx op, enum machine_mode mode)
841390075Sobrien{
841490075Sobrien  enum rtx_code code;
841590075Sobrien
841690075Sobrien  if (! branch_comparison_operator (op, mode))
841790075Sobrien    return 0;
841890075Sobrien
841990075Sobrien  code = GET_CODE (op);
842090075Sobrien  return (code == EQ || code == LT || code == GT
842190075Sobrien	  || code == LTU || code == GTU
842290075Sobrien	  || code == UNORDERED);
842390075Sobrien}
842490075Sobrien
8425132718Skan/* Return 1 if OP is a comparison operation that is valid for an scc
8426132718Skan   insn: it must be a positive comparison.  */
842790075Sobrien
842890075Sobrienint
8429132718Skanscc_comparison_operator (rtx op, enum machine_mode mode)
843090075Sobrien{
8431132718Skan  return branch_positive_comparison_operator (op, mode);
843290075Sobrien}
843390075Sobrien
843490075Sobrienint
8435132718Skantrap_comparison_operator (rtx op, enum machine_mode mode)
843690075Sobrien{
843790075Sobrien  if (mode != VOIDmode && mode != GET_MODE (op))
843890075Sobrien    return 0;
843990075Sobrien  return GET_RTX_CLASS (GET_CODE (op)) == '<';
844090075Sobrien}
844190075Sobrien
844290075Sobrienint
8443132718Skanboolean_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
844490075Sobrien{
844590075Sobrien  enum rtx_code code = GET_CODE (op);
844690075Sobrien  return (code == AND || code == IOR || code == XOR);
844790075Sobrien}
844890075Sobrien
844990075Sobrienint
8450132718Skanboolean_or_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
845190075Sobrien{
845290075Sobrien  enum rtx_code code = GET_CODE (op);
845390075Sobrien  return (code == IOR || code == XOR);
845490075Sobrien}
845590075Sobrien
845690075Sobrienint
8457132718Skanmin_max_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
845890075Sobrien{
845990075Sobrien  enum rtx_code code = GET_CODE (op);
846090075Sobrien  return (code == SMIN || code == SMAX || code == UMIN || code == UMAX);
846190075Sobrien}
846290075Sobrien
846390075Sobrien/* Return 1 if ANDOP is a mask that has no bits on that are not in the
846490075Sobrien   mask required to convert the result of a rotate insn into a shift
846596263Sobrien   left insn of SHIFTOP bits.  Both are known to be SImode CONST_INT.  */
846690075Sobrien
846790075Sobrienint
8468132718Skanincludes_lshift_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/* Similar, but for right shift.  */
847890075Sobrien
847990075Sobrienint
8480132718Skanincludes_rshift_p (rtx shiftop, rtx andop)
848190075Sobrien{
848290075Sobrien  unsigned HOST_WIDE_INT shift_mask = ~(unsigned HOST_WIDE_INT) 0;
848390075Sobrien
848490075Sobrien  shift_mask >>= INTVAL (shiftop);
848590075Sobrien
848696263Sobrien  return (INTVAL (andop) & 0xffffffff & ~shift_mask) == 0;
848790075Sobrien}
848890075Sobrien
848990075Sobrien/* Return 1 if ANDOP is a mask suitable for use with an rldic insn
849090075Sobrien   to perform a left shift.  It must have exactly SHIFTOP least
8491132718Skan   significant 0's, then one or more 1's, then zero or more 0's.  */
849290075Sobrien
849390075Sobrienint
8494132718Skanincludes_rldic_lshift_p (rtx shiftop, rtx andop)
849590075Sobrien{
849690075Sobrien  if (GET_CODE (andop) == CONST_INT)
849790075Sobrien    {
849890075Sobrien      HOST_WIDE_INT c, lsb, shift_mask;
849990075Sobrien
850090075Sobrien      c = INTVAL (andop);
850190075Sobrien      if (c == 0 || c == ~0)
850290075Sobrien	return 0;
850390075Sobrien
850490075Sobrien      shift_mask = ~0;
850590075Sobrien      shift_mask <<= INTVAL (shiftop);
850690075Sobrien
8507132718Skan      /* Find the least significant one bit.  */
850890075Sobrien      lsb = c & -c;
850990075Sobrien
851090075Sobrien      /* It must coincide with the LSB of the shift mask.  */
851190075Sobrien      if (-lsb != shift_mask)
851290075Sobrien	return 0;
851390075Sobrien
851490075Sobrien      /* Invert to look for the next transition (if any).  */
851590075Sobrien      c = ~c;
851690075Sobrien
851790075Sobrien      /* Remove the low group of ones (originally low group of zeros).  */
851890075Sobrien      c &= -lsb;
851990075Sobrien
852090075Sobrien      /* Again find the lsb, and check we have all 1's above.  */
852190075Sobrien      lsb = c & -c;
852290075Sobrien      return c == -lsb;
852390075Sobrien    }
852490075Sobrien  else if (GET_CODE (andop) == CONST_DOUBLE
852590075Sobrien	   && (GET_MODE (andop) == VOIDmode || GET_MODE (andop) == DImode))
852690075Sobrien    {
852790075Sobrien      HOST_WIDE_INT low, high, lsb;
852890075Sobrien      HOST_WIDE_INT shift_mask_low, shift_mask_high;
852990075Sobrien
853090075Sobrien      low = CONST_DOUBLE_LOW (andop);
853190075Sobrien      if (HOST_BITS_PER_WIDE_INT < 64)
853290075Sobrien	high = CONST_DOUBLE_HIGH (andop);
853390075Sobrien
853490075Sobrien      if ((low == 0 && (HOST_BITS_PER_WIDE_INT >= 64 || high == 0))
853590075Sobrien	  || (low == ~0 && (HOST_BITS_PER_WIDE_INT >= 64 || high == ~0)))
853690075Sobrien	return 0;
853790075Sobrien
853890075Sobrien      if (HOST_BITS_PER_WIDE_INT < 64 && low == 0)
853990075Sobrien	{
854090075Sobrien	  shift_mask_high = ~0;
854190075Sobrien	  if (INTVAL (shiftop) > 32)
854290075Sobrien	    shift_mask_high <<= INTVAL (shiftop) - 32;
854390075Sobrien
854490075Sobrien	  lsb = high & -high;
854590075Sobrien
854690075Sobrien	  if (-lsb != shift_mask_high || INTVAL (shiftop) < 32)
854790075Sobrien	    return 0;
854890075Sobrien
854990075Sobrien	  high = ~high;
855090075Sobrien	  high &= -lsb;
855190075Sobrien
855290075Sobrien	  lsb = high & -high;
855390075Sobrien	  return high == -lsb;
855490075Sobrien	}
855590075Sobrien
855690075Sobrien      shift_mask_low = ~0;
855790075Sobrien      shift_mask_low <<= INTVAL (shiftop);
855890075Sobrien
855990075Sobrien      lsb = low & -low;
856090075Sobrien
856190075Sobrien      if (-lsb != shift_mask_low)
856290075Sobrien	return 0;
856390075Sobrien
856490075Sobrien      if (HOST_BITS_PER_WIDE_INT < 64)
856590075Sobrien	high = ~high;
856690075Sobrien      low = ~low;
856790075Sobrien      low &= -lsb;
856890075Sobrien
856990075Sobrien      if (HOST_BITS_PER_WIDE_INT < 64 && low == 0)
857090075Sobrien	{
857190075Sobrien	  lsb = high & -high;
857290075Sobrien	  return high == -lsb;
857390075Sobrien	}
857490075Sobrien
857590075Sobrien      lsb = low & -low;
857690075Sobrien      return low == -lsb && (HOST_BITS_PER_WIDE_INT >= 64 || high == ~0);
857790075Sobrien    }
857890075Sobrien  else
857990075Sobrien    return 0;
858090075Sobrien}
858190075Sobrien
858290075Sobrien/* Return 1 if ANDOP is a mask suitable for use with an rldicr insn
858390075Sobrien   to perform a left shift.  It must have SHIFTOP or more least
8584132718Skan   significant 0's, with the remainder of the word 1's.  */
858590075Sobrien
858690075Sobrienint
8587132718Skanincludes_rldicr_lshift_p (rtx shiftop, rtx andop)
858890075Sobrien{
858990075Sobrien  if (GET_CODE (andop) == CONST_INT)
859090075Sobrien    {
859190075Sobrien      HOST_WIDE_INT c, lsb, shift_mask;
859290075Sobrien
859390075Sobrien      shift_mask = ~0;
859490075Sobrien      shift_mask <<= INTVAL (shiftop);
859590075Sobrien      c = INTVAL (andop);
859690075Sobrien
8597132718Skan      /* Find the least significant one bit.  */
859890075Sobrien      lsb = c & -c;
859990075Sobrien
860090075Sobrien      /* It must be covered by the shift mask.
860190075Sobrien	 This test also rejects c == 0.  */
860290075Sobrien      if ((lsb & shift_mask) == 0)
860390075Sobrien	return 0;
860490075Sobrien
860590075Sobrien      /* Check we have all 1's above the transition, and reject all 1's.  */
860690075Sobrien      return c == -lsb && lsb != 1;
860790075Sobrien    }
860890075Sobrien  else if (GET_CODE (andop) == CONST_DOUBLE
860990075Sobrien	   && (GET_MODE (andop) == VOIDmode || GET_MODE (andop) == DImode))
861090075Sobrien    {
861190075Sobrien      HOST_WIDE_INT low, lsb, shift_mask_low;
861290075Sobrien
861390075Sobrien      low = CONST_DOUBLE_LOW (andop);
861490075Sobrien
861590075Sobrien      if (HOST_BITS_PER_WIDE_INT < 64)
861690075Sobrien	{
861790075Sobrien	  HOST_WIDE_INT high, shift_mask_high;
861890075Sobrien
861990075Sobrien	  high = CONST_DOUBLE_HIGH (andop);
862090075Sobrien
862190075Sobrien	  if (low == 0)
862290075Sobrien	    {
862390075Sobrien	      shift_mask_high = ~0;
862490075Sobrien	      if (INTVAL (shiftop) > 32)
862590075Sobrien		shift_mask_high <<= INTVAL (shiftop) - 32;
862690075Sobrien
862790075Sobrien	      lsb = high & -high;
862890075Sobrien
862990075Sobrien	      if ((lsb & shift_mask_high) == 0)
863090075Sobrien		return 0;
863190075Sobrien
863290075Sobrien	      return high == -lsb;
863390075Sobrien	    }
863490075Sobrien	  if (high != ~0)
863590075Sobrien	    return 0;
863690075Sobrien	}
863790075Sobrien
863890075Sobrien      shift_mask_low = ~0;
863990075Sobrien      shift_mask_low <<= INTVAL (shiftop);
864090075Sobrien
864190075Sobrien      lsb = low & -low;
864290075Sobrien
864390075Sobrien      if ((lsb & shift_mask_low) == 0)
864490075Sobrien	return 0;
864590075Sobrien
864690075Sobrien      return low == -lsb && lsb != 1;
864790075Sobrien    }
864890075Sobrien  else
864990075Sobrien    return 0;
865090075Sobrien}
865190075Sobrien
865290075Sobrien/* Return 1 if REGNO (reg1) == REGNO (reg2) - 1 making them candidates
865390075Sobrien   for lfq and stfq insns.
865490075Sobrien
865590075Sobrien   Note reg1 and reg2 *must* be hard registers.  To be sure we will
865690075Sobrien   abort if we are passed pseudo registers.  */
865790075Sobrien
865890075Sobrienint
8659132718Skanregisters_ok_for_quad_peep (rtx reg1, rtx reg2)
866090075Sobrien{
866190075Sobrien  /* We might have been passed a SUBREG.  */
866290075Sobrien  if (GET_CODE (reg1) != REG || GET_CODE (reg2) != REG)
866390075Sobrien    return 0;
866490075Sobrien
866590075Sobrien  return (REGNO (reg1) == REGNO (reg2) - 1);
866690075Sobrien}
866790075Sobrien
866890075Sobrien/* Return 1 if addr1 and addr2 are suitable for lfq or stfq insn.
866990075Sobrien   addr1 and addr2 must be in consecutive memory locations
867090075Sobrien   (addr2 == addr1 + 8).  */
867190075Sobrien
867290075Sobrienint
8673132718Skanaddrs_ok_for_quad_peep (rtx addr1, rtx addr2)
867490075Sobrien{
867590075Sobrien  unsigned int reg1;
867690075Sobrien  int offset1;
867790075Sobrien
867890075Sobrien  /* Extract an offset (if used) from the first addr.  */
867990075Sobrien  if (GET_CODE (addr1) == PLUS)
868090075Sobrien    {
868190075Sobrien      /* If not a REG, return zero.  */
868290075Sobrien      if (GET_CODE (XEXP (addr1, 0)) != REG)
868390075Sobrien	return 0;
868490075Sobrien      else
868590075Sobrien	{
868690075Sobrien          reg1 = REGNO (XEXP (addr1, 0));
868790075Sobrien	  /* The offset must be constant!  */
868890075Sobrien	  if (GET_CODE (XEXP (addr1, 1)) != CONST_INT)
868990075Sobrien            return 0;
869090075Sobrien          offset1 = INTVAL (XEXP (addr1, 1));
869190075Sobrien	}
869290075Sobrien    }
869390075Sobrien  else if (GET_CODE (addr1) != REG)
869490075Sobrien    return 0;
869590075Sobrien  else
869690075Sobrien    {
869790075Sobrien      reg1 = REGNO (addr1);
869890075Sobrien      /* This was a simple (mem (reg)) expression.  Offset is 0.  */
869990075Sobrien      offset1 = 0;
870090075Sobrien    }
870190075Sobrien
8702132718Skan  /* Make sure the second address is a (mem (plus (reg) (const_int)))
8703132718Skan      or if it is (mem (reg)) then make sure that offset1 is -8 and the same
8704132718Skan      register as addr1.  */
8705132718Skan  if (offset1 == -8 && GET_CODE (addr2) == REG && reg1 == REGNO (addr2))
8706132718Skan   return 1;
870790075Sobrien  if (GET_CODE (addr2) != PLUS)
870890075Sobrien    return 0;
870990075Sobrien
871090075Sobrien  if (GET_CODE (XEXP (addr2, 0)) != REG
871190075Sobrien      || GET_CODE (XEXP (addr2, 1)) != CONST_INT)
871290075Sobrien    return 0;
871390075Sobrien
871490075Sobrien  if (reg1 != REGNO (XEXP (addr2, 0)))
871590075Sobrien    return 0;
871690075Sobrien
871790075Sobrien  /* The offset for the second addr must be 8 more than the first addr.  */
871890075Sobrien  if (INTVAL (XEXP (addr2, 1)) != offset1 + 8)
871990075Sobrien    return 0;
872090075Sobrien
872190075Sobrien  /* All the tests passed.  addr1 and addr2 are valid for lfq or stfq
872290075Sobrien     instructions.  */
872390075Sobrien  return 1;
872490075Sobrien}
872590075Sobrien
872690075Sobrien/* Return the register class of a scratch register needed to copy IN into
872790075Sobrien   or out of a register in CLASS in MODE.  If it can be done directly,
8728132718Skan   NO_REGS is returned.  INP is nonzero if we are loading the reg, zero
8729132718Skan   for storing.  */
873090075Sobrien
873190075Sobrienenum reg_class
8732132718Skansecondary_reload_class (enum reg_class class,
8733132718Skan			enum machine_mode mode,
8734132718Skan			rtx in,
8735132718Skan			int inp)
873690075Sobrien{
873790075Sobrien  int regno;
873890075Sobrien
8739132718Skan  if (TARGET_ELF || (DEFAULT_ABI == ABI_DARWIN
8740132718Skan#if TARGET_MACHO
8741132718Skan                    && MACHOPIC_INDIRECT
8742132718Skan#endif
8743132718Skan                    ))
874490075Sobrien    {
874590075Sobrien      /* We cannot copy a symbolic operand directly into anything
874690075Sobrien         other than BASE_REGS for TARGET_ELF.  So indicate that a
874790075Sobrien         register from BASE_REGS is needed as an intermediate
874890075Sobrien         register.
874990075Sobrien
875090075Sobrien	 On Darwin, pic addresses require a load from memory, which
875190075Sobrien	 needs a base register.  */
875290075Sobrien      if (class != BASE_REGS
875390075Sobrien          && (GET_CODE (in) == SYMBOL_REF
875490075Sobrien              || GET_CODE (in) == HIGH
875590075Sobrien              || GET_CODE (in) == LABEL_REF
875690075Sobrien              || GET_CODE (in) == CONST))
875790075Sobrien        return BASE_REGS;
875890075Sobrien    }
875990075Sobrien
8760132718Skan  /* A 64-bit gpr load or store using an offset that isn't a multiple of
8761132718Skan     four needs a secondary reload.  */
8762132718Skan  if (TARGET_POWERPC64
8763132718Skan      && GET_MODE_UNIT_SIZE (mode) >= 8
8764132718Skan      && (!inp || class != BASE_REGS)
8765132718Skan      && invalid_gpr_mem (in, mode))
8766132718Skan    return BASE_REGS;
8767132718Skan
876890075Sobrien  if (GET_CODE (in) == REG)
876990075Sobrien    {
877090075Sobrien      regno = REGNO (in);
877190075Sobrien      if (regno >= FIRST_PSEUDO_REGISTER)
877290075Sobrien	{
877390075Sobrien	  regno = true_regnum (in);
877490075Sobrien	  if (regno >= FIRST_PSEUDO_REGISTER)
877590075Sobrien	    regno = -1;
877690075Sobrien	}
877790075Sobrien    }
877890075Sobrien  else if (GET_CODE (in) == SUBREG)
877990075Sobrien    {
878090075Sobrien      regno = true_regnum (in);
878190075Sobrien      if (regno >= FIRST_PSEUDO_REGISTER)
878290075Sobrien	regno = -1;
878390075Sobrien    }
878490075Sobrien  else
878590075Sobrien    regno = -1;
878690075Sobrien
878790075Sobrien  /* We can place anything into GENERAL_REGS and can put GENERAL_REGS
878890075Sobrien     into anything.  */
878990075Sobrien  if (class == GENERAL_REGS || class == BASE_REGS
879090075Sobrien      || (regno >= 0 && INT_REGNO_P (regno)))
879190075Sobrien    return NO_REGS;
879290075Sobrien
879390075Sobrien  /* Constants, memory, and FP registers can go into FP registers.  */
879490075Sobrien  if ((regno == -1 || FP_REGNO_P (regno))
879590075Sobrien      && (class == FLOAT_REGS || class == NON_SPECIAL_REGS))
879690075Sobrien    return NO_REGS;
879790075Sobrien
879890075Sobrien  /* Memory, and AltiVec registers can go into AltiVec registers.  */
879990075Sobrien  if ((regno == -1 || ALTIVEC_REGNO_P (regno))
880090075Sobrien      && class == ALTIVEC_REGS)
880190075Sobrien    return NO_REGS;
880290075Sobrien
880390075Sobrien  /* We can copy among the CR registers.  */
880490075Sobrien  if ((class == CR_REGS || class == CR0_REGS)
880590075Sobrien      && regno >= 0 && CR_REGNO_P (regno))
880690075Sobrien    return NO_REGS;
880790075Sobrien
880890075Sobrien  /* Otherwise, we need GENERAL_REGS.  */
880990075Sobrien  return GENERAL_REGS;
881090075Sobrien}
881190075Sobrien
881290075Sobrien/* Given a comparison operation, return the bit number in CCR to test.  We
881390075Sobrien   know this is a valid comparison.
881490075Sobrien
881590075Sobrien   SCC_P is 1 if this is for an scc.  That means that %D will have been
881690075Sobrien   used instead of %C, so the bits will be in different places.
881790075Sobrien
881890075Sobrien   Return -1 if OP isn't a valid comparison for some reason.  */
881990075Sobrien
882090075Sobrienint
8821132718Skanccr_bit (rtx op, int scc_p)
882290075Sobrien{
882390075Sobrien  enum rtx_code code = GET_CODE (op);
882490075Sobrien  enum machine_mode cc_mode;
882590075Sobrien  int cc_regnum;
882690075Sobrien  int base_bit;
882790075Sobrien  rtx reg;
882890075Sobrien
882990075Sobrien  if (GET_RTX_CLASS (code) != '<')
883090075Sobrien    return -1;
883190075Sobrien
883290075Sobrien  reg = XEXP (op, 0);
883390075Sobrien
883490075Sobrien  if (GET_CODE (reg) != REG
883590075Sobrien      || ! CR_REGNO_P (REGNO (reg)))
883690075Sobrien    abort ();
883790075Sobrien
883890075Sobrien  cc_mode = GET_MODE (reg);
883990075Sobrien  cc_regnum = REGNO (reg);
884090075Sobrien  base_bit = 4 * (cc_regnum - CR0_REGNO);
884190075Sobrien
884290075Sobrien  validate_condition_mode (code, cc_mode);
884390075Sobrien
8844132718Skan  /* When generating a sCOND operation, only positive conditions are
8845132718Skan     allowed.  */
8846132718Skan  if (scc_p && code != EQ && code != GT && code != LT && code != UNORDERED
8847132718Skan      && code != GTU && code != LTU)
8848132718Skan    abort ();
8849132718Skan
885090075Sobrien  switch (code)
885190075Sobrien    {
885290075Sobrien    case NE:
885390075Sobrien      return scc_p ? base_bit + 3 : base_bit + 2;
885490075Sobrien    case EQ:
885590075Sobrien      return base_bit + 2;
885690075Sobrien    case GT:  case GTU:  case UNLE:
885790075Sobrien      return base_bit + 1;
885890075Sobrien    case LT:  case LTU:  case UNGE:
885990075Sobrien      return base_bit;
886090075Sobrien    case ORDERED:  case UNORDERED:
886190075Sobrien      return base_bit + 3;
886290075Sobrien
886390075Sobrien    case GE:  case GEU:
886490075Sobrien      /* If scc, we will have done a cror to put the bit in the
886590075Sobrien	 unordered position.  So test that bit.  For integer, this is ! LT
886690075Sobrien	 unless this is an scc insn.  */
886790075Sobrien      return scc_p ? base_bit + 3 : base_bit;
886890075Sobrien
886990075Sobrien    case LE:  case LEU:
887090075Sobrien      return scc_p ? base_bit + 3 : base_bit + 1;
887190075Sobrien
887290075Sobrien    default:
887390075Sobrien      abort ();
887490075Sobrien    }
887590075Sobrien}
887690075Sobrien
887790075Sobrien/* Return the GOT register.  */
887890075Sobrien
887990075Sobrienstruct rtx_def *
8880132718Skanrs6000_got_register (rtx value ATTRIBUTE_UNUSED)
888190075Sobrien{
888290075Sobrien  /* The second flow pass currently (June 1999) can't update
888390075Sobrien     regs_ever_live without disturbing other parts of the compiler, so
888490075Sobrien     update it here to make the prolog/epilogue code happy.  */
888596263Sobrien  if (no_new_pseudos && ! regs_ever_live[RS6000_PIC_OFFSET_TABLE_REGNUM])
888696263Sobrien    regs_ever_live[RS6000_PIC_OFFSET_TABLE_REGNUM] = 1;
888790075Sobrien
888890075Sobrien  current_function_uses_pic_offset_table = 1;
888990075Sobrien
889090075Sobrien  return pic_offset_table_rtx;
889190075Sobrien}
889290075Sobrien
8893117395Skan/* Function to init struct machine_function.
8894117395Skan   This will be called, via a pointer variable,
8895117395Skan   from push_function_context.  */
889690075Sobrien
8897117395Skanstatic struct machine_function *
8898132718Skanrs6000_init_machine_status (void)
889990075Sobrien{
8900117395Skan  return ggc_alloc_cleared (sizeof (machine_function));
890190075Sobrien}
8902117395Skan
8903117395Skan/* These macros test for integers and extract the low-order bits.  */
8904117395Skan#define INT_P(X)  \
8905117395Skan((GET_CODE (X) == CONST_INT || GET_CODE (X) == CONST_DOUBLE)	\
8906117395Skan && GET_MODE (X) == VOIDmode)
890790075Sobrien
8908117395Skan#define INT_LOWPART(X) \
8909117395Skan  (GET_CODE (X) == CONST_INT ? INTVAL (X) : CONST_DOUBLE_LOW (X))
8910117395Skan
8911117395Skanint
8912132718Skanextract_MB (rtx op)
891390075Sobrien{
8914117395Skan  int i;
8915117395Skan  unsigned long val = INT_LOWPART (op);
891690075Sobrien
8917117395Skan  /* If the high bit is zero, the value is the first 1 bit we find
8918117395Skan     from the left.  */
8919117395Skan  if ((val & 0x80000000) == 0)
8920117395Skan    {
8921117395Skan      if ((val & 0xffffffff) == 0)
8922117395Skan	abort ();
8923117395Skan
8924117395Skan      i = 1;
8925117395Skan      while (((val <<= 1) & 0x80000000) == 0)
8926117395Skan	++i;
8927117395Skan      return i;
8928117395Skan    }
8929117395Skan
8930117395Skan  /* If the high bit is set and the low bit is not, or the mask is all
8931117395Skan     1's, the value is zero.  */
8932117395Skan  if ((val & 1) == 0 || (val & 0xffffffff) == 0xffffffff)
8933117395Skan    return 0;
8934117395Skan
8935117395Skan  /* Otherwise we have a wrap-around mask.  Look for the first 0 bit
8936117395Skan     from the right.  */
8937117395Skan  i = 31;
8938117395Skan  while (((val >>= 1) & 1) != 0)
8939117395Skan    --i;
8940117395Skan
8941117395Skan  return i;
894290075Sobrien}
894390075Sobrien
8944117395Skanint
8945132718Skanextract_ME (rtx op)
8946117395Skan{
8947117395Skan  int i;
8948117395Skan  unsigned long val = INT_LOWPART (op);
8949117395Skan
8950117395Skan  /* If the low bit is zero, the value is the first 1 bit we find from
8951117395Skan     the right.  */
8952117395Skan  if ((val & 1) == 0)
8953117395Skan    {
8954117395Skan      if ((val & 0xffffffff) == 0)
8955117395Skan	abort ();
8956117395Skan
8957117395Skan      i = 30;
8958117395Skan      while (((val >>= 1) & 1) == 0)
8959117395Skan	--i;
8960117395Skan
8961117395Skan      return i;
8962117395Skan    }
8963117395Skan
8964117395Skan  /* If the low bit is set and the high bit is not, or the mask is all
8965117395Skan     1's, the value is 31.  */
8966117395Skan  if ((val & 0x80000000) == 0 || (val & 0xffffffff) == 0xffffffff)
8967117395Skan    return 31;
8968117395Skan
8969117395Skan  /* Otherwise we have a wrap-around mask.  Look for the first 0 bit
8970117395Skan     from the left.  */
8971117395Skan  i = 0;
8972117395Skan  while (((val <<= 1) & 0x80000000) != 0)
8973117395Skan    ++i;
8974117395Skan
8975117395Skan  return i;
8976117395Skan}
8977117395Skan
8978132718Skan/* Locate some local-dynamic symbol still in use by this function
8979132718Skan   so that we can print its name in some tls_ld pattern.  */
8980132718Skan
8981132718Skanstatic const char *
8982132718Skanrs6000_get_some_local_dynamic_name (void)
8983132718Skan{
8984132718Skan  rtx insn;
8985132718Skan
8986132718Skan  if (cfun->machine->some_ld_name)
8987132718Skan    return cfun->machine->some_ld_name;
8988132718Skan
8989132718Skan  for (insn = get_insns (); insn ; insn = NEXT_INSN (insn))
8990132718Skan    if (INSN_P (insn)
8991132718Skan	&& for_each_rtx (&PATTERN (insn),
8992132718Skan			 rs6000_get_some_local_dynamic_name_1, 0))
8993132718Skan      return cfun->machine->some_ld_name;
8994132718Skan
8995132718Skan  abort ();
8996132718Skan}
8997132718Skan
8998132718Skan/* Helper function for rs6000_get_some_local_dynamic_name.  */
8999132718Skan
9000132718Skanstatic int
9001132718Skanrs6000_get_some_local_dynamic_name_1 (rtx *px, void *data ATTRIBUTE_UNUSED)
9002132718Skan{
9003132718Skan  rtx x = *px;
9004132718Skan
9005132718Skan  if (GET_CODE (x) == SYMBOL_REF)
9006132718Skan    {
9007132718Skan      const char *str = XSTR (x, 0);
9008132718Skan      if (SYMBOL_REF_TLS_MODEL (x) == TLS_MODEL_LOCAL_DYNAMIC)
9009132718Skan	{
9010132718Skan	  cfun->machine->some_ld_name = str;
9011132718Skan	  return 1;
9012132718Skan	}
9013132718Skan    }
9014132718Skan
9015132718Skan  return 0;
9016132718Skan}
9017132718Skan
901890075Sobrien/* Print an operand.  Recognize special options, documented below.  */
901990075Sobrien
902090075Sobrien#if TARGET_ELF
902190075Sobrien#define SMALL_DATA_RELOC ((rs6000_sdata == SDATA_EABI) ? "sda21" : "sdarel")
902290075Sobrien#define SMALL_DATA_REG ((rs6000_sdata == SDATA_EABI) ? 0 : 13)
902390075Sobrien#else
902490075Sobrien#define SMALL_DATA_RELOC "sda21"
902590075Sobrien#define SMALL_DATA_REG 0
902690075Sobrien#endif
902790075Sobrien
902890075Sobrienvoid
9029132718Skanprint_operand (FILE *file, rtx x, int code)
903090075Sobrien{
903190075Sobrien  int i;
903290075Sobrien  HOST_WIDE_INT val;
9033117395Skan  unsigned HOST_WIDE_INT uval;
903490075Sobrien
903590075Sobrien  switch (code)
903690075Sobrien    {
903790075Sobrien    case '.':
903890075Sobrien      /* Write out an instruction after the call which may be replaced
903990075Sobrien	 with glue code by the loader.  This depends on the AIX version.  */
904090075Sobrien      asm_fprintf (file, RS6000_CALL_GLUE);
904190075Sobrien      return;
904290075Sobrien
904390075Sobrien      /* %a is output_address.  */
904490075Sobrien
904590075Sobrien    case 'A':
904690075Sobrien      /* If X is a constant integer whose low-order 5 bits are zero,
904790075Sobrien	 write 'l'.  Otherwise, write 'r'.  This is a kludge to fix a bug
904890075Sobrien	 in the AIX assembler where "sri" with a zero shift count
904990075Sobrien	 writes a trash instruction.  */
905090075Sobrien      if (GET_CODE (x) == CONST_INT && (INTVAL (x) & 31) == 0)
905190075Sobrien	putc ('l', file);
905290075Sobrien      else
905390075Sobrien	putc ('r', file);
905490075Sobrien      return;
905590075Sobrien
905690075Sobrien    case 'b':
905790075Sobrien      /* If constant, low-order 16 bits of constant, unsigned.
905890075Sobrien	 Otherwise, write normally.  */
905990075Sobrien      if (INT_P (x))
906090075Sobrien	fprintf (file, HOST_WIDE_INT_PRINT_DEC, INT_LOWPART (x) & 0xffff);
906190075Sobrien      else
906290075Sobrien	print_operand (file, x, 0);
906390075Sobrien      return;
906490075Sobrien
906590075Sobrien    case 'B':
906690075Sobrien      /* If the low-order bit is zero, write 'r'; otherwise, write 'l'
906790075Sobrien	 for 64-bit mask direction.  */
906890075Sobrien      putc (((INT_LOWPART(x) & 1) == 0 ? 'r' : 'l'), file);
906990075Sobrien      return;
907090075Sobrien
907190075Sobrien      /* %c is output_addr_const if a CONSTANT_ADDRESS_P, otherwise
907290075Sobrien	 output_operand.  */
907390075Sobrien
9074132718Skan    case 'c':
9075132718Skan      /* X is a CR register.  Print the number of the GT bit of the CR.  */
9076132718Skan      if (GET_CODE (x) != REG || ! CR_REGNO_P (REGNO (x)))
9077132718Skan       output_operand_lossage ("invalid %%E value");
9078132718Skan      else
9079132718Skan       fprintf (file, "%d", 4 * (REGNO (x) - CR0_REGNO) + 1);
9080132718Skan      return;
9081132718Skan
908290075Sobrien    case 'D':
9083146895Skan      /* Like 'J' but get to the EQ bit.  */
9084132718Skan      if (GET_CODE (x) != REG)
9085132718Skan       abort ();
908690075Sobrien
9087146895Skan      /* Bit 1 is EQ bit.  */
9088146895Skan      i = 4 * (REGNO (x) - CR0_REGNO) + 2;
908990075Sobrien
9090132718Skan      /* If we want bit 31, write a shift count of zero, not 32.  */
9091132718Skan      fprintf (file, "%d", i == 31 ? 0 : i + 1);
909290075Sobrien      return;
909390075Sobrien
909490075Sobrien    case 'E':
909590075Sobrien      /* X is a CR register.  Print the number of the EQ bit of the CR */
909690075Sobrien      if (GET_CODE (x) != REG || ! CR_REGNO_P (REGNO (x)))
909790075Sobrien	output_operand_lossage ("invalid %%E value");
909890075Sobrien      else
909990075Sobrien	fprintf (file, "%d", 4 * (REGNO (x) - CR0_REGNO) + 2);
910090075Sobrien      return;
910190075Sobrien
910290075Sobrien    case 'f':
910390075Sobrien      /* X is a CR register.  Print the shift count needed to move it
910490075Sobrien	 to the high-order four bits.  */
910590075Sobrien      if (GET_CODE (x) != REG || ! CR_REGNO_P (REGNO (x)))
910690075Sobrien	output_operand_lossage ("invalid %%f value");
910790075Sobrien      else
910890075Sobrien	fprintf (file, "%d", 4 * (REGNO (x) - CR0_REGNO));
910990075Sobrien      return;
911090075Sobrien
911190075Sobrien    case 'F':
911290075Sobrien      /* Similar, but print the count for the rotate in the opposite
911390075Sobrien	 direction.  */
911490075Sobrien      if (GET_CODE (x) != REG || ! CR_REGNO_P (REGNO (x)))
911590075Sobrien	output_operand_lossage ("invalid %%F value");
911690075Sobrien      else
911790075Sobrien	fprintf (file, "%d", 32 - 4 * (REGNO (x) - CR0_REGNO));
911890075Sobrien      return;
911990075Sobrien
912090075Sobrien    case 'G':
912190075Sobrien      /* X is a constant integer.  If it is negative, print "m",
9122117395Skan	 otherwise print "z".  This is to make an aze or ame insn.  */
912390075Sobrien      if (GET_CODE (x) != CONST_INT)
912490075Sobrien	output_operand_lossage ("invalid %%G value");
912590075Sobrien      else if (INTVAL (x) >= 0)
912690075Sobrien	putc ('z', file);
912790075Sobrien      else
912890075Sobrien	putc ('m', file);
912990075Sobrien      return;
913090075Sobrien
913190075Sobrien    case 'h':
913290075Sobrien      /* If constant, output low-order five bits.  Otherwise, write
913390075Sobrien	 normally.  */
913490075Sobrien      if (INT_P (x))
913590075Sobrien	fprintf (file, HOST_WIDE_INT_PRINT_DEC, INT_LOWPART (x) & 31);
913690075Sobrien      else
913790075Sobrien	print_operand (file, x, 0);
913890075Sobrien      return;
913990075Sobrien
914090075Sobrien    case 'H':
914190075Sobrien      /* If constant, output low-order six bits.  Otherwise, write
914290075Sobrien	 normally.  */
914390075Sobrien      if (INT_P (x))
914490075Sobrien	fprintf (file, HOST_WIDE_INT_PRINT_DEC, INT_LOWPART (x) & 63);
914590075Sobrien      else
914690075Sobrien	print_operand (file, x, 0);
914790075Sobrien      return;
914890075Sobrien
914990075Sobrien    case 'I':
915090075Sobrien      /* Print `i' if this is a constant, else nothing.  */
915190075Sobrien      if (INT_P (x))
915290075Sobrien	putc ('i', file);
915390075Sobrien      return;
915490075Sobrien
915590075Sobrien    case 'j':
915690075Sobrien      /* Write the bit number in CCR for jump.  */
915790075Sobrien      i = ccr_bit (x, 0);
915890075Sobrien      if (i == -1)
915990075Sobrien	output_operand_lossage ("invalid %%j code");
916090075Sobrien      else
916190075Sobrien	fprintf (file, "%d", i);
916290075Sobrien      return;
916390075Sobrien
916490075Sobrien    case 'J':
916590075Sobrien      /* Similar, but add one for shift count in rlinm for scc and pass
916690075Sobrien	 scc flag to `ccr_bit'.  */
916790075Sobrien      i = ccr_bit (x, 1);
916890075Sobrien      if (i == -1)
916990075Sobrien	output_operand_lossage ("invalid %%J code");
917090075Sobrien      else
917190075Sobrien	/* If we want bit 31, write a shift count of zero, not 32.  */
917290075Sobrien	fprintf (file, "%d", i == 31 ? 0 : i + 1);
917390075Sobrien      return;
917490075Sobrien
917590075Sobrien    case 'k':
917690075Sobrien      /* X must be a constant.  Write the 1's complement of the
917790075Sobrien	 constant.  */
917890075Sobrien      if (! INT_P (x))
917990075Sobrien	output_operand_lossage ("invalid %%k value");
918090075Sobrien      else
918190075Sobrien	fprintf (file, HOST_WIDE_INT_PRINT_DEC, ~ INT_LOWPART (x));
918290075Sobrien      return;
918390075Sobrien
918490075Sobrien    case 'K':
918590075Sobrien      /* X must be a symbolic constant on ELF.  Write an
918690075Sobrien	 expression suitable for an 'addi' that adds in the low 16
918790075Sobrien	 bits of the MEM.  */
918890075Sobrien      if (GET_CODE (x) != CONST)
918990075Sobrien	{
919090075Sobrien	  print_operand_address (file, x);
919190075Sobrien	  fputs ("@l", file);
919290075Sobrien	}
919390075Sobrien      else
919490075Sobrien	{
919590075Sobrien	  if (GET_CODE (XEXP (x, 0)) != PLUS
919690075Sobrien	      || (GET_CODE (XEXP (XEXP (x, 0), 0)) != SYMBOL_REF
919790075Sobrien		  && GET_CODE (XEXP (XEXP (x, 0), 0)) != LABEL_REF)
919890075Sobrien	      || GET_CODE (XEXP (XEXP (x, 0), 1)) != CONST_INT)
919990075Sobrien	    output_operand_lossage ("invalid %%K value");
920090075Sobrien	  print_operand_address (file, XEXP (XEXP (x, 0), 0));
920190075Sobrien	  fputs ("@l", file);
9202117395Skan	  /* For GNU as, there must be a non-alphanumeric character
9203117395Skan	     between 'l' and the number.  The '-' is added by
9204117395Skan	     print_operand() already.  */
9205117395Skan	  if (INTVAL (XEXP (XEXP (x, 0), 1)) >= 0)
9206117395Skan	    fputs ("+", file);
920790075Sobrien	  print_operand (file, XEXP (XEXP (x, 0), 1), 0);
920890075Sobrien	}
920990075Sobrien      return;
921090075Sobrien
921190075Sobrien      /* %l is output_asm_label.  */
921290075Sobrien
921390075Sobrien    case 'L':
921490075Sobrien      /* Write second word of DImode or DFmode reference.  Works on register
921590075Sobrien	 or non-indexed memory only.  */
921690075Sobrien      if (GET_CODE (x) == REG)
921790075Sobrien	fprintf (file, "%s", reg_names[REGNO (x) + 1]);
921890075Sobrien      else if (GET_CODE (x) == MEM)
921990075Sobrien	{
922090075Sobrien	  /* Handle possible auto-increment.  Since it is pre-increment and
922190075Sobrien	     we have already done it, we can just use an offset of word.  */
922290075Sobrien	  if (GET_CODE (XEXP (x, 0)) == PRE_INC
922390075Sobrien	      || GET_CODE (XEXP (x, 0)) == PRE_DEC)
922490075Sobrien	    output_address (plus_constant (XEXP (XEXP (x, 0), 0),
922590075Sobrien					   UNITS_PER_WORD));
922690075Sobrien	  else
922790075Sobrien	    output_address (XEXP (adjust_address_nv (x, SImode,
922890075Sobrien						     UNITS_PER_WORD),
922990075Sobrien				  0));
923090075Sobrien
923190075Sobrien	  if (small_data_operand (x, GET_MODE (x)))
923290075Sobrien	    fprintf (file, "@%s(%s)", SMALL_DATA_RELOC,
923390075Sobrien		     reg_names[SMALL_DATA_REG]);
923490075Sobrien	}
923590075Sobrien      return;
923690075Sobrien
923790075Sobrien    case 'm':
923890075Sobrien      /* MB value for a mask operand.  */
923996263Sobrien      if (! mask_operand (x, SImode))
924090075Sobrien	output_operand_lossage ("invalid %%m value");
924190075Sobrien
9242117395Skan      fprintf (file, "%d", extract_MB (x));
924390075Sobrien      return;
924490075Sobrien
924590075Sobrien    case 'M':
924690075Sobrien      /* ME value for a mask operand.  */
924796263Sobrien      if (! mask_operand (x, SImode))
924890075Sobrien	output_operand_lossage ("invalid %%M value");
924990075Sobrien
9250117395Skan      fprintf (file, "%d", extract_ME (x));
925190075Sobrien      return;
925290075Sobrien
925390075Sobrien      /* %n outputs the negative of its operand.  */
925490075Sobrien
925590075Sobrien    case 'N':
925690075Sobrien      /* Write the number of elements in the vector times 4.  */
925790075Sobrien      if (GET_CODE (x) != PARALLEL)
925890075Sobrien	output_operand_lossage ("invalid %%N value");
925990075Sobrien      else
926090075Sobrien	fprintf (file, "%d", XVECLEN (x, 0) * 4);
926190075Sobrien      return;
926290075Sobrien
926390075Sobrien    case 'O':
926490075Sobrien      /* Similar, but subtract 1 first.  */
926590075Sobrien      if (GET_CODE (x) != PARALLEL)
926690075Sobrien	output_operand_lossage ("invalid %%O value");
926790075Sobrien      else
926890075Sobrien	fprintf (file, "%d", (XVECLEN (x, 0) - 1) * 4);
926990075Sobrien      return;
927090075Sobrien
927190075Sobrien    case 'p':
927290075Sobrien      /* X is a CONST_INT that is a power of two.  Output the logarithm.  */
927390075Sobrien      if (! INT_P (x)
927490075Sobrien	  || INT_LOWPART (x) < 0
927590075Sobrien	  || (i = exact_log2 (INT_LOWPART (x))) < 0)
927690075Sobrien	output_operand_lossage ("invalid %%p value");
927790075Sobrien      else
927890075Sobrien	fprintf (file, "%d", i);
927990075Sobrien      return;
928090075Sobrien
928190075Sobrien    case 'P':
928290075Sobrien      /* The operand must be an indirect memory reference.  The result
9283146895Skan	 is the register name.  */
928490075Sobrien      if (GET_CODE (x) != MEM || GET_CODE (XEXP (x, 0)) != REG
928590075Sobrien	  || REGNO (XEXP (x, 0)) >= 32)
928690075Sobrien	output_operand_lossage ("invalid %%P value");
928790075Sobrien      else
9288146895Skan	fprintf (file, "%s", reg_names[REGNO (XEXP (x, 0))]);
928990075Sobrien      return;
929090075Sobrien
929190075Sobrien    case 'q':
929290075Sobrien      /* This outputs the logical code corresponding to a boolean
929390075Sobrien	 expression.  The expression may have one or both operands
929490075Sobrien	 negated (if one, only the first one).  For condition register
929590075Sobrien         logical operations, it will also treat the negated
929690075Sobrien         CR codes as NOTs, but not handle NOTs of them.  */
929790075Sobrien      {
929890075Sobrien	const char *const *t = 0;
929990075Sobrien	const char *s;
930090075Sobrien	enum rtx_code code = GET_CODE (x);
930190075Sobrien	static const char * const tbl[3][3] = {
930290075Sobrien	  { "and", "andc", "nor" },
930390075Sobrien	  { "or", "orc", "nand" },
930490075Sobrien	  { "xor", "eqv", "xor" } };
930590075Sobrien
930690075Sobrien	if (code == AND)
930790075Sobrien	  t = tbl[0];
930890075Sobrien	else if (code == IOR)
930990075Sobrien	  t = tbl[1];
931090075Sobrien	else if (code == XOR)
931190075Sobrien	  t = tbl[2];
931290075Sobrien	else
931390075Sobrien	  output_operand_lossage ("invalid %%q value");
931490075Sobrien
931590075Sobrien	if (GET_CODE (XEXP (x, 0)) != NOT)
931690075Sobrien	  s = t[0];
931790075Sobrien	else
931890075Sobrien	  {
931990075Sobrien	    if (GET_CODE (XEXP (x, 1)) == NOT)
932090075Sobrien	      s = t[2];
932190075Sobrien	    else
932290075Sobrien	      s = t[1];
932390075Sobrien	  }
932490075Sobrien
932590075Sobrien	fputs (s, file);
932690075Sobrien      }
932790075Sobrien      return;
932890075Sobrien
9329132718Skan    case 'Q':
9330132718Skan      if (TARGET_MFCRF)
9331132718Skan	fputc (',',file);
9332132718Skan        /* FALLTHRU */
9333132718Skan      else
9334132718Skan	return;
9335132718Skan
933690075Sobrien    case 'R':
933790075Sobrien      /* X is a CR register.  Print the mask for `mtcrf'.  */
933890075Sobrien      if (GET_CODE (x) != REG || ! CR_REGNO_P (REGNO (x)))
933990075Sobrien	output_operand_lossage ("invalid %%R value");
934090075Sobrien      else
934190075Sobrien	fprintf (file, "%d", 128 >> (REGNO (x) - CR0_REGNO));
934290075Sobrien      return;
934390075Sobrien
934490075Sobrien    case 's':
934590075Sobrien      /* Low 5 bits of 32 - value */
934690075Sobrien      if (! INT_P (x))
934790075Sobrien	output_operand_lossage ("invalid %%s value");
934890075Sobrien      else
934990075Sobrien	fprintf (file, HOST_WIDE_INT_PRINT_DEC, (32 - INT_LOWPART (x)) & 31);
935090075Sobrien      return;
935190075Sobrien
935290075Sobrien    case 'S':
9353117395Skan      /* PowerPC64 mask position.  All 0's is excluded.
935490075Sobrien	 CONST_INT 32-bit mask is considered sign-extended so any
935590075Sobrien	 transition must occur within the CONST_INT, not on the boundary.  */
935696263Sobrien      if (! mask64_operand (x, DImode))
935790075Sobrien	output_operand_lossage ("invalid %%S value");
935890075Sobrien
9359117395Skan      uval = INT_LOWPART (x);
936090075Sobrien
9361117395Skan      if (uval & 1)	/* Clear Left */
936290075Sobrien	{
9363132718Skan#if HOST_BITS_PER_WIDE_INT > 64
9364132718Skan	  uval &= ((unsigned HOST_WIDE_INT) 1 << 64) - 1;
9365132718Skan#endif
9366117395Skan	  i = 64;
936790075Sobrien	}
9368117395Skan      else		/* Clear Right */
936990075Sobrien	{
9370117395Skan	  uval = ~uval;
9371132718Skan#if HOST_BITS_PER_WIDE_INT > 64
9372132718Skan	  uval &= ((unsigned HOST_WIDE_INT) 1 << 64) - 1;
9373132718Skan#endif
9374117395Skan	  i = 63;
9375117395Skan	}
9376117395Skan      while (uval != 0)
9377117395Skan	--i, uval >>= 1;
9378117395Skan      if (i < 0)
9379117395Skan	abort ();
9380117395Skan      fprintf (file, "%d", i);
9381117395Skan      return;
938290075Sobrien
9383117395Skan    case 't':
9384117395Skan      /* Like 'J' but get to the OVERFLOW/UNORDERED bit.  */
9385117395Skan      if (GET_CODE (x) != REG || GET_MODE (x) != CCmode)
9386117395Skan	abort ();
938790075Sobrien
9388117395Skan      /* Bit 3 is OV bit.  */
9389117395Skan      i = 4 * (REGNO (x) - CR0_REGNO) + 3;
939090075Sobrien
9391117395Skan      /* If we want bit 31, write a shift count of zero, not 32.  */
9392117395Skan      fprintf (file, "%d", i == 31 ? 0 : i + 1);
9393117395Skan      return;
939490075Sobrien
939590075Sobrien    case 'T':
939690075Sobrien      /* Print the symbolic name of a branch target register.  */
939790075Sobrien      if (GET_CODE (x) != REG || (REGNO (x) != LINK_REGISTER_REGNUM
939890075Sobrien				  && REGNO (x) != COUNT_REGISTER_REGNUM))
939990075Sobrien	output_operand_lossage ("invalid %%T value");
940090075Sobrien      else if (REGNO (x) == LINK_REGISTER_REGNUM)
940190075Sobrien	fputs (TARGET_NEW_MNEMONICS ? "lr" : "r", file);
940290075Sobrien      else
940390075Sobrien	fputs ("ctr", file);
940490075Sobrien      return;
940590075Sobrien
940690075Sobrien    case 'u':
940790075Sobrien      /* High-order 16 bits of constant for use in unsigned operand.  */
940890075Sobrien      if (! INT_P (x))
940990075Sobrien	output_operand_lossage ("invalid %%u value");
941090075Sobrien      else
941190075Sobrien	fprintf (file, HOST_WIDE_INT_PRINT_HEX,
941290075Sobrien		 (INT_LOWPART (x) >> 16) & 0xffff);
941390075Sobrien      return;
941490075Sobrien
941590075Sobrien    case 'v':
941690075Sobrien      /* High-order 16 bits of constant for use in signed operand.  */
941790075Sobrien      if (! INT_P (x))
941890075Sobrien	output_operand_lossage ("invalid %%v value");
941990075Sobrien      else
942090075Sobrien	fprintf (file, HOST_WIDE_INT_PRINT_HEX,
942190075Sobrien		 (INT_LOWPART (x) >> 16) & 0xffff);
942290075Sobrien      return;
942390075Sobrien
942490075Sobrien    case 'U':
942590075Sobrien      /* Print `u' if this has an auto-increment or auto-decrement.  */
942690075Sobrien      if (GET_CODE (x) == MEM
942790075Sobrien	  && (GET_CODE (XEXP (x, 0)) == PRE_INC
942890075Sobrien	      || GET_CODE (XEXP (x, 0)) == PRE_DEC))
942990075Sobrien	putc ('u', file);
943090075Sobrien      return;
943190075Sobrien
943290075Sobrien    case 'V':
943390075Sobrien      /* Print the trap code for this operand.  */
943490075Sobrien      switch (GET_CODE (x))
943590075Sobrien	{
943690075Sobrien	case EQ:
943790075Sobrien	  fputs ("eq", file);   /* 4 */
943890075Sobrien	  break;
943990075Sobrien	case NE:
944090075Sobrien	  fputs ("ne", file);   /* 24 */
944190075Sobrien	  break;
944290075Sobrien	case LT:
944390075Sobrien	  fputs ("lt", file);   /* 16 */
944490075Sobrien	  break;
944590075Sobrien	case LE:
944690075Sobrien	  fputs ("le", file);   /* 20 */
944790075Sobrien	  break;
944890075Sobrien	case GT:
944990075Sobrien	  fputs ("gt", file);   /* 8 */
945090075Sobrien	  break;
945190075Sobrien	case GE:
945290075Sobrien	  fputs ("ge", file);   /* 12 */
945390075Sobrien	  break;
945490075Sobrien	case LTU:
945590075Sobrien	  fputs ("llt", file);  /* 2 */
945690075Sobrien	  break;
945790075Sobrien	case LEU:
945890075Sobrien	  fputs ("lle", file);  /* 6 */
945990075Sobrien	  break;
946090075Sobrien	case GTU:
946190075Sobrien	  fputs ("lgt", file);  /* 1 */
946290075Sobrien	  break;
946390075Sobrien	case GEU:
946490075Sobrien	  fputs ("lge", file);  /* 5 */
946590075Sobrien	  break;
946690075Sobrien	default:
946790075Sobrien	  abort ();
946890075Sobrien	}
946990075Sobrien      break;
947090075Sobrien
947190075Sobrien    case 'w':
947290075Sobrien      /* If constant, low-order 16 bits of constant, signed.  Otherwise, write
947390075Sobrien	 normally.  */
947490075Sobrien      if (INT_P (x))
947590075Sobrien	fprintf (file, HOST_WIDE_INT_PRINT_DEC,
947690075Sobrien		 ((INT_LOWPART (x) & 0xffff) ^ 0x8000) - 0x8000);
947790075Sobrien      else
947890075Sobrien	print_operand (file, x, 0);
947990075Sobrien      return;
948090075Sobrien
948190075Sobrien    case 'W':
948290075Sobrien      /* MB value for a PowerPC64 rldic operand.  */
948390075Sobrien      val = (GET_CODE (x) == CONST_INT
948490075Sobrien	     ? INTVAL (x) : CONST_DOUBLE_HIGH (x));
948590075Sobrien
948690075Sobrien      if (val < 0)
948790075Sobrien	i = -1;
948890075Sobrien      else
948990075Sobrien	for (i = 0; i < HOST_BITS_PER_WIDE_INT; i++)
949090075Sobrien	  if ((val <<= 1) < 0)
949190075Sobrien	    break;
949290075Sobrien
949390075Sobrien#if HOST_BITS_PER_WIDE_INT == 32
949490075Sobrien      if (GET_CODE (x) == CONST_INT && i >= 0)
949590075Sobrien	i += 32;  /* zero-extend high-part was all 0's */
949690075Sobrien      else if (GET_CODE (x) == CONST_DOUBLE && i == 32)
949790075Sobrien	{
949890075Sobrien	  val = CONST_DOUBLE_LOW (x);
949990075Sobrien
950090075Sobrien	  if (val == 0)
950190075Sobrien	    abort ();
950290075Sobrien	  else if (val < 0)
950390075Sobrien	    --i;
950490075Sobrien	  else
950590075Sobrien	    for ( ; i < 64; i++)
950690075Sobrien	      if ((val <<= 1) < 0)
950790075Sobrien		break;
950890075Sobrien	}
950990075Sobrien#endif
951090075Sobrien
951190075Sobrien      fprintf (file, "%d", i + 1);
951290075Sobrien      return;
951390075Sobrien
951490075Sobrien    case 'X':
951590075Sobrien      if (GET_CODE (x) == MEM
9516132718Skan	  && legitimate_indexed_address_p (XEXP (x, 0), 0))
951790075Sobrien	putc ('x', file);
951890075Sobrien      return;
951990075Sobrien
952090075Sobrien    case 'Y':
952190075Sobrien      /* Like 'L', for third word of TImode  */
952290075Sobrien      if (GET_CODE (x) == REG)
952390075Sobrien	fprintf (file, "%s", reg_names[REGNO (x) + 2]);
952490075Sobrien      else if (GET_CODE (x) == MEM)
952590075Sobrien	{
952690075Sobrien	  if (GET_CODE (XEXP (x, 0)) == PRE_INC
952790075Sobrien	      || GET_CODE (XEXP (x, 0)) == PRE_DEC)
952890075Sobrien	    output_address (plus_constant (XEXP (XEXP (x, 0), 0), 8));
952990075Sobrien	  else
953090075Sobrien	    output_address (XEXP (adjust_address_nv (x, SImode, 8), 0));
953190075Sobrien	  if (small_data_operand (x, GET_MODE (x)))
953290075Sobrien	    fprintf (file, "@%s(%s)", SMALL_DATA_RELOC,
953390075Sobrien		     reg_names[SMALL_DATA_REG]);
953490075Sobrien	}
953590075Sobrien      return;
953690075Sobrien
953790075Sobrien    case 'z':
953890075Sobrien      /* X is a SYMBOL_REF.  Write out the name preceded by a
953990075Sobrien	 period and without any trailing data in brackets.  Used for function
954090075Sobrien	 names.  If we are configured for System V (or the embedded ABI) on
954190075Sobrien	 the PowerPC, do not emit the period, since those systems do not use
954290075Sobrien	 TOCs and the like.  */
954390075Sobrien      if (GET_CODE (x) != SYMBOL_REF)
954490075Sobrien	abort ();
954590075Sobrien
954690075Sobrien      if (XSTR (x, 0)[0] != '.')
954790075Sobrien	{
954890075Sobrien	  switch (DEFAULT_ABI)
954990075Sobrien	    {
955090075Sobrien	    default:
955190075Sobrien	      abort ();
955290075Sobrien
955390075Sobrien	    case ABI_AIX:
955490075Sobrien	      putc ('.', file);
955590075Sobrien	      break;
955690075Sobrien
955790075Sobrien	    case ABI_V4:
955890075Sobrien	    case ABI_DARWIN:
955990075Sobrien	      break;
956090075Sobrien	    }
956190075Sobrien	}
9562132718Skan      if (TARGET_AIX)
9563132718Skan	RS6000_OUTPUT_BASENAME (file, XSTR (x, 0));
9564132718Skan      else
9565132718Skan	assemble_name (file, XSTR (x, 0));
956690075Sobrien      return;
956790075Sobrien
956890075Sobrien    case 'Z':
956990075Sobrien      /* Like 'L', for last word of TImode.  */
957090075Sobrien      if (GET_CODE (x) == REG)
957190075Sobrien	fprintf (file, "%s", reg_names[REGNO (x) + 3]);
957290075Sobrien      else if (GET_CODE (x) == MEM)
957390075Sobrien	{
957490075Sobrien	  if (GET_CODE (XEXP (x, 0)) == PRE_INC
957590075Sobrien	      || GET_CODE (XEXP (x, 0)) == PRE_DEC)
957690075Sobrien	    output_address (plus_constant (XEXP (XEXP (x, 0), 0), 12));
957790075Sobrien	  else
957890075Sobrien	    output_address (XEXP (adjust_address_nv (x, SImode, 12), 0));
957990075Sobrien	  if (small_data_operand (x, GET_MODE (x)))
958090075Sobrien	    fprintf (file, "@%s(%s)", SMALL_DATA_RELOC,
958190075Sobrien		     reg_names[SMALL_DATA_REG]);
958290075Sobrien	}
958390075Sobrien      return;
958490075Sobrien
9585117395Skan      /* Print AltiVec or SPE memory operand.  */
958690075Sobrien    case 'y':
958790075Sobrien      {
958890075Sobrien	rtx tmp;
958990075Sobrien
959090075Sobrien	if (GET_CODE (x) != MEM)
959190075Sobrien	  abort ();
959290075Sobrien
959390075Sobrien	tmp = XEXP (x, 0);
959490075Sobrien
9595132718Skan	if (TARGET_E500)
9596117395Skan	  {
9597117395Skan	    /* Handle [reg].  */
9598117395Skan	    if (GET_CODE (tmp) == REG)
9599117395Skan	      {
9600117395Skan		fprintf (file, "0(%s)", reg_names[REGNO (tmp)]);
9601117395Skan		break;
9602117395Skan	      }
9603117395Skan	    /* Handle [reg+UIMM].  */
9604117395Skan	    else if (GET_CODE (tmp) == PLUS &&
9605117395Skan		     GET_CODE (XEXP (tmp, 1)) == CONST_INT)
9606117395Skan	      {
9607117395Skan		int x;
9608117395Skan
9609117395Skan		if (GET_CODE (XEXP (tmp, 0)) != REG)
9610117395Skan		  abort ();
9611117395Skan
9612117395Skan		x = INTVAL (XEXP (tmp, 1));
9613117395Skan		fprintf (file, "%d(%s)", x, reg_names[REGNO (XEXP (tmp, 0))]);
9614117395Skan		break;
9615117395Skan	      }
9616117395Skan
9617117395Skan	    /* Fall through.  Must be [reg+reg].  */
9618117395Skan	  }
961990075Sobrien	if (GET_CODE (tmp) == REG)
962090075Sobrien	  fprintf (file, "0,%s", reg_names[REGNO (tmp)]);
962190075Sobrien	else if (GET_CODE (tmp) == PLUS && GET_CODE (XEXP (tmp, 1)) == REG)
962290075Sobrien	  {
962390075Sobrien	    if (REGNO (XEXP (tmp, 0)) == 0)
962490075Sobrien	      fprintf (file, "%s,%s", reg_names[ REGNO (XEXP (tmp, 1)) ],
962590075Sobrien		       reg_names[ REGNO (XEXP (tmp, 0)) ]);
962690075Sobrien	    else
962790075Sobrien	      fprintf (file, "%s,%s", reg_names[ REGNO (XEXP (tmp, 0)) ],
962890075Sobrien		       reg_names[ REGNO (XEXP (tmp, 1)) ]);
962990075Sobrien	  }
963090075Sobrien	else
963190075Sobrien	  abort ();
963290075Sobrien	break;
963390075Sobrien      }
963490075Sobrien
963590075Sobrien    case 0:
963690075Sobrien      if (GET_CODE (x) == REG)
963790075Sobrien	fprintf (file, "%s", reg_names[REGNO (x)]);
963890075Sobrien      else if (GET_CODE (x) == MEM)
963990075Sobrien	{
964090075Sobrien	  /* We need to handle PRE_INC and PRE_DEC here, since we need to
964190075Sobrien	     know the width from the mode.  */
964290075Sobrien	  if (GET_CODE (XEXP (x, 0)) == PRE_INC)
964390075Sobrien	    fprintf (file, "%d(%s)", GET_MODE_SIZE (GET_MODE (x)),
964490075Sobrien		     reg_names[REGNO (XEXP (XEXP (x, 0), 0))]);
964590075Sobrien	  else if (GET_CODE (XEXP (x, 0)) == PRE_DEC)
964690075Sobrien	    fprintf (file, "%d(%s)", - GET_MODE_SIZE (GET_MODE (x)),
964790075Sobrien		     reg_names[REGNO (XEXP (XEXP (x, 0), 0))]);
964890075Sobrien	  else
964990075Sobrien	    output_address (XEXP (x, 0));
965090075Sobrien	}
965190075Sobrien      else
965290075Sobrien	output_addr_const (file, x);
965390075Sobrien      return;
965490075Sobrien
9655132718Skan    case '&':
9656132718Skan      assemble_name (file, rs6000_get_some_local_dynamic_name ());
9657132718Skan      return;
9658132718Skan
965990075Sobrien    default:
966090075Sobrien      output_operand_lossage ("invalid %%xn code");
966190075Sobrien    }
966290075Sobrien}
966390075Sobrien
966490075Sobrien/* Print the address of an operand.  */
966590075Sobrien
966690075Sobrienvoid
9667132718Skanprint_operand_address (FILE *file, rtx x)
966890075Sobrien{
966990075Sobrien  if (GET_CODE (x) == REG)
967090075Sobrien    fprintf (file, "0(%s)", reg_names[ REGNO (x) ]);
967190075Sobrien  else if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == CONST
967290075Sobrien	   || GET_CODE (x) == LABEL_REF)
967390075Sobrien    {
967490075Sobrien      output_addr_const (file, x);
967590075Sobrien      if (small_data_operand (x, GET_MODE (x)))
967690075Sobrien	fprintf (file, "@%s(%s)", SMALL_DATA_RELOC,
967790075Sobrien		 reg_names[SMALL_DATA_REG]);
967890075Sobrien      else if (TARGET_TOC)
967990075Sobrien	abort ();
968090075Sobrien    }
968190075Sobrien  else if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == REG)
968290075Sobrien    {
968390075Sobrien      if (REGNO (XEXP (x, 0)) == 0)
968490075Sobrien	fprintf (file, "%s,%s", reg_names[ REGNO (XEXP (x, 1)) ],
968590075Sobrien		 reg_names[ REGNO (XEXP (x, 0)) ]);
968690075Sobrien      else
968790075Sobrien	fprintf (file, "%s,%s", reg_names[ REGNO (XEXP (x, 0)) ],
968890075Sobrien		 reg_names[ REGNO (XEXP (x, 1)) ]);
968990075Sobrien    }
969090075Sobrien  else if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
9691132718Skan    fprintf (file, HOST_WIDE_INT_PRINT_DEC "(%s)",
9692132718Skan	     INTVAL (XEXP (x, 1)), reg_names[ REGNO (XEXP (x, 0)) ]);
969390075Sobrien#if TARGET_ELF
969490075Sobrien  else if (GET_CODE (x) == LO_SUM && GET_CODE (XEXP (x, 0)) == REG
969590075Sobrien           && CONSTANT_P (XEXP (x, 1)))
969690075Sobrien    {
969790075Sobrien      output_addr_const (file, XEXP (x, 1));
969890075Sobrien      fprintf (file, "@l(%s)", reg_names[ REGNO (XEXP (x, 0)) ]);
969990075Sobrien    }
970090075Sobrien#endif
970190075Sobrien#if TARGET_MACHO
970290075Sobrien  else if (GET_CODE (x) == LO_SUM && GET_CODE (XEXP (x, 0)) == REG
970390075Sobrien           && CONSTANT_P (XEXP (x, 1)))
970490075Sobrien    {
970590075Sobrien      fprintf (file, "lo16(");
970690075Sobrien      output_addr_const (file, XEXP (x, 1));
970790075Sobrien      fprintf (file, ")(%s)", reg_names[ REGNO (XEXP (x, 0)) ]);
970890075Sobrien    }
970990075Sobrien#endif
9710132718Skan  else if (legitimate_constant_pool_address_p (x))
971190075Sobrien    {
971290075Sobrien      if (TARGET_AIX && (!TARGET_ELF || !TARGET_MINIMAL_TOC))
971390075Sobrien	{
971490075Sobrien	  rtx contains_minus = XEXP (x, 1);
971590075Sobrien	  rtx minus, symref;
971690075Sobrien	  const char *name;
971790075Sobrien
971890075Sobrien	  /* Find the (minus (sym) (toc)) buried in X, and temporarily
971990075Sobrien	     turn it into (sym) for output_addr_const.  */
972090075Sobrien	  while (GET_CODE (XEXP (contains_minus, 0)) != MINUS)
972190075Sobrien	    contains_minus = XEXP (contains_minus, 0);
972290075Sobrien
972390075Sobrien	  minus = XEXP (contains_minus, 0);
972490075Sobrien	  symref = XEXP (minus, 0);
972590075Sobrien	  XEXP (contains_minus, 0) = symref;
972690075Sobrien	  if (TARGET_ELF)
972790075Sobrien	    {
972890075Sobrien	      char *newname;
972990075Sobrien
973090075Sobrien	      name = XSTR (symref, 0);
973190075Sobrien	      newname = alloca (strlen (name) + sizeof ("@toc"));
973290075Sobrien	      strcpy (newname, name);
973390075Sobrien	      strcat (newname, "@toc");
973490075Sobrien	      XSTR (symref, 0) = newname;
973590075Sobrien	    }
973690075Sobrien	  output_addr_const (file, XEXP (x, 1));
973790075Sobrien	  if (TARGET_ELF)
973890075Sobrien	    XSTR (symref, 0) = name;
973990075Sobrien	  XEXP (contains_minus, 0) = minus;
974090075Sobrien	}
974190075Sobrien      else
974290075Sobrien	output_addr_const (file, XEXP (x, 1));
974390075Sobrien
974490075Sobrien      fprintf (file, "(%s)", reg_names[REGNO (XEXP (x, 0))]);
974590075Sobrien    }
974690075Sobrien  else
974790075Sobrien    abort ();
974890075Sobrien}
974990075Sobrien
9750117395Skan/* Target hook for assembling integer objects.  The PowerPC version has
975190075Sobrien   to handle fixup entries for relocatable code if RELOCATABLE_NEEDS_FIXUP
975290075Sobrien   is defined.  It also needs to handle DI-mode objects on 64-bit
975390075Sobrien   targets.  */
975490075Sobrien
975590075Sobrienstatic bool
9756132718Skanrs6000_assemble_integer (rtx x, unsigned int size, int aligned_p)
975790075Sobrien{
975890075Sobrien#ifdef RELOCATABLE_NEEDS_FIXUP
975990075Sobrien  /* Special handling for SI values.  */
9760146895Skan  if (RELOCATABLE_NEEDS_FIXUP && size == 4 && aligned_p)
976190075Sobrien    {
9762132718Skan      extern int in_toc_section (void);
976390075Sobrien      static int recurse = 0;
976490075Sobrien
976590075Sobrien      /* For -mrelocatable, we mark all addresses that need to be fixed up
976690075Sobrien	 in the .fixup section.  */
976790075Sobrien      if (TARGET_RELOCATABLE
976890075Sobrien	  && !in_toc_section ()
976990075Sobrien	  && !in_text_section ()
977090075Sobrien	  && !recurse
977190075Sobrien	  && GET_CODE (x) != CONST_INT
977290075Sobrien	  && GET_CODE (x) != CONST_DOUBLE
977390075Sobrien	  && CONSTANT_P (x))
977490075Sobrien	{
977590075Sobrien	  char buf[256];
977690075Sobrien
977790075Sobrien	  recurse = 1;
977890075Sobrien	  ASM_GENERATE_INTERNAL_LABEL (buf, "LCP", fixuplabelno);
977990075Sobrien	  fixuplabelno++;
978090075Sobrien	  ASM_OUTPUT_LABEL (asm_out_file, buf);
978190075Sobrien	  fprintf (asm_out_file, "\t.long\t(");
978290075Sobrien	  output_addr_const (asm_out_file, x);
978390075Sobrien	  fprintf (asm_out_file, ")@fixup\n");
978490075Sobrien	  fprintf (asm_out_file, "\t.section\t\".fixup\",\"aw\"\n");
978590075Sobrien	  ASM_OUTPUT_ALIGN (asm_out_file, 2);
978690075Sobrien	  fprintf (asm_out_file, "\t.long\t");
978790075Sobrien	  assemble_name (asm_out_file, buf);
978890075Sobrien	  fprintf (asm_out_file, "\n\t.previous\n");
978990075Sobrien	  recurse = 0;
979090075Sobrien	  return true;
979190075Sobrien	}
979290075Sobrien      /* Remove initial .'s to turn a -mcall-aixdesc function
979390075Sobrien	 address into the address of the descriptor, not the function
979490075Sobrien	 itself.  */
979590075Sobrien      else if (GET_CODE (x) == SYMBOL_REF
979690075Sobrien	       && XSTR (x, 0)[0] == '.'
979790075Sobrien	       && DEFAULT_ABI == ABI_AIX)
979890075Sobrien	{
979990075Sobrien	  const char *name = XSTR (x, 0);
980090075Sobrien	  while (*name == '.')
980190075Sobrien	    name++;
980290075Sobrien
980390075Sobrien	  fprintf (asm_out_file, "\t.long\t%s\n", name);
980490075Sobrien	  return true;
980590075Sobrien	}
980690075Sobrien    }
980790075Sobrien#endif /* RELOCATABLE_NEEDS_FIXUP */
980890075Sobrien  return default_assemble_integer (x, size, aligned_p);
980990075Sobrien}
9810117395Skan
9811117395Skan#ifdef HAVE_GAS_HIDDEN
9812117395Skan/* Emit an assembler directive to set symbol visibility for DECL to
9813117395Skan   VISIBILITY_TYPE.  */
9814117395Skan
9815117395Skanstatic void
9816132718Skanrs6000_assemble_visibility (tree decl, int vis)
9817117395Skan{
9818117395Skan  /* Functions need to have their entry point symbol visibility set as
9819117395Skan     well as their descriptor symbol visibility.  */
9820117395Skan  if (DEFAULT_ABI == ABI_AIX && TREE_CODE (decl) == FUNCTION_DECL)
9821117395Skan    {
9822117395Skan      static const char * const visibility_types[] = {
9823117395Skan        NULL, "internal", "hidden", "protected"
9824117395Skan      };
9825117395Skan
9826117395Skan      const char *name, *type;
9827117395Skan
9828117395Skan      name = ((* targetm.strip_name_encoding)
9829117395Skan	      (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl))));
9830117395Skan      type = visibility_types[vis];
9831117395Skan
9832117395Skan      fprintf (asm_out_file, "\t.%s\t%s\n", type, name);
9833117395Skan      fprintf (asm_out_file, "\t.%s\t.%s\n", type, name);
9834117395Skan    }
9835117395Skan  else
9836117395Skan    default_assemble_visibility (decl, vis);
9837117395Skan}
9838117395Skan#endif
983990075Sobrien
984090075Sobrienenum rtx_code
9841132718Skanrs6000_reverse_condition (enum machine_mode mode, enum rtx_code code)
984290075Sobrien{
984390075Sobrien  /* Reversal of FP compares takes care -- an ordered compare
984490075Sobrien     becomes an unordered compare and vice versa.  */
9845132718Skan  if (mode == CCFPmode
9846132718Skan      && (!flag_finite_math_only
9847132718Skan	  || code == UNLT || code == UNLE || code == UNGT || code == UNGE
9848132718Skan	  || code == UNEQ || code == LTGT))
984990075Sobrien    return reverse_condition_maybe_unordered (code);
985090075Sobrien  else
985190075Sobrien    return reverse_condition (code);
985290075Sobrien}
985390075Sobrien
985490075Sobrien/* Generate a compare for CODE.  Return a brand-new rtx that
985590075Sobrien   represents the result of the compare.  */
985690075Sobrien
985790075Sobrienstatic rtx
9858132718Skanrs6000_generate_compare (enum rtx_code code)
985990075Sobrien{
986090075Sobrien  enum machine_mode comp_mode;
986190075Sobrien  rtx compare_result;
986290075Sobrien
986390075Sobrien  if (rs6000_compare_fp_p)
986490075Sobrien    comp_mode = CCFPmode;
986590075Sobrien  else if (code == GTU || code == LTU
986690075Sobrien	  || code == GEU || code == LEU)
986790075Sobrien    comp_mode = CCUNSmode;
986890075Sobrien  else
986990075Sobrien    comp_mode = CCmode;
987090075Sobrien
987190075Sobrien  /* First, the compare.  */
987290075Sobrien  compare_result = gen_reg_rtx (comp_mode);
9873117395Skan
9874117395Skan  /* SPE FP compare instructions on the GPRs.  Yuck!  */
9875132718Skan  if ((TARGET_E500 && !TARGET_FPRS && TARGET_HARD_FLOAT)
9876132718Skan      && rs6000_compare_fp_p)
9877117395Skan    {
9878117395Skan      rtx cmp, or1, or2, or_result, compare_result2;
9879117395Skan
9880132718Skan      /* Note: The E500 comparison instructions set the GT bit (x +
9881132718Skan        1), on success.  This explains the mess.  */
9882132718Skan
9883117395Skan      switch (code)
9884117395Skan	{
9885132718Skan       case EQ: case UNEQ: case NE: case LTGT:
9886132718Skan	  cmp = flag_finite_math_only
9887117395Skan	    ? gen_tstsfeq_gpr (compare_result, rs6000_compare_op0,
9888117395Skan			       rs6000_compare_op1)
9889117395Skan	    : gen_cmpsfeq_gpr (compare_result, rs6000_compare_op0,
9890117395Skan			       rs6000_compare_op1);
9891117395Skan	  break;
9892132718Skan       case GT: case GTU: case UNGT: case UNGE: case GE: case GEU:
9893132718Skan	  cmp = flag_finite_math_only
9894117395Skan	    ? gen_tstsfgt_gpr (compare_result, rs6000_compare_op0,
9895117395Skan			       rs6000_compare_op1)
9896117395Skan	    : gen_cmpsfgt_gpr (compare_result, rs6000_compare_op0,
9897117395Skan			       rs6000_compare_op1);
9898117395Skan	  break;
9899132718Skan       case LT: case LTU: case UNLT: case UNLE: case LE: case LEU:
9900132718Skan	  cmp = flag_finite_math_only
9901117395Skan	    ? gen_tstsflt_gpr (compare_result, rs6000_compare_op0,
9902117395Skan			       rs6000_compare_op1)
9903117395Skan	    : gen_cmpsflt_gpr (compare_result, rs6000_compare_op0,
9904117395Skan			       rs6000_compare_op1);
9905117395Skan	  break;
9906117395Skan	default:
9907117395Skan	  abort ();
9908117395Skan	}
9909117395Skan
9910117395Skan      /* Synthesize LE and GE from LT/GT || EQ.  */
9911117395Skan      if (code == LE || code == GE || code == LEU || code == GEU)
9912117395Skan	{
9913117395Skan	  emit_insn (cmp);
9914117395Skan
9915117395Skan	  switch (code)
9916117395Skan	    {
9917117395Skan	    case LE: code = LT; break;
9918117395Skan	    case GE: code = GT; break;
9919117395Skan	    case LEU: code = LT; break;
9920117395Skan	    case GEU: code = GT; break;
9921117395Skan	    default: abort ();
9922117395Skan	    }
9923117395Skan
9924117395Skan	  or1 = gen_reg_rtx (SImode);
9925117395Skan	  or2 = gen_reg_rtx (SImode);
9926117395Skan	  or_result = gen_reg_rtx (CCEQmode);
9927117395Skan	  compare_result2 = gen_reg_rtx (CCFPmode);
9928117395Skan
9929117395Skan	  /* Do the EQ.  */
9930132718Skan	  cmp = flag_finite_math_only
9931117395Skan	    ? gen_tstsfeq_gpr (compare_result2, rs6000_compare_op0,
9932117395Skan			       rs6000_compare_op1)
9933117395Skan	    : gen_cmpsfeq_gpr (compare_result2, rs6000_compare_op0,
9934117395Skan			       rs6000_compare_op1);
9935117395Skan	  emit_insn (cmp);
9936117395Skan
9937132718Skan	  or1 = gen_rtx_GT (SImode, compare_result, const0_rtx);
9938132718Skan	  or2 = gen_rtx_GT (SImode, compare_result2, const0_rtx);
9939117395Skan
9940117395Skan	  /* OR them together.  */
9941117395Skan	  cmp = gen_rtx_SET (VOIDmode, or_result,
9942117395Skan			     gen_rtx_COMPARE (CCEQmode,
9943117395Skan					      gen_rtx_IOR (SImode, or1, or2),
9944117395Skan					      const_true_rtx));
9945117395Skan	  compare_result = or_result;
9946117395Skan	  code = EQ;
9947117395Skan	}
9948117395Skan      else
9949117395Skan	{
9950117395Skan	  if (code == NE || code == LTGT)
9951117395Skan	    code = NE;
9952132718Skan         else
9953132718Skan           code = EQ;
9954117395Skan	}
9955117395Skan
9956117395Skan      emit_insn (cmp);
9957117395Skan    }
9958117395Skan  else
9959146895Skan    {
9960146895Skan      /* Generate XLC-compatible TFmode compare as PARALLEL with extra
9961146895Skan         CLOBBERs to match cmptf_internal2 pattern.  */
9962146895Skan      if (comp_mode == CCFPmode && TARGET_XL_COMPAT
9963146895Skan          && GET_MODE (rs6000_compare_op0) == TFmode
9964146895Skan          && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_DARWIN)
9965146895Skan          && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128)
9966146895Skan        emit_insn (gen_rtx_PARALLEL (VOIDmode,
9967146895Skan          gen_rtvec (9,
9968146895Skan		     gen_rtx_SET (VOIDmode,
9969146895Skan				  compare_result,
9970146895Skan				  gen_rtx_COMPARE (comp_mode,
9971146895Skan						   rs6000_compare_op0,
9972146895Skan						   rs6000_compare_op1)),
9973146895Skan		     gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
9974146895Skan		     gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
9975146895Skan		     gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
9976146895Skan		     gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
9977146895Skan		     gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
9978146895Skan		     gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
9979146895Skan		     gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
9980146895Skan		     gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)))));
9981146895Skan      else
9982146895Skan	emit_insn (gen_rtx_SET (VOIDmode, compare_result,
9983146895Skan				gen_rtx_COMPARE (comp_mode,
9984146895Skan						 rs6000_compare_op0,
9985146895Skan						 rs6000_compare_op1)));
9986146895Skan    }
998790075Sobrien
998890075Sobrien  /* Some kinds of FP comparisons need an OR operation;
9989132718Skan     under flag_finite_math_only we don't bother.  */
999090075Sobrien  if (rs6000_compare_fp_p
9991132718Skan      && ! flag_finite_math_only
9992132718Skan      && ! (TARGET_HARD_FLOAT && TARGET_E500 && !TARGET_FPRS)
999390075Sobrien      && (code == LE || code == GE
999490075Sobrien	  || code == UNEQ || code == LTGT
999590075Sobrien	  || code == UNGT || code == UNLT))
999690075Sobrien    {
999790075Sobrien      enum rtx_code or1, or2;
999890075Sobrien      rtx or1_rtx, or2_rtx, compare2_rtx;
999990075Sobrien      rtx or_result = gen_reg_rtx (CCEQmode);
1000090075Sobrien
1000190075Sobrien      switch (code)
1000290075Sobrien	{
1000390075Sobrien	case LE: or1 = LT;  or2 = EQ;  break;
1000490075Sobrien	case GE: or1 = GT;  or2 = EQ;  break;
1000590075Sobrien	case UNEQ: or1 = UNORDERED;  or2 = EQ;  break;
1000690075Sobrien	case LTGT: or1 = LT;  or2 = GT;  break;
1000790075Sobrien	case UNGT: or1 = UNORDERED;  or2 = GT;  break;
1000890075Sobrien	case UNLT: or1 = UNORDERED;  or2 = LT;  break;
1000990075Sobrien	default:  abort ();
1001090075Sobrien	}
1001190075Sobrien      validate_condition_mode (or1, comp_mode);
1001290075Sobrien      validate_condition_mode (or2, comp_mode);
1001390075Sobrien      or1_rtx = gen_rtx (or1, SImode, compare_result, const0_rtx);
1001490075Sobrien      or2_rtx = gen_rtx (or2, SImode, compare_result, const0_rtx);
1001590075Sobrien      compare2_rtx = gen_rtx_COMPARE (CCEQmode,
1001690075Sobrien				      gen_rtx_IOR (SImode, or1_rtx, or2_rtx),
1001790075Sobrien				      const_true_rtx);
1001890075Sobrien      emit_insn (gen_rtx_SET (VOIDmode, or_result, compare2_rtx));
1001990075Sobrien
1002090075Sobrien      compare_result = or_result;
1002190075Sobrien      code = EQ;
1002290075Sobrien    }
1002390075Sobrien
1002490075Sobrien  validate_condition_mode (code, GET_MODE (compare_result));
1002590075Sobrien
1002690075Sobrien  return gen_rtx (code, VOIDmode, compare_result, const0_rtx);
1002790075Sobrien}
1002890075Sobrien
1002990075Sobrien
1003090075Sobrien/* Emit the RTL for an sCOND pattern.  */
1003190075Sobrien
1003290075Sobrienvoid
10033132718Skanrs6000_emit_sCOND (enum rtx_code code, rtx result)
1003490075Sobrien{
1003590075Sobrien  rtx condition_rtx;
1003690075Sobrien  enum machine_mode op_mode;
10037132718Skan  enum rtx_code cond_code;
1003890075Sobrien
1003990075Sobrien  condition_rtx = rs6000_generate_compare (code);
10040132718Skan  cond_code = GET_CODE (condition_rtx);
1004190075Sobrien
10042132718Skan  if (TARGET_E500 && rs6000_compare_fp_p
10043132718Skan      && !TARGET_FPRS && TARGET_HARD_FLOAT)
10044132718Skan    {
10045132718Skan      rtx t;
10046132718Skan
10047132718Skan      PUT_MODE (condition_rtx, SImode);
10048132718Skan      t = XEXP (condition_rtx, 0);
10049132718Skan
10050132718Skan      if (cond_code != NE && cond_code != EQ)
10051132718Skan       abort ();
10052132718Skan
10053132718Skan      if (cond_code == NE)
10054146895Skan       emit_insn (gen_e500_flip_eq_bit (t, t));
10055132718Skan
10056146895Skan      emit_insn (gen_move_from_CR_eq_bit (result, t));
10057132718Skan      return;
10058132718Skan    }
10059132718Skan
10060132718Skan  if (cond_code == NE
10061132718Skan      || cond_code == GE || cond_code == LE
10062132718Skan      || cond_code == GEU || cond_code == LEU
10063132718Skan      || cond_code == ORDERED || cond_code == UNGE || cond_code == UNLE)
10064132718Skan    {
10065132718Skan      rtx not_result = gen_reg_rtx (CCEQmode);
10066132718Skan      rtx not_op, rev_cond_rtx;
10067132718Skan      enum machine_mode cc_mode;
10068132718Skan
10069132718Skan      cc_mode = GET_MODE (XEXP (condition_rtx, 0));
10070132718Skan
10071132718Skan      rev_cond_rtx = gen_rtx (rs6000_reverse_condition (cc_mode, cond_code),
10072132718Skan			      SImode, XEXP (condition_rtx, 0), const0_rtx);
10073132718Skan      not_op = gen_rtx_COMPARE (CCEQmode, rev_cond_rtx, const0_rtx);
10074132718Skan      emit_insn (gen_rtx_SET (VOIDmode, not_result, not_op));
10075132718Skan      condition_rtx = gen_rtx_EQ (VOIDmode, not_result, const0_rtx);
10076132718Skan    }
10077132718Skan
1007890075Sobrien  op_mode = GET_MODE (rs6000_compare_op0);
1007990075Sobrien  if (op_mode == VOIDmode)
1008090075Sobrien    op_mode = GET_MODE (rs6000_compare_op1);
1008190075Sobrien
1008290075Sobrien  if (TARGET_POWERPC64 && (op_mode == DImode || rs6000_compare_fp_p))
1008390075Sobrien    {
1008490075Sobrien      PUT_MODE (condition_rtx, DImode);
1008590075Sobrien      convert_move (result, condition_rtx, 0);
1008690075Sobrien    }
1008790075Sobrien  else
1008890075Sobrien    {
1008990075Sobrien      PUT_MODE (condition_rtx, SImode);
1009090075Sobrien      emit_insn (gen_rtx_SET (VOIDmode, result, condition_rtx));
1009190075Sobrien    }
1009290075Sobrien}
1009390075Sobrien
1009490075Sobrien/* Emit a branch of kind CODE to location LOC.  */
1009590075Sobrien
1009690075Sobrienvoid
10097132718Skanrs6000_emit_cbranch (enum rtx_code code, rtx loc)
1009890075Sobrien{
1009990075Sobrien  rtx condition_rtx, loc_ref;
1010090075Sobrien
1010190075Sobrien  condition_rtx = rs6000_generate_compare (code);
1010290075Sobrien  loc_ref = gen_rtx_LABEL_REF (VOIDmode, loc);
1010390075Sobrien  emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx,
1010490075Sobrien			       gen_rtx_IF_THEN_ELSE (VOIDmode, condition_rtx,
1010590075Sobrien						     loc_ref, pc_rtx)));
1010690075Sobrien}
1010790075Sobrien
1010890075Sobrien/* Return the string to output a conditional branch to LABEL, which is
1010990075Sobrien   the operand number of the label, or -1 if the branch is really a
1011090075Sobrien   conditional return.
1011190075Sobrien
1011290075Sobrien   OP is the conditional expression.  XEXP (OP, 0) is assumed to be a
1011390075Sobrien   condition code register and its mode specifies what kind of
1011490075Sobrien   comparison we made.
1011590075Sobrien
10116117395Skan   REVERSED is nonzero if we should reverse the sense of the comparison.
1011790075Sobrien
1011890075Sobrien   INSN is the insn.  */
1011990075Sobrien
1012090075Sobrienchar *
10121132718Skanoutput_cbranch (rtx op, const char *label, int reversed, rtx insn)
1012290075Sobrien{
1012390075Sobrien  static char string[64];
1012490075Sobrien  enum rtx_code code = GET_CODE (op);
1012590075Sobrien  rtx cc_reg = XEXP (op, 0);
1012690075Sobrien  enum machine_mode mode = GET_MODE (cc_reg);
1012790075Sobrien  int cc_regno = REGNO (cc_reg) - CR0_REGNO;
1012890075Sobrien  int need_longbranch = label != NULL && get_attr_length (insn) == 8;
1012990075Sobrien  int really_reversed = reversed ^ need_longbranch;
1013090075Sobrien  char *s = string;
1013190075Sobrien  const char *ccode;
1013290075Sobrien  const char *pred;
1013390075Sobrien  rtx note;
1013490075Sobrien
1013590075Sobrien  validate_condition_mode (code, mode);
1013690075Sobrien
1013790075Sobrien  /* Work out which way this really branches.  We could use
1013890075Sobrien     reverse_condition_maybe_unordered here always but this
1013990075Sobrien     makes the resulting assembler clearer.  */
1014090075Sobrien  if (really_reversed)
10141107590Sobrien    {
10142107590Sobrien      /* Reversal of FP compares takes care -- an ordered compare
10143107590Sobrien	 becomes an unordered compare and vice versa.  */
10144107590Sobrien      if (mode == CCFPmode)
10145107590Sobrien	code = reverse_condition_maybe_unordered (code);
10146107590Sobrien      else
10147107590Sobrien	code = reverse_condition (code);
10148107590Sobrien    }
1014990075Sobrien
10150132718Skan  if ((TARGET_E500 && !TARGET_FPRS && TARGET_HARD_FLOAT) && mode == CCFPmode)
10151117395Skan    {
10152117395Skan      /* The efscmp/tst* instructions twiddle bit 2, which maps nicely
10153117395Skan	 to the GT bit.  */
10154117395Skan      if (code == EQ)
10155117395Skan	/* Opposite of GT.  */
10156132718Skan	code = GT;
10157117395Skan      else if (code == NE)
10158132718Skan       code = UNLE;
10159117395Skan      else
10160117395Skan	abort ();
10161117395Skan    }
10162117395Skan
1016390075Sobrien  switch (code)
1016490075Sobrien    {
1016590075Sobrien      /* Not all of these are actually distinct opcodes, but
1016690075Sobrien	 we distinguish them for clarity of the resulting assembler.  */
1016790075Sobrien    case NE: case LTGT:
1016890075Sobrien      ccode = "ne"; break;
1016990075Sobrien    case EQ: case UNEQ:
1017090075Sobrien      ccode = "eq"; break;
1017190075Sobrien    case GE: case GEU:
1017290075Sobrien      ccode = "ge"; break;
1017390075Sobrien    case GT: case GTU: case UNGT:
1017490075Sobrien      ccode = "gt"; break;
1017590075Sobrien    case LE: case LEU:
1017690075Sobrien      ccode = "le"; break;
1017790075Sobrien    case LT: case LTU: case UNLT:
1017890075Sobrien      ccode = "lt"; break;
1017990075Sobrien    case UNORDERED: ccode = "un"; break;
1018090075Sobrien    case ORDERED: ccode = "nu"; break;
1018190075Sobrien    case UNGE: ccode = "nl"; break;
1018290075Sobrien    case UNLE: ccode = "ng"; break;
1018390075Sobrien    default:
1018490075Sobrien      abort ();
1018590075Sobrien    }
1018690075Sobrien
1018790075Sobrien  /* Maybe we have a guess as to how likely the branch is.
1018890075Sobrien     The old mnemonics don't have a way to specify this information.  */
10189117395Skan  pred = "";
1019090075Sobrien  note = find_reg_note (insn, REG_BR_PROB, NULL_RTX);
1019190075Sobrien  if (note != NULL_RTX)
1019290075Sobrien    {
1019390075Sobrien      /* PROB is the difference from 50%.  */
1019490075Sobrien      int prob = INTVAL (XEXP (note, 0)) - REG_BR_PROB_BASE / 2;
10195117395Skan
10196117395Skan      /* Only hint for highly probable/improbable branches on newer
10197117395Skan	 cpus as static prediction overrides processor dynamic
10198117395Skan	 prediction.  For older cpus we may as well always hint, but
10199117395Skan	 assume not taken for branches that are very close to 50% as a
10200117395Skan	 mispredicted taken branch is more expensive than a
10201117395Skan	 mispredicted not-taken branch.  */
10202132718Skan      if (rs6000_always_hint
10203117395Skan	  || abs (prob) > REG_BR_PROB_BASE / 100 * 48)
10204117395Skan	{
10205117395Skan	  if (abs (prob) > REG_BR_PROB_BASE / 20
10206117395Skan	      && ((prob > 0) ^ need_longbranch))
10207132718Skan              pred = "+";
10208117395Skan	  else
10209117395Skan	    pred = "-";
10210117395Skan	}
1021190075Sobrien    }
1021290075Sobrien
1021390075Sobrien  if (label == NULL)
1021490075Sobrien    s += sprintf (s, "{b%sr|b%slr%s} ", ccode, ccode, pred);
1021590075Sobrien  else
1021690075Sobrien    s += sprintf (s, "{b%s|b%s%s} ", ccode, ccode, pred);
1021790075Sobrien
1021890075Sobrien  /* We need to escape any '%' characters in the reg_names string.
10219132718Skan     Assume they'd only be the first character....  */
1022090075Sobrien  if (reg_names[cc_regno + CR0_REGNO][0] == '%')
1022190075Sobrien    *s++ = '%';
1022290075Sobrien  s += sprintf (s, "%s", reg_names[cc_regno + CR0_REGNO]);
1022390075Sobrien
1022490075Sobrien  if (label != NULL)
1022590075Sobrien    {
1022690075Sobrien      /* If the branch distance was too far, we may have to use an
1022790075Sobrien	 unconditional branch to go the distance.  */
1022890075Sobrien      if (need_longbranch)
1022990075Sobrien	s += sprintf (s, ",$+8\n\tb %s", label);
1023090075Sobrien      else
1023190075Sobrien	s += sprintf (s, ",%s", label);
1023290075Sobrien    }
1023390075Sobrien
1023490075Sobrien  return string;
1023590075Sobrien}
1023690075Sobrien
10237146895Skan/* Return the string to flip the EQ bit on a CR.  */
10238132718Skanchar *
10239146895Skanoutput_e500_flip_eq_bit (rtx dst, rtx src)
10240132718Skan{
10241132718Skan  static char string[64];
10242132718Skan  int a, b;
10243132718Skan
10244132718Skan  if (GET_CODE (dst) != REG || ! CR_REGNO_P (REGNO (dst))
10245132718Skan      || GET_CODE (src) != REG || ! CR_REGNO_P (REGNO (src)))
10246132718Skan    abort ();
10247132718Skan
10248146895Skan  /* EQ bit.  */
10249146895Skan  a = 4 * (REGNO (dst) - CR0_REGNO) + 2;
10250146895Skan  b = 4 * (REGNO (src) - CR0_REGNO) + 2;
10251132718Skan
10252132718Skan  sprintf (string, "crnot %d,%d", a, b);
10253132718Skan  return string;
10254132718Skan}
10255132718Skan
1025690075Sobrien/* Emit a conditional move: move TRUE_COND to DEST if OP of the
1025790075Sobrien   operands of the last comparison is nonzero/true, FALSE_COND if it
1025890075Sobrien   is zero/false.  Return 0 if the hardware has no such operation.  */
1025990075Sobrien
1026090075Sobrienint
10261132718Skanrs6000_emit_cmove (rtx dest, rtx op, rtx true_cond, rtx false_cond)
1026290075Sobrien{
1026390075Sobrien  enum rtx_code code = GET_CODE (op);
1026490075Sobrien  rtx op0 = rs6000_compare_op0;
1026590075Sobrien  rtx op1 = rs6000_compare_op1;
1026690075Sobrien  REAL_VALUE_TYPE c1;
1026796263Sobrien  enum machine_mode compare_mode = GET_MODE (op0);
1026896263Sobrien  enum machine_mode result_mode = GET_MODE (dest);
1026990075Sobrien  rtx temp;
1027090075Sobrien
10271132718Skan  /* These modes should always match.  */
10272117395Skan  if (GET_MODE (op1) != compare_mode
10273117395Skan      /* In the isel case however, we can use a compare immediate, so
10274117395Skan	 op1 may be a small constant.  */
10275117395Skan      && (!TARGET_ISEL || !short_cint_operand (op1, VOIDmode)))
1027696263Sobrien    return 0;
1027796263Sobrien  if (GET_MODE (true_cond) != result_mode)
1027896263Sobrien    return 0;
1027996263Sobrien  if (GET_MODE (false_cond) != result_mode)
1028096263Sobrien    return 0;
1028196263Sobrien
1028290075Sobrien  /* First, work out if the hardware can do this at all, or
10283132718Skan     if it's too slow....  */
1028490075Sobrien  if (! rs6000_compare_fp_p)
10285117395Skan    {
10286117395Skan      if (TARGET_ISEL)
10287117395Skan	return rs6000_emit_int_cmove (dest, op, true_cond, false_cond);
10288117395Skan      return 0;
10289117395Skan    }
10290132718Skan  else if (TARGET_E500 && TARGET_HARD_FLOAT && !TARGET_FPRS
10291132718Skan	   && GET_MODE_CLASS (compare_mode) == MODE_FLOAT)
10292132718Skan    return 0;
1029390075Sobrien
1029490075Sobrien  /* Eliminate half of the comparisons by switching operands, this
1029590075Sobrien     makes the remaining code simpler.  */
1029690075Sobrien  if (code == UNLT || code == UNGT || code == UNORDERED || code == NE
10297132718Skan      || code == LTGT || code == LT || code == UNLE)
1029890075Sobrien    {
1029990075Sobrien      code = reverse_condition_maybe_unordered (code);
1030090075Sobrien      temp = true_cond;
1030190075Sobrien      true_cond = false_cond;
1030290075Sobrien      false_cond = temp;
1030390075Sobrien    }
1030490075Sobrien
1030590075Sobrien  /* UNEQ and LTGT take four instructions for a comparison with zero,
1030690075Sobrien     it'll probably be faster to use a branch here too.  */
10307132718Skan  if (code == UNEQ && HONOR_NANS (compare_mode))
1030890075Sobrien    return 0;
1030990075Sobrien
1031090075Sobrien  if (GET_CODE (op1) == CONST_DOUBLE)
1031190075Sobrien    REAL_VALUE_FROM_CONST_DOUBLE (c1, op1);
1031290075Sobrien
10313132718Skan  /* We're going to try to implement comparisons by performing
1031490075Sobrien     a subtract, then comparing against zero.  Unfortunately,
1031590075Sobrien     Inf - Inf is NaN which is not zero, and so if we don't
10316117395Skan     know that the operand is finite and the comparison
1031790075Sobrien     would treat EQ different to UNORDERED, we can't do it.  */
10318132718Skan  if (HONOR_INFINITIES (compare_mode)
1031990075Sobrien      && code != GT && code != UNGE
10320117395Skan      && (GET_CODE (op1) != CONST_DOUBLE || real_isinf (&c1))
1032190075Sobrien      /* Constructs of the form (a OP b ? a : b) are safe.  */
1032290075Sobrien      && ((! rtx_equal_p (op0, false_cond) && ! rtx_equal_p (op1, false_cond))
1032390075Sobrien	  || (! rtx_equal_p (op0, true_cond)
1032490075Sobrien	      && ! rtx_equal_p (op1, true_cond))))
1032590075Sobrien    return 0;
1032690075Sobrien  /* At this point we know we can use fsel.  */
1032790075Sobrien
1032890075Sobrien  /* Reduce the comparison to a comparison against zero.  */
1032996263Sobrien  temp = gen_reg_rtx (compare_mode);
1033090075Sobrien  emit_insn (gen_rtx_SET (VOIDmode, temp,
1033196263Sobrien			  gen_rtx_MINUS (compare_mode, op0, op1)));
1033290075Sobrien  op0 = temp;
1033396263Sobrien  op1 = CONST0_RTX (compare_mode);
1033490075Sobrien
1033590075Sobrien  /* If we don't care about NaNs we can reduce some of the comparisons
1033690075Sobrien     down to faster ones.  */
10337132718Skan  if (! HONOR_NANS (compare_mode))
1033890075Sobrien    switch (code)
1033990075Sobrien      {
1034090075Sobrien      case GT:
1034190075Sobrien	code = LE;
1034290075Sobrien	temp = true_cond;
1034390075Sobrien	true_cond = false_cond;
1034490075Sobrien	false_cond = temp;
1034590075Sobrien	break;
1034690075Sobrien      case UNGE:
1034790075Sobrien	code = GE;
1034890075Sobrien	break;
1034990075Sobrien      case UNEQ:
1035090075Sobrien	code = EQ;
1035190075Sobrien	break;
1035290075Sobrien      default:
1035390075Sobrien	break;
1035490075Sobrien      }
1035590075Sobrien
1035690075Sobrien  /* Now, reduce everything down to a GE.  */
1035790075Sobrien  switch (code)
1035890075Sobrien    {
1035990075Sobrien    case GE:
1036090075Sobrien      break;
1036190075Sobrien
1036290075Sobrien    case LE:
1036396263Sobrien      temp = gen_reg_rtx (compare_mode);
1036496263Sobrien      emit_insn (gen_rtx_SET (VOIDmode, temp, gen_rtx_NEG (compare_mode, op0)));
1036590075Sobrien      op0 = temp;
1036690075Sobrien      break;
1036790075Sobrien
1036890075Sobrien    case ORDERED:
1036996263Sobrien      temp = gen_reg_rtx (compare_mode);
1037096263Sobrien      emit_insn (gen_rtx_SET (VOIDmode, temp, gen_rtx_ABS (compare_mode, op0)));
1037190075Sobrien      op0 = temp;
1037290075Sobrien      break;
1037390075Sobrien
1037490075Sobrien    case EQ:
1037596263Sobrien      temp = gen_reg_rtx (compare_mode);
1037690075Sobrien      emit_insn (gen_rtx_SET (VOIDmode, temp,
1037796263Sobrien			      gen_rtx_NEG (compare_mode,
1037896263Sobrien					   gen_rtx_ABS (compare_mode, op0))));
1037990075Sobrien      op0 = temp;
1038090075Sobrien      break;
1038190075Sobrien
1038290075Sobrien    case UNGE:
10383132718Skan      /* a UNGE 0 <-> (a GE 0 || -a UNLT 0) */
1038496263Sobrien      temp = gen_reg_rtx (result_mode);
1038590075Sobrien      emit_insn (gen_rtx_SET (VOIDmode, temp,
1038696263Sobrien			      gen_rtx_IF_THEN_ELSE (result_mode,
1038790075Sobrien						    gen_rtx_GE (VOIDmode,
1038890075Sobrien								op0, op1),
1038990075Sobrien						    true_cond, false_cond)));
10390132718Skan      false_cond = true_cond;
10391132718Skan      true_cond = temp;
1039290075Sobrien
1039396263Sobrien      temp = gen_reg_rtx (compare_mode);
1039496263Sobrien      emit_insn (gen_rtx_SET (VOIDmode, temp, gen_rtx_NEG (compare_mode, op0)));
1039590075Sobrien      op0 = temp;
1039690075Sobrien      break;
1039790075Sobrien
1039890075Sobrien    case GT:
10399132718Skan      /* a GT 0 <-> (a GE 0 && -a UNLT 0) */
1040096263Sobrien      temp = gen_reg_rtx (result_mode);
1040190075Sobrien      emit_insn (gen_rtx_SET (VOIDmode, temp,
1040296263Sobrien			      gen_rtx_IF_THEN_ELSE (result_mode,
1040390075Sobrien						    gen_rtx_GE (VOIDmode,
1040490075Sobrien								op0, op1),
1040590075Sobrien						    true_cond, false_cond)));
10406132718Skan      true_cond = false_cond;
10407132718Skan      false_cond = temp;
1040890075Sobrien
1040996263Sobrien      temp = gen_reg_rtx (compare_mode);
1041096263Sobrien      emit_insn (gen_rtx_SET (VOIDmode, temp, gen_rtx_NEG (compare_mode, op0)));
1041190075Sobrien      op0 = temp;
1041290075Sobrien      break;
1041390075Sobrien
1041490075Sobrien    default:
1041590075Sobrien      abort ();
1041690075Sobrien    }
1041790075Sobrien
1041890075Sobrien  emit_insn (gen_rtx_SET (VOIDmode, dest,
1041996263Sobrien			  gen_rtx_IF_THEN_ELSE (result_mode,
1042090075Sobrien						gen_rtx_GE (VOIDmode,
1042190075Sobrien							    op0, op1),
1042290075Sobrien						true_cond, false_cond)));
1042390075Sobrien  return 1;
1042490075Sobrien}
1042590075Sobrien
10426117395Skan/* Same as above, but for ints (isel).  */
10427117395Skan
10428117395Skanstatic int
10429132718Skanrs6000_emit_int_cmove (rtx dest, rtx op, rtx true_cond, rtx false_cond)
10430117395Skan{
10431117395Skan  rtx condition_rtx, cr;
10432117395Skan
10433117395Skan  /* All isel implementations thus far are 32-bits.  */
10434117395Skan  if (GET_MODE (rs6000_compare_op0) != SImode)
10435117395Skan    return 0;
10436117395Skan
10437117395Skan  /* We still have to do the compare, because isel doesn't do a
10438117395Skan     compare, it just looks at the CRx bits set by a previous compare
10439117395Skan     instruction.  */
10440117395Skan  condition_rtx = rs6000_generate_compare (GET_CODE (op));
10441117395Skan  cr = XEXP (condition_rtx, 0);
10442117395Skan
10443117395Skan  if (GET_MODE (cr) == CCmode)
10444117395Skan    emit_insn (gen_isel_signed (dest, condition_rtx,
10445117395Skan				true_cond, false_cond, cr));
10446117395Skan  else
10447117395Skan    emit_insn (gen_isel_unsigned (dest, condition_rtx,
10448117395Skan				  true_cond, false_cond, cr));
10449117395Skan
10450117395Skan  return 1;
10451117395Skan}
10452117395Skan
10453117395Skanconst char *
10454132718Skanoutput_isel (rtx *operands)
10455117395Skan{
10456117395Skan  enum rtx_code code;
10457117395Skan
10458117395Skan  code = GET_CODE (operands[1]);
10459117395Skan  if (code == GE || code == GEU || code == LE || code == LEU || code == NE)
10460117395Skan    {
10461117395Skan      PUT_CODE (operands[1], reverse_condition (code));
10462117395Skan      return "isel %0,%3,%2,%j1";
10463117395Skan    }
10464117395Skan  else
10465117395Skan    return "isel %0,%2,%3,%j1";
10466117395Skan}
10467117395Skan
1046890075Sobrienvoid
10469132718Skanrs6000_emit_minmax (rtx dest, enum rtx_code code, rtx op0, rtx op1)
1047090075Sobrien{
1047190075Sobrien  enum machine_mode mode = GET_MODE (op0);
10472117395Skan  enum rtx_code c;
1047390075Sobrien  rtx target;
10474117395Skan
10475117395Skan  if (code == SMAX || code == SMIN)
10476117395Skan    c = GE;
10477117395Skan  else
10478117395Skan    c = GEU;
10479117395Skan
1048090075Sobrien  if (code == SMAX || code == UMAX)
10481117395Skan    target = emit_conditional_move (dest, c, op0, op1, mode,
1048290075Sobrien				    op0, op1, mode, 0);
1048390075Sobrien  else
10484117395Skan    target = emit_conditional_move (dest, c, op0, op1, mode,
1048590075Sobrien				    op1, op0, mode, 0);
1048690075Sobrien  if (target == NULL_RTX)
1048790075Sobrien    abort ();
1048890075Sobrien  if (target != dest)
1048990075Sobrien    emit_move_insn (dest, target);
1049090075Sobrien}
10491132718Skan
10492132718Skan/* Emit instructions to move SRC to DST.  Called by splitters for
10493132718Skan   multi-register moves.  It will emit at most one instruction for
10494132718Skan   each register that is accessed; that is, it won't emit li/lis pairs
10495132718Skan   (or equivalent for 64-bit code).  One of SRC or DST must be a hard
10496132718Skan   register.  */
10497132718Skan
10498132718Skanvoid
10499132718Skanrs6000_split_multireg_move (rtx dst, rtx src)
10500132718Skan{
10501132718Skan  /* The register number of the first register being moved.  */
10502132718Skan  int reg;
10503132718Skan  /* The mode that is to be moved.  */
10504132718Skan  enum machine_mode mode;
10505132718Skan  /* The mode that the move is being done in, and its size.  */
10506132718Skan  enum machine_mode reg_mode;
10507132718Skan  int reg_mode_size;
10508132718Skan  /* The number of registers that will be moved.  */
10509132718Skan  int nregs;
10510132718Skan
10511132718Skan  reg = REG_P (dst) ? REGNO (dst) : REGNO (src);
10512132718Skan  mode = GET_MODE (dst);
10513132718Skan  nregs = HARD_REGNO_NREGS (reg, mode);
10514132718Skan  if (FP_REGNO_P (reg))
10515132718Skan    reg_mode = DFmode;
10516132718Skan  else if (ALTIVEC_REGNO_P (reg))
10517132718Skan    reg_mode = V16QImode;
10518132718Skan  else
10519132718Skan    reg_mode = word_mode;
10520132718Skan  reg_mode_size = GET_MODE_SIZE (reg_mode);
10521132718Skan
10522132718Skan  if (reg_mode_size * nregs != GET_MODE_SIZE (mode))
10523132718Skan    abort ();
10524132718Skan
10525132718Skan  if (REG_P (src) && REG_P (dst) && (REGNO (src) < REGNO (dst)))
10526132718Skan    {
10527132718Skan      /* Move register range backwards, if we might have destructive
10528132718Skan	 overlap.  */
10529132718Skan      int i;
10530132718Skan      for (i = nregs - 1; i >= 0; i--)
10531132718Skan	emit_insn (gen_rtx_SET (VOIDmode,
10532132718Skan				simplify_gen_subreg (reg_mode, dst, mode,
10533132718Skan						     i * reg_mode_size),
10534132718Skan				simplify_gen_subreg (reg_mode, src, mode,
10535132718Skan						     i * reg_mode_size)));
10536132718Skan    }
10537132718Skan  else
10538132718Skan    {
10539132718Skan      int i;
10540132718Skan      int j = -1;
10541132718Skan      bool used_update = false;
10542132718Skan
10543132718Skan      if (GET_CODE (src) == MEM && INT_REGNO_P (reg))
10544132718Skan        {
10545132718Skan          rtx breg;
10546132718Skan
10547132718Skan	  if (GET_CODE (XEXP (src, 0)) == PRE_INC
10548132718Skan	      || GET_CODE (XEXP (src, 0)) == PRE_DEC)
10549132718Skan	    {
10550132718Skan	      rtx delta_rtx;
10551132718Skan	      breg = XEXP (XEXP (src, 0), 0);
10552132718Skan	      delta_rtx =  GET_CODE (XEXP (src, 0)) == PRE_INC
10553132718Skan		  ? GEN_INT (GET_MODE_SIZE (GET_MODE (src)))
10554132718Skan		  : GEN_INT (-GET_MODE_SIZE (GET_MODE (src)));
10555132718Skan	      emit_insn (TARGET_32BIT
10556132718Skan			 ? gen_addsi3 (breg, breg, delta_rtx)
10557132718Skan			 : gen_adddi3 (breg, breg, delta_rtx));
10558132718Skan	      src = gen_rtx_MEM (mode, breg);
10559132718Skan	    }
10560146895Skan	  else if (! offsettable_memref_p (src))
10561146895Skan	    {
10562146895Skan	      rtx newsrc, basereg;
10563146895Skan	      basereg = gen_rtx_REG (Pmode, reg);
10564146895Skan	      emit_insn (gen_rtx_SET (VOIDmode, basereg, XEXP (src, 0)));
10565146895Skan	      newsrc = gen_rtx_MEM (GET_MODE (src), basereg);
10566146895Skan	      MEM_COPY_ATTRIBUTES (newsrc, src);
10567146895Skan	      src = newsrc;
10568146895Skan	    }
10569132718Skan
10570146895Skan	  breg = XEXP (src, 0);
10571146895Skan	  if (GET_CODE (breg) == PLUS || GET_CODE (breg) == LO_SUM)
10572146895Skan	    breg = XEXP (breg, 0);
10573132718Skan
10574146895Skan	  /* If the base register we are using to address memory is
10575146895Skan	     also a destination reg, then change that register last.  */
10576146895Skan	  if (REG_P (breg)
10577146895Skan	      && REGNO (breg) >= REGNO (dst)
10578132718Skan	      && REGNO (breg) < REGNO (dst) + nregs)
10579132718Skan	    j = REGNO (breg) - REGNO (dst);
10580146895Skan	}
10581132718Skan
10582132718Skan      if (GET_CODE (dst) == MEM && INT_REGNO_P (reg))
10583132718Skan	{
10584132718Skan	  rtx breg;
10585132718Skan
10586132718Skan	  if (GET_CODE (XEXP (dst, 0)) == PRE_INC
10587132718Skan	      || GET_CODE (XEXP (dst, 0)) == PRE_DEC)
10588132718Skan	    {
10589132718Skan	      rtx delta_rtx;
10590132718Skan	      breg = XEXP (XEXP (dst, 0), 0);
10591132718Skan	      delta_rtx = GET_CODE (XEXP (dst, 0)) == PRE_INC
10592132718Skan		? GEN_INT (GET_MODE_SIZE (GET_MODE (dst)))
10593132718Skan		: GEN_INT (-GET_MODE_SIZE (GET_MODE (dst)));
10594132718Skan
10595132718Skan	      /* We have to update the breg before doing the store.
10596132718Skan		 Use store with update, if available.  */
10597132718Skan
10598132718Skan	      if (TARGET_UPDATE)
10599132718Skan		{
10600132718Skan		  rtx nsrc = simplify_gen_subreg (reg_mode, src, mode, 0);
10601132718Skan		  emit_insn (TARGET_32BIT
10602132718Skan			     ? gen_movsi_update (breg, breg, delta_rtx, nsrc)
10603132718Skan			     : gen_movdi_update (breg, breg, delta_rtx, nsrc));
10604132718Skan		  used_update = true;
10605132718Skan		}
10606132718Skan	      else
10607132718Skan		emit_insn (TARGET_32BIT
10608132718Skan			   ? gen_addsi3 (breg, breg, delta_rtx)
10609132718Skan			   : gen_adddi3 (breg, breg, delta_rtx));
10610132718Skan	      dst = gen_rtx_MEM (mode, breg);
10611132718Skan	    }
10612146895Skan	  else if (! offsettable_memref_p (dst))
10613146895Skan	    abort ();
10614132718Skan	}
10615132718Skan
10616132718Skan      for (i = 0; i < nregs; i++)
10617132718Skan	{
10618132718Skan	  /* Calculate index to next subword.  */
10619132718Skan	  ++j;
10620132718Skan	  if (j == nregs)
10621132718Skan	    j = 0;
10622132718Skan
10623146895Skan	  /* If compiler already emitted move of first word by
10624132718Skan	     store with update, no need to do anything.  */
10625132718Skan	  if (j == 0 && used_update)
10626132718Skan	    continue;
10627132718Skan
10628132718Skan	  emit_insn (gen_rtx_SET (VOIDmode,
10629132718Skan				  simplify_gen_subreg (reg_mode, dst, mode,
10630132718Skan						       j * reg_mode_size),
10631132718Skan				  simplify_gen_subreg (reg_mode, src, mode,
10632132718Skan						       j * reg_mode_size)));
10633132718Skan	}
10634132718Skan    }
10635132718Skan}
10636132718Skan
1063790075Sobrien
1063890075Sobrien/* This page contains routines that are used to determine what the
1063990075Sobrien   function prologue and epilogue code will do and write them out.  */
1064090075Sobrien
1064190075Sobrien/* Return the first fixed-point register that is required to be
1064290075Sobrien   saved. 32 if none.  */
1064390075Sobrien
1064490075Sobrienint
10645132718Skanfirst_reg_to_save (void)
1064690075Sobrien{
1064790075Sobrien  int first_reg;
1064890075Sobrien
1064990075Sobrien  /* Find lowest numbered live register.  */
1065090075Sobrien  for (first_reg = 13; first_reg <= 31; first_reg++)
1065190075Sobrien    if (regs_ever_live[first_reg]
1065290075Sobrien	&& (! call_used_regs[first_reg]
1065396263Sobrien	    || (first_reg == RS6000_PIC_OFFSET_TABLE_REGNUM
10654117395Skan		&& ((DEFAULT_ABI == ABI_V4 && flag_pic != 0)
10655146895Skan		    || (DEFAULT_ABI == ABI_DARWIN && flag_pic)
10656146895Skan		    || (TARGET_TOC && TARGET_MINIMAL_TOC)))))
1065790075Sobrien      break;
1065890075Sobrien
1065990075Sobrien#if TARGET_MACHO
10660117395Skan  if (flag_pic
10661117395Skan      && current_function_uses_pic_offset_table
10662117395Skan      && first_reg > RS6000_PIC_OFFSET_TABLE_REGNUM)
1066396263Sobrien    return RS6000_PIC_OFFSET_TABLE_REGNUM;
1066490075Sobrien#endif
1066590075Sobrien
1066690075Sobrien  return first_reg;
1066790075Sobrien}
1066890075Sobrien
1066990075Sobrien/* Similar, for FP regs.  */
1067090075Sobrien
1067190075Sobrienint
10672132718Skanfirst_fp_reg_to_save (void)
1067390075Sobrien{
1067490075Sobrien  int first_reg;
1067590075Sobrien
1067690075Sobrien  /* Find lowest numbered live register.  */
1067790075Sobrien  for (first_reg = 14 + 32; first_reg <= 63; first_reg++)
1067890075Sobrien    if (regs_ever_live[first_reg])
1067990075Sobrien      break;
1068090075Sobrien
1068190075Sobrien  return first_reg;
1068290075Sobrien}
1068390075Sobrien
1068490075Sobrien/* Similar, for AltiVec regs.  */
1068590075Sobrien
1068690075Sobrienstatic int
10687132718Skanfirst_altivec_reg_to_save (void)
1068890075Sobrien{
1068990075Sobrien  int i;
1069090075Sobrien
1069190075Sobrien  /* Stack frame remains as is unless we are in AltiVec ABI.  */
1069290075Sobrien  if (! TARGET_ALTIVEC_ABI)
1069390075Sobrien    return LAST_ALTIVEC_REGNO + 1;
1069490075Sobrien
1069590075Sobrien  /* Find lowest numbered live register.  */
1069690075Sobrien  for (i = FIRST_ALTIVEC_REGNO + 20; i <= LAST_ALTIVEC_REGNO; ++i)
1069790075Sobrien    if (regs_ever_live[i])
1069890075Sobrien      break;
1069990075Sobrien
1070090075Sobrien  return i;
1070190075Sobrien}
1070290075Sobrien
1070390075Sobrien/* Return a 32-bit mask of the AltiVec registers we need to set in
1070490075Sobrien   VRSAVE.  Bit n of the return value is 1 if Vn is live.  The MSB in
1070590075Sobrien   the 32-bit word is 0.  */
1070690075Sobrien
1070790075Sobrienstatic unsigned int
10708132718Skancompute_vrsave_mask (void)
1070990075Sobrien{
1071090075Sobrien  unsigned int i, mask = 0;
1071190075Sobrien
1071290075Sobrien  /* First, find out if we use _any_ altivec registers.  */
1071390075Sobrien  for (i = FIRST_ALTIVEC_REGNO; i <= LAST_ALTIVEC_REGNO; ++i)
1071490075Sobrien    if (regs_ever_live[i])
1071590075Sobrien      mask |= ALTIVEC_REG_BIT (i);
1071690075Sobrien
1071790075Sobrien  if (mask == 0)
1071890075Sobrien    return mask;
1071990075Sobrien
1072090075Sobrien  /* Next, remove the argument registers from the set.  These must
1072190075Sobrien     be in the VRSAVE mask set by the caller, so we don't need to add
1072290075Sobrien     them in again.  More importantly, the mask we compute here is
1072390075Sobrien     used to generate CLOBBERs in the set_vrsave insn, and we do not
1072490075Sobrien     wish the argument registers to die.  */
10725132718Skan  for (i = cfun->args_info.vregno - 1; i >= ALTIVEC_ARG_MIN_REG; --i)
1072690075Sobrien    mask &= ~ALTIVEC_REG_BIT (i);
1072790075Sobrien
1072890075Sobrien  /* Similarly, remove the return value from the set.  */
1072990075Sobrien  {
1073090075Sobrien    bool yes = false;
1073190075Sobrien    diddle_return_value (is_altivec_return_reg, &yes);
1073290075Sobrien    if (yes)
1073390075Sobrien      mask &= ~ALTIVEC_REG_BIT (ALTIVEC_ARG_RETURN);
1073490075Sobrien  }
1073590075Sobrien
1073690075Sobrien  return mask;
1073790075Sobrien}
1073890075Sobrien
1073990075Sobrienstatic void
10740132718Skanis_altivec_return_reg (rtx reg, void *xyes)
1074190075Sobrien{
1074290075Sobrien  bool *yes = (bool *) xyes;
1074390075Sobrien  if (REGNO (reg) == ALTIVEC_ARG_RETURN)
1074490075Sobrien    *yes = true;
1074590075Sobrien}
1074690075Sobrien
1074790075Sobrien
1074890075Sobrien/* Calculate the stack information for the current function.  This is
1074990075Sobrien   complicated by having two separate calling sequences, the AIX calling
1075090075Sobrien   sequence and the V.4 calling sequence.
1075190075Sobrien
1075290075Sobrien   AIX (and Darwin/Mac OS X) stack frames look like:
1075390075Sobrien							  32-bit  64-bit
1075490075Sobrien	SP---->	+---------------------------------------+
1075590075Sobrien		| back chain to caller			| 0	  0
1075690075Sobrien		+---------------------------------------+
1075790075Sobrien		| saved CR				| 4       8 (8-11)
1075890075Sobrien		+---------------------------------------+
1075990075Sobrien		| saved LR				| 8       16
1076090075Sobrien		+---------------------------------------+
1076190075Sobrien		| reserved for compilers		| 12      24
1076290075Sobrien		+---------------------------------------+
1076390075Sobrien		| reserved for binders			| 16      32
1076490075Sobrien		+---------------------------------------+
1076590075Sobrien		| saved TOC pointer			| 20      40
1076690075Sobrien		+---------------------------------------+
1076790075Sobrien		| Parameter save area (P)		| 24      48
1076890075Sobrien		+---------------------------------------+
1076990075Sobrien		| Alloca space (A)			| 24+P    etc.
1077090075Sobrien		+---------------------------------------+
1077190075Sobrien		| Local variable space (L)		| 24+P+A
1077290075Sobrien		+---------------------------------------+
1077390075Sobrien		| Float/int conversion temporary (X)	| 24+P+A+L
1077490075Sobrien		+---------------------------------------+
1077590075Sobrien		| Save area for AltiVec registers (W)	| 24+P+A+L+X
1077690075Sobrien		+---------------------------------------+
1077790075Sobrien		| AltiVec alignment padding (Y)		| 24+P+A+L+X+W
1077890075Sobrien		+---------------------------------------+
1077990075Sobrien		| Save area for VRSAVE register (Z)	| 24+P+A+L+X+W+Y
1078090075Sobrien		+---------------------------------------+
1078190075Sobrien		| Save area for GP registers (G)	| 24+P+A+X+L+X+W+Y+Z
1078290075Sobrien		+---------------------------------------+
1078390075Sobrien		| Save area for FP registers (F)	| 24+P+A+X+L+X+W+Y+Z+G
1078490075Sobrien		+---------------------------------------+
1078590075Sobrien	old SP->| back chain to caller's caller		|
1078690075Sobrien		+---------------------------------------+
1078790075Sobrien
1078890075Sobrien   The required alignment for AIX configurations is two words (i.e., 8
1078990075Sobrien   or 16 bytes).
1079090075Sobrien
1079190075Sobrien
1079290075Sobrien   V.4 stack frames look like:
1079390075Sobrien
1079490075Sobrien	SP---->	+---------------------------------------+
1079590075Sobrien		| back chain to caller			| 0
1079690075Sobrien		+---------------------------------------+
1079790075Sobrien		| caller's saved LR			| 4
1079890075Sobrien		+---------------------------------------+
1079990075Sobrien		| Parameter save area (P)		| 8
1080090075Sobrien		+---------------------------------------+
1080190075Sobrien		| Alloca space (A)			| 8+P
1080290075Sobrien		+---------------------------------------+
1080390075Sobrien		| Varargs save area (V)			| 8+P+A
1080490075Sobrien		+---------------------------------------+
1080590075Sobrien		| Local variable space (L)		| 8+P+A+V
1080690075Sobrien		+---------------------------------------+
1080790075Sobrien		| Float/int conversion temporary (X)	| 8+P+A+V+L
1080890075Sobrien		+---------------------------------------+
1080990075Sobrien		| Save area for AltiVec registers (W)	| 8+P+A+V+L+X
1081090075Sobrien		+---------------------------------------+
1081190075Sobrien		| AltiVec alignment padding (Y)		| 8+P+A+V+L+X+W
1081290075Sobrien		+---------------------------------------+
1081390075Sobrien		| Save area for VRSAVE register (Z)	| 8+P+A+V+L+X+W+Y
1081490075Sobrien		+---------------------------------------+
10815117395Skan                | SPE: area for 64-bit GP registers     |
10816117395Skan                +---------------------------------------+
10817117395Skan                | SPE alignment padding                 |
10818117395Skan                +---------------------------------------+
1081990075Sobrien		| saved CR (C)				| 8+P+A+V+L+X+W+Y+Z
1082090075Sobrien		+---------------------------------------+
1082190075Sobrien		| Save area for GP registers (G)	| 8+P+A+V+L+X+W+Y+Z+C
1082290075Sobrien		+---------------------------------------+
1082390075Sobrien		| Save area for FP registers (F)	| 8+P+A+V+L+X+W+Y+Z+C+G
1082490075Sobrien		+---------------------------------------+
1082590075Sobrien	old SP->| back chain to caller's caller		|
1082690075Sobrien		+---------------------------------------+
1082790075Sobrien
1082890075Sobrien   The required alignment for V.4 is 16 bytes, or 8 bytes if -meabi is
1082990075Sobrien   given.  (But note below and in sysv4.h that we require only 8 and
1083090075Sobrien   may round up the size of our stack frame anyways.  The historical
1083190075Sobrien   reason is early versions of powerpc-linux which didn't properly
1083290075Sobrien   align the stack at program startup.  A happy side-effect is that
1083390075Sobrien   -mno-eabi libraries can be used with -meabi programs.)
1083490075Sobrien
10835132718Skan   The EABI configuration defaults to the V.4 layout.  However,
1083690075Sobrien   the stack alignment requirements may differ.  If -mno-eabi is not
1083790075Sobrien   given, the required stack alignment is 8 bytes; if -mno-eabi is
1083890075Sobrien   given, the required alignment is 16 bytes.  (But see V.4 comment
1083990075Sobrien   above.)  */
1084090075Sobrien
1084190075Sobrien#ifndef ABI_STACK_BOUNDARY
1084290075Sobrien#define ABI_STACK_BOUNDARY STACK_BOUNDARY
1084390075Sobrien#endif
1084490075Sobrien
10845132718Skanstatic rs6000_stack_t *
10846132718Skanrs6000_stack_info (void)
1084790075Sobrien{
1084890075Sobrien  static rs6000_stack_t info, zero_info;
1084990075Sobrien  rs6000_stack_t *info_ptr = &info;
10850132718Skan  int reg_size = TARGET_32BIT ? 4 : 8;
1085190075Sobrien  int ehrd_size;
10852146895Skan  int save_align;
10853132718Skan  HOST_WIDE_INT non_fixed_size;
1085490075Sobrien
1085590075Sobrien  /* Zero all fields portably.  */
1085690075Sobrien  info = zero_info;
1085790075Sobrien
10858132718Skan  if (TARGET_SPE)
10859132718Skan    {
10860132718Skan      /* Cache value so we don't rescan instruction chain over and over.  */
10861132718Skan      if (cfun->machine->insn_chain_scanned_p == 0)
10862132718Skan	{
10863132718Skan	  cfun->machine->insn_chain_scanned_p = 1;
10864132718Skan	  info_ptr->spe_64bit_regs_used = (int) spe_func_has_64bit_regs_p ();
10865132718Skan	}
10866132718Skan    }
10867132718Skan
1086890075Sobrien  /* Select which calling sequence.  */
10869132718Skan  info_ptr->abi = DEFAULT_ABI;
1087090075Sobrien
1087190075Sobrien  /* Calculate which registers need to be saved & save area size.  */
1087290075Sobrien  info_ptr->first_gp_reg_save = first_reg_to_save ();
1087396263Sobrien  /* Assume that we will have to save RS6000_PIC_OFFSET_TABLE_REGNUM,
1087490075Sobrien     even if it currently looks like we won't.  */
1087590075Sobrien  if (((TARGET_TOC && TARGET_MINIMAL_TOC)
10876132718Skan       || (flag_pic == 1 && DEFAULT_ABI == ABI_V4)
10877132718Skan       || (flag_pic && DEFAULT_ABI == ABI_DARWIN))
1087896263Sobrien      && info_ptr->first_gp_reg_save > RS6000_PIC_OFFSET_TABLE_REGNUM)
1087996263Sobrien    info_ptr->gp_size = reg_size * (32 - RS6000_PIC_OFFSET_TABLE_REGNUM);
1088090075Sobrien  else
1088190075Sobrien    info_ptr->gp_size = reg_size * (32 - info_ptr->first_gp_reg_save);
1088290075Sobrien
10883117395Skan  /* For the SPE, we have an additional upper 32-bits on each GPR.
10884117395Skan     Ideally we should save the entire 64-bits only when the upper
10885117395Skan     half is used in SIMD instructions.  Since we only record
10886117395Skan     registers live (not the size they are used in), this proves
10887117395Skan     difficult because we'd have to traverse the instruction chain at
10888117395Skan     the right time, taking reload into account.  This is a real pain,
10889132718Skan     so we opt to save the GPRs in 64-bits always if but one register
10890132718Skan     gets used in 64-bits.  Otherwise, all the registers in the frame
10891132718Skan     get saved in 32-bits.
10892117395Skan
10893132718Skan     So... since when we save all GPRs (except the SP) in 64-bits, the
10894117395Skan     traditional GP save area will be empty.  */
10895132718Skan  if (TARGET_SPE_ABI && info_ptr->spe_64bit_regs_used != 0)
10896117395Skan    info_ptr->gp_size = 0;
10897117395Skan
1089890075Sobrien  info_ptr->first_fp_reg_save = first_fp_reg_to_save ();
1089990075Sobrien  info_ptr->fp_size = 8 * (64 - info_ptr->first_fp_reg_save);
1090090075Sobrien
1090190075Sobrien  info_ptr->first_altivec_reg_save = first_altivec_reg_to_save ();
1090290075Sobrien  info_ptr->altivec_size = 16 * (LAST_ALTIVEC_REGNO + 1
1090390075Sobrien				 - info_ptr->first_altivec_reg_save);
1090490075Sobrien
1090590075Sobrien  /* Does this function call anything?  */
1090690075Sobrien  info_ptr->calls_p = (! current_function_is_leaf
1090790075Sobrien		       || cfun->machine->ra_needs_full_frame);
1090890075Sobrien
1090990075Sobrien  /* Determine if we need to save the link register.  */
1091090075Sobrien  if (rs6000_ra_ever_killed ()
10911132718Skan      || (DEFAULT_ABI == ABI_AIX
10912132718Skan	  && current_function_profile
10913132718Skan	  && !TARGET_PROFILE_KERNEL)
1091490075Sobrien#ifdef TARGET_RELOCATABLE
1091590075Sobrien      || (TARGET_RELOCATABLE && (get_pool_size () != 0))
1091690075Sobrien#endif
1091790075Sobrien      || (info_ptr->first_fp_reg_save != 64
1091890075Sobrien	  && !FP_SAVE_INLINE (info_ptr->first_fp_reg_save))
1091990075Sobrien      || info_ptr->first_altivec_reg_save <= LAST_ALTIVEC_REGNO
10920132718Skan      || (DEFAULT_ABI == ABI_V4 && current_function_calls_alloca)
1092190075Sobrien      || (DEFAULT_ABI == ABI_DARWIN
1092290075Sobrien	  && flag_pic
1092390075Sobrien	  && current_function_uses_pic_offset_table)
1092490075Sobrien      || info_ptr->calls_p)
1092590075Sobrien    {
1092690075Sobrien      info_ptr->lr_save_p = 1;
1092790075Sobrien      regs_ever_live[LINK_REGISTER_REGNUM] = 1;
1092890075Sobrien    }
1092990075Sobrien
1093090075Sobrien  /* Determine if we need to save the condition code registers.  */
1093190075Sobrien  if (regs_ever_live[CR2_REGNO]
1093290075Sobrien      || regs_ever_live[CR3_REGNO]
1093390075Sobrien      || regs_ever_live[CR4_REGNO])
1093490075Sobrien    {
1093590075Sobrien      info_ptr->cr_save_p = 1;
10936132718Skan      if (DEFAULT_ABI == ABI_V4)
1093790075Sobrien	info_ptr->cr_size = reg_size;
1093890075Sobrien    }
1093990075Sobrien
1094090075Sobrien  /* If the current function calls __builtin_eh_return, then we need
1094190075Sobrien     to allocate stack space for registers that will hold data for
1094290075Sobrien     the exception handler.  */
1094390075Sobrien  if (current_function_calls_eh_return)
1094490075Sobrien    {
1094590075Sobrien      unsigned int i;
1094690075Sobrien      for (i = 0; EH_RETURN_DATA_REGNO (i) != INVALID_REGNUM; ++i)
1094790075Sobrien	continue;
10948117395Skan
10949117395Skan      /* SPE saves EH registers in 64-bits.  */
10950132718Skan      ehrd_size = i * (TARGET_SPE_ABI
10951132718Skan		       && info_ptr->spe_64bit_regs_used != 0
10952132718Skan		       ? UNITS_PER_SPE_WORD : UNITS_PER_WORD);
1095390075Sobrien    }
1095490075Sobrien  else
1095590075Sobrien    ehrd_size = 0;
1095690075Sobrien
1095790075Sobrien  /* Determine various sizes.  */
1095890075Sobrien  info_ptr->reg_size     = reg_size;
1095990075Sobrien  info_ptr->fixed_size   = RS6000_SAVE_AREA;
1096090075Sobrien  info_ptr->varargs_size = RS6000_VARARGS_AREA;
1096190075Sobrien  info_ptr->vars_size    = RS6000_ALIGN (get_frame_size (), 8);
1096290075Sobrien  info_ptr->parm_size    = RS6000_ALIGN (current_function_outgoing_args_size,
10963132718Skan					 TARGET_ALTIVEC ? 16 : 8);
1096490075Sobrien
10965132718Skan  if (TARGET_SPE_ABI && info_ptr->spe_64bit_regs_used != 0)
10966117395Skan    info_ptr->spe_gp_size = 8 * (32 - info_ptr->first_gp_reg_save);
10967117395Skan  else
10968117395Skan    info_ptr->spe_gp_size = 0;
10969117395Skan
10970132718Skan  if (TARGET_ALTIVEC_ABI)
10971132718Skan    info_ptr->vrsave_mask = compute_vrsave_mask ();
1097290075Sobrien  else
10973132718Skan    info_ptr->vrsave_mask = 0;
1097490075Sobrien
10975132718Skan  if (TARGET_ALTIVEC_VRSAVE && info_ptr->vrsave_mask)
10976132718Skan    info_ptr->vrsave_size  = 4;
10977132718Skan  else
10978132718Skan    info_ptr->vrsave_size  = 0;
10979132718Skan
1098090075Sobrien  /* Calculate the offsets.  */
10981132718Skan  switch (DEFAULT_ABI)
1098290075Sobrien    {
1098390075Sobrien    case ABI_NONE:
1098490075Sobrien    default:
1098590075Sobrien      abort ();
1098690075Sobrien
1098790075Sobrien    case ABI_AIX:
1098890075Sobrien    case ABI_DARWIN:
1098990075Sobrien      info_ptr->fp_save_offset   = - info_ptr->fp_size;
1099090075Sobrien      info_ptr->gp_save_offset   = info_ptr->fp_save_offset - info_ptr->gp_size;
1099190075Sobrien
1099290075Sobrien      if (TARGET_ALTIVEC_ABI)
1099390075Sobrien	{
1099490075Sobrien	  info_ptr->vrsave_save_offset
1099590075Sobrien	    = info_ptr->gp_save_offset - info_ptr->vrsave_size;
1099690075Sobrien
1099790075Sobrien	  /* Align stack so vector save area is on a quadword boundary.  */
1099890075Sobrien	  if (info_ptr->altivec_size != 0)
1099990075Sobrien	    info_ptr->altivec_padding_size
1100090075Sobrien	      = 16 - (-info_ptr->vrsave_save_offset % 16);
1100190075Sobrien	  else
1100290075Sobrien	    info_ptr->altivec_padding_size = 0;
1100390075Sobrien
1100490075Sobrien	  info_ptr->altivec_save_offset
1100590075Sobrien	    = info_ptr->vrsave_save_offset
1100690075Sobrien	    - info_ptr->altivec_padding_size
1100790075Sobrien	    - info_ptr->altivec_size;
1100890075Sobrien
1100990075Sobrien	  /* Adjust for AltiVec case.  */
1101090075Sobrien	  info_ptr->ehrd_offset = info_ptr->altivec_save_offset - ehrd_size;
1101190075Sobrien	}
1101290075Sobrien      else
1101390075Sobrien	info_ptr->ehrd_offset      = info_ptr->gp_save_offset - ehrd_size;
1101490075Sobrien      info_ptr->cr_save_offset   = reg_size; /* first word when 64-bit.  */
1101590075Sobrien      info_ptr->lr_save_offset   = 2*reg_size;
1101690075Sobrien      break;
1101790075Sobrien
1101890075Sobrien    case ABI_V4:
1101990075Sobrien      info_ptr->fp_save_offset   = - info_ptr->fp_size;
1102090075Sobrien      info_ptr->gp_save_offset   = info_ptr->fp_save_offset - info_ptr->gp_size;
1102190075Sobrien      info_ptr->cr_save_offset   = info_ptr->gp_save_offset - info_ptr->cr_size;
1102290075Sobrien
11023132718Skan      if (TARGET_SPE_ABI && info_ptr->spe_64bit_regs_used != 0)
11024117395Skan      {
11025117395Skan        /* Align stack so SPE GPR save area is aligned on a
11026117395Skan           double-word boundary.  */
11027117395Skan        if (info_ptr->spe_gp_size != 0)
11028117395Skan          info_ptr->spe_padding_size
11029117395Skan            = 8 - (-info_ptr->cr_save_offset % 8);
11030117395Skan        else
11031117395Skan          info_ptr->spe_padding_size = 0;
11032117395Skan
11033117395Skan        info_ptr->spe_gp_save_offset
11034117395Skan          = info_ptr->cr_save_offset
11035117395Skan          - info_ptr->spe_padding_size
11036117395Skan          - info_ptr->spe_gp_size;
11037117395Skan
11038117395Skan        /* Adjust for SPE case.  */
11039117395Skan        info_ptr->toc_save_offset
11040117395Skan          = info_ptr->spe_gp_save_offset - info_ptr->toc_size;
11041117395Skan      }
11042117395Skan      else if (TARGET_ALTIVEC_ABI)
1104390075Sobrien	{
1104490075Sobrien	  info_ptr->vrsave_save_offset
1104590075Sobrien	    = info_ptr->cr_save_offset - info_ptr->vrsave_size;
1104690075Sobrien
1104790075Sobrien	  /* Align stack so vector save area is on a quadword boundary.  */
1104890075Sobrien	  if (info_ptr->altivec_size != 0)
1104990075Sobrien	    info_ptr->altivec_padding_size
1105090075Sobrien	      = 16 - (-info_ptr->vrsave_save_offset % 16);
1105190075Sobrien	  else
1105290075Sobrien	    info_ptr->altivec_padding_size = 0;
1105390075Sobrien
1105490075Sobrien	  info_ptr->altivec_save_offset
1105590075Sobrien	    = info_ptr->vrsave_save_offset
1105690075Sobrien	    - info_ptr->altivec_padding_size
1105790075Sobrien	    - info_ptr->altivec_size;
1105890075Sobrien
1105990075Sobrien	  /* Adjust for AltiVec case.  */
1106090075Sobrien	  info_ptr->toc_save_offset
1106190075Sobrien	    = info_ptr->altivec_save_offset - info_ptr->toc_size;
1106290075Sobrien	}
1106390075Sobrien      else
1106490075Sobrien	info_ptr->toc_save_offset  = info_ptr->cr_save_offset - info_ptr->toc_size;
1106590075Sobrien      info_ptr->ehrd_offset      = info_ptr->toc_save_offset - ehrd_size;
1106690075Sobrien      info_ptr->lr_save_offset   = reg_size;
1106790075Sobrien      break;
1106890075Sobrien    }
1106990075Sobrien
11070146895Skan  save_align = (TARGET_ALTIVEC_ABI || DEFAULT_ABI == ABI_DARWIN) ? 16 : 8;
1107190075Sobrien  info_ptr->save_size    = RS6000_ALIGN (info_ptr->fp_size
1107290075Sobrien					 + info_ptr->gp_size
1107390075Sobrien					 + info_ptr->altivec_size
1107490075Sobrien					 + info_ptr->altivec_padding_size
11075117395Skan					 + info_ptr->spe_gp_size
11076117395Skan					 + info_ptr->spe_padding_size
1107790075Sobrien					 + ehrd_size
1107890075Sobrien					 + info_ptr->cr_size
1107990075Sobrien					 + info_ptr->lr_size
11080132718Skan					 + info_ptr->vrsave_size
1108190075Sobrien					 + info_ptr->toc_size,
11082146895Skan					 save_align);
1108390075Sobrien
11084132718Skan  non_fixed_size	 = (info_ptr->vars_size
1108590075Sobrien			    + info_ptr->parm_size
1108690075Sobrien			    + info_ptr->save_size
11087132718Skan			    + info_ptr->varargs_size);
1108890075Sobrien
11089132718Skan  info_ptr->total_size = RS6000_ALIGN (non_fixed_size + info_ptr->fixed_size,
11090132718Skan				       ABI_STACK_BOUNDARY / BITS_PER_UNIT);
1109190075Sobrien
1109290075Sobrien  /* Determine if we need to allocate any stack frame:
1109390075Sobrien
1109490075Sobrien     For AIX we need to push the stack if a frame pointer is needed
1109590075Sobrien     (because the stack might be dynamically adjusted), if we are
1109690075Sobrien     debugging, if we make calls, or if the sum of fp_save, gp_save,
1109790075Sobrien     and local variables are more than the space needed to save all
1109890075Sobrien     non-volatile registers: 32-bit: 18*8 + 19*4 = 220 or 64-bit: 18*8
1109990075Sobrien     + 18*8 = 288 (GPR13 reserved).
1110090075Sobrien
1110190075Sobrien     For V.4 we don't have the stack cushion that AIX uses, but assume
1110290075Sobrien     that the debugger can handle stackless frames.  */
1110390075Sobrien
1110490075Sobrien  if (info_ptr->calls_p)
1110590075Sobrien    info_ptr->push_p = 1;
1110690075Sobrien
11107132718Skan  else if (DEFAULT_ABI == ABI_V4)
11108132718Skan    info_ptr->push_p = non_fixed_size != 0;
1110990075Sobrien
11110132718Skan  else if (frame_pointer_needed)
11111132718Skan    info_ptr->push_p = 1;
11112132718Skan
11113132718Skan  else if (TARGET_XCOFF && write_symbols != NO_DEBUG)
11114132718Skan    info_ptr->push_p = 1;
11115132718Skan
1111690075Sobrien  else
11117132718Skan    info_ptr->push_p = non_fixed_size > (TARGET_32BIT ? 220 : 288);
1111890075Sobrien
1111990075Sobrien  /* Zero offsets if we're not saving those registers.  */
1112090075Sobrien  if (info_ptr->fp_size == 0)
1112190075Sobrien    info_ptr->fp_save_offset = 0;
1112290075Sobrien
1112390075Sobrien  if (info_ptr->gp_size == 0)
1112490075Sobrien    info_ptr->gp_save_offset = 0;
1112590075Sobrien
1112690075Sobrien  if (! TARGET_ALTIVEC_ABI || info_ptr->altivec_size == 0)
1112790075Sobrien    info_ptr->altivec_save_offset = 0;
1112890075Sobrien
1112990075Sobrien  if (! TARGET_ALTIVEC_ABI || info_ptr->vrsave_mask == 0)
1113090075Sobrien    info_ptr->vrsave_save_offset = 0;
1113190075Sobrien
11132132718Skan  if (! TARGET_SPE_ABI
11133132718Skan      || info_ptr->spe_64bit_regs_used == 0
11134132718Skan      || info_ptr->spe_gp_size == 0)
11135117395Skan    info_ptr->spe_gp_save_offset = 0;
11136117395Skan
1113790075Sobrien  if (! info_ptr->lr_save_p)
1113890075Sobrien    info_ptr->lr_save_offset = 0;
1113990075Sobrien
1114090075Sobrien  if (! info_ptr->cr_save_p)
1114190075Sobrien    info_ptr->cr_save_offset = 0;
1114290075Sobrien
1114390075Sobrien  if (! info_ptr->toc_save_p)
1114490075Sobrien    info_ptr->toc_save_offset = 0;
1114590075Sobrien
1114690075Sobrien  return info_ptr;
1114790075Sobrien}
1114890075Sobrien
11149132718Skan/* Return true if the current function uses any GPRs in 64-bit SIMD
11150132718Skan   mode.  */
11151132718Skan
11152132718Skanstatic bool
11153132718Skanspe_func_has_64bit_regs_p (void)
1115490075Sobrien{
11155132718Skan  rtx insns, insn;
11156132718Skan
11157132718Skan  /* Functions that save and restore all the call-saved registers will
11158132718Skan     need to save/restore the registers in 64-bits.  */
11159132718Skan  if (current_function_calls_eh_return
11160132718Skan      || current_function_calls_setjmp
11161132718Skan      || current_function_has_nonlocal_goto)
11162132718Skan    return true;
11163132718Skan
11164132718Skan  insns = get_insns ();
11165132718Skan
11166132718Skan  for (insn = NEXT_INSN (insns); insn != NULL_RTX; insn = NEXT_INSN (insn))
11167132718Skan    {
11168132718Skan      if (INSN_P (insn))
11169132718Skan	{
11170132718Skan	  rtx i;
11171132718Skan
11172132718Skan	  i = PATTERN (insn);
11173132718Skan	  if (GET_CODE (i) == SET
11174132718Skan	      && SPE_VECTOR_MODE (GET_MODE (SET_SRC (i))))
11175132718Skan	    return true;
11176132718Skan	}
11177132718Skan    }
11178132718Skan
11179132718Skan  return false;
11180132718Skan}
11181132718Skan
11182132718Skanstatic void
11183132718Skandebug_stack_info (rs6000_stack_t *info)
11184132718Skan{
1118590075Sobrien  const char *abi_string;
1118690075Sobrien
1118790075Sobrien  if (! info)
1118890075Sobrien    info = rs6000_stack_info ();
1118990075Sobrien
1119090075Sobrien  fprintf (stderr, "\nStack information for function %s:\n",
1119190075Sobrien	   ((current_function_decl && DECL_NAME (current_function_decl))
1119290075Sobrien	    ? IDENTIFIER_POINTER (DECL_NAME (current_function_decl))
1119390075Sobrien	    : "<unknown>"));
1119490075Sobrien
1119590075Sobrien  switch (info->abi)
1119690075Sobrien    {
1119790075Sobrien    default:		 abi_string = "Unknown";	break;
1119890075Sobrien    case ABI_NONE:	 abi_string = "NONE";		break;
11199132718Skan    case ABI_AIX:	 abi_string = "AIX";		break;
1120090075Sobrien    case ABI_DARWIN:	 abi_string = "Darwin";		break;
1120190075Sobrien    case ABI_V4:	 abi_string = "V.4";		break;
1120290075Sobrien    }
1120390075Sobrien
1120490075Sobrien  fprintf (stderr, "\tABI                 = %5s\n", abi_string);
1120590075Sobrien
1120690075Sobrien  if (TARGET_ALTIVEC_ABI)
1120790075Sobrien    fprintf (stderr, "\tALTIVEC ABI extensions enabled.\n");
1120890075Sobrien
11209117395Skan  if (TARGET_SPE_ABI)
11210117395Skan    fprintf (stderr, "\tSPE ABI extensions enabled.\n");
11211117395Skan
1121290075Sobrien  if (info->first_gp_reg_save != 32)
1121390075Sobrien    fprintf (stderr, "\tfirst_gp_reg_save   = %5d\n", info->first_gp_reg_save);
1121490075Sobrien
1121590075Sobrien  if (info->first_fp_reg_save != 64)
1121690075Sobrien    fprintf (stderr, "\tfirst_fp_reg_save   = %5d\n", info->first_fp_reg_save);
1121790075Sobrien
1121890075Sobrien  if (info->first_altivec_reg_save <= LAST_ALTIVEC_REGNO)
1121990075Sobrien    fprintf (stderr, "\tfirst_altivec_reg_save = %5d\n",
1122090075Sobrien	     info->first_altivec_reg_save);
1122190075Sobrien
1122290075Sobrien  if (info->lr_save_p)
1122390075Sobrien    fprintf (stderr, "\tlr_save_p           = %5d\n", info->lr_save_p);
1122490075Sobrien
1122590075Sobrien  if (info->cr_save_p)
1122690075Sobrien    fprintf (stderr, "\tcr_save_p           = %5d\n", info->cr_save_p);
1122790075Sobrien
1122890075Sobrien  if (info->toc_save_p)
1122990075Sobrien    fprintf (stderr, "\ttoc_save_p          = %5d\n", info->toc_save_p);
1123090075Sobrien
1123190075Sobrien  if (info->vrsave_mask)
1123290075Sobrien    fprintf (stderr, "\tvrsave_mask         = 0x%x\n", info->vrsave_mask);
1123390075Sobrien
1123490075Sobrien  if (info->push_p)
1123590075Sobrien    fprintf (stderr, "\tpush_p              = %5d\n", info->push_p);
1123690075Sobrien
1123790075Sobrien  if (info->calls_p)
1123890075Sobrien    fprintf (stderr, "\tcalls_p             = %5d\n", info->calls_p);
1123990075Sobrien
1124090075Sobrien  if (info->gp_save_offset)
1124190075Sobrien    fprintf (stderr, "\tgp_save_offset      = %5d\n", info->gp_save_offset);
1124290075Sobrien
1124390075Sobrien  if (info->fp_save_offset)
1124490075Sobrien    fprintf (stderr, "\tfp_save_offset      = %5d\n", info->fp_save_offset);
1124590075Sobrien
1124690075Sobrien  if (info->altivec_save_offset)
1124790075Sobrien    fprintf (stderr, "\taltivec_save_offset = %5d\n",
1124890075Sobrien	     info->altivec_save_offset);
1124990075Sobrien
11250117395Skan  if (info->spe_gp_save_offset)
11251117395Skan    fprintf (stderr, "\tspe_gp_save_offset  = %5d\n",
11252117395Skan	     info->spe_gp_save_offset);
11253117395Skan
1125490075Sobrien  if (info->vrsave_save_offset)
1125590075Sobrien    fprintf (stderr, "\tvrsave_save_offset  = %5d\n",
1125690075Sobrien	     info->vrsave_save_offset);
1125790075Sobrien
1125890075Sobrien  if (info->lr_save_offset)
1125990075Sobrien    fprintf (stderr, "\tlr_save_offset      = %5d\n", info->lr_save_offset);
1126090075Sobrien
1126190075Sobrien  if (info->cr_save_offset)
1126290075Sobrien    fprintf (stderr, "\tcr_save_offset      = %5d\n", info->cr_save_offset);
1126390075Sobrien
1126490075Sobrien  if (info->toc_save_offset)
1126590075Sobrien    fprintf (stderr, "\ttoc_save_offset     = %5d\n", info->toc_save_offset);
1126690075Sobrien
1126790075Sobrien  if (info->varargs_save_offset)
1126890075Sobrien    fprintf (stderr, "\tvarargs_save_offset = %5d\n", info->varargs_save_offset);
1126990075Sobrien
1127090075Sobrien  if (info->total_size)
11271132718Skan    fprintf (stderr, "\ttotal_size          = "HOST_WIDE_INT_PRINT_DEC"\n",
11272132718Skan	     info->total_size);
1127390075Sobrien
1127490075Sobrien  if (info->varargs_size)
1127590075Sobrien    fprintf (stderr, "\tvarargs_size        = %5d\n", info->varargs_size);
1127690075Sobrien
1127790075Sobrien  if (info->vars_size)
11278132718Skan    fprintf (stderr, "\tvars_size           = "HOST_WIDE_INT_PRINT_DEC"\n",
11279132718Skan	     info->vars_size);
1128090075Sobrien
1128190075Sobrien  if (info->parm_size)
1128290075Sobrien    fprintf (stderr, "\tparm_size           = %5d\n", info->parm_size);
1128390075Sobrien
1128490075Sobrien  if (info->fixed_size)
1128590075Sobrien    fprintf (stderr, "\tfixed_size          = %5d\n", info->fixed_size);
1128690075Sobrien
1128790075Sobrien  if (info->gp_size)
1128890075Sobrien    fprintf (stderr, "\tgp_size             = %5d\n", info->gp_size);
1128990075Sobrien
11290117395Skan  if (info->spe_gp_size)
11291117395Skan    fprintf (stderr, "\tspe_gp_size         = %5d\n", info->spe_gp_size);
11292117395Skan
1129390075Sobrien  if (info->fp_size)
1129490075Sobrien    fprintf (stderr, "\tfp_size             = %5d\n", info->fp_size);
1129590075Sobrien
1129690075Sobrien  if (info->altivec_size)
1129790075Sobrien    fprintf (stderr, "\taltivec_size        = %5d\n", info->altivec_size);
1129890075Sobrien
1129990075Sobrien  if (info->vrsave_size)
1130090075Sobrien    fprintf (stderr, "\tvrsave_size         = %5d\n", info->vrsave_size);
1130190075Sobrien
1130290075Sobrien  if (info->altivec_padding_size)
1130390075Sobrien    fprintf (stderr, "\taltivec_padding_size= %5d\n",
1130490075Sobrien	     info->altivec_padding_size);
1130590075Sobrien
11306117395Skan  if (info->spe_padding_size)
11307117395Skan    fprintf (stderr, "\tspe_padding_size    = %5d\n",
11308117395Skan	     info->spe_padding_size);
11309117395Skan
1131090075Sobrien  if (info->lr_size)
1131190075Sobrien    fprintf (stderr, "\tlr_size             = %5d\n", info->lr_size);
1131290075Sobrien
1131390075Sobrien  if (info->cr_size)
1131490075Sobrien    fprintf (stderr, "\tcr_size             = %5d\n", info->cr_size);
1131590075Sobrien
1131690075Sobrien  if (info->toc_size)
1131790075Sobrien    fprintf (stderr, "\ttoc_size            = %5d\n", info->toc_size);
1131890075Sobrien
1131990075Sobrien  if (info->save_size)
1132090075Sobrien    fprintf (stderr, "\tsave_size           = %5d\n", info->save_size);
1132190075Sobrien
1132290075Sobrien  if (info->reg_size != 4)
1132390075Sobrien    fprintf (stderr, "\treg_size            = %5d\n", info->reg_size);
1132490075Sobrien
1132590075Sobrien  fprintf (stderr, "\n");
1132690075Sobrien}
1132790075Sobrien
1132890075Sobrienrtx
11329132718Skanrs6000_return_addr (int count, rtx frame)
1133090075Sobrien{
1133190075Sobrien  /* Currently we don't optimize very well between prolog and body
1133290075Sobrien     code and for PIC code the code can be actually quite bad, so
1133390075Sobrien     don't try to be too clever here.  */
11334132718Skan  if (count != 0 || (DEFAULT_ABI != ABI_AIX && flag_pic))
1133590075Sobrien    {
1133690075Sobrien      cfun->machine->ra_needs_full_frame = 1;
1133790075Sobrien
1133890075Sobrien      return
1133990075Sobrien	gen_rtx_MEM
1134090075Sobrien	  (Pmode,
1134190075Sobrien	   memory_address
1134290075Sobrien	   (Pmode,
1134390075Sobrien	    plus_constant (copy_to_reg
1134490075Sobrien			   (gen_rtx_MEM (Pmode,
1134590075Sobrien					 memory_address (Pmode, frame))),
1134690075Sobrien			   RETURN_ADDRESS_OFFSET)));
1134790075Sobrien    }
1134890075Sobrien
11349132718Skan  cfun->machine->ra_need_lr = 1;
1135090075Sobrien  return get_hard_reg_initial_val (Pmode, LINK_REGISTER_REGNUM);
1135190075Sobrien}
1135290075Sobrien
11353117395Skan/* Say whether a function is a candidate for sibcall handling or not.
11354117395Skan   We do not allow indirect calls to be optimized into sibling calls.
11355117395Skan   Also, we can't do it if there are any vector parameters; there's
11356117395Skan   nowhere to put the VRsave code so it works; note that functions with
11357117395Skan   vector parameters are required to have a prototype, so the argument
11358117395Skan   type info must be available here.  (The tail recursion case can work
11359117395Skan   with vector parameters, but there's no way to distinguish here.) */
11360132718Skanstatic bool
11361132718Skanrs6000_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
11362117395Skan{
11363117395Skan  tree type;
11364132718Skan  if (decl)
11365117395Skan    {
11366117395Skan      if (TARGET_ALTIVEC_VRSAVE)
11367117395Skan        {
11368132718Skan	  for (type = TYPE_ARG_TYPES (TREE_TYPE (decl));
11369117395Skan	       type; type = TREE_CHAIN (type))
11370117395Skan	    {
11371117395Skan	      if (TREE_CODE (TREE_VALUE (type)) == VECTOR_TYPE)
11372132718Skan		return false;
11373117395Skan	    }
11374117395Skan        }
11375117395Skan      if (DEFAULT_ABI == ABI_DARWIN
11376132718Skan	  || (*targetm.binds_local_p) (decl))
11377117395Skan	{
11378132718Skan	  tree attr_list = TYPE_ATTRIBUTES (TREE_TYPE (decl));
11379117395Skan
11380117395Skan	  if (!lookup_attribute ("longcall", attr_list)
11381117395Skan	      || lookup_attribute ("shortcall", attr_list))
11382132718Skan	    return true;
11383117395Skan	}
11384117395Skan    }
11385132718Skan  return false;
11386117395Skan}
11387117395Skan
1138890075Sobrienstatic int
11389132718Skanrs6000_ra_ever_killed (void)
1139090075Sobrien{
1139190075Sobrien  rtx top;
11392117395Skan  rtx reg;
11393117395Skan  rtx insn;
1139490075Sobrien
11395132718Skan  if (current_function_is_thunk)
1139690075Sobrien    return 0;
1139790075Sobrien
11398117395Skan  /* regs_ever_live has LR marked as used if any sibcalls are present,
11399117395Skan     but this should not force saving and restoring in the
11400117395Skan     pro/epilogue.  Likewise, reg_set_between_p thinks a sibcall
11401132718Skan     clobbers LR, so that is inappropriate.  */
11402117395Skan
11403117395Skan  /* Also, the prologue can generate a store into LR that
11404117395Skan     doesn't really count, like this:
11405117395Skan
11406117395Skan        move LR->R0
11407117395Skan        bcl to set PIC register
11408117395Skan        move LR->R31
11409117395Skan        move R0->LR
11410117395Skan
11411117395Skan     When we're called from the epilogue, we need to avoid counting
11412117395Skan     this as a store.  */
11413117395Skan
1141490075Sobrien  push_topmost_sequence ();
1141590075Sobrien  top = get_insns ();
1141690075Sobrien  pop_topmost_sequence ();
11417117395Skan  reg = gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM);
1141890075Sobrien
11419117395Skan  for (insn = NEXT_INSN (top); insn != NULL_RTX; insn = NEXT_INSN (insn))
11420117395Skan    {
11421117395Skan      if (INSN_P (insn))
11422117395Skan	{
11423117395Skan	  if (FIND_REG_INC_NOTE (insn, reg))
11424117395Skan	    return 1;
11425117395Skan	  else if (GET_CODE (insn) == CALL_INSN
11426117395Skan		   && !SIBLING_CALL_P (insn))
11427117395Skan	    return 1;
11428117395Skan	  else if (set_of (reg, insn) != NULL_RTX
11429117395Skan		   && !prologue_epilogue_contains (insn))
11430117395Skan	    return 1;
11431117395Skan    	}
11432117395Skan    }
11433117395Skan  return 0;
1143490075Sobrien}
1143590075Sobrien
1143690075Sobrien/* Add a REG_MAYBE_DEAD note to the insn.  */
1143790075Sobrienstatic void
11438132718Skanrs6000_maybe_dead (rtx insn)
1143990075Sobrien{
1144090075Sobrien  REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD,
1144190075Sobrien					const0_rtx,
1144290075Sobrien					REG_NOTES (insn));
1144390075Sobrien}
1144490075Sobrien
1144590075Sobrien/* Emit instructions needed to load the TOC register.
1144690075Sobrien   This is only needed when TARGET_TOC, TARGET_MINIMAL_TOC, and there is
1144790075Sobrien   a constant pool; or for SVR4 -fpic.  */
1144890075Sobrien
1144990075Sobrienvoid
11450132718Skanrs6000_emit_load_toc_table (int fromprolog)
1145190075Sobrien{
11452117395Skan  rtx dest, insn;
1145396263Sobrien  dest = gen_rtx_REG (Pmode, RS6000_PIC_OFFSET_TABLE_REGNUM);
1145490075Sobrien
11455103445Skan  if (TARGET_ELF && DEFAULT_ABI == ABI_V4 && flag_pic == 1)
1145690075Sobrien    {
11457103445Skan      rtx temp = (fromprolog
11458103445Skan		  ? gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM)
11459103445Skan		  : gen_reg_rtx (Pmode));
11460117395Skan      insn = emit_insn (gen_load_toc_v4_pic_si (temp));
11461117395Skan      if (fromprolog)
11462117395Skan	rs6000_maybe_dead (insn);
11463117395Skan      insn = emit_move_insn (dest, temp);
11464117395Skan      if (fromprolog)
11465117395Skan	rs6000_maybe_dead (insn);
11466103445Skan    }
11467103445Skan  else if (TARGET_ELF && DEFAULT_ABI != ABI_AIX && flag_pic == 2)
11468103445Skan    {
11469103445Skan      char buf[30];
11470103445Skan      rtx tempLR = (fromprolog
11471103445Skan		    ? gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM)
11472103445Skan		    : gen_reg_rtx (Pmode));
11473103445Skan      rtx temp0 = (fromprolog
11474103445Skan		   ? gen_rtx_REG (Pmode, 0)
11475103445Skan		   : gen_reg_rtx (Pmode));
11476103445Skan
11477103445Skan      /* possibly create the toc section */
11478103445Skan      if (! toc_initialized)
1147990075Sobrien	{
11480103445Skan	  toc_section ();
11481103445Skan	  function_section (current_function_decl);
1148290075Sobrien	}
1148390075Sobrien
11484103445Skan      if (fromprolog)
11485103445Skan	{
11486146895Skan	  rtx symF, symL;
1148790075Sobrien
11488103445Skan	  ASM_GENERATE_INTERNAL_LABEL (buf, "LCF", rs6000_pic_labelno);
11489103445Skan	  symF = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
1149090075Sobrien
11491103445Skan	  ASM_GENERATE_INTERNAL_LABEL (buf, "LCL", rs6000_pic_labelno);
11492103445Skan	  symL = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
1149390075Sobrien
11494103445Skan	  rs6000_maybe_dead (emit_insn (gen_load_toc_v4_PIC_1 (tempLR,
11495103445Skan							       symF)));
11496103445Skan	  rs6000_maybe_dead (emit_move_insn (dest, tempLR));
11497103445Skan	  rs6000_maybe_dead (emit_insn (gen_load_toc_v4_PIC_2 (temp0, dest,
11498103445Skan							       symL,
11499103445Skan							       symF)));
11500103445Skan	}
11501103445Skan      else
11502103445Skan	{
11503103445Skan	  rtx tocsym;
1150490075Sobrien
11505103445Skan	  tocsym = gen_rtx_SYMBOL_REF (Pmode, toc_label_name);
11506146895Skan	  emit_insn (gen_load_toc_v4_PIC_1b (tempLR, tocsym));
11507117395Skan	  emit_move_insn (dest, tempLR);
11508117395Skan	  emit_move_insn (temp0, gen_rtx_MEM (Pmode, dest));
1150990075Sobrien	}
11510117395Skan      insn = emit_insn (gen_addsi3 (dest, temp0, dest));
11511117395Skan      if (fromprolog)
11512117395Skan	rs6000_maybe_dead (insn);
1151390075Sobrien    }
11514103445Skan  else if (TARGET_ELF && !TARGET_AIX && flag_pic == 0 && TARGET_MINIMAL_TOC)
1151590075Sobrien    {
11516103445Skan      /* This is for AIX code running in non-PIC ELF32.  */
11517103445Skan      char buf[30];
11518103445Skan      rtx realsym;
11519103445Skan      ASM_GENERATE_INTERNAL_LABEL (buf, "LCTOC", 1);
11520103445Skan      realsym = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
11521103445Skan
11522117395Skan      insn = emit_insn (gen_elf_high (dest, realsym));
11523117395Skan      if (fromprolog)
11524117395Skan	rs6000_maybe_dead (insn);
11525117395Skan      insn = emit_insn (gen_elf_low (dest, dest, realsym));
11526117395Skan      if (fromprolog)
11527117395Skan	rs6000_maybe_dead (insn);
11528103445Skan    }
11529103445Skan  else if (DEFAULT_ABI == ABI_AIX)
11530103445Skan    {
1153190075Sobrien      if (TARGET_32BIT)
11532117395Skan	insn = emit_insn (gen_load_toc_aix_si (dest));
1153390075Sobrien      else
11534117395Skan	insn = emit_insn (gen_load_toc_aix_di (dest));
11535117395Skan      if (fromprolog)
11536117395Skan	rs6000_maybe_dead (insn);
1153790075Sobrien    }
11538103445Skan  else
11539103445Skan    abort ();
1154090075Sobrien}
1154190075Sobrien
11542132718Skan/* Emit instructions to restore the link register after determining where
11543132718Skan   its value has been stored.  */
11544132718Skan
11545132718Skanvoid
11546132718Skanrs6000_emit_eh_reg_restore (rtx source, rtx scratch)
11547132718Skan{
11548132718Skan  rs6000_stack_t *info = rs6000_stack_info ();
11549132718Skan  rtx operands[2];
11550132718Skan
11551132718Skan  operands[0] = source;
11552132718Skan  operands[1] = scratch;
11553132718Skan
11554132718Skan  if (info->lr_save_p)
11555132718Skan    {
11556132718Skan      rtx frame_rtx = stack_pointer_rtx;
11557132718Skan      HOST_WIDE_INT sp_offset = 0;
11558132718Skan      rtx tmp;
11559132718Skan
11560132718Skan      if (frame_pointer_needed
11561132718Skan	  || current_function_calls_alloca
11562132718Skan	  || info->total_size > 32767)
11563132718Skan	{
11564132718Skan	  emit_move_insn (operands[1], gen_rtx_MEM (Pmode, frame_rtx));
11565132718Skan	  frame_rtx = operands[1];
11566132718Skan	}
11567132718Skan      else if (info->push_p)
11568132718Skan	sp_offset = info->total_size;
11569132718Skan
11570132718Skan      tmp = plus_constant (frame_rtx, info->lr_save_offset + sp_offset);
11571132718Skan      tmp = gen_rtx_MEM (Pmode, tmp);
11572132718Skan      emit_move_insn (tmp, operands[0]);
11573132718Skan    }
11574132718Skan  else
11575132718Skan    emit_move_insn (gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM), operands[0]);
11576132718Skan}
11577132718Skan
11578132718Skanstatic GTY(()) int set = -1;
11579132718Skan
1158090075Sobrienint
11581132718Skanget_TOC_alias_set (void)
1158290075Sobrien{
11583132718Skan  if (set == -1)
11584132718Skan    set = new_alias_set ();
11585132718Skan  return set;
1158690075Sobrien}
1158790075Sobrien
11588132718Skan/* This returns nonzero if the current function uses the TOC.  This is
11589132718Skan   determined by the presence of (use (unspec ... UNSPEC_TOC)), which
11590132718Skan   is generated by the ABI_V4 load_toc_* patterns.  */
11591132718Skan#if TARGET_ELF
11592132718Skanstatic int
11593132718Skanuses_TOC (void)
1159490075Sobrien{
11595132718Skan  rtx insn;
1159690075Sobrien
11597132718Skan  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
11598132718Skan    if (INSN_P (insn))
11599132718Skan      {
11600132718Skan	rtx pat = PATTERN (insn);
11601132718Skan	int i;
1160290075Sobrien
11603132718Skan	if (GET_CODE (pat) == PARALLEL)
11604132718Skan	  for (i = 0; i < XVECLEN (pat, 0); i++)
11605132718Skan	    {
11606132718Skan	      rtx sub = XVECEXP (pat, 0, i);
11607132718Skan	      if (GET_CODE (sub) == USE)
11608132718Skan		{
11609132718Skan		  sub = XEXP (sub, 0);
11610132718Skan		  if (GET_CODE (sub) == UNSPEC
11611132718Skan		      && XINT (sub, 1) == UNSPEC_TOC)
11612132718Skan		    return 1;
11613132718Skan		}
11614132718Skan	    }
11615132718Skan      }
11616132718Skan  return 0;
1161790075Sobrien}
11618132718Skan#endif
1161990075Sobrien
1162090075Sobrienrtx
11621132718Skancreate_TOC_reference (rtx symbol)
1162290075Sobrien{
1162390075Sobrien  return gen_rtx_PLUS (Pmode,
1162490075Sobrien	   gen_rtx_REG (Pmode, TOC_REGISTER),
1162590075Sobrien	     gen_rtx_CONST (Pmode,
1162690075Sobrien	       gen_rtx_MINUS (Pmode, symbol,
1162790075Sobrien		 gen_rtx_SYMBOL_REF (Pmode, toc_label_name))));
1162890075Sobrien}
1162990075Sobrien
11630132718Skan/* If _Unwind_* has been called from within the same module,
11631132718Skan   toc register is not guaranteed to be saved to 40(1) on function
11632132718Skan   entry.  Save it there in that case.  */
1163390075Sobrien
1163490075Sobrienvoid
11635132718Skanrs6000_aix_emit_builtin_unwind_init (void)
1163690075Sobrien{
1163790075Sobrien  rtx mem;
1163890075Sobrien  rtx stack_top = gen_reg_rtx (Pmode);
1163990075Sobrien  rtx opcode_addr = gen_reg_rtx (Pmode);
11640132718Skan  rtx opcode = gen_reg_rtx (SImode);
11641132718Skan  rtx tocompare = gen_reg_rtx (SImode);
11642132718Skan  rtx no_toc_save_needed = gen_label_rtx ();
1164390075Sobrien
1164490075Sobrien  mem = gen_rtx_MEM (Pmode, hard_frame_pointer_rtx);
1164590075Sobrien  emit_move_insn (stack_top, mem);
1164690075Sobrien
11647132718Skan  mem = gen_rtx_MEM (Pmode,
11648132718Skan		     gen_rtx_PLUS (Pmode, stack_top,
1164990075Sobrien				   GEN_INT (2 * GET_MODE_SIZE (Pmode))));
1165090075Sobrien  emit_move_insn (opcode_addr, mem);
11651132718Skan  emit_move_insn (opcode, gen_rtx_MEM (SImode, opcode_addr));
11652132718Skan  emit_move_insn (tocompare, gen_int_mode (TARGET_32BIT ? 0x80410014
11653117395Skan					   : 0xE8410028, SImode));
1165490075Sobrien
11655132718Skan  do_compare_rtx_and_jump (opcode, tocompare, EQ, 1,
1165690075Sobrien			   SImode, NULL_RTX, NULL_RTX,
11657132718Skan			   no_toc_save_needed);
11658132718Skan
11659132718Skan  mem = gen_rtx_MEM (Pmode,
11660132718Skan		     gen_rtx_PLUS (Pmode, stack_top,
1166190075Sobrien				   GEN_INT (5 * GET_MODE_SIZE (Pmode))));
11662132718Skan  emit_move_insn (mem, gen_rtx_REG (Pmode, 2));
11663132718Skan  emit_label (no_toc_save_needed);
1166490075Sobrien}
1166590075Sobrien
1166690075Sobrien/* This ties together stack memory (MEM with an alias set of
1166790075Sobrien   rs6000_sr_alias_set) and the change to the stack pointer.  */
1166890075Sobrien
1166990075Sobrienstatic void
11670132718Skanrs6000_emit_stack_tie (void)
1167190075Sobrien{
1167290075Sobrien  rtx mem = gen_rtx_MEM (BLKmode, gen_rtx_REG (Pmode, STACK_POINTER_REGNUM));
1167390075Sobrien
1167490075Sobrien  set_mem_alias_set (mem, rs6000_sr_alias_set);
1167590075Sobrien  emit_insn (gen_stack_tie (mem));
1167690075Sobrien}
1167790075Sobrien
1167890075Sobrien/* Emit the correct code for allocating stack space, as insns.
1167990075Sobrien   If COPY_R12, make sure a copy of the old frame is left in r12.
1168090075Sobrien   The generated code may use hard register 0 as a temporary.  */
1168190075Sobrien
1168290075Sobrienstatic void
11683132718Skanrs6000_emit_allocate_stack (HOST_WIDE_INT size, int copy_r12)
1168490075Sobrien{
1168590075Sobrien  rtx insn;
1168690075Sobrien  rtx stack_reg = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
1168790075Sobrien  rtx tmp_reg = gen_rtx_REG (Pmode, 0);
1168890075Sobrien  rtx todec = GEN_INT (-size);
1168990075Sobrien
1169090075Sobrien  if (current_function_limit_stack)
1169190075Sobrien    {
1169290075Sobrien      if (REG_P (stack_limit_rtx)
1169390075Sobrien	  && REGNO (stack_limit_rtx) > 1
1169490075Sobrien	  && REGNO (stack_limit_rtx) <= 31)
1169590075Sobrien	{
11696132718Skan	  emit_insn (TARGET_32BIT
1169790075Sobrien		     ? gen_addsi3 (tmp_reg,
1169890075Sobrien				   stack_limit_rtx,
1169990075Sobrien				   GEN_INT (size))
1170090075Sobrien		     : gen_adddi3 (tmp_reg,
1170190075Sobrien				   stack_limit_rtx,
1170290075Sobrien				   GEN_INT (size)));
11703132718Skan
1170490075Sobrien	  emit_insn (gen_cond_trap (LTU, stack_reg, tmp_reg,
1170590075Sobrien				    const0_rtx));
1170690075Sobrien	}
1170790075Sobrien      else if (GET_CODE (stack_limit_rtx) == SYMBOL_REF
1170890075Sobrien	       && TARGET_32BIT
1170990075Sobrien	       && DEFAULT_ABI == ABI_V4)
1171090075Sobrien	{
1171190075Sobrien	  rtx toload = gen_rtx_CONST (VOIDmode,
1171290075Sobrien				      gen_rtx_PLUS (Pmode,
1171390075Sobrien						    stack_limit_rtx,
1171490075Sobrien						    GEN_INT (size)));
11715132718Skan
1171690075Sobrien	  emit_insn (gen_elf_high (tmp_reg, toload));
1171790075Sobrien	  emit_insn (gen_elf_low (tmp_reg, tmp_reg, toload));
1171890075Sobrien	  emit_insn (gen_cond_trap (LTU, stack_reg, tmp_reg,
1171990075Sobrien				    const0_rtx));
1172090075Sobrien	}
1172190075Sobrien      else
1172290075Sobrien	warning ("stack limit expression is not supported");
1172390075Sobrien    }
1172490075Sobrien
1172590075Sobrien  if (copy_r12 || ! TARGET_UPDATE)
1172690075Sobrien    emit_move_insn (gen_rtx_REG (Pmode, 12), stack_reg);
1172790075Sobrien
1172890075Sobrien  if (TARGET_UPDATE)
1172990075Sobrien    {
1173090075Sobrien      if (size > 32767)
1173190075Sobrien	{
1173290075Sobrien	  /* Need a note here so that try_split doesn't get confused.  */
1173390075Sobrien	  if (get_last_insn() == NULL_RTX)
11734132718Skan	    emit_note (NOTE_INSN_DELETED);
1173590075Sobrien	  insn = emit_move_insn (tmp_reg, todec);
1173690075Sobrien	  try_split (PATTERN (insn), insn, 0);
1173790075Sobrien	  todec = tmp_reg;
1173890075Sobrien	}
11739132718Skan
11740132718Skan      insn = emit_insn (TARGET_32BIT
11741132718Skan			? gen_movsi_update (stack_reg, stack_reg,
11742132718Skan					    todec, stack_reg)
11743132718Skan			: gen_movdi_update (stack_reg, stack_reg,
1174490075Sobrien					    todec, stack_reg));
1174590075Sobrien    }
1174690075Sobrien  else
1174790075Sobrien    {
11748132718Skan      insn = emit_insn (TARGET_32BIT
11749132718Skan			? gen_addsi3 (stack_reg, stack_reg, todec)
11750132718Skan			: gen_adddi3 (stack_reg, stack_reg, todec));
1175190075Sobrien      emit_move_insn (gen_rtx_MEM (Pmode, stack_reg),
1175290075Sobrien		      gen_rtx_REG (Pmode, 12));
1175390075Sobrien    }
11754132718Skan
1175590075Sobrien  RTX_FRAME_RELATED_P (insn) = 1;
1175690075Sobrien  REG_NOTES (insn) =
1175790075Sobrien    gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
1175890075Sobrien		       gen_rtx_SET (VOIDmode, stack_reg,
1175990075Sobrien				    gen_rtx_PLUS (Pmode, stack_reg,
1176090075Sobrien						  GEN_INT (-size))),
1176190075Sobrien		       REG_NOTES (insn));
1176290075Sobrien}
1176390075Sobrien
1176490075Sobrien/* Add to 'insn' a note which is PATTERN (INSN) but with REG replaced
1176590075Sobrien   with (plus:P (reg 1) VAL), and with REG2 replaced with RREG if REG2
1176690075Sobrien   is not NULL.  It would be nice if dwarf2out_frame_debug_expr could
1176790075Sobrien   deduce these equivalences by itself so it wasn't necessary to hold
1176890075Sobrien   its hand so much.  */
1176990075Sobrien
1177090075Sobrienstatic void
11771132718Skanrs6000_frame_related (rtx insn, rtx reg, HOST_WIDE_INT val,
11772132718Skan		      rtx reg2, rtx rreg)
1177390075Sobrien{
1177490075Sobrien  rtx real, temp;
1177590075Sobrien
11776117395Skan  /* copy_rtx will not make unique copies of registers, so we need to
11777117395Skan     ensure we don't have unwanted sharing here.  */
11778117395Skan  if (reg == reg2)
11779117395Skan    reg = gen_raw_REG (GET_MODE (reg), REGNO (reg));
11780117395Skan
11781117395Skan  if (reg == rreg)
11782117395Skan    reg = gen_raw_REG (GET_MODE (reg), REGNO (reg));
11783117395Skan
1178490075Sobrien  real = copy_rtx (PATTERN (insn));
1178590075Sobrien
11786117395Skan  if (reg2 != NULL_RTX)
11787117395Skan    real = replace_rtx (real, reg2, rreg);
11788117395Skan
1178990075Sobrien  real = replace_rtx (real, reg,
1179090075Sobrien		      gen_rtx_PLUS (Pmode, gen_rtx_REG (Pmode,
1179190075Sobrien							STACK_POINTER_REGNUM),
1179290075Sobrien				    GEN_INT (val)));
1179390075Sobrien
1179490075Sobrien  /* We expect that 'real' is either a SET or a PARALLEL containing
1179590075Sobrien     SETs (and possibly other stuff).  In a PARALLEL, all the SETs
1179690075Sobrien     are important so they all have to be marked RTX_FRAME_RELATED_P.  */
1179790075Sobrien
1179890075Sobrien  if (GET_CODE (real) == SET)
1179990075Sobrien    {
1180090075Sobrien      rtx set = real;
1180190075Sobrien
1180290075Sobrien      temp = simplify_rtx (SET_SRC (set));
1180390075Sobrien      if (temp)
1180490075Sobrien	SET_SRC (set) = temp;
1180590075Sobrien      temp = simplify_rtx (SET_DEST (set));
1180690075Sobrien      if (temp)
1180790075Sobrien	SET_DEST (set) = temp;
1180890075Sobrien      if (GET_CODE (SET_DEST (set)) == MEM)
1180990075Sobrien	{
1181090075Sobrien	  temp = simplify_rtx (XEXP (SET_DEST (set), 0));
1181190075Sobrien	  if (temp)
1181290075Sobrien	    XEXP (SET_DEST (set), 0) = temp;
1181390075Sobrien	}
1181490075Sobrien    }
1181590075Sobrien  else if (GET_CODE (real) == PARALLEL)
1181690075Sobrien    {
1181790075Sobrien      int i;
1181890075Sobrien      for (i = 0; i < XVECLEN (real, 0); i++)
1181990075Sobrien	if (GET_CODE (XVECEXP (real, 0, i)) == SET)
1182090075Sobrien	  {
1182190075Sobrien	    rtx set = XVECEXP (real, 0, i);
1182290075Sobrien
1182390075Sobrien	    temp = simplify_rtx (SET_SRC (set));
1182490075Sobrien	    if (temp)
1182590075Sobrien	      SET_SRC (set) = temp;
1182690075Sobrien	    temp = simplify_rtx (SET_DEST (set));
1182790075Sobrien	    if (temp)
1182890075Sobrien	      SET_DEST (set) = temp;
1182990075Sobrien	    if (GET_CODE (SET_DEST (set)) == MEM)
1183090075Sobrien	      {
1183190075Sobrien		temp = simplify_rtx (XEXP (SET_DEST (set), 0));
1183290075Sobrien		if (temp)
1183390075Sobrien		  XEXP (SET_DEST (set), 0) = temp;
1183490075Sobrien	      }
1183590075Sobrien	    RTX_FRAME_RELATED_P (set) = 1;
1183690075Sobrien	  }
1183790075Sobrien    }
1183890075Sobrien  else
1183990075Sobrien    abort ();
11840132718Skan
11841132718Skan  if (TARGET_SPE)
11842132718Skan    real = spe_synthesize_frame_save (real);
11843132718Skan
1184490075Sobrien  RTX_FRAME_RELATED_P (insn) = 1;
1184590075Sobrien  REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
1184690075Sobrien					real,
1184790075Sobrien					REG_NOTES (insn));
1184890075Sobrien}
1184990075Sobrien
11850132718Skan/* Given an SPE frame note, return a PARALLEL of SETs with the
11851132718Skan   original note, plus a synthetic register save.  */
11852132718Skan
11853132718Skanstatic rtx
11854132718Skanspe_synthesize_frame_save (rtx real)
11855132718Skan{
11856132718Skan  rtx synth, offset, reg, real2;
11857132718Skan
11858132718Skan  if (GET_CODE (real) != SET
11859132718Skan      || GET_MODE (SET_SRC (real)) != V2SImode)
11860132718Skan    return real;
11861132718Skan
11862132718Skan  /* For the SPE, registers saved in 64-bits, get a PARALLEL for their
11863132718Skan     frame related note.  The parallel contains a set of the register
11864132718Skan     being saved, and another set to a synthetic register (n+1200).
11865132718Skan     This is so we can differentiate between 64-bit and 32-bit saves.
11866132718Skan     Words cannot describe this nastiness.  */
11867132718Skan
11868132718Skan  if (GET_CODE (SET_DEST (real)) != MEM
11869132718Skan      || GET_CODE (XEXP (SET_DEST (real), 0)) != PLUS
11870132718Skan      || GET_CODE (SET_SRC (real)) != REG)
11871132718Skan    abort ();
11872132718Skan
11873132718Skan  /* Transform:
11874132718Skan       (set (mem (plus (reg x) (const y)))
11875132718Skan            (reg z))
11876132718Skan     into:
11877132718Skan       (set (mem (plus (reg x) (const y+4)))
11878132718Skan            (reg z+1200))
11879132718Skan  */
11880132718Skan
11881132718Skan  real2 = copy_rtx (real);
11882132718Skan  PUT_MODE (SET_DEST (real2), SImode);
11883132718Skan  reg = SET_SRC (real2);
11884132718Skan  real2 = replace_rtx (real2, reg, gen_rtx_REG (SImode, REGNO (reg)));
11885132718Skan  synth = copy_rtx (real2);
11886132718Skan
11887132718Skan  if (BYTES_BIG_ENDIAN)
11888132718Skan    {
11889132718Skan      offset = XEXP (XEXP (SET_DEST (real2), 0), 1);
11890132718Skan      real2 = replace_rtx (real2, offset, GEN_INT (INTVAL (offset) + 4));
11891132718Skan    }
11892132718Skan
11893132718Skan  reg = SET_SRC (synth);
11894132718Skan
11895132718Skan  synth = replace_rtx (synth, reg,
11896132718Skan		       gen_rtx_REG (SImode, REGNO (reg) + 1200));
11897132718Skan
11898132718Skan  offset = XEXP (XEXP (SET_DEST (synth), 0), 1);
11899132718Skan  synth = replace_rtx (synth, offset,
11900132718Skan		       GEN_INT (INTVAL (offset)
11901132718Skan				+ (BYTES_BIG_ENDIAN ? 0 : 4)));
11902132718Skan
11903132718Skan  RTX_FRAME_RELATED_P (synth) = 1;
11904132718Skan  RTX_FRAME_RELATED_P (real2) = 1;
11905132718Skan  if (BYTES_BIG_ENDIAN)
11906132718Skan    real = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, synth, real2));
11907132718Skan  else
11908132718Skan    real = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, real2, synth));
11909132718Skan
11910132718Skan  return real;
11911132718Skan}
11912132718Skan
1191390075Sobrien/* Returns an insn that has a vrsave set operation with the
1191490075Sobrien   appropriate CLOBBERs.  */
1191590075Sobrien
1191690075Sobrienstatic rtx
11917132718Skangenerate_set_vrsave (rtx reg, rs6000_stack_t *info, int epiloguep)
1191890075Sobrien{
1191990075Sobrien  int nclobs, i;
1192090075Sobrien  rtx insn, clobs[TOTAL_ALTIVEC_REGS + 1];
1192190075Sobrien  rtx vrsave = gen_rtx_REG (SImode, VRSAVE_REGNO);
1192290075Sobrien
1192390075Sobrien  clobs[0]
1192490075Sobrien    = gen_rtx_SET (VOIDmode,
1192590075Sobrien		   vrsave,
1192690075Sobrien		   gen_rtx_UNSPEC_VOLATILE (SImode,
1192790075Sobrien					    gen_rtvec (2, reg, vrsave),
1192890075Sobrien					    30));
1192990075Sobrien
1193090075Sobrien  nclobs = 1;
1193190075Sobrien
1193290075Sobrien  /* We need to clobber the registers in the mask so the scheduler
1193390075Sobrien     does not move sets to VRSAVE before sets of AltiVec registers.
1193490075Sobrien
1193590075Sobrien     However, if the function receives nonlocal gotos, reload will set
1193690075Sobrien     all call saved registers live.  We will end up with:
1193790075Sobrien
1193890075Sobrien     	(set (reg 999) (mem))
1193990075Sobrien	(parallel [ (set (reg vrsave) (unspec blah))
1194090075Sobrien		    (clobber (reg 999))])
1194190075Sobrien
1194290075Sobrien     The clobber will cause the store into reg 999 to be dead, and
1194390075Sobrien     flow will attempt to delete an epilogue insn.  In this case, we
1194490075Sobrien     need an unspec use/set of the register.  */
1194590075Sobrien
1194690075Sobrien  for (i = FIRST_ALTIVEC_REGNO; i <= LAST_ALTIVEC_REGNO; ++i)
11947132718Skan    if (info->vrsave_mask & ALTIVEC_REG_BIT (i))
1194890075Sobrien      {
1194990075Sobrien	if (!epiloguep || call_used_regs [i])
1195090075Sobrien	  clobs[nclobs++] = gen_rtx_CLOBBER (VOIDmode,
1195190075Sobrien					     gen_rtx_REG (V4SImode, i));
1195290075Sobrien	else
1195390075Sobrien	  {
1195490075Sobrien	    rtx reg = gen_rtx_REG (V4SImode, i);
1195590075Sobrien
1195690075Sobrien	    clobs[nclobs++]
1195790075Sobrien	      = gen_rtx_SET (VOIDmode,
1195890075Sobrien			     reg,
1195990075Sobrien			     gen_rtx_UNSPEC (V4SImode,
1196090075Sobrien					     gen_rtvec (1, reg), 27));
1196190075Sobrien	  }
1196290075Sobrien      }
1196390075Sobrien
1196490075Sobrien  insn = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (nclobs));
1196590075Sobrien
1196690075Sobrien  for (i = 0; i < nclobs; ++i)
1196790075Sobrien    XVECEXP (insn, 0, i) = clobs[i];
1196890075Sobrien
1196990075Sobrien  return insn;
1197090075Sobrien}
1197190075Sobrien
11972117395Skan/* Save a register into the frame, and emit RTX_FRAME_RELATED_P notes.
11973117395Skan   Save REGNO into [FRAME_REG + OFFSET] in mode MODE.  */
11974117395Skan
11975117395Skanstatic void
11976132718Skanemit_frame_save (rtx frame_reg, rtx frame_ptr, enum machine_mode mode,
11977132718Skan		 unsigned int regno, int offset, HOST_WIDE_INT total_size)
11978117395Skan{
11979117395Skan  rtx reg, offset_rtx, insn, mem, addr, int_rtx;
11980117395Skan  rtx replacea, replaceb;
11981117395Skan
11982117395Skan  int_rtx = GEN_INT (offset);
11983117395Skan
11984117395Skan  /* Some cases that need register indexed addressing.  */
11985117395Skan  if ((TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
11986117395Skan      || (TARGET_SPE_ABI
11987117395Skan	  && SPE_VECTOR_MODE (mode)
11988117395Skan	  && !SPE_CONST_OFFSET_OK (offset)))
11989117395Skan    {
11990117395Skan      /* Whomever calls us must make sure r11 is available in the
11991117395Skan         flow path of instructions in the prologue.  */
11992117395Skan      offset_rtx = gen_rtx_REG (Pmode, 11);
11993117395Skan      emit_move_insn (offset_rtx, int_rtx);
11994117395Skan
11995117395Skan      replacea = offset_rtx;
11996117395Skan      replaceb = int_rtx;
11997117395Skan    }
11998117395Skan  else
11999117395Skan    {
12000117395Skan      offset_rtx = int_rtx;
12001117395Skan      replacea = NULL_RTX;
12002117395Skan      replaceb = NULL_RTX;
12003117395Skan    }
12004117395Skan
12005117395Skan  reg = gen_rtx_REG (mode, regno);
12006117395Skan  addr = gen_rtx_PLUS (Pmode, frame_reg, offset_rtx);
12007117395Skan  mem = gen_rtx_MEM (mode, addr);
12008117395Skan  set_mem_alias_set (mem, rs6000_sr_alias_set);
12009117395Skan
12010117395Skan  insn = emit_move_insn (mem, reg);
12011117395Skan
12012117395Skan  rs6000_frame_related (insn, frame_ptr, total_size, replacea, replaceb);
12013117395Skan}
12014117395Skan
12015117395Skan/* Emit an offset memory reference suitable for a frame store, while
12016117395Skan   converting to a valid addressing mode.  */
12017117395Skan
12018117395Skanstatic rtx
12019132718Skangen_frame_mem_offset (enum machine_mode mode, rtx reg, int offset)
12020117395Skan{
12021117395Skan  rtx int_rtx, offset_rtx;
12022117395Skan
12023117395Skan  int_rtx = GEN_INT (offset);
12024117395Skan
12025117395Skan  if (TARGET_SPE_ABI && SPE_VECTOR_MODE (mode))
12026117395Skan    {
12027117395Skan      offset_rtx = gen_rtx_REG (Pmode, FIXED_SCRATCH);
12028117395Skan      emit_move_insn (offset_rtx, int_rtx);
12029117395Skan    }
12030117395Skan  else
12031117395Skan    offset_rtx = int_rtx;
12032117395Skan
12033117395Skan  return gen_rtx_MEM (mode, gen_rtx_PLUS (Pmode, reg, offset_rtx));
12034117395Skan}
12035117395Skan
1203690075Sobrien/* Emit function prologue as insns.  */
1203790075Sobrien
1203890075Sobrienvoid
12039132718Skanrs6000_emit_prologue (void)
1204090075Sobrien{
1204190075Sobrien  rs6000_stack_t *info = rs6000_stack_info ();
12042132718Skan  enum machine_mode reg_mode = Pmode;
12043132718Skan  int reg_size = TARGET_32BIT ? 4 : 8;
1204490075Sobrien  rtx sp_reg_rtx = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
1204590075Sobrien  rtx frame_ptr_rtx = gen_rtx_REG (Pmode, 12);
1204690075Sobrien  rtx frame_reg_rtx = sp_reg_rtx;
12047132718Skan  rtx cr_save_rtx = NULL_RTX;
1204890075Sobrien  rtx insn;
1204990075Sobrien  int saving_FPRs_inline;
1205090075Sobrien  int using_store_multiple;
1205190075Sobrien  HOST_WIDE_INT sp_offset = 0;
1205290075Sobrien
12053132718Skan   if (TARGET_SPE_ABI && info->spe_64bit_regs_used != 0)
12054117395Skan     {
12055117395Skan       reg_mode = V2SImode;
12056117395Skan       reg_size = 8;
12057117395Skan     }
12058117395Skan
1205990075Sobrien  using_store_multiple = (TARGET_MULTIPLE && ! TARGET_POWERPC64
12060132718Skan			  && (!TARGET_SPE_ABI
12061132718Skan			      || info->spe_64bit_regs_used == 0)
1206290075Sobrien			  && info->first_gp_reg_save < 31);
1206390075Sobrien  saving_FPRs_inline = (info->first_fp_reg_save == 64
12064132718Skan			|| FP_SAVE_INLINE (info->first_fp_reg_save)
12065132718Skan			|| current_function_calls_eh_return
12066132718Skan			|| cfun->machine->ra_need_lr);
1206790075Sobrien
1206890075Sobrien  /* For V.4, update stack before we do any saving and set back pointer.  */
12069132718Skan  if (info->push_p
12070132718Skan      && (DEFAULT_ABI == ABI_V4
12071132718Skan	  || current_function_calls_eh_return))
1207290075Sobrien    {
1207390075Sobrien      if (info->total_size < 32767)
1207490075Sobrien	sp_offset = info->total_size;
1207590075Sobrien      else
1207690075Sobrien	frame_reg_rtx = frame_ptr_rtx;
1207790075Sobrien      rs6000_emit_allocate_stack (info->total_size,
1207890075Sobrien				  (frame_reg_rtx != sp_reg_rtx
1207990075Sobrien				   && (info->cr_save_p
1208090075Sobrien				       || info->lr_save_p
1208190075Sobrien				       || info->first_fp_reg_save < 64
1208290075Sobrien				       || info->first_gp_reg_save < 32
1208390075Sobrien				       )));
1208490075Sobrien      if (frame_reg_rtx != sp_reg_rtx)
1208590075Sobrien	rs6000_emit_stack_tie ();
1208690075Sobrien    }
1208790075Sobrien
1208890075Sobrien  /* Save AltiVec registers if needed.  */
1208990075Sobrien  if (TARGET_ALTIVEC_ABI && info->altivec_size != 0)
1209090075Sobrien    {
1209190075Sobrien      int i;
1209290075Sobrien
1209390075Sobrien      /* There should be a non inline version of this, for when we
1209490075Sobrien	 are saving lots of vector registers.  */
1209590075Sobrien      for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i)
1209690075Sobrien	if (info->vrsave_mask & ALTIVEC_REG_BIT (i))
1209790075Sobrien	  {
1209890075Sobrien	    rtx areg, savereg, mem;
1209990075Sobrien	    int offset;
1210090075Sobrien
1210190075Sobrien	    offset = info->altivec_save_offset + sp_offset
1210290075Sobrien	      + 16 * (i - info->first_altivec_reg_save);
1210390075Sobrien
1210490075Sobrien	    savereg = gen_rtx_REG (V4SImode, i);
1210590075Sobrien
1210690075Sobrien	    areg = gen_rtx_REG (Pmode, 0);
1210790075Sobrien	    emit_move_insn (areg, GEN_INT (offset));
1210890075Sobrien
1210990075Sobrien	    /* AltiVec addressing mode is [reg+reg].  */
1211090075Sobrien	    mem = gen_rtx_MEM (V4SImode,
1211190075Sobrien			       gen_rtx_PLUS (Pmode, frame_reg_rtx, areg));
1211290075Sobrien
1211390075Sobrien	    set_mem_alias_set (mem, rs6000_sr_alias_set);
1211490075Sobrien
1211590075Sobrien	    insn = emit_move_insn (mem, savereg);
1211690075Sobrien
12117132718Skan	    rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
12118132718Skan				  areg, GEN_INT (offset));
1211990075Sobrien	  }
1212090075Sobrien    }
1212190075Sobrien
1212290075Sobrien  /* VRSAVE is a bit vector representing which AltiVec registers
1212390075Sobrien     are used.  The OS uses this to determine which vector
1212490075Sobrien     registers to save on a context switch.  We need to save
1212590075Sobrien     VRSAVE on the stack frame, add whatever AltiVec registers we
1212690075Sobrien     used in this function, and do the corresponding magic in the
1212790075Sobrien     epilogue.  */
1212890075Sobrien
12129132718Skan  if (TARGET_ALTIVEC && TARGET_ALTIVEC_VRSAVE
12130132718Skan      && info->vrsave_mask != 0)
1213190075Sobrien    {
1213290075Sobrien      rtx reg, mem, vrsave;
1213390075Sobrien      int offset;
1213490075Sobrien
12135146895Skan      /* Get VRSAVE onto a GPR.  Note that ABI_V4 might be using r12
12136146895Skan	 as frame_reg_rtx and r11 as the static chain pointer for
12137146895Skan	 nested functions.  */
12138146895Skan      reg = gen_rtx_REG (SImode, 0);
1213990075Sobrien      vrsave = gen_rtx_REG (SImode, VRSAVE_REGNO);
1214096263Sobrien      if (TARGET_MACHO)
1214196263Sobrien	emit_insn (gen_get_vrsave_internal (reg));
1214296263Sobrien      else
1214396263Sobrien	emit_insn (gen_rtx_SET (VOIDmode, reg, vrsave));
1214490075Sobrien
1214590075Sobrien      /* Save VRSAVE.  */
1214690075Sobrien      offset = info->vrsave_save_offset + sp_offset;
1214790075Sobrien      mem
1214890075Sobrien	= gen_rtx_MEM (SImode,
1214990075Sobrien		       gen_rtx_PLUS (Pmode, frame_reg_rtx, GEN_INT (offset)));
1215090075Sobrien      set_mem_alias_set (mem, rs6000_sr_alias_set);
1215190075Sobrien      insn = emit_move_insn (mem, reg);
1215290075Sobrien
1215390075Sobrien      /* Include the registers in the mask.  */
1215490075Sobrien      emit_insn (gen_iorsi3 (reg, reg, GEN_INT ((int) info->vrsave_mask)));
1215590075Sobrien
1215690075Sobrien      insn = emit_insn (generate_set_vrsave (reg, info, 0));
1215790075Sobrien    }
1215890075Sobrien
1215990075Sobrien  /* If we use the link register, get it into r0.  */
1216090075Sobrien  if (info->lr_save_p)
1216190075Sobrien    emit_move_insn (gen_rtx_REG (Pmode, 0),
1216290075Sobrien		    gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM));
1216390075Sobrien
1216490075Sobrien  /* If we need to save CR, put it into r12.  */
1216590075Sobrien  if (info->cr_save_p && frame_reg_rtx != frame_ptr_rtx)
1216690075Sobrien    {
1216790075Sobrien      cr_save_rtx = gen_rtx_REG (SImode, 12);
1216890075Sobrien      emit_insn (gen_movesi_from_cr (cr_save_rtx));
1216990075Sobrien    }
1217090075Sobrien
1217190075Sobrien  /* Do any required saving of fpr's.  If only one or two to save, do
1217290075Sobrien     it ourselves.  Otherwise, call function.  */
1217390075Sobrien  if (saving_FPRs_inline)
1217490075Sobrien    {
1217590075Sobrien      int i;
1217690075Sobrien      for (i = 0; i < 64 - info->first_fp_reg_save; i++)
1217790075Sobrien	if ((regs_ever_live[info->first_fp_reg_save+i]
1217890075Sobrien	     && ! call_used_regs[info->first_fp_reg_save+i]))
12179117395Skan	  emit_frame_save (frame_reg_rtx, frame_ptr_rtx, DFmode,
12180117395Skan			   info->first_fp_reg_save + i,
12181117395Skan			   info->fp_save_offset + sp_offset + 8 * i,
12182117395Skan			   info->total_size);
1218390075Sobrien    }
1218490075Sobrien  else if (info->first_fp_reg_save != 64)
1218590075Sobrien    {
1218690075Sobrien      int i;
1218790075Sobrien      char rname[30];
1218890075Sobrien      const char *alloc_rname;
1218990075Sobrien      rtvec p;
1219090075Sobrien      p = rtvec_alloc (2 + 64 - info->first_fp_reg_save);
1219190075Sobrien
1219290075Sobrien      RTVEC_ELT (p, 0) = gen_rtx_CLOBBER (VOIDmode,
1219390075Sobrien					  gen_rtx_REG (Pmode,
1219490075Sobrien						       LINK_REGISTER_REGNUM));
1219590075Sobrien      sprintf (rname, "%s%d%s", SAVE_FP_PREFIX,
1219690075Sobrien	       info->first_fp_reg_save - 32, SAVE_FP_SUFFIX);
1219790075Sobrien      alloc_rname = ggc_strdup (rname);
1219890075Sobrien      RTVEC_ELT (p, 1) = gen_rtx_USE (VOIDmode,
1219990075Sobrien				      gen_rtx_SYMBOL_REF (Pmode,
1220090075Sobrien							  alloc_rname));
1220190075Sobrien      for (i = 0; i < 64 - info->first_fp_reg_save; i++)
1220290075Sobrien	{
1220390075Sobrien	  rtx addr, reg, mem;
1220490075Sobrien	  reg = gen_rtx_REG (DFmode, info->first_fp_reg_save + i);
1220590075Sobrien	  addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
1220690075Sobrien			       GEN_INT (info->fp_save_offset
1220790075Sobrien					+ sp_offset + 8*i));
1220890075Sobrien	  mem = gen_rtx_MEM (DFmode, addr);
1220990075Sobrien	  set_mem_alias_set (mem, rs6000_sr_alias_set);
1221090075Sobrien
1221190075Sobrien	  RTVEC_ELT (p, i + 2) = gen_rtx_SET (VOIDmode, mem, reg);
1221290075Sobrien	}
1221390075Sobrien      insn = emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
1221490075Sobrien      rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
1221590075Sobrien			    NULL_RTX, NULL_RTX);
1221690075Sobrien    }
1221790075Sobrien
1221890075Sobrien  /* Save GPRs.  This is done as a PARALLEL if we are using
1221990075Sobrien     the store-multiple instructions.  */
1222090075Sobrien  if (using_store_multiple)
1222190075Sobrien    {
12222117395Skan      rtvec p;
1222390075Sobrien      int i;
1222490075Sobrien      p = rtvec_alloc (32 - info->first_gp_reg_save);
1222590075Sobrien      for (i = 0; i < 32 - info->first_gp_reg_save; i++)
1222690075Sobrien	{
1222790075Sobrien	  rtx addr, reg, mem;
1222890075Sobrien	  reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
1222990075Sobrien	  addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
1223090075Sobrien			       GEN_INT (info->gp_save_offset
1223190075Sobrien					+ sp_offset
1223290075Sobrien					+ reg_size * i));
1223390075Sobrien	  mem = gen_rtx_MEM (reg_mode, addr);
1223490075Sobrien	  set_mem_alias_set (mem, rs6000_sr_alias_set);
1223590075Sobrien
1223690075Sobrien	  RTVEC_ELT (p, i) = gen_rtx_SET (VOIDmode, mem, reg);
1223790075Sobrien	}
1223890075Sobrien      insn = emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
1223990075Sobrien      rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
1224090075Sobrien			    NULL_RTX, NULL_RTX);
1224190075Sobrien    }
1224290075Sobrien  else
1224390075Sobrien    {
1224490075Sobrien      int i;
1224590075Sobrien      for (i = 0; i < 32 - info->first_gp_reg_save; i++)
1224690075Sobrien	if ((regs_ever_live[info->first_gp_reg_save+i]
12247146895Skan	     && (! call_used_regs[info->first_gp_reg_save+i]
12248146895Skan		 || (i+info->first_gp_reg_save
12249146895Skan		     == RS6000_PIC_OFFSET_TABLE_REGNUM
12250146895Skan		     && TARGET_TOC && TARGET_MINIMAL_TOC)))
1225196263Sobrien	    || (i+info->first_gp_reg_save == RS6000_PIC_OFFSET_TABLE_REGNUM
12252117395Skan		&& ((DEFAULT_ABI == ABI_V4 && flag_pic != 0)
1225390075Sobrien		    || (DEFAULT_ABI == ABI_DARWIN && flag_pic))))
1225490075Sobrien	  {
1225590075Sobrien	    rtx addr, reg, mem;
1225690075Sobrien	    reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
1225790075Sobrien
12258132718Skan	    if (TARGET_SPE_ABI && info->spe_64bit_regs_used != 0)
12259117395Skan	      {
12260117395Skan		int offset = info->spe_gp_save_offset + sp_offset + 8 * i;
12261117395Skan		rtx b;
12262117395Skan
12263117395Skan		if (!SPE_CONST_OFFSET_OK (offset))
12264117395Skan		  {
12265117395Skan		    b = gen_rtx_REG (Pmode, FIXED_SCRATCH);
12266117395Skan		    emit_move_insn (b, GEN_INT (offset));
12267117395Skan		  }
12268117395Skan		else
12269117395Skan		  b = GEN_INT (offset);
12270117395Skan
12271117395Skan		addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, b);
12272117395Skan		mem = gen_rtx_MEM (V2SImode, addr);
12273117395Skan		set_mem_alias_set (mem, rs6000_sr_alias_set);
12274117395Skan		insn = emit_move_insn (mem, reg);
12275117395Skan
12276117395Skan		if (GET_CODE (b) == CONST_INT)
12277117395Skan		  rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
12278117395Skan					NULL_RTX, NULL_RTX);
12279117395Skan		else
12280117395Skan		  rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
12281117395Skan					b, GEN_INT (offset));
12282117395Skan	      }
12283117395Skan	    else
12284117395Skan	      {
12285117395Skan		addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
12286117395Skan				     GEN_INT (info->gp_save_offset
12287117395Skan					      + sp_offset
12288117395Skan					      + reg_size * i));
12289117395Skan		mem = gen_rtx_MEM (reg_mode, addr);
12290117395Skan		set_mem_alias_set (mem, rs6000_sr_alias_set);
12291117395Skan
12292117395Skan		insn = emit_move_insn (mem, reg);
12293117395Skan		rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
12294117395Skan				      NULL_RTX, NULL_RTX);
12295117395Skan	      }
1229690075Sobrien	  }
1229790075Sobrien    }
1229890075Sobrien
1229990075Sobrien  /* ??? There's no need to emit actual instructions here, but it's the
1230090075Sobrien     easiest way to get the frame unwind information emitted.  */
1230190075Sobrien  if (current_function_calls_eh_return)
1230290075Sobrien    {
1230390075Sobrien      unsigned int i, regno;
1230490075Sobrien
12305132718Skan      /* In AIX ABI we need to pretend we save r2 here.  */
12306132718Skan      if (TARGET_AIX)
12307132718Skan	{
12308132718Skan	  rtx addr, reg, mem;
12309132718Skan
12310132718Skan	  reg = gen_rtx_REG (reg_mode, 2);
12311132718Skan	  addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
12312132718Skan			       GEN_INT (sp_offset + 5 * reg_size));
12313132718Skan	  mem = gen_rtx_MEM (reg_mode, addr);
12314132718Skan	  set_mem_alias_set (mem, rs6000_sr_alias_set);
12315132718Skan
12316132718Skan	  insn = emit_move_insn (mem, reg);
12317132718Skan	  rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
12318132718Skan				NULL_RTX, NULL_RTX);
12319132718Skan	  PATTERN (insn) = gen_blockage ();
12320132718Skan	}
12321132718Skan
1232290075Sobrien      for (i = 0; ; ++i)
1232390075Sobrien	{
1232490075Sobrien	  regno = EH_RETURN_DATA_REGNO (i);
1232590075Sobrien	  if (regno == INVALID_REGNUM)
1232690075Sobrien	    break;
1232790075Sobrien
12328117395Skan	  emit_frame_save (frame_reg_rtx, frame_ptr_rtx, reg_mode, regno,
12329117395Skan			   info->ehrd_offset + sp_offset
12330117395Skan			   + reg_size * (int) i,
12331117395Skan			   info->total_size);
1233290075Sobrien	}
1233390075Sobrien    }
1233490075Sobrien
1233590075Sobrien  /* Save lr if we used it.  */
1233690075Sobrien  if (info->lr_save_p)
1233790075Sobrien    {
1233890075Sobrien      rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
1233990075Sobrien			       GEN_INT (info->lr_save_offset + sp_offset));
1234090075Sobrien      rtx reg = gen_rtx_REG (Pmode, 0);
1234190075Sobrien      rtx mem = gen_rtx_MEM (Pmode, addr);
1234290075Sobrien      /* This should not be of rs6000_sr_alias_set, because of
1234390075Sobrien	 __builtin_return_address.  */
1234490075Sobrien
1234590075Sobrien      insn = emit_move_insn (mem, reg);
1234690075Sobrien      rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
1234790075Sobrien			    reg, gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM));
1234890075Sobrien    }
1234990075Sobrien
1235090075Sobrien  /* Save CR if we use any that must be preserved.  */
1235190075Sobrien  if (info->cr_save_p)
1235290075Sobrien    {
1235390075Sobrien      rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
1235490075Sobrien			       GEN_INT (info->cr_save_offset + sp_offset));
1235590075Sobrien      rtx mem = gen_rtx_MEM (SImode, addr);
1235690075Sobrien
1235790075Sobrien      set_mem_alias_set (mem, rs6000_sr_alias_set);
1235890075Sobrien
1235990075Sobrien      /* If r12 was used to hold the original sp, copy cr into r0 now
1236090075Sobrien	 that it's free.  */
1236190075Sobrien      if (REGNO (frame_reg_rtx) == 12)
1236290075Sobrien	{
1236390075Sobrien	  cr_save_rtx = gen_rtx_REG (SImode, 0);
1236490075Sobrien	  emit_insn (gen_movesi_from_cr (cr_save_rtx));
1236590075Sobrien	}
1236690075Sobrien      insn = emit_move_insn (mem, cr_save_rtx);
1236790075Sobrien
1236890075Sobrien      /* Now, there's no way that dwarf2out_frame_debug_expr is going
12369132718Skan	 to understand '(unspec:SI [(reg:CC 68) ...] UNSPEC_MOVESI_FROM_CR)'.
12370132718Skan	 But that's OK.  All we have to do is specify that _one_ condition
12371132718Skan	 code register is saved in this stack slot.  The thrower's epilogue
1237290075Sobrien	 will then restore all the call-saved registers.
1237390075Sobrien	 We use CR2_REGNO (70) to be compatible with gcc-2.95 on Linux.  */
1237490075Sobrien      rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
1237590075Sobrien			    cr_save_rtx, gen_rtx_REG (SImode, CR2_REGNO));
1237690075Sobrien    }
1237790075Sobrien
1237890075Sobrien  /* Update stack and set back pointer unless this is V.4,
1237990075Sobrien     for which it was done previously.  */
12380132718Skan  if (info->push_p
12381132718Skan      && !(DEFAULT_ABI == ABI_V4 || current_function_calls_eh_return))
1238290075Sobrien    rs6000_emit_allocate_stack (info->total_size, FALSE);
1238390075Sobrien
1238490075Sobrien  /* Set frame pointer, if needed.  */
1238590075Sobrien  if (frame_pointer_needed)
1238690075Sobrien    {
12387117395Skan      insn = emit_move_insn (gen_rtx_REG (Pmode, FRAME_POINTER_REGNUM),
1238890075Sobrien			     sp_reg_rtx);
1238990075Sobrien      RTX_FRAME_RELATED_P (insn) = 1;
1239090075Sobrien    }
1239190075Sobrien
1239296263Sobrien  /* If we are using RS6000_PIC_OFFSET_TABLE_REGNUM, we need to set it up.  */
1239390075Sobrien  if ((TARGET_TOC && TARGET_MINIMAL_TOC && get_pool_size () != 0)
1239490075Sobrien      || (DEFAULT_ABI == ABI_V4 && flag_pic == 1
1239596263Sobrien	  && regs_ever_live[RS6000_PIC_OFFSET_TABLE_REGNUM]))
1239690075Sobrien  {
1239790075Sobrien    /* If emit_load_toc_table will use the link register, we need to save
12398132718Skan       it.  We use R12 for this purpose because emit_load_toc_table
1239990075Sobrien       can use register 0.  This allows us to use a plain 'blr' to return
1240090075Sobrien       from the procedure more often.  */
12401132718Skan    int save_LR_around_toc_setup = (TARGET_ELF
12402132718Skan				    && DEFAULT_ABI != ABI_AIX
12403132718Skan				    && flag_pic
1240490075Sobrien				    && ! info->lr_save_p
1240590075Sobrien				    && EXIT_BLOCK_PTR->pred != NULL);
1240690075Sobrien    if (save_LR_around_toc_setup)
12407132718Skan      {
12408132718Skan	rtx lr = gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM);
12409132718Skan	rs6000_maybe_dead (emit_move_insn (frame_ptr_rtx, lr));
12410132718Skan	rs6000_emit_load_toc_table (TRUE);
12411132718Skan	rs6000_maybe_dead (emit_move_insn (lr, frame_ptr_rtx));
12412132718Skan      }
12413132718Skan    else
12414132718Skan      rs6000_emit_load_toc_table (TRUE);
1241590075Sobrien  }
1241690075Sobrien
12417117395Skan#if TARGET_MACHO
1241890075Sobrien  if (DEFAULT_ABI == ABI_DARWIN
1241990075Sobrien      && flag_pic && current_function_uses_pic_offset_table)
1242090075Sobrien    {
1242190075Sobrien      rtx dest = gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM);
12422132718Skan      const char *picbase = machopic_function_base_name ();
12423132718Skan      rtx src = gen_rtx_SYMBOL_REF (Pmode, picbase);
1242490075Sobrien
12425117395Skan      rs6000_maybe_dead (emit_insn (gen_load_macho_picbase (dest, src)));
1242690075Sobrien
1242790075Sobrien      rs6000_maybe_dead (
1242896263Sobrien	emit_move_insn (gen_rtx_REG (Pmode, RS6000_PIC_OFFSET_TABLE_REGNUM),
1242990075Sobrien			gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM)));
1243090075Sobrien    }
12431117395Skan#endif
1243290075Sobrien}
1243390075Sobrien
1243490075Sobrien/* Write function prologue.  */
1243590075Sobrien
1243690075Sobrienstatic void
12437132718Skanrs6000_output_function_prologue (FILE *file,
12438132718Skan				 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
1243990075Sobrien{
1244090075Sobrien  rs6000_stack_t *info = rs6000_stack_info ();
1244190075Sobrien
1244290075Sobrien  if (TARGET_DEBUG_STACK)
1244390075Sobrien    debug_stack_info (info);
1244490075Sobrien
1244590075Sobrien  /* Write .extern for any function we will call to save and restore
1244690075Sobrien     fp values.  */
1244790075Sobrien  if (info->first_fp_reg_save < 64
1244890075Sobrien      && !FP_SAVE_INLINE (info->first_fp_reg_save))
1244990075Sobrien    fprintf (file, "\t.extern %s%d%s\n\t.extern %s%d%s\n",
1245090075Sobrien	     SAVE_FP_PREFIX, info->first_fp_reg_save - 32, SAVE_FP_SUFFIX,
1245190075Sobrien	     RESTORE_FP_PREFIX, info->first_fp_reg_save - 32,
1245290075Sobrien	     RESTORE_FP_SUFFIX);
1245390075Sobrien
1245490075Sobrien  /* Write .extern for AIX common mode routines, if needed.  */
1245590075Sobrien  if (! TARGET_POWER && ! TARGET_POWERPC && ! common_mode_defined)
1245690075Sobrien    {
1245790075Sobrien      fputs ("\t.extern __mulh\n", file);
1245890075Sobrien      fputs ("\t.extern __mull\n", file);
1245990075Sobrien      fputs ("\t.extern __divss\n", file);
1246090075Sobrien      fputs ("\t.extern __divus\n", file);
1246190075Sobrien      fputs ("\t.extern __quoss\n", file);
1246290075Sobrien      fputs ("\t.extern __quous\n", file);
1246390075Sobrien      common_mode_defined = 1;
1246490075Sobrien    }
1246590075Sobrien
1246690075Sobrien  if (! HAVE_prologue)
1246790075Sobrien    {
1246890075Sobrien      start_sequence ();
1246996263Sobrien
1247090075Sobrien      /* A NOTE_INSN_DELETED is supposed to be at the start and end of
1247190075Sobrien	 the "toplevel" insn chain.  */
12472132718Skan      emit_note (NOTE_INSN_DELETED);
1247390075Sobrien      rs6000_emit_prologue ();
12474132718Skan      emit_note (NOTE_INSN_DELETED);
1247596263Sobrien
12476132718Skan      /* Expand INSN_ADDRESSES so final() doesn't crash.  */
1247796263Sobrien      {
1247896263Sobrien	rtx insn;
1247996263Sobrien	unsigned addr = 0;
1248096263Sobrien	for (insn = get_insns (); insn != 0; insn = NEXT_INSN (insn))
1248196263Sobrien	  {
1248296263Sobrien	    INSN_ADDRESSES_NEW (insn, addr);
1248396263Sobrien	    addr += 4;
1248496263Sobrien	  }
1248596263Sobrien      }
1248696263Sobrien
1248790075Sobrien      if (TARGET_DEBUG_STACK)
1248890075Sobrien	debug_rtx_list (get_insns (), 100);
1248990075Sobrien      final (get_insns (), file, FALSE, FALSE);
1249090075Sobrien      end_sequence ();
1249190075Sobrien    }
1249290075Sobrien
1249390075Sobrien  rs6000_pic_labelno++;
1249490075Sobrien}
1249590075Sobrien
1249690075Sobrien/* Emit function epilogue as insns.
1249790075Sobrien
1249890075Sobrien   At present, dwarf2out_frame_debug_expr doesn't understand
1249990075Sobrien   register restores, so we don't bother setting RTX_FRAME_RELATED_P
1250090075Sobrien   anywhere in the epilogue.  Most of the insns below would in any case
1250190075Sobrien   need special notes to explain where r11 is in relation to the stack.  */
1250290075Sobrien
1250390075Sobrienvoid
12504132718Skanrs6000_emit_epilogue (int sibcall)
1250590075Sobrien{
1250690075Sobrien  rs6000_stack_t *info;
1250790075Sobrien  int restoring_FPRs_inline;
1250890075Sobrien  int using_load_multiple;
1250990075Sobrien  int using_mfcr_multiple;
1251090075Sobrien  int use_backchain_to_restore_sp;
1251190075Sobrien  int sp_offset = 0;
1251290075Sobrien  rtx sp_reg_rtx = gen_rtx_REG (Pmode, 1);
1251390075Sobrien  rtx frame_reg_rtx = sp_reg_rtx;
12514132718Skan  enum machine_mode reg_mode = Pmode;
12515132718Skan  int reg_size = TARGET_32BIT ? 4 : 8;
1251690075Sobrien  int i;
1251790075Sobrien
12518132718Skan  info = rs6000_stack_info ();
12519132718Skan
12520132718Skan  if (TARGET_SPE_ABI && info->spe_64bit_regs_used != 0)
12521117395Skan    {
12522117395Skan      reg_mode = V2SImode;
12523117395Skan      reg_size = 8;
12524117395Skan    }
12525117395Skan
1252690075Sobrien  using_load_multiple = (TARGET_MULTIPLE && ! TARGET_POWERPC64
12527132718Skan			 && (!TARGET_SPE_ABI
12528132718Skan			     || info->spe_64bit_regs_used == 0)
1252990075Sobrien			 && info->first_gp_reg_save < 31);
1253090075Sobrien  restoring_FPRs_inline = (sibcall
1253190075Sobrien			   || current_function_calls_eh_return
1253290075Sobrien			   || info->first_fp_reg_save == 64
1253390075Sobrien			   || FP_SAVE_INLINE (info->first_fp_reg_save));
1253490075Sobrien  use_backchain_to_restore_sp = (frame_pointer_needed
1253590075Sobrien				 || current_function_calls_alloca
1253690075Sobrien				 || info->total_size > 32767);
1253790075Sobrien  using_mfcr_multiple = (rs6000_cpu == PROCESSOR_PPC601
1253890075Sobrien			 || rs6000_cpu == PROCESSOR_PPC603
1253990075Sobrien			 || rs6000_cpu == PROCESSOR_PPC750
1254090075Sobrien			 || optimize_size);
1254190075Sobrien
1254290075Sobrien  /* If we have a frame pointer, a call to alloca,  or a large stack
1254390075Sobrien     frame, restore the old stack pointer using the backchain.  Otherwise,
1254490075Sobrien     we know what size to update it with.  */
1254590075Sobrien  if (use_backchain_to_restore_sp)
1254690075Sobrien    {
1254790075Sobrien      /* Under V.4, don't reset the stack pointer until after we're done
1254890075Sobrien	 loading the saved registers.  */
1254990075Sobrien      if (DEFAULT_ABI == ABI_V4)
1255090075Sobrien	frame_reg_rtx = gen_rtx_REG (Pmode, 11);
1255190075Sobrien
1255290075Sobrien      emit_move_insn (frame_reg_rtx,
1255390075Sobrien		      gen_rtx_MEM (Pmode, sp_reg_rtx));
1255490075Sobrien
1255590075Sobrien    }
1255690075Sobrien  else if (info->push_p)
1255790075Sobrien    {
12558132718Skan      if (DEFAULT_ABI == ABI_V4
12559132718Skan	  || current_function_calls_eh_return)
1256090075Sobrien	sp_offset = info->total_size;
1256190075Sobrien      else
1256290075Sobrien	{
1256390075Sobrien	  emit_insn (TARGET_32BIT
1256490075Sobrien		     ? gen_addsi3 (sp_reg_rtx, sp_reg_rtx,
1256590075Sobrien				   GEN_INT (info->total_size))
1256690075Sobrien		     : gen_adddi3 (sp_reg_rtx, sp_reg_rtx,
1256790075Sobrien				   GEN_INT (info->total_size)));
1256890075Sobrien	}
1256990075Sobrien    }
1257090075Sobrien
1257190075Sobrien  /* Restore AltiVec registers if needed.  */
1257290075Sobrien  if (TARGET_ALTIVEC_ABI && info->altivec_size != 0)
1257390075Sobrien    {
1257490075Sobrien      int i;
1257590075Sobrien
1257690075Sobrien      for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i)
1257790075Sobrien	if (info->vrsave_mask & ALTIVEC_REG_BIT (i))
1257890075Sobrien	  {
1257990075Sobrien	    rtx addr, areg, mem;
1258090075Sobrien
1258190075Sobrien	    areg = gen_rtx_REG (Pmode, 0);
1258290075Sobrien	    emit_move_insn
1258390075Sobrien	      (areg, GEN_INT (info->altivec_save_offset
1258490075Sobrien			      + sp_offset
1258590075Sobrien			      + 16 * (i - info->first_altivec_reg_save)));
1258690075Sobrien
1258790075Sobrien	    /* AltiVec addressing mode is [reg+reg].  */
1258890075Sobrien	    addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, areg);
1258990075Sobrien	    mem = gen_rtx_MEM (V4SImode, addr);
1259090075Sobrien	    set_mem_alias_set (mem, rs6000_sr_alias_set);
1259190075Sobrien
1259290075Sobrien	    emit_move_insn (gen_rtx_REG (V4SImode, i), mem);
1259390075Sobrien	  }
1259490075Sobrien    }
1259590075Sobrien
1259690075Sobrien  /* Restore VRSAVE if needed.  */
12597132718Skan  if (TARGET_ALTIVEC && TARGET_ALTIVEC_VRSAVE
12598132718Skan      && info->vrsave_mask != 0)
1259990075Sobrien    {
1260090075Sobrien      rtx addr, mem, reg;
1260190075Sobrien
1260290075Sobrien      addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
1260390075Sobrien			   GEN_INT (info->vrsave_save_offset + sp_offset));
1260490075Sobrien      mem = gen_rtx_MEM (SImode, addr);
1260590075Sobrien      set_mem_alias_set (mem, rs6000_sr_alias_set);
1260690075Sobrien      reg = gen_rtx_REG (SImode, 12);
1260790075Sobrien      emit_move_insn (reg, mem);
1260890075Sobrien
1260990075Sobrien      emit_insn (generate_set_vrsave (reg, info, 1));
1261090075Sobrien    }
1261190075Sobrien
1261290075Sobrien  /* Get the old lr if we saved it.  */
1261390075Sobrien  if (info->lr_save_p)
1261490075Sobrien    {
12615117395Skan      rtx mem = gen_frame_mem_offset (Pmode, frame_reg_rtx,
12616117395Skan				      info->lr_save_offset + sp_offset);
1261790075Sobrien
1261890075Sobrien      set_mem_alias_set (mem, rs6000_sr_alias_set);
1261990075Sobrien
1262090075Sobrien      emit_move_insn (gen_rtx_REG (Pmode, 0), mem);
1262190075Sobrien    }
1262290075Sobrien
1262390075Sobrien  /* Get the old cr if we saved it.  */
1262490075Sobrien  if (info->cr_save_p)
1262590075Sobrien    {
1262690075Sobrien      rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
1262790075Sobrien			       GEN_INT (info->cr_save_offset + sp_offset));
1262890075Sobrien      rtx mem = gen_rtx_MEM (SImode, addr);
1262990075Sobrien
1263090075Sobrien      set_mem_alias_set (mem, rs6000_sr_alias_set);
1263190075Sobrien
1263290075Sobrien      emit_move_insn (gen_rtx_REG (SImode, 12), mem);
1263390075Sobrien    }
1263490075Sobrien
1263590075Sobrien  /* Set LR here to try to overlap restores below.  */
1263690075Sobrien  if (info->lr_save_p)
1263790075Sobrien    emit_move_insn (gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM),
1263890075Sobrien		    gen_rtx_REG (Pmode, 0));
1263990075Sobrien
1264090075Sobrien  /* Load exception handler data registers, if needed.  */
1264190075Sobrien  if (current_function_calls_eh_return)
1264290075Sobrien    {
1264390075Sobrien      unsigned int i, regno;
1264490075Sobrien
12645132718Skan      if (TARGET_AIX)
12646132718Skan	{
12647132718Skan	  rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
12648132718Skan				   GEN_INT (sp_offset + 5 * reg_size));
12649132718Skan	  rtx mem = gen_rtx_MEM (reg_mode, addr);
12650132718Skan
12651132718Skan	  set_mem_alias_set (mem, rs6000_sr_alias_set);
12652132718Skan
12653132718Skan	  emit_move_insn (gen_rtx_REG (reg_mode, 2), mem);
12654132718Skan	}
12655132718Skan
1265690075Sobrien      for (i = 0; ; ++i)
1265790075Sobrien	{
12658117395Skan	  rtx mem;
1265990075Sobrien
1266090075Sobrien	  regno = EH_RETURN_DATA_REGNO (i);
1266190075Sobrien	  if (regno == INVALID_REGNUM)
1266290075Sobrien	    break;
1266390075Sobrien
12664117395Skan	  mem = gen_frame_mem_offset (reg_mode, frame_reg_rtx,
12665117395Skan				      info->ehrd_offset + sp_offset
12666117395Skan				      + reg_size * (int) i);
1266790075Sobrien	  set_mem_alias_set (mem, rs6000_sr_alias_set);
1266890075Sobrien
1266990075Sobrien	  emit_move_insn (gen_rtx_REG (reg_mode, regno), mem);
1267090075Sobrien	}
1267190075Sobrien    }
1267290075Sobrien
1267390075Sobrien  /* Restore GPRs.  This is done as a PARALLEL if we are using
1267490075Sobrien     the load-multiple instructions.  */
1267590075Sobrien  if (using_load_multiple)
1267690075Sobrien    {
1267790075Sobrien      rtvec p;
1267890075Sobrien      p = rtvec_alloc (32 - info->first_gp_reg_save);
1267990075Sobrien      for (i = 0; i < 32 - info->first_gp_reg_save; i++)
1268090075Sobrien	{
1268190075Sobrien	  rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
1268290075Sobrien				   GEN_INT (info->gp_save_offset
1268390075Sobrien					    + sp_offset
1268490075Sobrien					    + reg_size * i));
1268590075Sobrien	  rtx mem = gen_rtx_MEM (reg_mode, addr);
1268690075Sobrien
1268790075Sobrien	  set_mem_alias_set (mem, rs6000_sr_alias_set);
1268890075Sobrien
1268990075Sobrien	  RTVEC_ELT (p, i) =
1269090075Sobrien	    gen_rtx_SET (VOIDmode,
1269190075Sobrien			 gen_rtx_REG (reg_mode, info->first_gp_reg_save + i),
1269290075Sobrien			 mem);
1269390075Sobrien	}
1269490075Sobrien      emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
1269590075Sobrien    }
1269690075Sobrien  else
1269790075Sobrien    for (i = 0; i < 32 - info->first_gp_reg_save; i++)
1269890075Sobrien      if ((regs_ever_live[info->first_gp_reg_save+i]
12699146895Skan	   && (! call_used_regs[info->first_gp_reg_save+i]
12700146895Skan	       || (i+info->first_gp_reg_save == RS6000_PIC_OFFSET_TABLE_REGNUM
12701146895Skan		   && TARGET_TOC && TARGET_MINIMAL_TOC)))
1270296263Sobrien	  || (i+info->first_gp_reg_save == RS6000_PIC_OFFSET_TABLE_REGNUM
12703117395Skan	      && ((DEFAULT_ABI == ABI_V4 && flag_pic != 0)
1270490075Sobrien		  || (DEFAULT_ABI == ABI_DARWIN && flag_pic))))
1270590075Sobrien	{
1270690075Sobrien	  rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
1270790075Sobrien				   GEN_INT (info->gp_save_offset
1270890075Sobrien					    + sp_offset
1270990075Sobrien					    + reg_size * i));
1271090075Sobrien	  rtx mem = gen_rtx_MEM (reg_mode, addr);
1271190075Sobrien
12712117395Skan	  /* Restore 64-bit quantities for SPE.  */
12713132718Skan	  if (TARGET_SPE_ABI && info->spe_64bit_regs_used != 0)
12714117395Skan	    {
12715117395Skan	      int offset = info->spe_gp_save_offset + sp_offset + 8 * i;
12716117395Skan	      rtx b;
12717117395Skan
12718117395Skan	      if (!SPE_CONST_OFFSET_OK (offset))
12719117395Skan		{
12720117395Skan		  b = gen_rtx_REG (Pmode, FIXED_SCRATCH);
12721117395Skan		  emit_move_insn (b, GEN_INT (offset));
12722117395Skan		}
12723117395Skan	      else
12724117395Skan		b = GEN_INT (offset);
12725117395Skan
12726117395Skan	      addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, b);
12727117395Skan	      mem = gen_rtx_MEM (V2SImode, addr);
12728117395Skan	    }
12729117395Skan
1273090075Sobrien	  set_mem_alias_set (mem, rs6000_sr_alias_set);
1273190075Sobrien
1273290075Sobrien	  emit_move_insn (gen_rtx_REG (reg_mode,
12733117395Skan				       info->first_gp_reg_save + i), mem);
1273490075Sobrien	}
1273590075Sobrien
1273690075Sobrien  /* Restore fpr's if we need to do it without calling a function.  */
1273790075Sobrien  if (restoring_FPRs_inline)
1273890075Sobrien    for (i = 0; i < 64 - info->first_fp_reg_save; i++)
1273990075Sobrien      if ((regs_ever_live[info->first_fp_reg_save+i]
1274090075Sobrien	   && ! call_used_regs[info->first_fp_reg_save+i]))
1274190075Sobrien	{
1274290075Sobrien	  rtx addr, mem;
1274390075Sobrien	  addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
1274490075Sobrien			       GEN_INT (info->fp_save_offset
1274590075Sobrien					+ sp_offset
1274690075Sobrien					+ 8 * i));
1274790075Sobrien	  mem = gen_rtx_MEM (DFmode, addr);
1274890075Sobrien	  set_mem_alias_set (mem, rs6000_sr_alias_set);
1274990075Sobrien
1275090075Sobrien	  emit_move_insn (gen_rtx_REG (DFmode,
1275190075Sobrien				       info->first_fp_reg_save + i),
1275290075Sobrien			  mem);
1275390075Sobrien	}
1275490075Sobrien
1275590075Sobrien  /* If we saved cr, restore it here.  Just those that were used.  */
1275690075Sobrien  if (info->cr_save_p)
1275790075Sobrien    {
1275890075Sobrien      rtx r12_rtx = gen_rtx_REG (SImode, 12);
1275990075Sobrien      int count = 0;
1276090075Sobrien
1276190075Sobrien      if (using_mfcr_multiple)
1276290075Sobrien	{
1276390075Sobrien	  for (i = 0; i < 8; i++)
1276490075Sobrien	    if (regs_ever_live[CR0_REGNO+i] && ! call_used_regs[CR0_REGNO+i])
1276590075Sobrien	      count++;
1276690075Sobrien	  if (count == 0)
1276790075Sobrien	    abort ();
1276890075Sobrien	}
1276990075Sobrien
1277090075Sobrien      if (using_mfcr_multiple && count > 1)
1277190075Sobrien	{
1277290075Sobrien	  rtvec p;
1277390075Sobrien	  int ndx;
1277490075Sobrien
1277590075Sobrien	  p = rtvec_alloc (count);
1277690075Sobrien
1277790075Sobrien	  ndx = 0;
1277890075Sobrien	  for (i = 0; i < 8; i++)
1277990075Sobrien	    if (regs_ever_live[CR0_REGNO+i] && ! call_used_regs[CR0_REGNO+i])
1278090075Sobrien	      {
1278190075Sobrien		rtvec r = rtvec_alloc (2);
1278290075Sobrien		RTVEC_ELT (r, 0) = r12_rtx;
1278390075Sobrien		RTVEC_ELT (r, 1) = GEN_INT (1 << (7-i));
1278490075Sobrien		RTVEC_ELT (p, ndx) =
1278590075Sobrien		  gen_rtx_SET (VOIDmode, gen_rtx_REG (CCmode, CR0_REGNO+i),
12786132718Skan			       gen_rtx_UNSPEC (CCmode, r, UNSPEC_MOVESI_TO_CR));
1278790075Sobrien		ndx++;
1278890075Sobrien	      }
1278990075Sobrien	  emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
1279090075Sobrien	  if (ndx != count)
1279190075Sobrien	    abort ();
1279290075Sobrien	}
1279390075Sobrien      else
1279490075Sobrien	for (i = 0; i < 8; i++)
1279590075Sobrien	  if (regs_ever_live[CR0_REGNO+i] && ! call_used_regs[CR0_REGNO+i])
1279690075Sobrien	    {
1279790075Sobrien	      emit_insn (gen_movsi_to_cr_one (gen_rtx_REG (CCmode,
1279890075Sobrien							   CR0_REGNO+i),
1279990075Sobrien					      r12_rtx));
1280090075Sobrien	    }
1280190075Sobrien    }
1280290075Sobrien
1280390075Sobrien  /* If this is V.4, unwind the stack pointer after all of the loads
1280490075Sobrien     have been done.  We need to emit a block here so that sched
1280590075Sobrien     doesn't decide to move the sp change before the register restores
1280690075Sobrien     (which may not have any obvious dependency on the stack).  This
1280790075Sobrien     doesn't hurt performance, because there is no scheduling that can
1280890075Sobrien     be done after this point.  */
12809132718Skan  if (DEFAULT_ABI == ABI_V4
12810132718Skan      || current_function_calls_eh_return)
1281190075Sobrien    {
1281290075Sobrien      if (frame_reg_rtx != sp_reg_rtx)
1281390075Sobrien	  rs6000_emit_stack_tie ();
1281490075Sobrien
1281590075Sobrien      if (use_backchain_to_restore_sp)
1281690075Sobrien	{
1281790075Sobrien	  emit_move_insn (sp_reg_rtx, frame_reg_rtx);
1281890075Sobrien	}
1281990075Sobrien      else if (sp_offset != 0)
1282090075Sobrien	{
12821132718Skan	  emit_insn (TARGET_32BIT
1282290075Sobrien		     ? gen_addsi3 (sp_reg_rtx, sp_reg_rtx,
1282390075Sobrien				   GEN_INT (sp_offset))
1282490075Sobrien		     : gen_adddi3 (sp_reg_rtx, sp_reg_rtx,
1282590075Sobrien				   GEN_INT (sp_offset)));
1282690075Sobrien	}
1282790075Sobrien    }
1282890075Sobrien
1282990075Sobrien  if (current_function_calls_eh_return)
1283090075Sobrien    {
1283190075Sobrien      rtx sa = EH_RETURN_STACKADJ_RTX;
12832132718Skan      emit_insn (TARGET_32BIT
1283390075Sobrien		 ? gen_addsi3 (sp_reg_rtx, sp_reg_rtx, sa)
1283490075Sobrien		 : gen_adddi3 (sp_reg_rtx, sp_reg_rtx, sa));
1283590075Sobrien    }
1283690075Sobrien
1283790075Sobrien  if (!sibcall)
1283890075Sobrien    {
1283990075Sobrien      rtvec p;
1284090075Sobrien      if (! restoring_FPRs_inline)
1284190075Sobrien	p = rtvec_alloc (3 + 64 - info->first_fp_reg_save);
1284290075Sobrien      else
1284390075Sobrien	p = rtvec_alloc (2);
1284490075Sobrien
1284590075Sobrien      RTVEC_ELT (p, 0) = gen_rtx_RETURN (VOIDmode);
1284690075Sobrien      RTVEC_ELT (p, 1) = gen_rtx_USE (VOIDmode,
1284790075Sobrien				      gen_rtx_REG (Pmode,
1284890075Sobrien						   LINK_REGISTER_REGNUM));
1284990075Sobrien
1285090075Sobrien      /* If we have to restore more than two FP registers, branch to the
1285190075Sobrien	 restore function.  It will return to our caller.  */
1285290075Sobrien      if (! restoring_FPRs_inline)
1285390075Sobrien	{
1285490075Sobrien	  int i;
1285590075Sobrien	  char rname[30];
1285690075Sobrien	  const char *alloc_rname;
1285790075Sobrien
1285890075Sobrien	  sprintf (rname, "%s%d%s", RESTORE_FP_PREFIX,
1285990075Sobrien		   info->first_fp_reg_save - 32, RESTORE_FP_SUFFIX);
1286090075Sobrien	  alloc_rname = ggc_strdup (rname);
1286190075Sobrien	  RTVEC_ELT (p, 2) = gen_rtx_USE (VOIDmode,
1286290075Sobrien					  gen_rtx_SYMBOL_REF (Pmode,
1286390075Sobrien							      alloc_rname));
1286490075Sobrien
1286590075Sobrien	  for (i = 0; i < 64 - info->first_fp_reg_save; i++)
1286690075Sobrien	    {
1286790075Sobrien	      rtx addr, mem;
1286890075Sobrien	      addr = gen_rtx_PLUS (Pmode, sp_reg_rtx,
1286990075Sobrien				   GEN_INT (info->fp_save_offset + 8*i));
1287090075Sobrien	      mem = gen_rtx_MEM (DFmode, addr);
1287190075Sobrien	      set_mem_alias_set (mem, rs6000_sr_alias_set);
1287290075Sobrien
1287390075Sobrien	      RTVEC_ELT (p, i+3) =
1287490075Sobrien		gen_rtx_SET (VOIDmode,
1287590075Sobrien			     gen_rtx_REG (DFmode, info->first_fp_reg_save + i),
1287690075Sobrien			     mem);
1287790075Sobrien	    }
1287890075Sobrien	}
1287990075Sobrien
1288090075Sobrien      emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, p));
1288190075Sobrien    }
1288290075Sobrien}
1288390075Sobrien
1288490075Sobrien/* Write function epilogue.  */
1288590075Sobrien
1288690075Sobrienstatic void
12887132718Skanrs6000_output_function_epilogue (FILE *file,
12888132718Skan				 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
1288990075Sobrien{
1289090075Sobrien  rs6000_stack_t *info = rs6000_stack_info ();
1289190075Sobrien
1289290075Sobrien  if (! HAVE_epilogue)
1289390075Sobrien    {
1289490075Sobrien      rtx insn = get_last_insn ();
1289590075Sobrien      /* If the last insn was a BARRIER, we don't have to write anything except
1289690075Sobrien	 the trace table.  */
1289790075Sobrien      if (GET_CODE (insn) == NOTE)
1289890075Sobrien	insn = prev_nonnote_insn (insn);
1289990075Sobrien      if (insn == 0 ||  GET_CODE (insn) != BARRIER)
1290090075Sobrien	{
1290190075Sobrien	  /* This is slightly ugly, but at least we don't have two
1290290075Sobrien	     copies of the epilogue-emitting code.  */
1290390075Sobrien	  start_sequence ();
1290490075Sobrien
1290590075Sobrien	  /* A NOTE_INSN_DELETED is supposed to be at the start
1290690075Sobrien	     and end of the "toplevel" insn chain.  */
12907132718Skan	  emit_note (NOTE_INSN_DELETED);
1290890075Sobrien	  rs6000_emit_epilogue (FALSE);
12909132718Skan	  emit_note (NOTE_INSN_DELETED);
1291090075Sobrien
12911132718Skan	  /* Expand INSN_ADDRESSES so final() doesn't crash.  */
1291296263Sobrien	  {
1291396263Sobrien	    rtx insn;
1291496263Sobrien	    unsigned addr = 0;
1291596263Sobrien	    for (insn = get_insns (); insn != 0; insn = NEXT_INSN (insn))
1291696263Sobrien	      {
1291796263Sobrien		INSN_ADDRESSES_NEW (insn, addr);
1291896263Sobrien		addr += 4;
1291996263Sobrien	      }
1292096263Sobrien	  }
1292196263Sobrien
1292290075Sobrien	  if (TARGET_DEBUG_STACK)
1292390075Sobrien	    debug_rtx_list (get_insns (), 100);
1292490075Sobrien	  final (get_insns (), file, FALSE, FALSE);
1292590075Sobrien	  end_sequence ();
1292690075Sobrien	}
1292790075Sobrien    }
1292890075Sobrien
12929132718Skan#if TARGET_MACHO
12930132718Skan  macho_branch_islands ();
12931119256Skan  /* Mach-O doesn't support labels at the end of objects, so if
12932119256Skan     it looks like we might want one, insert a NOP.  */
12933119256Skan  {
12934119256Skan    rtx insn = get_last_insn ();
12935119256Skan    while (insn
12936119256Skan	   && NOTE_P (insn)
12937119256Skan	   && NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED_LABEL)
12938119256Skan      insn = PREV_INSN (insn);
12939119256Skan    if (insn
12940119256Skan	&& (LABEL_P (insn)
12941119256Skan	    || (NOTE_P (insn)
12942119256Skan		&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED_LABEL)))
12943119256Skan      fputs ("\tnop\n", file);
12944119256Skan  }
12945119256Skan#endif
12946119256Skan
1294790075Sobrien  /* Output a traceback table here.  See /usr/include/sys/debug.h for info
1294890075Sobrien     on its format.
1294990075Sobrien
1295090075Sobrien     We don't output a traceback table if -finhibit-size-directive was
1295190075Sobrien     used.  The documentation for -finhibit-size-directive reads
1295290075Sobrien     ``don't output a @code{.size} assembler directive, or anything
1295390075Sobrien     else that would cause trouble if the function is split in the
1295490075Sobrien     middle, and the two halves are placed at locations far apart in
1295590075Sobrien     memory.''  The traceback table has this property, since it
1295690075Sobrien     includes the offset from the start of the function to the
1295790075Sobrien     traceback table itself.
1295890075Sobrien
1295990075Sobrien     System V.4 Powerpc's (and the embedded ABI derived from it) use a
1296090075Sobrien     different traceback table.  */
12961117395Skan  if (DEFAULT_ABI == ABI_AIX && ! flag_inhibit_size_directive
12962117395Skan      && rs6000_traceback != traceback_none)
1296390075Sobrien    {
12964117395Skan      const char *fname = NULL;
1296590075Sobrien      const char *language_string = lang_hooks.name;
1296690075Sobrien      int fixed_parms = 0, float_parms = 0, parm_info = 0;
1296790075Sobrien      int i;
12968117395Skan      int optional_tbtab;
1296990075Sobrien
12970117395Skan      if (rs6000_traceback == traceback_full)
12971117395Skan	optional_tbtab = 1;
12972117395Skan      else if (rs6000_traceback == traceback_part)
12973117395Skan	optional_tbtab = 0;
12974117395Skan      else
12975117395Skan	optional_tbtab = !optimize_size && !TARGET_ELF;
1297690075Sobrien
12977117395Skan      if (optional_tbtab)
12978117395Skan	{
12979117395Skan	  fname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
12980117395Skan	  while (*fname == '.')	/* V.4 encodes . in the name */
12981117395Skan	    fname++;
1298290075Sobrien
12983117395Skan	  /* Need label immediately before tbtab, so we can compute
12984117395Skan	     its offset from the function start.  */
12985117395Skan	  ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "LT");
12986117395Skan	  ASM_OUTPUT_LABEL (file, fname);
12987117395Skan	}
12988117395Skan
1298990075Sobrien      /* The .tbtab pseudo-op can only be used for the first eight
1299090075Sobrien	 expressions, since it can't handle the possibly variable
1299190075Sobrien	 length fields that follow.  However, if you omit the optional
1299290075Sobrien	 fields, the assembler outputs zeros for all optional fields
1299390075Sobrien	 anyways, giving each variable length field is minimum length
1299490075Sobrien	 (as defined in sys/debug.h).  Thus we can not use the .tbtab
1299590075Sobrien	 pseudo-op at all.  */
1299690075Sobrien
1299790075Sobrien      /* An all-zero word flags the start of the tbtab, for debuggers
1299890075Sobrien	 that have to find it by searching forward from the entry
1299990075Sobrien	 point or from the current pc.  */
1300090075Sobrien      fputs ("\t.long 0\n", file);
1300190075Sobrien
1300290075Sobrien      /* Tbtab format type.  Use format type 0.  */
1300390075Sobrien      fputs ("\t.byte 0,", file);
1300490075Sobrien
13005132718Skan      /* Language type.  Unfortunately, there does not seem to be any
13006132718Skan	 official way to discover the language being compiled, so we
13007132718Skan	 use language_string.
13008132718Skan	 C is 0.  Fortran is 1.  Pascal is 2.  Ada is 3.  C++ is 9.
13009132718Skan	 Java is 13.  Objective-C is 14.  */
13010132718Skan      if (! strcmp (language_string, "GNU C"))
1301190075Sobrien	i = 0;
1301290075Sobrien      else if (! strcmp (language_string, "GNU F77"))
1301390075Sobrien	i = 1;
13014132718Skan      else if (! strcmp (language_string, "GNU Pascal"))
13015132718Skan	i = 2;
1301690075Sobrien      else if (! strcmp (language_string, "GNU Ada"))
1301790075Sobrien	i = 3;
1301890075Sobrien      else if (! strcmp (language_string, "GNU C++"))
1301990075Sobrien	i = 9;
1302090075Sobrien      else if (! strcmp (language_string, "GNU Java"))
1302190075Sobrien	i = 13;
13022132718Skan      else if (! strcmp (language_string, "GNU Objective-C"))
13023132718Skan	i = 14;
1302490075Sobrien      else
1302590075Sobrien	abort ();
1302690075Sobrien      fprintf (file, "%d,", i);
1302790075Sobrien
1302890075Sobrien      /* 8 single bit fields: global linkage (not set for C extern linkage,
1302990075Sobrien	 apparently a PL/I convention?), out-of-line epilogue/prologue, offset
1303090075Sobrien	 from start of procedure stored in tbtab, internal function, function
1303190075Sobrien	 has controlled storage, function has no toc, function uses fp,
1303290075Sobrien	 function logs/aborts fp operations.  */
1303390075Sobrien      /* Assume that fp operations are used if any fp reg must be saved.  */
1303490075Sobrien      fprintf (file, "%d,",
1303590075Sobrien	       (optional_tbtab << 5) | ((info->first_fp_reg_save != 64) << 1));
1303690075Sobrien
1303790075Sobrien      /* 6 bitfields: function is interrupt handler, name present in
1303890075Sobrien	 proc table, function calls alloca, on condition directives
1303990075Sobrien	 (controls stack walks, 3 bits), saves condition reg, saves
1304090075Sobrien	 link reg.  */
1304190075Sobrien      /* The `function calls alloca' bit seems to be set whenever reg 31 is
1304290075Sobrien	 set up as a frame pointer, even when there is no alloca call.  */
1304390075Sobrien      fprintf (file, "%d,",
1304490075Sobrien	       ((optional_tbtab << 6)
1304590075Sobrien		| ((optional_tbtab & frame_pointer_needed) << 5)
1304690075Sobrien		| (info->cr_save_p << 1)
1304790075Sobrien		| (info->lr_save_p)));
1304890075Sobrien
1304990075Sobrien      /* 3 bitfields: saves backchain, fixup code, number of fpr saved
1305090075Sobrien	 (6 bits).  */
1305190075Sobrien      fprintf (file, "%d,",
1305290075Sobrien	       (info->push_p << 7) | (64 - info->first_fp_reg_save));
1305390075Sobrien
1305490075Sobrien      /* 2 bitfields: spare bits (2 bits), number of gpr saved (6 bits).  */
1305590075Sobrien      fprintf (file, "%d,", (32 - first_reg_to_save ()));
1305690075Sobrien
1305790075Sobrien      if (optional_tbtab)
1305890075Sobrien	{
1305990075Sobrien	  /* Compute the parameter info from the function decl argument
1306090075Sobrien	     list.  */
1306190075Sobrien	  tree decl;
1306290075Sobrien	  int next_parm_info_bit = 31;
1306390075Sobrien
1306490075Sobrien	  for (decl = DECL_ARGUMENTS (current_function_decl);
1306590075Sobrien	       decl; decl = TREE_CHAIN (decl))
1306690075Sobrien	    {
1306790075Sobrien	      rtx parameter = DECL_INCOMING_RTL (decl);
1306890075Sobrien	      enum machine_mode mode = GET_MODE (parameter);
1306990075Sobrien
1307090075Sobrien	      if (GET_CODE (parameter) == REG)
1307190075Sobrien		{
1307290075Sobrien		  if (GET_MODE_CLASS (mode) == MODE_FLOAT)
1307390075Sobrien		    {
1307490075Sobrien		      int bits;
1307590075Sobrien
1307690075Sobrien		      float_parms++;
1307790075Sobrien
1307890075Sobrien		      if (mode == SFmode)
1307990075Sobrien			bits = 0x2;
13080117395Skan		      else if (mode == DFmode || mode == TFmode)
1308190075Sobrien			bits = 0x3;
1308290075Sobrien		      else
1308390075Sobrien			abort ();
1308490075Sobrien
1308590075Sobrien		      /* If only one bit will fit, don't or in this entry.  */
1308690075Sobrien		      if (next_parm_info_bit > 0)
1308790075Sobrien			parm_info |= (bits << (next_parm_info_bit - 1));
1308890075Sobrien		      next_parm_info_bit -= 2;
1308990075Sobrien		    }
1309090075Sobrien		  else
1309190075Sobrien		    {
1309290075Sobrien		      fixed_parms += ((GET_MODE_SIZE (mode)
1309390075Sobrien				       + (UNITS_PER_WORD - 1))
1309490075Sobrien				      / UNITS_PER_WORD);
1309590075Sobrien		      next_parm_info_bit -= 1;
1309690075Sobrien		    }
1309790075Sobrien		}
1309890075Sobrien	    }
1309990075Sobrien	}
1310090075Sobrien
1310190075Sobrien      /* Number of fixed point parameters.  */
1310290075Sobrien      /* This is actually the number of words of fixed point parameters; thus
1310390075Sobrien	 an 8 byte struct counts as 2; and thus the maximum value is 8.  */
1310490075Sobrien      fprintf (file, "%d,", fixed_parms);
1310590075Sobrien
1310690075Sobrien      /* 2 bitfields: number of floating point parameters (7 bits), parameters
1310790075Sobrien	 all on stack.  */
1310890075Sobrien      /* This is actually the number of fp registers that hold parameters;
1310990075Sobrien	 and thus the maximum value is 13.  */
1311090075Sobrien      /* Set parameters on stack bit if parameters are not in their original
1311190075Sobrien	 registers, regardless of whether they are on the stack?  Xlc
1311290075Sobrien	 seems to set the bit when not optimizing.  */
1311390075Sobrien      fprintf (file, "%d\n", ((float_parms << 1) | (! optimize)));
1311490075Sobrien
1311590075Sobrien      if (! optional_tbtab)
1311690075Sobrien	return;
1311790075Sobrien
1311890075Sobrien      /* Optional fields follow.  Some are variable length.  */
1311990075Sobrien
1312090075Sobrien      /* Parameter types, left adjusted bit fields: 0 fixed, 10 single float,
1312190075Sobrien	 11 double float.  */
1312290075Sobrien      /* There is an entry for each parameter in a register, in the order that
1312390075Sobrien	 they occur in the parameter list.  Any intervening arguments on the
1312490075Sobrien	 stack are ignored.  If the list overflows a long (max possible length
1312590075Sobrien	 34 bits) then completely leave off all elements that don't fit.  */
1312690075Sobrien      /* Only emit this long if there was at least one parameter.  */
1312790075Sobrien      if (fixed_parms || float_parms)
1312890075Sobrien	fprintf (file, "\t.long %d\n", parm_info);
1312990075Sobrien
1313090075Sobrien      /* Offset from start of code to tb table.  */
1313190075Sobrien      fputs ("\t.long ", file);
1313290075Sobrien      ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "LT");
1313390075Sobrien#if TARGET_AIX
1313490075Sobrien      RS6000_OUTPUT_BASENAME (file, fname);
1313590075Sobrien#else
1313690075Sobrien      assemble_name (file, fname);
1313790075Sobrien#endif
1313890075Sobrien      fputs ("-.", file);
1313990075Sobrien#if TARGET_AIX
1314090075Sobrien      RS6000_OUTPUT_BASENAME (file, fname);
1314190075Sobrien#else
1314290075Sobrien      assemble_name (file, fname);
1314390075Sobrien#endif
1314490075Sobrien      putc ('\n', file);
1314590075Sobrien
1314690075Sobrien      /* Interrupt handler mask.  */
1314790075Sobrien      /* Omit this long, since we never set the interrupt handler bit
1314890075Sobrien	 above.  */
1314990075Sobrien
1315090075Sobrien      /* Number of CTL (controlled storage) anchors.  */
1315190075Sobrien      /* Omit this long, since the has_ctl bit is never set above.  */
1315290075Sobrien
1315390075Sobrien      /* Displacement into stack of each CTL anchor.  */
1315490075Sobrien      /* Omit this list of longs, because there are no CTL anchors.  */
1315590075Sobrien
1315690075Sobrien      /* Length of function name.  */
13157117395Skan      if (*fname == '*')
13158117395Skan	++fname;
1315990075Sobrien      fprintf (file, "\t.short %d\n", (int) strlen (fname));
1316090075Sobrien
1316190075Sobrien      /* Function name.  */
1316290075Sobrien      assemble_string (fname, strlen (fname));
1316390075Sobrien
1316490075Sobrien      /* Register for alloca automatic storage; this is always reg 31.
1316590075Sobrien	 Only emit this if the alloca bit was set above.  */
1316690075Sobrien      if (frame_pointer_needed)
1316790075Sobrien	fputs ("\t.byte 31\n", file);
1316896263Sobrien
1316996263Sobrien      fputs ("\t.align 2\n", file);
1317090075Sobrien    }
1317190075Sobrien}
1317290075Sobrien
1317390075Sobrien/* A C compound statement that outputs the assembler code for a thunk
1317490075Sobrien   function, used to implement C++ virtual function calls with
1317590075Sobrien   multiple inheritance.  The thunk acts as a wrapper around a virtual
1317690075Sobrien   function, adjusting the implicit object parameter before handing
1317790075Sobrien   control off to the real function.
1317890075Sobrien
1317990075Sobrien   First, emit code to add the integer DELTA to the location that
1318090075Sobrien   contains the incoming first argument.  Assume that this argument
1318190075Sobrien   contains a pointer, and is the one used to pass the `this' pointer
1318290075Sobrien   in C++.  This is the incoming argument *before* the function
1318390075Sobrien   prologue, e.g. `%o0' on a sparc.  The addition must preserve the
1318490075Sobrien   values of all other incoming arguments.
1318590075Sobrien
1318690075Sobrien   After the addition, emit code to jump to FUNCTION, which is a
1318790075Sobrien   `FUNCTION_DECL'.  This is a direct pure jump, not a call, and does
1318890075Sobrien   not touch the return address.  Hence returning from FUNCTION will
1318990075Sobrien   return to whoever called the current `thunk'.
1319090075Sobrien
1319190075Sobrien   The effect must be as if FUNCTION had been called directly with the
1319290075Sobrien   adjusted first argument.  This macro is responsible for emitting
1319390075Sobrien   all of the code for a thunk function; output_function_prologue()
1319490075Sobrien   and output_function_epilogue() are not invoked.
1319590075Sobrien
1319690075Sobrien   The THUNK_FNDECL is redundant.  (DELTA and FUNCTION have already
1319790075Sobrien   been extracted from it.)  It might possibly be useful on some
1319890075Sobrien   targets, but probably not.
1319990075Sobrien
1320090075Sobrien   If you do not define this macro, the target-independent code in the
1320190075Sobrien   C++ frontend will generate a less efficient heavyweight thunk that
1320290075Sobrien   calls FUNCTION instead of jumping to it.  The generic approach does
1320390075Sobrien   not support varargs.  */
1320490075Sobrien
13205117395Skanstatic void
13206132718Skanrs6000_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
13207132718Skan			HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
13208132718Skan			tree function)
1320990075Sobrien{
13210132718Skan  rtx this, insn, funexp;
1321190075Sobrien
13212132718Skan  reload_completed = 1;
13213132718Skan  epilogue_completed = 1;
13214132718Skan  no_new_pseudos = 1;
1321590075Sobrien
13216132718Skan  /* Mark the end of the (empty) prologue.  */
13217132718Skan  emit_note (NOTE_INSN_PROLOGUE_END);
13218102780Skan
13219132718Skan  /* Find the "this" pointer.  If the function returns a structure,
13220132718Skan     the structure return pointer is in r3.  */
13221132718Skan  if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
13222132718Skan    this = gen_rtx_REG (Pmode, 4);
13223132718Skan  else
13224132718Skan    this = gen_rtx_REG (Pmode, 3);
1322590075Sobrien
13226132718Skan  /* Apply the constant offset, if required.  */
13227132718Skan  if (delta)
1322890075Sobrien    {
13229132718Skan      rtx delta_rtx = GEN_INT (delta);
13230132718Skan      emit_insn (TARGET_32BIT
13231132718Skan		 ? gen_addsi3 (this, this, delta_rtx)
13232132718Skan		 : gen_adddi3 (this, this, delta_rtx));
1323390075Sobrien    }
1323490075Sobrien
13235132718Skan  /* Apply the offset from the vtable, if required.  */
13236132718Skan  if (vcall_offset)
1323790075Sobrien    {
13238132718Skan      rtx vcall_offset_rtx = GEN_INT (vcall_offset);
13239132718Skan      rtx tmp = gen_rtx_REG (Pmode, 12);
1324090075Sobrien
13241132718Skan      emit_move_insn (tmp, gen_rtx_MEM (Pmode, this));
13242132718Skan      if (((unsigned HOST_WIDE_INT) vcall_offset) + 0x8000 >= 0x10000)
13243132718Skan	{
13244132718Skan	  emit_insn (TARGET_32BIT
13245132718Skan		     ? gen_addsi3 (tmp, tmp, vcall_offset_rtx)
13246132718Skan		     : gen_adddi3 (tmp, tmp, vcall_offset_rtx));
13247132718Skan	  emit_move_insn (tmp, gen_rtx_MEM (Pmode, tmp));
13248132718Skan	}
13249132718Skan      else
13250132718Skan	{
13251132718Skan	  rtx loc = gen_rtx_PLUS (Pmode, tmp, vcall_offset_rtx);
1325290075Sobrien
13253132718Skan	  emit_move_insn (tmp, gen_rtx_MEM (Pmode, loc));
13254132718Skan	}
13255132718Skan      emit_insn (TARGET_32BIT
13256132718Skan		 ? gen_addsi3 (this, this, tmp)
13257132718Skan		 : gen_adddi3 (this, this, tmp));
1325890075Sobrien    }
1325990075Sobrien
13260132718Skan  /* Generate a tail call to the target function.  */
13261132718Skan  if (!TREE_USED (function))
1326290075Sobrien    {
13263132718Skan      assemble_external (function);
13264132718Skan      TREE_USED (function) = 1;
1326590075Sobrien    }
13266132718Skan  funexp = XEXP (DECL_RTL (function), 0);
13267132718Skan  funexp = gen_rtx_MEM (FUNCTION_MODE, funexp);
1326890075Sobrien
13269132718Skan#if TARGET_MACHO
13270132718Skan  if (MACHOPIC_INDIRECT)
13271132718Skan    funexp = machopic_indirect_call_target (funexp);
13272132718Skan#endif
1327390075Sobrien
13274132718Skan  /* gen_sibcall expects reload to convert scratch pseudo to LR so we must
13275132718Skan     generate sibcall RTL explicitly to avoid constraint abort.  */
13276132718Skan  insn = emit_call_insn (
13277132718Skan	   gen_rtx_PARALLEL (VOIDmode,
13278132718Skan	     gen_rtvec (4,
13279132718Skan			gen_rtx_CALL (VOIDmode,
13280132718Skan				      funexp, const0_rtx),
13281132718Skan			gen_rtx_USE (VOIDmode, const0_rtx),
13282132718Skan			gen_rtx_USE (VOIDmode,
13283132718Skan				     gen_rtx_REG (SImode,
13284132718Skan						  LINK_REGISTER_REGNUM)),
13285132718Skan			gen_rtx_RETURN (VOIDmode))));
13286132718Skan  SIBLING_CALL_P (insn) = 1;
13287132718Skan  emit_barrier ();
1328890075Sobrien
13289132718Skan  /* Run just enough of rest_of_compilation to get the insns emitted.
13290132718Skan     There's not really enough bulk here to make other passes such as
13291132718Skan     instruction scheduling worth while.  Note that use_thunk calls
13292132718Skan     assemble_start_function and assemble_end_function.  */
13293132718Skan  insn = get_insns ();
13294132718Skan  insn_locators_initialize ();
13295132718Skan  shorten_branches (insn);
13296132718Skan  final_start_function (insn, file, 1);
13297132718Skan  final (insn, file, 1, 0);
13298132718Skan  final_end_function ();
1329990075Sobrien
13300132718Skan  reload_completed = 0;
13301132718Skan  epilogue_completed = 0;
13302132718Skan  no_new_pseudos = 0;
1330390075Sobrien}
1330490075Sobrien
1330590075Sobrien/* A quick summary of the various types of 'constant-pool tables'
1330690075Sobrien   under PowerPC:
1330790075Sobrien
1330890075Sobrien   Target	Flags		Name		One table per
1330990075Sobrien   AIX		(none)		AIX TOC		object file
1331090075Sobrien   AIX		-mfull-toc	AIX TOC		object file
1331190075Sobrien   AIX		-mminimal-toc	AIX minimal TOC	translation unit
1331290075Sobrien   SVR4/EABI	(none)		SVR4 SDATA	object file
1331390075Sobrien   SVR4/EABI	-fpic		SVR4 pic	object file
1331490075Sobrien   SVR4/EABI	-fPIC		SVR4 PIC	translation unit
1331590075Sobrien   SVR4/EABI	-mrelocatable	EABI TOC	function
1331690075Sobrien   SVR4/EABI	-maix		AIX TOC		object file
1331790075Sobrien   SVR4/EABI	-maix -mminimal-toc
1331890075Sobrien				AIX minimal TOC	translation unit
1331990075Sobrien
1332090075Sobrien   Name			Reg.	Set by	entries	      contains:
1332190075Sobrien					made by	 addrs?	fp?	sum?
1332290075Sobrien
1332390075Sobrien   AIX TOC		2	crt0	as	 Y	option	option
1332490075Sobrien   AIX minimal TOC	30	prolog	gcc	 Y	Y	option
1332590075Sobrien   SVR4 SDATA		13	crt0	gcc	 N	Y	N
1332690075Sobrien   SVR4 pic		30	prolog	ld	 Y	not yet	N
1332790075Sobrien   SVR4 PIC		30	prolog	gcc	 Y	option	option
1332890075Sobrien   EABI TOC		30	prolog	gcc	 Y	option	option
1332990075Sobrien
1333090075Sobrien*/
1333190075Sobrien
1333290075Sobrien/* Hash functions for the hash table.  */
1333390075Sobrien
1333490075Sobrienstatic unsigned
13335132718Skanrs6000_hash_constant (rtx k)
1333690075Sobrien{
13337117395Skan  enum rtx_code code = GET_CODE (k);
13338117395Skan  enum machine_mode mode = GET_MODE (k);
13339117395Skan  unsigned result = (code << 3) ^ mode;
13340117395Skan  const char *format;
13341117395Skan  int flen, fidx;
1334290075Sobrien
13343117395Skan  format = GET_RTX_FORMAT (code);
13344117395Skan  flen = strlen (format);
13345117395Skan  fidx = 0;
1334690075Sobrien
13347117395Skan  switch (code)
13348117395Skan    {
13349117395Skan    case LABEL_REF:
13350117395Skan      return result * 1231 + (unsigned) INSN_UID (XEXP (k, 0));
1335190075Sobrien
13352117395Skan    case CONST_DOUBLE:
13353117395Skan      if (mode != VOIDmode)
13354117395Skan	return real_hash (CONST_DOUBLE_REAL_VALUE (k)) * result;
13355117395Skan      flen = 2;
13356117395Skan      break;
13357117395Skan
13358117395Skan    case CODE_LABEL:
13359117395Skan      fidx = 3;
13360117395Skan      break;
13361117395Skan
13362117395Skan    default:
13363117395Skan      break;
13364117395Skan    }
13365117395Skan
1336690075Sobrien  for (; fidx < flen; fidx++)
1336790075Sobrien    switch (format[fidx])
1336890075Sobrien      {
1336990075Sobrien      case 's':
1337090075Sobrien	{
1337190075Sobrien	  unsigned i, len;
1337290075Sobrien	  const char *str = XSTR (k, fidx);
1337390075Sobrien	  len = strlen (str);
1337490075Sobrien	  result = result * 613 + len;
1337590075Sobrien	  for (i = 0; i < len; i++)
1337690075Sobrien	    result = result * 613 + (unsigned) str[i];
1337790075Sobrien	  break;
1337890075Sobrien	}
1337990075Sobrien      case 'u':
1338090075Sobrien      case 'e':
1338190075Sobrien	result = result * 1231 + rs6000_hash_constant (XEXP (k, fidx));
1338290075Sobrien	break;
1338390075Sobrien      case 'i':
1338490075Sobrien      case 'n':
1338590075Sobrien	result = result * 613 + (unsigned) XINT (k, fidx);
1338690075Sobrien	break;
1338790075Sobrien      case 'w':
1338890075Sobrien	if (sizeof (unsigned) >= sizeof (HOST_WIDE_INT))
1338990075Sobrien	  result = result * 613 + (unsigned) XWINT (k, fidx);
1339090075Sobrien	else
1339190075Sobrien	  {
1339290075Sobrien	    size_t i;
1339390075Sobrien	    for (i = 0; i < sizeof(HOST_WIDE_INT)/sizeof(unsigned); i++)
1339490075Sobrien	      result = result * 613 + (unsigned) (XWINT (k, fidx)
1339590075Sobrien						  >> CHAR_BIT * i);
1339690075Sobrien	  }
1339790075Sobrien	break;
13398132718Skan      case '0':
13399132718Skan	break;
1340090075Sobrien      default:
1340190075Sobrien	abort ();
1340290075Sobrien      }
13403117395Skan
1340490075Sobrien  return result;
1340590075Sobrien}
1340690075Sobrien
1340790075Sobrienstatic unsigned
13408132718Skantoc_hash_function (const void *hash_entry)
1340990075Sobrien{
1341090075Sobrien  const struct toc_hash_struct *thc =
1341190075Sobrien    (const struct toc_hash_struct *) hash_entry;
1341290075Sobrien  return rs6000_hash_constant (thc->key) ^ thc->key_mode;
1341390075Sobrien}
1341490075Sobrien
1341590075Sobrien/* Compare H1 and H2 for equivalence.  */
1341690075Sobrien
1341790075Sobrienstatic int
13418132718Skantoc_hash_eq (const void *h1, const void *h2)
1341990075Sobrien{
1342090075Sobrien  rtx r1 = ((const struct toc_hash_struct *) h1)->key;
1342190075Sobrien  rtx r2 = ((const struct toc_hash_struct *) h2)->key;
1342290075Sobrien
1342390075Sobrien  if (((const struct toc_hash_struct *) h1)->key_mode
1342490075Sobrien      != ((const struct toc_hash_struct *) h2)->key_mode)
1342590075Sobrien    return 0;
1342690075Sobrien
13427117395Skan  return rtx_equal_p (r1, r2);
1342890075Sobrien}
1342990075Sobrien
1343090075Sobrien/* These are the names given by the C++ front-end to vtables, and
1343190075Sobrien   vtable-like objects.  Ideally, this logic should not be here;
1343290075Sobrien   instead, there should be some programmatic way of inquiring as
1343390075Sobrien   to whether or not an object is a vtable.  */
1343490075Sobrien
1343590075Sobrien#define VTABLE_NAME_P(NAME)				\
1343690075Sobrien  (strncmp ("_vt.", name, strlen("_vt.")) == 0		\
1343790075Sobrien  || strncmp ("_ZTV", name, strlen ("_ZTV")) == 0	\
1343890075Sobrien  || strncmp ("_ZTT", name, strlen ("_ZTT")) == 0	\
13439132718Skan  || strncmp ("_ZTI", name, strlen ("_ZTI")) == 0	\
1344090075Sobrien  || strncmp ("_ZTC", name, strlen ("_ZTC")) == 0)
1344190075Sobrien
1344290075Sobrienvoid
13443132718Skanrs6000_output_symbol_ref (FILE *file, rtx x)
1344490075Sobrien{
1344590075Sobrien  /* Currently C++ toc references to vtables can be emitted before it
1344690075Sobrien     is decided whether the vtable is public or private.  If this is
1344790075Sobrien     the case, then the linker will eventually complain that there is
1344890075Sobrien     a reference to an unknown section.  Thus, for vtables only,
1344990075Sobrien     we emit the TOC reference to reference the symbol and not the
1345090075Sobrien     section.  */
1345190075Sobrien  const char *name = XSTR (x, 0);
1345290075Sobrien
1345390075Sobrien  if (VTABLE_NAME_P (name))
1345490075Sobrien    {
1345590075Sobrien      RS6000_OUTPUT_BASENAME (file, name);
1345690075Sobrien    }
1345790075Sobrien  else
1345890075Sobrien    assemble_name (file, name);
1345990075Sobrien}
1346090075Sobrien
1346190075Sobrien/* Output a TOC entry.  We derive the entry name from what is being
1346290075Sobrien   written.  */
1346390075Sobrien
1346490075Sobrienvoid
13465132718Skanoutput_toc (FILE *file, rtx x, int labelno, enum machine_mode mode)
1346690075Sobrien{
1346790075Sobrien  char buf[256];
1346890075Sobrien  const char *name = buf;
1346990075Sobrien  const char *real_name;
1347090075Sobrien  rtx base = x;
1347190075Sobrien  int offset = 0;
1347290075Sobrien
1347390075Sobrien  if (TARGET_NO_TOC)
1347490075Sobrien    abort ();
1347590075Sobrien
1347690075Sobrien  /* When the linker won't eliminate them, don't output duplicate
1347790075Sobrien     TOC entries (this happens on AIX if there is any kind of TOC,
13478132718Skan     and on SVR4 under -fPIC or -mrelocatable).  Don't do this for
13479132718Skan     CODE_LABELs.  */
13480132718Skan  if (TARGET_TOC && GET_CODE (x) != LABEL_REF)
1348190075Sobrien    {
1348290075Sobrien      struct toc_hash_struct *h;
1348390075Sobrien      void * * found;
1348490075Sobrien
13485132718Skan      /* Create toc_hash_table.  This can't be done at OVERRIDE_OPTIONS
13486132718Skan         time because GGC is not initialized at that point.  */
13487132718Skan      if (toc_hash_table == NULL)
13488132718Skan	toc_hash_table = htab_create_ggc (1021, toc_hash_function,
13489132718Skan					  toc_hash_eq, NULL);
13490132718Skan
1349190075Sobrien      h = ggc_alloc (sizeof (*h));
1349290075Sobrien      h->key = x;
1349390075Sobrien      h->key_mode = mode;
1349490075Sobrien      h->labelno = labelno;
1349590075Sobrien
1349690075Sobrien      found = htab_find_slot (toc_hash_table, h, 1);
1349790075Sobrien      if (*found == NULL)
1349890075Sobrien	*found = h;
1349990075Sobrien      else  /* This is indeed a duplicate.
1350090075Sobrien	       Set this label equal to that label.  */
1350190075Sobrien	{
1350290075Sobrien	  fputs ("\t.set ", file);
1350390075Sobrien	  ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "LC");
1350490075Sobrien	  fprintf (file, "%d,", labelno);
1350590075Sobrien	  ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "LC");
1350690075Sobrien	  fprintf (file, "%d\n", ((*(const struct toc_hash_struct **)
1350790075Sobrien					      found)->labelno));
1350890075Sobrien	  return;
1350990075Sobrien	}
1351090075Sobrien    }
1351190075Sobrien
1351290075Sobrien  /* If we're going to put a double constant in the TOC, make sure it's
1351390075Sobrien     aligned properly when strict alignment is on.  */
1351490075Sobrien  if (GET_CODE (x) == CONST_DOUBLE
1351590075Sobrien      && STRICT_ALIGNMENT
1351690075Sobrien      && GET_MODE_BITSIZE (mode) >= 64
1351790075Sobrien      && ! (TARGET_NO_FP_IN_TOC && ! TARGET_MINIMAL_TOC)) {
1351890075Sobrien    ASM_OUTPUT_ALIGN (file, 3);
1351990075Sobrien  }
1352090075Sobrien
13521132718Skan  (*targetm.asm_out.internal_label) (file, "LC", labelno);
1352290075Sobrien
1352390075Sobrien  /* Handle FP constants specially.  Note that if we have a minimal
1352490075Sobrien     TOC, things we put here aren't actually in the TOC, so we can allow
1352590075Sobrien     FP constants.  */
13526117395Skan  if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == TFmode)
1352790075Sobrien    {
1352890075Sobrien      REAL_VALUE_TYPE rv;
13529117395Skan      long k[4];
13530117395Skan
13531117395Skan      REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
13532117395Skan      REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, k);
13533117395Skan
13534117395Skan      if (TARGET_64BIT)
13535117395Skan	{
13536117395Skan	  if (TARGET_MINIMAL_TOC)
13537117395Skan	    fputs (DOUBLE_INT_ASM_OP, file);
13538117395Skan	  else
13539117395Skan	    fprintf (file, "\t.tc FT_%lx_%lx_%lx_%lx[TC],",
13540117395Skan		     k[0] & 0xffffffff, k[1] & 0xffffffff,
13541117395Skan		     k[2] & 0xffffffff, k[3] & 0xffffffff);
13542117395Skan	  fprintf (file, "0x%lx%08lx,0x%lx%08lx\n",
13543117395Skan		   k[0] & 0xffffffff, k[1] & 0xffffffff,
13544117395Skan		   k[2] & 0xffffffff, k[3] & 0xffffffff);
13545117395Skan	  return;
13546117395Skan	}
13547117395Skan      else
13548117395Skan	{
13549117395Skan	  if (TARGET_MINIMAL_TOC)
13550117395Skan	    fputs ("\t.long ", file);
13551117395Skan	  else
13552117395Skan	    fprintf (file, "\t.tc FT_%lx_%lx_%lx_%lx[TC],",
13553117395Skan		     k[0] & 0xffffffff, k[1] & 0xffffffff,
13554117395Skan		     k[2] & 0xffffffff, k[3] & 0xffffffff);
13555117395Skan	  fprintf (file, "0x%lx,0x%lx,0x%lx,0x%lx\n",
13556117395Skan		   k[0] & 0xffffffff, k[1] & 0xffffffff,
13557117395Skan		   k[2] & 0xffffffff, k[3] & 0xffffffff);
13558117395Skan	  return;
13559117395Skan	}
13560117395Skan    }
13561117395Skan  else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == DFmode)
13562117395Skan    {
13563117395Skan      REAL_VALUE_TYPE rv;
1356490075Sobrien      long k[2];
1356590075Sobrien
1356690075Sobrien      REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
1356790075Sobrien      REAL_VALUE_TO_TARGET_DOUBLE (rv, k);
1356890075Sobrien
1356990075Sobrien      if (TARGET_64BIT)
1357090075Sobrien	{
1357190075Sobrien	  if (TARGET_MINIMAL_TOC)
1357290075Sobrien	    fputs (DOUBLE_INT_ASM_OP, file);
1357390075Sobrien	  else
13574102780Skan	    fprintf (file, "\t.tc FD_%lx_%lx[TC],",
13575102780Skan		     k[0] & 0xffffffff, k[1] & 0xffffffff);
13576102780Skan	  fprintf (file, "0x%lx%08lx\n",
13577102780Skan		   k[0] & 0xffffffff, k[1] & 0xffffffff);
1357890075Sobrien	  return;
1357990075Sobrien	}
1358090075Sobrien      else
1358190075Sobrien	{
1358290075Sobrien	  if (TARGET_MINIMAL_TOC)
1358390075Sobrien	    fputs ("\t.long ", file);
1358490075Sobrien	  else
13585102780Skan	    fprintf (file, "\t.tc FD_%lx_%lx[TC],",
13586102780Skan		     k[0] & 0xffffffff, k[1] & 0xffffffff);
13587102780Skan	  fprintf (file, "0x%lx,0x%lx\n",
13588102780Skan		   k[0] & 0xffffffff, k[1] & 0xffffffff);
1358990075Sobrien	  return;
1359090075Sobrien	}
1359190075Sobrien    }
1359290075Sobrien  else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == SFmode)
1359390075Sobrien    {
1359490075Sobrien      REAL_VALUE_TYPE rv;
1359590075Sobrien      long l;
1359690075Sobrien
1359790075Sobrien      REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
1359890075Sobrien      REAL_VALUE_TO_TARGET_SINGLE (rv, l);
1359990075Sobrien
1360090075Sobrien      if (TARGET_64BIT)
1360190075Sobrien	{
1360290075Sobrien	  if (TARGET_MINIMAL_TOC)
1360390075Sobrien	    fputs (DOUBLE_INT_ASM_OP, file);
1360490075Sobrien	  else
13605102780Skan	    fprintf (file, "\t.tc FS_%lx[TC],", l & 0xffffffff);
13606102780Skan	  fprintf (file, "0x%lx00000000\n", l & 0xffffffff);
1360790075Sobrien	  return;
1360890075Sobrien	}
1360990075Sobrien      else
1361090075Sobrien	{
1361190075Sobrien	  if (TARGET_MINIMAL_TOC)
1361290075Sobrien	    fputs ("\t.long ", file);
1361390075Sobrien	  else
13614102780Skan	    fprintf (file, "\t.tc FS_%lx[TC],", l & 0xffffffff);
13615102780Skan	  fprintf (file, "0x%lx\n", l & 0xffffffff);
1361690075Sobrien	  return;
1361790075Sobrien	}
1361890075Sobrien    }
1361990075Sobrien  else if (GET_MODE (x) == VOIDmode
1362090075Sobrien	   && (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE))
1362190075Sobrien    {
1362290075Sobrien      unsigned HOST_WIDE_INT low;
1362390075Sobrien      HOST_WIDE_INT high;
1362490075Sobrien
1362590075Sobrien      if (GET_CODE (x) == CONST_DOUBLE)
1362690075Sobrien	{
1362790075Sobrien	  low = CONST_DOUBLE_LOW (x);
1362890075Sobrien	  high = CONST_DOUBLE_HIGH (x);
1362990075Sobrien	}
1363090075Sobrien      else
1363190075Sobrien#if HOST_BITS_PER_WIDE_INT == 32
1363290075Sobrien	{
1363390075Sobrien	  low = INTVAL (x);
1363490075Sobrien	  high = (low & 0x80000000) ? ~0 : 0;
1363590075Sobrien	}
1363690075Sobrien#else
1363790075Sobrien	{
1363890075Sobrien          low = INTVAL (x) & 0xffffffff;
1363990075Sobrien          high = (HOST_WIDE_INT) INTVAL (x) >> 32;
1364090075Sobrien	}
1364190075Sobrien#endif
1364290075Sobrien
1364390075Sobrien      /* TOC entries are always Pmode-sized, but since this
1364490075Sobrien	 is a bigendian machine then if we're putting smaller
1364590075Sobrien	 integer constants in the TOC we have to pad them.
1364690075Sobrien	 (This is still a win over putting the constants in
1364790075Sobrien	 a separate constant pool, because then we'd have
1364890075Sobrien	 to have both a TOC entry _and_ the actual constant.)
1364990075Sobrien
1365090075Sobrien	 For a 32-bit target, CONST_INT values are loaded and shifted
1365190075Sobrien	 entirely within `low' and can be stored in one TOC entry.  */
1365290075Sobrien
1365390075Sobrien      if (TARGET_64BIT && POINTER_SIZE < GET_MODE_BITSIZE (mode))
1365490075Sobrien	abort ();/* It would be easy to make this work, but it doesn't now.  */
1365590075Sobrien
1365690075Sobrien      if (POINTER_SIZE > GET_MODE_BITSIZE (mode))
13657103445Skan	{
13658103445Skan#if HOST_BITS_PER_WIDE_INT == 32
13659103445Skan	  lshift_double (low, high, POINTER_SIZE - GET_MODE_BITSIZE (mode),
13660103445Skan			 POINTER_SIZE, &low, &high, 0);
13661103445Skan#else
13662103445Skan	  low |= high << 32;
13663103445Skan	  low <<= POINTER_SIZE - GET_MODE_BITSIZE (mode);
13664103445Skan	  high = (HOST_WIDE_INT) low >> 32;
13665103445Skan	  low &= 0xffffffff;
13666103445Skan#endif
13667103445Skan	}
1366890075Sobrien
1366990075Sobrien      if (TARGET_64BIT)
1367090075Sobrien	{
1367190075Sobrien	  if (TARGET_MINIMAL_TOC)
1367290075Sobrien	    fputs (DOUBLE_INT_ASM_OP, file);
1367390075Sobrien	  else
13674102780Skan	    fprintf (file, "\t.tc ID_%lx_%lx[TC],",
13675102780Skan		     (long) high & 0xffffffff, (long) low & 0xffffffff);
13676102780Skan	  fprintf (file, "0x%lx%08lx\n",
13677102780Skan		   (long) high & 0xffffffff, (long) low & 0xffffffff);
1367890075Sobrien	  return;
1367990075Sobrien	}
1368090075Sobrien      else
1368190075Sobrien	{
1368290075Sobrien	  if (POINTER_SIZE < GET_MODE_BITSIZE (mode))
1368390075Sobrien	    {
1368490075Sobrien	      if (TARGET_MINIMAL_TOC)
1368590075Sobrien		fputs ("\t.long ", file);
1368690075Sobrien	      else
1368790075Sobrien		fprintf (file, "\t.tc ID_%lx_%lx[TC],",
13688102780Skan			 (long) high & 0xffffffff, (long) low & 0xffffffff);
13689102780Skan	      fprintf (file, "0x%lx,0x%lx\n",
13690102780Skan		       (long) high & 0xffffffff, (long) low & 0xffffffff);
1369190075Sobrien	    }
1369290075Sobrien	  else
1369390075Sobrien	    {
1369490075Sobrien	      if (TARGET_MINIMAL_TOC)
1369590075Sobrien		fputs ("\t.long ", file);
1369690075Sobrien	      else
13697102780Skan		fprintf (file, "\t.tc IS_%lx[TC],", (long) low & 0xffffffff);
13698102780Skan	      fprintf (file, "0x%lx\n", (long) low & 0xffffffff);
1369990075Sobrien	    }
1370090075Sobrien	  return;
1370190075Sobrien	}
1370290075Sobrien    }
1370390075Sobrien
1370490075Sobrien  if (GET_CODE (x) == CONST)
1370590075Sobrien    {
1370690075Sobrien      if (GET_CODE (XEXP (x, 0)) != PLUS)
1370790075Sobrien	abort ();
1370890075Sobrien
1370990075Sobrien      base = XEXP (XEXP (x, 0), 0);
1371090075Sobrien      offset = INTVAL (XEXP (XEXP (x, 0), 1));
1371190075Sobrien    }
1371290075Sobrien
1371390075Sobrien  if (GET_CODE (base) == SYMBOL_REF)
1371490075Sobrien    name = XSTR (base, 0);
1371590075Sobrien  else if (GET_CODE (base) == LABEL_REF)
1371690075Sobrien    ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (XEXP (base, 0)));
1371790075Sobrien  else if (GET_CODE (base) == CODE_LABEL)
1371890075Sobrien    ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (base));
1371990075Sobrien  else
1372090075Sobrien    abort ();
1372190075Sobrien
13722117395Skan  real_name = (*targetm.strip_name_encoding) (name);
1372390075Sobrien  if (TARGET_MINIMAL_TOC)
1372490075Sobrien    fputs (TARGET_32BIT ? "\t.long " : DOUBLE_INT_ASM_OP, file);
1372590075Sobrien  else
1372690075Sobrien    {
1372790075Sobrien      fprintf (file, "\t.tc %s", real_name);
1372890075Sobrien
1372990075Sobrien      if (offset < 0)
1373090075Sobrien	fprintf (file, ".N%d", - offset);
1373190075Sobrien      else if (offset)
1373290075Sobrien	fprintf (file, ".P%d", offset);
1373390075Sobrien
1373490075Sobrien      fputs ("[TC],", file);
1373590075Sobrien    }
1373690075Sobrien
1373790075Sobrien  /* Currently C++ toc references to vtables can be emitted before it
1373890075Sobrien     is decided whether the vtable is public or private.  If this is
1373990075Sobrien     the case, then the linker will eventually complain that there is
1374090075Sobrien     a TOC reference to an unknown section.  Thus, for vtables only,
1374190075Sobrien     we emit the TOC reference to reference the symbol and not the
1374290075Sobrien     section.  */
1374390075Sobrien  if (VTABLE_NAME_P (name))
1374490075Sobrien    {
1374590075Sobrien      RS6000_OUTPUT_BASENAME (file, name);
1374690075Sobrien      if (offset < 0)
1374790075Sobrien	fprintf (file, "%d", offset);
1374890075Sobrien      else if (offset > 0)
1374990075Sobrien	fprintf (file, "+%d", offset);
1375090075Sobrien    }
1375190075Sobrien  else
1375290075Sobrien    output_addr_const (file, x);
1375390075Sobrien  putc ('\n', file);
1375490075Sobrien}
1375590075Sobrien
1375690075Sobrien/* Output an assembler pseudo-op to write an ASCII string of N characters
1375790075Sobrien   starting at P to FILE.
1375890075Sobrien
1375990075Sobrien   On the RS/6000, we have to do this using the .byte operation and
1376090075Sobrien   write out special characters outside the quoted string.
1376190075Sobrien   Also, the assembler is broken; very long strings are truncated,
1376290075Sobrien   so we must artificially break them up early.  */
1376390075Sobrien
1376490075Sobrienvoid
13765132718Skanoutput_ascii (FILE *file, const char *p, int n)
1376690075Sobrien{
1376790075Sobrien  char c;
1376890075Sobrien  int i, count_string;
1376990075Sobrien  const char *for_string = "\t.byte \"";
1377090075Sobrien  const char *for_decimal = "\t.byte ";
1377190075Sobrien  const char *to_close = NULL;
1377290075Sobrien
1377390075Sobrien  count_string = 0;
1377490075Sobrien  for (i = 0; i < n; i++)
1377590075Sobrien    {
1377690075Sobrien      c = *p++;
1377790075Sobrien      if (c >= ' ' && c < 0177)
1377890075Sobrien	{
1377990075Sobrien	  if (for_string)
1378090075Sobrien	    fputs (for_string, file);
1378190075Sobrien	  putc (c, file);
1378290075Sobrien
1378390075Sobrien	  /* Write two quotes to get one.  */
1378490075Sobrien	  if (c == '"')
1378590075Sobrien	    {
1378690075Sobrien	      putc (c, file);
1378790075Sobrien	      ++count_string;
1378890075Sobrien	    }
1378990075Sobrien
1379090075Sobrien	  for_string = NULL;
1379190075Sobrien	  for_decimal = "\"\n\t.byte ";
1379290075Sobrien	  to_close = "\"\n";
1379390075Sobrien	  ++count_string;
1379490075Sobrien
1379590075Sobrien	  if (count_string >= 512)
1379690075Sobrien	    {
1379790075Sobrien	      fputs (to_close, file);
1379890075Sobrien
1379990075Sobrien	      for_string = "\t.byte \"";
1380090075Sobrien	      for_decimal = "\t.byte ";
1380190075Sobrien	      to_close = NULL;
1380290075Sobrien	      count_string = 0;
1380390075Sobrien	    }
1380490075Sobrien	}
1380590075Sobrien      else
1380690075Sobrien	{
1380790075Sobrien	  if (for_decimal)
1380890075Sobrien	    fputs (for_decimal, file);
1380990075Sobrien	  fprintf (file, "%d", c);
1381090075Sobrien
1381190075Sobrien	  for_string = "\n\t.byte \"";
1381290075Sobrien	  for_decimal = ", ";
1381390075Sobrien	  to_close = "\n";
1381490075Sobrien	  count_string = 0;
1381590075Sobrien	}
1381690075Sobrien    }
1381790075Sobrien
1381890075Sobrien  /* Now close the string if we have written one.  Then end the line.  */
1381990075Sobrien  if (to_close)
1382090075Sobrien    fputs (to_close, file);
1382190075Sobrien}
1382290075Sobrien
1382390075Sobrien/* Generate a unique section name for FILENAME for a section type
1382490075Sobrien   represented by SECTION_DESC.  Output goes into BUF.
1382590075Sobrien
1382690075Sobrien   SECTION_DESC can be any string, as long as it is different for each
1382790075Sobrien   possible section type.
1382890075Sobrien
1382990075Sobrien   We name the section in the same manner as xlc.  The name begins with an
1383090075Sobrien   underscore followed by the filename (after stripping any leading directory
1383190075Sobrien   names) with the last period replaced by the string SECTION_DESC.  If
1383290075Sobrien   FILENAME does not contain a period, SECTION_DESC is appended to the end of
1383390075Sobrien   the name.  */
1383490075Sobrien
1383590075Sobrienvoid
13836132718Skanrs6000_gen_section_name (char **buf, const char *filename,
13837132718Skan		         const char *section_desc)
1383890075Sobrien{
1383990075Sobrien  const char *q, *after_last_slash, *last_period = 0;
1384090075Sobrien  char *p;
1384190075Sobrien  int len;
1384290075Sobrien
1384390075Sobrien  after_last_slash = filename;
1384490075Sobrien  for (q = filename; *q; q++)
1384590075Sobrien    {
1384690075Sobrien      if (*q == '/')
1384790075Sobrien	after_last_slash = q + 1;
1384890075Sobrien      else if (*q == '.')
1384990075Sobrien	last_period = q;
1385090075Sobrien    }
1385190075Sobrien
1385290075Sobrien  len = strlen (after_last_slash) + strlen (section_desc) + 2;
13853117395Skan  *buf = (char *) xmalloc (len);
1385490075Sobrien
1385590075Sobrien  p = *buf;
1385690075Sobrien  *p++ = '_';
1385790075Sobrien
1385890075Sobrien  for (q = after_last_slash; *q; q++)
1385990075Sobrien    {
1386090075Sobrien      if (q == last_period)
1386190075Sobrien        {
1386290075Sobrien	  strcpy (p, section_desc);
1386390075Sobrien	  p += strlen (section_desc);
13864132718Skan	  break;
1386590075Sobrien        }
1386690075Sobrien
1386790075Sobrien      else if (ISALNUM (*q))
1386890075Sobrien        *p++ = *q;
1386990075Sobrien    }
1387090075Sobrien
1387190075Sobrien  if (last_period == 0)
1387290075Sobrien    strcpy (p, section_desc);
1387390075Sobrien  else
1387490075Sobrien    *p = '\0';
1387590075Sobrien}
1387690075Sobrien
1387790075Sobrien/* Emit profile function.  */
1387890075Sobrien
1387990075Sobrienvoid
13880132718Skanoutput_profile_hook (int labelno ATTRIBUTE_UNUSED)
1388190075Sobrien{
13882132718Skan  if (TARGET_PROFILE_KERNEL)
13883132718Skan    return;
13884132718Skan
1388590075Sobrien  if (DEFAULT_ABI == ABI_AIX)
1388690075Sobrien    {
13887132718Skan#ifndef NO_PROFILE_COUNTERS
13888132718Skan# define NO_PROFILE_COUNTERS 0
13889132718Skan#endif
13890132718Skan      if (NO_PROFILE_COUNTERS)
13891132718Skan	emit_library_call (init_one_libfunc (RS6000_MCOUNT), 0, VOIDmode, 0);
13892132718Skan      else
13893132718Skan	{
13894132718Skan	  char buf[30];
13895132718Skan	  const char *label_name;
13896132718Skan	  rtx fun;
1389790075Sobrien
13898132718Skan	  ASM_GENERATE_INTERNAL_LABEL (buf, "LP", labelno);
13899132718Skan	  label_name = (*targetm.strip_name_encoding) (ggc_strdup (buf));
13900132718Skan	  fun = gen_rtx_SYMBOL_REF (Pmode, label_name);
1390190075Sobrien
13902132718Skan	  emit_library_call (init_one_libfunc (RS6000_MCOUNT), 0, VOIDmode, 1,
13903132718Skan			     fun, Pmode);
13904132718Skan	}
1390590075Sobrien    }
1390690075Sobrien  else if (DEFAULT_ABI == ABI_DARWIN)
1390790075Sobrien    {
1390890075Sobrien      const char *mcount_name = RS6000_MCOUNT;
1390990075Sobrien      int caller_addr_regno = LINK_REGISTER_REGNUM;
1391090075Sobrien
1391190075Sobrien      /* Be conservative and always set this, at least for now.  */
1391290075Sobrien      current_function_uses_pic_offset_table = 1;
1391390075Sobrien
1391490075Sobrien#if TARGET_MACHO
1391590075Sobrien      /* For PIC code, set up a stub and collect the caller's address
1391690075Sobrien	 from r0, which is where the prologue puts it.  */
13917132718Skan      if (MACHOPIC_INDIRECT)
1391890075Sobrien	{
1391990075Sobrien	  mcount_name = machopic_stub_name (mcount_name);
1392090075Sobrien	  if (current_function_uses_pic_offset_table)
1392190075Sobrien	    caller_addr_regno = 0;
1392290075Sobrien	}
1392390075Sobrien#endif
1392490075Sobrien      emit_library_call (gen_rtx_SYMBOL_REF (Pmode, mcount_name),
1392590075Sobrien			 0, VOIDmode, 1,
1392690075Sobrien			 gen_rtx_REG (Pmode, caller_addr_regno), Pmode);
1392790075Sobrien    }
1392890075Sobrien}
1392990075Sobrien
1393090075Sobrien/* Write function profiler code.  */
1393190075Sobrien
1393290075Sobrienvoid
13933132718Skanoutput_function_profiler (FILE *file, int labelno)
1393490075Sobrien{
1393590075Sobrien  char buf[100];
13936103445Skan  int save_lr = 8;
1393790075Sobrien
1393890075Sobrien  switch (DEFAULT_ABI)
1393990075Sobrien    {
1394090075Sobrien    default:
1394190075Sobrien      abort ();
1394290075Sobrien
1394390075Sobrien    case ABI_V4:
13944103445Skan      save_lr = 4;
13945103445Skan      if (!TARGET_32BIT)
13946103445Skan	{
13947103445Skan	  warning ("no profiling of 64-bit code for this ABI");
13948103445Skan	  return;
13949103445Skan	}
13950132718Skan      ASM_GENERATE_INTERNAL_LABEL (buf, "LP", labelno);
1395190075Sobrien      fprintf (file, "\tmflr %s\n", reg_names[0]);
1395290075Sobrien      if (flag_pic == 1)
1395390075Sobrien	{
1395490075Sobrien	  fputs ("\tbl _GLOBAL_OFFSET_TABLE_@local-4\n", file);
13955103445Skan	  asm_fprintf (file, "\t{st|stw} %s,%d(%s)\n",
13956103445Skan		       reg_names[0], save_lr, reg_names[1]);
1395790075Sobrien	  asm_fprintf (file, "\tmflr %s\n", reg_names[12]);
1395890075Sobrien	  asm_fprintf (file, "\t{l|lwz} %s,", reg_names[0]);
1395990075Sobrien	  assemble_name (file, buf);
1396090075Sobrien	  asm_fprintf (file, "@got(%s)\n", reg_names[12]);
1396190075Sobrien	}
1396290075Sobrien      else if (flag_pic > 1)
1396390075Sobrien	{
13964103445Skan	  asm_fprintf (file, "\t{st|stw} %s,%d(%s)\n",
13965103445Skan		       reg_names[0], save_lr, reg_names[1]);
1396690075Sobrien	  /* Now, we need to get the address of the label.  */
1396790075Sobrien	  fputs ("\tbl 1f\n\t.long ", file);
1396890075Sobrien	  assemble_name (file, buf);
1396990075Sobrien	  fputs ("-.\n1:", file);
1397090075Sobrien	  asm_fprintf (file, "\tmflr %s\n", reg_names[11]);
1397190075Sobrien	  asm_fprintf (file, "\t{l|lwz} %s,0(%s)\n",
1397290075Sobrien		       reg_names[0], reg_names[11]);
1397390075Sobrien	  asm_fprintf (file, "\t{cax|add} %s,%s,%s\n",
1397490075Sobrien		       reg_names[0], reg_names[0], reg_names[11]);
1397590075Sobrien	}
1397690075Sobrien      else
1397790075Sobrien	{
1397890075Sobrien	  asm_fprintf (file, "\t{liu|lis} %s,", reg_names[12]);
1397990075Sobrien	  assemble_name (file, buf);
1398090075Sobrien	  fputs ("@ha\n", file);
13981103445Skan	  asm_fprintf (file, "\t{st|stw} %s,%d(%s)\n",
13982103445Skan		       reg_names[0], save_lr, reg_names[1]);
1398390075Sobrien	  asm_fprintf (file, "\t{cal|la} %s,", reg_names[0]);
1398490075Sobrien	  assemble_name (file, buf);
1398590075Sobrien	  asm_fprintf (file, "@l(%s)\n", reg_names[12]);
1398690075Sobrien	}
1398790075Sobrien
13988132718Skan      /* ABI_V4 saves the static chain reg with ASM_OUTPUT_REG_PUSH.  */
13989132718Skan      fprintf (file, "\tbl %s%s\n",
13990132718Skan	       RS6000_MCOUNT, flag_pic ? "@plt" : "");
13991132718Skan
13992132718Skan      break;
13993132718Skan
13994132718Skan    case ABI_AIX:
13995132718Skan    case ABI_DARWIN:
13996132718Skan      if (!TARGET_PROFILE_KERNEL)
13997103445Skan	{
13998132718Skan	  /* Don't do anything, done in output_profile_hook ().  */
13999103445Skan	}
14000103445Skan      else
14001132718Skan	{
14002132718Skan	  if (TARGET_32BIT)
14003132718Skan	    abort ();
1400490075Sobrien
14005132718Skan	  asm_fprintf (file, "\tmflr %s\n", reg_names[0]);
14006132718Skan	  asm_fprintf (file, "\tstd %s,16(%s)\n", reg_names[0], reg_names[1]);
14007132718Skan
14008132718Skan	  if (current_function_needs_context)
14009132718Skan	    {
14010132718Skan	      asm_fprintf (file, "\tstd %s,24(%s)\n",
14011132718Skan			   reg_names[STATIC_CHAIN_REGNUM], reg_names[1]);
14012132718Skan	      fprintf (file, "\tbl %s\n", RS6000_MCOUNT);
14013132718Skan	      asm_fprintf (file, "\tld %s,24(%s)\n",
14014132718Skan			   reg_names[STATIC_CHAIN_REGNUM], reg_names[1]);
14015132718Skan	    }
14016132718Skan	  else
14017132718Skan	    fprintf (file, "\tbl %s\n", RS6000_MCOUNT);
14018132718Skan	}
1401990075Sobrien      break;
1402090075Sobrien    }
1402190075Sobrien}
1402290075Sobrien
14023132718Skan
14024132718Skanstatic int
14025132718Skanrs6000_use_dfa_pipeline_interface (void)
14026132718Skan{
14027132718Skan  return 1;
14028132718Skan}
14029132718Skan
14030132718Skan/* Power4 load update and store update instructions are cracked into a
14031132718Skan   load or store and an integer insn which are executed in the same cycle.
14032132718Skan   Branches have their own dispatch slot which does not count against the
14033132718Skan   GCC issue rate, but it changes the program flow so there are no other
14034132718Skan   instructions to issue in this cycle.  */
14035132718Skan
14036132718Skanstatic int
14037132718Skanrs6000_variable_issue (FILE *stream ATTRIBUTE_UNUSED,
14038132718Skan		       int verbose ATTRIBUTE_UNUSED,
14039132718Skan		       rtx insn, int more)
14040132718Skan{
14041132718Skan  if (GET_CODE (PATTERN (insn)) == USE
14042132718Skan      || GET_CODE (PATTERN (insn)) == CLOBBER)
14043132718Skan    return more;
14044132718Skan
14045132718Skan  if (rs6000_sched_groups)
14046132718Skan    {
14047132718Skan      if (is_microcoded_insn (insn))
14048132718Skan        return 0;
14049132718Skan      else if (is_cracked_insn (insn))
14050132718Skan        return more > 2 ? more - 2 : 0;
14051132718Skan    }
14052132718Skan
14053132718Skan  return more - 1;
14054132718Skan}
14055132718Skan
1405690075Sobrien/* Adjust the cost of a scheduling dependency.  Return the new cost of
1405790075Sobrien   a dependency LINK or INSN on DEP_INSN.  COST is the current cost.  */
1405890075Sobrien
1405990075Sobrienstatic int
14060132718Skanrs6000_adjust_cost (rtx insn, rtx link, rtx dep_insn ATTRIBUTE_UNUSED,
14061132718Skan		    int cost)
1406290075Sobrien{
1406390075Sobrien  if (! recog_memoized (insn))
1406490075Sobrien    return 0;
1406590075Sobrien
1406690075Sobrien  if (REG_NOTE_KIND (link) != 0)
1406790075Sobrien    return 0;
1406890075Sobrien
1406990075Sobrien  if (REG_NOTE_KIND (link) == 0)
1407090075Sobrien    {
1407190075Sobrien      /* Data dependency; DEP_INSN writes a register that INSN reads
1407290075Sobrien	 some cycles later.  */
1407390075Sobrien      switch (get_attr_type (insn))
1407490075Sobrien	{
1407590075Sobrien	case TYPE_JMPREG:
14076117395Skan	  /* Tell the first scheduling pass about the latency between
1407790075Sobrien	     a mtctr and bctr (and mtlr and br/blr).  The first
1407890075Sobrien	     scheduling pass will not know about this latency since
1407990075Sobrien	     the mtctr instruction, which has the latency associated
1408090075Sobrien	     to it, will be generated by reload.  */
14081117395Skan	  return TARGET_POWER ? 5 : 4;
1408290075Sobrien	case TYPE_BRANCH:
1408390075Sobrien	  /* Leave some extra cycles between a compare and its
1408490075Sobrien	     dependent branch, to inhibit expensive mispredicts.  */
14085117395Skan	  if ((rs6000_cpu_attr == CPU_PPC603
14086117395Skan	       || rs6000_cpu_attr == CPU_PPC604
14087117395Skan	       || rs6000_cpu_attr == CPU_PPC604E
14088117395Skan	       || rs6000_cpu_attr == CPU_PPC620
14089117395Skan	       || rs6000_cpu_attr == CPU_PPC630
14090117395Skan	       || rs6000_cpu_attr == CPU_PPC750
14091117395Skan	       || rs6000_cpu_attr == CPU_PPC7400
14092117395Skan	       || rs6000_cpu_attr == CPU_PPC7450
14093132718Skan	       || rs6000_cpu_attr == CPU_POWER4
14094132718Skan	       || rs6000_cpu_attr == CPU_POWER5)
1409590075Sobrien	      && recog_memoized (dep_insn)
1409690075Sobrien	      && (INSN_CODE (dep_insn) >= 0)
14097132718Skan	      && (get_attr_type (dep_insn) == TYPE_CMP
14098132718Skan		  || get_attr_type (dep_insn) == TYPE_COMPARE
1409990075Sobrien		  || get_attr_type (dep_insn) == TYPE_DELAYED_COMPARE
14100132718Skan		  || get_attr_type (dep_insn) == TYPE_IMUL_COMPARE
14101132718Skan		  || get_attr_type (dep_insn) == TYPE_LMUL_COMPARE
1410290075Sobrien		  || get_attr_type (dep_insn) == TYPE_FPCOMPARE
14103132718Skan		  || get_attr_type (dep_insn) == TYPE_CR_LOGICAL
14104132718Skan		  || get_attr_type (dep_insn) == TYPE_DELAYED_CR))
1410590075Sobrien	    return cost + 2;
1410690075Sobrien	default:
1410790075Sobrien	  break;
1410890075Sobrien	}
1410990075Sobrien      /* Fall out to return default cost.  */
1411090075Sobrien    }
1411190075Sobrien
1411290075Sobrien  return cost;
1411390075Sobrien}
1411490075Sobrien
14115132718Skan/* The function returns a true if INSN is microcoded.
14116132718Skan   Return false otherwise.  */
14117132718Skan
14118132718Skanstatic bool
14119132718Skanis_microcoded_insn (rtx insn)
14120132718Skan{
14121132718Skan  if (!insn || !INSN_P (insn)
14122132718Skan      || GET_CODE (PATTERN (insn)) == USE
14123132718Skan      || GET_CODE (PATTERN (insn)) == CLOBBER)
14124132718Skan    return false;
14125132718Skan
14126132718Skan  if (rs6000_sched_groups)
14127132718Skan    {
14128132718Skan      enum attr_type type = get_attr_type (insn);
14129132718Skan      if (type == TYPE_LOAD_EXT_U
14130132718Skan	  || type == TYPE_LOAD_EXT_UX
14131132718Skan	  || type == TYPE_LOAD_UX
14132132718Skan	  || type == TYPE_STORE_UX
14133132718Skan	  || type == TYPE_MFCR)
14134132718Skan        return true;
14135132718Skan    }
14136132718Skan
14137132718Skan  return false;
14138132718Skan}
14139132718Skan
14140132718Skan/* The function returns a nonzero value if INSN can be scheduled only
14141132718Skan   as the first insn in a dispatch group ("dispatch-slot restricted").
14142132718Skan   In this case, the returned value indicates how many dispatch slots
14143132718Skan   the insn occupies (at the beginning of the group).
14144132718Skan   Return 0 otherwise.  */
14145132718Skan
14146132718Skanstatic int
14147132718Skanis_dispatch_slot_restricted (rtx insn)
14148132718Skan{
14149132718Skan  enum attr_type type;
14150132718Skan
14151132718Skan  if (!rs6000_sched_groups)
14152132718Skan    return 0;
14153132718Skan
14154132718Skan  if (!insn
14155132718Skan      || insn == NULL_RTX
14156132718Skan      || GET_CODE (insn) == NOTE
14157132718Skan      || GET_CODE (PATTERN (insn)) == USE
14158132718Skan      || GET_CODE (PATTERN (insn)) == CLOBBER)
14159132718Skan    return 0;
14160132718Skan
14161132718Skan  type = get_attr_type (insn);
14162132718Skan
14163132718Skan  switch (type)
14164132718Skan    {
14165132718Skan    case TYPE_MFCR:
14166132718Skan    case TYPE_MFCRF:
14167132718Skan    case TYPE_MTCR:
14168132718Skan    case TYPE_DELAYED_CR:
14169132718Skan    case TYPE_CR_LOGICAL:
14170132718Skan    case TYPE_MTJMPR:
14171132718Skan    case TYPE_MFJMPR:
14172132718Skan      return 1;
14173132718Skan    case TYPE_IDIV:
14174132718Skan    case TYPE_LDIV:
14175132718Skan      return 2;
14176132718Skan    default:
14177132718Skan      if (rs6000_cpu == PROCESSOR_POWER5
14178132718Skan	  && is_cracked_insn (insn))
14179132718Skan	return 2;
14180132718Skan      return 0;
14181132718Skan    }
14182132718Skan}
14183132718Skan
14184132718Skan/* The function returns true if INSN is cracked into 2 instructions
14185132718Skan   by the processor (and therefore occupies 2 issue slots).  */
14186132718Skan
14187132718Skanstatic bool
14188132718Skanis_cracked_insn (rtx insn)
14189132718Skan{
14190132718Skan  if (!insn || !INSN_P (insn)
14191132718Skan      || GET_CODE (PATTERN (insn)) == USE
14192132718Skan      || GET_CODE (PATTERN (insn)) == CLOBBER)
14193132718Skan    return false;
14194132718Skan
14195132718Skan  if (rs6000_sched_groups)
14196132718Skan    {
14197132718Skan      enum attr_type type = get_attr_type (insn);
14198132718Skan      if (type == TYPE_LOAD_U || type == TYPE_STORE_U
14199132718Skan	       || type == TYPE_FPLOAD_U || type == TYPE_FPSTORE_U
14200132718Skan	       || type == TYPE_FPLOAD_UX || type == TYPE_FPSTORE_UX
14201132718Skan	       || type == TYPE_LOAD_EXT || type == TYPE_DELAYED_CR
14202132718Skan	       || type == TYPE_COMPARE || type == TYPE_DELAYED_COMPARE
14203132718Skan	       || type == TYPE_IMUL_COMPARE || type == TYPE_LMUL_COMPARE
14204132718Skan	       || type == TYPE_IDIV || type == TYPE_LDIV
14205132718Skan	       || type == TYPE_INSERT_WORD)
14206132718Skan        return true;
14207132718Skan    }
14208132718Skan
14209132718Skan  return false;
14210132718Skan}
14211132718Skan
14212132718Skan/* The function returns true if INSN can be issued only from
14213132718Skan   the branch slot.  */
14214132718Skan
14215132718Skanstatic bool
14216132718Skanis_branch_slot_insn (rtx insn)
14217132718Skan{
14218132718Skan  if (!insn || !INSN_P (insn)
14219132718Skan      || GET_CODE (PATTERN (insn)) == USE
14220132718Skan      || GET_CODE (PATTERN (insn)) == CLOBBER)
14221132718Skan    return false;
14222132718Skan
14223132718Skan  if (rs6000_sched_groups)
14224132718Skan    {
14225132718Skan      enum attr_type type = get_attr_type (insn);
14226132718Skan      if (type == TYPE_BRANCH || type == TYPE_JMPREG)
14227132718Skan	return true;
14228132718Skan      return false;
14229132718Skan    }
14230132718Skan
14231132718Skan  return false;
14232132718Skan}
14233132718Skan
1423490075Sobrien/* A C statement (sans semicolon) to update the integer scheduling
14235132718Skan   priority INSN_PRIORITY (INSN). Increase the priority to execute the
14236132718Skan   INSN earlier, reduce the priority to execute INSN later.  Do not
1423790075Sobrien   define this macro if you do not need to adjust the scheduling
1423890075Sobrien   priorities of insns.  */
1423990075Sobrien
1424090075Sobrienstatic int
14241132718Skanrs6000_adjust_priority (rtx insn ATTRIBUTE_UNUSED, int priority)
1424290075Sobrien{
1424390075Sobrien  /* On machines (like the 750) which have asymmetric integer units,
1424490075Sobrien     where one integer unit can do multiply and divides and the other
1424590075Sobrien     can't, reduce the priority of multiply/divide so it is scheduled
1424690075Sobrien     before other integer operations.  */
1424790075Sobrien
1424890075Sobrien#if 0
1424990075Sobrien  if (! INSN_P (insn))
1425090075Sobrien    return priority;
1425190075Sobrien
1425290075Sobrien  if (GET_CODE (PATTERN (insn)) == USE)
1425390075Sobrien    return priority;
1425490075Sobrien
1425590075Sobrien  switch (rs6000_cpu_attr) {
1425690075Sobrien  case CPU_PPC750:
1425790075Sobrien    switch (get_attr_type (insn))
1425890075Sobrien      {
1425990075Sobrien      default:
1426090075Sobrien	break;
1426190075Sobrien
1426290075Sobrien      case TYPE_IMUL:
1426390075Sobrien      case TYPE_IDIV:
1426490075Sobrien	fprintf (stderr, "priority was %#x (%d) before adjustment\n",
1426590075Sobrien		 priority, priority);
1426690075Sobrien	if (priority >= 0 && priority < 0x01000000)
1426790075Sobrien	  priority >>= 3;
1426890075Sobrien	break;
1426990075Sobrien      }
1427090075Sobrien  }
1427190075Sobrien#endif
1427290075Sobrien
14273132718Skan  if (is_dispatch_slot_restricted (insn)
14274132718Skan      && reload_completed
14275132718Skan      && current_sched_info->sched_max_insns_priority
14276132718Skan      && rs6000_sched_restricted_insns_priority)
14277132718Skan    {
14278132718Skan
14279132718Skan      /* Prioritize insns that can be dispatched only in the first dispatch slot.  */
14280132718Skan      if (rs6000_sched_restricted_insns_priority == 1)
14281132718Skan	/* Attach highest priority to insn. This means that in
14282132718Skan	   haifa-sched.c:ready_sort(), dispatch-slot restriction considerations
14283132718Skan	   precede 'priority' (critical path) considerations.  */
14284132718Skan	return current_sched_info->sched_max_insns_priority;
14285132718Skan      else if (rs6000_sched_restricted_insns_priority == 2)
14286132718Skan	/* Increase priority of insn by a minimal amount. This means that in
14287132718Skan	   haifa-sched.c:ready_sort(), only 'priority' (critical path) considerations
14288132718Skan	   precede dispatch-slot restriction considerations.  */
14289132718Skan	return (priority + 1);
14290132718Skan    }
14291132718Skan
1429290075Sobrien  return priority;
1429390075Sobrien}
1429490075Sobrien
1429590075Sobrien/* Return how many instructions the machine can issue per cycle.  */
1429690075Sobrien
1429790075Sobrienstatic int
14298132718Skanrs6000_issue_rate (void)
1429990075Sobrien{
14300132718Skan  /* Use issue rate of 1 for first scheduling pass to decrease degradation.  */
14301132718Skan  if (!reload_completed)
14302132718Skan    return 1;
14303132718Skan
1430490075Sobrien  switch (rs6000_cpu_attr) {
1430590075Sobrien  case CPU_RIOS1:  /* ? */
1430690075Sobrien  case CPU_RS64A:
1430790075Sobrien  case CPU_PPC601: /* ? */
1430890075Sobrien  case CPU_PPC7450:
1430990075Sobrien    return 3;
14310132718Skan  case CPU_PPC440:
1431190075Sobrien  case CPU_PPC603:
1431290075Sobrien  case CPU_PPC750:
1431390075Sobrien  case CPU_PPC7400:
14314132718Skan  case CPU_PPC8540:
1431590075Sobrien    return 2;
1431690075Sobrien  case CPU_RIOS2:
1431790075Sobrien  case CPU_PPC604:
1431890075Sobrien  case CPU_PPC604E:
1431990075Sobrien  case CPU_PPC620:
1432090075Sobrien  case CPU_PPC630:
14321132718Skan    return 4;
14322117395Skan  case CPU_POWER4:
14323132718Skan  case CPU_POWER5:
14324132718Skan    return 5;
1432590075Sobrien  default:
1432690075Sobrien    return 1;
1432790075Sobrien  }
1432890075Sobrien}
1432990075Sobrien
14330132718Skan/* Return how many instructions to look ahead for better insn
14331132718Skan   scheduling.  */
14332132718Skan
14333132718Skanstatic int
14334132718Skanrs6000_use_sched_lookahead (void)
14335132718Skan{
14336132718Skan  if (rs6000_cpu_attr == CPU_PPC8540)
14337132718Skan    return 4;
14338132718Skan  return 0;
14339132718Skan}
14340132718Skan
14341132718Skan/* Determine is PAT refers to memory.  */
14342132718Skan
14343132718Skanstatic bool
14344132718Skanis_mem_ref (rtx pat)
14345132718Skan{
14346132718Skan  const char * fmt;
14347132718Skan  int i, j;
14348132718Skan  bool ret = false;
14349132718Skan
14350132718Skan  if (GET_CODE (pat) == MEM)
14351132718Skan    return true;
14352132718Skan
14353132718Skan  /* Recursively process the pattern.  */
14354132718Skan  fmt = GET_RTX_FORMAT (GET_CODE (pat));
14355132718Skan
14356132718Skan  for (i = GET_RTX_LENGTH (GET_CODE (pat)) - 1; i >= 0 && !ret; i--)
14357132718Skan    {
14358132718Skan      if (fmt[i] == 'e')
14359132718Skan	ret |= is_mem_ref (XEXP (pat, i));
14360132718Skan      else if (fmt[i] == 'E')
14361132718Skan	for (j = XVECLEN (pat, i) - 1; j >= 0; j--)
14362132718Skan	  ret |= is_mem_ref (XVECEXP (pat, i, j));
14363132718Skan    }
14364132718Skan
14365132718Skan  return ret;
14366132718Skan}
14367132718Skan
14368132718Skan/* Determine if PAT is a PATTERN of a load insn.  */
14369132718Skan
14370132718Skanstatic bool
14371132718Skanis_load_insn1 (rtx pat)
14372132718Skan{
14373132718Skan  if (!pat || pat == NULL_RTX)
14374132718Skan    return false;
14375132718Skan
14376132718Skan  if (GET_CODE (pat) == SET)
14377132718Skan    return is_mem_ref (SET_SRC (pat));
14378132718Skan
14379132718Skan  if (GET_CODE (pat) == PARALLEL)
14380132718Skan    {
14381132718Skan      int i;
14382132718Skan
14383132718Skan      for (i = 0; i < XVECLEN (pat, 0); i++)
14384132718Skan	if (is_load_insn1 (XVECEXP (pat, 0, i)))
14385132718Skan	  return true;
14386132718Skan    }
14387132718Skan
14388132718Skan  return false;
14389132718Skan}
14390132718Skan
14391132718Skan/* Determine if INSN loads from memory.  */
14392132718Skan
14393132718Skanstatic bool
14394132718Skanis_load_insn (rtx insn)
14395132718Skan{
14396132718Skan  if (!insn || !INSN_P (insn))
14397132718Skan    return false;
14398132718Skan
14399132718Skan  if (GET_CODE (insn) == CALL_INSN)
14400132718Skan    return false;
14401132718Skan
14402132718Skan  return is_load_insn1 (PATTERN (insn));
14403132718Skan}
14404132718Skan
14405132718Skan/* Determine if PAT is a PATTERN of a store insn.  */
14406132718Skan
14407132718Skanstatic bool
14408132718Skanis_store_insn1 (rtx pat)
14409132718Skan{
14410132718Skan  if (!pat || pat == NULL_RTX)
14411132718Skan    return false;
14412132718Skan
14413132718Skan  if (GET_CODE (pat) == SET)
14414132718Skan    return is_mem_ref (SET_DEST (pat));
14415132718Skan
14416132718Skan  if (GET_CODE (pat) == PARALLEL)
14417132718Skan    {
14418132718Skan      int i;
14419132718Skan
14420132718Skan      for (i = 0; i < XVECLEN (pat, 0); i++)
14421132718Skan	if (is_store_insn1 (XVECEXP (pat, 0, i)))
14422132718Skan	  return true;
14423132718Skan    }
14424132718Skan
14425132718Skan  return false;
14426132718Skan}
14427132718Skan
14428132718Skan/* Determine if INSN stores to memory.  */
14429132718Skan
14430132718Skanstatic bool
14431132718Skanis_store_insn (rtx insn)
14432132718Skan{
14433132718Skan  if (!insn || !INSN_P (insn))
14434132718Skan    return false;
14435132718Skan
14436132718Skan  return is_store_insn1 (PATTERN (insn));
14437132718Skan}
14438132718Skan
14439132718Skan/* Returns whether the dependence between INSN and NEXT is considered
14440132718Skan   costly by the given target.  */
14441132718Skan
14442132718Skanstatic bool
14443132718Skanrs6000_is_costly_dependence (rtx insn, rtx next, rtx link, int cost, int distance)
14444132718Skan{
14445132718Skan  /* If the flag is not enbled - no dependence is considered costly;
14446132718Skan     allow all dependent insns in the same group.
14447132718Skan     This is the most aggressive option.  */
14448132718Skan  if (rs6000_sched_costly_dep == no_dep_costly)
14449132718Skan    return false;
14450132718Skan
14451132718Skan  /* If the flag is set to 1 - a dependence is always considered costly;
14452132718Skan     do not allow dependent instructions in the same group.
14453132718Skan     This is the most conservative option.  */
14454132718Skan  if (rs6000_sched_costly_dep == all_deps_costly)
14455132718Skan    return true;
14456132718Skan
14457132718Skan  if (rs6000_sched_costly_dep == store_to_load_dep_costly
14458132718Skan      && is_load_insn (next)
14459132718Skan      && is_store_insn (insn))
14460132718Skan    /* Prevent load after store in the same group.  */
14461132718Skan    return true;
14462132718Skan
14463132718Skan  if (rs6000_sched_costly_dep == true_store_to_load_dep_costly
14464132718Skan      && is_load_insn (next)
14465132718Skan      && is_store_insn (insn)
14466132718Skan      && (!link || (int) REG_NOTE_KIND (link) == 0))
14467132718Skan     /* Prevent load after store in the same group if it is a true dependence.  */
14468132718Skan     return true;
14469132718Skan
14470132718Skan  /* The flag is set to X; dependences with latency >= X are considered costly,
14471132718Skan     and will not be scheduled in the same group.  */
14472132718Skan  if (rs6000_sched_costly_dep <= max_dep_latency
14473132718Skan      && ((cost - distance) >= (int)rs6000_sched_costly_dep))
14474132718Skan    return true;
14475132718Skan
14476132718Skan  return false;
14477132718Skan}
14478132718Skan
14479132718Skan/* Return the next insn after INSN that is found before TAIL is reached,
14480132718Skan   skipping any "non-active" insns - insns that will not actually occupy
14481132718Skan   an issue slot.  Return NULL_RTX if such an insn is not found.  */
14482132718Skan
14483132718Skanstatic rtx
14484132718Skanget_next_active_insn (rtx insn, rtx tail)
14485132718Skan{
14486132718Skan  rtx next_insn;
14487132718Skan
14488132718Skan  if (!insn || insn == tail)
14489132718Skan    return NULL_RTX;
14490132718Skan
14491132718Skan  next_insn = NEXT_INSN (insn);
14492132718Skan
14493132718Skan  while (next_insn
14494132718Skan  	 && next_insn != tail
14495132718Skan	 && (GET_CODE(next_insn) == NOTE
14496132718Skan	     || GET_CODE (PATTERN (next_insn)) == USE
14497132718Skan	     || GET_CODE (PATTERN (next_insn)) == CLOBBER))
14498132718Skan    {
14499132718Skan      next_insn = NEXT_INSN (next_insn);
14500132718Skan    }
14501132718Skan
14502132718Skan  if (!next_insn || next_insn == tail)
14503132718Skan    return NULL_RTX;
14504132718Skan
14505132718Skan  return next_insn;
14506132718Skan}
14507132718Skan
14508132718Skan/* Return whether the presence of INSN causes a dispatch group termination
14509132718Skan   of group WHICH_GROUP.
14510132718Skan
14511132718Skan   If WHICH_GROUP == current_group, this function will return true if INSN
14512132718Skan   causes the termination of the current group (i.e, the dispatch group to
14513132718Skan   which INSN belongs). This means that INSN will be the last insn in the
14514132718Skan   group it belongs to.
14515132718Skan
14516132718Skan   If WHICH_GROUP == previous_group, this function will return true if INSN
14517132718Skan   causes the termination of the previous group (i.e, the dispatch group that
14518132718Skan   precedes the group to which INSN belongs).  This means that INSN will be
14519132718Skan   the first insn in the group it belongs to).  */
14520132718Skan
14521132718Skanstatic bool
14522132718Skaninsn_terminates_group_p (rtx insn, enum group_termination which_group)
14523132718Skan{
14524132718Skan  enum attr_type type;
14525132718Skan
14526132718Skan  if (! insn)
14527132718Skan    return false;
14528132718Skan
14529132718Skan  type = get_attr_type (insn);
14530132718Skan
14531132718Skan  if (is_microcoded_insn (insn))
14532132718Skan    return true;
14533132718Skan
14534132718Skan  if (which_group == current_group)
14535132718Skan    {
14536132718Skan      if (is_branch_slot_insn (insn))
14537132718Skan        return true;
14538132718Skan      return false;
14539132718Skan    }
14540132718Skan  else if (which_group == previous_group)
14541132718Skan    {
14542132718Skan      if (is_dispatch_slot_restricted (insn))
14543132718Skan        return true;
14544132718Skan      return false;
14545132718Skan    }
14546132718Skan
14547132718Skan  return false;
14548132718Skan}
14549132718Skan
14550132718Skan/* Return true if it is recommended to keep NEXT_INSN "far" (in a separate
14551132718Skan   dispatch group) from the insns in GROUP_INSNS.  Return false otherwise.  */
14552132718Skan
14553132718Skanstatic bool
14554132718Skanis_costly_group (rtx *group_insns, rtx next_insn)
14555132718Skan{
14556132718Skan  int i;
14557132718Skan  rtx link;
14558132718Skan  int cost;
14559132718Skan  int issue_rate = rs6000_issue_rate ();
14560132718Skan
14561132718Skan  for (i = 0; i < issue_rate; i++)
14562132718Skan    {
14563132718Skan      rtx insn = group_insns[i];
14564132718Skan      if (!insn)
14565132718Skan        continue;
14566132718Skan      for (link = INSN_DEPEND (insn); link != 0; link = XEXP (link, 1))
14567132718Skan        {
14568132718Skan          rtx next = XEXP (link, 0);
14569132718Skan          if (next == next_insn)
14570132718Skan            {
14571132718Skan              cost = insn_cost (insn, link, next_insn);
14572132718Skan              if (rs6000_is_costly_dependence (insn, next_insn, link, cost, 0))
14573132718Skan                return true;
14574132718Skan            }
14575132718Skan        }
14576132718Skan    }
14577132718Skan
14578132718Skan  return false;
14579132718Skan}
14580132718Skan
14581132718Skan/* Utility of the function redefine_groups.
14582132718Skan   Check if it is too costly to schedule NEXT_INSN together with GROUP_INSNS
14583132718Skan   in the same dispatch group.  If so, insert nops before NEXT_INSN, in order
14584132718Skan   to keep it "far" (in a separate group) from GROUP_INSNS, following
14585132718Skan   one of the following schemes, depending on the value of the flag
14586132718Skan   -minsert_sched_nops = X:
14587132718Skan   (1) X == sched_finish_regroup_exact: insert exactly as many nops as needed
14588132718Skan       in order to force NEXT_INSN into a separate group.
14589132718Skan   (2) X < sched_finish_regroup_exact: insert exactly X nops.
14590132718Skan   GROUP_END, CAN_ISSUE_MORE and GROUP_COUNT record the state after nop
14591132718Skan   insertion (has a group just ended, how many vacant issue slots remain in the
14592132718Skan   last group, and how many dispatch groups were encountered so far).  */
14593132718Skan
14594132718Skanstatic int
14595132718Skanforce_new_group (int sched_verbose, FILE *dump, rtx *group_insns, rtx next_insn,
14596132718Skan		 bool *group_end, int can_issue_more, int *group_count)
14597132718Skan{
14598132718Skan  rtx nop;
14599132718Skan  bool force;
14600132718Skan  int issue_rate = rs6000_issue_rate ();
14601132718Skan  bool end = *group_end;
14602132718Skan  int i;
14603132718Skan
14604132718Skan  if (next_insn == NULL_RTX)
14605132718Skan    return can_issue_more;
14606132718Skan
14607132718Skan  if (rs6000_sched_insert_nops > sched_finish_regroup_exact)
14608132718Skan    return can_issue_more;
14609132718Skan
14610132718Skan  force = is_costly_group (group_insns, next_insn);
14611132718Skan  if (!force)
14612132718Skan    return can_issue_more;
14613132718Skan
14614132718Skan  if (sched_verbose > 6)
14615132718Skan    fprintf (dump,"force: group count = %d, can_issue_more = %d\n",
14616132718Skan			*group_count ,can_issue_more);
14617132718Skan
14618132718Skan  if (rs6000_sched_insert_nops == sched_finish_regroup_exact)
14619132718Skan    {
14620132718Skan      if (*group_end)
14621132718Skan        can_issue_more = 0;
14622132718Skan
14623132718Skan      /* Since only a branch can be issued in the last issue_slot, it is
14624132718Skan	 sufficient to insert 'can_issue_more - 1' nops if next_insn is not
14625132718Skan	 a branch. If next_insn is a branch, we insert 'can_issue_more' nops;
14626132718Skan	 in this case the last nop will start a new group and the branch will be
14627132718Skan	 forced to the new group.  */
14628132718Skan      if (can_issue_more && !is_branch_slot_insn (next_insn))
14629132718Skan        can_issue_more--;
14630132718Skan
14631132718Skan      while (can_issue_more > 0)
14632132718Skan        {
14633132718Skan          nop = gen_nop();
14634132718Skan          emit_insn_before (nop, next_insn);
14635132718Skan          can_issue_more--;
14636132718Skan        }
14637132718Skan
14638132718Skan      *group_end = true;
14639132718Skan      return 0;
14640132718Skan    }
14641132718Skan
14642132718Skan  if (rs6000_sched_insert_nops < sched_finish_regroup_exact)
14643132718Skan    {
14644132718Skan      int n_nops = rs6000_sched_insert_nops;
14645132718Skan
14646132718Skan      /* Nops can't be issued from the branch slot, so the effective
14647132718Skan         issue_rate for nops is 'issue_rate - 1'.  */
14648132718Skan      if (can_issue_more == 0)
14649132718Skan        can_issue_more = issue_rate;
14650132718Skan      can_issue_more--;
14651132718Skan      if (can_issue_more == 0)
14652132718Skan        {
14653132718Skan          can_issue_more = issue_rate - 1;
14654132718Skan          (*group_count)++;
14655132718Skan          end = true;
14656132718Skan          for (i = 0; i < issue_rate; i++)
14657132718Skan            {
14658132718Skan              group_insns[i] = 0;
14659132718Skan            }
14660132718Skan        }
14661132718Skan
14662132718Skan      while (n_nops > 0)
14663132718Skan        {
14664132718Skan          nop = gen_nop ();
14665132718Skan          emit_insn_before (nop, next_insn);
14666132718Skan          if (can_issue_more == issue_rate - 1) /* new group begins */
14667132718Skan            end = false;
14668132718Skan          can_issue_more--;
14669132718Skan          if (can_issue_more == 0)
14670132718Skan            {
14671132718Skan              can_issue_more = issue_rate - 1;
14672132718Skan              (*group_count)++;
14673132718Skan              end = true;
14674132718Skan              for (i = 0; i < issue_rate; i++)
14675132718Skan                {
14676132718Skan                  group_insns[i] = 0;
14677132718Skan                }
14678132718Skan            }
14679132718Skan          n_nops--;
14680132718Skan        }
14681132718Skan
14682132718Skan      /* Scale back relative to 'issue_rate' (instead of 'issue_rate - 1').  */
14683132718Skan      can_issue_more++;
14684132718Skan
14685132718Skan      *group_end = /* Is next_insn going to start a new group?  */
14686132718Skan	  (end
14687132718Skan	   || (can_issue_more == 1 && !is_branch_slot_insn (next_insn))
14688132718Skan	   || (can_issue_more <= 2 && is_cracked_insn (next_insn))
14689132718Skan	   || (can_issue_more < issue_rate &&
14690132718Skan	      insn_terminates_group_p (next_insn, previous_group)));
14691132718Skan      if (*group_end && end)
14692132718Skan        (*group_count)--;
14693132718Skan
14694132718Skan      if (sched_verbose > 6)
14695132718Skan        fprintf (dump, "done force: group count = %d, can_issue_more = %d\n",
14696132718Skan			*group_count, can_issue_more);
14697132718Skan      return can_issue_more;
14698132718Skan    }
14699132718Skan
14700132718Skan  return can_issue_more;
14701132718Skan}
14702132718Skan
14703132718Skan/* This function tries to synch the dispatch groups that the compiler "sees"
14704132718Skan   with the dispatch groups that the processor dispatcher is expected to
14705132718Skan   form in practice.  It tries to achieve this synchronization by forcing the
14706132718Skan   estimated processor grouping on the compiler (as opposed to the function
14707132718Skan   'pad_goups' which tries to force the scheduler's grouping on the processor).
14708132718Skan
14709132718Skan   The function scans the insn sequence between PREV_HEAD_INSN and TAIL and
14710132718Skan   examines the (estimated) dispatch groups that will be formed by the processor
14711132718Skan   dispatcher.  It marks these group boundaries to reflect the estimated
14712132718Skan   processor grouping, overriding the grouping that the scheduler had marked.
14713132718Skan   Depending on the value of the flag '-minsert-sched-nops' this function can
14714132718Skan   force certain insns into separate groups or force a certain distance between
14715132718Skan   them by inserting nops, for example, if there exists a "costly dependence"
14716132718Skan   between the insns.
14717132718Skan
14718132718Skan   The function estimates the group boundaries that the processor will form as
14719132718Skan   folllows:  It keeps track of how many vacant issue slots are available after
14720132718Skan   each insn.  A subsequent insn will start a new group if one of the following
14721132718Skan   4 cases applies:
14722132718Skan   - no more vacant issue slots remain in the current dispatch group.
14723132718Skan   - only the last issue slot, which is the branch slot, is vacant, but the next
14724132718Skan     insn is not a branch.
14725132718Skan   - only the last 2 or less issue slots, including the branch slot, are vacant,
14726132718Skan     which means that a cracked insn (which occupies two issue slots) can't be
14727132718Skan     issued in this group.
14728132718Skan   - less than 'issue_rate' slots are vacant, and the next insn always needs to
14729132718Skan     start a new group.  */
14730132718Skan
14731132718Skanstatic int
14732132718Skanredefine_groups (FILE *dump, int sched_verbose, rtx prev_head_insn, rtx tail)
14733132718Skan{
14734132718Skan  rtx insn, next_insn;
14735132718Skan  int issue_rate;
14736132718Skan  int can_issue_more;
14737132718Skan  int slot, i;
14738132718Skan  bool group_end;
14739132718Skan  int group_count = 0;
14740132718Skan  rtx *group_insns;
14741132718Skan
14742132718Skan  /* Initialize.  */
14743132718Skan  issue_rate = rs6000_issue_rate ();
14744132718Skan  group_insns = alloca (issue_rate * sizeof (rtx));
14745132718Skan  for (i = 0; i < issue_rate; i++)
14746132718Skan    {
14747132718Skan      group_insns[i] = 0;
14748132718Skan    }
14749132718Skan  can_issue_more = issue_rate;
14750132718Skan  slot = 0;
14751132718Skan  insn = get_next_active_insn (prev_head_insn, tail);
14752132718Skan  group_end = false;
14753132718Skan
14754132718Skan  while (insn != NULL_RTX)
14755132718Skan    {
14756132718Skan      slot = (issue_rate - can_issue_more);
14757132718Skan      group_insns[slot] = insn;
14758132718Skan      can_issue_more =
14759132718Skan        rs6000_variable_issue (dump, sched_verbose, insn, can_issue_more);
14760132718Skan      if (insn_terminates_group_p (insn, current_group))
14761132718Skan        can_issue_more = 0;
14762132718Skan
14763132718Skan      next_insn = get_next_active_insn (insn, tail);
14764132718Skan      if (next_insn == NULL_RTX)
14765132718Skan        return group_count + 1;
14766132718Skan
14767132718Skan      group_end = /* Is next_insn going to start a new group?  */
14768132718Skan        (can_issue_more == 0
14769132718Skan         || (can_issue_more == 1 && !is_branch_slot_insn (next_insn))
14770132718Skan         || (can_issue_more <= 2 && is_cracked_insn (next_insn))
14771132718Skan         || (can_issue_more < issue_rate &&
14772132718Skan             insn_terminates_group_p (next_insn, previous_group)));
14773132718Skan
14774132718Skan      can_issue_more = force_new_group (sched_verbose, dump, group_insns,
14775132718Skan			next_insn, &group_end, can_issue_more, &group_count);
14776132718Skan
14777132718Skan      if (group_end)
14778132718Skan        {
14779132718Skan          group_count++;
14780132718Skan          can_issue_more = 0;
14781132718Skan          for (i = 0; i < issue_rate; i++)
14782132718Skan            {
14783132718Skan              group_insns[i] = 0;
14784132718Skan            }
14785132718Skan        }
14786132718Skan
14787132718Skan      if (GET_MODE (next_insn) == TImode && can_issue_more)
14788132718Skan        PUT_MODE(next_insn, VOIDmode);
14789132718Skan      else if (!can_issue_more && GET_MODE (next_insn) != TImode)
14790132718Skan        PUT_MODE (next_insn, TImode);
14791132718Skan
14792132718Skan      insn = next_insn;
14793132718Skan      if (can_issue_more == 0)
14794132718Skan        can_issue_more = issue_rate;
14795132718Skan   } /* while */
14796132718Skan
14797132718Skan  return group_count;
14798132718Skan}
14799132718Skan
14800132718Skan/* Scan the insn sequence between PREV_HEAD_INSN and TAIL and examine the
14801132718Skan   dispatch group boundaries that the scheduler had marked.  Pad with nops
14802132718Skan   any dispatch groups which have vacant issue slots, in order to force the
14803132718Skan   scheduler's grouping on the processor dispatcher.  The function
14804132718Skan   returns the number of dispatch groups found.  */
14805132718Skan
14806132718Skanstatic int
14807132718Skanpad_groups (FILE *dump, int sched_verbose, rtx prev_head_insn, rtx tail)
14808132718Skan{
14809132718Skan  rtx insn, next_insn;
14810132718Skan  rtx nop;
14811132718Skan  int issue_rate;
14812132718Skan  int can_issue_more;
14813132718Skan  int group_end;
14814132718Skan  int group_count = 0;
14815132718Skan
14816132718Skan  /* Initialize issue_rate.  */
14817132718Skan  issue_rate = rs6000_issue_rate ();
14818132718Skan  can_issue_more = issue_rate;
14819132718Skan
14820132718Skan  insn = get_next_active_insn (prev_head_insn, tail);
14821132718Skan  next_insn = get_next_active_insn (insn, tail);
14822132718Skan
14823132718Skan  while (insn != NULL_RTX)
14824132718Skan    {
14825132718Skan      can_issue_more =
14826132718Skan      	rs6000_variable_issue (dump, sched_verbose, insn, can_issue_more);
14827132718Skan
14828132718Skan      group_end = (next_insn == NULL_RTX || GET_MODE (next_insn) == TImode);
14829132718Skan
14830132718Skan      if (next_insn == NULL_RTX)
14831132718Skan        break;
14832132718Skan
14833132718Skan      if (group_end)
14834132718Skan        {
14835132718Skan          /* If the scheduler had marked group termination at this location
14836132718Skan             (between insn and next_indn), and neither insn nor next_insn will
14837132718Skan             force group termination, pad the group with nops to force group
14838132718Skan             termination.  */
14839132718Skan          if (can_issue_more
14840132718Skan              && (rs6000_sched_insert_nops == sched_finish_pad_groups)
14841132718Skan              && !insn_terminates_group_p (insn, current_group)
14842132718Skan              && !insn_terminates_group_p (next_insn, previous_group))
14843132718Skan            {
14844132718Skan              if (!is_branch_slot_insn(next_insn))
14845132718Skan                can_issue_more--;
14846132718Skan
14847132718Skan              while (can_issue_more)
14848132718Skan                {
14849132718Skan                  nop = gen_nop ();
14850132718Skan                  emit_insn_before (nop, next_insn);
14851132718Skan                  can_issue_more--;
14852132718Skan                }
14853132718Skan            }
14854132718Skan
14855132718Skan          can_issue_more = issue_rate;
14856132718Skan          group_count++;
14857132718Skan        }
14858132718Skan
14859132718Skan      insn = next_insn;
14860132718Skan      next_insn = get_next_active_insn (insn, tail);
14861132718Skan    }
14862132718Skan
14863132718Skan  return group_count;
14864132718Skan}
14865132718Skan
14866132718Skan/* The following function is called at the end of scheduling BB.
14867132718Skan   After reload, it inserts nops at insn group bundling.  */
14868132718Skan
14869132718Skanstatic void
14870132718Skanrs6000_sched_finish (FILE *dump, int sched_verbose)
14871132718Skan{
14872132718Skan  int n_groups;
14873132718Skan
14874132718Skan  if (sched_verbose)
14875132718Skan    fprintf (dump, "=== Finishing schedule.\n");
14876132718Skan
14877132718Skan  if (reload_completed && rs6000_sched_groups)
14878132718Skan    {
14879132718Skan      if (rs6000_sched_insert_nops == sched_finish_none)
14880132718Skan        return;
14881132718Skan
14882132718Skan      if (rs6000_sched_insert_nops == sched_finish_pad_groups)
14883132718Skan        n_groups = pad_groups (dump, sched_verbose,
14884132718Skan				current_sched_info->prev_head,
14885132718Skan  			   	current_sched_info->next_tail);
14886132718Skan      else
14887132718Skan        n_groups = redefine_groups (dump, sched_verbose,
14888132718Skan				current_sched_info->prev_head,
14889132718Skan  				current_sched_info->next_tail);
14890132718Skan
14891132718Skan      if (sched_verbose >= 6)
14892132718Skan	{
14893132718Skan    	  fprintf (dump, "ngroups = %d\n", n_groups);
14894132718Skan	  print_rtl (dump, current_sched_info->prev_head);
14895132718Skan	  fprintf (dump, "Done finish_sched\n");
14896132718Skan	}
14897132718Skan    }
14898132718Skan}
1489990075Sobrien
1490090075Sobrien/* Length in units of the trampoline for entering a nested function.  */
1490190075Sobrien
1490290075Sobrienint
14903132718Skanrs6000_trampoline_size (void)
1490490075Sobrien{
1490590075Sobrien  int ret = 0;
1490690075Sobrien
1490790075Sobrien  switch (DEFAULT_ABI)
1490890075Sobrien    {
1490990075Sobrien    default:
1491090075Sobrien      abort ();
1491190075Sobrien
1491290075Sobrien    case ABI_AIX:
1491390075Sobrien      ret = (TARGET_32BIT) ? 12 : 24;
1491490075Sobrien      break;
1491590075Sobrien
1491690075Sobrien    case ABI_DARWIN:
1491790075Sobrien    case ABI_V4:
1491890075Sobrien      ret = (TARGET_32BIT) ? 40 : 48;
1491990075Sobrien      break;
1492090075Sobrien    }
1492190075Sobrien
1492290075Sobrien  return ret;
1492390075Sobrien}
1492490075Sobrien
1492590075Sobrien/* Emit RTL insns to initialize the variable parts of a trampoline.
1492690075Sobrien   FNADDR is an RTX for the address of the function's pure code.
1492790075Sobrien   CXT is an RTX for the static chain value for the function.  */
1492890075Sobrien
1492990075Sobrienvoid
14930132718Skanrs6000_initialize_trampoline (rtx addr, rtx fnaddr, rtx cxt)
1493190075Sobrien{
1493290075Sobrien  enum machine_mode pmode = Pmode;
1493390075Sobrien  int regsize = (TARGET_32BIT) ? 4 : 8;
1493490075Sobrien  rtx ctx_reg = force_reg (pmode, cxt);
1493590075Sobrien
1493690075Sobrien  switch (DEFAULT_ABI)
1493790075Sobrien    {
1493890075Sobrien    default:
1493990075Sobrien      abort ();
1494090075Sobrien
1494190075Sobrien/* Macros to shorten the code expansions below.  */
1494290075Sobrien#define MEM_DEREF(addr) gen_rtx_MEM (pmode, memory_address (pmode, addr))
1494390075Sobrien#define MEM_PLUS(addr,offset) \
1494490075Sobrien  gen_rtx_MEM (pmode, memory_address (pmode, plus_constant (addr, offset)))
1494590075Sobrien
1494690075Sobrien    /* Under AIX, just build the 3 word function descriptor */
1494790075Sobrien    case ABI_AIX:
1494890075Sobrien      {
1494990075Sobrien	rtx fn_reg = gen_reg_rtx (pmode);
1495090075Sobrien	rtx toc_reg = gen_reg_rtx (pmode);
1495190075Sobrien	emit_move_insn (fn_reg, MEM_DEREF (fnaddr));
1495290075Sobrien	emit_move_insn (toc_reg, MEM_PLUS (fnaddr, regsize));
1495390075Sobrien	emit_move_insn (MEM_DEREF (addr), fn_reg);
1495490075Sobrien	emit_move_insn (MEM_PLUS (addr, regsize), toc_reg);
1495590075Sobrien	emit_move_insn (MEM_PLUS (addr, 2*regsize), ctx_reg);
1495690075Sobrien      }
1495790075Sobrien      break;
1495890075Sobrien
1495990075Sobrien    /* Under V.4/eabi/darwin, __trampoline_setup does the real work.  */
1496090075Sobrien    case ABI_DARWIN:
1496190075Sobrien    case ABI_V4:
1496290075Sobrien      emit_library_call (gen_rtx_SYMBOL_REF (SImode, "__trampoline_setup"),
1496390075Sobrien			 FALSE, VOIDmode, 4,
1496490075Sobrien			 addr, pmode,
1496590075Sobrien			 GEN_INT (rs6000_trampoline_size ()), SImode,
1496690075Sobrien			 fnaddr, pmode,
1496790075Sobrien			 ctx_reg, pmode);
1496890075Sobrien      break;
1496990075Sobrien    }
1497090075Sobrien
1497190075Sobrien  return;
1497290075Sobrien}
1497390075Sobrien
1497490075Sobrien
1497590075Sobrien/* Table of valid machine attributes.  */
1497690075Sobrien
1497790075Sobrienconst struct attribute_spec rs6000_attribute_table[] =
1497890075Sobrien{
1497990075Sobrien  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
14980146895Skan  { "altivec",   1, 1, false, true,  false, rs6000_handle_altivec_attribute },
14981117395Skan  { "longcall",  0, 0, false, true,  true,  rs6000_handle_longcall_attribute },
14982117395Skan  { "shortcall", 0, 0, false, true,  true,  rs6000_handle_longcall_attribute },
14983117395Skan  { NULL,        0, 0, false, false, false, NULL }
1498490075Sobrien};
1498590075Sobrien
14986146895Skan/* Handle the "altivec" attribute.  The attribute may have
14987146895Skan   arguments as follows:
14988146895Skan
14989146895Skan       __attribute__((altivec(vector__)))
14990146895Skan       __attribute__((altivec(pixel__)))       (always followed by 'unsigned short')
14991146895Skan       __attribute__((altivec(bool__)))        (always followed by 'unsigned')
14992146895Skan
14993146895Skan  and may appear more than once (e.g., 'vector bool char') in a
14994146895Skan  given declaration.  */
14995146895Skan
14996146895Skanstatic tree
14997146895Skanrs6000_handle_altivec_attribute (tree *node, tree name, tree args,
14998146895Skan				 int flags ATTRIBUTE_UNUSED,
14999146895Skan				 bool *no_add_attrs)
15000146895Skan{
15001146895Skan  tree type = *node, result = NULL_TREE;
15002146895Skan  enum machine_mode mode;
15003146895Skan  int unsigned_p;
15004146895Skan  char altivec_type
15005146895Skan    = ((args && TREE_CODE (args) == TREE_LIST && TREE_VALUE (args)
15006146895Skan       && TREE_CODE (TREE_VALUE (args)) == IDENTIFIER_NODE)
15007146895Skan       ? *IDENTIFIER_POINTER (TREE_VALUE (args))
15008146895Skan       : '?');
15009146895Skan
15010146895Skan  while (POINTER_TYPE_P (type)
15011146895Skan	 || TREE_CODE (type) == FUNCTION_TYPE
15012146895Skan	 || TREE_CODE (type) == METHOD_TYPE
15013146895Skan	 || TREE_CODE (type) == ARRAY_TYPE)
15014146895Skan    type = TREE_TYPE (type);
15015146895Skan
15016146895Skan  mode = TYPE_MODE (type);
15017146895Skan
15018146895Skan  if (rs6000_warn_altivec_long
15019146895Skan      && (type == long_unsigned_type_node || type == long_integer_type_node))
15020146895Skan    warning ("use of 'long' in AltiVec types is deprecated; use 'int'");
15021146895Skan
15022146895Skan  switch (altivec_type)
15023146895Skan    {
15024146895Skan    case 'v':
15025146895Skan      unsigned_p = TREE_UNSIGNED (type);
15026146895Skan      switch (mode)
15027146895Skan	{
15028146895Skan	  case SImode:
15029146895Skan	    result = (unsigned_p ? unsigned_V4SI_type_node : V4SI_type_node);
15030146895Skan	    break;
15031146895Skan	  case HImode:
15032146895Skan	    result = (unsigned_p ? unsigned_V8HI_type_node : V8HI_type_node);
15033146895Skan	    break;
15034146895Skan	  case QImode:
15035146895Skan	    result = (unsigned_p ? unsigned_V16QI_type_node : V16QI_type_node);
15036146895Skan	    break;
15037146895Skan	  case SFmode: result = V4SF_type_node; break;
15038146895Skan	    /* If the user says 'vector int bool', we may be handed the 'bool'
15039146895Skan	       attribute _before_ the 'vector' attribute, and so select the proper
15040146895Skan	       type in the 'b' case below.  */
15041146895Skan	  case V4SImode: case V8HImode: case V16QImode: result = type;
15042146895Skan	  default: break;
15043146895Skan	}
15044146895Skan      break;
15045146895Skan    case 'b':
15046146895Skan      switch (mode)
15047146895Skan	{
15048146895Skan	  case SImode: case V4SImode: result = bool_V4SI_type_node; break;
15049146895Skan	  case HImode: case V8HImode: result = bool_V8HI_type_node; break;
15050146895Skan	  case QImode: case V16QImode: result = bool_V16QI_type_node;
15051146895Skan	  default: break;
15052146895Skan	}
15053146895Skan      break;
15054146895Skan    case 'p':
15055146895Skan      switch (mode)
15056146895Skan	{
15057146895Skan	  case V8HImode: result = pixel_V8HI_type_node;
15058146895Skan	  default: break;
15059146895Skan	}
15060146895Skan    default: break;
15061146895Skan    }
15062146895Skan
15063146895Skan  if (result && result != type && TYPE_READONLY (type))
15064146895Skan    result = build_qualified_type (result, TYPE_QUAL_CONST);
15065146895Skan
15066146895Skan  *no_add_attrs = true;  /* No need to hang on to the attribute.  */
15067146895Skan
15068146895Skan  if (!result)
15069146895Skan    warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
15070146895Skan  else
15071146895Skan    *node = reconstruct_complex_type (*node, result);
15072146895Skan
15073146895Skan  return NULL_TREE;
15074146895Skan}
15075146895Skan
15076146895Skan/* AltiVec defines four built-in scalar types that serve as vector
15077146895Skan   elements; we must teach the compiler how to mangle them.  */
15078146895Skan
15079146895Skanstatic const char *
15080146895Skanrs6000_mangle_fundamental_type (tree type)
15081146895Skan{
15082146895Skan  if (type == bool_char_type_node) return "U6__boolc";
15083146895Skan  if (type == bool_short_type_node) return "U6__bools";
15084146895Skan  if (type == pixel_type_node) return "u7__pixel";
15085146895Skan  if (type == bool_int_type_node) return "U6__booli";
15086146895Skan
15087146895Skan  /* For all other types, use normal C++ mangling.  */
15088146895Skan  return NULL;
15089146895Skan}
15090146895Skan
15091117395Skan/* Handle a "longcall" or "shortcall" attribute; arguments as in
15092117395Skan   struct attribute_spec.handler.  */
1509390075Sobrien
1509490075Sobrienstatic tree
15095132718Skanrs6000_handle_longcall_attribute (tree *node, tree name,
15096132718Skan				  tree args ATTRIBUTE_UNUSED,
15097132718Skan				  int flags ATTRIBUTE_UNUSED,
15098132718Skan				  bool *no_add_attrs)
1509990075Sobrien{
1510090075Sobrien  if (TREE_CODE (*node) != FUNCTION_TYPE
1510190075Sobrien      && TREE_CODE (*node) != FIELD_DECL
1510290075Sobrien      && TREE_CODE (*node) != TYPE_DECL)
1510390075Sobrien    {
1510490075Sobrien      warning ("`%s' attribute only applies to functions",
1510590075Sobrien	       IDENTIFIER_POINTER (name));
1510690075Sobrien      *no_add_attrs = true;
1510790075Sobrien    }
1510890075Sobrien
1510990075Sobrien  return NULL_TREE;
1511090075Sobrien}
1511190075Sobrien
15112117395Skan/* Set longcall attributes on all functions declared when
15113117395Skan   rs6000_default_long_calls is true.  */
15114117395Skanstatic void
15115132718Skanrs6000_set_default_type_attributes (tree type)
15116117395Skan{
15117117395Skan  if (rs6000_default_long_calls
15118117395Skan      && (TREE_CODE (type) == FUNCTION_TYPE
15119117395Skan	  || TREE_CODE (type) == METHOD_TYPE))
15120117395Skan    TYPE_ATTRIBUTES (type) = tree_cons (get_identifier ("longcall"),
15121117395Skan					NULL_TREE,
15122117395Skan					TYPE_ATTRIBUTES (type));
15123117395Skan}
15124117395Skan
1512590075Sobrien/* Return a reference suitable for calling a function with the
1512690075Sobrien   longcall attribute.  */
1512790075Sobrien
1512890075Sobrienstruct rtx_def *
15129132718Skanrs6000_longcall_ref (rtx call_ref)
1513090075Sobrien{
1513190075Sobrien  const char *call_name;
1513290075Sobrien  tree node;
1513390075Sobrien
1513490075Sobrien  if (GET_CODE (call_ref) != SYMBOL_REF)
1513590075Sobrien    return call_ref;
1513690075Sobrien
1513790075Sobrien  /* System V adds '.' to the internal name, so skip them.  */
1513890075Sobrien  call_name = XSTR (call_ref, 0);
1513990075Sobrien  if (*call_name == '.')
1514090075Sobrien    {
1514190075Sobrien      while (*call_name == '.')
1514290075Sobrien	call_name++;
1514390075Sobrien
1514490075Sobrien      node = get_identifier (call_name);
1514590075Sobrien      call_ref = gen_rtx_SYMBOL_REF (VOIDmode, IDENTIFIER_POINTER (node));
1514690075Sobrien    }
1514790075Sobrien
1514890075Sobrien  return force_reg (Pmode, call_ref);
1514990075Sobrien}
1515090075Sobrien
15151117395Skan#ifdef USING_ELFOS_H
15152117395Skan
1515390075Sobrien/* A C statement or statements to switch to the appropriate section
1515490075Sobrien   for output of RTX in mode MODE.  You can assume that RTX is some
1515590075Sobrien   kind of constant in RTL.  The argument MODE is redundant except in
1515690075Sobrien   the case of a `const_int' rtx.  Select the section by calling
1515790075Sobrien   `text_section' or one of the alternatives for other sections.
1515890075Sobrien
1515990075Sobrien   Do not define this macro if you put all constants in the read-only
1516090075Sobrien   data section.  */
1516190075Sobrien
15162117395Skanstatic void
15163132718Skanrs6000_elf_select_rtx_section (enum machine_mode mode, rtx x,
15164132718Skan			       unsigned HOST_WIDE_INT align)
1516590075Sobrien{
1516690075Sobrien  if (ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (x, mode))
1516790075Sobrien    toc_section ();
1516890075Sobrien  else
15169117395Skan    default_elf_select_rtx_section (mode, x, align);
1517090075Sobrien}
1517190075Sobrien
1517290075Sobrien/* A C statement or statements to switch to the appropriate
1517390075Sobrien   section for output of DECL.  DECL is either a `VAR_DECL' node
1517490075Sobrien   or a constant of some sort.  RELOC indicates whether forming
1517590075Sobrien   the initial value of DECL requires link-time relocations.  */
1517690075Sobrien
15177117395Skanstatic void
15178132718Skanrs6000_elf_select_section (tree decl, int reloc,
15179132718Skan			   unsigned HOST_WIDE_INT align)
1518090075Sobrien{
15181132718Skan  /* Pretend that we're always building for a shared library when
15182132718Skan     ABI_AIX, because otherwise we end up with dynamic relocations
15183132718Skan     in read-only sections.  This happens for function pointers,
15184132718Skan     references to vtables in typeinfo, and probably other cases.  */
15185117395Skan  default_elf_select_section_1 (decl, reloc, align,
15186117395Skan				flag_pic || DEFAULT_ABI == ABI_AIX);
1518790075Sobrien}
1518890075Sobrien
1518990075Sobrien/* A C statement to build up a unique section name, expressed as a
1519090075Sobrien   STRING_CST node, and assign it to DECL_SECTION_NAME (decl).
1519190075Sobrien   RELOC indicates whether the initial value of EXP requires
1519290075Sobrien   link-time relocations.  If you do not define this macro, GCC will use
1519390075Sobrien   the symbol name prefixed by `.' as the section name.  Note - this
1519490075Sobrien   macro can now be called for uninitialized data items as well as
15195117395Skan   initialized data and functions.  */
1519690075Sobrien
15197117395Skanstatic void
15198132718Skanrs6000_elf_unique_section (tree decl, int reloc)
1519990075Sobrien{
15200132718Skan  /* As above, pretend that we're always building for a shared library
15201132718Skan     when ABI_AIX, to avoid dynamic relocations in read-only sections.  */
15202117395Skan  default_unique_section_1 (decl, reloc,
15203117395Skan			    flag_pic || DEFAULT_ABI == ABI_AIX);
1520490075Sobrien}
15205117395Skan
15206132718Skan/* For a SYMBOL_REF, set generic flags and then perform some
15207132718Skan   target-specific processing.
1520890075Sobrien
15209132718Skan   When the AIX ABI is requested on a non-AIX system, replace the
15210132718Skan   function name with the real name (with a leading .) rather than the
15211132718Skan   function descriptor name.  This saves a lot of overriding code to
15212132718Skan   read the prefixes.  */
15213132718Skan
15214117395Skanstatic void
15215132718Skanrs6000_elf_encode_section_info (tree decl, rtx rtl, int first)
1521690075Sobrien{
15217132718Skan  default_encode_section_info (decl, rtl, first);
15218117395Skan
15219132718Skan  if (first
15220132718Skan      && TREE_CODE (decl) == FUNCTION_DECL
15221132718Skan      && !TARGET_AIX
15222132718Skan      && DEFAULT_ABI == ABI_AIX)
1522390075Sobrien    {
15224132718Skan      rtx sym_ref = XEXP (rtl, 0);
15225132718Skan      size_t len = strlen (XSTR (sym_ref, 0));
15226132718Skan      char *str = alloca (len + 2);
15227132718Skan      str[0] = '.';
15228132718Skan      memcpy (str + 1, XSTR (sym_ref, 0), len + 1);
15229132718Skan      XSTR (sym_ref, 0) = ggc_alloc_string (str, len + 1);
1523090075Sobrien    }
1523190075Sobrien}
1523290075Sobrien
15233117395Skanstatic bool
15234132718Skanrs6000_elf_in_small_data_p (tree decl)
15235117395Skan{
15236117395Skan  if (rs6000_sdata == SDATA_NONE)
15237117395Skan    return false;
15238117395Skan
15239146895Skan  /* We want to merge strings, so we never consider them small data.  */
15240146895Skan  if (TREE_CODE (decl) == STRING_CST)
15241146895Skan    return false;
15242146895Skan
15243146895Skan  /* Functions are never in the small data area.  */
15244146895Skan  if (TREE_CODE (decl) == FUNCTION_DECL)
15245146895Skan    return false;
15246146895Skan
15247146895Skan  /* Thread-local vars can't go in the small data area.  */
15248146895Skan  if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl))
15249146895Skan    return false;
15250146895Skan
15251117395Skan  if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl))
15252117395Skan    {
15253117395Skan      const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
15254117395Skan      if (strcmp (section, ".sdata") == 0
15255117395Skan	  || strcmp (section, ".sdata2") == 0
15256132718Skan	  || strcmp (section, ".sbss") == 0
15257132718Skan	  || strcmp (section, ".sbss2") == 0
15258132718Skan	  || strcmp (section, ".PPC.EMB.sdata0") == 0
15259132718Skan	  || strcmp (section, ".PPC.EMB.sbss0") == 0)
15260117395Skan	return true;
15261117395Skan    }
15262117395Skan  else
15263117395Skan    {
15264117395Skan      HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (decl));
15265117395Skan
15266117395Skan      if (size > 0
15267132718Skan	  && (unsigned HOST_WIDE_INT) size <= g_switch_value
15268132718Skan	  /* If it's not public, and we're not going to reference it there,
15269132718Skan	     there's no need to put it in the small data section.  */
15270117395Skan	  && (rs6000_sdata != SDATA_DATA || TREE_PUBLIC (decl)))
15271117395Skan	return true;
15272117395Skan    }
15273117395Skan
15274117395Skan  return false;
15275117395Skan}
15276117395Skan
1527790075Sobrien#endif /* USING_ELFOS_H */
1527890075Sobrien
1527990075Sobrien
1528090075Sobrien/* Return a REG that occurs in ADDR with coefficient 1.
1528190075Sobrien   ADDR can be effectively incremented by incrementing REG.
1528290075Sobrien
1528390075Sobrien   r0 is special and we must not select it as an address
1528490075Sobrien   register by this routine since our caller will try to
1528590075Sobrien   increment the returned register via an "la" instruction.  */
1528690075Sobrien
1528790075Sobrienstruct rtx_def *
15288132718Skanfind_addr_reg (rtx addr)
1528990075Sobrien{
1529090075Sobrien  while (GET_CODE (addr) == PLUS)
1529190075Sobrien    {
1529290075Sobrien      if (GET_CODE (XEXP (addr, 0)) == REG
1529390075Sobrien	  && REGNO (XEXP (addr, 0)) != 0)
1529490075Sobrien	addr = XEXP (addr, 0);
1529590075Sobrien      else if (GET_CODE (XEXP (addr, 1)) == REG
1529690075Sobrien	       && REGNO (XEXP (addr, 1)) != 0)
1529790075Sobrien	addr = XEXP (addr, 1);
1529890075Sobrien      else if (CONSTANT_P (XEXP (addr, 0)))
1529990075Sobrien	addr = XEXP (addr, 1);
1530090075Sobrien      else if (CONSTANT_P (XEXP (addr, 1)))
1530190075Sobrien	addr = XEXP (addr, 0);
1530290075Sobrien      else
1530390075Sobrien	abort ();
1530490075Sobrien    }
1530590075Sobrien  if (GET_CODE (addr) == REG && REGNO (addr) != 0)
1530690075Sobrien    return addr;
1530790075Sobrien  abort ();
1530890075Sobrien}
1530990075Sobrien
1531090075Sobrienvoid
15311132718Skanrs6000_fatal_bad_address (rtx op)
1531290075Sobrien{
1531390075Sobrien  fatal_insn ("bad address", op);
1531490075Sobrien}
1531590075Sobrien
1531690075Sobrien#if TARGET_MACHO
1531790075Sobrien
1531890075Sobrien#if 0
1531990075Sobrien/* Returns 1 if OP is either a symbol reference or a sum of a symbol
1532090075Sobrien   reference and a constant.  */
1532190075Sobrien
1532290075Sobrienint
15323132718Skansymbolic_operand (rtx op)
1532490075Sobrien{
1532590075Sobrien  switch (GET_CODE (op))
1532690075Sobrien    {
1532790075Sobrien    case SYMBOL_REF:
1532890075Sobrien    case LABEL_REF:
1532990075Sobrien      return 1;
1533090075Sobrien    case CONST:
1533190075Sobrien      op = XEXP (op, 0);
1533290075Sobrien      return (GET_CODE (op) == SYMBOL_REF ||
1533390075Sobrien	      (GET_CODE (XEXP (op, 0)) == SYMBOL_REF
1533490075Sobrien	       || GET_CODE (XEXP (op, 0)) == LABEL_REF)
1533590075Sobrien	      && GET_CODE (XEXP (op, 1)) == CONST_INT);
1533690075Sobrien    default:
1533790075Sobrien      return 0;
1533890075Sobrien    }
1533990075Sobrien}
1534090075Sobrien#endif
1534190075Sobrien
15342132718Skan#if TARGET_MACHO
1534390075Sobrien
15344132718Skanstatic tree branch_island_list = 0;
1534590075Sobrien
15346132718Skan/* Remember to generate a branch island for far calls to the given
15347132718Skan   function.  */
1534890075Sobrien
15349132718Skanstatic void
15350132718Skanadd_compiler_branch_island (tree label_name, tree function_name, int line_number)
1535190075Sobrien{
15352132718Skan  tree branch_island = build_tree_list (function_name, label_name);
15353132718Skan  TREE_TYPE (branch_island) = build_int_2 (line_number, 0);
15354132718Skan  TREE_CHAIN (branch_island) = branch_island_list;
15355132718Skan  branch_island_list = branch_island;
1535690075Sobrien}
1535790075Sobrien
15358132718Skan#define BRANCH_ISLAND_LABEL_NAME(BRANCH_ISLAND)     TREE_VALUE (BRANCH_ISLAND)
15359132718Skan#define BRANCH_ISLAND_FUNCTION_NAME(BRANCH_ISLAND)  TREE_PURPOSE (BRANCH_ISLAND)
15360132718Skan#define BRANCH_ISLAND_LINE_NUMBER(BRANCH_ISLAND)    \
15361132718Skan		TREE_INT_CST_LOW (TREE_TYPE (BRANCH_ISLAND))
1536290075Sobrien
15363132718Skan/* Generate far-jump branch islands for everything on the
15364132718Skan   branch_island_list.  Invoked immediately after the last instruction
15365132718Skan   of the epilogue has been emitted; the branch-islands must be
15366132718Skan   appended to, and contiguous with, the function body.  Mach-O stubs
15367132718Skan   are generated in machopic_output_stub().  */
1536890075Sobrien
15369132718Skanstatic void
15370132718Skanmacho_branch_islands (void)
1537190075Sobrien{
15372132718Skan  char tmp_buf[512];
15373132718Skan  tree branch_island;
1537490075Sobrien
15375132718Skan  for (branch_island = branch_island_list;
15376132718Skan       branch_island;
15377132718Skan       branch_island = TREE_CHAIN (branch_island))
15378132718Skan    {
15379132718Skan      const char *label =
15380132718Skan	IDENTIFIER_POINTER (BRANCH_ISLAND_LABEL_NAME (branch_island));
15381132718Skan      const char *name  =
15382132718Skan	darwin_strip_name_encoding (
15383132718Skan	  IDENTIFIER_POINTER (BRANCH_ISLAND_FUNCTION_NAME (branch_island)));
15384132718Skan      char name_buf[512];
15385132718Skan      /* Cheap copy of the details from the Darwin ASM_OUTPUT_LABELREF().  */
15386132718Skan      if (name[0] == '*' || name[0] == '&')
15387132718Skan	strcpy (name_buf, name+1);
15388132718Skan      else
15389132718Skan	{
15390132718Skan	  name_buf[0] = '_';
15391132718Skan	  strcpy (name_buf+1, name);
15392132718Skan	}
15393132718Skan      strcpy (tmp_buf, "\n");
15394132718Skan      strcat (tmp_buf, label);
1539590075Sobrien#if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO)
15396132718Skan      if (write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG)
15397132718Skan	fprintf (asm_out_file, "\t.stabd 68,0," HOST_WIDE_INT_PRINT_UNSIGNED "\n",
15398132718Skan		 BRANCH_ISLAND_LINE_NUMBER(branch_island));
1539990075Sobrien#endif /* DBX_DEBUGGING_INFO || XCOFF_DEBUGGING_INFO */
15400132718Skan      if (flag_pic)
15401132718Skan	{
15402132718Skan	  strcat (tmp_buf, ":\n\tmflr r0\n\tbcl 20,31,");
15403132718Skan	  strcat (tmp_buf, label);
15404132718Skan	  strcat (tmp_buf, "_pic\n");
15405132718Skan	  strcat (tmp_buf, label);
15406132718Skan	  strcat (tmp_buf, "_pic:\n\tmflr r11\n");
15407132718Skan
15408132718Skan	  strcat (tmp_buf, "\taddis r11,r11,ha16(");
15409132718Skan	  strcat (tmp_buf, name_buf);
15410132718Skan	  strcat (tmp_buf, " - ");
15411132718Skan	  strcat (tmp_buf, label);
15412132718Skan	  strcat (tmp_buf, "_pic)\n");
15413132718Skan
15414132718Skan	  strcat (tmp_buf, "\tmtlr r0\n");
15415132718Skan
15416132718Skan	  strcat (tmp_buf, "\taddi r12,r11,lo16(");
15417132718Skan	  strcat (tmp_buf, name_buf);
15418132718Skan	  strcat (tmp_buf, " - ");
15419132718Skan	  strcat (tmp_buf, label);
15420132718Skan	  strcat (tmp_buf, "_pic)\n");
15421132718Skan
15422132718Skan	  strcat (tmp_buf, "\tmtctr r12\n\tbctr\n");
15423132718Skan	}
15424132718Skan      else
15425132718Skan	{
15426132718Skan	  strcat (tmp_buf, ":\nlis r12,hi16(");
15427132718Skan	  strcat (tmp_buf, name_buf);
15428132718Skan	  strcat (tmp_buf, ")\n\tori r12,r12,lo16(");
15429132718Skan	  strcat (tmp_buf, name_buf);
15430132718Skan	  strcat (tmp_buf, ")\n\tmtctr r12\n\tbctr");
15431132718Skan	}
15432132718Skan      output_asm_insn (tmp_buf, 0);
1543390075Sobrien#if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO)
15434132718Skan      if (write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG)
15435132718Skan	fprintf(asm_out_file, "\t.stabd 68,0," HOST_WIDE_INT_PRINT_UNSIGNED "\n",
15436132718Skan		BRANCH_ISLAND_LINE_NUMBER (branch_island));
1543790075Sobrien#endif /* DBX_DEBUGGING_INFO || XCOFF_DEBUGGING_INFO */
15438132718Skan    }
1543990075Sobrien
15440132718Skan  branch_island_list = 0;
1544190075Sobrien}
1544290075Sobrien
1544390075Sobrien/* NO_PREVIOUS_DEF checks in the link list whether the function name is
1544490075Sobrien   already there or not.  */
1544590075Sobrien
15446132718Skanstatic int
15447132718Skanno_previous_def (tree function_name)
1544890075Sobrien{
15449132718Skan  tree branch_island;
15450132718Skan  for (branch_island = branch_island_list;
15451132718Skan       branch_island;
15452132718Skan       branch_island = TREE_CHAIN (branch_island))
15453132718Skan    if (function_name == BRANCH_ISLAND_FUNCTION_NAME (branch_island))
1545490075Sobrien      return 0;
1545590075Sobrien  return 1;
1545690075Sobrien}
1545790075Sobrien
1545890075Sobrien/* GET_PREV_LABEL gets the label name from the previous definition of
1545990075Sobrien   the function.  */
1546090075Sobrien
15461132718Skanstatic tree
15462132718Skanget_prev_label (tree function_name)
1546390075Sobrien{
15464132718Skan  tree branch_island;
15465132718Skan  for (branch_island = branch_island_list;
15466132718Skan       branch_island;
15467132718Skan       branch_island = TREE_CHAIN (branch_island))
15468132718Skan    if (function_name == BRANCH_ISLAND_FUNCTION_NAME (branch_island))
15469132718Skan      return BRANCH_ISLAND_LABEL_NAME (branch_island);
1547090075Sobrien  return 0;
1547190075Sobrien}
1547290075Sobrien
1547390075Sobrien/* INSN is either a function call or a millicode call.  It may have an
1547490075Sobrien   unconditional jump in its delay slot.
1547590075Sobrien
1547690075Sobrien   CALL_DEST is the routine we are calling.  */
1547790075Sobrien
1547890075Sobrienchar *
15479132718Skanoutput_call (rtx insn, rtx *operands, int dest_operand_number, int cookie_operand_number)
1548090075Sobrien{
1548190075Sobrien  static char buf[256];
15482132718Skan  if (GET_CODE (operands[dest_operand_number]) == SYMBOL_REF
15483132718Skan      && (INTVAL (operands[cookie_operand_number]) & CALL_LONG))
1548490075Sobrien    {
1548590075Sobrien      tree labelname;
15486132718Skan      tree funname = get_identifier (XSTR (operands[dest_operand_number], 0));
1548790075Sobrien
1548890075Sobrien      if (no_previous_def (funname))
1548990075Sobrien	{
15490117395Skan	  int line_number = 0;
1549190075Sobrien	  rtx label_rtx = gen_label_rtx ();
1549290075Sobrien	  char *label_buf, temp_buf[256];
1549390075Sobrien	  ASM_GENERATE_INTERNAL_LABEL (temp_buf, "L",
1549490075Sobrien				       CODE_LABEL_NUMBER (label_rtx));
1549590075Sobrien	  label_buf = temp_buf[0] == '*' ? temp_buf + 1 : temp_buf;
1549690075Sobrien	  labelname = get_identifier (label_buf);
1549790075Sobrien	  for (; insn && GET_CODE (insn) != NOTE; insn = PREV_INSN (insn));
1549890075Sobrien	  if (insn)
1549990075Sobrien	    line_number = NOTE_LINE_NUMBER (insn);
15500132718Skan	  add_compiler_branch_island (labelname, funname, line_number);
1550190075Sobrien	}
1550290075Sobrien      else
1550390075Sobrien	labelname = get_prev_label (funname);
1550490075Sobrien
15505132718Skan      /* "jbsr foo, L42" is Mach-O for "Link as 'bl foo' if a 'bl'
15506132718Skan	 instruction will reach 'foo', otherwise link as 'bl L42'".
15507132718Skan	 "L42" should be a 'branch island', that will do a far jump to
15508132718Skan	 'foo'.  Branch islands are generated in
15509132718Skan	 macho_branch_islands().  */
1551090075Sobrien      sprintf (buf, "jbsr %%z%d,%.246s",
15511132718Skan	       dest_operand_number, IDENTIFIER_POINTER (labelname));
1551290075Sobrien    }
1551390075Sobrien  else
15514132718Skan    sprintf (buf, "bl %%z%d", dest_operand_number);
15515132718Skan  return buf;
1551690075Sobrien}
1551790075Sobrien
15518132718Skan#endif /* TARGET_MACHO */
1551990075Sobrien
1552090075Sobrien/* Generate PIC and indirect symbol stubs.  */
1552190075Sobrien
1552290075Sobrienvoid
15523132718Skanmachopic_output_stub (FILE *file, const char *symb, const char *stub)
1552490075Sobrien{
1552590075Sobrien  unsigned int length;
1552690075Sobrien  char *symbol_name, *lazy_ptr_name;
1552790075Sobrien  char *local_label_0;
1552890075Sobrien  static int label = 0;
1552990075Sobrien
1553090075Sobrien  /* Lose our funky encoding stuff so it doesn't contaminate the stub.  */
15531117395Skan  symb = (*targetm.strip_name_encoding) (symb);
1553290075Sobrien
1553390075Sobrien
1553490075Sobrien  length = strlen (symb);
1553590075Sobrien  symbol_name = alloca (length + 32);
1553690075Sobrien  GEN_SYMBOL_NAME_FOR_SYMBOL (symbol_name, symb, length);
1553790075Sobrien
1553890075Sobrien  lazy_ptr_name = alloca (length + 32);
1553990075Sobrien  GEN_LAZY_PTR_NAME_FOR_SYMBOL (lazy_ptr_name, symb, length);
1554090075Sobrien
1554190075Sobrien  if (flag_pic == 2)
15542132718Skan    machopic_picsymbol_stub1_section ();
1554390075Sobrien  else
15544132718Skan    machopic_symbol_stub1_section ();
15545132718Skan  fprintf (file, "\t.align 2\n");
1554690075Sobrien
1554790075Sobrien  fprintf (file, "%s:\n", stub);
1554890075Sobrien  fprintf (file, "\t.indirect_symbol %s\n", symbol_name);
1554990075Sobrien
1555090075Sobrien  if (flag_pic == 2)
1555190075Sobrien    {
15552132718Skan      label++;
15553132718Skan      local_label_0 = alloca (sizeof("\"L0000000000$spb\""));
15554132718Skan      sprintf (local_label_0, "\"L%011d$spb\"", label);
15555132718Skan
1555690075Sobrien      fprintf (file, "\tmflr r0\n");
1555790075Sobrien      fprintf (file, "\tbcl 20,31,%s\n", local_label_0);
1555890075Sobrien      fprintf (file, "%s:\n\tmflr r11\n", local_label_0);
1555990075Sobrien      fprintf (file, "\taddis r11,r11,ha16(%s-%s)\n",
1556090075Sobrien	       lazy_ptr_name, local_label_0);
1556190075Sobrien      fprintf (file, "\tmtlr r0\n");
15562132718Skan      fprintf (file, "\tlwzu r12,lo16(%s-%s)(r11)\n",
1556390075Sobrien	       lazy_ptr_name, local_label_0);
1556490075Sobrien      fprintf (file, "\tmtctr r12\n");
1556590075Sobrien      fprintf (file, "\tbctr\n");
1556690075Sobrien    }
1556790075Sobrien  else
15568132718Skan   {
15569132718Skan     fprintf (file, "\tlis r11,ha16(%s)\n", lazy_ptr_name);
15570132718Skan     fprintf (file, "\tlwzu r12,lo16(%s)(r11)\n", lazy_ptr_name);
15571132718Skan     fprintf (file, "\tmtctr r12\n");
15572132718Skan     fprintf (file, "\tbctr\n");
15573132718Skan   }
1557490075Sobrien
1557590075Sobrien  machopic_lazy_symbol_ptr_section ();
1557690075Sobrien  fprintf (file, "%s:\n", lazy_ptr_name);
1557790075Sobrien  fprintf (file, "\t.indirect_symbol %s\n", symbol_name);
1557890075Sobrien  fprintf (file, "\t.long dyld_stub_binding_helper\n");
1557990075Sobrien}
1558090075Sobrien
1558190075Sobrien/* Legitimize PIC addresses.  If the address is already
1558290075Sobrien   position-independent, we return ORIG.  Newly generated
1558390075Sobrien   position-independent addresses go into a reg.  This is REG if non
1558490075Sobrien   zero, otherwise we allocate register(s) as necessary.  */
1558590075Sobrien
1558690075Sobrien#define SMALL_INT(X) ((unsigned) (INTVAL(X) + 0x8000) < 0x10000)
1558790075Sobrien
1558890075Sobrienrtx
15589132718Skanrs6000_machopic_legitimize_pic_address (rtx orig, enum machine_mode mode,
15590132718Skan					rtx reg)
1559190075Sobrien{
1559290075Sobrien  rtx base, offset;
1559390075Sobrien
1559490075Sobrien  if (reg == NULL && ! reload_in_progress && ! reload_completed)
1559590075Sobrien    reg = gen_reg_rtx (Pmode);
1559690075Sobrien
1559790075Sobrien  if (GET_CODE (orig) == CONST)
1559890075Sobrien    {
1559990075Sobrien      if (GET_CODE (XEXP (orig, 0)) == PLUS
1560090075Sobrien	  && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx)
1560190075Sobrien	return orig;
1560290075Sobrien
1560390075Sobrien      if (GET_CODE (XEXP (orig, 0)) == PLUS)
1560490075Sobrien	{
15605132718Skan	  /* Use a different reg for the intermediate value, as
15606132718Skan	     it will be marked UNCHANGING.  */
15607132718Skan	  rtx reg_temp = no_new_pseudos ? reg : gen_reg_rtx (Pmode);
15608132718Skan
1560990075Sobrien	  base =
1561090075Sobrien	    rs6000_machopic_legitimize_pic_address (XEXP (XEXP (orig, 0), 0),
15611132718Skan						    Pmode, reg_temp);
1561290075Sobrien	  offset =
1561390075Sobrien	    rs6000_machopic_legitimize_pic_address (XEXP (XEXP (orig, 0), 1),
1561490075Sobrien						    Pmode, reg);
1561590075Sobrien	}
1561690075Sobrien      else
1561790075Sobrien	abort ();
1561890075Sobrien
1561990075Sobrien      if (GET_CODE (offset) == CONST_INT)
1562090075Sobrien	{
1562190075Sobrien	  if (SMALL_INT (offset))
1562290075Sobrien	    return plus_constant (base, INTVAL (offset));
1562390075Sobrien	  else if (! reload_in_progress && ! reload_completed)
1562490075Sobrien	    offset = force_reg (Pmode, offset);
1562590075Sobrien	  else
1562690075Sobrien	    {
1562790075Sobrien 	      rtx mem = force_const_mem (Pmode, orig);
1562890075Sobrien	      return machopic_legitimize_pic_address (mem, Pmode, reg);
1562990075Sobrien	    }
1563090075Sobrien	}
1563190075Sobrien      return gen_rtx (PLUS, Pmode, base, offset);
1563290075Sobrien    }
1563390075Sobrien
1563490075Sobrien  /* Fall back on generic machopic code.  */
1563590075Sobrien  return machopic_legitimize_pic_address (orig, mode, reg);
1563690075Sobrien}
1563790075Sobrien
1563890075Sobrien/* This is just a placeholder to make linking work without having to
1563990075Sobrien   add this to the generic Darwin EXTRA_SECTIONS.  If -mcall-aix is
1564090075Sobrien   ever needed for Darwin (not too likely!) this would have to get a
1564190075Sobrien   real definition.  */
1564290075Sobrien
1564390075Sobrienvoid
15644132718Skantoc_section (void)
1564590075Sobrien{
1564690075Sobrien}
1564790075Sobrien
1564890075Sobrien#endif /* TARGET_MACHO */
1564990075Sobrien
1565090075Sobrien#if TARGET_ELF
1565190075Sobrienstatic unsigned int
15652132718Skanrs6000_elf_section_type_flags (tree decl, const char *name, int reloc)
1565390075Sobrien{
15654132718Skan  return default_section_type_flags_1 (decl, name, reloc,
15655132718Skan				       flag_pic || DEFAULT_ABI == ABI_AIX);
1565690075Sobrien}
1565790075Sobrien
1565890075Sobrien/* Record an element in the table of global constructors.  SYMBOL is
1565990075Sobrien   a SYMBOL_REF of the function to be called; PRIORITY is a number
1566090075Sobrien   between 0 and MAX_INIT_PRIORITY.
1566190075Sobrien
1566290075Sobrien   This differs from default_named_section_asm_out_constructor in
1566390075Sobrien   that we have special handling for -mrelocatable.  */
1566490075Sobrien
1566590075Sobrienstatic void
15666132718Skanrs6000_elf_asm_out_constructor (rtx symbol, int priority)
1566790075Sobrien{
1566890075Sobrien  const char *section = ".ctors";
1566990075Sobrien  char buf[16];
1567090075Sobrien
1567190075Sobrien  if (priority != DEFAULT_INIT_PRIORITY)
1567290075Sobrien    {
1567390075Sobrien      sprintf (buf, ".ctors.%.5u",
1567490075Sobrien               /* Invert the numbering so the linker puts us in the proper
1567590075Sobrien                  order; constructors are run from right to left, and the
1567690075Sobrien                  linker sorts in increasing order.  */
1567790075Sobrien               MAX_INIT_PRIORITY - priority);
1567890075Sobrien      section = buf;
1567990075Sobrien    }
1568090075Sobrien
1568190075Sobrien  named_section_flags (section, SECTION_WRITE);
1568290075Sobrien  assemble_align (POINTER_SIZE);
1568390075Sobrien
1568490075Sobrien  if (TARGET_RELOCATABLE)
1568590075Sobrien    {
1568690075Sobrien      fputs ("\t.long (", asm_out_file);
1568790075Sobrien      output_addr_const (asm_out_file, symbol);
1568890075Sobrien      fputs (")@fixup\n", asm_out_file);
1568990075Sobrien    }
1569090075Sobrien  else
1569190075Sobrien    assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
1569290075Sobrien}
1569390075Sobrien
1569490075Sobrienstatic void
15695132718Skanrs6000_elf_asm_out_destructor (rtx symbol, int priority)
1569690075Sobrien{
1569790075Sobrien  const char *section = ".dtors";
1569890075Sobrien  char buf[16];
1569990075Sobrien
1570090075Sobrien  if (priority != DEFAULT_INIT_PRIORITY)
1570190075Sobrien    {
1570290075Sobrien      sprintf (buf, ".dtors.%.5u",
1570390075Sobrien               /* Invert the numbering so the linker puts us in the proper
1570490075Sobrien                  order; constructors are run from right to left, and the
1570590075Sobrien                  linker sorts in increasing order.  */
1570690075Sobrien               MAX_INIT_PRIORITY - priority);
1570790075Sobrien      section = buf;
1570890075Sobrien    }
1570990075Sobrien
1571090075Sobrien  named_section_flags (section, SECTION_WRITE);
1571190075Sobrien  assemble_align (POINTER_SIZE);
1571290075Sobrien
1571390075Sobrien  if (TARGET_RELOCATABLE)
1571490075Sobrien    {
1571590075Sobrien      fputs ("\t.long (", asm_out_file);
1571690075Sobrien      output_addr_const (asm_out_file, symbol);
1571790075Sobrien      fputs (")@fixup\n", asm_out_file);
1571890075Sobrien    }
1571990075Sobrien  else
1572090075Sobrien    assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
1572190075Sobrien}
15722132718Skan
15723132718Skanvoid
15724132718Skanrs6000_elf_declare_function_name (FILE *file, const char *name, tree decl)
15725132718Skan{
15726132718Skan  if (TARGET_64BIT)
15727132718Skan    {
15728132718Skan      fputs ("\t.section\t\".opd\",\"aw\"\n\t.align 3\n", file);
15729132718Skan      ASM_OUTPUT_LABEL (file, name);
15730132718Skan      fputs (DOUBLE_INT_ASM_OP, file);
15731132718Skan      putc ('.', file);
15732132718Skan      assemble_name (file, name);
15733132718Skan      fputs (",.TOC.@tocbase,0\n\t.previous\n\t.size\t", file);
15734132718Skan      assemble_name (file, name);
15735132718Skan      fputs (",24\n\t.type\t.", file);
15736132718Skan      assemble_name (file, name);
15737132718Skan      fputs (",@function\n", file);
15738132718Skan      if (TREE_PUBLIC (decl) && ! DECL_WEAK (decl))
15739132718Skan	{
15740132718Skan	  fputs ("\t.globl\t.", file);
15741132718Skan	  assemble_name (file, name);
15742132718Skan	  putc ('\n', file);
15743132718Skan	}
15744132718Skan      ASM_DECLARE_RESULT (file, DECL_RESULT (decl));
15745132718Skan      putc ('.', file);
15746132718Skan      ASM_OUTPUT_LABEL (file, name);
15747132718Skan      return;
15748132718Skan    }
15749132718Skan
15750132718Skan  if (TARGET_RELOCATABLE
15751132718Skan      && (get_pool_size () != 0 || current_function_profile)
15752132718Skan      && uses_TOC ())
15753132718Skan    {
15754132718Skan      char buf[256];
15755132718Skan
15756132718Skan      (*targetm.asm_out.internal_label) (file, "LCL", rs6000_pic_labelno);
15757132718Skan
15758132718Skan      ASM_GENERATE_INTERNAL_LABEL (buf, "LCTOC", 1);
15759132718Skan      fprintf (file, "\t.long ");
15760132718Skan      assemble_name (file, buf);
15761132718Skan      putc ('-', file);
15762132718Skan      ASM_GENERATE_INTERNAL_LABEL (buf, "LCF", rs6000_pic_labelno);
15763132718Skan      assemble_name (file, buf);
15764132718Skan      putc ('\n', file);
15765132718Skan    }
15766132718Skan
15767132718Skan  ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function");
15768132718Skan  ASM_DECLARE_RESULT (file, DECL_RESULT (decl));
15769132718Skan
15770132718Skan  if (DEFAULT_ABI == ABI_AIX)
15771132718Skan    {
15772132718Skan      const char *desc_name, *orig_name;
15773132718Skan
15774132718Skan      orig_name = (*targetm.strip_name_encoding) (name);
15775132718Skan      desc_name = orig_name;
15776132718Skan      while (*desc_name == '.')
15777132718Skan	desc_name++;
15778132718Skan
15779132718Skan      if (TREE_PUBLIC (decl))
15780132718Skan	fprintf (file, "\t.globl %s\n", desc_name);
15781132718Skan
15782132718Skan      fprintf (file, "%s\n", MINIMAL_TOC_SECTION_ASM_OP);
15783132718Skan      fprintf (file, "%s:\n", desc_name);
15784132718Skan      fprintf (file, "\t.long %s\n", orig_name);
15785132718Skan      fputs ("\t.long _GLOBAL_OFFSET_TABLE_\n", file);
15786132718Skan      if (DEFAULT_ABI == ABI_AIX)
15787132718Skan	fputs ("\t.long 0\n", file);
15788132718Skan      fprintf (file, "\t.previous\n");
15789132718Skan    }
15790132718Skan  ASM_OUTPUT_LABEL (file, name);
15791132718Skan}
15792146895Skan
15793146895Skanstatic void
15794146895Skanrs6000_elf_end_indicate_exec_stack (void)
15795146895Skan{
15796146895Skan  if (TARGET_32BIT)
15797146895Skan    file_end_indicate_exec_stack ();
15798146895Skan}
1579990075Sobrien#endif
1580090075Sobrien
15801117395Skan#if TARGET_XCOFF
1580290075Sobrienstatic void
15803132718Skanrs6000_xcoff_asm_globalize_label (FILE *stream, const char *name)
1580490075Sobrien{
15805117395Skan  fputs (GLOBAL_ASM_OP, stream);
15806117395Skan  RS6000_OUTPUT_BASENAME (stream, name);
15807117395Skan  putc ('\n', stream);
1580890075Sobrien}
15809117395Skan
15810117395Skanstatic void
15811132718Skanrs6000_xcoff_asm_named_section (const char *name, unsigned int flags)
15812117395Skan{
15813117395Skan  int smclass;
15814117395Skan  static const char * const suffix[3] = { "PR", "RO", "RW" };
15815117395Skan
15816117395Skan  if (flags & SECTION_CODE)
15817117395Skan    smclass = 0;
15818117395Skan  else if (flags & SECTION_WRITE)
15819117395Skan    smclass = 2;
15820117395Skan  else
15821117395Skan    smclass = 1;
15822117395Skan
15823117395Skan  fprintf (asm_out_file, "\t.csect %s%s[%s],%u\n",
15824117395Skan	   (flags & SECTION_CODE) ? "." : "",
15825117395Skan	   name, suffix[smclass], flags & SECTION_ENTSIZE);
15826117395Skan}
15827117395Skan
15828117395Skanstatic void
15829132718Skanrs6000_xcoff_select_section (tree decl, int reloc,
15830132718Skan			    unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
15831117395Skan{
15832117395Skan  if (decl_readonly_section_1 (decl, reloc, 1))
15833117395Skan    {
15834117395Skan      if (TREE_PUBLIC (decl))
15835117395Skan        read_only_data_section ();
15836117395Skan      else
15837117395Skan        read_only_private_data_section ();
15838117395Skan    }
15839117395Skan  else
15840117395Skan    {
15841117395Skan      if (TREE_PUBLIC (decl))
15842117395Skan        data_section ();
15843117395Skan      else
15844117395Skan        private_data_section ();
15845117395Skan    }
15846117395Skan}
15847117395Skan
15848117395Skanstatic void
15849132718Skanrs6000_xcoff_unique_section (tree decl, int reloc ATTRIBUTE_UNUSED)
15850117395Skan{
15851117395Skan  const char *name;
15852117395Skan
15853117395Skan  /* Use select_section for private and uninitialized data.  */
15854117395Skan  if (!TREE_PUBLIC (decl)
15855117395Skan      || DECL_COMMON (decl)
15856117395Skan      || DECL_INITIAL (decl) == NULL_TREE
15857117395Skan      || DECL_INITIAL (decl) == error_mark_node
15858117395Skan      || (flag_zero_initialized_in_bss
15859117395Skan	  && initializer_zerop (DECL_INITIAL (decl))))
15860117395Skan    return;
15861117395Skan
15862117395Skan  name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
15863117395Skan  name = (*targetm.strip_name_encoding) (name);
15864117395Skan  DECL_SECTION_NAME (decl) = build_string (strlen (name), name);
15865117395Skan}
15866117395Skan
15867117395Skan/* Select section for constant in constant pool.
15868117395Skan
15869117395Skan   On RS/6000, all constants are in the private read-only data area.
15870117395Skan   However, if this is being placed in the TOC it must be output as a
15871117395Skan   toc entry.  */
15872117395Skan
15873117395Skanstatic void
15874132718Skanrs6000_xcoff_select_rtx_section (enum machine_mode mode, rtx x,
15875132718Skan				unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
15876117395Skan{
15877117395Skan  if (ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (x, mode))
15878117395Skan    toc_section ();
15879117395Skan  else
15880117395Skan    read_only_private_data_section ();
15881117395Skan}
15882117395Skan
15883117395Skan/* Remove any trailing [DS] or the like from the symbol name.  */
15884117395Skan
15885117395Skanstatic const char *
15886132718Skanrs6000_xcoff_strip_name_encoding (const char *name)
15887117395Skan{
15888117395Skan  size_t len;
15889117395Skan  if (*name == '*')
15890117395Skan    name++;
15891117395Skan  len = strlen (name);
15892117395Skan  if (name[len - 1] == ']')
15893117395Skan    return ggc_alloc_string (name, len - 4);
15894117395Skan  else
15895117395Skan    return name;
15896117395Skan}
15897117395Skan
15898117395Skan/* Section attributes.  AIX is always PIC.  */
15899117395Skan
15900117395Skanstatic unsigned int
15901132718Skanrs6000_xcoff_section_type_flags (tree decl, const char *name, int reloc)
15902117395Skan{
15903117395Skan  unsigned int align;
15904117395Skan  unsigned int flags = default_section_type_flags_1 (decl, name, reloc, 1);
15905117395Skan
15906117395Skan  /* Align to at least UNIT size.  */
15907117395Skan  if (flags & SECTION_CODE)
15908117395Skan    align = MIN_UNITS_PER_WORD;
15909117395Skan  else
15910117395Skan    /* Increase alignment of large objects if not already stricter.  */
15911117395Skan    align = MAX ((DECL_ALIGN (decl) / BITS_PER_UNIT),
15912117395Skan		 int_size_in_bytes (TREE_TYPE (decl)) > MIN_UNITS_PER_WORD
15913117395Skan		 ? UNITS_PER_FP_WORD : MIN_UNITS_PER_WORD);
15914117395Skan
15915117395Skan  return flags | (exact_log2 (align) & SECTION_ENTSIZE);
15916117395Skan}
15917117395Skan
15918132718Skan/* Output at beginning of assembler file.
15919117395Skan
15920132718Skan   Initialize the section names for the RS/6000 at this point.
15921117395Skan
15922132718Skan   Specify filename, including full path, to assembler.
15923132718Skan
15924132718Skan   We want to go into the TOC section so at least one .toc will be emitted.
15925132718Skan   Also, in order to output proper .bs/.es pairs, we need at least one static
15926132718Skan   [RW] section emitted.
15927132718Skan
15928132718Skan   Finally, declare mcount when profiling to make the assembler happy.  */
15929132718Skan
15930117395Skanstatic void
15931132718Skanrs6000_xcoff_file_start (void)
15932117395Skan{
15933132718Skan  rs6000_gen_section_name (&xcoff_bss_section_name,
15934132718Skan			   main_input_filename, ".bss_");
15935132718Skan  rs6000_gen_section_name (&xcoff_private_data_section_name,
15936132718Skan			   main_input_filename, ".rw_");
15937132718Skan  rs6000_gen_section_name (&xcoff_read_only_section_name,
15938132718Skan			   main_input_filename, ".ro_");
15939132718Skan
15940132718Skan  fputs ("\t.file\t", asm_out_file);
15941132718Skan  output_quoted_string (asm_out_file, main_input_filename);
15942132718Skan  fputc ('\n', asm_out_file);
15943132718Skan  toc_section ();
15944132718Skan  if (write_symbols != NO_DEBUG)
15945132718Skan    private_data_section ();
15946132718Skan  text_section ();
15947132718Skan  if (profile_flag)
15948132718Skan    fprintf (asm_out_file, "\t.extern %s\n", RS6000_MCOUNT);
15949132718Skan  rs6000_file_start ();
15950117395Skan}
15951117395Skan
15952132718Skan/* Output at end of assembler file.
15953132718Skan   On the RS/6000, referencing data should automatically pull in text.  */
15954117395Skan
15955132718Skanstatic void
15956132718Skanrs6000_xcoff_file_end (void)
15957132718Skan{
15958132718Skan  text_section ();
15959132718Skan  fputs ("_section_.text:\n", asm_out_file);
15960132718Skan  data_section ();
15961132718Skan  fputs (TARGET_32BIT
15962132718Skan	 ? "\t.long _section_.text\n" : "\t.llong _section_.text\n",
15963132718Skan	 asm_out_file);
15964132718Skan}
15965132718Skan#endif /* TARGET_XCOFF */
15966132718Skan
15967132718Skan#if TARGET_MACHO
15968132718Skan/* Cross-module name binding.  Darwin does not support overriding
15969132718Skan   functions at dynamic-link time.  */
15970132718Skan
15971117395Skanstatic bool
15972132718Skanrs6000_binds_local_p (tree decl)
15973117395Skan{
15974132718Skan  return default_binds_local_p_1 (decl, 0);
15975117395Skan}
15976132718Skan#endif
15977117395Skan
15978132718Skan/* Compute a (partial) cost for rtx X.  Return true if the complete
15979132718Skan   cost has been computed, and false if subexpressions should be
15980132718Skan   scanned.  In either case, *TOTAL contains the cost result.  */
15981132718Skan
15982132718Skanstatic bool
15983132718Skanrs6000_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED,
15984132718Skan		  int *total)
15985132718Skan{
15986132718Skan  switch (code)
15987132718Skan    {
15988132718Skan      /* On the RS/6000, if it is valid in the insn, it is free.
15989132718Skan	 So this always returns 0.  */
15990132718Skan    case CONST_INT:
15991132718Skan    case CONST:
15992132718Skan    case LABEL_REF:
15993132718Skan    case SYMBOL_REF:
15994132718Skan    case CONST_DOUBLE:
15995132718Skan    case HIGH:
15996132718Skan      *total = 0;
15997132718Skan      return true;
15998132718Skan
15999132718Skan    case PLUS:
16000132718Skan      *total = ((GET_CODE (XEXP (x, 1)) == CONST_INT
16001132718Skan		 && ((unsigned HOST_WIDE_INT) (INTVAL (XEXP (x, 1))
16002132718Skan					       + 0x8000) >= 0x10000)
16003132718Skan		 && ((INTVAL (XEXP (x, 1)) & 0xffff) != 0))
16004132718Skan		? COSTS_N_INSNS (2)
16005132718Skan		: COSTS_N_INSNS (1));
16006132718Skan      return true;
16007132718Skan
16008132718Skan    case AND:
16009132718Skan    case IOR:
16010132718Skan    case XOR:
16011132718Skan      *total = ((GET_CODE (XEXP (x, 1)) == CONST_INT
16012132718Skan		 && (INTVAL (XEXP (x, 1)) & (~ (HOST_WIDE_INT) 0xffff)) != 0
16013132718Skan		 && ((INTVAL (XEXP (x, 1)) & 0xffff) != 0))
16014132718Skan		? COSTS_N_INSNS (2)
16015132718Skan		: COSTS_N_INSNS (1));
16016132718Skan      return true;
16017132718Skan
16018132718Skan    case MULT:
16019132718Skan      if (optimize_size)
16020132718Skan	{
16021132718Skan	  *total = COSTS_N_INSNS (2);
16022132718Skan	  return true;
16023132718Skan	}
16024132718Skan      switch (rs6000_cpu)
16025132718Skan	{
16026132718Skan	case PROCESSOR_RIOS1:
16027132718Skan	case PROCESSOR_PPC405:
16028132718Skan	  *total = (GET_CODE (XEXP (x, 1)) != CONST_INT
16029132718Skan		    ? COSTS_N_INSNS (5)
16030132718Skan		    : (INTVAL (XEXP (x, 1)) >= -256
16031132718Skan		       && INTVAL (XEXP (x, 1)) <= 255)
16032132718Skan		    ? COSTS_N_INSNS (3) : COSTS_N_INSNS (4));
16033132718Skan	  return true;
16034132718Skan
16035132718Skan	case PROCESSOR_PPC440:
16036132718Skan	  *total = (GET_CODE (XEXP (x, 1)) != CONST_INT
16037132718Skan		    ? COSTS_N_INSNS (3)
16038132718Skan		    : COSTS_N_INSNS (2));
16039132718Skan	  return true;
16040132718Skan
16041132718Skan	case PROCESSOR_RS64A:
16042132718Skan	  *total = (GET_CODE (XEXP (x, 1)) != CONST_INT
16043132718Skan		    ? GET_MODE (XEXP (x, 1)) != DImode
16044132718Skan		    ? COSTS_N_INSNS (20) : COSTS_N_INSNS (34)
16045132718Skan		    : (INTVAL (XEXP (x, 1)) >= -256
16046132718Skan		       && INTVAL (XEXP (x, 1)) <= 255)
16047132718Skan		    ? COSTS_N_INSNS (8) : COSTS_N_INSNS (12));
16048132718Skan	  return true;
16049132718Skan
16050132718Skan	case PROCESSOR_RIOS2:
16051132718Skan	case PROCESSOR_MPCCORE:
16052132718Skan	case PROCESSOR_PPC604e:
16053132718Skan	  *total = COSTS_N_INSNS (2);
16054132718Skan	  return true;
16055132718Skan
16056132718Skan	case PROCESSOR_PPC601:
16057132718Skan	  *total = COSTS_N_INSNS (5);
16058132718Skan	  return true;
16059132718Skan
16060132718Skan	case PROCESSOR_PPC603:
16061132718Skan	case PROCESSOR_PPC7400:
16062132718Skan	case PROCESSOR_PPC750:
16063132718Skan	  *total = (GET_CODE (XEXP (x, 1)) != CONST_INT
16064132718Skan		    ? COSTS_N_INSNS (5)
16065132718Skan		    : (INTVAL (XEXP (x, 1)) >= -256
16066132718Skan		       && INTVAL (XEXP (x, 1)) <= 255)
16067132718Skan		    ? COSTS_N_INSNS (2) : COSTS_N_INSNS (3));
16068132718Skan	  return true;
16069132718Skan
16070132718Skan	case PROCESSOR_PPC7450:
16071132718Skan	  *total = (GET_CODE (XEXP (x, 1)) != CONST_INT
16072132718Skan		    ? COSTS_N_INSNS (4)
16073132718Skan		    : COSTS_N_INSNS (3));
16074132718Skan	  return true;
16075132718Skan
16076132718Skan	case PROCESSOR_PPC403:
16077132718Skan	case PROCESSOR_PPC604:
16078132718Skan	case PROCESSOR_PPC8540:
16079132718Skan	  *total = COSTS_N_INSNS (4);
16080132718Skan	  return true;
16081132718Skan
16082132718Skan	case PROCESSOR_PPC620:
16083132718Skan	case PROCESSOR_PPC630:
16084132718Skan	  *total = (GET_CODE (XEXP (x, 1)) != CONST_INT
16085132718Skan		    ? GET_MODE (XEXP (x, 1)) != DImode
16086132718Skan		    ? COSTS_N_INSNS (5) : COSTS_N_INSNS (7)
16087132718Skan		    : (INTVAL (XEXP (x, 1)) >= -256
16088132718Skan		       && INTVAL (XEXP (x, 1)) <= 255)
16089132718Skan		    ? COSTS_N_INSNS (3) : COSTS_N_INSNS (4));
16090132718Skan	  return true;
16091132718Skan
16092132718Skan	case PROCESSOR_POWER4:
16093132718Skan	case PROCESSOR_POWER5:
16094132718Skan	  *total = (GET_CODE (XEXP (x, 1)) != CONST_INT
16095132718Skan		    ? GET_MODE (XEXP (x, 1)) != DImode
16096132718Skan		    ? COSTS_N_INSNS (3) : COSTS_N_INSNS (4)
16097132718Skan		    : COSTS_N_INSNS (2));
16098132718Skan	  return true;
16099132718Skan
16100132718Skan	default:
16101132718Skan	  abort ();
16102132718Skan	}
16103132718Skan
16104132718Skan    case DIV:
16105132718Skan    case MOD:
16106132718Skan      if (GET_CODE (XEXP (x, 1)) == CONST_INT
16107132718Skan	  && exact_log2 (INTVAL (XEXP (x, 1))) >= 0)
16108132718Skan	{
16109132718Skan	  *total = COSTS_N_INSNS (2);
16110132718Skan	  return true;
16111132718Skan	}
16112132718Skan      /* FALLTHRU */
16113132718Skan
16114132718Skan    case UDIV:
16115132718Skan    case UMOD:
16116132718Skan      switch (rs6000_cpu)
16117132718Skan	{
16118132718Skan	case PROCESSOR_RIOS1:
16119132718Skan	  *total = COSTS_N_INSNS (19);
16120132718Skan	  return true;
16121132718Skan
16122132718Skan	case PROCESSOR_RIOS2:
16123132718Skan	  *total = COSTS_N_INSNS (13);
16124132718Skan	  return true;
16125132718Skan
16126132718Skan	case PROCESSOR_RS64A:
16127132718Skan	  *total = (GET_MODE (XEXP (x, 1)) != DImode
16128132718Skan		    ? COSTS_N_INSNS (65)
16129132718Skan		    : COSTS_N_INSNS (67));
16130132718Skan	  return true;
16131132718Skan
16132132718Skan	case PROCESSOR_MPCCORE:
16133132718Skan	  *total = COSTS_N_INSNS (6);
16134132718Skan	  return true;
16135132718Skan
16136132718Skan	case PROCESSOR_PPC403:
16137132718Skan	  *total = COSTS_N_INSNS (33);
16138132718Skan	  return true;
16139132718Skan
16140132718Skan	case PROCESSOR_PPC405:
16141132718Skan	  *total = COSTS_N_INSNS (35);
16142132718Skan	  return true;
16143132718Skan
16144132718Skan	case PROCESSOR_PPC440:
16145132718Skan	  *total = COSTS_N_INSNS (34);
16146132718Skan	  return true;
16147132718Skan
16148132718Skan	case PROCESSOR_PPC601:
16149132718Skan	  *total = COSTS_N_INSNS (36);
16150132718Skan	  return true;
16151132718Skan
16152132718Skan	case PROCESSOR_PPC603:
16153132718Skan	  *total = COSTS_N_INSNS (37);
16154132718Skan	  return true;
16155132718Skan
16156132718Skan	case PROCESSOR_PPC604:
16157132718Skan	case PROCESSOR_PPC604e:
16158132718Skan	  *total = COSTS_N_INSNS (20);
16159132718Skan	  return true;
16160132718Skan
16161132718Skan	case PROCESSOR_PPC620:
16162132718Skan	case PROCESSOR_PPC630:
16163132718Skan	  *total = (GET_MODE (XEXP (x, 1)) != DImode
16164132718Skan		    ? COSTS_N_INSNS (21)
16165132718Skan		    : COSTS_N_INSNS (37));
16166132718Skan	  return true;
16167132718Skan
16168132718Skan	case PROCESSOR_PPC750:
16169132718Skan	case PROCESSOR_PPC8540:
16170132718Skan	case PROCESSOR_PPC7400:
16171132718Skan	  *total = COSTS_N_INSNS (19);
16172132718Skan	  return true;
16173132718Skan
16174132718Skan	case PROCESSOR_PPC7450:
16175132718Skan	  *total = COSTS_N_INSNS (23);
16176132718Skan	  return true;
16177132718Skan
16178132718Skan	case PROCESSOR_POWER4:
16179132718Skan	case PROCESSOR_POWER5:
16180132718Skan	  *total = (GET_MODE (XEXP (x, 1)) != DImode
16181132718Skan		    ? COSTS_N_INSNS (18)
16182132718Skan		    : COSTS_N_INSNS (34));
16183132718Skan	  return true;
16184132718Skan
16185132718Skan	default:
16186132718Skan	  abort ();
16187132718Skan	}
16188132718Skan
16189132718Skan    case FFS:
16190132718Skan      *total = COSTS_N_INSNS (4);
16191132718Skan      return true;
16192132718Skan
16193132718Skan    case MEM:
16194132718Skan      /* MEM should be slightly more expensive than (plus (reg) (const)).  */
16195132718Skan      *total = 5;
16196132718Skan      return true;
16197132718Skan
16198132718Skan    default:
16199132718Skan      return false;
16200132718Skan    }
16201132718Skan}
16202132718Skan
16203117395Skan/* A C expression returning the cost of moving data from a register of class
16204117395Skan   CLASS1 to one of CLASS2.  */
16205117395Skan
16206117395Skanint
16207132718Skanrs6000_register_move_cost (enum machine_mode mode,
16208132718Skan			   enum reg_class from, enum reg_class to)
16209117395Skan{
16210117395Skan  /*  Moves from/to GENERAL_REGS.  */
16211117395Skan  if (reg_classes_intersect_p (to, GENERAL_REGS)
16212117395Skan      || reg_classes_intersect_p (from, GENERAL_REGS))
16213117395Skan    {
16214117395Skan      if (! reg_classes_intersect_p (to, GENERAL_REGS))
16215117395Skan	from = to;
16216117395Skan
16217117395Skan      if (from == FLOAT_REGS || from == ALTIVEC_REGS)
16218117395Skan	return (rs6000_memory_move_cost (mode, from, 0)
16219117395Skan		+ rs6000_memory_move_cost (mode, GENERAL_REGS, 0));
16220117395Skan
16221132718Skan/* It's more expensive to move CR_REGS than CR0_REGS because of the shift....  */
16222117395Skan      else if (from == CR_REGS)
16223117395Skan	return 4;
16224117395Skan
16225117395Skan      else
16226117395Skan/* A move will cost one instruction per GPR moved.  */
16227117395Skan	return 2 * HARD_REGNO_NREGS (0, mode);
16228117395Skan    }
16229117395Skan
16230117395Skan/* Moving between two similar registers is just one instruction.  */
16231117395Skan  else if (reg_classes_intersect_p (to, from))
16232117395Skan    return mode == TFmode ? 4 : 2;
16233117395Skan
16234117395Skan/* Everything else has to go through GENERAL_REGS.  */
16235117395Skan  else
16236117395Skan    return (rs6000_register_move_cost (mode, GENERAL_REGS, to)
16237117395Skan	    + rs6000_register_move_cost (mode, from, GENERAL_REGS));
16238117395Skan}
16239117395Skan
16240117395Skan/* A C expressions returning the cost of moving data of MODE from a register to
16241117395Skan   or from memory.  */
16242117395Skan
16243117395Skanint
16244132718Skanrs6000_memory_move_cost (enum machine_mode mode, enum reg_class class,
16245132718Skan			 int in ATTRIBUTE_UNUSED)
16246117395Skan{
16247117395Skan  if (reg_classes_intersect_p (class, GENERAL_REGS))
16248117395Skan    return 4 * HARD_REGNO_NREGS (0, mode);
16249117395Skan  else if (reg_classes_intersect_p (class, FLOAT_REGS))
16250117395Skan    return 4 * HARD_REGNO_NREGS (32, mode);
16251117395Skan  else if (reg_classes_intersect_p (class, ALTIVEC_REGS))
16252117395Skan    return 4 * HARD_REGNO_NREGS (FIRST_ALTIVEC_REGNO, mode);
16253117395Skan  else
16254117395Skan    return 4 + rs6000_register_move_cost (mode, class, GENERAL_REGS);
16255117395Skan}
16256117395Skan
16257132718Skan/* Return an RTX representing where to find the function value of a
16258132718Skan   function returning MODE.  */
16259132718Skanstatic rtx
16260132718Skanrs6000_complex_function_value (enum machine_mode mode)
16261132718Skan{
16262132718Skan  unsigned int regno;
16263132718Skan  rtx r1, r2;
16264132718Skan  enum machine_mode inner = GET_MODE_INNER (mode);
16265132718Skan  unsigned int inner_bytes = GET_MODE_SIZE (inner);
16266132718Skan
16267132718Skan  if (FLOAT_MODE_P (mode) && TARGET_HARD_FLOAT && TARGET_FPRS)
16268132718Skan    regno = FP_ARG_RETURN;
16269132718Skan  else
16270132718Skan    {
16271132718Skan      regno = GP_ARG_RETURN;
16272132718Skan
16273132718Skan      /* 32-bit is OK since it'll go in r3/r4.  */
16274132718Skan      if (TARGET_32BIT && inner_bytes >= 4)
16275132718Skan	return gen_rtx_REG (mode, regno);
16276132718Skan    }
16277132718Skan
16278132718Skan  if (inner_bytes >= 8)
16279132718Skan    return gen_rtx_REG (mode, regno);
16280132718Skan
16281132718Skan  r1 = gen_rtx_EXPR_LIST (inner, gen_rtx_REG (inner, regno),
16282132718Skan			  const0_rtx);
16283132718Skan  r2 = gen_rtx_EXPR_LIST (inner, gen_rtx_REG (inner, regno + 1),
16284132718Skan			  GEN_INT (inner_bytes));
16285132718Skan  return gen_rtx_PARALLEL (mode, gen_rtvec (2, r1, r2));
16286132718Skan}
16287132718Skan
16288132718Skan/* Define how to find the value returned by a function.
16289132718Skan   VALTYPE is the data type of the value (as a tree).
16290132718Skan   If the precise function being called is known, FUNC is its FUNCTION_DECL;
16291132718Skan   otherwise, FUNC is 0.
16292132718Skan
16293132718Skan   On the SPE, both FPs and vectors are returned in r3.
16294132718Skan
16295132718Skan   On RS/6000 an integer value is in r3 and a floating-point value is in
16296132718Skan   fp1, unless -msoft-float.  */
16297132718Skan
16298132718Skanrtx
16299132718Skanrs6000_function_value (tree valtype, tree func ATTRIBUTE_UNUSED)
16300132718Skan{
16301132718Skan  enum machine_mode mode;
16302132718Skan  unsigned int regno;
16303132718Skan
16304132718Skan  if (TARGET_32BIT && TARGET_POWERPC64 && TYPE_MODE (valtype) == DImode)
16305132718Skan    {
16306132718Skan      /* Long long return value need be split in -mpowerpc64, 32bit ABI.  */
16307132718Skan      return gen_rtx_PARALLEL (DImode,
16308132718Skan	gen_rtvec (2,
16309132718Skan		   gen_rtx_EXPR_LIST (VOIDmode,
16310132718Skan				      gen_rtx_REG (SImode, GP_ARG_RETURN),
16311132718Skan				      const0_rtx),
16312132718Skan		   gen_rtx_EXPR_LIST (VOIDmode,
16313132718Skan				      gen_rtx_REG (SImode,
16314132718Skan						   GP_ARG_RETURN + 1),
16315132718Skan				      GEN_INT (4))));
16316132718Skan    }
16317132718Skan
16318132718Skan  if ((INTEGRAL_TYPE_P (valtype)
16319132718Skan       && TYPE_PRECISION (valtype) < BITS_PER_WORD)
16320132718Skan      || POINTER_TYPE_P (valtype))
16321132718Skan    mode = TARGET_32BIT ? SImode : DImode;
16322132718Skan  else
16323132718Skan    mode = TYPE_MODE (valtype);
16324132718Skan
16325132718Skan  if (SCALAR_FLOAT_TYPE_P (valtype) && TARGET_HARD_FLOAT && TARGET_FPRS)
16326132718Skan    regno = FP_ARG_RETURN;
16327132718Skan  else if (TREE_CODE (valtype) == COMPLEX_TYPE
16328132718Skan	   && targetm.calls.split_complex_arg)
16329132718Skan    return rs6000_complex_function_value (mode);
16330132718Skan  else if (TREE_CODE (valtype) == VECTOR_TYPE
16331132718Skan	   && TARGET_ALTIVEC && TARGET_ALTIVEC_ABI)
16332132718Skan    regno = ALTIVEC_ARG_RETURN;
16333132718Skan  else
16334132718Skan    regno = GP_ARG_RETURN;
16335132718Skan
16336132718Skan  return gen_rtx_REG (mode, regno);
16337132718Skan}
16338132718Skan
16339132718Skan/* Define how to find the value returned by a library function
16340132718Skan   assuming the value has mode MODE.  */
16341132718Skanrtx
16342132718Skanrs6000_libcall_value (enum machine_mode mode)
16343132718Skan{
16344132718Skan  unsigned int regno;
16345132718Skan
16346132718Skan  if (GET_MODE_CLASS (mode) == MODE_FLOAT
16347132718Skan	   && TARGET_HARD_FLOAT && TARGET_FPRS)
16348132718Skan    regno = FP_ARG_RETURN;
16349132718Skan  else if (ALTIVEC_VECTOR_MODE (mode)
16350132718Skan	   && TARGET_ALTIVEC && TARGET_ALTIVEC_ABI)
16351132718Skan    regno = ALTIVEC_ARG_RETURN;
16352132718Skan  else if (COMPLEX_MODE_P (mode) && targetm.calls.split_complex_arg)
16353132718Skan    return rs6000_complex_function_value (mode);
16354132718Skan  else
16355132718Skan    regno = GP_ARG_RETURN;
16356132718Skan
16357132718Skan  return gen_rtx_REG (mode, regno);
16358132718Skan}
16359132718Skan
16360132718Skan/* Define the offset between two registers, FROM to be eliminated and its
16361132718Skan   replacement TO, at the start of a routine.  */
16362132718SkanHOST_WIDE_INT
16363132718Skanrs6000_initial_elimination_offset (int from, int to)
16364132718Skan{
16365132718Skan  rs6000_stack_t *info = rs6000_stack_info ();
16366132718Skan  HOST_WIDE_INT offset;
16367132718Skan
16368132718Skan  if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
16369132718Skan    offset = info->push_p ? 0 : -info->total_size;
16370132718Skan  else if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)
16371132718Skan    offset = info->total_size;
16372132718Skan  else if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
16373132718Skan    offset = info->push_p ? info->total_size : 0;
16374132718Skan  else if (from == RS6000_PIC_OFFSET_TABLE_REGNUM)
16375132718Skan    offset = 0;
16376132718Skan  else
16377132718Skan    abort ();
16378132718Skan
16379132718Skan  return offset;
16380132718Skan}
16381132718Skan
16382132718Skan/* Return true if TYPE is of type __ev64_opaque__.  */
16383132718Skan
16384132718Skanstatic bool
16385132718Skanis_ev64_opaque_type (tree type)
16386132718Skan{
16387132718Skan  return (TARGET_SPE
16388132718Skan	  && (type == opaque_V2SI_type_node
16389132718Skan	      || type == opaque_V2SF_type_node
16390132718Skan	      || type == opaque_p_V2SI_type_node));
16391132718Skan}
16392132718Skan
16393132718Skanstatic rtx
16394132718Skanrs6000_dwarf_register_span (rtx reg)
16395132718Skan{
16396132718Skan  unsigned regno;
16397132718Skan
16398132718Skan  if (!TARGET_SPE || !SPE_VECTOR_MODE (GET_MODE (reg)))
16399132718Skan    return NULL_RTX;
16400132718Skan
16401132718Skan  regno = REGNO (reg);
16402132718Skan
16403132718Skan  /* The duality of the SPE register size wreaks all kinds of havoc.
16404132718Skan     This is a way of distinguishing r0 in 32-bits from r0 in
16405132718Skan     64-bits.  */
16406132718Skan  return
16407132718Skan    gen_rtx_PARALLEL (VOIDmode,
16408132718Skan		      BYTES_BIG_ENDIAN
16409132718Skan		      ? gen_rtvec (2,
16410132718Skan				   gen_rtx_REG (SImode, regno + 1200),
16411132718Skan				   gen_rtx_REG (SImode, regno))
16412132718Skan		      : gen_rtvec (2,
16413132718Skan				   gen_rtx_REG (SImode, regno),
16414132718Skan				   gen_rtx_REG (SImode, regno + 1200)));
16415132718Skan}
16416132718Skan
16417132718Skan/* Map internal gcc register numbers to DWARF2 register numbers.  */
16418132718Skan
16419132718Skanunsigned int
16420132718Skanrs6000_dbx_register_number (unsigned int regno)
16421132718Skan{
16422132718Skan  if (regno <= 63 || write_symbols != DWARF2_DEBUG)
16423132718Skan    return regno;
16424132718Skan  if (regno == MQ_REGNO)
16425132718Skan    return 100;
16426132718Skan  if (regno == LINK_REGISTER_REGNUM)
16427132718Skan    return 108;
16428132718Skan  if (regno == COUNT_REGISTER_REGNUM)
16429132718Skan    return 109;
16430132718Skan  if (CR_REGNO_P (regno))
16431132718Skan    return regno - CR0_REGNO + 86;
16432132718Skan  if (regno == XER_REGNO)
16433132718Skan    return 101;
16434132718Skan  if (ALTIVEC_REGNO_P (regno))
16435132718Skan    return regno - FIRST_ALTIVEC_REGNO + 1124;
16436132718Skan  if (regno == VRSAVE_REGNO)
16437132718Skan    return 356;
16438132718Skan  if (regno == VSCR_REGNO)
16439132718Skan    return 67;
16440132718Skan  if (regno == SPE_ACC_REGNO)
16441132718Skan    return 99;
16442132718Skan  if (regno == SPEFSCR_REGNO)
16443132718Skan    return 612;
16444132718Skan  /* SPE high reg number.  We get these values of regno from
16445132718Skan     rs6000_dwarf_register_span.  */
16446132718Skan  if (regno >= 1200 && regno < 1232)
16447132718Skan    return regno;
16448132718Skan
16449132718Skan  abort ();
16450132718Skan}
16451132718Skan
16452132718Skan#include "gt-rs6000.h"
16453