190075Sobrien/* Subroutines used for code generation on IBM RS/6000.
2169689Skan   Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
3169689Skan   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
4169689Skan   Free Software Foundation, Inc.
590075Sobrien   Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
690075Sobrien
7132718Skan   This file is part of GCC.
890075Sobrien
9132718Skan   GCC is free software; you can redistribute it and/or modify it
10132718Skan   under the terms of the GNU General Public License as published
11132718Skan   by the Free Software Foundation; either version 2, or (at your
12132718Skan   option) any later version.
1390075Sobrien
14132718Skan   GCC is distributed in the hope that it will be useful, but WITHOUT
15132718Skan   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16132718Skan   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
17132718Skan   License for more details.
1890075Sobrien
19132718Skan   You should have received a copy of the GNU General Public License
20132718Skan   along with GCC; see the file COPYING.  If not, write to the
21169689Skan   Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
22169689Skan   MA 02110-1301, USA.  */
2390075Sobrien
2490075Sobrien#include "config.h"
2590075Sobrien#include "system.h"
26132718Skan#include "coretypes.h"
27132718Skan#include "tm.h"
2890075Sobrien#include "rtl.h"
2990075Sobrien#include "regs.h"
3090075Sobrien#include "hard-reg-set.h"
3190075Sobrien#include "real.h"
3290075Sobrien#include "insn-config.h"
3390075Sobrien#include "conditions.h"
3490075Sobrien#include "insn-attr.h"
3590075Sobrien#include "flags.h"
3690075Sobrien#include "recog.h"
3790075Sobrien#include "obstack.h"
3890075Sobrien#include "tree.h"
3990075Sobrien#include "expr.h"
4090075Sobrien#include "optabs.h"
4190075Sobrien#include "except.h"
4290075Sobrien#include "function.h"
4390075Sobrien#include "output.h"
4490075Sobrien#include "basic-block.h"
4590075Sobrien#include "integrate.h"
4690075Sobrien#include "toplev.h"
4790075Sobrien#include "ggc.h"
4890075Sobrien#include "hashtab.h"
4990075Sobrien#include "tm_p.h"
5090075Sobrien#include "target.h"
5190075Sobrien#include "target-def.h"
5290075Sobrien#include "langhooks.h"
5390075Sobrien#include "reload.h"
54132718Skan#include "cfglayout.h"
55132718Skan#include "sched-int.h"
56169689Skan#include "tree-gimple.h"
57169689Skan#include "intl.h"
58169689Skan#include "params.h"
59169689Skan#include "tm-constrs.h"
60132718Skan#if TARGET_XCOFF
61132718Skan#include "xcoffout.h"  /* get declarations of xcoff_*_section_name */
62132718Skan#endif
63169689Skan#if TARGET_MACHO
64169689Skan#include "gstab.h"  /* for N_SLINE */
65169689Skan#endif
6690075Sobrien
6790075Sobrien#ifndef TARGET_NO_PROTOTYPE
6890075Sobrien#define TARGET_NO_PROTOTYPE 0
6990075Sobrien#endif
7090075Sobrien
7190075Sobrien#define min(A,B)	((A) < (B) ? (A) : (B))
7290075Sobrien#define max(A,B)	((A) > (B) ? (A) : (B))
7390075Sobrien
74132718Skan/* Structure used to define the rs6000 stack */
75132718Skantypedef struct rs6000_stack {
76132718Skan  int first_gp_reg_save;	/* first callee saved GP register used */
77132718Skan  int first_fp_reg_save;	/* first callee saved FP register used */
78132718Skan  int first_altivec_reg_save;	/* first callee saved AltiVec register used */
79132718Skan  int lr_save_p;		/* true if the link reg needs to be saved */
80132718Skan  int cr_save_p;		/* true if the CR reg needs to be saved */
81132718Skan  unsigned int vrsave_mask;	/* mask of vec registers to save */
82132718Skan  int push_p;			/* true if we need to allocate stack space */
83132718Skan  int calls_p;			/* true if the function makes any calls */
84169689Skan  int world_save_p;		/* true if we're saving *everything*:
85169689Skan				   r13-r31, cr, f14-f31, vrsave, v20-v31  */
86132718Skan  enum rs6000_abi abi;		/* which ABI to use */
87132718Skan  int gp_save_offset;		/* offset to save GP regs from initial SP */
88132718Skan  int fp_save_offset;		/* offset to save FP regs from initial SP */
89132718Skan  int altivec_save_offset;	/* offset to save AltiVec regs from initial SP */
90132718Skan  int lr_save_offset;		/* offset to save LR from initial SP */
91132718Skan  int cr_save_offset;		/* offset to save CR from initial SP */
92132718Skan  int vrsave_save_offset;	/* offset to save VRSAVE from initial SP */
93132718Skan  int spe_gp_save_offset;	/* offset to save spe 64-bit gprs  */
94132718Skan  int varargs_save_offset;	/* offset to save the varargs registers */
95132718Skan  int ehrd_offset;		/* offset to EH return data */
96132718Skan  int reg_size;			/* register size (4 or 8) */
97132718Skan  HOST_WIDE_INT vars_size;	/* variable save area size */
98132718Skan  int parm_size;		/* outgoing parameter size */
99132718Skan  int save_size;		/* save area size */
100132718Skan  int fixed_size;		/* fixed size of stack frame */
101132718Skan  int gp_size;			/* size of saved GP registers */
102132718Skan  int fp_size;			/* size of saved FP registers */
103132718Skan  int altivec_size;		/* size of saved AltiVec registers */
104132718Skan  int cr_size;			/* size to hold CR if not in save_size */
105132718Skan  int vrsave_size;		/* size to hold VRSAVE if not in save_size */
106132718Skan  int altivec_padding_size;	/* size of altivec alignment padding if
107132718Skan				   not in save_size */
108132718Skan  int spe_gp_size;		/* size of 64-bit GPR save size for SPE */
109132718Skan  int spe_padding_size;
110132718Skan  HOST_WIDE_INT total_size;	/* total bytes allocated for stack */
111132718Skan  int spe_64bit_regs_used;
112132718Skan} rs6000_stack_t;
113132718Skan
114169689Skan/* A C structure for machine-specific, per-function data.
115169689Skan   This is added to the cfun structure.  */
116169689Skantypedef struct machine_function GTY(())
117169689Skan{
118169689Skan  /* Flags if __builtin_return_address (n) with n >= 1 was used.  */
119169689Skan  int ra_needs_full_frame;
120169689Skan  /* Some local-dynamic symbol.  */
121169689Skan  const char *some_ld_name;
122169689Skan  /* Whether the instruction chain has been scanned already.  */
123169689Skan  int insn_chain_scanned_p;
124169689Skan  /* Flags if __builtin_return_address (0) was used.  */
125169689Skan  int ra_need_lr;
126169689Skan  /* Offset from virtual_stack_vars_rtx to the start of the ABI_V4
127169689Skan     varargs save area.  */
128169689Skan  HOST_WIDE_INT varargs_save_offset;
129169689Skan} machine_function;
130169689Skan
13190075Sobrien/* Target cpu type */
13290075Sobrien
13390075Sobrienenum processor_type rs6000_cpu;
13490075Sobrienstruct rs6000_cpu_select rs6000_select[3] =
13590075Sobrien{
13690075Sobrien  /* switch		name,			tune	arch */
13790075Sobrien  { (const char *)0,	"--with-cpu=",		1,	1 },
13890075Sobrien  { (const char *)0,	"-mcpu=",		1,	1 },
13990075Sobrien  { (const char *)0,	"-mtune=",		1,	0 },
14090075Sobrien};
14190075Sobrien
142132718Skan/* Always emit branch hint bits.  */
143132718Skanstatic GTY(()) bool rs6000_always_hint;
144132718Skan
145132718Skan/* Schedule instructions for group formation.  */
146132718Skanstatic GTY(()) bool rs6000_sched_groups;
147132718Skan
148132718Skan/* Support for -msched-costly-dep option.  */
149132718Skanconst char *rs6000_sched_costly_dep_str;
150132718Skanenum rs6000_dependence_cost rs6000_sched_costly_dep;
151132718Skan
152132718Skan/* Support for -minsert-sched-nops option.  */
153132718Skanconst char *rs6000_sched_insert_nops_str;
154132718Skanenum rs6000_nop_insertion rs6000_sched_insert_nops;
155132718Skan
156169689Skan/* Support targetm.vectorize.builtin_mask_for_load.  */
157169689Skanstatic GTY(()) tree altivec_builtin_mask_for_load;
158169689Skan
159169689Skan/* Size of long double.  */
16090075Sobrienint rs6000_long_double_type_size;
16190075Sobrien
162169689Skan/* IEEE quad extended precision long double. */
163169689Skanint rs6000_ieeequad;
164169689Skan
165169689Skan/* Whether -mabi=altivec has appeared.  */
16690075Sobrienint rs6000_altivec_abi;
16790075Sobrien
168117395Skan/* Nonzero if we want SPE ABI extensions.  */
169117395Skanint rs6000_spe_abi;
170117395Skan
171132718Skan/* Nonzero if floating point operations are done in the GPRs.  */
172132718Skanint rs6000_float_gprs = 0;
173132718Skan
174169689Skan/* Nonzero if we want Darwin's struct-by-value-in-regs ABI.  */
175169689Skanint rs6000_darwin64_abi;
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
210169689Skan/* Whether to use variant of AIX ABI for PowerPC64 Linux.  */
211169689Skanint dot_symbols;
21290075Sobrien
21390075Sobrien/* Debug flags */
21490075Sobrienconst char *rs6000_debug_name;
21590075Sobrienint rs6000_debug_stack;		/* debug stack applications */
21690075Sobrienint rs6000_debug_arg;		/* debug argument handling */
21790075Sobrien
218169689Skan/* Value is TRUE if register/mode pair is acceptable.  */
219169689Skanbool rs6000_hard_regno_mode_ok_p[NUM_MACHINE_MODES][FIRST_PSEUDO_REGISTER];
220132718Skan
221169689Skan/* Built in types.  */
222146895Skan
223169689Skantree rs6000_builtin_types[RS6000_BTI_MAX];
224169689Skantree rs6000_builtin_decls[RS6000_BUILTIN_COUNT];
225146895Skan
226117395Skanconst char *rs6000_traceback_name;
227117395Skanstatic enum {
228117395Skan  traceback_default = 0,
229117395Skan  traceback_none,
230117395Skan  traceback_part,
231117395Skan  traceback_full
232117395Skan} rs6000_traceback;
233117395Skan
23490075Sobrien/* Flag to say the TOC is initialized */
23590075Sobrienint toc_initialized;
23690075Sobrienchar toc_label_name[10];
23790075Sobrien
238169689Skanstatic GTY(()) section *read_only_data_section;
239169689Skanstatic GTY(()) section *private_data_section;
240169689Skanstatic GTY(()) section *read_only_private_data_section;
241169689Skanstatic GTY(()) section *sdata2_section;
242169689Skanstatic GTY(()) section *toc_section;
24390075Sobrien
244132718Skan/* Control alignment for fields within structures.  */
245132718Skan/* String from -malign-XXXXX.  */
246132718Skanint rs6000_alignment_flags;
247132718Skan
248169689Skan/* True for any options that were explicitly set.  */
249169689Skanstruct {
250169689Skan  bool aix_struct_ret;		/* True if -maix-struct-ret was used.  */
251169689Skan  bool alignment;		/* True if -malign- was used.  */
252169689Skan  bool abi;			/* True if -mabi=spe/nospe was used.  */
253169689Skan  bool spe;			/* True if -mspe= was used.  */
254169689Skan  bool float_gprs;		/* True if -mfloat-gprs= was used.  */
255169689Skan  bool isel;			/* True if -misel was used. */
256169689Skan  bool long_double;	        /* True if -mlong-double- was used.  */
257169689Skan  bool ieee;			/* True if -mabi=ieee/ibmlongdouble used.  */
258169689Skan} rs6000_explicit_options;
259169689Skan
260117395Skanstruct builtin_description
261117395Skan{
262117395Skan  /* mask is not const because we're going to alter it below.  This
263117395Skan     nonsense will go away when we rewrite the -march infrastructure
264117395Skan     to give us more target flag bits.  */
265117395Skan  unsigned int mask;
266117395Skan  const enum insn_code icode;
267117395Skan  const char *const name;
268117395Skan  const enum rs6000_builtins code;
269117395Skan};
270169689Skan
271169689Skan/* Target cpu costs.  */
272117395Skan
273169689Skanstruct processor_costs {
274169689Skan  const int mulsi;	  /* cost of SImode multiplication.  */
275169689Skan  const int mulsi_const;  /* cost of SImode multiplication by constant.  */
276169689Skan  const int mulsi_const9; /* cost of SImode mult by short constant.  */
277169689Skan  const int muldi;	  /* cost of DImode multiplication.  */
278169689Skan  const int divsi;	  /* cost of SImode division.  */
279169689Skan  const int divdi;	  /* cost of DImode division.  */
280169689Skan  const int fp;		  /* cost of simple SFmode and DFmode insns.  */
281169689Skan  const int dmul;	  /* cost of DFmode multiplication (and fmadd).  */
282169689Skan  const int sdiv;	  /* cost of SFmode division (fdivs).  */
283169689Skan  const int ddiv;	  /* cost of DFmode division (fdiv).  */
284169689Skan};
285169689Skan
286169689Skanconst struct processor_costs *rs6000_cost;
287169689Skan
288169689Skan/* Processor costs (relative to an add) */
289169689Skan
290169689Skan/* Instruction size costs on 32bit processors.  */
291169689Skanstatic const
292169689Skanstruct processor_costs size32_cost = {
293169689Skan  COSTS_N_INSNS (1),    /* mulsi */
294169689Skan  COSTS_N_INSNS (1),    /* mulsi_const */
295169689Skan  COSTS_N_INSNS (1),    /* mulsi_const9 */
296169689Skan  COSTS_N_INSNS (1),    /* muldi */
297169689Skan  COSTS_N_INSNS (1),    /* divsi */
298169689Skan  COSTS_N_INSNS (1),    /* divdi */
299169689Skan  COSTS_N_INSNS (1),    /* fp */
300169689Skan  COSTS_N_INSNS (1),    /* dmul */
301169689Skan  COSTS_N_INSNS (1),    /* sdiv */
302169689Skan  COSTS_N_INSNS (1),    /* ddiv */
303169689Skan};
304169689Skan
305169689Skan/* Instruction size costs on 64bit processors.  */
306169689Skanstatic const
307169689Skanstruct processor_costs size64_cost = {
308169689Skan  COSTS_N_INSNS (1),    /* mulsi */
309169689Skan  COSTS_N_INSNS (1),    /* mulsi_const */
310169689Skan  COSTS_N_INSNS (1),    /* mulsi_const9 */
311169689Skan  COSTS_N_INSNS (1),    /* muldi */
312169689Skan  COSTS_N_INSNS (1),    /* divsi */
313169689Skan  COSTS_N_INSNS (1),    /* divdi */
314169689Skan  COSTS_N_INSNS (1),    /* fp */
315169689Skan  COSTS_N_INSNS (1),    /* dmul */
316169689Skan  COSTS_N_INSNS (1),    /* sdiv */
317169689Skan  COSTS_N_INSNS (1),    /* ddiv */
318169689Skan};
319169689Skan
320169689Skan/* Instruction costs on RIOS1 processors.  */
321169689Skanstatic const
322169689Skanstruct processor_costs rios1_cost = {
323169689Skan  COSTS_N_INSNS (5),    /* mulsi */
324169689Skan  COSTS_N_INSNS (4),    /* mulsi_const */
325169689Skan  COSTS_N_INSNS (3),    /* mulsi_const9 */
326169689Skan  COSTS_N_INSNS (5),    /* muldi */
327169689Skan  COSTS_N_INSNS (19),   /* divsi */
328169689Skan  COSTS_N_INSNS (19),   /* divdi */
329169689Skan  COSTS_N_INSNS (2),    /* fp */
330169689Skan  COSTS_N_INSNS (2),    /* dmul */
331169689Skan  COSTS_N_INSNS (19),   /* sdiv */
332169689Skan  COSTS_N_INSNS (19),   /* ddiv */
333169689Skan};
334169689Skan
335169689Skan/* Instruction costs on RIOS2 processors.  */
336169689Skanstatic const
337169689Skanstruct processor_costs rios2_cost = {
338169689Skan  COSTS_N_INSNS (2),    /* mulsi */
339169689Skan  COSTS_N_INSNS (2),    /* mulsi_const */
340169689Skan  COSTS_N_INSNS (2),    /* mulsi_const9 */
341169689Skan  COSTS_N_INSNS (2),    /* muldi */
342169689Skan  COSTS_N_INSNS (13),   /* divsi */
343169689Skan  COSTS_N_INSNS (13),   /* divdi */
344169689Skan  COSTS_N_INSNS (2),    /* fp */
345169689Skan  COSTS_N_INSNS (2),    /* dmul */
346169689Skan  COSTS_N_INSNS (17),   /* sdiv */
347169689Skan  COSTS_N_INSNS (17),   /* ddiv */
348169689Skan};
349169689Skan
350169689Skan/* Instruction costs on RS64A processors.  */
351169689Skanstatic const
352169689Skanstruct processor_costs rs64a_cost = {
353169689Skan  COSTS_N_INSNS (20),   /* mulsi */
354169689Skan  COSTS_N_INSNS (12),   /* mulsi_const */
355169689Skan  COSTS_N_INSNS (8),    /* mulsi_const9 */
356169689Skan  COSTS_N_INSNS (34),   /* muldi */
357169689Skan  COSTS_N_INSNS (65),   /* divsi */
358169689Skan  COSTS_N_INSNS (67),   /* divdi */
359169689Skan  COSTS_N_INSNS (4),    /* fp */
360169689Skan  COSTS_N_INSNS (4),    /* dmul */
361169689Skan  COSTS_N_INSNS (31),   /* sdiv */
362169689Skan  COSTS_N_INSNS (31),   /* ddiv */
363169689Skan};
364169689Skan
365169689Skan/* Instruction costs on MPCCORE processors.  */
366169689Skanstatic const
367169689Skanstruct processor_costs mpccore_cost = {
368169689Skan  COSTS_N_INSNS (2),    /* mulsi */
369169689Skan  COSTS_N_INSNS (2),    /* mulsi_const */
370169689Skan  COSTS_N_INSNS (2),    /* mulsi_const9 */
371169689Skan  COSTS_N_INSNS (2),    /* muldi */
372169689Skan  COSTS_N_INSNS (6),    /* divsi */
373169689Skan  COSTS_N_INSNS (6),    /* divdi */
374169689Skan  COSTS_N_INSNS (4),    /* fp */
375169689Skan  COSTS_N_INSNS (5),    /* dmul */
376169689Skan  COSTS_N_INSNS (10),   /* sdiv */
377169689Skan  COSTS_N_INSNS (17),   /* ddiv */
378169689Skan};
379169689Skan
380169689Skan/* Instruction costs on PPC403 processors.  */
381169689Skanstatic const
382169689Skanstruct processor_costs ppc403_cost = {
383169689Skan  COSTS_N_INSNS (4),    /* mulsi */
384169689Skan  COSTS_N_INSNS (4),    /* mulsi_const */
385169689Skan  COSTS_N_INSNS (4),    /* mulsi_const9 */
386169689Skan  COSTS_N_INSNS (4),    /* muldi */
387169689Skan  COSTS_N_INSNS (33),   /* divsi */
388169689Skan  COSTS_N_INSNS (33),   /* divdi */
389169689Skan  COSTS_N_INSNS (11),   /* fp */
390169689Skan  COSTS_N_INSNS (11),   /* dmul */
391169689Skan  COSTS_N_INSNS (11),   /* sdiv */
392169689Skan  COSTS_N_INSNS (11),   /* ddiv */
393169689Skan};
394169689Skan
395169689Skan/* Instruction costs on PPC405 processors.  */
396169689Skanstatic const
397169689Skanstruct processor_costs ppc405_cost = {
398169689Skan  COSTS_N_INSNS (5),    /* mulsi */
399169689Skan  COSTS_N_INSNS (4),    /* mulsi_const */
400169689Skan  COSTS_N_INSNS (3),    /* mulsi_const9 */
401169689Skan  COSTS_N_INSNS (5),    /* muldi */
402169689Skan  COSTS_N_INSNS (35),   /* divsi */
403169689Skan  COSTS_N_INSNS (35),   /* divdi */
404169689Skan  COSTS_N_INSNS (11),   /* fp */
405169689Skan  COSTS_N_INSNS (11),   /* dmul */
406169689Skan  COSTS_N_INSNS (11),   /* sdiv */
407169689Skan  COSTS_N_INSNS (11),   /* ddiv */
408169689Skan};
409169689Skan
410169689Skan/* Instruction costs on PPC440 processors.  */
411169689Skanstatic const
412169689Skanstruct processor_costs ppc440_cost = {
413169689Skan  COSTS_N_INSNS (3),    /* mulsi */
414169689Skan  COSTS_N_INSNS (2),    /* mulsi_const */
415169689Skan  COSTS_N_INSNS (2),    /* mulsi_const9 */
416169689Skan  COSTS_N_INSNS (3),    /* muldi */
417169689Skan  COSTS_N_INSNS (34),   /* divsi */
418169689Skan  COSTS_N_INSNS (34),   /* divdi */
419169689Skan  COSTS_N_INSNS (5),    /* fp */
420169689Skan  COSTS_N_INSNS (5),    /* dmul */
421169689Skan  COSTS_N_INSNS (19),   /* sdiv */
422169689Skan  COSTS_N_INSNS (33),   /* ddiv */
423169689Skan};
424169689Skan
425169689Skan/* Instruction costs on PPC601 processors.  */
426169689Skanstatic const
427169689Skanstruct processor_costs ppc601_cost = {
428169689Skan  COSTS_N_INSNS (5),    /* mulsi */
429169689Skan  COSTS_N_INSNS (5),    /* mulsi_const */
430169689Skan  COSTS_N_INSNS (5),    /* mulsi_const9 */
431169689Skan  COSTS_N_INSNS (5),    /* muldi */
432169689Skan  COSTS_N_INSNS (36),   /* divsi */
433169689Skan  COSTS_N_INSNS (36),   /* divdi */
434169689Skan  COSTS_N_INSNS (4),    /* fp */
435169689Skan  COSTS_N_INSNS (5),    /* dmul */
436169689Skan  COSTS_N_INSNS (17),   /* sdiv */
437169689Skan  COSTS_N_INSNS (31),   /* ddiv */
438169689Skan};
439169689Skan
440169689Skan/* Instruction costs on PPC603 processors.  */
441169689Skanstatic const
442169689Skanstruct processor_costs ppc603_cost = {
443169689Skan  COSTS_N_INSNS (5),    /* mulsi */
444169689Skan  COSTS_N_INSNS (3),    /* mulsi_const */
445169689Skan  COSTS_N_INSNS (2),    /* mulsi_const9 */
446169689Skan  COSTS_N_INSNS (5),    /* muldi */
447169689Skan  COSTS_N_INSNS (37),   /* divsi */
448169689Skan  COSTS_N_INSNS (37),   /* divdi */
449169689Skan  COSTS_N_INSNS (3),    /* fp */
450169689Skan  COSTS_N_INSNS (4),    /* dmul */
451169689Skan  COSTS_N_INSNS (18),   /* sdiv */
452169689Skan  COSTS_N_INSNS (33),   /* ddiv */
453169689Skan};
454169689Skan
455169689Skan/* Instruction costs on PPC604 processors.  */
456169689Skanstatic const
457169689Skanstruct processor_costs ppc604_cost = {
458169689Skan  COSTS_N_INSNS (4),    /* mulsi */
459169689Skan  COSTS_N_INSNS (4),    /* mulsi_const */
460169689Skan  COSTS_N_INSNS (4),    /* mulsi_const9 */
461169689Skan  COSTS_N_INSNS (4),    /* muldi */
462169689Skan  COSTS_N_INSNS (20),   /* divsi */
463169689Skan  COSTS_N_INSNS (20),   /* divdi */
464169689Skan  COSTS_N_INSNS (3),    /* fp */
465169689Skan  COSTS_N_INSNS (3),    /* dmul */
466169689Skan  COSTS_N_INSNS (18),   /* sdiv */
467169689Skan  COSTS_N_INSNS (32),   /* ddiv */
468169689Skan};
469169689Skan
470169689Skan/* Instruction costs on PPC604e processors.  */
471169689Skanstatic const
472169689Skanstruct processor_costs ppc604e_cost = {
473169689Skan  COSTS_N_INSNS (2),    /* mulsi */
474169689Skan  COSTS_N_INSNS (2),    /* mulsi_const */
475169689Skan  COSTS_N_INSNS (2),    /* mulsi_const9 */
476169689Skan  COSTS_N_INSNS (2),    /* muldi */
477169689Skan  COSTS_N_INSNS (20),   /* divsi */
478169689Skan  COSTS_N_INSNS (20),   /* divdi */
479169689Skan  COSTS_N_INSNS (3),    /* fp */
480169689Skan  COSTS_N_INSNS (3),    /* dmul */
481169689Skan  COSTS_N_INSNS (18),   /* sdiv */
482169689Skan  COSTS_N_INSNS (32),   /* ddiv */
483169689Skan};
484169689Skan
485169689Skan/* Instruction costs on PPC620 processors.  */
486169689Skanstatic const
487169689Skanstruct processor_costs ppc620_cost = {
488169689Skan  COSTS_N_INSNS (5),    /* mulsi */
489169689Skan  COSTS_N_INSNS (4),    /* mulsi_const */
490169689Skan  COSTS_N_INSNS (3),    /* mulsi_const9 */
491169689Skan  COSTS_N_INSNS (7),    /* muldi */
492169689Skan  COSTS_N_INSNS (21),   /* divsi */
493169689Skan  COSTS_N_INSNS (37),   /* divdi */
494169689Skan  COSTS_N_INSNS (3),    /* fp */
495169689Skan  COSTS_N_INSNS (3),    /* dmul */
496169689Skan  COSTS_N_INSNS (18),   /* sdiv */
497169689Skan  COSTS_N_INSNS (32),   /* ddiv */
498169689Skan};
499169689Skan
500169689Skan/* Instruction costs on PPC630 processors.  */
501169689Skanstatic const
502169689Skanstruct processor_costs ppc630_cost = {
503169689Skan  COSTS_N_INSNS (5),    /* mulsi */
504169689Skan  COSTS_N_INSNS (4),    /* mulsi_const */
505169689Skan  COSTS_N_INSNS (3),    /* mulsi_const9 */
506169689Skan  COSTS_N_INSNS (7),    /* muldi */
507169689Skan  COSTS_N_INSNS (21),   /* divsi */
508169689Skan  COSTS_N_INSNS (37),   /* divdi */
509169689Skan  COSTS_N_INSNS (3),    /* fp */
510169689Skan  COSTS_N_INSNS (3),    /* dmul */
511169689Skan  COSTS_N_INSNS (17),   /* sdiv */
512169689Skan  COSTS_N_INSNS (21),   /* ddiv */
513169689Skan};
514169689Skan
515169689Skan/* Instruction costs on PPC750 and PPC7400 processors.  */
516169689Skanstatic const
517169689Skanstruct processor_costs ppc750_cost = {
518169689Skan  COSTS_N_INSNS (5),    /* mulsi */
519169689Skan  COSTS_N_INSNS (3),    /* mulsi_const */
520169689Skan  COSTS_N_INSNS (2),    /* mulsi_const9 */
521169689Skan  COSTS_N_INSNS (5),    /* muldi */
522169689Skan  COSTS_N_INSNS (17),   /* divsi */
523169689Skan  COSTS_N_INSNS (17),   /* divdi */
524169689Skan  COSTS_N_INSNS (3),    /* fp */
525169689Skan  COSTS_N_INSNS (3),    /* dmul */
526169689Skan  COSTS_N_INSNS (17),   /* sdiv */
527169689Skan  COSTS_N_INSNS (31),   /* ddiv */
528169689Skan};
529169689Skan
530169689Skan/* Instruction costs on PPC7450 processors.  */
531169689Skanstatic const
532169689Skanstruct processor_costs ppc7450_cost = {
533169689Skan  COSTS_N_INSNS (4),    /* mulsi */
534169689Skan  COSTS_N_INSNS (3),    /* mulsi_const */
535169689Skan  COSTS_N_INSNS (3),    /* mulsi_const9 */
536169689Skan  COSTS_N_INSNS (4),    /* muldi */
537169689Skan  COSTS_N_INSNS (23),   /* divsi */
538169689Skan  COSTS_N_INSNS (23),   /* divdi */
539169689Skan  COSTS_N_INSNS (5),    /* fp */
540169689Skan  COSTS_N_INSNS (5),    /* dmul */
541169689Skan  COSTS_N_INSNS (21),   /* sdiv */
542169689Skan  COSTS_N_INSNS (35),   /* ddiv */
543169689Skan};
544169689Skan
545169689Skan/* Instruction costs on PPC8540 processors.  */
546169689Skanstatic const
547169689Skanstruct processor_costs ppc8540_cost = {
548169689Skan  COSTS_N_INSNS (4),    /* mulsi */
549169689Skan  COSTS_N_INSNS (4),    /* mulsi_const */
550169689Skan  COSTS_N_INSNS (4),    /* mulsi_const9 */
551169689Skan  COSTS_N_INSNS (4),    /* muldi */
552169689Skan  COSTS_N_INSNS (19),   /* divsi */
553169689Skan  COSTS_N_INSNS (19),   /* divdi */
554169689Skan  COSTS_N_INSNS (4),    /* fp */
555169689Skan  COSTS_N_INSNS (4),    /* dmul */
556169689Skan  COSTS_N_INSNS (29),   /* sdiv */
557169689Skan  COSTS_N_INSNS (29),   /* ddiv */
558169689Skan};
559169689Skan
560169689Skan/* Instruction costs on POWER4 and POWER5 processors.  */
561169689Skanstatic const
562169689Skanstruct processor_costs power4_cost = {
563169689Skan  COSTS_N_INSNS (3),    /* mulsi */
564169689Skan  COSTS_N_INSNS (2),    /* mulsi_const */
565169689Skan  COSTS_N_INSNS (2),    /* mulsi_const9 */
566169689Skan  COSTS_N_INSNS (4),    /* muldi */
567169689Skan  COSTS_N_INSNS (18),   /* divsi */
568169689Skan  COSTS_N_INSNS (34),   /* divdi */
569169689Skan  COSTS_N_INSNS (3),    /* fp */
570169689Skan  COSTS_N_INSNS (3),    /* dmul */
571169689Skan  COSTS_N_INSNS (17),   /* sdiv */
572169689Skan  COSTS_N_INSNS (17),   /* ddiv */
573169689Skan};
574169689Skan
575169689Skan
576132718Skanstatic bool rs6000_function_ok_for_sibcall (tree, tree);
577169689Skanstatic const char *rs6000_invalid_within_doloop (rtx);
578132718Skanstatic rtx rs6000_generate_compare (enum rtx_code);
579132718Skanstatic void rs6000_maybe_dead (rtx);
580132718Skanstatic void rs6000_emit_stack_tie (void);
581132718Skanstatic void rs6000_frame_related (rtx, rtx, HOST_WIDE_INT, rtx, rtx);
582132718Skanstatic rtx spe_synthesize_frame_save (rtx);
583132718Skanstatic bool spe_func_has_64bit_regs_p (void);
584132718Skanstatic void emit_frame_save (rtx, rtx, enum machine_mode, unsigned int,
585132718Skan			     int, HOST_WIDE_INT);
586132718Skanstatic rtx gen_frame_mem_offset (enum machine_mode, rtx, int);
587132718Skanstatic void rs6000_emit_allocate_stack (HOST_WIDE_INT, int);
588132718Skanstatic unsigned rs6000_hash_constant (rtx);
589132718Skanstatic unsigned toc_hash_function (const void *);
590132718Skanstatic int toc_hash_eq (const void *, const void *);
591132718Skanstatic int constant_pool_expr_1 (rtx, int *, int *);
592132718Skanstatic bool constant_pool_expr_p (rtx);
593132718Skanstatic bool legitimate_small_data_p (enum machine_mode, rtx);
594132718Skanstatic bool legitimate_indexed_address_p (rtx, int);
595132718Skanstatic bool legitimate_lo_sum_address_p (enum machine_mode, rtx, int);
596132718Skanstatic struct machine_function * rs6000_init_machine_status (void);
597132718Skanstatic bool rs6000_assemble_integer (rtx, unsigned int, int);
598169689Skanstatic bool no_global_regs_above (int);
599117395Skan#ifdef HAVE_GAS_HIDDEN
600132718Skanstatic void rs6000_assemble_visibility (tree, int);
601117395Skan#endif
602132718Skanstatic int rs6000_ra_ever_killed (void);
603132718Skanstatic tree rs6000_handle_longcall_attribute (tree *, tree, tree, int, bool *);
604146895Skanstatic tree rs6000_handle_altivec_attribute (tree *, tree, tree, int, bool *);
605169689Skanstatic bool rs6000_ms_bitfield_layout_p (tree);
606169689Skanstatic tree rs6000_handle_struct_attribute (tree *, tree, tree, int, bool *);
607169689Skanstatic void rs6000_eliminate_indexed_memrefs (rtx operands[2]);
608146895Skanstatic const char *rs6000_mangle_fundamental_type (tree);
609132718Skanextern const struct attribute_spec rs6000_attribute_table[];
610132718Skanstatic void rs6000_set_default_type_attributes (tree);
611132718Skanstatic void rs6000_output_function_prologue (FILE *, HOST_WIDE_INT);
612132718Skanstatic void rs6000_output_function_epilogue (FILE *, HOST_WIDE_INT);
613132718Skanstatic void rs6000_output_mi_thunk (FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT,
614132718Skan				    tree);
615132718Skanstatic rtx rs6000_emit_set_long_const (rtx, HOST_WIDE_INT, HOST_WIDE_INT);
616132718Skanstatic bool rs6000_return_in_memory (tree, tree);
617132718Skanstatic void rs6000_file_start (void);
61890075Sobrien#if TARGET_ELF
619169689Skanstatic int rs6000_elf_reloc_rw_mask (void);
620132718Skanstatic void rs6000_elf_asm_out_constructor (rtx, int);
621132718Skanstatic void rs6000_elf_asm_out_destructor (rtx, int);
622146895Skanstatic void rs6000_elf_end_indicate_exec_stack (void) ATTRIBUTE_UNUSED;
623169689Skanstatic void rs6000_elf_asm_init_sections (void);
624169689Skanstatic section *rs6000_elf_select_rtx_section (enum machine_mode, rtx,
625169689Skan					       unsigned HOST_WIDE_INT);
626132718Skanstatic void rs6000_elf_encode_section_info (tree, rtx, int)
627117395Skan     ATTRIBUTE_UNUSED;
62890075Sobrien#endif
629169689Skanstatic bool rs6000_use_blocks_for_constant_p (enum machine_mode, rtx);
630117395Skan#if TARGET_XCOFF
631169689Skanstatic void rs6000_xcoff_asm_output_anchor (rtx);
632132718Skanstatic void rs6000_xcoff_asm_globalize_label (FILE *, const char *);
633169689Skanstatic void rs6000_xcoff_asm_init_sections (void);
634169689Skanstatic int rs6000_xcoff_reloc_rw_mask (void);
635169689Skanstatic void rs6000_xcoff_asm_named_section (const char *, unsigned int, tree);
636169689Skanstatic section *rs6000_xcoff_select_section (tree, int,
637169689Skan					     unsigned HOST_WIDE_INT);
638132718Skanstatic void rs6000_xcoff_unique_section (tree, int);
639169689Skanstatic section *rs6000_xcoff_select_rtx_section
640169689Skan  (enum machine_mode, rtx, unsigned HOST_WIDE_INT);
641132718Skanstatic const char * rs6000_xcoff_strip_name_encoding (const char *);
642132718Skanstatic unsigned int rs6000_xcoff_section_type_flags (tree, const char *, int);
643132718Skanstatic void rs6000_xcoff_file_start (void);
644132718Skanstatic void rs6000_xcoff_file_end (void);
64590075Sobrien#endif
646132718Skanstatic int rs6000_variable_issue (FILE *, int, rtx, int);
647132718Skanstatic bool rs6000_rtx_costs (rtx, int, int, int *);
648132718Skanstatic int rs6000_adjust_cost (rtx, rtx, rtx, int);
649132718Skanstatic bool is_microcoded_insn (rtx);
650132718Skanstatic int is_dispatch_slot_restricted (rtx);
651132718Skanstatic bool is_cracked_insn (rtx);
652132718Skanstatic bool is_branch_slot_insn (rtx);
653132718Skanstatic int rs6000_adjust_priority (rtx, int);
654132718Skanstatic int rs6000_issue_rate (void);
655132718Skanstatic bool rs6000_is_costly_dependence (rtx, rtx, rtx, int, int);
656132718Skanstatic rtx get_next_active_insn (rtx, rtx);
657132718Skanstatic bool insn_terminates_group_p (rtx , enum group_termination);
658132718Skanstatic bool is_costly_group (rtx *, rtx);
659132718Skanstatic int force_new_group (int, FILE *, rtx *, rtx, bool *, int, int *);
660132718Skanstatic int redefine_groups (FILE *, int, rtx, rtx);
661132718Skanstatic int pad_groups (FILE *, int, rtx, rtx);
662132718Skanstatic void rs6000_sched_finish (FILE *, int);
663132718Skanstatic int rs6000_use_sched_lookahead (void);
664169689Skanstatic tree rs6000_builtin_mask_for_load (void);
66590075Sobrien
666169689Skanstatic void def_builtin (int, const char *, tree, int);
667220150Smmstatic bool rs6000_vector_alignment_reachable (tree, bool);
668132718Skanstatic void rs6000_init_builtins (void);
669132718Skanstatic rtx rs6000_expand_unop_builtin (enum insn_code, tree, rtx);
670132718Skanstatic rtx rs6000_expand_binop_builtin (enum insn_code, tree, rtx);
671132718Skanstatic rtx rs6000_expand_ternop_builtin (enum insn_code, tree, rtx);
672132718Skanstatic rtx rs6000_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
673132718Skanstatic void altivec_init_builtins (void);
674132718Skanstatic void rs6000_common_init_builtins (void);
675132718Skanstatic void rs6000_init_libfuncs (void);
676117395Skan
677132718Skanstatic void enable_mask_for_builtins (struct builtin_description *, int,
678132718Skan				      enum rs6000_builtins,
679132718Skan				      enum rs6000_builtins);
680169689Skanstatic tree build_opaque_vector_type (tree, int);
681132718Skanstatic void spe_init_builtins (void);
682132718Skanstatic rtx spe_expand_builtin (tree, rtx, bool *);
683132718Skanstatic rtx spe_expand_stv_builtin (enum insn_code, tree);
684132718Skanstatic rtx spe_expand_predicate_builtin (enum insn_code, tree, rtx);
685132718Skanstatic rtx spe_expand_evsel_builtin (enum insn_code, tree, rtx);
686132718Skanstatic int rs6000_emit_int_cmove (rtx, rtx, rtx, rtx);
687132718Skanstatic rs6000_stack_t *rs6000_stack_info (void);
688132718Skanstatic void debug_stack_info (rs6000_stack_t *);
689117395Skan
690132718Skanstatic rtx altivec_expand_builtin (tree, rtx, bool *);
691132718Skanstatic rtx altivec_expand_ld_builtin (tree, rtx, bool *);
692132718Skanstatic rtx altivec_expand_st_builtin (tree, rtx, bool *);
693132718Skanstatic rtx altivec_expand_dst_builtin (tree, rtx, bool *);
694132718Skanstatic rtx altivec_expand_abs_builtin (enum insn_code, tree, rtx);
695169689Skanstatic rtx altivec_expand_predicate_builtin (enum insn_code,
696169689Skan					     const char *, tree, rtx);
697132718Skanstatic rtx altivec_expand_lv_builtin (enum insn_code, tree, rtx);
698132718Skanstatic rtx altivec_expand_stv_builtin (enum insn_code, tree);
699169689Skanstatic rtx altivec_expand_vec_init_builtin (tree, tree, rtx);
700169689Skanstatic rtx altivec_expand_vec_set_builtin (tree);
701169689Skanstatic rtx altivec_expand_vec_ext_builtin (tree, rtx);
702169689Skanstatic int get_element_number (tree, tree);
703169689Skanstatic bool rs6000_handle_option (size_t, const char *, int);
704132718Skanstatic void rs6000_parse_tls_size_option (void);
705132718Skanstatic void rs6000_parse_yes_no_option (const char *, const char *, int *);
706132718Skanstatic int first_altivec_reg_to_save (void);
707132718Skanstatic unsigned int compute_vrsave_mask (void);
708169689Skanstatic void compute_save_world_info (rs6000_stack_t *info_ptr);
709132718Skanstatic void is_altivec_return_reg (rtx, void *);
710132718Skanstatic rtx generate_set_vrsave (rtx, rs6000_stack_t *, int);
711132718Skanint easy_vector_constant (rtx, enum machine_mode);
712169689Skanstatic bool rs6000_is_opaque_type (tree);
713132718Skanstatic rtx rs6000_dwarf_register_span (rtx);
714132718Skanstatic rtx rs6000_legitimize_tls_address (rtx, enum tls_model);
715169689Skanstatic void rs6000_output_dwarf_dtprel (FILE *, int, rtx) ATTRIBUTE_UNUSED;
716132718Skanstatic rtx rs6000_tls_get_addr (void);
717132718Skanstatic rtx rs6000_got_sym (void);
718169689Skanstatic int rs6000_tls_symbol_ref_1 (rtx *, void *);
719132718Skanstatic const char *rs6000_get_some_local_dynamic_name (void);
720132718Skanstatic int rs6000_get_some_local_dynamic_name_1 (rtx *, void *);
721132718Skanstatic rtx rs6000_complex_function_value (enum machine_mode);
722132718Skanstatic rtx rs6000_spe_function_arg (CUMULATIVE_ARGS *,
723132718Skan				    enum machine_mode, tree);
724169689Skanstatic void rs6000_darwin64_record_arg_advance_flush (CUMULATIVE_ARGS *,
725169689Skan						      HOST_WIDE_INT);
726169689Skanstatic void rs6000_darwin64_record_arg_advance_recurse (CUMULATIVE_ARGS *,
727169689Skan							tree, HOST_WIDE_INT);
728169689Skanstatic void rs6000_darwin64_record_arg_flush (CUMULATIVE_ARGS *,
729169689Skan					      HOST_WIDE_INT,
730169689Skan					      rtx[], int *);
731169689Skanstatic void rs6000_darwin64_record_arg_recurse (CUMULATIVE_ARGS *,
732169689Skan					       tree, HOST_WIDE_INT,
733169689Skan					       rtx[], int *);
734169689Skanstatic rtx rs6000_darwin64_record_arg (CUMULATIVE_ARGS *, tree, int, bool);
735146895Skanstatic rtx rs6000_mixed_function_arg (enum machine_mode, tree, int);
736132718Skanstatic void rs6000_move_block_from_reg (int regno, rtx x, int nregs);
737132718Skanstatic void setup_incoming_varargs (CUMULATIVE_ARGS *,
738132718Skan				    enum machine_mode, tree,
739132718Skan				    int *, int);
740169689Skanstatic bool rs6000_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode,
741169689Skan				      tree, bool);
742169689Skanstatic int rs6000_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,
743169689Skan				     tree, bool);
744169689Skanstatic const char *invalid_arg_for_unprototyped_fn (tree, tree, tree);
745132718Skan#if TARGET_MACHO
746132718Skanstatic void macho_branch_islands (void);
747132718Skanstatic int no_previous_def (tree function_name);
748132718Skanstatic tree get_prev_label (tree function_name);
749169689Skanstatic void rs6000_darwin_file_start (void);
750132718Skan#endif
751132718Skan
752132718Skanstatic tree rs6000_build_builtin_va_list (void);
753169689Skanstatic tree rs6000_gimplify_va_arg (tree, tree, tree *, tree *);
754169689Skanstatic bool rs6000_must_pass_in_stack (enum machine_mode, tree);
755169689Skanstatic bool rs6000_scalar_mode_supported_p (enum machine_mode);
756169689Skanstatic bool rs6000_vector_mode_supported_p (enum machine_mode);
757169689Skanstatic int get_vec_cmp_insn (enum rtx_code, enum machine_mode,
758169689Skan			     enum machine_mode);
759169689Skanstatic rtx rs6000_emit_vector_compare (enum rtx_code, rtx, rtx,
760169689Skan				       enum machine_mode);
761169689Skanstatic int get_vsel_insn (enum machine_mode);
762169689Skanstatic void rs6000_emit_vector_select (rtx, rtx, rtx, rtx);
763169689Skanstatic tree rs6000_stack_protect_fail (void);
764132718Skan
765169689Skanconst int INSN_NOT_AVAILABLE = -1;
766169689Skanstatic enum machine_mode rs6000_eh_return_filter_mode (void);
767169689Skan
768132718Skan/* Hash table stuff for keeping track of TOC entries.  */
769132718Skan
770132718Skanstruct toc_hash_struct GTY(())
771132718Skan{
772132718Skan  /* `key' will satisfy CONSTANT_P; in fact, it will satisfy
773132718Skan     ASM_OUTPUT_SPECIAL_POOL_ENTRY_P.  */
774132718Skan  rtx key;
775132718Skan  enum machine_mode key_mode;
776132718Skan  int labelno;
777132718Skan};
778132718Skan
779132718Skanstatic GTY ((param_is (struct toc_hash_struct))) htab_t toc_hash_table;
78090075Sobrien
78190075Sobrien/* Default register names.  */
78290075Sobrienchar rs6000_reg_names[][8] =
78390075Sobrien{
78490075Sobrien      "0",  "1",  "2",  "3",  "4",  "5",  "6",  "7",
78590075Sobrien      "8",  "9", "10", "11", "12", "13", "14", "15",
78690075Sobrien     "16", "17", "18", "19", "20", "21", "22", "23",
78790075Sobrien     "24", "25", "26", "27", "28", "29", "30", "31",
78890075Sobrien      "0",  "1",  "2",  "3",  "4",  "5",  "6",  "7",
78990075Sobrien      "8",  "9", "10", "11", "12", "13", "14", "15",
79090075Sobrien     "16", "17", "18", "19", "20", "21", "22", "23",
79190075Sobrien     "24", "25", "26", "27", "28", "29", "30", "31",
79290075Sobrien     "mq", "lr", "ctr","ap",
79390075Sobrien      "0",  "1",  "2",  "3",  "4",  "5",  "6",  "7",
79490075Sobrien      "xer",
79590075Sobrien      /* AltiVec registers.  */
79690075Sobrien      "0",  "1",  "2",  "3",  "4",  "5",  "6", "7",
79790075Sobrien      "8",  "9",  "10", "11", "12", "13", "14", "15",
79890075Sobrien      "16", "17", "18", "19", "20", "21", "22", "23",
79990075Sobrien      "24", "25", "26", "27", "28", "29", "30", "31",
800117395Skan      "vrsave", "vscr",
801117395Skan      /* SPE registers.  */
802169689Skan      "spe_acc", "spefscr",
803169689Skan      /* Soft frame pointer.  */
804169689Skan      "sfp"
80590075Sobrien};
80690075Sobrien
80790075Sobrien#ifdef TARGET_REGNAMES
80890075Sobrienstatic const char alt_reg_names[][8] =
80990075Sobrien{
81090075Sobrien   "%r0",   "%r1",  "%r2",  "%r3",  "%r4",  "%r5",  "%r6",  "%r7",
81190075Sobrien   "%r8",   "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15",
81290075Sobrien  "%r16",  "%r17", "%r18", "%r19", "%r20", "%r21", "%r22", "%r23",
81390075Sobrien  "%r24",  "%r25", "%r26", "%r27", "%r28", "%r29", "%r30", "%r31",
81490075Sobrien   "%f0",   "%f1",  "%f2",  "%f3",  "%f4",  "%f5",  "%f6",  "%f7",
81590075Sobrien   "%f8",   "%f9", "%f10", "%f11", "%f12", "%f13", "%f14", "%f15",
81690075Sobrien  "%f16",  "%f17", "%f18", "%f19", "%f20", "%f21", "%f22", "%f23",
81790075Sobrien  "%f24",  "%f25", "%f26", "%f27", "%f28", "%f29", "%f30", "%f31",
81890075Sobrien    "mq",    "lr",  "ctr",   "ap",
81990075Sobrien  "%cr0",  "%cr1", "%cr2", "%cr3", "%cr4", "%cr5", "%cr6", "%cr7",
82090075Sobrien   "xer",
821117395Skan  /* AltiVec registers.  */
82290075Sobrien   "%v0",  "%v1",  "%v2",  "%v3",  "%v4",  "%v5",  "%v6", "%v7",
823117395Skan   "%v8",  "%v9", "%v10", "%v11", "%v12", "%v13", "%v14", "%v15",
824117395Skan  "%v16", "%v17", "%v18", "%v19", "%v20", "%v21", "%v22", "%v23",
825117395Skan  "%v24", "%v25", "%v26", "%v27", "%v28", "%v29", "%v30", "%v31",
826117395Skan  "vrsave", "vscr",
827117395Skan  /* SPE registers.  */
828169689Skan  "spe_acc", "spefscr",
829169689Skan  /* Soft frame pointer.  */
830169689Skan  "sfp"
83190075Sobrien};
83290075Sobrien#endif
83390075Sobrien
83490075Sobrien#ifndef MASK_STRICT_ALIGN
83590075Sobrien#define MASK_STRICT_ALIGN 0
83690075Sobrien#endif
837132718Skan#ifndef TARGET_PROFILE_KERNEL
838132718Skan#define TARGET_PROFILE_KERNEL 0
839132718Skan#endif
840117395Skan
841117395Skan/* The VRSAVE bitmask puts bit %v0 as the most significant bit.  */
842117395Skan#define ALTIVEC_REG_BIT(REGNO) (0x80000000 >> ((REGNO) - FIRST_ALTIVEC_REGNO))
84390075Sobrien
84490075Sobrien/* Initialize the GCC target structure.  */
84590075Sobrien#undef TARGET_ATTRIBUTE_TABLE
84690075Sobrien#define TARGET_ATTRIBUTE_TABLE rs6000_attribute_table
847117395Skan#undef TARGET_SET_DEFAULT_TYPE_ATTRIBUTES
848117395Skan#define TARGET_SET_DEFAULT_TYPE_ATTRIBUTES rs6000_set_default_type_attributes
84990075Sobrien
85090075Sobrien#undef TARGET_ASM_ALIGNED_DI_OP
85190075Sobrien#define TARGET_ASM_ALIGNED_DI_OP DOUBLE_INT_ASM_OP
85290075Sobrien
85390075Sobrien/* Default unaligned ops are only provided for ELF.  Find the ops needed
85490075Sobrien   for non-ELF systems.  */
85590075Sobrien#ifndef OBJECT_FORMAT_ELF
856117395Skan#if TARGET_XCOFF
85790075Sobrien/* For XCOFF.  rs6000_assemble_integer will handle unaligned DIs on
85890075Sobrien   64-bit targets.  */
85990075Sobrien#undef TARGET_ASM_UNALIGNED_HI_OP
86090075Sobrien#define TARGET_ASM_UNALIGNED_HI_OP "\t.vbyte\t2,"
86190075Sobrien#undef TARGET_ASM_UNALIGNED_SI_OP
86290075Sobrien#define TARGET_ASM_UNALIGNED_SI_OP "\t.vbyte\t4,"
86390075Sobrien#undef TARGET_ASM_UNALIGNED_DI_OP
86490075Sobrien#define TARGET_ASM_UNALIGNED_DI_OP "\t.vbyte\t8,"
86590075Sobrien#else
86690075Sobrien/* For Darwin.  */
86790075Sobrien#undef TARGET_ASM_UNALIGNED_HI_OP
86890075Sobrien#define TARGET_ASM_UNALIGNED_HI_OP "\t.short\t"
86990075Sobrien#undef TARGET_ASM_UNALIGNED_SI_OP
87090075Sobrien#define TARGET_ASM_UNALIGNED_SI_OP "\t.long\t"
871169689Skan#undef TARGET_ASM_UNALIGNED_DI_OP
872169689Skan#define TARGET_ASM_UNALIGNED_DI_OP "\t.quad\t"
873169689Skan#undef TARGET_ASM_ALIGNED_DI_OP
874169689Skan#define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t"
87590075Sobrien#endif
87690075Sobrien#endif
87790075Sobrien
87890075Sobrien/* This hook deals with fixups for relocatable code and DI-mode objects
87990075Sobrien   in 64-bit code.  */
88090075Sobrien#undef TARGET_ASM_INTEGER
88190075Sobrien#define TARGET_ASM_INTEGER rs6000_assemble_integer
88290075Sobrien
883117395Skan#ifdef HAVE_GAS_HIDDEN
884117395Skan#undef TARGET_ASM_ASSEMBLE_VISIBILITY
885117395Skan#define TARGET_ASM_ASSEMBLE_VISIBILITY rs6000_assemble_visibility
886117395Skan#endif
887117395Skan
888132718Skan#undef TARGET_HAVE_TLS
889132718Skan#define TARGET_HAVE_TLS HAVE_AS_TLS
890132718Skan
891132718Skan#undef TARGET_CANNOT_FORCE_CONST_MEM
892132718Skan#define TARGET_CANNOT_FORCE_CONST_MEM rs6000_tls_referenced_p
893132718Skan
89490075Sobrien#undef TARGET_ASM_FUNCTION_PROLOGUE
89590075Sobrien#define TARGET_ASM_FUNCTION_PROLOGUE rs6000_output_function_prologue
89690075Sobrien#undef TARGET_ASM_FUNCTION_EPILOGUE
89790075Sobrien#define TARGET_ASM_FUNCTION_EPILOGUE rs6000_output_function_epilogue
89890075Sobrien
899132718Skan#undef  TARGET_SCHED_VARIABLE_ISSUE
900132718Skan#define TARGET_SCHED_VARIABLE_ISSUE rs6000_variable_issue
901132718Skan
90290075Sobrien#undef TARGET_SCHED_ISSUE_RATE
90390075Sobrien#define TARGET_SCHED_ISSUE_RATE rs6000_issue_rate
90490075Sobrien#undef TARGET_SCHED_ADJUST_COST
90590075Sobrien#define TARGET_SCHED_ADJUST_COST rs6000_adjust_cost
90690075Sobrien#undef TARGET_SCHED_ADJUST_PRIORITY
90790075Sobrien#define TARGET_SCHED_ADJUST_PRIORITY rs6000_adjust_priority
908169689Skan#undef TARGET_SCHED_IS_COSTLY_DEPENDENCE
909132718Skan#define TARGET_SCHED_IS_COSTLY_DEPENDENCE rs6000_is_costly_dependence
910132718Skan#undef TARGET_SCHED_FINISH
911132718Skan#define TARGET_SCHED_FINISH rs6000_sched_finish
91290075Sobrien
913132718Skan#undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD
914132718Skan#define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD rs6000_use_sched_lookahead
915132718Skan
916169689Skan#undef TARGET_VECTORIZE_BUILTIN_MASK_FOR_LOAD
917169689Skan#define TARGET_VECTORIZE_BUILTIN_MASK_FOR_LOAD rs6000_builtin_mask_for_load
918169689Skan
919220150Smm#undef TARGET_VECTOR_ALIGNMENT_REACHABLE
920220150Smm#define TARGET_VECTOR_ALIGNMENT_REACHABLE rs6000_vector_alignment_reachable
921220150Smm
92290075Sobrien#undef TARGET_INIT_BUILTINS
92390075Sobrien#define TARGET_INIT_BUILTINS rs6000_init_builtins
92490075Sobrien
92590075Sobrien#undef TARGET_EXPAND_BUILTIN
92690075Sobrien#define TARGET_EXPAND_BUILTIN rs6000_expand_builtin
92790075Sobrien
928146895Skan#undef TARGET_MANGLE_FUNDAMENTAL_TYPE
929146895Skan#define TARGET_MANGLE_FUNDAMENTAL_TYPE rs6000_mangle_fundamental_type
930146895Skan
931132718Skan#undef TARGET_INIT_LIBFUNCS
932132718Skan#define TARGET_INIT_LIBFUNCS rs6000_init_libfuncs
933132718Skan
934132718Skan#if TARGET_MACHO
935117395Skan#undef TARGET_BINDS_LOCAL_P
936169689Skan#define TARGET_BINDS_LOCAL_P darwin_binds_local_p
937132718Skan#endif
93890075Sobrien
939169689Skan#undef TARGET_MS_BITFIELD_LAYOUT_P
940169689Skan#define TARGET_MS_BITFIELD_LAYOUT_P rs6000_ms_bitfield_layout_p
941169689Skan
942117395Skan#undef TARGET_ASM_OUTPUT_MI_THUNK
943117395Skan#define TARGET_ASM_OUTPUT_MI_THUNK rs6000_output_mi_thunk
944117395Skan
945117395Skan#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
946132718Skan#define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_tree_hwi_hwi_tree_true
947117395Skan
948132718Skan#undef TARGET_FUNCTION_OK_FOR_SIBCALL
949132718Skan#define TARGET_FUNCTION_OK_FOR_SIBCALL rs6000_function_ok_for_sibcall
950132718Skan
951169689Skan#undef TARGET_INVALID_WITHIN_DOLOOP
952169689Skan#define TARGET_INVALID_WITHIN_DOLOOP rs6000_invalid_within_doloop
953169689Skan
954132718Skan#undef TARGET_RTX_COSTS
955132718Skan#define TARGET_RTX_COSTS rs6000_rtx_costs
956132718Skan#undef TARGET_ADDRESS_COST
957132718Skan#define TARGET_ADDRESS_COST hook_int_rtx_0
958132718Skan
959132718Skan#undef TARGET_VECTOR_OPAQUE_P
960169689Skan#define TARGET_VECTOR_OPAQUE_P rs6000_is_opaque_type
961132718Skan
962132718Skan#undef TARGET_DWARF_REGISTER_SPAN
963132718Skan#define TARGET_DWARF_REGISTER_SPAN rs6000_dwarf_register_span
964132718Skan
965132718Skan/* On rs6000, function arguments are promoted, as are function return
966132718Skan   values.  */
967132718Skan#undef TARGET_PROMOTE_FUNCTION_ARGS
968132718Skan#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true
969132718Skan#undef TARGET_PROMOTE_FUNCTION_RETURN
970132718Skan#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
971132718Skan
972132718Skan#undef TARGET_RETURN_IN_MEMORY
973132718Skan#define TARGET_RETURN_IN_MEMORY rs6000_return_in_memory
974132718Skan
975132718Skan#undef TARGET_SETUP_INCOMING_VARARGS
976132718Skan#define TARGET_SETUP_INCOMING_VARARGS setup_incoming_varargs
977132718Skan
978132718Skan/* Always strict argument naming on rs6000.  */
979132718Skan#undef TARGET_STRICT_ARGUMENT_NAMING
980132718Skan#define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true
981132718Skan#undef TARGET_PRETEND_OUTGOING_VARARGS_NAMED
982132718Skan#define TARGET_PRETEND_OUTGOING_VARARGS_NAMED hook_bool_CUMULATIVE_ARGS_true
983132718Skan#undef TARGET_SPLIT_COMPLEX_ARG
984132718Skan#define TARGET_SPLIT_COMPLEX_ARG hook_bool_tree_true
985169689Skan#undef TARGET_MUST_PASS_IN_STACK
986169689Skan#define TARGET_MUST_PASS_IN_STACK rs6000_must_pass_in_stack
987169689Skan#undef TARGET_PASS_BY_REFERENCE
988169689Skan#define TARGET_PASS_BY_REFERENCE rs6000_pass_by_reference
989169689Skan#undef TARGET_ARG_PARTIAL_BYTES
990169689Skan#define TARGET_ARG_PARTIAL_BYTES rs6000_arg_partial_bytes
991132718Skan
992132718Skan#undef TARGET_BUILD_BUILTIN_VA_LIST
993132718Skan#define TARGET_BUILD_BUILTIN_VA_LIST rs6000_build_builtin_va_list
994132718Skan
995169689Skan#undef TARGET_GIMPLIFY_VA_ARG_EXPR
996169689Skan#define TARGET_GIMPLIFY_VA_ARG_EXPR rs6000_gimplify_va_arg
997169689Skan
998169689Skan#undef TARGET_EH_RETURN_FILTER_MODE
999169689Skan#define TARGET_EH_RETURN_FILTER_MODE rs6000_eh_return_filter_mode
1000169689Skan
1001169689Skan#undef TARGET_SCALAR_MODE_SUPPORTED_P
1002169689Skan#define TARGET_SCALAR_MODE_SUPPORTED_P rs6000_scalar_mode_supported_p
1003169689Skan
1004169689Skan#undef TARGET_VECTOR_MODE_SUPPORTED_P
1005169689Skan#define TARGET_VECTOR_MODE_SUPPORTED_P rs6000_vector_mode_supported_p
1006169689Skan
1007169689Skan#undef TARGET_INVALID_ARG_FOR_UNPROTOTYPED_FN
1008169689Skan#define TARGET_INVALID_ARG_FOR_UNPROTOTYPED_FN invalid_arg_for_unprototyped_fn
1009169689Skan
1010169689Skan#undef TARGET_HANDLE_OPTION
1011169689Skan#define TARGET_HANDLE_OPTION rs6000_handle_option
1012169689Skan
1013169689Skan#undef TARGET_DEFAULT_TARGET_FLAGS
1014169689Skan#define TARGET_DEFAULT_TARGET_FLAGS \
1015169689Skan  (TARGET_DEFAULT)
1016169689Skan
1017169689Skan#undef TARGET_STACK_PROTECT_FAIL
1018169689Skan#define TARGET_STACK_PROTECT_FAIL rs6000_stack_protect_fail
1019169689Skan
1020169689Skan/* MPC604EUM 3.5.2 Weak Consistency between Multiple Processors
1021169689Skan   The PowerPC architecture requires only weak consistency among
1022169689Skan   processors--that is, memory accesses between processors need not be
1023169689Skan   sequentially consistent and memory accesses among processors can occur
1024169689Skan   in any order. The ability to order memory accesses weakly provides
1025169689Skan   opportunities for more efficient use of the system bus. Unless a
1026169689Skan   dependency exists, the 604e allows read operations to precede store
1027169689Skan   operations.  */
1028169689Skan#undef TARGET_RELAXED_ORDERING
1029169689Skan#define TARGET_RELAXED_ORDERING true
1030169689Skan
1031169689Skan#ifdef HAVE_AS_TLS
1032169689Skan#undef TARGET_ASM_OUTPUT_DWARF_DTPREL
1033169689Skan#define TARGET_ASM_OUTPUT_DWARF_DTPREL rs6000_output_dwarf_dtprel
1034169689Skan#endif
1035169689Skan
1036169689Skan/* Use a 32-bit anchor range.  This leads to sequences like:
1037169689Skan
1038169689Skan	addis	tmp,anchor,high
1039169689Skan	add	dest,tmp,low
1040169689Skan
1041169689Skan   where tmp itself acts as an anchor, and can be shared between
1042169689Skan   accesses to the same 64k page.  */
1043169689Skan#undef TARGET_MIN_ANCHOR_OFFSET
1044169689Skan#define TARGET_MIN_ANCHOR_OFFSET -0x7fffffff - 1
1045169689Skan#undef TARGET_MAX_ANCHOR_OFFSET
1046169689Skan#define TARGET_MAX_ANCHOR_OFFSET 0x7fffffff
1047169689Skan#undef TARGET_USE_BLOCKS_FOR_CONSTANT_P
1048169689Skan#define TARGET_USE_BLOCKS_FOR_CONSTANT_P rs6000_use_blocks_for_constant_p
1049169689Skan
105090075Sobrienstruct gcc_target targetm = TARGET_INITIALIZER;
105190075Sobrien
1052169689Skan
1053169689Skan/* Value is 1 if hard register REGNO can hold a value of machine-mode
1054169689Skan   MODE.  */
1055169689Skanstatic int
1056169689Skanrs6000_hard_regno_mode_ok (int regno, enum machine_mode mode)
1057169689Skan{
1058169689Skan  /* The GPRs can hold any mode, but values bigger than one register
1059169689Skan     cannot go past R31.  */
1060169689Skan  if (INT_REGNO_P (regno))
1061169689Skan    return INT_REGNO_P (regno + HARD_REGNO_NREGS (regno, mode) - 1);
1062169689Skan
1063169689Skan  /* The float registers can only hold floating modes and DImode.
1064169689Skan     This also excludes decimal float modes.  */
1065169689Skan  if (FP_REGNO_P (regno))
1066169689Skan    return
1067169689Skan      (SCALAR_FLOAT_MODE_P (mode)
1068169689Skan       && !DECIMAL_FLOAT_MODE_P (mode)
1069169689Skan       && FP_REGNO_P (regno + HARD_REGNO_NREGS (regno, mode) - 1))
1070169689Skan      || (GET_MODE_CLASS (mode) == MODE_INT
1071169689Skan	  && GET_MODE_SIZE (mode) == UNITS_PER_FP_WORD);
1072169689Skan
1073169689Skan  /* The CR register can only hold CC modes.  */
1074169689Skan  if (CR_REGNO_P (regno))
1075169689Skan    return GET_MODE_CLASS (mode) == MODE_CC;
1076169689Skan
1077169689Skan  if (XER_REGNO_P (regno))
1078169689Skan    return mode == PSImode;
1079169689Skan
1080169689Skan  /* AltiVec only in AldyVec registers.  */
1081169689Skan  if (ALTIVEC_REGNO_P (regno))
1082169689Skan    return ALTIVEC_VECTOR_MODE (mode);
1083169689Skan
1084169689Skan  /* ...but GPRs can hold SIMD data on the SPE in one register.  */
1085169689Skan  if (SPE_SIMD_REGNO_P (regno) && TARGET_SPE && SPE_VECTOR_MODE (mode))
1086169689Skan    return 1;
1087169689Skan
1088169689Skan  /* We cannot put TImode anywhere except general register and it must be
1089169689Skan     able to fit within the register set.  */
1090169689Skan
1091169689Skan  return GET_MODE_SIZE (mode) <= UNITS_PER_WORD;
1092169689Skan}
1093169689Skan
1094169689Skan/* Initialize rs6000_hard_regno_mode_ok_p table.  */
1095169689Skanstatic void
1096169689Skanrs6000_init_hard_regno_mode_ok (void)
1097169689Skan{
1098169689Skan  int r, m;
1099169689Skan
1100169689Skan  for (r = 0; r < FIRST_PSEUDO_REGISTER; ++r)
1101169689Skan    for (m = 0; m < NUM_MACHINE_MODES; ++m)
1102169689Skan      if (rs6000_hard_regno_mode_ok (r, m))
1103169689Skan	rs6000_hard_regno_mode_ok_p[m][r] = true;
1104169689Skan}
1105169689Skan
1106169689Skan/* If not otherwise specified by a target, make 'long double' equivalent to
1107169689Skan   'double'.  */
1108169689Skan
1109169689Skan#ifndef RS6000_DEFAULT_LONG_DOUBLE_SIZE
1110169689Skan#define RS6000_DEFAULT_LONG_DOUBLE_SIZE 64
1111169689Skan#endif
1112169689Skan
111390075Sobrien/* Override command line options.  Mostly we process the processor
111490075Sobrien   type and sometimes adjust other TARGET_ options.  */
111590075Sobrien
111690075Sobrienvoid
1117132718Skanrs6000_override_options (const char *default_cpu)
111890075Sobrien{
111990075Sobrien  size_t i, j;
112090075Sobrien  struct rs6000_cpu_select *ptr;
1121132718Skan  int set_masks;
112290075Sobrien
1123132718Skan  /* Simplifications for entries below.  */
112490075Sobrien
1125132718Skan  enum {
1126132718Skan    POWERPC_BASE_MASK = MASK_POWERPC | MASK_NEW_MNEMONICS,
1127132718Skan    POWERPC_7400_MASK = POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_ALTIVEC
1128132718Skan  };
112990075Sobrien
1130132718Skan  /* This table occasionally claims that a processor does not support
1131132718Skan     a particular feature even though it does, but the feature is slower
1132132718Skan     than the alternative.  Thus, it shouldn't be relied on as a
1133169689Skan     complete description of the processor's support.
1134132718Skan
1135132718Skan     Please keep this list in order, and don't forget to update the
1136132718Skan     documentation in invoke.texi when adding a new processor or
1137132718Skan     flag.  */
113890075Sobrien  static struct ptt
113990075Sobrien    {
114090075Sobrien      const char *const name;		/* Canonical processor name.  */
114190075Sobrien      const enum processor_type processor; /* Processor type enum value.  */
114290075Sobrien      const int target_enable;	/* Target flags to enable.  */
114390075Sobrien    } const processor_target_table[]
1144132718Skan      = {{"401", PROCESSOR_PPC403, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
1145132718Skan	 {"403", PROCESSOR_PPC403,
1146132718Skan	  POWERPC_BASE_MASK | MASK_SOFT_FLOAT | MASK_STRICT_ALIGN},
1147169689Skan	 {"405", PROCESSOR_PPC405,
1148169689Skan	  POWERPC_BASE_MASK | MASK_SOFT_FLOAT | MASK_MULHW | MASK_DLMZB},
1149169689Skan	 {"405fp", PROCESSOR_PPC405,
1150169689Skan	  POWERPC_BASE_MASK | MASK_MULHW | MASK_DLMZB},
1151169689Skan	 {"440", PROCESSOR_PPC440,
1152169689Skan	  POWERPC_BASE_MASK | MASK_SOFT_FLOAT | MASK_MULHW | MASK_DLMZB},
1153169689Skan	 {"440fp", PROCESSOR_PPC440,
1154169689Skan	  POWERPC_BASE_MASK | MASK_MULHW | MASK_DLMZB},
1155132718Skan	 {"505", PROCESSOR_MPCCORE, POWERPC_BASE_MASK},
1156132718Skan	 {"601", PROCESSOR_PPC601,
1157132718Skan	  MASK_POWER | POWERPC_BASE_MASK | MASK_MULTIPLE | MASK_STRING},
1158132718Skan	 {"602", PROCESSOR_PPC603, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
1159132718Skan	 {"603", PROCESSOR_PPC603, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
1160132718Skan	 {"603e", PROCESSOR_PPC603, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
1161132718Skan	 {"604", PROCESSOR_PPC604, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
1162132718Skan	 {"604e", PROCESSOR_PPC604e, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
1163132718Skan	 {"620", PROCESSOR_PPC620,
1164132718Skan	  POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64},
1165132718Skan	 {"630", PROCESSOR_PPC630,
1166132718Skan	  POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64},
1167132718Skan	 {"740", PROCESSOR_PPC750, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
1168132718Skan	 {"7400", PROCESSOR_PPC7400, POWERPC_7400_MASK},
1169132718Skan	 {"7450", PROCESSOR_PPC7450, POWERPC_7400_MASK},
1170132718Skan	 {"750", PROCESSOR_PPC750, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
1171132718Skan	 {"801", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
1172132718Skan	 {"821", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
1173132718Skan	 {"823", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
1174259268Spfg	 {"8540", PROCESSOR_PPC8540, POWERPC_BASE_MASK | MASK_STRICT_ALIGN},
1175169689Skan	 /* 8548 has a dummy entry for now.  */
1176259268Spfg	 {"8548", PROCESSOR_PPC8540, POWERPC_BASE_MASK | MASK_STRICT_ALIGN},
1177132718Skan	 {"860", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
1178132718Skan	 {"970", PROCESSOR_POWER4,
1179132718Skan	  POWERPC_7400_MASK | MASK_PPC_GPOPT | MASK_MFCRF | MASK_POWERPC64},
1180132718Skan	 {"common", PROCESSOR_COMMON, MASK_NEW_MNEMONICS},
1181132718Skan	 {"ec603e", PROCESSOR_PPC603, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
1182132718Skan	 {"G3", PROCESSOR_PPC750, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
1183132718Skan	 {"G4",  PROCESSOR_PPC7450, POWERPC_7400_MASK},
1184132718Skan	 {"G5", PROCESSOR_POWER4,
1185132718Skan	  POWERPC_7400_MASK | MASK_PPC_GPOPT | MASK_MFCRF | MASK_POWERPC64},
1186132718Skan	 {"power", PROCESSOR_POWER, MASK_POWER | MASK_MULTIPLE | MASK_STRING},
118790075Sobrien	 {"power2", PROCESSOR_POWER,
1188132718Skan	  MASK_POWER | MASK_POWER2 | MASK_MULTIPLE | MASK_STRING},
118990075Sobrien	 {"power3", PROCESSOR_PPC630,
1190132718Skan	  POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64},
1191117395Skan	 {"power4", PROCESSOR_POWER4,
1192132718Skan	  POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_MFCRF | MASK_POWERPC64},
1193132718Skan	 {"power5", PROCESSOR_POWER5,
1194169689Skan	  POWERPC_BASE_MASK | MASK_POWERPC64 | MASK_PPC_GFXOPT
1195169689Skan	  | MASK_MFCRF | MASK_POPCNTB},
1196169689Skan	 {"power5+", PROCESSOR_POWER5,
1197169689Skan	  POWERPC_BASE_MASK | MASK_POWERPC64 | MASK_PPC_GFXOPT
1198169689Skan	  | MASK_MFCRF | MASK_POPCNTB | MASK_FPRND},
1199169689Skan 	 {"power6", PROCESSOR_POWER5,
1200169689Skan	  POWERPC_7400_MASK | MASK_POWERPC64 | MASK_MFCRF | MASK_POPCNTB
1201169689Skan	  | MASK_FPRND},
1202132718Skan	 {"powerpc", PROCESSOR_POWERPC, POWERPC_BASE_MASK},
120390075Sobrien	 {"powerpc64", PROCESSOR_POWERPC64,
1204169689Skan	  POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64},
1205132718Skan	 {"rios", PROCESSOR_RIOS1, MASK_POWER | MASK_MULTIPLE | MASK_STRING},
1206132718Skan	 {"rios1", PROCESSOR_RIOS1, MASK_POWER | MASK_MULTIPLE | MASK_STRING},
120790075Sobrien	 {"rios2", PROCESSOR_RIOS2,
1208132718Skan	  MASK_POWER | MASK_POWER2 | MASK_MULTIPLE | MASK_STRING},
1209132718Skan	 {"rsc", PROCESSOR_PPC601, MASK_POWER | MASK_MULTIPLE | MASK_STRING},
1210132718Skan	 {"rsc1", PROCESSOR_PPC601, MASK_POWER | MASK_MULTIPLE | MASK_STRING},
1211169689Skan	 {"rs64", PROCESSOR_RS64A,
1212169689Skan	  POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64}
1213132718Skan      };
121490075Sobrien
1215117395Skan  const size_t ptt_size = ARRAY_SIZE (processor_target_table);
121690075Sobrien
1217132718Skan  /* Some OSs don't support saving the high part of 64-bit registers on
1218132718Skan     context switch.  Other OSs don't support saving Altivec registers.
1219132718Skan     On those OSs, we don't touch the MASK_POWERPC64 or MASK_ALTIVEC
1220132718Skan     settings; if the user wants either, the user must explicitly specify
1221132718Skan     them and we won't interfere with the user's specification.  */
122290075Sobrien
1223132718Skan  enum {
1224132718Skan    POWER_MASKS = MASK_POWER | MASK_POWER2 | MASK_MULTIPLE | MASK_STRING,
1225169689Skan    POWERPC_MASKS = (POWERPC_BASE_MASK | MASK_PPC_GPOPT | MASK_STRICT_ALIGN
1226132718Skan		     | MASK_PPC_GFXOPT | MASK_POWERPC64 | MASK_ALTIVEC
1227169689Skan		     | MASK_MFCRF | MASK_POPCNTB | MASK_FPRND | MASK_MULHW
1228169689Skan		     | MASK_DLMZB)
1229132718Skan  };
1230169689Skan
1231169689Skan  rs6000_init_hard_regno_mode_ok ();
1232169689Skan
1233169689Skan  set_masks = POWER_MASKS | POWERPC_MASKS | MASK_SOFT_FLOAT;
1234132718Skan#ifdef OS_MISSING_POWERPC64
1235132718Skan  if (OS_MISSING_POWERPC64)
1236132718Skan    set_masks &= ~MASK_POWERPC64;
1237132718Skan#endif
1238132718Skan#ifdef OS_MISSING_ALTIVEC
1239132718Skan  if (OS_MISSING_ALTIVEC)
1240132718Skan    set_masks &= ~MASK_ALTIVEC;
1241132718Skan#endif
1242132718Skan
1243146895Skan  /* Don't override by the processor default if given explicitly.  */
1244146895Skan  set_masks &= ~target_flags_explicit;
1245132718Skan
124690075Sobrien  /* Identify the processor type.  */
124790075Sobrien  rs6000_select[0].string = default_cpu;
124890075Sobrien  rs6000_cpu = TARGET_POWERPC64 ? PROCESSOR_DEFAULT64 : PROCESSOR_DEFAULT;
124990075Sobrien
125090075Sobrien  for (i = 0; i < ARRAY_SIZE (rs6000_select); i++)
125190075Sobrien    {
125290075Sobrien      ptr = &rs6000_select[i];
125390075Sobrien      if (ptr->string != (char *)0 && ptr->string[0] != '\0')
125490075Sobrien	{
125590075Sobrien	  for (j = 0; j < ptt_size; j++)
125690075Sobrien	    if (! strcmp (ptr->string, processor_target_table[j].name))
125790075Sobrien	      {
125890075Sobrien		if (ptr->set_tune_p)
125990075Sobrien		  rs6000_cpu = processor_target_table[j].processor;
126090075Sobrien
126190075Sobrien		if (ptr->set_arch_p)
126290075Sobrien		  {
1263132718Skan		    target_flags &= ~set_masks;
1264132718Skan		    target_flags |= (processor_target_table[j].target_enable
1265132718Skan				     & set_masks);
126690075Sobrien		  }
126790075Sobrien		break;
126890075Sobrien	      }
126990075Sobrien
127090075Sobrien	  if (j == ptt_size)
127190075Sobrien	    error ("bad value (%s) for %s switch", ptr->string, ptr->name);
127290075Sobrien	}
127390075Sobrien    }
127490075Sobrien
1275132718Skan  if (TARGET_E500)
1276117395Skan    rs6000_isel = 1;
1277117395Skan
1278117395Skan  /* If we are optimizing big endian systems for space, use the load/store
1279117395Skan     multiple and string instructions.  */
128090075Sobrien  if (BYTES_BIG_ENDIAN && optimize_size)
1281132718Skan    target_flags |= ~target_flags_explicit & (MASK_MULTIPLE | MASK_STRING);
128290075Sobrien
128390075Sobrien  /* Don't allow -mmultiple or -mstring on little endian systems
128490075Sobrien     unless the cpu is a 750, because the hardware doesn't support the
128590075Sobrien     instructions used in little endian mode, and causes an alignment
128690075Sobrien     trap.  The 750 does not cause an alignment trap (except when the
128790075Sobrien     target is unaligned).  */
128890075Sobrien
1289132718Skan  if (!BYTES_BIG_ENDIAN && rs6000_cpu != PROCESSOR_PPC750)
129090075Sobrien    {
129190075Sobrien      if (TARGET_MULTIPLE)
129290075Sobrien	{
129390075Sobrien	  target_flags &= ~MASK_MULTIPLE;
1294132718Skan	  if ((target_flags_explicit & MASK_MULTIPLE) != 0)
1295169689Skan	    warning (0, "-mmultiple is not supported on little endian systems");
129690075Sobrien	}
129790075Sobrien
129890075Sobrien      if (TARGET_STRING)
129990075Sobrien	{
130090075Sobrien	  target_flags &= ~MASK_STRING;
1301132718Skan	  if ((target_flags_explicit & MASK_STRING) != 0)
1302169689Skan	    warning (0, "-mstring is not supported on little endian systems");
130390075Sobrien	}
130490075Sobrien    }
130590075Sobrien
130690075Sobrien  /* Set debug flags */
130790075Sobrien  if (rs6000_debug_name)
130890075Sobrien    {
130990075Sobrien      if (! strcmp (rs6000_debug_name, "all"))
131090075Sobrien	rs6000_debug_stack = rs6000_debug_arg = 1;
131190075Sobrien      else if (! strcmp (rs6000_debug_name, "stack"))
131290075Sobrien	rs6000_debug_stack = 1;
131390075Sobrien      else if (! strcmp (rs6000_debug_name, "arg"))
131490075Sobrien	rs6000_debug_arg = 1;
131590075Sobrien      else
131690075Sobrien	error ("unknown -mdebug-%s switch", rs6000_debug_name);
131790075Sobrien    }
131890075Sobrien
1319117395Skan  if (rs6000_traceback_name)
1320117395Skan    {
1321117395Skan      if (! strncmp (rs6000_traceback_name, "full", 4))
1322117395Skan	rs6000_traceback = traceback_full;
1323117395Skan      else if (! strncmp (rs6000_traceback_name, "part", 4))
1324117395Skan	rs6000_traceback = traceback_part;
1325117395Skan      else if (! strncmp (rs6000_traceback_name, "no", 2))
1326117395Skan	rs6000_traceback = traceback_none;
1327117395Skan      else
1328169689Skan	error ("unknown -mtraceback arg %qs; expecting %<full%>, %<partial%> or %<none%>",
1329117395Skan	       rs6000_traceback_name);
1330117395Skan    }
1331117395Skan
1332169689Skan  if (!rs6000_explicit_options.long_double)
1333169689Skan    rs6000_long_double_type_size = RS6000_DEFAULT_LONG_DOUBLE_SIZE;
133490075Sobrien
1335169689Skan#ifndef POWERPC_LINUX
1336169689Skan  if (!rs6000_explicit_options.ieee)
1337169689Skan    rs6000_ieeequad = 1;
1338169689Skan#endif
1339169689Skan
1340132718Skan  /* Set Altivec ABI as default for powerpc64 linux.  */
1341132718Skan  if (TARGET_ELF && TARGET_64BIT)
1342132718Skan    {
1343132718Skan      rs6000_altivec_abi = 1;
1344169689Skan      TARGET_ALTIVEC_VRSAVE = 1;
1345132718Skan    }
1346132718Skan
1347169689Skan  /* Set the Darwin64 ABI as default for 64-bit Darwin.  */
1348169689Skan  if (DEFAULT_ABI == ABI_DARWIN && TARGET_64BIT)
1349169689Skan    {
1350169689Skan      rs6000_darwin64_abi = 1;
1351169689Skan#if TARGET_MACHO
1352169689Skan      darwin_one_byte_bool = 1;
1353169689Skan#endif
1354169689Skan      /* Default to natural alignment, for better performance.  */
1355169689Skan      rs6000_alignment_flags = MASK_ALIGN_NATURAL;
1356169689Skan    }
135790075Sobrien
1358169689Skan  /* Place FP constants in the constant pool instead of TOC
1359169689Skan     if section anchors enabled.  */
1360169689Skan  if (flag_section_anchors)
1361169689Skan    TARGET_NO_FP_IN_TOC = 1;
136290075Sobrien
1363132718Skan  /* Handle -mtls-size option.  */
1364132718Skan  rs6000_parse_tls_size_option ();
1365132718Skan
136690075Sobrien#ifdef SUBTARGET_OVERRIDE_OPTIONS
136790075Sobrien  SUBTARGET_OVERRIDE_OPTIONS;
136890075Sobrien#endif
136990075Sobrien#ifdef SUBSUBTARGET_OVERRIDE_OPTIONS
137090075Sobrien  SUBSUBTARGET_OVERRIDE_OPTIONS;
137190075Sobrien#endif
1372169689Skan#ifdef SUB3TARGET_OVERRIDE_OPTIONS
1373169689Skan  SUB3TARGET_OVERRIDE_OPTIONS;
1374169689Skan#endif
137590075Sobrien
1376132718Skan  if (TARGET_E500)
1377132718Skan    {
1378132718Skan      if (TARGET_ALTIVEC)
1379169689Skan	error ("AltiVec and E500 instructions cannot coexist");
1380132718Skan
1381132718Skan      /* The e500 does not have string instructions, and we set
1382132718Skan	 MASK_STRING above when optimizing for size.  */
1383132718Skan      if ((target_flags & MASK_STRING) != 0)
1384132718Skan	target_flags = target_flags & ~MASK_STRING;
1385132718Skan    }
1386132718Skan  else if (rs6000_select[1].string != NULL)
1387132718Skan    {
1388132718Skan      /* For the powerpc-eabispe configuration, we set all these by
1389132718Skan	 default, so let's unset them if we manually set another
1390132718Skan	 CPU that is not the E500.  */
1391169689Skan      if (!rs6000_explicit_options.abi)
1392132718Skan	rs6000_spe_abi = 0;
1393169689Skan      if (!rs6000_explicit_options.spe)
1394132718Skan	rs6000_spe = 0;
1395169689Skan      if (!rs6000_explicit_options.float_gprs)
1396132718Skan	rs6000_float_gprs = 0;
1397169689Skan      if (!rs6000_explicit_options.isel)
1398132718Skan	rs6000_isel = 0;
1399169689Skan      if (!rs6000_explicit_options.long_double)
1400169689Skan	rs6000_long_double_type_size = RS6000_DEFAULT_LONG_DOUBLE_SIZE;
1401132718Skan    }
1402132718Skan
1403132718Skan  rs6000_always_hint = (rs6000_cpu != PROCESSOR_POWER4
1404132718Skan			&& rs6000_cpu != PROCESSOR_POWER5);
1405132718Skan  rs6000_sched_groups = (rs6000_cpu == PROCESSOR_POWER4
1406132718Skan			 || rs6000_cpu == PROCESSOR_POWER5);
1407132718Skan
1408132718Skan  rs6000_sched_restricted_insns_priority
1409132718Skan    = (rs6000_sched_groups ? 1 : 0);
1410132718Skan
1411132718Skan  /* Handle -msched-costly-dep option.  */
1412132718Skan  rs6000_sched_costly_dep
1413132718Skan    = (rs6000_sched_groups ? store_to_load_dep_costly : no_dep_costly);
1414169689Skan
1415132718Skan  if (rs6000_sched_costly_dep_str)
1416132718Skan    {
1417169689Skan      if (! strcmp (rs6000_sched_costly_dep_str, "no"))
1418169689Skan	rs6000_sched_costly_dep = no_dep_costly;
1419132718Skan      else if (! strcmp (rs6000_sched_costly_dep_str, "all"))
1420169689Skan	rs6000_sched_costly_dep = all_deps_costly;
1421132718Skan      else if (! strcmp (rs6000_sched_costly_dep_str, "true_store_to_load"))
1422169689Skan	rs6000_sched_costly_dep = true_store_to_load_dep_costly;
1423132718Skan      else if (! strcmp (rs6000_sched_costly_dep_str, "store_to_load"))
1424169689Skan	rs6000_sched_costly_dep = store_to_load_dep_costly;
1425169689Skan      else
1426169689Skan	rs6000_sched_costly_dep = atoi (rs6000_sched_costly_dep_str);
1427132718Skan    }
1428132718Skan
1429132718Skan  /* Handle -minsert-sched-nops option.  */
1430132718Skan  rs6000_sched_insert_nops
1431132718Skan    = (rs6000_sched_groups ? sched_finish_regroup_exact : sched_finish_none);
1432169689Skan
1433132718Skan  if (rs6000_sched_insert_nops_str)
1434132718Skan    {
1435132718Skan      if (! strcmp (rs6000_sched_insert_nops_str, "no"))
1436169689Skan	rs6000_sched_insert_nops = sched_finish_none;
1437132718Skan      else if (! strcmp (rs6000_sched_insert_nops_str, "pad"))
1438169689Skan	rs6000_sched_insert_nops = sched_finish_pad_groups;
1439132718Skan      else if (! strcmp (rs6000_sched_insert_nops_str, "regroup_exact"))
1440169689Skan	rs6000_sched_insert_nops = sched_finish_regroup_exact;
1441132718Skan      else
1442169689Skan	rs6000_sched_insert_nops = atoi (rs6000_sched_insert_nops_str);
1443132718Skan    }
1444132718Skan
1445117395Skan#ifdef TARGET_REGNAMES
1446117395Skan  /* If the user desires alternate register names, copy in the
1447117395Skan     alternate names now.  */
1448117395Skan  if (TARGET_REGNAMES)
1449117395Skan    memcpy (rs6000_reg_names, alt_reg_names, sizeof (rs6000_reg_names));
1450117395Skan#endif
1451117395Skan
1452169689Skan  /* Set aix_struct_return last, after the ABI is determined.
145390075Sobrien     If -maix-struct-return or -msvr4-struct-return was explicitly
145490075Sobrien     used, don't override with the ABI default.  */
1455169689Skan  if (!rs6000_explicit_options.aix_struct_ret)
1456169689Skan    aix_struct_return = (DEFAULT_ABI != ABI_V4 || DRAFT_V4_STRUCT_RET);
145790075Sobrien
1458169689Skan  if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
1459132718Skan    REAL_MODE_FORMAT (TFmode) = &ibm_extended_format;
1460117395Skan
1461169689Skan  if (TARGET_TOC)
146290075Sobrien    ASM_GENERATE_INTERNAL_LABEL (toc_label_name, "LCTOC", 1);
146390075Sobrien
146490075Sobrien  /* We can only guarantee the availability of DI pseudo-ops when
146590075Sobrien     assembling for 64-bit targets.  */
146690075Sobrien  if (!TARGET_64BIT)
146790075Sobrien    {
146890075Sobrien      targetm.asm_out.aligned_op.di = NULL;
146990075Sobrien      targetm.asm_out.unaligned_op.di = NULL;
147090075Sobrien    }
147190075Sobrien
1472169689Skan  /* Set branch target alignment, if not optimizing for size.  */
1473169689Skan  if (!optimize_size)
1474169689Skan    {
1475169689Skan      if (rs6000_sched_groups)
1476169689Skan	{
1477169689Skan	  if (align_functions <= 0)
1478169689Skan	    align_functions = 16;
1479169689Skan	  if (align_jumps <= 0)
1480169689Skan	    align_jumps = 16;
1481169689Skan	  if (align_loops <= 0)
1482169689Skan	    align_loops = 16;
1483169689Skan	}
1484169689Skan      if (align_jumps_max_skip <= 0)
1485169689Skan	align_jumps_max_skip = 15;
1486169689Skan      if (align_loops_max_skip <= 0)
1487169689Skan	align_loops_max_skip = 15;
1488169689Skan    }
1489132718Skan
149090075Sobrien  /* Arrange to save and restore machine status around nested functions.  */
149190075Sobrien  init_machine_status = rs6000_init_machine_status;
1492132718Skan
1493132718Skan  /* We should always be splitting complex arguments, but we can't break
1494132718Skan     Linux and Darwin ABIs at the moment.  For now, only AIX is fixed.  */
1495132718Skan  if (DEFAULT_ABI != ABI_AIX)
1496132718Skan    targetm.calls.split_complex_arg = NULL;
1497169689Skan
1498169689Skan  /* Initialize rs6000_cost with the appropriate target costs.  */
1499169689Skan  if (optimize_size)
1500169689Skan    rs6000_cost = TARGET_POWERPC64 ? &size64_cost : &size32_cost;
1501169689Skan  else
1502169689Skan    switch (rs6000_cpu)
1503169689Skan      {
1504169689Skan      case PROCESSOR_RIOS1:
1505169689Skan	rs6000_cost = &rios1_cost;
1506169689Skan	break;
1507169689Skan
1508169689Skan      case PROCESSOR_RIOS2:
1509169689Skan	rs6000_cost = &rios2_cost;
1510169689Skan	break;
1511169689Skan
1512169689Skan      case PROCESSOR_RS64A:
1513169689Skan	rs6000_cost = &rs64a_cost;
1514169689Skan	break;
1515169689Skan
1516169689Skan      case PROCESSOR_MPCCORE:
1517169689Skan	rs6000_cost = &mpccore_cost;
1518169689Skan	break;
1519169689Skan
1520169689Skan      case PROCESSOR_PPC403:
1521169689Skan	rs6000_cost = &ppc403_cost;
1522169689Skan	break;
1523169689Skan
1524169689Skan      case PROCESSOR_PPC405:
1525169689Skan	rs6000_cost = &ppc405_cost;
1526169689Skan	break;
1527169689Skan
1528169689Skan      case PROCESSOR_PPC440:
1529169689Skan	rs6000_cost = &ppc440_cost;
1530169689Skan	break;
1531169689Skan
1532169689Skan      case PROCESSOR_PPC601:
1533169689Skan	rs6000_cost = &ppc601_cost;
1534169689Skan	break;
1535169689Skan
1536169689Skan      case PROCESSOR_PPC603:
1537169689Skan	rs6000_cost = &ppc603_cost;
1538169689Skan	break;
1539169689Skan
1540169689Skan      case PROCESSOR_PPC604:
1541169689Skan	rs6000_cost = &ppc604_cost;
1542169689Skan	break;
1543169689Skan
1544169689Skan      case PROCESSOR_PPC604e:
1545169689Skan	rs6000_cost = &ppc604e_cost;
1546169689Skan	break;
1547169689Skan
1548169689Skan      case PROCESSOR_PPC620:
1549169689Skan	rs6000_cost = &ppc620_cost;
1550169689Skan	break;
1551169689Skan
1552169689Skan      case PROCESSOR_PPC630:
1553169689Skan	rs6000_cost = &ppc630_cost;
1554169689Skan	break;
1555169689Skan
1556169689Skan      case PROCESSOR_PPC750:
1557169689Skan      case PROCESSOR_PPC7400:
1558169689Skan	rs6000_cost = &ppc750_cost;
1559169689Skan	break;
1560169689Skan
1561169689Skan      case PROCESSOR_PPC7450:
1562169689Skan	rs6000_cost = &ppc7450_cost;
1563169689Skan	break;
1564169689Skan
1565169689Skan      case PROCESSOR_PPC8540:
1566169689Skan	rs6000_cost = &ppc8540_cost;
1567169689Skan	break;
1568169689Skan
1569169689Skan      case PROCESSOR_POWER4:
1570169689Skan      case PROCESSOR_POWER5:
1571169689Skan	rs6000_cost = &power4_cost;
1572169689Skan	break;
1573169689Skan
1574169689Skan      default:
1575169689Skan	gcc_unreachable ();
1576169689Skan      }
157790075Sobrien}
157890075Sobrien
1579169689Skan/* Implement targetm.vectorize.builtin_mask_for_load.  */
1580169689Skanstatic tree
1581169689Skanrs6000_builtin_mask_for_load (void)
1582169689Skan{
1583169689Skan  if (TARGET_ALTIVEC)
1584169689Skan    return altivec_builtin_mask_for_load;
1585169689Skan  else
1586169689Skan    return 0;
1587169689Skan}
1588169689Skan
1589220150Smm
1590220150Smm/* Return true iff, data reference of TYPE can reach vector alignment (16)
1591220150Smm   after applying N number of iterations.  This routine does not determine
1592220150Smm   how may iterations are required to reach desired alignment.  */
1593220150Smm
1594220150Smmstatic bool
1595220150Smmrs6000_vector_alignment_reachable (tree type ATTRIBUTE_UNUSED, bool is_packed)
1596220150Smm{
1597220150Smm  if (is_packed)
1598220150Smm    return false;
1599220150Smm
1600220150Smm  if (TARGET_32BIT)
1601220150Smm    {
1602220150Smm      if (rs6000_alignment_flags == MASK_ALIGN_NATURAL)
1603220150Smm        return true;
1604220150Smm
1605220150Smm      if (rs6000_alignment_flags ==  MASK_ALIGN_POWER)
1606220150Smm        return true;
1607220150Smm
1608220150Smm      return false;
1609220150Smm    }
1610220150Smm  else
1611220150Smm    {
1612220150Smm      if (TARGET_MACHO)
1613220150Smm        return false;
1614220150Smm
1615220150Smm      /* Assuming that all other types are naturally aligned. CHECKME!  */
1616220150Smm      return true;
1617220150Smm    }
1618220150Smm}
1619220150Smm
1620132718Skan/* Handle generic options of the form -mfoo=yes/no.
1621132718Skan   NAME is the option name.
1622132718Skan   VALUE is the option value.
1623132718Skan   FLAG is the pointer to the flag where to store a 1 or 0, depending on
1624132718Skan   whether the option value is 'yes' or 'no' respectively.  */
1625117395Skanstatic void
1626132718Skanrs6000_parse_yes_no_option (const char *name, const char *value, int *flag)
1627117395Skan{
1628132718Skan  if (value == 0)
1629117395Skan    return;
1630132718Skan  else if (!strcmp (value, "yes"))
1631132718Skan    *flag = 1;
1632132718Skan  else if (!strcmp (value, "no"))
1633132718Skan    *flag = 0;
1634117395Skan  else
1635132718Skan    error ("unknown -m%s= option specified: '%s'", name, value);
1636117395Skan}
1637117395Skan
1638132718Skan/* Validate and record the size specified with the -mtls-size option.  */
1639132718Skan
1640132718Skanstatic void
1641132718Skanrs6000_parse_tls_size_option (void)
1642132718Skan{
1643132718Skan  if (rs6000_tls_size_string == 0)
1644132718Skan    return;
1645132718Skan  else if (strcmp (rs6000_tls_size_string, "16") == 0)
1646132718Skan    rs6000_tls_size = 16;
1647132718Skan  else if (strcmp (rs6000_tls_size_string, "32") == 0)
1648132718Skan    rs6000_tls_size = 32;
1649132718Skan  else if (strcmp (rs6000_tls_size_string, "64") == 0)
1650132718Skan    rs6000_tls_size = 64;
1651132718Skan  else
1652169689Skan    error ("bad value %qs for -mtls-size switch", rs6000_tls_size_string);
1653132718Skan}
1654132718Skan
165590075Sobrienvoid
1656132718Skanoptimization_options (int level ATTRIBUTE_UNUSED, int size ATTRIBUTE_UNUSED)
165790075Sobrien{
1658169689Skan  if (DEFAULT_ABI == ABI_DARWIN)
1659169689Skan    /* The Darwin libraries never set errno, so we might as well
1660169689Skan       avoid calling them when that's the only reason we would.  */
1661169689Skan    flag_errno_math = 0;
1662169689Skan
1663169689Skan  /* Double growth factor to counter reduced min jump length.  */
1664169689Skan  set_param_value ("max-grow-copy-bb-insns", 16);
1665169689Skan
1666169689Skan  /* Enable section anchors by default.
1667169689Skan     Skip section anchors for Objective C and Objective C++
1668169689Skan     until front-ends fixed.  */
1669169689Skan  if (!TARGET_MACHO && lang_hooks.name[4] != 'O')
1670169689Skan    flag_section_anchors = 1;
167190075Sobrien}
1672169689Skan
1673169689Skan/* Implement TARGET_HANDLE_OPTION.  */
1674169689Skan
1675169689Skanstatic bool
1676169689Skanrs6000_handle_option (size_t code, const char *arg, int value)
1677169689Skan{
1678169689Skan  switch (code)
1679169689Skan    {
1680169689Skan    case OPT_mno_power:
1681169689Skan      target_flags &= ~(MASK_POWER | MASK_POWER2
1682169689Skan			| MASK_MULTIPLE | MASK_STRING);
1683169689Skan      target_flags_explicit |= (MASK_POWER | MASK_POWER2
1684169689Skan				| MASK_MULTIPLE | MASK_STRING);
1685169689Skan      break;
1686169689Skan    case OPT_mno_powerpc:
1687169689Skan      target_flags &= ~(MASK_POWERPC | MASK_PPC_GPOPT
1688169689Skan			| MASK_PPC_GFXOPT | MASK_POWERPC64);
1689169689Skan      target_flags_explicit |= (MASK_POWERPC | MASK_PPC_GPOPT
1690169689Skan				| MASK_PPC_GFXOPT | MASK_POWERPC64);
1691169689Skan      break;
1692169689Skan    case OPT_mfull_toc:
1693169689Skan      target_flags &= ~MASK_MINIMAL_TOC;
1694169689Skan      TARGET_NO_FP_IN_TOC = 0;
1695169689Skan      TARGET_NO_SUM_IN_TOC = 0;
1696169689Skan      target_flags_explicit |= MASK_MINIMAL_TOC;
1697169689Skan#ifdef TARGET_USES_SYSV4_OPT
1698169689Skan      /* Note, V.4 no longer uses a normal TOC, so make -mfull-toc, be
1699169689Skan	 just the same as -mminimal-toc.  */
1700169689Skan      target_flags |= MASK_MINIMAL_TOC;
1701169689Skan      target_flags_explicit |= MASK_MINIMAL_TOC;
1702169689Skan#endif
1703169689Skan      break;
1704169689Skan
1705169689Skan#ifdef TARGET_USES_SYSV4_OPT
1706169689Skan    case OPT_mtoc:
1707169689Skan      /* Make -mtoc behave like -mminimal-toc.  */
1708169689Skan      target_flags |= MASK_MINIMAL_TOC;
1709169689Skan      target_flags_explicit |= MASK_MINIMAL_TOC;
1710169689Skan      break;
1711169689Skan#endif
1712169689Skan
1713169689Skan#ifdef TARGET_USES_AIX64_OPT
1714169689Skan    case OPT_maix64:
1715169689Skan#else
1716169689Skan    case OPT_m64:
1717169689Skan#endif
1718169689Skan      target_flags |= MASK_POWERPC64 | MASK_POWERPC;
1719169689Skan      target_flags |= ~target_flags_explicit & MASK_PPC_GFXOPT;
1720169689Skan      target_flags_explicit |= MASK_POWERPC64 | MASK_POWERPC;
1721169689Skan      break;
1722169689Skan
1723169689Skan#ifdef TARGET_USES_AIX64_OPT
1724169689Skan    case OPT_maix32:
1725169689Skan#else
1726169689Skan    case OPT_m32:
1727169689Skan#endif
1728169689Skan      target_flags &= ~MASK_POWERPC64;
1729169689Skan      target_flags_explicit |= MASK_POWERPC64;
1730169689Skan      break;
1731169689Skan
1732169689Skan    case OPT_minsert_sched_nops_:
1733169689Skan      rs6000_sched_insert_nops_str = arg;
1734169689Skan      break;
1735169689Skan
1736169689Skan    case OPT_mminimal_toc:
1737169689Skan      if (value == 1)
1738169689Skan	{
1739169689Skan	  TARGET_NO_FP_IN_TOC = 0;
1740169689Skan	  TARGET_NO_SUM_IN_TOC = 0;
1741169689Skan	}
1742169689Skan      break;
1743169689Skan
1744169689Skan    case OPT_mpower:
1745169689Skan      if (value == 1)
1746169689Skan	{
1747169689Skan	  target_flags |= (MASK_MULTIPLE | MASK_STRING);
1748169689Skan	  target_flags_explicit |= (MASK_MULTIPLE | MASK_STRING);
1749169689Skan	}
1750169689Skan      break;
1751169689Skan
1752169689Skan    case OPT_mpower2:
1753169689Skan      if (value == 1)
1754169689Skan	{
1755169689Skan	  target_flags |= (MASK_POWER | MASK_MULTIPLE | MASK_STRING);
1756169689Skan	  target_flags_explicit |= (MASK_POWER | MASK_MULTIPLE | MASK_STRING);
1757169689Skan	}
1758169689Skan      break;
1759169689Skan
1760169689Skan    case OPT_mpowerpc_gpopt:
1761169689Skan    case OPT_mpowerpc_gfxopt:
1762169689Skan      if (value == 1)
1763169689Skan	{
1764169689Skan	  target_flags |= MASK_POWERPC;
1765169689Skan	  target_flags_explicit |= MASK_POWERPC;
1766169689Skan	}
1767169689Skan      break;
1768169689Skan
1769169689Skan    case OPT_maix_struct_return:
1770169689Skan    case OPT_msvr4_struct_return:
1771169689Skan      rs6000_explicit_options.aix_struct_ret = true;
1772169689Skan      break;
1773169689Skan
1774169689Skan    case OPT_mvrsave_:
1775169689Skan      rs6000_parse_yes_no_option ("vrsave", arg, &(TARGET_ALTIVEC_VRSAVE));
1776169689Skan      break;
1777169689Skan
1778169689Skan    case OPT_misel_:
1779169689Skan      rs6000_explicit_options.isel = true;
1780169689Skan      rs6000_parse_yes_no_option ("isel", arg, &(rs6000_isel));
1781169689Skan      break;
1782169689Skan
1783169689Skan    case OPT_mspe_:
1784169689Skan      rs6000_explicit_options.spe = true;
1785169689Skan      rs6000_parse_yes_no_option ("spe", arg, &(rs6000_spe));
1786169689Skan      /* No SPE means 64-bit long doubles, even if an E500.  */
1787169689Skan      if (!rs6000_spe)
1788169689Skan	rs6000_long_double_type_size = 64;
1789169689Skan      break;
1790169689Skan
1791169689Skan    case OPT_mdebug_:
1792169689Skan      rs6000_debug_name = arg;
1793169689Skan      break;
1794169689Skan
1795169689Skan#ifdef TARGET_USES_SYSV4_OPT
1796169689Skan    case OPT_mcall_:
1797169689Skan      rs6000_abi_name = arg;
1798169689Skan      break;
1799169689Skan
1800169689Skan    case OPT_msdata_:
1801169689Skan      rs6000_sdata_name = arg;
1802169689Skan      break;
1803169689Skan
1804169689Skan    case OPT_mtls_size_:
1805169689Skan      rs6000_tls_size_string = arg;
1806169689Skan      break;
1807169689Skan
1808169689Skan    case OPT_mrelocatable:
1809169689Skan      if (value == 1)
1810169689Skan	{
1811169689Skan	  target_flags |= MASK_MINIMAL_TOC;
1812169689Skan	  target_flags_explicit |= MASK_MINIMAL_TOC;
1813169689Skan	  TARGET_NO_FP_IN_TOC = 1;
1814169689Skan	}
1815169689Skan      break;
1816169689Skan
1817169689Skan    case OPT_mrelocatable_lib:
1818169689Skan      if (value == 1)
1819169689Skan	{
1820169689Skan	  target_flags |= MASK_RELOCATABLE | MASK_MINIMAL_TOC;
1821169689Skan	  target_flags_explicit |= MASK_RELOCATABLE | MASK_MINIMAL_TOC;
1822169689Skan	  TARGET_NO_FP_IN_TOC = 1;
1823169689Skan	}
1824169689Skan      else
1825169689Skan	{
1826169689Skan	  target_flags &= ~MASK_RELOCATABLE;
1827169689Skan	  target_flags_explicit |= MASK_RELOCATABLE;
1828169689Skan	}
1829169689Skan      break;
1830169689Skan#endif
1831169689Skan
1832169689Skan    case OPT_mabi_:
1833169689Skan      if (!strcmp (arg, "altivec"))
1834169689Skan	{
1835169689Skan	  rs6000_explicit_options.abi = true;
1836169689Skan	  rs6000_altivec_abi = 1;
1837169689Skan	  rs6000_spe_abi = 0;
1838169689Skan	}
1839169689Skan      else if (! strcmp (arg, "no-altivec"))
1840169689Skan	{
1841169689Skan	  /* ??? Don't set rs6000_explicit_options.abi here, to allow
1842169689Skan	     the default for rs6000_spe_abi to be chosen later.  */
1843169689Skan	  rs6000_altivec_abi = 0;
1844169689Skan	}
1845169689Skan      else if (! strcmp (arg, "spe"))
1846169689Skan	{
1847169689Skan	  rs6000_explicit_options.abi = true;
1848169689Skan	  rs6000_spe_abi = 1;
1849169689Skan	  rs6000_altivec_abi = 0;
1850169689Skan	  if (!TARGET_SPE_ABI)
1851169689Skan	    error ("not configured for ABI: '%s'", arg);
1852169689Skan	}
1853169689Skan      else if (! strcmp (arg, "no-spe"))
1854169689Skan	{
1855169689Skan	  rs6000_explicit_options.abi = true;
1856169689Skan	  rs6000_spe_abi = 0;
1857169689Skan	}
1858169689Skan
1859169689Skan      /* These are here for testing during development only, do not
1860169689Skan	 document in the manual please.  */
1861169689Skan      else if (! strcmp (arg, "d64"))
1862169689Skan	{
1863169689Skan	  rs6000_darwin64_abi = 1;
1864169689Skan	  warning (0, "Using darwin64 ABI");
1865169689Skan	}
1866169689Skan      else if (! strcmp (arg, "d32"))
1867169689Skan	{
1868169689Skan	  rs6000_darwin64_abi = 0;
1869169689Skan	  warning (0, "Using old darwin ABI");
1870169689Skan	}
1871169689Skan
1872169689Skan      else if (! strcmp (arg, "ibmlongdouble"))
1873169689Skan	{
1874169689Skan	  rs6000_explicit_options.ieee = true;
1875169689Skan	  rs6000_ieeequad = 0;
1876169689Skan	  warning (0, "Using IBM extended precision long double");
1877169689Skan	}
1878169689Skan      else if (! strcmp (arg, "ieeelongdouble"))
1879169689Skan	{
1880169689Skan	  rs6000_explicit_options.ieee = true;
1881169689Skan	  rs6000_ieeequad = 1;
1882169689Skan	  warning (0, "Using IEEE extended precision long double");
1883169689Skan	}
1884169689Skan
1885169689Skan      else
1886169689Skan	{
1887169689Skan	  error ("unknown ABI specified: '%s'", arg);
1888169689Skan	  return false;
1889169689Skan	}
1890169689Skan      break;
1891169689Skan
1892169689Skan    case OPT_mcpu_:
1893169689Skan      rs6000_select[1].string = arg;
1894169689Skan      break;
1895169689Skan
1896169689Skan    case OPT_mtune_:
1897169689Skan      rs6000_select[2].string = arg;
1898169689Skan      break;
1899169689Skan
1900169689Skan    case OPT_mtraceback_:
1901169689Skan      rs6000_traceback_name = arg;
1902169689Skan      break;
1903169689Skan
1904169689Skan    case OPT_mfloat_gprs_:
1905169689Skan      rs6000_explicit_options.float_gprs = true;
1906169689Skan      if (! strcmp (arg, "yes") || ! strcmp (arg, "single"))
1907169689Skan	rs6000_float_gprs = 1;
1908169689Skan      else if (! strcmp (arg, "double"))
1909169689Skan	rs6000_float_gprs = 2;
1910169689Skan      else if (! strcmp (arg, "no"))
1911169689Skan	rs6000_float_gprs = 0;
1912169689Skan      else
1913169689Skan	{
1914169689Skan	  error ("invalid option for -mfloat-gprs: '%s'", arg);
1915169689Skan	  return false;
1916169689Skan	}
1917169689Skan      break;
1918169689Skan
1919169689Skan    case OPT_mlong_double_:
1920169689Skan      rs6000_explicit_options.long_double = true;
1921169689Skan      rs6000_long_double_type_size = RS6000_DEFAULT_LONG_DOUBLE_SIZE;
1922169689Skan      if (value != 64 && value != 128)
1923169689Skan	{
1924169689Skan	  error ("Unknown switch -mlong-double-%s", arg);
1925169689Skan	  rs6000_long_double_type_size = RS6000_DEFAULT_LONG_DOUBLE_SIZE;
1926169689Skan	  return false;
1927169689Skan	}
1928169689Skan      else
1929169689Skan	rs6000_long_double_type_size = value;
1930169689Skan      break;
1931169689Skan
1932169689Skan    case OPT_msched_costly_dep_:
1933169689Skan      rs6000_sched_costly_dep_str = arg;
1934169689Skan      break;
1935169689Skan
1936169689Skan    case OPT_malign_:
1937169689Skan      rs6000_explicit_options.alignment = true;
1938169689Skan      if (! strcmp (arg, "power"))
1939169689Skan	{
1940169689Skan	  /* On 64-bit Darwin, power alignment is ABI-incompatible with
1941169689Skan	     some C library functions, so warn about it. The flag may be
1942169689Skan	     useful for performance studies from time to time though, so
1943169689Skan	     don't disable it entirely.  */
1944169689Skan	  if (DEFAULT_ABI == ABI_DARWIN && TARGET_64BIT)
1945169689Skan	    warning (0, "-malign-power is not supported for 64-bit Darwin;"
1946169689Skan		     " it is incompatible with the installed C and C++ libraries");
1947169689Skan	  rs6000_alignment_flags = MASK_ALIGN_POWER;
1948169689Skan	}
1949169689Skan      else if (! strcmp (arg, "natural"))
1950169689Skan	rs6000_alignment_flags = MASK_ALIGN_NATURAL;
1951169689Skan      else
1952169689Skan	{
1953169689Skan	  error ("unknown -malign-XXXXX option specified: '%s'", arg);
1954169689Skan	  return false;
1955169689Skan	}
1956169689Skan      break;
1957169689Skan    }
1958169689Skan  return true;
1959169689Skan}
196090075Sobrien
196190075Sobrien/* Do anything needed at the start of the asm file.  */
196290075Sobrien
1963132718Skanstatic void
1964132718Skanrs6000_file_start (void)
196590075Sobrien{
196690075Sobrien  size_t i;
196790075Sobrien  char buffer[80];
196890075Sobrien  const char *start = buffer;
196990075Sobrien  struct rs6000_cpu_select *ptr;
1970132718Skan  const char *default_cpu = TARGET_CPU_DEFAULT;
1971132718Skan  FILE *file = asm_out_file;
197290075Sobrien
1973132718Skan  default_file_start ();
1974132718Skan
1975132718Skan#ifdef TARGET_BI_ARCH
1976132718Skan  if ((TARGET_DEFAULT ^ target_flags) & MASK_64BIT)
1977132718Skan    default_cpu = 0;
1978132718Skan#endif
1979132718Skan
198090075Sobrien  if (flag_verbose_asm)
198190075Sobrien    {
198290075Sobrien      sprintf (buffer, "\n%s rs6000/powerpc options:", ASM_COMMENT_START);
198390075Sobrien      rs6000_select[0].string = default_cpu;
198490075Sobrien
198590075Sobrien      for (i = 0; i < ARRAY_SIZE (rs6000_select); i++)
198690075Sobrien	{
198790075Sobrien	  ptr = &rs6000_select[i];
198890075Sobrien	  if (ptr->string != (char *)0 && ptr->string[0] != '\0')
198990075Sobrien	    {
199090075Sobrien	      fprintf (file, "%s %s%s", start, ptr->name, ptr->string);
199190075Sobrien	      start = "";
199290075Sobrien	    }
199390075Sobrien	}
199490075Sobrien
1995169689Skan      if (PPC405_ERRATUM77)
1996169689Skan	{
1997169689Skan	  fprintf (file, "%s PPC405CR_ERRATUM77", start);
1998169689Skan	  start = "";
1999169689Skan	}
2000169689Skan
200190075Sobrien#ifdef USING_ELFOS_H
200290075Sobrien      switch (rs6000_sdata)
200390075Sobrien	{
200490075Sobrien	case SDATA_NONE: fprintf (file, "%s -msdata=none", start); start = ""; break;
200590075Sobrien	case SDATA_DATA: fprintf (file, "%s -msdata=data", start); start = ""; break;
200690075Sobrien	case SDATA_SYSV: fprintf (file, "%s -msdata=sysv", start); start = ""; break;
200790075Sobrien	case SDATA_EABI: fprintf (file, "%s -msdata=eabi", start); start = ""; break;
200890075Sobrien	}
200990075Sobrien
201090075Sobrien      if (rs6000_sdata && g_switch_value)
201190075Sobrien	{
2012132718Skan	  fprintf (file, "%s -G " HOST_WIDE_INT_PRINT_UNSIGNED, start,
2013132718Skan		   g_switch_value);
201490075Sobrien	  start = "";
201590075Sobrien	}
201690075Sobrien#endif
201790075Sobrien
201890075Sobrien      if (*start == '\0')
201990075Sobrien	putc ('\n', file);
202090075Sobrien    }
2021169689Skan
2022169689Skan  if (DEFAULT_ABI == ABI_AIX || (TARGET_ELF && flag_pic == 2))
2023169689Skan    {
2024169689Skan      switch_to_section (toc_section);
2025169689Skan      switch_to_section (text_section);
2026169689Skan    }
202790075Sobrien}
2028169689Skan
202990075Sobrien
2030117395Skan/* Return nonzero if this function is known to have a null epilogue.  */
203190075Sobrien
203290075Sobrienint
2033132718Skandirect_return (void)
203490075Sobrien{
203590075Sobrien  if (reload_completed)
203690075Sobrien    {
203790075Sobrien      rs6000_stack_t *info = rs6000_stack_info ();
203890075Sobrien
203990075Sobrien      if (info->first_gp_reg_save == 32
204090075Sobrien	  && info->first_fp_reg_save == 64
204190075Sobrien	  && info->first_altivec_reg_save == LAST_ALTIVEC_REGNO + 1
204290075Sobrien	  && ! info->lr_save_p
204390075Sobrien	  && ! info->cr_save_p
204490075Sobrien	  && info->vrsave_mask == 0
204590075Sobrien	  && ! info->push_p)
204690075Sobrien	return 1;
204790075Sobrien    }
204890075Sobrien
204990075Sobrien  return 0;
205090075Sobrien}
205190075Sobrien
205290075Sobrien/* Return the number of instructions it takes to form a constant in an
205390075Sobrien   integer register.  */
205490075Sobrien
2055169689Skanint
2056132718Skannum_insns_constant_wide (HOST_WIDE_INT value)
205790075Sobrien{
205890075Sobrien  /* signed constant loadable with {cal|addi} */
2059169689Skan  if ((unsigned HOST_WIDE_INT) (value + 0x8000) < 0x10000)
206090075Sobrien    return 1;
206190075Sobrien
206290075Sobrien  /* constant loadable with {cau|addis} */
2063169689Skan  else if ((value & 0xffff) == 0
2064169689Skan	   && (value >> 31 == -1 || value >> 31 == 0))
206590075Sobrien    return 1;
206690075Sobrien
206790075Sobrien#if HOST_BITS_PER_WIDE_INT == 64
206890075Sobrien  else if (TARGET_POWERPC64)
206990075Sobrien    {
2070117395Skan      HOST_WIDE_INT low  = ((value & 0xffffffff) ^ 0x80000000) - 0x80000000;
2071117395Skan      HOST_WIDE_INT high = value >> 31;
207290075Sobrien
2073117395Skan      if (high == 0 || high == -1)
207490075Sobrien	return 2;
207590075Sobrien
2076117395Skan      high >>= 1;
207790075Sobrien
2078117395Skan      if (low == 0)
207990075Sobrien	return num_insns_constant_wide (high) + 1;
208090075Sobrien      else
208190075Sobrien	return (num_insns_constant_wide (high)
208290075Sobrien		+ num_insns_constant_wide (low) + 1);
208390075Sobrien    }
208490075Sobrien#endif
208590075Sobrien
208690075Sobrien  else
208790075Sobrien    return 2;
208890075Sobrien}
208990075Sobrien
209090075Sobrienint
2091132718Skannum_insns_constant (rtx op, enum machine_mode mode)
209290075Sobrien{
2093169689Skan  HOST_WIDE_INT low, high;
2094169689Skan
2095169689Skan  switch (GET_CODE (op))
209690075Sobrien    {
2097169689Skan    case CONST_INT:
209890075Sobrien#if HOST_BITS_PER_WIDE_INT == 64
209990075Sobrien      if ((INTVAL (op) >> 31) != 0 && (INTVAL (op) >> 31) != -1
210090075Sobrien	  && mask64_operand (op, mode))
2101169689Skan	return 2;
210290075Sobrien      else
210390075Sobrien#endif
210490075Sobrien	return num_insns_constant_wide (INTVAL (op));
210590075Sobrien
2106169689Skan      case CONST_DOUBLE:
2107169689Skan	if (mode == SFmode)
2108169689Skan	  {
2109169689Skan	    long l;
2110169689Skan	    REAL_VALUE_TYPE rv;
211190075Sobrien
2112169689Skan	    REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
2113169689Skan	    REAL_VALUE_TO_TARGET_SINGLE (rv, l);
2114169689Skan	    return num_insns_constant_wide ((HOST_WIDE_INT) l);
2115169689Skan	  }
211690075Sobrien
2117169689Skan	if (mode == VOIDmode || mode == DImode)
2118169689Skan	  {
2119169689Skan	    high = CONST_DOUBLE_HIGH (op);
2120169689Skan	    low  = CONST_DOUBLE_LOW (op);
2121169689Skan	  }
2122169689Skan	else
2123169689Skan	  {
2124169689Skan	    long l[2];
2125169689Skan	    REAL_VALUE_TYPE rv;
212690075Sobrien
2127169689Skan	    REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
2128169689Skan	    REAL_VALUE_TO_TARGET_DOUBLE (rv, l);
2129169689Skan	    high = l[WORDS_BIG_ENDIAN == 0];
2130169689Skan	    low  = l[WORDS_BIG_ENDIAN != 0];
2131169689Skan	  }
213290075Sobrien
2133169689Skan	if (TARGET_32BIT)
2134169689Skan	  return (num_insns_constant_wide (low)
2135169689Skan		  + num_insns_constant_wide (high));
2136169689Skan	else
2137169689Skan	  {
2138169689Skan	    if ((high == 0 && low >= 0)
2139169689Skan		|| (high == -1 && low < 0))
2140169689Skan	      return num_insns_constant_wide (low);
214190075Sobrien
2142169689Skan	    else if (mask64_operand (op, mode))
2143169689Skan	      return 2;
214490075Sobrien
2145169689Skan	    else if (low == 0)
2146169689Skan	      return num_insns_constant_wide (high) + 1;
214790075Sobrien
2148169689Skan	    else
2149169689Skan	      return (num_insns_constant_wide (high)
2150169689Skan		      + num_insns_constant_wide (low) + 1);
2151169689Skan	  }
215290075Sobrien
2153169689Skan    default:
2154169689Skan      gcc_unreachable ();
215590075Sobrien    }
2156169689Skan}
215790075Sobrien
2158169689Skan/* Interpret element ELT of the CONST_VECTOR OP as an integer value.
2159169689Skan   If the mode of OP is MODE_VECTOR_INT, this simply returns the
2160169689Skan   corresponding element of the vector, but for V4SFmode and V2SFmode,
2161169689Skan   the corresponding "float" is interpreted as an SImode integer.  */
2162169689Skan
2163169689Skanstatic HOST_WIDE_INT
2164169689Skanconst_vector_elt_as_int (rtx op, unsigned int elt)
2165169689Skan{
2166169689Skan  rtx tmp = CONST_VECTOR_ELT (op, elt);
2167169689Skan  if (GET_MODE (op) == V4SFmode
2168169689Skan      || GET_MODE (op) == V2SFmode)
2169169689Skan    tmp = gen_lowpart (SImode, tmp);
2170169689Skan  return INTVAL (tmp);
217190075Sobrien}
217290075Sobrien
2173169689Skan/* Return true if OP can be synthesized with a particular vspltisb, vspltish
2174169689Skan   or vspltisw instruction.  OP is a CONST_VECTOR.  Which instruction is used
2175169689Skan   depends on STEP and COPIES, one of which will be 1.  If COPIES > 1,
2176169689Skan   all items are set to the same value and contain COPIES replicas of the
2177169689Skan   vsplt's operand; if STEP > 1, one in STEP elements is set to the vsplt's
2178169689Skan   operand and the others are set to the value of the operand's msb.  */
217990075Sobrien
2180169689Skanstatic bool
2181169689Skanvspltis_constant (rtx op, unsigned step, unsigned copies)
218290075Sobrien{
2183169689Skan  enum machine_mode mode = GET_MODE (op);
2184169689Skan  enum machine_mode inner = GET_MODE_INNER (mode);
218590075Sobrien
2186169689Skan  unsigned i;
2187169689Skan  unsigned nunits = GET_MODE_NUNITS (mode);
2188169689Skan  unsigned bitsize = GET_MODE_BITSIZE (inner);
2189169689Skan  unsigned mask = GET_MODE_MASK (inner);
219090075Sobrien
2191169689Skan  HOST_WIDE_INT val = const_vector_elt_as_int (op, nunits - 1);
2192169689Skan  HOST_WIDE_INT splat_val = val;
2193169689Skan  HOST_WIDE_INT msb_val = val > 0 ? 0 : -1;
219490075Sobrien
2195169689Skan  /* Construct the value to be splatted, if possible.  If not, return 0.  */
2196169689Skan  for (i = 2; i <= copies; i *= 2)
219790075Sobrien    {
2198169689Skan      HOST_WIDE_INT small_val;
2199169689Skan      bitsize /= 2;
2200169689Skan      small_val = splat_val >> bitsize;
2201169689Skan      mask >>= bitsize;
2202169689Skan      if (splat_val != ((small_val << bitsize) | (small_val & mask)))
2203169689Skan	return false;
2204169689Skan      splat_val = small_val;
2205117395Skan    }
2206117395Skan
2207169689Skan  /* Check if SPLAT_VAL can really be the operand of a vspltis[bhw].  */
2208169689Skan  if (EASY_VECTOR_15 (splat_val))
2209169689Skan    ;
221090075Sobrien
2211169689Skan  /* Also check if we can splat, and then add the result to itself.  Do so if
2212169689Skan     the value is positive, of if the splat instruction is using OP's mode;
2213169689Skan     for splat_val < 0, the splat and the add should use the same mode.  */
2214169689Skan  else if (EASY_VECTOR_15_ADD_SELF (splat_val)
2215169689Skan           && (splat_val >= 0 || (step == 1 && copies == 1)))
2216169689Skan    ;
221790075Sobrien
2218169689Skan  else
2219169689Skan    return false;
222090075Sobrien
2221169689Skan  /* Check if VAL is present in every STEP-th element, and the
2222169689Skan     other elements are filled with its most significant bit.  */
2223169689Skan  for (i = 0; i < nunits - 1; ++i)
222490075Sobrien    {
2225169689Skan      HOST_WIDE_INT desired_val;
2226169689Skan      if (((i + 1) & (step - 1)) == 0)
2227169689Skan	desired_val = val;
2228169689Skan      else
2229169689Skan	desired_val = msb_val;
223090075Sobrien
2231169689Skan      if (desired_val != const_vector_elt_as_int (op, i))
2232169689Skan	return false;
223390075Sobrien    }
223490075Sobrien
2235169689Skan  return true;
223690075Sobrien}
223790075Sobrien
223896263Sobrien
2239169689Skan/* Return true if OP is of the given MODE and can be synthesized
2240169689Skan   with a vspltisb, vspltish or vspltisw.  */
224196263Sobrien
2242169689Skanbool
2243169689Skaneasy_altivec_constant (rtx op, enum machine_mode mode)
2244132718Skan{
2245169689Skan  unsigned step, copies;
2246132718Skan
2247169689Skan  if (mode == VOIDmode)
2248169689Skan    mode = GET_MODE (op);
2249169689Skan  else if (mode != GET_MODE (op))
2250169689Skan    return false;
225196263Sobrien
2252169689Skan  /* Start with a vspltisw.  */
2253169689Skan  step = GET_MODE_NUNITS (mode) / 4;
2254169689Skan  copies = 1;
2255132718Skan
2256169689Skan  if (vspltis_constant (op, step, copies))
2257169689Skan    return true;
2258132718Skan
2259169689Skan  /* Then try with a vspltish.  */
2260169689Skan  if (step == 1)
2261169689Skan    copies <<= 1;
2262169689Skan  else
2263169689Skan    step >>= 1;
2264132718Skan
2265169689Skan  if (vspltis_constant (op, step, copies))
2266169689Skan    return true;
2267132718Skan
2268169689Skan  /* And finally a vspltisb.  */
2269169689Skan  if (step == 1)
2270169689Skan    copies <<= 1;
2271169689Skan  else
2272169689Skan    step >>= 1;
2273132718Skan
2274169689Skan  if (vspltis_constant (op, step, copies))
2275169689Skan    return true;
2276132718Skan
2277169689Skan  return false;
2278169689Skan}
2279132718Skan
2280169689Skan/* Generate a VEC_DUPLICATE representing a vspltis[bhw] instruction whose
2281169689Skan   result is OP.  Abort if it is not possible.  */
2282132718Skan
2283169689Skanrtx
2284169689Skangen_easy_altivec_constant (rtx op)
2285169689Skan{
2286169689Skan  enum machine_mode mode = GET_MODE (op);
2287169689Skan  int nunits = GET_MODE_NUNITS (mode);
2288169689Skan  rtx last = CONST_VECTOR_ELT (op, nunits - 1);
2289169689Skan  unsigned step = nunits / 4;
2290169689Skan  unsigned copies = 1;
2291132718Skan
2292169689Skan  /* Start with a vspltisw.  */
2293169689Skan  if (vspltis_constant (op, step, copies))
2294169689Skan    return gen_rtx_VEC_DUPLICATE (V4SImode, gen_lowpart (SImode, last));
2295132718Skan
2296169689Skan  /* Then try with a vspltish.  */
2297169689Skan  if (step == 1)
2298169689Skan    copies <<= 1;
2299169689Skan  else
2300169689Skan    step >>= 1;
230196263Sobrien
2302169689Skan  if (vspltis_constant (op, step, copies))
2303169689Skan    return gen_rtx_VEC_DUPLICATE (V8HImode, gen_lowpart (HImode, last));
230496263Sobrien
2305169689Skan  /* And finally a vspltisb.  */
2306169689Skan  if (step == 1)
2307169689Skan    copies <<= 1;
2308169689Skan  else
2309169689Skan    step >>= 1;
2310132718Skan
2311169689Skan  if (vspltis_constant (op, step, copies))
2312169689Skan    return gen_rtx_VEC_DUPLICATE (V16QImode, gen_lowpart (QImode, last));
2313132718Skan
2314169689Skan  gcc_unreachable ();
2315132718Skan}
2316132718Skan
2317132718Skanconst char *
2318132718Skanoutput_vec_const_move (rtx *operands)
2319132718Skan{
2320132718Skan  int cst, cst2;
2321132718Skan  enum machine_mode mode;
2322132718Skan  rtx dest, vec;
2323132718Skan
2324132718Skan  dest = operands[0];
2325132718Skan  vec = operands[1];
2326132718Skan  mode = GET_MODE (dest);
2327132718Skan
2328132718Skan  if (TARGET_ALTIVEC)
2329132718Skan    {
2330169689Skan      rtx splat_vec;
2331132718Skan      if (zero_constant (vec, mode))
2332132718Skan	return "vxor %0,%0,%0";
233396263Sobrien
2334169689Skan      splat_vec = gen_easy_altivec_constant (vec);
2335169689Skan      gcc_assert (GET_CODE (splat_vec) == VEC_DUPLICATE);
2336169689Skan      operands[1] = XEXP (splat_vec, 0);
2337169689Skan      if (!EASY_VECTOR_15 (INTVAL (operands[1])))
2338169689Skan	return "#";
2339132718Skan
2340169689Skan      switch (GET_MODE (splat_vec))
2341169689Skan	{
2342169689Skan	case V4SImode:
2343169689Skan	  return "vspltisw %0,%1";
2344132718Skan
2345169689Skan	case V8HImode:
2346169689Skan	  return "vspltish %0,%1";
234796263Sobrien
2348169689Skan	case V16QImode:
2349169689Skan	  return "vspltisb %0,%1";
235096263Sobrien
2351169689Skan	default:
2352169689Skan	  gcc_unreachable ();
2353169689Skan	}
2354169689Skan    }
235590075Sobrien
2356169689Skan  gcc_assert (TARGET_SPE);
235790075Sobrien
2358169689Skan  /* Vector constant 0 is handled as a splitter of V2SI, and in the
2359169689Skan     pattern of V1DI, V4HI, and V2SF.
236090075Sobrien
2361169689Skan     FIXME: We should probably return # and add post reload
2362169689Skan     splitters for these, but this way is so easy ;-).  */
2363169689Skan  cst = INTVAL (CONST_VECTOR_ELT (vec, 0));
2364169689Skan  cst2 = INTVAL (CONST_VECTOR_ELT (vec, 1));
2365169689Skan  operands[1] = CONST_VECTOR_ELT (vec, 0);
2366169689Skan  operands[2] = CONST_VECTOR_ELT (vec, 1);
2367169689Skan  if (cst == cst2)
2368169689Skan    return "li %0,%1\n\tevmergelo %0,%0,%0";
2369169689Skan  else
2370169689Skan    return "li %0,%1\n\tevmergelo %0,%0,%0\n\tli %0,%2";
237190075Sobrien}
237290075Sobrien
2373169689Skan/* Initialize vector TARGET to VALS.  */
237490075Sobrien
2375169689Skanvoid
2376169689Skanrs6000_expand_vector_init (rtx target, rtx vals)
237790075Sobrien{
2378169689Skan  enum machine_mode mode = GET_MODE (target);
2379169689Skan  enum machine_mode inner_mode = GET_MODE_INNER (mode);
2380169689Skan  int n_elts = GET_MODE_NUNITS (mode);
2381169689Skan  int n_var = 0, one_var = -1;
2382169689Skan  bool all_same = true, all_const_zero = true;
2383169689Skan  rtx x, mem;
2384169689Skan  int i;
238590075Sobrien
2386169689Skan  for (i = 0; i < n_elts; ++i)
2387169689Skan    {
2388169689Skan      x = XVECEXP (vals, 0, i);
2389169689Skan      if (!CONSTANT_P (x))
2390169689Skan	++n_var, one_var = i;
2391169689Skan      else if (x != CONST0_RTX (inner_mode))
2392169689Skan	all_const_zero = false;
239390075Sobrien
2394169689Skan      if (i > 0 && !rtx_equal_p (x, XVECEXP (vals, 0, 0)))
2395169689Skan	all_same = false;
2396169689Skan    }
239790075Sobrien
2398169689Skan  if (n_var == 0)
239990075Sobrien    {
2400169689Skan      if (mode != V4SFmode && all_const_zero)
2401169689Skan	{
2402169689Skan	  /* Zero register.  */
2403169689Skan	  emit_insn (gen_rtx_SET (VOIDmode, target,
2404169689Skan				  gen_rtx_XOR (mode, target, target)));
2405169689Skan	  return;
2406169689Skan	}
2407169689Skan      else if (mode != V4SFmode && easy_vector_constant (vals, mode))
2408169689Skan	{
2409169689Skan	  /* Splat immediate.  */
2410169689Skan	  emit_insn (gen_rtx_SET (VOIDmode, target, vals));
2411169689Skan	  return;
2412169689Skan	}
2413169689Skan      else if (all_same)
2414169689Skan	;	/* Splat vector element.  */
2415169689Skan      else
2416169689Skan	{
2417169689Skan	  /* Load from constant pool.  */
2418169689Skan	  emit_move_insn (target, gen_rtx_CONST_VECTOR (mode, XVEC (vals, 0)));
2419169689Skan	  return;
2420169689Skan	}
2421169689Skan    }
242290075Sobrien
2423169689Skan  /* Store value to stack temp.  Load vector element.  Splat.  */
2424169689Skan  if (all_same)
242590075Sobrien    {
2426169689Skan      mem = assign_stack_temp (mode, GET_MODE_SIZE (inner_mode), 0);
2427169689Skan      emit_move_insn (adjust_address_nv (mem, inner_mode, 0),
2428169689Skan		      XVECEXP (vals, 0, 0));
2429169689Skan      x = gen_rtx_UNSPEC (VOIDmode,
2430169689Skan			  gen_rtvec (1, const0_rtx), UNSPEC_LVE);
2431169689Skan      emit_insn (gen_rtx_PARALLEL (VOIDmode,
2432169689Skan				   gen_rtvec (2,
2433169689Skan					      gen_rtx_SET (VOIDmode,
2434169689Skan							   target, mem),
2435169689Skan					      x)));
2436169689Skan      x = gen_rtx_VEC_SELECT (inner_mode, target,
2437169689Skan			      gen_rtx_PARALLEL (VOIDmode,
2438169689Skan						gen_rtvec (1, const0_rtx)));
2439169689Skan      emit_insn (gen_rtx_SET (VOIDmode, target,
2440169689Skan			      gen_rtx_VEC_DUPLICATE (mode, x)));
2441169689Skan      return;
244290075Sobrien    }
244390075Sobrien
2444169689Skan  /* One field is non-constant.  Load constant then overwrite
2445169689Skan     varying field.  */
2446169689Skan  if (n_var == 1)
2447169689Skan    {
2448169689Skan      rtx copy = copy_rtx (vals);
244990075Sobrien
2450169689Skan      /* Load constant part of vector, substitute neighboring value for
2451169689Skan	 varying element.  */
2452169689Skan      XVECEXP (copy, 0, one_var) = XVECEXP (vals, 0, (one_var + 1) % n_elts);
2453169689Skan      rs6000_expand_vector_init (target, copy);
245490075Sobrien
2455169689Skan      /* Insert variable.  */
2456169689Skan      rs6000_expand_vector_set (target, XVECEXP (vals, 0, one_var), one_var);
2457169689Skan      return;
2458169689Skan    }
245990075Sobrien
2460169689Skan  /* Construct the vector in memory one field at a time
2461169689Skan     and load the whole vector.  */
2462169689Skan  mem = assign_stack_temp (mode, GET_MODE_SIZE (mode), 0);
2463169689Skan  for (i = 0; i < n_elts; i++)
2464169689Skan    emit_move_insn (adjust_address_nv (mem, inner_mode,
2465169689Skan				    i * GET_MODE_SIZE (inner_mode)),
2466169689Skan		    XVECEXP (vals, 0, i));
2467169689Skan  emit_move_insn (target, mem);
246890075Sobrien}
246990075Sobrien
2470169689Skan/* Set field ELT of TARGET to VAL.  */
2471117395Skan
2472169689Skanvoid
2473169689Skanrs6000_expand_vector_set (rtx target, rtx val, int elt)
2474117395Skan{
2475169689Skan  enum machine_mode mode = GET_MODE (target);
2476169689Skan  enum machine_mode inner_mode = GET_MODE_INNER (mode);
2477169689Skan  rtx reg = gen_reg_rtx (mode);
2478169689Skan  rtx mask, mem, x;
2479169689Skan  int width = GET_MODE_SIZE (inner_mode);
2480169689Skan  int i;
2481117395Skan
2482169689Skan  /* Load single variable value.  */
2483169689Skan  mem = assign_stack_temp (mode, GET_MODE_SIZE (inner_mode), 0);
2484169689Skan  emit_move_insn (adjust_address_nv (mem, inner_mode, 0), val);
2485169689Skan  x = gen_rtx_UNSPEC (VOIDmode,
2486169689Skan		      gen_rtvec (1, const0_rtx), UNSPEC_LVE);
2487169689Skan  emit_insn (gen_rtx_PARALLEL (VOIDmode,
2488169689Skan			       gen_rtvec (2,
2489169689Skan					  gen_rtx_SET (VOIDmode,
2490169689Skan						       reg, mem),
2491169689Skan					  x)));
2492117395Skan
2493169689Skan  /* Linear sequence.  */
2494169689Skan  mask = gen_rtx_PARALLEL (V16QImode, rtvec_alloc (16));
2495169689Skan  for (i = 0; i < 16; ++i)
2496169689Skan    XVECEXP (mask, 0, i) = GEN_INT (i);
2497117395Skan
2498169689Skan  /* Set permute mask to insert element into target.  */
2499169689Skan  for (i = 0; i < width; ++i)
2500169689Skan    XVECEXP (mask, 0, elt*width + i)
2501169689Skan      = GEN_INT (i + 0x10);
2502169689Skan  x = gen_rtx_CONST_VECTOR (V16QImode, XVEC (mask, 0));
2503169689Skan  x = gen_rtx_UNSPEC (mode,
2504169689Skan		      gen_rtvec (3, target, reg,
2505169689Skan				 force_reg (V16QImode, x)),
2506169689Skan		      UNSPEC_VPERM);
2507169689Skan  emit_insn (gen_rtx_SET (VOIDmode, target, x));
2508117395Skan}
2509117395Skan
2510169689Skan/* Extract field ELT from VEC into TARGET.  */
251190075Sobrien
2512169689Skanvoid
2513169689Skanrs6000_expand_vector_extract (rtx target, rtx vec, int elt)
251490075Sobrien{
2515169689Skan  enum machine_mode mode = GET_MODE (vec);
2516169689Skan  enum machine_mode inner_mode = GET_MODE_INNER (mode);
2517169689Skan  rtx mem, x;
251890075Sobrien
2519169689Skan  /* Allocate mode-sized buffer.  */
2520169689Skan  mem = assign_stack_temp (mode, GET_MODE_SIZE (mode), 0);
2521117395Skan
2522169689Skan  /* Add offset to field within buffer matching vector element.  */
2523169689Skan  mem = adjust_address_nv (mem, mode, elt * GET_MODE_SIZE (inner_mode));
2524117395Skan
2525169689Skan  /* Store single field into mode-sized buffer.  */
2526169689Skan  x = gen_rtx_UNSPEC (VOIDmode,
2527169689Skan		      gen_rtvec (1, const0_rtx), UNSPEC_STVE);
2528169689Skan  emit_insn (gen_rtx_PARALLEL (VOIDmode,
2529169689Skan			       gen_rtvec (2,
2530169689Skan					  gen_rtx_SET (VOIDmode,
2531169689Skan						       mem, vec),
2532169689Skan					  x)));
2533169689Skan  emit_move_insn (target, adjust_address_nv (mem, inner_mode, 0));
2534117395Skan}
2535117395Skan
2536117395Skan/* Generates shifts and masks for a pair of rldicl or rldicr insns to
2537117395Skan   implement ANDing by the mask IN.  */
2538117395Skanvoid
2539132718Skanbuild_mask64_2_operands (rtx in, rtx *out)
2540117395Skan{
2541117395Skan#if HOST_BITS_PER_WIDE_INT >= 64
2542117395Skan  unsigned HOST_WIDE_INT c, lsb, m1, m2;
2543117395Skan  int shift;
2544117395Skan
2545169689Skan  gcc_assert (GET_CODE (in) == CONST_INT);
2546117395Skan
2547117395Skan  c = INTVAL (in);
2548117395Skan  if (c & 1)
2549117395Skan    {
2550117395Skan      /* Assume c initially something like 0x00fff000000fffff.  The idea
2551117395Skan	 is to rotate the word so that the middle ^^^^^^ group of zeros
2552117395Skan	 is at the MS end and can be cleared with an rldicl mask.  We then
2553117395Skan	 rotate back and clear off the MS    ^^ group of zeros with a
2554117395Skan	 second rldicl.  */
2555117395Skan      c = ~c;			/*   c == 0xff000ffffff00000 */
2556117395Skan      lsb = c & -c;		/* lsb == 0x0000000000100000 */
2557117395Skan      m1 = -lsb;		/*  m1 == 0xfffffffffff00000 */
2558117395Skan      c = ~c;			/*   c == 0x00fff000000fffff */
2559117395Skan      c &= -lsb;		/*   c == 0x00fff00000000000 */
2560117395Skan      lsb = c & -c;		/* lsb == 0x0000100000000000 */
2561117395Skan      c = ~c;			/*   c == 0xff000fffffffffff */
2562117395Skan      c &= -lsb;		/*   c == 0xff00000000000000 */
2563117395Skan      shift = 0;
2564117395Skan      while ((lsb >>= 1) != 0)
2565117395Skan	shift++;		/* shift == 44 on exit from loop */
2566117395Skan      m1 <<= 64 - shift;	/*  m1 == 0xffffff0000000000 */
2567117395Skan      m1 = ~m1;			/*  m1 == 0x000000ffffffffff */
2568117395Skan      m2 = ~c;			/*  m2 == 0x00ffffffffffffff */
2569117395Skan    }
257090075Sobrien  else
2571117395Skan    {
2572117395Skan      /* Assume c initially something like 0xff000f0000000000.  The idea
2573117395Skan	 is to rotate the word so that the     ^^^  middle group of zeros
2574117395Skan	 is at the LS end and can be cleared with an rldicr mask.  We then
2575117395Skan	 rotate back and clear off the LS group of ^^^^^^^^^^ zeros with
2576117395Skan	 a second rldicr.  */
2577117395Skan      lsb = c & -c;		/* lsb == 0x0000010000000000 */
2578117395Skan      m2 = -lsb;		/*  m2 == 0xffffff0000000000 */
2579117395Skan      c = ~c;			/*   c == 0x00fff0ffffffffff */
2580117395Skan      c &= -lsb;		/*   c == 0x00fff00000000000 */
2581117395Skan      lsb = c & -c;		/* lsb == 0x0000100000000000 */
2582117395Skan      c = ~c;			/*   c == 0xff000fffffffffff */
2583117395Skan      c &= -lsb;		/*   c == 0xff00000000000000 */
2584117395Skan      shift = 0;
2585117395Skan      while ((lsb >>= 1) != 0)
2586117395Skan	shift++;		/* shift == 44 on exit from loop */
2587117395Skan      m1 = ~c;			/*  m1 == 0x00ffffffffffffff */
2588117395Skan      m1 >>= shift;		/*  m1 == 0x0000000000000fff */
2589117395Skan      m1 = ~m1;			/*  m1 == 0xfffffffffffff000 */
2590117395Skan    }
2591117395Skan
2592117395Skan  /* Note that when we only have two 0->1 and 1->0 transitions, one of the
2593117395Skan     masks will be all 1's.  We are guaranteed more than one transition.  */
2594117395Skan  out[0] = GEN_INT (64 - shift);
2595117395Skan  out[1] = GEN_INT (m1);
2596117395Skan  out[2] = GEN_INT (shift);
2597117395Skan  out[3] = GEN_INT (m2);
2598117395Skan#else
2599117395Skan  (void)in;
2600117395Skan  (void)out;
2601169689Skan  gcc_unreachable ();
2602117395Skan#endif
260390075Sobrien}
260490075Sobrien
2605169689Skan/* Return TRUE if OP is an invalid SUBREG operation on the e500.  */
260690075Sobrien
2607169689Skanbool
2608169689Skaninvalid_e500_subreg (rtx op, enum machine_mode mode)
260990075Sobrien{
2610169689Skan  if (TARGET_E500_DOUBLE)
2611169689Skan    {
2612169689Skan      /* Reject (subreg:SI (reg:DF)).  */
2613169689Skan      if (GET_CODE (op) == SUBREG
2614169689Skan	  && mode == SImode
2615169689Skan	  && REG_P (SUBREG_REG (op))
2616169689Skan	  && GET_MODE (SUBREG_REG (op)) == DFmode)
2617169689Skan	return true;
261890075Sobrien
2619169689Skan      /* Reject (subreg:DF (reg:DI)).  */
2620169689Skan      if (GET_CODE (op) == SUBREG
2621169689Skan	  && mode == DFmode
2622169689Skan	  && REG_P (SUBREG_REG (op))
2623169689Skan	  && GET_MODE (SUBREG_REG (op)) == DImode)
2624169689Skan	return true;
2625169689Skan    }
262690075Sobrien
2627169689Skan  if (TARGET_SPE
2628169689Skan      && GET_CODE (op) == SUBREG
2629169689Skan      && mode == SImode
2630169689Skan      && REG_P (SUBREG_REG (op))
2631169689Skan      && SPE_VECTOR_MODE (GET_MODE (SUBREG_REG (op))))
2632169689Skan    return true;
2633117395Skan
2634169689Skan  return false;
2635117395Skan}
2636117395Skan
2637132718Skan/* Darwin, AIX increases natural record alignment to doubleword if the first
2638132718Skan   field is an FP double while the FP fields remain word aligned.  */
2639132718Skan
2640132718Skanunsigned int
2641169689Skanrs6000_special_round_type_align (tree type, unsigned int computed,
2642169689Skan				 unsigned int specified)
2643132718Skan{
2644169689Skan  unsigned int align = MAX (computed, specified);
2645132718Skan  tree field = TYPE_FIELDS (type);
2646132718Skan
2647169689Skan  /* Skip all non field decls */
2648169689Skan  while (field != NULL && TREE_CODE (field) != FIELD_DECL)
2649132718Skan    field = TREE_CHAIN (field);
2650132718Skan
2651169689Skan  if (field != NULL && field != type)
2652169689Skan    {
2653169689Skan      type = TREE_TYPE (field);
2654169689Skan      while (TREE_CODE (type) == ARRAY_TYPE)
2655169689Skan	type = TREE_TYPE (type);
2656132718Skan
2657169689Skan      if (type != error_mark_node && TYPE_MODE (type) == DFmode)
2658169689Skan	align = MAX (align, 64);
2659169689Skan    }
2660169689Skan
2661169689Skan  return align;
2662132718Skan}
2663132718Skan
266490075Sobrien/* Return 1 for an operand in small memory on V.4/eabi.  */
266590075Sobrien
266690075Sobrienint
2667169689Skansmall_data_operand (rtx op ATTRIBUTE_UNUSED,
2668132718Skan		    enum machine_mode mode ATTRIBUTE_UNUSED)
266990075Sobrien{
267090075Sobrien#if TARGET_ELF
267190075Sobrien  rtx sym_ref;
267290075Sobrien
267390075Sobrien  if (rs6000_sdata == SDATA_NONE || rs6000_sdata == SDATA_DATA)
267490075Sobrien    return 0;
267590075Sobrien
267690075Sobrien  if (DEFAULT_ABI != ABI_V4)
267790075Sobrien    return 0;
267890075Sobrien
267990075Sobrien  if (GET_CODE (op) == SYMBOL_REF)
268090075Sobrien    sym_ref = op;
268190075Sobrien
268290075Sobrien  else if (GET_CODE (op) != CONST
268390075Sobrien	   || GET_CODE (XEXP (op, 0)) != PLUS
268490075Sobrien	   || GET_CODE (XEXP (XEXP (op, 0), 0)) != SYMBOL_REF
268590075Sobrien	   || GET_CODE (XEXP (XEXP (op, 0), 1)) != CONST_INT)
268690075Sobrien    return 0;
268790075Sobrien
268890075Sobrien  else
268990075Sobrien    {
269090075Sobrien      rtx sum = XEXP (op, 0);
269190075Sobrien      HOST_WIDE_INT summand;
269290075Sobrien
269390075Sobrien      /* We have to be careful here, because it is the referenced address
2694169689Skan	 that must be 32k from _SDA_BASE_, not just the symbol.  */
269590075Sobrien      summand = INTVAL (XEXP (sum, 1));
2696132718Skan      if (summand < 0 || (unsigned HOST_WIDE_INT) summand > g_switch_value)
2697169689Skan	return 0;
269890075Sobrien
269990075Sobrien      sym_ref = XEXP (sum, 0);
270090075Sobrien    }
270190075Sobrien
2702132718Skan  return SYMBOL_REF_SMALL_P (sym_ref);
270390075Sobrien#else
270490075Sobrien  return 0;
270590075Sobrien#endif
270690075Sobrien}
2707132718Skan
2708132718Skan/* Return true if either operand is a general purpose register.  */
2709132718Skan
2710132718Skanbool
2711132718Skangpr_or_gpr_p (rtx op0, rtx op1)
2712132718Skan{
2713132718Skan  return ((REG_P (op0) && INT_REGNO_P (REGNO (op0)))
2714132718Skan	  || (REG_P (op1) && INT_REGNO_P (REGNO (op1))));
2715132718Skan}
2716132718Skan
271790075Sobrien
2718132718Skan/* Subroutines of rs6000_legitimize_address and rs6000_legitimate_address.  */
2719132718Skan
2720169689Skanstatic int
2721169689Skanconstant_pool_expr_1 (rtx op, int *have_sym, int *have_toc)
272290075Sobrien{
2723169689Skan  switch (GET_CODE (op))
272490075Sobrien    {
272590075Sobrien    case SYMBOL_REF:
2726132718Skan      if (RS6000_SYMBOL_REF_TLS_P (op))
2727132718Skan	return 0;
2728132718Skan      else if (CONSTANT_POOL_ADDRESS_P (op))
272990075Sobrien	{
273090075Sobrien	  if (ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (op), Pmode))
273190075Sobrien	    {
273290075Sobrien	      *have_sym = 1;
273390075Sobrien	      return 1;
273490075Sobrien	    }
273590075Sobrien	  else
273690075Sobrien	    return 0;
273790075Sobrien	}
273890075Sobrien      else if (! strcmp (XSTR (op, 0), toc_label_name))
273990075Sobrien	{
274090075Sobrien	  *have_toc = 1;
274190075Sobrien	  return 1;
274290075Sobrien	}
274390075Sobrien      else
274490075Sobrien	return 0;
274590075Sobrien    case PLUS:
274690075Sobrien    case MINUS:
274796263Sobrien      return (constant_pool_expr_1 (XEXP (op, 0), have_sym, have_toc)
274896263Sobrien	      && constant_pool_expr_1 (XEXP (op, 1), have_sym, have_toc));
274990075Sobrien    case CONST:
275090075Sobrien      return constant_pool_expr_1 (XEXP (op, 0), have_sym, have_toc);
275190075Sobrien    case CONST_INT:
275290075Sobrien      return 1;
275390075Sobrien    default:
275490075Sobrien      return 0;
275590075Sobrien    }
275690075Sobrien}
275790075Sobrien
2758132718Skanstatic bool
2759132718Skanconstant_pool_expr_p (rtx op)
276090075Sobrien{
276190075Sobrien  int have_sym = 0;
276290075Sobrien  int have_toc = 0;
276390075Sobrien  return constant_pool_expr_1 (op, &have_sym, &have_toc) && have_sym;
276490075Sobrien}
276590075Sobrien
2766169689Skanbool
2767132718Skantoc_relative_expr_p (rtx op)
276890075Sobrien{
2769132718Skan  int have_sym = 0;
2770132718Skan  int have_toc = 0;
2771132718Skan  return constant_pool_expr_1 (op, &have_sym, &have_toc) && have_toc;
277290075Sobrien}
277390075Sobrien
2774132718Skanbool
2775132718Skanlegitimate_constant_pool_address_p (rtx x)
2776132718Skan{
2777132718Skan  return (TARGET_TOC
2778132718Skan	  && GET_CODE (x) == PLUS
2779132718Skan	  && GET_CODE (XEXP (x, 0)) == REG
2780132718Skan	  && (TARGET_MINIMAL_TOC || REGNO (XEXP (x, 0)) == TOC_REGISTER)
2781132718Skan	  && constant_pool_expr_p (XEXP (x, 1)));
2782132718Skan}
2783132718Skan
2784132718Skanstatic bool
2785132718Skanlegitimate_small_data_p (enum machine_mode mode, rtx x)
2786132718Skan{
2787132718Skan  return (DEFAULT_ABI == ABI_V4
2788132718Skan	  && !flag_pic && !TARGET_TOC
2789132718Skan	  && (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == CONST)
2790132718Skan	  && small_data_operand (x, mode));
2791132718Skan}
2792132718Skan
2793169689Skan/* SPE offset addressing is limited to 5-bits worth of double words.  */
2794169689Skan#define SPE_CONST_OFFSET_OK(x) (((x) & ~0xf8) == 0)
2795169689Skan
2796169689Skanbool
2797169689Skanrs6000_legitimate_offset_address_p (enum machine_mode mode, rtx x, int strict)
2798132718Skan{
2799132718Skan  unsigned HOST_WIDE_INT offset, extra;
2800132718Skan
2801132718Skan  if (GET_CODE (x) != PLUS)
2802132718Skan    return false;
2803132718Skan  if (GET_CODE (XEXP (x, 0)) != REG)
2804132718Skan    return false;
2805132718Skan  if (!INT_REG_OK_FOR_BASE_P (XEXP (x, 0), strict))
2806132718Skan    return false;
2807169689Skan  if (legitimate_constant_pool_address_p (x))
2808169689Skan    return true;
2809132718Skan  if (GET_CODE (XEXP (x, 1)) != CONST_INT)
2810132718Skan    return false;
2811132718Skan
2812132718Skan  offset = INTVAL (XEXP (x, 1));
2813132718Skan  extra = 0;
2814132718Skan  switch (mode)
2815132718Skan    {
2816132718Skan    case V16QImode:
2817132718Skan    case V8HImode:
2818132718Skan    case V4SFmode:
2819132718Skan    case V4SImode:
2820169689Skan      /* AltiVec vector modes.  Only reg+reg addressing is valid and
2821169689Skan	 constant offset zero should not occur due to canonicalization.
2822169689Skan	 Allow any offset when not strict before reload.  */
2823169689Skan      return !strict;
2824132718Skan
2825132718Skan    case V4HImode:
2826132718Skan    case V2SImode:
2827132718Skan    case V1DImode:
2828132718Skan    case V2SFmode:
2829132718Skan      /* SPE vector modes.  */
2830132718Skan      return SPE_CONST_OFFSET_OK (offset);
2831132718Skan
2832132718Skan    case DFmode:
2833169689Skan      if (TARGET_E500_DOUBLE)
2834169689Skan	return SPE_CONST_OFFSET_OK (offset);
2835169689Skan
2836132718Skan    case DImode:
2837169689Skan      /* On e500v2, we may have:
2838169689Skan
2839169689Skan	   (subreg:DF (mem:DI (plus (reg) (const_int))) 0).
2840169689Skan
2841169689Skan         Which gets addressed with evldd instructions.  */
2842169689Skan      if (TARGET_E500_DOUBLE)
2843169689Skan	return SPE_CONST_OFFSET_OK (offset);
2844169689Skan
2845161651Skan      if (mode == DFmode || !TARGET_POWERPC64)
2846132718Skan	extra = 4;
2847161651Skan      else if (offset & 3)
2848161651Skan	return false;
2849132718Skan      break;
2850132718Skan
2851132718Skan    case TFmode:
2852132718Skan    case TImode:
2853161651Skan      if (mode == TFmode || !TARGET_POWERPC64)
2854132718Skan	extra = 12;
2855161651Skan      else if (offset & 3)
2856161651Skan	return false;
2857132718Skan      else
2858132718Skan	extra = 8;
2859132718Skan      break;
2860132718Skan
2861132718Skan    default:
2862132718Skan      break;
2863132718Skan    }
2864132718Skan
2865132718Skan  offset += 0x8000;
2866132718Skan  return (offset < 0x10000) && (offset + extra < 0x10000);
2867132718Skan}
2868132718Skan
2869132718Skanstatic bool
2870132718Skanlegitimate_indexed_address_p (rtx x, int strict)
2871132718Skan{
2872132718Skan  rtx op0, op1;
2873132718Skan
2874132718Skan  if (GET_CODE (x) != PLUS)
2875132718Skan    return false;
2876169689Skan
2877132718Skan  op0 = XEXP (x, 0);
2878132718Skan  op1 = XEXP (x, 1);
2879132718Skan
2880169689Skan  /* Recognize the rtl generated by reload which we know will later be
2881169689Skan     replaced with proper base and index regs.  */
2882169689Skan  if (!strict
2883169689Skan      && reload_in_progress
2884169689Skan      && (REG_P (op0) || GET_CODE (op0) == PLUS)
2885169689Skan      && REG_P (op1))
2886169689Skan    return true;
2887132718Skan
2888169689Skan  return (REG_P (op0) && REG_P (op1)
2889169689Skan	  && ((INT_REG_OK_FOR_BASE_P (op0, strict)
2890169689Skan	       && INT_REG_OK_FOR_INDEX_P (op1, strict))
2891169689Skan	      || (INT_REG_OK_FOR_BASE_P (op1, strict)
2892169689Skan		  && INT_REG_OK_FOR_INDEX_P (op0, strict))));
2893132718Skan}
2894132718Skan
2895169689Skaninline bool
2896132718Skanlegitimate_indirect_address_p (rtx x, int strict)
2897132718Skan{
2898132718Skan  return GET_CODE (x) == REG && INT_REG_OK_FOR_BASE_P (x, strict);
2899132718Skan}
2900132718Skan
2901169689Skanbool
2902132718Skanmacho_lo_sum_memory_operand (rtx x, enum machine_mode mode)
2903132718Skan{
2904169689Skan  if (!TARGET_MACHO || !flag_pic
2905169689Skan      || mode != SImode || GET_CODE (x) != MEM)
2906169689Skan    return false;
2907169689Skan  x = XEXP (x, 0);
2908132718Skan
2909132718Skan  if (GET_CODE (x) != LO_SUM)
2910132718Skan    return false;
2911132718Skan  if (GET_CODE (XEXP (x, 0)) != REG)
2912132718Skan    return false;
2913132718Skan  if (!INT_REG_OK_FOR_BASE_P (XEXP (x, 0), 0))
2914132718Skan    return false;
2915132718Skan  x = XEXP (x, 1);
2916132718Skan
2917132718Skan  return CONSTANT_P (x);
2918132718Skan}
2919132718Skan
2920132718Skanstatic bool
2921132718Skanlegitimate_lo_sum_address_p (enum machine_mode mode, rtx x, int strict)
2922132718Skan{
2923132718Skan  if (GET_CODE (x) != LO_SUM)
2924132718Skan    return false;
2925132718Skan  if (GET_CODE (XEXP (x, 0)) != REG)
2926132718Skan    return false;
2927132718Skan  if (!INT_REG_OK_FOR_BASE_P (XEXP (x, 0), strict))
2928132718Skan    return false;
2929169689Skan  /* Restrict addressing for DI because of our SUBREG hackery.  */
2930169689Skan  if (TARGET_E500_DOUBLE && (mode == DFmode || mode == DImode))
2931169689Skan    return false;
2932132718Skan  x = XEXP (x, 1);
2933132718Skan
2934132718Skan  if (TARGET_ELF || TARGET_MACHO)
2935132718Skan    {
2936132718Skan      if (DEFAULT_ABI != ABI_AIX && DEFAULT_ABI != ABI_DARWIN && flag_pic)
2937132718Skan	return false;
2938132718Skan      if (TARGET_TOC)
2939132718Skan	return false;
2940132718Skan      if (GET_MODE_NUNITS (mode) != 1)
2941132718Skan	return false;
2942169689Skan      if (GET_MODE_BITSIZE (mode) > 64
2943169689Skan	  || (GET_MODE_BITSIZE (mode) > 32 && !TARGET_POWERPC64
2944169689Skan	      && !(TARGET_HARD_FLOAT && TARGET_FPRS && mode == DFmode)))
2945132718Skan	return false;
2946132718Skan
2947132718Skan      return CONSTANT_P (x);
2948132718Skan    }
2949132718Skan
2950132718Skan  return false;
2951132718Skan}
2952132718Skan
2953132718Skan
295490075Sobrien/* Try machine-dependent ways of modifying an illegitimate address
295590075Sobrien   to be legitimate.  If we find one, return the new, valid address.
295690075Sobrien   This is used from only one place: `memory_address' in explow.c.
295790075Sobrien
295890075Sobrien   OLDX is the address as it was before break_out_memory_refs was
295990075Sobrien   called.  In some cases it is useful to look at this to decide what
296090075Sobrien   needs to be done.
296190075Sobrien
296290075Sobrien   MODE is passed so that this function can use GO_IF_LEGITIMATE_ADDRESS.
296390075Sobrien
296490075Sobrien   It is always safe for this function to do nothing.  It exists to
296590075Sobrien   recognize opportunities to optimize the output.
296690075Sobrien
296790075Sobrien   On RS/6000, first check for the sum of a register with a constant
296890075Sobrien   integer that is out of range.  If so, generate code to add the
296990075Sobrien   constant with the low-order 16 bits masked to the register and force
297090075Sobrien   this result into another register (this can be done with `cau').
297190075Sobrien   Then generate an address of REG+(CONST&0xffff), allowing for the
297290075Sobrien   possibility of bit 16 being a one.
297390075Sobrien
297490075Sobrien   Then check for the sum of a register and something not constant, try to
297590075Sobrien   load the other things into a register and return the sum.  */
2976132718Skan
297790075Sobrienrtx
2978132718Skanrs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
2979132718Skan			   enum machine_mode mode)
298090075Sobrien{
2981132718Skan  if (GET_CODE (x) == SYMBOL_REF)
2982132718Skan    {
2983132718Skan      enum tls_model model = SYMBOL_REF_TLS_MODEL (x);
2984132718Skan      if (model != 0)
2985132718Skan	return rs6000_legitimize_tls_address (x, model);
2986132718Skan    }
2987132718Skan
2988169689Skan  if (GET_CODE (x) == PLUS
298990075Sobrien      && GET_CODE (XEXP (x, 0)) == REG
299090075Sobrien      && GET_CODE (XEXP (x, 1)) == CONST_INT
299190075Sobrien      && (unsigned HOST_WIDE_INT) (INTVAL (XEXP (x, 1)) + 0x8000) >= 0x10000)
2992169689Skan    {
299390075Sobrien      HOST_WIDE_INT high_int, low_int;
299490075Sobrien      rtx sum;
2995117395Skan      low_int = ((INTVAL (XEXP (x, 1)) & 0xffff) ^ 0x8000) - 0x8000;
2996117395Skan      high_int = INTVAL (XEXP (x, 1)) - low_int;
299790075Sobrien      sum = force_operand (gen_rtx_PLUS (Pmode, XEXP (x, 0),
299890075Sobrien					 GEN_INT (high_int)), 0);
299990075Sobrien      return gen_rtx_PLUS (Pmode, sum, GEN_INT (low_int));
300090075Sobrien    }
3001169689Skan  else if (GET_CODE (x) == PLUS
300290075Sobrien	   && GET_CODE (XEXP (x, 0)) == REG
300390075Sobrien	   && GET_CODE (XEXP (x, 1)) != CONST_INT
300490075Sobrien	   && GET_MODE_NUNITS (mode) == 1
3005117395Skan	   && ((TARGET_HARD_FLOAT && TARGET_FPRS)
3006117395Skan	       || TARGET_POWERPC64
3007169689Skan	       || (((mode != DImode && mode != DFmode) || TARGET_E500_DOUBLE)
3008169689Skan		   && mode != TFmode))
300990075Sobrien	   && (TARGET_POWERPC64 || mode != DImode)
301090075Sobrien	   && mode != TImode)
301190075Sobrien    {
301290075Sobrien      return gen_rtx_PLUS (Pmode, XEXP (x, 0),
301390075Sobrien			   force_reg (Pmode, force_operand (XEXP (x, 1), 0)));
301490075Sobrien    }
301590075Sobrien  else if (ALTIVEC_VECTOR_MODE (mode))
301690075Sobrien    {
301790075Sobrien      rtx reg;
301890075Sobrien
301990075Sobrien      /* Make sure both operands are registers.  */
302090075Sobrien      if (GET_CODE (x) == PLUS)
302190075Sobrien	return gen_rtx_PLUS (Pmode, force_reg (Pmode, XEXP (x, 0)),
302290075Sobrien			     force_reg (Pmode, XEXP (x, 1)));
302390075Sobrien
302490075Sobrien      reg = force_reg (Pmode, x);
302590075Sobrien      return reg;
302690075Sobrien    }
3027169689Skan  else if (SPE_VECTOR_MODE (mode)
3028169689Skan	   || (TARGET_E500_DOUBLE && (mode == DFmode
3029169689Skan				      || mode == DImode)))
3030117395Skan    {
3031169689Skan      if (mode == DImode)
3032169689Skan	return NULL_RTX;
3033117395Skan      /* We accept [reg + reg] and [reg + OFFSET].  */
3034117395Skan
3035117395Skan      if (GET_CODE (x) == PLUS)
3036169689Skan	{
3037169689Skan	  rtx op1 = XEXP (x, 0);
3038169689Skan	  rtx op2 = XEXP (x, 1);
3039117395Skan
3040169689Skan	  op1 = force_reg (Pmode, op1);
3041117395Skan
3042169689Skan	  if (GET_CODE (op2) != REG
3043169689Skan	      && (GET_CODE (op2) != CONST_INT
3044169689Skan		  || !SPE_CONST_OFFSET_OK (INTVAL (op2))))
3045169689Skan	    op2 = force_reg (Pmode, op2);
3046117395Skan
3047169689Skan	  return gen_rtx_PLUS (Pmode, op1, op2);
3048169689Skan	}
3049117395Skan
3050117395Skan      return force_reg (Pmode, x);
3051117395Skan    }
3052132718Skan  else if (TARGET_ELF
3053132718Skan	   && TARGET_32BIT
3054132718Skan	   && TARGET_NO_TOC
3055132718Skan	   && ! flag_pic
305690075Sobrien	   && GET_CODE (x) != CONST_INT
3057169689Skan	   && GET_CODE (x) != CONST_DOUBLE
305890075Sobrien	   && CONSTANT_P (x)
305990075Sobrien	   && GET_MODE_NUNITS (mode) == 1
306090075Sobrien	   && (GET_MODE_BITSIZE (mode) <= 32
3061117395Skan	       || ((TARGET_HARD_FLOAT && TARGET_FPRS) && mode == DFmode)))
306290075Sobrien    {
306390075Sobrien      rtx reg = gen_reg_rtx (Pmode);
3064132718Skan      emit_insn (gen_elf_high (reg, x));
3065132718Skan      return gen_rtx_LO_SUM (Pmode, reg, x);
306690075Sobrien    }
306790075Sobrien  else if (TARGET_MACHO && TARGET_32BIT && TARGET_NO_TOC
306890075Sobrien	   && ! flag_pic
3069132718Skan#if TARGET_MACHO
3070132718Skan	   && ! MACHO_DYNAMIC_NO_PIC_P
3071132718Skan#endif
307290075Sobrien	   && GET_CODE (x) != CONST_INT
3073169689Skan	   && GET_CODE (x) != CONST_DOUBLE
307490075Sobrien	   && CONSTANT_P (x)
3075117395Skan	   && ((TARGET_HARD_FLOAT && TARGET_FPRS) || mode != DFmode)
3076169689Skan	   && mode != DImode
307790075Sobrien	   && mode != TImode)
307890075Sobrien    {
307990075Sobrien      rtx reg = gen_reg_rtx (Pmode);
3080132718Skan      emit_insn (gen_macho_high (reg, x));
3081132718Skan      return gen_rtx_LO_SUM (Pmode, reg, x);
308290075Sobrien    }
3083169689Skan  else if (TARGET_TOC
3084132718Skan	   && constant_pool_expr_p (x)
308590075Sobrien	   && ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (x), Pmode))
308690075Sobrien    {
308790075Sobrien      return create_TOC_reference (x);
308890075Sobrien    }
308990075Sobrien  else
309090075Sobrien    return NULL_RTX;
309190075Sobrien}
309290075Sobrien
3093169689Skan/* This is called from dwarf2out.c via TARGET_ASM_OUTPUT_DWARF_DTPREL.
3094132718Skan   We need to emit DTP-relative relocations.  */
3095132718Skan
3096169689Skanstatic void
3097132718Skanrs6000_output_dwarf_dtprel (FILE *file, int size, rtx x)
3098132718Skan{
3099132718Skan  switch (size)
3100132718Skan    {
3101132718Skan    case 4:
3102132718Skan      fputs ("\t.long\t", file);
3103132718Skan      break;
3104132718Skan    case 8:
3105132718Skan      fputs (DOUBLE_INT_ASM_OP, file);
3106132718Skan      break;
3107132718Skan    default:
3108169689Skan      gcc_unreachable ();
3109132718Skan    }
3110132718Skan  output_addr_const (file, x);
3111132718Skan  fputs ("@dtprel+0x8000", file);
3112132718Skan}
3113132718Skan
3114132718Skan/* Construct the SYMBOL_REF for the tls_get_addr function.  */
3115132718Skan
3116132718Skanstatic GTY(()) rtx rs6000_tls_symbol;
3117132718Skanstatic rtx
3118132718Skanrs6000_tls_get_addr (void)
3119132718Skan{
3120132718Skan  if (!rs6000_tls_symbol)
3121132718Skan    rs6000_tls_symbol = init_one_libfunc ("__tls_get_addr");
3122132718Skan
3123132718Skan  return rs6000_tls_symbol;
3124132718Skan}
3125132718Skan
3126132718Skan/* Construct the SYMBOL_REF for TLS GOT references.  */
3127132718Skan
3128132718Skanstatic GTY(()) rtx rs6000_got_symbol;
3129132718Skanstatic rtx
3130132718Skanrs6000_got_sym (void)
3131132718Skan{
3132132718Skan  if (!rs6000_got_symbol)
3133132718Skan    {
3134132718Skan      rs6000_got_symbol = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
3135132718Skan      SYMBOL_REF_FLAGS (rs6000_got_symbol) |= SYMBOL_FLAG_LOCAL;
3136132718Skan      SYMBOL_REF_FLAGS (rs6000_got_symbol) |= SYMBOL_FLAG_EXTERNAL;
3137169689Skan    }
3138132718Skan
3139132718Skan  return rs6000_got_symbol;
3140132718Skan}
3141132718Skan
3142132718Skan/* ADDR contains a thread-local SYMBOL_REF.  Generate code to compute
3143132718Skan   this (thread-local) address.  */
3144132718Skan
3145132718Skanstatic rtx
3146132718Skanrs6000_legitimize_tls_address (rtx addr, enum tls_model model)
3147132718Skan{
3148132718Skan  rtx dest, insn;
3149132718Skan
3150132718Skan  dest = gen_reg_rtx (Pmode);
3151132718Skan  if (model == TLS_MODEL_LOCAL_EXEC && rs6000_tls_size == 16)
3152132718Skan    {
3153132718Skan      rtx tlsreg;
3154132718Skan
3155132718Skan      if (TARGET_64BIT)
3156132718Skan	{
3157132718Skan	  tlsreg = gen_rtx_REG (Pmode, 13);
3158132718Skan	  insn = gen_tls_tprel_64 (dest, tlsreg, addr);
3159132718Skan	}
3160132718Skan      else
3161132718Skan	{
3162132718Skan	  tlsreg = gen_rtx_REG (Pmode, 2);
3163132718Skan	  insn = gen_tls_tprel_32 (dest, tlsreg, addr);
3164132718Skan	}
3165132718Skan      emit_insn (insn);
3166132718Skan    }
3167132718Skan  else if (model == TLS_MODEL_LOCAL_EXEC && rs6000_tls_size == 32)
3168132718Skan    {
3169132718Skan      rtx tlsreg, tmp;
3170132718Skan
3171132718Skan      tmp = gen_reg_rtx (Pmode);
3172132718Skan      if (TARGET_64BIT)
3173132718Skan	{
3174132718Skan	  tlsreg = gen_rtx_REG (Pmode, 13);
3175132718Skan	  insn = gen_tls_tprel_ha_64 (tmp, tlsreg, addr);
3176132718Skan	}
3177132718Skan      else
3178132718Skan	{
3179132718Skan	  tlsreg = gen_rtx_REG (Pmode, 2);
3180132718Skan	  insn = gen_tls_tprel_ha_32 (tmp, tlsreg, addr);
3181132718Skan	}
3182132718Skan      emit_insn (insn);
3183132718Skan      if (TARGET_64BIT)
3184132718Skan	insn = gen_tls_tprel_lo_64 (dest, tmp, addr);
3185132718Skan      else
3186132718Skan	insn = gen_tls_tprel_lo_32 (dest, tmp, addr);
3187132718Skan      emit_insn (insn);
3188132718Skan    }
3189132718Skan  else
3190132718Skan    {
3191132718Skan      rtx r3, got, tga, tmp1, tmp2, eqv;
3192132718Skan
3193169689Skan      /* We currently use relocations like @got@tlsgd for tls, which
3194169689Skan	 means the linker will handle allocation of tls entries, placing
3195169689Skan	 them in the .got section.  So use a pointer to the .got section,
3196169689Skan	 not one to secondary TOC sections used by 64-bit -mminimal-toc,
3197169689Skan	 or to secondary GOT sections used by 32-bit -fPIC.  */
3198132718Skan      if (TARGET_64BIT)
3199161651Skan	got = gen_rtx_REG (Pmode, 2);
3200132718Skan      else
3201132718Skan	{
3202132718Skan	  if (flag_pic == 1)
3203132718Skan	    got = gen_rtx_REG (Pmode, RS6000_PIC_OFFSET_TABLE_REGNUM);
3204132718Skan	  else
3205132718Skan	    {
3206132718Skan	      rtx gsym = rs6000_got_sym ();
3207132718Skan	      got = gen_reg_rtx (Pmode);
3208132718Skan	      if (flag_pic == 0)
3209132718Skan		rs6000_emit_move (got, gsym, Pmode);
3210132718Skan	      else
3211132718Skan		{
3212146895Skan		  rtx tempLR, tmp3, mem;
3213132718Skan		  rtx first, last;
3214132718Skan
3215132718Skan		  tempLR = gen_reg_rtx (Pmode);
3216132718Skan		  tmp1 = gen_reg_rtx (Pmode);
3217132718Skan		  tmp2 = gen_reg_rtx (Pmode);
3218132718Skan		  tmp3 = gen_reg_rtx (Pmode);
3219169689Skan		  mem = gen_const_mem (Pmode, tmp1);
3220132718Skan
3221146895Skan		  first = emit_insn (gen_load_toc_v4_PIC_1b (tempLR, gsym));
3222132718Skan		  emit_move_insn (tmp1, tempLR);
3223132718Skan		  emit_move_insn (tmp2, mem);
3224132718Skan		  emit_insn (gen_addsi3 (tmp3, tmp1, tmp2));
3225132718Skan		  last = emit_move_insn (got, tmp3);
3226132718Skan		  REG_NOTES (last) = gen_rtx_EXPR_LIST (REG_EQUAL, gsym,
3227132718Skan							REG_NOTES (last));
3228132718Skan		  REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last,
3229132718Skan							 REG_NOTES (first));
3230132718Skan		  REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first,
3231132718Skan							REG_NOTES (last));
3232132718Skan		}
3233132718Skan	    }
3234132718Skan	}
3235132718Skan
3236132718Skan      if (model == TLS_MODEL_GLOBAL_DYNAMIC)
3237132718Skan	{
3238132718Skan	  r3 = gen_rtx_REG (Pmode, 3);
3239132718Skan	  if (TARGET_64BIT)
3240132718Skan	    insn = gen_tls_gd_64 (r3, got, addr);
3241132718Skan	  else
3242132718Skan	    insn = gen_tls_gd_32 (r3, got, addr);
3243132718Skan	  start_sequence ();
3244132718Skan	  emit_insn (insn);
3245132718Skan	  tga = gen_rtx_MEM (Pmode, rs6000_tls_get_addr ());
3246132718Skan	  insn = gen_call_value (r3, tga, const0_rtx, const0_rtx);
3247132718Skan	  insn = emit_call_insn (insn);
3248132718Skan	  CONST_OR_PURE_CALL_P (insn) = 1;
3249132718Skan	  use_reg (&CALL_INSN_FUNCTION_USAGE (insn), r3);
3250132718Skan	  insn = get_insns ();
3251132718Skan	  end_sequence ();
3252132718Skan	  emit_libcall_block (insn, dest, r3, addr);
3253132718Skan	}
3254132718Skan      else if (model == TLS_MODEL_LOCAL_DYNAMIC)
3255132718Skan	{
3256132718Skan	  r3 = gen_rtx_REG (Pmode, 3);
3257132718Skan	  if (TARGET_64BIT)
3258132718Skan	    insn = gen_tls_ld_64 (r3, got);
3259132718Skan	  else
3260132718Skan	    insn = gen_tls_ld_32 (r3, got);
3261132718Skan	  start_sequence ();
3262132718Skan	  emit_insn (insn);
3263132718Skan	  tga = gen_rtx_MEM (Pmode, rs6000_tls_get_addr ());
3264132718Skan	  insn = gen_call_value (r3, tga, const0_rtx, const0_rtx);
3265132718Skan	  insn = emit_call_insn (insn);
3266132718Skan	  CONST_OR_PURE_CALL_P (insn) = 1;
3267132718Skan	  use_reg (&CALL_INSN_FUNCTION_USAGE (insn), r3);
3268132718Skan	  insn = get_insns ();
3269132718Skan	  end_sequence ();
3270132718Skan	  tmp1 = gen_reg_rtx (Pmode);
3271132718Skan	  eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx),
3272132718Skan				UNSPEC_TLSLD);
3273132718Skan	  emit_libcall_block (insn, tmp1, r3, eqv);
3274132718Skan	  if (rs6000_tls_size == 16)
3275132718Skan	    {
3276132718Skan	      if (TARGET_64BIT)
3277132718Skan		insn = gen_tls_dtprel_64 (dest, tmp1, addr);
3278132718Skan	      else
3279132718Skan		insn = gen_tls_dtprel_32 (dest, tmp1, addr);
3280132718Skan	    }
3281132718Skan	  else if (rs6000_tls_size == 32)
3282132718Skan	    {
3283132718Skan	      tmp2 = gen_reg_rtx (Pmode);
3284132718Skan	      if (TARGET_64BIT)
3285132718Skan		insn = gen_tls_dtprel_ha_64 (tmp2, tmp1, addr);
3286132718Skan	      else
3287132718Skan		insn = gen_tls_dtprel_ha_32 (tmp2, tmp1, addr);
3288132718Skan	      emit_insn (insn);
3289132718Skan	      if (TARGET_64BIT)
3290132718Skan		insn = gen_tls_dtprel_lo_64 (dest, tmp2, addr);
3291132718Skan	      else
3292132718Skan		insn = gen_tls_dtprel_lo_32 (dest, tmp2, addr);
3293132718Skan	    }
3294132718Skan	  else
3295132718Skan	    {
3296132718Skan	      tmp2 = gen_reg_rtx (Pmode);
3297132718Skan	      if (TARGET_64BIT)
3298132718Skan		insn = gen_tls_got_dtprel_64 (tmp2, got, addr);
3299132718Skan	      else
3300132718Skan		insn = gen_tls_got_dtprel_32 (tmp2, got, addr);
3301132718Skan	      emit_insn (insn);
3302132718Skan	      insn = gen_rtx_SET (Pmode, dest,
3303132718Skan				  gen_rtx_PLUS (Pmode, tmp2, tmp1));
3304132718Skan	    }
3305132718Skan	  emit_insn (insn);
3306132718Skan	}
3307132718Skan      else
3308132718Skan	{
3309132718Skan	  /* IE, or 64 bit offset LE.  */
3310132718Skan	  tmp2 = gen_reg_rtx (Pmode);
3311132718Skan	  if (TARGET_64BIT)
3312132718Skan	    insn = gen_tls_got_tprel_64 (tmp2, got, addr);
3313132718Skan	  else
3314132718Skan	    insn = gen_tls_got_tprel_32 (tmp2, got, addr);
3315132718Skan	  emit_insn (insn);
3316132718Skan	  if (TARGET_64BIT)
3317132718Skan	    insn = gen_tls_tls_64 (dest, tmp2, addr);
3318132718Skan	  else
3319132718Skan	    insn = gen_tls_tls_32 (dest, tmp2, addr);
3320132718Skan	  emit_insn (insn);
3321132718Skan	}
3322132718Skan    }
3323132718Skan
3324132718Skan  return dest;
3325132718Skan}
3326132718Skan
3327132718Skan/* Return 1 if X contains a thread-local symbol.  */
3328132718Skan
3329132718Skanbool
3330132718Skanrs6000_tls_referenced_p (rtx x)
3331132718Skan{
3332132718Skan  if (! TARGET_HAVE_TLS)
3333132718Skan    return false;
3334132718Skan
3335132718Skan  return for_each_rtx (&x, &rs6000_tls_symbol_ref_1, 0);
3336132718Skan}
3337132718Skan
3338132718Skan/* Return 1 if *X is a thread-local symbol.  This is the same as
3339132718Skan   rs6000_tls_symbol_ref except for the type of the unused argument.  */
3340132718Skan
3341169689Skanstatic int
3342132718Skanrs6000_tls_symbol_ref_1 (rtx *x, void *data ATTRIBUTE_UNUSED)
3343132718Skan{
3344132718Skan  return RS6000_SYMBOL_REF_TLS_P (*x);
3345132718Skan}
3346132718Skan
334790075Sobrien/* The convention appears to be to define this wherever it is used.
334890075Sobrien   With legitimize_reload_address now defined here, REG_MODE_OK_FOR_BASE_P
334990075Sobrien   is now used here.  */
335090075Sobrien#ifndef REG_MODE_OK_FOR_BASE_P
335190075Sobrien#define REG_MODE_OK_FOR_BASE_P(REGNO, MODE) REG_OK_FOR_BASE_P (REGNO)
335290075Sobrien#endif
335390075Sobrien
335490075Sobrien/* Our implementation of LEGITIMIZE_RELOAD_ADDRESS.  Returns a value to
335590075Sobrien   replace the input X, or the original X if no replacement is called for.
335690075Sobrien   The output parameter *WIN is 1 if the calling macro should goto WIN,
335790075Sobrien   0 if it should not.
335890075Sobrien
335990075Sobrien   For RS/6000, we wish to handle large displacements off a base
336090075Sobrien   register by splitting the addend across an addiu/addis and the mem insn.
336190075Sobrien   This cuts number of extra insns needed from 3 to 1.
336290075Sobrien
336390075Sobrien   On Darwin, we use this to generate code for floating point constants.
336490075Sobrien   A movsf_low is generated so we wind up with 2 instructions rather than 3.
336590075Sobrien   The Darwin code is inside #if TARGET_MACHO because only then is
336690075Sobrien   machopic_function_base_name() defined.  */
336790075Sobrienrtx
3368169689Skanrs6000_legitimize_reload_address (rtx x, enum machine_mode mode,
3369169689Skan				  int opnum, int type,
3370169689Skan				  int ind_levels ATTRIBUTE_UNUSED, int *win)
337190075Sobrien{
3372169689Skan  /* We must recognize output that we have already generated ourselves.  */
337390075Sobrien  if (GET_CODE (x) == PLUS
337490075Sobrien      && GET_CODE (XEXP (x, 0)) == PLUS
337590075Sobrien      && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG
337690075Sobrien      && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
337790075Sobrien      && GET_CODE (XEXP (x, 1)) == CONST_INT)
337890075Sobrien    {
337990075Sobrien      push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
3380169689Skan		   BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0,
3381169689Skan		   opnum, (enum reload_type)type);
338290075Sobrien      *win = 1;
338390075Sobrien      return x;
338490075Sobrien    }
338596263Sobrien
338690075Sobrien#if TARGET_MACHO
338790075Sobrien  if (DEFAULT_ABI == ABI_DARWIN && flag_pic
338890075Sobrien      && GET_CODE (x) == LO_SUM
338990075Sobrien      && GET_CODE (XEXP (x, 0)) == PLUS
339090075Sobrien      && XEXP (XEXP (x, 0), 0) == pic_offset_table_rtx
339190075Sobrien      && GET_CODE (XEXP (XEXP (x, 0), 1)) == HIGH
339290075Sobrien      && GET_CODE (XEXP (XEXP (XEXP (x, 0), 1), 0)) == CONST
339390075Sobrien      && XEXP (XEXP (XEXP (x, 0), 1), 0) == XEXP (x, 1)
339490075Sobrien      && GET_CODE (XEXP (XEXP (x, 1), 0)) == MINUS
339590075Sobrien      && GET_CODE (XEXP (XEXP (XEXP (x, 1), 0), 0)) == SYMBOL_REF
339690075Sobrien      && GET_CODE (XEXP (XEXP (XEXP (x, 1), 0), 1)) == SYMBOL_REF)
339790075Sobrien    {
339890075Sobrien      /* Result of previous invocation of this function on Darwin
339990075Sobrien	 floating point constant.  */
340090075Sobrien      push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
3401169689Skan		   BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
3402169689Skan		   opnum, (enum reload_type)type);
340390075Sobrien      *win = 1;
340490075Sobrien      return x;
340590075Sobrien    }
340690075Sobrien#endif
3407161651Skan
3408161651Skan  /* Force ld/std non-word aligned offset into base register by wrapping
3409161651Skan     in offset 0.  */
341090075Sobrien  if (GET_CODE (x) == PLUS
341190075Sobrien      && GET_CODE (XEXP (x, 0)) == REG
3412161651Skan      && REGNO (XEXP (x, 0)) < 32
3413161651Skan      && REG_MODE_OK_FOR_BASE_P (XEXP (x, 0), mode)
3414161651Skan      && GET_CODE (XEXP (x, 1)) == CONST_INT
3415161651Skan      && (INTVAL (XEXP (x, 1)) & 3) != 0
3416169689Skan      && !ALTIVEC_VECTOR_MODE (mode)
3417161651Skan      && GET_MODE_SIZE (mode) >= UNITS_PER_WORD
3418161651Skan      && TARGET_POWERPC64)
3419161651Skan    {
3420161651Skan      x = gen_rtx_PLUS (GET_MODE (x), x, GEN_INT (0));
3421161651Skan      push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
3422161651Skan		   BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0,
3423161651Skan		   opnum, (enum reload_type) type);
3424161651Skan      *win = 1;
3425161651Skan      return x;
3426161651Skan    }
3427161651Skan
3428161651Skan  if (GET_CODE (x) == PLUS
3429161651Skan      && GET_CODE (XEXP (x, 0)) == REG
343090075Sobrien      && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER
343190075Sobrien      && REG_MODE_OK_FOR_BASE_P (XEXP (x, 0), mode)
343296263Sobrien      && GET_CODE (XEXP (x, 1)) == CONST_INT
3433117395Skan      && !SPE_VECTOR_MODE (mode)
3434169689Skan      && !(TARGET_E500_DOUBLE && (mode == DFmode
3435169689Skan				  || mode == DImode))
343696263Sobrien      && !ALTIVEC_VECTOR_MODE (mode))
343790075Sobrien    {
343890075Sobrien      HOST_WIDE_INT val = INTVAL (XEXP (x, 1));
343990075Sobrien      HOST_WIDE_INT low = ((val & 0xffff) ^ 0x8000) - 0x8000;
344090075Sobrien      HOST_WIDE_INT high
3441169689Skan	= (((val - low) & 0xffffffff) ^ 0x80000000) - 0x80000000;
344290075Sobrien
344390075Sobrien      /* Check for 32-bit overflow.  */
344490075Sobrien      if (high + low != val)
3445169689Skan	{
344690075Sobrien	  *win = 0;
344790075Sobrien	  return x;
344890075Sobrien	}
344990075Sobrien
345090075Sobrien      /* Reload the high part into a base reg; leave the low part
3451169689Skan	 in the mem directly.  */
345290075Sobrien
345390075Sobrien      x = gen_rtx_PLUS (GET_MODE (x),
3454169689Skan			gen_rtx_PLUS (GET_MODE (x), XEXP (x, 0),
3455169689Skan				      GEN_INT (high)),
3456169689Skan			GEN_INT (low));
345790075Sobrien
345890075Sobrien      push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
3459169689Skan		   BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0,
3460169689Skan		   opnum, (enum reload_type)type);
346190075Sobrien      *win = 1;
346290075Sobrien      return x;
346390075Sobrien    }
3464161651Skan
3465169689Skan  if (GET_CODE (x) == SYMBOL_REF
3466169689Skan      && !ALTIVEC_VECTOR_MODE (mode)
3467169689Skan      && !SPE_VECTOR_MODE (mode)
346890075Sobrien#if TARGET_MACHO
346990075Sobrien      && DEFAULT_ABI == ABI_DARWIN
3470132718Skan      && (flag_pic || MACHO_DYNAMIC_NO_PIC_P)
3471169689Skan#else
3472169689Skan      && DEFAULT_ABI == ABI_V4
3473169689Skan      && !flag_pic
3474169689Skan#endif
3475169689Skan      /* Don't do this for TFmode, since the result isn't offsettable.
3476169689Skan	 The same goes for DImode without 64-bit gprs and DFmode
3477169689Skan	 without fprs.  */
3478169689Skan      && mode != TFmode
3479169689Skan      && (mode != DImode || TARGET_POWERPC64)
3480169689Skan      && (mode != DFmode || TARGET_POWERPC64
3481169689Skan	  || (TARGET_FPRS && TARGET_HARD_FLOAT)))
348290075Sobrien    {
3483169689Skan#if TARGET_MACHO
3484132718Skan      if (flag_pic)
3485132718Skan	{
3486132718Skan	  rtx offset = gen_rtx_CONST (Pmode,
3487132718Skan			 gen_rtx_MINUS (Pmode, x,
3488169689Skan					machopic_function_base_sym ()));
3489132718Skan	  x = gen_rtx_LO_SUM (GET_MODE (x),
3490132718Skan		gen_rtx_PLUS (Pmode, pic_offset_table_rtx,
3491132718Skan		  gen_rtx_HIGH (Pmode, offset)), offset);
3492132718Skan	}
3493132718Skan      else
3494169689Skan#endif
3495132718Skan	x = gen_rtx_LO_SUM (GET_MODE (x),
3496169689Skan	      gen_rtx_HIGH (Pmode, x), x);
3497132718Skan
349890075Sobrien      push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
3499132718Skan		   BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
3500132718Skan		   opnum, (enum reload_type)type);
350190075Sobrien      *win = 1;
350290075Sobrien      return x;
350390075Sobrien    }
3504161651Skan
3505169689Skan  /* Reload an offset address wrapped by an AND that represents the
3506169689Skan     masking of the lower bits.  Strip the outer AND and let reload
3507169689Skan     convert the offset address into an indirect address.  */
3508169689Skan  if (TARGET_ALTIVEC
3509169689Skan      && ALTIVEC_VECTOR_MODE (mode)
3510169689Skan      && GET_CODE (x) == AND
3511169689Skan      && GET_CODE (XEXP (x, 0)) == PLUS
3512169689Skan      && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG
3513169689Skan      && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
3514169689Skan      && GET_CODE (XEXP (x, 1)) == CONST_INT
3515169689Skan      && INTVAL (XEXP (x, 1)) == -16)
3516169689Skan    {
3517169689Skan      x = XEXP (x, 0);
3518169689Skan      *win = 1;
3519169689Skan      return x;
3520169689Skan    }
3521169689Skan
352290075Sobrien  if (TARGET_TOC
3523132718Skan      && constant_pool_expr_p (x)
352496263Sobrien      && ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (x), mode))
352590075Sobrien    {
3526169689Skan      x = create_TOC_reference (x);
352790075Sobrien      *win = 1;
352890075Sobrien      return x;
352990075Sobrien    }
353090075Sobrien  *win = 0;
353190075Sobrien  return x;
3532169689Skan}
353390075Sobrien
353490075Sobrien/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression
353590075Sobrien   that is a valid memory address for an instruction.
353690075Sobrien   The MODE argument is the machine mode for the MEM expression
353790075Sobrien   that wants to use this address.
353890075Sobrien
353990075Sobrien   On the RS/6000, there are four valid address: a SYMBOL_REF that
354090075Sobrien   refers to a constant pool entry of an address (or the sum of it
354190075Sobrien   plus a constant), a short (16-bit signed) constant plus a register,
354290075Sobrien   the sum of two registers, or a register indirect, possibly with an
3543132718Skan   auto-increment.  For DFmode and DImode with a constant plus register,
354490075Sobrien   we must ensure that both words are addressable or PowerPC64 with offset
354590075Sobrien   word aligned.
354690075Sobrien
354790075Sobrien   For modes spanning multiple registers (DFmode in 32-bit GPRs,
3548169689Skan   32-bit DImode, TImode, TFmode), indexed addressing cannot be used because
354990075Sobrien   adjacent memory cells are accessed by adding word-sized offsets
355090075Sobrien   during assembly output.  */
355190075Sobrienint
3552132718Skanrs6000_legitimate_address (enum machine_mode mode, rtx x, int reg_ok_strict)
355390075Sobrien{
3554169689Skan  /* If this is an unaligned stvx/ldvx type address, discard the outer AND.  */
3555169689Skan  if (TARGET_ALTIVEC
3556169689Skan      && ALTIVEC_VECTOR_MODE (mode)
3557169689Skan      && GET_CODE (x) == AND
3558169689Skan      && GET_CODE (XEXP (x, 1)) == CONST_INT
3559169689Skan      && INTVAL (XEXP (x, 1)) == -16)
3560169689Skan    x = XEXP (x, 0);
3561169689Skan
3562132718Skan  if (RS6000_SYMBOL_REF_TLS_P (x))
3563132718Skan    return 0;
3564132718Skan  if (legitimate_indirect_address_p (x, reg_ok_strict))
356590075Sobrien    return 1;
356690075Sobrien  if ((GET_CODE (x) == PRE_INC || GET_CODE (x) == PRE_DEC)
3567107590Sobrien      && !ALTIVEC_VECTOR_MODE (mode)
3568117395Skan      && !SPE_VECTOR_MODE (mode)
3569169689Skan      && mode != TFmode
3570169689Skan      /* Restrict addressing for DI because of our SUBREG hackery.  */
3571169689Skan      && !(TARGET_E500_DOUBLE && (mode == DFmode || mode == DImode))
357290075Sobrien      && TARGET_UPDATE
3573132718Skan      && legitimate_indirect_address_p (XEXP (x, 0), reg_ok_strict))
357490075Sobrien    return 1;
3575132718Skan  if (legitimate_small_data_p (mode, x))
357690075Sobrien    return 1;
3577132718Skan  if (legitimate_constant_pool_address_p (x))
357890075Sobrien    return 1;
357990075Sobrien  /* If not REG_OK_STRICT (before reload) let pass any stack offset.  */
358090075Sobrien  if (! reg_ok_strict
358190075Sobrien      && GET_CODE (x) == PLUS
358290075Sobrien      && GET_CODE (XEXP (x, 0)) == REG
3583132718Skan      && (XEXP (x, 0) == virtual_stack_vars_rtx
3584132718Skan	  || XEXP (x, 0) == arg_pointer_rtx)
358590075Sobrien      && GET_CODE (XEXP (x, 1)) == CONST_INT)
358690075Sobrien    return 1;
3587169689Skan  if (rs6000_legitimate_offset_address_p (mode, x, reg_ok_strict))
358890075Sobrien    return 1;
358990075Sobrien  if (mode != TImode
3590169689Skan      && mode != TFmode
3591117395Skan      && ((TARGET_HARD_FLOAT && TARGET_FPRS)
3592117395Skan	  || TARGET_POWERPC64
3593169689Skan	  || ((mode != DFmode || TARGET_E500_DOUBLE) && mode != TFmode))
359490075Sobrien      && (TARGET_POWERPC64 || mode != DImode)
3595132718Skan      && legitimate_indexed_address_p (x, reg_ok_strict))
359690075Sobrien    return 1;
3597132718Skan  if (legitimate_lo_sum_address_p (mode, x, reg_ok_strict))
359890075Sobrien    return 1;
359990075Sobrien  return 0;
360090075Sobrien}
3601132718Skan
3602132718Skan/* Go to LABEL if ADDR (a legitimate address expression)
3603132718Skan   has an effect that depends on the machine mode it is used for.
3604132718Skan
3605132718Skan   On the RS/6000 this is true of all integral offsets (since AltiVec
3606132718Skan   modes don't allow them) or is a pre-increment or decrement.
3607132718Skan
3608132718Skan   ??? Except that due to conceptual problems in offsettable_address_p
3609132718Skan   we can't really report the problems of integral offsets.  So leave
3610169689Skan   this assuming that the adjustable offset must be valid for the
3611132718Skan   sub-words of a TFmode operand, which is what we had before.  */
3612132718Skan
3613132718Skanbool
3614132718Skanrs6000_mode_dependent_address (rtx addr)
3615132718Skan{
3616132718Skan  switch (GET_CODE (addr))
3617132718Skan    {
3618132718Skan    case PLUS:
3619132718Skan      if (GET_CODE (XEXP (addr, 1)) == CONST_INT)
3620132718Skan	{
3621132718Skan	  unsigned HOST_WIDE_INT val = INTVAL (XEXP (addr, 1));
3622132718Skan	  return val + 12 + 0x8000 >= 0x10000;
3623132718Skan	}
3624132718Skan      break;
3625132718Skan
3626132718Skan    case LO_SUM:
3627132718Skan      return true;
3628132718Skan
3629132718Skan    case PRE_INC:
3630132718Skan    case PRE_DEC:
3631132718Skan      return TARGET_UPDATE;
3632132718Skan
3633132718Skan    default:
3634132718Skan      break;
3635132718Skan    }
3636132718Skan
3637132718Skan  return false;
3638132718Skan}
3639169689Skan
3640169689Skan/* More elaborate version of recog's offsettable_memref_p predicate
3641169689Skan   that works around the ??? note of rs6000_mode_dependent_address.
3642169689Skan   In particular it accepts
3643169689Skan
3644169689Skan     (mem:DI (plus:SI (reg/f:SI 31 31) (const_int 32760 [0x7ff8])))
3645169689Skan
3646169689Skan   in 32-bit mode, that the recog predicate rejects.  */
3647169689Skan
3648169689Skanbool
3649169689Skanrs6000_offsettable_memref_p (rtx op)
3650169689Skan{
3651169689Skan  if (!MEM_P (op))
3652169689Skan    return false;
3653169689Skan
3654169689Skan  /* First mimic offsettable_memref_p.  */
3655169689Skan  if (offsettable_address_p (1, GET_MODE (op), XEXP (op, 0)))
3656169689Skan    return true;
3657169689Skan
3658169689Skan  /* offsettable_address_p invokes rs6000_mode_dependent_address, but
3659169689Skan     the latter predicate knows nothing about the mode of the memory
3660169689Skan     reference and, therefore, assumes that it is the largest supported
3661169689Skan     mode (TFmode).  As a consequence, legitimate offsettable memory
3662169689Skan     references are rejected.  rs6000_legitimate_offset_address_p contains
3663169689Skan     the correct logic for the PLUS case of rs6000_mode_dependent_address.  */
3664169689Skan  return rs6000_legitimate_offset_address_p (GET_MODE (op), XEXP (op, 0), 1);
3665169689Skan}
3666169689Skan
3667169689Skan/* Return number of consecutive hard regs needed starting at reg REGNO
3668169689Skan   to hold something of mode MODE.
3669169689Skan   This is ordinarily the length in words of a value of mode MODE
3670169689Skan   but can be less for certain modes in special long registers.
3671169689Skan
3672169689Skan   For the SPE, GPRs are 64 bits but only 32 bits are visible in
3673169689Skan   scalar instructions.  The upper 32 bits are only available to the
3674169689Skan   SIMD instructions.
3675169689Skan
3676169689Skan   POWER and PowerPC GPRs hold 32 bits worth;
3677169689Skan   PowerPC64 GPRs and FPRs point register holds 64 bits worth.  */
3678169689Skan
3679169689Skanint
3680169689Skanrs6000_hard_regno_nregs (int regno, enum machine_mode mode)
3681169689Skan{
3682169689Skan  if (FP_REGNO_P (regno))
3683169689Skan    return (GET_MODE_SIZE (mode) + UNITS_PER_FP_WORD - 1) / UNITS_PER_FP_WORD;
3684169689Skan
3685169689Skan  if (SPE_SIMD_REGNO_P (regno) && TARGET_SPE && SPE_VECTOR_MODE (mode))
3686169689Skan    return (GET_MODE_SIZE (mode) + UNITS_PER_SPE_WORD - 1) / UNITS_PER_SPE_WORD;
3687169689Skan
3688169689Skan  if (ALTIVEC_REGNO_P (regno))
3689169689Skan    return
3690169689Skan      (GET_MODE_SIZE (mode) + UNITS_PER_ALTIVEC_WORD - 1) / UNITS_PER_ALTIVEC_WORD;
3691169689Skan
3692169689Skan  /* The value returned for SCmode in the E500 double case is 2 for
3693169689Skan     ABI compatibility; storing an SCmode value in a single register
3694169689Skan     would require function_arg and rs6000_spe_function_arg to handle
3695169689Skan     SCmode so as to pass the value correctly in a pair of
3696169689Skan     registers.  */
3697169689Skan  if (TARGET_E500_DOUBLE && FLOAT_MODE_P (mode) && mode != SCmode)
3698169689Skan    return (GET_MODE_SIZE (mode) + UNITS_PER_FP_WORD - 1) / UNITS_PER_FP_WORD;
3699169689Skan
3700169689Skan  return (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
3701169689Skan}
3702169689Skan
3703169689Skan/* Change register usage conditional on target flags.  */
3704169689Skanvoid
3705169689Skanrs6000_conditional_register_usage (void)
3706169689Skan{
3707169689Skan  int i;
3708169689Skan
3709169689Skan  /* Set MQ register fixed (already call_used) if not POWER
3710169689Skan     architecture (RIOS1, RIOS2, RSC, and PPC601) so that it will not
3711169689Skan     be allocated.  */
3712169689Skan  if (! TARGET_POWER)
3713169689Skan    fixed_regs[64] = 1;
3714169689Skan
3715169689Skan  /* 64-bit AIX and Linux reserve GPR13 for thread-private data.  */
3716169689Skan  if (TARGET_64BIT)
3717169689Skan    fixed_regs[13] = call_used_regs[13]
3718169689Skan      = call_really_used_regs[13] = 1;
3719169689Skan
3720169689Skan  /* Conditionally disable FPRs.  */
3721169689Skan  if (TARGET_SOFT_FLOAT || !TARGET_FPRS)
3722169689Skan    for (i = 32; i < 64; i++)
3723169689Skan      fixed_regs[i] = call_used_regs[i]
3724169689Skan	= call_really_used_regs[i] = 1;
3725169689Skan
3726169689Skan  /* The TOC register is not killed across calls in a way that is
3727169689Skan     visible to the compiler.  */
3728169689Skan  if (DEFAULT_ABI == ABI_AIX)
3729169689Skan    call_really_used_regs[2] = 0;
3730169689Skan
3731169689Skan  if (DEFAULT_ABI == ABI_V4
3732169689Skan      && PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM
3733169689Skan      && flag_pic == 2)
3734169689Skan    fixed_regs[RS6000_PIC_OFFSET_TABLE_REGNUM] = 1;
3735169689Skan
3736169689Skan  if (DEFAULT_ABI == ABI_V4
3737169689Skan      && PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM
3738169689Skan      && flag_pic == 1)
3739169689Skan    fixed_regs[RS6000_PIC_OFFSET_TABLE_REGNUM]
3740169689Skan      = call_used_regs[RS6000_PIC_OFFSET_TABLE_REGNUM]
3741169689Skan      = call_really_used_regs[RS6000_PIC_OFFSET_TABLE_REGNUM] = 1;
3742169689Skan
3743169689Skan  if (DEFAULT_ABI == ABI_DARWIN
3744169689Skan      && PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM)
3745169689Skan      fixed_regs[RS6000_PIC_OFFSET_TABLE_REGNUM]
3746169689Skan      = call_used_regs[RS6000_PIC_OFFSET_TABLE_REGNUM]
3747169689Skan      = call_really_used_regs[RS6000_PIC_OFFSET_TABLE_REGNUM] = 1;
3748169689Skan
3749169689Skan  if (TARGET_TOC && TARGET_MINIMAL_TOC)
3750169689Skan    fixed_regs[RS6000_PIC_OFFSET_TABLE_REGNUM]
3751169689Skan      = call_used_regs[RS6000_PIC_OFFSET_TABLE_REGNUM] = 1;
3752169689Skan
3753169689Skan  if (TARGET_ALTIVEC)
3754169689Skan    global_regs[VSCR_REGNO] = 1;
3755169689Skan
3756169689Skan  if (TARGET_SPE)
3757169689Skan    {
3758169689Skan      global_regs[SPEFSCR_REGNO] = 1;
3759169689Skan      fixed_regs[FIXED_SCRATCH]
3760169689Skan	= call_used_regs[FIXED_SCRATCH]
3761169689Skan	= call_really_used_regs[FIXED_SCRATCH] = 1;
3762169689Skan    }
3763169689Skan
3764169689Skan  if (! TARGET_ALTIVEC)
3765169689Skan    {
3766169689Skan      for (i = FIRST_ALTIVEC_REGNO; i <= LAST_ALTIVEC_REGNO; ++i)
3767169689Skan	fixed_regs[i] = call_used_regs[i] = call_really_used_regs[i] = 1;
3768169689Skan      call_really_used_regs[VRSAVE_REGNO] = 1;
3769169689Skan    }
3770169689Skan
3771169689Skan  if (TARGET_ALTIVEC_ABI)
3772169689Skan    for (i = FIRST_ALTIVEC_REGNO; i < FIRST_ALTIVEC_REGNO + 20; ++i)
3773169689Skan      call_used_regs[i] = call_really_used_regs[i] = 1;
3774169689Skan}
377590075Sobrien
377690075Sobrien/* Try to output insns to set TARGET equal to the constant C if it can
377790075Sobrien   be done in less than N insns.  Do all computations in MODE.
377890075Sobrien   Returns the place where the output has been placed if it can be
377990075Sobrien   done and the insns have been emitted.  If it would take more than N
378090075Sobrien   insns, zero is returned and no insns and emitted.  */
378190075Sobrien
378290075Sobrienrtx
3783169689Skanrs6000_emit_set_const (rtx dest, enum machine_mode mode,
3784132718Skan		       rtx source, int n ATTRIBUTE_UNUSED)
378590075Sobrien{
3786117395Skan  rtx result, insn, set;
378790075Sobrien  HOST_WIDE_INT c0, c1;
378890075Sobrien
3789169689Skan  switch (mode)
379090075Sobrien    {
3791169689Skan      case  QImode:
3792169689Skan    case HImode:
379390075Sobrien      if (dest == NULL)
3794169689Skan	dest = gen_reg_rtx (mode);
379590075Sobrien      emit_insn (gen_rtx_SET (VOIDmode, dest, source));
379690075Sobrien      return dest;
3797169689Skan
3798169689Skan    case SImode:
3799117395Skan      result = no_new_pseudos ? dest : gen_reg_rtx (SImode);
380090075Sobrien
3801117395Skan      emit_insn (gen_rtx_SET (VOIDmode, result,
3802117395Skan			      GEN_INT (INTVAL (source)
3803117395Skan				       & (~ (HOST_WIDE_INT) 0xffff))));
3804117395Skan      emit_insn (gen_rtx_SET (VOIDmode, dest,
3805117395Skan			      gen_rtx_IOR (SImode, result,
3806117395Skan					   GEN_INT (INTVAL (source) & 0xffff))));
3807117395Skan      result = dest;
3808169689Skan      break;
3809169689Skan
3810169689Skan    case DImode:
3811169689Skan      switch (GET_CODE (source))
3812117395Skan	{
3813169689Skan	case CONST_INT:
3814117395Skan	  c0 = INTVAL (source);
3815117395Skan	  c1 = -(c0 < 0);
3816169689Skan	  break;
3817169689Skan
3818169689Skan	case CONST_DOUBLE:
381990075Sobrien#if HOST_BITS_PER_WIDE_INT >= 64
3820117395Skan	  c0 = CONST_DOUBLE_LOW (source);
3821117395Skan	  c1 = -(c0 < 0);
382290075Sobrien#else
3823117395Skan	  c0 = CONST_DOUBLE_LOW (source);
3824117395Skan	  c1 = CONST_DOUBLE_HIGH (source);
382590075Sobrien#endif
3826169689Skan	  break;
3827169689Skan
3828169689Skan	default:
3829169689Skan	  gcc_unreachable ();
3830117395Skan	}
3831117395Skan
3832117395Skan      result = rs6000_emit_set_long_const (dest, c0, c1);
3833169689Skan      break;
3834169689Skan
3835169689Skan    default:
3836169689Skan      gcc_unreachable ();
383790075Sobrien    }
383890075Sobrien
3839117395Skan  insn = get_last_insn ();
3840117395Skan  set = single_set (insn);
3841117395Skan  if (! CONSTANT_P (SET_SRC (set)))
3842117395Skan    set_unique_reg_note (insn, REG_EQUAL, source);
3843117395Skan
3844117395Skan  return result;
384590075Sobrien}
384690075Sobrien
384790075Sobrien/* Having failed to find a 3 insn sequence in rs6000_emit_set_const,
384890075Sobrien   fall back to a straight forward decomposition.  We do this to avoid
384990075Sobrien   exponential run times encountered when looking for longer sequences
385090075Sobrien   with rs6000_emit_set_const.  */
385190075Sobrienstatic rtx
3852132718Skanrs6000_emit_set_long_const (rtx dest, HOST_WIDE_INT c1, HOST_WIDE_INT c2)
385390075Sobrien{
385490075Sobrien  if (!TARGET_POWERPC64)
385590075Sobrien    {
385690075Sobrien      rtx operand1, operand2;
385790075Sobrien
385890075Sobrien      operand1 = operand_subword_force (dest, WORDS_BIG_ENDIAN == 0,
385990075Sobrien					DImode);
386090075Sobrien      operand2 = operand_subword_force (dest, WORDS_BIG_ENDIAN != 0,
386190075Sobrien					DImode);
386290075Sobrien      emit_move_insn (operand1, GEN_INT (c1));
386390075Sobrien      emit_move_insn (operand2, GEN_INT (c2));
386490075Sobrien    }
386590075Sobrien  else
386690075Sobrien    {
386790075Sobrien      HOST_WIDE_INT ud1, ud2, ud3, ud4;
386890075Sobrien
386990075Sobrien      ud1 = c1 & 0xffff;
387090075Sobrien      ud2 = (c1 & 0xffff0000) >> 16;
387190075Sobrien#if HOST_BITS_PER_WIDE_INT >= 64
387290075Sobrien      c2 = c1 >> 32;
387390075Sobrien#endif
387490075Sobrien      ud3 = c2 & 0xffff;
387590075Sobrien      ud4 = (c2 & 0xffff0000) >> 16;
387690075Sobrien
3877169689Skan      if ((ud4 == 0xffff && ud3 == 0xffff && ud2 == 0xffff && (ud1 & 0x8000))
387890075Sobrien	  || (ud4 == 0 && ud3 == 0 && ud2 == 0 && ! (ud1 & 0x8000)))
387990075Sobrien	{
388090075Sobrien	  if (ud1 & 0x8000)
3881132718Skan	    emit_move_insn (dest, GEN_INT (((ud1 ^ 0x8000) -  0x8000)));
388290075Sobrien	  else
388390075Sobrien	    emit_move_insn (dest, GEN_INT (ud1));
388490075Sobrien	}
388590075Sobrien
3886169689Skan      else if ((ud4 == 0xffff && ud3 == 0xffff && (ud2 & 0x8000))
388790075Sobrien	       || (ud4 == 0 && ud3 == 0 && ! (ud2 & 0x8000)))
388890075Sobrien	{
388990075Sobrien	  if (ud2 & 0x8000)
3890169689Skan	    emit_move_insn (dest, GEN_INT (((ud2 << 16) ^ 0x80000000)
389190075Sobrien					   - 0x80000000));
389290075Sobrien	  else
389390075Sobrien	    emit_move_insn (dest, GEN_INT (ud2 << 16));
389490075Sobrien	  if (ud1 != 0)
389590075Sobrien	    emit_move_insn (dest, gen_rtx_IOR (DImode, dest, GEN_INT (ud1)));
389690075Sobrien	}
3897169689Skan      else if ((ud4 == 0xffff && (ud3 & 0x8000))
389890075Sobrien	       || (ud4 == 0 && ! (ud3 & 0x8000)))
389990075Sobrien	{
390090075Sobrien	  if (ud3 & 0x8000)
3901169689Skan	    emit_move_insn (dest, GEN_INT (((ud3 << 16) ^ 0x80000000)
390290075Sobrien					   - 0x80000000));
390390075Sobrien	  else
390490075Sobrien	    emit_move_insn (dest, GEN_INT (ud3 << 16));
390590075Sobrien
390690075Sobrien	  if (ud2 != 0)
390790075Sobrien	    emit_move_insn (dest, gen_rtx_IOR (DImode, dest, GEN_INT (ud2)));
390890075Sobrien	  emit_move_insn (dest, gen_rtx_ASHIFT (DImode, dest, GEN_INT (16)));
390990075Sobrien	  if (ud1 != 0)
391090075Sobrien	    emit_move_insn (dest, gen_rtx_IOR (DImode, dest, GEN_INT (ud1)));
391190075Sobrien	}
3912169689Skan      else
391390075Sobrien	{
391490075Sobrien	  if (ud4 & 0x8000)
3915169689Skan	    emit_move_insn (dest, GEN_INT (((ud4 << 16) ^ 0x80000000)
391690075Sobrien					   - 0x80000000));
391790075Sobrien	  else
391890075Sobrien	    emit_move_insn (dest, GEN_INT (ud4 << 16));
391990075Sobrien
392090075Sobrien	  if (ud3 != 0)
392190075Sobrien	    emit_move_insn (dest, gen_rtx_IOR (DImode, dest, GEN_INT (ud3)));
392290075Sobrien
392390075Sobrien	  emit_move_insn (dest, gen_rtx_ASHIFT (DImode, dest, GEN_INT (32)));
392490075Sobrien	  if (ud2 != 0)
3925169689Skan	    emit_move_insn (dest, gen_rtx_IOR (DImode, dest,
3926169689Skan					       GEN_INT (ud2 << 16)));
392790075Sobrien	  if (ud1 != 0)
392890075Sobrien	    emit_move_insn (dest, gen_rtx_IOR (DImode, dest, GEN_INT (ud1)));
392990075Sobrien	}
393090075Sobrien    }
393190075Sobrien  return dest;
393290075Sobrien}
393390075Sobrien
3934169689Skan/* Helper for the following.  Get rid of [r+r] memory refs
3935169689Skan   in cases where it won't work (TImode, TFmode).  */
3936169689Skan
3937169689Skanstatic void
3938169689Skanrs6000_eliminate_indexed_memrefs (rtx operands[2])
3939169689Skan{
3940169689Skan  if (GET_CODE (operands[0]) == MEM
3941169689Skan      && GET_CODE (XEXP (operands[0], 0)) != REG
3942169689Skan      && ! legitimate_constant_pool_address_p (XEXP (operands[0], 0))
3943169689Skan      && ! reload_in_progress)
3944169689Skan    operands[0]
3945169689Skan      = replace_equiv_address (operands[0],
3946169689Skan			       copy_addr_to_reg (XEXP (operands[0], 0)));
3947169689Skan
3948169689Skan  if (GET_CODE (operands[1]) == MEM
3949169689Skan      && GET_CODE (XEXP (operands[1], 0)) != REG
3950169689Skan      && ! legitimate_constant_pool_address_p (XEXP (operands[1], 0))
3951169689Skan      && ! reload_in_progress)
3952169689Skan    operands[1]
3953169689Skan      = replace_equiv_address (operands[1],
3954169689Skan			       copy_addr_to_reg (XEXP (operands[1], 0)));
3955169689Skan}
3956169689Skan
395790075Sobrien/* Emit a move from SOURCE to DEST in mode MODE.  */
395890075Sobrienvoid
3959132718Skanrs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
396090075Sobrien{
396190075Sobrien  rtx operands[2];
396290075Sobrien  operands[0] = dest;
396390075Sobrien  operands[1] = source;
3964169689Skan
396590075Sobrien  /* Sanity checks.  Check that we get CONST_DOUBLE only when we should.  */
396690075Sobrien  if (GET_CODE (operands[1]) == CONST_DOUBLE
396790075Sobrien      && ! FLOAT_MODE_P (mode)
396890075Sobrien      && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
396990075Sobrien    {
397090075Sobrien      /* FIXME.  This should never happen.  */
397190075Sobrien      /* Since it seems that it does, do the safe thing and convert
397290075Sobrien	 to a CONST_INT.  */
3973117395Skan      operands[1] = gen_int_mode (CONST_DOUBLE_LOW (operands[1]), mode);
397490075Sobrien    }
3975169689Skan  gcc_assert (GET_CODE (operands[1]) != CONST_DOUBLE
3976169689Skan	      || FLOAT_MODE_P (mode)
3977169689Skan	      || ((CONST_DOUBLE_HIGH (operands[1]) != 0
3978169689Skan		   || CONST_DOUBLE_LOW (operands[1]) < 0)
3979169689Skan		  && (CONST_DOUBLE_HIGH (operands[1]) != -1
3980169689Skan		      || CONST_DOUBLE_LOW (operands[1]) >= 0)));
398190075Sobrien
398290075Sobrien  /* Check if GCC is setting up a block move that will end up using FP
398390075Sobrien     registers as temporaries.  We must make sure this is acceptable.  */
398490075Sobrien  if (GET_CODE (operands[0]) == MEM
398590075Sobrien      && GET_CODE (operands[1]) == MEM
398690075Sobrien      && mode == DImode
398790075Sobrien      && (SLOW_UNALIGNED_ACCESS (DImode, MEM_ALIGN (operands[0]))
398890075Sobrien	  || SLOW_UNALIGNED_ACCESS (DImode, MEM_ALIGN (operands[1])))
398990075Sobrien      && ! (SLOW_UNALIGNED_ACCESS (SImode, (MEM_ALIGN (operands[0]) > 32
399090075Sobrien					    ? 32 : MEM_ALIGN (operands[0])))
399190075Sobrien	    || SLOW_UNALIGNED_ACCESS (SImode, (MEM_ALIGN (operands[1]) > 32
3992169689Skan					       ? 32
399390075Sobrien					       : MEM_ALIGN (operands[1]))))
399490075Sobrien      && ! MEM_VOLATILE_P (operands [0])
399590075Sobrien      && ! MEM_VOLATILE_P (operands [1]))
399690075Sobrien    {
399790075Sobrien      emit_move_insn (adjust_address (operands[0], SImode, 0),
399890075Sobrien		      adjust_address (operands[1], SImode, 0));
399990075Sobrien      emit_move_insn (adjust_address (operands[0], SImode, 4),
400090075Sobrien		      adjust_address (operands[1], SImode, 4));
400190075Sobrien      return;
400290075Sobrien    }
400390075Sobrien
4004169689Skan  if (!no_new_pseudos && GET_CODE (operands[0]) == MEM
4005169689Skan      && !gpc_reg_operand (operands[1], mode))
4006169689Skan    operands[1] = force_reg (mode, operands[1]);
4007117395Skan
4008117395Skan  if (mode == SFmode && ! TARGET_POWERPC
4009117395Skan      && TARGET_HARD_FLOAT && TARGET_FPRS
401090075Sobrien      && GET_CODE (operands[0]) == MEM)
401190075Sobrien    {
401290075Sobrien      int regnum;
401390075Sobrien
401490075Sobrien      if (reload_in_progress || reload_completed)
401590075Sobrien	regnum = true_regnum (operands[1]);
401690075Sobrien      else if (GET_CODE (operands[1]) == REG)
401790075Sobrien	regnum = REGNO (operands[1]);
401890075Sobrien      else
401990075Sobrien	regnum = -1;
4020169689Skan
402190075Sobrien      /* If operands[1] is a register, on POWER it may have
402290075Sobrien	 double-precision data in it, so truncate it to single
402390075Sobrien	 precision.  */
402490075Sobrien      if (FP_REGNO_P (regnum) || regnum >= FIRST_PSEUDO_REGISTER)
402590075Sobrien	{
402690075Sobrien	  rtx newreg;
402790075Sobrien	  newreg = (no_new_pseudos ? operands[1] : gen_reg_rtx (mode));
402890075Sobrien	  emit_insn (gen_aux_truncdfsf2 (newreg, operands[1]));
402990075Sobrien	  operands[1] = newreg;
403090075Sobrien	}
403190075Sobrien    }
403290075Sobrien
4033132718Skan  /* Recognize the case where operand[1] is a reference to thread-local
4034132718Skan     data and load its address to a register.  */
4035169689Skan  if (rs6000_tls_referenced_p (operands[1]))
4036132718Skan    {
4037169689Skan      enum tls_model model;
4038169689Skan      rtx tmp = operands[1];
4039169689Skan      rtx addend = NULL;
4040169689Skan
4041169689Skan      if (GET_CODE (tmp) == CONST && GET_CODE (XEXP (tmp, 0)) == PLUS)
4042169689Skan	{
4043169689Skan          addend = XEXP (XEXP (tmp, 0), 1);
4044169689Skan	  tmp = XEXP (XEXP (tmp, 0), 0);
4045169689Skan	}
4046169689Skan
4047169689Skan      gcc_assert (GET_CODE (tmp) == SYMBOL_REF);
4048169689Skan      model = SYMBOL_REF_TLS_MODEL (tmp);
4049169689Skan      gcc_assert (model != 0);
4050169689Skan
4051169689Skan      tmp = rs6000_legitimize_tls_address (tmp, model);
4052169689Skan      if (addend)
4053169689Skan	{
4054169689Skan	  tmp = gen_rtx_PLUS (mode, tmp, addend);
4055169689Skan	  tmp = force_operand (tmp, operands[0]);
4056169689Skan	}
4057169689Skan      operands[1] = tmp;
4058132718Skan    }
4059132718Skan
4060117395Skan  /* Handle the case where reload calls us with an invalid address.  */
4061117395Skan  if (reload_in_progress && mode == Pmode
406296263Sobrien      && (! general_operand (operands[1], mode)
4063117395Skan	  || ! nonimmediate_operand (operands[0], mode)))
4064117395Skan    goto emit_set;
4065117395Skan
4066132718Skan  /* 128-bit constant floating-point values on Darwin should really be
4067132718Skan     loaded as two parts.  */
4068169689Skan  if (!TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128
4069132718Skan      && mode == TFmode && GET_CODE (operands[1]) == CONST_DOUBLE)
4070132718Skan    {
4071132718Skan      /* DImode is used, not DFmode, because simplify_gen_subreg doesn't
4072132718Skan	 know how to get a DFmode SUBREG of a TFmode.  */
4073132718Skan      rs6000_emit_move (simplify_gen_subreg (DImode, operands[0], mode, 0),
4074132718Skan			simplify_gen_subreg (DImode, operands[1], mode, 0),
4075132718Skan			DImode);
4076132718Skan      rs6000_emit_move (simplify_gen_subreg (DImode, operands[0], mode,
4077132718Skan					     GET_MODE_SIZE (DImode)),
4078132718Skan			simplify_gen_subreg (DImode, operands[1], mode,
4079132718Skan					     GET_MODE_SIZE (DImode)),
4080132718Skan			DImode);
4081132718Skan      return;
4082132718Skan    }
4083132718Skan
408490075Sobrien  /* FIXME:  In the long term, this switch statement should go away
408590075Sobrien     and be replaced by a sequence of tests based on things like
408690075Sobrien     mode == Pmode.  */
408790075Sobrien  switch (mode)
408890075Sobrien    {
408990075Sobrien    case HImode:
409090075Sobrien    case QImode:
409190075Sobrien      if (CONSTANT_P (operands[1])
409290075Sobrien	  && GET_CODE (operands[1]) != CONST_INT)
409390075Sobrien	operands[1] = force_const_mem (mode, operands[1]);
409490075Sobrien      break;
409590075Sobrien
409690075Sobrien    case TFmode:
4097169689Skan      rs6000_eliminate_indexed_memrefs (operands);
4098169689Skan      /* fall through */
4099169689Skan
410090075Sobrien    case DFmode:
410190075Sobrien    case SFmode:
4102169689Skan      if (CONSTANT_P (operands[1])
410390075Sobrien	  && ! easy_fp_constant (operands[1], mode))
410490075Sobrien	operands[1] = force_const_mem (mode, operands[1]);
410590075Sobrien      break;
4106169689Skan
410790075Sobrien    case V16QImode:
410890075Sobrien    case V8HImode:
410990075Sobrien    case V4SFmode:
411090075Sobrien    case V4SImode:
4111117395Skan    case V4HImode:
4112117395Skan    case V2SFmode:
4113117395Skan    case V2SImode:
4114117395Skan    case V1DImode:
411596263Sobrien      if (CONSTANT_P (operands[1])
4116132718Skan	  && !easy_vector_constant (operands[1], mode))
411790075Sobrien	operands[1] = force_const_mem (mode, operands[1]);
411890075Sobrien      break;
4119169689Skan
412090075Sobrien    case SImode:
412190075Sobrien    case DImode:
412290075Sobrien      /* Use default pattern for address of ELF small data */
412390075Sobrien      if (TARGET_ELF
412490075Sobrien	  && mode == Pmode
412590075Sobrien	  && DEFAULT_ABI == ABI_V4
4126169689Skan	  && (GET_CODE (operands[1]) == SYMBOL_REF
412790075Sobrien	      || GET_CODE (operands[1]) == CONST)
412890075Sobrien	  && small_data_operand (operands[1], mode))
412990075Sobrien	{
413090075Sobrien	  emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
413190075Sobrien	  return;
413290075Sobrien	}
413390075Sobrien
413490075Sobrien      if (DEFAULT_ABI == ABI_V4
413590075Sobrien	  && mode == Pmode && mode == SImode
413690075Sobrien	  && flag_pic == 1 && got_operand (operands[1], mode))
413790075Sobrien	{
413890075Sobrien	  emit_insn (gen_movsi_got (operands[0], operands[1]));
413990075Sobrien	  return;
414090075Sobrien	}
414190075Sobrien
414290075Sobrien      if ((TARGET_ELF || DEFAULT_ABI == ABI_DARWIN)
4143132718Skan	  && TARGET_NO_TOC
4144132718Skan	  && ! flag_pic
414590075Sobrien	  && mode == Pmode
414690075Sobrien	  && CONSTANT_P (operands[1])
414790075Sobrien	  && GET_CODE (operands[1]) != HIGH
414890075Sobrien	  && GET_CODE (operands[1]) != CONST_INT)
414990075Sobrien	{
415090075Sobrien	  rtx target = (no_new_pseudos ? operands[0] : gen_reg_rtx (mode));
415190075Sobrien
415290075Sobrien	  /* If this is a function address on -mcall-aixdesc,
415390075Sobrien	     convert it to the address of the descriptor.  */
415490075Sobrien	  if (DEFAULT_ABI == ABI_AIX
415590075Sobrien	      && GET_CODE (operands[1]) == SYMBOL_REF
415690075Sobrien	      && XSTR (operands[1], 0)[0] == '.')
415790075Sobrien	    {
415890075Sobrien	      const char *name = XSTR (operands[1], 0);
415990075Sobrien	      rtx new_ref;
416090075Sobrien	      while (*name == '.')
416190075Sobrien		name++;
416290075Sobrien	      new_ref = gen_rtx_SYMBOL_REF (Pmode, name);
416390075Sobrien	      CONSTANT_POOL_ADDRESS_P (new_ref)
416490075Sobrien		= CONSTANT_POOL_ADDRESS_P (operands[1]);
4165132718Skan	      SYMBOL_REF_FLAGS (new_ref) = SYMBOL_REF_FLAGS (operands[1]);
416690075Sobrien	      SYMBOL_REF_USED (new_ref) = SYMBOL_REF_USED (operands[1]);
4167169689Skan	      SYMBOL_REF_DATA (new_ref) = SYMBOL_REF_DATA (operands[1]);
416890075Sobrien	      operands[1] = new_ref;
416990075Sobrien	    }
417090075Sobrien
417190075Sobrien	  if (DEFAULT_ABI == ABI_DARWIN)
417290075Sobrien	    {
4173132718Skan#if TARGET_MACHO
4174132718Skan	      if (MACHO_DYNAMIC_NO_PIC_P)
4175132718Skan		{
4176132718Skan		  /* Take care of any required data indirection.  */
4177132718Skan		  operands[1] = rs6000_machopic_legitimize_pic_address (
4178132718Skan				  operands[1], mode, operands[0]);
4179132718Skan		  if (operands[0] != operands[1])
4180132718Skan		    emit_insn (gen_rtx_SET (VOIDmode,
4181169689Skan					    operands[0], operands[1]));
4182132718Skan		  return;
4183132718Skan		}
4184132718Skan#endif
418590075Sobrien	      emit_insn (gen_macho_high (target, operands[1]));
418690075Sobrien	      emit_insn (gen_macho_low (operands[0], target, operands[1]));
418790075Sobrien	      return;
418890075Sobrien	    }
418990075Sobrien
419090075Sobrien	  emit_insn (gen_elf_high (target, operands[1]));
419190075Sobrien	  emit_insn (gen_elf_low (operands[0], target, operands[1]));
419290075Sobrien	  return;
419390075Sobrien	}
419490075Sobrien
419590075Sobrien      /* If this is a SYMBOL_REF that refers to a constant pool entry,
419690075Sobrien	 and we have put it in the TOC, we just need to make a TOC-relative
419790075Sobrien	 reference to it.  */
419890075Sobrien      if (TARGET_TOC
419990075Sobrien	  && GET_CODE (operands[1]) == SYMBOL_REF
4200132718Skan	  && constant_pool_expr_p (operands[1])
420190075Sobrien	  && ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (operands[1]),
420290075Sobrien					      get_pool_mode (operands[1])))
420390075Sobrien	{
420490075Sobrien	  operands[1] = create_TOC_reference (operands[1]);
420590075Sobrien	}
420690075Sobrien      else if (mode == Pmode
420790075Sobrien	       && CONSTANT_P (operands[1])
420890075Sobrien	       && ((GET_CODE (operands[1]) != CONST_INT
420990075Sobrien		    && ! easy_fp_constant (operands[1], mode))
421090075Sobrien		   || (GET_CODE (operands[1]) == CONST_INT
421190075Sobrien		       && num_insns_constant (operands[1], mode) > 2)
421290075Sobrien		   || (GET_CODE (operands[0]) == REG
421390075Sobrien		       && FP_REGNO_P (REGNO (operands[0]))))
421490075Sobrien	       && GET_CODE (operands[1]) != HIGH
4215132718Skan	       && ! legitimate_constant_pool_address_p (operands[1])
4216132718Skan	       && ! toc_relative_expr_p (operands[1]))
421790075Sobrien	{
421890075Sobrien	  /* Emit a USE operation so that the constant isn't deleted if
421990075Sobrien	     expensive optimizations are turned on because nobody
422090075Sobrien	     references it.  This should only be done for operands that
422190075Sobrien	     contain SYMBOL_REFs with CONSTANT_POOL_ADDRESS_P set.
422290075Sobrien	     This should not be done for operands that contain LABEL_REFs.
422390075Sobrien	     For now, we just handle the obvious case.  */
422490075Sobrien	  if (GET_CODE (operands[1]) != LABEL_REF)
422590075Sobrien	    emit_insn (gen_rtx_USE (VOIDmode, operands[1]));
422690075Sobrien
422790075Sobrien#if TARGET_MACHO
422890075Sobrien	  /* Darwin uses a special PIC legitimizer.  */
4229132718Skan	  if (DEFAULT_ABI == ABI_DARWIN && MACHOPIC_INDIRECT)
423090075Sobrien	    {
423190075Sobrien	      operands[1] =
423290075Sobrien		rs6000_machopic_legitimize_pic_address (operands[1], mode,
423390075Sobrien							operands[0]);
423490075Sobrien	      if (operands[0] != operands[1])
423590075Sobrien		emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
423690075Sobrien	      return;
423790075Sobrien	    }
423890075Sobrien#endif
423990075Sobrien
424090075Sobrien	  /* If we are to limit the number of things we put in the TOC and
424190075Sobrien	     this is a symbol plus a constant we can add in one insn,
424290075Sobrien	     just put the symbol in the TOC and add the constant.  Don't do
424390075Sobrien	     this if reload is in progress.  */
424490075Sobrien	  if (GET_CODE (operands[1]) == CONST
424590075Sobrien	      && TARGET_NO_SUM_IN_TOC && ! reload_in_progress
424690075Sobrien	      && GET_CODE (XEXP (operands[1], 0)) == PLUS
424790075Sobrien	      && add_operand (XEXP (XEXP (operands[1], 0), 1), mode)
424890075Sobrien	      && (GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == LABEL_REF
424990075Sobrien		  || GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == SYMBOL_REF)
425090075Sobrien	      && ! side_effects_p (operands[0]))
425190075Sobrien	    {
425290075Sobrien	      rtx sym =
425390075Sobrien		force_const_mem (mode, XEXP (XEXP (operands[1], 0), 0));
425490075Sobrien	      rtx other = XEXP (XEXP (operands[1], 0), 1);
425590075Sobrien
425690075Sobrien	      sym = force_reg (mode, sym);
425790075Sobrien	      if (mode == SImode)
425890075Sobrien		emit_insn (gen_addsi3 (operands[0], sym, other));
425990075Sobrien	      else
426090075Sobrien		emit_insn (gen_adddi3 (operands[0], sym, other));
426190075Sobrien	      return;
426290075Sobrien	    }
426390075Sobrien
426490075Sobrien	  operands[1] = force_const_mem (mode, operands[1]);
426590075Sobrien
4266169689Skan	  if (TARGET_TOC
4267132718Skan	      && constant_pool_expr_p (XEXP (operands[1], 0))
426890075Sobrien	      && ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (
426990075Sobrien			get_pool_constant (XEXP (operands[1], 0)),
427090075Sobrien			get_pool_mode (XEXP (operands[1], 0))))
427190075Sobrien	    {
427290075Sobrien	      operands[1]
4273169689Skan		= gen_const_mem (mode,
4274169689Skan				 create_TOC_reference (XEXP (operands[1], 0)));
427590075Sobrien	      set_mem_alias_set (operands[1], get_TOC_alias_set ());
427690075Sobrien	    }
427790075Sobrien	}
427890075Sobrien      break;
427990075Sobrien
428090075Sobrien    case TImode:
4281169689Skan      rs6000_eliminate_indexed_memrefs (operands);
428290075Sobrien
4283117395Skan      if (TARGET_POWER)
4284132718Skan	{
4285117395Skan	  emit_insn (gen_rtx_PARALLEL (VOIDmode,
4286117395Skan		       gen_rtvec (2,
4287117395Skan				  gen_rtx_SET (VOIDmode,
4288117395Skan					       operands[0], operands[1]),
4289117395Skan				  gen_rtx_CLOBBER (VOIDmode,
4290117395Skan						   gen_rtx_SCRATCH (SImode)))));
4291117395Skan	  return;
4292117395Skan	}
429390075Sobrien      break;
429490075Sobrien
429590075Sobrien    default:
4296169689Skan      gcc_unreachable ();
429790075Sobrien    }
429890075Sobrien
429990075Sobrien  /* Above, we may have called force_const_mem which may have returned
430090075Sobrien     an invalid address.  If we can, fix this up; otherwise, reload will
430190075Sobrien     have to deal with it.  */
4302117395Skan  if (GET_CODE (operands[1]) == MEM && ! reload_in_progress)
4303117395Skan    operands[1] = validize_mem (operands[1]);
430490075Sobrien
4305117395Skan emit_set:
430690075Sobrien  emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
430790075Sobrien}
430890075Sobrien
4309132718Skan/* Nonzero if we can use a floating-point register to pass this arg.  */
4310132718Skan#define USE_FP_FOR_ARG_P(CUM,MODE,TYPE)		\
4311169689Skan  (SCALAR_FLOAT_MODE_P (MODE)			\
4312169689Skan   && !DECIMAL_FLOAT_MODE_P (MODE)		\
4313132718Skan   && (CUM)->fregno <= FP_ARG_MAX_REG		\
4314132718Skan   && TARGET_HARD_FLOAT && TARGET_FPRS)
4315132718Skan
4316132718Skan/* Nonzero if we can use an AltiVec register to pass this arg.  */
4317132718Skan#define USE_ALTIVEC_FOR_ARG_P(CUM,MODE,TYPE,NAMED)	\
4318132718Skan  (ALTIVEC_VECTOR_MODE (MODE)				\
4319132718Skan   && (CUM)->vregno <= ALTIVEC_ARG_MAX_REG		\
4320132718Skan   && TARGET_ALTIVEC_ABI				\
4321132718Skan   && (NAMED))
4322132718Skan
4323132718Skan/* Return a nonzero value to say to return the function value in
4324132718Skan   memory, just as large structures are always returned.  TYPE will be
4325132718Skan   the data type of the value, and FNTYPE will be the type of the
4326132718Skan   function doing the returning, or @code{NULL} for libcalls.
4327132718Skan
4328132718Skan   The AIX ABI for the RS/6000 specifies that all structures are
4329132718Skan   returned in memory.  The Darwin ABI does the same.  The SVR4 ABI
4330132718Skan   specifies that structures <= 8 bytes are returned in r3/r4, but a
4331132718Skan   draft put them in memory, and GCC used to implement the draft
4332169689Skan   instead of the final standard.  Therefore, aix_struct_return
4333132718Skan   controls this instead of DEFAULT_ABI; V.4 targets needing backward
4334132718Skan   compatibility can change DRAFT_V4_STRUCT_RET to override the
4335132718Skan   default, and -m switches get the final word.  See
4336132718Skan   rs6000_override_options for more details.
4337132718Skan
4338132718Skan   The PPC32 SVR4 ABI uses IEEE double extended for long double, if 128-bit
4339132718Skan   long double support is enabled.  These values are returned in memory.
4340132718Skan
4341132718Skan   int_size_in_bytes returns -1 for variable size objects, which go in
4342132718Skan   memory always.  The cast to unsigned makes -1 > 8.  */
4343132718Skan
4344132718Skanstatic bool
4345132718Skanrs6000_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
4346132718Skan{
4347169689Skan  /* In the darwin64 abi, try to use registers for larger structs
4348169689Skan     if possible.  */
4349169689Skan  if (rs6000_darwin64_abi
4350169689Skan      && TREE_CODE (type) == RECORD_TYPE
4351169689Skan      && int_size_in_bytes (type) > 0)
4352169689Skan    {
4353169689Skan      CUMULATIVE_ARGS valcum;
4354169689Skan      rtx valret;
4355169689Skan
4356169689Skan      valcum.words = 0;
4357169689Skan      valcum.fregno = FP_ARG_MIN_REG;
4358169689Skan      valcum.vregno = ALTIVEC_ARG_MIN_REG;
4359169689Skan      /* Do a trial code generation as if this were going to be passed
4360169689Skan	 as an argument; if any part goes in memory, we return NULL.  */
4361169689Skan      valret = rs6000_darwin64_record_arg (&valcum, type, 1, true);
4362169689Skan      if (valret)
4363169689Skan	return false;
4364169689Skan      /* Otherwise fall through to more conventional ABI rules.  */
4365169689Skan    }
4366169689Skan
4367132718Skan  if (AGGREGATE_TYPE_P (type)
4368169689Skan      && (aix_struct_return
4369132718Skan	  || (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 8))
4370132718Skan    return true;
4371169689Skan
4372169689Skan  /* Allow -maltivec -mabi=no-altivec without warning.  Altivec vector
4373169689Skan     modes only exist for GCC vector types if -maltivec.  */
4374169689Skan  if (TARGET_32BIT && !TARGET_ALTIVEC_ABI
4375169689Skan      && ALTIVEC_VECTOR_MODE (TYPE_MODE (type)))
4376169689Skan    return false;
4377169689Skan
4378169689Skan  /* Return synthetic vectors in memory.  */
4379169689Skan  if (TREE_CODE (type) == VECTOR_TYPE
4380169689Skan      && int_size_in_bytes (type) > (TARGET_ALTIVEC_ABI ? 16 : 8))
4381169689Skan    {
4382169689Skan      static bool warned_for_return_big_vectors = false;
4383169689Skan      if (!warned_for_return_big_vectors)
4384169689Skan	{
4385169689Skan	  warning (0, "GCC vector returned by reference: "
4386169689Skan		   "non-standard ABI extension with no compatibility guarantee");
4387169689Skan	  warned_for_return_big_vectors = true;
4388169689Skan	}
4389169689Skan      return true;
4390169689Skan    }
4391169689Skan
4392169689Skan  if (DEFAULT_ABI == ABI_V4 && TARGET_IEEEQUAD && TYPE_MODE (type) == TFmode)
4393132718Skan    return true;
4394169689Skan
4395132718Skan  return false;
4396132718Skan}
4397132718Skan
439890075Sobrien/* Initialize a variable CUM of type CUMULATIVE_ARGS
439990075Sobrien   for a call to a function whose data type is FNTYPE.
440090075Sobrien   For a library call, FNTYPE is 0.
440190075Sobrien
440290075Sobrien   For incoming args we set the number of arguments in the prototype large
440390075Sobrien   so we never return a PARALLEL.  */
440490075Sobrien
440590075Sobrienvoid
4406169689Skaninit_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
4407132718Skan		      rtx libname ATTRIBUTE_UNUSED, int incoming,
4408132718Skan		      int libcall, int n_named_args)
440990075Sobrien{
441090075Sobrien  static CUMULATIVE_ARGS zero_cumulative;
441190075Sobrien
441290075Sobrien  *cum = zero_cumulative;
441390075Sobrien  cum->words = 0;
441490075Sobrien  cum->fregno = FP_ARG_MIN_REG;
441590075Sobrien  cum->vregno = ALTIVEC_ARG_MIN_REG;
441690075Sobrien  cum->prototype = (fntype && TYPE_ARG_TYPES (fntype));
4417117395Skan  cum->call_cookie = ((DEFAULT_ABI == ABI_V4 && libcall)
4418117395Skan		      ? CALL_LIBCALL : CALL_NORMAL);
441990075Sobrien  cum->sysv_gregno = GP_ARG_MIN_REG;
4420132718Skan  cum->stdarg = fntype
4421132718Skan    && (TYPE_ARG_TYPES (fntype) != 0
4422132718Skan	&& (TREE_VALUE (tree_last  (TYPE_ARG_TYPES (fntype)))
4423132718Skan	    != void_type_node));
442490075Sobrien
4425132718Skan  cum->nargs_prototype = 0;
4426132718Skan  if (incoming || cum->prototype)
4427132718Skan    cum->nargs_prototype = n_named_args;
442890075Sobrien
4429117395Skan  /* Check for a longcall attribute.  */
4430146895Skan  if ((!fntype && rs6000_default_long_calls)
4431146895Skan      || (fntype
4432146895Skan	  && lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype))
4433146895Skan	  && !lookup_attribute ("shortcall", TYPE_ATTRIBUTES (fntype))))
4434146895Skan    cum->call_cookie |= CALL_LONG;
443590075Sobrien
443690075Sobrien  if (TARGET_DEBUG_ARG)
443790075Sobrien    {
443890075Sobrien      fprintf (stderr, "\ninit_cumulative_args:");
443990075Sobrien      if (fntype)
444090075Sobrien	{
444190075Sobrien	  tree ret_type = TREE_TYPE (fntype);
444290075Sobrien	  fprintf (stderr, " ret code = %s,",
444390075Sobrien		   tree_code_name[ (int)TREE_CODE (ret_type) ]);
444490075Sobrien	}
444590075Sobrien
444690075Sobrien      if (cum->call_cookie & CALL_LONG)
444790075Sobrien	fprintf (stderr, " longcall,");
444890075Sobrien
444990075Sobrien      fprintf (stderr, " proto = %d, nargs = %d\n",
445090075Sobrien	       cum->prototype, cum->nargs_prototype);
445190075Sobrien    }
4452169689Skan
4453169689Skan  if (fntype
4454169689Skan      && !TARGET_ALTIVEC
4455169689Skan      && TARGET_ALTIVEC_ABI
4456169689Skan      && ALTIVEC_VECTOR_MODE (TYPE_MODE (TREE_TYPE (fntype))))
4457169689Skan    {
4458169689Skan      error ("cannot return value in vector register because"
4459169689Skan	     " altivec instructions are disabled, use -maltivec"
4460169689Skan	     " to enable them");
4461169689Skan    }
446290075Sobrien}
446390075Sobrien
4464169689Skan/* Return true if TYPE must be passed on the stack and not in registers.  */
4465169689Skan
4466169689Skanstatic bool
4467169689Skanrs6000_must_pass_in_stack (enum machine_mode mode, tree type)
4468169689Skan{
4469169689Skan  if (DEFAULT_ABI == ABI_AIX || TARGET_64BIT)
4470169689Skan    return must_pass_in_stack_var_size (mode, type);
4471169689Skan  else
4472169689Skan    return must_pass_in_stack_var_size_or_pad (mode, type);
4473169689Skan}
4474169689Skan
447590075Sobrien/* If defined, a C expression which determines whether, and in which
447690075Sobrien   direction, to pad out an argument with extra space.  The value
447790075Sobrien   should be of type `enum direction': either `upward' to pad above
447890075Sobrien   the argument, `downward' to pad below, or `none' to inhibit
447990075Sobrien   padding.
448090075Sobrien
448190075Sobrien   For the AIX ABI structs are always stored left shifted in their
448290075Sobrien   argument slot.  */
448390075Sobrien
448490075Sobrienenum direction
4485132718Skanfunction_arg_padding (enum machine_mode mode, tree type)
448690075Sobrien{
4487132718Skan#ifndef AGGREGATE_PADDING_FIXED
4488132718Skan#define AGGREGATE_PADDING_FIXED 0
4489132718Skan#endif
4490132718Skan#ifndef AGGREGATES_PAD_UPWARD_ALWAYS
4491132718Skan#define AGGREGATES_PAD_UPWARD_ALWAYS 0
4492132718Skan#endif
449390075Sobrien
4494132718Skan  if (!AGGREGATE_PADDING_FIXED)
4495132718Skan    {
4496132718Skan      /* GCC used to pass structures of the same size as integer types as
4497132718Skan	 if they were in fact integers, ignoring FUNCTION_ARG_PADDING.
4498169689Skan	 i.e. Structures of size 1 or 2 (or 4 when TARGET_64BIT) were
4499132718Skan	 passed padded downward, except that -mstrict-align further
4500132718Skan	 muddied the water in that multi-component structures of 2 and 4
4501132718Skan	 bytes in size were passed padded upward.
4502132718Skan
4503132718Skan	 The following arranges for best compatibility with previous
4504132718Skan	 versions of gcc, but removes the -mstrict-align dependency.  */
4505132718Skan      if (BYTES_BIG_ENDIAN)
4506132718Skan	{
4507132718Skan	  HOST_WIDE_INT size = 0;
4508132718Skan
4509132718Skan	  if (mode == BLKmode)
4510132718Skan	    {
4511132718Skan	      if (type && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST)
4512132718Skan		size = int_size_in_bytes (type);
4513132718Skan	    }
4514132718Skan	  else
4515132718Skan	    size = GET_MODE_SIZE (mode);
4516132718Skan
4517132718Skan	  if (size == 1 || size == 2 || size == 4)
4518132718Skan	    return downward;
4519132718Skan	}
4520132718Skan      return upward;
4521132718Skan    }
4522132718Skan
4523132718Skan  if (AGGREGATES_PAD_UPWARD_ALWAYS)
4524132718Skan    {
4525132718Skan      if (type != 0 && AGGREGATE_TYPE_P (type))
4526132718Skan	return upward;
4527132718Skan    }
4528132718Skan
4529132718Skan  /* Fall back to the default.  */
4530132718Skan  return DEFAULT_FUNCTION_ARG_PADDING (mode, type);
453190075Sobrien}
453290075Sobrien
453390075Sobrien/* If defined, a C expression that gives the alignment boundary, in bits,
4534169689Skan   of an argument with the specified mode and type.  If it is not defined,
453590075Sobrien   PARM_BOUNDARY is used for all arguments.
453690075Sobrien
4537169689Skan   V.4 wants long longs and doubles to be double word aligned.  Just
4538169689Skan   testing the mode size is a boneheaded way to do this as it means
4539169689Skan   that other types such as complex int are also double word aligned.
4540169689Skan   However, we're stuck with this because changing the ABI might break
4541169689Skan   existing library interfaces.
4542169689Skan
4543169689Skan   Doubleword align SPE vectors.
4544169689Skan   Quadword align Altivec vectors.
4545169689Skan   Quadword align large synthetic vector types.   */
4546169689Skan
454790075Sobrienint
4548169689Skanfunction_arg_boundary (enum machine_mode mode, tree type)
454990075Sobrien{
4550169689Skan  if (DEFAULT_ABI == ABI_V4
4551169689Skan      && (GET_MODE_SIZE (mode) == 8
4552169689Skan	  || (TARGET_HARD_FLOAT
4553169689Skan	      && TARGET_FPRS
4554169689Skan	      && mode == TFmode)))
455590075Sobrien    return 64;
4556169689Skan  else if (SPE_VECTOR_MODE (mode)
4557169689Skan	   || (type && TREE_CODE (type) == VECTOR_TYPE
4558169689Skan	       && int_size_in_bytes (type) >= 8
4559169689Skan	       && int_size_in_bytes (type) < 16))
4560132718Skan    return 64;
4561169689Skan  else if (ALTIVEC_VECTOR_MODE (mode)
4562169689Skan	   || (type && TREE_CODE (type) == VECTOR_TYPE
4563169689Skan	       && int_size_in_bytes (type) >= 16))
456490075Sobrien    return 128;
4565169689Skan  else if (rs6000_darwin64_abi && mode == BLKmode
4566169689Skan	   && type && TYPE_ALIGN (type) > 64)
4567169689Skan    return 128;
456890075Sobrien  else
456990075Sobrien    return PARM_BOUNDARY;
457090075Sobrien}
4571132718Skan
4572169689Skan/* For a function parm of MODE and TYPE, return the starting word in
4573169689Skan   the parameter area.  NWORDS of the parameter area are already used.  */
4574169689Skan
4575169689Skanstatic unsigned int
4576169689Skanrs6000_parm_start (enum machine_mode mode, tree type, unsigned int nwords)
4577169689Skan{
4578169689Skan  unsigned int align;
4579169689Skan  unsigned int parm_offset;
4580169689Skan
4581169689Skan  align = function_arg_boundary (mode, type) / PARM_BOUNDARY - 1;
4582169689Skan  parm_offset = DEFAULT_ABI == ABI_V4 ? 2 : 6;
4583169689Skan  return nwords + (-(parm_offset + nwords) & align);
4584169689Skan}
4585169689Skan
4586132718Skan/* Compute the size (in words) of a function argument.  */
4587132718Skan
4588132718Skanstatic unsigned long
4589132718Skanrs6000_arg_size (enum machine_mode mode, tree type)
4590132718Skan{
4591132718Skan  unsigned long size;
4592132718Skan
4593132718Skan  if (mode != BLKmode)
4594132718Skan    size = GET_MODE_SIZE (mode);
4595132718Skan  else
4596132718Skan    size = int_size_in_bytes (type);
4597132718Skan
4598132718Skan  if (TARGET_32BIT)
4599132718Skan    return (size + 3) >> 2;
4600132718Skan  else
4601132718Skan    return (size + 7) >> 3;
4602132718Skan}
460390075Sobrien
4604169689Skan/* Use this to flush pending int fields.  */
4605169689Skan
4606169689Skanstatic void
4607169689Skanrs6000_darwin64_record_arg_advance_flush (CUMULATIVE_ARGS *cum,
4608169689Skan					  HOST_WIDE_INT bitpos)
4609169689Skan{
4610169689Skan  unsigned int startbit, endbit;
4611169689Skan  int intregs, intoffset;
4612169689Skan  enum machine_mode mode;
4613169689Skan
4614169689Skan  if (cum->intoffset == -1)
4615169689Skan    return;
4616169689Skan
4617169689Skan  intoffset = cum->intoffset;
4618169689Skan  cum->intoffset = -1;
4619169689Skan
4620169689Skan  if (intoffset % BITS_PER_WORD != 0)
4621169689Skan    {
4622169689Skan      mode = mode_for_size (BITS_PER_WORD - intoffset % BITS_PER_WORD,
4623169689Skan			    MODE_INT, 0);
4624169689Skan      if (mode == BLKmode)
4625169689Skan	{
4626169689Skan	  /* We couldn't find an appropriate mode, which happens,
4627169689Skan	     e.g., in packed structs when there are 3 bytes to load.
4628169689Skan	     Back intoffset back to the beginning of the word in this
4629169689Skan	     case.  */
4630169689Skan	  intoffset = intoffset & -BITS_PER_WORD;
4631169689Skan	}
4632169689Skan    }
4633169689Skan
4634169689Skan  startbit = intoffset & -BITS_PER_WORD;
4635169689Skan  endbit = (bitpos + BITS_PER_WORD - 1) & -BITS_PER_WORD;
4636169689Skan  intregs = (endbit - startbit) / BITS_PER_WORD;
4637169689Skan  cum->words += intregs;
4638169689Skan}
4639169689Skan
4640169689Skan/* The darwin64 ABI calls for us to recurse down through structs,
4641169689Skan   looking for elements passed in registers.  Unfortunately, we have
4642169689Skan   to track int register count here also because of misalignments
4643169689Skan   in powerpc alignment mode.  */
4644169689Skan
4645169689Skanstatic void
4646169689Skanrs6000_darwin64_record_arg_advance_recurse (CUMULATIVE_ARGS *cum,
4647169689Skan					    tree type,
4648169689Skan					    HOST_WIDE_INT startbitpos)
4649169689Skan{
4650169689Skan  tree f;
4651169689Skan
4652169689Skan  for (f = TYPE_FIELDS (type); f ; f = TREE_CHAIN (f))
4653169689Skan    if (TREE_CODE (f) == FIELD_DECL)
4654169689Skan      {
4655169689Skan	HOST_WIDE_INT bitpos = startbitpos;
4656169689Skan	tree ftype = TREE_TYPE (f);
4657169689Skan	enum machine_mode mode;
4658169689Skan	if (ftype == error_mark_node)
4659169689Skan	  continue;
4660169689Skan	mode = TYPE_MODE (ftype);
4661169689Skan
4662169689Skan	if (DECL_SIZE (f) != 0
4663169689Skan	    && host_integerp (bit_position (f), 1))
4664169689Skan	  bitpos += int_bit_position (f);
4665169689Skan
4666169689Skan	/* ??? FIXME: else assume zero offset.  */
4667169689Skan
4668169689Skan	if (TREE_CODE (ftype) == RECORD_TYPE)
4669169689Skan	  rs6000_darwin64_record_arg_advance_recurse (cum, ftype, bitpos);
4670169689Skan	else if (USE_FP_FOR_ARG_P (cum, mode, ftype))
4671169689Skan	  {
4672169689Skan	    rs6000_darwin64_record_arg_advance_flush (cum, bitpos);
4673169689Skan	    cum->fregno += (GET_MODE_SIZE (mode) + 7) >> 3;
4674169689Skan	    cum->words += (GET_MODE_SIZE (mode) + 7) >> 3;
4675169689Skan	  }
4676169689Skan	else if (USE_ALTIVEC_FOR_ARG_P (cum, mode, type, 1))
4677169689Skan	  {
4678169689Skan	    rs6000_darwin64_record_arg_advance_flush (cum, bitpos);
4679169689Skan	    cum->vregno++;
4680169689Skan	    cum->words += 2;
4681169689Skan	  }
4682169689Skan	else if (cum->intoffset == -1)
4683169689Skan	  cum->intoffset = bitpos;
4684169689Skan      }
4685169689Skan}
4686169689Skan
468790075Sobrien/* Update the data in CUM to advance over an argument
468890075Sobrien   of mode MODE and data type TYPE.
4689132718Skan   (TYPE is null for libcalls where that information may not be available.)
469090075Sobrien
4691132718Skan   Note that for args passed by reference, function_arg will be called
4692132718Skan   with MODE and TYPE set to that of the pointer to the arg, not the arg
4693132718Skan   itself.  */
4694132718Skan
469590075Sobrienvoid
4696169689Skanfunction_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
4697169689Skan		      tree type, int named, int depth)
469890075Sobrien{
4699169689Skan  int size;
470090075Sobrien
4701169689Skan  /* Only tick off an argument if we're not recursing.  */
4702169689Skan  if (depth == 0)
4703169689Skan    cum->nargs_prototype--;
4704169689Skan
4705169689Skan  if (TARGET_ALTIVEC_ABI
4706169689Skan      && (ALTIVEC_VECTOR_MODE (mode)
4707169689Skan	  || (type && TREE_CODE (type) == VECTOR_TYPE
4708169689Skan	      && int_size_in_bytes (type) == 16)))
470990075Sobrien    {
4710132718Skan      bool stack = false;
4711132718Skan
4712132718Skan      if (USE_ALTIVEC_FOR_ARG_P (cum, mode, type, named))
4713169689Skan	{
4714132718Skan	  cum->vregno++;
4715132718Skan	  if (!TARGET_ALTIVEC)
4716169689Skan	    error ("cannot pass argument in vector register because"
4717132718Skan		   " altivec instructions are disabled, use -maltivec"
4718169689Skan		   " to enable them");
4719132718Skan
4720132718Skan	  /* PowerPC64 Linux and AIX allocate GPRs for a vector argument
4721169689Skan	     even if it is going to be passed in a vector register.
4722132718Skan	     Darwin does the same for variable-argument functions.  */
4723132718Skan	  if ((DEFAULT_ABI == ABI_AIX && TARGET_64BIT)
4724132718Skan	      || (cum->stdarg && DEFAULT_ABI != ABI_V4))
4725132718Skan	    stack = true;
4726132718Skan	}
472790075Sobrien      else
4728132718Skan	stack = true;
4729132718Skan
4730132718Skan      if (stack)
4731169689Skan	{
4732132718Skan	  int align;
4733169689Skan
4734132718Skan	  /* Vector parameters must be 16-byte aligned.  This places
4735132718Skan	     them at 2 mod 4 in terms of words in 32-bit mode, since
4736132718Skan	     the parameter save area starts at offset 24 from the
4737132718Skan	     stack.  In 64-bit mode, they just have to start on an
4738132718Skan	     even word, since the parameter save area is 16-byte
4739132718Skan	     aligned.  Space for GPRs is reserved even if the argument
4740132718Skan	     will be passed in memory.  */
4741132718Skan	  if (TARGET_32BIT)
4742132718Skan	    align = (2 - cum->words) & 3;
4743132718Skan	  else
4744132718Skan	    align = cum->words & 1;
4745132718Skan	  cum->words += align + rs6000_arg_size (mode, type);
4746169689Skan
4747132718Skan	  if (TARGET_DEBUG_ARG)
4748132718Skan	    {
4749169689Skan	      fprintf (stderr, "function_adv: words = %2d, align=%d, ",
4750132718Skan		       cum->words, align);
4751132718Skan	      fprintf (stderr, "nargs = %4d, proto = %d, mode = %4s\n",
4752169689Skan		       cum->nargs_prototype, cum->prototype,
4753132718Skan		       GET_MODE_NAME (mode));
4754132718Skan	    }
4755132718Skan	}
475690075Sobrien    }
4757117395Skan  else if (TARGET_SPE_ABI && TARGET_SPE && SPE_VECTOR_MODE (mode)
4758132718Skan	   && !cum->stdarg
4759132718Skan	   && cum->sysv_gregno <= GP_ARG_MAX_REG)
4760117395Skan    cum->sysv_gregno++;
4761169689Skan
4762169689Skan  else if (rs6000_darwin64_abi
4763169689Skan	   && mode == BLKmode
4764169689Skan    	   && TREE_CODE (type) == RECORD_TYPE
4765169689Skan	   && (size = int_size_in_bytes (type)) > 0)
4766169689Skan    {
4767169689Skan      /* Variable sized types have size == -1 and are
4768169689Skan	 treated as if consisting entirely of ints.
4769169689Skan	 Pad to 16 byte boundary if needed.  */
4770169689Skan      if (TYPE_ALIGN (type) >= 2 * BITS_PER_WORD
4771169689Skan	  && (cum->words % 2) != 0)
4772169689Skan	cum->words++;
4773169689Skan      /* For varargs, we can just go up by the size of the struct. */
4774169689Skan      if (!named)
4775169689Skan	cum->words += (size + 7) / 8;
4776169689Skan      else
4777169689Skan	{
4778169689Skan	  /* It is tempting to say int register count just goes up by
4779169689Skan	     sizeof(type)/8, but this is wrong in a case such as
4780169689Skan	     { int; double; int; } [powerpc alignment].  We have to
4781169689Skan	     grovel through the fields for these too.  */
4782169689Skan	  cum->intoffset = 0;
4783169689Skan	  rs6000_darwin64_record_arg_advance_recurse (cum, type, 0);
4784169689Skan	  rs6000_darwin64_record_arg_advance_flush (cum,
4785169689Skan						    size * BITS_PER_UNIT);
4786169689Skan	}
4787169689Skan    }
478890075Sobrien  else if (DEFAULT_ABI == ABI_V4)
478990075Sobrien    {
4790117395Skan      if (TARGET_HARD_FLOAT && TARGET_FPRS
4791169689Skan	  && (mode == SFmode || mode == DFmode
4792169689Skan	      || (mode == TFmode && !TARGET_IEEEQUAD)))
479390075Sobrien	{
4794169689Skan	  if (cum->fregno + (mode == TFmode ? 1 : 0) <= FP_ARG_V4_MAX_REG)
4795169689Skan	    cum->fregno += (GET_MODE_SIZE (mode) + 7) >> 3;
479690075Sobrien	  else
479790075Sobrien	    {
4798169689Skan	      cum->fregno = FP_ARG_V4_MAX_REG + 1;
4799169689Skan	      if (mode == DFmode || mode == TFmode)
4800169689Skan		cum->words += cum->words & 1;
4801132718Skan	      cum->words += rs6000_arg_size (mode, type);
480290075Sobrien	    }
480390075Sobrien	}
480490075Sobrien      else
480590075Sobrien	{
4806132718Skan	  int n_words = rs6000_arg_size (mode, type);
480790075Sobrien	  int gregno = cum->sysv_gregno;
480890075Sobrien
4809132718Skan	  /* Long long and SPE vectors are put in (r3,r4), (r5,r6),
4810132718Skan	     (r7,r8) or (r9,r10).  As does any other 2 word item such
4811132718Skan	     as complex int due to a historical mistake.  */
4812132718Skan	  if (n_words == 2)
4813132718Skan	    gregno += (1 - gregno) & 1;
481490075Sobrien
4815132718Skan	  /* Multi-reg args are not split between registers and stack.  */
481690075Sobrien	  if (gregno + n_words - 1 > GP_ARG_MAX_REG)
481790075Sobrien	    {
4818132718Skan	      /* Long long and SPE vectors are aligned on the stack.
4819132718Skan		 So are other 2 word items such as complex int due to
4820132718Skan		 a historical mistake.  */
482190075Sobrien	      if (n_words == 2)
482290075Sobrien		cum->words += cum->words & 1;
482390075Sobrien	      cum->words += n_words;
482490075Sobrien	    }
482590075Sobrien
482690075Sobrien	  /* Note: continuing to accumulate gregno past when we've started
482790075Sobrien	     spilling to the stack indicates the fact that we've started
482890075Sobrien	     spilling to the stack to expand_builtin_saveregs.  */
482990075Sobrien	  cum->sysv_gregno = gregno + n_words;
483090075Sobrien	}
483190075Sobrien
483290075Sobrien      if (TARGET_DEBUG_ARG)
483390075Sobrien	{
483490075Sobrien	  fprintf (stderr, "function_adv: words = %2d, fregno = %2d, ",
483590075Sobrien		   cum->words, cum->fregno);
483690075Sobrien	  fprintf (stderr, "gregno = %2d, nargs = %4d, proto = %d, ",
483790075Sobrien		   cum->sysv_gregno, cum->nargs_prototype, cum->prototype);
483890075Sobrien	  fprintf (stderr, "mode = %4s, named = %d\n",
483990075Sobrien		   GET_MODE_NAME (mode), named);
484090075Sobrien	}
484190075Sobrien    }
484290075Sobrien  else
484390075Sobrien    {
4844132718Skan      int n_words = rs6000_arg_size (mode, type);
4845169689Skan      int start_words = cum->words;
4846169689Skan      int align_words = rs6000_parm_start (mode, type, start_words);
484790075Sobrien
4848169689Skan      cum->words = align_words + n_words;
484990075Sobrien
4850169689Skan      if (SCALAR_FLOAT_MODE_P (mode)
4851169689Skan	  && !DECIMAL_FLOAT_MODE_P (mode)
4852117395Skan	  && TARGET_HARD_FLOAT && TARGET_FPRS)
4853132718Skan	cum->fregno += (GET_MODE_SIZE (mode) + 7) >> 3;
485490075Sobrien
485590075Sobrien      if (TARGET_DEBUG_ARG)
485690075Sobrien	{
485790075Sobrien	  fprintf (stderr, "function_adv: words = %2d, fregno = %2d, ",
485890075Sobrien		   cum->words, cum->fregno);
485990075Sobrien	  fprintf (stderr, "nargs = %4d, proto = %d, mode = %4s, ",
486090075Sobrien		   cum->nargs_prototype, cum->prototype, GET_MODE_NAME (mode));
4861169689Skan	  fprintf (stderr, "named = %d, align = %d, depth = %d\n",
4862169689Skan		   named, align_words - start_words, depth);
486390075Sobrien	}
486490075Sobrien    }
486590075Sobrien}
4866132718Skan
4867169689Skanstatic rtx
4868169689Skanspe_build_register_parallel (enum machine_mode mode, int gregno)
4869169689Skan{
4870169689Skan  rtx r1, r3;
4871169689Skan
4872169689Skan  switch (mode)
4873169689Skan    {
4874169689Skan    case DFmode:
4875169689Skan      r1 = gen_rtx_REG (DImode, gregno);
4876169689Skan      r1 = gen_rtx_EXPR_LIST (VOIDmode, r1, const0_rtx);
4877169689Skan      return gen_rtx_PARALLEL (mode, gen_rtvec (1, r1));
4878169689Skan
4879169689Skan    case DCmode:
4880169689Skan      r1 = gen_rtx_REG (DImode, gregno);
4881169689Skan      r1 = gen_rtx_EXPR_LIST (VOIDmode, r1, const0_rtx);
4882169689Skan      r3 = gen_rtx_REG (DImode, gregno + 2);
4883169689Skan      r3 = gen_rtx_EXPR_LIST (VOIDmode, r3, GEN_INT (8));
4884169689Skan      return gen_rtx_PARALLEL (mode, gen_rtvec (2, r1, r3));
4885169689Skan
4886169689Skan    default:
4887169689Skan      gcc_unreachable ();
4888169689Skan    }
4889169689Skan}
4890169689Skan
4891132718Skan/* Determine where to put a SIMD argument on the SPE.  */
4892132718Skanstatic rtx
4893169689Skanrs6000_spe_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
4894132718Skan			 tree type)
4895132718Skan{
4896169689Skan  int gregno = cum->sysv_gregno;
4897169689Skan
4898169689Skan  /* On E500 v2, double arithmetic is done on the full 64-bit GPR, but
4899169689Skan     are passed and returned in a pair of GPRs for ABI compatibility.  */
4900169689Skan  if (TARGET_E500_DOUBLE && (mode == DFmode || mode == DCmode))
4901169689Skan    {
4902169689Skan      int n_words = rs6000_arg_size (mode, type);
4903169689Skan
4904169689Skan      /* Doubles go in an odd/even register pair (r5/r6, etc).  */
4905169689Skan      if (mode == DFmode)
4906169689Skan	gregno += (1 - gregno) & 1;
4907169689Skan
4908169689Skan      /* Multi-reg args are not split between registers and stack.  */
4909169689Skan      if (gregno + n_words - 1 > GP_ARG_MAX_REG)
4910169689Skan	return NULL_RTX;
4911169689Skan
4912169689Skan      return spe_build_register_parallel (mode, gregno);
4913169689Skan    }
4914132718Skan  if (cum->stdarg)
4915132718Skan    {
4916132718Skan      int n_words = rs6000_arg_size (mode, type);
4917132718Skan
4918132718Skan      /* SPE vectors are put in odd registers.  */
4919132718Skan      if (n_words == 2 && (gregno & 1) == 0)
4920132718Skan	gregno += 1;
4921132718Skan
4922132718Skan      if (gregno + n_words - 1 <= GP_ARG_MAX_REG)
4923132718Skan	{
4924132718Skan	  rtx r1, r2;
4925132718Skan	  enum machine_mode m = SImode;
4926132718Skan
4927132718Skan	  r1 = gen_rtx_REG (m, gregno);
4928132718Skan	  r1 = gen_rtx_EXPR_LIST (m, r1, const0_rtx);
4929132718Skan	  r2 = gen_rtx_REG (m, gregno + 1);
4930132718Skan	  r2 = gen_rtx_EXPR_LIST (m, r2, GEN_INT (4));
4931132718Skan	  return gen_rtx_PARALLEL (mode, gen_rtvec (2, r1, r2));
4932132718Skan	}
4933132718Skan      else
4934132718Skan	return NULL_RTX;
4935132718Skan    }
4936132718Skan  else
4937132718Skan    {
4938169689Skan      if (gregno <= GP_ARG_MAX_REG)
4939169689Skan	return gen_rtx_REG (mode, gregno);
4940132718Skan      else
4941132718Skan	return NULL_RTX;
4942132718Skan    }
4943132718Skan}
4944132718Skan
4945169689Skan/* A subroutine of rs6000_darwin64_record_arg.  Assign the bits of the
4946169689Skan   structure between cum->intoffset and bitpos to integer registers.  */
4947169689Skan
4948169689Skanstatic void
4949169689Skanrs6000_darwin64_record_arg_flush (CUMULATIVE_ARGS *cum,
4950169689Skan				  HOST_WIDE_INT bitpos, rtx rvec[], int *k)
4951169689Skan{
4952169689Skan  enum machine_mode mode;
4953169689Skan  unsigned int regno;
4954169689Skan  unsigned int startbit, endbit;
4955169689Skan  int this_regno, intregs, intoffset;
4956169689Skan  rtx reg;
4957169689Skan
4958169689Skan  if (cum->intoffset == -1)
4959169689Skan    return;
4960169689Skan
4961169689Skan  intoffset = cum->intoffset;
4962169689Skan  cum->intoffset = -1;
4963169689Skan
4964169689Skan  /* If this is the trailing part of a word, try to only load that
4965169689Skan     much into the register.  Otherwise load the whole register.  Note
4966169689Skan     that in the latter case we may pick up unwanted bits.  It's not a
4967169689Skan     problem at the moment but may wish to revisit.  */
4968169689Skan
4969169689Skan  if (intoffset % BITS_PER_WORD != 0)
4970169689Skan    {
4971169689Skan      mode = mode_for_size (BITS_PER_WORD - intoffset % BITS_PER_WORD,
4972169689Skan			  MODE_INT, 0);
4973169689Skan      if (mode == BLKmode)
4974169689Skan	{
4975169689Skan	  /* We couldn't find an appropriate mode, which happens,
4976169689Skan	     e.g., in packed structs when there are 3 bytes to load.
4977169689Skan	     Back intoffset back to the beginning of the word in this
4978169689Skan	     case.  */
4979169689Skan	 intoffset = intoffset & -BITS_PER_WORD;
4980169689Skan	 mode = word_mode;
4981169689Skan	}
4982169689Skan    }
4983169689Skan  else
4984169689Skan    mode = word_mode;
4985169689Skan
4986169689Skan  startbit = intoffset & -BITS_PER_WORD;
4987169689Skan  endbit = (bitpos + BITS_PER_WORD - 1) & -BITS_PER_WORD;
4988169689Skan  intregs = (endbit - startbit) / BITS_PER_WORD;
4989169689Skan  this_regno = cum->words + intoffset / BITS_PER_WORD;
4990169689Skan
4991169689Skan  if (intregs > 0 && intregs > GP_ARG_NUM_REG - this_regno)
4992169689Skan    cum->use_stack = 1;
4993169689Skan
4994169689Skan  intregs = MIN (intregs, GP_ARG_NUM_REG - this_regno);
4995169689Skan  if (intregs <= 0)
4996169689Skan    return;
4997169689Skan
4998169689Skan  intoffset /= BITS_PER_UNIT;
4999169689Skan  do
5000169689Skan    {
5001169689Skan      regno = GP_ARG_MIN_REG + this_regno;
5002169689Skan      reg = gen_rtx_REG (mode, regno);
5003169689Skan      rvec[(*k)++] =
5004169689Skan	gen_rtx_EXPR_LIST (VOIDmode, reg, GEN_INT (intoffset));
5005169689Skan
5006169689Skan      this_regno += 1;
5007169689Skan      intoffset = (intoffset | (UNITS_PER_WORD-1)) + 1;
5008169689Skan      mode = word_mode;
5009169689Skan      intregs -= 1;
5010169689Skan    }
5011169689Skan  while (intregs > 0);
5012169689Skan}
5013169689Skan
5014169689Skan/* Recursive workhorse for the following.  */
5015169689Skan
5016169689Skanstatic void
5017169689Skanrs6000_darwin64_record_arg_recurse (CUMULATIVE_ARGS *cum, tree type,
5018169689Skan				    HOST_WIDE_INT startbitpos, rtx rvec[],
5019169689Skan				    int *k)
5020169689Skan{
5021169689Skan  tree f;
5022169689Skan
5023169689Skan  for (f = TYPE_FIELDS (type); f ; f = TREE_CHAIN (f))
5024169689Skan    if (TREE_CODE (f) == FIELD_DECL)
5025169689Skan      {
5026169689Skan	HOST_WIDE_INT bitpos = startbitpos;
5027169689Skan	tree ftype = TREE_TYPE (f);
5028169689Skan	enum machine_mode mode;
5029169689Skan	if (ftype == error_mark_node)
5030169689Skan	  continue;
5031169689Skan	mode = TYPE_MODE (ftype);
5032169689Skan
5033169689Skan	if (DECL_SIZE (f) != 0
5034169689Skan	    && host_integerp (bit_position (f), 1))
5035169689Skan	  bitpos += int_bit_position (f);
5036169689Skan
5037169689Skan	/* ??? FIXME: else assume zero offset.  */
5038169689Skan
5039169689Skan	if (TREE_CODE (ftype) == RECORD_TYPE)
5040169689Skan	  rs6000_darwin64_record_arg_recurse (cum, ftype, bitpos, rvec, k);
5041169689Skan	else if (cum->named && USE_FP_FOR_ARG_P (cum, mode, ftype))
5042169689Skan	  {
5043169689Skan#if 0
5044169689Skan	    switch (mode)
5045169689Skan	      {
5046169689Skan	      case SCmode: mode = SFmode; break;
5047169689Skan	      case DCmode: mode = DFmode; break;
5048169689Skan	      case TCmode: mode = TFmode; break;
5049169689Skan	      default: break;
5050169689Skan	      }
5051169689Skan#endif
5052169689Skan	    rs6000_darwin64_record_arg_flush (cum, bitpos, rvec, k);
5053169689Skan	    rvec[(*k)++]
5054169689Skan	      = gen_rtx_EXPR_LIST (VOIDmode,
5055169689Skan				   gen_rtx_REG (mode, cum->fregno++),
5056169689Skan				   GEN_INT (bitpos / BITS_PER_UNIT));
5057169689Skan	    if (mode == TFmode)
5058169689Skan	      cum->fregno++;
5059169689Skan	  }
5060169689Skan	else if (cum->named && USE_ALTIVEC_FOR_ARG_P (cum, mode, ftype, 1))
5061169689Skan	  {
5062169689Skan	    rs6000_darwin64_record_arg_flush (cum, bitpos, rvec, k);
5063169689Skan	    rvec[(*k)++]
5064169689Skan	      = gen_rtx_EXPR_LIST (VOIDmode,
5065169689Skan				   gen_rtx_REG (mode, cum->vregno++),
5066169689Skan				   GEN_INT (bitpos / BITS_PER_UNIT));
5067169689Skan	  }
5068169689Skan	else if (cum->intoffset == -1)
5069169689Skan	  cum->intoffset = bitpos;
5070169689Skan      }
5071169689Skan}
5072169689Skan
5073169689Skan/* For the darwin64 ABI, we want to construct a PARALLEL consisting of
5074169689Skan   the register(s) to be used for each field and subfield of a struct
5075169689Skan   being passed by value, along with the offset of where the
5076169689Skan   register's value may be found in the block.  FP fields go in FP
5077169689Skan   register, vector fields go in vector registers, and everything
5078169689Skan   else goes in int registers, packed as in memory.
5079169689Skan
5080169689Skan   This code is also used for function return values.  RETVAL indicates
5081169689Skan   whether this is the case.
5082169689Skan
5083169689Skan   Much of this is taken from the SPARC V9 port, which has a similar
5084169689Skan   calling convention.  */
5085169689Skan
5086169689Skanstatic rtx
5087169689Skanrs6000_darwin64_record_arg (CUMULATIVE_ARGS *orig_cum, tree type,
5088169689Skan			    int named, bool retval)
5089169689Skan{
5090169689Skan  rtx rvec[FIRST_PSEUDO_REGISTER];
5091169689Skan  int k = 1, kbase = 1;
5092169689Skan  HOST_WIDE_INT typesize = int_size_in_bytes (type);
5093169689Skan  /* This is a copy; modifications are not visible to our caller.  */
5094169689Skan  CUMULATIVE_ARGS copy_cum = *orig_cum;
5095169689Skan  CUMULATIVE_ARGS *cum = &copy_cum;
5096169689Skan
5097169689Skan  /* Pad to 16 byte boundary if needed.  */
5098169689Skan  if (!retval && TYPE_ALIGN (type) >= 2 * BITS_PER_WORD
5099169689Skan      && (cum->words % 2) != 0)
5100169689Skan    cum->words++;
5101169689Skan
5102169689Skan  cum->intoffset = 0;
5103169689Skan  cum->use_stack = 0;
5104169689Skan  cum->named = named;
5105169689Skan
5106169689Skan  /* Put entries into rvec[] for individual FP and vector fields, and
5107169689Skan     for the chunks of memory that go in int regs.  Note we start at
5108169689Skan     element 1; 0 is reserved for an indication of using memory, and
5109169689Skan     may or may not be filled in below. */
5110169689Skan  rs6000_darwin64_record_arg_recurse (cum, type, 0, rvec, &k);
5111169689Skan  rs6000_darwin64_record_arg_flush (cum, typesize * BITS_PER_UNIT, rvec, &k);
5112169689Skan
5113169689Skan  /* If any part of the struct went on the stack put all of it there.
5114169689Skan     This hack is because the generic code for
5115169689Skan     FUNCTION_ARG_PARTIAL_NREGS cannot handle cases where the register
5116169689Skan     parts of the struct are not at the beginning.  */
5117169689Skan  if (cum->use_stack)
5118169689Skan    {
5119169689Skan      if (retval)
5120169689Skan	return NULL_RTX;    /* doesn't go in registers at all */
5121169689Skan      kbase = 0;
5122169689Skan      rvec[0] = gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX, const0_rtx);
5123169689Skan    }
5124169689Skan  if (k > 1 || cum->use_stack)
5125169689Skan    return gen_rtx_PARALLEL (BLKmode, gen_rtvec_v (k - kbase, &rvec[kbase]));
5126169689Skan  else
5127169689Skan    return NULL_RTX;
5128169689Skan}
5129169689Skan
5130132718Skan/* Determine where to place an argument in 64-bit mode with 32-bit ABI.  */
5131132718Skan
5132132718Skanstatic rtx
5133146895Skanrs6000_mixed_function_arg (enum machine_mode mode, tree type, int align_words)
5134132718Skan{
5135146895Skan  int n_units;
5136146895Skan  int i, k;
5137146895Skan  rtx rvec[GP_ARG_NUM_REG + 1];
5138132718Skan
5139146895Skan  if (align_words >= GP_ARG_NUM_REG)
5140146895Skan    return NULL_RTX;
5141132718Skan
5142146895Skan  n_units = rs6000_arg_size (mode, type);
5143132718Skan
5144146895Skan  /* Optimize the simple case where the arg fits in one gpr, except in
5145146895Skan     the case of BLKmode due to assign_parms assuming that registers are
5146146895Skan     BITS_PER_WORD wide.  */
5147146895Skan  if (n_units == 0
5148146895Skan      || (n_units == 1 && mode != BLKmode))
5149146895Skan    return gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
5150132718Skan
5151146895Skan  k = 0;
5152146895Skan  if (align_words + n_units > GP_ARG_NUM_REG)
5153146895Skan    /* Not all of the arg fits in gprs.  Say that it goes in memory too,
5154146895Skan       using a magic NULL_RTX component.
5155169689Skan       This is not strictly correct.  Only some of the arg belongs in
5156169689Skan       memory, not all of it.  However, the normal scheme using
5157169689Skan       function_arg_partial_nregs can result in unusual subregs, eg.
5158169689Skan       (subreg:SI (reg:DF) 4), which are not handled well.  The code to
5159169689Skan       store the whole arg to memory is often more efficient than code
5160169689Skan       to store pieces, and we know that space is available in the right
5161169689Skan       place for the whole arg.  */
5162146895Skan    rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX, const0_rtx);
5163132718Skan
5164146895Skan  i = 0;
5165146895Skan  do
5166146895Skan    {
5167146895Skan      rtx r = gen_rtx_REG (SImode, GP_ARG_MIN_REG + align_words);
5168146895Skan      rtx off = GEN_INT (i++ * 4);
5169146895Skan      rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, off);
5170146895Skan    }
5171146895Skan  while (++align_words < GP_ARG_NUM_REG && --n_units != 0);
5172146895Skan
5173146895Skan  return gen_rtx_PARALLEL (mode, gen_rtvec_v (k, rvec));
5174132718Skan}
5175132718Skan
517690075Sobrien/* Determine where to put an argument to a function.
517790075Sobrien   Value is zero to push the argument on the stack,
517890075Sobrien   or a hard register in which to store the argument.
517990075Sobrien
518090075Sobrien   MODE is the argument's machine mode.
518190075Sobrien   TYPE is the data type of the argument (as a tree).
518290075Sobrien    This is null for libcalls where that information may
518390075Sobrien    not be available.
518490075Sobrien   CUM is a variable of type CUMULATIVE_ARGS which gives info about
5185169689Skan    the preceding args and about the function being called.  It is
5186169689Skan    not modified in this routine.
518790075Sobrien   NAMED is nonzero if this argument is a named parameter
518890075Sobrien    (otherwise it is an extra parameter matching an ellipsis).
518990075Sobrien
519090075Sobrien   On RS/6000 the first eight words of non-FP are normally in registers
519190075Sobrien   and the rest are pushed.  Under AIX, the first 13 FP args are in registers.
519290075Sobrien   Under V.4, the first 8 FP args are in registers.
519390075Sobrien
519490075Sobrien   If this is floating-point and no prototype is specified, we use
519590075Sobrien   both an FP and integer register (or possibly FP reg and stack).  Library
5196117395Skan   functions (when CALL_LIBCALL is set) always have the proper types for args,
519790075Sobrien   so we can pass the FP value just in one register.  emit_library_function
5198132718Skan   doesn't support PARALLEL anyway.
519990075Sobrien
5200132718Skan   Note that for args passed by reference, function_arg will be called
5201132718Skan   with MODE and TYPE set to that of the pointer to the arg, not the arg
5202132718Skan   itself.  */
5203132718Skan
5204169689Skanrtx
5205169689Skanfunction_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
5206132718Skan	      tree type, int named)
520790075Sobrien{
520890075Sobrien  enum rs6000_abi abi = DEFAULT_ABI;
520990075Sobrien
521090075Sobrien  /* Return a marker to indicate whether CR1 needs to set or clear the
521190075Sobrien     bit that V.4 uses to say fp args were passed in registers.
521290075Sobrien     Assume that we don't need the marker for software floating point,
521390075Sobrien     or compiler generated library calls.  */
521490075Sobrien  if (mode == VOIDmode)
521590075Sobrien    {
521690075Sobrien      if (abi == ABI_V4
5217117395Skan	  && (cum->call_cookie & CALL_LIBCALL) == 0
5218161651Skan	  && (cum->stdarg
5219161651Skan	      || (cum->nargs_prototype < 0
5220161651Skan		  && (cum->prototype || TARGET_NO_PROTOTYPE))))
522190075Sobrien	{
5222117395Skan	  /* For the SPE, we need to crxor CR6 always.  */
5223117395Skan	  if (TARGET_SPE_ABI)
5224117395Skan	    return GEN_INT (cum->call_cookie | CALL_V4_SET_FP_ARGS);
5225117395Skan	  else if (TARGET_HARD_FLOAT && TARGET_FPRS)
5226117395Skan	    return GEN_INT (cum->call_cookie
5227117395Skan			    | ((cum->fregno == FP_ARG_MIN_REG)
5228117395Skan			       ? CALL_V4_SET_FP_ARGS
5229117395Skan			       : CALL_V4_CLEAR_FP_ARGS));
523090075Sobrien	}
523190075Sobrien
523290075Sobrien      return GEN_INT (cum->call_cookie);
523390075Sobrien    }
523490075Sobrien
5235169689Skan  if (rs6000_darwin64_abi && mode == BLKmode
5236169689Skan      && TREE_CODE (type) == RECORD_TYPE)
5237169689Skan    {
5238169689Skan      rtx rslt = rs6000_darwin64_record_arg (cum, type, named, false);
5239169689Skan      if (rslt != NULL_RTX)
5240169689Skan	return rslt;
5241169689Skan      /* Else fall through to usual handling.  */
5242169689Skan    }
5243169689Skan
5244132718Skan  if (USE_ALTIVEC_FOR_ARG_P (cum, mode, type, named))
5245132718Skan    if (TARGET_64BIT && ! cum->prototype)
5246132718Skan      {
5247169689Skan	/* Vector parameters get passed in vector register
5248169689Skan	   and also in GPRs or memory, in absence of prototype.  */
5249169689Skan	int align_words;
5250169689Skan	rtx slot;
5251169689Skan	align_words = (cum->words + 1) & ~1;
5252132718Skan
5253169689Skan	if (align_words >= GP_ARG_NUM_REG)
5254169689Skan	  {
5255169689Skan	    slot = NULL_RTX;
5256169689Skan	  }
5257169689Skan	else
5258169689Skan	  {
5259169689Skan	    slot = gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
5260169689Skan	  }
5261169689Skan	return gen_rtx_PARALLEL (mode,
5262169689Skan		 gen_rtvec (2,
5263169689Skan			    gen_rtx_EXPR_LIST (VOIDmode,
5264169689Skan					       slot, const0_rtx),
5265169689Skan			    gen_rtx_EXPR_LIST (VOIDmode,
5266169689Skan					       gen_rtx_REG (mode, cum->vregno),
5267169689Skan					       const0_rtx)));
5268132718Skan      }
5269132718Skan    else
5270132718Skan      return gen_rtx_REG (mode, cum->vregno);
5271169689Skan  else if (TARGET_ALTIVEC_ABI
5272169689Skan	   && (ALTIVEC_VECTOR_MODE (mode)
5273169689Skan	       || (type && TREE_CODE (type) == VECTOR_TYPE
5274169689Skan		   && int_size_in_bytes (type) == 16)))
527590075Sobrien    {
5276132718Skan      if (named || abi == ABI_V4)
5277132718Skan	return NULL_RTX;
527890075Sobrien      else
5279132718Skan	{
5280132718Skan	  /* Vector parameters to varargs functions under AIX or Darwin
5281132718Skan	     get passed in memory and possibly also in GPRs.  */
5282146895Skan	  int align, align_words, n_words;
5283146895Skan	  enum machine_mode part_mode;
5284132718Skan
5285132718Skan	  /* Vector parameters must be 16-byte aligned.  This places them at
5286132718Skan	     2 mod 4 in terms of words in 32-bit mode, since the parameter
5287132718Skan	     save area starts at offset 24 from the stack.  In 64-bit mode,
5288132718Skan	     they just have to start on an even word, since the parameter
5289132718Skan	     save area is 16-byte aligned.  */
5290132718Skan	  if (TARGET_32BIT)
5291132718Skan	    align = (2 - cum->words) & 3;
5292132718Skan	  else
5293132718Skan	    align = cum->words & 1;
5294132718Skan	  align_words = cum->words + align;
5295132718Skan
5296132718Skan	  /* Out of registers?  Memory, then.  */
5297132718Skan	  if (align_words >= GP_ARG_NUM_REG)
5298132718Skan	    return NULL_RTX;
5299146895Skan
5300146895Skan	  if (TARGET_32BIT && TARGET_POWERPC64)
5301146895Skan	    return rs6000_mixed_function_arg (mode, type, align_words);
5302146895Skan
5303132718Skan	  /* The vector value goes in GPRs.  Only the part of the
5304132718Skan	     value in GPRs is reported here.  */
5305146895Skan	  part_mode = mode;
5306146895Skan	  n_words = rs6000_arg_size (mode, type);
5307146895Skan	  if (align_words + n_words > GP_ARG_NUM_REG)
5308132718Skan	    /* Fortunately, there are only two possibilities, the value
5309132718Skan	       is either wholly in GPRs or half in GPRs and half not.  */
5310132718Skan	    part_mode = DImode;
5311146895Skan
5312132718Skan	  return gen_rtx_REG (part_mode, GP_ARG_MIN_REG + align_words);
5313132718Skan	}
531490075Sobrien    }
5315169689Skan  else if (TARGET_SPE_ABI && TARGET_SPE
5316169689Skan	   && (SPE_VECTOR_MODE (mode)
5317169689Skan	       || (TARGET_E500_DOUBLE && (mode == DFmode
5318169689Skan					  || mode == DCmode))))
5319132718Skan    return rs6000_spe_function_arg (cum, mode, type);
5320169689Skan
532190075Sobrien  else if (abi == ABI_V4)
532290075Sobrien    {
5323117395Skan      if (TARGET_HARD_FLOAT && TARGET_FPRS
5324169689Skan	  && (mode == SFmode || mode == DFmode
5325169689Skan	      || (mode == TFmode && !TARGET_IEEEQUAD)))
532690075Sobrien	{
5327169689Skan	  if (cum->fregno + (mode == TFmode ? 1 : 0) <= FP_ARG_V4_MAX_REG)
532890075Sobrien	    return gen_rtx_REG (mode, cum->fregno);
532990075Sobrien	  else
5330132718Skan	    return NULL_RTX;
533190075Sobrien	}
533290075Sobrien      else
533390075Sobrien	{
5334132718Skan	  int n_words = rs6000_arg_size (mode, type);
533590075Sobrien	  int gregno = cum->sysv_gregno;
533690075Sobrien
5337132718Skan	  /* Long long and SPE vectors are put in (r3,r4), (r5,r6),
5338132718Skan	     (r7,r8) or (r9,r10).  As does any other 2 word item such
5339132718Skan	     as complex int due to a historical mistake.  */
5340132718Skan	  if (n_words == 2)
5341132718Skan	    gregno += (1 - gregno) & 1;
534290075Sobrien
5343132718Skan	  /* Multi-reg args are not split between registers and stack.  */
5344146895Skan	  if (gregno + n_words - 1 > GP_ARG_MAX_REG)
5345132718Skan	    return NULL_RTX;
5346146895Skan
5347146895Skan	  if (TARGET_32BIT && TARGET_POWERPC64)
5348146895Skan	    return rs6000_mixed_function_arg (mode, type,
5349146895Skan					      gregno - GP_ARG_MIN_REG);
5350146895Skan	  return gen_rtx_REG (mode, gregno);
535190075Sobrien	}
535290075Sobrien    }
535390075Sobrien  else
535490075Sobrien    {
5355169689Skan      int align_words = rs6000_parm_start (mode, type, cum->words);
535690075Sobrien
5357132718Skan      if (USE_FP_FOR_ARG_P (cum, mode, type))
5358132718Skan	{
5359146895Skan	  rtx rvec[GP_ARG_NUM_REG + 1];
5360146895Skan	  rtx r;
5361146895Skan	  int k;
5362132718Skan	  bool needs_psave;
5363132718Skan	  enum machine_mode fmode = mode;
5364132718Skan	  unsigned long n_fpreg = (GET_MODE_SIZE (mode) + 7) >> 3;
536590075Sobrien
5366132718Skan	  if (cum->fregno + n_fpreg > FP_ARG_MAX_REG + 1)
5367132718Skan	    {
5368132718Skan	      /* Currently, we only ever need one reg here because complex
5369132718Skan		 doubles are split.  */
5370169689Skan	      gcc_assert (cum->fregno == FP_ARG_MAX_REG && fmode == TFmode);
5371146895Skan
5372146895Skan	      /* Long double split over regs and memory.  */
5373146895Skan	      fmode = DFmode;
5374132718Skan	    }
5375132718Skan
5376132718Skan	  /* Do we also need to pass this arg in the parameter save
5377132718Skan	     area?  */
5378132718Skan	  needs_psave = (type
5379132718Skan			 && (cum->nargs_prototype <= 0
5380132718Skan			     || (DEFAULT_ABI == ABI_AIX
5381146895Skan				 && TARGET_XL_COMPAT
5382132718Skan				 && align_words >= GP_ARG_NUM_REG)));
5383132718Skan
5384132718Skan	  if (!needs_psave && mode == fmode)
5385146895Skan	    return gen_rtx_REG (fmode, cum->fregno);
5386132718Skan
5387146895Skan	  k = 0;
5388132718Skan	  if (needs_psave)
5389132718Skan	    {
5390146895Skan	      /* Describe the part that goes in gprs or the stack.
5391132718Skan		 This piece must come first, before the fprs.  */
5392132718Skan	      if (align_words < GP_ARG_NUM_REG)
5393132718Skan		{
5394132718Skan		  unsigned long n_words = rs6000_arg_size (mode, type);
5395132718Skan
5396146895Skan		  if (align_words + n_words > GP_ARG_NUM_REG
5397146895Skan		      || (TARGET_32BIT && TARGET_POWERPC64))
5398146895Skan		    {
5399146895Skan		      /* If this is partially on the stack, then we only
5400146895Skan			 include the portion actually in registers here.  */
5401146895Skan		      enum machine_mode rmode = TARGET_32BIT ? SImode : DImode;
5402146895Skan		      rtx off;
5403169689Skan		      int i = 0;
5404169689Skan		      if (align_words + n_words > GP_ARG_NUM_REG)
5405169689Skan			/* Not all of the arg fits in gprs.  Say that it
5406169689Skan			   goes in memory too, using a magic NULL_RTX
5407169689Skan			   component.  Also see comment in
5408169689Skan			   rs6000_mixed_function_arg for why the normal
5409169689Skan			   function_arg_partial_nregs scheme doesn't work
5410169689Skan			   in this case. */
5411169689Skan			rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX,
5412169689Skan						       const0_rtx);
5413146895Skan		      do
5414146895Skan			{
5415146895Skan			  r = gen_rtx_REG (rmode,
5416146895Skan					   GP_ARG_MIN_REG + align_words);
5417169689Skan			  off = GEN_INT (i++ * GET_MODE_SIZE (rmode));
5418146895Skan			  rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, off);
5419146895Skan			}
5420146895Skan		      while (++align_words < GP_ARG_NUM_REG && --n_words != 0);
5421146895Skan		    }
5422146895Skan		  else
5423146895Skan		    {
5424146895Skan		      /* The whole arg fits in gprs.  */
5425146895Skan		      r = gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
5426146895Skan		      rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, const0_rtx);
5427146895Skan		    }
5428132718Skan		}
5429146895Skan	      else
5430146895Skan		/* It's entirely in memory.  */
5431146895Skan		rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX, const0_rtx);
5432132718Skan	    }
5433132718Skan
5434146895Skan	  /* Describe where this piece goes in the fprs.  */
5435146895Skan	  r = gen_rtx_REG (fmode, cum->fregno);
5436146895Skan	  rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, const0_rtx);
5437146895Skan
5438146895Skan	  return gen_rtx_PARALLEL (mode, gen_rtvec_v (k, rvec));
5439132718Skan	}
5440132718Skan      else if (align_words < GP_ARG_NUM_REG)
544190075Sobrien	{
5442146895Skan	  if (TARGET_32BIT && TARGET_POWERPC64)
5443146895Skan	    return rs6000_mixed_function_arg (mode, type, align_words);
544490075Sobrien
5445169689Skan	  if (mode == BLKmode)
5446169689Skan	    mode = Pmode;
5447169689Skan
5448132718Skan	  return gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
544990075Sobrien	}
545090075Sobrien      else
545190075Sobrien	return NULL_RTX;
545290075Sobrien    }
545390075Sobrien}
545490075Sobrien
5455146895Skan/* For an arg passed partly in registers and partly in memory, this is
5456169689Skan   the number of bytes passed in registers.  For args passed entirely in
5457169689Skan   registers or entirely in memory, zero.  When an arg is described by a
5458169689Skan   PARALLEL, perhaps using more than one register type, this function
5459169689Skan   returns the number of bytes used by the first element of the PARALLEL.  */
546090075Sobrien
5461169689Skanstatic int
5462169689Skanrs6000_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
5463169689Skan			  tree type, bool named)
546490075Sobrien{
5465132718Skan  int ret = 0;
5466146895Skan  int align_words;
5467132718Skan
546890075Sobrien  if (DEFAULT_ABI == ABI_V4)
546990075Sobrien    return 0;
547090075Sobrien
5471132718Skan  if (USE_ALTIVEC_FOR_ARG_P (cum, mode, type, named)
5472132718Skan      && cum->nargs_prototype >= 0)
5473132718Skan    return 0;
5474132718Skan
5475169689Skan  /* In this complicated case we just disable the partial_nregs code.  */
5476169689Skan  if (rs6000_darwin64_abi && mode == BLKmode
5477169689Skan      && TREE_CODE (type) == RECORD_TYPE
5478169689Skan      && int_size_in_bytes (type) > 0)
5479169689Skan    return 0;
5480146895Skan
5481169689Skan  align_words = rs6000_parm_start (mode, type, cum->words);
5482169689Skan
5483169689Skan  if (USE_FP_FOR_ARG_P (cum, mode, type))
548490075Sobrien    {
5485169689Skan      /* If we are passing this arg in the fixed parameter save area
5486169689Skan	 (gprs or memory) as well as fprs, then this function should
5487169689Skan	 return the number of partial bytes passed in the parameter
5488169689Skan	 save area rather than partial bytes passed in fprs.  */
5489169689Skan      if (type
5490169689Skan	  && (cum->nargs_prototype <= 0
5491169689Skan	      || (DEFAULT_ABI == ABI_AIX
5492169689Skan		  && TARGET_XL_COMPAT
5493169689Skan		  && align_words >= GP_ARG_NUM_REG)))
5494169689Skan	return 0;
5495169689Skan      else if (cum->fregno + ((GET_MODE_SIZE (mode) + 7) >> 3)
5496169689Skan	       > FP_ARG_MAX_REG + 1)
5497169689Skan	ret = (FP_ARG_MAX_REG + 1 - cum->fregno) * 8;
5498132718Skan      else if (cum->nargs_prototype >= 0)
549990075Sobrien	return 0;
550090075Sobrien    }
550190075Sobrien
5502146895Skan  if (align_words < GP_ARG_NUM_REG
5503146895Skan      && GP_ARG_NUM_REG < align_words + rs6000_arg_size (mode, type))
5504169689Skan    ret = (GP_ARG_NUM_REG - align_words) * (TARGET_32BIT ? 4 : 8);
550590075Sobrien
5506132718Skan  if (ret != 0 && TARGET_DEBUG_ARG)
5507169689Skan    fprintf (stderr, "rs6000_arg_partial_bytes: %d\n", ret);
550890075Sobrien
5509132718Skan  return ret;
551090075Sobrien}
551190075Sobrien
551290075Sobrien/* A C expression that indicates when an argument must be passed by
551390075Sobrien   reference.  If nonzero for an argument, a copy of that argument is
551490075Sobrien   made in memory and a pointer to the argument is passed instead of
551590075Sobrien   the argument itself.  The pointer is passed in whatever way is
551690075Sobrien   appropriate for passing a pointer to that type.
551790075Sobrien
5518132718Skan   Under V.4, aggregates and long double are passed by reference.
551990075Sobrien
5520132718Skan   As an extension to all 32-bit ABIs, AltiVec vectors are passed by
5521132718Skan   reference unless the AltiVec vector extension ABI is in force.
5522132718Skan
5523117395Skan   As an extension to all ABIs, variable sized types are passed by
5524117395Skan   reference.  */
5525117395Skan
5526169689Skanstatic bool
5527169689Skanrs6000_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
5528169689Skan			  enum machine_mode mode, tree type,
5529169689Skan			  bool named ATTRIBUTE_UNUSED)
553090075Sobrien{
5531169689Skan  if (DEFAULT_ABI == ABI_V4 && TARGET_IEEEQUAD && mode == TFmode)
553290075Sobrien    {
553390075Sobrien      if (TARGET_DEBUG_ARG)
5534169689Skan	fprintf (stderr, "function_arg_pass_by_reference: V4 long double\n");
5535169689Skan      return 1;
5536169689Skan    }
553790075Sobrien
5538169689Skan  if (!type)
5539169689Skan    return 0;
5540169689Skan
5541169689Skan  if (DEFAULT_ABI == ABI_V4 && AGGREGATE_TYPE_P (type))
5542169689Skan    {
5543169689Skan      if (TARGET_DEBUG_ARG)
5544169689Skan	fprintf (stderr, "function_arg_pass_by_reference: V4 aggregate\n");
554590075Sobrien      return 1;
554690075Sobrien    }
5547169689Skan
5548169689Skan  if (int_size_in_bytes (type) < 0)
5549169689Skan    {
5550169689Skan      if (TARGET_DEBUG_ARG)
5551169689Skan	fprintf (stderr, "function_arg_pass_by_reference: variable size\n");
5552169689Skan      return 1;
5553169689Skan    }
5554169689Skan
5555169689Skan  /* Allow -maltivec -mabi=no-altivec without warning.  Altivec vector
5556169689Skan     modes only exist for GCC vector types if -maltivec.  */
5557169689Skan  if (TARGET_32BIT && !TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
5558169689Skan    {
5559169689Skan      if (TARGET_DEBUG_ARG)
5560169689Skan	fprintf (stderr, "function_arg_pass_by_reference: AltiVec\n");
5561169689Skan      return 1;
5562169689Skan    }
5563169689Skan
5564169689Skan  /* Pass synthetic vectors in memory.  */
5565169689Skan  if (TREE_CODE (type) == VECTOR_TYPE
5566169689Skan      && int_size_in_bytes (type) > (TARGET_ALTIVEC_ABI ? 16 : 8))
5567169689Skan    {
5568169689Skan      static bool warned_for_pass_big_vectors = false;
5569169689Skan      if (TARGET_DEBUG_ARG)
5570169689Skan	fprintf (stderr, "function_arg_pass_by_reference: synthetic vector\n");
5571169689Skan      if (!warned_for_pass_big_vectors)
5572169689Skan	{
5573169689Skan	  warning (0, "GCC vector passed by reference: "
5574169689Skan		   "non-standard ABI extension with no compatibility guarantee");
5575169689Skan	  warned_for_pass_big_vectors = true;
5576169689Skan	}
5577169689Skan      return 1;
5578169689Skan    }
5579169689Skan
5580132718Skan  return 0;
558190075Sobrien}
5582132718Skan
5583132718Skanstatic void
5584132718Skanrs6000_move_block_from_reg (int regno, rtx x, int nregs)
5585132718Skan{
5586132718Skan  int i;
5587132718Skan  enum machine_mode reg_mode = TARGET_32BIT ? SImode : DImode;
5588132718Skan
5589132718Skan  if (nregs == 0)
5590132718Skan    return;
5591132718Skan
5592169689Skan  for (i = 0; i < nregs; i++)
5593132718Skan    {
5594169689Skan      rtx tem = adjust_address_nv (x, reg_mode, i * GET_MODE_SIZE (reg_mode));
5595132718Skan      if (reload_completed)
5596169689Skan	{
5597169689Skan	  if (! strict_memory_address_p (reg_mode, XEXP (tem, 0)))
5598169689Skan	    tem = NULL_RTX;
5599169689Skan	  else
5600169689Skan	    tem = simplify_gen_subreg (reg_mode, x, BLKmode,
5601169689Skan				       i * GET_MODE_SIZE (reg_mode));
5602169689Skan	}
5603132718Skan      else
5604132718Skan	tem = replace_equiv_address (tem, XEXP (tem, 0));
5605132718Skan
5606169689Skan      gcc_assert (tem);
5607132718Skan
5608132718Skan      emit_move_insn (tem, gen_rtx_REG (reg_mode, regno + i));
5609132718Skan    }
5610132718Skan}
561190075Sobrien
561290075Sobrien/* Perform any needed actions needed for a function that is receiving a
5613169689Skan   variable number of arguments.
561490075Sobrien
561590075Sobrien   CUM is as above.
561690075Sobrien
561790075Sobrien   MODE and TYPE are the mode and type of the current parameter.
561890075Sobrien
561990075Sobrien   PRETEND_SIZE is a variable that should be set to the amount of stack
562090075Sobrien   that must be pushed by the prolog to pretend that our caller pushed
562190075Sobrien   it.
562290075Sobrien
562390075Sobrien   Normally, this macro will push all remaining incoming registers on the
562490075Sobrien   stack and set PRETEND_SIZE to the length of the registers pushed.  */
562590075Sobrien
5626132718Skanstatic void
5627169689Skansetup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
5628169689Skan			tree type, int *pretend_size ATTRIBUTE_UNUSED,
5629169689Skan			int no_rtl)
563090075Sobrien{
563190075Sobrien  CUMULATIVE_ARGS next_cum;
563290075Sobrien  int reg_size = TARGET_32BIT ? 4 : 8;
563390075Sobrien  rtx save_area = NULL_RTX, mem;
563490075Sobrien  int first_reg_offset, set;
563590075Sobrien
5636132718Skan  /* Skip the last named argument.  */
563790075Sobrien  next_cum = *cum;
5638169689Skan  function_arg_advance (&next_cum, mode, type, 1, 0);
563990075Sobrien
564090075Sobrien  if (DEFAULT_ABI == ABI_V4)
564190075Sobrien    {
5642169689Skan      first_reg_offset = next_cum.sysv_gregno - GP_ARG_MIN_REG;
5643169689Skan
564490075Sobrien      if (! no_rtl)
5645169689Skan	{
5646169689Skan	  int gpr_reg_num = 0, gpr_size = 0, fpr_size = 0;
5647169689Skan	  HOST_WIDE_INT offset = 0;
564890075Sobrien
5649169689Skan	  /* Try to optimize the size of the varargs save area.
5650169689Skan	     The ABI requires that ap.reg_save_area is doubleword
5651169689Skan	     aligned, but we don't need to allocate space for all
5652169689Skan	     the bytes, only those to which we actually will save
5653169689Skan	     anything.  */
5654169689Skan	  if (cfun->va_list_gpr_size && first_reg_offset < GP_ARG_NUM_REG)
5655169689Skan	    gpr_reg_num = GP_ARG_NUM_REG - first_reg_offset;
5656169689Skan	  if (TARGET_HARD_FLOAT && TARGET_FPRS
5657169689Skan	      && next_cum.fregno <= FP_ARG_V4_MAX_REG
5658169689Skan	      && cfun->va_list_fpr_size)
5659169689Skan	    {
5660169689Skan	      if (gpr_reg_num)
5661169689Skan		fpr_size = (next_cum.fregno - FP_ARG_MIN_REG)
5662169689Skan			   * UNITS_PER_FP_WORD;
5663169689Skan	      if (cfun->va_list_fpr_size
5664169689Skan		  < FP_ARG_V4_MAX_REG + 1 - next_cum.fregno)
5665169689Skan		fpr_size += cfun->va_list_fpr_size * UNITS_PER_FP_WORD;
5666169689Skan	      else
5667169689Skan		fpr_size += (FP_ARG_V4_MAX_REG + 1 - next_cum.fregno)
5668169689Skan			    * UNITS_PER_FP_WORD;
5669169689Skan	    }
5670169689Skan	  if (gpr_reg_num)
5671169689Skan	    {
5672169689Skan	      offset = -((first_reg_offset * reg_size) & ~7);
5673169689Skan	      if (!fpr_size && gpr_reg_num > cfun->va_list_gpr_size)
5674169689Skan		{
5675169689Skan		  gpr_reg_num = cfun->va_list_gpr_size;
5676169689Skan		  if (reg_size == 4 && (first_reg_offset & 1))
5677169689Skan		    gpr_reg_num++;
5678169689Skan		}
5679169689Skan	      gpr_size = (gpr_reg_num * reg_size + 7) & ~7;
5680169689Skan	    }
5681169689Skan	  else if (fpr_size)
5682169689Skan	    offset = - (int) (next_cum.fregno - FP_ARG_MIN_REG)
5683169689Skan		       * UNITS_PER_FP_WORD
5684169689Skan		     - (int) (GP_ARG_NUM_REG * reg_size);
5685169689Skan
5686169689Skan	  if (gpr_size + fpr_size)
5687169689Skan	    {
5688169689Skan	      rtx reg_save_area
5689169689Skan		= assign_stack_local (BLKmode, gpr_size + fpr_size, 64);
5690169689Skan	      gcc_assert (GET_CODE (reg_save_area) == MEM);
5691169689Skan	      reg_save_area = XEXP (reg_save_area, 0);
5692169689Skan	      if (GET_CODE (reg_save_area) == PLUS)
5693169689Skan		{
5694169689Skan		  gcc_assert (XEXP (reg_save_area, 0)
5695169689Skan			      == virtual_stack_vars_rtx);
5696169689Skan		  gcc_assert (GET_CODE (XEXP (reg_save_area, 1)) == CONST_INT);
5697169689Skan		  offset += INTVAL (XEXP (reg_save_area, 1));
5698169689Skan		}
5699169689Skan	      else
5700169689Skan		gcc_assert (reg_save_area == virtual_stack_vars_rtx);
5701169689Skan	    }
5702169689Skan
5703169689Skan	  cfun->machine->varargs_save_offset = offset;
5704169689Skan	  save_area = plus_constant (virtual_stack_vars_rtx, offset);
5705169689Skan	}
570690075Sobrien    }
570790075Sobrien  else
570890075Sobrien    {
570990075Sobrien      first_reg_offset = next_cum.words;
571090075Sobrien      save_area = virtual_incoming_args_rtx;
571190075Sobrien
5712169689Skan      if (targetm.calls.must_pass_in_stack (mode, type))
5713132718Skan	first_reg_offset += rs6000_arg_size (TYPE_MODE (type), type);
571490075Sobrien    }
571590075Sobrien
571690075Sobrien  set = get_varargs_alias_set ();
5717169689Skan  if (! no_rtl && first_reg_offset < GP_ARG_NUM_REG
5718169689Skan      && cfun->va_list_gpr_size)
571990075Sobrien    {
5720169689Skan      int nregs = GP_ARG_NUM_REG - first_reg_offset;
5721169689Skan
5722169689Skan      if (va_list_gpr_counter_field)
5723169689Skan	{
5724169689Skan	  /* V4 va_list_gpr_size counts number of registers needed.  */
5725169689Skan	  if (nregs > cfun->va_list_gpr_size)
5726169689Skan	    nregs = cfun->va_list_gpr_size;
5727169689Skan	}
5728169689Skan      else
5729169689Skan	{
5730169689Skan	  /* char * va_list instead counts number of bytes needed.  */
5731169689Skan	  if (nregs > cfun->va_list_gpr_size / reg_size)
5732169689Skan	    nregs = cfun->va_list_gpr_size / reg_size;
5733169689Skan	}
5734169689Skan
573590075Sobrien      mem = gen_rtx_MEM (BLKmode,
5736169689Skan			 plus_constant (save_area,
5737169689Skan					first_reg_offset * reg_size));
5738169689Skan      MEM_NOTRAP_P (mem) = 1;
573990075Sobrien      set_mem_alias_set (mem, set);
574090075Sobrien      set_mem_align (mem, BITS_PER_WORD);
574190075Sobrien
5742169689Skan      rs6000_move_block_from_reg (GP_ARG_MIN_REG + first_reg_offset, mem,
5743169689Skan				  nregs);
574490075Sobrien    }
574590075Sobrien
574690075Sobrien  /* Save FP registers if needed.  */
574790075Sobrien  if (DEFAULT_ABI == ABI_V4
5748117395Skan      && TARGET_HARD_FLOAT && TARGET_FPRS
5749117395Skan      && ! no_rtl
5750169689Skan      && next_cum.fregno <= FP_ARG_V4_MAX_REG
5751169689Skan      && cfun->va_list_fpr_size)
575290075Sobrien    {
5753169689Skan      int fregno = next_cum.fregno, nregs;
575490075Sobrien      rtx cr1 = gen_rtx_REG (CCmode, CR1_REGNO);
575590075Sobrien      rtx lab = gen_label_rtx ();
5756169689Skan      int off = (GP_ARG_NUM_REG * reg_size) + ((fregno - FP_ARG_MIN_REG)
5757169689Skan					       * UNITS_PER_FP_WORD);
575890075Sobrien
5759169689Skan      emit_jump_insn
5760169689Skan	(gen_rtx_SET (VOIDmode,
5761169689Skan		      pc_rtx,
5762169689Skan		      gen_rtx_IF_THEN_ELSE (VOIDmode,
576390075Sobrien					    gen_rtx_NE (VOIDmode, cr1,
5764169689Skan							const0_rtx),
576590075Sobrien					    gen_rtx_LABEL_REF (VOIDmode, lab),
576690075Sobrien					    pc_rtx)));
576790075Sobrien
5768169689Skan      for (nregs = 0;
5769169689Skan	   fregno <= FP_ARG_V4_MAX_REG && nregs < cfun->va_list_fpr_size;
5770169689Skan	   fregno++, off += UNITS_PER_FP_WORD, nregs++)
577190075Sobrien	{
577290075Sobrien	  mem = gen_rtx_MEM (DFmode, plus_constant (save_area, off));
5773169689Skan	  MEM_NOTRAP_P (mem) = 1;
5774169689Skan	  set_mem_alias_set (mem, set);
5775146895Skan	  set_mem_align (mem, GET_MODE_ALIGNMENT (DFmode));
577690075Sobrien	  emit_move_insn (mem, gen_rtx_REG (DFmode, fregno));
577790075Sobrien	}
577890075Sobrien
577990075Sobrien      emit_label (lab);
578090075Sobrien    }
578190075Sobrien}
578290075Sobrien
578390075Sobrien/* Create the va_list data type.  */
578490075Sobrien
5785132718Skanstatic tree
5786132718Skanrs6000_build_builtin_va_list (void)
578790075Sobrien{
5788132718Skan  tree f_gpr, f_fpr, f_res, f_ovf, f_sav, record, type_decl;
578990075Sobrien
579090075Sobrien  /* For AIX, prefer 'char *' because that's what the system
579190075Sobrien     header files like.  */
579290075Sobrien  if (DEFAULT_ABI != ABI_V4)
579390075Sobrien    return build_pointer_type (char_type_node);
579490075Sobrien
5795117395Skan  record = (*lang_hooks.types.make_type) (RECORD_TYPE);
579690075Sobrien  type_decl = build_decl (TYPE_DECL, get_identifier ("__va_list_tag"), record);
579790075Sobrien
5798169689Skan  f_gpr = build_decl (FIELD_DECL, get_identifier ("gpr"),
579990075Sobrien		      unsigned_char_type_node);
5800169689Skan  f_fpr = build_decl (FIELD_DECL, get_identifier ("fpr"),
580190075Sobrien		      unsigned_char_type_node);
5802132718Skan  /* Give the two bytes of padding a name, so that -Wpadded won't warn on
5803132718Skan     every user file.  */
5804132718Skan  f_res = build_decl (FIELD_DECL, get_identifier ("reserved"),
5805132718Skan		      short_unsigned_type_node);
580690075Sobrien  f_ovf = build_decl (FIELD_DECL, get_identifier ("overflow_arg_area"),
580790075Sobrien		      ptr_type_node);
580890075Sobrien  f_sav = build_decl (FIELD_DECL, get_identifier ("reg_save_area"),
580990075Sobrien		      ptr_type_node);
581090075Sobrien
5811169689Skan  va_list_gpr_counter_field = f_gpr;
5812169689Skan  va_list_fpr_counter_field = f_fpr;
5813169689Skan
581490075Sobrien  DECL_FIELD_CONTEXT (f_gpr) = record;
581590075Sobrien  DECL_FIELD_CONTEXT (f_fpr) = record;
5816132718Skan  DECL_FIELD_CONTEXT (f_res) = record;
581790075Sobrien  DECL_FIELD_CONTEXT (f_ovf) = record;
581890075Sobrien  DECL_FIELD_CONTEXT (f_sav) = record;
581990075Sobrien
582090075Sobrien  TREE_CHAIN (record) = type_decl;
582190075Sobrien  TYPE_NAME (record) = type_decl;
582290075Sobrien  TYPE_FIELDS (record) = f_gpr;
582390075Sobrien  TREE_CHAIN (f_gpr) = f_fpr;
5824132718Skan  TREE_CHAIN (f_fpr) = f_res;
5825132718Skan  TREE_CHAIN (f_res) = f_ovf;
582690075Sobrien  TREE_CHAIN (f_ovf) = f_sav;
582790075Sobrien
582890075Sobrien  layout_type (record);
582990075Sobrien
583090075Sobrien  /* The correct type is an array type of one element.  */
583190075Sobrien  return build_array_type (record, build_index_type (size_zero_node));
583290075Sobrien}
583390075Sobrien
583490075Sobrien/* Implement va_start.  */
583590075Sobrien
583690075Sobrienvoid
5837132718Skanrs6000_va_start (tree valist, rtx nextarg)
583890075Sobrien{
583990075Sobrien  HOST_WIDE_INT words, n_gpr, n_fpr;
5840132718Skan  tree f_gpr, f_fpr, f_res, f_ovf, f_sav;
584190075Sobrien  tree gpr, fpr, ovf, sav, t;
584290075Sobrien
584390075Sobrien  /* Only SVR4 needs something special.  */
584490075Sobrien  if (DEFAULT_ABI != ABI_V4)
584590075Sobrien    {
5846117395Skan      std_expand_builtin_va_start (valist, nextarg);
584790075Sobrien      return;
584890075Sobrien    }
584990075Sobrien
585090075Sobrien  f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
585190075Sobrien  f_fpr = TREE_CHAIN (f_gpr);
5852132718Skan  f_res = TREE_CHAIN (f_fpr);
5853132718Skan  f_ovf = TREE_CHAIN (f_res);
585490075Sobrien  f_sav = TREE_CHAIN (f_ovf);
585590075Sobrien
5856169689Skan  valist = build_va_arg_indirect_ref (valist);
5857169689Skan  gpr = build3 (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr, NULL_TREE);
5858169689Skan  fpr = build3 (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr, NULL_TREE);
5859169689Skan  ovf = build3 (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf, NULL_TREE);
5860169689Skan  sav = build3 (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav, NULL_TREE);
586190075Sobrien
586290075Sobrien  /* Count number of gp and fp argument registers used.  */
586390075Sobrien  words = current_function_args_info.words;
5864169689Skan  n_gpr = MIN (current_function_args_info.sysv_gregno - GP_ARG_MIN_REG,
5865169689Skan	       GP_ARG_NUM_REG);
5866169689Skan  n_fpr = MIN (current_function_args_info.fregno - FP_ARG_MIN_REG,
5867169689Skan	       FP_ARG_NUM_REG);
586890075Sobrien
586990075Sobrien  if (TARGET_DEBUG_ARG)
5870132718Skan    fprintf (stderr, "va_start: words = "HOST_WIDE_INT_PRINT_DEC", n_gpr = "
5871132718Skan	     HOST_WIDE_INT_PRINT_DEC", n_fpr = "HOST_WIDE_INT_PRINT_DEC"\n",
5872132718Skan	     words, n_gpr, n_fpr);
587390075Sobrien
5874169689Skan  if (cfun->va_list_gpr_size)
5875169689Skan    {
5876169689Skan      t = build2 (MODIFY_EXPR, TREE_TYPE (gpr), gpr,
5877169689Skan		  build_int_cst (NULL_TREE, n_gpr));
5878169689Skan      TREE_SIDE_EFFECTS (t) = 1;
5879169689Skan      expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
5880169689Skan    }
588190075Sobrien
5882169689Skan  if (cfun->va_list_fpr_size)
5883169689Skan    {
5884169689Skan      t = build2 (MODIFY_EXPR, TREE_TYPE (fpr), fpr,
5885169689Skan		  build_int_cst (NULL_TREE, n_fpr));
5886169689Skan      TREE_SIDE_EFFECTS (t) = 1;
5887169689Skan      expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
5888169689Skan    }
588990075Sobrien
589090075Sobrien  /* Find the overflow area.  */
589190075Sobrien  t = make_tree (TREE_TYPE (ovf), virtual_incoming_args_rtx);
589290075Sobrien  if (words != 0)
5893169689Skan    t = build2 (PLUS_EXPR, TREE_TYPE (ovf), t,
5894169689Skan	        build_int_cst (NULL_TREE, words * UNITS_PER_WORD));
5895169689Skan  t = build2 (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t);
589690075Sobrien  TREE_SIDE_EFFECTS (t) = 1;
589790075Sobrien  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
589890075Sobrien
5899169689Skan  /* If there were no va_arg invocations, don't set up the register
5900169689Skan     save area.  */
5901169689Skan  if (!cfun->va_list_gpr_size
5902169689Skan      && !cfun->va_list_fpr_size
5903169689Skan      && n_gpr < GP_ARG_NUM_REG
5904169689Skan      && n_fpr < FP_ARG_V4_MAX_REG)
5905169689Skan    return;
5906169689Skan
590790075Sobrien  /* Find the register save area.  */
590890075Sobrien  t = make_tree (TREE_TYPE (sav), virtual_stack_vars_rtx);
5909169689Skan  if (cfun->machine->varargs_save_offset)
5910169689Skan    t = build2 (PLUS_EXPR, TREE_TYPE (sav), t,
5911169689Skan	        build_int_cst (NULL_TREE, cfun->machine->varargs_save_offset));
5912169689Skan  t = build2 (MODIFY_EXPR, TREE_TYPE (sav), sav, t);
591390075Sobrien  TREE_SIDE_EFFECTS (t) = 1;
591490075Sobrien  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
591590075Sobrien}
591690075Sobrien
591790075Sobrien/* Implement va_arg.  */
591890075Sobrien
5919169689Skantree
5920169689Skanrs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
592190075Sobrien{
5922132718Skan  tree f_gpr, f_fpr, f_res, f_ovf, f_sav;
592390075Sobrien  tree gpr, fpr, ovf, sav, reg, t, u;
5924169689Skan  int size, rsize, n_reg, sav_ofs, sav_scale;
5925169689Skan  tree lab_false, lab_over, addr;
5926132718Skan  int align;
5927169689Skan  tree ptrtype = build_pointer_type (type);
592890075Sobrien
5929169689Skan  if (pass_by_reference (NULL, TYPE_MODE (type), type, false))
5930169689Skan    {
5931169689Skan      t = rs6000_gimplify_va_arg (valist, ptrtype, pre_p, post_p);
5932169689Skan      return build_va_arg_indirect_ref (t);
5933169689Skan    }
5934169689Skan
593590075Sobrien  if (DEFAULT_ABI != ABI_V4)
5936117395Skan    {
5937169689Skan      if (targetm.calls.split_complex_arg && TREE_CODE (type) == COMPLEX_TYPE)
5938117395Skan	{
5939132718Skan	  tree elem_type = TREE_TYPE (type);
5940132718Skan	  enum machine_mode elem_mode = TYPE_MODE (elem_type);
5941132718Skan	  int elem_size = GET_MODE_SIZE (elem_mode);
5942132718Skan
5943132718Skan	  if (elem_size < UNITS_PER_WORD)
5944132718Skan	    {
5945169689Skan	      tree real_part, imag_part;
5946169689Skan	      tree post = NULL_TREE;
5947132718Skan
5948169689Skan	      real_part = rs6000_gimplify_va_arg (valist, elem_type, pre_p,
5949169689Skan						  &post);
5950169689Skan	      /* Copy the value into a temporary, lest the formal temporary
5951169689Skan		 be reused out from under us.  */
5952169689Skan	      real_part = get_initialized_tmp_var (real_part, pre_p, &post);
5953169689Skan	      append_to_statement_list (post, pre_p);
5954132718Skan
5955169689Skan	      imag_part = rs6000_gimplify_va_arg (valist, elem_type, pre_p,
5956169689Skan						  post_p);
5957132718Skan
5958169689Skan	      return build2 (COMPLEX_EXPR, type, real_part, imag_part);
5959132718Skan	    }
5960132718Skan	}
5961132718Skan
5962169689Skan      return std_gimplify_va_arg_expr (valist, type, pre_p, post_p);
5963117395Skan    }
5964117395Skan
596590075Sobrien  f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
596690075Sobrien  f_fpr = TREE_CHAIN (f_gpr);
5967132718Skan  f_res = TREE_CHAIN (f_fpr);
5968132718Skan  f_ovf = TREE_CHAIN (f_res);
596990075Sobrien  f_sav = TREE_CHAIN (f_ovf);
597090075Sobrien
5971169689Skan  valist = build_va_arg_indirect_ref (valist);
5972169689Skan  gpr = build3 (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr, NULL_TREE);
5973169689Skan  fpr = build3 (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr, NULL_TREE);
5974169689Skan  ovf = build3 (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf, NULL_TREE);
5975169689Skan  sav = build3 (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav, NULL_TREE);
597690075Sobrien
597790075Sobrien  size = int_size_in_bytes (type);
5978132718Skan  rsize = (size + 3) / 4;
5979132718Skan  align = 1;
598090075Sobrien
5981169689Skan  if (TARGET_HARD_FLOAT && TARGET_FPRS
5982169689Skan      && (TYPE_MODE (type) == SFmode
5983169689Skan	  || TYPE_MODE (type) == DFmode
5984169689Skan	  || TYPE_MODE (type) == TFmode))
598590075Sobrien    {
598690075Sobrien      /* FP args go in FP registers, if present.  */
598790075Sobrien      reg = fpr;
5988169689Skan      n_reg = (size + 7) / 8;
598990075Sobrien      sav_ofs = 8*4;
599090075Sobrien      sav_scale = 8;
5991169689Skan      if (TYPE_MODE (type) != SFmode)
5992132718Skan	align = 8;
599390075Sobrien    }
599490075Sobrien  else
599590075Sobrien    {
599690075Sobrien      /* Otherwise into GP registers.  */
599790075Sobrien      reg = gpr;
599890075Sobrien      n_reg = rsize;
599990075Sobrien      sav_ofs = 0;
600090075Sobrien      sav_scale = 4;
6001132718Skan      if (n_reg == 2)
6002132718Skan	align = 8;
600390075Sobrien    }
600490075Sobrien
6005132718Skan  /* Pull the value out of the saved registers....  */
600690075Sobrien
6007169689Skan  lab_over = NULL;
6008169689Skan  addr = create_tmp_var (ptr_type_node, "addr");
6009169689Skan  DECL_POINTER_ALIAS_SET (addr) = get_varargs_alias_set ();
601090075Sobrien
6011132718Skan  /*  AltiVec vectors never go in registers when -mabi=altivec.  */
6012132718Skan  if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (TYPE_MODE (type)))
6013132718Skan    align = 16;
6014132718Skan  else
601596263Sobrien    {
6016169689Skan      lab_false = create_artificial_label ();
6017169689Skan      lab_over = create_artificial_label ();
601890075Sobrien
6019132718Skan      /* Long long and SPE vectors are aligned in the registers.
6020132718Skan	 As are any other 2 gpr item such as complex int due to a
6021132718Skan	 historical mistake.  */
6022132718Skan      u = reg;
6023169689Skan      if (n_reg == 2 && reg == gpr)
602496263Sobrien	{
6025169689Skan	  u = build2 (BIT_AND_EXPR, TREE_TYPE (reg), reg,
6026169689Skan		     size_int (n_reg - 1));
6027169689Skan	  u = build2 (POSTINCREMENT_EXPR, TREE_TYPE (reg), reg, u);
602896263Sobrien	}
602996263Sobrien
6030169689Skan      t = fold_convert (TREE_TYPE (reg), size_int (8 - n_reg + 1));
6031169689Skan      t = build2 (GE_EXPR, boolean_type_node, u, t);
6032169689Skan      u = build1 (GOTO_EXPR, void_type_node, lab_false);
6033169689Skan      t = build3 (COND_EXPR, void_type_node, t, u, NULL_TREE);
6034169689Skan      gimplify_and_add (t, pre_p);
6035132718Skan
6036132718Skan      t = sav;
603796263Sobrien      if (sav_ofs)
6038169689Skan	t = build2 (PLUS_EXPR, ptr_type_node, sav, size_int (sav_ofs));
603996263Sobrien
6040169689Skan      u = build2 (POSTINCREMENT_EXPR, TREE_TYPE (reg), reg, size_int (n_reg));
604196263Sobrien      u = build1 (CONVERT_EXPR, integer_type_node, u);
6042169689Skan      u = build2 (MULT_EXPR, integer_type_node, u, size_int (sav_scale));
6043169689Skan      t = build2 (PLUS_EXPR, ptr_type_node, t, u);
604490075Sobrien
6045169689Skan      t = build2 (MODIFY_EXPR, void_type_node, addr, t);
6046169689Skan      gimplify_and_add (t, pre_p);
604790075Sobrien
6048169689Skan      t = build1 (GOTO_EXPR, void_type_node, lab_over);
6049169689Skan      gimplify_and_add (t, pre_p);
605090075Sobrien
6051169689Skan      t = build1 (LABEL_EXPR, void_type_node, lab_false);
6052169689Skan      append_to_statement_list (t, pre_p);
605390075Sobrien
6054169689Skan      if ((n_reg == 2 && reg != gpr) || n_reg > 2)
6055132718Skan	{
6056132718Skan	  /* Ensure that we don't find any more args in regs.
6057169689Skan	     Alignment has taken care of the n_reg == 2 gpr case.  */
6058169689Skan	  t = build2 (MODIFY_EXPR, TREE_TYPE (reg), reg, size_int (8));
6059169689Skan	  gimplify_and_add (t, pre_p);
6060132718Skan	}
606196263Sobrien    }
606290075Sobrien
606390075Sobrien  /* ... otherwise out of the overflow area.  */
606490075Sobrien
606590075Sobrien  /* Care for on-stack alignment if needed.  */
6066132718Skan  t = ovf;
6067132718Skan  if (align != 1)
606890075Sobrien    {
6069169689Skan      t = build2 (PLUS_EXPR, TREE_TYPE (t), t, size_int (align - 1));
6070169689Skan      t = build2 (BIT_AND_EXPR, TREE_TYPE (t), t,
6071169689Skan		  build_int_cst (NULL_TREE, -align));
607290075Sobrien    }
6073169689Skan  gimplify_expr (&t, pre_p, NULL, is_gimple_val, fb_rvalue);
607490075Sobrien
6075169689Skan  u = build2 (MODIFY_EXPR, void_type_node, addr, t);
6076169689Skan  gimplify_and_add (u, pre_p);
607790075Sobrien
6078169689Skan  t = build2 (PLUS_EXPR, TREE_TYPE (t), t, size_int (size));
6079169689Skan  t = build2 (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t);
6080169689Skan  gimplify_and_add (t, pre_p);
608190075Sobrien
6082132718Skan  if (lab_over)
6083169689Skan    {
6084169689Skan      t = build1 (LABEL_EXPR, void_type_node, lab_over);
6085169689Skan      append_to_statement_list (t, pre_p);
6086169689Skan    }
608790075Sobrien
6088169689Skan  if (STRICT_ALIGNMENT
6089169689Skan      && (TYPE_ALIGN (type)
6090169689Skan	  > (unsigned) BITS_PER_UNIT * (align < 4 ? 4 : align)))
609190075Sobrien    {
6092169689Skan      /* The value (of type complex double, for example) may not be
6093169689Skan	 aligned in memory in the saved registers, so copy via a
6094169689Skan	 temporary.  (This is the same code as used for SPARC.)  */
6095169689Skan      tree tmp = create_tmp_var (type, "va_arg_tmp");
6096169689Skan      tree dest_addr = build_fold_addr_expr (tmp);
6097169689Skan
6098169689Skan      tree copy = build_function_call_expr
6099169689Skan	(implicit_built_in_decls[BUILT_IN_MEMCPY],
6100169689Skan	 tree_cons (NULL_TREE, dest_addr,
6101169689Skan		    tree_cons (NULL_TREE, addr,
6102169689Skan			       tree_cons (NULL_TREE, size_int (rsize * 4),
6103169689Skan					  NULL_TREE))));
6104169689Skan
6105169689Skan      gimplify_and_add (copy, pre_p);
6106169689Skan      addr = dest_addr;
610790075Sobrien    }
610890075Sobrien
6109169689Skan  addr = fold_convert (ptrtype, addr);
6110169689Skan  return build_va_arg_indirect_ref (addr);
611190075Sobrien}
611290075Sobrien
611390075Sobrien/* Builtins.  */
611490075Sobrien
6115169689Skanstatic void
6116169689Skandef_builtin (int mask, const char *name, tree type, int code)
6117169689Skan{
6118169689Skan  if (mask & target_flags)
6119169689Skan    {
6120169689Skan      if (rs6000_builtin_decls[code])
6121169689Skan	abort ();
612290075Sobrien
6123169689Skan      rs6000_builtin_decls[code] =
6124169689Skan        lang_hooks.builtin_function (name, type, code, BUILT_IN_MD,
6125169689Skan				     NULL, NULL_TREE);
6126169689Skan    }
6127169689Skan}
6128169689Skan
612990075Sobrien/* Simple ternary operations: VECd = foo (VECa, VECb, VECc).  */
613090075Sobrien
613190075Sobrienstatic const struct builtin_description bdesc_3arg[] =
613290075Sobrien{
613390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmaddfp, "__builtin_altivec_vmaddfp", ALTIVEC_BUILTIN_VMADDFP },
613490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmhaddshs, "__builtin_altivec_vmhaddshs", ALTIVEC_BUILTIN_VMHADDSHS },
613590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmhraddshs, "__builtin_altivec_vmhraddshs", ALTIVEC_BUILTIN_VMHRADDSHS },
613690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmladduhm, "__builtin_altivec_vmladduhm", ALTIVEC_BUILTIN_VMLADDUHM},
613790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmsumubm, "__builtin_altivec_vmsumubm", ALTIVEC_BUILTIN_VMSUMUBM },
613890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmsummbm, "__builtin_altivec_vmsummbm", ALTIVEC_BUILTIN_VMSUMMBM },
613990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmsumuhm, "__builtin_altivec_vmsumuhm", ALTIVEC_BUILTIN_VMSUMUHM },
614090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmsumshm, "__builtin_altivec_vmsumshm", ALTIVEC_BUILTIN_VMSUMSHM },
614190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmsumuhs, "__builtin_altivec_vmsumuhs", ALTIVEC_BUILTIN_VMSUMUHS },
614290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmsumshs, "__builtin_altivec_vmsumshs", ALTIVEC_BUILTIN_VMSUMSHS },
6143169689Skan  { MASK_ALTIVEC, CODE_FOR_altivec_vnmsubfp, "__builtin_altivec_vnmsubfp", ALTIVEC_BUILTIN_VNMSUBFP },
6144169689Skan  { MASK_ALTIVEC, CODE_FOR_altivec_vperm_v4sf, "__builtin_altivec_vperm_4sf", ALTIVEC_BUILTIN_VPERM_4SF },
6145169689Skan  { MASK_ALTIVEC, CODE_FOR_altivec_vperm_v4si, "__builtin_altivec_vperm_4si", ALTIVEC_BUILTIN_VPERM_4SI },
6146169689Skan  { MASK_ALTIVEC, CODE_FOR_altivec_vperm_v8hi, "__builtin_altivec_vperm_8hi", ALTIVEC_BUILTIN_VPERM_8HI },
6147169689Skan  { MASK_ALTIVEC, CODE_FOR_altivec_vperm_v16qi, "__builtin_altivec_vperm_16qi", ALTIVEC_BUILTIN_VPERM_16QI },
6148169689Skan  { MASK_ALTIVEC, CODE_FOR_altivec_vsel_v4sf, "__builtin_altivec_vsel_4sf", ALTIVEC_BUILTIN_VSEL_4SF },
6149169689Skan  { MASK_ALTIVEC, CODE_FOR_altivec_vsel_v4si, "__builtin_altivec_vsel_4si", ALTIVEC_BUILTIN_VSEL_4SI },
6150169689Skan  { MASK_ALTIVEC, CODE_FOR_altivec_vsel_v8hi, "__builtin_altivec_vsel_8hi", ALTIVEC_BUILTIN_VSEL_8HI },
6151169689Skan  { MASK_ALTIVEC, CODE_FOR_altivec_vsel_v16qi, "__builtin_altivec_vsel_16qi", ALTIVEC_BUILTIN_VSEL_16QI },
6152169689Skan  { MASK_ALTIVEC, CODE_FOR_altivec_vsldoi_v16qi, "__builtin_altivec_vsldoi_16qi", ALTIVEC_BUILTIN_VSLDOI_16QI },
6153169689Skan  { MASK_ALTIVEC, CODE_FOR_altivec_vsldoi_v8hi, "__builtin_altivec_vsldoi_8hi", ALTIVEC_BUILTIN_VSLDOI_8HI },
6154169689Skan  { MASK_ALTIVEC, CODE_FOR_altivec_vsldoi_v4si, "__builtin_altivec_vsldoi_4si", ALTIVEC_BUILTIN_VSLDOI_4SI },
6155169689Skan  { MASK_ALTIVEC, CODE_FOR_altivec_vsldoi_v4sf, "__builtin_altivec_vsldoi_4sf", ALTIVEC_BUILTIN_VSLDOI_4SF },
6156169689Skan
6157169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_madd", ALTIVEC_BUILTIN_VEC_MADD },
6158169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_madds", ALTIVEC_BUILTIN_VEC_MADDS },
6159169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_mladd", ALTIVEC_BUILTIN_VEC_MLADD },
6160169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_mradds", ALTIVEC_BUILTIN_VEC_MRADDS },
6161169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_msum", ALTIVEC_BUILTIN_VEC_MSUM },
6162169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmsumshm", ALTIVEC_BUILTIN_VEC_VMSUMSHM },
6163169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmsumuhm", ALTIVEC_BUILTIN_VEC_VMSUMUHM },
6164169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmsummbm", ALTIVEC_BUILTIN_VEC_VMSUMMBM },
6165169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmsumubm", ALTIVEC_BUILTIN_VEC_VMSUMUBM },
6166169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_msums", ALTIVEC_BUILTIN_VEC_MSUMS },
6167169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmsumshs", ALTIVEC_BUILTIN_VEC_VMSUMSHS },
6168169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmsumuhs", ALTIVEC_BUILTIN_VEC_VMSUMUHS },
6169169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_nmsub", ALTIVEC_BUILTIN_VEC_NMSUB },
6170169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_perm", ALTIVEC_BUILTIN_VEC_PERM },
6171169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_sel", ALTIVEC_BUILTIN_VEC_SEL },
617290075Sobrien};
617390075Sobrien
617490075Sobrien/* DST operations: void foo (void *, const int, const char).  */
617590075Sobrien
617690075Sobrienstatic const struct builtin_description bdesc_dst[] =
617790075Sobrien{
617890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_dst, "__builtin_altivec_dst", ALTIVEC_BUILTIN_DST },
617990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_dstt, "__builtin_altivec_dstt", ALTIVEC_BUILTIN_DSTT },
618090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_dstst, "__builtin_altivec_dstst", ALTIVEC_BUILTIN_DSTST },
6181169689Skan  { MASK_ALTIVEC, CODE_FOR_altivec_dststt, "__builtin_altivec_dststt", ALTIVEC_BUILTIN_DSTSTT },
6182169689Skan
6183169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_dst", ALTIVEC_BUILTIN_VEC_DST },
6184169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_dstt", ALTIVEC_BUILTIN_VEC_DSTT },
6185169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_dstst", ALTIVEC_BUILTIN_VEC_DSTST },
6186169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_dststt", ALTIVEC_BUILTIN_VEC_DSTSTT }
618790075Sobrien};
618890075Sobrien
618990075Sobrien/* Simple binary operations: VECc = foo (VECa, VECb).  */
619090075Sobrien
6191117395Skanstatic struct builtin_description bdesc_2arg[] =
619290075Sobrien{
619390075Sobrien  { MASK_ALTIVEC, CODE_FOR_addv16qi3, "__builtin_altivec_vaddubm", ALTIVEC_BUILTIN_VADDUBM },
619490075Sobrien  { MASK_ALTIVEC, CODE_FOR_addv8hi3, "__builtin_altivec_vadduhm", ALTIVEC_BUILTIN_VADDUHM },
619590075Sobrien  { MASK_ALTIVEC, CODE_FOR_addv4si3, "__builtin_altivec_vadduwm", ALTIVEC_BUILTIN_VADDUWM },
619690075Sobrien  { MASK_ALTIVEC, CODE_FOR_addv4sf3, "__builtin_altivec_vaddfp", ALTIVEC_BUILTIN_VADDFP },
619790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vaddcuw, "__builtin_altivec_vaddcuw", ALTIVEC_BUILTIN_VADDCUW },
619890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vaddubs, "__builtin_altivec_vaddubs", ALTIVEC_BUILTIN_VADDUBS },
619990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vaddsbs, "__builtin_altivec_vaddsbs", ALTIVEC_BUILTIN_VADDSBS },
620090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vadduhs, "__builtin_altivec_vadduhs", ALTIVEC_BUILTIN_VADDUHS },
620190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vaddshs, "__builtin_altivec_vaddshs", ALTIVEC_BUILTIN_VADDSHS },
620290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vadduws, "__builtin_altivec_vadduws", ALTIVEC_BUILTIN_VADDUWS },
620390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vaddsws, "__builtin_altivec_vaddsws", ALTIVEC_BUILTIN_VADDSWS },
620490075Sobrien  { MASK_ALTIVEC, CODE_FOR_andv4si3, "__builtin_altivec_vand", ALTIVEC_BUILTIN_VAND },
6205169689Skan  { MASK_ALTIVEC, CODE_FOR_andcv4si3, "__builtin_altivec_vandc", ALTIVEC_BUILTIN_VANDC },
620690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vavgub, "__builtin_altivec_vavgub", ALTIVEC_BUILTIN_VAVGUB },
620790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vavgsb, "__builtin_altivec_vavgsb", ALTIVEC_BUILTIN_VAVGSB },
620890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vavguh, "__builtin_altivec_vavguh", ALTIVEC_BUILTIN_VAVGUH },
620990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vavgsh, "__builtin_altivec_vavgsh", ALTIVEC_BUILTIN_VAVGSH },
621090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vavguw, "__builtin_altivec_vavguw", ALTIVEC_BUILTIN_VAVGUW },
621190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vavgsw, "__builtin_altivec_vavgsw", ALTIVEC_BUILTIN_VAVGSW },
621290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcfux, "__builtin_altivec_vcfux", ALTIVEC_BUILTIN_VCFUX },
621390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcfsx, "__builtin_altivec_vcfsx", ALTIVEC_BUILTIN_VCFSX },
621490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpbfp, "__builtin_altivec_vcmpbfp", ALTIVEC_BUILTIN_VCMPBFP },
621590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpequb, "__builtin_altivec_vcmpequb", ALTIVEC_BUILTIN_VCMPEQUB },
621690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpequh, "__builtin_altivec_vcmpequh", ALTIVEC_BUILTIN_VCMPEQUH },
621790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpequw, "__builtin_altivec_vcmpequw", ALTIVEC_BUILTIN_VCMPEQUW },
621890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpeqfp, "__builtin_altivec_vcmpeqfp", ALTIVEC_BUILTIN_VCMPEQFP },
621990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpgefp, "__builtin_altivec_vcmpgefp", ALTIVEC_BUILTIN_VCMPGEFP },
622090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpgtub, "__builtin_altivec_vcmpgtub", ALTIVEC_BUILTIN_VCMPGTUB },
622190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpgtsb, "__builtin_altivec_vcmpgtsb", ALTIVEC_BUILTIN_VCMPGTSB },
622290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpgtuh, "__builtin_altivec_vcmpgtuh", ALTIVEC_BUILTIN_VCMPGTUH },
622390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpgtsh, "__builtin_altivec_vcmpgtsh", ALTIVEC_BUILTIN_VCMPGTSH },
622490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpgtuw, "__builtin_altivec_vcmpgtuw", ALTIVEC_BUILTIN_VCMPGTUW },
622590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpgtsw, "__builtin_altivec_vcmpgtsw", ALTIVEC_BUILTIN_VCMPGTSW },
622690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpgtfp, "__builtin_altivec_vcmpgtfp", ALTIVEC_BUILTIN_VCMPGTFP },
622790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vctsxs, "__builtin_altivec_vctsxs", ALTIVEC_BUILTIN_VCTSXS },
622890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vctuxs, "__builtin_altivec_vctuxs", ALTIVEC_BUILTIN_VCTUXS },
622990075Sobrien  { MASK_ALTIVEC, CODE_FOR_umaxv16qi3, "__builtin_altivec_vmaxub", ALTIVEC_BUILTIN_VMAXUB },
623090075Sobrien  { MASK_ALTIVEC, CODE_FOR_smaxv16qi3, "__builtin_altivec_vmaxsb", ALTIVEC_BUILTIN_VMAXSB },
6231117395Skan  { MASK_ALTIVEC, CODE_FOR_umaxv8hi3, "__builtin_altivec_vmaxuh", ALTIVEC_BUILTIN_VMAXUH },
6232117395Skan  { MASK_ALTIVEC, CODE_FOR_smaxv8hi3, "__builtin_altivec_vmaxsh", ALTIVEC_BUILTIN_VMAXSH },
6233117395Skan  { MASK_ALTIVEC, CODE_FOR_umaxv4si3, "__builtin_altivec_vmaxuw", ALTIVEC_BUILTIN_VMAXUW },
6234117395Skan  { MASK_ALTIVEC, CODE_FOR_smaxv4si3, "__builtin_altivec_vmaxsw", ALTIVEC_BUILTIN_VMAXSW },
6235117395Skan  { MASK_ALTIVEC, CODE_FOR_smaxv4sf3, "__builtin_altivec_vmaxfp", ALTIVEC_BUILTIN_VMAXFP },
623690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmrghb, "__builtin_altivec_vmrghb", ALTIVEC_BUILTIN_VMRGHB },
623790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmrghh, "__builtin_altivec_vmrghh", ALTIVEC_BUILTIN_VMRGHH },
623890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmrghw, "__builtin_altivec_vmrghw", ALTIVEC_BUILTIN_VMRGHW },
623990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmrglb, "__builtin_altivec_vmrglb", ALTIVEC_BUILTIN_VMRGLB },
624090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmrglh, "__builtin_altivec_vmrglh", ALTIVEC_BUILTIN_VMRGLH },
624190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmrglw, "__builtin_altivec_vmrglw", ALTIVEC_BUILTIN_VMRGLW },
624290075Sobrien  { MASK_ALTIVEC, CODE_FOR_uminv16qi3, "__builtin_altivec_vminub", ALTIVEC_BUILTIN_VMINUB },
624390075Sobrien  { MASK_ALTIVEC, CODE_FOR_sminv16qi3, "__builtin_altivec_vminsb", ALTIVEC_BUILTIN_VMINSB },
624490075Sobrien  { MASK_ALTIVEC, CODE_FOR_uminv8hi3, "__builtin_altivec_vminuh", ALTIVEC_BUILTIN_VMINUH },
624590075Sobrien  { MASK_ALTIVEC, CODE_FOR_sminv8hi3, "__builtin_altivec_vminsh", ALTIVEC_BUILTIN_VMINSH },
624690075Sobrien  { MASK_ALTIVEC, CODE_FOR_uminv4si3, "__builtin_altivec_vminuw", ALTIVEC_BUILTIN_VMINUW },
624790075Sobrien  { MASK_ALTIVEC, CODE_FOR_sminv4si3, "__builtin_altivec_vminsw", ALTIVEC_BUILTIN_VMINSW },
624890075Sobrien  { MASK_ALTIVEC, CODE_FOR_sminv4sf3, "__builtin_altivec_vminfp", ALTIVEC_BUILTIN_VMINFP },
624990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmuleub, "__builtin_altivec_vmuleub", ALTIVEC_BUILTIN_VMULEUB },
625090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmulesb, "__builtin_altivec_vmulesb", ALTIVEC_BUILTIN_VMULESB },
625190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmuleuh, "__builtin_altivec_vmuleuh", ALTIVEC_BUILTIN_VMULEUH },
625290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmulesh, "__builtin_altivec_vmulesh", ALTIVEC_BUILTIN_VMULESH },
625390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmuloub, "__builtin_altivec_vmuloub", ALTIVEC_BUILTIN_VMULOUB },
625490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmulosb, "__builtin_altivec_vmulosb", ALTIVEC_BUILTIN_VMULOSB },
625590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmulouh, "__builtin_altivec_vmulouh", ALTIVEC_BUILTIN_VMULOUH },
625690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmulosh, "__builtin_altivec_vmulosh", ALTIVEC_BUILTIN_VMULOSH },
6257169689Skan  { MASK_ALTIVEC, CODE_FOR_altivec_norv4si3, "__builtin_altivec_vnor", ALTIVEC_BUILTIN_VNOR },
625890075Sobrien  { MASK_ALTIVEC, CODE_FOR_iorv4si3, "__builtin_altivec_vor", ALTIVEC_BUILTIN_VOR },
625990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkuhum, "__builtin_altivec_vpkuhum", ALTIVEC_BUILTIN_VPKUHUM },
626090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkuwum, "__builtin_altivec_vpkuwum", ALTIVEC_BUILTIN_VPKUWUM },
626190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkpx, "__builtin_altivec_vpkpx", ALTIVEC_BUILTIN_VPKPX },
626290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkshss, "__builtin_altivec_vpkshss", ALTIVEC_BUILTIN_VPKSHSS },
626390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkswss, "__builtin_altivec_vpkswss", ALTIVEC_BUILTIN_VPKSWSS },
626490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkuhus, "__builtin_altivec_vpkuhus", ALTIVEC_BUILTIN_VPKUHUS },
626590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkshus, "__builtin_altivec_vpkshus", ALTIVEC_BUILTIN_VPKSHUS },
626690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkuwus, "__builtin_altivec_vpkuwus", ALTIVEC_BUILTIN_VPKUWUS },
626790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkswus, "__builtin_altivec_vpkswus", ALTIVEC_BUILTIN_VPKSWUS },
626890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vrlb, "__builtin_altivec_vrlb", ALTIVEC_BUILTIN_VRLB },
626990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vrlh, "__builtin_altivec_vrlh", ALTIVEC_BUILTIN_VRLH },
627090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vrlw, "__builtin_altivec_vrlw", ALTIVEC_BUILTIN_VRLW },
627190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vslb, "__builtin_altivec_vslb", ALTIVEC_BUILTIN_VSLB },
627290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vslh, "__builtin_altivec_vslh", ALTIVEC_BUILTIN_VSLH },
627390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vslw, "__builtin_altivec_vslw", ALTIVEC_BUILTIN_VSLW },
627490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsl, "__builtin_altivec_vsl", ALTIVEC_BUILTIN_VSL },
627590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vslo, "__builtin_altivec_vslo", ALTIVEC_BUILTIN_VSLO },
627690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vspltb, "__builtin_altivec_vspltb", ALTIVEC_BUILTIN_VSPLTB },
627790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsplth, "__builtin_altivec_vsplth", ALTIVEC_BUILTIN_VSPLTH },
627890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vspltw, "__builtin_altivec_vspltw", ALTIVEC_BUILTIN_VSPLTW },
6279169689Skan  { MASK_ALTIVEC, CODE_FOR_lshrv16qi3, "__builtin_altivec_vsrb", ALTIVEC_BUILTIN_VSRB },
6280169689Skan  { MASK_ALTIVEC, CODE_FOR_lshrv8hi3, "__builtin_altivec_vsrh", ALTIVEC_BUILTIN_VSRH },
6281169689Skan  { MASK_ALTIVEC, CODE_FOR_lshrv4si3, "__builtin_altivec_vsrw", ALTIVEC_BUILTIN_VSRW },
6282169689Skan  { MASK_ALTIVEC, CODE_FOR_ashrv16qi3, "__builtin_altivec_vsrab", ALTIVEC_BUILTIN_VSRAB },
6283169689Skan  { MASK_ALTIVEC, CODE_FOR_ashrv8hi3, "__builtin_altivec_vsrah", ALTIVEC_BUILTIN_VSRAH },
6284169689Skan  { MASK_ALTIVEC, CODE_FOR_ashrv4si3, "__builtin_altivec_vsraw", ALTIVEC_BUILTIN_VSRAW },
628590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsr, "__builtin_altivec_vsr", ALTIVEC_BUILTIN_VSR },
628690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsro, "__builtin_altivec_vsro", ALTIVEC_BUILTIN_VSRO },
628790075Sobrien  { MASK_ALTIVEC, CODE_FOR_subv16qi3, "__builtin_altivec_vsububm", ALTIVEC_BUILTIN_VSUBUBM },
628890075Sobrien  { MASK_ALTIVEC, CODE_FOR_subv8hi3, "__builtin_altivec_vsubuhm", ALTIVEC_BUILTIN_VSUBUHM },
628990075Sobrien  { MASK_ALTIVEC, CODE_FOR_subv4si3, "__builtin_altivec_vsubuwm", ALTIVEC_BUILTIN_VSUBUWM },
629090075Sobrien  { MASK_ALTIVEC, CODE_FOR_subv4sf3, "__builtin_altivec_vsubfp", ALTIVEC_BUILTIN_VSUBFP },
629190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsubcuw, "__builtin_altivec_vsubcuw", ALTIVEC_BUILTIN_VSUBCUW },
629290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsububs, "__builtin_altivec_vsububs", ALTIVEC_BUILTIN_VSUBUBS },
629390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsubsbs, "__builtin_altivec_vsubsbs", ALTIVEC_BUILTIN_VSUBSBS },
629490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsubuhs, "__builtin_altivec_vsubuhs", ALTIVEC_BUILTIN_VSUBUHS },
629590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsubshs, "__builtin_altivec_vsubshs", ALTIVEC_BUILTIN_VSUBSHS },
629690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsubuws, "__builtin_altivec_vsubuws", ALTIVEC_BUILTIN_VSUBUWS },
629790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsubsws, "__builtin_altivec_vsubsws", ALTIVEC_BUILTIN_VSUBSWS },
629890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsum4ubs, "__builtin_altivec_vsum4ubs", ALTIVEC_BUILTIN_VSUM4UBS },
629990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsum4sbs, "__builtin_altivec_vsum4sbs", ALTIVEC_BUILTIN_VSUM4SBS },
630090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsum4shs, "__builtin_altivec_vsum4shs", ALTIVEC_BUILTIN_VSUM4SHS },
630190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsum2sws, "__builtin_altivec_vsum2sws", ALTIVEC_BUILTIN_VSUM2SWS },
630290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsumsws, "__builtin_altivec_vsumsws", ALTIVEC_BUILTIN_VSUMSWS },
630390075Sobrien  { MASK_ALTIVEC, CODE_FOR_xorv4si3, "__builtin_altivec_vxor", ALTIVEC_BUILTIN_VXOR },
6304117395Skan
6305169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_add", ALTIVEC_BUILTIN_VEC_ADD },
6306169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vaddfp", ALTIVEC_BUILTIN_VEC_VADDFP },
6307169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vadduwm", ALTIVEC_BUILTIN_VEC_VADDUWM },
6308169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vadduhm", ALTIVEC_BUILTIN_VEC_VADDUHM },
6309169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vaddubm", ALTIVEC_BUILTIN_VEC_VADDUBM },
6310169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_addc", ALTIVEC_BUILTIN_VEC_ADDC },
6311169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_adds", ALTIVEC_BUILTIN_VEC_ADDS },
6312169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vaddsws", ALTIVEC_BUILTIN_VEC_VADDSWS },
6313169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vadduws", ALTIVEC_BUILTIN_VEC_VADDUWS },
6314169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vaddshs", ALTIVEC_BUILTIN_VEC_VADDSHS },
6315169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vadduhs", ALTIVEC_BUILTIN_VEC_VADDUHS },
6316169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vaddsbs", ALTIVEC_BUILTIN_VEC_VADDSBS },
6317169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vaddubs", ALTIVEC_BUILTIN_VEC_VADDUBS },
6318169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_and", ALTIVEC_BUILTIN_VEC_AND },
6319169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_andc", ALTIVEC_BUILTIN_VEC_ANDC },
6320169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_avg", ALTIVEC_BUILTIN_VEC_AVG },
6321169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vavgsw", ALTIVEC_BUILTIN_VEC_VAVGSW },
6322169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vavguw", ALTIVEC_BUILTIN_VEC_VAVGUW },
6323169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vavgsh", ALTIVEC_BUILTIN_VEC_VAVGSH },
6324169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vavguh", ALTIVEC_BUILTIN_VEC_VAVGUH },
6325169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vavgsb", ALTIVEC_BUILTIN_VEC_VAVGSB },
6326169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vavgub", ALTIVEC_BUILTIN_VEC_VAVGUB },
6327169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_cmpb", ALTIVEC_BUILTIN_VEC_CMPB },
6328169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_cmpeq", ALTIVEC_BUILTIN_VEC_CMPEQ },
6329169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vcmpeqfp", ALTIVEC_BUILTIN_VEC_VCMPEQFP },
6330169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vcmpequw", ALTIVEC_BUILTIN_VEC_VCMPEQUW },
6331169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vcmpequh", ALTIVEC_BUILTIN_VEC_VCMPEQUH },
6332169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vcmpequb", ALTIVEC_BUILTIN_VEC_VCMPEQUB },
6333169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_cmpge", ALTIVEC_BUILTIN_VEC_CMPGE },
6334169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_cmpgt", ALTIVEC_BUILTIN_VEC_CMPGT },
6335169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vcmpgtfp", ALTIVEC_BUILTIN_VEC_VCMPGTFP },
6336169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vcmpgtsw", ALTIVEC_BUILTIN_VEC_VCMPGTSW },
6337169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vcmpgtuw", ALTIVEC_BUILTIN_VEC_VCMPGTUW },
6338169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vcmpgtsh", ALTIVEC_BUILTIN_VEC_VCMPGTSH },
6339169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vcmpgtuh", ALTIVEC_BUILTIN_VEC_VCMPGTUH },
6340169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vcmpgtsb", ALTIVEC_BUILTIN_VEC_VCMPGTSB },
6341169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vcmpgtub", ALTIVEC_BUILTIN_VEC_VCMPGTUB },
6342169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_cmple", ALTIVEC_BUILTIN_VEC_CMPLE },
6343169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_cmplt", ALTIVEC_BUILTIN_VEC_CMPLT },
6344169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_max", ALTIVEC_BUILTIN_VEC_MAX },
6345169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmaxfp", ALTIVEC_BUILTIN_VEC_VMAXFP },
6346169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmaxsw", ALTIVEC_BUILTIN_VEC_VMAXSW },
6347169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmaxuw", ALTIVEC_BUILTIN_VEC_VMAXUW },
6348169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmaxsh", ALTIVEC_BUILTIN_VEC_VMAXSH },
6349169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmaxuh", ALTIVEC_BUILTIN_VEC_VMAXUH },
6350169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmaxsb", ALTIVEC_BUILTIN_VEC_VMAXSB },
6351169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmaxub", ALTIVEC_BUILTIN_VEC_VMAXUB },
6352169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_mergeh", ALTIVEC_BUILTIN_VEC_MERGEH },
6353169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmrghw", ALTIVEC_BUILTIN_VEC_VMRGHW },
6354169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmrghh", ALTIVEC_BUILTIN_VEC_VMRGHH },
6355169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmrghb", ALTIVEC_BUILTIN_VEC_VMRGHB },
6356169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_mergel", ALTIVEC_BUILTIN_VEC_MERGEL },
6357169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmrglw", ALTIVEC_BUILTIN_VEC_VMRGLW },
6358169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmrglh", ALTIVEC_BUILTIN_VEC_VMRGLH },
6359169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmrglb", ALTIVEC_BUILTIN_VEC_VMRGLB },
6360169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_min", ALTIVEC_BUILTIN_VEC_MIN },
6361169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vminfp", ALTIVEC_BUILTIN_VEC_VMINFP },
6362169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vminsw", ALTIVEC_BUILTIN_VEC_VMINSW },
6363169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vminuw", ALTIVEC_BUILTIN_VEC_VMINUW },
6364169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vminsh", ALTIVEC_BUILTIN_VEC_VMINSH },
6365169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vminuh", ALTIVEC_BUILTIN_VEC_VMINUH },
6366169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vminsb", ALTIVEC_BUILTIN_VEC_VMINSB },
6367169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vminub", ALTIVEC_BUILTIN_VEC_VMINUB },
6368169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_mule", ALTIVEC_BUILTIN_VEC_MULE },
6369169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmuleub", ALTIVEC_BUILTIN_VEC_VMULEUB },
6370169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmulesb", ALTIVEC_BUILTIN_VEC_VMULESB },
6371169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmuleuh", ALTIVEC_BUILTIN_VEC_VMULEUH },
6372169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmulesh", ALTIVEC_BUILTIN_VEC_VMULESH },
6373169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_mulo", ALTIVEC_BUILTIN_VEC_MULO },
6374169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmulosh", ALTIVEC_BUILTIN_VEC_VMULOSH },
6375169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmulouh", ALTIVEC_BUILTIN_VEC_VMULOUH },
6376169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmulosb", ALTIVEC_BUILTIN_VEC_VMULOSB },
6377169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmuloub", ALTIVEC_BUILTIN_VEC_VMULOUB },
6378169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_nor", ALTIVEC_BUILTIN_VEC_NOR },
6379169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_or", ALTIVEC_BUILTIN_VEC_OR },
6380169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_pack", ALTIVEC_BUILTIN_VEC_PACK },
6381169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vpkuwum", ALTIVEC_BUILTIN_VEC_VPKUWUM },
6382169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vpkuhum", ALTIVEC_BUILTIN_VEC_VPKUHUM },
6383169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_packpx", ALTIVEC_BUILTIN_VEC_PACKPX },
6384169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_packs", ALTIVEC_BUILTIN_VEC_PACKS },
6385169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vpkswss", ALTIVEC_BUILTIN_VEC_VPKSWSS },
6386169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vpkuwus", ALTIVEC_BUILTIN_VEC_VPKUWUS },
6387169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vpkshss", ALTIVEC_BUILTIN_VEC_VPKSHSS },
6388169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vpkuhus", ALTIVEC_BUILTIN_VEC_VPKUHUS },
6389169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_packsu", ALTIVEC_BUILTIN_VEC_PACKSU },
6390169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vpkswus", ALTIVEC_BUILTIN_VEC_VPKSWUS },
6391169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vpkshus", ALTIVEC_BUILTIN_VEC_VPKSHUS },
6392169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_rl", ALTIVEC_BUILTIN_VEC_RL },
6393169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vrlw", ALTIVEC_BUILTIN_VEC_VRLW },
6394169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vrlh", ALTIVEC_BUILTIN_VEC_VRLH },
6395169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vrlb", ALTIVEC_BUILTIN_VEC_VRLB },
6396169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_sl", ALTIVEC_BUILTIN_VEC_SL },
6397169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vslw", ALTIVEC_BUILTIN_VEC_VSLW },
6398169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vslh", ALTIVEC_BUILTIN_VEC_VSLH },
6399169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vslb", ALTIVEC_BUILTIN_VEC_VSLB },
6400169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_sll", ALTIVEC_BUILTIN_VEC_SLL },
6401169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_slo", ALTIVEC_BUILTIN_VEC_SLO },
6402169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_sr", ALTIVEC_BUILTIN_VEC_SR },
6403169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsrw", ALTIVEC_BUILTIN_VEC_VSRW },
6404169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsrh", ALTIVEC_BUILTIN_VEC_VSRH },
6405169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsrb", ALTIVEC_BUILTIN_VEC_VSRB },
6406169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_sra", ALTIVEC_BUILTIN_VEC_SRA },
6407169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsraw", ALTIVEC_BUILTIN_VEC_VSRAW },
6408169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsrah", ALTIVEC_BUILTIN_VEC_VSRAH },
6409169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsrab", ALTIVEC_BUILTIN_VEC_VSRAB },
6410169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_srl", ALTIVEC_BUILTIN_VEC_SRL },
6411169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_sro", ALTIVEC_BUILTIN_VEC_SRO },
6412169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_sub", ALTIVEC_BUILTIN_VEC_SUB },
6413169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsubfp", ALTIVEC_BUILTIN_VEC_VSUBFP },
6414169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsubuwm", ALTIVEC_BUILTIN_VEC_VSUBUWM },
6415169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsubuhm", ALTIVEC_BUILTIN_VEC_VSUBUHM },
6416169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsububm", ALTIVEC_BUILTIN_VEC_VSUBUBM },
6417169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_subc", ALTIVEC_BUILTIN_VEC_SUBC },
6418169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_subs", ALTIVEC_BUILTIN_VEC_SUBS },
6419169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsubsws", ALTIVEC_BUILTIN_VEC_VSUBSWS },
6420169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsubuws", ALTIVEC_BUILTIN_VEC_VSUBUWS },
6421169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsubshs", ALTIVEC_BUILTIN_VEC_VSUBSHS },
6422169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsubuhs", ALTIVEC_BUILTIN_VEC_VSUBUHS },
6423169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsubsbs", ALTIVEC_BUILTIN_VEC_VSUBSBS },
6424169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsububs", ALTIVEC_BUILTIN_VEC_VSUBUBS },
6425169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_sum4s", ALTIVEC_BUILTIN_VEC_SUM4S },
6426169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsum4shs", ALTIVEC_BUILTIN_VEC_VSUM4SHS },
6427169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsum4sbs", ALTIVEC_BUILTIN_VEC_VSUM4SBS },
6428169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsum4ubs", ALTIVEC_BUILTIN_VEC_VSUM4UBS },
6429169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_sum2s", ALTIVEC_BUILTIN_VEC_SUM2S },
6430169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_sums", ALTIVEC_BUILTIN_VEC_SUMS },
6431169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_xor", ALTIVEC_BUILTIN_VEC_XOR },
6432169689Skan
6433117395Skan  /* Place holder, leave as first spe builtin.  */
6434117395Skan  { 0, CODE_FOR_spe_evaddw, "__builtin_spe_evaddw", SPE_BUILTIN_EVADDW },
6435117395Skan  { 0, CODE_FOR_spe_evand, "__builtin_spe_evand", SPE_BUILTIN_EVAND },
6436117395Skan  { 0, CODE_FOR_spe_evandc, "__builtin_spe_evandc", SPE_BUILTIN_EVANDC },
6437117395Skan  { 0, CODE_FOR_spe_evdivws, "__builtin_spe_evdivws", SPE_BUILTIN_EVDIVWS },
6438117395Skan  { 0, CODE_FOR_spe_evdivwu, "__builtin_spe_evdivwu", SPE_BUILTIN_EVDIVWU },
6439117395Skan  { 0, CODE_FOR_spe_eveqv, "__builtin_spe_eveqv", SPE_BUILTIN_EVEQV },
6440117395Skan  { 0, CODE_FOR_spe_evfsadd, "__builtin_spe_evfsadd", SPE_BUILTIN_EVFSADD },
6441117395Skan  { 0, CODE_FOR_spe_evfsdiv, "__builtin_spe_evfsdiv", SPE_BUILTIN_EVFSDIV },
6442117395Skan  { 0, CODE_FOR_spe_evfsmul, "__builtin_spe_evfsmul", SPE_BUILTIN_EVFSMUL },
6443117395Skan  { 0, CODE_FOR_spe_evfssub, "__builtin_spe_evfssub", SPE_BUILTIN_EVFSSUB },
6444117395Skan  { 0, CODE_FOR_spe_evmergehi, "__builtin_spe_evmergehi", SPE_BUILTIN_EVMERGEHI },
6445117395Skan  { 0, CODE_FOR_spe_evmergehilo, "__builtin_spe_evmergehilo", SPE_BUILTIN_EVMERGEHILO },
6446117395Skan  { 0, CODE_FOR_spe_evmergelo, "__builtin_spe_evmergelo", SPE_BUILTIN_EVMERGELO },
6447117395Skan  { 0, CODE_FOR_spe_evmergelohi, "__builtin_spe_evmergelohi", SPE_BUILTIN_EVMERGELOHI },
6448117395Skan  { 0, CODE_FOR_spe_evmhegsmfaa, "__builtin_spe_evmhegsmfaa", SPE_BUILTIN_EVMHEGSMFAA },
6449117395Skan  { 0, CODE_FOR_spe_evmhegsmfan, "__builtin_spe_evmhegsmfan", SPE_BUILTIN_EVMHEGSMFAN },
6450117395Skan  { 0, CODE_FOR_spe_evmhegsmiaa, "__builtin_spe_evmhegsmiaa", SPE_BUILTIN_EVMHEGSMIAA },
6451117395Skan  { 0, CODE_FOR_spe_evmhegsmian, "__builtin_spe_evmhegsmian", SPE_BUILTIN_EVMHEGSMIAN },
6452117395Skan  { 0, CODE_FOR_spe_evmhegumiaa, "__builtin_spe_evmhegumiaa", SPE_BUILTIN_EVMHEGUMIAA },
6453117395Skan  { 0, CODE_FOR_spe_evmhegumian, "__builtin_spe_evmhegumian", SPE_BUILTIN_EVMHEGUMIAN },
6454117395Skan  { 0, CODE_FOR_spe_evmhesmf, "__builtin_spe_evmhesmf", SPE_BUILTIN_EVMHESMF },
6455117395Skan  { 0, CODE_FOR_spe_evmhesmfa, "__builtin_spe_evmhesmfa", SPE_BUILTIN_EVMHESMFA },
6456117395Skan  { 0, CODE_FOR_spe_evmhesmfaaw, "__builtin_spe_evmhesmfaaw", SPE_BUILTIN_EVMHESMFAAW },
6457117395Skan  { 0, CODE_FOR_spe_evmhesmfanw, "__builtin_spe_evmhesmfanw", SPE_BUILTIN_EVMHESMFANW },
6458117395Skan  { 0, CODE_FOR_spe_evmhesmi, "__builtin_spe_evmhesmi", SPE_BUILTIN_EVMHESMI },
6459117395Skan  { 0, CODE_FOR_spe_evmhesmia, "__builtin_spe_evmhesmia", SPE_BUILTIN_EVMHESMIA },
6460117395Skan  { 0, CODE_FOR_spe_evmhesmiaaw, "__builtin_spe_evmhesmiaaw", SPE_BUILTIN_EVMHESMIAAW },
6461117395Skan  { 0, CODE_FOR_spe_evmhesmianw, "__builtin_spe_evmhesmianw", SPE_BUILTIN_EVMHESMIANW },
6462117395Skan  { 0, CODE_FOR_spe_evmhessf, "__builtin_spe_evmhessf", SPE_BUILTIN_EVMHESSF },
6463117395Skan  { 0, CODE_FOR_spe_evmhessfa, "__builtin_spe_evmhessfa", SPE_BUILTIN_EVMHESSFA },
6464117395Skan  { 0, CODE_FOR_spe_evmhessfaaw, "__builtin_spe_evmhessfaaw", SPE_BUILTIN_EVMHESSFAAW },
6465117395Skan  { 0, CODE_FOR_spe_evmhessfanw, "__builtin_spe_evmhessfanw", SPE_BUILTIN_EVMHESSFANW },
6466117395Skan  { 0, CODE_FOR_spe_evmhessiaaw, "__builtin_spe_evmhessiaaw", SPE_BUILTIN_EVMHESSIAAW },
6467117395Skan  { 0, CODE_FOR_spe_evmhessianw, "__builtin_spe_evmhessianw", SPE_BUILTIN_EVMHESSIANW },
6468117395Skan  { 0, CODE_FOR_spe_evmheumi, "__builtin_spe_evmheumi", SPE_BUILTIN_EVMHEUMI },
6469117395Skan  { 0, CODE_FOR_spe_evmheumia, "__builtin_spe_evmheumia", SPE_BUILTIN_EVMHEUMIA },
6470117395Skan  { 0, CODE_FOR_spe_evmheumiaaw, "__builtin_spe_evmheumiaaw", SPE_BUILTIN_EVMHEUMIAAW },
6471117395Skan  { 0, CODE_FOR_spe_evmheumianw, "__builtin_spe_evmheumianw", SPE_BUILTIN_EVMHEUMIANW },
6472117395Skan  { 0, CODE_FOR_spe_evmheusiaaw, "__builtin_spe_evmheusiaaw", SPE_BUILTIN_EVMHEUSIAAW },
6473117395Skan  { 0, CODE_FOR_spe_evmheusianw, "__builtin_spe_evmheusianw", SPE_BUILTIN_EVMHEUSIANW },
6474117395Skan  { 0, CODE_FOR_spe_evmhogsmfaa, "__builtin_spe_evmhogsmfaa", SPE_BUILTIN_EVMHOGSMFAA },
6475117395Skan  { 0, CODE_FOR_spe_evmhogsmfan, "__builtin_spe_evmhogsmfan", SPE_BUILTIN_EVMHOGSMFAN },
6476117395Skan  { 0, CODE_FOR_spe_evmhogsmiaa, "__builtin_spe_evmhogsmiaa", SPE_BUILTIN_EVMHOGSMIAA },
6477117395Skan  { 0, CODE_FOR_spe_evmhogsmian, "__builtin_spe_evmhogsmian", SPE_BUILTIN_EVMHOGSMIAN },
6478117395Skan  { 0, CODE_FOR_spe_evmhogumiaa, "__builtin_spe_evmhogumiaa", SPE_BUILTIN_EVMHOGUMIAA },
6479117395Skan  { 0, CODE_FOR_spe_evmhogumian, "__builtin_spe_evmhogumian", SPE_BUILTIN_EVMHOGUMIAN },
6480117395Skan  { 0, CODE_FOR_spe_evmhosmf, "__builtin_spe_evmhosmf", SPE_BUILTIN_EVMHOSMF },
6481117395Skan  { 0, CODE_FOR_spe_evmhosmfa, "__builtin_spe_evmhosmfa", SPE_BUILTIN_EVMHOSMFA },
6482117395Skan  { 0, CODE_FOR_spe_evmhosmfaaw, "__builtin_spe_evmhosmfaaw", SPE_BUILTIN_EVMHOSMFAAW },
6483117395Skan  { 0, CODE_FOR_spe_evmhosmfanw, "__builtin_spe_evmhosmfanw", SPE_BUILTIN_EVMHOSMFANW },
6484117395Skan  { 0, CODE_FOR_spe_evmhosmi, "__builtin_spe_evmhosmi", SPE_BUILTIN_EVMHOSMI },
6485117395Skan  { 0, CODE_FOR_spe_evmhosmia, "__builtin_spe_evmhosmia", SPE_BUILTIN_EVMHOSMIA },
6486117395Skan  { 0, CODE_FOR_spe_evmhosmiaaw, "__builtin_spe_evmhosmiaaw", SPE_BUILTIN_EVMHOSMIAAW },
6487117395Skan  { 0, CODE_FOR_spe_evmhosmianw, "__builtin_spe_evmhosmianw", SPE_BUILTIN_EVMHOSMIANW },
6488117395Skan  { 0, CODE_FOR_spe_evmhossf, "__builtin_spe_evmhossf", SPE_BUILTIN_EVMHOSSF },
6489117395Skan  { 0, CODE_FOR_spe_evmhossfa, "__builtin_spe_evmhossfa", SPE_BUILTIN_EVMHOSSFA },
6490117395Skan  { 0, CODE_FOR_spe_evmhossfaaw, "__builtin_spe_evmhossfaaw", SPE_BUILTIN_EVMHOSSFAAW },
6491117395Skan  { 0, CODE_FOR_spe_evmhossfanw, "__builtin_spe_evmhossfanw", SPE_BUILTIN_EVMHOSSFANW },
6492117395Skan  { 0, CODE_FOR_spe_evmhossiaaw, "__builtin_spe_evmhossiaaw", SPE_BUILTIN_EVMHOSSIAAW },
6493117395Skan  { 0, CODE_FOR_spe_evmhossianw, "__builtin_spe_evmhossianw", SPE_BUILTIN_EVMHOSSIANW },
6494117395Skan  { 0, CODE_FOR_spe_evmhoumi, "__builtin_spe_evmhoumi", SPE_BUILTIN_EVMHOUMI },
6495117395Skan  { 0, CODE_FOR_spe_evmhoumia, "__builtin_spe_evmhoumia", SPE_BUILTIN_EVMHOUMIA },
6496117395Skan  { 0, CODE_FOR_spe_evmhoumiaaw, "__builtin_spe_evmhoumiaaw", SPE_BUILTIN_EVMHOUMIAAW },
6497117395Skan  { 0, CODE_FOR_spe_evmhoumianw, "__builtin_spe_evmhoumianw", SPE_BUILTIN_EVMHOUMIANW },
6498117395Skan  { 0, CODE_FOR_spe_evmhousiaaw, "__builtin_spe_evmhousiaaw", SPE_BUILTIN_EVMHOUSIAAW },
6499117395Skan  { 0, CODE_FOR_spe_evmhousianw, "__builtin_spe_evmhousianw", SPE_BUILTIN_EVMHOUSIANW },
6500117395Skan  { 0, CODE_FOR_spe_evmwhsmf, "__builtin_spe_evmwhsmf", SPE_BUILTIN_EVMWHSMF },
6501117395Skan  { 0, CODE_FOR_spe_evmwhsmfa, "__builtin_spe_evmwhsmfa", SPE_BUILTIN_EVMWHSMFA },
6502117395Skan  { 0, CODE_FOR_spe_evmwhsmi, "__builtin_spe_evmwhsmi", SPE_BUILTIN_EVMWHSMI },
6503117395Skan  { 0, CODE_FOR_spe_evmwhsmia, "__builtin_spe_evmwhsmia", SPE_BUILTIN_EVMWHSMIA },
6504117395Skan  { 0, CODE_FOR_spe_evmwhssf, "__builtin_spe_evmwhssf", SPE_BUILTIN_EVMWHSSF },
6505117395Skan  { 0, CODE_FOR_spe_evmwhssfa, "__builtin_spe_evmwhssfa", SPE_BUILTIN_EVMWHSSFA },
6506117395Skan  { 0, CODE_FOR_spe_evmwhumi, "__builtin_spe_evmwhumi", SPE_BUILTIN_EVMWHUMI },
6507117395Skan  { 0, CODE_FOR_spe_evmwhumia, "__builtin_spe_evmwhumia", SPE_BUILTIN_EVMWHUMIA },
6508117395Skan  { 0, CODE_FOR_spe_evmwlsmiaaw, "__builtin_spe_evmwlsmiaaw", SPE_BUILTIN_EVMWLSMIAAW },
6509117395Skan  { 0, CODE_FOR_spe_evmwlsmianw, "__builtin_spe_evmwlsmianw", SPE_BUILTIN_EVMWLSMIANW },
6510117395Skan  { 0, CODE_FOR_spe_evmwlssiaaw, "__builtin_spe_evmwlssiaaw", SPE_BUILTIN_EVMWLSSIAAW },
6511117395Skan  { 0, CODE_FOR_spe_evmwlssianw, "__builtin_spe_evmwlssianw", SPE_BUILTIN_EVMWLSSIANW },
6512117395Skan  { 0, CODE_FOR_spe_evmwlumi, "__builtin_spe_evmwlumi", SPE_BUILTIN_EVMWLUMI },
6513117395Skan  { 0, CODE_FOR_spe_evmwlumia, "__builtin_spe_evmwlumia", SPE_BUILTIN_EVMWLUMIA },
6514117395Skan  { 0, CODE_FOR_spe_evmwlumiaaw, "__builtin_spe_evmwlumiaaw", SPE_BUILTIN_EVMWLUMIAAW },
6515117395Skan  { 0, CODE_FOR_spe_evmwlumianw, "__builtin_spe_evmwlumianw", SPE_BUILTIN_EVMWLUMIANW },
6516117395Skan  { 0, CODE_FOR_spe_evmwlusiaaw, "__builtin_spe_evmwlusiaaw", SPE_BUILTIN_EVMWLUSIAAW },
6517117395Skan  { 0, CODE_FOR_spe_evmwlusianw, "__builtin_spe_evmwlusianw", SPE_BUILTIN_EVMWLUSIANW },
6518117395Skan  { 0, CODE_FOR_spe_evmwsmf, "__builtin_spe_evmwsmf", SPE_BUILTIN_EVMWSMF },
6519117395Skan  { 0, CODE_FOR_spe_evmwsmfa, "__builtin_spe_evmwsmfa", SPE_BUILTIN_EVMWSMFA },
6520117395Skan  { 0, CODE_FOR_spe_evmwsmfaa, "__builtin_spe_evmwsmfaa", SPE_BUILTIN_EVMWSMFAA },
6521117395Skan  { 0, CODE_FOR_spe_evmwsmfan, "__builtin_spe_evmwsmfan", SPE_BUILTIN_EVMWSMFAN },
6522117395Skan  { 0, CODE_FOR_spe_evmwsmi, "__builtin_spe_evmwsmi", SPE_BUILTIN_EVMWSMI },
6523117395Skan  { 0, CODE_FOR_spe_evmwsmia, "__builtin_spe_evmwsmia", SPE_BUILTIN_EVMWSMIA },
6524117395Skan  { 0, CODE_FOR_spe_evmwsmiaa, "__builtin_spe_evmwsmiaa", SPE_BUILTIN_EVMWSMIAA },
6525117395Skan  { 0, CODE_FOR_spe_evmwsmian, "__builtin_spe_evmwsmian", SPE_BUILTIN_EVMWSMIAN },
6526117395Skan  { 0, CODE_FOR_spe_evmwssf, "__builtin_spe_evmwssf", SPE_BUILTIN_EVMWSSF },
6527117395Skan  { 0, CODE_FOR_spe_evmwssfa, "__builtin_spe_evmwssfa", SPE_BUILTIN_EVMWSSFA },
6528117395Skan  { 0, CODE_FOR_spe_evmwssfaa, "__builtin_spe_evmwssfaa", SPE_BUILTIN_EVMWSSFAA },
6529117395Skan  { 0, CODE_FOR_spe_evmwssfan, "__builtin_spe_evmwssfan", SPE_BUILTIN_EVMWSSFAN },
6530117395Skan  { 0, CODE_FOR_spe_evmwumi, "__builtin_spe_evmwumi", SPE_BUILTIN_EVMWUMI },
6531117395Skan  { 0, CODE_FOR_spe_evmwumia, "__builtin_spe_evmwumia", SPE_BUILTIN_EVMWUMIA },
6532117395Skan  { 0, CODE_FOR_spe_evmwumiaa, "__builtin_spe_evmwumiaa", SPE_BUILTIN_EVMWUMIAA },
6533117395Skan  { 0, CODE_FOR_spe_evmwumian, "__builtin_spe_evmwumian", SPE_BUILTIN_EVMWUMIAN },
6534117395Skan  { 0, CODE_FOR_spe_evnand, "__builtin_spe_evnand", SPE_BUILTIN_EVNAND },
6535117395Skan  { 0, CODE_FOR_spe_evnor, "__builtin_spe_evnor", SPE_BUILTIN_EVNOR },
6536117395Skan  { 0, CODE_FOR_spe_evor, "__builtin_spe_evor", SPE_BUILTIN_EVOR },
6537117395Skan  { 0, CODE_FOR_spe_evorc, "__builtin_spe_evorc", SPE_BUILTIN_EVORC },
6538117395Skan  { 0, CODE_FOR_spe_evrlw, "__builtin_spe_evrlw", SPE_BUILTIN_EVRLW },
6539117395Skan  { 0, CODE_FOR_spe_evslw, "__builtin_spe_evslw", SPE_BUILTIN_EVSLW },
6540117395Skan  { 0, CODE_FOR_spe_evsrws, "__builtin_spe_evsrws", SPE_BUILTIN_EVSRWS },
6541117395Skan  { 0, CODE_FOR_spe_evsrwu, "__builtin_spe_evsrwu", SPE_BUILTIN_EVSRWU },
6542117395Skan  { 0, CODE_FOR_spe_evsubfw, "__builtin_spe_evsubfw", SPE_BUILTIN_EVSUBFW },
6543117395Skan
6544117395Skan  /* SPE binary operations expecting a 5-bit unsigned literal.  */
6545117395Skan  { 0, CODE_FOR_spe_evaddiw, "__builtin_spe_evaddiw", SPE_BUILTIN_EVADDIW },
6546117395Skan
6547117395Skan  { 0, CODE_FOR_spe_evrlwi, "__builtin_spe_evrlwi", SPE_BUILTIN_EVRLWI },
6548117395Skan  { 0, CODE_FOR_spe_evslwi, "__builtin_spe_evslwi", SPE_BUILTIN_EVSLWI },
6549117395Skan  { 0, CODE_FOR_spe_evsrwis, "__builtin_spe_evsrwis", SPE_BUILTIN_EVSRWIS },
6550117395Skan  { 0, CODE_FOR_spe_evsrwiu, "__builtin_spe_evsrwiu", SPE_BUILTIN_EVSRWIU },
6551117395Skan  { 0, CODE_FOR_spe_evsubifw, "__builtin_spe_evsubifw", SPE_BUILTIN_EVSUBIFW },
6552117395Skan  { 0, CODE_FOR_spe_evmwhssfaa, "__builtin_spe_evmwhssfaa", SPE_BUILTIN_EVMWHSSFAA },
6553117395Skan  { 0, CODE_FOR_spe_evmwhssmaa, "__builtin_spe_evmwhssmaa", SPE_BUILTIN_EVMWHSSMAA },
6554117395Skan  { 0, CODE_FOR_spe_evmwhsmfaa, "__builtin_spe_evmwhsmfaa", SPE_BUILTIN_EVMWHSMFAA },
6555117395Skan  { 0, CODE_FOR_spe_evmwhsmiaa, "__builtin_spe_evmwhsmiaa", SPE_BUILTIN_EVMWHSMIAA },
6556117395Skan  { 0, CODE_FOR_spe_evmwhusiaa, "__builtin_spe_evmwhusiaa", SPE_BUILTIN_EVMWHUSIAA },
6557117395Skan  { 0, CODE_FOR_spe_evmwhumiaa, "__builtin_spe_evmwhumiaa", SPE_BUILTIN_EVMWHUMIAA },
6558117395Skan  { 0, CODE_FOR_spe_evmwhssfan, "__builtin_spe_evmwhssfan", SPE_BUILTIN_EVMWHSSFAN },
6559117395Skan  { 0, CODE_FOR_spe_evmwhssian, "__builtin_spe_evmwhssian", SPE_BUILTIN_EVMWHSSIAN },
6560117395Skan  { 0, CODE_FOR_spe_evmwhsmfan, "__builtin_spe_evmwhsmfan", SPE_BUILTIN_EVMWHSMFAN },
6561117395Skan  { 0, CODE_FOR_spe_evmwhsmian, "__builtin_spe_evmwhsmian", SPE_BUILTIN_EVMWHSMIAN },
6562117395Skan  { 0, CODE_FOR_spe_evmwhusian, "__builtin_spe_evmwhusian", SPE_BUILTIN_EVMWHUSIAN },
6563117395Skan  { 0, CODE_FOR_spe_evmwhumian, "__builtin_spe_evmwhumian", SPE_BUILTIN_EVMWHUMIAN },
6564117395Skan  { 0, CODE_FOR_spe_evmwhgssfaa, "__builtin_spe_evmwhgssfaa", SPE_BUILTIN_EVMWHGSSFAA },
6565117395Skan  { 0, CODE_FOR_spe_evmwhgsmfaa, "__builtin_spe_evmwhgsmfaa", SPE_BUILTIN_EVMWHGSMFAA },
6566117395Skan  { 0, CODE_FOR_spe_evmwhgsmiaa, "__builtin_spe_evmwhgsmiaa", SPE_BUILTIN_EVMWHGSMIAA },
6567117395Skan  { 0, CODE_FOR_spe_evmwhgumiaa, "__builtin_spe_evmwhgumiaa", SPE_BUILTIN_EVMWHGUMIAA },
6568117395Skan  { 0, CODE_FOR_spe_evmwhgssfan, "__builtin_spe_evmwhgssfan", SPE_BUILTIN_EVMWHGSSFAN },
6569117395Skan  { 0, CODE_FOR_spe_evmwhgsmfan, "__builtin_spe_evmwhgsmfan", SPE_BUILTIN_EVMWHGSMFAN },
6570117395Skan  { 0, CODE_FOR_spe_evmwhgsmian, "__builtin_spe_evmwhgsmian", SPE_BUILTIN_EVMWHGSMIAN },
6571117395Skan  { 0, CODE_FOR_spe_evmwhgumian, "__builtin_spe_evmwhgumian", SPE_BUILTIN_EVMWHGUMIAN },
6572117395Skan  { 0, CODE_FOR_spe_brinc, "__builtin_spe_brinc", SPE_BUILTIN_BRINC },
6573117395Skan
6574117395Skan  /* Place-holder.  Leave as last binary SPE builtin.  */
6575169689Skan  { 0, CODE_FOR_xorv2si3, "__builtin_spe_evxor", SPE_BUILTIN_EVXOR }
657690075Sobrien};
657790075Sobrien
657896263Sobrien/* AltiVec predicates.  */
657996263Sobrien
658096263Sobrienstruct builtin_description_predicates
658196263Sobrien{
658296263Sobrien  const unsigned int mask;
658396263Sobrien  const enum insn_code icode;
658496263Sobrien  const char *opcode;
658596263Sobrien  const char *const name;
658696263Sobrien  const enum rs6000_builtins code;
658796263Sobrien};
658896263Sobrien
658996263Sobrienstatic const struct builtin_description_predicates bdesc_altivec_preds[] =
659096263Sobrien{
659196263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v4sf, "*vcmpbfp.", "__builtin_altivec_vcmpbfp_p", ALTIVEC_BUILTIN_VCMPBFP_P },
659296263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v4sf, "*vcmpeqfp.", "__builtin_altivec_vcmpeqfp_p", ALTIVEC_BUILTIN_VCMPEQFP_P },
659396263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v4sf, "*vcmpgefp.", "__builtin_altivec_vcmpgefp_p", ALTIVEC_BUILTIN_VCMPGEFP_P },
659496263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v4sf, "*vcmpgtfp.", "__builtin_altivec_vcmpgtfp_p", ALTIVEC_BUILTIN_VCMPGTFP_P },
659596263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v4si, "*vcmpequw.", "__builtin_altivec_vcmpequw_p", ALTIVEC_BUILTIN_VCMPEQUW_P },
659696263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v4si, "*vcmpgtsw.", "__builtin_altivec_vcmpgtsw_p", ALTIVEC_BUILTIN_VCMPGTSW_P },
659796263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v4si, "*vcmpgtuw.", "__builtin_altivec_vcmpgtuw_p", ALTIVEC_BUILTIN_VCMPGTUW_P },
659896263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v8hi, "*vcmpgtuh.", "__builtin_altivec_vcmpgtuh_p", ALTIVEC_BUILTIN_VCMPGTUH_P },
659996263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v8hi, "*vcmpgtsh.", "__builtin_altivec_vcmpgtsh_p", ALTIVEC_BUILTIN_VCMPGTSH_P },
660096263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v8hi, "*vcmpequh.", "__builtin_altivec_vcmpequh_p", ALTIVEC_BUILTIN_VCMPEQUH_P },
660196263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v16qi, "*vcmpequb.", "__builtin_altivec_vcmpequb_p", ALTIVEC_BUILTIN_VCMPEQUB_P },
660296263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v16qi, "*vcmpgtsb.", "__builtin_altivec_vcmpgtsb_p", ALTIVEC_BUILTIN_VCMPGTSB_P },
6603169689Skan  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v16qi, "*vcmpgtub.", "__builtin_altivec_vcmpgtub_p", ALTIVEC_BUILTIN_VCMPGTUB_P },
6604169689Skan
6605169689Skan  { MASK_ALTIVEC, 0, NULL, "__builtin_vec_vcmpeq_p", ALTIVEC_BUILTIN_VCMPEQ_P },
6606169689Skan  { MASK_ALTIVEC, 0, NULL, "__builtin_vec_vcmpgt_p", ALTIVEC_BUILTIN_VCMPGT_P },
6607169689Skan  { MASK_ALTIVEC, 0, NULL, "__builtin_vec_vcmpge_p", ALTIVEC_BUILTIN_VCMPGE_P }
660896263Sobrien};
660996263Sobrien
6610117395Skan/* SPE predicates.  */
6611117395Skanstatic struct builtin_description bdesc_spe_predicates[] =
6612117395Skan{
6613117395Skan  /* Place-holder.  Leave as first.  */
6614117395Skan  { 0, CODE_FOR_spe_evcmpeq, "__builtin_spe_evcmpeq", SPE_BUILTIN_EVCMPEQ },
6615117395Skan  { 0, CODE_FOR_spe_evcmpgts, "__builtin_spe_evcmpgts", SPE_BUILTIN_EVCMPGTS },
6616117395Skan  { 0, CODE_FOR_spe_evcmpgtu, "__builtin_spe_evcmpgtu", SPE_BUILTIN_EVCMPGTU },
6617117395Skan  { 0, CODE_FOR_spe_evcmplts, "__builtin_spe_evcmplts", SPE_BUILTIN_EVCMPLTS },
6618117395Skan  { 0, CODE_FOR_spe_evcmpltu, "__builtin_spe_evcmpltu", SPE_BUILTIN_EVCMPLTU },
6619117395Skan  { 0, CODE_FOR_spe_evfscmpeq, "__builtin_spe_evfscmpeq", SPE_BUILTIN_EVFSCMPEQ },
6620117395Skan  { 0, CODE_FOR_spe_evfscmpgt, "__builtin_spe_evfscmpgt", SPE_BUILTIN_EVFSCMPGT },
6621117395Skan  { 0, CODE_FOR_spe_evfscmplt, "__builtin_spe_evfscmplt", SPE_BUILTIN_EVFSCMPLT },
6622117395Skan  { 0, CODE_FOR_spe_evfststeq, "__builtin_spe_evfststeq", SPE_BUILTIN_EVFSTSTEQ },
6623117395Skan  { 0, CODE_FOR_spe_evfststgt, "__builtin_spe_evfststgt", SPE_BUILTIN_EVFSTSTGT },
6624117395Skan  /* Place-holder.  Leave as last.  */
6625117395Skan  { 0, CODE_FOR_spe_evfststlt, "__builtin_spe_evfststlt", SPE_BUILTIN_EVFSTSTLT },
6626117395Skan};
6627117395Skan
6628117395Skan/* SPE evsel predicates.  */
6629117395Skanstatic struct builtin_description bdesc_spe_evsel[] =
6630117395Skan{
6631117395Skan  /* Place-holder.  Leave as first.  */
6632117395Skan  { 0, CODE_FOR_spe_evcmpgts, "__builtin_spe_evsel_gts", SPE_BUILTIN_EVSEL_CMPGTS },
6633117395Skan  { 0, CODE_FOR_spe_evcmpgtu, "__builtin_spe_evsel_gtu", SPE_BUILTIN_EVSEL_CMPGTU },
6634117395Skan  { 0, CODE_FOR_spe_evcmplts, "__builtin_spe_evsel_lts", SPE_BUILTIN_EVSEL_CMPLTS },
6635117395Skan  { 0, CODE_FOR_spe_evcmpltu, "__builtin_spe_evsel_ltu", SPE_BUILTIN_EVSEL_CMPLTU },
6636117395Skan  { 0, CODE_FOR_spe_evcmpeq, "__builtin_spe_evsel_eq", SPE_BUILTIN_EVSEL_CMPEQ },
6637117395Skan  { 0, CODE_FOR_spe_evfscmpgt, "__builtin_spe_evsel_fsgt", SPE_BUILTIN_EVSEL_FSCMPGT },
6638117395Skan  { 0, CODE_FOR_spe_evfscmplt, "__builtin_spe_evsel_fslt", SPE_BUILTIN_EVSEL_FSCMPLT },
6639117395Skan  { 0, CODE_FOR_spe_evfscmpeq, "__builtin_spe_evsel_fseq", SPE_BUILTIN_EVSEL_FSCMPEQ },
6640117395Skan  { 0, CODE_FOR_spe_evfststgt, "__builtin_spe_evsel_fststgt", SPE_BUILTIN_EVSEL_FSTSTGT },
6641117395Skan  { 0, CODE_FOR_spe_evfststlt, "__builtin_spe_evsel_fststlt", SPE_BUILTIN_EVSEL_FSTSTLT },
6642117395Skan  /* Place-holder.  Leave as last.  */
6643117395Skan  { 0, CODE_FOR_spe_evfststeq, "__builtin_spe_evsel_fststeq", SPE_BUILTIN_EVSEL_FSTSTEQ },
6644117395Skan};
6645117395Skan
6646132718Skan/* ABS* operations.  */
664796263Sobrien
664896263Sobrienstatic const struct builtin_description bdesc_abs[] =
664996263Sobrien{
665096263Sobrien  { MASK_ALTIVEC, CODE_FOR_absv4si2, "__builtin_altivec_abs_v4si", ALTIVEC_BUILTIN_ABS_V4SI },
665196263Sobrien  { MASK_ALTIVEC, CODE_FOR_absv8hi2, "__builtin_altivec_abs_v8hi", ALTIVEC_BUILTIN_ABS_V8HI },
665296263Sobrien  { MASK_ALTIVEC, CODE_FOR_absv4sf2, "__builtin_altivec_abs_v4sf", ALTIVEC_BUILTIN_ABS_V4SF },
665396263Sobrien  { MASK_ALTIVEC, CODE_FOR_absv16qi2, "__builtin_altivec_abs_v16qi", ALTIVEC_BUILTIN_ABS_V16QI },
665496263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_abss_v4si, "__builtin_altivec_abss_v4si", ALTIVEC_BUILTIN_ABSS_V4SI },
665596263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_abss_v8hi, "__builtin_altivec_abss_v8hi", ALTIVEC_BUILTIN_ABSS_V8HI },
665696263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_abss_v16qi, "__builtin_altivec_abss_v16qi", ALTIVEC_BUILTIN_ABSS_V16QI }
665796263Sobrien};
665896263Sobrien
665990075Sobrien/* Simple unary operations: VECb = foo (unsigned literal) or VECb =
666090075Sobrien   foo (VECa).  */
666190075Sobrien
6662117395Skanstatic struct builtin_description bdesc_1arg[] =
666390075Sobrien{
666490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vexptefp, "__builtin_altivec_vexptefp", ALTIVEC_BUILTIN_VEXPTEFP },
666590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vlogefp, "__builtin_altivec_vlogefp", ALTIVEC_BUILTIN_VLOGEFP },
666690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vrefp, "__builtin_altivec_vrefp", ALTIVEC_BUILTIN_VREFP },
666790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vrfim, "__builtin_altivec_vrfim", ALTIVEC_BUILTIN_VRFIM },
666890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vrfin, "__builtin_altivec_vrfin", ALTIVEC_BUILTIN_VRFIN },
666990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vrfip, "__builtin_altivec_vrfip", ALTIVEC_BUILTIN_VRFIP },
667090075Sobrien  { MASK_ALTIVEC, CODE_FOR_ftruncv4sf2, "__builtin_altivec_vrfiz", ALTIVEC_BUILTIN_VRFIZ },
667190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vrsqrtefp, "__builtin_altivec_vrsqrtefp", ALTIVEC_BUILTIN_VRSQRTEFP },
667290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vspltisb, "__builtin_altivec_vspltisb", ALTIVEC_BUILTIN_VSPLTISB },
667390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vspltish, "__builtin_altivec_vspltish", ALTIVEC_BUILTIN_VSPLTISH },
667490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vspltisw, "__builtin_altivec_vspltisw", ALTIVEC_BUILTIN_VSPLTISW },
667590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vupkhsb, "__builtin_altivec_vupkhsb", ALTIVEC_BUILTIN_VUPKHSB },
667690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vupkhpx, "__builtin_altivec_vupkhpx", ALTIVEC_BUILTIN_VUPKHPX },
667790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vupkhsh, "__builtin_altivec_vupkhsh", ALTIVEC_BUILTIN_VUPKHSH },
667890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vupklsb, "__builtin_altivec_vupklsb", ALTIVEC_BUILTIN_VUPKLSB },
667990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vupklpx, "__builtin_altivec_vupklpx", ALTIVEC_BUILTIN_VUPKLPX },
668090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vupklsh, "__builtin_altivec_vupklsh", ALTIVEC_BUILTIN_VUPKLSH },
6681117395Skan
6682169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_abs", ALTIVEC_BUILTIN_VEC_ABS },
6683169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_abss", ALTIVEC_BUILTIN_VEC_ABSS },
6684169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_ceil", ALTIVEC_BUILTIN_VEC_CEIL },
6685169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_expte", ALTIVEC_BUILTIN_VEC_EXPTE },
6686169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_floor", ALTIVEC_BUILTIN_VEC_FLOOR },
6687169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_loge", ALTIVEC_BUILTIN_VEC_LOGE },
6688169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_mtvscr", ALTIVEC_BUILTIN_VEC_MTVSCR },
6689169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_re", ALTIVEC_BUILTIN_VEC_RE },
6690169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_round", ALTIVEC_BUILTIN_VEC_ROUND },
6691169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_rsqrte", ALTIVEC_BUILTIN_VEC_RSQRTE },
6692169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_trunc", ALTIVEC_BUILTIN_VEC_TRUNC },
6693169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_unpackh", ALTIVEC_BUILTIN_VEC_UNPACKH },
6694169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vupkhsh", ALTIVEC_BUILTIN_VEC_VUPKHSH },
6695169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vupkhpx", ALTIVEC_BUILTIN_VEC_VUPKHPX },
6696169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vupkhsb", ALTIVEC_BUILTIN_VEC_VUPKHSB },
6697169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_unpackl", ALTIVEC_BUILTIN_VEC_UNPACKL },
6698169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vupklpx", ALTIVEC_BUILTIN_VEC_VUPKLPX },
6699169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vupklsh", ALTIVEC_BUILTIN_VEC_VUPKLSH },
6700169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vupklsb", ALTIVEC_BUILTIN_VEC_VUPKLSB },
6701169689Skan
6702117395Skan  /* The SPE unary builtins must start with SPE_BUILTIN_EVABS and
6703117395Skan     end with SPE_BUILTIN_EVSUBFUSIAAW.  */
6704117395Skan  { 0, CODE_FOR_spe_evabs, "__builtin_spe_evabs", SPE_BUILTIN_EVABS },
6705117395Skan  { 0, CODE_FOR_spe_evaddsmiaaw, "__builtin_spe_evaddsmiaaw", SPE_BUILTIN_EVADDSMIAAW },
6706117395Skan  { 0, CODE_FOR_spe_evaddssiaaw, "__builtin_spe_evaddssiaaw", SPE_BUILTIN_EVADDSSIAAW },
6707117395Skan  { 0, CODE_FOR_spe_evaddumiaaw, "__builtin_spe_evaddumiaaw", SPE_BUILTIN_EVADDUMIAAW },
6708117395Skan  { 0, CODE_FOR_spe_evaddusiaaw, "__builtin_spe_evaddusiaaw", SPE_BUILTIN_EVADDUSIAAW },
6709117395Skan  { 0, CODE_FOR_spe_evcntlsw, "__builtin_spe_evcntlsw", SPE_BUILTIN_EVCNTLSW },
6710117395Skan  { 0, CODE_FOR_spe_evcntlzw, "__builtin_spe_evcntlzw", SPE_BUILTIN_EVCNTLZW },
6711117395Skan  { 0, CODE_FOR_spe_evextsb, "__builtin_spe_evextsb", SPE_BUILTIN_EVEXTSB },
6712117395Skan  { 0, CODE_FOR_spe_evextsh, "__builtin_spe_evextsh", SPE_BUILTIN_EVEXTSH },
6713117395Skan  { 0, CODE_FOR_spe_evfsabs, "__builtin_spe_evfsabs", SPE_BUILTIN_EVFSABS },
6714117395Skan  { 0, CODE_FOR_spe_evfscfsf, "__builtin_spe_evfscfsf", SPE_BUILTIN_EVFSCFSF },
6715117395Skan  { 0, CODE_FOR_spe_evfscfsi, "__builtin_spe_evfscfsi", SPE_BUILTIN_EVFSCFSI },
6716117395Skan  { 0, CODE_FOR_spe_evfscfuf, "__builtin_spe_evfscfuf", SPE_BUILTIN_EVFSCFUF },
6717117395Skan  { 0, CODE_FOR_spe_evfscfui, "__builtin_spe_evfscfui", SPE_BUILTIN_EVFSCFUI },
6718117395Skan  { 0, CODE_FOR_spe_evfsctsf, "__builtin_spe_evfsctsf", SPE_BUILTIN_EVFSCTSF },
6719117395Skan  { 0, CODE_FOR_spe_evfsctsi, "__builtin_spe_evfsctsi", SPE_BUILTIN_EVFSCTSI },
6720117395Skan  { 0, CODE_FOR_spe_evfsctsiz, "__builtin_spe_evfsctsiz", SPE_BUILTIN_EVFSCTSIZ },
6721117395Skan  { 0, CODE_FOR_spe_evfsctuf, "__builtin_spe_evfsctuf", SPE_BUILTIN_EVFSCTUF },
6722117395Skan  { 0, CODE_FOR_spe_evfsctui, "__builtin_spe_evfsctui", SPE_BUILTIN_EVFSCTUI },
6723117395Skan  { 0, CODE_FOR_spe_evfsctuiz, "__builtin_spe_evfsctuiz", SPE_BUILTIN_EVFSCTUIZ },
6724117395Skan  { 0, CODE_FOR_spe_evfsnabs, "__builtin_spe_evfsnabs", SPE_BUILTIN_EVFSNABS },
6725117395Skan  { 0, CODE_FOR_spe_evfsneg, "__builtin_spe_evfsneg", SPE_BUILTIN_EVFSNEG },
6726117395Skan  { 0, CODE_FOR_spe_evmra, "__builtin_spe_evmra", SPE_BUILTIN_EVMRA },
6727132718Skan  { 0, CODE_FOR_negv2si2, "__builtin_spe_evneg", SPE_BUILTIN_EVNEG },
6728117395Skan  { 0, CODE_FOR_spe_evrndw, "__builtin_spe_evrndw", SPE_BUILTIN_EVRNDW },
6729117395Skan  { 0, CODE_FOR_spe_evsubfsmiaaw, "__builtin_spe_evsubfsmiaaw", SPE_BUILTIN_EVSUBFSMIAAW },
6730117395Skan  { 0, CODE_FOR_spe_evsubfssiaaw, "__builtin_spe_evsubfssiaaw", SPE_BUILTIN_EVSUBFSSIAAW },
6731117395Skan  { 0, CODE_FOR_spe_evsubfumiaaw, "__builtin_spe_evsubfumiaaw", SPE_BUILTIN_EVSUBFUMIAAW },
6732117395Skan
6733117395Skan  /* Place-holder.  Leave as last unary SPE builtin.  */
6734169689Skan  { 0, CODE_FOR_spe_evsubfusiaaw, "__builtin_spe_evsubfusiaaw", SPE_BUILTIN_EVSUBFUSIAAW }
673590075Sobrien};
673690075Sobrien
673790075Sobrienstatic rtx
6738132718Skanrs6000_expand_unop_builtin (enum insn_code icode, tree arglist, rtx target)
673990075Sobrien{
674090075Sobrien  rtx pat;
674190075Sobrien  tree arg0 = TREE_VALUE (arglist);
6742169689Skan  rtx op0 = expand_normal (arg0);
674390075Sobrien  enum machine_mode tmode = insn_data[icode].operand[0].mode;
674490075Sobrien  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
674590075Sobrien
6746117395Skan  if (icode == CODE_FOR_nothing)
6747117395Skan    /* Builtin not supported on this processor.  */
6748117395Skan    return 0;
6749117395Skan
675090075Sobrien  /* If we got invalid arguments bail out before generating bad rtl.  */
675190075Sobrien  if (arg0 == error_mark_node)
6752117395Skan    return const0_rtx;
675390075Sobrien
6754117395Skan  if (icode == CODE_FOR_altivec_vspltisb
6755117395Skan      || icode == CODE_FOR_altivec_vspltish
6756117395Skan      || icode == CODE_FOR_altivec_vspltisw
6757117395Skan      || icode == CODE_FOR_spe_evsplatfi
6758117395Skan      || icode == CODE_FOR_spe_evsplati)
6759117395Skan    {
6760117395Skan      /* Only allow 5-bit *signed* literals.  */
6761117395Skan      if (GET_CODE (op0) != CONST_INT
6762169689Skan	  || INTVAL (op0) > 15
6763169689Skan	  || INTVAL (op0) < -16)
6764117395Skan	{
6765117395Skan	  error ("argument 1 must be a 5-bit signed literal");
6766117395Skan	  return const0_rtx;
6767117395Skan	}
6768117395Skan    }
6769117395Skan
677090075Sobrien  if (target == 0
677190075Sobrien      || GET_MODE (target) != tmode
677290075Sobrien      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
677390075Sobrien    target = gen_reg_rtx (tmode);
677490075Sobrien
677590075Sobrien  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
677690075Sobrien    op0 = copy_to_mode_reg (mode0, op0);
677790075Sobrien
677890075Sobrien  pat = GEN_FCN (icode) (target, op0);
677990075Sobrien  if (! pat)
678090075Sobrien    return 0;
678190075Sobrien  emit_insn (pat);
678290075Sobrien
678390075Sobrien  return target;
678490075Sobrien}
678596263Sobrien
678690075Sobrienstatic rtx
6787132718Skanaltivec_expand_abs_builtin (enum insn_code icode, tree arglist, rtx target)
678896263Sobrien{
678996263Sobrien  rtx pat, scratch1, scratch2;
679096263Sobrien  tree arg0 = TREE_VALUE (arglist);
6791169689Skan  rtx op0 = expand_normal (arg0);
679296263Sobrien  enum machine_mode tmode = insn_data[icode].operand[0].mode;
679396263Sobrien  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
679496263Sobrien
679596263Sobrien  /* If we have invalid arguments, bail out before generating bad rtl.  */
679696263Sobrien  if (arg0 == error_mark_node)
6797117395Skan    return const0_rtx;
679896263Sobrien
679996263Sobrien  if (target == 0
680096263Sobrien      || GET_MODE (target) != tmode
680196263Sobrien      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
680296263Sobrien    target = gen_reg_rtx (tmode);
680396263Sobrien
680496263Sobrien  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
680596263Sobrien    op0 = copy_to_mode_reg (mode0, op0);
680696263Sobrien
680796263Sobrien  scratch1 = gen_reg_rtx (mode0);
680896263Sobrien  scratch2 = gen_reg_rtx (mode0);
680996263Sobrien
681096263Sobrien  pat = GEN_FCN (icode) (target, op0, scratch1, scratch2);
681196263Sobrien  if (! pat)
681296263Sobrien    return 0;
681396263Sobrien  emit_insn (pat);
681496263Sobrien
681596263Sobrien  return target;
681696263Sobrien}
681796263Sobrien
681896263Sobrienstatic rtx
6819132718Skanrs6000_expand_binop_builtin (enum insn_code icode, tree arglist, rtx target)
682090075Sobrien{
682190075Sobrien  rtx pat;
682290075Sobrien  tree arg0 = TREE_VALUE (arglist);
682390075Sobrien  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
6824169689Skan  rtx op0 = expand_normal (arg0);
6825169689Skan  rtx op1 = expand_normal (arg1);
682690075Sobrien  enum machine_mode tmode = insn_data[icode].operand[0].mode;
682790075Sobrien  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
682890075Sobrien  enum machine_mode mode1 = insn_data[icode].operand[2].mode;
682990075Sobrien
6830117395Skan  if (icode == CODE_FOR_nothing)
6831117395Skan    /* Builtin not supported on this processor.  */
6832117395Skan    return 0;
6833117395Skan
683490075Sobrien  /* If we got invalid arguments bail out before generating bad rtl.  */
683590075Sobrien  if (arg0 == error_mark_node || arg1 == error_mark_node)
6836117395Skan    return const0_rtx;
683790075Sobrien
6838117395Skan  if (icode == CODE_FOR_altivec_vcfux
6839117395Skan      || icode == CODE_FOR_altivec_vcfsx
6840117395Skan      || icode == CODE_FOR_altivec_vctsxs
6841117395Skan      || icode == CODE_FOR_altivec_vctuxs
6842117395Skan      || icode == CODE_FOR_altivec_vspltb
6843117395Skan      || icode == CODE_FOR_altivec_vsplth
6844117395Skan      || icode == CODE_FOR_altivec_vspltw
6845117395Skan      || icode == CODE_FOR_spe_evaddiw
6846117395Skan      || icode == CODE_FOR_spe_evldd
6847117395Skan      || icode == CODE_FOR_spe_evldh
6848117395Skan      || icode == CODE_FOR_spe_evldw
6849117395Skan      || icode == CODE_FOR_spe_evlhhesplat
6850117395Skan      || icode == CODE_FOR_spe_evlhhossplat
6851117395Skan      || icode == CODE_FOR_spe_evlhhousplat
6852117395Skan      || icode == CODE_FOR_spe_evlwhe
6853117395Skan      || icode == CODE_FOR_spe_evlwhos
6854117395Skan      || icode == CODE_FOR_spe_evlwhou
6855117395Skan      || icode == CODE_FOR_spe_evlwhsplat
6856117395Skan      || icode == CODE_FOR_spe_evlwwsplat
6857117395Skan      || icode == CODE_FOR_spe_evrlwi
6858117395Skan      || icode == CODE_FOR_spe_evslwi
6859117395Skan      || icode == CODE_FOR_spe_evsrwis
6860132718Skan      || icode == CODE_FOR_spe_evsubifw
6861117395Skan      || icode == CODE_FOR_spe_evsrwiu)
6862117395Skan    {
6863117395Skan      /* Only allow 5-bit unsigned literals.  */
6864146895Skan      STRIP_NOPS (arg1);
6865117395Skan      if (TREE_CODE (arg1) != INTEGER_CST
6866117395Skan	  || TREE_INT_CST_LOW (arg1) & ~0x1f)
6867117395Skan	{
6868117395Skan	  error ("argument 2 must be a 5-bit unsigned literal");
6869117395Skan	  return const0_rtx;
6870117395Skan	}
6871117395Skan    }
6872117395Skan
687390075Sobrien  if (target == 0
687490075Sobrien      || GET_MODE (target) != tmode
687590075Sobrien      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
687690075Sobrien    target = gen_reg_rtx (tmode);
687790075Sobrien
687890075Sobrien  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
687990075Sobrien    op0 = copy_to_mode_reg (mode0, op0);
688090075Sobrien  if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
688190075Sobrien    op1 = copy_to_mode_reg (mode1, op1);
688290075Sobrien
688390075Sobrien  pat = GEN_FCN (icode) (target, op0, op1);
688490075Sobrien  if (! pat)
688590075Sobrien    return 0;
688690075Sobrien  emit_insn (pat);
688790075Sobrien
688890075Sobrien  return target;
688990075Sobrien}
689090075Sobrien
689190075Sobrienstatic rtx
6892169689Skanaltivec_expand_predicate_builtin (enum insn_code icode, const char *opcode,
6893132718Skan				  tree arglist, rtx target)
689496263Sobrien{
689596263Sobrien  rtx pat, scratch;
689696263Sobrien  tree cr6_form = TREE_VALUE (arglist);
689796263Sobrien  tree arg0 = TREE_VALUE (TREE_CHAIN (arglist));
689896263Sobrien  tree arg1 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
6899169689Skan  rtx op0 = expand_normal (arg0);
6900169689Skan  rtx op1 = expand_normal (arg1);
690196263Sobrien  enum machine_mode tmode = SImode;
690296263Sobrien  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
690396263Sobrien  enum machine_mode mode1 = insn_data[icode].operand[2].mode;
690496263Sobrien  int cr6_form_int;
690596263Sobrien
690696263Sobrien  if (TREE_CODE (cr6_form) != INTEGER_CST)
690796263Sobrien    {
690896263Sobrien      error ("argument 1 of __builtin_altivec_predicate must be a constant");
6909117395Skan      return const0_rtx;
691096263Sobrien    }
691196263Sobrien  else
691296263Sobrien    cr6_form_int = TREE_INT_CST_LOW (cr6_form);
691396263Sobrien
6914169689Skan  gcc_assert (mode0 == mode1);
691596263Sobrien
691696263Sobrien  /* If we have invalid arguments, bail out before generating bad rtl.  */
691796263Sobrien  if (arg0 == error_mark_node || arg1 == error_mark_node)
6918117395Skan    return const0_rtx;
691996263Sobrien
692096263Sobrien  if (target == 0
692196263Sobrien      || GET_MODE (target) != tmode
692296263Sobrien      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
692396263Sobrien    target = gen_reg_rtx (tmode);
692496263Sobrien
692596263Sobrien  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
692696263Sobrien    op0 = copy_to_mode_reg (mode0, op0);
692796263Sobrien  if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
692896263Sobrien    op1 = copy_to_mode_reg (mode1, op1);
692996263Sobrien
693096263Sobrien  scratch = gen_reg_rtx (mode0);
693196263Sobrien
693296263Sobrien  pat = GEN_FCN (icode) (scratch, op0, op1,
6933169689Skan			 gen_rtx_SYMBOL_REF (Pmode, opcode));
693496263Sobrien  if (! pat)
693596263Sobrien    return 0;
693696263Sobrien  emit_insn (pat);
693796263Sobrien
693896263Sobrien  /* The vec_any* and vec_all* predicates use the same opcodes for two
693996263Sobrien     different operations, but the bits in CR6 will be different
694096263Sobrien     depending on what information we want.  So we have to play tricks
694196263Sobrien     with CR6 to get the right bits out.
694296263Sobrien
694396263Sobrien     If you think this is disgusting, look at the specs for the
694496263Sobrien     AltiVec predicates.  */
694596263Sobrien
6946169689Skan  switch (cr6_form_int)
6947169689Skan    {
6948169689Skan    case 0:
6949169689Skan      emit_insn (gen_cr6_test_for_zero (target));
6950169689Skan      break;
6951169689Skan    case 1:
6952169689Skan      emit_insn (gen_cr6_test_for_zero_reverse (target));
6953169689Skan      break;
6954169689Skan    case 2:
6955169689Skan      emit_insn (gen_cr6_test_for_lt (target));
6956169689Skan      break;
6957169689Skan    case 3:
6958169689Skan      emit_insn (gen_cr6_test_for_lt_reverse (target));
6959169689Skan      break;
6960169689Skan    default:
6961169689Skan      error ("argument 1 of __builtin_altivec_predicate is out of range");
6962169689Skan      break;
6963169689Skan    }
696496263Sobrien
696596263Sobrien  return target;
696696263Sobrien}
696796263Sobrien
696896263Sobrienstatic rtx
6969132718Skanaltivec_expand_lv_builtin (enum insn_code icode, tree arglist, rtx target)
697090075Sobrien{
6971132718Skan  rtx pat, addr;
697290075Sobrien  tree arg0 = TREE_VALUE (arglist);
697390075Sobrien  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
6974132718Skan  enum machine_mode tmode = insn_data[icode].operand[0].mode;
6975132718Skan  enum machine_mode mode0 = Pmode;
6976132718Skan  enum machine_mode mode1 = Pmode;
6977169689Skan  rtx op0 = expand_normal (arg0);
6978169689Skan  rtx op1 = expand_normal (arg1);
6979132718Skan
6980132718Skan  if (icode == CODE_FOR_nothing)
6981132718Skan    /* Builtin not supported on this processor.  */
6982132718Skan    return 0;
6983132718Skan
6984132718Skan  /* If we got invalid arguments bail out before generating bad rtl.  */
6985132718Skan  if (arg0 == error_mark_node || arg1 == error_mark_node)
6986132718Skan    return const0_rtx;
6987132718Skan
6988132718Skan  if (target == 0
6989132718Skan      || GET_MODE (target) != tmode
6990132718Skan      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
6991132718Skan    target = gen_reg_rtx (tmode);
6992132718Skan
6993169689Skan  op1 = copy_to_mode_reg (mode1, op1);
6994132718Skan
6995132718Skan  if (op0 == const0_rtx)
6996132718Skan    {
6997132718Skan      addr = gen_rtx_MEM (tmode, op1);
6998132718Skan    }
6999132718Skan  else
7000132718Skan    {
7001132718Skan      op0 = copy_to_mode_reg (mode0, op0);
7002132718Skan      addr = gen_rtx_MEM (tmode, gen_rtx_PLUS (Pmode, op0, op1));
7003132718Skan    }
7004132718Skan
7005132718Skan  pat = GEN_FCN (icode) (target, addr);
7006132718Skan
7007132718Skan  if (! pat)
7008132718Skan    return 0;
7009132718Skan  emit_insn (pat);
7010132718Skan
7011132718Skan  return target;
7012132718Skan}
7013132718Skan
7014132718Skanstatic rtx
7015132718Skanspe_expand_stv_builtin (enum insn_code icode, tree arglist)
7016132718Skan{
7017132718Skan  tree arg0 = TREE_VALUE (arglist);
7018132718Skan  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
701990075Sobrien  tree arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
7020169689Skan  rtx op0 = expand_normal (arg0);
7021169689Skan  rtx op1 = expand_normal (arg1);
7022169689Skan  rtx op2 = expand_normal (arg2);
702390075Sobrien  rtx pat;
702490075Sobrien  enum machine_mode mode0 = insn_data[icode].operand[0].mode;
702590075Sobrien  enum machine_mode mode1 = insn_data[icode].operand[1].mode;
702690075Sobrien  enum machine_mode mode2 = insn_data[icode].operand[2].mode;
702790075Sobrien
702890075Sobrien  /* Invalid arguments.  Bail before doing anything stoopid!  */
702990075Sobrien  if (arg0 == error_mark_node
703090075Sobrien      || arg1 == error_mark_node
703190075Sobrien      || arg2 == error_mark_node)
7032117395Skan    return const0_rtx;
703390075Sobrien
703490075Sobrien  if (! (*insn_data[icode].operand[2].predicate) (op0, mode2))
703590075Sobrien    op0 = copy_to_mode_reg (mode2, op0);
703690075Sobrien  if (! (*insn_data[icode].operand[0].predicate) (op1, mode0))
703790075Sobrien    op1 = copy_to_mode_reg (mode0, op1);
703890075Sobrien  if (! (*insn_data[icode].operand[1].predicate) (op2, mode1))
703990075Sobrien    op2 = copy_to_mode_reg (mode1, op2);
704090075Sobrien
704190075Sobrien  pat = GEN_FCN (icode) (op1, op2, op0);
704290075Sobrien  if (pat)
704390075Sobrien    emit_insn (pat);
704490075Sobrien  return NULL_RTX;
704590075Sobrien}
704690075Sobrien
704790075Sobrienstatic rtx
7048132718Skanaltivec_expand_stv_builtin (enum insn_code icode, tree arglist)
704990075Sobrien{
7050132718Skan  tree arg0 = TREE_VALUE (arglist);
7051132718Skan  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
7052132718Skan  tree arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
7053169689Skan  rtx op0 = expand_normal (arg0);
7054169689Skan  rtx op1 = expand_normal (arg1);
7055169689Skan  rtx op2 = expand_normal (arg2);
7056132718Skan  rtx pat, addr;
7057132718Skan  enum machine_mode tmode = insn_data[icode].operand[0].mode;
7058132718Skan  enum machine_mode mode1 = Pmode;
7059132718Skan  enum machine_mode mode2 = Pmode;
7060132718Skan
7061132718Skan  /* Invalid arguments.  Bail before doing anything stoopid!  */
7062132718Skan  if (arg0 == error_mark_node
7063132718Skan      || arg1 == error_mark_node
7064132718Skan      || arg2 == error_mark_node)
7065132718Skan    return const0_rtx;
7066132718Skan
7067132718Skan  if (! (*insn_data[icode].operand[1].predicate) (op0, tmode))
7068132718Skan    op0 = copy_to_mode_reg (tmode, op0);
7069132718Skan
7070169689Skan  op2 = copy_to_mode_reg (mode2, op2);
7071132718Skan
7072132718Skan  if (op1 == const0_rtx)
7073132718Skan    {
7074132718Skan      addr = gen_rtx_MEM (tmode, op2);
7075132718Skan    }
7076132718Skan  else
7077132718Skan    {
7078132718Skan      op1 = copy_to_mode_reg (mode1, op1);
7079132718Skan      addr = gen_rtx_MEM (tmode, gen_rtx_PLUS (Pmode, op1, op2));
7080132718Skan    }
7081132718Skan
7082132718Skan  pat = GEN_FCN (icode) (addr, op0);
7083132718Skan  if (pat)
7084132718Skan    emit_insn (pat);
7085132718Skan  return NULL_RTX;
7086132718Skan}
7087132718Skan
7088132718Skanstatic rtx
7089132718Skanrs6000_expand_ternop_builtin (enum insn_code icode, tree arglist, rtx target)
7090132718Skan{
709190075Sobrien  rtx pat;
709290075Sobrien  tree arg0 = TREE_VALUE (arglist);
709390075Sobrien  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
709490075Sobrien  tree arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
7095169689Skan  rtx op0 = expand_normal (arg0);
7096169689Skan  rtx op1 = expand_normal (arg1);
7097169689Skan  rtx op2 = expand_normal (arg2);
709890075Sobrien  enum machine_mode tmode = insn_data[icode].operand[0].mode;
709990075Sobrien  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
710090075Sobrien  enum machine_mode mode1 = insn_data[icode].operand[2].mode;
710190075Sobrien  enum machine_mode mode2 = insn_data[icode].operand[3].mode;
710290075Sobrien
7103117395Skan  if (icode == CODE_FOR_nothing)
7104117395Skan    /* Builtin not supported on this processor.  */
7105117395Skan    return 0;
7106117395Skan
710790075Sobrien  /* If we got invalid arguments bail out before generating bad rtl.  */
710890075Sobrien  if (arg0 == error_mark_node
710990075Sobrien      || arg1 == error_mark_node
711090075Sobrien      || arg2 == error_mark_node)
7111117395Skan    return const0_rtx;
711290075Sobrien
7113169689Skan  if (icode == CODE_FOR_altivec_vsldoi_v4sf
7114169689Skan      || icode == CODE_FOR_altivec_vsldoi_v4si
7115169689Skan      || icode == CODE_FOR_altivec_vsldoi_v8hi
7116169689Skan      || icode == CODE_FOR_altivec_vsldoi_v16qi)
7117117395Skan    {
7118117395Skan      /* Only allow 4-bit unsigned literals.  */
7119169689Skan      STRIP_NOPS (arg2);
7120117395Skan      if (TREE_CODE (arg2) != INTEGER_CST
7121117395Skan	  || TREE_INT_CST_LOW (arg2) & ~0xf)
7122117395Skan	{
7123117395Skan	  error ("argument 3 must be a 4-bit unsigned literal");
7124117395Skan	  return const0_rtx;
7125117395Skan	}
7126117395Skan    }
7127117395Skan
712890075Sobrien  if (target == 0
712990075Sobrien      || GET_MODE (target) != tmode
713090075Sobrien      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
713190075Sobrien    target = gen_reg_rtx (tmode);
713290075Sobrien
713390075Sobrien  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
713490075Sobrien    op0 = copy_to_mode_reg (mode0, op0);
713590075Sobrien  if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
713690075Sobrien    op1 = copy_to_mode_reg (mode1, op1);
713790075Sobrien  if (! (*insn_data[icode].operand[3].predicate) (op2, mode2))
713890075Sobrien    op2 = copy_to_mode_reg (mode2, op2);
713990075Sobrien
714090075Sobrien  pat = GEN_FCN (icode) (target, op0, op1, op2);
714190075Sobrien  if (! pat)
714290075Sobrien    return 0;
714390075Sobrien  emit_insn (pat);
714490075Sobrien
714590075Sobrien  return target;
714690075Sobrien}
7147117395Skan
7148117395Skan/* Expand the lvx builtins.  */
714990075Sobrienstatic rtx
7150132718Skanaltivec_expand_ld_builtin (tree exp, rtx target, bool *expandedp)
715190075Sobrien{
715290075Sobrien  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
715390075Sobrien  tree arglist = TREE_OPERAND (exp, 1);
715490075Sobrien  unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
7155117395Skan  tree arg0;
7156117395Skan  enum machine_mode tmode, mode0;
7157117395Skan  rtx pat, op0;
7158117395Skan  enum insn_code icode;
7159117395Skan
716090075Sobrien  switch (fcode)
716190075Sobrien    {
716290075Sobrien    case ALTIVEC_BUILTIN_LD_INTERNAL_16qi:
7163169689Skan      icode = CODE_FOR_altivec_lvx_v16qi;
7164117395Skan      break;
7165117395Skan    case ALTIVEC_BUILTIN_LD_INTERNAL_8hi:
7166169689Skan      icode = CODE_FOR_altivec_lvx_v8hi;
7167117395Skan      break;
7168117395Skan    case ALTIVEC_BUILTIN_LD_INTERNAL_4si:
7169169689Skan      icode = CODE_FOR_altivec_lvx_v4si;
7170117395Skan      break;
7171117395Skan    case ALTIVEC_BUILTIN_LD_INTERNAL_4sf:
7172169689Skan      icode = CODE_FOR_altivec_lvx_v4sf;
7173117395Skan      break;
7174117395Skan    default:
7175117395Skan      *expandedp = false;
7176117395Skan      return NULL_RTX;
7177117395Skan    }
717890075Sobrien
7179117395Skan  *expandedp = true;
718090075Sobrien
7181117395Skan  arg0 = TREE_VALUE (arglist);
7182169689Skan  op0 = expand_normal (arg0);
7183117395Skan  tmode = insn_data[icode].operand[0].mode;
7184117395Skan  mode0 = insn_data[icode].operand[1].mode;
718590075Sobrien
7186117395Skan  if (target == 0
7187117395Skan      || GET_MODE (target) != tmode
7188117395Skan      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
7189117395Skan    target = gen_reg_rtx (tmode);
719090075Sobrien
7191117395Skan  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
7192117395Skan    op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
719390075Sobrien
7194117395Skan  pat = GEN_FCN (icode) (target, op0);
7195117395Skan  if (! pat)
7196117395Skan    return 0;
7197117395Skan  emit_insn (pat);
7198117395Skan  return target;
7199117395Skan}
720090075Sobrien
7201117395Skan/* Expand the stvx builtins.  */
7202117395Skanstatic rtx
7203169689Skanaltivec_expand_st_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
7204132718Skan			   bool *expandedp)
7205117395Skan{
7206117395Skan  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
7207117395Skan  tree arglist = TREE_OPERAND (exp, 1);
7208117395Skan  unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
7209117395Skan  tree arg0, arg1;
7210117395Skan  enum machine_mode mode0, mode1;
7211117395Skan  rtx pat, op0, op1;
7212117395Skan  enum insn_code icode;
721390075Sobrien
7214117395Skan  switch (fcode)
7215117395Skan    {
7216117395Skan    case ALTIVEC_BUILTIN_ST_INTERNAL_16qi:
7217169689Skan      icode = CODE_FOR_altivec_stvx_v16qi;
7218117395Skan      break;
7219117395Skan    case ALTIVEC_BUILTIN_ST_INTERNAL_8hi:
7220169689Skan      icode = CODE_FOR_altivec_stvx_v8hi;
7221117395Skan      break;
7222117395Skan    case ALTIVEC_BUILTIN_ST_INTERNAL_4si:
7223169689Skan      icode = CODE_FOR_altivec_stvx_v4si;
7224117395Skan      break;
7225117395Skan    case ALTIVEC_BUILTIN_ST_INTERNAL_4sf:
7226169689Skan      icode = CODE_FOR_altivec_stvx_v4sf;
7227117395Skan      break;
7228117395Skan    default:
7229117395Skan      *expandedp = false;
7230117395Skan      return NULL_RTX;
7231117395Skan    }
723290075Sobrien
7233117395Skan  arg0 = TREE_VALUE (arglist);
7234117395Skan  arg1 = TREE_VALUE (TREE_CHAIN (arglist));
7235169689Skan  op0 = expand_normal (arg0);
7236169689Skan  op1 = expand_normal (arg1);
7237117395Skan  mode0 = insn_data[icode].operand[0].mode;
7238117395Skan  mode1 = insn_data[icode].operand[1].mode;
723990075Sobrien
7240117395Skan  if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
7241117395Skan    op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
7242117395Skan  if (! (*insn_data[icode].operand[1].predicate) (op1, mode1))
7243117395Skan    op1 = copy_to_mode_reg (mode1, op1);
724490075Sobrien
7245117395Skan  pat = GEN_FCN (icode) (op0, op1);
7246117395Skan  if (pat)
7247117395Skan    emit_insn (pat);
724890075Sobrien
7249117395Skan  *expandedp = true;
7250117395Skan  return NULL_RTX;
7251117395Skan}
725290075Sobrien
7253117395Skan/* Expand the dst builtins.  */
7254117395Skanstatic rtx
7255169689Skanaltivec_expand_dst_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
7256132718Skan			    bool *expandedp)
7257117395Skan{
7258117395Skan  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
7259117395Skan  tree arglist = TREE_OPERAND (exp, 1);
7260117395Skan  unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
7261117395Skan  tree arg0, arg1, arg2;
7262117395Skan  enum machine_mode mode0, mode1, mode2;
7263117395Skan  rtx pat, op0, op1, op2;
7264117395Skan  struct builtin_description *d;
7265117395Skan  size_t i;
726690075Sobrien
7267117395Skan  *expandedp = false;
726890075Sobrien
7269117395Skan  /* Handle DST variants.  */
7270117395Skan  d = (struct builtin_description *) bdesc_dst;
7271117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_dst); i++, d++)
7272117395Skan    if (d->code == fcode)
7273117395Skan      {
7274117395Skan	arg0 = TREE_VALUE (arglist);
7275117395Skan	arg1 = TREE_VALUE (TREE_CHAIN (arglist));
7276117395Skan	arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
7277169689Skan	op0 = expand_normal (arg0);
7278169689Skan	op1 = expand_normal (arg1);
7279169689Skan	op2 = expand_normal (arg2);
7280117395Skan	mode0 = insn_data[d->icode].operand[0].mode;
7281117395Skan	mode1 = insn_data[d->icode].operand[1].mode;
7282117395Skan	mode2 = insn_data[d->icode].operand[2].mode;
728390075Sobrien
7284117395Skan	/* Invalid arguments, bail out before generating bad rtl.  */
7285117395Skan	if (arg0 == error_mark_node
7286117395Skan	    || arg1 == error_mark_node
7287117395Skan	    || arg2 == error_mark_node)
7288117395Skan	  return const0_rtx;
728990075Sobrien
7290146895Skan	*expandedp = true;
7291146895Skan	STRIP_NOPS (arg2);
7292117395Skan	if (TREE_CODE (arg2) != INTEGER_CST
7293117395Skan	    || TREE_INT_CST_LOW (arg2) & ~0x3)
7294117395Skan	  {
7295169689Skan	    error ("argument to %qs must be a 2-bit unsigned literal", d->name);
7296117395Skan	    return const0_rtx;
7297117395Skan	  }
729890075Sobrien
7299117395Skan	if (! (*insn_data[d->icode].operand[0].predicate) (op0, mode0))
7300169689Skan	  op0 = copy_to_mode_reg (Pmode, op0);
7301117395Skan	if (! (*insn_data[d->icode].operand[1].predicate) (op1, mode1))
7302117395Skan	  op1 = copy_to_mode_reg (mode1, op1);
730390075Sobrien
7304117395Skan	pat = GEN_FCN (d->icode) (op0, op1, op2);
7305117395Skan	if (pat != 0)
7306117395Skan	  emit_insn (pat);
730790075Sobrien
7308117395Skan	return NULL_RTX;
7309117395Skan      }
731090075Sobrien
7311117395Skan  return NULL_RTX;
7312117395Skan}
731390075Sobrien
7314169689Skan/* Expand vec_init builtin.  */
7315169689Skanstatic rtx
7316169689Skanaltivec_expand_vec_init_builtin (tree type, tree arglist, rtx target)
7317169689Skan{
7318169689Skan  enum machine_mode tmode = TYPE_MODE (type);
7319169689Skan  enum machine_mode inner_mode = GET_MODE_INNER (tmode);
7320169689Skan  int i, n_elt = GET_MODE_NUNITS (tmode);
7321169689Skan  rtvec v = rtvec_alloc (n_elt);
7322169689Skan
7323169689Skan  gcc_assert (VECTOR_MODE_P (tmode));
7324169689Skan
7325169689Skan  for (i = 0; i < n_elt; ++i, arglist = TREE_CHAIN (arglist))
7326169689Skan    {
7327169689Skan      rtx x = expand_normal (TREE_VALUE (arglist));
7328169689Skan      RTVEC_ELT (v, i) = gen_lowpart (inner_mode, x);
7329169689Skan    }
7330169689Skan
7331169689Skan  gcc_assert (arglist == NULL);
7332169689Skan
7333169689Skan  if (!target || !register_operand (target, tmode))
7334169689Skan    target = gen_reg_rtx (tmode);
7335169689Skan
7336169689Skan  rs6000_expand_vector_init (target, gen_rtx_PARALLEL (tmode, v));
7337169689Skan  return target;
7338169689Skan}
7339169689Skan
7340169689Skan/* Return the integer constant in ARG.  Constrain it to be in the range
7341169689Skan   of the subparts of VEC_TYPE; issue an error if not.  */
7342169689Skan
7343169689Skanstatic int
7344169689Skanget_element_number (tree vec_type, tree arg)
7345169689Skan{
7346169689Skan  unsigned HOST_WIDE_INT elt, max = TYPE_VECTOR_SUBPARTS (vec_type) - 1;
7347169689Skan
7348169689Skan  if (!host_integerp (arg, 1)
7349169689Skan      || (elt = tree_low_cst (arg, 1), elt > max))
7350169689Skan    {
7351169689Skan      error ("selector must be an integer constant in the range 0..%wi", max);
7352169689Skan      return 0;
7353169689Skan    }
7354169689Skan
7355169689Skan  return elt;
7356169689Skan}
7357169689Skan
7358169689Skan/* Expand vec_set builtin.  */
7359169689Skanstatic rtx
7360169689Skanaltivec_expand_vec_set_builtin (tree arglist)
7361169689Skan{
7362169689Skan  enum machine_mode tmode, mode1;
7363169689Skan  tree arg0, arg1, arg2;
7364169689Skan  int elt;
7365169689Skan  rtx op0, op1;
7366169689Skan
7367169689Skan  arg0 = TREE_VALUE (arglist);
7368169689Skan  arg1 = TREE_VALUE (TREE_CHAIN (arglist));
7369169689Skan  arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
7370169689Skan
7371169689Skan  tmode = TYPE_MODE (TREE_TYPE (arg0));
7372169689Skan  mode1 = TYPE_MODE (TREE_TYPE (TREE_TYPE (arg0)));
7373169689Skan  gcc_assert (VECTOR_MODE_P (tmode));
7374169689Skan
7375169689Skan  op0 = expand_expr (arg0, NULL_RTX, tmode, 0);
7376169689Skan  op1 = expand_expr (arg1, NULL_RTX, mode1, 0);
7377169689Skan  elt = get_element_number (TREE_TYPE (arg0), arg2);
7378169689Skan
7379169689Skan  if (GET_MODE (op1) != mode1 && GET_MODE (op1) != VOIDmode)
7380169689Skan    op1 = convert_modes (mode1, GET_MODE (op1), op1, true);
7381169689Skan
7382169689Skan  op0 = force_reg (tmode, op0);
7383169689Skan  op1 = force_reg (mode1, op1);
7384169689Skan
7385169689Skan  rs6000_expand_vector_set (op0, op1, elt);
7386169689Skan
7387169689Skan  return op0;
7388169689Skan}
7389169689Skan
7390169689Skan/* Expand vec_ext builtin.  */
7391169689Skanstatic rtx
7392169689Skanaltivec_expand_vec_ext_builtin (tree arglist, rtx target)
7393169689Skan{
7394169689Skan  enum machine_mode tmode, mode0;
7395169689Skan  tree arg0, arg1;
7396169689Skan  int elt;
7397169689Skan  rtx op0;
7398169689Skan
7399169689Skan  arg0 = TREE_VALUE (arglist);
7400169689Skan  arg1 = TREE_VALUE (TREE_CHAIN (arglist));
7401169689Skan
7402169689Skan  op0 = expand_normal (arg0);
7403169689Skan  elt = get_element_number (TREE_TYPE (arg0), arg1);
7404169689Skan
7405169689Skan  tmode = TYPE_MODE (TREE_TYPE (TREE_TYPE (arg0)));
7406169689Skan  mode0 = TYPE_MODE (TREE_TYPE (arg0));
7407169689Skan  gcc_assert (VECTOR_MODE_P (mode0));
7408169689Skan
7409169689Skan  op0 = force_reg (mode0, op0);
7410169689Skan
7411169689Skan  if (optimize || !target || !register_operand (target, tmode))
7412169689Skan    target = gen_reg_rtx (tmode);
7413169689Skan
7414169689Skan  rs6000_expand_vector_extract (target, op0, elt);
7415169689Skan
7416169689Skan  return target;
7417169689Skan}
7418169689Skan
7419117395Skan/* Expand the builtin in EXP and store the result in TARGET.  Store
7420117395Skan   true in *EXPANDEDP if we found a builtin to expand.  */
7421117395Skanstatic rtx
7422132718Skanaltivec_expand_builtin (tree exp, rtx target, bool *expandedp)
7423117395Skan{
7424117395Skan  struct builtin_description *d;
7425117395Skan  struct builtin_description_predicates *dp;
7426117395Skan  size_t i;
7427117395Skan  enum insn_code icode;
7428117395Skan  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
7429117395Skan  tree arglist = TREE_OPERAND (exp, 1);
7430117395Skan  tree arg0;
7431117395Skan  rtx op0, pat;
7432117395Skan  enum machine_mode tmode, mode0;
7433117395Skan  unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
743490075Sobrien
7435169689Skan  if (fcode >= ALTIVEC_BUILTIN_OVERLOADED_FIRST
7436169689Skan      && fcode <= ALTIVEC_BUILTIN_OVERLOADED_LAST)
7437169689Skan    {
7438169689Skan      *expandedp = true;
7439169689Skan      error ("unresolved overload for Altivec builtin %qF", fndecl);
7440169689Skan      return const0_rtx;
7441169689Skan    }
7442169689Skan
7443117395Skan  target = altivec_expand_ld_builtin (exp, target, expandedp);
7444117395Skan  if (*expandedp)
7445117395Skan    return target;
744690075Sobrien
7447117395Skan  target = altivec_expand_st_builtin (exp, target, expandedp);
7448117395Skan  if (*expandedp)
7449117395Skan    return target;
745090075Sobrien
7451117395Skan  target = altivec_expand_dst_builtin (exp, target, expandedp);
7452117395Skan  if (*expandedp)
7453117395Skan    return target;
745490075Sobrien
7455117395Skan  *expandedp = true;
745690075Sobrien
7457117395Skan  switch (fcode)
7458117395Skan    {
745990075Sobrien    case ALTIVEC_BUILTIN_STVX:
746090075Sobrien      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvx, arglist);
746190075Sobrien    case ALTIVEC_BUILTIN_STVEBX:
746290075Sobrien      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvebx, arglist);
746390075Sobrien    case ALTIVEC_BUILTIN_STVEHX:
746490075Sobrien      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvehx, arglist);
746590075Sobrien    case ALTIVEC_BUILTIN_STVEWX:
746690075Sobrien      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvewx, arglist);
746790075Sobrien    case ALTIVEC_BUILTIN_STVXL:
746890075Sobrien      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvxl, arglist);
7469117395Skan
747090075Sobrien    case ALTIVEC_BUILTIN_MFVSCR:
747190075Sobrien      icode = CODE_FOR_altivec_mfvscr;
747290075Sobrien      tmode = insn_data[icode].operand[0].mode;
747390075Sobrien
747490075Sobrien      if (target == 0
747590075Sobrien	  || GET_MODE (target) != tmode
747690075Sobrien	  || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
747790075Sobrien	target = gen_reg_rtx (tmode);
7478169689Skan
747990075Sobrien      pat = GEN_FCN (icode) (target);
748090075Sobrien      if (! pat)
748190075Sobrien	return 0;
748290075Sobrien      emit_insn (pat);
748390075Sobrien      return target;
748490075Sobrien
748590075Sobrien    case ALTIVEC_BUILTIN_MTVSCR:
748690075Sobrien      icode = CODE_FOR_altivec_mtvscr;
748790075Sobrien      arg0 = TREE_VALUE (arglist);
7488169689Skan      op0 = expand_normal (arg0);
748990075Sobrien      mode0 = insn_data[icode].operand[0].mode;
749090075Sobrien
749190075Sobrien      /* If we got invalid arguments bail out before generating bad rtl.  */
749290075Sobrien      if (arg0 == error_mark_node)
7493117395Skan	return const0_rtx;
749490075Sobrien
749590075Sobrien      if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
749690075Sobrien	op0 = copy_to_mode_reg (mode0, op0);
749790075Sobrien
749890075Sobrien      pat = GEN_FCN (icode) (op0);
749990075Sobrien      if (pat)
750090075Sobrien	emit_insn (pat);
750190075Sobrien      return NULL_RTX;
7502117395Skan
750390075Sobrien    case ALTIVEC_BUILTIN_DSSALL:
750490075Sobrien      emit_insn (gen_altivec_dssall ());
750590075Sobrien      return NULL_RTX;
750690075Sobrien
750790075Sobrien    case ALTIVEC_BUILTIN_DSS:
750890075Sobrien      icode = CODE_FOR_altivec_dss;
750990075Sobrien      arg0 = TREE_VALUE (arglist);
7510146895Skan      STRIP_NOPS (arg0);
7511169689Skan      op0 = expand_normal (arg0);
751290075Sobrien      mode0 = insn_data[icode].operand[0].mode;
751390075Sobrien
751490075Sobrien      /* If we got invalid arguments bail out before generating bad rtl.  */
751590075Sobrien      if (arg0 == error_mark_node)
7516117395Skan	return const0_rtx;
751790075Sobrien
7518117395Skan      if (TREE_CODE (arg0) != INTEGER_CST
7519117395Skan	  || TREE_INT_CST_LOW (arg0) & ~0x3)
7520117395Skan	{
7521117395Skan	  error ("argument to dss must be a 2-bit unsigned literal");
7522117395Skan	  return const0_rtx;
7523117395Skan	}
7524117395Skan
752590075Sobrien      if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
752690075Sobrien	op0 = copy_to_mode_reg (mode0, op0);
752790075Sobrien
752890075Sobrien      emit_insn (gen_altivec_dss (op0));
752990075Sobrien      return NULL_RTX;
7530146895Skan
7531169689Skan    case ALTIVEC_BUILTIN_VEC_INIT_V4SI:
7532169689Skan    case ALTIVEC_BUILTIN_VEC_INIT_V8HI:
7533169689Skan    case ALTIVEC_BUILTIN_VEC_INIT_V16QI:
7534169689Skan    case ALTIVEC_BUILTIN_VEC_INIT_V4SF:
7535169689Skan      return altivec_expand_vec_init_builtin (TREE_TYPE (exp), arglist, target);
7536146895Skan
7537169689Skan    case ALTIVEC_BUILTIN_VEC_SET_V4SI:
7538169689Skan    case ALTIVEC_BUILTIN_VEC_SET_V8HI:
7539169689Skan    case ALTIVEC_BUILTIN_VEC_SET_V16QI:
7540169689Skan    case ALTIVEC_BUILTIN_VEC_SET_V4SF:
7541169689Skan      return altivec_expand_vec_set_builtin (arglist);
7542169689Skan
7543169689Skan    case ALTIVEC_BUILTIN_VEC_EXT_V4SI:
7544169689Skan    case ALTIVEC_BUILTIN_VEC_EXT_V8HI:
7545169689Skan    case ALTIVEC_BUILTIN_VEC_EXT_V16QI:
7546169689Skan    case ALTIVEC_BUILTIN_VEC_EXT_V4SF:
7547169689Skan      return altivec_expand_vec_ext_builtin (arglist, target);
7548169689Skan
7549169689Skan    default:
7550169689Skan      break;
7551169689Skan      /* Fall through.  */
755290075Sobrien    }
755390075Sobrien
755496263Sobrien  /* Expand abs* operations.  */
755596263Sobrien  d = (struct builtin_description *) bdesc_abs;
7556117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_abs); i++, d++)
755796263Sobrien    if (d->code == fcode)
755896263Sobrien      return altivec_expand_abs_builtin (d->icode, arglist, target);
755996263Sobrien
756096263Sobrien  /* Expand the AltiVec predicates.  */
756196263Sobrien  dp = (struct builtin_description_predicates *) bdesc_altivec_preds;
7562117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_altivec_preds); i++, dp++)
756396263Sobrien    if (dp->code == fcode)
7564169689Skan      return altivec_expand_predicate_builtin (dp->icode, dp->opcode,
7565169689Skan					       arglist, target);
756696263Sobrien
756790075Sobrien  /* LV* are funky.  We initialized them differently.  */
756890075Sobrien  switch (fcode)
756990075Sobrien    {
757090075Sobrien    case ALTIVEC_BUILTIN_LVSL:
7571132718Skan      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvsl,
7572169689Skan					arglist, target);
757390075Sobrien    case ALTIVEC_BUILTIN_LVSR:
7574132718Skan      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvsr,
7575169689Skan					arglist, target);
757690075Sobrien    case ALTIVEC_BUILTIN_LVEBX:
7577132718Skan      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvebx,
7578169689Skan					arglist, target);
757990075Sobrien    case ALTIVEC_BUILTIN_LVEHX:
7580132718Skan      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvehx,
7581169689Skan					arglist, target);
758290075Sobrien    case ALTIVEC_BUILTIN_LVEWX:
7583132718Skan      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvewx,
7584169689Skan					arglist, target);
758590075Sobrien    case ALTIVEC_BUILTIN_LVXL:
7586132718Skan      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvxl,
7587169689Skan					arglist, target);
758890075Sobrien    case ALTIVEC_BUILTIN_LVX:
7589132718Skan      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvx,
7590169689Skan					arglist, target);
759190075Sobrien    default:
759290075Sobrien      break;
759390075Sobrien      /* Fall through.  */
759490075Sobrien    }
759590075Sobrien
7596117395Skan  *expandedp = false;
7597117395Skan  return NULL_RTX;
7598117395Skan}
7599117395Skan
7600117395Skan/* Binops that need to be initialized manually, but can be expanded
7601117395Skan   automagically by rs6000_expand_binop_builtin.  */
7602117395Skanstatic struct builtin_description bdesc_2arg_spe[] =
7603117395Skan{
7604117395Skan  { 0, CODE_FOR_spe_evlddx, "__builtin_spe_evlddx", SPE_BUILTIN_EVLDDX },
7605117395Skan  { 0, CODE_FOR_spe_evldwx, "__builtin_spe_evldwx", SPE_BUILTIN_EVLDWX },
7606117395Skan  { 0, CODE_FOR_spe_evldhx, "__builtin_spe_evldhx", SPE_BUILTIN_EVLDHX },
7607117395Skan  { 0, CODE_FOR_spe_evlwhex, "__builtin_spe_evlwhex", SPE_BUILTIN_EVLWHEX },
7608117395Skan  { 0, CODE_FOR_spe_evlwhoux, "__builtin_spe_evlwhoux", SPE_BUILTIN_EVLWHOUX },
7609117395Skan  { 0, CODE_FOR_spe_evlwhosx, "__builtin_spe_evlwhosx", SPE_BUILTIN_EVLWHOSX },
7610117395Skan  { 0, CODE_FOR_spe_evlwwsplatx, "__builtin_spe_evlwwsplatx", SPE_BUILTIN_EVLWWSPLATX },
7611117395Skan  { 0, CODE_FOR_spe_evlwhsplatx, "__builtin_spe_evlwhsplatx", SPE_BUILTIN_EVLWHSPLATX },
7612117395Skan  { 0, CODE_FOR_spe_evlhhesplatx, "__builtin_spe_evlhhesplatx", SPE_BUILTIN_EVLHHESPLATX },
7613117395Skan  { 0, CODE_FOR_spe_evlhhousplatx, "__builtin_spe_evlhhousplatx", SPE_BUILTIN_EVLHHOUSPLATX },
7614117395Skan  { 0, CODE_FOR_spe_evlhhossplatx, "__builtin_spe_evlhhossplatx", SPE_BUILTIN_EVLHHOSSPLATX },
7615117395Skan  { 0, CODE_FOR_spe_evldd, "__builtin_spe_evldd", SPE_BUILTIN_EVLDD },
7616117395Skan  { 0, CODE_FOR_spe_evldw, "__builtin_spe_evldw", SPE_BUILTIN_EVLDW },
7617117395Skan  { 0, CODE_FOR_spe_evldh, "__builtin_spe_evldh", SPE_BUILTIN_EVLDH },
7618117395Skan  { 0, CODE_FOR_spe_evlwhe, "__builtin_spe_evlwhe", SPE_BUILTIN_EVLWHE },
7619117395Skan  { 0, CODE_FOR_spe_evlwhou, "__builtin_spe_evlwhou", SPE_BUILTIN_EVLWHOU },
7620117395Skan  { 0, CODE_FOR_spe_evlwhos, "__builtin_spe_evlwhos", SPE_BUILTIN_EVLWHOS },
7621117395Skan  { 0, CODE_FOR_spe_evlwwsplat, "__builtin_spe_evlwwsplat", SPE_BUILTIN_EVLWWSPLAT },
7622117395Skan  { 0, CODE_FOR_spe_evlwhsplat, "__builtin_spe_evlwhsplat", SPE_BUILTIN_EVLWHSPLAT },
7623117395Skan  { 0, CODE_FOR_spe_evlhhesplat, "__builtin_spe_evlhhesplat", SPE_BUILTIN_EVLHHESPLAT },
7624117395Skan  { 0, CODE_FOR_spe_evlhhousplat, "__builtin_spe_evlhhousplat", SPE_BUILTIN_EVLHHOUSPLAT },
7625117395Skan  { 0, CODE_FOR_spe_evlhhossplat, "__builtin_spe_evlhhossplat", SPE_BUILTIN_EVLHHOSSPLAT }
7626117395Skan};
7627117395Skan
7628117395Skan/* Expand the builtin in EXP and store the result in TARGET.  Store
7629117395Skan   true in *EXPANDEDP if we found a builtin to expand.
7630117395Skan
7631117395Skan   This expands the SPE builtins that are not simple unary and binary
7632117395Skan   operations.  */
7633117395Skanstatic rtx
7634132718Skanspe_expand_builtin (tree exp, rtx target, bool *expandedp)
7635117395Skan{
7636117395Skan  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
7637117395Skan  tree arglist = TREE_OPERAND (exp, 1);
7638117395Skan  tree arg1, arg0;
7639117395Skan  unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
7640117395Skan  enum insn_code icode;
7641117395Skan  enum machine_mode tmode, mode0;
7642117395Skan  rtx pat, op0;
7643117395Skan  struct builtin_description *d;
7644117395Skan  size_t i;
7645117395Skan
7646117395Skan  *expandedp = true;
7647117395Skan
7648117395Skan  /* Syntax check for a 5-bit unsigned immediate.  */
7649117395Skan  switch (fcode)
7650117395Skan    {
7651117395Skan    case SPE_BUILTIN_EVSTDD:
7652117395Skan    case SPE_BUILTIN_EVSTDH:
7653117395Skan    case SPE_BUILTIN_EVSTDW:
7654117395Skan    case SPE_BUILTIN_EVSTWHE:
7655117395Skan    case SPE_BUILTIN_EVSTWHO:
7656117395Skan    case SPE_BUILTIN_EVSTWWE:
7657117395Skan    case SPE_BUILTIN_EVSTWWO:
7658117395Skan      arg1 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
7659117395Skan      if (TREE_CODE (arg1) != INTEGER_CST
7660117395Skan	  || TREE_INT_CST_LOW (arg1) & ~0x1f)
7661117395Skan	{
7662117395Skan	  error ("argument 2 must be a 5-bit unsigned literal");
7663117395Skan	  return const0_rtx;
7664117395Skan	}
7665117395Skan      break;
7666117395Skan    default:
7667117395Skan      break;
7668117395Skan    }
7669117395Skan
7670132718Skan  /* The evsplat*i instructions are not quite generic.  */
7671132718Skan  switch (fcode)
7672132718Skan    {
7673132718Skan    case SPE_BUILTIN_EVSPLATFI:
7674132718Skan      return rs6000_expand_unop_builtin (CODE_FOR_spe_evsplatfi,
7675132718Skan					 arglist, target);
7676132718Skan    case SPE_BUILTIN_EVSPLATI:
7677132718Skan      return rs6000_expand_unop_builtin (CODE_FOR_spe_evsplati,
7678132718Skan					 arglist, target);
7679132718Skan    default:
7680132718Skan      break;
7681132718Skan    }
7682132718Skan
7683117395Skan  d = (struct builtin_description *) bdesc_2arg_spe;
7684117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_2arg_spe); ++i, ++d)
768590075Sobrien    if (d->code == fcode)
7686117395Skan      return rs6000_expand_binop_builtin (d->icode, arglist, target);
768790075Sobrien
7688117395Skan  d = (struct builtin_description *) bdesc_spe_predicates;
7689117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_spe_predicates); ++i, ++d)
7690117395Skan    if (d->code == fcode)
7691117395Skan      return spe_expand_predicate_builtin (d->icode, arglist, target);
7692117395Skan
7693117395Skan  d = (struct builtin_description *) bdesc_spe_evsel;
7694117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_spe_evsel); ++i, ++d)
7695117395Skan    if (d->code == fcode)
7696117395Skan      return spe_expand_evsel_builtin (d->icode, arglist, target);
7697117395Skan
7698117395Skan  switch (fcode)
7699117395Skan    {
7700117395Skan    case SPE_BUILTIN_EVSTDDX:
7701132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstddx, arglist);
7702117395Skan    case SPE_BUILTIN_EVSTDHX:
7703132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstdhx, arglist);
7704117395Skan    case SPE_BUILTIN_EVSTDWX:
7705132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstdwx, arglist);
7706117395Skan    case SPE_BUILTIN_EVSTWHEX:
7707132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstwhex, arglist);
7708117395Skan    case SPE_BUILTIN_EVSTWHOX:
7709132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstwhox, arglist);
7710117395Skan    case SPE_BUILTIN_EVSTWWEX:
7711132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstwwex, arglist);
7712117395Skan    case SPE_BUILTIN_EVSTWWOX:
7713132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstwwox, arglist);
7714117395Skan    case SPE_BUILTIN_EVSTDD:
7715132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstdd, arglist);
7716117395Skan    case SPE_BUILTIN_EVSTDH:
7717132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstdh, arglist);
7718117395Skan    case SPE_BUILTIN_EVSTDW:
7719132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstdw, arglist);
7720117395Skan    case SPE_BUILTIN_EVSTWHE:
7721132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstwhe, arglist);
7722117395Skan    case SPE_BUILTIN_EVSTWHO:
7723132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstwho, arglist);
7724117395Skan    case SPE_BUILTIN_EVSTWWE:
7725132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstwwe, arglist);
7726117395Skan    case SPE_BUILTIN_EVSTWWO:
7727132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstwwo, arglist);
7728117395Skan    case SPE_BUILTIN_MFSPEFSCR:
7729117395Skan      icode = CODE_FOR_spe_mfspefscr;
7730117395Skan      tmode = insn_data[icode].operand[0].mode;
7731117395Skan
7732117395Skan      if (target == 0
7733117395Skan	  || GET_MODE (target) != tmode
7734117395Skan	  || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
7735117395Skan	target = gen_reg_rtx (tmode);
7736169689Skan
7737117395Skan      pat = GEN_FCN (icode) (target);
7738117395Skan      if (! pat)
7739117395Skan	return 0;
7740117395Skan      emit_insn (pat);
7741117395Skan      return target;
7742117395Skan    case SPE_BUILTIN_MTSPEFSCR:
7743117395Skan      icode = CODE_FOR_spe_mtspefscr;
7744117395Skan      arg0 = TREE_VALUE (arglist);
7745169689Skan      op0 = expand_normal (arg0);
7746117395Skan      mode0 = insn_data[icode].operand[0].mode;
7747117395Skan
7748117395Skan      if (arg0 == error_mark_node)
7749117395Skan	return const0_rtx;
7750117395Skan
7751117395Skan      if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
7752117395Skan	op0 = copy_to_mode_reg (mode0, op0);
7753117395Skan
7754117395Skan      pat = GEN_FCN (icode) (op0);
7755117395Skan      if (pat)
7756117395Skan	emit_insn (pat);
7757117395Skan      return NULL_RTX;
7758117395Skan    default:
7759117395Skan      break;
7760117395Skan    }
7761117395Skan
7762117395Skan  *expandedp = false;
776390075Sobrien  return NULL_RTX;
776490075Sobrien}
776590075Sobrien
7766117395Skanstatic rtx
7767132718Skanspe_expand_predicate_builtin (enum insn_code icode, tree arglist, rtx target)
7768117395Skan{
7769117395Skan  rtx pat, scratch, tmp;
7770117395Skan  tree form = TREE_VALUE (arglist);
7771117395Skan  tree arg0 = TREE_VALUE (TREE_CHAIN (arglist));
7772117395Skan  tree arg1 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
7773169689Skan  rtx op0 = expand_normal (arg0);
7774169689Skan  rtx op1 = expand_normal (arg1);
7775117395Skan  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
7776117395Skan  enum machine_mode mode1 = insn_data[icode].operand[2].mode;
7777117395Skan  int form_int;
7778117395Skan  enum rtx_code code;
7779117395Skan
7780117395Skan  if (TREE_CODE (form) != INTEGER_CST)
7781117395Skan    {
7782117395Skan      error ("argument 1 of __builtin_spe_predicate must be a constant");
7783117395Skan      return const0_rtx;
7784117395Skan    }
7785117395Skan  else
7786117395Skan    form_int = TREE_INT_CST_LOW (form);
7787117395Skan
7788169689Skan  gcc_assert (mode0 == mode1);
7789117395Skan
7790117395Skan  if (arg0 == error_mark_node || arg1 == error_mark_node)
7791117395Skan    return const0_rtx;
7792117395Skan
7793117395Skan  if (target == 0
7794117395Skan      || GET_MODE (target) != SImode
7795117395Skan      || ! (*insn_data[icode].operand[0].predicate) (target, SImode))
7796117395Skan    target = gen_reg_rtx (SImode);
7797117395Skan
7798117395Skan  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
7799117395Skan    op0 = copy_to_mode_reg (mode0, op0);
7800117395Skan  if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
7801117395Skan    op1 = copy_to_mode_reg (mode1, op1);
7802117395Skan
7803117395Skan  scratch = gen_reg_rtx (CCmode);
7804117395Skan
7805117395Skan  pat = GEN_FCN (icode) (scratch, op0, op1);
7806117395Skan  if (! pat)
7807117395Skan    return const0_rtx;
7808117395Skan  emit_insn (pat);
7809117395Skan
7810117395Skan  /* There are 4 variants for each predicate: _any_, _all_, _upper_,
7811117395Skan     _lower_.  We use one compare, but look in different bits of the
7812117395Skan     CR for each variant.
7813117395Skan
7814117395Skan     There are 2 elements in each SPE simd type (upper/lower).  The CR
7815117395Skan     bits are set as follows:
7816117395Skan
7817117395Skan     BIT0  | BIT 1  | BIT 2   | BIT 3
7818117395Skan     U     |   L    | (U | L) | (U & L)
7819117395Skan
7820117395Skan     So, for an "all" relationship, BIT 3 would be set.
7821117395Skan     For an "any" relationship, BIT 2 would be set.  Etc.
7822117395Skan
7823117395Skan     Following traditional nomenclature, these bits map to:
7824117395Skan
7825117395Skan     BIT0  | BIT 1  | BIT 2   | BIT 3
7826117395Skan     LT    | GT     | EQ      | OV
7827117395Skan
7828117395Skan     Later, we will generate rtl to look in the LT/EQ/EQ/OV bits.
7829117395Skan  */
7830117395Skan
7831117395Skan  switch (form_int)
7832117395Skan    {
7833117395Skan      /* All variant.  OV bit.  */
7834117395Skan    case 0:
7835117395Skan      /* We need to get to the OV bit, which is the ORDERED bit.  We
7836117395Skan	 could generate (ordered:SI (reg:CC xx) (const_int 0)), but
7837169689Skan	 that's ugly and will make validate_condition_mode die.
7838117395Skan	 So let's just use another pattern.  */
7839117395Skan      emit_insn (gen_move_from_CR_ov_bit (target, scratch));
7840117395Skan      return target;
7841117395Skan      /* Any variant.  EQ bit.  */
7842117395Skan    case 1:
7843117395Skan      code = EQ;
7844117395Skan      break;
7845117395Skan      /* Upper variant.  LT bit.  */
7846117395Skan    case 2:
7847117395Skan      code = LT;
7848117395Skan      break;
7849117395Skan      /* Lower variant.  GT bit.  */
7850117395Skan    case 3:
7851117395Skan      code = GT;
7852117395Skan      break;
7853117395Skan    default:
7854117395Skan      error ("argument 1 of __builtin_spe_predicate is out of range");
7855117395Skan      return const0_rtx;
7856117395Skan    }
7857117395Skan
7858117395Skan  tmp = gen_rtx_fmt_ee (code, SImode, scratch, const0_rtx);
7859117395Skan  emit_move_insn (target, tmp);
7860117395Skan
7861117395Skan  return target;
7862117395Skan}
7863117395Skan
7864117395Skan/* The evsel builtins look like this:
7865117395Skan
7866117395Skan     e = __builtin_spe_evsel_OP (a, b, c, d);
7867117395Skan
7868117395Skan   and work like this:
7869117395Skan
7870117395Skan     e[upper] = a[upper] *OP* b[upper] ? c[upper] : d[upper];
7871117395Skan     e[lower] = a[lower] *OP* b[lower] ? c[lower] : d[lower];
7872117395Skan*/
7873117395Skan
7874117395Skanstatic rtx
7875132718Skanspe_expand_evsel_builtin (enum insn_code icode, tree arglist, rtx target)
7876117395Skan{
7877117395Skan  rtx pat, scratch;
7878117395Skan  tree arg0 = TREE_VALUE (arglist);
7879117395Skan  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
7880117395Skan  tree arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
7881117395Skan  tree arg3 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (arglist))));
7882169689Skan  rtx op0 = expand_normal (arg0);
7883169689Skan  rtx op1 = expand_normal (arg1);
7884169689Skan  rtx op2 = expand_normal (arg2);
7885169689Skan  rtx op3 = expand_normal (arg3);
7886117395Skan  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
7887117395Skan  enum machine_mode mode1 = insn_data[icode].operand[2].mode;
7888117395Skan
7889169689Skan  gcc_assert (mode0 == mode1);
7890117395Skan
7891117395Skan  if (arg0 == error_mark_node || arg1 == error_mark_node
7892117395Skan      || arg2 == error_mark_node || arg3 == error_mark_node)
7893117395Skan    return const0_rtx;
7894117395Skan
7895117395Skan  if (target == 0
7896117395Skan      || GET_MODE (target) != mode0
7897117395Skan      || ! (*insn_data[icode].operand[0].predicate) (target, mode0))
7898117395Skan    target = gen_reg_rtx (mode0);
7899117395Skan
7900117395Skan  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
7901117395Skan    op0 = copy_to_mode_reg (mode0, op0);
7902117395Skan  if (! (*insn_data[icode].operand[1].predicate) (op1, mode1))
7903117395Skan    op1 = copy_to_mode_reg (mode0, op1);
7904117395Skan  if (! (*insn_data[icode].operand[1].predicate) (op2, mode1))
7905117395Skan    op2 = copy_to_mode_reg (mode0, op2);
7906117395Skan  if (! (*insn_data[icode].operand[1].predicate) (op3, mode1))
7907117395Skan    op3 = copy_to_mode_reg (mode0, op3);
7908117395Skan
7909117395Skan  /* Generate the compare.  */
7910117395Skan  scratch = gen_reg_rtx (CCmode);
7911117395Skan  pat = GEN_FCN (icode) (scratch, op0, op1);
7912117395Skan  if (! pat)
7913117395Skan    return const0_rtx;
7914117395Skan  emit_insn (pat);
7915117395Skan
7916117395Skan  if (mode0 == V2SImode)
7917117395Skan    emit_insn (gen_spe_evsel (target, op2, op3, scratch));
7918117395Skan  else
7919117395Skan    emit_insn (gen_spe_evsel_fs (target, op2, op3, scratch));
7920117395Skan
7921117395Skan  return target;
7922117395Skan}
7923117395Skan
792490075Sobrien/* Expand an expression EXP that calls a built-in function,
792590075Sobrien   with result going to TARGET if that's convenient
792690075Sobrien   (and in mode MODE if that's convenient).
792790075Sobrien   SUBTARGET may be used as the target for computing one of EXP's operands.
792890075Sobrien   IGNORE is nonzero if the value is to be ignored.  */
792990075Sobrien
793090075Sobrienstatic rtx
7931132718Skanrs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
7932169689Skan		       enum machine_mode mode ATTRIBUTE_UNUSED,
7933169689Skan		       int ignore ATTRIBUTE_UNUSED)
793490075Sobrien{
7935117395Skan  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
7936117395Skan  tree arglist = TREE_OPERAND (exp, 1);
7937117395Skan  unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
7938117395Skan  struct builtin_description *d;
7939117395Skan  size_t i;
7940117395Skan  rtx ret;
7941117395Skan  bool success;
7942169689Skan
7943169689Skan  if (fcode == ALTIVEC_BUILTIN_MASK_FOR_LOAD
7944169689Skan      || fcode == ALTIVEC_BUILTIN_MASK_FOR_STORE)
7945169689Skan    {
7946169689Skan      int icode = (int) CODE_FOR_altivec_lvsr;
7947169689Skan      enum machine_mode tmode = insn_data[icode].operand[0].mode;
7948169689Skan      enum machine_mode mode = insn_data[icode].operand[1].mode;
7949169689Skan      tree arg;
7950169689Skan      rtx op, addr, pat;
7951169689Skan
7952169689Skan      gcc_assert (TARGET_ALTIVEC);
7953169689Skan
7954169689Skan      arg = TREE_VALUE (arglist);
7955169689Skan      gcc_assert (TREE_CODE (TREE_TYPE (arg)) == POINTER_TYPE);
7956169689Skan      op = expand_expr (arg, NULL_RTX, Pmode, EXPAND_NORMAL);
7957169689Skan      addr = memory_address (mode, op);
7958169689Skan      if (fcode == ALTIVEC_BUILTIN_MASK_FOR_STORE)
7959169689Skan	op = addr;
7960169689Skan      else
7961169689Skan	{
7962169689Skan	  /* For the load case need to negate the address.  */
7963169689Skan	  op = gen_reg_rtx (GET_MODE (addr));
7964169689Skan	  emit_insn (gen_rtx_SET (VOIDmode, op,
7965169689Skan			 gen_rtx_NEG (GET_MODE (addr), addr)));
7966169689Skan	}
7967169689Skan      op = gen_rtx_MEM (mode, op);
7968169689Skan
7969169689Skan      if (target == 0
7970169689Skan	  || GET_MODE (target) != tmode
7971169689Skan	  || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
7972169689Skan	target = gen_reg_rtx (tmode);
7973169689Skan
7974169689Skan      /*pat = gen_altivec_lvsr (target, op);*/
7975169689Skan      pat = GEN_FCN (icode) (target, op);
7976169689Skan      if (!pat)
7977169689Skan	return 0;
7978169689Skan      emit_insn (pat);
7979169689Skan
7980169689Skan      return target;
7981169689Skan    }
7982169689Skan
798390075Sobrien  if (TARGET_ALTIVEC)
7984117395Skan    {
7985117395Skan      ret = altivec_expand_builtin (exp, target, &success);
798690075Sobrien
7987117395Skan      if (success)
7988117395Skan	return ret;
7989117395Skan    }
7990117395Skan  if (TARGET_SPE)
7991117395Skan    {
7992117395Skan      ret = spe_expand_builtin (exp, target, &success);
7993117395Skan
7994117395Skan      if (success)
7995117395Skan	return ret;
7996117395Skan    }
7997117395Skan
7998169689Skan  gcc_assert (TARGET_ALTIVEC || TARGET_SPE);
7999117395Skan
8000169689Skan  /* Handle simple unary operations.  */
8001169689Skan  d = (struct builtin_description *) bdesc_1arg;
8002169689Skan  for (i = 0; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
8003169689Skan    if (d->code == fcode)
8004169689Skan      return rs6000_expand_unop_builtin (d->icode, arglist, target);
8005117395Skan
8006169689Skan  /* Handle simple binary operations.  */
8007169689Skan  d = (struct builtin_description *) bdesc_2arg;
8008169689Skan  for (i = 0; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
8009169689Skan    if (d->code == fcode)
8010169689Skan      return rs6000_expand_binop_builtin (d->icode, arglist, target);
8011117395Skan
8012169689Skan  /* Handle simple ternary operations.  */
8013169689Skan  d = (struct builtin_description *) bdesc_3arg;
8014169689Skan  for (i = 0; i < ARRAY_SIZE  (bdesc_3arg); i++, d++)
8015169689Skan    if (d->code == fcode)
8016169689Skan      return rs6000_expand_ternop_builtin (d->icode, arglist, target);
8017169689Skan
8018169689Skan  gcc_unreachable ();
801990075Sobrien}
802090075Sobrien
8021169689Skanstatic tree
8022169689Skanbuild_opaque_vector_type (tree node, int nunits)
8023169689Skan{
8024169689Skan  node = copy_node (node);
8025169689Skan  TYPE_MAIN_VARIANT (node) = node;
8026169689Skan  return build_vector_type (node, nunits);
8027169689Skan}
8028169689Skan
802990075Sobrienstatic void
8030132718Skanrs6000_init_builtins (void)
803190075Sobrien{
8032169689Skan  V2SI_type_node = build_vector_type (intSI_type_node, 2);
8033169689Skan  V2SF_type_node = build_vector_type (float_type_node, 2);
8034169689Skan  V4HI_type_node = build_vector_type (intHI_type_node, 4);
8035169689Skan  V4SI_type_node = build_vector_type (intSI_type_node, 4);
8036169689Skan  V4SF_type_node = build_vector_type (float_type_node, 4);
8037169689Skan  V8HI_type_node = build_vector_type (intHI_type_node, 8);
8038169689Skan  V16QI_type_node = build_vector_type (intQI_type_node, 16);
8039169689Skan
8040169689Skan  unsigned_V16QI_type_node = build_vector_type (unsigned_intQI_type_node, 16);
8041169689Skan  unsigned_V8HI_type_node = build_vector_type (unsigned_intHI_type_node, 8);
8042169689Skan  unsigned_V4SI_type_node = build_vector_type (unsigned_intSI_type_node, 4);
8043169689Skan
8044169689Skan  opaque_V2SF_type_node = build_opaque_vector_type (float_type_node, 2);
8045169689Skan  opaque_V2SI_type_node = build_opaque_vector_type (intSI_type_node, 2);
8046132718Skan  opaque_p_V2SI_type_node = build_pointer_type (opaque_V2SI_type_node);
8047169689Skan  opaque_V4SI_type_node = copy_node (V4SI_type_node);
8048132718Skan
8049146895Skan  /* The 'vector bool ...' types must be kept distinct from 'vector unsigned ...'
8050169689Skan     types, especially in C++ land.  Similarly, 'vector pixel' is distinct from
8051169689Skan     'vector unsigned short'.  */
8052146895Skan
8053169689Skan  bool_char_type_node = build_distinct_type_copy (unsigned_intQI_type_node);
8054169689Skan  bool_short_type_node = build_distinct_type_copy (unsigned_intHI_type_node);
8055169689Skan  bool_int_type_node = build_distinct_type_copy (unsigned_intSI_type_node);
8056169689Skan  pixel_type_node = build_distinct_type_copy (unsigned_intHI_type_node);
8057146895Skan
8058169689Skan  long_integer_type_internal_node = long_integer_type_node;
8059169689Skan  long_unsigned_type_internal_node = long_unsigned_type_node;
8060169689Skan  intQI_type_internal_node = intQI_type_node;
8061169689Skan  uintQI_type_internal_node = unsigned_intQI_type_node;
8062169689Skan  intHI_type_internal_node = intHI_type_node;
8063169689Skan  uintHI_type_internal_node = unsigned_intHI_type_node;
8064169689Skan  intSI_type_internal_node = intSI_type_node;
8065169689Skan  uintSI_type_internal_node = unsigned_intSI_type_node;
8066169689Skan  float_type_internal_node = float_type_node;
8067169689Skan  void_type_internal_node = void_type_node;
8068169689Skan
8069146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
8070146895Skan					    get_identifier ("__bool char"),
8071146895Skan					    bool_char_type_node));
8072146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
8073146895Skan					    get_identifier ("__bool short"),
8074146895Skan					    bool_short_type_node));
8075146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
8076146895Skan					    get_identifier ("__bool int"),
8077146895Skan					    bool_int_type_node));
8078146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
8079146895Skan					    get_identifier ("__pixel"),
8080146895Skan					    pixel_type_node));
8081146895Skan
8082169689Skan  bool_V16QI_type_node = build_vector_type (bool_char_type_node, 16);
8083169689Skan  bool_V8HI_type_node = build_vector_type (bool_short_type_node, 8);
8084169689Skan  bool_V4SI_type_node = build_vector_type (bool_int_type_node, 4);
8085169689Skan  pixel_V8HI_type_node = build_vector_type (pixel_type_node, 8);
8086146895Skan
8087146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
8088146895Skan					    get_identifier ("__vector unsigned char"),
8089146895Skan					    unsigned_V16QI_type_node));
8090146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
8091146895Skan					    get_identifier ("__vector signed char"),
8092146895Skan					    V16QI_type_node));
8093146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
8094146895Skan					    get_identifier ("__vector __bool char"),
8095146895Skan					    bool_V16QI_type_node));
8096146895Skan
8097146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
8098146895Skan					    get_identifier ("__vector unsigned short"),
8099146895Skan					    unsigned_V8HI_type_node));
8100146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
8101146895Skan					    get_identifier ("__vector signed short"),
8102146895Skan					    V8HI_type_node));
8103146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
8104146895Skan					    get_identifier ("__vector __bool short"),
8105146895Skan					    bool_V8HI_type_node));
8106146895Skan
8107146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
8108146895Skan					    get_identifier ("__vector unsigned int"),
8109146895Skan					    unsigned_V4SI_type_node));
8110146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
8111146895Skan					    get_identifier ("__vector signed int"),
8112146895Skan					    V4SI_type_node));
8113146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
8114146895Skan					    get_identifier ("__vector __bool int"),
8115146895Skan					    bool_V4SI_type_node));
8116146895Skan
8117146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
8118146895Skan					    get_identifier ("__vector float"),
8119146895Skan					    V4SF_type_node));
8120146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
8121146895Skan					    get_identifier ("__vector __pixel"),
8122146895Skan					    pixel_V8HI_type_node));
8123146895Skan
8124117395Skan  if (TARGET_SPE)
8125117395Skan    spe_init_builtins ();
812690075Sobrien  if (TARGET_ALTIVEC)
812790075Sobrien    altivec_init_builtins ();
8128117395Skan  if (TARGET_ALTIVEC || TARGET_SPE)
8129117395Skan    rs6000_common_init_builtins ();
8130169689Skan
8131169689Skan#if TARGET_XCOFF
8132169689Skan  /* AIX libm provides clog as __clog.  */
8133169689Skan  if (built_in_decls [BUILT_IN_CLOG])
8134169689Skan    set_user_assembler_name (built_in_decls [BUILT_IN_CLOG], "__clog");
8135169689Skan#endif
813690075Sobrien}
813790075Sobrien
8138117395Skan/* Search through a set of builtins and enable the mask bits.
8139117395Skan   DESC is an array of builtins.
8140132718Skan   SIZE is the total number of builtins.
8141117395Skan   START is the builtin enum at which to start.
8142117395Skan   END is the builtin enum at which to end.  */
814390075Sobrienstatic void
8144132718Skanenable_mask_for_builtins (struct builtin_description *desc, int size,
8145169689Skan			  enum rs6000_builtins start,
8146132718Skan			  enum rs6000_builtins end)
814790075Sobrien{
8148117395Skan  int i;
814990075Sobrien
8150117395Skan  for (i = 0; i < size; ++i)
8151117395Skan    if (desc[i].code == start)
8152117395Skan      break;
815390075Sobrien
8154117395Skan  if (i == size)
8155117395Skan    return;
815690075Sobrien
8157117395Skan  for (; i < size; ++i)
8158117395Skan    {
8159117395Skan      /* Flip all the bits on.  */
8160117395Skan      desc[i].mask = target_flags;
8161117395Skan      if (desc[i].code == end)
8162117395Skan	break;
8163117395Skan    }
8164117395Skan}
816590075Sobrien
8166117395Skanstatic void
8167132718Skanspe_init_builtins (void)
8168117395Skan{
8169117395Skan  tree endlink = void_list_node;
8170117395Skan  tree puint_type_node = build_pointer_type (unsigned_type_node);
8171117395Skan  tree pushort_type_node = build_pointer_type (short_unsigned_type_node);
8172117395Skan  struct builtin_description *d;
8173117395Skan  size_t i;
817490075Sobrien
8175117395Skan  tree v2si_ftype_4_v2si
8176117395Skan    = build_function_type
8177132718Skan    (opaque_V2SI_type_node,
8178132718Skan     tree_cons (NULL_TREE, opaque_V2SI_type_node,
8179132718Skan		tree_cons (NULL_TREE, opaque_V2SI_type_node,
8180132718Skan			   tree_cons (NULL_TREE, opaque_V2SI_type_node,
8181132718Skan				      tree_cons (NULL_TREE, opaque_V2SI_type_node,
8182117395Skan						 endlink)))));
818390075Sobrien
8184117395Skan  tree v2sf_ftype_4_v2sf
8185117395Skan    = build_function_type
8186132718Skan    (opaque_V2SF_type_node,
8187132718Skan     tree_cons (NULL_TREE, opaque_V2SF_type_node,
8188132718Skan		tree_cons (NULL_TREE, opaque_V2SF_type_node,
8189132718Skan			   tree_cons (NULL_TREE, opaque_V2SF_type_node,
8190132718Skan				      tree_cons (NULL_TREE, opaque_V2SF_type_node,
8191117395Skan						 endlink)))));
819290075Sobrien
8193117395Skan  tree int_ftype_int_v2si_v2si
8194117395Skan    = build_function_type
8195117395Skan    (integer_type_node,
8196117395Skan     tree_cons (NULL_TREE, integer_type_node,
8197132718Skan		tree_cons (NULL_TREE, opaque_V2SI_type_node,
8198132718Skan			   tree_cons (NULL_TREE, opaque_V2SI_type_node,
8199117395Skan				      endlink))));
820090075Sobrien
8201117395Skan  tree int_ftype_int_v2sf_v2sf
8202117395Skan    = build_function_type
8203117395Skan    (integer_type_node,
8204117395Skan     tree_cons (NULL_TREE, integer_type_node,
8205132718Skan		tree_cons (NULL_TREE, opaque_V2SF_type_node,
8206132718Skan			   tree_cons (NULL_TREE, opaque_V2SF_type_node,
8207117395Skan				      endlink))));
820890075Sobrien
8209117395Skan  tree void_ftype_v2si_puint_int
821090075Sobrien    = build_function_type (void_type_node,
8211132718Skan			   tree_cons (NULL_TREE, opaque_V2SI_type_node,
8212117395Skan				      tree_cons (NULL_TREE, puint_type_node,
821390075Sobrien						 tree_cons (NULL_TREE,
8214117395Skan							    integer_type_node,
821590075Sobrien							    endlink))));
821690075Sobrien
8217117395Skan  tree void_ftype_v2si_puint_char
821890075Sobrien    = build_function_type (void_type_node,
8219132718Skan			   tree_cons (NULL_TREE, opaque_V2SI_type_node,
8220117395Skan				      tree_cons (NULL_TREE, puint_type_node,
822190075Sobrien						 tree_cons (NULL_TREE,
8222117395Skan							    char_type_node,
822390075Sobrien							    endlink))));
822490075Sobrien
8225117395Skan  tree void_ftype_v2si_pv2si_int
822690075Sobrien    = build_function_type (void_type_node,
8227132718Skan			   tree_cons (NULL_TREE, opaque_V2SI_type_node,
8228132718Skan				      tree_cons (NULL_TREE, opaque_p_V2SI_type_node,
822990075Sobrien						 tree_cons (NULL_TREE,
8230117395Skan							    integer_type_node,
823190075Sobrien							    endlink))));
823290075Sobrien
8233117395Skan  tree void_ftype_v2si_pv2si_char
823490075Sobrien    = build_function_type (void_type_node,
8235132718Skan			   tree_cons (NULL_TREE, opaque_V2SI_type_node,
8236132718Skan				      tree_cons (NULL_TREE, opaque_p_V2SI_type_node,
823790075Sobrien						 tree_cons (NULL_TREE,
8238117395Skan							    char_type_node,
823990075Sobrien							    endlink))));
824090075Sobrien
8241117395Skan  tree void_ftype_int
824290075Sobrien    = build_function_type (void_type_node,
8243117395Skan			   tree_cons (NULL_TREE, integer_type_node, endlink));
824490075Sobrien
8245117395Skan  tree int_ftype_void
8246132718Skan    = build_function_type (integer_type_node, endlink);
824790075Sobrien
8248117395Skan  tree v2si_ftype_pv2si_int
8249132718Skan    = build_function_type (opaque_V2SI_type_node,
8250132718Skan			   tree_cons (NULL_TREE, opaque_p_V2SI_type_node,
8251117395Skan				      tree_cons (NULL_TREE, integer_type_node,
8252117395Skan						 endlink)));
8253117395Skan
8254117395Skan  tree v2si_ftype_puint_int
8255132718Skan    = build_function_type (opaque_V2SI_type_node,
8256117395Skan			   tree_cons (NULL_TREE, puint_type_node,
8257117395Skan				      tree_cons (NULL_TREE, integer_type_node,
8258117395Skan						 endlink)));
8259117395Skan
8260117395Skan  tree v2si_ftype_pushort_int
8261132718Skan    = build_function_type (opaque_V2SI_type_node,
8262117395Skan			   tree_cons (NULL_TREE, pushort_type_node,
8263117395Skan				      tree_cons (NULL_TREE, integer_type_node,
8264117395Skan						 endlink)));
8265117395Skan
8266132718Skan  tree v2si_ftype_signed_char
8267132718Skan    = build_function_type (opaque_V2SI_type_node,
8268132718Skan			   tree_cons (NULL_TREE, signed_char_type_node,
8269132718Skan				      endlink));
8270132718Skan
8271117395Skan  /* The initialization of the simple binary and unary builtins is
8272117395Skan     done in rs6000_common_init_builtins, but we have to enable the
8273117395Skan     mask bits here manually because we have run out of `target_flags'
8274117395Skan     bits.  We really need to redesign this mask business.  */
8275117395Skan
8276117395Skan  enable_mask_for_builtins ((struct builtin_description *) bdesc_2arg,
8277117395Skan			    ARRAY_SIZE (bdesc_2arg),
8278117395Skan			    SPE_BUILTIN_EVADDW,
8279117395Skan			    SPE_BUILTIN_EVXOR);
8280117395Skan  enable_mask_for_builtins ((struct builtin_description *) bdesc_1arg,
8281117395Skan			    ARRAY_SIZE (bdesc_1arg),
8282117395Skan			    SPE_BUILTIN_EVABS,
8283117395Skan			    SPE_BUILTIN_EVSUBFUSIAAW);
8284117395Skan  enable_mask_for_builtins ((struct builtin_description *) bdesc_spe_predicates,
8285117395Skan			    ARRAY_SIZE (bdesc_spe_predicates),
8286117395Skan			    SPE_BUILTIN_EVCMPEQ,
8287117395Skan			    SPE_BUILTIN_EVFSTSTLT);
8288117395Skan  enable_mask_for_builtins ((struct builtin_description *) bdesc_spe_evsel,
8289117395Skan			    ARRAY_SIZE (bdesc_spe_evsel),
8290117395Skan			    SPE_BUILTIN_EVSEL_CMPGTS,
8291117395Skan			    SPE_BUILTIN_EVSEL_FSTSTEQ);
8292117395Skan
8293132718Skan  (*lang_hooks.decls.pushdecl)
8294132718Skan    (build_decl (TYPE_DECL, get_identifier ("__ev64_opaque__"),
8295132718Skan		 opaque_V2SI_type_node));
8296132718Skan
8297117395Skan  /* Initialize irregular SPE builtins.  */
8298169689Skan
8299117395Skan  def_builtin (target_flags, "__builtin_spe_mtspefscr", void_ftype_int, SPE_BUILTIN_MTSPEFSCR);
8300117395Skan  def_builtin (target_flags, "__builtin_spe_mfspefscr", int_ftype_void, SPE_BUILTIN_MFSPEFSCR);
8301117395Skan  def_builtin (target_flags, "__builtin_spe_evstddx", void_ftype_v2si_pv2si_int, SPE_BUILTIN_EVSTDDX);
8302117395Skan  def_builtin (target_flags, "__builtin_spe_evstdhx", void_ftype_v2si_pv2si_int, SPE_BUILTIN_EVSTDHX);
8303117395Skan  def_builtin (target_flags, "__builtin_spe_evstdwx", void_ftype_v2si_pv2si_int, SPE_BUILTIN_EVSTDWX);
8304117395Skan  def_builtin (target_flags, "__builtin_spe_evstwhex", void_ftype_v2si_puint_int, SPE_BUILTIN_EVSTWHEX);
8305117395Skan  def_builtin (target_flags, "__builtin_spe_evstwhox", void_ftype_v2si_puint_int, SPE_BUILTIN_EVSTWHOX);
8306117395Skan  def_builtin (target_flags, "__builtin_spe_evstwwex", void_ftype_v2si_puint_int, SPE_BUILTIN_EVSTWWEX);
8307117395Skan  def_builtin (target_flags, "__builtin_spe_evstwwox", void_ftype_v2si_puint_int, SPE_BUILTIN_EVSTWWOX);
8308117395Skan  def_builtin (target_flags, "__builtin_spe_evstdd", void_ftype_v2si_pv2si_char, SPE_BUILTIN_EVSTDD);
8309117395Skan  def_builtin (target_flags, "__builtin_spe_evstdh", void_ftype_v2si_pv2si_char, SPE_BUILTIN_EVSTDH);
8310117395Skan  def_builtin (target_flags, "__builtin_spe_evstdw", void_ftype_v2si_pv2si_char, SPE_BUILTIN_EVSTDW);
8311117395Skan  def_builtin (target_flags, "__builtin_spe_evstwhe", void_ftype_v2si_puint_char, SPE_BUILTIN_EVSTWHE);
8312117395Skan  def_builtin (target_flags, "__builtin_spe_evstwho", void_ftype_v2si_puint_char, SPE_BUILTIN_EVSTWHO);
8313117395Skan  def_builtin (target_flags, "__builtin_spe_evstwwe", void_ftype_v2si_puint_char, SPE_BUILTIN_EVSTWWE);
8314117395Skan  def_builtin (target_flags, "__builtin_spe_evstwwo", void_ftype_v2si_puint_char, SPE_BUILTIN_EVSTWWO);
8315132718Skan  def_builtin (target_flags, "__builtin_spe_evsplatfi", v2si_ftype_signed_char, SPE_BUILTIN_EVSPLATFI);
8316132718Skan  def_builtin (target_flags, "__builtin_spe_evsplati", v2si_ftype_signed_char, SPE_BUILTIN_EVSPLATI);
8317117395Skan
8318117395Skan  /* Loads.  */
8319117395Skan  def_builtin (target_flags, "__builtin_spe_evlddx", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDDX);
8320117395Skan  def_builtin (target_flags, "__builtin_spe_evldwx", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDWX);
8321117395Skan  def_builtin (target_flags, "__builtin_spe_evldhx", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDHX);
8322117395Skan  def_builtin (target_flags, "__builtin_spe_evlwhex", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHEX);
8323117395Skan  def_builtin (target_flags, "__builtin_spe_evlwhoux", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHOUX);
8324117395Skan  def_builtin (target_flags, "__builtin_spe_evlwhosx", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHOSX);
8325117395Skan  def_builtin (target_flags, "__builtin_spe_evlwwsplatx", v2si_ftype_puint_int, SPE_BUILTIN_EVLWWSPLATX);
8326117395Skan  def_builtin (target_flags, "__builtin_spe_evlwhsplatx", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHSPLATX);
8327117395Skan  def_builtin (target_flags, "__builtin_spe_evlhhesplatx", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHESPLATX);
8328117395Skan  def_builtin (target_flags, "__builtin_spe_evlhhousplatx", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHOUSPLATX);
8329117395Skan  def_builtin (target_flags, "__builtin_spe_evlhhossplatx", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHOSSPLATX);
8330117395Skan  def_builtin (target_flags, "__builtin_spe_evldd", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDD);
8331117395Skan  def_builtin (target_flags, "__builtin_spe_evldw", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDW);
8332117395Skan  def_builtin (target_flags, "__builtin_spe_evldh", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDH);
8333117395Skan  def_builtin (target_flags, "__builtin_spe_evlhhesplat", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHESPLAT);
8334117395Skan  def_builtin (target_flags, "__builtin_spe_evlhhossplat", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHOSSPLAT);
8335117395Skan  def_builtin (target_flags, "__builtin_spe_evlhhousplat", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHOUSPLAT);
8336117395Skan  def_builtin (target_flags, "__builtin_spe_evlwhe", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHE);
8337117395Skan  def_builtin (target_flags, "__builtin_spe_evlwhos", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHOS);
8338117395Skan  def_builtin (target_flags, "__builtin_spe_evlwhou", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHOU);
8339117395Skan  def_builtin (target_flags, "__builtin_spe_evlwhsplat", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHSPLAT);
8340117395Skan  def_builtin (target_flags, "__builtin_spe_evlwwsplat", v2si_ftype_puint_int, SPE_BUILTIN_EVLWWSPLAT);
8341117395Skan
8342117395Skan  /* Predicates.  */
8343117395Skan  d = (struct builtin_description *) bdesc_spe_predicates;
8344117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_spe_predicates); ++i, d++)
8345117395Skan    {
8346117395Skan      tree type;
8347117395Skan
8348117395Skan      switch (insn_data[d->icode].operand[1].mode)
8349117395Skan	{
8350117395Skan	case V2SImode:
8351117395Skan	  type = int_ftype_int_v2si_v2si;
8352117395Skan	  break;
8353117395Skan	case V2SFmode:
8354117395Skan	  type = int_ftype_int_v2sf_v2sf;
8355117395Skan	  break;
8356117395Skan	default:
8357169689Skan	  gcc_unreachable ();
8358117395Skan	}
8359117395Skan
8360117395Skan      def_builtin (d->mask, d->name, type, d->code);
8361117395Skan    }
8362117395Skan
8363117395Skan  /* Evsel predicates.  */
8364117395Skan  d = (struct builtin_description *) bdesc_spe_evsel;
8365117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_spe_evsel); ++i, d++)
8366117395Skan    {
8367117395Skan      tree type;
8368117395Skan
8369117395Skan      switch (insn_data[d->icode].operand[1].mode)
8370117395Skan	{
8371117395Skan	case V2SImode:
8372117395Skan	  type = v2si_ftype_4_v2si;
8373117395Skan	  break;
8374117395Skan	case V2SFmode:
8375117395Skan	  type = v2sf_ftype_4_v2sf;
8376117395Skan	  break;
8377117395Skan	default:
8378169689Skan	  gcc_unreachable ();
8379117395Skan	}
8380117395Skan
8381117395Skan      def_builtin (d->mask, d->name, type, d->code);
8382117395Skan    }
8383117395Skan}
8384117395Skan
8385117395Skanstatic void
8386132718Skanaltivec_init_builtins (void)
8387117395Skan{
8388117395Skan  struct builtin_description *d;
8389117395Skan  struct builtin_description_predicates *dp;
8390117395Skan  size_t i;
8391169689Skan  tree ftype;
8392169689Skan
8393117395Skan  tree pfloat_type_node = build_pointer_type (float_type_node);
8394117395Skan  tree pint_type_node = build_pointer_type (integer_type_node);
8395117395Skan  tree pshort_type_node = build_pointer_type (short_integer_type_node);
8396117395Skan  tree pchar_type_node = build_pointer_type (char_type_node);
8397117395Skan
8398117395Skan  tree pvoid_type_node = build_pointer_type (void_type_node);
8399117395Skan
8400117395Skan  tree pcfloat_type_node = build_pointer_type (build_qualified_type (float_type_node, TYPE_QUAL_CONST));
8401117395Skan  tree pcint_type_node = build_pointer_type (build_qualified_type (integer_type_node, TYPE_QUAL_CONST));
8402117395Skan  tree pcshort_type_node = build_pointer_type (build_qualified_type (short_integer_type_node, TYPE_QUAL_CONST));
8403117395Skan  tree pcchar_type_node = build_pointer_type (build_qualified_type (char_type_node, TYPE_QUAL_CONST));
8404117395Skan
8405117395Skan  tree pcvoid_type_node = build_pointer_type (build_qualified_type (void_type_node, TYPE_QUAL_CONST));
8406117395Skan
8407169689Skan  tree int_ftype_opaque
8408169689Skan    = build_function_type_list (integer_type_node,
8409169689Skan				opaque_V4SI_type_node, NULL_TREE);
8410169689Skan
8411169689Skan  tree opaque_ftype_opaque_int
8412169689Skan    = build_function_type_list (opaque_V4SI_type_node,
8413169689Skan				opaque_V4SI_type_node, integer_type_node, NULL_TREE);
8414169689Skan  tree opaque_ftype_opaque_opaque_int
8415169689Skan    = build_function_type_list (opaque_V4SI_type_node,
8416169689Skan				opaque_V4SI_type_node, opaque_V4SI_type_node,
8417169689Skan				integer_type_node, NULL_TREE);
8418169689Skan  tree int_ftype_int_opaque_opaque
8419169689Skan    = build_function_type_list (integer_type_node,
8420169689Skan                                integer_type_node, opaque_V4SI_type_node,
8421169689Skan                                opaque_V4SI_type_node, NULL_TREE);
8422117395Skan  tree int_ftype_int_v4si_v4si
8423117395Skan    = build_function_type_list (integer_type_node,
8424117395Skan				integer_type_node, V4SI_type_node,
8425117395Skan				V4SI_type_node, NULL_TREE);
8426117395Skan  tree v4sf_ftype_pcfloat
8427117395Skan    = build_function_type_list (V4SF_type_node, pcfloat_type_node, NULL_TREE);
8428117395Skan  tree void_ftype_pfloat_v4sf
8429117395Skan    = build_function_type_list (void_type_node,
8430117395Skan				pfloat_type_node, V4SF_type_node, NULL_TREE);
8431117395Skan  tree v4si_ftype_pcint
8432117395Skan    = build_function_type_list (V4SI_type_node, pcint_type_node, NULL_TREE);
8433117395Skan  tree void_ftype_pint_v4si
8434117395Skan    = build_function_type_list (void_type_node,
8435117395Skan				pint_type_node, V4SI_type_node, NULL_TREE);
8436117395Skan  tree v8hi_ftype_pcshort
8437117395Skan    = build_function_type_list (V8HI_type_node, pcshort_type_node, NULL_TREE);
8438117395Skan  tree void_ftype_pshort_v8hi
8439117395Skan    = build_function_type_list (void_type_node,
8440117395Skan				pshort_type_node, V8HI_type_node, NULL_TREE);
8441117395Skan  tree v16qi_ftype_pcchar
8442117395Skan    = build_function_type_list (V16QI_type_node, pcchar_type_node, NULL_TREE);
8443117395Skan  tree void_ftype_pchar_v16qi
8444117395Skan    = build_function_type_list (void_type_node,
8445117395Skan				pchar_type_node, V16QI_type_node, NULL_TREE);
8446117395Skan  tree void_ftype_v4si
8447117395Skan    = build_function_type_list (void_type_node, V4SI_type_node, NULL_TREE);
844890075Sobrien  tree v8hi_ftype_void
844996263Sobrien    = build_function_type (V8HI_type_node, void_list_node);
8450117395Skan  tree void_ftype_void
8451117395Skan    = build_function_type (void_type_node, void_list_node);
8452146895Skan  tree void_ftype_int
8453146895Skan    = build_function_type_list (void_type_node, integer_type_node, NULL_TREE);
845490075Sobrien
8455169689Skan  tree opaque_ftype_long_pcvoid
8456169689Skan    = build_function_type_list (opaque_V4SI_type_node,
8457169689Skan				long_integer_type_node, pcvoid_type_node, NULL_TREE);
8458132718Skan  tree v16qi_ftype_long_pcvoid
8459117395Skan    = build_function_type_list (V16QI_type_node,
8460132718Skan				long_integer_type_node, pcvoid_type_node, NULL_TREE);
8461132718Skan  tree v8hi_ftype_long_pcvoid
8462117395Skan    = build_function_type_list (V8HI_type_node,
8463132718Skan				long_integer_type_node, pcvoid_type_node, NULL_TREE);
8464132718Skan  tree v4si_ftype_long_pcvoid
8465117395Skan    = build_function_type_list (V4SI_type_node,
8466132718Skan				long_integer_type_node, pcvoid_type_node, NULL_TREE);
846790075Sobrien
8468169689Skan  tree void_ftype_opaque_long_pvoid
8469169689Skan    = build_function_type_list (void_type_node,
8470169689Skan				opaque_V4SI_type_node, long_integer_type_node,
8471169689Skan				pvoid_type_node, NULL_TREE);
8472132718Skan  tree void_ftype_v4si_long_pvoid
8473117395Skan    = build_function_type_list (void_type_node,
8474132718Skan				V4SI_type_node, long_integer_type_node,
8475117395Skan				pvoid_type_node, NULL_TREE);
8476132718Skan  tree void_ftype_v16qi_long_pvoid
8477117395Skan    = build_function_type_list (void_type_node,
8478132718Skan				V16QI_type_node, long_integer_type_node,
8479117395Skan				pvoid_type_node, NULL_TREE);
8480132718Skan  tree void_ftype_v8hi_long_pvoid
8481117395Skan    = build_function_type_list (void_type_node,
8482132718Skan				V8HI_type_node, long_integer_type_node,
8483117395Skan				pvoid_type_node, NULL_TREE);
8484117395Skan  tree int_ftype_int_v8hi_v8hi
8485117395Skan    = build_function_type_list (integer_type_node,
8486117395Skan				integer_type_node, V8HI_type_node,
8487117395Skan				V8HI_type_node, NULL_TREE);
8488117395Skan  tree int_ftype_int_v16qi_v16qi
8489117395Skan    = build_function_type_list (integer_type_node,
8490117395Skan				integer_type_node, V16QI_type_node,
8491117395Skan				V16QI_type_node, NULL_TREE);
8492117395Skan  tree int_ftype_int_v4sf_v4sf
8493117395Skan    = build_function_type_list (integer_type_node,
8494117395Skan				integer_type_node, V4SF_type_node,
8495117395Skan				V4SF_type_node, NULL_TREE);
8496117395Skan  tree v4si_ftype_v4si
8497117395Skan    = build_function_type_list (V4SI_type_node, V4SI_type_node, NULL_TREE);
8498117395Skan  tree v8hi_ftype_v8hi
8499117395Skan    = build_function_type_list (V8HI_type_node, V8HI_type_node, NULL_TREE);
8500117395Skan  tree v16qi_ftype_v16qi
8501117395Skan    = build_function_type_list (V16QI_type_node, V16QI_type_node, NULL_TREE);
8502117395Skan  tree v4sf_ftype_v4sf
8503117395Skan    = build_function_type_list (V4SF_type_node, V4SF_type_node, NULL_TREE);
8504146895Skan  tree void_ftype_pcvoid_int_int
8505117395Skan    = build_function_type_list (void_type_node,
8506117395Skan				pcvoid_type_node, integer_type_node,
8507146895Skan				integer_type_node, NULL_TREE);
8508169689Skan
8509117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_4sf", v4sf_ftype_pcfloat,
8510117395Skan	       ALTIVEC_BUILTIN_LD_INTERNAL_4sf);
8511117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_4sf", void_ftype_pfloat_v4sf,
8512117395Skan	       ALTIVEC_BUILTIN_ST_INTERNAL_4sf);
8513117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_4si", v4si_ftype_pcint,
8514117395Skan	       ALTIVEC_BUILTIN_LD_INTERNAL_4si);
8515117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_4si", void_ftype_pint_v4si,
8516117395Skan	       ALTIVEC_BUILTIN_ST_INTERNAL_4si);
8517117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_8hi", v8hi_ftype_pcshort,
8518117395Skan	       ALTIVEC_BUILTIN_LD_INTERNAL_8hi);
8519117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_8hi", void_ftype_pshort_v8hi,
8520117395Skan	       ALTIVEC_BUILTIN_ST_INTERNAL_8hi);
8521117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_16qi", v16qi_ftype_pcchar,
8522117395Skan	       ALTIVEC_BUILTIN_LD_INTERNAL_16qi);
8523117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_16qi", void_ftype_pchar_v16qi,
8524117395Skan	       ALTIVEC_BUILTIN_ST_INTERNAL_16qi);
8525117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_mtvscr", void_ftype_v4si, ALTIVEC_BUILTIN_MTVSCR);
8526117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_mfvscr", v8hi_ftype_void, ALTIVEC_BUILTIN_MFVSCR);
8527117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_dssall", void_ftype_void, ALTIVEC_BUILTIN_DSSALL);
8528146895Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_dss", void_ftype_int, ALTIVEC_BUILTIN_DSS);
8529132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvsl", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVSL);
8530132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvsr", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVSR);
8531132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvebx", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVEBX);
8532132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvehx", v8hi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVEHX);
8533132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvewx", v4si_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVEWX);
8534132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvxl", v4si_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVXL);
8535132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvx", v4si_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVX);
8536132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvx", void_ftype_v4si_long_pvoid, ALTIVEC_BUILTIN_STVX);
8537132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvewx", void_ftype_v4si_long_pvoid, ALTIVEC_BUILTIN_STVEWX);
8538132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvxl", void_ftype_v4si_long_pvoid, ALTIVEC_BUILTIN_STVXL);
8539132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvebx", void_ftype_v16qi_long_pvoid, ALTIVEC_BUILTIN_STVEBX);
8540132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvehx", void_ftype_v8hi_long_pvoid, ALTIVEC_BUILTIN_STVEHX);
8541169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_ld", opaque_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LD);
8542169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_lde", opaque_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LDE);
8543169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_ldl", opaque_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LDL);
8544169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_lvsl", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVSL);
8545169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_lvsr", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVSR);
8546169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_lvebx", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVEBX);
8547169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_lvehx", v8hi_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVEHX);
8548169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_lvewx", v4si_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVEWX);
8549169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_st", void_ftype_opaque_long_pvoid, ALTIVEC_BUILTIN_VEC_ST);
8550169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_ste", void_ftype_opaque_long_pvoid, ALTIVEC_BUILTIN_VEC_STE);
8551169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_stl", void_ftype_opaque_long_pvoid, ALTIVEC_BUILTIN_VEC_STL);
8552169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_stvewx", void_ftype_opaque_long_pvoid, ALTIVEC_BUILTIN_VEC_STVEWX);
8553169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_stvebx", void_ftype_opaque_long_pvoid, ALTIVEC_BUILTIN_VEC_STVEBX);
8554169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_stvehx", void_ftype_opaque_long_pvoid, ALTIVEC_BUILTIN_VEC_STVEHX);
855590075Sobrien
8556169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_step", int_ftype_opaque, ALTIVEC_BUILTIN_VEC_STEP);
8557146895Skan
8558169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_sld", opaque_ftype_opaque_opaque_int, ALTIVEC_BUILTIN_VEC_SLD);
8559169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_splat", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_SPLAT);
8560169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_vspltw", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_VSPLTW);
8561169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_vsplth", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_VSPLTH);
8562169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_vspltb", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_VSPLTB);
8563169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_ctf", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_CTF);
8564169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_vcfsx", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_VCFSX);
8565169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_vcfux", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_VCFUX);
8566169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_cts", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_CTS);
8567169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_ctu", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_CTU);
8568169689Skan
8569117395Skan  /* Add the DST variants.  */
8570117395Skan  d = (struct builtin_description *) bdesc_dst;
8571117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_dst); i++, d++)
8572146895Skan    def_builtin (d->mask, d->name, void_ftype_pcvoid_int_int, d->code);
8573117395Skan
8574117395Skan  /* Initialize the predicates.  */
8575117395Skan  dp = (struct builtin_description_predicates *) bdesc_altivec_preds;
8576117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_altivec_preds); i++, dp++)
8577117395Skan    {
8578117395Skan      enum machine_mode mode1;
8579117395Skan      tree type;
8580169689Skan      bool is_overloaded = dp->code >= ALTIVEC_BUILTIN_OVERLOADED_FIRST
8581169689Skan			   && dp->code <= ALTIVEC_BUILTIN_OVERLOADED_LAST;
8582117395Skan
8583169689Skan      if (is_overloaded)
8584169689Skan	mode1 = VOIDmode;
8585169689Skan      else
8586169689Skan	mode1 = insn_data[dp->icode].operand[1].mode;
8587117395Skan
8588117395Skan      switch (mode1)
8589117395Skan	{
8590169689Skan	case VOIDmode:
8591169689Skan	  type = int_ftype_int_opaque_opaque;
8592169689Skan	  break;
8593117395Skan	case V4SImode:
8594117395Skan	  type = int_ftype_int_v4si_v4si;
8595117395Skan	  break;
8596117395Skan	case V8HImode:
8597117395Skan	  type = int_ftype_int_v8hi_v8hi;
8598117395Skan	  break;
8599117395Skan	case V16QImode:
8600117395Skan	  type = int_ftype_int_v16qi_v16qi;
8601117395Skan	  break;
8602117395Skan	case V4SFmode:
8603117395Skan	  type = int_ftype_int_v4sf_v4sf;
8604117395Skan	  break;
8605117395Skan	default:
8606169689Skan	  gcc_unreachable ();
8607117395Skan	}
8608169689Skan
8609117395Skan      def_builtin (dp->mask, dp->name, type, dp->code);
8610117395Skan    }
8611117395Skan
8612117395Skan  /* Initialize the abs* operators.  */
8613117395Skan  d = (struct builtin_description *) bdesc_abs;
8614117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_abs); i++, d++)
8615117395Skan    {
8616117395Skan      enum machine_mode mode0;
8617117395Skan      tree type;
8618117395Skan
8619117395Skan      mode0 = insn_data[d->icode].operand[0].mode;
8620117395Skan
8621117395Skan      switch (mode0)
8622117395Skan	{
8623117395Skan	case V4SImode:
8624117395Skan	  type = v4si_ftype_v4si;
8625117395Skan	  break;
8626117395Skan	case V8HImode:
8627117395Skan	  type = v8hi_ftype_v8hi;
8628117395Skan	  break;
8629117395Skan	case V16QImode:
8630117395Skan	  type = v16qi_ftype_v16qi;
8631117395Skan	  break;
8632117395Skan	case V4SFmode:
8633117395Skan	  type = v4sf_ftype_v4sf;
8634117395Skan	  break;
8635117395Skan	default:
8636169689Skan	  gcc_unreachable ();
8637117395Skan	}
8638169689Skan
8639117395Skan      def_builtin (d->mask, d->name, type, d->code);
8640117395Skan    }
8641169689Skan
8642169689Skan  if (TARGET_ALTIVEC)
8643169689Skan    {
8644169689Skan      tree decl;
8645169689Skan
8646169689Skan      /* Initialize target builtin that implements
8647169689Skan         targetm.vectorize.builtin_mask_for_load.  */
8648169689Skan
8649169689Skan      decl = lang_hooks.builtin_function ("__builtin_altivec_mask_for_load",
8650169689Skan                               v16qi_ftype_long_pcvoid,
8651169689Skan                               ALTIVEC_BUILTIN_MASK_FOR_LOAD,
8652169689Skan                               BUILT_IN_MD, NULL,
8653169689Skan                               tree_cons (get_identifier ("const"),
8654169689Skan                                          NULL_TREE, NULL_TREE));
8655169689Skan      /* Record the decl. Will be used by rs6000_builtin_mask_for_load.  */
8656169689Skan      altivec_builtin_mask_for_load = decl;
8657169689Skan    }
8658169689Skan
8659169689Skan  /* Access to the vec_init patterns.  */
8660169689Skan  ftype = build_function_type_list (V4SI_type_node, integer_type_node,
8661169689Skan				    integer_type_node, integer_type_node,
8662169689Skan				    integer_type_node, NULL_TREE);
8663169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_init_v4si", ftype,
8664169689Skan	       ALTIVEC_BUILTIN_VEC_INIT_V4SI);
8665169689Skan
8666169689Skan  ftype = build_function_type_list (V8HI_type_node, short_integer_type_node,
8667169689Skan				    short_integer_type_node,
8668169689Skan				    short_integer_type_node,
8669169689Skan				    short_integer_type_node,
8670169689Skan				    short_integer_type_node,
8671169689Skan				    short_integer_type_node,
8672169689Skan				    short_integer_type_node,
8673169689Skan				    short_integer_type_node, NULL_TREE);
8674169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_init_v8hi", ftype,
8675169689Skan	       ALTIVEC_BUILTIN_VEC_INIT_V8HI);
8676169689Skan
8677169689Skan  ftype = build_function_type_list (V16QI_type_node, char_type_node,
8678169689Skan				    char_type_node, char_type_node,
8679169689Skan				    char_type_node, char_type_node,
8680169689Skan				    char_type_node, char_type_node,
8681169689Skan				    char_type_node, char_type_node,
8682169689Skan				    char_type_node, char_type_node,
8683169689Skan				    char_type_node, char_type_node,
8684169689Skan				    char_type_node, char_type_node,
8685169689Skan				    char_type_node, NULL_TREE);
8686169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_init_v16qi", ftype,
8687169689Skan	       ALTIVEC_BUILTIN_VEC_INIT_V16QI);
8688169689Skan
8689169689Skan  ftype = build_function_type_list (V4SF_type_node, float_type_node,
8690169689Skan				    float_type_node, float_type_node,
8691169689Skan				    float_type_node, NULL_TREE);
8692169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_init_v4sf", ftype,
8693169689Skan	       ALTIVEC_BUILTIN_VEC_INIT_V4SF);
8694169689Skan
8695169689Skan  /* Access to the vec_set patterns.  */
8696169689Skan  ftype = build_function_type_list (V4SI_type_node, V4SI_type_node,
8697169689Skan				    intSI_type_node,
8698169689Skan				    integer_type_node, NULL_TREE);
8699169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_set_v4si", ftype,
8700169689Skan	       ALTIVEC_BUILTIN_VEC_SET_V4SI);
8701169689Skan
8702169689Skan  ftype = build_function_type_list (V8HI_type_node, V8HI_type_node,
8703169689Skan				    intHI_type_node,
8704169689Skan				    integer_type_node, NULL_TREE);
8705169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_set_v8hi", ftype,
8706169689Skan	       ALTIVEC_BUILTIN_VEC_SET_V8HI);
8707169689Skan
8708169689Skan  ftype = build_function_type_list (V8HI_type_node, V16QI_type_node,
8709169689Skan				    intQI_type_node,
8710169689Skan				    integer_type_node, NULL_TREE);
8711169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_set_v16qi", ftype,
8712169689Skan	       ALTIVEC_BUILTIN_VEC_SET_V16QI);
8713169689Skan
8714169689Skan  ftype = build_function_type_list (V4SF_type_node, V4SF_type_node,
8715169689Skan				    float_type_node,
8716169689Skan				    integer_type_node, NULL_TREE);
8717169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_set_v4sf", ftype,
8718169689Skan	       ALTIVEC_BUILTIN_VEC_SET_V4SF);
8719169689Skan
8720169689Skan  /* Access to the vec_extract patterns.  */
8721169689Skan  ftype = build_function_type_list (intSI_type_node, V4SI_type_node,
8722169689Skan				    integer_type_node, NULL_TREE);
8723169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_ext_v4si", ftype,
8724169689Skan	       ALTIVEC_BUILTIN_VEC_EXT_V4SI);
8725169689Skan
8726169689Skan  ftype = build_function_type_list (intHI_type_node, V8HI_type_node,
8727169689Skan				    integer_type_node, NULL_TREE);
8728169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_ext_v8hi", ftype,
8729169689Skan	       ALTIVEC_BUILTIN_VEC_EXT_V8HI);
8730169689Skan
8731169689Skan  ftype = build_function_type_list (intQI_type_node, V16QI_type_node,
8732169689Skan				    integer_type_node, NULL_TREE);
8733169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_ext_v16qi", ftype,
8734169689Skan	       ALTIVEC_BUILTIN_VEC_EXT_V16QI);
8735169689Skan
8736169689Skan  ftype = build_function_type_list (float_type_node, V4SF_type_node,
8737169689Skan				    integer_type_node, NULL_TREE);
8738169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_ext_v4sf", ftype,
8739169689Skan	       ALTIVEC_BUILTIN_VEC_EXT_V4SF);
8740117395Skan}
8741117395Skan
8742117395Skanstatic void
8743132718Skanrs6000_common_init_builtins (void)
8744117395Skan{
8745117395Skan  struct builtin_description *d;
8746117395Skan  size_t i;
8747117395Skan
8748117395Skan  tree v4sf_ftype_v4sf_v4sf_v16qi
8749117395Skan    = build_function_type_list (V4SF_type_node,
8750117395Skan				V4SF_type_node, V4SF_type_node,
8751117395Skan				V16QI_type_node, NULL_TREE);
8752117395Skan  tree v4si_ftype_v4si_v4si_v16qi
8753117395Skan    = build_function_type_list (V4SI_type_node,
8754117395Skan				V4SI_type_node, V4SI_type_node,
8755117395Skan				V16QI_type_node, NULL_TREE);
8756117395Skan  tree v8hi_ftype_v8hi_v8hi_v16qi
8757117395Skan    = build_function_type_list (V8HI_type_node,
8758117395Skan				V8HI_type_node, V8HI_type_node,
8759117395Skan				V16QI_type_node, NULL_TREE);
8760117395Skan  tree v16qi_ftype_v16qi_v16qi_v16qi
8761117395Skan    = build_function_type_list (V16QI_type_node,
8762117395Skan				V16QI_type_node, V16QI_type_node,
8763117395Skan				V16QI_type_node, NULL_TREE);
8764146895Skan  tree v4si_ftype_int
8765146895Skan    = build_function_type_list (V4SI_type_node, integer_type_node, NULL_TREE);
8766146895Skan  tree v8hi_ftype_int
8767146895Skan    = build_function_type_list (V8HI_type_node, integer_type_node, NULL_TREE);
8768146895Skan  tree v16qi_ftype_int
8769146895Skan    = build_function_type_list (V16QI_type_node, integer_type_node, NULL_TREE);
8770117395Skan  tree v8hi_ftype_v16qi
8771117395Skan    = build_function_type_list (V8HI_type_node, V16QI_type_node, NULL_TREE);
8772117395Skan  tree v4sf_ftype_v4sf
8773117395Skan    = build_function_type_list (V4SF_type_node, V4SF_type_node, NULL_TREE);
8774117395Skan
8775117395Skan  tree v2si_ftype_v2si_v2si
8776132718Skan    = build_function_type_list (opaque_V2SI_type_node,
8777132718Skan				opaque_V2SI_type_node,
8778132718Skan				opaque_V2SI_type_node, NULL_TREE);
8779117395Skan
8780117395Skan  tree v2sf_ftype_v2sf_v2sf
8781132718Skan    = build_function_type_list (opaque_V2SF_type_node,
8782132718Skan				opaque_V2SF_type_node,
8783132718Skan				opaque_V2SF_type_node, NULL_TREE);
8784117395Skan
8785117395Skan  tree v2si_ftype_int_int
8786132718Skan    = build_function_type_list (opaque_V2SI_type_node,
8787117395Skan				integer_type_node, integer_type_node,
8788117395Skan				NULL_TREE);
8789117395Skan
8790169689Skan  tree opaque_ftype_opaque
8791169689Skan    = build_function_type_list (opaque_V4SI_type_node,
8792169689Skan				opaque_V4SI_type_node, NULL_TREE);
8793169689Skan
8794117395Skan  tree v2si_ftype_v2si
8795132718Skan    = build_function_type_list (opaque_V2SI_type_node,
8796132718Skan				opaque_V2SI_type_node, NULL_TREE);
8797117395Skan
8798117395Skan  tree v2sf_ftype_v2sf
8799132718Skan    = build_function_type_list (opaque_V2SF_type_node,
8800132718Skan				opaque_V2SF_type_node, NULL_TREE);
8801169689Skan
8802117395Skan  tree v2sf_ftype_v2si
8803132718Skan    = build_function_type_list (opaque_V2SF_type_node,
8804132718Skan				opaque_V2SI_type_node, NULL_TREE);
8805117395Skan
8806117395Skan  tree v2si_ftype_v2sf
8807132718Skan    = build_function_type_list (opaque_V2SI_type_node,
8808132718Skan				opaque_V2SF_type_node, NULL_TREE);
8809117395Skan
8810117395Skan  tree v2si_ftype_v2si_char
8811132718Skan    = build_function_type_list (opaque_V2SI_type_node,
8812132718Skan				opaque_V2SI_type_node,
8813132718Skan				char_type_node, NULL_TREE);
8814117395Skan
8815117395Skan  tree v2si_ftype_int_char
8816132718Skan    = build_function_type_list (opaque_V2SI_type_node,
8817117395Skan				integer_type_node, char_type_node, NULL_TREE);
8818117395Skan
8819117395Skan  tree v2si_ftype_char
8820132718Skan    = build_function_type_list (opaque_V2SI_type_node,
8821132718Skan				char_type_node, NULL_TREE);
8822117395Skan
8823117395Skan  tree int_ftype_int_int
8824117395Skan    = build_function_type_list (integer_type_node,
8825117395Skan				integer_type_node, integer_type_node,
8826117395Skan				NULL_TREE);
8827117395Skan
8828169689Skan  tree opaque_ftype_opaque_opaque
8829169689Skan    = build_function_type_list (opaque_V4SI_type_node,
8830169689Skan                                opaque_V4SI_type_node, opaque_V4SI_type_node, NULL_TREE);
8831117395Skan  tree v4si_ftype_v4si_v4si
8832117395Skan    = build_function_type_list (V4SI_type_node,
8833117395Skan				V4SI_type_node, V4SI_type_node, NULL_TREE);
8834146895Skan  tree v4sf_ftype_v4si_int
8835117395Skan    = build_function_type_list (V4SF_type_node,
8836146895Skan				V4SI_type_node, integer_type_node, NULL_TREE);
8837146895Skan  tree v4si_ftype_v4sf_int
8838117395Skan    = build_function_type_list (V4SI_type_node,
8839146895Skan				V4SF_type_node, integer_type_node, NULL_TREE);
8840146895Skan  tree v4si_ftype_v4si_int
8841117395Skan    = build_function_type_list (V4SI_type_node,
8842146895Skan				V4SI_type_node, integer_type_node, NULL_TREE);
8843146895Skan  tree v8hi_ftype_v8hi_int
8844117395Skan    = build_function_type_list (V8HI_type_node,
8845146895Skan				V8HI_type_node, integer_type_node, NULL_TREE);
8846146895Skan  tree v16qi_ftype_v16qi_int
8847117395Skan    = build_function_type_list (V16QI_type_node,
8848146895Skan				V16QI_type_node, integer_type_node, NULL_TREE);
8849146895Skan  tree v16qi_ftype_v16qi_v16qi_int
8850117395Skan    = build_function_type_list (V16QI_type_node,
8851117395Skan				V16QI_type_node, V16QI_type_node,
8852146895Skan				integer_type_node, NULL_TREE);
8853146895Skan  tree v8hi_ftype_v8hi_v8hi_int
8854117395Skan    = build_function_type_list (V8HI_type_node,
8855117395Skan				V8HI_type_node, V8HI_type_node,
8856146895Skan				integer_type_node, NULL_TREE);
8857146895Skan  tree v4si_ftype_v4si_v4si_int
8858117395Skan    = build_function_type_list (V4SI_type_node,
8859117395Skan				V4SI_type_node, V4SI_type_node,
8860146895Skan				integer_type_node, NULL_TREE);
8861146895Skan  tree v4sf_ftype_v4sf_v4sf_int
8862117395Skan    = build_function_type_list (V4SF_type_node,
8863117395Skan				V4SF_type_node, V4SF_type_node,
8864146895Skan				integer_type_node, NULL_TREE);
886590075Sobrien  tree v4sf_ftype_v4sf_v4sf
8866117395Skan    = build_function_type_list (V4SF_type_node,
8867117395Skan				V4SF_type_node, V4SF_type_node, NULL_TREE);
8868169689Skan  tree opaque_ftype_opaque_opaque_opaque
8869169689Skan    = build_function_type_list (opaque_V4SI_type_node,
8870169689Skan                                opaque_V4SI_type_node, opaque_V4SI_type_node,
8871169689Skan                                opaque_V4SI_type_node, NULL_TREE);
887290075Sobrien  tree v4sf_ftype_v4sf_v4sf_v4si
8873117395Skan    = build_function_type_list (V4SF_type_node,
8874117395Skan				V4SF_type_node, V4SF_type_node,
8875117395Skan				V4SI_type_node, NULL_TREE);
887690075Sobrien  tree v4sf_ftype_v4sf_v4sf_v4sf
8877117395Skan    = build_function_type_list (V4SF_type_node,
8878117395Skan				V4SF_type_node, V4SF_type_node,
8879117395Skan				V4SF_type_node, NULL_TREE);
8880169689Skan  tree v4si_ftype_v4si_v4si_v4si
8881117395Skan    = build_function_type_list (V4SI_type_node,
8882117395Skan				V4SI_type_node, V4SI_type_node,
8883117395Skan				V4SI_type_node, NULL_TREE);
888490075Sobrien  tree v8hi_ftype_v8hi_v8hi
8885117395Skan    = build_function_type_list (V8HI_type_node,
8886117395Skan				V8HI_type_node, V8HI_type_node, NULL_TREE);
888790075Sobrien  tree v8hi_ftype_v8hi_v8hi_v8hi
8888117395Skan    = build_function_type_list (V8HI_type_node,
8889117395Skan				V8HI_type_node, V8HI_type_node,
8890117395Skan				V8HI_type_node, NULL_TREE);
8891169689Skan  tree v4si_ftype_v8hi_v8hi_v4si
8892117395Skan    = build_function_type_list (V4SI_type_node,
8893117395Skan				V8HI_type_node, V8HI_type_node,
8894117395Skan				V4SI_type_node, NULL_TREE);
8895169689Skan  tree v4si_ftype_v16qi_v16qi_v4si
8896117395Skan    = build_function_type_list (V4SI_type_node,
8897117395Skan				V16QI_type_node, V16QI_type_node,
8898117395Skan				V4SI_type_node, NULL_TREE);
889990075Sobrien  tree v16qi_ftype_v16qi_v16qi
8900117395Skan    = build_function_type_list (V16QI_type_node,
8901117395Skan				V16QI_type_node, V16QI_type_node, NULL_TREE);
890290075Sobrien  tree v4si_ftype_v4sf_v4sf
8903117395Skan    = build_function_type_list (V4SI_type_node,
8904117395Skan				V4SF_type_node, V4SF_type_node, NULL_TREE);
890590075Sobrien  tree v8hi_ftype_v16qi_v16qi
8906117395Skan    = build_function_type_list (V8HI_type_node,
8907117395Skan				V16QI_type_node, V16QI_type_node, NULL_TREE);
890890075Sobrien  tree v4si_ftype_v8hi_v8hi
8909117395Skan    = build_function_type_list (V4SI_type_node,
8910117395Skan				V8HI_type_node, V8HI_type_node, NULL_TREE);
891190075Sobrien  tree v8hi_ftype_v4si_v4si
8912117395Skan    = build_function_type_list (V8HI_type_node,
8913117395Skan				V4SI_type_node, V4SI_type_node, NULL_TREE);
891490075Sobrien  tree v16qi_ftype_v8hi_v8hi
8915117395Skan    = build_function_type_list (V16QI_type_node,
8916117395Skan				V8HI_type_node, V8HI_type_node, NULL_TREE);
891790075Sobrien  tree v4si_ftype_v16qi_v4si
8918117395Skan    = build_function_type_list (V4SI_type_node,
8919117395Skan				V16QI_type_node, V4SI_type_node, NULL_TREE);
892090075Sobrien  tree v4si_ftype_v16qi_v16qi
8921117395Skan    = build_function_type_list (V4SI_type_node,
8922117395Skan				V16QI_type_node, V16QI_type_node, NULL_TREE);
892390075Sobrien  tree v4si_ftype_v8hi_v4si
8924117395Skan    = build_function_type_list (V4SI_type_node,
8925117395Skan				V8HI_type_node, V4SI_type_node, NULL_TREE);
892690075Sobrien  tree v4si_ftype_v8hi
8927117395Skan    = build_function_type_list (V4SI_type_node, V8HI_type_node, NULL_TREE);
892890075Sobrien  tree int_ftype_v4si_v4si
8929117395Skan    = build_function_type_list (integer_type_node,
8930117395Skan				V4SI_type_node, V4SI_type_node, NULL_TREE);
893190075Sobrien  tree int_ftype_v4sf_v4sf
8932117395Skan    = build_function_type_list (integer_type_node,
8933117395Skan				V4SF_type_node, V4SF_type_node, NULL_TREE);
893490075Sobrien  tree int_ftype_v16qi_v16qi
8935117395Skan    = build_function_type_list (integer_type_node,
8936117395Skan				V16QI_type_node, V16QI_type_node, NULL_TREE);
893790075Sobrien  tree int_ftype_v8hi_v8hi
8938117395Skan    = build_function_type_list (integer_type_node,
8939117395Skan				V8HI_type_node, V8HI_type_node, NULL_TREE);
894090075Sobrien
894190075Sobrien  /* Add the simple ternary operators.  */
894290075Sobrien  d = (struct builtin_description *) bdesc_3arg;
8943117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_3arg); i++, d++)
894490075Sobrien    {
894590075Sobrien      enum machine_mode mode0, mode1, mode2, mode3;
894690075Sobrien      tree type;
8947169689Skan      bool is_overloaded = d->code >= ALTIVEC_BUILTIN_OVERLOADED_FIRST
8948169689Skan			   && d->code <= ALTIVEC_BUILTIN_OVERLOADED_LAST;
894990075Sobrien
8950169689Skan      if (is_overloaded)
8951169689Skan	{
8952169689Skan          mode0 = VOIDmode;
8953169689Skan          mode1 = VOIDmode;
8954169689Skan          mode2 = VOIDmode;
8955169689Skan          mode3 = VOIDmode;
8956169689Skan	}
8957169689Skan      else
8958169689Skan	{
8959169689Skan          if (d->name == 0 || d->icode == CODE_FOR_nothing)
8960169689Skan	    continue;
8961169689Skan
8962169689Skan          mode0 = insn_data[d->icode].operand[0].mode;
8963169689Skan          mode1 = insn_data[d->icode].operand[1].mode;
8964169689Skan          mode2 = insn_data[d->icode].operand[2].mode;
8965169689Skan          mode3 = insn_data[d->icode].operand[3].mode;
8966169689Skan	}
8967169689Skan
896890075Sobrien      /* When all four are of the same mode.  */
896990075Sobrien      if (mode0 == mode1 && mode1 == mode2 && mode2 == mode3)
897090075Sobrien	{
897190075Sobrien	  switch (mode0)
897290075Sobrien	    {
8973169689Skan	    case VOIDmode:
8974169689Skan	      type = opaque_ftype_opaque_opaque_opaque;
8975169689Skan	      break;
897690075Sobrien	    case V4SImode:
897790075Sobrien	      type = v4si_ftype_v4si_v4si_v4si;
897890075Sobrien	      break;
897990075Sobrien	    case V4SFmode:
898090075Sobrien	      type = v4sf_ftype_v4sf_v4sf_v4sf;
898190075Sobrien	      break;
898290075Sobrien	    case V8HImode:
898390075Sobrien	      type = v8hi_ftype_v8hi_v8hi_v8hi;
8984169689Skan	      break;
898590075Sobrien	    case V16QImode:
898690075Sobrien	      type = v16qi_ftype_v16qi_v16qi_v16qi;
8987169689Skan	      break;
898890075Sobrien	    default:
8989169689Skan	      gcc_unreachable ();
899090075Sobrien	    }
899190075Sobrien	}
899290075Sobrien      else if (mode0 == mode1 && mode1 == mode2 && mode3 == V16QImode)
8993169689Skan	{
899490075Sobrien	  switch (mode0)
899590075Sobrien	    {
899690075Sobrien	    case V4SImode:
899790075Sobrien	      type = v4si_ftype_v4si_v4si_v16qi;
899890075Sobrien	      break;
899990075Sobrien	    case V4SFmode:
900090075Sobrien	      type = v4sf_ftype_v4sf_v4sf_v16qi;
900190075Sobrien	      break;
900290075Sobrien	    case V8HImode:
900390075Sobrien	      type = v8hi_ftype_v8hi_v8hi_v16qi;
9004169689Skan	      break;
900590075Sobrien	    case V16QImode:
900690075Sobrien	      type = v16qi_ftype_v16qi_v16qi_v16qi;
9007169689Skan	      break;
900890075Sobrien	    default:
9009169689Skan	      gcc_unreachable ();
901090075Sobrien	    }
901190075Sobrien	}
9012169689Skan      else if (mode0 == V4SImode && mode1 == V16QImode && mode2 == V16QImode
901390075Sobrien	       && mode3 == V4SImode)
901490075Sobrien	type = v4si_ftype_v16qi_v16qi_v4si;
9015169689Skan      else if (mode0 == V4SImode && mode1 == V8HImode && mode2 == V8HImode
901690075Sobrien	       && mode3 == V4SImode)
901790075Sobrien	type = v4si_ftype_v8hi_v8hi_v4si;
9018169689Skan      else if (mode0 == V4SFmode && mode1 == V4SFmode && mode2 == V4SFmode
901990075Sobrien	       && mode3 == V4SImode)
902090075Sobrien	type = v4sf_ftype_v4sf_v4sf_v4si;
902190075Sobrien
902290075Sobrien      /* vchar, vchar, vchar, 4 bit literal.  */
902390075Sobrien      else if (mode0 == V16QImode && mode1 == mode0 && mode2 == mode0
902490075Sobrien	       && mode3 == QImode)
9025146895Skan	type = v16qi_ftype_v16qi_v16qi_int;
902690075Sobrien
902790075Sobrien      /* vshort, vshort, vshort, 4 bit literal.  */
902890075Sobrien      else if (mode0 == V8HImode && mode1 == mode0 && mode2 == mode0
902990075Sobrien	       && mode3 == QImode)
9030146895Skan	type = v8hi_ftype_v8hi_v8hi_int;
903190075Sobrien
903290075Sobrien      /* vint, vint, vint, 4 bit literal.  */
903390075Sobrien      else if (mode0 == V4SImode && mode1 == mode0 && mode2 == mode0
903490075Sobrien	       && mode3 == QImode)
9035146895Skan	type = v4si_ftype_v4si_v4si_int;
903690075Sobrien
903790075Sobrien      /* vfloat, vfloat, vfloat, 4 bit literal.  */
903890075Sobrien      else if (mode0 == V4SFmode && mode1 == mode0 && mode2 == mode0
903990075Sobrien	       && mode3 == QImode)
9040146895Skan	type = v4sf_ftype_v4sf_v4sf_int;
904190075Sobrien
904290075Sobrien      else
9043169689Skan	gcc_unreachable ();
904490075Sobrien
904590075Sobrien      def_builtin (d->mask, d->name, type, d->code);
904690075Sobrien    }
904790075Sobrien
904890075Sobrien  /* Add the simple binary operators.  */
904990075Sobrien  d = (struct builtin_description *) bdesc_2arg;
9050117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
905190075Sobrien    {
905290075Sobrien      enum machine_mode mode0, mode1, mode2;
905390075Sobrien      tree type;
9054169689Skan      bool is_overloaded = d->code >= ALTIVEC_BUILTIN_OVERLOADED_FIRST
9055169689Skan			   && d->code <= ALTIVEC_BUILTIN_OVERLOADED_LAST;
905690075Sobrien
9057169689Skan      if (is_overloaded)
9058169689Skan	{
9059169689Skan	  mode0 = VOIDmode;
9060169689Skan	  mode1 = VOIDmode;
9061169689Skan	  mode2 = VOIDmode;
9062169689Skan	}
9063169689Skan      else
9064169689Skan	{
9065169689Skan          if (d->name == 0 || d->icode == CODE_FOR_nothing)
9066169689Skan	    continue;
906790075Sobrien
9068169689Skan          mode0 = insn_data[d->icode].operand[0].mode;
9069169689Skan          mode1 = insn_data[d->icode].operand[1].mode;
9070169689Skan          mode2 = insn_data[d->icode].operand[2].mode;
9071169689Skan	}
9072169689Skan
907390075Sobrien      /* When all three operands are of the same mode.  */
907490075Sobrien      if (mode0 == mode1 && mode1 == mode2)
907590075Sobrien	{
907690075Sobrien	  switch (mode0)
907790075Sobrien	    {
9078169689Skan	    case VOIDmode:
9079169689Skan	      type = opaque_ftype_opaque_opaque;
9080169689Skan	      break;
908190075Sobrien	    case V4SFmode:
908290075Sobrien	      type = v4sf_ftype_v4sf_v4sf;
908390075Sobrien	      break;
908490075Sobrien	    case V4SImode:
908590075Sobrien	      type = v4si_ftype_v4si_v4si;
908690075Sobrien	      break;
908790075Sobrien	    case V16QImode:
908890075Sobrien	      type = v16qi_ftype_v16qi_v16qi;
908990075Sobrien	      break;
909090075Sobrien	    case V8HImode:
909190075Sobrien	      type = v8hi_ftype_v8hi_v8hi;
909290075Sobrien	      break;
9093117395Skan	    case V2SImode:
9094117395Skan	      type = v2si_ftype_v2si_v2si;
9095117395Skan	      break;
9096117395Skan	    case V2SFmode:
9097117395Skan	      type = v2sf_ftype_v2sf_v2sf;
9098117395Skan	      break;
9099117395Skan	    case SImode:
9100117395Skan	      type = int_ftype_int_int;
9101117395Skan	      break;
910290075Sobrien	    default:
9103169689Skan	      gcc_unreachable ();
910490075Sobrien	    }
910590075Sobrien	}
910690075Sobrien
910790075Sobrien      /* A few other combos we really don't want to do manually.  */
910890075Sobrien
910990075Sobrien      /* vint, vfloat, vfloat.  */
911090075Sobrien      else if (mode0 == V4SImode && mode1 == V4SFmode && mode2 == V4SFmode)
911190075Sobrien	type = v4si_ftype_v4sf_v4sf;
911290075Sobrien
911390075Sobrien      /* vshort, vchar, vchar.  */
911490075Sobrien      else if (mode0 == V8HImode && mode1 == V16QImode && mode2 == V16QImode)
911590075Sobrien	type = v8hi_ftype_v16qi_v16qi;
911690075Sobrien
911790075Sobrien      /* vint, vshort, vshort.  */
911890075Sobrien      else if (mode0 == V4SImode && mode1 == V8HImode && mode2 == V8HImode)
911990075Sobrien	type = v4si_ftype_v8hi_v8hi;
912090075Sobrien
912190075Sobrien      /* vshort, vint, vint.  */
912290075Sobrien      else if (mode0 == V8HImode && mode1 == V4SImode && mode2 == V4SImode)
912390075Sobrien	type = v8hi_ftype_v4si_v4si;
912490075Sobrien
912590075Sobrien      /* vchar, vshort, vshort.  */
912690075Sobrien      else if (mode0 == V16QImode && mode1 == V8HImode && mode2 == V8HImode)
912790075Sobrien	type = v16qi_ftype_v8hi_v8hi;
912890075Sobrien
912990075Sobrien      /* vint, vchar, vint.  */
913090075Sobrien      else if (mode0 == V4SImode && mode1 == V16QImode && mode2 == V4SImode)
913190075Sobrien	type = v4si_ftype_v16qi_v4si;
913290075Sobrien
913390075Sobrien      /* vint, vchar, vchar.  */
913490075Sobrien      else if (mode0 == V4SImode && mode1 == V16QImode && mode2 == V16QImode)
913590075Sobrien	type = v4si_ftype_v16qi_v16qi;
913690075Sobrien
913790075Sobrien      /* vint, vshort, vint.  */
913890075Sobrien      else if (mode0 == V4SImode && mode1 == V8HImode && mode2 == V4SImode)
913990075Sobrien	type = v4si_ftype_v8hi_v4si;
9140169689Skan
914190075Sobrien      /* vint, vint, 5 bit literal.  */
914290075Sobrien      else if (mode0 == V4SImode && mode1 == V4SImode && mode2 == QImode)
9143146895Skan	type = v4si_ftype_v4si_int;
9144169689Skan
914590075Sobrien      /* vshort, vshort, 5 bit literal.  */
914690075Sobrien      else if (mode0 == V8HImode && mode1 == V8HImode && mode2 == QImode)
9147146895Skan	type = v8hi_ftype_v8hi_int;
9148169689Skan
914990075Sobrien      /* vchar, vchar, 5 bit literal.  */
915090075Sobrien      else if (mode0 == V16QImode && mode1 == V16QImode && mode2 == QImode)
9151146895Skan	type = v16qi_ftype_v16qi_int;
915290075Sobrien
915390075Sobrien      /* vfloat, vint, 5 bit literal.  */
915490075Sobrien      else if (mode0 == V4SFmode && mode1 == V4SImode && mode2 == QImode)
9155146895Skan	type = v4sf_ftype_v4si_int;
9156169689Skan
915790075Sobrien      /* vint, vfloat, 5 bit literal.  */
915890075Sobrien      else if (mode0 == V4SImode && mode1 == V4SFmode && mode2 == QImode)
9159146895Skan	type = v4si_ftype_v4sf_int;
916090075Sobrien
9161117395Skan      else if (mode0 == V2SImode && mode1 == SImode && mode2 == SImode)
9162117395Skan	type = v2si_ftype_int_int;
9163117395Skan
9164117395Skan      else if (mode0 == V2SImode && mode1 == V2SImode && mode2 == QImode)
9165117395Skan	type = v2si_ftype_v2si_char;
9166117395Skan
9167117395Skan      else if (mode0 == V2SImode && mode1 == SImode && mode2 == QImode)
9168117395Skan	type = v2si_ftype_int_char;
9169117395Skan
9170169689Skan      else
917190075Sobrien	{
9172169689Skan	  /* int, x, x.  */
9173169689Skan	  gcc_assert (mode0 == SImode);
917490075Sobrien	  switch (mode1)
917590075Sobrien	    {
917690075Sobrien	    case V4SImode:
917790075Sobrien	      type = int_ftype_v4si_v4si;
917890075Sobrien	      break;
917990075Sobrien	    case V4SFmode:
918090075Sobrien	      type = int_ftype_v4sf_v4sf;
918190075Sobrien	      break;
918290075Sobrien	    case V16QImode:
918390075Sobrien	      type = int_ftype_v16qi_v16qi;
918490075Sobrien	      break;
918590075Sobrien	    case V8HImode:
918690075Sobrien	      type = int_ftype_v8hi_v8hi;
918790075Sobrien	      break;
918890075Sobrien	    default:
9189169689Skan	      gcc_unreachable ();
919090075Sobrien	    }
919190075Sobrien	}
919290075Sobrien
919390075Sobrien      def_builtin (d->mask, d->name, type, d->code);
919490075Sobrien    }
919590075Sobrien
919690075Sobrien  /* Add the simple unary operators.  */
919790075Sobrien  d = (struct builtin_description *) bdesc_1arg;
9198117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
919990075Sobrien    {
920090075Sobrien      enum machine_mode mode0, mode1;
920190075Sobrien      tree type;
9202169689Skan      bool is_overloaded = d->code >= ALTIVEC_BUILTIN_OVERLOADED_FIRST
9203169689Skan			   && d->code <= ALTIVEC_BUILTIN_OVERLOADED_LAST;
920490075Sobrien
9205169689Skan      if (is_overloaded)
9206169689Skan        {
9207169689Skan          mode0 = VOIDmode;
9208169689Skan          mode1 = VOIDmode;
9209169689Skan        }
9210169689Skan      else
9211169689Skan        {
9212169689Skan          if (d->name == 0 || d->icode == CODE_FOR_nothing)
9213169689Skan	    continue;
921490075Sobrien
9215169689Skan          mode0 = insn_data[d->icode].operand[0].mode;
9216169689Skan          mode1 = insn_data[d->icode].operand[1].mode;
9217169689Skan        }
9218169689Skan
921990075Sobrien      if (mode0 == V4SImode && mode1 == QImode)
9220169689Skan	type = v4si_ftype_int;
922190075Sobrien      else if (mode0 == V8HImode && mode1 == QImode)
9222169689Skan	type = v8hi_ftype_int;
922390075Sobrien      else if (mode0 == V16QImode && mode1 == QImode)
9224169689Skan	type = v16qi_ftype_int;
9225169689Skan      else if (mode0 == VOIDmode && mode1 == VOIDmode)
9226169689Skan	type = opaque_ftype_opaque;
922790075Sobrien      else if (mode0 == V4SFmode && mode1 == V4SFmode)
922890075Sobrien	type = v4sf_ftype_v4sf;
922990075Sobrien      else if (mode0 == V8HImode && mode1 == V16QImode)
923090075Sobrien	type = v8hi_ftype_v16qi;
923190075Sobrien      else if (mode0 == V4SImode && mode1 == V8HImode)
923290075Sobrien	type = v4si_ftype_v8hi;
9233117395Skan      else if (mode0 == V2SImode && mode1 == V2SImode)
9234117395Skan	type = v2si_ftype_v2si;
9235117395Skan      else if (mode0 == V2SFmode && mode1 == V2SFmode)
9236117395Skan	type = v2sf_ftype_v2sf;
9237117395Skan      else if (mode0 == V2SFmode && mode1 == V2SImode)
9238117395Skan	type = v2sf_ftype_v2si;
9239117395Skan      else if (mode0 == V2SImode && mode1 == V2SFmode)
9240117395Skan	type = v2si_ftype_v2sf;
9241117395Skan      else if (mode0 == V2SImode && mode1 == QImode)
9242117395Skan	type = v2si_ftype_char;
924390075Sobrien      else
9244169689Skan	gcc_unreachable ();
924590075Sobrien
924690075Sobrien      def_builtin (d->mask, d->name, type, d->code);
924790075Sobrien    }
924890075Sobrien}
924990075Sobrien
9250132718Skanstatic void
9251132718Skanrs6000_init_libfuncs (void)
9252132718Skan{
9253169689Skan  if (DEFAULT_ABI != ABI_V4 && TARGET_XCOFF
9254169689Skan      && !TARGET_POWER2 && !TARGET_POWERPC)
9255132718Skan    {
9256169689Skan      /* AIX library routines for float->int conversion.  */
9257169689Skan      set_conv_libfunc (sfix_optab, SImode, DFmode, "__itrunc");
9258169689Skan      set_conv_libfunc (ufix_optab, SImode, DFmode, "__uitrunc");
9259169689Skan      set_conv_libfunc (sfix_optab, SImode, TFmode, "_qitrunc");
9260169689Skan      set_conv_libfunc (ufix_optab, SImode, TFmode, "_quitrunc");
9261169689Skan    }
9262132718Skan
9263169689Skan  if (!TARGET_IEEEQUAD)
9264146895Skan      /* AIX/Darwin/64-bit Linux quad floating point routines.  */
9265169689Skan    if (!TARGET_XL_COMPAT)
9266169689Skan      {
9267169689Skan	set_optab_libfunc (add_optab, TFmode, "__gcc_qadd");
9268169689Skan	set_optab_libfunc (sub_optab, TFmode, "__gcc_qsub");
9269169689Skan	set_optab_libfunc (smul_optab, TFmode, "__gcc_qmul");
9270169689Skan	set_optab_libfunc (sdiv_optab, TFmode, "__gcc_qdiv");
9271169689Skan
9272169689Skan	if (TARGET_SOFT_FLOAT)
9273169689Skan	  {
9274169689Skan	    set_optab_libfunc (neg_optab, TFmode, "__gcc_qneg");
9275169689Skan	    set_optab_libfunc (eq_optab, TFmode, "__gcc_qeq");
9276169689Skan	    set_optab_libfunc (ne_optab, TFmode, "__gcc_qne");
9277169689Skan	    set_optab_libfunc (gt_optab, TFmode, "__gcc_qgt");
9278169689Skan	    set_optab_libfunc (ge_optab, TFmode, "__gcc_qge");
9279169689Skan	    set_optab_libfunc (lt_optab, TFmode, "__gcc_qlt");
9280169689Skan	    set_optab_libfunc (le_optab, TFmode, "__gcc_qle");
9281169689Skan	    set_optab_libfunc (unord_optab, TFmode, "__gcc_qunord");
9282169689Skan
9283169689Skan	    set_conv_libfunc (sext_optab, TFmode, SFmode, "__gcc_stoq");
9284169689Skan	    set_conv_libfunc (sext_optab, TFmode, DFmode, "__gcc_dtoq");
9285169689Skan	    set_conv_libfunc (trunc_optab, SFmode, TFmode, "__gcc_qtos");
9286169689Skan	    set_conv_libfunc (trunc_optab, DFmode, TFmode, "__gcc_qtod");
9287169689Skan	    set_conv_libfunc (sfix_optab, SImode, TFmode, "__gcc_qtoi");
9288169689Skan	    set_conv_libfunc (ufix_optab, SImode, TFmode, "__gcc_qtou");
9289169689Skan	    set_conv_libfunc (sfloat_optab, TFmode, SImode, "__gcc_itoq");
9290169689Skan	    set_conv_libfunc (ufloat_optab, TFmode, SImode, "__gcc_utoq");
9291169689Skan	  }
9292169689Skan      }
9293169689Skan    else
9294169689Skan      {
9295169689Skan	set_optab_libfunc (add_optab, TFmode, "_xlqadd");
9296169689Skan	set_optab_libfunc (sub_optab, TFmode, "_xlqsub");
9297169689Skan	set_optab_libfunc (smul_optab, TFmode, "_xlqmul");
9298169689Skan	set_optab_libfunc (sdiv_optab, TFmode, "_xlqdiv");
9299169689Skan      }
9300132718Skan  else
9301132718Skan    {
9302132718Skan      /* 32-bit SVR4 quad floating point routines.  */
9303132718Skan
9304132718Skan      set_optab_libfunc (add_optab, TFmode, "_q_add");
9305132718Skan      set_optab_libfunc (sub_optab, TFmode, "_q_sub");
9306132718Skan      set_optab_libfunc (neg_optab, TFmode, "_q_neg");
9307132718Skan      set_optab_libfunc (smul_optab, TFmode, "_q_mul");
9308132718Skan      set_optab_libfunc (sdiv_optab, TFmode, "_q_div");
9309132718Skan      if (TARGET_PPC_GPOPT || TARGET_POWER2)
9310132718Skan	set_optab_libfunc (sqrt_optab, TFmode, "_q_sqrt");
9311132718Skan
9312132718Skan      set_optab_libfunc (eq_optab, TFmode, "_q_feq");
9313132718Skan      set_optab_libfunc (ne_optab, TFmode, "_q_fne");
9314132718Skan      set_optab_libfunc (gt_optab, TFmode, "_q_fgt");
9315132718Skan      set_optab_libfunc (ge_optab, TFmode, "_q_fge");
9316132718Skan      set_optab_libfunc (lt_optab, TFmode, "_q_flt");
9317132718Skan      set_optab_libfunc (le_optab, TFmode, "_q_fle");
9318132718Skan
9319132718Skan      set_conv_libfunc (sext_optab, TFmode, SFmode, "_q_stoq");
9320132718Skan      set_conv_libfunc (sext_optab, TFmode, DFmode, "_q_dtoq");
9321132718Skan      set_conv_libfunc (trunc_optab, SFmode, TFmode, "_q_qtos");
9322132718Skan      set_conv_libfunc (trunc_optab, DFmode, TFmode, "_q_qtod");
9323132718Skan      set_conv_libfunc (sfix_optab, SImode, TFmode, "_q_qtoi");
9324132718Skan      set_conv_libfunc (ufix_optab, SImode, TFmode, "_q_qtou");
9325132718Skan      set_conv_libfunc (sfloat_optab, TFmode, SImode, "_q_itoq");
9326169689Skan      set_conv_libfunc (ufloat_optab, TFmode, SImode, "_q_utoq");
9327132718Skan    }
9328132718Skan}
9329169689Skan
933090075Sobrien
9331169689Skan/* Expand a block clear operation, and return 1 if successful.  Return 0
9332169689Skan   if we should let the compiler generate normal code.
9333169689Skan
9334169689Skan   operands[0] is the destination
9335169689Skan   operands[1] is the length
9336169689Skan   operands[3] is the alignment */
9337169689Skan
9338169689Skanint
9339169689Skanexpand_block_clear (rtx operands[])
9340169689Skan{
9341169689Skan  rtx orig_dest = operands[0];
9342169689Skan  rtx bytes_rtx	= operands[1];
9343169689Skan  rtx align_rtx = operands[3];
9344169689Skan  bool constp	= (GET_CODE (bytes_rtx) == CONST_INT);
9345169689Skan  HOST_WIDE_INT align;
9346169689Skan  HOST_WIDE_INT bytes;
9347169689Skan  int offset;
9348169689Skan  int clear_bytes;
9349169689Skan  int clear_step;
9350169689Skan
9351169689Skan  /* If this is not a fixed size move, just call memcpy */
9352169689Skan  if (! constp)
9353169689Skan    return 0;
9354169689Skan
9355169689Skan  /* This must be a fixed size alignment  */
9356169689Skan  gcc_assert (GET_CODE (align_rtx) == CONST_INT);
9357169689Skan  align = INTVAL (align_rtx) * BITS_PER_UNIT;
9358169689Skan
9359169689Skan  /* Anything to clear? */
9360169689Skan  bytes = INTVAL (bytes_rtx);
9361169689Skan  if (bytes <= 0)
9362169689Skan    return 1;
9363169689Skan
9364169689Skan  /* Use the builtin memset after a point, to avoid huge code bloat.
9365169689Skan     When optimize_size, avoid any significant code bloat; calling
9366169689Skan     memset is about 4 instructions, so allow for one instruction to
9367169689Skan     load zero and three to do clearing.  */
9368169689Skan  if (TARGET_ALTIVEC && align >= 128)
9369169689Skan    clear_step = 16;
9370169689Skan  else if (TARGET_POWERPC64 && align >= 32)
9371169689Skan    clear_step = 8;
9372169689Skan  else
9373169689Skan    clear_step = 4;
9374169689Skan
9375169689Skan  if (optimize_size && bytes > 3 * clear_step)
9376169689Skan    return 0;
9377169689Skan  if (! optimize_size && bytes > 8 * clear_step)
9378169689Skan    return 0;
9379169689Skan
9380169689Skan  for (offset = 0; bytes > 0; offset += clear_bytes, bytes -= clear_bytes)
9381169689Skan    {
9382169689Skan      enum machine_mode mode = BLKmode;
9383169689Skan      rtx dest;
9384169689Skan
9385169689Skan      if (bytes >= 16 && TARGET_ALTIVEC && align >= 128)
9386169689Skan	{
9387169689Skan	  clear_bytes = 16;
9388169689Skan	  mode = V4SImode;
9389169689Skan	}
9390169689Skan      else if (bytes >= 8 && TARGET_POWERPC64
9391169689Skan	  /* 64-bit loads and stores require word-aligned
9392169689Skan	     displacements.  */
9393169689Skan	  && (align >= 64 || (!STRICT_ALIGNMENT && align >= 32)))
9394169689Skan	{
9395169689Skan	  clear_bytes = 8;
9396169689Skan	  mode = DImode;
9397169689Skan	}
9398169689Skan      else if (bytes >= 4 && (align >= 32 || !STRICT_ALIGNMENT))
9399169689Skan	{			/* move 4 bytes */
9400169689Skan	  clear_bytes = 4;
9401169689Skan	  mode = SImode;
9402169689Skan	}
9403169689Skan      else if (bytes >= 2 && (align >= 16 || !STRICT_ALIGNMENT))
9404169689Skan	{			/* move 2 bytes */
9405169689Skan	  clear_bytes = 2;
9406169689Skan	  mode = HImode;
9407169689Skan	}
9408169689Skan      else /* move 1 byte at a time */
9409169689Skan	{
9410169689Skan	  clear_bytes = 1;
9411169689Skan	  mode = QImode;
9412169689Skan	}
9413169689Skan
9414169689Skan      dest = adjust_address (orig_dest, mode, offset);
9415169689Skan
9416169689Skan      emit_move_insn (dest, CONST0_RTX (mode));
9417169689Skan    }
9418169689Skan
9419169689Skan  return 1;
9420169689Skan}
9421169689Skan
9422169689Skan
942390075Sobrien/* Expand a block move operation, and return 1 if successful.  Return 0
942490075Sobrien   if we should let the compiler generate normal code.
942590075Sobrien
942690075Sobrien   operands[0] is the destination
942790075Sobrien   operands[1] is the source
942890075Sobrien   operands[2] is the length
942990075Sobrien   operands[3] is the alignment */
943090075Sobrien
943190075Sobrien#define MAX_MOVE_REG 4
943290075Sobrien
943390075Sobrienint
9434132718Skanexpand_block_move (rtx operands[])
943590075Sobrien{
943690075Sobrien  rtx orig_dest = operands[0];
943790075Sobrien  rtx orig_src	= operands[1];
943890075Sobrien  rtx bytes_rtx	= operands[2];
943990075Sobrien  rtx align_rtx = operands[3];
944090075Sobrien  int constp	= (GET_CODE (bytes_rtx) == CONST_INT);
944190075Sobrien  int align;
944290075Sobrien  int bytes;
944390075Sobrien  int offset;
944490075Sobrien  int move_bytes;
9445132718Skan  rtx stores[MAX_MOVE_REG];
9446132718Skan  int num_reg = 0;
944790075Sobrien
944890075Sobrien  /* If this is not a fixed size move, just call memcpy */
944990075Sobrien  if (! constp)
945090075Sobrien    return 0;
945190075Sobrien
9452169689Skan  /* This must be a fixed size alignment */
9453169689Skan  gcc_assert (GET_CODE (align_rtx) == CONST_INT);
9454169689Skan  align = INTVAL (align_rtx) * BITS_PER_UNIT;
945590075Sobrien
945690075Sobrien  /* Anything to move? */
945790075Sobrien  bytes = INTVAL (bytes_rtx);
945890075Sobrien  if (bytes <= 0)
945990075Sobrien    return 1;
946090075Sobrien
946190075Sobrien  /* store_one_arg depends on expand_block_move to handle at least the size of
9462169689Skan     reg_parm_stack_space.  */
946390075Sobrien  if (bytes > (TARGET_POWERPC64 ? 64 : 32))
946490075Sobrien    return 0;
946590075Sobrien
9466132718Skan  for (offset = 0; bytes > 0; offset += move_bytes, bytes -= move_bytes)
946790075Sobrien    {
9468132718Skan      union {
9469169689Skan	rtx (*movmemsi) (rtx, rtx, rtx, rtx);
9470132718Skan	rtx (*mov) (rtx, rtx);
9471132718Skan      } gen_func;
9472132718Skan      enum machine_mode mode = BLKmode;
9473132718Skan      rtx src, dest;
9474169689Skan
9475169689Skan      /* Altivec first, since it will be faster than a string move
9476169689Skan	 when it applies, and usually not significantly larger.  */
9477169689Skan      if (TARGET_ALTIVEC && bytes >= 16 && align >= 128)
9478169689Skan	{
9479169689Skan	  move_bytes = 16;
9480169689Skan	  mode = V4SImode;
9481169689Skan	  gen_func.mov = gen_movv4si;
9482169689Skan	}
9483169689Skan      else if (TARGET_STRING
9484132718Skan	  && bytes > 24		/* move up to 32 bytes at a time */
9485132718Skan	  && ! fixed_regs[5]
9486132718Skan	  && ! fixed_regs[6]
9487132718Skan	  && ! fixed_regs[7]
9488132718Skan	  && ! fixed_regs[8]
9489132718Skan	  && ! fixed_regs[9]
9490132718Skan	  && ! fixed_regs[10]
9491132718Skan	  && ! fixed_regs[11]
9492132718Skan	  && ! fixed_regs[12])
949390075Sobrien	{
9494132718Skan	  move_bytes = (bytes > 32) ? 32 : bytes;
9495169689Skan	  gen_func.movmemsi = gen_movmemsi_8reg;
9496132718Skan	}
9497132718Skan      else if (TARGET_STRING
9498132718Skan	       && bytes > 16	/* move up to 24 bytes at a time */
9499132718Skan	       && ! fixed_regs[5]
9500132718Skan	       && ! fixed_regs[6]
9501132718Skan	       && ! fixed_regs[7]
9502132718Skan	       && ! fixed_regs[8]
9503132718Skan	       && ! fixed_regs[9]
9504132718Skan	       && ! fixed_regs[10])
9505132718Skan	{
9506132718Skan	  move_bytes = (bytes > 24) ? 24 : bytes;
9507169689Skan	  gen_func.movmemsi = gen_movmemsi_6reg;
9508132718Skan	}
9509132718Skan      else if (TARGET_STRING
9510132718Skan	       && bytes > 8	/* move up to 16 bytes at a time */
9511132718Skan	       && ! fixed_regs[5]
9512132718Skan	       && ! fixed_regs[6]
9513132718Skan	       && ! fixed_regs[7]
9514132718Skan	       && ! fixed_regs[8])
9515132718Skan	{
9516132718Skan	  move_bytes = (bytes > 16) ? 16 : bytes;
9517169689Skan	  gen_func.movmemsi = gen_movmemsi_4reg;
9518132718Skan	}
9519132718Skan      else if (bytes >= 8 && TARGET_POWERPC64
9520132718Skan	       /* 64-bit loads and stores require word-aligned
9521132718Skan		  displacements.  */
9522169689Skan	       && (align >= 64 || (!STRICT_ALIGNMENT && align >= 32)))
9523132718Skan	{
9524132718Skan	  move_bytes = 8;
9525132718Skan	  mode = DImode;
9526132718Skan	  gen_func.mov = gen_movdi;
9527132718Skan	}
9528132718Skan      else if (TARGET_STRING && bytes > 4 && !TARGET_POWERPC64)
9529132718Skan	{			/* move up to 8 bytes at a time */
9530132718Skan	  move_bytes = (bytes > 8) ? 8 : bytes;
9531169689Skan	  gen_func.movmemsi = gen_movmemsi_2reg;
9532132718Skan	}
9533169689Skan      else if (bytes >= 4 && (align >= 32 || !STRICT_ALIGNMENT))
9534132718Skan	{			/* move 4 bytes */
9535132718Skan	  move_bytes = 4;
9536132718Skan	  mode = SImode;
9537132718Skan	  gen_func.mov = gen_movsi;
9538132718Skan	}
9539169689Skan      else if (bytes >= 2 && (align >= 16 || !STRICT_ALIGNMENT))
9540132718Skan	{			/* move 2 bytes */
9541132718Skan	  move_bytes = 2;
9542132718Skan	  mode = HImode;
9543132718Skan	  gen_func.mov = gen_movhi;
9544132718Skan	}
9545132718Skan      else if (TARGET_STRING && bytes > 1)
9546132718Skan	{			/* move up to 4 bytes at a time */
9547132718Skan	  move_bytes = (bytes > 4) ? 4 : bytes;
9548169689Skan	  gen_func.movmemsi = gen_movmemsi_1reg;
9549132718Skan	}
9550132718Skan      else /* move 1 byte at a time */
9551132718Skan	{
9552132718Skan	  move_bytes = 1;
9553132718Skan	  mode = QImode;
9554132718Skan	  gen_func.mov = gen_movqi;
9555132718Skan	}
9556169689Skan
9557132718Skan      src = adjust_address (orig_src, mode, offset);
9558132718Skan      dest = adjust_address (orig_dest, mode, offset);
9559169689Skan
9560169689Skan      if (mode != BLKmode)
9561132718Skan	{
9562132718Skan	  rtx tmp_reg = gen_reg_rtx (mode);
9563169689Skan
9564132718Skan	  emit_insn ((*gen_func.mov) (tmp_reg, src));
9565132718Skan	  stores[num_reg++] = (*gen_func.mov) (dest, tmp_reg);
9566132718Skan	}
9567103445Skan
9568132718Skan      if (mode == BLKmode || num_reg >= MAX_MOVE_REG || bytes == move_bytes)
9569132718Skan	{
9570132718Skan	  int i;
9571132718Skan	  for (i = 0; i < num_reg; i++)
9572132718Skan	    emit_insn (stores[i]);
9573132718Skan	  num_reg = 0;
957490075Sobrien	}
957590075Sobrien
9576132718Skan      if (mode == BLKmode)
957790075Sobrien	{
9578169689Skan	  /* Move the address into scratch registers.  The movmemsi
9579132718Skan	     patterns require zero offset.  */
9580132718Skan	  if (!REG_P (XEXP (src, 0)))
958190075Sobrien	    {
9582132718Skan	      rtx src_reg = copy_addr_to_reg (XEXP (src, 0));
9583132718Skan	      src = replace_equiv_address (src, src_reg);
958490075Sobrien	    }
9585132718Skan	  set_mem_size (src, GEN_INT (move_bytes));
9586169689Skan
9587132718Skan	  if (!REG_P (XEXP (dest, 0)))
958890075Sobrien	    {
9589132718Skan	      rtx dest_reg = copy_addr_to_reg (XEXP (dest, 0));
9590132718Skan	      dest = replace_equiv_address (dest, dest_reg);
959190075Sobrien	    }
9592132718Skan	  set_mem_size (dest, GEN_INT (move_bytes));
9593169689Skan
9594169689Skan	  emit_insn ((*gen_func.movmemsi) (dest, src,
9595132718Skan					   GEN_INT (move_bytes & 31),
9596132718Skan					   align_rtx));
959790075Sobrien	}
959890075Sobrien    }
959990075Sobrien
960090075Sobrien  return 1;
960190075Sobrien}
960290075Sobrien
960390075Sobrien
9604110611Skan/* Return a string to perform a load_multiple operation.
9605110611Skan   operands[0] is the vector.
9606110611Skan   operands[1] is the source address.
9607110611Skan   operands[2] is the first destination register.  */
9608110611Skan
9609110611Skanconst char *
9610132718Skanrs6000_output_load_multiple (rtx operands[3])
9611110611Skan{
9612110611Skan  /* We have to handle the case where the pseudo used to contain the address
9613110611Skan     is assigned to one of the output registers.  */
9614110611Skan  int i, j;
9615110611Skan  int words = XVECLEN (operands[0], 0);
9616110611Skan  rtx xop[10];
9617110611Skan
9618110611Skan  if (XVECLEN (operands[0], 0) == 1)
9619110611Skan    return "{l|lwz} %2,0(%1)";
9620110611Skan
9621110611Skan  for (i = 0; i < words; i++)
9622110611Skan    if (refers_to_regno_p (REGNO (operands[2]) + i,
9623110611Skan			   REGNO (operands[2]) + i + 1, operands[1], 0))
9624110611Skan      {
9625110611Skan	if (i == words-1)
9626110611Skan	  {
9627110611Skan	    xop[0] = GEN_INT (4 * (words-1));
9628110611Skan	    xop[1] = operands[1];
9629110611Skan	    xop[2] = operands[2];
9630110611Skan	    output_asm_insn ("{lsi|lswi} %2,%1,%0\n\t{l|lwz} %1,%0(%1)", xop);
9631110611Skan	    return "";
9632110611Skan	  }
9633110611Skan	else if (i == 0)
9634110611Skan	  {
9635110611Skan	    xop[0] = GEN_INT (4 * (words-1));
9636110611Skan	    xop[1] = operands[1];
9637110611Skan	    xop[2] = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
9638110611Skan	    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);
9639110611Skan	    return "";
9640110611Skan	  }
9641110611Skan	else
9642110611Skan	  {
9643110611Skan	    for (j = 0; j < words; j++)
9644110611Skan	      if (j != i)
9645110611Skan		{
9646110611Skan		  xop[0] = GEN_INT (j * 4);
9647110611Skan		  xop[1] = operands[1];
9648110611Skan		  xop[2] = gen_rtx_REG (SImode, REGNO (operands[2]) + j);
9649110611Skan		  output_asm_insn ("{l|lwz} %2,%0(%1)", xop);
9650110611Skan		}
9651110611Skan	    xop[0] = GEN_INT (i * 4);
9652110611Skan	    xop[1] = operands[1];
9653110611Skan	    output_asm_insn ("{l|lwz} %1,%0(%1)", xop);
9654110611Skan	    return "";
9655110611Skan	  }
9656110611Skan      }
9657110611Skan
9658110611Skan  return "{lsi|lswi} %2,%1,%N0";
9659110611Skan}
9660110611Skan
966190075Sobrien
966290075Sobrien/* A validation routine: say whether CODE, a condition code, and MODE
966390075Sobrien   match.  The other alternatives either don't make sense or should
966490075Sobrien   never be generated.  */
966590075Sobrien
9666169689Skanvoid
9667132718Skanvalidate_condition_mode (enum rtx_code code, enum machine_mode mode)
966890075Sobrien{
9669169689Skan  gcc_assert ((GET_RTX_CLASS (code) == RTX_COMPARE
9670169689Skan	       || GET_RTX_CLASS (code) == RTX_COMM_COMPARE)
9671169689Skan	      && GET_MODE_CLASS (mode) == MODE_CC);
967290075Sobrien
967390075Sobrien  /* These don't make sense.  */
9674169689Skan  gcc_assert ((code != GT && code != LT && code != GE && code != LE)
9675169689Skan	      || mode != CCUNSmode);
967690075Sobrien
9677169689Skan  gcc_assert ((code != GTU && code != LTU && code != GEU && code != LEU)
9678169689Skan	      || mode == CCUNSmode);
967990075Sobrien
9680169689Skan  gcc_assert (mode == CCFPmode
9681169689Skan	      || (code != ORDERED && code != UNORDERED
9682169689Skan		  && code != UNEQ && code != LTGT
9683169689Skan		  && code != UNGT && code != UNLT
9684169689Skan		  && code != UNGE && code != UNLE));
9685169689Skan
9686169689Skan  /* These should never be generated except for
9687132718Skan     flag_finite_math_only.  */
9688169689Skan  gcc_assert (mode != CCFPmode
9689169689Skan	      || flag_finite_math_only
9690169689Skan	      || (code != LE && code != GE
9691169689Skan		  && code != UNEQ && code != LTGT
9692169689Skan		  && code != UNGT && code != UNLT));
969390075Sobrien
969490075Sobrien  /* These are invalid; the information is not there.  */
9695169689Skan  gcc_assert (mode != CCEQmode || code == EQ || code == NE);
969690075Sobrien}
969790075Sobrien
969890075Sobrien
969990075Sobrien/* Return 1 if ANDOP is a mask that has no bits on that are not in the
970090075Sobrien   mask required to convert the result of a rotate insn into a shift
970196263Sobrien   left insn of SHIFTOP bits.  Both are known to be SImode CONST_INT.  */
970290075Sobrien
970390075Sobrienint
9704132718Skanincludes_lshift_p (rtx shiftop, rtx andop)
970590075Sobrien{
970690075Sobrien  unsigned HOST_WIDE_INT shift_mask = ~(unsigned HOST_WIDE_INT) 0;
970790075Sobrien
970890075Sobrien  shift_mask <<= INTVAL (shiftop);
970990075Sobrien
971096263Sobrien  return (INTVAL (andop) & 0xffffffff & ~shift_mask) == 0;
971190075Sobrien}
971290075Sobrien
971390075Sobrien/* Similar, but for right shift.  */
971490075Sobrien
971590075Sobrienint
9716132718Skanincludes_rshift_p (rtx shiftop, rtx andop)
971790075Sobrien{
971890075Sobrien  unsigned HOST_WIDE_INT shift_mask = ~(unsigned HOST_WIDE_INT) 0;
971990075Sobrien
972090075Sobrien  shift_mask >>= INTVAL (shiftop);
972190075Sobrien
972296263Sobrien  return (INTVAL (andop) & 0xffffffff & ~shift_mask) == 0;
972390075Sobrien}
972490075Sobrien
972590075Sobrien/* Return 1 if ANDOP is a mask suitable for use with an rldic insn
972690075Sobrien   to perform a left shift.  It must have exactly SHIFTOP least
9727132718Skan   significant 0's, then one or more 1's, then zero or more 0's.  */
972890075Sobrien
972990075Sobrienint
9730132718Skanincludes_rldic_lshift_p (rtx shiftop, rtx andop)
973190075Sobrien{
973290075Sobrien  if (GET_CODE (andop) == CONST_INT)
973390075Sobrien    {
973490075Sobrien      HOST_WIDE_INT c, lsb, shift_mask;
973590075Sobrien
973690075Sobrien      c = INTVAL (andop);
973790075Sobrien      if (c == 0 || c == ~0)
973890075Sobrien	return 0;
973990075Sobrien
974090075Sobrien      shift_mask = ~0;
974190075Sobrien      shift_mask <<= INTVAL (shiftop);
974290075Sobrien
9743132718Skan      /* Find the least significant one bit.  */
974490075Sobrien      lsb = c & -c;
974590075Sobrien
974690075Sobrien      /* It must coincide with the LSB of the shift mask.  */
974790075Sobrien      if (-lsb != shift_mask)
974890075Sobrien	return 0;
974990075Sobrien
975090075Sobrien      /* Invert to look for the next transition (if any).  */
975190075Sobrien      c = ~c;
975290075Sobrien
975390075Sobrien      /* Remove the low group of ones (originally low group of zeros).  */
975490075Sobrien      c &= -lsb;
975590075Sobrien
975690075Sobrien      /* Again find the lsb, and check we have all 1's above.  */
975790075Sobrien      lsb = c & -c;
975890075Sobrien      return c == -lsb;
975990075Sobrien    }
976090075Sobrien  else if (GET_CODE (andop) == CONST_DOUBLE
976190075Sobrien	   && (GET_MODE (andop) == VOIDmode || GET_MODE (andop) == DImode))
976290075Sobrien    {
976390075Sobrien      HOST_WIDE_INT low, high, lsb;
976490075Sobrien      HOST_WIDE_INT shift_mask_low, shift_mask_high;
976590075Sobrien
976690075Sobrien      low = CONST_DOUBLE_LOW (andop);
976790075Sobrien      if (HOST_BITS_PER_WIDE_INT < 64)
976890075Sobrien	high = CONST_DOUBLE_HIGH (andop);
976990075Sobrien
977090075Sobrien      if ((low == 0 && (HOST_BITS_PER_WIDE_INT >= 64 || high == 0))
977190075Sobrien	  || (low == ~0 && (HOST_BITS_PER_WIDE_INT >= 64 || high == ~0)))
977290075Sobrien	return 0;
977390075Sobrien
977490075Sobrien      if (HOST_BITS_PER_WIDE_INT < 64 && low == 0)
977590075Sobrien	{
977690075Sobrien	  shift_mask_high = ~0;
977790075Sobrien	  if (INTVAL (shiftop) > 32)
977890075Sobrien	    shift_mask_high <<= INTVAL (shiftop) - 32;
977990075Sobrien
978090075Sobrien	  lsb = high & -high;
978190075Sobrien
978290075Sobrien	  if (-lsb != shift_mask_high || INTVAL (shiftop) < 32)
978390075Sobrien	    return 0;
978490075Sobrien
978590075Sobrien	  high = ~high;
978690075Sobrien	  high &= -lsb;
978790075Sobrien
978890075Sobrien	  lsb = high & -high;
978990075Sobrien	  return high == -lsb;
979090075Sobrien	}
979190075Sobrien
979290075Sobrien      shift_mask_low = ~0;
979390075Sobrien      shift_mask_low <<= INTVAL (shiftop);
979490075Sobrien
979590075Sobrien      lsb = low & -low;
979690075Sobrien
979790075Sobrien      if (-lsb != shift_mask_low)
979890075Sobrien	return 0;
979990075Sobrien
980090075Sobrien      if (HOST_BITS_PER_WIDE_INT < 64)
980190075Sobrien	high = ~high;
980290075Sobrien      low = ~low;
980390075Sobrien      low &= -lsb;
980490075Sobrien
980590075Sobrien      if (HOST_BITS_PER_WIDE_INT < 64 && low == 0)
980690075Sobrien	{
980790075Sobrien	  lsb = high & -high;
980890075Sobrien	  return high == -lsb;
980990075Sobrien	}
981090075Sobrien
981190075Sobrien      lsb = low & -low;
981290075Sobrien      return low == -lsb && (HOST_BITS_PER_WIDE_INT >= 64 || high == ~0);
981390075Sobrien    }
981490075Sobrien  else
981590075Sobrien    return 0;
981690075Sobrien}
981790075Sobrien
981890075Sobrien/* Return 1 if ANDOP is a mask suitable for use with an rldicr insn
981990075Sobrien   to perform a left shift.  It must have SHIFTOP or more least
9820132718Skan   significant 0's, with the remainder of the word 1's.  */
982190075Sobrien
982290075Sobrienint
9823132718Skanincludes_rldicr_lshift_p (rtx shiftop, rtx andop)
982490075Sobrien{
982590075Sobrien  if (GET_CODE (andop) == CONST_INT)
982690075Sobrien    {
982790075Sobrien      HOST_WIDE_INT c, lsb, shift_mask;
982890075Sobrien
982990075Sobrien      shift_mask = ~0;
983090075Sobrien      shift_mask <<= INTVAL (shiftop);
983190075Sobrien      c = INTVAL (andop);
983290075Sobrien
9833132718Skan      /* Find the least significant one bit.  */
983490075Sobrien      lsb = c & -c;
983590075Sobrien
983690075Sobrien      /* It must be covered by the shift mask.
983790075Sobrien	 This test also rejects c == 0.  */
983890075Sobrien      if ((lsb & shift_mask) == 0)
983990075Sobrien	return 0;
984090075Sobrien
984190075Sobrien      /* Check we have all 1's above the transition, and reject all 1's.  */
984290075Sobrien      return c == -lsb && lsb != 1;
984390075Sobrien    }
984490075Sobrien  else if (GET_CODE (andop) == CONST_DOUBLE
984590075Sobrien	   && (GET_MODE (andop) == VOIDmode || GET_MODE (andop) == DImode))
984690075Sobrien    {
984790075Sobrien      HOST_WIDE_INT low, lsb, shift_mask_low;
984890075Sobrien
984990075Sobrien      low = CONST_DOUBLE_LOW (andop);
985090075Sobrien
985190075Sobrien      if (HOST_BITS_PER_WIDE_INT < 64)
985290075Sobrien	{
985390075Sobrien	  HOST_WIDE_INT high, shift_mask_high;
985490075Sobrien
985590075Sobrien	  high = CONST_DOUBLE_HIGH (andop);
985690075Sobrien
985790075Sobrien	  if (low == 0)
985890075Sobrien	    {
985990075Sobrien	      shift_mask_high = ~0;
986090075Sobrien	      if (INTVAL (shiftop) > 32)
986190075Sobrien		shift_mask_high <<= INTVAL (shiftop) - 32;
986290075Sobrien
986390075Sobrien	      lsb = high & -high;
986490075Sobrien
986590075Sobrien	      if ((lsb & shift_mask_high) == 0)
986690075Sobrien		return 0;
986790075Sobrien
986890075Sobrien	      return high == -lsb;
986990075Sobrien	    }
987090075Sobrien	  if (high != ~0)
987190075Sobrien	    return 0;
987290075Sobrien	}
987390075Sobrien
987490075Sobrien      shift_mask_low = ~0;
987590075Sobrien      shift_mask_low <<= INTVAL (shiftop);
987690075Sobrien
987790075Sobrien      lsb = low & -low;
987890075Sobrien
987990075Sobrien      if ((lsb & shift_mask_low) == 0)
988090075Sobrien	return 0;
988190075Sobrien
988290075Sobrien      return low == -lsb && lsb != 1;
988390075Sobrien    }
988490075Sobrien  else
988590075Sobrien    return 0;
988690075Sobrien}
988790075Sobrien
9888169689Skan/* Return 1 if operands will generate a valid arguments to rlwimi
9889169689Skaninstruction for insert with right shift in 64-bit mode.  The mask may
9890169689Skannot start on the first bit or stop on the last bit because wrap-around
9891169689Skaneffects of instruction do not correspond to semantics of RTL insn.  */
9892169689Skan
9893169689Skanint
9894169689Skaninsvdi_rshift_rlwimi_p (rtx sizeop, rtx startop, rtx shiftop)
9895169689Skan{
9896169689Skan  if (INTVAL (startop) > 32
9897169689Skan      && INTVAL (startop) < 64
9898169689Skan      && INTVAL (sizeop) > 1
9899169689Skan      && INTVAL (sizeop) + INTVAL (startop) < 64
9900169689Skan      && INTVAL (shiftop) > 0
9901169689Skan      && INTVAL (sizeop) + INTVAL (shiftop) < 32
9902169689Skan      && (64 - (INTVAL (shiftop) & 63)) >= INTVAL (sizeop))
9903169689Skan    return 1;
9904169689Skan
9905169689Skan  return 0;
9906169689Skan}
9907169689Skan
990890075Sobrien/* Return 1 if REGNO (reg1) == REGNO (reg2) - 1 making them candidates
9909169689Skan   for lfq and stfq insns iff the registers are hard registers.   */
991090075Sobrien
991190075Sobrienint
9912132718Skanregisters_ok_for_quad_peep (rtx reg1, rtx reg2)
991390075Sobrien{
991490075Sobrien  /* We might have been passed a SUBREG.  */
9915169689Skan  if (GET_CODE (reg1) != REG || GET_CODE (reg2) != REG)
991690075Sobrien    return 0;
991790075Sobrien
9918169689Skan  /* We might have been passed non floating point registers.  */
9919169689Skan  if (!FP_REGNO_P (REGNO (reg1))
9920169689Skan      || !FP_REGNO_P (REGNO (reg2)))
9921169689Skan    return 0;
9922169689Skan
992390075Sobrien  return (REGNO (reg1) == REGNO (reg2) - 1);
992490075Sobrien}
992590075Sobrien
992690075Sobrien/* Return 1 if addr1 and addr2 are suitable for lfq or stfq insn.
992790075Sobrien   addr1 and addr2 must be in consecutive memory locations
992890075Sobrien   (addr2 == addr1 + 8).  */
992990075Sobrien
993090075Sobrienint
9931169689Skanmems_ok_for_quad_peep (rtx mem1, rtx mem2)
993290075Sobrien{
9933169689Skan  rtx addr1, addr2;
9934169689Skan  unsigned int reg1, reg2;
9935169689Skan  int offset1, offset2;
993690075Sobrien
9937169689Skan  /* The mems cannot be volatile.  */
9938169689Skan  if (MEM_VOLATILE_P (mem1) || MEM_VOLATILE_P (mem2))
9939169689Skan    return 0;
9940169689Skan
9941169689Skan  addr1 = XEXP (mem1, 0);
9942169689Skan  addr2 = XEXP (mem2, 0);
9943169689Skan
994490075Sobrien  /* Extract an offset (if used) from the first addr.  */
994590075Sobrien  if (GET_CODE (addr1) == PLUS)
994690075Sobrien    {
994790075Sobrien      /* If not a REG, return zero.  */
994890075Sobrien      if (GET_CODE (XEXP (addr1, 0)) != REG)
994990075Sobrien	return 0;
995090075Sobrien      else
995190075Sobrien	{
9952169689Skan	  reg1 = REGNO (XEXP (addr1, 0));
995390075Sobrien	  /* The offset must be constant!  */
995490075Sobrien	  if (GET_CODE (XEXP (addr1, 1)) != CONST_INT)
9955169689Skan	    return 0;
9956169689Skan	  offset1 = INTVAL (XEXP (addr1, 1));
995790075Sobrien	}
995890075Sobrien    }
995990075Sobrien  else if (GET_CODE (addr1) != REG)
996090075Sobrien    return 0;
996190075Sobrien  else
996290075Sobrien    {
996390075Sobrien      reg1 = REGNO (addr1);
996490075Sobrien      /* This was a simple (mem (reg)) expression.  Offset is 0.  */
996590075Sobrien      offset1 = 0;
996690075Sobrien    }
996790075Sobrien
9968169689Skan  /* And now for the second addr.  */
9969169689Skan  if (GET_CODE (addr2) == PLUS)
9970169689Skan    {
9971169689Skan      /* If not a REG, return zero.  */
9972169689Skan      if (GET_CODE (XEXP (addr2, 0)) != REG)
9973169689Skan	return 0;
9974169689Skan      else
9975169689Skan	{
9976169689Skan	  reg2 = REGNO (XEXP (addr2, 0));
9977169689Skan	  /* The offset must be constant. */
9978169689Skan	  if (GET_CODE (XEXP (addr2, 1)) != CONST_INT)
9979169689Skan	    return 0;
9980169689Skan	  offset2 = INTVAL (XEXP (addr2, 1));
9981169689Skan	}
9982169689Skan    }
9983169689Skan  else if (GET_CODE (addr2) != REG)
998490075Sobrien    return 0;
9985169689Skan  else
9986169689Skan    {
9987169689Skan      reg2 = REGNO (addr2);
9988169689Skan      /* This was a simple (mem (reg)) expression.  Offset is 0.  */
9989169689Skan      offset2 = 0;
9990169689Skan    }
999190075Sobrien
9992169689Skan  /* Both of these must have the same base register.  */
9993169689Skan  if (reg1 != reg2)
999490075Sobrien    return 0;
999590075Sobrien
999690075Sobrien  /* The offset for the second addr must be 8 more than the first addr.  */
9997169689Skan  if (offset2 != offset1 + 8)
999890075Sobrien    return 0;
999990075Sobrien
1000090075Sobrien  /* All the tests passed.  addr1 and addr2 are valid for lfq or stfq
1000190075Sobrien     instructions.  */
1000290075Sobrien  return 1;
1000390075Sobrien}
1000490075Sobrien
1000590075Sobrien/* Return the register class of a scratch register needed to copy IN into
1000690075Sobrien   or out of a register in CLASS in MODE.  If it can be done directly,
10007161651Skan   NO_REGS is returned.  */
1000890075Sobrien
1000990075Sobrienenum reg_class
10010169689Skanrs6000_secondary_reload_class (enum reg_class class,
10011169689Skan			       enum machine_mode mode ATTRIBUTE_UNUSED,
10012169689Skan			       rtx in)
1001390075Sobrien{
1001490075Sobrien  int regno;
1001590075Sobrien
10016132718Skan  if (TARGET_ELF || (DEFAULT_ABI == ABI_DARWIN
10017132718Skan#if TARGET_MACHO
10018169689Skan		     && MACHOPIC_INDIRECT
10019132718Skan#endif
10020169689Skan		     ))
1002190075Sobrien    {
1002290075Sobrien      /* We cannot copy a symbolic operand directly into anything
10023169689Skan	 other than BASE_REGS for TARGET_ELF.  So indicate that a
10024169689Skan	 register from BASE_REGS is needed as an intermediate
10025169689Skan	 register.
10026169689Skan
1002790075Sobrien	 On Darwin, pic addresses require a load from memory, which
1002890075Sobrien	 needs a base register.  */
1002990075Sobrien      if (class != BASE_REGS
10030169689Skan	  && (GET_CODE (in) == SYMBOL_REF
10031169689Skan	      || GET_CODE (in) == HIGH
10032169689Skan	      || GET_CODE (in) == LABEL_REF
10033169689Skan	      || GET_CODE (in) == CONST))
10034169689Skan	return BASE_REGS;
1003590075Sobrien    }
1003690075Sobrien
1003790075Sobrien  if (GET_CODE (in) == REG)
1003890075Sobrien    {
1003990075Sobrien      regno = REGNO (in);
1004090075Sobrien      if (regno >= FIRST_PSEUDO_REGISTER)
1004190075Sobrien	{
1004290075Sobrien	  regno = true_regnum (in);
1004390075Sobrien	  if (regno >= FIRST_PSEUDO_REGISTER)
1004490075Sobrien	    regno = -1;
1004590075Sobrien	}
1004690075Sobrien    }
1004790075Sobrien  else if (GET_CODE (in) == SUBREG)
1004890075Sobrien    {
1004990075Sobrien      regno = true_regnum (in);
1005090075Sobrien      if (regno >= FIRST_PSEUDO_REGISTER)
1005190075Sobrien	regno = -1;
1005290075Sobrien    }
1005390075Sobrien  else
1005490075Sobrien    regno = -1;
1005590075Sobrien
1005690075Sobrien  /* We can place anything into GENERAL_REGS and can put GENERAL_REGS
1005790075Sobrien     into anything.  */
1005890075Sobrien  if (class == GENERAL_REGS || class == BASE_REGS
1005990075Sobrien      || (regno >= 0 && INT_REGNO_P (regno)))
1006090075Sobrien    return NO_REGS;
1006190075Sobrien
1006290075Sobrien  /* Constants, memory, and FP registers can go into FP registers.  */
1006390075Sobrien  if ((regno == -1 || FP_REGNO_P (regno))
1006490075Sobrien      && (class == FLOAT_REGS || class == NON_SPECIAL_REGS))
1006590075Sobrien    return NO_REGS;
1006690075Sobrien
1006790075Sobrien  /* Memory, and AltiVec registers can go into AltiVec registers.  */
1006890075Sobrien  if ((regno == -1 || ALTIVEC_REGNO_P (regno))
1006990075Sobrien      && class == ALTIVEC_REGS)
1007090075Sobrien    return NO_REGS;
1007190075Sobrien
1007290075Sobrien  /* We can copy among the CR registers.  */
1007390075Sobrien  if ((class == CR_REGS || class == CR0_REGS)
1007490075Sobrien      && regno >= 0 && CR_REGNO_P (regno))
1007590075Sobrien    return NO_REGS;
1007690075Sobrien
1007790075Sobrien  /* Otherwise, we need GENERAL_REGS.  */
1007890075Sobrien  return GENERAL_REGS;
1007990075Sobrien}
1008090075Sobrien
1008190075Sobrien/* Given a comparison operation, return the bit number in CCR to test.  We
10082169689Skan   know this is a valid comparison.
1008390075Sobrien
1008490075Sobrien   SCC_P is 1 if this is for an scc.  That means that %D will have been
1008590075Sobrien   used instead of %C, so the bits will be in different places.
1008690075Sobrien
1008790075Sobrien   Return -1 if OP isn't a valid comparison for some reason.  */
1008890075Sobrien
1008990075Sobrienint
10090132718Skanccr_bit (rtx op, int scc_p)
1009190075Sobrien{
1009290075Sobrien  enum rtx_code code = GET_CODE (op);
1009390075Sobrien  enum machine_mode cc_mode;
1009490075Sobrien  int cc_regnum;
1009590075Sobrien  int base_bit;
1009690075Sobrien  rtx reg;
1009790075Sobrien
10098169689Skan  if (!COMPARISON_P (op))
1009990075Sobrien    return -1;
1010090075Sobrien
1010190075Sobrien  reg = XEXP (op, 0);
1010290075Sobrien
10103169689Skan  gcc_assert (GET_CODE (reg) == REG && CR_REGNO_P (REGNO (reg)));
1010490075Sobrien
1010590075Sobrien  cc_mode = GET_MODE (reg);
1010690075Sobrien  cc_regnum = REGNO (reg);
1010790075Sobrien  base_bit = 4 * (cc_regnum - CR0_REGNO);
1010890075Sobrien
1010990075Sobrien  validate_condition_mode (code, cc_mode);
1011090075Sobrien
10111132718Skan  /* When generating a sCOND operation, only positive conditions are
10112132718Skan     allowed.  */
10113169689Skan  gcc_assert (!scc_p
10114169689Skan	      || code == EQ || code == GT || code == LT || code == UNORDERED
10115169689Skan	      || code == GTU || code == LTU);
10116169689Skan
1011790075Sobrien  switch (code)
1011890075Sobrien    {
1011990075Sobrien    case NE:
1012090075Sobrien      return scc_p ? base_bit + 3 : base_bit + 2;
1012190075Sobrien    case EQ:
1012290075Sobrien      return base_bit + 2;
1012390075Sobrien    case GT:  case GTU:  case UNLE:
1012490075Sobrien      return base_bit + 1;
1012590075Sobrien    case LT:  case LTU:  case UNGE:
1012690075Sobrien      return base_bit;
1012790075Sobrien    case ORDERED:  case UNORDERED:
1012890075Sobrien      return base_bit + 3;
1012990075Sobrien
1013090075Sobrien    case GE:  case GEU:
1013190075Sobrien      /* If scc, we will have done a cror to put the bit in the
1013290075Sobrien	 unordered position.  So test that bit.  For integer, this is ! LT
1013390075Sobrien	 unless this is an scc insn.  */
1013490075Sobrien      return scc_p ? base_bit + 3 : base_bit;
1013590075Sobrien
1013690075Sobrien    case LE:  case LEU:
1013790075Sobrien      return scc_p ? base_bit + 3 : base_bit + 1;
1013890075Sobrien
1013990075Sobrien    default:
10140169689Skan      gcc_unreachable ();
1014190075Sobrien    }
1014290075Sobrien}
1014390075Sobrien
1014490075Sobrien/* Return the GOT register.  */
1014590075Sobrien
10146169689Skanrtx
10147132718Skanrs6000_got_register (rtx value ATTRIBUTE_UNUSED)
1014890075Sobrien{
1014990075Sobrien  /* The second flow pass currently (June 1999) can't update
1015090075Sobrien     regs_ever_live without disturbing other parts of the compiler, so
1015190075Sobrien     update it here to make the prolog/epilogue code happy.  */
1015296263Sobrien  if (no_new_pseudos && ! regs_ever_live[RS6000_PIC_OFFSET_TABLE_REGNUM])
1015396263Sobrien    regs_ever_live[RS6000_PIC_OFFSET_TABLE_REGNUM] = 1;
1015490075Sobrien
1015590075Sobrien  current_function_uses_pic_offset_table = 1;
1015690075Sobrien
1015790075Sobrien  return pic_offset_table_rtx;
1015890075Sobrien}
1015990075Sobrien
10160117395Skan/* Function to init struct machine_function.
10161117395Skan   This will be called, via a pointer variable,
10162117395Skan   from push_function_context.  */
1016390075Sobrien
10164117395Skanstatic struct machine_function *
10165132718Skanrs6000_init_machine_status (void)
1016690075Sobrien{
10167117395Skan  return ggc_alloc_cleared (sizeof (machine_function));
1016890075Sobrien}
10169117395Skan
10170117395Skan/* These macros test for integers and extract the low-order bits.  */
10171117395Skan#define INT_P(X)  \
10172117395Skan((GET_CODE (X) == CONST_INT || GET_CODE (X) == CONST_DOUBLE)	\
10173117395Skan && GET_MODE (X) == VOIDmode)
1017490075Sobrien
10175117395Skan#define INT_LOWPART(X) \
10176117395Skan  (GET_CODE (X) == CONST_INT ? INTVAL (X) : CONST_DOUBLE_LOW (X))
10177117395Skan
10178117395Skanint
10179132718Skanextract_MB (rtx op)
1018090075Sobrien{
10181117395Skan  int i;
10182117395Skan  unsigned long val = INT_LOWPART (op);
1018390075Sobrien
10184117395Skan  /* If the high bit is zero, the value is the first 1 bit we find
10185117395Skan     from the left.  */
10186117395Skan  if ((val & 0x80000000) == 0)
10187117395Skan    {
10188169689Skan      gcc_assert (val & 0xffffffff);
10189117395Skan
10190117395Skan      i = 1;
10191117395Skan      while (((val <<= 1) & 0x80000000) == 0)
10192117395Skan	++i;
10193117395Skan      return i;
10194117395Skan    }
10195117395Skan
10196117395Skan  /* If the high bit is set and the low bit is not, or the mask is all
10197117395Skan     1's, the value is zero.  */
10198117395Skan  if ((val & 1) == 0 || (val & 0xffffffff) == 0xffffffff)
10199117395Skan    return 0;
10200117395Skan
10201117395Skan  /* Otherwise we have a wrap-around mask.  Look for the first 0 bit
10202117395Skan     from the right.  */
10203117395Skan  i = 31;
10204117395Skan  while (((val >>= 1) & 1) != 0)
10205117395Skan    --i;
10206117395Skan
10207117395Skan  return i;
1020890075Sobrien}
1020990075Sobrien
10210117395Skanint
10211132718Skanextract_ME (rtx op)
10212117395Skan{
10213117395Skan  int i;
10214117395Skan  unsigned long val = INT_LOWPART (op);
10215117395Skan
10216117395Skan  /* If the low bit is zero, the value is the first 1 bit we find from
10217117395Skan     the right.  */
10218117395Skan  if ((val & 1) == 0)
10219117395Skan    {
10220169689Skan      gcc_assert (val & 0xffffffff);
10221117395Skan
10222117395Skan      i = 30;
10223117395Skan      while (((val >>= 1) & 1) == 0)
10224117395Skan	--i;
10225117395Skan
10226117395Skan      return i;
10227117395Skan    }
10228117395Skan
10229117395Skan  /* If the low bit is set and the high bit is not, or the mask is all
10230117395Skan     1's, the value is 31.  */
10231117395Skan  if ((val & 0x80000000) == 0 || (val & 0xffffffff) == 0xffffffff)
10232117395Skan    return 31;
10233117395Skan
10234117395Skan  /* Otherwise we have a wrap-around mask.  Look for the first 0 bit
10235117395Skan     from the left.  */
10236117395Skan  i = 0;
10237117395Skan  while (((val <<= 1) & 0x80000000) != 0)
10238117395Skan    ++i;
10239117395Skan
10240117395Skan  return i;
10241117395Skan}
10242117395Skan
10243132718Skan/* Locate some local-dynamic symbol still in use by this function
10244132718Skan   so that we can print its name in some tls_ld pattern.  */
10245132718Skan
10246132718Skanstatic const char *
10247132718Skanrs6000_get_some_local_dynamic_name (void)
10248132718Skan{
10249132718Skan  rtx insn;
10250132718Skan
10251132718Skan  if (cfun->machine->some_ld_name)
10252132718Skan    return cfun->machine->some_ld_name;
10253132718Skan
10254132718Skan  for (insn = get_insns (); insn ; insn = NEXT_INSN (insn))
10255132718Skan    if (INSN_P (insn)
10256132718Skan	&& for_each_rtx (&PATTERN (insn),
10257132718Skan			 rs6000_get_some_local_dynamic_name_1, 0))
10258132718Skan      return cfun->machine->some_ld_name;
10259132718Skan
10260169689Skan  gcc_unreachable ();
10261132718Skan}
10262132718Skan
10263132718Skan/* Helper function for rs6000_get_some_local_dynamic_name.  */
10264132718Skan
10265132718Skanstatic int
10266132718Skanrs6000_get_some_local_dynamic_name_1 (rtx *px, void *data ATTRIBUTE_UNUSED)
10267132718Skan{
10268132718Skan  rtx x = *px;
10269132718Skan
10270132718Skan  if (GET_CODE (x) == SYMBOL_REF)
10271132718Skan    {
10272132718Skan      const char *str = XSTR (x, 0);
10273132718Skan      if (SYMBOL_REF_TLS_MODEL (x) == TLS_MODEL_LOCAL_DYNAMIC)
10274132718Skan	{
10275132718Skan	  cfun->machine->some_ld_name = str;
10276132718Skan	  return 1;
10277132718Skan	}
10278132718Skan    }
10279132718Skan
10280132718Skan  return 0;
10281132718Skan}
10282132718Skan
10283169689Skan/* Write out a function code label.  */
10284169689Skan
10285169689Skanvoid
10286169689Skanrs6000_output_function_entry (FILE *file, const char *fname)
10287169689Skan{
10288169689Skan  if (fname[0] != '.')
10289169689Skan    {
10290169689Skan      switch (DEFAULT_ABI)
10291169689Skan	{
10292169689Skan	default:
10293169689Skan	  gcc_unreachable ();
10294169689Skan
10295169689Skan	case ABI_AIX:
10296169689Skan	  if (DOT_SYMBOLS)
10297169689Skan	    putc ('.', file);
10298169689Skan	  else
10299169689Skan	    ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "L.");
10300169689Skan	  break;
10301169689Skan
10302169689Skan	case ABI_V4:
10303169689Skan	case ABI_DARWIN:
10304169689Skan	  break;
10305169689Skan	}
10306169689Skan    }
10307169689Skan  if (TARGET_AIX)
10308169689Skan    RS6000_OUTPUT_BASENAME (file, fname);
10309169689Skan  else
10310169689Skan    assemble_name (file, fname);
10311169689Skan}
10312169689Skan
1031390075Sobrien/* Print an operand.  Recognize special options, documented below.  */
1031490075Sobrien
1031590075Sobrien#if TARGET_ELF
1031690075Sobrien#define SMALL_DATA_RELOC ((rs6000_sdata == SDATA_EABI) ? "sda21" : "sdarel")
1031790075Sobrien#define SMALL_DATA_REG ((rs6000_sdata == SDATA_EABI) ? 0 : 13)
1031890075Sobrien#else
1031990075Sobrien#define SMALL_DATA_RELOC "sda21"
1032090075Sobrien#define SMALL_DATA_REG 0
1032190075Sobrien#endif
1032290075Sobrien
1032390075Sobrienvoid
10324132718Skanprint_operand (FILE *file, rtx x, int code)
1032590075Sobrien{
1032690075Sobrien  int i;
1032790075Sobrien  HOST_WIDE_INT val;
10328117395Skan  unsigned HOST_WIDE_INT uval;
1032990075Sobrien
1033090075Sobrien  switch (code)
1033190075Sobrien    {
1033290075Sobrien    case '.':
1033390075Sobrien      /* Write out an instruction after the call which may be replaced
1033490075Sobrien	 with glue code by the loader.  This depends on the AIX version.  */
1033590075Sobrien      asm_fprintf (file, RS6000_CALL_GLUE);
1033690075Sobrien      return;
1033790075Sobrien
1033890075Sobrien      /* %a is output_address.  */
1033990075Sobrien
1034090075Sobrien    case 'A':
1034190075Sobrien      /* If X is a constant integer whose low-order 5 bits are zero,
1034290075Sobrien	 write 'l'.  Otherwise, write 'r'.  This is a kludge to fix a bug
1034390075Sobrien	 in the AIX assembler where "sri" with a zero shift count
1034490075Sobrien	 writes a trash instruction.  */
1034590075Sobrien      if (GET_CODE (x) == CONST_INT && (INTVAL (x) & 31) == 0)
1034690075Sobrien	putc ('l', file);
1034790075Sobrien      else
1034890075Sobrien	putc ('r', file);
1034990075Sobrien      return;
1035090075Sobrien
1035190075Sobrien    case 'b':
1035290075Sobrien      /* If constant, low-order 16 bits of constant, unsigned.
1035390075Sobrien	 Otherwise, write normally.  */
1035490075Sobrien      if (INT_P (x))
1035590075Sobrien	fprintf (file, HOST_WIDE_INT_PRINT_DEC, INT_LOWPART (x) & 0xffff);
1035690075Sobrien      else
1035790075Sobrien	print_operand (file, x, 0);
1035890075Sobrien      return;
1035990075Sobrien
1036090075Sobrien    case 'B':
1036190075Sobrien      /* If the low-order bit is zero, write 'r'; otherwise, write 'l'
1036290075Sobrien	 for 64-bit mask direction.  */
10363169689Skan      putc (((INT_LOWPART (x) & 1) == 0 ? 'r' : 'l'), file);
1036490075Sobrien      return;
1036590075Sobrien
1036690075Sobrien      /* %c is output_addr_const if a CONSTANT_ADDRESS_P, otherwise
1036790075Sobrien	 output_operand.  */
1036890075Sobrien
10369132718Skan    case 'c':
10370132718Skan      /* X is a CR register.  Print the number of the GT bit of the CR.  */
10371132718Skan      if (GET_CODE (x) != REG || ! CR_REGNO_P (REGNO (x)))
10372169689Skan	output_operand_lossage ("invalid %%E value");
10373132718Skan      else
10374169689Skan	fprintf (file, "%d", 4 * (REGNO (x) - CR0_REGNO) + 1);
10375132718Skan      return;
10376132718Skan
1037790075Sobrien    case 'D':
10378169689Skan      /* Like 'J' but get to the GT bit only.  */
10379169689Skan      gcc_assert (GET_CODE (x) == REG);
1038090075Sobrien
10381169689Skan      /* Bit 1 is GT bit.  */
10382169689Skan      i = 4 * (REGNO (x) - CR0_REGNO) + 1;
1038390075Sobrien
10384169689Skan      /* Add one for shift count in rlinm for scc.  */
10385169689Skan      fprintf (file, "%d", i + 1);
1038690075Sobrien      return;
1038790075Sobrien
1038890075Sobrien    case 'E':
1038990075Sobrien      /* X is a CR register.  Print the number of the EQ bit of the CR */
1039090075Sobrien      if (GET_CODE (x) != REG || ! CR_REGNO_P (REGNO (x)))
1039190075Sobrien	output_operand_lossage ("invalid %%E value");
1039290075Sobrien      else
1039390075Sobrien	fprintf (file, "%d", 4 * (REGNO (x) - CR0_REGNO) + 2);
1039490075Sobrien      return;
1039590075Sobrien
1039690075Sobrien    case 'f':
1039790075Sobrien      /* X is a CR register.  Print the shift count needed to move it
1039890075Sobrien	 to the high-order four bits.  */
1039990075Sobrien      if (GET_CODE (x) != REG || ! CR_REGNO_P (REGNO (x)))
1040090075Sobrien	output_operand_lossage ("invalid %%f value");
1040190075Sobrien      else
1040290075Sobrien	fprintf (file, "%d", 4 * (REGNO (x) - CR0_REGNO));
1040390075Sobrien      return;
1040490075Sobrien
1040590075Sobrien    case 'F':
1040690075Sobrien      /* Similar, but print the count for the rotate in the opposite
1040790075Sobrien	 direction.  */
1040890075Sobrien      if (GET_CODE (x) != REG || ! CR_REGNO_P (REGNO (x)))
1040990075Sobrien	output_operand_lossage ("invalid %%F value");
1041090075Sobrien      else
1041190075Sobrien	fprintf (file, "%d", 32 - 4 * (REGNO (x) - CR0_REGNO));
1041290075Sobrien      return;
1041390075Sobrien
1041490075Sobrien    case 'G':
1041590075Sobrien      /* X is a constant integer.  If it is negative, print "m",
10416117395Skan	 otherwise print "z".  This is to make an aze or ame insn.  */
1041790075Sobrien      if (GET_CODE (x) != CONST_INT)
1041890075Sobrien	output_operand_lossage ("invalid %%G value");
1041990075Sobrien      else if (INTVAL (x) >= 0)
1042090075Sobrien	putc ('z', file);
1042190075Sobrien      else
1042290075Sobrien	putc ('m', file);
1042390075Sobrien      return;
1042490075Sobrien
1042590075Sobrien    case 'h':
1042690075Sobrien      /* If constant, output low-order five bits.  Otherwise, write
1042790075Sobrien	 normally.  */
1042890075Sobrien      if (INT_P (x))
1042990075Sobrien	fprintf (file, HOST_WIDE_INT_PRINT_DEC, INT_LOWPART (x) & 31);
1043090075Sobrien      else
1043190075Sobrien	print_operand (file, x, 0);
1043290075Sobrien      return;
1043390075Sobrien
1043490075Sobrien    case 'H':
1043590075Sobrien      /* If constant, output low-order six bits.  Otherwise, write
1043690075Sobrien	 normally.  */
1043790075Sobrien      if (INT_P (x))
1043890075Sobrien	fprintf (file, HOST_WIDE_INT_PRINT_DEC, INT_LOWPART (x) & 63);
1043990075Sobrien      else
1044090075Sobrien	print_operand (file, x, 0);
1044190075Sobrien      return;
1044290075Sobrien
1044390075Sobrien    case 'I':
1044490075Sobrien      /* Print `i' if this is a constant, else nothing.  */
1044590075Sobrien      if (INT_P (x))
1044690075Sobrien	putc ('i', file);
1044790075Sobrien      return;
1044890075Sobrien
1044990075Sobrien    case 'j':
1045090075Sobrien      /* Write the bit number in CCR for jump.  */
1045190075Sobrien      i = ccr_bit (x, 0);
1045290075Sobrien      if (i == -1)
1045390075Sobrien	output_operand_lossage ("invalid %%j code");
1045490075Sobrien      else
1045590075Sobrien	fprintf (file, "%d", i);
1045690075Sobrien      return;
1045790075Sobrien
1045890075Sobrien    case 'J':
1045990075Sobrien      /* Similar, but add one for shift count in rlinm for scc and pass
1046090075Sobrien	 scc flag to `ccr_bit'.  */
1046190075Sobrien      i = ccr_bit (x, 1);
1046290075Sobrien      if (i == -1)
1046390075Sobrien	output_operand_lossage ("invalid %%J code");
1046490075Sobrien      else
1046590075Sobrien	/* If we want bit 31, write a shift count of zero, not 32.  */
1046690075Sobrien	fprintf (file, "%d", i == 31 ? 0 : i + 1);
1046790075Sobrien      return;
1046890075Sobrien
1046990075Sobrien    case 'k':
1047090075Sobrien      /* X must be a constant.  Write the 1's complement of the
1047190075Sobrien	 constant.  */
1047290075Sobrien      if (! INT_P (x))
1047390075Sobrien	output_operand_lossage ("invalid %%k value");
1047490075Sobrien      else
1047590075Sobrien	fprintf (file, HOST_WIDE_INT_PRINT_DEC, ~ INT_LOWPART (x));
1047690075Sobrien      return;
1047790075Sobrien
1047890075Sobrien    case 'K':
1047990075Sobrien      /* X must be a symbolic constant on ELF.  Write an
1048090075Sobrien	 expression suitable for an 'addi' that adds in the low 16
1048190075Sobrien	 bits of the MEM.  */
1048290075Sobrien      if (GET_CODE (x) != CONST)
1048390075Sobrien	{
1048490075Sobrien	  print_operand_address (file, x);
1048590075Sobrien	  fputs ("@l", file);
1048690075Sobrien	}
1048790075Sobrien      else
1048890075Sobrien	{
1048990075Sobrien	  if (GET_CODE (XEXP (x, 0)) != PLUS
1049090075Sobrien	      || (GET_CODE (XEXP (XEXP (x, 0), 0)) != SYMBOL_REF
1049190075Sobrien		  && GET_CODE (XEXP (XEXP (x, 0), 0)) != LABEL_REF)
1049290075Sobrien	      || GET_CODE (XEXP (XEXP (x, 0), 1)) != CONST_INT)
1049390075Sobrien	    output_operand_lossage ("invalid %%K value");
1049490075Sobrien	  print_operand_address (file, XEXP (XEXP (x, 0), 0));
1049590075Sobrien	  fputs ("@l", file);
10496117395Skan	  /* For GNU as, there must be a non-alphanumeric character
10497117395Skan	     between 'l' and the number.  The '-' is added by
10498117395Skan	     print_operand() already.  */
10499117395Skan	  if (INTVAL (XEXP (XEXP (x, 0), 1)) >= 0)
10500117395Skan	    fputs ("+", file);
1050190075Sobrien	  print_operand (file, XEXP (XEXP (x, 0), 1), 0);
1050290075Sobrien	}
1050390075Sobrien      return;
1050490075Sobrien
1050590075Sobrien      /* %l is output_asm_label.  */
1050690075Sobrien
1050790075Sobrien    case 'L':
1050890075Sobrien      /* Write second word of DImode or DFmode reference.  Works on register
1050990075Sobrien	 or non-indexed memory only.  */
1051090075Sobrien      if (GET_CODE (x) == REG)
10511169689Skan	fputs (reg_names[REGNO (x) + 1], file);
1051290075Sobrien      else if (GET_CODE (x) == MEM)
1051390075Sobrien	{
1051490075Sobrien	  /* Handle possible auto-increment.  Since it is pre-increment and
1051590075Sobrien	     we have already done it, we can just use an offset of word.  */
1051690075Sobrien	  if (GET_CODE (XEXP (x, 0)) == PRE_INC
1051790075Sobrien	      || GET_CODE (XEXP (x, 0)) == PRE_DEC)
1051890075Sobrien	    output_address (plus_constant (XEXP (XEXP (x, 0), 0),
1051990075Sobrien					   UNITS_PER_WORD));
1052090075Sobrien	  else
1052190075Sobrien	    output_address (XEXP (adjust_address_nv (x, SImode,
1052290075Sobrien						     UNITS_PER_WORD),
1052390075Sobrien				  0));
1052490075Sobrien
1052590075Sobrien	  if (small_data_operand (x, GET_MODE (x)))
1052690075Sobrien	    fprintf (file, "@%s(%s)", SMALL_DATA_RELOC,
1052790075Sobrien		     reg_names[SMALL_DATA_REG]);
1052890075Sobrien	}
1052990075Sobrien      return;
10530169689Skan
1053190075Sobrien    case 'm':
1053290075Sobrien      /* MB value for a mask operand.  */
1053396263Sobrien      if (! mask_operand (x, SImode))
1053490075Sobrien	output_operand_lossage ("invalid %%m value");
1053590075Sobrien
10536117395Skan      fprintf (file, "%d", extract_MB (x));
1053790075Sobrien      return;
1053890075Sobrien
1053990075Sobrien    case 'M':
1054090075Sobrien      /* ME value for a mask operand.  */
1054196263Sobrien      if (! mask_operand (x, SImode))
1054290075Sobrien	output_operand_lossage ("invalid %%M value");
1054390075Sobrien
10544117395Skan      fprintf (file, "%d", extract_ME (x));
1054590075Sobrien      return;
1054690075Sobrien
1054790075Sobrien      /* %n outputs the negative of its operand.  */
1054890075Sobrien
1054990075Sobrien    case 'N':
1055090075Sobrien      /* Write the number of elements in the vector times 4.  */
1055190075Sobrien      if (GET_CODE (x) != PARALLEL)
1055290075Sobrien	output_operand_lossage ("invalid %%N value");
1055390075Sobrien      else
1055490075Sobrien	fprintf (file, "%d", XVECLEN (x, 0) * 4);
1055590075Sobrien      return;
1055690075Sobrien
1055790075Sobrien    case 'O':
1055890075Sobrien      /* Similar, but subtract 1 first.  */
1055990075Sobrien      if (GET_CODE (x) != PARALLEL)
1056090075Sobrien	output_operand_lossage ("invalid %%O value");
1056190075Sobrien      else
1056290075Sobrien	fprintf (file, "%d", (XVECLEN (x, 0) - 1) * 4);
1056390075Sobrien      return;
1056490075Sobrien
1056590075Sobrien    case 'p':
1056690075Sobrien      /* X is a CONST_INT that is a power of two.  Output the logarithm.  */
1056790075Sobrien      if (! INT_P (x)
1056890075Sobrien	  || INT_LOWPART (x) < 0
1056990075Sobrien	  || (i = exact_log2 (INT_LOWPART (x))) < 0)
1057090075Sobrien	output_operand_lossage ("invalid %%p value");
1057190075Sobrien      else
1057290075Sobrien	fprintf (file, "%d", i);
1057390075Sobrien      return;
1057490075Sobrien
1057590075Sobrien    case 'P':
1057690075Sobrien      /* The operand must be an indirect memory reference.  The result
10577146895Skan	 is the register name.  */
1057890075Sobrien      if (GET_CODE (x) != MEM || GET_CODE (XEXP (x, 0)) != REG
1057990075Sobrien	  || REGNO (XEXP (x, 0)) >= 32)
1058090075Sobrien	output_operand_lossage ("invalid %%P value");
1058190075Sobrien      else
10582169689Skan	fputs (reg_names[REGNO (XEXP (x, 0))], file);
1058390075Sobrien      return;
1058490075Sobrien
1058590075Sobrien    case 'q':
1058690075Sobrien      /* This outputs the logical code corresponding to a boolean
1058790075Sobrien	 expression.  The expression may have one or both operands
1058890075Sobrien	 negated (if one, only the first one).  For condition register
10589169689Skan	 logical operations, it will also treat the negated
10590169689Skan	 CR codes as NOTs, but not handle NOTs of them.  */
1059190075Sobrien      {
1059290075Sobrien	const char *const *t = 0;
1059390075Sobrien	const char *s;
1059490075Sobrien	enum rtx_code code = GET_CODE (x);
1059590075Sobrien	static const char * const tbl[3][3] = {
1059690075Sobrien	  { "and", "andc", "nor" },
1059790075Sobrien	  { "or", "orc", "nand" },
1059890075Sobrien	  { "xor", "eqv", "xor" } };
1059990075Sobrien
1060090075Sobrien	if (code == AND)
1060190075Sobrien	  t = tbl[0];
1060290075Sobrien	else if (code == IOR)
1060390075Sobrien	  t = tbl[1];
1060490075Sobrien	else if (code == XOR)
1060590075Sobrien	  t = tbl[2];
1060690075Sobrien	else
1060790075Sobrien	  output_operand_lossage ("invalid %%q value");
1060890075Sobrien
1060990075Sobrien	if (GET_CODE (XEXP (x, 0)) != NOT)
1061090075Sobrien	  s = t[0];
1061190075Sobrien	else
1061290075Sobrien	  {
1061390075Sobrien	    if (GET_CODE (XEXP (x, 1)) == NOT)
1061490075Sobrien	      s = t[2];
1061590075Sobrien	    else
1061690075Sobrien	      s = t[1];
1061790075Sobrien	  }
10618169689Skan
1061990075Sobrien	fputs (s, file);
1062090075Sobrien      }
1062190075Sobrien      return;
1062290075Sobrien
10623132718Skan    case 'Q':
10624132718Skan      if (TARGET_MFCRF)
10625169689Skan	fputc (',', file);
10626132718Skan        /* FALLTHRU */
10627132718Skan      else
10628132718Skan	return;
10629132718Skan
1063090075Sobrien    case 'R':
1063190075Sobrien      /* X is a CR register.  Print the mask for `mtcrf'.  */
1063290075Sobrien      if (GET_CODE (x) != REG || ! CR_REGNO_P (REGNO (x)))
1063390075Sobrien	output_operand_lossage ("invalid %%R value");
1063490075Sobrien      else
1063590075Sobrien	fprintf (file, "%d", 128 >> (REGNO (x) - CR0_REGNO));
1063690075Sobrien      return;
1063790075Sobrien
1063890075Sobrien    case 's':
1063990075Sobrien      /* Low 5 bits of 32 - value */
1064090075Sobrien      if (! INT_P (x))
1064190075Sobrien	output_operand_lossage ("invalid %%s value");
1064290075Sobrien      else
1064390075Sobrien	fprintf (file, HOST_WIDE_INT_PRINT_DEC, (32 - INT_LOWPART (x)) & 31);
1064490075Sobrien      return;
1064590075Sobrien
1064690075Sobrien    case 'S':
10647117395Skan      /* PowerPC64 mask position.  All 0's is excluded.
1064890075Sobrien	 CONST_INT 32-bit mask is considered sign-extended so any
1064990075Sobrien	 transition must occur within the CONST_INT, not on the boundary.  */
1065096263Sobrien      if (! mask64_operand (x, DImode))
1065190075Sobrien	output_operand_lossage ("invalid %%S value");
1065290075Sobrien
10653117395Skan      uval = INT_LOWPART (x);
1065490075Sobrien
10655117395Skan      if (uval & 1)	/* Clear Left */
1065690075Sobrien	{
10657132718Skan#if HOST_BITS_PER_WIDE_INT > 64
10658132718Skan	  uval &= ((unsigned HOST_WIDE_INT) 1 << 64) - 1;
10659132718Skan#endif
10660117395Skan	  i = 64;
1066190075Sobrien	}
10662117395Skan      else		/* Clear Right */
1066390075Sobrien	{
10664117395Skan	  uval = ~uval;
10665132718Skan#if HOST_BITS_PER_WIDE_INT > 64
10666132718Skan	  uval &= ((unsigned HOST_WIDE_INT) 1 << 64) - 1;
10667132718Skan#endif
10668117395Skan	  i = 63;
10669117395Skan	}
10670117395Skan      while (uval != 0)
10671117395Skan	--i, uval >>= 1;
10672169689Skan      gcc_assert (i >= 0);
10673117395Skan      fprintf (file, "%d", i);
10674117395Skan      return;
1067590075Sobrien
10676117395Skan    case 't':
10677117395Skan      /* Like 'J' but get to the OVERFLOW/UNORDERED bit.  */
10678169689Skan      gcc_assert (GET_CODE (x) == REG && GET_MODE (x) == CCmode);
1067990075Sobrien
10680117395Skan      /* Bit 3 is OV bit.  */
10681117395Skan      i = 4 * (REGNO (x) - CR0_REGNO) + 3;
1068290075Sobrien
10683117395Skan      /* If we want bit 31, write a shift count of zero, not 32.  */
10684117395Skan      fprintf (file, "%d", i == 31 ? 0 : i + 1);
10685117395Skan      return;
1068690075Sobrien
1068790075Sobrien    case 'T':
1068890075Sobrien      /* Print the symbolic name of a branch target register.  */
1068990075Sobrien      if (GET_CODE (x) != REG || (REGNO (x) != LINK_REGISTER_REGNUM
1069090075Sobrien				  && REGNO (x) != COUNT_REGISTER_REGNUM))
1069190075Sobrien	output_operand_lossage ("invalid %%T value");
1069290075Sobrien      else if (REGNO (x) == LINK_REGISTER_REGNUM)
1069390075Sobrien	fputs (TARGET_NEW_MNEMONICS ? "lr" : "r", file);
1069490075Sobrien      else
1069590075Sobrien	fputs ("ctr", file);
1069690075Sobrien      return;
1069790075Sobrien
1069890075Sobrien    case 'u':
1069990075Sobrien      /* High-order 16 bits of constant for use in unsigned operand.  */
1070090075Sobrien      if (! INT_P (x))
1070190075Sobrien	output_operand_lossage ("invalid %%u value");
1070290075Sobrien      else
10703169689Skan	fprintf (file, HOST_WIDE_INT_PRINT_HEX,
1070490075Sobrien		 (INT_LOWPART (x) >> 16) & 0xffff);
1070590075Sobrien      return;
1070690075Sobrien
1070790075Sobrien    case 'v':
1070890075Sobrien      /* High-order 16 bits of constant for use in signed operand.  */
1070990075Sobrien      if (! INT_P (x))
1071090075Sobrien	output_operand_lossage ("invalid %%v value");
1071190075Sobrien      else
1071290075Sobrien	fprintf (file, HOST_WIDE_INT_PRINT_HEX,
1071390075Sobrien		 (INT_LOWPART (x) >> 16) & 0xffff);
1071490075Sobrien      return;
1071590075Sobrien
1071690075Sobrien    case 'U':
1071790075Sobrien      /* Print `u' if this has an auto-increment or auto-decrement.  */
1071890075Sobrien      if (GET_CODE (x) == MEM
1071990075Sobrien	  && (GET_CODE (XEXP (x, 0)) == PRE_INC
1072090075Sobrien	      || GET_CODE (XEXP (x, 0)) == PRE_DEC))
1072190075Sobrien	putc ('u', file);
1072290075Sobrien      return;
1072390075Sobrien
1072490075Sobrien    case 'V':
1072590075Sobrien      /* Print the trap code for this operand.  */
1072690075Sobrien      switch (GET_CODE (x))
1072790075Sobrien	{
1072890075Sobrien	case EQ:
1072990075Sobrien	  fputs ("eq", file);   /* 4 */
1073090075Sobrien	  break;
1073190075Sobrien	case NE:
1073290075Sobrien	  fputs ("ne", file);   /* 24 */
1073390075Sobrien	  break;
1073490075Sobrien	case LT:
1073590075Sobrien	  fputs ("lt", file);   /* 16 */
1073690075Sobrien	  break;
1073790075Sobrien	case LE:
1073890075Sobrien	  fputs ("le", file);   /* 20 */
1073990075Sobrien	  break;
1074090075Sobrien	case GT:
1074190075Sobrien	  fputs ("gt", file);   /* 8 */
1074290075Sobrien	  break;
1074390075Sobrien	case GE:
1074490075Sobrien	  fputs ("ge", file);   /* 12 */
1074590075Sobrien	  break;
1074690075Sobrien	case LTU:
1074790075Sobrien	  fputs ("llt", file);  /* 2 */
1074890075Sobrien	  break;
1074990075Sobrien	case LEU:
1075090075Sobrien	  fputs ("lle", file);  /* 6 */
1075190075Sobrien	  break;
1075290075Sobrien	case GTU:
1075390075Sobrien	  fputs ("lgt", file);  /* 1 */
1075490075Sobrien	  break;
1075590075Sobrien	case GEU:
1075690075Sobrien	  fputs ("lge", file);  /* 5 */
1075790075Sobrien	  break;
1075890075Sobrien	default:
10759169689Skan	  gcc_unreachable ();
1076090075Sobrien	}
1076190075Sobrien      break;
1076290075Sobrien
1076390075Sobrien    case 'w':
1076490075Sobrien      /* If constant, low-order 16 bits of constant, signed.  Otherwise, write
1076590075Sobrien	 normally.  */
1076690075Sobrien      if (INT_P (x))
10767169689Skan	fprintf (file, HOST_WIDE_INT_PRINT_DEC,
1076890075Sobrien		 ((INT_LOWPART (x) & 0xffff) ^ 0x8000) - 0x8000);
1076990075Sobrien      else
1077090075Sobrien	print_operand (file, x, 0);
1077190075Sobrien      return;
1077290075Sobrien
1077390075Sobrien    case 'W':
1077490075Sobrien      /* MB value for a PowerPC64 rldic operand.  */
1077590075Sobrien      val = (GET_CODE (x) == CONST_INT
1077690075Sobrien	     ? INTVAL (x) : CONST_DOUBLE_HIGH (x));
1077790075Sobrien
1077890075Sobrien      if (val < 0)
1077990075Sobrien	i = -1;
1078090075Sobrien      else
1078190075Sobrien	for (i = 0; i < HOST_BITS_PER_WIDE_INT; i++)
1078290075Sobrien	  if ((val <<= 1) < 0)
1078390075Sobrien	    break;
1078490075Sobrien
1078590075Sobrien#if HOST_BITS_PER_WIDE_INT == 32
1078690075Sobrien      if (GET_CODE (x) == CONST_INT && i >= 0)
1078790075Sobrien	i += 32;  /* zero-extend high-part was all 0's */
1078890075Sobrien      else if (GET_CODE (x) == CONST_DOUBLE && i == 32)
1078990075Sobrien	{
1079090075Sobrien	  val = CONST_DOUBLE_LOW (x);
1079190075Sobrien
10792169689Skan	  gcc_assert (val);
10793169689Skan	  if (val < 0)
1079490075Sobrien	    --i;
1079590075Sobrien	  else
1079690075Sobrien	    for ( ; i < 64; i++)
1079790075Sobrien	      if ((val <<= 1) < 0)
1079890075Sobrien		break;
1079990075Sobrien	}
1080090075Sobrien#endif
1080190075Sobrien
1080290075Sobrien      fprintf (file, "%d", i + 1);
1080390075Sobrien      return;
1080490075Sobrien
1080590075Sobrien    case 'X':
1080690075Sobrien      if (GET_CODE (x) == MEM
10807132718Skan	  && legitimate_indexed_address_p (XEXP (x, 0), 0))
1080890075Sobrien	putc ('x', file);
1080990075Sobrien      return;
1081090075Sobrien
1081190075Sobrien    case 'Y':
1081290075Sobrien      /* Like 'L', for third word of TImode  */
1081390075Sobrien      if (GET_CODE (x) == REG)
10814169689Skan	fputs (reg_names[REGNO (x) + 2], file);
1081590075Sobrien      else if (GET_CODE (x) == MEM)
1081690075Sobrien	{
1081790075Sobrien	  if (GET_CODE (XEXP (x, 0)) == PRE_INC
1081890075Sobrien	      || GET_CODE (XEXP (x, 0)) == PRE_DEC)
1081990075Sobrien	    output_address (plus_constant (XEXP (XEXP (x, 0), 0), 8));
1082090075Sobrien	  else
1082190075Sobrien	    output_address (XEXP (adjust_address_nv (x, SImode, 8), 0));
1082290075Sobrien	  if (small_data_operand (x, GET_MODE (x)))
1082390075Sobrien	    fprintf (file, "@%s(%s)", SMALL_DATA_RELOC,
1082490075Sobrien		     reg_names[SMALL_DATA_REG]);
1082590075Sobrien	}
1082690075Sobrien      return;
10827169689Skan
1082890075Sobrien    case 'z':
1082990075Sobrien      /* X is a SYMBOL_REF.  Write out the name preceded by a
1083090075Sobrien	 period and without any trailing data in brackets.  Used for function
1083190075Sobrien	 names.  If we are configured for System V (or the embedded ABI) on
1083290075Sobrien	 the PowerPC, do not emit the period, since those systems do not use
1083390075Sobrien	 TOCs and the like.  */
10834169689Skan      gcc_assert (GET_CODE (x) == SYMBOL_REF);
1083590075Sobrien
10836169689Skan      /* Mark the decl as referenced so that cgraph will output the
10837169689Skan	 function.  */
10838169689Skan      if (SYMBOL_REF_DECL (x))
10839169689Skan	mark_decl_referenced (SYMBOL_REF_DECL (x));
10840169689Skan
10841169689Skan      /* For macho, check to see if we need a stub.  */
10842169689Skan      if (TARGET_MACHO)
1084390075Sobrien	{
10844169689Skan	  const char *name = XSTR (x, 0);
10845169689Skan#if TARGET_MACHO
10846169689Skan	  if (MACHOPIC_INDIRECT
10847169689Skan	      && machopic_classify_symbol (x) == MACHOPIC_UNDEFINED_FUNCTION)
10848169689Skan	    name = machopic_indirection_name (x, /*stub_p=*/true);
10849169689Skan#endif
10850169689Skan	  assemble_name (file, name);
1085190075Sobrien	}
10852169689Skan      else if (!DOT_SYMBOLS)
10853169689Skan	assemble_name (file, XSTR (x, 0));
10854132718Skan      else
10855169689Skan	rs6000_output_function_entry (file, XSTR (x, 0));
1085690075Sobrien      return;
1085790075Sobrien
1085890075Sobrien    case 'Z':
1085990075Sobrien      /* Like 'L', for last word of TImode.  */
1086090075Sobrien      if (GET_CODE (x) == REG)
10861169689Skan	fputs (reg_names[REGNO (x) + 3], file);
1086290075Sobrien      else if (GET_CODE (x) == MEM)
1086390075Sobrien	{
1086490075Sobrien	  if (GET_CODE (XEXP (x, 0)) == PRE_INC
1086590075Sobrien	      || GET_CODE (XEXP (x, 0)) == PRE_DEC)
1086690075Sobrien	    output_address (plus_constant (XEXP (XEXP (x, 0), 0), 12));
1086790075Sobrien	  else
1086890075Sobrien	    output_address (XEXP (adjust_address_nv (x, SImode, 12), 0));
1086990075Sobrien	  if (small_data_operand (x, GET_MODE (x)))
1087090075Sobrien	    fprintf (file, "@%s(%s)", SMALL_DATA_RELOC,
1087190075Sobrien		     reg_names[SMALL_DATA_REG]);
1087290075Sobrien	}
1087390075Sobrien      return;
1087490075Sobrien
10875117395Skan      /* Print AltiVec or SPE memory operand.  */
1087690075Sobrien    case 'y':
1087790075Sobrien      {
1087890075Sobrien	rtx tmp;
1087990075Sobrien
10880169689Skan	gcc_assert (GET_CODE (x) == MEM);
1088190075Sobrien
1088290075Sobrien	tmp = XEXP (x, 0);
1088390075Sobrien
10884169689Skan	/* Ugly hack because %y is overloaded.  */
10885169689Skan	if (TARGET_E500 && GET_MODE_SIZE (GET_MODE (x)) == 8)
10886117395Skan	  {
10887117395Skan	    /* Handle [reg].  */
10888117395Skan	    if (GET_CODE (tmp) == REG)
10889117395Skan	      {
10890117395Skan		fprintf (file, "0(%s)", reg_names[REGNO (tmp)]);
10891117395Skan		break;
10892117395Skan	      }
10893117395Skan	    /* Handle [reg+UIMM].  */
10894117395Skan	    else if (GET_CODE (tmp) == PLUS &&
10895117395Skan		     GET_CODE (XEXP (tmp, 1)) == CONST_INT)
10896117395Skan	      {
10897117395Skan		int x;
10898117395Skan
10899169689Skan		gcc_assert (GET_CODE (XEXP (tmp, 0)) == REG);
10900117395Skan
10901117395Skan		x = INTVAL (XEXP (tmp, 1));
10902117395Skan		fprintf (file, "%d(%s)", x, reg_names[REGNO (XEXP (tmp, 0))]);
10903117395Skan		break;
10904117395Skan	      }
10905117395Skan
10906117395Skan	    /* Fall through.  Must be [reg+reg].  */
10907117395Skan	  }
10908169689Skan	if (TARGET_ALTIVEC
10909169689Skan	    && GET_CODE (tmp) == AND
10910169689Skan	    && GET_CODE (XEXP (tmp, 1)) == CONST_INT
10911169689Skan	    && INTVAL (XEXP (tmp, 1)) == -16)
10912169689Skan	  tmp = XEXP (tmp, 0);
1091390075Sobrien	if (GET_CODE (tmp) == REG)
1091490075Sobrien	  fprintf (file, "0,%s", reg_names[REGNO (tmp)]);
10915169689Skan	else
1091690075Sobrien	  {
10917169689Skan	    gcc_assert (GET_CODE (tmp) == PLUS
10918169689Skan			&& REG_P (XEXP (tmp, 0))
10919169689Skan			&& REG_P (XEXP (tmp, 1)));
10920169689Skan
1092190075Sobrien	    if (REGNO (XEXP (tmp, 0)) == 0)
1092290075Sobrien	      fprintf (file, "%s,%s", reg_names[ REGNO (XEXP (tmp, 1)) ],
1092390075Sobrien		       reg_names[ REGNO (XEXP (tmp, 0)) ]);
1092490075Sobrien	    else
1092590075Sobrien	      fprintf (file, "%s,%s", reg_names[ REGNO (XEXP (tmp, 0)) ],
1092690075Sobrien		       reg_names[ REGNO (XEXP (tmp, 1)) ]);
1092790075Sobrien	  }
1092890075Sobrien	break;
1092990075Sobrien      }
10930169689Skan
1093190075Sobrien    case 0:
1093290075Sobrien      if (GET_CODE (x) == REG)
1093390075Sobrien	fprintf (file, "%s", reg_names[REGNO (x)]);
1093490075Sobrien      else if (GET_CODE (x) == MEM)
1093590075Sobrien	{
1093690075Sobrien	  /* We need to handle PRE_INC and PRE_DEC here, since we need to
1093790075Sobrien	     know the width from the mode.  */
1093890075Sobrien	  if (GET_CODE (XEXP (x, 0)) == PRE_INC)
1093990075Sobrien	    fprintf (file, "%d(%s)", GET_MODE_SIZE (GET_MODE (x)),
1094090075Sobrien		     reg_names[REGNO (XEXP (XEXP (x, 0), 0))]);
1094190075Sobrien	  else if (GET_CODE (XEXP (x, 0)) == PRE_DEC)
1094290075Sobrien	    fprintf (file, "%d(%s)", - GET_MODE_SIZE (GET_MODE (x)),
1094390075Sobrien		     reg_names[REGNO (XEXP (XEXP (x, 0), 0))]);
1094490075Sobrien	  else
1094590075Sobrien	    output_address (XEXP (x, 0));
1094690075Sobrien	}
1094790075Sobrien      else
1094890075Sobrien	output_addr_const (file, x);
1094990075Sobrien      return;
1095090075Sobrien
10951132718Skan    case '&':
10952132718Skan      assemble_name (file, rs6000_get_some_local_dynamic_name ());
10953132718Skan      return;
10954132718Skan
1095590075Sobrien    default:
1095690075Sobrien      output_operand_lossage ("invalid %%xn code");
1095790075Sobrien    }
1095890075Sobrien}
1095990075Sobrien
1096090075Sobrien/* Print the address of an operand.  */
1096190075Sobrien
1096290075Sobrienvoid
10963132718Skanprint_operand_address (FILE *file, rtx x)
1096490075Sobrien{
1096590075Sobrien  if (GET_CODE (x) == REG)
1096690075Sobrien    fprintf (file, "0(%s)", reg_names[ REGNO (x) ]);
1096790075Sobrien  else if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == CONST
1096890075Sobrien	   || GET_CODE (x) == LABEL_REF)
1096990075Sobrien    {
1097090075Sobrien      output_addr_const (file, x);
1097190075Sobrien      if (small_data_operand (x, GET_MODE (x)))
1097290075Sobrien	fprintf (file, "@%s(%s)", SMALL_DATA_RELOC,
1097390075Sobrien		 reg_names[SMALL_DATA_REG]);
10974169689Skan      else
10975169689Skan	gcc_assert (!TARGET_TOC);
1097690075Sobrien    }
1097790075Sobrien  else if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == REG)
1097890075Sobrien    {
10979169689Skan      gcc_assert (REG_P (XEXP (x, 0)));
1098090075Sobrien      if (REGNO (XEXP (x, 0)) == 0)
1098190075Sobrien	fprintf (file, "%s,%s", reg_names[ REGNO (XEXP (x, 1)) ],
1098290075Sobrien		 reg_names[ REGNO (XEXP (x, 0)) ]);
1098390075Sobrien      else
1098490075Sobrien	fprintf (file, "%s,%s", reg_names[ REGNO (XEXP (x, 0)) ],
1098590075Sobrien		 reg_names[ REGNO (XEXP (x, 1)) ]);
1098690075Sobrien    }
1098790075Sobrien  else if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
10988132718Skan    fprintf (file, HOST_WIDE_INT_PRINT_DEC "(%s)",
10989132718Skan	     INTVAL (XEXP (x, 1)), reg_names[ REGNO (XEXP (x, 0)) ]);
1099090075Sobrien#if TARGET_ELF
1099190075Sobrien  else if (GET_CODE (x) == LO_SUM && GET_CODE (XEXP (x, 0)) == REG
10992169689Skan	   && CONSTANT_P (XEXP (x, 1)))
1099390075Sobrien    {
1099490075Sobrien      output_addr_const (file, XEXP (x, 1));
1099590075Sobrien      fprintf (file, "@l(%s)", reg_names[ REGNO (XEXP (x, 0)) ]);
1099690075Sobrien    }
1099790075Sobrien#endif
1099890075Sobrien#if TARGET_MACHO
1099990075Sobrien  else if (GET_CODE (x) == LO_SUM && GET_CODE (XEXP (x, 0)) == REG
11000169689Skan	   && CONSTANT_P (XEXP (x, 1)))
1100190075Sobrien    {
1100290075Sobrien      fprintf (file, "lo16(");
1100390075Sobrien      output_addr_const (file, XEXP (x, 1));
1100490075Sobrien      fprintf (file, ")(%s)", reg_names[ REGNO (XEXP (x, 0)) ]);
1100590075Sobrien    }
1100690075Sobrien#endif
11007132718Skan  else if (legitimate_constant_pool_address_p (x))
1100890075Sobrien    {
1100990075Sobrien      if (TARGET_AIX && (!TARGET_ELF || !TARGET_MINIMAL_TOC))
1101090075Sobrien	{
1101190075Sobrien	  rtx contains_minus = XEXP (x, 1);
1101290075Sobrien	  rtx minus, symref;
1101390075Sobrien	  const char *name;
11014169689Skan
1101590075Sobrien	  /* Find the (minus (sym) (toc)) buried in X, and temporarily
1101690075Sobrien	     turn it into (sym) for output_addr_const.  */
1101790075Sobrien	  while (GET_CODE (XEXP (contains_minus, 0)) != MINUS)
1101890075Sobrien	    contains_minus = XEXP (contains_minus, 0);
1101990075Sobrien
1102090075Sobrien	  minus = XEXP (contains_minus, 0);
1102190075Sobrien	  symref = XEXP (minus, 0);
1102290075Sobrien	  XEXP (contains_minus, 0) = symref;
1102390075Sobrien	  if (TARGET_ELF)
1102490075Sobrien	    {
1102590075Sobrien	      char *newname;
1102690075Sobrien
1102790075Sobrien	      name = XSTR (symref, 0);
1102890075Sobrien	      newname = alloca (strlen (name) + sizeof ("@toc"));
1102990075Sobrien	      strcpy (newname, name);
1103090075Sobrien	      strcat (newname, "@toc");
1103190075Sobrien	      XSTR (symref, 0) = newname;
1103290075Sobrien	    }
1103390075Sobrien	  output_addr_const (file, XEXP (x, 1));
1103490075Sobrien	  if (TARGET_ELF)
1103590075Sobrien	    XSTR (symref, 0) = name;
1103690075Sobrien	  XEXP (contains_minus, 0) = minus;
1103790075Sobrien	}
1103890075Sobrien      else
1103990075Sobrien	output_addr_const (file, XEXP (x, 1));
1104090075Sobrien
1104190075Sobrien      fprintf (file, "(%s)", reg_names[REGNO (XEXP (x, 0))]);
1104290075Sobrien    }
1104390075Sobrien  else
11044169689Skan    gcc_unreachable ();
1104590075Sobrien}
1104690075Sobrien
11047117395Skan/* Target hook for assembling integer objects.  The PowerPC version has
1104890075Sobrien   to handle fixup entries for relocatable code if RELOCATABLE_NEEDS_FIXUP
1104990075Sobrien   is defined.  It also needs to handle DI-mode objects on 64-bit
1105090075Sobrien   targets.  */
1105190075Sobrien
1105290075Sobrienstatic bool
11053132718Skanrs6000_assemble_integer (rtx x, unsigned int size, int aligned_p)
1105490075Sobrien{
1105590075Sobrien#ifdef RELOCATABLE_NEEDS_FIXUP
1105690075Sobrien  /* Special handling for SI values.  */
11057146895Skan  if (RELOCATABLE_NEEDS_FIXUP && size == 4 && aligned_p)
1105890075Sobrien    {
1105990075Sobrien      static int recurse = 0;
11060169689Skan
1106190075Sobrien      /* For -mrelocatable, we mark all addresses that need to be fixed up
1106290075Sobrien	 in the .fixup section.  */
1106390075Sobrien      if (TARGET_RELOCATABLE
11064169689Skan	  && in_section != toc_section
11065169689Skan	  && in_section != text_section
11066169689Skan	  && !unlikely_text_section_p (in_section)
1106790075Sobrien	  && !recurse
1106890075Sobrien	  && GET_CODE (x) != CONST_INT
1106990075Sobrien	  && GET_CODE (x) != CONST_DOUBLE
1107090075Sobrien	  && CONSTANT_P (x))
1107190075Sobrien	{
1107290075Sobrien	  char buf[256];
1107390075Sobrien
1107490075Sobrien	  recurse = 1;
1107590075Sobrien	  ASM_GENERATE_INTERNAL_LABEL (buf, "LCP", fixuplabelno);
1107690075Sobrien	  fixuplabelno++;
1107790075Sobrien	  ASM_OUTPUT_LABEL (asm_out_file, buf);
1107890075Sobrien	  fprintf (asm_out_file, "\t.long\t(");
1107990075Sobrien	  output_addr_const (asm_out_file, x);
1108090075Sobrien	  fprintf (asm_out_file, ")@fixup\n");
1108190075Sobrien	  fprintf (asm_out_file, "\t.section\t\".fixup\",\"aw\"\n");
1108290075Sobrien	  ASM_OUTPUT_ALIGN (asm_out_file, 2);
1108390075Sobrien	  fprintf (asm_out_file, "\t.long\t");
1108490075Sobrien	  assemble_name (asm_out_file, buf);
1108590075Sobrien	  fprintf (asm_out_file, "\n\t.previous\n");
1108690075Sobrien	  recurse = 0;
1108790075Sobrien	  return true;
1108890075Sobrien	}
1108990075Sobrien      /* Remove initial .'s to turn a -mcall-aixdesc function
1109090075Sobrien	 address into the address of the descriptor, not the function
1109190075Sobrien	 itself.  */
1109290075Sobrien      else if (GET_CODE (x) == SYMBOL_REF
1109390075Sobrien	       && XSTR (x, 0)[0] == '.'
1109490075Sobrien	       && DEFAULT_ABI == ABI_AIX)
1109590075Sobrien	{
1109690075Sobrien	  const char *name = XSTR (x, 0);
1109790075Sobrien	  while (*name == '.')
1109890075Sobrien	    name++;
1109990075Sobrien
1110090075Sobrien	  fprintf (asm_out_file, "\t.long\t%s\n", name);
1110190075Sobrien	  return true;
1110290075Sobrien	}
1110390075Sobrien    }
1110490075Sobrien#endif /* RELOCATABLE_NEEDS_FIXUP */
1110590075Sobrien  return default_assemble_integer (x, size, aligned_p);
1110690075Sobrien}
11107117395Skan
11108117395Skan#ifdef HAVE_GAS_HIDDEN
11109117395Skan/* Emit an assembler directive to set symbol visibility for DECL to
11110117395Skan   VISIBILITY_TYPE.  */
11111117395Skan
11112117395Skanstatic void
11113132718Skanrs6000_assemble_visibility (tree decl, int vis)
11114117395Skan{
11115117395Skan  /* Functions need to have their entry point symbol visibility set as
11116117395Skan     well as their descriptor symbol visibility.  */
11117169689Skan  if (DEFAULT_ABI == ABI_AIX
11118169689Skan      && DOT_SYMBOLS
11119169689Skan      && TREE_CODE (decl) == FUNCTION_DECL)
11120117395Skan    {
11121117395Skan      static const char * const visibility_types[] = {
11122169689Skan	NULL, "internal", "hidden", "protected"
11123117395Skan      };
11124117395Skan
11125117395Skan      const char *name, *type;
11126117395Skan
11127117395Skan      name = ((* targetm.strip_name_encoding)
11128117395Skan	      (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl))));
11129117395Skan      type = visibility_types[vis];
11130117395Skan
11131117395Skan      fprintf (asm_out_file, "\t.%s\t%s\n", type, name);
11132117395Skan      fprintf (asm_out_file, "\t.%s\t.%s\n", type, name);
11133117395Skan    }
11134117395Skan  else
11135117395Skan    default_assemble_visibility (decl, vis);
11136117395Skan}
11137117395Skan#endif
1113890075Sobrien
1113990075Sobrienenum rtx_code
11140132718Skanrs6000_reverse_condition (enum machine_mode mode, enum rtx_code code)
1114190075Sobrien{
1114290075Sobrien  /* Reversal of FP compares takes care -- an ordered compare
1114390075Sobrien     becomes an unordered compare and vice versa.  */
11144169689Skan  if (mode == CCFPmode
11145132718Skan      && (!flag_finite_math_only
11146132718Skan	  || code == UNLT || code == UNLE || code == UNGT || code == UNGE
11147132718Skan	  || code == UNEQ || code == LTGT))
1114890075Sobrien    return reverse_condition_maybe_unordered (code);
1114990075Sobrien  else
1115090075Sobrien    return reverse_condition (code);
1115190075Sobrien}
1115290075Sobrien
1115390075Sobrien/* Generate a compare for CODE.  Return a brand-new rtx that
1115490075Sobrien   represents the result of the compare.  */
1115590075Sobrien
1115690075Sobrienstatic rtx
11157132718Skanrs6000_generate_compare (enum rtx_code code)
1115890075Sobrien{
1115990075Sobrien  enum machine_mode comp_mode;
1116090075Sobrien  rtx compare_result;
1116190075Sobrien
1116290075Sobrien  if (rs6000_compare_fp_p)
1116390075Sobrien    comp_mode = CCFPmode;
1116490075Sobrien  else if (code == GTU || code == LTU
11165169689Skan	   || code == GEU || code == LEU)
1116690075Sobrien    comp_mode = CCUNSmode;
11167169689Skan  else if ((code == EQ || code == NE)
11168169689Skan	   && GET_CODE (rs6000_compare_op0) == SUBREG
11169169689Skan	   && GET_CODE (rs6000_compare_op1) == SUBREG
11170169689Skan	   && SUBREG_PROMOTED_UNSIGNED_P (rs6000_compare_op0)
11171169689Skan	   && SUBREG_PROMOTED_UNSIGNED_P (rs6000_compare_op1))
11172169689Skan    /* These are unsigned values, perhaps there will be a later
11173169689Skan       ordering compare that can be shared with this one.
11174169689Skan       Unfortunately we cannot detect the signedness of the operands
11175169689Skan       for non-subregs.  */
11176169689Skan    comp_mode = CCUNSmode;
1117790075Sobrien  else
1117890075Sobrien    comp_mode = CCmode;
1117990075Sobrien
1118090075Sobrien  /* First, the compare.  */
1118190075Sobrien  compare_result = gen_reg_rtx (comp_mode);
11182117395Skan
11183169689Skan  /* E500 FP compare instructions on the GPRs.  Yuck!  */
11184132718Skan  if ((TARGET_E500 && !TARGET_FPRS && TARGET_HARD_FLOAT)
11185132718Skan      && rs6000_compare_fp_p)
11186117395Skan    {
11187169689Skan      rtx cmp, or_result, compare_result2;
11188169689Skan      enum machine_mode op_mode = GET_MODE (rs6000_compare_op0);
11189117395Skan
11190169689Skan      if (op_mode == VOIDmode)
11191169689Skan	op_mode = GET_MODE (rs6000_compare_op1);
11192132718Skan
11193169689Skan      /* The E500 FP compare instructions toggle the GT bit (CR bit 1) only.
11194169689Skan	 This explains the following mess.  */
11195169689Skan
11196117395Skan      switch (code)
11197117395Skan	{
11198169689Skan	case EQ: case UNEQ: case NE: case LTGT:
11199169689Skan	  switch (op_mode)
11200169689Skan	    {
11201169689Skan	    case SFmode:
11202169689Skan	      cmp = flag_unsafe_math_optimizations
11203169689Skan		? gen_tstsfeq_gpr (compare_result, rs6000_compare_op0,
11204169689Skan				   rs6000_compare_op1)
11205169689Skan		: gen_cmpsfeq_gpr (compare_result, rs6000_compare_op0,
11206169689Skan				   rs6000_compare_op1);
11207169689Skan	      break;
11208169689Skan
11209169689Skan	    case DFmode:
11210169689Skan	      cmp = flag_unsafe_math_optimizations
11211169689Skan		? gen_tstdfeq_gpr (compare_result, rs6000_compare_op0,
11212169689Skan				   rs6000_compare_op1)
11213169689Skan		: gen_cmpdfeq_gpr (compare_result, rs6000_compare_op0,
11214169689Skan				   rs6000_compare_op1);
11215169689Skan	      break;
11216169689Skan
11217169689Skan	    default:
11218169689Skan	      gcc_unreachable ();
11219169689Skan	    }
11220117395Skan	  break;
11221169689Skan
11222169689Skan	case GT: case GTU: case UNGT: case UNGE: case GE: case GEU:
11223169689Skan	  switch (op_mode)
11224169689Skan	    {
11225169689Skan	    case SFmode:
11226169689Skan	      cmp = flag_unsafe_math_optimizations
11227169689Skan		? gen_tstsfgt_gpr (compare_result, rs6000_compare_op0,
11228169689Skan				   rs6000_compare_op1)
11229169689Skan		: gen_cmpsfgt_gpr (compare_result, rs6000_compare_op0,
11230169689Skan				   rs6000_compare_op1);
11231169689Skan	      break;
11232169689Skan
11233169689Skan	    case DFmode:
11234169689Skan	      cmp = flag_unsafe_math_optimizations
11235169689Skan		? gen_tstdfgt_gpr (compare_result, rs6000_compare_op0,
11236169689Skan				   rs6000_compare_op1)
11237169689Skan		: gen_cmpdfgt_gpr (compare_result, rs6000_compare_op0,
11238169689Skan				   rs6000_compare_op1);
11239169689Skan	      break;
11240169689Skan
11241169689Skan	    default:
11242169689Skan	      gcc_unreachable ();
11243169689Skan	    }
11244117395Skan	  break;
11245169689Skan
11246169689Skan	case LT: case LTU: case UNLT: case UNLE: case LE: case LEU:
11247169689Skan	  switch (op_mode)
11248169689Skan	    {
11249169689Skan	    case SFmode:
11250169689Skan	      cmp = flag_unsafe_math_optimizations
11251169689Skan		? gen_tstsflt_gpr (compare_result, rs6000_compare_op0,
11252169689Skan				   rs6000_compare_op1)
11253169689Skan		: gen_cmpsflt_gpr (compare_result, rs6000_compare_op0,
11254169689Skan				   rs6000_compare_op1);
11255169689Skan	      break;
11256169689Skan
11257169689Skan	    case DFmode:
11258169689Skan	      cmp = flag_unsafe_math_optimizations
11259169689Skan		? gen_tstdflt_gpr (compare_result, rs6000_compare_op0,
11260169689Skan				   rs6000_compare_op1)
11261169689Skan		: gen_cmpdflt_gpr (compare_result, rs6000_compare_op0,
11262169689Skan				   rs6000_compare_op1);
11263169689Skan	      break;
11264169689Skan
11265169689Skan	    default:
11266169689Skan	      gcc_unreachable ();
11267169689Skan	    }
11268117395Skan	  break;
11269169689Skan        default:
11270169689Skan          gcc_unreachable ();
11271117395Skan	}
11272117395Skan
11273117395Skan      /* Synthesize LE and GE from LT/GT || EQ.  */
11274117395Skan      if (code == LE || code == GE || code == LEU || code == GEU)
11275117395Skan	{
11276117395Skan	  emit_insn (cmp);
11277117395Skan
11278117395Skan	  switch (code)
11279117395Skan	    {
11280117395Skan	    case LE: code = LT; break;
11281117395Skan	    case GE: code = GT; break;
11282117395Skan	    case LEU: code = LT; break;
11283117395Skan	    case GEU: code = GT; break;
11284169689Skan	    default: gcc_unreachable ();
11285117395Skan	    }
11286117395Skan
11287117395Skan	  compare_result2 = gen_reg_rtx (CCFPmode);
11288117395Skan
11289117395Skan	  /* Do the EQ.  */
11290169689Skan	  switch (op_mode)
11291169689Skan	    {
11292169689Skan	    case SFmode:
11293169689Skan	      cmp = flag_unsafe_math_optimizations
11294169689Skan		? gen_tstsfeq_gpr (compare_result2, rs6000_compare_op0,
11295169689Skan				   rs6000_compare_op1)
11296169689Skan		: gen_cmpsfeq_gpr (compare_result2, rs6000_compare_op0,
11297169689Skan				   rs6000_compare_op1);
11298169689Skan	      break;
11299169689Skan
11300169689Skan	    case DFmode:
11301169689Skan	      cmp = flag_unsafe_math_optimizations
11302169689Skan		? gen_tstdfeq_gpr (compare_result2, rs6000_compare_op0,
11303169689Skan				   rs6000_compare_op1)
11304169689Skan		: gen_cmpdfeq_gpr (compare_result2, rs6000_compare_op0,
11305169689Skan				   rs6000_compare_op1);
11306169689Skan	      break;
11307169689Skan
11308169689Skan	    default:
11309169689Skan	      gcc_unreachable ();
11310169689Skan	    }
11311117395Skan	  emit_insn (cmp);
11312117395Skan
11313117395Skan	  /* OR them together.  */
11314169689Skan	  or_result = gen_reg_rtx (CCFPmode);
11315169689Skan	  cmp = gen_e500_cr_ior_compare (or_result, compare_result,
11316169689Skan					   compare_result2);
11317117395Skan	  compare_result = or_result;
11318117395Skan	  code = EQ;
11319117395Skan	}
11320117395Skan      else
11321117395Skan	{
11322117395Skan	  if (code == NE || code == LTGT)
11323117395Skan	    code = NE;
11324169689Skan	  else
11325169689Skan	    code = EQ;
11326117395Skan	}
11327117395Skan
11328117395Skan      emit_insn (cmp);
11329117395Skan    }
11330117395Skan  else
11331146895Skan    {
11332146895Skan      /* Generate XLC-compatible TFmode compare as PARALLEL with extra
11333169689Skan	 CLOBBERs to match cmptf_internal2 pattern.  */
11334146895Skan      if (comp_mode == CCFPmode && TARGET_XL_COMPAT
11335169689Skan	  && GET_MODE (rs6000_compare_op0) == TFmode
11336169689Skan	  && !TARGET_IEEEQUAD
11337169689Skan	  && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128)
11338169689Skan	emit_insn (gen_rtx_PARALLEL (VOIDmode,
11339169689Skan	  gen_rtvec (9,
11340146895Skan		     gen_rtx_SET (VOIDmode,
11341146895Skan				  compare_result,
11342146895Skan				  gen_rtx_COMPARE (comp_mode,
11343146895Skan						   rs6000_compare_op0,
11344146895Skan						   rs6000_compare_op1)),
11345146895Skan		     gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
11346146895Skan		     gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
11347146895Skan		     gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
11348146895Skan		     gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
11349146895Skan		     gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
11350146895Skan		     gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
11351146895Skan		     gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
11352146895Skan		     gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)))));
11353169689Skan      else if (GET_CODE (rs6000_compare_op1) == UNSPEC
11354169689Skan	       && XINT (rs6000_compare_op1, 1) == UNSPEC_SP_TEST)
11355169689Skan	{
11356169689Skan	  rtx op1 = XVECEXP (rs6000_compare_op1, 0, 0);
11357169689Skan	  comp_mode = CCEQmode;
11358169689Skan	  compare_result = gen_reg_rtx (CCEQmode);
11359169689Skan	  if (TARGET_64BIT)
11360169689Skan	    emit_insn (gen_stack_protect_testdi (compare_result,
11361169689Skan						 rs6000_compare_op0, op1));
11362169689Skan	  else
11363169689Skan	    emit_insn (gen_stack_protect_testsi (compare_result,
11364169689Skan						 rs6000_compare_op0, op1));
11365169689Skan	}
11366146895Skan      else
11367146895Skan	emit_insn (gen_rtx_SET (VOIDmode, compare_result,
11368146895Skan				gen_rtx_COMPARE (comp_mode,
11369169689Skan						 rs6000_compare_op0,
11370146895Skan						 rs6000_compare_op1)));
11371146895Skan    }
11372169689Skan
1137390075Sobrien  /* Some kinds of FP comparisons need an OR operation;
11374132718Skan     under flag_finite_math_only we don't bother.  */
1137590075Sobrien  if (rs6000_compare_fp_p
11376169689Skan      && !flag_finite_math_only
11377169689Skan      && !(TARGET_HARD_FLOAT && TARGET_E500 && !TARGET_FPRS)
1137890075Sobrien      && (code == LE || code == GE
1137990075Sobrien	  || code == UNEQ || code == LTGT
1138090075Sobrien	  || code == UNGT || code == UNLT))
1138190075Sobrien    {
1138290075Sobrien      enum rtx_code or1, or2;
1138390075Sobrien      rtx or1_rtx, or2_rtx, compare2_rtx;
1138490075Sobrien      rtx or_result = gen_reg_rtx (CCEQmode);
11385169689Skan
1138690075Sobrien      switch (code)
1138790075Sobrien	{
1138890075Sobrien	case LE: or1 = LT;  or2 = EQ;  break;
1138990075Sobrien	case GE: or1 = GT;  or2 = EQ;  break;
1139090075Sobrien	case UNEQ: or1 = UNORDERED;  or2 = EQ;  break;
1139190075Sobrien	case LTGT: or1 = LT;  or2 = GT;  break;
1139290075Sobrien	case UNGT: or1 = UNORDERED;  or2 = GT;  break;
1139390075Sobrien	case UNLT: or1 = UNORDERED;  or2 = LT;  break;
11394169689Skan	default:  gcc_unreachable ();
1139590075Sobrien	}
1139690075Sobrien      validate_condition_mode (or1, comp_mode);
1139790075Sobrien      validate_condition_mode (or2, comp_mode);
11398169689Skan      or1_rtx = gen_rtx_fmt_ee (or1, SImode, compare_result, const0_rtx);
11399169689Skan      or2_rtx = gen_rtx_fmt_ee (or2, SImode, compare_result, const0_rtx);
1140090075Sobrien      compare2_rtx = gen_rtx_COMPARE (CCEQmode,
1140190075Sobrien				      gen_rtx_IOR (SImode, or1_rtx, or2_rtx),
1140290075Sobrien				      const_true_rtx);
1140390075Sobrien      emit_insn (gen_rtx_SET (VOIDmode, or_result, compare2_rtx));
1140490075Sobrien
1140590075Sobrien      compare_result = or_result;
1140690075Sobrien      code = EQ;
1140790075Sobrien    }
1140890075Sobrien
1140990075Sobrien  validate_condition_mode (code, GET_MODE (compare_result));
11410169689Skan
11411169689Skan  return gen_rtx_fmt_ee (code, VOIDmode, compare_result, const0_rtx);
1141290075Sobrien}
1141390075Sobrien
1141490075Sobrien
1141590075Sobrien/* Emit the RTL for an sCOND pattern.  */
1141690075Sobrien
1141790075Sobrienvoid
11418132718Skanrs6000_emit_sCOND (enum rtx_code code, rtx result)
1141990075Sobrien{
1142090075Sobrien  rtx condition_rtx;
1142190075Sobrien  enum machine_mode op_mode;
11422132718Skan  enum rtx_code cond_code;
1142390075Sobrien
1142490075Sobrien  condition_rtx = rs6000_generate_compare (code);
11425132718Skan  cond_code = GET_CODE (condition_rtx);
1142690075Sobrien
11427132718Skan  if (TARGET_E500 && rs6000_compare_fp_p
11428132718Skan      && !TARGET_FPRS && TARGET_HARD_FLOAT)
11429132718Skan    {
11430132718Skan      rtx t;
11431132718Skan
11432132718Skan      PUT_MODE (condition_rtx, SImode);
11433132718Skan      t = XEXP (condition_rtx, 0);
11434132718Skan
11435169689Skan      gcc_assert (cond_code == NE || cond_code == EQ);
11436132718Skan
11437132718Skan      if (cond_code == NE)
11438169689Skan	emit_insn (gen_e500_flip_gt_bit (t, t));
11439132718Skan
11440169689Skan      emit_insn (gen_move_from_CR_gt_bit (result, t));
11441132718Skan      return;
11442132718Skan    }
11443132718Skan
11444132718Skan  if (cond_code == NE
11445132718Skan      || cond_code == GE || cond_code == LE
11446132718Skan      || cond_code == GEU || cond_code == LEU
11447132718Skan      || cond_code == ORDERED || cond_code == UNGE || cond_code == UNLE)
11448132718Skan    {
11449132718Skan      rtx not_result = gen_reg_rtx (CCEQmode);
11450132718Skan      rtx not_op, rev_cond_rtx;
11451132718Skan      enum machine_mode cc_mode;
11452169689Skan
11453132718Skan      cc_mode = GET_MODE (XEXP (condition_rtx, 0));
11454132718Skan
11455169689Skan      rev_cond_rtx = gen_rtx_fmt_ee (rs6000_reverse_condition (cc_mode, cond_code),
11456169689Skan				     SImode, XEXP (condition_rtx, 0), const0_rtx);
11457132718Skan      not_op = gen_rtx_COMPARE (CCEQmode, rev_cond_rtx, const0_rtx);
11458132718Skan      emit_insn (gen_rtx_SET (VOIDmode, not_result, not_op));
11459132718Skan      condition_rtx = gen_rtx_EQ (VOIDmode, not_result, const0_rtx);
11460132718Skan    }
11461132718Skan
1146290075Sobrien  op_mode = GET_MODE (rs6000_compare_op0);
1146390075Sobrien  if (op_mode == VOIDmode)
1146490075Sobrien    op_mode = GET_MODE (rs6000_compare_op1);
1146590075Sobrien
1146690075Sobrien  if (TARGET_POWERPC64 && (op_mode == DImode || rs6000_compare_fp_p))
1146790075Sobrien    {
1146890075Sobrien      PUT_MODE (condition_rtx, DImode);
1146990075Sobrien      convert_move (result, condition_rtx, 0);
1147090075Sobrien    }
1147190075Sobrien  else
1147290075Sobrien    {
1147390075Sobrien      PUT_MODE (condition_rtx, SImode);
1147490075Sobrien      emit_insn (gen_rtx_SET (VOIDmode, result, condition_rtx));
1147590075Sobrien    }
1147690075Sobrien}
1147790075Sobrien
1147890075Sobrien/* Emit a branch of kind CODE to location LOC.  */
1147990075Sobrien
1148090075Sobrienvoid
11481132718Skanrs6000_emit_cbranch (enum rtx_code code, rtx loc)
1148290075Sobrien{
1148390075Sobrien  rtx condition_rtx, loc_ref;
1148490075Sobrien
1148590075Sobrien  condition_rtx = rs6000_generate_compare (code);
1148690075Sobrien  loc_ref = gen_rtx_LABEL_REF (VOIDmode, loc);
1148790075Sobrien  emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx,
1148890075Sobrien			       gen_rtx_IF_THEN_ELSE (VOIDmode, condition_rtx,
1148990075Sobrien						     loc_ref, pc_rtx)));
1149090075Sobrien}
1149190075Sobrien
1149290075Sobrien/* Return the string to output a conditional branch to LABEL, which is
1149390075Sobrien   the operand number of the label, or -1 if the branch is really a
11494169689Skan   conditional return.
1149590075Sobrien
1149690075Sobrien   OP is the conditional expression.  XEXP (OP, 0) is assumed to be a
1149790075Sobrien   condition code register and its mode specifies what kind of
1149890075Sobrien   comparison we made.
1149990075Sobrien
11500117395Skan   REVERSED is nonzero if we should reverse the sense of the comparison.
1150190075Sobrien
1150290075Sobrien   INSN is the insn.  */
1150390075Sobrien
1150490075Sobrienchar *
11505132718Skanoutput_cbranch (rtx op, const char *label, int reversed, rtx insn)
1150690075Sobrien{
1150790075Sobrien  static char string[64];
1150890075Sobrien  enum rtx_code code = GET_CODE (op);
1150990075Sobrien  rtx cc_reg = XEXP (op, 0);
1151090075Sobrien  enum machine_mode mode = GET_MODE (cc_reg);
1151190075Sobrien  int cc_regno = REGNO (cc_reg) - CR0_REGNO;
1151290075Sobrien  int need_longbranch = label != NULL && get_attr_length (insn) == 8;
1151390075Sobrien  int really_reversed = reversed ^ need_longbranch;
1151490075Sobrien  char *s = string;
1151590075Sobrien  const char *ccode;
1151690075Sobrien  const char *pred;
1151790075Sobrien  rtx note;
1151890075Sobrien
1151990075Sobrien  validate_condition_mode (code, mode);
1152090075Sobrien
1152190075Sobrien  /* Work out which way this really branches.  We could use
1152290075Sobrien     reverse_condition_maybe_unordered here always but this
1152390075Sobrien     makes the resulting assembler clearer.  */
1152490075Sobrien  if (really_reversed)
11525107590Sobrien    {
11526107590Sobrien      /* Reversal of FP compares takes care -- an ordered compare
11527107590Sobrien	 becomes an unordered compare and vice versa.  */
11528107590Sobrien      if (mode == CCFPmode)
11529107590Sobrien	code = reverse_condition_maybe_unordered (code);
11530107590Sobrien      else
11531107590Sobrien	code = reverse_condition (code);
11532107590Sobrien    }
1153390075Sobrien
11534132718Skan  if ((TARGET_E500 && !TARGET_FPRS && TARGET_HARD_FLOAT) && mode == CCFPmode)
11535117395Skan    {
11536117395Skan      /* The efscmp/tst* instructions twiddle bit 2, which maps nicely
11537117395Skan	 to the GT bit.  */
11538169689Skan      switch (code)
11539169689Skan	{
11540169689Skan	case EQ:
11541169689Skan	  /* Opposite of GT.  */
11542169689Skan	  code = GT;
11543169689Skan	  break;
11544169689Skan
11545169689Skan	case NE:
11546169689Skan	  code = UNLE;
11547169689Skan	  break;
11548169689Skan
11549169689Skan	default:
11550169689Skan	  gcc_unreachable ();
11551169689Skan	}
11552117395Skan    }
11553117395Skan
1155490075Sobrien  switch (code)
1155590075Sobrien    {
1155690075Sobrien      /* Not all of these are actually distinct opcodes, but
1155790075Sobrien	 we distinguish them for clarity of the resulting assembler.  */
1155890075Sobrien    case NE: case LTGT:
1155990075Sobrien      ccode = "ne"; break;
1156090075Sobrien    case EQ: case UNEQ:
1156190075Sobrien      ccode = "eq"; break;
11562169689Skan    case GE: case GEU:
1156390075Sobrien      ccode = "ge"; break;
11564169689Skan    case GT: case GTU: case UNGT:
1156590075Sobrien      ccode = "gt"; break;
11566169689Skan    case LE: case LEU:
1156790075Sobrien      ccode = "le"; break;
11568169689Skan    case LT: case LTU: case UNLT:
1156990075Sobrien      ccode = "lt"; break;
1157090075Sobrien    case UNORDERED: ccode = "un"; break;
1157190075Sobrien    case ORDERED: ccode = "nu"; break;
1157290075Sobrien    case UNGE: ccode = "nl"; break;
1157390075Sobrien    case UNLE: ccode = "ng"; break;
1157490075Sobrien    default:
11575169689Skan      gcc_unreachable ();
1157690075Sobrien    }
11577169689Skan
11578169689Skan  /* Maybe we have a guess as to how likely the branch is.
1157990075Sobrien     The old mnemonics don't have a way to specify this information.  */
11580117395Skan  pred = "";
1158190075Sobrien  note = find_reg_note (insn, REG_BR_PROB, NULL_RTX);
1158290075Sobrien  if (note != NULL_RTX)
1158390075Sobrien    {
1158490075Sobrien      /* PROB is the difference from 50%.  */
1158590075Sobrien      int prob = INTVAL (XEXP (note, 0)) - REG_BR_PROB_BASE / 2;
11586117395Skan
11587117395Skan      /* Only hint for highly probable/improbable branches on newer
11588117395Skan	 cpus as static prediction overrides processor dynamic
11589117395Skan	 prediction.  For older cpus we may as well always hint, but
11590117395Skan	 assume not taken for branches that are very close to 50% as a
11591117395Skan	 mispredicted taken branch is more expensive than a
11592169689Skan	 mispredicted not-taken branch.  */
11593132718Skan      if (rs6000_always_hint
11594169689Skan	  || (abs (prob) > REG_BR_PROB_BASE / 100 * 48
11595169689Skan	      && br_prob_note_reliable_p (note)))
11596117395Skan	{
11597117395Skan	  if (abs (prob) > REG_BR_PROB_BASE / 20
11598117395Skan	      && ((prob > 0) ^ need_longbranch))
11599169689Skan	    pred = "+";
11600117395Skan	  else
11601117395Skan	    pred = "-";
11602117395Skan	}
1160390075Sobrien    }
1160490075Sobrien
1160590075Sobrien  if (label == NULL)
1160690075Sobrien    s += sprintf (s, "{b%sr|b%slr%s} ", ccode, ccode, pred);
1160790075Sobrien  else
1160890075Sobrien    s += sprintf (s, "{b%s|b%s%s} ", ccode, ccode, pred);
1160990075Sobrien
1161090075Sobrien  /* We need to escape any '%' characters in the reg_names string.
11611132718Skan     Assume they'd only be the first character....  */
1161290075Sobrien  if (reg_names[cc_regno + CR0_REGNO][0] == '%')
1161390075Sobrien    *s++ = '%';
1161490075Sobrien  s += sprintf (s, "%s", reg_names[cc_regno + CR0_REGNO]);
1161590075Sobrien
1161690075Sobrien  if (label != NULL)
1161790075Sobrien    {
1161890075Sobrien      /* If the branch distance was too far, we may have to use an
1161990075Sobrien	 unconditional branch to go the distance.  */
1162090075Sobrien      if (need_longbranch)
1162190075Sobrien	s += sprintf (s, ",$+8\n\tb %s", label);
1162290075Sobrien      else
1162390075Sobrien	s += sprintf (s, ",%s", label);
1162490075Sobrien    }
1162590075Sobrien
1162690075Sobrien  return string;
1162790075Sobrien}
1162890075Sobrien
11629169689Skan/* Return the string to flip the GT bit on a CR.  */
11630132718Skanchar *
11631169689Skanoutput_e500_flip_gt_bit (rtx dst, rtx src)
11632132718Skan{
11633132718Skan  static char string[64];
11634132718Skan  int a, b;
11635132718Skan
11636169689Skan  gcc_assert (GET_CODE (dst) == REG && CR_REGNO_P (REGNO (dst))
11637169689Skan	      && GET_CODE (src) == REG && CR_REGNO_P (REGNO (src)));
11638132718Skan
11639169689Skan  /* GT bit.  */
11640169689Skan  a = 4 * (REGNO (dst) - CR0_REGNO) + 1;
11641169689Skan  b = 4 * (REGNO (src) - CR0_REGNO) + 1;
11642132718Skan
11643132718Skan  sprintf (string, "crnot %d,%d", a, b);
11644132718Skan  return string;
11645132718Skan}
11646132718Skan
11647169689Skan/* Return insn index for the vector compare instruction for given CODE,
11648169689Skan   and DEST_MODE, OP_MODE. Return INSN_NOT_AVAILABLE if valid insn is
11649169689Skan   not available.  */
11650169689Skan
11651169689Skanstatic int
11652169689Skanget_vec_cmp_insn (enum rtx_code code,
11653169689Skan		  enum machine_mode dest_mode,
11654169689Skan		  enum machine_mode op_mode)
11655169689Skan{
11656169689Skan  if (!TARGET_ALTIVEC)
11657169689Skan    return INSN_NOT_AVAILABLE;
11658169689Skan
11659169689Skan  switch (code)
11660169689Skan    {
11661169689Skan    case EQ:
11662169689Skan      if (dest_mode == V16QImode && op_mode == V16QImode)
11663169689Skan	return UNSPEC_VCMPEQUB;
11664169689Skan      if (dest_mode == V8HImode && op_mode == V8HImode)
11665169689Skan	return UNSPEC_VCMPEQUH;
11666169689Skan      if (dest_mode == V4SImode && op_mode == V4SImode)
11667169689Skan	return UNSPEC_VCMPEQUW;
11668169689Skan      if (dest_mode == V4SImode && op_mode == V4SFmode)
11669169689Skan	return UNSPEC_VCMPEQFP;
11670169689Skan      break;
11671169689Skan    case GE:
11672169689Skan      if (dest_mode == V4SImode && op_mode == V4SFmode)
11673169689Skan	return UNSPEC_VCMPGEFP;
11674169689Skan    case GT:
11675169689Skan      if (dest_mode == V16QImode && op_mode == V16QImode)
11676169689Skan	return UNSPEC_VCMPGTSB;
11677169689Skan      if (dest_mode == V8HImode && op_mode == V8HImode)
11678169689Skan	return UNSPEC_VCMPGTSH;
11679169689Skan      if (dest_mode == V4SImode && op_mode == V4SImode)
11680169689Skan	return UNSPEC_VCMPGTSW;
11681169689Skan      if (dest_mode == V4SImode && op_mode == V4SFmode)
11682169689Skan	return UNSPEC_VCMPGTFP;
11683169689Skan      break;
11684169689Skan    case GTU:
11685169689Skan      if (dest_mode == V16QImode && op_mode == V16QImode)
11686169689Skan	return UNSPEC_VCMPGTUB;
11687169689Skan      if (dest_mode == V8HImode && op_mode == V8HImode)
11688169689Skan	return UNSPEC_VCMPGTUH;
11689169689Skan      if (dest_mode == V4SImode && op_mode == V4SImode)
11690169689Skan	return UNSPEC_VCMPGTUW;
11691169689Skan      break;
11692169689Skan    default:
11693169689Skan      break;
11694169689Skan    }
11695169689Skan  return INSN_NOT_AVAILABLE;
11696169689Skan}
11697169689Skan
11698169689Skan/* Emit vector compare for operands OP0 and OP1 using code RCODE.
11699169689Skan   DMODE is expected destination mode. This is a recursive function.  */
11700169689Skan
11701169689Skanstatic rtx
11702169689Skanrs6000_emit_vector_compare (enum rtx_code rcode,
11703169689Skan			    rtx op0, rtx op1,
11704169689Skan			    enum machine_mode dmode)
11705169689Skan{
11706169689Skan  int vec_cmp_insn;
11707169689Skan  rtx mask;
11708169689Skan  enum machine_mode dest_mode;
11709169689Skan  enum machine_mode op_mode = GET_MODE (op1);
11710169689Skan
11711169689Skan  gcc_assert (TARGET_ALTIVEC);
11712169689Skan  gcc_assert (GET_MODE (op0) == GET_MODE (op1));
11713169689Skan
11714169689Skan  /* Floating point vector compare instructions uses destination V4SImode.
11715169689Skan     Move destination to appropriate mode later.  */
11716169689Skan  if (dmode == V4SFmode)
11717169689Skan    dest_mode = V4SImode;
11718169689Skan  else
11719169689Skan    dest_mode = dmode;
11720169689Skan
11721169689Skan  mask = gen_reg_rtx (dest_mode);
11722169689Skan  vec_cmp_insn = get_vec_cmp_insn (rcode, dest_mode, op_mode);
11723169689Skan
11724169689Skan  if (vec_cmp_insn == INSN_NOT_AVAILABLE)
11725169689Skan    {
11726169689Skan      bool swap_operands = false;
11727169689Skan      bool try_again = false;
11728169689Skan      switch (rcode)
11729169689Skan	{
11730169689Skan	case LT:
11731169689Skan	  rcode = GT;
11732169689Skan	  swap_operands = true;
11733169689Skan	  try_again = true;
11734169689Skan	  break;
11735169689Skan	case LTU:
11736169689Skan	  rcode = GTU;
11737169689Skan	  swap_operands = true;
11738169689Skan	  try_again = true;
11739169689Skan	  break;
11740169689Skan	case NE:
11741260139Spfg	case UNLE:
11742260139Spfg	case UNLT:
11743260139Spfg	case UNGE:
11744260139Spfg	case UNGT:
11745260139Spfg	  /* Invert condition and try again.
11746260139Spfg	     e.g., A != B becomes ~(A==B).  */
11747169689Skan	  {
11748260139Spfg	    enum rtx_code rev_code;
11749169689Skan	    enum insn_code nor_code;
11750260139Spfg	    rtx eq_rtx;
11751169689Skan
11752260139Spfg	    rev_code = reverse_condition_maybe_unordered (rcode);
11753260139Spfg	    eq_rtx = rs6000_emit_vector_compare (rev_code, op0, op1,
11754260139Spfg						 dest_mode);
11755260139Spfg
11756169689Skan	    nor_code = one_cmpl_optab->handlers[(int)dest_mode].insn_code;
11757169689Skan	    gcc_assert (nor_code != CODE_FOR_nothing);
11758169689Skan	    emit_insn (GEN_FCN (nor_code) (mask, eq_rtx));
11759169689Skan
11760169689Skan	    if (dmode != dest_mode)
11761169689Skan	      {
11762169689Skan		rtx temp = gen_reg_rtx (dest_mode);
11763169689Skan		convert_move (temp, mask, 0);
11764169689Skan		return temp;
11765169689Skan	      }
11766169689Skan	    return mask;
11767169689Skan	  }
11768169689Skan	  break;
11769169689Skan	case GE:
11770169689Skan	case GEU:
11771169689Skan	case LE:
11772169689Skan	case LEU:
11773169689Skan	  /* Try GT/GTU/LT/LTU OR EQ */
11774169689Skan	  {
11775169689Skan	    rtx c_rtx, eq_rtx;
11776169689Skan	    enum insn_code ior_code;
11777169689Skan	    enum rtx_code new_code;
11778169689Skan
11779169689Skan	    switch (rcode)
11780169689Skan	      {
11781169689Skan	      case  GE:
11782169689Skan		new_code = GT;
11783169689Skan		break;
11784169689Skan
11785169689Skan	      case GEU:
11786169689Skan		new_code = GTU;
11787169689Skan		break;
11788169689Skan
11789169689Skan	      case LE:
11790169689Skan		new_code = LT;
11791169689Skan		break;
11792169689Skan
11793169689Skan	      case LEU:
11794169689Skan		new_code = LTU;
11795169689Skan		break;
11796169689Skan
11797169689Skan	      default:
11798169689Skan		gcc_unreachable ();
11799169689Skan	      }
11800169689Skan
11801169689Skan	    c_rtx = rs6000_emit_vector_compare (new_code,
11802169689Skan						op0, op1, dest_mode);
11803169689Skan	    eq_rtx = rs6000_emit_vector_compare (EQ, op0, op1,
11804169689Skan						 dest_mode);
11805169689Skan
11806169689Skan	    ior_code = ior_optab->handlers[(int)dest_mode].insn_code;
11807169689Skan	    gcc_assert (ior_code != CODE_FOR_nothing);
11808169689Skan	    emit_insn (GEN_FCN (ior_code) (mask, c_rtx, eq_rtx));
11809169689Skan	    if (dmode != dest_mode)
11810169689Skan	      {
11811169689Skan		rtx temp = gen_reg_rtx (dest_mode);
11812169689Skan		convert_move (temp, mask, 0);
11813169689Skan		return temp;
11814169689Skan	      }
11815169689Skan	    return mask;
11816169689Skan	  }
11817169689Skan	  break;
11818169689Skan	default:
11819169689Skan	  gcc_unreachable ();
11820169689Skan	}
11821169689Skan
11822169689Skan      if (try_again)
11823169689Skan	{
11824169689Skan	  vec_cmp_insn = get_vec_cmp_insn (rcode, dest_mode, op_mode);
11825169689Skan	  /* You only get two chances.  */
11826169689Skan	  gcc_assert (vec_cmp_insn != INSN_NOT_AVAILABLE);
11827169689Skan	}
11828169689Skan
11829169689Skan      if (swap_operands)
11830169689Skan	{
11831169689Skan	  rtx tmp;
11832169689Skan	  tmp = op0;
11833169689Skan	  op0 = op1;
11834169689Skan	  op1 = tmp;
11835169689Skan	}
11836169689Skan    }
11837169689Skan
11838169689Skan  emit_insn (gen_rtx_SET (VOIDmode, mask,
11839169689Skan			  gen_rtx_UNSPEC (dest_mode,
11840169689Skan					  gen_rtvec (2, op0, op1),
11841169689Skan					  vec_cmp_insn)));
11842169689Skan  if (dmode != dest_mode)
11843169689Skan    {
11844169689Skan      rtx temp = gen_reg_rtx (dest_mode);
11845169689Skan      convert_move (temp, mask, 0);
11846169689Skan      return temp;
11847169689Skan    }
11848169689Skan  return mask;
11849169689Skan}
11850169689Skan
11851169689Skan/* Return vector select instruction for MODE. Return INSN_NOT_AVAILABLE, if
11852169689Skan   valid insn doesn exist for given mode.  */
11853169689Skan
11854169689Skanstatic int
11855169689Skanget_vsel_insn (enum machine_mode mode)
11856169689Skan{
11857169689Skan  switch (mode)
11858169689Skan    {
11859169689Skan    case V4SImode:
11860169689Skan      return UNSPEC_VSEL4SI;
11861169689Skan      break;
11862169689Skan    case V4SFmode:
11863169689Skan      return UNSPEC_VSEL4SF;
11864169689Skan      break;
11865169689Skan    case V8HImode:
11866169689Skan      return UNSPEC_VSEL8HI;
11867169689Skan      break;
11868169689Skan    case V16QImode:
11869169689Skan      return UNSPEC_VSEL16QI;
11870169689Skan      break;
11871169689Skan    default:
11872169689Skan      return INSN_NOT_AVAILABLE;
11873169689Skan      break;
11874169689Skan    }
11875169689Skan  return INSN_NOT_AVAILABLE;
11876169689Skan}
11877169689Skan
11878169689Skan/* Emit vector select insn where DEST is destination using
11879169689Skan   operands OP1, OP2 and MASK.  */
11880169689Skan
11881169689Skanstatic void
11882169689Skanrs6000_emit_vector_select (rtx dest, rtx op1, rtx op2, rtx mask)
11883169689Skan{
11884169689Skan  rtx t, temp;
11885169689Skan  enum machine_mode dest_mode = GET_MODE (dest);
11886169689Skan  int vsel_insn_index  = get_vsel_insn (GET_MODE (dest));
11887169689Skan
11888169689Skan  temp = gen_reg_rtx (dest_mode);
11889169689Skan
11890169689Skan  /* For each vector element, select op1 when mask is 1 otherwise
11891169689Skan     select op2.  */
11892169689Skan  t = gen_rtx_SET (VOIDmode, temp,
11893169689Skan		   gen_rtx_UNSPEC (dest_mode,
11894169689Skan				   gen_rtvec (3, op2, op1, mask),
11895169689Skan				   vsel_insn_index));
11896169689Skan  emit_insn (t);
11897169689Skan  emit_move_insn (dest, temp);
11898169689Skan  return;
11899169689Skan}
11900169689Skan
11901169689Skan/* Emit vector conditional expression.
11902169689Skan   DEST is destination. OP1 and OP2 are two VEC_COND_EXPR operands.
11903169689Skan   CC_OP0 and CC_OP1 are the two operands for the relation operation COND.  */
11904169689Skan
11905169689Skanint
11906169689Skanrs6000_emit_vector_cond_expr (rtx dest, rtx op1, rtx op2,
11907169689Skan			      rtx cond, rtx cc_op0, rtx cc_op1)
11908169689Skan{
11909169689Skan  enum machine_mode dest_mode = GET_MODE (dest);
11910169689Skan  enum rtx_code rcode = GET_CODE (cond);
11911169689Skan  rtx mask;
11912169689Skan
11913169689Skan  if (!TARGET_ALTIVEC)
11914169689Skan    return 0;
11915169689Skan
11916169689Skan  /* Get the vector mask for the given relational operations.  */
11917169689Skan  mask = rs6000_emit_vector_compare (rcode, cc_op0, cc_op1, dest_mode);
11918169689Skan
11919169689Skan  rs6000_emit_vector_select (dest, op1, op2, mask);
11920169689Skan
11921169689Skan  return 1;
11922169689Skan}
11923169689Skan
1192490075Sobrien/* Emit a conditional move: move TRUE_COND to DEST if OP of the
1192590075Sobrien   operands of the last comparison is nonzero/true, FALSE_COND if it
1192690075Sobrien   is zero/false.  Return 0 if the hardware has no such operation.  */
1192790075Sobrien
1192890075Sobrienint
11929132718Skanrs6000_emit_cmove (rtx dest, rtx op, rtx true_cond, rtx false_cond)
1193090075Sobrien{
1193190075Sobrien  enum rtx_code code = GET_CODE (op);
1193290075Sobrien  rtx op0 = rs6000_compare_op0;
1193390075Sobrien  rtx op1 = rs6000_compare_op1;
1193490075Sobrien  REAL_VALUE_TYPE c1;
1193596263Sobrien  enum machine_mode compare_mode = GET_MODE (op0);
1193696263Sobrien  enum machine_mode result_mode = GET_MODE (dest);
1193790075Sobrien  rtx temp;
11938169689Skan  bool is_against_zero;
1193990075Sobrien
11940132718Skan  /* These modes should always match.  */
11941117395Skan  if (GET_MODE (op1) != compare_mode
11942117395Skan      /* In the isel case however, we can use a compare immediate, so
11943117395Skan	 op1 may be a small constant.  */
11944117395Skan      && (!TARGET_ISEL || !short_cint_operand (op1, VOIDmode)))
1194596263Sobrien    return 0;
1194696263Sobrien  if (GET_MODE (true_cond) != result_mode)
1194796263Sobrien    return 0;
1194896263Sobrien  if (GET_MODE (false_cond) != result_mode)
1194996263Sobrien    return 0;
1195096263Sobrien
1195190075Sobrien  /* First, work out if the hardware can do this at all, or
11952132718Skan     if it's too slow....  */
1195390075Sobrien  if (! rs6000_compare_fp_p)
11954117395Skan    {
11955117395Skan      if (TARGET_ISEL)
11956117395Skan	return rs6000_emit_int_cmove (dest, op, true_cond, false_cond);
11957117395Skan      return 0;
11958117395Skan    }
11959132718Skan  else if (TARGET_E500 && TARGET_HARD_FLOAT && !TARGET_FPRS
11960169689Skan	   && SCALAR_FLOAT_MODE_P (compare_mode))
11961132718Skan    return 0;
1196290075Sobrien
11963169689Skan  is_against_zero = op1 == CONST0_RTX (compare_mode);
11964169689Skan
11965169689Skan  /* A floating-point subtract might overflow, underflow, or produce
11966169689Skan     an inexact result, thus changing the floating-point flags, so it
11967169689Skan     can't be generated if we care about that.  It's safe if one side
11968169689Skan     of the construct is zero, since then no subtract will be
11969169689Skan     generated.  */
11970169689Skan  if (SCALAR_FLOAT_MODE_P (compare_mode)
11971169689Skan      && flag_trapping_math && ! is_against_zero)
11972169689Skan    return 0;
11973169689Skan
1197490075Sobrien  /* Eliminate half of the comparisons by switching operands, this
1197590075Sobrien     makes the remaining code simpler.  */
1197690075Sobrien  if (code == UNLT || code == UNGT || code == UNORDERED || code == NE
11977132718Skan      || code == LTGT || code == LT || code == UNLE)
1197890075Sobrien    {
1197990075Sobrien      code = reverse_condition_maybe_unordered (code);
1198090075Sobrien      temp = true_cond;
1198190075Sobrien      true_cond = false_cond;
1198290075Sobrien      false_cond = temp;
1198390075Sobrien    }
1198490075Sobrien
1198590075Sobrien  /* UNEQ and LTGT take four instructions for a comparison with zero,
1198690075Sobrien     it'll probably be faster to use a branch here too.  */
11987132718Skan  if (code == UNEQ && HONOR_NANS (compare_mode))
1198890075Sobrien    return 0;
11989169689Skan
1199090075Sobrien  if (GET_CODE (op1) == CONST_DOUBLE)
1199190075Sobrien    REAL_VALUE_FROM_CONST_DOUBLE (c1, op1);
11992169689Skan
11993132718Skan  /* We're going to try to implement comparisons by performing
1199490075Sobrien     a subtract, then comparing against zero.  Unfortunately,
1199590075Sobrien     Inf - Inf is NaN which is not zero, and so if we don't
11996117395Skan     know that the operand is finite and the comparison
1199790075Sobrien     would treat EQ different to UNORDERED, we can't do it.  */
11998132718Skan  if (HONOR_INFINITIES (compare_mode)
1199990075Sobrien      && code != GT && code != UNGE
12000117395Skan      && (GET_CODE (op1) != CONST_DOUBLE || real_isinf (&c1))
1200190075Sobrien      /* Constructs of the form (a OP b ? a : b) are safe.  */
1200290075Sobrien      && ((! rtx_equal_p (op0, false_cond) && ! rtx_equal_p (op1, false_cond))
12003169689Skan	  || (! rtx_equal_p (op0, true_cond)
1200490075Sobrien	      && ! rtx_equal_p (op1, true_cond))))
1200590075Sobrien    return 0;
12006169689Skan
1200790075Sobrien  /* At this point we know we can use fsel.  */
1200890075Sobrien
1200990075Sobrien  /* Reduce the comparison to a comparison against zero.  */
12010169689Skan  if (! is_against_zero)
12011169689Skan    {
12012169689Skan      temp = gen_reg_rtx (compare_mode);
12013169689Skan      emit_insn (gen_rtx_SET (VOIDmode, temp,
12014169689Skan			      gen_rtx_MINUS (compare_mode, op0, op1)));
12015169689Skan      op0 = temp;
12016169689Skan      op1 = CONST0_RTX (compare_mode);
12017169689Skan    }
1201890075Sobrien
1201990075Sobrien  /* If we don't care about NaNs we can reduce some of the comparisons
1202090075Sobrien     down to faster ones.  */
12021132718Skan  if (! HONOR_NANS (compare_mode))
1202290075Sobrien    switch (code)
1202390075Sobrien      {
1202490075Sobrien      case GT:
1202590075Sobrien	code = LE;
1202690075Sobrien	temp = true_cond;
1202790075Sobrien	true_cond = false_cond;
1202890075Sobrien	false_cond = temp;
1202990075Sobrien	break;
1203090075Sobrien      case UNGE:
1203190075Sobrien	code = GE;
1203290075Sobrien	break;
1203390075Sobrien      case UNEQ:
1203490075Sobrien	code = EQ;
1203590075Sobrien	break;
1203690075Sobrien      default:
1203790075Sobrien	break;
1203890075Sobrien      }
1203990075Sobrien
1204090075Sobrien  /* Now, reduce everything down to a GE.  */
1204190075Sobrien  switch (code)
1204290075Sobrien    {
1204390075Sobrien    case GE:
1204490075Sobrien      break;
1204590075Sobrien
1204690075Sobrien    case LE:
1204796263Sobrien      temp = gen_reg_rtx (compare_mode);
1204896263Sobrien      emit_insn (gen_rtx_SET (VOIDmode, temp, gen_rtx_NEG (compare_mode, op0)));
1204990075Sobrien      op0 = temp;
1205090075Sobrien      break;
1205190075Sobrien
1205290075Sobrien    case ORDERED:
1205396263Sobrien      temp = gen_reg_rtx (compare_mode);
1205496263Sobrien      emit_insn (gen_rtx_SET (VOIDmode, temp, gen_rtx_ABS (compare_mode, op0)));
1205590075Sobrien      op0 = temp;
1205690075Sobrien      break;
1205790075Sobrien
1205890075Sobrien    case EQ:
1205996263Sobrien      temp = gen_reg_rtx (compare_mode);
12060169689Skan      emit_insn (gen_rtx_SET (VOIDmode, temp,
1206196263Sobrien			      gen_rtx_NEG (compare_mode,
1206296263Sobrien					   gen_rtx_ABS (compare_mode, op0))));
1206390075Sobrien      op0 = temp;
1206490075Sobrien      break;
1206590075Sobrien
1206690075Sobrien    case UNGE:
12067132718Skan      /* a UNGE 0 <-> (a GE 0 || -a UNLT 0) */
1206896263Sobrien      temp = gen_reg_rtx (result_mode);
1206990075Sobrien      emit_insn (gen_rtx_SET (VOIDmode, temp,
1207096263Sobrien			      gen_rtx_IF_THEN_ELSE (result_mode,
1207190075Sobrien						    gen_rtx_GE (VOIDmode,
1207290075Sobrien								op0, op1),
1207390075Sobrien						    true_cond, false_cond)));
12074132718Skan      false_cond = true_cond;
12075132718Skan      true_cond = temp;
1207690075Sobrien
1207796263Sobrien      temp = gen_reg_rtx (compare_mode);
1207896263Sobrien      emit_insn (gen_rtx_SET (VOIDmode, temp, gen_rtx_NEG (compare_mode, op0)));
1207990075Sobrien      op0 = temp;
1208090075Sobrien      break;
1208190075Sobrien
1208290075Sobrien    case GT:
12083132718Skan      /* a GT 0 <-> (a GE 0 && -a UNLT 0) */
1208496263Sobrien      temp = gen_reg_rtx (result_mode);
1208590075Sobrien      emit_insn (gen_rtx_SET (VOIDmode, temp,
12086169689Skan			      gen_rtx_IF_THEN_ELSE (result_mode,
1208790075Sobrien						    gen_rtx_GE (VOIDmode,
1208890075Sobrien								op0, op1),
1208990075Sobrien						    true_cond, false_cond)));
12090132718Skan      true_cond = false_cond;
12091132718Skan      false_cond = temp;
1209290075Sobrien
1209396263Sobrien      temp = gen_reg_rtx (compare_mode);
1209496263Sobrien      emit_insn (gen_rtx_SET (VOIDmode, temp, gen_rtx_NEG (compare_mode, op0)));
1209590075Sobrien      op0 = temp;
1209690075Sobrien      break;
1209790075Sobrien
1209890075Sobrien    default:
12099169689Skan      gcc_unreachable ();
1210090075Sobrien    }
1210190075Sobrien
1210290075Sobrien  emit_insn (gen_rtx_SET (VOIDmode, dest,
1210396263Sobrien			  gen_rtx_IF_THEN_ELSE (result_mode,
1210490075Sobrien						gen_rtx_GE (VOIDmode,
1210590075Sobrien							    op0, op1),
1210690075Sobrien						true_cond, false_cond)));
1210790075Sobrien  return 1;
1210890075Sobrien}
1210990075Sobrien
12110117395Skan/* Same as above, but for ints (isel).  */
12111117395Skan
12112117395Skanstatic int
12113132718Skanrs6000_emit_int_cmove (rtx dest, rtx op, rtx true_cond, rtx false_cond)
12114117395Skan{
12115117395Skan  rtx condition_rtx, cr;
12116117395Skan
12117117395Skan  /* All isel implementations thus far are 32-bits.  */
12118117395Skan  if (GET_MODE (rs6000_compare_op0) != SImode)
12119117395Skan    return 0;
12120117395Skan
12121117395Skan  /* We still have to do the compare, because isel doesn't do a
12122117395Skan     compare, it just looks at the CRx bits set by a previous compare
12123117395Skan     instruction.  */
12124117395Skan  condition_rtx = rs6000_generate_compare (GET_CODE (op));
12125117395Skan  cr = XEXP (condition_rtx, 0);
12126117395Skan
12127117395Skan  if (GET_MODE (cr) == CCmode)
12128117395Skan    emit_insn (gen_isel_signed (dest, condition_rtx,
12129117395Skan				true_cond, false_cond, cr));
12130117395Skan  else
12131117395Skan    emit_insn (gen_isel_unsigned (dest, condition_rtx,
12132117395Skan				  true_cond, false_cond, cr));
12133117395Skan
12134117395Skan  return 1;
12135117395Skan}
12136117395Skan
12137117395Skanconst char *
12138132718Skanoutput_isel (rtx *operands)
12139117395Skan{
12140117395Skan  enum rtx_code code;
12141117395Skan
12142117395Skan  code = GET_CODE (operands[1]);
12143117395Skan  if (code == GE || code == GEU || code == LE || code == LEU || code == NE)
12144117395Skan    {
12145117395Skan      PUT_CODE (operands[1], reverse_condition (code));
12146117395Skan      return "isel %0,%3,%2,%j1";
12147117395Skan    }
12148117395Skan  else
12149117395Skan    return "isel %0,%2,%3,%j1";
12150117395Skan}
12151117395Skan
1215290075Sobrienvoid
12153132718Skanrs6000_emit_minmax (rtx dest, enum rtx_code code, rtx op0, rtx op1)
1215490075Sobrien{
1215590075Sobrien  enum machine_mode mode = GET_MODE (op0);
12156117395Skan  enum rtx_code c;
1215790075Sobrien  rtx target;
12158117395Skan
12159117395Skan  if (code == SMAX || code == SMIN)
12160117395Skan    c = GE;
12161117395Skan  else
12162117395Skan    c = GEU;
12163117395Skan
1216490075Sobrien  if (code == SMAX || code == UMAX)
12165169689Skan    target = emit_conditional_move (dest, c, op0, op1, mode,
1216690075Sobrien				    op0, op1, mode, 0);
1216790075Sobrien  else
12168169689Skan    target = emit_conditional_move (dest, c, op0, op1, mode,
1216990075Sobrien				    op1, op0, mode, 0);
12170169689Skan  gcc_assert (target);
1217190075Sobrien  if (target != dest)
1217290075Sobrien    emit_move_insn (dest, target);
1217390075Sobrien}
12174132718Skan
12175169689Skan/* Emit instructions to perform a load-reserved/store-conditional operation.
12176169689Skan   The operation performed is an atomic
12177169689Skan   (set M (CODE:MODE M OP))
12178169689Skan   If not NULL, BEFORE is atomically set to M before the operation, and
12179169689Skan   AFTER is set to M after the operation (that is, (CODE:MODE M OP)).
12180169689Skan   If SYNC_P then a memory barrier is emitted before the operation.
12181169689Skan   Either OP or M may be wrapped in a NOT operation.  */
12182169689Skan
12183169689Skanvoid
12184169689Skanrs6000_emit_sync (enum rtx_code code, enum machine_mode mode,
12185169689Skan		  rtx m, rtx op, rtx before_param, rtx after_param,
12186169689Skan		  bool sync_p)
12187169689Skan{
12188169689Skan  enum machine_mode used_mode;
12189169689Skan  rtx the_op, set_before, set_after, set_atomic, cc_scratch, before, after;
12190169689Skan  rtx used_m;
12191169689Skan  rtvec vec;
12192169689Skan  HOST_WIDE_INT imask = GET_MODE_MASK (mode);
12193169689Skan  rtx shift = NULL_RTX;
12194169689Skan
12195169689Skan  if (sync_p)
12196169689Skan    emit_insn (gen_memory_barrier ());
12197169689Skan
12198169689Skan  if (GET_CODE (m) == NOT)
12199169689Skan    used_m = XEXP (m, 0);
12200169689Skan  else
12201169689Skan    used_m = m;
12202169689Skan
12203169689Skan  /* If this is smaller than SImode, we'll have to use SImode with
12204169689Skan     adjustments.  */
12205169689Skan  if (mode == QImode || mode == HImode)
12206169689Skan    {
12207169689Skan      rtx newop, oldop;
12208169689Skan
12209169689Skan      if (MEM_ALIGN (used_m) >= 32)
12210169689Skan	{
12211169689Skan	  int ishift = 0;
12212169689Skan	  if (BYTES_BIG_ENDIAN)
12213169689Skan	    ishift = GET_MODE_BITSIZE (SImode) - GET_MODE_BITSIZE (mode);
12214169689Skan
12215169689Skan	  shift = GEN_INT (ishift);
12216169689Skan	}
12217169689Skan      else
12218169689Skan	{
12219169689Skan	  rtx addrSI, aligned_addr;
12220169689Skan	  int shift_mask = mode == QImode ? 0x18 : 0x10;
12221169689Skan
12222169689Skan	  addrSI = force_reg (SImode, gen_lowpart_common (SImode,
12223169689Skan							  XEXP (used_m, 0)));
12224169689Skan	  shift = gen_reg_rtx (SImode);
12225169689Skan
12226169689Skan	  emit_insn (gen_rlwinm (shift, addrSI, GEN_INT (3),
12227169689Skan				 GEN_INT (shift_mask)));
12228169689Skan	  emit_insn (gen_xorsi3 (shift, shift, GEN_INT (shift_mask)));
12229169689Skan
12230169689Skan	  aligned_addr = expand_binop (Pmode, and_optab,
12231169689Skan				       XEXP (used_m, 0),
12232169689Skan				       GEN_INT (-4), NULL_RTX,
12233169689Skan				       1, OPTAB_LIB_WIDEN);
12234169689Skan	  used_m = change_address (used_m, SImode, aligned_addr);
12235169689Skan	  set_mem_align (used_m, 32);
12236169689Skan	  /* It's safe to keep the old alias set of USED_M, because
12237169689Skan	     the operation is atomic and only affects the original
12238169689Skan	     USED_M.  */
12239169689Skan	  if (GET_CODE (m) == NOT)
12240169689Skan	    m = gen_rtx_NOT (SImode, used_m);
12241169689Skan	  else
12242169689Skan	    m = used_m;
12243169689Skan	}
12244169689Skan
12245169689Skan      if (GET_CODE (op) == NOT)
12246169689Skan	{
12247169689Skan	  oldop = lowpart_subreg (SImode, XEXP (op, 0), mode);
12248169689Skan	  oldop = gen_rtx_NOT (SImode, oldop);
12249169689Skan	}
12250169689Skan      else
12251169689Skan	oldop = lowpart_subreg (SImode, op, mode);
12252169689Skan
12253169689Skan      switch (code)
12254169689Skan	{
12255169689Skan	case IOR:
12256169689Skan	case XOR:
12257169689Skan	  newop = expand_binop (SImode, and_optab,
12258169689Skan				oldop, GEN_INT (imask), NULL_RTX,
12259169689Skan				1, OPTAB_LIB_WIDEN);
12260169689Skan	  emit_insn (gen_ashlsi3 (newop, newop, shift));
12261169689Skan	  break;
12262169689Skan
12263169689Skan	case AND:
12264169689Skan	  newop = expand_binop (SImode, ior_optab,
12265169689Skan				oldop, GEN_INT (~imask), NULL_RTX,
12266169689Skan				1, OPTAB_LIB_WIDEN);
12267169689Skan	  emit_insn (gen_rotlsi3 (newop, newop, shift));
12268169689Skan	  break;
12269169689Skan
12270169689Skan	case PLUS:
12271169689Skan	case MINUS:
12272169689Skan	  {
12273169689Skan	    rtx mask;
12274169689Skan
12275169689Skan	    newop = expand_binop (SImode, and_optab,
12276169689Skan				  oldop, GEN_INT (imask), NULL_RTX,
12277169689Skan				  1, OPTAB_LIB_WIDEN);
12278169689Skan	    emit_insn (gen_ashlsi3 (newop, newop, shift));
12279169689Skan
12280169689Skan	    mask = gen_reg_rtx (SImode);
12281169689Skan	    emit_move_insn (mask, GEN_INT (imask));
12282169689Skan	    emit_insn (gen_ashlsi3 (mask, mask, shift));
12283169689Skan
12284169689Skan	    if (code == PLUS)
12285169689Skan	      newop = gen_rtx_PLUS (SImode, m, newop);
12286169689Skan	    else
12287169689Skan	      newop = gen_rtx_MINUS (SImode, m, newop);
12288169689Skan	    newop = gen_rtx_AND (SImode, newop, mask);
12289169689Skan	    newop = gen_rtx_IOR (SImode, newop,
12290169689Skan				 gen_rtx_AND (SImode,
12291169689Skan					      gen_rtx_NOT (SImode, mask),
12292169689Skan					      m));
12293169689Skan	    break;
12294169689Skan	  }
12295169689Skan
12296169689Skan	default:
12297169689Skan	  gcc_unreachable ();
12298169689Skan	}
12299169689Skan
12300169689Skan      if (GET_CODE (m) == NOT)
12301169689Skan	{
12302169689Skan	  rtx mask, xorm;
12303169689Skan
12304169689Skan	  mask = gen_reg_rtx (SImode);
12305169689Skan	  emit_move_insn (mask, GEN_INT (imask));
12306169689Skan	  emit_insn (gen_ashlsi3 (mask, mask, shift));
12307169689Skan
12308169689Skan	  xorm = gen_rtx_XOR (SImode, used_m, mask);
12309169689Skan	  /* Depending on the value of 'op', the XOR or the operation might
12310169689Skan	     be able to be simplified away.  */
12311169689Skan	  newop = simplify_gen_binary (code, SImode, xorm, newop);
12312169689Skan	}
12313169689Skan      op = newop;
12314169689Skan      used_mode = SImode;
12315169689Skan      before = gen_reg_rtx (used_mode);
12316169689Skan      after = gen_reg_rtx (used_mode);
12317169689Skan    }
12318169689Skan  else
12319169689Skan    {
12320169689Skan      used_mode = mode;
12321169689Skan      before = before_param;
12322169689Skan      after = after_param;
12323169689Skan
12324169689Skan      if (before == NULL_RTX)
12325169689Skan	before = gen_reg_rtx (used_mode);
12326169689Skan      if (after == NULL_RTX)
12327169689Skan	after = gen_reg_rtx (used_mode);
12328169689Skan    }
12329169689Skan
12330169689Skan  if ((code == PLUS || code == MINUS || GET_CODE (m) == NOT)
12331169689Skan      && used_mode != mode)
12332169689Skan    the_op = op;  /* Computed above.  */
12333169689Skan  else if (GET_CODE (op) == NOT && GET_CODE (m) != NOT)
12334169689Skan    the_op = gen_rtx_fmt_ee (code, used_mode, op, m);
12335169689Skan  else
12336169689Skan    the_op = gen_rtx_fmt_ee (code, used_mode, m, op);
12337169689Skan
12338169689Skan  set_after = gen_rtx_SET (VOIDmode, after, the_op);
12339169689Skan  set_before = gen_rtx_SET (VOIDmode, before, used_m);
12340169689Skan  set_atomic = gen_rtx_SET (VOIDmode, used_m,
12341169689Skan			    gen_rtx_UNSPEC (used_mode,
12342169689Skan					    gen_rtvec (1, the_op),
12343169689Skan					    UNSPEC_SYNC_OP));
12344169689Skan  cc_scratch = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (CCmode));
12345169689Skan
12346169689Skan  if ((code == PLUS || code == MINUS) && used_mode != mode)
12347169689Skan    vec = gen_rtvec (5, set_after, set_before, set_atomic, cc_scratch,
12348169689Skan		     gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (SImode)));
12349169689Skan  else
12350169689Skan    vec = gen_rtvec (4, set_after, set_before, set_atomic, cc_scratch);
12351169689Skan  emit_insn (gen_rtx_PARALLEL (VOIDmode, vec));
12352169689Skan
12353169689Skan  /* Shift and mask the return values properly.  */
12354169689Skan  if (used_mode != mode && before_param)
12355169689Skan    {
12356169689Skan      emit_insn (gen_lshrsi3 (before, before, shift));
12357169689Skan      convert_move (before_param, before, 1);
12358169689Skan    }
12359169689Skan
12360169689Skan  if (used_mode != mode && after_param)
12361169689Skan    {
12362169689Skan      emit_insn (gen_lshrsi3 (after, after, shift));
12363169689Skan      convert_move (after_param, after, 1);
12364169689Skan    }
12365169689Skan
12366169689Skan  /* The previous sequence will end with a branch that's dependent on
12367169689Skan     the conditional store, so placing an isync will ensure that no
12368169689Skan     other instructions (especially, no load or store instructions)
12369169689Skan     can start before the atomic operation completes.  */
12370169689Skan  if (sync_p)
12371169689Skan    emit_insn (gen_isync ());
12372169689Skan}
12373169689Skan
12374169689Skan/* A subroutine of the atomic operation splitters.  Jump to LABEL if
12375169689Skan   COND is true.  Mark the jump as unlikely to be taken.  */
12376169689Skan
12377169689Skanstatic void
12378169689Skanemit_unlikely_jump (rtx cond, rtx label)
12379169689Skan{
12380169689Skan  rtx very_unlikely = GEN_INT (REG_BR_PROB_BASE / 100 - 1);
12381169689Skan  rtx x;
12382169689Skan
12383169689Skan  x = gen_rtx_IF_THEN_ELSE (VOIDmode, cond, label, pc_rtx);
12384169689Skan  x = emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, x));
12385169689Skan  REG_NOTES (x) = gen_rtx_EXPR_LIST (REG_BR_PROB, very_unlikely, NULL_RTX);
12386169689Skan}
12387169689Skan
12388169689Skan/* A subroutine of the atomic operation splitters.  Emit a load-locked
12389169689Skan   instruction in MODE.  */
12390169689Skan
12391169689Skanstatic void
12392169689Skanemit_load_locked (enum machine_mode mode, rtx reg, rtx mem)
12393169689Skan{
12394169689Skan  rtx (*fn) (rtx, rtx) = NULL;
12395169689Skan  if (mode == SImode)
12396169689Skan    fn = gen_load_locked_si;
12397169689Skan  else if (mode == DImode)
12398169689Skan    fn = gen_load_locked_di;
12399169689Skan  emit_insn (fn (reg, mem));
12400169689Skan}
12401169689Skan
12402169689Skan/* A subroutine of the atomic operation splitters.  Emit a store-conditional
12403169689Skan   instruction in MODE.  */
12404169689Skan
12405169689Skanstatic void
12406169689Skanemit_store_conditional (enum machine_mode mode, rtx res, rtx mem, rtx val)
12407169689Skan{
12408169689Skan  rtx (*fn) (rtx, rtx, rtx) = NULL;
12409169689Skan  if (mode == SImode)
12410169689Skan    fn = gen_store_conditional_si;
12411169689Skan  else if (mode == DImode)
12412169689Skan    fn = gen_store_conditional_di;
12413169689Skan
12414169689Skan  /* Emit sync before stwcx. to address PPC405 Erratum.  */
12415169689Skan  if (PPC405_ERRATUM77)
12416169689Skan    emit_insn (gen_memory_barrier ());
12417169689Skan
12418169689Skan  emit_insn (fn (res, mem, val));
12419169689Skan}
12420169689Skan
12421169689Skan/* Expand an an atomic fetch-and-operate pattern.  CODE is the binary operation
12422169689Skan   to perform.  MEM is the memory on which to operate.  VAL is the second
12423169689Skan   operand of the binary operator.  BEFORE and AFTER are optional locations to
12424169689Skan   return the value of MEM either before of after the operation.  SCRATCH is
12425169689Skan   a scratch register.  */
12426169689Skan
12427169689Skanvoid
12428169689Skanrs6000_split_atomic_op (enum rtx_code code, rtx mem, rtx val,
12429169689Skan                       rtx before, rtx after, rtx scratch)
12430169689Skan{
12431169689Skan  enum machine_mode mode = GET_MODE (mem);
12432169689Skan  rtx label, x, cond = gen_rtx_REG (CCmode, CR0_REGNO);
12433169689Skan
12434169689Skan  emit_insn (gen_memory_barrier ());
12435169689Skan
12436169689Skan  label = gen_label_rtx ();
12437169689Skan  emit_label (label);
12438169689Skan  label = gen_rtx_LABEL_REF (VOIDmode, label);
12439169689Skan
12440169689Skan  if (before == NULL_RTX)
12441169689Skan    before = scratch;
12442169689Skan  emit_load_locked (mode, before, mem);
12443169689Skan
12444169689Skan  if (code == NOT)
12445169689Skan    x = gen_rtx_AND (mode, gen_rtx_NOT (mode, before), val);
12446169689Skan  else if (code == AND)
12447169689Skan    x = gen_rtx_UNSPEC (mode, gen_rtvec (2, before, val), UNSPEC_AND);
12448169689Skan  else
12449169689Skan    x = gen_rtx_fmt_ee (code, mode, before, val);
12450169689Skan
12451169689Skan  if (after != NULL_RTX)
12452169689Skan    emit_insn (gen_rtx_SET (VOIDmode, after, copy_rtx (x)));
12453169689Skan  emit_insn (gen_rtx_SET (VOIDmode, scratch, x));
12454169689Skan
12455169689Skan  emit_store_conditional (mode, cond, mem, scratch);
12456169689Skan
12457169689Skan  x = gen_rtx_NE (VOIDmode, cond, const0_rtx);
12458169689Skan  emit_unlikely_jump (x, label);
12459169689Skan
12460169689Skan  emit_insn (gen_isync ());
12461169689Skan}
12462169689Skan
12463169689Skan/* Expand an atomic compare and swap operation.  MEM is the memory on which
12464169689Skan   to operate.  OLDVAL is the old value to be compared.  NEWVAL is the new
12465169689Skan   value to be stored.  SCRATCH is a scratch GPR.  */
12466169689Skan
12467169689Skanvoid
12468169689Skanrs6000_split_compare_and_swap (rtx retval, rtx mem, rtx oldval, rtx newval,
12469169689Skan			       rtx scratch)
12470169689Skan{
12471169689Skan  enum machine_mode mode = GET_MODE (mem);
12472169689Skan  rtx label1, label2, x, cond = gen_rtx_REG (CCmode, CR0_REGNO);
12473169689Skan
12474169689Skan  emit_insn (gen_memory_barrier ());
12475169689Skan
12476169689Skan  label1 = gen_rtx_LABEL_REF (VOIDmode, gen_label_rtx ());
12477169689Skan  label2 = gen_rtx_LABEL_REF (VOIDmode, gen_label_rtx ());
12478169689Skan  emit_label (XEXP (label1, 0));
12479169689Skan
12480169689Skan  emit_load_locked (mode, retval, mem);
12481169689Skan
12482169689Skan  x = gen_rtx_COMPARE (CCmode, retval, oldval);
12483169689Skan  emit_insn (gen_rtx_SET (VOIDmode, cond, x));
12484169689Skan
12485169689Skan  x = gen_rtx_NE (VOIDmode, cond, const0_rtx);
12486169689Skan  emit_unlikely_jump (x, label2);
12487169689Skan
12488169689Skan  emit_move_insn (scratch, newval);
12489169689Skan  emit_store_conditional (mode, cond, mem, scratch);
12490169689Skan
12491169689Skan  x = gen_rtx_NE (VOIDmode, cond, const0_rtx);
12492169689Skan  emit_unlikely_jump (x, label1);
12493169689Skan
12494169689Skan  emit_insn (gen_isync ());
12495169689Skan  emit_label (XEXP (label2, 0));
12496169689Skan}
12497169689Skan
12498169689Skan/* Expand an atomic test and set operation.  MEM is the memory on which
12499169689Skan   to operate.  VAL is the value set.  SCRATCH is a scratch GPR.  */
12500169689Skan
12501169689Skanvoid
12502169689Skanrs6000_split_lock_test_and_set (rtx retval, rtx mem, rtx val, rtx scratch)
12503169689Skan{
12504169689Skan  enum machine_mode mode = GET_MODE (mem);
12505169689Skan  rtx label, x, cond = gen_rtx_REG (CCmode, CR0_REGNO);
12506169689Skan
12507169689Skan  emit_insn (gen_memory_barrier ());
12508169689Skan
12509169689Skan  label = gen_rtx_LABEL_REF (VOIDmode, gen_label_rtx ());
12510169689Skan  emit_label (XEXP (label, 0));
12511169689Skan
12512169689Skan  emit_load_locked (mode, retval, mem);
12513169689Skan  emit_move_insn (scratch, val);
12514169689Skan  emit_store_conditional (mode, cond, mem, scratch);
12515169689Skan
12516169689Skan  x = gen_rtx_NE (VOIDmode, cond, const0_rtx);
12517169689Skan  emit_unlikely_jump (x, label);
12518169689Skan
12519169689Skan  emit_insn (gen_isync ());
12520169689Skan}
12521169689Skan
12522169689Skanvoid
12523169689Skanrs6000_expand_compare_and_swapqhi (rtx dst, rtx mem, rtx oldval, rtx newval)
12524169689Skan{
12525169689Skan  enum machine_mode mode = GET_MODE (mem);
12526169689Skan  rtx addrSI, align, wdst, shift, mask;
12527169689Skan  HOST_WIDE_INT shift_mask = mode == QImode ? 0x18 : 0x10;
12528169689Skan  HOST_WIDE_INT imask = GET_MODE_MASK (mode);
12529169689Skan
12530169689Skan  /* Shift amount for subword relative to aligned word.  */
12531169689Skan  addrSI = force_reg (SImode, gen_lowpart_common (SImode, XEXP (mem, 0)));
12532169689Skan  shift = gen_reg_rtx (SImode);
12533169689Skan  emit_insn (gen_rlwinm (shift, addrSI, GEN_INT (3),
12534169689Skan			 GEN_INT (shift_mask)));
12535169689Skan  emit_insn (gen_xorsi3 (shift, shift, GEN_INT (shift_mask)));
12536169689Skan
12537169689Skan  /* Shift and mask old value into position within word.  */
12538169689Skan  oldval = convert_modes (SImode, mode, oldval, 1);
12539169689Skan  oldval = expand_binop (SImode, and_optab,
12540169689Skan			 oldval, GEN_INT (imask), NULL_RTX,
12541169689Skan			 1, OPTAB_LIB_WIDEN);
12542169689Skan  emit_insn (gen_ashlsi3 (oldval, oldval, shift));
12543169689Skan
12544169689Skan  /* Shift and mask new value into position within word.  */
12545169689Skan  newval = convert_modes (SImode, mode, newval, 1);
12546169689Skan  newval = expand_binop (SImode, and_optab,
12547169689Skan			 newval, GEN_INT (imask), NULL_RTX,
12548169689Skan			 1, OPTAB_LIB_WIDEN);
12549169689Skan  emit_insn (gen_ashlsi3 (newval, newval, shift));
12550169689Skan
12551169689Skan  /* Mask for insertion.  */
12552169689Skan  mask = gen_reg_rtx (SImode);
12553169689Skan  emit_move_insn (mask, GEN_INT (imask));
12554169689Skan  emit_insn (gen_ashlsi3 (mask, mask, shift));
12555169689Skan
12556169689Skan  /* Address of aligned word containing subword.  */
12557169689Skan  align = expand_binop (Pmode, and_optab, XEXP (mem, 0), GEN_INT (-4),
12558169689Skan			NULL_RTX, 1, OPTAB_LIB_WIDEN);
12559169689Skan  mem = change_address (mem, SImode, align);
12560169689Skan  set_mem_align (mem, 32);
12561169689Skan  MEM_VOLATILE_P (mem) = 1;
12562169689Skan
12563169689Skan  wdst = gen_reg_rtx (SImode);
12564169689Skan  emit_insn (gen_sync_compare_and_swapqhi_internal (wdst, mask,
12565169689Skan						    oldval, newval, mem));
12566169689Skan
12567169689Skan  emit_move_insn (dst, gen_lowpart (mode, wdst));
12568169689Skan}
12569169689Skan
12570169689Skanvoid
12571169689Skanrs6000_split_compare_and_swapqhi (rtx dest, rtx mask,
12572169689Skan				  rtx oldval, rtx newval, rtx mem,
12573169689Skan				  rtx scratch)
12574169689Skan{
12575169689Skan  rtx label1, label2, x, cond = gen_rtx_REG (CCmode, CR0_REGNO);
12576169689Skan
12577169689Skan  emit_insn (gen_memory_barrier ());
12578169689Skan  label1 = gen_rtx_LABEL_REF (VOIDmode, gen_label_rtx ());
12579169689Skan  label2 = gen_rtx_LABEL_REF (VOIDmode, gen_label_rtx ());
12580169689Skan  emit_label (XEXP (label1, 0));
12581169689Skan
12582169689Skan  emit_load_locked (SImode, scratch, mem);
12583169689Skan
12584169689Skan  /* Mask subword within loaded value for comparison with oldval.
12585169689Skan     Use UNSPEC_AND to avoid clobber.*/
12586169689Skan  emit_insn (gen_rtx_SET (SImode, dest,
12587169689Skan			  gen_rtx_UNSPEC (SImode,
12588169689Skan					  gen_rtvec (2, scratch, mask),
12589169689Skan					  UNSPEC_AND)));
12590169689Skan
12591169689Skan  x = gen_rtx_COMPARE (CCmode, dest, oldval);
12592169689Skan  emit_insn (gen_rtx_SET (VOIDmode, cond, x));
12593169689Skan
12594169689Skan  x = gen_rtx_NE (VOIDmode, cond, const0_rtx);
12595169689Skan  emit_unlikely_jump (x, label2);
12596169689Skan
12597169689Skan  /* Clear subword within loaded value for insertion of new value.  */
12598169689Skan  emit_insn (gen_rtx_SET (SImode, scratch,
12599169689Skan			  gen_rtx_AND (SImode,
12600169689Skan				       gen_rtx_NOT (SImode, mask), scratch)));
12601169689Skan  emit_insn (gen_iorsi3 (scratch, scratch, newval));
12602169689Skan  emit_store_conditional (SImode, cond, mem, scratch);
12603169689Skan
12604169689Skan  x = gen_rtx_NE (VOIDmode, cond, const0_rtx);
12605169689Skan  emit_unlikely_jump (x, label1);
12606169689Skan
12607169689Skan  emit_insn (gen_isync ());
12608169689Skan  emit_label (XEXP (label2, 0));
12609169689Skan}
12610169689Skan
12611169689Skan
12612169689Skan  /* Emit instructions to move SRC to DST.  Called by splitters for
12613132718Skan   multi-register moves.  It will emit at most one instruction for
12614132718Skan   each register that is accessed; that is, it won't emit li/lis pairs
12615132718Skan   (or equivalent for 64-bit code).  One of SRC or DST must be a hard
12616132718Skan   register.  */
12617132718Skan
12618132718Skanvoid
12619132718Skanrs6000_split_multireg_move (rtx dst, rtx src)
12620132718Skan{
12621132718Skan  /* The register number of the first register being moved.  */
12622132718Skan  int reg;
12623132718Skan  /* The mode that is to be moved.  */
12624132718Skan  enum machine_mode mode;
12625132718Skan  /* The mode that the move is being done in, and its size.  */
12626132718Skan  enum machine_mode reg_mode;
12627132718Skan  int reg_mode_size;
12628132718Skan  /* The number of registers that will be moved.  */
12629132718Skan  int nregs;
12630132718Skan
12631132718Skan  reg = REG_P (dst) ? REGNO (dst) : REGNO (src);
12632132718Skan  mode = GET_MODE (dst);
12633169689Skan  nregs = hard_regno_nregs[reg][mode];
12634132718Skan  if (FP_REGNO_P (reg))
12635132718Skan    reg_mode = DFmode;
12636132718Skan  else if (ALTIVEC_REGNO_P (reg))
12637132718Skan    reg_mode = V16QImode;
12638169689Skan  else if (TARGET_E500_DOUBLE && mode == TFmode)
12639169689Skan    reg_mode = DFmode;
12640132718Skan  else
12641132718Skan    reg_mode = word_mode;
12642132718Skan  reg_mode_size = GET_MODE_SIZE (reg_mode);
12643169689Skan
12644169689Skan  gcc_assert (reg_mode_size * nregs == GET_MODE_SIZE (mode));
12645169689Skan
12646132718Skan  if (REG_P (src) && REG_P (dst) && (REGNO (src) < REGNO (dst)))
12647132718Skan    {
12648132718Skan      /* Move register range backwards, if we might have destructive
12649132718Skan	 overlap.  */
12650132718Skan      int i;
12651132718Skan      for (i = nregs - 1; i >= 0; i--)
12652169689Skan	emit_insn (gen_rtx_SET (VOIDmode,
12653132718Skan				simplify_gen_subreg (reg_mode, dst, mode,
12654132718Skan						     i * reg_mode_size),
12655132718Skan				simplify_gen_subreg (reg_mode, src, mode,
12656132718Skan						     i * reg_mode_size)));
12657132718Skan    }
12658132718Skan  else
12659132718Skan    {
12660132718Skan      int i;
12661132718Skan      int j = -1;
12662132718Skan      bool used_update = false;
12663132718Skan
12664169689Skan      if (MEM_P (src) && INT_REGNO_P (reg))
12665169689Skan	{
12666169689Skan	  rtx breg;
12667132718Skan
12668132718Skan	  if (GET_CODE (XEXP (src, 0)) == PRE_INC
12669132718Skan	      || GET_CODE (XEXP (src, 0)) == PRE_DEC)
12670132718Skan	    {
12671132718Skan	      rtx delta_rtx;
12672132718Skan	      breg = XEXP (XEXP (src, 0), 0);
12673169689Skan	      delta_rtx = (GET_CODE (XEXP (src, 0)) == PRE_INC
12674169689Skan			   ? GEN_INT (GET_MODE_SIZE (GET_MODE (src)))
12675169689Skan			   : GEN_INT (-GET_MODE_SIZE (GET_MODE (src))));
12676132718Skan	      emit_insn (TARGET_32BIT
12677132718Skan			 ? gen_addsi3 (breg, breg, delta_rtx)
12678132718Skan			 : gen_adddi3 (breg, breg, delta_rtx));
12679169689Skan	      src = replace_equiv_address (src, breg);
12680132718Skan	    }
12681169689Skan	  else if (! rs6000_offsettable_memref_p (src))
12682146895Skan	    {
12683169689Skan	      rtx basereg;
12684146895Skan	      basereg = gen_rtx_REG (Pmode, reg);
12685146895Skan	      emit_insn (gen_rtx_SET (VOIDmode, basereg, XEXP (src, 0)));
12686169689Skan	      src = replace_equiv_address (src, basereg);
12687146895Skan	    }
12688132718Skan
12689146895Skan	  breg = XEXP (src, 0);
12690146895Skan	  if (GET_CODE (breg) == PLUS || GET_CODE (breg) == LO_SUM)
12691146895Skan	    breg = XEXP (breg, 0);
12692132718Skan
12693146895Skan	  /* If the base register we are using to address memory is
12694146895Skan	     also a destination reg, then change that register last.  */
12695146895Skan	  if (REG_P (breg)
12696146895Skan	      && REGNO (breg) >= REGNO (dst)
12697132718Skan	      && REGNO (breg) < REGNO (dst) + nregs)
12698132718Skan	    j = REGNO (breg) - REGNO (dst);
12699146895Skan	}
12700132718Skan
12701132718Skan      if (GET_CODE (dst) == MEM && INT_REGNO_P (reg))
12702132718Skan	{
12703132718Skan	  rtx breg;
12704132718Skan
12705132718Skan	  if (GET_CODE (XEXP (dst, 0)) == PRE_INC
12706132718Skan	      || GET_CODE (XEXP (dst, 0)) == PRE_DEC)
12707132718Skan	    {
12708132718Skan	      rtx delta_rtx;
12709132718Skan	      breg = XEXP (XEXP (dst, 0), 0);
12710169689Skan	      delta_rtx = (GET_CODE (XEXP (dst, 0)) == PRE_INC
12711169689Skan			   ? GEN_INT (GET_MODE_SIZE (GET_MODE (dst)))
12712169689Skan			   : GEN_INT (-GET_MODE_SIZE (GET_MODE (dst))));
12713132718Skan
12714132718Skan	      /* We have to update the breg before doing the store.
12715132718Skan		 Use store with update, if available.  */
12716132718Skan
12717132718Skan	      if (TARGET_UPDATE)
12718132718Skan		{
12719132718Skan		  rtx nsrc = simplify_gen_subreg (reg_mode, src, mode, 0);
12720132718Skan		  emit_insn (TARGET_32BIT
12721169689Skan			     ? (TARGET_POWERPC64
12722169689Skan				? gen_movdi_si_update (breg, breg, delta_rtx, nsrc)
12723169689Skan				: gen_movsi_update (breg, breg, delta_rtx, nsrc))
12724169689Skan			     : gen_movdi_di_update (breg, breg, delta_rtx, nsrc));
12725132718Skan		  used_update = true;
12726132718Skan		}
12727132718Skan	      else
12728132718Skan		emit_insn (TARGET_32BIT
12729132718Skan			   ? gen_addsi3 (breg, breg, delta_rtx)
12730132718Skan			   : gen_adddi3 (breg, breg, delta_rtx));
12731169689Skan	      dst = replace_equiv_address (dst, breg);
12732132718Skan	    }
12733169689Skan	  else
12734169689Skan	    gcc_assert (rs6000_offsettable_memref_p (dst));
12735132718Skan	}
12736132718Skan
12737132718Skan      for (i = 0; i < nregs; i++)
12738169689Skan	{
12739132718Skan	  /* Calculate index to next subword.  */
12740132718Skan	  ++j;
12741169689Skan	  if (j == nregs)
12742132718Skan	    j = 0;
12743132718Skan
12744169689Skan	  /* If compiler already emitted move of first word by
12745132718Skan	     store with update, no need to do anything.  */
12746132718Skan	  if (j == 0 && used_update)
12747132718Skan	    continue;
12748169689Skan
12749132718Skan	  emit_insn (gen_rtx_SET (VOIDmode,
12750132718Skan				  simplify_gen_subreg (reg_mode, dst, mode,
12751132718Skan						       j * reg_mode_size),
12752132718Skan				  simplify_gen_subreg (reg_mode, src, mode,
12753132718Skan						       j * reg_mode_size)));
12754132718Skan	}
12755132718Skan    }
12756132718Skan}
12757132718Skan
1275890075Sobrien
1275990075Sobrien/* This page contains routines that are used to determine what the
1276090075Sobrien   function prologue and epilogue code will do and write them out.  */
1276190075Sobrien
1276290075Sobrien/* Return the first fixed-point register that is required to be
1276390075Sobrien   saved. 32 if none.  */
1276490075Sobrien
1276590075Sobrienint
12766132718Skanfirst_reg_to_save (void)
1276790075Sobrien{
1276890075Sobrien  int first_reg;
1276990075Sobrien
1277090075Sobrien  /* Find lowest numbered live register.  */
1277190075Sobrien  for (first_reg = 13; first_reg <= 31; first_reg++)
12772169689Skan    if (regs_ever_live[first_reg]
1277390075Sobrien	&& (! call_used_regs[first_reg]
1277496263Sobrien	    || (first_reg == RS6000_PIC_OFFSET_TABLE_REGNUM
12775117395Skan		&& ((DEFAULT_ABI == ABI_V4 && flag_pic != 0)
12776146895Skan		    || (DEFAULT_ABI == ABI_DARWIN && flag_pic)
12777146895Skan		    || (TARGET_TOC && TARGET_MINIMAL_TOC)))))
1277890075Sobrien      break;
1277990075Sobrien
1278090075Sobrien#if TARGET_MACHO
12781117395Skan  if (flag_pic
12782117395Skan      && current_function_uses_pic_offset_table
12783117395Skan      && first_reg > RS6000_PIC_OFFSET_TABLE_REGNUM)
1278496263Sobrien    return RS6000_PIC_OFFSET_TABLE_REGNUM;
1278590075Sobrien#endif
1278690075Sobrien
1278790075Sobrien  return first_reg;
1278890075Sobrien}
1278990075Sobrien
1279090075Sobrien/* Similar, for FP regs.  */
1279190075Sobrien
1279290075Sobrienint
12793132718Skanfirst_fp_reg_to_save (void)
1279490075Sobrien{
1279590075Sobrien  int first_reg;
1279690075Sobrien
1279790075Sobrien  /* Find lowest numbered live register.  */
1279890075Sobrien  for (first_reg = 14 + 32; first_reg <= 63; first_reg++)
1279990075Sobrien    if (regs_ever_live[first_reg])
1280090075Sobrien      break;
1280190075Sobrien
1280290075Sobrien  return first_reg;
1280390075Sobrien}
1280490075Sobrien
1280590075Sobrien/* Similar, for AltiVec regs.  */
1280690075Sobrien
1280790075Sobrienstatic int
12808132718Skanfirst_altivec_reg_to_save (void)
1280990075Sobrien{
1281090075Sobrien  int i;
1281190075Sobrien
1281290075Sobrien  /* Stack frame remains as is unless we are in AltiVec ABI.  */
1281390075Sobrien  if (! TARGET_ALTIVEC_ABI)
1281490075Sobrien    return LAST_ALTIVEC_REGNO + 1;
1281590075Sobrien
12816169689Skan  /* On Darwin, the unwind routines are compiled without
12817169689Skan     TARGET_ALTIVEC, and use save_world to save/restore the
12818169689Skan     altivec registers when necessary.  */
12819169689Skan  if (DEFAULT_ABI == ABI_DARWIN && current_function_calls_eh_return
12820169689Skan      && ! TARGET_ALTIVEC)
12821169689Skan    return FIRST_ALTIVEC_REGNO + 20;
12822169689Skan
1282390075Sobrien  /* Find lowest numbered live register.  */
1282490075Sobrien  for (i = FIRST_ALTIVEC_REGNO + 20; i <= LAST_ALTIVEC_REGNO; ++i)
1282590075Sobrien    if (regs_ever_live[i])
1282690075Sobrien      break;
1282790075Sobrien
1282890075Sobrien  return i;
1282990075Sobrien}
1283090075Sobrien
1283190075Sobrien/* Return a 32-bit mask of the AltiVec registers we need to set in
1283290075Sobrien   VRSAVE.  Bit n of the return value is 1 if Vn is live.  The MSB in
1283390075Sobrien   the 32-bit word is 0.  */
1283490075Sobrien
1283590075Sobrienstatic unsigned int
12836132718Skancompute_vrsave_mask (void)
1283790075Sobrien{
1283890075Sobrien  unsigned int i, mask = 0;
1283990075Sobrien
12840169689Skan  /* On Darwin, the unwind routines are compiled without
12841169689Skan     TARGET_ALTIVEC, and use save_world to save/restore the
12842169689Skan     call-saved altivec registers when necessary.  */
12843169689Skan  if (DEFAULT_ABI == ABI_DARWIN && current_function_calls_eh_return
12844169689Skan      && ! TARGET_ALTIVEC)
12845169689Skan    mask |= 0xFFF;
12846169689Skan
1284790075Sobrien  /* First, find out if we use _any_ altivec registers.  */
1284890075Sobrien  for (i = FIRST_ALTIVEC_REGNO; i <= LAST_ALTIVEC_REGNO; ++i)
1284990075Sobrien    if (regs_ever_live[i])
1285090075Sobrien      mask |= ALTIVEC_REG_BIT (i);
1285190075Sobrien
1285290075Sobrien  if (mask == 0)
1285390075Sobrien    return mask;
1285490075Sobrien
1285590075Sobrien  /* Next, remove the argument registers from the set.  These must
1285690075Sobrien     be in the VRSAVE mask set by the caller, so we don't need to add
1285790075Sobrien     them in again.  More importantly, the mask we compute here is
1285890075Sobrien     used to generate CLOBBERs in the set_vrsave insn, and we do not
1285990075Sobrien     wish the argument registers to die.  */
12860132718Skan  for (i = cfun->args_info.vregno - 1; i >= ALTIVEC_ARG_MIN_REG; --i)
1286190075Sobrien    mask &= ~ALTIVEC_REG_BIT (i);
1286290075Sobrien
1286390075Sobrien  /* Similarly, remove the return value from the set.  */
1286490075Sobrien  {
1286590075Sobrien    bool yes = false;
1286690075Sobrien    diddle_return_value (is_altivec_return_reg, &yes);
1286790075Sobrien    if (yes)
1286890075Sobrien      mask &= ~ALTIVEC_REG_BIT (ALTIVEC_ARG_RETURN);
1286990075Sobrien  }
1287090075Sobrien
1287190075Sobrien  return mask;
1287290075Sobrien}
1287390075Sobrien
12874169689Skan/* For a very restricted set of circumstances, we can cut down the
12875169689Skan   size of prologues/epilogues by calling our own save/restore-the-world
12876169689Skan   routines.  */
12877169689Skan
1287890075Sobrienstatic void
12879169689Skancompute_save_world_info (rs6000_stack_t *info_ptr)
12880169689Skan{
12881169689Skan  info_ptr->world_save_p = 1;
12882169689Skan  info_ptr->world_save_p
12883169689Skan    = (WORLD_SAVE_P (info_ptr)
12884169689Skan       && DEFAULT_ABI == ABI_DARWIN
12885169689Skan       && ! (current_function_calls_setjmp && flag_exceptions)
12886169689Skan       && info_ptr->first_fp_reg_save == FIRST_SAVED_FP_REGNO
12887169689Skan       && info_ptr->first_gp_reg_save == FIRST_SAVED_GP_REGNO
12888169689Skan       && info_ptr->first_altivec_reg_save == FIRST_SAVED_ALTIVEC_REGNO
12889169689Skan       && info_ptr->cr_save_p);
12890169689Skan
12891169689Skan  /* This will not work in conjunction with sibcalls.  Make sure there
12892169689Skan     are none.  (This check is expensive, but seldom executed.) */
12893169689Skan  if (WORLD_SAVE_P (info_ptr))
12894169689Skan    {
12895169689Skan      rtx insn;
12896169689Skan      for ( insn = get_last_insn_anywhere (); insn; insn = PREV_INSN (insn))
12897169689Skan	if ( GET_CODE (insn) == CALL_INSN
12898169689Skan	     && SIBLING_CALL_P (insn))
12899169689Skan	  {
12900169689Skan	    info_ptr->world_save_p = 0;
12901169689Skan	    break;
12902169689Skan	  }
12903169689Skan    }
12904169689Skan
12905169689Skan  if (WORLD_SAVE_P (info_ptr))
12906169689Skan    {
12907169689Skan      /* Even if we're not touching VRsave, make sure there's room on the
12908169689Skan	 stack for it, if it looks like we're calling SAVE_WORLD, which
12909169689Skan	 will attempt to save it. */
12910169689Skan      info_ptr->vrsave_size  = 4;
12911169689Skan
12912169689Skan      /* "Save" the VRsave register too if we're saving the world.  */
12913169689Skan      if (info_ptr->vrsave_mask == 0)
12914169689Skan	info_ptr->vrsave_mask = compute_vrsave_mask ();
12915169689Skan
12916169689Skan      /* Because the Darwin register save/restore routines only handle
12917169689Skan	 F14 .. F31 and V20 .. V31 as per the ABI, perform a consistency
12918169689Skan	 check.  */
12919169689Skan      gcc_assert (info_ptr->first_fp_reg_save >= FIRST_SAVED_FP_REGNO
12920169689Skan		  && (info_ptr->first_altivec_reg_save
12921169689Skan		      >= FIRST_SAVED_ALTIVEC_REGNO));
12922169689Skan    }
12923169689Skan  return;
12924169689Skan}
12925169689Skan
12926169689Skan
12927169689Skanstatic void
12928132718Skanis_altivec_return_reg (rtx reg, void *xyes)
1292990075Sobrien{
1293090075Sobrien  bool *yes = (bool *) xyes;
1293190075Sobrien  if (REGNO (reg) == ALTIVEC_ARG_RETURN)
1293290075Sobrien    *yes = true;
1293390075Sobrien}
1293490075Sobrien
1293590075Sobrien
1293690075Sobrien/* Calculate the stack information for the current function.  This is
1293790075Sobrien   complicated by having two separate calling sequences, the AIX calling
1293890075Sobrien   sequence and the V.4 calling sequence.
1293990075Sobrien
1294090075Sobrien   AIX (and Darwin/Mac OS X) stack frames look like:
1294190075Sobrien							  32-bit  64-bit
1294290075Sobrien	SP---->	+---------------------------------------+
1294390075Sobrien		| back chain to caller			| 0	  0
1294490075Sobrien		+---------------------------------------+
1294590075Sobrien		| saved CR				| 4       8 (8-11)
1294690075Sobrien		+---------------------------------------+
1294790075Sobrien		| saved LR				| 8       16
1294890075Sobrien		+---------------------------------------+
1294990075Sobrien		| reserved for compilers		| 12      24
1295090075Sobrien		+---------------------------------------+
1295190075Sobrien		| reserved for binders			| 16      32
1295290075Sobrien		+---------------------------------------+
1295390075Sobrien		| saved TOC pointer			| 20      40
1295490075Sobrien		+---------------------------------------+
1295590075Sobrien		| Parameter save area (P)		| 24      48
1295690075Sobrien		+---------------------------------------+
1295790075Sobrien		| Alloca space (A)			| 24+P    etc.
1295890075Sobrien		+---------------------------------------+
1295990075Sobrien		| Local variable space (L)		| 24+P+A
1296090075Sobrien		+---------------------------------------+
1296190075Sobrien		| Float/int conversion temporary (X)	| 24+P+A+L
1296290075Sobrien		+---------------------------------------+
1296390075Sobrien		| Save area for AltiVec registers (W)	| 24+P+A+L+X
1296490075Sobrien		+---------------------------------------+
1296590075Sobrien		| AltiVec alignment padding (Y)		| 24+P+A+L+X+W
1296690075Sobrien		+---------------------------------------+
1296790075Sobrien		| Save area for VRSAVE register (Z)	| 24+P+A+L+X+W+Y
1296890075Sobrien		+---------------------------------------+
1296990075Sobrien		| Save area for GP registers (G)	| 24+P+A+X+L+X+W+Y+Z
1297090075Sobrien		+---------------------------------------+
1297190075Sobrien		| Save area for FP registers (F)	| 24+P+A+X+L+X+W+Y+Z+G
1297290075Sobrien		+---------------------------------------+
1297390075Sobrien	old SP->| back chain to caller's caller		|
1297490075Sobrien		+---------------------------------------+
1297590075Sobrien
1297690075Sobrien   The required alignment for AIX configurations is two words (i.e., 8
1297790075Sobrien   or 16 bytes).
1297890075Sobrien
1297990075Sobrien
1298090075Sobrien   V.4 stack frames look like:
1298190075Sobrien
1298290075Sobrien	SP---->	+---------------------------------------+
1298390075Sobrien		| back chain to caller			| 0
1298490075Sobrien		+---------------------------------------+
1298590075Sobrien		| caller's saved LR			| 4
1298690075Sobrien		+---------------------------------------+
1298790075Sobrien		| Parameter save area (P)		| 8
1298890075Sobrien		+---------------------------------------+
1298990075Sobrien		| Alloca space (A)			| 8+P
12990169689Skan		+---------------------------------------+
1299190075Sobrien		| Varargs save area (V)			| 8+P+A
12992169689Skan		+---------------------------------------+
1299390075Sobrien		| Local variable space (L)		| 8+P+A+V
12994169689Skan		+---------------------------------------+
1299590075Sobrien		| Float/int conversion temporary (X)	| 8+P+A+V+L
1299690075Sobrien		+---------------------------------------+
1299790075Sobrien		| Save area for AltiVec registers (W)	| 8+P+A+V+L+X
1299890075Sobrien		+---------------------------------------+
1299990075Sobrien		| AltiVec alignment padding (Y)		| 8+P+A+V+L+X+W
1300090075Sobrien		+---------------------------------------+
1300190075Sobrien		| Save area for VRSAVE register (Z)	| 8+P+A+V+L+X+W+Y
1300290075Sobrien		+---------------------------------------+
13003169689Skan		| SPE: area for 64-bit GP registers	|
13004169689Skan		+---------------------------------------+
13005169689Skan		| SPE alignment padding			|
13006169689Skan		+---------------------------------------+
1300790075Sobrien		| saved CR (C)				| 8+P+A+V+L+X+W+Y+Z
13008169689Skan		+---------------------------------------+
1300990075Sobrien		| Save area for GP registers (G)	| 8+P+A+V+L+X+W+Y+Z+C
13010169689Skan		+---------------------------------------+
1301190075Sobrien		| Save area for FP registers (F)	| 8+P+A+V+L+X+W+Y+Z+C+G
1301290075Sobrien		+---------------------------------------+
1301390075Sobrien	old SP->| back chain to caller's caller		|
1301490075Sobrien		+---------------------------------------+
1301590075Sobrien
1301690075Sobrien   The required alignment for V.4 is 16 bytes, or 8 bytes if -meabi is
1301790075Sobrien   given.  (But note below and in sysv4.h that we require only 8 and
1301890075Sobrien   may round up the size of our stack frame anyways.  The historical
1301990075Sobrien   reason is early versions of powerpc-linux which didn't properly
1302090075Sobrien   align the stack at program startup.  A happy side-effect is that
1302190075Sobrien   -mno-eabi libraries can be used with -meabi programs.)
1302290075Sobrien
13023132718Skan   The EABI configuration defaults to the V.4 layout.  However,
1302490075Sobrien   the stack alignment requirements may differ.  If -mno-eabi is not
1302590075Sobrien   given, the required stack alignment is 8 bytes; if -mno-eabi is
1302690075Sobrien   given, the required alignment is 16 bytes.  (But see V.4 comment
1302790075Sobrien   above.)  */
1302890075Sobrien
1302990075Sobrien#ifndef ABI_STACK_BOUNDARY
1303090075Sobrien#define ABI_STACK_BOUNDARY STACK_BOUNDARY
1303190075Sobrien#endif
1303290075Sobrien
13033132718Skanstatic rs6000_stack_t *
13034132718Skanrs6000_stack_info (void)
1303590075Sobrien{
13036169689Skan  static rs6000_stack_t info;
1303790075Sobrien  rs6000_stack_t *info_ptr = &info;
13038132718Skan  int reg_size = TARGET_32BIT ? 4 : 8;
1303990075Sobrien  int ehrd_size;
13040146895Skan  int save_align;
13041132718Skan  HOST_WIDE_INT non_fixed_size;
1304290075Sobrien
13043169689Skan  memset (&info, 0, sizeof (info));
1304490075Sobrien
13045132718Skan  if (TARGET_SPE)
13046132718Skan    {
13047132718Skan      /* Cache value so we don't rescan instruction chain over and over.  */
13048132718Skan      if (cfun->machine->insn_chain_scanned_p == 0)
13049169689Skan	cfun->machine->insn_chain_scanned_p
13050169689Skan	  = spe_func_has_64bit_regs_p () + 1;
13051169689Skan      info_ptr->spe_64bit_regs_used = cfun->machine->insn_chain_scanned_p - 1;
13052132718Skan    }
13053132718Skan
1305490075Sobrien  /* Select which calling sequence.  */
13055132718Skan  info_ptr->abi = DEFAULT_ABI;
1305690075Sobrien
1305790075Sobrien  /* Calculate which registers need to be saved & save area size.  */
1305890075Sobrien  info_ptr->first_gp_reg_save = first_reg_to_save ();
13059169689Skan  /* Assume that we will have to save RS6000_PIC_OFFSET_TABLE_REGNUM,
1306090075Sobrien     even if it currently looks like we won't.  */
1306190075Sobrien  if (((TARGET_TOC && TARGET_MINIMAL_TOC)
13062132718Skan       || (flag_pic == 1 && DEFAULT_ABI == ABI_V4)
13063132718Skan       || (flag_pic && DEFAULT_ABI == ABI_DARWIN))
1306496263Sobrien      && info_ptr->first_gp_reg_save > RS6000_PIC_OFFSET_TABLE_REGNUM)
1306596263Sobrien    info_ptr->gp_size = reg_size * (32 - RS6000_PIC_OFFSET_TABLE_REGNUM);
1306690075Sobrien  else
1306790075Sobrien    info_ptr->gp_size = reg_size * (32 - info_ptr->first_gp_reg_save);
1306890075Sobrien
13069117395Skan  /* For the SPE, we have an additional upper 32-bits on each GPR.
13070117395Skan     Ideally we should save the entire 64-bits only when the upper
13071117395Skan     half is used in SIMD instructions.  Since we only record
13072117395Skan     registers live (not the size they are used in), this proves
13073117395Skan     difficult because we'd have to traverse the instruction chain at
13074117395Skan     the right time, taking reload into account.  This is a real pain,
13075132718Skan     so we opt to save the GPRs in 64-bits always if but one register
13076132718Skan     gets used in 64-bits.  Otherwise, all the registers in the frame
13077132718Skan     get saved in 32-bits.
13078117395Skan
13079132718Skan     So... since when we save all GPRs (except the SP) in 64-bits, the
13080117395Skan     traditional GP save area will be empty.  */
13081132718Skan  if (TARGET_SPE_ABI && info_ptr->spe_64bit_regs_used != 0)
13082117395Skan    info_ptr->gp_size = 0;
13083117395Skan
1308490075Sobrien  info_ptr->first_fp_reg_save = first_fp_reg_to_save ();
1308590075Sobrien  info_ptr->fp_size = 8 * (64 - info_ptr->first_fp_reg_save);
1308690075Sobrien
1308790075Sobrien  info_ptr->first_altivec_reg_save = first_altivec_reg_to_save ();
1308890075Sobrien  info_ptr->altivec_size = 16 * (LAST_ALTIVEC_REGNO + 1
1308990075Sobrien				 - info_ptr->first_altivec_reg_save);
1309090075Sobrien
1309190075Sobrien  /* Does this function call anything?  */
1309290075Sobrien  info_ptr->calls_p = (! current_function_is_leaf
1309390075Sobrien		       || cfun->machine->ra_needs_full_frame);
1309490075Sobrien
1309590075Sobrien  /* Determine if we need to save the link register.  */
13096169689Skan  if ((DEFAULT_ABI == ABI_AIX
13097169689Skan       && current_function_profile
13098169689Skan       && !TARGET_PROFILE_KERNEL)
1309990075Sobrien#ifdef TARGET_RELOCATABLE
1310090075Sobrien      || (TARGET_RELOCATABLE && (get_pool_size () != 0))
1310190075Sobrien#endif
1310290075Sobrien      || (info_ptr->first_fp_reg_save != 64
1310390075Sobrien	  && !FP_SAVE_INLINE (info_ptr->first_fp_reg_save))
1310490075Sobrien      || info_ptr->first_altivec_reg_save <= LAST_ALTIVEC_REGNO
13105132718Skan      || (DEFAULT_ABI == ABI_V4 && current_function_calls_alloca)
13106169689Skan      || info_ptr->calls_p
13107169689Skan      || rs6000_ra_ever_killed ())
1310890075Sobrien    {
1310990075Sobrien      info_ptr->lr_save_p = 1;
1311090075Sobrien      regs_ever_live[LINK_REGISTER_REGNUM] = 1;
1311190075Sobrien    }
1311290075Sobrien
1311390075Sobrien  /* Determine if we need to save the condition code registers.  */
13114169689Skan  if (regs_ever_live[CR2_REGNO]
1311590075Sobrien      || regs_ever_live[CR3_REGNO]
1311690075Sobrien      || regs_ever_live[CR4_REGNO])
1311790075Sobrien    {
1311890075Sobrien      info_ptr->cr_save_p = 1;
13119132718Skan      if (DEFAULT_ABI == ABI_V4)
1312090075Sobrien	info_ptr->cr_size = reg_size;
1312190075Sobrien    }
1312290075Sobrien
1312390075Sobrien  /* If the current function calls __builtin_eh_return, then we need
1312490075Sobrien     to allocate stack space for registers that will hold data for
1312590075Sobrien     the exception handler.  */
1312690075Sobrien  if (current_function_calls_eh_return)
1312790075Sobrien    {
1312890075Sobrien      unsigned int i;
1312990075Sobrien      for (i = 0; EH_RETURN_DATA_REGNO (i) != INVALID_REGNUM; ++i)
1313090075Sobrien	continue;
13131117395Skan
13132117395Skan      /* SPE saves EH registers in 64-bits.  */
13133132718Skan      ehrd_size = i * (TARGET_SPE_ABI
13134132718Skan		       && info_ptr->spe_64bit_regs_used != 0
13135132718Skan		       ? UNITS_PER_SPE_WORD : UNITS_PER_WORD);
1313690075Sobrien    }
1313790075Sobrien  else
1313890075Sobrien    ehrd_size = 0;
1313990075Sobrien
1314090075Sobrien  /* Determine various sizes.  */
1314190075Sobrien  info_ptr->reg_size     = reg_size;
1314290075Sobrien  info_ptr->fixed_size   = RS6000_SAVE_AREA;
1314390075Sobrien  info_ptr->vars_size    = RS6000_ALIGN (get_frame_size (), 8);
1314490075Sobrien  info_ptr->parm_size    = RS6000_ALIGN (current_function_outgoing_args_size,
13145132718Skan					 TARGET_ALTIVEC ? 16 : 8);
13146169689Skan  if (FRAME_GROWS_DOWNWARD)
13147169689Skan    info_ptr->vars_size
13148169689Skan      += RS6000_ALIGN (info_ptr->fixed_size + info_ptr->vars_size
13149169689Skan		       + info_ptr->parm_size,
13150169689Skan		       ABI_STACK_BOUNDARY / BITS_PER_UNIT)
13151169689Skan	 - (info_ptr->fixed_size + info_ptr->vars_size
13152169689Skan	    + info_ptr->parm_size);
1315390075Sobrien
13154132718Skan  if (TARGET_SPE_ABI && info_ptr->spe_64bit_regs_used != 0)
13155117395Skan    info_ptr->spe_gp_size = 8 * (32 - info_ptr->first_gp_reg_save);
13156117395Skan  else
13157117395Skan    info_ptr->spe_gp_size = 0;
13158117395Skan
13159132718Skan  if (TARGET_ALTIVEC_ABI)
13160132718Skan    info_ptr->vrsave_mask = compute_vrsave_mask ();
1316190075Sobrien  else
13162132718Skan    info_ptr->vrsave_mask = 0;
1316390075Sobrien
13164132718Skan  if (TARGET_ALTIVEC_VRSAVE && info_ptr->vrsave_mask)
13165132718Skan    info_ptr->vrsave_size  = 4;
13166132718Skan  else
13167132718Skan    info_ptr->vrsave_size  = 0;
13168132718Skan
13169169689Skan  compute_save_world_info (info_ptr);
13170169689Skan
1317190075Sobrien  /* Calculate the offsets.  */
13172132718Skan  switch (DEFAULT_ABI)
1317390075Sobrien    {
1317490075Sobrien    case ABI_NONE:
1317590075Sobrien    default:
13176169689Skan      gcc_unreachable ();
1317790075Sobrien
1317890075Sobrien    case ABI_AIX:
1317990075Sobrien    case ABI_DARWIN:
1318090075Sobrien      info_ptr->fp_save_offset   = - info_ptr->fp_size;
1318190075Sobrien      info_ptr->gp_save_offset   = info_ptr->fp_save_offset - info_ptr->gp_size;
1318290075Sobrien
1318390075Sobrien      if (TARGET_ALTIVEC_ABI)
1318490075Sobrien	{
1318590075Sobrien	  info_ptr->vrsave_save_offset
1318690075Sobrien	    = info_ptr->gp_save_offset - info_ptr->vrsave_size;
1318790075Sobrien
13188169689Skan	  /* Align stack so vector save area is on a quadword boundary.
13189169689Skan	     The padding goes above the vectors.  */
1319090075Sobrien	  if (info_ptr->altivec_size != 0)
1319190075Sobrien	    info_ptr->altivec_padding_size
13192169689Skan	      = info_ptr->vrsave_save_offset & 0xF;
1319390075Sobrien	  else
1319490075Sobrien	    info_ptr->altivec_padding_size = 0;
1319590075Sobrien
1319690075Sobrien	  info_ptr->altivec_save_offset
1319790075Sobrien	    = info_ptr->vrsave_save_offset
1319890075Sobrien	    - info_ptr->altivec_padding_size
1319990075Sobrien	    - info_ptr->altivec_size;
13200169689Skan	  gcc_assert (info_ptr->altivec_size == 0
13201169689Skan		      || info_ptr->altivec_save_offset % 16 == 0);
1320290075Sobrien
1320390075Sobrien	  /* Adjust for AltiVec case.  */
1320490075Sobrien	  info_ptr->ehrd_offset = info_ptr->altivec_save_offset - ehrd_size;
1320590075Sobrien	}
1320690075Sobrien      else
1320790075Sobrien	info_ptr->ehrd_offset      = info_ptr->gp_save_offset - ehrd_size;
1320890075Sobrien      info_ptr->cr_save_offset   = reg_size; /* first word when 64-bit.  */
1320990075Sobrien      info_ptr->lr_save_offset   = 2*reg_size;
1321090075Sobrien      break;
1321190075Sobrien
1321290075Sobrien    case ABI_V4:
1321390075Sobrien      info_ptr->fp_save_offset   = - info_ptr->fp_size;
1321490075Sobrien      info_ptr->gp_save_offset   = info_ptr->fp_save_offset - info_ptr->gp_size;
1321590075Sobrien      info_ptr->cr_save_offset   = info_ptr->gp_save_offset - info_ptr->cr_size;
1321690075Sobrien
13217132718Skan      if (TARGET_SPE_ABI && info_ptr->spe_64bit_regs_used != 0)
13218169689Skan	{
13219169689Skan	  /* Align stack so SPE GPR save area is aligned on a
13220169689Skan	     double-word boundary.  */
13221169689Skan	  if (info_ptr->spe_gp_size != 0)
13222169689Skan	    info_ptr->spe_padding_size
13223169689Skan	      = 8 - (-info_ptr->cr_save_offset % 8);
13224169689Skan	  else
13225169689Skan	    info_ptr->spe_padding_size = 0;
13226117395Skan
13227169689Skan	  info_ptr->spe_gp_save_offset
13228169689Skan	    = info_ptr->cr_save_offset
13229169689Skan	    - info_ptr->spe_padding_size
13230169689Skan	    - info_ptr->spe_gp_size;
13231117395Skan
13232169689Skan	  /* Adjust for SPE case.  */
13233169689Skan	  info_ptr->ehrd_offset = info_ptr->spe_gp_save_offset;
13234169689Skan	}
13235117395Skan      else if (TARGET_ALTIVEC_ABI)
1323690075Sobrien	{
1323790075Sobrien	  info_ptr->vrsave_save_offset
1323890075Sobrien	    = info_ptr->cr_save_offset - info_ptr->vrsave_size;
1323990075Sobrien
1324090075Sobrien	  /* Align stack so vector save area is on a quadword boundary.  */
1324190075Sobrien	  if (info_ptr->altivec_size != 0)
1324290075Sobrien	    info_ptr->altivec_padding_size
1324390075Sobrien	      = 16 - (-info_ptr->vrsave_save_offset % 16);
1324490075Sobrien	  else
1324590075Sobrien	    info_ptr->altivec_padding_size = 0;
1324690075Sobrien
1324790075Sobrien	  info_ptr->altivec_save_offset
1324890075Sobrien	    = info_ptr->vrsave_save_offset
1324990075Sobrien	    - info_ptr->altivec_padding_size
1325090075Sobrien	    - info_ptr->altivec_size;
1325190075Sobrien
1325290075Sobrien	  /* Adjust for AltiVec case.  */
13253169689Skan	  info_ptr->ehrd_offset = info_ptr->altivec_save_offset;
1325490075Sobrien	}
1325590075Sobrien      else
13256169689Skan	info_ptr->ehrd_offset    = info_ptr->cr_save_offset;
13257169689Skan      info_ptr->ehrd_offset      -= ehrd_size;
1325890075Sobrien      info_ptr->lr_save_offset   = reg_size;
1325990075Sobrien      break;
1326090075Sobrien    }
1326190075Sobrien
13262146895Skan  save_align = (TARGET_ALTIVEC_ABI || DEFAULT_ABI == ABI_DARWIN) ? 16 : 8;
1326390075Sobrien  info_ptr->save_size    = RS6000_ALIGN (info_ptr->fp_size
1326490075Sobrien					 + info_ptr->gp_size
1326590075Sobrien					 + info_ptr->altivec_size
1326690075Sobrien					 + info_ptr->altivec_padding_size
13267117395Skan					 + info_ptr->spe_gp_size
13268117395Skan					 + info_ptr->spe_padding_size
1326990075Sobrien					 + ehrd_size
1327090075Sobrien					 + info_ptr->cr_size
13271169689Skan					 + info_ptr->vrsave_size,
13272146895Skan					 save_align);
1327390075Sobrien
13274132718Skan  non_fixed_size	 = (info_ptr->vars_size
1327590075Sobrien			    + info_ptr->parm_size
13276169689Skan			    + info_ptr->save_size);
1327790075Sobrien
13278132718Skan  info_ptr->total_size = RS6000_ALIGN (non_fixed_size + info_ptr->fixed_size,
13279132718Skan				       ABI_STACK_BOUNDARY / BITS_PER_UNIT);
1328090075Sobrien
1328190075Sobrien  /* Determine if we need to allocate any stack frame:
1328290075Sobrien
1328390075Sobrien     For AIX we need to push the stack if a frame pointer is needed
1328490075Sobrien     (because the stack might be dynamically adjusted), if we are
1328590075Sobrien     debugging, if we make calls, or if the sum of fp_save, gp_save,
1328690075Sobrien     and local variables are more than the space needed to save all
1328790075Sobrien     non-volatile registers: 32-bit: 18*8 + 19*4 = 220 or 64-bit: 18*8
1328890075Sobrien     + 18*8 = 288 (GPR13 reserved).
1328990075Sobrien
1329090075Sobrien     For V.4 we don't have the stack cushion that AIX uses, but assume
1329190075Sobrien     that the debugger can handle stackless frames.  */
1329290075Sobrien
1329390075Sobrien  if (info_ptr->calls_p)
1329490075Sobrien    info_ptr->push_p = 1;
1329590075Sobrien
13296132718Skan  else if (DEFAULT_ABI == ABI_V4)
13297132718Skan    info_ptr->push_p = non_fixed_size != 0;
1329890075Sobrien
13299132718Skan  else if (frame_pointer_needed)
13300132718Skan    info_ptr->push_p = 1;
13301132718Skan
13302132718Skan  else if (TARGET_XCOFF && write_symbols != NO_DEBUG)
13303132718Skan    info_ptr->push_p = 1;
13304132718Skan
1330590075Sobrien  else
13306132718Skan    info_ptr->push_p = non_fixed_size > (TARGET_32BIT ? 220 : 288);
1330790075Sobrien
1330890075Sobrien  /* Zero offsets if we're not saving those registers.  */
1330990075Sobrien  if (info_ptr->fp_size == 0)
1331090075Sobrien    info_ptr->fp_save_offset = 0;
1331190075Sobrien
1331290075Sobrien  if (info_ptr->gp_size == 0)
1331390075Sobrien    info_ptr->gp_save_offset = 0;
1331490075Sobrien
1331590075Sobrien  if (! TARGET_ALTIVEC_ABI || info_ptr->altivec_size == 0)
1331690075Sobrien    info_ptr->altivec_save_offset = 0;
1331790075Sobrien
1331890075Sobrien  if (! TARGET_ALTIVEC_ABI || info_ptr->vrsave_mask == 0)
1331990075Sobrien    info_ptr->vrsave_save_offset = 0;
1332090075Sobrien
13321132718Skan  if (! TARGET_SPE_ABI
13322132718Skan      || info_ptr->spe_64bit_regs_used == 0
13323132718Skan      || info_ptr->spe_gp_size == 0)
13324117395Skan    info_ptr->spe_gp_save_offset = 0;
13325117395Skan
1332690075Sobrien  if (! info_ptr->lr_save_p)
1332790075Sobrien    info_ptr->lr_save_offset = 0;
1332890075Sobrien
1332990075Sobrien  if (! info_ptr->cr_save_p)
1333090075Sobrien    info_ptr->cr_save_offset = 0;
1333190075Sobrien
1333290075Sobrien  return info_ptr;
1333390075Sobrien}
1333490075Sobrien
13335132718Skan/* Return true if the current function uses any GPRs in 64-bit SIMD
13336132718Skan   mode.  */
13337132718Skan
13338132718Skanstatic bool
13339132718Skanspe_func_has_64bit_regs_p (void)
1334090075Sobrien{
13341132718Skan  rtx insns, insn;
13342132718Skan
13343132718Skan  /* Functions that save and restore all the call-saved registers will
13344132718Skan     need to save/restore the registers in 64-bits.  */
13345132718Skan  if (current_function_calls_eh_return
13346132718Skan      || current_function_calls_setjmp
13347132718Skan      || current_function_has_nonlocal_goto)
13348132718Skan    return true;
13349132718Skan
13350132718Skan  insns = get_insns ();
13351132718Skan
13352132718Skan  for (insn = NEXT_INSN (insns); insn != NULL_RTX; insn = NEXT_INSN (insn))
13353132718Skan    {
13354132718Skan      if (INSN_P (insn))
13355132718Skan	{
13356132718Skan	  rtx i;
13357132718Skan
13358169689Skan	  /* FIXME: This should be implemented with attributes...
13359169689Skan
13360169689Skan	         (set_attr "spe64" "true")....then,
13361169689Skan	         if (get_spe64(insn)) return true;
13362169689Skan
13363169689Skan	     It's the only reliable way to do the stuff below.  */
13364169689Skan
13365132718Skan	  i = PATTERN (insn);
13366169689Skan	  if (GET_CODE (i) == SET)
13367169689Skan	    {
13368169689Skan	      enum machine_mode mode = GET_MODE (SET_SRC (i));
13369169689Skan
13370169689Skan	      if (SPE_VECTOR_MODE (mode))
13371169689Skan		return true;
13372169689Skan	      if (TARGET_E500_DOUBLE && mode == DFmode)
13373169689Skan		return true;
13374169689Skan	    }
13375132718Skan	}
13376132718Skan    }
13377132718Skan
13378132718Skan  return false;
13379132718Skan}
13380132718Skan
13381132718Skanstatic void
13382132718Skandebug_stack_info (rs6000_stack_t *info)
13383132718Skan{
1338490075Sobrien  const char *abi_string;
1338590075Sobrien
1338690075Sobrien  if (! info)
1338790075Sobrien    info = rs6000_stack_info ();
1338890075Sobrien
1338990075Sobrien  fprintf (stderr, "\nStack information for function %s:\n",
1339090075Sobrien	   ((current_function_decl && DECL_NAME (current_function_decl))
1339190075Sobrien	    ? IDENTIFIER_POINTER (DECL_NAME (current_function_decl))
1339290075Sobrien	    : "<unknown>"));
1339390075Sobrien
1339490075Sobrien  switch (info->abi)
1339590075Sobrien    {
1339690075Sobrien    default:		 abi_string = "Unknown";	break;
1339790075Sobrien    case ABI_NONE:	 abi_string = "NONE";		break;
13398132718Skan    case ABI_AIX:	 abi_string = "AIX";		break;
1339990075Sobrien    case ABI_DARWIN:	 abi_string = "Darwin";		break;
1340090075Sobrien    case ABI_V4:	 abi_string = "V.4";		break;
1340190075Sobrien    }
1340290075Sobrien
1340390075Sobrien  fprintf (stderr, "\tABI                 = %5s\n", abi_string);
1340490075Sobrien
1340590075Sobrien  if (TARGET_ALTIVEC_ABI)
1340690075Sobrien    fprintf (stderr, "\tALTIVEC ABI extensions enabled.\n");
1340790075Sobrien
13408117395Skan  if (TARGET_SPE_ABI)
13409117395Skan    fprintf (stderr, "\tSPE ABI extensions enabled.\n");
13410117395Skan
1341190075Sobrien  if (info->first_gp_reg_save != 32)
1341290075Sobrien    fprintf (stderr, "\tfirst_gp_reg_save   = %5d\n", info->first_gp_reg_save);
1341390075Sobrien
1341490075Sobrien  if (info->first_fp_reg_save != 64)
1341590075Sobrien    fprintf (stderr, "\tfirst_fp_reg_save   = %5d\n", info->first_fp_reg_save);
1341690075Sobrien
1341790075Sobrien  if (info->first_altivec_reg_save <= LAST_ALTIVEC_REGNO)
1341890075Sobrien    fprintf (stderr, "\tfirst_altivec_reg_save = %5d\n",
1341990075Sobrien	     info->first_altivec_reg_save);
1342090075Sobrien
1342190075Sobrien  if (info->lr_save_p)
1342290075Sobrien    fprintf (stderr, "\tlr_save_p           = %5d\n", info->lr_save_p);
1342390075Sobrien
1342490075Sobrien  if (info->cr_save_p)
1342590075Sobrien    fprintf (stderr, "\tcr_save_p           = %5d\n", info->cr_save_p);
1342690075Sobrien
1342790075Sobrien  if (info->vrsave_mask)
1342890075Sobrien    fprintf (stderr, "\tvrsave_mask         = 0x%x\n", info->vrsave_mask);
1342990075Sobrien
1343090075Sobrien  if (info->push_p)
1343190075Sobrien    fprintf (stderr, "\tpush_p              = %5d\n", info->push_p);
1343290075Sobrien
1343390075Sobrien  if (info->calls_p)
1343490075Sobrien    fprintf (stderr, "\tcalls_p             = %5d\n", info->calls_p);
1343590075Sobrien
1343690075Sobrien  if (info->gp_save_offset)
1343790075Sobrien    fprintf (stderr, "\tgp_save_offset      = %5d\n", info->gp_save_offset);
1343890075Sobrien
1343990075Sobrien  if (info->fp_save_offset)
1344090075Sobrien    fprintf (stderr, "\tfp_save_offset      = %5d\n", info->fp_save_offset);
1344190075Sobrien
1344290075Sobrien  if (info->altivec_save_offset)
1344390075Sobrien    fprintf (stderr, "\taltivec_save_offset = %5d\n",
1344490075Sobrien	     info->altivec_save_offset);
1344590075Sobrien
13446117395Skan  if (info->spe_gp_save_offset)
13447117395Skan    fprintf (stderr, "\tspe_gp_save_offset  = %5d\n",
13448117395Skan	     info->spe_gp_save_offset);
13449117395Skan
1345090075Sobrien  if (info->vrsave_save_offset)
1345190075Sobrien    fprintf (stderr, "\tvrsave_save_offset  = %5d\n",
1345290075Sobrien	     info->vrsave_save_offset);
1345390075Sobrien
1345490075Sobrien  if (info->lr_save_offset)
1345590075Sobrien    fprintf (stderr, "\tlr_save_offset      = %5d\n", info->lr_save_offset);
1345690075Sobrien
1345790075Sobrien  if (info->cr_save_offset)
1345890075Sobrien    fprintf (stderr, "\tcr_save_offset      = %5d\n", info->cr_save_offset);
1345990075Sobrien
1346090075Sobrien  if (info->varargs_save_offset)
1346190075Sobrien    fprintf (stderr, "\tvarargs_save_offset = %5d\n", info->varargs_save_offset);
1346290075Sobrien
1346390075Sobrien  if (info->total_size)
13464132718Skan    fprintf (stderr, "\ttotal_size          = "HOST_WIDE_INT_PRINT_DEC"\n",
13465132718Skan	     info->total_size);
1346690075Sobrien
1346790075Sobrien  if (info->vars_size)
13468132718Skan    fprintf (stderr, "\tvars_size           = "HOST_WIDE_INT_PRINT_DEC"\n",
13469132718Skan	     info->vars_size);
1347090075Sobrien
1347190075Sobrien  if (info->parm_size)
1347290075Sobrien    fprintf (stderr, "\tparm_size           = %5d\n", info->parm_size);
1347390075Sobrien
1347490075Sobrien  if (info->fixed_size)
1347590075Sobrien    fprintf (stderr, "\tfixed_size          = %5d\n", info->fixed_size);
1347690075Sobrien
1347790075Sobrien  if (info->gp_size)
1347890075Sobrien    fprintf (stderr, "\tgp_size             = %5d\n", info->gp_size);
1347990075Sobrien
13480117395Skan  if (info->spe_gp_size)
13481117395Skan    fprintf (stderr, "\tspe_gp_size         = %5d\n", info->spe_gp_size);
13482117395Skan
1348390075Sobrien  if (info->fp_size)
1348490075Sobrien    fprintf (stderr, "\tfp_size             = %5d\n", info->fp_size);
1348590075Sobrien
1348690075Sobrien  if (info->altivec_size)
1348790075Sobrien    fprintf (stderr, "\taltivec_size        = %5d\n", info->altivec_size);
1348890075Sobrien
1348990075Sobrien  if (info->vrsave_size)
1349090075Sobrien    fprintf (stderr, "\tvrsave_size         = %5d\n", info->vrsave_size);
1349190075Sobrien
1349290075Sobrien  if (info->altivec_padding_size)
1349390075Sobrien    fprintf (stderr, "\taltivec_padding_size= %5d\n",
1349490075Sobrien	     info->altivec_padding_size);
1349590075Sobrien
13496117395Skan  if (info->spe_padding_size)
13497117395Skan    fprintf (stderr, "\tspe_padding_size    = %5d\n",
13498117395Skan	     info->spe_padding_size);
13499117395Skan
1350090075Sobrien  if (info->cr_size)
1350190075Sobrien    fprintf (stderr, "\tcr_size             = %5d\n", info->cr_size);
1350290075Sobrien
1350390075Sobrien  if (info->save_size)
1350490075Sobrien    fprintf (stderr, "\tsave_size           = %5d\n", info->save_size);
1350590075Sobrien
1350690075Sobrien  if (info->reg_size != 4)
1350790075Sobrien    fprintf (stderr, "\treg_size            = %5d\n", info->reg_size);
1350890075Sobrien
1350990075Sobrien  fprintf (stderr, "\n");
1351090075Sobrien}
1351190075Sobrien
1351290075Sobrienrtx
13513132718Skanrs6000_return_addr (int count, rtx frame)
1351490075Sobrien{
1351590075Sobrien  /* Currently we don't optimize very well between prolog and body
1351690075Sobrien     code and for PIC code the code can be actually quite bad, so
1351790075Sobrien     don't try to be too clever here.  */
13518132718Skan  if (count != 0 || (DEFAULT_ABI != ABI_AIX && flag_pic))
1351990075Sobrien    {
1352090075Sobrien      cfun->machine->ra_needs_full_frame = 1;
1352190075Sobrien
1352290075Sobrien      return
1352390075Sobrien	gen_rtx_MEM
1352490075Sobrien	  (Pmode,
1352590075Sobrien	   memory_address
1352690075Sobrien	   (Pmode,
1352790075Sobrien	    plus_constant (copy_to_reg
1352890075Sobrien			   (gen_rtx_MEM (Pmode,
1352990075Sobrien					 memory_address (Pmode, frame))),
1353090075Sobrien			   RETURN_ADDRESS_OFFSET)));
1353190075Sobrien    }
1353290075Sobrien
13533132718Skan  cfun->machine->ra_need_lr = 1;
1353490075Sobrien  return get_hard_reg_initial_val (Pmode, LINK_REGISTER_REGNUM);
1353590075Sobrien}
1353690075Sobrien
13537117395Skan/* Say whether a function is a candidate for sibcall handling or not.
13538117395Skan   We do not allow indirect calls to be optimized into sibling calls.
13539117395Skan   Also, we can't do it if there are any vector parameters; there's
13540117395Skan   nowhere to put the VRsave code so it works; note that functions with
13541117395Skan   vector parameters are required to have a prototype, so the argument
13542117395Skan   type info must be available here.  (The tail recursion case can work
13543117395Skan   with vector parameters, but there's no way to distinguish here.) */
13544132718Skanstatic bool
13545132718Skanrs6000_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
13546117395Skan{
13547117395Skan  tree type;
13548132718Skan  if (decl)
13549117395Skan    {
13550117395Skan      if (TARGET_ALTIVEC_VRSAVE)
13551169689Skan	{
13552132718Skan	  for (type = TYPE_ARG_TYPES (TREE_TYPE (decl));
13553117395Skan	       type; type = TREE_CHAIN (type))
13554117395Skan	    {
13555117395Skan	      if (TREE_CODE (TREE_VALUE (type)) == VECTOR_TYPE)
13556132718Skan		return false;
13557117395Skan	    }
13558169689Skan	}
13559117395Skan      if (DEFAULT_ABI == ABI_DARWIN
13560171825Skan	  || ((*targetm.binds_local_p) (decl)
13561171825Skan	      && (DEFAULT_ABI != ABI_AIX || !DECL_EXTERNAL (decl))))
13562117395Skan	{
13563132718Skan	  tree attr_list = TYPE_ATTRIBUTES (TREE_TYPE (decl));
13564117395Skan
13565117395Skan	  if (!lookup_attribute ("longcall", attr_list)
13566117395Skan	      || lookup_attribute ("shortcall", attr_list))
13567132718Skan	    return true;
13568117395Skan	}
13569117395Skan    }
13570132718Skan  return false;
13571117395Skan}
13572117395Skan
13573169689Skan/* NULL if INSN insn is valid within a low-overhead loop.
13574169689Skan   Otherwise return why doloop cannot be applied.
13575169689Skan   PowerPC uses the COUNT register for branch on table instructions.  */
13576169689Skan
13577169689Skanstatic const char *
13578169689Skanrs6000_invalid_within_doloop (rtx insn)
13579169689Skan{
13580169689Skan  if (CALL_P (insn))
13581169689Skan    return "Function call in the loop.";
13582169689Skan
13583169689Skan  if (JUMP_P (insn)
13584169689Skan      && (GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC
13585169689Skan	  || GET_CODE (PATTERN (insn)) == ADDR_VEC))
13586169689Skan    return "Computed branch in the loop.";
13587169689Skan
13588169689Skan  return NULL;
13589169689Skan}
13590169689Skan
1359190075Sobrienstatic int
13592132718Skanrs6000_ra_ever_killed (void)
1359390075Sobrien{
1359490075Sobrien  rtx top;
13595117395Skan  rtx reg;
13596117395Skan  rtx insn;
1359790075Sobrien
13598132718Skan  if (current_function_is_thunk)
1359990075Sobrien    return 0;
1360090075Sobrien
13601117395Skan  /* regs_ever_live has LR marked as used if any sibcalls are present,
13602117395Skan     but this should not force saving and restoring in the
13603117395Skan     pro/epilogue.  Likewise, reg_set_between_p thinks a sibcall
13604132718Skan     clobbers LR, so that is inappropriate.  */
13605117395Skan
13606117395Skan  /* Also, the prologue can generate a store into LR that
13607117395Skan     doesn't really count, like this:
13608117395Skan
13609117395Skan        move LR->R0
13610117395Skan        bcl to set PIC register
13611117395Skan        move LR->R31
13612117395Skan        move R0->LR
13613117395Skan
13614117395Skan     When we're called from the epilogue, we need to avoid counting
13615117395Skan     this as a store.  */
13616169689Skan
1361790075Sobrien  push_topmost_sequence ();
1361890075Sobrien  top = get_insns ();
1361990075Sobrien  pop_topmost_sequence ();
13620117395Skan  reg = gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM);
1362190075Sobrien
13622117395Skan  for (insn = NEXT_INSN (top); insn != NULL_RTX; insn = NEXT_INSN (insn))
13623117395Skan    {
13624117395Skan      if (INSN_P (insn))
13625117395Skan	{
13626169689Skan	  if (CALL_P (insn))
13627169689Skan	    {
13628169689Skan	      if (!SIBLING_CALL_P (insn))
13629169689Skan		return 1;
13630169689Skan	    }
13631169689Skan	  else if (find_regno_note (insn, REG_INC, LINK_REGISTER_REGNUM))
13632117395Skan	    return 1;
13633117395Skan	  else if (set_of (reg, insn) != NULL_RTX
13634117395Skan		   && !prologue_epilogue_contains (insn))
13635117395Skan	    return 1;
13636117395Skan    	}
13637117395Skan    }
13638117395Skan  return 0;
1363990075Sobrien}
1364090075Sobrien
1364190075Sobrien/* Add a REG_MAYBE_DEAD note to the insn.  */
1364290075Sobrienstatic void
13643132718Skanrs6000_maybe_dead (rtx insn)
1364490075Sobrien{
1364590075Sobrien  REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD,
1364690075Sobrien					const0_rtx,
1364790075Sobrien					REG_NOTES (insn));
1364890075Sobrien}
1364990075Sobrien
1365090075Sobrien/* Emit instructions needed to load the TOC register.
1365190075Sobrien   This is only needed when TARGET_TOC, TARGET_MINIMAL_TOC, and there is
1365290075Sobrien   a constant pool; or for SVR4 -fpic.  */
1365390075Sobrien
1365490075Sobrienvoid
13655132718Skanrs6000_emit_load_toc_table (int fromprolog)
1365690075Sobrien{
13657117395Skan  rtx dest, insn;
1365896263Sobrien  dest = gen_rtx_REG (Pmode, RS6000_PIC_OFFSET_TABLE_REGNUM);
1365990075Sobrien
13660169689Skan  if (TARGET_ELF && TARGET_SECURE_PLT && DEFAULT_ABI != ABI_AIX && flag_pic)
1366190075Sobrien    {
13662169689Skan      char buf[30];
13663169689Skan      rtx lab, tmp1, tmp2, got, tempLR;
13664169689Skan
13665169689Skan      ASM_GENERATE_INTERNAL_LABEL (buf, "LCF", rs6000_pic_labelno);
13666169689Skan      lab = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
13667169689Skan      if (flag_pic == 2)
13668169689Skan	got = gen_rtx_SYMBOL_REF (Pmode, toc_label_name);
13669169689Skan      else
13670169689Skan	got = rs6000_got_sym ();
13671169689Skan      tmp1 = tmp2 = dest;
13672169689Skan      if (!fromprolog)
13673169689Skan	{
13674169689Skan	  tmp1 = gen_reg_rtx (Pmode);
13675169689Skan	  tmp2 = gen_reg_rtx (Pmode);
13676169689Skan	}
13677169689Skan      tempLR = (fromprolog
13678169689Skan		? gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM)
13679169689Skan		: gen_reg_rtx (Pmode));
13680169689Skan      insn = emit_insn (gen_load_toc_v4_PIC_1 (tempLR, lab));
13681117395Skan      if (fromprolog)
13682117395Skan	rs6000_maybe_dead (insn);
13683169689Skan      insn = emit_move_insn (tmp1, tempLR);
13684117395Skan      if (fromprolog)
13685117395Skan	rs6000_maybe_dead (insn);
13686169689Skan      insn = emit_insn (gen_load_toc_v4_PIC_3b (tmp2, tmp1, got, lab));
13687169689Skan      if (fromprolog)
13688169689Skan	rs6000_maybe_dead (insn);
13689169689Skan      insn = emit_insn (gen_load_toc_v4_PIC_3c (dest, tmp2, got, lab));
13690169689Skan      if (fromprolog)
13691169689Skan	rs6000_maybe_dead (insn);
13692103445Skan    }
13693169689Skan  else if (TARGET_ELF && DEFAULT_ABI == ABI_V4 && flag_pic == 1)
13694169689Skan    {
13695169689Skan      rtx tempLR = (fromprolog
13696169689Skan		    ? gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM)
13697169689Skan		    : gen_reg_rtx (Pmode));
13698169689Skan
13699169689Skan      insn = emit_insn (gen_load_toc_v4_pic_si (tempLR));
13700169689Skan      if (fromprolog)
13701169689Skan	rs6000_maybe_dead (insn);
13702169689Skan      insn = emit_move_insn (dest, tempLR);
13703169689Skan      if (fromprolog)
13704169689Skan	rs6000_maybe_dead (insn);
13705169689Skan    }
13706103445Skan  else if (TARGET_ELF && DEFAULT_ABI != ABI_AIX && flag_pic == 2)
13707103445Skan    {
13708103445Skan      char buf[30];
13709103445Skan      rtx tempLR = (fromprolog
13710103445Skan		    ? gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM)
13711103445Skan		    : gen_reg_rtx (Pmode));
13712103445Skan      rtx temp0 = (fromprolog
13713103445Skan		   ? gen_rtx_REG (Pmode, 0)
13714103445Skan		   : gen_reg_rtx (Pmode));
13715103445Skan
13716103445Skan      if (fromprolog)
13717103445Skan	{
13718146895Skan	  rtx symF, symL;
1371990075Sobrien
13720103445Skan	  ASM_GENERATE_INTERNAL_LABEL (buf, "LCF", rs6000_pic_labelno);
13721103445Skan	  symF = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
1372290075Sobrien
13723103445Skan	  ASM_GENERATE_INTERNAL_LABEL (buf, "LCL", rs6000_pic_labelno);
13724103445Skan	  symL = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
1372590075Sobrien
13726103445Skan	  rs6000_maybe_dead (emit_insn (gen_load_toc_v4_PIC_1 (tempLR,
13727103445Skan							       symF)));
13728103445Skan	  rs6000_maybe_dead (emit_move_insn (dest, tempLR));
13729103445Skan	  rs6000_maybe_dead (emit_insn (gen_load_toc_v4_PIC_2 (temp0, dest,
13730103445Skan							       symL,
13731103445Skan							       symF)));
13732103445Skan	}
13733103445Skan      else
13734103445Skan	{
13735103445Skan	  rtx tocsym;
1373690075Sobrien
13737103445Skan	  tocsym = gen_rtx_SYMBOL_REF (Pmode, toc_label_name);
13738146895Skan	  emit_insn (gen_load_toc_v4_PIC_1b (tempLR, tocsym));
13739117395Skan	  emit_move_insn (dest, tempLR);
13740117395Skan	  emit_move_insn (temp0, gen_rtx_MEM (Pmode, dest));
1374190075Sobrien	}
13742117395Skan      insn = emit_insn (gen_addsi3 (dest, temp0, dest));
13743117395Skan      if (fromprolog)
13744117395Skan	rs6000_maybe_dead (insn);
1374590075Sobrien    }
13746103445Skan  else if (TARGET_ELF && !TARGET_AIX && flag_pic == 0 && TARGET_MINIMAL_TOC)
1374790075Sobrien    {
13748103445Skan      /* This is for AIX code running in non-PIC ELF32.  */
13749103445Skan      char buf[30];
13750103445Skan      rtx realsym;
13751103445Skan      ASM_GENERATE_INTERNAL_LABEL (buf, "LCTOC", 1);
13752103445Skan      realsym = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
13753103445Skan
13754117395Skan      insn = emit_insn (gen_elf_high (dest, realsym));
13755117395Skan      if (fromprolog)
13756117395Skan	rs6000_maybe_dead (insn);
13757117395Skan      insn = emit_insn (gen_elf_low (dest, dest, realsym));
13758117395Skan      if (fromprolog)
13759117395Skan	rs6000_maybe_dead (insn);
13760103445Skan    }
13761169689Skan  else
13762103445Skan    {
13763169689Skan      gcc_assert (DEFAULT_ABI == ABI_AIX);
13764169689Skan
1376590075Sobrien      if (TARGET_32BIT)
13766117395Skan	insn = emit_insn (gen_load_toc_aix_si (dest));
1376790075Sobrien      else
13768117395Skan	insn = emit_insn (gen_load_toc_aix_di (dest));
13769117395Skan      if (fromprolog)
13770117395Skan	rs6000_maybe_dead (insn);
1377190075Sobrien    }
1377290075Sobrien}
1377390075Sobrien
13774132718Skan/* Emit instructions to restore the link register after determining where
13775132718Skan   its value has been stored.  */
13776132718Skan
13777132718Skanvoid
13778132718Skanrs6000_emit_eh_reg_restore (rtx source, rtx scratch)
13779132718Skan{
13780132718Skan  rs6000_stack_t *info = rs6000_stack_info ();
13781132718Skan  rtx operands[2];
13782132718Skan
13783132718Skan  operands[0] = source;
13784132718Skan  operands[1] = scratch;
13785132718Skan
13786132718Skan  if (info->lr_save_p)
13787132718Skan    {
13788132718Skan      rtx frame_rtx = stack_pointer_rtx;
13789132718Skan      HOST_WIDE_INT sp_offset = 0;
13790132718Skan      rtx tmp;
13791132718Skan
13792132718Skan      if (frame_pointer_needed
13793132718Skan	  || current_function_calls_alloca
13794132718Skan	  || info->total_size > 32767)
13795132718Skan	{
13796169689Skan	  tmp = gen_frame_mem (Pmode, frame_rtx);
13797169689Skan	  emit_move_insn (operands[1], tmp);
13798132718Skan	  frame_rtx = operands[1];
13799132718Skan	}
13800132718Skan      else if (info->push_p)
13801132718Skan	sp_offset = info->total_size;
13802132718Skan
13803132718Skan      tmp = plus_constant (frame_rtx, info->lr_save_offset + sp_offset);
13804169689Skan      tmp = gen_frame_mem (Pmode, tmp);
13805132718Skan      emit_move_insn (tmp, operands[0]);
13806132718Skan    }
13807132718Skan  else
13808132718Skan    emit_move_insn (gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM), operands[0]);
13809132718Skan}
13810132718Skan
13811132718Skanstatic GTY(()) int set = -1;
13812132718Skan
13813169689Skanint
13814132718Skanget_TOC_alias_set (void)
1381590075Sobrien{
13816132718Skan  if (set == -1)
13817132718Skan    set = new_alias_set ();
13818132718Skan  return set;
13819169689Skan}
1382090075Sobrien
13821132718Skan/* This returns nonzero if the current function uses the TOC.  This is
13822132718Skan   determined by the presence of (use (unspec ... UNSPEC_TOC)), which
13823132718Skan   is generated by the ABI_V4 load_toc_* patterns.  */
13824132718Skan#if TARGET_ELF
13825132718Skanstatic int
13826169689Skanuses_TOC (void)
1382790075Sobrien{
13828132718Skan  rtx insn;
1382990075Sobrien
13830132718Skan  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
13831132718Skan    if (INSN_P (insn))
13832132718Skan      {
13833132718Skan	rtx pat = PATTERN (insn);
13834132718Skan	int i;
1383590075Sobrien
13836169689Skan	if (GET_CODE (pat) == PARALLEL)
13837132718Skan	  for (i = 0; i < XVECLEN (pat, 0); i++)
13838132718Skan	    {
13839132718Skan	      rtx sub = XVECEXP (pat, 0, i);
13840132718Skan	      if (GET_CODE (sub) == USE)
13841132718Skan		{
13842132718Skan		  sub = XEXP (sub, 0);
13843132718Skan		  if (GET_CODE (sub) == UNSPEC
13844132718Skan		      && XINT (sub, 1) == UNSPEC_TOC)
13845132718Skan		    return 1;
13846132718Skan		}
13847132718Skan	    }
13848132718Skan      }
13849132718Skan  return 0;
1385090075Sobrien}
13851132718Skan#endif
1385290075Sobrien
1385390075Sobrienrtx
13854169689Skancreate_TOC_reference (rtx symbol)
1385590075Sobrien{
13856161651Skan  if (no_new_pseudos)
13857161651Skan    regs_ever_live[TOC_REGISTER] = 1;
13858169689Skan  return gen_rtx_PLUS (Pmode,
1385990075Sobrien	   gen_rtx_REG (Pmode, TOC_REGISTER),
13860169689Skan	     gen_rtx_CONST (Pmode,
13861169689Skan	       gen_rtx_MINUS (Pmode, symbol,
1386290075Sobrien		 gen_rtx_SYMBOL_REF (Pmode, toc_label_name))));
1386390075Sobrien}
1386490075Sobrien
13865132718Skan/* If _Unwind_* has been called from within the same module,
13866132718Skan   toc register is not guaranteed to be saved to 40(1) on function
13867132718Skan   entry.  Save it there in that case.  */
1386890075Sobrien
1386990075Sobrienvoid
13870132718Skanrs6000_aix_emit_builtin_unwind_init (void)
1387190075Sobrien{
1387290075Sobrien  rtx mem;
1387390075Sobrien  rtx stack_top = gen_reg_rtx (Pmode);
1387490075Sobrien  rtx opcode_addr = gen_reg_rtx (Pmode);
13875132718Skan  rtx opcode = gen_reg_rtx (SImode);
13876132718Skan  rtx tocompare = gen_reg_rtx (SImode);
13877132718Skan  rtx no_toc_save_needed = gen_label_rtx ();
1387890075Sobrien
13879169689Skan  mem = gen_frame_mem (Pmode, hard_frame_pointer_rtx);
1388090075Sobrien  emit_move_insn (stack_top, mem);
1388190075Sobrien
13882169689Skan  mem = gen_frame_mem (Pmode,
13883169689Skan		       gen_rtx_PLUS (Pmode, stack_top,
13884169689Skan				     GEN_INT (2 * GET_MODE_SIZE (Pmode))));
1388590075Sobrien  emit_move_insn (opcode_addr, mem);
13886132718Skan  emit_move_insn (opcode, gen_rtx_MEM (SImode, opcode_addr));
13887132718Skan  emit_move_insn (tocompare, gen_int_mode (TARGET_32BIT ? 0x80410014
13888117395Skan					   : 0xE8410028, SImode));
1388990075Sobrien
13890132718Skan  do_compare_rtx_and_jump (opcode, tocompare, EQ, 1,
1389190075Sobrien			   SImode, NULL_RTX, NULL_RTX,
13892132718Skan			   no_toc_save_needed);
13893132718Skan
13894169689Skan  mem = gen_frame_mem (Pmode,
13895169689Skan		       gen_rtx_PLUS (Pmode, stack_top,
13896169689Skan				     GEN_INT (5 * GET_MODE_SIZE (Pmode))));
13897132718Skan  emit_move_insn (mem, gen_rtx_REG (Pmode, 2));
13898132718Skan  emit_label (no_toc_save_needed);
1389990075Sobrien}
1390090075Sobrien
13901169689Skan/* This ties together stack memory (MEM with an alias set of frame_alias_set)
13902169689Skan   and the change to the stack pointer.  */
1390390075Sobrien
1390490075Sobrienstatic void
13905132718Skanrs6000_emit_stack_tie (void)
1390690075Sobrien{
13907169689Skan  rtx mem = gen_frame_mem (BLKmode,
13908169689Skan			   gen_rtx_REG (Pmode, STACK_POINTER_REGNUM));
1390990075Sobrien
1391090075Sobrien  emit_insn (gen_stack_tie (mem));
1391190075Sobrien}
1391290075Sobrien
1391390075Sobrien/* Emit the correct code for allocating stack space, as insns.
1391490075Sobrien   If COPY_R12, make sure a copy of the old frame is left in r12.
1391590075Sobrien   The generated code may use hard register 0 as a temporary.  */
1391690075Sobrien
1391790075Sobrienstatic void
13918132718Skanrs6000_emit_allocate_stack (HOST_WIDE_INT size, int copy_r12)
1391990075Sobrien{
1392090075Sobrien  rtx insn;
1392190075Sobrien  rtx stack_reg = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
1392290075Sobrien  rtx tmp_reg = gen_rtx_REG (Pmode, 0);
13923169689Skan  rtx todec = gen_int_mode (-size, Pmode);
1392490075Sobrien
13925169689Skan  if (INTVAL (todec) != -size)
13926169689Skan    {
13927169689Skan      warning (0, "stack frame too large");
13928169689Skan      emit_insn (gen_trap ());
13929169689Skan      return;
13930169689Skan    }
13931169689Skan
1393290075Sobrien  if (current_function_limit_stack)
1393390075Sobrien    {
1393490075Sobrien      if (REG_P (stack_limit_rtx)
13935169689Skan	  && REGNO (stack_limit_rtx) > 1
1393690075Sobrien	  && REGNO (stack_limit_rtx) <= 31)
1393790075Sobrien	{
13938132718Skan	  emit_insn (TARGET_32BIT
1393990075Sobrien		     ? gen_addsi3 (tmp_reg,
1394090075Sobrien				   stack_limit_rtx,
1394190075Sobrien				   GEN_INT (size))
1394290075Sobrien		     : gen_adddi3 (tmp_reg,
1394390075Sobrien				   stack_limit_rtx,
1394490075Sobrien				   GEN_INT (size)));
13945132718Skan
1394690075Sobrien	  emit_insn (gen_cond_trap (LTU, stack_reg, tmp_reg,
1394790075Sobrien				    const0_rtx));
1394890075Sobrien	}
1394990075Sobrien      else if (GET_CODE (stack_limit_rtx) == SYMBOL_REF
1395090075Sobrien	       && TARGET_32BIT
1395190075Sobrien	       && DEFAULT_ABI == ABI_V4)
1395290075Sobrien	{
1395390075Sobrien	  rtx toload = gen_rtx_CONST (VOIDmode,
13954169689Skan				      gen_rtx_PLUS (Pmode,
13955169689Skan						    stack_limit_rtx,
1395690075Sobrien						    GEN_INT (size)));
13957132718Skan
1395890075Sobrien	  emit_insn (gen_elf_high (tmp_reg, toload));
1395990075Sobrien	  emit_insn (gen_elf_low (tmp_reg, tmp_reg, toload));
1396090075Sobrien	  emit_insn (gen_cond_trap (LTU, stack_reg, tmp_reg,
1396190075Sobrien				    const0_rtx));
1396290075Sobrien	}
1396390075Sobrien      else
13964169689Skan	warning (0, "stack limit expression is not supported");
1396590075Sobrien    }
1396690075Sobrien
1396790075Sobrien  if (copy_r12 || ! TARGET_UPDATE)
1396890075Sobrien    emit_move_insn (gen_rtx_REG (Pmode, 12), stack_reg);
1396990075Sobrien
1397090075Sobrien  if (TARGET_UPDATE)
1397190075Sobrien    {
1397290075Sobrien      if (size > 32767)
1397390075Sobrien	{
1397490075Sobrien	  /* Need a note here so that try_split doesn't get confused.  */
13975169689Skan	  if (get_last_insn () == NULL_RTX)
13976132718Skan	    emit_note (NOTE_INSN_DELETED);
1397790075Sobrien	  insn = emit_move_insn (tmp_reg, todec);
1397890075Sobrien	  try_split (PATTERN (insn), insn, 0);
1397990075Sobrien	  todec = tmp_reg;
1398090075Sobrien	}
13981132718Skan
13982132718Skan      insn = emit_insn (TARGET_32BIT
13983132718Skan			? gen_movsi_update (stack_reg, stack_reg,
13984132718Skan					    todec, stack_reg)
13985169689Skan			: gen_movdi_di_update (stack_reg, stack_reg,
1398690075Sobrien					    todec, stack_reg));
1398790075Sobrien    }
1398890075Sobrien  else
1398990075Sobrien    {
13990132718Skan      insn = emit_insn (TARGET_32BIT
13991132718Skan			? gen_addsi3 (stack_reg, stack_reg, todec)
13992132718Skan			: gen_adddi3 (stack_reg, stack_reg, todec));
1399390075Sobrien      emit_move_insn (gen_rtx_MEM (Pmode, stack_reg),
1399490075Sobrien		      gen_rtx_REG (Pmode, 12));
1399590075Sobrien    }
13996169689Skan
1399790075Sobrien  RTX_FRAME_RELATED_P (insn) = 1;
13998169689Skan  REG_NOTES (insn) =
1399990075Sobrien    gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
14000169689Skan		       gen_rtx_SET (VOIDmode, stack_reg,
1400190075Sobrien				    gen_rtx_PLUS (Pmode, stack_reg,
1400290075Sobrien						  GEN_INT (-size))),
1400390075Sobrien		       REG_NOTES (insn));
1400490075Sobrien}
1400590075Sobrien
1400690075Sobrien/* Add to 'insn' a note which is PATTERN (INSN) but with REG replaced
1400790075Sobrien   with (plus:P (reg 1) VAL), and with REG2 replaced with RREG if REG2
1400890075Sobrien   is not NULL.  It would be nice if dwarf2out_frame_debug_expr could
1400990075Sobrien   deduce these equivalences by itself so it wasn't necessary to hold
1401090075Sobrien   its hand so much.  */
1401190075Sobrien
1401290075Sobrienstatic void
14013169689Skanrs6000_frame_related (rtx insn, rtx reg, HOST_WIDE_INT val,
14014132718Skan		      rtx reg2, rtx rreg)
1401590075Sobrien{
1401690075Sobrien  rtx real, temp;
1401790075Sobrien
14018117395Skan  /* copy_rtx will not make unique copies of registers, so we need to
14019117395Skan     ensure we don't have unwanted sharing here.  */
14020117395Skan  if (reg == reg2)
14021117395Skan    reg = gen_raw_REG (GET_MODE (reg), REGNO (reg));
14022117395Skan
14023117395Skan  if (reg == rreg)
14024117395Skan    reg = gen_raw_REG (GET_MODE (reg), REGNO (reg));
14025117395Skan
1402690075Sobrien  real = copy_rtx (PATTERN (insn));
1402790075Sobrien
14028117395Skan  if (reg2 != NULL_RTX)
14029117395Skan    real = replace_rtx (real, reg2, rreg);
14030169689Skan
14031169689Skan  real = replace_rtx (real, reg,
1403290075Sobrien		      gen_rtx_PLUS (Pmode, gen_rtx_REG (Pmode,
1403390075Sobrien							STACK_POINTER_REGNUM),
1403490075Sobrien				    GEN_INT (val)));
14035169689Skan
1403690075Sobrien  /* We expect that 'real' is either a SET or a PARALLEL containing
1403790075Sobrien     SETs (and possibly other stuff).  In a PARALLEL, all the SETs
1403890075Sobrien     are important so they all have to be marked RTX_FRAME_RELATED_P.  */
1403990075Sobrien
1404090075Sobrien  if (GET_CODE (real) == SET)
1404190075Sobrien    {
1404290075Sobrien      rtx set = real;
14043169689Skan
1404490075Sobrien      temp = simplify_rtx (SET_SRC (set));
1404590075Sobrien      if (temp)
1404690075Sobrien	SET_SRC (set) = temp;
1404790075Sobrien      temp = simplify_rtx (SET_DEST (set));
1404890075Sobrien      if (temp)
1404990075Sobrien	SET_DEST (set) = temp;
1405090075Sobrien      if (GET_CODE (SET_DEST (set)) == MEM)
1405190075Sobrien	{
1405290075Sobrien	  temp = simplify_rtx (XEXP (SET_DEST (set), 0));
1405390075Sobrien	  if (temp)
1405490075Sobrien	    XEXP (SET_DEST (set), 0) = temp;
1405590075Sobrien	}
1405690075Sobrien    }
14057169689Skan  else
1405890075Sobrien    {
1405990075Sobrien      int i;
14060169689Skan
14061169689Skan      gcc_assert (GET_CODE (real) == PARALLEL);
1406290075Sobrien      for (i = 0; i < XVECLEN (real, 0); i++)
1406390075Sobrien	if (GET_CODE (XVECEXP (real, 0, i)) == SET)
1406490075Sobrien	  {
1406590075Sobrien	    rtx set = XVECEXP (real, 0, i);
14066169689Skan
1406790075Sobrien	    temp = simplify_rtx (SET_SRC (set));
1406890075Sobrien	    if (temp)
1406990075Sobrien	      SET_SRC (set) = temp;
1407090075Sobrien	    temp = simplify_rtx (SET_DEST (set));
1407190075Sobrien	    if (temp)
1407290075Sobrien	      SET_DEST (set) = temp;
1407390075Sobrien	    if (GET_CODE (SET_DEST (set)) == MEM)
1407490075Sobrien	      {
1407590075Sobrien		temp = simplify_rtx (XEXP (SET_DEST (set), 0));
1407690075Sobrien		if (temp)
1407790075Sobrien		  XEXP (SET_DEST (set), 0) = temp;
1407890075Sobrien	      }
1407990075Sobrien	    RTX_FRAME_RELATED_P (set) = 1;
1408090075Sobrien	  }
1408190075Sobrien    }
14082132718Skan
14083132718Skan  if (TARGET_SPE)
14084132718Skan    real = spe_synthesize_frame_save (real);
14085132718Skan
1408690075Sobrien  RTX_FRAME_RELATED_P (insn) = 1;
1408790075Sobrien  REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
1408890075Sobrien					real,
1408990075Sobrien					REG_NOTES (insn));
1409090075Sobrien}
1409190075Sobrien
14092132718Skan/* Given an SPE frame note, return a PARALLEL of SETs with the
14093132718Skan   original note, plus a synthetic register save.  */
14094132718Skan
14095132718Skanstatic rtx
14096132718Skanspe_synthesize_frame_save (rtx real)
14097132718Skan{
14098132718Skan  rtx synth, offset, reg, real2;
14099132718Skan
14100132718Skan  if (GET_CODE (real) != SET
14101132718Skan      || GET_MODE (SET_SRC (real)) != V2SImode)
14102132718Skan    return real;
14103132718Skan
14104132718Skan  /* For the SPE, registers saved in 64-bits, get a PARALLEL for their
14105132718Skan     frame related note.  The parallel contains a set of the register
14106132718Skan     being saved, and another set to a synthetic register (n+1200).
14107132718Skan     This is so we can differentiate between 64-bit and 32-bit saves.
14108132718Skan     Words cannot describe this nastiness.  */
14109132718Skan
14110169689Skan  gcc_assert (GET_CODE (SET_DEST (real)) == MEM
14111169689Skan	      && GET_CODE (XEXP (SET_DEST (real), 0)) == PLUS
14112169689Skan	      && GET_CODE (SET_SRC (real)) == REG);
14113132718Skan
14114132718Skan  /* Transform:
14115132718Skan       (set (mem (plus (reg x) (const y)))
14116132718Skan            (reg z))
14117132718Skan     into:
14118132718Skan       (set (mem (plus (reg x) (const y+4)))
14119132718Skan            (reg z+1200))
14120132718Skan  */
14121132718Skan
14122132718Skan  real2 = copy_rtx (real);
14123132718Skan  PUT_MODE (SET_DEST (real2), SImode);
14124132718Skan  reg = SET_SRC (real2);
14125132718Skan  real2 = replace_rtx (real2, reg, gen_rtx_REG (SImode, REGNO (reg)));
14126132718Skan  synth = copy_rtx (real2);
14127132718Skan
14128132718Skan  if (BYTES_BIG_ENDIAN)
14129132718Skan    {
14130132718Skan      offset = XEXP (XEXP (SET_DEST (real2), 0), 1);
14131132718Skan      real2 = replace_rtx (real2, offset, GEN_INT (INTVAL (offset) + 4));
14132132718Skan    }
14133132718Skan
14134132718Skan  reg = SET_SRC (synth);
14135132718Skan
14136132718Skan  synth = replace_rtx (synth, reg,
14137132718Skan		       gen_rtx_REG (SImode, REGNO (reg) + 1200));
14138132718Skan
14139132718Skan  offset = XEXP (XEXP (SET_DEST (synth), 0), 1);
14140132718Skan  synth = replace_rtx (synth, offset,
14141132718Skan		       GEN_INT (INTVAL (offset)
14142132718Skan				+ (BYTES_BIG_ENDIAN ? 0 : 4)));
14143132718Skan
14144132718Skan  RTX_FRAME_RELATED_P (synth) = 1;
14145132718Skan  RTX_FRAME_RELATED_P (real2) = 1;
14146132718Skan  if (BYTES_BIG_ENDIAN)
14147132718Skan    real = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, synth, real2));
14148132718Skan  else
14149132718Skan    real = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, real2, synth));
14150132718Skan
14151132718Skan  return real;
14152132718Skan}
14153132718Skan
1415490075Sobrien/* Returns an insn that has a vrsave set operation with the
1415590075Sobrien   appropriate CLOBBERs.  */
1415690075Sobrien
1415790075Sobrienstatic rtx
14158132718Skangenerate_set_vrsave (rtx reg, rs6000_stack_t *info, int epiloguep)
1415990075Sobrien{
1416090075Sobrien  int nclobs, i;
1416190075Sobrien  rtx insn, clobs[TOTAL_ALTIVEC_REGS + 1];
1416290075Sobrien  rtx vrsave = gen_rtx_REG (SImode, VRSAVE_REGNO);
1416390075Sobrien
1416490075Sobrien  clobs[0]
1416590075Sobrien    = gen_rtx_SET (VOIDmode,
1416690075Sobrien		   vrsave,
1416790075Sobrien		   gen_rtx_UNSPEC_VOLATILE (SImode,
1416890075Sobrien					    gen_rtvec (2, reg, vrsave),
14169169689Skan					    UNSPECV_SET_VRSAVE));
1417090075Sobrien
1417190075Sobrien  nclobs = 1;
1417290075Sobrien
1417390075Sobrien  /* We need to clobber the registers in the mask so the scheduler
1417490075Sobrien     does not move sets to VRSAVE before sets of AltiVec registers.
1417590075Sobrien
1417690075Sobrien     However, if the function receives nonlocal gotos, reload will set
1417790075Sobrien     all call saved registers live.  We will end up with:
1417890075Sobrien
1417990075Sobrien     	(set (reg 999) (mem))
1418090075Sobrien	(parallel [ (set (reg vrsave) (unspec blah))
1418190075Sobrien		    (clobber (reg 999))])
1418290075Sobrien
1418390075Sobrien     The clobber will cause the store into reg 999 to be dead, and
1418490075Sobrien     flow will attempt to delete an epilogue insn.  In this case, we
1418590075Sobrien     need an unspec use/set of the register.  */
1418690075Sobrien
1418790075Sobrien  for (i = FIRST_ALTIVEC_REGNO; i <= LAST_ALTIVEC_REGNO; ++i)
14188132718Skan    if (info->vrsave_mask & ALTIVEC_REG_BIT (i))
1418990075Sobrien      {
1419090075Sobrien	if (!epiloguep || call_used_regs [i])
1419190075Sobrien	  clobs[nclobs++] = gen_rtx_CLOBBER (VOIDmode,
1419290075Sobrien					     gen_rtx_REG (V4SImode, i));
1419390075Sobrien	else
1419490075Sobrien	  {
1419590075Sobrien	    rtx reg = gen_rtx_REG (V4SImode, i);
1419690075Sobrien
1419790075Sobrien	    clobs[nclobs++]
1419890075Sobrien	      = gen_rtx_SET (VOIDmode,
1419990075Sobrien			     reg,
1420090075Sobrien			     gen_rtx_UNSPEC (V4SImode,
1420190075Sobrien					     gen_rtvec (1, reg), 27));
1420290075Sobrien	  }
1420390075Sobrien      }
1420490075Sobrien
1420590075Sobrien  insn = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (nclobs));
1420690075Sobrien
1420790075Sobrien  for (i = 0; i < nclobs; ++i)
1420890075Sobrien    XVECEXP (insn, 0, i) = clobs[i];
1420990075Sobrien
1421090075Sobrien  return insn;
1421190075Sobrien}
1421290075Sobrien
14213117395Skan/* Save a register into the frame, and emit RTX_FRAME_RELATED_P notes.
14214117395Skan   Save REGNO into [FRAME_REG + OFFSET] in mode MODE.  */
14215117395Skan
14216117395Skanstatic void
14217169689Skanemit_frame_save (rtx frame_reg, rtx frame_ptr, enum machine_mode mode,
14218132718Skan		 unsigned int regno, int offset, HOST_WIDE_INT total_size)
14219117395Skan{
14220117395Skan  rtx reg, offset_rtx, insn, mem, addr, int_rtx;
14221117395Skan  rtx replacea, replaceb;
14222117395Skan
14223117395Skan  int_rtx = GEN_INT (offset);
14224117395Skan
14225117395Skan  /* Some cases that need register indexed addressing.  */
14226117395Skan  if ((TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
14227169689Skan      || (TARGET_E500_DOUBLE && mode == DFmode)
14228117395Skan      || (TARGET_SPE_ABI
14229117395Skan	  && SPE_VECTOR_MODE (mode)
14230117395Skan	  && !SPE_CONST_OFFSET_OK (offset)))
14231117395Skan    {
14232117395Skan      /* Whomever calls us must make sure r11 is available in the
14233169689Skan	 flow path of instructions in the prologue.  */
14234117395Skan      offset_rtx = gen_rtx_REG (Pmode, 11);
14235117395Skan      emit_move_insn (offset_rtx, int_rtx);
14236117395Skan
14237117395Skan      replacea = offset_rtx;
14238117395Skan      replaceb = int_rtx;
14239117395Skan    }
14240117395Skan  else
14241117395Skan    {
14242117395Skan      offset_rtx = int_rtx;
14243117395Skan      replacea = NULL_RTX;
14244117395Skan      replaceb = NULL_RTX;
14245117395Skan    }
14246117395Skan
14247117395Skan  reg = gen_rtx_REG (mode, regno);
14248117395Skan  addr = gen_rtx_PLUS (Pmode, frame_reg, offset_rtx);
14249169689Skan  mem = gen_frame_mem (mode, addr);
14250117395Skan
14251117395Skan  insn = emit_move_insn (mem, reg);
14252117395Skan
14253117395Skan  rs6000_frame_related (insn, frame_ptr, total_size, replacea, replaceb);
14254117395Skan}
14255117395Skan
14256117395Skan/* Emit an offset memory reference suitable for a frame store, while
14257117395Skan   converting to a valid addressing mode.  */
14258117395Skan
14259117395Skanstatic rtx
14260132718Skangen_frame_mem_offset (enum machine_mode mode, rtx reg, int offset)
14261117395Skan{
14262117395Skan  rtx int_rtx, offset_rtx;
14263117395Skan
14264117395Skan  int_rtx = GEN_INT (offset);
14265117395Skan
14266169689Skan  if ((TARGET_SPE_ABI && SPE_VECTOR_MODE (mode))
14267169689Skan      || (TARGET_E500_DOUBLE && mode == DFmode))
14268117395Skan    {
14269117395Skan      offset_rtx = gen_rtx_REG (Pmode, FIXED_SCRATCH);
14270117395Skan      emit_move_insn (offset_rtx, int_rtx);
14271117395Skan    }
14272117395Skan  else
14273117395Skan    offset_rtx = int_rtx;
14274117395Skan
14275169689Skan  return gen_frame_mem (mode, gen_rtx_PLUS (Pmode, reg, offset_rtx));
14276117395Skan}
14277117395Skan
14278169689Skan/* Look for user-defined global regs.  We should not save and restore these,
14279169689Skan   and cannot use stmw/lmw if there are any in its range.  */
14280169689Skan
14281169689Skanstatic bool
14282169689Skanno_global_regs_above (int first_greg)
14283169689Skan{
14284169689Skan  int i;
14285169689Skan  for (i = 0; i < 32 - first_greg; i++)
14286169689Skan    if (global_regs[first_greg + i])
14287169689Skan      return false;
14288169689Skan  return true;
14289169689Skan}
14290169689Skan
14291169689Skan#ifndef TARGET_FIX_AND_CONTINUE
14292169689Skan#define TARGET_FIX_AND_CONTINUE 0
14293169689Skan#endif
14294169689Skan
1429590075Sobrien/* Emit function prologue as insns.  */
1429690075Sobrien
1429790075Sobrienvoid
14298132718Skanrs6000_emit_prologue (void)
1429990075Sobrien{
1430090075Sobrien  rs6000_stack_t *info = rs6000_stack_info ();
14301132718Skan  enum machine_mode reg_mode = Pmode;
14302132718Skan  int reg_size = TARGET_32BIT ? 4 : 8;
1430390075Sobrien  rtx sp_reg_rtx = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
1430490075Sobrien  rtx frame_ptr_rtx = gen_rtx_REG (Pmode, 12);
1430590075Sobrien  rtx frame_reg_rtx = sp_reg_rtx;
14306132718Skan  rtx cr_save_rtx = NULL_RTX;
1430790075Sobrien  rtx insn;
1430890075Sobrien  int saving_FPRs_inline;
1430990075Sobrien  int using_store_multiple;
1431090075Sobrien  HOST_WIDE_INT sp_offset = 0;
14311117395Skan
14312169689Skan  if (TARGET_FIX_AND_CONTINUE)
14313169689Skan    {
14314169689Skan      /* gdb on darwin arranges to forward a function from the old
14315169689Skan	 address by modifying the first 5 instructions of the function
14316169689Skan	 to branch to the overriding function.  This is necessary to
14317169689Skan	 permit function pointers that point to the old function to
14318169689Skan	 actually forward to the new function.  */
14319169689Skan      emit_insn (gen_nop ());
14320169689Skan      emit_insn (gen_nop ());
14321169689Skan      emit_insn (gen_nop ());
14322169689Skan      emit_insn (gen_nop ());
14323169689Skan      emit_insn (gen_nop ());
14324169689Skan    }
14325169689Skan
14326169689Skan  if (TARGET_SPE_ABI && info->spe_64bit_regs_used != 0)
14327169689Skan    {
14328169689Skan      reg_mode = V2SImode;
14329169689Skan      reg_size = 8;
14330169689Skan    }
14331169689Skan
1433290075Sobrien  using_store_multiple = (TARGET_MULTIPLE && ! TARGET_POWERPC64
14333132718Skan			  && (!TARGET_SPE_ABI
14334132718Skan			      || info->spe_64bit_regs_used == 0)
14335169689Skan			  && info->first_gp_reg_save < 31
14336169689Skan			  && no_global_regs_above (info->first_gp_reg_save));
1433790075Sobrien  saving_FPRs_inline = (info->first_fp_reg_save == 64
14338132718Skan			|| FP_SAVE_INLINE (info->first_fp_reg_save)
14339132718Skan			|| current_function_calls_eh_return
14340132718Skan			|| cfun->machine->ra_need_lr);
1434190075Sobrien
1434290075Sobrien  /* For V.4, update stack before we do any saving and set back pointer.  */
14343169689Skan  if (! WORLD_SAVE_P (info)
14344169689Skan      && info->push_p
14345132718Skan      && (DEFAULT_ABI == ABI_V4
14346132718Skan	  || current_function_calls_eh_return))
1434790075Sobrien    {
1434890075Sobrien      if (info->total_size < 32767)
1434990075Sobrien	sp_offset = info->total_size;
1435090075Sobrien      else
1435190075Sobrien	frame_reg_rtx = frame_ptr_rtx;
14352169689Skan      rs6000_emit_allocate_stack (info->total_size,
1435390075Sobrien				  (frame_reg_rtx != sp_reg_rtx
1435490075Sobrien				   && (info->cr_save_p
1435590075Sobrien				       || info->lr_save_p
1435690075Sobrien				       || info->first_fp_reg_save < 64
1435790075Sobrien				       || info->first_gp_reg_save < 32
1435890075Sobrien				       )));
1435990075Sobrien      if (frame_reg_rtx != sp_reg_rtx)
1436090075Sobrien	rs6000_emit_stack_tie ();
1436190075Sobrien    }
1436290075Sobrien
14363169689Skan  /* Handle world saves specially here.  */
14364169689Skan  if (WORLD_SAVE_P (info))
14365169689Skan    {
14366169689Skan      int i, j, sz;
14367169689Skan      rtx treg;
14368169689Skan      rtvec p;
14369169689Skan      rtx reg0;
14370169689Skan
14371169689Skan      /* save_world expects lr in r0. */
14372169689Skan      reg0 = gen_rtx_REG (Pmode, 0);
14373169689Skan      if (info->lr_save_p)
14374169689Skan	{
14375169689Skan	  insn = emit_move_insn (reg0,
14376169689Skan				 gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM));
14377169689Skan	  RTX_FRAME_RELATED_P (insn) = 1;
14378169689Skan	}
14379169689Skan
14380169689Skan      /* The SAVE_WORLD and RESTORE_WORLD routines make a number of
14381169689Skan	 assumptions about the offsets of various bits of the stack
14382169689Skan	 frame.  */
14383169689Skan      gcc_assert (info->gp_save_offset == -220
14384169689Skan		  && info->fp_save_offset == -144
14385169689Skan		  && info->lr_save_offset == 8
14386169689Skan		  && info->cr_save_offset == 4
14387169689Skan		  && info->push_p
14388169689Skan		  && info->lr_save_p
14389169689Skan		  && (!current_function_calls_eh_return
14390169689Skan		       || info->ehrd_offset == -432)
14391169689Skan		  && info->vrsave_save_offset == -224
14392169689Skan		  && info->altivec_save_offset == -416);
14393169689Skan
14394169689Skan      treg = gen_rtx_REG (SImode, 11);
14395169689Skan      emit_move_insn (treg, GEN_INT (-info->total_size));
14396169689Skan
14397169689Skan      /* SAVE_WORLD takes the caller's LR in R0 and the frame size
14398169689Skan	 in R11.  It also clobbers R12, so beware!  */
14399169689Skan
14400169689Skan      /* Preserve CR2 for save_world prologues */
14401169689Skan      sz = 5;
14402169689Skan      sz += 32 - info->first_gp_reg_save;
14403169689Skan      sz += 64 - info->first_fp_reg_save;
14404169689Skan      sz += LAST_ALTIVEC_REGNO - info->first_altivec_reg_save + 1;
14405169689Skan      p = rtvec_alloc (sz);
14406169689Skan      j = 0;
14407169689Skan      RTVEC_ELT (p, j++) = gen_rtx_CLOBBER (VOIDmode,
14408169689Skan					    gen_rtx_REG (Pmode,
14409169689Skan							 LINK_REGISTER_REGNUM));
14410169689Skan      RTVEC_ELT (p, j++) = gen_rtx_USE (VOIDmode,
14411169689Skan					gen_rtx_SYMBOL_REF (Pmode,
14412169689Skan							    "*save_world"));
14413169689Skan      /* We do floats first so that the instruction pattern matches
14414169689Skan	 properly.  */
14415169689Skan      for (i = 0; i < 64 - info->first_fp_reg_save; i++)
14416169689Skan	{
14417169689Skan	  rtx reg = gen_rtx_REG (DFmode, info->first_fp_reg_save + i);
14418169689Skan	  rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
14419169689Skan				   GEN_INT (info->fp_save_offset
14420169689Skan					    + sp_offset + 8 * i));
14421169689Skan	  rtx mem = gen_frame_mem (DFmode, addr);
14422169689Skan
14423169689Skan	  RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg);
14424169689Skan	}
14425169689Skan      for (i = 0; info->first_altivec_reg_save + i <= LAST_ALTIVEC_REGNO; i++)
14426169689Skan	{
14427169689Skan	  rtx reg = gen_rtx_REG (V4SImode, info->first_altivec_reg_save + i);
14428169689Skan	  rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
14429169689Skan				   GEN_INT (info->altivec_save_offset
14430169689Skan					    + sp_offset + 16 * i));
14431169689Skan	  rtx mem = gen_frame_mem (V4SImode, addr);
14432169689Skan
14433169689Skan	  RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg);
14434169689Skan	}
14435169689Skan      for (i = 0; i < 32 - info->first_gp_reg_save; i++)
14436169689Skan	{
14437169689Skan	  rtx reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
14438169689Skan	  rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
14439169689Skan				   GEN_INT (info->gp_save_offset
14440169689Skan					    + sp_offset + reg_size * i));
14441169689Skan	  rtx mem = gen_frame_mem (reg_mode, addr);
14442169689Skan
14443169689Skan	  RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg);
14444169689Skan	}
14445169689Skan
14446169689Skan      {
14447169689Skan	/* CR register traditionally saved as CR2.  */
14448169689Skan	rtx reg = gen_rtx_REG (reg_mode, CR2_REGNO);
14449169689Skan	rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
14450169689Skan				 GEN_INT (info->cr_save_offset
14451169689Skan					  + sp_offset));
14452169689Skan	rtx mem = gen_frame_mem (reg_mode, addr);
14453169689Skan
14454169689Skan	RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg);
14455169689Skan      }
14456169689Skan      /* Explain about use of R0.  */
14457169689Skan      if (info->lr_save_p)
14458169689Skan	{
14459169689Skan	  rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
14460169689Skan				   GEN_INT (info->lr_save_offset
14461169689Skan					    + sp_offset));
14462169689Skan	  rtx mem = gen_frame_mem (reg_mode, addr);
14463169689Skan
14464169689Skan	  RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg0);
14465169689Skan	}
14466169689Skan      /* Explain what happens to the stack pointer.  */
14467169689Skan      {
14468169689Skan	rtx newval = gen_rtx_PLUS (Pmode, sp_reg_rtx, treg);
14469169689Skan	RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, sp_reg_rtx, newval);
14470169689Skan      }
14471169689Skan
14472169689Skan      insn = emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
14473169689Skan      rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
14474169689Skan			    treg, GEN_INT (-info->total_size));
14475169689Skan      sp_offset = info->total_size;
14476169689Skan    }
14477169689Skan
1447890075Sobrien  /* If we use the link register, get it into r0.  */
14479169689Skan  if (!WORLD_SAVE_P (info) && info->lr_save_p)
14480169689Skan    {
14481169689Skan      insn = emit_move_insn (gen_rtx_REG (Pmode, 0),
14482169689Skan			     gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM));
14483169689Skan      RTX_FRAME_RELATED_P (insn) = 1;
14484169689Skan    }
1448590075Sobrien
1448690075Sobrien  /* If we need to save CR, put it into r12.  */
14487169689Skan  if (!WORLD_SAVE_P (info) && info->cr_save_p && frame_reg_rtx != frame_ptr_rtx)
1448890075Sobrien    {
14489169689Skan      rtx set;
14490169689Skan
1449190075Sobrien      cr_save_rtx = gen_rtx_REG (SImode, 12);
14492169689Skan      insn = emit_insn (gen_movesi_from_cr (cr_save_rtx));
14493169689Skan      RTX_FRAME_RELATED_P (insn) = 1;
14494169689Skan      /* Now, there's no way that dwarf2out_frame_debug_expr is going
14495169689Skan	 to understand '(unspec:SI [(reg:CC 68) ...] UNSPEC_MOVESI_FROM_CR)'.
14496169689Skan	 But that's OK.  All we have to do is specify that _one_ condition
14497169689Skan	 code register is saved in this stack slot.  The thrower's epilogue
14498169689Skan	 will then restore all the call-saved registers.
14499169689Skan	 We use CR2_REGNO (70) to be compatible with gcc-2.95 on Linux.  */
14500169689Skan      set = gen_rtx_SET (VOIDmode, cr_save_rtx,
14501169689Skan			 gen_rtx_REG (SImode, CR2_REGNO));
14502169689Skan      REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
14503169689Skan					    set,
14504169689Skan					    REG_NOTES (insn));
1450590075Sobrien    }
1450690075Sobrien
1450790075Sobrien  /* Do any required saving of fpr's.  If only one or two to save, do
1450890075Sobrien     it ourselves.  Otherwise, call function.  */
14509169689Skan  if (!WORLD_SAVE_P (info) && saving_FPRs_inline)
1451090075Sobrien    {
1451190075Sobrien      int i;
1451290075Sobrien      for (i = 0; i < 64 - info->first_fp_reg_save; i++)
14513169689Skan	if ((regs_ever_live[info->first_fp_reg_save+i]
1451490075Sobrien	     && ! call_used_regs[info->first_fp_reg_save+i]))
14515117395Skan	  emit_frame_save (frame_reg_rtx, frame_ptr_rtx, DFmode,
14516117395Skan			   info->first_fp_reg_save + i,
14517117395Skan			   info->fp_save_offset + sp_offset + 8 * i,
14518117395Skan			   info->total_size);
1451990075Sobrien    }
14520169689Skan  else if (!WORLD_SAVE_P (info) && info->first_fp_reg_save != 64)
1452190075Sobrien    {
1452290075Sobrien      int i;
1452390075Sobrien      char rname[30];
1452490075Sobrien      const char *alloc_rname;
1452590075Sobrien      rtvec p;
1452690075Sobrien      p = rtvec_alloc (2 + 64 - info->first_fp_reg_save);
14527169689Skan
14528169689Skan      RTVEC_ELT (p, 0) = gen_rtx_CLOBBER (VOIDmode,
14529169689Skan					  gen_rtx_REG (Pmode,
1453090075Sobrien						       LINK_REGISTER_REGNUM));
1453190075Sobrien      sprintf (rname, "%s%d%s", SAVE_FP_PREFIX,
1453290075Sobrien	       info->first_fp_reg_save - 32, SAVE_FP_SUFFIX);
1453390075Sobrien      alloc_rname = ggc_strdup (rname);
1453490075Sobrien      RTVEC_ELT (p, 1) = gen_rtx_USE (VOIDmode,
1453590075Sobrien				      gen_rtx_SYMBOL_REF (Pmode,
1453690075Sobrien							  alloc_rname));
1453790075Sobrien      for (i = 0; i < 64 - info->first_fp_reg_save; i++)
1453890075Sobrien	{
1453990075Sobrien	  rtx addr, reg, mem;
1454090075Sobrien	  reg = gen_rtx_REG (DFmode, info->first_fp_reg_save + i);
1454190075Sobrien	  addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
14542169689Skan			       GEN_INT (info->fp_save_offset
1454390075Sobrien					+ sp_offset + 8*i));
14544169689Skan	  mem = gen_frame_mem (DFmode, addr);
1454590075Sobrien
1454690075Sobrien	  RTVEC_ELT (p, i + 2) = gen_rtx_SET (VOIDmode, mem, reg);
1454790075Sobrien	}
1454890075Sobrien      insn = emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
14549169689Skan      rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
1455090075Sobrien			    NULL_RTX, NULL_RTX);
1455190075Sobrien    }
1455290075Sobrien
1455390075Sobrien  /* Save GPRs.  This is done as a PARALLEL if we are using
1455490075Sobrien     the store-multiple instructions.  */
14555169689Skan  if (!WORLD_SAVE_P (info) && using_store_multiple)
1455690075Sobrien    {
14557117395Skan      rtvec p;
1455890075Sobrien      int i;
1455990075Sobrien      p = rtvec_alloc (32 - info->first_gp_reg_save);
1456090075Sobrien      for (i = 0; i < 32 - info->first_gp_reg_save; i++)
1456190075Sobrien	{
1456290075Sobrien	  rtx addr, reg, mem;
1456390075Sobrien	  reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
14564169689Skan	  addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
14565169689Skan			       GEN_INT (info->gp_save_offset
14566169689Skan					+ sp_offset
1456790075Sobrien					+ reg_size * i));
14568169689Skan	  mem = gen_frame_mem (reg_mode, addr);
1456990075Sobrien
1457090075Sobrien	  RTVEC_ELT (p, i) = gen_rtx_SET (VOIDmode, mem, reg);
1457190075Sobrien	}
1457290075Sobrien      insn = emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
14573169689Skan      rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
1457490075Sobrien			    NULL_RTX, NULL_RTX);
1457590075Sobrien    }
14576169689Skan  else if (!WORLD_SAVE_P (info))
1457790075Sobrien    {
1457890075Sobrien      int i;
1457990075Sobrien      for (i = 0; i < 32 - info->first_gp_reg_save; i++)
14580169689Skan	if ((regs_ever_live[info->first_gp_reg_save + i]
14581169689Skan	     && (!call_used_regs[info->first_gp_reg_save + i]
14582169689Skan		 || (i + info->first_gp_reg_save
14583146895Skan		     == RS6000_PIC_OFFSET_TABLE_REGNUM
14584146895Skan		     && TARGET_TOC && TARGET_MINIMAL_TOC)))
14585169689Skan	    || (i + info->first_gp_reg_save == RS6000_PIC_OFFSET_TABLE_REGNUM
14586117395Skan		&& ((DEFAULT_ABI == ABI_V4 && flag_pic != 0)
1458790075Sobrien		    || (DEFAULT_ABI == ABI_DARWIN && flag_pic))))
1458890075Sobrien	  {
1458990075Sobrien	    rtx addr, reg, mem;
1459090075Sobrien	    reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
1459190075Sobrien
14592132718Skan	    if (TARGET_SPE_ABI && info->spe_64bit_regs_used != 0)
14593117395Skan	      {
14594117395Skan		int offset = info->spe_gp_save_offset + sp_offset + 8 * i;
14595117395Skan		rtx b;
14596117395Skan
14597117395Skan		if (!SPE_CONST_OFFSET_OK (offset))
14598117395Skan		  {
14599117395Skan		    b = gen_rtx_REG (Pmode, FIXED_SCRATCH);
14600117395Skan		    emit_move_insn (b, GEN_INT (offset));
14601117395Skan		  }
14602117395Skan		else
14603117395Skan		  b = GEN_INT (offset);
14604117395Skan
14605117395Skan		addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, b);
14606169689Skan		mem = gen_frame_mem (V2SImode, addr);
14607117395Skan		insn = emit_move_insn (mem, reg);
14608117395Skan
14609117395Skan		if (GET_CODE (b) == CONST_INT)
14610117395Skan		  rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
14611117395Skan					NULL_RTX, NULL_RTX);
14612117395Skan		else
14613117395Skan		  rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
14614117395Skan					b, GEN_INT (offset));
14615117395Skan	      }
14616117395Skan	    else
14617117395Skan	      {
14618169689Skan		addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
14619169689Skan				     GEN_INT (info->gp_save_offset
14620169689Skan					      + sp_offset
14621117395Skan					      + reg_size * i));
14622169689Skan		mem = gen_frame_mem (reg_mode, addr);
14623117395Skan
14624117395Skan		insn = emit_move_insn (mem, reg);
14625169689Skan		rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
14626117395Skan				      NULL_RTX, NULL_RTX);
14627117395Skan	      }
1462890075Sobrien	  }
1462990075Sobrien    }
1463090075Sobrien
1463190075Sobrien  /* ??? There's no need to emit actual instructions here, but it's the
1463290075Sobrien     easiest way to get the frame unwind information emitted.  */
1463390075Sobrien  if (current_function_calls_eh_return)
1463490075Sobrien    {
1463590075Sobrien      unsigned int i, regno;
1463690075Sobrien
14637132718Skan      /* In AIX ABI we need to pretend we save r2 here.  */
14638132718Skan      if (TARGET_AIX)
14639132718Skan	{
14640132718Skan	  rtx addr, reg, mem;
14641132718Skan
14642132718Skan	  reg = gen_rtx_REG (reg_mode, 2);
14643132718Skan	  addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
14644132718Skan			       GEN_INT (sp_offset + 5 * reg_size));
14645169689Skan	  mem = gen_frame_mem (reg_mode, addr);
14646132718Skan
14647132718Skan	  insn = emit_move_insn (mem, reg);
14648169689Skan	  rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
14649132718Skan				NULL_RTX, NULL_RTX);
14650132718Skan	  PATTERN (insn) = gen_blockage ();
14651132718Skan	}
14652132718Skan
1465390075Sobrien      for (i = 0; ; ++i)
1465490075Sobrien	{
1465590075Sobrien	  regno = EH_RETURN_DATA_REGNO (i);
1465690075Sobrien	  if (regno == INVALID_REGNUM)
1465790075Sobrien	    break;
1465890075Sobrien
14659117395Skan	  emit_frame_save (frame_reg_rtx, frame_ptr_rtx, reg_mode, regno,
14660117395Skan			   info->ehrd_offset + sp_offset
14661117395Skan			   + reg_size * (int) i,
14662117395Skan			   info->total_size);
1466390075Sobrien	}
1466490075Sobrien    }
1466590075Sobrien
1466690075Sobrien  /* Save lr if we used it.  */
14667169689Skan  if (!WORLD_SAVE_P (info) && info->lr_save_p)
1466890075Sobrien    {
1466990075Sobrien      rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
1467090075Sobrien			       GEN_INT (info->lr_save_offset + sp_offset));
1467190075Sobrien      rtx reg = gen_rtx_REG (Pmode, 0);
1467290075Sobrien      rtx mem = gen_rtx_MEM (Pmode, addr);
14673169689Skan      /* This should not be of frame_alias_set, because of
1467490075Sobrien	 __builtin_return_address.  */
14675169689Skan
1467690075Sobrien      insn = emit_move_insn (mem, reg);
14677169689Skan      rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
14678169689Skan			    NULL_RTX, NULL_RTX);
1467990075Sobrien    }
1468090075Sobrien
1468190075Sobrien  /* Save CR if we use any that must be preserved.  */
14682169689Skan  if (!WORLD_SAVE_P (info) && info->cr_save_p)
1468390075Sobrien    {
1468490075Sobrien      rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
1468590075Sobrien			       GEN_INT (info->cr_save_offset + sp_offset));
14686169689Skan      rtx mem = gen_frame_mem (SImode, addr);
14687169689Skan      /* See the large comment above about why CR2_REGNO is used.  */
14688169689Skan      rtx magic_eh_cr_reg = gen_rtx_REG (SImode, CR2_REGNO);
1468990075Sobrien
1469090075Sobrien      /* If r12 was used to hold the original sp, copy cr into r0 now
1469190075Sobrien	 that it's free.  */
1469290075Sobrien      if (REGNO (frame_reg_rtx) == 12)
1469390075Sobrien	{
14694169689Skan	  rtx set;
14695169689Skan
1469690075Sobrien	  cr_save_rtx = gen_rtx_REG (SImode, 0);
14697169689Skan	  insn = emit_insn (gen_movesi_from_cr (cr_save_rtx));
14698169689Skan	  RTX_FRAME_RELATED_P (insn) = 1;
14699169689Skan	  set = gen_rtx_SET (VOIDmode, cr_save_rtx, magic_eh_cr_reg);
14700169689Skan	  REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
14701169689Skan						set,
14702169689Skan						REG_NOTES (insn));
14703169689Skan
1470490075Sobrien	}
1470590075Sobrien      insn = emit_move_insn (mem, cr_save_rtx);
1470690075Sobrien
14707169689Skan      rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
14708169689Skan			    NULL_RTX, NULL_RTX);
1470990075Sobrien    }
1471090075Sobrien
14711169689Skan  /* Update stack and set back pointer unless this is V.4,
1471290075Sobrien     for which it was done previously.  */
14713169689Skan  if (!WORLD_SAVE_P (info) && info->push_p
14714132718Skan      && !(DEFAULT_ABI == ABI_V4 || current_function_calls_eh_return))
14715259583Spfg    {
14716259583Spfg      if (info->total_size < 32767)
14717259583Spfg      sp_offset = info->total_size;
14718259583Spfg      else
14719259583Spfg	frame_reg_rtx = frame_ptr_rtx;
14720259583Spfg      rs6000_emit_allocate_stack (info->total_size,
14721259583Spfg				  (frame_reg_rtx != sp_reg_rtx
14722259583Spfg				   && ((info->altivec_size != 0)
14723259583Spfg				       || (info->vrsave_mask != 0)
14724259583Spfg				       )));
14725259583Spfg      if (frame_reg_rtx != sp_reg_rtx)
14726259583Spfg	rs6000_emit_stack_tie ();
14727259583Spfg    }
1472890075Sobrien
1472990075Sobrien  /* Set frame pointer, if needed.  */
1473090075Sobrien  if (frame_pointer_needed)
1473190075Sobrien    {
14732169689Skan      insn = emit_move_insn (gen_rtx_REG (Pmode, HARD_FRAME_POINTER_REGNUM),
1473390075Sobrien			     sp_reg_rtx);
1473490075Sobrien      RTX_FRAME_RELATED_P (insn) = 1;
1473590075Sobrien    }
1473690075Sobrien
14737259583Spfg  /* Save AltiVec registers if needed.  Save here because the red zone does
14738259583Spfg     not include AltiVec registers.  */
14739259583Spfg  if (!WORLD_SAVE_P (info) && TARGET_ALTIVEC_ABI && info->altivec_size != 0)
14740259583Spfg    {
14741259583Spfg      int i;
14742259583Spfg
14743259583Spfg      /* There should be a non inline version of this, for when we
14744259583Spfg         are saving lots of vector registers.  */
14745259583Spfg      for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i)
14746259583Spfg        if (info->vrsave_mask & ALTIVEC_REG_BIT (i))
14747259583Spfg          {
14748259583Spfg            rtx areg, savereg, mem;
14749259583Spfg            int offset;
14750259583Spfg
14751259583Spfg            offset = info->altivec_save_offset + sp_offset
14752259583Spfg              + 16 * (i - info->first_altivec_reg_save);
14753259583Spfg
14754259583Spfg            savereg = gen_rtx_REG (V4SImode, i);
14755259583Spfg
14756259583Spfg            areg = gen_rtx_REG (Pmode, 0);
14757259583Spfg            emit_move_insn (areg, GEN_INT (offset));
14758259583Spfg
14759259583Spfg            /* AltiVec addressing mode is [reg+reg].  */
14760259583Spfg            mem = gen_frame_mem (V4SImode,
14761259583Spfg                                 gen_rtx_PLUS (Pmode, frame_reg_rtx, areg));
14762259583Spfg
14763259583Spfg            insn = emit_move_insn (mem, savereg);
14764259583Spfg
14765259583Spfg            rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
14766259583Spfg                                  areg, GEN_INT (offset));
14767259583Spfg          }
14768259583Spfg    }
14769259583Spfg
14770259583Spfg  /* VRSAVE is a bit vector representing which AltiVec registers
14771259583Spfg     are used.  The OS uses this to determine which vector
14772259583Spfg     registers to save on a context switch.  We need to save
14773259583Spfg     VRSAVE on the stack frame, add whatever AltiVec registers we
14774259583Spfg     used in this function, and do the corresponding magic in the
14775259583Spfg     epilogue.  */
14776259583Spfg
14777259583Spfg  if (TARGET_ALTIVEC && TARGET_ALTIVEC_VRSAVE
14778259583Spfg      && info->vrsave_mask != 0)
14779259583Spfg    {
14780259583Spfg      rtx reg, mem, vrsave;
14781259583Spfg      int offset;
14782259583Spfg
14783259583Spfg      /* Get VRSAVE onto a GPR.  Note that ABI_V4 might be using r12
14784259583Spfg         as frame_reg_rtx and r11 as the static chain pointer for
14785259583Spfg         nested functions.  */
14786259583Spfg      reg = gen_rtx_REG (SImode, 0);
14787259583Spfg      vrsave = gen_rtx_REG (SImode, VRSAVE_REGNO);
14788259583Spfg      if (TARGET_MACHO)
14789259583Spfg        emit_insn (gen_get_vrsave_internal (reg));
14790259583Spfg      else
14791259583Spfg        emit_insn (gen_rtx_SET (VOIDmode, reg, vrsave));
14792259583Spfg
14793259583Spfg      if (!WORLD_SAVE_P (info))
14794259583Spfg        {
14795259583Spfg          /* Save VRSAVE.  */
14796259583Spfg          offset = info->vrsave_save_offset + sp_offset;
14797259583Spfg          mem = gen_frame_mem (SImode,
14798259583Spfg                               gen_rtx_PLUS (Pmode, frame_reg_rtx,
14799259583Spfg                                             GEN_INT (offset)));
14800259583Spfg          insn = emit_move_insn (mem, reg);
14801259583Spfg        }
14802259583Spfg
14803259583Spfg      /* Include the registers in the mask.  */
14804259583Spfg      emit_insn (gen_iorsi3 (reg, reg, GEN_INT ((int) info->vrsave_mask)));
14805259583Spfg
14806259583Spfg      insn = emit_insn (generate_set_vrsave (reg, info, 0));
14807259583Spfg    }
14808259583Spfg
1480996263Sobrien  /* If we are using RS6000_PIC_OFFSET_TABLE_REGNUM, we need to set it up.  */
1481090075Sobrien  if ((TARGET_TOC && TARGET_MINIMAL_TOC && get_pool_size () != 0)
14811169689Skan      || (DEFAULT_ABI == ABI_V4
14812169689Skan	  && (flag_pic == 1 || (flag_pic && TARGET_SECURE_PLT))
1481396263Sobrien	  && regs_ever_live[RS6000_PIC_OFFSET_TABLE_REGNUM]))
14814169689Skan    {
14815169689Skan      /* If emit_load_toc_table will use the link register, we need to save
14816169689Skan	 it.  We use R12 for this purpose because emit_load_toc_table
14817169689Skan	 can use register 0.  This allows us to use a plain 'blr' to return
14818169689Skan	 from the procedure more often.  */
14819169689Skan      int save_LR_around_toc_setup = (TARGET_ELF
14820169689Skan				      && DEFAULT_ABI != ABI_AIX
14821169689Skan				      && flag_pic
14822169689Skan				      && ! info->lr_save_p
14823169689Skan				      && EDGE_COUNT (EXIT_BLOCK_PTR->preds) > 0);
14824169689Skan      if (save_LR_around_toc_setup)
14825169689Skan	{
14826169689Skan	  rtx lr = gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM);
14827169689Skan
14828169689Skan	  insn = emit_move_insn (frame_ptr_rtx, lr);
14829169689Skan	  rs6000_maybe_dead (insn);
14830169689Skan	  RTX_FRAME_RELATED_P (insn) = 1;
14831169689Skan
14832169689Skan	  rs6000_emit_load_toc_table (TRUE);
14833169689Skan
14834169689Skan	  insn = emit_move_insn (lr, frame_ptr_rtx);
14835169689Skan	  rs6000_maybe_dead (insn);
14836169689Skan	  RTX_FRAME_RELATED_P (insn) = 1;
14837169689Skan	}
14838169689Skan      else
14839132718Skan	rs6000_emit_load_toc_table (TRUE);
14840169689Skan    }
1484190075Sobrien
14842117395Skan#if TARGET_MACHO
1484390075Sobrien  if (DEFAULT_ABI == ABI_DARWIN
1484490075Sobrien      && flag_pic && current_function_uses_pic_offset_table)
1484590075Sobrien    {
14846169689Skan      rtx lr = gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM);
14847169689Skan      rtx src = machopic_function_base_sym ();
1484890075Sobrien
14849169689Skan      /* Save and restore LR locally around this call (in R0).  */
14850169689Skan      if (!info->lr_save_p)
14851169689Skan	rs6000_maybe_dead (emit_move_insn (gen_rtx_REG (Pmode, 0), lr));
1485290075Sobrien
14853169689Skan      rs6000_maybe_dead (emit_insn (gen_load_macho_picbase (lr, src)));
14854169689Skan
14855169689Skan      insn = emit_move_insn (gen_rtx_REG (Pmode,
14856169689Skan					  RS6000_PIC_OFFSET_TABLE_REGNUM),
14857169689Skan			     lr);
14858169689Skan      rs6000_maybe_dead (insn);
14859169689Skan
14860169689Skan      if (!info->lr_save_p)
14861169689Skan	rs6000_maybe_dead (emit_move_insn (lr, gen_rtx_REG (Pmode, 0)));
1486290075Sobrien    }
14863117395Skan#endif
1486490075Sobrien}
1486590075Sobrien
1486690075Sobrien/* Write function prologue.  */
1486790075Sobrien
1486890075Sobrienstatic void
14869169689Skanrs6000_output_function_prologue (FILE *file,
14870132718Skan				 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
1487190075Sobrien{
1487290075Sobrien  rs6000_stack_t *info = rs6000_stack_info ();
1487390075Sobrien
1487490075Sobrien  if (TARGET_DEBUG_STACK)
1487590075Sobrien    debug_stack_info (info);
1487690075Sobrien
1487790075Sobrien  /* Write .extern for any function we will call to save and restore
1487890075Sobrien     fp values.  */
1487990075Sobrien  if (info->first_fp_reg_save < 64
1488090075Sobrien      && !FP_SAVE_INLINE (info->first_fp_reg_save))
1488190075Sobrien    fprintf (file, "\t.extern %s%d%s\n\t.extern %s%d%s\n",
1488290075Sobrien	     SAVE_FP_PREFIX, info->first_fp_reg_save - 32, SAVE_FP_SUFFIX,
1488390075Sobrien	     RESTORE_FP_PREFIX, info->first_fp_reg_save - 32,
1488490075Sobrien	     RESTORE_FP_SUFFIX);
1488590075Sobrien
1488690075Sobrien  /* Write .extern for AIX common mode routines, if needed.  */
1488790075Sobrien  if (! TARGET_POWER && ! TARGET_POWERPC && ! common_mode_defined)
1488890075Sobrien    {
1488990075Sobrien      fputs ("\t.extern __mulh\n", file);
1489090075Sobrien      fputs ("\t.extern __mull\n", file);
1489190075Sobrien      fputs ("\t.extern __divss\n", file);
1489290075Sobrien      fputs ("\t.extern __divus\n", file);
1489390075Sobrien      fputs ("\t.extern __quoss\n", file);
1489490075Sobrien      fputs ("\t.extern __quous\n", file);
1489590075Sobrien      common_mode_defined = 1;
1489690075Sobrien    }
1489790075Sobrien
1489890075Sobrien  if (! HAVE_prologue)
1489990075Sobrien    {
1490090075Sobrien      start_sequence ();
1490196263Sobrien
1490290075Sobrien      /* A NOTE_INSN_DELETED is supposed to be at the start and end of
1490390075Sobrien	 the "toplevel" insn chain.  */
14904132718Skan      emit_note (NOTE_INSN_DELETED);
1490590075Sobrien      rs6000_emit_prologue ();
14906132718Skan      emit_note (NOTE_INSN_DELETED);
1490796263Sobrien
14908132718Skan      /* Expand INSN_ADDRESSES so final() doesn't crash.  */
1490996263Sobrien      {
1491096263Sobrien	rtx insn;
1491196263Sobrien	unsigned addr = 0;
1491296263Sobrien	for (insn = get_insns (); insn != 0; insn = NEXT_INSN (insn))
1491396263Sobrien	  {
1491496263Sobrien	    INSN_ADDRESSES_NEW (insn, addr);
1491596263Sobrien	    addr += 4;
1491696263Sobrien	  }
1491796263Sobrien      }
1491896263Sobrien
1491990075Sobrien      if (TARGET_DEBUG_STACK)
1492090075Sobrien	debug_rtx_list (get_insns (), 100);
14921169689Skan      final (get_insns (), file, FALSE);
1492290075Sobrien      end_sequence ();
1492390075Sobrien    }
1492490075Sobrien
1492590075Sobrien  rs6000_pic_labelno++;
1492690075Sobrien}
14927169689Skan
1492890075Sobrien/* Emit function epilogue as insns.
1492990075Sobrien
1493090075Sobrien   At present, dwarf2out_frame_debug_expr doesn't understand
1493190075Sobrien   register restores, so we don't bother setting RTX_FRAME_RELATED_P
1493290075Sobrien   anywhere in the epilogue.  Most of the insns below would in any case
1493390075Sobrien   need special notes to explain where r11 is in relation to the stack.  */
1493490075Sobrien
1493590075Sobrienvoid
14936132718Skanrs6000_emit_epilogue (int sibcall)
1493790075Sobrien{
1493890075Sobrien  rs6000_stack_t *info;
1493990075Sobrien  int restoring_FPRs_inline;
1494090075Sobrien  int using_load_multiple;
1494190075Sobrien  int using_mfcr_multiple;
1494290075Sobrien  int use_backchain_to_restore_sp;
1494390075Sobrien  int sp_offset = 0;
1494490075Sobrien  rtx sp_reg_rtx = gen_rtx_REG (Pmode, 1);
1494590075Sobrien  rtx frame_reg_rtx = sp_reg_rtx;
14946132718Skan  enum machine_mode reg_mode = Pmode;
14947132718Skan  int reg_size = TARGET_32BIT ? 4 : 8;
1494890075Sobrien  int i;
1494990075Sobrien
14950132718Skan  info = rs6000_stack_info ();
14951132718Skan
14952132718Skan  if (TARGET_SPE_ABI && info->spe_64bit_regs_used != 0)
14953117395Skan    {
14954117395Skan      reg_mode = V2SImode;
14955117395Skan      reg_size = 8;
14956117395Skan    }
14957117395Skan
1495890075Sobrien  using_load_multiple = (TARGET_MULTIPLE && ! TARGET_POWERPC64
14959132718Skan			 && (!TARGET_SPE_ABI
14960132718Skan			     || info->spe_64bit_regs_used == 0)
14961169689Skan			 && info->first_gp_reg_save < 31
14962169689Skan			 && no_global_regs_above (info->first_gp_reg_save));
1496390075Sobrien  restoring_FPRs_inline = (sibcall
1496490075Sobrien			   || current_function_calls_eh_return
1496590075Sobrien			   || info->first_fp_reg_save == 64
1496690075Sobrien			   || FP_SAVE_INLINE (info->first_fp_reg_save));
14967169689Skan  use_backchain_to_restore_sp = (frame_pointer_needed
1496890075Sobrien				 || current_function_calls_alloca
1496990075Sobrien				 || info->total_size > 32767);
1497090075Sobrien  using_mfcr_multiple = (rs6000_cpu == PROCESSOR_PPC601
1497190075Sobrien			 || rs6000_cpu == PROCESSOR_PPC603
1497290075Sobrien			 || rs6000_cpu == PROCESSOR_PPC750
1497390075Sobrien			 || optimize_size);
1497490075Sobrien
14975169689Skan  if (WORLD_SAVE_P (info))
14976169689Skan    {
14977169689Skan      int i, j;
14978169689Skan      char rname[30];
14979169689Skan      const char *alloc_rname;
14980169689Skan      rtvec p;
14981169689Skan
14982169689Skan      /* eh_rest_world_r10 will return to the location saved in the LR
14983169689Skan	 stack slot (which is not likely to be our caller.)
14984169689Skan	 Input: R10 -- stack adjustment.  Clobbers R0, R11, R12, R7, R8.
14985169689Skan	 rest_world is similar, except any R10 parameter is ignored.
14986169689Skan	 The exception-handling stuff that was here in 2.95 is no
14987169689Skan	 longer necessary.  */
14988169689Skan
14989169689Skan      p = rtvec_alloc (9
14990169689Skan		       + 1
14991169689Skan		       + 32 - info->first_gp_reg_save
14992169689Skan		       + LAST_ALTIVEC_REGNO + 1 - info->first_altivec_reg_save
14993169689Skan		       + 63 + 1 - info->first_fp_reg_save);
14994169689Skan
14995169689Skan      strcpy (rname, ((current_function_calls_eh_return) ?
14996169689Skan		      "*eh_rest_world_r10" : "*rest_world"));
14997169689Skan      alloc_rname = ggc_strdup (rname);
14998169689Skan
14999169689Skan      j = 0;
15000169689Skan      RTVEC_ELT (p, j++) = gen_rtx_RETURN (VOIDmode);
15001169689Skan      RTVEC_ELT (p, j++) = gen_rtx_USE (VOIDmode,
15002169689Skan					gen_rtx_REG (Pmode,
15003169689Skan						     LINK_REGISTER_REGNUM));
15004169689Skan      RTVEC_ELT (p, j++)
15005169689Skan	= gen_rtx_USE (VOIDmode, gen_rtx_SYMBOL_REF (Pmode, alloc_rname));
15006169689Skan      /* The instruction pattern requires a clobber here;
15007169689Skan	 it is shared with the restVEC helper. */
15008169689Skan      RTVEC_ELT (p, j++)
15009169689Skan	= gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, 11));
15010169689Skan
15011169689Skan      {
15012169689Skan	/* CR register traditionally saved as CR2.  */
15013169689Skan	rtx reg = gen_rtx_REG (reg_mode, CR2_REGNO);
15014169689Skan	rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
15015169689Skan				 GEN_INT (info->cr_save_offset));
15016169689Skan	rtx mem = gen_frame_mem (reg_mode, addr);
15017169689Skan
15018169689Skan	RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem);
15019169689Skan      }
15020169689Skan
15021169689Skan      for (i = 0; i < 32 - info->first_gp_reg_save; i++)
15022169689Skan	{
15023169689Skan	  rtx reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
15024169689Skan	  rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
15025169689Skan				   GEN_INT (info->gp_save_offset
15026169689Skan					    + reg_size * i));
15027169689Skan	  rtx mem = gen_frame_mem (reg_mode, addr);
15028169689Skan
15029169689Skan	  RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem);
15030169689Skan	}
15031169689Skan      for (i = 0; info->first_altivec_reg_save + i <= LAST_ALTIVEC_REGNO; i++)
15032169689Skan	{
15033169689Skan	  rtx reg = gen_rtx_REG (V4SImode, info->first_altivec_reg_save + i);
15034169689Skan	  rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
15035169689Skan				   GEN_INT (info->altivec_save_offset
15036169689Skan					    + 16 * i));
15037169689Skan	  rtx mem = gen_frame_mem (V4SImode, addr);
15038169689Skan
15039169689Skan	  RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem);
15040169689Skan	}
15041169689Skan      for (i = 0; info->first_fp_reg_save + i <= 63; i++)
15042169689Skan	{
15043169689Skan	  rtx reg = gen_rtx_REG (DFmode, info->first_fp_reg_save + i);
15044169689Skan	  rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
15045169689Skan				   GEN_INT (info->fp_save_offset
15046169689Skan					    + 8 * i));
15047169689Skan	  rtx mem = gen_frame_mem (DFmode, addr);
15048169689Skan
15049169689Skan	  RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem);
15050169689Skan	}
15051169689Skan      RTVEC_ELT (p, j++)
15052169689Skan	= gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, 0));
15053169689Skan      RTVEC_ELT (p, j++)
15054169689Skan	= gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, 12));
15055169689Skan      RTVEC_ELT (p, j++)
15056169689Skan	= gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, 7));
15057169689Skan      RTVEC_ELT (p, j++)
15058169689Skan	= gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, 8));
15059169689Skan      RTVEC_ELT (p, j++)
15060169689Skan	= gen_rtx_USE (VOIDmode, gen_rtx_REG (SImode, 10));
15061169689Skan      emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, p));
15062169689Skan
15063169689Skan      return;
15064169689Skan    }
15065169689Skan
15066259583Spfg  /* Set sp_offset based on the stack push from the prologue.  */
15067259583Spfg  if (info->total_size < 32767)
15068259583Spfg    sp_offset = info->total_size;
1506990075Sobrien
1507090075Sobrien  /* Restore AltiVec registers if needed.  */
1507190075Sobrien  if (TARGET_ALTIVEC_ABI && info->altivec_size != 0)
1507290075Sobrien    {
1507390075Sobrien      int i;
1507490075Sobrien
1507590075Sobrien      for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i)
1507690075Sobrien	if (info->vrsave_mask & ALTIVEC_REG_BIT (i))
1507790075Sobrien	  {
1507890075Sobrien	    rtx addr, areg, mem;
1507990075Sobrien
1508090075Sobrien	    areg = gen_rtx_REG (Pmode, 0);
1508190075Sobrien	    emit_move_insn
1508290075Sobrien	      (areg, GEN_INT (info->altivec_save_offset
1508390075Sobrien			      + sp_offset
1508490075Sobrien			      + 16 * (i - info->first_altivec_reg_save)));
1508590075Sobrien
1508690075Sobrien	    /* AltiVec addressing mode is [reg+reg].  */
1508790075Sobrien	    addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, areg);
15088169689Skan	    mem = gen_frame_mem (V4SImode, addr);
1508990075Sobrien
1509090075Sobrien	    emit_move_insn (gen_rtx_REG (V4SImode, i), mem);
1509190075Sobrien	  }
1509290075Sobrien    }
1509390075Sobrien
1509490075Sobrien  /* Restore VRSAVE if needed.  */
15095132718Skan  if (TARGET_ALTIVEC && TARGET_ALTIVEC_VRSAVE
15096132718Skan      && info->vrsave_mask != 0)
1509790075Sobrien    {
1509890075Sobrien      rtx addr, mem, reg;
1509990075Sobrien
1510090075Sobrien      addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
1510190075Sobrien			   GEN_INT (info->vrsave_save_offset + sp_offset));
15102169689Skan      mem = gen_frame_mem (SImode, addr);
1510390075Sobrien      reg = gen_rtx_REG (SImode, 12);
1510490075Sobrien      emit_move_insn (reg, mem);
1510590075Sobrien
1510690075Sobrien      emit_insn (generate_set_vrsave (reg, info, 1));
1510790075Sobrien    }
1510890075Sobrien
15109259583Spfg  sp_offset = 0;
15110259583Spfg
15111259583Spfg  /* If we have a frame pointer, a call to alloca,  or a large stack
15112259583Spfg     frame, restore the old stack pointer using the backchain.  Otherwise,
15113259583Spfg     we know what size to update it with.  */
15114259583Spfg  if (use_backchain_to_restore_sp)
15115259583Spfg    {
15116259583Spfg      /* Under V.4, don't reset the stack pointer until after we're done
15117259583Spfg	 loading the saved registers.  */
15118259583Spfg      if (DEFAULT_ABI == ABI_V4)
15119259583Spfg	frame_reg_rtx = gen_rtx_REG (Pmode, 11);
15120259583Spfg
15121259583Spfg      emit_move_insn (frame_reg_rtx,
15122259583Spfg		      gen_rtx_MEM (Pmode, sp_reg_rtx));
15123259583Spfg    }
15124259583Spfg  else if (info->push_p)
15125259583Spfg    {
15126259583Spfg      if (DEFAULT_ABI == ABI_V4
15127259583Spfg	  || current_function_calls_eh_return)
15128259583Spfg	sp_offset = info->total_size;
15129259583Spfg      else
15130259583Spfg	{
15131259583Spfg	  emit_insn (TARGET_32BIT
15132259583Spfg		     ? gen_addsi3 (sp_reg_rtx, sp_reg_rtx,
15133259583Spfg				   GEN_INT (info->total_size))
15134259583Spfg		     : gen_adddi3 (sp_reg_rtx, sp_reg_rtx,
15135259583Spfg				   GEN_INT (info->total_size)));
15136259583Spfg	}
15137259583Spfg    }
15138259583Spfg
1513990075Sobrien  /* Get the old lr if we saved it.  */
1514090075Sobrien  if (info->lr_save_p)
1514190075Sobrien    {
15142117395Skan      rtx mem = gen_frame_mem_offset (Pmode, frame_reg_rtx,
15143117395Skan				      info->lr_save_offset + sp_offset);
1514490075Sobrien
1514590075Sobrien      emit_move_insn (gen_rtx_REG (Pmode, 0), mem);
1514690075Sobrien    }
15147169689Skan
1514890075Sobrien  /* Get the old cr if we saved it.  */
1514990075Sobrien  if (info->cr_save_p)
1515090075Sobrien    {
1515190075Sobrien      rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
1515290075Sobrien			       GEN_INT (info->cr_save_offset + sp_offset));
15153169689Skan      rtx mem = gen_frame_mem (SImode, addr);
1515490075Sobrien
1515590075Sobrien      emit_move_insn (gen_rtx_REG (SImode, 12), mem);
1515690075Sobrien    }
15157169689Skan
1515890075Sobrien  /* Set LR here to try to overlap restores below.  */
1515990075Sobrien  if (info->lr_save_p)
1516090075Sobrien    emit_move_insn (gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM),
1516190075Sobrien		    gen_rtx_REG (Pmode, 0));
15162169689Skan
1516390075Sobrien  /* Load exception handler data registers, if needed.  */
1516490075Sobrien  if (current_function_calls_eh_return)
1516590075Sobrien    {
1516690075Sobrien      unsigned int i, regno;
1516790075Sobrien
15168132718Skan      if (TARGET_AIX)
15169132718Skan	{
15170132718Skan	  rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
15171132718Skan				   GEN_INT (sp_offset + 5 * reg_size));
15172169689Skan	  rtx mem = gen_frame_mem (reg_mode, addr);
15173132718Skan
15174132718Skan	  emit_move_insn (gen_rtx_REG (reg_mode, 2), mem);
15175132718Skan	}
15176132718Skan
1517790075Sobrien      for (i = 0; ; ++i)
1517890075Sobrien	{
15179117395Skan	  rtx mem;
1518090075Sobrien
1518190075Sobrien	  regno = EH_RETURN_DATA_REGNO (i);
1518290075Sobrien	  if (regno == INVALID_REGNUM)
1518390075Sobrien	    break;
1518490075Sobrien
15185117395Skan	  mem = gen_frame_mem_offset (reg_mode, frame_reg_rtx,
15186117395Skan				      info->ehrd_offset + sp_offset
15187117395Skan				      + reg_size * (int) i);
1518890075Sobrien
1518990075Sobrien	  emit_move_insn (gen_rtx_REG (reg_mode, regno), mem);
1519090075Sobrien	}
1519190075Sobrien    }
15192169689Skan
1519390075Sobrien  /* Restore GPRs.  This is done as a PARALLEL if we are using
1519490075Sobrien     the load-multiple instructions.  */
1519590075Sobrien  if (using_load_multiple)
1519690075Sobrien    {
1519790075Sobrien      rtvec p;
1519890075Sobrien      p = rtvec_alloc (32 - info->first_gp_reg_save);
1519990075Sobrien      for (i = 0; i < 32 - info->first_gp_reg_save; i++)
1520090075Sobrien	{
15201169689Skan	  rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
15202169689Skan				   GEN_INT (info->gp_save_offset
15203169689Skan					    + sp_offset
1520490075Sobrien					    + reg_size * i));
15205169689Skan	  rtx mem = gen_frame_mem (reg_mode, addr);
1520690075Sobrien
15207169689Skan	  RTVEC_ELT (p, i) =
1520890075Sobrien	    gen_rtx_SET (VOIDmode,
1520990075Sobrien			 gen_rtx_REG (reg_mode, info->first_gp_reg_save + i),
1521090075Sobrien			 mem);
1521190075Sobrien	}
1521290075Sobrien      emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
1521390075Sobrien    }
1521490075Sobrien  else
1521590075Sobrien    for (i = 0; i < 32 - info->first_gp_reg_save; i++)
15216169689Skan      if ((regs_ever_live[info->first_gp_reg_save + i]
15217169689Skan	   && (!call_used_regs[info->first_gp_reg_save + i]
15218169689Skan	       || (i + info->first_gp_reg_save == RS6000_PIC_OFFSET_TABLE_REGNUM
15219146895Skan		   && TARGET_TOC && TARGET_MINIMAL_TOC)))
15220169689Skan	  || (i + info->first_gp_reg_save == RS6000_PIC_OFFSET_TABLE_REGNUM
15221117395Skan	      && ((DEFAULT_ABI == ABI_V4 && flag_pic != 0)
1522290075Sobrien		  || (DEFAULT_ABI == ABI_DARWIN && flag_pic))))
1522390075Sobrien	{
15224169689Skan	  rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
15225169689Skan				   GEN_INT (info->gp_save_offset
15226169689Skan					    + sp_offset
1522790075Sobrien					    + reg_size * i));
15228169689Skan	  rtx mem = gen_frame_mem (reg_mode, addr);
1522990075Sobrien
15230117395Skan	  /* Restore 64-bit quantities for SPE.  */
15231132718Skan	  if (TARGET_SPE_ABI && info->spe_64bit_regs_used != 0)
15232117395Skan	    {
15233117395Skan	      int offset = info->spe_gp_save_offset + sp_offset + 8 * i;
15234117395Skan	      rtx b;
15235117395Skan
15236117395Skan	      if (!SPE_CONST_OFFSET_OK (offset))
15237117395Skan		{
15238117395Skan		  b = gen_rtx_REG (Pmode, FIXED_SCRATCH);
15239117395Skan		  emit_move_insn (b, GEN_INT (offset));
15240117395Skan		}
15241117395Skan	      else
15242117395Skan		b = GEN_INT (offset);
15243117395Skan
15244117395Skan	      addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, b);
15245169689Skan	      mem = gen_frame_mem (V2SImode, addr);
15246117395Skan	    }
15247117395Skan
15248169689Skan	  emit_move_insn (gen_rtx_REG (reg_mode,
15249117395Skan				       info->first_gp_reg_save + i), mem);
1525090075Sobrien	}
1525190075Sobrien
1525290075Sobrien  /* Restore fpr's if we need to do it without calling a function.  */
1525390075Sobrien  if (restoring_FPRs_inline)
1525490075Sobrien    for (i = 0; i < 64 - info->first_fp_reg_save; i++)
15255169689Skan      if ((regs_ever_live[info->first_fp_reg_save+i]
1525690075Sobrien	   && ! call_used_regs[info->first_fp_reg_save+i]))
1525790075Sobrien	{
1525890075Sobrien	  rtx addr, mem;
1525990075Sobrien	  addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
15260169689Skan			       GEN_INT (info->fp_save_offset
15261169689Skan					+ sp_offset
1526290075Sobrien					+ 8 * i));
15263169689Skan	  mem = gen_frame_mem (DFmode, addr);
1526490075Sobrien
15265169689Skan	  emit_move_insn (gen_rtx_REG (DFmode,
1526690075Sobrien				       info->first_fp_reg_save + i),
1526790075Sobrien			  mem);
1526890075Sobrien	}
1526990075Sobrien
1527090075Sobrien  /* If we saved cr, restore it here.  Just those that were used.  */
1527190075Sobrien  if (info->cr_save_p)
1527290075Sobrien    {
1527390075Sobrien      rtx r12_rtx = gen_rtx_REG (SImode, 12);
1527490075Sobrien      int count = 0;
15275169689Skan
1527690075Sobrien      if (using_mfcr_multiple)
1527790075Sobrien	{
1527890075Sobrien	  for (i = 0; i < 8; i++)
1527990075Sobrien	    if (regs_ever_live[CR0_REGNO+i] && ! call_used_regs[CR0_REGNO+i])
1528090075Sobrien	      count++;
15281169689Skan	  gcc_assert (count);
1528290075Sobrien	}
1528390075Sobrien
1528490075Sobrien      if (using_mfcr_multiple && count > 1)
1528590075Sobrien	{
1528690075Sobrien	  rtvec p;
1528790075Sobrien	  int ndx;
15288169689Skan
1528990075Sobrien	  p = rtvec_alloc (count);
1529090075Sobrien
1529190075Sobrien	  ndx = 0;
1529290075Sobrien	  for (i = 0; i < 8; i++)
1529390075Sobrien	    if (regs_ever_live[CR0_REGNO+i] && ! call_used_regs[CR0_REGNO+i])
1529490075Sobrien	      {
1529590075Sobrien		rtvec r = rtvec_alloc (2);
1529690075Sobrien		RTVEC_ELT (r, 0) = r12_rtx;
1529790075Sobrien		RTVEC_ELT (r, 1) = GEN_INT (1 << (7-i));
1529890075Sobrien		RTVEC_ELT (p, ndx) =
15299169689Skan		  gen_rtx_SET (VOIDmode, gen_rtx_REG (CCmode, CR0_REGNO+i),
15300132718Skan			       gen_rtx_UNSPEC (CCmode, r, UNSPEC_MOVESI_TO_CR));
1530190075Sobrien		ndx++;
1530290075Sobrien	      }
1530390075Sobrien	  emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
15304169689Skan	  gcc_assert (ndx == count);
1530590075Sobrien	}
1530690075Sobrien      else
1530790075Sobrien	for (i = 0; i < 8; i++)
1530890075Sobrien	  if (regs_ever_live[CR0_REGNO+i] && ! call_used_regs[CR0_REGNO+i])
1530990075Sobrien	    {
15310169689Skan	      emit_insn (gen_movsi_to_cr_one (gen_rtx_REG (CCmode,
1531190075Sobrien							   CR0_REGNO+i),
1531290075Sobrien					      r12_rtx));
1531390075Sobrien	    }
1531490075Sobrien    }
1531590075Sobrien
1531690075Sobrien  /* If this is V.4, unwind the stack pointer after all of the loads
15317169689Skan     have been done.  */
15318169689Skan  if (frame_reg_rtx != sp_reg_rtx)
1531990075Sobrien    {
15320169689Skan      /* This blockage is needed so that sched doesn't decide to move
15321169689Skan	 the sp change before the register restores.  */
15322169689Skan      rs6000_emit_stack_tie ();
15323169689Skan      emit_move_insn (sp_reg_rtx, frame_reg_rtx);
1532490075Sobrien    }
15325169689Skan  else if (sp_offset != 0)
15326169689Skan    emit_insn (TARGET_32BIT
15327169689Skan	       ? gen_addsi3 (sp_reg_rtx, sp_reg_rtx,
15328169689Skan			     GEN_INT (sp_offset))
15329169689Skan	       : gen_adddi3 (sp_reg_rtx, sp_reg_rtx,
15330169689Skan			     GEN_INT (sp_offset)));
1533190075Sobrien
1533290075Sobrien  if (current_function_calls_eh_return)
1533390075Sobrien    {
1533490075Sobrien      rtx sa = EH_RETURN_STACKADJ_RTX;
15335132718Skan      emit_insn (TARGET_32BIT
1533690075Sobrien		 ? gen_addsi3 (sp_reg_rtx, sp_reg_rtx, sa)
1533790075Sobrien		 : gen_adddi3 (sp_reg_rtx, sp_reg_rtx, sa));
1533890075Sobrien    }
1533990075Sobrien
1534090075Sobrien  if (!sibcall)
1534190075Sobrien    {
1534290075Sobrien      rtvec p;
1534390075Sobrien      if (! restoring_FPRs_inline)
1534490075Sobrien	p = rtvec_alloc (3 + 64 - info->first_fp_reg_save);
1534590075Sobrien      else
1534690075Sobrien	p = rtvec_alloc (2);
1534790075Sobrien
1534890075Sobrien      RTVEC_ELT (p, 0) = gen_rtx_RETURN (VOIDmode);
15349169689Skan      RTVEC_ELT (p, 1) = gen_rtx_USE (VOIDmode,
15350169689Skan				      gen_rtx_REG (Pmode,
1535190075Sobrien						   LINK_REGISTER_REGNUM));
1535290075Sobrien
1535390075Sobrien      /* If we have to restore more than two FP registers, branch to the
1535490075Sobrien	 restore function.  It will return to our caller.  */
1535590075Sobrien      if (! restoring_FPRs_inline)
1535690075Sobrien	{
1535790075Sobrien	  int i;
1535890075Sobrien	  char rname[30];
1535990075Sobrien	  const char *alloc_rname;
1536090075Sobrien
15361169689Skan	  sprintf (rname, "%s%d%s", RESTORE_FP_PREFIX,
1536290075Sobrien		   info->first_fp_reg_save - 32, RESTORE_FP_SUFFIX);
1536390075Sobrien	  alloc_rname = ggc_strdup (rname);
1536490075Sobrien	  RTVEC_ELT (p, 2) = gen_rtx_USE (VOIDmode,
1536590075Sobrien					  gen_rtx_SYMBOL_REF (Pmode,
1536690075Sobrien							      alloc_rname));
1536790075Sobrien
1536890075Sobrien	  for (i = 0; i < 64 - info->first_fp_reg_save; i++)
1536990075Sobrien	    {
1537090075Sobrien	      rtx addr, mem;
1537190075Sobrien	      addr = gen_rtx_PLUS (Pmode, sp_reg_rtx,
1537290075Sobrien				   GEN_INT (info->fp_save_offset + 8*i));
15373169689Skan	      mem = gen_frame_mem (DFmode, addr);
1537490075Sobrien
15375169689Skan	      RTVEC_ELT (p, i+3) =
1537690075Sobrien		gen_rtx_SET (VOIDmode,
1537790075Sobrien			     gen_rtx_REG (DFmode, info->first_fp_reg_save + i),
1537890075Sobrien			     mem);
1537990075Sobrien	    }
1538090075Sobrien	}
15381169689Skan
1538290075Sobrien      emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, p));
1538390075Sobrien    }
1538490075Sobrien}
1538590075Sobrien
1538690075Sobrien/* Write function epilogue.  */
1538790075Sobrien
1538890075Sobrienstatic void
15389169689Skanrs6000_output_function_epilogue (FILE *file,
15390132718Skan				 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
1539190075Sobrien{
1539290075Sobrien  if (! HAVE_epilogue)
1539390075Sobrien    {
1539490075Sobrien      rtx insn = get_last_insn ();
1539590075Sobrien      /* If the last insn was a BARRIER, we don't have to write anything except
1539690075Sobrien	 the trace table.  */
1539790075Sobrien      if (GET_CODE (insn) == NOTE)
1539890075Sobrien	insn = prev_nonnote_insn (insn);
1539990075Sobrien      if (insn == 0 ||  GET_CODE (insn) != BARRIER)
1540090075Sobrien	{
1540190075Sobrien	  /* This is slightly ugly, but at least we don't have two
1540290075Sobrien	     copies of the epilogue-emitting code.  */
1540390075Sobrien	  start_sequence ();
1540490075Sobrien
1540590075Sobrien	  /* A NOTE_INSN_DELETED is supposed to be at the start
1540690075Sobrien	     and end of the "toplevel" insn chain.  */
15407132718Skan	  emit_note (NOTE_INSN_DELETED);
1540890075Sobrien	  rs6000_emit_epilogue (FALSE);
15409132718Skan	  emit_note (NOTE_INSN_DELETED);
1541090075Sobrien
15411132718Skan	  /* Expand INSN_ADDRESSES so final() doesn't crash.  */
1541296263Sobrien	  {
1541396263Sobrien	    rtx insn;
1541496263Sobrien	    unsigned addr = 0;
1541596263Sobrien	    for (insn = get_insns (); insn != 0; insn = NEXT_INSN (insn))
1541696263Sobrien	      {
1541796263Sobrien		INSN_ADDRESSES_NEW (insn, addr);
1541896263Sobrien		addr += 4;
1541996263Sobrien	      }
1542096263Sobrien	  }
1542196263Sobrien
1542290075Sobrien	  if (TARGET_DEBUG_STACK)
1542390075Sobrien	    debug_rtx_list (get_insns (), 100);
15424169689Skan	  final (get_insns (), file, FALSE);
1542590075Sobrien	  end_sequence ();
1542690075Sobrien	}
1542790075Sobrien    }
1542890075Sobrien
15429132718Skan#if TARGET_MACHO
15430132718Skan  macho_branch_islands ();
15431119256Skan  /* Mach-O doesn't support labels at the end of objects, so if
15432119256Skan     it looks like we might want one, insert a NOP.  */
15433119256Skan  {
15434119256Skan    rtx insn = get_last_insn ();
15435119256Skan    while (insn
15436119256Skan	   && NOTE_P (insn)
15437119256Skan	   && NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED_LABEL)
15438119256Skan      insn = PREV_INSN (insn);
15439169689Skan    if (insn
15440169689Skan	&& (LABEL_P (insn)
15441119256Skan	    || (NOTE_P (insn)
15442119256Skan		&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED_LABEL)))
15443119256Skan      fputs ("\tnop\n", file);
15444119256Skan  }
15445119256Skan#endif
15446119256Skan
1544790075Sobrien  /* Output a traceback table here.  See /usr/include/sys/debug.h for info
1544890075Sobrien     on its format.
1544990075Sobrien
1545090075Sobrien     We don't output a traceback table if -finhibit-size-directive was
1545190075Sobrien     used.  The documentation for -finhibit-size-directive reads
1545290075Sobrien     ``don't output a @code{.size} assembler directive, or anything
1545390075Sobrien     else that would cause trouble if the function is split in the
1545490075Sobrien     middle, and the two halves are placed at locations far apart in
1545590075Sobrien     memory.''  The traceback table has this property, since it
1545690075Sobrien     includes the offset from the start of the function to the
1545790075Sobrien     traceback table itself.
1545890075Sobrien
1545990075Sobrien     System V.4 Powerpc's (and the embedded ABI derived from it) use a
1546090075Sobrien     different traceback table.  */
15461117395Skan  if (DEFAULT_ABI == ABI_AIX && ! flag_inhibit_size_directive
15462169689Skan      && rs6000_traceback != traceback_none && !current_function_is_thunk)
1546390075Sobrien    {
15464117395Skan      const char *fname = NULL;
1546590075Sobrien      const char *language_string = lang_hooks.name;
1546690075Sobrien      int fixed_parms = 0, float_parms = 0, parm_info = 0;
1546790075Sobrien      int i;
15468117395Skan      int optional_tbtab;
15469169689Skan      rs6000_stack_t *info = rs6000_stack_info ();
1547090075Sobrien
15471117395Skan      if (rs6000_traceback == traceback_full)
15472117395Skan	optional_tbtab = 1;
15473117395Skan      else if (rs6000_traceback == traceback_part)
15474117395Skan	optional_tbtab = 0;
15475117395Skan      else
15476117395Skan	optional_tbtab = !optimize_size && !TARGET_ELF;
1547790075Sobrien
15478117395Skan      if (optional_tbtab)
15479117395Skan	{
15480117395Skan	  fname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
15481117395Skan	  while (*fname == '.')	/* V.4 encodes . in the name */
15482117395Skan	    fname++;
1548390075Sobrien
15484117395Skan	  /* Need label immediately before tbtab, so we can compute
15485117395Skan	     its offset from the function start.  */
15486117395Skan	  ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "LT");
15487117395Skan	  ASM_OUTPUT_LABEL (file, fname);
15488117395Skan	}
15489117395Skan
1549090075Sobrien      /* The .tbtab pseudo-op can only be used for the first eight
1549190075Sobrien	 expressions, since it can't handle the possibly variable
1549290075Sobrien	 length fields that follow.  However, if you omit the optional
1549390075Sobrien	 fields, the assembler outputs zeros for all optional fields
1549490075Sobrien	 anyways, giving each variable length field is minimum length
1549590075Sobrien	 (as defined in sys/debug.h).  Thus we can not use the .tbtab
1549690075Sobrien	 pseudo-op at all.  */
1549790075Sobrien
1549890075Sobrien      /* An all-zero word flags the start of the tbtab, for debuggers
1549990075Sobrien	 that have to find it by searching forward from the entry
1550090075Sobrien	 point or from the current pc.  */
1550190075Sobrien      fputs ("\t.long 0\n", file);
1550290075Sobrien
1550390075Sobrien      /* Tbtab format type.  Use format type 0.  */
1550490075Sobrien      fputs ("\t.byte 0,", file);
1550590075Sobrien
15506132718Skan      /* Language type.  Unfortunately, there does not seem to be any
15507132718Skan	 official way to discover the language being compiled, so we
15508132718Skan	 use language_string.
15509132718Skan	 C is 0.  Fortran is 1.  Pascal is 2.  Ada is 3.  C++ is 9.
15510169689Skan	 Java is 13.  Objective-C is 14.  Objective-C++ isn't assigned
15511169689Skan	 a number, so for now use 9.  */
15512132718Skan      if (! strcmp (language_string, "GNU C"))
1551390075Sobrien	i = 0;
15514169689Skan      else if (! strcmp (language_string, "GNU F77")
15515169689Skan	       || ! strcmp (language_string, "GNU F95"))
1551690075Sobrien	i = 1;
15517132718Skan      else if (! strcmp (language_string, "GNU Pascal"))
15518132718Skan	i = 2;
1551990075Sobrien      else if (! strcmp (language_string, "GNU Ada"))
1552090075Sobrien	i = 3;
15521169689Skan      else if (! strcmp (language_string, "GNU C++")
15522169689Skan	       || ! strcmp (language_string, "GNU Objective-C++"))
1552390075Sobrien	i = 9;
1552490075Sobrien      else if (! strcmp (language_string, "GNU Java"))
1552590075Sobrien	i = 13;
15526132718Skan      else if (! strcmp (language_string, "GNU Objective-C"))
15527132718Skan	i = 14;
1552890075Sobrien      else
15529169689Skan	gcc_unreachable ();
1553090075Sobrien      fprintf (file, "%d,", i);
1553190075Sobrien
1553290075Sobrien      /* 8 single bit fields: global linkage (not set for C extern linkage,
1553390075Sobrien	 apparently a PL/I convention?), out-of-line epilogue/prologue, offset
1553490075Sobrien	 from start of procedure stored in tbtab, internal function, function
1553590075Sobrien	 has controlled storage, function has no toc, function uses fp,
1553690075Sobrien	 function logs/aborts fp operations.  */
1553790075Sobrien      /* Assume that fp operations are used if any fp reg must be saved.  */
1553890075Sobrien      fprintf (file, "%d,",
1553990075Sobrien	       (optional_tbtab << 5) | ((info->first_fp_reg_save != 64) << 1));
1554090075Sobrien
1554190075Sobrien      /* 6 bitfields: function is interrupt handler, name present in
1554290075Sobrien	 proc table, function calls alloca, on condition directives
1554390075Sobrien	 (controls stack walks, 3 bits), saves condition reg, saves
1554490075Sobrien	 link reg.  */
1554590075Sobrien      /* The `function calls alloca' bit seems to be set whenever reg 31 is
1554690075Sobrien	 set up as a frame pointer, even when there is no alloca call.  */
1554790075Sobrien      fprintf (file, "%d,",
1554890075Sobrien	       ((optional_tbtab << 6)
1554990075Sobrien		| ((optional_tbtab & frame_pointer_needed) << 5)
1555090075Sobrien		| (info->cr_save_p << 1)
1555190075Sobrien		| (info->lr_save_p)));
1555290075Sobrien
1555390075Sobrien      /* 3 bitfields: saves backchain, fixup code, number of fpr saved
1555490075Sobrien	 (6 bits).  */
1555590075Sobrien      fprintf (file, "%d,",
1555690075Sobrien	       (info->push_p << 7) | (64 - info->first_fp_reg_save));
1555790075Sobrien
1555890075Sobrien      /* 2 bitfields: spare bits (2 bits), number of gpr saved (6 bits).  */
1555990075Sobrien      fprintf (file, "%d,", (32 - first_reg_to_save ()));
1556090075Sobrien
1556190075Sobrien      if (optional_tbtab)
1556290075Sobrien	{
1556390075Sobrien	  /* Compute the parameter info from the function decl argument
1556490075Sobrien	     list.  */
1556590075Sobrien	  tree decl;
1556690075Sobrien	  int next_parm_info_bit = 31;
1556790075Sobrien
1556890075Sobrien	  for (decl = DECL_ARGUMENTS (current_function_decl);
1556990075Sobrien	       decl; decl = TREE_CHAIN (decl))
1557090075Sobrien	    {
1557190075Sobrien	      rtx parameter = DECL_INCOMING_RTL (decl);
1557290075Sobrien	      enum machine_mode mode = GET_MODE (parameter);
1557390075Sobrien
1557490075Sobrien	      if (GET_CODE (parameter) == REG)
1557590075Sobrien		{
15576169689Skan		  if (SCALAR_FLOAT_MODE_P (mode))
1557790075Sobrien		    {
1557890075Sobrien		      int bits;
1557990075Sobrien
1558090075Sobrien		      float_parms++;
1558190075Sobrien
15582169689Skan		      switch (mode)
15583169689Skan			{
15584169689Skan			case SFmode:
15585169689Skan			  bits = 0x2;
15586169689Skan			  break;
1558790075Sobrien
15588169689Skan			case DFmode:
15589169689Skan			case TFmode:
15590169689Skan			  bits = 0x3;
15591169689Skan			  break;
15592169689Skan
15593169689Skan			default:
15594169689Skan			  gcc_unreachable ();
15595169689Skan			}
15596169689Skan
1559790075Sobrien		      /* If only one bit will fit, don't or in this entry.  */
1559890075Sobrien		      if (next_parm_info_bit > 0)
1559990075Sobrien			parm_info |= (bits << (next_parm_info_bit - 1));
1560090075Sobrien		      next_parm_info_bit -= 2;
1560190075Sobrien		    }
1560290075Sobrien		  else
1560390075Sobrien		    {
1560490075Sobrien		      fixed_parms += ((GET_MODE_SIZE (mode)
1560590075Sobrien				       + (UNITS_PER_WORD - 1))
1560690075Sobrien				      / UNITS_PER_WORD);
1560790075Sobrien		      next_parm_info_bit -= 1;
1560890075Sobrien		    }
1560990075Sobrien		}
1561090075Sobrien	    }
1561190075Sobrien	}
1561290075Sobrien
1561390075Sobrien      /* Number of fixed point parameters.  */
1561490075Sobrien      /* This is actually the number of words of fixed point parameters; thus
1561590075Sobrien	 an 8 byte struct counts as 2; and thus the maximum value is 8.  */
1561690075Sobrien      fprintf (file, "%d,", fixed_parms);
1561790075Sobrien
1561890075Sobrien      /* 2 bitfields: number of floating point parameters (7 bits), parameters
1561990075Sobrien	 all on stack.  */
1562090075Sobrien      /* This is actually the number of fp registers that hold parameters;
1562190075Sobrien	 and thus the maximum value is 13.  */
1562290075Sobrien      /* Set parameters on stack bit if parameters are not in their original
1562390075Sobrien	 registers, regardless of whether they are on the stack?  Xlc
1562490075Sobrien	 seems to set the bit when not optimizing.  */
1562590075Sobrien      fprintf (file, "%d\n", ((float_parms << 1) | (! optimize)));
1562690075Sobrien
1562790075Sobrien      if (! optional_tbtab)
1562890075Sobrien	return;
1562990075Sobrien
1563090075Sobrien      /* Optional fields follow.  Some are variable length.  */
1563190075Sobrien
1563290075Sobrien      /* Parameter types, left adjusted bit fields: 0 fixed, 10 single float,
1563390075Sobrien	 11 double float.  */
1563490075Sobrien      /* There is an entry for each parameter in a register, in the order that
1563590075Sobrien	 they occur in the parameter list.  Any intervening arguments on the
1563690075Sobrien	 stack are ignored.  If the list overflows a long (max possible length
1563790075Sobrien	 34 bits) then completely leave off all elements that don't fit.  */
1563890075Sobrien      /* Only emit this long if there was at least one parameter.  */
1563990075Sobrien      if (fixed_parms || float_parms)
1564090075Sobrien	fprintf (file, "\t.long %d\n", parm_info);
1564190075Sobrien
1564290075Sobrien      /* Offset from start of code to tb table.  */
1564390075Sobrien      fputs ("\t.long ", file);
1564490075Sobrien      ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "LT");
15645169689Skan      if (TARGET_AIX)
15646169689Skan	RS6000_OUTPUT_BASENAME (file, fname);
15647169689Skan      else
15648169689Skan	assemble_name (file, fname);
15649169689Skan      putc ('-', file);
15650169689Skan      rs6000_output_function_entry (file, fname);
1565190075Sobrien      putc ('\n', file);
1565290075Sobrien
1565390075Sobrien      /* Interrupt handler mask.  */
1565490075Sobrien      /* Omit this long, since we never set the interrupt handler bit
1565590075Sobrien	 above.  */
1565690075Sobrien
1565790075Sobrien      /* Number of CTL (controlled storage) anchors.  */
1565890075Sobrien      /* Omit this long, since the has_ctl bit is never set above.  */
1565990075Sobrien
1566090075Sobrien      /* Displacement into stack of each CTL anchor.  */
1566190075Sobrien      /* Omit this list of longs, because there are no CTL anchors.  */
1566290075Sobrien
1566390075Sobrien      /* Length of function name.  */
15664117395Skan      if (*fname == '*')
15665117395Skan	++fname;
1566690075Sobrien      fprintf (file, "\t.short %d\n", (int) strlen (fname));
1566790075Sobrien
1566890075Sobrien      /* Function name.  */
1566990075Sobrien      assemble_string (fname, strlen (fname));
1567090075Sobrien
1567190075Sobrien      /* Register for alloca automatic storage; this is always reg 31.
1567290075Sobrien	 Only emit this if the alloca bit was set above.  */
1567390075Sobrien      if (frame_pointer_needed)
1567490075Sobrien	fputs ("\t.byte 31\n", file);
1567596263Sobrien
1567696263Sobrien      fputs ("\t.align 2\n", file);
1567790075Sobrien    }
1567890075Sobrien}
1567990075Sobrien
1568090075Sobrien/* A C compound statement that outputs the assembler code for a thunk
1568190075Sobrien   function, used to implement C++ virtual function calls with
1568290075Sobrien   multiple inheritance.  The thunk acts as a wrapper around a virtual
1568390075Sobrien   function, adjusting the implicit object parameter before handing
1568490075Sobrien   control off to the real function.
1568590075Sobrien
1568690075Sobrien   First, emit code to add the integer DELTA to the location that
1568790075Sobrien   contains the incoming first argument.  Assume that this argument
1568890075Sobrien   contains a pointer, and is the one used to pass the `this' pointer
1568990075Sobrien   in C++.  This is the incoming argument *before* the function
1569090075Sobrien   prologue, e.g. `%o0' on a sparc.  The addition must preserve the
1569190075Sobrien   values of all other incoming arguments.
1569290075Sobrien
1569390075Sobrien   After the addition, emit code to jump to FUNCTION, which is a
1569490075Sobrien   `FUNCTION_DECL'.  This is a direct pure jump, not a call, and does
1569590075Sobrien   not touch the return address.  Hence returning from FUNCTION will
1569690075Sobrien   return to whoever called the current `thunk'.
1569790075Sobrien
1569890075Sobrien   The effect must be as if FUNCTION had been called directly with the
1569990075Sobrien   adjusted first argument.  This macro is responsible for emitting
1570090075Sobrien   all of the code for a thunk function; output_function_prologue()
1570190075Sobrien   and output_function_epilogue() are not invoked.
1570290075Sobrien
1570390075Sobrien   The THUNK_FNDECL is redundant.  (DELTA and FUNCTION have already
1570490075Sobrien   been extracted from it.)  It might possibly be useful on some
1570590075Sobrien   targets, but probably not.
1570690075Sobrien
1570790075Sobrien   If you do not define this macro, the target-independent code in the
1570890075Sobrien   C++ frontend will generate a less efficient heavyweight thunk that
1570990075Sobrien   calls FUNCTION instead of jumping to it.  The generic approach does
1571090075Sobrien   not support varargs.  */
1571190075Sobrien
15712117395Skanstatic void
15713169689Skanrs6000_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
15714169689Skan			HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
15715132718Skan			tree function)
1571690075Sobrien{
15717132718Skan  rtx this, insn, funexp;
1571890075Sobrien
15719132718Skan  reload_completed = 1;
15720132718Skan  epilogue_completed = 1;
15721132718Skan  no_new_pseudos = 1;
15722169689Skan  reset_block_changes ();
1572390075Sobrien
15724132718Skan  /* Mark the end of the (empty) prologue.  */
15725132718Skan  emit_note (NOTE_INSN_PROLOGUE_END);
15726102780Skan
15727132718Skan  /* Find the "this" pointer.  If the function returns a structure,
15728132718Skan     the structure return pointer is in r3.  */
15729132718Skan  if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
15730132718Skan    this = gen_rtx_REG (Pmode, 4);
15731132718Skan  else
15732132718Skan    this = gen_rtx_REG (Pmode, 3);
1573390075Sobrien
15734132718Skan  /* Apply the constant offset, if required.  */
15735132718Skan  if (delta)
1573690075Sobrien    {
15737132718Skan      rtx delta_rtx = GEN_INT (delta);
15738132718Skan      emit_insn (TARGET_32BIT
15739132718Skan		 ? gen_addsi3 (this, this, delta_rtx)
15740132718Skan		 : gen_adddi3 (this, this, delta_rtx));
1574190075Sobrien    }
1574290075Sobrien
15743132718Skan  /* Apply the offset from the vtable, if required.  */
15744132718Skan  if (vcall_offset)
1574590075Sobrien    {
15746132718Skan      rtx vcall_offset_rtx = GEN_INT (vcall_offset);
15747132718Skan      rtx tmp = gen_rtx_REG (Pmode, 12);
1574890075Sobrien
15749132718Skan      emit_move_insn (tmp, gen_rtx_MEM (Pmode, this));
15750132718Skan      if (((unsigned HOST_WIDE_INT) vcall_offset) + 0x8000 >= 0x10000)
15751132718Skan	{
15752132718Skan	  emit_insn (TARGET_32BIT
15753132718Skan		     ? gen_addsi3 (tmp, tmp, vcall_offset_rtx)
15754132718Skan		     : gen_adddi3 (tmp, tmp, vcall_offset_rtx));
15755132718Skan	  emit_move_insn (tmp, gen_rtx_MEM (Pmode, tmp));
15756132718Skan	}
15757132718Skan      else
15758132718Skan	{
15759132718Skan	  rtx loc = gen_rtx_PLUS (Pmode, tmp, vcall_offset_rtx);
1576090075Sobrien
15761132718Skan	  emit_move_insn (tmp, gen_rtx_MEM (Pmode, loc));
15762132718Skan	}
15763132718Skan      emit_insn (TARGET_32BIT
15764132718Skan		 ? gen_addsi3 (this, this, tmp)
15765132718Skan		 : gen_adddi3 (this, this, tmp));
1576690075Sobrien    }
1576790075Sobrien
15768132718Skan  /* Generate a tail call to the target function.  */
15769132718Skan  if (!TREE_USED (function))
1577090075Sobrien    {
15771132718Skan      assemble_external (function);
15772132718Skan      TREE_USED (function) = 1;
1577390075Sobrien    }
15774132718Skan  funexp = XEXP (DECL_RTL (function), 0);
15775132718Skan  funexp = gen_rtx_MEM (FUNCTION_MODE, funexp);
1577690075Sobrien
15777132718Skan#if TARGET_MACHO
15778132718Skan  if (MACHOPIC_INDIRECT)
15779132718Skan    funexp = machopic_indirect_call_target (funexp);
15780132718Skan#endif
1578190075Sobrien
15782132718Skan  /* gen_sibcall expects reload to convert scratch pseudo to LR so we must
15783169689Skan     generate sibcall RTL explicitly.  */
15784132718Skan  insn = emit_call_insn (
15785132718Skan	   gen_rtx_PARALLEL (VOIDmode,
15786132718Skan	     gen_rtvec (4,
15787132718Skan			gen_rtx_CALL (VOIDmode,
15788132718Skan				      funexp, const0_rtx),
15789132718Skan			gen_rtx_USE (VOIDmode, const0_rtx),
15790132718Skan			gen_rtx_USE (VOIDmode,
15791132718Skan				     gen_rtx_REG (SImode,
15792132718Skan						  LINK_REGISTER_REGNUM)),
15793132718Skan			gen_rtx_RETURN (VOIDmode))));
15794132718Skan  SIBLING_CALL_P (insn) = 1;
15795132718Skan  emit_barrier ();
1579690075Sobrien
15797132718Skan  /* Run just enough of rest_of_compilation to get the insns emitted.
15798132718Skan     There's not really enough bulk here to make other passes such as
15799132718Skan     instruction scheduling worth while.  Note that use_thunk calls
15800132718Skan     assemble_start_function and assemble_end_function.  */
15801132718Skan  insn = get_insns ();
15802132718Skan  insn_locators_initialize ();
15803132718Skan  shorten_branches (insn);
15804132718Skan  final_start_function (insn, file, 1);
15805169689Skan  final (insn, file, 1);
15806132718Skan  final_end_function ();
1580790075Sobrien
15808132718Skan  reload_completed = 0;
15809132718Skan  epilogue_completed = 0;
15810132718Skan  no_new_pseudos = 0;
1581190075Sobrien}
1581290075Sobrien
1581390075Sobrien/* A quick summary of the various types of 'constant-pool tables'
1581490075Sobrien   under PowerPC:
1581590075Sobrien
15816169689Skan   Target	Flags		Name		One table per
1581790075Sobrien   AIX		(none)		AIX TOC		object file
1581890075Sobrien   AIX		-mfull-toc	AIX TOC		object file
1581990075Sobrien   AIX		-mminimal-toc	AIX minimal TOC	translation unit
1582090075Sobrien   SVR4/EABI	(none)		SVR4 SDATA	object file
1582190075Sobrien   SVR4/EABI	-fpic		SVR4 pic	object file
1582290075Sobrien   SVR4/EABI	-fPIC		SVR4 PIC	translation unit
1582390075Sobrien   SVR4/EABI	-mrelocatable	EABI TOC	function
1582490075Sobrien   SVR4/EABI	-maix		AIX TOC		object file
15825169689Skan   SVR4/EABI	-maix -mminimal-toc
1582690075Sobrien				AIX minimal TOC	translation unit
1582790075Sobrien
1582890075Sobrien   Name			Reg.	Set by	entries	      contains:
1582990075Sobrien					made by	 addrs?	fp?	sum?
1583090075Sobrien
1583190075Sobrien   AIX TOC		2	crt0	as	 Y	option	option
1583290075Sobrien   AIX minimal TOC	30	prolog	gcc	 Y	Y	option
1583390075Sobrien   SVR4 SDATA		13	crt0	gcc	 N	Y	N
1583490075Sobrien   SVR4 pic		30	prolog	ld	 Y	not yet	N
1583590075Sobrien   SVR4 PIC		30	prolog	gcc	 Y	option	option
1583690075Sobrien   EABI TOC		30	prolog	gcc	 Y	option	option
1583790075Sobrien
1583890075Sobrien*/
1583990075Sobrien
1584090075Sobrien/* Hash functions for the hash table.  */
1584190075Sobrien
1584290075Sobrienstatic unsigned
15843132718Skanrs6000_hash_constant (rtx k)
1584490075Sobrien{
15845117395Skan  enum rtx_code code = GET_CODE (k);
15846117395Skan  enum machine_mode mode = GET_MODE (k);
15847117395Skan  unsigned result = (code << 3) ^ mode;
15848117395Skan  const char *format;
15849117395Skan  int flen, fidx;
15850169689Skan
15851117395Skan  format = GET_RTX_FORMAT (code);
15852117395Skan  flen = strlen (format);
15853117395Skan  fidx = 0;
1585490075Sobrien
15855117395Skan  switch (code)
15856117395Skan    {
15857117395Skan    case LABEL_REF:
15858117395Skan      return result * 1231 + (unsigned) INSN_UID (XEXP (k, 0));
1585990075Sobrien
15860117395Skan    case CONST_DOUBLE:
15861117395Skan      if (mode != VOIDmode)
15862117395Skan	return real_hash (CONST_DOUBLE_REAL_VALUE (k)) * result;
15863117395Skan      flen = 2;
15864117395Skan      break;
15865117395Skan
15866117395Skan    case CODE_LABEL:
15867117395Skan      fidx = 3;
15868117395Skan      break;
15869117395Skan
15870117395Skan    default:
15871117395Skan      break;
15872117395Skan    }
15873117395Skan
1587490075Sobrien  for (; fidx < flen; fidx++)
1587590075Sobrien    switch (format[fidx])
1587690075Sobrien      {
1587790075Sobrien      case 's':
1587890075Sobrien	{
1587990075Sobrien	  unsigned i, len;
1588090075Sobrien	  const char *str = XSTR (k, fidx);
1588190075Sobrien	  len = strlen (str);
1588290075Sobrien	  result = result * 613 + len;
1588390075Sobrien	  for (i = 0; i < len; i++)
1588490075Sobrien	    result = result * 613 + (unsigned) str[i];
1588590075Sobrien	  break;
1588690075Sobrien	}
1588790075Sobrien      case 'u':
1588890075Sobrien      case 'e':
1588990075Sobrien	result = result * 1231 + rs6000_hash_constant (XEXP (k, fidx));
1589090075Sobrien	break;
1589190075Sobrien      case 'i':
1589290075Sobrien      case 'n':
1589390075Sobrien	result = result * 613 + (unsigned) XINT (k, fidx);
1589490075Sobrien	break;
1589590075Sobrien      case 'w':
1589690075Sobrien	if (sizeof (unsigned) >= sizeof (HOST_WIDE_INT))
1589790075Sobrien	  result = result * 613 + (unsigned) XWINT (k, fidx);
1589890075Sobrien	else
1589990075Sobrien	  {
1590090075Sobrien	    size_t i;
15901169689Skan	    for (i = 0; i < sizeof (HOST_WIDE_INT) / sizeof (unsigned); i++)
1590290075Sobrien	      result = result * 613 + (unsigned) (XWINT (k, fidx)
1590390075Sobrien						  >> CHAR_BIT * i);
1590490075Sobrien	  }
1590590075Sobrien	break;
15906132718Skan      case '0':
15907132718Skan	break;
1590890075Sobrien      default:
15909169689Skan	gcc_unreachable ();
1591090075Sobrien      }
15911117395Skan
1591290075Sobrien  return result;
1591390075Sobrien}
1591490075Sobrien
1591590075Sobrienstatic unsigned
15916132718Skantoc_hash_function (const void *hash_entry)
1591790075Sobrien{
15918169689Skan  const struct toc_hash_struct *thc =
1591990075Sobrien    (const struct toc_hash_struct *) hash_entry;
1592090075Sobrien  return rs6000_hash_constant (thc->key) ^ thc->key_mode;
1592190075Sobrien}
1592290075Sobrien
1592390075Sobrien/* Compare H1 and H2 for equivalence.  */
1592490075Sobrien
1592590075Sobrienstatic int
15926132718Skantoc_hash_eq (const void *h1, const void *h2)
1592790075Sobrien{
1592890075Sobrien  rtx r1 = ((const struct toc_hash_struct *) h1)->key;
1592990075Sobrien  rtx r2 = ((const struct toc_hash_struct *) h2)->key;
1593090075Sobrien
1593190075Sobrien  if (((const struct toc_hash_struct *) h1)->key_mode
1593290075Sobrien      != ((const struct toc_hash_struct *) h2)->key_mode)
1593390075Sobrien    return 0;
1593490075Sobrien
15935117395Skan  return rtx_equal_p (r1, r2);
1593690075Sobrien}
1593790075Sobrien
1593890075Sobrien/* These are the names given by the C++ front-end to vtables, and
1593990075Sobrien   vtable-like objects.  Ideally, this logic should not be here;
1594090075Sobrien   instead, there should be some programmatic way of inquiring as
1594190075Sobrien   to whether or not an object is a vtable.  */
1594290075Sobrien
1594390075Sobrien#define VTABLE_NAME_P(NAME)				\
15944169689Skan  (strncmp ("_vt.", name, strlen ("_vt.")) == 0		\
1594590075Sobrien  || strncmp ("_ZTV", name, strlen ("_ZTV")) == 0	\
1594690075Sobrien  || strncmp ("_ZTT", name, strlen ("_ZTT")) == 0	\
15947132718Skan  || strncmp ("_ZTI", name, strlen ("_ZTI")) == 0	\
15948169689Skan  || strncmp ("_ZTC", name, strlen ("_ZTC")) == 0)
1594990075Sobrien
1595090075Sobrienvoid
15951132718Skanrs6000_output_symbol_ref (FILE *file, rtx x)
1595290075Sobrien{
1595390075Sobrien  /* Currently C++ toc references to vtables can be emitted before it
1595490075Sobrien     is decided whether the vtable is public or private.  If this is
1595590075Sobrien     the case, then the linker will eventually complain that there is
15956169689Skan     a reference to an unknown section.  Thus, for vtables only,
1595790075Sobrien     we emit the TOC reference to reference the symbol and not the
1595890075Sobrien     section.  */
1595990075Sobrien  const char *name = XSTR (x, 0);
1596090075Sobrien
15961169689Skan  if (VTABLE_NAME_P (name))
1596290075Sobrien    {
1596390075Sobrien      RS6000_OUTPUT_BASENAME (file, name);
1596490075Sobrien    }
1596590075Sobrien  else
1596690075Sobrien    assemble_name (file, name);
1596790075Sobrien}
1596890075Sobrien
1596990075Sobrien/* Output a TOC entry.  We derive the entry name from what is being
1597090075Sobrien   written.  */
1597190075Sobrien
1597290075Sobrienvoid
15973132718Skanoutput_toc (FILE *file, rtx x, int labelno, enum machine_mode mode)
1597490075Sobrien{
1597590075Sobrien  char buf[256];
1597690075Sobrien  const char *name = buf;
1597790075Sobrien  const char *real_name;
1597890075Sobrien  rtx base = x;
15979169689Skan  HOST_WIDE_INT offset = 0;
1598090075Sobrien
15981169689Skan  gcc_assert (!TARGET_NO_TOC);
1598290075Sobrien
1598390075Sobrien  /* When the linker won't eliminate them, don't output duplicate
1598490075Sobrien     TOC entries (this happens on AIX if there is any kind of TOC,
15985132718Skan     and on SVR4 under -fPIC or -mrelocatable).  Don't do this for
15986132718Skan     CODE_LABELs.  */
15987132718Skan  if (TARGET_TOC && GET_CODE (x) != LABEL_REF)
1598890075Sobrien    {
1598990075Sobrien      struct toc_hash_struct *h;
1599090075Sobrien      void * * found;
15991169689Skan
15992132718Skan      /* Create toc_hash_table.  This can't be done at OVERRIDE_OPTIONS
15993169689Skan	 time because GGC is not initialized at that point.  */
15994132718Skan      if (toc_hash_table == NULL)
15995169689Skan	toc_hash_table = htab_create_ggc (1021, toc_hash_function,
15996132718Skan					  toc_hash_eq, NULL);
15997132718Skan
1599890075Sobrien      h = ggc_alloc (sizeof (*h));
1599990075Sobrien      h->key = x;
1600090075Sobrien      h->key_mode = mode;
1600190075Sobrien      h->labelno = labelno;
16002169689Skan
1600390075Sobrien      found = htab_find_slot (toc_hash_table, h, 1);
1600490075Sobrien      if (*found == NULL)
1600590075Sobrien	*found = h;
16006169689Skan      else  /* This is indeed a duplicate.
1600790075Sobrien	       Set this label equal to that label.  */
1600890075Sobrien	{
1600990075Sobrien	  fputs ("\t.set ", file);
1601090075Sobrien	  ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "LC");
1601190075Sobrien	  fprintf (file, "%d,", labelno);
1601290075Sobrien	  ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "LC");
16013169689Skan	  fprintf (file, "%d\n", ((*(const struct toc_hash_struct **)
1601490075Sobrien					      found)->labelno));
1601590075Sobrien	  return;
1601690075Sobrien	}
1601790075Sobrien    }
1601890075Sobrien
1601990075Sobrien  /* If we're going to put a double constant in the TOC, make sure it's
1602090075Sobrien     aligned properly when strict alignment is on.  */
1602190075Sobrien  if (GET_CODE (x) == CONST_DOUBLE
1602290075Sobrien      && STRICT_ALIGNMENT
1602390075Sobrien      && GET_MODE_BITSIZE (mode) >= 64
1602490075Sobrien      && ! (TARGET_NO_FP_IN_TOC && ! TARGET_MINIMAL_TOC)) {
1602590075Sobrien    ASM_OUTPUT_ALIGN (file, 3);
1602690075Sobrien  }
1602790075Sobrien
16028132718Skan  (*targetm.asm_out.internal_label) (file, "LC", labelno);
1602990075Sobrien
1603090075Sobrien  /* Handle FP constants specially.  Note that if we have a minimal
1603190075Sobrien     TOC, things we put here aren't actually in the TOC, so we can allow
1603290075Sobrien     FP constants.  */
16033169689Skan  if (GET_CODE (x) == CONST_DOUBLE &&
16034169689Skan      (GET_MODE (x) == TFmode || GET_MODE (x) == TDmode))
1603590075Sobrien    {
1603690075Sobrien      REAL_VALUE_TYPE rv;
16037117395Skan      long k[4];
16038117395Skan
16039117395Skan      REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
16040169689Skan      if (DECIMAL_FLOAT_MODE_P (GET_MODE (x)))
16041169689Skan	REAL_VALUE_TO_TARGET_DECIMAL128 (rv, k);
16042169689Skan      else
16043169689Skan	REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, k);
16044117395Skan
16045117395Skan      if (TARGET_64BIT)
16046117395Skan	{
16047117395Skan	  if (TARGET_MINIMAL_TOC)
16048117395Skan	    fputs (DOUBLE_INT_ASM_OP, file);
16049117395Skan	  else
16050117395Skan	    fprintf (file, "\t.tc FT_%lx_%lx_%lx_%lx[TC],",
16051117395Skan		     k[0] & 0xffffffff, k[1] & 0xffffffff,
16052117395Skan		     k[2] & 0xffffffff, k[3] & 0xffffffff);
16053117395Skan	  fprintf (file, "0x%lx%08lx,0x%lx%08lx\n",
16054117395Skan		   k[0] & 0xffffffff, k[1] & 0xffffffff,
16055117395Skan		   k[2] & 0xffffffff, k[3] & 0xffffffff);
16056117395Skan	  return;
16057117395Skan	}
16058117395Skan      else
16059117395Skan	{
16060117395Skan	  if (TARGET_MINIMAL_TOC)
16061117395Skan	    fputs ("\t.long ", file);
16062117395Skan	  else
16063117395Skan	    fprintf (file, "\t.tc FT_%lx_%lx_%lx_%lx[TC],",
16064117395Skan		     k[0] & 0xffffffff, k[1] & 0xffffffff,
16065117395Skan		     k[2] & 0xffffffff, k[3] & 0xffffffff);
16066117395Skan	  fprintf (file, "0x%lx,0x%lx,0x%lx,0x%lx\n",
16067117395Skan		   k[0] & 0xffffffff, k[1] & 0xffffffff,
16068117395Skan		   k[2] & 0xffffffff, k[3] & 0xffffffff);
16069117395Skan	  return;
16070117395Skan	}
16071117395Skan    }
16072169689Skan  else if (GET_CODE (x) == CONST_DOUBLE &&
16073169689Skan	   (GET_MODE (x) == DFmode || GET_MODE (x) == DDmode))
16074117395Skan    {
16075117395Skan      REAL_VALUE_TYPE rv;
1607690075Sobrien      long k[2];
1607790075Sobrien
1607890075Sobrien      REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
1607990075Sobrien
16080169689Skan      if (DECIMAL_FLOAT_MODE_P (GET_MODE (x)))
16081169689Skan	REAL_VALUE_TO_TARGET_DECIMAL64 (rv, k);
16082169689Skan      else
16083169689Skan	REAL_VALUE_TO_TARGET_DOUBLE (rv, k);
16084169689Skan
1608590075Sobrien      if (TARGET_64BIT)
1608690075Sobrien	{
1608790075Sobrien	  if (TARGET_MINIMAL_TOC)
1608890075Sobrien	    fputs (DOUBLE_INT_ASM_OP, file);
1608990075Sobrien	  else
16090102780Skan	    fprintf (file, "\t.tc FD_%lx_%lx[TC],",
16091102780Skan		     k[0] & 0xffffffff, k[1] & 0xffffffff);
16092102780Skan	  fprintf (file, "0x%lx%08lx\n",
16093102780Skan		   k[0] & 0xffffffff, k[1] & 0xffffffff);
1609490075Sobrien	  return;
1609590075Sobrien	}
1609690075Sobrien      else
1609790075Sobrien	{
1609890075Sobrien	  if (TARGET_MINIMAL_TOC)
1609990075Sobrien	    fputs ("\t.long ", file);
1610090075Sobrien	  else
16101102780Skan	    fprintf (file, "\t.tc FD_%lx_%lx[TC],",
16102102780Skan		     k[0] & 0xffffffff, k[1] & 0xffffffff);
16103102780Skan	  fprintf (file, "0x%lx,0x%lx\n",
16104102780Skan		   k[0] & 0xffffffff, k[1] & 0xffffffff);
1610590075Sobrien	  return;
1610690075Sobrien	}
1610790075Sobrien    }
16108169689Skan  else if (GET_CODE (x) == CONST_DOUBLE &&
16109169689Skan	   (GET_MODE (x) == SFmode || GET_MODE (x) == SDmode))
1611090075Sobrien    {
1611190075Sobrien      REAL_VALUE_TYPE rv;
1611290075Sobrien      long l;
1611390075Sobrien
1611490075Sobrien      REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
16115169689Skan      if (DECIMAL_FLOAT_MODE_P (GET_MODE (x)))
16116169689Skan	REAL_VALUE_TO_TARGET_DECIMAL32 (rv, l);
16117169689Skan      else
16118169689Skan	REAL_VALUE_TO_TARGET_SINGLE (rv, l);
1611990075Sobrien
1612090075Sobrien      if (TARGET_64BIT)
1612190075Sobrien	{
1612290075Sobrien	  if (TARGET_MINIMAL_TOC)
1612390075Sobrien	    fputs (DOUBLE_INT_ASM_OP, file);
1612490075Sobrien	  else
16125102780Skan	    fprintf (file, "\t.tc FS_%lx[TC],", l & 0xffffffff);
16126102780Skan	  fprintf (file, "0x%lx00000000\n", l & 0xffffffff);
1612790075Sobrien	  return;
1612890075Sobrien	}
1612990075Sobrien      else
1613090075Sobrien	{
1613190075Sobrien	  if (TARGET_MINIMAL_TOC)
1613290075Sobrien	    fputs ("\t.long ", file);
1613390075Sobrien	  else
16134102780Skan	    fprintf (file, "\t.tc FS_%lx[TC],", l & 0xffffffff);
16135102780Skan	  fprintf (file, "0x%lx\n", l & 0xffffffff);
1613690075Sobrien	  return;
1613790075Sobrien	}
1613890075Sobrien    }
1613990075Sobrien  else if (GET_MODE (x) == VOIDmode
1614090075Sobrien	   && (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE))
1614190075Sobrien    {
1614290075Sobrien      unsigned HOST_WIDE_INT low;
1614390075Sobrien      HOST_WIDE_INT high;
1614490075Sobrien
1614590075Sobrien      if (GET_CODE (x) == CONST_DOUBLE)
1614690075Sobrien	{
1614790075Sobrien	  low = CONST_DOUBLE_LOW (x);
1614890075Sobrien	  high = CONST_DOUBLE_HIGH (x);
1614990075Sobrien	}
1615090075Sobrien      else
1615190075Sobrien#if HOST_BITS_PER_WIDE_INT == 32
1615290075Sobrien	{
1615390075Sobrien	  low = INTVAL (x);
1615490075Sobrien	  high = (low & 0x80000000) ? ~0 : 0;
1615590075Sobrien	}
1615690075Sobrien#else
1615790075Sobrien	{
16158169689Skan	  low = INTVAL (x) & 0xffffffff;
16159169689Skan	  high = (HOST_WIDE_INT) INTVAL (x) >> 32;
1616090075Sobrien	}
1616190075Sobrien#endif
1616290075Sobrien
1616390075Sobrien      /* TOC entries are always Pmode-sized, but since this
1616490075Sobrien	 is a bigendian machine then if we're putting smaller
1616590075Sobrien	 integer constants in the TOC we have to pad them.
1616690075Sobrien	 (This is still a win over putting the constants in
1616790075Sobrien	 a separate constant pool, because then we'd have
1616890075Sobrien	 to have both a TOC entry _and_ the actual constant.)
1616990075Sobrien
1617090075Sobrien	 For a 32-bit target, CONST_INT values are loaded and shifted
1617190075Sobrien	 entirely within `low' and can be stored in one TOC entry.  */
1617290075Sobrien
16173169689Skan      /* It would be easy to make this work, but it doesn't now.  */
16174169689Skan      gcc_assert (!TARGET_64BIT || POINTER_SIZE >= GET_MODE_BITSIZE (mode));
1617590075Sobrien
1617690075Sobrien      if (POINTER_SIZE > GET_MODE_BITSIZE (mode))
16177103445Skan	{
16178103445Skan#if HOST_BITS_PER_WIDE_INT == 32
16179103445Skan	  lshift_double (low, high, POINTER_SIZE - GET_MODE_BITSIZE (mode),
16180103445Skan			 POINTER_SIZE, &low, &high, 0);
16181103445Skan#else
16182103445Skan	  low |= high << 32;
16183103445Skan	  low <<= POINTER_SIZE - GET_MODE_BITSIZE (mode);
16184103445Skan	  high = (HOST_WIDE_INT) low >> 32;
16185103445Skan	  low &= 0xffffffff;
16186103445Skan#endif
16187103445Skan	}
1618890075Sobrien
1618990075Sobrien      if (TARGET_64BIT)
1619090075Sobrien	{
1619190075Sobrien	  if (TARGET_MINIMAL_TOC)
1619290075Sobrien	    fputs (DOUBLE_INT_ASM_OP, file);
1619390075Sobrien	  else
16194102780Skan	    fprintf (file, "\t.tc ID_%lx_%lx[TC],",
16195102780Skan		     (long) high & 0xffffffff, (long) low & 0xffffffff);
16196102780Skan	  fprintf (file, "0x%lx%08lx\n",
16197102780Skan		   (long) high & 0xffffffff, (long) low & 0xffffffff);
1619890075Sobrien	  return;
1619990075Sobrien	}
1620090075Sobrien      else
1620190075Sobrien	{
1620290075Sobrien	  if (POINTER_SIZE < GET_MODE_BITSIZE (mode))
1620390075Sobrien	    {
1620490075Sobrien	      if (TARGET_MINIMAL_TOC)
1620590075Sobrien		fputs ("\t.long ", file);
1620690075Sobrien	      else
1620790075Sobrien		fprintf (file, "\t.tc ID_%lx_%lx[TC],",
16208102780Skan			 (long) high & 0xffffffff, (long) low & 0xffffffff);
16209102780Skan	      fprintf (file, "0x%lx,0x%lx\n",
16210102780Skan		       (long) high & 0xffffffff, (long) low & 0xffffffff);
1621190075Sobrien	    }
1621290075Sobrien	  else
1621390075Sobrien	    {
1621490075Sobrien	      if (TARGET_MINIMAL_TOC)
1621590075Sobrien		fputs ("\t.long ", file);
1621690075Sobrien	      else
16217102780Skan		fprintf (file, "\t.tc IS_%lx[TC],", (long) low & 0xffffffff);
16218102780Skan	      fprintf (file, "0x%lx\n", (long) low & 0xffffffff);
1621990075Sobrien	    }
1622090075Sobrien	  return;
1622190075Sobrien	}
1622290075Sobrien    }
1622390075Sobrien
1622490075Sobrien  if (GET_CODE (x) == CONST)
1622590075Sobrien    {
16226169689Skan      gcc_assert (GET_CODE (XEXP (x, 0)) == PLUS);
1622790075Sobrien
1622890075Sobrien      base = XEXP (XEXP (x, 0), 0);
1622990075Sobrien      offset = INTVAL (XEXP (XEXP (x, 0), 1));
1623090075Sobrien    }
1623190075Sobrien
16232169689Skan  switch (GET_CODE (base))
16233169689Skan    {
16234169689Skan    case SYMBOL_REF:
16235169689Skan      name = XSTR (base, 0);
16236169689Skan      break;
16237169689Skan
16238169689Skan    case LABEL_REF:
16239169689Skan      ASM_GENERATE_INTERNAL_LABEL (buf, "L",
16240169689Skan				   CODE_LABEL_NUMBER (XEXP (base, 0)));
16241169689Skan      break;
16242169689Skan
16243169689Skan    case CODE_LABEL:
16244169689Skan      ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (base));
16245169689Skan      break;
16246169689Skan
16247169689Skan    default:
16248169689Skan      gcc_unreachable ();
16249169689Skan    }
16250169689Skan
16251117395Skan  real_name = (*targetm.strip_name_encoding) (name);
1625290075Sobrien  if (TARGET_MINIMAL_TOC)
1625390075Sobrien    fputs (TARGET_32BIT ? "\t.long " : DOUBLE_INT_ASM_OP, file);
1625490075Sobrien  else
1625590075Sobrien    {
1625690075Sobrien      fprintf (file, "\t.tc %s", real_name);
1625790075Sobrien
1625890075Sobrien      if (offset < 0)
16259169689Skan	fprintf (file, ".N" HOST_WIDE_INT_PRINT_UNSIGNED, - offset);
1626090075Sobrien      else if (offset)
16261169689Skan	fprintf (file, ".P" HOST_WIDE_INT_PRINT_UNSIGNED, offset);
1626290075Sobrien
1626390075Sobrien      fputs ("[TC],", file);
1626490075Sobrien    }
1626590075Sobrien
1626690075Sobrien  /* Currently C++ toc references to vtables can be emitted before it
1626790075Sobrien     is decided whether the vtable is public or private.  If this is
1626890075Sobrien     the case, then the linker will eventually complain that there is
1626990075Sobrien     a TOC reference to an unknown section.  Thus, for vtables only,
1627090075Sobrien     we emit the TOC reference to reference the symbol and not the
1627190075Sobrien     section.  */
1627290075Sobrien  if (VTABLE_NAME_P (name))
1627390075Sobrien    {
1627490075Sobrien      RS6000_OUTPUT_BASENAME (file, name);
1627590075Sobrien      if (offset < 0)
16276169689Skan	fprintf (file, HOST_WIDE_INT_PRINT_DEC, offset);
1627790075Sobrien      else if (offset > 0)
16278169689Skan	fprintf (file, "+" HOST_WIDE_INT_PRINT_DEC, offset);
1627990075Sobrien    }
1628090075Sobrien  else
1628190075Sobrien    output_addr_const (file, x);
1628290075Sobrien  putc ('\n', file);
1628390075Sobrien}
1628490075Sobrien
1628590075Sobrien/* Output an assembler pseudo-op to write an ASCII string of N characters
1628690075Sobrien   starting at P to FILE.
1628790075Sobrien
1628890075Sobrien   On the RS/6000, we have to do this using the .byte operation and
1628990075Sobrien   write out special characters outside the quoted string.
1629090075Sobrien   Also, the assembler is broken; very long strings are truncated,
1629190075Sobrien   so we must artificially break them up early.  */
1629290075Sobrien
1629390075Sobrienvoid
16294132718Skanoutput_ascii (FILE *file, const char *p, int n)
1629590075Sobrien{
1629690075Sobrien  char c;
1629790075Sobrien  int i, count_string;
1629890075Sobrien  const char *for_string = "\t.byte \"";
1629990075Sobrien  const char *for_decimal = "\t.byte ";
1630090075Sobrien  const char *to_close = NULL;
1630190075Sobrien
1630290075Sobrien  count_string = 0;
1630390075Sobrien  for (i = 0; i < n; i++)
1630490075Sobrien    {
1630590075Sobrien      c = *p++;
1630690075Sobrien      if (c >= ' ' && c < 0177)
1630790075Sobrien	{
1630890075Sobrien	  if (for_string)
1630990075Sobrien	    fputs (for_string, file);
1631090075Sobrien	  putc (c, file);
1631190075Sobrien
1631290075Sobrien	  /* Write two quotes to get one.  */
1631390075Sobrien	  if (c == '"')
1631490075Sobrien	    {
1631590075Sobrien	      putc (c, file);
1631690075Sobrien	      ++count_string;
1631790075Sobrien	    }
1631890075Sobrien
1631990075Sobrien	  for_string = NULL;
1632090075Sobrien	  for_decimal = "\"\n\t.byte ";
1632190075Sobrien	  to_close = "\"\n";
1632290075Sobrien	  ++count_string;
1632390075Sobrien
1632490075Sobrien	  if (count_string >= 512)
1632590075Sobrien	    {
1632690075Sobrien	      fputs (to_close, file);
1632790075Sobrien
1632890075Sobrien	      for_string = "\t.byte \"";
1632990075Sobrien	      for_decimal = "\t.byte ";
1633090075Sobrien	      to_close = NULL;
1633190075Sobrien	      count_string = 0;
1633290075Sobrien	    }
1633390075Sobrien	}
1633490075Sobrien      else
1633590075Sobrien	{
1633690075Sobrien	  if (for_decimal)
1633790075Sobrien	    fputs (for_decimal, file);
1633890075Sobrien	  fprintf (file, "%d", c);
1633990075Sobrien
1634090075Sobrien	  for_string = "\n\t.byte \"";
1634190075Sobrien	  for_decimal = ", ";
1634290075Sobrien	  to_close = "\n";
1634390075Sobrien	  count_string = 0;
1634490075Sobrien	}
1634590075Sobrien    }
1634690075Sobrien
1634790075Sobrien  /* Now close the string if we have written one.  Then end the line.  */
1634890075Sobrien  if (to_close)
1634990075Sobrien    fputs (to_close, file);
1635090075Sobrien}
1635190075Sobrien
1635290075Sobrien/* Generate a unique section name for FILENAME for a section type
1635390075Sobrien   represented by SECTION_DESC.  Output goes into BUF.
1635490075Sobrien
1635590075Sobrien   SECTION_DESC can be any string, as long as it is different for each
1635690075Sobrien   possible section type.
1635790075Sobrien
1635890075Sobrien   We name the section in the same manner as xlc.  The name begins with an
1635990075Sobrien   underscore followed by the filename (after stripping any leading directory
1636090075Sobrien   names) with the last period replaced by the string SECTION_DESC.  If
1636190075Sobrien   FILENAME does not contain a period, SECTION_DESC is appended to the end of
1636290075Sobrien   the name.  */
1636390075Sobrien
1636490075Sobrienvoid
16365169689Skanrs6000_gen_section_name (char **buf, const char *filename,
16366169689Skan			 const char *section_desc)
1636790075Sobrien{
1636890075Sobrien  const char *q, *after_last_slash, *last_period = 0;
1636990075Sobrien  char *p;
1637090075Sobrien  int len;
1637190075Sobrien
1637290075Sobrien  after_last_slash = filename;
1637390075Sobrien  for (q = filename; *q; q++)
1637490075Sobrien    {
1637590075Sobrien      if (*q == '/')
1637690075Sobrien	after_last_slash = q + 1;
1637790075Sobrien      else if (*q == '.')
1637890075Sobrien	last_period = q;
1637990075Sobrien    }
1638090075Sobrien
1638190075Sobrien  len = strlen (after_last_slash) + strlen (section_desc) + 2;
16382117395Skan  *buf = (char *) xmalloc (len);
1638390075Sobrien
1638490075Sobrien  p = *buf;
1638590075Sobrien  *p++ = '_';
1638690075Sobrien
1638790075Sobrien  for (q = after_last_slash; *q; q++)
1638890075Sobrien    {
1638990075Sobrien      if (q == last_period)
16390169689Skan	{
1639190075Sobrien	  strcpy (p, section_desc);
1639290075Sobrien	  p += strlen (section_desc);
16393132718Skan	  break;
16394169689Skan	}
1639590075Sobrien
1639690075Sobrien      else if (ISALNUM (*q))
16397169689Skan	*p++ = *q;
1639890075Sobrien    }
1639990075Sobrien
1640090075Sobrien  if (last_period == 0)
1640190075Sobrien    strcpy (p, section_desc);
1640290075Sobrien  else
1640390075Sobrien    *p = '\0';
1640490075Sobrien}
1640590075Sobrien
1640690075Sobrien/* Emit profile function.  */
1640790075Sobrien
1640890075Sobrienvoid
16409132718Skanoutput_profile_hook (int labelno ATTRIBUTE_UNUSED)
1641090075Sobrien{
16411169689Skan  /* Non-standard profiling for kernels, which just saves LR then calls
16412169689Skan     _mcount without worrying about arg saves.  The idea is to change
16413169689Skan     the function prologue as little as possible as it isn't easy to
16414169689Skan     account for arg save/restore code added just for _mcount.  */
16415132718Skan  if (TARGET_PROFILE_KERNEL)
16416132718Skan    return;
16417132718Skan
1641890075Sobrien  if (DEFAULT_ABI == ABI_AIX)
1641990075Sobrien    {
16420132718Skan#ifndef NO_PROFILE_COUNTERS
16421132718Skan# define NO_PROFILE_COUNTERS 0
16422132718Skan#endif
16423169689Skan      if (NO_PROFILE_COUNTERS)
16424132718Skan	emit_library_call (init_one_libfunc (RS6000_MCOUNT), 0, VOIDmode, 0);
16425132718Skan      else
16426132718Skan	{
16427132718Skan	  char buf[30];
16428132718Skan	  const char *label_name;
16429132718Skan	  rtx fun;
1643090075Sobrien
16431132718Skan	  ASM_GENERATE_INTERNAL_LABEL (buf, "LP", labelno);
16432132718Skan	  label_name = (*targetm.strip_name_encoding) (ggc_strdup (buf));
16433132718Skan	  fun = gen_rtx_SYMBOL_REF (Pmode, label_name);
1643490075Sobrien
16435132718Skan	  emit_library_call (init_one_libfunc (RS6000_MCOUNT), 0, VOIDmode, 1,
16436132718Skan			     fun, Pmode);
16437132718Skan	}
1643890075Sobrien    }
1643990075Sobrien  else if (DEFAULT_ABI == ABI_DARWIN)
1644090075Sobrien    {
1644190075Sobrien      const char *mcount_name = RS6000_MCOUNT;
1644290075Sobrien      int caller_addr_regno = LINK_REGISTER_REGNUM;
1644390075Sobrien
1644490075Sobrien      /* Be conservative and always set this, at least for now.  */
1644590075Sobrien      current_function_uses_pic_offset_table = 1;
1644690075Sobrien
1644790075Sobrien#if TARGET_MACHO
1644890075Sobrien      /* For PIC code, set up a stub and collect the caller's address
1644990075Sobrien	 from r0, which is where the prologue puts it.  */
16450169689Skan      if (MACHOPIC_INDIRECT
16451169689Skan	  && current_function_uses_pic_offset_table)
16452169689Skan	caller_addr_regno = 0;
1645390075Sobrien#endif
1645490075Sobrien      emit_library_call (gen_rtx_SYMBOL_REF (Pmode, mcount_name),
1645590075Sobrien			 0, VOIDmode, 1,
1645690075Sobrien			 gen_rtx_REG (Pmode, caller_addr_regno), Pmode);
1645790075Sobrien    }
1645890075Sobrien}
1645990075Sobrien
1646090075Sobrien/* Write function profiler code.  */
1646190075Sobrien
1646290075Sobrienvoid
16463132718Skanoutput_function_profiler (FILE *file, int labelno)
1646490075Sobrien{
1646590075Sobrien  char buf[100];
1646690075Sobrien
1646790075Sobrien  switch (DEFAULT_ABI)
1646890075Sobrien    {
1646990075Sobrien    default:
16470169689Skan      gcc_unreachable ();
1647190075Sobrien
1647290075Sobrien    case ABI_V4:
16473103445Skan      if (!TARGET_32BIT)
16474103445Skan	{
16475169689Skan	  warning (0, "no profiling of 64-bit code for this ABI");
16476103445Skan	  return;
16477103445Skan	}
16478132718Skan      ASM_GENERATE_INTERNAL_LABEL (buf, "LP", labelno);
1647990075Sobrien      fprintf (file, "\tmflr %s\n", reg_names[0]);
16480169689Skan      if (NO_PROFILE_COUNTERS)
1648190075Sobrien	{
16482169689Skan	  asm_fprintf (file, "\t{st|stw} %s,4(%s)\n",
16483169689Skan		       reg_names[0], reg_names[1]);
16484169689Skan	}
16485169689Skan      else if (TARGET_SECURE_PLT && flag_pic)
16486169689Skan	{
16487169689Skan	  asm_fprintf (file, "\tbcl 20,31,1f\n1:\n\t{st|stw} %s,4(%s)\n",
16488169689Skan		       reg_names[0], reg_names[1]);
16489169689Skan	  asm_fprintf (file, "\tmflr %s\n", reg_names[12]);
16490169689Skan	  asm_fprintf (file, "\t{cau|addis} %s,%s,",
16491169689Skan		       reg_names[12], reg_names[12]);
16492169689Skan	  assemble_name (file, buf);
16493169689Skan	  asm_fprintf (file, "-1b@ha\n\t{cal|la} %s,", reg_names[0]);
16494169689Skan	  assemble_name (file, buf);
16495169689Skan	  asm_fprintf (file, "-1b@l(%s)\n", reg_names[12]);
16496169689Skan	}
16497169689Skan      else if (flag_pic == 1)
16498169689Skan	{
1649990075Sobrien	  fputs ("\tbl _GLOBAL_OFFSET_TABLE_@local-4\n", file);
16500169689Skan	  asm_fprintf (file, "\t{st|stw} %s,4(%s)\n",
16501169689Skan		       reg_names[0], reg_names[1]);
1650290075Sobrien	  asm_fprintf (file, "\tmflr %s\n", reg_names[12]);
1650390075Sobrien	  asm_fprintf (file, "\t{l|lwz} %s,", reg_names[0]);
1650490075Sobrien	  assemble_name (file, buf);
1650590075Sobrien	  asm_fprintf (file, "@got(%s)\n", reg_names[12]);
1650690075Sobrien	}
1650790075Sobrien      else if (flag_pic > 1)
1650890075Sobrien	{
16509169689Skan	  asm_fprintf (file, "\t{st|stw} %s,4(%s)\n",
16510169689Skan		       reg_names[0], reg_names[1]);
1651190075Sobrien	  /* Now, we need to get the address of the label.  */
16512169689Skan	  fputs ("\tbcl 20,31,1f\n\t.long ", file);
1651390075Sobrien	  assemble_name (file, buf);
1651490075Sobrien	  fputs ("-.\n1:", file);
1651590075Sobrien	  asm_fprintf (file, "\tmflr %s\n", reg_names[11]);
16516169689Skan	  asm_fprintf (file, "\t{l|lwz} %s,0(%s)\n",
1651790075Sobrien		       reg_names[0], reg_names[11]);
1651890075Sobrien	  asm_fprintf (file, "\t{cax|add} %s,%s,%s\n",
1651990075Sobrien		       reg_names[0], reg_names[0], reg_names[11]);
1652090075Sobrien	}
1652190075Sobrien      else
1652290075Sobrien	{
1652390075Sobrien	  asm_fprintf (file, "\t{liu|lis} %s,", reg_names[12]);
1652490075Sobrien	  assemble_name (file, buf);
1652590075Sobrien	  fputs ("@ha\n", file);
16526169689Skan	  asm_fprintf (file, "\t{st|stw} %s,4(%s)\n",
16527169689Skan		       reg_names[0], reg_names[1]);
1652890075Sobrien	  asm_fprintf (file, "\t{cal|la} %s,", reg_names[0]);
1652990075Sobrien	  assemble_name (file, buf);
1653090075Sobrien	  asm_fprintf (file, "@l(%s)\n", reg_names[12]);
1653190075Sobrien	}
1653290075Sobrien
16533132718Skan      /* ABI_V4 saves the static chain reg with ASM_OUTPUT_REG_PUSH.  */
16534132718Skan      fprintf (file, "\tbl %s%s\n",
16535132718Skan	       RS6000_MCOUNT, flag_pic ? "@plt" : "");
16536132718Skan      break;
16537132718Skan
16538132718Skan    case ABI_AIX:
16539132718Skan    case ABI_DARWIN:
16540132718Skan      if (!TARGET_PROFILE_KERNEL)
16541103445Skan	{
16542132718Skan	  /* Don't do anything, done in output_profile_hook ().  */
16543103445Skan	}
16544103445Skan      else
16545132718Skan	{
16546169689Skan	  gcc_assert (!TARGET_32BIT);
1654790075Sobrien
16548132718Skan	  asm_fprintf (file, "\tmflr %s\n", reg_names[0]);
16549132718Skan	  asm_fprintf (file, "\tstd %s,16(%s)\n", reg_names[0], reg_names[1]);
16550132718Skan
16551169689Skan	  if (cfun->static_chain_decl != NULL)
16552132718Skan	    {
16553132718Skan	      asm_fprintf (file, "\tstd %s,24(%s)\n",
16554132718Skan			   reg_names[STATIC_CHAIN_REGNUM], reg_names[1]);
16555132718Skan	      fprintf (file, "\tbl %s\n", RS6000_MCOUNT);
16556132718Skan	      asm_fprintf (file, "\tld %s,24(%s)\n",
16557132718Skan			   reg_names[STATIC_CHAIN_REGNUM], reg_names[1]);
16558132718Skan	    }
16559132718Skan	  else
16560132718Skan	    fprintf (file, "\tbl %s\n", RS6000_MCOUNT);
16561132718Skan	}
1656290075Sobrien      break;
1656390075Sobrien    }
1656490075Sobrien}
1656590075Sobrien
16566132718Skan
16567132718Skan/* Power4 load update and store update instructions are cracked into a
16568132718Skan   load or store and an integer insn which are executed in the same cycle.
16569132718Skan   Branches have their own dispatch slot which does not count against the
16570132718Skan   GCC issue rate, but it changes the program flow so there are no other
16571132718Skan   instructions to issue in this cycle.  */
16572132718Skan
16573132718Skanstatic int
16574169689Skanrs6000_variable_issue (FILE *stream ATTRIBUTE_UNUSED,
16575169689Skan		       int verbose ATTRIBUTE_UNUSED,
16576132718Skan		       rtx insn, int more)
16577132718Skan{
16578132718Skan  if (GET_CODE (PATTERN (insn)) == USE
16579132718Skan      || GET_CODE (PATTERN (insn)) == CLOBBER)
16580132718Skan    return more;
16581132718Skan
16582132718Skan  if (rs6000_sched_groups)
16583132718Skan    {
16584132718Skan      if (is_microcoded_insn (insn))
16585169689Skan	return 0;
16586132718Skan      else if (is_cracked_insn (insn))
16587169689Skan	return more > 2 ? more - 2 : 0;
16588132718Skan    }
16589132718Skan
16590132718Skan  return more - 1;
16591132718Skan}
16592132718Skan
1659390075Sobrien/* Adjust the cost of a scheduling dependency.  Return the new cost of
1659490075Sobrien   a dependency LINK or INSN on DEP_INSN.  COST is the current cost.  */
1659590075Sobrien
1659690075Sobrienstatic int
16597169689Skanrs6000_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
1659890075Sobrien{
1659990075Sobrien  if (! recog_memoized (insn))
1660090075Sobrien    return 0;
1660190075Sobrien
1660290075Sobrien  if (REG_NOTE_KIND (link) != 0)
1660390075Sobrien    return 0;
1660490075Sobrien
1660590075Sobrien  if (REG_NOTE_KIND (link) == 0)
1660690075Sobrien    {
1660790075Sobrien      /* Data dependency; DEP_INSN writes a register that INSN reads
1660890075Sobrien	 some cycles later.  */
16609169689Skan
16610169689Skan      /* Separate a load from a narrower, dependent store.  */
16611169689Skan      if (rs6000_sched_groups
16612169689Skan	  && GET_CODE (PATTERN (insn)) == SET
16613169689Skan	  && GET_CODE (PATTERN (dep_insn)) == SET
16614169689Skan	  && GET_CODE (XEXP (PATTERN (insn), 1)) == MEM
16615169689Skan	  && GET_CODE (XEXP (PATTERN (dep_insn), 0)) == MEM
16616169689Skan	  && (GET_MODE_SIZE (GET_MODE (XEXP (PATTERN (insn), 1)))
16617169689Skan	      > GET_MODE_SIZE (GET_MODE (XEXP (PATTERN (dep_insn), 0)))))
16618169689Skan	return cost + 14;
16619169689Skan
1662090075Sobrien      switch (get_attr_type (insn))
1662190075Sobrien	{
1662290075Sobrien	case TYPE_JMPREG:
16623117395Skan	  /* Tell the first scheduling pass about the latency between
1662490075Sobrien	     a mtctr and bctr (and mtlr and br/blr).  The first
1662590075Sobrien	     scheduling pass will not know about this latency since
1662690075Sobrien	     the mtctr instruction, which has the latency associated
1662790075Sobrien	     to it, will be generated by reload.  */
16628117395Skan	  return TARGET_POWER ? 5 : 4;
1662990075Sobrien	case TYPE_BRANCH:
1663090075Sobrien	  /* Leave some extra cycles between a compare and its
1663190075Sobrien	     dependent branch, to inhibit expensive mispredicts.  */
16632117395Skan	  if ((rs6000_cpu_attr == CPU_PPC603
16633117395Skan	       || rs6000_cpu_attr == CPU_PPC604
16634117395Skan	       || rs6000_cpu_attr == CPU_PPC604E
16635117395Skan	       || rs6000_cpu_attr == CPU_PPC620
16636117395Skan	       || rs6000_cpu_attr == CPU_PPC630
16637117395Skan	       || rs6000_cpu_attr == CPU_PPC750
16638117395Skan	       || rs6000_cpu_attr == CPU_PPC7400
16639117395Skan	       || rs6000_cpu_attr == CPU_PPC7450
16640132718Skan	       || rs6000_cpu_attr == CPU_POWER4
16641132718Skan	       || rs6000_cpu_attr == CPU_POWER5)
1664290075Sobrien	      && recog_memoized (dep_insn)
1664390075Sobrien	      && (INSN_CODE (dep_insn) >= 0)
16644132718Skan	      && (get_attr_type (dep_insn) == TYPE_CMP
16645132718Skan		  || get_attr_type (dep_insn) == TYPE_COMPARE
1664690075Sobrien		  || get_attr_type (dep_insn) == TYPE_DELAYED_COMPARE
16647132718Skan		  || get_attr_type (dep_insn) == TYPE_IMUL_COMPARE
16648132718Skan		  || get_attr_type (dep_insn) == TYPE_LMUL_COMPARE
1664990075Sobrien		  || get_attr_type (dep_insn) == TYPE_FPCOMPARE
16650132718Skan		  || get_attr_type (dep_insn) == TYPE_CR_LOGICAL
16651132718Skan		  || get_attr_type (dep_insn) == TYPE_DELAYED_CR))
1665290075Sobrien	    return cost + 2;
1665390075Sobrien	default:
1665490075Sobrien	  break;
1665590075Sobrien	}
1665690075Sobrien      /* Fall out to return default cost.  */
1665790075Sobrien    }
1665890075Sobrien
1665990075Sobrien  return cost;
1666090075Sobrien}
1666190075Sobrien
16662132718Skan/* The function returns a true if INSN is microcoded.
16663132718Skan   Return false otherwise.  */
16664132718Skan
16665132718Skanstatic bool
16666132718Skanis_microcoded_insn (rtx insn)
16667132718Skan{
16668132718Skan  if (!insn || !INSN_P (insn)
16669132718Skan      || GET_CODE (PATTERN (insn)) == USE
16670132718Skan      || GET_CODE (PATTERN (insn)) == CLOBBER)
16671132718Skan    return false;
16672132718Skan
16673132718Skan  if (rs6000_sched_groups)
16674132718Skan    {
16675132718Skan      enum attr_type type = get_attr_type (insn);
16676132718Skan      if (type == TYPE_LOAD_EXT_U
16677132718Skan	  || type == TYPE_LOAD_EXT_UX
16678132718Skan	  || type == TYPE_LOAD_UX
16679132718Skan	  || type == TYPE_STORE_UX
16680132718Skan	  || type == TYPE_MFCR)
16681169689Skan	return true;
16682132718Skan    }
16683132718Skan
16684132718Skan  return false;
16685132718Skan}
16686132718Skan
16687132718Skan/* The function returns a nonzero value if INSN can be scheduled only
16688132718Skan   as the first insn in a dispatch group ("dispatch-slot restricted").
16689132718Skan   In this case, the returned value indicates how many dispatch slots
16690132718Skan   the insn occupies (at the beginning of the group).
16691132718Skan   Return 0 otherwise.  */
16692132718Skan
16693132718Skanstatic int
16694132718Skanis_dispatch_slot_restricted (rtx insn)
16695132718Skan{
16696132718Skan  enum attr_type type;
16697132718Skan
16698132718Skan  if (!rs6000_sched_groups)
16699132718Skan    return 0;
16700132718Skan
16701132718Skan  if (!insn
16702132718Skan      || insn == NULL_RTX
16703132718Skan      || GET_CODE (insn) == NOTE
16704132718Skan      || GET_CODE (PATTERN (insn)) == USE
16705132718Skan      || GET_CODE (PATTERN (insn)) == CLOBBER)
16706132718Skan    return 0;
16707132718Skan
16708132718Skan  type = get_attr_type (insn);
16709132718Skan
16710132718Skan  switch (type)
16711132718Skan    {
16712132718Skan    case TYPE_MFCR:
16713132718Skan    case TYPE_MFCRF:
16714132718Skan    case TYPE_MTCR:
16715132718Skan    case TYPE_DELAYED_CR:
16716132718Skan    case TYPE_CR_LOGICAL:
16717132718Skan    case TYPE_MTJMPR:
16718132718Skan    case TYPE_MFJMPR:
16719132718Skan      return 1;
16720132718Skan    case TYPE_IDIV:
16721132718Skan    case TYPE_LDIV:
16722132718Skan      return 2;
16723169689Skan    case TYPE_LOAD_L:
16724169689Skan    case TYPE_STORE_C:
16725169689Skan    case TYPE_ISYNC:
16726169689Skan    case TYPE_SYNC:
16727169689Skan      return 4;
16728132718Skan    default:
16729132718Skan      if (rs6000_cpu == PROCESSOR_POWER5
16730132718Skan	  && is_cracked_insn (insn))
16731132718Skan	return 2;
16732132718Skan      return 0;
16733132718Skan    }
16734132718Skan}
16735132718Skan
16736132718Skan/* The function returns true if INSN is cracked into 2 instructions
16737132718Skan   by the processor (and therefore occupies 2 issue slots).  */
16738132718Skan
16739132718Skanstatic bool
16740132718Skanis_cracked_insn (rtx insn)
16741132718Skan{
16742132718Skan  if (!insn || !INSN_P (insn)
16743132718Skan      || GET_CODE (PATTERN (insn)) == USE
16744132718Skan      || GET_CODE (PATTERN (insn)) == CLOBBER)
16745132718Skan    return false;
16746132718Skan
16747132718Skan  if (rs6000_sched_groups)
16748132718Skan    {
16749132718Skan      enum attr_type type = get_attr_type (insn);
16750132718Skan      if (type == TYPE_LOAD_U || type == TYPE_STORE_U
16751169689Skan	  || type == TYPE_FPLOAD_U || type == TYPE_FPSTORE_U
16752169689Skan	  || type == TYPE_FPLOAD_UX || type == TYPE_FPSTORE_UX
16753169689Skan	  || type == TYPE_LOAD_EXT || type == TYPE_DELAYED_CR
16754169689Skan	  || type == TYPE_COMPARE || type == TYPE_DELAYED_COMPARE
16755169689Skan	  || type == TYPE_IMUL_COMPARE || type == TYPE_LMUL_COMPARE
16756169689Skan	  || type == TYPE_IDIV || type == TYPE_LDIV
16757169689Skan	  || type == TYPE_INSERT_WORD)
16758169689Skan	return true;
16759132718Skan    }
16760132718Skan
16761132718Skan  return false;
16762132718Skan}
16763132718Skan
16764132718Skan/* The function returns true if INSN can be issued only from
16765132718Skan   the branch slot.  */
16766132718Skan
16767132718Skanstatic bool
16768132718Skanis_branch_slot_insn (rtx insn)
16769132718Skan{
16770132718Skan  if (!insn || !INSN_P (insn)
16771132718Skan      || GET_CODE (PATTERN (insn)) == USE
16772132718Skan      || GET_CODE (PATTERN (insn)) == CLOBBER)
16773132718Skan    return false;
16774132718Skan
16775132718Skan  if (rs6000_sched_groups)
16776132718Skan    {
16777132718Skan      enum attr_type type = get_attr_type (insn);
16778132718Skan      if (type == TYPE_BRANCH || type == TYPE_JMPREG)
16779169689Skan	return true;
16780132718Skan      return false;
16781132718Skan    }
16782132718Skan
16783132718Skan  return false;
16784132718Skan}
16785132718Skan
1678690075Sobrien/* A C statement (sans semicolon) to update the integer scheduling
16787132718Skan   priority INSN_PRIORITY (INSN). Increase the priority to execute the
16788132718Skan   INSN earlier, reduce the priority to execute INSN later.  Do not
1678990075Sobrien   define this macro if you do not need to adjust the scheduling
1679090075Sobrien   priorities of insns.  */
1679190075Sobrien
1679290075Sobrienstatic int
16793132718Skanrs6000_adjust_priority (rtx insn ATTRIBUTE_UNUSED, int priority)
1679490075Sobrien{
1679590075Sobrien  /* On machines (like the 750) which have asymmetric integer units,
1679690075Sobrien     where one integer unit can do multiply and divides and the other
1679790075Sobrien     can't, reduce the priority of multiply/divide so it is scheduled
1679890075Sobrien     before other integer operations.  */
1679990075Sobrien
1680090075Sobrien#if 0
1680190075Sobrien  if (! INSN_P (insn))
1680290075Sobrien    return priority;
1680390075Sobrien
1680490075Sobrien  if (GET_CODE (PATTERN (insn)) == USE)
1680590075Sobrien    return priority;
1680690075Sobrien
1680790075Sobrien  switch (rs6000_cpu_attr) {
1680890075Sobrien  case CPU_PPC750:
1680990075Sobrien    switch (get_attr_type (insn))
1681090075Sobrien      {
1681190075Sobrien      default:
1681290075Sobrien	break;
1681390075Sobrien
1681490075Sobrien      case TYPE_IMUL:
1681590075Sobrien      case TYPE_IDIV:
1681690075Sobrien	fprintf (stderr, "priority was %#x (%d) before adjustment\n",
1681790075Sobrien		 priority, priority);
1681890075Sobrien	if (priority >= 0 && priority < 0x01000000)
1681990075Sobrien	  priority >>= 3;
1682090075Sobrien	break;
1682190075Sobrien      }
1682290075Sobrien  }
1682390075Sobrien#endif
1682490075Sobrien
16825132718Skan  if (is_dispatch_slot_restricted (insn)
16826132718Skan      && reload_completed
16827169689Skan      && current_sched_info->sched_max_insns_priority
16828132718Skan      && rs6000_sched_restricted_insns_priority)
16829132718Skan    {
16830132718Skan
16831169689Skan      /* Prioritize insns that can be dispatched only in the first
16832169689Skan	 dispatch slot.  */
16833132718Skan      if (rs6000_sched_restricted_insns_priority == 1)
16834169689Skan	/* Attach highest priority to insn. This means that in
16835169689Skan	   haifa-sched.c:ready_sort(), dispatch-slot restriction considerations
16836132718Skan	   precede 'priority' (critical path) considerations.  */
16837169689Skan	return current_sched_info->sched_max_insns_priority;
16838132718Skan      else if (rs6000_sched_restricted_insns_priority == 2)
16839169689Skan	/* Increase priority of insn by a minimal amount. This means that in
16840169689Skan	   haifa-sched.c:ready_sort(), only 'priority' (critical path)
16841169689Skan	   considerations precede dispatch-slot restriction considerations.  */
16842169689Skan	return (priority + 1);
16843169689Skan    }
16844132718Skan
1684590075Sobrien  return priority;
1684690075Sobrien}
1684790075Sobrien
1684890075Sobrien/* Return how many instructions the machine can issue per cycle.  */
1684990075Sobrien
1685090075Sobrienstatic int
16851132718Skanrs6000_issue_rate (void)
1685290075Sobrien{
16853132718Skan  /* Use issue rate of 1 for first scheduling pass to decrease degradation.  */
16854132718Skan  if (!reload_completed)
16855132718Skan    return 1;
16856132718Skan
1685790075Sobrien  switch (rs6000_cpu_attr) {
1685890075Sobrien  case CPU_RIOS1:  /* ? */
1685990075Sobrien  case CPU_RS64A:
1686090075Sobrien  case CPU_PPC601: /* ? */
1686190075Sobrien  case CPU_PPC7450:
1686290075Sobrien    return 3;
16863132718Skan  case CPU_PPC440:
1686490075Sobrien  case CPU_PPC603:
1686590075Sobrien  case CPU_PPC750:
1686690075Sobrien  case CPU_PPC7400:
16867132718Skan  case CPU_PPC8540:
16868169689Skan    return 2;
1686990075Sobrien  case CPU_RIOS2:
1687090075Sobrien  case CPU_PPC604:
1687190075Sobrien  case CPU_PPC604E:
1687290075Sobrien  case CPU_PPC620:
1687390075Sobrien  case CPU_PPC630:
16874132718Skan    return 4;
16875117395Skan  case CPU_POWER4:
16876132718Skan  case CPU_POWER5:
16877132718Skan    return 5;
1687890075Sobrien  default:
1687990075Sobrien    return 1;
1688090075Sobrien  }
1688190075Sobrien}
1688290075Sobrien
16883132718Skan/* Return how many instructions to look ahead for better insn
16884132718Skan   scheduling.  */
16885132718Skan
16886132718Skanstatic int
16887132718Skanrs6000_use_sched_lookahead (void)
16888132718Skan{
16889132718Skan  if (rs6000_cpu_attr == CPU_PPC8540)
16890132718Skan    return 4;
16891132718Skan  return 0;
16892132718Skan}
16893132718Skan
16894132718Skan/* Determine is PAT refers to memory.  */
16895132718Skan
16896132718Skanstatic bool
16897132718Skanis_mem_ref (rtx pat)
16898132718Skan{
16899132718Skan  const char * fmt;
16900132718Skan  int i, j;
16901132718Skan  bool ret = false;
16902132718Skan
16903132718Skan  if (GET_CODE (pat) == MEM)
16904132718Skan    return true;
16905132718Skan
16906132718Skan  /* Recursively process the pattern.  */
16907132718Skan  fmt = GET_RTX_FORMAT (GET_CODE (pat));
16908132718Skan
16909132718Skan  for (i = GET_RTX_LENGTH (GET_CODE (pat)) - 1; i >= 0 && !ret; i--)
16910132718Skan    {
16911132718Skan      if (fmt[i] == 'e')
16912132718Skan	ret |= is_mem_ref (XEXP (pat, i));
16913132718Skan      else if (fmt[i] == 'E')
16914132718Skan	for (j = XVECLEN (pat, i) - 1; j >= 0; j--)
16915132718Skan	  ret |= is_mem_ref (XVECEXP (pat, i, j));
16916132718Skan    }
16917132718Skan
16918132718Skan  return ret;
16919132718Skan}
16920132718Skan
16921132718Skan/* Determine if PAT is a PATTERN of a load insn.  */
16922169689Skan
16923132718Skanstatic bool
16924132718Skanis_load_insn1 (rtx pat)
16925132718Skan{
16926132718Skan  if (!pat || pat == NULL_RTX)
16927132718Skan    return false;
16928132718Skan
16929132718Skan  if (GET_CODE (pat) == SET)
16930132718Skan    return is_mem_ref (SET_SRC (pat));
16931132718Skan
16932132718Skan  if (GET_CODE (pat) == PARALLEL)
16933132718Skan    {
16934132718Skan      int i;
16935132718Skan
16936132718Skan      for (i = 0; i < XVECLEN (pat, 0); i++)
16937132718Skan	if (is_load_insn1 (XVECEXP (pat, 0, i)))
16938132718Skan	  return true;
16939132718Skan    }
16940132718Skan
16941132718Skan  return false;
16942132718Skan}
16943132718Skan
16944132718Skan/* Determine if INSN loads from memory.  */
16945132718Skan
16946132718Skanstatic bool
16947132718Skanis_load_insn (rtx insn)
16948132718Skan{
16949132718Skan  if (!insn || !INSN_P (insn))
16950132718Skan    return false;
16951132718Skan
16952132718Skan  if (GET_CODE (insn) == CALL_INSN)
16953132718Skan    return false;
16954132718Skan
16955132718Skan  return is_load_insn1 (PATTERN (insn));
16956132718Skan}
16957132718Skan
16958132718Skan/* Determine if PAT is a PATTERN of a store insn.  */
16959132718Skan
16960132718Skanstatic bool
16961132718Skanis_store_insn1 (rtx pat)
16962132718Skan{
16963132718Skan  if (!pat || pat == NULL_RTX)
16964132718Skan    return false;
16965132718Skan
16966132718Skan  if (GET_CODE (pat) == SET)
16967132718Skan    return is_mem_ref (SET_DEST (pat));
16968132718Skan
16969132718Skan  if (GET_CODE (pat) == PARALLEL)
16970132718Skan    {
16971132718Skan      int i;
16972132718Skan
16973132718Skan      for (i = 0; i < XVECLEN (pat, 0); i++)
16974132718Skan	if (is_store_insn1 (XVECEXP (pat, 0, i)))
16975132718Skan	  return true;
16976132718Skan    }
16977132718Skan
16978132718Skan  return false;
16979132718Skan}
16980132718Skan
16981132718Skan/* Determine if INSN stores to memory.  */
16982132718Skan
16983132718Skanstatic bool
16984132718Skanis_store_insn (rtx insn)
16985132718Skan{
16986132718Skan  if (!insn || !INSN_P (insn))
16987132718Skan    return false;
16988132718Skan
16989132718Skan  return is_store_insn1 (PATTERN (insn));
16990132718Skan}
16991132718Skan
16992132718Skan/* Returns whether the dependence between INSN and NEXT is considered
16993132718Skan   costly by the given target.  */
16994132718Skan
16995132718Skanstatic bool
16996169689Skanrs6000_is_costly_dependence (rtx insn, rtx next, rtx link, int cost,
16997169689Skan			     int distance)
16998169689Skan{
16999169689Skan  /* If the flag is not enabled - no dependence is considered costly;
17000169689Skan     allow all dependent insns in the same group.
17001132718Skan     This is the most aggressive option.  */
17002132718Skan  if (rs6000_sched_costly_dep == no_dep_costly)
17003132718Skan    return false;
17004132718Skan
17005169689Skan  /* If the flag is set to 1 - a dependence is always considered costly;
17006132718Skan     do not allow dependent instructions in the same group.
17007132718Skan     This is the most conservative option.  */
17008132718Skan  if (rs6000_sched_costly_dep == all_deps_costly)
17009169689Skan    return true;
17010132718Skan
17011169689Skan  if (rs6000_sched_costly_dep == store_to_load_dep_costly
17012169689Skan      && is_load_insn (next)
17013132718Skan      && is_store_insn (insn))
17014132718Skan    /* Prevent load after store in the same group.  */
17015132718Skan    return true;
17016132718Skan
17017132718Skan  if (rs6000_sched_costly_dep == true_store_to_load_dep_costly
17018169689Skan      && is_load_insn (next)
17019132718Skan      && is_store_insn (insn)
17020132718Skan      && (!link || (int) REG_NOTE_KIND (link) == 0))
17021169689Skan     /* Prevent load after store in the same group if it is a true
17022169689Skan	dependence.  */
17023132718Skan     return true;
17024169689Skan
17025169689Skan  /* The flag is set to X; dependences with latency >= X are considered costly,
17026132718Skan     and will not be scheduled in the same group.  */
17027132718Skan  if (rs6000_sched_costly_dep <= max_dep_latency
17028132718Skan      && ((cost - distance) >= (int)rs6000_sched_costly_dep))
17029132718Skan    return true;
17030132718Skan
17031132718Skan  return false;
17032132718Skan}
17033132718Skan
17034169689Skan/* Return the next insn after INSN that is found before TAIL is reached,
17035132718Skan   skipping any "non-active" insns - insns that will not actually occupy
17036132718Skan   an issue slot.  Return NULL_RTX if such an insn is not found.  */
17037132718Skan
17038132718Skanstatic rtx
17039132718Skanget_next_active_insn (rtx insn, rtx tail)
17040132718Skan{
17041169689Skan  if (insn == NULL_RTX || insn == tail)
17042132718Skan    return NULL_RTX;
17043132718Skan
17044169689Skan  while (1)
17045169689Skan    {
17046169689Skan      insn = NEXT_INSN (insn);
17047169689Skan      if (insn == NULL_RTX || insn == tail)
17048169689Skan	return NULL_RTX;
17049132718Skan
17050169689Skan      if (CALL_P (insn)
17051169689Skan	  || JUMP_P (insn)
17052169689Skan	  || (NONJUMP_INSN_P (insn)
17053169689Skan	      && GET_CODE (PATTERN (insn)) != USE
17054169689Skan	      && GET_CODE (PATTERN (insn)) != CLOBBER
17055169689Skan	      && INSN_CODE (insn) != CODE_FOR_stack_tie))
17056169689Skan	break;
17057132718Skan    }
17058169689Skan  return insn;
17059132718Skan}
17060132718Skan
17061132718Skan/* Return whether the presence of INSN causes a dispatch group termination
17062132718Skan   of group WHICH_GROUP.
17063132718Skan
17064132718Skan   If WHICH_GROUP == current_group, this function will return true if INSN
17065132718Skan   causes the termination of the current group (i.e, the dispatch group to
17066132718Skan   which INSN belongs). This means that INSN will be the last insn in the
17067132718Skan   group it belongs to.
17068132718Skan
17069132718Skan   If WHICH_GROUP == previous_group, this function will return true if INSN
17070132718Skan   causes the termination of the previous group (i.e, the dispatch group that
17071132718Skan   precedes the group to which INSN belongs).  This means that INSN will be
17072132718Skan   the first insn in the group it belongs to).  */
17073132718Skan
17074132718Skanstatic bool
17075132718Skaninsn_terminates_group_p (rtx insn, enum group_termination which_group)
17076132718Skan{
17077132718Skan  enum attr_type type;
17078132718Skan
17079132718Skan  if (! insn)
17080132718Skan    return false;
17081132718Skan
17082132718Skan  type = get_attr_type (insn);
17083132718Skan
17084132718Skan  if (is_microcoded_insn (insn))
17085132718Skan    return true;
17086132718Skan
17087132718Skan  if (which_group == current_group)
17088132718Skan    {
17089132718Skan      if (is_branch_slot_insn (insn))
17090169689Skan	return true;
17091132718Skan      return false;
17092132718Skan    }
17093132718Skan  else if (which_group == previous_group)
17094132718Skan    {
17095132718Skan      if (is_dispatch_slot_restricted (insn))
17096169689Skan	return true;
17097132718Skan      return false;
17098132718Skan    }
17099132718Skan
17100132718Skan  return false;
17101132718Skan}
17102132718Skan
17103132718Skan/* Return true if it is recommended to keep NEXT_INSN "far" (in a separate
17104132718Skan   dispatch group) from the insns in GROUP_INSNS.  Return false otherwise.  */
17105132718Skan
17106132718Skanstatic bool
17107132718Skanis_costly_group (rtx *group_insns, rtx next_insn)
17108132718Skan{
17109132718Skan  int i;
17110132718Skan  rtx link;
17111132718Skan  int cost;
17112132718Skan  int issue_rate = rs6000_issue_rate ();
17113132718Skan
17114132718Skan  for (i = 0; i < issue_rate; i++)
17115132718Skan    {
17116132718Skan      rtx insn = group_insns[i];
17117132718Skan      if (!insn)
17118169689Skan	continue;
17119132718Skan      for (link = INSN_DEPEND (insn); link != 0; link = XEXP (link, 1))
17120169689Skan	{
17121169689Skan	  rtx next = XEXP (link, 0);
17122169689Skan	  if (next == next_insn)
17123169689Skan	    {
17124169689Skan	      cost = insn_cost (insn, link, next_insn);
17125169689Skan	      if (rs6000_is_costly_dependence (insn, next_insn, link, cost, 0))
17126169689Skan		return true;
17127169689Skan	    }
17128169689Skan	}
17129132718Skan    }
17130132718Skan
17131132718Skan  return false;
17132132718Skan}
17133132718Skan
17134169689Skan/* Utility of the function redefine_groups.
17135132718Skan   Check if it is too costly to schedule NEXT_INSN together with GROUP_INSNS
17136132718Skan   in the same dispatch group.  If so, insert nops before NEXT_INSN, in order
17137132718Skan   to keep it "far" (in a separate group) from GROUP_INSNS, following
17138132718Skan   one of the following schemes, depending on the value of the flag
17139132718Skan   -minsert_sched_nops = X:
17140132718Skan   (1) X == sched_finish_regroup_exact: insert exactly as many nops as needed
17141132718Skan       in order to force NEXT_INSN into a separate group.
17142169689Skan   (2) X < sched_finish_regroup_exact: insert exactly X nops.
17143169689Skan   GROUP_END, CAN_ISSUE_MORE and GROUP_COUNT record the state after nop
17144132718Skan   insertion (has a group just ended, how many vacant issue slots remain in the
17145132718Skan   last group, and how many dispatch groups were encountered so far).  */
17146132718Skan
17147169689Skanstatic int
17148169689Skanforce_new_group (int sched_verbose, FILE *dump, rtx *group_insns,
17149169689Skan		 rtx next_insn, bool *group_end, int can_issue_more,
17150169689Skan		 int *group_count)
17151132718Skan{
17152132718Skan  rtx nop;
17153132718Skan  bool force;
17154132718Skan  int issue_rate = rs6000_issue_rate ();
17155132718Skan  bool end = *group_end;
17156132718Skan  int i;
17157132718Skan
17158132718Skan  if (next_insn == NULL_RTX)
17159132718Skan    return can_issue_more;
17160132718Skan
17161132718Skan  if (rs6000_sched_insert_nops > sched_finish_regroup_exact)
17162132718Skan    return can_issue_more;
17163132718Skan
17164132718Skan  force = is_costly_group (group_insns, next_insn);
17165132718Skan  if (!force)
17166132718Skan    return can_issue_more;
17167132718Skan
17168132718Skan  if (sched_verbose > 6)
17169132718Skan    fprintf (dump,"force: group count = %d, can_issue_more = %d\n",
17170169689Skan	     *group_count ,can_issue_more);
17171132718Skan
17172132718Skan  if (rs6000_sched_insert_nops == sched_finish_regroup_exact)
17173132718Skan    {
17174132718Skan      if (*group_end)
17175169689Skan	can_issue_more = 0;
17176132718Skan
17177132718Skan      /* Since only a branch can be issued in the last issue_slot, it is
17178132718Skan	 sufficient to insert 'can_issue_more - 1' nops if next_insn is not
17179132718Skan	 a branch. If next_insn is a branch, we insert 'can_issue_more' nops;
17180169689Skan	 in this case the last nop will start a new group and the branch
17181169689Skan	 will be forced to the new group.  */
17182132718Skan      if (can_issue_more && !is_branch_slot_insn (next_insn))
17183169689Skan	can_issue_more--;
17184132718Skan
17185132718Skan      while (can_issue_more > 0)
17186169689Skan	{
17187169689Skan	  nop = gen_nop ();
17188169689Skan	  emit_insn_before (nop, next_insn);
17189169689Skan	  can_issue_more--;
17190169689Skan	}
17191132718Skan
17192132718Skan      *group_end = true;
17193132718Skan      return 0;
17194169689Skan    }
17195132718Skan
17196132718Skan  if (rs6000_sched_insert_nops < sched_finish_regroup_exact)
17197132718Skan    {
17198132718Skan      int n_nops = rs6000_sched_insert_nops;
17199132718Skan
17200169689Skan      /* Nops can't be issued from the branch slot, so the effective
17201169689Skan	 issue_rate for nops is 'issue_rate - 1'.  */
17202132718Skan      if (can_issue_more == 0)
17203169689Skan	can_issue_more = issue_rate;
17204132718Skan      can_issue_more--;
17205132718Skan      if (can_issue_more == 0)
17206169689Skan	{
17207169689Skan	  can_issue_more = issue_rate - 1;
17208169689Skan	  (*group_count)++;
17209169689Skan	  end = true;
17210169689Skan	  for (i = 0; i < issue_rate; i++)
17211169689Skan	    {
17212169689Skan	      group_insns[i] = 0;
17213169689Skan	    }
17214169689Skan	}
17215132718Skan
17216132718Skan      while (n_nops > 0)
17217169689Skan	{
17218169689Skan	  nop = gen_nop ();
17219169689Skan	  emit_insn_before (nop, next_insn);
17220169689Skan	  if (can_issue_more == issue_rate - 1) /* new group begins */
17221169689Skan	    end = false;
17222169689Skan	  can_issue_more--;
17223169689Skan	  if (can_issue_more == 0)
17224169689Skan	    {
17225169689Skan	      can_issue_more = issue_rate - 1;
17226169689Skan	      (*group_count)++;
17227169689Skan	      end = true;
17228169689Skan	      for (i = 0; i < issue_rate; i++)
17229169689Skan		{
17230169689Skan		  group_insns[i] = 0;
17231169689Skan		}
17232169689Skan	    }
17233169689Skan	  n_nops--;
17234169689Skan	}
17235132718Skan
17236132718Skan      /* Scale back relative to 'issue_rate' (instead of 'issue_rate - 1').  */
17237169689Skan      can_issue_more++;
17238132718Skan
17239169689Skan      /* Is next_insn going to start a new group?  */
17240169689Skan      *group_end
17241169689Skan	= (end
17242132718Skan	   || (can_issue_more == 1 && !is_branch_slot_insn (next_insn))
17243132718Skan	   || (can_issue_more <= 2 && is_cracked_insn (next_insn))
17244132718Skan	   || (can_issue_more < issue_rate &&
17245169689Skan	       insn_terminates_group_p (next_insn, previous_group)));
17246132718Skan      if (*group_end && end)
17247169689Skan	(*group_count)--;
17248132718Skan
17249132718Skan      if (sched_verbose > 6)
17250169689Skan	fprintf (dump, "done force: group count = %d, can_issue_more = %d\n",
17251169689Skan		 *group_count, can_issue_more);
17252169689Skan      return can_issue_more;
17253169689Skan    }
17254132718Skan
17255132718Skan  return can_issue_more;
17256132718Skan}
17257132718Skan
17258132718Skan/* This function tries to synch the dispatch groups that the compiler "sees"
17259169689Skan   with the dispatch groups that the processor dispatcher is expected to
17260132718Skan   form in practice.  It tries to achieve this synchronization by forcing the
17261132718Skan   estimated processor grouping on the compiler (as opposed to the function
17262132718Skan   'pad_goups' which tries to force the scheduler's grouping on the processor).
17263132718Skan
17264132718Skan   The function scans the insn sequence between PREV_HEAD_INSN and TAIL and
17265132718Skan   examines the (estimated) dispatch groups that will be formed by the processor
17266132718Skan   dispatcher.  It marks these group boundaries to reflect the estimated
17267132718Skan   processor grouping, overriding the grouping that the scheduler had marked.
17268132718Skan   Depending on the value of the flag '-minsert-sched-nops' this function can
17269132718Skan   force certain insns into separate groups or force a certain distance between
17270132718Skan   them by inserting nops, for example, if there exists a "costly dependence"
17271132718Skan   between the insns.
17272132718Skan
17273132718Skan   The function estimates the group boundaries that the processor will form as
17274169689Skan   follows:  It keeps track of how many vacant issue slots are available after
17275132718Skan   each insn.  A subsequent insn will start a new group if one of the following
17276132718Skan   4 cases applies:
17277132718Skan   - no more vacant issue slots remain in the current dispatch group.
17278132718Skan   - only the last issue slot, which is the branch slot, is vacant, but the next
17279132718Skan     insn is not a branch.
17280132718Skan   - only the last 2 or less issue slots, including the branch slot, are vacant,
17281132718Skan     which means that a cracked insn (which occupies two issue slots) can't be
17282132718Skan     issued in this group.
17283169689Skan   - less than 'issue_rate' slots are vacant, and the next insn always needs to
17284132718Skan     start a new group.  */
17285132718Skan
17286132718Skanstatic int
17287132718Skanredefine_groups (FILE *dump, int sched_verbose, rtx prev_head_insn, rtx tail)
17288132718Skan{
17289132718Skan  rtx insn, next_insn;
17290132718Skan  int issue_rate;
17291132718Skan  int can_issue_more;
17292132718Skan  int slot, i;
17293132718Skan  bool group_end;
17294132718Skan  int group_count = 0;
17295132718Skan  rtx *group_insns;
17296132718Skan
17297132718Skan  /* Initialize.  */
17298132718Skan  issue_rate = rs6000_issue_rate ();
17299132718Skan  group_insns = alloca (issue_rate * sizeof (rtx));
17300169689Skan  for (i = 0; i < issue_rate; i++)
17301132718Skan    {
17302132718Skan      group_insns[i] = 0;
17303132718Skan    }
17304132718Skan  can_issue_more = issue_rate;
17305132718Skan  slot = 0;
17306132718Skan  insn = get_next_active_insn (prev_head_insn, tail);
17307132718Skan  group_end = false;
17308132718Skan
17309132718Skan  while (insn != NULL_RTX)
17310132718Skan    {
17311132718Skan      slot = (issue_rate - can_issue_more);
17312132718Skan      group_insns[slot] = insn;
17313132718Skan      can_issue_more =
17314169689Skan	rs6000_variable_issue (dump, sched_verbose, insn, can_issue_more);
17315132718Skan      if (insn_terminates_group_p (insn, current_group))
17316169689Skan	can_issue_more = 0;
17317132718Skan
17318132718Skan      next_insn = get_next_active_insn (insn, tail);
17319132718Skan      if (next_insn == NULL_RTX)
17320169689Skan	return group_count + 1;
17321132718Skan
17322169689Skan      /* Is next_insn going to start a new group?  */
17323169689Skan      group_end
17324169689Skan	= (can_issue_more == 0
17325169689Skan	   || (can_issue_more == 1 && !is_branch_slot_insn (next_insn))
17326169689Skan	   || (can_issue_more <= 2 && is_cracked_insn (next_insn))
17327169689Skan	   || (can_issue_more < issue_rate &&
17328169689Skan	       insn_terminates_group_p (next_insn, previous_group)));
17329132718Skan
17330169689Skan      can_issue_more = force_new_group (sched_verbose, dump, group_insns,
17331169689Skan					next_insn, &group_end, can_issue_more,
17332169689Skan					&group_count);
17333132718Skan
17334132718Skan      if (group_end)
17335169689Skan	{
17336169689Skan	  group_count++;
17337169689Skan	  can_issue_more = 0;
17338169689Skan	  for (i = 0; i < issue_rate; i++)
17339169689Skan	    {
17340169689Skan	      group_insns[i] = 0;
17341169689Skan	    }
17342169689Skan	}
17343132718Skan
17344132718Skan      if (GET_MODE (next_insn) == TImode && can_issue_more)
17345169689Skan	PUT_MODE (next_insn, VOIDmode);
17346132718Skan      else if (!can_issue_more && GET_MODE (next_insn) != TImode)
17347169689Skan	PUT_MODE (next_insn, TImode);
17348132718Skan
17349132718Skan      insn = next_insn;
17350132718Skan      if (can_issue_more == 0)
17351169689Skan	can_issue_more = issue_rate;
17352169689Skan    } /* while */
17353132718Skan
17354132718Skan  return group_count;
17355132718Skan}
17356132718Skan
17357132718Skan/* Scan the insn sequence between PREV_HEAD_INSN and TAIL and examine the
17358132718Skan   dispatch group boundaries that the scheduler had marked.  Pad with nops
17359132718Skan   any dispatch groups which have vacant issue slots, in order to force the
17360132718Skan   scheduler's grouping on the processor dispatcher.  The function
17361132718Skan   returns the number of dispatch groups found.  */
17362132718Skan
17363132718Skanstatic int
17364132718Skanpad_groups (FILE *dump, int sched_verbose, rtx prev_head_insn, rtx tail)
17365132718Skan{
17366132718Skan  rtx insn, next_insn;
17367132718Skan  rtx nop;
17368132718Skan  int issue_rate;
17369132718Skan  int can_issue_more;
17370132718Skan  int group_end;
17371132718Skan  int group_count = 0;
17372132718Skan
17373132718Skan  /* Initialize issue_rate.  */
17374132718Skan  issue_rate = rs6000_issue_rate ();
17375132718Skan  can_issue_more = issue_rate;
17376132718Skan
17377132718Skan  insn = get_next_active_insn (prev_head_insn, tail);
17378132718Skan  next_insn = get_next_active_insn (insn, tail);
17379132718Skan
17380132718Skan  while (insn != NULL_RTX)
17381132718Skan    {
17382132718Skan      can_issue_more =
17383132718Skan      	rs6000_variable_issue (dump, sched_verbose, insn, can_issue_more);
17384132718Skan
17385132718Skan      group_end = (next_insn == NULL_RTX || GET_MODE (next_insn) == TImode);
17386132718Skan
17387132718Skan      if (next_insn == NULL_RTX)
17388169689Skan	break;
17389132718Skan
17390132718Skan      if (group_end)
17391169689Skan	{
17392169689Skan	  /* If the scheduler had marked group termination at this location
17393169689Skan	     (between insn and next_indn), and neither insn nor next_insn will
17394169689Skan	     force group termination, pad the group with nops to force group
17395169689Skan	     termination.  */
17396169689Skan	  if (can_issue_more
17397169689Skan	      && (rs6000_sched_insert_nops == sched_finish_pad_groups)
17398169689Skan	      && !insn_terminates_group_p (insn, current_group)
17399169689Skan	      && !insn_terminates_group_p (next_insn, previous_group))
17400169689Skan	    {
17401169689Skan	      if (!is_branch_slot_insn (next_insn))
17402169689Skan		can_issue_more--;
17403132718Skan
17404169689Skan	      while (can_issue_more)
17405169689Skan		{
17406169689Skan		  nop = gen_nop ();
17407169689Skan		  emit_insn_before (nop, next_insn);
17408169689Skan		  can_issue_more--;
17409169689Skan		}
17410169689Skan	    }
17411132718Skan
17412169689Skan	  can_issue_more = issue_rate;
17413169689Skan	  group_count++;
17414169689Skan	}
17415132718Skan
17416132718Skan      insn = next_insn;
17417132718Skan      next_insn = get_next_active_insn (insn, tail);
17418132718Skan    }
17419132718Skan
17420132718Skan  return group_count;
17421132718Skan}
17422132718Skan
17423132718Skan/* The following function is called at the end of scheduling BB.
17424132718Skan   After reload, it inserts nops at insn group bundling.  */
17425132718Skan
17426132718Skanstatic void
17427132718Skanrs6000_sched_finish (FILE *dump, int sched_verbose)
17428132718Skan{
17429132718Skan  int n_groups;
17430132718Skan
17431132718Skan  if (sched_verbose)
17432132718Skan    fprintf (dump, "=== Finishing schedule.\n");
17433132718Skan
17434132718Skan  if (reload_completed && rs6000_sched_groups)
17435132718Skan    {
17436132718Skan      if (rs6000_sched_insert_nops == sched_finish_none)
17437169689Skan	return;
17438132718Skan
17439132718Skan      if (rs6000_sched_insert_nops == sched_finish_pad_groups)
17440169689Skan	n_groups = pad_groups (dump, sched_verbose,
17441169689Skan			       current_sched_info->prev_head,
17442169689Skan			       current_sched_info->next_tail);
17443132718Skan      else
17444169689Skan	n_groups = redefine_groups (dump, sched_verbose,
17445169689Skan				    current_sched_info->prev_head,
17446169689Skan				    current_sched_info->next_tail);
17447132718Skan
17448132718Skan      if (sched_verbose >= 6)
17449132718Skan	{
17450132718Skan    	  fprintf (dump, "ngroups = %d\n", n_groups);
17451132718Skan	  print_rtl (dump, current_sched_info->prev_head);
17452132718Skan	  fprintf (dump, "Done finish_sched\n");
17453132718Skan	}
17454132718Skan    }
17455132718Skan}
1745690075Sobrien
1745790075Sobrien/* Length in units of the trampoline for entering a nested function.  */
1745890075Sobrien
1745990075Sobrienint
17460132718Skanrs6000_trampoline_size (void)
1746190075Sobrien{
1746290075Sobrien  int ret = 0;
1746390075Sobrien
1746490075Sobrien  switch (DEFAULT_ABI)
1746590075Sobrien    {
1746690075Sobrien    default:
17467169689Skan      gcc_unreachable ();
1746890075Sobrien
1746990075Sobrien    case ABI_AIX:
1747090075Sobrien      ret = (TARGET_32BIT) ? 12 : 24;
1747190075Sobrien      break;
1747290075Sobrien
1747390075Sobrien    case ABI_DARWIN:
1747490075Sobrien    case ABI_V4:
1747590075Sobrien      ret = (TARGET_32BIT) ? 40 : 48;
1747690075Sobrien      break;
1747790075Sobrien    }
1747890075Sobrien
1747990075Sobrien  return ret;
1748090075Sobrien}
1748190075Sobrien
1748290075Sobrien/* Emit RTL insns to initialize the variable parts of a trampoline.
1748390075Sobrien   FNADDR is an RTX for the address of the function's pure code.
1748490075Sobrien   CXT is an RTX for the static chain value for the function.  */
1748590075Sobrien
1748690075Sobrienvoid
17487132718Skanrs6000_initialize_trampoline (rtx addr, rtx fnaddr, rtx cxt)
1748890075Sobrien{
1748990075Sobrien  int regsize = (TARGET_32BIT) ? 4 : 8;
17490169689Skan  rtx ctx_reg = force_reg (Pmode, cxt);
1749190075Sobrien
1749290075Sobrien  switch (DEFAULT_ABI)
1749390075Sobrien    {
1749490075Sobrien    default:
17495169689Skan      gcc_unreachable ();
1749690075Sobrien
1749790075Sobrien/* Macros to shorten the code expansions below.  */
17498169689Skan#define MEM_DEREF(addr) gen_rtx_MEM (Pmode, memory_address (Pmode, addr))
1749990075Sobrien#define MEM_PLUS(addr,offset) \
17500169689Skan  gen_rtx_MEM (Pmode, memory_address (Pmode, plus_constant (addr, offset)))
1750190075Sobrien
1750290075Sobrien    /* Under AIX, just build the 3 word function descriptor */
1750390075Sobrien    case ABI_AIX:
1750490075Sobrien      {
17505169689Skan	rtx fn_reg = gen_reg_rtx (Pmode);
17506169689Skan	rtx toc_reg = gen_reg_rtx (Pmode);
1750790075Sobrien	emit_move_insn (fn_reg, MEM_DEREF (fnaddr));
1750890075Sobrien	emit_move_insn (toc_reg, MEM_PLUS (fnaddr, regsize));
1750990075Sobrien	emit_move_insn (MEM_DEREF (addr), fn_reg);
1751090075Sobrien	emit_move_insn (MEM_PLUS (addr, regsize), toc_reg);
1751190075Sobrien	emit_move_insn (MEM_PLUS (addr, 2*regsize), ctx_reg);
1751290075Sobrien      }
1751390075Sobrien      break;
1751490075Sobrien
1751590075Sobrien    /* Under V.4/eabi/darwin, __trampoline_setup does the real work.  */
1751690075Sobrien    case ABI_DARWIN:
1751790075Sobrien    case ABI_V4:
17518169689Skan      emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__trampoline_setup"),
1751990075Sobrien			 FALSE, VOIDmode, 4,
17520169689Skan			 addr, Pmode,
1752190075Sobrien			 GEN_INT (rs6000_trampoline_size ()), SImode,
17522169689Skan			 fnaddr, Pmode,
17523169689Skan			 ctx_reg, Pmode);
1752490075Sobrien      break;
1752590075Sobrien    }
1752690075Sobrien
1752790075Sobrien  return;
1752890075Sobrien}
1752990075Sobrien
1753090075Sobrien
1753190075Sobrien/* Table of valid machine attributes.  */
1753290075Sobrien
1753390075Sobrienconst struct attribute_spec rs6000_attribute_table[] =
1753490075Sobrien{
1753590075Sobrien  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
17536146895Skan  { "altivec",   1, 1, false, true,  false, rs6000_handle_altivec_attribute },
17537117395Skan  { "longcall",  0, 0, false, true,  true,  rs6000_handle_longcall_attribute },
17538117395Skan  { "shortcall", 0, 0, false, true,  true,  rs6000_handle_longcall_attribute },
17539169689Skan  { "ms_struct", 0, 0, false, false, false, rs6000_handle_struct_attribute },
17540169689Skan  { "gcc_struct", 0, 0, false, false, false, rs6000_handle_struct_attribute },
17541169689Skan#ifdef SUBTARGET_ATTRIBUTE_TABLE
17542169689Skan  SUBTARGET_ATTRIBUTE_TABLE,
17543169689Skan#endif
17544117395Skan  { NULL,        0, 0, false, false, false, NULL }
1754590075Sobrien};
1754690075Sobrien
17547146895Skan/* Handle the "altivec" attribute.  The attribute may have
17548146895Skan   arguments as follows:
17549146895Skan
17550169689Skan	__attribute__((altivec(vector__)))
17551169689Skan	__attribute__((altivec(pixel__)))	(always followed by 'unsigned short')
17552169689Skan	__attribute__((altivec(bool__)))	(always followed by 'unsigned')
17553146895Skan
17554146895Skan  and may appear more than once (e.g., 'vector bool char') in a
17555146895Skan  given declaration.  */
17556146895Skan
17557146895Skanstatic tree
17558169689Skanrs6000_handle_altivec_attribute (tree *node,
17559169689Skan				 tree name ATTRIBUTE_UNUSED,
17560169689Skan				 tree args,
17561146895Skan				 int flags ATTRIBUTE_UNUSED,
17562146895Skan				 bool *no_add_attrs)
17563146895Skan{
17564146895Skan  tree type = *node, result = NULL_TREE;
17565146895Skan  enum machine_mode mode;
17566146895Skan  int unsigned_p;
17567146895Skan  char altivec_type
17568146895Skan    = ((args && TREE_CODE (args) == TREE_LIST && TREE_VALUE (args)
17569169689Skan	&& TREE_CODE (TREE_VALUE (args)) == IDENTIFIER_NODE)
17570146895Skan       ? *IDENTIFIER_POINTER (TREE_VALUE (args))
17571146895Skan       : '?');
17572146895Skan
17573146895Skan  while (POINTER_TYPE_P (type)
17574146895Skan	 || TREE_CODE (type) == FUNCTION_TYPE
17575146895Skan	 || TREE_CODE (type) == METHOD_TYPE
17576146895Skan	 || TREE_CODE (type) == ARRAY_TYPE)
17577146895Skan    type = TREE_TYPE (type);
17578146895Skan
17579146895Skan  mode = TYPE_MODE (type);
17580146895Skan
17581169689Skan  /* Check for invalid AltiVec type qualifiers.  */
17582169689Skan  if (type == long_unsigned_type_node || type == long_integer_type_node)
17583169689Skan    {
17584169689Skan    if (TARGET_64BIT)
17585169689Skan      error ("use of %<long%> in AltiVec types is invalid for 64-bit code");
17586169689Skan    else if (rs6000_warn_altivec_long)
17587169689Skan      warning (0, "use of %<long%> in AltiVec types is deprecated; use %<int%>");
17588169689Skan    }
17589169689Skan  else if (type == long_long_unsigned_type_node
17590169689Skan           || type == long_long_integer_type_node)
17591169689Skan    error ("use of %<long long%> in AltiVec types is invalid");
17592169689Skan  else if (type == double_type_node)
17593169689Skan    error ("use of %<double%> in AltiVec types is invalid");
17594169689Skan  else if (type == long_double_type_node)
17595169689Skan    error ("use of %<long double%> in AltiVec types is invalid");
17596169689Skan  else if (type == boolean_type_node)
17597169689Skan    error ("use of boolean types in AltiVec types is invalid");
17598169689Skan  else if (TREE_CODE (type) == COMPLEX_TYPE)
17599169689Skan    error ("use of %<complex%> in AltiVec types is invalid");
17600169689Skan  else if (DECIMAL_FLOAT_MODE_P (mode))
17601169689Skan    error ("use of decimal floating point types in AltiVec types is invalid");
17602146895Skan
17603146895Skan  switch (altivec_type)
17604146895Skan    {
17605146895Skan    case 'v':
17606169689Skan      unsigned_p = TYPE_UNSIGNED (type);
17607146895Skan      switch (mode)
17608146895Skan	{
17609169689Skan	case SImode:
17610169689Skan	  result = (unsigned_p ? unsigned_V4SI_type_node : V4SI_type_node);
17611169689Skan	  break;
17612169689Skan	case HImode:
17613169689Skan	  result = (unsigned_p ? unsigned_V8HI_type_node : V8HI_type_node);
17614169689Skan	  break;
17615169689Skan	case QImode:
17616169689Skan	  result = (unsigned_p ? unsigned_V16QI_type_node : V16QI_type_node);
17617169689Skan	  break;
17618169689Skan	case SFmode: result = V4SF_type_node; break;
17619169689Skan	  /* If the user says 'vector int bool', we may be handed the 'bool'
17620169689Skan	     attribute _before_ the 'vector' attribute, and so select the
17621169689Skan	     proper type in the 'b' case below.  */
17622169689Skan	case V4SImode: case V8HImode: case V16QImode: case V4SFmode:
17623169689Skan	  result = type;
17624169689Skan	default: break;
17625146895Skan	}
17626146895Skan      break;
17627146895Skan    case 'b':
17628146895Skan      switch (mode)
17629146895Skan	{
17630169689Skan	case SImode: case V4SImode: result = bool_V4SI_type_node; break;
17631169689Skan	case HImode: case V8HImode: result = bool_V8HI_type_node; break;
17632169689Skan	case QImode: case V16QImode: result = bool_V16QI_type_node;
17633169689Skan	default: break;
17634146895Skan	}
17635146895Skan      break;
17636146895Skan    case 'p':
17637146895Skan      switch (mode)
17638146895Skan	{
17639169689Skan	case V8HImode: result = pixel_V8HI_type_node;
17640169689Skan	default: break;
17641146895Skan	}
17642146895Skan    default: break;
17643146895Skan    }
17644146895Skan
17645146895Skan  if (result && result != type && TYPE_READONLY (type))
17646146895Skan    result = build_qualified_type (result, TYPE_QUAL_CONST);
17647146895Skan
17648146895Skan  *no_add_attrs = true;  /* No need to hang on to the attribute.  */
17649146895Skan
17650169689Skan  if (result)
17651146895Skan    *node = reconstruct_complex_type (*node, result);
17652146895Skan
17653146895Skan  return NULL_TREE;
17654146895Skan}
17655146895Skan
17656146895Skan/* AltiVec defines four built-in scalar types that serve as vector
17657146895Skan   elements; we must teach the compiler how to mangle them.  */
17658146895Skan
17659146895Skanstatic const char *
17660146895Skanrs6000_mangle_fundamental_type (tree type)
17661146895Skan{
17662146895Skan  if (type == bool_char_type_node) return "U6__boolc";
17663146895Skan  if (type == bool_short_type_node) return "U6__bools";
17664146895Skan  if (type == pixel_type_node) return "u7__pixel";
17665146895Skan  if (type == bool_int_type_node) return "U6__booli";
17666146895Skan
17667169689Skan  /* Mangle IBM extended float long double as `g' (__float128) on
17668169689Skan     powerpc*-linux where long-double-64 previously was the default.  */
17669169689Skan  if (TYPE_MAIN_VARIANT (type) == long_double_type_node
17670169689Skan      && TARGET_ELF
17671169689Skan      && TARGET_LONG_DOUBLE_128
17672169689Skan      && !TARGET_IEEEQUAD)
17673169689Skan    return "g";
17674169689Skan
17675146895Skan  /* For all other types, use normal C++ mangling.  */
17676146895Skan  return NULL;
17677146895Skan}
17678146895Skan
17679117395Skan/* Handle a "longcall" or "shortcall" attribute; arguments as in
17680117395Skan   struct attribute_spec.handler.  */
1768190075Sobrien
1768290075Sobrienstatic tree
17683169689Skanrs6000_handle_longcall_attribute (tree *node, tree name,
17684169689Skan				  tree args ATTRIBUTE_UNUSED,
17685169689Skan				  int flags ATTRIBUTE_UNUSED,
17686132718Skan				  bool *no_add_attrs)
1768790075Sobrien{
1768890075Sobrien  if (TREE_CODE (*node) != FUNCTION_TYPE
1768990075Sobrien      && TREE_CODE (*node) != FIELD_DECL
1769090075Sobrien      && TREE_CODE (*node) != TYPE_DECL)
1769190075Sobrien    {
17692169689Skan      warning (OPT_Wattributes, "%qs attribute only applies to functions",
1769390075Sobrien	       IDENTIFIER_POINTER (name));
1769490075Sobrien      *no_add_attrs = true;
1769590075Sobrien    }
1769690075Sobrien
1769790075Sobrien  return NULL_TREE;
1769890075Sobrien}
1769990075Sobrien
17700117395Skan/* Set longcall attributes on all functions declared when
17701117395Skan   rs6000_default_long_calls is true.  */
17702117395Skanstatic void
17703132718Skanrs6000_set_default_type_attributes (tree type)
17704117395Skan{
17705117395Skan  if (rs6000_default_long_calls
17706117395Skan      && (TREE_CODE (type) == FUNCTION_TYPE
17707117395Skan	  || TREE_CODE (type) == METHOD_TYPE))
17708117395Skan    TYPE_ATTRIBUTES (type) = tree_cons (get_identifier ("longcall"),
17709117395Skan					NULL_TREE,
17710117395Skan					TYPE_ATTRIBUTES (type));
17711169689Skan
17712169689Skan#if TARGET_MACHO
17713169689Skan  darwin_set_default_type_attributes (type);
17714169689Skan#endif
17715117395Skan}
17716117395Skan
1771790075Sobrien/* Return a reference suitable for calling a function with the
1771890075Sobrien   longcall attribute.  */
1771990075Sobrien
17720169689Skanrtx
17721132718Skanrs6000_longcall_ref (rtx call_ref)
1772290075Sobrien{
1772390075Sobrien  const char *call_name;
1772490075Sobrien  tree node;
1772590075Sobrien
1772690075Sobrien  if (GET_CODE (call_ref) != SYMBOL_REF)
1772790075Sobrien    return call_ref;
1772890075Sobrien
1772990075Sobrien  /* System V adds '.' to the internal name, so skip them.  */
1773090075Sobrien  call_name = XSTR (call_ref, 0);
1773190075Sobrien  if (*call_name == '.')
1773290075Sobrien    {
1773390075Sobrien      while (*call_name == '.')
1773490075Sobrien	call_name++;
1773590075Sobrien
1773690075Sobrien      node = get_identifier (call_name);
1773790075Sobrien      call_ref = gen_rtx_SYMBOL_REF (VOIDmode, IDENTIFIER_POINTER (node));
1773890075Sobrien    }
1773990075Sobrien
1774090075Sobrien  return force_reg (Pmode, call_ref);
1774190075Sobrien}
1774290075Sobrien
17743169689Skan#ifndef TARGET_USE_MS_BITFIELD_LAYOUT
17744169689Skan#define TARGET_USE_MS_BITFIELD_LAYOUT 0
17745169689Skan#endif
17746169689Skan
17747169689Skan/* Handle a "ms_struct" or "gcc_struct" attribute; arguments as in
17748169689Skan   struct attribute_spec.handler.  */
17749169689Skanstatic tree
17750169689Skanrs6000_handle_struct_attribute (tree *node, tree name,
17751169689Skan				tree args ATTRIBUTE_UNUSED,
17752169689Skan				int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
17753169689Skan{
17754169689Skan  tree *type = NULL;
17755169689Skan  if (DECL_P (*node))
17756169689Skan    {
17757169689Skan      if (TREE_CODE (*node) == TYPE_DECL)
17758169689Skan        type = &TREE_TYPE (*node);
17759169689Skan    }
17760169689Skan  else
17761169689Skan    type = node;
17762169689Skan
17763169689Skan  if (!(type && (TREE_CODE (*type) == RECORD_TYPE
17764169689Skan                 || TREE_CODE (*type) == UNION_TYPE)))
17765169689Skan    {
17766169689Skan      warning (OPT_Wattributes, "%qs attribute ignored", IDENTIFIER_POINTER (name));
17767169689Skan      *no_add_attrs = true;
17768169689Skan    }
17769169689Skan
17770169689Skan  else if ((is_attribute_p ("ms_struct", name)
17771169689Skan            && lookup_attribute ("gcc_struct", TYPE_ATTRIBUTES (*type)))
17772169689Skan           || ((is_attribute_p ("gcc_struct", name)
17773169689Skan                && lookup_attribute ("ms_struct", TYPE_ATTRIBUTES (*type)))))
17774169689Skan    {
17775169689Skan      warning (OPT_Wattributes, "%qs incompatible attribute ignored",
17776169689Skan               IDENTIFIER_POINTER (name));
17777169689Skan      *no_add_attrs = true;
17778169689Skan    }
17779169689Skan
17780169689Skan  return NULL_TREE;
17781169689Skan}
17782169689Skan
17783169689Skanstatic bool
17784169689Skanrs6000_ms_bitfield_layout_p (tree record_type)
17785169689Skan{
17786169689Skan  return (TARGET_USE_MS_BITFIELD_LAYOUT &&
17787169689Skan          !lookup_attribute ("gcc_struct", TYPE_ATTRIBUTES (record_type)))
17788169689Skan    || lookup_attribute ("ms_struct", TYPE_ATTRIBUTES (record_type));
17789169689Skan}
17790169689Skan
17791117395Skan#ifdef USING_ELFOS_H
17792117395Skan
17793169689Skan/* A get_unnamed_section callback, used for switching to toc_section.  */
1779490075Sobrien
17795117395Skanstatic void
17796169689Skanrs6000_elf_output_toc_section_asm_op (const void *data ATTRIBUTE_UNUSED)
1779790075Sobrien{
17798169689Skan  if (DEFAULT_ABI == ABI_AIX
17799169689Skan      && TARGET_MINIMAL_TOC
17800169689Skan      && !TARGET_RELOCATABLE)
17801169689Skan    {
17802169689Skan      if (!toc_initialized)
17803169689Skan	{
17804169689Skan	  toc_initialized = 1;
17805169689Skan	  fprintf (asm_out_file, "%s\n", TOC_SECTION_ASM_OP);
17806169689Skan	  (*targetm.asm_out.internal_label) (asm_out_file, "LCTOC", 0);
17807169689Skan	  fprintf (asm_out_file, "\t.tc ");
17808169689Skan	  ASM_OUTPUT_INTERNAL_LABEL_PREFIX (asm_out_file, "LCTOC1[TC],");
17809169689Skan	  ASM_OUTPUT_INTERNAL_LABEL_PREFIX (asm_out_file, "LCTOC1");
17810169689Skan	  fprintf (asm_out_file, "\n");
17811169689Skan
17812169689Skan	  fprintf (asm_out_file, "%s\n", MINIMAL_TOC_SECTION_ASM_OP);
17813169689Skan	  ASM_OUTPUT_INTERNAL_LABEL_PREFIX (asm_out_file, "LCTOC1");
17814169689Skan	  fprintf (asm_out_file, " = .+32768\n");
17815169689Skan	}
17816169689Skan      else
17817169689Skan	fprintf (asm_out_file, "%s\n", MINIMAL_TOC_SECTION_ASM_OP);
17818169689Skan    }
17819169689Skan  else if (DEFAULT_ABI == ABI_AIX && !TARGET_RELOCATABLE)
17820169689Skan    fprintf (asm_out_file, "%s\n", TOC_SECTION_ASM_OP);
1782190075Sobrien  else
17822169689Skan    {
17823169689Skan      fprintf (asm_out_file, "%s\n", MINIMAL_TOC_SECTION_ASM_OP);
17824169689Skan      if (!toc_initialized)
17825169689Skan	{
17826169689Skan	  ASM_OUTPUT_INTERNAL_LABEL_PREFIX (asm_out_file, "LCTOC1");
17827169689Skan	  fprintf (asm_out_file, " = .+32768\n");
17828169689Skan	  toc_initialized = 1;
17829169689Skan	}
17830169689Skan    }
1783190075Sobrien}
1783290075Sobrien
17833169689Skan/* Implement TARGET_ASM_INIT_SECTIONS.  */
1783490075Sobrien
17835117395Skanstatic void
17836169689Skanrs6000_elf_asm_init_sections (void)
1783790075Sobrien{
17838169689Skan  toc_section
17839169689Skan    = get_unnamed_section (0, rs6000_elf_output_toc_section_asm_op, NULL);
17840169689Skan
17841169689Skan  sdata2_section
17842169689Skan    = get_unnamed_section (SECTION_WRITE, output_section_asm_op,
17843169689Skan			   SDATA2_SECTION_ASM_OP);
1784490075Sobrien}
1784590075Sobrien
17846169689Skan/* Implement TARGET_SELECT_RTX_SECTION.  */
1784790075Sobrien
17848169689Skanstatic section *
17849169689Skanrs6000_elf_select_rtx_section (enum machine_mode mode, rtx x,
17850169689Skan			       unsigned HOST_WIDE_INT align)
1785190075Sobrien{
17852169689Skan  if (ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (x, mode))
17853169689Skan    return toc_section;
17854169689Skan  else
17855169689Skan    return default_elf_select_rtx_section (mode, x, align);
1785690075Sobrien}
17857117395Skan
17858132718Skan/* For a SYMBOL_REF, set generic flags and then perform some
17859132718Skan   target-specific processing.
1786090075Sobrien
17861132718Skan   When the AIX ABI is requested on a non-AIX system, replace the
17862132718Skan   function name with the real name (with a leading .) rather than the
17863132718Skan   function descriptor name.  This saves a lot of overriding code to
17864132718Skan   read the prefixes.  */
17865132718Skan
17866117395Skanstatic void
17867132718Skanrs6000_elf_encode_section_info (tree decl, rtx rtl, int first)
1786890075Sobrien{
17869132718Skan  default_encode_section_info (decl, rtl, first);
17870117395Skan
17871132718Skan  if (first
17872132718Skan      && TREE_CODE (decl) == FUNCTION_DECL
17873132718Skan      && !TARGET_AIX
17874132718Skan      && DEFAULT_ABI == ABI_AIX)
1787590075Sobrien    {
17876132718Skan      rtx sym_ref = XEXP (rtl, 0);
17877132718Skan      size_t len = strlen (XSTR (sym_ref, 0));
17878132718Skan      char *str = alloca (len + 2);
17879132718Skan      str[0] = '.';
17880132718Skan      memcpy (str + 1, XSTR (sym_ref, 0), len + 1);
17881132718Skan      XSTR (sym_ref, 0) = ggc_alloc_string (str, len + 1);
1788290075Sobrien    }
1788390075Sobrien}
1788490075Sobrien
17885169689Skanbool
17886132718Skanrs6000_elf_in_small_data_p (tree decl)
17887117395Skan{
17888117395Skan  if (rs6000_sdata == SDATA_NONE)
17889117395Skan    return false;
17890117395Skan
17891146895Skan  /* We want to merge strings, so we never consider them small data.  */
17892146895Skan  if (TREE_CODE (decl) == STRING_CST)
17893146895Skan    return false;
17894146895Skan
17895146895Skan  /* Functions are never in the small data area.  */
17896146895Skan  if (TREE_CODE (decl) == FUNCTION_DECL)
17897146895Skan    return false;
17898146895Skan
17899117395Skan  if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl))
17900117395Skan    {
17901117395Skan      const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
17902117395Skan      if (strcmp (section, ".sdata") == 0
17903117395Skan	  || strcmp (section, ".sdata2") == 0
17904132718Skan	  || strcmp (section, ".sbss") == 0
17905132718Skan	  || strcmp (section, ".sbss2") == 0
17906132718Skan	  || strcmp (section, ".PPC.EMB.sdata0") == 0
17907132718Skan	  || strcmp (section, ".PPC.EMB.sbss0") == 0)
17908117395Skan	return true;
17909117395Skan    }
17910117395Skan  else
17911117395Skan    {
17912117395Skan      HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (decl));
17913117395Skan
17914117395Skan      if (size > 0
17915132718Skan	  && (unsigned HOST_WIDE_INT) size <= g_switch_value
17916132718Skan	  /* If it's not public, and we're not going to reference it there,
17917132718Skan	     there's no need to put it in the small data section.  */
17918117395Skan	  && (rs6000_sdata != SDATA_DATA || TREE_PUBLIC (decl)))
17919117395Skan	return true;
17920117395Skan    }
17921117395Skan
17922117395Skan  return false;
17923117395Skan}
17924117395Skan
1792590075Sobrien#endif /* USING_ELFOS_H */
17926169689Skan
17927169689Skan/* Implement TARGET_USE_BLOCKS_FOR_CONSTANT_P.  */
1792890075Sobrien
17929169689Skanstatic bool
17930169689Skanrs6000_use_blocks_for_constant_p (enum machine_mode mode, rtx x)
17931169689Skan{
17932169689Skan  return !ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (x, mode);
17933169689Skan}
1793490075Sobrien
1793590075Sobrien/* Return a REG that occurs in ADDR with coefficient 1.
1793690075Sobrien   ADDR can be effectively incremented by incrementing REG.
1793790075Sobrien
1793890075Sobrien   r0 is special and we must not select it as an address
1793990075Sobrien   register by this routine since our caller will try to
1794090075Sobrien   increment the returned register via an "la" instruction.  */
1794190075Sobrien
17942169689Skanrtx
17943132718Skanfind_addr_reg (rtx addr)
1794490075Sobrien{
1794590075Sobrien  while (GET_CODE (addr) == PLUS)
1794690075Sobrien    {
1794790075Sobrien      if (GET_CODE (XEXP (addr, 0)) == REG
1794890075Sobrien	  && REGNO (XEXP (addr, 0)) != 0)
1794990075Sobrien	addr = XEXP (addr, 0);
1795090075Sobrien      else if (GET_CODE (XEXP (addr, 1)) == REG
1795190075Sobrien	       && REGNO (XEXP (addr, 1)) != 0)
1795290075Sobrien	addr = XEXP (addr, 1);
1795390075Sobrien      else if (CONSTANT_P (XEXP (addr, 0)))
1795490075Sobrien	addr = XEXP (addr, 1);
1795590075Sobrien      else if (CONSTANT_P (XEXP (addr, 1)))
1795690075Sobrien	addr = XEXP (addr, 0);
1795790075Sobrien      else
17958169689Skan	gcc_unreachable ();
1795990075Sobrien    }
17960169689Skan  gcc_assert (GET_CODE (addr) == REG && REGNO (addr) != 0);
17961169689Skan  return addr;
1796290075Sobrien}
1796390075Sobrien
1796490075Sobrienvoid
17965132718Skanrs6000_fatal_bad_address (rtx op)
1796690075Sobrien{
1796790075Sobrien  fatal_insn ("bad address", op);
1796890075Sobrien}
1796990075Sobrien
1797090075Sobrien#if TARGET_MACHO
1797190075Sobrien
17972132718Skanstatic tree branch_island_list = 0;
1797390075Sobrien
17974132718Skan/* Remember to generate a branch island for far calls to the given
17975132718Skan   function.  */
1797690075Sobrien
17977169689Skanstatic void
17978169689Skanadd_compiler_branch_island (tree label_name, tree function_name,
17979169689Skan			    int line_number)
1798090075Sobrien{
17981132718Skan  tree branch_island = build_tree_list (function_name, label_name);
17982169689Skan  TREE_TYPE (branch_island) = build_int_cst (NULL_TREE, line_number);
17983132718Skan  TREE_CHAIN (branch_island) = branch_island_list;
17984132718Skan  branch_island_list = branch_island;
1798590075Sobrien}
1798690075Sobrien
17987132718Skan#define BRANCH_ISLAND_LABEL_NAME(BRANCH_ISLAND)     TREE_VALUE (BRANCH_ISLAND)
17988132718Skan#define BRANCH_ISLAND_FUNCTION_NAME(BRANCH_ISLAND)  TREE_PURPOSE (BRANCH_ISLAND)
17989132718Skan#define BRANCH_ISLAND_LINE_NUMBER(BRANCH_ISLAND)    \
17990132718Skan		TREE_INT_CST_LOW (TREE_TYPE (BRANCH_ISLAND))
1799190075Sobrien
17992132718Skan/* Generate far-jump branch islands for everything on the
17993132718Skan   branch_island_list.  Invoked immediately after the last instruction
17994132718Skan   of the epilogue has been emitted; the branch-islands must be
17995132718Skan   appended to, and contiguous with, the function body.  Mach-O stubs
17996132718Skan   are generated in machopic_output_stub().  */
1799790075Sobrien
17998132718Skanstatic void
17999132718Skanmacho_branch_islands (void)
1800090075Sobrien{
18001132718Skan  char tmp_buf[512];
18002132718Skan  tree branch_island;
1800390075Sobrien
18004132718Skan  for (branch_island = branch_island_list;
18005132718Skan       branch_island;
18006132718Skan       branch_island = TREE_CHAIN (branch_island))
18007132718Skan    {
18008132718Skan      const char *label =
18009132718Skan	IDENTIFIER_POINTER (BRANCH_ISLAND_LABEL_NAME (branch_island));
18010132718Skan      const char *name  =
18011169689Skan	IDENTIFIER_POINTER (BRANCH_ISLAND_FUNCTION_NAME (branch_island));
18012132718Skan      char name_buf[512];
18013132718Skan      /* Cheap copy of the details from the Darwin ASM_OUTPUT_LABELREF().  */
18014132718Skan      if (name[0] == '*' || name[0] == '&')
18015132718Skan	strcpy (name_buf, name+1);
18016132718Skan      else
18017132718Skan	{
18018132718Skan	  name_buf[0] = '_';
18019132718Skan	  strcpy (name_buf+1, name);
18020132718Skan	}
18021132718Skan      strcpy (tmp_buf, "\n");
18022132718Skan      strcat (tmp_buf, label);
1802390075Sobrien#if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO)
18024132718Skan      if (write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG)
18025169689Skan	dbxout_stabd (N_SLINE, BRANCH_ISLAND_LINE_NUMBER (branch_island));
1802690075Sobrien#endif /* DBX_DEBUGGING_INFO || XCOFF_DEBUGGING_INFO */
18027132718Skan      if (flag_pic)
18028132718Skan	{
18029132718Skan	  strcat (tmp_buf, ":\n\tmflr r0\n\tbcl 20,31,");
18030132718Skan	  strcat (tmp_buf, label);
18031132718Skan	  strcat (tmp_buf, "_pic\n");
18032132718Skan	  strcat (tmp_buf, label);
18033132718Skan	  strcat (tmp_buf, "_pic:\n\tmflr r11\n");
18034169689Skan
18035132718Skan	  strcat (tmp_buf, "\taddis r11,r11,ha16(");
18036132718Skan	  strcat (tmp_buf, name_buf);
18037132718Skan	  strcat (tmp_buf, " - ");
18038132718Skan	  strcat (tmp_buf, label);
18039132718Skan	  strcat (tmp_buf, "_pic)\n");
18040169689Skan
18041132718Skan	  strcat (tmp_buf, "\tmtlr r0\n");
18042169689Skan
18043132718Skan	  strcat (tmp_buf, "\taddi r12,r11,lo16(");
18044132718Skan	  strcat (tmp_buf, name_buf);
18045132718Skan	  strcat (tmp_buf, " - ");
18046132718Skan	  strcat (tmp_buf, label);
18047132718Skan	  strcat (tmp_buf, "_pic)\n");
18048169689Skan
18049132718Skan	  strcat (tmp_buf, "\tmtctr r12\n\tbctr\n");
18050132718Skan	}
18051132718Skan      else
18052132718Skan	{
18053132718Skan	  strcat (tmp_buf, ":\nlis r12,hi16(");
18054132718Skan	  strcat (tmp_buf, name_buf);
18055132718Skan	  strcat (tmp_buf, ")\n\tori r12,r12,lo16(");
18056132718Skan	  strcat (tmp_buf, name_buf);
18057132718Skan	  strcat (tmp_buf, ")\n\tmtctr r12\n\tbctr");
18058132718Skan	}
18059132718Skan      output_asm_insn (tmp_buf, 0);
1806090075Sobrien#if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO)
18061132718Skan      if (write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG)
18062169689Skan	dbxout_stabd (N_SLINE, BRANCH_ISLAND_LINE_NUMBER (branch_island));
1806390075Sobrien#endif /* DBX_DEBUGGING_INFO || XCOFF_DEBUGGING_INFO */
18064132718Skan    }
1806590075Sobrien
18066132718Skan  branch_island_list = 0;
1806790075Sobrien}
1806890075Sobrien
1806990075Sobrien/* NO_PREVIOUS_DEF checks in the link list whether the function name is
1807090075Sobrien   already there or not.  */
1807190075Sobrien
18072132718Skanstatic int
18073132718Skanno_previous_def (tree function_name)
1807490075Sobrien{
18075132718Skan  tree branch_island;
18076132718Skan  for (branch_island = branch_island_list;
18077132718Skan       branch_island;
18078132718Skan       branch_island = TREE_CHAIN (branch_island))
18079132718Skan    if (function_name == BRANCH_ISLAND_FUNCTION_NAME (branch_island))
1808090075Sobrien      return 0;
1808190075Sobrien  return 1;
1808290075Sobrien}
1808390075Sobrien
1808490075Sobrien/* GET_PREV_LABEL gets the label name from the previous definition of
1808590075Sobrien   the function.  */
1808690075Sobrien
18087132718Skanstatic tree
18088132718Skanget_prev_label (tree function_name)
1808990075Sobrien{
18090132718Skan  tree branch_island;
18091132718Skan  for (branch_island = branch_island_list;
18092132718Skan       branch_island;
18093132718Skan       branch_island = TREE_CHAIN (branch_island))
18094132718Skan    if (function_name == BRANCH_ISLAND_FUNCTION_NAME (branch_island))
18095132718Skan      return BRANCH_ISLAND_LABEL_NAME (branch_island);
1809690075Sobrien  return 0;
1809790075Sobrien}
1809890075Sobrien
18099169689Skan#ifndef DARWIN_LINKER_GENERATES_ISLANDS
18100169689Skan#define DARWIN_LINKER_GENERATES_ISLANDS 0
18101169689Skan#endif
18102169689Skan
18103169689Skan/* KEXTs still need branch islands.  */
18104169689Skan#define DARWIN_GENERATE_ISLANDS (!DARWIN_LINKER_GENERATES_ISLANDS \
18105169689Skan				 || flag_mkernel || flag_apple_kext)
18106169689Skan
1810790075Sobrien/* INSN is either a function call or a millicode call.  It may have an
18108169689Skan   unconditional jump in its delay slot.
1810990075Sobrien
1811090075Sobrien   CALL_DEST is the routine we are calling.  */
1811190075Sobrien
1811290075Sobrienchar *
18113169689Skanoutput_call (rtx insn, rtx *operands, int dest_operand_number,
18114169689Skan	     int cookie_operand_number)
1811590075Sobrien{
1811690075Sobrien  static char buf[256];
18117169689Skan  if (DARWIN_GENERATE_ISLANDS
18118169689Skan      && GET_CODE (operands[dest_operand_number]) == SYMBOL_REF
18119132718Skan      && (INTVAL (operands[cookie_operand_number]) & CALL_LONG))
1812090075Sobrien    {
1812190075Sobrien      tree labelname;
18122132718Skan      tree funname = get_identifier (XSTR (operands[dest_operand_number], 0));
18123169689Skan
1812490075Sobrien      if (no_previous_def (funname))
1812590075Sobrien	{
18126117395Skan	  int line_number = 0;
1812790075Sobrien	  rtx label_rtx = gen_label_rtx ();
1812890075Sobrien	  char *label_buf, temp_buf[256];
1812990075Sobrien	  ASM_GENERATE_INTERNAL_LABEL (temp_buf, "L",
1813090075Sobrien				       CODE_LABEL_NUMBER (label_rtx));
1813190075Sobrien	  label_buf = temp_buf[0] == '*' ? temp_buf + 1 : temp_buf;
1813290075Sobrien	  labelname = get_identifier (label_buf);
1813390075Sobrien	  for (; insn && GET_CODE (insn) != NOTE; insn = PREV_INSN (insn));
1813490075Sobrien	  if (insn)
1813590075Sobrien	    line_number = NOTE_LINE_NUMBER (insn);
18136132718Skan	  add_compiler_branch_island (labelname, funname, line_number);
1813790075Sobrien	}
1813890075Sobrien      else
1813990075Sobrien	labelname = get_prev_label (funname);
1814090075Sobrien
18141132718Skan      /* "jbsr foo, L42" is Mach-O for "Link as 'bl foo' if a 'bl'
18142132718Skan	 instruction will reach 'foo', otherwise link as 'bl L42'".
18143132718Skan	 "L42" should be a 'branch island', that will do a far jump to
18144132718Skan	 'foo'.  Branch islands are generated in
18145132718Skan	 macho_branch_islands().  */
1814690075Sobrien      sprintf (buf, "jbsr %%z%d,%.246s",
18147132718Skan	       dest_operand_number, IDENTIFIER_POINTER (labelname));
1814890075Sobrien    }
1814990075Sobrien  else
18150132718Skan    sprintf (buf, "bl %%z%d", dest_operand_number);
18151132718Skan  return buf;
1815290075Sobrien}
1815390075Sobrien
1815490075Sobrien/* Generate PIC and indirect symbol stubs.  */
1815590075Sobrien
1815690075Sobrienvoid
18157132718Skanmachopic_output_stub (FILE *file, const char *symb, const char *stub)
1815890075Sobrien{
1815990075Sobrien  unsigned int length;
1816090075Sobrien  char *symbol_name, *lazy_ptr_name;
1816190075Sobrien  char *local_label_0;
1816290075Sobrien  static int label = 0;
1816390075Sobrien
1816490075Sobrien  /* Lose our funky encoding stuff so it doesn't contaminate the stub.  */
18165117395Skan  symb = (*targetm.strip_name_encoding) (symb);
1816690075Sobrien
1816790075Sobrien
1816890075Sobrien  length = strlen (symb);
1816990075Sobrien  symbol_name = alloca (length + 32);
1817090075Sobrien  GEN_SYMBOL_NAME_FOR_SYMBOL (symbol_name, symb, length);
1817190075Sobrien
1817290075Sobrien  lazy_ptr_name = alloca (length + 32);
1817390075Sobrien  GEN_LAZY_PTR_NAME_FOR_SYMBOL (lazy_ptr_name, symb, length);
1817490075Sobrien
1817590075Sobrien  if (flag_pic == 2)
18176169689Skan    switch_to_section (darwin_sections[machopic_picsymbol_stub1_section]);
1817790075Sobrien  else
18178169689Skan    switch_to_section (darwin_sections[machopic_symbol_stub1_section]);
1817990075Sobrien
1818090075Sobrien  if (flag_pic == 2)
1818190075Sobrien    {
18182169689Skan      fprintf (file, "\t.align 5\n");
18183169689Skan
18184169689Skan      fprintf (file, "%s:\n", stub);
18185169689Skan      fprintf (file, "\t.indirect_symbol %s\n", symbol_name);
18186169689Skan
18187132718Skan      label++;
18188169689Skan      local_label_0 = alloca (sizeof ("\"L00000000000$spb\""));
18189132718Skan      sprintf (local_label_0, "\"L%011d$spb\"", label);
18190169689Skan
1819190075Sobrien      fprintf (file, "\tmflr r0\n");
1819290075Sobrien      fprintf (file, "\tbcl 20,31,%s\n", local_label_0);
1819390075Sobrien      fprintf (file, "%s:\n\tmflr r11\n", local_label_0);
1819490075Sobrien      fprintf (file, "\taddis r11,r11,ha16(%s-%s)\n",
1819590075Sobrien	       lazy_ptr_name, local_label_0);
1819690075Sobrien      fprintf (file, "\tmtlr r0\n");
18197169689Skan      fprintf (file, "\t%s r12,lo16(%s-%s)(r11)\n",
18198169689Skan	       (TARGET_64BIT ? "ldu" : "lwzu"),
1819990075Sobrien	       lazy_ptr_name, local_label_0);
1820090075Sobrien      fprintf (file, "\tmtctr r12\n");
1820190075Sobrien      fprintf (file, "\tbctr\n");
1820290075Sobrien    }
1820390075Sobrien  else
18204169689Skan    {
18205169689Skan      fprintf (file, "\t.align 4\n");
18206169689Skan
18207169689Skan      fprintf (file, "%s:\n", stub);
18208169689Skan      fprintf (file, "\t.indirect_symbol %s\n", symbol_name);
18209169689Skan
18210169689Skan      fprintf (file, "\tlis r11,ha16(%s)\n", lazy_ptr_name);
18211169689Skan      fprintf (file, "\t%s r12,lo16(%s)(r11)\n",
18212169689Skan	       (TARGET_64BIT ? "ldu" : "lwzu"),
18213169689Skan	       lazy_ptr_name);
18214169689Skan      fprintf (file, "\tmtctr r12\n");
18215169689Skan      fprintf (file, "\tbctr\n");
18216169689Skan    }
18217169689Skan
18218169689Skan  switch_to_section (darwin_sections[machopic_lazy_symbol_ptr_section]);
1821990075Sobrien  fprintf (file, "%s:\n", lazy_ptr_name);
1822090075Sobrien  fprintf (file, "\t.indirect_symbol %s\n", symbol_name);
18221169689Skan  fprintf (file, "%sdyld_stub_binding_helper\n",
18222169689Skan	   (TARGET_64BIT ? DOUBLE_INT_ASM_OP : "\t.long\t"));
1822390075Sobrien}
1822490075Sobrien
1822590075Sobrien/* Legitimize PIC addresses.  If the address is already
1822690075Sobrien   position-independent, we return ORIG.  Newly generated
1822790075Sobrien   position-independent addresses go into a reg.  This is REG if non
1822890075Sobrien   zero, otherwise we allocate register(s) as necessary.  */
1822990075Sobrien
18230169689Skan#define SMALL_INT(X) ((UINTVAL (X) + 0x8000) < 0x10000)
1823190075Sobrien
1823290075Sobrienrtx
18233169689Skanrs6000_machopic_legitimize_pic_address (rtx orig, enum machine_mode mode,
18234132718Skan					rtx reg)
1823590075Sobrien{
1823690075Sobrien  rtx base, offset;
1823790075Sobrien
1823890075Sobrien  if (reg == NULL && ! reload_in_progress && ! reload_completed)
1823990075Sobrien    reg = gen_reg_rtx (Pmode);
1824090075Sobrien
1824190075Sobrien  if (GET_CODE (orig) == CONST)
1824290075Sobrien    {
18243169689Skan      rtx reg_temp;
18244169689Skan
1824590075Sobrien      if (GET_CODE (XEXP (orig, 0)) == PLUS
1824690075Sobrien	  && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx)
1824790075Sobrien	return orig;
1824890075Sobrien
18249169689Skan      gcc_assert (GET_CODE (XEXP (orig, 0)) == PLUS);
18250132718Skan
18251169689Skan      /* Use a different reg for the intermediate value, as
18252169689Skan	 it will be marked UNCHANGING.  */
18253169689Skan      reg_temp = no_new_pseudos ? reg : gen_reg_rtx (Pmode);
18254169689Skan      base = rs6000_machopic_legitimize_pic_address (XEXP (XEXP (orig, 0), 0),
18255169689Skan						     Pmode, reg_temp);
18256169689Skan      offset =
18257169689Skan	rs6000_machopic_legitimize_pic_address (XEXP (XEXP (orig, 0), 1),
18258169689Skan						Pmode, reg);
1825990075Sobrien
1826090075Sobrien      if (GET_CODE (offset) == CONST_INT)
1826190075Sobrien	{
1826290075Sobrien	  if (SMALL_INT (offset))
1826390075Sobrien	    return plus_constant (base, INTVAL (offset));
1826490075Sobrien	  else if (! reload_in_progress && ! reload_completed)
1826590075Sobrien	    offset = force_reg (Pmode, offset);
1826690075Sobrien	  else
1826790075Sobrien	    {
1826890075Sobrien 	      rtx mem = force_const_mem (Pmode, orig);
1826990075Sobrien	      return machopic_legitimize_pic_address (mem, Pmode, reg);
1827090075Sobrien	    }
1827190075Sobrien	}
18272169689Skan      return gen_rtx_PLUS (Pmode, base, offset);
1827390075Sobrien    }
1827490075Sobrien
1827590075Sobrien  /* Fall back on generic machopic code.  */
1827690075Sobrien  return machopic_legitimize_pic_address (orig, mode, reg);
1827790075Sobrien}
1827890075Sobrien
18279169689Skan/* Output a .machine directive for the Darwin assembler, and call
18280169689Skan   the generic start_file routine.  */
1828190075Sobrien
18282169689Skanstatic void
18283169689Skanrs6000_darwin_file_start (void)
1828490075Sobrien{
18285169689Skan  static const struct
18286169689Skan  {
18287169689Skan    const char *arg;
18288169689Skan    const char *name;
18289169689Skan    int if_set;
18290169689Skan  } mapping[] = {
18291169689Skan    { "ppc64", "ppc64", MASK_64BIT },
18292169689Skan    { "970", "ppc970", MASK_PPC_GPOPT | MASK_MFCRF | MASK_POWERPC64 },
18293169689Skan    { "power4", "ppc970", 0 },
18294169689Skan    { "G5", "ppc970", 0 },
18295169689Skan    { "7450", "ppc7450", 0 },
18296169689Skan    { "7400", "ppc7400", MASK_ALTIVEC },
18297169689Skan    { "G4", "ppc7400", 0 },
18298169689Skan    { "750", "ppc750", 0 },
18299169689Skan    { "740", "ppc750", 0 },
18300169689Skan    { "G3", "ppc750", 0 },
18301169689Skan    { "604e", "ppc604e", 0 },
18302169689Skan    { "604", "ppc604", 0 },
18303169689Skan    { "603e", "ppc603", 0 },
18304169689Skan    { "603", "ppc603", 0 },
18305169689Skan    { "601", "ppc601", 0 },
18306169689Skan    { NULL, "ppc", 0 } };
18307169689Skan  const char *cpu_id = "";
18308169689Skan  size_t i;
18309169689Skan
18310169689Skan  rs6000_file_start ();
18311169689Skan  darwin_file_start ();
18312169689Skan
18313169689Skan  /* Determine the argument to -mcpu=.  Default to G3 if not specified.  */
18314169689Skan  for (i = 0; i < ARRAY_SIZE (rs6000_select); i++)
18315169689Skan    if (rs6000_select[i].set_arch_p && rs6000_select[i].string
18316169689Skan	&& rs6000_select[i].string[0] != '\0')
18317169689Skan      cpu_id = rs6000_select[i].string;
18318169689Skan
18319169689Skan  /* Look through the mapping array.  Pick the first name that either
18320169689Skan     matches the argument, has a bit set in IF_SET that is also set
18321169689Skan     in the target flags, or has a NULL name.  */
18322169689Skan
18323169689Skan  i = 0;
18324169689Skan  while (mapping[i].arg != NULL
18325169689Skan	 && strcmp (mapping[i].arg, cpu_id) != 0
18326169689Skan	 && (mapping[i].if_set & target_flags) == 0)
18327169689Skan    i++;
18328169689Skan
18329169689Skan  fprintf (asm_out_file, "\t.machine %s\n", mapping[i].name);
1833090075Sobrien}
1833190075Sobrien
1833290075Sobrien#endif /* TARGET_MACHO */
1833390075Sobrien
1833490075Sobrien#if TARGET_ELF
18335169689Skanstatic int
18336169689Skanrs6000_elf_reloc_rw_mask (void)
1833790075Sobrien{
18338169689Skan  if (flag_pic)
18339169689Skan    return 3;
18340169689Skan  else if (DEFAULT_ABI == ABI_AIX)
18341169689Skan    return 2;
18342169689Skan  else
18343169689Skan    return 0;
1834490075Sobrien}
1834590075Sobrien
1834690075Sobrien/* Record an element in the table of global constructors.  SYMBOL is
1834790075Sobrien   a SYMBOL_REF of the function to be called; PRIORITY is a number
1834890075Sobrien   between 0 and MAX_INIT_PRIORITY.
1834990075Sobrien
1835090075Sobrien   This differs from default_named_section_asm_out_constructor in
1835190075Sobrien   that we have special handling for -mrelocatable.  */
1835290075Sobrien
1835390075Sobrienstatic void
18354132718Skanrs6000_elf_asm_out_constructor (rtx symbol, int priority)
1835590075Sobrien{
1835690075Sobrien  const char *section = ".ctors";
1835790075Sobrien  char buf[16];
1835890075Sobrien
1835990075Sobrien  if (priority != DEFAULT_INIT_PRIORITY)
1836090075Sobrien    {
1836190075Sobrien      sprintf (buf, ".ctors.%.5u",
18362169689Skan	       /* Invert the numbering so the linker puts us in the proper
18363169689Skan		  order; constructors are run from right to left, and the
18364169689Skan		  linker sorts in increasing order.  */
18365169689Skan	       MAX_INIT_PRIORITY - priority);
1836690075Sobrien      section = buf;
1836790075Sobrien    }
1836890075Sobrien
18369169689Skan  switch_to_section (get_section (section, SECTION_WRITE, NULL));
1837090075Sobrien  assemble_align (POINTER_SIZE);
1837190075Sobrien
1837290075Sobrien  if (TARGET_RELOCATABLE)
1837390075Sobrien    {
1837490075Sobrien      fputs ("\t.long (", asm_out_file);
1837590075Sobrien      output_addr_const (asm_out_file, symbol);
1837690075Sobrien      fputs (")@fixup\n", asm_out_file);
1837790075Sobrien    }
1837890075Sobrien  else
1837990075Sobrien    assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
1838090075Sobrien}
1838190075Sobrien
1838290075Sobrienstatic void
18383132718Skanrs6000_elf_asm_out_destructor (rtx symbol, int priority)
1838490075Sobrien{
1838590075Sobrien  const char *section = ".dtors";
1838690075Sobrien  char buf[16];
1838790075Sobrien
1838890075Sobrien  if (priority != DEFAULT_INIT_PRIORITY)
1838990075Sobrien    {
1839090075Sobrien      sprintf (buf, ".dtors.%.5u",
18391169689Skan	       /* Invert the numbering so the linker puts us in the proper
18392169689Skan		  order; constructors are run from right to left, and the
18393169689Skan		  linker sorts in increasing order.  */
18394169689Skan	       MAX_INIT_PRIORITY - priority);
1839590075Sobrien      section = buf;
1839690075Sobrien    }
1839790075Sobrien
18398169689Skan  switch_to_section (get_section (section, SECTION_WRITE, NULL));
1839990075Sobrien  assemble_align (POINTER_SIZE);
1840090075Sobrien
1840190075Sobrien  if (TARGET_RELOCATABLE)
1840290075Sobrien    {
1840390075Sobrien      fputs ("\t.long (", asm_out_file);
1840490075Sobrien      output_addr_const (asm_out_file, symbol);
1840590075Sobrien      fputs (")@fixup\n", asm_out_file);
1840690075Sobrien    }
1840790075Sobrien  else
1840890075Sobrien    assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
1840990075Sobrien}
18410132718Skan
18411132718Skanvoid
18412132718Skanrs6000_elf_declare_function_name (FILE *file, const char *name, tree decl)
18413132718Skan{
18414132718Skan  if (TARGET_64BIT)
18415132718Skan    {
18416132718Skan      fputs ("\t.section\t\".opd\",\"aw\"\n\t.align 3\n", file);
18417132718Skan      ASM_OUTPUT_LABEL (file, name);
18418132718Skan      fputs (DOUBLE_INT_ASM_OP, file);
18419169689Skan      rs6000_output_function_entry (file, name);
18420169689Skan      fputs (",.TOC.@tocbase,0\n\t.previous\n", file);
18421169689Skan      if (DOT_SYMBOLS)
18422132718Skan	{
18423169689Skan	  fputs ("\t.size\t", file);
18424132718Skan	  assemble_name (file, name);
18425169689Skan	  fputs (",24\n\t.type\t.", file);
18426169689Skan	  assemble_name (file, name);
18427169689Skan	  fputs (",@function\n", file);
18428169689Skan	  if (TREE_PUBLIC (decl) && ! DECL_WEAK (decl))
18429169689Skan	    {
18430169689Skan	      fputs ("\t.globl\t.", file);
18431169689Skan	      assemble_name (file, name);
18432169689Skan	      putc ('\n', file);
18433169689Skan	    }
18434132718Skan	}
18435169689Skan      else
18436169689Skan	ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function");
18437132718Skan      ASM_DECLARE_RESULT (file, DECL_RESULT (decl));
18438169689Skan      rs6000_output_function_entry (file, name);
18439169689Skan      fputs (":\n", file);
18440132718Skan      return;
18441132718Skan    }
18442132718Skan
18443132718Skan  if (TARGET_RELOCATABLE
18444169689Skan      && !TARGET_SECURE_PLT
18445132718Skan      && (get_pool_size () != 0 || current_function_profile)
18446132718Skan      && uses_TOC ())
18447132718Skan    {
18448132718Skan      char buf[256];
18449132718Skan
18450132718Skan      (*targetm.asm_out.internal_label) (file, "LCL", rs6000_pic_labelno);
18451132718Skan
18452132718Skan      ASM_GENERATE_INTERNAL_LABEL (buf, "LCTOC", 1);
18453132718Skan      fprintf (file, "\t.long ");
18454132718Skan      assemble_name (file, buf);
18455132718Skan      putc ('-', file);
18456132718Skan      ASM_GENERATE_INTERNAL_LABEL (buf, "LCF", rs6000_pic_labelno);
18457132718Skan      assemble_name (file, buf);
18458132718Skan      putc ('\n', file);
18459132718Skan    }
18460132718Skan
18461132718Skan  ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function");
18462132718Skan  ASM_DECLARE_RESULT (file, DECL_RESULT (decl));
18463132718Skan
18464132718Skan  if (DEFAULT_ABI == ABI_AIX)
18465132718Skan    {
18466132718Skan      const char *desc_name, *orig_name;
18467132718Skan
18468132718Skan      orig_name = (*targetm.strip_name_encoding) (name);
18469132718Skan      desc_name = orig_name;
18470132718Skan      while (*desc_name == '.')
18471132718Skan	desc_name++;
18472132718Skan
18473132718Skan      if (TREE_PUBLIC (decl))
18474132718Skan	fprintf (file, "\t.globl %s\n", desc_name);
18475132718Skan
18476132718Skan      fprintf (file, "%s\n", MINIMAL_TOC_SECTION_ASM_OP);
18477132718Skan      fprintf (file, "%s:\n", desc_name);
18478132718Skan      fprintf (file, "\t.long %s\n", orig_name);
18479132718Skan      fputs ("\t.long _GLOBAL_OFFSET_TABLE_\n", file);
18480132718Skan      if (DEFAULT_ABI == ABI_AIX)
18481132718Skan	fputs ("\t.long 0\n", file);
18482132718Skan      fprintf (file, "\t.previous\n");
18483132718Skan    }
18484132718Skan  ASM_OUTPUT_LABEL (file, name);
18485132718Skan}
18486146895Skan
18487146895Skanstatic void
18488146895Skanrs6000_elf_end_indicate_exec_stack (void)
18489146895Skan{
18490217396Skib  if (NEED_INDICATE_EXEC_STACK)
18491146895Skan    file_end_indicate_exec_stack ();
18492146895Skan}
1849390075Sobrien#endif
1849490075Sobrien
18495117395Skan#if TARGET_XCOFF
1849690075Sobrienstatic void
18497169689Skanrs6000_xcoff_asm_output_anchor (rtx symbol)
18498169689Skan{
18499169689Skan  char buffer[100];
18500169689Skan
18501169689Skan  sprintf (buffer, "$ + " HOST_WIDE_INT_PRINT_DEC,
18502169689Skan	   SYMBOL_REF_BLOCK_OFFSET (symbol));
18503169689Skan  ASM_OUTPUT_DEF (asm_out_file, XSTR (symbol, 0), buffer);
18504169689Skan}
18505169689Skan
18506169689Skanstatic void
18507132718Skanrs6000_xcoff_asm_globalize_label (FILE *stream, const char *name)
1850890075Sobrien{
18509117395Skan  fputs (GLOBAL_ASM_OP, stream);
18510117395Skan  RS6000_OUTPUT_BASENAME (stream, name);
18511117395Skan  putc ('\n', stream);
1851290075Sobrien}
18513117395Skan
18514169689Skan/* A get_unnamed_decl callback, used for read-only sections.  PTR
18515169689Skan   points to the section string variable.  */
18516169689Skan
18517117395Skanstatic void
18518169689Skanrs6000_xcoff_output_readonly_section_asm_op (const void *directive)
18519117395Skan{
18520169689Skan  fprintf (asm_out_file, "\t.csect %s[RO],3\n",
18521169689Skan	   *(const char *const *) directive);
18522169689Skan}
18523169689Skan
18524169689Skan/* Likewise for read-write sections.  */
18525169689Skan
18526169689Skanstatic void
18527169689Skanrs6000_xcoff_output_readwrite_section_asm_op (const void *directive)
18528169689Skan{
18529169689Skan  fprintf (asm_out_file, "\t.csect %s[RW],3\n",
18530169689Skan	   *(const char *const *) directive);
18531169689Skan}
18532169689Skan
18533169689Skan/* A get_unnamed_section callback, used for switching to toc_section.  */
18534169689Skan
18535169689Skanstatic void
18536169689Skanrs6000_xcoff_output_toc_section_asm_op (const void *data ATTRIBUTE_UNUSED)
18537169689Skan{
18538169689Skan  if (TARGET_MINIMAL_TOC)
18539169689Skan    {
18540169689Skan      /* toc_section is always selected at least once from
18541169689Skan	 rs6000_xcoff_file_start, so this is guaranteed to
18542169689Skan	 always be defined once and only once in each file.  */
18543169689Skan      if (!toc_initialized)
18544169689Skan	{
18545169689Skan	  fputs ("\t.toc\nLCTOC..1:\n", asm_out_file);
18546169689Skan	  fputs ("\t.tc toc_table[TC],toc_table[RW]\n", asm_out_file);
18547169689Skan	  toc_initialized = 1;
18548169689Skan	}
18549169689Skan      fprintf (asm_out_file, "\t.csect toc_table[RW]%s\n",
18550169689Skan	       (TARGET_32BIT ? "" : ",3"));
18551169689Skan    }
18552169689Skan  else
18553169689Skan    fputs ("\t.toc\n", asm_out_file);
18554169689Skan}
18555169689Skan
18556169689Skan/* Implement TARGET_ASM_INIT_SECTIONS.  */
18557169689Skan
18558169689Skanstatic void
18559169689Skanrs6000_xcoff_asm_init_sections (void)
18560169689Skan{
18561169689Skan  read_only_data_section
18562169689Skan    = get_unnamed_section (0, rs6000_xcoff_output_readonly_section_asm_op,
18563169689Skan			   &xcoff_read_only_section_name);
18564169689Skan
18565169689Skan  private_data_section
18566169689Skan    = get_unnamed_section (SECTION_WRITE,
18567169689Skan			   rs6000_xcoff_output_readwrite_section_asm_op,
18568169689Skan			   &xcoff_private_data_section_name);
18569169689Skan
18570169689Skan  read_only_private_data_section
18571169689Skan    = get_unnamed_section (0, rs6000_xcoff_output_readonly_section_asm_op,
18572169689Skan			   &xcoff_private_data_section_name);
18573169689Skan
18574169689Skan  toc_section
18575169689Skan    = get_unnamed_section (0, rs6000_xcoff_output_toc_section_asm_op, NULL);
18576169689Skan
18577169689Skan  readonly_data_section = read_only_data_section;
18578169689Skan  exception_section = data_section;
18579169689Skan}
18580169689Skan
18581169689Skanstatic int
18582169689Skanrs6000_xcoff_reloc_rw_mask (void)
18583169689Skan{
18584169689Skan  return 3;
18585169689Skan}
18586169689Skan
18587169689Skanstatic void
18588169689Skanrs6000_xcoff_asm_named_section (const char *name, unsigned int flags,
18589169689Skan				tree decl ATTRIBUTE_UNUSED)
18590169689Skan{
18591117395Skan  int smclass;
18592117395Skan  static const char * const suffix[3] = { "PR", "RO", "RW" };
18593117395Skan
18594117395Skan  if (flags & SECTION_CODE)
18595117395Skan    smclass = 0;
18596117395Skan  else if (flags & SECTION_WRITE)
18597117395Skan    smclass = 2;
18598117395Skan  else
18599117395Skan    smclass = 1;
18600117395Skan
18601117395Skan  fprintf (asm_out_file, "\t.csect %s%s[%s],%u\n",
18602117395Skan	   (flags & SECTION_CODE) ? "." : "",
18603117395Skan	   name, suffix[smclass], flags & SECTION_ENTSIZE);
18604117395Skan}
18605117395Skan
18606169689Skanstatic section *
18607169689Skanrs6000_xcoff_select_section (tree decl, int reloc,
18608169689Skan			     unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
18609117395Skan{
18610169689Skan  if (decl_readonly_section (decl, reloc))
18611117395Skan    {
18612117395Skan      if (TREE_PUBLIC (decl))
18613169689Skan	return read_only_data_section;
18614117395Skan      else
18615169689Skan	return read_only_private_data_section;
18616117395Skan    }
18617117395Skan  else
18618117395Skan    {
18619117395Skan      if (TREE_PUBLIC (decl))
18620169689Skan	return data_section;
18621117395Skan      else
18622169689Skan	return private_data_section;
18623117395Skan    }
18624117395Skan}
18625117395Skan
18626117395Skanstatic void
18627132718Skanrs6000_xcoff_unique_section (tree decl, int reloc ATTRIBUTE_UNUSED)
18628117395Skan{
18629117395Skan  const char *name;
18630117395Skan
18631117395Skan  /* Use select_section for private and uninitialized data.  */
18632117395Skan  if (!TREE_PUBLIC (decl)
18633117395Skan      || DECL_COMMON (decl)
18634117395Skan      || DECL_INITIAL (decl) == NULL_TREE
18635117395Skan      || DECL_INITIAL (decl) == error_mark_node
18636117395Skan      || (flag_zero_initialized_in_bss
18637117395Skan	  && initializer_zerop (DECL_INITIAL (decl))))
18638117395Skan    return;
18639117395Skan
18640117395Skan  name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
18641117395Skan  name = (*targetm.strip_name_encoding) (name);
18642117395Skan  DECL_SECTION_NAME (decl) = build_string (strlen (name), name);
18643117395Skan}
18644117395Skan
18645117395Skan/* Select section for constant in constant pool.
18646117395Skan
18647117395Skan   On RS/6000, all constants are in the private read-only data area.
18648117395Skan   However, if this is being placed in the TOC it must be output as a
18649117395Skan   toc entry.  */
18650117395Skan
18651169689Skanstatic section *
18652169689Skanrs6000_xcoff_select_rtx_section (enum machine_mode mode, rtx x,
18653169689Skan				 unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
18654117395Skan{
18655117395Skan  if (ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (x, mode))
18656169689Skan    return toc_section;
18657117395Skan  else
18658169689Skan    return read_only_private_data_section;
18659117395Skan}
18660117395Skan
18661117395Skan/* Remove any trailing [DS] or the like from the symbol name.  */
18662117395Skan
18663117395Skanstatic const char *
18664132718Skanrs6000_xcoff_strip_name_encoding (const char *name)
18665117395Skan{
18666117395Skan  size_t len;
18667117395Skan  if (*name == '*')
18668117395Skan    name++;
18669117395Skan  len = strlen (name);
18670117395Skan  if (name[len - 1] == ']')
18671117395Skan    return ggc_alloc_string (name, len - 4);
18672117395Skan  else
18673117395Skan    return name;
18674117395Skan}
18675117395Skan
18676117395Skan/* Section attributes.  AIX is always PIC.  */
18677117395Skan
18678117395Skanstatic unsigned int
18679132718Skanrs6000_xcoff_section_type_flags (tree decl, const char *name, int reloc)
18680117395Skan{
18681117395Skan  unsigned int align;
18682169689Skan  unsigned int flags = default_section_type_flags (decl, name, reloc);
18683117395Skan
18684117395Skan  /* Align to at least UNIT size.  */
18685117395Skan  if (flags & SECTION_CODE)
18686117395Skan    align = MIN_UNITS_PER_WORD;
18687117395Skan  else
18688117395Skan    /* Increase alignment of large objects if not already stricter.  */
18689117395Skan    align = MAX ((DECL_ALIGN (decl) / BITS_PER_UNIT),
18690117395Skan		 int_size_in_bytes (TREE_TYPE (decl)) > MIN_UNITS_PER_WORD
18691117395Skan		 ? UNITS_PER_FP_WORD : MIN_UNITS_PER_WORD);
18692117395Skan
18693117395Skan  return flags | (exact_log2 (align) & SECTION_ENTSIZE);
18694117395Skan}
18695117395Skan
18696132718Skan/* Output at beginning of assembler file.
18697117395Skan
18698132718Skan   Initialize the section names for the RS/6000 at this point.
18699117395Skan
18700132718Skan   Specify filename, including full path, to assembler.
18701132718Skan
18702132718Skan   We want to go into the TOC section so at least one .toc will be emitted.
18703132718Skan   Also, in order to output proper .bs/.es pairs, we need at least one static
18704132718Skan   [RW] section emitted.
18705132718Skan
18706132718Skan   Finally, declare mcount when profiling to make the assembler happy.  */
18707132718Skan
18708117395Skanstatic void
18709132718Skanrs6000_xcoff_file_start (void)
18710117395Skan{
18711132718Skan  rs6000_gen_section_name (&xcoff_bss_section_name,
18712132718Skan			   main_input_filename, ".bss_");
18713132718Skan  rs6000_gen_section_name (&xcoff_private_data_section_name,
18714132718Skan			   main_input_filename, ".rw_");
18715132718Skan  rs6000_gen_section_name (&xcoff_read_only_section_name,
18716132718Skan			   main_input_filename, ".ro_");
18717132718Skan
18718132718Skan  fputs ("\t.file\t", asm_out_file);
18719132718Skan  output_quoted_string (asm_out_file, main_input_filename);
18720132718Skan  fputc ('\n', asm_out_file);
18721132718Skan  if (write_symbols != NO_DEBUG)
18722169689Skan    switch_to_section (private_data_section);
18723169689Skan  switch_to_section (text_section);
18724132718Skan  if (profile_flag)
18725132718Skan    fprintf (asm_out_file, "\t.extern %s\n", RS6000_MCOUNT);
18726132718Skan  rs6000_file_start ();
18727117395Skan}
18728117395Skan
18729132718Skan/* Output at end of assembler file.
18730132718Skan   On the RS/6000, referencing data should automatically pull in text.  */
18731117395Skan
18732132718Skanstatic void
18733132718Skanrs6000_xcoff_file_end (void)
18734132718Skan{
18735169689Skan  switch_to_section (text_section);
18736132718Skan  fputs ("_section_.text:\n", asm_out_file);
18737169689Skan  switch_to_section (data_section);
18738132718Skan  fputs (TARGET_32BIT
18739132718Skan	 ? "\t.long _section_.text\n" : "\t.llong _section_.text\n",
18740132718Skan	 asm_out_file);
18741132718Skan}
18742132718Skan#endif /* TARGET_XCOFF */
18743132718Skan
18744132718Skan/* Compute a (partial) cost for rtx X.  Return true if the complete
18745132718Skan   cost has been computed, and false if subexpressions should be
18746132718Skan   scanned.  In either case, *TOTAL contains the cost result.  */
18747132718Skan
18748132718Skanstatic bool
18749169689Skanrs6000_rtx_costs (rtx x, int code, int outer_code, int *total)
18750132718Skan{
18751169689Skan  enum machine_mode mode = GET_MODE (x);
18752169689Skan
18753132718Skan  switch (code)
18754132718Skan    {
18755169689Skan      /* On the RS/6000, if it is valid in the insn, it is free.  */
18756132718Skan    case CONST_INT:
18757169689Skan      if (((outer_code == SET
18758169689Skan	    || outer_code == PLUS
18759169689Skan	    || outer_code == MINUS)
18760169689Skan	   && (satisfies_constraint_I (x)
18761169689Skan	       || satisfies_constraint_L (x)))
18762169689Skan	  || (outer_code == AND
18763169689Skan	      && (satisfies_constraint_K (x)
18764169689Skan		  || (mode == SImode
18765169689Skan		      ? satisfies_constraint_L (x)
18766169689Skan		      : satisfies_constraint_J (x))
18767169689Skan		  || mask_operand (x, mode)
18768169689Skan		  || (mode == DImode
18769169689Skan		      && mask64_operand (x, DImode))))
18770169689Skan	  || ((outer_code == IOR || outer_code == XOR)
18771169689Skan	      && (satisfies_constraint_K (x)
18772169689Skan		  || (mode == SImode
18773169689Skan		      ? satisfies_constraint_L (x)
18774169689Skan		      : satisfies_constraint_J (x))))
18775169689Skan	  || outer_code == ASHIFT
18776169689Skan	  || outer_code == ASHIFTRT
18777169689Skan	  || outer_code == LSHIFTRT
18778169689Skan	  || outer_code == ROTATE
18779169689Skan	  || outer_code == ROTATERT
18780169689Skan	  || outer_code == ZERO_EXTRACT
18781169689Skan	  || (outer_code == MULT
18782169689Skan	      && satisfies_constraint_I (x))
18783169689Skan	  || ((outer_code == DIV || outer_code == UDIV
18784169689Skan	       || outer_code == MOD || outer_code == UMOD)
18785169689Skan	      && exact_log2 (INTVAL (x)) >= 0)
18786169689Skan	  || (outer_code == COMPARE
18787169689Skan	      && (satisfies_constraint_I (x)
18788169689Skan		  || satisfies_constraint_K (x)))
18789169689Skan	  || (outer_code == EQ
18790169689Skan	      && (satisfies_constraint_I (x)
18791169689Skan		  || satisfies_constraint_K (x)
18792169689Skan		  || (mode == SImode
18793169689Skan		      ? satisfies_constraint_L (x)
18794169689Skan		      : satisfies_constraint_J (x))))
18795169689Skan	  || (outer_code == GTU
18796169689Skan	      && satisfies_constraint_I (x))
18797169689Skan	  || (outer_code == LTU
18798169689Skan	      && satisfies_constraint_P (x)))
18799169689Skan	{
18800169689Skan	  *total = 0;
18801169689Skan	  return true;
18802169689Skan	}
18803169689Skan      else if ((outer_code == PLUS
18804169689Skan		&& reg_or_add_cint_operand (x, VOIDmode))
18805169689Skan	       || (outer_code == MINUS
18806169689Skan		   && reg_or_sub_cint_operand (x, VOIDmode))
18807169689Skan	       || ((outer_code == SET
18808169689Skan		    || outer_code == IOR
18809169689Skan		    || outer_code == XOR)
18810169689Skan		   && (INTVAL (x)
18811169689Skan		       & ~ (unsigned HOST_WIDE_INT) 0xffffffff) == 0))
18812169689Skan	{
18813169689Skan	  *total = COSTS_N_INSNS (1);
18814169689Skan	  return true;
18815169689Skan	}
18816169689Skan      /* FALLTHRU */
18817169689Skan
18818169689Skan    case CONST_DOUBLE:
18819169689Skan      if (mode == DImode && code == CONST_DOUBLE)
18820169689Skan	{
18821169689Skan	  if ((outer_code == IOR || outer_code == XOR)
18822169689Skan	      && CONST_DOUBLE_HIGH (x) == 0
18823169689Skan	      && (CONST_DOUBLE_LOW (x)
18824169689Skan		  & ~ (unsigned HOST_WIDE_INT) 0xffff) == 0)
18825169689Skan	    {
18826169689Skan	      *total = 0;
18827169689Skan	      return true;
18828169689Skan	    }
18829169689Skan	  else if ((outer_code == AND && and64_2_operand (x, DImode))
18830169689Skan		   || ((outer_code == SET
18831169689Skan			|| outer_code == IOR
18832169689Skan			|| outer_code == XOR)
18833169689Skan		       && CONST_DOUBLE_HIGH (x) == 0))
18834169689Skan	    {
18835169689Skan	      *total = COSTS_N_INSNS (1);
18836169689Skan	      return true;
18837169689Skan	    }
18838169689Skan	}
18839169689Skan      /* FALLTHRU */
18840169689Skan
18841132718Skan    case CONST:
18842169689Skan    case HIGH:
18843169689Skan    case SYMBOL_REF:
18844169689Skan    case MEM:
18845169689Skan      /* When optimizing for size, MEM should be slightly more expensive
18846169689Skan	 than generating address, e.g., (plus (reg) (const)).
18847169689Skan	 L1 cache latency is about two instructions.  */
18848169689Skan      *total = optimize_size ? COSTS_N_INSNS (1) + 1 : COSTS_N_INSNS (2);
18849169689Skan      return true;
18850169689Skan
18851132718Skan    case LABEL_REF:
18852132718Skan      *total = 0;
18853132718Skan      return true;
18854132718Skan
18855132718Skan    case PLUS:
18856169689Skan      if (mode == DFmode)
18857169689Skan	{
18858169689Skan	  if (GET_CODE (XEXP (x, 0)) == MULT)
18859169689Skan	    {
18860169689Skan	      /* FNMA accounted in outer NEG.  */
18861169689Skan	      if (outer_code == NEG)
18862169689Skan		*total = rs6000_cost->dmul - rs6000_cost->fp;
18863169689Skan	      else
18864169689Skan		*total = rs6000_cost->dmul;
18865169689Skan	    }
18866169689Skan	  else
18867169689Skan	    *total = rs6000_cost->fp;
18868169689Skan	}
18869169689Skan      else if (mode == SFmode)
18870169689Skan	{
18871169689Skan	  /* FNMA accounted in outer NEG.  */
18872169689Skan	  if (outer_code == NEG && GET_CODE (XEXP (x, 0)) == MULT)
18873169689Skan	    *total = 0;
18874169689Skan	  else
18875169689Skan	    *total = rs6000_cost->fp;
18876169689Skan	}
18877169689Skan      else
18878169689Skan	*total = COSTS_N_INSNS (1);
18879169689Skan      return false;
18880132718Skan
18881169689Skan    case MINUS:
18882169689Skan      if (mode == DFmode)
18883132718Skan	{
18884169689Skan	  if (GET_CODE (XEXP (x, 0)) == MULT)
18885169689Skan	    {
18886169689Skan	      /* FNMA accounted in outer NEG.  */
18887169689Skan	      if (outer_code == NEG)
18888169689Skan		*total = 0;
18889169689Skan	      else
18890169689Skan		*total = rs6000_cost->dmul;
18891169689Skan	    }
18892169689Skan	  else
18893169689Skan	    *total = rs6000_cost->fp;
18894132718Skan	}
18895169689Skan      else if (mode == SFmode)
18896132718Skan	{
18897169689Skan	  /* FNMA accounted in outer NEG.  */
18898169689Skan	  if (outer_code == NEG && GET_CODE (XEXP (x, 0)) == MULT)
18899169689Skan	    *total = 0;
18900169689Skan	  else
18901169689Skan	    *total = rs6000_cost->fp;
18902169689Skan	}
18903169689Skan      else
18904169689Skan	*total = COSTS_N_INSNS (1);
18905169689Skan      return false;
18906132718Skan
18907169689Skan    case MULT:
18908169689Skan      if (GET_CODE (XEXP (x, 1)) == CONST_INT
18909169689Skan	  && satisfies_constraint_I (XEXP (x, 1)))
18910169689Skan	{
18911169689Skan	  if (INTVAL (XEXP (x, 1)) >= -256
18912169689Skan	      && INTVAL (XEXP (x, 1)) <= 255)
18913169689Skan	    *total = rs6000_cost->mulsi_const9;
18914169689Skan	  else
18915169689Skan	    *total = rs6000_cost->mulsi_const;
18916132718Skan	}
18917169689Skan      /* FMA accounted in outer PLUS/MINUS.  */
18918169689Skan      else if ((mode == DFmode || mode == SFmode)
18919169689Skan	       && (outer_code == PLUS || outer_code == MINUS))
18920169689Skan	*total = 0;
18921169689Skan      else if (mode == DFmode)
18922169689Skan	*total = rs6000_cost->dmul;
18923169689Skan      else if (mode == SFmode)
18924169689Skan	*total = rs6000_cost->fp;
18925169689Skan      else if (mode == DImode)
18926169689Skan	*total = rs6000_cost->muldi;
18927169689Skan      else
18928169689Skan	*total = rs6000_cost->mulsi;
18929169689Skan      return false;
18930132718Skan
18931132718Skan    case DIV:
18932132718Skan    case MOD:
18933169689Skan      if (FLOAT_MODE_P (mode))
18934132718Skan	{
18935169689Skan	  *total = mode == DFmode ? rs6000_cost->ddiv
18936169689Skan				  : rs6000_cost->sdiv;
18937169689Skan	  return false;
18938132718Skan	}
18939132718Skan      /* FALLTHRU */
18940132718Skan
18941132718Skan    case UDIV:
18942132718Skan    case UMOD:
18943169689Skan      if (GET_CODE (XEXP (x, 1)) == CONST_INT
18944169689Skan	  && exact_log2 (INTVAL (XEXP (x, 1))) >= 0)
18945132718Skan	{
18946169689Skan	  if (code == DIV || code == MOD)
18947169689Skan	    /* Shift, addze */
18948169689Skan	    *total = COSTS_N_INSNS (2);
18949169689Skan	  else
18950169689Skan	    /* Shift */
18951169689Skan	    *total = COSTS_N_INSNS (1);
18952169689Skan	}
18953169689Skan      else
18954169689Skan	{
18955169689Skan	  if (GET_MODE (XEXP (x, 1)) == DImode)
18956169689Skan	    *total = rs6000_cost->divdi;
18957169689Skan	  else
18958169689Skan	    *total = rs6000_cost->divsi;
18959169689Skan	}
18960169689Skan      /* Add in shift and subtract for MOD. */
18961169689Skan      if (code == MOD || code == UMOD)
18962169689Skan	*total += COSTS_N_INSNS (2);
18963169689Skan      return false;
18964132718Skan
18965169689Skan    case FFS:
18966169689Skan      *total = COSTS_N_INSNS (4);
18967169689Skan      return false;
18968132718Skan
18969169689Skan    case NOT:
18970169689Skan      if (outer_code == AND || outer_code == IOR || outer_code == XOR)
18971169689Skan	{
18972169689Skan	  *total = 0;
18973169689Skan	  return false;
18974169689Skan	}
18975169689Skan      /* FALLTHRU */
18976132718Skan
18977169689Skan    case AND:
18978169689Skan    case IOR:
18979169689Skan    case XOR:
18980169689Skan    case ZERO_EXTRACT:
18981169689Skan      *total = COSTS_N_INSNS (1);
18982169689Skan      return false;
18983132718Skan
18984169689Skan    case ASHIFT:
18985169689Skan    case ASHIFTRT:
18986169689Skan    case LSHIFTRT:
18987169689Skan    case ROTATE:
18988169689Skan    case ROTATERT:
18989169689Skan      /* Handle mul_highpart.  */
18990169689Skan      if (outer_code == TRUNCATE
18991169689Skan	  && GET_CODE (XEXP (x, 0)) == MULT)
18992169689Skan	{
18993169689Skan	  if (mode == DImode)
18994169689Skan	    *total = rs6000_cost->muldi;
18995169689Skan	  else
18996169689Skan	    *total = rs6000_cost->mulsi;
18997132718Skan	  return true;
18998169689Skan	}
18999169689Skan      else if (outer_code == AND)
19000169689Skan	*total = 0;
19001169689Skan      else
19002169689Skan	*total = COSTS_N_INSNS (1);
19003169689Skan      return false;
19004132718Skan
19005169689Skan    case SIGN_EXTEND:
19006169689Skan    case ZERO_EXTEND:
19007169689Skan      if (GET_CODE (XEXP (x, 0)) == MEM)
19008169689Skan	*total = 0;
19009169689Skan      else
19010169689Skan	*total = COSTS_N_INSNS (1);
19011169689Skan      return false;
19012132718Skan
19013169689Skan    case COMPARE:
19014169689Skan    case NEG:
19015169689Skan    case ABS:
19016169689Skan      if (!FLOAT_MODE_P (mode))
19017169689Skan	{
19018169689Skan	  *total = COSTS_N_INSNS (1);
19019169689Skan	  return false;
19020169689Skan	}
19021169689Skan      /* FALLTHRU */
19022132718Skan
19023169689Skan    case FLOAT:
19024169689Skan    case UNSIGNED_FLOAT:
19025169689Skan    case FIX:
19026169689Skan    case UNSIGNED_FIX:
19027169689Skan    case FLOAT_TRUNCATE:
19028169689Skan      *total = rs6000_cost->fp;
19029169689Skan      return false;
19030132718Skan
19031169689Skan    case FLOAT_EXTEND:
19032169689Skan      if (mode == DFmode)
19033169689Skan	*total = 0;
19034169689Skan      else
19035169689Skan	*total = rs6000_cost->fp;
19036169689Skan      return false;
19037132718Skan
19038169689Skan    case UNSPEC:
19039169689Skan      switch (XINT (x, 1))
19040169689Skan	{
19041169689Skan	case UNSPEC_FRSP:
19042169689Skan	  *total = rs6000_cost->fp;
19043132718Skan	  return true;
19044132718Skan
19045169689Skan	default:
19046169689Skan	  break;
19047169689Skan	}
19048169689Skan      break;
19049132718Skan
19050169689Skan    case CALL:
19051169689Skan    case IF_THEN_ELSE:
19052169689Skan      if (optimize_size)
19053169689Skan	{
19054169689Skan	  *total = COSTS_N_INSNS (1);
19055132718Skan	  return true;
19056169689Skan	}
19057169689Skan      else if (FLOAT_MODE_P (mode)
19058169689Skan	       && TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS)
19059169689Skan	{
19060169689Skan	  *total = rs6000_cost->fp;
19061169689Skan	  return false;
19062169689Skan	}
19063169689Skan      break;
19064132718Skan
19065169689Skan    case EQ:
19066169689Skan    case GTU:
19067169689Skan    case LTU:
19068169689Skan      /* Carry bit requires mode == Pmode.
19069169689Skan	 NEG or PLUS already counted so only add one.  */
19070169689Skan      if (mode == Pmode
19071169689Skan	  && (outer_code == NEG || outer_code == PLUS))
19072169689Skan	{
19073169689Skan	  *total = COSTS_N_INSNS (1);
19074132718Skan	  return true;
19075169689Skan	}
19076169689Skan      if (outer_code == SET)
19077169689Skan	{
19078169689Skan	  if (XEXP (x, 1) == const0_rtx)
19079169689Skan	    {
19080169689Skan	      *total = COSTS_N_INSNS (2);
19081169689Skan	      return true;
19082169689Skan	    }
19083169689Skan	  else if (mode == Pmode)
19084169689Skan	    {
19085169689Skan	      *total = COSTS_N_INSNS (3);
19086169689Skan	      return false;
19087169689Skan	    }
19088169689Skan	}
19089169689Skan      /* FALLTHRU */
19090132718Skan
19091169689Skan    case GT:
19092169689Skan    case LT:
19093169689Skan    case UNORDERED:
19094169689Skan      if (outer_code == SET && (XEXP (x, 1) == const0_rtx))
19095169689Skan	{
19096169689Skan	  *total = COSTS_N_INSNS (2);
19097132718Skan	  return true;
19098132718Skan	}
19099169689Skan      /* CC COMPARE.  */
19100169689Skan      if (outer_code == COMPARE)
19101169689Skan	{
19102169689Skan	  *total = 0;
19103169689Skan	  return true;
19104169689Skan	}
19105169689Skan      break;
19106132718Skan
19107132718Skan    default:
19108169689Skan      break;
19109132718Skan    }
19110169689Skan
19111169689Skan  return false;
19112132718Skan}
19113132718Skan
19114117395Skan/* A C expression returning the cost of moving data from a register of class
19115117395Skan   CLASS1 to one of CLASS2.  */
19116117395Skan
19117117395Skanint
19118169689Skanrs6000_register_move_cost (enum machine_mode mode,
19119132718Skan			   enum reg_class from, enum reg_class to)
19120117395Skan{
19121117395Skan  /*  Moves from/to GENERAL_REGS.  */
19122117395Skan  if (reg_classes_intersect_p (to, GENERAL_REGS)
19123117395Skan      || reg_classes_intersect_p (from, GENERAL_REGS))
19124117395Skan    {
19125117395Skan      if (! reg_classes_intersect_p (to, GENERAL_REGS))
19126117395Skan	from = to;
19127117395Skan
19128117395Skan      if (from == FLOAT_REGS || from == ALTIVEC_REGS)
19129117395Skan	return (rs6000_memory_move_cost (mode, from, 0)
19130117395Skan		+ rs6000_memory_move_cost (mode, GENERAL_REGS, 0));
19131117395Skan
19132169689Skan      /* It's more expensive to move CR_REGS than CR0_REGS because of the
19133169689Skan	 shift.  */
19134117395Skan      else if (from == CR_REGS)
19135117395Skan	return 4;
19136117395Skan
19137117395Skan      else
19138169689Skan	/* A move will cost one instruction per GPR moved.  */
19139169689Skan	return 2 * hard_regno_nregs[0][mode];
19140117395Skan    }
19141117395Skan
19142169689Skan  /* Moving between two similar registers is just one instruction.  */
19143117395Skan  else if (reg_classes_intersect_p (to, from))
19144117395Skan    return mode == TFmode ? 4 : 2;
19145117395Skan
19146169689Skan  /* Everything else has to go through GENERAL_REGS.  */
19147117395Skan  else
19148169689Skan    return (rs6000_register_move_cost (mode, GENERAL_REGS, to)
19149117395Skan	    + rs6000_register_move_cost (mode, from, GENERAL_REGS));
19150117395Skan}
19151117395Skan
19152117395Skan/* A C expressions returning the cost of moving data of MODE from a register to
19153117395Skan   or from memory.  */
19154117395Skan
19155117395Skanint
19156169689Skanrs6000_memory_move_cost (enum machine_mode mode, enum reg_class class,
19157132718Skan			 int in ATTRIBUTE_UNUSED)
19158117395Skan{
19159117395Skan  if (reg_classes_intersect_p (class, GENERAL_REGS))
19160169689Skan    return 4 * hard_regno_nregs[0][mode];
19161117395Skan  else if (reg_classes_intersect_p (class, FLOAT_REGS))
19162169689Skan    return 4 * hard_regno_nregs[32][mode];
19163117395Skan  else if (reg_classes_intersect_p (class, ALTIVEC_REGS))
19164169689Skan    return 4 * hard_regno_nregs[FIRST_ALTIVEC_REGNO][mode];
19165117395Skan  else
19166117395Skan    return 4 + rs6000_register_move_cost (mode, class, GENERAL_REGS);
19167117395Skan}
19168117395Skan
19169169689Skan/* Newton-Raphson approximation of single-precision floating point divide n/d.
19170169689Skan   Assumes no trapping math and finite arguments.  */
19171169689Skan
19172169689Skanvoid
19173169689Skanrs6000_emit_swdivsf (rtx res, rtx n, rtx d)
19174169689Skan{
19175169689Skan  rtx x0, e0, e1, y1, u0, v0, one;
19176169689Skan
19177169689Skan  x0 = gen_reg_rtx (SFmode);
19178169689Skan  e0 = gen_reg_rtx (SFmode);
19179169689Skan  e1 = gen_reg_rtx (SFmode);
19180169689Skan  y1 = gen_reg_rtx (SFmode);
19181169689Skan  u0 = gen_reg_rtx (SFmode);
19182169689Skan  v0 = gen_reg_rtx (SFmode);
19183169689Skan  one = force_reg (SFmode, CONST_DOUBLE_FROM_REAL_VALUE (dconst1, SFmode));
19184169689Skan
19185169689Skan  /* x0 = 1./d estimate */
19186169689Skan  emit_insn (gen_rtx_SET (VOIDmode, x0,
19187169689Skan			  gen_rtx_UNSPEC (SFmode, gen_rtvec (1, d),
19188169689Skan					  UNSPEC_FRES)));
19189169689Skan  /* e0 = 1. - d * x0 */
19190169689Skan  emit_insn (gen_rtx_SET (VOIDmode, e0,
19191169689Skan			  gen_rtx_MINUS (SFmode, one,
19192169689Skan					 gen_rtx_MULT (SFmode, d, x0))));
19193169689Skan  /* e1 = e0 + e0 * e0 */
19194169689Skan  emit_insn (gen_rtx_SET (VOIDmode, e1,
19195169689Skan			  gen_rtx_PLUS (SFmode,
19196169689Skan					gen_rtx_MULT (SFmode, e0, e0), e0)));
19197169689Skan  /* y1 = x0 + e1 * x0 */
19198169689Skan  emit_insn (gen_rtx_SET (VOIDmode, y1,
19199169689Skan			  gen_rtx_PLUS (SFmode,
19200169689Skan					gen_rtx_MULT (SFmode, e1, x0), x0)));
19201169689Skan  /* u0 = n * y1 */
19202169689Skan  emit_insn (gen_rtx_SET (VOIDmode, u0,
19203169689Skan			  gen_rtx_MULT (SFmode, n, y1)));
19204169689Skan  /* v0 = n - d * u0 */
19205169689Skan  emit_insn (gen_rtx_SET (VOIDmode, v0,
19206169689Skan			  gen_rtx_MINUS (SFmode, n,
19207169689Skan					 gen_rtx_MULT (SFmode, d, u0))));
19208169689Skan  /* res = u0 + v0 * y1 */
19209169689Skan  emit_insn (gen_rtx_SET (VOIDmode, res,
19210169689Skan			  gen_rtx_PLUS (SFmode,
19211169689Skan					gen_rtx_MULT (SFmode, v0, y1), u0)));
19212169689Skan}
19213169689Skan
19214169689Skan/* Newton-Raphson approximation of double-precision floating point divide n/d.
19215169689Skan   Assumes no trapping math and finite arguments.  */
19216169689Skan
19217169689Skanvoid
19218169689Skanrs6000_emit_swdivdf (rtx res, rtx n, rtx d)
19219169689Skan{
19220169689Skan  rtx x0, e0, e1, e2, y1, y2, y3, u0, v0, one;
19221169689Skan
19222169689Skan  x0 = gen_reg_rtx (DFmode);
19223169689Skan  e0 = gen_reg_rtx (DFmode);
19224169689Skan  e1 = gen_reg_rtx (DFmode);
19225169689Skan  e2 = gen_reg_rtx (DFmode);
19226169689Skan  y1 = gen_reg_rtx (DFmode);
19227169689Skan  y2 = gen_reg_rtx (DFmode);
19228169689Skan  y3 = gen_reg_rtx (DFmode);
19229169689Skan  u0 = gen_reg_rtx (DFmode);
19230169689Skan  v0 = gen_reg_rtx (DFmode);
19231169689Skan  one = force_reg (DFmode, CONST_DOUBLE_FROM_REAL_VALUE (dconst1, DFmode));
19232169689Skan
19233169689Skan  /* x0 = 1./d estimate */
19234169689Skan  emit_insn (gen_rtx_SET (VOIDmode, x0,
19235169689Skan			  gen_rtx_UNSPEC (DFmode, gen_rtvec (1, d),
19236169689Skan					  UNSPEC_FRES)));
19237169689Skan  /* e0 = 1. - d * x0 */
19238169689Skan  emit_insn (gen_rtx_SET (VOIDmode, e0,
19239169689Skan			  gen_rtx_MINUS (DFmode, one,
19240169689Skan					 gen_rtx_MULT (SFmode, d, x0))));
19241169689Skan  /* y1 = x0 + e0 * x0 */
19242169689Skan  emit_insn (gen_rtx_SET (VOIDmode, y1,
19243169689Skan			  gen_rtx_PLUS (DFmode,
19244169689Skan					gen_rtx_MULT (DFmode, e0, x0), x0)));
19245169689Skan  /* e1 = e0 * e0 */
19246169689Skan  emit_insn (gen_rtx_SET (VOIDmode, e1,
19247169689Skan			  gen_rtx_MULT (DFmode, e0, e0)));
19248169689Skan  /* y2 = y1 + e1 * y1 */
19249169689Skan  emit_insn (gen_rtx_SET (VOIDmode, y2,
19250169689Skan			  gen_rtx_PLUS (DFmode,
19251169689Skan					gen_rtx_MULT (DFmode, e1, y1), y1)));
19252169689Skan  /* e2 = e1 * e1 */
19253169689Skan  emit_insn (gen_rtx_SET (VOIDmode, e2,
19254169689Skan			  gen_rtx_MULT (DFmode, e1, e1)));
19255169689Skan  /* y3 = y2 + e2 * y2 */
19256169689Skan  emit_insn (gen_rtx_SET (VOIDmode, y3,
19257169689Skan			  gen_rtx_PLUS (DFmode,
19258169689Skan					gen_rtx_MULT (DFmode, e2, y2), y2)));
19259169689Skan  /* u0 = n * y3 */
19260169689Skan  emit_insn (gen_rtx_SET (VOIDmode, u0,
19261169689Skan			  gen_rtx_MULT (DFmode, n, y3)));
19262169689Skan  /* v0 = n - d * u0 */
19263169689Skan  emit_insn (gen_rtx_SET (VOIDmode, v0,
19264169689Skan			  gen_rtx_MINUS (DFmode, n,
19265169689Skan					 gen_rtx_MULT (DFmode, d, u0))));
19266169689Skan  /* res = u0 + v0 * y3 */
19267169689Skan  emit_insn (gen_rtx_SET (VOIDmode, res,
19268169689Skan			  gen_rtx_PLUS (DFmode,
19269169689Skan					gen_rtx_MULT (DFmode, v0, y3), u0)));
19270169689Skan}
19271169689Skan
19272132718Skan/* Return an RTX representing where to find the function value of a
19273132718Skan   function returning MODE.  */
19274132718Skanstatic rtx
19275132718Skanrs6000_complex_function_value (enum machine_mode mode)
19276132718Skan{
19277132718Skan  unsigned int regno;
19278132718Skan  rtx r1, r2;
19279132718Skan  enum machine_mode inner = GET_MODE_INNER (mode);
19280132718Skan  unsigned int inner_bytes = GET_MODE_SIZE (inner);
19281132718Skan
19282132718Skan  if (FLOAT_MODE_P (mode) && TARGET_HARD_FLOAT && TARGET_FPRS)
19283132718Skan    regno = FP_ARG_RETURN;
19284132718Skan  else
19285132718Skan    {
19286132718Skan      regno = GP_ARG_RETURN;
19287132718Skan
19288132718Skan      /* 32-bit is OK since it'll go in r3/r4.  */
19289132718Skan      if (TARGET_32BIT && inner_bytes >= 4)
19290132718Skan	return gen_rtx_REG (mode, regno);
19291132718Skan    }
19292132718Skan
19293132718Skan  if (inner_bytes >= 8)
19294132718Skan    return gen_rtx_REG (mode, regno);
19295132718Skan
19296132718Skan  r1 = gen_rtx_EXPR_LIST (inner, gen_rtx_REG (inner, regno),
19297132718Skan			  const0_rtx);
19298132718Skan  r2 = gen_rtx_EXPR_LIST (inner, gen_rtx_REG (inner, regno + 1),
19299132718Skan			  GEN_INT (inner_bytes));
19300132718Skan  return gen_rtx_PARALLEL (mode, gen_rtvec (2, r1, r2));
19301132718Skan}
19302132718Skan
19303132718Skan/* Define how to find the value returned by a function.
19304132718Skan   VALTYPE is the data type of the value (as a tree).
19305132718Skan   If the precise function being called is known, FUNC is its FUNCTION_DECL;
19306132718Skan   otherwise, FUNC is 0.
19307132718Skan
19308132718Skan   On the SPE, both FPs and vectors are returned in r3.
19309132718Skan
19310132718Skan   On RS/6000 an integer value is in r3 and a floating-point value is in
19311132718Skan   fp1, unless -msoft-float.  */
19312132718Skan
19313132718Skanrtx
19314132718Skanrs6000_function_value (tree valtype, tree func ATTRIBUTE_UNUSED)
19315132718Skan{
19316132718Skan  enum machine_mode mode;
19317132718Skan  unsigned int regno;
19318132718Skan
19319169689Skan  /* Special handling for structs in darwin64.  */
19320169689Skan  if (rs6000_darwin64_abi
19321169689Skan      && TYPE_MODE (valtype) == BLKmode
19322169689Skan      && TREE_CODE (valtype) == RECORD_TYPE
19323169689Skan      && int_size_in_bytes (valtype) > 0)
19324169689Skan    {
19325169689Skan      CUMULATIVE_ARGS valcum;
19326169689Skan      rtx valret;
19327169689Skan
19328169689Skan      valcum.words = 0;
19329169689Skan      valcum.fregno = FP_ARG_MIN_REG;
19330169689Skan      valcum.vregno = ALTIVEC_ARG_MIN_REG;
19331169689Skan      /* Do a trial code generation as if this were going to be passed as
19332169689Skan	 an argument; if any part goes in memory, we return NULL.  */
19333169689Skan      valret = rs6000_darwin64_record_arg (&valcum, valtype, 1, true);
19334169689Skan      if (valret)
19335169689Skan	return valret;
19336169689Skan      /* Otherwise fall through to standard ABI rules.  */
19337169689Skan    }
19338169689Skan
19339132718Skan  if (TARGET_32BIT && TARGET_POWERPC64 && TYPE_MODE (valtype) == DImode)
19340132718Skan    {
19341132718Skan      /* Long long return value need be split in -mpowerpc64, 32bit ABI.  */
19342132718Skan      return gen_rtx_PARALLEL (DImode,
19343132718Skan	gen_rtvec (2,
19344132718Skan		   gen_rtx_EXPR_LIST (VOIDmode,
19345132718Skan				      gen_rtx_REG (SImode, GP_ARG_RETURN),
19346132718Skan				      const0_rtx),
19347132718Skan		   gen_rtx_EXPR_LIST (VOIDmode,
19348132718Skan				      gen_rtx_REG (SImode,
19349132718Skan						   GP_ARG_RETURN + 1),
19350132718Skan				      GEN_INT (4))));
19351132718Skan    }
19352169689Skan  if (TARGET_32BIT && TARGET_POWERPC64 && TYPE_MODE (valtype) == DCmode)
19353169689Skan    {
19354169689Skan      return gen_rtx_PARALLEL (DCmode,
19355169689Skan	gen_rtvec (4,
19356169689Skan		   gen_rtx_EXPR_LIST (VOIDmode,
19357169689Skan				      gen_rtx_REG (SImode, GP_ARG_RETURN),
19358169689Skan				      const0_rtx),
19359169689Skan		   gen_rtx_EXPR_LIST (VOIDmode,
19360169689Skan				      gen_rtx_REG (SImode,
19361169689Skan						   GP_ARG_RETURN + 1),
19362169689Skan				      GEN_INT (4)),
19363169689Skan		   gen_rtx_EXPR_LIST (VOIDmode,
19364169689Skan				      gen_rtx_REG (SImode,
19365169689Skan						   GP_ARG_RETURN + 2),
19366169689Skan				      GEN_INT (8)),
19367169689Skan		   gen_rtx_EXPR_LIST (VOIDmode,
19368169689Skan				      gen_rtx_REG (SImode,
19369169689Skan						   GP_ARG_RETURN + 3),
19370169689Skan				      GEN_INT (12))));
19371169689Skan    }
19372132718Skan
19373169689Skan  mode = TYPE_MODE (valtype);
19374169689Skan  if ((INTEGRAL_TYPE_P (valtype) && GET_MODE_BITSIZE (mode) < BITS_PER_WORD)
19375132718Skan      || POINTER_TYPE_P (valtype))
19376132718Skan    mode = TARGET_32BIT ? SImode : DImode;
19377132718Skan
19378169689Skan  if (DECIMAL_FLOAT_MODE_P (mode))
19379169689Skan    regno = GP_ARG_RETURN;
19380169689Skan  else if (SCALAR_FLOAT_TYPE_P (valtype) && TARGET_HARD_FLOAT && TARGET_FPRS)
19381132718Skan    regno = FP_ARG_RETURN;
19382132718Skan  else if (TREE_CODE (valtype) == COMPLEX_TYPE
19383132718Skan	   && targetm.calls.split_complex_arg)
19384132718Skan    return rs6000_complex_function_value (mode);
19385132718Skan  else if (TREE_CODE (valtype) == VECTOR_TYPE
19386169689Skan	   && TARGET_ALTIVEC && TARGET_ALTIVEC_ABI
19387169689Skan	   && ALTIVEC_VECTOR_MODE (mode))
19388132718Skan    regno = ALTIVEC_ARG_RETURN;
19389169689Skan  else if (TARGET_E500_DOUBLE && TARGET_HARD_FLOAT
19390169689Skan	   && (mode == DFmode || mode == DCmode))
19391169689Skan    return spe_build_register_parallel (mode, GP_ARG_RETURN);
19392132718Skan  else
19393132718Skan    regno = GP_ARG_RETURN;
19394132718Skan
19395132718Skan  return gen_rtx_REG (mode, regno);
19396132718Skan}
19397132718Skan
19398132718Skan/* Define how to find the value returned by a library function
19399132718Skan   assuming the value has mode MODE.  */
19400132718Skanrtx
19401132718Skanrs6000_libcall_value (enum machine_mode mode)
19402132718Skan{
19403132718Skan  unsigned int regno;
19404132718Skan
19405169689Skan  if (TARGET_32BIT && TARGET_POWERPC64 && mode == DImode)
19406169689Skan    {
19407169689Skan      /* Long long return value need be split in -mpowerpc64, 32bit ABI.  */
19408169689Skan      return gen_rtx_PARALLEL (DImode,
19409169689Skan	gen_rtvec (2,
19410169689Skan		   gen_rtx_EXPR_LIST (VOIDmode,
19411169689Skan				      gen_rtx_REG (SImode, GP_ARG_RETURN),
19412169689Skan				      const0_rtx),
19413169689Skan		   gen_rtx_EXPR_LIST (VOIDmode,
19414169689Skan				      gen_rtx_REG (SImode,
19415169689Skan						   GP_ARG_RETURN + 1),
19416169689Skan				      GEN_INT (4))));
19417169689Skan    }
19418169689Skan
19419169689Skan  if (DECIMAL_FLOAT_MODE_P (mode))
19420169689Skan    regno = GP_ARG_RETURN;
19421169689Skan  else if (SCALAR_FLOAT_MODE_P (mode)
19422132718Skan	   && TARGET_HARD_FLOAT && TARGET_FPRS)
19423132718Skan    regno = FP_ARG_RETURN;
19424132718Skan  else if (ALTIVEC_VECTOR_MODE (mode)
19425132718Skan	   && TARGET_ALTIVEC && TARGET_ALTIVEC_ABI)
19426132718Skan    regno = ALTIVEC_ARG_RETURN;
19427132718Skan  else if (COMPLEX_MODE_P (mode) && targetm.calls.split_complex_arg)
19428132718Skan    return rs6000_complex_function_value (mode);
19429169689Skan  else if (TARGET_E500_DOUBLE && TARGET_HARD_FLOAT
19430169689Skan	   && (mode == DFmode || mode == DCmode))
19431169689Skan    return spe_build_register_parallel (mode, GP_ARG_RETURN);
19432132718Skan  else
19433132718Skan    regno = GP_ARG_RETURN;
19434132718Skan
19435132718Skan  return gen_rtx_REG (mode, regno);
19436132718Skan}
19437132718Skan
19438132718Skan/* Define the offset between two registers, FROM to be eliminated and its
19439132718Skan   replacement TO, at the start of a routine.  */
19440132718SkanHOST_WIDE_INT
19441132718Skanrs6000_initial_elimination_offset (int from, int to)
19442132718Skan{
19443132718Skan  rs6000_stack_t *info = rs6000_stack_info ();
19444132718Skan  HOST_WIDE_INT offset;
19445132718Skan
19446169689Skan  if (from == HARD_FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
19447132718Skan    offset = info->push_p ? 0 : -info->total_size;
19448169689Skan  else if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
19449169689Skan    {
19450169689Skan      offset = info->push_p ? 0 : -info->total_size;
19451169689Skan      if (FRAME_GROWS_DOWNWARD)
19452169689Skan	offset += info->fixed_size + info->vars_size + info->parm_size;
19453169689Skan    }
19454169689Skan  else if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
19455169689Skan    offset = FRAME_GROWS_DOWNWARD
19456169689Skan	     ? info->fixed_size + info->vars_size + info->parm_size
19457169689Skan	     : 0;
19458169689Skan  else if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
19459132718Skan    offset = info->total_size;
19460132718Skan  else if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
19461132718Skan    offset = info->push_p ? info->total_size : 0;
19462132718Skan  else if (from == RS6000_PIC_OFFSET_TABLE_REGNUM)
19463132718Skan    offset = 0;
19464132718Skan  else
19465169689Skan    gcc_unreachable ();
19466132718Skan
19467132718Skan  return offset;
19468132718Skan}
19469132718Skan
19470169689Skan/* Return true if TYPE is a SPE or AltiVec opaque type.  */
19471132718Skan
19472132718Skanstatic bool
19473169689Skanrs6000_is_opaque_type (tree type)
19474132718Skan{
19475169689Skan  return (type == opaque_V2SI_type_node
19476132718Skan	      || type == opaque_V2SF_type_node
19477169689Skan	      || type == opaque_p_V2SI_type_node
19478169689Skan	      || type == opaque_V4SI_type_node);
19479132718Skan}
19480132718Skan
19481132718Skanstatic rtx
19482132718Skanrs6000_dwarf_register_span (rtx reg)
19483132718Skan{
19484132718Skan  unsigned regno;
19485132718Skan
19486169689Skan  if (TARGET_SPE
19487169689Skan      && (SPE_VECTOR_MODE (GET_MODE (reg))
19488169689Skan	  || (TARGET_E500_DOUBLE && GET_MODE (reg) == DFmode)))
19489169689Skan    ;
19490169689Skan  else
19491132718Skan    return NULL_RTX;
19492132718Skan
19493132718Skan  regno = REGNO (reg);
19494132718Skan
19495132718Skan  /* The duality of the SPE register size wreaks all kinds of havoc.
19496132718Skan     This is a way of distinguishing r0 in 32-bits from r0 in
19497132718Skan     64-bits.  */
19498132718Skan  return
19499132718Skan    gen_rtx_PARALLEL (VOIDmode,
19500132718Skan		      BYTES_BIG_ENDIAN
19501132718Skan		      ? gen_rtvec (2,
19502132718Skan				   gen_rtx_REG (SImode, regno + 1200),
19503132718Skan				   gen_rtx_REG (SImode, regno))
19504132718Skan		      : gen_rtvec (2,
19505132718Skan				   gen_rtx_REG (SImode, regno),
19506132718Skan				   gen_rtx_REG (SImode, regno + 1200)));
19507132718Skan}
19508132718Skan
19509132718Skan/* Map internal gcc register numbers to DWARF2 register numbers.  */
19510132718Skan
19511132718Skanunsigned int
19512132718Skanrs6000_dbx_register_number (unsigned int regno)
19513132718Skan{
19514132718Skan  if (regno <= 63 || write_symbols != DWARF2_DEBUG)
19515132718Skan    return regno;
19516132718Skan  if (regno == MQ_REGNO)
19517132718Skan    return 100;
19518132718Skan  if (regno == LINK_REGISTER_REGNUM)
19519132718Skan    return 108;
19520132718Skan  if (regno == COUNT_REGISTER_REGNUM)
19521132718Skan    return 109;
19522132718Skan  if (CR_REGNO_P (regno))
19523132718Skan    return regno - CR0_REGNO + 86;
19524132718Skan  if (regno == XER_REGNO)
19525132718Skan    return 101;
19526132718Skan  if (ALTIVEC_REGNO_P (regno))
19527132718Skan    return regno - FIRST_ALTIVEC_REGNO + 1124;
19528132718Skan  if (regno == VRSAVE_REGNO)
19529132718Skan    return 356;
19530132718Skan  if (regno == VSCR_REGNO)
19531132718Skan    return 67;
19532132718Skan  if (regno == SPE_ACC_REGNO)
19533132718Skan    return 99;
19534132718Skan  if (regno == SPEFSCR_REGNO)
19535132718Skan    return 612;
19536132718Skan  /* SPE high reg number.  We get these values of regno from
19537132718Skan     rs6000_dwarf_register_span.  */
19538169689Skan  gcc_assert (regno >= 1200 && regno < 1232);
19539169689Skan  return regno;
19540169689Skan}
19541132718Skan
19542169689Skan/* target hook eh_return_filter_mode */
19543169689Skanstatic enum machine_mode
19544169689Skanrs6000_eh_return_filter_mode (void)
19545169689Skan{
19546169689Skan  return TARGET_32BIT ? SImode : word_mode;
19547132718Skan}
19548132718Skan
19549169689Skan/* Target hook for scalar_mode_supported_p.  */
19550169689Skanstatic bool
19551169689Skanrs6000_scalar_mode_supported_p (enum machine_mode mode)
19552169689Skan{
19553169689Skan  if (DECIMAL_FLOAT_MODE_P (mode))
19554169689Skan    return true;
19555169689Skan  else
19556169689Skan    return default_scalar_mode_supported_p (mode);
19557169689Skan}
19558169689Skan
19559169689Skan/* Target hook for vector_mode_supported_p.  */
19560169689Skanstatic bool
19561169689Skanrs6000_vector_mode_supported_p (enum machine_mode mode)
19562169689Skan{
19563169689Skan
19564169689Skan  if (TARGET_SPE && SPE_VECTOR_MODE (mode))
19565169689Skan    return true;
19566169689Skan
19567169689Skan  else if (TARGET_ALTIVEC && ALTIVEC_VECTOR_MODE (mode))
19568169689Skan    return true;
19569169689Skan
19570169689Skan  else
19571169689Skan    return false;
19572169689Skan}
19573169689Skan
19574169689Skan/* Target hook for invalid_arg_for_unprototyped_fn. */
19575169689Skanstatic const char *
19576169689Skaninvalid_arg_for_unprototyped_fn (tree typelist, tree funcdecl, tree val)
19577169689Skan{
19578169689Skan  return (!rs6000_darwin64_abi
19579169689Skan	  && typelist == 0
19580169689Skan          && TREE_CODE (TREE_TYPE (val)) == VECTOR_TYPE
19581169689Skan          && (funcdecl == NULL_TREE
19582169689Skan              || (TREE_CODE (funcdecl) == FUNCTION_DECL
19583169689Skan                  && DECL_BUILT_IN_CLASS (funcdecl) != BUILT_IN_MD)))
19584169689Skan	  ? N_("AltiVec argument passed to unprototyped function")
19585169689Skan	  : NULL;
19586169689Skan}
19587169689Skan
19588169689Skan/* For TARGET_SECURE_PLT 32-bit PIC code we can save PIC register
19589169689Skan   setup by using __stack_chk_fail_local hidden function instead of
19590169689Skan   calling __stack_chk_fail directly.  Otherwise it is better to call
19591169689Skan   __stack_chk_fail directly.  */
19592169689Skan
19593169689Skanstatic tree
19594169689Skanrs6000_stack_protect_fail (void)
19595169689Skan{
19596169689Skan  return (DEFAULT_ABI == ABI_V4 && TARGET_SECURE_PLT && flag_pic)
19597169689Skan	 ? default_hidden_stack_protect_fail ()
19598169689Skan	 : default_external_stack_protect_fail ();
19599169689Skan}
19600169689Skan
19601132718Skan#include "gt-rs6000.h"
19602