rs6000.c revision 169689
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);
667132718Skanstatic void rs6000_init_builtins (void);
668132718Skanstatic rtx rs6000_expand_unop_builtin (enum insn_code, tree, rtx);
669132718Skanstatic rtx rs6000_expand_binop_builtin (enum insn_code, tree, rtx);
670132718Skanstatic rtx rs6000_expand_ternop_builtin (enum insn_code, tree, rtx);
671132718Skanstatic rtx rs6000_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
672132718Skanstatic void altivec_init_builtins (void);
673132718Skanstatic void rs6000_common_init_builtins (void);
674132718Skanstatic void rs6000_init_libfuncs (void);
675117395Skan
676132718Skanstatic void enable_mask_for_builtins (struct builtin_description *, int,
677132718Skan				      enum rs6000_builtins,
678132718Skan				      enum rs6000_builtins);
679169689Skanstatic tree build_opaque_vector_type (tree, int);
680132718Skanstatic void spe_init_builtins (void);
681132718Skanstatic rtx spe_expand_builtin (tree, rtx, bool *);
682132718Skanstatic rtx spe_expand_stv_builtin (enum insn_code, tree);
683132718Skanstatic rtx spe_expand_predicate_builtin (enum insn_code, tree, rtx);
684132718Skanstatic rtx spe_expand_evsel_builtin (enum insn_code, tree, rtx);
685132718Skanstatic int rs6000_emit_int_cmove (rtx, rtx, rtx, rtx);
686132718Skanstatic rs6000_stack_t *rs6000_stack_info (void);
687132718Skanstatic void debug_stack_info (rs6000_stack_t *);
688117395Skan
689132718Skanstatic rtx altivec_expand_builtin (tree, rtx, bool *);
690132718Skanstatic rtx altivec_expand_ld_builtin (tree, rtx, bool *);
691132718Skanstatic rtx altivec_expand_st_builtin (tree, rtx, bool *);
692132718Skanstatic rtx altivec_expand_dst_builtin (tree, rtx, bool *);
693132718Skanstatic rtx altivec_expand_abs_builtin (enum insn_code, tree, rtx);
694169689Skanstatic rtx altivec_expand_predicate_builtin (enum insn_code,
695169689Skan					     const char *, tree, rtx);
696132718Skanstatic rtx altivec_expand_lv_builtin (enum insn_code, tree, rtx);
697132718Skanstatic rtx altivec_expand_stv_builtin (enum insn_code, tree);
698169689Skanstatic rtx altivec_expand_vec_init_builtin (tree, tree, rtx);
699169689Skanstatic rtx altivec_expand_vec_set_builtin (tree);
700169689Skanstatic rtx altivec_expand_vec_ext_builtin (tree, rtx);
701169689Skanstatic int get_element_number (tree, tree);
702169689Skanstatic bool rs6000_handle_option (size_t, const char *, int);
703132718Skanstatic void rs6000_parse_tls_size_option (void);
704132718Skanstatic void rs6000_parse_yes_no_option (const char *, const char *, int *);
705132718Skanstatic int first_altivec_reg_to_save (void);
706132718Skanstatic unsigned int compute_vrsave_mask (void);
707169689Skanstatic void compute_save_world_info (rs6000_stack_t *info_ptr);
708132718Skanstatic void is_altivec_return_reg (rtx, void *);
709132718Skanstatic rtx generate_set_vrsave (rtx, rs6000_stack_t *, int);
710132718Skanint easy_vector_constant (rtx, enum machine_mode);
711169689Skanstatic bool rs6000_is_opaque_type (tree);
712132718Skanstatic rtx rs6000_dwarf_register_span (rtx);
713132718Skanstatic rtx rs6000_legitimize_tls_address (rtx, enum tls_model);
714169689Skanstatic void rs6000_output_dwarf_dtprel (FILE *, int, rtx) ATTRIBUTE_UNUSED;
715132718Skanstatic rtx rs6000_tls_get_addr (void);
716132718Skanstatic rtx rs6000_got_sym (void);
717169689Skanstatic int rs6000_tls_symbol_ref_1 (rtx *, void *);
718132718Skanstatic const char *rs6000_get_some_local_dynamic_name (void);
719132718Skanstatic int rs6000_get_some_local_dynamic_name_1 (rtx *, void *);
720132718Skanstatic rtx rs6000_complex_function_value (enum machine_mode);
721132718Skanstatic rtx rs6000_spe_function_arg (CUMULATIVE_ARGS *,
722132718Skan				    enum machine_mode, tree);
723169689Skanstatic void rs6000_darwin64_record_arg_advance_flush (CUMULATIVE_ARGS *,
724169689Skan						      HOST_WIDE_INT);
725169689Skanstatic void rs6000_darwin64_record_arg_advance_recurse (CUMULATIVE_ARGS *,
726169689Skan							tree, HOST_WIDE_INT);
727169689Skanstatic void rs6000_darwin64_record_arg_flush (CUMULATIVE_ARGS *,
728169689Skan					      HOST_WIDE_INT,
729169689Skan					      rtx[], int *);
730169689Skanstatic void rs6000_darwin64_record_arg_recurse (CUMULATIVE_ARGS *,
731169689Skan					       tree, HOST_WIDE_INT,
732169689Skan					       rtx[], int *);
733169689Skanstatic rtx rs6000_darwin64_record_arg (CUMULATIVE_ARGS *, tree, int, bool);
734146895Skanstatic rtx rs6000_mixed_function_arg (enum machine_mode, tree, int);
735132718Skanstatic void rs6000_move_block_from_reg (int regno, rtx x, int nregs);
736132718Skanstatic void setup_incoming_varargs (CUMULATIVE_ARGS *,
737132718Skan				    enum machine_mode, tree,
738132718Skan				    int *, int);
739169689Skanstatic bool rs6000_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode,
740169689Skan				      tree, bool);
741169689Skanstatic int rs6000_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,
742169689Skan				     tree, bool);
743169689Skanstatic const char *invalid_arg_for_unprototyped_fn (tree, tree, tree);
744132718Skan#if TARGET_MACHO
745132718Skanstatic void macho_branch_islands (void);
746132718Skanstatic int no_previous_def (tree function_name);
747132718Skanstatic tree get_prev_label (tree function_name);
748169689Skanstatic void rs6000_darwin_file_start (void);
749132718Skan#endif
750132718Skan
751132718Skanstatic tree rs6000_build_builtin_va_list (void);
752169689Skanstatic tree rs6000_gimplify_va_arg (tree, tree, tree *, tree *);
753169689Skanstatic bool rs6000_must_pass_in_stack (enum machine_mode, tree);
754169689Skanstatic bool rs6000_scalar_mode_supported_p (enum machine_mode);
755169689Skanstatic bool rs6000_vector_mode_supported_p (enum machine_mode);
756169689Skanstatic int get_vec_cmp_insn (enum rtx_code, enum machine_mode,
757169689Skan			     enum machine_mode);
758169689Skanstatic rtx rs6000_emit_vector_compare (enum rtx_code, rtx, rtx,
759169689Skan				       enum machine_mode);
760169689Skanstatic int get_vsel_insn (enum machine_mode);
761169689Skanstatic void rs6000_emit_vector_select (rtx, rtx, rtx, rtx);
762169689Skanstatic tree rs6000_stack_protect_fail (void);
763132718Skan
764169689Skanconst int INSN_NOT_AVAILABLE = -1;
765169689Skanstatic enum machine_mode rs6000_eh_return_filter_mode (void);
766169689Skan
767132718Skan/* Hash table stuff for keeping track of TOC entries.  */
768132718Skan
769132718Skanstruct toc_hash_struct GTY(())
770132718Skan{
771132718Skan  /* `key' will satisfy CONSTANT_P; in fact, it will satisfy
772132718Skan     ASM_OUTPUT_SPECIAL_POOL_ENTRY_P.  */
773132718Skan  rtx key;
774132718Skan  enum machine_mode key_mode;
775132718Skan  int labelno;
776132718Skan};
777132718Skan
778132718Skanstatic GTY ((param_is (struct toc_hash_struct))) htab_t toc_hash_table;
77990075Sobrien
78090075Sobrien/* Default register names.  */
78190075Sobrienchar rs6000_reg_names[][8] =
78290075Sobrien{
78390075Sobrien      "0",  "1",  "2",  "3",  "4",  "5",  "6",  "7",
78490075Sobrien      "8",  "9", "10", "11", "12", "13", "14", "15",
78590075Sobrien     "16", "17", "18", "19", "20", "21", "22", "23",
78690075Sobrien     "24", "25", "26", "27", "28", "29", "30", "31",
78790075Sobrien      "0",  "1",  "2",  "3",  "4",  "5",  "6",  "7",
78890075Sobrien      "8",  "9", "10", "11", "12", "13", "14", "15",
78990075Sobrien     "16", "17", "18", "19", "20", "21", "22", "23",
79090075Sobrien     "24", "25", "26", "27", "28", "29", "30", "31",
79190075Sobrien     "mq", "lr", "ctr","ap",
79290075Sobrien      "0",  "1",  "2",  "3",  "4",  "5",  "6",  "7",
79390075Sobrien      "xer",
79490075Sobrien      /* AltiVec registers.  */
79590075Sobrien      "0",  "1",  "2",  "3",  "4",  "5",  "6", "7",
79690075Sobrien      "8",  "9",  "10", "11", "12", "13", "14", "15",
79790075Sobrien      "16", "17", "18", "19", "20", "21", "22", "23",
79890075Sobrien      "24", "25", "26", "27", "28", "29", "30", "31",
799117395Skan      "vrsave", "vscr",
800117395Skan      /* SPE registers.  */
801169689Skan      "spe_acc", "spefscr",
802169689Skan      /* Soft frame pointer.  */
803169689Skan      "sfp"
80490075Sobrien};
80590075Sobrien
80690075Sobrien#ifdef TARGET_REGNAMES
80790075Sobrienstatic const char alt_reg_names[][8] =
80890075Sobrien{
80990075Sobrien   "%r0",   "%r1",  "%r2",  "%r3",  "%r4",  "%r5",  "%r6",  "%r7",
81090075Sobrien   "%r8",   "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15",
81190075Sobrien  "%r16",  "%r17", "%r18", "%r19", "%r20", "%r21", "%r22", "%r23",
81290075Sobrien  "%r24",  "%r25", "%r26", "%r27", "%r28", "%r29", "%r30", "%r31",
81390075Sobrien   "%f0",   "%f1",  "%f2",  "%f3",  "%f4",  "%f5",  "%f6",  "%f7",
81490075Sobrien   "%f8",   "%f9", "%f10", "%f11", "%f12", "%f13", "%f14", "%f15",
81590075Sobrien  "%f16",  "%f17", "%f18", "%f19", "%f20", "%f21", "%f22", "%f23",
81690075Sobrien  "%f24",  "%f25", "%f26", "%f27", "%f28", "%f29", "%f30", "%f31",
81790075Sobrien    "mq",    "lr",  "ctr",   "ap",
81890075Sobrien  "%cr0",  "%cr1", "%cr2", "%cr3", "%cr4", "%cr5", "%cr6", "%cr7",
81990075Sobrien   "xer",
820117395Skan  /* AltiVec registers.  */
82190075Sobrien   "%v0",  "%v1",  "%v2",  "%v3",  "%v4",  "%v5",  "%v6", "%v7",
822117395Skan   "%v8",  "%v9", "%v10", "%v11", "%v12", "%v13", "%v14", "%v15",
823117395Skan  "%v16", "%v17", "%v18", "%v19", "%v20", "%v21", "%v22", "%v23",
824117395Skan  "%v24", "%v25", "%v26", "%v27", "%v28", "%v29", "%v30", "%v31",
825117395Skan  "vrsave", "vscr",
826117395Skan  /* SPE registers.  */
827169689Skan  "spe_acc", "spefscr",
828169689Skan  /* Soft frame pointer.  */
829169689Skan  "sfp"
83090075Sobrien};
83190075Sobrien#endif
83290075Sobrien
83390075Sobrien#ifndef MASK_STRICT_ALIGN
83490075Sobrien#define MASK_STRICT_ALIGN 0
83590075Sobrien#endif
836132718Skan#ifndef TARGET_PROFILE_KERNEL
837132718Skan#define TARGET_PROFILE_KERNEL 0
838132718Skan#endif
839117395Skan
840117395Skan/* The VRSAVE bitmask puts bit %v0 as the most significant bit.  */
841117395Skan#define ALTIVEC_REG_BIT(REGNO) (0x80000000 >> ((REGNO) - FIRST_ALTIVEC_REGNO))
84290075Sobrien
84390075Sobrien/* Initialize the GCC target structure.  */
84490075Sobrien#undef TARGET_ATTRIBUTE_TABLE
84590075Sobrien#define TARGET_ATTRIBUTE_TABLE rs6000_attribute_table
846117395Skan#undef TARGET_SET_DEFAULT_TYPE_ATTRIBUTES
847117395Skan#define TARGET_SET_DEFAULT_TYPE_ATTRIBUTES rs6000_set_default_type_attributes
84890075Sobrien
84990075Sobrien#undef TARGET_ASM_ALIGNED_DI_OP
85090075Sobrien#define TARGET_ASM_ALIGNED_DI_OP DOUBLE_INT_ASM_OP
85190075Sobrien
85290075Sobrien/* Default unaligned ops are only provided for ELF.  Find the ops needed
85390075Sobrien   for non-ELF systems.  */
85490075Sobrien#ifndef OBJECT_FORMAT_ELF
855117395Skan#if TARGET_XCOFF
85690075Sobrien/* For XCOFF.  rs6000_assemble_integer will handle unaligned DIs on
85790075Sobrien   64-bit targets.  */
85890075Sobrien#undef TARGET_ASM_UNALIGNED_HI_OP
85990075Sobrien#define TARGET_ASM_UNALIGNED_HI_OP "\t.vbyte\t2,"
86090075Sobrien#undef TARGET_ASM_UNALIGNED_SI_OP
86190075Sobrien#define TARGET_ASM_UNALIGNED_SI_OP "\t.vbyte\t4,"
86290075Sobrien#undef TARGET_ASM_UNALIGNED_DI_OP
86390075Sobrien#define TARGET_ASM_UNALIGNED_DI_OP "\t.vbyte\t8,"
86490075Sobrien#else
86590075Sobrien/* For Darwin.  */
86690075Sobrien#undef TARGET_ASM_UNALIGNED_HI_OP
86790075Sobrien#define TARGET_ASM_UNALIGNED_HI_OP "\t.short\t"
86890075Sobrien#undef TARGET_ASM_UNALIGNED_SI_OP
86990075Sobrien#define TARGET_ASM_UNALIGNED_SI_OP "\t.long\t"
870169689Skan#undef TARGET_ASM_UNALIGNED_DI_OP
871169689Skan#define TARGET_ASM_UNALIGNED_DI_OP "\t.quad\t"
872169689Skan#undef TARGET_ASM_ALIGNED_DI_OP
873169689Skan#define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t"
87490075Sobrien#endif
87590075Sobrien#endif
87690075Sobrien
87790075Sobrien/* This hook deals with fixups for relocatable code and DI-mode objects
87890075Sobrien   in 64-bit code.  */
87990075Sobrien#undef TARGET_ASM_INTEGER
88090075Sobrien#define TARGET_ASM_INTEGER rs6000_assemble_integer
88190075Sobrien
882117395Skan#ifdef HAVE_GAS_HIDDEN
883117395Skan#undef TARGET_ASM_ASSEMBLE_VISIBILITY
884117395Skan#define TARGET_ASM_ASSEMBLE_VISIBILITY rs6000_assemble_visibility
885117395Skan#endif
886117395Skan
887132718Skan#undef TARGET_HAVE_TLS
888132718Skan#define TARGET_HAVE_TLS HAVE_AS_TLS
889132718Skan
890132718Skan#undef TARGET_CANNOT_FORCE_CONST_MEM
891132718Skan#define TARGET_CANNOT_FORCE_CONST_MEM rs6000_tls_referenced_p
892132718Skan
89390075Sobrien#undef TARGET_ASM_FUNCTION_PROLOGUE
89490075Sobrien#define TARGET_ASM_FUNCTION_PROLOGUE rs6000_output_function_prologue
89590075Sobrien#undef TARGET_ASM_FUNCTION_EPILOGUE
89690075Sobrien#define TARGET_ASM_FUNCTION_EPILOGUE rs6000_output_function_epilogue
89790075Sobrien
898132718Skan#undef  TARGET_SCHED_VARIABLE_ISSUE
899132718Skan#define TARGET_SCHED_VARIABLE_ISSUE rs6000_variable_issue
900132718Skan
90190075Sobrien#undef TARGET_SCHED_ISSUE_RATE
90290075Sobrien#define TARGET_SCHED_ISSUE_RATE rs6000_issue_rate
90390075Sobrien#undef TARGET_SCHED_ADJUST_COST
90490075Sobrien#define TARGET_SCHED_ADJUST_COST rs6000_adjust_cost
90590075Sobrien#undef TARGET_SCHED_ADJUST_PRIORITY
90690075Sobrien#define TARGET_SCHED_ADJUST_PRIORITY rs6000_adjust_priority
907169689Skan#undef TARGET_SCHED_IS_COSTLY_DEPENDENCE
908132718Skan#define TARGET_SCHED_IS_COSTLY_DEPENDENCE rs6000_is_costly_dependence
909132718Skan#undef TARGET_SCHED_FINISH
910132718Skan#define TARGET_SCHED_FINISH rs6000_sched_finish
91190075Sobrien
912132718Skan#undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD
913132718Skan#define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD rs6000_use_sched_lookahead
914132718Skan
915169689Skan#undef TARGET_VECTORIZE_BUILTIN_MASK_FOR_LOAD
916169689Skan#define TARGET_VECTORIZE_BUILTIN_MASK_FOR_LOAD rs6000_builtin_mask_for_load
917169689Skan
91890075Sobrien#undef TARGET_INIT_BUILTINS
91990075Sobrien#define TARGET_INIT_BUILTINS rs6000_init_builtins
92090075Sobrien
92190075Sobrien#undef TARGET_EXPAND_BUILTIN
92290075Sobrien#define TARGET_EXPAND_BUILTIN rs6000_expand_builtin
92390075Sobrien
924146895Skan#undef TARGET_MANGLE_FUNDAMENTAL_TYPE
925146895Skan#define TARGET_MANGLE_FUNDAMENTAL_TYPE rs6000_mangle_fundamental_type
926146895Skan
927132718Skan#undef TARGET_INIT_LIBFUNCS
928132718Skan#define TARGET_INIT_LIBFUNCS rs6000_init_libfuncs
929132718Skan
930132718Skan#if TARGET_MACHO
931117395Skan#undef TARGET_BINDS_LOCAL_P
932169689Skan#define TARGET_BINDS_LOCAL_P darwin_binds_local_p
933132718Skan#endif
93490075Sobrien
935169689Skan#undef TARGET_MS_BITFIELD_LAYOUT_P
936169689Skan#define TARGET_MS_BITFIELD_LAYOUT_P rs6000_ms_bitfield_layout_p
937169689Skan
938117395Skan#undef TARGET_ASM_OUTPUT_MI_THUNK
939117395Skan#define TARGET_ASM_OUTPUT_MI_THUNK rs6000_output_mi_thunk
940117395Skan
941117395Skan#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
942132718Skan#define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_tree_hwi_hwi_tree_true
943117395Skan
944132718Skan#undef TARGET_FUNCTION_OK_FOR_SIBCALL
945132718Skan#define TARGET_FUNCTION_OK_FOR_SIBCALL rs6000_function_ok_for_sibcall
946132718Skan
947169689Skan#undef TARGET_INVALID_WITHIN_DOLOOP
948169689Skan#define TARGET_INVALID_WITHIN_DOLOOP rs6000_invalid_within_doloop
949169689Skan
950132718Skan#undef TARGET_RTX_COSTS
951132718Skan#define TARGET_RTX_COSTS rs6000_rtx_costs
952132718Skan#undef TARGET_ADDRESS_COST
953132718Skan#define TARGET_ADDRESS_COST hook_int_rtx_0
954132718Skan
955132718Skan#undef TARGET_VECTOR_OPAQUE_P
956169689Skan#define TARGET_VECTOR_OPAQUE_P rs6000_is_opaque_type
957132718Skan
958132718Skan#undef TARGET_DWARF_REGISTER_SPAN
959132718Skan#define TARGET_DWARF_REGISTER_SPAN rs6000_dwarf_register_span
960132718Skan
961132718Skan/* On rs6000, function arguments are promoted, as are function return
962132718Skan   values.  */
963132718Skan#undef TARGET_PROMOTE_FUNCTION_ARGS
964132718Skan#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true
965132718Skan#undef TARGET_PROMOTE_FUNCTION_RETURN
966132718Skan#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
967132718Skan
968132718Skan#undef TARGET_RETURN_IN_MEMORY
969132718Skan#define TARGET_RETURN_IN_MEMORY rs6000_return_in_memory
970132718Skan
971132718Skan#undef TARGET_SETUP_INCOMING_VARARGS
972132718Skan#define TARGET_SETUP_INCOMING_VARARGS setup_incoming_varargs
973132718Skan
974132718Skan/* Always strict argument naming on rs6000.  */
975132718Skan#undef TARGET_STRICT_ARGUMENT_NAMING
976132718Skan#define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true
977132718Skan#undef TARGET_PRETEND_OUTGOING_VARARGS_NAMED
978132718Skan#define TARGET_PRETEND_OUTGOING_VARARGS_NAMED hook_bool_CUMULATIVE_ARGS_true
979132718Skan#undef TARGET_SPLIT_COMPLEX_ARG
980132718Skan#define TARGET_SPLIT_COMPLEX_ARG hook_bool_tree_true
981169689Skan#undef TARGET_MUST_PASS_IN_STACK
982169689Skan#define TARGET_MUST_PASS_IN_STACK rs6000_must_pass_in_stack
983169689Skan#undef TARGET_PASS_BY_REFERENCE
984169689Skan#define TARGET_PASS_BY_REFERENCE rs6000_pass_by_reference
985169689Skan#undef TARGET_ARG_PARTIAL_BYTES
986169689Skan#define TARGET_ARG_PARTIAL_BYTES rs6000_arg_partial_bytes
987132718Skan
988132718Skan#undef TARGET_BUILD_BUILTIN_VA_LIST
989132718Skan#define TARGET_BUILD_BUILTIN_VA_LIST rs6000_build_builtin_va_list
990132718Skan
991169689Skan#undef TARGET_GIMPLIFY_VA_ARG_EXPR
992169689Skan#define TARGET_GIMPLIFY_VA_ARG_EXPR rs6000_gimplify_va_arg
993169689Skan
994169689Skan#undef TARGET_EH_RETURN_FILTER_MODE
995169689Skan#define TARGET_EH_RETURN_FILTER_MODE rs6000_eh_return_filter_mode
996169689Skan
997169689Skan#undef TARGET_SCALAR_MODE_SUPPORTED_P
998169689Skan#define TARGET_SCALAR_MODE_SUPPORTED_P rs6000_scalar_mode_supported_p
999169689Skan
1000169689Skan#undef TARGET_VECTOR_MODE_SUPPORTED_P
1001169689Skan#define TARGET_VECTOR_MODE_SUPPORTED_P rs6000_vector_mode_supported_p
1002169689Skan
1003169689Skan#undef TARGET_INVALID_ARG_FOR_UNPROTOTYPED_FN
1004169689Skan#define TARGET_INVALID_ARG_FOR_UNPROTOTYPED_FN invalid_arg_for_unprototyped_fn
1005169689Skan
1006169689Skan#undef TARGET_HANDLE_OPTION
1007169689Skan#define TARGET_HANDLE_OPTION rs6000_handle_option
1008169689Skan
1009169689Skan#undef TARGET_DEFAULT_TARGET_FLAGS
1010169689Skan#define TARGET_DEFAULT_TARGET_FLAGS \
1011169689Skan  (TARGET_DEFAULT)
1012169689Skan
1013169689Skan#undef TARGET_STACK_PROTECT_FAIL
1014169689Skan#define TARGET_STACK_PROTECT_FAIL rs6000_stack_protect_fail
1015169689Skan
1016169689Skan/* MPC604EUM 3.5.2 Weak Consistency between Multiple Processors
1017169689Skan   The PowerPC architecture requires only weak consistency among
1018169689Skan   processors--that is, memory accesses between processors need not be
1019169689Skan   sequentially consistent and memory accesses among processors can occur
1020169689Skan   in any order. The ability to order memory accesses weakly provides
1021169689Skan   opportunities for more efficient use of the system bus. Unless a
1022169689Skan   dependency exists, the 604e allows read operations to precede store
1023169689Skan   operations.  */
1024169689Skan#undef TARGET_RELAXED_ORDERING
1025169689Skan#define TARGET_RELAXED_ORDERING true
1026169689Skan
1027169689Skan#ifdef HAVE_AS_TLS
1028169689Skan#undef TARGET_ASM_OUTPUT_DWARF_DTPREL
1029169689Skan#define TARGET_ASM_OUTPUT_DWARF_DTPREL rs6000_output_dwarf_dtprel
1030169689Skan#endif
1031169689Skan
1032169689Skan/* Use a 32-bit anchor range.  This leads to sequences like:
1033169689Skan
1034169689Skan	addis	tmp,anchor,high
1035169689Skan	add	dest,tmp,low
1036169689Skan
1037169689Skan   where tmp itself acts as an anchor, and can be shared between
1038169689Skan   accesses to the same 64k page.  */
1039169689Skan#undef TARGET_MIN_ANCHOR_OFFSET
1040169689Skan#define TARGET_MIN_ANCHOR_OFFSET -0x7fffffff - 1
1041169689Skan#undef TARGET_MAX_ANCHOR_OFFSET
1042169689Skan#define TARGET_MAX_ANCHOR_OFFSET 0x7fffffff
1043169689Skan#undef TARGET_USE_BLOCKS_FOR_CONSTANT_P
1044169689Skan#define TARGET_USE_BLOCKS_FOR_CONSTANT_P rs6000_use_blocks_for_constant_p
1045169689Skan
104690075Sobrienstruct gcc_target targetm = TARGET_INITIALIZER;
104790075Sobrien
1048169689Skan
1049169689Skan/* Value is 1 if hard register REGNO can hold a value of machine-mode
1050169689Skan   MODE.  */
1051169689Skanstatic int
1052169689Skanrs6000_hard_regno_mode_ok (int regno, enum machine_mode mode)
1053169689Skan{
1054169689Skan  /* The GPRs can hold any mode, but values bigger than one register
1055169689Skan     cannot go past R31.  */
1056169689Skan  if (INT_REGNO_P (regno))
1057169689Skan    return INT_REGNO_P (regno + HARD_REGNO_NREGS (regno, mode) - 1);
1058169689Skan
1059169689Skan  /* The float registers can only hold floating modes and DImode.
1060169689Skan     This also excludes decimal float modes.  */
1061169689Skan  if (FP_REGNO_P (regno))
1062169689Skan    return
1063169689Skan      (SCALAR_FLOAT_MODE_P (mode)
1064169689Skan       && !DECIMAL_FLOAT_MODE_P (mode)
1065169689Skan       && FP_REGNO_P (regno + HARD_REGNO_NREGS (regno, mode) - 1))
1066169689Skan      || (GET_MODE_CLASS (mode) == MODE_INT
1067169689Skan	  && GET_MODE_SIZE (mode) == UNITS_PER_FP_WORD);
1068169689Skan
1069169689Skan  /* The CR register can only hold CC modes.  */
1070169689Skan  if (CR_REGNO_P (regno))
1071169689Skan    return GET_MODE_CLASS (mode) == MODE_CC;
1072169689Skan
1073169689Skan  if (XER_REGNO_P (regno))
1074169689Skan    return mode == PSImode;
1075169689Skan
1076169689Skan  /* AltiVec only in AldyVec registers.  */
1077169689Skan  if (ALTIVEC_REGNO_P (regno))
1078169689Skan    return ALTIVEC_VECTOR_MODE (mode);
1079169689Skan
1080169689Skan  /* ...but GPRs can hold SIMD data on the SPE in one register.  */
1081169689Skan  if (SPE_SIMD_REGNO_P (regno) && TARGET_SPE && SPE_VECTOR_MODE (mode))
1082169689Skan    return 1;
1083169689Skan
1084169689Skan  /* We cannot put TImode anywhere except general register and it must be
1085169689Skan     able to fit within the register set.  */
1086169689Skan
1087169689Skan  return GET_MODE_SIZE (mode) <= UNITS_PER_WORD;
1088169689Skan}
1089169689Skan
1090169689Skan/* Initialize rs6000_hard_regno_mode_ok_p table.  */
1091169689Skanstatic void
1092169689Skanrs6000_init_hard_regno_mode_ok (void)
1093169689Skan{
1094169689Skan  int r, m;
1095169689Skan
1096169689Skan  for (r = 0; r < FIRST_PSEUDO_REGISTER; ++r)
1097169689Skan    for (m = 0; m < NUM_MACHINE_MODES; ++m)
1098169689Skan      if (rs6000_hard_regno_mode_ok (r, m))
1099169689Skan	rs6000_hard_regno_mode_ok_p[m][r] = true;
1100169689Skan}
1101169689Skan
1102169689Skan/* If not otherwise specified by a target, make 'long double' equivalent to
1103169689Skan   'double'.  */
1104169689Skan
1105169689Skan#ifndef RS6000_DEFAULT_LONG_DOUBLE_SIZE
1106169689Skan#define RS6000_DEFAULT_LONG_DOUBLE_SIZE 64
1107169689Skan#endif
1108169689Skan
110990075Sobrien/* Override command line options.  Mostly we process the processor
111090075Sobrien   type and sometimes adjust other TARGET_ options.  */
111190075Sobrien
111290075Sobrienvoid
1113132718Skanrs6000_override_options (const char *default_cpu)
111490075Sobrien{
111590075Sobrien  size_t i, j;
111690075Sobrien  struct rs6000_cpu_select *ptr;
1117132718Skan  int set_masks;
111890075Sobrien
1119132718Skan  /* Simplifications for entries below.  */
112090075Sobrien
1121132718Skan  enum {
1122132718Skan    POWERPC_BASE_MASK = MASK_POWERPC | MASK_NEW_MNEMONICS,
1123132718Skan    POWERPC_7400_MASK = POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_ALTIVEC
1124132718Skan  };
112590075Sobrien
1126132718Skan  /* This table occasionally claims that a processor does not support
1127132718Skan     a particular feature even though it does, but the feature is slower
1128132718Skan     than the alternative.  Thus, it shouldn't be relied on as a
1129169689Skan     complete description of the processor's support.
1130132718Skan
1131132718Skan     Please keep this list in order, and don't forget to update the
1132132718Skan     documentation in invoke.texi when adding a new processor or
1133132718Skan     flag.  */
113490075Sobrien  static struct ptt
113590075Sobrien    {
113690075Sobrien      const char *const name;		/* Canonical processor name.  */
113790075Sobrien      const enum processor_type processor; /* Processor type enum value.  */
113890075Sobrien      const int target_enable;	/* Target flags to enable.  */
113990075Sobrien    } const processor_target_table[]
1140132718Skan      = {{"401", PROCESSOR_PPC403, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
1141132718Skan	 {"403", PROCESSOR_PPC403,
1142132718Skan	  POWERPC_BASE_MASK | MASK_SOFT_FLOAT | MASK_STRICT_ALIGN},
1143169689Skan	 {"405", PROCESSOR_PPC405,
1144169689Skan	  POWERPC_BASE_MASK | MASK_SOFT_FLOAT | MASK_MULHW | MASK_DLMZB},
1145169689Skan	 {"405fp", PROCESSOR_PPC405,
1146169689Skan	  POWERPC_BASE_MASK | MASK_MULHW | MASK_DLMZB},
1147169689Skan	 {"440", PROCESSOR_PPC440,
1148169689Skan	  POWERPC_BASE_MASK | MASK_SOFT_FLOAT | MASK_MULHW | MASK_DLMZB},
1149169689Skan	 {"440fp", PROCESSOR_PPC440,
1150169689Skan	  POWERPC_BASE_MASK | MASK_MULHW | MASK_DLMZB},
1151132718Skan	 {"505", PROCESSOR_MPCCORE, POWERPC_BASE_MASK},
1152132718Skan	 {"601", PROCESSOR_PPC601,
1153132718Skan	  MASK_POWER | POWERPC_BASE_MASK | MASK_MULTIPLE | MASK_STRING},
1154132718Skan	 {"602", PROCESSOR_PPC603, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
1155132718Skan	 {"603", PROCESSOR_PPC603, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
1156132718Skan	 {"603e", PROCESSOR_PPC603, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
1157132718Skan	 {"604", PROCESSOR_PPC604, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
1158132718Skan	 {"604e", PROCESSOR_PPC604e, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
1159132718Skan	 {"620", PROCESSOR_PPC620,
1160132718Skan	  POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64},
1161132718Skan	 {"630", PROCESSOR_PPC630,
1162132718Skan	  POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64},
1163132718Skan	 {"740", PROCESSOR_PPC750, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
1164132718Skan	 {"7400", PROCESSOR_PPC7400, POWERPC_7400_MASK},
1165132718Skan	 {"7450", PROCESSOR_PPC7450, POWERPC_7400_MASK},
1166132718Skan	 {"750", PROCESSOR_PPC750, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
1167132718Skan	 {"801", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
1168132718Skan	 {"821", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
1169132718Skan	 {"823", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
1170169689Skan	 {"8540", PROCESSOR_PPC8540,
1171169689Skan	  POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_STRICT_ALIGN},
1172169689Skan	 /* 8548 has a dummy entry for now.  */
1173169689Skan	 {"8548", PROCESSOR_PPC8540,
1174169689Skan	  POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_STRICT_ALIGN},
1175132718Skan	 {"860", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
1176132718Skan	 {"970", PROCESSOR_POWER4,
1177132718Skan	  POWERPC_7400_MASK | MASK_PPC_GPOPT | MASK_MFCRF | MASK_POWERPC64},
1178132718Skan	 {"common", PROCESSOR_COMMON, MASK_NEW_MNEMONICS},
1179132718Skan	 {"ec603e", PROCESSOR_PPC603, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
1180132718Skan	 {"G3", PROCESSOR_PPC750, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
1181132718Skan	 {"G4",  PROCESSOR_PPC7450, POWERPC_7400_MASK},
1182132718Skan	 {"G5", PROCESSOR_POWER4,
1183132718Skan	  POWERPC_7400_MASK | MASK_PPC_GPOPT | MASK_MFCRF | MASK_POWERPC64},
1184132718Skan	 {"power", PROCESSOR_POWER, MASK_POWER | MASK_MULTIPLE | MASK_STRING},
118590075Sobrien	 {"power2", PROCESSOR_POWER,
1186132718Skan	  MASK_POWER | MASK_POWER2 | MASK_MULTIPLE | MASK_STRING},
118790075Sobrien	 {"power3", PROCESSOR_PPC630,
1188132718Skan	  POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64},
1189117395Skan	 {"power4", PROCESSOR_POWER4,
1190132718Skan	  POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_MFCRF | MASK_POWERPC64},
1191132718Skan	 {"power5", PROCESSOR_POWER5,
1192169689Skan	  POWERPC_BASE_MASK | MASK_POWERPC64 | MASK_PPC_GFXOPT
1193169689Skan	  | MASK_MFCRF | MASK_POPCNTB},
1194169689Skan	 {"power5+", PROCESSOR_POWER5,
1195169689Skan	  POWERPC_BASE_MASK | MASK_POWERPC64 | MASK_PPC_GFXOPT
1196169689Skan	  | MASK_MFCRF | MASK_POPCNTB | MASK_FPRND},
1197169689Skan 	 {"power6", PROCESSOR_POWER5,
1198169689Skan	  POWERPC_7400_MASK | MASK_POWERPC64 | MASK_MFCRF | MASK_POPCNTB
1199169689Skan	  | MASK_FPRND},
1200132718Skan	 {"powerpc", PROCESSOR_POWERPC, POWERPC_BASE_MASK},
120190075Sobrien	 {"powerpc64", PROCESSOR_POWERPC64,
1202169689Skan	  POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64},
1203132718Skan	 {"rios", PROCESSOR_RIOS1, MASK_POWER | MASK_MULTIPLE | MASK_STRING},
1204132718Skan	 {"rios1", PROCESSOR_RIOS1, MASK_POWER | MASK_MULTIPLE | MASK_STRING},
120590075Sobrien	 {"rios2", PROCESSOR_RIOS2,
1206132718Skan	  MASK_POWER | MASK_POWER2 | MASK_MULTIPLE | MASK_STRING},
1207132718Skan	 {"rsc", PROCESSOR_PPC601, MASK_POWER | MASK_MULTIPLE | MASK_STRING},
1208132718Skan	 {"rsc1", PROCESSOR_PPC601, MASK_POWER | MASK_MULTIPLE | MASK_STRING},
1209169689Skan	 {"rs64", PROCESSOR_RS64A,
1210169689Skan	  POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64}
1211132718Skan      };
121290075Sobrien
1213117395Skan  const size_t ptt_size = ARRAY_SIZE (processor_target_table);
121490075Sobrien
1215132718Skan  /* Some OSs don't support saving the high part of 64-bit registers on
1216132718Skan     context switch.  Other OSs don't support saving Altivec registers.
1217132718Skan     On those OSs, we don't touch the MASK_POWERPC64 or MASK_ALTIVEC
1218132718Skan     settings; if the user wants either, the user must explicitly specify
1219132718Skan     them and we won't interfere with the user's specification.  */
122090075Sobrien
1221132718Skan  enum {
1222132718Skan    POWER_MASKS = MASK_POWER | MASK_POWER2 | MASK_MULTIPLE | MASK_STRING,
1223169689Skan    POWERPC_MASKS = (POWERPC_BASE_MASK | MASK_PPC_GPOPT | MASK_STRICT_ALIGN
1224132718Skan		     | MASK_PPC_GFXOPT | MASK_POWERPC64 | MASK_ALTIVEC
1225169689Skan		     | MASK_MFCRF | MASK_POPCNTB | MASK_FPRND | MASK_MULHW
1226169689Skan		     | MASK_DLMZB)
1227132718Skan  };
1228169689Skan
1229169689Skan  rs6000_init_hard_regno_mode_ok ();
1230169689Skan
1231169689Skan  set_masks = POWER_MASKS | POWERPC_MASKS | MASK_SOFT_FLOAT;
1232132718Skan#ifdef OS_MISSING_POWERPC64
1233132718Skan  if (OS_MISSING_POWERPC64)
1234132718Skan    set_masks &= ~MASK_POWERPC64;
1235132718Skan#endif
1236132718Skan#ifdef OS_MISSING_ALTIVEC
1237132718Skan  if (OS_MISSING_ALTIVEC)
1238132718Skan    set_masks &= ~MASK_ALTIVEC;
1239132718Skan#endif
1240132718Skan
1241146895Skan  /* Don't override by the processor default if given explicitly.  */
1242146895Skan  set_masks &= ~target_flags_explicit;
1243132718Skan
124490075Sobrien  /* Identify the processor type.  */
124590075Sobrien  rs6000_select[0].string = default_cpu;
124690075Sobrien  rs6000_cpu = TARGET_POWERPC64 ? PROCESSOR_DEFAULT64 : PROCESSOR_DEFAULT;
124790075Sobrien
124890075Sobrien  for (i = 0; i < ARRAY_SIZE (rs6000_select); i++)
124990075Sobrien    {
125090075Sobrien      ptr = &rs6000_select[i];
125190075Sobrien      if (ptr->string != (char *)0 && ptr->string[0] != '\0')
125290075Sobrien	{
125390075Sobrien	  for (j = 0; j < ptt_size; j++)
125490075Sobrien	    if (! strcmp (ptr->string, processor_target_table[j].name))
125590075Sobrien	      {
125690075Sobrien		if (ptr->set_tune_p)
125790075Sobrien		  rs6000_cpu = processor_target_table[j].processor;
125890075Sobrien
125990075Sobrien		if (ptr->set_arch_p)
126090075Sobrien		  {
1261132718Skan		    target_flags &= ~set_masks;
1262132718Skan		    target_flags |= (processor_target_table[j].target_enable
1263132718Skan				     & set_masks);
126490075Sobrien		  }
126590075Sobrien		break;
126690075Sobrien	      }
126790075Sobrien
126890075Sobrien	  if (j == ptt_size)
126990075Sobrien	    error ("bad value (%s) for %s switch", ptr->string, ptr->name);
127090075Sobrien	}
127190075Sobrien    }
127290075Sobrien
1273132718Skan  if (TARGET_E500)
1274117395Skan    rs6000_isel = 1;
1275117395Skan
1276117395Skan  /* If we are optimizing big endian systems for space, use the load/store
1277117395Skan     multiple and string instructions.  */
127890075Sobrien  if (BYTES_BIG_ENDIAN && optimize_size)
1279132718Skan    target_flags |= ~target_flags_explicit & (MASK_MULTIPLE | MASK_STRING);
128090075Sobrien
128190075Sobrien  /* Don't allow -mmultiple or -mstring on little endian systems
128290075Sobrien     unless the cpu is a 750, because the hardware doesn't support the
128390075Sobrien     instructions used in little endian mode, and causes an alignment
128490075Sobrien     trap.  The 750 does not cause an alignment trap (except when the
128590075Sobrien     target is unaligned).  */
128690075Sobrien
1287132718Skan  if (!BYTES_BIG_ENDIAN && rs6000_cpu != PROCESSOR_PPC750)
128890075Sobrien    {
128990075Sobrien      if (TARGET_MULTIPLE)
129090075Sobrien	{
129190075Sobrien	  target_flags &= ~MASK_MULTIPLE;
1292132718Skan	  if ((target_flags_explicit & MASK_MULTIPLE) != 0)
1293169689Skan	    warning (0, "-mmultiple is not supported on little endian systems");
129490075Sobrien	}
129590075Sobrien
129690075Sobrien      if (TARGET_STRING)
129790075Sobrien	{
129890075Sobrien	  target_flags &= ~MASK_STRING;
1299132718Skan	  if ((target_flags_explicit & MASK_STRING) != 0)
1300169689Skan	    warning (0, "-mstring is not supported on little endian systems");
130190075Sobrien	}
130290075Sobrien    }
130390075Sobrien
130490075Sobrien  /* Set debug flags */
130590075Sobrien  if (rs6000_debug_name)
130690075Sobrien    {
130790075Sobrien      if (! strcmp (rs6000_debug_name, "all"))
130890075Sobrien	rs6000_debug_stack = rs6000_debug_arg = 1;
130990075Sobrien      else if (! strcmp (rs6000_debug_name, "stack"))
131090075Sobrien	rs6000_debug_stack = 1;
131190075Sobrien      else if (! strcmp (rs6000_debug_name, "arg"))
131290075Sobrien	rs6000_debug_arg = 1;
131390075Sobrien      else
131490075Sobrien	error ("unknown -mdebug-%s switch", rs6000_debug_name);
131590075Sobrien    }
131690075Sobrien
1317117395Skan  if (rs6000_traceback_name)
1318117395Skan    {
1319117395Skan      if (! strncmp (rs6000_traceback_name, "full", 4))
1320117395Skan	rs6000_traceback = traceback_full;
1321117395Skan      else if (! strncmp (rs6000_traceback_name, "part", 4))
1322117395Skan	rs6000_traceback = traceback_part;
1323117395Skan      else if (! strncmp (rs6000_traceback_name, "no", 2))
1324117395Skan	rs6000_traceback = traceback_none;
1325117395Skan      else
1326169689Skan	error ("unknown -mtraceback arg %qs; expecting %<full%>, %<partial%> or %<none%>",
1327117395Skan	       rs6000_traceback_name);
1328117395Skan    }
1329117395Skan
1330169689Skan  if (!rs6000_explicit_options.long_double)
1331169689Skan    rs6000_long_double_type_size = RS6000_DEFAULT_LONG_DOUBLE_SIZE;
133290075Sobrien
1333169689Skan#ifndef POWERPC_LINUX
1334169689Skan  if (!rs6000_explicit_options.ieee)
1335169689Skan    rs6000_ieeequad = 1;
1336169689Skan#endif
1337169689Skan
1338132718Skan  /* Set Altivec ABI as default for powerpc64 linux.  */
1339132718Skan  if (TARGET_ELF && TARGET_64BIT)
1340132718Skan    {
1341132718Skan      rs6000_altivec_abi = 1;
1342169689Skan      TARGET_ALTIVEC_VRSAVE = 1;
1343132718Skan    }
1344132718Skan
1345169689Skan  /* Set the Darwin64 ABI as default for 64-bit Darwin.  */
1346169689Skan  if (DEFAULT_ABI == ABI_DARWIN && TARGET_64BIT)
1347169689Skan    {
1348169689Skan      rs6000_darwin64_abi = 1;
1349169689Skan#if TARGET_MACHO
1350169689Skan      darwin_one_byte_bool = 1;
1351169689Skan#endif
1352169689Skan      /* Default to natural alignment, for better performance.  */
1353169689Skan      rs6000_alignment_flags = MASK_ALIGN_NATURAL;
1354169689Skan    }
135590075Sobrien
1356169689Skan  /* Place FP constants in the constant pool instead of TOC
1357169689Skan     if section anchors enabled.  */
1358169689Skan  if (flag_section_anchors)
1359169689Skan    TARGET_NO_FP_IN_TOC = 1;
136090075Sobrien
1361132718Skan  /* Handle -mtls-size option.  */
1362132718Skan  rs6000_parse_tls_size_option ();
1363132718Skan
136490075Sobrien#ifdef SUBTARGET_OVERRIDE_OPTIONS
136590075Sobrien  SUBTARGET_OVERRIDE_OPTIONS;
136690075Sobrien#endif
136790075Sobrien#ifdef SUBSUBTARGET_OVERRIDE_OPTIONS
136890075Sobrien  SUBSUBTARGET_OVERRIDE_OPTIONS;
136990075Sobrien#endif
1370169689Skan#ifdef SUB3TARGET_OVERRIDE_OPTIONS
1371169689Skan  SUB3TARGET_OVERRIDE_OPTIONS;
1372169689Skan#endif
137390075Sobrien
1374132718Skan  if (TARGET_E500)
1375132718Skan    {
1376132718Skan      if (TARGET_ALTIVEC)
1377169689Skan	error ("AltiVec and E500 instructions cannot coexist");
1378132718Skan
1379132718Skan      /* The e500 does not have string instructions, and we set
1380132718Skan	 MASK_STRING above when optimizing for size.  */
1381132718Skan      if ((target_flags & MASK_STRING) != 0)
1382132718Skan	target_flags = target_flags & ~MASK_STRING;
1383132718Skan    }
1384132718Skan  else if (rs6000_select[1].string != NULL)
1385132718Skan    {
1386132718Skan      /* For the powerpc-eabispe configuration, we set all these by
1387132718Skan	 default, so let's unset them if we manually set another
1388132718Skan	 CPU that is not the E500.  */
1389169689Skan      if (!rs6000_explicit_options.abi)
1390132718Skan	rs6000_spe_abi = 0;
1391169689Skan      if (!rs6000_explicit_options.spe)
1392132718Skan	rs6000_spe = 0;
1393169689Skan      if (!rs6000_explicit_options.float_gprs)
1394132718Skan	rs6000_float_gprs = 0;
1395169689Skan      if (!rs6000_explicit_options.isel)
1396132718Skan	rs6000_isel = 0;
1397169689Skan      if (!rs6000_explicit_options.long_double)
1398169689Skan	rs6000_long_double_type_size = RS6000_DEFAULT_LONG_DOUBLE_SIZE;
1399132718Skan    }
1400132718Skan
1401132718Skan  rs6000_always_hint = (rs6000_cpu != PROCESSOR_POWER4
1402132718Skan			&& rs6000_cpu != PROCESSOR_POWER5);
1403132718Skan  rs6000_sched_groups = (rs6000_cpu == PROCESSOR_POWER4
1404132718Skan			 || rs6000_cpu == PROCESSOR_POWER5);
1405132718Skan
1406132718Skan  rs6000_sched_restricted_insns_priority
1407132718Skan    = (rs6000_sched_groups ? 1 : 0);
1408132718Skan
1409132718Skan  /* Handle -msched-costly-dep option.  */
1410132718Skan  rs6000_sched_costly_dep
1411132718Skan    = (rs6000_sched_groups ? store_to_load_dep_costly : no_dep_costly);
1412169689Skan
1413132718Skan  if (rs6000_sched_costly_dep_str)
1414132718Skan    {
1415169689Skan      if (! strcmp (rs6000_sched_costly_dep_str, "no"))
1416169689Skan	rs6000_sched_costly_dep = no_dep_costly;
1417132718Skan      else if (! strcmp (rs6000_sched_costly_dep_str, "all"))
1418169689Skan	rs6000_sched_costly_dep = all_deps_costly;
1419132718Skan      else if (! strcmp (rs6000_sched_costly_dep_str, "true_store_to_load"))
1420169689Skan	rs6000_sched_costly_dep = true_store_to_load_dep_costly;
1421132718Skan      else if (! strcmp (rs6000_sched_costly_dep_str, "store_to_load"))
1422169689Skan	rs6000_sched_costly_dep = store_to_load_dep_costly;
1423169689Skan      else
1424169689Skan	rs6000_sched_costly_dep = atoi (rs6000_sched_costly_dep_str);
1425132718Skan    }
1426132718Skan
1427132718Skan  /* Handle -minsert-sched-nops option.  */
1428132718Skan  rs6000_sched_insert_nops
1429132718Skan    = (rs6000_sched_groups ? sched_finish_regroup_exact : sched_finish_none);
1430169689Skan
1431132718Skan  if (rs6000_sched_insert_nops_str)
1432132718Skan    {
1433132718Skan      if (! strcmp (rs6000_sched_insert_nops_str, "no"))
1434169689Skan	rs6000_sched_insert_nops = sched_finish_none;
1435132718Skan      else if (! strcmp (rs6000_sched_insert_nops_str, "pad"))
1436169689Skan	rs6000_sched_insert_nops = sched_finish_pad_groups;
1437132718Skan      else if (! strcmp (rs6000_sched_insert_nops_str, "regroup_exact"))
1438169689Skan	rs6000_sched_insert_nops = sched_finish_regroup_exact;
1439132718Skan      else
1440169689Skan	rs6000_sched_insert_nops = atoi (rs6000_sched_insert_nops_str);
1441132718Skan    }
1442132718Skan
1443117395Skan#ifdef TARGET_REGNAMES
1444117395Skan  /* If the user desires alternate register names, copy in the
1445117395Skan     alternate names now.  */
1446117395Skan  if (TARGET_REGNAMES)
1447117395Skan    memcpy (rs6000_reg_names, alt_reg_names, sizeof (rs6000_reg_names));
1448117395Skan#endif
1449117395Skan
1450169689Skan  /* Set aix_struct_return last, after the ABI is determined.
145190075Sobrien     If -maix-struct-return or -msvr4-struct-return was explicitly
145290075Sobrien     used, don't override with the ABI default.  */
1453169689Skan  if (!rs6000_explicit_options.aix_struct_ret)
1454169689Skan    aix_struct_return = (DEFAULT_ABI != ABI_V4 || DRAFT_V4_STRUCT_RET);
145590075Sobrien
1456169689Skan  if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
1457132718Skan    REAL_MODE_FORMAT (TFmode) = &ibm_extended_format;
1458117395Skan
1459169689Skan  if (TARGET_TOC)
146090075Sobrien    ASM_GENERATE_INTERNAL_LABEL (toc_label_name, "LCTOC", 1);
146190075Sobrien
146290075Sobrien  /* We can only guarantee the availability of DI pseudo-ops when
146390075Sobrien     assembling for 64-bit targets.  */
146490075Sobrien  if (!TARGET_64BIT)
146590075Sobrien    {
146690075Sobrien      targetm.asm_out.aligned_op.di = NULL;
146790075Sobrien      targetm.asm_out.unaligned_op.di = NULL;
146890075Sobrien    }
146990075Sobrien
1470169689Skan  /* Set branch target alignment, if not optimizing for size.  */
1471169689Skan  if (!optimize_size)
1472169689Skan    {
1473169689Skan      if (rs6000_sched_groups)
1474169689Skan	{
1475169689Skan	  if (align_functions <= 0)
1476169689Skan	    align_functions = 16;
1477169689Skan	  if (align_jumps <= 0)
1478169689Skan	    align_jumps = 16;
1479169689Skan	  if (align_loops <= 0)
1480169689Skan	    align_loops = 16;
1481169689Skan	}
1482169689Skan      if (align_jumps_max_skip <= 0)
1483169689Skan	align_jumps_max_skip = 15;
1484169689Skan      if (align_loops_max_skip <= 0)
1485169689Skan	align_loops_max_skip = 15;
1486169689Skan    }
1487132718Skan
148890075Sobrien  /* Arrange to save and restore machine status around nested functions.  */
148990075Sobrien  init_machine_status = rs6000_init_machine_status;
1490132718Skan
1491132718Skan  /* We should always be splitting complex arguments, but we can't break
1492132718Skan     Linux and Darwin ABIs at the moment.  For now, only AIX is fixed.  */
1493132718Skan  if (DEFAULT_ABI != ABI_AIX)
1494132718Skan    targetm.calls.split_complex_arg = NULL;
1495169689Skan
1496169689Skan  /* Initialize rs6000_cost with the appropriate target costs.  */
1497169689Skan  if (optimize_size)
1498169689Skan    rs6000_cost = TARGET_POWERPC64 ? &size64_cost : &size32_cost;
1499169689Skan  else
1500169689Skan    switch (rs6000_cpu)
1501169689Skan      {
1502169689Skan      case PROCESSOR_RIOS1:
1503169689Skan	rs6000_cost = &rios1_cost;
1504169689Skan	break;
1505169689Skan
1506169689Skan      case PROCESSOR_RIOS2:
1507169689Skan	rs6000_cost = &rios2_cost;
1508169689Skan	break;
1509169689Skan
1510169689Skan      case PROCESSOR_RS64A:
1511169689Skan	rs6000_cost = &rs64a_cost;
1512169689Skan	break;
1513169689Skan
1514169689Skan      case PROCESSOR_MPCCORE:
1515169689Skan	rs6000_cost = &mpccore_cost;
1516169689Skan	break;
1517169689Skan
1518169689Skan      case PROCESSOR_PPC403:
1519169689Skan	rs6000_cost = &ppc403_cost;
1520169689Skan	break;
1521169689Skan
1522169689Skan      case PROCESSOR_PPC405:
1523169689Skan	rs6000_cost = &ppc405_cost;
1524169689Skan	break;
1525169689Skan
1526169689Skan      case PROCESSOR_PPC440:
1527169689Skan	rs6000_cost = &ppc440_cost;
1528169689Skan	break;
1529169689Skan
1530169689Skan      case PROCESSOR_PPC601:
1531169689Skan	rs6000_cost = &ppc601_cost;
1532169689Skan	break;
1533169689Skan
1534169689Skan      case PROCESSOR_PPC603:
1535169689Skan	rs6000_cost = &ppc603_cost;
1536169689Skan	break;
1537169689Skan
1538169689Skan      case PROCESSOR_PPC604:
1539169689Skan	rs6000_cost = &ppc604_cost;
1540169689Skan	break;
1541169689Skan
1542169689Skan      case PROCESSOR_PPC604e:
1543169689Skan	rs6000_cost = &ppc604e_cost;
1544169689Skan	break;
1545169689Skan
1546169689Skan      case PROCESSOR_PPC620:
1547169689Skan	rs6000_cost = &ppc620_cost;
1548169689Skan	break;
1549169689Skan
1550169689Skan      case PROCESSOR_PPC630:
1551169689Skan	rs6000_cost = &ppc630_cost;
1552169689Skan	break;
1553169689Skan
1554169689Skan      case PROCESSOR_PPC750:
1555169689Skan      case PROCESSOR_PPC7400:
1556169689Skan	rs6000_cost = &ppc750_cost;
1557169689Skan	break;
1558169689Skan
1559169689Skan      case PROCESSOR_PPC7450:
1560169689Skan	rs6000_cost = &ppc7450_cost;
1561169689Skan	break;
1562169689Skan
1563169689Skan      case PROCESSOR_PPC8540:
1564169689Skan	rs6000_cost = &ppc8540_cost;
1565169689Skan	break;
1566169689Skan
1567169689Skan      case PROCESSOR_POWER4:
1568169689Skan      case PROCESSOR_POWER5:
1569169689Skan	rs6000_cost = &power4_cost;
1570169689Skan	break;
1571169689Skan
1572169689Skan      default:
1573169689Skan	gcc_unreachable ();
1574169689Skan      }
157590075Sobrien}
157690075Sobrien
1577169689Skan/* Implement targetm.vectorize.builtin_mask_for_load.  */
1578169689Skanstatic tree
1579169689Skanrs6000_builtin_mask_for_load (void)
1580169689Skan{
1581169689Skan  if (TARGET_ALTIVEC)
1582169689Skan    return altivec_builtin_mask_for_load;
1583169689Skan  else
1584169689Skan    return 0;
1585169689Skan}
1586169689Skan
1587132718Skan/* Handle generic options of the form -mfoo=yes/no.
1588132718Skan   NAME is the option name.
1589132718Skan   VALUE is the option value.
1590132718Skan   FLAG is the pointer to the flag where to store a 1 or 0, depending on
1591132718Skan   whether the option value is 'yes' or 'no' respectively.  */
1592117395Skanstatic void
1593132718Skanrs6000_parse_yes_no_option (const char *name, const char *value, int *flag)
1594117395Skan{
1595132718Skan  if (value == 0)
1596117395Skan    return;
1597132718Skan  else if (!strcmp (value, "yes"))
1598132718Skan    *flag = 1;
1599132718Skan  else if (!strcmp (value, "no"))
1600132718Skan    *flag = 0;
1601117395Skan  else
1602132718Skan    error ("unknown -m%s= option specified: '%s'", name, value);
1603117395Skan}
1604117395Skan
1605132718Skan/* Validate and record the size specified with the -mtls-size option.  */
1606132718Skan
1607132718Skanstatic void
1608132718Skanrs6000_parse_tls_size_option (void)
1609132718Skan{
1610132718Skan  if (rs6000_tls_size_string == 0)
1611132718Skan    return;
1612132718Skan  else if (strcmp (rs6000_tls_size_string, "16") == 0)
1613132718Skan    rs6000_tls_size = 16;
1614132718Skan  else if (strcmp (rs6000_tls_size_string, "32") == 0)
1615132718Skan    rs6000_tls_size = 32;
1616132718Skan  else if (strcmp (rs6000_tls_size_string, "64") == 0)
1617132718Skan    rs6000_tls_size = 64;
1618132718Skan  else
1619169689Skan    error ("bad value %qs for -mtls-size switch", rs6000_tls_size_string);
1620132718Skan}
1621132718Skan
162290075Sobrienvoid
1623132718Skanoptimization_options (int level ATTRIBUTE_UNUSED, int size ATTRIBUTE_UNUSED)
162490075Sobrien{
1625169689Skan  if (DEFAULT_ABI == ABI_DARWIN)
1626169689Skan    /* The Darwin libraries never set errno, so we might as well
1627169689Skan       avoid calling them when that's the only reason we would.  */
1628169689Skan    flag_errno_math = 0;
1629169689Skan
1630169689Skan  /* Double growth factor to counter reduced min jump length.  */
1631169689Skan  set_param_value ("max-grow-copy-bb-insns", 16);
1632169689Skan
1633169689Skan  /* Enable section anchors by default.
1634169689Skan     Skip section anchors for Objective C and Objective C++
1635169689Skan     until front-ends fixed.  */
1636169689Skan  if (!TARGET_MACHO && lang_hooks.name[4] != 'O')
1637169689Skan    flag_section_anchors = 1;
163890075Sobrien}
1639169689Skan
1640169689Skan/* Implement TARGET_HANDLE_OPTION.  */
1641169689Skan
1642169689Skanstatic bool
1643169689Skanrs6000_handle_option (size_t code, const char *arg, int value)
1644169689Skan{
1645169689Skan  switch (code)
1646169689Skan    {
1647169689Skan    case OPT_mno_power:
1648169689Skan      target_flags &= ~(MASK_POWER | MASK_POWER2
1649169689Skan			| MASK_MULTIPLE | MASK_STRING);
1650169689Skan      target_flags_explicit |= (MASK_POWER | MASK_POWER2
1651169689Skan				| MASK_MULTIPLE | MASK_STRING);
1652169689Skan      break;
1653169689Skan    case OPT_mno_powerpc:
1654169689Skan      target_flags &= ~(MASK_POWERPC | MASK_PPC_GPOPT
1655169689Skan			| MASK_PPC_GFXOPT | MASK_POWERPC64);
1656169689Skan      target_flags_explicit |= (MASK_POWERPC | MASK_PPC_GPOPT
1657169689Skan				| MASK_PPC_GFXOPT | MASK_POWERPC64);
1658169689Skan      break;
1659169689Skan    case OPT_mfull_toc:
1660169689Skan      target_flags &= ~MASK_MINIMAL_TOC;
1661169689Skan      TARGET_NO_FP_IN_TOC = 0;
1662169689Skan      TARGET_NO_SUM_IN_TOC = 0;
1663169689Skan      target_flags_explicit |= MASK_MINIMAL_TOC;
1664169689Skan#ifdef TARGET_USES_SYSV4_OPT
1665169689Skan      /* Note, V.4 no longer uses a normal TOC, so make -mfull-toc, be
1666169689Skan	 just the same as -mminimal-toc.  */
1667169689Skan      target_flags |= MASK_MINIMAL_TOC;
1668169689Skan      target_flags_explicit |= MASK_MINIMAL_TOC;
1669169689Skan#endif
1670169689Skan      break;
1671169689Skan
1672169689Skan#ifdef TARGET_USES_SYSV4_OPT
1673169689Skan    case OPT_mtoc:
1674169689Skan      /* Make -mtoc behave like -mminimal-toc.  */
1675169689Skan      target_flags |= MASK_MINIMAL_TOC;
1676169689Skan      target_flags_explicit |= MASK_MINIMAL_TOC;
1677169689Skan      break;
1678169689Skan#endif
1679169689Skan
1680169689Skan#ifdef TARGET_USES_AIX64_OPT
1681169689Skan    case OPT_maix64:
1682169689Skan#else
1683169689Skan    case OPT_m64:
1684169689Skan#endif
1685169689Skan      target_flags |= MASK_POWERPC64 | MASK_POWERPC;
1686169689Skan      target_flags |= ~target_flags_explicit & MASK_PPC_GFXOPT;
1687169689Skan      target_flags_explicit |= MASK_POWERPC64 | MASK_POWERPC;
1688169689Skan      break;
1689169689Skan
1690169689Skan#ifdef TARGET_USES_AIX64_OPT
1691169689Skan    case OPT_maix32:
1692169689Skan#else
1693169689Skan    case OPT_m32:
1694169689Skan#endif
1695169689Skan      target_flags &= ~MASK_POWERPC64;
1696169689Skan      target_flags_explicit |= MASK_POWERPC64;
1697169689Skan      break;
1698169689Skan
1699169689Skan    case OPT_minsert_sched_nops_:
1700169689Skan      rs6000_sched_insert_nops_str = arg;
1701169689Skan      break;
1702169689Skan
1703169689Skan    case OPT_mminimal_toc:
1704169689Skan      if (value == 1)
1705169689Skan	{
1706169689Skan	  TARGET_NO_FP_IN_TOC = 0;
1707169689Skan	  TARGET_NO_SUM_IN_TOC = 0;
1708169689Skan	}
1709169689Skan      break;
1710169689Skan
1711169689Skan    case OPT_mpower:
1712169689Skan      if (value == 1)
1713169689Skan	{
1714169689Skan	  target_flags |= (MASK_MULTIPLE | MASK_STRING);
1715169689Skan	  target_flags_explicit |= (MASK_MULTIPLE | MASK_STRING);
1716169689Skan	}
1717169689Skan      break;
1718169689Skan
1719169689Skan    case OPT_mpower2:
1720169689Skan      if (value == 1)
1721169689Skan	{
1722169689Skan	  target_flags |= (MASK_POWER | MASK_MULTIPLE | MASK_STRING);
1723169689Skan	  target_flags_explicit |= (MASK_POWER | MASK_MULTIPLE | MASK_STRING);
1724169689Skan	}
1725169689Skan      break;
1726169689Skan
1727169689Skan    case OPT_mpowerpc_gpopt:
1728169689Skan    case OPT_mpowerpc_gfxopt:
1729169689Skan      if (value == 1)
1730169689Skan	{
1731169689Skan	  target_flags |= MASK_POWERPC;
1732169689Skan	  target_flags_explicit |= MASK_POWERPC;
1733169689Skan	}
1734169689Skan      break;
1735169689Skan
1736169689Skan    case OPT_maix_struct_return:
1737169689Skan    case OPT_msvr4_struct_return:
1738169689Skan      rs6000_explicit_options.aix_struct_ret = true;
1739169689Skan      break;
1740169689Skan
1741169689Skan    case OPT_mvrsave_:
1742169689Skan      rs6000_parse_yes_no_option ("vrsave", arg, &(TARGET_ALTIVEC_VRSAVE));
1743169689Skan      break;
1744169689Skan
1745169689Skan    case OPT_misel_:
1746169689Skan      rs6000_explicit_options.isel = true;
1747169689Skan      rs6000_parse_yes_no_option ("isel", arg, &(rs6000_isel));
1748169689Skan      break;
1749169689Skan
1750169689Skan    case OPT_mspe_:
1751169689Skan      rs6000_explicit_options.spe = true;
1752169689Skan      rs6000_parse_yes_no_option ("spe", arg, &(rs6000_spe));
1753169689Skan      /* No SPE means 64-bit long doubles, even if an E500.  */
1754169689Skan      if (!rs6000_spe)
1755169689Skan	rs6000_long_double_type_size = 64;
1756169689Skan      break;
1757169689Skan
1758169689Skan    case OPT_mdebug_:
1759169689Skan      rs6000_debug_name = arg;
1760169689Skan      break;
1761169689Skan
1762169689Skan#ifdef TARGET_USES_SYSV4_OPT
1763169689Skan    case OPT_mcall_:
1764169689Skan      rs6000_abi_name = arg;
1765169689Skan      break;
1766169689Skan
1767169689Skan    case OPT_msdata_:
1768169689Skan      rs6000_sdata_name = arg;
1769169689Skan      break;
1770169689Skan
1771169689Skan    case OPT_mtls_size_:
1772169689Skan      rs6000_tls_size_string = arg;
1773169689Skan      break;
1774169689Skan
1775169689Skan    case OPT_mrelocatable:
1776169689Skan      if (value == 1)
1777169689Skan	{
1778169689Skan	  target_flags |= MASK_MINIMAL_TOC;
1779169689Skan	  target_flags_explicit |= MASK_MINIMAL_TOC;
1780169689Skan	  TARGET_NO_FP_IN_TOC = 1;
1781169689Skan	}
1782169689Skan      break;
1783169689Skan
1784169689Skan    case OPT_mrelocatable_lib:
1785169689Skan      if (value == 1)
1786169689Skan	{
1787169689Skan	  target_flags |= MASK_RELOCATABLE | MASK_MINIMAL_TOC;
1788169689Skan	  target_flags_explicit |= MASK_RELOCATABLE | MASK_MINIMAL_TOC;
1789169689Skan	  TARGET_NO_FP_IN_TOC = 1;
1790169689Skan	}
1791169689Skan      else
1792169689Skan	{
1793169689Skan	  target_flags &= ~MASK_RELOCATABLE;
1794169689Skan	  target_flags_explicit |= MASK_RELOCATABLE;
1795169689Skan	}
1796169689Skan      break;
1797169689Skan#endif
1798169689Skan
1799169689Skan    case OPT_mabi_:
1800169689Skan      if (!strcmp (arg, "altivec"))
1801169689Skan	{
1802169689Skan	  rs6000_explicit_options.abi = true;
1803169689Skan	  rs6000_altivec_abi = 1;
1804169689Skan	  rs6000_spe_abi = 0;
1805169689Skan	}
1806169689Skan      else if (! strcmp (arg, "no-altivec"))
1807169689Skan	{
1808169689Skan	  /* ??? Don't set rs6000_explicit_options.abi here, to allow
1809169689Skan	     the default for rs6000_spe_abi to be chosen later.  */
1810169689Skan	  rs6000_altivec_abi = 0;
1811169689Skan	}
1812169689Skan      else if (! strcmp (arg, "spe"))
1813169689Skan	{
1814169689Skan	  rs6000_explicit_options.abi = true;
1815169689Skan	  rs6000_spe_abi = 1;
1816169689Skan	  rs6000_altivec_abi = 0;
1817169689Skan	  if (!TARGET_SPE_ABI)
1818169689Skan	    error ("not configured for ABI: '%s'", arg);
1819169689Skan	}
1820169689Skan      else if (! strcmp (arg, "no-spe"))
1821169689Skan	{
1822169689Skan	  rs6000_explicit_options.abi = true;
1823169689Skan	  rs6000_spe_abi = 0;
1824169689Skan	}
1825169689Skan
1826169689Skan      /* These are here for testing during development only, do not
1827169689Skan	 document in the manual please.  */
1828169689Skan      else if (! strcmp (arg, "d64"))
1829169689Skan	{
1830169689Skan	  rs6000_darwin64_abi = 1;
1831169689Skan	  warning (0, "Using darwin64 ABI");
1832169689Skan	}
1833169689Skan      else if (! strcmp (arg, "d32"))
1834169689Skan	{
1835169689Skan	  rs6000_darwin64_abi = 0;
1836169689Skan	  warning (0, "Using old darwin ABI");
1837169689Skan	}
1838169689Skan
1839169689Skan      else if (! strcmp (arg, "ibmlongdouble"))
1840169689Skan	{
1841169689Skan	  rs6000_explicit_options.ieee = true;
1842169689Skan	  rs6000_ieeequad = 0;
1843169689Skan	  warning (0, "Using IBM extended precision long double");
1844169689Skan	}
1845169689Skan      else if (! strcmp (arg, "ieeelongdouble"))
1846169689Skan	{
1847169689Skan	  rs6000_explicit_options.ieee = true;
1848169689Skan	  rs6000_ieeequad = 1;
1849169689Skan	  warning (0, "Using IEEE extended precision long double");
1850169689Skan	}
1851169689Skan
1852169689Skan      else
1853169689Skan	{
1854169689Skan	  error ("unknown ABI specified: '%s'", arg);
1855169689Skan	  return false;
1856169689Skan	}
1857169689Skan      break;
1858169689Skan
1859169689Skan    case OPT_mcpu_:
1860169689Skan      rs6000_select[1].string = arg;
1861169689Skan      break;
1862169689Skan
1863169689Skan    case OPT_mtune_:
1864169689Skan      rs6000_select[2].string = arg;
1865169689Skan      break;
1866169689Skan
1867169689Skan    case OPT_mtraceback_:
1868169689Skan      rs6000_traceback_name = arg;
1869169689Skan      break;
1870169689Skan
1871169689Skan    case OPT_mfloat_gprs_:
1872169689Skan      rs6000_explicit_options.float_gprs = true;
1873169689Skan      if (! strcmp (arg, "yes") || ! strcmp (arg, "single"))
1874169689Skan	rs6000_float_gprs = 1;
1875169689Skan      else if (! strcmp (arg, "double"))
1876169689Skan	rs6000_float_gprs = 2;
1877169689Skan      else if (! strcmp (arg, "no"))
1878169689Skan	rs6000_float_gprs = 0;
1879169689Skan      else
1880169689Skan	{
1881169689Skan	  error ("invalid option for -mfloat-gprs: '%s'", arg);
1882169689Skan	  return false;
1883169689Skan	}
1884169689Skan      break;
1885169689Skan
1886169689Skan    case OPT_mlong_double_:
1887169689Skan      rs6000_explicit_options.long_double = true;
1888169689Skan      rs6000_long_double_type_size = RS6000_DEFAULT_LONG_DOUBLE_SIZE;
1889169689Skan      if (value != 64 && value != 128)
1890169689Skan	{
1891169689Skan	  error ("Unknown switch -mlong-double-%s", arg);
1892169689Skan	  rs6000_long_double_type_size = RS6000_DEFAULT_LONG_DOUBLE_SIZE;
1893169689Skan	  return false;
1894169689Skan	}
1895169689Skan      else
1896169689Skan	rs6000_long_double_type_size = value;
1897169689Skan      break;
1898169689Skan
1899169689Skan    case OPT_msched_costly_dep_:
1900169689Skan      rs6000_sched_costly_dep_str = arg;
1901169689Skan      break;
1902169689Skan
1903169689Skan    case OPT_malign_:
1904169689Skan      rs6000_explicit_options.alignment = true;
1905169689Skan      if (! strcmp (arg, "power"))
1906169689Skan	{
1907169689Skan	  /* On 64-bit Darwin, power alignment is ABI-incompatible with
1908169689Skan	     some C library functions, so warn about it. The flag may be
1909169689Skan	     useful for performance studies from time to time though, so
1910169689Skan	     don't disable it entirely.  */
1911169689Skan	  if (DEFAULT_ABI == ABI_DARWIN && TARGET_64BIT)
1912169689Skan	    warning (0, "-malign-power is not supported for 64-bit Darwin;"
1913169689Skan		     " it is incompatible with the installed C and C++ libraries");
1914169689Skan	  rs6000_alignment_flags = MASK_ALIGN_POWER;
1915169689Skan	}
1916169689Skan      else if (! strcmp (arg, "natural"))
1917169689Skan	rs6000_alignment_flags = MASK_ALIGN_NATURAL;
1918169689Skan      else
1919169689Skan	{
1920169689Skan	  error ("unknown -malign-XXXXX option specified: '%s'", arg);
1921169689Skan	  return false;
1922169689Skan	}
1923169689Skan      break;
1924169689Skan    }
1925169689Skan  return true;
1926169689Skan}
192790075Sobrien
192890075Sobrien/* Do anything needed at the start of the asm file.  */
192990075Sobrien
1930132718Skanstatic void
1931132718Skanrs6000_file_start (void)
193290075Sobrien{
193390075Sobrien  size_t i;
193490075Sobrien  char buffer[80];
193590075Sobrien  const char *start = buffer;
193690075Sobrien  struct rs6000_cpu_select *ptr;
1937132718Skan  const char *default_cpu = TARGET_CPU_DEFAULT;
1938132718Skan  FILE *file = asm_out_file;
193990075Sobrien
1940132718Skan  default_file_start ();
1941132718Skan
1942132718Skan#ifdef TARGET_BI_ARCH
1943132718Skan  if ((TARGET_DEFAULT ^ target_flags) & MASK_64BIT)
1944132718Skan    default_cpu = 0;
1945132718Skan#endif
1946132718Skan
194790075Sobrien  if (flag_verbose_asm)
194890075Sobrien    {
194990075Sobrien      sprintf (buffer, "\n%s rs6000/powerpc options:", ASM_COMMENT_START);
195090075Sobrien      rs6000_select[0].string = default_cpu;
195190075Sobrien
195290075Sobrien      for (i = 0; i < ARRAY_SIZE (rs6000_select); i++)
195390075Sobrien	{
195490075Sobrien	  ptr = &rs6000_select[i];
195590075Sobrien	  if (ptr->string != (char *)0 && ptr->string[0] != '\0')
195690075Sobrien	    {
195790075Sobrien	      fprintf (file, "%s %s%s", start, ptr->name, ptr->string);
195890075Sobrien	      start = "";
195990075Sobrien	    }
196090075Sobrien	}
196190075Sobrien
1962169689Skan      if (PPC405_ERRATUM77)
1963169689Skan	{
1964169689Skan	  fprintf (file, "%s PPC405CR_ERRATUM77", start);
1965169689Skan	  start = "";
1966169689Skan	}
1967169689Skan
196890075Sobrien#ifdef USING_ELFOS_H
196990075Sobrien      switch (rs6000_sdata)
197090075Sobrien	{
197190075Sobrien	case SDATA_NONE: fprintf (file, "%s -msdata=none", start); start = ""; break;
197290075Sobrien	case SDATA_DATA: fprintf (file, "%s -msdata=data", start); start = ""; break;
197390075Sobrien	case SDATA_SYSV: fprintf (file, "%s -msdata=sysv", start); start = ""; break;
197490075Sobrien	case SDATA_EABI: fprintf (file, "%s -msdata=eabi", start); start = ""; break;
197590075Sobrien	}
197690075Sobrien
197790075Sobrien      if (rs6000_sdata && g_switch_value)
197890075Sobrien	{
1979132718Skan	  fprintf (file, "%s -G " HOST_WIDE_INT_PRINT_UNSIGNED, start,
1980132718Skan		   g_switch_value);
198190075Sobrien	  start = "";
198290075Sobrien	}
198390075Sobrien#endif
198490075Sobrien
198590075Sobrien      if (*start == '\0')
198690075Sobrien	putc ('\n', file);
198790075Sobrien    }
1988169689Skan
1989169689Skan  if (DEFAULT_ABI == ABI_AIX || (TARGET_ELF && flag_pic == 2))
1990169689Skan    {
1991169689Skan      switch_to_section (toc_section);
1992169689Skan      switch_to_section (text_section);
1993169689Skan    }
199490075Sobrien}
1995169689Skan
199690075Sobrien
1997117395Skan/* Return nonzero if this function is known to have a null epilogue.  */
199890075Sobrien
199990075Sobrienint
2000132718Skandirect_return (void)
200190075Sobrien{
200290075Sobrien  if (reload_completed)
200390075Sobrien    {
200490075Sobrien      rs6000_stack_t *info = rs6000_stack_info ();
200590075Sobrien
200690075Sobrien      if (info->first_gp_reg_save == 32
200790075Sobrien	  && info->first_fp_reg_save == 64
200890075Sobrien	  && info->first_altivec_reg_save == LAST_ALTIVEC_REGNO + 1
200990075Sobrien	  && ! info->lr_save_p
201090075Sobrien	  && ! info->cr_save_p
201190075Sobrien	  && info->vrsave_mask == 0
201290075Sobrien	  && ! info->push_p)
201390075Sobrien	return 1;
201490075Sobrien    }
201590075Sobrien
201690075Sobrien  return 0;
201790075Sobrien}
201890075Sobrien
201990075Sobrien/* Return the number of instructions it takes to form a constant in an
202090075Sobrien   integer register.  */
202190075Sobrien
2022169689Skanint
2023132718Skannum_insns_constant_wide (HOST_WIDE_INT value)
202490075Sobrien{
202590075Sobrien  /* signed constant loadable with {cal|addi} */
2026169689Skan  if ((unsigned HOST_WIDE_INT) (value + 0x8000) < 0x10000)
202790075Sobrien    return 1;
202890075Sobrien
202990075Sobrien  /* constant loadable with {cau|addis} */
2030169689Skan  else if ((value & 0xffff) == 0
2031169689Skan	   && (value >> 31 == -1 || value >> 31 == 0))
203290075Sobrien    return 1;
203390075Sobrien
203490075Sobrien#if HOST_BITS_PER_WIDE_INT == 64
203590075Sobrien  else if (TARGET_POWERPC64)
203690075Sobrien    {
2037117395Skan      HOST_WIDE_INT low  = ((value & 0xffffffff) ^ 0x80000000) - 0x80000000;
2038117395Skan      HOST_WIDE_INT high = value >> 31;
203990075Sobrien
2040117395Skan      if (high == 0 || high == -1)
204190075Sobrien	return 2;
204290075Sobrien
2043117395Skan      high >>= 1;
204490075Sobrien
2045117395Skan      if (low == 0)
204690075Sobrien	return num_insns_constant_wide (high) + 1;
204790075Sobrien      else
204890075Sobrien	return (num_insns_constant_wide (high)
204990075Sobrien		+ num_insns_constant_wide (low) + 1);
205090075Sobrien    }
205190075Sobrien#endif
205290075Sobrien
205390075Sobrien  else
205490075Sobrien    return 2;
205590075Sobrien}
205690075Sobrien
205790075Sobrienint
2058132718Skannum_insns_constant (rtx op, enum machine_mode mode)
205990075Sobrien{
2060169689Skan  HOST_WIDE_INT low, high;
2061169689Skan
2062169689Skan  switch (GET_CODE (op))
206390075Sobrien    {
2064169689Skan    case CONST_INT:
206590075Sobrien#if HOST_BITS_PER_WIDE_INT == 64
206690075Sobrien      if ((INTVAL (op) >> 31) != 0 && (INTVAL (op) >> 31) != -1
206790075Sobrien	  && mask64_operand (op, mode))
2068169689Skan	return 2;
206990075Sobrien      else
207090075Sobrien#endif
207190075Sobrien	return num_insns_constant_wide (INTVAL (op));
207290075Sobrien
2073169689Skan      case CONST_DOUBLE:
2074169689Skan	if (mode == SFmode)
2075169689Skan	  {
2076169689Skan	    long l;
2077169689Skan	    REAL_VALUE_TYPE rv;
207890075Sobrien
2079169689Skan	    REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
2080169689Skan	    REAL_VALUE_TO_TARGET_SINGLE (rv, l);
2081169689Skan	    return num_insns_constant_wide ((HOST_WIDE_INT) l);
2082169689Skan	  }
208390075Sobrien
2084169689Skan	if (mode == VOIDmode || mode == DImode)
2085169689Skan	  {
2086169689Skan	    high = CONST_DOUBLE_HIGH (op);
2087169689Skan	    low  = CONST_DOUBLE_LOW (op);
2088169689Skan	  }
2089169689Skan	else
2090169689Skan	  {
2091169689Skan	    long l[2];
2092169689Skan	    REAL_VALUE_TYPE rv;
209390075Sobrien
2094169689Skan	    REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
2095169689Skan	    REAL_VALUE_TO_TARGET_DOUBLE (rv, l);
2096169689Skan	    high = l[WORDS_BIG_ENDIAN == 0];
2097169689Skan	    low  = l[WORDS_BIG_ENDIAN != 0];
2098169689Skan	  }
209990075Sobrien
2100169689Skan	if (TARGET_32BIT)
2101169689Skan	  return (num_insns_constant_wide (low)
2102169689Skan		  + num_insns_constant_wide (high));
2103169689Skan	else
2104169689Skan	  {
2105169689Skan	    if ((high == 0 && low >= 0)
2106169689Skan		|| (high == -1 && low < 0))
2107169689Skan	      return num_insns_constant_wide (low);
210890075Sobrien
2109169689Skan	    else if (mask64_operand (op, mode))
2110169689Skan	      return 2;
211190075Sobrien
2112169689Skan	    else if (low == 0)
2113169689Skan	      return num_insns_constant_wide (high) + 1;
211490075Sobrien
2115169689Skan	    else
2116169689Skan	      return (num_insns_constant_wide (high)
2117169689Skan		      + num_insns_constant_wide (low) + 1);
2118169689Skan	  }
211990075Sobrien
2120169689Skan    default:
2121169689Skan      gcc_unreachable ();
212290075Sobrien    }
2123169689Skan}
212490075Sobrien
2125169689Skan/* Interpret element ELT of the CONST_VECTOR OP as an integer value.
2126169689Skan   If the mode of OP is MODE_VECTOR_INT, this simply returns the
2127169689Skan   corresponding element of the vector, but for V4SFmode and V2SFmode,
2128169689Skan   the corresponding "float" is interpreted as an SImode integer.  */
2129169689Skan
2130169689Skanstatic HOST_WIDE_INT
2131169689Skanconst_vector_elt_as_int (rtx op, unsigned int elt)
2132169689Skan{
2133169689Skan  rtx tmp = CONST_VECTOR_ELT (op, elt);
2134169689Skan  if (GET_MODE (op) == V4SFmode
2135169689Skan      || GET_MODE (op) == V2SFmode)
2136169689Skan    tmp = gen_lowpart (SImode, tmp);
2137169689Skan  return INTVAL (tmp);
213890075Sobrien}
213990075Sobrien
2140169689Skan/* Return true if OP can be synthesized with a particular vspltisb, vspltish
2141169689Skan   or vspltisw instruction.  OP is a CONST_VECTOR.  Which instruction is used
2142169689Skan   depends on STEP and COPIES, one of which will be 1.  If COPIES > 1,
2143169689Skan   all items are set to the same value and contain COPIES replicas of the
2144169689Skan   vsplt's operand; if STEP > 1, one in STEP elements is set to the vsplt's
2145169689Skan   operand and the others are set to the value of the operand's msb.  */
214690075Sobrien
2147169689Skanstatic bool
2148169689Skanvspltis_constant (rtx op, unsigned step, unsigned copies)
214990075Sobrien{
2150169689Skan  enum machine_mode mode = GET_MODE (op);
2151169689Skan  enum machine_mode inner = GET_MODE_INNER (mode);
215290075Sobrien
2153169689Skan  unsigned i;
2154169689Skan  unsigned nunits = GET_MODE_NUNITS (mode);
2155169689Skan  unsigned bitsize = GET_MODE_BITSIZE (inner);
2156169689Skan  unsigned mask = GET_MODE_MASK (inner);
215790075Sobrien
2158169689Skan  HOST_WIDE_INT val = const_vector_elt_as_int (op, nunits - 1);
2159169689Skan  HOST_WIDE_INT splat_val = val;
2160169689Skan  HOST_WIDE_INT msb_val = val > 0 ? 0 : -1;
216190075Sobrien
2162169689Skan  /* Construct the value to be splatted, if possible.  If not, return 0.  */
2163169689Skan  for (i = 2; i <= copies; i *= 2)
216490075Sobrien    {
2165169689Skan      HOST_WIDE_INT small_val;
2166169689Skan      bitsize /= 2;
2167169689Skan      small_val = splat_val >> bitsize;
2168169689Skan      mask >>= bitsize;
2169169689Skan      if (splat_val != ((small_val << bitsize) | (small_val & mask)))
2170169689Skan	return false;
2171169689Skan      splat_val = small_val;
2172117395Skan    }
2173117395Skan
2174169689Skan  /* Check if SPLAT_VAL can really be the operand of a vspltis[bhw].  */
2175169689Skan  if (EASY_VECTOR_15 (splat_val))
2176169689Skan    ;
217790075Sobrien
2178169689Skan  /* Also check if we can splat, and then add the result to itself.  Do so if
2179169689Skan     the value is positive, of if the splat instruction is using OP's mode;
2180169689Skan     for splat_val < 0, the splat and the add should use the same mode.  */
2181169689Skan  else if (EASY_VECTOR_15_ADD_SELF (splat_val)
2182169689Skan           && (splat_val >= 0 || (step == 1 && copies == 1)))
2183169689Skan    ;
218490075Sobrien
2185169689Skan  else
2186169689Skan    return false;
218790075Sobrien
2188169689Skan  /* Check if VAL is present in every STEP-th element, and the
2189169689Skan     other elements are filled with its most significant bit.  */
2190169689Skan  for (i = 0; i < nunits - 1; ++i)
219190075Sobrien    {
2192169689Skan      HOST_WIDE_INT desired_val;
2193169689Skan      if (((i + 1) & (step - 1)) == 0)
2194169689Skan	desired_val = val;
2195169689Skan      else
2196169689Skan	desired_val = msb_val;
219790075Sobrien
2198169689Skan      if (desired_val != const_vector_elt_as_int (op, i))
2199169689Skan	return false;
220090075Sobrien    }
220190075Sobrien
2202169689Skan  return true;
220390075Sobrien}
220490075Sobrien
220596263Sobrien
2206169689Skan/* Return true if OP is of the given MODE and can be synthesized
2207169689Skan   with a vspltisb, vspltish or vspltisw.  */
220896263Sobrien
2209169689Skanbool
2210169689Skaneasy_altivec_constant (rtx op, enum machine_mode mode)
2211132718Skan{
2212169689Skan  unsigned step, copies;
2213132718Skan
2214169689Skan  if (mode == VOIDmode)
2215169689Skan    mode = GET_MODE (op);
2216169689Skan  else if (mode != GET_MODE (op))
2217169689Skan    return false;
221896263Sobrien
2219169689Skan  /* Start with a vspltisw.  */
2220169689Skan  step = GET_MODE_NUNITS (mode) / 4;
2221169689Skan  copies = 1;
2222132718Skan
2223169689Skan  if (vspltis_constant (op, step, copies))
2224169689Skan    return true;
2225132718Skan
2226169689Skan  /* Then try with a vspltish.  */
2227169689Skan  if (step == 1)
2228169689Skan    copies <<= 1;
2229169689Skan  else
2230169689Skan    step >>= 1;
2231132718Skan
2232169689Skan  if (vspltis_constant (op, step, copies))
2233169689Skan    return true;
2234132718Skan
2235169689Skan  /* And finally a vspltisb.  */
2236169689Skan  if (step == 1)
2237169689Skan    copies <<= 1;
2238169689Skan  else
2239169689Skan    step >>= 1;
2240132718Skan
2241169689Skan  if (vspltis_constant (op, step, copies))
2242169689Skan    return true;
2243132718Skan
2244169689Skan  return false;
2245169689Skan}
2246132718Skan
2247169689Skan/* Generate a VEC_DUPLICATE representing a vspltis[bhw] instruction whose
2248169689Skan   result is OP.  Abort if it is not possible.  */
2249132718Skan
2250169689Skanrtx
2251169689Skangen_easy_altivec_constant (rtx op)
2252169689Skan{
2253169689Skan  enum machine_mode mode = GET_MODE (op);
2254169689Skan  int nunits = GET_MODE_NUNITS (mode);
2255169689Skan  rtx last = CONST_VECTOR_ELT (op, nunits - 1);
2256169689Skan  unsigned step = nunits / 4;
2257169689Skan  unsigned copies = 1;
2258132718Skan
2259169689Skan  /* Start with a vspltisw.  */
2260169689Skan  if (vspltis_constant (op, step, copies))
2261169689Skan    return gen_rtx_VEC_DUPLICATE (V4SImode, gen_lowpart (SImode, last));
2262132718Skan
2263169689Skan  /* Then try with a vspltish.  */
2264169689Skan  if (step == 1)
2265169689Skan    copies <<= 1;
2266169689Skan  else
2267169689Skan    step >>= 1;
226896263Sobrien
2269169689Skan  if (vspltis_constant (op, step, copies))
2270169689Skan    return gen_rtx_VEC_DUPLICATE (V8HImode, gen_lowpart (HImode, last));
227196263Sobrien
2272169689Skan  /* And finally a vspltisb.  */
2273169689Skan  if (step == 1)
2274169689Skan    copies <<= 1;
2275169689Skan  else
2276169689Skan    step >>= 1;
2277132718Skan
2278169689Skan  if (vspltis_constant (op, step, copies))
2279169689Skan    return gen_rtx_VEC_DUPLICATE (V16QImode, gen_lowpart (QImode, last));
2280132718Skan
2281169689Skan  gcc_unreachable ();
2282132718Skan}
2283132718Skan
2284132718Skanconst char *
2285132718Skanoutput_vec_const_move (rtx *operands)
2286132718Skan{
2287132718Skan  int cst, cst2;
2288132718Skan  enum machine_mode mode;
2289132718Skan  rtx dest, vec;
2290132718Skan
2291132718Skan  dest = operands[0];
2292132718Skan  vec = operands[1];
2293132718Skan  mode = GET_MODE (dest);
2294132718Skan
2295132718Skan  if (TARGET_ALTIVEC)
2296132718Skan    {
2297169689Skan      rtx splat_vec;
2298132718Skan      if (zero_constant (vec, mode))
2299132718Skan	return "vxor %0,%0,%0";
230096263Sobrien
2301169689Skan      splat_vec = gen_easy_altivec_constant (vec);
2302169689Skan      gcc_assert (GET_CODE (splat_vec) == VEC_DUPLICATE);
2303169689Skan      operands[1] = XEXP (splat_vec, 0);
2304169689Skan      if (!EASY_VECTOR_15 (INTVAL (operands[1])))
2305169689Skan	return "#";
2306132718Skan
2307169689Skan      switch (GET_MODE (splat_vec))
2308169689Skan	{
2309169689Skan	case V4SImode:
2310169689Skan	  return "vspltisw %0,%1";
2311132718Skan
2312169689Skan	case V8HImode:
2313169689Skan	  return "vspltish %0,%1";
231496263Sobrien
2315169689Skan	case V16QImode:
2316169689Skan	  return "vspltisb %0,%1";
231796263Sobrien
2318169689Skan	default:
2319169689Skan	  gcc_unreachable ();
2320169689Skan	}
2321169689Skan    }
232290075Sobrien
2323169689Skan  gcc_assert (TARGET_SPE);
232490075Sobrien
2325169689Skan  /* Vector constant 0 is handled as a splitter of V2SI, and in the
2326169689Skan     pattern of V1DI, V4HI, and V2SF.
232790075Sobrien
2328169689Skan     FIXME: We should probably return # and add post reload
2329169689Skan     splitters for these, but this way is so easy ;-).  */
2330169689Skan  cst = INTVAL (CONST_VECTOR_ELT (vec, 0));
2331169689Skan  cst2 = INTVAL (CONST_VECTOR_ELT (vec, 1));
2332169689Skan  operands[1] = CONST_VECTOR_ELT (vec, 0);
2333169689Skan  operands[2] = CONST_VECTOR_ELT (vec, 1);
2334169689Skan  if (cst == cst2)
2335169689Skan    return "li %0,%1\n\tevmergelo %0,%0,%0";
2336169689Skan  else
2337169689Skan    return "li %0,%1\n\tevmergelo %0,%0,%0\n\tli %0,%2";
233890075Sobrien}
233990075Sobrien
2340169689Skan/* Initialize vector TARGET to VALS.  */
234190075Sobrien
2342169689Skanvoid
2343169689Skanrs6000_expand_vector_init (rtx target, rtx vals)
234490075Sobrien{
2345169689Skan  enum machine_mode mode = GET_MODE (target);
2346169689Skan  enum machine_mode inner_mode = GET_MODE_INNER (mode);
2347169689Skan  int n_elts = GET_MODE_NUNITS (mode);
2348169689Skan  int n_var = 0, one_var = -1;
2349169689Skan  bool all_same = true, all_const_zero = true;
2350169689Skan  rtx x, mem;
2351169689Skan  int i;
235290075Sobrien
2353169689Skan  for (i = 0; i < n_elts; ++i)
2354169689Skan    {
2355169689Skan      x = XVECEXP (vals, 0, i);
2356169689Skan      if (!CONSTANT_P (x))
2357169689Skan	++n_var, one_var = i;
2358169689Skan      else if (x != CONST0_RTX (inner_mode))
2359169689Skan	all_const_zero = false;
236090075Sobrien
2361169689Skan      if (i > 0 && !rtx_equal_p (x, XVECEXP (vals, 0, 0)))
2362169689Skan	all_same = false;
2363169689Skan    }
236490075Sobrien
2365169689Skan  if (n_var == 0)
236690075Sobrien    {
2367169689Skan      if (mode != V4SFmode && all_const_zero)
2368169689Skan	{
2369169689Skan	  /* Zero register.  */
2370169689Skan	  emit_insn (gen_rtx_SET (VOIDmode, target,
2371169689Skan				  gen_rtx_XOR (mode, target, target)));
2372169689Skan	  return;
2373169689Skan	}
2374169689Skan      else if (mode != V4SFmode && easy_vector_constant (vals, mode))
2375169689Skan	{
2376169689Skan	  /* Splat immediate.  */
2377169689Skan	  emit_insn (gen_rtx_SET (VOIDmode, target, vals));
2378169689Skan	  return;
2379169689Skan	}
2380169689Skan      else if (all_same)
2381169689Skan	;	/* Splat vector element.  */
2382169689Skan      else
2383169689Skan	{
2384169689Skan	  /* Load from constant pool.  */
2385169689Skan	  emit_move_insn (target, gen_rtx_CONST_VECTOR (mode, XVEC (vals, 0)));
2386169689Skan	  return;
2387169689Skan	}
2388169689Skan    }
238990075Sobrien
2390169689Skan  /* Store value to stack temp.  Load vector element.  Splat.  */
2391169689Skan  if (all_same)
239290075Sobrien    {
2393169689Skan      mem = assign_stack_temp (mode, GET_MODE_SIZE (inner_mode), 0);
2394169689Skan      emit_move_insn (adjust_address_nv (mem, inner_mode, 0),
2395169689Skan		      XVECEXP (vals, 0, 0));
2396169689Skan      x = gen_rtx_UNSPEC (VOIDmode,
2397169689Skan			  gen_rtvec (1, const0_rtx), UNSPEC_LVE);
2398169689Skan      emit_insn (gen_rtx_PARALLEL (VOIDmode,
2399169689Skan				   gen_rtvec (2,
2400169689Skan					      gen_rtx_SET (VOIDmode,
2401169689Skan							   target, mem),
2402169689Skan					      x)));
2403169689Skan      x = gen_rtx_VEC_SELECT (inner_mode, target,
2404169689Skan			      gen_rtx_PARALLEL (VOIDmode,
2405169689Skan						gen_rtvec (1, const0_rtx)));
2406169689Skan      emit_insn (gen_rtx_SET (VOIDmode, target,
2407169689Skan			      gen_rtx_VEC_DUPLICATE (mode, x)));
2408169689Skan      return;
240990075Sobrien    }
241090075Sobrien
2411169689Skan  /* One field is non-constant.  Load constant then overwrite
2412169689Skan     varying field.  */
2413169689Skan  if (n_var == 1)
2414169689Skan    {
2415169689Skan      rtx copy = copy_rtx (vals);
241690075Sobrien
2417169689Skan      /* Load constant part of vector, substitute neighboring value for
2418169689Skan	 varying element.  */
2419169689Skan      XVECEXP (copy, 0, one_var) = XVECEXP (vals, 0, (one_var + 1) % n_elts);
2420169689Skan      rs6000_expand_vector_init (target, copy);
242190075Sobrien
2422169689Skan      /* Insert variable.  */
2423169689Skan      rs6000_expand_vector_set (target, XVECEXP (vals, 0, one_var), one_var);
2424169689Skan      return;
2425169689Skan    }
242690075Sobrien
2427169689Skan  /* Construct the vector in memory one field at a time
2428169689Skan     and load the whole vector.  */
2429169689Skan  mem = assign_stack_temp (mode, GET_MODE_SIZE (mode), 0);
2430169689Skan  for (i = 0; i < n_elts; i++)
2431169689Skan    emit_move_insn (adjust_address_nv (mem, inner_mode,
2432169689Skan				    i * GET_MODE_SIZE (inner_mode)),
2433169689Skan		    XVECEXP (vals, 0, i));
2434169689Skan  emit_move_insn (target, mem);
243590075Sobrien}
243690075Sobrien
2437169689Skan/* Set field ELT of TARGET to VAL.  */
2438117395Skan
2439169689Skanvoid
2440169689Skanrs6000_expand_vector_set (rtx target, rtx val, int elt)
2441117395Skan{
2442169689Skan  enum machine_mode mode = GET_MODE (target);
2443169689Skan  enum machine_mode inner_mode = GET_MODE_INNER (mode);
2444169689Skan  rtx reg = gen_reg_rtx (mode);
2445169689Skan  rtx mask, mem, x;
2446169689Skan  int width = GET_MODE_SIZE (inner_mode);
2447169689Skan  int i;
2448117395Skan
2449169689Skan  /* Load single variable value.  */
2450169689Skan  mem = assign_stack_temp (mode, GET_MODE_SIZE (inner_mode), 0);
2451169689Skan  emit_move_insn (adjust_address_nv (mem, inner_mode, 0), val);
2452169689Skan  x = gen_rtx_UNSPEC (VOIDmode,
2453169689Skan		      gen_rtvec (1, const0_rtx), UNSPEC_LVE);
2454169689Skan  emit_insn (gen_rtx_PARALLEL (VOIDmode,
2455169689Skan			       gen_rtvec (2,
2456169689Skan					  gen_rtx_SET (VOIDmode,
2457169689Skan						       reg, mem),
2458169689Skan					  x)));
2459117395Skan
2460169689Skan  /* Linear sequence.  */
2461169689Skan  mask = gen_rtx_PARALLEL (V16QImode, rtvec_alloc (16));
2462169689Skan  for (i = 0; i < 16; ++i)
2463169689Skan    XVECEXP (mask, 0, i) = GEN_INT (i);
2464117395Skan
2465169689Skan  /* Set permute mask to insert element into target.  */
2466169689Skan  for (i = 0; i < width; ++i)
2467169689Skan    XVECEXP (mask, 0, elt*width + i)
2468169689Skan      = GEN_INT (i + 0x10);
2469169689Skan  x = gen_rtx_CONST_VECTOR (V16QImode, XVEC (mask, 0));
2470169689Skan  x = gen_rtx_UNSPEC (mode,
2471169689Skan		      gen_rtvec (3, target, reg,
2472169689Skan				 force_reg (V16QImode, x)),
2473169689Skan		      UNSPEC_VPERM);
2474169689Skan  emit_insn (gen_rtx_SET (VOIDmode, target, x));
2475117395Skan}
2476117395Skan
2477169689Skan/* Extract field ELT from VEC into TARGET.  */
247890075Sobrien
2479169689Skanvoid
2480169689Skanrs6000_expand_vector_extract (rtx target, rtx vec, int elt)
248190075Sobrien{
2482169689Skan  enum machine_mode mode = GET_MODE (vec);
2483169689Skan  enum machine_mode inner_mode = GET_MODE_INNER (mode);
2484169689Skan  rtx mem, x;
248590075Sobrien
2486169689Skan  /* Allocate mode-sized buffer.  */
2487169689Skan  mem = assign_stack_temp (mode, GET_MODE_SIZE (mode), 0);
2488117395Skan
2489169689Skan  /* Add offset to field within buffer matching vector element.  */
2490169689Skan  mem = adjust_address_nv (mem, mode, elt * GET_MODE_SIZE (inner_mode));
2491117395Skan
2492169689Skan  /* Store single field into mode-sized buffer.  */
2493169689Skan  x = gen_rtx_UNSPEC (VOIDmode,
2494169689Skan		      gen_rtvec (1, const0_rtx), UNSPEC_STVE);
2495169689Skan  emit_insn (gen_rtx_PARALLEL (VOIDmode,
2496169689Skan			       gen_rtvec (2,
2497169689Skan					  gen_rtx_SET (VOIDmode,
2498169689Skan						       mem, vec),
2499169689Skan					  x)));
2500169689Skan  emit_move_insn (target, adjust_address_nv (mem, inner_mode, 0));
2501117395Skan}
2502117395Skan
2503117395Skan/* Generates shifts and masks for a pair of rldicl or rldicr insns to
2504117395Skan   implement ANDing by the mask IN.  */
2505117395Skanvoid
2506132718Skanbuild_mask64_2_operands (rtx in, rtx *out)
2507117395Skan{
2508117395Skan#if HOST_BITS_PER_WIDE_INT >= 64
2509117395Skan  unsigned HOST_WIDE_INT c, lsb, m1, m2;
2510117395Skan  int shift;
2511117395Skan
2512169689Skan  gcc_assert (GET_CODE (in) == CONST_INT);
2513117395Skan
2514117395Skan  c = INTVAL (in);
2515117395Skan  if (c & 1)
2516117395Skan    {
2517117395Skan      /* Assume c initially something like 0x00fff000000fffff.  The idea
2518117395Skan	 is to rotate the word so that the middle ^^^^^^ group of zeros
2519117395Skan	 is at the MS end and can be cleared with an rldicl mask.  We then
2520117395Skan	 rotate back and clear off the MS    ^^ group of zeros with a
2521117395Skan	 second rldicl.  */
2522117395Skan      c = ~c;			/*   c == 0xff000ffffff00000 */
2523117395Skan      lsb = c & -c;		/* lsb == 0x0000000000100000 */
2524117395Skan      m1 = -lsb;		/*  m1 == 0xfffffffffff00000 */
2525117395Skan      c = ~c;			/*   c == 0x00fff000000fffff */
2526117395Skan      c &= -lsb;		/*   c == 0x00fff00000000000 */
2527117395Skan      lsb = c & -c;		/* lsb == 0x0000100000000000 */
2528117395Skan      c = ~c;			/*   c == 0xff000fffffffffff */
2529117395Skan      c &= -lsb;		/*   c == 0xff00000000000000 */
2530117395Skan      shift = 0;
2531117395Skan      while ((lsb >>= 1) != 0)
2532117395Skan	shift++;		/* shift == 44 on exit from loop */
2533117395Skan      m1 <<= 64 - shift;	/*  m1 == 0xffffff0000000000 */
2534117395Skan      m1 = ~m1;			/*  m1 == 0x000000ffffffffff */
2535117395Skan      m2 = ~c;			/*  m2 == 0x00ffffffffffffff */
2536117395Skan    }
253790075Sobrien  else
2538117395Skan    {
2539117395Skan      /* Assume c initially something like 0xff000f0000000000.  The idea
2540117395Skan	 is to rotate the word so that the     ^^^  middle group of zeros
2541117395Skan	 is at the LS end and can be cleared with an rldicr mask.  We then
2542117395Skan	 rotate back and clear off the LS group of ^^^^^^^^^^ zeros with
2543117395Skan	 a second rldicr.  */
2544117395Skan      lsb = c & -c;		/* lsb == 0x0000010000000000 */
2545117395Skan      m2 = -lsb;		/*  m2 == 0xffffff0000000000 */
2546117395Skan      c = ~c;			/*   c == 0x00fff0ffffffffff */
2547117395Skan      c &= -lsb;		/*   c == 0x00fff00000000000 */
2548117395Skan      lsb = c & -c;		/* lsb == 0x0000100000000000 */
2549117395Skan      c = ~c;			/*   c == 0xff000fffffffffff */
2550117395Skan      c &= -lsb;		/*   c == 0xff00000000000000 */
2551117395Skan      shift = 0;
2552117395Skan      while ((lsb >>= 1) != 0)
2553117395Skan	shift++;		/* shift == 44 on exit from loop */
2554117395Skan      m1 = ~c;			/*  m1 == 0x00ffffffffffffff */
2555117395Skan      m1 >>= shift;		/*  m1 == 0x0000000000000fff */
2556117395Skan      m1 = ~m1;			/*  m1 == 0xfffffffffffff000 */
2557117395Skan    }
2558117395Skan
2559117395Skan  /* Note that when we only have two 0->1 and 1->0 transitions, one of the
2560117395Skan     masks will be all 1's.  We are guaranteed more than one transition.  */
2561117395Skan  out[0] = GEN_INT (64 - shift);
2562117395Skan  out[1] = GEN_INT (m1);
2563117395Skan  out[2] = GEN_INT (shift);
2564117395Skan  out[3] = GEN_INT (m2);
2565117395Skan#else
2566117395Skan  (void)in;
2567117395Skan  (void)out;
2568169689Skan  gcc_unreachable ();
2569117395Skan#endif
257090075Sobrien}
257190075Sobrien
2572169689Skan/* Return TRUE if OP is an invalid SUBREG operation on the e500.  */
257390075Sobrien
2574169689Skanbool
2575169689Skaninvalid_e500_subreg (rtx op, enum machine_mode mode)
257690075Sobrien{
2577169689Skan  if (TARGET_E500_DOUBLE)
2578169689Skan    {
2579169689Skan      /* Reject (subreg:SI (reg:DF)).  */
2580169689Skan      if (GET_CODE (op) == SUBREG
2581169689Skan	  && mode == SImode
2582169689Skan	  && REG_P (SUBREG_REG (op))
2583169689Skan	  && GET_MODE (SUBREG_REG (op)) == DFmode)
2584169689Skan	return true;
258590075Sobrien
2586169689Skan      /* Reject (subreg:DF (reg:DI)).  */
2587169689Skan      if (GET_CODE (op) == SUBREG
2588169689Skan	  && mode == DFmode
2589169689Skan	  && REG_P (SUBREG_REG (op))
2590169689Skan	  && GET_MODE (SUBREG_REG (op)) == DImode)
2591169689Skan	return true;
2592169689Skan    }
259390075Sobrien
2594169689Skan  if (TARGET_SPE
2595169689Skan      && GET_CODE (op) == SUBREG
2596169689Skan      && mode == SImode
2597169689Skan      && REG_P (SUBREG_REG (op))
2598169689Skan      && SPE_VECTOR_MODE (GET_MODE (SUBREG_REG (op))))
2599169689Skan    return true;
2600117395Skan
2601169689Skan  return false;
2602117395Skan}
2603117395Skan
2604132718Skan/* Darwin, AIX increases natural record alignment to doubleword if the first
2605132718Skan   field is an FP double while the FP fields remain word aligned.  */
2606132718Skan
2607132718Skanunsigned int
2608169689Skanrs6000_special_round_type_align (tree type, unsigned int computed,
2609169689Skan				 unsigned int specified)
2610132718Skan{
2611169689Skan  unsigned int align = MAX (computed, specified);
2612132718Skan  tree field = TYPE_FIELDS (type);
2613132718Skan
2614169689Skan  /* Skip all non field decls */
2615169689Skan  while (field != NULL && TREE_CODE (field) != FIELD_DECL)
2616132718Skan    field = TREE_CHAIN (field);
2617132718Skan
2618169689Skan  if (field != NULL && field != type)
2619169689Skan    {
2620169689Skan      type = TREE_TYPE (field);
2621169689Skan      while (TREE_CODE (type) == ARRAY_TYPE)
2622169689Skan	type = TREE_TYPE (type);
2623132718Skan
2624169689Skan      if (type != error_mark_node && TYPE_MODE (type) == DFmode)
2625169689Skan	align = MAX (align, 64);
2626169689Skan    }
2627169689Skan
2628169689Skan  return align;
2629132718Skan}
2630132718Skan
263190075Sobrien/* Return 1 for an operand in small memory on V.4/eabi.  */
263290075Sobrien
263390075Sobrienint
2634169689Skansmall_data_operand (rtx op ATTRIBUTE_UNUSED,
2635132718Skan		    enum machine_mode mode ATTRIBUTE_UNUSED)
263690075Sobrien{
263790075Sobrien#if TARGET_ELF
263890075Sobrien  rtx sym_ref;
263990075Sobrien
264090075Sobrien  if (rs6000_sdata == SDATA_NONE || rs6000_sdata == SDATA_DATA)
264190075Sobrien    return 0;
264290075Sobrien
264390075Sobrien  if (DEFAULT_ABI != ABI_V4)
264490075Sobrien    return 0;
264590075Sobrien
264690075Sobrien  if (GET_CODE (op) == SYMBOL_REF)
264790075Sobrien    sym_ref = op;
264890075Sobrien
264990075Sobrien  else if (GET_CODE (op) != CONST
265090075Sobrien	   || GET_CODE (XEXP (op, 0)) != PLUS
265190075Sobrien	   || GET_CODE (XEXP (XEXP (op, 0), 0)) != SYMBOL_REF
265290075Sobrien	   || GET_CODE (XEXP (XEXP (op, 0), 1)) != CONST_INT)
265390075Sobrien    return 0;
265490075Sobrien
265590075Sobrien  else
265690075Sobrien    {
265790075Sobrien      rtx sum = XEXP (op, 0);
265890075Sobrien      HOST_WIDE_INT summand;
265990075Sobrien
266090075Sobrien      /* We have to be careful here, because it is the referenced address
2661169689Skan	 that must be 32k from _SDA_BASE_, not just the symbol.  */
266290075Sobrien      summand = INTVAL (XEXP (sum, 1));
2663132718Skan      if (summand < 0 || (unsigned HOST_WIDE_INT) summand > g_switch_value)
2664169689Skan	return 0;
266590075Sobrien
266690075Sobrien      sym_ref = XEXP (sum, 0);
266790075Sobrien    }
266890075Sobrien
2669132718Skan  return SYMBOL_REF_SMALL_P (sym_ref);
267090075Sobrien#else
267190075Sobrien  return 0;
267290075Sobrien#endif
267390075Sobrien}
2674132718Skan
2675132718Skan/* Return true if either operand is a general purpose register.  */
2676132718Skan
2677132718Skanbool
2678132718Skangpr_or_gpr_p (rtx op0, rtx op1)
2679132718Skan{
2680132718Skan  return ((REG_P (op0) && INT_REGNO_P (REGNO (op0)))
2681132718Skan	  || (REG_P (op1) && INT_REGNO_P (REGNO (op1))));
2682132718Skan}
2683132718Skan
268490075Sobrien
2685132718Skan/* Subroutines of rs6000_legitimize_address and rs6000_legitimate_address.  */
2686132718Skan
2687169689Skanstatic int
2688169689Skanconstant_pool_expr_1 (rtx op, int *have_sym, int *have_toc)
268990075Sobrien{
2690169689Skan  switch (GET_CODE (op))
269190075Sobrien    {
269290075Sobrien    case SYMBOL_REF:
2693132718Skan      if (RS6000_SYMBOL_REF_TLS_P (op))
2694132718Skan	return 0;
2695132718Skan      else if (CONSTANT_POOL_ADDRESS_P (op))
269690075Sobrien	{
269790075Sobrien	  if (ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (op), Pmode))
269890075Sobrien	    {
269990075Sobrien	      *have_sym = 1;
270090075Sobrien	      return 1;
270190075Sobrien	    }
270290075Sobrien	  else
270390075Sobrien	    return 0;
270490075Sobrien	}
270590075Sobrien      else if (! strcmp (XSTR (op, 0), toc_label_name))
270690075Sobrien	{
270790075Sobrien	  *have_toc = 1;
270890075Sobrien	  return 1;
270990075Sobrien	}
271090075Sobrien      else
271190075Sobrien	return 0;
271290075Sobrien    case PLUS:
271390075Sobrien    case MINUS:
271496263Sobrien      return (constant_pool_expr_1 (XEXP (op, 0), have_sym, have_toc)
271596263Sobrien	      && constant_pool_expr_1 (XEXP (op, 1), have_sym, have_toc));
271690075Sobrien    case CONST:
271790075Sobrien      return constant_pool_expr_1 (XEXP (op, 0), have_sym, have_toc);
271890075Sobrien    case CONST_INT:
271990075Sobrien      return 1;
272090075Sobrien    default:
272190075Sobrien      return 0;
272290075Sobrien    }
272390075Sobrien}
272490075Sobrien
2725132718Skanstatic bool
2726132718Skanconstant_pool_expr_p (rtx op)
272790075Sobrien{
272890075Sobrien  int have_sym = 0;
272990075Sobrien  int have_toc = 0;
273090075Sobrien  return constant_pool_expr_1 (op, &have_sym, &have_toc) && have_sym;
273190075Sobrien}
273290075Sobrien
2733169689Skanbool
2734132718Skantoc_relative_expr_p (rtx op)
273590075Sobrien{
2736132718Skan  int have_sym = 0;
2737132718Skan  int have_toc = 0;
2738132718Skan  return constant_pool_expr_1 (op, &have_sym, &have_toc) && have_toc;
273990075Sobrien}
274090075Sobrien
2741132718Skanbool
2742132718Skanlegitimate_constant_pool_address_p (rtx x)
2743132718Skan{
2744132718Skan  return (TARGET_TOC
2745132718Skan	  && GET_CODE (x) == PLUS
2746132718Skan	  && GET_CODE (XEXP (x, 0)) == REG
2747132718Skan	  && (TARGET_MINIMAL_TOC || REGNO (XEXP (x, 0)) == TOC_REGISTER)
2748132718Skan	  && constant_pool_expr_p (XEXP (x, 1)));
2749132718Skan}
2750132718Skan
2751132718Skanstatic bool
2752132718Skanlegitimate_small_data_p (enum machine_mode mode, rtx x)
2753132718Skan{
2754132718Skan  return (DEFAULT_ABI == ABI_V4
2755132718Skan	  && !flag_pic && !TARGET_TOC
2756132718Skan	  && (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == CONST)
2757132718Skan	  && small_data_operand (x, mode));
2758132718Skan}
2759132718Skan
2760169689Skan/* SPE offset addressing is limited to 5-bits worth of double words.  */
2761169689Skan#define SPE_CONST_OFFSET_OK(x) (((x) & ~0xf8) == 0)
2762169689Skan
2763169689Skanbool
2764169689Skanrs6000_legitimate_offset_address_p (enum machine_mode mode, rtx x, int strict)
2765132718Skan{
2766132718Skan  unsigned HOST_WIDE_INT offset, extra;
2767132718Skan
2768132718Skan  if (GET_CODE (x) != PLUS)
2769132718Skan    return false;
2770132718Skan  if (GET_CODE (XEXP (x, 0)) != REG)
2771132718Skan    return false;
2772132718Skan  if (!INT_REG_OK_FOR_BASE_P (XEXP (x, 0), strict))
2773132718Skan    return false;
2774169689Skan  if (legitimate_constant_pool_address_p (x))
2775169689Skan    return true;
2776132718Skan  if (GET_CODE (XEXP (x, 1)) != CONST_INT)
2777132718Skan    return false;
2778132718Skan
2779132718Skan  offset = INTVAL (XEXP (x, 1));
2780132718Skan  extra = 0;
2781132718Skan  switch (mode)
2782132718Skan    {
2783132718Skan    case V16QImode:
2784132718Skan    case V8HImode:
2785132718Skan    case V4SFmode:
2786132718Skan    case V4SImode:
2787169689Skan      /* AltiVec vector modes.  Only reg+reg addressing is valid and
2788169689Skan	 constant offset zero should not occur due to canonicalization.
2789169689Skan	 Allow any offset when not strict before reload.  */
2790169689Skan      return !strict;
2791132718Skan
2792132718Skan    case V4HImode:
2793132718Skan    case V2SImode:
2794132718Skan    case V1DImode:
2795132718Skan    case V2SFmode:
2796132718Skan      /* SPE vector modes.  */
2797132718Skan      return SPE_CONST_OFFSET_OK (offset);
2798132718Skan
2799132718Skan    case DFmode:
2800169689Skan      if (TARGET_E500_DOUBLE)
2801169689Skan	return SPE_CONST_OFFSET_OK (offset);
2802169689Skan
2803132718Skan    case DImode:
2804169689Skan      /* On e500v2, we may have:
2805169689Skan
2806169689Skan	   (subreg:DF (mem:DI (plus (reg) (const_int))) 0).
2807169689Skan
2808169689Skan         Which gets addressed with evldd instructions.  */
2809169689Skan      if (TARGET_E500_DOUBLE)
2810169689Skan	return SPE_CONST_OFFSET_OK (offset);
2811169689Skan
2812161651Skan      if (mode == DFmode || !TARGET_POWERPC64)
2813132718Skan	extra = 4;
2814161651Skan      else if (offset & 3)
2815161651Skan	return false;
2816132718Skan      break;
2817132718Skan
2818132718Skan    case TFmode:
2819132718Skan    case TImode:
2820161651Skan      if (mode == TFmode || !TARGET_POWERPC64)
2821132718Skan	extra = 12;
2822161651Skan      else if (offset & 3)
2823161651Skan	return false;
2824132718Skan      else
2825132718Skan	extra = 8;
2826132718Skan      break;
2827132718Skan
2828132718Skan    default:
2829132718Skan      break;
2830132718Skan    }
2831132718Skan
2832132718Skan  offset += 0x8000;
2833132718Skan  return (offset < 0x10000) && (offset + extra < 0x10000);
2834132718Skan}
2835132718Skan
2836132718Skanstatic bool
2837132718Skanlegitimate_indexed_address_p (rtx x, int strict)
2838132718Skan{
2839132718Skan  rtx op0, op1;
2840132718Skan
2841132718Skan  if (GET_CODE (x) != PLUS)
2842132718Skan    return false;
2843169689Skan
2844132718Skan  op0 = XEXP (x, 0);
2845132718Skan  op1 = XEXP (x, 1);
2846132718Skan
2847169689Skan  /* Recognize the rtl generated by reload which we know will later be
2848169689Skan     replaced with proper base and index regs.  */
2849169689Skan  if (!strict
2850169689Skan      && reload_in_progress
2851169689Skan      && (REG_P (op0) || GET_CODE (op0) == PLUS)
2852169689Skan      && REG_P (op1))
2853169689Skan    return true;
2854132718Skan
2855169689Skan  return (REG_P (op0) && REG_P (op1)
2856169689Skan	  && ((INT_REG_OK_FOR_BASE_P (op0, strict)
2857169689Skan	       && INT_REG_OK_FOR_INDEX_P (op1, strict))
2858169689Skan	      || (INT_REG_OK_FOR_BASE_P (op1, strict)
2859169689Skan		  && INT_REG_OK_FOR_INDEX_P (op0, strict))));
2860132718Skan}
2861132718Skan
2862169689Skaninline bool
2863132718Skanlegitimate_indirect_address_p (rtx x, int strict)
2864132718Skan{
2865132718Skan  return GET_CODE (x) == REG && INT_REG_OK_FOR_BASE_P (x, strict);
2866132718Skan}
2867132718Skan
2868169689Skanbool
2869132718Skanmacho_lo_sum_memory_operand (rtx x, enum machine_mode mode)
2870132718Skan{
2871169689Skan  if (!TARGET_MACHO || !flag_pic
2872169689Skan      || mode != SImode || GET_CODE (x) != MEM)
2873169689Skan    return false;
2874169689Skan  x = XEXP (x, 0);
2875132718Skan
2876132718Skan  if (GET_CODE (x) != LO_SUM)
2877132718Skan    return false;
2878132718Skan  if (GET_CODE (XEXP (x, 0)) != REG)
2879132718Skan    return false;
2880132718Skan  if (!INT_REG_OK_FOR_BASE_P (XEXP (x, 0), 0))
2881132718Skan    return false;
2882132718Skan  x = XEXP (x, 1);
2883132718Skan
2884132718Skan  return CONSTANT_P (x);
2885132718Skan}
2886132718Skan
2887132718Skanstatic bool
2888132718Skanlegitimate_lo_sum_address_p (enum machine_mode mode, rtx x, int strict)
2889132718Skan{
2890132718Skan  if (GET_CODE (x) != LO_SUM)
2891132718Skan    return false;
2892132718Skan  if (GET_CODE (XEXP (x, 0)) != REG)
2893132718Skan    return false;
2894132718Skan  if (!INT_REG_OK_FOR_BASE_P (XEXP (x, 0), strict))
2895132718Skan    return false;
2896169689Skan  /* Restrict addressing for DI because of our SUBREG hackery.  */
2897169689Skan  if (TARGET_E500_DOUBLE && (mode == DFmode || mode == DImode))
2898169689Skan    return false;
2899132718Skan  x = XEXP (x, 1);
2900132718Skan
2901132718Skan  if (TARGET_ELF || TARGET_MACHO)
2902132718Skan    {
2903132718Skan      if (DEFAULT_ABI != ABI_AIX && DEFAULT_ABI != ABI_DARWIN && flag_pic)
2904132718Skan	return false;
2905132718Skan      if (TARGET_TOC)
2906132718Skan	return false;
2907132718Skan      if (GET_MODE_NUNITS (mode) != 1)
2908132718Skan	return false;
2909169689Skan      if (GET_MODE_BITSIZE (mode) > 64
2910169689Skan	  || (GET_MODE_BITSIZE (mode) > 32 && !TARGET_POWERPC64
2911169689Skan	      && !(TARGET_HARD_FLOAT && TARGET_FPRS && mode == DFmode)))
2912132718Skan	return false;
2913132718Skan
2914132718Skan      return CONSTANT_P (x);
2915132718Skan    }
2916132718Skan
2917132718Skan  return false;
2918132718Skan}
2919132718Skan
2920132718Skan
292190075Sobrien/* Try machine-dependent ways of modifying an illegitimate address
292290075Sobrien   to be legitimate.  If we find one, return the new, valid address.
292390075Sobrien   This is used from only one place: `memory_address' in explow.c.
292490075Sobrien
292590075Sobrien   OLDX is the address as it was before break_out_memory_refs was
292690075Sobrien   called.  In some cases it is useful to look at this to decide what
292790075Sobrien   needs to be done.
292890075Sobrien
292990075Sobrien   MODE is passed so that this function can use GO_IF_LEGITIMATE_ADDRESS.
293090075Sobrien
293190075Sobrien   It is always safe for this function to do nothing.  It exists to
293290075Sobrien   recognize opportunities to optimize the output.
293390075Sobrien
293490075Sobrien   On RS/6000, first check for the sum of a register with a constant
293590075Sobrien   integer that is out of range.  If so, generate code to add the
293690075Sobrien   constant with the low-order 16 bits masked to the register and force
293790075Sobrien   this result into another register (this can be done with `cau').
293890075Sobrien   Then generate an address of REG+(CONST&0xffff), allowing for the
293990075Sobrien   possibility of bit 16 being a one.
294090075Sobrien
294190075Sobrien   Then check for the sum of a register and something not constant, try to
294290075Sobrien   load the other things into a register and return the sum.  */
2943132718Skan
294490075Sobrienrtx
2945132718Skanrs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
2946132718Skan			   enum machine_mode mode)
294790075Sobrien{
2948132718Skan  if (GET_CODE (x) == SYMBOL_REF)
2949132718Skan    {
2950132718Skan      enum tls_model model = SYMBOL_REF_TLS_MODEL (x);
2951132718Skan      if (model != 0)
2952132718Skan	return rs6000_legitimize_tls_address (x, model);
2953132718Skan    }
2954132718Skan
2955169689Skan  if (GET_CODE (x) == PLUS
295690075Sobrien      && GET_CODE (XEXP (x, 0)) == REG
295790075Sobrien      && GET_CODE (XEXP (x, 1)) == CONST_INT
295890075Sobrien      && (unsigned HOST_WIDE_INT) (INTVAL (XEXP (x, 1)) + 0x8000) >= 0x10000)
2959169689Skan    {
296090075Sobrien      HOST_WIDE_INT high_int, low_int;
296190075Sobrien      rtx sum;
2962117395Skan      low_int = ((INTVAL (XEXP (x, 1)) & 0xffff) ^ 0x8000) - 0x8000;
2963117395Skan      high_int = INTVAL (XEXP (x, 1)) - low_int;
296490075Sobrien      sum = force_operand (gen_rtx_PLUS (Pmode, XEXP (x, 0),
296590075Sobrien					 GEN_INT (high_int)), 0);
296690075Sobrien      return gen_rtx_PLUS (Pmode, sum, GEN_INT (low_int));
296790075Sobrien    }
2968169689Skan  else if (GET_CODE (x) == PLUS
296990075Sobrien	   && GET_CODE (XEXP (x, 0)) == REG
297090075Sobrien	   && GET_CODE (XEXP (x, 1)) != CONST_INT
297190075Sobrien	   && GET_MODE_NUNITS (mode) == 1
2972117395Skan	   && ((TARGET_HARD_FLOAT && TARGET_FPRS)
2973117395Skan	       || TARGET_POWERPC64
2974169689Skan	       || (((mode != DImode && mode != DFmode) || TARGET_E500_DOUBLE)
2975169689Skan		   && mode != TFmode))
297690075Sobrien	   && (TARGET_POWERPC64 || mode != DImode)
297790075Sobrien	   && mode != TImode)
297890075Sobrien    {
297990075Sobrien      return gen_rtx_PLUS (Pmode, XEXP (x, 0),
298090075Sobrien			   force_reg (Pmode, force_operand (XEXP (x, 1), 0)));
298190075Sobrien    }
298290075Sobrien  else if (ALTIVEC_VECTOR_MODE (mode))
298390075Sobrien    {
298490075Sobrien      rtx reg;
298590075Sobrien
298690075Sobrien      /* Make sure both operands are registers.  */
298790075Sobrien      if (GET_CODE (x) == PLUS)
298890075Sobrien	return gen_rtx_PLUS (Pmode, force_reg (Pmode, XEXP (x, 0)),
298990075Sobrien			     force_reg (Pmode, XEXP (x, 1)));
299090075Sobrien
299190075Sobrien      reg = force_reg (Pmode, x);
299290075Sobrien      return reg;
299390075Sobrien    }
2994169689Skan  else if (SPE_VECTOR_MODE (mode)
2995169689Skan	   || (TARGET_E500_DOUBLE && (mode == DFmode
2996169689Skan				      || mode == DImode)))
2997117395Skan    {
2998169689Skan      if (mode == DImode)
2999169689Skan	return NULL_RTX;
3000117395Skan      /* We accept [reg + reg] and [reg + OFFSET].  */
3001117395Skan
3002117395Skan      if (GET_CODE (x) == PLUS)
3003169689Skan	{
3004169689Skan	  rtx op1 = XEXP (x, 0);
3005169689Skan	  rtx op2 = XEXP (x, 1);
3006117395Skan
3007169689Skan	  op1 = force_reg (Pmode, op1);
3008117395Skan
3009169689Skan	  if (GET_CODE (op2) != REG
3010169689Skan	      && (GET_CODE (op2) != CONST_INT
3011169689Skan		  || !SPE_CONST_OFFSET_OK (INTVAL (op2))))
3012169689Skan	    op2 = force_reg (Pmode, op2);
3013117395Skan
3014169689Skan	  return gen_rtx_PLUS (Pmode, op1, op2);
3015169689Skan	}
3016117395Skan
3017117395Skan      return force_reg (Pmode, x);
3018117395Skan    }
3019132718Skan  else if (TARGET_ELF
3020132718Skan	   && TARGET_32BIT
3021132718Skan	   && TARGET_NO_TOC
3022132718Skan	   && ! flag_pic
302390075Sobrien	   && GET_CODE (x) != CONST_INT
3024169689Skan	   && GET_CODE (x) != CONST_DOUBLE
302590075Sobrien	   && CONSTANT_P (x)
302690075Sobrien	   && GET_MODE_NUNITS (mode) == 1
302790075Sobrien	   && (GET_MODE_BITSIZE (mode) <= 32
3028117395Skan	       || ((TARGET_HARD_FLOAT && TARGET_FPRS) && mode == DFmode)))
302990075Sobrien    {
303090075Sobrien      rtx reg = gen_reg_rtx (Pmode);
3031132718Skan      emit_insn (gen_elf_high (reg, x));
3032132718Skan      return gen_rtx_LO_SUM (Pmode, reg, x);
303390075Sobrien    }
303490075Sobrien  else if (TARGET_MACHO && TARGET_32BIT && TARGET_NO_TOC
303590075Sobrien	   && ! flag_pic
3036132718Skan#if TARGET_MACHO
3037132718Skan	   && ! MACHO_DYNAMIC_NO_PIC_P
3038132718Skan#endif
303990075Sobrien	   && GET_CODE (x) != CONST_INT
3040169689Skan	   && GET_CODE (x) != CONST_DOUBLE
304190075Sobrien	   && CONSTANT_P (x)
3042117395Skan	   && ((TARGET_HARD_FLOAT && TARGET_FPRS) || mode != DFmode)
3043169689Skan	   && mode != DImode
304490075Sobrien	   && mode != TImode)
304590075Sobrien    {
304690075Sobrien      rtx reg = gen_reg_rtx (Pmode);
3047132718Skan      emit_insn (gen_macho_high (reg, x));
3048132718Skan      return gen_rtx_LO_SUM (Pmode, reg, x);
304990075Sobrien    }
3050169689Skan  else if (TARGET_TOC
3051132718Skan	   && constant_pool_expr_p (x)
305290075Sobrien	   && ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (x), Pmode))
305390075Sobrien    {
305490075Sobrien      return create_TOC_reference (x);
305590075Sobrien    }
305690075Sobrien  else
305790075Sobrien    return NULL_RTX;
305890075Sobrien}
305990075Sobrien
3060169689Skan/* This is called from dwarf2out.c via TARGET_ASM_OUTPUT_DWARF_DTPREL.
3061132718Skan   We need to emit DTP-relative relocations.  */
3062132718Skan
3063169689Skanstatic void
3064132718Skanrs6000_output_dwarf_dtprel (FILE *file, int size, rtx x)
3065132718Skan{
3066132718Skan  switch (size)
3067132718Skan    {
3068132718Skan    case 4:
3069132718Skan      fputs ("\t.long\t", file);
3070132718Skan      break;
3071132718Skan    case 8:
3072132718Skan      fputs (DOUBLE_INT_ASM_OP, file);
3073132718Skan      break;
3074132718Skan    default:
3075169689Skan      gcc_unreachable ();
3076132718Skan    }
3077132718Skan  output_addr_const (file, x);
3078132718Skan  fputs ("@dtprel+0x8000", file);
3079132718Skan}
3080132718Skan
3081132718Skan/* Construct the SYMBOL_REF for the tls_get_addr function.  */
3082132718Skan
3083132718Skanstatic GTY(()) rtx rs6000_tls_symbol;
3084132718Skanstatic rtx
3085132718Skanrs6000_tls_get_addr (void)
3086132718Skan{
3087132718Skan  if (!rs6000_tls_symbol)
3088132718Skan    rs6000_tls_symbol = init_one_libfunc ("__tls_get_addr");
3089132718Skan
3090132718Skan  return rs6000_tls_symbol;
3091132718Skan}
3092132718Skan
3093132718Skan/* Construct the SYMBOL_REF for TLS GOT references.  */
3094132718Skan
3095132718Skanstatic GTY(()) rtx rs6000_got_symbol;
3096132718Skanstatic rtx
3097132718Skanrs6000_got_sym (void)
3098132718Skan{
3099132718Skan  if (!rs6000_got_symbol)
3100132718Skan    {
3101132718Skan      rs6000_got_symbol = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
3102132718Skan      SYMBOL_REF_FLAGS (rs6000_got_symbol) |= SYMBOL_FLAG_LOCAL;
3103132718Skan      SYMBOL_REF_FLAGS (rs6000_got_symbol) |= SYMBOL_FLAG_EXTERNAL;
3104169689Skan    }
3105132718Skan
3106132718Skan  return rs6000_got_symbol;
3107132718Skan}
3108132718Skan
3109132718Skan/* ADDR contains a thread-local SYMBOL_REF.  Generate code to compute
3110132718Skan   this (thread-local) address.  */
3111132718Skan
3112132718Skanstatic rtx
3113132718Skanrs6000_legitimize_tls_address (rtx addr, enum tls_model model)
3114132718Skan{
3115132718Skan  rtx dest, insn;
3116132718Skan
3117132718Skan  dest = gen_reg_rtx (Pmode);
3118132718Skan  if (model == TLS_MODEL_LOCAL_EXEC && rs6000_tls_size == 16)
3119132718Skan    {
3120132718Skan      rtx tlsreg;
3121132718Skan
3122132718Skan      if (TARGET_64BIT)
3123132718Skan	{
3124132718Skan	  tlsreg = gen_rtx_REG (Pmode, 13);
3125132718Skan	  insn = gen_tls_tprel_64 (dest, tlsreg, addr);
3126132718Skan	}
3127132718Skan      else
3128132718Skan	{
3129132718Skan	  tlsreg = gen_rtx_REG (Pmode, 2);
3130132718Skan	  insn = gen_tls_tprel_32 (dest, tlsreg, addr);
3131132718Skan	}
3132132718Skan      emit_insn (insn);
3133132718Skan    }
3134132718Skan  else if (model == TLS_MODEL_LOCAL_EXEC && rs6000_tls_size == 32)
3135132718Skan    {
3136132718Skan      rtx tlsreg, tmp;
3137132718Skan
3138132718Skan      tmp = gen_reg_rtx (Pmode);
3139132718Skan      if (TARGET_64BIT)
3140132718Skan	{
3141132718Skan	  tlsreg = gen_rtx_REG (Pmode, 13);
3142132718Skan	  insn = gen_tls_tprel_ha_64 (tmp, tlsreg, addr);
3143132718Skan	}
3144132718Skan      else
3145132718Skan	{
3146132718Skan	  tlsreg = gen_rtx_REG (Pmode, 2);
3147132718Skan	  insn = gen_tls_tprel_ha_32 (tmp, tlsreg, addr);
3148132718Skan	}
3149132718Skan      emit_insn (insn);
3150132718Skan      if (TARGET_64BIT)
3151132718Skan	insn = gen_tls_tprel_lo_64 (dest, tmp, addr);
3152132718Skan      else
3153132718Skan	insn = gen_tls_tprel_lo_32 (dest, tmp, addr);
3154132718Skan      emit_insn (insn);
3155132718Skan    }
3156132718Skan  else
3157132718Skan    {
3158132718Skan      rtx r3, got, tga, tmp1, tmp2, eqv;
3159132718Skan
3160169689Skan      /* We currently use relocations like @got@tlsgd for tls, which
3161169689Skan	 means the linker will handle allocation of tls entries, placing
3162169689Skan	 them in the .got section.  So use a pointer to the .got section,
3163169689Skan	 not one to secondary TOC sections used by 64-bit -mminimal-toc,
3164169689Skan	 or to secondary GOT sections used by 32-bit -fPIC.  */
3165132718Skan      if (TARGET_64BIT)
3166161651Skan	got = gen_rtx_REG (Pmode, 2);
3167132718Skan      else
3168132718Skan	{
3169132718Skan	  if (flag_pic == 1)
3170132718Skan	    got = gen_rtx_REG (Pmode, RS6000_PIC_OFFSET_TABLE_REGNUM);
3171132718Skan	  else
3172132718Skan	    {
3173132718Skan	      rtx gsym = rs6000_got_sym ();
3174132718Skan	      got = gen_reg_rtx (Pmode);
3175132718Skan	      if (flag_pic == 0)
3176132718Skan		rs6000_emit_move (got, gsym, Pmode);
3177132718Skan	      else
3178132718Skan		{
3179146895Skan		  rtx tempLR, tmp3, mem;
3180132718Skan		  rtx first, last;
3181132718Skan
3182132718Skan		  tempLR = gen_reg_rtx (Pmode);
3183132718Skan		  tmp1 = gen_reg_rtx (Pmode);
3184132718Skan		  tmp2 = gen_reg_rtx (Pmode);
3185132718Skan		  tmp3 = gen_reg_rtx (Pmode);
3186169689Skan		  mem = gen_const_mem (Pmode, tmp1);
3187132718Skan
3188146895Skan		  first = emit_insn (gen_load_toc_v4_PIC_1b (tempLR, gsym));
3189132718Skan		  emit_move_insn (tmp1, tempLR);
3190132718Skan		  emit_move_insn (tmp2, mem);
3191132718Skan		  emit_insn (gen_addsi3 (tmp3, tmp1, tmp2));
3192132718Skan		  last = emit_move_insn (got, tmp3);
3193132718Skan		  REG_NOTES (last) = gen_rtx_EXPR_LIST (REG_EQUAL, gsym,
3194132718Skan							REG_NOTES (last));
3195132718Skan		  REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last,
3196132718Skan							 REG_NOTES (first));
3197132718Skan		  REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first,
3198132718Skan							REG_NOTES (last));
3199132718Skan		}
3200132718Skan	    }
3201132718Skan	}
3202132718Skan
3203132718Skan      if (model == TLS_MODEL_GLOBAL_DYNAMIC)
3204132718Skan	{
3205132718Skan	  r3 = gen_rtx_REG (Pmode, 3);
3206132718Skan	  if (TARGET_64BIT)
3207132718Skan	    insn = gen_tls_gd_64 (r3, got, addr);
3208132718Skan	  else
3209132718Skan	    insn = gen_tls_gd_32 (r3, got, addr);
3210132718Skan	  start_sequence ();
3211132718Skan	  emit_insn (insn);
3212132718Skan	  tga = gen_rtx_MEM (Pmode, rs6000_tls_get_addr ());
3213132718Skan	  insn = gen_call_value (r3, tga, const0_rtx, const0_rtx);
3214132718Skan	  insn = emit_call_insn (insn);
3215132718Skan	  CONST_OR_PURE_CALL_P (insn) = 1;
3216132718Skan	  use_reg (&CALL_INSN_FUNCTION_USAGE (insn), r3);
3217132718Skan	  insn = get_insns ();
3218132718Skan	  end_sequence ();
3219132718Skan	  emit_libcall_block (insn, dest, r3, addr);
3220132718Skan	}
3221132718Skan      else if (model == TLS_MODEL_LOCAL_DYNAMIC)
3222132718Skan	{
3223132718Skan	  r3 = gen_rtx_REG (Pmode, 3);
3224132718Skan	  if (TARGET_64BIT)
3225132718Skan	    insn = gen_tls_ld_64 (r3, got);
3226132718Skan	  else
3227132718Skan	    insn = gen_tls_ld_32 (r3, got);
3228132718Skan	  start_sequence ();
3229132718Skan	  emit_insn (insn);
3230132718Skan	  tga = gen_rtx_MEM (Pmode, rs6000_tls_get_addr ());
3231132718Skan	  insn = gen_call_value (r3, tga, const0_rtx, const0_rtx);
3232132718Skan	  insn = emit_call_insn (insn);
3233132718Skan	  CONST_OR_PURE_CALL_P (insn) = 1;
3234132718Skan	  use_reg (&CALL_INSN_FUNCTION_USAGE (insn), r3);
3235132718Skan	  insn = get_insns ();
3236132718Skan	  end_sequence ();
3237132718Skan	  tmp1 = gen_reg_rtx (Pmode);
3238132718Skan	  eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx),
3239132718Skan				UNSPEC_TLSLD);
3240132718Skan	  emit_libcall_block (insn, tmp1, r3, eqv);
3241132718Skan	  if (rs6000_tls_size == 16)
3242132718Skan	    {
3243132718Skan	      if (TARGET_64BIT)
3244132718Skan		insn = gen_tls_dtprel_64 (dest, tmp1, addr);
3245132718Skan	      else
3246132718Skan		insn = gen_tls_dtprel_32 (dest, tmp1, addr);
3247132718Skan	    }
3248132718Skan	  else if (rs6000_tls_size == 32)
3249132718Skan	    {
3250132718Skan	      tmp2 = gen_reg_rtx (Pmode);
3251132718Skan	      if (TARGET_64BIT)
3252132718Skan		insn = gen_tls_dtprel_ha_64 (tmp2, tmp1, addr);
3253132718Skan	      else
3254132718Skan		insn = gen_tls_dtprel_ha_32 (tmp2, tmp1, addr);
3255132718Skan	      emit_insn (insn);
3256132718Skan	      if (TARGET_64BIT)
3257132718Skan		insn = gen_tls_dtprel_lo_64 (dest, tmp2, addr);
3258132718Skan	      else
3259132718Skan		insn = gen_tls_dtprel_lo_32 (dest, tmp2, addr);
3260132718Skan	    }
3261132718Skan	  else
3262132718Skan	    {
3263132718Skan	      tmp2 = gen_reg_rtx (Pmode);
3264132718Skan	      if (TARGET_64BIT)
3265132718Skan		insn = gen_tls_got_dtprel_64 (tmp2, got, addr);
3266132718Skan	      else
3267132718Skan		insn = gen_tls_got_dtprel_32 (tmp2, got, addr);
3268132718Skan	      emit_insn (insn);
3269132718Skan	      insn = gen_rtx_SET (Pmode, dest,
3270132718Skan				  gen_rtx_PLUS (Pmode, tmp2, tmp1));
3271132718Skan	    }
3272132718Skan	  emit_insn (insn);
3273132718Skan	}
3274132718Skan      else
3275132718Skan	{
3276132718Skan	  /* IE, or 64 bit offset LE.  */
3277132718Skan	  tmp2 = gen_reg_rtx (Pmode);
3278132718Skan	  if (TARGET_64BIT)
3279132718Skan	    insn = gen_tls_got_tprel_64 (tmp2, got, addr);
3280132718Skan	  else
3281132718Skan	    insn = gen_tls_got_tprel_32 (tmp2, got, addr);
3282132718Skan	  emit_insn (insn);
3283132718Skan	  if (TARGET_64BIT)
3284132718Skan	    insn = gen_tls_tls_64 (dest, tmp2, addr);
3285132718Skan	  else
3286132718Skan	    insn = gen_tls_tls_32 (dest, tmp2, addr);
3287132718Skan	  emit_insn (insn);
3288132718Skan	}
3289132718Skan    }
3290132718Skan
3291132718Skan  return dest;
3292132718Skan}
3293132718Skan
3294132718Skan/* Return 1 if X contains a thread-local symbol.  */
3295132718Skan
3296132718Skanbool
3297132718Skanrs6000_tls_referenced_p (rtx x)
3298132718Skan{
3299132718Skan  if (! TARGET_HAVE_TLS)
3300132718Skan    return false;
3301132718Skan
3302132718Skan  return for_each_rtx (&x, &rs6000_tls_symbol_ref_1, 0);
3303132718Skan}
3304132718Skan
3305132718Skan/* Return 1 if *X is a thread-local symbol.  This is the same as
3306132718Skan   rs6000_tls_symbol_ref except for the type of the unused argument.  */
3307132718Skan
3308169689Skanstatic int
3309132718Skanrs6000_tls_symbol_ref_1 (rtx *x, void *data ATTRIBUTE_UNUSED)
3310132718Skan{
3311132718Skan  return RS6000_SYMBOL_REF_TLS_P (*x);
3312132718Skan}
3313132718Skan
331490075Sobrien/* The convention appears to be to define this wherever it is used.
331590075Sobrien   With legitimize_reload_address now defined here, REG_MODE_OK_FOR_BASE_P
331690075Sobrien   is now used here.  */
331790075Sobrien#ifndef REG_MODE_OK_FOR_BASE_P
331890075Sobrien#define REG_MODE_OK_FOR_BASE_P(REGNO, MODE) REG_OK_FOR_BASE_P (REGNO)
331990075Sobrien#endif
332090075Sobrien
332190075Sobrien/* Our implementation of LEGITIMIZE_RELOAD_ADDRESS.  Returns a value to
332290075Sobrien   replace the input X, or the original X if no replacement is called for.
332390075Sobrien   The output parameter *WIN is 1 if the calling macro should goto WIN,
332490075Sobrien   0 if it should not.
332590075Sobrien
332690075Sobrien   For RS/6000, we wish to handle large displacements off a base
332790075Sobrien   register by splitting the addend across an addiu/addis and the mem insn.
332890075Sobrien   This cuts number of extra insns needed from 3 to 1.
332990075Sobrien
333090075Sobrien   On Darwin, we use this to generate code for floating point constants.
333190075Sobrien   A movsf_low is generated so we wind up with 2 instructions rather than 3.
333290075Sobrien   The Darwin code is inside #if TARGET_MACHO because only then is
333390075Sobrien   machopic_function_base_name() defined.  */
333490075Sobrienrtx
3335169689Skanrs6000_legitimize_reload_address (rtx x, enum machine_mode mode,
3336169689Skan				  int opnum, int type,
3337169689Skan				  int ind_levels ATTRIBUTE_UNUSED, int *win)
333890075Sobrien{
3339169689Skan  /* We must recognize output that we have already generated ourselves.  */
334090075Sobrien  if (GET_CODE (x) == PLUS
334190075Sobrien      && GET_CODE (XEXP (x, 0)) == PLUS
334290075Sobrien      && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG
334390075Sobrien      && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
334490075Sobrien      && GET_CODE (XEXP (x, 1)) == CONST_INT)
334590075Sobrien    {
334690075Sobrien      push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
3347169689Skan		   BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0,
3348169689Skan		   opnum, (enum reload_type)type);
334990075Sobrien      *win = 1;
335090075Sobrien      return x;
335190075Sobrien    }
335296263Sobrien
335390075Sobrien#if TARGET_MACHO
335490075Sobrien  if (DEFAULT_ABI == ABI_DARWIN && flag_pic
335590075Sobrien      && GET_CODE (x) == LO_SUM
335690075Sobrien      && GET_CODE (XEXP (x, 0)) == PLUS
335790075Sobrien      && XEXP (XEXP (x, 0), 0) == pic_offset_table_rtx
335890075Sobrien      && GET_CODE (XEXP (XEXP (x, 0), 1)) == HIGH
335990075Sobrien      && GET_CODE (XEXP (XEXP (XEXP (x, 0), 1), 0)) == CONST
336090075Sobrien      && XEXP (XEXP (XEXP (x, 0), 1), 0) == XEXP (x, 1)
336190075Sobrien      && GET_CODE (XEXP (XEXP (x, 1), 0)) == MINUS
336290075Sobrien      && GET_CODE (XEXP (XEXP (XEXP (x, 1), 0), 0)) == SYMBOL_REF
336390075Sobrien      && GET_CODE (XEXP (XEXP (XEXP (x, 1), 0), 1)) == SYMBOL_REF)
336490075Sobrien    {
336590075Sobrien      /* Result of previous invocation of this function on Darwin
336690075Sobrien	 floating point constant.  */
336790075Sobrien      push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
3368169689Skan		   BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
3369169689Skan		   opnum, (enum reload_type)type);
337090075Sobrien      *win = 1;
337190075Sobrien      return x;
337290075Sobrien    }
337390075Sobrien#endif
3374161651Skan
3375161651Skan  /* Force ld/std non-word aligned offset into base register by wrapping
3376161651Skan     in offset 0.  */
337790075Sobrien  if (GET_CODE (x) == PLUS
337890075Sobrien      && GET_CODE (XEXP (x, 0)) == REG
3379161651Skan      && REGNO (XEXP (x, 0)) < 32
3380161651Skan      && REG_MODE_OK_FOR_BASE_P (XEXP (x, 0), mode)
3381161651Skan      && GET_CODE (XEXP (x, 1)) == CONST_INT
3382161651Skan      && (INTVAL (XEXP (x, 1)) & 3) != 0
3383169689Skan      && !ALTIVEC_VECTOR_MODE (mode)
3384161651Skan      && GET_MODE_SIZE (mode) >= UNITS_PER_WORD
3385161651Skan      && TARGET_POWERPC64)
3386161651Skan    {
3387161651Skan      x = gen_rtx_PLUS (GET_MODE (x), x, GEN_INT (0));
3388161651Skan      push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
3389161651Skan		   BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0,
3390161651Skan		   opnum, (enum reload_type) type);
3391161651Skan      *win = 1;
3392161651Skan      return x;
3393161651Skan    }
3394161651Skan
3395161651Skan  if (GET_CODE (x) == PLUS
3396161651Skan      && GET_CODE (XEXP (x, 0)) == REG
339790075Sobrien      && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER
339890075Sobrien      && REG_MODE_OK_FOR_BASE_P (XEXP (x, 0), mode)
339996263Sobrien      && GET_CODE (XEXP (x, 1)) == CONST_INT
3400117395Skan      && !SPE_VECTOR_MODE (mode)
3401169689Skan      && !(TARGET_E500_DOUBLE && (mode == DFmode
3402169689Skan				  || mode == DImode))
340396263Sobrien      && !ALTIVEC_VECTOR_MODE (mode))
340490075Sobrien    {
340590075Sobrien      HOST_WIDE_INT val = INTVAL (XEXP (x, 1));
340690075Sobrien      HOST_WIDE_INT low = ((val & 0xffff) ^ 0x8000) - 0x8000;
340790075Sobrien      HOST_WIDE_INT high
3408169689Skan	= (((val - low) & 0xffffffff) ^ 0x80000000) - 0x80000000;
340990075Sobrien
341090075Sobrien      /* Check for 32-bit overflow.  */
341190075Sobrien      if (high + low != val)
3412169689Skan	{
341390075Sobrien	  *win = 0;
341490075Sobrien	  return x;
341590075Sobrien	}
341690075Sobrien
341790075Sobrien      /* Reload the high part into a base reg; leave the low part
3418169689Skan	 in the mem directly.  */
341990075Sobrien
342090075Sobrien      x = gen_rtx_PLUS (GET_MODE (x),
3421169689Skan			gen_rtx_PLUS (GET_MODE (x), XEXP (x, 0),
3422169689Skan				      GEN_INT (high)),
3423169689Skan			GEN_INT (low));
342490075Sobrien
342590075Sobrien      push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
3426169689Skan		   BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0,
3427169689Skan		   opnum, (enum reload_type)type);
342890075Sobrien      *win = 1;
342990075Sobrien      return x;
343090075Sobrien    }
3431161651Skan
3432169689Skan  if (GET_CODE (x) == SYMBOL_REF
3433169689Skan      && !ALTIVEC_VECTOR_MODE (mode)
3434169689Skan      && !SPE_VECTOR_MODE (mode)
343590075Sobrien#if TARGET_MACHO
343690075Sobrien      && DEFAULT_ABI == ABI_DARWIN
3437132718Skan      && (flag_pic || MACHO_DYNAMIC_NO_PIC_P)
3438169689Skan#else
3439169689Skan      && DEFAULT_ABI == ABI_V4
3440169689Skan      && !flag_pic
3441169689Skan#endif
3442169689Skan      /* Don't do this for TFmode, since the result isn't offsettable.
3443169689Skan	 The same goes for DImode without 64-bit gprs and DFmode
3444169689Skan	 without fprs.  */
3445169689Skan      && mode != TFmode
3446169689Skan      && (mode != DImode || TARGET_POWERPC64)
3447169689Skan      && (mode != DFmode || TARGET_POWERPC64
3448169689Skan	  || (TARGET_FPRS && TARGET_HARD_FLOAT)))
344990075Sobrien    {
3450169689Skan#if TARGET_MACHO
3451132718Skan      if (flag_pic)
3452132718Skan	{
3453132718Skan	  rtx offset = gen_rtx_CONST (Pmode,
3454132718Skan			 gen_rtx_MINUS (Pmode, x,
3455169689Skan					machopic_function_base_sym ()));
3456132718Skan	  x = gen_rtx_LO_SUM (GET_MODE (x),
3457132718Skan		gen_rtx_PLUS (Pmode, pic_offset_table_rtx,
3458132718Skan		  gen_rtx_HIGH (Pmode, offset)), offset);
3459132718Skan	}
3460132718Skan      else
3461169689Skan#endif
3462132718Skan	x = gen_rtx_LO_SUM (GET_MODE (x),
3463169689Skan	      gen_rtx_HIGH (Pmode, x), x);
3464132718Skan
346590075Sobrien      push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
3466132718Skan		   BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
3467132718Skan		   opnum, (enum reload_type)type);
346890075Sobrien      *win = 1;
346990075Sobrien      return x;
347090075Sobrien    }
3471161651Skan
3472169689Skan  /* Reload an offset address wrapped by an AND that represents the
3473169689Skan     masking of the lower bits.  Strip the outer AND and let reload
3474169689Skan     convert the offset address into an indirect address.  */
3475169689Skan  if (TARGET_ALTIVEC
3476169689Skan      && ALTIVEC_VECTOR_MODE (mode)
3477169689Skan      && GET_CODE (x) == AND
3478169689Skan      && GET_CODE (XEXP (x, 0)) == PLUS
3479169689Skan      && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG
3480169689Skan      && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
3481169689Skan      && GET_CODE (XEXP (x, 1)) == CONST_INT
3482169689Skan      && INTVAL (XEXP (x, 1)) == -16)
3483169689Skan    {
3484169689Skan      x = XEXP (x, 0);
3485169689Skan      *win = 1;
3486169689Skan      return x;
3487169689Skan    }
3488169689Skan
348990075Sobrien  if (TARGET_TOC
3490132718Skan      && constant_pool_expr_p (x)
349196263Sobrien      && ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (x), mode))
349290075Sobrien    {
3493169689Skan      x = create_TOC_reference (x);
349490075Sobrien      *win = 1;
349590075Sobrien      return x;
349690075Sobrien    }
349790075Sobrien  *win = 0;
349890075Sobrien  return x;
3499169689Skan}
350090075Sobrien
350190075Sobrien/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression
350290075Sobrien   that is a valid memory address for an instruction.
350390075Sobrien   The MODE argument is the machine mode for the MEM expression
350490075Sobrien   that wants to use this address.
350590075Sobrien
350690075Sobrien   On the RS/6000, there are four valid address: a SYMBOL_REF that
350790075Sobrien   refers to a constant pool entry of an address (or the sum of it
350890075Sobrien   plus a constant), a short (16-bit signed) constant plus a register,
350990075Sobrien   the sum of two registers, or a register indirect, possibly with an
3510132718Skan   auto-increment.  For DFmode and DImode with a constant plus register,
351190075Sobrien   we must ensure that both words are addressable or PowerPC64 with offset
351290075Sobrien   word aligned.
351390075Sobrien
351490075Sobrien   For modes spanning multiple registers (DFmode in 32-bit GPRs,
3515169689Skan   32-bit DImode, TImode, TFmode), indexed addressing cannot be used because
351690075Sobrien   adjacent memory cells are accessed by adding word-sized offsets
351790075Sobrien   during assembly output.  */
351890075Sobrienint
3519132718Skanrs6000_legitimate_address (enum machine_mode mode, rtx x, int reg_ok_strict)
352090075Sobrien{
3521169689Skan  /* If this is an unaligned stvx/ldvx type address, discard the outer AND.  */
3522169689Skan  if (TARGET_ALTIVEC
3523169689Skan      && ALTIVEC_VECTOR_MODE (mode)
3524169689Skan      && GET_CODE (x) == AND
3525169689Skan      && GET_CODE (XEXP (x, 1)) == CONST_INT
3526169689Skan      && INTVAL (XEXP (x, 1)) == -16)
3527169689Skan    x = XEXP (x, 0);
3528169689Skan
3529132718Skan  if (RS6000_SYMBOL_REF_TLS_P (x))
3530132718Skan    return 0;
3531132718Skan  if (legitimate_indirect_address_p (x, reg_ok_strict))
353290075Sobrien    return 1;
353390075Sobrien  if ((GET_CODE (x) == PRE_INC || GET_CODE (x) == PRE_DEC)
3534107590Sobrien      && !ALTIVEC_VECTOR_MODE (mode)
3535117395Skan      && !SPE_VECTOR_MODE (mode)
3536169689Skan      && mode != TFmode
3537169689Skan      /* Restrict addressing for DI because of our SUBREG hackery.  */
3538169689Skan      && !(TARGET_E500_DOUBLE && (mode == DFmode || mode == DImode))
353990075Sobrien      && TARGET_UPDATE
3540132718Skan      && legitimate_indirect_address_p (XEXP (x, 0), reg_ok_strict))
354190075Sobrien    return 1;
3542132718Skan  if (legitimate_small_data_p (mode, x))
354390075Sobrien    return 1;
3544132718Skan  if (legitimate_constant_pool_address_p (x))
354590075Sobrien    return 1;
354690075Sobrien  /* If not REG_OK_STRICT (before reload) let pass any stack offset.  */
354790075Sobrien  if (! reg_ok_strict
354890075Sobrien      && GET_CODE (x) == PLUS
354990075Sobrien      && GET_CODE (XEXP (x, 0)) == REG
3550132718Skan      && (XEXP (x, 0) == virtual_stack_vars_rtx
3551132718Skan	  || XEXP (x, 0) == arg_pointer_rtx)
355290075Sobrien      && GET_CODE (XEXP (x, 1)) == CONST_INT)
355390075Sobrien    return 1;
3554169689Skan  if (rs6000_legitimate_offset_address_p (mode, x, reg_ok_strict))
355590075Sobrien    return 1;
355690075Sobrien  if (mode != TImode
3557169689Skan      && mode != TFmode
3558117395Skan      && ((TARGET_HARD_FLOAT && TARGET_FPRS)
3559117395Skan	  || TARGET_POWERPC64
3560169689Skan	  || ((mode != DFmode || TARGET_E500_DOUBLE) && mode != TFmode))
356190075Sobrien      && (TARGET_POWERPC64 || mode != DImode)
3562132718Skan      && legitimate_indexed_address_p (x, reg_ok_strict))
356390075Sobrien    return 1;
3564132718Skan  if (legitimate_lo_sum_address_p (mode, x, reg_ok_strict))
356590075Sobrien    return 1;
356690075Sobrien  return 0;
356790075Sobrien}
3568132718Skan
3569132718Skan/* Go to LABEL if ADDR (a legitimate address expression)
3570132718Skan   has an effect that depends on the machine mode it is used for.
3571132718Skan
3572132718Skan   On the RS/6000 this is true of all integral offsets (since AltiVec
3573132718Skan   modes don't allow them) or is a pre-increment or decrement.
3574132718Skan
3575132718Skan   ??? Except that due to conceptual problems in offsettable_address_p
3576132718Skan   we can't really report the problems of integral offsets.  So leave
3577169689Skan   this assuming that the adjustable offset must be valid for the
3578132718Skan   sub-words of a TFmode operand, which is what we had before.  */
3579132718Skan
3580132718Skanbool
3581132718Skanrs6000_mode_dependent_address (rtx addr)
3582132718Skan{
3583132718Skan  switch (GET_CODE (addr))
3584132718Skan    {
3585132718Skan    case PLUS:
3586132718Skan      if (GET_CODE (XEXP (addr, 1)) == CONST_INT)
3587132718Skan	{
3588132718Skan	  unsigned HOST_WIDE_INT val = INTVAL (XEXP (addr, 1));
3589132718Skan	  return val + 12 + 0x8000 >= 0x10000;
3590132718Skan	}
3591132718Skan      break;
3592132718Skan
3593132718Skan    case LO_SUM:
3594132718Skan      return true;
3595132718Skan
3596132718Skan    case PRE_INC:
3597132718Skan    case PRE_DEC:
3598132718Skan      return TARGET_UPDATE;
3599132718Skan
3600132718Skan    default:
3601132718Skan      break;
3602132718Skan    }
3603132718Skan
3604132718Skan  return false;
3605132718Skan}
3606169689Skan
3607169689Skan/* More elaborate version of recog's offsettable_memref_p predicate
3608169689Skan   that works around the ??? note of rs6000_mode_dependent_address.
3609169689Skan   In particular it accepts
3610169689Skan
3611169689Skan     (mem:DI (plus:SI (reg/f:SI 31 31) (const_int 32760 [0x7ff8])))
3612169689Skan
3613169689Skan   in 32-bit mode, that the recog predicate rejects.  */
3614169689Skan
3615169689Skanbool
3616169689Skanrs6000_offsettable_memref_p (rtx op)
3617169689Skan{
3618169689Skan  if (!MEM_P (op))
3619169689Skan    return false;
3620169689Skan
3621169689Skan  /* First mimic offsettable_memref_p.  */
3622169689Skan  if (offsettable_address_p (1, GET_MODE (op), XEXP (op, 0)))
3623169689Skan    return true;
3624169689Skan
3625169689Skan  /* offsettable_address_p invokes rs6000_mode_dependent_address, but
3626169689Skan     the latter predicate knows nothing about the mode of the memory
3627169689Skan     reference and, therefore, assumes that it is the largest supported
3628169689Skan     mode (TFmode).  As a consequence, legitimate offsettable memory
3629169689Skan     references are rejected.  rs6000_legitimate_offset_address_p contains
3630169689Skan     the correct logic for the PLUS case of rs6000_mode_dependent_address.  */
3631169689Skan  return rs6000_legitimate_offset_address_p (GET_MODE (op), XEXP (op, 0), 1);
3632169689Skan}
3633169689Skan
3634169689Skan/* Return number of consecutive hard regs needed starting at reg REGNO
3635169689Skan   to hold something of mode MODE.
3636169689Skan   This is ordinarily the length in words of a value of mode MODE
3637169689Skan   but can be less for certain modes in special long registers.
3638169689Skan
3639169689Skan   For the SPE, GPRs are 64 bits but only 32 bits are visible in
3640169689Skan   scalar instructions.  The upper 32 bits are only available to the
3641169689Skan   SIMD instructions.
3642169689Skan
3643169689Skan   POWER and PowerPC GPRs hold 32 bits worth;
3644169689Skan   PowerPC64 GPRs and FPRs point register holds 64 bits worth.  */
3645169689Skan
3646169689Skanint
3647169689Skanrs6000_hard_regno_nregs (int regno, enum machine_mode mode)
3648169689Skan{
3649169689Skan  if (FP_REGNO_P (regno))
3650169689Skan    return (GET_MODE_SIZE (mode) + UNITS_PER_FP_WORD - 1) / UNITS_PER_FP_WORD;
3651169689Skan
3652169689Skan  if (SPE_SIMD_REGNO_P (regno) && TARGET_SPE && SPE_VECTOR_MODE (mode))
3653169689Skan    return (GET_MODE_SIZE (mode) + UNITS_PER_SPE_WORD - 1) / UNITS_PER_SPE_WORD;
3654169689Skan
3655169689Skan  if (ALTIVEC_REGNO_P (regno))
3656169689Skan    return
3657169689Skan      (GET_MODE_SIZE (mode) + UNITS_PER_ALTIVEC_WORD - 1) / UNITS_PER_ALTIVEC_WORD;
3658169689Skan
3659169689Skan  /* The value returned for SCmode in the E500 double case is 2 for
3660169689Skan     ABI compatibility; storing an SCmode value in a single register
3661169689Skan     would require function_arg and rs6000_spe_function_arg to handle
3662169689Skan     SCmode so as to pass the value correctly in a pair of
3663169689Skan     registers.  */
3664169689Skan  if (TARGET_E500_DOUBLE && FLOAT_MODE_P (mode) && mode != SCmode)
3665169689Skan    return (GET_MODE_SIZE (mode) + UNITS_PER_FP_WORD - 1) / UNITS_PER_FP_WORD;
3666169689Skan
3667169689Skan  return (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
3668169689Skan}
3669169689Skan
3670169689Skan/* Change register usage conditional on target flags.  */
3671169689Skanvoid
3672169689Skanrs6000_conditional_register_usage (void)
3673169689Skan{
3674169689Skan  int i;
3675169689Skan
3676169689Skan  /* Set MQ register fixed (already call_used) if not POWER
3677169689Skan     architecture (RIOS1, RIOS2, RSC, and PPC601) so that it will not
3678169689Skan     be allocated.  */
3679169689Skan  if (! TARGET_POWER)
3680169689Skan    fixed_regs[64] = 1;
3681169689Skan
3682169689Skan  /* 64-bit AIX and Linux reserve GPR13 for thread-private data.  */
3683169689Skan  if (TARGET_64BIT)
3684169689Skan    fixed_regs[13] = call_used_regs[13]
3685169689Skan      = call_really_used_regs[13] = 1;
3686169689Skan
3687169689Skan  /* Conditionally disable FPRs.  */
3688169689Skan  if (TARGET_SOFT_FLOAT || !TARGET_FPRS)
3689169689Skan    for (i = 32; i < 64; i++)
3690169689Skan      fixed_regs[i] = call_used_regs[i]
3691169689Skan	= call_really_used_regs[i] = 1;
3692169689Skan
3693169689Skan  /* The TOC register is not killed across calls in a way that is
3694169689Skan     visible to the compiler.  */
3695169689Skan  if (DEFAULT_ABI == ABI_AIX)
3696169689Skan    call_really_used_regs[2] = 0;
3697169689Skan
3698169689Skan  if (DEFAULT_ABI == ABI_V4
3699169689Skan      && PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM
3700169689Skan      && flag_pic == 2)
3701169689Skan    fixed_regs[RS6000_PIC_OFFSET_TABLE_REGNUM] = 1;
3702169689Skan
3703169689Skan  if (DEFAULT_ABI == ABI_V4
3704169689Skan      && PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM
3705169689Skan      && flag_pic == 1)
3706169689Skan    fixed_regs[RS6000_PIC_OFFSET_TABLE_REGNUM]
3707169689Skan      = call_used_regs[RS6000_PIC_OFFSET_TABLE_REGNUM]
3708169689Skan      = call_really_used_regs[RS6000_PIC_OFFSET_TABLE_REGNUM] = 1;
3709169689Skan
3710169689Skan  if (DEFAULT_ABI == ABI_DARWIN
3711169689Skan      && PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM)
3712169689Skan      fixed_regs[RS6000_PIC_OFFSET_TABLE_REGNUM]
3713169689Skan      = call_used_regs[RS6000_PIC_OFFSET_TABLE_REGNUM]
3714169689Skan      = call_really_used_regs[RS6000_PIC_OFFSET_TABLE_REGNUM] = 1;
3715169689Skan
3716169689Skan  if (TARGET_TOC && TARGET_MINIMAL_TOC)
3717169689Skan    fixed_regs[RS6000_PIC_OFFSET_TABLE_REGNUM]
3718169689Skan      = call_used_regs[RS6000_PIC_OFFSET_TABLE_REGNUM] = 1;
3719169689Skan
3720169689Skan  if (TARGET_ALTIVEC)
3721169689Skan    global_regs[VSCR_REGNO] = 1;
3722169689Skan
3723169689Skan  if (TARGET_SPE)
3724169689Skan    {
3725169689Skan      global_regs[SPEFSCR_REGNO] = 1;
3726169689Skan      fixed_regs[FIXED_SCRATCH]
3727169689Skan	= call_used_regs[FIXED_SCRATCH]
3728169689Skan	= call_really_used_regs[FIXED_SCRATCH] = 1;
3729169689Skan    }
3730169689Skan
3731169689Skan  if (! TARGET_ALTIVEC)
3732169689Skan    {
3733169689Skan      for (i = FIRST_ALTIVEC_REGNO; i <= LAST_ALTIVEC_REGNO; ++i)
3734169689Skan	fixed_regs[i] = call_used_regs[i] = call_really_used_regs[i] = 1;
3735169689Skan      call_really_used_regs[VRSAVE_REGNO] = 1;
3736169689Skan    }
3737169689Skan
3738169689Skan  if (TARGET_ALTIVEC_ABI)
3739169689Skan    for (i = FIRST_ALTIVEC_REGNO; i < FIRST_ALTIVEC_REGNO + 20; ++i)
3740169689Skan      call_used_regs[i] = call_really_used_regs[i] = 1;
3741169689Skan}
374290075Sobrien
374390075Sobrien/* Try to output insns to set TARGET equal to the constant C if it can
374490075Sobrien   be done in less than N insns.  Do all computations in MODE.
374590075Sobrien   Returns the place where the output has been placed if it can be
374690075Sobrien   done and the insns have been emitted.  If it would take more than N
374790075Sobrien   insns, zero is returned and no insns and emitted.  */
374890075Sobrien
374990075Sobrienrtx
3750169689Skanrs6000_emit_set_const (rtx dest, enum machine_mode mode,
3751132718Skan		       rtx source, int n ATTRIBUTE_UNUSED)
375290075Sobrien{
3753117395Skan  rtx result, insn, set;
375490075Sobrien  HOST_WIDE_INT c0, c1;
375590075Sobrien
3756169689Skan  switch (mode)
375790075Sobrien    {
3758169689Skan      case  QImode:
3759169689Skan    case HImode:
376090075Sobrien      if (dest == NULL)
3761169689Skan	dest = gen_reg_rtx (mode);
376290075Sobrien      emit_insn (gen_rtx_SET (VOIDmode, dest, source));
376390075Sobrien      return dest;
3764169689Skan
3765169689Skan    case SImode:
3766117395Skan      result = no_new_pseudos ? dest : gen_reg_rtx (SImode);
376790075Sobrien
3768117395Skan      emit_insn (gen_rtx_SET (VOIDmode, result,
3769117395Skan			      GEN_INT (INTVAL (source)
3770117395Skan				       & (~ (HOST_WIDE_INT) 0xffff))));
3771117395Skan      emit_insn (gen_rtx_SET (VOIDmode, dest,
3772117395Skan			      gen_rtx_IOR (SImode, result,
3773117395Skan					   GEN_INT (INTVAL (source) & 0xffff))));
3774117395Skan      result = dest;
3775169689Skan      break;
3776169689Skan
3777169689Skan    case DImode:
3778169689Skan      switch (GET_CODE (source))
3779117395Skan	{
3780169689Skan	case CONST_INT:
3781117395Skan	  c0 = INTVAL (source);
3782117395Skan	  c1 = -(c0 < 0);
3783169689Skan	  break;
3784169689Skan
3785169689Skan	case CONST_DOUBLE:
378690075Sobrien#if HOST_BITS_PER_WIDE_INT >= 64
3787117395Skan	  c0 = CONST_DOUBLE_LOW (source);
3788117395Skan	  c1 = -(c0 < 0);
378990075Sobrien#else
3790117395Skan	  c0 = CONST_DOUBLE_LOW (source);
3791117395Skan	  c1 = CONST_DOUBLE_HIGH (source);
379290075Sobrien#endif
3793169689Skan	  break;
3794169689Skan
3795169689Skan	default:
3796169689Skan	  gcc_unreachable ();
3797117395Skan	}
3798117395Skan
3799117395Skan      result = rs6000_emit_set_long_const (dest, c0, c1);
3800169689Skan      break;
3801169689Skan
3802169689Skan    default:
3803169689Skan      gcc_unreachable ();
380490075Sobrien    }
380590075Sobrien
3806117395Skan  insn = get_last_insn ();
3807117395Skan  set = single_set (insn);
3808117395Skan  if (! CONSTANT_P (SET_SRC (set)))
3809117395Skan    set_unique_reg_note (insn, REG_EQUAL, source);
3810117395Skan
3811117395Skan  return result;
381290075Sobrien}
381390075Sobrien
381490075Sobrien/* Having failed to find a 3 insn sequence in rs6000_emit_set_const,
381590075Sobrien   fall back to a straight forward decomposition.  We do this to avoid
381690075Sobrien   exponential run times encountered when looking for longer sequences
381790075Sobrien   with rs6000_emit_set_const.  */
381890075Sobrienstatic rtx
3819132718Skanrs6000_emit_set_long_const (rtx dest, HOST_WIDE_INT c1, HOST_WIDE_INT c2)
382090075Sobrien{
382190075Sobrien  if (!TARGET_POWERPC64)
382290075Sobrien    {
382390075Sobrien      rtx operand1, operand2;
382490075Sobrien
382590075Sobrien      operand1 = operand_subword_force (dest, WORDS_BIG_ENDIAN == 0,
382690075Sobrien					DImode);
382790075Sobrien      operand2 = operand_subword_force (dest, WORDS_BIG_ENDIAN != 0,
382890075Sobrien					DImode);
382990075Sobrien      emit_move_insn (operand1, GEN_INT (c1));
383090075Sobrien      emit_move_insn (operand2, GEN_INT (c2));
383190075Sobrien    }
383290075Sobrien  else
383390075Sobrien    {
383490075Sobrien      HOST_WIDE_INT ud1, ud2, ud3, ud4;
383590075Sobrien
383690075Sobrien      ud1 = c1 & 0xffff;
383790075Sobrien      ud2 = (c1 & 0xffff0000) >> 16;
383890075Sobrien#if HOST_BITS_PER_WIDE_INT >= 64
383990075Sobrien      c2 = c1 >> 32;
384090075Sobrien#endif
384190075Sobrien      ud3 = c2 & 0xffff;
384290075Sobrien      ud4 = (c2 & 0xffff0000) >> 16;
384390075Sobrien
3844169689Skan      if ((ud4 == 0xffff && ud3 == 0xffff && ud2 == 0xffff && (ud1 & 0x8000))
384590075Sobrien	  || (ud4 == 0 && ud3 == 0 && ud2 == 0 && ! (ud1 & 0x8000)))
384690075Sobrien	{
384790075Sobrien	  if (ud1 & 0x8000)
3848132718Skan	    emit_move_insn (dest, GEN_INT (((ud1 ^ 0x8000) -  0x8000)));
384990075Sobrien	  else
385090075Sobrien	    emit_move_insn (dest, GEN_INT (ud1));
385190075Sobrien	}
385290075Sobrien
3853169689Skan      else if ((ud4 == 0xffff && ud3 == 0xffff && (ud2 & 0x8000))
385490075Sobrien	       || (ud4 == 0 && ud3 == 0 && ! (ud2 & 0x8000)))
385590075Sobrien	{
385690075Sobrien	  if (ud2 & 0x8000)
3857169689Skan	    emit_move_insn (dest, GEN_INT (((ud2 << 16) ^ 0x80000000)
385890075Sobrien					   - 0x80000000));
385990075Sobrien	  else
386090075Sobrien	    emit_move_insn (dest, GEN_INT (ud2 << 16));
386190075Sobrien	  if (ud1 != 0)
386290075Sobrien	    emit_move_insn (dest, gen_rtx_IOR (DImode, dest, GEN_INT (ud1)));
386390075Sobrien	}
3864169689Skan      else if ((ud4 == 0xffff && (ud3 & 0x8000))
386590075Sobrien	       || (ud4 == 0 && ! (ud3 & 0x8000)))
386690075Sobrien	{
386790075Sobrien	  if (ud3 & 0x8000)
3868169689Skan	    emit_move_insn (dest, GEN_INT (((ud3 << 16) ^ 0x80000000)
386990075Sobrien					   - 0x80000000));
387090075Sobrien	  else
387190075Sobrien	    emit_move_insn (dest, GEN_INT (ud3 << 16));
387290075Sobrien
387390075Sobrien	  if (ud2 != 0)
387490075Sobrien	    emit_move_insn (dest, gen_rtx_IOR (DImode, dest, GEN_INT (ud2)));
387590075Sobrien	  emit_move_insn (dest, gen_rtx_ASHIFT (DImode, dest, GEN_INT (16)));
387690075Sobrien	  if (ud1 != 0)
387790075Sobrien	    emit_move_insn (dest, gen_rtx_IOR (DImode, dest, GEN_INT (ud1)));
387890075Sobrien	}
3879169689Skan      else
388090075Sobrien	{
388190075Sobrien	  if (ud4 & 0x8000)
3882169689Skan	    emit_move_insn (dest, GEN_INT (((ud4 << 16) ^ 0x80000000)
388390075Sobrien					   - 0x80000000));
388490075Sobrien	  else
388590075Sobrien	    emit_move_insn (dest, GEN_INT (ud4 << 16));
388690075Sobrien
388790075Sobrien	  if (ud3 != 0)
388890075Sobrien	    emit_move_insn (dest, gen_rtx_IOR (DImode, dest, GEN_INT (ud3)));
388990075Sobrien
389090075Sobrien	  emit_move_insn (dest, gen_rtx_ASHIFT (DImode, dest, GEN_INT (32)));
389190075Sobrien	  if (ud2 != 0)
3892169689Skan	    emit_move_insn (dest, gen_rtx_IOR (DImode, dest,
3893169689Skan					       GEN_INT (ud2 << 16)));
389490075Sobrien	  if (ud1 != 0)
389590075Sobrien	    emit_move_insn (dest, gen_rtx_IOR (DImode, dest, GEN_INT (ud1)));
389690075Sobrien	}
389790075Sobrien    }
389890075Sobrien  return dest;
389990075Sobrien}
390090075Sobrien
3901169689Skan/* Helper for the following.  Get rid of [r+r] memory refs
3902169689Skan   in cases where it won't work (TImode, TFmode).  */
3903169689Skan
3904169689Skanstatic void
3905169689Skanrs6000_eliminate_indexed_memrefs (rtx operands[2])
3906169689Skan{
3907169689Skan  if (GET_CODE (operands[0]) == MEM
3908169689Skan      && GET_CODE (XEXP (operands[0], 0)) != REG
3909169689Skan      && ! legitimate_constant_pool_address_p (XEXP (operands[0], 0))
3910169689Skan      && ! reload_in_progress)
3911169689Skan    operands[0]
3912169689Skan      = replace_equiv_address (operands[0],
3913169689Skan			       copy_addr_to_reg (XEXP (operands[0], 0)));
3914169689Skan
3915169689Skan  if (GET_CODE (operands[1]) == MEM
3916169689Skan      && GET_CODE (XEXP (operands[1], 0)) != REG
3917169689Skan      && ! legitimate_constant_pool_address_p (XEXP (operands[1], 0))
3918169689Skan      && ! reload_in_progress)
3919169689Skan    operands[1]
3920169689Skan      = replace_equiv_address (operands[1],
3921169689Skan			       copy_addr_to_reg (XEXP (operands[1], 0)));
3922169689Skan}
3923169689Skan
392490075Sobrien/* Emit a move from SOURCE to DEST in mode MODE.  */
392590075Sobrienvoid
3926132718Skanrs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
392790075Sobrien{
392890075Sobrien  rtx operands[2];
392990075Sobrien  operands[0] = dest;
393090075Sobrien  operands[1] = source;
3931169689Skan
393290075Sobrien  /* Sanity checks.  Check that we get CONST_DOUBLE only when we should.  */
393390075Sobrien  if (GET_CODE (operands[1]) == CONST_DOUBLE
393490075Sobrien      && ! FLOAT_MODE_P (mode)
393590075Sobrien      && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
393690075Sobrien    {
393790075Sobrien      /* FIXME.  This should never happen.  */
393890075Sobrien      /* Since it seems that it does, do the safe thing and convert
393990075Sobrien	 to a CONST_INT.  */
3940117395Skan      operands[1] = gen_int_mode (CONST_DOUBLE_LOW (operands[1]), mode);
394190075Sobrien    }
3942169689Skan  gcc_assert (GET_CODE (operands[1]) != CONST_DOUBLE
3943169689Skan	      || FLOAT_MODE_P (mode)
3944169689Skan	      || ((CONST_DOUBLE_HIGH (operands[1]) != 0
3945169689Skan		   || CONST_DOUBLE_LOW (operands[1]) < 0)
3946169689Skan		  && (CONST_DOUBLE_HIGH (operands[1]) != -1
3947169689Skan		      || CONST_DOUBLE_LOW (operands[1]) >= 0)));
394890075Sobrien
394990075Sobrien  /* Check if GCC is setting up a block move that will end up using FP
395090075Sobrien     registers as temporaries.  We must make sure this is acceptable.  */
395190075Sobrien  if (GET_CODE (operands[0]) == MEM
395290075Sobrien      && GET_CODE (operands[1]) == MEM
395390075Sobrien      && mode == DImode
395490075Sobrien      && (SLOW_UNALIGNED_ACCESS (DImode, MEM_ALIGN (operands[0]))
395590075Sobrien	  || SLOW_UNALIGNED_ACCESS (DImode, MEM_ALIGN (operands[1])))
395690075Sobrien      && ! (SLOW_UNALIGNED_ACCESS (SImode, (MEM_ALIGN (operands[0]) > 32
395790075Sobrien					    ? 32 : MEM_ALIGN (operands[0])))
395890075Sobrien	    || SLOW_UNALIGNED_ACCESS (SImode, (MEM_ALIGN (operands[1]) > 32
3959169689Skan					       ? 32
396090075Sobrien					       : MEM_ALIGN (operands[1]))))
396190075Sobrien      && ! MEM_VOLATILE_P (operands [0])
396290075Sobrien      && ! MEM_VOLATILE_P (operands [1]))
396390075Sobrien    {
396490075Sobrien      emit_move_insn (adjust_address (operands[0], SImode, 0),
396590075Sobrien		      adjust_address (operands[1], SImode, 0));
396690075Sobrien      emit_move_insn (adjust_address (operands[0], SImode, 4),
396790075Sobrien		      adjust_address (operands[1], SImode, 4));
396890075Sobrien      return;
396990075Sobrien    }
397090075Sobrien
3971169689Skan  if (!no_new_pseudos && GET_CODE (operands[0]) == MEM
3972169689Skan      && !gpc_reg_operand (operands[1], mode))
3973169689Skan    operands[1] = force_reg (mode, operands[1]);
3974117395Skan
3975117395Skan  if (mode == SFmode && ! TARGET_POWERPC
3976117395Skan      && TARGET_HARD_FLOAT && TARGET_FPRS
397790075Sobrien      && GET_CODE (operands[0]) == MEM)
397890075Sobrien    {
397990075Sobrien      int regnum;
398090075Sobrien
398190075Sobrien      if (reload_in_progress || reload_completed)
398290075Sobrien	regnum = true_regnum (operands[1]);
398390075Sobrien      else if (GET_CODE (operands[1]) == REG)
398490075Sobrien	regnum = REGNO (operands[1]);
398590075Sobrien      else
398690075Sobrien	regnum = -1;
3987169689Skan
398890075Sobrien      /* If operands[1] is a register, on POWER it may have
398990075Sobrien	 double-precision data in it, so truncate it to single
399090075Sobrien	 precision.  */
399190075Sobrien      if (FP_REGNO_P (regnum) || regnum >= FIRST_PSEUDO_REGISTER)
399290075Sobrien	{
399390075Sobrien	  rtx newreg;
399490075Sobrien	  newreg = (no_new_pseudos ? operands[1] : gen_reg_rtx (mode));
399590075Sobrien	  emit_insn (gen_aux_truncdfsf2 (newreg, operands[1]));
399690075Sobrien	  operands[1] = newreg;
399790075Sobrien	}
399890075Sobrien    }
399990075Sobrien
4000132718Skan  /* Recognize the case where operand[1] is a reference to thread-local
4001132718Skan     data and load its address to a register.  */
4002169689Skan  if (rs6000_tls_referenced_p (operands[1]))
4003132718Skan    {
4004169689Skan      enum tls_model model;
4005169689Skan      rtx tmp = operands[1];
4006169689Skan      rtx addend = NULL;
4007169689Skan
4008169689Skan      if (GET_CODE (tmp) == CONST && GET_CODE (XEXP (tmp, 0)) == PLUS)
4009169689Skan	{
4010169689Skan          addend = XEXP (XEXP (tmp, 0), 1);
4011169689Skan	  tmp = XEXP (XEXP (tmp, 0), 0);
4012169689Skan	}
4013169689Skan
4014169689Skan      gcc_assert (GET_CODE (tmp) == SYMBOL_REF);
4015169689Skan      model = SYMBOL_REF_TLS_MODEL (tmp);
4016169689Skan      gcc_assert (model != 0);
4017169689Skan
4018169689Skan      tmp = rs6000_legitimize_tls_address (tmp, model);
4019169689Skan      if (addend)
4020169689Skan	{
4021169689Skan	  tmp = gen_rtx_PLUS (mode, tmp, addend);
4022169689Skan	  tmp = force_operand (tmp, operands[0]);
4023169689Skan	}
4024169689Skan      operands[1] = tmp;
4025132718Skan    }
4026132718Skan
4027117395Skan  /* Handle the case where reload calls us with an invalid address.  */
4028117395Skan  if (reload_in_progress && mode == Pmode
402996263Sobrien      && (! general_operand (operands[1], mode)
4030117395Skan	  || ! nonimmediate_operand (operands[0], mode)))
4031117395Skan    goto emit_set;
4032117395Skan
4033132718Skan  /* 128-bit constant floating-point values on Darwin should really be
4034132718Skan     loaded as two parts.  */
4035169689Skan  if (!TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128
4036132718Skan      && mode == TFmode && GET_CODE (operands[1]) == CONST_DOUBLE)
4037132718Skan    {
4038132718Skan      /* DImode is used, not DFmode, because simplify_gen_subreg doesn't
4039132718Skan	 know how to get a DFmode SUBREG of a TFmode.  */
4040132718Skan      rs6000_emit_move (simplify_gen_subreg (DImode, operands[0], mode, 0),
4041132718Skan			simplify_gen_subreg (DImode, operands[1], mode, 0),
4042132718Skan			DImode);
4043132718Skan      rs6000_emit_move (simplify_gen_subreg (DImode, operands[0], mode,
4044132718Skan					     GET_MODE_SIZE (DImode)),
4045132718Skan			simplify_gen_subreg (DImode, operands[1], mode,
4046132718Skan					     GET_MODE_SIZE (DImode)),
4047132718Skan			DImode);
4048132718Skan      return;
4049132718Skan    }
4050132718Skan
405190075Sobrien  /* FIXME:  In the long term, this switch statement should go away
405290075Sobrien     and be replaced by a sequence of tests based on things like
405390075Sobrien     mode == Pmode.  */
405490075Sobrien  switch (mode)
405590075Sobrien    {
405690075Sobrien    case HImode:
405790075Sobrien    case QImode:
405890075Sobrien      if (CONSTANT_P (operands[1])
405990075Sobrien	  && GET_CODE (operands[1]) != CONST_INT)
406090075Sobrien	operands[1] = force_const_mem (mode, operands[1]);
406190075Sobrien      break;
406290075Sobrien
406390075Sobrien    case TFmode:
4064169689Skan      rs6000_eliminate_indexed_memrefs (operands);
4065169689Skan      /* fall through */
4066169689Skan
406790075Sobrien    case DFmode:
406890075Sobrien    case SFmode:
4069169689Skan      if (CONSTANT_P (operands[1])
407090075Sobrien	  && ! easy_fp_constant (operands[1], mode))
407190075Sobrien	operands[1] = force_const_mem (mode, operands[1]);
407290075Sobrien      break;
4073169689Skan
407490075Sobrien    case V16QImode:
407590075Sobrien    case V8HImode:
407690075Sobrien    case V4SFmode:
407790075Sobrien    case V4SImode:
4078117395Skan    case V4HImode:
4079117395Skan    case V2SFmode:
4080117395Skan    case V2SImode:
4081117395Skan    case V1DImode:
408296263Sobrien      if (CONSTANT_P (operands[1])
4083132718Skan	  && !easy_vector_constant (operands[1], mode))
408490075Sobrien	operands[1] = force_const_mem (mode, operands[1]);
408590075Sobrien      break;
4086169689Skan
408790075Sobrien    case SImode:
408890075Sobrien    case DImode:
408990075Sobrien      /* Use default pattern for address of ELF small data */
409090075Sobrien      if (TARGET_ELF
409190075Sobrien	  && mode == Pmode
409290075Sobrien	  && DEFAULT_ABI == ABI_V4
4093169689Skan	  && (GET_CODE (operands[1]) == SYMBOL_REF
409490075Sobrien	      || GET_CODE (operands[1]) == CONST)
409590075Sobrien	  && small_data_operand (operands[1], mode))
409690075Sobrien	{
409790075Sobrien	  emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
409890075Sobrien	  return;
409990075Sobrien	}
410090075Sobrien
410190075Sobrien      if (DEFAULT_ABI == ABI_V4
410290075Sobrien	  && mode == Pmode && mode == SImode
410390075Sobrien	  && flag_pic == 1 && got_operand (operands[1], mode))
410490075Sobrien	{
410590075Sobrien	  emit_insn (gen_movsi_got (operands[0], operands[1]));
410690075Sobrien	  return;
410790075Sobrien	}
410890075Sobrien
410990075Sobrien      if ((TARGET_ELF || DEFAULT_ABI == ABI_DARWIN)
4110132718Skan	  && TARGET_NO_TOC
4111132718Skan	  && ! flag_pic
411290075Sobrien	  && mode == Pmode
411390075Sobrien	  && CONSTANT_P (operands[1])
411490075Sobrien	  && GET_CODE (operands[1]) != HIGH
411590075Sobrien	  && GET_CODE (operands[1]) != CONST_INT)
411690075Sobrien	{
411790075Sobrien	  rtx target = (no_new_pseudos ? operands[0] : gen_reg_rtx (mode));
411890075Sobrien
411990075Sobrien	  /* If this is a function address on -mcall-aixdesc,
412090075Sobrien	     convert it to the address of the descriptor.  */
412190075Sobrien	  if (DEFAULT_ABI == ABI_AIX
412290075Sobrien	      && GET_CODE (operands[1]) == SYMBOL_REF
412390075Sobrien	      && XSTR (operands[1], 0)[0] == '.')
412490075Sobrien	    {
412590075Sobrien	      const char *name = XSTR (operands[1], 0);
412690075Sobrien	      rtx new_ref;
412790075Sobrien	      while (*name == '.')
412890075Sobrien		name++;
412990075Sobrien	      new_ref = gen_rtx_SYMBOL_REF (Pmode, name);
413090075Sobrien	      CONSTANT_POOL_ADDRESS_P (new_ref)
413190075Sobrien		= CONSTANT_POOL_ADDRESS_P (operands[1]);
4132132718Skan	      SYMBOL_REF_FLAGS (new_ref) = SYMBOL_REF_FLAGS (operands[1]);
413390075Sobrien	      SYMBOL_REF_USED (new_ref) = SYMBOL_REF_USED (operands[1]);
4134169689Skan	      SYMBOL_REF_DATA (new_ref) = SYMBOL_REF_DATA (operands[1]);
413590075Sobrien	      operands[1] = new_ref;
413690075Sobrien	    }
413790075Sobrien
413890075Sobrien	  if (DEFAULT_ABI == ABI_DARWIN)
413990075Sobrien	    {
4140132718Skan#if TARGET_MACHO
4141132718Skan	      if (MACHO_DYNAMIC_NO_PIC_P)
4142132718Skan		{
4143132718Skan		  /* Take care of any required data indirection.  */
4144132718Skan		  operands[1] = rs6000_machopic_legitimize_pic_address (
4145132718Skan				  operands[1], mode, operands[0]);
4146132718Skan		  if (operands[0] != operands[1])
4147132718Skan		    emit_insn (gen_rtx_SET (VOIDmode,
4148169689Skan					    operands[0], operands[1]));
4149132718Skan		  return;
4150132718Skan		}
4151132718Skan#endif
415290075Sobrien	      emit_insn (gen_macho_high (target, operands[1]));
415390075Sobrien	      emit_insn (gen_macho_low (operands[0], target, operands[1]));
415490075Sobrien	      return;
415590075Sobrien	    }
415690075Sobrien
415790075Sobrien	  emit_insn (gen_elf_high (target, operands[1]));
415890075Sobrien	  emit_insn (gen_elf_low (operands[0], target, operands[1]));
415990075Sobrien	  return;
416090075Sobrien	}
416190075Sobrien
416290075Sobrien      /* If this is a SYMBOL_REF that refers to a constant pool entry,
416390075Sobrien	 and we have put it in the TOC, we just need to make a TOC-relative
416490075Sobrien	 reference to it.  */
416590075Sobrien      if (TARGET_TOC
416690075Sobrien	  && GET_CODE (operands[1]) == SYMBOL_REF
4167132718Skan	  && constant_pool_expr_p (operands[1])
416890075Sobrien	  && ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (operands[1]),
416990075Sobrien					      get_pool_mode (operands[1])))
417090075Sobrien	{
417190075Sobrien	  operands[1] = create_TOC_reference (operands[1]);
417290075Sobrien	}
417390075Sobrien      else if (mode == Pmode
417490075Sobrien	       && CONSTANT_P (operands[1])
417590075Sobrien	       && ((GET_CODE (operands[1]) != CONST_INT
417690075Sobrien		    && ! easy_fp_constant (operands[1], mode))
417790075Sobrien		   || (GET_CODE (operands[1]) == CONST_INT
417890075Sobrien		       && num_insns_constant (operands[1], mode) > 2)
417990075Sobrien		   || (GET_CODE (operands[0]) == REG
418090075Sobrien		       && FP_REGNO_P (REGNO (operands[0]))))
418190075Sobrien	       && GET_CODE (operands[1]) != HIGH
4182132718Skan	       && ! legitimate_constant_pool_address_p (operands[1])
4183132718Skan	       && ! toc_relative_expr_p (operands[1]))
418490075Sobrien	{
418590075Sobrien	  /* Emit a USE operation so that the constant isn't deleted if
418690075Sobrien	     expensive optimizations are turned on because nobody
418790075Sobrien	     references it.  This should only be done for operands that
418890075Sobrien	     contain SYMBOL_REFs with CONSTANT_POOL_ADDRESS_P set.
418990075Sobrien	     This should not be done for operands that contain LABEL_REFs.
419090075Sobrien	     For now, we just handle the obvious case.  */
419190075Sobrien	  if (GET_CODE (operands[1]) != LABEL_REF)
419290075Sobrien	    emit_insn (gen_rtx_USE (VOIDmode, operands[1]));
419390075Sobrien
419490075Sobrien#if TARGET_MACHO
419590075Sobrien	  /* Darwin uses a special PIC legitimizer.  */
4196132718Skan	  if (DEFAULT_ABI == ABI_DARWIN && MACHOPIC_INDIRECT)
419790075Sobrien	    {
419890075Sobrien	      operands[1] =
419990075Sobrien		rs6000_machopic_legitimize_pic_address (operands[1], mode,
420090075Sobrien							operands[0]);
420190075Sobrien	      if (operands[0] != operands[1])
420290075Sobrien		emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
420390075Sobrien	      return;
420490075Sobrien	    }
420590075Sobrien#endif
420690075Sobrien
420790075Sobrien	  /* If we are to limit the number of things we put in the TOC and
420890075Sobrien	     this is a symbol plus a constant we can add in one insn,
420990075Sobrien	     just put the symbol in the TOC and add the constant.  Don't do
421090075Sobrien	     this if reload is in progress.  */
421190075Sobrien	  if (GET_CODE (operands[1]) == CONST
421290075Sobrien	      && TARGET_NO_SUM_IN_TOC && ! reload_in_progress
421390075Sobrien	      && GET_CODE (XEXP (operands[1], 0)) == PLUS
421490075Sobrien	      && add_operand (XEXP (XEXP (operands[1], 0), 1), mode)
421590075Sobrien	      && (GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == LABEL_REF
421690075Sobrien		  || GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == SYMBOL_REF)
421790075Sobrien	      && ! side_effects_p (operands[0]))
421890075Sobrien	    {
421990075Sobrien	      rtx sym =
422090075Sobrien		force_const_mem (mode, XEXP (XEXP (operands[1], 0), 0));
422190075Sobrien	      rtx other = XEXP (XEXP (operands[1], 0), 1);
422290075Sobrien
422390075Sobrien	      sym = force_reg (mode, sym);
422490075Sobrien	      if (mode == SImode)
422590075Sobrien		emit_insn (gen_addsi3 (operands[0], sym, other));
422690075Sobrien	      else
422790075Sobrien		emit_insn (gen_adddi3 (operands[0], sym, other));
422890075Sobrien	      return;
422990075Sobrien	    }
423090075Sobrien
423190075Sobrien	  operands[1] = force_const_mem (mode, operands[1]);
423290075Sobrien
4233169689Skan	  if (TARGET_TOC
4234132718Skan	      && constant_pool_expr_p (XEXP (operands[1], 0))
423590075Sobrien	      && ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (
423690075Sobrien			get_pool_constant (XEXP (operands[1], 0)),
423790075Sobrien			get_pool_mode (XEXP (operands[1], 0))))
423890075Sobrien	    {
423990075Sobrien	      operands[1]
4240169689Skan		= gen_const_mem (mode,
4241169689Skan				 create_TOC_reference (XEXP (operands[1], 0)));
424290075Sobrien	      set_mem_alias_set (operands[1], get_TOC_alias_set ());
424390075Sobrien	    }
424490075Sobrien	}
424590075Sobrien      break;
424690075Sobrien
424790075Sobrien    case TImode:
4248169689Skan      rs6000_eliminate_indexed_memrefs (operands);
424990075Sobrien
4250117395Skan      if (TARGET_POWER)
4251132718Skan	{
4252117395Skan	  emit_insn (gen_rtx_PARALLEL (VOIDmode,
4253117395Skan		       gen_rtvec (2,
4254117395Skan				  gen_rtx_SET (VOIDmode,
4255117395Skan					       operands[0], operands[1]),
4256117395Skan				  gen_rtx_CLOBBER (VOIDmode,
4257117395Skan						   gen_rtx_SCRATCH (SImode)))));
4258117395Skan	  return;
4259117395Skan	}
426090075Sobrien      break;
426190075Sobrien
426290075Sobrien    default:
4263169689Skan      gcc_unreachable ();
426490075Sobrien    }
426590075Sobrien
426690075Sobrien  /* Above, we may have called force_const_mem which may have returned
426790075Sobrien     an invalid address.  If we can, fix this up; otherwise, reload will
426890075Sobrien     have to deal with it.  */
4269117395Skan  if (GET_CODE (operands[1]) == MEM && ! reload_in_progress)
4270117395Skan    operands[1] = validize_mem (operands[1]);
427190075Sobrien
4272117395Skan emit_set:
427390075Sobrien  emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
427490075Sobrien}
427590075Sobrien
4276132718Skan/* Nonzero if we can use a floating-point register to pass this arg.  */
4277132718Skan#define USE_FP_FOR_ARG_P(CUM,MODE,TYPE)		\
4278169689Skan  (SCALAR_FLOAT_MODE_P (MODE)			\
4279169689Skan   && !DECIMAL_FLOAT_MODE_P (MODE)		\
4280132718Skan   && (CUM)->fregno <= FP_ARG_MAX_REG		\
4281132718Skan   && TARGET_HARD_FLOAT && TARGET_FPRS)
4282132718Skan
4283132718Skan/* Nonzero if we can use an AltiVec register to pass this arg.  */
4284132718Skan#define USE_ALTIVEC_FOR_ARG_P(CUM,MODE,TYPE,NAMED)	\
4285132718Skan  (ALTIVEC_VECTOR_MODE (MODE)				\
4286132718Skan   && (CUM)->vregno <= ALTIVEC_ARG_MAX_REG		\
4287132718Skan   && TARGET_ALTIVEC_ABI				\
4288132718Skan   && (NAMED))
4289132718Skan
4290132718Skan/* Return a nonzero value to say to return the function value in
4291132718Skan   memory, just as large structures are always returned.  TYPE will be
4292132718Skan   the data type of the value, and FNTYPE will be the type of the
4293132718Skan   function doing the returning, or @code{NULL} for libcalls.
4294132718Skan
4295132718Skan   The AIX ABI for the RS/6000 specifies that all structures are
4296132718Skan   returned in memory.  The Darwin ABI does the same.  The SVR4 ABI
4297132718Skan   specifies that structures <= 8 bytes are returned in r3/r4, but a
4298132718Skan   draft put them in memory, and GCC used to implement the draft
4299169689Skan   instead of the final standard.  Therefore, aix_struct_return
4300132718Skan   controls this instead of DEFAULT_ABI; V.4 targets needing backward
4301132718Skan   compatibility can change DRAFT_V4_STRUCT_RET to override the
4302132718Skan   default, and -m switches get the final word.  See
4303132718Skan   rs6000_override_options for more details.
4304132718Skan
4305132718Skan   The PPC32 SVR4 ABI uses IEEE double extended for long double, if 128-bit
4306132718Skan   long double support is enabled.  These values are returned in memory.
4307132718Skan
4308132718Skan   int_size_in_bytes returns -1 for variable size objects, which go in
4309132718Skan   memory always.  The cast to unsigned makes -1 > 8.  */
4310132718Skan
4311132718Skanstatic bool
4312132718Skanrs6000_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
4313132718Skan{
4314169689Skan  /* In the darwin64 abi, try to use registers for larger structs
4315169689Skan     if possible.  */
4316169689Skan  if (rs6000_darwin64_abi
4317169689Skan      && TREE_CODE (type) == RECORD_TYPE
4318169689Skan      && int_size_in_bytes (type) > 0)
4319169689Skan    {
4320169689Skan      CUMULATIVE_ARGS valcum;
4321169689Skan      rtx valret;
4322169689Skan
4323169689Skan      valcum.words = 0;
4324169689Skan      valcum.fregno = FP_ARG_MIN_REG;
4325169689Skan      valcum.vregno = ALTIVEC_ARG_MIN_REG;
4326169689Skan      /* Do a trial code generation as if this were going to be passed
4327169689Skan	 as an argument; if any part goes in memory, we return NULL.  */
4328169689Skan      valret = rs6000_darwin64_record_arg (&valcum, type, 1, true);
4329169689Skan      if (valret)
4330169689Skan	return false;
4331169689Skan      /* Otherwise fall through to more conventional ABI rules.  */
4332169689Skan    }
4333169689Skan
4334132718Skan  if (AGGREGATE_TYPE_P (type)
4335169689Skan      && (aix_struct_return
4336132718Skan	  || (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 8))
4337132718Skan    return true;
4338169689Skan
4339169689Skan  /* Allow -maltivec -mabi=no-altivec without warning.  Altivec vector
4340169689Skan     modes only exist for GCC vector types if -maltivec.  */
4341169689Skan  if (TARGET_32BIT && !TARGET_ALTIVEC_ABI
4342169689Skan      && ALTIVEC_VECTOR_MODE (TYPE_MODE (type)))
4343169689Skan    return false;
4344169689Skan
4345169689Skan  /* Return synthetic vectors in memory.  */
4346169689Skan  if (TREE_CODE (type) == VECTOR_TYPE
4347169689Skan      && int_size_in_bytes (type) > (TARGET_ALTIVEC_ABI ? 16 : 8))
4348169689Skan    {
4349169689Skan      static bool warned_for_return_big_vectors = false;
4350169689Skan      if (!warned_for_return_big_vectors)
4351169689Skan	{
4352169689Skan	  warning (0, "GCC vector returned by reference: "
4353169689Skan		   "non-standard ABI extension with no compatibility guarantee");
4354169689Skan	  warned_for_return_big_vectors = true;
4355169689Skan	}
4356169689Skan      return true;
4357169689Skan    }
4358169689Skan
4359169689Skan  if (DEFAULT_ABI == ABI_V4 && TARGET_IEEEQUAD && TYPE_MODE (type) == TFmode)
4360132718Skan    return true;
4361169689Skan
4362132718Skan  return false;
4363132718Skan}
4364132718Skan
436590075Sobrien/* Initialize a variable CUM of type CUMULATIVE_ARGS
436690075Sobrien   for a call to a function whose data type is FNTYPE.
436790075Sobrien   For a library call, FNTYPE is 0.
436890075Sobrien
436990075Sobrien   For incoming args we set the number of arguments in the prototype large
437090075Sobrien   so we never return a PARALLEL.  */
437190075Sobrien
437290075Sobrienvoid
4373169689Skaninit_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
4374132718Skan		      rtx libname ATTRIBUTE_UNUSED, int incoming,
4375132718Skan		      int libcall, int n_named_args)
437690075Sobrien{
437790075Sobrien  static CUMULATIVE_ARGS zero_cumulative;
437890075Sobrien
437990075Sobrien  *cum = zero_cumulative;
438090075Sobrien  cum->words = 0;
438190075Sobrien  cum->fregno = FP_ARG_MIN_REG;
438290075Sobrien  cum->vregno = ALTIVEC_ARG_MIN_REG;
438390075Sobrien  cum->prototype = (fntype && TYPE_ARG_TYPES (fntype));
4384117395Skan  cum->call_cookie = ((DEFAULT_ABI == ABI_V4 && libcall)
4385117395Skan		      ? CALL_LIBCALL : CALL_NORMAL);
438690075Sobrien  cum->sysv_gregno = GP_ARG_MIN_REG;
4387132718Skan  cum->stdarg = fntype
4388132718Skan    && (TYPE_ARG_TYPES (fntype) != 0
4389132718Skan	&& (TREE_VALUE (tree_last  (TYPE_ARG_TYPES (fntype)))
4390132718Skan	    != void_type_node));
439190075Sobrien
4392132718Skan  cum->nargs_prototype = 0;
4393132718Skan  if (incoming || cum->prototype)
4394132718Skan    cum->nargs_prototype = n_named_args;
439590075Sobrien
4396117395Skan  /* Check for a longcall attribute.  */
4397146895Skan  if ((!fntype && rs6000_default_long_calls)
4398146895Skan      || (fntype
4399146895Skan	  && lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype))
4400146895Skan	  && !lookup_attribute ("shortcall", TYPE_ATTRIBUTES (fntype))))
4401146895Skan    cum->call_cookie |= CALL_LONG;
440290075Sobrien
440390075Sobrien  if (TARGET_DEBUG_ARG)
440490075Sobrien    {
440590075Sobrien      fprintf (stderr, "\ninit_cumulative_args:");
440690075Sobrien      if (fntype)
440790075Sobrien	{
440890075Sobrien	  tree ret_type = TREE_TYPE (fntype);
440990075Sobrien	  fprintf (stderr, " ret code = %s,",
441090075Sobrien		   tree_code_name[ (int)TREE_CODE (ret_type) ]);
441190075Sobrien	}
441290075Sobrien
441390075Sobrien      if (cum->call_cookie & CALL_LONG)
441490075Sobrien	fprintf (stderr, " longcall,");
441590075Sobrien
441690075Sobrien      fprintf (stderr, " proto = %d, nargs = %d\n",
441790075Sobrien	       cum->prototype, cum->nargs_prototype);
441890075Sobrien    }
4419169689Skan
4420169689Skan  if (fntype
4421169689Skan      && !TARGET_ALTIVEC
4422169689Skan      && TARGET_ALTIVEC_ABI
4423169689Skan      && ALTIVEC_VECTOR_MODE (TYPE_MODE (TREE_TYPE (fntype))))
4424169689Skan    {
4425169689Skan      error ("cannot return value in vector register because"
4426169689Skan	     " altivec instructions are disabled, use -maltivec"
4427169689Skan	     " to enable them");
4428169689Skan    }
442990075Sobrien}
443090075Sobrien
4431169689Skan/* Return true if TYPE must be passed on the stack and not in registers.  */
4432169689Skan
4433169689Skanstatic bool
4434169689Skanrs6000_must_pass_in_stack (enum machine_mode mode, tree type)
4435169689Skan{
4436169689Skan  if (DEFAULT_ABI == ABI_AIX || TARGET_64BIT)
4437169689Skan    return must_pass_in_stack_var_size (mode, type);
4438169689Skan  else
4439169689Skan    return must_pass_in_stack_var_size_or_pad (mode, type);
4440169689Skan}
4441169689Skan
444290075Sobrien/* If defined, a C expression which determines whether, and in which
444390075Sobrien   direction, to pad out an argument with extra space.  The value
444490075Sobrien   should be of type `enum direction': either `upward' to pad above
444590075Sobrien   the argument, `downward' to pad below, or `none' to inhibit
444690075Sobrien   padding.
444790075Sobrien
444890075Sobrien   For the AIX ABI structs are always stored left shifted in their
444990075Sobrien   argument slot.  */
445090075Sobrien
445190075Sobrienenum direction
4452132718Skanfunction_arg_padding (enum machine_mode mode, tree type)
445390075Sobrien{
4454132718Skan#ifndef AGGREGATE_PADDING_FIXED
4455132718Skan#define AGGREGATE_PADDING_FIXED 0
4456132718Skan#endif
4457132718Skan#ifndef AGGREGATES_PAD_UPWARD_ALWAYS
4458132718Skan#define AGGREGATES_PAD_UPWARD_ALWAYS 0
4459132718Skan#endif
446090075Sobrien
4461132718Skan  if (!AGGREGATE_PADDING_FIXED)
4462132718Skan    {
4463132718Skan      /* GCC used to pass structures of the same size as integer types as
4464132718Skan	 if they were in fact integers, ignoring FUNCTION_ARG_PADDING.
4465169689Skan	 i.e. Structures of size 1 or 2 (or 4 when TARGET_64BIT) were
4466132718Skan	 passed padded downward, except that -mstrict-align further
4467132718Skan	 muddied the water in that multi-component structures of 2 and 4
4468132718Skan	 bytes in size were passed padded upward.
4469132718Skan
4470132718Skan	 The following arranges for best compatibility with previous
4471132718Skan	 versions of gcc, but removes the -mstrict-align dependency.  */
4472132718Skan      if (BYTES_BIG_ENDIAN)
4473132718Skan	{
4474132718Skan	  HOST_WIDE_INT size = 0;
4475132718Skan
4476132718Skan	  if (mode == BLKmode)
4477132718Skan	    {
4478132718Skan	      if (type && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST)
4479132718Skan		size = int_size_in_bytes (type);
4480132718Skan	    }
4481132718Skan	  else
4482132718Skan	    size = GET_MODE_SIZE (mode);
4483132718Skan
4484132718Skan	  if (size == 1 || size == 2 || size == 4)
4485132718Skan	    return downward;
4486132718Skan	}
4487132718Skan      return upward;
4488132718Skan    }
4489132718Skan
4490132718Skan  if (AGGREGATES_PAD_UPWARD_ALWAYS)
4491132718Skan    {
4492132718Skan      if (type != 0 && AGGREGATE_TYPE_P (type))
4493132718Skan	return upward;
4494132718Skan    }
4495132718Skan
4496132718Skan  /* Fall back to the default.  */
4497132718Skan  return DEFAULT_FUNCTION_ARG_PADDING (mode, type);
449890075Sobrien}
449990075Sobrien
450090075Sobrien/* If defined, a C expression that gives the alignment boundary, in bits,
4501169689Skan   of an argument with the specified mode and type.  If it is not defined,
450290075Sobrien   PARM_BOUNDARY is used for all arguments.
450390075Sobrien
4504169689Skan   V.4 wants long longs and doubles to be double word aligned.  Just
4505169689Skan   testing the mode size is a boneheaded way to do this as it means
4506169689Skan   that other types such as complex int are also double word aligned.
4507169689Skan   However, we're stuck with this because changing the ABI might break
4508169689Skan   existing library interfaces.
4509169689Skan
4510169689Skan   Doubleword align SPE vectors.
4511169689Skan   Quadword align Altivec vectors.
4512169689Skan   Quadword align large synthetic vector types.   */
4513169689Skan
451490075Sobrienint
4515169689Skanfunction_arg_boundary (enum machine_mode mode, tree type)
451690075Sobrien{
4517169689Skan  if (DEFAULT_ABI == ABI_V4
4518169689Skan      && (GET_MODE_SIZE (mode) == 8
4519169689Skan	  || (TARGET_HARD_FLOAT
4520169689Skan	      && TARGET_FPRS
4521169689Skan	      && mode == TFmode)))
452290075Sobrien    return 64;
4523169689Skan  else if (SPE_VECTOR_MODE (mode)
4524169689Skan	   || (type && TREE_CODE (type) == VECTOR_TYPE
4525169689Skan	       && int_size_in_bytes (type) >= 8
4526169689Skan	       && int_size_in_bytes (type) < 16))
4527132718Skan    return 64;
4528169689Skan  else if (ALTIVEC_VECTOR_MODE (mode)
4529169689Skan	   || (type && TREE_CODE (type) == VECTOR_TYPE
4530169689Skan	       && int_size_in_bytes (type) >= 16))
453190075Sobrien    return 128;
4532169689Skan  else if (rs6000_darwin64_abi && mode == BLKmode
4533169689Skan	   && type && TYPE_ALIGN (type) > 64)
4534169689Skan    return 128;
453590075Sobrien  else
453690075Sobrien    return PARM_BOUNDARY;
453790075Sobrien}
4538132718Skan
4539169689Skan/* For a function parm of MODE and TYPE, return the starting word in
4540169689Skan   the parameter area.  NWORDS of the parameter area are already used.  */
4541169689Skan
4542169689Skanstatic unsigned int
4543169689Skanrs6000_parm_start (enum machine_mode mode, tree type, unsigned int nwords)
4544169689Skan{
4545169689Skan  unsigned int align;
4546169689Skan  unsigned int parm_offset;
4547169689Skan
4548169689Skan  align = function_arg_boundary (mode, type) / PARM_BOUNDARY - 1;
4549169689Skan  parm_offset = DEFAULT_ABI == ABI_V4 ? 2 : 6;
4550169689Skan  return nwords + (-(parm_offset + nwords) & align);
4551169689Skan}
4552169689Skan
4553132718Skan/* Compute the size (in words) of a function argument.  */
4554132718Skan
4555132718Skanstatic unsigned long
4556132718Skanrs6000_arg_size (enum machine_mode mode, tree type)
4557132718Skan{
4558132718Skan  unsigned long size;
4559132718Skan
4560132718Skan  if (mode != BLKmode)
4561132718Skan    size = GET_MODE_SIZE (mode);
4562132718Skan  else
4563132718Skan    size = int_size_in_bytes (type);
4564132718Skan
4565132718Skan  if (TARGET_32BIT)
4566132718Skan    return (size + 3) >> 2;
4567132718Skan  else
4568132718Skan    return (size + 7) >> 3;
4569132718Skan}
457090075Sobrien
4571169689Skan/* Use this to flush pending int fields.  */
4572169689Skan
4573169689Skanstatic void
4574169689Skanrs6000_darwin64_record_arg_advance_flush (CUMULATIVE_ARGS *cum,
4575169689Skan					  HOST_WIDE_INT bitpos)
4576169689Skan{
4577169689Skan  unsigned int startbit, endbit;
4578169689Skan  int intregs, intoffset;
4579169689Skan  enum machine_mode mode;
4580169689Skan
4581169689Skan  if (cum->intoffset == -1)
4582169689Skan    return;
4583169689Skan
4584169689Skan  intoffset = cum->intoffset;
4585169689Skan  cum->intoffset = -1;
4586169689Skan
4587169689Skan  if (intoffset % BITS_PER_WORD != 0)
4588169689Skan    {
4589169689Skan      mode = mode_for_size (BITS_PER_WORD - intoffset % BITS_PER_WORD,
4590169689Skan			    MODE_INT, 0);
4591169689Skan      if (mode == BLKmode)
4592169689Skan	{
4593169689Skan	  /* We couldn't find an appropriate mode, which happens,
4594169689Skan	     e.g., in packed structs when there are 3 bytes to load.
4595169689Skan	     Back intoffset back to the beginning of the word in this
4596169689Skan	     case.  */
4597169689Skan	  intoffset = intoffset & -BITS_PER_WORD;
4598169689Skan	}
4599169689Skan    }
4600169689Skan
4601169689Skan  startbit = intoffset & -BITS_PER_WORD;
4602169689Skan  endbit = (bitpos + BITS_PER_WORD - 1) & -BITS_PER_WORD;
4603169689Skan  intregs = (endbit - startbit) / BITS_PER_WORD;
4604169689Skan  cum->words += intregs;
4605169689Skan}
4606169689Skan
4607169689Skan/* The darwin64 ABI calls for us to recurse down through structs,
4608169689Skan   looking for elements passed in registers.  Unfortunately, we have
4609169689Skan   to track int register count here also because of misalignments
4610169689Skan   in powerpc alignment mode.  */
4611169689Skan
4612169689Skanstatic void
4613169689Skanrs6000_darwin64_record_arg_advance_recurse (CUMULATIVE_ARGS *cum,
4614169689Skan					    tree type,
4615169689Skan					    HOST_WIDE_INT startbitpos)
4616169689Skan{
4617169689Skan  tree f;
4618169689Skan
4619169689Skan  for (f = TYPE_FIELDS (type); f ; f = TREE_CHAIN (f))
4620169689Skan    if (TREE_CODE (f) == FIELD_DECL)
4621169689Skan      {
4622169689Skan	HOST_WIDE_INT bitpos = startbitpos;
4623169689Skan	tree ftype = TREE_TYPE (f);
4624169689Skan	enum machine_mode mode;
4625169689Skan	if (ftype == error_mark_node)
4626169689Skan	  continue;
4627169689Skan	mode = TYPE_MODE (ftype);
4628169689Skan
4629169689Skan	if (DECL_SIZE (f) != 0
4630169689Skan	    && host_integerp (bit_position (f), 1))
4631169689Skan	  bitpos += int_bit_position (f);
4632169689Skan
4633169689Skan	/* ??? FIXME: else assume zero offset.  */
4634169689Skan
4635169689Skan	if (TREE_CODE (ftype) == RECORD_TYPE)
4636169689Skan	  rs6000_darwin64_record_arg_advance_recurse (cum, ftype, bitpos);
4637169689Skan	else if (USE_FP_FOR_ARG_P (cum, mode, ftype))
4638169689Skan	  {
4639169689Skan	    rs6000_darwin64_record_arg_advance_flush (cum, bitpos);
4640169689Skan	    cum->fregno += (GET_MODE_SIZE (mode) + 7) >> 3;
4641169689Skan	    cum->words += (GET_MODE_SIZE (mode) + 7) >> 3;
4642169689Skan	  }
4643169689Skan	else if (USE_ALTIVEC_FOR_ARG_P (cum, mode, type, 1))
4644169689Skan	  {
4645169689Skan	    rs6000_darwin64_record_arg_advance_flush (cum, bitpos);
4646169689Skan	    cum->vregno++;
4647169689Skan	    cum->words += 2;
4648169689Skan	  }
4649169689Skan	else if (cum->intoffset == -1)
4650169689Skan	  cum->intoffset = bitpos;
4651169689Skan      }
4652169689Skan}
4653169689Skan
465490075Sobrien/* Update the data in CUM to advance over an argument
465590075Sobrien   of mode MODE and data type TYPE.
4656132718Skan   (TYPE is null for libcalls where that information may not be available.)
465790075Sobrien
4658132718Skan   Note that for args passed by reference, function_arg will be called
4659132718Skan   with MODE and TYPE set to that of the pointer to the arg, not the arg
4660132718Skan   itself.  */
4661132718Skan
466290075Sobrienvoid
4663169689Skanfunction_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
4664169689Skan		      tree type, int named, int depth)
466590075Sobrien{
4666169689Skan  int size;
466790075Sobrien
4668169689Skan  /* Only tick off an argument if we're not recursing.  */
4669169689Skan  if (depth == 0)
4670169689Skan    cum->nargs_prototype--;
4671169689Skan
4672169689Skan  if (TARGET_ALTIVEC_ABI
4673169689Skan      && (ALTIVEC_VECTOR_MODE (mode)
4674169689Skan	  || (type && TREE_CODE (type) == VECTOR_TYPE
4675169689Skan	      && int_size_in_bytes (type) == 16)))
467690075Sobrien    {
4677132718Skan      bool stack = false;
4678132718Skan
4679132718Skan      if (USE_ALTIVEC_FOR_ARG_P (cum, mode, type, named))
4680169689Skan	{
4681132718Skan	  cum->vregno++;
4682132718Skan	  if (!TARGET_ALTIVEC)
4683169689Skan	    error ("cannot pass argument in vector register because"
4684132718Skan		   " altivec instructions are disabled, use -maltivec"
4685169689Skan		   " to enable them");
4686132718Skan
4687132718Skan	  /* PowerPC64 Linux and AIX allocate GPRs for a vector argument
4688169689Skan	     even if it is going to be passed in a vector register.
4689132718Skan	     Darwin does the same for variable-argument functions.  */
4690132718Skan	  if ((DEFAULT_ABI == ABI_AIX && TARGET_64BIT)
4691132718Skan	      || (cum->stdarg && DEFAULT_ABI != ABI_V4))
4692132718Skan	    stack = true;
4693132718Skan	}
469490075Sobrien      else
4695132718Skan	stack = true;
4696132718Skan
4697132718Skan      if (stack)
4698169689Skan	{
4699132718Skan	  int align;
4700169689Skan
4701132718Skan	  /* Vector parameters must be 16-byte aligned.  This places
4702132718Skan	     them at 2 mod 4 in terms of words in 32-bit mode, since
4703132718Skan	     the parameter save area starts at offset 24 from the
4704132718Skan	     stack.  In 64-bit mode, they just have to start on an
4705132718Skan	     even word, since the parameter save area is 16-byte
4706132718Skan	     aligned.  Space for GPRs is reserved even if the argument
4707132718Skan	     will be passed in memory.  */
4708132718Skan	  if (TARGET_32BIT)
4709132718Skan	    align = (2 - cum->words) & 3;
4710132718Skan	  else
4711132718Skan	    align = cum->words & 1;
4712132718Skan	  cum->words += align + rs6000_arg_size (mode, type);
4713169689Skan
4714132718Skan	  if (TARGET_DEBUG_ARG)
4715132718Skan	    {
4716169689Skan	      fprintf (stderr, "function_adv: words = %2d, align=%d, ",
4717132718Skan		       cum->words, align);
4718132718Skan	      fprintf (stderr, "nargs = %4d, proto = %d, mode = %4s\n",
4719169689Skan		       cum->nargs_prototype, cum->prototype,
4720132718Skan		       GET_MODE_NAME (mode));
4721132718Skan	    }
4722132718Skan	}
472390075Sobrien    }
4724117395Skan  else if (TARGET_SPE_ABI && TARGET_SPE && SPE_VECTOR_MODE (mode)
4725132718Skan	   && !cum->stdarg
4726132718Skan	   && cum->sysv_gregno <= GP_ARG_MAX_REG)
4727117395Skan    cum->sysv_gregno++;
4728169689Skan
4729169689Skan  else if (rs6000_darwin64_abi
4730169689Skan	   && mode == BLKmode
4731169689Skan    	   && TREE_CODE (type) == RECORD_TYPE
4732169689Skan	   && (size = int_size_in_bytes (type)) > 0)
4733169689Skan    {
4734169689Skan      /* Variable sized types have size == -1 and are
4735169689Skan	 treated as if consisting entirely of ints.
4736169689Skan	 Pad to 16 byte boundary if needed.  */
4737169689Skan      if (TYPE_ALIGN (type) >= 2 * BITS_PER_WORD
4738169689Skan	  && (cum->words % 2) != 0)
4739169689Skan	cum->words++;
4740169689Skan      /* For varargs, we can just go up by the size of the struct. */
4741169689Skan      if (!named)
4742169689Skan	cum->words += (size + 7) / 8;
4743169689Skan      else
4744169689Skan	{
4745169689Skan	  /* It is tempting to say int register count just goes up by
4746169689Skan	     sizeof(type)/8, but this is wrong in a case such as
4747169689Skan	     { int; double; int; } [powerpc alignment].  We have to
4748169689Skan	     grovel through the fields for these too.  */
4749169689Skan	  cum->intoffset = 0;
4750169689Skan	  rs6000_darwin64_record_arg_advance_recurse (cum, type, 0);
4751169689Skan	  rs6000_darwin64_record_arg_advance_flush (cum,
4752169689Skan						    size * BITS_PER_UNIT);
4753169689Skan	}
4754169689Skan    }
475590075Sobrien  else if (DEFAULT_ABI == ABI_V4)
475690075Sobrien    {
4757117395Skan      if (TARGET_HARD_FLOAT && TARGET_FPRS
4758169689Skan	  && (mode == SFmode || mode == DFmode
4759169689Skan	      || (mode == TFmode && !TARGET_IEEEQUAD)))
476090075Sobrien	{
4761169689Skan	  if (cum->fregno + (mode == TFmode ? 1 : 0) <= FP_ARG_V4_MAX_REG)
4762169689Skan	    cum->fregno += (GET_MODE_SIZE (mode) + 7) >> 3;
476390075Sobrien	  else
476490075Sobrien	    {
4765169689Skan	      cum->fregno = FP_ARG_V4_MAX_REG + 1;
4766169689Skan	      if (mode == DFmode || mode == TFmode)
4767169689Skan		cum->words += cum->words & 1;
4768132718Skan	      cum->words += rs6000_arg_size (mode, type);
476990075Sobrien	    }
477090075Sobrien	}
477190075Sobrien      else
477290075Sobrien	{
4773132718Skan	  int n_words = rs6000_arg_size (mode, type);
477490075Sobrien	  int gregno = cum->sysv_gregno;
477590075Sobrien
4776132718Skan	  /* Long long and SPE vectors are put in (r3,r4), (r5,r6),
4777132718Skan	     (r7,r8) or (r9,r10).  As does any other 2 word item such
4778132718Skan	     as complex int due to a historical mistake.  */
4779132718Skan	  if (n_words == 2)
4780132718Skan	    gregno += (1 - gregno) & 1;
478190075Sobrien
4782132718Skan	  /* Multi-reg args are not split between registers and stack.  */
478390075Sobrien	  if (gregno + n_words - 1 > GP_ARG_MAX_REG)
478490075Sobrien	    {
4785132718Skan	      /* Long long and SPE vectors are aligned on the stack.
4786132718Skan		 So are other 2 word items such as complex int due to
4787132718Skan		 a historical mistake.  */
478890075Sobrien	      if (n_words == 2)
478990075Sobrien		cum->words += cum->words & 1;
479090075Sobrien	      cum->words += n_words;
479190075Sobrien	    }
479290075Sobrien
479390075Sobrien	  /* Note: continuing to accumulate gregno past when we've started
479490075Sobrien	     spilling to the stack indicates the fact that we've started
479590075Sobrien	     spilling to the stack to expand_builtin_saveregs.  */
479690075Sobrien	  cum->sysv_gregno = gregno + n_words;
479790075Sobrien	}
479890075Sobrien
479990075Sobrien      if (TARGET_DEBUG_ARG)
480090075Sobrien	{
480190075Sobrien	  fprintf (stderr, "function_adv: words = %2d, fregno = %2d, ",
480290075Sobrien		   cum->words, cum->fregno);
480390075Sobrien	  fprintf (stderr, "gregno = %2d, nargs = %4d, proto = %d, ",
480490075Sobrien		   cum->sysv_gregno, cum->nargs_prototype, cum->prototype);
480590075Sobrien	  fprintf (stderr, "mode = %4s, named = %d\n",
480690075Sobrien		   GET_MODE_NAME (mode), named);
480790075Sobrien	}
480890075Sobrien    }
480990075Sobrien  else
481090075Sobrien    {
4811132718Skan      int n_words = rs6000_arg_size (mode, type);
4812169689Skan      int start_words = cum->words;
4813169689Skan      int align_words = rs6000_parm_start (mode, type, start_words);
481490075Sobrien
4815169689Skan      cum->words = align_words + n_words;
481690075Sobrien
4817169689Skan      if (SCALAR_FLOAT_MODE_P (mode)
4818169689Skan	  && !DECIMAL_FLOAT_MODE_P (mode)
4819117395Skan	  && TARGET_HARD_FLOAT && TARGET_FPRS)
4820132718Skan	cum->fregno += (GET_MODE_SIZE (mode) + 7) >> 3;
482190075Sobrien
482290075Sobrien      if (TARGET_DEBUG_ARG)
482390075Sobrien	{
482490075Sobrien	  fprintf (stderr, "function_adv: words = %2d, fregno = %2d, ",
482590075Sobrien		   cum->words, cum->fregno);
482690075Sobrien	  fprintf (stderr, "nargs = %4d, proto = %d, mode = %4s, ",
482790075Sobrien		   cum->nargs_prototype, cum->prototype, GET_MODE_NAME (mode));
4828169689Skan	  fprintf (stderr, "named = %d, align = %d, depth = %d\n",
4829169689Skan		   named, align_words - start_words, depth);
483090075Sobrien	}
483190075Sobrien    }
483290075Sobrien}
4833132718Skan
4834169689Skanstatic rtx
4835169689Skanspe_build_register_parallel (enum machine_mode mode, int gregno)
4836169689Skan{
4837169689Skan  rtx r1, r3;
4838169689Skan
4839169689Skan  switch (mode)
4840169689Skan    {
4841169689Skan    case DFmode:
4842169689Skan      r1 = gen_rtx_REG (DImode, gregno);
4843169689Skan      r1 = gen_rtx_EXPR_LIST (VOIDmode, r1, const0_rtx);
4844169689Skan      return gen_rtx_PARALLEL (mode, gen_rtvec (1, r1));
4845169689Skan
4846169689Skan    case DCmode:
4847169689Skan      r1 = gen_rtx_REG (DImode, gregno);
4848169689Skan      r1 = gen_rtx_EXPR_LIST (VOIDmode, r1, const0_rtx);
4849169689Skan      r3 = gen_rtx_REG (DImode, gregno + 2);
4850169689Skan      r3 = gen_rtx_EXPR_LIST (VOIDmode, r3, GEN_INT (8));
4851169689Skan      return gen_rtx_PARALLEL (mode, gen_rtvec (2, r1, r3));
4852169689Skan
4853169689Skan    default:
4854169689Skan      gcc_unreachable ();
4855169689Skan    }
4856169689Skan}
4857169689Skan
4858132718Skan/* Determine where to put a SIMD argument on the SPE.  */
4859132718Skanstatic rtx
4860169689Skanrs6000_spe_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
4861132718Skan			 tree type)
4862132718Skan{
4863169689Skan  int gregno = cum->sysv_gregno;
4864169689Skan
4865169689Skan  /* On E500 v2, double arithmetic is done on the full 64-bit GPR, but
4866169689Skan     are passed and returned in a pair of GPRs for ABI compatibility.  */
4867169689Skan  if (TARGET_E500_DOUBLE && (mode == DFmode || mode == DCmode))
4868169689Skan    {
4869169689Skan      int n_words = rs6000_arg_size (mode, type);
4870169689Skan
4871169689Skan      /* Doubles go in an odd/even register pair (r5/r6, etc).  */
4872169689Skan      if (mode == DFmode)
4873169689Skan	gregno += (1 - gregno) & 1;
4874169689Skan
4875169689Skan      /* Multi-reg args are not split between registers and stack.  */
4876169689Skan      if (gregno + n_words - 1 > GP_ARG_MAX_REG)
4877169689Skan	return NULL_RTX;
4878169689Skan
4879169689Skan      return spe_build_register_parallel (mode, gregno);
4880169689Skan    }
4881132718Skan  if (cum->stdarg)
4882132718Skan    {
4883132718Skan      int n_words = rs6000_arg_size (mode, type);
4884132718Skan
4885132718Skan      /* SPE vectors are put in odd registers.  */
4886132718Skan      if (n_words == 2 && (gregno & 1) == 0)
4887132718Skan	gregno += 1;
4888132718Skan
4889132718Skan      if (gregno + n_words - 1 <= GP_ARG_MAX_REG)
4890132718Skan	{
4891132718Skan	  rtx r1, r2;
4892132718Skan	  enum machine_mode m = SImode;
4893132718Skan
4894132718Skan	  r1 = gen_rtx_REG (m, gregno);
4895132718Skan	  r1 = gen_rtx_EXPR_LIST (m, r1, const0_rtx);
4896132718Skan	  r2 = gen_rtx_REG (m, gregno + 1);
4897132718Skan	  r2 = gen_rtx_EXPR_LIST (m, r2, GEN_INT (4));
4898132718Skan	  return gen_rtx_PARALLEL (mode, gen_rtvec (2, r1, r2));
4899132718Skan	}
4900132718Skan      else
4901132718Skan	return NULL_RTX;
4902132718Skan    }
4903132718Skan  else
4904132718Skan    {
4905169689Skan      if (gregno <= GP_ARG_MAX_REG)
4906169689Skan	return gen_rtx_REG (mode, gregno);
4907132718Skan      else
4908132718Skan	return NULL_RTX;
4909132718Skan    }
4910132718Skan}
4911132718Skan
4912169689Skan/* A subroutine of rs6000_darwin64_record_arg.  Assign the bits of the
4913169689Skan   structure between cum->intoffset and bitpos to integer registers.  */
4914169689Skan
4915169689Skanstatic void
4916169689Skanrs6000_darwin64_record_arg_flush (CUMULATIVE_ARGS *cum,
4917169689Skan				  HOST_WIDE_INT bitpos, rtx rvec[], int *k)
4918169689Skan{
4919169689Skan  enum machine_mode mode;
4920169689Skan  unsigned int regno;
4921169689Skan  unsigned int startbit, endbit;
4922169689Skan  int this_regno, intregs, intoffset;
4923169689Skan  rtx reg;
4924169689Skan
4925169689Skan  if (cum->intoffset == -1)
4926169689Skan    return;
4927169689Skan
4928169689Skan  intoffset = cum->intoffset;
4929169689Skan  cum->intoffset = -1;
4930169689Skan
4931169689Skan  /* If this is the trailing part of a word, try to only load that
4932169689Skan     much into the register.  Otherwise load the whole register.  Note
4933169689Skan     that in the latter case we may pick up unwanted bits.  It's not a
4934169689Skan     problem at the moment but may wish to revisit.  */
4935169689Skan
4936169689Skan  if (intoffset % BITS_PER_WORD != 0)
4937169689Skan    {
4938169689Skan      mode = mode_for_size (BITS_PER_WORD - intoffset % BITS_PER_WORD,
4939169689Skan			  MODE_INT, 0);
4940169689Skan      if (mode == BLKmode)
4941169689Skan	{
4942169689Skan	  /* We couldn't find an appropriate mode, which happens,
4943169689Skan	     e.g., in packed structs when there are 3 bytes to load.
4944169689Skan	     Back intoffset back to the beginning of the word in this
4945169689Skan	     case.  */
4946169689Skan	 intoffset = intoffset & -BITS_PER_WORD;
4947169689Skan	 mode = word_mode;
4948169689Skan	}
4949169689Skan    }
4950169689Skan  else
4951169689Skan    mode = word_mode;
4952169689Skan
4953169689Skan  startbit = intoffset & -BITS_PER_WORD;
4954169689Skan  endbit = (bitpos + BITS_PER_WORD - 1) & -BITS_PER_WORD;
4955169689Skan  intregs = (endbit - startbit) / BITS_PER_WORD;
4956169689Skan  this_regno = cum->words + intoffset / BITS_PER_WORD;
4957169689Skan
4958169689Skan  if (intregs > 0 && intregs > GP_ARG_NUM_REG - this_regno)
4959169689Skan    cum->use_stack = 1;
4960169689Skan
4961169689Skan  intregs = MIN (intregs, GP_ARG_NUM_REG - this_regno);
4962169689Skan  if (intregs <= 0)
4963169689Skan    return;
4964169689Skan
4965169689Skan  intoffset /= BITS_PER_UNIT;
4966169689Skan  do
4967169689Skan    {
4968169689Skan      regno = GP_ARG_MIN_REG + this_regno;
4969169689Skan      reg = gen_rtx_REG (mode, regno);
4970169689Skan      rvec[(*k)++] =
4971169689Skan	gen_rtx_EXPR_LIST (VOIDmode, reg, GEN_INT (intoffset));
4972169689Skan
4973169689Skan      this_regno += 1;
4974169689Skan      intoffset = (intoffset | (UNITS_PER_WORD-1)) + 1;
4975169689Skan      mode = word_mode;
4976169689Skan      intregs -= 1;
4977169689Skan    }
4978169689Skan  while (intregs > 0);
4979169689Skan}
4980169689Skan
4981169689Skan/* Recursive workhorse for the following.  */
4982169689Skan
4983169689Skanstatic void
4984169689Skanrs6000_darwin64_record_arg_recurse (CUMULATIVE_ARGS *cum, tree type,
4985169689Skan				    HOST_WIDE_INT startbitpos, rtx rvec[],
4986169689Skan				    int *k)
4987169689Skan{
4988169689Skan  tree f;
4989169689Skan
4990169689Skan  for (f = TYPE_FIELDS (type); f ; f = TREE_CHAIN (f))
4991169689Skan    if (TREE_CODE (f) == FIELD_DECL)
4992169689Skan      {
4993169689Skan	HOST_WIDE_INT bitpos = startbitpos;
4994169689Skan	tree ftype = TREE_TYPE (f);
4995169689Skan	enum machine_mode mode;
4996169689Skan	if (ftype == error_mark_node)
4997169689Skan	  continue;
4998169689Skan	mode = TYPE_MODE (ftype);
4999169689Skan
5000169689Skan	if (DECL_SIZE (f) != 0
5001169689Skan	    && host_integerp (bit_position (f), 1))
5002169689Skan	  bitpos += int_bit_position (f);
5003169689Skan
5004169689Skan	/* ??? FIXME: else assume zero offset.  */
5005169689Skan
5006169689Skan	if (TREE_CODE (ftype) == RECORD_TYPE)
5007169689Skan	  rs6000_darwin64_record_arg_recurse (cum, ftype, bitpos, rvec, k);
5008169689Skan	else if (cum->named && USE_FP_FOR_ARG_P (cum, mode, ftype))
5009169689Skan	  {
5010169689Skan#if 0
5011169689Skan	    switch (mode)
5012169689Skan	      {
5013169689Skan	      case SCmode: mode = SFmode; break;
5014169689Skan	      case DCmode: mode = DFmode; break;
5015169689Skan	      case TCmode: mode = TFmode; break;
5016169689Skan	      default: break;
5017169689Skan	      }
5018169689Skan#endif
5019169689Skan	    rs6000_darwin64_record_arg_flush (cum, bitpos, rvec, k);
5020169689Skan	    rvec[(*k)++]
5021169689Skan	      = gen_rtx_EXPR_LIST (VOIDmode,
5022169689Skan				   gen_rtx_REG (mode, cum->fregno++),
5023169689Skan				   GEN_INT (bitpos / BITS_PER_UNIT));
5024169689Skan	    if (mode == TFmode)
5025169689Skan	      cum->fregno++;
5026169689Skan	  }
5027169689Skan	else if (cum->named && USE_ALTIVEC_FOR_ARG_P (cum, mode, ftype, 1))
5028169689Skan	  {
5029169689Skan	    rs6000_darwin64_record_arg_flush (cum, bitpos, rvec, k);
5030169689Skan	    rvec[(*k)++]
5031169689Skan	      = gen_rtx_EXPR_LIST (VOIDmode,
5032169689Skan				   gen_rtx_REG (mode, cum->vregno++),
5033169689Skan				   GEN_INT (bitpos / BITS_PER_UNIT));
5034169689Skan	  }
5035169689Skan	else if (cum->intoffset == -1)
5036169689Skan	  cum->intoffset = bitpos;
5037169689Skan      }
5038169689Skan}
5039169689Skan
5040169689Skan/* For the darwin64 ABI, we want to construct a PARALLEL consisting of
5041169689Skan   the register(s) to be used for each field and subfield of a struct
5042169689Skan   being passed by value, along with the offset of where the
5043169689Skan   register's value may be found in the block.  FP fields go in FP
5044169689Skan   register, vector fields go in vector registers, and everything
5045169689Skan   else goes in int registers, packed as in memory.
5046169689Skan
5047169689Skan   This code is also used for function return values.  RETVAL indicates
5048169689Skan   whether this is the case.
5049169689Skan
5050169689Skan   Much of this is taken from the SPARC V9 port, which has a similar
5051169689Skan   calling convention.  */
5052169689Skan
5053169689Skanstatic rtx
5054169689Skanrs6000_darwin64_record_arg (CUMULATIVE_ARGS *orig_cum, tree type,
5055169689Skan			    int named, bool retval)
5056169689Skan{
5057169689Skan  rtx rvec[FIRST_PSEUDO_REGISTER];
5058169689Skan  int k = 1, kbase = 1;
5059169689Skan  HOST_WIDE_INT typesize = int_size_in_bytes (type);
5060169689Skan  /* This is a copy; modifications are not visible to our caller.  */
5061169689Skan  CUMULATIVE_ARGS copy_cum = *orig_cum;
5062169689Skan  CUMULATIVE_ARGS *cum = &copy_cum;
5063169689Skan
5064169689Skan  /* Pad to 16 byte boundary if needed.  */
5065169689Skan  if (!retval && TYPE_ALIGN (type) >= 2 * BITS_PER_WORD
5066169689Skan      && (cum->words % 2) != 0)
5067169689Skan    cum->words++;
5068169689Skan
5069169689Skan  cum->intoffset = 0;
5070169689Skan  cum->use_stack = 0;
5071169689Skan  cum->named = named;
5072169689Skan
5073169689Skan  /* Put entries into rvec[] for individual FP and vector fields, and
5074169689Skan     for the chunks of memory that go in int regs.  Note we start at
5075169689Skan     element 1; 0 is reserved for an indication of using memory, and
5076169689Skan     may or may not be filled in below. */
5077169689Skan  rs6000_darwin64_record_arg_recurse (cum, type, 0, rvec, &k);
5078169689Skan  rs6000_darwin64_record_arg_flush (cum, typesize * BITS_PER_UNIT, rvec, &k);
5079169689Skan
5080169689Skan  /* If any part of the struct went on the stack put all of it there.
5081169689Skan     This hack is because the generic code for
5082169689Skan     FUNCTION_ARG_PARTIAL_NREGS cannot handle cases where the register
5083169689Skan     parts of the struct are not at the beginning.  */
5084169689Skan  if (cum->use_stack)
5085169689Skan    {
5086169689Skan      if (retval)
5087169689Skan	return NULL_RTX;    /* doesn't go in registers at all */
5088169689Skan      kbase = 0;
5089169689Skan      rvec[0] = gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX, const0_rtx);
5090169689Skan    }
5091169689Skan  if (k > 1 || cum->use_stack)
5092169689Skan    return gen_rtx_PARALLEL (BLKmode, gen_rtvec_v (k - kbase, &rvec[kbase]));
5093169689Skan  else
5094169689Skan    return NULL_RTX;
5095169689Skan}
5096169689Skan
5097132718Skan/* Determine where to place an argument in 64-bit mode with 32-bit ABI.  */
5098132718Skan
5099132718Skanstatic rtx
5100146895Skanrs6000_mixed_function_arg (enum machine_mode mode, tree type, int align_words)
5101132718Skan{
5102146895Skan  int n_units;
5103146895Skan  int i, k;
5104146895Skan  rtx rvec[GP_ARG_NUM_REG + 1];
5105132718Skan
5106146895Skan  if (align_words >= GP_ARG_NUM_REG)
5107146895Skan    return NULL_RTX;
5108132718Skan
5109146895Skan  n_units = rs6000_arg_size (mode, type);
5110132718Skan
5111146895Skan  /* Optimize the simple case where the arg fits in one gpr, except in
5112146895Skan     the case of BLKmode due to assign_parms assuming that registers are
5113146895Skan     BITS_PER_WORD wide.  */
5114146895Skan  if (n_units == 0
5115146895Skan      || (n_units == 1 && mode != BLKmode))
5116146895Skan    return gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
5117132718Skan
5118146895Skan  k = 0;
5119146895Skan  if (align_words + n_units > GP_ARG_NUM_REG)
5120146895Skan    /* Not all of the arg fits in gprs.  Say that it goes in memory too,
5121146895Skan       using a magic NULL_RTX component.
5122169689Skan       This is not strictly correct.  Only some of the arg belongs in
5123169689Skan       memory, not all of it.  However, the normal scheme using
5124169689Skan       function_arg_partial_nregs can result in unusual subregs, eg.
5125169689Skan       (subreg:SI (reg:DF) 4), which are not handled well.  The code to
5126169689Skan       store the whole arg to memory is often more efficient than code
5127169689Skan       to store pieces, and we know that space is available in the right
5128169689Skan       place for the whole arg.  */
5129146895Skan    rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX, const0_rtx);
5130132718Skan
5131146895Skan  i = 0;
5132146895Skan  do
5133146895Skan    {
5134146895Skan      rtx r = gen_rtx_REG (SImode, GP_ARG_MIN_REG + align_words);
5135146895Skan      rtx off = GEN_INT (i++ * 4);
5136146895Skan      rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, off);
5137146895Skan    }
5138146895Skan  while (++align_words < GP_ARG_NUM_REG && --n_units != 0);
5139146895Skan
5140146895Skan  return gen_rtx_PARALLEL (mode, gen_rtvec_v (k, rvec));
5141132718Skan}
5142132718Skan
514390075Sobrien/* Determine where to put an argument to a function.
514490075Sobrien   Value is zero to push the argument on the stack,
514590075Sobrien   or a hard register in which to store the argument.
514690075Sobrien
514790075Sobrien   MODE is the argument's machine mode.
514890075Sobrien   TYPE is the data type of the argument (as a tree).
514990075Sobrien    This is null for libcalls where that information may
515090075Sobrien    not be available.
515190075Sobrien   CUM is a variable of type CUMULATIVE_ARGS which gives info about
5152169689Skan    the preceding args and about the function being called.  It is
5153169689Skan    not modified in this routine.
515490075Sobrien   NAMED is nonzero if this argument is a named parameter
515590075Sobrien    (otherwise it is an extra parameter matching an ellipsis).
515690075Sobrien
515790075Sobrien   On RS/6000 the first eight words of non-FP are normally in registers
515890075Sobrien   and the rest are pushed.  Under AIX, the first 13 FP args are in registers.
515990075Sobrien   Under V.4, the first 8 FP args are in registers.
516090075Sobrien
516190075Sobrien   If this is floating-point and no prototype is specified, we use
516290075Sobrien   both an FP and integer register (or possibly FP reg and stack).  Library
5163117395Skan   functions (when CALL_LIBCALL is set) always have the proper types for args,
516490075Sobrien   so we can pass the FP value just in one register.  emit_library_function
5165132718Skan   doesn't support PARALLEL anyway.
516690075Sobrien
5167132718Skan   Note that for args passed by reference, function_arg will be called
5168132718Skan   with MODE and TYPE set to that of the pointer to the arg, not the arg
5169132718Skan   itself.  */
5170132718Skan
5171169689Skanrtx
5172169689Skanfunction_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
5173132718Skan	      tree type, int named)
517490075Sobrien{
517590075Sobrien  enum rs6000_abi abi = DEFAULT_ABI;
517690075Sobrien
517790075Sobrien  /* Return a marker to indicate whether CR1 needs to set or clear the
517890075Sobrien     bit that V.4 uses to say fp args were passed in registers.
517990075Sobrien     Assume that we don't need the marker for software floating point,
518090075Sobrien     or compiler generated library calls.  */
518190075Sobrien  if (mode == VOIDmode)
518290075Sobrien    {
518390075Sobrien      if (abi == ABI_V4
5184117395Skan	  && (cum->call_cookie & CALL_LIBCALL) == 0
5185161651Skan	  && (cum->stdarg
5186161651Skan	      || (cum->nargs_prototype < 0
5187161651Skan		  && (cum->prototype || TARGET_NO_PROTOTYPE))))
518890075Sobrien	{
5189117395Skan	  /* For the SPE, we need to crxor CR6 always.  */
5190117395Skan	  if (TARGET_SPE_ABI)
5191117395Skan	    return GEN_INT (cum->call_cookie | CALL_V4_SET_FP_ARGS);
5192117395Skan	  else if (TARGET_HARD_FLOAT && TARGET_FPRS)
5193117395Skan	    return GEN_INT (cum->call_cookie
5194117395Skan			    | ((cum->fregno == FP_ARG_MIN_REG)
5195117395Skan			       ? CALL_V4_SET_FP_ARGS
5196117395Skan			       : CALL_V4_CLEAR_FP_ARGS));
519790075Sobrien	}
519890075Sobrien
519990075Sobrien      return GEN_INT (cum->call_cookie);
520090075Sobrien    }
520190075Sobrien
5202169689Skan  if (rs6000_darwin64_abi && mode == BLKmode
5203169689Skan      && TREE_CODE (type) == RECORD_TYPE)
5204169689Skan    {
5205169689Skan      rtx rslt = rs6000_darwin64_record_arg (cum, type, named, false);
5206169689Skan      if (rslt != NULL_RTX)
5207169689Skan	return rslt;
5208169689Skan      /* Else fall through to usual handling.  */
5209169689Skan    }
5210169689Skan
5211132718Skan  if (USE_ALTIVEC_FOR_ARG_P (cum, mode, type, named))
5212132718Skan    if (TARGET_64BIT && ! cum->prototype)
5213132718Skan      {
5214169689Skan	/* Vector parameters get passed in vector register
5215169689Skan	   and also in GPRs or memory, in absence of prototype.  */
5216169689Skan	int align_words;
5217169689Skan	rtx slot;
5218169689Skan	align_words = (cum->words + 1) & ~1;
5219132718Skan
5220169689Skan	if (align_words >= GP_ARG_NUM_REG)
5221169689Skan	  {
5222169689Skan	    slot = NULL_RTX;
5223169689Skan	  }
5224169689Skan	else
5225169689Skan	  {
5226169689Skan	    slot = gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
5227169689Skan	  }
5228169689Skan	return gen_rtx_PARALLEL (mode,
5229169689Skan		 gen_rtvec (2,
5230169689Skan			    gen_rtx_EXPR_LIST (VOIDmode,
5231169689Skan					       slot, const0_rtx),
5232169689Skan			    gen_rtx_EXPR_LIST (VOIDmode,
5233169689Skan					       gen_rtx_REG (mode, cum->vregno),
5234169689Skan					       const0_rtx)));
5235132718Skan      }
5236132718Skan    else
5237132718Skan      return gen_rtx_REG (mode, cum->vregno);
5238169689Skan  else if (TARGET_ALTIVEC_ABI
5239169689Skan	   && (ALTIVEC_VECTOR_MODE (mode)
5240169689Skan	       || (type && TREE_CODE (type) == VECTOR_TYPE
5241169689Skan		   && int_size_in_bytes (type) == 16)))
524290075Sobrien    {
5243132718Skan      if (named || abi == ABI_V4)
5244132718Skan	return NULL_RTX;
524590075Sobrien      else
5246132718Skan	{
5247132718Skan	  /* Vector parameters to varargs functions under AIX or Darwin
5248132718Skan	     get passed in memory and possibly also in GPRs.  */
5249146895Skan	  int align, align_words, n_words;
5250146895Skan	  enum machine_mode part_mode;
5251132718Skan
5252132718Skan	  /* Vector parameters must be 16-byte aligned.  This places them at
5253132718Skan	     2 mod 4 in terms of words in 32-bit mode, since the parameter
5254132718Skan	     save area starts at offset 24 from the stack.  In 64-bit mode,
5255132718Skan	     they just have to start on an even word, since the parameter
5256132718Skan	     save area is 16-byte aligned.  */
5257132718Skan	  if (TARGET_32BIT)
5258132718Skan	    align = (2 - cum->words) & 3;
5259132718Skan	  else
5260132718Skan	    align = cum->words & 1;
5261132718Skan	  align_words = cum->words + align;
5262132718Skan
5263132718Skan	  /* Out of registers?  Memory, then.  */
5264132718Skan	  if (align_words >= GP_ARG_NUM_REG)
5265132718Skan	    return NULL_RTX;
5266146895Skan
5267146895Skan	  if (TARGET_32BIT && TARGET_POWERPC64)
5268146895Skan	    return rs6000_mixed_function_arg (mode, type, align_words);
5269146895Skan
5270132718Skan	  /* The vector value goes in GPRs.  Only the part of the
5271132718Skan	     value in GPRs is reported here.  */
5272146895Skan	  part_mode = mode;
5273146895Skan	  n_words = rs6000_arg_size (mode, type);
5274146895Skan	  if (align_words + n_words > GP_ARG_NUM_REG)
5275132718Skan	    /* Fortunately, there are only two possibilities, the value
5276132718Skan	       is either wholly in GPRs or half in GPRs and half not.  */
5277132718Skan	    part_mode = DImode;
5278146895Skan
5279132718Skan	  return gen_rtx_REG (part_mode, GP_ARG_MIN_REG + align_words);
5280132718Skan	}
528190075Sobrien    }
5282169689Skan  else if (TARGET_SPE_ABI && TARGET_SPE
5283169689Skan	   && (SPE_VECTOR_MODE (mode)
5284169689Skan	       || (TARGET_E500_DOUBLE && (mode == DFmode
5285169689Skan					  || mode == DCmode))))
5286132718Skan    return rs6000_spe_function_arg (cum, mode, type);
5287169689Skan
528890075Sobrien  else if (abi == ABI_V4)
528990075Sobrien    {
5290117395Skan      if (TARGET_HARD_FLOAT && TARGET_FPRS
5291169689Skan	  && (mode == SFmode || mode == DFmode
5292169689Skan	      || (mode == TFmode && !TARGET_IEEEQUAD)))
529390075Sobrien	{
5294169689Skan	  if (cum->fregno + (mode == TFmode ? 1 : 0) <= FP_ARG_V4_MAX_REG)
529590075Sobrien	    return gen_rtx_REG (mode, cum->fregno);
529690075Sobrien	  else
5297132718Skan	    return NULL_RTX;
529890075Sobrien	}
529990075Sobrien      else
530090075Sobrien	{
5301132718Skan	  int n_words = rs6000_arg_size (mode, type);
530290075Sobrien	  int gregno = cum->sysv_gregno;
530390075Sobrien
5304132718Skan	  /* Long long and SPE vectors are put in (r3,r4), (r5,r6),
5305132718Skan	     (r7,r8) or (r9,r10).  As does any other 2 word item such
5306132718Skan	     as complex int due to a historical mistake.  */
5307132718Skan	  if (n_words == 2)
5308132718Skan	    gregno += (1 - gregno) & 1;
530990075Sobrien
5310132718Skan	  /* Multi-reg args are not split between registers and stack.  */
5311146895Skan	  if (gregno + n_words - 1 > GP_ARG_MAX_REG)
5312132718Skan	    return NULL_RTX;
5313146895Skan
5314146895Skan	  if (TARGET_32BIT && TARGET_POWERPC64)
5315146895Skan	    return rs6000_mixed_function_arg (mode, type,
5316146895Skan					      gregno - GP_ARG_MIN_REG);
5317146895Skan	  return gen_rtx_REG (mode, gregno);
531890075Sobrien	}
531990075Sobrien    }
532090075Sobrien  else
532190075Sobrien    {
5322169689Skan      int align_words = rs6000_parm_start (mode, type, cum->words);
532390075Sobrien
5324132718Skan      if (USE_FP_FOR_ARG_P (cum, mode, type))
5325132718Skan	{
5326146895Skan	  rtx rvec[GP_ARG_NUM_REG + 1];
5327146895Skan	  rtx r;
5328146895Skan	  int k;
5329132718Skan	  bool needs_psave;
5330132718Skan	  enum machine_mode fmode = mode;
5331132718Skan	  unsigned long n_fpreg = (GET_MODE_SIZE (mode) + 7) >> 3;
533290075Sobrien
5333132718Skan	  if (cum->fregno + n_fpreg > FP_ARG_MAX_REG + 1)
5334132718Skan	    {
5335132718Skan	      /* Currently, we only ever need one reg here because complex
5336132718Skan		 doubles are split.  */
5337169689Skan	      gcc_assert (cum->fregno == FP_ARG_MAX_REG && fmode == TFmode);
5338146895Skan
5339146895Skan	      /* Long double split over regs and memory.  */
5340146895Skan	      fmode = DFmode;
5341132718Skan	    }
5342132718Skan
5343132718Skan	  /* Do we also need to pass this arg in the parameter save
5344132718Skan	     area?  */
5345132718Skan	  needs_psave = (type
5346132718Skan			 && (cum->nargs_prototype <= 0
5347132718Skan			     || (DEFAULT_ABI == ABI_AIX
5348146895Skan				 && TARGET_XL_COMPAT
5349132718Skan				 && align_words >= GP_ARG_NUM_REG)));
5350132718Skan
5351132718Skan	  if (!needs_psave && mode == fmode)
5352146895Skan	    return gen_rtx_REG (fmode, cum->fregno);
5353132718Skan
5354146895Skan	  k = 0;
5355132718Skan	  if (needs_psave)
5356132718Skan	    {
5357146895Skan	      /* Describe the part that goes in gprs or the stack.
5358132718Skan		 This piece must come first, before the fprs.  */
5359132718Skan	      if (align_words < GP_ARG_NUM_REG)
5360132718Skan		{
5361132718Skan		  unsigned long n_words = rs6000_arg_size (mode, type);
5362132718Skan
5363146895Skan		  if (align_words + n_words > GP_ARG_NUM_REG
5364146895Skan		      || (TARGET_32BIT && TARGET_POWERPC64))
5365146895Skan		    {
5366146895Skan		      /* If this is partially on the stack, then we only
5367146895Skan			 include the portion actually in registers here.  */
5368146895Skan		      enum machine_mode rmode = TARGET_32BIT ? SImode : DImode;
5369146895Skan		      rtx off;
5370169689Skan		      int i = 0;
5371169689Skan		      if (align_words + n_words > GP_ARG_NUM_REG)
5372169689Skan			/* Not all of the arg fits in gprs.  Say that it
5373169689Skan			   goes in memory too, using a magic NULL_RTX
5374169689Skan			   component.  Also see comment in
5375169689Skan			   rs6000_mixed_function_arg for why the normal
5376169689Skan			   function_arg_partial_nregs scheme doesn't work
5377169689Skan			   in this case. */
5378169689Skan			rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX,
5379169689Skan						       const0_rtx);
5380146895Skan		      do
5381146895Skan			{
5382146895Skan			  r = gen_rtx_REG (rmode,
5383146895Skan					   GP_ARG_MIN_REG + align_words);
5384169689Skan			  off = GEN_INT (i++ * GET_MODE_SIZE (rmode));
5385146895Skan			  rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, off);
5386146895Skan			}
5387146895Skan		      while (++align_words < GP_ARG_NUM_REG && --n_words != 0);
5388146895Skan		    }
5389146895Skan		  else
5390146895Skan		    {
5391146895Skan		      /* The whole arg fits in gprs.  */
5392146895Skan		      r = gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
5393146895Skan		      rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, const0_rtx);
5394146895Skan		    }
5395132718Skan		}
5396146895Skan	      else
5397146895Skan		/* It's entirely in memory.  */
5398146895Skan		rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX, const0_rtx);
5399132718Skan	    }
5400132718Skan
5401146895Skan	  /* Describe where this piece goes in the fprs.  */
5402146895Skan	  r = gen_rtx_REG (fmode, cum->fregno);
5403146895Skan	  rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, const0_rtx);
5404146895Skan
5405146895Skan	  return gen_rtx_PARALLEL (mode, gen_rtvec_v (k, rvec));
5406132718Skan	}
5407132718Skan      else if (align_words < GP_ARG_NUM_REG)
540890075Sobrien	{
5409146895Skan	  if (TARGET_32BIT && TARGET_POWERPC64)
5410146895Skan	    return rs6000_mixed_function_arg (mode, type, align_words);
541190075Sobrien
5412169689Skan	  if (mode == BLKmode)
5413169689Skan	    mode = Pmode;
5414169689Skan
5415132718Skan	  return gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
541690075Sobrien	}
541790075Sobrien      else
541890075Sobrien	return NULL_RTX;
541990075Sobrien    }
542090075Sobrien}
542190075Sobrien
5422146895Skan/* For an arg passed partly in registers and partly in memory, this is
5423169689Skan   the number of bytes passed in registers.  For args passed entirely in
5424169689Skan   registers or entirely in memory, zero.  When an arg is described by a
5425169689Skan   PARALLEL, perhaps using more than one register type, this function
5426169689Skan   returns the number of bytes used by the first element of the PARALLEL.  */
542790075Sobrien
5428169689Skanstatic int
5429169689Skanrs6000_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
5430169689Skan			  tree type, bool named)
543190075Sobrien{
5432132718Skan  int ret = 0;
5433146895Skan  int align_words;
5434132718Skan
543590075Sobrien  if (DEFAULT_ABI == ABI_V4)
543690075Sobrien    return 0;
543790075Sobrien
5438132718Skan  if (USE_ALTIVEC_FOR_ARG_P (cum, mode, type, named)
5439132718Skan      && cum->nargs_prototype >= 0)
5440132718Skan    return 0;
5441132718Skan
5442169689Skan  /* In this complicated case we just disable the partial_nregs code.  */
5443169689Skan  if (rs6000_darwin64_abi && mode == BLKmode
5444169689Skan      && TREE_CODE (type) == RECORD_TYPE
5445169689Skan      && int_size_in_bytes (type) > 0)
5446169689Skan    return 0;
5447146895Skan
5448169689Skan  align_words = rs6000_parm_start (mode, type, cum->words);
5449169689Skan
5450169689Skan  if (USE_FP_FOR_ARG_P (cum, mode, type))
545190075Sobrien    {
5452169689Skan      /* If we are passing this arg in the fixed parameter save area
5453169689Skan	 (gprs or memory) as well as fprs, then this function should
5454169689Skan	 return the number of partial bytes passed in the parameter
5455169689Skan	 save area rather than partial bytes passed in fprs.  */
5456169689Skan      if (type
5457169689Skan	  && (cum->nargs_prototype <= 0
5458169689Skan	      || (DEFAULT_ABI == ABI_AIX
5459169689Skan		  && TARGET_XL_COMPAT
5460169689Skan		  && align_words >= GP_ARG_NUM_REG)))
5461169689Skan	return 0;
5462169689Skan      else if (cum->fregno + ((GET_MODE_SIZE (mode) + 7) >> 3)
5463169689Skan	       > FP_ARG_MAX_REG + 1)
5464169689Skan	ret = (FP_ARG_MAX_REG + 1 - cum->fregno) * 8;
5465132718Skan      else if (cum->nargs_prototype >= 0)
546690075Sobrien	return 0;
546790075Sobrien    }
546890075Sobrien
5469146895Skan  if (align_words < GP_ARG_NUM_REG
5470146895Skan      && GP_ARG_NUM_REG < align_words + rs6000_arg_size (mode, type))
5471169689Skan    ret = (GP_ARG_NUM_REG - align_words) * (TARGET_32BIT ? 4 : 8);
547290075Sobrien
5473132718Skan  if (ret != 0 && TARGET_DEBUG_ARG)
5474169689Skan    fprintf (stderr, "rs6000_arg_partial_bytes: %d\n", ret);
547590075Sobrien
5476132718Skan  return ret;
547790075Sobrien}
547890075Sobrien
547990075Sobrien/* A C expression that indicates when an argument must be passed by
548090075Sobrien   reference.  If nonzero for an argument, a copy of that argument is
548190075Sobrien   made in memory and a pointer to the argument is passed instead of
548290075Sobrien   the argument itself.  The pointer is passed in whatever way is
548390075Sobrien   appropriate for passing a pointer to that type.
548490075Sobrien
5485132718Skan   Under V.4, aggregates and long double are passed by reference.
548690075Sobrien
5487132718Skan   As an extension to all 32-bit ABIs, AltiVec vectors are passed by
5488132718Skan   reference unless the AltiVec vector extension ABI is in force.
5489132718Skan
5490117395Skan   As an extension to all ABIs, variable sized types are passed by
5491117395Skan   reference.  */
5492117395Skan
5493169689Skanstatic bool
5494169689Skanrs6000_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
5495169689Skan			  enum machine_mode mode, tree type,
5496169689Skan			  bool named ATTRIBUTE_UNUSED)
549790075Sobrien{
5498169689Skan  if (DEFAULT_ABI == ABI_V4 && TARGET_IEEEQUAD && mode == TFmode)
549990075Sobrien    {
550090075Sobrien      if (TARGET_DEBUG_ARG)
5501169689Skan	fprintf (stderr, "function_arg_pass_by_reference: V4 long double\n");
5502169689Skan      return 1;
5503169689Skan    }
550490075Sobrien
5505169689Skan  if (!type)
5506169689Skan    return 0;
5507169689Skan
5508169689Skan  if (DEFAULT_ABI == ABI_V4 && AGGREGATE_TYPE_P (type))
5509169689Skan    {
5510169689Skan      if (TARGET_DEBUG_ARG)
5511169689Skan	fprintf (stderr, "function_arg_pass_by_reference: V4 aggregate\n");
551290075Sobrien      return 1;
551390075Sobrien    }
5514169689Skan
5515169689Skan  if (int_size_in_bytes (type) < 0)
5516169689Skan    {
5517169689Skan      if (TARGET_DEBUG_ARG)
5518169689Skan	fprintf (stderr, "function_arg_pass_by_reference: variable size\n");
5519169689Skan      return 1;
5520169689Skan    }
5521169689Skan
5522169689Skan  /* Allow -maltivec -mabi=no-altivec without warning.  Altivec vector
5523169689Skan     modes only exist for GCC vector types if -maltivec.  */
5524169689Skan  if (TARGET_32BIT && !TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
5525169689Skan    {
5526169689Skan      if (TARGET_DEBUG_ARG)
5527169689Skan	fprintf (stderr, "function_arg_pass_by_reference: AltiVec\n");
5528169689Skan      return 1;
5529169689Skan    }
5530169689Skan
5531169689Skan  /* Pass synthetic vectors in memory.  */
5532169689Skan  if (TREE_CODE (type) == VECTOR_TYPE
5533169689Skan      && int_size_in_bytes (type) > (TARGET_ALTIVEC_ABI ? 16 : 8))
5534169689Skan    {
5535169689Skan      static bool warned_for_pass_big_vectors = false;
5536169689Skan      if (TARGET_DEBUG_ARG)
5537169689Skan	fprintf (stderr, "function_arg_pass_by_reference: synthetic vector\n");
5538169689Skan      if (!warned_for_pass_big_vectors)
5539169689Skan	{
5540169689Skan	  warning (0, "GCC vector passed by reference: "
5541169689Skan		   "non-standard ABI extension with no compatibility guarantee");
5542169689Skan	  warned_for_pass_big_vectors = true;
5543169689Skan	}
5544169689Skan      return 1;
5545169689Skan    }
5546169689Skan
5547132718Skan  return 0;
554890075Sobrien}
5549132718Skan
5550132718Skanstatic void
5551132718Skanrs6000_move_block_from_reg (int regno, rtx x, int nregs)
5552132718Skan{
5553132718Skan  int i;
5554132718Skan  enum machine_mode reg_mode = TARGET_32BIT ? SImode : DImode;
5555132718Skan
5556132718Skan  if (nregs == 0)
5557132718Skan    return;
5558132718Skan
5559169689Skan  for (i = 0; i < nregs; i++)
5560132718Skan    {
5561169689Skan      rtx tem = adjust_address_nv (x, reg_mode, i * GET_MODE_SIZE (reg_mode));
5562132718Skan      if (reload_completed)
5563169689Skan	{
5564169689Skan	  if (! strict_memory_address_p (reg_mode, XEXP (tem, 0)))
5565169689Skan	    tem = NULL_RTX;
5566169689Skan	  else
5567169689Skan	    tem = simplify_gen_subreg (reg_mode, x, BLKmode,
5568169689Skan				       i * GET_MODE_SIZE (reg_mode));
5569169689Skan	}
5570132718Skan      else
5571132718Skan	tem = replace_equiv_address (tem, XEXP (tem, 0));
5572132718Skan
5573169689Skan      gcc_assert (tem);
5574132718Skan
5575132718Skan      emit_move_insn (tem, gen_rtx_REG (reg_mode, regno + i));
5576132718Skan    }
5577132718Skan}
557890075Sobrien
557990075Sobrien/* Perform any needed actions needed for a function that is receiving a
5580169689Skan   variable number of arguments.
558190075Sobrien
558290075Sobrien   CUM is as above.
558390075Sobrien
558490075Sobrien   MODE and TYPE are the mode and type of the current parameter.
558590075Sobrien
558690075Sobrien   PRETEND_SIZE is a variable that should be set to the amount of stack
558790075Sobrien   that must be pushed by the prolog to pretend that our caller pushed
558890075Sobrien   it.
558990075Sobrien
559090075Sobrien   Normally, this macro will push all remaining incoming registers on the
559190075Sobrien   stack and set PRETEND_SIZE to the length of the registers pushed.  */
559290075Sobrien
5593132718Skanstatic void
5594169689Skansetup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
5595169689Skan			tree type, int *pretend_size ATTRIBUTE_UNUSED,
5596169689Skan			int no_rtl)
559790075Sobrien{
559890075Sobrien  CUMULATIVE_ARGS next_cum;
559990075Sobrien  int reg_size = TARGET_32BIT ? 4 : 8;
560090075Sobrien  rtx save_area = NULL_RTX, mem;
560190075Sobrien  int first_reg_offset, set;
560290075Sobrien
5603132718Skan  /* Skip the last named argument.  */
560490075Sobrien  next_cum = *cum;
5605169689Skan  function_arg_advance (&next_cum, mode, type, 1, 0);
560690075Sobrien
560790075Sobrien  if (DEFAULT_ABI == ABI_V4)
560890075Sobrien    {
5609169689Skan      first_reg_offset = next_cum.sysv_gregno - GP_ARG_MIN_REG;
5610169689Skan
561190075Sobrien      if (! no_rtl)
5612169689Skan	{
5613169689Skan	  int gpr_reg_num = 0, gpr_size = 0, fpr_size = 0;
5614169689Skan	  HOST_WIDE_INT offset = 0;
561590075Sobrien
5616169689Skan	  /* Try to optimize the size of the varargs save area.
5617169689Skan	     The ABI requires that ap.reg_save_area is doubleword
5618169689Skan	     aligned, but we don't need to allocate space for all
5619169689Skan	     the bytes, only those to which we actually will save
5620169689Skan	     anything.  */
5621169689Skan	  if (cfun->va_list_gpr_size && first_reg_offset < GP_ARG_NUM_REG)
5622169689Skan	    gpr_reg_num = GP_ARG_NUM_REG - first_reg_offset;
5623169689Skan	  if (TARGET_HARD_FLOAT && TARGET_FPRS
5624169689Skan	      && next_cum.fregno <= FP_ARG_V4_MAX_REG
5625169689Skan	      && cfun->va_list_fpr_size)
5626169689Skan	    {
5627169689Skan	      if (gpr_reg_num)
5628169689Skan		fpr_size = (next_cum.fregno - FP_ARG_MIN_REG)
5629169689Skan			   * UNITS_PER_FP_WORD;
5630169689Skan	      if (cfun->va_list_fpr_size
5631169689Skan		  < FP_ARG_V4_MAX_REG + 1 - next_cum.fregno)
5632169689Skan		fpr_size += cfun->va_list_fpr_size * UNITS_PER_FP_WORD;
5633169689Skan	      else
5634169689Skan		fpr_size += (FP_ARG_V4_MAX_REG + 1 - next_cum.fregno)
5635169689Skan			    * UNITS_PER_FP_WORD;
5636169689Skan	    }
5637169689Skan	  if (gpr_reg_num)
5638169689Skan	    {
5639169689Skan	      offset = -((first_reg_offset * reg_size) & ~7);
5640169689Skan	      if (!fpr_size && gpr_reg_num > cfun->va_list_gpr_size)
5641169689Skan		{
5642169689Skan		  gpr_reg_num = cfun->va_list_gpr_size;
5643169689Skan		  if (reg_size == 4 && (first_reg_offset & 1))
5644169689Skan		    gpr_reg_num++;
5645169689Skan		}
5646169689Skan	      gpr_size = (gpr_reg_num * reg_size + 7) & ~7;
5647169689Skan	    }
5648169689Skan	  else if (fpr_size)
5649169689Skan	    offset = - (int) (next_cum.fregno - FP_ARG_MIN_REG)
5650169689Skan		       * UNITS_PER_FP_WORD
5651169689Skan		     - (int) (GP_ARG_NUM_REG * reg_size);
5652169689Skan
5653169689Skan	  if (gpr_size + fpr_size)
5654169689Skan	    {
5655169689Skan	      rtx reg_save_area
5656169689Skan		= assign_stack_local (BLKmode, gpr_size + fpr_size, 64);
5657169689Skan	      gcc_assert (GET_CODE (reg_save_area) == MEM);
5658169689Skan	      reg_save_area = XEXP (reg_save_area, 0);
5659169689Skan	      if (GET_CODE (reg_save_area) == PLUS)
5660169689Skan		{
5661169689Skan		  gcc_assert (XEXP (reg_save_area, 0)
5662169689Skan			      == virtual_stack_vars_rtx);
5663169689Skan		  gcc_assert (GET_CODE (XEXP (reg_save_area, 1)) == CONST_INT);
5664169689Skan		  offset += INTVAL (XEXP (reg_save_area, 1));
5665169689Skan		}
5666169689Skan	      else
5667169689Skan		gcc_assert (reg_save_area == virtual_stack_vars_rtx);
5668169689Skan	    }
5669169689Skan
5670169689Skan	  cfun->machine->varargs_save_offset = offset;
5671169689Skan	  save_area = plus_constant (virtual_stack_vars_rtx, offset);
5672169689Skan	}
567390075Sobrien    }
567490075Sobrien  else
567590075Sobrien    {
567690075Sobrien      first_reg_offset = next_cum.words;
567790075Sobrien      save_area = virtual_incoming_args_rtx;
567890075Sobrien
5679169689Skan      if (targetm.calls.must_pass_in_stack (mode, type))
5680132718Skan	first_reg_offset += rs6000_arg_size (TYPE_MODE (type), type);
568190075Sobrien    }
568290075Sobrien
568390075Sobrien  set = get_varargs_alias_set ();
5684169689Skan  if (! no_rtl && first_reg_offset < GP_ARG_NUM_REG
5685169689Skan      && cfun->va_list_gpr_size)
568690075Sobrien    {
5687169689Skan      int nregs = GP_ARG_NUM_REG - first_reg_offset;
5688169689Skan
5689169689Skan      if (va_list_gpr_counter_field)
5690169689Skan	{
5691169689Skan	  /* V4 va_list_gpr_size counts number of registers needed.  */
5692169689Skan	  if (nregs > cfun->va_list_gpr_size)
5693169689Skan	    nregs = cfun->va_list_gpr_size;
5694169689Skan	}
5695169689Skan      else
5696169689Skan	{
5697169689Skan	  /* char * va_list instead counts number of bytes needed.  */
5698169689Skan	  if (nregs > cfun->va_list_gpr_size / reg_size)
5699169689Skan	    nregs = cfun->va_list_gpr_size / reg_size;
5700169689Skan	}
5701169689Skan
570290075Sobrien      mem = gen_rtx_MEM (BLKmode,
5703169689Skan			 plus_constant (save_area,
5704169689Skan					first_reg_offset * reg_size));
5705169689Skan      MEM_NOTRAP_P (mem) = 1;
570690075Sobrien      set_mem_alias_set (mem, set);
570790075Sobrien      set_mem_align (mem, BITS_PER_WORD);
570890075Sobrien
5709169689Skan      rs6000_move_block_from_reg (GP_ARG_MIN_REG + first_reg_offset, mem,
5710169689Skan				  nregs);
571190075Sobrien    }
571290075Sobrien
571390075Sobrien  /* Save FP registers if needed.  */
571490075Sobrien  if (DEFAULT_ABI == ABI_V4
5715117395Skan      && TARGET_HARD_FLOAT && TARGET_FPRS
5716117395Skan      && ! no_rtl
5717169689Skan      && next_cum.fregno <= FP_ARG_V4_MAX_REG
5718169689Skan      && cfun->va_list_fpr_size)
571990075Sobrien    {
5720169689Skan      int fregno = next_cum.fregno, nregs;
572190075Sobrien      rtx cr1 = gen_rtx_REG (CCmode, CR1_REGNO);
572290075Sobrien      rtx lab = gen_label_rtx ();
5723169689Skan      int off = (GP_ARG_NUM_REG * reg_size) + ((fregno - FP_ARG_MIN_REG)
5724169689Skan					       * UNITS_PER_FP_WORD);
572590075Sobrien
5726169689Skan      emit_jump_insn
5727169689Skan	(gen_rtx_SET (VOIDmode,
5728169689Skan		      pc_rtx,
5729169689Skan		      gen_rtx_IF_THEN_ELSE (VOIDmode,
573090075Sobrien					    gen_rtx_NE (VOIDmode, cr1,
5731169689Skan							const0_rtx),
573290075Sobrien					    gen_rtx_LABEL_REF (VOIDmode, lab),
573390075Sobrien					    pc_rtx)));
573490075Sobrien
5735169689Skan      for (nregs = 0;
5736169689Skan	   fregno <= FP_ARG_V4_MAX_REG && nregs < cfun->va_list_fpr_size;
5737169689Skan	   fregno++, off += UNITS_PER_FP_WORD, nregs++)
573890075Sobrien	{
573990075Sobrien	  mem = gen_rtx_MEM (DFmode, plus_constant (save_area, off));
5740169689Skan	  MEM_NOTRAP_P (mem) = 1;
5741169689Skan	  set_mem_alias_set (mem, set);
5742146895Skan	  set_mem_align (mem, GET_MODE_ALIGNMENT (DFmode));
574390075Sobrien	  emit_move_insn (mem, gen_rtx_REG (DFmode, fregno));
574490075Sobrien	}
574590075Sobrien
574690075Sobrien      emit_label (lab);
574790075Sobrien    }
574890075Sobrien}
574990075Sobrien
575090075Sobrien/* Create the va_list data type.  */
575190075Sobrien
5752132718Skanstatic tree
5753132718Skanrs6000_build_builtin_va_list (void)
575490075Sobrien{
5755132718Skan  tree f_gpr, f_fpr, f_res, f_ovf, f_sav, record, type_decl;
575690075Sobrien
575790075Sobrien  /* For AIX, prefer 'char *' because that's what the system
575890075Sobrien     header files like.  */
575990075Sobrien  if (DEFAULT_ABI != ABI_V4)
576090075Sobrien    return build_pointer_type (char_type_node);
576190075Sobrien
5762117395Skan  record = (*lang_hooks.types.make_type) (RECORD_TYPE);
576390075Sobrien  type_decl = build_decl (TYPE_DECL, get_identifier ("__va_list_tag"), record);
576490075Sobrien
5765169689Skan  f_gpr = build_decl (FIELD_DECL, get_identifier ("gpr"),
576690075Sobrien		      unsigned_char_type_node);
5767169689Skan  f_fpr = build_decl (FIELD_DECL, get_identifier ("fpr"),
576890075Sobrien		      unsigned_char_type_node);
5769132718Skan  /* Give the two bytes of padding a name, so that -Wpadded won't warn on
5770132718Skan     every user file.  */
5771132718Skan  f_res = build_decl (FIELD_DECL, get_identifier ("reserved"),
5772132718Skan		      short_unsigned_type_node);
577390075Sobrien  f_ovf = build_decl (FIELD_DECL, get_identifier ("overflow_arg_area"),
577490075Sobrien		      ptr_type_node);
577590075Sobrien  f_sav = build_decl (FIELD_DECL, get_identifier ("reg_save_area"),
577690075Sobrien		      ptr_type_node);
577790075Sobrien
5778169689Skan  va_list_gpr_counter_field = f_gpr;
5779169689Skan  va_list_fpr_counter_field = f_fpr;
5780169689Skan
578190075Sobrien  DECL_FIELD_CONTEXT (f_gpr) = record;
578290075Sobrien  DECL_FIELD_CONTEXT (f_fpr) = record;
5783132718Skan  DECL_FIELD_CONTEXT (f_res) = record;
578490075Sobrien  DECL_FIELD_CONTEXT (f_ovf) = record;
578590075Sobrien  DECL_FIELD_CONTEXT (f_sav) = record;
578690075Sobrien
578790075Sobrien  TREE_CHAIN (record) = type_decl;
578890075Sobrien  TYPE_NAME (record) = type_decl;
578990075Sobrien  TYPE_FIELDS (record) = f_gpr;
579090075Sobrien  TREE_CHAIN (f_gpr) = f_fpr;
5791132718Skan  TREE_CHAIN (f_fpr) = f_res;
5792132718Skan  TREE_CHAIN (f_res) = f_ovf;
579390075Sobrien  TREE_CHAIN (f_ovf) = f_sav;
579490075Sobrien
579590075Sobrien  layout_type (record);
579690075Sobrien
579790075Sobrien  /* The correct type is an array type of one element.  */
579890075Sobrien  return build_array_type (record, build_index_type (size_zero_node));
579990075Sobrien}
580090075Sobrien
580190075Sobrien/* Implement va_start.  */
580290075Sobrien
580390075Sobrienvoid
5804132718Skanrs6000_va_start (tree valist, rtx nextarg)
580590075Sobrien{
580690075Sobrien  HOST_WIDE_INT words, n_gpr, n_fpr;
5807132718Skan  tree f_gpr, f_fpr, f_res, f_ovf, f_sav;
580890075Sobrien  tree gpr, fpr, ovf, sav, t;
580990075Sobrien
581090075Sobrien  /* Only SVR4 needs something special.  */
581190075Sobrien  if (DEFAULT_ABI != ABI_V4)
581290075Sobrien    {
5813117395Skan      std_expand_builtin_va_start (valist, nextarg);
581490075Sobrien      return;
581590075Sobrien    }
581690075Sobrien
581790075Sobrien  f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
581890075Sobrien  f_fpr = TREE_CHAIN (f_gpr);
5819132718Skan  f_res = TREE_CHAIN (f_fpr);
5820132718Skan  f_ovf = TREE_CHAIN (f_res);
582190075Sobrien  f_sav = TREE_CHAIN (f_ovf);
582290075Sobrien
5823169689Skan  valist = build_va_arg_indirect_ref (valist);
5824169689Skan  gpr = build3 (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr, NULL_TREE);
5825169689Skan  fpr = build3 (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr, NULL_TREE);
5826169689Skan  ovf = build3 (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf, NULL_TREE);
5827169689Skan  sav = build3 (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav, NULL_TREE);
582890075Sobrien
582990075Sobrien  /* Count number of gp and fp argument registers used.  */
583090075Sobrien  words = current_function_args_info.words;
5831169689Skan  n_gpr = MIN (current_function_args_info.sysv_gregno - GP_ARG_MIN_REG,
5832169689Skan	       GP_ARG_NUM_REG);
5833169689Skan  n_fpr = MIN (current_function_args_info.fregno - FP_ARG_MIN_REG,
5834169689Skan	       FP_ARG_NUM_REG);
583590075Sobrien
583690075Sobrien  if (TARGET_DEBUG_ARG)
5837132718Skan    fprintf (stderr, "va_start: words = "HOST_WIDE_INT_PRINT_DEC", n_gpr = "
5838132718Skan	     HOST_WIDE_INT_PRINT_DEC", n_fpr = "HOST_WIDE_INT_PRINT_DEC"\n",
5839132718Skan	     words, n_gpr, n_fpr);
584090075Sobrien
5841169689Skan  if (cfun->va_list_gpr_size)
5842169689Skan    {
5843169689Skan      t = build2 (MODIFY_EXPR, TREE_TYPE (gpr), gpr,
5844169689Skan		  build_int_cst (NULL_TREE, n_gpr));
5845169689Skan      TREE_SIDE_EFFECTS (t) = 1;
5846169689Skan      expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
5847169689Skan    }
584890075Sobrien
5849169689Skan  if (cfun->va_list_fpr_size)
5850169689Skan    {
5851169689Skan      t = build2 (MODIFY_EXPR, TREE_TYPE (fpr), fpr,
5852169689Skan		  build_int_cst (NULL_TREE, n_fpr));
5853169689Skan      TREE_SIDE_EFFECTS (t) = 1;
5854169689Skan      expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
5855169689Skan    }
585690075Sobrien
585790075Sobrien  /* Find the overflow area.  */
585890075Sobrien  t = make_tree (TREE_TYPE (ovf), virtual_incoming_args_rtx);
585990075Sobrien  if (words != 0)
5860169689Skan    t = build2 (PLUS_EXPR, TREE_TYPE (ovf), t,
5861169689Skan	        build_int_cst (NULL_TREE, words * UNITS_PER_WORD));
5862169689Skan  t = build2 (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t);
586390075Sobrien  TREE_SIDE_EFFECTS (t) = 1;
586490075Sobrien  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
586590075Sobrien
5866169689Skan  /* If there were no va_arg invocations, don't set up the register
5867169689Skan     save area.  */
5868169689Skan  if (!cfun->va_list_gpr_size
5869169689Skan      && !cfun->va_list_fpr_size
5870169689Skan      && n_gpr < GP_ARG_NUM_REG
5871169689Skan      && n_fpr < FP_ARG_V4_MAX_REG)
5872169689Skan    return;
5873169689Skan
587490075Sobrien  /* Find the register save area.  */
587590075Sobrien  t = make_tree (TREE_TYPE (sav), virtual_stack_vars_rtx);
5876169689Skan  if (cfun->machine->varargs_save_offset)
5877169689Skan    t = build2 (PLUS_EXPR, TREE_TYPE (sav), t,
5878169689Skan	        build_int_cst (NULL_TREE, cfun->machine->varargs_save_offset));
5879169689Skan  t = build2 (MODIFY_EXPR, TREE_TYPE (sav), sav, t);
588090075Sobrien  TREE_SIDE_EFFECTS (t) = 1;
588190075Sobrien  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
588290075Sobrien}
588390075Sobrien
588490075Sobrien/* Implement va_arg.  */
588590075Sobrien
5886169689Skantree
5887169689Skanrs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
588890075Sobrien{
5889132718Skan  tree f_gpr, f_fpr, f_res, f_ovf, f_sav;
589090075Sobrien  tree gpr, fpr, ovf, sav, reg, t, u;
5891169689Skan  int size, rsize, n_reg, sav_ofs, sav_scale;
5892169689Skan  tree lab_false, lab_over, addr;
5893132718Skan  int align;
5894169689Skan  tree ptrtype = build_pointer_type (type);
589590075Sobrien
5896169689Skan  if (pass_by_reference (NULL, TYPE_MODE (type), type, false))
5897169689Skan    {
5898169689Skan      t = rs6000_gimplify_va_arg (valist, ptrtype, pre_p, post_p);
5899169689Skan      return build_va_arg_indirect_ref (t);
5900169689Skan    }
5901169689Skan
590290075Sobrien  if (DEFAULT_ABI != ABI_V4)
5903117395Skan    {
5904169689Skan      if (targetm.calls.split_complex_arg && TREE_CODE (type) == COMPLEX_TYPE)
5905117395Skan	{
5906132718Skan	  tree elem_type = TREE_TYPE (type);
5907132718Skan	  enum machine_mode elem_mode = TYPE_MODE (elem_type);
5908132718Skan	  int elem_size = GET_MODE_SIZE (elem_mode);
5909132718Skan
5910132718Skan	  if (elem_size < UNITS_PER_WORD)
5911132718Skan	    {
5912169689Skan	      tree real_part, imag_part;
5913169689Skan	      tree post = NULL_TREE;
5914132718Skan
5915169689Skan	      real_part = rs6000_gimplify_va_arg (valist, elem_type, pre_p,
5916169689Skan						  &post);
5917169689Skan	      /* Copy the value into a temporary, lest the formal temporary
5918169689Skan		 be reused out from under us.  */
5919169689Skan	      real_part = get_initialized_tmp_var (real_part, pre_p, &post);
5920169689Skan	      append_to_statement_list (post, pre_p);
5921132718Skan
5922169689Skan	      imag_part = rs6000_gimplify_va_arg (valist, elem_type, pre_p,
5923169689Skan						  post_p);
5924132718Skan
5925169689Skan	      return build2 (COMPLEX_EXPR, type, real_part, imag_part);
5926132718Skan	    }
5927132718Skan	}
5928132718Skan
5929169689Skan      return std_gimplify_va_arg_expr (valist, type, pre_p, post_p);
5930117395Skan    }
5931117395Skan
593290075Sobrien  f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
593390075Sobrien  f_fpr = TREE_CHAIN (f_gpr);
5934132718Skan  f_res = TREE_CHAIN (f_fpr);
5935132718Skan  f_ovf = TREE_CHAIN (f_res);
593690075Sobrien  f_sav = TREE_CHAIN (f_ovf);
593790075Sobrien
5938169689Skan  valist = build_va_arg_indirect_ref (valist);
5939169689Skan  gpr = build3 (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr, NULL_TREE);
5940169689Skan  fpr = build3 (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr, NULL_TREE);
5941169689Skan  ovf = build3 (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf, NULL_TREE);
5942169689Skan  sav = build3 (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav, NULL_TREE);
594390075Sobrien
594490075Sobrien  size = int_size_in_bytes (type);
5945132718Skan  rsize = (size + 3) / 4;
5946132718Skan  align = 1;
594790075Sobrien
5948169689Skan  if (TARGET_HARD_FLOAT && TARGET_FPRS
5949169689Skan      && (TYPE_MODE (type) == SFmode
5950169689Skan	  || TYPE_MODE (type) == DFmode
5951169689Skan	  || TYPE_MODE (type) == TFmode))
595290075Sobrien    {
595390075Sobrien      /* FP args go in FP registers, if present.  */
595490075Sobrien      reg = fpr;
5955169689Skan      n_reg = (size + 7) / 8;
595690075Sobrien      sav_ofs = 8*4;
595790075Sobrien      sav_scale = 8;
5958169689Skan      if (TYPE_MODE (type) != SFmode)
5959132718Skan	align = 8;
596090075Sobrien    }
596190075Sobrien  else
596290075Sobrien    {
596390075Sobrien      /* Otherwise into GP registers.  */
596490075Sobrien      reg = gpr;
596590075Sobrien      n_reg = rsize;
596690075Sobrien      sav_ofs = 0;
596790075Sobrien      sav_scale = 4;
5968132718Skan      if (n_reg == 2)
5969132718Skan	align = 8;
597090075Sobrien    }
597190075Sobrien
5972132718Skan  /* Pull the value out of the saved registers....  */
597390075Sobrien
5974169689Skan  lab_over = NULL;
5975169689Skan  addr = create_tmp_var (ptr_type_node, "addr");
5976169689Skan  DECL_POINTER_ALIAS_SET (addr) = get_varargs_alias_set ();
597790075Sobrien
5978132718Skan  /*  AltiVec vectors never go in registers when -mabi=altivec.  */
5979132718Skan  if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (TYPE_MODE (type)))
5980132718Skan    align = 16;
5981132718Skan  else
598296263Sobrien    {
5983169689Skan      lab_false = create_artificial_label ();
5984169689Skan      lab_over = create_artificial_label ();
598590075Sobrien
5986132718Skan      /* Long long and SPE vectors are aligned in the registers.
5987132718Skan	 As are any other 2 gpr item such as complex int due to a
5988132718Skan	 historical mistake.  */
5989132718Skan      u = reg;
5990169689Skan      if (n_reg == 2 && reg == gpr)
599196263Sobrien	{
5992169689Skan	  u = build2 (BIT_AND_EXPR, TREE_TYPE (reg), reg,
5993169689Skan		     size_int (n_reg - 1));
5994169689Skan	  u = build2 (POSTINCREMENT_EXPR, TREE_TYPE (reg), reg, u);
599596263Sobrien	}
599696263Sobrien
5997169689Skan      t = fold_convert (TREE_TYPE (reg), size_int (8 - n_reg + 1));
5998169689Skan      t = build2 (GE_EXPR, boolean_type_node, u, t);
5999169689Skan      u = build1 (GOTO_EXPR, void_type_node, lab_false);
6000169689Skan      t = build3 (COND_EXPR, void_type_node, t, u, NULL_TREE);
6001169689Skan      gimplify_and_add (t, pre_p);
6002132718Skan
6003132718Skan      t = sav;
600496263Sobrien      if (sav_ofs)
6005169689Skan	t = build2 (PLUS_EXPR, ptr_type_node, sav, size_int (sav_ofs));
600696263Sobrien
6007169689Skan      u = build2 (POSTINCREMENT_EXPR, TREE_TYPE (reg), reg, size_int (n_reg));
600896263Sobrien      u = build1 (CONVERT_EXPR, integer_type_node, u);
6009169689Skan      u = build2 (MULT_EXPR, integer_type_node, u, size_int (sav_scale));
6010169689Skan      t = build2 (PLUS_EXPR, ptr_type_node, t, u);
601190075Sobrien
6012169689Skan      t = build2 (MODIFY_EXPR, void_type_node, addr, t);
6013169689Skan      gimplify_and_add (t, pre_p);
601490075Sobrien
6015169689Skan      t = build1 (GOTO_EXPR, void_type_node, lab_over);
6016169689Skan      gimplify_and_add (t, pre_p);
601790075Sobrien
6018169689Skan      t = build1 (LABEL_EXPR, void_type_node, lab_false);
6019169689Skan      append_to_statement_list (t, pre_p);
602090075Sobrien
6021169689Skan      if ((n_reg == 2 && reg != gpr) || n_reg > 2)
6022132718Skan	{
6023132718Skan	  /* Ensure that we don't find any more args in regs.
6024169689Skan	     Alignment has taken care of the n_reg == 2 gpr case.  */
6025169689Skan	  t = build2 (MODIFY_EXPR, TREE_TYPE (reg), reg, size_int (8));
6026169689Skan	  gimplify_and_add (t, pre_p);
6027132718Skan	}
602896263Sobrien    }
602990075Sobrien
603090075Sobrien  /* ... otherwise out of the overflow area.  */
603190075Sobrien
603290075Sobrien  /* Care for on-stack alignment if needed.  */
6033132718Skan  t = ovf;
6034132718Skan  if (align != 1)
603590075Sobrien    {
6036169689Skan      t = build2 (PLUS_EXPR, TREE_TYPE (t), t, size_int (align - 1));
6037169689Skan      t = build2 (BIT_AND_EXPR, TREE_TYPE (t), t,
6038169689Skan		  build_int_cst (NULL_TREE, -align));
603990075Sobrien    }
6040169689Skan  gimplify_expr (&t, pre_p, NULL, is_gimple_val, fb_rvalue);
604190075Sobrien
6042169689Skan  u = build2 (MODIFY_EXPR, void_type_node, addr, t);
6043169689Skan  gimplify_and_add (u, pre_p);
604490075Sobrien
6045169689Skan  t = build2 (PLUS_EXPR, TREE_TYPE (t), t, size_int (size));
6046169689Skan  t = build2 (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t);
6047169689Skan  gimplify_and_add (t, pre_p);
604890075Sobrien
6049132718Skan  if (lab_over)
6050169689Skan    {
6051169689Skan      t = build1 (LABEL_EXPR, void_type_node, lab_over);
6052169689Skan      append_to_statement_list (t, pre_p);
6053169689Skan    }
605490075Sobrien
6055169689Skan  if (STRICT_ALIGNMENT
6056169689Skan      && (TYPE_ALIGN (type)
6057169689Skan	  > (unsigned) BITS_PER_UNIT * (align < 4 ? 4 : align)))
605890075Sobrien    {
6059169689Skan      /* The value (of type complex double, for example) may not be
6060169689Skan	 aligned in memory in the saved registers, so copy via a
6061169689Skan	 temporary.  (This is the same code as used for SPARC.)  */
6062169689Skan      tree tmp = create_tmp_var (type, "va_arg_tmp");
6063169689Skan      tree dest_addr = build_fold_addr_expr (tmp);
6064169689Skan
6065169689Skan      tree copy = build_function_call_expr
6066169689Skan	(implicit_built_in_decls[BUILT_IN_MEMCPY],
6067169689Skan	 tree_cons (NULL_TREE, dest_addr,
6068169689Skan		    tree_cons (NULL_TREE, addr,
6069169689Skan			       tree_cons (NULL_TREE, size_int (rsize * 4),
6070169689Skan					  NULL_TREE))));
6071169689Skan
6072169689Skan      gimplify_and_add (copy, pre_p);
6073169689Skan      addr = dest_addr;
607490075Sobrien    }
607590075Sobrien
6076169689Skan  addr = fold_convert (ptrtype, addr);
6077169689Skan  return build_va_arg_indirect_ref (addr);
607890075Sobrien}
607990075Sobrien
608090075Sobrien/* Builtins.  */
608190075Sobrien
6082169689Skanstatic void
6083169689Skandef_builtin (int mask, const char *name, tree type, int code)
6084169689Skan{
6085169689Skan  if (mask & target_flags)
6086169689Skan    {
6087169689Skan      if (rs6000_builtin_decls[code])
6088169689Skan	abort ();
608990075Sobrien
6090169689Skan      rs6000_builtin_decls[code] =
6091169689Skan        lang_hooks.builtin_function (name, type, code, BUILT_IN_MD,
6092169689Skan				     NULL, NULL_TREE);
6093169689Skan    }
6094169689Skan}
6095169689Skan
609690075Sobrien/* Simple ternary operations: VECd = foo (VECa, VECb, VECc).  */
609790075Sobrien
609890075Sobrienstatic const struct builtin_description bdesc_3arg[] =
609990075Sobrien{
610090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmaddfp, "__builtin_altivec_vmaddfp", ALTIVEC_BUILTIN_VMADDFP },
610190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmhaddshs, "__builtin_altivec_vmhaddshs", ALTIVEC_BUILTIN_VMHADDSHS },
610290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmhraddshs, "__builtin_altivec_vmhraddshs", ALTIVEC_BUILTIN_VMHRADDSHS },
610390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmladduhm, "__builtin_altivec_vmladduhm", ALTIVEC_BUILTIN_VMLADDUHM},
610490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmsumubm, "__builtin_altivec_vmsumubm", ALTIVEC_BUILTIN_VMSUMUBM },
610590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmsummbm, "__builtin_altivec_vmsummbm", ALTIVEC_BUILTIN_VMSUMMBM },
610690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmsumuhm, "__builtin_altivec_vmsumuhm", ALTIVEC_BUILTIN_VMSUMUHM },
610790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmsumshm, "__builtin_altivec_vmsumshm", ALTIVEC_BUILTIN_VMSUMSHM },
610890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmsumuhs, "__builtin_altivec_vmsumuhs", ALTIVEC_BUILTIN_VMSUMUHS },
610990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmsumshs, "__builtin_altivec_vmsumshs", ALTIVEC_BUILTIN_VMSUMSHS },
6110169689Skan  { MASK_ALTIVEC, CODE_FOR_altivec_vnmsubfp, "__builtin_altivec_vnmsubfp", ALTIVEC_BUILTIN_VNMSUBFP },
6111169689Skan  { MASK_ALTIVEC, CODE_FOR_altivec_vperm_v4sf, "__builtin_altivec_vperm_4sf", ALTIVEC_BUILTIN_VPERM_4SF },
6112169689Skan  { MASK_ALTIVEC, CODE_FOR_altivec_vperm_v4si, "__builtin_altivec_vperm_4si", ALTIVEC_BUILTIN_VPERM_4SI },
6113169689Skan  { MASK_ALTIVEC, CODE_FOR_altivec_vperm_v8hi, "__builtin_altivec_vperm_8hi", ALTIVEC_BUILTIN_VPERM_8HI },
6114169689Skan  { MASK_ALTIVEC, CODE_FOR_altivec_vperm_v16qi, "__builtin_altivec_vperm_16qi", ALTIVEC_BUILTIN_VPERM_16QI },
6115169689Skan  { MASK_ALTIVEC, CODE_FOR_altivec_vsel_v4sf, "__builtin_altivec_vsel_4sf", ALTIVEC_BUILTIN_VSEL_4SF },
6116169689Skan  { MASK_ALTIVEC, CODE_FOR_altivec_vsel_v4si, "__builtin_altivec_vsel_4si", ALTIVEC_BUILTIN_VSEL_4SI },
6117169689Skan  { MASK_ALTIVEC, CODE_FOR_altivec_vsel_v8hi, "__builtin_altivec_vsel_8hi", ALTIVEC_BUILTIN_VSEL_8HI },
6118169689Skan  { MASK_ALTIVEC, CODE_FOR_altivec_vsel_v16qi, "__builtin_altivec_vsel_16qi", ALTIVEC_BUILTIN_VSEL_16QI },
6119169689Skan  { MASK_ALTIVEC, CODE_FOR_altivec_vsldoi_v16qi, "__builtin_altivec_vsldoi_16qi", ALTIVEC_BUILTIN_VSLDOI_16QI },
6120169689Skan  { MASK_ALTIVEC, CODE_FOR_altivec_vsldoi_v8hi, "__builtin_altivec_vsldoi_8hi", ALTIVEC_BUILTIN_VSLDOI_8HI },
6121169689Skan  { MASK_ALTIVEC, CODE_FOR_altivec_vsldoi_v4si, "__builtin_altivec_vsldoi_4si", ALTIVEC_BUILTIN_VSLDOI_4SI },
6122169689Skan  { MASK_ALTIVEC, CODE_FOR_altivec_vsldoi_v4sf, "__builtin_altivec_vsldoi_4sf", ALTIVEC_BUILTIN_VSLDOI_4SF },
6123169689Skan
6124169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_madd", ALTIVEC_BUILTIN_VEC_MADD },
6125169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_madds", ALTIVEC_BUILTIN_VEC_MADDS },
6126169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_mladd", ALTIVEC_BUILTIN_VEC_MLADD },
6127169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_mradds", ALTIVEC_BUILTIN_VEC_MRADDS },
6128169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_msum", ALTIVEC_BUILTIN_VEC_MSUM },
6129169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmsumshm", ALTIVEC_BUILTIN_VEC_VMSUMSHM },
6130169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmsumuhm", ALTIVEC_BUILTIN_VEC_VMSUMUHM },
6131169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmsummbm", ALTIVEC_BUILTIN_VEC_VMSUMMBM },
6132169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmsumubm", ALTIVEC_BUILTIN_VEC_VMSUMUBM },
6133169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_msums", ALTIVEC_BUILTIN_VEC_MSUMS },
6134169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmsumshs", ALTIVEC_BUILTIN_VEC_VMSUMSHS },
6135169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmsumuhs", ALTIVEC_BUILTIN_VEC_VMSUMUHS },
6136169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_nmsub", ALTIVEC_BUILTIN_VEC_NMSUB },
6137169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_perm", ALTIVEC_BUILTIN_VEC_PERM },
6138169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_sel", ALTIVEC_BUILTIN_VEC_SEL },
613990075Sobrien};
614090075Sobrien
614190075Sobrien/* DST operations: void foo (void *, const int, const char).  */
614290075Sobrien
614390075Sobrienstatic const struct builtin_description bdesc_dst[] =
614490075Sobrien{
614590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_dst, "__builtin_altivec_dst", ALTIVEC_BUILTIN_DST },
614690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_dstt, "__builtin_altivec_dstt", ALTIVEC_BUILTIN_DSTT },
614790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_dstst, "__builtin_altivec_dstst", ALTIVEC_BUILTIN_DSTST },
6148169689Skan  { MASK_ALTIVEC, CODE_FOR_altivec_dststt, "__builtin_altivec_dststt", ALTIVEC_BUILTIN_DSTSTT },
6149169689Skan
6150169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_dst", ALTIVEC_BUILTIN_VEC_DST },
6151169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_dstt", ALTIVEC_BUILTIN_VEC_DSTT },
6152169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_dstst", ALTIVEC_BUILTIN_VEC_DSTST },
6153169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_dststt", ALTIVEC_BUILTIN_VEC_DSTSTT }
615490075Sobrien};
615590075Sobrien
615690075Sobrien/* Simple binary operations: VECc = foo (VECa, VECb).  */
615790075Sobrien
6158117395Skanstatic struct builtin_description bdesc_2arg[] =
615990075Sobrien{
616090075Sobrien  { MASK_ALTIVEC, CODE_FOR_addv16qi3, "__builtin_altivec_vaddubm", ALTIVEC_BUILTIN_VADDUBM },
616190075Sobrien  { MASK_ALTIVEC, CODE_FOR_addv8hi3, "__builtin_altivec_vadduhm", ALTIVEC_BUILTIN_VADDUHM },
616290075Sobrien  { MASK_ALTIVEC, CODE_FOR_addv4si3, "__builtin_altivec_vadduwm", ALTIVEC_BUILTIN_VADDUWM },
616390075Sobrien  { MASK_ALTIVEC, CODE_FOR_addv4sf3, "__builtin_altivec_vaddfp", ALTIVEC_BUILTIN_VADDFP },
616490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vaddcuw, "__builtin_altivec_vaddcuw", ALTIVEC_BUILTIN_VADDCUW },
616590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vaddubs, "__builtin_altivec_vaddubs", ALTIVEC_BUILTIN_VADDUBS },
616690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vaddsbs, "__builtin_altivec_vaddsbs", ALTIVEC_BUILTIN_VADDSBS },
616790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vadduhs, "__builtin_altivec_vadduhs", ALTIVEC_BUILTIN_VADDUHS },
616890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vaddshs, "__builtin_altivec_vaddshs", ALTIVEC_BUILTIN_VADDSHS },
616990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vadduws, "__builtin_altivec_vadduws", ALTIVEC_BUILTIN_VADDUWS },
617090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vaddsws, "__builtin_altivec_vaddsws", ALTIVEC_BUILTIN_VADDSWS },
617190075Sobrien  { MASK_ALTIVEC, CODE_FOR_andv4si3, "__builtin_altivec_vand", ALTIVEC_BUILTIN_VAND },
6172169689Skan  { MASK_ALTIVEC, CODE_FOR_andcv4si3, "__builtin_altivec_vandc", ALTIVEC_BUILTIN_VANDC },
617390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vavgub, "__builtin_altivec_vavgub", ALTIVEC_BUILTIN_VAVGUB },
617490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vavgsb, "__builtin_altivec_vavgsb", ALTIVEC_BUILTIN_VAVGSB },
617590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vavguh, "__builtin_altivec_vavguh", ALTIVEC_BUILTIN_VAVGUH },
617690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vavgsh, "__builtin_altivec_vavgsh", ALTIVEC_BUILTIN_VAVGSH },
617790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vavguw, "__builtin_altivec_vavguw", ALTIVEC_BUILTIN_VAVGUW },
617890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vavgsw, "__builtin_altivec_vavgsw", ALTIVEC_BUILTIN_VAVGSW },
617990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcfux, "__builtin_altivec_vcfux", ALTIVEC_BUILTIN_VCFUX },
618090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcfsx, "__builtin_altivec_vcfsx", ALTIVEC_BUILTIN_VCFSX },
618190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpbfp, "__builtin_altivec_vcmpbfp", ALTIVEC_BUILTIN_VCMPBFP },
618290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpequb, "__builtin_altivec_vcmpequb", ALTIVEC_BUILTIN_VCMPEQUB },
618390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpequh, "__builtin_altivec_vcmpequh", ALTIVEC_BUILTIN_VCMPEQUH },
618490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpequw, "__builtin_altivec_vcmpequw", ALTIVEC_BUILTIN_VCMPEQUW },
618590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpeqfp, "__builtin_altivec_vcmpeqfp", ALTIVEC_BUILTIN_VCMPEQFP },
618690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpgefp, "__builtin_altivec_vcmpgefp", ALTIVEC_BUILTIN_VCMPGEFP },
618790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpgtub, "__builtin_altivec_vcmpgtub", ALTIVEC_BUILTIN_VCMPGTUB },
618890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpgtsb, "__builtin_altivec_vcmpgtsb", ALTIVEC_BUILTIN_VCMPGTSB },
618990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpgtuh, "__builtin_altivec_vcmpgtuh", ALTIVEC_BUILTIN_VCMPGTUH },
619090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpgtsh, "__builtin_altivec_vcmpgtsh", ALTIVEC_BUILTIN_VCMPGTSH },
619190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpgtuw, "__builtin_altivec_vcmpgtuw", ALTIVEC_BUILTIN_VCMPGTUW },
619290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpgtsw, "__builtin_altivec_vcmpgtsw", ALTIVEC_BUILTIN_VCMPGTSW },
619390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpgtfp, "__builtin_altivec_vcmpgtfp", ALTIVEC_BUILTIN_VCMPGTFP },
619490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vctsxs, "__builtin_altivec_vctsxs", ALTIVEC_BUILTIN_VCTSXS },
619590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vctuxs, "__builtin_altivec_vctuxs", ALTIVEC_BUILTIN_VCTUXS },
619690075Sobrien  { MASK_ALTIVEC, CODE_FOR_umaxv16qi3, "__builtin_altivec_vmaxub", ALTIVEC_BUILTIN_VMAXUB },
619790075Sobrien  { MASK_ALTIVEC, CODE_FOR_smaxv16qi3, "__builtin_altivec_vmaxsb", ALTIVEC_BUILTIN_VMAXSB },
6198117395Skan  { MASK_ALTIVEC, CODE_FOR_umaxv8hi3, "__builtin_altivec_vmaxuh", ALTIVEC_BUILTIN_VMAXUH },
6199117395Skan  { MASK_ALTIVEC, CODE_FOR_smaxv8hi3, "__builtin_altivec_vmaxsh", ALTIVEC_BUILTIN_VMAXSH },
6200117395Skan  { MASK_ALTIVEC, CODE_FOR_umaxv4si3, "__builtin_altivec_vmaxuw", ALTIVEC_BUILTIN_VMAXUW },
6201117395Skan  { MASK_ALTIVEC, CODE_FOR_smaxv4si3, "__builtin_altivec_vmaxsw", ALTIVEC_BUILTIN_VMAXSW },
6202117395Skan  { MASK_ALTIVEC, CODE_FOR_smaxv4sf3, "__builtin_altivec_vmaxfp", ALTIVEC_BUILTIN_VMAXFP },
620390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmrghb, "__builtin_altivec_vmrghb", ALTIVEC_BUILTIN_VMRGHB },
620490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmrghh, "__builtin_altivec_vmrghh", ALTIVEC_BUILTIN_VMRGHH },
620590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmrghw, "__builtin_altivec_vmrghw", ALTIVEC_BUILTIN_VMRGHW },
620690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmrglb, "__builtin_altivec_vmrglb", ALTIVEC_BUILTIN_VMRGLB },
620790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmrglh, "__builtin_altivec_vmrglh", ALTIVEC_BUILTIN_VMRGLH },
620890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmrglw, "__builtin_altivec_vmrglw", ALTIVEC_BUILTIN_VMRGLW },
620990075Sobrien  { MASK_ALTIVEC, CODE_FOR_uminv16qi3, "__builtin_altivec_vminub", ALTIVEC_BUILTIN_VMINUB },
621090075Sobrien  { MASK_ALTIVEC, CODE_FOR_sminv16qi3, "__builtin_altivec_vminsb", ALTIVEC_BUILTIN_VMINSB },
621190075Sobrien  { MASK_ALTIVEC, CODE_FOR_uminv8hi3, "__builtin_altivec_vminuh", ALTIVEC_BUILTIN_VMINUH },
621290075Sobrien  { MASK_ALTIVEC, CODE_FOR_sminv8hi3, "__builtin_altivec_vminsh", ALTIVEC_BUILTIN_VMINSH },
621390075Sobrien  { MASK_ALTIVEC, CODE_FOR_uminv4si3, "__builtin_altivec_vminuw", ALTIVEC_BUILTIN_VMINUW },
621490075Sobrien  { MASK_ALTIVEC, CODE_FOR_sminv4si3, "__builtin_altivec_vminsw", ALTIVEC_BUILTIN_VMINSW },
621590075Sobrien  { MASK_ALTIVEC, CODE_FOR_sminv4sf3, "__builtin_altivec_vminfp", ALTIVEC_BUILTIN_VMINFP },
621690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmuleub, "__builtin_altivec_vmuleub", ALTIVEC_BUILTIN_VMULEUB },
621790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmulesb, "__builtin_altivec_vmulesb", ALTIVEC_BUILTIN_VMULESB },
621890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmuleuh, "__builtin_altivec_vmuleuh", ALTIVEC_BUILTIN_VMULEUH },
621990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmulesh, "__builtin_altivec_vmulesh", ALTIVEC_BUILTIN_VMULESH },
622090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmuloub, "__builtin_altivec_vmuloub", ALTIVEC_BUILTIN_VMULOUB },
622190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmulosb, "__builtin_altivec_vmulosb", ALTIVEC_BUILTIN_VMULOSB },
622290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmulouh, "__builtin_altivec_vmulouh", ALTIVEC_BUILTIN_VMULOUH },
622390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vmulosh, "__builtin_altivec_vmulosh", ALTIVEC_BUILTIN_VMULOSH },
6224169689Skan  { MASK_ALTIVEC, CODE_FOR_altivec_norv4si3, "__builtin_altivec_vnor", ALTIVEC_BUILTIN_VNOR },
622590075Sobrien  { MASK_ALTIVEC, CODE_FOR_iorv4si3, "__builtin_altivec_vor", ALTIVEC_BUILTIN_VOR },
622690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkuhum, "__builtin_altivec_vpkuhum", ALTIVEC_BUILTIN_VPKUHUM },
622790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkuwum, "__builtin_altivec_vpkuwum", ALTIVEC_BUILTIN_VPKUWUM },
622890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkpx, "__builtin_altivec_vpkpx", ALTIVEC_BUILTIN_VPKPX },
622990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkshss, "__builtin_altivec_vpkshss", ALTIVEC_BUILTIN_VPKSHSS },
623090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkswss, "__builtin_altivec_vpkswss", ALTIVEC_BUILTIN_VPKSWSS },
623190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkuhus, "__builtin_altivec_vpkuhus", ALTIVEC_BUILTIN_VPKUHUS },
623290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkshus, "__builtin_altivec_vpkshus", ALTIVEC_BUILTIN_VPKSHUS },
623390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkuwus, "__builtin_altivec_vpkuwus", ALTIVEC_BUILTIN_VPKUWUS },
623490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vpkswus, "__builtin_altivec_vpkswus", ALTIVEC_BUILTIN_VPKSWUS },
623590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vrlb, "__builtin_altivec_vrlb", ALTIVEC_BUILTIN_VRLB },
623690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vrlh, "__builtin_altivec_vrlh", ALTIVEC_BUILTIN_VRLH },
623790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vrlw, "__builtin_altivec_vrlw", ALTIVEC_BUILTIN_VRLW },
623890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vslb, "__builtin_altivec_vslb", ALTIVEC_BUILTIN_VSLB },
623990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vslh, "__builtin_altivec_vslh", ALTIVEC_BUILTIN_VSLH },
624090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vslw, "__builtin_altivec_vslw", ALTIVEC_BUILTIN_VSLW },
624190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsl, "__builtin_altivec_vsl", ALTIVEC_BUILTIN_VSL },
624290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vslo, "__builtin_altivec_vslo", ALTIVEC_BUILTIN_VSLO },
624390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vspltb, "__builtin_altivec_vspltb", ALTIVEC_BUILTIN_VSPLTB },
624490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsplth, "__builtin_altivec_vsplth", ALTIVEC_BUILTIN_VSPLTH },
624590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vspltw, "__builtin_altivec_vspltw", ALTIVEC_BUILTIN_VSPLTW },
6246169689Skan  { MASK_ALTIVEC, CODE_FOR_lshrv16qi3, "__builtin_altivec_vsrb", ALTIVEC_BUILTIN_VSRB },
6247169689Skan  { MASK_ALTIVEC, CODE_FOR_lshrv8hi3, "__builtin_altivec_vsrh", ALTIVEC_BUILTIN_VSRH },
6248169689Skan  { MASK_ALTIVEC, CODE_FOR_lshrv4si3, "__builtin_altivec_vsrw", ALTIVEC_BUILTIN_VSRW },
6249169689Skan  { MASK_ALTIVEC, CODE_FOR_ashrv16qi3, "__builtin_altivec_vsrab", ALTIVEC_BUILTIN_VSRAB },
6250169689Skan  { MASK_ALTIVEC, CODE_FOR_ashrv8hi3, "__builtin_altivec_vsrah", ALTIVEC_BUILTIN_VSRAH },
6251169689Skan  { MASK_ALTIVEC, CODE_FOR_ashrv4si3, "__builtin_altivec_vsraw", ALTIVEC_BUILTIN_VSRAW },
625290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsr, "__builtin_altivec_vsr", ALTIVEC_BUILTIN_VSR },
625390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsro, "__builtin_altivec_vsro", ALTIVEC_BUILTIN_VSRO },
625490075Sobrien  { MASK_ALTIVEC, CODE_FOR_subv16qi3, "__builtin_altivec_vsububm", ALTIVEC_BUILTIN_VSUBUBM },
625590075Sobrien  { MASK_ALTIVEC, CODE_FOR_subv8hi3, "__builtin_altivec_vsubuhm", ALTIVEC_BUILTIN_VSUBUHM },
625690075Sobrien  { MASK_ALTIVEC, CODE_FOR_subv4si3, "__builtin_altivec_vsubuwm", ALTIVEC_BUILTIN_VSUBUWM },
625790075Sobrien  { MASK_ALTIVEC, CODE_FOR_subv4sf3, "__builtin_altivec_vsubfp", ALTIVEC_BUILTIN_VSUBFP },
625890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsubcuw, "__builtin_altivec_vsubcuw", ALTIVEC_BUILTIN_VSUBCUW },
625990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsububs, "__builtin_altivec_vsububs", ALTIVEC_BUILTIN_VSUBUBS },
626090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsubsbs, "__builtin_altivec_vsubsbs", ALTIVEC_BUILTIN_VSUBSBS },
626190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsubuhs, "__builtin_altivec_vsubuhs", ALTIVEC_BUILTIN_VSUBUHS },
626290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsubshs, "__builtin_altivec_vsubshs", ALTIVEC_BUILTIN_VSUBSHS },
626390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsubuws, "__builtin_altivec_vsubuws", ALTIVEC_BUILTIN_VSUBUWS },
626490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsubsws, "__builtin_altivec_vsubsws", ALTIVEC_BUILTIN_VSUBSWS },
626590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsum4ubs, "__builtin_altivec_vsum4ubs", ALTIVEC_BUILTIN_VSUM4UBS },
626690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsum4sbs, "__builtin_altivec_vsum4sbs", ALTIVEC_BUILTIN_VSUM4SBS },
626790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsum4shs, "__builtin_altivec_vsum4shs", ALTIVEC_BUILTIN_VSUM4SHS },
626890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsum2sws, "__builtin_altivec_vsum2sws", ALTIVEC_BUILTIN_VSUM2SWS },
626990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vsumsws, "__builtin_altivec_vsumsws", ALTIVEC_BUILTIN_VSUMSWS },
627090075Sobrien  { MASK_ALTIVEC, CODE_FOR_xorv4si3, "__builtin_altivec_vxor", ALTIVEC_BUILTIN_VXOR },
6271117395Skan
6272169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_add", ALTIVEC_BUILTIN_VEC_ADD },
6273169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vaddfp", ALTIVEC_BUILTIN_VEC_VADDFP },
6274169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vadduwm", ALTIVEC_BUILTIN_VEC_VADDUWM },
6275169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vadduhm", ALTIVEC_BUILTIN_VEC_VADDUHM },
6276169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vaddubm", ALTIVEC_BUILTIN_VEC_VADDUBM },
6277169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_addc", ALTIVEC_BUILTIN_VEC_ADDC },
6278169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_adds", ALTIVEC_BUILTIN_VEC_ADDS },
6279169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vaddsws", ALTIVEC_BUILTIN_VEC_VADDSWS },
6280169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vadduws", ALTIVEC_BUILTIN_VEC_VADDUWS },
6281169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vaddshs", ALTIVEC_BUILTIN_VEC_VADDSHS },
6282169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vadduhs", ALTIVEC_BUILTIN_VEC_VADDUHS },
6283169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vaddsbs", ALTIVEC_BUILTIN_VEC_VADDSBS },
6284169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vaddubs", ALTIVEC_BUILTIN_VEC_VADDUBS },
6285169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_and", ALTIVEC_BUILTIN_VEC_AND },
6286169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_andc", ALTIVEC_BUILTIN_VEC_ANDC },
6287169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_avg", ALTIVEC_BUILTIN_VEC_AVG },
6288169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vavgsw", ALTIVEC_BUILTIN_VEC_VAVGSW },
6289169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vavguw", ALTIVEC_BUILTIN_VEC_VAVGUW },
6290169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vavgsh", ALTIVEC_BUILTIN_VEC_VAVGSH },
6291169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vavguh", ALTIVEC_BUILTIN_VEC_VAVGUH },
6292169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vavgsb", ALTIVEC_BUILTIN_VEC_VAVGSB },
6293169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vavgub", ALTIVEC_BUILTIN_VEC_VAVGUB },
6294169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_cmpb", ALTIVEC_BUILTIN_VEC_CMPB },
6295169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_cmpeq", ALTIVEC_BUILTIN_VEC_CMPEQ },
6296169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vcmpeqfp", ALTIVEC_BUILTIN_VEC_VCMPEQFP },
6297169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vcmpequw", ALTIVEC_BUILTIN_VEC_VCMPEQUW },
6298169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vcmpequh", ALTIVEC_BUILTIN_VEC_VCMPEQUH },
6299169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vcmpequb", ALTIVEC_BUILTIN_VEC_VCMPEQUB },
6300169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_cmpge", ALTIVEC_BUILTIN_VEC_CMPGE },
6301169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_cmpgt", ALTIVEC_BUILTIN_VEC_CMPGT },
6302169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vcmpgtfp", ALTIVEC_BUILTIN_VEC_VCMPGTFP },
6303169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vcmpgtsw", ALTIVEC_BUILTIN_VEC_VCMPGTSW },
6304169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vcmpgtuw", ALTIVEC_BUILTIN_VEC_VCMPGTUW },
6305169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vcmpgtsh", ALTIVEC_BUILTIN_VEC_VCMPGTSH },
6306169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vcmpgtuh", ALTIVEC_BUILTIN_VEC_VCMPGTUH },
6307169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vcmpgtsb", ALTIVEC_BUILTIN_VEC_VCMPGTSB },
6308169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vcmpgtub", ALTIVEC_BUILTIN_VEC_VCMPGTUB },
6309169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_cmple", ALTIVEC_BUILTIN_VEC_CMPLE },
6310169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_cmplt", ALTIVEC_BUILTIN_VEC_CMPLT },
6311169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_max", ALTIVEC_BUILTIN_VEC_MAX },
6312169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmaxfp", ALTIVEC_BUILTIN_VEC_VMAXFP },
6313169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmaxsw", ALTIVEC_BUILTIN_VEC_VMAXSW },
6314169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmaxuw", ALTIVEC_BUILTIN_VEC_VMAXUW },
6315169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmaxsh", ALTIVEC_BUILTIN_VEC_VMAXSH },
6316169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmaxuh", ALTIVEC_BUILTIN_VEC_VMAXUH },
6317169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmaxsb", ALTIVEC_BUILTIN_VEC_VMAXSB },
6318169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmaxub", ALTIVEC_BUILTIN_VEC_VMAXUB },
6319169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_mergeh", ALTIVEC_BUILTIN_VEC_MERGEH },
6320169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmrghw", ALTIVEC_BUILTIN_VEC_VMRGHW },
6321169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmrghh", ALTIVEC_BUILTIN_VEC_VMRGHH },
6322169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmrghb", ALTIVEC_BUILTIN_VEC_VMRGHB },
6323169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_mergel", ALTIVEC_BUILTIN_VEC_MERGEL },
6324169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmrglw", ALTIVEC_BUILTIN_VEC_VMRGLW },
6325169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmrglh", ALTIVEC_BUILTIN_VEC_VMRGLH },
6326169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmrglb", ALTIVEC_BUILTIN_VEC_VMRGLB },
6327169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_min", ALTIVEC_BUILTIN_VEC_MIN },
6328169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vminfp", ALTIVEC_BUILTIN_VEC_VMINFP },
6329169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vminsw", ALTIVEC_BUILTIN_VEC_VMINSW },
6330169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vminuw", ALTIVEC_BUILTIN_VEC_VMINUW },
6331169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vminsh", ALTIVEC_BUILTIN_VEC_VMINSH },
6332169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vminuh", ALTIVEC_BUILTIN_VEC_VMINUH },
6333169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vminsb", ALTIVEC_BUILTIN_VEC_VMINSB },
6334169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vminub", ALTIVEC_BUILTIN_VEC_VMINUB },
6335169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_mule", ALTIVEC_BUILTIN_VEC_MULE },
6336169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmuleub", ALTIVEC_BUILTIN_VEC_VMULEUB },
6337169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmulesb", ALTIVEC_BUILTIN_VEC_VMULESB },
6338169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmuleuh", ALTIVEC_BUILTIN_VEC_VMULEUH },
6339169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmulesh", ALTIVEC_BUILTIN_VEC_VMULESH },
6340169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_mulo", ALTIVEC_BUILTIN_VEC_MULO },
6341169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmulosh", ALTIVEC_BUILTIN_VEC_VMULOSH },
6342169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmulouh", ALTIVEC_BUILTIN_VEC_VMULOUH },
6343169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmulosb", ALTIVEC_BUILTIN_VEC_VMULOSB },
6344169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmuloub", ALTIVEC_BUILTIN_VEC_VMULOUB },
6345169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_nor", ALTIVEC_BUILTIN_VEC_NOR },
6346169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_or", ALTIVEC_BUILTIN_VEC_OR },
6347169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_pack", ALTIVEC_BUILTIN_VEC_PACK },
6348169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vpkuwum", ALTIVEC_BUILTIN_VEC_VPKUWUM },
6349169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vpkuhum", ALTIVEC_BUILTIN_VEC_VPKUHUM },
6350169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_packpx", ALTIVEC_BUILTIN_VEC_PACKPX },
6351169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_packs", ALTIVEC_BUILTIN_VEC_PACKS },
6352169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vpkswss", ALTIVEC_BUILTIN_VEC_VPKSWSS },
6353169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vpkuwus", ALTIVEC_BUILTIN_VEC_VPKUWUS },
6354169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vpkshss", ALTIVEC_BUILTIN_VEC_VPKSHSS },
6355169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vpkuhus", ALTIVEC_BUILTIN_VEC_VPKUHUS },
6356169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_packsu", ALTIVEC_BUILTIN_VEC_PACKSU },
6357169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vpkswus", ALTIVEC_BUILTIN_VEC_VPKSWUS },
6358169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vpkshus", ALTIVEC_BUILTIN_VEC_VPKSHUS },
6359169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_rl", ALTIVEC_BUILTIN_VEC_RL },
6360169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vrlw", ALTIVEC_BUILTIN_VEC_VRLW },
6361169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vrlh", ALTIVEC_BUILTIN_VEC_VRLH },
6362169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vrlb", ALTIVEC_BUILTIN_VEC_VRLB },
6363169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_sl", ALTIVEC_BUILTIN_VEC_SL },
6364169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vslw", ALTIVEC_BUILTIN_VEC_VSLW },
6365169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vslh", ALTIVEC_BUILTIN_VEC_VSLH },
6366169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vslb", ALTIVEC_BUILTIN_VEC_VSLB },
6367169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_sll", ALTIVEC_BUILTIN_VEC_SLL },
6368169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_slo", ALTIVEC_BUILTIN_VEC_SLO },
6369169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_sr", ALTIVEC_BUILTIN_VEC_SR },
6370169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsrw", ALTIVEC_BUILTIN_VEC_VSRW },
6371169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsrh", ALTIVEC_BUILTIN_VEC_VSRH },
6372169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsrb", ALTIVEC_BUILTIN_VEC_VSRB },
6373169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_sra", ALTIVEC_BUILTIN_VEC_SRA },
6374169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsraw", ALTIVEC_BUILTIN_VEC_VSRAW },
6375169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsrah", ALTIVEC_BUILTIN_VEC_VSRAH },
6376169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsrab", ALTIVEC_BUILTIN_VEC_VSRAB },
6377169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_srl", ALTIVEC_BUILTIN_VEC_SRL },
6378169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_sro", ALTIVEC_BUILTIN_VEC_SRO },
6379169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_sub", ALTIVEC_BUILTIN_VEC_SUB },
6380169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsubfp", ALTIVEC_BUILTIN_VEC_VSUBFP },
6381169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsubuwm", ALTIVEC_BUILTIN_VEC_VSUBUWM },
6382169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsubuhm", ALTIVEC_BUILTIN_VEC_VSUBUHM },
6383169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsububm", ALTIVEC_BUILTIN_VEC_VSUBUBM },
6384169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_subc", ALTIVEC_BUILTIN_VEC_SUBC },
6385169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_subs", ALTIVEC_BUILTIN_VEC_SUBS },
6386169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsubsws", ALTIVEC_BUILTIN_VEC_VSUBSWS },
6387169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsubuws", ALTIVEC_BUILTIN_VEC_VSUBUWS },
6388169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsubshs", ALTIVEC_BUILTIN_VEC_VSUBSHS },
6389169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsubuhs", ALTIVEC_BUILTIN_VEC_VSUBUHS },
6390169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsubsbs", ALTIVEC_BUILTIN_VEC_VSUBSBS },
6391169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsububs", ALTIVEC_BUILTIN_VEC_VSUBUBS },
6392169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_sum4s", ALTIVEC_BUILTIN_VEC_SUM4S },
6393169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsum4shs", ALTIVEC_BUILTIN_VEC_VSUM4SHS },
6394169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsum4sbs", ALTIVEC_BUILTIN_VEC_VSUM4SBS },
6395169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsum4ubs", ALTIVEC_BUILTIN_VEC_VSUM4UBS },
6396169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_sum2s", ALTIVEC_BUILTIN_VEC_SUM2S },
6397169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_sums", ALTIVEC_BUILTIN_VEC_SUMS },
6398169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_xor", ALTIVEC_BUILTIN_VEC_XOR },
6399169689Skan
6400117395Skan  /* Place holder, leave as first spe builtin.  */
6401117395Skan  { 0, CODE_FOR_spe_evaddw, "__builtin_spe_evaddw", SPE_BUILTIN_EVADDW },
6402117395Skan  { 0, CODE_FOR_spe_evand, "__builtin_spe_evand", SPE_BUILTIN_EVAND },
6403117395Skan  { 0, CODE_FOR_spe_evandc, "__builtin_spe_evandc", SPE_BUILTIN_EVANDC },
6404117395Skan  { 0, CODE_FOR_spe_evdivws, "__builtin_spe_evdivws", SPE_BUILTIN_EVDIVWS },
6405117395Skan  { 0, CODE_FOR_spe_evdivwu, "__builtin_spe_evdivwu", SPE_BUILTIN_EVDIVWU },
6406117395Skan  { 0, CODE_FOR_spe_eveqv, "__builtin_spe_eveqv", SPE_BUILTIN_EVEQV },
6407117395Skan  { 0, CODE_FOR_spe_evfsadd, "__builtin_spe_evfsadd", SPE_BUILTIN_EVFSADD },
6408117395Skan  { 0, CODE_FOR_spe_evfsdiv, "__builtin_spe_evfsdiv", SPE_BUILTIN_EVFSDIV },
6409117395Skan  { 0, CODE_FOR_spe_evfsmul, "__builtin_spe_evfsmul", SPE_BUILTIN_EVFSMUL },
6410117395Skan  { 0, CODE_FOR_spe_evfssub, "__builtin_spe_evfssub", SPE_BUILTIN_EVFSSUB },
6411117395Skan  { 0, CODE_FOR_spe_evmergehi, "__builtin_spe_evmergehi", SPE_BUILTIN_EVMERGEHI },
6412117395Skan  { 0, CODE_FOR_spe_evmergehilo, "__builtin_spe_evmergehilo", SPE_BUILTIN_EVMERGEHILO },
6413117395Skan  { 0, CODE_FOR_spe_evmergelo, "__builtin_spe_evmergelo", SPE_BUILTIN_EVMERGELO },
6414117395Skan  { 0, CODE_FOR_spe_evmergelohi, "__builtin_spe_evmergelohi", SPE_BUILTIN_EVMERGELOHI },
6415117395Skan  { 0, CODE_FOR_spe_evmhegsmfaa, "__builtin_spe_evmhegsmfaa", SPE_BUILTIN_EVMHEGSMFAA },
6416117395Skan  { 0, CODE_FOR_spe_evmhegsmfan, "__builtin_spe_evmhegsmfan", SPE_BUILTIN_EVMHEGSMFAN },
6417117395Skan  { 0, CODE_FOR_spe_evmhegsmiaa, "__builtin_spe_evmhegsmiaa", SPE_BUILTIN_EVMHEGSMIAA },
6418117395Skan  { 0, CODE_FOR_spe_evmhegsmian, "__builtin_spe_evmhegsmian", SPE_BUILTIN_EVMHEGSMIAN },
6419117395Skan  { 0, CODE_FOR_spe_evmhegumiaa, "__builtin_spe_evmhegumiaa", SPE_BUILTIN_EVMHEGUMIAA },
6420117395Skan  { 0, CODE_FOR_spe_evmhegumian, "__builtin_spe_evmhegumian", SPE_BUILTIN_EVMHEGUMIAN },
6421117395Skan  { 0, CODE_FOR_spe_evmhesmf, "__builtin_spe_evmhesmf", SPE_BUILTIN_EVMHESMF },
6422117395Skan  { 0, CODE_FOR_spe_evmhesmfa, "__builtin_spe_evmhesmfa", SPE_BUILTIN_EVMHESMFA },
6423117395Skan  { 0, CODE_FOR_spe_evmhesmfaaw, "__builtin_spe_evmhesmfaaw", SPE_BUILTIN_EVMHESMFAAW },
6424117395Skan  { 0, CODE_FOR_spe_evmhesmfanw, "__builtin_spe_evmhesmfanw", SPE_BUILTIN_EVMHESMFANW },
6425117395Skan  { 0, CODE_FOR_spe_evmhesmi, "__builtin_spe_evmhesmi", SPE_BUILTIN_EVMHESMI },
6426117395Skan  { 0, CODE_FOR_spe_evmhesmia, "__builtin_spe_evmhesmia", SPE_BUILTIN_EVMHESMIA },
6427117395Skan  { 0, CODE_FOR_spe_evmhesmiaaw, "__builtin_spe_evmhesmiaaw", SPE_BUILTIN_EVMHESMIAAW },
6428117395Skan  { 0, CODE_FOR_spe_evmhesmianw, "__builtin_spe_evmhesmianw", SPE_BUILTIN_EVMHESMIANW },
6429117395Skan  { 0, CODE_FOR_spe_evmhessf, "__builtin_spe_evmhessf", SPE_BUILTIN_EVMHESSF },
6430117395Skan  { 0, CODE_FOR_spe_evmhessfa, "__builtin_spe_evmhessfa", SPE_BUILTIN_EVMHESSFA },
6431117395Skan  { 0, CODE_FOR_spe_evmhessfaaw, "__builtin_spe_evmhessfaaw", SPE_BUILTIN_EVMHESSFAAW },
6432117395Skan  { 0, CODE_FOR_spe_evmhessfanw, "__builtin_spe_evmhessfanw", SPE_BUILTIN_EVMHESSFANW },
6433117395Skan  { 0, CODE_FOR_spe_evmhessiaaw, "__builtin_spe_evmhessiaaw", SPE_BUILTIN_EVMHESSIAAW },
6434117395Skan  { 0, CODE_FOR_spe_evmhessianw, "__builtin_spe_evmhessianw", SPE_BUILTIN_EVMHESSIANW },
6435117395Skan  { 0, CODE_FOR_spe_evmheumi, "__builtin_spe_evmheumi", SPE_BUILTIN_EVMHEUMI },
6436117395Skan  { 0, CODE_FOR_spe_evmheumia, "__builtin_spe_evmheumia", SPE_BUILTIN_EVMHEUMIA },
6437117395Skan  { 0, CODE_FOR_spe_evmheumiaaw, "__builtin_spe_evmheumiaaw", SPE_BUILTIN_EVMHEUMIAAW },
6438117395Skan  { 0, CODE_FOR_spe_evmheumianw, "__builtin_spe_evmheumianw", SPE_BUILTIN_EVMHEUMIANW },
6439117395Skan  { 0, CODE_FOR_spe_evmheusiaaw, "__builtin_spe_evmheusiaaw", SPE_BUILTIN_EVMHEUSIAAW },
6440117395Skan  { 0, CODE_FOR_spe_evmheusianw, "__builtin_spe_evmheusianw", SPE_BUILTIN_EVMHEUSIANW },
6441117395Skan  { 0, CODE_FOR_spe_evmhogsmfaa, "__builtin_spe_evmhogsmfaa", SPE_BUILTIN_EVMHOGSMFAA },
6442117395Skan  { 0, CODE_FOR_spe_evmhogsmfan, "__builtin_spe_evmhogsmfan", SPE_BUILTIN_EVMHOGSMFAN },
6443117395Skan  { 0, CODE_FOR_spe_evmhogsmiaa, "__builtin_spe_evmhogsmiaa", SPE_BUILTIN_EVMHOGSMIAA },
6444117395Skan  { 0, CODE_FOR_spe_evmhogsmian, "__builtin_spe_evmhogsmian", SPE_BUILTIN_EVMHOGSMIAN },
6445117395Skan  { 0, CODE_FOR_spe_evmhogumiaa, "__builtin_spe_evmhogumiaa", SPE_BUILTIN_EVMHOGUMIAA },
6446117395Skan  { 0, CODE_FOR_spe_evmhogumian, "__builtin_spe_evmhogumian", SPE_BUILTIN_EVMHOGUMIAN },
6447117395Skan  { 0, CODE_FOR_spe_evmhosmf, "__builtin_spe_evmhosmf", SPE_BUILTIN_EVMHOSMF },
6448117395Skan  { 0, CODE_FOR_spe_evmhosmfa, "__builtin_spe_evmhosmfa", SPE_BUILTIN_EVMHOSMFA },
6449117395Skan  { 0, CODE_FOR_spe_evmhosmfaaw, "__builtin_spe_evmhosmfaaw", SPE_BUILTIN_EVMHOSMFAAW },
6450117395Skan  { 0, CODE_FOR_spe_evmhosmfanw, "__builtin_spe_evmhosmfanw", SPE_BUILTIN_EVMHOSMFANW },
6451117395Skan  { 0, CODE_FOR_spe_evmhosmi, "__builtin_spe_evmhosmi", SPE_BUILTIN_EVMHOSMI },
6452117395Skan  { 0, CODE_FOR_spe_evmhosmia, "__builtin_spe_evmhosmia", SPE_BUILTIN_EVMHOSMIA },
6453117395Skan  { 0, CODE_FOR_spe_evmhosmiaaw, "__builtin_spe_evmhosmiaaw", SPE_BUILTIN_EVMHOSMIAAW },
6454117395Skan  { 0, CODE_FOR_spe_evmhosmianw, "__builtin_spe_evmhosmianw", SPE_BUILTIN_EVMHOSMIANW },
6455117395Skan  { 0, CODE_FOR_spe_evmhossf, "__builtin_spe_evmhossf", SPE_BUILTIN_EVMHOSSF },
6456117395Skan  { 0, CODE_FOR_spe_evmhossfa, "__builtin_spe_evmhossfa", SPE_BUILTIN_EVMHOSSFA },
6457117395Skan  { 0, CODE_FOR_spe_evmhossfaaw, "__builtin_spe_evmhossfaaw", SPE_BUILTIN_EVMHOSSFAAW },
6458117395Skan  { 0, CODE_FOR_spe_evmhossfanw, "__builtin_spe_evmhossfanw", SPE_BUILTIN_EVMHOSSFANW },
6459117395Skan  { 0, CODE_FOR_spe_evmhossiaaw, "__builtin_spe_evmhossiaaw", SPE_BUILTIN_EVMHOSSIAAW },
6460117395Skan  { 0, CODE_FOR_spe_evmhossianw, "__builtin_spe_evmhossianw", SPE_BUILTIN_EVMHOSSIANW },
6461117395Skan  { 0, CODE_FOR_spe_evmhoumi, "__builtin_spe_evmhoumi", SPE_BUILTIN_EVMHOUMI },
6462117395Skan  { 0, CODE_FOR_spe_evmhoumia, "__builtin_spe_evmhoumia", SPE_BUILTIN_EVMHOUMIA },
6463117395Skan  { 0, CODE_FOR_spe_evmhoumiaaw, "__builtin_spe_evmhoumiaaw", SPE_BUILTIN_EVMHOUMIAAW },
6464117395Skan  { 0, CODE_FOR_spe_evmhoumianw, "__builtin_spe_evmhoumianw", SPE_BUILTIN_EVMHOUMIANW },
6465117395Skan  { 0, CODE_FOR_spe_evmhousiaaw, "__builtin_spe_evmhousiaaw", SPE_BUILTIN_EVMHOUSIAAW },
6466117395Skan  { 0, CODE_FOR_spe_evmhousianw, "__builtin_spe_evmhousianw", SPE_BUILTIN_EVMHOUSIANW },
6467117395Skan  { 0, CODE_FOR_spe_evmwhsmf, "__builtin_spe_evmwhsmf", SPE_BUILTIN_EVMWHSMF },
6468117395Skan  { 0, CODE_FOR_spe_evmwhsmfa, "__builtin_spe_evmwhsmfa", SPE_BUILTIN_EVMWHSMFA },
6469117395Skan  { 0, CODE_FOR_spe_evmwhsmi, "__builtin_spe_evmwhsmi", SPE_BUILTIN_EVMWHSMI },
6470117395Skan  { 0, CODE_FOR_spe_evmwhsmia, "__builtin_spe_evmwhsmia", SPE_BUILTIN_EVMWHSMIA },
6471117395Skan  { 0, CODE_FOR_spe_evmwhssf, "__builtin_spe_evmwhssf", SPE_BUILTIN_EVMWHSSF },
6472117395Skan  { 0, CODE_FOR_spe_evmwhssfa, "__builtin_spe_evmwhssfa", SPE_BUILTIN_EVMWHSSFA },
6473117395Skan  { 0, CODE_FOR_spe_evmwhumi, "__builtin_spe_evmwhumi", SPE_BUILTIN_EVMWHUMI },
6474117395Skan  { 0, CODE_FOR_spe_evmwhumia, "__builtin_spe_evmwhumia", SPE_BUILTIN_EVMWHUMIA },
6475117395Skan  { 0, CODE_FOR_spe_evmwlsmiaaw, "__builtin_spe_evmwlsmiaaw", SPE_BUILTIN_EVMWLSMIAAW },
6476117395Skan  { 0, CODE_FOR_spe_evmwlsmianw, "__builtin_spe_evmwlsmianw", SPE_BUILTIN_EVMWLSMIANW },
6477117395Skan  { 0, CODE_FOR_spe_evmwlssiaaw, "__builtin_spe_evmwlssiaaw", SPE_BUILTIN_EVMWLSSIAAW },
6478117395Skan  { 0, CODE_FOR_spe_evmwlssianw, "__builtin_spe_evmwlssianw", SPE_BUILTIN_EVMWLSSIANW },
6479117395Skan  { 0, CODE_FOR_spe_evmwlumi, "__builtin_spe_evmwlumi", SPE_BUILTIN_EVMWLUMI },
6480117395Skan  { 0, CODE_FOR_spe_evmwlumia, "__builtin_spe_evmwlumia", SPE_BUILTIN_EVMWLUMIA },
6481117395Skan  { 0, CODE_FOR_spe_evmwlumiaaw, "__builtin_spe_evmwlumiaaw", SPE_BUILTIN_EVMWLUMIAAW },
6482117395Skan  { 0, CODE_FOR_spe_evmwlumianw, "__builtin_spe_evmwlumianw", SPE_BUILTIN_EVMWLUMIANW },
6483117395Skan  { 0, CODE_FOR_spe_evmwlusiaaw, "__builtin_spe_evmwlusiaaw", SPE_BUILTIN_EVMWLUSIAAW },
6484117395Skan  { 0, CODE_FOR_spe_evmwlusianw, "__builtin_spe_evmwlusianw", SPE_BUILTIN_EVMWLUSIANW },
6485117395Skan  { 0, CODE_FOR_spe_evmwsmf, "__builtin_spe_evmwsmf", SPE_BUILTIN_EVMWSMF },
6486117395Skan  { 0, CODE_FOR_spe_evmwsmfa, "__builtin_spe_evmwsmfa", SPE_BUILTIN_EVMWSMFA },
6487117395Skan  { 0, CODE_FOR_spe_evmwsmfaa, "__builtin_spe_evmwsmfaa", SPE_BUILTIN_EVMWSMFAA },
6488117395Skan  { 0, CODE_FOR_spe_evmwsmfan, "__builtin_spe_evmwsmfan", SPE_BUILTIN_EVMWSMFAN },
6489117395Skan  { 0, CODE_FOR_spe_evmwsmi, "__builtin_spe_evmwsmi", SPE_BUILTIN_EVMWSMI },
6490117395Skan  { 0, CODE_FOR_spe_evmwsmia, "__builtin_spe_evmwsmia", SPE_BUILTIN_EVMWSMIA },
6491117395Skan  { 0, CODE_FOR_spe_evmwsmiaa, "__builtin_spe_evmwsmiaa", SPE_BUILTIN_EVMWSMIAA },
6492117395Skan  { 0, CODE_FOR_spe_evmwsmian, "__builtin_spe_evmwsmian", SPE_BUILTIN_EVMWSMIAN },
6493117395Skan  { 0, CODE_FOR_spe_evmwssf, "__builtin_spe_evmwssf", SPE_BUILTIN_EVMWSSF },
6494117395Skan  { 0, CODE_FOR_spe_evmwssfa, "__builtin_spe_evmwssfa", SPE_BUILTIN_EVMWSSFA },
6495117395Skan  { 0, CODE_FOR_spe_evmwssfaa, "__builtin_spe_evmwssfaa", SPE_BUILTIN_EVMWSSFAA },
6496117395Skan  { 0, CODE_FOR_spe_evmwssfan, "__builtin_spe_evmwssfan", SPE_BUILTIN_EVMWSSFAN },
6497117395Skan  { 0, CODE_FOR_spe_evmwumi, "__builtin_spe_evmwumi", SPE_BUILTIN_EVMWUMI },
6498117395Skan  { 0, CODE_FOR_spe_evmwumia, "__builtin_spe_evmwumia", SPE_BUILTIN_EVMWUMIA },
6499117395Skan  { 0, CODE_FOR_spe_evmwumiaa, "__builtin_spe_evmwumiaa", SPE_BUILTIN_EVMWUMIAA },
6500117395Skan  { 0, CODE_FOR_spe_evmwumian, "__builtin_spe_evmwumian", SPE_BUILTIN_EVMWUMIAN },
6501117395Skan  { 0, CODE_FOR_spe_evnand, "__builtin_spe_evnand", SPE_BUILTIN_EVNAND },
6502117395Skan  { 0, CODE_FOR_spe_evnor, "__builtin_spe_evnor", SPE_BUILTIN_EVNOR },
6503117395Skan  { 0, CODE_FOR_spe_evor, "__builtin_spe_evor", SPE_BUILTIN_EVOR },
6504117395Skan  { 0, CODE_FOR_spe_evorc, "__builtin_spe_evorc", SPE_BUILTIN_EVORC },
6505117395Skan  { 0, CODE_FOR_spe_evrlw, "__builtin_spe_evrlw", SPE_BUILTIN_EVRLW },
6506117395Skan  { 0, CODE_FOR_spe_evslw, "__builtin_spe_evslw", SPE_BUILTIN_EVSLW },
6507117395Skan  { 0, CODE_FOR_spe_evsrws, "__builtin_spe_evsrws", SPE_BUILTIN_EVSRWS },
6508117395Skan  { 0, CODE_FOR_spe_evsrwu, "__builtin_spe_evsrwu", SPE_BUILTIN_EVSRWU },
6509117395Skan  { 0, CODE_FOR_spe_evsubfw, "__builtin_spe_evsubfw", SPE_BUILTIN_EVSUBFW },
6510117395Skan
6511117395Skan  /* SPE binary operations expecting a 5-bit unsigned literal.  */
6512117395Skan  { 0, CODE_FOR_spe_evaddiw, "__builtin_spe_evaddiw", SPE_BUILTIN_EVADDIW },
6513117395Skan
6514117395Skan  { 0, CODE_FOR_spe_evrlwi, "__builtin_spe_evrlwi", SPE_BUILTIN_EVRLWI },
6515117395Skan  { 0, CODE_FOR_spe_evslwi, "__builtin_spe_evslwi", SPE_BUILTIN_EVSLWI },
6516117395Skan  { 0, CODE_FOR_spe_evsrwis, "__builtin_spe_evsrwis", SPE_BUILTIN_EVSRWIS },
6517117395Skan  { 0, CODE_FOR_spe_evsrwiu, "__builtin_spe_evsrwiu", SPE_BUILTIN_EVSRWIU },
6518117395Skan  { 0, CODE_FOR_spe_evsubifw, "__builtin_spe_evsubifw", SPE_BUILTIN_EVSUBIFW },
6519117395Skan  { 0, CODE_FOR_spe_evmwhssfaa, "__builtin_spe_evmwhssfaa", SPE_BUILTIN_EVMWHSSFAA },
6520117395Skan  { 0, CODE_FOR_spe_evmwhssmaa, "__builtin_spe_evmwhssmaa", SPE_BUILTIN_EVMWHSSMAA },
6521117395Skan  { 0, CODE_FOR_spe_evmwhsmfaa, "__builtin_spe_evmwhsmfaa", SPE_BUILTIN_EVMWHSMFAA },
6522117395Skan  { 0, CODE_FOR_spe_evmwhsmiaa, "__builtin_spe_evmwhsmiaa", SPE_BUILTIN_EVMWHSMIAA },
6523117395Skan  { 0, CODE_FOR_spe_evmwhusiaa, "__builtin_spe_evmwhusiaa", SPE_BUILTIN_EVMWHUSIAA },
6524117395Skan  { 0, CODE_FOR_spe_evmwhumiaa, "__builtin_spe_evmwhumiaa", SPE_BUILTIN_EVMWHUMIAA },
6525117395Skan  { 0, CODE_FOR_spe_evmwhssfan, "__builtin_spe_evmwhssfan", SPE_BUILTIN_EVMWHSSFAN },
6526117395Skan  { 0, CODE_FOR_spe_evmwhssian, "__builtin_spe_evmwhssian", SPE_BUILTIN_EVMWHSSIAN },
6527117395Skan  { 0, CODE_FOR_spe_evmwhsmfan, "__builtin_spe_evmwhsmfan", SPE_BUILTIN_EVMWHSMFAN },
6528117395Skan  { 0, CODE_FOR_spe_evmwhsmian, "__builtin_spe_evmwhsmian", SPE_BUILTIN_EVMWHSMIAN },
6529117395Skan  { 0, CODE_FOR_spe_evmwhusian, "__builtin_spe_evmwhusian", SPE_BUILTIN_EVMWHUSIAN },
6530117395Skan  { 0, CODE_FOR_spe_evmwhumian, "__builtin_spe_evmwhumian", SPE_BUILTIN_EVMWHUMIAN },
6531117395Skan  { 0, CODE_FOR_spe_evmwhgssfaa, "__builtin_spe_evmwhgssfaa", SPE_BUILTIN_EVMWHGSSFAA },
6532117395Skan  { 0, CODE_FOR_spe_evmwhgsmfaa, "__builtin_spe_evmwhgsmfaa", SPE_BUILTIN_EVMWHGSMFAA },
6533117395Skan  { 0, CODE_FOR_spe_evmwhgsmiaa, "__builtin_spe_evmwhgsmiaa", SPE_BUILTIN_EVMWHGSMIAA },
6534117395Skan  { 0, CODE_FOR_spe_evmwhgumiaa, "__builtin_spe_evmwhgumiaa", SPE_BUILTIN_EVMWHGUMIAA },
6535117395Skan  { 0, CODE_FOR_spe_evmwhgssfan, "__builtin_spe_evmwhgssfan", SPE_BUILTIN_EVMWHGSSFAN },
6536117395Skan  { 0, CODE_FOR_spe_evmwhgsmfan, "__builtin_spe_evmwhgsmfan", SPE_BUILTIN_EVMWHGSMFAN },
6537117395Skan  { 0, CODE_FOR_spe_evmwhgsmian, "__builtin_spe_evmwhgsmian", SPE_BUILTIN_EVMWHGSMIAN },
6538117395Skan  { 0, CODE_FOR_spe_evmwhgumian, "__builtin_spe_evmwhgumian", SPE_BUILTIN_EVMWHGUMIAN },
6539117395Skan  { 0, CODE_FOR_spe_brinc, "__builtin_spe_brinc", SPE_BUILTIN_BRINC },
6540117395Skan
6541117395Skan  /* Place-holder.  Leave as last binary SPE builtin.  */
6542169689Skan  { 0, CODE_FOR_xorv2si3, "__builtin_spe_evxor", SPE_BUILTIN_EVXOR }
654390075Sobrien};
654490075Sobrien
654596263Sobrien/* AltiVec predicates.  */
654696263Sobrien
654796263Sobrienstruct builtin_description_predicates
654896263Sobrien{
654996263Sobrien  const unsigned int mask;
655096263Sobrien  const enum insn_code icode;
655196263Sobrien  const char *opcode;
655296263Sobrien  const char *const name;
655396263Sobrien  const enum rs6000_builtins code;
655496263Sobrien};
655596263Sobrien
655696263Sobrienstatic const struct builtin_description_predicates bdesc_altivec_preds[] =
655796263Sobrien{
655896263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v4sf, "*vcmpbfp.", "__builtin_altivec_vcmpbfp_p", ALTIVEC_BUILTIN_VCMPBFP_P },
655996263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v4sf, "*vcmpeqfp.", "__builtin_altivec_vcmpeqfp_p", ALTIVEC_BUILTIN_VCMPEQFP_P },
656096263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v4sf, "*vcmpgefp.", "__builtin_altivec_vcmpgefp_p", ALTIVEC_BUILTIN_VCMPGEFP_P },
656196263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v4sf, "*vcmpgtfp.", "__builtin_altivec_vcmpgtfp_p", ALTIVEC_BUILTIN_VCMPGTFP_P },
656296263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v4si, "*vcmpequw.", "__builtin_altivec_vcmpequw_p", ALTIVEC_BUILTIN_VCMPEQUW_P },
656396263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v4si, "*vcmpgtsw.", "__builtin_altivec_vcmpgtsw_p", ALTIVEC_BUILTIN_VCMPGTSW_P },
656496263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v4si, "*vcmpgtuw.", "__builtin_altivec_vcmpgtuw_p", ALTIVEC_BUILTIN_VCMPGTUW_P },
656596263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v8hi, "*vcmpgtuh.", "__builtin_altivec_vcmpgtuh_p", ALTIVEC_BUILTIN_VCMPGTUH_P },
656696263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v8hi, "*vcmpgtsh.", "__builtin_altivec_vcmpgtsh_p", ALTIVEC_BUILTIN_VCMPGTSH_P },
656796263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v8hi, "*vcmpequh.", "__builtin_altivec_vcmpequh_p", ALTIVEC_BUILTIN_VCMPEQUH_P },
656896263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v16qi, "*vcmpequb.", "__builtin_altivec_vcmpequb_p", ALTIVEC_BUILTIN_VCMPEQUB_P },
656996263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v16qi, "*vcmpgtsb.", "__builtin_altivec_vcmpgtsb_p", ALTIVEC_BUILTIN_VCMPGTSB_P },
6570169689Skan  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v16qi, "*vcmpgtub.", "__builtin_altivec_vcmpgtub_p", ALTIVEC_BUILTIN_VCMPGTUB_P },
6571169689Skan
6572169689Skan  { MASK_ALTIVEC, 0, NULL, "__builtin_vec_vcmpeq_p", ALTIVEC_BUILTIN_VCMPEQ_P },
6573169689Skan  { MASK_ALTIVEC, 0, NULL, "__builtin_vec_vcmpgt_p", ALTIVEC_BUILTIN_VCMPGT_P },
6574169689Skan  { MASK_ALTIVEC, 0, NULL, "__builtin_vec_vcmpge_p", ALTIVEC_BUILTIN_VCMPGE_P }
657596263Sobrien};
657696263Sobrien
6577117395Skan/* SPE predicates.  */
6578117395Skanstatic struct builtin_description bdesc_spe_predicates[] =
6579117395Skan{
6580117395Skan  /* Place-holder.  Leave as first.  */
6581117395Skan  { 0, CODE_FOR_spe_evcmpeq, "__builtin_spe_evcmpeq", SPE_BUILTIN_EVCMPEQ },
6582117395Skan  { 0, CODE_FOR_spe_evcmpgts, "__builtin_spe_evcmpgts", SPE_BUILTIN_EVCMPGTS },
6583117395Skan  { 0, CODE_FOR_spe_evcmpgtu, "__builtin_spe_evcmpgtu", SPE_BUILTIN_EVCMPGTU },
6584117395Skan  { 0, CODE_FOR_spe_evcmplts, "__builtin_spe_evcmplts", SPE_BUILTIN_EVCMPLTS },
6585117395Skan  { 0, CODE_FOR_spe_evcmpltu, "__builtin_spe_evcmpltu", SPE_BUILTIN_EVCMPLTU },
6586117395Skan  { 0, CODE_FOR_spe_evfscmpeq, "__builtin_spe_evfscmpeq", SPE_BUILTIN_EVFSCMPEQ },
6587117395Skan  { 0, CODE_FOR_spe_evfscmpgt, "__builtin_spe_evfscmpgt", SPE_BUILTIN_EVFSCMPGT },
6588117395Skan  { 0, CODE_FOR_spe_evfscmplt, "__builtin_spe_evfscmplt", SPE_BUILTIN_EVFSCMPLT },
6589117395Skan  { 0, CODE_FOR_spe_evfststeq, "__builtin_spe_evfststeq", SPE_BUILTIN_EVFSTSTEQ },
6590117395Skan  { 0, CODE_FOR_spe_evfststgt, "__builtin_spe_evfststgt", SPE_BUILTIN_EVFSTSTGT },
6591117395Skan  /* Place-holder.  Leave as last.  */
6592117395Skan  { 0, CODE_FOR_spe_evfststlt, "__builtin_spe_evfststlt", SPE_BUILTIN_EVFSTSTLT },
6593117395Skan};
6594117395Skan
6595117395Skan/* SPE evsel predicates.  */
6596117395Skanstatic struct builtin_description bdesc_spe_evsel[] =
6597117395Skan{
6598117395Skan  /* Place-holder.  Leave as first.  */
6599117395Skan  { 0, CODE_FOR_spe_evcmpgts, "__builtin_spe_evsel_gts", SPE_BUILTIN_EVSEL_CMPGTS },
6600117395Skan  { 0, CODE_FOR_spe_evcmpgtu, "__builtin_spe_evsel_gtu", SPE_BUILTIN_EVSEL_CMPGTU },
6601117395Skan  { 0, CODE_FOR_spe_evcmplts, "__builtin_spe_evsel_lts", SPE_BUILTIN_EVSEL_CMPLTS },
6602117395Skan  { 0, CODE_FOR_spe_evcmpltu, "__builtin_spe_evsel_ltu", SPE_BUILTIN_EVSEL_CMPLTU },
6603117395Skan  { 0, CODE_FOR_spe_evcmpeq, "__builtin_spe_evsel_eq", SPE_BUILTIN_EVSEL_CMPEQ },
6604117395Skan  { 0, CODE_FOR_spe_evfscmpgt, "__builtin_spe_evsel_fsgt", SPE_BUILTIN_EVSEL_FSCMPGT },
6605117395Skan  { 0, CODE_FOR_spe_evfscmplt, "__builtin_spe_evsel_fslt", SPE_BUILTIN_EVSEL_FSCMPLT },
6606117395Skan  { 0, CODE_FOR_spe_evfscmpeq, "__builtin_spe_evsel_fseq", SPE_BUILTIN_EVSEL_FSCMPEQ },
6607117395Skan  { 0, CODE_FOR_spe_evfststgt, "__builtin_spe_evsel_fststgt", SPE_BUILTIN_EVSEL_FSTSTGT },
6608117395Skan  { 0, CODE_FOR_spe_evfststlt, "__builtin_spe_evsel_fststlt", SPE_BUILTIN_EVSEL_FSTSTLT },
6609117395Skan  /* Place-holder.  Leave as last.  */
6610117395Skan  { 0, CODE_FOR_spe_evfststeq, "__builtin_spe_evsel_fststeq", SPE_BUILTIN_EVSEL_FSTSTEQ },
6611117395Skan};
6612117395Skan
6613132718Skan/* ABS* operations.  */
661496263Sobrien
661596263Sobrienstatic const struct builtin_description bdesc_abs[] =
661696263Sobrien{
661796263Sobrien  { MASK_ALTIVEC, CODE_FOR_absv4si2, "__builtin_altivec_abs_v4si", ALTIVEC_BUILTIN_ABS_V4SI },
661896263Sobrien  { MASK_ALTIVEC, CODE_FOR_absv8hi2, "__builtin_altivec_abs_v8hi", ALTIVEC_BUILTIN_ABS_V8HI },
661996263Sobrien  { MASK_ALTIVEC, CODE_FOR_absv4sf2, "__builtin_altivec_abs_v4sf", ALTIVEC_BUILTIN_ABS_V4SF },
662096263Sobrien  { MASK_ALTIVEC, CODE_FOR_absv16qi2, "__builtin_altivec_abs_v16qi", ALTIVEC_BUILTIN_ABS_V16QI },
662196263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_abss_v4si, "__builtin_altivec_abss_v4si", ALTIVEC_BUILTIN_ABSS_V4SI },
662296263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_abss_v8hi, "__builtin_altivec_abss_v8hi", ALTIVEC_BUILTIN_ABSS_V8HI },
662396263Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_abss_v16qi, "__builtin_altivec_abss_v16qi", ALTIVEC_BUILTIN_ABSS_V16QI }
662496263Sobrien};
662596263Sobrien
662690075Sobrien/* Simple unary operations: VECb = foo (unsigned literal) or VECb =
662790075Sobrien   foo (VECa).  */
662890075Sobrien
6629117395Skanstatic struct builtin_description bdesc_1arg[] =
663090075Sobrien{
663190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vexptefp, "__builtin_altivec_vexptefp", ALTIVEC_BUILTIN_VEXPTEFP },
663290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vlogefp, "__builtin_altivec_vlogefp", ALTIVEC_BUILTIN_VLOGEFP },
663390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vrefp, "__builtin_altivec_vrefp", ALTIVEC_BUILTIN_VREFP },
663490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vrfim, "__builtin_altivec_vrfim", ALTIVEC_BUILTIN_VRFIM },
663590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vrfin, "__builtin_altivec_vrfin", ALTIVEC_BUILTIN_VRFIN },
663690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vrfip, "__builtin_altivec_vrfip", ALTIVEC_BUILTIN_VRFIP },
663790075Sobrien  { MASK_ALTIVEC, CODE_FOR_ftruncv4sf2, "__builtin_altivec_vrfiz", ALTIVEC_BUILTIN_VRFIZ },
663890075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vrsqrtefp, "__builtin_altivec_vrsqrtefp", ALTIVEC_BUILTIN_VRSQRTEFP },
663990075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vspltisb, "__builtin_altivec_vspltisb", ALTIVEC_BUILTIN_VSPLTISB },
664090075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vspltish, "__builtin_altivec_vspltish", ALTIVEC_BUILTIN_VSPLTISH },
664190075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vspltisw, "__builtin_altivec_vspltisw", ALTIVEC_BUILTIN_VSPLTISW },
664290075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vupkhsb, "__builtin_altivec_vupkhsb", ALTIVEC_BUILTIN_VUPKHSB },
664390075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vupkhpx, "__builtin_altivec_vupkhpx", ALTIVEC_BUILTIN_VUPKHPX },
664490075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vupkhsh, "__builtin_altivec_vupkhsh", ALTIVEC_BUILTIN_VUPKHSH },
664590075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vupklsb, "__builtin_altivec_vupklsb", ALTIVEC_BUILTIN_VUPKLSB },
664690075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vupklpx, "__builtin_altivec_vupklpx", ALTIVEC_BUILTIN_VUPKLPX },
664790075Sobrien  { MASK_ALTIVEC, CODE_FOR_altivec_vupklsh, "__builtin_altivec_vupklsh", ALTIVEC_BUILTIN_VUPKLSH },
6648117395Skan
6649169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_abs", ALTIVEC_BUILTIN_VEC_ABS },
6650169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_abss", ALTIVEC_BUILTIN_VEC_ABSS },
6651169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_ceil", ALTIVEC_BUILTIN_VEC_CEIL },
6652169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_expte", ALTIVEC_BUILTIN_VEC_EXPTE },
6653169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_floor", ALTIVEC_BUILTIN_VEC_FLOOR },
6654169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_loge", ALTIVEC_BUILTIN_VEC_LOGE },
6655169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_mtvscr", ALTIVEC_BUILTIN_VEC_MTVSCR },
6656169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_re", ALTIVEC_BUILTIN_VEC_RE },
6657169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_round", ALTIVEC_BUILTIN_VEC_ROUND },
6658169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_rsqrte", ALTIVEC_BUILTIN_VEC_RSQRTE },
6659169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_trunc", ALTIVEC_BUILTIN_VEC_TRUNC },
6660169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_unpackh", ALTIVEC_BUILTIN_VEC_UNPACKH },
6661169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vupkhsh", ALTIVEC_BUILTIN_VEC_VUPKHSH },
6662169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vupkhpx", ALTIVEC_BUILTIN_VEC_VUPKHPX },
6663169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vupkhsb", ALTIVEC_BUILTIN_VEC_VUPKHSB },
6664169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_unpackl", ALTIVEC_BUILTIN_VEC_UNPACKL },
6665169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vupklpx", ALTIVEC_BUILTIN_VEC_VUPKLPX },
6666169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vupklsh", ALTIVEC_BUILTIN_VEC_VUPKLSH },
6667169689Skan  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vupklsb", ALTIVEC_BUILTIN_VEC_VUPKLSB },
6668169689Skan
6669117395Skan  /* The SPE unary builtins must start with SPE_BUILTIN_EVABS and
6670117395Skan     end with SPE_BUILTIN_EVSUBFUSIAAW.  */
6671117395Skan  { 0, CODE_FOR_spe_evabs, "__builtin_spe_evabs", SPE_BUILTIN_EVABS },
6672117395Skan  { 0, CODE_FOR_spe_evaddsmiaaw, "__builtin_spe_evaddsmiaaw", SPE_BUILTIN_EVADDSMIAAW },
6673117395Skan  { 0, CODE_FOR_spe_evaddssiaaw, "__builtin_spe_evaddssiaaw", SPE_BUILTIN_EVADDSSIAAW },
6674117395Skan  { 0, CODE_FOR_spe_evaddumiaaw, "__builtin_spe_evaddumiaaw", SPE_BUILTIN_EVADDUMIAAW },
6675117395Skan  { 0, CODE_FOR_spe_evaddusiaaw, "__builtin_spe_evaddusiaaw", SPE_BUILTIN_EVADDUSIAAW },
6676117395Skan  { 0, CODE_FOR_spe_evcntlsw, "__builtin_spe_evcntlsw", SPE_BUILTIN_EVCNTLSW },
6677117395Skan  { 0, CODE_FOR_spe_evcntlzw, "__builtin_spe_evcntlzw", SPE_BUILTIN_EVCNTLZW },
6678117395Skan  { 0, CODE_FOR_spe_evextsb, "__builtin_spe_evextsb", SPE_BUILTIN_EVEXTSB },
6679117395Skan  { 0, CODE_FOR_spe_evextsh, "__builtin_spe_evextsh", SPE_BUILTIN_EVEXTSH },
6680117395Skan  { 0, CODE_FOR_spe_evfsabs, "__builtin_spe_evfsabs", SPE_BUILTIN_EVFSABS },
6681117395Skan  { 0, CODE_FOR_spe_evfscfsf, "__builtin_spe_evfscfsf", SPE_BUILTIN_EVFSCFSF },
6682117395Skan  { 0, CODE_FOR_spe_evfscfsi, "__builtin_spe_evfscfsi", SPE_BUILTIN_EVFSCFSI },
6683117395Skan  { 0, CODE_FOR_spe_evfscfuf, "__builtin_spe_evfscfuf", SPE_BUILTIN_EVFSCFUF },
6684117395Skan  { 0, CODE_FOR_spe_evfscfui, "__builtin_spe_evfscfui", SPE_BUILTIN_EVFSCFUI },
6685117395Skan  { 0, CODE_FOR_spe_evfsctsf, "__builtin_spe_evfsctsf", SPE_BUILTIN_EVFSCTSF },
6686117395Skan  { 0, CODE_FOR_spe_evfsctsi, "__builtin_spe_evfsctsi", SPE_BUILTIN_EVFSCTSI },
6687117395Skan  { 0, CODE_FOR_spe_evfsctsiz, "__builtin_spe_evfsctsiz", SPE_BUILTIN_EVFSCTSIZ },
6688117395Skan  { 0, CODE_FOR_spe_evfsctuf, "__builtin_spe_evfsctuf", SPE_BUILTIN_EVFSCTUF },
6689117395Skan  { 0, CODE_FOR_spe_evfsctui, "__builtin_spe_evfsctui", SPE_BUILTIN_EVFSCTUI },
6690117395Skan  { 0, CODE_FOR_spe_evfsctuiz, "__builtin_spe_evfsctuiz", SPE_BUILTIN_EVFSCTUIZ },
6691117395Skan  { 0, CODE_FOR_spe_evfsnabs, "__builtin_spe_evfsnabs", SPE_BUILTIN_EVFSNABS },
6692117395Skan  { 0, CODE_FOR_spe_evfsneg, "__builtin_spe_evfsneg", SPE_BUILTIN_EVFSNEG },
6693117395Skan  { 0, CODE_FOR_spe_evmra, "__builtin_spe_evmra", SPE_BUILTIN_EVMRA },
6694132718Skan  { 0, CODE_FOR_negv2si2, "__builtin_spe_evneg", SPE_BUILTIN_EVNEG },
6695117395Skan  { 0, CODE_FOR_spe_evrndw, "__builtin_spe_evrndw", SPE_BUILTIN_EVRNDW },
6696117395Skan  { 0, CODE_FOR_spe_evsubfsmiaaw, "__builtin_spe_evsubfsmiaaw", SPE_BUILTIN_EVSUBFSMIAAW },
6697117395Skan  { 0, CODE_FOR_spe_evsubfssiaaw, "__builtin_spe_evsubfssiaaw", SPE_BUILTIN_EVSUBFSSIAAW },
6698117395Skan  { 0, CODE_FOR_spe_evsubfumiaaw, "__builtin_spe_evsubfumiaaw", SPE_BUILTIN_EVSUBFUMIAAW },
6699117395Skan
6700117395Skan  /* Place-holder.  Leave as last unary SPE builtin.  */
6701169689Skan  { 0, CODE_FOR_spe_evsubfusiaaw, "__builtin_spe_evsubfusiaaw", SPE_BUILTIN_EVSUBFUSIAAW }
670290075Sobrien};
670390075Sobrien
670490075Sobrienstatic rtx
6705132718Skanrs6000_expand_unop_builtin (enum insn_code icode, tree arglist, rtx target)
670690075Sobrien{
670790075Sobrien  rtx pat;
670890075Sobrien  tree arg0 = TREE_VALUE (arglist);
6709169689Skan  rtx op0 = expand_normal (arg0);
671090075Sobrien  enum machine_mode tmode = insn_data[icode].operand[0].mode;
671190075Sobrien  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
671290075Sobrien
6713117395Skan  if (icode == CODE_FOR_nothing)
6714117395Skan    /* Builtin not supported on this processor.  */
6715117395Skan    return 0;
6716117395Skan
671790075Sobrien  /* If we got invalid arguments bail out before generating bad rtl.  */
671890075Sobrien  if (arg0 == error_mark_node)
6719117395Skan    return const0_rtx;
672090075Sobrien
6721117395Skan  if (icode == CODE_FOR_altivec_vspltisb
6722117395Skan      || icode == CODE_FOR_altivec_vspltish
6723117395Skan      || icode == CODE_FOR_altivec_vspltisw
6724117395Skan      || icode == CODE_FOR_spe_evsplatfi
6725117395Skan      || icode == CODE_FOR_spe_evsplati)
6726117395Skan    {
6727117395Skan      /* Only allow 5-bit *signed* literals.  */
6728117395Skan      if (GET_CODE (op0) != CONST_INT
6729169689Skan	  || INTVAL (op0) > 15
6730169689Skan	  || INTVAL (op0) < -16)
6731117395Skan	{
6732117395Skan	  error ("argument 1 must be a 5-bit signed literal");
6733117395Skan	  return const0_rtx;
6734117395Skan	}
6735117395Skan    }
6736117395Skan
673790075Sobrien  if (target == 0
673890075Sobrien      || GET_MODE (target) != tmode
673990075Sobrien      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
674090075Sobrien    target = gen_reg_rtx (tmode);
674190075Sobrien
674290075Sobrien  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
674390075Sobrien    op0 = copy_to_mode_reg (mode0, op0);
674490075Sobrien
674590075Sobrien  pat = GEN_FCN (icode) (target, op0);
674690075Sobrien  if (! pat)
674790075Sobrien    return 0;
674890075Sobrien  emit_insn (pat);
674990075Sobrien
675090075Sobrien  return target;
675190075Sobrien}
675296263Sobrien
675390075Sobrienstatic rtx
6754132718Skanaltivec_expand_abs_builtin (enum insn_code icode, tree arglist, rtx target)
675596263Sobrien{
675696263Sobrien  rtx pat, scratch1, scratch2;
675796263Sobrien  tree arg0 = TREE_VALUE (arglist);
6758169689Skan  rtx op0 = expand_normal (arg0);
675996263Sobrien  enum machine_mode tmode = insn_data[icode].operand[0].mode;
676096263Sobrien  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
676196263Sobrien
676296263Sobrien  /* If we have invalid arguments, bail out before generating bad rtl.  */
676396263Sobrien  if (arg0 == error_mark_node)
6764117395Skan    return const0_rtx;
676596263Sobrien
676696263Sobrien  if (target == 0
676796263Sobrien      || GET_MODE (target) != tmode
676896263Sobrien      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
676996263Sobrien    target = gen_reg_rtx (tmode);
677096263Sobrien
677196263Sobrien  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
677296263Sobrien    op0 = copy_to_mode_reg (mode0, op0);
677396263Sobrien
677496263Sobrien  scratch1 = gen_reg_rtx (mode0);
677596263Sobrien  scratch2 = gen_reg_rtx (mode0);
677696263Sobrien
677796263Sobrien  pat = GEN_FCN (icode) (target, op0, scratch1, scratch2);
677896263Sobrien  if (! pat)
677996263Sobrien    return 0;
678096263Sobrien  emit_insn (pat);
678196263Sobrien
678296263Sobrien  return target;
678396263Sobrien}
678496263Sobrien
678596263Sobrienstatic rtx
6786132718Skanrs6000_expand_binop_builtin (enum insn_code icode, tree arglist, rtx target)
678790075Sobrien{
678890075Sobrien  rtx pat;
678990075Sobrien  tree arg0 = TREE_VALUE (arglist);
679090075Sobrien  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
6791169689Skan  rtx op0 = expand_normal (arg0);
6792169689Skan  rtx op1 = expand_normal (arg1);
679390075Sobrien  enum machine_mode tmode = insn_data[icode].operand[0].mode;
679490075Sobrien  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
679590075Sobrien  enum machine_mode mode1 = insn_data[icode].operand[2].mode;
679690075Sobrien
6797117395Skan  if (icode == CODE_FOR_nothing)
6798117395Skan    /* Builtin not supported on this processor.  */
6799117395Skan    return 0;
6800117395Skan
680190075Sobrien  /* If we got invalid arguments bail out before generating bad rtl.  */
680290075Sobrien  if (arg0 == error_mark_node || arg1 == error_mark_node)
6803117395Skan    return const0_rtx;
680490075Sobrien
6805117395Skan  if (icode == CODE_FOR_altivec_vcfux
6806117395Skan      || icode == CODE_FOR_altivec_vcfsx
6807117395Skan      || icode == CODE_FOR_altivec_vctsxs
6808117395Skan      || icode == CODE_FOR_altivec_vctuxs
6809117395Skan      || icode == CODE_FOR_altivec_vspltb
6810117395Skan      || icode == CODE_FOR_altivec_vsplth
6811117395Skan      || icode == CODE_FOR_altivec_vspltw
6812117395Skan      || icode == CODE_FOR_spe_evaddiw
6813117395Skan      || icode == CODE_FOR_spe_evldd
6814117395Skan      || icode == CODE_FOR_spe_evldh
6815117395Skan      || icode == CODE_FOR_spe_evldw
6816117395Skan      || icode == CODE_FOR_spe_evlhhesplat
6817117395Skan      || icode == CODE_FOR_spe_evlhhossplat
6818117395Skan      || icode == CODE_FOR_spe_evlhhousplat
6819117395Skan      || icode == CODE_FOR_spe_evlwhe
6820117395Skan      || icode == CODE_FOR_spe_evlwhos
6821117395Skan      || icode == CODE_FOR_spe_evlwhou
6822117395Skan      || icode == CODE_FOR_spe_evlwhsplat
6823117395Skan      || icode == CODE_FOR_spe_evlwwsplat
6824117395Skan      || icode == CODE_FOR_spe_evrlwi
6825117395Skan      || icode == CODE_FOR_spe_evslwi
6826117395Skan      || icode == CODE_FOR_spe_evsrwis
6827132718Skan      || icode == CODE_FOR_spe_evsubifw
6828117395Skan      || icode == CODE_FOR_spe_evsrwiu)
6829117395Skan    {
6830117395Skan      /* Only allow 5-bit unsigned literals.  */
6831146895Skan      STRIP_NOPS (arg1);
6832117395Skan      if (TREE_CODE (arg1) != INTEGER_CST
6833117395Skan	  || TREE_INT_CST_LOW (arg1) & ~0x1f)
6834117395Skan	{
6835117395Skan	  error ("argument 2 must be a 5-bit unsigned literal");
6836117395Skan	  return const0_rtx;
6837117395Skan	}
6838117395Skan    }
6839117395Skan
684090075Sobrien  if (target == 0
684190075Sobrien      || GET_MODE (target) != tmode
684290075Sobrien      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
684390075Sobrien    target = gen_reg_rtx (tmode);
684490075Sobrien
684590075Sobrien  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
684690075Sobrien    op0 = copy_to_mode_reg (mode0, op0);
684790075Sobrien  if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
684890075Sobrien    op1 = copy_to_mode_reg (mode1, op1);
684990075Sobrien
685090075Sobrien  pat = GEN_FCN (icode) (target, op0, op1);
685190075Sobrien  if (! pat)
685290075Sobrien    return 0;
685390075Sobrien  emit_insn (pat);
685490075Sobrien
685590075Sobrien  return target;
685690075Sobrien}
685790075Sobrien
685890075Sobrienstatic rtx
6859169689Skanaltivec_expand_predicate_builtin (enum insn_code icode, const char *opcode,
6860132718Skan				  tree arglist, rtx target)
686196263Sobrien{
686296263Sobrien  rtx pat, scratch;
686396263Sobrien  tree cr6_form = TREE_VALUE (arglist);
686496263Sobrien  tree arg0 = TREE_VALUE (TREE_CHAIN (arglist));
686596263Sobrien  tree arg1 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
6866169689Skan  rtx op0 = expand_normal (arg0);
6867169689Skan  rtx op1 = expand_normal (arg1);
686896263Sobrien  enum machine_mode tmode = SImode;
686996263Sobrien  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
687096263Sobrien  enum machine_mode mode1 = insn_data[icode].operand[2].mode;
687196263Sobrien  int cr6_form_int;
687296263Sobrien
687396263Sobrien  if (TREE_CODE (cr6_form) != INTEGER_CST)
687496263Sobrien    {
687596263Sobrien      error ("argument 1 of __builtin_altivec_predicate must be a constant");
6876117395Skan      return const0_rtx;
687796263Sobrien    }
687896263Sobrien  else
687996263Sobrien    cr6_form_int = TREE_INT_CST_LOW (cr6_form);
688096263Sobrien
6881169689Skan  gcc_assert (mode0 == mode1);
688296263Sobrien
688396263Sobrien  /* If we have invalid arguments, bail out before generating bad rtl.  */
688496263Sobrien  if (arg0 == error_mark_node || arg1 == error_mark_node)
6885117395Skan    return const0_rtx;
688696263Sobrien
688796263Sobrien  if (target == 0
688896263Sobrien      || GET_MODE (target) != tmode
688996263Sobrien      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
689096263Sobrien    target = gen_reg_rtx (tmode);
689196263Sobrien
689296263Sobrien  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
689396263Sobrien    op0 = copy_to_mode_reg (mode0, op0);
689496263Sobrien  if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
689596263Sobrien    op1 = copy_to_mode_reg (mode1, op1);
689696263Sobrien
689796263Sobrien  scratch = gen_reg_rtx (mode0);
689896263Sobrien
689996263Sobrien  pat = GEN_FCN (icode) (scratch, op0, op1,
6900169689Skan			 gen_rtx_SYMBOL_REF (Pmode, opcode));
690196263Sobrien  if (! pat)
690296263Sobrien    return 0;
690396263Sobrien  emit_insn (pat);
690496263Sobrien
690596263Sobrien  /* The vec_any* and vec_all* predicates use the same opcodes for two
690696263Sobrien     different operations, but the bits in CR6 will be different
690796263Sobrien     depending on what information we want.  So we have to play tricks
690896263Sobrien     with CR6 to get the right bits out.
690996263Sobrien
691096263Sobrien     If you think this is disgusting, look at the specs for the
691196263Sobrien     AltiVec predicates.  */
691296263Sobrien
6913169689Skan  switch (cr6_form_int)
6914169689Skan    {
6915169689Skan    case 0:
6916169689Skan      emit_insn (gen_cr6_test_for_zero (target));
6917169689Skan      break;
6918169689Skan    case 1:
6919169689Skan      emit_insn (gen_cr6_test_for_zero_reverse (target));
6920169689Skan      break;
6921169689Skan    case 2:
6922169689Skan      emit_insn (gen_cr6_test_for_lt (target));
6923169689Skan      break;
6924169689Skan    case 3:
6925169689Skan      emit_insn (gen_cr6_test_for_lt_reverse (target));
6926169689Skan      break;
6927169689Skan    default:
6928169689Skan      error ("argument 1 of __builtin_altivec_predicate is out of range");
6929169689Skan      break;
6930169689Skan    }
693196263Sobrien
693296263Sobrien  return target;
693396263Sobrien}
693496263Sobrien
693596263Sobrienstatic rtx
6936132718Skanaltivec_expand_lv_builtin (enum insn_code icode, tree arglist, rtx target)
693790075Sobrien{
6938132718Skan  rtx pat, addr;
693990075Sobrien  tree arg0 = TREE_VALUE (arglist);
694090075Sobrien  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
6941132718Skan  enum machine_mode tmode = insn_data[icode].operand[0].mode;
6942132718Skan  enum machine_mode mode0 = Pmode;
6943132718Skan  enum machine_mode mode1 = Pmode;
6944169689Skan  rtx op0 = expand_normal (arg0);
6945169689Skan  rtx op1 = expand_normal (arg1);
6946132718Skan
6947132718Skan  if (icode == CODE_FOR_nothing)
6948132718Skan    /* Builtin not supported on this processor.  */
6949132718Skan    return 0;
6950132718Skan
6951132718Skan  /* If we got invalid arguments bail out before generating bad rtl.  */
6952132718Skan  if (arg0 == error_mark_node || arg1 == error_mark_node)
6953132718Skan    return const0_rtx;
6954132718Skan
6955132718Skan  if (target == 0
6956132718Skan      || GET_MODE (target) != tmode
6957132718Skan      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
6958132718Skan    target = gen_reg_rtx (tmode);
6959132718Skan
6960169689Skan  op1 = copy_to_mode_reg (mode1, op1);
6961132718Skan
6962132718Skan  if (op0 == const0_rtx)
6963132718Skan    {
6964132718Skan      addr = gen_rtx_MEM (tmode, op1);
6965132718Skan    }
6966132718Skan  else
6967132718Skan    {
6968132718Skan      op0 = copy_to_mode_reg (mode0, op0);
6969132718Skan      addr = gen_rtx_MEM (tmode, gen_rtx_PLUS (Pmode, op0, op1));
6970132718Skan    }
6971132718Skan
6972132718Skan  pat = GEN_FCN (icode) (target, addr);
6973132718Skan
6974132718Skan  if (! pat)
6975132718Skan    return 0;
6976132718Skan  emit_insn (pat);
6977132718Skan
6978132718Skan  return target;
6979132718Skan}
6980132718Skan
6981132718Skanstatic rtx
6982132718Skanspe_expand_stv_builtin (enum insn_code icode, tree arglist)
6983132718Skan{
6984132718Skan  tree arg0 = TREE_VALUE (arglist);
6985132718Skan  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
698690075Sobrien  tree arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
6987169689Skan  rtx op0 = expand_normal (arg0);
6988169689Skan  rtx op1 = expand_normal (arg1);
6989169689Skan  rtx op2 = expand_normal (arg2);
699090075Sobrien  rtx pat;
699190075Sobrien  enum machine_mode mode0 = insn_data[icode].operand[0].mode;
699290075Sobrien  enum machine_mode mode1 = insn_data[icode].operand[1].mode;
699390075Sobrien  enum machine_mode mode2 = insn_data[icode].operand[2].mode;
699490075Sobrien
699590075Sobrien  /* Invalid arguments.  Bail before doing anything stoopid!  */
699690075Sobrien  if (arg0 == error_mark_node
699790075Sobrien      || arg1 == error_mark_node
699890075Sobrien      || arg2 == error_mark_node)
6999117395Skan    return const0_rtx;
700090075Sobrien
700190075Sobrien  if (! (*insn_data[icode].operand[2].predicate) (op0, mode2))
700290075Sobrien    op0 = copy_to_mode_reg (mode2, op0);
700390075Sobrien  if (! (*insn_data[icode].operand[0].predicate) (op1, mode0))
700490075Sobrien    op1 = copy_to_mode_reg (mode0, op1);
700590075Sobrien  if (! (*insn_data[icode].operand[1].predicate) (op2, mode1))
700690075Sobrien    op2 = copy_to_mode_reg (mode1, op2);
700790075Sobrien
700890075Sobrien  pat = GEN_FCN (icode) (op1, op2, op0);
700990075Sobrien  if (pat)
701090075Sobrien    emit_insn (pat);
701190075Sobrien  return NULL_RTX;
701290075Sobrien}
701390075Sobrien
701490075Sobrienstatic rtx
7015132718Skanaltivec_expand_stv_builtin (enum insn_code icode, tree arglist)
701690075Sobrien{
7017132718Skan  tree arg0 = TREE_VALUE (arglist);
7018132718Skan  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
7019132718Skan  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);
7023132718Skan  rtx pat, addr;
7024132718Skan  enum machine_mode tmode = insn_data[icode].operand[0].mode;
7025132718Skan  enum machine_mode mode1 = Pmode;
7026132718Skan  enum machine_mode mode2 = Pmode;
7027132718Skan
7028132718Skan  /* Invalid arguments.  Bail before doing anything stoopid!  */
7029132718Skan  if (arg0 == error_mark_node
7030132718Skan      || arg1 == error_mark_node
7031132718Skan      || arg2 == error_mark_node)
7032132718Skan    return const0_rtx;
7033132718Skan
7034132718Skan  if (! (*insn_data[icode].operand[1].predicate) (op0, tmode))
7035132718Skan    op0 = copy_to_mode_reg (tmode, op0);
7036132718Skan
7037169689Skan  op2 = copy_to_mode_reg (mode2, op2);
7038132718Skan
7039132718Skan  if (op1 == const0_rtx)
7040132718Skan    {
7041132718Skan      addr = gen_rtx_MEM (tmode, op2);
7042132718Skan    }
7043132718Skan  else
7044132718Skan    {
7045132718Skan      op1 = copy_to_mode_reg (mode1, op1);
7046132718Skan      addr = gen_rtx_MEM (tmode, gen_rtx_PLUS (Pmode, op1, op2));
7047132718Skan    }
7048132718Skan
7049132718Skan  pat = GEN_FCN (icode) (addr, op0);
7050132718Skan  if (pat)
7051132718Skan    emit_insn (pat);
7052132718Skan  return NULL_RTX;
7053132718Skan}
7054132718Skan
7055132718Skanstatic rtx
7056132718Skanrs6000_expand_ternop_builtin (enum insn_code icode, tree arglist, rtx target)
7057132718Skan{
705890075Sobrien  rtx pat;
705990075Sobrien  tree arg0 = TREE_VALUE (arglist);
706090075Sobrien  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
706190075Sobrien  tree arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
7062169689Skan  rtx op0 = expand_normal (arg0);
7063169689Skan  rtx op1 = expand_normal (arg1);
7064169689Skan  rtx op2 = expand_normal (arg2);
706590075Sobrien  enum machine_mode tmode = insn_data[icode].operand[0].mode;
706690075Sobrien  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
706790075Sobrien  enum machine_mode mode1 = insn_data[icode].operand[2].mode;
706890075Sobrien  enum machine_mode mode2 = insn_data[icode].operand[3].mode;
706990075Sobrien
7070117395Skan  if (icode == CODE_FOR_nothing)
7071117395Skan    /* Builtin not supported on this processor.  */
7072117395Skan    return 0;
7073117395Skan
707490075Sobrien  /* If we got invalid arguments bail out before generating bad rtl.  */
707590075Sobrien  if (arg0 == error_mark_node
707690075Sobrien      || arg1 == error_mark_node
707790075Sobrien      || arg2 == error_mark_node)
7078117395Skan    return const0_rtx;
707990075Sobrien
7080169689Skan  if (icode == CODE_FOR_altivec_vsldoi_v4sf
7081169689Skan      || icode == CODE_FOR_altivec_vsldoi_v4si
7082169689Skan      || icode == CODE_FOR_altivec_vsldoi_v8hi
7083169689Skan      || icode == CODE_FOR_altivec_vsldoi_v16qi)
7084117395Skan    {
7085117395Skan      /* Only allow 4-bit unsigned literals.  */
7086169689Skan      STRIP_NOPS (arg2);
7087117395Skan      if (TREE_CODE (arg2) != INTEGER_CST
7088117395Skan	  || TREE_INT_CST_LOW (arg2) & ~0xf)
7089117395Skan	{
7090117395Skan	  error ("argument 3 must be a 4-bit unsigned literal");
7091117395Skan	  return const0_rtx;
7092117395Skan	}
7093117395Skan    }
7094117395Skan
709590075Sobrien  if (target == 0
709690075Sobrien      || GET_MODE (target) != tmode
709790075Sobrien      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
709890075Sobrien    target = gen_reg_rtx (tmode);
709990075Sobrien
710090075Sobrien  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
710190075Sobrien    op0 = copy_to_mode_reg (mode0, op0);
710290075Sobrien  if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
710390075Sobrien    op1 = copy_to_mode_reg (mode1, op1);
710490075Sobrien  if (! (*insn_data[icode].operand[3].predicate) (op2, mode2))
710590075Sobrien    op2 = copy_to_mode_reg (mode2, op2);
710690075Sobrien
710790075Sobrien  pat = GEN_FCN (icode) (target, op0, op1, op2);
710890075Sobrien  if (! pat)
710990075Sobrien    return 0;
711090075Sobrien  emit_insn (pat);
711190075Sobrien
711290075Sobrien  return target;
711390075Sobrien}
7114117395Skan
7115117395Skan/* Expand the lvx builtins.  */
711690075Sobrienstatic rtx
7117132718Skanaltivec_expand_ld_builtin (tree exp, rtx target, bool *expandedp)
711890075Sobrien{
711990075Sobrien  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
712090075Sobrien  tree arglist = TREE_OPERAND (exp, 1);
712190075Sobrien  unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
7122117395Skan  tree arg0;
7123117395Skan  enum machine_mode tmode, mode0;
7124117395Skan  rtx pat, op0;
7125117395Skan  enum insn_code icode;
7126117395Skan
712790075Sobrien  switch (fcode)
712890075Sobrien    {
712990075Sobrien    case ALTIVEC_BUILTIN_LD_INTERNAL_16qi:
7130169689Skan      icode = CODE_FOR_altivec_lvx_v16qi;
7131117395Skan      break;
7132117395Skan    case ALTIVEC_BUILTIN_LD_INTERNAL_8hi:
7133169689Skan      icode = CODE_FOR_altivec_lvx_v8hi;
7134117395Skan      break;
7135117395Skan    case ALTIVEC_BUILTIN_LD_INTERNAL_4si:
7136169689Skan      icode = CODE_FOR_altivec_lvx_v4si;
7137117395Skan      break;
7138117395Skan    case ALTIVEC_BUILTIN_LD_INTERNAL_4sf:
7139169689Skan      icode = CODE_FOR_altivec_lvx_v4sf;
7140117395Skan      break;
7141117395Skan    default:
7142117395Skan      *expandedp = false;
7143117395Skan      return NULL_RTX;
7144117395Skan    }
714590075Sobrien
7146117395Skan  *expandedp = true;
714790075Sobrien
7148117395Skan  arg0 = TREE_VALUE (arglist);
7149169689Skan  op0 = expand_normal (arg0);
7150117395Skan  tmode = insn_data[icode].operand[0].mode;
7151117395Skan  mode0 = insn_data[icode].operand[1].mode;
715290075Sobrien
7153117395Skan  if (target == 0
7154117395Skan      || GET_MODE (target) != tmode
7155117395Skan      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
7156117395Skan    target = gen_reg_rtx (tmode);
715790075Sobrien
7158117395Skan  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
7159117395Skan    op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
716090075Sobrien
7161117395Skan  pat = GEN_FCN (icode) (target, op0);
7162117395Skan  if (! pat)
7163117395Skan    return 0;
7164117395Skan  emit_insn (pat);
7165117395Skan  return target;
7166117395Skan}
716790075Sobrien
7168117395Skan/* Expand the stvx builtins.  */
7169117395Skanstatic rtx
7170169689Skanaltivec_expand_st_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
7171132718Skan			   bool *expandedp)
7172117395Skan{
7173117395Skan  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
7174117395Skan  tree arglist = TREE_OPERAND (exp, 1);
7175117395Skan  unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
7176117395Skan  tree arg0, arg1;
7177117395Skan  enum machine_mode mode0, mode1;
7178117395Skan  rtx pat, op0, op1;
7179117395Skan  enum insn_code icode;
718090075Sobrien
7181117395Skan  switch (fcode)
7182117395Skan    {
7183117395Skan    case ALTIVEC_BUILTIN_ST_INTERNAL_16qi:
7184169689Skan      icode = CODE_FOR_altivec_stvx_v16qi;
7185117395Skan      break;
7186117395Skan    case ALTIVEC_BUILTIN_ST_INTERNAL_8hi:
7187169689Skan      icode = CODE_FOR_altivec_stvx_v8hi;
7188117395Skan      break;
7189117395Skan    case ALTIVEC_BUILTIN_ST_INTERNAL_4si:
7190169689Skan      icode = CODE_FOR_altivec_stvx_v4si;
7191117395Skan      break;
7192117395Skan    case ALTIVEC_BUILTIN_ST_INTERNAL_4sf:
7193169689Skan      icode = CODE_FOR_altivec_stvx_v4sf;
7194117395Skan      break;
7195117395Skan    default:
7196117395Skan      *expandedp = false;
7197117395Skan      return NULL_RTX;
7198117395Skan    }
719990075Sobrien
7200117395Skan  arg0 = TREE_VALUE (arglist);
7201117395Skan  arg1 = TREE_VALUE (TREE_CHAIN (arglist));
7202169689Skan  op0 = expand_normal (arg0);
7203169689Skan  op1 = expand_normal (arg1);
7204117395Skan  mode0 = insn_data[icode].operand[0].mode;
7205117395Skan  mode1 = insn_data[icode].operand[1].mode;
720690075Sobrien
7207117395Skan  if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
7208117395Skan    op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
7209117395Skan  if (! (*insn_data[icode].operand[1].predicate) (op1, mode1))
7210117395Skan    op1 = copy_to_mode_reg (mode1, op1);
721190075Sobrien
7212117395Skan  pat = GEN_FCN (icode) (op0, op1);
7213117395Skan  if (pat)
7214117395Skan    emit_insn (pat);
721590075Sobrien
7216117395Skan  *expandedp = true;
7217117395Skan  return NULL_RTX;
7218117395Skan}
721990075Sobrien
7220117395Skan/* Expand the dst builtins.  */
7221117395Skanstatic rtx
7222169689Skanaltivec_expand_dst_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
7223132718Skan			    bool *expandedp)
7224117395Skan{
7225117395Skan  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
7226117395Skan  tree arglist = TREE_OPERAND (exp, 1);
7227117395Skan  unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
7228117395Skan  tree arg0, arg1, arg2;
7229117395Skan  enum machine_mode mode0, mode1, mode2;
7230117395Skan  rtx pat, op0, op1, op2;
7231117395Skan  struct builtin_description *d;
7232117395Skan  size_t i;
723390075Sobrien
7234117395Skan  *expandedp = false;
723590075Sobrien
7236117395Skan  /* Handle DST variants.  */
7237117395Skan  d = (struct builtin_description *) bdesc_dst;
7238117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_dst); i++, d++)
7239117395Skan    if (d->code == fcode)
7240117395Skan      {
7241117395Skan	arg0 = TREE_VALUE (arglist);
7242117395Skan	arg1 = TREE_VALUE (TREE_CHAIN (arglist));
7243117395Skan	arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
7244169689Skan	op0 = expand_normal (arg0);
7245169689Skan	op1 = expand_normal (arg1);
7246169689Skan	op2 = expand_normal (arg2);
7247117395Skan	mode0 = insn_data[d->icode].operand[0].mode;
7248117395Skan	mode1 = insn_data[d->icode].operand[1].mode;
7249117395Skan	mode2 = insn_data[d->icode].operand[2].mode;
725090075Sobrien
7251117395Skan	/* Invalid arguments, bail out before generating bad rtl.  */
7252117395Skan	if (arg0 == error_mark_node
7253117395Skan	    || arg1 == error_mark_node
7254117395Skan	    || arg2 == error_mark_node)
7255117395Skan	  return const0_rtx;
725690075Sobrien
7257146895Skan	*expandedp = true;
7258146895Skan	STRIP_NOPS (arg2);
7259117395Skan	if (TREE_CODE (arg2) != INTEGER_CST
7260117395Skan	    || TREE_INT_CST_LOW (arg2) & ~0x3)
7261117395Skan	  {
7262169689Skan	    error ("argument to %qs must be a 2-bit unsigned literal", d->name);
7263117395Skan	    return const0_rtx;
7264117395Skan	  }
726590075Sobrien
7266117395Skan	if (! (*insn_data[d->icode].operand[0].predicate) (op0, mode0))
7267169689Skan	  op0 = copy_to_mode_reg (Pmode, op0);
7268117395Skan	if (! (*insn_data[d->icode].operand[1].predicate) (op1, mode1))
7269117395Skan	  op1 = copy_to_mode_reg (mode1, op1);
727090075Sobrien
7271117395Skan	pat = GEN_FCN (d->icode) (op0, op1, op2);
7272117395Skan	if (pat != 0)
7273117395Skan	  emit_insn (pat);
727490075Sobrien
7275117395Skan	return NULL_RTX;
7276117395Skan      }
727790075Sobrien
7278117395Skan  return NULL_RTX;
7279117395Skan}
728090075Sobrien
7281169689Skan/* Expand vec_init builtin.  */
7282169689Skanstatic rtx
7283169689Skanaltivec_expand_vec_init_builtin (tree type, tree arglist, rtx target)
7284169689Skan{
7285169689Skan  enum machine_mode tmode = TYPE_MODE (type);
7286169689Skan  enum machine_mode inner_mode = GET_MODE_INNER (tmode);
7287169689Skan  int i, n_elt = GET_MODE_NUNITS (tmode);
7288169689Skan  rtvec v = rtvec_alloc (n_elt);
7289169689Skan
7290169689Skan  gcc_assert (VECTOR_MODE_P (tmode));
7291169689Skan
7292169689Skan  for (i = 0; i < n_elt; ++i, arglist = TREE_CHAIN (arglist))
7293169689Skan    {
7294169689Skan      rtx x = expand_normal (TREE_VALUE (arglist));
7295169689Skan      RTVEC_ELT (v, i) = gen_lowpart (inner_mode, x);
7296169689Skan    }
7297169689Skan
7298169689Skan  gcc_assert (arglist == NULL);
7299169689Skan
7300169689Skan  if (!target || !register_operand (target, tmode))
7301169689Skan    target = gen_reg_rtx (tmode);
7302169689Skan
7303169689Skan  rs6000_expand_vector_init (target, gen_rtx_PARALLEL (tmode, v));
7304169689Skan  return target;
7305169689Skan}
7306169689Skan
7307169689Skan/* Return the integer constant in ARG.  Constrain it to be in the range
7308169689Skan   of the subparts of VEC_TYPE; issue an error if not.  */
7309169689Skan
7310169689Skanstatic int
7311169689Skanget_element_number (tree vec_type, tree arg)
7312169689Skan{
7313169689Skan  unsigned HOST_WIDE_INT elt, max = TYPE_VECTOR_SUBPARTS (vec_type) - 1;
7314169689Skan
7315169689Skan  if (!host_integerp (arg, 1)
7316169689Skan      || (elt = tree_low_cst (arg, 1), elt > max))
7317169689Skan    {
7318169689Skan      error ("selector must be an integer constant in the range 0..%wi", max);
7319169689Skan      return 0;
7320169689Skan    }
7321169689Skan
7322169689Skan  return elt;
7323169689Skan}
7324169689Skan
7325169689Skan/* Expand vec_set builtin.  */
7326169689Skanstatic rtx
7327169689Skanaltivec_expand_vec_set_builtin (tree arglist)
7328169689Skan{
7329169689Skan  enum machine_mode tmode, mode1;
7330169689Skan  tree arg0, arg1, arg2;
7331169689Skan  int elt;
7332169689Skan  rtx op0, op1;
7333169689Skan
7334169689Skan  arg0 = TREE_VALUE (arglist);
7335169689Skan  arg1 = TREE_VALUE (TREE_CHAIN (arglist));
7336169689Skan  arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
7337169689Skan
7338169689Skan  tmode = TYPE_MODE (TREE_TYPE (arg0));
7339169689Skan  mode1 = TYPE_MODE (TREE_TYPE (TREE_TYPE (arg0)));
7340169689Skan  gcc_assert (VECTOR_MODE_P (tmode));
7341169689Skan
7342169689Skan  op0 = expand_expr (arg0, NULL_RTX, tmode, 0);
7343169689Skan  op1 = expand_expr (arg1, NULL_RTX, mode1, 0);
7344169689Skan  elt = get_element_number (TREE_TYPE (arg0), arg2);
7345169689Skan
7346169689Skan  if (GET_MODE (op1) != mode1 && GET_MODE (op1) != VOIDmode)
7347169689Skan    op1 = convert_modes (mode1, GET_MODE (op1), op1, true);
7348169689Skan
7349169689Skan  op0 = force_reg (tmode, op0);
7350169689Skan  op1 = force_reg (mode1, op1);
7351169689Skan
7352169689Skan  rs6000_expand_vector_set (op0, op1, elt);
7353169689Skan
7354169689Skan  return op0;
7355169689Skan}
7356169689Skan
7357169689Skan/* Expand vec_ext builtin.  */
7358169689Skanstatic rtx
7359169689Skanaltivec_expand_vec_ext_builtin (tree arglist, rtx target)
7360169689Skan{
7361169689Skan  enum machine_mode tmode, mode0;
7362169689Skan  tree arg0, arg1;
7363169689Skan  int elt;
7364169689Skan  rtx op0;
7365169689Skan
7366169689Skan  arg0 = TREE_VALUE (arglist);
7367169689Skan  arg1 = TREE_VALUE (TREE_CHAIN (arglist));
7368169689Skan
7369169689Skan  op0 = expand_normal (arg0);
7370169689Skan  elt = get_element_number (TREE_TYPE (arg0), arg1);
7371169689Skan
7372169689Skan  tmode = TYPE_MODE (TREE_TYPE (TREE_TYPE (arg0)));
7373169689Skan  mode0 = TYPE_MODE (TREE_TYPE (arg0));
7374169689Skan  gcc_assert (VECTOR_MODE_P (mode0));
7375169689Skan
7376169689Skan  op0 = force_reg (mode0, op0);
7377169689Skan
7378169689Skan  if (optimize || !target || !register_operand (target, tmode))
7379169689Skan    target = gen_reg_rtx (tmode);
7380169689Skan
7381169689Skan  rs6000_expand_vector_extract (target, op0, elt);
7382169689Skan
7383169689Skan  return target;
7384169689Skan}
7385169689Skan
7386117395Skan/* Expand the builtin in EXP and store the result in TARGET.  Store
7387117395Skan   true in *EXPANDEDP if we found a builtin to expand.  */
7388117395Skanstatic rtx
7389132718Skanaltivec_expand_builtin (tree exp, rtx target, bool *expandedp)
7390117395Skan{
7391117395Skan  struct builtin_description *d;
7392117395Skan  struct builtin_description_predicates *dp;
7393117395Skan  size_t i;
7394117395Skan  enum insn_code icode;
7395117395Skan  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
7396117395Skan  tree arglist = TREE_OPERAND (exp, 1);
7397117395Skan  tree arg0;
7398117395Skan  rtx op0, pat;
7399117395Skan  enum machine_mode tmode, mode0;
7400117395Skan  unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
740190075Sobrien
7402169689Skan  if (fcode >= ALTIVEC_BUILTIN_OVERLOADED_FIRST
7403169689Skan      && fcode <= ALTIVEC_BUILTIN_OVERLOADED_LAST)
7404169689Skan    {
7405169689Skan      *expandedp = true;
7406169689Skan      error ("unresolved overload for Altivec builtin %qF", fndecl);
7407169689Skan      return const0_rtx;
7408169689Skan    }
7409169689Skan
7410117395Skan  target = altivec_expand_ld_builtin (exp, target, expandedp);
7411117395Skan  if (*expandedp)
7412117395Skan    return target;
741390075Sobrien
7414117395Skan  target = altivec_expand_st_builtin (exp, target, expandedp);
7415117395Skan  if (*expandedp)
7416117395Skan    return target;
741790075Sobrien
7418117395Skan  target = altivec_expand_dst_builtin (exp, target, expandedp);
7419117395Skan  if (*expandedp)
7420117395Skan    return target;
742190075Sobrien
7422117395Skan  *expandedp = true;
742390075Sobrien
7424117395Skan  switch (fcode)
7425117395Skan    {
742690075Sobrien    case ALTIVEC_BUILTIN_STVX:
742790075Sobrien      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvx, arglist);
742890075Sobrien    case ALTIVEC_BUILTIN_STVEBX:
742990075Sobrien      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvebx, arglist);
743090075Sobrien    case ALTIVEC_BUILTIN_STVEHX:
743190075Sobrien      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvehx, arglist);
743290075Sobrien    case ALTIVEC_BUILTIN_STVEWX:
743390075Sobrien      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvewx, arglist);
743490075Sobrien    case ALTIVEC_BUILTIN_STVXL:
743590075Sobrien      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvxl, arglist);
7436117395Skan
743790075Sobrien    case ALTIVEC_BUILTIN_MFVSCR:
743890075Sobrien      icode = CODE_FOR_altivec_mfvscr;
743990075Sobrien      tmode = insn_data[icode].operand[0].mode;
744090075Sobrien
744190075Sobrien      if (target == 0
744290075Sobrien	  || GET_MODE (target) != tmode
744390075Sobrien	  || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
744490075Sobrien	target = gen_reg_rtx (tmode);
7445169689Skan
744690075Sobrien      pat = GEN_FCN (icode) (target);
744790075Sobrien      if (! pat)
744890075Sobrien	return 0;
744990075Sobrien      emit_insn (pat);
745090075Sobrien      return target;
745190075Sobrien
745290075Sobrien    case ALTIVEC_BUILTIN_MTVSCR:
745390075Sobrien      icode = CODE_FOR_altivec_mtvscr;
745490075Sobrien      arg0 = TREE_VALUE (arglist);
7455169689Skan      op0 = expand_normal (arg0);
745690075Sobrien      mode0 = insn_data[icode].operand[0].mode;
745790075Sobrien
745890075Sobrien      /* If we got invalid arguments bail out before generating bad rtl.  */
745990075Sobrien      if (arg0 == error_mark_node)
7460117395Skan	return const0_rtx;
746190075Sobrien
746290075Sobrien      if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
746390075Sobrien	op0 = copy_to_mode_reg (mode0, op0);
746490075Sobrien
746590075Sobrien      pat = GEN_FCN (icode) (op0);
746690075Sobrien      if (pat)
746790075Sobrien	emit_insn (pat);
746890075Sobrien      return NULL_RTX;
7469117395Skan
747090075Sobrien    case ALTIVEC_BUILTIN_DSSALL:
747190075Sobrien      emit_insn (gen_altivec_dssall ());
747290075Sobrien      return NULL_RTX;
747390075Sobrien
747490075Sobrien    case ALTIVEC_BUILTIN_DSS:
747590075Sobrien      icode = CODE_FOR_altivec_dss;
747690075Sobrien      arg0 = TREE_VALUE (arglist);
7477146895Skan      STRIP_NOPS (arg0);
7478169689Skan      op0 = expand_normal (arg0);
747990075Sobrien      mode0 = insn_data[icode].operand[0].mode;
748090075Sobrien
748190075Sobrien      /* If we got invalid arguments bail out before generating bad rtl.  */
748290075Sobrien      if (arg0 == error_mark_node)
7483117395Skan	return const0_rtx;
748490075Sobrien
7485117395Skan      if (TREE_CODE (arg0) != INTEGER_CST
7486117395Skan	  || TREE_INT_CST_LOW (arg0) & ~0x3)
7487117395Skan	{
7488117395Skan	  error ("argument to dss must be a 2-bit unsigned literal");
7489117395Skan	  return const0_rtx;
7490117395Skan	}
7491117395Skan
749290075Sobrien      if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
749390075Sobrien	op0 = copy_to_mode_reg (mode0, op0);
749490075Sobrien
749590075Sobrien      emit_insn (gen_altivec_dss (op0));
749690075Sobrien      return NULL_RTX;
7497146895Skan
7498169689Skan    case ALTIVEC_BUILTIN_VEC_INIT_V4SI:
7499169689Skan    case ALTIVEC_BUILTIN_VEC_INIT_V8HI:
7500169689Skan    case ALTIVEC_BUILTIN_VEC_INIT_V16QI:
7501169689Skan    case ALTIVEC_BUILTIN_VEC_INIT_V4SF:
7502169689Skan      return altivec_expand_vec_init_builtin (TREE_TYPE (exp), arglist, target);
7503146895Skan
7504169689Skan    case ALTIVEC_BUILTIN_VEC_SET_V4SI:
7505169689Skan    case ALTIVEC_BUILTIN_VEC_SET_V8HI:
7506169689Skan    case ALTIVEC_BUILTIN_VEC_SET_V16QI:
7507169689Skan    case ALTIVEC_BUILTIN_VEC_SET_V4SF:
7508169689Skan      return altivec_expand_vec_set_builtin (arglist);
7509169689Skan
7510169689Skan    case ALTIVEC_BUILTIN_VEC_EXT_V4SI:
7511169689Skan    case ALTIVEC_BUILTIN_VEC_EXT_V8HI:
7512169689Skan    case ALTIVEC_BUILTIN_VEC_EXT_V16QI:
7513169689Skan    case ALTIVEC_BUILTIN_VEC_EXT_V4SF:
7514169689Skan      return altivec_expand_vec_ext_builtin (arglist, target);
7515169689Skan
7516169689Skan    default:
7517169689Skan      break;
7518169689Skan      /* Fall through.  */
751990075Sobrien    }
752090075Sobrien
752196263Sobrien  /* Expand abs* operations.  */
752296263Sobrien  d = (struct builtin_description *) bdesc_abs;
7523117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_abs); i++, d++)
752496263Sobrien    if (d->code == fcode)
752596263Sobrien      return altivec_expand_abs_builtin (d->icode, arglist, target);
752696263Sobrien
752796263Sobrien  /* Expand the AltiVec predicates.  */
752896263Sobrien  dp = (struct builtin_description_predicates *) bdesc_altivec_preds;
7529117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_altivec_preds); i++, dp++)
753096263Sobrien    if (dp->code == fcode)
7531169689Skan      return altivec_expand_predicate_builtin (dp->icode, dp->opcode,
7532169689Skan					       arglist, target);
753396263Sobrien
753490075Sobrien  /* LV* are funky.  We initialized them differently.  */
753590075Sobrien  switch (fcode)
753690075Sobrien    {
753790075Sobrien    case ALTIVEC_BUILTIN_LVSL:
7538132718Skan      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvsl,
7539169689Skan					arglist, target);
754090075Sobrien    case ALTIVEC_BUILTIN_LVSR:
7541132718Skan      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvsr,
7542169689Skan					arglist, target);
754390075Sobrien    case ALTIVEC_BUILTIN_LVEBX:
7544132718Skan      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvebx,
7545169689Skan					arglist, target);
754690075Sobrien    case ALTIVEC_BUILTIN_LVEHX:
7547132718Skan      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvehx,
7548169689Skan					arglist, target);
754990075Sobrien    case ALTIVEC_BUILTIN_LVEWX:
7550132718Skan      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvewx,
7551169689Skan					arglist, target);
755290075Sobrien    case ALTIVEC_BUILTIN_LVXL:
7553132718Skan      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvxl,
7554169689Skan					arglist, target);
755590075Sobrien    case ALTIVEC_BUILTIN_LVX:
7556132718Skan      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvx,
7557169689Skan					arglist, target);
755890075Sobrien    default:
755990075Sobrien      break;
756090075Sobrien      /* Fall through.  */
756190075Sobrien    }
756290075Sobrien
7563117395Skan  *expandedp = false;
7564117395Skan  return NULL_RTX;
7565117395Skan}
7566117395Skan
7567117395Skan/* Binops that need to be initialized manually, but can be expanded
7568117395Skan   automagically by rs6000_expand_binop_builtin.  */
7569117395Skanstatic struct builtin_description bdesc_2arg_spe[] =
7570117395Skan{
7571117395Skan  { 0, CODE_FOR_spe_evlddx, "__builtin_spe_evlddx", SPE_BUILTIN_EVLDDX },
7572117395Skan  { 0, CODE_FOR_spe_evldwx, "__builtin_spe_evldwx", SPE_BUILTIN_EVLDWX },
7573117395Skan  { 0, CODE_FOR_spe_evldhx, "__builtin_spe_evldhx", SPE_BUILTIN_EVLDHX },
7574117395Skan  { 0, CODE_FOR_spe_evlwhex, "__builtin_spe_evlwhex", SPE_BUILTIN_EVLWHEX },
7575117395Skan  { 0, CODE_FOR_spe_evlwhoux, "__builtin_spe_evlwhoux", SPE_BUILTIN_EVLWHOUX },
7576117395Skan  { 0, CODE_FOR_spe_evlwhosx, "__builtin_spe_evlwhosx", SPE_BUILTIN_EVLWHOSX },
7577117395Skan  { 0, CODE_FOR_spe_evlwwsplatx, "__builtin_spe_evlwwsplatx", SPE_BUILTIN_EVLWWSPLATX },
7578117395Skan  { 0, CODE_FOR_spe_evlwhsplatx, "__builtin_spe_evlwhsplatx", SPE_BUILTIN_EVLWHSPLATX },
7579117395Skan  { 0, CODE_FOR_spe_evlhhesplatx, "__builtin_spe_evlhhesplatx", SPE_BUILTIN_EVLHHESPLATX },
7580117395Skan  { 0, CODE_FOR_spe_evlhhousplatx, "__builtin_spe_evlhhousplatx", SPE_BUILTIN_EVLHHOUSPLATX },
7581117395Skan  { 0, CODE_FOR_spe_evlhhossplatx, "__builtin_spe_evlhhossplatx", SPE_BUILTIN_EVLHHOSSPLATX },
7582117395Skan  { 0, CODE_FOR_spe_evldd, "__builtin_spe_evldd", SPE_BUILTIN_EVLDD },
7583117395Skan  { 0, CODE_FOR_spe_evldw, "__builtin_spe_evldw", SPE_BUILTIN_EVLDW },
7584117395Skan  { 0, CODE_FOR_spe_evldh, "__builtin_spe_evldh", SPE_BUILTIN_EVLDH },
7585117395Skan  { 0, CODE_FOR_spe_evlwhe, "__builtin_spe_evlwhe", SPE_BUILTIN_EVLWHE },
7586117395Skan  { 0, CODE_FOR_spe_evlwhou, "__builtin_spe_evlwhou", SPE_BUILTIN_EVLWHOU },
7587117395Skan  { 0, CODE_FOR_spe_evlwhos, "__builtin_spe_evlwhos", SPE_BUILTIN_EVLWHOS },
7588117395Skan  { 0, CODE_FOR_spe_evlwwsplat, "__builtin_spe_evlwwsplat", SPE_BUILTIN_EVLWWSPLAT },
7589117395Skan  { 0, CODE_FOR_spe_evlwhsplat, "__builtin_spe_evlwhsplat", SPE_BUILTIN_EVLWHSPLAT },
7590117395Skan  { 0, CODE_FOR_spe_evlhhesplat, "__builtin_spe_evlhhesplat", SPE_BUILTIN_EVLHHESPLAT },
7591117395Skan  { 0, CODE_FOR_spe_evlhhousplat, "__builtin_spe_evlhhousplat", SPE_BUILTIN_EVLHHOUSPLAT },
7592117395Skan  { 0, CODE_FOR_spe_evlhhossplat, "__builtin_spe_evlhhossplat", SPE_BUILTIN_EVLHHOSSPLAT }
7593117395Skan};
7594117395Skan
7595117395Skan/* Expand the builtin in EXP and store the result in TARGET.  Store
7596117395Skan   true in *EXPANDEDP if we found a builtin to expand.
7597117395Skan
7598117395Skan   This expands the SPE builtins that are not simple unary and binary
7599117395Skan   operations.  */
7600117395Skanstatic rtx
7601132718Skanspe_expand_builtin (tree exp, rtx target, bool *expandedp)
7602117395Skan{
7603117395Skan  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
7604117395Skan  tree arglist = TREE_OPERAND (exp, 1);
7605117395Skan  tree arg1, arg0;
7606117395Skan  unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
7607117395Skan  enum insn_code icode;
7608117395Skan  enum machine_mode tmode, mode0;
7609117395Skan  rtx pat, op0;
7610117395Skan  struct builtin_description *d;
7611117395Skan  size_t i;
7612117395Skan
7613117395Skan  *expandedp = true;
7614117395Skan
7615117395Skan  /* Syntax check for a 5-bit unsigned immediate.  */
7616117395Skan  switch (fcode)
7617117395Skan    {
7618117395Skan    case SPE_BUILTIN_EVSTDD:
7619117395Skan    case SPE_BUILTIN_EVSTDH:
7620117395Skan    case SPE_BUILTIN_EVSTDW:
7621117395Skan    case SPE_BUILTIN_EVSTWHE:
7622117395Skan    case SPE_BUILTIN_EVSTWHO:
7623117395Skan    case SPE_BUILTIN_EVSTWWE:
7624117395Skan    case SPE_BUILTIN_EVSTWWO:
7625117395Skan      arg1 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
7626117395Skan      if (TREE_CODE (arg1) != INTEGER_CST
7627117395Skan	  || TREE_INT_CST_LOW (arg1) & ~0x1f)
7628117395Skan	{
7629117395Skan	  error ("argument 2 must be a 5-bit unsigned literal");
7630117395Skan	  return const0_rtx;
7631117395Skan	}
7632117395Skan      break;
7633117395Skan    default:
7634117395Skan      break;
7635117395Skan    }
7636117395Skan
7637132718Skan  /* The evsplat*i instructions are not quite generic.  */
7638132718Skan  switch (fcode)
7639132718Skan    {
7640132718Skan    case SPE_BUILTIN_EVSPLATFI:
7641132718Skan      return rs6000_expand_unop_builtin (CODE_FOR_spe_evsplatfi,
7642132718Skan					 arglist, target);
7643132718Skan    case SPE_BUILTIN_EVSPLATI:
7644132718Skan      return rs6000_expand_unop_builtin (CODE_FOR_spe_evsplati,
7645132718Skan					 arglist, target);
7646132718Skan    default:
7647132718Skan      break;
7648132718Skan    }
7649132718Skan
7650117395Skan  d = (struct builtin_description *) bdesc_2arg_spe;
7651117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_2arg_spe); ++i, ++d)
765290075Sobrien    if (d->code == fcode)
7653117395Skan      return rs6000_expand_binop_builtin (d->icode, arglist, target);
765490075Sobrien
7655117395Skan  d = (struct builtin_description *) bdesc_spe_predicates;
7656117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_spe_predicates); ++i, ++d)
7657117395Skan    if (d->code == fcode)
7658117395Skan      return spe_expand_predicate_builtin (d->icode, arglist, target);
7659117395Skan
7660117395Skan  d = (struct builtin_description *) bdesc_spe_evsel;
7661117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_spe_evsel); ++i, ++d)
7662117395Skan    if (d->code == fcode)
7663117395Skan      return spe_expand_evsel_builtin (d->icode, arglist, target);
7664117395Skan
7665117395Skan  switch (fcode)
7666117395Skan    {
7667117395Skan    case SPE_BUILTIN_EVSTDDX:
7668132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstddx, arglist);
7669117395Skan    case SPE_BUILTIN_EVSTDHX:
7670132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstdhx, arglist);
7671117395Skan    case SPE_BUILTIN_EVSTDWX:
7672132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstdwx, arglist);
7673117395Skan    case SPE_BUILTIN_EVSTWHEX:
7674132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstwhex, arglist);
7675117395Skan    case SPE_BUILTIN_EVSTWHOX:
7676132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstwhox, arglist);
7677117395Skan    case SPE_BUILTIN_EVSTWWEX:
7678132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstwwex, arglist);
7679117395Skan    case SPE_BUILTIN_EVSTWWOX:
7680132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstwwox, arglist);
7681117395Skan    case SPE_BUILTIN_EVSTDD:
7682132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstdd, arglist);
7683117395Skan    case SPE_BUILTIN_EVSTDH:
7684132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstdh, arglist);
7685117395Skan    case SPE_BUILTIN_EVSTDW:
7686132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstdw, arglist);
7687117395Skan    case SPE_BUILTIN_EVSTWHE:
7688132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstwhe, arglist);
7689117395Skan    case SPE_BUILTIN_EVSTWHO:
7690132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstwho, arglist);
7691117395Skan    case SPE_BUILTIN_EVSTWWE:
7692132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstwwe, arglist);
7693117395Skan    case SPE_BUILTIN_EVSTWWO:
7694132718Skan      return spe_expand_stv_builtin (CODE_FOR_spe_evstwwo, arglist);
7695117395Skan    case SPE_BUILTIN_MFSPEFSCR:
7696117395Skan      icode = CODE_FOR_spe_mfspefscr;
7697117395Skan      tmode = insn_data[icode].operand[0].mode;
7698117395Skan
7699117395Skan      if (target == 0
7700117395Skan	  || GET_MODE (target) != tmode
7701117395Skan	  || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
7702117395Skan	target = gen_reg_rtx (tmode);
7703169689Skan
7704117395Skan      pat = GEN_FCN (icode) (target);
7705117395Skan      if (! pat)
7706117395Skan	return 0;
7707117395Skan      emit_insn (pat);
7708117395Skan      return target;
7709117395Skan    case SPE_BUILTIN_MTSPEFSCR:
7710117395Skan      icode = CODE_FOR_spe_mtspefscr;
7711117395Skan      arg0 = TREE_VALUE (arglist);
7712169689Skan      op0 = expand_normal (arg0);
7713117395Skan      mode0 = insn_data[icode].operand[0].mode;
7714117395Skan
7715117395Skan      if (arg0 == error_mark_node)
7716117395Skan	return const0_rtx;
7717117395Skan
7718117395Skan      if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
7719117395Skan	op0 = copy_to_mode_reg (mode0, op0);
7720117395Skan
7721117395Skan      pat = GEN_FCN (icode) (op0);
7722117395Skan      if (pat)
7723117395Skan	emit_insn (pat);
7724117395Skan      return NULL_RTX;
7725117395Skan    default:
7726117395Skan      break;
7727117395Skan    }
7728117395Skan
7729117395Skan  *expandedp = false;
773090075Sobrien  return NULL_RTX;
773190075Sobrien}
773290075Sobrien
7733117395Skanstatic rtx
7734132718Skanspe_expand_predicate_builtin (enum insn_code icode, tree arglist, rtx target)
7735117395Skan{
7736117395Skan  rtx pat, scratch, tmp;
7737117395Skan  tree form = TREE_VALUE (arglist);
7738117395Skan  tree arg0 = TREE_VALUE (TREE_CHAIN (arglist));
7739117395Skan  tree arg1 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
7740169689Skan  rtx op0 = expand_normal (arg0);
7741169689Skan  rtx op1 = expand_normal (arg1);
7742117395Skan  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
7743117395Skan  enum machine_mode mode1 = insn_data[icode].operand[2].mode;
7744117395Skan  int form_int;
7745117395Skan  enum rtx_code code;
7746117395Skan
7747117395Skan  if (TREE_CODE (form) != INTEGER_CST)
7748117395Skan    {
7749117395Skan      error ("argument 1 of __builtin_spe_predicate must be a constant");
7750117395Skan      return const0_rtx;
7751117395Skan    }
7752117395Skan  else
7753117395Skan    form_int = TREE_INT_CST_LOW (form);
7754117395Skan
7755169689Skan  gcc_assert (mode0 == mode1);
7756117395Skan
7757117395Skan  if (arg0 == error_mark_node || arg1 == error_mark_node)
7758117395Skan    return const0_rtx;
7759117395Skan
7760117395Skan  if (target == 0
7761117395Skan      || GET_MODE (target) != SImode
7762117395Skan      || ! (*insn_data[icode].operand[0].predicate) (target, SImode))
7763117395Skan    target = gen_reg_rtx (SImode);
7764117395Skan
7765117395Skan  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
7766117395Skan    op0 = copy_to_mode_reg (mode0, op0);
7767117395Skan  if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
7768117395Skan    op1 = copy_to_mode_reg (mode1, op1);
7769117395Skan
7770117395Skan  scratch = gen_reg_rtx (CCmode);
7771117395Skan
7772117395Skan  pat = GEN_FCN (icode) (scratch, op0, op1);
7773117395Skan  if (! pat)
7774117395Skan    return const0_rtx;
7775117395Skan  emit_insn (pat);
7776117395Skan
7777117395Skan  /* There are 4 variants for each predicate: _any_, _all_, _upper_,
7778117395Skan     _lower_.  We use one compare, but look in different bits of the
7779117395Skan     CR for each variant.
7780117395Skan
7781117395Skan     There are 2 elements in each SPE simd type (upper/lower).  The CR
7782117395Skan     bits are set as follows:
7783117395Skan
7784117395Skan     BIT0  | BIT 1  | BIT 2   | BIT 3
7785117395Skan     U     |   L    | (U | L) | (U & L)
7786117395Skan
7787117395Skan     So, for an "all" relationship, BIT 3 would be set.
7788117395Skan     For an "any" relationship, BIT 2 would be set.  Etc.
7789117395Skan
7790117395Skan     Following traditional nomenclature, these bits map to:
7791117395Skan
7792117395Skan     BIT0  | BIT 1  | BIT 2   | BIT 3
7793117395Skan     LT    | GT     | EQ      | OV
7794117395Skan
7795117395Skan     Later, we will generate rtl to look in the LT/EQ/EQ/OV bits.
7796117395Skan  */
7797117395Skan
7798117395Skan  switch (form_int)
7799117395Skan    {
7800117395Skan      /* All variant.  OV bit.  */
7801117395Skan    case 0:
7802117395Skan      /* We need to get to the OV bit, which is the ORDERED bit.  We
7803117395Skan	 could generate (ordered:SI (reg:CC xx) (const_int 0)), but
7804169689Skan	 that's ugly and will make validate_condition_mode die.
7805117395Skan	 So let's just use another pattern.  */
7806117395Skan      emit_insn (gen_move_from_CR_ov_bit (target, scratch));
7807117395Skan      return target;
7808117395Skan      /* Any variant.  EQ bit.  */
7809117395Skan    case 1:
7810117395Skan      code = EQ;
7811117395Skan      break;
7812117395Skan      /* Upper variant.  LT bit.  */
7813117395Skan    case 2:
7814117395Skan      code = LT;
7815117395Skan      break;
7816117395Skan      /* Lower variant.  GT bit.  */
7817117395Skan    case 3:
7818117395Skan      code = GT;
7819117395Skan      break;
7820117395Skan    default:
7821117395Skan      error ("argument 1 of __builtin_spe_predicate is out of range");
7822117395Skan      return const0_rtx;
7823117395Skan    }
7824117395Skan
7825117395Skan  tmp = gen_rtx_fmt_ee (code, SImode, scratch, const0_rtx);
7826117395Skan  emit_move_insn (target, tmp);
7827117395Skan
7828117395Skan  return target;
7829117395Skan}
7830117395Skan
7831117395Skan/* The evsel builtins look like this:
7832117395Skan
7833117395Skan     e = __builtin_spe_evsel_OP (a, b, c, d);
7834117395Skan
7835117395Skan   and work like this:
7836117395Skan
7837117395Skan     e[upper] = a[upper] *OP* b[upper] ? c[upper] : d[upper];
7838117395Skan     e[lower] = a[lower] *OP* b[lower] ? c[lower] : d[lower];
7839117395Skan*/
7840117395Skan
7841117395Skanstatic rtx
7842132718Skanspe_expand_evsel_builtin (enum insn_code icode, tree arglist, rtx target)
7843117395Skan{
7844117395Skan  rtx pat, scratch;
7845117395Skan  tree arg0 = TREE_VALUE (arglist);
7846117395Skan  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
7847117395Skan  tree arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
7848117395Skan  tree arg3 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (arglist))));
7849169689Skan  rtx op0 = expand_normal (arg0);
7850169689Skan  rtx op1 = expand_normal (arg1);
7851169689Skan  rtx op2 = expand_normal (arg2);
7852169689Skan  rtx op3 = expand_normal (arg3);
7853117395Skan  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
7854117395Skan  enum machine_mode mode1 = insn_data[icode].operand[2].mode;
7855117395Skan
7856169689Skan  gcc_assert (mode0 == mode1);
7857117395Skan
7858117395Skan  if (arg0 == error_mark_node || arg1 == error_mark_node
7859117395Skan      || arg2 == error_mark_node || arg3 == error_mark_node)
7860117395Skan    return const0_rtx;
7861117395Skan
7862117395Skan  if (target == 0
7863117395Skan      || GET_MODE (target) != mode0
7864117395Skan      || ! (*insn_data[icode].operand[0].predicate) (target, mode0))
7865117395Skan    target = gen_reg_rtx (mode0);
7866117395Skan
7867117395Skan  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
7868117395Skan    op0 = copy_to_mode_reg (mode0, op0);
7869117395Skan  if (! (*insn_data[icode].operand[1].predicate) (op1, mode1))
7870117395Skan    op1 = copy_to_mode_reg (mode0, op1);
7871117395Skan  if (! (*insn_data[icode].operand[1].predicate) (op2, mode1))
7872117395Skan    op2 = copy_to_mode_reg (mode0, op2);
7873117395Skan  if (! (*insn_data[icode].operand[1].predicate) (op3, mode1))
7874117395Skan    op3 = copy_to_mode_reg (mode0, op3);
7875117395Skan
7876117395Skan  /* Generate the compare.  */
7877117395Skan  scratch = gen_reg_rtx (CCmode);
7878117395Skan  pat = GEN_FCN (icode) (scratch, op0, op1);
7879117395Skan  if (! pat)
7880117395Skan    return const0_rtx;
7881117395Skan  emit_insn (pat);
7882117395Skan
7883117395Skan  if (mode0 == V2SImode)
7884117395Skan    emit_insn (gen_spe_evsel (target, op2, op3, scratch));
7885117395Skan  else
7886117395Skan    emit_insn (gen_spe_evsel_fs (target, op2, op3, scratch));
7887117395Skan
7888117395Skan  return target;
7889117395Skan}
7890117395Skan
789190075Sobrien/* Expand an expression EXP that calls a built-in function,
789290075Sobrien   with result going to TARGET if that's convenient
789390075Sobrien   (and in mode MODE if that's convenient).
789490075Sobrien   SUBTARGET may be used as the target for computing one of EXP's operands.
789590075Sobrien   IGNORE is nonzero if the value is to be ignored.  */
789690075Sobrien
789790075Sobrienstatic rtx
7898132718Skanrs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
7899169689Skan		       enum machine_mode mode ATTRIBUTE_UNUSED,
7900169689Skan		       int ignore ATTRIBUTE_UNUSED)
790190075Sobrien{
7902117395Skan  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
7903117395Skan  tree arglist = TREE_OPERAND (exp, 1);
7904117395Skan  unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
7905117395Skan  struct builtin_description *d;
7906117395Skan  size_t i;
7907117395Skan  rtx ret;
7908117395Skan  bool success;
7909169689Skan
7910169689Skan  if (fcode == ALTIVEC_BUILTIN_MASK_FOR_LOAD
7911169689Skan      || fcode == ALTIVEC_BUILTIN_MASK_FOR_STORE)
7912169689Skan    {
7913169689Skan      int icode = (int) CODE_FOR_altivec_lvsr;
7914169689Skan      enum machine_mode tmode = insn_data[icode].operand[0].mode;
7915169689Skan      enum machine_mode mode = insn_data[icode].operand[1].mode;
7916169689Skan      tree arg;
7917169689Skan      rtx op, addr, pat;
7918169689Skan
7919169689Skan      gcc_assert (TARGET_ALTIVEC);
7920169689Skan
7921169689Skan      arg = TREE_VALUE (arglist);
7922169689Skan      gcc_assert (TREE_CODE (TREE_TYPE (arg)) == POINTER_TYPE);
7923169689Skan      op = expand_expr (arg, NULL_RTX, Pmode, EXPAND_NORMAL);
7924169689Skan      addr = memory_address (mode, op);
7925169689Skan      if (fcode == ALTIVEC_BUILTIN_MASK_FOR_STORE)
7926169689Skan	op = addr;
7927169689Skan      else
7928169689Skan	{
7929169689Skan	  /* For the load case need to negate the address.  */
7930169689Skan	  op = gen_reg_rtx (GET_MODE (addr));
7931169689Skan	  emit_insn (gen_rtx_SET (VOIDmode, op,
7932169689Skan			 gen_rtx_NEG (GET_MODE (addr), addr)));
7933169689Skan	}
7934169689Skan      op = gen_rtx_MEM (mode, op);
7935169689Skan
7936169689Skan      if (target == 0
7937169689Skan	  || GET_MODE (target) != tmode
7938169689Skan	  || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
7939169689Skan	target = gen_reg_rtx (tmode);
7940169689Skan
7941169689Skan      /*pat = gen_altivec_lvsr (target, op);*/
7942169689Skan      pat = GEN_FCN (icode) (target, op);
7943169689Skan      if (!pat)
7944169689Skan	return 0;
7945169689Skan      emit_insn (pat);
7946169689Skan
7947169689Skan      return target;
7948169689Skan    }
7949169689Skan
795090075Sobrien  if (TARGET_ALTIVEC)
7951117395Skan    {
7952117395Skan      ret = altivec_expand_builtin (exp, target, &success);
795390075Sobrien
7954117395Skan      if (success)
7955117395Skan	return ret;
7956117395Skan    }
7957117395Skan  if (TARGET_SPE)
7958117395Skan    {
7959117395Skan      ret = spe_expand_builtin (exp, target, &success);
7960117395Skan
7961117395Skan      if (success)
7962117395Skan	return ret;
7963117395Skan    }
7964117395Skan
7965169689Skan  gcc_assert (TARGET_ALTIVEC || TARGET_SPE);
7966117395Skan
7967169689Skan  /* Handle simple unary operations.  */
7968169689Skan  d = (struct builtin_description *) bdesc_1arg;
7969169689Skan  for (i = 0; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
7970169689Skan    if (d->code == fcode)
7971169689Skan      return rs6000_expand_unop_builtin (d->icode, arglist, target);
7972117395Skan
7973169689Skan  /* Handle simple binary operations.  */
7974169689Skan  d = (struct builtin_description *) bdesc_2arg;
7975169689Skan  for (i = 0; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
7976169689Skan    if (d->code == fcode)
7977169689Skan      return rs6000_expand_binop_builtin (d->icode, arglist, target);
7978117395Skan
7979169689Skan  /* Handle simple ternary operations.  */
7980169689Skan  d = (struct builtin_description *) bdesc_3arg;
7981169689Skan  for (i = 0; i < ARRAY_SIZE  (bdesc_3arg); i++, d++)
7982169689Skan    if (d->code == fcode)
7983169689Skan      return rs6000_expand_ternop_builtin (d->icode, arglist, target);
7984169689Skan
7985169689Skan  gcc_unreachable ();
798690075Sobrien}
798790075Sobrien
7988169689Skanstatic tree
7989169689Skanbuild_opaque_vector_type (tree node, int nunits)
7990169689Skan{
7991169689Skan  node = copy_node (node);
7992169689Skan  TYPE_MAIN_VARIANT (node) = node;
7993169689Skan  return build_vector_type (node, nunits);
7994169689Skan}
7995169689Skan
799690075Sobrienstatic void
7997132718Skanrs6000_init_builtins (void)
799890075Sobrien{
7999169689Skan  V2SI_type_node = build_vector_type (intSI_type_node, 2);
8000169689Skan  V2SF_type_node = build_vector_type (float_type_node, 2);
8001169689Skan  V4HI_type_node = build_vector_type (intHI_type_node, 4);
8002169689Skan  V4SI_type_node = build_vector_type (intSI_type_node, 4);
8003169689Skan  V4SF_type_node = build_vector_type (float_type_node, 4);
8004169689Skan  V8HI_type_node = build_vector_type (intHI_type_node, 8);
8005169689Skan  V16QI_type_node = build_vector_type (intQI_type_node, 16);
8006169689Skan
8007169689Skan  unsigned_V16QI_type_node = build_vector_type (unsigned_intQI_type_node, 16);
8008169689Skan  unsigned_V8HI_type_node = build_vector_type (unsigned_intHI_type_node, 8);
8009169689Skan  unsigned_V4SI_type_node = build_vector_type (unsigned_intSI_type_node, 4);
8010169689Skan
8011169689Skan  opaque_V2SF_type_node = build_opaque_vector_type (float_type_node, 2);
8012169689Skan  opaque_V2SI_type_node = build_opaque_vector_type (intSI_type_node, 2);
8013132718Skan  opaque_p_V2SI_type_node = build_pointer_type (opaque_V2SI_type_node);
8014169689Skan  opaque_V4SI_type_node = copy_node (V4SI_type_node);
8015132718Skan
8016146895Skan  /* The 'vector bool ...' types must be kept distinct from 'vector unsigned ...'
8017169689Skan     types, especially in C++ land.  Similarly, 'vector pixel' is distinct from
8018169689Skan     'vector unsigned short'.  */
8019146895Skan
8020169689Skan  bool_char_type_node = build_distinct_type_copy (unsigned_intQI_type_node);
8021169689Skan  bool_short_type_node = build_distinct_type_copy (unsigned_intHI_type_node);
8022169689Skan  bool_int_type_node = build_distinct_type_copy (unsigned_intSI_type_node);
8023169689Skan  pixel_type_node = build_distinct_type_copy (unsigned_intHI_type_node);
8024146895Skan
8025169689Skan  long_integer_type_internal_node = long_integer_type_node;
8026169689Skan  long_unsigned_type_internal_node = long_unsigned_type_node;
8027169689Skan  intQI_type_internal_node = intQI_type_node;
8028169689Skan  uintQI_type_internal_node = unsigned_intQI_type_node;
8029169689Skan  intHI_type_internal_node = intHI_type_node;
8030169689Skan  uintHI_type_internal_node = unsigned_intHI_type_node;
8031169689Skan  intSI_type_internal_node = intSI_type_node;
8032169689Skan  uintSI_type_internal_node = unsigned_intSI_type_node;
8033169689Skan  float_type_internal_node = float_type_node;
8034169689Skan  void_type_internal_node = void_type_node;
8035169689Skan
8036146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
8037146895Skan					    get_identifier ("__bool char"),
8038146895Skan					    bool_char_type_node));
8039146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
8040146895Skan					    get_identifier ("__bool short"),
8041146895Skan					    bool_short_type_node));
8042146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
8043146895Skan					    get_identifier ("__bool int"),
8044146895Skan					    bool_int_type_node));
8045146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
8046146895Skan					    get_identifier ("__pixel"),
8047146895Skan					    pixel_type_node));
8048146895Skan
8049169689Skan  bool_V16QI_type_node = build_vector_type (bool_char_type_node, 16);
8050169689Skan  bool_V8HI_type_node = build_vector_type (bool_short_type_node, 8);
8051169689Skan  bool_V4SI_type_node = build_vector_type (bool_int_type_node, 4);
8052169689Skan  pixel_V8HI_type_node = build_vector_type (pixel_type_node, 8);
8053146895Skan
8054146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
8055146895Skan					    get_identifier ("__vector unsigned char"),
8056146895Skan					    unsigned_V16QI_type_node));
8057146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
8058146895Skan					    get_identifier ("__vector signed char"),
8059146895Skan					    V16QI_type_node));
8060146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
8061146895Skan					    get_identifier ("__vector __bool char"),
8062146895Skan					    bool_V16QI_type_node));
8063146895Skan
8064146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
8065146895Skan					    get_identifier ("__vector unsigned short"),
8066146895Skan					    unsigned_V8HI_type_node));
8067146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
8068146895Skan					    get_identifier ("__vector signed short"),
8069146895Skan					    V8HI_type_node));
8070146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
8071146895Skan					    get_identifier ("__vector __bool short"),
8072146895Skan					    bool_V8HI_type_node));
8073146895Skan
8074146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
8075146895Skan					    get_identifier ("__vector unsigned int"),
8076146895Skan					    unsigned_V4SI_type_node));
8077146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
8078146895Skan					    get_identifier ("__vector signed int"),
8079146895Skan					    V4SI_type_node));
8080146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
8081146895Skan					    get_identifier ("__vector __bool int"),
8082146895Skan					    bool_V4SI_type_node));
8083146895Skan
8084146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
8085146895Skan					    get_identifier ("__vector float"),
8086146895Skan					    V4SF_type_node));
8087146895Skan  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
8088146895Skan					    get_identifier ("__vector __pixel"),
8089146895Skan					    pixel_V8HI_type_node));
8090146895Skan
8091117395Skan  if (TARGET_SPE)
8092117395Skan    spe_init_builtins ();
809390075Sobrien  if (TARGET_ALTIVEC)
809490075Sobrien    altivec_init_builtins ();
8095117395Skan  if (TARGET_ALTIVEC || TARGET_SPE)
8096117395Skan    rs6000_common_init_builtins ();
8097169689Skan
8098169689Skan#if TARGET_XCOFF
8099169689Skan  /* AIX libm provides clog as __clog.  */
8100169689Skan  if (built_in_decls [BUILT_IN_CLOG])
8101169689Skan    set_user_assembler_name (built_in_decls [BUILT_IN_CLOG], "__clog");
8102169689Skan#endif
810390075Sobrien}
810490075Sobrien
8105117395Skan/* Search through a set of builtins and enable the mask bits.
8106117395Skan   DESC is an array of builtins.
8107132718Skan   SIZE is the total number of builtins.
8108117395Skan   START is the builtin enum at which to start.
8109117395Skan   END is the builtin enum at which to end.  */
811090075Sobrienstatic void
8111132718Skanenable_mask_for_builtins (struct builtin_description *desc, int size,
8112169689Skan			  enum rs6000_builtins start,
8113132718Skan			  enum rs6000_builtins end)
811490075Sobrien{
8115117395Skan  int i;
811690075Sobrien
8117117395Skan  for (i = 0; i < size; ++i)
8118117395Skan    if (desc[i].code == start)
8119117395Skan      break;
812090075Sobrien
8121117395Skan  if (i == size)
8122117395Skan    return;
812390075Sobrien
8124117395Skan  for (; i < size; ++i)
8125117395Skan    {
8126117395Skan      /* Flip all the bits on.  */
8127117395Skan      desc[i].mask = target_flags;
8128117395Skan      if (desc[i].code == end)
8129117395Skan	break;
8130117395Skan    }
8131117395Skan}
813290075Sobrien
8133117395Skanstatic void
8134132718Skanspe_init_builtins (void)
8135117395Skan{
8136117395Skan  tree endlink = void_list_node;
8137117395Skan  tree puint_type_node = build_pointer_type (unsigned_type_node);
8138117395Skan  tree pushort_type_node = build_pointer_type (short_unsigned_type_node);
8139117395Skan  struct builtin_description *d;
8140117395Skan  size_t i;
814190075Sobrien
8142117395Skan  tree v2si_ftype_4_v2si
8143117395Skan    = build_function_type
8144132718Skan    (opaque_V2SI_type_node,
8145132718Skan     tree_cons (NULL_TREE, opaque_V2SI_type_node,
8146132718Skan		tree_cons (NULL_TREE, opaque_V2SI_type_node,
8147132718Skan			   tree_cons (NULL_TREE, opaque_V2SI_type_node,
8148132718Skan				      tree_cons (NULL_TREE, opaque_V2SI_type_node,
8149117395Skan						 endlink)))));
815090075Sobrien
8151117395Skan  tree v2sf_ftype_4_v2sf
8152117395Skan    = build_function_type
8153132718Skan    (opaque_V2SF_type_node,
8154132718Skan     tree_cons (NULL_TREE, opaque_V2SF_type_node,
8155132718Skan		tree_cons (NULL_TREE, opaque_V2SF_type_node,
8156132718Skan			   tree_cons (NULL_TREE, opaque_V2SF_type_node,
8157132718Skan				      tree_cons (NULL_TREE, opaque_V2SF_type_node,
8158117395Skan						 endlink)))));
815990075Sobrien
8160117395Skan  tree int_ftype_int_v2si_v2si
8161117395Skan    = build_function_type
8162117395Skan    (integer_type_node,
8163117395Skan     tree_cons (NULL_TREE, integer_type_node,
8164132718Skan		tree_cons (NULL_TREE, opaque_V2SI_type_node,
8165132718Skan			   tree_cons (NULL_TREE, opaque_V2SI_type_node,
8166117395Skan				      endlink))));
816790075Sobrien
8168117395Skan  tree int_ftype_int_v2sf_v2sf
8169117395Skan    = build_function_type
8170117395Skan    (integer_type_node,
8171117395Skan     tree_cons (NULL_TREE, integer_type_node,
8172132718Skan		tree_cons (NULL_TREE, opaque_V2SF_type_node,
8173132718Skan			   tree_cons (NULL_TREE, opaque_V2SF_type_node,
8174117395Skan				      endlink))));
817590075Sobrien
8176117395Skan  tree void_ftype_v2si_puint_int
817790075Sobrien    = build_function_type (void_type_node,
8178132718Skan			   tree_cons (NULL_TREE, opaque_V2SI_type_node,
8179117395Skan				      tree_cons (NULL_TREE, puint_type_node,
818090075Sobrien						 tree_cons (NULL_TREE,
8181117395Skan							    integer_type_node,
818290075Sobrien							    endlink))));
818390075Sobrien
8184117395Skan  tree void_ftype_v2si_puint_char
818590075Sobrien    = build_function_type (void_type_node,
8186132718Skan			   tree_cons (NULL_TREE, opaque_V2SI_type_node,
8187117395Skan				      tree_cons (NULL_TREE, puint_type_node,
818890075Sobrien						 tree_cons (NULL_TREE,
8189117395Skan							    char_type_node,
819090075Sobrien							    endlink))));
819190075Sobrien
8192117395Skan  tree void_ftype_v2si_pv2si_int
819390075Sobrien    = build_function_type (void_type_node,
8194132718Skan			   tree_cons (NULL_TREE, opaque_V2SI_type_node,
8195132718Skan				      tree_cons (NULL_TREE, opaque_p_V2SI_type_node,
819690075Sobrien						 tree_cons (NULL_TREE,
8197117395Skan							    integer_type_node,
819890075Sobrien							    endlink))));
819990075Sobrien
8200117395Skan  tree void_ftype_v2si_pv2si_char
820190075Sobrien    = build_function_type (void_type_node,
8202132718Skan			   tree_cons (NULL_TREE, opaque_V2SI_type_node,
8203132718Skan				      tree_cons (NULL_TREE, opaque_p_V2SI_type_node,
820490075Sobrien						 tree_cons (NULL_TREE,
8205117395Skan							    char_type_node,
820690075Sobrien							    endlink))));
820790075Sobrien
8208117395Skan  tree void_ftype_int
820990075Sobrien    = build_function_type (void_type_node,
8210117395Skan			   tree_cons (NULL_TREE, integer_type_node, endlink));
821190075Sobrien
8212117395Skan  tree int_ftype_void
8213132718Skan    = build_function_type (integer_type_node, endlink);
821490075Sobrien
8215117395Skan  tree v2si_ftype_pv2si_int
8216132718Skan    = build_function_type (opaque_V2SI_type_node,
8217132718Skan			   tree_cons (NULL_TREE, opaque_p_V2SI_type_node,
8218117395Skan				      tree_cons (NULL_TREE, integer_type_node,
8219117395Skan						 endlink)));
8220117395Skan
8221117395Skan  tree v2si_ftype_puint_int
8222132718Skan    = build_function_type (opaque_V2SI_type_node,
8223117395Skan			   tree_cons (NULL_TREE, puint_type_node,
8224117395Skan				      tree_cons (NULL_TREE, integer_type_node,
8225117395Skan						 endlink)));
8226117395Skan
8227117395Skan  tree v2si_ftype_pushort_int
8228132718Skan    = build_function_type (opaque_V2SI_type_node,
8229117395Skan			   tree_cons (NULL_TREE, pushort_type_node,
8230117395Skan				      tree_cons (NULL_TREE, integer_type_node,
8231117395Skan						 endlink)));
8232117395Skan
8233132718Skan  tree v2si_ftype_signed_char
8234132718Skan    = build_function_type (opaque_V2SI_type_node,
8235132718Skan			   tree_cons (NULL_TREE, signed_char_type_node,
8236132718Skan				      endlink));
8237132718Skan
8238117395Skan  /* The initialization of the simple binary and unary builtins is
8239117395Skan     done in rs6000_common_init_builtins, but we have to enable the
8240117395Skan     mask bits here manually because we have run out of `target_flags'
8241117395Skan     bits.  We really need to redesign this mask business.  */
8242117395Skan
8243117395Skan  enable_mask_for_builtins ((struct builtin_description *) bdesc_2arg,
8244117395Skan			    ARRAY_SIZE (bdesc_2arg),
8245117395Skan			    SPE_BUILTIN_EVADDW,
8246117395Skan			    SPE_BUILTIN_EVXOR);
8247117395Skan  enable_mask_for_builtins ((struct builtin_description *) bdesc_1arg,
8248117395Skan			    ARRAY_SIZE (bdesc_1arg),
8249117395Skan			    SPE_BUILTIN_EVABS,
8250117395Skan			    SPE_BUILTIN_EVSUBFUSIAAW);
8251117395Skan  enable_mask_for_builtins ((struct builtin_description *) bdesc_spe_predicates,
8252117395Skan			    ARRAY_SIZE (bdesc_spe_predicates),
8253117395Skan			    SPE_BUILTIN_EVCMPEQ,
8254117395Skan			    SPE_BUILTIN_EVFSTSTLT);
8255117395Skan  enable_mask_for_builtins ((struct builtin_description *) bdesc_spe_evsel,
8256117395Skan			    ARRAY_SIZE (bdesc_spe_evsel),
8257117395Skan			    SPE_BUILTIN_EVSEL_CMPGTS,
8258117395Skan			    SPE_BUILTIN_EVSEL_FSTSTEQ);
8259117395Skan
8260132718Skan  (*lang_hooks.decls.pushdecl)
8261132718Skan    (build_decl (TYPE_DECL, get_identifier ("__ev64_opaque__"),
8262132718Skan		 opaque_V2SI_type_node));
8263132718Skan
8264117395Skan  /* Initialize irregular SPE builtins.  */
8265169689Skan
8266117395Skan  def_builtin (target_flags, "__builtin_spe_mtspefscr", void_ftype_int, SPE_BUILTIN_MTSPEFSCR);
8267117395Skan  def_builtin (target_flags, "__builtin_spe_mfspefscr", int_ftype_void, SPE_BUILTIN_MFSPEFSCR);
8268117395Skan  def_builtin (target_flags, "__builtin_spe_evstddx", void_ftype_v2si_pv2si_int, SPE_BUILTIN_EVSTDDX);
8269117395Skan  def_builtin (target_flags, "__builtin_spe_evstdhx", void_ftype_v2si_pv2si_int, SPE_BUILTIN_EVSTDHX);
8270117395Skan  def_builtin (target_flags, "__builtin_spe_evstdwx", void_ftype_v2si_pv2si_int, SPE_BUILTIN_EVSTDWX);
8271117395Skan  def_builtin (target_flags, "__builtin_spe_evstwhex", void_ftype_v2si_puint_int, SPE_BUILTIN_EVSTWHEX);
8272117395Skan  def_builtin (target_flags, "__builtin_spe_evstwhox", void_ftype_v2si_puint_int, SPE_BUILTIN_EVSTWHOX);
8273117395Skan  def_builtin (target_flags, "__builtin_spe_evstwwex", void_ftype_v2si_puint_int, SPE_BUILTIN_EVSTWWEX);
8274117395Skan  def_builtin (target_flags, "__builtin_spe_evstwwox", void_ftype_v2si_puint_int, SPE_BUILTIN_EVSTWWOX);
8275117395Skan  def_builtin (target_flags, "__builtin_spe_evstdd", void_ftype_v2si_pv2si_char, SPE_BUILTIN_EVSTDD);
8276117395Skan  def_builtin (target_flags, "__builtin_spe_evstdh", void_ftype_v2si_pv2si_char, SPE_BUILTIN_EVSTDH);
8277117395Skan  def_builtin (target_flags, "__builtin_spe_evstdw", void_ftype_v2si_pv2si_char, SPE_BUILTIN_EVSTDW);
8278117395Skan  def_builtin (target_flags, "__builtin_spe_evstwhe", void_ftype_v2si_puint_char, SPE_BUILTIN_EVSTWHE);
8279117395Skan  def_builtin (target_flags, "__builtin_spe_evstwho", void_ftype_v2si_puint_char, SPE_BUILTIN_EVSTWHO);
8280117395Skan  def_builtin (target_flags, "__builtin_spe_evstwwe", void_ftype_v2si_puint_char, SPE_BUILTIN_EVSTWWE);
8281117395Skan  def_builtin (target_flags, "__builtin_spe_evstwwo", void_ftype_v2si_puint_char, SPE_BUILTIN_EVSTWWO);
8282132718Skan  def_builtin (target_flags, "__builtin_spe_evsplatfi", v2si_ftype_signed_char, SPE_BUILTIN_EVSPLATFI);
8283132718Skan  def_builtin (target_flags, "__builtin_spe_evsplati", v2si_ftype_signed_char, SPE_BUILTIN_EVSPLATI);
8284117395Skan
8285117395Skan  /* Loads.  */
8286117395Skan  def_builtin (target_flags, "__builtin_spe_evlddx", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDDX);
8287117395Skan  def_builtin (target_flags, "__builtin_spe_evldwx", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDWX);
8288117395Skan  def_builtin (target_flags, "__builtin_spe_evldhx", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDHX);
8289117395Skan  def_builtin (target_flags, "__builtin_spe_evlwhex", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHEX);
8290117395Skan  def_builtin (target_flags, "__builtin_spe_evlwhoux", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHOUX);
8291117395Skan  def_builtin (target_flags, "__builtin_spe_evlwhosx", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHOSX);
8292117395Skan  def_builtin (target_flags, "__builtin_spe_evlwwsplatx", v2si_ftype_puint_int, SPE_BUILTIN_EVLWWSPLATX);
8293117395Skan  def_builtin (target_flags, "__builtin_spe_evlwhsplatx", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHSPLATX);
8294117395Skan  def_builtin (target_flags, "__builtin_spe_evlhhesplatx", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHESPLATX);
8295117395Skan  def_builtin (target_flags, "__builtin_spe_evlhhousplatx", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHOUSPLATX);
8296117395Skan  def_builtin (target_flags, "__builtin_spe_evlhhossplatx", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHOSSPLATX);
8297117395Skan  def_builtin (target_flags, "__builtin_spe_evldd", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDD);
8298117395Skan  def_builtin (target_flags, "__builtin_spe_evldw", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDW);
8299117395Skan  def_builtin (target_flags, "__builtin_spe_evldh", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDH);
8300117395Skan  def_builtin (target_flags, "__builtin_spe_evlhhesplat", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHESPLAT);
8301117395Skan  def_builtin (target_flags, "__builtin_spe_evlhhossplat", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHOSSPLAT);
8302117395Skan  def_builtin (target_flags, "__builtin_spe_evlhhousplat", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHOUSPLAT);
8303117395Skan  def_builtin (target_flags, "__builtin_spe_evlwhe", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHE);
8304117395Skan  def_builtin (target_flags, "__builtin_spe_evlwhos", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHOS);
8305117395Skan  def_builtin (target_flags, "__builtin_spe_evlwhou", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHOU);
8306117395Skan  def_builtin (target_flags, "__builtin_spe_evlwhsplat", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHSPLAT);
8307117395Skan  def_builtin (target_flags, "__builtin_spe_evlwwsplat", v2si_ftype_puint_int, SPE_BUILTIN_EVLWWSPLAT);
8308117395Skan
8309117395Skan  /* Predicates.  */
8310117395Skan  d = (struct builtin_description *) bdesc_spe_predicates;
8311117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_spe_predicates); ++i, d++)
8312117395Skan    {
8313117395Skan      tree type;
8314117395Skan
8315117395Skan      switch (insn_data[d->icode].operand[1].mode)
8316117395Skan	{
8317117395Skan	case V2SImode:
8318117395Skan	  type = int_ftype_int_v2si_v2si;
8319117395Skan	  break;
8320117395Skan	case V2SFmode:
8321117395Skan	  type = int_ftype_int_v2sf_v2sf;
8322117395Skan	  break;
8323117395Skan	default:
8324169689Skan	  gcc_unreachable ();
8325117395Skan	}
8326117395Skan
8327117395Skan      def_builtin (d->mask, d->name, type, d->code);
8328117395Skan    }
8329117395Skan
8330117395Skan  /* Evsel predicates.  */
8331117395Skan  d = (struct builtin_description *) bdesc_spe_evsel;
8332117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_spe_evsel); ++i, d++)
8333117395Skan    {
8334117395Skan      tree type;
8335117395Skan
8336117395Skan      switch (insn_data[d->icode].operand[1].mode)
8337117395Skan	{
8338117395Skan	case V2SImode:
8339117395Skan	  type = v2si_ftype_4_v2si;
8340117395Skan	  break;
8341117395Skan	case V2SFmode:
8342117395Skan	  type = v2sf_ftype_4_v2sf;
8343117395Skan	  break;
8344117395Skan	default:
8345169689Skan	  gcc_unreachable ();
8346117395Skan	}
8347117395Skan
8348117395Skan      def_builtin (d->mask, d->name, type, d->code);
8349117395Skan    }
8350117395Skan}
8351117395Skan
8352117395Skanstatic void
8353132718Skanaltivec_init_builtins (void)
8354117395Skan{
8355117395Skan  struct builtin_description *d;
8356117395Skan  struct builtin_description_predicates *dp;
8357117395Skan  size_t i;
8358169689Skan  tree ftype;
8359169689Skan
8360117395Skan  tree pfloat_type_node = build_pointer_type (float_type_node);
8361117395Skan  tree pint_type_node = build_pointer_type (integer_type_node);
8362117395Skan  tree pshort_type_node = build_pointer_type (short_integer_type_node);
8363117395Skan  tree pchar_type_node = build_pointer_type (char_type_node);
8364117395Skan
8365117395Skan  tree pvoid_type_node = build_pointer_type (void_type_node);
8366117395Skan
8367117395Skan  tree pcfloat_type_node = build_pointer_type (build_qualified_type (float_type_node, TYPE_QUAL_CONST));
8368117395Skan  tree pcint_type_node = build_pointer_type (build_qualified_type (integer_type_node, TYPE_QUAL_CONST));
8369117395Skan  tree pcshort_type_node = build_pointer_type (build_qualified_type (short_integer_type_node, TYPE_QUAL_CONST));
8370117395Skan  tree pcchar_type_node = build_pointer_type (build_qualified_type (char_type_node, TYPE_QUAL_CONST));
8371117395Skan
8372117395Skan  tree pcvoid_type_node = build_pointer_type (build_qualified_type (void_type_node, TYPE_QUAL_CONST));
8373117395Skan
8374169689Skan  tree int_ftype_opaque
8375169689Skan    = build_function_type_list (integer_type_node,
8376169689Skan				opaque_V4SI_type_node, NULL_TREE);
8377169689Skan
8378169689Skan  tree opaque_ftype_opaque_int
8379169689Skan    = build_function_type_list (opaque_V4SI_type_node,
8380169689Skan				opaque_V4SI_type_node, integer_type_node, NULL_TREE);
8381169689Skan  tree opaque_ftype_opaque_opaque_int
8382169689Skan    = build_function_type_list (opaque_V4SI_type_node,
8383169689Skan				opaque_V4SI_type_node, opaque_V4SI_type_node,
8384169689Skan				integer_type_node, NULL_TREE);
8385169689Skan  tree int_ftype_int_opaque_opaque
8386169689Skan    = build_function_type_list (integer_type_node,
8387169689Skan                                integer_type_node, opaque_V4SI_type_node,
8388169689Skan                                opaque_V4SI_type_node, NULL_TREE);
8389117395Skan  tree int_ftype_int_v4si_v4si
8390117395Skan    = build_function_type_list (integer_type_node,
8391117395Skan				integer_type_node, V4SI_type_node,
8392117395Skan				V4SI_type_node, NULL_TREE);
8393117395Skan  tree v4sf_ftype_pcfloat
8394117395Skan    = build_function_type_list (V4SF_type_node, pcfloat_type_node, NULL_TREE);
8395117395Skan  tree void_ftype_pfloat_v4sf
8396117395Skan    = build_function_type_list (void_type_node,
8397117395Skan				pfloat_type_node, V4SF_type_node, NULL_TREE);
8398117395Skan  tree v4si_ftype_pcint
8399117395Skan    = build_function_type_list (V4SI_type_node, pcint_type_node, NULL_TREE);
8400117395Skan  tree void_ftype_pint_v4si
8401117395Skan    = build_function_type_list (void_type_node,
8402117395Skan				pint_type_node, V4SI_type_node, NULL_TREE);
8403117395Skan  tree v8hi_ftype_pcshort
8404117395Skan    = build_function_type_list (V8HI_type_node, pcshort_type_node, NULL_TREE);
8405117395Skan  tree void_ftype_pshort_v8hi
8406117395Skan    = build_function_type_list (void_type_node,
8407117395Skan				pshort_type_node, V8HI_type_node, NULL_TREE);
8408117395Skan  tree v16qi_ftype_pcchar
8409117395Skan    = build_function_type_list (V16QI_type_node, pcchar_type_node, NULL_TREE);
8410117395Skan  tree void_ftype_pchar_v16qi
8411117395Skan    = build_function_type_list (void_type_node,
8412117395Skan				pchar_type_node, V16QI_type_node, NULL_TREE);
8413117395Skan  tree void_ftype_v4si
8414117395Skan    = build_function_type_list (void_type_node, V4SI_type_node, NULL_TREE);
841590075Sobrien  tree v8hi_ftype_void
841696263Sobrien    = build_function_type (V8HI_type_node, void_list_node);
8417117395Skan  tree void_ftype_void
8418117395Skan    = build_function_type (void_type_node, void_list_node);
8419146895Skan  tree void_ftype_int
8420146895Skan    = build_function_type_list (void_type_node, integer_type_node, NULL_TREE);
842190075Sobrien
8422169689Skan  tree opaque_ftype_long_pcvoid
8423169689Skan    = build_function_type_list (opaque_V4SI_type_node,
8424169689Skan				long_integer_type_node, pcvoid_type_node, NULL_TREE);
8425132718Skan  tree v16qi_ftype_long_pcvoid
8426117395Skan    = build_function_type_list (V16QI_type_node,
8427132718Skan				long_integer_type_node, pcvoid_type_node, NULL_TREE);
8428132718Skan  tree v8hi_ftype_long_pcvoid
8429117395Skan    = build_function_type_list (V8HI_type_node,
8430132718Skan				long_integer_type_node, pcvoid_type_node, NULL_TREE);
8431132718Skan  tree v4si_ftype_long_pcvoid
8432117395Skan    = build_function_type_list (V4SI_type_node,
8433132718Skan				long_integer_type_node, pcvoid_type_node, NULL_TREE);
843490075Sobrien
8435169689Skan  tree void_ftype_opaque_long_pvoid
8436169689Skan    = build_function_type_list (void_type_node,
8437169689Skan				opaque_V4SI_type_node, long_integer_type_node,
8438169689Skan				pvoid_type_node, NULL_TREE);
8439132718Skan  tree void_ftype_v4si_long_pvoid
8440117395Skan    = build_function_type_list (void_type_node,
8441132718Skan				V4SI_type_node, long_integer_type_node,
8442117395Skan				pvoid_type_node, NULL_TREE);
8443132718Skan  tree void_ftype_v16qi_long_pvoid
8444117395Skan    = build_function_type_list (void_type_node,
8445132718Skan				V16QI_type_node, long_integer_type_node,
8446117395Skan				pvoid_type_node, NULL_TREE);
8447132718Skan  tree void_ftype_v8hi_long_pvoid
8448117395Skan    = build_function_type_list (void_type_node,
8449132718Skan				V8HI_type_node, long_integer_type_node,
8450117395Skan				pvoid_type_node, NULL_TREE);
8451117395Skan  tree int_ftype_int_v8hi_v8hi
8452117395Skan    = build_function_type_list (integer_type_node,
8453117395Skan				integer_type_node, V8HI_type_node,
8454117395Skan				V8HI_type_node, NULL_TREE);
8455117395Skan  tree int_ftype_int_v16qi_v16qi
8456117395Skan    = build_function_type_list (integer_type_node,
8457117395Skan				integer_type_node, V16QI_type_node,
8458117395Skan				V16QI_type_node, NULL_TREE);
8459117395Skan  tree int_ftype_int_v4sf_v4sf
8460117395Skan    = build_function_type_list (integer_type_node,
8461117395Skan				integer_type_node, V4SF_type_node,
8462117395Skan				V4SF_type_node, NULL_TREE);
8463117395Skan  tree v4si_ftype_v4si
8464117395Skan    = build_function_type_list (V4SI_type_node, V4SI_type_node, NULL_TREE);
8465117395Skan  tree v8hi_ftype_v8hi
8466117395Skan    = build_function_type_list (V8HI_type_node, V8HI_type_node, NULL_TREE);
8467117395Skan  tree v16qi_ftype_v16qi
8468117395Skan    = build_function_type_list (V16QI_type_node, V16QI_type_node, NULL_TREE);
8469117395Skan  tree v4sf_ftype_v4sf
8470117395Skan    = build_function_type_list (V4SF_type_node, V4SF_type_node, NULL_TREE);
8471146895Skan  tree void_ftype_pcvoid_int_int
8472117395Skan    = build_function_type_list (void_type_node,
8473117395Skan				pcvoid_type_node, integer_type_node,
8474146895Skan				integer_type_node, NULL_TREE);
8475169689Skan
8476117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_4sf", v4sf_ftype_pcfloat,
8477117395Skan	       ALTIVEC_BUILTIN_LD_INTERNAL_4sf);
8478117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_4sf", void_ftype_pfloat_v4sf,
8479117395Skan	       ALTIVEC_BUILTIN_ST_INTERNAL_4sf);
8480117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_4si", v4si_ftype_pcint,
8481117395Skan	       ALTIVEC_BUILTIN_LD_INTERNAL_4si);
8482117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_4si", void_ftype_pint_v4si,
8483117395Skan	       ALTIVEC_BUILTIN_ST_INTERNAL_4si);
8484117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_8hi", v8hi_ftype_pcshort,
8485117395Skan	       ALTIVEC_BUILTIN_LD_INTERNAL_8hi);
8486117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_8hi", void_ftype_pshort_v8hi,
8487117395Skan	       ALTIVEC_BUILTIN_ST_INTERNAL_8hi);
8488117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_16qi", v16qi_ftype_pcchar,
8489117395Skan	       ALTIVEC_BUILTIN_LD_INTERNAL_16qi);
8490117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_16qi", void_ftype_pchar_v16qi,
8491117395Skan	       ALTIVEC_BUILTIN_ST_INTERNAL_16qi);
8492117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_mtvscr", void_ftype_v4si, ALTIVEC_BUILTIN_MTVSCR);
8493117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_mfvscr", v8hi_ftype_void, ALTIVEC_BUILTIN_MFVSCR);
8494117395Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_dssall", void_ftype_void, ALTIVEC_BUILTIN_DSSALL);
8495146895Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_dss", void_ftype_int, ALTIVEC_BUILTIN_DSS);
8496132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvsl", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVSL);
8497132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvsr", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVSR);
8498132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvebx", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVEBX);
8499132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvehx", v8hi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVEHX);
8500132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvewx", v4si_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVEWX);
8501132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvxl", v4si_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVXL);
8502132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvx", v4si_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVX);
8503132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvx", void_ftype_v4si_long_pvoid, ALTIVEC_BUILTIN_STVX);
8504132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvewx", void_ftype_v4si_long_pvoid, ALTIVEC_BUILTIN_STVEWX);
8505132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvxl", void_ftype_v4si_long_pvoid, ALTIVEC_BUILTIN_STVXL);
8506132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvebx", void_ftype_v16qi_long_pvoid, ALTIVEC_BUILTIN_STVEBX);
8507132718Skan  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvehx", void_ftype_v8hi_long_pvoid, ALTIVEC_BUILTIN_STVEHX);
8508169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_ld", opaque_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LD);
8509169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_lde", opaque_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LDE);
8510169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_ldl", opaque_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LDL);
8511169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_lvsl", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVSL);
8512169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_lvsr", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVSR);
8513169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_lvebx", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVEBX);
8514169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_lvehx", v8hi_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVEHX);
8515169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_lvewx", v4si_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVEWX);
8516169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_st", void_ftype_opaque_long_pvoid, ALTIVEC_BUILTIN_VEC_ST);
8517169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_ste", void_ftype_opaque_long_pvoid, ALTIVEC_BUILTIN_VEC_STE);
8518169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_stl", void_ftype_opaque_long_pvoid, ALTIVEC_BUILTIN_VEC_STL);
8519169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_stvewx", void_ftype_opaque_long_pvoid, ALTIVEC_BUILTIN_VEC_STVEWX);
8520169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_stvebx", void_ftype_opaque_long_pvoid, ALTIVEC_BUILTIN_VEC_STVEBX);
8521169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_stvehx", void_ftype_opaque_long_pvoid, ALTIVEC_BUILTIN_VEC_STVEHX);
852290075Sobrien
8523169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_step", int_ftype_opaque, ALTIVEC_BUILTIN_VEC_STEP);
8524146895Skan
8525169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_sld", opaque_ftype_opaque_opaque_int, ALTIVEC_BUILTIN_VEC_SLD);
8526169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_splat", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_SPLAT);
8527169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_vspltw", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_VSPLTW);
8528169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_vsplth", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_VSPLTH);
8529169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_vspltb", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_VSPLTB);
8530169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_ctf", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_CTF);
8531169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_vcfsx", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_VCFSX);
8532169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_vcfux", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_VCFUX);
8533169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_cts", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_CTS);
8534169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_ctu", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_CTU);
8535169689Skan
8536117395Skan  /* Add the DST variants.  */
8537117395Skan  d = (struct builtin_description *) bdesc_dst;
8538117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_dst); i++, d++)
8539146895Skan    def_builtin (d->mask, d->name, void_ftype_pcvoid_int_int, d->code);
8540117395Skan
8541117395Skan  /* Initialize the predicates.  */
8542117395Skan  dp = (struct builtin_description_predicates *) bdesc_altivec_preds;
8543117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_altivec_preds); i++, dp++)
8544117395Skan    {
8545117395Skan      enum machine_mode mode1;
8546117395Skan      tree type;
8547169689Skan      bool is_overloaded = dp->code >= ALTIVEC_BUILTIN_OVERLOADED_FIRST
8548169689Skan			   && dp->code <= ALTIVEC_BUILTIN_OVERLOADED_LAST;
8549117395Skan
8550169689Skan      if (is_overloaded)
8551169689Skan	mode1 = VOIDmode;
8552169689Skan      else
8553169689Skan	mode1 = insn_data[dp->icode].operand[1].mode;
8554117395Skan
8555117395Skan      switch (mode1)
8556117395Skan	{
8557169689Skan	case VOIDmode:
8558169689Skan	  type = int_ftype_int_opaque_opaque;
8559169689Skan	  break;
8560117395Skan	case V4SImode:
8561117395Skan	  type = int_ftype_int_v4si_v4si;
8562117395Skan	  break;
8563117395Skan	case V8HImode:
8564117395Skan	  type = int_ftype_int_v8hi_v8hi;
8565117395Skan	  break;
8566117395Skan	case V16QImode:
8567117395Skan	  type = int_ftype_int_v16qi_v16qi;
8568117395Skan	  break;
8569117395Skan	case V4SFmode:
8570117395Skan	  type = int_ftype_int_v4sf_v4sf;
8571117395Skan	  break;
8572117395Skan	default:
8573169689Skan	  gcc_unreachable ();
8574117395Skan	}
8575169689Skan
8576117395Skan      def_builtin (dp->mask, dp->name, type, dp->code);
8577117395Skan    }
8578117395Skan
8579117395Skan  /* Initialize the abs* operators.  */
8580117395Skan  d = (struct builtin_description *) bdesc_abs;
8581117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_abs); i++, d++)
8582117395Skan    {
8583117395Skan      enum machine_mode mode0;
8584117395Skan      tree type;
8585117395Skan
8586117395Skan      mode0 = insn_data[d->icode].operand[0].mode;
8587117395Skan
8588117395Skan      switch (mode0)
8589117395Skan	{
8590117395Skan	case V4SImode:
8591117395Skan	  type = v4si_ftype_v4si;
8592117395Skan	  break;
8593117395Skan	case V8HImode:
8594117395Skan	  type = v8hi_ftype_v8hi;
8595117395Skan	  break;
8596117395Skan	case V16QImode:
8597117395Skan	  type = v16qi_ftype_v16qi;
8598117395Skan	  break;
8599117395Skan	case V4SFmode:
8600117395Skan	  type = v4sf_ftype_v4sf;
8601117395Skan	  break;
8602117395Skan	default:
8603169689Skan	  gcc_unreachable ();
8604117395Skan	}
8605169689Skan
8606117395Skan      def_builtin (d->mask, d->name, type, d->code);
8607117395Skan    }
8608169689Skan
8609169689Skan  if (TARGET_ALTIVEC)
8610169689Skan    {
8611169689Skan      tree decl;
8612169689Skan
8613169689Skan      /* Initialize target builtin that implements
8614169689Skan         targetm.vectorize.builtin_mask_for_load.  */
8615169689Skan
8616169689Skan      decl = lang_hooks.builtin_function ("__builtin_altivec_mask_for_load",
8617169689Skan                               v16qi_ftype_long_pcvoid,
8618169689Skan                               ALTIVEC_BUILTIN_MASK_FOR_LOAD,
8619169689Skan                               BUILT_IN_MD, NULL,
8620169689Skan                               tree_cons (get_identifier ("const"),
8621169689Skan                                          NULL_TREE, NULL_TREE));
8622169689Skan      /* Record the decl. Will be used by rs6000_builtin_mask_for_load.  */
8623169689Skan      altivec_builtin_mask_for_load = decl;
8624169689Skan    }
8625169689Skan
8626169689Skan  /* Access to the vec_init patterns.  */
8627169689Skan  ftype = build_function_type_list (V4SI_type_node, integer_type_node,
8628169689Skan				    integer_type_node, integer_type_node,
8629169689Skan				    integer_type_node, NULL_TREE);
8630169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_init_v4si", ftype,
8631169689Skan	       ALTIVEC_BUILTIN_VEC_INIT_V4SI);
8632169689Skan
8633169689Skan  ftype = build_function_type_list (V8HI_type_node, short_integer_type_node,
8634169689Skan				    short_integer_type_node,
8635169689Skan				    short_integer_type_node,
8636169689Skan				    short_integer_type_node,
8637169689Skan				    short_integer_type_node,
8638169689Skan				    short_integer_type_node,
8639169689Skan				    short_integer_type_node,
8640169689Skan				    short_integer_type_node, NULL_TREE);
8641169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_init_v8hi", ftype,
8642169689Skan	       ALTIVEC_BUILTIN_VEC_INIT_V8HI);
8643169689Skan
8644169689Skan  ftype = build_function_type_list (V16QI_type_node, char_type_node,
8645169689Skan				    char_type_node, char_type_node,
8646169689Skan				    char_type_node, char_type_node,
8647169689Skan				    char_type_node, char_type_node,
8648169689Skan				    char_type_node, char_type_node,
8649169689Skan				    char_type_node, char_type_node,
8650169689Skan				    char_type_node, char_type_node,
8651169689Skan				    char_type_node, char_type_node,
8652169689Skan				    char_type_node, NULL_TREE);
8653169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_init_v16qi", ftype,
8654169689Skan	       ALTIVEC_BUILTIN_VEC_INIT_V16QI);
8655169689Skan
8656169689Skan  ftype = build_function_type_list (V4SF_type_node, float_type_node,
8657169689Skan				    float_type_node, float_type_node,
8658169689Skan				    float_type_node, NULL_TREE);
8659169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_init_v4sf", ftype,
8660169689Skan	       ALTIVEC_BUILTIN_VEC_INIT_V4SF);
8661169689Skan
8662169689Skan  /* Access to the vec_set patterns.  */
8663169689Skan  ftype = build_function_type_list (V4SI_type_node, V4SI_type_node,
8664169689Skan				    intSI_type_node,
8665169689Skan				    integer_type_node, NULL_TREE);
8666169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_set_v4si", ftype,
8667169689Skan	       ALTIVEC_BUILTIN_VEC_SET_V4SI);
8668169689Skan
8669169689Skan  ftype = build_function_type_list (V8HI_type_node, V8HI_type_node,
8670169689Skan				    intHI_type_node,
8671169689Skan				    integer_type_node, NULL_TREE);
8672169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_set_v8hi", ftype,
8673169689Skan	       ALTIVEC_BUILTIN_VEC_SET_V8HI);
8674169689Skan
8675169689Skan  ftype = build_function_type_list (V8HI_type_node, V16QI_type_node,
8676169689Skan				    intQI_type_node,
8677169689Skan				    integer_type_node, NULL_TREE);
8678169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_set_v16qi", ftype,
8679169689Skan	       ALTIVEC_BUILTIN_VEC_SET_V16QI);
8680169689Skan
8681169689Skan  ftype = build_function_type_list (V4SF_type_node, V4SF_type_node,
8682169689Skan				    float_type_node,
8683169689Skan				    integer_type_node, NULL_TREE);
8684169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_set_v4sf", ftype,
8685169689Skan	       ALTIVEC_BUILTIN_VEC_SET_V4SF);
8686169689Skan
8687169689Skan  /* Access to the vec_extract patterns.  */
8688169689Skan  ftype = build_function_type_list (intSI_type_node, V4SI_type_node,
8689169689Skan				    integer_type_node, NULL_TREE);
8690169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_ext_v4si", ftype,
8691169689Skan	       ALTIVEC_BUILTIN_VEC_EXT_V4SI);
8692169689Skan
8693169689Skan  ftype = build_function_type_list (intHI_type_node, V8HI_type_node,
8694169689Skan				    integer_type_node, NULL_TREE);
8695169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_ext_v8hi", ftype,
8696169689Skan	       ALTIVEC_BUILTIN_VEC_EXT_V8HI);
8697169689Skan
8698169689Skan  ftype = build_function_type_list (intQI_type_node, V16QI_type_node,
8699169689Skan				    integer_type_node, NULL_TREE);
8700169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_ext_v16qi", ftype,
8701169689Skan	       ALTIVEC_BUILTIN_VEC_EXT_V16QI);
8702169689Skan
8703169689Skan  ftype = build_function_type_list (float_type_node, V4SF_type_node,
8704169689Skan				    integer_type_node, NULL_TREE);
8705169689Skan  def_builtin (MASK_ALTIVEC, "__builtin_vec_ext_v4sf", ftype,
8706169689Skan	       ALTIVEC_BUILTIN_VEC_EXT_V4SF);
8707117395Skan}
8708117395Skan
8709117395Skanstatic void
8710132718Skanrs6000_common_init_builtins (void)
8711117395Skan{
8712117395Skan  struct builtin_description *d;
8713117395Skan  size_t i;
8714117395Skan
8715117395Skan  tree v4sf_ftype_v4sf_v4sf_v16qi
8716117395Skan    = build_function_type_list (V4SF_type_node,
8717117395Skan				V4SF_type_node, V4SF_type_node,
8718117395Skan				V16QI_type_node, NULL_TREE);
8719117395Skan  tree v4si_ftype_v4si_v4si_v16qi
8720117395Skan    = build_function_type_list (V4SI_type_node,
8721117395Skan				V4SI_type_node, V4SI_type_node,
8722117395Skan				V16QI_type_node, NULL_TREE);
8723117395Skan  tree v8hi_ftype_v8hi_v8hi_v16qi
8724117395Skan    = build_function_type_list (V8HI_type_node,
8725117395Skan				V8HI_type_node, V8HI_type_node,
8726117395Skan				V16QI_type_node, NULL_TREE);
8727117395Skan  tree v16qi_ftype_v16qi_v16qi_v16qi
8728117395Skan    = build_function_type_list (V16QI_type_node,
8729117395Skan				V16QI_type_node, V16QI_type_node,
8730117395Skan				V16QI_type_node, NULL_TREE);
8731146895Skan  tree v4si_ftype_int
8732146895Skan    = build_function_type_list (V4SI_type_node, integer_type_node, NULL_TREE);
8733146895Skan  tree v8hi_ftype_int
8734146895Skan    = build_function_type_list (V8HI_type_node, integer_type_node, NULL_TREE);
8735146895Skan  tree v16qi_ftype_int
8736146895Skan    = build_function_type_list (V16QI_type_node, integer_type_node, NULL_TREE);
8737117395Skan  tree v8hi_ftype_v16qi
8738117395Skan    = build_function_type_list (V8HI_type_node, V16QI_type_node, NULL_TREE);
8739117395Skan  tree v4sf_ftype_v4sf
8740117395Skan    = build_function_type_list (V4SF_type_node, V4SF_type_node, NULL_TREE);
8741117395Skan
8742117395Skan  tree v2si_ftype_v2si_v2si
8743132718Skan    = build_function_type_list (opaque_V2SI_type_node,
8744132718Skan				opaque_V2SI_type_node,
8745132718Skan				opaque_V2SI_type_node, NULL_TREE);
8746117395Skan
8747117395Skan  tree v2sf_ftype_v2sf_v2sf
8748132718Skan    = build_function_type_list (opaque_V2SF_type_node,
8749132718Skan				opaque_V2SF_type_node,
8750132718Skan				opaque_V2SF_type_node, NULL_TREE);
8751117395Skan
8752117395Skan  tree v2si_ftype_int_int
8753132718Skan    = build_function_type_list (opaque_V2SI_type_node,
8754117395Skan				integer_type_node, integer_type_node,
8755117395Skan				NULL_TREE);
8756117395Skan
8757169689Skan  tree opaque_ftype_opaque
8758169689Skan    = build_function_type_list (opaque_V4SI_type_node,
8759169689Skan				opaque_V4SI_type_node, NULL_TREE);
8760169689Skan
8761117395Skan  tree v2si_ftype_v2si
8762132718Skan    = build_function_type_list (opaque_V2SI_type_node,
8763132718Skan				opaque_V2SI_type_node, NULL_TREE);
8764117395Skan
8765117395Skan  tree v2sf_ftype_v2sf
8766132718Skan    = build_function_type_list (opaque_V2SF_type_node,
8767132718Skan				opaque_V2SF_type_node, NULL_TREE);
8768169689Skan
8769117395Skan  tree v2sf_ftype_v2si
8770132718Skan    = build_function_type_list (opaque_V2SF_type_node,
8771132718Skan				opaque_V2SI_type_node, NULL_TREE);
8772117395Skan
8773117395Skan  tree v2si_ftype_v2sf
8774132718Skan    = build_function_type_list (opaque_V2SI_type_node,
8775132718Skan				opaque_V2SF_type_node, NULL_TREE);
8776117395Skan
8777117395Skan  tree v2si_ftype_v2si_char
8778132718Skan    = build_function_type_list (opaque_V2SI_type_node,
8779132718Skan				opaque_V2SI_type_node,
8780132718Skan				char_type_node, NULL_TREE);
8781117395Skan
8782117395Skan  tree v2si_ftype_int_char
8783132718Skan    = build_function_type_list (opaque_V2SI_type_node,
8784117395Skan				integer_type_node, char_type_node, NULL_TREE);
8785117395Skan
8786117395Skan  tree v2si_ftype_char
8787132718Skan    = build_function_type_list (opaque_V2SI_type_node,
8788132718Skan				char_type_node, NULL_TREE);
8789117395Skan
8790117395Skan  tree int_ftype_int_int
8791117395Skan    = build_function_type_list (integer_type_node,
8792117395Skan				integer_type_node, integer_type_node,
8793117395Skan				NULL_TREE);
8794117395Skan
8795169689Skan  tree opaque_ftype_opaque_opaque
8796169689Skan    = build_function_type_list (opaque_V4SI_type_node,
8797169689Skan                                opaque_V4SI_type_node, opaque_V4SI_type_node, NULL_TREE);
8798117395Skan  tree v4si_ftype_v4si_v4si
8799117395Skan    = build_function_type_list (V4SI_type_node,
8800117395Skan				V4SI_type_node, V4SI_type_node, NULL_TREE);
8801146895Skan  tree v4sf_ftype_v4si_int
8802117395Skan    = build_function_type_list (V4SF_type_node,
8803146895Skan				V4SI_type_node, integer_type_node, NULL_TREE);
8804146895Skan  tree v4si_ftype_v4sf_int
8805117395Skan    = build_function_type_list (V4SI_type_node,
8806146895Skan				V4SF_type_node, integer_type_node, NULL_TREE);
8807146895Skan  tree v4si_ftype_v4si_int
8808117395Skan    = build_function_type_list (V4SI_type_node,
8809146895Skan				V4SI_type_node, integer_type_node, NULL_TREE);
8810146895Skan  tree v8hi_ftype_v8hi_int
8811117395Skan    = build_function_type_list (V8HI_type_node,
8812146895Skan				V8HI_type_node, integer_type_node, NULL_TREE);
8813146895Skan  tree v16qi_ftype_v16qi_int
8814117395Skan    = build_function_type_list (V16QI_type_node,
8815146895Skan				V16QI_type_node, integer_type_node, NULL_TREE);
8816146895Skan  tree v16qi_ftype_v16qi_v16qi_int
8817117395Skan    = build_function_type_list (V16QI_type_node,
8818117395Skan				V16QI_type_node, V16QI_type_node,
8819146895Skan				integer_type_node, NULL_TREE);
8820146895Skan  tree v8hi_ftype_v8hi_v8hi_int
8821117395Skan    = build_function_type_list (V8HI_type_node,
8822117395Skan				V8HI_type_node, V8HI_type_node,
8823146895Skan				integer_type_node, NULL_TREE);
8824146895Skan  tree v4si_ftype_v4si_v4si_int
8825117395Skan    = build_function_type_list (V4SI_type_node,
8826117395Skan				V4SI_type_node, V4SI_type_node,
8827146895Skan				integer_type_node, NULL_TREE);
8828146895Skan  tree v4sf_ftype_v4sf_v4sf_int
8829117395Skan    = build_function_type_list (V4SF_type_node,
8830117395Skan				V4SF_type_node, V4SF_type_node,
8831146895Skan				integer_type_node, NULL_TREE);
883290075Sobrien  tree v4sf_ftype_v4sf_v4sf
8833117395Skan    = build_function_type_list (V4SF_type_node,
8834117395Skan				V4SF_type_node, V4SF_type_node, NULL_TREE);
8835169689Skan  tree opaque_ftype_opaque_opaque_opaque
8836169689Skan    = build_function_type_list (opaque_V4SI_type_node,
8837169689Skan                                opaque_V4SI_type_node, opaque_V4SI_type_node,
8838169689Skan                                opaque_V4SI_type_node, NULL_TREE);
883990075Sobrien  tree v4sf_ftype_v4sf_v4sf_v4si
8840117395Skan    = build_function_type_list (V4SF_type_node,
8841117395Skan				V4SF_type_node, V4SF_type_node,
8842117395Skan				V4SI_type_node, NULL_TREE);
884390075Sobrien  tree v4sf_ftype_v4sf_v4sf_v4sf
8844117395Skan    = build_function_type_list (V4SF_type_node,
8845117395Skan				V4SF_type_node, V4SF_type_node,
8846117395Skan				V4SF_type_node, NULL_TREE);
8847169689Skan  tree v4si_ftype_v4si_v4si_v4si
8848117395Skan    = build_function_type_list (V4SI_type_node,
8849117395Skan				V4SI_type_node, V4SI_type_node,
8850117395Skan				V4SI_type_node, NULL_TREE);
885190075Sobrien  tree v8hi_ftype_v8hi_v8hi
8852117395Skan    = build_function_type_list (V8HI_type_node,
8853117395Skan				V8HI_type_node, V8HI_type_node, NULL_TREE);
885490075Sobrien  tree v8hi_ftype_v8hi_v8hi_v8hi
8855117395Skan    = build_function_type_list (V8HI_type_node,
8856117395Skan				V8HI_type_node, V8HI_type_node,
8857117395Skan				V8HI_type_node, NULL_TREE);
8858169689Skan  tree v4si_ftype_v8hi_v8hi_v4si
8859117395Skan    = build_function_type_list (V4SI_type_node,
8860117395Skan				V8HI_type_node, V8HI_type_node,
8861117395Skan				V4SI_type_node, NULL_TREE);
8862169689Skan  tree v4si_ftype_v16qi_v16qi_v4si
8863117395Skan    = build_function_type_list (V4SI_type_node,
8864117395Skan				V16QI_type_node, V16QI_type_node,
8865117395Skan				V4SI_type_node, NULL_TREE);
886690075Sobrien  tree v16qi_ftype_v16qi_v16qi
8867117395Skan    = build_function_type_list (V16QI_type_node,
8868117395Skan				V16QI_type_node, V16QI_type_node, NULL_TREE);
886990075Sobrien  tree v4si_ftype_v4sf_v4sf
8870117395Skan    = build_function_type_list (V4SI_type_node,
8871117395Skan				V4SF_type_node, V4SF_type_node, NULL_TREE);
887290075Sobrien  tree v8hi_ftype_v16qi_v16qi
8873117395Skan    = build_function_type_list (V8HI_type_node,
8874117395Skan				V16QI_type_node, V16QI_type_node, NULL_TREE);
887590075Sobrien  tree v4si_ftype_v8hi_v8hi
8876117395Skan    = build_function_type_list (V4SI_type_node,
8877117395Skan				V8HI_type_node, V8HI_type_node, NULL_TREE);
887890075Sobrien  tree v8hi_ftype_v4si_v4si
8879117395Skan    = build_function_type_list (V8HI_type_node,
8880117395Skan				V4SI_type_node, V4SI_type_node, NULL_TREE);
888190075Sobrien  tree v16qi_ftype_v8hi_v8hi
8882117395Skan    = build_function_type_list (V16QI_type_node,
8883117395Skan				V8HI_type_node, V8HI_type_node, NULL_TREE);
888490075Sobrien  tree v4si_ftype_v16qi_v4si
8885117395Skan    = build_function_type_list (V4SI_type_node,
8886117395Skan				V16QI_type_node, V4SI_type_node, NULL_TREE);
888790075Sobrien  tree v4si_ftype_v16qi_v16qi
8888117395Skan    = build_function_type_list (V4SI_type_node,
8889117395Skan				V16QI_type_node, V16QI_type_node, NULL_TREE);
889090075Sobrien  tree v4si_ftype_v8hi_v4si
8891117395Skan    = build_function_type_list (V4SI_type_node,
8892117395Skan				V8HI_type_node, V4SI_type_node, NULL_TREE);
889390075Sobrien  tree v4si_ftype_v8hi
8894117395Skan    = build_function_type_list (V4SI_type_node, V8HI_type_node, NULL_TREE);
889590075Sobrien  tree int_ftype_v4si_v4si
8896117395Skan    = build_function_type_list (integer_type_node,
8897117395Skan				V4SI_type_node, V4SI_type_node, NULL_TREE);
889890075Sobrien  tree int_ftype_v4sf_v4sf
8899117395Skan    = build_function_type_list (integer_type_node,
8900117395Skan				V4SF_type_node, V4SF_type_node, NULL_TREE);
890190075Sobrien  tree int_ftype_v16qi_v16qi
8902117395Skan    = build_function_type_list (integer_type_node,
8903117395Skan				V16QI_type_node, V16QI_type_node, NULL_TREE);
890490075Sobrien  tree int_ftype_v8hi_v8hi
8905117395Skan    = build_function_type_list (integer_type_node,
8906117395Skan				V8HI_type_node, V8HI_type_node, NULL_TREE);
890790075Sobrien
890890075Sobrien  /* Add the simple ternary operators.  */
890990075Sobrien  d = (struct builtin_description *) bdesc_3arg;
8910117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_3arg); i++, d++)
891190075Sobrien    {
891290075Sobrien      enum machine_mode mode0, mode1, mode2, mode3;
891390075Sobrien      tree type;
8914169689Skan      bool is_overloaded = d->code >= ALTIVEC_BUILTIN_OVERLOADED_FIRST
8915169689Skan			   && d->code <= ALTIVEC_BUILTIN_OVERLOADED_LAST;
891690075Sobrien
8917169689Skan      if (is_overloaded)
8918169689Skan	{
8919169689Skan          mode0 = VOIDmode;
8920169689Skan          mode1 = VOIDmode;
8921169689Skan          mode2 = VOIDmode;
8922169689Skan          mode3 = VOIDmode;
8923169689Skan	}
8924169689Skan      else
8925169689Skan	{
8926169689Skan          if (d->name == 0 || d->icode == CODE_FOR_nothing)
8927169689Skan	    continue;
8928169689Skan
8929169689Skan          mode0 = insn_data[d->icode].operand[0].mode;
8930169689Skan          mode1 = insn_data[d->icode].operand[1].mode;
8931169689Skan          mode2 = insn_data[d->icode].operand[2].mode;
8932169689Skan          mode3 = insn_data[d->icode].operand[3].mode;
8933169689Skan	}
8934169689Skan
893590075Sobrien      /* When all four are of the same mode.  */
893690075Sobrien      if (mode0 == mode1 && mode1 == mode2 && mode2 == mode3)
893790075Sobrien	{
893890075Sobrien	  switch (mode0)
893990075Sobrien	    {
8940169689Skan	    case VOIDmode:
8941169689Skan	      type = opaque_ftype_opaque_opaque_opaque;
8942169689Skan	      break;
894390075Sobrien	    case V4SImode:
894490075Sobrien	      type = v4si_ftype_v4si_v4si_v4si;
894590075Sobrien	      break;
894690075Sobrien	    case V4SFmode:
894790075Sobrien	      type = v4sf_ftype_v4sf_v4sf_v4sf;
894890075Sobrien	      break;
894990075Sobrien	    case V8HImode:
895090075Sobrien	      type = v8hi_ftype_v8hi_v8hi_v8hi;
8951169689Skan	      break;
895290075Sobrien	    case V16QImode:
895390075Sobrien	      type = v16qi_ftype_v16qi_v16qi_v16qi;
8954169689Skan	      break;
895590075Sobrien	    default:
8956169689Skan	      gcc_unreachable ();
895790075Sobrien	    }
895890075Sobrien	}
895990075Sobrien      else if (mode0 == mode1 && mode1 == mode2 && mode3 == V16QImode)
8960169689Skan	{
896190075Sobrien	  switch (mode0)
896290075Sobrien	    {
896390075Sobrien	    case V4SImode:
896490075Sobrien	      type = v4si_ftype_v4si_v4si_v16qi;
896590075Sobrien	      break;
896690075Sobrien	    case V4SFmode:
896790075Sobrien	      type = v4sf_ftype_v4sf_v4sf_v16qi;
896890075Sobrien	      break;
896990075Sobrien	    case V8HImode:
897090075Sobrien	      type = v8hi_ftype_v8hi_v8hi_v16qi;
8971169689Skan	      break;
897290075Sobrien	    case V16QImode:
897390075Sobrien	      type = v16qi_ftype_v16qi_v16qi_v16qi;
8974169689Skan	      break;
897590075Sobrien	    default:
8976169689Skan	      gcc_unreachable ();
897790075Sobrien	    }
897890075Sobrien	}
8979169689Skan      else if (mode0 == V4SImode && mode1 == V16QImode && mode2 == V16QImode
898090075Sobrien	       && mode3 == V4SImode)
898190075Sobrien	type = v4si_ftype_v16qi_v16qi_v4si;
8982169689Skan      else if (mode0 == V4SImode && mode1 == V8HImode && mode2 == V8HImode
898390075Sobrien	       && mode3 == V4SImode)
898490075Sobrien	type = v4si_ftype_v8hi_v8hi_v4si;
8985169689Skan      else if (mode0 == V4SFmode && mode1 == V4SFmode && mode2 == V4SFmode
898690075Sobrien	       && mode3 == V4SImode)
898790075Sobrien	type = v4sf_ftype_v4sf_v4sf_v4si;
898890075Sobrien
898990075Sobrien      /* vchar, vchar, vchar, 4 bit literal.  */
899090075Sobrien      else if (mode0 == V16QImode && mode1 == mode0 && mode2 == mode0
899190075Sobrien	       && mode3 == QImode)
8992146895Skan	type = v16qi_ftype_v16qi_v16qi_int;
899390075Sobrien
899490075Sobrien      /* vshort, vshort, vshort, 4 bit literal.  */
899590075Sobrien      else if (mode0 == V8HImode && mode1 == mode0 && mode2 == mode0
899690075Sobrien	       && mode3 == QImode)
8997146895Skan	type = v8hi_ftype_v8hi_v8hi_int;
899890075Sobrien
899990075Sobrien      /* vint, vint, vint, 4 bit literal.  */
900090075Sobrien      else if (mode0 == V4SImode && mode1 == mode0 && mode2 == mode0
900190075Sobrien	       && mode3 == QImode)
9002146895Skan	type = v4si_ftype_v4si_v4si_int;
900390075Sobrien
900490075Sobrien      /* vfloat, vfloat, vfloat, 4 bit literal.  */
900590075Sobrien      else if (mode0 == V4SFmode && mode1 == mode0 && mode2 == mode0
900690075Sobrien	       && mode3 == QImode)
9007146895Skan	type = v4sf_ftype_v4sf_v4sf_int;
900890075Sobrien
900990075Sobrien      else
9010169689Skan	gcc_unreachable ();
901190075Sobrien
901290075Sobrien      def_builtin (d->mask, d->name, type, d->code);
901390075Sobrien    }
901490075Sobrien
901590075Sobrien  /* Add the simple binary operators.  */
901690075Sobrien  d = (struct builtin_description *) bdesc_2arg;
9017117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
901890075Sobrien    {
901990075Sobrien      enum machine_mode mode0, mode1, mode2;
902090075Sobrien      tree type;
9021169689Skan      bool is_overloaded = d->code >= ALTIVEC_BUILTIN_OVERLOADED_FIRST
9022169689Skan			   && d->code <= ALTIVEC_BUILTIN_OVERLOADED_LAST;
902390075Sobrien
9024169689Skan      if (is_overloaded)
9025169689Skan	{
9026169689Skan	  mode0 = VOIDmode;
9027169689Skan	  mode1 = VOIDmode;
9028169689Skan	  mode2 = VOIDmode;
9029169689Skan	}
9030169689Skan      else
9031169689Skan	{
9032169689Skan          if (d->name == 0 || d->icode == CODE_FOR_nothing)
9033169689Skan	    continue;
903490075Sobrien
9035169689Skan          mode0 = insn_data[d->icode].operand[0].mode;
9036169689Skan          mode1 = insn_data[d->icode].operand[1].mode;
9037169689Skan          mode2 = insn_data[d->icode].operand[2].mode;
9038169689Skan	}
9039169689Skan
904090075Sobrien      /* When all three operands are of the same mode.  */
904190075Sobrien      if (mode0 == mode1 && mode1 == mode2)
904290075Sobrien	{
904390075Sobrien	  switch (mode0)
904490075Sobrien	    {
9045169689Skan	    case VOIDmode:
9046169689Skan	      type = opaque_ftype_opaque_opaque;
9047169689Skan	      break;
904890075Sobrien	    case V4SFmode:
904990075Sobrien	      type = v4sf_ftype_v4sf_v4sf;
905090075Sobrien	      break;
905190075Sobrien	    case V4SImode:
905290075Sobrien	      type = v4si_ftype_v4si_v4si;
905390075Sobrien	      break;
905490075Sobrien	    case V16QImode:
905590075Sobrien	      type = v16qi_ftype_v16qi_v16qi;
905690075Sobrien	      break;
905790075Sobrien	    case V8HImode:
905890075Sobrien	      type = v8hi_ftype_v8hi_v8hi;
905990075Sobrien	      break;
9060117395Skan	    case V2SImode:
9061117395Skan	      type = v2si_ftype_v2si_v2si;
9062117395Skan	      break;
9063117395Skan	    case V2SFmode:
9064117395Skan	      type = v2sf_ftype_v2sf_v2sf;
9065117395Skan	      break;
9066117395Skan	    case SImode:
9067117395Skan	      type = int_ftype_int_int;
9068117395Skan	      break;
906990075Sobrien	    default:
9070169689Skan	      gcc_unreachable ();
907190075Sobrien	    }
907290075Sobrien	}
907390075Sobrien
907490075Sobrien      /* A few other combos we really don't want to do manually.  */
907590075Sobrien
907690075Sobrien      /* vint, vfloat, vfloat.  */
907790075Sobrien      else if (mode0 == V4SImode && mode1 == V4SFmode && mode2 == V4SFmode)
907890075Sobrien	type = v4si_ftype_v4sf_v4sf;
907990075Sobrien
908090075Sobrien      /* vshort, vchar, vchar.  */
908190075Sobrien      else if (mode0 == V8HImode && mode1 == V16QImode && mode2 == V16QImode)
908290075Sobrien	type = v8hi_ftype_v16qi_v16qi;
908390075Sobrien
908490075Sobrien      /* vint, vshort, vshort.  */
908590075Sobrien      else if (mode0 == V4SImode && mode1 == V8HImode && mode2 == V8HImode)
908690075Sobrien	type = v4si_ftype_v8hi_v8hi;
908790075Sobrien
908890075Sobrien      /* vshort, vint, vint.  */
908990075Sobrien      else if (mode0 == V8HImode && mode1 == V4SImode && mode2 == V4SImode)
909090075Sobrien	type = v8hi_ftype_v4si_v4si;
909190075Sobrien
909290075Sobrien      /* vchar, vshort, vshort.  */
909390075Sobrien      else if (mode0 == V16QImode && mode1 == V8HImode && mode2 == V8HImode)
909490075Sobrien	type = v16qi_ftype_v8hi_v8hi;
909590075Sobrien
909690075Sobrien      /* vint, vchar, vint.  */
909790075Sobrien      else if (mode0 == V4SImode && mode1 == V16QImode && mode2 == V4SImode)
909890075Sobrien	type = v4si_ftype_v16qi_v4si;
909990075Sobrien
910090075Sobrien      /* vint, vchar, vchar.  */
910190075Sobrien      else if (mode0 == V4SImode && mode1 == V16QImode && mode2 == V16QImode)
910290075Sobrien	type = v4si_ftype_v16qi_v16qi;
910390075Sobrien
910490075Sobrien      /* vint, vshort, vint.  */
910590075Sobrien      else if (mode0 == V4SImode && mode1 == V8HImode && mode2 == V4SImode)
910690075Sobrien	type = v4si_ftype_v8hi_v4si;
9107169689Skan
910890075Sobrien      /* vint, vint, 5 bit literal.  */
910990075Sobrien      else if (mode0 == V4SImode && mode1 == V4SImode && mode2 == QImode)
9110146895Skan	type = v4si_ftype_v4si_int;
9111169689Skan
911290075Sobrien      /* vshort, vshort, 5 bit literal.  */
911390075Sobrien      else if (mode0 == V8HImode && mode1 == V8HImode && mode2 == QImode)
9114146895Skan	type = v8hi_ftype_v8hi_int;
9115169689Skan
911690075Sobrien      /* vchar, vchar, 5 bit literal.  */
911790075Sobrien      else if (mode0 == V16QImode && mode1 == V16QImode && mode2 == QImode)
9118146895Skan	type = v16qi_ftype_v16qi_int;
911990075Sobrien
912090075Sobrien      /* vfloat, vint, 5 bit literal.  */
912190075Sobrien      else if (mode0 == V4SFmode && mode1 == V4SImode && mode2 == QImode)
9122146895Skan	type = v4sf_ftype_v4si_int;
9123169689Skan
912490075Sobrien      /* vint, vfloat, 5 bit literal.  */
912590075Sobrien      else if (mode0 == V4SImode && mode1 == V4SFmode && mode2 == QImode)
9126146895Skan	type = v4si_ftype_v4sf_int;
912790075Sobrien
9128117395Skan      else if (mode0 == V2SImode && mode1 == SImode && mode2 == SImode)
9129117395Skan	type = v2si_ftype_int_int;
9130117395Skan
9131117395Skan      else if (mode0 == V2SImode && mode1 == V2SImode && mode2 == QImode)
9132117395Skan	type = v2si_ftype_v2si_char;
9133117395Skan
9134117395Skan      else if (mode0 == V2SImode && mode1 == SImode && mode2 == QImode)
9135117395Skan	type = v2si_ftype_int_char;
9136117395Skan
9137169689Skan      else
913890075Sobrien	{
9139169689Skan	  /* int, x, x.  */
9140169689Skan	  gcc_assert (mode0 == SImode);
914190075Sobrien	  switch (mode1)
914290075Sobrien	    {
914390075Sobrien	    case V4SImode:
914490075Sobrien	      type = int_ftype_v4si_v4si;
914590075Sobrien	      break;
914690075Sobrien	    case V4SFmode:
914790075Sobrien	      type = int_ftype_v4sf_v4sf;
914890075Sobrien	      break;
914990075Sobrien	    case V16QImode:
915090075Sobrien	      type = int_ftype_v16qi_v16qi;
915190075Sobrien	      break;
915290075Sobrien	    case V8HImode:
915390075Sobrien	      type = int_ftype_v8hi_v8hi;
915490075Sobrien	      break;
915590075Sobrien	    default:
9156169689Skan	      gcc_unreachable ();
915790075Sobrien	    }
915890075Sobrien	}
915990075Sobrien
916090075Sobrien      def_builtin (d->mask, d->name, type, d->code);
916190075Sobrien    }
916290075Sobrien
916390075Sobrien  /* Add the simple unary operators.  */
916490075Sobrien  d = (struct builtin_description *) bdesc_1arg;
9165117395Skan  for (i = 0; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
916690075Sobrien    {
916790075Sobrien      enum machine_mode mode0, mode1;
916890075Sobrien      tree type;
9169169689Skan      bool is_overloaded = d->code >= ALTIVEC_BUILTIN_OVERLOADED_FIRST
9170169689Skan			   && d->code <= ALTIVEC_BUILTIN_OVERLOADED_LAST;
917190075Sobrien
9172169689Skan      if (is_overloaded)
9173169689Skan        {
9174169689Skan          mode0 = VOIDmode;
9175169689Skan          mode1 = VOIDmode;
9176169689Skan        }
9177169689Skan      else
9178169689Skan        {
9179169689Skan          if (d->name == 0 || d->icode == CODE_FOR_nothing)
9180169689Skan	    continue;
918190075Sobrien
9182169689Skan          mode0 = insn_data[d->icode].operand[0].mode;
9183169689Skan          mode1 = insn_data[d->icode].operand[1].mode;
9184169689Skan        }
9185169689Skan
918690075Sobrien      if (mode0 == V4SImode && mode1 == QImode)
9187169689Skan	type = v4si_ftype_int;
918890075Sobrien      else if (mode0 == V8HImode && mode1 == QImode)
9189169689Skan	type = v8hi_ftype_int;
919090075Sobrien      else if (mode0 == V16QImode && mode1 == QImode)
9191169689Skan	type = v16qi_ftype_int;
9192169689Skan      else if (mode0 == VOIDmode && mode1 == VOIDmode)
9193169689Skan	type = opaque_ftype_opaque;
919490075Sobrien      else if (mode0 == V4SFmode && mode1 == V4SFmode)
919590075Sobrien	type = v4sf_ftype_v4sf;
919690075Sobrien      else if (mode0 == V8HImode && mode1 == V16QImode)
919790075Sobrien	type = v8hi_ftype_v16qi;
919890075Sobrien      else if (mode0 == V4SImode && mode1 == V8HImode)
919990075Sobrien	type = v4si_ftype_v8hi;
9200117395Skan      else if (mode0 == V2SImode && mode1 == V2SImode)
9201117395Skan	type = v2si_ftype_v2si;
9202117395Skan      else if (mode0 == V2SFmode && mode1 == V2SFmode)
9203117395Skan	type = v2sf_ftype_v2sf;
9204117395Skan      else if (mode0 == V2SFmode && mode1 == V2SImode)
9205117395Skan	type = v2sf_ftype_v2si;
9206117395Skan      else if (mode0 == V2SImode && mode1 == V2SFmode)
9207117395Skan	type = v2si_ftype_v2sf;
9208117395Skan      else if (mode0 == V2SImode && mode1 == QImode)
9209117395Skan	type = v2si_ftype_char;
921090075Sobrien      else
9211169689Skan	gcc_unreachable ();
921290075Sobrien
921390075Sobrien      def_builtin (d->mask, d->name, type, d->code);
921490075Sobrien    }
921590075Sobrien}
921690075Sobrien
9217132718Skanstatic void
9218132718Skanrs6000_init_libfuncs (void)
9219132718Skan{
9220169689Skan  if (DEFAULT_ABI != ABI_V4 && TARGET_XCOFF
9221169689Skan      && !TARGET_POWER2 && !TARGET_POWERPC)
9222132718Skan    {
9223169689Skan      /* AIX library routines for float->int conversion.  */
9224169689Skan      set_conv_libfunc (sfix_optab, SImode, DFmode, "__itrunc");
9225169689Skan      set_conv_libfunc (ufix_optab, SImode, DFmode, "__uitrunc");
9226169689Skan      set_conv_libfunc (sfix_optab, SImode, TFmode, "_qitrunc");
9227169689Skan      set_conv_libfunc (ufix_optab, SImode, TFmode, "_quitrunc");
9228169689Skan    }
9229132718Skan
9230169689Skan  if (!TARGET_IEEEQUAD)
9231146895Skan      /* AIX/Darwin/64-bit Linux quad floating point routines.  */
9232169689Skan    if (!TARGET_XL_COMPAT)
9233169689Skan      {
9234169689Skan	set_optab_libfunc (add_optab, TFmode, "__gcc_qadd");
9235169689Skan	set_optab_libfunc (sub_optab, TFmode, "__gcc_qsub");
9236169689Skan	set_optab_libfunc (smul_optab, TFmode, "__gcc_qmul");
9237169689Skan	set_optab_libfunc (sdiv_optab, TFmode, "__gcc_qdiv");
9238169689Skan
9239169689Skan	if (TARGET_SOFT_FLOAT)
9240169689Skan	  {
9241169689Skan	    set_optab_libfunc (neg_optab, TFmode, "__gcc_qneg");
9242169689Skan	    set_optab_libfunc (eq_optab, TFmode, "__gcc_qeq");
9243169689Skan	    set_optab_libfunc (ne_optab, TFmode, "__gcc_qne");
9244169689Skan	    set_optab_libfunc (gt_optab, TFmode, "__gcc_qgt");
9245169689Skan	    set_optab_libfunc (ge_optab, TFmode, "__gcc_qge");
9246169689Skan	    set_optab_libfunc (lt_optab, TFmode, "__gcc_qlt");
9247169689Skan	    set_optab_libfunc (le_optab, TFmode, "__gcc_qle");
9248169689Skan	    set_optab_libfunc (unord_optab, TFmode, "__gcc_qunord");
9249169689Skan
9250169689Skan	    set_conv_libfunc (sext_optab, TFmode, SFmode, "__gcc_stoq");
9251169689Skan	    set_conv_libfunc (sext_optab, TFmode, DFmode, "__gcc_dtoq");
9252169689Skan	    set_conv_libfunc (trunc_optab, SFmode, TFmode, "__gcc_qtos");
9253169689Skan	    set_conv_libfunc (trunc_optab, DFmode, TFmode, "__gcc_qtod");
9254169689Skan	    set_conv_libfunc (sfix_optab, SImode, TFmode, "__gcc_qtoi");
9255169689Skan	    set_conv_libfunc (ufix_optab, SImode, TFmode, "__gcc_qtou");
9256169689Skan	    set_conv_libfunc (sfloat_optab, TFmode, SImode, "__gcc_itoq");
9257169689Skan	    set_conv_libfunc (ufloat_optab, TFmode, SImode, "__gcc_utoq");
9258169689Skan	  }
9259169689Skan      }
9260169689Skan    else
9261169689Skan      {
9262169689Skan	set_optab_libfunc (add_optab, TFmode, "_xlqadd");
9263169689Skan	set_optab_libfunc (sub_optab, TFmode, "_xlqsub");
9264169689Skan	set_optab_libfunc (smul_optab, TFmode, "_xlqmul");
9265169689Skan	set_optab_libfunc (sdiv_optab, TFmode, "_xlqdiv");
9266169689Skan      }
9267132718Skan  else
9268132718Skan    {
9269132718Skan      /* 32-bit SVR4 quad floating point routines.  */
9270132718Skan
9271132718Skan      set_optab_libfunc (add_optab, TFmode, "_q_add");
9272132718Skan      set_optab_libfunc (sub_optab, TFmode, "_q_sub");
9273132718Skan      set_optab_libfunc (neg_optab, TFmode, "_q_neg");
9274132718Skan      set_optab_libfunc (smul_optab, TFmode, "_q_mul");
9275132718Skan      set_optab_libfunc (sdiv_optab, TFmode, "_q_div");
9276132718Skan      if (TARGET_PPC_GPOPT || TARGET_POWER2)
9277132718Skan	set_optab_libfunc (sqrt_optab, TFmode, "_q_sqrt");
9278132718Skan
9279132718Skan      set_optab_libfunc (eq_optab, TFmode, "_q_feq");
9280132718Skan      set_optab_libfunc (ne_optab, TFmode, "_q_fne");
9281132718Skan      set_optab_libfunc (gt_optab, TFmode, "_q_fgt");
9282132718Skan      set_optab_libfunc (ge_optab, TFmode, "_q_fge");
9283132718Skan      set_optab_libfunc (lt_optab, TFmode, "_q_flt");
9284132718Skan      set_optab_libfunc (le_optab, TFmode, "_q_fle");
9285132718Skan
9286132718Skan      set_conv_libfunc (sext_optab, TFmode, SFmode, "_q_stoq");
9287132718Skan      set_conv_libfunc (sext_optab, TFmode, DFmode, "_q_dtoq");
9288132718Skan      set_conv_libfunc (trunc_optab, SFmode, TFmode, "_q_qtos");
9289132718Skan      set_conv_libfunc (trunc_optab, DFmode, TFmode, "_q_qtod");
9290132718Skan      set_conv_libfunc (sfix_optab, SImode, TFmode, "_q_qtoi");
9291132718Skan      set_conv_libfunc (ufix_optab, SImode, TFmode, "_q_qtou");
9292132718Skan      set_conv_libfunc (sfloat_optab, TFmode, SImode, "_q_itoq");
9293169689Skan      set_conv_libfunc (ufloat_optab, TFmode, SImode, "_q_utoq");
9294132718Skan    }
9295132718Skan}
9296169689Skan
929790075Sobrien
9298169689Skan/* Expand a block clear operation, and return 1 if successful.  Return 0
9299169689Skan   if we should let the compiler generate normal code.
9300169689Skan
9301169689Skan   operands[0] is the destination
9302169689Skan   operands[1] is the length
9303169689Skan   operands[3] is the alignment */
9304169689Skan
9305169689Skanint
9306169689Skanexpand_block_clear (rtx operands[])
9307169689Skan{
9308169689Skan  rtx orig_dest = operands[0];
9309169689Skan  rtx bytes_rtx	= operands[1];
9310169689Skan  rtx align_rtx = operands[3];
9311169689Skan  bool constp	= (GET_CODE (bytes_rtx) == CONST_INT);
9312169689Skan  HOST_WIDE_INT align;
9313169689Skan  HOST_WIDE_INT bytes;
9314169689Skan  int offset;
9315169689Skan  int clear_bytes;
9316169689Skan  int clear_step;
9317169689Skan
9318169689Skan  /* If this is not a fixed size move, just call memcpy */
9319169689Skan  if (! constp)
9320169689Skan    return 0;
9321169689Skan
9322169689Skan  /* This must be a fixed size alignment  */
9323169689Skan  gcc_assert (GET_CODE (align_rtx) == CONST_INT);
9324169689Skan  align = INTVAL (align_rtx) * BITS_PER_UNIT;
9325169689Skan
9326169689Skan  /* Anything to clear? */
9327169689Skan  bytes = INTVAL (bytes_rtx);
9328169689Skan  if (bytes <= 0)
9329169689Skan    return 1;
9330169689Skan
9331169689Skan  /* Use the builtin memset after a point, to avoid huge code bloat.
9332169689Skan     When optimize_size, avoid any significant code bloat; calling
9333169689Skan     memset is about 4 instructions, so allow for one instruction to
9334169689Skan     load zero and three to do clearing.  */
9335169689Skan  if (TARGET_ALTIVEC && align >= 128)
9336169689Skan    clear_step = 16;
9337169689Skan  else if (TARGET_POWERPC64 && align >= 32)
9338169689Skan    clear_step = 8;
9339169689Skan  else
9340169689Skan    clear_step = 4;
9341169689Skan
9342169689Skan  if (optimize_size && bytes > 3 * clear_step)
9343169689Skan    return 0;
9344169689Skan  if (! optimize_size && bytes > 8 * clear_step)
9345169689Skan    return 0;
9346169689Skan
9347169689Skan  for (offset = 0; bytes > 0; offset += clear_bytes, bytes -= clear_bytes)
9348169689Skan    {
9349169689Skan      enum machine_mode mode = BLKmode;
9350169689Skan      rtx dest;
9351169689Skan
9352169689Skan      if (bytes >= 16 && TARGET_ALTIVEC && align >= 128)
9353169689Skan	{
9354169689Skan	  clear_bytes = 16;
9355169689Skan	  mode = V4SImode;
9356169689Skan	}
9357169689Skan      else if (bytes >= 8 && TARGET_POWERPC64
9358169689Skan	  /* 64-bit loads and stores require word-aligned
9359169689Skan	     displacements.  */
9360169689Skan	  && (align >= 64 || (!STRICT_ALIGNMENT && align >= 32)))
9361169689Skan	{
9362169689Skan	  clear_bytes = 8;
9363169689Skan	  mode = DImode;
9364169689Skan	}
9365169689Skan      else if (bytes >= 4 && (align >= 32 || !STRICT_ALIGNMENT))
9366169689Skan	{			/* move 4 bytes */
9367169689Skan	  clear_bytes = 4;
9368169689Skan	  mode = SImode;
9369169689Skan	}
9370169689Skan      else if (bytes >= 2 && (align >= 16 || !STRICT_ALIGNMENT))
9371169689Skan	{			/* move 2 bytes */
9372169689Skan	  clear_bytes = 2;
9373169689Skan	  mode = HImode;
9374169689Skan	}
9375169689Skan      else /* move 1 byte at a time */
9376169689Skan	{
9377169689Skan	  clear_bytes = 1;
9378169689Skan	  mode = QImode;
9379169689Skan	}
9380169689Skan
9381169689Skan      dest = adjust_address (orig_dest, mode, offset);
9382169689Skan
9383169689Skan      emit_move_insn (dest, CONST0_RTX (mode));
9384169689Skan    }
9385169689Skan
9386169689Skan  return 1;
9387169689Skan}
9388169689Skan
9389169689Skan
939090075Sobrien/* Expand a block move operation, and return 1 if successful.  Return 0
939190075Sobrien   if we should let the compiler generate normal code.
939290075Sobrien
939390075Sobrien   operands[0] is the destination
939490075Sobrien   operands[1] is the source
939590075Sobrien   operands[2] is the length
939690075Sobrien   operands[3] is the alignment */
939790075Sobrien
939890075Sobrien#define MAX_MOVE_REG 4
939990075Sobrien
940090075Sobrienint
9401132718Skanexpand_block_move (rtx operands[])
940290075Sobrien{
940390075Sobrien  rtx orig_dest = operands[0];
940490075Sobrien  rtx orig_src	= operands[1];
940590075Sobrien  rtx bytes_rtx	= operands[2];
940690075Sobrien  rtx align_rtx = operands[3];
940790075Sobrien  int constp	= (GET_CODE (bytes_rtx) == CONST_INT);
940890075Sobrien  int align;
940990075Sobrien  int bytes;
941090075Sobrien  int offset;
941190075Sobrien  int move_bytes;
9412132718Skan  rtx stores[MAX_MOVE_REG];
9413132718Skan  int num_reg = 0;
941490075Sobrien
941590075Sobrien  /* If this is not a fixed size move, just call memcpy */
941690075Sobrien  if (! constp)
941790075Sobrien    return 0;
941890075Sobrien
9419169689Skan  /* This must be a fixed size alignment */
9420169689Skan  gcc_assert (GET_CODE (align_rtx) == CONST_INT);
9421169689Skan  align = INTVAL (align_rtx) * BITS_PER_UNIT;
942290075Sobrien
942390075Sobrien  /* Anything to move? */
942490075Sobrien  bytes = INTVAL (bytes_rtx);
942590075Sobrien  if (bytes <= 0)
942690075Sobrien    return 1;
942790075Sobrien
942890075Sobrien  /* store_one_arg depends on expand_block_move to handle at least the size of
9429169689Skan     reg_parm_stack_space.  */
943090075Sobrien  if (bytes > (TARGET_POWERPC64 ? 64 : 32))
943190075Sobrien    return 0;
943290075Sobrien
9433132718Skan  for (offset = 0; bytes > 0; offset += move_bytes, bytes -= move_bytes)
943490075Sobrien    {
9435132718Skan      union {
9436169689Skan	rtx (*movmemsi) (rtx, rtx, rtx, rtx);
9437132718Skan	rtx (*mov) (rtx, rtx);
9438132718Skan      } gen_func;
9439132718Skan      enum machine_mode mode = BLKmode;
9440132718Skan      rtx src, dest;
9441169689Skan
9442169689Skan      /* Altivec first, since it will be faster than a string move
9443169689Skan	 when it applies, and usually not significantly larger.  */
9444169689Skan      if (TARGET_ALTIVEC && bytes >= 16 && align >= 128)
9445169689Skan	{
9446169689Skan	  move_bytes = 16;
9447169689Skan	  mode = V4SImode;
9448169689Skan	  gen_func.mov = gen_movv4si;
9449169689Skan	}
9450169689Skan      else if (TARGET_STRING
9451132718Skan	  && bytes > 24		/* move up to 32 bytes at a time */
9452132718Skan	  && ! fixed_regs[5]
9453132718Skan	  && ! fixed_regs[6]
9454132718Skan	  && ! fixed_regs[7]
9455132718Skan	  && ! fixed_regs[8]
9456132718Skan	  && ! fixed_regs[9]
9457132718Skan	  && ! fixed_regs[10]
9458132718Skan	  && ! fixed_regs[11]
9459132718Skan	  && ! fixed_regs[12])
946090075Sobrien	{
9461132718Skan	  move_bytes = (bytes > 32) ? 32 : bytes;
9462169689Skan	  gen_func.movmemsi = gen_movmemsi_8reg;
9463132718Skan	}
9464132718Skan      else if (TARGET_STRING
9465132718Skan	       && bytes > 16	/* move up to 24 bytes at a time */
9466132718Skan	       && ! fixed_regs[5]
9467132718Skan	       && ! fixed_regs[6]
9468132718Skan	       && ! fixed_regs[7]
9469132718Skan	       && ! fixed_regs[8]
9470132718Skan	       && ! fixed_regs[9]
9471132718Skan	       && ! fixed_regs[10])
9472132718Skan	{
9473132718Skan	  move_bytes = (bytes > 24) ? 24 : bytes;
9474169689Skan	  gen_func.movmemsi = gen_movmemsi_6reg;
9475132718Skan	}
9476132718Skan      else if (TARGET_STRING
9477132718Skan	       && bytes > 8	/* move up to 16 bytes at a time */
9478132718Skan	       && ! fixed_regs[5]
9479132718Skan	       && ! fixed_regs[6]
9480132718Skan	       && ! fixed_regs[7]
9481132718Skan	       && ! fixed_regs[8])
9482132718Skan	{
9483132718Skan	  move_bytes = (bytes > 16) ? 16 : bytes;
9484169689Skan	  gen_func.movmemsi = gen_movmemsi_4reg;
9485132718Skan	}
9486132718Skan      else if (bytes >= 8 && TARGET_POWERPC64
9487132718Skan	       /* 64-bit loads and stores require word-aligned
9488132718Skan		  displacements.  */
9489169689Skan	       && (align >= 64 || (!STRICT_ALIGNMENT && align >= 32)))
9490132718Skan	{
9491132718Skan	  move_bytes = 8;
9492132718Skan	  mode = DImode;
9493132718Skan	  gen_func.mov = gen_movdi;
9494132718Skan	}
9495132718Skan      else if (TARGET_STRING && bytes > 4 && !TARGET_POWERPC64)
9496132718Skan	{			/* move up to 8 bytes at a time */
9497132718Skan	  move_bytes = (bytes > 8) ? 8 : bytes;
9498169689Skan	  gen_func.movmemsi = gen_movmemsi_2reg;
9499132718Skan	}
9500169689Skan      else if (bytes >= 4 && (align >= 32 || !STRICT_ALIGNMENT))
9501132718Skan	{			/* move 4 bytes */
9502132718Skan	  move_bytes = 4;
9503132718Skan	  mode = SImode;
9504132718Skan	  gen_func.mov = gen_movsi;
9505132718Skan	}
9506169689Skan      else if (bytes >= 2 && (align >= 16 || !STRICT_ALIGNMENT))
9507132718Skan	{			/* move 2 bytes */
9508132718Skan	  move_bytes = 2;
9509132718Skan	  mode = HImode;
9510132718Skan	  gen_func.mov = gen_movhi;
9511132718Skan	}
9512132718Skan      else if (TARGET_STRING && bytes > 1)
9513132718Skan	{			/* move up to 4 bytes at a time */
9514132718Skan	  move_bytes = (bytes > 4) ? 4 : bytes;
9515169689Skan	  gen_func.movmemsi = gen_movmemsi_1reg;
9516132718Skan	}
9517132718Skan      else /* move 1 byte at a time */
9518132718Skan	{
9519132718Skan	  move_bytes = 1;
9520132718Skan	  mode = QImode;
9521132718Skan	  gen_func.mov = gen_movqi;
9522132718Skan	}
9523169689Skan
9524132718Skan      src = adjust_address (orig_src, mode, offset);
9525132718Skan      dest = adjust_address (orig_dest, mode, offset);
9526169689Skan
9527169689Skan      if (mode != BLKmode)
9528132718Skan	{
9529132718Skan	  rtx tmp_reg = gen_reg_rtx (mode);
9530169689Skan
9531132718Skan	  emit_insn ((*gen_func.mov) (tmp_reg, src));
9532132718Skan	  stores[num_reg++] = (*gen_func.mov) (dest, tmp_reg);
9533132718Skan	}
9534103445Skan
9535132718Skan      if (mode == BLKmode || num_reg >= MAX_MOVE_REG || bytes == move_bytes)
9536132718Skan	{
9537132718Skan	  int i;
9538132718Skan	  for (i = 0; i < num_reg; i++)
9539132718Skan	    emit_insn (stores[i]);
9540132718Skan	  num_reg = 0;
954190075Sobrien	}
954290075Sobrien
9543132718Skan      if (mode == BLKmode)
954490075Sobrien	{
9545169689Skan	  /* Move the address into scratch registers.  The movmemsi
9546132718Skan	     patterns require zero offset.  */
9547132718Skan	  if (!REG_P (XEXP (src, 0)))
954890075Sobrien	    {
9549132718Skan	      rtx src_reg = copy_addr_to_reg (XEXP (src, 0));
9550132718Skan	      src = replace_equiv_address (src, src_reg);
955190075Sobrien	    }
9552132718Skan	  set_mem_size (src, GEN_INT (move_bytes));
9553169689Skan
9554132718Skan	  if (!REG_P (XEXP (dest, 0)))
955590075Sobrien	    {
9556132718Skan	      rtx dest_reg = copy_addr_to_reg (XEXP (dest, 0));
9557132718Skan	      dest = replace_equiv_address (dest, dest_reg);
955890075Sobrien	    }
9559132718Skan	  set_mem_size (dest, GEN_INT (move_bytes));
9560169689Skan
9561169689Skan	  emit_insn ((*gen_func.movmemsi) (dest, src,
9562132718Skan					   GEN_INT (move_bytes & 31),
9563132718Skan					   align_rtx));
956490075Sobrien	}
956590075Sobrien    }
956690075Sobrien
956790075Sobrien  return 1;
956890075Sobrien}
956990075Sobrien
957090075Sobrien
9571110611Skan/* Return a string to perform a load_multiple operation.
9572110611Skan   operands[0] is the vector.
9573110611Skan   operands[1] is the source address.
9574110611Skan   operands[2] is the first destination register.  */
9575110611Skan
9576110611Skanconst char *
9577132718Skanrs6000_output_load_multiple (rtx operands[3])
9578110611Skan{
9579110611Skan  /* We have to handle the case where the pseudo used to contain the address
9580110611Skan     is assigned to one of the output registers.  */
9581110611Skan  int i, j;
9582110611Skan  int words = XVECLEN (operands[0], 0);
9583110611Skan  rtx xop[10];
9584110611Skan
9585110611Skan  if (XVECLEN (operands[0], 0) == 1)
9586110611Skan    return "{l|lwz} %2,0(%1)";
9587110611Skan
9588110611Skan  for (i = 0; i < words; i++)
9589110611Skan    if (refers_to_regno_p (REGNO (operands[2]) + i,
9590110611Skan			   REGNO (operands[2]) + i + 1, operands[1], 0))
9591110611Skan      {
9592110611Skan	if (i == words-1)
9593110611Skan	  {
9594110611Skan	    xop[0] = GEN_INT (4 * (words-1));
9595110611Skan	    xop[1] = operands[1];
9596110611Skan	    xop[2] = operands[2];
9597110611Skan	    output_asm_insn ("{lsi|lswi} %2,%1,%0\n\t{l|lwz} %1,%0(%1)", xop);
9598110611Skan	    return "";
9599110611Skan	  }
9600110611Skan	else if (i == 0)
9601110611Skan	  {
9602110611Skan	    xop[0] = GEN_INT (4 * (words-1));
9603110611Skan	    xop[1] = operands[1];
9604110611Skan	    xop[2] = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
9605110611Skan	    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);
9606110611Skan	    return "";
9607110611Skan	  }
9608110611Skan	else
9609110611Skan	  {
9610110611Skan	    for (j = 0; j < words; j++)
9611110611Skan	      if (j != i)
9612110611Skan		{
9613110611Skan		  xop[0] = GEN_INT (j * 4);
9614110611Skan		  xop[1] = operands[1];
9615110611Skan		  xop[2] = gen_rtx_REG (SImode, REGNO (operands[2]) + j);
9616110611Skan		  output_asm_insn ("{l|lwz} %2,%0(%1)", xop);
9617110611Skan		}
9618110611Skan	    xop[0] = GEN_INT (i * 4);
9619110611Skan	    xop[1] = operands[1];
9620110611Skan	    output_asm_insn ("{l|lwz} %1,%0(%1)", xop);
9621110611Skan	    return "";
9622110611Skan	  }
9623110611Skan      }
9624110611Skan
9625110611Skan  return "{lsi|lswi} %2,%1,%N0";
9626110611Skan}
9627110611Skan
962890075Sobrien
962990075Sobrien/* A validation routine: say whether CODE, a condition code, and MODE
963090075Sobrien   match.  The other alternatives either don't make sense or should
963190075Sobrien   never be generated.  */
963290075Sobrien
9633169689Skanvoid
9634132718Skanvalidate_condition_mode (enum rtx_code code, enum machine_mode mode)
963590075Sobrien{
9636169689Skan  gcc_assert ((GET_RTX_CLASS (code) == RTX_COMPARE
9637169689Skan	       || GET_RTX_CLASS (code) == RTX_COMM_COMPARE)
9638169689Skan	      && GET_MODE_CLASS (mode) == MODE_CC);
963990075Sobrien
964090075Sobrien  /* These don't make sense.  */
9641169689Skan  gcc_assert ((code != GT && code != LT && code != GE && code != LE)
9642169689Skan	      || mode != CCUNSmode);
964390075Sobrien
9644169689Skan  gcc_assert ((code != GTU && code != LTU && code != GEU && code != LEU)
9645169689Skan	      || mode == CCUNSmode);
964690075Sobrien
9647169689Skan  gcc_assert (mode == CCFPmode
9648169689Skan	      || (code != ORDERED && code != UNORDERED
9649169689Skan		  && code != UNEQ && code != LTGT
9650169689Skan		  && code != UNGT && code != UNLT
9651169689Skan		  && code != UNGE && code != UNLE));
9652169689Skan
9653169689Skan  /* These should never be generated except for
9654132718Skan     flag_finite_math_only.  */
9655169689Skan  gcc_assert (mode != CCFPmode
9656169689Skan	      || flag_finite_math_only
9657169689Skan	      || (code != LE && code != GE
9658169689Skan		  && code != UNEQ && code != LTGT
9659169689Skan		  && code != UNGT && code != UNLT));
966090075Sobrien
966190075Sobrien  /* These are invalid; the information is not there.  */
9662169689Skan  gcc_assert (mode != CCEQmode || code == EQ || code == NE);
966390075Sobrien}
966490075Sobrien
966590075Sobrien
966690075Sobrien/* Return 1 if ANDOP is a mask that has no bits on that are not in the
966790075Sobrien   mask required to convert the result of a rotate insn into a shift
966896263Sobrien   left insn of SHIFTOP bits.  Both are known to be SImode CONST_INT.  */
966990075Sobrien
967090075Sobrienint
9671132718Skanincludes_lshift_p (rtx shiftop, rtx andop)
967290075Sobrien{
967390075Sobrien  unsigned HOST_WIDE_INT shift_mask = ~(unsigned HOST_WIDE_INT) 0;
967490075Sobrien
967590075Sobrien  shift_mask <<= INTVAL (shiftop);
967690075Sobrien
967796263Sobrien  return (INTVAL (andop) & 0xffffffff & ~shift_mask) == 0;
967890075Sobrien}
967990075Sobrien
968090075Sobrien/* Similar, but for right shift.  */
968190075Sobrien
968290075Sobrienint
9683132718Skanincludes_rshift_p (rtx shiftop, rtx andop)
968490075Sobrien{
968590075Sobrien  unsigned HOST_WIDE_INT shift_mask = ~(unsigned HOST_WIDE_INT) 0;
968690075Sobrien
968790075Sobrien  shift_mask >>= INTVAL (shiftop);
968890075Sobrien
968996263Sobrien  return (INTVAL (andop) & 0xffffffff & ~shift_mask) == 0;
969090075Sobrien}
969190075Sobrien
969290075Sobrien/* Return 1 if ANDOP is a mask suitable for use with an rldic insn
969390075Sobrien   to perform a left shift.  It must have exactly SHIFTOP least
9694132718Skan   significant 0's, then one or more 1's, then zero or more 0's.  */
969590075Sobrien
969690075Sobrienint
9697132718Skanincludes_rldic_lshift_p (rtx shiftop, rtx andop)
969890075Sobrien{
969990075Sobrien  if (GET_CODE (andop) == CONST_INT)
970090075Sobrien    {
970190075Sobrien      HOST_WIDE_INT c, lsb, shift_mask;
970290075Sobrien
970390075Sobrien      c = INTVAL (andop);
970490075Sobrien      if (c == 0 || c == ~0)
970590075Sobrien	return 0;
970690075Sobrien
970790075Sobrien      shift_mask = ~0;
970890075Sobrien      shift_mask <<= INTVAL (shiftop);
970990075Sobrien
9710132718Skan      /* Find the least significant one bit.  */
971190075Sobrien      lsb = c & -c;
971290075Sobrien
971390075Sobrien      /* It must coincide with the LSB of the shift mask.  */
971490075Sobrien      if (-lsb != shift_mask)
971590075Sobrien	return 0;
971690075Sobrien
971790075Sobrien      /* Invert to look for the next transition (if any).  */
971890075Sobrien      c = ~c;
971990075Sobrien
972090075Sobrien      /* Remove the low group of ones (originally low group of zeros).  */
972190075Sobrien      c &= -lsb;
972290075Sobrien
972390075Sobrien      /* Again find the lsb, and check we have all 1's above.  */
972490075Sobrien      lsb = c & -c;
972590075Sobrien      return c == -lsb;
972690075Sobrien    }
972790075Sobrien  else if (GET_CODE (andop) == CONST_DOUBLE
972890075Sobrien	   && (GET_MODE (andop) == VOIDmode || GET_MODE (andop) == DImode))
972990075Sobrien    {
973090075Sobrien      HOST_WIDE_INT low, high, lsb;
973190075Sobrien      HOST_WIDE_INT shift_mask_low, shift_mask_high;
973290075Sobrien
973390075Sobrien      low = CONST_DOUBLE_LOW (andop);
973490075Sobrien      if (HOST_BITS_PER_WIDE_INT < 64)
973590075Sobrien	high = CONST_DOUBLE_HIGH (andop);
973690075Sobrien
973790075Sobrien      if ((low == 0 && (HOST_BITS_PER_WIDE_INT >= 64 || high == 0))
973890075Sobrien	  || (low == ~0 && (HOST_BITS_PER_WIDE_INT >= 64 || high == ~0)))
973990075Sobrien	return 0;
974090075Sobrien
974190075Sobrien      if (HOST_BITS_PER_WIDE_INT < 64 && low == 0)
974290075Sobrien	{
974390075Sobrien	  shift_mask_high = ~0;
974490075Sobrien	  if (INTVAL (shiftop) > 32)
974590075Sobrien	    shift_mask_high <<= INTVAL (shiftop) - 32;
974690075Sobrien
974790075Sobrien	  lsb = high & -high;
974890075Sobrien
974990075Sobrien	  if (-lsb != shift_mask_high || INTVAL (shiftop) < 32)
975090075Sobrien	    return 0;
975190075Sobrien
975290075Sobrien	  high = ~high;
975390075Sobrien	  high &= -lsb;
975490075Sobrien
975590075Sobrien	  lsb = high & -high;
975690075Sobrien	  return high == -lsb;
975790075Sobrien	}
975890075Sobrien
975990075Sobrien      shift_mask_low = ~0;
976090075Sobrien      shift_mask_low <<= INTVAL (shiftop);
976190075Sobrien
976290075Sobrien      lsb = low & -low;
976390075Sobrien
976490075Sobrien      if (-lsb != shift_mask_low)
976590075Sobrien	return 0;
976690075Sobrien
976790075Sobrien      if (HOST_BITS_PER_WIDE_INT < 64)
976890075Sobrien	high = ~high;
976990075Sobrien      low = ~low;
977090075Sobrien      low &= -lsb;
977190075Sobrien
977290075Sobrien      if (HOST_BITS_PER_WIDE_INT < 64 && low == 0)
977390075Sobrien	{
977490075Sobrien	  lsb = high & -high;
977590075Sobrien	  return high == -lsb;
977690075Sobrien	}
977790075Sobrien
977890075Sobrien      lsb = low & -low;
977990075Sobrien      return low == -lsb && (HOST_BITS_PER_WIDE_INT >= 64 || high == ~0);
978090075Sobrien    }
978190075Sobrien  else
978290075Sobrien    return 0;
978390075Sobrien}
978490075Sobrien
978590075Sobrien/* Return 1 if ANDOP is a mask suitable for use with an rldicr insn
978690075Sobrien   to perform a left shift.  It must have SHIFTOP or more least
9787132718Skan   significant 0's, with the remainder of the word 1's.  */
978890075Sobrien
978990075Sobrienint
9790132718Skanincludes_rldicr_lshift_p (rtx shiftop, rtx andop)
979190075Sobrien{
979290075Sobrien  if (GET_CODE (andop) == CONST_INT)
979390075Sobrien    {
979490075Sobrien      HOST_WIDE_INT c, lsb, shift_mask;
979590075Sobrien
979690075Sobrien      shift_mask = ~0;
979790075Sobrien      shift_mask <<= INTVAL (shiftop);
979890075Sobrien      c = INTVAL (andop);
979990075Sobrien
9800132718Skan      /* Find the least significant one bit.  */
980190075Sobrien      lsb = c & -c;
980290075Sobrien
980390075Sobrien      /* It must be covered by the shift mask.
980490075Sobrien	 This test also rejects c == 0.  */
980590075Sobrien      if ((lsb & shift_mask) == 0)
980690075Sobrien	return 0;
980790075Sobrien
980890075Sobrien      /* Check we have all 1's above the transition, and reject all 1's.  */
980990075Sobrien      return c == -lsb && lsb != 1;
981090075Sobrien    }
981190075Sobrien  else if (GET_CODE (andop) == CONST_DOUBLE
981290075Sobrien	   && (GET_MODE (andop) == VOIDmode || GET_MODE (andop) == DImode))
981390075Sobrien    {
981490075Sobrien      HOST_WIDE_INT low, lsb, shift_mask_low;
981590075Sobrien
981690075Sobrien      low = CONST_DOUBLE_LOW (andop);
981790075Sobrien
981890075Sobrien      if (HOST_BITS_PER_WIDE_INT < 64)
981990075Sobrien	{
982090075Sobrien	  HOST_WIDE_INT high, shift_mask_high;
982190075Sobrien
982290075Sobrien	  high = CONST_DOUBLE_HIGH (andop);
982390075Sobrien
982490075Sobrien	  if (low == 0)
982590075Sobrien	    {
982690075Sobrien	      shift_mask_high = ~0;
982790075Sobrien	      if (INTVAL (shiftop) > 32)
982890075Sobrien		shift_mask_high <<= INTVAL (shiftop) - 32;
982990075Sobrien
983090075Sobrien	      lsb = high & -high;
983190075Sobrien
983290075Sobrien	      if ((lsb & shift_mask_high) == 0)
983390075Sobrien		return 0;
983490075Sobrien
983590075Sobrien	      return high == -lsb;
983690075Sobrien	    }
983790075Sobrien	  if (high != ~0)
983890075Sobrien	    return 0;
983990075Sobrien	}
984090075Sobrien
984190075Sobrien      shift_mask_low = ~0;
984290075Sobrien      shift_mask_low <<= INTVAL (shiftop);
984390075Sobrien
984490075Sobrien      lsb = low & -low;
984590075Sobrien
984690075Sobrien      if ((lsb & shift_mask_low) == 0)
984790075Sobrien	return 0;
984890075Sobrien
984990075Sobrien      return low == -lsb && lsb != 1;
985090075Sobrien    }
985190075Sobrien  else
985290075Sobrien    return 0;
985390075Sobrien}
985490075Sobrien
9855169689Skan/* Return 1 if operands will generate a valid arguments to rlwimi
9856169689Skaninstruction for insert with right shift in 64-bit mode.  The mask may
9857169689Skannot start on the first bit or stop on the last bit because wrap-around
9858169689Skaneffects of instruction do not correspond to semantics of RTL insn.  */
9859169689Skan
9860169689Skanint
9861169689Skaninsvdi_rshift_rlwimi_p (rtx sizeop, rtx startop, rtx shiftop)
9862169689Skan{
9863169689Skan  if (INTVAL (startop) > 32
9864169689Skan      && INTVAL (startop) < 64
9865169689Skan      && INTVAL (sizeop) > 1
9866169689Skan      && INTVAL (sizeop) + INTVAL (startop) < 64
9867169689Skan      && INTVAL (shiftop) > 0
9868169689Skan      && INTVAL (sizeop) + INTVAL (shiftop) < 32
9869169689Skan      && (64 - (INTVAL (shiftop) & 63)) >= INTVAL (sizeop))
9870169689Skan    return 1;
9871169689Skan
9872169689Skan  return 0;
9873169689Skan}
9874169689Skan
987590075Sobrien/* Return 1 if REGNO (reg1) == REGNO (reg2) - 1 making them candidates
9876169689Skan   for lfq and stfq insns iff the registers are hard registers.   */
987790075Sobrien
987890075Sobrienint
9879132718Skanregisters_ok_for_quad_peep (rtx reg1, rtx reg2)
988090075Sobrien{
988190075Sobrien  /* We might have been passed a SUBREG.  */
9882169689Skan  if (GET_CODE (reg1) != REG || GET_CODE (reg2) != REG)
988390075Sobrien    return 0;
988490075Sobrien
9885169689Skan  /* We might have been passed non floating point registers.  */
9886169689Skan  if (!FP_REGNO_P (REGNO (reg1))
9887169689Skan      || !FP_REGNO_P (REGNO (reg2)))
9888169689Skan    return 0;
9889169689Skan
989090075Sobrien  return (REGNO (reg1) == REGNO (reg2) - 1);
989190075Sobrien}
989290075Sobrien
989390075Sobrien/* Return 1 if addr1 and addr2 are suitable for lfq or stfq insn.
989490075Sobrien   addr1 and addr2 must be in consecutive memory locations
989590075Sobrien   (addr2 == addr1 + 8).  */
989690075Sobrien
989790075Sobrienint
9898169689Skanmems_ok_for_quad_peep (rtx mem1, rtx mem2)
989990075Sobrien{
9900169689Skan  rtx addr1, addr2;
9901169689Skan  unsigned int reg1, reg2;
9902169689Skan  int offset1, offset2;
990390075Sobrien
9904169689Skan  /* The mems cannot be volatile.  */
9905169689Skan  if (MEM_VOLATILE_P (mem1) || MEM_VOLATILE_P (mem2))
9906169689Skan    return 0;
9907169689Skan
9908169689Skan  addr1 = XEXP (mem1, 0);
9909169689Skan  addr2 = XEXP (mem2, 0);
9910169689Skan
991190075Sobrien  /* Extract an offset (if used) from the first addr.  */
991290075Sobrien  if (GET_CODE (addr1) == PLUS)
991390075Sobrien    {
991490075Sobrien      /* If not a REG, return zero.  */
991590075Sobrien      if (GET_CODE (XEXP (addr1, 0)) != REG)
991690075Sobrien	return 0;
991790075Sobrien      else
991890075Sobrien	{
9919169689Skan	  reg1 = REGNO (XEXP (addr1, 0));
992090075Sobrien	  /* The offset must be constant!  */
992190075Sobrien	  if (GET_CODE (XEXP (addr1, 1)) != CONST_INT)
9922169689Skan	    return 0;
9923169689Skan	  offset1 = INTVAL (XEXP (addr1, 1));
992490075Sobrien	}
992590075Sobrien    }
992690075Sobrien  else if (GET_CODE (addr1) != REG)
992790075Sobrien    return 0;
992890075Sobrien  else
992990075Sobrien    {
993090075Sobrien      reg1 = REGNO (addr1);
993190075Sobrien      /* This was a simple (mem (reg)) expression.  Offset is 0.  */
993290075Sobrien      offset1 = 0;
993390075Sobrien    }
993490075Sobrien
9935169689Skan  /* And now for the second addr.  */
9936169689Skan  if (GET_CODE (addr2) == PLUS)
9937169689Skan    {
9938169689Skan      /* If not a REG, return zero.  */
9939169689Skan      if (GET_CODE (XEXP (addr2, 0)) != REG)
9940169689Skan	return 0;
9941169689Skan      else
9942169689Skan	{
9943169689Skan	  reg2 = REGNO (XEXP (addr2, 0));
9944169689Skan	  /* The offset must be constant. */
9945169689Skan	  if (GET_CODE (XEXP (addr2, 1)) != CONST_INT)
9946169689Skan	    return 0;
9947169689Skan	  offset2 = INTVAL (XEXP (addr2, 1));
9948169689Skan	}
9949169689Skan    }
9950169689Skan  else if (GET_CODE (addr2) != REG)
995190075Sobrien    return 0;
9952169689Skan  else
9953169689Skan    {
9954169689Skan      reg2 = REGNO (addr2);
9955169689Skan      /* This was a simple (mem (reg)) expression.  Offset is 0.  */
9956169689Skan      offset2 = 0;
9957169689Skan    }
995890075Sobrien
9959169689Skan  /* Both of these must have the same base register.  */
9960169689Skan  if (reg1 != reg2)
996190075Sobrien    return 0;
996290075Sobrien
996390075Sobrien  /* The offset for the second addr must be 8 more than the first addr.  */
9964169689Skan  if (offset2 != offset1 + 8)
996590075Sobrien    return 0;
996690075Sobrien
996790075Sobrien  /* All the tests passed.  addr1 and addr2 are valid for lfq or stfq
996890075Sobrien     instructions.  */
996990075Sobrien  return 1;
997090075Sobrien}
997190075Sobrien
997290075Sobrien/* Return the register class of a scratch register needed to copy IN into
997390075Sobrien   or out of a register in CLASS in MODE.  If it can be done directly,
9974161651Skan   NO_REGS is returned.  */
997590075Sobrien
997690075Sobrienenum reg_class
9977169689Skanrs6000_secondary_reload_class (enum reg_class class,
9978169689Skan			       enum machine_mode mode ATTRIBUTE_UNUSED,
9979169689Skan			       rtx in)
998090075Sobrien{
998190075Sobrien  int regno;
998290075Sobrien
9983132718Skan  if (TARGET_ELF || (DEFAULT_ABI == ABI_DARWIN
9984132718Skan#if TARGET_MACHO
9985169689Skan		     && MACHOPIC_INDIRECT
9986132718Skan#endif
9987169689Skan		     ))
998890075Sobrien    {
998990075Sobrien      /* We cannot copy a symbolic operand directly into anything
9990169689Skan	 other than BASE_REGS for TARGET_ELF.  So indicate that a
9991169689Skan	 register from BASE_REGS is needed as an intermediate
9992169689Skan	 register.
9993169689Skan
999490075Sobrien	 On Darwin, pic addresses require a load from memory, which
999590075Sobrien	 needs a base register.  */
999690075Sobrien      if (class != BASE_REGS
9997169689Skan	  && (GET_CODE (in) == SYMBOL_REF
9998169689Skan	      || GET_CODE (in) == HIGH
9999169689Skan	      || GET_CODE (in) == LABEL_REF
10000169689Skan	      || GET_CODE (in) == CONST))
10001169689Skan	return BASE_REGS;
1000290075Sobrien    }
1000390075Sobrien
1000490075Sobrien  if (GET_CODE (in) == REG)
1000590075Sobrien    {
1000690075Sobrien      regno = REGNO (in);
1000790075Sobrien      if (regno >= FIRST_PSEUDO_REGISTER)
1000890075Sobrien	{
1000990075Sobrien	  regno = true_regnum (in);
1001090075Sobrien	  if (regno >= FIRST_PSEUDO_REGISTER)
1001190075Sobrien	    regno = -1;
1001290075Sobrien	}
1001390075Sobrien    }
1001490075Sobrien  else if (GET_CODE (in) == SUBREG)
1001590075Sobrien    {
1001690075Sobrien      regno = true_regnum (in);
1001790075Sobrien      if (regno >= FIRST_PSEUDO_REGISTER)
1001890075Sobrien	regno = -1;
1001990075Sobrien    }
1002090075Sobrien  else
1002190075Sobrien    regno = -1;
1002290075Sobrien
1002390075Sobrien  /* We can place anything into GENERAL_REGS and can put GENERAL_REGS
1002490075Sobrien     into anything.  */
1002590075Sobrien  if (class == GENERAL_REGS || class == BASE_REGS
1002690075Sobrien      || (regno >= 0 && INT_REGNO_P (regno)))
1002790075Sobrien    return NO_REGS;
1002890075Sobrien
1002990075Sobrien  /* Constants, memory, and FP registers can go into FP registers.  */
1003090075Sobrien  if ((regno == -1 || FP_REGNO_P (regno))
1003190075Sobrien      && (class == FLOAT_REGS || class == NON_SPECIAL_REGS))
1003290075Sobrien    return NO_REGS;
1003390075Sobrien
1003490075Sobrien  /* Memory, and AltiVec registers can go into AltiVec registers.  */
1003590075Sobrien  if ((regno == -1 || ALTIVEC_REGNO_P (regno))
1003690075Sobrien      && class == ALTIVEC_REGS)
1003790075Sobrien    return NO_REGS;
1003890075Sobrien
1003990075Sobrien  /* We can copy among the CR registers.  */
1004090075Sobrien  if ((class == CR_REGS || class == CR0_REGS)
1004190075Sobrien      && regno >= 0 && CR_REGNO_P (regno))
1004290075Sobrien    return NO_REGS;
1004390075Sobrien
1004490075Sobrien  /* Otherwise, we need GENERAL_REGS.  */
1004590075Sobrien  return GENERAL_REGS;
1004690075Sobrien}
1004790075Sobrien
1004890075Sobrien/* Given a comparison operation, return the bit number in CCR to test.  We
10049169689Skan   know this is a valid comparison.
1005090075Sobrien
1005190075Sobrien   SCC_P is 1 if this is for an scc.  That means that %D will have been
1005290075Sobrien   used instead of %C, so the bits will be in different places.
1005390075Sobrien
1005490075Sobrien   Return -1 if OP isn't a valid comparison for some reason.  */
1005590075Sobrien
1005690075Sobrienint
10057132718Skanccr_bit (rtx op, int scc_p)
1005890075Sobrien{
1005990075Sobrien  enum rtx_code code = GET_CODE (op);
1006090075Sobrien  enum machine_mode cc_mode;
1006190075Sobrien  int cc_regnum;
1006290075Sobrien  int base_bit;
1006390075Sobrien  rtx reg;
1006490075Sobrien
10065169689Skan  if (!COMPARISON_P (op))
1006690075Sobrien    return -1;
1006790075Sobrien
1006890075Sobrien  reg = XEXP (op, 0);
1006990075Sobrien
10070169689Skan  gcc_assert (GET_CODE (reg) == REG && CR_REGNO_P (REGNO (reg)));
1007190075Sobrien
1007290075Sobrien  cc_mode = GET_MODE (reg);
1007390075Sobrien  cc_regnum = REGNO (reg);
1007490075Sobrien  base_bit = 4 * (cc_regnum - CR0_REGNO);
1007590075Sobrien
1007690075Sobrien  validate_condition_mode (code, cc_mode);
1007790075Sobrien
10078132718Skan  /* When generating a sCOND operation, only positive conditions are
10079132718Skan     allowed.  */
10080169689Skan  gcc_assert (!scc_p
10081169689Skan	      || code == EQ || code == GT || code == LT || code == UNORDERED
10082169689Skan	      || code == GTU || code == LTU);
10083169689Skan
1008490075Sobrien  switch (code)
1008590075Sobrien    {
1008690075Sobrien    case NE:
1008790075Sobrien      return scc_p ? base_bit + 3 : base_bit + 2;
1008890075Sobrien    case EQ:
1008990075Sobrien      return base_bit + 2;
1009090075Sobrien    case GT:  case GTU:  case UNLE:
1009190075Sobrien      return base_bit + 1;
1009290075Sobrien    case LT:  case LTU:  case UNGE:
1009390075Sobrien      return base_bit;
1009490075Sobrien    case ORDERED:  case UNORDERED:
1009590075Sobrien      return base_bit + 3;
1009690075Sobrien
1009790075Sobrien    case GE:  case GEU:
1009890075Sobrien      /* If scc, we will have done a cror to put the bit in the
1009990075Sobrien	 unordered position.  So test that bit.  For integer, this is ! LT
1010090075Sobrien	 unless this is an scc insn.  */
1010190075Sobrien      return scc_p ? base_bit + 3 : base_bit;
1010290075Sobrien
1010390075Sobrien    case LE:  case LEU:
1010490075Sobrien      return scc_p ? base_bit + 3 : base_bit + 1;
1010590075Sobrien
1010690075Sobrien    default:
10107169689Skan      gcc_unreachable ();
1010890075Sobrien    }
1010990075Sobrien}
1011090075Sobrien
1011190075Sobrien/* Return the GOT register.  */
1011290075Sobrien
10113169689Skanrtx
10114132718Skanrs6000_got_register (rtx value ATTRIBUTE_UNUSED)
1011590075Sobrien{
1011690075Sobrien  /* The second flow pass currently (June 1999) can't update
1011790075Sobrien     regs_ever_live without disturbing other parts of the compiler, so
1011890075Sobrien     update it here to make the prolog/epilogue code happy.  */
1011996263Sobrien  if (no_new_pseudos && ! regs_ever_live[RS6000_PIC_OFFSET_TABLE_REGNUM])
1012096263Sobrien    regs_ever_live[RS6000_PIC_OFFSET_TABLE_REGNUM] = 1;
1012190075Sobrien
1012290075Sobrien  current_function_uses_pic_offset_table = 1;
1012390075Sobrien
1012490075Sobrien  return pic_offset_table_rtx;
1012590075Sobrien}
1012690075Sobrien
10127117395Skan/* Function to init struct machine_function.
10128117395Skan   This will be called, via a pointer variable,
10129117395Skan   from push_function_context.  */
1013090075Sobrien
10131117395Skanstatic struct machine_function *
10132132718Skanrs6000_init_machine_status (void)
1013390075Sobrien{
10134117395Skan  return ggc_alloc_cleared (sizeof (machine_function));
1013590075Sobrien}
10136117395Skan
10137117395Skan/* These macros test for integers and extract the low-order bits.  */
10138117395Skan#define INT_P(X)  \
10139117395Skan((GET_CODE (X) == CONST_INT || GET_CODE (X) == CONST_DOUBLE)	\
10140117395Skan && GET_MODE (X) == VOIDmode)
1014190075Sobrien
10142117395Skan#define INT_LOWPART(X) \
10143117395Skan  (GET_CODE (X) == CONST_INT ? INTVAL (X) : CONST_DOUBLE_LOW (X))
10144117395Skan
10145117395Skanint
10146132718Skanextract_MB (rtx op)
1014790075Sobrien{
10148117395Skan  int i;
10149117395Skan  unsigned long val = INT_LOWPART (op);
1015090075Sobrien
10151117395Skan  /* If the high bit is zero, the value is the first 1 bit we find
10152117395Skan     from the left.  */
10153117395Skan  if ((val & 0x80000000) == 0)
10154117395Skan    {
10155169689Skan      gcc_assert (val & 0xffffffff);
10156117395Skan
10157117395Skan      i = 1;
10158117395Skan      while (((val <<= 1) & 0x80000000) == 0)
10159117395Skan	++i;
10160117395Skan      return i;
10161117395Skan    }
10162117395Skan
10163117395Skan  /* If the high bit is set and the low bit is not, or the mask is all
10164117395Skan     1's, the value is zero.  */
10165117395Skan  if ((val & 1) == 0 || (val & 0xffffffff) == 0xffffffff)
10166117395Skan    return 0;
10167117395Skan
10168117395Skan  /* Otherwise we have a wrap-around mask.  Look for the first 0 bit
10169117395Skan     from the right.  */
10170117395Skan  i = 31;
10171117395Skan  while (((val >>= 1) & 1) != 0)
10172117395Skan    --i;
10173117395Skan
10174117395Skan  return i;
1017590075Sobrien}
1017690075Sobrien
10177117395Skanint
10178132718Skanextract_ME (rtx op)
10179117395Skan{
10180117395Skan  int i;
10181117395Skan  unsigned long val = INT_LOWPART (op);
10182117395Skan
10183117395Skan  /* If the low bit is zero, the value is the first 1 bit we find from
10184117395Skan     the right.  */
10185117395Skan  if ((val & 1) == 0)
10186117395Skan    {
10187169689Skan      gcc_assert (val & 0xffffffff);
10188117395Skan
10189117395Skan      i = 30;
10190117395Skan      while (((val >>= 1) & 1) == 0)
10191117395Skan	--i;
10192117395Skan
10193117395Skan      return i;
10194117395Skan    }
10195117395Skan
10196117395Skan  /* If the low bit is set and the high bit is not, or the mask is all
10197117395Skan     1's, the value is 31.  */
10198117395Skan  if ((val & 0x80000000) == 0 || (val & 0xffffffff) == 0xffffffff)
10199117395Skan    return 31;
10200117395Skan
10201117395Skan  /* Otherwise we have a wrap-around mask.  Look for the first 0 bit
10202117395Skan     from the left.  */
10203117395Skan  i = 0;
10204117395Skan  while (((val <<= 1) & 0x80000000) != 0)
10205117395Skan    ++i;
10206117395Skan
10207117395Skan  return i;
10208117395Skan}
10209117395Skan
10210132718Skan/* Locate some local-dynamic symbol still in use by this function
10211132718Skan   so that we can print its name in some tls_ld pattern.  */
10212132718Skan
10213132718Skanstatic const char *
10214132718Skanrs6000_get_some_local_dynamic_name (void)
10215132718Skan{
10216132718Skan  rtx insn;
10217132718Skan
10218132718Skan  if (cfun->machine->some_ld_name)
10219132718Skan    return cfun->machine->some_ld_name;
10220132718Skan
10221132718Skan  for (insn = get_insns (); insn ; insn = NEXT_INSN (insn))
10222132718Skan    if (INSN_P (insn)
10223132718Skan	&& for_each_rtx (&PATTERN (insn),
10224132718Skan			 rs6000_get_some_local_dynamic_name_1, 0))
10225132718Skan      return cfun->machine->some_ld_name;
10226132718Skan
10227169689Skan  gcc_unreachable ();
10228132718Skan}
10229132718Skan
10230132718Skan/* Helper function for rs6000_get_some_local_dynamic_name.  */
10231132718Skan
10232132718Skanstatic int
10233132718Skanrs6000_get_some_local_dynamic_name_1 (rtx *px, void *data ATTRIBUTE_UNUSED)
10234132718Skan{
10235132718Skan  rtx x = *px;
10236132718Skan
10237132718Skan  if (GET_CODE (x) == SYMBOL_REF)
10238132718Skan    {
10239132718Skan      const char *str = XSTR (x, 0);
10240132718Skan      if (SYMBOL_REF_TLS_MODEL (x) == TLS_MODEL_LOCAL_DYNAMIC)
10241132718Skan	{
10242132718Skan	  cfun->machine->some_ld_name = str;
10243132718Skan	  return 1;
10244132718Skan	}
10245132718Skan    }
10246132718Skan
10247132718Skan  return 0;
10248132718Skan}
10249132718Skan
10250169689Skan/* Write out a function code label.  */
10251169689Skan
10252169689Skanvoid
10253169689Skanrs6000_output_function_entry (FILE *file, const char *fname)
10254169689Skan{
10255169689Skan  if (fname[0] != '.')
10256169689Skan    {
10257169689Skan      switch (DEFAULT_ABI)
10258169689Skan	{
10259169689Skan	default:
10260169689Skan	  gcc_unreachable ();
10261169689Skan
10262169689Skan	case ABI_AIX:
10263169689Skan	  if (DOT_SYMBOLS)
10264169689Skan	    putc ('.', file);
10265169689Skan	  else
10266169689Skan	    ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "L.");
10267169689Skan	  break;
10268169689Skan
10269169689Skan	case ABI_V4:
10270169689Skan	case ABI_DARWIN:
10271169689Skan	  break;
10272169689Skan	}
10273169689Skan    }
10274169689Skan  if (TARGET_AIX)
10275169689Skan    RS6000_OUTPUT_BASENAME (file, fname);
10276169689Skan  else
10277169689Skan    assemble_name (file, fname);
10278169689Skan}
10279169689Skan
1028090075Sobrien/* Print an operand.  Recognize special options, documented below.  */
1028190075Sobrien
1028290075Sobrien#if TARGET_ELF
1028390075Sobrien#define SMALL_DATA_RELOC ((rs6000_sdata == SDATA_EABI) ? "sda21" : "sdarel")
1028490075Sobrien#define SMALL_DATA_REG ((rs6000_sdata == SDATA_EABI) ? 0 : 13)
1028590075Sobrien#else
1028690075Sobrien#define SMALL_DATA_RELOC "sda21"
1028790075Sobrien#define SMALL_DATA_REG 0
1028890075Sobrien#endif
1028990075Sobrien
1029090075Sobrienvoid
10291132718Skanprint_operand (FILE *file, rtx x, int code)
1029290075Sobrien{
1029390075Sobrien  int i;
1029490075Sobrien  HOST_WIDE_INT val;
10295117395Skan  unsigned HOST_WIDE_INT uval;
1029690075Sobrien
1029790075Sobrien  switch (code)
1029890075Sobrien    {
1029990075Sobrien    case '.':
1030090075Sobrien      /* Write out an instruction after the call which may be replaced
1030190075Sobrien	 with glue code by the loader.  This depends on the AIX version.  */
1030290075Sobrien      asm_fprintf (file, RS6000_CALL_GLUE);
1030390075Sobrien      return;
1030490075Sobrien
1030590075Sobrien      /* %a is output_address.  */
1030690075Sobrien
1030790075Sobrien    case 'A':
1030890075Sobrien      /* If X is a constant integer whose low-order 5 bits are zero,
1030990075Sobrien	 write 'l'.  Otherwise, write 'r'.  This is a kludge to fix a bug
1031090075Sobrien	 in the AIX assembler where "sri" with a zero shift count
1031190075Sobrien	 writes a trash instruction.  */
1031290075Sobrien      if (GET_CODE (x) == CONST_INT && (INTVAL (x) & 31) == 0)
1031390075Sobrien	putc ('l', file);
1031490075Sobrien      else
1031590075Sobrien	putc ('r', file);
1031690075Sobrien      return;
1031790075Sobrien
1031890075Sobrien    case 'b':
1031990075Sobrien      /* If constant, low-order 16 bits of constant, unsigned.
1032090075Sobrien	 Otherwise, write normally.  */
1032190075Sobrien      if (INT_P (x))
1032290075Sobrien	fprintf (file, HOST_WIDE_INT_PRINT_DEC, INT_LOWPART (x) & 0xffff);
1032390075Sobrien      else
1032490075Sobrien	print_operand (file, x, 0);
1032590075Sobrien      return;
1032690075Sobrien
1032790075Sobrien    case 'B':
1032890075Sobrien      /* If the low-order bit is zero, write 'r'; otherwise, write 'l'
1032990075Sobrien	 for 64-bit mask direction.  */
10330169689Skan      putc (((INT_LOWPART (x) & 1) == 0 ? 'r' : 'l'), file);
1033190075Sobrien      return;
1033290075Sobrien
1033390075Sobrien      /* %c is output_addr_const if a CONSTANT_ADDRESS_P, otherwise
1033490075Sobrien	 output_operand.  */
1033590075Sobrien
10336132718Skan    case 'c':
10337132718Skan      /* X is a CR register.  Print the number of the GT bit of the CR.  */
10338132718Skan      if (GET_CODE (x) != REG || ! CR_REGNO_P (REGNO (x)))
10339169689Skan	output_operand_lossage ("invalid %%E value");
10340132718Skan      else
10341169689Skan	fprintf (file, "%d", 4 * (REGNO (x) - CR0_REGNO) + 1);
10342132718Skan      return;
10343132718Skan
1034490075Sobrien    case 'D':
10345169689Skan      /* Like 'J' but get to the GT bit only.  */
10346169689Skan      gcc_assert (GET_CODE (x) == REG);
1034790075Sobrien
10348169689Skan      /* Bit 1 is GT bit.  */
10349169689Skan      i = 4 * (REGNO (x) - CR0_REGNO) + 1;
1035090075Sobrien
10351169689Skan      /* Add one for shift count in rlinm for scc.  */
10352169689Skan      fprintf (file, "%d", i + 1);
1035390075Sobrien      return;
1035490075Sobrien
1035590075Sobrien    case 'E':
1035690075Sobrien      /* X is a CR register.  Print the number of the EQ bit of the CR */
1035790075Sobrien      if (GET_CODE (x) != REG || ! CR_REGNO_P (REGNO (x)))
1035890075Sobrien	output_operand_lossage ("invalid %%E value");
1035990075Sobrien      else
1036090075Sobrien	fprintf (file, "%d", 4 * (REGNO (x) - CR0_REGNO) + 2);
1036190075Sobrien      return;
1036290075Sobrien
1036390075Sobrien    case 'f':
1036490075Sobrien      /* X is a CR register.  Print the shift count needed to move it
1036590075Sobrien	 to the high-order four bits.  */
1036690075Sobrien      if (GET_CODE (x) != REG || ! CR_REGNO_P (REGNO (x)))
1036790075Sobrien	output_operand_lossage ("invalid %%f value");
1036890075Sobrien      else
1036990075Sobrien	fprintf (file, "%d", 4 * (REGNO (x) - CR0_REGNO));
1037090075Sobrien      return;
1037190075Sobrien
1037290075Sobrien    case 'F':
1037390075Sobrien      /* Similar, but print the count for the rotate in the opposite
1037490075Sobrien	 direction.  */
1037590075Sobrien      if (GET_CODE (x) != REG || ! CR_REGNO_P (REGNO (x)))
1037690075Sobrien	output_operand_lossage ("invalid %%F value");
1037790075Sobrien      else
1037890075Sobrien	fprintf (file, "%d", 32 - 4 * (REGNO (x) - CR0_REGNO));
1037990075Sobrien      return;
1038090075Sobrien
1038190075Sobrien    case 'G':
1038290075Sobrien      /* X is a constant integer.  If it is negative, print "m",
10383117395Skan	 otherwise print "z".  This is to make an aze or ame insn.  */
1038490075Sobrien      if (GET_CODE (x) != CONST_INT)
1038590075Sobrien	output_operand_lossage ("invalid %%G value");
1038690075Sobrien      else if (INTVAL (x) >= 0)
1038790075Sobrien	putc ('z', file);
1038890075Sobrien      else
1038990075Sobrien	putc ('m', file);
1039090075Sobrien      return;
1039190075Sobrien
1039290075Sobrien    case 'h':
1039390075Sobrien      /* If constant, output low-order five bits.  Otherwise, write
1039490075Sobrien	 normally.  */
1039590075Sobrien      if (INT_P (x))
1039690075Sobrien	fprintf (file, HOST_WIDE_INT_PRINT_DEC, INT_LOWPART (x) & 31);
1039790075Sobrien      else
1039890075Sobrien	print_operand (file, x, 0);
1039990075Sobrien      return;
1040090075Sobrien
1040190075Sobrien    case 'H':
1040290075Sobrien      /* If constant, output low-order six bits.  Otherwise, write
1040390075Sobrien	 normally.  */
1040490075Sobrien      if (INT_P (x))
1040590075Sobrien	fprintf (file, HOST_WIDE_INT_PRINT_DEC, INT_LOWPART (x) & 63);
1040690075Sobrien      else
1040790075Sobrien	print_operand (file, x, 0);
1040890075Sobrien      return;
1040990075Sobrien
1041090075Sobrien    case 'I':
1041190075Sobrien      /* Print `i' if this is a constant, else nothing.  */
1041290075Sobrien      if (INT_P (x))
1041390075Sobrien	putc ('i', file);
1041490075Sobrien      return;
1041590075Sobrien
1041690075Sobrien    case 'j':
1041790075Sobrien      /* Write the bit number in CCR for jump.  */
1041890075Sobrien      i = ccr_bit (x, 0);
1041990075Sobrien      if (i == -1)
1042090075Sobrien	output_operand_lossage ("invalid %%j code");
1042190075Sobrien      else
1042290075Sobrien	fprintf (file, "%d", i);
1042390075Sobrien      return;
1042490075Sobrien
1042590075Sobrien    case 'J':
1042690075Sobrien      /* Similar, but add one for shift count in rlinm for scc and pass
1042790075Sobrien	 scc flag to `ccr_bit'.  */
1042890075Sobrien      i = ccr_bit (x, 1);
1042990075Sobrien      if (i == -1)
1043090075Sobrien	output_operand_lossage ("invalid %%J code");
1043190075Sobrien      else
1043290075Sobrien	/* If we want bit 31, write a shift count of zero, not 32.  */
1043390075Sobrien	fprintf (file, "%d", i == 31 ? 0 : i + 1);
1043490075Sobrien      return;
1043590075Sobrien
1043690075Sobrien    case 'k':
1043790075Sobrien      /* X must be a constant.  Write the 1's complement of the
1043890075Sobrien	 constant.  */
1043990075Sobrien      if (! INT_P (x))
1044090075Sobrien	output_operand_lossage ("invalid %%k value");
1044190075Sobrien      else
1044290075Sobrien	fprintf (file, HOST_WIDE_INT_PRINT_DEC, ~ INT_LOWPART (x));
1044390075Sobrien      return;
1044490075Sobrien
1044590075Sobrien    case 'K':
1044690075Sobrien      /* X must be a symbolic constant on ELF.  Write an
1044790075Sobrien	 expression suitable for an 'addi' that adds in the low 16
1044890075Sobrien	 bits of the MEM.  */
1044990075Sobrien      if (GET_CODE (x) != CONST)
1045090075Sobrien	{
1045190075Sobrien	  print_operand_address (file, x);
1045290075Sobrien	  fputs ("@l", file);
1045390075Sobrien	}
1045490075Sobrien      else
1045590075Sobrien	{
1045690075Sobrien	  if (GET_CODE (XEXP (x, 0)) != PLUS
1045790075Sobrien	      || (GET_CODE (XEXP (XEXP (x, 0), 0)) != SYMBOL_REF
1045890075Sobrien		  && GET_CODE (XEXP (XEXP (x, 0), 0)) != LABEL_REF)
1045990075Sobrien	      || GET_CODE (XEXP (XEXP (x, 0), 1)) != CONST_INT)
1046090075Sobrien	    output_operand_lossage ("invalid %%K value");
1046190075Sobrien	  print_operand_address (file, XEXP (XEXP (x, 0), 0));
1046290075Sobrien	  fputs ("@l", file);
10463117395Skan	  /* For GNU as, there must be a non-alphanumeric character
10464117395Skan	     between 'l' and the number.  The '-' is added by
10465117395Skan	     print_operand() already.  */
10466117395Skan	  if (INTVAL (XEXP (XEXP (x, 0), 1)) >= 0)
10467117395Skan	    fputs ("+", file);
1046890075Sobrien	  print_operand (file, XEXP (XEXP (x, 0), 1), 0);
1046990075Sobrien	}
1047090075Sobrien      return;
1047190075Sobrien
1047290075Sobrien      /* %l is output_asm_label.  */
1047390075Sobrien
1047490075Sobrien    case 'L':
1047590075Sobrien      /* Write second word of DImode or DFmode reference.  Works on register
1047690075Sobrien	 or non-indexed memory only.  */
1047790075Sobrien      if (GET_CODE (x) == REG)
10478169689Skan	fputs (reg_names[REGNO (x) + 1], file);
1047990075Sobrien      else if (GET_CODE (x) == MEM)
1048090075Sobrien	{
1048190075Sobrien	  /* Handle possible auto-increment.  Since it is pre-increment and
1048290075Sobrien	     we have already done it, we can just use an offset of word.  */
1048390075Sobrien	  if (GET_CODE (XEXP (x, 0)) == PRE_INC
1048490075Sobrien	      || GET_CODE (XEXP (x, 0)) == PRE_DEC)
1048590075Sobrien	    output_address (plus_constant (XEXP (XEXP (x, 0), 0),
1048690075Sobrien					   UNITS_PER_WORD));
1048790075Sobrien	  else
1048890075Sobrien	    output_address (XEXP (adjust_address_nv (x, SImode,
1048990075Sobrien						     UNITS_PER_WORD),
1049090075Sobrien				  0));
1049190075Sobrien
1049290075Sobrien	  if (small_data_operand (x, GET_MODE (x)))
1049390075Sobrien	    fprintf (file, "@%s(%s)", SMALL_DATA_RELOC,
1049490075Sobrien		     reg_names[SMALL_DATA_REG]);
1049590075Sobrien	}
1049690075Sobrien      return;
10497169689Skan
1049890075Sobrien    case 'm':
1049990075Sobrien      /* MB value for a mask operand.  */
1050096263Sobrien      if (! mask_operand (x, SImode))
1050190075Sobrien	output_operand_lossage ("invalid %%m value");
1050290075Sobrien
10503117395Skan      fprintf (file, "%d", extract_MB (x));
1050490075Sobrien      return;
1050590075Sobrien
1050690075Sobrien    case 'M':
1050790075Sobrien      /* ME value for a mask operand.  */
1050896263Sobrien      if (! mask_operand (x, SImode))
1050990075Sobrien	output_operand_lossage ("invalid %%M value");
1051090075Sobrien
10511117395Skan      fprintf (file, "%d", extract_ME (x));
1051290075Sobrien      return;
1051390075Sobrien
1051490075Sobrien      /* %n outputs the negative of its operand.  */
1051590075Sobrien
1051690075Sobrien    case 'N':
1051790075Sobrien      /* Write the number of elements in the vector times 4.  */
1051890075Sobrien      if (GET_CODE (x) != PARALLEL)
1051990075Sobrien	output_operand_lossage ("invalid %%N value");
1052090075Sobrien      else
1052190075Sobrien	fprintf (file, "%d", XVECLEN (x, 0) * 4);
1052290075Sobrien      return;
1052390075Sobrien
1052490075Sobrien    case 'O':
1052590075Sobrien      /* Similar, but subtract 1 first.  */
1052690075Sobrien      if (GET_CODE (x) != PARALLEL)
1052790075Sobrien	output_operand_lossage ("invalid %%O value");
1052890075Sobrien      else
1052990075Sobrien	fprintf (file, "%d", (XVECLEN (x, 0) - 1) * 4);
1053090075Sobrien      return;
1053190075Sobrien
1053290075Sobrien    case 'p':
1053390075Sobrien      /* X is a CONST_INT that is a power of two.  Output the logarithm.  */
1053490075Sobrien      if (! INT_P (x)
1053590075Sobrien	  || INT_LOWPART (x) < 0
1053690075Sobrien	  || (i = exact_log2 (INT_LOWPART (x))) < 0)
1053790075Sobrien	output_operand_lossage ("invalid %%p value");
1053890075Sobrien      else
1053990075Sobrien	fprintf (file, "%d", i);
1054090075Sobrien      return;
1054190075Sobrien
1054290075Sobrien    case 'P':
1054390075Sobrien      /* The operand must be an indirect memory reference.  The result
10544146895Skan	 is the register name.  */
1054590075Sobrien      if (GET_CODE (x) != MEM || GET_CODE (XEXP (x, 0)) != REG
1054690075Sobrien	  || REGNO (XEXP (x, 0)) >= 32)
1054790075Sobrien	output_operand_lossage ("invalid %%P value");
1054890075Sobrien      else
10549169689Skan	fputs (reg_names[REGNO (XEXP (x, 0))], file);
1055090075Sobrien      return;
1055190075Sobrien
1055290075Sobrien    case 'q':
1055390075Sobrien      /* This outputs the logical code corresponding to a boolean
1055490075Sobrien	 expression.  The expression may have one or both operands
1055590075Sobrien	 negated (if one, only the first one).  For condition register
10556169689Skan	 logical operations, it will also treat the negated
10557169689Skan	 CR codes as NOTs, but not handle NOTs of them.  */
1055890075Sobrien      {
1055990075Sobrien	const char *const *t = 0;
1056090075Sobrien	const char *s;
1056190075Sobrien	enum rtx_code code = GET_CODE (x);
1056290075Sobrien	static const char * const tbl[3][3] = {
1056390075Sobrien	  { "and", "andc", "nor" },
1056490075Sobrien	  { "or", "orc", "nand" },
1056590075Sobrien	  { "xor", "eqv", "xor" } };
1056690075Sobrien
1056790075Sobrien	if (code == AND)
1056890075Sobrien	  t = tbl[0];
1056990075Sobrien	else if (code == IOR)
1057090075Sobrien	  t = tbl[1];
1057190075Sobrien	else if (code == XOR)
1057290075Sobrien	  t = tbl[2];
1057390075Sobrien	else
1057490075Sobrien	  output_operand_lossage ("invalid %%q value");
1057590075Sobrien
1057690075Sobrien	if (GET_CODE (XEXP (x, 0)) != NOT)
1057790075Sobrien	  s = t[0];
1057890075Sobrien	else
1057990075Sobrien	  {
1058090075Sobrien	    if (GET_CODE (XEXP (x, 1)) == NOT)
1058190075Sobrien	      s = t[2];
1058290075Sobrien	    else
1058390075Sobrien	      s = t[1];
1058490075Sobrien	  }
10585169689Skan
1058690075Sobrien	fputs (s, file);
1058790075Sobrien      }
1058890075Sobrien      return;
1058990075Sobrien
10590132718Skan    case 'Q':
10591132718Skan      if (TARGET_MFCRF)
10592169689Skan	fputc (',', file);
10593132718Skan        /* FALLTHRU */
10594132718Skan      else
10595132718Skan	return;
10596132718Skan
1059790075Sobrien    case 'R':
1059890075Sobrien      /* X is a CR register.  Print the mask for `mtcrf'.  */
1059990075Sobrien      if (GET_CODE (x) != REG || ! CR_REGNO_P (REGNO (x)))
1060090075Sobrien	output_operand_lossage ("invalid %%R value");
1060190075Sobrien      else
1060290075Sobrien	fprintf (file, "%d", 128 >> (REGNO (x) - CR0_REGNO));
1060390075Sobrien      return;
1060490075Sobrien
1060590075Sobrien    case 's':
1060690075Sobrien      /* Low 5 bits of 32 - value */
1060790075Sobrien      if (! INT_P (x))
1060890075Sobrien	output_operand_lossage ("invalid %%s value");
1060990075Sobrien      else
1061090075Sobrien	fprintf (file, HOST_WIDE_INT_PRINT_DEC, (32 - INT_LOWPART (x)) & 31);
1061190075Sobrien      return;
1061290075Sobrien
1061390075Sobrien    case 'S':
10614117395Skan      /* PowerPC64 mask position.  All 0's is excluded.
1061590075Sobrien	 CONST_INT 32-bit mask is considered sign-extended so any
1061690075Sobrien	 transition must occur within the CONST_INT, not on the boundary.  */
1061796263Sobrien      if (! mask64_operand (x, DImode))
1061890075Sobrien	output_operand_lossage ("invalid %%S value");
1061990075Sobrien
10620117395Skan      uval = INT_LOWPART (x);
1062190075Sobrien
10622117395Skan      if (uval & 1)	/* Clear Left */
1062390075Sobrien	{
10624132718Skan#if HOST_BITS_PER_WIDE_INT > 64
10625132718Skan	  uval &= ((unsigned HOST_WIDE_INT) 1 << 64) - 1;
10626132718Skan#endif
10627117395Skan	  i = 64;
1062890075Sobrien	}
10629117395Skan      else		/* Clear Right */
1063090075Sobrien	{
10631117395Skan	  uval = ~uval;
10632132718Skan#if HOST_BITS_PER_WIDE_INT > 64
10633132718Skan	  uval &= ((unsigned HOST_WIDE_INT) 1 << 64) - 1;
10634132718Skan#endif
10635117395Skan	  i = 63;
10636117395Skan	}
10637117395Skan      while (uval != 0)
10638117395Skan	--i, uval >>= 1;
10639169689Skan      gcc_assert (i >= 0);
10640117395Skan      fprintf (file, "%d", i);
10641117395Skan      return;
1064290075Sobrien
10643117395Skan    case 't':
10644117395Skan      /* Like 'J' but get to the OVERFLOW/UNORDERED bit.  */
10645169689Skan      gcc_assert (GET_CODE (x) == REG && GET_MODE (x) == CCmode);
1064690075Sobrien
10647117395Skan      /* Bit 3 is OV bit.  */
10648117395Skan      i = 4 * (REGNO (x) - CR0_REGNO) + 3;
1064990075Sobrien
10650117395Skan      /* If we want bit 31, write a shift count of zero, not 32.  */
10651117395Skan      fprintf (file, "%d", i == 31 ? 0 : i + 1);
10652117395Skan      return;
1065390075Sobrien
1065490075Sobrien    case 'T':
1065590075Sobrien      /* Print the symbolic name of a branch target register.  */
1065690075Sobrien      if (GET_CODE (x) != REG || (REGNO (x) != LINK_REGISTER_REGNUM
1065790075Sobrien				  && REGNO (x) != COUNT_REGISTER_REGNUM))
1065890075Sobrien	output_operand_lossage ("invalid %%T value");
1065990075Sobrien      else if (REGNO (x) == LINK_REGISTER_REGNUM)
1066090075Sobrien	fputs (TARGET_NEW_MNEMONICS ? "lr" : "r", file);
1066190075Sobrien      else
1066290075Sobrien	fputs ("ctr", file);
1066390075Sobrien      return;
1066490075Sobrien
1066590075Sobrien    case 'u':
1066690075Sobrien      /* High-order 16 bits of constant for use in unsigned operand.  */
1066790075Sobrien      if (! INT_P (x))
1066890075Sobrien	output_operand_lossage ("invalid %%u value");
1066990075Sobrien      else
10670169689Skan	fprintf (file, HOST_WIDE_INT_PRINT_HEX,
1067190075Sobrien		 (INT_LOWPART (x) >> 16) & 0xffff);
1067290075Sobrien      return;
1067390075Sobrien
1067490075Sobrien    case 'v':
1067590075Sobrien      /* High-order 16 bits of constant for use in signed operand.  */
1067690075Sobrien      if (! INT_P (x))
1067790075Sobrien	output_operand_lossage ("invalid %%v value");
1067890075Sobrien      else
1067990075Sobrien	fprintf (file, HOST_WIDE_INT_PRINT_HEX,
1068090075Sobrien		 (INT_LOWPART (x) >> 16) & 0xffff);
1068190075Sobrien      return;
1068290075Sobrien
1068390075Sobrien    case 'U':
1068490075Sobrien      /* Print `u' if this has an auto-increment or auto-decrement.  */
1068590075Sobrien      if (GET_CODE (x) == MEM
1068690075Sobrien	  && (GET_CODE (XEXP (x, 0)) == PRE_INC
1068790075Sobrien	      || GET_CODE (XEXP (x, 0)) == PRE_DEC))
1068890075Sobrien	putc ('u', file);
1068990075Sobrien      return;
1069090075Sobrien
1069190075Sobrien    case 'V':
1069290075Sobrien      /* Print the trap code for this operand.  */
1069390075Sobrien      switch (GET_CODE (x))
1069490075Sobrien	{
1069590075Sobrien	case EQ:
1069690075Sobrien	  fputs ("eq", file);   /* 4 */
1069790075Sobrien	  break;
1069890075Sobrien	case NE:
1069990075Sobrien	  fputs ("ne", file);   /* 24 */
1070090075Sobrien	  break;
1070190075Sobrien	case LT:
1070290075Sobrien	  fputs ("lt", file);   /* 16 */
1070390075Sobrien	  break;
1070490075Sobrien	case LE:
1070590075Sobrien	  fputs ("le", file);   /* 20 */
1070690075Sobrien	  break;
1070790075Sobrien	case GT:
1070890075Sobrien	  fputs ("gt", file);   /* 8 */
1070990075Sobrien	  break;
1071090075Sobrien	case GE:
1071190075Sobrien	  fputs ("ge", file);   /* 12 */
1071290075Sobrien	  break;
1071390075Sobrien	case LTU:
1071490075Sobrien	  fputs ("llt", file);  /* 2 */
1071590075Sobrien	  break;
1071690075Sobrien	case LEU:
1071790075Sobrien	  fputs ("lle", file);  /* 6 */
1071890075Sobrien	  break;
1071990075Sobrien	case GTU:
1072090075Sobrien	  fputs ("lgt", file);  /* 1 */
1072190075Sobrien	  break;
1072290075Sobrien	case GEU:
1072390075Sobrien	  fputs ("lge", file);  /* 5 */
1072490075Sobrien	  break;
1072590075Sobrien	default:
10726169689Skan	  gcc_unreachable ();
1072790075Sobrien	}
1072890075Sobrien      break;
1072990075Sobrien
1073090075Sobrien    case 'w':
1073190075Sobrien      /* If constant, low-order 16 bits of constant, signed.  Otherwise, write
1073290075Sobrien	 normally.  */
1073390075Sobrien      if (INT_P (x))
10734169689Skan	fprintf (file, HOST_WIDE_INT_PRINT_DEC,
1073590075Sobrien		 ((INT_LOWPART (x) & 0xffff) ^ 0x8000) - 0x8000);
1073690075Sobrien      else
1073790075Sobrien	print_operand (file, x, 0);
1073890075Sobrien      return;
1073990075Sobrien
1074090075Sobrien    case 'W':
1074190075Sobrien      /* MB value for a PowerPC64 rldic operand.  */
1074290075Sobrien      val = (GET_CODE (x) == CONST_INT
1074390075Sobrien	     ? INTVAL (x) : CONST_DOUBLE_HIGH (x));
1074490075Sobrien
1074590075Sobrien      if (val < 0)
1074690075Sobrien	i = -1;
1074790075Sobrien      else
1074890075Sobrien	for (i = 0; i < HOST_BITS_PER_WIDE_INT; i++)
1074990075Sobrien	  if ((val <<= 1) < 0)
1075090075Sobrien	    break;
1075190075Sobrien
1075290075Sobrien#if HOST_BITS_PER_WIDE_INT == 32
1075390075Sobrien      if (GET_CODE (x) == CONST_INT && i >= 0)
1075490075Sobrien	i += 32;  /* zero-extend high-part was all 0's */
1075590075Sobrien      else if (GET_CODE (x) == CONST_DOUBLE && i == 32)
1075690075Sobrien	{
1075790075Sobrien	  val = CONST_DOUBLE_LOW (x);
1075890075Sobrien
10759169689Skan	  gcc_assert (val);
10760169689Skan	  if (val < 0)
1076190075Sobrien	    --i;
1076290075Sobrien	  else
1076390075Sobrien	    for ( ; i < 64; i++)
1076490075Sobrien	      if ((val <<= 1) < 0)
1076590075Sobrien		break;
1076690075Sobrien	}
1076790075Sobrien#endif
1076890075Sobrien
1076990075Sobrien      fprintf (file, "%d", i + 1);
1077090075Sobrien      return;
1077190075Sobrien
1077290075Sobrien    case 'X':
1077390075Sobrien      if (GET_CODE (x) == MEM
10774132718Skan	  && legitimate_indexed_address_p (XEXP (x, 0), 0))
1077590075Sobrien	putc ('x', file);
1077690075Sobrien      return;
1077790075Sobrien
1077890075Sobrien    case 'Y':
1077990075Sobrien      /* Like 'L', for third word of TImode  */
1078090075Sobrien      if (GET_CODE (x) == REG)
10781169689Skan	fputs (reg_names[REGNO (x) + 2], file);
1078290075Sobrien      else if (GET_CODE (x) == MEM)
1078390075Sobrien	{
1078490075Sobrien	  if (GET_CODE (XEXP (x, 0)) == PRE_INC
1078590075Sobrien	      || GET_CODE (XEXP (x, 0)) == PRE_DEC)
1078690075Sobrien	    output_address (plus_constant (XEXP (XEXP (x, 0), 0), 8));
1078790075Sobrien	  else
1078890075Sobrien	    output_address (XEXP (adjust_address_nv (x, SImode, 8), 0));
1078990075Sobrien	  if (small_data_operand (x, GET_MODE (x)))
1079090075Sobrien	    fprintf (file, "@%s(%s)", SMALL_DATA_RELOC,
1079190075Sobrien		     reg_names[SMALL_DATA_REG]);
1079290075Sobrien	}
1079390075Sobrien      return;
10794169689Skan
1079590075Sobrien    case 'z':
1079690075Sobrien      /* X is a SYMBOL_REF.  Write out the name preceded by a
1079790075Sobrien	 period and without any trailing data in brackets.  Used for function
1079890075Sobrien	 names.  If we are configured for System V (or the embedded ABI) on
1079990075Sobrien	 the PowerPC, do not emit the period, since those systems do not use
1080090075Sobrien	 TOCs and the like.  */
10801169689Skan      gcc_assert (GET_CODE (x) == SYMBOL_REF);
1080290075Sobrien
10803169689Skan      /* Mark the decl as referenced so that cgraph will output the
10804169689Skan	 function.  */
10805169689Skan      if (SYMBOL_REF_DECL (x))
10806169689Skan	mark_decl_referenced (SYMBOL_REF_DECL (x));
10807169689Skan
10808169689Skan      /* For macho, check to see if we need a stub.  */
10809169689Skan      if (TARGET_MACHO)
1081090075Sobrien	{
10811169689Skan	  const char *name = XSTR (x, 0);
10812169689Skan#if TARGET_MACHO
10813169689Skan	  if (MACHOPIC_INDIRECT
10814169689Skan	      && machopic_classify_symbol (x) == MACHOPIC_UNDEFINED_FUNCTION)
10815169689Skan	    name = machopic_indirection_name (x, /*stub_p=*/true);
10816169689Skan#endif
10817169689Skan	  assemble_name (file, name);
1081890075Sobrien	}
10819169689Skan      else if (!DOT_SYMBOLS)
10820169689Skan	assemble_name (file, XSTR (x, 0));
10821132718Skan      else
10822169689Skan	rs6000_output_function_entry (file, XSTR (x, 0));
1082390075Sobrien      return;
1082490075Sobrien
1082590075Sobrien    case 'Z':
1082690075Sobrien      /* Like 'L', for last word of TImode.  */
1082790075Sobrien      if (GET_CODE (x) == REG)
10828169689Skan	fputs (reg_names[REGNO (x) + 3], file);
1082990075Sobrien      else if (GET_CODE (x) == MEM)
1083090075Sobrien	{
1083190075Sobrien	  if (GET_CODE (XEXP (x, 0)) == PRE_INC
1083290075Sobrien	      || GET_CODE (XEXP (x, 0)) == PRE_DEC)
1083390075Sobrien	    output_address (plus_constant (XEXP (XEXP (x, 0), 0), 12));
1083490075Sobrien	  else
1083590075Sobrien	    output_address (XEXP (adjust_address_nv (x, SImode, 12), 0));
1083690075Sobrien	  if (small_data_operand (x, GET_MODE (x)))
1083790075Sobrien	    fprintf (file, "@%s(%s)", SMALL_DATA_RELOC,
1083890075Sobrien		     reg_names[SMALL_DATA_REG]);
1083990075Sobrien	}
1084090075Sobrien      return;
1084190075Sobrien
10842117395Skan      /* Print AltiVec or SPE memory operand.  */
1084390075Sobrien    case 'y':
1084490075Sobrien      {
1084590075Sobrien	rtx tmp;
1084690075Sobrien
10847169689Skan	gcc_assert (GET_CODE (x) == MEM);
1084890075Sobrien
1084990075Sobrien	tmp = XEXP (x, 0);
1085090075Sobrien
10851169689Skan	/* Ugly hack because %y is overloaded.  */
10852169689Skan	if (TARGET_E500 && GET_MODE_SIZE (GET_MODE (x)) == 8)
10853117395Skan	  {
10854117395Skan	    /* Handle [reg].  */
10855117395Skan	    if (GET_CODE (tmp) == REG)
10856117395Skan	      {
10857117395Skan		fprintf (file, "0(%s)", reg_names[REGNO (tmp)]);
10858117395Skan		break;
10859117395Skan	      }
10860117395Skan	    /* Handle [reg+UIMM].  */
10861117395Skan	    else if (GET_CODE (tmp) == PLUS &&
10862117395Skan		     GET_CODE (XEXP (tmp, 1)) == CONST_INT)
10863117395Skan	      {
10864117395Skan		int x;
10865117395Skan
10866169689Skan		gcc_assert (GET_CODE (XEXP (tmp, 0)) == REG);
10867117395Skan
10868117395Skan		x = INTVAL (XEXP (tmp, 1));
10869117395Skan		fprintf (file, "%d(%s)", x, reg_names[REGNO (XEXP (tmp, 0))]);
10870117395Skan		break;
10871117395Skan	      }
10872117395Skan
10873117395Skan	    /* Fall through.  Must be [reg+reg].  */
10874117395Skan	  }
10875169689Skan	if (TARGET_ALTIVEC
10876169689Skan	    && GET_CODE (tmp) == AND
10877169689Skan	    && GET_CODE (XEXP (tmp, 1)) == CONST_INT
10878169689Skan	    && INTVAL (XEXP (tmp, 1)) == -16)
10879169689Skan	  tmp = XEXP (tmp, 0);
1088090075Sobrien	if (GET_CODE (tmp) == REG)
1088190075Sobrien	  fprintf (file, "0,%s", reg_names[REGNO (tmp)]);
10882169689Skan	else
1088390075Sobrien	  {
10884169689Skan	    gcc_assert (GET_CODE (tmp) == PLUS
10885169689Skan			&& REG_P (XEXP (tmp, 0))
10886169689Skan			&& REG_P (XEXP (tmp, 1)));
10887169689Skan
1088890075Sobrien	    if (REGNO (XEXP (tmp, 0)) == 0)
1088990075Sobrien	      fprintf (file, "%s,%s", reg_names[ REGNO (XEXP (tmp, 1)) ],
1089090075Sobrien		       reg_names[ REGNO (XEXP (tmp, 0)) ]);
1089190075Sobrien	    else
1089290075Sobrien	      fprintf (file, "%s,%s", reg_names[ REGNO (XEXP (tmp, 0)) ],
1089390075Sobrien		       reg_names[ REGNO (XEXP (tmp, 1)) ]);
1089490075Sobrien	  }
1089590075Sobrien	break;
1089690075Sobrien      }
10897169689Skan
1089890075Sobrien    case 0:
1089990075Sobrien      if (GET_CODE (x) == REG)
1090090075Sobrien	fprintf (file, "%s", reg_names[REGNO (x)]);
1090190075Sobrien      else if (GET_CODE (x) == MEM)
1090290075Sobrien	{
1090390075Sobrien	  /* We need to handle PRE_INC and PRE_DEC here, since we need to
1090490075Sobrien	     know the width from the mode.  */
1090590075Sobrien	  if (GET_CODE (XEXP (x, 0)) == PRE_INC)
1090690075Sobrien	    fprintf (file, "%d(%s)", GET_MODE_SIZE (GET_MODE (x)),
1090790075Sobrien		     reg_names[REGNO (XEXP (XEXP (x, 0), 0))]);
1090890075Sobrien	  else if (GET_CODE (XEXP (x, 0)) == PRE_DEC)
1090990075Sobrien	    fprintf (file, "%d(%s)", - GET_MODE_SIZE (GET_MODE (x)),
1091090075Sobrien		     reg_names[REGNO (XEXP (XEXP (x, 0), 0))]);
1091190075Sobrien	  else
1091290075Sobrien	    output_address (XEXP (x, 0));
1091390075Sobrien	}
1091490075Sobrien      else
1091590075Sobrien	output_addr_const (file, x);
1091690075Sobrien      return;
1091790075Sobrien
10918132718Skan    case '&':
10919132718Skan      assemble_name (file, rs6000_get_some_local_dynamic_name ());
10920132718Skan      return;
10921132718Skan
1092290075Sobrien    default:
1092390075Sobrien      output_operand_lossage ("invalid %%xn code");
1092490075Sobrien    }
1092590075Sobrien}
1092690075Sobrien
1092790075Sobrien/* Print the address of an operand.  */
1092890075Sobrien
1092990075Sobrienvoid
10930132718Skanprint_operand_address (FILE *file, rtx x)
1093190075Sobrien{
1093290075Sobrien  if (GET_CODE (x) == REG)
1093390075Sobrien    fprintf (file, "0(%s)", reg_names[ REGNO (x) ]);
1093490075Sobrien  else if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == CONST
1093590075Sobrien	   || GET_CODE (x) == LABEL_REF)
1093690075Sobrien    {
1093790075Sobrien      output_addr_const (file, x);
1093890075Sobrien      if (small_data_operand (x, GET_MODE (x)))
1093990075Sobrien	fprintf (file, "@%s(%s)", SMALL_DATA_RELOC,
1094090075Sobrien		 reg_names[SMALL_DATA_REG]);
10941169689Skan      else
10942169689Skan	gcc_assert (!TARGET_TOC);
1094390075Sobrien    }
1094490075Sobrien  else if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == REG)
1094590075Sobrien    {
10946169689Skan      gcc_assert (REG_P (XEXP (x, 0)));
1094790075Sobrien      if (REGNO (XEXP (x, 0)) == 0)
1094890075Sobrien	fprintf (file, "%s,%s", reg_names[ REGNO (XEXP (x, 1)) ],
1094990075Sobrien		 reg_names[ REGNO (XEXP (x, 0)) ]);
1095090075Sobrien      else
1095190075Sobrien	fprintf (file, "%s,%s", reg_names[ REGNO (XEXP (x, 0)) ],
1095290075Sobrien		 reg_names[ REGNO (XEXP (x, 1)) ]);
1095390075Sobrien    }
1095490075Sobrien  else if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
10955132718Skan    fprintf (file, HOST_WIDE_INT_PRINT_DEC "(%s)",
10956132718Skan	     INTVAL (XEXP (x, 1)), reg_names[ REGNO (XEXP (x, 0)) ]);
1095790075Sobrien#if TARGET_ELF
1095890075Sobrien  else if (GET_CODE (x) == LO_SUM && GET_CODE (XEXP (x, 0)) == REG
10959169689Skan	   && CONSTANT_P (XEXP (x, 1)))
1096090075Sobrien    {
1096190075Sobrien      output_addr_const (file, XEXP (x, 1));
1096290075Sobrien      fprintf (file, "@l(%s)", reg_names[ REGNO (XEXP (x, 0)) ]);
1096390075Sobrien    }
1096490075Sobrien#endif
1096590075Sobrien#if TARGET_MACHO
1096690075Sobrien  else if (GET_CODE (x) == LO_SUM && GET_CODE (XEXP (x, 0)) == REG
10967169689Skan	   && CONSTANT_P (XEXP (x, 1)))
1096890075Sobrien    {
1096990075Sobrien      fprintf (file, "lo16(");
1097090075Sobrien      output_addr_const (file, XEXP (x, 1));
1097190075Sobrien      fprintf (file, ")(%s)", reg_names[ REGNO (XEXP (x, 0)) ]);
1097290075Sobrien    }
1097390075Sobrien#endif
10974132718Skan  else if (legitimate_constant_pool_address_p (x))
1097590075Sobrien    {
1097690075Sobrien      if (TARGET_AIX && (!TARGET_ELF || !TARGET_MINIMAL_TOC))
1097790075Sobrien	{
1097890075Sobrien	  rtx contains_minus = XEXP (x, 1);
1097990075Sobrien	  rtx minus, symref;
1098090075Sobrien	  const char *name;
10981169689Skan
1098290075Sobrien	  /* Find the (minus (sym) (toc)) buried in X, and temporarily
1098390075Sobrien	     turn it into (sym) for output_addr_const.  */
1098490075Sobrien	  while (GET_CODE (XEXP (contains_minus, 0)) != MINUS)
1098590075Sobrien	    contains_minus = XEXP (contains_minus, 0);
1098690075Sobrien
1098790075Sobrien	  minus = XEXP (contains_minus, 0);
1098890075Sobrien	  symref = XEXP (minus, 0);
1098990075Sobrien	  XEXP (contains_minus, 0) = symref;
1099090075Sobrien	  if (TARGET_ELF)
1099190075Sobrien	    {
1099290075Sobrien	      char *newname;
1099390075Sobrien
1099490075Sobrien	      name = XSTR (symref, 0);
1099590075Sobrien	      newname = alloca (strlen (name) + sizeof ("@toc"));
1099690075Sobrien	      strcpy (newname, name);
1099790075Sobrien	      strcat (newname, "@toc");
1099890075Sobrien	      XSTR (symref, 0) = newname;
1099990075Sobrien	    }
1100090075Sobrien	  output_addr_const (file, XEXP (x, 1));
1100190075Sobrien	  if (TARGET_ELF)
1100290075Sobrien	    XSTR (symref, 0) = name;
1100390075Sobrien	  XEXP (contains_minus, 0) = minus;
1100490075Sobrien	}
1100590075Sobrien      else
1100690075Sobrien	output_addr_const (file, XEXP (x, 1));
1100790075Sobrien
1100890075Sobrien      fprintf (file, "(%s)", reg_names[REGNO (XEXP (x, 0))]);
1100990075Sobrien    }
1101090075Sobrien  else
11011169689Skan    gcc_unreachable ();
1101290075Sobrien}
1101390075Sobrien
11014117395Skan/* Target hook for assembling integer objects.  The PowerPC version has
1101590075Sobrien   to handle fixup entries for relocatable code if RELOCATABLE_NEEDS_FIXUP
1101690075Sobrien   is defined.  It also needs to handle DI-mode objects on 64-bit
1101790075Sobrien   targets.  */
1101890075Sobrien
1101990075Sobrienstatic bool
11020132718Skanrs6000_assemble_integer (rtx x, unsigned int size, int aligned_p)
1102190075Sobrien{
1102290075Sobrien#ifdef RELOCATABLE_NEEDS_FIXUP
1102390075Sobrien  /* Special handling for SI values.  */
11024146895Skan  if (RELOCATABLE_NEEDS_FIXUP && size == 4 && aligned_p)
1102590075Sobrien    {
1102690075Sobrien      static int recurse = 0;
11027169689Skan
1102890075Sobrien      /* For -mrelocatable, we mark all addresses that need to be fixed up
1102990075Sobrien	 in the .fixup section.  */
1103090075Sobrien      if (TARGET_RELOCATABLE
11031169689Skan	  && in_section != toc_section
11032169689Skan	  && in_section != text_section
11033169689Skan	  && !unlikely_text_section_p (in_section)
1103490075Sobrien	  && !recurse
1103590075Sobrien	  && GET_CODE (x) != CONST_INT
1103690075Sobrien	  && GET_CODE (x) != CONST_DOUBLE
1103790075Sobrien	  && CONSTANT_P (x))
1103890075Sobrien	{
1103990075Sobrien	  char buf[256];
1104090075Sobrien
1104190075Sobrien	  recurse = 1;
1104290075Sobrien	  ASM_GENERATE_INTERNAL_LABEL (buf, "LCP", fixuplabelno);
1104390075Sobrien	  fixuplabelno++;
1104490075Sobrien	  ASM_OUTPUT_LABEL (asm_out_file, buf);
1104590075Sobrien	  fprintf (asm_out_file, "\t.long\t(");
1104690075Sobrien	  output_addr_const (asm_out_file, x);
1104790075Sobrien	  fprintf (asm_out_file, ")@fixup\n");
1104890075Sobrien	  fprintf (asm_out_file, "\t.section\t\".fixup\",\"aw\"\n");
1104990075Sobrien	  ASM_OUTPUT_ALIGN (asm_out_file, 2);
1105090075Sobrien	  fprintf (asm_out_file, "\t.long\t");
1105190075Sobrien	  assemble_name (asm_out_file, buf);
1105290075Sobrien	  fprintf (asm_out_file, "\n\t.previous\n");
1105390075Sobrien	  recurse = 0;
1105490075Sobrien	  return true;
1105590075Sobrien	}
1105690075Sobrien      /* Remove initial .'s to turn a -mcall-aixdesc function
1105790075Sobrien	 address into the address of the descriptor, not the function
1105890075Sobrien	 itself.  */
1105990075Sobrien      else if (GET_CODE (x) == SYMBOL_REF
1106090075Sobrien	       && XSTR (x, 0)[0] == '.'
1106190075Sobrien	       && DEFAULT_ABI == ABI_AIX)
1106290075Sobrien	{
1106390075Sobrien	  const char *name = XSTR (x, 0);
1106490075Sobrien	  while (*name == '.')
1106590075Sobrien	    name++;
1106690075Sobrien
1106790075Sobrien	  fprintf (asm_out_file, "\t.long\t%s\n", name);
1106890075Sobrien	  return true;
1106990075Sobrien	}
1107090075Sobrien    }
1107190075Sobrien#endif /* RELOCATABLE_NEEDS_FIXUP */
1107290075Sobrien  return default_assemble_integer (x, size, aligned_p);
1107390075Sobrien}
11074117395Skan
11075117395Skan#ifdef HAVE_GAS_HIDDEN
11076117395Skan/* Emit an assembler directive to set symbol visibility for DECL to
11077117395Skan   VISIBILITY_TYPE.  */
11078117395Skan
11079117395Skanstatic void
11080132718Skanrs6000_assemble_visibility (tree decl, int vis)
11081117395Skan{
11082117395Skan  /* Functions need to have their entry point symbol visibility set as
11083117395Skan     well as their descriptor symbol visibility.  */
11084169689Skan  if (DEFAULT_ABI == ABI_AIX
11085169689Skan      && DOT_SYMBOLS
11086169689Skan      && TREE_CODE (decl) == FUNCTION_DECL)
11087117395Skan    {
11088117395Skan      static const char * const visibility_types[] = {
11089169689Skan	NULL, "internal", "hidden", "protected"
11090117395Skan      };
11091117395Skan
11092117395Skan      const char *name, *type;
11093117395Skan
11094117395Skan      name = ((* targetm.strip_name_encoding)
11095117395Skan	      (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl))));
11096117395Skan      type = visibility_types[vis];
11097117395Skan
11098117395Skan      fprintf (asm_out_file, "\t.%s\t%s\n", type, name);
11099117395Skan      fprintf (asm_out_file, "\t.%s\t.%s\n", type, name);
11100117395Skan    }
11101117395Skan  else
11102117395Skan    default_assemble_visibility (decl, vis);
11103117395Skan}
11104117395Skan#endif
1110590075Sobrien
1110690075Sobrienenum rtx_code
11107132718Skanrs6000_reverse_condition (enum machine_mode mode, enum rtx_code code)
1110890075Sobrien{
1110990075Sobrien  /* Reversal of FP compares takes care -- an ordered compare
1111090075Sobrien     becomes an unordered compare and vice versa.  */
11111169689Skan  if (mode == CCFPmode
11112132718Skan      && (!flag_finite_math_only
11113132718Skan	  || code == UNLT || code == UNLE || code == UNGT || code == UNGE
11114132718Skan	  || code == UNEQ || code == LTGT))
1111590075Sobrien    return reverse_condition_maybe_unordered (code);
1111690075Sobrien  else
1111790075Sobrien    return reverse_condition (code);
1111890075Sobrien}
1111990075Sobrien
1112090075Sobrien/* Generate a compare for CODE.  Return a brand-new rtx that
1112190075Sobrien   represents the result of the compare.  */
1112290075Sobrien
1112390075Sobrienstatic rtx
11124132718Skanrs6000_generate_compare (enum rtx_code code)
1112590075Sobrien{
1112690075Sobrien  enum machine_mode comp_mode;
1112790075Sobrien  rtx compare_result;
1112890075Sobrien
1112990075Sobrien  if (rs6000_compare_fp_p)
1113090075Sobrien    comp_mode = CCFPmode;
1113190075Sobrien  else if (code == GTU || code == LTU
11132169689Skan	   || code == GEU || code == LEU)
1113390075Sobrien    comp_mode = CCUNSmode;
11134169689Skan  else if ((code == EQ || code == NE)
11135169689Skan	   && GET_CODE (rs6000_compare_op0) == SUBREG
11136169689Skan	   && GET_CODE (rs6000_compare_op1) == SUBREG
11137169689Skan	   && SUBREG_PROMOTED_UNSIGNED_P (rs6000_compare_op0)
11138169689Skan	   && SUBREG_PROMOTED_UNSIGNED_P (rs6000_compare_op1))
11139169689Skan    /* These are unsigned values, perhaps there will be a later
11140169689Skan       ordering compare that can be shared with this one.
11141169689Skan       Unfortunately we cannot detect the signedness of the operands
11142169689Skan       for non-subregs.  */
11143169689Skan    comp_mode = CCUNSmode;
1114490075Sobrien  else
1114590075Sobrien    comp_mode = CCmode;
1114690075Sobrien
1114790075Sobrien  /* First, the compare.  */
1114890075Sobrien  compare_result = gen_reg_rtx (comp_mode);
11149117395Skan
11150169689Skan  /* E500 FP compare instructions on the GPRs.  Yuck!  */
11151132718Skan  if ((TARGET_E500 && !TARGET_FPRS && TARGET_HARD_FLOAT)
11152132718Skan      && rs6000_compare_fp_p)
11153117395Skan    {
11154169689Skan      rtx cmp, or_result, compare_result2;
11155169689Skan      enum machine_mode op_mode = GET_MODE (rs6000_compare_op0);
11156117395Skan
11157169689Skan      if (op_mode == VOIDmode)
11158169689Skan	op_mode = GET_MODE (rs6000_compare_op1);
11159132718Skan
11160169689Skan      /* The E500 FP compare instructions toggle the GT bit (CR bit 1) only.
11161169689Skan	 This explains the following mess.  */
11162169689Skan
11163117395Skan      switch (code)
11164117395Skan	{
11165169689Skan	case EQ: case UNEQ: case NE: case LTGT:
11166169689Skan	  switch (op_mode)
11167169689Skan	    {
11168169689Skan	    case SFmode:
11169169689Skan	      cmp = flag_unsafe_math_optimizations
11170169689Skan		? gen_tstsfeq_gpr (compare_result, rs6000_compare_op0,
11171169689Skan				   rs6000_compare_op1)
11172169689Skan		: gen_cmpsfeq_gpr (compare_result, rs6000_compare_op0,
11173169689Skan				   rs6000_compare_op1);
11174169689Skan	      break;
11175169689Skan
11176169689Skan	    case DFmode:
11177169689Skan	      cmp = flag_unsafe_math_optimizations
11178169689Skan		? gen_tstdfeq_gpr (compare_result, rs6000_compare_op0,
11179169689Skan				   rs6000_compare_op1)
11180169689Skan		: gen_cmpdfeq_gpr (compare_result, rs6000_compare_op0,
11181169689Skan				   rs6000_compare_op1);
11182169689Skan	      break;
11183169689Skan
11184169689Skan	    default:
11185169689Skan	      gcc_unreachable ();
11186169689Skan	    }
11187117395Skan	  break;
11188169689Skan
11189169689Skan	case GT: case GTU: case UNGT: case UNGE: case GE: case GEU:
11190169689Skan	  switch (op_mode)
11191169689Skan	    {
11192169689Skan	    case SFmode:
11193169689Skan	      cmp = flag_unsafe_math_optimizations
11194169689Skan		? gen_tstsfgt_gpr (compare_result, rs6000_compare_op0,
11195169689Skan				   rs6000_compare_op1)
11196169689Skan		: gen_cmpsfgt_gpr (compare_result, rs6000_compare_op0,
11197169689Skan				   rs6000_compare_op1);
11198169689Skan	      break;
11199169689Skan
11200169689Skan	    case DFmode:
11201169689Skan	      cmp = flag_unsafe_math_optimizations
11202169689Skan		? gen_tstdfgt_gpr (compare_result, rs6000_compare_op0,
11203169689Skan				   rs6000_compare_op1)
11204169689Skan		: gen_cmpdfgt_gpr (compare_result, rs6000_compare_op0,
11205169689Skan				   rs6000_compare_op1);
11206169689Skan	      break;
11207169689Skan
11208169689Skan	    default:
11209169689Skan	      gcc_unreachable ();
11210169689Skan	    }
11211117395Skan	  break;
11212169689Skan
11213169689Skan	case LT: case LTU: case UNLT: case UNLE: case LE: case LEU:
11214169689Skan	  switch (op_mode)
11215169689Skan	    {
11216169689Skan	    case SFmode:
11217169689Skan	      cmp = flag_unsafe_math_optimizations
11218169689Skan		? gen_tstsflt_gpr (compare_result, rs6000_compare_op0,
11219169689Skan				   rs6000_compare_op1)
11220169689Skan		: gen_cmpsflt_gpr (compare_result, rs6000_compare_op0,
11221169689Skan				   rs6000_compare_op1);
11222169689Skan	      break;
11223169689Skan
11224169689Skan	    case DFmode:
11225169689Skan	      cmp = flag_unsafe_math_optimizations
11226169689Skan		? gen_tstdflt_gpr (compare_result, rs6000_compare_op0,
11227169689Skan				   rs6000_compare_op1)
11228169689Skan		: gen_cmpdflt_gpr (compare_result, rs6000_compare_op0,
11229169689Skan				   rs6000_compare_op1);
11230169689Skan	      break;
11231169689Skan
11232169689Skan	    default:
11233169689Skan	      gcc_unreachable ();
11234169689Skan	    }
11235117395Skan	  break;
11236169689Skan        default:
11237169689Skan          gcc_unreachable ();
11238117395Skan	}
11239117395Skan
11240117395Skan      /* Synthesize LE and GE from LT/GT || EQ.  */
11241117395Skan      if (code == LE || code == GE || code == LEU || code == GEU)
11242117395Skan	{
11243117395Skan	  emit_insn (cmp);
11244117395Skan
11245117395Skan	  switch (code)
11246117395Skan	    {
11247117395Skan	    case LE: code = LT; break;
11248117395Skan	    case GE: code = GT; break;
11249117395Skan	    case LEU: code = LT; break;
11250117395Skan	    case GEU: code = GT; break;
11251169689Skan	    default: gcc_unreachable ();
11252117395Skan	    }
11253117395Skan
11254117395Skan	  compare_result2 = gen_reg_rtx (CCFPmode);
11255117395Skan
11256117395Skan	  /* Do the EQ.  */
11257169689Skan	  switch (op_mode)
11258169689Skan	    {
11259169689Skan	    case SFmode:
11260169689Skan	      cmp = flag_unsafe_math_optimizations
11261169689Skan		? gen_tstsfeq_gpr (compare_result2, rs6000_compare_op0,
11262169689Skan				   rs6000_compare_op1)
11263169689Skan		: gen_cmpsfeq_gpr (compare_result2, rs6000_compare_op0,
11264169689Skan				   rs6000_compare_op1);
11265169689Skan	      break;
11266169689Skan
11267169689Skan	    case DFmode:
11268169689Skan	      cmp = flag_unsafe_math_optimizations
11269169689Skan		? gen_tstdfeq_gpr (compare_result2, rs6000_compare_op0,
11270169689Skan				   rs6000_compare_op1)
11271169689Skan		: gen_cmpdfeq_gpr (compare_result2, rs6000_compare_op0,
11272169689Skan				   rs6000_compare_op1);
11273169689Skan	      break;
11274169689Skan
11275169689Skan	    default:
11276169689Skan	      gcc_unreachable ();
11277169689Skan	    }
11278117395Skan	  emit_insn (cmp);
11279117395Skan
11280117395Skan	  /* OR them together.  */
11281169689Skan	  or_result = gen_reg_rtx (CCFPmode);
11282169689Skan	  cmp = gen_e500_cr_ior_compare (or_result, compare_result,
11283169689Skan					   compare_result2);
11284117395Skan	  compare_result = or_result;
11285117395Skan	  code = EQ;
11286117395Skan	}
11287117395Skan      else
11288117395Skan	{
11289117395Skan	  if (code == NE || code == LTGT)
11290117395Skan	    code = NE;
11291169689Skan	  else
11292169689Skan	    code = EQ;
11293117395Skan	}
11294117395Skan
11295117395Skan      emit_insn (cmp);
11296117395Skan    }
11297117395Skan  else
11298146895Skan    {
11299146895Skan      /* Generate XLC-compatible TFmode compare as PARALLEL with extra
11300169689Skan	 CLOBBERs to match cmptf_internal2 pattern.  */
11301146895Skan      if (comp_mode == CCFPmode && TARGET_XL_COMPAT
11302169689Skan	  && GET_MODE (rs6000_compare_op0) == TFmode
11303169689Skan	  && !TARGET_IEEEQUAD
11304169689Skan	  && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128)
11305169689Skan	emit_insn (gen_rtx_PARALLEL (VOIDmode,
11306169689Skan	  gen_rtvec (9,
11307146895Skan		     gen_rtx_SET (VOIDmode,
11308146895Skan				  compare_result,
11309146895Skan				  gen_rtx_COMPARE (comp_mode,
11310146895Skan						   rs6000_compare_op0,
11311146895Skan						   rs6000_compare_op1)),
11312146895Skan		     gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
11313146895Skan		     gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
11314146895Skan		     gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
11315146895Skan		     gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
11316146895Skan		     gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
11317146895Skan		     gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
11318146895Skan		     gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
11319146895Skan		     gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)))));
11320169689Skan      else if (GET_CODE (rs6000_compare_op1) == UNSPEC
11321169689Skan	       && XINT (rs6000_compare_op1, 1) == UNSPEC_SP_TEST)
11322169689Skan	{
11323169689Skan	  rtx op1 = XVECEXP (rs6000_compare_op1, 0, 0);
11324169689Skan	  comp_mode = CCEQmode;
11325169689Skan	  compare_result = gen_reg_rtx (CCEQmode);
11326169689Skan	  if (TARGET_64BIT)
11327169689Skan	    emit_insn (gen_stack_protect_testdi (compare_result,
11328169689Skan						 rs6000_compare_op0, op1));
11329169689Skan	  else
11330169689Skan	    emit_insn (gen_stack_protect_testsi (compare_result,
11331169689Skan						 rs6000_compare_op0, op1));
11332169689Skan	}
11333146895Skan      else
11334146895Skan	emit_insn (gen_rtx_SET (VOIDmode, compare_result,
11335146895Skan				gen_rtx_COMPARE (comp_mode,
11336169689Skan						 rs6000_compare_op0,
11337146895Skan						 rs6000_compare_op1)));
11338146895Skan    }
11339169689Skan
1134090075Sobrien  /* Some kinds of FP comparisons need an OR operation;
11341132718Skan     under flag_finite_math_only we don't bother.  */
1134290075Sobrien  if (rs6000_compare_fp_p
11343169689Skan      && !flag_finite_math_only
11344169689Skan      && !(TARGET_HARD_FLOAT && TARGET_E500 && !TARGET_FPRS)
1134590075Sobrien      && (code == LE || code == GE
1134690075Sobrien	  || code == UNEQ || code == LTGT
1134790075Sobrien	  || code == UNGT || code == UNLT))
1134890075Sobrien    {
1134990075Sobrien      enum rtx_code or1, or2;
1135090075Sobrien      rtx or1_rtx, or2_rtx, compare2_rtx;
1135190075Sobrien      rtx or_result = gen_reg_rtx (CCEQmode);
11352169689Skan
1135390075Sobrien      switch (code)
1135490075Sobrien	{
1135590075Sobrien	case LE: or1 = LT;  or2 = EQ;  break;
1135690075Sobrien	case GE: or1 = GT;  or2 = EQ;  break;
1135790075Sobrien	case UNEQ: or1 = UNORDERED;  or2 = EQ;  break;
1135890075Sobrien	case LTGT: or1 = LT;  or2 = GT;  break;
1135990075Sobrien	case UNGT: or1 = UNORDERED;  or2 = GT;  break;
1136090075Sobrien	case UNLT: or1 = UNORDERED;  or2 = LT;  break;
11361169689Skan	default:  gcc_unreachable ();
1136290075Sobrien	}
1136390075Sobrien      validate_condition_mode (or1, comp_mode);
1136490075Sobrien      validate_condition_mode (or2, comp_mode);
11365169689Skan      or1_rtx = gen_rtx_fmt_ee (or1, SImode, compare_result, const0_rtx);
11366169689Skan      or2_rtx = gen_rtx_fmt_ee (or2, SImode, compare_result, const0_rtx);
1136790075Sobrien      compare2_rtx = gen_rtx_COMPARE (CCEQmode,
1136890075Sobrien				      gen_rtx_IOR (SImode, or1_rtx, or2_rtx),
1136990075Sobrien				      const_true_rtx);
1137090075Sobrien      emit_insn (gen_rtx_SET (VOIDmode, or_result, compare2_rtx));
1137190075Sobrien
1137290075Sobrien      compare_result = or_result;
1137390075Sobrien      code = EQ;
1137490075Sobrien    }
1137590075Sobrien
1137690075Sobrien  validate_condition_mode (code, GET_MODE (compare_result));
11377169689Skan
11378169689Skan  return gen_rtx_fmt_ee (code, VOIDmode, compare_result, const0_rtx);
1137990075Sobrien}
1138090075Sobrien
1138190075Sobrien
1138290075Sobrien/* Emit the RTL for an sCOND pattern.  */
1138390075Sobrien
1138490075Sobrienvoid
11385132718Skanrs6000_emit_sCOND (enum rtx_code code, rtx result)
1138690075Sobrien{
1138790075Sobrien  rtx condition_rtx;
1138890075Sobrien  enum machine_mode op_mode;
11389132718Skan  enum rtx_code cond_code;
1139090075Sobrien
1139190075Sobrien  condition_rtx = rs6000_generate_compare (code);
11392132718Skan  cond_code = GET_CODE (condition_rtx);
1139390075Sobrien
11394132718Skan  if (TARGET_E500 && rs6000_compare_fp_p
11395132718Skan      && !TARGET_FPRS && TARGET_HARD_FLOAT)
11396132718Skan    {
11397132718Skan      rtx t;
11398132718Skan
11399132718Skan      PUT_MODE (condition_rtx, SImode);
11400132718Skan      t = XEXP (condition_rtx, 0);
11401132718Skan
11402169689Skan      gcc_assert (cond_code == NE || cond_code == EQ);
11403132718Skan
11404132718Skan      if (cond_code == NE)
11405169689Skan	emit_insn (gen_e500_flip_gt_bit (t, t));
11406132718Skan
11407169689Skan      emit_insn (gen_move_from_CR_gt_bit (result, t));
11408132718Skan      return;
11409132718Skan    }
11410132718Skan
11411132718Skan  if (cond_code == NE
11412132718Skan      || cond_code == GE || cond_code == LE
11413132718Skan      || cond_code == GEU || cond_code == LEU
11414132718Skan      || cond_code == ORDERED || cond_code == UNGE || cond_code == UNLE)
11415132718Skan    {
11416132718Skan      rtx not_result = gen_reg_rtx (CCEQmode);
11417132718Skan      rtx not_op, rev_cond_rtx;
11418132718Skan      enum machine_mode cc_mode;
11419169689Skan
11420132718Skan      cc_mode = GET_MODE (XEXP (condition_rtx, 0));
11421132718Skan
11422169689Skan      rev_cond_rtx = gen_rtx_fmt_ee (rs6000_reverse_condition (cc_mode, cond_code),
11423169689Skan				     SImode, XEXP (condition_rtx, 0), const0_rtx);
11424132718Skan      not_op = gen_rtx_COMPARE (CCEQmode, rev_cond_rtx, const0_rtx);
11425132718Skan      emit_insn (gen_rtx_SET (VOIDmode, not_result, not_op));
11426132718Skan      condition_rtx = gen_rtx_EQ (VOIDmode, not_result, const0_rtx);
11427132718Skan    }
11428132718Skan
1142990075Sobrien  op_mode = GET_MODE (rs6000_compare_op0);
1143090075Sobrien  if (op_mode == VOIDmode)
1143190075Sobrien    op_mode = GET_MODE (rs6000_compare_op1);
1143290075Sobrien
1143390075Sobrien  if (TARGET_POWERPC64 && (op_mode == DImode || rs6000_compare_fp_p))
1143490075Sobrien    {
1143590075Sobrien      PUT_MODE (condition_rtx, DImode);
1143690075Sobrien      convert_move (result, condition_rtx, 0);
1143790075Sobrien    }
1143890075Sobrien  else
1143990075Sobrien    {
1144090075Sobrien      PUT_MODE (condition_rtx, SImode);
1144190075Sobrien      emit_insn (gen_rtx_SET (VOIDmode, result, condition_rtx));
1144290075Sobrien    }
1144390075Sobrien}
1144490075Sobrien
1144590075Sobrien/* Emit a branch of kind CODE to location LOC.  */
1144690075Sobrien
1144790075Sobrienvoid
11448132718Skanrs6000_emit_cbranch (enum rtx_code code, rtx loc)
1144990075Sobrien{
1145090075Sobrien  rtx condition_rtx, loc_ref;
1145190075Sobrien
1145290075Sobrien  condition_rtx = rs6000_generate_compare (code);
1145390075Sobrien  loc_ref = gen_rtx_LABEL_REF (VOIDmode, loc);
1145490075Sobrien  emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx,
1145590075Sobrien			       gen_rtx_IF_THEN_ELSE (VOIDmode, condition_rtx,
1145690075Sobrien						     loc_ref, pc_rtx)));
1145790075Sobrien}
1145890075Sobrien
1145990075Sobrien/* Return the string to output a conditional branch to LABEL, which is
1146090075Sobrien   the operand number of the label, or -1 if the branch is really a
11461169689Skan   conditional return.
1146290075Sobrien
1146390075Sobrien   OP is the conditional expression.  XEXP (OP, 0) is assumed to be a
1146490075Sobrien   condition code register and its mode specifies what kind of
1146590075Sobrien   comparison we made.
1146690075Sobrien
11467117395Skan   REVERSED is nonzero if we should reverse the sense of the comparison.
1146890075Sobrien
1146990075Sobrien   INSN is the insn.  */
1147090075Sobrien
1147190075Sobrienchar *
11472132718Skanoutput_cbranch (rtx op, const char *label, int reversed, rtx insn)
1147390075Sobrien{
1147490075Sobrien  static char string[64];
1147590075Sobrien  enum rtx_code code = GET_CODE (op);
1147690075Sobrien  rtx cc_reg = XEXP (op, 0);
1147790075Sobrien  enum machine_mode mode = GET_MODE (cc_reg);
1147890075Sobrien  int cc_regno = REGNO (cc_reg) - CR0_REGNO;
1147990075Sobrien  int need_longbranch = label != NULL && get_attr_length (insn) == 8;
1148090075Sobrien  int really_reversed = reversed ^ need_longbranch;
1148190075Sobrien  char *s = string;
1148290075Sobrien  const char *ccode;
1148390075Sobrien  const char *pred;
1148490075Sobrien  rtx note;
1148590075Sobrien
1148690075Sobrien  validate_condition_mode (code, mode);
1148790075Sobrien
1148890075Sobrien  /* Work out which way this really branches.  We could use
1148990075Sobrien     reverse_condition_maybe_unordered here always but this
1149090075Sobrien     makes the resulting assembler clearer.  */
1149190075Sobrien  if (really_reversed)
11492107590Sobrien    {
11493107590Sobrien      /* Reversal of FP compares takes care -- an ordered compare
11494107590Sobrien	 becomes an unordered compare and vice versa.  */
11495107590Sobrien      if (mode == CCFPmode)
11496107590Sobrien	code = reverse_condition_maybe_unordered (code);
11497107590Sobrien      else
11498107590Sobrien	code = reverse_condition (code);
11499107590Sobrien    }
1150090075Sobrien
11501132718Skan  if ((TARGET_E500 && !TARGET_FPRS && TARGET_HARD_FLOAT) && mode == CCFPmode)
11502117395Skan    {
11503117395Skan      /* The efscmp/tst* instructions twiddle bit 2, which maps nicely
11504117395Skan	 to the GT bit.  */
11505169689Skan      switch (code)
11506169689Skan	{
11507169689Skan	case EQ:
11508169689Skan	  /* Opposite of GT.  */
11509169689Skan	  code = GT;
11510169689Skan	  break;
11511169689Skan
11512169689Skan	case NE:
11513169689Skan	  code = UNLE;
11514169689Skan	  break;
11515169689Skan
11516169689Skan	default:
11517169689Skan	  gcc_unreachable ();
11518169689Skan	}
11519117395Skan    }
11520117395Skan
1152190075Sobrien  switch (code)
1152290075Sobrien    {
1152390075Sobrien      /* Not all of these are actually distinct opcodes, but
1152490075Sobrien	 we distinguish them for clarity of the resulting assembler.  */
1152590075Sobrien    case NE: case LTGT:
1152690075Sobrien      ccode = "ne"; break;
1152790075Sobrien    case EQ: case UNEQ:
1152890075Sobrien      ccode = "eq"; break;
11529169689Skan    case GE: case GEU:
1153090075Sobrien      ccode = "ge"; break;
11531169689Skan    case GT: case GTU: case UNGT:
1153290075Sobrien      ccode = "gt"; break;
11533169689Skan    case LE: case LEU:
1153490075Sobrien      ccode = "le"; break;
11535169689Skan    case LT: case LTU: case UNLT:
1153690075Sobrien      ccode = "lt"; break;
1153790075Sobrien    case UNORDERED: ccode = "un"; break;
1153890075Sobrien    case ORDERED: ccode = "nu"; break;
1153990075Sobrien    case UNGE: ccode = "nl"; break;
1154090075Sobrien    case UNLE: ccode = "ng"; break;
1154190075Sobrien    default:
11542169689Skan      gcc_unreachable ();
1154390075Sobrien    }
11544169689Skan
11545169689Skan  /* Maybe we have a guess as to how likely the branch is.
1154690075Sobrien     The old mnemonics don't have a way to specify this information.  */
11547117395Skan  pred = "";
1154890075Sobrien  note = find_reg_note (insn, REG_BR_PROB, NULL_RTX);
1154990075Sobrien  if (note != NULL_RTX)
1155090075Sobrien    {
1155190075Sobrien      /* PROB is the difference from 50%.  */
1155290075Sobrien      int prob = INTVAL (XEXP (note, 0)) - REG_BR_PROB_BASE / 2;
11553117395Skan
11554117395Skan      /* Only hint for highly probable/improbable branches on newer
11555117395Skan	 cpus as static prediction overrides processor dynamic
11556117395Skan	 prediction.  For older cpus we may as well always hint, but
11557117395Skan	 assume not taken for branches that are very close to 50% as a
11558117395Skan	 mispredicted taken branch is more expensive than a
11559169689Skan	 mispredicted not-taken branch.  */
11560132718Skan      if (rs6000_always_hint
11561169689Skan	  || (abs (prob) > REG_BR_PROB_BASE / 100 * 48
11562169689Skan	      && br_prob_note_reliable_p (note)))
11563117395Skan	{
11564117395Skan	  if (abs (prob) > REG_BR_PROB_BASE / 20
11565117395Skan	      && ((prob > 0) ^ need_longbranch))
11566169689Skan	    pred = "+";
11567117395Skan	  else
11568117395Skan	    pred = "-";
11569117395Skan	}
1157090075Sobrien    }
1157190075Sobrien
1157290075Sobrien  if (label == NULL)
1157390075Sobrien    s += sprintf (s, "{b%sr|b%slr%s} ", ccode, ccode, pred);
1157490075Sobrien  else
1157590075Sobrien    s += sprintf (s, "{b%s|b%s%s} ", ccode, ccode, pred);
1157690075Sobrien
1157790075Sobrien  /* We need to escape any '%' characters in the reg_names string.
11578132718Skan     Assume they'd only be the first character....  */
1157990075Sobrien  if (reg_names[cc_regno + CR0_REGNO][0] == '%')
1158090075Sobrien    *s++ = '%';
1158190075Sobrien  s += sprintf (s, "%s", reg_names[cc_regno + CR0_REGNO]);
1158290075Sobrien
1158390075Sobrien  if (label != NULL)
1158490075Sobrien    {
1158590075Sobrien      /* If the branch distance was too far, we may have to use an
1158690075Sobrien	 unconditional branch to go the distance.  */
1158790075Sobrien      if (need_longbranch)
1158890075Sobrien	s += sprintf (s, ",$+8\n\tb %s", label);
1158990075Sobrien      else
1159090075Sobrien	s += sprintf (s, ",%s", label);
1159190075Sobrien    }
1159290075Sobrien
1159390075Sobrien  return string;
1159490075Sobrien}
1159590075Sobrien
11596169689Skan/* Return the string to flip the GT bit on a CR.  */
11597132718Skanchar *
11598169689Skanoutput_e500_flip_gt_bit (rtx dst, rtx src)
11599132718Skan{
11600132718Skan  static char string[64];
11601132718Skan  int a, b;
11602132718Skan
11603169689Skan  gcc_assert (GET_CODE (dst) == REG && CR_REGNO_P (REGNO (dst))
11604169689Skan	      && GET_CODE (src) == REG && CR_REGNO_P (REGNO (src)));
11605132718Skan
11606169689Skan  /* GT bit.  */
11607169689Skan  a = 4 * (REGNO (dst) - CR0_REGNO) + 1;
11608169689Skan  b = 4 * (REGNO (src) - CR0_REGNO) + 1;
11609132718Skan
11610132718Skan  sprintf (string, "crnot %d,%d", a, b);
11611132718Skan  return string;
11612132718Skan}
11613132718Skan
11614169689Skan/* Return insn index for the vector compare instruction for given CODE,
11615169689Skan   and DEST_MODE, OP_MODE. Return INSN_NOT_AVAILABLE if valid insn is
11616169689Skan   not available.  */
11617169689Skan
11618169689Skanstatic int
11619169689Skanget_vec_cmp_insn (enum rtx_code code,
11620169689Skan		  enum machine_mode dest_mode,
11621169689Skan		  enum machine_mode op_mode)
11622169689Skan{
11623169689Skan  if (!TARGET_ALTIVEC)
11624169689Skan    return INSN_NOT_AVAILABLE;
11625169689Skan
11626169689Skan  switch (code)
11627169689Skan    {
11628169689Skan    case EQ:
11629169689Skan      if (dest_mode == V16QImode && op_mode == V16QImode)
11630169689Skan	return UNSPEC_VCMPEQUB;
11631169689Skan      if (dest_mode == V8HImode && op_mode == V8HImode)
11632169689Skan	return UNSPEC_VCMPEQUH;
11633169689Skan      if (dest_mode == V4SImode && op_mode == V4SImode)
11634169689Skan	return UNSPEC_VCMPEQUW;
11635169689Skan      if (dest_mode == V4SImode && op_mode == V4SFmode)
11636169689Skan	return UNSPEC_VCMPEQFP;
11637169689Skan      break;
11638169689Skan    case GE:
11639169689Skan      if (dest_mode == V4SImode && op_mode == V4SFmode)
11640169689Skan	return UNSPEC_VCMPGEFP;
11641169689Skan    case GT:
11642169689Skan      if (dest_mode == V16QImode && op_mode == V16QImode)
11643169689Skan	return UNSPEC_VCMPGTSB;
11644169689Skan      if (dest_mode == V8HImode && op_mode == V8HImode)
11645169689Skan	return UNSPEC_VCMPGTSH;
11646169689Skan      if (dest_mode == V4SImode && op_mode == V4SImode)
11647169689Skan	return UNSPEC_VCMPGTSW;
11648169689Skan      if (dest_mode == V4SImode && op_mode == V4SFmode)
11649169689Skan	return UNSPEC_VCMPGTFP;
11650169689Skan      break;
11651169689Skan    case GTU:
11652169689Skan      if (dest_mode == V16QImode && op_mode == V16QImode)
11653169689Skan	return UNSPEC_VCMPGTUB;
11654169689Skan      if (dest_mode == V8HImode && op_mode == V8HImode)
11655169689Skan	return UNSPEC_VCMPGTUH;
11656169689Skan      if (dest_mode == V4SImode && op_mode == V4SImode)
11657169689Skan	return UNSPEC_VCMPGTUW;
11658169689Skan      break;
11659169689Skan    default:
11660169689Skan      break;
11661169689Skan    }
11662169689Skan  return INSN_NOT_AVAILABLE;
11663169689Skan}
11664169689Skan
11665169689Skan/* Emit vector compare for operands OP0 and OP1 using code RCODE.
11666169689Skan   DMODE is expected destination mode. This is a recursive function.  */
11667169689Skan
11668169689Skanstatic rtx
11669169689Skanrs6000_emit_vector_compare (enum rtx_code rcode,
11670169689Skan			    rtx op0, rtx op1,
11671169689Skan			    enum machine_mode dmode)
11672169689Skan{
11673169689Skan  int vec_cmp_insn;
11674169689Skan  rtx mask;
11675169689Skan  enum machine_mode dest_mode;
11676169689Skan  enum machine_mode op_mode = GET_MODE (op1);
11677169689Skan
11678169689Skan  gcc_assert (TARGET_ALTIVEC);
11679169689Skan  gcc_assert (GET_MODE (op0) == GET_MODE (op1));
11680169689Skan
11681169689Skan  /* Floating point vector compare instructions uses destination V4SImode.
11682169689Skan     Move destination to appropriate mode later.  */
11683169689Skan  if (dmode == V4SFmode)
11684169689Skan    dest_mode = V4SImode;
11685169689Skan  else
11686169689Skan    dest_mode = dmode;
11687169689Skan
11688169689Skan  mask = gen_reg_rtx (dest_mode);
11689169689Skan  vec_cmp_insn = get_vec_cmp_insn (rcode, dest_mode, op_mode);
11690169689Skan
11691169689Skan  if (vec_cmp_insn == INSN_NOT_AVAILABLE)
11692169689Skan    {
11693169689Skan      bool swap_operands = false;
11694169689Skan      bool try_again = false;
11695169689Skan      switch (rcode)
11696169689Skan	{
11697169689Skan	case LT:
11698169689Skan	  rcode = GT;
11699169689Skan	  swap_operands = true;
11700169689Skan	  try_again = true;
11701169689Skan	  break;
11702169689Skan	case LTU:
11703169689Skan	  rcode = GTU;
11704169689Skan	  swap_operands = true;
11705169689Skan	  try_again = true;
11706169689Skan	  break;
11707169689Skan	case NE:
11708169689Skan	  /* Treat A != B as ~(A==B).  */
11709169689Skan	  {
11710169689Skan	    enum insn_code nor_code;
11711169689Skan	    rtx eq_rtx = rs6000_emit_vector_compare (EQ, op0, op1,
11712169689Skan						     dest_mode);
11713169689Skan
11714169689Skan	    nor_code = one_cmpl_optab->handlers[(int)dest_mode].insn_code;
11715169689Skan	    gcc_assert (nor_code != CODE_FOR_nothing);
11716169689Skan	    emit_insn (GEN_FCN (nor_code) (mask, eq_rtx));
11717169689Skan
11718169689Skan	    if (dmode != dest_mode)
11719169689Skan	      {
11720169689Skan		rtx temp = gen_reg_rtx (dest_mode);
11721169689Skan		convert_move (temp, mask, 0);
11722169689Skan		return temp;
11723169689Skan	      }
11724169689Skan	    return mask;
11725169689Skan	  }
11726169689Skan	  break;
11727169689Skan	case GE:
11728169689Skan	case GEU:
11729169689Skan	case LE:
11730169689Skan	case LEU:
11731169689Skan	  /* Try GT/GTU/LT/LTU OR EQ */
11732169689Skan	  {
11733169689Skan	    rtx c_rtx, eq_rtx;
11734169689Skan	    enum insn_code ior_code;
11735169689Skan	    enum rtx_code new_code;
11736169689Skan
11737169689Skan	    switch (rcode)
11738169689Skan	      {
11739169689Skan	      case  GE:
11740169689Skan		new_code = GT;
11741169689Skan		break;
11742169689Skan
11743169689Skan	      case GEU:
11744169689Skan		new_code = GTU;
11745169689Skan		break;
11746169689Skan
11747169689Skan	      case LE:
11748169689Skan		new_code = LT;
11749169689Skan		break;
11750169689Skan
11751169689Skan	      case LEU:
11752169689Skan		new_code = LTU;
11753169689Skan		break;
11754169689Skan
11755169689Skan	      default:
11756169689Skan		gcc_unreachable ();
11757169689Skan	      }
11758169689Skan
11759169689Skan	    c_rtx = rs6000_emit_vector_compare (new_code,
11760169689Skan						op0, op1, dest_mode);
11761169689Skan	    eq_rtx = rs6000_emit_vector_compare (EQ, op0, op1,
11762169689Skan						 dest_mode);
11763169689Skan
11764169689Skan	    ior_code = ior_optab->handlers[(int)dest_mode].insn_code;
11765169689Skan	    gcc_assert (ior_code != CODE_FOR_nothing);
11766169689Skan	    emit_insn (GEN_FCN (ior_code) (mask, c_rtx, eq_rtx));
11767169689Skan	    if (dmode != dest_mode)
11768169689Skan	      {
11769169689Skan		rtx temp = gen_reg_rtx (dest_mode);
11770169689Skan		convert_move (temp, mask, 0);
11771169689Skan		return temp;
11772169689Skan	      }
11773169689Skan	    return mask;
11774169689Skan	  }
11775169689Skan	  break;
11776169689Skan	default:
11777169689Skan	  gcc_unreachable ();
11778169689Skan	}
11779169689Skan
11780169689Skan      if (try_again)
11781169689Skan	{
11782169689Skan	  vec_cmp_insn = get_vec_cmp_insn (rcode, dest_mode, op_mode);
11783169689Skan	  /* You only get two chances.  */
11784169689Skan	  gcc_assert (vec_cmp_insn != INSN_NOT_AVAILABLE);
11785169689Skan	}
11786169689Skan
11787169689Skan      if (swap_operands)
11788169689Skan	{
11789169689Skan	  rtx tmp;
11790169689Skan	  tmp = op0;
11791169689Skan	  op0 = op1;
11792169689Skan	  op1 = tmp;
11793169689Skan	}
11794169689Skan    }
11795169689Skan
11796169689Skan  emit_insn (gen_rtx_SET (VOIDmode, mask,
11797169689Skan			  gen_rtx_UNSPEC (dest_mode,
11798169689Skan					  gen_rtvec (2, op0, op1),
11799169689Skan					  vec_cmp_insn)));
11800169689Skan  if (dmode != dest_mode)
11801169689Skan    {
11802169689Skan      rtx temp = gen_reg_rtx (dest_mode);
11803169689Skan      convert_move (temp, mask, 0);
11804169689Skan      return temp;
11805169689Skan    }
11806169689Skan  return mask;
11807169689Skan}
11808169689Skan
11809169689Skan/* Return vector select instruction for MODE. Return INSN_NOT_AVAILABLE, if
11810169689Skan   valid insn doesn exist for given mode.  */
11811169689Skan
11812169689Skanstatic int
11813169689Skanget_vsel_insn (enum machine_mode mode)
11814169689Skan{
11815169689Skan  switch (mode)
11816169689Skan    {
11817169689Skan    case V4SImode:
11818169689Skan      return UNSPEC_VSEL4SI;
11819169689Skan      break;
11820169689Skan    case V4SFmode:
11821169689Skan      return UNSPEC_VSEL4SF;
11822169689Skan      break;
11823169689Skan    case V8HImode:
11824169689Skan      return UNSPEC_VSEL8HI;
11825169689Skan      break;
11826169689Skan    case V16QImode:
11827169689Skan      return UNSPEC_VSEL16QI;
11828169689Skan      break;
11829169689Skan    default:
11830169689Skan      return INSN_NOT_AVAILABLE;
11831169689Skan      break;
11832169689Skan    }
11833169689Skan  return INSN_NOT_AVAILABLE;
11834169689Skan}
11835169689Skan
11836169689Skan/* Emit vector select insn where DEST is destination using
11837169689Skan   operands OP1, OP2 and MASK.  */
11838169689Skan
11839169689Skanstatic void
11840169689Skanrs6000_emit_vector_select (rtx dest, rtx op1, rtx op2, rtx mask)
11841169689Skan{
11842169689Skan  rtx t, temp;
11843169689Skan  enum machine_mode dest_mode = GET_MODE (dest);
11844169689Skan  int vsel_insn_index  = get_vsel_insn (GET_MODE (dest));
11845169689Skan
11846169689Skan  temp = gen_reg_rtx (dest_mode);
11847169689Skan
11848169689Skan  /* For each vector element, select op1 when mask is 1 otherwise
11849169689Skan     select op2.  */
11850169689Skan  t = gen_rtx_SET (VOIDmode, temp,
11851169689Skan		   gen_rtx_UNSPEC (dest_mode,
11852169689Skan				   gen_rtvec (3, op2, op1, mask),
11853169689Skan				   vsel_insn_index));
11854169689Skan  emit_insn (t);
11855169689Skan  emit_move_insn (dest, temp);
11856169689Skan  return;
11857169689Skan}
11858169689Skan
11859169689Skan/* Emit vector conditional expression.
11860169689Skan   DEST is destination. OP1 and OP2 are two VEC_COND_EXPR operands.
11861169689Skan   CC_OP0 and CC_OP1 are the two operands for the relation operation COND.  */
11862169689Skan
11863169689Skanint
11864169689Skanrs6000_emit_vector_cond_expr (rtx dest, rtx op1, rtx op2,
11865169689Skan			      rtx cond, rtx cc_op0, rtx cc_op1)
11866169689Skan{
11867169689Skan  enum machine_mode dest_mode = GET_MODE (dest);
11868169689Skan  enum rtx_code rcode = GET_CODE (cond);
11869169689Skan  rtx mask;
11870169689Skan
11871169689Skan  if (!TARGET_ALTIVEC)
11872169689Skan    return 0;
11873169689Skan
11874169689Skan  /* Get the vector mask for the given relational operations.  */
11875169689Skan  mask = rs6000_emit_vector_compare (rcode, cc_op0, cc_op1, dest_mode);
11876169689Skan
11877169689Skan  rs6000_emit_vector_select (dest, op1, op2, mask);
11878169689Skan
11879169689Skan  return 1;
11880169689Skan}
11881169689Skan
1188290075Sobrien/* Emit a conditional move: move TRUE_COND to DEST if OP of the
1188390075Sobrien   operands of the last comparison is nonzero/true, FALSE_COND if it
1188490075Sobrien   is zero/false.  Return 0 if the hardware has no such operation.  */
1188590075Sobrien
1188690075Sobrienint
11887132718Skanrs6000_emit_cmove (rtx dest, rtx op, rtx true_cond, rtx false_cond)
1188890075Sobrien{
1188990075Sobrien  enum rtx_code code = GET_CODE (op);
1189090075Sobrien  rtx op0 = rs6000_compare_op0;
1189190075Sobrien  rtx op1 = rs6000_compare_op1;
1189290075Sobrien  REAL_VALUE_TYPE c1;
1189396263Sobrien  enum machine_mode compare_mode = GET_MODE (op0);
1189496263Sobrien  enum machine_mode result_mode = GET_MODE (dest);
1189590075Sobrien  rtx temp;
11896169689Skan  bool is_against_zero;
1189790075Sobrien
11898132718Skan  /* These modes should always match.  */
11899117395Skan  if (GET_MODE (op1) != compare_mode
11900117395Skan      /* In the isel case however, we can use a compare immediate, so
11901117395Skan	 op1 may be a small constant.  */
11902117395Skan      && (!TARGET_ISEL || !short_cint_operand (op1, VOIDmode)))
1190396263Sobrien    return 0;
1190496263Sobrien  if (GET_MODE (true_cond) != result_mode)
1190596263Sobrien    return 0;
1190696263Sobrien  if (GET_MODE (false_cond) != result_mode)
1190796263Sobrien    return 0;
1190896263Sobrien
1190990075Sobrien  /* First, work out if the hardware can do this at all, or
11910132718Skan     if it's too slow....  */
1191190075Sobrien  if (! rs6000_compare_fp_p)
11912117395Skan    {
11913117395Skan      if (TARGET_ISEL)
11914117395Skan	return rs6000_emit_int_cmove (dest, op, true_cond, false_cond);
11915117395Skan      return 0;
11916117395Skan    }
11917132718Skan  else if (TARGET_E500 && TARGET_HARD_FLOAT && !TARGET_FPRS
11918169689Skan	   && SCALAR_FLOAT_MODE_P (compare_mode))
11919132718Skan    return 0;
1192090075Sobrien
11921169689Skan  is_against_zero = op1 == CONST0_RTX (compare_mode);
11922169689Skan
11923169689Skan  /* A floating-point subtract might overflow, underflow, or produce
11924169689Skan     an inexact result, thus changing the floating-point flags, so it
11925169689Skan     can't be generated if we care about that.  It's safe if one side
11926169689Skan     of the construct is zero, since then no subtract will be
11927169689Skan     generated.  */
11928169689Skan  if (SCALAR_FLOAT_MODE_P (compare_mode)
11929169689Skan      && flag_trapping_math && ! is_against_zero)
11930169689Skan    return 0;
11931169689Skan
1193290075Sobrien  /* Eliminate half of the comparisons by switching operands, this
1193390075Sobrien     makes the remaining code simpler.  */
1193490075Sobrien  if (code == UNLT || code == UNGT || code == UNORDERED || code == NE
11935132718Skan      || code == LTGT || code == LT || code == UNLE)
1193690075Sobrien    {
1193790075Sobrien      code = reverse_condition_maybe_unordered (code);
1193890075Sobrien      temp = true_cond;
1193990075Sobrien      true_cond = false_cond;
1194090075Sobrien      false_cond = temp;
1194190075Sobrien    }
1194290075Sobrien
1194390075Sobrien  /* UNEQ and LTGT take four instructions for a comparison with zero,
1194490075Sobrien     it'll probably be faster to use a branch here too.  */
11945132718Skan  if (code == UNEQ && HONOR_NANS (compare_mode))
1194690075Sobrien    return 0;
11947169689Skan
1194890075Sobrien  if (GET_CODE (op1) == CONST_DOUBLE)
1194990075Sobrien    REAL_VALUE_FROM_CONST_DOUBLE (c1, op1);
11950169689Skan
11951132718Skan  /* We're going to try to implement comparisons by performing
1195290075Sobrien     a subtract, then comparing against zero.  Unfortunately,
1195390075Sobrien     Inf - Inf is NaN which is not zero, and so if we don't
11954117395Skan     know that the operand is finite and the comparison
1195590075Sobrien     would treat EQ different to UNORDERED, we can't do it.  */
11956132718Skan  if (HONOR_INFINITIES (compare_mode)
1195790075Sobrien      && code != GT && code != UNGE
11958117395Skan      && (GET_CODE (op1) != CONST_DOUBLE || real_isinf (&c1))
1195990075Sobrien      /* Constructs of the form (a OP b ? a : b) are safe.  */
1196090075Sobrien      && ((! rtx_equal_p (op0, false_cond) && ! rtx_equal_p (op1, false_cond))
11961169689Skan	  || (! rtx_equal_p (op0, true_cond)
1196290075Sobrien	      && ! rtx_equal_p (op1, true_cond))))
1196390075Sobrien    return 0;
11964169689Skan
1196590075Sobrien  /* At this point we know we can use fsel.  */
1196690075Sobrien
1196790075Sobrien  /* Reduce the comparison to a comparison against zero.  */
11968169689Skan  if (! is_against_zero)
11969169689Skan    {
11970169689Skan      temp = gen_reg_rtx (compare_mode);
11971169689Skan      emit_insn (gen_rtx_SET (VOIDmode, temp,
11972169689Skan			      gen_rtx_MINUS (compare_mode, op0, op1)));
11973169689Skan      op0 = temp;
11974169689Skan      op1 = CONST0_RTX (compare_mode);
11975169689Skan    }
1197690075Sobrien
1197790075Sobrien  /* If we don't care about NaNs we can reduce some of the comparisons
1197890075Sobrien     down to faster ones.  */
11979132718Skan  if (! HONOR_NANS (compare_mode))
1198090075Sobrien    switch (code)
1198190075Sobrien      {
1198290075Sobrien      case GT:
1198390075Sobrien	code = LE;
1198490075Sobrien	temp = true_cond;
1198590075Sobrien	true_cond = false_cond;
1198690075Sobrien	false_cond = temp;
1198790075Sobrien	break;
1198890075Sobrien      case UNGE:
1198990075Sobrien	code = GE;
1199090075Sobrien	break;
1199190075Sobrien      case UNEQ:
1199290075Sobrien	code = EQ;
1199390075Sobrien	break;
1199490075Sobrien      default:
1199590075Sobrien	break;
1199690075Sobrien      }
1199790075Sobrien
1199890075Sobrien  /* Now, reduce everything down to a GE.  */
1199990075Sobrien  switch (code)
1200090075Sobrien    {
1200190075Sobrien    case GE:
1200290075Sobrien      break;
1200390075Sobrien
1200490075Sobrien    case LE:
1200596263Sobrien      temp = gen_reg_rtx (compare_mode);
1200696263Sobrien      emit_insn (gen_rtx_SET (VOIDmode, temp, gen_rtx_NEG (compare_mode, op0)));
1200790075Sobrien      op0 = temp;
1200890075Sobrien      break;
1200990075Sobrien
1201090075Sobrien    case ORDERED:
1201196263Sobrien      temp = gen_reg_rtx (compare_mode);
1201296263Sobrien      emit_insn (gen_rtx_SET (VOIDmode, temp, gen_rtx_ABS (compare_mode, op0)));
1201390075Sobrien      op0 = temp;
1201490075Sobrien      break;
1201590075Sobrien
1201690075Sobrien    case EQ:
1201796263Sobrien      temp = gen_reg_rtx (compare_mode);
12018169689Skan      emit_insn (gen_rtx_SET (VOIDmode, temp,
1201996263Sobrien			      gen_rtx_NEG (compare_mode,
1202096263Sobrien					   gen_rtx_ABS (compare_mode, op0))));
1202190075Sobrien      op0 = temp;
1202290075Sobrien      break;
1202390075Sobrien
1202490075Sobrien    case UNGE:
12025132718Skan      /* a UNGE 0 <-> (a GE 0 || -a UNLT 0) */
1202696263Sobrien      temp = gen_reg_rtx (result_mode);
1202790075Sobrien      emit_insn (gen_rtx_SET (VOIDmode, temp,
1202896263Sobrien			      gen_rtx_IF_THEN_ELSE (result_mode,
1202990075Sobrien						    gen_rtx_GE (VOIDmode,
1203090075Sobrien								op0, op1),
1203190075Sobrien						    true_cond, false_cond)));
12032132718Skan      false_cond = true_cond;
12033132718Skan      true_cond = temp;
1203490075Sobrien
1203596263Sobrien      temp = gen_reg_rtx (compare_mode);
1203696263Sobrien      emit_insn (gen_rtx_SET (VOIDmode, temp, gen_rtx_NEG (compare_mode, op0)));
1203790075Sobrien      op0 = temp;
1203890075Sobrien      break;
1203990075Sobrien
1204090075Sobrien    case GT:
12041132718Skan      /* a GT 0 <-> (a GE 0 && -a UNLT 0) */
1204296263Sobrien      temp = gen_reg_rtx (result_mode);
1204390075Sobrien      emit_insn (gen_rtx_SET (VOIDmode, temp,
12044169689Skan			      gen_rtx_IF_THEN_ELSE (result_mode,
1204590075Sobrien						    gen_rtx_GE (VOIDmode,
1204690075Sobrien								op0, op1),
1204790075Sobrien						    true_cond, false_cond)));
12048132718Skan      true_cond = false_cond;
12049132718Skan      false_cond = temp;
1205090075Sobrien
1205196263Sobrien      temp = gen_reg_rtx (compare_mode);
1205296263Sobrien      emit_insn (gen_rtx_SET (VOIDmode, temp, gen_rtx_NEG (compare_mode, op0)));
1205390075Sobrien      op0 = temp;
1205490075Sobrien      break;
1205590075Sobrien
1205690075Sobrien    default:
12057169689Skan      gcc_unreachable ();
1205890075Sobrien    }
1205990075Sobrien
1206090075Sobrien  emit_insn (gen_rtx_SET (VOIDmode, dest,
1206196263Sobrien			  gen_rtx_IF_THEN_ELSE (result_mode,
1206290075Sobrien						gen_rtx_GE (VOIDmode,
1206390075Sobrien							    op0, op1),
1206490075Sobrien						true_cond, false_cond)));
1206590075Sobrien  return 1;
1206690075Sobrien}
1206790075Sobrien
12068117395Skan/* Same as above, but for ints (isel).  */
12069117395Skan
12070117395Skanstatic int
12071132718Skanrs6000_emit_int_cmove (rtx dest, rtx op, rtx true_cond, rtx false_cond)
12072117395Skan{
12073117395Skan  rtx condition_rtx, cr;
12074117395Skan
12075117395Skan  /* All isel implementations thus far are 32-bits.  */
12076117395Skan  if (GET_MODE (rs6000_compare_op0) != SImode)
12077117395Skan    return 0;
12078117395Skan
12079117395Skan  /* We still have to do the compare, because isel doesn't do a
12080117395Skan     compare, it just looks at the CRx bits set by a previous compare
12081117395Skan     instruction.  */
12082117395Skan  condition_rtx = rs6000_generate_compare (GET_CODE (op));
12083117395Skan  cr = XEXP (condition_rtx, 0);
12084117395Skan
12085117395Skan  if (GET_MODE (cr) == CCmode)
12086117395Skan    emit_insn (gen_isel_signed (dest, condition_rtx,
12087117395Skan				true_cond, false_cond, cr));
12088117395Skan  else
12089117395Skan    emit_insn (gen_isel_unsigned (dest, condition_rtx,
12090117395Skan				  true_cond, false_cond, cr));
12091117395Skan
12092117395Skan  return 1;
12093117395Skan}
12094117395Skan
12095117395Skanconst char *
12096132718Skanoutput_isel (rtx *operands)
12097117395Skan{
12098117395Skan  enum rtx_code code;
12099117395Skan
12100117395Skan  code = GET_CODE (operands[1]);
12101117395Skan  if (code == GE || code == GEU || code == LE || code == LEU || code == NE)
12102117395Skan    {
12103117395Skan      PUT_CODE (operands[1], reverse_condition (code));
12104117395Skan      return "isel %0,%3,%2,%j1";
12105117395Skan    }
12106117395Skan  else
12107117395Skan    return "isel %0,%2,%3,%j1";
12108117395Skan}
12109117395Skan
1211090075Sobrienvoid
12111132718Skanrs6000_emit_minmax (rtx dest, enum rtx_code code, rtx op0, rtx op1)
1211290075Sobrien{
1211390075Sobrien  enum machine_mode mode = GET_MODE (op0);
12114117395Skan  enum rtx_code c;
1211590075Sobrien  rtx target;
12116117395Skan
12117117395Skan  if (code == SMAX || code == SMIN)
12118117395Skan    c = GE;
12119117395Skan  else
12120117395Skan    c = GEU;
12121117395Skan
1212290075Sobrien  if (code == SMAX || code == UMAX)
12123169689Skan    target = emit_conditional_move (dest, c, op0, op1, mode,
1212490075Sobrien				    op0, op1, mode, 0);
1212590075Sobrien  else
12126169689Skan    target = emit_conditional_move (dest, c, op0, op1, mode,
1212790075Sobrien				    op1, op0, mode, 0);
12128169689Skan  gcc_assert (target);
1212990075Sobrien  if (target != dest)
1213090075Sobrien    emit_move_insn (dest, target);
1213190075Sobrien}
12132132718Skan
12133169689Skan/* Emit instructions to perform a load-reserved/store-conditional operation.
12134169689Skan   The operation performed is an atomic
12135169689Skan   (set M (CODE:MODE M OP))
12136169689Skan   If not NULL, BEFORE is atomically set to M before the operation, and
12137169689Skan   AFTER is set to M after the operation (that is, (CODE:MODE M OP)).
12138169689Skan   If SYNC_P then a memory barrier is emitted before the operation.
12139169689Skan   Either OP or M may be wrapped in a NOT operation.  */
12140169689Skan
12141169689Skanvoid
12142169689Skanrs6000_emit_sync (enum rtx_code code, enum machine_mode mode,
12143169689Skan		  rtx m, rtx op, rtx before_param, rtx after_param,
12144169689Skan		  bool sync_p)
12145169689Skan{
12146169689Skan  enum machine_mode used_mode;
12147169689Skan  rtx the_op, set_before, set_after, set_atomic, cc_scratch, before, after;
12148169689Skan  rtx used_m;
12149169689Skan  rtvec vec;
12150169689Skan  HOST_WIDE_INT imask = GET_MODE_MASK (mode);
12151169689Skan  rtx shift = NULL_RTX;
12152169689Skan
12153169689Skan  if (sync_p)
12154169689Skan    emit_insn (gen_memory_barrier ());
12155169689Skan
12156169689Skan  if (GET_CODE (m) == NOT)
12157169689Skan    used_m = XEXP (m, 0);
12158169689Skan  else
12159169689Skan    used_m = m;
12160169689Skan
12161169689Skan  /* If this is smaller than SImode, we'll have to use SImode with
12162169689Skan     adjustments.  */
12163169689Skan  if (mode == QImode || mode == HImode)
12164169689Skan    {
12165169689Skan      rtx newop, oldop;
12166169689Skan
12167169689Skan      if (MEM_ALIGN (used_m) >= 32)
12168169689Skan	{
12169169689Skan	  int ishift = 0;
12170169689Skan	  if (BYTES_BIG_ENDIAN)
12171169689Skan	    ishift = GET_MODE_BITSIZE (SImode) - GET_MODE_BITSIZE (mode);
12172169689Skan
12173169689Skan	  shift = GEN_INT (ishift);
12174169689Skan	}
12175169689Skan      else
12176169689Skan	{
12177169689Skan	  rtx addrSI, aligned_addr;
12178169689Skan	  int shift_mask = mode == QImode ? 0x18 : 0x10;
12179169689Skan
12180169689Skan	  addrSI = force_reg (SImode, gen_lowpart_common (SImode,
12181169689Skan							  XEXP (used_m, 0)));
12182169689Skan	  shift = gen_reg_rtx (SImode);
12183169689Skan
12184169689Skan	  emit_insn (gen_rlwinm (shift, addrSI, GEN_INT (3),
12185169689Skan				 GEN_INT (shift_mask)));
12186169689Skan	  emit_insn (gen_xorsi3 (shift, shift, GEN_INT (shift_mask)));
12187169689Skan
12188169689Skan	  aligned_addr = expand_binop (Pmode, and_optab,
12189169689Skan				       XEXP (used_m, 0),
12190169689Skan				       GEN_INT (-4), NULL_RTX,
12191169689Skan				       1, OPTAB_LIB_WIDEN);
12192169689Skan	  used_m = change_address (used_m, SImode, aligned_addr);
12193169689Skan	  set_mem_align (used_m, 32);
12194169689Skan	  /* It's safe to keep the old alias set of USED_M, because
12195169689Skan	     the operation is atomic and only affects the original
12196169689Skan	     USED_M.  */
12197169689Skan	  if (GET_CODE (m) == NOT)
12198169689Skan	    m = gen_rtx_NOT (SImode, used_m);
12199169689Skan	  else
12200169689Skan	    m = used_m;
12201169689Skan	}
12202169689Skan
12203169689Skan      if (GET_CODE (op) == NOT)
12204169689Skan	{
12205169689Skan	  oldop = lowpart_subreg (SImode, XEXP (op, 0), mode);
12206169689Skan	  oldop = gen_rtx_NOT (SImode, oldop);
12207169689Skan	}
12208169689Skan      else
12209169689Skan	oldop = lowpart_subreg (SImode, op, mode);
12210169689Skan
12211169689Skan      switch (code)
12212169689Skan	{
12213169689Skan	case IOR:
12214169689Skan	case XOR:
12215169689Skan	  newop = expand_binop (SImode, and_optab,
12216169689Skan				oldop, GEN_INT (imask), NULL_RTX,
12217169689Skan				1, OPTAB_LIB_WIDEN);
12218169689Skan	  emit_insn (gen_ashlsi3 (newop, newop, shift));
12219169689Skan	  break;
12220169689Skan
12221169689Skan	case AND:
12222169689Skan	  newop = expand_binop (SImode, ior_optab,
12223169689Skan				oldop, GEN_INT (~imask), NULL_RTX,
12224169689Skan				1, OPTAB_LIB_WIDEN);
12225169689Skan	  emit_insn (gen_rotlsi3 (newop, newop, shift));
12226169689Skan	  break;
12227169689Skan
12228169689Skan	case PLUS:
12229169689Skan	case MINUS:
12230169689Skan	  {
12231169689Skan	    rtx mask;
12232169689Skan
12233169689Skan	    newop = expand_binop (SImode, and_optab,
12234169689Skan				  oldop, GEN_INT (imask), NULL_RTX,
12235169689Skan				  1, OPTAB_LIB_WIDEN);
12236169689Skan	    emit_insn (gen_ashlsi3 (newop, newop, shift));
12237169689Skan
12238169689Skan	    mask = gen_reg_rtx (SImode);
12239169689Skan	    emit_move_insn (mask, GEN_INT (imask));
12240169689Skan	    emit_insn (gen_ashlsi3 (mask, mask, shift));
12241169689Skan
12242169689Skan	    if (code == PLUS)
12243169689Skan	      newop = gen_rtx_PLUS (SImode, m, newop);
12244169689Skan	    else
12245169689Skan	      newop = gen_rtx_MINUS (SImode, m, newop);
12246169689Skan	    newop = gen_rtx_AND (SImode, newop, mask);
12247169689Skan	    newop = gen_rtx_IOR (SImode, newop,
12248169689Skan				 gen_rtx_AND (SImode,
12249169689Skan					      gen_rtx_NOT (SImode, mask),
12250169689Skan					      m));
12251169689Skan	    break;
12252169689Skan	  }
12253169689Skan
12254169689Skan	default:
12255169689Skan	  gcc_unreachable ();
12256169689Skan	}
12257169689Skan
12258169689Skan      if (GET_CODE (m) == NOT)
12259169689Skan	{
12260169689Skan	  rtx mask, xorm;
12261169689Skan
12262169689Skan	  mask = gen_reg_rtx (SImode);
12263169689Skan	  emit_move_insn (mask, GEN_INT (imask));
12264169689Skan	  emit_insn (gen_ashlsi3 (mask, mask, shift));
12265169689Skan
12266169689Skan	  xorm = gen_rtx_XOR (SImode, used_m, mask);
12267169689Skan	  /* Depending on the value of 'op', the XOR or the operation might
12268169689Skan	     be able to be simplified away.  */
12269169689Skan	  newop = simplify_gen_binary (code, SImode, xorm, newop);
12270169689Skan	}
12271169689Skan      op = newop;
12272169689Skan      used_mode = SImode;
12273169689Skan      before = gen_reg_rtx (used_mode);
12274169689Skan      after = gen_reg_rtx (used_mode);
12275169689Skan    }
12276169689Skan  else
12277169689Skan    {
12278169689Skan      used_mode = mode;
12279169689Skan      before = before_param;
12280169689Skan      after = after_param;
12281169689Skan
12282169689Skan      if (before == NULL_RTX)
12283169689Skan	before = gen_reg_rtx (used_mode);
12284169689Skan      if (after == NULL_RTX)
12285169689Skan	after = gen_reg_rtx (used_mode);
12286169689Skan    }
12287169689Skan
12288169689Skan  if ((code == PLUS || code == MINUS || GET_CODE (m) == NOT)
12289169689Skan      && used_mode != mode)
12290169689Skan    the_op = op;  /* Computed above.  */
12291169689Skan  else if (GET_CODE (op) == NOT && GET_CODE (m) != NOT)
12292169689Skan    the_op = gen_rtx_fmt_ee (code, used_mode, op, m);
12293169689Skan  else
12294169689Skan    the_op = gen_rtx_fmt_ee (code, used_mode, m, op);
12295169689Skan
12296169689Skan  set_after = gen_rtx_SET (VOIDmode, after, the_op);
12297169689Skan  set_before = gen_rtx_SET (VOIDmode, before, used_m);
12298169689Skan  set_atomic = gen_rtx_SET (VOIDmode, used_m,
12299169689Skan			    gen_rtx_UNSPEC (used_mode,
12300169689Skan					    gen_rtvec (1, the_op),
12301169689Skan					    UNSPEC_SYNC_OP));
12302169689Skan  cc_scratch = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (CCmode));
12303169689Skan
12304169689Skan  if ((code == PLUS || code == MINUS) && used_mode != mode)
12305169689Skan    vec = gen_rtvec (5, set_after, set_before, set_atomic, cc_scratch,
12306169689Skan		     gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (SImode)));
12307169689Skan  else
12308169689Skan    vec = gen_rtvec (4, set_after, set_before, set_atomic, cc_scratch);
12309169689Skan  emit_insn (gen_rtx_PARALLEL (VOIDmode, vec));
12310169689Skan
12311169689Skan  /* Shift and mask the return values properly.  */
12312169689Skan  if (used_mode != mode && before_param)
12313169689Skan    {
12314169689Skan      emit_insn (gen_lshrsi3 (before, before, shift));
12315169689Skan      convert_move (before_param, before, 1);
12316169689Skan    }
12317169689Skan
12318169689Skan  if (used_mode != mode && after_param)
12319169689Skan    {
12320169689Skan      emit_insn (gen_lshrsi3 (after, after, shift));
12321169689Skan      convert_move (after_param, after, 1);
12322169689Skan    }
12323169689Skan
12324169689Skan  /* The previous sequence will end with a branch that's dependent on
12325169689Skan     the conditional store, so placing an isync will ensure that no
12326169689Skan     other instructions (especially, no load or store instructions)
12327169689Skan     can start before the atomic operation completes.  */
12328169689Skan  if (sync_p)
12329169689Skan    emit_insn (gen_isync ());
12330169689Skan}
12331169689Skan
12332169689Skan/* A subroutine of the atomic operation splitters.  Jump to LABEL if
12333169689Skan   COND is true.  Mark the jump as unlikely to be taken.  */
12334169689Skan
12335169689Skanstatic void
12336169689Skanemit_unlikely_jump (rtx cond, rtx label)
12337169689Skan{
12338169689Skan  rtx very_unlikely = GEN_INT (REG_BR_PROB_BASE / 100 - 1);
12339169689Skan  rtx x;
12340169689Skan
12341169689Skan  x = gen_rtx_IF_THEN_ELSE (VOIDmode, cond, label, pc_rtx);
12342169689Skan  x = emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, x));
12343169689Skan  REG_NOTES (x) = gen_rtx_EXPR_LIST (REG_BR_PROB, very_unlikely, NULL_RTX);
12344169689Skan}
12345169689Skan
12346169689Skan/* A subroutine of the atomic operation splitters.  Emit a load-locked
12347169689Skan   instruction in MODE.  */
12348169689Skan
12349169689Skanstatic void
12350169689Skanemit_load_locked (enum machine_mode mode, rtx reg, rtx mem)
12351169689Skan{
12352169689Skan  rtx (*fn) (rtx, rtx) = NULL;
12353169689Skan  if (mode == SImode)
12354169689Skan    fn = gen_load_locked_si;
12355169689Skan  else if (mode == DImode)
12356169689Skan    fn = gen_load_locked_di;
12357169689Skan  emit_insn (fn (reg, mem));
12358169689Skan}
12359169689Skan
12360169689Skan/* A subroutine of the atomic operation splitters.  Emit a store-conditional
12361169689Skan   instruction in MODE.  */
12362169689Skan
12363169689Skanstatic void
12364169689Skanemit_store_conditional (enum machine_mode mode, rtx res, rtx mem, rtx val)
12365169689Skan{
12366169689Skan  rtx (*fn) (rtx, rtx, rtx) = NULL;
12367169689Skan  if (mode == SImode)
12368169689Skan    fn = gen_store_conditional_si;
12369169689Skan  else if (mode == DImode)
12370169689Skan    fn = gen_store_conditional_di;
12371169689Skan
12372169689Skan  /* Emit sync before stwcx. to address PPC405 Erratum.  */
12373169689Skan  if (PPC405_ERRATUM77)
12374169689Skan    emit_insn (gen_memory_barrier ());
12375169689Skan
12376169689Skan  emit_insn (fn (res, mem, val));
12377169689Skan}
12378169689Skan
12379169689Skan/* Expand an an atomic fetch-and-operate pattern.  CODE is the binary operation
12380169689Skan   to perform.  MEM is the memory on which to operate.  VAL is the second
12381169689Skan   operand of the binary operator.  BEFORE and AFTER are optional locations to
12382169689Skan   return the value of MEM either before of after the operation.  SCRATCH is
12383169689Skan   a scratch register.  */
12384169689Skan
12385169689Skanvoid
12386169689Skanrs6000_split_atomic_op (enum rtx_code code, rtx mem, rtx val,
12387169689Skan                       rtx before, rtx after, rtx scratch)
12388169689Skan{
12389169689Skan  enum machine_mode mode = GET_MODE (mem);
12390169689Skan  rtx label, x, cond = gen_rtx_REG (CCmode, CR0_REGNO);
12391169689Skan
12392169689Skan  emit_insn (gen_memory_barrier ());
12393169689Skan
12394169689Skan  label = gen_label_rtx ();
12395169689Skan  emit_label (label);
12396169689Skan  label = gen_rtx_LABEL_REF (VOIDmode, label);
12397169689Skan
12398169689Skan  if (before == NULL_RTX)
12399169689Skan    before = scratch;
12400169689Skan  emit_load_locked (mode, before, mem);
12401169689Skan
12402169689Skan  if (code == NOT)
12403169689Skan    x = gen_rtx_AND (mode, gen_rtx_NOT (mode, before), val);
12404169689Skan  else if (code == AND)
12405169689Skan    x = gen_rtx_UNSPEC (mode, gen_rtvec (2, before, val), UNSPEC_AND);
12406169689Skan  else
12407169689Skan    x = gen_rtx_fmt_ee (code, mode, before, val);
12408169689Skan
12409169689Skan  if (after != NULL_RTX)
12410169689Skan    emit_insn (gen_rtx_SET (VOIDmode, after, copy_rtx (x)));
12411169689Skan  emit_insn (gen_rtx_SET (VOIDmode, scratch, x));
12412169689Skan
12413169689Skan  emit_store_conditional (mode, cond, mem, scratch);
12414169689Skan
12415169689Skan  x = gen_rtx_NE (VOIDmode, cond, const0_rtx);
12416169689Skan  emit_unlikely_jump (x, label);
12417169689Skan
12418169689Skan  emit_insn (gen_isync ());
12419169689Skan}
12420169689Skan
12421169689Skan/* Expand an atomic compare and swap operation.  MEM is the memory on which
12422169689Skan   to operate.  OLDVAL is the old value to be compared.  NEWVAL is the new
12423169689Skan   value to be stored.  SCRATCH is a scratch GPR.  */
12424169689Skan
12425169689Skanvoid
12426169689Skanrs6000_split_compare_and_swap (rtx retval, rtx mem, rtx oldval, rtx newval,
12427169689Skan			       rtx scratch)
12428169689Skan{
12429169689Skan  enum machine_mode mode = GET_MODE (mem);
12430169689Skan  rtx label1, label2, x, cond = gen_rtx_REG (CCmode, CR0_REGNO);
12431169689Skan
12432169689Skan  emit_insn (gen_memory_barrier ());
12433169689Skan
12434169689Skan  label1 = gen_rtx_LABEL_REF (VOIDmode, gen_label_rtx ());
12435169689Skan  label2 = gen_rtx_LABEL_REF (VOIDmode, gen_label_rtx ());
12436169689Skan  emit_label (XEXP (label1, 0));
12437169689Skan
12438169689Skan  emit_load_locked (mode, retval, mem);
12439169689Skan
12440169689Skan  x = gen_rtx_COMPARE (CCmode, retval, oldval);
12441169689Skan  emit_insn (gen_rtx_SET (VOIDmode, cond, x));
12442169689Skan
12443169689Skan  x = gen_rtx_NE (VOIDmode, cond, const0_rtx);
12444169689Skan  emit_unlikely_jump (x, label2);
12445169689Skan
12446169689Skan  emit_move_insn (scratch, newval);
12447169689Skan  emit_store_conditional (mode, cond, mem, scratch);
12448169689Skan
12449169689Skan  x = gen_rtx_NE (VOIDmode, cond, const0_rtx);
12450169689Skan  emit_unlikely_jump (x, label1);
12451169689Skan
12452169689Skan  emit_insn (gen_isync ());
12453169689Skan  emit_label (XEXP (label2, 0));
12454169689Skan}
12455169689Skan
12456169689Skan/* Expand an atomic test and set operation.  MEM is the memory on which
12457169689Skan   to operate.  VAL is the value set.  SCRATCH is a scratch GPR.  */
12458169689Skan
12459169689Skanvoid
12460169689Skanrs6000_split_lock_test_and_set (rtx retval, rtx mem, rtx val, rtx scratch)
12461169689Skan{
12462169689Skan  enum machine_mode mode = GET_MODE (mem);
12463169689Skan  rtx label, x, cond = gen_rtx_REG (CCmode, CR0_REGNO);
12464169689Skan
12465169689Skan  emit_insn (gen_memory_barrier ());
12466169689Skan
12467169689Skan  label = gen_rtx_LABEL_REF (VOIDmode, gen_label_rtx ());
12468169689Skan  emit_label (XEXP (label, 0));
12469169689Skan
12470169689Skan  emit_load_locked (mode, retval, mem);
12471169689Skan  emit_move_insn (scratch, val);
12472169689Skan  emit_store_conditional (mode, cond, mem, scratch);
12473169689Skan
12474169689Skan  x = gen_rtx_NE (VOIDmode, cond, const0_rtx);
12475169689Skan  emit_unlikely_jump (x, label);
12476169689Skan
12477169689Skan  emit_insn (gen_isync ());
12478169689Skan}
12479169689Skan
12480169689Skanvoid
12481169689Skanrs6000_expand_compare_and_swapqhi (rtx dst, rtx mem, rtx oldval, rtx newval)
12482169689Skan{
12483169689Skan  enum machine_mode mode = GET_MODE (mem);
12484169689Skan  rtx addrSI, align, wdst, shift, mask;
12485169689Skan  HOST_WIDE_INT shift_mask = mode == QImode ? 0x18 : 0x10;
12486169689Skan  HOST_WIDE_INT imask = GET_MODE_MASK (mode);
12487169689Skan
12488169689Skan  /* Shift amount for subword relative to aligned word.  */
12489169689Skan  addrSI = force_reg (SImode, gen_lowpart_common (SImode, XEXP (mem, 0)));
12490169689Skan  shift = gen_reg_rtx (SImode);
12491169689Skan  emit_insn (gen_rlwinm (shift, addrSI, GEN_INT (3),
12492169689Skan			 GEN_INT (shift_mask)));
12493169689Skan  emit_insn (gen_xorsi3 (shift, shift, GEN_INT (shift_mask)));
12494169689Skan
12495169689Skan  /* Shift and mask old value into position within word.  */
12496169689Skan  oldval = convert_modes (SImode, mode, oldval, 1);
12497169689Skan  oldval = expand_binop (SImode, and_optab,
12498169689Skan			 oldval, GEN_INT (imask), NULL_RTX,
12499169689Skan			 1, OPTAB_LIB_WIDEN);
12500169689Skan  emit_insn (gen_ashlsi3 (oldval, oldval, shift));
12501169689Skan
12502169689Skan  /* Shift and mask new value into position within word.  */
12503169689Skan  newval = convert_modes (SImode, mode, newval, 1);
12504169689Skan  newval = expand_binop (SImode, and_optab,
12505169689Skan			 newval, GEN_INT (imask), NULL_RTX,
12506169689Skan			 1, OPTAB_LIB_WIDEN);
12507169689Skan  emit_insn (gen_ashlsi3 (newval, newval, shift));
12508169689Skan
12509169689Skan  /* Mask for insertion.  */
12510169689Skan  mask = gen_reg_rtx (SImode);
12511169689Skan  emit_move_insn (mask, GEN_INT (imask));
12512169689Skan  emit_insn (gen_ashlsi3 (mask, mask, shift));
12513169689Skan
12514169689Skan  /* Address of aligned word containing subword.  */
12515169689Skan  align = expand_binop (Pmode, and_optab, XEXP (mem, 0), GEN_INT (-4),
12516169689Skan			NULL_RTX, 1, OPTAB_LIB_WIDEN);
12517169689Skan  mem = change_address (mem, SImode, align);
12518169689Skan  set_mem_align (mem, 32);
12519169689Skan  MEM_VOLATILE_P (mem) = 1;
12520169689Skan
12521169689Skan  wdst = gen_reg_rtx (SImode);
12522169689Skan  emit_insn (gen_sync_compare_and_swapqhi_internal (wdst, mask,
12523169689Skan						    oldval, newval, mem));
12524169689Skan
12525169689Skan  emit_move_insn (dst, gen_lowpart (mode, wdst));
12526169689Skan}
12527169689Skan
12528169689Skanvoid
12529169689Skanrs6000_split_compare_and_swapqhi (rtx dest, rtx mask,
12530169689Skan				  rtx oldval, rtx newval, rtx mem,
12531169689Skan				  rtx scratch)
12532169689Skan{
12533169689Skan  rtx label1, label2, x, cond = gen_rtx_REG (CCmode, CR0_REGNO);
12534169689Skan
12535169689Skan  emit_insn (gen_memory_barrier ());
12536169689Skan  label1 = gen_rtx_LABEL_REF (VOIDmode, gen_label_rtx ());
12537169689Skan  label2 = gen_rtx_LABEL_REF (VOIDmode, gen_label_rtx ());
12538169689Skan  emit_label (XEXP (label1, 0));
12539169689Skan
12540169689Skan  emit_load_locked (SImode, scratch, mem);
12541169689Skan
12542169689Skan  /* Mask subword within loaded value for comparison with oldval.
12543169689Skan     Use UNSPEC_AND to avoid clobber.*/
12544169689Skan  emit_insn (gen_rtx_SET (SImode, dest,
12545169689Skan			  gen_rtx_UNSPEC (SImode,
12546169689Skan					  gen_rtvec (2, scratch, mask),
12547169689Skan					  UNSPEC_AND)));
12548169689Skan
12549169689Skan  x = gen_rtx_COMPARE (CCmode, dest, oldval);
12550169689Skan  emit_insn (gen_rtx_SET (VOIDmode, cond, x));
12551169689Skan
12552169689Skan  x = gen_rtx_NE (VOIDmode, cond, const0_rtx);
12553169689Skan  emit_unlikely_jump (x, label2);
12554169689Skan
12555169689Skan  /* Clear subword within loaded value for insertion of new value.  */
12556169689Skan  emit_insn (gen_rtx_SET (SImode, scratch,
12557169689Skan			  gen_rtx_AND (SImode,
12558169689Skan				       gen_rtx_NOT (SImode, mask), scratch)));
12559169689Skan  emit_insn (gen_iorsi3 (scratch, scratch, newval));
12560169689Skan  emit_store_conditional (SImode, cond, mem, scratch);
12561169689Skan
12562169689Skan  x = gen_rtx_NE (VOIDmode, cond, const0_rtx);
12563169689Skan  emit_unlikely_jump (x, label1);
12564169689Skan
12565169689Skan  emit_insn (gen_isync ());
12566169689Skan  emit_label (XEXP (label2, 0));
12567169689Skan}
12568169689Skan
12569169689Skan
12570169689Skan  /* Emit instructions to move SRC to DST.  Called by splitters for
12571132718Skan   multi-register moves.  It will emit at most one instruction for
12572132718Skan   each register that is accessed; that is, it won't emit li/lis pairs
12573132718Skan   (or equivalent for 64-bit code).  One of SRC or DST must be a hard
12574132718Skan   register.  */
12575132718Skan
12576132718Skanvoid
12577132718Skanrs6000_split_multireg_move (rtx dst, rtx src)
12578132718Skan{
12579132718Skan  /* The register number of the first register being moved.  */
12580132718Skan  int reg;
12581132718Skan  /* The mode that is to be moved.  */
12582132718Skan  enum machine_mode mode;
12583132718Skan  /* The mode that the move is being done in, and its size.  */
12584132718Skan  enum machine_mode reg_mode;
12585132718Skan  int reg_mode_size;
12586132718Skan  /* The number of registers that will be moved.  */
12587132718Skan  int nregs;
12588132718Skan
12589132718Skan  reg = REG_P (dst) ? REGNO (dst) : REGNO (src);
12590132718Skan  mode = GET_MODE (dst);
12591169689Skan  nregs = hard_regno_nregs[reg][mode];
12592132718Skan  if (FP_REGNO_P (reg))
12593132718Skan    reg_mode = DFmode;
12594132718Skan  else if (ALTIVEC_REGNO_P (reg))
12595132718Skan    reg_mode = V16QImode;
12596169689Skan  else if (TARGET_E500_DOUBLE && mode == TFmode)
12597169689Skan    reg_mode = DFmode;
12598132718Skan  else
12599132718Skan    reg_mode = word_mode;
12600132718Skan  reg_mode_size = GET_MODE_SIZE (reg_mode);
12601169689Skan
12602169689Skan  gcc_assert (reg_mode_size * nregs == GET_MODE_SIZE (mode));
12603169689Skan
12604132718Skan  if (REG_P (src) && REG_P (dst) && (REGNO (src) < REGNO (dst)))
12605132718Skan    {
12606132718Skan      /* Move register range backwards, if we might have destructive
12607132718Skan	 overlap.  */
12608132718Skan      int i;
12609132718Skan      for (i = nregs - 1; i >= 0; i--)
12610169689Skan	emit_insn (gen_rtx_SET (VOIDmode,
12611132718Skan				simplify_gen_subreg (reg_mode, dst, mode,
12612132718Skan						     i * reg_mode_size),
12613132718Skan				simplify_gen_subreg (reg_mode, src, mode,
12614132718Skan						     i * reg_mode_size)));
12615132718Skan    }
12616132718Skan  else
12617132718Skan    {
12618132718Skan      int i;
12619132718Skan      int j = -1;
12620132718Skan      bool used_update = false;
12621132718Skan
12622169689Skan      if (MEM_P (src) && INT_REGNO_P (reg))
12623169689Skan	{
12624169689Skan	  rtx breg;
12625132718Skan
12626132718Skan	  if (GET_CODE (XEXP (src, 0)) == PRE_INC
12627132718Skan	      || GET_CODE (XEXP (src, 0)) == PRE_DEC)
12628132718Skan	    {
12629132718Skan	      rtx delta_rtx;
12630132718Skan	      breg = XEXP (XEXP (src, 0), 0);
12631169689Skan	      delta_rtx = (GET_CODE (XEXP (src, 0)) == PRE_INC
12632169689Skan			   ? GEN_INT (GET_MODE_SIZE (GET_MODE (src)))
12633169689Skan			   : GEN_INT (-GET_MODE_SIZE (GET_MODE (src))));
12634132718Skan	      emit_insn (TARGET_32BIT
12635132718Skan			 ? gen_addsi3 (breg, breg, delta_rtx)
12636132718Skan			 : gen_adddi3 (breg, breg, delta_rtx));
12637169689Skan	      src = replace_equiv_address (src, breg);
12638132718Skan	    }
12639169689Skan	  else if (! rs6000_offsettable_memref_p (src))
12640146895Skan	    {
12641169689Skan	      rtx basereg;
12642146895Skan	      basereg = gen_rtx_REG (Pmode, reg);
12643146895Skan	      emit_insn (gen_rtx_SET (VOIDmode, basereg, XEXP (src, 0)));
12644169689Skan	      src = replace_equiv_address (src, basereg);
12645146895Skan	    }
12646132718Skan
12647146895Skan	  breg = XEXP (src, 0);
12648146895Skan	  if (GET_CODE (breg) == PLUS || GET_CODE (breg) == LO_SUM)
12649146895Skan	    breg = XEXP (breg, 0);
12650132718Skan
12651146895Skan	  /* If the base register we are using to address memory is
12652146895Skan	     also a destination reg, then change that register last.  */
12653146895Skan	  if (REG_P (breg)
12654146895Skan	      && REGNO (breg) >= REGNO (dst)
12655132718Skan	      && REGNO (breg) < REGNO (dst) + nregs)
12656132718Skan	    j = REGNO (breg) - REGNO (dst);
12657146895Skan	}
12658132718Skan
12659132718Skan      if (GET_CODE (dst) == MEM && INT_REGNO_P (reg))
12660132718Skan	{
12661132718Skan	  rtx breg;
12662132718Skan
12663132718Skan	  if (GET_CODE (XEXP (dst, 0)) == PRE_INC
12664132718Skan	      || GET_CODE (XEXP (dst, 0)) == PRE_DEC)
12665132718Skan	    {
12666132718Skan	      rtx delta_rtx;
12667132718Skan	      breg = XEXP (XEXP (dst, 0), 0);
12668169689Skan	      delta_rtx = (GET_CODE (XEXP (dst, 0)) == PRE_INC
12669169689Skan			   ? GEN_INT (GET_MODE_SIZE (GET_MODE (dst)))
12670169689Skan			   : GEN_INT (-GET_MODE_SIZE (GET_MODE (dst))));
12671132718Skan
12672132718Skan	      /* We have to update the breg before doing the store.
12673132718Skan		 Use store with update, if available.  */
12674132718Skan
12675132718Skan	      if (TARGET_UPDATE)
12676132718Skan		{
12677132718Skan		  rtx nsrc = simplify_gen_subreg (reg_mode, src, mode, 0);
12678132718Skan		  emit_insn (TARGET_32BIT
12679169689Skan			     ? (TARGET_POWERPC64
12680169689Skan				? gen_movdi_si_update (breg, breg, delta_rtx, nsrc)
12681169689Skan				: gen_movsi_update (breg, breg, delta_rtx, nsrc))
12682169689Skan			     : gen_movdi_di_update (breg, breg, delta_rtx, nsrc));
12683132718Skan		  used_update = true;
12684132718Skan		}
12685132718Skan	      else
12686132718Skan		emit_insn (TARGET_32BIT
12687132718Skan			   ? gen_addsi3 (breg, breg, delta_rtx)
12688132718Skan			   : gen_adddi3 (breg, breg, delta_rtx));
12689169689Skan	      dst = replace_equiv_address (dst, breg);
12690132718Skan	    }
12691169689Skan	  else
12692169689Skan	    gcc_assert (rs6000_offsettable_memref_p (dst));
12693132718Skan	}
12694132718Skan
12695132718Skan      for (i = 0; i < nregs; i++)
12696169689Skan	{
12697132718Skan	  /* Calculate index to next subword.  */
12698132718Skan	  ++j;
12699169689Skan	  if (j == nregs)
12700132718Skan	    j = 0;
12701132718Skan
12702169689Skan	  /* If compiler already emitted move of first word by
12703132718Skan	     store with update, no need to do anything.  */
12704132718Skan	  if (j == 0 && used_update)
12705132718Skan	    continue;
12706169689Skan
12707132718Skan	  emit_insn (gen_rtx_SET (VOIDmode,
12708132718Skan				  simplify_gen_subreg (reg_mode, dst, mode,
12709132718Skan						       j * reg_mode_size),
12710132718Skan				  simplify_gen_subreg (reg_mode, src, mode,
12711132718Skan						       j * reg_mode_size)));
12712132718Skan	}
12713132718Skan    }
12714132718Skan}
12715132718Skan
1271690075Sobrien
1271790075Sobrien/* This page contains routines that are used to determine what the
1271890075Sobrien   function prologue and epilogue code will do and write them out.  */
1271990075Sobrien
1272090075Sobrien/* Return the first fixed-point register that is required to be
1272190075Sobrien   saved. 32 if none.  */
1272290075Sobrien
1272390075Sobrienint
12724132718Skanfirst_reg_to_save (void)
1272590075Sobrien{
1272690075Sobrien  int first_reg;
1272790075Sobrien
1272890075Sobrien  /* Find lowest numbered live register.  */
1272990075Sobrien  for (first_reg = 13; first_reg <= 31; first_reg++)
12730169689Skan    if (regs_ever_live[first_reg]
1273190075Sobrien	&& (! call_used_regs[first_reg]
1273296263Sobrien	    || (first_reg == RS6000_PIC_OFFSET_TABLE_REGNUM
12733117395Skan		&& ((DEFAULT_ABI == ABI_V4 && flag_pic != 0)
12734146895Skan		    || (DEFAULT_ABI == ABI_DARWIN && flag_pic)
12735146895Skan		    || (TARGET_TOC && TARGET_MINIMAL_TOC)))))
1273690075Sobrien      break;
1273790075Sobrien
1273890075Sobrien#if TARGET_MACHO
12739117395Skan  if (flag_pic
12740117395Skan      && current_function_uses_pic_offset_table
12741117395Skan      && first_reg > RS6000_PIC_OFFSET_TABLE_REGNUM)
1274296263Sobrien    return RS6000_PIC_OFFSET_TABLE_REGNUM;
1274390075Sobrien#endif
1274490075Sobrien
1274590075Sobrien  return first_reg;
1274690075Sobrien}
1274790075Sobrien
1274890075Sobrien/* Similar, for FP regs.  */
1274990075Sobrien
1275090075Sobrienint
12751132718Skanfirst_fp_reg_to_save (void)
1275290075Sobrien{
1275390075Sobrien  int first_reg;
1275490075Sobrien
1275590075Sobrien  /* Find lowest numbered live register.  */
1275690075Sobrien  for (first_reg = 14 + 32; first_reg <= 63; first_reg++)
1275790075Sobrien    if (regs_ever_live[first_reg])
1275890075Sobrien      break;
1275990075Sobrien
1276090075Sobrien  return first_reg;
1276190075Sobrien}
1276290075Sobrien
1276390075Sobrien/* Similar, for AltiVec regs.  */
1276490075Sobrien
1276590075Sobrienstatic int
12766132718Skanfirst_altivec_reg_to_save (void)
1276790075Sobrien{
1276890075Sobrien  int i;
1276990075Sobrien
1277090075Sobrien  /* Stack frame remains as is unless we are in AltiVec ABI.  */
1277190075Sobrien  if (! TARGET_ALTIVEC_ABI)
1277290075Sobrien    return LAST_ALTIVEC_REGNO + 1;
1277390075Sobrien
12774169689Skan  /* On Darwin, the unwind routines are compiled without
12775169689Skan     TARGET_ALTIVEC, and use save_world to save/restore the
12776169689Skan     altivec registers when necessary.  */
12777169689Skan  if (DEFAULT_ABI == ABI_DARWIN && current_function_calls_eh_return
12778169689Skan      && ! TARGET_ALTIVEC)
12779169689Skan    return FIRST_ALTIVEC_REGNO + 20;
12780169689Skan
1278190075Sobrien  /* Find lowest numbered live register.  */
1278290075Sobrien  for (i = FIRST_ALTIVEC_REGNO + 20; i <= LAST_ALTIVEC_REGNO; ++i)
1278390075Sobrien    if (regs_ever_live[i])
1278490075Sobrien      break;
1278590075Sobrien
1278690075Sobrien  return i;
1278790075Sobrien}
1278890075Sobrien
1278990075Sobrien/* Return a 32-bit mask of the AltiVec registers we need to set in
1279090075Sobrien   VRSAVE.  Bit n of the return value is 1 if Vn is live.  The MSB in
1279190075Sobrien   the 32-bit word is 0.  */
1279290075Sobrien
1279390075Sobrienstatic unsigned int
12794132718Skancompute_vrsave_mask (void)
1279590075Sobrien{
1279690075Sobrien  unsigned int i, mask = 0;
1279790075Sobrien
12798169689Skan  /* On Darwin, the unwind routines are compiled without
12799169689Skan     TARGET_ALTIVEC, and use save_world to save/restore the
12800169689Skan     call-saved altivec registers when necessary.  */
12801169689Skan  if (DEFAULT_ABI == ABI_DARWIN && current_function_calls_eh_return
12802169689Skan      && ! TARGET_ALTIVEC)
12803169689Skan    mask |= 0xFFF;
12804169689Skan
1280590075Sobrien  /* First, find out if we use _any_ altivec registers.  */
1280690075Sobrien  for (i = FIRST_ALTIVEC_REGNO; i <= LAST_ALTIVEC_REGNO; ++i)
1280790075Sobrien    if (regs_ever_live[i])
1280890075Sobrien      mask |= ALTIVEC_REG_BIT (i);
1280990075Sobrien
1281090075Sobrien  if (mask == 0)
1281190075Sobrien    return mask;
1281290075Sobrien
1281390075Sobrien  /* Next, remove the argument registers from the set.  These must
1281490075Sobrien     be in the VRSAVE mask set by the caller, so we don't need to add
1281590075Sobrien     them in again.  More importantly, the mask we compute here is
1281690075Sobrien     used to generate CLOBBERs in the set_vrsave insn, and we do not
1281790075Sobrien     wish the argument registers to die.  */
12818132718Skan  for (i = cfun->args_info.vregno - 1; i >= ALTIVEC_ARG_MIN_REG; --i)
1281990075Sobrien    mask &= ~ALTIVEC_REG_BIT (i);
1282090075Sobrien
1282190075Sobrien  /* Similarly, remove the return value from the set.  */
1282290075Sobrien  {
1282390075Sobrien    bool yes = false;
1282490075Sobrien    diddle_return_value (is_altivec_return_reg, &yes);
1282590075Sobrien    if (yes)
1282690075Sobrien      mask &= ~ALTIVEC_REG_BIT (ALTIVEC_ARG_RETURN);
1282790075Sobrien  }
1282890075Sobrien
1282990075Sobrien  return mask;
1283090075Sobrien}
1283190075Sobrien
12832169689Skan/* For a very restricted set of circumstances, we can cut down the
12833169689Skan   size of prologues/epilogues by calling our own save/restore-the-world
12834169689Skan   routines.  */
12835169689Skan
1283690075Sobrienstatic void
12837169689Skancompute_save_world_info (rs6000_stack_t *info_ptr)
12838169689Skan{
12839169689Skan  info_ptr->world_save_p = 1;
12840169689Skan  info_ptr->world_save_p
12841169689Skan    = (WORLD_SAVE_P (info_ptr)
12842169689Skan       && DEFAULT_ABI == ABI_DARWIN
12843169689Skan       && ! (current_function_calls_setjmp && flag_exceptions)
12844169689Skan       && info_ptr->first_fp_reg_save == FIRST_SAVED_FP_REGNO
12845169689Skan       && info_ptr->first_gp_reg_save == FIRST_SAVED_GP_REGNO
12846169689Skan       && info_ptr->first_altivec_reg_save == FIRST_SAVED_ALTIVEC_REGNO
12847169689Skan       && info_ptr->cr_save_p);
12848169689Skan
12849169689Skan  /* This will not work in conjunction with sibcalls.  Make sure there
12850169689Skan     are none.  (This check is expensive, but seldom executed.) */
12851169689Skan  if (WORLD_SAVE_P (info_ptr))
12852169689Skan    {
12853169689Skan      rtx insn;
12854169689Skan      for ( insn = get_last_insn_anywhere (); insn; insn = PREV_INSN (insn))
12855169689Skan	if ( GET_CODE (insn) == CALL_INSN
12856169689Skan	     && SIBLING_CALL_P (insn))
12857169689Skan	  {
12858169689Skan	    info_ptr->world_save_p = 0;
12859169689Skan	    break;
12860169689Skan	  }
12861169689Skan    }
12862169689Skan
12863169689Skan  if (WORLD_SAVE_P (info_ptr))
12864169689Skan    {
12865169689Skan      /* Even if we're not touching VRsave, make sure there's room on the
12866169689Skan	 stack for it, if it looks like we're calling SAVE_WORLD, which
12867169689Skan	 will attempt to save it. */
12868169689Skan      info_ptr->vrsave_size  = 4;
12869169689Skan
12870169689Skan      /* "Save" the VRsave register too if we're saving the world.  */
12871169689Skan      if (info_ptr->vrsave_mask == 0)
12872169689Skan	info_ptr->vrsave_mask = compute_vrsave_mask ();
12873169689Skan
12874169689Skan      /* Because the Darwin register save/restore routines only handle
12875169689Skan	 F14 .. F31 and V20 .. V31 as per the ABI, perform a consistency
12876169689Skan	 check.  */
12877169689Skan      gcc_assert (info_ptr->first_fp_reg_save >= FIRST_SAVED_FP_REGNO
12878169689Skan		  && (info_ptr->first_altivec_reg_save
12879169689Skan		      >= FIRST_SAVED_ALTIVEC_REGNO));
12880169689Skan    }
12881169689Skan  return;
12882169689Skan}
12883169689Skan
12884169689Skan
12885169689Skanstatic void
12886132718Skanis_altivec_return_reg (rtx reg, void *xyes)
1288790075Sobrien{
1288890075Sobrien  bool *yes = (bool *) xyes;
1288990075Sobrien  if (REGNO (reg) == ALTIVEC_ARG_RETURN)
1289090075Sobrien    *yes = true;
1289190075Sobrien}
1289290075Sobrien
1289390075Sobrien
1289490075Sobrien/* Calculate the stack information for the current function.  This is
1289590075Sobrien   complicated by having two separate calling sequences, the AIX calling
1289690075Sobrien   sequence and the V.4 calling sequence.
1289790075Sobrien
1289890075Sobrien   AIX (and Darwin/Mac OS X) stack frames look like:
1289990075Sobrien							  32-bit  64-bit
1290090075Sobrien	SP---->	+---------------------------------------+
1290190075Sobrien		| back chain to caller			| 0	  0
1290290075Sobrien		+---------------------------------------+
1290390075Sobrien		| saved CR				| 4       8 (8-11)
1290490075Sobrien		+---------------------------------------+
1290590075Sobrien		| saved LR				| 8       16
1290690075Sobrien		+---------------------------------------+
1290790075Sobrien		| reserved for compilers		| 12      24
1290890075Sobrien		+---------------------------------------+
1290990075Sobrien		| reserved for binders			| 16      32
1291090075Sobrien		+---------------------------------------+
1291190075Sobrien		| saved TOC pointer			| 20      40
1291290075Sobrien		+---------------------------------------+
1291390075Sobrien		| Parameter save area (P)		| 24      48
1291490075Sobrien		+---------------------------------------+
1291590075Sobrien		| Alloca space (A)			| 24+P    etc.
1291690075Sobrien		+---------------------------------------+
1291790075Sobrien		| Local variable space (L)		| 24+P+A
1291890075Sobrien		+---------------------------------------+
1291990075Sobrien		| Float/int conversion temporary (X)	| 24+P+A+L
1292090075Sobrien		+---------------------------------------+
1292190075Sobrien		| Save area for AltiVec registers (W)	| 24+P+A+L+X
1292290075Sobrien		+---------------------------------------+
1292390075Sobrien		| AltiVec alignment padding (Y)		| 24+P+A+L+X+W
1292490075Sobrien		+---------------------------------------+
1292590075Sobrien		| Save area for VRSAVE register (Z)	| 24+P+A+L+X+W+Y
1292690075Sobrien		+---------------------------------------+
1292790075Sobrien		| Save area for GP registers (G)	| 24+P+A+X+L+X+W+Y+Z
1292890075Sobrien		+---------------------------------------+
1292990075Sobrien		| Save area for FP registers (F)	| 24+P+A+X+L+X+W+Y+Z+G
1293090075Sobrien		+---------------------------------------+
1293190075Sobrien	old SP->| back chain to caller's caller		|
1293290075Sobrien		+---------------------------------------+
1293390075Sobrien
1293490075Sobrien   The required alignment for AIX configurations is two words (i.e., 8
1293590075Sobrien   or 16 bytes).
1293690075Sobrien
1293790075Sobrien
1293890075Sobrien   V.4 stack frames look like:
1293990075Sobrien
1294090075Sobrien	SP---->	+---------------------------------------+
1294190075Sobrien		| back chain to caller			| 0
1294290075Sobrien		+---------------------------------------+
1294390075Sobrien		| caller's saved LR			| 4
1294490075Sobrien		+---------------------------------------+
1294590075Sobrien		| Parameter save area (P)		| 8
1294690075Sobrien		+---------------------------------------+
1294790075Sobrien		| Alloca space (A)			| 8+P
12948169689Skan		+---------------------------------------+
1294990075Sobrien		| Varargs save area (V)			| 8+P+A
12950169689Skan		+---------------------------------------+
1295190075Sobrien		| Local variable space (L)		| 8+P+A+V
12952169689Skan		+---------------------------------------+
1295390075Sobrien		| Float/int conversion temporary (X)	| 8+P+A+V+L
1295490075Sobrien		+---------------------------------------+
1295590075Sobrien		| Save area for AltiVec registers (W)	| 8+P+A+V+L+X
1295690075Sobrien		+---------------------------------------+
1295790075Sobrien		| AltiVec alignment padding (Y)		| 8+P+A+V+L+X+W
1295890075Sobrien		+---------------------------------------+
1295990075Sobrien		| Save area for VRSAVE register (Z)	| 8+P+A+V+L+X+W+Y
1296090075Sobrien		+---------------------------------------+
12961169689Skan		| SPE: area for 64-bit GP registers	|
12962169689Skan		+---------------------------------------+
12963169689Skan		| SPE alignment padding			|
12964169689Skan		+---------------------------------------+
1296590075Sobrien		| saved CR (C)				| 8+P+A+V+L+X+W+Y+Z
12966169689Skan		+---------------------------------------+
1296790075Sobrien		| Save area for GP registers (G)	| 8+P+A+V+L+X+W+Y+Z+C
12968169689Skan		+---------------------------------------+
1296990075Sobrien		| Save area for FP registers (F)	| 8+P+A+V+L+X+W+Y+Z+C+G
1297090075Sobrien		+---------------------------------------+
1297190075Sobrien	old SP->| back chain to caller's caller		|
1297290075Sobrien		+---------------------------------------+
1297390075Sobrien
1297490075Sobrien   The required alignment for V.4 is 16 bytes, or 8 bytes if -meabi is
1297590075Sobrien   given.  (But note below and in sysv4.h that we require only 8 and
1297690075Sobrien   may round up the size of our stack frame anyways.  The historical
1297790075Sobrien   reason is early versions of powerpc-linux which didn't properly
1297890075Sobrien   align the stack at program startup.  A happy side-effect is that
1297990075Sobrien   -mno-eabi libraries can be used with -meabi programs.)
1298090075Sobrien
12981132718Skan   The EABI configuration defaults to the V.4 layout.  However,
1298290075Sobrien   the stack alignment requirements may differ.  If -mno-eabi is not
1298390075Sobrien   given, the required stack alignment is 8 bytes; if -mno-eabi is
1298490075Sobrien   given, the required alignment is 16 bytes.  (But see V.4 comment
1298590075Sobrien   above.)  */
1298690075Sobrien
1298790075Sobrien#ifndef ABI_STACK_BOUNDARY
1298890075Sobrien#define ABI_STACK_BOUNDARY STACK_BOUNDARY
1298990075Sobrien#endif
1299090075Sobrien
12991132718Skanstatic rs6000_stack_t *
12992132718Skanrs6000_stack_info (void)
1299390075Sobrien{
12994169689Skan  static rs6000_stack_t info;
1299590075Sobrien  rs6000_stack_t *info_ptr = &info;
12996132718Skan  int reg_size = TARGET_32BIT ? 4 : 8;
1299790075Sobrien  int ehrd_size;
12998146895Skan  int save_align;
12999132718Skan  HOST_WIDE_INT non_fixed_size;
1300090075Sobrien
13001169689Skan  memset (&info, 0, sizeof (info));
1300290075Sobrien
13003132718Skan  if (TARGET_SPE)
13004132718Skan    {
13005132718Skan      /* Cache value so we don't rescan instruction chain over and over.  */
13006132718Skan      if (cfun->machine->insn_chain_scanned_p == 0)
13007169689Skan	cfun->machine->insn_chain_scanned_p
13008169689Skan	  = spe_func_has_64bit_regs_p () + 1;
13009169689Skan      info_ptr->spe_64bit_regs_used = cfun->machine->insn_chain_scanned_p - 1;
13010132718Skan    }
13011132718Skan
1301290075Sobrien  /* Select which calling sequence.  */
13013132718Skan  info_ptr->abi = DEFAULT_ABI;
1301490075Sobrien
1301590075Sobrien  /* Calculate which registers need to be saved & save area size.  */
1301690075Sobrien  info_ptr->first_gp_reg_save = first_reg_to_save ();
13017169689Skan  /* Assume that we will have to save RS6000_PIC_OFFSET_TABLE_REGNUM,
1301890075Sobrien     even if it currently looks like we won't.  */
1301990075Sobrien  if (((TARGET_TOC && TARGET_MINIMAL_TOC)
13020132718Skan       || (flag_pic == 1 && DEFAULT_ABI == ABI_V4)
13021132718Skan       || (flag_pic && DEFAULT_ABI == ABI_DARWIN))
1302296263Sobrien      && info_ptr->first_gp_reg_save > RS6000_PIC_OFFSET_TABLE_REGNUM)
1302396263Sobrien    info_ptr->gp_size = reg_size * (32 - RS6000_PIC_OFFSET_TABLE_REGNUM);
1302490075Sobrien  else
1302590075Sobrien    info_ptr->gp_size = reg_size * (32 - info_ptr->first_gp_reg_save);
1302690075Sobrien
13027117395Skan  /* For the SPE, we have an additional upper 32-bits on each GPR.
13028117395Skan     Ideally we should save the entire 64-bits only when the upper
13029117395Skan     half is used in SIMD instructions.  Since we only record
13030117395Skan     registers live (not the size they are used in), this proves
13031117395Skan     difficult because we'd have to traverse the instruction chain at
13032117395Skan     the right time, taking reload into account.  This is a real pain,
13033132718Skan     so we opt to save the GPRs in 64-bits always if but one register
13034132718Skan     gets used in 64-bits.  Otherwise, all the registers in the frame
13035132718Skan     get saved in 32-bits.
13036117395Skan
13037132718Skan     So... since when we save all GPRs (except the SP) in 64-bits, the
13038117395Skan     traditional GP save area will be empty.  */
13039132718Skan  if (TARGET_SPE_ABI && info_ptr->spe_64bit_regs_used != 0)
13040117395Skan    info_ptr->gp_size = 0;
13041117395Skan
1304290075Sobrien  info_ptr->first_fp_reg_save = first_fp_reg_to_save ();
1304390075Sobrien  info_ptr->fp_size = 8 * (64 - info_ptr->first_fp_reg_save);
1304490075Sobrien
1304590075Sobrien  info_ptr->first_altivec_reg_save = first_altivec_reg_to_save ();
1304690075Sobrien  info_ptr->altivec_size = 16 * (LAST_ALTIVEC_REGNO + 1
1304790075Sobrien				 - info_ptr->first_altivec_reg_save);
1304890075Sobrien
1304990075Sobrien  /* Does this function call anything?  */
1305090075Sobrien  info_ptr->calls_p = (! current_function_is_leaf
1305190075Sobrien		       || cfun->machine->ra_needs_full_frame);
1305290075Sobrien
1305390075Sobrien  /* Determine if we need to save the link register.  */
13054169689Skan  if ((DEFAULT_ABI == ABI_AIX
13055169689Skan       && current_function_profile
13056169689Skan       && !TARGET_PROFILE_KERNEL)
1305790075Sobrien#ifdef TARGET_RELOCATABLE
1305890075Sobrien      || (TARGET_RELOCATABLE && (get_pool_size () != 0))
1305990075Sobrien#endif
1306090075Sobrien      || (info_ptr->first_fp_reg_save != 64
1306190075Sobrien	  && !FP_SAVE_INLINE (info_ptr->first_fp_reg_save))
1306290075Sobrien      || info_ptr->first_altivec_reg_save <= LAST_ALTIVEC_REGNO
13063132718Skan      || (DEFAULT_ABI == ABI_V4 && current_function_calls_alloca)
13064169689Skan      || info_ptr->calls_p
13065169689Skan      || rs6000_ra_ever_killed ())
1306690075Sobrien    {
1306790075Sobrien      info_ptr->lr_save_p = 1;
1306890075Sobrien      regs_ever_live[LINK_REGISTER_REGNUM] = 1;
1306990075Sobrien    }
1307090075Sobrien
1307190075Sobrien  /* Determine if we need to save the condition code registers.  */
13072169689Skan  if (regs_ever_live[CR2_REGNO]
1307390075Sobrien      || regs_ever_live[CR3_REGNO]
1307490075Sobrien      || regs_ever_live[CR4_REGNO])
1307590075Sobrien    {
1307690075Sobrien      info_ptr->cr_save_p = 1;
13077132718Skan      if (DEFAULT_ABI == ABI_V4)
1307890075Sobrien	info_ptr->cr_size = reg_size;
1307990075Sobrien    }
1308090075Sobrien
1308190075Sobrien  /* If the current function calls __builtin_eh_return, then we need
1308290075Sobrien     to allocate stack space for registers that will hold data for
1308390075Sobrien     the exception handler.  */
1308490075Sobrien  if (current_function_calls_eh_return)
1308590075Sobrien    {
1308690075Sobrien      unsigned int i;
1308790075Sobrien      for (i = 0; EH_RETURN_DATA_REGNO (i) != INVALID_REGNUM; ++i)
1308890075Sobrien	continue;
13089117395Skan
13090117395Skan      /* SPE saves EH registers in 64-bits.  */
13091132718Skan      ehrd_size = i * (TARGET_SPE_ABI
13092132718Skan		       && info_ptr->spe_64bit_regs_used != 0
13093132718Skan		       ? UNITS_PER_SPE_WORD : UNITS_PER_WORD);
1309490075Sobrien    }
1309590075Sobrien  else
1309690075Sobrien    ehrd_size = 0;
1309790075Sobrien
1309890075Sobrien  /* Determine various sizes.  */
1309990075Sobrien  info_ptr->reg_size     = reg_size;
1310090075Sobrien  info_ptr->fixed_size   = RS6000_SAVE_AREA;
1310190075Sobrien  info_ptr->vars_size    = RS6000_ALIGN (get_frame_size (), 8);
1310290075Sobrien  info_ptr->parm_size    = RS6000_ALIGN (current_function_outgoing_args_size,
13103132718Skan					 TARGET_ALTIVEC ? 16 : 8);
13104169689Skan  if (FRAME_GROWS_DOWNWARD)
13105169689Skan    info_ptr->vars_size
13106169689Skan      += RS6000_ALIGN (info_ptr->fixed_size + info_ptr->vars_size
13107169689Skan		       + info_ptr->parm_size,
13108169689Skan		       ABI_STACK_BOUNDARY / BITS_PER_UNIT)
13109169689Skan	 - (info_ptr->fixed_size + info_ptr->vars_size
13110169689Skan	    + info_ptr->parm_size);
1311190075Sobrien
13112132718Skan  if (TARGET_SPE_ABI && info_ptr->spe_64bit_regs_used != 0)
13113117395Skan    info_ptr->spe_gp_size = 8 * (32 - info_ptr->first_gp_reg_save);
13114117395Skan  else
13115117395Skan    info_ptr->spe_gp_size = 0;
13116117395Skan
13117132718Skan  if (TARGET_ALTIVEC_ABI)
13118132718Skan    info_ptr->vrsave_mask = compute_vrsave_mask ();
1311990075Sobrien  else
13120132718Skan    info_ptr->vrsave_mask = 0;
1312190075Sobrien
13122132718Skan  if (TARGET_ALTIVEC_VRSAVE && info_ptr->vrsave_mask)
13123132718Skan    info_ptr->vrsave_size  = 4;
13124132718Skan  else
13125132718Skan    info_ptr->vrsave_size  = 0;
13126132718Skan
13127169689Skan  compute_save_world_info (info_ptr);
13128169689Skan
1312990075Sobrien  /* Calculate the offsets.  */
13130132718Skan  switch (DEFAULT_ABI)
1313190075Sobrien    {
1313290075Sobrien    case ABI_NONE:
1313390075Sobrien    default:
13134169689Skan      gcc_unreachable ();
1313590075Sobrien
1313690075Sobrien    case ABI_AIX:
1313790075Sobrien    case ABI_DARWIN:
1313890075Sobrien      info_ptr->fp_save_offset   = - info_ptr->fp_size;
1313990075Sobrien      info_ptr->gp_save_offset   = info_ptr->fp_save_offset - info_ptr->gp_size;
1314090075Sobrien
1314190075Sobrien      if (TARGET_ALTIVEC_ABI)
1314290075Sobrien	{
1314390075Sobrien	  info_ptr->vrsave_save_offset
1314490075Sobrien	    = info_ptr->gp_save_offset - info_ptr->vrsave_size;
1314590075Sobrien
13146169689Skan	  /* Align stack so vector save area is on a quadword boundary.
13147169689Skan	     The padding goes above the vectors.  */
1314890075Sobrien	  if (info_ptr->altivec_size != 0)
1314990075Sobrien	    info_ptr->altivec_padding_size
13150169689Skan	      = info_ptr->vrsave_save_offset & 0xF;
1315190075Sobrien	  else
1315290075Sobrien	    info_ptr->altivec_padding_size = 0;
1315390075Sobrien
1315490075Sobrien	  info_ptr->altivec_save_offset
1315590075Sobrien	    = info_ptr->vrsave_save_offset
1315690075Sobrien	    - info_ptr->altivec_padding_size
1315790075Sobrien	    - info_ptr->altivec_size;
13158169689Skan	  gcc_assert (info_ptr->altivec_size == 0
13159169689Skan		      || info_ptr->altivec_save_offset % 16 == 0);
1316090075Sobrien
1316190075Sobrien	  /* Adjust for AltiVec case.  */
1316290075Sobrien	  info_ptr->ehrd_offset = info_ptr->altivec_save_offset - ehrd_size;
1316390075Sobrien	}
1316490075Sobrien      else
1316590075Sobrien	info_ptr->ehrd_offset      = info_ptr->gp_save_offset - ehrd_size;
1316690075Sobrien      info_ptr->cr_save_offset   = reg_size; /* first word when 64-bit.  */
1316790075Sobrien      info_ptr->lr_save_offset   = 2*reg_size;
1316890075Sobrien      break;
1316990075Sobrien
1317090075Sobrien    case ABI_V4:
1317190075Sobrien      info_ptr->fp_save_offset   = - info_ptr->fp_size;
1317290075Sobrien      info_ptr->gp_save_offset   = info_ptr->fp_save_offset - info_ptr->gp_size;
1317390075Sobrien      info_ptr->cr_save_offset   = info_ptr->gp_save_offset - info_ptr->cr_size;
1317490075Sobrien
13175132718Skan      if (TARGET_SPE_ABI && info_ptr->spe_64bit_regs_used != 0)
13176169689Skan	{
13177169689Skan	  /* Align stack so SPE GPR save area is aligned on a
13178169689Skan	     double-word boundary.  */
13179169689Skan	  if (info_ptr->spe_gp_size != 0)
13180169689Skan	    info_ptr->spe_padding_size
13181169689Skan	      = 8 - (-info_ptr->cr_save_offset % 8);
13182169689Skan	  else
13183169689Skan	    info_ptr->spe_padding_size = 0;
13184117395Skan
13185169689Skan	  info_ptr->spe_gp_save_offset
13186169689Skan	    = info_ptr->cr_save_offset
13187169689Skan	    - info_ptr->spe_padding_size
13188169689Skan	    - info_ptr->spe_gp_size;
13189117395Skan
13190169689Skan	  /* Adjust for SPE case.  */
13191169689Skan	  info_ptr->ehrd_offset = info_ptr->spe_gp_save_offset;
13192169689Skan	}
13193117395Skan      else if (TARGET_ALTIVEC_ABI)
1319490075Sobrien	{
1319590075Sobrien	  info_ptr->vrsave_save_offset
1319690075Sobrien	    = info_ptr->cr_save_offset - info_ptr->vrsave_size;
1319790075Sobrien
1319890075Sobrien	  /* Align stack so vector save area is on a quadword boundary.  */
1319990075Sobrien	  if (info_ptr->altivec_size != 0)
1320090075Sobrien	    info_ptr->altivec_padding_size
1320190075Sobrien	      = 16 - (-info_ptr->vrsave_save_offset % 16);
1320290075Sobrien	  else
1320390075Sobrien	    info_ptr->altivec_padding_size = 0;
1320490075Sobrien
1320590075Sobrien	  info_ptr->altivec_save_offset
1320690075Sobrien	    = info_ptr->vrsave_save_offset
1320790075Sobrien	    - info_ptr->altivec_padding_size
1320890075Sobrien	    - info_ptr->altivec_size;
1320990075Sobrien
1321090075Sobrien	  /* Adjust for AltiVec case.  */
13211169689Skan	  info_ptr->ehrd_offset = info_ptr->altivec_save_offset;
1321290075Sobrien	}
1321390075Sobrien      else
13214169689Skan	info_ptr->ehrd_offset    = info_ptr->cr_save_offset;
13215169689Skan      info_ptr->ehrd_offset      -= ehrd_size;
1321690075Sobrien      info_ptr->lr_save_offset   = reg_size;
1321790075Sobrien      break;
1321890075Sobrien    }
1321990075Sobrien
13220146895Skan  save_align = (TARGET_ALTIVEC_ABI || DEFAULT_ABI == ABI_DARWIN) ? 16 : 8;
1322190075Sobrien  info_ptr->save_size    = RS6000_ALIGN (info_ptr->fp_size
1322290075Sobrien					 + info_ptr->gp_size
1322390075Sobrien					 + info_ptr->altivec_size
1322490075Sobrien					 + info_ptr->altivec_padding_size
13225117395Skan					 + info_ptr->spe_gp_size
13226117395Skan					 + info_ptr->spe_padding_size
1322790075Sobrien					 + ehrd_size
1322890075Sobrien					 + info_ptr->cr_size
13229169689Skan					 + info_ptr->vrsave_size,
13230146895Skan					 save_align);
1323190075Sobrien
13232132718Skan  non_fixed_size	 = (info_ptr->vars_size
1323390075Sobrien			    + info_ptr->parm_size
13234169689Skan			    + info_ptr->save_size);
1323590075Sobrien
13236132718Skan  info_ptr->total_size = RS6000_ALIGN (non_fixed_size + info_ptr->fixed_size,
13237132718Skan				       ABI_STACK_BOUNDARY / BITS_PER_UNIT);
1323890075Sobrien
1323990075Sobrien  /* Determine if we need to allocate any stack frame:
1324090075Sobrien
1324190075Sobrien     For AIX we need to push the stack if a frame pointer is needed
1324290075Sobrien     (because the stack might be dynamically adjusted), if we are
1324390075Sobrien     debugging, if we make calls, or if the sum of fp_save, gp_save,
1324490075Sobrien     and local variables are more than the space needed to save all
1324590075Sobrien     non-volatile registers: 32-bit: 18*8 + 19*4 = 220 or 64-bit: 18*8
1324690075Sobrien     + 18*8 = 288 (GPR13 reserved).
1324790075Sobrien
1324890075Sobrien     For V.4 we don't have the stack cushion that AIX uses, but assume
1324990075Sobrien     that the debugger can handle stackless frames.  */
1325090075Sobrien
1325190075Sobrien  if (info_ptr->calls_p)
1325290075Sobrien    info_ptr->push_p = 1;
1325390075Sobrien
13254132718Skan  else if (DEFAULT_ABI == ABI_V4)
13255132718Skan    info_ptr->push_p = non_fixed_size != 0;
1325690075Sobrien
13257132718Skan  else if (frame_pointer_needed)
13258132718Skan    info_ptr->push_p = 1;
13259132718Skan
13260132718Skan  else if (TARGET_XCOFF && write_symbols != NO_DEBUG)
13261132718Skan    info_ptr->push_p = 1;
13262132718Skan
1326390075Sobrien  else
13264132718Skan    info_ptr->push_p = non_fixed_size > (TARGET_32BIT ? 220 : 288);
1326590075Sobrien
1326690075Sobrien  /* Zero offsets if we're not saving those registers.  */
1326790075Sobrien  if (info_ptr->fp_size == 0)
1326890075Sobrien    info_ptr->fp_save_offset = 0;
1326990075Sobrien
1327090075Sobrien  if (info_ptr->gp_size == 0)
1327190075Sobrien    info_ptr->gp_save_offset = 0;
1327290075Sobrien
1327390075Sobrien  if (! TARGET_ALTIVEC_ABI || info_ptr->altivec_size == 0)
1327490075Sobrien    info_ptr->altivec_save_offset = 0;
1327590075Sobrien
1327690075Sobrien  if (! TARGET_ALTIVEC_ABI || info_ptr->vrsave_mask == 0)
1327790075Sobrien    info_ptr->vrsave_save_offset = 0;
1327890075Sobrien
13279132718Skan  if (! TARGET_SPE_ABI
13280132718Skan      || info_ptr->spe_64bit_regs_used == 0
13281132718Skan      || info_ptr->spe_gp_size == 0)
13282117395Skan    info_ptr->spe_gp_save_offset = 0;
13283117395Skan
1328490075Sobrien  if (! info_ptr->lr_save_p)
1328590075Sobrien    info_ptr->lr_save_offset = 0;
1328690075Sobrien
1328790075Sobrien  if (! info_ptr->cr_save_p)
1328890075Sobrien    info_ptr->cr_save_offset = 0;
1328990075Sobrien
1329090075Sobrien  return info_ptr;
1329190075Sobrien}
1329290075Sobrien
13293132718Skan/* Return true if the current function uses any GPRs in 64-bit SIMD
13294132718Skan   mode.  */
13295132718Skan
13296132718Skanstatic bool
13297132718Skanspe_func_has_64bit_regs_p (void)
1329890075Sobrien{
13299132718Skan  rtx insns, insn;
13300132718Skan
13301132718Skan  /* Functions that save and restore all the call-saved registers will
13302132718Skan     need to save/restore the registers in 64-bits.  */
13303132718Skan  if (current_function_calls_eh_return
13304132718Skan      || current_function_calls_setjmp
13305132718Skan      || current_function_has_nonlocal_goto)
13306132718Skan    return true;
13307132718Skan
13308132718Skan  insns = get_insns ();
13309132718Skan
13310132718Skan  for (insn = NEXT_INSN (insns); insn != NULL_RTX; insn = NEXT_INSN (insn))
13311132718Skan    {
13312132718Skan      if (INSN_P (insn))
13313132718Skan	{
13314132718Skan	  rtx i;
13315132718Skan
13316169689Skan	  /* FIXME: This should be implemented with attributes...
13317169689Skan
13318169689Skan	         (set_attr "spe64" "true")....then,
13319169689Skan	         if (get_spe64(insn)) return true;
13320169689Skan
13321169689Skan	     It's the only reliable way to do the stuff below.  */
13322169689Skan
13323132718Skan	  i = PATTERN (insn);
13324169689Skan	  if (GET_CODE (i) == SET)
13325169689Skan	    {
13326169689Skan	      enum machine_mode mode = GET_MODE (SET_SRC (i));
13327169689Skan
13328169689Skan	      if (SPE_VECTOR_MODE (mode))
13329169689Skan		return true;
13330169689Skan	      if (TARGET_E500_DOUBLE && mode == DFmode)
13331169689Skan		return true;
13332169689Skan	    }
13333132718Skan	}
13334132718Skan    }
13335132718Skan
13336132718Skan  return false;
13337132718Skan}
13338132718Skan
13339132718Skanstatic void
13340132718Skandebug_stack_info (rs6000_stack_t *info)
13341132718Skan{
1334290075Sobrien  const char *abi_string;
1334390075Sobrien
1334490075Sobrien  if (! info)
1334590075Sobrien    info = rs6000_stack_info ();
1334690075Sobrien
1334790075Sobrien  fprintf (stderr, "\nStack information for function %s:\n",
1334890075Sobrien	   ((current_function_decl && DECL_NAME (current_function_decl))
1334990075Sobrien	    ? IDENTIFIER_POINTER (DECL_NAME (current_function_decl))
1335090075Sobrien	    : "<unknown>"));
1335190075Sobrien
1335290075Sobrien  switch (info->abi)
1335390075Sobrien    {
1335490075Sobrien    default:		 abi_string = "Unknown";	break;
1335590075Sobrien    case ABI_NONE:	 abi_string = "NONE";		break;
13356132718Skan    case ABI_AIX:	 abi_string = "AIX";		break;
1335790075Sobrien    case ABI_DARWIN:	 abi_string = "Darwin";		break;
1335890075Sobrien    case ABI_V4:	 abi_string = "V.4";		break;
1335990075Sobrien    }
1336090075Sobrien
1336190075Sobrien  fprintf (stderr, "\tABI                 = %5s\n", abi_string);
1336290075Sobrien
1336390075Sobrien  if (TARGET_ALTIVEC_ABI)
1336490075Sobrien    fprintf (stderr, "\tALTIVEC ABI extensions enabled.\n");
1336590075Sobrien
13366117395Skan  if (TARGET_SPE_ABI)
13367117395Skan    fprintf (stderr, "\tSPE ABI extensions enabled.\n");
13368117395Skan
1336990075Sobrien  if (info->first_gp_reg_save != 32)
1337090075Sobrien    fprintf (stderr, "\tfirst_gp_reg_save   = %5d\n", info->first_gp_reg_save);
1337190075Sobrien
1337290075Sobrien  if (info->first_fp_reg_save != 64)
1337390075Sobrien    fprintf (stderr, "\tfirst_fp_reg_save   = %5d\n", info->first_fp_reg_save);
1337490075Sobrien
1337590075Sobrien  if (info->first_altivec_reg_save <= LAST_ALTIVEC_REGNO)
1337690075Sobrien    fprintf (stderr, "\tfirst_altivec_reg_save = %5d\n",
1337790075Sobrien	     info->first_altivec_reg_save);
1337890075Sobrien
1337990075Sobrien  if (info->lr_save_p)
1338090075Sobrien    fprintf (stderr, "\tlr_save_p           = %5d\n", info->lr_save_p);
1338190075Sobrien
1338290075Sobrien  if (info->cr_save_p)
1338390075Sobrien    fprintf (stderr, "\tcr_save_p           = %5d\n", info->cr_save_p);
1338490075Sobrien
1338590075Sobrien  if (info->vrsave_mask)
1338690075Sobrien    fprintf (stderr, "\tvrsave_mask         = 0x%x\n", info->vrsave_mask);
1338790075Sobrien
1338890075Sobrien  if (info->push_p)
1338990075Sobrien    fprintf (stderr, "\tpush_p              = %5d\n", info->push_p);
1339090075Sobrien
1339190075Sobrien  if (info->calls_p)
1339290075Sobrien    fprintf (stderr, "\tcalls_p             = %5d\n", info->calls_p);
1339390075Sobrien
1339490075Sobrien  if (info->gp_save_offset)
1339590075Sobrien    fprintf (stderr, "\tgp_save_offset      = %5d\n", info->gp_save_offset);
1339690075Sobrien
1339790075Sobrien  if (info->fp_save_offset)
1339890075Sobrien    fprintf (stderr, "\tfp_save_offset      = %5d\n", info->fp_save_offset);
1339990075Sobrien
1340090075Sobrien  if (info->altivec_save_offset)
1340190075Sobrien    fprintf (stderr, "\taltivec_save_offset = %5d\n",
1340290075Sobrien	     info->altivec_save_offset);
1340390075Sobrien
13404117395Skan  if (info->spe_gp_save_offset)
13405117395Skan    fprintf (stderr, "\tspe_gp_save_offset  = %5d\n",
13406117395Skan	     info->spe_gp_save_offset);
13407117395Skan
1340890075Sobrien  if (info->vrsave_save_offset)
1340990075Sobrien    fprintf (stderr, "\tvrsave_save_offset  = %5d\n",
1341090075Sobrien	     info->vrsave_save_offset);
1341190075Sobrien
1341290075Sobrien  if (info->lr_save_offset)
1341390075Sobrien    fprintf (stderr, "\tlr_save_offset      = %5d\n", info->lr_save_offset);
1341490075Sobrien
1341590075Sobrien  if (info->cr_save_offset)
1341690075Sobrien    fprintf (stderr, "\tcr_save_offset      = %5d\n", info->cr_save_offset);
1341790075Sobrien
1341890075Sobrien  if (info->varargs_save_offset)
1341990075Sobrien    fprintf (stderr, "\tvarargs_save_offset = %5d\n", info->varargs_save_offset);
1342090075Sobrien
1342190075Sobrien  if (info->total_size)
13422132718Skan    fprintf (stderr, "\ttotal_size          = "HOST_WIDE_INT_PRINT_DEC"\n",
13423132718Skan	     info->total_size);
1342490075Sobrien
1342590075Sobrien  if (info->vars_size)
13426132718Skan    fprintf (stderr, "\tvars_size           = "HOST_WIDE_INT_PRINT_DEC"\n",
13427132718Skan	     info->vars_size);
1342890075Sobrien
1342990075Sobrien  if (info->parm_size)
1343090075Sobrien    fprintf (stderr, "\tparm_size           = %5d\n", info->parm_size);
1343190075Sobrien
1343290075Sobrien  if (info->fixed_size)
1343390075Sobrien    fprintf (stderr, "\tfixed_size          = %5d\n", info->fixed_size);
1343490075Sobrien
1343590075Sobrien  if (info->gp_size)
1343690075Sobrien    fprintf (stderr, "\tgp_size             = %5d\n", info->gp_size);
1343790075Sobrien
13438117395Skan  if (info->spe_gp_size)
13439117395Skan    fprintf (stderr, "\tspe_gp_size         = %5d\n", info->spe_gp_size);
13440117395Skan
1344190075Sobrien  if (info->fp_size)
1344290075Sobrien    fprintf (stderr, "\tfp_size             = %5d\n", info->fp_size);
1344390075Sobrien
1344490075Sobrien  if (info->altivec_size)
1344590075Sobrien    fprintf (stderr, "\taltivec_size        = %5d\n", info->altivec_size);
1344690075Sobrien
1344790075Sobrien  if (info->vrsave_size)
1344890075Sobrien    fprintf (stderr, "\tvrsave_size         = %5d\n", info->vrsave_size);
1344990075Sobrien
1345090075Sobrien  if (info->altivec_padding_size)
1345190075Sobrien    fprintf (stderr, "\taltivec_padding_size= %5d\n",
1345290075Sobrien	     info->altivec_padding_size);
1345390075Sobrien
13454117395Skan  if (info->spe_padding_size)
13455117395Skan    fprintf (stderr, "\tspe_padding_size    = %5d\n",
13456117395Skan	     info->spe_padding_size);
13457117395Skan
1345890075Sobrien  if (info->cr_size)
1345990075Sobrien    fprintf (stderr, "\tcr_size             = %5d\n", info->cr_size);
1346090075Sobrien
1346190075Sobrien  if (info->save_size)
1346290075Sobrien    fprintf (stderr, "\tsave_size           = %5d\n", info->save_size);
1346390075Sobrien
1346490075Sobrien  if (info->reg_size != 4)
1346590075Sobrien    fprintf (stderr, "\treg_size            = %5d\n", info->reg_size);
1346690075Sobrien
1346790075Sobrien  fprintf (stderr, "\n");
1346890075Sobrien}
1346990075Sobrien
1347090075Sobrienrtx
13471132718Skanrs6000_return_addr (int count, rtx frame)
1347290075Sobrien{
1347390075Sobrien  /* Currently we don't optimize very well between prolog and body
1347490075Sobrien     code and for PIC code the code can be actually quite bad, so
1347590075Sobrien     don't try to be too clever here.  */
13476132718Skan  if (count != 0 || (DEFAULT_ABI != ABI_AIX && flag_pic))
1347790075Sobrien    {
1347890075Sobrien      cfun->machine->ra_needs_full_frame = 1;
1347990075Sobrien
1348090075Sobrien      return
1348190075Sobrien	gen_rtx_MEM
1348290075Sobrien	  (Pmode,
1348390075Sobrien	   memory_address
1348490075Sobrien	   (Pmode,
1348590075Sobrien	    plus_constant (copy_to_reg
1348690075Sobrien			   (gen_rtx_MEM (Pmode,
1348790075Sobrien					 memory_address (Pmode, frame))),
1348890075Sobrien			   RETURN_ADDRESS_OFFSET)));
1348990075Sobrien    }
1349090075Sobrien
13491132718Skan  cfun->machine->ra_need_lr = 1;
1349290075Sobrien  return get_hard_reg_initial_val (Pmode, LINK_REGISTER_REGNUM);
1349390075Sobrien}
1349490075Sobrien
13495117395Skan/* Say whether a function is a candidate for sibcall handling or not.
13496117395Skan   We do not allow indirect calls to be optimized into sibling calls.
13497117395Skan   Also, we can't do it if there are any vector parameters; there's
13498117395Skan   nowhere to put the VRsave code so it works; note that functions with
13499117395Skan   vector parameters are required to have a prototype, so the argument
13500117395Skan   type info must be available here.  (The tail recursion case can work
13501117395Skan   with vector parameters, but there's no way to distinguish here.) */
13502132718Skanstatic bool
13503132718Skanrs6000_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
13504117395Skan{
13505117395Skan  tree type;
13506132718Skan  if (decl)
13507117395Skan    {
13508117395Skan      if (TARGET_ALTIVEC_VRSAVE)
13509169689Skan	{
13510132718Skan	  for (type = TYPE_ARG_TYPES (TREE_TYPE (decl));
13511117395Skan	       type; type = TREE_CHAIN (type))
13512117395Skan	    {
13513117395Skan	      if (TREE_CODE (TREE_VALUE (type)) == VECTOR_TYPE)
13514132718Skan		return false;
13515117395Skan	    }
13516169689Skan	}
13517117395Skan      if (DEFAULT_ABI == ABI_DARWIN
13518132718Skan	  || (*targetm.binds_local_p) (decl))
13519117395Skan	{
13520132718Skan	  tree attr_list = TYPE_ATTRIBUTES (TREE_TYPE (decl));
13521117395Skan
13522117395Skan	  if (!lookup_attribute ("longcall", attr_list)
13523117395Skan	      || lookup_attribute ("shortcall", attr_list))
13524132718Skan	    return true;
13525117395Skan	}
13526117395Skan    }
13527132718Skan  return false;
13528117395Skan}
13529117395Skan
13530169689Skan/* NULL if INSN insn is valid within a low-overhead loop.
13531169689Skan   Otherwise return why doloop cannot be applied.
13532169689Skan   PowerPC uses the COUNT register for branch on table instructions.  */
13533169689Skan
13534169689Skanstatic const char *
13535169689Skanrs6000_invalid_within_doloop (rtx insn)
13536169689Skan{
13537169689Skan  if (CALL_P (insn))
13538169689Skan    return "Function call in the loop.";
13539169689Skan
13540169689Skan  if (JUMP_P (insn)
13541169689Skan      && (GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC
13542169689Skan	  || GET_CODE (PATTERN (insn)) == ADDR_VEC))
13543169689Skan    return "Computed branch in the loop.";
13544169689Skan
13545169689Skan  return NULL;
13546169689Skan}
13547169689Skan
1354890075Sobrienstatic int
13549132718Skanrs6000_ra_ever_killed (void)
1355090075Sobrien{
1355190075Sobrien  rtx top;
13552117395Skan  rtx reg;
13553117395Skan  rtx insn;
1355490075Sobrien
13555132718Skan  if (current_function_is_thunk)
1355690075Sobrien    return 0;
1355790075Sobrien
13558117395Skan  /* regs_ever_live has LR marked as used if any sibcalls are present,
13559117395Skan     but this should not force saving and restoring in the
13560117395Skan     pro/epilogue.  Likewise, reg_set_between_p thinks a sibcall
13561132718Skan     clobbers LR, so that is inappropriate.  */
13562117395Skan
13563117395Skan  /* Also, the prologue can generate a store into LR that
13564117395Skan     doesn't really count, like this:
13565117395Skan
13566117395Skan        move LR->R0
13567117395Skan        bcl to set PIC register
13568117395Skan        move LR->R31
13569117395Skan        move R0->LR
13570117395Skan
13571117395Skan     When we're called from the epilogue, we need to avoid counting
13572117395Skan     this as a store.  */
13573169689Skan
1357490075Sobrien  push_topmost_sequence ();
1357590075Sobrien  top = get_insns ();
1357690075Sobrien  pop_topmost_sequence ();
13577117395Skan  reg = gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM);
1357890075Sobrien
13579117395Skan  for (insn = NEXT_INSN (top); insn != NULL_RTX; insn = NEXT_INSN (insn))
13580117395Skan    {
13581117395Skan      if (INSN_P (insn))
13582117395Skan	{
13583169689Skan	  if (CALL_P (insn))
13584169689Skan	    {
13585169689Skan	      if (!SIBLING_CALL_P (insn))
13586169689Skan		return 1;
13587169689Skan	    }
13588169689Skan	  else if (find_regno_note (insn, REG_INC, LINK_REGISTER_REGNUM))
13589117395Skan	    return 1;
13590117395Skan	  else if (set_of (reg, insn) != NULL_RTX
13591117395Skan		   && !prologue_epilogue_contains (insn))
13592117395Skan	    return 1;
13593117395Skan    	}
13594117395Skan    }
13595117395Skan  return 0;
1359690075Sobrien}
1359790075Sobrien
1359890075Sobrien/* Add a REG_MAYBE_DEAD note to the insn.  */
1359990075Sobrienstatic void
13600132718Skanrs6000_maybe_dead (rtx insn)
1360190075Sobrien{
1360290075Sobrien  REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD,
1360390075Sobrien					const0_rtx,
1360490075Sobrien					REG_NOTES (insn));
1360590075Sobrien}
1360690075Sobrien
1360790075Sobrien/* Emit instructions needed to load the TOC register.
1360890075Sobrien   This is only needed when TARGET_TOC, TARGET_MINIMAL_TOC, and there is
1360990075Sobrien   a constant pool; or for SVR4 -fpic.  */
1361090075Sobrien
1361190075Sobrienvoid
13612132718Skanrs6000_emit_load_toc_table (int fromprolog)
1361390075Sobrien{
13614117395Skan  rtx dest, insn;
1361596263Sobrien  dest = gen_rtx_REG (Pmode, RS6000_PIC_OFFSET_TABLE_REGNUM);
1361690075Sobrien
13617169689Skan  if (TARGET_ELF && TARGET_SECURE_PLT && DEFAULT_ABI != ABI_AIX && flag_pic)
1361890075Sobrien    {
13619169689Skan      char buf[30];
13620169689Skan      rtx lab, tmp1, tmp2, got, tempLR;
13621169689Skan
13622169689Skan      ASM_GENERATE_INTERNAL_LABEL (buf, "LCF", rs6000_pic_labelno);
13623169689Skan      lab = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
13624169689Skan      if (flag_pic == 2)
13625169689Skan	got = gen_rtx_SYMBOL_REF (Pmode, toc_label_name);
13626169689Skan      else
13627169689Skan	got = rs6000_got_sym ();
13628169689Skan      tmp1 = tmp2 = dest;
13629169689Skan      if (!fromprolog)
13630169689Skan	{
13631169689Skan	  tmp1 = gen_reg_rtx (Pmode);
13632169689Skan	  tmp2 = gen_reg_rtx (Pmode);
13633169689Skan	}
13634169689Skan      tempLR = (fromprolog
13635169689Skan		? gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM)
13636169689Skan		: gen_reg_rtx (Pmode));
13637169689Skan      insn = emit_insn (gen_load_toc_v4_PIC_1 (tempLR, lab));
13638117395Skan      if (fromprolog)
13639117395Skan	rs6000_maybe_dead (insn);
13640169689Skan      insn = emit_move_insn (tmp1, tempLR);
13641117395Skan      if (fromprolog)
13642117395Skan	rs6000_maybe_dead (insn);
13643169689Skan      insn = emit_insn (gen_load_toc_v4_PIC_3b (tmp2, tmp1, got, lab));
13644169689Skan      if (fromprolog)
13645169689Skan	rs6000_maybe_dead (insn);
13646169689Skan      insn = emit_insn (gen_load_toc_v4_PIC_3c (dest, tmp2, got, lab));
13647169689Skan      if (fromprolog)
13648169689Skan	rs6000_maybe_dead (insn);
13649103445Skan    }
13650169689Skan  else if (TARGET_ELF && DEFAULT_ABI == ABI_V4 && flag_pic == 1)
13651169689Skan    {
13652169689Skan      rtx tempLR = (fromprolog
13653169689Skan		    ? gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM)
13654169689Skan		    : gen_reg_rtx (Pmode));
13655169689Skan
13656169689Skan      insn = emit_insn (gen_load_toc_v4_pic_si (tempLR));
13657169689Skan      if (fromprolog)
13658169689Skan	rs6000_maybe_dead (insn);
13659169689Skan      insn = emit_move_insn (dest, tempLR);
13660169689Skan      if (fromprolog)
13661169689Skan	rs6000_maybe_dead (insn);
13662169689Skan    }
13663103445Skan  else if (TARGET_ELF && DEFAULT_ABI != ABI_AIX && flag_pic == 2)
13664103445Skan    {
13665103445Skan      char buf[30];
13666103445Skan      rtx tempLR = (fromprolog
13667103445Skan		    ? gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM)
13668103445Skan		    : gen_reg_rtx (Pmode));
13669103445Skan      rtx temp0 = (fromprolog
13670103445Skan		   ? gen_rtx_REG (Pmode, 0)
13671103445Skan		   : gen_reg_rtx (Pmode));
13672103445Skan
13673103445Skan      if (fromprolog)
13674103445Skan	{
13675146895Skan	  rtx symF, symL;
1367690075Sobrien
13677103445Skan	  ASM_GENERATE_INTERNAL_LABEL (buf, "LCF", rs6000_pic_labelno);
13678103445Skan	  symF = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
1367990075Sobrien
13680103445Skan	  ASM_GENERATE_INTERNAL_LABEL (buf, "LCL", rs6000_pic_labelno);
13681103445Skan	  symL = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
1368290075Sobrien
13683103445Skan	  rs6000_maybe_dead (emit_insn (gen_load_toc_v4_PIC_1 (tempLR,
13684103445Skan							       symF)));
13685103445Skan	  rs6000_maybe_dead (emit_move_insn (dest, tempLR));
13686103445Skan	  rs6000_maybe_dead (emit_insn (gen_load_toc_v4_PIC_2 (temp0, dest,
13687103445Skan							       symL,
13688103445Skan							       symF)));
13689103445Skan	}
13690103445Skan      else
13691103445Skan	{
13692103445Skan	  rtx tocsym;
1369390075Sobrien
13694103445Skan	  tocsym = gen_rtx_SYMBOL_REF (Pmode, toc_label_name);
13695146895Skan	  emit_insn (gen_load_toc_v4_PIC_1b (tempLR, tocsym));
13696117395Skan	  emit_move_insn (dest, tempLR);
13697117395Skan	  emit_move_insn (temp0, gen_rtx_MEM (Pmode, dest));
1369890075Sobrien	}
13699117395Skan      insn = emit_insn (gen_addsi3 (dest, temp0, dest));
13700117395Skan      if (fromprolog)
13701117395Skan	rs6000_maybe_dead (insn);
1370290075Sobrien    }
13703103445Skan  else if (TARGET_ELF && !TARGET_AIX && flag_pic == 0 && TARGET_MINIMAL_TOC)
1370490075Sobrien    {
13705103445Skan      /* This is for AIX code running in non-PIC ELF32.  */
13706103445Skan      char buf[30];
13707103445Skan      rtx realsym;
13708103445Skan      ASM_GENERATE_INTERNAL_LABEL (buf, "LCTOC", 1);
13709103445Skan      realsym = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
13710103445Skan
13711117395Skan      insn = emit_insn (gen_elf_high (dest, realsym));
13712117395Skan      if (fromprolog)
13713117395Skan	rs6000_maybe_dead (insn);
13714117395Skan      insn = emit_insn (gen_elf_low (dest, dest, realsym));
13715117395Skan      if (fromprolog)
13716117395Skan	rs6000_maybe_dead (insn);
13717103445Skan    }
13718169689Skan  else
13719103445Skan    {
13720169689Skan      gcc_assert (DEFAULT_ABI == ABI_AIX);
13721169689Skan
1372290075Sobrien      if (TARGET_32BIT)
13723117395Skan	insn = emit_insn (gen_load_toc_aix_si (dest));
1372490075Sobrien      else
13725117395Skan	insn = emit_insn (gen_load_toc_aix_di (dest));
13726117395Skan      if (fromprolog)
13727117395Skan	rs6000_maybe_dead (insn);
1372890075Sobrien    }
1372990075Sobrien}
1373090075Sobrien
13731132718Skan/* Emit instructions to restore the link register after determining where
13732132718Skan   its value has been stored.  */
13733132718Skan
13734132718Skanvoid
13735132718Skanrs6000_emit_eh_reg_restore (rtx source, rtx scratch)
13736132718Skan{
13737132718Skan  rs6000_stack_t *info = rs6000_stack_info ();
13738132718Skan  rtx operands[2];
13739132718Skan
13740132718Skan  operands[0] = source;
13741132718Skan  operands[1] = scratch;
13742132718Skan
13743132718Skan  if (info->lr_save_p)
13744132718Skan    {
13745132718Skan      rtx frame_rtx = stack_pointer_rtx;
13746132718Skan      HOST_WIDE_INT sp_offset = 0;
13747132718Skan      rtx tmp;
13748132718Skan
13749132718Skan      if (frame_pointer_needed
13750132718Skan	  || current_function_calls_alloca
13751132718Skan	  || info->total_size > 32767)
13752132718Skan	{
13753169689Skan	  tmp = gen_frame_mem (Pmode, frame_rtx);
13754169689Skan	  emit_move_insn (operands[1], tmp);
13755132718Skan	  frame_rtx = operands[1];
13756132718Skan	}
13757132718Skan      else if (info->push_p)
13758132718Skan	sp_offset = info->total_size;
13759132718Skan
13760132718Skan      tmp = plus_constant (frame_rtx, info->lr_save_offset + sp_offset);
13761169689Skan      tmp = gen_frame_mem (Pmode, tmp);
13762132718Skan      emit_move_insn (tmp, operands[0]);
13763132718Skan    }
13764132718Skan  else
13765132718Skan    emit_move_insn (gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM), operands[0]);
13766132718Skan}
13767132718Skan
13768132718Skanstatic GTY(()) int set = -1;
13769132718Skan
13770169689Skanint
13771132718Skanget_TOC_alias_set (void)
1377290075Sobrien{
13773132718Skan  if (set == -1)
13774132718Skan    set = new_alias_set ();
13775132718Skan  return set;
13776169689Skan}
1377790075Sobrien
13778132718Skan/* This returns nonzero if the current function uses the TOC.  This is
13779132718Skan   determined by the presence of (use (unspec ... UNSPEC_TOC)), which
13780132718Skan   is generated by the ABI_V4 load_toc_* patterns.  */
13781132718Skan#if TARGET_ELF
13782132718Skanstatic int
13783169689Skanuses_TOC (void)
1378490075Sobrien{
13785132718Skan  rtx insn;
1378690075Sobrien
13787132718Skan  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
13788132718Skan    if (INSN_P (insn))
13789132718Skan      {
13790132718Skan	rtx pat = PATTERN (insn);
13791132718Skan	int i;
1379290075Sobrien
13793169689Skan	if (GET_CODE (pat) == PARALLEL)
13794132718Skan	  for (i = 0; i < XVECLEN (pat, 0); i++)
13795132718Skan	    {
13796132718Skan	      rtx sub = XVECEXP (pat, 0, i);
13797132718Skan	      if (GET_CODE (sub) == USE)
13798132718Skan		{
13799132718Skan		  sub = XEXP (sub, 0);
13800132718Skan		  if (GET_CODE (sub) == UNSPEC
13801132718Skan		      && XINT (sub, 1) == UNSPEC_TOC)
13802132718Skan		    return 1;
13803132718Skan		}
13804132718Skan	    }
13805132718Skan      }
13806132718Skan  return 0;
1380790075Sobrien}
13808132718Skan#endif
1380990075Sobrien
1381090075Sobrienrtx
13811169689Skancreate_TOC_reference (rtx symbol)
1381290075Sobrien{
13813161651Skan  if (no_new_pseudos)
13814161651Skan    regs_ever_live[TOC_REGISTER] = 1;
13815169689Skan  return gen_rtx_PLUS (Pmode,
1381690075Sobrien	   gen_rtx_REG (Pmode, TOC_REGISTER),
13817169689Skan	     gen_rtx_CONST (Pmode,
13818169689Skan	       gen_rtx_MINUS (Pmode, symbol,
1381990075Sobrien		 gen_rtx_SYMBOL_REF (Pmode, toc_label_name))));
1382090075Sobrien}
1382190075Sobrien
13822132718Skan/* If _Unwind_* has been called from within the same module,
13823132718Skan   toc register is not guaranteed to be saved to 40(1) on function
13824132718Skan   entry.  Save it there in that case.  */
1382590075Sobrien
1382690075Sobrienvoid
13827132718Skanrs6000_aix_emit_builtin_unwind_init (void)
1382890075Sobrien{
1382990075Sobrien  rtx mem;
1383090075Sobrien  rtx stack_top = gen_reg_rtx (Pmode);
1383190075Sobrien  rtx opcode_addr = gen_reg_rtx (Pmode);
13832132718Skan  rtx opcode = gen_reg_rtx (SImode);
13833132718Skan  rtx tocompare = gen_reg_rtx (SImode);
13834132718Skan  rtx no_toc_save_needed = gen_label_rtx ();
1383590075Sobrien
13836169689Skan  mem = gen_frame_mem (Pmode, hard_frame_pointer_rtx);
1383790075Sobrien  emit_move_insn (stack_top, mem);
1383890075Sobrien
13839169689Skan  mem = gen_frame_mem (Pmode,
13840169689Skan		       gen_rtx_PLUS (Pmode, stack_top,
13841169689Skan				     GEN_INT (2 * GET_MODE_SIZE (Pmode))));
1384290075Sobrien  emit_move_insn (opcode_addr, mem);
13843132718Skan  emit_move_insn (opcode, gen_rtx_MEM (SImode, opcode_addr));
13844132718Skan  emit_move_insn (tocompare, gen_int_mode (TARGET_32BIT ? 0x80410014
13845117395Skan					   : 0xE8410028, SImode));
1384690075Sobrien
13847132718Skan  do_compare_rtx_and_jump (opcode, tocompare, EQ, 1,
1384890075Sobrien			   SImode, NULL_RTX, NULL_RTX,
13849132718Skan			   no_toc_save_needed);
13850132718Skan
13851169689Skan  mem = gen_frame_mem (Pmode,
13852169689Skan		       gen_rtx_PLUS (Pmode, stack_top,
13853169689Skan				     GEN_INT (5 * GET_MODE_SIZE (Pmode))));
13854132718Skan  emit_move_insn (mem, gen_rtx_REG (Pmode, 2));
13855132718Skan  emit_label (no_toc_save_needed);
1385690075Sobrien}
1385790075Sobrien
13858169689Skan/* This ties together stack memory (MEM with an alias set of frame_alias_set)
13859169689Skan   and the change to the stack pointer.  */
1386090075Sobrien
1386190075Sobrienstatic void
13862132718Skanrs6000_emit_stack_tie (void)
1386390075Sobrien{
13864169689Skan  rtx mem = gen_frame_mem (BLKmode,
13865169689Skan			   gen_rtx_REG (Pmode, STACK_POINTER_REGNUM));
1386690075Sobrien
1386790075Sobrien  emit_insn (gen_stack_tie (mem));
1386890075Sobrien}
1386990075Sobrien
1387090075Sobrien/* Emit the correct code for allocating stack space, as insns.
1387190075Sobrien   If COPY_R12, make sure a copy of the old frame is left in r12.
1387290075Sobrien   The generated code may use hard register 0 as a temporary.  */
1387390075Sobrien
1387490075Sobrienstatic void
13875132718Skanrs6000_emit_allocate_stack (HOST_WIDE_INT size, int copy_r12)
1387690075Sobrien{
1387790075Sobrien  rtx insn;
1387890075Sobrien  rtx stack_reg = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
1387990075Sobrien  rtx tmp_reg = gen_rtx_REG (Pmode, 0);
13880169689Skan  rtx todec = gen_int_mode (-size, Pmode);
1388190075Sobrien
13882169689Skan  if (INTVAL (todec) != -size)
13883169689Skan    {
13884169689Skan      warning (0, "stack frame too large");
13885169689Skan      emit_insn (gen_trap ());
13886169689Skan      return;
13887169689Skan    }
13888169689Skan
1388990075Sobrien  if (current_function_limit_stack)
1389090075Sobrien    {
1389190075Sobrien      if (REG_P (stack_limit_rtx)
13892169689Skan	  && REGNO (stack_limit_rtx) > 1
1389390075Sobrien	  && REGNO (stack_limit_rtx) <= 31)
1389490075Sobrien	{
13895132718Skan	  emit_insn (TARGET_32BIT
1389690075Sobrien		     ? gen_addsi3 (tmp_reg,
1389790075Sobrien				   stack_limit_rtx,
1389890075Sobrien				   GEN_INT (size))
1389990075Sobrien		     : gen_adddi3 (tmp_reg,
1390090075Sobrien				   stack_limit_rtx,
1390190075Sobrien				   GEN_INT (size)));
13902132718Skan
1390390075Sobrien	  emit_insn (gen_cond_trap (LTU, stack_reg, tmp_reg,
1390490075Sobrien				    const0_rtx));
1390590075Sobrien	}
1390690075Sobrien      else if (GET_CODE (stack_limit_rtx) == SYMBOL_REF
1390790075Sobrien	       && TARGET_32BIT
1390890075Sobrien	       && DEFAULT_ABI == ABI_V4)
1390990075Sobrien	{
1391090075Sobrien	  rtx toload = gen_rtx_CONST (VOIDmode,
13911169689Skan				      gen_rtx_PLUS (Pmode,
13912169689Skan						    stack_limit_rtx,
1391390075Sobrien						    GEN_INT (size)));
13914132718Skan
1391590075Sobrien	  emit_insn (gen_elf_high (tmp_reg, toload));
1391690075Sobrien	  emit_insn (gen_elf_low (tmp_reg, tmp_reg, toload));
1391790075Sobrien	  emit_insn (gen_cond_trap (LTU, stack_reg, tmp_reg,
1391890075Sobrien				    const0_rtx));
1391990075Sobrien	}
1392090075Sobrien      else
13921169689Skan	warning (0, "stack limit expression is not supported");
1392290075Sobrien    }
1392390075Sobrien
1392490075Sobrien  if (copy_r12 || ! TARGET_UPDATE)
1392590075Sobrien    emit_move_insn (gen_rtx_REG (Pmode, 12), stack_reg);
1392690075Sobrien
1392790075Sobrien  if (TARGET_UPDATE)
1392890075Sobrien    {
1392990075Sobrien      if (size > 32767)
1393090075Sobrien	{
1393190075Sobrien	  /* Need a note here so that try_split doesn't get confused.  */
13932169689Skan	  if (get_last_insn () == NULL_RTX)
13933132718Skan	    emit_note (NOTE_INSN_DELETED);
1393490075Sobrien	  insn = emit_move_insn (tmp_reg, todec);
1393590075Sobrien	  try_split (PATTERN (insn), insn, 0);
1393690075Sobrien	  todec = tmp_reg;
1393790075Sobrien	}
13938132718Skan
13939132718Skan      insn = emit_insn (TARGET_32BIT
13940132718Skan			? gen_movsi_update (stack_reg, stack_reg,
13941132718Skan					    todec, stack_reg)
13942169689Skan			: gen_movdi_di_update (stack_reg, stack_reg,
1394390075Sobrien					    todec, stack_reg));
1394490075Sobrien    }
1394590075Sobrien  else
1394690075Sobrien    {
13947132718Skan      insn = emit_insn (TARGET_32BIT
13948132718Skan			? gen_addsi3 (stack_reg, stack_reg, todec)
13949132718Skan			: gen_adddi3 (stack_reg, stack_reg, todec));
1395090075Sobrien      emit_move_insn (gen_rtx_MEM (Pmode, stack_reg),
1395190075Sobrien		      gen_rtx_REG (Pmode, 12));
1395290075Sobrien    }
13953169689Skan
1395490075Sobrien  RTX_FRAME_RELATED_P (insn) = 1;
13955169689Skan  REG_NOTES (insn) =
1395690075Sobrien    gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
13957169689Skan		       gen_rtx_SET (VOIDmode, stack_reg,
1395890075Sobrien				    gen_rtx_PLUS (Pmode, stack_reg,
1395990075Sobrien						  GEN_INT (-size))),
1396090075Sobrien		       REG_NOTES (insn));
1396190075Sobrien}
1396290075Sobrien
1396390075Sobrien/* Add to 'insn' a note which is PATTERN (INSN) but with REG replaced
1396490075Sobrien   with (plus:P (reg 1) VAL), and with REG2 replaced with RREG if REG2
1396590075Sobrien   is not NULL.  It would be nice if dwarf2out_frame_debug_expr could
1396690075Sobrien   deduce these equivalences by itself so it wasn't necessary to hold
1396790075Sobrien   its hand so much.  */
1396890075Sobrien
1396990075Sobrienstatic void
13970169689Skanrs6000_frame_related (rtx insn, rtx reg, HOST_WIDE_INT val,
13971132718Skan		      rtx reg2, rtx rreg)
1397290075Sobrien{
1397390075Sobrien  rtx real, temp;
1397490075Sobrien
13975117395Skan  /* copy_rtx will not make unique copies of registers, so we need to
13976117395Skan     ensure we don't have unwanted sharing here.  */
13977117395Skan  if (reg == reg2)
13978117395Skan    reg = gen_raw_REG (GET_MODE (reg), REGNO (reg));
13979117395Skan
13980117395Skan  if (reg == rreg)
13981117395Skan    reg = gen_raw_REG (GET_MODE (reg), REGNO (reg));
13982117395Skan
1398390075Sobrien  real = copy_rtx (PATTERN (insn));
1398490075Sobrien
13985117395Skan  if (reg2 != NULL_RTX)
13986117395Skan    real = replace_rtx (real, reg2, rreg);
13987169689Skan
13988169689Skan  real = replace_rtx (real, reg,
1398990075Sobrien		      gen_rtx_PLUS (Pmode, gen_rtx_REG (Pmode,
1399090075Sobrien							STACK_POINTER_REGNUM),
1399190075Sobrien				    GEN_INT (val)));
13992169689Skan
1399390075Sobrien  /* We expect that 'real' is either a SET or a PARALLEL containing
1399490075Sobrien     SETs (and possibly other stuff).  In a PARALLEL, all the SETs
1399590075Sobrien     are important so they all have to be marked RTX_FRAME_RELATED_P.  */
1399690075Sobrien
1399790075Sobrien  if (GET_CODE (real) == SET)
1399890075Sobrien    {
1399990075Sobrien      rtx set = real;
14000169689Skan
1400190075Sobrien      temp = simplify_rtx (SET_SRC (set));
1400290075Sobrien      if (temp)
1400390075Sobrien	SET_SRC (set) = temp;
1400490075Sobrien      temp = simplify_rtx (SET_DEST (set));
1400590075Sobrien      if (temp)
1400690075Sobrien	SET_DEST (set) = temp;
1400790075Sobrien      if (GET_CODE (SET_DEST (set)) == MEM)
1400890075Sobrien	{
1400990075Sobrien	  temp = simplify_rtx (XEXP (SET_DEST (set), 0));
1401090075Sobrien	  if (temp)
1401190075Sobrien	    XEXP (SET_DEST (set), 0) = temp;
1401290075Sobrien	}
1401390075Sobrien    }
14014169689Skan  else
1401590075Sobrien    {
1401690075Sobrien      int i;
14017169689Skan
14018169689Skan      gcc_assert (GET_CODE (real) == PARALLEL);
1401990075Sobrien      for (i = 0; i < XVECLEN (real, 0); i++)
1402090075Sobrien	if (GET_CODE (XVECEXP (real, 0, i)) == SET)
1402190075Sobrien	  {
1402290075Sobrien	    rtx set = XVECEXP (real, 0, i);
14023169689Skan
1402490075Sobrien	    temp = simplify_rtx (SET_SRC (set));
1402590075Sobrien	    if (temp)
1402690075Sobrien	      SET_SRC (set) = temp;
1402790075Sobrien	    temp = simplify_rtx (SET_DEST (set));
1402890075Sobrien	    if (temp)
1402990075Sobrien	      SET_DEST (set) = temp;
1403090075Sobrien	    if (GET_CODE (SET_DEST (set)) == MEM)
1403190075Sobrien	      {
1403290075Sobrien		temp = simplify_rtx (XEXP (SET_DEST (set), 0));
1403390075Sobrien		if (temp)
1403490075Sobrien		  XEXP (SET_DEST (set), 0) = temp;
1403590075Sobrien	      }
1403690075Sobrien	    RTX_FRAME_RELATED_P (set) = 1;
1403790075Sobrien	  }
1403890075Sobrien    }
14039132718Skan
14040132718Skan  if (TARGET_SPE)
14041132718Skan    real = spe_synthesize_frame_save (real);
14042132718Skan
1404390075Sobrien  RTX_FRAME_RELATED_P (insn) = 1;
1404490075Sobrien  REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
1404590075Sobrien					real,
1404690075Sobrien					REG_NOTES (insn));
1404790075Sobrien}
1404890075Sobrien
14049132718Skan/* Given an SPE frame note, return a PARALLEL of SETs with the
14050132718Skan   original note, plus a synthetic register save.  */
14051132718Skan
14052132718Skanstatic rtx
14053132718Skanspe_synthesize_frame_save (rtx real)
14054132718Skan{
14055132718Skan  rtx synth, offset, reg, real2;
14056132718Skan
14057132718Skan  if (GET_CODE (real) != SET
14058132718Skan      || GET_MODE (SET_SRC (real)) != V2SImode)
14059132718Skan    return real;
14060132718Skan
14061132718Skan  /* For the SPE, registers saved in 64-bits, get a PARALLEL for their
14062132718Skan     frame related note.  The parallel contains a set of the register
14063132718Skan     being saved, and another set to a synthetic register (n+1200).
14064132718Skan     This is so we can differentiate between 64-bit and 32-bit saves.
14065132718Skan     Words cannot describe this nastiness.  */
14066132718Skan
14067169689Skan  gcc_assert (GET_CODE (SET_DEST (real)) == MEM
14068169689Skan	      && GET_CODE (XEXP (SET_DEST (real), 0)) == PLUS
14069169689Skan	      && GET_CODE (SET_SRC (real)) == REG);
14070132718Skan
14071132718Skan  /* Transform:
14072132718Skan       (set (mem (plus (reg x) (const y)))
14073132718Skan            (reg z))
14074132718Skan     into:
14075132718Skan       (set (mem (plus (reg x) (const y+4)))
14076132718Skan            (reg z+1200))
14077132718Skan  */
14078132718Skan
14079132718Skan  real2 = copy_rtx (real);
14080132718Skan  PUT_MODE (SET_DEST (real2), SImode);
14081132718Skan  reg = SET_SRC (real2);
14082132718Skan  real2 = replace_rtx (real2, reg, gen_rtx_REG (SImode, REGNO (reg)));
14083132718Skan  synth = copy_rtx (real2);
14084132718Skan
14085132718Skan  if (BYTES_BIG_ENDIAN)
14086132718Skan    {
14087132718Skan      offset = XEXP (XEXP (SET_DEST (real2), 0), 1);
14088132718Skan      real2 = replace_rtx (real2, offset, GEN_INT (INTVAL (offset) + 4));
14089132718Skan    }
14090132718Skan
14091132718Skan  reg = SET_SRC (synth);
14092132718Skan
14093132718Skan  synth = replace_rtx (synth, reg,
14094132718Skan		       gen_rtx_REG (SImode, REGNO (reg) + 1200));
14095132718Skan
14096132718Skan  offset = XEXP (XEXP (SET_DEST (synth), 0), 1);
14097132718Skan  synth = replace_rtx (synth, offset,
14098132718Skan		       GEN_INT (INTVAL (offset)
14099132718Skan				+ (BYTES_BIG_ENDIAN ? 0 : 4)));
14100132718Skan
14101132718Skan  RTX_FRAME_RELATED_P (synth) = 1;
14102132718Skan  RTX_FRAME_RELATED_P (real2) = 1;
14103132718Skan  if (BYTES_BIG_ENDIAN)
14104132718Skan    real = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, synth, real2));
14105132718Skan  else
14106132718Skan    real = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, real2, synth));
14107132718Skan
14108132718Skan  return real;
14109132718Skan}
14110132718Skan
1411190075Sobrien/* Returns an insn that has a vrsave set operation with the
1411290075Sobrien   appropriate CLOBBERs.  */
1411390075Sobrien
1411490075Sobrienstatic rtx
14115132718Skangenerate_set_vrsave (rtx reg, rs6000_stack_t *info, int epiloguep)
1411690075Sobrien{
1411790075Sobrien  int nclobs, i;
1411890075Sobrien  rtx insn, clobs[TOTAL_ALTIVEC_REGS + 1];
1411990075Sobrien  rtx vrsave = gen_rtx_REG (SImode, VRSAVE_REGNO);
1412090075Sobrien
1412190075Sobrien  clobs[0]
1412290075Sobrien    = gen_rtx_SET (VOIDmode,
1412390075Sobrien		   vrsave,
1412490075Sobrien		   gen_rtx_UNSPEC_VOLATILE (SImode,
1412590075Sobrien					    gen_rtvec (2, reg, vrsave),
14126169689Skan					    UNSPECV_SET_VRSAVE));
1412790075Sobrien
1412890075Sobrien  nclobs = 1;
1412990075Sobrien
1413090075Sobrien  /* We need to clobber the registers in the mask so the scheduler
1413190075Sobrien     does not move sets to VRSAVE before sets of AltiVec registers.
1413290075Sobrien
1413390075Sobrien     However, if the function receives nonlocal gotos, reload will set
1413490075Sobrien     all call saved registers live.  We will end up with:
1413590075Sobrien
1413690075Sobrien     	(set (reg 999) (mem))
1413790075Sobrien	(parallel [ (set (reg vrsave) (unspec blah))
1413890075Sobrien		    (clobber (reg 999))])
1413990075Sobrien
1414090075Sobrien     The clobber will cause the store into reg 999 to be dead, and
1414190075Sobrien     flow will attempt to delete an epilogue insn.  In this case, we
1414290075Sobrien     need an unspec use/set of the register.  */
1414390075Sobrien
1414490075Sobrien  for (i = FIRST_ALTIVEC_REGNO; i <= LAST_ALTIVEC_REGNO; ++i)
14145132718Skan    if (info->vrsave_mask & ALTIVEC_REG_BIT (i))
1414690075Sobrien      {
1414790075Sobrien	if (!epiloguep || call_used_regs [i])
1414890075Sobrien	  clobs[nclobs++] = gen_rtx_CLOBBER (VOIDmode,
1414990075Sobrien					     gen_rtx_REG (V4SImode, i));
1415090075Sobrien	else
1415190075Sobrien	  {
1415290075Sobrien	    rtx reg = gen_rtx_REG (V4SImode, i);
1415390075Sobrien
1415490075Sobrien	    clobs[nclobs++]
1415590075Sobrien	      = gen_rtx_SET (VOIDmode,
1415690075Sobrien			     reg,
1415790075Sobrien			     gen_rtx_UNSPEC (V4SImode,
1415890075Sobrien					     gen_rtvec (1, reg), 27));
1415990075Sobrien	  }
1416090075Sobrien      }
1416190075Sobrien
1416290075Sobrien  insn = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (nclobs));
1416390075Sobrien
1416490075Sobrien  for (i = 0; i < nclobs; ++i)
1416590075Sobrien    XVECEXP (insn, 0, i) = clobs[i];
1416690075Sobrien
1416790075Sobrien  return insn;
1416890075Sobrien}
1416990075Sobrien
14170117395Skan/* Save a register into the frame, and emit RTX_FRAME_RELATED_P notes.
14171117395Skan   Save REGNO into [FRAME_REG + OFFSET] in mode MODE.  */
14172117395Skan
14173117395Skanstatic void
14174169689Skanemit_frame_save (rtx frame_reg, rtx frame_ptr, enum machine_mode mode,
14175132718Skan		 unsigned int regno, int offset, HOST_WIDE_INT total_size)
14176117395Skan{
14177117395Skan  rtx reg, offset_rtx, insn, mem, addr, int_rtx;
14178117395Skan  rtx replacea, replaceb;
14179117395Skan
14180117395Skan  int_rtx = GEN_INT (offset);
14181117395Skan
14182117395Skan  /* Some cases that need register indexed addressing.  */
14183117395Skan  if ((TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
14184169689Skan      || (TARGET_E500_DOUBLE && mode == DFmode)
14185117395Skan      || (TARGET_SPE_ABI
14186117395Skan	  && SPE_VECTOR_MODE (mode)
14187117395Skan	  && !SPE_CONST_OFFSET_OK (offset)))
14188117395Skan    {
14189117395Skan      /* Whomever calls us must make sure r11 is available in the
14190169689Skan	 flow path of instructions in the prologue.  */
14191117395Skan      offset_rtx = gen_rtx_REG (Pmode, 11);
14192117395Skan      emit_move_insn (offset_rtx, int_rtx);
14193117395Skan
14194117395Skan      replacea = offset_rtx;
14195117395Skan      replaceb = int_rtx;
14196117395Skan    }
14197117395Skan  else
14198117395Skan    {
14199117395Skan      offset_rtx = int_rtx;
14200117395Skan      replacea = NULL_RTX;
14201117395Skan      replaceb = NULL_RTX;
14202117395Skan    }
14203117395Skan
14204117395Skan  reg = gen_rtx_REG (mode, regno);
14205117395Skan  addr = gen_rtx_PLUS (Pmode, frame_reg, offset_rtx);
14206169689Skan  mem = gen_frame_mem (mode, addr);
14207117395Skan
14208117395Skan  insn = emit_move_insn (mem, reg);
14209117395Skan
14210117395Skan  rs6000_frame_related (insn, frame_ptr, total_size, replacea, replaceb);
14211117395Skan}
14212117395Skan
14213117395Skan/* Emit an offset memory reference suitable for a frame store, while
14214117395Skan   converting to a valid addressing mode.  */
14215117395Skan
14216117395Skanstatic rtx
14217132718Skangen_frame_mem_offset (enum machine_mode mode, rtx reg, int offset)
14218117395Skan{
14219117395Skan  rtx int_rtx, offset_rtx;
14220117395Skan
14221117395Skan  int_rtx = GEN_INT (offset);
14222117395Skan
14223169689Skan  if ((TARGET_SPE_ABI && SPE_VECTOR_MODE (mode))
14224169689Skan      || (TARGET_E500_DOUBLE && mode == DFmode))
14225117395Skan    {
14226117395Skan      offset_rtx = gen_rtx_REG (Pmode, FIXED_SCRATCH);
14227117395Skan      emit_move_insn (offset_rtx, int_rtx);
14228117395Skan    }
14229117395Skan  else
14230117395Skan    offset_rtx = int_rtx;
14231117395Skan
14232169689Skan  return gen_frame_mem (mode, gen_rtx_PLUS (Pmode, reg, offset_rtx));
14233117395Skan}
14234117395Skan
14235169689Skan/* Look for user-defined global regs.  We should not save and restore these,
14236169689Skan   and cannot use stmw/lmw if there are any in its range.  */
14237169689Skan
14238169689Skanstatic bool
14239169689Skanno_global_regs_above (int first_greg)
14240169689Skan{
14241169689Skan  int i;
14242169689Skan  for (i = 0; i < 32 - first_greg; i++)
14243169689Skan    if (global_regs[first_greg + i])
14244169689Skan      return false;
14245169689Skan  return true;
14246169689Skan}
14247169689Skan
14248169689Skan#ifndef TARGET_FIX_AND_CONTINUE
14249169689Skan#define TARGET_FIX_AND_CONTINUE 0
14250169689Skan#endif
14251169689Skan
1425290075Sobrien/* Emit function prologue as insns.  */
1425390075Sobrien
1425490075Sobrienvoid
14255132718Skanrs6000_emit_prologue (void)
1425690075Sobrien{
1425790075Sobrien  rs6000_stack_t *info = rs6000_stack_info ();
14258132718Skan  enum machine_mode reg_mode = Pmode;
14259132718Skan  int reg_size = TARGET_32BIT ? 4 : 8;
1426090075Sobrien  rtx sp_reg_rtx = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
1426190075Sobrien  rtx frame_ptr_rtx = gen_rtx_REG (Pmode, 12);
1426290075Sobrien  rtx frame_reg_rtx = sp_reg_rtx;
14263132718Skan  rtx cr_save_rtx = NULL_RTX;
1426490075Sobrien  rtx insn;
1426590075Sobrien  int saving_FPRs_inline;
1426690075Sobrien  int using_store_multiple;
1426790075Sobrien  HOST_WIDE_INT sp_offset = 0;
14268117395Skan
14269169689Skan  if (TARGET_FIX_AND_CONTINUE)
14270169689Skan    {
14271169689Skan      /* gdb on darwin arranges to forward a function from the old
14272169689Skan	 address by modifying the first 5 instructions of the function
14273169689Skan	 to branch to the overriding function.  This is necessary to
14274169689Skan	 permit function pointers that point to the old function to
14275169689Skan	 actually forward to the new function.  */
14276169689Skan      emit_insn (gen_nop ());
14277169689Skan      emit_insn (gen_nop ());
14278169689Skan      emit_insn (gen_nop ());
14279169689Skan      emit_insn (gen_nop ());
14280169689Skan      emit_insn (gen_nop ());
14281169689Skan    }
14282169689Skan
14283169689Skan  if (TARGET_SPE_ABI && info->spe_64bit_regs_used != 0)
14284169689Skan    {
14285169689Skan      reg_mode = V2SImode;
14286169689Skan      reg_size = 8;
14287169689Skan    }
14288169689Skan
1428990075Sobrien  using_store_multiple = (TARGET_MULTIPLE && ! TARGET_POWERPC64
14290132718Skan			  && (!TARGET_SPE_ABI
14291132718Skan			      || info->spe_64bit_regs_used == 0)
14292169689Skan			  && info->first_gp_reg_save < 31
14293169689Skan			  && no_global_regs_above (info->first_gp_reg_save));
1429490075Sobrien  saving_FPRs_inline = (info->first_fp_reg_save == 64
14295132718Skan			|| FP_SAVE_INLINE (info->first_fp_reg_save)
14296132718Skan			|| current_function_calls_eh_return
14297132718Skan			|| cfun->machine->ra_need_lr);
1429890075Sobrien
1429990075Sobrien  /* For V.4, update stack before we do any saving and set back pointer.  */
14300169689Skan  if (! WORLD_SAVE_P (info)
14301169689Skan      && info->push_p
14302132718Skan      && (DEFAULT_ABI == ABI_V4
14303132718Skan	  || current_function_calls_eh_return))
1430490075Sobrien    {
1430590075Sobrien      if (info->total_size < 32767)
1430690075Sobrien	sp_offset = info->total_size;
1430790075Sobrien      else
1430890075Sobrien	frame_reg_rtx = frame_ptr_rtx;
14309169689Skan      rs6000_emit_allocate_stack (info->total_size,
1431090075Sobrien				  (frame_reg_rtx != sp_reg_rtx
1431190075Sobrien				   && (info->cr_save_p
1431290075Sobrien				       || info->lr_save_p
1431390075Sobrien				       || info->first_fp_reg_save < 64
1431490075Sobrien				       || info->first_gp_reg_save < 32
1431590075Sobrien				       )));
1431690075Sobrien      if (frame_reg_rtx != sp_reg_rtx)
1431790075Sobrien	rs6000_emit_stack_tie ();
1431890075Sobrien    }
1431990075Sobrien
14320169689Skan  /* Handle world saves specially here.  */
14321169689Skan  if (WORLD_SAVE_P (info))
14322169689Skan    {
14323169689Skan      int i, j, sz;
14324169689Skan      rtx treg;
14325169689Skan      rtvec p;
14326169689Skan      rtx reg0;
14327169689Skan
14328169689Skan      /* save_world expects lr in r0. */
14329169689Skan      reg0 = gen_rtx_REG (Pmode, 0);
14330169689Skan      if (info->lr_save_p)
14331169689Skan	{
14332169689Skan	  insn = emit_move_insn (reg0,
14333169689Skan				 gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM));
14334169689Skan	  RTX_FRAME_RELATED_P (insn) = 1;
14335169689Skan	}
14336169689Skan
14337169689Skan      /* The SAVE_WORLD and RESTORE_WORLD routines make a number of
14338169689Skan	 assumptions about the offsets of various bits of the stack
14339169689Skan	 frame.  */
14340169689Skan      gcc_assert (info->gp_save_offset == -220
14341169689Skan		  && info->fp_save_offset == -144
14342169689Skan		  && info->lr_save_offset == 8
14343169689Skan		  && info->cr_save_offset == 4
14344169689Skan		  && info->push_p
14345169689Skan		  && info->lr_save_p
14346169689Skan		  && (!current_function_calls_eh_return
14347169689Skan		       || info->ehrd_offset == -432)
14348169689Skan		  && info->vrsave_save_offset == -224
14349169689Skan		  && info->altivec_save_offset == -416);
14350169689Skan
14351169689Skan      treg = gen_rtx_REG (SImode, 11);
14352169689Skan      emit_move_insn (treg, GEN_INT (-info->total_size));
14353169689Skan
14354169689Skan      /* SAVE_WORLD takes the caller's LR in R0 and the frame size
14355169689Skan	 in R11.  It also clobbers R12, so beware!  */
14356169689Skan
14357169689Skan      /* Preserve CR2 for save_world prologues */
14358169689Skan      sz = 5;
14359169689Skan      sz += 32 - info->first_gp_reg_save;
14360169689Skan      sz += 64 - info->first_fp_reg_save;
14361169689Skan      sz += LAST_ALTIVEC_REGNO - info->first_altivec_reg_save + 1;
14362169689Skan      p = rtvec_alloc (sz);
14363169689Skan      j = 0;
14364169689Skan      RTVEC_ELT (p, j++) = gen_rtx_CLOBBER (VOIDmode,
14365169689Skan					    gen_rtx_REG (Pmode,
14366169689Skan							 LINK_REGISTER_REGNUM));
14367169689Skan      RTVEC_ELT (p, j++) = gen_rtx_USE (VOIDmode,
14368169689Skan					gen_rtx_SYMBOL_REF (Pmode,
14369169689Skan							    "*save_world"));
14370169689Skan      /* We do floats first so that the instruction pattern matches
14371169689Skan	 properly.  */
14372169689Skan      for (i = 0; i < 64 - info->first_fp_reg_save; i++)
14373169689Skan	{
14374169689Skan	  rtx reg = gen_rtx_REG (DFmode, info->first_fp_reg_save + i);
14375169689Skan	  rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
14376169689Skan				   GEN_INT (info->fp_save_offset
14377169689Skan					    + sp_offset + 8 * i));
14378169689Skan	  rtx mem = gen_frame_mem (DFmode, addr);
14379169689Skan
14380169689Skan	  RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg);
14381169689Skan	}
14382169689Skan      for (i = 0; info->first_altivec_reg_save + i <= LAST_ALTIVEC_REGNO; i++)
14383169689Skan	{
14384169689Skan	  rtx reg = gen_rtx_REG (V4SImode, info->first_altivec_reg_save + i);
14385169689Skan	  rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
14386169689Skan				   GEN_INT (info->altivec_save_offset
14387169689Skan					    + sp_offset + 16 * i));
14388169689Skan	  rtx mem = gen_frame_mem (V4SImode, addr);
14389169689Skan
14390169689Skan	  RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg);
14391169689Skan	}
14392169689Skan      for (i = 0; i < 32 - info->first_gp_reg_save; i++)
14393169689Skan	{
14394169689Skan	  rtx reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
14395169689Skan	  rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
14396169689Skan				   GEN_INT (info->gp_save_offset
14397169689Skan					    + sp_offset + reg_size * i));
14398169689Skan	  rtx mem = gen_frame_mem (reg_mode, addr);
14399169689Skan
14400169689Skan	  RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg);
14401169689Skan	}
14402169689Skan
14403169689Skan      {
14404169689Skan	/* CR register traditionally saved as CR2.  */
14405169689Skan	rtx reg = gen_rtx_REG (reg_mode, CR2_REGNO);
14406169689Skan	rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
14407169689Skan				 GEN_INT (info->cr_save_offset
14408169689Skan					  + sp_offset));
14409169689Skan	rtx mem = gen_frame_mem (reg_mode, addr);
14410169689Skan
14411169689Skan	RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg);
14412169689Skan      }
14413169689Skan      /* Explain about use of R0.  */
14414169689Skan      if (info->lr_save_p)
14415169689Skan	{
14416169689Skan	  rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
14417169689Skan				   GEN_INT (info->lr_save_offset
14418169689Skan					    + sp_offset));
14419169689Skan	  rtx mem = gen_frame_mem (reg_mode, addr);
14420169689Skan
14421169689Skan	  RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg0);
14422169689Skan	}
14423169689Skan      /* Explain what happens to the stack pointer.  */
14424169689Skan      {
14425169689Skan	rtx newval = gen_rtx_PLUS (Pmode, sp_reg_rtx, treg);
14426169689Skan	RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, sp_reg_rtx, newval);
14427169689Skan      }
14428169689Skan
14429169689Skan      insn = emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
14430169689Skan      rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
14431169689Skan			    treg, GEN_INT (-info->total_size));
14432169689Skan      sp_offset = info->total_size;
14433169689Skan    }
14434169689Skan
1443590075Sobrien  /* Save AltiVec registers if needed.  */
14436169689Skan  if (!WORLD_SAVE_P (info) && TARGET_ALTIVEC_ABI && info->altivec_size != 0)
1443790075Sobrien    {
1443890075Sobrien      int i;
1443990075Sobrien
1444090075Sobrien      /* There should be a non inline version of this, for when we
1444190075Sobrien	 are saving lots of vector registers.  */
1444290075Sobrien      for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i)
1444390075Sobrien	if (info->vrsave_mask & ALTIVEC_REG_BIT (i))
1444490075Sobrien	  {
1444590075Sobrien	    rtx areg, savereg, mem;
1444690075Sobrien	    int offset;
1444790075Sobrien
1444890075Sobrien	    offset = info->altivec_save_offset + sp_offset
1444990075Sobrien	      + 16 * (i - info->first_altivec_reg_save);
1445090075Sobrien
1445190075Sobrien	    savereg = gen_rtx_REG (V4SImode, i);
1445290075Sobrien
1445390075Sobrien	    areg = gen_rtx_REG (Pmode, 0);
1445490075Sobrien	    emit_move_insn (areg, GEN_INT (offset));
1445590075Sobrien
1445690075Sobrien	    /* AltiVec addressing mode is [reg+reg].  */
14457169689Skan	    mem = gen_frame_mem (V4SImode,
14458169689Skan				 gen_rtx_PLUS (Pmode, frame_reg_rtx, areg));
1445990075Sobrien
1446090075Sobrien	    insn = emit_move_insn (mem, savereg);
1446190075Sobrien
14462132718Skan	    rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
14463132718Skan				  areg, GEN_INT (offset));
1446490075Sobrien	  }
1446590075Sobrien    }
1446690075Sobrien
1446790075Sobrien  /* VRSAVE is a bit vector representing which AltiVec registers
1446890075Sobrien     are used.  The OS uses this to determine which vector
1446990075Sobrien     registers to save on a context switch.  We need to save
1447090075Sobrien     VRSAVE on the stack frame, add whatever AltiVec registers we
1447190075Sobrien     used in this function, and do the corresponding magic in the
1447290075Sobrien     epilogue.  */
1447390075Sobrien
14474132718Skan  if (TARGET_ALTIVEC && TARGET_ALTIVEC_VRSAVE
14475132718Skan      && info->vrsave_mask != 0)
1447690075Sobrien    {
1447790075Sobrien      rtx reg, mem, vrsave;
1447890075Sobrien      int offset;
1447990075Sobrien
14480146895Skan      /* Get VRSAVE onto a GPR.  Note that ABI_V4 might be using r12
14481146895Skan	 as frame_reg_rtx and r11 as the static chain pointer for
14482146895Skan	 nested functions.  */
14483146895Skan      reg = gen_rtx_REG (SImode, 0);
1448490075Sobrien      vrsave = gen_rtx_REG (SImode, VRSAVE_REGNO);
1448596263Sobrien      if (TARGET_MACHO)
1448696263Sobrien	emit_insn (gen_get_vrsave_internal (reg));
1448796263Sobrien      else
1448896263Sobrien	emit_insn (gen_rtx_SET (VOIDmode, reg, vrsave));
1448990075Sobrien
14490169689Skan      if (!WORLD_SAVE_P (info))
14491169689Skan	{
14492169689Skan          /* Save VRSAVE.  */
14493169689Skan          offset = info->vrsave_save_offset + sp_offset;
14494169689Skan          mem = gen_frame_mem (SImode,
14495169689Skan			       gen_rtx_PLUS (Pmode, frame_reg_rtx,
14496169689Skan					     GEN_INT (offset)));
14497169689Skan          insn = emit_move_insn (mem, reg);
14498169689Skan	}
1449990075Sobrien
1450090075Sobrien      /* Include the registers in the mask.  */
1450190075Sobrien      emit_insn (gen_iorsi3 (reg, reg, GEN_INT ((int) info->vrsave_mask)));
1450290075Sobrien
1450390075Sobrien      insn = emit_insn (generate_set_vrsave (reg, info, 0));
1450490075Sobrien    }
1450590075Sobrien
1450690075Sobrien  /* If we use the link register, get it into r0.  */
14507169689Skan  if (!WORLD_SAVE_P (info) && info->lr_save_p)
14508169689Skan    {
14509169689Skan      insn = emit_move_insn (gen_rtx_REG (Pmode, 0),
14510169689Skan			     gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM));
14511169689Skan      RTX_FRAME_RELATED_P (insn) = 1;
14512169689Skan    }
1451390075Sobrien
1451490075Sobrien  /* If we need to save CR, put it into r12.  */
14515169689Skan  if (!WORLD_SAVE_P (info) && info->cr_save_p && frame_reg_rtx != frame_ptr_rtx)
1451690075Sobrien    {
14517169689Skan      rtx set;
14518169689Skan
1451990075Sobrien      cr_save_rtx = gen_rtx_REG (SImode, 12);
14520169689Skan      insn = emit_insn (gen_movesi_from_cr (cr_save_rtx));
14521169689Skan      RTX_FRAME_RELATED_P (insn) = 1;
14522169689Skan      /* Now, there's no way that dwarf2out_frame_debug_expr is going
14523169689Skan	 to understand '(unspec:SI [(reg:CC 68) ...] UNSPEC_MOVESI_FROM_CR)'.
14524169689Skan	 But that's OK.  All we have to do is specify that _one_ condition
14525169689Skan	 code register is saved in this stack slot.  The thrower's epilogue
14526169689Skan	 will then restore all the call-saved registers.
14527169689Skan	 We use CR2_REGNO (70) to be compatible with gcc-2.95 on Linux.  */
14528169689Skan      set = gen_rtx_SET (VOIDmode, cr_save_rtx,
14529169689Skan			 gen_rtx_REG (SImode, CR2_REGNO));
14530169689Skan      REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
14531169689Skan					    set,
14532169689Skan					    REG_NOTES (insn));
1453390075Sobrien    }
1453490075Sobrien
1453590075Sobrien  /* Do any required saving of fpr's.  If only one or two to save, do
1453690075Sobrien     it ourselves.  Otherwise, call function.  */
14537169689Skan  if (!WORLD_SAVE_P (info) && saving_FPRs_inline)
1453890075Sobrien    {
1453990075Sobrien      int i;
1454090075Sobrien      for (i = 0; i < 64 - info->first_fp_reg_save; i++)
14541169689Skan	if ((regs_ever_live[info->first_fp_reg_save+i]
1454290075Sobrien	     && ! call_used_regs[info->first_fp_reg_save+i]))
14543117395Skan	  emit_frame_save (frame_reg_rtx, frame_ptr_rtx, DFmode,
14544117395Skan			   info->first_fp_reg_save + i,
14545117395Skan			   info->fp_save_offset + sp_offset + 8 * i,
14546117395Skan			   info->total_size);
1454790075Sobrien    }
14548169689Skan  else if (!WORLD_SAVE_P (info) && info->first_fp_reg_save != 64)
1454990075Sobrien    {
1455090075Sobrien      int i;
1455190075Sobrien      char rname[30];
1455290075Sobrien      const char *alloc_rname;
1455390075Sobrien      rtvec p;
1455490075Sobrien      p = rtvec_alloc (2 + 64 - info->first_fp_reg_save);
14555169689Skan
14556169689Skan      RTVEC_ELT (p, 0) = gen_rtx_CLOBBER (VOIDmode,
14557169689Skan					  gen_rtx_REG (Pmode,
1455890075Sobrien						       LINK_REGISTER_REGNUM));
1455990075Sobrien      sprintf (rname, "%s%d%s", SAVE_FP_PREFIX,
1456090075Sobrien	       info->first_fp_reg_save - 32, SAVE_FP_SUFFIX);
1456190075Sobrien      alloc_rname = ggc_strdup (rname);
1456290075Sobrien      RTVEC_ELT (p, 1) = gen_rtx_USE (VOIDmode,
1456390075Sobrien				      gen_rtx_SYMBOL_REF (Pmode,
1456490075Sobrien							  alloc_rname));
1456590075Sobrien      for (i = 0; i < 64 - info->first_fp_reg_save; i++)
1456690075Sobrien	{
1456790075Sobrien	  rtx addr, reg, mem;
1456890075Sobrien	  reg = gen_rtx_REG (DFmode, info->first_fp_reg_save + i);
1456990075Sobrien	  addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
14570169689Skan			       GEN_INT (info->fp_save_offset
1457190075Sobrien					+ sp_offset + 8*i));
14572169689Skan	  mem = gen_frame_mem (DFmode, addr);
1457390075Sobrien
1457490075Sobrien	  RTVEC_ELT (p, i + 2) = gen_rtx_SET (VOIDmode, mem, reg);
1457590075Sobrien	}
1457690075Sobrien      insn = emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
14577169689Skan      rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
1457890075Sobrien			    NULL_RTX, NULL_RTX);
1457990075Sobrien    }
1458090075Sobrien
1458190075Sobrien  /* Save GPRs.  This is done as a PARALLEL if we are using
1458290075Sobrien     the store-multiple instructions.  */
14583169689Skan  if (!WORLD_SAVE_P (info) && using_store_multiple)
1458490075Sobrien    {
14585117395Skan      rtvec p;
1458690075Sobrien      int i;
1458790075Sobrien      p = rtvec_alloc (32 - info->first_gp_reg_save);
1458890075Sobrien      for (i = 0; i < 32 - info->first_gp_reg_save; i++)
1458990075Sobrien	{
1459090075Sobrien	  rtx addr, reg, mem;
1459190075Sobrien	  reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
14592169689Skan	  addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
14593169689Skan			       GEN_INT (info->gp_save_offset
14594169689Skan					+ sp_offset
1459590075Sobrien					+ reg_size * i));
14596169689Skan	  mem = gen_frame_mem (reg_mode, addr);
1459790075Sobrien
1459890075Sobrien	  RTVEC_ELT (p, i) = gen_rtx_SET (VOIDmode, mem, reg);
1459990075Sobrien	}
1460090075Sobrien      insn = emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
14601169689Skan      rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
1460290075Sobrien			    NULL_RTX, NULL_RTX);
1460390075Sobrien    }
14604169689Skan  else if (!WORLD_SAVE_P (info))
1460590075Sobrien    {
1460690075Sobrien      int i;
1460790075Sobrien      for (i = 0; i < 32 - info->first_gp_reg_save; i++)
14608169689Skan	if ((regs_ever_live[info->first_gp_reg_save + i]
14609169689Skan	     && (!call_used_regs[info->first_gp_reg_save + i]
14610169689Skan		 || (i + info->first_gp_reg_save
14611146895Skan		     == RS6000_PIC_OFFSET_TABLE_REGNUM
14612146895Skan		     && TARGET_TOC && TARGET_MINIMAL_TOC)))
14613169689Skan	    || (i + info->first_gp_reg_save == RS6000_PIC_OFFSET_TABLE_REGNUM
14614117395Skan		&& ((DEFAULT_ABI == ABI_V4 && flag_pic != 0)
1461590075Sobrien		    || (DEFAULT_ABI == ABI_DARWIN && flag_pic))))
1461690075Sobrien	  {
1461790075Sobrien	    rtx addr, reg, mem;
1461890075Sobrien	    reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
1461990075Sobrien
14620132718Skan	    if (TARGET_SPE_ABI && info->spe_64bit_regs_used != 0)
14621117395Skan	      {
14622117395Skan		int offset = info->spe_gp_save_offset + sp_offset + 8 * i;
14623117395Skan		rtx b;
14624117395Skan
14625117395Skan		if (!SPE_CONST_OFFSET_OK (offset))
14626117395Skan		  {
14627117395Skan		    b = gen_rtx_REG (Pmode, FIXED_SCRATCH);
14628117395Skan		    emit_move_insn (b, GEN_INT (offset));
14629117395Skan		  }
14630117395Skan		else
14631117395Skan		  b = GEN_INT (offset);
14632117395Skan
14633117395Skan		addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, b);
14634169689Skan		mem = gen_frame_mem (V2SImode, addr);
14635117395Skan		insn = emit_move_insn (mem, reg);
14636117395Skan
14637117395Skan		if (GET_CODE (b) == CONST_INT)
14638117395Skan		  rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
14639117395Skan					NULL_RTX, NULL_RTX);
14640117395Skan		else
14641117395Skan		  rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
14642117395Skan					b, GEN_INT (offset));
14643117395Skan	      }
14644117395Skan	    else
14645117395Skan	      {
14646169689Skan		addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
14647169689Skan				     GEN_INT (info->gp_save_offset
14648169689Skan					      + sp_offset
14649117395Skan					      + reg_size * i));
14650169689Skan		mem = gen_frame_mem (reg_mode, addr);
14651117395Skan
14652117395Skan		insn = emit_move_insn (mem, reg);
14653169689Skan		rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
14654117395Skan				      NULL_RTX, NULL_RTX);
14655117395Skan	      }
1465690075Sobrien	  }
1465790075Sobrien    }
1465890075Sobrien
1465990075Sobrien  /* ??? There's no need to emit actual instructions here, but it's the
1466090075Sobrien     easiest way to get the frame unwind information emitted.  */
1466190075Sobrien  if (current_function_calls_eh_return)
1466290075Sobrien    {
1466390075Sobrien      unsigned int i, regno;
1466490075Sobrien
14665132718Skan      /* In AIX ABI we need to pretend we save r2 here.  */
14666132718Skan      if (TARGET_AIX)
14667132718Skan	{
14668132718Skan	  rtx addr, reg, mem;
14669132718Skan
14670132718Skan	  reg = gen_rtx_REG (reg_mode, 2);
14671132718Skan	  addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
14672132718Skan			       GEN_INT (sp_offset + 5 * reg_size));
14673169689Skan	  mem = gen_frame_mem (reg_mode, addr);
14674132718Skan
14675132718Skan	  insn = emit_move_insn (mem, reg);
14676169689Skan	  rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
14677132718Skan				NULL_RTX, NULL_RTX);
14678132718Skan	  PATTERN (insn) = gen_blockage ();
14679132718Skan	}
14680132718Skan
1468190075Sobrien      for (i = 0; ; ++i)
1468290075Sobrien	{
1468390075Sobrien	  regno = EH_RETURN_DATA_REGNO (i);
1468490075Sobrien	  if (regno == INVALID_REGNUM)
1468590075Sobrien	    break;
1468690075Sobrien
14687117395Skan	  emit_frame_save (frame_reg_rtx, frame_ptr_rtx, reg_mode, regno,
14688117395Skan			   info->ehrd_offset + sp_offset
14689117395Skan			   + reg_size * (int) i,
14690117395Skan			   info->total_size);
1469190075Sobrien	}
1469290075Sobrien    }
1469390075Sobrien
1469490075Sobrien  /* Save lr if we used it.  */
14695169689Skan  if (!WORLD_SAVE_P (info) && info->lr_save_p)
1469690075Sobrien    {
1469790075Sobrien      rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
1469890075Sobrien			       GEN_INT (info->lr_save_offset + sp_offset));
1469990075Sobrien      rtx reg = gen_rtx_REG (Pmode, 0);
1470090075Sobrien      rtx mem = gen_rtx_MEM (Pmode, addr);
14701169689Skan      /* This should not be of frame_alias_set, because of
1470290075Sobrien	 __builtin_return_address.  */
14703169689Skan
1470490075Sobrien      insn = emit_move_insn (mem, reg);
14705169689Skan      rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
14706169689Skan			    NULL_RTX, NULL_RTX);
1470790075Sobrien    }
1470890075Sobrien
1470990075Sobrien  /* Save CR if we use any that must be preserved.  */
14710169689Skan  if (!WORLD_SAVE_P (info) && info->cr_save_p)
1471190075Sobrien    {
1471290075Sobrien      rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
1471390075Sobrien			       GEN_INT (info->cr_save_offset + sp_offset));
14714169689Skan      rtx mem = gen_frame_mem (SImode, addr);
14715169689Skan      /* See the large comment above about why CR2_REGNO is used.  */
14716169689Skan      rtx magic_eh_cr_reg = gen_rtx_REG (SImode, CR2_REGNO);
1471790075Sobrien
1471890075Sobrien      /* If r12 was used to hold the original sp, copy cr into r0 now
1471990075Sobrien	 that it's free.  */
1472090075Sobrien      if (REGNO (frame_reg_rtx) == 12)
1472190075Sobrien	{
14722169689Skan	  rtx set;
14723169689Skan
1472490075Sobrien	  cr_save_rtx = gen_rtx_REG (SImode, 0);
14725169689Skan	  insn = emit_insn (gen_movesi_from_cr (cr_save_rtx));
14726169689Skan	  RTX_FRAME_RELATED_P (insn) = 1;
14727169689Skan	  set = gen_rtx_SET (VOIDmode, cr_save_rtx, magic_eh_cr_reg);
14728169689Skan	  REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
14729169689Skan						set,
14730169689Skan						REG_NOTES (insn));
14731169689Skan
1473290075Sobrien	}
1473390075Sobrien      insn = emit_move_insn (mem, cr_save_rtx);
1473490075Sobrien
14735169689Skan      rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
14736169689Skan			    NULL_RTX, NULL_RTX);
1473790075Sobrien    }
1473890075Sobrien
14739169689Skan  /* Update stack and set back pointer unless this is V.4,
1474090075Sobrien     for which it was done previously.  */
14741169689Skan  if (!WORLD_SAVE_P (info) && info->push_p
14742132718Skan      && !(DEFAULT_ABI == ABI_V4 || current_function_calls_eh_return))
1474390075Sobrien    rs6000_emit_allocate_stack (info->total_size, FALSE);
1474490075Sobrien
1474590075Sobrien  /* Set frame pointer, if needed.  */
1474690075Sobrien  if (frame_pointer_needed)
1474790075Sobrien    {
14748169689Skan      insn = emit_move_insn (gen_rtx_REG (Pmode, HARD_FRAME_POINTER_REGNUM),
1474990075Sobrien			     sp_reg_rtx);
1475090075Sobrien      RTX_FRAME_RELATED_P (insn) = 1;
1475190075Sobrien    }
1475290075Sobrien
1475396263Sobrien  /* If we are using RS6000_PIC_OFFSET_TABLE_REGNUM, we need to set it up.  */
1475490075Sobrien  if ((TARGET_TOC && TARGET_MINIMAL_TOC && get_pool_size () != 0)
14755169689Skan      || (DEFAULT_ABI == ABI_V4
14756169689Skan	  && (flag_pic == 1 || (flag_pic && TARGET_SECURE_PLT))
1475796263Sobrien	  && regs_ever_live[RS6000_PIC_OFFSET_TABLE_REGNUM]))
14758169689Skan    {
14759169689Skan      /* If emit_load_toc_table will use the link register, we need to save
14760169689Skan	 it.  We use R12 for this purpose because emit_load_toc_table
14761169689Skan	 can use register 0.  This allows us to use a plain 'blr' to return
14762169689Skan	 from the procedure more often.  */
14763169689Skan      int save_LR_around_toc_setup = (TARGET_ELF
14764169689Skan				      && DEFAULT_ABI != ABI_AIX
14765169689Skan				      && flag_pic
14766169689Skan				      && ! info->lr_save_p
14767169689Skan				      && EDGE_COUNT (EXIT_BLOCK_PTR->preds) > 0);
14768169689Skan      if (save_LR_around_toc_setup)
14769169689Skan	{
14770169689Skan	  rtx lr = gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM);
14771169689Skan
14772169689Skan	  insn = emit_move_insn (frame_ptr_rtx, lr);
14773169689Skan	  rs6000_maybe_dead (insn);
14774169689Skan	  RTX_FRAME_RELATED_P (insn) = 1;
14775169689Skan
14776169689Skan	  rs6000_emit_load_toc_table (TRUE);
14777169689Skan
14778169689Skan	  insn = emit_move_insn (lr, frame_ptr_rtx);
14779169689Skan	  rs6000_maybe_dead (insn);
14780169689Skan	  RTX_FRAME_RELATED_P (insn) = 1;
14781169689Skan	}
14782169689Skan      else
14783132718Skan	rs6000_emit_load_toc_table (TRUE);
14784169689Skan    }
1478590075Sobrien
14786117395Skan#if TARGET_MACHO
1478790075Sobrien  if (DEFAULT_ABI == ABI_DARWIN
1478890075Sobrien      && flag_pic && current_function_uses_pic_offset_table)
1478990075Sobrien    {
14790169689Skan      rtx lr = gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM);
14791169689Skan      rtx src = machopic_function_base_sym ();
1479290075Sobrien
14793169689Skan      /* Save and restore LR locally around this call (in R0).  */
14794169689Skan      if (!info->lr_save_p)
14795169689Skan	rs6000_maybe_dead (emit_move_insn (gen_rtx_REG (Pmode, 0), lr));
1479690075Sobrien
14797169689Skan      rs6000_maybe_dead (emit_insn (gen_load_macho_picbase (lr, src)));
14798169689Skan
14799169689Skan      insn = emit_move_insn (gen_rtx_REG (Pmode,
14800169689Skan					  RS6000_PIC_OFFSET_TABLE_REGNUM),
14801169689Skan			     lr);
14802169689Skan      rs6000_maybe_dead (insn);
14803169689Skan
14804169689Skan      if (!info->lr_save_p)
14805169689Skan	rs6000_maybe_dead (emit_move_insn (lr, gen_rtx_REG (Pmode, 0)));
1480690075Sobrien    }
14807117395Skan#endif
1480890075Sobrien}
1480990075Sobrien
1481090075Sobrien/* Write function prologue.  */
1481190075Sobrien
1481290075Sobrienstatic void
14813169689Skanrs6000_output_function_prologue (FILE *file,
14814132718Skan				 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
1481590075Sobrien{
1481690075Sobrien  rs6000_stack_t *info = rs6000_stack_info ();
1481790075Sobrien
1481890075Sobrien  if (TARGET_DEBUG_STACK)
1481990075Sobrien    debug_stack_info (info);
1482090075Sobrien
1482190075Sobrien  /* Write .extern for any function we will call to save and restore
1482290075Sobrien     fp values.  */
1482390075Sobrien  if (info->first_fp_reg_save < 64
1482490075Sobrien      && !FP_SAVE_INLINE (info->first_fp_reg_save))
1482590075Sobrien    fprintf (file, "\t.extern %s%d%s\n\t.extern %s%d%s\n",
1482690075Sobrien	     SAVE_FP_PREFIX, info->first_fp_reg_save - 32, SAVE_FP_SUFFIX,
1482790075Sobrien	     RESTORE_FP_PREFIX, info->first_fp_reg_save - 32,
1482890075Sobrien	     RESTORE_FP_SUFFIX);
1482990075Sobrien
1483090075Sobrien  /* Write .extern for AIX common mode routines, if needed.  */
1483190075Sobrien  if (! TARGET_POWER && ! TARGET_POWERPC && ! common_mode_defined)
1483290075Sobrien    {
1483390075Sobrien      fputs ("\t.extern __mulh\n", file);
1483490075Sobrien      fputs ("\t.extern __mull\n", file);
1483590075Sobrien      fputs ("\t.extern __divss\n", file);
1483690075Sobrien      fputs ("\t.extern __divus\n", file);
1483790075Sobrien      fputs ("\t.extern __quoss\n", file);
1483890075Sobrien      fputs ("\t.extern __quous\n", file);
1483990075Sobrien      common_mode_defined = 1;
1484090075Sobrien    }
1484190075Sobrien
1484290075Sobrien  if (! HAVE_prologue)
1484390075Sobrien    {
1484490075Sobrien      start_sequence ();
1484596263Sobrien
1484690075Sobrien      /* A NOTE_INSN_DELETED is supposed to be at the start and end of
1484790075Sobrien	 the "toplevel" insn chain.  */
14848132718Skan      emit_note (NOTE_INSN_DELETED);
1484990075Sobrien      rs6000_emit_prologue ();
14850132718Skan      emit_note (NOTE_INSN_DELETED);
1485196263Sobrien
14852132718Skan      /* Expand INSN_ADDRESSES so final() doesn't crash.  */
1485396263Sobrien      {
1485496263Sobrien	rtx insn;
1485596263Sobrien	unsigned addr = 0;
1485696263Sobrien	for (insn = get_insns (); insn != 0; insn = NEXT_INSN (insn))
1485796263Sobrien	  {
1485896263Sobrien	    INSN_ADDRESSES_NEW (insn, addr);
1485996263Sobrien	    addr += 4;
1486096263Sobrien	  }
1486196263Sobrien      }
1486296263Sobrien
1486390075Sobrien      if (TARGET_DEBUG_STACK)
1486490075Sobrien	debug_rtx_list (get_insns (), 100);
14865169689Skan      final (get_insns (), file, FALSE);
1486690075Sobrien      end_sequence ();
1486790075Sobrien    }
1486890075Sobrien
1486990075Sobrien  rs6000_pic_labelno++;
1487090075Sobrien}
14871169689Skan
1487290075Sobrien/* Emit function epilogue as insns.
1487390075Sobrien
1487490075Sobrien   At present, dwarf2out_frame_debug_expr doesn't understand
1487590075Sobrien   register restores, so we don't bother setting RTX_FRAME_RELATED_P
1487690075Sobrien   anywhere in the epilogue.  Most of the insns below would in any case
1487790075Sobrien   need special notes to explain where r11 is in relation to the stack.  */
1487890075Sobrien
1487990075Sobrienvoid
14880132718Skanrs6000_emit_epilogue (int sibcall)
1488190075Sobrien{
1488290075Sobrien  rs6000_stack_t *info;
1488390075Sobrien  int restoring_FPRs_inline;
1488490075Sobrien  int using_load_multiple;
1488590075Sobrien  int using_mfcr_multiple;
1488690075Sobrien  int use_backchain_to_restore_sp;
1488790075Sobrien  int sp_offset = 0;
1488890075Sobrien  rtx sp_reg_rtx = gen_rtx_REG (Pmode, 1);
1488990075Sobrien  rtx frame_reg_rtx = sp_reg_rtx;
14890132718Skan  enum machine_mode reg_mode = Pmode;
14891132718Skan  int reg_size = TARGET_32BIT ? 4 : 8;
1489290075Sobrien  int i;
1489390075Sobrien
14894132718Skan  info = rs6000_stack_info ();
14895132718Skan
14896132718Skan  if (TARGET_SPE_ABI && info->spe_64bit_regs_used != 0)
14897117395Skan    {
14898117395Skan      reg_mode = V2SImode;
14899117395Skan      reg_size = 8;
14900117395Skan    }
14901117395Skan
1490290075Sobrien  using_load_multiple = (TARGET_MULTIPLE && ! TARGET_POWERPC64
14903132718Skan			 && (!TARGET_SPE_ABI
14904132718Skan			     || info->spe_64bit_regs_used == 0)
14905169689Skan			 && info->first_gp_reg_save < 31
14906169689Skan			 && no_global_regs_above (info->first_gp_reg_save));
1490790075Sobrien  restoring_FPRs_inline = (sibcall
1490890075Sobrien			   || current_function_calls_eh_return
1490990075Sobrien			   || info->first_fp_reg_save == 64
1491090075Sobrien			   || FP_SAVE_INLINE (info->first_fp_reg_save));
14911169689Skan  use_backchain_to_restore_sp = (frame_pointer_needed
1491290075Sobrien				 || current_function_calls_alloca
1491390075Sobrien				 || info->total_size > 32767);
1491490075Sobrien  using_mfcr_multiple = (rs6000_cpu == PROCESSOR_PPC601
1491590075Sobrien			 || rs6000_cpu == PROCESSOR_PPC603
1491690075Sobrien			 || rs6000_cpu == PROCESSOR_PPC750
1491790075Sobrien			 || optimize_size);
1491890075Sobrien
14919169689Skan  if (WORLD_SAVE_P (info))
14920169689Skan    {
14921169689Skan      int i, j;
14922169689Skan      char rname[30];
14923169689Skan      const char *alloc_rname;
14924169689Skan      rtvec p;
14925169689Skan
14926169689Skan      /* eh_rest_world_r10 will return to the location saved in the LR
14927169689Skan	 stack slot (which is not likely to be our caller.)
14928169689Skan	 Input: R10 -- stack adjustment.  Clobbers R0, R11, R12, R7, R8.
14929169689Skan	 rest_world is similar, except any R10 parameter is ignored.
14930169689Skan	 The exception-handling stuff that was here in 2.95 is no
14931169689Skan	 longer necessary.  */
14932169689Skan
14933169689Skan      p = rtvec_alloc (9
14934169689Skan		       + 1
14935169689Skan		       + 32 - info->first_gp_reg_save
14936169689Skan		       + LAST_ALTIVEC_REGNO + 1 - info->first_altivec_reg_save
14937169689Skan		       + 63 + 1 - info->first_fp_reg_save);
14938169689Skan
14939169689Skan      strcpy (rname, ((current_function_calls_eh_return) ?
14940169689Skan		      "*eh_rest_world_r10" : "*rest_world"));
14941169689Skan      alloc_rname = ggc_strdup (rname);
14942169689Skan
14943169689Skan      j = 0;
14944169689Skan      RTVEC_ELT (p, j++) = gen_rtx_RETURN (VOIDmode);
14945169689Skan      RTVEC_ELT (p, j++) = gen_rtx_USE (VOIDmode,
14946169689Skan					gen_rtx_REG (Pmode,
14947169689Skan						     LINK_REGISTER_REGNUM));
14948169689Skan      RTVEC_ELT (p, j++)
14949169689Skan	= gen_rtx_USE (VOIDmode, gen_rtx_SYMBOL_REF (Pmode, alloc_rname));
14950169689Skan      /* The instruction pattern requires a clobber here;
14951169689Skan	 it is shared with the restVEC helper. */
14952169689Skan      RTVEC_ELT (p, j++)
14953169689Skan	= gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, 11));
14954169689Skan
14955169689Skan      {
14956169689Skan	/* CR register traditionally saved as CR2.  */
14957169689Skan	rtx reg = gen_rtx_REG (reg_mode, CR2_REGNO);
14958169689Skan	rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
14959169689Skan				 GEN_INT (info->cr_save_offset));
14960169689Skan	rtx mem = gen_frame_mem (reg_mode, addr);
14961169689Skan
14962169689Skan	RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem);
14963169689Skan      }
14964169689Skan
14965169689Skan      for (i = 0; i < 32 - info->first_gp_reg_save; i++)
14966169689Skan	{
14967169689Skan	  rtx reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
14968169689Skan	  rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
14969169689Skan				   GEN_INT (info->gp_save_offset
14970169689Skan					    + reg_size * i));
14971169689Skan	  rtx mem = gen_frame_mem (reg_mode, addr);
14972169689Skan
14973169689Skan	  RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem);
14974169689Skan	}
14975169689Skan      for (i = 0; info->first_altivec_reg_save + i <= LAST_ALTIVEC_REGNO; i++)
14976169689Skan	{
14977169689Skan	  rtx reg = gen_rtx_REG (V4SImode, info->first_altivec_reg_save + i);
14978169689Skan	  rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
14979169689Skan				   GEN_INT (info->altivec_save_offset
14980169689Skan					    + 16 * i));
14981169689Skan	  rtx mem = gen_frame_mem (V4SImode, addr);
14982169689Skan
14983169689Skan	  RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem);
14984169689Skan	}
14985169689Skan      for (i = 0; info->first_fp_reg_save + i <= 63; i++)
14986169689Skan	{
14987169689Skan	  rtx reg = gen_rtx_REG (DFmode, info->first_fp_reg_save + i);
14988169689Skan	  rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
14989169689Skan				   GEN_INT (info->fp_save_offset
14990169689Skan					    + 8 * i));
14991169689Skan	  rtx mem = gen_frame_mem (DFmode, addr);
14992169689Skan
14993169689Skan	  RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem);
14994169689Skan	}
14995169689Skan      RTVEC_ELT (p, j++)
14996169689Skan	= gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, 0));
14997169689Skan      RTVEC_ELT (p, j++)
14998169689Skan	= gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, 12));
14999169689Skan      RTVEC_ELT (p, j++)
15000169689Skan	= gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, 7));
15001169689Skan      RTVEC_ELT (p, j++)
15002169689Skan	= gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, 8));
15003169689Skan      RTVEC_ELT (p, j++)
15004169689Skan	= gen_rtx_USE (VOIDmode, gen_rtx_REG (SImode, 10));
15005169689Skan      emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, p));
15006169689Skan
15007169689Skan      return;
15008169689Skan    }
15009169689Skan
1501090075Sobrien  /* If we have a frame pointer, a call to alloca,  or a large stack
1501190075Sobrien     frame, restore the old stack pointer using the backchain.  Otherwise,
1501290075Sobrien     we know what size to update it with.  */
1501390075Sobrien  if (use_backchain_to_restore_sp)
1501490075Sobrien    {
1501590075Sobrien      /* Under V.4, don't reset the stack pointer until after we're done
1501690075Sobrien	 loading the saved registers.  */
1501790075Sobrien      if (DEFAULT_ABI == ABI_V4)
1501890075Sobrien	frame_reg_rtx = gen_rtx_REG (Pmode, 11);
1501990075Sobrien
1502090075Sobrien      emit_move_insn (frame_reg_rtx,
1502190075Sobrien		      gen_rtx_MEM (Pmode, sp_reg_rtx));
1502290075Sobrien    }
1502390075Sobrien  else if (info->push_p)
1502490075Sobrien    {
15025132718Skan      if (DEFAULT_ABI == ABI_V4
15026132718Skan	  || current_function_calls_eh_return)
1502790075Sobrien	sp_offset = info->total_size;
1502890075Sobrien      else
1502990075Sobrien	{
1503090075Sobrien	  emit_insn (TARGET_32BIT
1503190075Sobrien		     ? gen_addsi3 (sp_reg_rtx, sp_reg_rtx,
1503290075Sobrien				   GEN_INT (info->total_size))
1503390075Sobrien		     : gen_adddi3 (sp_reg_rtx, sp_reg_rtx,
1503490075Sobrien				   GEN_INT (info->total_size)));
1503590075Sobrien	}
1503690075Sobrien    }
15037169689Skan
1503890075Sobrien  /* Restore AltiVec registers if needed.  */
1503990075Sobrien  if (TARGET_ALTIVEC_ABI && info->altivec_size != 0)
1504090075Sobrien    {
1504190075Sobrien      int i;
1504290075Sobrien
1504390075Sobrien      for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i)
1504490075Sobrien	if (info->vrsave_mask & ALTIVEC_REG_BIT (i))
1504590075Sobrien	  {
1504690075Sobrien	    rtx addr, areg, mem;
1504790075Sobrien
1504890075Sobrien	    areg = gen_rtx_REG (Pmode, 0);
1504990075Sobrien	    emit_move_insn
1505090075Sobrien	      (areg, GEN_INT (info->altivec_save_offset
1505190075Sobrien			      + sp_offset
1505290075Sobrien			      + 16 * (i - info->first_altivec_reg_save)));
1505390075Sobrien
1505490075Sobrien	    /* AltiVec addressing mode is [reg+reg].  */
1505590075Sobrien	    addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, areg);
15056169689Skan	    mem = gen_frame_mem (V4SImode, addr);
1505790075Sobrien
1505890075Sobrien	    emit_move_insn (gen_rtx_REG (V4SImode, i), mem);
1505990075Sobrien	  }
1506090075Sobrien    }
1506190075Sobrien
1506290075Sobrien  /* Restore VRSAVE if needed.  */
15063132718Skan  if (TARGET_ALTIVEC && TARGET_ALTIVEC_VRSAVE
15064132718Skan      && info->vrsave_mask != 0)
1506590075Sobrien    {
1506690075Sobrien      rtx addr, mem, reg;
1506790075Sobrien
1506890075Sobrien      addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
1506990075Sobrien			   GEN_INT (info->vrsave_save_offset + sp_offset));
15070169689Skan      mem = gen_frame_mem (SImode, addr);
1507190075Sobrien      reg = gen_rtx_REG (SImode, 12);
1507290075Sobrien      emit_move_insn (reg, mem);
1507390075Sobrien
1507490075Sobrien      emit_insn (generate_set_vrsave (reg, info, 1));
1507590075Sobrien    }
1507690075Sobrien
1507790075Sobrien  /* Get the old lr if we saved it.  */
1507890075Sobrien  if (info->lr_save_p)
1507990075Sobrien    {
15080117395Skan      rtx mem = gen_frame_mem_offset (Pmode, frame_reg_rtx,
15081117395Skan				      info->lr_save_offset + sp_offset);
1508290075Sobrien
1508390075Sobrien      emit_move_insn (gen_rtx_REG (Pmode, 0), mem);
1508490075Sobrien    }
15085169689Skan
1508690075Sobrien  /* Get the old cr if we saved it.  */
1508790075Sobrien  if (info->cr_save_p)
1508890075Sobrien    {
1508990075Sobrien      rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
1509090075Sobrien			       GEN_INT (info->cr_save_offset + sp_offset));
15091169689Skan      rtx mem = gen_frame_mem (SImode, addr);
1509290075Sobrien
1509390075Sobrien      emit_move_insn (gen_rtx_REG (SImode, 12), mem);
1509490075Sobrien    }
15095169689Skan
1509690075Sobrien  /* Set LR here to try to overlap restores below.  */
1509790075Sobrien  if (info->lr_save_p)
1509890075Sobrien    emit_move_insn (gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM),
1509990075Sobrien		    gen_rtx_REG (Pmode, 0));
15100169689Skan
1510190075Sobrien  /* Load exception handler data registers, if needed.  */
1510290075Sobrien  if (current_function_calls_eh_return)
1510390075Sobrien    {
1510490075Sobrien      unsigned int i, regno;
1510590075Sobrien
15106132718Skan      if (TARGET_AIX)
15107132718Skan	{
15108132718Skan	  rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
15109132718Skan				   GEN_INT (sp_offset + 5 * reg_size));
15110169689Skan	  rtx mem = gen_frame_mem (reg_mode, addr);
15111132718Skan
15112132718Skan	  emit_move_insn (gen_rtx_REG (reg_mode, 2), mem);
15113132718Skan	}
15114132718Skan
1511590075Sobrien      for (i = 0; ; ++i)
1511690075Sobrien	{
15117117395Skan	  rtx mem;
1511890075Sobrien
1511990075Sobrien	  regno = EH_RETURN_DATA_REGNO (i);
1512090075Sobrien	  if (regno == INVALID_REGNUM)
1512190075Sobrien	    break;
1512290075Sobrien
15123117395Skan	  mem = gen_frame_mem_offset (reg_mode, frame_reg_rtx,
15124117395Skan				      info->ehrd_offset + sp_offset
15125117395Skan				      + reg_size * (int) i);
1512690075Sobrien
1512790075Sobrien	  emit_move_insn (gen_rtx_REG (reg_mode, regno), mem);
1512890075Sobrien	}
1512990075Sobrien    }
15130169689Skan
1513190075Sobrien  /* Restore GPRs.  This is done as a PARALLEL if we are using
1513290075Sobrien     the load-multiple instructions.  */
1513390075Sobrien  if (using_load_multiple)
1513490075Sobrien    {
1513590075Sobrien      rtvec p;
1513690075Sobrien      p = rtvec_alloc (32 - info->first_gp_reg_save);
1513790075Sobrien      for (i = 0; i < 32 - info->first_gp_reg_save; i++)
1513890075Sobrien	{
15139169689Skan	  rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
15140169689Skan				   GEN_INT (info->gp_save_offset
15141169689Skan					    + sp_offset
1514290075Sobrien					    + reg_size * i));
15143169689Skan	  rtx mem = gen_frame_mem (reg_mode, addr);
1514490075Sobrien
15145169689Skan	  RTVEC_ELT (p, i) =
1514690075Sobrien	    gen_rtx_SET (VOIDmode,
1514790075Sobrien			 gen_rtx_REG (reg_mode, info->first_gp_reg_save + i),
1514890075Sobrien			 mem);
1514990075Sobrien	}
1515090075Sobrien      emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
1515190075Sobrien    }
1515290075Sobrien  else
1515390075Sobrien    for (i = 0; i < 32 - info->first_gp_reg_save; i++)
15154169689Skan      if ((regs_ever_live[info->first_gp_reg_save + i]
15155169689Skan	   && (!call_used_regs[info->first_gp_reg_save + i]
15156169689Skan	       || (i + info->first_gp_reg_save == RS6000_PIC_OFFSET_TABLE_REGNUM
15157146895Skan		   && TARGET_TOC && TARGET_MINIMAL_TOC)))
15158169689Skan	  || (i + info->first_gp_reg_save == RS6000_PIC_OFFSET_TABLE_REGNUM
15159117395Skan	      && ((DEFAULT_ABI == ABI_V4 && flag_pic != 0)
1516090075Sobrien		  || (DEFAULT_ABI == ABI_DARWIN && flag_pic))))
1516190075Sobrien	{
15162169689Skan	  rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
15163169689Skan				   GEN_INT (info->gp_save_offset
15164169689Skan					    + sp_offset
1516590075Sobrien					    + reg_size * i));
15166169689Skan	  rtx mem = gen_frame_mem (reg_mode, addr);
1516790075Sobrien
15168117395Skan	  /* Restore 64-bit quantities for SPE.  */
15169132718Skan	  if (TARGET_SPE_ABI && info->spe_64bit_regs_used != 0)
15170117395Skan	    {
15171117395Skan	      int offset = info->spe_gp_save_offset + sp_offset + 8 * i;
15172117395Skan	      rtx b;
15173117395Skan
15174117395Skan	      if (!SPE_CONST_OFFSET_OK (offset))
15175117395Skan		{
15176117395Skan		  b = gen_rtx_REG (Pmode, FIXED_SCRATCH);
15177117395Skan		  emit_move_insn (b, GEN_INT (offset));
15178117395Skan		}
15179117395Skan	      else
15180117395Skan		b = GEN_INT (offset);
15181117395Skan
15182117395Skan	      addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, b);
15183169689Skan	      mem = gen_frame_mem (V2SImode, addr);
15184117395Skan	    }
15185117395Skan
15186169689Skan	  emit_move_insn (gen_rtx_REG (reg_mode,
15187117395Skan				       info->first_gp_reg_save + i), mem);
1518890075Sobrien	}
1518990075Sobrien
1519090075Sobrien  /* Restore fpr's if we need to do it without calling a function.  */
1519190075Sobrien  if (restoring_FPRs_inline)
1519290075Sobrien    for (i = 0; i < 64 - info->first_fp_reg_save; i++)
15193169689Skan      if ((regs_ever_live[info->first_fp_reg_save+i]
1519490075Sobrien	   && ! call_used_regs[info->first_fp_reg_save+i]))
1519590075Sobrien	{
1519690075Sobrien	  rtx addr, mem;
1519790075Sobrien	  addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
15198169689Skan			       GEN_INT (info->fp_save_offset
15199169689Skan					+ sp_offset
1520090075Sobrien					+ 8 * i));
15201169689Skan	  mem = gen_frame_mem (DFmode, addr);
1520290075Sobrien
15203169689Skan	  emit_move_insn (gen_rtx_REG (DFmode,
1520490075Sobrien				       info->first_fp_reg_save + i),
1520590075Sobrien			  mem);
1520690075Sobrien	}
1520790075Sobrien
1520890075Sobrien  /* If we saved cr, restore it here.  Just those that were used.  */
1520990075Sobrien  if (info->cr_save_p)
1521090075Sobrien    {
1521190075Sobrien      rtx r12_rtx = gen_rtx_REG (SImode, 12);
1521290075Sobrien      int count = 0;
15213169689Skan
1521490075Sobrien      if (using_mfcr_multiple)
1521590075Sobrien	{
1521690075Sobrien	  for (i = 0; i < 8; i++)
1521790075Sobrien	    if (regs_ever_live[CR0_REGNO+i] && ! call_used_regs[CR0_REGNO+i])
1521890075Sobrien	      count++;
15219169689Skan	  gcc_assert (count);
1522090075Sobrien	}
1522190075Sobrien
1522290075Sobrien      if (using_mfcr_multiple && count > 1)
1522390075Sobrien	{
1522490075Sobrien	  rtvec p;
1522590075Sobrien	  int ndx;
15226169689Skan
1522790075Sobrien	  p = rtvec_alloc (count);
1522890075Sobrien
1522990075Sobrien	  ndx = 0;
1523090075Sobrien	  for (i = 0; i < 8; i++)
1523190075Sobrien	    if (regs_ever_live[CR0_REGNO+i] && ! call_used_regs[CR0_REGNO+i])
1523290075Sobrien	      {
1523390075Sobrien		rtvec r = rtvec_alloc (2);
1523490075Sobrien		RTVEC_ELT (r, 0) = r12_rtx;
1523590075Sobrien		RTVEC_ELT (r, 1) = GEN_INT (1 << (7-i));
1523690075Sobrien		RTVEC_ELT (p, ndx) =
15237169689Skan		  gen_rtx_SET (VOIDmode, gen_rtx_REG (CCmode, CR0_REGNO+i),
15238132718Skan			       gen_rtx_UNSPEC (CCmode, r, UNSPEC_MOVESI_TO_CR));
1523990075Sobrien		ndx++;
1524090075Sobrien	      }
1524190075Sobrien	  emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
15242169689Skan	  gcc_assert (ndx == count);
1524390075Sobrien	}
1524490075Sobrien      else
1524590075Sobrien	for (i = 0; i < 8; i++)
1524690075Sobrien	  if (regs_ever_live[CR0_REGNO+i] && ! call_used_regs[CR0_REGNO+i])
1524790075Sobrien	    {
15248169689Skan	      emit_insn (gen_movsi_to_cr_one (gen_rtx_REG (CCmode,
1524990075Sobrien							   CR0_REGNO+i),
1525090075Sobrien					      r12_rtx));
1525190075Sobrien	    }
1525290075Sobrien    }
1525390075Sobrien
1525490075Sobrien  /* If this is V.4, unwind the stack pointer after all of the loads
15255169689Skan     have been done.  */
15256169689Skan  if (frame_reg_rtx != sp_reg_rtx)
1525790075Sobrien    {
15258169689Skan      /* This blockage is needed so that sched doesn't decide to move
15259169689Skan	 the sp change before the register restores.  */
15260169689Skan      rs6000_emit_stack_tie ();
15261169689Skan      emit_move_insn (sp_reg_rtx, frame_reg_rtx);
1526290075Sobrien    }
15263169689Skan  else if (sp_offset != 0)
15264169689Skan    emit_insn (TARGET_32BIT
15265169689Skan	       ? gen_addsi3 (sp_reg_rtx, sp_reg_rtx,
15266169689Skan			     GEN_INT (sp_offset))
15267169689Skan	       : gen_adddi3 (sp_reg_rtx, sp_reg_rtx,
15268169689Skan			     GEN_INT (sp_offset)));
1526990075Sobrien
1527090075Sobrien  if (current_function_calls_eh_return)
1527190075Sobrien    {
1527290075Sobrien      rtx sa = EH_RETURN_STACKADJ_RTX;
15273132718Skan      emit_insn (TARGET_32BIT
1527490075Sobrien		 ? gen_addsi3 (sp_reg_rtx, sp_reg_rtx, sa)
1527590075Sobrien		 : gen_adddi3 (sp_reg_rtx, sp_reg_rtx, sa));
1527690075Sobrien    }
1527790075Sobrien
1527890075Sobrien  if (!sibcall)
1527990075Sobrien    {
1528090075Sobrien      rtvec p;
1528190075Sobrien      if (! restoring_FPRs_inline)
1528290075Sobrien	p = rtvec_alloc (3 + 64 - info->first_fp_reg_save);
1528390075Sobrien      else
1528490075Sobrien	p = rtvec_alloc (2);
1528590075Sobrien
1528690075Sobrien      RTVEC_ELT (p, 0) = gen_rtx_RETURN (VOIDmode);
15287169689Skan      RTVEC_ELT (p, 1) = gen_rtx_USE (VOIDmode,
15288169689Skan				      gen_rtx_REG (Pmode,
1528990075Sobrien						   LINK_REGISTER_REGNUM));
1529090075Sobrien
1529190075Sobrien      /* If we have to restore more than two FP registers, branch to the
1529290075Sobrien	 restore function.  It will return to our caller.  */
1529390075Sobrien      if (! restoring_FPRs_inline)
1529490075Sobrien	{
1529590075Sobrien	  int i;
1529690075Sobrien	  char rname[30];
1529790075Sobrien	  const char *alloc_rname;
1529890075Sobrien
15299169689Skan	  sprintf (rname, "%s%d%s", RESTORE_FP_PREFIX,
1530090075Sobrien		   info->first_fp_reg_save - 32, RESTORE_FP_SUFFIX);
1530190075Sobrien	  alloc_rname = ggc_strdup (rname);
1530290075Sobrien	  RTVEC_ELT (p, 2) = gen_rtx_USE (VOIDmode,
1530390075Sobrien					  gen_rtx_SYMBOL_REF (Pmode,
1530490075Sobrien							      alloc_rname));
1530590075Sobrien
1530690075Sobrien	  for (i = 0; i < 64 - info->first_fp_reg_save; i++)
1530790075Sobrien	    {
1530890075Sobrien	      rtx addr, mem;
1530990075Sobrien	      addr = gen_rtx_PLUS (Pmode, sp_reg_rtx,
1531090075Sobrien				   GEN_INT (info->fp_save_offset + 8*i));
15311169689Skan	      mem = gen_frame_mem (DFmode, addr);
1531290075Sobrien
15313169689Skan	      RTVEC_ELT (p, i+3) =
1531490075Sobrien		gen_rtx_SET (VOIDmode,
1531590075Sobrien			     gen_rtx_REG (DFmode, info->first_fp_reg_save + i),
1531690075Sobrien			     mem);
1531790075Sobrien	    }
1531890075Sobrien	}
15319169689Skan
1532090075Sobrien      emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, p));
1532190075Sobrien    }
1532290075Sobrien}
1532390075Sobrien
1532490075Sobrien/* Write function epilogue.  */
1532590075Sobrien
1532690075Sobrienstatic void
15327169689Skanrs6000_output_function_epilogue (FILE *file,
15328132718Skan				 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
1532990075Sobrien{
1533090075Sobrien  if (! HAVE_epilogue)
1533190075Sobrien    {
1533290075Sobrien      rtx insn = get_last_insn ();
1533390075Sobrien      /* If the last insn was a BARRIER, we don't have to write anything except
1533490075Sobrien	 the trace table.  */
1533590075Sobrien      if (GET_CODE (insn) == NOTE)
1533690075Sobrien	insn = prev_nonnote_insn (insn);
1533790075Sobrien      if (insn == 0 ||  GET_CODE (insn) != BARRIER)
1533890075Sobrien	{
1533990075Sobrien	  /* This is slightly ugly, but at least we don't have two
1534090075Sobrien	     copies of the epilogue-emitting code.  */
1534190075Sobrien	  start_sequence ();
1534290075Sobrien
1534390075Sobrien	  /* A NOTE_INSN_DELETED is supposed to be at the start
1534490075Sobrien	     and end of the "toplevel" insn chain.  */
15345132718Skan	  emit_note (NOTE_INSN_DELETED);
1534690075Sobrien	  rs6000_emit_epilogue (FALSE);
15347132718Skan	  emit_note (NOTE_INSN_DELETED);
1534890075Sobrien
15349132718Skan	  /* Expand INSN_ADDRESSES so final() doesn't crash.  */
1535096263Sobrien	  {
1535196263Sobrien	    rtx insn;
1535296263Sobrien	    unsigned addr = 0;
1535396263Sobrien	    for (insn = get_insns (); insn != 0; insn = NEXT_INSN (insn))
1535496263Sobrien	      {
1535596263Sobrien		INSN_ADDRESSES_NEW (insn, addr);
1535696263Sobrien		addr += 4;
1535796263Sobrien	      }
1535896263Sobrien	  }
1535996263Sobrien
1536090075Sobrien	  if (TARGET_DEBUG_STACK)
1536190075Sobrien	    debug_rtx_list (get_insns (), 100);
15362169689Skan	  final (get_insns (), file, FALSE);
1536390075Sobrien	  end_sequence ();
1536490075Sobrien	}
1536590075Sobrien    }
1536690075Sobrien
15367132718Skan#if TARGET_MACHO
15368132718Skan  macho_branch_islands ();
15369119256Skan  /* Mach-O doesn't support labels at the end of objects, so if
15370119256Skan     it looks like we might want one, insert a NOP.  */
15371119256Skan  {
15372119256Skan    rtx insn = get_last_insn ();
15373119256Skan    while (insn
15374119256Skan	   && NOTE_P (insn)
15375119256Skan	   && NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED_LABEL)
15376119256Skan      insn = PREV_INSN (insn);
15377169689Skan    if (insn
15378169689Skan	&& (LABEL_P (insn)
15379119256Skan	    || (NOTE_P (insn)
15380119256Skan		&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED_LABEL)))
15381119256Skan      fputs ("\tnop\n", file);
15382119256Skan  }
15383119256Skan#endif
15384119256Skan
1538590075Sobrien  /* Output a traceback table here.  See /usr/include/sys/debug.h for info
1538690075Sobrien     on its format.
1538790075Sobrien
1538890075Sobrien     We don't output a traceback table if -finhibit-size-directive was
1538990075Sobrien     used.  The documentation for -finhibit-size-directive reads
1539090075Sobrien     ``don't output a @code{.size} assembler directive, or anything
1539190075Sobrien     else that would cause trouble if the function is split in the
1539290075Sobrien     middle, and the two halves are placed at locations far apart in
1539390075Sobrien     memory.''  The traceback table has this property, since it
1539490075Sobrien     includes the offset from the start of the function to the
1539590075Sobrien     traceback table itself.
1539690075Sobrien
1539790075Sobrien     System V.4 Powerpc's (and the embedded ABI derived from it) use a
1539890075Sobrien     different traceback table.  */
15399117395Skan  if (DEFAULT_ABI == ABI_AIX && ! flag_inhibit_size_directive
15400169689Skan      && rs6000_traceback != traceback_none && !current_function_is_thunk)
1540190075Sobrien    {
15402117395Skan      const char *fname = NULL;
1540390075Sobrien      const char *language_string = lang_hooks.name;
1540490075Sobrien      int fixed_parms = 0, float_parms = 0, parm_info = 0;
1540590075Sobrien      int i;
15406117395Skan      int optional_tbtab;
15407169689Skan      rs6000_stack_t *info = rs6000_stack_info ();
1540890075Sobrien
15409117395Skan      if (rs6000_traceback == traceback_full)
15410117395Skan	optional_tbtab = 1;
15411117395Skan      else if (rs6000_traceback == traceback_part)
15412117395Skan	optional_tbtab = 0;
15413117395Skan      else
15414117395Skan	optional_tbtab = !optimize_size && !TARGET_ELF;
1541590075Sobrien
15416117395Skan      if (optional_tbtab)
15417117395Skan	{
15418117395Skan	  fname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
15419117395Skan	  while (*fname == '.')	/* V.4 encodes . in the name */
15420117395Skan	    fname++;
1542190075Sobrien
15422117395Skan	  /* Need label immediately before tbtab, so we can compute
15423117395Skan	     its offset from the function start.  */
15424117395Skan	  ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "LT");
15425117395Skan	  ASM_OUTPUT_LABEL (file, fname);
15426117395Skan	}
15427117395Skan
1542890075Sobrien      /* The .tbtab pseudo-op can only be used for the first eight
1542990075Sobrien	 expressions, since it can't handle the possibly variable
1543090075Sobrien	 length fields that follow.  However, if you omit the optional
1543190075Sobrien	 fields, the assembler outputs zeros for all optional fields
1543290075Sobrien	 anyways, giving each variable length field is minimum length
1543390075Sobrien	 (as defined in sys/debug.h).  Thus we can not use the .tbtab
1543490075Sobrien	 pseudo-op at all.  */
1543590075Sobrien
1543690075Sobrien      /* An all-zero word flags the start of the tbtab, for debuggers
1543790075Sobrien	 that have to find it by searching forward from the entry
1543890075Sobrien	 point or from the current pc.  */
1543990075Sobrien      fputs ("\t.long 0\n", file);
1544090075Sobrien
1544190075Sobrien      /* Tbtab format type.  Use format type 0.  */
1544290075Sobrien      fputs ("\t.byte 0,", file);
1544390075Sobrien
15444132718Skan      /* Language type.  Unfortunately, there does not seem to be any
15445132718Skan	 official way to discover the language being compiled, so we
15446132718Skan	 use language_string.
15447132718Skan	 C is 0.  Fortran is 1.  Pascal is 2.  Ada is 3.  C++ is 9.
15448169689Skan	 Java is 13.  Objective-C is 14.  Objective-C++ isn't assigned
15449169689Skan	 a number, so for now use 9.  */
15450132718Skan      if (! strcmp (language_string, "GNU C"))
1545190075Sobrien	i = 0;
15452169689Skan      else if (! strcmp (language_string, "GNU F77")
15453169689Skan	       || ! strcmp (language_string, "GNU F95"))
1545490075Sobrien	i = 1;
15455132718Skan      else if (! strcmp (language_string, "GNU Pascal"))
15456132718Skan	i = 2;
1545790075Sobrien      else if (! strcmp (language_string, "GNU Ada"))
1545890075Sobrien	i = 3;
15459169689Skan      else if (! strcmp (language_string, "GNU C++")
15460169689Skan	       || ! strcmp (language_string, "GNU Objective-C++"))
1546190075Sobrien	i = 9;
1546290075Sobrien      else if (! strcmp (language_string, "GNU Java"))
1546390075Sobrien	i = 13;
15464132718Skan      else if (! strcmp (language_string, "GNU Objective-C"))
15465132718Skan	i = 14;
1546690075Sobrien      else
15467169689Skan	gcc_unreachable ();
1546890075Sobrien      fprintf (file, "%d,", i);
1546990075Sobrien
1547090075Sobrien      /* 8 single bit fields: global linkage (not set for C extern linkage,
1547190075Sobrien	 apparently a PL/I convention?), out-of-line epilogue/prologue, offset
1547290075Sobrien	 from start of procedure stored in tbtab, internal function, function
1547390075Sobrien	 has controlled storage, function has no toc, function uses fp,
1547490075Sobrien	 function logs/aborts fp operations.  */
1547590075Sobrien      /* Assume that fp operations are used if any fp reg must be saved.  */
1547690075Sobrien      fprintf (file, "%d,",
1547790075Sobrien	       (optional_tbtab << 5) | ((info->first_fp_reg_save != 64) << 1));
1547890075Sobrien
1547990075Sobrien      /* 6 bitfields: function is interrupt handler, name present in
1548090075Sobrien	 proc table, function calls alloca, on condition directives
1548190075Sobrien	 (controls stack walks, 3 bits), saves condition reg, saves
1548290075Sobrien	 link reg.  */
1548390075Sobrien      /* The `function calls alloca' bit seems to be set whenever reg 31 is
1548490075Sobrien	 set up as a frame pointer, even when there is no alloca call.  */
1548590075Sobrien      fprintf (file, "%d,",
1548690075Sobrien	       ((optional_tbtab << 6)
1548790075Sobrien		| ((optional_tbtab & frame_pointer_needed) << 5)
1548890075Sobrien		| (info->cr_save_p << 1)
1548990075Sobrien		| (info->lr_save_p)));
1549090075Sobrien
1549190075Sobrien      /* 3 bitfields: saves backchain, fixup code, number of fpr saved
1549290075Sobrien	 (6 bits).  */
1549390075Sobrien      fprintf (file, "%d,",
1549490075Sobrien	       (info->push_p << 7) | (64 - info->first_fp_reg_save));
1549590075Sobrien
1549690075Sobrien      /* 2 bitfields: spare bits (2 bits), number of gpr saved (6 bits).  */
1549790075Sobrien      fprintf (file, "%d,", (32 - first_reg_to_save ()));
1549890075Sobrien
1549990075Sobrien      if (optional_tbtab)
1550090075Sobrien	{
1550190075Sobrien	  /* Compute the parameter info from the function decl argument
1550290075Sobrien	     list.  */
1550390075Sobrien	  tree decl;
1550490075Sobrien	  int next_parm_info_bit = 31;
1550590075Sobrien
1550690075Sobrien	  for (decl = DECL_ARGUMENTS (current_function_decl);
1550790075Sobrien	       decl; decl = TREE_CHAIN (decl))
1550890075Sobrien	    {
1550990075Sobrien	      rtx parameter = DECL_INCOMING_RTL (decl);
1551090075Sobrien	      enum machine_mode mode = GET_MODE (parameter);
1551190075Sobrien
1551290075Sobrien	      if (GET_CODE (parameter) == REG)
1551390075Sobrien		{
15514169689Skan		  if (SCALAR_FLOAT_MODE_P (mode))
1551590075Sobrien		    {
1551690075Sobrien		      int bits;
1551790075Sobrien
1551890075Sobrien		      float_parms++;
1551990075Sobrien
15520169689Skan		      switch (mode)
15521169689Skan			{
15522169689Skan			case SFmode:
15523169689Skan			  bits = 0x2;
15524169689Skan			  break;
1552590075Sobrien
15526169689Skan			case DFmode:
15527169689Skan			case TFmode:
15528169689Skan			  bits = 0x3;
15529169689Skan			  break;
15530169689Skan
15531169689Skan			default:
15532169689Skan			  gcc_unreachable ();
15533169689Skan			}
15534169689Skan
1553590075Sobrien		      /* If only one bit will fit, don't or in this entry.  */
1553690075Sobrien		      if (next_parm_info_bit > 0)
1553790075Sobrien			parm_info |= (bits << (next_parm_info_bit - 1));
1553890075Sobrien		      next_parm_info_bit -= 2;
1553990075Sobrien		    }
1554090075Sobrien		  else
1554190075Sobrien		    {
1554290075Sobrien		      fixed_parms += ((GET_MODE_SIZE (mode)
1554390075Sobrien				       + (UNITS_PER_WORD - 1))
1554490075Sobrien				      / UNITS_PER_WORD);
1554590075Sobrien		      next_parm_info_bit -= 1;
1554690075Sobrien		    }
1554790075Sobrien		}
1554890075Sobrien	    }
1554990075Sobrien	}
1555090075Sobrien
1555190075Sobrien      /* Number of fixed point parameters.  */
1555290075Sobrien      /* This is actually the number of words of fixed point parameters; thus
1555390075Sobrien	 an 8 byte struct counts as 2; and thus the maximum value is 8.  */
1555490075Sobrien      fprintf (file, "%d,", fixed_parms);
1555590075Sobrien
1555690075Sobrien      /* 2 bitfields: number of floating point parameters (7 bits), parameters
1555790075Sobrien	 all on stack.  */
1555890075Sobrien      /* This is actually the number of fp registers that hold parameters;
1555990075Sobrien	 and thus the maximum value is 13.  */
1556090075Sobrien      /* Set parameters on stack bit if parameters are not in their original
1556190075Sobrien	 registers, regardless of whether they are on the stack?  Xlc
1556290075Sobrien	 seems to set the bit when not optimizing.  */
1556390075Sobrien      fprintf (file, "%d\n", ((float_parms << 1) | (! optimize)));
1556490075Sobrien
1556590075Sobrien      if (! optional_tbtab)
1556690075Sobrien	return;
1556790075Sobrien
1556890075Sobrien      /* Optional fields follow.  Some are variable length.  */
1556990075Sobrien
1557090075Sobrien      /* Parameter types, left adjusted bit fields: 0 fixed, 10 single float,
1557190075Sobrien	 11 double float.  */
1557290075Sobrien      /* There is an entry for each parameter in a register, in the order that
1557390075Sobrien	 they occur in the parameter list.  Any intervening arguments on the
1557490075Sobrien	 stack are ignored.  If the list overflows a long (max possible length
1557590075Sobrien	 34 bits) then completely leave off all elements that don't fit.  */
1557690075Sobrien      /* Only emit this long if there was at least one parameter.  */
1557790075Sobrien      if (fixed_parms || float_parms)
1557890075Sobrien	fprintf (file, "\t.long %d\n", parm_info);
1557990075Sobrien
1558090075Sobrien      /* Offset from start of code to tb table.  */
1558190075Sobrien      fputs ("\t.long ", file);
1558290075Sobrien      ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "LT");
15583169689Skan      if (TARGET_AIX)
15584169689Skan	RS6000_OUTPUT_BASENAME (file, fname);
15585169689Skan      else
15586169689Skan	assemble_name (file, fname);
15587169689Skan      putc ('-', file);
15588169689Skan      rs6000_output_function_entry (file, fname);
1558990075Sobrien      putc ('\n', file);
1559090075Sobrien
1559190075Sobrien      /* Interrupt handler mask.  */
1559290075Sobrien      /* Omit this long, since we never set the interrupt handler bit
1559390075Sobrien	 above.  */
1559490075Sobrien
1559590075Sobrien      /* Number of CTL (controlled storage) anchors.  */
1559690075Sobrien      /* Omit this long, since the has_ctl bit is never set above.  */
1559790075Sobrien
1559890075Sobrien      /* Displacement into stack of each CTL anchor.  */
1559990075Sobrien      /* Omit this list of longs, because there are no CTL anchors.  */
1560090075Sobrien
1560190075Sobrien      /* Length of function name.  */
15602117395Skan      if (*fname == '*')
15603117395Skan	++fname;
1560490075Sobrien      fprintf (file, "\t.short %d\n", (int) strlen (fname));
1560590075Sobrien
1560690075Sobrien      /* Function name.  */
1560790075Sobrien      assemble_string (fname, strlen (fname));
1560890075Sobrien
1560990075Sobrien      /* Register for alloca automatic storage; this is always reg 31.
1561090075Sobrien	 Only emit this if the alloca bit was set above.  */
1561190075Sobrien      if (frame_pointer_needed)
1561290075Sobrien	fputs ("\t.byte 31\n", file);
1561396263Sobrien
1561496263Sobrien      fputs ("\t.align 2\n", file);
1561590075Sobrien    }
1561690075Sobrien}
1561790075Sobrien
1561890075Sobrien/* A C compound statement that outputs the assembler code for a thunk
1561990075Sobrien   function, used to implement C++ virtual function calls with
1562090075Sobrien   multiple inheritance.  The thunk acts as a wrapper around a virtual
1562190075Sobrien   function, adjusting the implicit object parameter before handing
1562290075Sobrien   control off to the real function.
1562390075Sobrien
1562490075Sobrien   First, emit code to add the integer DELTA to the location that
1562590075Sobrien   contains the incoming first argument.  Assume that this argument
1562690075Sobrien   contains a pointer, and is the one used to pass the `this' pointer
1562790075Sobrien   in C++.  This is the incoming argument *before* the function
1562890075Sobrien   prologue, e.g. `%o0' on a sparc.  The addition must preserve the
1562990075Sobrien   values of all other incoming arguments.
1563090075Sobrien
1563190075Sobrien   After the addition, emit code to jump to FUNCTION, which is a
1563290075Sobrien   `FUNCTION_DECL'.  This is a direct pure jump, not a call, and does
1563390075Sobrien   not touch the return address.  Hence returning from FUNCTION will
1563490075Sobrien   return to whoever called the current `thunk'.
1563590075Sobrien
1563690075Sobrien   The effect must be as if FUNCTION had been called directly with the
1563790075Sobrien   adjusted first argument.  This macro is responsible for emitting
1563890075Sobrien   all of the code for a thunk function; output_function_prologue()
1563990075Sobrien   and output_function_epilogue() are not invoked.
1564090075Sobrien
1564190075Sobrien   The THUNK_FNDECL is redundant.  (DELTA and FUNCTION have already
1564290075Sobrien   been extracted from it.)  It might possibly be useful on some
1564390075Sobrien   targets, but probably not.
1564490075Sobrien
1564590075Sobrien   If you do not define this macro, the target-independent code in the
1564690075Sobrien   C++ frontend will generate a less efficient heavyweight thunk that
1564790075Sobrien   calls FUNCTION instead of jumping to it.  The generic approach does
1564890075Sobrien   not support varargs.  */
1564990075Sobrien
15650117395Skanstatic void
15651169689Skanrs6000_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
15652169689Skan			HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
15653132718Skan			tree function)
1565490075Sobrien{
15655132718Skan  rtx this, insn, funexp;
1565690075Sobrien
15657132718Skan  reload_completed = 1;
15658132718Skan  epilogue_completed = 1;
15659132718Skan  no_new_pseudos = 1;
15660169689Skan  reset_block_changes ();
1566190075Sobrien
15662132718Skan  /* Mark the end of the (empty) prologue.  */
15663132718Skan  emit_note (NOTE_INSN_PROLOGUE_END);
15664102780Skan
15665132718Skan  /* Find the "this" pointer.  If the function returns a structure,
15666132718Skan     the structure return pointer is in r3.  */
15667132718Skan  if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
15668132718Skan    this = gen_rtx_REG (Pmode, 4);
15669132718Skan  else
15670132718Skan    this = gen_rtx_REG (Pmode, 3);
1567190075Sobrien
15672132718Skan  /* Apply the constant offset, if required.  */
15673132718Skan  if (delta)
1567490075Sobrien    {
15675132718Skan      rtx delta_rtx = GEN_INT (delta);
15676132718Skan      emit_insn (TARGET_32BIT
15677132718Skan		 ? gen_addsi3 (this, this, delta_rtx)
15678132718Skan		 : gen_adddi3 (this, this, delta_rtx));
1567990075Sobrien    }
1568090075Sobrien
15681132718Skan  /* Apply the offset from the vtable, if required.  */
15682132718Skan  if (vcall_offset)
1568390075Sobrien    {
15684132718Skan      rtx vcall_offset_rtx = GEN_INT (vcall_offset);
15685132718Skan      rtx tmp = gen_rtx_REG (Pmode, 12);
1568690075Sobrien
15687132718Skan      emit_move_insn (tmp, gen_rtx_MEM (Pmode, this));
15688132718Skan      if (((unsigned HOST_WIDE_INT) vcall_offset) + 0x8000 >= 0x10000)
15689132718Skan	{
15690132718Skan	  emit_insn (TARGET_32BIT
15691132718Skan		     ? gen_addsi3 (tmp, tmp, vcall_offset_rtx)
15692132718Skan		     : gen_adddi3 (tmp, tmp, vcall_offset_rtx));
15693132718Skan	  emit_move_insn (tmp, gen_rtx_MEM (Pmode, tmp));
15694132718Skan	}
15695132718Skan      else
15696132718Skan	{
15697132718Skan	  rtx loc = gen_rtx_PLUS (Pmode, tmp, vcall_offset_rtx);
1569890075Sobrien
15699132718Skan	  emit_move_insn (tmp, gen_rtx_MEM (Pmode, loc));
15700132718Skan	}
15701132718Skan      emit_insn (TARGET_32BIT
15702132718Skan		 ? gen_addsi3 (this, this, tmp)
15703132718Skan		 : gen_adddi3 (this, this, tmp));
1570490075Sobrien    }
1570590075Sobrien
15706132718Skan  /* Generate a tail call to the target function.  */
15707132718Skan  if (!TREE_USED (function))
1570890075Sobrien    {
15709132718Skan      assemble_external (function);
15710132718Skan      TREE_USED (function) = 1;
1571190075Sobrien    }
15712132718Skan  funexp = XEXP (DECL_RTL (function), 0);
15713132718Skan  funexp = gen_rtx_MEM (FUNCTION_MODE, funexp);
1571490075Sobrien
15715132718Skan#if TARGET_MACHO
15716132718Skan  if (MACHOPIC_INDIRECT)
15717132718Skan    funexp = machopic_indirect_call_target (funexp);
15718132718Skan#endif
1571990075Sobrien
15720132718Skan  /* gen_sibcall expects reload to convert scratch pseudo to LR so we must
15721169689Skan     generate sibcall RTL explicitly.  */
15722132718Skan  insn = emit_call_insn (
15723132718Skan	   gen_rtx_PARALLEL (VOIDmode,
15724132718Skan	     gen_rtvec (4,
15725132718Skan			gen_rtx_CALL (VOIDmode,
15726132718Skan				      funexp, const0_rtx),
15727132718Skan			gen_rtx_USE (VOIDmode, const0_rtx),
15728132718Skan			gen_rtx_USE (VOIDmode,
15729132718Skan				     gen_rtx_REG (SImode,
15730132718Skan						  LINK_REGISTER_REGNUM)),
15731132718Skan			gen_rtx_RETURN (VOIDmode))));
15732132718Skan  SIBLING_CALL_P (insn) = 1;
15733132718Skan  emit_barrier ();
1573490075Sobrien
15735132718Skan  /* Run just enough of rest_of_compilation to get the insns emitted.
15736132718Skan     There's not really enough bulk here to make other passes such as
15737132718Skan     instruction scheduling worth while.  Note that use_thunk calls
15738132718Skan     assemble_start_function and assemble_end_function.  */
15739132718Skan  insn = get_insns ();
15740132718Skan  insn_locators_initialize ();
15741132718Skan  shorten_branches (insn);
15742132718Skan  final_start_function (insn, file, 1);
15743169689Skan  final (insn, file, 1);
15744132718Skan  final_end_function ();
1574590075Sobrien
15746132718Skan  reload_completed = 0;
15747132718Skan  epilogue_completed = 0;
15748132718Skan  no_new_pseudos = 0;
1574990075Sobrien}
1575090075Sobrien
1575190075Sobrien/* A quick summary of the various types of 'constant-pool tables'
1575290075Sobrien   under PowerPC:
1575390075Sobrien
15754169689Skan   Target	Flags		Name		One table per
1575590075Sobrien   AIX		(none)		AIX TOC		object file
1575690075Sobrien   AIX		-mfull-toc	AIX TOC		object file
1575790075Sobrien   AIX		-mminimal-toc	AIX minimal TOC	translation unit
1575890075Sobrien   SVR4/EABI	(none)		SVR4 SDATA	object file
1575990075Sobrien   SVR4/EABI	-fpic		SVR4 pic	object file
1576090075Sobrien   SVR4/EABI	-fPIC		SVR4 PIC	translation unit
1576190075Sobrien   SVR4/EABI	-mrelocatable	EABI TOC	function
1576290075Sobrien   SVR4/EABI	-maix		AIX TOC		object file
15763169689Skan   SVR4/EABI	-maix -mminimal-toc
1576490075Sobrien				AIX minimal TOC	translation unit
1576590075Sobrien
1576690075Sobrien   Name			Reg.	Set by	entries	      contains:
1576790075Sobrien					made by	 addrs?	fp?	sum?
1576890075Sobrien
1576990075Sobrien   AIX TOC		2	crt0	as	 Y	option	option
1577090075Sobrien   AIX minimal TOC	30	prolog	gcc	 Y	Y	option
1577190075Sobrien   SVR4 SDATA		13	crt0	gcc	 N	Y	N
1577290075Sobrien   SVR4 pic		30	prolog	ld	 Y	not yet	N
1577390075Sobrien   SVR4 PIC		30	prolog	gcc	 Y	option	option
1577490075Sobrien   EABI TOC		30	prolog	gcc	 Y	option	option
1577590075Sobrien
1577690075Sobrien*/
1577790075Sobrien
1577890075Sobrien/* Hash functions for the hash table.  */
1577990075Sobrien
1578090075Sobrienstatic unsigned
15781132718Skanrs6000_hash_constant (rtx k)
1578290075Sobrien{
15783117395Skan  enum rtx_code code = GET_CODE (k);
15784117395Skan  enum machine_mode mode = GET_MODE (k);
15785117395Skan  unsigned result = (code << 3) ^ mode;
15786117395Skan  const char *format;
15787117395Skan  int flen, fidx;
15788169689Skan
15789117395Skan  format = GET_RTX_FORMAT (code);
15790117395Skan  flen = strlen (format);
15791117395Skan  fidx = 0;
1579290075Sobrien
15793117395Skan  switch (code)
15794117395Skan    {
15795117395Skan    case LABEL_REF:
15796117395Skan      return result * 1231 + (unsigned) INSN_UID (XEXP (k, 0));
1579790075Sobrien
15798117395Skan    case CONST_DOUBLE:
15799117395Skan      if (mode != VOIDmode)
15800117395Skan	return real_hash (CONST_DOUBLE_REAL_VALUE (k)) * result;
15801117395Skan      flen = 2;
15802117395Skan      break;
15803117395Skan
15804117395Skan    case CODE_LABEL:
15805117395Skan      fidx = 3;
15806117395Skan      break;
15807117395Skan
15808117395Skan    default:
15809117395Skan      break;
15810117395Skan    }
15811117395Skan
1581290075Sobrien  for (; fidx < flen; fidx++)
1581390075Sobrien    switch (format[fidx])
1581490075Sobrien      {
1581590075Sobrien      case 's':
1581690075Sobrien	{
1581790075Sobrien	  unsigned i, len;
1581890075Sobrien	  const char *str = XSTR (k, fidx);
1581990075Sobrien	  len = strlen (str);
1582090075Sobrien	  result = result * 613 + len;
1582190075Sobrien	  for (i = 0; i < len; i++)
1582290075Sobrien	    result = result * 613 + (unsigned) str[i];
1582390075Sobrien	  break;
1582490075Sobrien	}
1582590075Sobrien      case 'u':
1582690075Sobrien      case 'e':
1582790075Sobrien	result = result * 1231 + rs6000_hash_constant (XEXP (k, fidx));
1582890075Sobrien	break;
1582990075Sobrien      case 'i':
1583090075Sobrien      case 'n':
1583190075Sobrien	result = result * 613 + (unsigned) XINT (k, fidx);
1583290075Sobrien	break;
1583390075Sobrien      case 'w':
1583490075Sobrien	if (sizeof (unsigned) >= sizeof (HOST_WIDE_INT))
1583590075Sobrien	  result = result * 613 + (unsigned) XWINT (k, fidx);
1583690075Sobrien	else
1583790075Sobrien	  {
1583890075Sobrien	    size_t i;
15839169689Skan	    for (i = 0; i < sizeof (HOST_WIDE_INT) / sizeof (unsigned); i++)
1584090075Sobrien	      result = result * 613 + (unsigned) (XWINT (k, fidx)
1584190075Sobrien						  >> CHAR_BIT * i);
1584290075Sobrien	  }
1584390075Sobrien	break;
15844132718Skan      case '0':
15845132718Skan	break;
1584690075Sobrien      default:
15847169689Skan	gcc_unreachable ();
1584890075Sobrien      }
15849117395Skan
1585090075Sobrien  return result;
1585190075Sobrien}
1585290075Sobrien
1585390075Sobrienstatic unsigned
15854132718Skantoc_hash_function (const void *hash_entry)
1585590075Sobrien{
15856169689Skan  const struct toc_hash_struct *thc =
1585790075Sobrien    (const struct toc_hash_struct *) hash_entry;
1585890075Sobrien  return rs6000_hash_constant (thc->key) ^ thc->key_mode;
1585990075Sobrien}
1586090075Sobrien
1586190075Sobrien/* Compare H1 and H2 for equivalence.  */
1586290075Sobrien
1586390075Sobrienstatic int
15864132718Skantoc_hash_eq (const void *h1, const void *h2)
1586590075Sobrien{
1586690075Sobrien  rtx r1 = ((const struct toc_hash_struct *) h1)->key;
1586790075Sobrien  rtx r2 = ((const struct toc_hash_struct *) h2)->key;
1586890075Sobrien
1586990075Sobrien  if (((const struct toc_hash_struct *) h1)->key_mode
1587090075Sobrien      != ((const struct toc_hash_struct *) h2)->key_mode)
1587190075Sobrien    return 0;
1587290075Sobrien
15873117395Skan  return rtx_equal_p (r1, r2);
1587490075Sobrien}
1587590075Sobrien
1587690075Sobrien/* These are the names given by the C++ front-end to vtables, and
1587790075Sobrien   vtable-like objects.  Ideally, this logic should not be here;
1587890075Sobrien   instead, there should be some programmatic way of inquiring as
1587990075Sobrien   to whether or not an object is a vtable.  */
1588090075Sobrien
1588190075Sobrien#define VTABLE_NAME_P(NAME)				\
15882169689Skan  (strncmp ("_vt.", name, strlen ("_vt.")) == 0		\
1588390075Sobrien  || strncmp ("_ZTV", name, strlen ("_ZTV")) == 0	\
1588490075Sobrien  || strncmp ("_ZTT", name, strlen ("_ZTT")) == 0	\
15885132718Skan  || strncmp ("_ZTI", name, strlen ("_ZTI")) == 0	\
15886169689Skan  || strncmp ("_ZTC", name, strlen ("_ZTC")) == 0)
1588790075Sobrien
1588890075Sobrienvoid
15889132718Skanrs6000_output_symbol_ref (FILE *file, rtx x)
1589090075Sobrien{
1589190075Sobrien  /* Currently C++ toc references to vtables can be emitted before it
1589290075Sobrien     is decided whether the vtable is public or private.  If this is
1589390075Sobrien     the case, then the linker will eventually complain that there is
15894169689Skan     a reference to an unknown section.  Thus, for vtables only,
1589590075Sobrien     we emit the TOC reference to reference the symbol and not the
1589690075Sobrien     section.  */
1589790075Sobrien  const char *name = XSTR (x, 0);
1589890075Sobrien
15899169689Skan  if (VTABLE_NAME_P (name))
1590090075Sobrien    {
1590190075Sobrien      RS6000_OUTPUT_BASENAME (file, name);
1590290075Sobrien    }
1590390075Sobrien  else
1590490075Sobrien    assemble_name (file, name);
1590590075Sobrien}
1590690075Sobrien
1590790075Sobrien/* Output a TOC entry.  We derive the entry name from what is being
1590890075Sobrien   written.  */
1590990075Sobrien
1591090075Sobrienvoid
15911132718Skanoutput_toc (FILE *file, rtx x, int labelno, enum machine_mode mode)
1591290075Sobrien{
1591390075Sobrien  char buf[256];
1591490075Sobrien  const char *name = buf;
1591590075Sobrien  const char *real_name;
1591690075Sobrien  rtx base = x;
15917169689Skan  HOST_WIDE_INT offset = 0;
1591890075Sobrien
15919169689Skan  gcc_assert (!TARGET_NO_TOC);
1592090075Sobrien
1592190075Sobrien  /* When the linker won't eliminate them, don't output duplicate
1592290075Sobrien     TOC entries (this happens on AIX if there is any kind of TOC,
15923132718Skan     and on SVR4 under -fPIC or -mrelocatable).  Don't do this for
15924132718Skan     CODE_LABELs.  */
15925132718Skan  if (TARGET_TOC && GET_CODE (x) != LABEL_REF)
1592690075Sobrien    {
1592790075Sobrien      struct toc_hash_struct *h;
1592890075Sobrien      void * * found;
15929169689Skan
15930132718Skan      /* Create toc_hash_table.  This can't be done at OVERRIDE_OPTIONS
15931169689Skan	 time because GGC is not initialized at that point.  */
15932132718Skan      if (toc_hash_table == NULL)
15933169689Skan	toc_hash_table = htab_create_ggc (1021, toc_hash_function,
15934132718Skan					  toc_hash_eq, NULL);
15935132718Skan
1593690075Sobrien      h = ggc_alloc (sizeof (*h));
1593790075Sobrien      h->key = x;
1593890075Sobrien      h->key_mode = mode;
1593990075Sobrien      h->labelno = labelno;
15940169689Skan
1594190075Sobrien      found = htab_find_slot (toc_hash_table, h, 1);
1594290075Sobrien      if (*found == NULL)
1594390075Sobrien	*found = h;
15944169689Skan      else  /* This is indeed a duplicate.
1594590075Sobrien	       Set this label equal to that label.  */
1594690075Sobrien	{
1594790075Sobrien	  fputs ("\t.set ", file);
1594890075Sobrien	  ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "LC");
1594990075Sobrien	  fprintf (file, "%d,", labelno);
1595090075Sobrien	  ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "LC");
15951169689Skan	  fprintf (file, "%d\n", ((*(const struct toc_hash_struct **)
1595290075Sobrien					      found)->labelno));
1595390075Sobrien	  return;
1595490075Sobrien	}
1595590075Sobrien    }
1595690075Sobrien
1595790075Sobrien  /* If we're going to put a double constant in the TOC, make sure it's
1595890075Sobrien     aligned properly when strict alignment is on.  */
1595990075Sobrien  if (GET_CODE (x) == CONST_DOUBLE
1596090075Sobrien      && STRICT_ALIGNMENT
1596190075Sobrien      && GET_MODE_BITSIZE (mode) >= 64
1596290075Sobrien      && ! (TARGET_NO_FP_IN_TOC && ! TARGET_MINIMAL_TOC)) {
1596390075Sobrien    ASM_OUTPUT_ALIGN (file, 3);
1596490075Sobrien  }
1596590075Sobrien
15966132718Skan  (*targetm.asm_out.internal_label) (file, "LC", labelno);
1596790075Sobrien
1596890075Sobrien  /* Handle FP constants specially.  Note that if we have a minimal
1596990075Sobrien     TOC, things we put here aren't actually in the TOC, so we can allow
1597090075Sobrien     FP constants.  */
15971169689Skan  if (GET_CODE (x) == CONST_DOUBLE &&
15972169689Skan      (GET_MODE (x) == TFmode || GET_MODE (x) == TDmode))
1597390075Sobrien    {
1597490075Sobrien      REAL_VALUE_TYPE rv;
15975117395Skan      long k[4];
15976117395Skan
15977117395Skan      REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
15978169689Skan      if (DECIMAL_FLOAT_MODE_P (GET_MODE (x)))
15979169689Skan	REAL_VALUE_TO_TARGET_DECIMAL128 (rv, k);
15980169689Skan      else
15981169689Skan	REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, k);
15982117395Skan
15983117395Skan      if (TARGET_64BIT)
15984117395Skan	{
15985117395Skan	  if (TARGET_MINIMAL_TOC)
15986117395Skan	    fputs (DOUBLE_INT_ASM_OP, file);
15987117395Skan	  else
15988117395Skan	    fprintf (file, "\t.tc FT_%lx_%lx_%lx_%lx[TC],",
15989117395Skan		     k[0] & 0xffffffff, k[1] & 0xffffffff,
15990117395Skan		     k[2] & 0xffffffff, k[3] & 0xffffffff);
15991117395Skan	  fprintf (file, "0x%lx%08lx,0x%lx%08lx\n",
15992117395Skan		   k[0] & 0xffffffff, k[1] & 0xffffffff,
15993117395Skan		   k[2] & 0xffffffff, k[3] & 0xffffffff);
15994117395Skan	  return;
15995117395Skan	}
15996117395Skan      else
15997117395Skan	{
15998117395Skan	  if (TARGET_MINIMAL_TOC)
15999117395Skan	    fputs ("\t.long ", file);
16000117395Skan	  else
16001117395Skan	    fprintf (file, "\t.tc FT_%lx_%lx_%lx_%lx[TC],",
16002117395Skan		     k[0] & 0xffffffff, k[1] & 0xffffffff,
16003117395Skan		     k[2] & 0xffffffff, k[3] & 0xffffffff);
16004117395Skan	  fprintf (file, "0x%lx,0x%lx,0x%lx,0x%lx\n",
16005117395Skan		   k[0] & 0xffffffff, k[1] & 0xffffffff,
16006117395Skan		   k[2] & 0xffffffff, k[3] & 0xffffffff);
16007117395Skan	  return;
16008117395Skan	}
16009117395Skan    }
16010169689Skan  else if (GET_CODE (x) == CONST_DOUBLE &&
16011169689Skan	   (GET_MODE (x) == DFmode || GET_MODE (x) == DDmode))
16012117395Skan    {
16013117395Skan      REAL_VALUE_TYPE rv;
1601490075Sobrien      long k[2];
1601590075Sobrien
1601690075Sobrien      REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
1601790075Sobrien
16018169689Skan      if (DECIMAL_FLOAT_MODE_P (GET_MODE (x)))
16019169689Skan	REAL_VALUE_TO_TARGET_DECIMAL64 (rv, k);
16020169689Skan      else
16021169689Skan	REAL_VALUE_TO_TARGET_DOUBLE (rv, k);
16022169689Skan
1602390075Sobrien      if (TARGET_64BIT)
1602490075Sobrien	{
1602590075Sobrien	  if (TARGET_MINIMAL_TOC)
1602690075Sobrien	    fputs (DOUBLE_INT_ASM_OP, file);
1602790075Sobrien	  else
16028102780Skan	    fprintf (file, "\t.tc FD_%lx_%lx[TC],",
16029102780Skan		     k[0] & 0xffffffff, k[1] & 0xffffffff);
16030102780Skan	  fprintf (file, "0x%lx%08lx\n",
16031102780Skan		   k[0] & 0xffffffff, k[1] & 0xffffffff);
1603290075Sobrien	  return;
1603390075Sobrien	}
1603490075Sobrien      else
1603590075Sobrien	{
1603690075Sobrien	  if (TARGET_MINIMAL_TOC)
1603790075Sobrien	    fputs ("\t.long ", file);
1603890075Sobrien	  else
16039102780Skan	    fprintf (file, "\t.tc FD_%lx_%lx[TC],",
16040102780Skan		     k[0] & 0xffffffff, k[1] & 0xffffffff);
16041102780Skan	  fprintf (file, "0x%lx,0x%lx\n",
16042102780Skan		   k[0] & 0xffffffff, k[1] & 0xffffffff);
1604390075Sobrien	  return;
1604490075Sobrien	}
1604590075Sobrien    }
16046169689Skan  else if (GET_CODE (x) == CONST_DOUBLE &&
16047169689Skan	   (GET_MODE (x) == SFmode || GET_MODE (x) == SDmode))
1604890075Sobrien    {
1604990075Sobrien      REAL_VALUE_TYPE rv;
1605090075Sobrien      long l;
1605190075Sobrien
1605290075Sobrien      REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
16053169689Skan      if (DECIMAL_FLOAT_MODE_P (GET_MODE (x)))
16054169689Skan	REAL_VALUE_TO_TARGET_DECIMAL32 (rv, l);
16055169689Skan      else
16056169689Skan	REAL_VALUE_TO_TARGET_SINGLE (rv, l);
1605790075Sobrien
1605890075Sobrien      if (TARGET_64BIT)
1605990075Sobrien	{
1606090075Sobrien	  if (TARGET_MINIMAL_TOC)
1606190075Sobrien	    fputs (DOUBLE_INT_ASM_OP, file);
1606290075Sobrien	  else
16063102780Skan	    fprintf (file, "\t.tc FS_%lx[TC],", l & 0xffffffff);
16064102780Skan	  fprintf (file, "0x%lx00000000\n", l & 0xffffffff);
1606590075Sobrien	  return;
1606690075Sobrien	}
1606790075Sobrien      else
1606890075Sobrien	{
1606990075Sobrien	  if (TARGET_MINIMAL_TOC)
1607090075Sobrien	    fputs ("\t.long ", file);
1607190075Sobrien	  else
16072102780Skan	    fprintf (file, "\t.tc FS_%lx[TC],", l & 0xffffffff);
16073102780Skan	  fprintf (file, "0x%lx\n", l & 0xffffffff);
1607490075Sobrien	  return;
1607590075Sobrien	}
1607690075Sobrien    }
1607790075Sobrien  else if (GET_MODE (x) == VOIDmode
1607890075Sobrien	   && (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE))
1607990075Sobrien    {
1608090075Sobrien      unsigned HOST_WIDE_INT low;
1608190075Sobrien      HOST_WIDE_INT high;
1608290075Sobrien
1608390075Sobrien      if (GET_CODE (x) == CONST_DOUBLE)
1608490075Sobrien	{
1608590075Sobrien	  low = CONST_DOUBLE_LOW (x);
1608690075Sobrien	  high = CONST_DOUBLE_HIGH (x);
1608790075Sobrien	}
1608890075Sobrien      else
1608990075Sobrien#if HOST_BITS_PER_WIDE_INT == 32
1609090075Sobrien	{
1609190075Sobrien	  low = INTVAL (x);
1609290075Sobrien	  high = (low & 0x80000000) ? ~0 : 0;
1609390075Sobrien	}
1609490075Sobrien#else
1609590075Sobrien	{
16096169689Skan	  low = INTVAL (x) & 0xffffffff;
16097169689Skan	  high = (HOST_WIDE_INT) INTVAL (x) >> 32;
1609890075Sobrien	}
1609990075Sobrien#endif
1610090075Sobrien
1610190075Sobrien      /* TOC entries are always Pmode-sized, but since this
1610290075Sobrien	 is a bigendian machine then if we're putting smaller
1610390075Sobrien	 integer constants in the TOC we have to pad them.
1610490075Sobrien	 (This is still a win over putting the constants in
1610590075Sobrien	 a separate constant pool, because then we'd have
1610690075Sobrien	 to have both a TOC entry _and_ the actual constant.)
1610790075Sobrien
1610890075Sobrien	 For a 32-bit target, CONST_INT values are loaded and shifted
1610990075Sobrien	 entirely within `low' and can be stored in one TOC entry.  */
1611090075Sobrien
16111169689Skan      /* It would be easy to make this work, but it doesn't now.  */
16112169689Skan      gcc_assert (!TARGET_64BIT || POINTER_SIZE >= GET_MODE_BITSIZE (mode));
1611390075Sobrien
1611490075Sobrien      if (POINTER_SIZE > GET_MODE_BITSIZE (mode))
16115103445Skan	{
16116103445Skan#if HOST_BITS_PER_WIDE_INT == 32
16117103445Skan	  lshift_double (low, high, POINTER_SIZE - GET_MODE_BITSIZE (mode),
16118103445Skan			 POINTER_SIZE, &low, &high, 0);
16119103445Skan#else
16120103445Skan	  low |= high << 32;
16121103445Skan	  low <<= POINTER_SIZE - GET_MODE_BITSIZE (mode);
16122103445Skan	  high = (HOST_WIDE_INT) low >> 32;
16123103445Skan	  low &= 0xffffffff;
16124103445Skan#endif
16125103445Skan	}
1612690075Sobrien
1612790075Sobrien      if (TARGET_64BIT)
1612890075Sobrien	{
1612990075Sobrien	  if (TARGET_MINIMAL_TOC)
1613090075Sobrien	    fputs (DOUBLE_INT_ASM_OP, file);
1613190075Sobrien	  else
16132102780Skan	    fprintf (file, "\t.tc ID_%lx_%lx[TC],",
16133102780Skan		     (long) high & 0xffffffff, (long) low & 0xffffffff);
16134102780Skan	  fprintf (file, "0x%lx%08lx\n",
16135102780Skan		   (long) high & 0xffffffff, (long) low & 0xffffffff);
1613690075Sobrien	  return;
1613790075Sobrien	}
1613890075Sobrien      else
1613990075Sobrien	{
1614090075Sobrien	  if (POINTER_SIZE < GET_MODE_BITSIZE (mode))
1614190075Sobrien	    {
1614290075Sobrien	      if (TARGET_MINIMAL_TOC)
1614390075Sobrien		fputs ("\t.long ", file);
1614490075Sobrien	      else
1614590075Sobrien		fprintf (file, "\t.tc ID_%lx_%lx[TC],",
16146102780Skan			 (long) high & 0xffffffff, (long) low & 0xffffffff);
16147102780Skan	      fprintf (file, "0x%lx,0x%lx\n",
16148102780Skan		       (long) high & 0xffffffff, (long) low & 0xffffffff);
1614990075Sobrien	    }
1615090075Sobrien	  else
1615190075Sobrien	    {
1615290075Sobrien	      if (TARGET_MINIMAL_TOC)
1615390075Sobrien		fputs ("\t.long ", file);
1615490075Sobrien	      else
16155102780Skan		fprintf (file, "\t.tc IS_%lx[TC],", (long) low & 0xffffffff);
16156102780Skan	      fprintf (file, "0x%lx\n", (long) low & 0xffffffff);
1615790075Sobrien	    }
1615890075Sobrien	  return;
1615990075Sobrien	}
1616090075Sobrien    }
1616190075Sobrien
1616290075Sobrien  if (GET_CODE (x) == CONST)
1616390075Sobrien    {
16164169689Skan      gcc_assert (GET_CODE (XEXP (x, 0)) == PLUS);
1616590075Sobrien
1616690075Sobrien      base = XEXP (XEXP (x, 0), 0);
1616790075Sobrien      offset = INTVAL (XEXP (XEXP (x, 0), 1));
1616890075Sobrien    }
1616990075Sobrien
16170169689Skan  switch (GET_CODE (base))
16171169689Skan    {
16172169689Skan    case SYMBOL_REF:
16173169689Skan      name = XSTR (base, 0);
16174169689Skan      break;
16175169689Skan
16176169689Skan    case LABEL_REF:
16177169689Skan      ASM_GENERATE_INTERNAL_LABEL (buf, "L",
16178169689Skan				   CODE_LABEL_NUMBER (XEXP (base, 0)));
16179169689Skan      break;
16180169689Skan
16181169689Skan    case CODE_LABEL:
16182169689Skan      ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (base));
16183169689Skan      break;
16184169689Skan
16185169689Skan    default:
16186169689Skan      gcc_unreachable ();
16187169689Skan    }
16188169689Skan
16189117395Skan  real_name = (*targetm.strip_name_encoding) (name);
1619090075Sobrien  if (TARGET_MINIMAL_TOC)
1619190075Sobrien    fputs (TARGET_32BIT ? "\t.long " : DOUBLE_INT_ASM_OP, file);
1619290075Sobrien  else
1619390075Sobrien    {
1619490075Sobrien      fprintf (file, "\t.tc %s", real_name);
1619590075Sobrien
1619690075Sobrien      if (offset < 0)
16197169689Skan	fprintf (file, ".N" HOST_WIDE_INT_PRINT_UNSIGNED, - offset);
1619890075Sobrien      else if (offset)
16199169689Skan	fprintf (file, ".P" HOST_WIDE_INT_PRINT_UNSIGNED, offset);
1620090075Sobrien
1620190075Sobrien      fputs ("[TC],", file);
1620290075Sobrien    }
1620390075Sobrien
1620490075Sobrien  /* Currently C++ toc references to vtables can be emitted before it
1620590075Sobrien     is decided whether the vtable is public or private.  If this is
1620690075Sobrien     the case, then the linker will eventually complain that there is
1620790075Sobrien     a TOC reference to an unknown section.  Thus, for vtables only,
1620890075Sobrien     we emit the TOC reference to reference the symbol and not the
1620990075Sobrien     section.  */
1621090075Sobrien  if (VTABLE_NAME_P (name))
1621190075Sobrien    {
1621290075Sobrien      RS6000_OUTPUT_BASENAME (file, name);
1621390075Sobrien      if (offset < 0)
16214169689Skan	fprintf (file, HOST_WIDE_INT_PRINT_DEC, offset);
1621590075Sobrien      else if (offset > 0)
16216169689Skan	fprintf (file, "+" HOST_WIDE_INT_PRINT_DEC, offset);
1621790075Sobrien    }
1621890075Sobrien  else
1621990075Sobrien    output_addr_const (file, x);
1622090075Sobrien  putc ('\n', file);
1622190075Sobrien}
1622290075Sobrien
1622390075Sobrien/* Output an assembler pseudo-op to write an ASCII string of N characters
1622490075Sobrien   starting at P to FILE.
1622590075Sobrien
1622690075Sobrien   On the RS/6000, we have to do this using the .byte operation and
1622790075Sobrien   write out special characters outside the quoted string.
1622890075Sobrien   Also, the assembler is broken; very long strings are truncated,
1622990075Sobrien   so we must artificially break them up early.  */
1623090075Sobrien
1623190075Sobrienvoid
16232132718Skanoutput_ascii (FILE *file, const char *p, int n)
1623390075Sobrien{
1623490075Sobrien  char c;
1623590075Sobrien  int i, count_string;
1623690075Sobrien  const char *for_string = "\t.byte \"";
1623790075Sobrien  const char *for_decimal = "\t.byte ";
1623890075Sobrien  const char *to_close = NULL;
1623990075Sobrien
1624090075Sobrien  count_string = 0;
1624190075Sobrien  for (i = 0; i < n; i++)
1624290075Sobrien    {
1624390075Sobrien      c = *p++;
1624490075Sobrien      if (c >= ' ' && c < 0177)
1624590075Sobrien	{
1624690075Sobrien	  if (for_string)
1624790075Sobrien	    fputs (for_string, file);
1624890075Sobrien	  putc (c, file);
1624990075Sobrien
1625090075Sobrien	  /* Write two quotes to get one.  */
1625190075Sobrien	  if (c == '"')
1625290075Sobrien	    {
1625390075Sobrien	      putc (c, file);
1625490075Sobrien	      ++count_string;
1625590075Sobrien	    }
1625690075Sobrien
1625790075Sobrien	  for_string = NULL;
1625890075Sobrien	  for_decimal = "\"\n\t.byte ";
1625990075Sobrien	  to_close = "\"\n";
1626090075Sobrien	  ++count_string;
1626190075Sobrien
1626290075Sobrien	  if (count_string >= 512)
1626390075Sobrien	    {
1626490075Sobrien	      fputs (to_close, file);
1626590075Sobrien
1626690075Sobrien	      for_string = "\t.byte \"";
1626790075Sobrien	      for_decimal = "\t.byte ";
1626890075Sobrien	      to_close = NULL;
1626990075Sobrien	      count_string = 0;
1627090075Sobrien	    }
1627190075Sobrien	}
1627290075Sobrien      else
1627390075Sobrien	{
1627490075Sobrien	  if (for_decimal)
1627590075Sobrien	    fputs (for_decimal, file);
1627690075Sobrien	  fprintf (file, "%d", c);
1627790075Sobrien
1627890075Sobrien	  for_string = "\n\t.byte \"";
1627990075Sobrien	  for_decimal = ", ";
1628090075Sobrien	  to_close = "\n";
1628190075Sobrien	  count_string = 0;
1628290075Sobrien	}
1628390075Sobrien    }
1628490075Sobrien
1628590075Sobrien  /* Now close the string if we have written one.  Then end the line.  */
1628690075Sobrien  if (to_close)
1628790075Sobrien    fputs (to_close, file);
1628890075Sobrien}
1628990075Sobrien
1629090075Sobrien/* Generate a unique section name for FILENAME for a section type
1629190075Sobrien   represented by SECTION_DESC.  Output goes into BUF.
1629290075Sobrien
1629390075Sobrien   SECTION_DESC can be any string, as long as it is different for each
1629490075Sobrien   possible section type.
1629590075Sobrien
1629690075Sobrien   We name the section in the same manner as xlc.  The name begins with an
1629790075Sobrien   underscore followed by the filename (after stripping any leading directory
1629890075Sobrien   names) with the last period replaced by the string SECTION_DESC.  If
1629990075Sobrien   FILENAME does not contain a period, SECTION_DESC is appended to the end of
1630090075Sobrien   the name.  */
1630190075Sobrien
1630290075Sobrienvoid
16303169689Skanrs6000_gen_section_name (char **buf, const char *filename,
16304169689Skan			 const char *section_desc)
1630590075Sobrien{
1630690075Sobrien  const char *q, *after_last_slash, *last_period = 0;
1630790075Sobrien  char *p;
1630890075Sobrien  int len;
1630990075Sobrien
1631090075Sobrien  after_last_slash = filename;
1631190075Sobrien  for (q = filename; *q; q++)
1631290075Sobrien    {
1631390075Sobrien      if (*q == '/')
1631490075Sobrien	after_last_slash = q + 1;
1631590075Sobrien      else if (*q == '.')
1631690075Sobrien	last_period = q;
1631790075Sobrien    }
1631890075Sobrien
1631990075Sobrien  len = strlen (after_last_slash) + strlen (section_desc) + 2;
16320117395Skan  *buf = (char *) xmalloc (len);
1632190075Sobrien
1632290075Sobrien  p = *buf;
1632390075Sobrien  *p++ = '_';
1632490075Sobrien
1632590075Sobrien  for (q = after_last_slash; *q; q++)
1632690075Sobrien    {
1632790075Sobrien      if (q == last_period)
16328169689Skan	{
1632990075Sobrien	  strcpy (p, section_desc);
1633090075Sobrien	  p += strlen (section_desc);
16331132718Skan	  break;
16332169689Skan	}
1633390075Sobrien
1633490075Sobrien      else if (ISALNUM (*q))
16335169689Skan	*p++ = *q;
1633690075Sobrien    }
1633790075Sobrien
1633890075Sobrien  if (last_period == 0)
1633990075Sobrien    strcpy (p, section_desc);
1634090075Sobrien  else
1634190075Sobrien    *p = '\0';
1634290075Sobrien}
1634390075Sobrien
1634490075Sobrien/* Emit profile function.  */
1634590075Sobrien
1634690075Sobrienvoid
16347132718Skanoutput_profile_hook (int labelno ATTRIBUTE_UNUSED)
1634890075Sobrien{
16349169689Skan  /* Non-standard profiling for kernels, which just saves LR then calls
16350169689Skan     _mcount without worrying about arg saves.  The idea is to change
16351169689Skan     the function prologue as little as possible as it isn't easy to
16352169689Skan     account for arg save/restore code added just for _mcount.  */
16353132718Skan  if (TARGET_PROFILE_KERNEL)
16354132718Skan    return;
16355132718Skan
1635690075Sobrien  if (DEFAULT_ABI == ABI_AIX)
1635790075Sobrien    {
16358132718Skan#ifndef NO_PROFILE_COUNTERS
16359132718Skan# define NO_PROFILE_COUNTERS 0
16360132718Skan#endif
16361169689Skan      if (NO_PROFILE_COUNTERS)
16362132718Skan	emit_library_call (init_one_libfunc (RS6000_MCOUNT), 0, VOIDmode, 0);
16363132718Skan      else
16364132718Skan	{
16365132718Skan	  char buf[30];
16366132718Skan	  const char *label_name;
16367132718Skan	  rtx fun;
1636890075Sobrien
16369132718Skan	  ASM_GENERATE_INTERNAL_LABEL (buf, "LP", labelno);
16370132718Skan	  label_name = (*targetm.strip_name_encoding) (ggc_strdup (buf));
16371132718Skan	  fun = gen_rtx_SYMBOL_REF (Pmode, label_name);
1637290075Sobrien
16373132718Skan	  emit_library_call (init_one_libfunc (RS6000_MCOUNT), 0, VOIDmode, 1,
16374132718Skan			     fun, Pmode);
16375132718Skan	}
1637690075Sobrien    }
1637790075Sobrien  else if (DEFAULT_ABI == ABI_DARWIN)
1637890075Sobrien    {
1637990075Sobrien      const char *mcount_name = RS6000_MCOUNT;
1638090075Sobrien      int caller_addr_regno = LINK_REGISTER_REGNUM;
1638190075Sobrien
1638290075Sobrien      /* Be conservative and always set this, at least for now.  */
1638390075Sobrien      current_function_uses_pic_offset_table = 1;
1638490075Sobrien
1638590075Sobrien#if TARGET_MACHO
1638690075Sobrien      /* For PIC code, set up a stub and collect the caller's address
1638790075Sobrien	 from r0, which is where the prologue puts it.  */
16388169689Skan      if (MACHOPIC_INDIRECT
16389169689Skan	  && current_function_uses_pic_offset_table)
16390169689Skan	caller_addr_regno = 0;
1639190075Sobrien#endif
1639290075Sobrien      emit_library_call (gen_rtx_SYMBOL_REF (Pmode, mcount_name),
1639390075Sobrien			 0, VOIDmode, 1,
1639490075Sobrien			 gen_rtx_REG (Pmode, caller_addr_regno), Pmode);
1639590075Sobrien    }
1639690075Sobrien}
1639790075Sobrien
1639890075Sobrien/* Write function profiler code.  */
1639990075Sobrien
1640090075Sobrienvoid
16401132718Skanoutput_function_profiler (FILE *file, int labelno)
1640290075Sobrien{
1640390075Sobrien  char buf[100];
1640490075Sobrien
1640590075Sobrien  switch (DEFAULT_ABI)
1640690075Sobrien    {
1640790075Sobrien    default:
16408169689Skan      gcc_unreachable ();
1640990075Sobrien
1641090075Sobrien    case ABI_V4:
16411103445Skan      if (!TARGET_32BIT)
16412103445Skan	{
16413169689Skan	  warning (0, "no profiling of 64-bit code for this ABI");
16414103445Skan	  return;
16415103445Skan	}
16416132718Skan      ASM_GENERATE_INTERNAL_LABEL (buf, "LP", labelno);
1641790075Sobrien      fprintf (file, "\tmflr %s\n", reg_names[0]);
16418169689Skan      if (NO_PROFILE_COUNTERS)
1641990075Sobrien	{
16420169689Skan	  asm_fprintf (file, "\t{st|stw} %s,4(%s)\n",
16421169689Skan		       reg_names[0], reg_names[1]);
16422169689Skan	}
16423169689Skan      else if (TARGET_SECURE_PLT && flag_pic)
16424169689Skan	{
16425169689Skan	  asm_fprintf (file, "\tbcl 20,31,1f\n1:\n\t{st|stw} %s,4(%s)\n",
16426169689Skan		       reg_names[0], reg_names[1]);
16427169689Skan	  asm_fprintf (file, "\tmflr %s\n", reg_names[12]);
16428169689Skan	  asm_fprintf (file, "\t{cau|addis} %s,%s,",
16429169689Skan		       reg_names[12], reg_names[12]);
16430169689Skan	  assemble_name (file, buf);
16431169689Skan	  asm_fprintf (file, "-1b@ha\n\t{cal|la} %s,", reg_names[0]);
16432169689Skan	  assemble_name (file, buf);
16433169689Skan	  asm_fprintf (file, "-1b@l(%s)\n", reg_names[12]);
16434169689Skan	}
16435169689Skan      else if (flag_pic == 1)
16436169689Skan	{
1643790075Sobrien	  fputs ("\tbl _GLOBAL_OFFSET_TABLE_@local-4\n", file);
16438169689Skan	  asm_fprintf (file, "\t{st|stw} %s,4(%s)\n",
16439169689Skan		       reg_names[0], reg_names[1]);
1644090075Sobrien	  asm_fprintf (file, "\tmflr %s\n", reg_names[12]);
1644190075Sobrien	  asm_fprintf (file, "\t{l|lwz} %s,", reg_names[0]);
1644290075Sobrien	  assemble_name (file, buf);
1644390075Sobrien	  asm_fprintf (file, "@got(%s)\n", reg_names[12]);
1644490075Sobrien	}
1644590075Sobrien      else if (flag_pic > 1)
1644690075Sobrien	{
16447169689Skan	  asm_fprintf (file, "\t{st|stw} %s,4(%s)\n",
16448169689Skan		       reg_names[0], reg_names[1]);
1644990075Sobrien	  /* Now, we need to get the address of the label.  */
16450169689Skan	  fputs ("\tbcl 20,31,1f\n\t.long ", file);
1645190075Sobrien	  assemble_name (file, buf);
1645290075Sobrien	  fputs ("-.\n1:", file);
1645390075Sobrien	  asm_fprintf (file, "\tmflr %s\n", reg_names[11]);
16454169689Skan	  asm_fprintf (file, "\t{l|lwz} %s,0(%s)\n",
1645590075Sobrien		       reg_names[0], reg_names[11]);
1645690075Sobrien	  asm_fprintf (file, "\t{cax|add} %s,%s,%s\n",
1645790075Sobrien		       reg_names[0], reg_names[0], reg_names[11]);
1645890075Sobrien	}
1645990075Sobrien      else
1646090075Sobrien	{
1646190075Sobrien	  asm_fprintf (file, "\t{liu|lis} %s,", reg_names[12]);
1646290075Sobrien	  assemble_name (file, buf);
1646390075Sobrien	  fputs ("@ha\n", file);
16464169689Skan	  asm_fprintf (file, "\t{st|stw} %s,4(%s)\n",
16465169689Skan		       reg_names[0], reg_names[1]);
1646690075Sobrien	  asm_fprintf (file, "\t{cal|la} %s,", reg_names[0]);
1646790075Sobrien	  assemble_name (file, buf);
1646890075Sobrien	  asm_fprintf (file, "@l(%s)\n", reg_names[12]);
1646990075Sobrien	}
1647090075Sobrien
16471132718Skan      /* ABI_V4 saves the static chain reg with ASM_OUTPUT_REG_PUSH.  */
16472132718Skan      fprintf (file, "\tbl %s%s\n",
16473132718Skan	       RS6000_MCOUNT, flag_pic ? "@plt" : "");
16474132718Skan      break;
16475132718Skan
16476132718Skan    case ABI_AIX:
16477132718Skan    case ABI_DARWIN:
16478132718Skan      if (!TARGET_PROFILE_KERNEL)
16479103445Skan	{
16480132718Skan	  /* Don't do anything, done in output_profile_hook ().  */
16481103445Skan	}
16482103445Skan      else
16483132718Skan	{
16484169689Skan	  gcc_assert (!TARGET_32BIT);
1648590075Sobrien
16486132718Skan	  asm_fprintf (file, "\tmflr %s\n", reg_names[0]);
16487132718Skan	  asm_fprintf (file, "\tstd %s,16(%s)\n", reg_names[0], reg_names[1]);
16488132718Skan
16489169689Skan	  if (cfun->static_chain_decl != NULL)
16490132718Skan	    {
16491132718Skan	      asm_fprintf (file, "\tstd %s,24(%s)\n",
16492132718Skan			   reg_names[STATIC_CHAIN_REGNUM], reg_names[1]);
16493132718Skan	      fprintf (file, "\tbl %s\n", RS6000_MCOUNT);
16494132718Skan	      asm_fprintf (file, "\tld %s,24(%s)\n",
16495132718Skan			   reg_names[STATIC_CHAIN_REGNUM], reg_names[1]);
16496132718Skan	    }
16497132718Skan	  else
16498132718Skan	    fprintf (file, "\tbl %s\n", RS6000_MCOUNT);
16499132718Skan	}
1650090075Sobrien      break;
1650190075Sobrien    }
1650290075Sobrien}
1650390075Sobrien
16504132718Skan
16505132718Skan/* Power4 load update and store update instructions are cracked into a
16506132718Skan   load or store and an integer insn which are executed in the same cycle.
16507132718Skan   Branches have their own dispatch slot which does not count against the
16508132718Skan   GCC issue rate, but it changes the program flow so there are no other
16509132718Skan   instructions to issue in this cycle.  */
16510132718Skan
16511132718Skanstatic int
16512169689Skanrs6000_variable_issue (FILE *stream ATTRIBUTE_UNUSED,
16513169689Skan		       int verbose ATTRIBUTE_UNUSED,
16514132718Skan		       rtx insn, int more)
16515132718Skan{
16516132718Skan  if (GET_CODE (PATTERN (insn)) == USE
16517132718Skan      || GET_CODE (PATTERN (insn)) == CLOBBER)
16518132718Skan    return more;
16519132718Skan
16520132718Skan  if (rs6000_sched_groups)
16521132718Skan    {
16522132718Skan      if (is_microcoded_insn (insn))
16523169689Skan	return 0;
16524132718Skan      else if (is_cracked_insn (insn))
16525169689Skan	return more > 2 ? more - 2 : 0;
16526132718Skan    }
16527132718Skan
16528132718Skan  return more - 1;
16529132718Skan}
16530132718Skan
1653190075Sobrien/* Adjust the cost of a scheduling dependency.  Return the new cost of
1653290075Sobrien   a dependency LINK or INSN on DEP_INSN.  COST is the current cost.  */
1653390075Sobrien
1653490075Sobrienstatic int
16535169689Skanrs6000_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
1653690075Sobrien{
1653790075Sobrien  if (! recog_memoized (insn))
1653890075Sobrien    return 0;
1653990075Sobrien
1654090075Sobrien  if (REG_NOTE_KIND (link) != 0)
1654190075Sobrien    return 0;
1654290075Sobrien
1654390075Sobrien  if (REG_NOTE_KIND (link) == 0)
1654490075Sobrien    {
1654590075Sobrien      /* Data dependency; DEP_INSN writes a register that INSN reads
1654690075Sobrien	 some cycles later.  */
16547169689Skan
16548169689Skan      /* Separate a load from a narrower, dependent store.  */
16549169689Skan      if (rs6000_sched_groups
16550169689Skan	  && GET_CODE (PATTERN (insn)) == SET
16551169689Skan	  && GET_CODE (PATTERN (dep_insn)) == SET
16552169689Skan	  && GET_CODE (XEXP (PATTERN (insn), 1)) == MEM
16553169689Skan	  && GET_CODE (XEXP (PATTERN (dep_insn), 0)) == MEM
16554169689Skan	  && (GET_MODE_SIZE (GET_MODE (XEXP (PATTERN (insn), 1)))
16555169689Skan	      > GET_MODE_SIZE (GET_MODE (XEXP (PATTERN (dep_insn), 0)))))
16556169689Skan	return cost + 14;
16557169689Skan
1655890075Sobrien      switch (get_attr_type (insn))
1655990075Sobrien	{
1656090075Sobrien	case TYPE_JMPREG:
16561117395Skan	  /* Tell the first scheduling pass about the latency between
1656290075Sobrien	     a mtctr and bctr (and mtlr and br/blr).  The first
1656390075Sobrien	     scheduling pass will not know about this latency since
1656490075Sobrien	     the mtctr instruction, which has the latency associated
1656590075Sobrien	     to it, will be generated by reload.  */
16566117395Skan	  return TARGET_POWER ? 5 : 4;
1656790075Sobrien	case TYPE_BRANCH:
1656890075Sobrien	  /* Leave some extra cycles between a compare and its
1656990075Sobrien	     dependent branch, to inhibit expensive mispredicts.  */
16570117395Skan	  if ((rs6000_cpu_attr == CPU_PPC603
16571117395Skan	       || rs6000_cpu_attr == CPU_PPC604
16572117395Skan	       || rs6000_cpu_attr == CPU_PPC604E
16573117395Skan	       || rs6000_cpu_attr == CPU_PPC620
16574117395Skan	       || rs6000_cpu_attr == CPU_PPC630
16575117395Skan	       || rs6000_cpu_attr == CPU_PPC750
16576117395Skan	       || rs6000_cpu_attr == CPU_PPC7400
16577117395Skan	       || rs6000_cpu_attr == CPU_PPC7450
16578132718Skan	       || rs6000_cpu_attr == CPU_POWER4
16579132718Skan	       || rs6000_cpu_attr == CPU_POWER5)
1658090075Sobrien	      && recog_memoized (dep_insn)
1658190075Sobrien	      && (INSN_CODE (dep_insn) >= 0)
16582132718Skan	      && (get_attr_type (dep_insn) == TYPE_CMP
16583132718Skan		  || get_attr_type (dep_insn) == TYPE_COMPARE
1658490075Sobrien		  || get_attr_type (dep_insn) == TYPE_DELAYED_COMPARE
16585132718Skan		  || get_attr_type (dep_insn) == TYPE_IMUL_COMPARE
16586132718Skan		  || get_attr_type (dep_insn) == TYPE_LMUL_COMPARE
1658790075Sobrien		  || get_attr_type (dep_insn) == TYPE_FPCOMPARE
16588132718Skan		  || get_attr_type (dep_insn) == TYPE_CR_LOGICAL
16589132718Skan		  || get_attr_type (dep_insn) == TYPE_DELAYED_CR))
1659090075Sobrien	    return cost + 2;
1659190075Sobrien	default:
1659290075Sobrien	  break;
1659390075Sobrien	}
1659490075Sobrien      /* Fall out to return default cost.  */
1659590075Sobrien    }
1659690075Sobrien
1659790075Sobrien  return cost;
1659890075Sobrien}
1659990075Sobrien
16600132718Skan/* The function returns a true if INSN is microcoded.
16601132718Skan   Return false otherwise.  */
16602132718Skan
16603132718Skanstatic bool
16604132718Skanis_microcoded_insn (rtx insn)
16605132718Skan{
16606132718Skan  if (!insn || !INSN_P (insn)
16607132718Skan      || GET_CODE (PATTERN (insn)) == USE
16608132718Skan      || GET_CODE (PATTERN (insn)) == CLOBBER)
16609132718Skan    return false;
16610132718Skan
16611132718Skan  if (rs6000_sched_groups)
16612132718Skan    {
16613132718Skan      enum attr_type type = get_attr_type (insn);
16614132718Skan      if (type == TYPE_LOAD_EXT_U
16615132718Skan	  || type == TYPE_LOAD_EXT_UX
16616132718Skan	  || type == TYPE_LOAD_UX
16617132718Skan	  || type == TYPE_STORE_UX
16618132718Skan	  || type == TYPE_MFCR)
16619169689Skan	return true;
16620132718Skan    }
16621132718Skan
16622132718Skan  return false;
16623132718Skan}
16624132718Skan
16625132718Skan/* The function returns a nonzero value if INSN can be scheduled only
16626132718Skan   as the first insn in a dispatch group ("dispatch-slot restricted").
16627132718Skan   In this case, the returned value indicates how many dispatch slots
16628132718Skan   the insn occupies (at the beginning of the group).
16629132718Skan   Return 0 otherwise.  */
16630132718Skan
16631132718Skanstatic int
16632132718Skanis_dispatch_slot_restricted (rtx insn)
16633132718Skan{
16634132718Skan  enum attr_type type;
16635132718Skan
16636132718Skan  if (!rs6000_sched_groups)
16637132718Skan    return 0;
16638132718Skan
16639132718Skan  if (!insn
16640132718Skan      || insn == NULL_RTX
16641132718Skan      || GET_CODE (insn) == NOTE
16642132718Skan      || GET_CODE (PATTERN (insn)) == USE
16643132718Skan      || GET_CODE (PATTERN (insn)) == CLOBBER)
16644132718Skan    return 0;
16645132718Skan
16646132718Skan  type = get_attr_type (insn);
16647132718Skan
16648132718Skan  switch (type)
16649132718Skan    {
16650132718Skan    case TYPE_MFCR:
16651132718Skan    case TYPE_MFCRF:
16652132718Skan    case TYPE_MTCR:
16653132718Skan    case TYPE_DELAYED_CR:
16654132718Skan    case TYPE_CR_LOGICAL:
16655132718Skan    case TYPE_MTJMPR:
16656132718Skan    case TYPE_MFJMPR:
16657132718Skan      return 1;
16658132718Skan    case TYPE_IDIV:
16659132718Skan    case TYPE_LDIV:
16660132718Skan      return 2;
16661169689Skan    case TYPE_LOAD_L:
16662169689Skan    case TYPE_STORE_C:
16663169689Skan    case TYPE_ISYNC:
16664169689Skan    case TYPE_SYNC:
16665169689Skan      return 4;
16666132718Skan    default:
16667132718Skan      if (rs6000_cpu == PROCESSOR_POWER5
16668132718Skan	  && is_cracked_insn (insn))
16669132718Skan	return 2;
16670132718Skan      return 0;
16671132718Skan    }
16672132718Skan}
16673132718Skan
16674132718Skan/* The function returns true if INSN is cracked into 2 instructions
16675132718Skan   by the processor (and therefore occupies 2 issue slots).  */
16676132718Skan
16677132718Skanstatic bool
16678132718Skanis_cracked_insn (rtx insn)
16679132718Skan{
16680132718Skan  if (!insn || !INSN_P (insn)
16681132718Skan      || GET_CODE (PATTERN (insn)) == USE
16682132718Skan      || GET_CODE (PATTERN (insn)) == CLOBBER)
16683132718Skan    return false;
16684132718Skan
16685132718Skan  if (rs6000_sched_groups)
16686132718Skan    {
16687132718Skan      enum attr_type type = get_attr_type (insn);
16688132718Skan      if (type == TYPE_LOAD_U || type == TYPE_STORE_U
16689169689Skan	  || type == TYPE_FPLOAD_U || type == TYPE_FPSTORE_U
16690169689Skan	  || type == TYPE_FPLOAD_UX || type == TYPE_FPSTORE_UX
16691169689Skan	  || type == TYPE_LOAD_EXT || type == TYPE_DELAYED_CR
16692169689Skan	  || type == TYPE_COMPARE || type == TYPE_DELAYED_COMPARE
16693169689Skan	  || type == TYPE_IMUL_COMPARE || type == TYPE_LMUL_COMPARE
16694169689Skan	  || type == TYPE_IDIV || type == TYPE_LDIV
16695169689Skan	  || type == TYPE_INSERT_WORD)
16696169689Skan	return true;
16697132718Skan    }
16698132718Skan
16699132718Skan  return false;
16700132718Skan}
16701132718Skan
16702132718Skan/* The function returns true if INSN can be issued only from
16703132718Skan   the branch slot.  */
16704132718Skan
16705132718Skanstatic bool
16706132718Skanis_branch_slot_insn (rtx insn)
16707132718Skan{
16708132718Skan  if (!insn || !INSN_P (insn)
16709132718Skan      || GET_CODE (PATTERN (insn)) == USE
16710132718Skan      || GET_CODE (PATTERN (insn)) == CLOBBER)
16711132718Skan    return false;
16712132718Skan
16713132718Skan  if (rs6000_sched_groups)
16714132718Skan    {
16715132718Skan      enum attr_type type = get_attr_type (insn);
16716132718Skan      if (type == TYPE_BRANCH || type == TYPE_JMPREG)
16717169689Skan	return true;
16718132718Skan      return false;
16719132718Skan    }
16720132718Skan
16721132718Skan  return false;
16722132718Skan}
16723132718Skan
1672490075Sobrien/* A C statement (sans semicolon) to update the integer scheduling
16725132718Skan   priority INSN_PRIORITY (INSN). Increase the priority to execute the
16726132718Skan   INSN earlier, reduce the priority to execute INSN later.  Do not
1672790075Sobrien   define this macro if you do not need to adjust the scheduling
1672890075Sobrien   priorities of insns.  */
1672990075Sobrien
1673090075Sobrienstatic int
16731132718Skanrs6000_adjust_priority (rtx insn ATTRIBUTE_UNUSED, int priority)
1673290075Sobrien{
1673390075Sobrien  /* On machines (like the 750) which have asymmetric integer units,
1673490075Sobrien     where one integer unit can do multiply and divides and the other
1673590075Sobrien     can't, reduce the priority of multiply/divide so it is scheduled
1673690075Sobrien     before other integer operations.  */
1673790075Sobrien
1673890075Sobrien#if 0
1673990075Sobrien  if (! INSN_P (insn))
1674090075Sobrien    return priority;
1674190075Sobrien
1674290075Sobrien  if (GET_CODE (PATTERN (insn)) == USE)
1674390075Sobrien    return priority;
1674490075Sobrien
1674590075Sobrien  switch (rs6000_cpu_attr) {
1674690075Sobrien  case CPU_PPC750:
1674790075Sobrien    switch (get_attr_type (insn))
1674890075Sobrien      {
1674990075Sobrien      default:
1675090075Sobrien	break;
1675190075Sobrien
1675290075Sobrien      case TYPE_IMUL:
1675390075Sobrien      case TYPE_IDIV:
1675490075Sobrien	fprintf (stderr, "priority was %#x (%d) before adjustment\n",
1675590075Sobrien		 priority, priority);
1675690075Sobrien	if (priority >= 0 && priority < 0x01000000)
1675790075Sobrien	  priority >>= 3;
1675890075Sobrien	break;
1675990075Sobrien      }
1676090075Sobrien  }
1676190075Sobrien#endif
1676290075Sobrien
16763132718Skan  if (is_dispatch_slot_restricted (insn)
16764132718Skan      && reload_completed
16765169689Skan      && current_sched_info->sched_max_insns_priority
16766132718Skan      && rs6000_sched_restricted_insns_priority)
16767132718Skan    {
16768132718Skan
16769169689Skan      /* Prioritize insns that can be dispatched only in the first
16770169689Skan	 dispatch slot.  */
16771132718Skan      if (rs6000_sched_restricted_insns_priority == 1)
16772169689Skan	/* Attach highest priority to insn. This means that in
16773169689Skan	   haifa-sched.c:ready_sort(), dispatch-slot restriction considerations
16774132718Skan	   precede 'priority' (critical path) considerations.  */
16775169689Skan	return current_sched_info->sched_max_insns_priority;
16776132718Skan      else if (rs6000_sched_restricted_insns_priority == 2)
16777169689Skan	/* Increase priority of insn by a minimal amount. This means that in
16778169689Skan	   haifa-sched.c:ready_sort(), only 'priority' (critical path)
16779169689Skan	   considerations precede dispatch-slot restriction considerations.  */
16780169689Skan	return (priority + 1);
16781169689Skan    }
16782132718Skan
1678390075Sobrien  return priority;
1678490075Sobrien}
1678590075Sobrien
1678690075Sobrien/* Return how many instructions the machine can issue per cycle.  */
1678790075Sobrien
1678890075Sobrienstatic int
16789132718Skanrs6000_issue_rate (void)
1679090075Sobrien{
16791132718Skan  /* Use issue rate of 1 for first scheduling pass to decrease degradation.  */
16792132718Skan  if (!reload_completed)
16793132718Skan    return 1;
16794132718Skan
1679590075Sobrien  switch (rs6000_cpu_attr) {
1679690075Sobrien  case CPU_RIOS1:  /* ? */
1679790075Sobrien  case CPU_RS64A:
1679890075Sobrien  case CPU_PPC601: /* ? */
1679990075Sobrien  case CPU_PPC7450:
1680090075Sobrien    return 3;
16801132718Skan  case CPU_PPC440:
1680290075Sobrien  case CPU_PPC603:
1680390075Sobrien  case CPU_PPC750:
1680490075Sobrien  case CPU_PPC7400:
16805132718Skan  case CPU_PPC8540:
16806169689Skan    return 2;
1680790075Sobrien  case CPU_RIOS2:
1680890075Sobrien  case CPU_PPC604:
1680990075Sobrien  case CPU_PPC604E:
1681090075Sobrien  case CPU_PPC620:
1681190075Sobrien  case CPU_PPC630:
16812132718Skan    return 4;
16813117395Skan  case CPU_POWER4:
16814132718Skan  case CPU_POWER5:
16815132718Skan    return 5;
1681690075Sobrien  default:
1681790075Sobrien    return 1;
1681890075Sobrien  }
1681990075Sobrien}
1682090075Sobrien
16821132718Skan/* Return how many instructions to look ahead for better insn
16822132718Skan   scheduling.  */
16823132718Skan
16824132718Skanstatic int
16825132718Skanrs6000_use_sched_lookahead (void)
16826132718Skan{
16827132718Skan  if (rs6000_cpu_attr == CPU_PPC8540)
16828132718Skan    return 4;
16829132718Skan  return 0;
16830132718Skan}
16831132718Skan
16832132718Skan/* Determine is PAT refers to memory.  */
16833132718Skan
16834132718Skanstatic bool
16835132718Skanis_mem_ref (rtx pat)
16836132718Skan{
16837132718Skan  const char * fmt;
16838132718Skan  int i, j;
16839132718Skan  bool ret = false;
16840132718Skan
16841132718Skan  if (GET_CODE (pat) == MEM)
16842132718Skan    return true;
16843132718Skan
16844132718Skan  /* Recursively process the pattern.  */
16845132718Skan  fmt = GET_RTX_FORMAT (GET_CODE (pat));
16846132718Skan
16847132718Skan  for (i = GET_RTX_LENGTH (GET_CODE (pat)) - 1; i >= 0 && !ret; i--)
16848132718Skan    {
16849132718Skan      if (fmt[i] == 'e')
16850132718Skan	ret |= is_mem_ref (XEXP (pat, i));
16851132718Skan      else if (fmt[i] == 'E')
16852132718Skan	for (j = XVECLEN (pat, i) - 1; j >= 0; j--)
16853132718Skan	  ret |= is_mem_ref (XVECEXP (pat, i, j));
16854132718Skan    }
16855132718Skan
16856132718Skan  return ret;
16857132718Skan}
16858132718Skan
16859132718Skan/* Determine if PAT is a PATTERN of a load insn.  */
16860169689Skan
16861132718Skanstatic bool
16862132718Skanis_load_insn1 (rtx pat)
16863132718Skan{
16864132718Skan  if (!pat || pat == NULL_RTX)
16865132718Skan    return false;
16866132718Skan
16867132718Skan  if (GET_CODE (pat) == SET)
16868132718Skan    return is_mem_ref (SET_SRC (pat));
16869132718Skan
16870132718Skan  if (GET_CODE (pat) == PARALLEL)
16871132718Skan    {
16872132718Skan      int i;
16873132718Skan
16874132718Skan      for (i = 0; i < XVECLEN (pat, 0); i++)
16875132718Skan	if (is_load_insn1 (XVECEXP (pat, 0, i)))
16876132718Skan	  return true;
16877132718Skan    }
16878132718Skan
16879132718Skan  return false;
16880132718Skan}
16881132718Skan
16882132718Skan/* Determine if INSN loads from memory.  */
16883132718Skan
16884132718Skanstatic bool
16885132718Skanis_load_insn (rtx insn)
16886132718Skan{
16887132718Skan  if (!insn || !INSN_P (insn))
16888132718Skan    return false;
16889132718Skan
16890132718Skan  if (GET_CODE (insn) == CALL_INSN)
16891132718Skan    return false;
16892132718Skan
16893132718Skan  return is_load_insn1 (PATTERN (insn));
16894132718Skan}
16895132718Skan
16896132718Skan/* Determine if PAT is a PATTERN of a store insn.  */
16897132718Skan
16898132718Skanstatic bool
16899132718Skanis_store_insn1 (rtx pat)
16900132718Skan{
16901132718Skan  if (!pat || pat == NULL_RTX)
16902132718Skan    return false;
16903132718Skan
16904132718Skan  if (GET_CODE (pat) == SET)
16905132718Skan    return is_mem_ref (SET_DEST (pat));
16906132718Skan
16907132718Skan  if (GET_CODE (pat) == PARALLEL)
16908132718Skan    {
16909132718Skan      int i;
16910132718Skan
16911132718Skan      for (i = 0; i < XVECLEN (pat, 0); i++)
16912132718Skan	if (is_store_insn1 (XVECEXP (pat, 0, i)))
16913132718Skan	  return true;
16914132718Skan    }
16915132718Skan
16916132718Skan  return false;
16917132718Skan}
16918132718Skan
16919132718Skan/* Determine if INSN stores to memory.  */
16920132718Skan
16921132718Skanstatic bool
16922132718Skanis_store_insn (rtx insn)
16923132718Skan{
16924132718Skan  if (!insn || !INSN_P (insn))
16925132718Skan    return false;
16926132718Skan
16927132718Skan  return is_store_insn1 (PATTERN (insn));
16928132718Skan}
16929132718Skan
16930132718Skan/* Returns whether the dependence between INSN and NEXT is considered
16931132718Skan   costly by the given target.  */
16932132718Skan
16933132718Skanstatic bool
16934169689Skanrs6000_is_costly_dependence (rtx insn, rtx next, rtx link, int cost,
16935169689Skan			     int distance)
16936169689Skan{
16937169689Skan  /* If the flag is not enabled - no dependence is considered costly;
16938169689Skan     allow all dependent insns in the same group.
16939132718Skan     This is the most aggressive option.  */
16940132718Skan  if (rs6000_sched_costly_dep == no_dep_costly)
16941132718Skan    return false;
16942132718Skan
16943169689Skan  /* If the flag is set to 1 - a dependence is always considered costly;
16944132718Skan     do not allow dependent instructions in the same group.
16945132718Skan     This is the most conservative option.  */
16946132718Skan  if (rs6000_sched_costly_dep == all_deps_costly)
16947169689Skan    return true;
16948132718Skan
16949169689Skan  if (rs6000_sched_costly_dep == store_to_load_dep_costly
16950169689Skan      && is_load_insn (next)
16951132718Skan      && is_store_insn (insn))
16952132718Skan    /* Prevent load after store in the same group.  */
16953132718Skan    return true;
16954132718Skan
16955132718Skan  if (rs6000_sched_costly_dep == true_store_to_load_dep_costly
16956169689Skan      && is_load_insn (next)
16957132718Skan      && is_store_insn (insn)
16958132718Skan      && (!link || (int) REG_NOTE_KIND (link) == 0))
16959169689Skan     /* Prevent load after store in the same group if it is a true
16960169689Skan	dependence.  */
16961132718Skan     return true;
16962169689Skan
16963169689Skan  /* The flag is set to X; dependences with latency >= X are considered costly,
16964132718Skan     and will not be scheduled in the same group.  */
16965132718Skan  if (rs6000_sched_costly_dep <= max_dep_latency
16966132718Skan      && ((cost - distance) >= (int)rs6000_sched_costly_dep))
16967132718Skan    return true;
16968132718Skan
16969132718Skan  return false;
16970132718Skan}
16971132718Skan
16972169689Skan/* Return the next insn after INSN that is found before TAIL is reached,
16973132718Skan   skipping any "non-active" insns - insns that will not actually occupy
16974132718Skan   an issue slot.  Return NULL_RTX if such an insn is not found.  */
16975132718Skan
16976132718Skanstatic rtx
16977132718Skanget_next_active_insn (rtx insn, rtx tail)
16978132718Skan{
16979169689Skan  if (insn == NULL_RTX || insn == tail)
16980132718Skan    return NULL_RTX;
16981132718Skan
16982169689Skan  while (1)
16983169689Skan    {
16984169689Skan      insn = NEXT_INSN (insn);
16985169689Skan      if (insn == NULL_RTX || insn == tail)
16986169689Skan	return NULL_RTX;
16987132718Skan
16988169689Skan      if (CALL_P (insn)
16989169689Skan	  || JUMP_P (insn)
16990169689Skan	  || (NONJUMP_INSN_P (insn)
16991169689Skan	      && GET_CODE (PATTERN (insn)) != USE
16992169689Skan	      && GET_CODE (PATTERN (insn)) != CLOBBER
16993169689Skan	      && INSN_CODE (insn) != CODE_FOR_stack_tie))
16994169689Skan	break;
16995132718Skan    }
16996169689Skan  return insn;
16997132718Skan}
16998132718Skan
16999132718Skan/* Return whether the presence of INSN causes a dispatch group termination
17000132718Skan   of group WHICH_GROUP.
17001132718Skan
17002132718Skan   If WHICH_GROUP == current_group, this function will return true if INSN
17003132718Skan   causes the termination of the current group (i.e, the dispatch group to
17004132718Skan   which INSN belongs). This means that INSN will be the last insn in the
17005132718Skan   group it belongs to.
17006132718Skan
17007132718Skan   If WHICH_GROUP == previous_group, this function will return true if INSN
17008132718Skan   causes the termination of the previous group (i.e, the dispatch group that
17009132718Skan   precedes the group to which INSN belongs).  This means that INSN will be
17010132718Skan   the first insn in the group it belongs to).  */
17011132718Skan
17012132718Skanstatic bool
17013132718Skaninsn_terminates_group_p (rtx insn, enum group_termination which_group)
17014132718Skan{
17015132718Skan  enum attr_type type;
17016132718Skan
17017132718Skan  if (! insn)
17018132718Skan    return false;
17019132718Skan
17020132718Skan  type = get_attr_type (insn);
17021132718Skan
17022132718Skan  if (is_microcoded_insn (insn))
17023132718Skan    return true;
17024132718Skan
17025132718Skan  if (which_group == current_group)
17026132718Skan    {
17027132718Skan      if (is_branch_slot_insn (insn))
17028169689Skan	return true;
17029132718Skan      return false;
17030132718Skan    }
17031132718Skan  else if (which_group == previous_group)
17032132718Skan    {
17033132718Skan      if (is_dispatch_slot_restricted (insn))
17034169689Skan	return true;
17035132718Skan      return false;
17036132718Skan    }
17037132718Skan
17038132718Skan  return false;
17039132718Skan}
17040132718Skan
17041132718Skan/* Return true if it is recommended to keep NEXT_INSN "far" (in a separate
17042132718Skan   dispatch group) from the insns in GROUP_INSNS.  Return false otherwise.  */
17043132718Skan
17044132718Skanstatic bool
17045132718Skanis_costly_group (rtx *group_insns, rtx next_insn)
17046132718Skan{
17047132718Skan  int i;
17048132718Skan  rtx link;
17049132718Skan  int cost;
17050132718Skan  int issue_rate = rs6000_issue_rate ();
17051132718Skan
17052132718Skan  for (i = 0; i < issue_rate; i++)
17053132718Skan    {
17054132718Skan      rtx insn = group_insns[i];
17055132718Skan      if (!insn)
17056169689Skan	continue;
17057132718Skan      for (link = INSN_DEPEND (insn); link != 0; link = XEXP (link, 1))
17058169689Skan	{
17059169689Skan	  rtx next = XEXP (link, 0);
17060169689Skan	  if (next == next_insn)
17061169689Skan	    {
17062169689Skan	      cost = insn_cost (insn, link, next_insn);
17063169689Skan	      if (rs6000_is_costly_dependence (insn, next_insn, link, cost, 0))
17064169689Skan		return true;
17065169689Skan	    }
17066169689Skan	}
17067132718Skan    }
17068132718Skan
17069132718Skan  return false;
17070132718Skan}
17071132718Skan
17072169689Skan/* Utility of the function redefine_groups.
17073132718Skan   Check if it is too costly to schedule NEXT_INSN together with GROUP_INSNS
17074132718Skan   in the same dispatch group.  If so, insert nops before NEXT_INSN, in order
17075132718Skan   to keep it "far" (in a separate group) from GROUP_INSNS, following
17076132718Skan   one of the following schemes, depending on the value of the flag
17077132718Skan   -minsert_sched_nops = X:
17078132718Skan   (1) X == sched_finish_regroup_exact: insert exactly as many nops as needed
17079132718Skan       in order to force NEXT_INSN into a separate group.
17080169689Skan   (2) X < sched_finish_regroup_exact: insert exactly X nops.
17081169689Skan   GROUP_END, CAN_ISSUE_MORE and GROUP_COUNT record the state after nop
17082132718Skan   insertion (has a group just ended, how many vacant issue slots remain in the
17083132718Skan   last group, and how many dispatch groups were encountered so far).  */
17084132718Skan
17085169689Skanstatic int
17086169689Skanforce_new_group (int sched_verbose, FILE *dump, rtx *group_insns,
17087169689Skan		 rtx next_insn, bool *group_end, int can_issue_more,
17088169689Skan		 int *group_count)
17089132718Skan{
17090132718Skan  rtx nop;
17091132718Skan  bool force;
17092132718Skan  int issue_rate = rs6000_issue_rate ();
17093132718Skan  bool end = *group_end;
17094132718Skan  int i;
17095132718Skan
17096132718Skan  if (next_insn == NULL_RTX)
17097132718Skan    return can_issue_more;
17098132718Skan
17099132718Skan  if (rs6000_sched_insert_nops > sched_finish_regroup_exact)
17100132718Skan    return can_issue_more;
17101132718Skan
17102132718Skan  force = is_costly_group (group_insns, next_insn);
17103132718Skan  if (!force)
17104132718Skan    return can_issue_more;
17105132718Skan
17106132718Skan  if (sched_verbose > 6)
17107132718Skan    fprintf (dump,"force: group count = %d, can_issue_more = %d\n",
17108169689Skan	     *group_count ,can_issue_more);
17109132718Skan
17110132718Skan  if (rs6000_sched_insert_nops == sched_finish_regroup_exact)
17111132718Skan    {
17112132718Skan      if (*group_end)
17113169689Skan	can_issue_more = 0;
17114132718Skan
17115132718Skan      /* Since only a branch can be issued in the last issue_slot, it is
17116132718Skan	 sufficient to insert 'can_issue_more - 1' nops if next_insn is not
17117132718Skan	 a branch. If next_insn is a branch, we insert 'can_issue_more' nops;
17118169689Skan	 in this case the last nop will start a new group and the branch
17119169689Skan	 will be forced to the new group.  */
17120132718Skan      if (can_issue_more && !is_branch_slot_insn (next_insn))
17121169689Skan	can_issue_more--;
17122132718Skan
17123132718Skan      while (can_issue_more > 0)
17124169689Skan	{
17125169689Skan	  nop = gen_nop ();
17126169689Skan	  emit_insn_before (nop, next_insn);
17127169689Skan	  can_issue_more--;
17128169689Skan	}
17129132718Skan
17130132718Skan      *group_end = true;
17131132718Skan      return 0;
17132169689Skan    }
17133132718Skan
17134132718Skan  if (rs6000_sched_insert_nops < sched_finish_regroup_exact)
17135132718Skan    {
17136132718Skan      int n_nops = rs6000_sched_insert_nops;
17137132718Skan
17138169689Skan      /* Nops can't be issued from the branch slot, so the effective
17139169689Skan	 issue_rate for nops is 'issue_rate - 1'.  */
17140132718Skan      if (can_issue_more == 0)
17141169689Skan	can_issue_more = issue_rate;
17142132718Skan      can_issue_more--;
17143132718Skan      if (can_issue_more == 0)
17144169689Skan	{
17145169689Skan	  can_issue_more = issue_rate - 1;
17146169689Skan	  (*group_count)++;
17147169689Skan	  end = true;
17148169689Skan	  for (i = 0; i < issue_rate; i++)
17149169689Skan	    {
17150169689Skan	      group_insns[i] = 0;
17151169689Skan	    }
17152169689Skan	}
17153132718Skan
17154132718Skan      while (n_nops > 0)
17155169689Skan	{
17156169689Skan	  nop = gen_nop ();
17157169689Skan	  emit_insn_before (nop, next_insn);
17158169689Skan	  if (can_issue_more == issue_rate - 1) /* new group begins */
17159169689Skan	    end = false;
17160169689Skan	  can_issue_more--;
17161169689Skan	  if (can_issue_more == 0)
17162169689Skan	    {
17163169689Skan	      can_issue_more = issue_rate - 1;
17164169689Skan	      (*group_count)++;
17165169689Skan	      end = true;
17166169689Skan	      for (i = 0; i < issue_rate; i++)
17167169689Skan		{
17168169689Skan		  group_insns[i] = 0;
17169169689Skan		}
17170169689Skan	    }
17171169689Skan	  n_nops--;
17172169689Skan	}
17173132718Skan
17174132718Skan      /* Scale back relative to 'issue_rate' (instead of 'issue_rate - 1').  */
17175169689Skan      can_issue_more++;
17176132718Skan
17177169689Skan      /* Is next_insn going to start a new group?  */
17178169689Skan      *group_end
17179169689Skan	= (end
17180132718Skan	   || (can_issue_more == 1 && !is_branch_slot_insn (next_insn))
17181132718Skan	   || (can_issue_more <= 2 && is_cracked_insn (next_insn))
17182132718Skan	   || (can_issue_more < issue_rate &&
17183169689Skan	       insn_terminates_group_p (next_insn, previous_group)));
17184132718Skan      if (*group_end && end)
17185169689Skan	(*group_count)--;
17186132718Skan
17187132718Skan      if (sched_verbose > 6)
17188169689Skan	fprintf (dump, "done force: group count = %d, can_issue_more = %d\n",
17189169689Skan		 *group_count, can_issue_more);
17190169689Skan      return can_issue_more;
17191169689Skan    }
17192132718Skan
17193132718Skan  return can_issue_more;
17194132718Skan}
17195132718Skan
17196132718Skan/* This function tries to synch the dispatch groups that the compiler "sees"
17197169689Skan   with the dispatch groups that the processor dispatcher is expected to
17198132718Skan   form in practice.  It tries to achieve this synchronization by forcing the
17199132718Skan   estimated processor grouping on the compiler (as opposed to the function
17200132718Skan   'pad_goups' which tries to force the scheduler's grouping on the processor).
17201132718Skan
17202132718Skan   The function scans the insn sequence between PREV_HEAD_INSN and TAIL and
17203132718Skan   examines the (estimated) dispatch groups that will be formed by the processor
17204132718Skan   dispatcher.  It marks these group boundaries to reflect the estimated
17205132718Skan   processor grouping, overriding the grouping that the scheduler had marked.
17206132718Skan   Depending on the value of the flag '-minsert-sched-nops' this function can
17207132718Skan   force certain insns into separate groups or force a certain distance between
17208132718Skan   them by inserting nops, for example, if there exists a "costly dependence"
17209132718Skan   between the insns.
17210132718Skan
17211132718Skan   The function estimates the group boundaries that the processor will form as
17212169689Skan   follows:  It keeps track of how many vacant issue slots are available after
17213132718Skan   each insn.  A subsequent insn will start a new group if one of the following
17214132718Skan   4 cases applies:
17215132718Skan   - no more vacant issue slots remain in the current dispatch group.
17216132718Skan   - only the last issue slot, which is the branch slot, is vacant, but the next
17217132718Skan     insn is not a branch.
17218132718Skan   - only the last 2 or less issue slots, including the branch slot, are vacant,
17219132718Skan     which means that a cracked insn (which occupies two issue slots) can't be
17220132718Skan     issued in this group.
17221169689Skan   - less than 'issue_rate' slots are vacant, and the next insn always needs to
17222132718Skan     start a new group.  */
17223132718Skan
17224132718Skanstatic int
17225132718Skanredefine_groups (FILE *dump, int sched_verbose, rtx prev_head_insn, rtx tail)
17226132718Skan{
17227132718Skan  rtx insn, next_insn;
17228132718Skan  int issue_rate;
17229132718Skan  int can_issue_more;
17230132718Skan  int slot, i;
17231132718Skan  bool group_end;
17232132718Skan  int group_count = 0;
17233132718Skan  rtx *group_insns;
17234132718Skan
17235132718Skan  /* Initialize.  */
17236132718Skan  issue_rate = rs6000_issue_rate ();
17237132718Skan  group_insns = alloca (issue_rate * sizeof (rtx));
17238169689Skan  for (i = 0; i < issue_rate; i++)
17239132718Skan    {
17240132718Skan      group_insns[i] = 0;
17241132718Skan    }
17242132718Skan  can_issue_more = issue_rate;
17243132718Skan  slot = 0;
17244132718Skan  insn = get_next_active_insn (prev_head_insn, tail);
17245132718Skan  group_end = false;
17246132718Skan
17247132718Skan  while (insn != NULL_RTX)
17248132718Skan    {
17249132718Skan      slot = (issue_rate - can_issue_more);
17250132718Skan      group_insns[slot] = insn;
17251132718Skan      can_issue_more =
17252169689Skan	rs6000_variable_issue (dump, sched_verbose, insn, can_issue_more);
17253132718Skan      if (insn_terminates_group_p (insn, current_group))
17254169689Skan	can_issue_more = 0;
17255132718Skan
17256132718Skan      next_insn = get_next_active_insn (insn, tail);
17257132718Skan      if (next_insn == NULL_RTX)
17258169689Skan	return group_count + 1;
17259132718Skan
17260169689Skan      /* Is next_insn going to start a new group?  */
17261169689Skan      group_end
17262169689Skan	= (can_issue_more == 0
17263169689Skan	   || (can_issue_more == 1 && !is_branch_slot_insn (next_insn))
17264169689Skan	   || (can_issue_more <= 2 && is_cracked_insn (next_insn))
17265169689Skan	   || (can_issue_more < issue_rate &&
17266169689Skan	       insn_terminates_group_p (next_insn, previous_group)));
17267132718Skan
17268169689Skan      can_issue_more = force_new_group (sched_verbose, dump, group_insns,
17269169689Skan					next_insn, &group_end, can_issue_more,
17270169689Skan					&group_count);
17271132718Skan
17272132718Skan      if (group_end)
17273169689Skan	{
17274169689Skan	  group_count++;
17275169689Skan	  can_issue_more = 0;
17276169689Skan	  for (i = 0; i < issue_rate; i++)
17277169689Skan	    {
17278169689Skan	      group_insns[i] = 0;
17279169689Skan	    }
17280169689Skan	}
17281132718Skan
17282132718Skan      if (GET_MODE (next_insn) == TImode && can_issue_more)
17283169689Skan	PUT_MODE (next_insn, VOIDmode);
17284132718Skan      else if (!can_issue_more && GET_MODE (next_insn) != TImode)
17285169689Skan	PUT_MODE (next_insn, TImode);
17286132718Skan
17287132718Skan      insn = next_insn;
17288132718Skan      if (can_issue_more == 0)
17289169689Skan	can_issue_more = issue_rate;
17290169689Skan    } /* while */
17291132718Skan
17292132718Skan  return group_count;
17293132718Skan}
17294132718Skan
17295132718Skan/* Scan the insn sequence between PREV_HEAD_INSN and TAIL and examine the
17296132718Skan   dispatch group boundaries that the scheduler had marked.  Pad with nops
17297132718Skan   any dispatch groups which have vacant issue slots, in order to force the
17298132718Skan   scheduler's grouping on the processor dispatcher.  The function
17299132718Skan   returns the number of dispatch groups found.  */
17300132718Skan
17301132718Skanstatic int
17302132718Skanpad_groups (FILE *dump, int sched_verbose, rtx prev_head_insn, rtx tail)
17303132718Skan{
17304132718Skan  rtx insn, next_insn;
17305132718Skan  rtx nop;
17306132718Skan  int issue_rate;
17307132718Skan  int can_issue_more;
17308132718Skan  int group_end;
17309132718Skan  int group_count = 0;
17310132718Skan
17311132718Skan  /* Initialize issue_rate.  */
17312132718Skan  issue_rate = rs6000_issue_rate ();
17313132718Skan  can_issue_more = issue_rate;
17314132718Skan
17315132718Skan  insn = get_next_active_insn (prev_head_insn, tail);
17316132718Skan  next_insn = get_next_active_insn (insn, tail);
17317132718Skan
17318132718Skan  while (insn != NULL_RTX)
17319132718Skan    {
17320132718Skan      can_issue_more =
17321132718Skan      	rs6000_variable_issue (dump, sched_verbose, insn, can_issue_more);
17322132718Skan
17323132718Skan      group_end = (next_insn == NULL_RTX || GET_MODE (next_insn) == TImode);
17324132718Skan
17325132718Skan      if (next_insn == NULL_RTX)
17326169689Skan	break;
17327132718Skan
17328132718Skan      if (group_end)
17329169689Skan	{
17330169689Skan	  /* If the scheduler had marked group termination at this location
17331169689Skan	     (between insn and next_indn), and neither insn nor next_insn will
17332169689Skan	     force group termination, pad the group with nops to force group
17333169689Skan	     termination.  */
17334169689Skan	  if (can_issue_more
17335169689Skan	      && (rs6000_sched_insert_nops == sched_finish_pad_groups)
17336169689Skan	      && !insn_terminates_group_p (insn, current_group)
17337169689Skan	      && !insn_terminates_group_p (next_insn, previous_group))
17338169689Skan	    {
17339169689Skan	      if (!is_branch_slot_insn (next_insn))
17340169689Skan		can_issue_more--;
17341132718Skan
17342169689Skan	      while (can_issue_more)
17343169689Skan		{
17344169689Skan		  nop = gen_nop ();
17345169689Skan		  emit_insn_before (nop, next_insn);
17346169689Skan		  can_issue_more--;
17347169689Skan		}
17348169689Skan	    }
17349132718Skan
17350169689Skan	  can_issue_more = issue_rate;
17351169689Skan	  group_count++;
17352169689Skan	}
17353132718Skan
17354132718Skan      insn = next_insn;
17355132718Skan      next_insn = get_next_active_insn (insn, tail);
17356132718Skan    }
17357132718Skan
17358132718Skan  return group_count;
17359132718Skan}
17360132718Skan
17361132718Skan/* The following function is called at the end of scheduling BB.
17362132718Skan   After reload, it inserts nops at insn group bundling.  */
17363132718Skan
17364132718Skanstatic void
17365132718Skanrs6000_sched_finish (FILE *dump, int sched_verbose)
17366132718Skan{
17367132718Skan  int n_groups;
17368132718Skan
17369132718Skan  if (sched_verbose)
17370132718Skan    fprintf (dump, "=== Finishing schedule.\n");
17371132718Skan
17372132718Skan  if (reload_completed && rs6000_sched_groups)
17373132718Skan    {
17374132718Skan      if (rs6000_sched_insert_nops == sched_finish_none)
17375169689Skan	return;
17376132718Skan
17377132718Skan      if (rs6000_sched_insert_nops == sched_finish_pad_groups)
17378169689Skan	n_groups = pad_groups (dump, sched_verbose,
17379169689Skan			       current_sched_info->prev_head,
17380169689Skan			       current_sched_info->next_tail);
17381132718Skan      else
17382169689Skan	n_groups = redefine_groups (dump, sched_verbose,
17383169689Skan				    current_sched_info->prev_head,
17384169689Skan				    current_sched_info->next_tail);
17385132718Skan
17386132718Skan      if (sched_verbose >= 6)
17387132718Skan	{
17388132718Skan    	  fprintf (dump, "ngroups = %d\n", n_groups);
17389132718Skan	  print_rtl (dump, current_sched_info->prev_head);
17390132718Skan	  fprintf (dump, "Done finish_sched\n");
17391132718Skan	}
17392132718Skan    }
17393132718Skan}
1739490075Sobrien
1739590075Sobrien/* Length in units of the trampoline for entering a nested function.  */
1739690075Sobrien
1739790075Sobrienint
17398132718Skanrs6000_trampoline_size (void)
1739990075Sobrien{
1740090075Sobrien  int ret = 0;
1740190075Sobrien
1740290075Sobrien  switch (DEFAULT_ABI)
1740390075Sobrien    {
1740490075Sobrien    default:
17405169689Skan      gcc_unreachable ();
1740690075Sobrien
1740790075Sobrien    case ABI_AIX:
1740890075Sobrien      ret = (TARGET_32BIT) ? 12 : 24;
1740990075Sobrien      break;
1741090075Sobrien
1741190075Sobrien    case ABI_DARWIN:
1741290075Sobrien    case ABI_V4:
1741390075Sobrien      ret = (TARGET_32BIT) ? 40 : 48;
1741490075Sobrien      break;
1741590075Sobrien    }
1741690075Sobrien
1741790075Sobrien  return ret;
1741890075Sobrien}
1741990075Sobrien
1742090075Sobrien/* Emit RTL insns to initialize the variable parts of a trampoline.
1742190075Sobrien   FNADDR is an RTX for the address of the function's pure code.
1742290075Sobrien   CXT is an RTX for the static chain value for the function.  */
1742390075Sobrien
1742490075Sobrienvoid
17425132718Skanrs6000_initialize_trampoline (rtx addr, rtx fnaddr, rtx cxt)
1742690075Sobrien{
1742790075Sobrien  int regsize = (TARGET_32BIT) ? 4 : 8;
17428169689Skan  rtx ctx_reg = force_reg (Pmode, cxt);
1742990075Sobrien
1743090075Sobrien  switch (DEFAULT_ABI)
1743190075Sobrien    {
1743290075Sobrien    default:
17433169689Skan      gcc_unreachable ();
1743490075Sobrien
1743590075Sobrien/* Macros to shorten the code expansions below.  */
17436169689Skan#define MEM_DEREF(addr) gen_rtx_MEM (Pmode, memory_address (Pmode, addr))
1743790075Sobrien#define MEM_PLUS(addr,offset) \
17438169689Skan  gen_rtx_MEM (Pmode, memory_address (Pmode, plus_constant (addr, offset)))
1743990075Sobrien
1744090075Sobrien    /* Under AIX, just build the 3 word function descriptor */
1744190075Sobrien    case ABI_AIX:
1744290075Sobrien      {
17443169689Skan	rtx fn_reg = gen_reg_rtx (Pmode);
17444169689Skan	rtx toc_reg = gen_reg_rtx (Pmode);
1744590075Sobrien	emit_move_insn (fn_reg, MEM_DEREF (fnaddr));
1744690075Sobrien	emit_move_insn (toc_reg, MEM_PLUS (fnaddr, regsize));
1744790075Sobrien	emit_move_insn (MEM_DEREF (addr), fn_reg);
1744890075Sobrien	emit_move_insn (MEM_PLUS (addr, regsize), toc_reg);
1744990075Sobrien	emit_move_insn (MEM_PLUS (addr, 2*regsize), ctx_reg);
1745090075Sobrien      }
1745190075Sobrien      break;
1745290075Sobrien
1745390075Sobrien    /* Under V.4/eabi/darwin, __trampoline_setup does the real work.  */
1745490075Sobrien    case ABI_DARWIN:
1745590075Sobrien    case ABI_V4:
17456169689Skan      emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__trampoline_setup"),
1745790075Sobrien			 FALSE, VOIDmode, 4,
17458169689Skan			 addr, Pmode,
1745990075Sobrien			 GEN_INT (rs6000_trampoline_size ()), SImode,
17460169689Skan			 fnaddr, Pmode,
17461169689Skan			 ctx_reg, Pmode);
1746290075Sobrien      break;
1746390075Sobrien    }
1746490075Sobrien
1746590075Sobrien  return;
1746690075Sobrien}
1746790075Sobrien
1746890075Sobrien
1746990075Sobrien/* Table of valid machine attributes.  */
1747090075Sobrien
1747190075Sobrienconst struct attribute_spec rs6000_attribute_table[] =
1747290075Sobrien{
1747390075Sobrien  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
17474146895Skan  { "altivec",   1, 1, false, true,  false, rs6000_handle_altivec_attribute },
17475117395Skan  { "longcall",  0, 0, false, true,  true,  rs6000_handle_longcall_attribute },
17476117395Skan  { "shortcall", 0, 0, false, true,  true,  rs6000_handle_longcall_attribute },
17477169689Skan  { "ms_struct", 0, 0, false, false, false, rs6000_handle_struct_attribute },
17478169689Skan  { "gcc_struct", 0, 0, false, false, false, rs6000_handle_struct_attribute },
17479169689Skan#ifdef SUBTARGET_ATTRIBUTE_TABLE
17480169689Skan  SUBTARGET_ATTRIBUTE_TABLE,
17481169689Skan#endif
17482117395Skan  { NULL,        0, 0, false, false, false, NULL }
1748390075Sobrien};
1748490075Sobrien
17485146895Skan/* Handle the "altivec" attribute.  The attribute may have
17486146895Skan   arguments as follows:
17487146895Skan
17488169689Skan	__attribute__((altivec(vector__)))
17489169689Skan	__attribute__((altivec(pixel__)))	(always followed by 'unsigned short')
17490169689Skan	__attribute__((altivec(bool__)))	(always followed by 'unsigned')
17491146895Skan
17492146895Skan  and may appear more than once (e.g., 'vector bool char') in a
17493146895Skan  given declaration.  */
17494146895Skan
17495146895Skanstatic tree
17496169689Skanrs6000_handle_altivec_attribute (tree *node,
17497169689Skan				 tree name ATTRIBUTE_UNUSED,
17498169689Skan				 tree args,
17499146895Skan				 int flags ATTRIBUTE_UNUSED,
17500146895Skan				 bool *no_add_attrs)
17501146895Skan{
17502146895Skan  tree type = *node, result = NULL_TREE;
17503146895Skan  enum machine_mode mode;
17504146895Skan  int unsigned_p;
17505146895Skan  char altivec_type
17506146895Skan    = ((args && TREE_CODE (args) == TREE_LIST && TREE_VALUE (args)
17507169689Skan	&& TREE_CODE (TREE_VALUE (args)) == IDENTIFIER_NODE)
17508146895Skan       ? *IDENTIFIER_POINTER (TREE_VALUE (args))
17509146895Skan       : '?');
17510146895Skan
17511146895Skan  while (POINTER_TYPE_P (type)
17512146895Skan	 || TREE_CODE (type) == FUNCTION_TYPE
17513146895Skan	 || TREE_CODE (type) == METHOD_TYPE
17514146895Skan	 || TREE_CODE (type) == ARRAY_TYPE)
17515146895Skan    type = TREE_TYPE (type);
17516146895Skan
17517146895Skan  mode = TYPE_MODE (type);
17518146895Skan
17519169689Skan  /* Check for invalid AltiVec type qualifiers.  */
17520169689Skan  if (type == long_unsigned_type_node || type == long_integer_type_node)
17521169689Skan    {
17522169689Skan    if (TARGET_64BIT)
17523169689Skan      error ("use of %<long%> in AltiVec types is invalid for 64-bit code");
17524169689Skan    else if (rs6000_warn_altivec_long)
17525169689Skan      warning (0, "use of %<long%> in AltiVec types is deprecated; use %<int%>");
17526169689Skan    }
17527169689Skan  else if (type == long_long_unsigned_type_node
17528169689Skan           || type == long_long_integer_type_node)
17529169689Skan    error ("use of %<long long%> in AltiVec types is invalid");
17530169689Skan  else if (type == double_type_node)
17531169689Skan    error ("use of %<double%> in AltiVec types is invalid");
17532169689Skan  else if (type == long_double_type_node)
17533169689Skan    error ("use of %<long double%> in AltiVec types is invalid");
17534169689Skan  else if (type == boolean_type_node)
17535169689Skan    error ("use of boolean types in AltiVec types is invalid");
17536169689Skan  else if (TREE_CODE (type) == COMPLEX_TYPE)
17537169689Skan    error ("use of %<complex%> in AltiVec types is invalid");
17538169689Skan  else if (DECIMAL_FLOAT_MODE_P (mode))
17539169689Skan    error ("use of decimal floating point types in AltiVec types is invalid");
17540146895Skan
17541146895Skan  switch (altivec_type)
17542146895Skan    {
17543146895Skan    case 'v':
17544169689Skan      unsigned_p = TYPE_UNSIGNED (type);
17545146895Skan      switch (mode)
17546146895Skan	{
17547169689Skan	case SImode:
17548169689Skan	  result = (unsigned_p ? unsigned_V4SI_type_node : V4SI_type_node);
17549169689Skan	  break;
17550169689Skan	case HImode:
17551169689Skan	  result = (unsigned_p ? unsigned_V8HI_type_node : V8HI_type_node);
17552169689Skan	  break;
17553169689Skan	case QImode:
17554169689Skan	  result = (unsigned_p ? unsigned_V16QI_type_node : V16QI_type_node);
17555169689Skan	  break;
17556169689Skan	case SFmode: result = V4SF_type_node; break;
17557169689Skan	  /* If the user says 'vector int bool', we may be handed the 'bool'
17558169689Skan	     attribute _before_ the 'vector' attribute, and so select the
17559169689Skan	     proper type in the 'b' case below.  */
17560169689Skan	case V4SImode: case V8HImode: case V16QImode: case V4SFmode:
17561169689Skan	  result = type;
17562169689Skan	default: break;
17563146895Skan	}
17564146895Skan      break;
17565146895Skan    case 'b':
17566146895Skan      switch (mode)
17567146895Skan	{
17568169689Skan	case SImode: case V4SImode: result = bool_V4SI_type_node; break;
17569169689Skan	case HImode: case V8HImode: result = bool_V8HI_type_node; break;
17570169689Skan	case QImode: case V16QImode: result = bool_V16QI_type_node;
17571169689Skan	default: break;
17572146895Skan	}
17573146895Skan      break;
17574146895Skan    case 'p':
17575146895Skan      switch (mode)
17576146895Skan	{
17577169689Skan	case V8HImode: result = pixel_V8HI_type_node;
17578169689Skan	default: break;
17579146895Skan	}
17580146895Skan    default: break;
17581146895Skan    }
17582146895Skan
17583146895Skan  if (result && result != type && TYPE_READONLY (type))
17584146895Skan    result = build_qualified_type (result, TYPE_QUAL_CONST);
17585146895Skan
17586146895Skan  *no_add_attrs = true;  /* No need to hang on to the attribute.  */
17587146895Skan
17588169689Skan  if (result)
17589146895Skan    *node = reconstruct_complex_type (*node, result);
17590146895Skan
17591146895Skan  return NULL_TREE;
17592146895Skan}
17593146895Skan
17594146895Skan/* AltiVec defines four built-in scalar types that serve as vector
17595146895Skan   elements; we must teach the compiler how to mangle them.  */
17596146895Skan
17597146895Skanstatic const char *
17598146895Skanrs6000_mangle_fundamental_type (tree type)
17599146895Skan{
17600146895Skan  if (type == bool_char_type_node) return "U6__boolc";
17601146895Skan  if (type == bool_short_type_node) return "U6__bools";
17602146895Skan  if (type == pixel_type_node) return "u7__pixel";
17603146895Skan  if (type == bool_int_type_node) return "U6__booli";
17604146895Skan
17605169689Skan  /* Mangle IBM extended float long double as `g' (__float128) on
17606169689Skan     powerpc*-linux where long-double-64 previously was the default.  */
17607169689Skan  if (TYPE_MAIN_VARIANT (type) == long_double_type_node
17608169689Skan      && TARGET_ELF
17609169689Skan      && TARGET_LONG_DOUBLE_128
17610169689Skan      && !TARGET_IEEEQUAD)
17611169689Skan    return "g";
17612169689Skan
17613146895Skan  /* For all other types, use normal C++ mangling.  */
17614146895Skan  return NULL;
17615146895Skan}
17616146895Skan
17617117395Skan/* Handle a "longcall" or "shortcall" attribute; arguments as in
17618117395Skan   struct attribute_spec.handler.  */
1761990075Sobrien
1762090075Sobrienstatic tree
17621169689Skanrs6000_handle_longcall_attribute (tree *node, tree name,
17622169689Skan				  tree args ATTRIBUTE_UNUSED,
17623169689Skan				  int flags ATTRIBUTE_UNUSED,
17624132718Skan				  bool *no_add_attrs)
1762590075Sobrien{
1762690075Sobrien  if (TREE_CODE (*node) != FUNCTION_TYPE
1762790075Sobrien      && TREE_CODE (*node) != FIELD_DECL
1762890075Sobrien      && TREE_CODE (*node) != TYPE_DECL)
1762990075Sobrien    {
17630169689Skan      warning (OPT_Wattributes, "%qs attribute only applies to functions",
1763190075Sobrien	       IDENTIFIER_POINTER (name));
1763290075Sobrien      *no_add_attrs = true;
1763390075Sobrien    }
1763490075Sobrien
1763590075Sobrien  return NULL_TREE;
1763690075Sobrien}
1763790075Sobrien
17638117395Skan/* Set longcall attributes on all functions declared when
17639117395Skan   rs6000_default_long_calls is true.  */
17640117395Skanstatic void
17641132718Skanrs6000_set_default_type_attributes (tree type)
17642117395Skan{
17643117395Skan  if (rs6000_default_long_calls
17644117395Skan      && (TREE_CODE (type) == FUNCTION_TYPE
17645117395Skan	  || TREE_CODE (type) == METHOD_TYPE))
17646117395Skan    TYPE_ATTRIBUTES (type) = tree_cons (get_identifier ("longcall"),
17647117395Skan					NULL_TREE,
17648117395Skan					TYPE_ATTRIBUTES (type));
17649169689Skan
17650169689Skan#if TARGET_MACHO
17651169689Skan  darwin_set_default_type_attributes (type);
17652169689Skan#endif
17653117395Skan}
17654117395Skan
1765590075Sobrien/* Return a reference suitable for calling a function with the
1765690075Sobrien   longcall attribute.  */
1765790075Sobrien
17658169689Skanrtx
17659132718Skanrs6000_longcall_ref (rtx call_ref)
1766090075Sobrien{
1766190075Sobrien  const char *call_name;
1766290075Sobrien  tree node;
1766390075Sobrien
1766490075Sobrien  if (GET_CODE (call_ref) != SYMBOL_REF)
1766590075Sobrien    return call_ref;
1766690075Sobrien
1766790075Sobrien  /* System V adds '.' to the internal name, so skip them.  */
1766890075Sobrien  call_name = XSTR (call_ref, 0);
1766990075Sobrien  if (*call_name == '.')
1767090075Sobrien    {
1767190075Sobrien      while (*call_name == '.')
1767290075Sobrien	call_name++;
1767390075Sobrien
1767490075Sobrien      node = get_identifier (call_name);
1767590075Sobrien      call_ref = gen_rtx_SYMBOL_REF (VOIDmode, IDENTIFIER_POINTER (node));
1767690075Sobrien    }
1767790075Sobrien
1767890075Sobrien  return force_reg (Pmode, call_ref);
1767990075Sobrien}
1768090075Sobrien
17681169689Skan#ifndef TARGET_USE_MS_BITFIELD_LAYOUT
17682169689Skan#define TARGET_USE_MS_BITFIELD_LAYOUT 0
17683169689Skan#endif
17684169689Skan
17685169689Skan/* Handle a "ms_struct" or "gcc_struct" attribute; arguments as in
17686169689Skan   struct attribute_spec.handler.  */
17687169689Skanstatic tree
17688169689Skanrs6000_handle_struct_attribute (tree *node, tree name,
17689169689Skan				tree args ATTRIBUTE_UNUSED,
17690169689Skan				int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
17691169689Skan{
17692169689Skan  tree *type = NULL;
17693169689Skan  if (DECL_P (*node))
17694169689Skan    {
17695169689Skan      if (TREE_CODE (*node) == TYPE_DECL)
17696169689Skan        type = &TREE_TYPE (*node);
17697169689Skan    }
17698169689Skan  else
17699169689Skan    type = node;
17700169689Skan
17701169689Skan  if (!(type && (TREE_CODE (*type) == RECORD_TYPE
17702169689Skan                 || TREE_CODE (*type) == UNION_TYPE)))
17703169689Skan    {
17704169689Skan      warning (OPT_Wattributes, "%qs attribute ignored", IDENTIFIER_POINTER (name));
17705169689Skan      *no_add_attrs = true;
17706169689Skan    }
17707169689Skan
17708169689Skan  else if ((is_attribute_p ("ms_struct", name)
17709169689Skan            && lookup_attribute ("gcc_struct", TYPE_ATTRIBUTES (*type)))
17710169689Skan           || ((is_attribute_p ("gcc_struct", name)
17711169689Skan                && lookup_attribute ("ms_struct", TYPE_ATTRIBUTES (*type)))))
17712169689Skan    {
17713169689Skan      warning (OPT_Wattributes, "%qs incompatible attribute ignored",
17714169689Skan               IDENTIFIER_POINTER (name));
17715169689Skan      *no_add_attrs = true;
17716169689Skan    }
17717169689Skan
17718169689Skan  return NULL_TREE;
17719169689Skan}
17720169689Skan
17721169689Skanstatic bool
17722169689Skanrs6000_ms_bitfield_layout_p (tree record_type)
17723169689Skan{
17724169689Skan  return (TARGET_USE_MS_BITFIELD_LAYOUT &&
17725169689Skan          !lookup_attribute ("gcc_struct", TYPE_ATTRIBUTES (record_type)))
17726169689Skan    || lookup_attribute ("ms_struct", TYPE_ATTRIBUTES (record_type));
17727169689Skan}
17728169689Skan
17729117395Skan#ifdef USING_ELFOS_H
17730117395Skan
17731169689Skan/* A get_unnamed_section callback, used for switching to toc_section.  */
1773290075Sobrien
17733117395Skanstatic void
17734169689Skanrs6000_elf_output_toc_section_asm_op (const void *data ATTRIBUTE_UNUSED)
1773590075Sobrien{
17736169689Skan  if (DEFAULT_ABI == ABI_AIX
17737169689Skan      && TARGET_MINIMAL_TOC
17738169689Skan      && !TARGET_RELOCATABLE)
17739169689Skan    {
17740169689Skan      if (!toc_initialized)
17741169689Skan	{
17742169689Skan	  toc_initialized = 1;
17743169689Skan	  fprintf (asm_out_file, "%s\n", TOC_SECTION_ASM_OP);
17744169689Skan	  (*targetm.asm_out.internal_label) (asm_out_file, "LCTOC", 0);
17745169689Skan	  fprintf (asm_out_file, "\t.tc ");
17746169689Skan	  ASM_OUTPUT_INTERNAL_LABEL_PREFIX (asm_out_file, "LCTOC1[TC],");
17747169689Skan	  ASM_OUTPUT_INTERNAL_LABEL_PREFIX (asm_out_file, "LCTOC1");
17748169689Skan	  fprintf (asm_out_file, "\n");
17749169689Skan
17750169689Skan	  fprintf (asm_out_file, "%s\n", MINIMAL_TOC_SECTION_ASM_OP);
17751169689Skan	  ASM_OUTPUT_INTERNAL_LABEL_PREFIX (asm_out_file, "LCTOC1");
17752169689Skan	  fprintf (asm_out_file, " = .+32768\n");
17753169689Skan	}
17754169689Skan      else
17755169689Skan	fprintf (asm_out_file, "%s\n", MINIMAL_TOC_SECTION_ASM_OP);
17756169689Skan    }
17757169689Skan  else if (DEFAULT_ABI == ABI_AIX && !TARGET_RELOCATABLE)
17758169689Skan    fprintf (asm_out_file, "%s\n", TOC_SECTION_ASM_OP);
1775990075Sobrien  else
17760169689Skan    {
17761169689Skan      fprintf (asm_out_file, "%s\n", MINIMAL_TOC_SECTION_ASM_OP);
17762169689Skan      if (!toc_initialized)
17763169689Skan	{
17764169689Skan	  ASM_OUTPUT_INTERNAL_LABEL_PREFIX (asm_out_file, "LCTOC1");
17765169689Skan	  fprintf (asm_out_file, " = .+32768\n");
17766169689Skan	  toc_initialized = 1;
17767169689Skan	}
17768169689Skan    }
1776990075Sobrien}
1777090075Sobrien
17771169689Skan/* Implement TARGET_ASM_INIT_SECTIONS.  */
1777290075Sobrien
17773117395Skanstatic void
17774169689Skanrs6000_elf_asm_init_sections (void)
1777590075Sobrien{
17776169689Skan  toc_section
17777169689Skan    = get_unnamed_section (0, rs6000_elf_output_toc_section_asm_op, NULL);
17778169689Skan
17779169689Skan  sdata2_section
17780169689Skan    = get_unnamed_section (SECTION_WRITE, output_section_asm_op,
17781169689Skan			   SDATA2_SECTION_ASM_OP);
1778290075Sobrien}
1778390075Sobrien
17784169689Skan/* Implement TARGET_SELECT_RTX_SECTION.  */
1778590075Sobrien
17786169689Skanstatic section *
17787169689Skanrs6000_elf_select_rtx_section (enum machine_mode mode, rtx x,
17788169689Skan			       unsigned HOST_WIDE_INT align)
1778990075Sobrien{
17790169689Skan  if (ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (x, mode))
17791169689Skan    return toc_section;
17792169689Skan  else
17793169689Skan    return default_elf_select_rtx_section (mode, x, align);
1779490075Sobrien}
17795117395Skan
17796132718Skan/* For a SYMBOL_REF, set generic flags and then perform some
17797132718Skan   target-specific processing.
1779890075Sobrien
17799132718Skan   When the AIX ABI is requested on a non-AIX system, replace the
17800132718Skan   function name with the real name (with a leading .) rather than the
17801132718Skan   function descriptor name.  This saves a lot of overriding code to
17802132718Skan   read the prefixes.  */
17803132718Skan
17804117395Skanstatic void
17805132718Skanrs6000_elf_encode_section_info (tree decl, rtx rtl, int first)
1780690075Sobrien{
17807132718Skan  default_encode_section_info (decl, rtl, first);
17808117395Skan
17809132718Skan  if (first
17810132718Skan      && TREE_CODE (decl) == FUNCTION_DECL
17811132718Skan      && !TARGET_AIX
17812132718Skan      && DEFAULT_ABI == ABI_AIX)
1781390075Sobrien    {
17814132718Skan      rtx sym_ref = XEXP (rtl, 0);
17815132718Skan      size_t len = strlen (XSTR (sym_ref, 0));
17816132718Skan      char *str = alloca (len + 2);
17817132718Skan      str[0] = '.';
17818132718Skan      memcpy (str + 1, XSTR (sym_ref, 0), len + 1);
17819132718Skan      XSTR (sym_ref, 0) = ggc_alloc_string (str, len + 1);
1782090075Sobrien    }
1782190075Sobrien}
1782290075Sobrien
17823169689Skanbool
17824132718Skanrs6000_elf_in_small_data_p (tree decl)
17825117395Skan{
17826117395Skan  if (rs6000_sdata == SDATA_NONE)
17827117395Skan    return false;
17828117395Skan
17829146895Skan  /* We want to merge strings, so we never consider them small data.  */
17830146895Skan  if (TREE_CODE (decl) == STRING_CST)
17831146895Skan    return false;
17832146895Skan
17833146895Skan  /* Functions are never in the small data area.  */
17834146895Skan  if (TREE_CODE (decl) == FUNCTION_DECL)
17835146895Skan    return false;
17836146895Skan
17837117395Skan  if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl))
17838117395Skan    {
17839117395Skan      const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
17840117395Skan      if (strcmp (section, ".sdata") == 0
17841117395Skan	  || strcmp (section, ".sdata2") == 0
17842132718Skan	  || strcmp (section, ".sbss") == 0
17843132718Skan	  || strcmp (section, ".sbss2") == 0
17844132718Skan	  || strcmp (section, ".PPC.EMB.sdata0") == 0
17845132718Skan	  || strcmp (section, ".PPC.EMB.sbss0") == 0)
17846117395Skan	return true;
17847117395Skan    }
17848117395Skan  else
17849117395Skan    {
17850117395Skan      HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (decl));
17851117395Skan
17852117395Skan      if (size > 0
17853132718Skan	  && (unsigned HOST_WIDE_INT) size <= g_switch_value
17854132718Skan	  /* If it's not public, and we're not going to reference it there,
17855132718Skan	     there's no need to put it in the small data section.  */
17856117395Skan	  && (rs6000_sdata != SDATA_DATA || TREE_PUBLIC (decl)))
17857117395Skan	return true;
17858117395Skan    }
17859117395Skan
17860117395Skan  return false;
17861117395Skan}
17862117395Skan
1786390075Sobrien#endif /* USING_ELFOS_H */
17864169689Skan
17865169689Skan/* Implement TARGET_USE_BLOCKS_FOR_CONSTANT_P.  */
1786690075Sobrien
17867169689Skanstatic bool
17868169689Skanrs6000_use_blocks_for_constant_p (enum machine_mode mode, rtx x)
17869169689Skan{
17870169689Skan  return !ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (x, mode);
17871169689Skan}
1787290075Sobrien
1787390075Sobrien/* Return a REG that occurs in ADDR with coefficient 1.
1787490075Sobrien   ADDR can be effectively incremented by incrementing REG.
1787590075Sobrien
1787690075Sobrien   r0 is special and we must not select it as an address
1787790075Sobrien   register by this routine since our caller will try to
1787890075Sobrien   increment the returned register via an "la" instruction.  */
1787990075Sobrien
17880169689Skanrtx
17881132718Skanfind_addr_reg (rtx addr)
1788290075Sobrien{
1788390075Sobrien  while (GET_CODE (addr) == PLUS)
1788490075Sobrien    {
1788590075Sobrien      if (GET_CODE (XEXP (addr, 0)) == REG
1788690075Sobrien	  && REGNO (XEXP (addr, 0)) != 0)
1788790075Sobrien	addr = XEXP (addr, 0);
1788890075Sobrien      else if (GET_CODE (XEXP (addr, 1)) == REG
1788990075Sobrien	       && REGNO (XEXP (addr, 1)) != 0)
1789090075Sobrien	addr = XEXP (addr, 1);
1789190075Sobrien      else if (CONSTANT_P (XEXP (addr, 0)))
1789290075Sobrien	addr = XEXP (addr, 1);
1789390075Sobrien      else if (CONSTANT_P (XEXP (addr, 1)))
1789490075Sobrien	addr = XEXP (addr, 0);
1789590075Sobrien      else
17896169689Skan	gcc_unreachable ();
1789790075Sobrien    }
17898169689Skan  gcc_assert (GET_CODE (addr) == REG && REGNO (addr) != 0);
17899169689Skan  return addr;
1790090075Sobrien}
1790190075Sobrien
1790290075Sobrienvoid
17903132718Skanrs6000_fatal_bad_address (rtx op)
1790490075Sobrien{
1790590075Sobrien  fatal_insn ("bad address", op);
1790690075Sobrien}
1790790075Sobrien
1790890075Sobrien#if TARGET_MACHO
1790990075Sobrien
17910132718Skanstatic tree branch_island_list = 0;
1791190075Sobrien
17912132718Skan/* Remember to generate a branch island for far calls to the given
17913132718Skan   function.  */
1791490075Sobrien
17915169689Skanstatic void
17916169689Skanadd_compiler_branch_island (tree label_name, tree function_name,
17917169689Skan			    int line_number)
1791890075Sobrien{
17919132718Skan  tree branch_island = build_tree_list (function_name, label_name);
17920169689Skan  TREE_TYPE (branch_island) = build_int_cst (NULL_TREE, line_number);
17921132718Skan  TREE_CHAIN (branch_island) = branch_island_list;
17922132718Skan  branch_island_list = branch_island;
1792390075Sobrien}
1792490075Sobrien
17925132718Skan#define BRANCH_ISLAND_LABEL_NAME(BRANCH_ISLAND)     TREE_VALUE (BRANCH_ISLAND)
17926132718Skan#define BRANCH_ISLAND_FUNCTION_NAME(BRANCH_ISLAND)  TREE_PURPOSE (BRANCH_ISLAND)
17927132718Skan#define BRANCH_ISLAND_LINE_NUMBER(BRANCH_ISLAND)    \
17928132718Skan		TREE_INT_CST_LOW (TREE_TYPE (BRANCH_ISLAND))
1792990075Sobrien
17930132718Skan/* Generate far-jump branch islands for everything on the
17931132718Skan   branch_island_list.  Invoked immediately after the last instruction
17932132718Skan   of the epilogue has been emitted; the branch-islands must be
17933132718Skan   appended to, and contiguous with, the function body.  Mach-O stubs
17934132718Skan   are generated in machopic_output_stub().  */
1793590075Sobrien
17936132718Skanstatic void
17937132718Skanmacho_branch_islands (void)
1793890075Sobrien{
17939132718Skan  char tmp_buf[512];
17940132718Skan  tree branch_island;
1794190075Sobrien
17942132718Skan  for (branch_island = branch_island_list;
17943132718Skan       branch_island;
17944132718Skan       branch_island = TREE_CHAIN (branch_island))
17945132718Skan    {
17946132718Skan      const char *label =
17947132718Skan	IDENTIFIER_POINTER (BRANCH_ISLAND_LABEL_NAME (branch_island));
17948132718Skan      const char *name  =
17949169689Skan	IDENTIFIER_POINTER (BRANCH_ISLAND_FUNCTION_NAME (branch_island));
17950132718Skan      char name_buf[512];
17951132718Skan      /* Cheap copy of the details from the Darwin ASM_OUTPUT_LABELREF().  */
17952132718Skan      if (name[0] == '*' || name[0] == '&')
17953132718Skan	strcpy (name_buf, name+1);
17954132718Skan      else
17955132718Skan	{
17956132718Skan	  name_buf[0] = '_';
17957132718Skan	  strcpy (name_buf+1, name);
17958132718Skan	}
17959132718Skan      strcpy (tmp_buf, "\n");
17960132718Skan      strcat (tmp_buf, label);
1796190075Sobrien#if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO)
17962132718Skan      if (write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG)
17963169689Skan	dbxout_stabd (N_SLINE, BRANCH_ISLAND_LINE_NUMBER (branch_island));
1796490075Sobrien#endif /* DBX_DEBUGGING_INFO || XCOFF_DEBUGGING_INFO */
17965132718Skan      if (flag_pic)
17966132718Skan	{
17967132718Skan	  strcat (tmp_buf, ":\n\tmflr r0\n\tbcl 20,31,");
17968132718Skan	  strcat (tmp_buf, label);
17969132718Skan	  strcat (tmp_buf, "_pic\n");
17970132718Skan	  strcat (tmp_buf, label);
17971132718Skan	  strcat (tmp_buf, "_pic:\n\tmflr r11\n");
17972169689Skan
17973132718Skan	  strcat (tmp_buf, "\taddis r11,r11,ha16(");
17974132718Skan	  strcat (tmp_buf, name_buf);
17975132718Skan	  strcat (tmp_buf, " - ");
17976132718Skan	  strcat (tmp_buf, label);
17977132718Skan	  strcat (tmp_buf, "_pic)\n");
17978169689Skan
17979132718Skan	  strcat (tmp_buf, "\tmtlr r0\n");
17980169689Skan
17981132718Skan	  strcat (tmp_buf, "\taddi r12,r11,lo16(");
17982132718Skan	  strcat (tmp_buf, name_buf);
17983132718Skan	  strcat (tmp_buf, " - ");
17984132718Skan	  strcat (tmp_buf, label);
17985132718Skan	  strcat (tmp_buf, "_pic)\n");
17986169689Skan
17987132718Skan	  strcat (tmp_buf, "\tmtctr r12\n\tbctr\n");
17988132718Skan	}
17989132718Skan      else
17990132718Skan	{
17991132718Skan	  strcat (tmp_buf, ":\nlis r12,hi16(");
17992132718Skan	  strcat (tmp_buf, name_buf);
17993132718Skan	  strcat (tmp_buf, ")\n\tori r12,r12,lo16(");
17994132718Skan	  strcat (tmp_buf, name_buf);
17995132718Skan	  strcat (tmp_buf, ")\n\tmtctr r12\n\tbctr");
17996132718Skan	}
17997132718Skan      output_asm_insn (tmp_buf, 0);
1799890075Sobrien#if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO)
17999132718Skan      if (write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG)
18000169689Skan	dbxout_stabd (N_SLINE, BRANCH_ISLAND_LINE_NUMBER (branch_island));
1800190075Sobrien#endif /* DBX_DEBUGGING_INFO || XCOFF_DEBUGGING_INFO */
18002132718Skan    }
1800390075Sobrien
18004132718Skan  branch_island_list = 0;
1800590075Sobrien}
1800690075Sobrien
1800790075Sobrien/* NO_PREVIOUS_DEF checks in the link list whether the function name is
1800890075Sobrien   already there or not.  */
1800990075Sobrien
18010132718Skanstatic int
18011132718Skanno_previous_def (tree function_name)
1801290075Sobrien{
18013132718Skan  tree branch_island;
18014132718Skan  for (branch_island = branch_island_list;
18015132718Skan       branch_island;
18016132718Skan       branch_island = TREE_CHAIN (branch_island))
18017132718Skan    if (function_name == BRANCH_ISLAND_FUNCTION_NAME (branch_island))
1801890075Sobrien      return 0;
1801990075Sobrien  return 1;
1802090075Sobrien}
1802190075Sobrien
1802290075Sobrien/* GET_PREV_LABEL gets the label name from the previous definition of
1802390075Sobrien   the function.  */
1802490075Sobrien
18025132718Skanstatic tree
18026132718Skanget_prev_label (tree function_name)
1802790075Sobrien{
18028132718Skan  tree branch_island;
18029132718Skan  for (branch_island = branch_island_list;
18030132718Skan       branch_island;
18031132718Skan       branch_island = TREE_CHAIN (branch_island))
18032132718Skan    if (function_name == BRANCH_ISLAND_FUNCTION_NAME (branch_island))
18033132718Skan      return BRANCH_ISLAND_LABEL_NAME (branch_island);
1803490075Sobrien  return 0;
1803590075Sobrien}
1803690075Sobrien
18037169689Skan#ifndef DARWIN_LINKER_GENERATES_ISLANDS
18038169689Skan#define DARWIN_LINKER_GENERATES_ISLANDS 0
18039169689Skan#endif
18040169689Skan
18041169689Skan/* KEXTs still need branch islands.  */
18042169689Skan#define DARWIN_GENERATE_ISLANDS (!DARWIN_LINKER_GENERATES_ISLANDS \
18043169689Skan				 || flag_mkernel || flag_apple_kext)
18044169689Skan
1804590075Sobrien/* INSN is either a function call or a millicode call.  It may have an
18046169689Skan   unconditional jump in its delay slot.
1804790075Sobrien
1804890075Sobrien   CALL_DEST is the routine we are calling.  */
1804990075Sobrien
1805090075Sobrienchar *
18051169689Skanoutput_call (rtx insn, rtx *operands, int dest_operand_number,
18052169689Skan	     int cookie_operand_number)
1805390075Sobrien{
1805490075Sobrien  static char buf[256];
18055169689Skan  if (DARWIN_GENERATE_ISLANDS
18056169689Skan      && GET_CODE (operands[dest_operand_number]) == SYMBOL_REF
18057132718Skan      && (INTVAL (operands[cookie_operand_number]) & CALL_LONG))
1805890075Sobrien    {
1805990075Sobrien      tree labelname;
18060132718Skan      tree funname = get_identifier (XSTR (operands[dest_operand_number], 0));
18061169689Skan
1806290075Sobrien      if (no_previous_def (funname))
1806390075Sobrien	{
18064117395Skan	  int line_number = 0;
1806590075Sobrien	  rtx label_rtx = gen_label_rtx ();
1806690075Sobrien	  char *label_buf, temp_buf[256];
1806790075Sobrien	  ASM_GENERATE_INTERNAL_LABEL (temp_buf, "L",
1806890075Sobrien				       CODE_LABEL_NUMBER (label_rtx));
1806990075Sobrien	  label_buf = temp_buf[0] == '*' ? temp_buf + 1 : temp_buf;
1807090075Sobrien	  labelname = get_identifier (label_buf);
1807190075Sobrien	  for (; insn && GET_CODE (insn) != NOTE; insn = PREV_INSN (insn));
1807290075Sobrien	  if (insn)
1807390075Sobrien	    line_number = NOTE_LINE_NUMBER (insn);
18074132718Skan	  add_compiler_branch_island (labelname, funname, line_number);
1807590075Sobrien	}
1807690075Sobrien      else
1807790075Sobrien	labelname = get_prev_label (funname);
1807890075Sobrien
18079132718Skan      /* "jbsr foo, L42" is Mach-O for "Link as 'bl foo' if a 'bl'
18080132718Skan	 instruction will reach 'foo', otherwise link as 'bl L42'".
18081132718Skan	 "L42" should be a 'branch island', that will do a far jump to
18082132718Skan	 'foo'.  Branch islands are generated in
18083132718Skan	 macho_branch_islands().  */
1808490075Sobrien      sprintf (buf, "jbsr %%z%d,%.246s",
18085132718Skan	       dest_operand_number, IDENTIFIER_POINTER (labelname));
1808690075Sobrien    }
1808790075Sobrien  else
18088132718Skan    sprintf (buf, "bl %%z%d", dest_operand_number);
18089132718Skan  return buf;
1809090075Sobrien}
1809190075Sobrien
1809290075Sobrien/* Generate PIC and indirect symbol stubs.  */
1809390075Sobrien
1809490075Sobrienvoid
18095132718Skanmachopic_output_stub (FILE *file, const char *symb, const char *stub)
1809690075Sobrien{
1809790075Sobrien  unsigned int length;
1809890075Sobrien  char *symbol_name, *lazy_ptr_name;
1809990075Sobrien  char *local_label_0;
1810090075Sobrien  static int label = 0;
1810190075Sobrien
1810290075Sobrien  /* Lose our funky encoding stuff so it doesn't contaminate the stub.  */
18103117395Skan  symb = (*targetm.strip_name_encoding) (symb);
1810490075Sobrien
1810590075Sobrien
1810690075Sobrien  length = strlen (symb);
1810790075Sobrien  symbol_name = alloca (length + 32);
1810890075Sobrien  GEN_SYMBOL_NAME_FOR_SYMBOL (symbol_name, symb, length);
1810990075Sobrien
1811090075Sobrien  lazy_ptr_name = alloca (length + 32);
1811190075Sobrien  GEN_LAZY_PTR_NAME_FOR_SYMBOL (lazy_ptr_name, symb, length);
1811290075Sobrien
1811390075Sobrien  if (flag_pic == 2)
18114169689Skan    switch_to_section (darwin_sections[machopic_picsymbol_stub1_section]);
1811590075Sobrien  else
18116169689Skan    switch_to_section (darwin_sections[machopic_symbol_stub1_section]);
1811790075Sobrien
1811890075Sobrien  if (flag_pic == 2)
1811990075Sobrien    {
18120169689Skan      fprintf (file, "\t.align 5\n");
18121169689Skan
18122169689Skan      fprintf (file, "%s:\n", stub);
18123169689Skan      fprintf (file, "\t.indirect_symbol %s\n", symbol_name);
18124169689Skan
18125132718Skan      label++;
18126169689Skan      local_label_0 = alloca (sizeof ("\"L00000000000$spb\""));
18127132718Skan      sprintf (local_label_0, "\"L%011d$spb\"", label);
18128169689Skan
1812990075Sobrien      fprintf (file, "\tmflr r0\n");
1813090075Sobrien      fprintf (file, "\tbcl 20,31,%s\n", local_label_0);
1813190075Sobrien      fprintf (file, "%s:\n\tmflr r11\n", local_label_0);
1813290075Sobrien      fprintf (file, "\taddis r11,r11,ha16(%s-%s)\n",
1813390075Sobrien	       lazy_ptr_name, local_label_0);
1813490075Sobrien      fprintf (file, "\tmtlr r0\n");
18135169689Skan      fprintf (file, "\t%s r12,lo16(%s-%s)(r11)\n",
18136169689Skan	       (TARGET_64BIT ? "ldu" : "lwzu"),
1813790075Sobrien	       lazy_ptr_name, local_label_0);
1813890075Sobrien      fprintf (file, "\tmtctr r12\n");
1813990075Sobrien      fprintf (file, "\tbctr\n");
1814090075Sobrien    }
1814190075Sobrien  else
18142169689Skan    {
18143169689Skan      fprintf (file, "\t.align 4\n");
18144169689Skan
18145169689Skan      fprintf (file, "%s:\n", stub);
18146169689Skan      fprintf (file, "\t.indirect_symbol %s\n", symbol_name);
18147169689Skan
18148169689Skan      fprintf (file, "\tlis r11,ha16(%s)\n", lazy_ptr_name);
18149169689Skan      fprintf (file, "\t%s r12,lo16(%s)(r11)\n",
18150169689Skan	       (TARGET_64BIT ? "ldu" : "lwzu"),
18151169689Skan	       lazy_ptr_name);
18152169689Skan      fprintf (file, "\tmtctr r12\n");
18153169689Skan      fprintf (file, "\tbctr\n");
18154169689Skan    }
18155169689Skan
18156169689Skan  switch_to_section (darwin_sections[machopic_lazy_symbol_ptr_section]);
1815790075Sobrien  fprintf (file, "%s:\n", lazy_ptr_name);
1815890075Sobrien  fprintf (file, "\t.indirect_symbol %s\n", symbol_name);
18159169689Skan  fprintf (file, "%sdyld_stub_binding_helper\n",
18160169689Skan	   (TARGET_64BIT ? DOUBLE_INT_ASM_OP : "\t.long\t"));
1816190075Sobrien}
1816290075Sobrien
1816390075Sobrien/* Legitimize PIC addresses.  If the address is already
1816490075Sobrien   position-independent, we return ORIG.  Newly generated
1816590075Sobrien   position-independent addresses go into a reg.  This is REG if non
1816690075Sobrien   zero, otherwise we allocate register(s) as necessary.  */
1816790075Sobrien
18168169689Skan#define SMALL_INT(X) ((UINTVAL (X) + 0x8000) < 0x10000)
1816990075Sobrien
1817090075Sobrienrtx
18171169689Skanrs6000_machopic_legitimize_pic_address (rtx orig, enum machine_mode mode,
18172132718Skan					rtx reg)
1817390075Sobrien{
1817490075Sobrien  rtx base, offset;
1817590075Sobrien
1817690075Sobrien  if (reg == NULL && ! reload_in_progress && ! reload_completed)
1817790075Sobrien    reg = gen_reg_rtx (Pmode);
1817890075Sobrien
1817990075Sobrien  if (GET_CODE (orig) == CONST)
1818090075Sobrien    {
18181169689Skan      rtx reg_temp;
18182169689Skan
1818390075Sobrien      if (GET_CODE (XEXP (orig, 0)) == PLUS
1818490075Sobrien	  && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx)
1818590075Sobrien	return orig;
1818690075Sobrien
18187169689Skan      gcc_assert (GET_CODE (XEXP (orig, 0)) == PLUS);
18188132718Skan
18189169689Skan      /* Use a different reg for the intermediate value, as
18190169689Skan	 it will be marked UNCHANGING.  */
18191169689Skan      reg_temp = no_new_pseudos ? reg : gen_reg_rtx (Pmode);
18192169689Skan      base = rs6000_machopic_legitimize_pic_address (XEXP (XEXP (orig, 0), 0),
18193169689Skan						     Pmode, reg_temp);
18194169689Skan      offset =
18195169689Skan	rs6000_machopic_legitimize_pic_address (XEXP (XEXP (orig, 0), 1),
18196169689Skan						Pmode, reg);
1819790075Sobrien
1819890075Sobrien      if (GET_CODE (offset) == CONST_INT)
1819990075Sobrien	{
1820090075Sobrien	  if (SMALL_INT (offset))
1820190075Sobrien	    return plus_constant (base, INTVAL (offset));
1820290075Sobrien	  else if (! reload_in_progress && ! reload_completed)
1820390075Sobrien	    offset = force_reg (Pmode, offset);
1820490075Sobrien	  else
1820590075Sobrien	    {
1820690075Sobrien 	      rtx mem = force_const_mem (Pmode, orig);
1820790075Sobrien	      return machopic_legitimize_pic_address (mem, Pmode, reg);
1820890075Sobrien	    }
1820990075Sobrien	}
18210169689Skan      return gen_rtx_PLUS (Pmode, base, offset);
1821190075Sobrien    }
1821290075Sobrien
1821390075Sobrien  /* Fall back on generic machopic code.  */
1821490075Sobrien  return machopic_legitimize_pic_address (orig, mode, reg);
1821590075Sobrien}
1821690075Sobrien
18217169689Skan/* Output a .machine directive for the Darwin assembler, and call
18218169689Skan   the generic start_file routine.  */
1821990075Sobrien
18220169689Skanstatic void
18221169689Skanrs6000_darwin_file_start (void)
1822290075Sobrien{
18223169689Skan  static const struct
18224169689Skan  {
18225169689Skan    const char *arg;
18226169689Skan    const char *name;
18227169689Skan    int if_set;
18228169689Skan  } mapping[] = {
18229169689Skan    { "ppc64", "ppc64", MASK_64BIT },
18230169689Skan    { "970", "ppc970", MASK_PPC_GPOPT | MASK_MFCRF | MASK_POWERPC64 },
18231169689Skan    { "power4", "ppc970", 0 },
18232169689Skan    { "G5", "ppc970", 0 },
18233169689Skan    { "7450", "ppc7450", 0 },
18234169689Skan    { "7400", "ppc7400", MASK_ALTIVEC },
18235169689Skan    { "G4", "ppc7400", 0 },
18236169689Skan    { "750", "ppc750", 0 },
18237169689Skan    { "740", "ppc750", 0 },
18238169689Skan    { "G3", "ppc750", 0 },
18239169689Skan    { "604e", "ppc604e", 0 },
18240169689Skan    { "604", "ppc604", 0 },
18241169689Skan    { "603e", "ppc603", 0 },
18242169689Skan    { "603", "ppc603", 0 },
18243169689Skan    { "601", "ppc601", 0 },
18244169689Skan    { NULL, "ppc", 0 } };
18245169689Skan  const char *cpu_id = "";
18246169689Skan  size_t i;
18247169689Skan
18248169689Skan  rs6000_file_start ();
18249169689Skan  darwin_file_start ();
18250169689Skan
18251169689Skan  /* Determine the argument to -mcpu=.  Default to G3 if not specified.  */
18252169689Skan  for (i = 0; i < ARRAY_SIZE (rs6000_select); i++)
18253169689Skan    if (rs6000_select[i].set_arch_p && rs6000_select[i].string
18254169689Skan	&& rs6000_select[i].string[0] != '\0')
18255169689Skan      cpu_id = rs6000_select[i].string;
18256169689Skan
18257169689Skan  /* Look through the mapping array.  Pick the first name that either
18258169689Skan     matches the argument, has a bit set in IF_SET that is also set
18259169689Skan     in the target flags, or has a NULL name.  */
18260169689Skan
18261169689Skan  i = 0;
18262169689Skan  while (mapping[i].arg != NULL
18263169689Skan	 && strcmp (mapping[i].arg, cpu_id) != 0
18264169689Skan	 && (mapping[i].if_set & target_flags) == 0)
18265169689Skan    i++;
18266169689Skan
18267169689Skan  fprintf (asm_out_file, "\t.machine %s\n", mapping[i].name);
1826890075Sobrien}
1826990075Sobrien
1827090075Sobrien#endif /* TARGET_MACHO */
1827190075Sobrien
1827290075Sobrien#if TARGET_ELF
18273169689Skanstatic int
18274169689Skanrs6000_elf_reloc_rw_mask (void)
1827590075Sobrien{
18276169689Skan  if (flag_pic)
18277169689Skan    return 3;
18278169689Skan  else if (DEFAULT_ABI == ABI_AIX)
18279169689Skan    return 2;
18280169689Skan  else
18281169689Skan    return 0;
1828290075Sobrien}
1828390075Sobrien
1828490075Sobrien/* Record an element in the table of global constructors.  SYMBOL is
1828590075Sobrien   a SYMBOL_REF of the function to be called; PRIORITY is a number
1828690075Sobrien   between 0 and MAX_INIT_PRIORITY.
1828790075Sobrien
1828890075Sobrien   This differs from default_named_section_asm_out_constructor in
1828990075Sobrien   that we have special handling for -mrelocatable.  */
1829090075Sobrien
1829190075Sobrienstatic void
18292132718Skanrs6000_elf_asm_out_constructor (rtx symbol, int priority)
1829390075Sobrien{
1829490075Sobrien  const char *section = ".ctors";
1829590075Sobrien  char buf[16];
1829690075Sobrien
1829790075Sobrien  if (priority != DEFAULT_INIT_PRIORITY)
1829890075Sobrien    {
1829990075Sobrien      sprintf (buf, ".ctors.%.5u",
18300169689Skan	       /* Invert the numbering so the linker puts us in the proper
18301169689Skan		  order; constructors are run from right to left, and the
18302169689Skan		  linker sorts in increasing order.  */
18303169689Skan	       MAX_INIT_PRIORITY - priority);
1830490075Sobrien      section = buf;
1830590075Sobrien    }
1830690075Sobrien
18307169689Skan  switch_to_section (get_section (section, SECTION_WRITE, NULL));
1830890075Sobrien  assemble_align (POINTER_SIZE);
1830990075Sobrien
1831090075Sobrien  if (TARGET_RELOCATABLE)
1831190075Sobrien    {
1831290075Sobrien      fputs ("\t.long (", asm_out_file);
1831390075Sobrien      output_addr_const (asm_out_file, symbol);
1831490075Sobrien      fputs (")@fixup\n", asm_out_file);
1831590075Sobrien    }
1831690075Sobrien  else
1831790075Sobrien    assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
1831890075Sobrien}
1831990075Sobrien
1832090075Sobrienstatic void
18321132718Skanrs6000_elf_asm_out_destructor (rtx symbol, int priority)
1832290075Sobrien{
1832390075Sobrien  const char *section = ".dtors";
1832490075Sobrien  char buf[16];
1832590075Sobrien
1832690075Sobrien  if (priority != DEFAULT_INIT_PRIORITY)
1832790075Sobrien    {
1832890075Sobrien      sprintf (buf, ".dtors.%.5u",
18329169689Skan	       /* Invert the numbering so the linker puts us in the proper
18330169689Skan		  order; constructors are run from right to left, and the
18331169689Skan		  linker sorts in increasing order.  */
18332169689Skan	       MAX_INIT_PRIORITY - priority);
1833390075Sobrien      section = buf;
1833490075Sobrien    }
1833590075Sobrien
18336169689Skan  switch_to_section (get_section (section, SECTION_WRITE, NULL));
1833790075Sobrien  assemble_align (POINTER_SIZE);
1833890075Sobrien
1833990075Sobrien  if (TARGET_RELOCATABLE)
1834090075Sobrien    {
1834190075Sobrien      fputs ("\t.long (", asm_out_file);
1834290075Sobrien      output_addr_const (asm_out_file, symbol);
1834390075Sobrien      fputs (")@fixup\n", asm_out_file);
1834490075Sobrien    }
1834590075Sobrien  else
1834690075Sobrien    assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
1834790075Sobrien}
18348132718Skan
18349132718Skanvoid
18350132718Skanrs6000_elf_declare_function_name (FILE *file, const char *name, tree decl)
18351132718Skan{
18352132718Skan  if (TARGET_64BIT)
18353132718Skan    {
18354132718Skan      fputs ("\t.section\t\".opd\",\"aw\"\n\t.align 3\n", file);
18355132718Skan      ASM_OUTPUT_LABEL (file, name);
18356132718Skan      fputs (DOUBLE_INT_ASM_OP, file);
18357169689Skan      rs6000_output_function_entry (file, name);
18358169689Skan      fputs (",.TOC.@tocbase,0\n\t.previous\n", file);
18359169689Skan      if (DOT_SYMBOLS)
18360132718Skan	{
18361169689Skan	  fputs ("\t.size\t", file);
18362132718Skan	  assemble_name (file, name);
18363169689Skan	  fputs (",24\n\t.type\t.", file);
18364169689Skan	  assemble_name (file, name);
18365169689Skan	  fputs (",@function\n", file);
18366169689Skan	  if (TREE_PUBLIC (decl) && ! DECL_WEAK (decl))
18367169689Skan	    {
18368169689Skan	      fputs ("\t.globl\t.", file);
18369169689Skan	      assemble_name (file, name);
18370169689Skan	      putc ('\n', file);
18371169689Skan	    }
18372132718Skan	}
18373169689Skan      else
18374169689Skan	ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function");
18375132718Skan      ASM_DECLARE_RESULT (file, DECL_RESULT (decl));
18376169689Skan      rs6000_output_function_entry (file, name);
18377169689Skan      fputs (":\n", file);
18378132718Skan      return;
18379132718Skan    }
18380132718Skan
18381132718Skan  if (TARGET_RELOCATABLE
18382169689Skan      && !TARGET_SECURE_PLT
18383132718Skan      && (get_pool_size () != 0 || current_function_profile)
18384132718Skan      && uses_TOC ())
18385132718Skan    {
18386132718Skan      char buf[256];
18387132718Skan
18388132718Skan      (*targetm.asm_out.internal_label) (file, "LCL", rs6000_pic_labelno);
18389132718Skan
18390132718Skan      ASM_GENERATE_INTERNAL_LABEL (buf, "LCTOC", 1);
18391132718Skan      fprintf (file, "\t.long ");
18392132718Skan      assemble_name (file, buf);
18393132718Skan      putc ('-', file);
18394132718Skan      ASM_GENERATE_INTERNAL_LABEL (buf, "LCF", rs6000_pic_labelno);
18395132718Skan      assemble_name (file, buf);
18396132718Skan      putc ('\n', file);
18397132718Skan    }
18398132718Skan
18399132718Skan  ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function");
18400132718Skan  ASM_DECLARE_RESULT (file, DECL_RESULT (decl));
18401132718Skan
18402132718Skan  if (DEFAULT_ABI == ABI_AIX)
18403132718Skan    {
18404132718Skan      const char *desc_name, *orig_name;
18405132718Skan
18406132718Skan      orig_name = (*targetm.strip_name_encoding) (name);
18407132718Skan      desc_name = orig_name;
18408132718Skan      while (*desc_name == '.')
18409132718Skan	desc_name++;
18410132718Skan
18411132718Skan      if (TREE_PUBLIC (decl))
18412132718Skan	fprintf (file, "\t.globl %s\n", desc_name);
18413132718Skan
18414132718Skan      fprintf (file, "%s\n", MINIMAL_TOC_SECTION_ASM_OP);
18415132718Skan      fprintf (file, "%s:\n", desc_name);
18416132718Skan      fprintf (file, "\t.long %s\n", orig_name);
18417132718Skan      fputs ("\t.long _GLOBAL_OFFSET_TABLE_\n", file);
18418132718Skan      if (DEFAULT_ABI == ABI_AIX)
18419132718Skan	fputs ("\t.long 0\n", file);
18420132718Skan      fprintf (file, "\t.previous\n");
18421132718Skan    }
18422132718Skan  ASM_OUTPUT_LABEL (file, name);
18423132718Skan}
18424146895Skan
18425146895Skanstatic void
18426146895Skanrs6000_elf_end_indicate_exec_stack (void)
18427146895Skan{
18428146895Skan  if (TARGET_32BIT)
18429146895Skan    file_end_indicate_exec_stack ();
18430146895Skan}
1843190075Sobrien#endif
1843290075Sobrien
18433117395Skan#if TARGET_XCOFF
1843490075Sobrienstatic void
18435169689Skanrs6000_xcoff_asm_output_anchor (rtx symbol)
18436169689Skan{
18437169689Skan  char buffer[100];
18438169689Skan
18439169689Skan  sprintf (buffer, "$ + " HOST_WIDE_INT_PRINT_DEC,
18440169689Skan	   SYMBOL_REF_BLOCK_OFFSET (symbol));
18441169689Skan  ASM_OUTPUT_DEF (asm_out_file, XSTR (symbol, 0), buffer);
18442169689Skan}
18443169689Skan
18444169689Skanstatic void
18445132718Skanrs6000_xcoff_asm_globalize_label (FILE *stream, const char *name)
1844690075Sobrien{
18447117395Skan  fputs (GLOBAL_ASM_OP, stream);
18448117395Skan  RS6000_OUTPUT_BASENAME (stream, name);
18449117395Skan  putc ('\n', stream);
1845090075Sobrien}
18451117395Skan
18452169689Skan/* A get_unnamed_decl callback, used for read-only sections.  PTR
18453169689Skan   points to the section string variable.  */
18454169689Skan
18455117395Skanstatic void
18456169689Skanrs6000_xcoff_output_readonly_section_asm_op (const void *directive)
18457117395Skan{
18458169689Skan  fprintf (asm_out_file, "\t.csect %s[RO],3\n",
18459169689Skan	   *(const char *const *) directive);
18460169689Skan}
18461169689Skan
18462169689Skan/* Likewise for read-write sections.  */
18463169689Skan
18464169689Skanstatic void
18465169689Skanrs6000_xcoff_output_readwrite_section_asm_op (const void *directive)
18466169689Skan{
18467169689Skan  fprintf (asm_out_file, "\t.csect %s[RW],3\n",
18468169689Skan	   *(const char *const *) directive);
18469169689Skan}
18470169689Skan
18471169689Skan/* A get_unnamed_section callback, used for switching to toc_section.  */
18472169689Skan
18473169689Skanstatic void
18474169689Skanrs6000_xcoff_output_toc_section_asm_op (const void *data ATTRIBUTE_UNUSED)
18475169689Skan{
18476169689Skan  if (TARGET_MINIMAL_TOC)
18477169689Skan    {
18478169689Skan      /* toc_section is always selected at least once from
18479169689Skan	 rs6000_xcoff_file_start, so this is guaranteed to
18480169689Skan	 always be defined once and only once in each file.  */
18481169689Skan      if (!toc_initialized)
18482169689Skan	{
18483169689Skan	  fputs ("\t.toc\nLCTOC..1:\n", asm_out_file);
18484169689Skan	  fputs ("\t.tc toc_table[TC],toc_table[RW]\n", asm_out_file);
18485169689Skan	  toc_initialized = 1;
18486169689Skan	}
18487169689Skan      fprintf (asm_out_file, "\t.csect toc_table[RW]%s\n",
18488169689Skan	       (TARGET_32BIT ? "" : ",3"));
18489169689Skan    }
18490169689Skan  else
18491169689Skan    fputs ("\t.toc\n", asm_out_file);
18492169689Skan}
18493169689Skan
18494169689Skan/* Implement TARGET_ASM_INIT_SECTIONS.  */
18495169689Skan
18496169689Skanstatic void
18497169689Skanrs6000_xcoff_asm_init_sections (void)
18498169689Skan{
18499169689Skan  read_only_data_section
18500169689Skan    = get_unnamed_section (0, rs6000_xcoff_output_readonly_section_asm_op,
18501169689Skan			   &xcoff_read_only_section_name);
18502169689Skan
18503169689Skan  private_data_section
18504169689Skan    = get_unnamed_section (SECTION_WRITE,
18505169689Skan			   rs6000_xcoff_output_readwrite_section_asm_op,
18506169689Skan			   &xcoff_private_data_section_name);
18507169689Skan
18508169689Skan  read_only_private_data_section
18509169689Skan    = get_unnamed_section (0, rs6000_xcoff_output_readonly_section_asm_op,
18510169689Skan			   &xcoff_private_data_section_name);
18511169689Skan
18512169689Skan  toc_section
18513169689Skan    = get_unnamed_section (0, rs6000_xcoff_output_toc_section_asm_op, NULL);
18514169689Skan
18515169689Skan  readonly_data_section = read_only_data_section;
18516169689Skan  exception_section = data_section;
18517169689Skan}
18518169689Skan
18519169689Skanstatic int
18520169689Skanrs6000_xcoff_reloc_rw_mask (void)
18521169689Skan{
18522169689Skan  return 3;
18523169689Skan}
18524169689Skan
18525169689Skanstatic void
18526169689Skanrs6000_xcoff_asm_named_section (const char *name, unsigned int flags,
18527169689Skan				tree decl ATTRIBUTE_UNUSED)
18528169689Skan{
18529117395Skan  int smclass;
18530117395Skan  static const char * const suffix[3] = { "PR", "RO", "RW" };
18531117395Skan
18532117395Skan  if (flags & SECTION_CODE)
18533117395Skan    smclass = 0;
18534117395Skan  else if (flags & SECTION_WRITE)
18535117395Skan    smclass = 2;
18536117395Skan  else
18537117395Skan    smclass = 1;
18538117395Skan
18539117395Skan  fprintf (asm_out_file, "\t.csect %s%s[%s],%u\n",
18540117395Skan	   (flags & SECTION_CODE) ? "." : "",
18541117395Skan	   name, suffix[smclass], flags & SECTION_ENTSIZE);
18542117395Skan}
18543117395Skan
18544169689Skanstatic section *
18545169689Skanrs6000_xcoff_select_section (tree decl, int reloc,
18546169689Skan			     unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
18547117395Skan{
18548169689Skan  if (decl_readonly_section (decl, reloc))
18549117395Skan    {
18550117395Skan      if (TREE_PUBLIC (decl))
18551169689Skan	return read_only_data_section;
18552117395Skan      else
18553169689Skan	return read_only_private_data_section;
18554117395Skan    }
18555117395Skan  else
18556117395Skan    {
18557117395Skan      if (TREE_PUBLIC (decl))
18558169689Skan	return data_section;
18559117395Skan      else
18560169689Skan	return private_data_section;
18561117395Skan    }
18562117395Skan}
18563117395Skan
18564117395Skanstatic void
18565132718Skanrs6000_xcoff_unique_section (tree decl, int reloc ATTRIBUTE_UNUSED)
18566117395Skan{
18567117395Skan  const char *name;
18568117395Skan
18569117395Skan  /* Use select_section for private and uninitialized data.  */
18570117395Skan  if (!TREE_PUBLIC (decl)
18571117395Skan      || DECL_COMMON (decl)
18572117395Skan      || DECL_INITIAL (decl) == NULL_TREE
18573117395Skan      || DECL_INITIAL (decl) == error_mark_node
18574117395Skan      || (flag_zero_initialized_in_bss
18575117395Skan	  && initializer_zerop (DECL_INITIAL (decl))))
18576117395Skan    return;
18577117395Skan
18578117395Skan  name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
18579117395Skan  name = (*targetm.strip_name_encoding) (name);
18580117395Skan  DECL_SECTION_NAME (decl) = build_string (strlen (name), name);
18581117395Skan}
18582117395Skan
18583117395Skan/* Select section for constant in constant pool.
18584117395Skan
18585117395Skan   On RS/6000, all constants are in the private read-only data area.
18586117395Skan   However, if this is being placed in the TOC it must be output as a
18587117395Skan   toc entry.  */
18588117395Skan
18589169689Skanstatic section *
18590169689Skanrs6000_xcoff_select_rtx_section (enum machine_mode mode, rtx x,
18591169689Skan				 unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
18592117395Skan{
18593117395Skan  if (ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (x, mode))
18594169689Skan    return toc_section;
18595117395Skan  else
18596169689Skan    return read_only_private_data_section;
18597117395Skan}
18598117395Skan
18599117395Skan/* Remove any trailing [DS] or the like from the symbol name.  */
18600117395Skan
18601117395Skanstatic const char *
18602132718Skanrs6000_xcoff_strip_name_encoding (const char *name)
18603117395Skan{
18604117395Skan  size_t len;
18605117395Skan  if (*name == '*')
18606117395Skan    name++;
18607117395Skan  len = strlen (name);
18608117395Skan  if (name[len - 1] == ']')
18609117395Skan    return ggc_alloc_string (name, len - 4);
18610117395Skan  else
18611117395Skan    return name;
18612117395Skan}
18613117395Skan
18614117395Skan/* Section attributes.  AIX is always PIC.  */
18615117395Skan
18616117395Skanstatic unsigned int
18617132718Skanrs6000_xcoff_section_type_flags (tree decl, const char *name, int reloc)
18618117395Skan{
18619117395Skan  unsigned int align;
18620169689Skan  unsigned int flags = default_section_type_flags (decl, name, reloc);
18621117395Skan
18622117395Skan  /* Align to at least UNIT size.  */
18623117395Skan  if (flags & SECTION_CODE)
18624117395Skan    align = MIN_UNITS_PER_WORD;
18625117395Skan  else
18626117395Skan    /* Increase alignment of large objects if not already stricter.  */
18627117395Skan    align = MAX ((DECL_ALIGN (decl) / BITS_PER_UNIT),
18628117395Skan		 int_size_in_bytes (TREE_TYPE (decl)) > MIN_UNITS_PER_WORD
18629117395Skan		 ? UNITS_PER_FP_WORD : MIN_UNITS_PER_WORD);
18630117395Skan
18631117395Skan  return flags | (exact_log2 (align) & SECTION_ENTSIZE);
18632117395Skan}
18633117395Skan
18634132718Skan/* Output at beginning of assembler file.
18635117395Skan
18636132718Skan   Initialize the section names for the RS/6000 at this point.
18637117395Skan
18638132718Skan   Specify filename, including full path, to assembler.
18639132718Skan
18640132718Skan   We want to go into the TOC section so at least one .toc will be emitted.
18641132718Skan   Also, in order to output proper .bs/.es pairs, we need at least one static
18642132718Skan   [RW] section emitted.
18643132718Skan
18644132718Skan   Finally, declare mcount when profiling to make the assembler happy.  */
18645132718Skan
18646117395Skanstatic void
18647132718Skanrs6000_xcoff_file_start (void)
18648117395Skan{
18649132718Skan  rs6000_gen_section_name (&xcoff_bss_section_name,
18650132718Skan			   main_input_filename, ".bss_");
18651132718Skan  rs6000_gen_section_name (&xcoff_private_data_section_name,
18652132718Skan			   main_input_filename, ".rw_");
18653132718Skan  rs6000_gen_section_name (&xcoff_read_only_section_name,
18654132718Skan			   main_input_filename, ".ro_");
18655132718Skan
18656132718Skan  fputs ("\t.file\t", asm_out_file);
18657132718Skan  output_quoted_string (asm_out_file, main_input_filename);
18658132718Skan  fputc ('\n', asm_out_file);
18659132718Skan  if (write_symbols != NO_DEBUG)
18660169689Skan    switch_to_section (private_data_section);
18661169689Skan  switch_to_section (text_section);
18662132718Skan  if (profile_flag)
18663132718Skan    fprintf (asm_out_file, "\t.extern %s\n", RS6000_MCOUNT);
18664132718Skan  rs6000_file_start ();
18665117395Skan}
18666117395Skan
18667132718Skan/* Output at end of assembler file.
18668132718Skan   On the RS/6000, referencing data should automatically pull in text.  */
18669117395Skan
18670132718Skanstatic void
18671132718Skanrs6000_xcoff_file_end (void)
18672132718Skan{
18673169689Skan  switch_to_section (text_section);
18674132718Skan  fputs ("_section_.text:\n", asm_out_file);
18675169689Skan  switch_to_section (data_section);
18676132718Skan  fputs (TARGET_32BIT
18677132718Skan	 ? "\t.long _section_.text\n" : "\t.llong _section_.text\n",
18678132718Skan	 asm_out_file);
18679132718Skan}
18680132718Skan#endif /* TARGET_XCOFF */
18681132718Skan
18682132718Skan/* Compute a (partial) cost for rtx X.  Return true if the complete
18683132718Skan   cost has been computed, and false if subexpressions should be
18684132718Skan   scanned.  In either case, *TOTAL contains the cost result.  */
18685132718Skan
18686132718Skanstatic bool
18687169689Skanrs6000_rtx_costs (rtx x, int code, int outer_code, int *total)
18688132718Skan{
18689169689Skan  enum machine_mode mode = GET_MODE (x);
18690169689Skan
18691132718Skan  switch (code)
18692132718Skan    {
18693169689Skan      /* On the RS/6000, if it is valid in the insn, it is free.  */
18694132718Skan    case CONST_INT:
18695169689Skan      if (((outer_code == SET
18696169689Skan	    || outer_code == PLUS
18697169689Skan	    || outer_code == MINUS)
18698169689Skan	   && (satisfies_constraint_I (x)
18699169689Skan	       || satisfies_constraint_L (x)))
18700169689Skan	  || (outer_code == AND
18701169689Skan	      && (satisfies_constraint_K (x)
18702169689Skan		  || (mode == SImode
18703169689Skan		      ? satisfies_constraint_L (x)
18704169689Skan		      : satisfies_constraint_J (x))
18705169689Skan		  || mask_operand (x, mode)
18706169689Skan		  || (mode == DImode
18707169689Skan		      && mask64_operand (x, DImode))))
18708169689Skan	  || ((outer_code == IOR || outer_code == XOR)
18709169689Skan	      && (satisfies_constraint_K (x)
18710169689Skan		  || (mode == SImode
18711169689Skan		      ? satisfies_constraint_L (x)
18712169689Skan		      : satisfies_constraint_J (x))))
18713169689Skan	  || outer_code == ASHIFT
18714169689Skan	  || outer_code == ASHIFTRT
18715169689Skan	  || outer_code == LSHIFTRT
18716169689Skan	  || outer_code == ROTATE
18717169689Skan	  || outer_code == ROTATERT
18718169689Skan	  || outer_code == ZERO_EXTRACT
18719169689Skan	  || (outer_code == MULT
18720169689Skan	      && satisfies_constraint_I (x))
18721169689Skan	  || ((outer_code == DIV || outer_code == UDIV
18722169689Skan	       || outer_code == MOD || outer_code == UMOD)
18723169689Skan	      && exact_log2 (INTVAL (x)) >= 0)
18724169689Skan	  || (outer_code == COMPARE
18725169689Skan	      && (satisfies_constraint_I (x)
18726169689Skan		  || satisfies_constraint_K (x)))
18727169689Skan	  || (outer_code == EQ
18728169689Skan	      && (satisfies_constraint_I (x)
18729169689Skan		  || satisfies_constraint_K (x)
18730169689Skan		  || (mode == SImode
18731169689Skan		      ? satisfies_constraint_L (x)
18732169689Skan		      : satisfies_constraint_J (x))))
18733169689Skan	  || (outer_code == GTU
18734169689Skan	      && satisfies_constraint_I (x))
18735169689Skan	  || (outer_code == LTU
18736169689Skan	      && satisfies_constraint_P (x)))
18737169689Skan	{
18738169689Skan	  *total = 0;
18739169689Skan	  return true;
18740169689Skan	}
18741169689Skan      else if ((outer_code == PLUS
18742169689Skan		&& reg_or_add_cint_operand (x, VOIDmode))
18743169689Skan	       || (outer_code == MINUS
18744169689Skan		   && reg_or_sub_cint_operand (x, VOIDmode))
18745169689Skan	       || ((outer_code == SET
18746169689Skan		    || outer_code == IOR
18747169689Skan		    || outer_code == XOR)
18748169689Skan		   && (INTVAL (x)
18749169689Skan		       & ~ (unsigned HOST_WIDE_INT) 0xffffffff) == 0))
18750169689Skan	{
18751169689Skan	  *total = COSTS_N_INSNS (1);
18752169689Skan	  return true;
18753169689Skan	}
18754169689Skan      /* FALLTHRU */
18755169689Skan
18756169689Skan    case CONST_DOUBLE:
18757169689Skan      if (mode == DImode && code == CONST_DOUBLE)
18758169689Skan	{
18759169689Skan	  if ((outer_code == IOR || outer_code == XOR)
18760169689Skan	      && CONST_DOUBLE_HIGH (x) == 0
18761169689Skan	      && (CONST_DOUBLE_LOW (x)
18762169689Skan		  & ~ (unsigned HOST_WIDE_INT) 0xffff) == 0)
18763169689Skan	    {
18764169689Skan	      *total = 0;
18765169689Skan	      return true;
18766169689Skan	    }
18767169689Skan	  else if ((outer_code == AND && and64_2_operand (x, DImode))
18768169689Skan		   || ((outer_code == SET
18769169689Skan			|| outer_code == IOR
18770169689Skan			|| outer_code == XOR)
18771169689Skan		       && CONST_DOUBLE_HIGH (x) == 0))
18772169689Skan	    {
18773169689Skan	      *total = COSTS_N_INSNS (1);
18774169689Skan	      return true;
18775169689Skan	    }
18776169689Skan	}
18777169689Skan      /* FALLTHRU */
18778169689Skan
18779132718Skan    case CONST:
18780169689Skan    case HIGH:
18781169689Skan    case SYMBOL_REF:
18782169689Skan    case MEM:
18783169689Skan      /* When optimizing for size, MEM should be slightly more expensive
18784169689Skan	 than generating address, e.g., (plus (reg) (const)).
18785169689Skan	 L1 cache latency is about two instructions.  */
18786169689Skan      *total = optimize_size ? COSTS_N_INSNS (1) + 1 : COSTS_N_INSNS (2);
18787169689Skan      return true;
18788169689Skan
18789132718Skan    case LABEL_REF:
18790132718Skan      *total = 0;
18791132718Skan      return true;
18792132718Skan
18793132718Skan    case PLUS:
18794169689Skan      if (mode == DFmode)
18795169689Skan	{
18796169689Skan	  if (GET_CODE (XEXP (x, 0)) == MULT)
18797169689Skan	    {
18798169689Skan	      /* FNMA accounted in outer NEG.  */
18799169689Skan	      if (outer_code == NEG)
18800169689Skan		*total = rs6000_cost->dmul - rs6000_cost->fp;
18801169689Skan	      else
18802169689Skan		*total = rs6000_cost->dmul;
18803169689Skan	    }
18804169689Skan	  else
18805169689Skan	    *total = rs6000_cost->fp;
18806169689Skan	}
18807169689Skan      else if (mode == SFmode)
18808169689Skan	{
18809169689Skan	  /* FNMA accounted in outer NEG.  */
18810169689Skan	  if (outer_code == NEG && GET_CODE (XEXP (x, 0)) == MULT)
18811169689Skan	    *total = 0;
18812169689Skan	  else
18813169689Skan	    *total = rs6000_cost->fp;
18814169689Skan	}
18815169689Skan      else
18816169689Skan	*total = COSTS_N_INSNS (1);
18817169689Skan      return false;
18818132718Skan
18819169689Skan    case MINUS:
18820169689Skan      if (mode == DFmode)
18821132718Skan	{
18822169689Skan	  if (GET_CODE (XEXP (x, 0)) == MULT)
18823169689Skan	    {
18824169689Skan	      /* FNMA accounted in outer NEG.  */
18825169689Skan	      if (outer_code == NEG)
18826169689Skan		*total = 0;
18827169689Skan	      else
18828169689Skan		*total = rs6000_cost->dmul;
18829169689Skan	    }
18830169689Skan	  else
18831169689Skan	    *total = rs6000_cost->fp;
18832132718Skan	}
18833169689Skan      else if (mode == SFmode)
18834132718Skan	{
18835169689Skan	  /* FNMA accounted in outer NEG.  */
18836169689Skan	  if (outer_code == NEG && GET_CODE (XEXP (x, 0)) == MULT)
18837169689Skan	    *total = 0;
18838169689Skan	  else
18839169689Skan	    *total = rs6000_cost->fp;
18840169689Skan	}
18841169689Skan      else
18842169689Skan	*total = COSTS_N_INSNS (1);
18843169689Skan      return false;
18844132718Skan
18845169689Skan    case MULT:
18846169689Skan      if (GET_CODE (XEXP (x, 1)) == CONST_INT
18847169689Skan	  && satisfies_constraint_I (XEXP (x, 1)))
18848169689Skan	{
18849169689Skan	  if (INTVAL (XEXP (x, 1)) >= -256
18850169689Skan	      && INTVAL (XEXP (x, 1)) <= 255)
18851169689Skan	    *total = rs6000_cost->mulsi_const9;
18852169689Skan	  else
18853169689Skan	    *total = rs6000_cost->mulsi_const;
18854132718Skan	}
18855169689Skan      /* FMA accounted in outer PLUS/MINUS.  */
18856169689Skan      else if ((mode == DFmode || mode == SFmode)
18857169689Skan	       && (outer_code == PLUS || outer_code == MINUS))
18858169689Skan	*total = 0;
18859169689Skan      else if (mode == DFmode)
18860169689Skan	*total = rs6000_cost->dmul;
18861169689Skan      else if (mode == SFmode)
18862169689Skan	*total = rs6000_cost->fp;
18863169689Skan      else if (mode == DImode)
18864169689Skan	*total = rs6000_cost->muldi;
18865169689Skan      else
18866169689Skan	*total = rs6000_cost->mulsi;
18867169689Skan      return false;
18868132718Skan
18869132718Skan    case DIV:
18870132718Skan    case MOD:
18871169689Skan      if (FLOAT_MODE_P (mode))
18872132718Skan	{
18873169689Skan	  *total = mode == DFmode ? rs6000_cost->ddiv
18874169689Skan				  : rs6000_cost->sdiv;
18875169689Skan	  return false;
18876132718Skan	}
18877132718Skan      /* FALLTHRU */
18878132718Skan
18879132718Skan    case UDIV:
18880132718Skan    case UMOD:
18881169689Skan      if (GET_CODE (XEXP (x, 1)) == CONST_INT
18882169689Skan	  && exact_log2 (INTVAL (XEXP (x, 1))) >= 0)
18883132718Skan	{
18884169689Skan	  if (code == DIV || code == MOD)
18885169689Skan	    /* Shift, addze */
18886169689Skan	    *total = COSTS_N_INSNS (2);
18887169689Skan	  else
18888169689Skan	    /* Shift */
18889169689Skan	    *total = COSTS_N_INSNS (1);
18890169689Skan	}
18891169689Skan      else
18892169689Skan	{
18893169689Skan	  if (GET_MODE (XEXP (x, 1)) == DImode)
18894169689Skan	    *total = rs6000_cost->divdi;
18895169689Skan	  else
18896169689Skan	    *total = rs6000_cost->divsi;
18897169689Skan	}
18898169689Skan      /* Add in shift and subtract for MOD. */
18899169689Skan      if (code == MOD || code == UMOD)
18900169689Skan	*total += COSTS_N_INSNS (2);
18901169689Skan      return false;
18902132718Skan
18903169689Skan    case FFS:
18904169689Skan      *total = COSTS_N_INSNS (4);
18905169689Skan      return false;
18906132718Skan
18907169689Skan    case NOT:
18908169689Skan      if (outer_code == AND || outer_code == IOR || outer_code == XOR)
18909169689Skan	{
18910169689Skan	  *total = 0;
18911169689Skan	  return false;
18912169689Skan	}
18913169689Skan      /* FALLTHRU */
18914132718Skan
18915169689Skan    case AND:
18916169689Skan    case IOR:
18917169689Skan    case XOR:
18918169689Skan    case ZERO_EXTRACT:
18919169689Skan      *total = COSTS_N_INSNS (1);
18920169689Skan      return false;
18921132718Skan
18922169689Skan    case ASHIFT:
18923169689Skan    case ASHIFTRT:
18924169689Skan    case LSHIFTRT:
18925169689Skan    case ROTATE:
18926169689Skan    case ROTATERT:
18927169689Skan      /* Handle mul_highpart.  */
18928169689Skan      if (outer_code == TRUNCATE
18929169689Skan	  && GET_CODE (XEXP (x, 0)) == MULT)
18930169689Skan	{
18931169689Skan	  if (mode == DImode)
18932169689Skan	    *total = rs6000_cost->muldi;
18933169689Skan	  else
18934169689Skan	    *total = rs6000_cost->mulsi;
18935132718Skan	  return true;
18936169689Skan	}
18937169689Skan      else if (outer_code == AND)
18938169689Skan	*total = 0;
18939169689Skan      else
18940169689Skan	*total = COSTS_N_INSNS (1);
18941169689Skan      return false;
18942132718Skan
18943169689Skan    case SIGN_EXTEND:
18944169689Skan    case ZERO_EXTEND:
18945169689Skan      if (GET_CODE (XEXP (x, 0)) == MEM)
18946169689Skan	*total = 0;
18947169689Skan      else
18948169689Skan	*total = COSTS_N_INSNS (1);
18949169689Skan      return false;
18950132718Skan
18951169689Skan    case COMPARE:
18952169689Skan    case NEG:
18953169689Skan    case ABS:
18954169689Skan      if (!FLOAT_MODE_P (mode))
18955169689Skan	{
18956169689Skan	  *total = COSTS_N_INSNS (1);
18957169689Skan	  return false;
18958169689Skan	}
18959169689Skan      /* FALLTHRU */
18960132718Skan
18961169689Skan    case FLOAT:
18962169689Skan    case UNSIGNED_FLOAT:
18963169689Skan    case FIX:
18964169689Skan    case UNSIGNED_FIX:
18965169689Skan    case FLOAT_TRUNCATE:
18966169689Skan      *total = rs6000_cost->fp;
18967169689Skan      return false;
18968132718Skan
18969169689Skan    case FLOAT_EXTEND:
18970169689Skan      if (mode == DFmode)
18971169689Skan	*total = 0;
18972169689Skan      else
18973169689Skan	*total = rs6000_cost->fp;
18974169689Skan      return false;
18975132718Skan
18976169689Skan    case UNSPEC:
18977169689Skan      switch (XINT (x, 1))
18978169689Skan	{
18979169689Skan	case UNSPEC_FRSP:
18980169689Skan	  *total = rs6000_cost->fp;
18981132718Skan	  return true;
18982132718Skan
18983169689Skan	default:
18984169689Skan	  break;
18985169689Skan	}
18986169689Skan      break;
18987132718Skan
18988169689Skan    case CALL:
18989169689Skan    case IF_THEN_ELSE:
18990169689Skan      if (optimize_size)
18991169689Skan	{
18992169689Skan	  *total = COSTS_N_INSNS (1);
18993132718Skan	  return true;
18994169689Skan	}
18995169689Skan      else if (FLOAT_MODE_P (mode)
18996169689Skan	       && TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS)
18997169689Skan	{
18998169689Skan	  *total = rs6000_cost->fp;
18999169689Skan	  return false;
19000169689Skan	}
19001169689Skan      break;
19002132718Skan
19003169689Skan    case EQ:
19004169689Skan    case GTU:
19005169689Skan    case LTU:
19006169689Skan      /* Carry bit requires mode == Pmode.
19007169689Skan	 NEG or PLUS already counted so only add one.  */
19008169689Skan      if (mode == Pmode
19009169689Skan	  && (outer_code == NEG || outer_code == PLUS))
19010169689Skan	{
19011169689Skan	  *total = COSTS_N_INSNS (1);
19012132718Skan	  return true;
19013169689Skan	}
19014169689Skan      if (outer_code == SET)
19015169689Skan	{
19016169689Skan	  if (XEXP (x, 1) == const0_rtx)
19017169689Skan	    {
19018169689Skan	      *total = COSTS_N_INSNS (2);
19019169689Skan	      return true;
19020169689Skan	    }
19021169689Skan	  else if (mode == Pmode)
19022169689Skan	    {
19023169689Skan	      *total = COSTS_N_INSNS (3);
19024169689Skan	      return false;
19025169689Skan	    }
19026169689Skan	}
19027169689Skan      /* FALLTHRU */
19028132718Skan
19029169689Skan    case GT:
19030169689Skan    case LT:
19031169689Skan    case UNORDERED:
19032169689Skan      if (outer_code == SET && (XEXP (x, 1) == const0_rtx))
19033169689Skan	{
19034169689Skan	  *total = COSTS_N_INSNS (2);
19035132718Skan	  return true;
19036132718Skan	}
19037169689Skan      /* CC COMPARE.  */
19038169689Skan      if (outer_code == COMPARE)
19039169689Skan	{
19040169689Skan	  *total = 0;
19041169689Skan	  return true;
19042169689Skan	}
19043169689Skan      break;
19044132718Skan
19045132718Skan    default:
19046169689Skan      break;
19047132718Skan    }
19048169689Skan
19049169689Skan  return false;
19050132718Skan}
19051132718Skan
19052117395Skan/* A C expression returning the cost of moving data from a register of class
19053117395Skan   CLASS1 to one of CLASS2.  */
19054117395Skan
19055117395Skanint
19056169689Skanrs6000_register_move_cost (enum machine_mode mode,
19057132718Skan			   enum reg_class from, enum reg_class to)
19058117395Skan{
19059117395Skan  /*  Moves from/to GENERAL_REGS.  */
19060117395Skan  if (reg_classes_intersect_p (to, GENERAL_REGS)
19061117395Skan      || reg_classes_intersect_p (from, GENERAL_REGS))
19062117395Skan    {
19063117395Skan      if (! reg_classes_intersect_p (to, GENERAL_REGS))
19064117395Skan	from = to;
19065117395Skan
19066117395Skan      if (from == FLOAT_REGS || from == ALTIVEC_REGS)
19067117395Skan	return (rs6000_memory_move_cost (mode, from, 0)
19068117395Skan		+ rs6000_memory_move_cost (mode, GENERAL_REGS, 0));
19069117395Skan
19070169689Skan      /* It's more expensive to move CR_REGS than CR0_REGS because of the
19071169689Skan	 shift.  */
19072117395Skan      else if (from == CR_REGS)
19073117395Skan	return 4;
19074117395Skan
19075117395Skan      else
19076169689Skan	/* A move will cost one instruction per GPR moved.  */
19077169689Skan	return 2 * hard_regno_nregs[0][mode];
19078117395Skan    }
19079117395Skan
19080169689Skan  /* Moving between two similar registers is just one instruction.  */
19081117395Skan  else if (reg_classes_intersect_p (to, from))
19082117395Skan    return mode == TFmode ? 4 : 2;
19083117395Skan
19084169689Skan  /* Everything else has to go through GENERAL_REGS.  */
19085117395Skan  else
19086169689Skan    return (rs6000_register_move_cost (mode, GENERAL_REGS, to)
19087117395Skan	    + rs6000_register_move_cost (mode, from, GENERAL_REGS));
19088117395Skan}
19089117395Skan
19090117395Skan/* A C expressions returning the cost of moving data of MODE from a register to
19091117395Skan   or from memory.  */
19092117395Skan
19093117395Skanint
19094169689Skanrs6000_memory_move_cost (enum machine_mode mode, enum reg_class class,
19095132718Skan			 int in ATTRIBUTE_UNUSED)
19096117395Skan{
19097117395Skan  if (reg_classes_intersect_p (class, GENERAL_REGS))
19098169689Skan    return 4 * hard_regno_nregs[0][mode];
19099117395Skan  else if (reg_classes_intersect_p (class, FLOAT_REGS))
19100169689Skan    return 4 * hard_regno_nregs[32][mode];
19101117395Skan  else if (reg_classes_intersect_p (class, ALTIVEC_REGS))
19102169689Skan    return 4 * hard_regno_nregs[FIRST_ALTIVEC_REGNO][mode];
19103117395Skan  else
19104117395Skan    return 4 + rs6000_register_move_cost (mode, class, GENERAL_REGS);
19105117395Skan}
19106117395Skan
19107169689Skan/* Newton-Raphson approximation of single-precision floating point divide n/d.
19108169689Skan   Assumes no trapping math and finite arguments.  */
19109169689Skan
19110169689Skanvoid
19111169689Skanrs6000_emit_swdivsf (rtx res, rtx n, rtx d)
19112169689Skan{
19113169689Skan  rtx x0, e0, e1, y1, u0, v0, one;
19114169689Skan
19115169689Skan  x0 = gen_reg_rtx (SFmode);
19116169689Skan  e0 = gen_reg_rtx (SFmode);
19117169689Skan  e1 = gen_reg_rtx (SFmode);
19118169689Skan  y1 = gen_reg_rtx (SFmode);
19119169689Skan  u0 = gen_reg_rtx (SFmode);
19120169689Skan  v0 = gen_reg_rtx (SFmode);
19121169689Skan  one = force_reg (SFmode, CONST_DOUBLE_FROM_REAL_VALUE (dconst1, SFmode));
19122169689Skan
19123169689Skan  /* x0 = 1./d estimate */
19124169689Skan  emit_insn (gen_rtx_SET (VOIDmode, x0,
19125169689Skan			  gen_rtx_UNSPEC (SFmode, gen_rtvec (1, d),
19126169689Skan					  UNSPEC_FRES)));
19127169689Skan  /* e0 = 1. - d * x0 */
19128169689Skan  emit_insn (gen_rtx_SET (VOIDmode, e0,
19129169689Skan			  gen_rtx_MINUS (SFmode, one,
19130169689Skan					 gen_rtx_MULT (SFmode, d, x0))));
19131169689Skan  /* e1 = e0 + e0 * e0 */
19132169689Skan  emit_insn (gen_rtx_SET (VOIDmode, e1,
19133169689Skan			  gen_rtx_PLUS (SFmode,
19134169689Skan					gen_rtx_MULT (SFmode, e0, e0), e0)));
19135169689Skan  /* y1 = x0 + e1 * x0 */
19136169689Skan  emit_insn (gen_rtx_SET (VOIDmode, y1,
19137169689Skan			  gen_rtx_PLUS (SFmode,
19138169689Skan					gen_rtx_MULT (SFmode, e1, x0), x0)));
19139169689Skan  /* u0 = n * y1 */
19140169689Skan  emit_insn (gen_rtx_SET (VOIDmode, u0,
19141169689Skan			  gen_rtx_MULT (SFmode, n, y1)));
19142169689Skan  /* v0 = n - d * u0 */
19143169689Skan  emit_insn (gen_rtx_SET (VOIDmode, v0,
19144169689Skan			  gen_rtx_MINUS (SFmode, n,
19145169689Skan					 gen_rtx_MULT (SFmode, d, u0))));
19146169689Skan  /* res = u0 + v0 * y1 */
19147169689Skan  emit_insn (gen_rtx_SET (VOIDmode, res,
19148169689Skan			  gen_rtx_PLUS (SFmode,
19149169689Skan					gen_rtx_MULT (SFmode, v0, y1), u0)));
19150169689Skan}
19151169689Skan
19152169689Skan/* Newton-Raphson approximation of double-precision floating point divide n/d.
19153169689Skan   Assumes no trapping math and finite arguments.  */
19154169689Skan
19155169689Skanvoid
19156169689Skanrs6000_emit_swdivdf (rtx res, rtx n, rtx d)
19157169689Skan{
19158169689Skan  rtx x0, e0, e1, e2, y1, y2, y3, u0, v0, one;
19159169689Skan
19160169689Skan  x0 = gen_reg_rtx (DFmode);
19161169689Skan  e0 = gen_reg_rtx (DFmode);
19162169689Skan  e1 = gen_reg_rtx (DFmode);
19163169689Skan  e2 = gen_reg_rtx (DFmode);
19164169689Skan  y1 = gen_reg_rtx (DFmode);
19165169689Skan  y2 = gen_reg_rtx (DFmode);
19166169689Skan  y3 = gen_reg_rtx (DFmode);
19167169689Skan  u0 = gen_reg_rtx (DFmode);
19168169689Skan  v0 = gen_reg_rtx (DFmode);
19169169689Skan  one = force_reg (DFmode, CONST_DOUBLE_FROM_REAL_VALUE (dconst1, DFmode));
19170169689Skan
19171169689Skan  /* x0 = 1./d estimate */
19172169689Skan  emit_insn (gen_rtx_SET (VOIDmode, x0,
19173169689Skan			  gen_rtx_UNSPEC (DFmode, gen_rtvec (1, d),
19174169689Skan					  UNSPEC_FRES)));
19175169689Skan  /* e0 = 1. - d * x0 */
19176169689Skan  emit_insn (gen_rtx_SET (VOIDmode, e0,
19177169689Skan			  gen_rtx_MINUS (DFmode, one,
19178169689Skan					 gen_rtx_MULT (SFmode, d, x0))));
19179169689Skan  /* y1 = x0 + e0 * x0 */
19180169689Skan  emit_insn (gen_rtx_SET (VOIDmode, y1,
19181169689Skan			  gen_rtx_PLUS (DFmode,
19182169689Skan					gen_rtx_MULT (DFmode, e0, x0), x0)));
19183169689Skan  /* e1 = e0 * e0 */
19184169689Skan  emit_insn (gen_rtx_SET (VOIDmode, e1,
19185169689Skan			  gen_rtx_MULT (DFmode, e0, e0)));
19186169689Skan  /* y2 = y1 + e1 * y1 */
19187169689Skan  emit_insn (gen_rtx_SET (VOIDmode, y2,
19188169689Skan			  gen_rtx_PLUS (DFmode,
19189169689Skan					gen_rtx_MULT (DFmode, e1, y1), y1)));
19190169689Skan  /* e2 = e1 * e1 */
19191169689Skan  emit_insn (gen_rtx_SET (VOIDmode, e2,
19192169689Skan			  gen_rtx_MULT (DFmode, e1, e1)));
19193169689Skan  /* y3 = y2 + e2 * y2 */
19194169689Skan  emit_insn (gen_rtx_SET (VOIDmode, y3,
19195169689Skan			  gen_rtx_PLUS (DFmode,
19196169689Skan					gen_rtx_MULT (DFmode, e2, y2), y2)));
19197169689Skan  /* u0 = n * y3 */
19198169689Skan  emit_insn (gen_rtx_SET (VOIDmode, u0,
19199169689Skan			  gen_rtx_MULT (DFmode, n, y3)));
19200169689Skan  /* v0 = n - d * u0 */
19201169689Skan  emit_insn (gen_rtx_SET (VOIDmode, v0,
19202169689Skan			  gen_rtx_MINUS (DFmode, n,
19203169689Skan					 gen_rtx_MULT (DFmode, d, u0))));
19204169689Skan  /* res = u0 + v0 * y3 */
19205169689Skan  emit_insn (gen_rtx_SET (VOIDmode, res,
19206169689Skan			  gen_rtx_PLUS (DFmode,
19207169689Skan					gen_rtx_MULT (DFmode, v0, y3), u0)));
19208169689Skan}
19209169689Skan
19210132718Skan/* Return an RTX representing where to find the function value of a
19211132718Skan   function returning MODE.  */
19212132718Skanstatic rtx
19213132718Skanrs6000_complex_function_value (enum machine_mode mode)
19214132718Skan{
19215132718Skan  unsigned int regno;
19216132718Skan  rtx r1, r2;
19217132718Skan  enum machine_mode inner = GET_MODE_INNER (mode);
19218132718Skan  unsigned int inner_bytes = GET_MODE_SIZE (inner);
19219132718Skan
19220132718Skan  if (FLOAT_MODE_P (mode) && TARGET_HARD_FLOAT && TARGET_FPRS)
19221132718Skan    regno = FP_ARG_RETURN;
19222132718Skan  else
19223132718Skan    {
19224132718Skan      regno = GP_ARG_RETURN;
19225132718Skan
19226132718Skan      /* 32-bit is OK since it'll go in r3/r4.  */
19227132718Skan      if (TARGET_32BIT && inner_bytes >= 4)
19228132718Skan	return gen_rtx_REG (mode, regno);
19229132718Skan    }
19230132718Skan
19231132718Skan  if (inner_bytes >= 8)
19232132718Skan    return gen_rtx_REG (mode, regno);
19233132718Skan
19234132718Skan  r1 = gen_rtx_EXPR_LIST (inner, gen_rtx_REG (inner, regno),
19235132718Skan			  const0_rtx);
19236132718Skan  r2 = gen_rtx_EXPR_LIST (inner, gen_rtx_REG (inner, regno + 1),
19237132718Skan			  GEN_INT (inner_bytes));
19238132718Skan  return gen_rtx_PARALLEL (mode, gen_rtvec (2, r1, r2));
19239132718Skan}
19240132718Skan
19241132718Skan/* Define how to find the value returned by a function.
19242132718Skan   VALTYPE is the data type of the value (as a tree).
19243132718Skan   If the precise function being called is known, FUNC is its FUNCTION_DECL;
19244132718Skan   otherwise, FUNC is 0.
19245132718Skan
19246132718Skan   On the SPE, both FPs and vectors are returned in r3.
19247132718Skan
19248132718Skan   On RS/6000 an integer value is in r3 and a floating-point value is in
19249132718Skan   fp1, unless -msoft-float.  */
19250132718Skan
19251132718Skanrtx
19252132718Skanrs6000_function_value (tree valtype, tree func ATTRIBUTE_UNUSED)
19253132718Skan{
19254132718Skan  enum machine_mode mode;
19255132718Skan  unsigned int regno;
19256132718Skan
19257169689Skan  /* Special handling for structs in darwin64.  */
19258169689Skan  if (rs6000_darwin64_abi
19259169689Skan      && TYPE_MODE (valtype) == BLKmode
19260169689Skan      && TREE_CODE (valtype) == RECORD_TYPE
19261169689Skan      && int_size_in_bytes (valtype) > 0)
19262169689Skan    {
19263169689Skan      CUMULATIVE_ARGS valcum;
19264169689Skan      rtx valret;
19265169689Skan
19266169689Skan      valcum.words = 0;
19267169689Skan      valcum.fregno = FP_ARG_MIN_REG;
19268169689Skan      valcum.vregno = ALTIVEC_ARG_MIN_REG;
19269169689Skan      /* Do a trial code generation as if this were going to be passed as
19270169689Skan	 an argument; if any part goes in memory, we return NULL.  */
19271169689Skan      valret = rs6000_darwin64_record_arg (&valcum, valtype, 1, true);
19272169689Skan      if (valret)
19273169689Skan	return valret;
19274169689Skan      /* Otherwise fall through to standard ABI rules.  */
19275169689Skan    }
19276169689Skan
19277132718Skan  if (TARGET_32BIT && TARGET_POWERPC64 && TYPE_MODE (valtype) == DImode)
19278132718Skan    {
19279132718Skan      /* Long long return value need be split in -mpowerpc64, 32bit ABI.  */
19280132718Skan      return gen_rtx_PARALLEL (DImode,
19281132718Skan	gen_rtvec (2,
19282132718Skan		   gen_rtx_EXPR_LIST (VOIDmode,
19283132718Skan				      gen_rtx_REG (SImode, GP_ARG_RETURN),
19284132718Skan				      const0_rtx),
19285132718Skan		   gen_rtx_EXPR_LIST (VOIDmode,
19286132718Skan				      gen_rtx_REG (SImode,
19287132718Skan						   GP_ARG_RETURN + 1),
19288132718Skan				      GEN_INT (4))));
19289132718Skan    }
19290169689Skan  if (TARGET_32BIT && TARGET_POWERPC64 && TYPE_MODE (valtype) == DCmode)
19291169689Skan    {
19292169689Skan      return gen_rtx_PARALLEL (DCmode,
19293169689Skan	gen_rtvec (4,
19294169689Skan		   gen_rtx_EXPR_LIST (VOIDmode,
19295169689Skan				      gen_rtx_REG (SImode, GP_ARG_RETURN),
19296169689Skan				      const0_rtx),
19297169689Skan		   gen_rtx_EXPR_LIST (VOIDmode,
19298169689Skan				      gen_rtx_REG (SImode,
19299169689Skan						   GP_ARG_RETURN + 1),
19300169689Skan				      GEN_INT (4)),
19301169689Skan		   gen_rtx_EXPR_LIST (VOIDmode,
19302169689Skan				      gen_rtx_REG (SImode,
19303169689Skan						   GP_ARG_RETURN + 2),
19304169689Skan				      GEN_INT (8)),
19305169689Skan		   gen_rtx_EXPR_LIST (VOIDmode,
19306169689Skan				      gen_rtx_REG (SImode,
19307169689Skan						   GP_ARG_RETURN + 3),
19308169689Skan				      GEN_INT (12))));
19309169689Skan    }
19310132718Skan
19311169689Skan  mode = TYPE_MODE (valtype);
19312169689Skan  if ((INTEGRAL_TYPE_P (valtype) && GET_MODE_BITSIZE (mode) < BITS_PER_WORD)
19313132718Skan      || POINTER_TYPE_P (valtype))
19314132718Skan    mode = TARGET_32BIT ? SImode : DImode;
19315132718Skan
19316169689Skan  if (DECIMAL_FLOAT_MODE_P (mode))
19317169689Skan    regno = GP_ARG_RETURN;
19318169689Skan  else if (SCALAR_FLOAT_TYPE_P (valtype) && TARGET_HARD_FLOAT && TARGET_FPRS)
19319132718Skan    regno = FP_ARG_RETURN;
19320132718Skan  else if (TREE_CODE (valtype) == COMPLEX_TYPE
19321132718Skan	   && targetm.calls.split_complex_arg)
19322132718Skan    return rs6000_complex_function_value (mode);
19323132718Skan  else if (TREE_CODE (valtype) == VECTOR_TYPE
19324169689Skan	   && TARGET_ALTIVEC && TARGET_ALTIVEC_ABI
19325169689Skan	   && ALTIVEC_VECTOR_MODE (mode))
19326132718Skan    regno = ALTIVEC_ARG_RETURN;
19327169689Skan  else if (TARGET_E500_DOUBLE && TARGET_HARD_FLOAT
19328169689Skan	   && (mode == DFmode || mode == DCmode))
19329169689Skan    return spe_build_register_parallel (mode, GP_ARG_RETURN);
19330132718Skan  else
19331132718Skan    regno = GP_ARG_RETURN;
19332132718Skan
19333132718Skan  return gen_rtx_REG (mode, regno);
19334132718Skan}
19335132718Skan
19336132718Skan/* Define how to find the value returned by a library function
19337132718Skan   assuming the value has mode MODE.  */
19338132718Skanrtx
19339132718Skanrs6000_libcall_value (enum machine_mode mode)
19340132718Skan{
19341132718Skan  unsigned int regno;
19342132718Skan
19343169689Skan  if (TARGET_32BIT && TARGET_POWERPC64 && mode == DImode)
19344169689Skan    {
19345169689Skan      /* Long long return value need be split in -mpowerpc64, 32bit ABI.  */
19346169689Skan      return gen_rtx_PARALLEL (DImode,
19347169689Skan	gen_rtvec (2,
19348169689Skan		   gen_rtx_EXPR_LIST (VOIDmode,
19349169689Skan				      gen_rtx_REG (SImode, GP_ARG_RETURN),
19350169689Skan				      const0_rtx),
19351169689Skan		   gen_rtx_EXPR_LIST (VOIDmode,
19352169689Skan				      gen_rtx_REG (SImode,
19353169689Skan						   GP_ARG_RETURN + 1),
19354169689Skan				      GEN_INT (4))));
19355169689Skan    }
19356169689Skan
19357169689Skan  if (DECIMAL_FLOAT_MODE_P (mode))
19358169689Skan    regno = GP_ARG_RETURN;
19359169689Skan  else if (SCALAR_FLOAT_MODE_P (mode)
19360132718Skan	   && TARGET_HARD_FLOAT && TARGET_FPRS)
19361132718Skan    regno = FP_ARG_RETURN;
19362132718Skan  else if (ALTIVEC_VECTOR_MODE (mode)
19363132718Skan	   && TARGET_ALTIVEC && TARGET_ALTIVEC_ABI)
19364132718Skan    regno = ALTIVEC_ARG_RETURN;
19365132718Skan  else if (COMPLEX_MODE_P (mode) && targetm.calls.split_complex_arg)
19366132718Skan    return rs6000_complex_function_value (mode);
19367169689Skan  else if (TARGET_E500_DOUBLE && TARGET_HARD_FLOAT
19368169689Skan	   && (mode == DFmode || mode == DCmode))
19369169689Skan    return spe_build_register_parallel (mode, GP_ARG_RETURN);
19370132718Skan  else
19371132718Skan    regno = GP_ARG_RETURN;
19372132718Skan
19373132718Skan  return gen_rtx_REG (mode, regno);
19374132718Skan}
19375132718Skan
19376132718Skan/* Define the offset between two registers, FROM to be eliminated and its
19377132718Skan   replacement TO, at the start of a routine.  */
19378132718SkanHOST_WIDE_INT
19379132718Skanrs6000_initial_elimination_offset (int from, int to)
19380132718Skan{
19381132718Skan  rs6000_stack_t *info = rs6000_stack_info ();
19382132718Skan  HOST_WIDE_INT offset;
19383132718Skan
19384169689Skan  if (from == HARD_FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
19385132718Skan    offset = info->push_p ? 0 : -info->total_size;
19386169689Skan  else if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
19387169689Skan    {
19388169689Skan      offset = info->push_p ? 0 : -info->total_size;
19389169689Skan      if (FRAME_GROWS_DOWNWARD)
19390169689Skan	offset += info->fixed_size + info->vars_size + info->parm_size;
19391169689Skan    }
19392169689Skan  else if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
19393169689Skan    offset = FRAME_GROWS_DOWNWARD
19394169689Skan	     ? info->fixed_size + info->vars_size + info->parm_size
19395169689Skan	     : 0;
19396169689Skan  else if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
19397132718Skan    offset = info->total_size;
19398132718Skan  else if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
19399132718Skan    offset = info->push_p ? info->total_size : 0;
19400132718Skan  else if (from == RS6000_PIC_OFFSET_TABLE_REGNUM)
19401132718Skan    offset = 0;
19402132718Skan  else
19403169689Skan    gcc_unreachable ();
19404132718Skan
19405132718Skan  return offset;
19406132718Skan}
19407132718Skan
19408169689Skan/* Return true if TYPE is a SPE or AltiVec opaque type.  */
19409132718Skan
19410132718Skanstatic bool
19411169689Skanrs6000_is_opaque_type (tree type)
19412132718Skan{
19413169689Skan  return (type == opaque_V2SI_type_node
19414132718Skan	      || type == opaque_V2SF_type_node
19415169689Skan	      || type == opaque_p_V2SI_type_node
19416169689Skan	      || type == opaque_V4SI_type_node);
19417132718Skan}
19418132718Skan
19419132718Skanstatic rtx
19420132718Skanrs6000_dwarf_register_span (rtx reg)
19421132718Skan{
19422132718Skan  unsigned regno;
19423132718Skan
19424169689Skan  if (TARGET_SPE
19425169689Skan      && (SPE_VECTOR_MODE (GET_MODE (reg))
19426169689Skan	  || (TARGET_E500_DOUBLE && GET_MODE (reg) == DFmode)))
19427169689Skan    ;
19428169689Skan  else
19429132718Skan    return NULL_RTX;
19430132718Skan
19431132718Skan  regno = REGNO (reg);
19432132718Skan
19433132718Skan  /* The duality of the SPE register size wreaks all kinds of havoc.
19434132718Skan     This is a way of distinguishing r0 in 32-bits from r0 in
19435132718Skan     64-bits.  */
19436132718Skan  return
19437132718Skan    gen_rtx_PARALLEL (VOIDmode,
19438132718Skan		      BYTES_BIG_ENDIAN
19439132718Skan		      ? gen_rtvec (2,
19440132718Skan				   gen_rtx_REG (SImode, regno + 1200),
19441132718Skan				   gen_rtx_REG (SImode, regno))
19442132718Skan		      : gen_rtvec (2,
19443132718Skan				   gen_rtx_REG (SImode, regno),
19444132718Skan				   gen_rtx_REG (SImode, regno + 1200)));
19445132718Skan}
19446132718Skan
19447132718Skan/* Map internal gcc register numbers to DWARF2 register numbers.  */
19448132718Skan
19449132718Skanunsigned int
19450132718Skanrs6000_dbx_register_number (unsigned int regno)
19451132718Skan{
19452132718Skan  if (regno <= 63 || write_symbols != DWARF2_DEBUG)
19453132718Skan    return regno;
19454132718Skan  if (regno == MQ_REGNO)
19455132718Skan    return 100;
19456132718Skan  if (regno == LINK_REGISTER_REGNUM)
19457132718Skan    return 108;
19458132718Skan  if (regno == COUNT_REGISTER_REGNUM)
19459132718Skan    return 109;
19460132718Skan  if (CR_REGNO_P (regno))
19461132718Skan    return regno - CR0_REGNO + 86;
19462132718Skan  if (regno == XER_REGNO)
19463132718Skan    return 101;
19464132718Skan  if (ALTIVEC_REGNO_P (regno))
19465132718Skan    return regno - FIRST_ALTIVEC_REGNO + 1124;
19466132718Skan  if (regno == VRSAVE_REGNO)
19467132718Skan    return 356;
19468132718Skan  if (regno == VSCR_REGNO)
19469132718Skan    return 67;
19470132718Skan  if (regno == SPE_ACC_REGNO)
19471132718Skan    return 99;
19472132718Skan  if (regno == SPEFSCR_REGNO)
19473132718Skan    return 612;
19474132718Skan  /* SPE high reg number.  We get these values of regno from
19475132718Skan     rs6000_dwarf_register_span.  */
19476169689Skan  gcc_assert (regno >= 1200 && regno < 1232);
19477169689Skan  return regno;
19478169689Skan}
19479132718Skan
19480169689Skan/* target hook eh_return_filter_mode */
19481169689Skanstatic enum machine_mode
19482169689Skanrs6000_eh_return_filter_mode (void)
19483169689Skan{
19484169689Skan  return TARGET_32BIT ? SImode : word_mode;
19485132718Skan}
19486132718Skan
19487169689Skan/* Target hook for scalar_mode_supported_p.  */
19488169689Skanstatic bool
19489169689Skanrs6000_scalar_mode_supported_p (enum machine_mode mode)
19490169689Skan{
19491169689Skan  if (DECIMAL_FLOAT_MODE_P (mode))
19492169689Skan    return true;
19493169689Skan  else
19494169689Skan    return default_scalar_mode_supported_p (mode);
19495169689Skan}
19496169689Skan
19497169689Skan/* Target hook for vector_mode_supported_p.  */
19498169689Skanstatic bool
19499169689Skanrs6000_vector_mode_supported_p (enum machine_mode mode)
19500169689Skan{
19501169689Skan
19502169689Skan  if (TARGET_SPE && SPE_VECTOR_MODE (mode))
19503169689Skan    return true;
19504169689Skan
19505169689Skan  else if (TARGET_ALTIVEC && ALTIVEC_VECTOR_MODE (mode))
19506169689Skan    return true;
19507169689Skan
19508169689Skan  else
19509169689Skan    return false;
19510169689Skan}
19511169689Skan
19512169689Skan/* Target hook for invalid_arg_for_unprototyped_fn. */
19513169689Skanstatic const char *
19514169689Skaninvalid_arg_for_unprototyped_fn (tree typelist, tree funcdecl, tree val)
19515169689Skan{
19516169689Skan  return (!rs6000_darwin64_abi
19517169689Skan	  && typelist == 0
19518169689Skan          && TREE_CODE (TREE_TYPE (val)) == VECTOR_TYPE
19519169689Skan          && (funcdecl == NULL_TREE
19520169689Skan              || (TREE_CODE (funcdecl) == FUNCTION_DECL
19521169689Skan                  && DECL_BUILT_IN_CLASS (funcdecl) != BUILT_IN_MD)))
19522169689Skan	  ? N_("AltiVec argument passed to unprototyped function")
19523169689Skan	  : NULL;
19524169689Skan}
19525169689Skan
19526169689Skan/* For TARGET_SECURE_PLT 32-bit PIC code we can save PIC register
19527169689Skan   setup by using __stack_chk_fail_local hidden function instead of
19528169689Skan   calling __stack_chk_fail directly.  Otherwise it is better to call
19529169689Skan   __stack_chk_fail directly.  */
19530169689Skan
19531169689Skanstatic tree
19532169689Skanrs6000_stack_protect_fail (void)
19533169689Skan{
19534169689Skan  return (DEFAULT_ABI == ABI_V4 && TARGET_SECURE_PLT && flag_pic)
19535169689Skan	 ? default_hidden_stack_protect_fail ()
19536169689Skan	 : default_external_stack_protect_fail ();
19537169689Skan}
19538169689Skan
19539132718Skan#include "gt-rs6000.h"
19540