190284Sobrien/* Subroutines used for code generation on IA-32.
290284Sobrien   Copyright (C) 1988, 1992, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
3169705Skan   2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
418334Speter
5132743SkanThis file is part of GCC.
618334Speter
7132743SkanGCC is free software; you can redistribute it and/or modify
818334Speterit under the terms of the GNU General Public License as published by
918334Speterthe Free Software Foundation; either version 2, or (at your option)
1018334Speterany later version.
1118334Speter
12132743SkanGCC is distributed in the hope that it will be useful,
1318334Speterbut WITHOUT ANY WARRANTY; without even the implied warranty of
1418334SpeterMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1518334SpeterGNU General Public License for more details.
1618334Speter
1718334SpeterYou should have received a copy of the GNU General Public License
18132743Skanalong with GCC; see the file COPYING.  If not, write to
19169705Skanthe Free Software Foundation, 51 Franklin Street, Fifth Floor,
20169705SkanBoston, MA 02110-1301, USA.  */
2118334Speter
2251411Sobrien/* $FreeBSD: releng/11.0/contrib/gcc/config/i386/i386.c 265231 2014-05-02 16:15:34Z pfg $ */
2351411Sobrien
2418334Speter#include "config.h"
2551411Sobrien#include "system.h"
26132743Skan#include "coretypes.h"
27132743Skan#include "tm.h"
2818334Speter#include "rtl.h"
2990284Sobrien#include "tree.h"
3090284Sobrien#include "tm_p.h"
3118334Speter#include "regs.h"
3218334Speter#include "hard-reg-set.h"
3318334Speter#include "real.h"
3418334Speter#include "insn-config.h"
3518334Speter#include "conditions.h"
3618334Speter#include "output.h"
37169705Skan#include "insn-codes.h"
3818334Speter#include "insn-attr.h"
3918334Speter#include "flags.h"
4051411Sobrien#include "except.h"
4118334Speter#include "function.h"
4251411Sobrien#include "recog.h"
4351411Sobrien#include "expr.h"
4490284Sobrien#include "optabs.h"
4551411Sobrien#include "toplev.h"
4690284Sobrien#include "basic-block.h"
4790284Sobrien#include "ggc.h"
4890284Sobrien#include "target.h"
4990284Sobrien#include "target-def.h"
50117408Skan#include "langhooks.h"
51132743Skan#include "cgraph.h"
52169705Skan#include "tree-gimple.h"
53169705Skan#include "dwarf2.h"
54169705Skan#include "tm-constrs.h"
5518334Speter
5651411Sobrien#ifndef CHECK_STACK_LIMIT
5790284Sobrien#define CHECK_STACK_LIMIT (-1)
5851411Sobrien#endif
5918334Speter
60132743Skan/* Return index of given mode in mult and division cost tables.  */
61132743Skan#define MODE_INDEX(mode)					\
62132743Skan  ((mode) == QImode ? 0						\
63132743Skan   : (mode) == HImode ? 1					\
64132743Skan   : (mode) == SImode ? 2					\
65132743Skan   : (mode) == DImode ? 3					\
66132743Skan   : 4)
67132743Skan
6890284Sobrien/* Processor costs (relative to an add) */
69169705Skan/* We assume COSTS_N_INSNS is defined as (N)*4 and an addition is 2 bytes.  */
70169705Skan#define COSTS_N_BYTES(N) ((N) * 2)
71169705Skan
72117408Skanstatic const
73169705Skanstruct processor_costs size_cost = {	/* costs for tuning for size */
74169705Skan  COSTS_N_BYTES (2),			/* cost of an add instruction */
75169705Skan  COSTS_N_BYTES (3),			/* cost of a lea instruction */
76169705Skan  COSTS_N_BYTES (2),			/* variable shift costs */
77169705Skan  COSTS_N_BYTES (3),			/* constant shift costs */
78169705Skan  {COSTS_N_BYTES (3),			/* cost of starting multiply for QI */
79169705Skan   COSTS_N_BYTES (3),			/*                               HI */
80169705Skan   COSTS_N_BYTES (3),			/*                               SI */
81169705Skan   COSTS_N_BYTES (3),			/*                               DI */
82169705Skan   COSTS_N_BYTES (5)},			/*                            other */
8390284Sobrien  0,					/* cost of multiply per each bit set */
84169705Skan  {COSTS_N_BYTES (3),			/* cost of a divide/mod for QI */
85169705Skan   COSTS_N_BYTES (3),			/*                          HI */
86169705Skan   COSTS_N_BYTES (3),			/*                          SI */
87169705Skan   COSTS_N_BYTES (3),			/*                          DI */
88169705Skan   COSTS_N_BYTES (5)},			/*                       other */
89169705Skan  COSTS_N_BYTES (3),			/* cost of movsx */
90169705Skan  COSTS_N_BYTES (3),			/* cost of movzx */
9190284Sobrien  0,					/* "large" insn */
9290284Sobrien  2,					/* MOVE_RATIO */
9390284Sobrien  2,					/* cost for loading QImode using movzbl */
9490284Sobrien  {2, 2, 2},				/* cost of loading integer registers
9590284Sobrien					   in QImode, HImode and SImode.
9690284Sobrien					   Relative to reg-reg move (2).  */
9790284Sobrien  {2, 2, 2},				/* cost of storing integer registers */
9890284Sobrien  2,					/* cost of reg,reg fld/fst */
9990284Sobrien  {2, 2, 2},				/* cost of loading fp registers
10090284Sobrien					   in SFmode, DFmode and XFmode */
101169705Skan  {2, 2, 2},				/* cost of storing fp registers
102169705Skan					   in SFmode, DFmode and XFmode */
10390284Sobrien  3,					/* cost of moving MMX register */
10490284Sobrien  {3, 3},				/* cost of loading MMX registers
10590284Sobrien					   in SImode and DImode */
10690284Sobrien  {3, 3},				/* cost of storing MMX registers
10790284Sobrien					   in SImode and DImode */
10890284Sobrien  3,					/* cost of moving SSE register */
10990284Sobrien  {3, 3, 3},				/* cost of loading SSE registers
11090284Sobrien					   in SImode, DImode and TImode */
11190284Sobrien  {3, 3, 3},				/* cost of storing SSE registers
11290284Sobrien					   in SImode, DImode and TImode */
11390284Sobrien  3,					/* MMX or SSE register to integer */
11490284Sobrien  0,					/* size of prefetch block */
11590284Sobrien  0,					/* number of parallel prefetches */
116169705Skan  2,					/* Branch cost */
117169705Skan  COSTS_N_BYTES (2),			/* cost of FADD and FSUB insns.  */
118169705Skan  COSTS_N_BYTES (2),			/* cost of FMUL instruction.  */
119169705Skan  COSTS_N_BYTES (2),			/* cost of FDIV instruction.  */
120169705Skan  COSTS_N_BYTES (2),			/* cost of FABS instruction.  */
121169705Skan  COSTS_N_BYTES (2),			/* cost of FCHS instruction.  */
122169705Skan  COSTS_N_BYTES (2),			/* cost of FSQRT instruction.  */
12351411Sobrien};
124117408Skan
12551411Sobrien/* Processor costs (relative to an add) */
126117408Skanstatic const
12751411Sobrienstruct processor_costs i386_cost = {	/* 386 specific costs */
128169705Skan  COSTS_N_INSNS (1),			/* cost of an add instruction */
129169705Skan  COSTS_N_INSNS (1),			/* cost of a lea instruction */
130169705Skan  COSTS_N_INSNS (3),			/* variable shift costs */
131169705Skan  COSTS_N_INSNS (2),			/* constant shift costs */
132169705Skan  {COSTS_N_INSNS (6),			/* cost of starting multiply for QI */
133169705Skan   COSTS_N_INSNS (6),			/*                               HI */
134169705Skan   COSTS_N_INSNS (6),			/*                               SI */
135169705Skan   COSTS_N_INSNS (6),			/*                               DI */
136169705Skan   COSTS_N_INSNS (6)},			/*                               other */
137169705Skan  COSTS_N_INSNS (1),			/* cost of multiply per each bit set */
138169705Skan  {COSTS_N_INSNS (23),			/* cost of a divide/mod for QI */
139169705Skan   COSTS_N_INSNS (23),			/*                          HI */
140169705Skan   COSTS_N_INSNS (23),			/*                          SI */
141169705Skan   COSTS_N_INSNS (23),			/*                          DI */
142169705Skan   COSTS_N_INSNS (23)},			/*                          other */
143169705Skan  COSTS_N_INSNS (3),			/* cost of movsx */
144169705Skan  COSTS_N_INSNS (2),			/* cost of movzx */
14590284Sobrien  15,					/* "large" insn */
14690284Sobrien  3,					/* MOVE_RATIO */
14790284Sobrien  4,					/* cost for loading QImode using movzbl */
14890284Sobrien  {2, 4, 2},				/* cost of loading integer registers
14990284Sobrien					   in QImode, HImode and SImode.
15090284Sobrien					   Relative to reg-reg move (2).  */
15190284Sobrien  {2, 4, 2},				/* cost of storing integer registers */
15290284Sobrien  2,					/* cost of reg,reg fld/fst */
15390284Sobrien  {8, 8, 8},				/* cost of loading fp registers
15490284Sobrien					   in SFmode, DFmode and XFmode */
155169705Skan  {8, 8, 8},				/* cost of storing fp registers
156169705Skan					   in SFmode, DFmode and XFmode */
15790284Sobrien  2,					/* cost of moving MMX register */
15890284Sobrien  {4, 8},				/* cost of loading MMX registers
15990284Sobrien					   in SImode and DImode */
16090284Sobrien  {4, 8},				/* cost of storing MMX registers
16190284Sobrien					   in SImode and DImode */
16290284Sobrien  2,					/* cost of moving SSE register */
16390284Sobrien  {4, 8, 16},				/* cost of loading SSE registers
16490284Sobrien					   in SImode, DImode and TImode */
16590284Sobrien  {4, 8, 16},				/* cost of storing SSE registers
16690284Sobrien					   in SImode, DImode and TImode */
16790284Sobrien  3,					/* MMX or SSE register to integer */
16890284Sobrien  0,					/* size of prefetch block */
16990284Sobrien  0,					/* number of parallel prefetches */
170132743Skan  1,					/* Branch cost */
171169705Skan  COSTS_N_INSNS (23),			/* cost of FADD and FSUB insns.  */
172169705Skan  COSTS_N_INSNS (27),			/* cost of FMUL instruction.  */
173169705Skan  COSTS_N_INSNS (88),			/* cost of FDIV instruction.  */
174169705Skan  COSTS_N_INSNS (22),			/* cost of FABS instruction.  */
175169705Skan  COSTS_N_INSNS (24),			/* cost of FCHS instruction.  */
176169705Skan  COSTS_N_INSNS (122),			/* cost of FSQRT instruction.  */
17751411Sobrien};
17851411Sobrien
179117408Skanstatic const
18051411Sobrienstruct processor_costs i486_cost = {	/* 486 specific costs */
181169705Skan  COSTS_N_INSNS (1),			/* cost of an add instruction */
182169705Skan  COSTS_N_INSNS (1),			/* cost of a lea instruction */
183169705Skan  COSTS_N_INSNS (3),			/* variable shift costs */
184169705Skan  COSTS_N_INSNS (2),			/* constant shift costs */
185169705Skan  {COSTS_N_INSNS (12),			/* cost of starting multiply for QI */
186169705Skan   COSTS_N_INSNS (12),			/*                               HI */
187169705Skan   COSTS_N_INSNS (12),			/*                               SI */
188169705Skan   COSTS_N_INSNS (12),			/*                               DI */
189169705Skan   COSTS_N_INSNS (12)},			/*                               other */
19051411Sobrien  1,					/* cost of multiply per each bit set */
191169705Skan  {COSTS_N_INSNS (40),			/* cost of a divide/mod for QI */
192169705Skan   COSTS_N_INSNS (40),			/*                          HI */
193169705Skan   COSTS_N_INSNS (40),			/*                          SI */
194169705Skan   COSTS_N_INSNS (40),			/*                          DI */
195169705Skan   COSTS_N_INSNS (40)},			/*                          other */
196169705Skan  COSTS_N_INSNS (3),			/* cost of movsx */
197169705Skan  COSTS_N_INSNS (2),			/* cost of movzx */
19890284Sobrien  15,					/* "large" insn */
19990284Sobrien  3,					/* MOVE_RATIO */
20090284Sobrien  4,					/* cost for loading QImode using movzbl */
20190284Sobrien  {2, 4, 2},				/* cost of loading integer registers
20290284Sobrien					   in QImode, HImode and SImode.
20390284Sobrien					   Relative to reg-reg move (2).  */
20490284Sobrien  {2, 4, 2},				/* cost of storing integer registers */
20590284Sobrien  2,					/* cost of reg,reg fld/fst */
20690284Sobrien  {8, 8, 8},				/* cost of loading fp registers
20790284Sobrien					   in SFmode, DFmode and XFmode */
208169705Skan  {8, 8, 8},				/* cost of storing fp registers
209169705Skan					   in SFmode, DFmode and XFmode */
21090284Sobrien  2,					/* cost of moving MMX register */
21190284Sobrien  {4, 8},				/* cost of loading MMX registers
21290284Sobrien					   in SImode and DImode */
21390284Sobrien  {4, 8},				/* cost of storing MMX registers
21490284Sobrien					   in SImode and DImode */
21590284Sobrien  2,					/* cost of moving SSE register */
21690284Sobrien  {4, 8, 16},				/* cost of loading SSE registers
21790284Sobrien					   in SImode, DImode and TImode */
21890284Sobrien  {4, 8, 16},				/* cost of storing SSE registers
21990284Sobrien					   in SImode, DImode and TImode */
22090284Sobrien  3,					/* MMX or SSE register to integer */
22190284Sobrien  0,					/* size of prefetch block */
22290284Sobrien  0,					/* number of parallel prefetches */
223132743Skan  1,					/* Branch cost */
224169705Skan  COSTS_N_INSNS (8),			/* cost of FADD and FSUB insns.  */
225169705Skan  COSTS_N_INSNS (16),			/* cost of FMUL instruction.  */
226169705Skan  COSTS_N_INSNS (73),			/* cost of FDIV instruction.  */
227169705Skan  COSTS_N_INSNS (3),			/* cost of FABS instruction.  */
228169705Skan  COSTS_N_INSNS (3),			/* cost of FCHS instruction.  */
229169705Skan  COSTS_N_INSNS (83),			/* cost of FSQRT instruction.  */
23051411Sobrien};
23151411Sobrien
232117408Skanstatic const
23351411Sobrienstruct processor_costs pentium_cost = {
234169705Skan  COSTS_N_INSNS (1),			/* cost of an add instruction */
235169705Skan  COSTS_N_INSNS (1),			/* cost of a lea instruction */
236169705Skan  COSTS_N_INSNS (4),			/* variable shift costs */
237169705Skan  COSTS_N_INSNS (1),			/* constant shift costs */
238169705Skan  {COSTS_N_INSNS (11),			/* cost of starting multiply for QI */
239169705Skan   COSTS_N_INSNS (11),			/*                               HI */
240169705Skan   COSTS_N_INSNS (11),			/*                               SI */
241169705Skan   COSTS_N_INSNS (11),			/*                               DI */
242169705Skan   COSTS_N_INSNS (11)},			/*                               other */
24351411Sobrien  0,					/* cost of multiply per each bit set */
244169705Skan  {COSTS_N_INSNS (25),			/* cost of a divide/mod for QI */
245169705Skan   COSTS_N_INSNS (25),			/*                          HI */
246169705Skan   COSTS_N_INSNS (25),			/*                          SI */
247169705Skan   COSTS_N_INSNS (25),			/*                          DI */
248169705Skan   COSTS_N_INSNS (25)},			/*                          other */
249169705Skan  COSTS_N_INSNS (3),			/* cost of movsx */
250169705Skan  COSTS_N_INSNS (2),			/* cost of movzx */
25190284Sobrien  8,					/* "large" insn */
25290284Sobrien  6,					/* MOVE_RATIO */
25390284Sobrien  6,					/* cost for loading QImode using movzbl */
25490284Sobrien  {2, 4, 2},				/* cost of loading integer registers
25590284Sobrien					   in QImode, HImode and SImode.
25690284Sobrien					   Relative to reg-reg move (2).  */
25790284Sobrien  {2, 4, 2},				/* cost of storing integer registers */
25890284Sobrien  2,					/* cost of reg,reg fld/fst */
25990284Sobrien  {2, 2, 6},				/* cost of loading fp registers
26090284Sobrien					   in SFmode, DFmode and XFmode */
261169705Skan  {4, 4, 6},				/* cost of storing fp registers
262169705Skan					   in SFmode, DFmode and XFmode */
26390284Sobrien  8,					/* cost of moving MMX register */
26490284Sobrien  {8, 8},				/* cost of loading MMX registers
26590284Sobrien					   in SImode and DImode */
26690284Sobrien  {8, 8},				/* cost of storing MMX registers
26790284Sobrien					   in SImode and DImode */
26890284Sobrien  2,					/* cost of moving SSE register */
26990284Sobrien  {4, 8, 16},				/* cost of loading SSE registers
27090284Sobrien					   in SImode, DImode and TImode */
27190284Sobrien  {4, 8, 16},				/* cost of storing SSE registers
27290284Sobrien					   in SImode, DImode and TImode */
27390284Sobrien  3,					/* MMX or SSE register to integer */
27490284Sobrien  0,					/* size of prefetch block */
27590284Sobrien  0,					/* number of parallel prefetches */
276132743Skan  2,					/* Branch cost */
277169705Skan  COSTS_N_INSNS (3),			/* cost of FADD and FSUB insns.  */
278169705Skan  COSTS_N_INSNS (3),			/* cost of FMUL instruction.  */
279169705Skan  COSTS_N_INSNS (39),			/* cost of FDIV instruction.  */
280169705Skan  COSTS_N_INSNS (1),			/* cost of FABS instruction.  */
281169705Skan  COSTS_N_INSNS (1),			/* cost of FCHS instruction.  */
282169705Skan  COSTS_N_INSNS (70),			/* cost of FSQRT instruction.  */
28351411Sobrien};
28451411Sobrien
285117408Skanstatic const
28651411Sobrienstruct processor_costs pentiumpro_cost = {
287169705Skan  COSTS_N_INSNS (1),			/* cost of an add instruction */
288169705Skan  COSTS_N_INSNS (1),			/* cost of a lea instruction */
289169705Skan  COSTS_N_INSNS (1),			/* variable shift costs */
290169705Skan  COSTS_N_INSNS (1),			/* constant shift costs */
291169705Skan  {COSTS_N_INSNS (4),			/* cost of starting multiply for QI */
292169705Skan   COSTS_N_INSNS (4),			/*                               HI */
293169705Skan   COSTS_N_INSNS (4),			/*                               SI */
294169705Skan   COSTS_N_INSNS (4),			/*                               DI */
295169705Skan   COSTS_N_INSNS (4)},			/*                               other */
29651411Sobrien  0,					/* cost of multiply per each bit set */
297169705Skan  {COSTS_N_INSNS (17),			/* cost of a divide/mod for QI */
298169705Skan   COSTS_N_INSNS (17),			/*                          HI */
299169705Skan   COSTS_N_INSNS (17),			/*                          SI */
300169705Skan   COSTS_N_INSNS (17),			/*                          DI */
301169705Skan   COSTS_N_INSNS (17)},			/*                          other */
302169705Skan  COSTS_N_INSNS (1),			/* cost of movsx */
303169705Skan  COSTS_N_INSNS (1),			/* cost of movzx */
30490284Sobrien  8,					/* "large" insn */
30590284Sobrien  6,					/* MOVE_RATIO */
30690284Sobrien  2,					/* cost for loading QImode using movzbl */
30790284Sobrien  {4, 4, 4},				/* cost of loading integer registers
30890284Sobrien					   in QImode, HImode and SImode.
30990284Sobrien					   Relative to reg-reg move (2).  */
31090284Sobrien  {2, 2, 2},				/* cost of storing integer registers */
31190284Sobrien  2,					/* cost of reg,reg fld/fst */
31290284Sobrien  {2, 2, 6},				/* cost of loading fp registers
31390284Sobrien					   in SFmode, DFmode and XFmode */
314169705Skan  {4, 4, 6},				/* cost of storing fp registers
315169705Skan					   in SFmode, DFmode and XFmode */
31690284Sobrien  2,					/* cost of moving MMX register */
31790284Sobrien  {2, 2},				/* cost of loading MMX registers
31890284Sobrien					   in SImode and DImode */
31990284Sobrien  {2, 2},				/* cost of storing MMX registers
32090284Sobrien					   in SImode and DImode */
32190284Sobrien  2,					/* cost of moving SSE register */
32290284Sobrien  {2, 2, 8},				/* cost of loading SSE registers
32390284Sobrien					   in SImode, DImode and TImode */
32490284Sobrien  {2, 2, 8},				/* cost of storing SSE registers
32590284Sobrien					   in SImode, DImode and TImode */
32690284Sobrien  3,					/* MMX or SSE register to integer */
32790284Sobrien  32,					/* size of prefetch block */
32890284Sobrien  6,					/* number of parallel prefetches */
329132743Skan  2,					/* Branch cost */
330169705Skan  COSTS_N_INSNS (3),			/* cost of FADD and FSUB insns.  */
331169705Skan  COSTS_N_INSNS (5),			/* cost of FMUL instruction.  */
332169705Skan  COSTS_N_INSNS (56),			/* cost of FDIV instruction.  */
333169705Skan  COSTS_N_INSNS (2),			/* cost of FABS instruction.  */
334169705Skan  COSTS_N_INSNS (2),			/* cost of FCHS instruction.  */
335169705Skan  COSTS_N_INSNS (56),			/* cost of FSQRT instruction.  */
33651411Sobrien};
33751411Sobrien
338117408Skanstatic const
339219374Smmstruct processor_costs geode_cost = {
340219374Smm  COSTS_N_INSNS (1),			/* cost of an add instruction */
341219374Smm  COSTS_N_INSNS (1),			/* cost of a lea instruction */
342219374Smm  COSTS_N_INSNS (2),			/* variable shift costs */
343219374Smm  COSTS_N_INSNS (1),			/* constant shift costs */
344219374Smm  {COSTS_N_INSNS (3),			/* cost of starting multiply for QI */
345219374Smm   COSTS_N_INSNS (4),			/*                               HI */
346219374Smm   COSTS_N_INSNS (7),			/*                               SI */
347219374Smm   COSTS_N_INSNS (7),			/*                               DI */
348219374Smm   COSTS_N_INSNS (7)},			/*                               other */
349219374Smm  0,					/* cost of multiply per each bit set */
350219374Smm  {COSTS_N_INSNS (15),			/* cost of a divide/mod for QI */
351219374Smm   COSTS_N_INSNS (23),			/*                          HI */
352219374Smm   COSTS_N_INSNS (39),			/*                          SI */
353219374Smm   COSTS_N_INSNS (39),			/*                          DI */
354219374Smm   COSTS_N_INSNS (39)},			/*                          other */
355219374Smm  COSTS_N_INSNS (1),			/* cost of movsx */
356219374Smm  COSTS_N_INSNS (1),			/* cost of movzx */
357219374Smm  8,					/* "large" insn */
358219374Smm  4,					/* MOVE_RATIO */
359219374Smm  1,					/* cost for loading QImode using movzbl */
360219374Smm  {1, 1, 1},				/* cost of loading integer registers
361219374Smm					   in QImode, HImode and SImode.
362219374Smm					   Relative to reg-reg move (2).  */
363219374Smm  {1, 1, 1},				/* cost of storing integer registers */
364219374Smm  1,					/* cost of reg,reg fld/fst */
365219374Smm  {1, 1, 1},				/* cost of loading fp registers
366219374Smm					   in SFmode, DFmode and XFmode */
367219374Smm  {4, 6, 6},				/* cost of storing fp registers
368219374Smm					   in SFmode, DFmode and XFmode */
369219374Smm
370219374Smm  1,					/* cost of moving MMX register */
371219374Smm  {1, 1},				/* cost of loading MMX registers
372219374Smm					   in SImode and DImode */
373219374Smm  {1, 1},				/* cost of storing MMX registers
374219374Smm					   in SImode and DImode */
375219374Smm  1,					/* cost of moving SSE register */
376219374Smm  {1, 1, 1},				/* cost of loading SSE registers
377219374Smm					   in SImode, DImode and TImode */
378219374Smm  {1, 1, 1},				/* cost of storing SSE registers
379219374Smm					   in SImode, DImode and TImode */
380219374Smm  1,					/* MMX or SSE register to integer */
381219374Smm  32,					/* size of prefetch block */
382219374Smm  1,					/* number of parallel prefetches */
383219374Smm  1,					/* Branch cost */
384219374Smm  COSTS_N_INSNS (6),			/* cost of FADD and FSUB insns.  */
385219374Smm  COSTS_N_INSNS (11),			/* cost of FMUL instruction.  */
386219374Smm  COSTS_N_INSNS (47),			/* cost of FDIV instruction.  */
387219374Smm  COSTS_N_INSNS (1),			/* cost of FABS instruction.  */
388219374Smm  COSTS_N_INSNS (1),			/* cost of FCHS instruction.  */
389219374Smm  COSTS_N_INSNS (54),			/* cost of FSQRT instruction.  */
390219374Smm};
391219374Smm
392219374Smmstatic const
39352294Sobrienstruct processor_costs k6_cost = {
394169705Skan  COSTS_N_INSNS (1),			/* cost of an add instruction */
395169705Skan  COSTS_N_INSNS (2),			/* cost of a lea instruction */
396169705Skan  COSTS_N_INSNS (1),			/* variable shift costs */
397169705Skan  COSTS_N_INSNS (1),			/* constant shift costs */
398169705Skan  {COSTS_N_INSNS (3),			/* cost of starting multiply for QI */
399169705Skan   COSTS_N_INSNS (3),			/*                               HI */
400169705Skan   COSTS_N_INSNS (3),			/*                               SI */
401169705Skan   COSTS_N_INSNS (3),			/*                               DI */
402169705Skan   COSTS_N_INSNS (3)},			/*                               other */
40352294Sobrien  0,					/* cost of multiply per each bit set */
404169705Skan  {COSTS_N_INSNS (18),			/* cost of a divide/mod for QI */
405169705Skan   COSTS_N_INSNS (18),			/*                          HI */
406169705Skan   COSTS_N_INSNS (18),			/*                          SI */
407169705Skan   COSTS_N_INSNS (18),			/*                          DI */
408169705Skan   COSTS_N_INSNS (18)},			/*                          other */
409169705Skan  COSTS_N_INSNS (2),			/* cost of movsx */
410169705Skan  COSTS_N_INSNS (2),			/* cost of movzx */
41190284Sobrien  8,					/* "large" insn */
41290284Sobrien  4,					/* MOVE_RATIO */
41390284Sobrien  3,					/* cost for loading QImode using movzbl */
41490284Sobrien  {4, 5, 4},				/* cost of loading integer registers
41590284Sobrien					   in QImode, HImode and SImode.
41690284Sobrien					   Relative to reg-reg move (2).  */
41790284Sobrien  {2, 3, 2},				/* cost of storing integer registers */
41890284Sobrien  4,					/* cost of reg,reg fld/fst */
41990284Sobrien  {6, 6, 6},				/* cost of loading fp registers
42090284Sobrien					   in SFmode, DFmode and XFmode */
421169705Skan  {4, 4, 4},				/* cost of storing fp registers
422169705Skan					   in SFmode, DFmode and XFmode */
42390284Sobrien  2,					/* cost of moving MMX register */
42490284Sobrien  {2, 2},				/* cost of loading MMX registers
42590284Sobrien					   in SImode and DImode */
42690284Sobrien  {2, 2},				/* cost of storing MMX registers
42790284Sobrien					   in SImode and DImode */
42890284Sobrien  2,					/* cost of moving SSE register */
42990284Sobrien  {2, 2, 8},				/* cost of loading SSE registers
43090284Sobrien					   in SImode, DImode and TImode */
43190284Sobrien  {2, 2, 8},				/* cost of storing SSE registers
43290284Sobrien					   in SImode, DImode and TImode */
43390284Sobrien  6,					/* MMX or SSE register to integer */
43490284Sobrien  32,					/* size of prefetch block */
43590284Sobrien  1,					/* number of parallel prefetches */
436132743Skan  1,					/* Branch cost */
437169705Skan  COSTS_N_INSNS (2),			/* cost of FADD and FSUB insns.  */
438169705Skan  COSTS_N_INSNS (2),			/* cost of FMUL instruction.  */
439169705Skan  COSTS_N_INSNS (56),			/* cost of FDIV instruction.  */
440169705Skan  COSTS_N_INSNS (2),			/* cost of FABS instruction.  */
441169705Skan  COSTS_N_INSNS (2),			/* cost of FCHS instruction.  */
442169705Skan  COSTS_N_INSNS (56),			/* cost of FSQRT instruction.  */
44352294Sobrien};
44452294Sobrien
445117408Skanstatic const
44690284Sobrienstruct processor_costs athlon_cost = {
447169705Skan  COSTS_N_INSNS (1),			/* cost of an add instruction */
448169705Skan  COSTS_N_INSNS (2),			/* cost of a lea instruction */
449169705Skan  COSTS_N_INSNS (1),			/* variable shift costs */
450169705Skan  COSTS_N_INSNS (1),			/* constant shift costs */
451169705Skan  {COSTS_N_INSNS (5),			/* cost of starting multiply for QI */
452169705Skan   COSTS_N_INSNS (5),			/*                               HI */
453169705Skan   COSTS_N_INSNS (5),			/*                               SI */
454169705Skan   COSTS_N_INSNS (5),			/*                               DI */
455169705Skan   COSTS_N_INSNS (5)},			/*                               other */
45690284Sobrien  0,					/* cost of multiply per each bit set */
457169705Skan  {COSTS_N_INSNS (18),			/* cost of a divide/mod for QI */
458169705Skan   COSTS_N_INSNS (26),			/*                          HI */
459169705Skan   COSTS_N_INSNS (42),			/*                          SI */
460169705Skan   COSTS_N_INSNS (74),			/*                          DI */
461169705Skan   COSTS_N_INSNS (74)},			/*                          other */
462169705Skan  COSTS_N_INSNS (1),			/* cost of movsx */
463169705Skan  COSTS_N_INSNS (1),			/* cost of movzx */
46490284Sobrien  8,					/* "large" insn */
46590284Sobrien  9,					/* MOVE_RATIO */
46690284Sobrien  4,					/* cost for loading QImode using movzbl */
467104767Skan  {3, 4, 3},				/* cost of loading integer registers
46890284Sobrien					   in QImode, HImode and SImode.
46990284Sobrien					   Relative to reg-reg move (2).  */
470104767Skan  {3, 4, 3},				/* cost of storing integer registers */
47190284Sobrien  4,					/* cost of reg,reg fld/fst */
472104767Skan  {4, 4, 12},				/* cost of loading fp registers
47390284Sobrien					   in SFmode, DFmode and XFmode */
474169705Skan  {6, 6, 8},				/* cost of storing fp registers
475169705Skan					   in SFmode, DFmode and XFmode */
47690284Sobrien  2,					/* cost of moving MMX register */
477104767Skan  {4, 4},				/* cost of loading MMX registers
47890284Sobrien					   in SImode and DImode */
479104767Skan  {4, 4},				/* cost of storing MMX registers
48090284Sobrien					   in SImode and DImode */
48190284Sobrien  2,					/* cost of moving SSE register */
482104767Skan  {4, 4, 6},				/* cost of loading SSE registers
48390284Sobrien					   in SImode, DImode and TImode */
484104767Skan  {4, 4, 5},				/* cost of storing SSE registers
48590284Sobrien					   in SImode, DImode and TImode */
486104767Skan  5,					/* MMX or SSE register to integer */
48790284Sobrien  64,					/* size of prefetch block */
48890284Sobrien  6,					/* number of parallel prefetches */
489169705Skan  5,					/* Branch cost */
490169705Skan  COSTS_N_INSNS (4),			/* cost of FADD and FSUB insns.  */
491169705Skan  COSTS_N_INSNS (4),			/* cost of FMUL instruction.  */
492169705Skan  COSTS_N_INSNS (24),			/* cost of FDIV instruction.  */
493169705Skan  COSTS_N_INSNS (2),			/* cost of FABS instruction.  */
494169705Skan  COSTS_N_INSNS (2),			/* cost of FCHS instruction.  */
495169705Skan  COSTS_N_INSNS (35),			/* cost of FSQRT instruction.  */
49690284Sobrien};
49751411Sobrien
498117408Skanstatic const
499132743Skanstruct processor_costs k8_cost = {
500169705Skan  COSTS_N_INSNS (1),			/* cost of an add instruction */
501169705Skan  COSTS_N_INSNS (2),			/* cost of a lea instruction */
502169705Skan  COSTS_N_INSNS (1),			/* variable shift costs */
503169705Skan  COSTS_N_INSNS (1),			/* constant shift costs */
504169705Skan  {COSTS_N_INSNS (3),			/* cost of starting multiply for QI */
505169705Skan   COSTS_N_INSNS (4),			/*                               HI */
506169705Skan   COSTS_N_INSNS (3),			/*                               SI */
507169705Skan   COSTS_N_INSNS (4),			/*                               DI */
508169705Skan   COSTS_N_INSNS (5)},			/*                               other */
509132743Skan  0,					/* cost of multiply per each bit set */
510169705Skan  {COSTS_N_INSNS (18),			/* cost of a divide/mod for QI */
511169705Skan   COSTS_N_INSNS (26),			/*                          HI */
512169705Skan   COSTS_N_INSNS (42),			/*                          SI */
513169705Skan   COSTS_N_INSNS (74),			/*                          DI */
514169705Skan   COSTS_N_INSNS (74)},			/*                          other */
515169705Skan  COSTS_N_INSNS (1),			/* cost of movsx */
516169705Skan  COSTS_N_INSNS (1),			/* cost of movzx */
517132743Skan  8,					/* "large" insn */
518132743Skan  9,					/* MOVE_RATIO */
519132743Skan  4,					/* cost for loading QImode using movzbl */
520132743Skan  {3, 4, 3},				/* cost of loading integer registers
521132743Skan					   in QImode, HImode and SImode.
522132743Skan					   Relative to reg-reg move (2).  */
523132743Skan  {3, 4, 3},				/* cost of storing integer registers */
524132743Skan  4,					/* cost of reg,reg fld/fst */
525132743Skan  {4, 4, 12},				/* cost of loading fp registers
526132743Skan					   in SFmode, DFmode and XFmode */
527169705Skan  {6, 6, 8},				/* cost of storing fp registers
528169705Skan					   in SFmode, DFmode and XFmode */
529132743Skan  2,					/* cost of moving MMX register */
530132743Skan  {3, 3},				/* cost of loading MMX registers
531132743Skan					   in SImode and DImode */
532132743Skan  {4, 4},				/* cost of storing MMX registers
533132743Skan					   in SImode and DImode */
534132743Skan  2,					/* cost of moving SSE register */
535132743Skan  {4, 3, 6},				/* cost of loading SSE registers
536132743Skan					   in SImode, DImode and TImode */
537132743Skan  {4, 4, 5},				/* cost of storing SSE registers
538132743Skan					   in SImode, DImode and TImode */
539132743Skan  5,					/* MMX or SSE register to integer */
540132743Skan  64,					/* size of prefetch block */
541132743Skan  6,					/* number of parallel prefetches */
542169705Skan  5,					/* Branch cost */
543169705Skan  COSTS_N_INSNS (4),			/* cost of FADD and FSUB insns.  */
544169705Skan  COSTS_N_INSNS (4),			/* cost of FMUL instruction.  */
545169705Skan  COSTS_N_INSNS (19),			/* cost of FDIV instruction.  */
546169705Skan  COSTS_N_INSNS (2),			/* cost of FABS instruction.  */
547169705Skan  COSTS_N_INSNS (2),			/* cost of FCHS instruction.  */
548169705Skan  COSTS_N_INSNS (35),			/* cost of FSQRT instruction.  */
549132743Skan};
550132743Skan
551251212Spfgstruct processor_costs amdfam10_cost = {
552251212Spfg  COSTS_N_INSNS (1),                    /* cost of an add instruction */
553251212Spfg  COSTS_N_INSNS (2),                    /* cost of a lea instruction */
554251212Spfg  COSTS_N_INSNS (1),                    /* variable shift costs */
555251212Spfg  COSTS_N_INSNS (1),                    /* constant shift costs */
556251212Spfg  {COSTS_N_INSNS (3),                   /* cost of starting multiply for QI */
557251212Spfg   COSTS_N_INSNS (4),                   /*                               HI */
558251212Spfg   COSTS_N_INSNS (3),                   /*                               SI */
559251212Spfg   COSTS_N_INSNS (4),                   /*                               DI */
560251212Spfg   COSTS_N_INSNS (5)},                  /*                               other */
561251212Spfg  0,                                    /* cost of multiply per each bit set */
562251212Spfg  {COSTS_N_INSNS (19),                  /* cost of a divide/mod for QI */
563251212Spfg   COSTS_N_INSNS (35),                  /*                          HI */
564251212Spfg   COSTS_N_INSNS (51),                  /*                          SI */
565251212Spfg   COSTS_N_INSNS (83),                  /*                          DI */
566251212Spfg   COSTS_N_INSNS (83)},                 /*                          other */
567251212Spfg  COSTS_N_INSNS (1),			/* cost of movsx */
568251212Spfg  COSTS_N_INSNS (1),			/* cost of movzx */
569251212Spfg  8,					/* "large" insn */
570251212Spfg  9,					/* MOVE_RATIO */
571251212Spfg  4,					/* cost for loading QImode using movzbl */
572251212Spfg  {3, 4, 3},				/* cost of loading integer registers
573251212Spfg					   in QImode, HImode and SImode.
574251212Spfg					   Relative to reg-reg move (2).  */
575251212Spfg  {3, 4, 3},				/* cost of storing integer registers */
576251212Spfg  4,					/* cost of reg,reg fld/fst */
577251212Spfg  {4, 4, 12},				/* cost of loading fp registers
578251212Spfg		   			   in SFmode, DFmode and XFmode */
579251212Spfg  {6, 6, 8},				/* cost of storing fp registers
580251212Spfg 		   			   in SFmode, DFmode and XFmode */
581251212Spfg  2,					/* cost of moving MMX register */
582251212Spfg  {3, 3},				/* cost of loading MMX registers
583251212Spfg					   in SImode and DImode */
584251212Spfg  {4, 4},				/* cost of storing MMX registers
585251212Spfg					   in SImode and DImode */
586251212Spfg  2,					/* cost of moving SSE register */
587251212Spfg  {4, 4, 3},				/* cost of loading SSE registers
588251212Spfg					   in SImode, DImode and TImode */
589251212Spfg  {4, 4, 5},				/* cost of storing SSE registers
590251212Spfg					   in SImode, DImode and TImode */
591251212Spfg  3,					/* MMX or SSE register to integer */
592251212Spfg  					/* On K8
593251212Spfg  					    MOVD reg64, xmmreg 	Double	FSTORE 4
594251212Spfg					    MOVD reg32, xmmreg 	Double	FSTORE 4
595251212Spfg					   On AMDFAM10
596251212Spfg					    MOVD reg64, xmmreg 	Double	FADD 3
597251212Spfg                                                                1/1  1/1
598251212Spfg					    MOVD reg32, xmmreg 	Double	FADD 3
599251212Spfg                                                                1/1  1/1 */
600251212Spfg  64,					/* size of prefetch block */
601251212Spfg  /* New AMD processors never drop prefetches; if they cannot be performed
602251212Spfg     immediately, they are queued.  We set number of simultaneous prefetches
603251212Spfg     to a large constant to reflect this (it probably is not a good idea not
604251212Spfg     to limit number of prefetches at all, as their execution also takes some
605251212Spfg     time).  */
606251212Spfg  100,					/* number of parallel prefetches */
607251212Spfg  5,					/* Branch cost */
608251212Spfg  COSTS_N_INSNS (4),			/* cost of FADD and FSUB insns.  */
609251212Spfg  COSTS_N_INSNS (4),			/* cost of FMUL instruction.  */
610251212Spfg  COSTS_N_INSNS (19),			/* cost of FDIV instruction.  */
611251212Spfg  COSTS_N_INSNS (2),			/* cost of FABS instruction.  */
612251212Spfg  COSTS_N_INSNS (2),			/* cost of FCHS instruction.  */
613251212Spfg  COSTS_N_INSNS (35),			/* cost of FSQRT instruction.  */
614251212Spfg};
615251212Spfg
616132743Skanstatic const
61790284Sobrienstruct processor_costs pentium4_cost = {
618169705Skan  COSTS_N_INSNS (1),			/* cost of an add instruction */
619169705Skan  COSTS_N_INSNS (3),			/* cost of a lea instruction */
620169705Skan  COSTS_N_INSNS (4),			/* variable shift costs */
621169705Skan  COSTS_N_INSNS (4),			/* constant shift costs */
622169705Skan  {COSTS_N_INSNS (15),			/* cost of starting multiply for QI */
623169705Skan   COSTS_N_INSNS (15),			/*                               HI */
624169705Skan   COSTS_N_INSNS (15),			/*                               SI */
625169705Skan   COSTS_N_INSNS (15),			/*                               DI */
626169705Skan   COSTS_N_INSNS (15)},			/*                               other */
62790284Sobrien  0,					/* cost of multiply per each bit set */
628169705Skan  {COSTS_N_INSNS (56),			/* cost of a divide/mod for QI */
629169705Skan   COSTS_N_INSNS (56),			/*                          HI */
630169705Skan   COSTS_N_INSNS (56),			/*                          SI */
631169705Skan   COSTS_N_INSNS (56),			/*                          DI */
632169705Skan   COSTS_N_INSNS (56)},			/*                          other */
633169705Skan  COSTS_N_INSNS (1),			/* cost of movsx */
634169705Skan  COSTS_N_INSNS (1),			/* cost of movzx */
63590284Sobrien  16,					/* "large" insn */
63690284Sobrien  6,					/* MOVE_RATIO */
63790284Sobrien  2,					/* cost for loading QImode using movzbl */
63890284Sobrien  {4, 5, 4},				/* cost of loading integer registers
63990284Sobrien					   in QImode, HImode and SImode.
64090284Sobrien					   Relative to reg-reg move (2).  */
64190284Sobrien  {2, 3, 2},				/* cost of storing integer registers */
64290284Sobrien  2,					/* cost of reg,reg fld/fst */
64390284Sobrien  {2, 2, 6},				/* cost of loading fp registers
64490284Sobrien					   in SFmode, DFmode and XFmode */
645169705Skan  {4, 4, 6},				/* cost of storing fp registers
646169705Skan					   in SFmode, DFmode and XFmode */
64790284Sobrien  2,					/* cost of moving MMX register */
64890284Sobrien  {2, 2},				/* cost of loading MMX registers
64990284Sobrien					   in SImode and DImode */
65090284Sobrien  {2, 2},				/* cost of storing MMX registers
65190284Sobrien					   in SImode and DImode */
65290284Sobrien  12,					/* cost of moving SSE register */
65390284Sobrien  {12, 12, 12},				/* cost of loading SSE registers
65490284Sobrien					   in SImode, DImode and TImode */
65590284Sobrien  {2, 2, 8},				/* cost of storing SSE registers
65690284Sobrien					   in SImode, DImode and TImode */
65790284Sobrien  10,					/* MMX or SSE register to integer */
65890284Sobrien  64,					/* size of prefetch block */
65990284Sobrien  6,					/* number of parallel prefetches */
660132743Skan  2,					/* Branch cost */
661169705Skan  COSTS_N_INSNS (5),			/* cost of FADD and FSUB insns.  */
662169705Skan  COSTS_N_INSNS (7),			/* cost of FMUL instruction.  */
663169705Skan  COSTS_N_INSNS (43),			/* cost of FDIV instruction.  */
664169705Skan  COSTS_N_INSNS (2),			/* cost of FABS instruction.  */
665169705Skan  COSTS_N_INSNS (2),			/* cost of FCHS instruction.  */
666169705Skan  COSTS_N_INSNS (43),			/* cost of FSQRT instruction.  */
66790284Sobrien};
66890284Sobrien
669169705Skanstatic const
670169705Skanstruct processor_costs nocona_cost = {
671169705Skan  COSTS_N_INSNS (1),			/* cost of an add instruction */
672169705Skan  COSTS_N_INSNS (1),			/* cost of a lea instruction */
673169705Skan  COSTS_N_INSNS (1),			/* variable shift costs */
674169705Skan  COSTS_N_INSNS (1),			/* constant shift costs */
675169705Skan  {COSTS_N_INSNS (10),			/* cost of starting multiply for QI */
676169705Skan   COSTS_N_INSNS (10),			/*                               HI */
677169705Skan   COSTS_N_INSNS (10),			/*                               SI */
678169705Skan   COSTS_N_INSNS (10),			/*                               DI */
679169705Skan   COSTS_N_INSNS (10)},			/*                               other */
680169705Skan  0,					/* cost of multiply per each bit set */
681169705Skan  {COSTS_N_INSNS (66),			/* cost of a divide/mod for QI */
682169705Skan   COSTS_N_INSNS (66),			/*                          HI */
683169705Skan   COSTS_N_INSNS (66),			/*                          SI */
684169705Skan   COSTS_N_INSNS (66),			/*                          DI */
685169705Skan   COSTS_N_INSNS (66)},			/*                          other */
686169705Skan  COSTS_N_INSNS (1),			/* cost of movsx */
687169705Skan  COSTS_N_INSNS (1),			/* cost of movzx */
688169705Skan  16,					/* "large" insn */
689169705Skan  17,					/* MOVE_RATIO */
690169705Skan  4,					/* cost for loading QImode using movzbl */
691169705Skan  {4, 4, 4},				/* cost of loading integer registers
692169705Skan					   in QImode, HImode and SImode.
693169705Skan					   Relative to reg-reg move (2).  */
694169705Skan  {4, 4, 4},				/* cost of storing integer registers */
695169705Skan  3,					/* cost of reg,reg fld/fst */
696169705Skan  {12, 12, 12},				/* cost of loading fp registers
697169705Skan					   in SFmode, DFmode and XFmode */
698169705Skan  {4, 4, 4},				/* cost of storing fp registers
699169705Skan					   in SFmode, DFmode and XFmode */
700169705Skan  6,					/* cost of moving MMX register */
701169705Skan  {12, 12},				/* cost of loading MMX registers
702169705Skan					   in SImode and DImode */
703169705Skan  {12, 12},				/* cost of storing MMX registers
704169705Skan					   in SImode and DImode */
705169705Skan  6,					/* cost of moving SSE register */
706169705Skan  {12, 12, 12},				/* cost of loading SSE registers
707169705Skan					   in SImode, DImode and TImode */
708169705Skan  {12, 12, 12},				/* cost of storing SSE registers
709169705Skan					   in SImode, DImode and TImode */
710169705Skan  8,					/* MMX or SSE register to integer */
711169705Skan  128,					/* size of prefetch block */
712169705Skan  8,					/* number of parallel prefetches */
713169705Skan  1,					/* Branch cost */
714169705Skan  COSTS_N_INSNS (6),			/* cost of FADD and FSUB insns.  */
715169705Skan  COSTS_N_INSNS (8),			/* cost of FMUL instruction.  */
716169705Skan  COSTS_N_INSNS (40),			/* cost of FDIV instruction.  */
717169705Skan  COSTS_N_INSNS (3),			/* cost of FABS instruction.  */
718169705Skan  COSTS_N_INSNS (3),			/* cost of FCHS instruction.  */
719169705Skan  COSTS_N_INSNS (44),			/* cost of FSQRT instruction.  */
720169705Skan};
721169705Skan
722219374Smmstatic const
723219374Smmstruct processor_costs core2_cost = {
724219374Smm  COSTS_N_INSNS (1),			/* cost of an add instruction */
725219374Smm  COSTS_N_INSNS (1) + 1,		/* cost of a lea instruction */
726219374Smm  COSTS_N_INSNS (1),			/* variable shift costs */
727219374Smm  COSTS_N_INSNS (1),			/* constant shift costs */
728219374Smm  {COSTS_N_INSNS (3),			/* cost of starting multiply for QI */
729219374Smm   COSTS_N_INSNS (3),			/*                               HI */
730219374Smm   COSTS_N_INSNS (3),			/*                               SI */
731219374Smm   COSTS_N_INSNS (3),			/*                               DI */
732219374Smm   COSTS_N_INSNS (3)},			/*                               other */
733219374Smm  0,					/* cost of multiply per each bit set */
734219374Smm  {COSTS_N_INSNS (22),			/* cost of a divide/mod for QI */
735219374Smm   COSTS_N_INSNS (22),			/*                          HI */
736219374Smm   COSTS_N_INSNS (22),			/*                          SI */
737219374Smm   COSTS_N_INSNS (22),			/*                          DI */
738219374Smm   COSTS_N_INSNS (22)},			/*                          other */
739219374Smm  COSTS_N_INSNS (1),			/* cost of movsx */
740219374Smm  COSTS_N_INSNS (1),			/* cost of movzx */
741219374Smm  8,					/* "large" insn */
742219374Smm  16,					/* MOVE_RATIO */
743219374Smm  2,					/* cost for loading QImode using movzbl */
744219374Smm  {6, 6, 6},				/* cost of loading integer registers
745219374Smm					   in QImode, HImode and SImode.
746219374Smm					   Relative to reg-reg move (2).  */
747219374Smm  {4, 4, 4},				/* cost of storing integer registers */
748219374Smm  2,					/* cost of reg,reg fld/fst */
749219374Smm  {6, 6, 6},				/* cost of loading fp registers
750219374Smm					   in SFmode, DFmode and XFmode */
751219374Smm  {4, 4, 4},				/* cost of loading integer registers */
752219374Smm  2,					/* cost of moving MMX register */
753219374Smm  {6, 6},				/* cost of loading MMX registers
754219374Smm					   in SImode and DImode */
755219374Smm  {4, 4},				/* cost of storing MMX registers
756219374Smm					   in SImode and DImode */
757219374Smm  2,					/* cost of moving SSE register */
758219374Smm  {6, 6, 6},				/* cost of loading SSE registers
759219374Smm					   in SImode, DImode and TImode */
760219374Smm  {4, 4, 4},				/* cost of storing SSE registers
761219374Smm					   in SImode, DImode and TImode */
762219374Smm  2,					/* MMX or SSE register to integer */
763219374Smm  128,					/* size of prefetch block */
764219374Smm  8,					/* number of parallel prefetches */
765219374Smm  3,					/* Branch cost */
766219374Smm  COSTS_N_INSNS (3),			/* cost of FADD and FSUB insns.  */
767219374Smm  COSTS_N_INSNS (5),			/* cost of FMUL instruction.  */
768219374Smm  COSTS_N_INSNS (32),			/* cost of FDIV instruction.  */
769219374Smm  COSTS_N_INSNS (1),			/* cost of FABS instruction.  */
770219374Smm  COSTS_N_INSNS (1),			/* cost of FCHS instruction.  */
771219374Smm  COSTS_N_INSNS (58),			/* cost of FSQRT instruction.  */
772219374Smm};
773219374Smm
774169705Skan/* Generic64 should produce code tuned for Nocona and K8.  */
775169705Skanstatic const
776169705Skanstruct processor_costs generic64_cost = {
777169705Skan  COSTS_N_INSNS (1),			/* cost of an add instruction */
778169705Skan  /* On all chips taken into consideration lea is 2 cycles and more.  With
779169705Skan     this cost however our current implementation of synth_mult results in
780169705Skan     use of unnecessary temporary registers causing regression on several
781169705Skan     SPECfp benchmarks.  */
782169705Skan  COSTS_N_INSNS (1) + 1,		/* cost of a lea instruction */
783169705Skan  COSTS_N_INSNS (1),			/* variable shift costs */
784169705Skan  COSTS_N_INSNS (1),			/* constant shift costs */
785169705Skan  {COSTS_N_INSNS (3),			/* cost of starting multiply for QI */
786169705Skan   COSTS_N_INSNS (4),			/*                               HI */
787169705Skan   COSTS_N_INSNS (3),			/*                               SI */
788169705Skan   COSTS_N_INSNS (4),			/*                               DI */
789169705Skan   COSTS_N_INSNS (2)},			/*                               other */
790169705Skan  0,					/* cost of multiply per each bit set */
791169705Skan  {COSTS_N_INSNS (18),			/* cost of a divide/mod for QI */
792169705Skan   COSTS_N_INSNS (26),			/*                          HI */
793169705Skan   COSTS_N_INSNS (42),			/*                          SI */
794169705Skan   COSTS_N_INSNS (74),			/*                          DI */
795169705Skan   COSTS_N_INSNS (74)},			/*                          other */
796169705Skan  COSTS_N_INSNS (1),			/* cost of movsx */
797169705Skan  COSTS_N_INSNS (1),			/* cost of movzx */
798169705Skan  8,					/* "large" insn */
799169705Skan  17,					/* MOVE_RATIO */
800169705Skan  4,					/* cost for loading QImode using movzbl */
801169705Skan  {4, 4, 4},				/* cost of loading integer registers
802169705Skan					   in QImode, HImode and SImode.
803169705Skan					   Relative to reg-reg move (2).  */
804169705Skan  {4, 4, 4},				/* cost of storing integer registers */
805169705Skan  4,					/* cost of reg,reg fld/fst */
806169705Skan  {12, 12, 12},				/* cost of loading fp registers
807169705Skan					   in SFmode, DFmode and XFmode */
808169705Skan  {6, 6, 8},				/* cost of storing fp registers
809169705Skan					   in SFmode, DFmode and XFmode */
810169705Skan  2,					/* cost of moving MMX register */
811169705Skan  {8, 8},				/* cost of loading MMX registers
812169705Skan					   in SImode and DImode */
813169705Skan  {8, 8},				/* cost of storing MMX registers
814169705Skan					   in SImode and DImode */
815169705Skan  2,					/* cost of moving SSE register */
816169705Skan  {8, 8, 8},				/* cost of loading SSE registers
817169705Skan					   in SImode, DImode and TImode */
818169705Skan  {8, 8, 8},				/* cost of storing SSE registers
819169705Skan					   in SImode, DImode and TImode */
820169705Skan  5,					/* MMX or SSE register to integer */
821169705Skan  64,					/* size of prefetch block */
822169705Skan  6,					/* number of parallel prefetches */
823169705Skan  /* Benchmarks shows large regressions on K8 sixtrack benchmark when this value
824169705Skan     is increased to perhaps more appropriate value of 5.  */
825169705Skan  3,					/* Branch cost */
826169705Skan  COSTS_N_INSNS (8),			/* cost of FADD and FSUB insns.  */
827169705Skan  COSTS_N_INSNS (8),			/* cost of FMUL instruction.  */
828169705Skan  COSTS_N_INSNS (20),			/* cost of FDIV instruction.  */
829169705Skan  COSTS_N_INSNS (8),			/* cost of FABS instruction.  */
830169705Skan  COSTS_N_INSNS (8),			/* cost of FCHS instruction.  */
831169705Skan  COSTS_N_INSNS (40),			/* cost of FSQRT instruction.  */
832169705Skan};
833169705Skan
834169705Skan/* Generic32 should produce code tuned for Athlon, PPro, Pentium4, Nocona and K8.  */
835169705Skanstatic const
836169705Skanstruct processor_costs generic32_cost = {
837169705Skan  COSTS_N_INSNS (1),			/* cost of an add instruction */
838169705Skan  COSTS_N_INSNS (1) + 1,		/* cost of a lea instruction */
839169705Skan  COSTS_N_INSNS (1),			/* variable shift costs */
840169705Skan  COSTS_N_INSNS (1),			/* constant shift costs */
841169705Skan  {COSTS_N_INSNS (3),			/* cost of starting multiply for QI */
842169705Skan   COSTS_N_INSNS (4),			/*                               HI */
843169705Skan   COSTS_N_INSNS (3),			/*                               SI */
844169705Skan   COSTS_N_INSNS (4),			/*                               DI */
845169705Skan   COSTS_N_INSNS (2)},			/*                               other */
846169705Skan  0,					/* cost of multiply per each bit set */
847169705Skan  {COSTS_N_INSNS (18),			/* cost of a divide/mod for QI */
848169705Skan   COSTS_N_INSNS (26),			/*                          HI */
849169705Skan   COSTS_N_INSNS (42),			/*                          SI */
850169705Skan   COSTS_N_INSNS (74),			/*                          DI */
851169705Skan   COSTS_N_INSNS (74)},			/*                          other */
852169705Skan  COSTS_N_INSNS (1),			/* cost of movsx */
853169705Skan  COSTS_N_INSNS (1),			/* cost of movzx */
854169705Skan  8,					/* "large" insn */
855169705Skan  17,					/* MOVE_RATIO */
856169705Skan  4,					/* cost for loading QImode using movzbl */
857169705Skan  {4, 4, 4},				/* cost of loading integer registers
858169705Skan					   in QImode, HImode and SImode.
859169705Skan					   Relative to reg-reg move (2).  */
860169705Skan  {4, 4, 4},				/* cost of storing integer registers */
861169705Skan  4,					/* cost of reg,reg fld/fst */
862169705Skan  {12, 12, 12},				/* cost of loading fp registers
863169705Skan					   in SFmode, DFmode and XFmode */
864169705Skan  {6, 6, 8},				/* cost of storing fp registers
865169705Skan					   in SFmode, DFmode and XFmode */
866169705Skan  2,					/* cost of moving MMX register */
867169705Skan  {8, 8},				/* cost of loading MMX registers
868169705Skan					   in SImode and DImode */
869169705Skan  {8, 8},				/* cost of storing MMX registers
870169705Skan					   in SImode and DImode */
871169705Skan  2,					/* cost of moving SSE register */
872169705Skan  {8, 8, 8},				/* cost of loading SSE registers
873169705Skan					   in SImode, DImode and TImode */
874169705Skan  {8, 8, 8},				/* cost of storing SSE registers
875169705Skan					   in SImode, DImode and TImode */
876169705Skan  5,					/* MMX or SSE register to integer */
877169705Skan  64,					/* size of prefetch block */
878169705Skan  6,					/* number of parallel prefetches */
879169705Skan  3,					/* Branch cost */
880169705Skan  COSTS_N_INSNS (8),			/* cost of FADD and FSUB insns.  */
881169705Skan  COSTS_N_INSNS (8),			/* cost of FMUL instruction.  */
882169705Skan  COSTS_N_INSNS (20),			/* cost of FDIV instruction.  */
883169705Skan  COSTS_N_INSNS (8),			/* cost of FABS instruction.  */
884169705Skan  COSTS_N_INSNS (8),			/* cost of FCHS instruction.  */
885169705Skan  COSTS_N_INSNS (40),			/* cost of FSQRT instruction.  */
886169705Skan};
887169705Skan
88890284Sobrienconst struct processor_costs *ix86_cost = &pentium_cost;
88990284Sobrien
89052294Sobrien/* Processor feature/optimization bitmasks.  */
89152294Sobrien#define m_386 (1<<PROCESSOR_I386)
89252294Sobrien#define m_486 (1<<PROCESSOR_I486)
89352294Sobrien#define m_PENT (1<<PROCESSOR_PENTIUM)
89452294Sobrien#define m_PPRO (1<<PROCESSOR_PENTIUMPRO)
895219374Smm#define m_GEODE  (1<<PROCESSOR_GEODE)
896219374Smm#define m_K6_GEODE  (m_K6 | m_GEODE)
89752294Sobrien#define m_K6  (1<<PROCESSOR_K6)
89890284Sobrien#define m_ATHLON  (1<<PROCESSOR_ATHLON)
89990284Sobrien#define m_PENT4  (1<<PROCESSOR_PENTIUM4)
900132743Skan#define m_K8  (1<<PROCESSOR_K8)
901132743Skan#define m_ATHLON_K8  (m_K8 | m_ATHLON)
902251212Spfg#define m_AMDFAM10  (1<<PROCESSOR_AMDFAM10)
903169705Skan#define m_NOCONA  (1<<PROCESSOR_NOCONA)
904219374Smm#define m_CORE2  (1<<PROCESSOR_CORE2)
905169705Skan#define m_GENERIC32 (1<<PROCESSOR_GENERIC32)
906169705Skan#define m_GENERIC64 (1<<PROCESSOR_GENERIC64)
907169705Skan#define m_GENERIC (m_GENERIC32 | m_GENERIC64)
908251212Spfg#define m_ATHLON_K8_AMDFAM10  (m_K8 | m_ATHLON | m_AMDFAM10)
90952294Sobrien
910169705Skan/* Generic instruction choice should be common subset of supported CPUs
911219374Smm   (PPro/PENT4/NOCONA/CORE2/Athlon/K8).  */
912169705Skan
913169705Skan/* Leave is not affecting Nocona SPEC2000 results negatively, so enabling for
914169705Skan   Generic64 seems like good code size tradeoff.  We can't enable it for 32bit
915169705Skan   generic because it is not working well with PPro base chips.  */
916251212Spfgconst int x86_use_leave = m_386 | m_K6_GEODE | m_ATHLON_K8_AMDFAM10 | m_CORE2
917251212Spfg                          | m_GENERIC64;
918251212Spfgconst int x86_push_memory = m_386 | m_K6_GEODE | m_ATHLON_K8_AMDFAM10 | m_PENT4
919251212Spfg                            | m_NOCONA | m_CORE2 | m_GENERIC;
92052294Sobrienconst int x86_zero_extend_with_and = m_486 | m_PENT;
921251212Spfg/* Enable to zero extend integer registers to avoid partial dependencies */
922251212Spfgconst int x86_movx = m_ATHLON_K8_AMDFAM10 | m_PPRO | m_PENT4 | m_NOCONA
923251212Spfg                     | m_CORE2 | m_GENERIC | m_GEODE /* m_386 | m_K6 */;
92490284Sobrienconst int x86_double_with_add = ~m_386;
92552294Sobrienconst int x86_use_bit_test = m_386;
926251212Spfgconst int x86_unroll_strlen = m_486 | m_PENT | m_PPRO | m_ATHLON_K8_AMDFAM10
927251212Spfg                              | m_K6 | m_CORE2 | m_GENERIC;
928251212Spfgconst int x86_cmove = m_PPRO | m_GEODE | m_ATHLON_K8_AMDFAM10 | m_PENT4
929251212Spfg                      | m_NOCONA;
930251212Spfgconst int x86_3dnow_a = m_ATHLON_K8_AMDFAM10;
931251212Spfgconst int x86_deep_branch = m_PPRO | m_K6_GEODE | m_ATHLON_K8_AMDFAM10
932251212Spfg                            | m_PENT4 | m_NOCONA | m_CORE2 | m_GENERIC;
933169705Skan/* Branch hints were put in P4 based on simulation result. But
934169705Skan   after P4 was made, no performance benefit was observed with
935169705Skan   branch hints. It also increases the code size. As the result,
936169705Skan   icc never generates branch hints.  */
937169705Skanconst int x86_branch_hints = 0;
938251212Spfgconst int x86_use_sahf = m_PPRO | m_K6_GEODE | m_PENT4 | m_NOCONA | m_GENERIC32;
939251212Spfg                         /*m_GENERIC | m_ATHLON_K8 ? */
940169705Skan/* We probably ought to watch for partial register stalls on Generic32
941169705Skan   compilation setting as well.  However in current implementation the
942169705Skan   partial register stalls are not eliminated very well - they can
943169705Skan   be introduced via subregs synthesized by combine and can happen
944169705Skan   in caller/callee saving sequences.
945169705Skan   Because this option pays back little on PPro based chips and is in conflict
946169705Skan   with partial reg. dependencies used by Athlon/P4 based chips, it is better
947169705Skan   to leave it off for generic32 for now.  */
94890284Sobrienconst int x86_partial_reg_stall = m_PPRO;
949219374Smmconst int x86_partial_flag_reg_stall =  m_CORE2 | m_GENERIC;
950219374Smmconst int x86_use_himode_fiop = m_386 | m_486 | m_K6_GEODE;
951251212Spfgconst int x86_use_simode_fiop = ~(m_PPRO | m_ATHLON_K8_AMDFAM10 | m_PENT
952251212Spfg                                  | m_CORE2 | m_GENERIC);
95390284Sobrienconst int x86_use_mov0 = m_K6;
954219374Smmconst int x86_use_cltd = ~(m_PENT | m_K6 | m_CORE2 | m_GENERIC);
95590284Sobrienconst int x86_read_modify_write = ~m_PENT;
95690284Sobrienconst int x86_read_modify = ~(m_PENT | m_PPRO);
95790284Sobrienconst int x86_split_long_moves = m_PPRO;
958251212Spfgconst int x86_promote_QImode = m_K6_GEODE | m_PENT | m_386 | m_486
959251212Spfg                               | m_ATHLON_K8_AMDFAM10 | m_CORE2 | m_GENERIC;
960251212Spfg                               /* m_PENT4 ? */
961117408Skanconst int x86_fast_prefix = ~(m_PENT | m_486 | m_386);
962169705Skanconst int x86_single_stringop = m_386 | m_PENT4 | m_NOCONA;
96390284Sobrienconst int x86_qimode_math = ~(0);
96490284Sobrienconst int x86_promote_qi_regs = 0;
965169705Skan/* On PPro this flag is meant to avoid partial register stalls.  Just like
966169705Skan   the x86_partial_reg_stall this option might be considered for Generic32
967169705Skan   if our scheme for avoiding partial stalls was more effective.  */
96890284Sobrienconst int x86_himode_math = ~(m_PPRO);
96990284Sobrienconst int x86_promote_hi_regs = m_PPRO;
970251212Spfg/* Enable if add/sub rsp is preferred over 1 or 2 push/pop */
971251212Spfgconst int x86_sub_esp_4 = m_ATHLON_K8_AMDFAM10 | m_PPRO | m_PENT4 | m_NOCONA
972251212Spfg                          | m_CORE2 | m_GENERIC;
973251212Spfgconst int x86_sub_esp_8 = m_ATHLON_K8_AMDFAM10 | m_PPRO | m_386 | m_486
974251212Spfg                          | m_PENT4 | m_NOCONA | m_CORE2 | m_GENERIC;
975251212Spfgconst int x86_add_esp_4 = m_ATHLON_K8_AMDFAM10 | m_K6_GEODE | m_PENT4 | m_NOCONA
976251212Spfg                          | m_CORE2 | m_GENERIC;
977251212Spfgconst int x86_add_esp_8 = m_ATHLON_K8_AMDFAM10 | m_PPRO | m_K6_GEODE | m_386
978251212Spfg                          | m_486 | m_PENT4 | m_NOCONA | m_CORE2 | m_GENERIC;
979251212Spfg/* Enable if integer moves are preferred for DFmode copies */
980251212Spfgconst int x86_integer_DFmode_moves = ~(m_ATHLON_K8_AMDFAM10 | m_PENT4 | m_NOCONA
981251212Spfg                                       | m_PPRO | m_CORE2 | m_GENERIC | m_GEODE);
982251212Spfgconst int x86_partial_reg_dependency = m_ATHLON_K8_AMDFAM10 | m_PENT4 | m_NOCONA
983251212Spfg                                       | m_CORE2 | m_GENERIC;
984251212Spfgconst int x86_memory_mismatch_stall = m_ATHLON_K8_AMDFAM10 | m_PENT4 | m_NOCONA
985251212Spfg                                      | m_CORE2 | m_GENERIC;
986251212Spfg/* If ACCUMULATE_OUTGOING_ARGS is enabled, the maximum amount of space required
987251212Spfg   for outgoing arguments will be computed and placed into the variable
988251212Spfg   `current_function_outgoing_args_size'. No space will be pushed onto the stack
989251212Spfg   for each call; instead, the function prologue should increase the stack frame
990251212Spfg   size by this amount. Setting both PUSH_ARGS and ACCUMULATE_OUTGOING_ARGS is
991251212Spfg   not proper. */
992251212Spfgconst int x86_accumulate_outgoing_args = m_ATHLON_K8_AMDFAM10 | m_PENT4
993251212Spfg                                         | m_NOCONA | m_PPRO | m_CORE2
994251212Spfg                                         | m_GENERIC;
995219374Smmconst int x86_prologue_using_move = m_ATHLON_K8 | m_PPRO | m_CORE2 | m_GENERIC;
996219374Smmconst int x86_epilogue_using_move = m_ATHLON_K8 | m_PPRO | m_CORE2 | m_GENERIC;
997117408Skanconst int x86_shift1 = ~m_486;
998251212Spfgconst int x86_arch_always_fancy_math_387 = m_PENT | m_PPRO
999251212Spfg                                           | m_ATHLON_K8_AMDFAM10 | m_PENT4
1000251212Spfg                                           | m_NOCONA | m_CORE2 | m_GENERIC;
1001169705Skan/* In Generic model we have an conflict here in between PPro/Pentium4 based chips
1002169705Skan   that thread 128bit SSE registers as single units versus K8 based chips that
1003169705Skan   divide SSE registers to two 64bit halves.
1004169705Skan   x86_sse_partial_reg_dependency promote all store destinations to be 128bit
1005169705Skan   to allow register renaming on 128bit SSE units, but usually results in one
1006169705Skan   extra microop on 64bit SSE units.  Experimental results shows that disabling
1007169705Skan   this option on P4 brings over 20% SPECfp regression, while enabling it on
1008169705Skan   K8 brings roughly 2.4% regression that can be partly masked by careful scheduling
1009169705Skan   of moves.  */
1010251212Spfgconst int x86_sse_partial_reg_dependency = m_PENT4 | m_NOCONA | m_PPRO | m_CORE2
1011251212Spfg                                           | m_GENERIC | m_AMDFAM10;
1012169705Skan/* Set for machines where the type and dependencies are resolved on SSE
1013169705Skan   register parts instead of whole registers, so we may maintain just
1014169705Skan   lower part of scalar values in proper format leaving the upper part
1015169705Skan   undefined.  */
1016169705Skanconst int x86_sse_split_regs = m_ATHLON_K8;
1017251212Spfg/* Code generation for scalar reg-reg moves of single and double precision data:
1018251212Spfg     if (x86_sse_partial_reg_dependency == true | x86_sse_split_regs == true)
1019251212Spfg       movaps reg, reg
1020251212Spfg     else
1021251212Spfg       movss reg, reg
1022251212Spfg     if (x86_sse_partial_reg_dependency == true)
1023251212Spfg       movapd reg, reg
1024251212Spfg     else
1025251212Spfg       movsd reg, reg
1026251212Spfg
1027251212Spfg   Code generation for scalar loads of double precision data:
1028251212Spfg     if (x86_sse_split_regs == true)
1029251212Spfg       movlpd mem, reg      (gas syntax)
1030251212Spfg     else
1031251212Spfg       movsd mem, reg
1032251212Spfg
1033251212Spfg   Code generation for unaligned packed loads of single precision data
1034251212Spfg   (x86_sse_unaligned_move_optimal overrides x86_sse_partial_reg_dependency):
1035251212Spfg     if (x86_sse_unaligned_move_optimal)
1036251212Spfg       movups mem, reg
1037251212Spfg
1038251212Spfg     if (x86_sse_partial_reg_dependency == true)
1039251212Spfg       {
1040251212Spfg         xorps  reg, reg
1041251212Spfg         movlps mem, reg
1042251212Spfg         movhps mem+8, reg
1043251212Spfg       }
1044251212Spfg     else
1045251212Spfg       {
1046251212Spfg         movlps mem, reg
1047251212Spfg         movhps mem+8, reg
1048251212Spfg       }
1049251212Spfg
1050251212Spfg   Code generation for unaligned packed loads of double precision data
1051251212Spfg   (x86_sse_unaligned_move_optimal overrides x86_sse_split_regs):
1052251212Spfg     if (x86_sse_unaligned_move_optimal)
1053251212Spfg       movupd mem, reg
1054251212Spfg
1055251212Spfg     if (x86_sse_split_regs == true)
1056251212Spfg       {
1057251212Spfg         movlpd mem, reg
1058251212Spfg         movhpd mem+8, reg
1059251212Spfg       }
1060251212Spfg     else
1061251212Spfg       {
1062251212Spfg         movsd  mem, reg
1063251212Spfg         movhpd mem+8, reg
1064251212Spfg       }
1065251212Spfg */
1066251212Spfgconst int x86_sse_unaligned_move_optimal = m_AMDFAM10;
1067251212Spfgconst int x86_sse_typeless_stores = m_ATHLON_K8_AMDFAM10;
1068169705Skanconst int x86_sse_load0_by_pxor = m_PPRO | m_PENT4 | m_NOCONA;
1069251212Spfgconst int x86_use_ffreep = m_ATHLON_K8_AMDFAM10;
1070219374Smmconst int x86_rep_movl_optimal = m_386 | m_PENT | m_PPRO | m_K6_GEODE | m_CORE2;
1071219374Smmconst int x86_use_incdec = ~(m_PENT4 | m_NOCONA | m_CORE2 | m_GENERIC);
1072146908Skan
1073169705Skan/* ??? Allowing interunit moves makes it all too easy for the compiler to put
1074169705Skan   integer data in xmm registers.  Which results in pretty abysmal code.  */
1075169705Skanconst int x86_inter_unit_moves = 0 /* ~(m_ATHLON_K8) */;
1076146908Skan
1077251212Spfgconst int x86_ext_80387_constants = m_K6_GEODE | m_ATHLON_K8 | m_PENT4
1078251212Spfg                                    | m_NOCONA | m_PPRO | m_CORE2 | m_GENERIC;
1079169705Skan/* Some CPU cores are not able to predict more than 4 branch instructions in
1080169705Skan   the 16 byte window.  */
1081251212Spfgconst int x86_four_jump_limit = m_PPRO | m_ATHLON_K8_AMDFAM10 | m_PENT4
1082251212Spfg                                | m_NOCONA | m_CORE2 | m_GENERIC;
1083251212Spfgconst int x86_schedule = m_PPRO | m_ATHLON_K8_AMDFAM10 | m_K6_GEODE | m_PENT
1084251212Spfg                         | m_CORE2 | m_GENERIC;
1085251212Spfgconst int x86_use_bt = m_ATHLON_K8_AMDFAM10;
1086169705Skan/* Compare and exchange was added for 80486.  */
1087169705Skanconst int x86_cmpxchg = ~m_386;
1088169705Skan/* Compare and exchange 8 bytes was added for pentium.  */
1089169705Skanconst int x86_cmpxchg8b = ~(m_386 | m_486);
1090169705Skan/* Exchange and add was added for 80486.  */
1091169705Skanconst int x86_xadd = ~m_386;
1092258428Spfg/* Byteswap was added for 80486.  */
1093258428Spfgconst int x86_bswap = ~m_386;
1094251212Spfgconst int x86_pad_returns = m_ATHLON_K8_AMDFAM10 | m_CORE2 | m_GENERIC;
109552294Sobrien
1096132743Skan/* In case the average insn count for single function invocation is
109790284Sobrien   lower than this constant, emit fast (but longer) prologue and
109890284Sobrien   epilogue code.  */
1099132743Skan#define FAST_PROLOGUE_INSN_COUNT 20
1100117408Skan
1101117408Skan/* Names for 8 (low), 8 (high), and 16-bit registers, respectively.  */
1102117408Skanstatic const char *const qi_reg_name[] = QI_REGISTER_NAMES;
1103117408Skanstatic const char *const qi_high_reg_name[] = QI_HIGH_REGISTER_NAMES;
1104117408Skanstatic const char *const hi_reg_name[] = HI_REGISTER_NAMES;
110518334Speter
110618334Speter/* Array of the smallest class containing reg number REGNO, indexed by
110790284Sobrien   REGNO.  Used by REGNO_REG_CLASS in i386.h.  */
110818334Speter
110990284Sobrienenum reg_class const regclass_map[FIRST_PSEUDO_REGISTER] =
111018334Speter{
111118334Speter  /* ax, dx, cx, bx */
111218334Speter  AREG, DREG, CREG, BREG,
111318334Speter  /* si, di, bp, sp */
111490284Sobrien  SIREG, DIREG, NON_Q_REGS, NON_Q_REGS,
111518334Speter  /* FP registers */
111618334Speter  FP_TOP_REG, FP_SECOND_REG, FLOAT_REGS, FLOAT_REGS,
111751411Sobrien  FLOAT_REGS, FLOAT_REGS, FLOAT_REGS, FLOAT_REGS,
111818334Speter  /* arg pointer */
111990284Sobrien  NON_Q_REGS,
1120237021Spfg  /* flags, fpsr, dirflag, frame */
1121237021Spfg  NO_REGS, NO_REGS, NO_REGS, NON_Q_REGS,
112290284Sobrien  SSE_REGS, SSE_REGS, SSE_REGS, SSE_REGS, SSE_REGS, SSE_REGS,
112390284Sobrien  SSE_REGS, SSE_REGS,
112490284Sobrien  MMX_REGS, MMX_REGS, MMX_REGS, MMX_REGS, MMX_REGS, MMX_REGS,
112590284Sobrien  MMX_REGS, MMX_REGS,
112690284Sobrien  NON_Q_REGS, NON_Q_REGS, NON_Q_REGS, NON_Q_REGS,
112790284Sobrien  NON_Q_REGS, NON_Q_REGS, NON_Q_REGS, NON_Q_REGS,
112890284Sobrien  SSE_REGS, SSE_REGS, SSE_REGS, SSE_REGS, SSE_REGS, SSE_REGS,
112990284Sobrien  SSE_REGS, SSE_REGS,
113018334Speter};
113118334Speter
113290284Sobrien/* The "default" register map used in 32bit mode.  */
113390284Sobrien
113490284Sobrienint const dbx_register_map[FIRST_PSEUDO_REGISTER] =
113590284Sobrien{
113690284Sobrien  0, 2, 1, 3, 6, 7, 4, 5,		/* general regs */
113790284Sobrien  12, 13, 14, 15, 16, 17, 18, 19,	/* fp regs */
1138237021Spfg  -1, -1, -1, -1, -1,			/* arg, flags, fpsr, dir, frame */
113990284Sobrien  21, 22, 23, 24, 25, 26, 27, 28,	/* SSE */
114090284Sobrien  29, 30, 31, 32, 33, 34, 35, 36,       /* MMX */
114190284Sobrien  -1, -1, -1, -1, -1, -1, -1, -1,	/* extended integer registers */
114290284Sobrien  -1, -1, -1, -1, -1, -1, -1, -1,	/* extended SSE registers */
114390284Sobrien};
114490284Sobrien
1145117408Skanstatic int const x86_64_int_parameter_registers[6] =
1146117408Skan{
1147117408Skan  5 /*RDI*/, 4 /*RSI*/, 1 /*RDX*/, 2 /*RCX*/,
1148117408Skan  FIRST_REX_INT_REG /*R8 */, FIRST_REX_INT_REG + 1 /*R9 */
1149117408Skan};
115090284Sobrien
1151117408Skanstatic int const x86_64_int_return_registers[4] =
1152117408Skan{
1153117408Skan  0 /*RAX*/, 1 /*RDI*/, 5 /*RDI*/, 4 /*RSI*/
1154117408Skan};
1155117408Skan
115690284Sobrien/* The "default" register map used in 64bit mode.  */
115790284Sobrienint const dbx64_register_map[FIRST_PSEUDO_REGISTER] =
115890284Sobrien{
115990284Sobrien  0, 1, 2, 3, 4, 5, 6, 7,		/* general regs */
1160102800Skan  33, 34, 35, 36, 37, 38, 39, 40,	/* fp regs */
1161237021Spfg  -1, -1, -1, -1, -1,			/* arg, flags, fpsr, dir, frame */
116290284Sobrien  17, 18, 19, 20, 21, 22, 23, 24,	/* SSE */
116390284Sobrien  41, 42, 43, 44, 45, 46, 47, 48,       /* MMX */
116490284Sobrien  8,9,10,11,12,13,14,15,		/* extended integer registers */
116590284Sobrien  25, 26, 27, 28, 29, 30, 31, 32,	/* extended SSE registers */
116690284Sobrien};
116790284Sobrien
116890284Sobrien/* Define the register numbers to be used in Dwarf debugging information.
116990284Sobrien   The SVR4 reference port C compiler uses the following register numbers
117090284Sobrien   in its Dwarf output code:
117190284Sobrien	0 for %eax (gcc regno = 0)
117290284Sobrien	1 for %ecx (gcc regno = 2)
117390284Sobrien	2 for %edx (gcc regno = 1)
117490284Sobrien	3 for %ebx (gcc regno = 3)
117590284Sobrien	4 for %esp (gcc regno = 7)
117690284Sobrien	5 for %ebp (gcc regno = 6)
117790284Sobrien	6 for %esi (gcc regno = 4)
117890284Sobrien	7 for %edi (gcc regno = 5)
117990284Sobrien   The following three DWARF register numbers are never generated by
118090284Sobrien   the SVR4 C compiler or by the GNU compilers, but SDB on x86/svr4
118190284Sobrien   believes these numbers have these meanings.
118290284Sobrien	8  for %eip    (no gcc equivalent)
118390284Sobrien	9  for %eflags (gcc regno = 17)
118490284Sobrien	10 for %trapno (no gcc equivalent)
118590284Sobrien   It is not at all clear how we should number the FP stack registers
118690284Sobrien   for the x86 architecture.  If the version of SDB on x86/svr4 were
118790284Sobrien   a bit less brain dead with respect to floating-point then we would
118890284Sobrien   have a precedent to follow with respect to DWARF register numbers
118990284Sobrien   for x86 FP registers, but the SDB on x86/svr4 is so completely
119090284Sobrien   broken with respect to FP registers that it is hardly worth thinking
119190284Sobrien   of it as something to strive for compatibility with.
119290284Sobrien   The version of x86/svr4 SDB I have at the moment does (partially)
119390284Sobrien   seem to believe that DWARF register number 11 is associated with
119490284Sobrien   the x86 register %st(0), but that's about all.  Higher DWARF
119590284Sobrien   register numbers don't seem to be associated with anything in
119690284Sobrien   particular, and even for DWARF regno 11, SDB only seems to under-
119790284Sobrien   stand that it should say that a variable lives in %st(0) (when
119890284Sobrien   asked via an `=' command) if we said it was in DWARF regno 11,
119990284Sobrien   but SDB still prints garbage when asked for the value of the
120090284Sobrien   variable in question (via a `/' command).
120190284Sobrien   (Also note that the labels SDB prints for various FP stack regs
120290284Sobrien   when doing an `x' command are all wrong.)
120390284Sobrien   Note that these problems generally don't affect the native SVR4
120490284Sobrien   C compiler because it doesn't allow the use of -O with -g and
120590284Sobrien   because when it is *not* optimizing, it allocates a memory
120690284Sobrien   location for each floating-point variable, and the memory
120790284Sobrien   location is what gets described in the DWARF AT_location
120890284Sobrien   attribute for the variable in question.
120990284Sobrien   Regardless of the severe mental illness of the x86/svr4 SDB, we
121090284Sobrien   do something sensible here and we use the following DWARF
121190284Sobrien   register numbers.  Note that these are all stack-top-relative
121290284Sobrien   numbers.
121390284Sobrien	11 for %st(0) (gcc regno = 8)
121490284Sobrien	12 for %st(1) (gcc regno = 9)
121590284Sobrien	13 for %st(2) (gcc regno = 10)
121690284Sobrien	14 for %st(3) (gcc regno = 11)
121790284Sobrien	15 for %st(4) (gcc regno = 12)
121890284Sobrien	16 for %st(5) (gcc regno = 13)
121990284Sobrien	17 for %st(6) (gcc regno = 14)
122090284Sobrien	18 for %st(7) (gcc regno = 15)
122190284Sobrien*/
122290284Sobrienint const svr4_dbx_register_map[FIRST_PSEUDO_REGISTER] =
122390284Sobrien{
122490284Sobrien  0, 2, 1, 3, 6, 7, 5, 4,		/* general regs */
122590284Sobrien  11, 12, 13, 14, 15, 16, 17, 18,	/* fp regs */
1226237021Spfg  -1, 9, -1, -1, -1,			/* arg, flags, fpsr, dir, frame */
122790284Sobrien  21, 22, 23, 24, 25, 26, 27, 28,	/* SSE registers */
122890284Sobrien  29, 30, 31, 32, 33, 34, 35, 36,	/* MMX registers */
1229132743Skan  -1, -1, -1, -1, -1, -1, -1, -1,	/* extended integer registers */
1230132743Skan  -1, -1, -1, -1, -1, -1, -1, -1,	/* extended SSE registers */
123190284Sobrien};
123290284Sobrien
123318334Speter/* Test and compare insns in i386.md store the information needed to
123418334Speter   generate branch and scc insns here.  */
123518334Speter
123690284Sobrienrtx ix86_compare_op0 = NULL_RTX;
123790284Sobrienrtx ix86_compare_op1 = NULL_RTX;
1238169705Skanrtx ix86_compare_emitted = NULL_RTX;
123918334Speter
124090284Sobrien/* Size of the register save area.  */
124190284Sobrien#define X86_64_VARARGS_SIZE (REGPARM_MAX * UNITS_PER_WORD + SSE_REGPARM_MAX * 16)
124290284Sobrien
124390284Sobrien/* Define the structure for the machine field in struct function.  */
1244132743Skan
1245132743Skanstruct stack_local_entry GTY(())
124690284Sobrien{
1247132743Skan  unsigned short mode;
1248132743Skan  unsigned short n;
1249132743Skan  rtx rtl;
1250132743Skan  struct stack_local_entry *next;
125190284Sobrien};
125290284Sobrien
125390284Sobrien/* Structure describing stack frame layout.
125490284Sobrien   Stack grows downward:
125590284Sobrien
125690284Sobrien   [arguments]
125790284Sobrien					      <- ARG_POINTER
125890284Sobrien   saved pc
125990284Sobrien
126090284Sobrien   saved frame pointer if frame_pointer_needed
126190284Sobrien					      <- HARD_FRAME_POINTER
126290284Sobrien   [saved regs]
126390284Sobrien
126490284Sobrien   [padding1]          \
126590284Sobrien		        )
126690284Sobrien   [va_arg registers]  (
126790284Sobrien		        > to_allocate	      <- FRAME_POINTER
126890284Sobrien   [frame]	       (
126990284Sobrien		        )
127090284Sobrien   [padding2]	       /
127190284Sobrien  */
127290284Sobrienstruct ix86_frame
127390284Sobrien{
127490284Sobrien  int nregs;
127590284Sobrien  int padding1;
127690284Sobrien  int va_arg_size;
127790284Sobrien  HOST_WIDE_INT frame;
127890284Sobrien  int padding2;
127990284Sobrien  int outgoing_arguments_size;
128090284Sobrien  int red_zone_size;
128190284Sobrien
128290284Sobrien  HOST_WIDE_INT to_allocate;
128390284Sobrien  /* The offsets relative to ARG_POINTER.  */
128490284Sobrien  HOST_WIDE_INT frame_pointer_offset;
128590284Sobrien  HOST_WIDE_INT hard_frame_pointer_offset;
128690284Sobrien  HOST_WIDE_INT stack_pointer_offset;
1287132743Skan
1288132743Skan  /* When save_regs_using_mov is set, emit prologue using
1289132743Skan     move instead of push instructions.  */
1290132743Skan  bool save_regs_using_mov;
129190284Sobrien};
129290284Sobrien
1293169705Skan/* Code model option.  */
129490284Sobrienenum cmodel ix86_cmodel;
129590284Sobrien/* Asm dialect.  */
129690284Sobrienenum asm_dialect ix86_asm_dialect = ASM_ATT;
1297169705Skan/* TLS dialects.  */
1298117408Skanenum tls_dialect ix86_tls_dialect = TLS_DIALECT_GNU;
129990284Sobrien
1300117408Skan/* Which unit we are generating floating point math for.  */
130190284Sobrienenum fpmath_unit ix86_fpmath;
130290284Sobrien
1303117408Skan/* Which cpu are we scheduling for.  */
1304132743Skanenum processor_type ix86_tune;
1305117408Skan/* Which instruction set architecture to use.  */
1306117408Skanenum processor_type ix86_arch;
130751411Sobrien
130890284Sobrien/* true if sse prefetch instruction is not NOOP.  */
130990284Sobrienint x86_prefetch_sse;
131018334Speter
1311251212Spfg/* true if cmpxchg16b is supported.  */
1312251212Spfgint x86_cmpxchg16b;
1313251212Spfg
131490284Sobrien/* ix86_regparm_string as a number */
1315169705Skanstatic int ix86_regparm;
131618334Speter
1317169705Skan/* -mstackrealign option */
1318169705Skanextern int ix86_force_align_arg_pointer;
1319169705Skanstatic const char ix86_force_align_arg_pointer_string[] = "force_align_arg_pointer";
132018334Speter
132152294Sobrien/* Preferred alignment for stack boundary in bits.  */
1322169705Skanunsigned int ix86_preferred_stack_boundary;
132352294Sobrien
132451411Sobrien/* Values 1-5: see jump.c */
132590284Sobrienint ix86_branch_cost;
132651411Sobrien
1327169705Skan/* Variables which are this size or smaller are put in the data/bss
1328169705Skan   or ldata/lbss sections.  */
132951411Sobrien
1330169705Skanint ix86_section_threshold = 65536;
1331169705Skan
133290284Sobrien/* Prefix built by ASM_GENERATE_INTERNAL_LABEL.  */
1333169705Skanchar internal_label_prefix[16];
1334169705Skanint internal_label_prefix_len;
133590284Sobrien
1336169705Skanstatic bool ix86_handle_option (size_t, const char *, int);
1337132743Skanstatic void output_pic_addr_const (FILE *, rtx, int);
1338132743Skanstatic void put_condition_code (enum rtx_code, enum machine_mode,
1339132743Skan				int, int, FILE *);
1340132743Skanstatic const char *get_some_local_dynamic_name (void);
1341132743Skanstatic int get_some_local_dynamic_name_1 (rtx *, void *);
1342132743Skanstatic rtx ix86_expand_int_compare (enum rtx_code, rtx, rtx);
1343132743Skanstatic enum rtx_code ix86_prepare_fp_compare_args (enum rtx_code, rtx *,
1344132743Skan						   rtx *);
1345132743Skanstatic bool ix86_fixed_condition_code_regs (unsigned int *, unsigned int *);
1346132743Skanstatic enum machine_mode ix86_cc_modes_compatible (enum machine_mode,
1347132743Skan						   enum machine_mode);
1348132743Skanstatic rtx get_thread_pointer (int);
1349132743Skanstatic rtx legitimize_tls_address (rtx, enum tls_model, int);
1350132743Skanstatic void get_pc_thunk_name (char [32], unsigned int);
1351132743Skanstatic rtx gen_push (rtx);
1352169705Skanstatic int ix86_flags_dependent (rtx, rtx, enum attr_type);
1353169705Skanstatic int ix86_agi_dependent (rtx, rtx, enum attr_type);
1354132743Skanstatic struct machine_function * ix86_init_machine_status (void);
1355132743Skanstatic int ix86_split_to_parts (rtx, rtx *, enum machine_mode);
1356132743Skanstatic int ix86_nsaved_regs (void);
1357132743Skanstatic void ix86_emit_save_regs (void);
1358132743Skanstatic void ix86_emit_save_regs_using_mov (rtx, HOST_WIDE_INT);
1359132743Skanstatic void ix86_emit_restore_regs_using_mov (rtx, HOST_WIDE_INT, int);
1360132743Skanstatic void ix86_output_function_epilogue (FILE *, HOST_WIDE_INT);
1361132743Skanstatic HOST_WIDE_INT ix86_GOT_alias_set (void);
1362132743Skanstatic void ix86_adjust_counter (rtx, HOST_WIDE_INT);
1363132743Skanstatic rtx ix86_expand_aligntest (rtx, int);
1364132743Skanstatic void ix86_expand_strlensi_unroll_1 (rtx, rtx, rtx);
1365132743Skanstatic int ix86_issue_rate (void);
1366132743Skanstatic int ix86_adjust_cost (rtx, rtx, rtx, int);
1367132743Skanstatic int ia32_multipass_dfa_lookahead (void);
1368132743Skanstatic void ix86_init_mmx_sse_builtins (void);
1369132743Skanstatic rtx x86_this_parameter (tree);
1370132743Skanstatic void x86_output_mi_thunk (FILE *, tree, HOST_WIDE_INT,
1371132743Skan				 HOST_WIDE_INT, tree);
1372132743Skanstatic bool x86_can_output_mi_thunk (tree, HOST_WIDE_INT, HOST_WIDE_INT, tree);
1373132743Skanstatic void x86_file_start (void);
1374132743Skanstatic void ix86_reorg (void);
1375132743Skanstatic bool ix86_expand_carry_flag_compare (enum rtx_code, rtx, rtx, rtx*);
1376132743Skanstatic tree ix86_build_builtin_va_list (void);
1377169705Skanstatic void ix86_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode,
1378169705Skan					 tree, int *, int);
1379169705Skanstatic tree ix86_gimplify_va_arg (tree, tree, tree *, tree *);
1380169705Skanstatic bool ix86_scalar_mode_supported_p (enum machine_mode);
1381169705Skanstatic bool ix86_vector_mode_supported_p (enum machine_mode);
138251411Sobrien
1383132743Skanstatic int ix86_address_cost (rtx);
1384132743Skanstatic bool ix86_cannot_force_const_mem (rtx);
1385132743Skanstatic rtx ix86_delegitimize_address (rtx);
138690284Sobrien
1387169705Skanstatic void i386_output_dwarf_dtprel (FILE *, int, rtx) ATTRIBUTE_UNUSED;
1388169705Skan
138990284Sobrienstruct builtin_description;
1390132743Skanstatic rtx ix86_expand_sse_comi (const struct builtin_description *,
1391132743Skan				 tree, rtx);
1392132743Skanstatic rtx ix86_expand_sse_compare (const struct builtin_description *,
1393132743Skan				    tree, rtx);
1394132743Skanstatic rtx ix86_expand_unop1_builtin (enum insn_code, tree, rtx);
1395132743Skanstatic rtx ix86_expand_unop_builtin (enum insn_code, tree, rtx, int);
1396132743Skanstatic rtx ix86_expand_binop_builtin (enum insn_code, tree, rtx);
1397132743Skanstatic rtx ix86_expand_store_builtin (enum insn_code, tree);
1398132743Skanstatic rtx safe_vector_operand (rtx, enum machine_mode);
1399132743Skanstatic rtx ix86_expand_fp_compare (enum rtx_code, rtx, rtx, rtx, rtx *, rtx *);
1400132743Skanstatic int ix86_fp_comparison_arithmetics_cost (enum rtx_code code);
1401132743Skanstatic int ix86_fp_comparison_fcomi_cost (enum rtx_code code);
1402132743Skanstatic int ix86_fp_comparison_sahf_cost (enum rtx_code code);
1403132743Skanstatic int ix86_fp_comparison_cost (enum rtx_code code);
1404132743Skanstatic unsigned int ix86_select_alt_pic_regnum (void);
1405132743Skanstatic int ix86_save_reg (unsigned int, int);
1406132743Skanstatic void ix86_compute_frame_layout (struct ix86_frame *);
1407132743Skanstatic int ix86_comp_type_attributes (tree, tree);
1408132743Skanstatic int ix86_function_regparm (tree, tree);
140990284Sobrienconst struct attribute_spec ix86_attribute_table[];
1410132743Skanstatic bool ix86_function_ok_for_sibcall (tree, tree);
1411169705Skanstatic tree ix86_handle_cconv_attribute (tree *, tree, tree, int, bool *);
1412169705Skanstatic int ix86_value_regno (enum machine_mode, tree, tree);
1413132743Skanstatic bool contains_128bit_aligned_vector_p (tree);
1414169705Skanstatic rtx ix86_struct_value_rtx (tree, int);
1415132743Skanstatic bool ix86_ms_bitfield_layout_p (tree);
1416132743Skanstatic tree ix86_handle_struct_attribute (tree *, tree, tree, int, bool *);
1417132743Skanstatic int extended_reg_mentioned_1 (rtx *, void *);
1418132743Skanstatic bool ix86_rtx_costs (rtx, int, int, int *);
1419132743Skanstatic int min_insn_size (rtx);
1420169705Skanstatic tree ix86_md_asm_clobbers (tree outputs, tree inputs, tree clobbers);
1421169705Skanstatic bool ix86_must_pass_in_stack (enum machine_mode mode, tree type);
1422169705Skanstatic bool ix86_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode,
1423169705Skan				    tree, bool);
1424169705Skanstatic void ix86_init_builtins (void);
1425169705Skanstatic rtx ix86_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
1426169705Skanstatic const char *ix86_mangle_fundamental_type (tree);
1427169705Skanstatic tree ix86_stack_protect_fail (void);
1428169705Skanstatic rtx ix86_internal_arg_pointer (void);
1429169705Skanstatic void ix86_dwarf_handle_frame_unspec (const char *, rtx, int);
143090284Sobrien
1431169705Skan/* This function is only used on Solaris.  */
1432169705Skanstatic void i386_solaris_elf_named_section (const char *, unsigned int, tree)
1433169705Skan  ATTRIBUTE_UNUSED;
143490284Sobrien
143590284Sobrien/* Register class used for passing given 64bit part of the argument.
143690284Sobrien   These represent classes as documented by the PS ABI, with the exception
143790284Sobrien   of SSESF, SSEDF classes, that are basically SSE class, just gcc will
1438132743Skan   use SF or DFmode move instead of DImode to avoid reformatting penalties.
143990284Sobrien
1440132743Skan   Similarly we play games with INTEGERSI_CLASS to use cheaper SImode moves
144190284Sobrien   whenever possible (upper half does contain padding).
144290284Sobrien */
144390284Sobrienenum x86_64_reg_class
144490284Sobrien  {
144590284Sobrien    X86_64_NO_CLASS,
144690284Sobrien    X86_64_INTEGER_CLASS,
144790284Sobrien    X86_64_INTEGERSI_CLASS,
144890284Sobrien    X86_64_SSE_CLASS,
144990284Sobrien    X86_64_SSESF_CLASS,
145090284Sobrien    X86_64_SSEDF_CLASS,
145190284Sobrien    X86_64_SSEUP_CLASS,
145290284Sobrien    X86_64_X87_CLASS,
145390284Sobrien    X86_64_X87UP_CLASS,
1454169705Skan    X86_64_COMPLEX_X87_CLASS,
145590284Sobrien    X86_64_MEMORY_CLASS
145690284Sobrien  };
1457169705Skanstatic const char * const x86_64_reg_class_name[] = {
1458169705Skan  "no", "integer", "integerSI", "sse", "sseSF", "sseDF",
1459169705Skan  "sseup", "x87", "x87up", "cplx87", "no"
1460169705Skan};
146190284Sobrien
146290284Sobrien#define MAX_CLASSES 4
1463132743Skan
1464132743Skan/* Table of constants used by fldpi, fldln2, etc....  */
1465132743Skanstatic REAL_VALUE_TYPE ext_80387_constants_table [5];
1466132743Skanstatic bool ext_80387_constants_init = 0;
1467132743Skanstatic void init_ext_80387_constants (void);
1468169705Skanstatic bool ix86_in_large_data_p (tree) ATTRIBUTE_UNUSED;
1469169705Skanstatic void ix86_encode_section_info (tree, rtx, int) ATTRIBUTE_UNUSED;
1470169705Skanstatic void x86_64_elf_unique_section (tree decl, int reloc) ATTRIBUTE_UNUSED;
1471169705Skanstatic section *x86_64_elf_select_section (tree decl, int reloc,
1472169705Skan					   unsigned HOST_WIDE_INT align)
1473169705Skan					     ATTRIBUTE_UNUSED;
147490284Sobrien
147590284Sobrien/* Initialize the GCC target structure.  */
147690284Sobrien#undef TARGET_ATTRIBUTE_TABLE
147790284Sobrien#define TARGET_ATTRIBUTE_TABLE ix86_attribute_table
1478169705Skan#if TARGET_DLLIMPORT_DECL_ATTRIBUTES
147990284Sobrien#  undef TARGET_MERGE_DECL_ATTRIBUTES
148090284Sobrien#  define TARGET_MERGE_DECL_ATTRIBUTES merge_dllimport_decl_attributes
148190284Sobrien#endif
148290284Sobrien
148390284Sobrien#undef TARGET_COMP_TYPE_ATTRIBUTES
148490284Sobrien#define TARGET_COMP_TYPE_ATTRIBUTES ix86_comp_type_attributes
148590284Sobrien
148690284Sobrien#undef TARGET_INIT_BUILTINS
148790284Sobrien#define TARGET_INIT_BUILTINS ix86_init_builtins
148890284Sobrien#undef TARGET_EXPAND_BUILTIN
148990284Sobrien#define TARGET_EXPAND_BUILTIN ix86_expand_builtin
149090284Sobrien
1491117408Skan#undef TARGET_ASM_FUNCTION_EPILOGUE
1492117408Skan#define TARGET_ASM_FUNCTION_EPILOGUE ix86_output_function_epilogue
149390284Sobrien
1494169705Skan#undef TARGET_ENCODE_SECTION_INFO
1495169705Skan#ifndef SUBTARGET_ENCODE_SECTION_INFO
1496169705Skan#define TARGET_ENCODE_SECTION_INFO ix86_encode_section_info
1497169705Skan#else
1498169705Skan#define TARGET_ENCODE_SECTION_INFO SUBTARGET_ENCODE_SECTION_INFO
1499169705Skan#endif
1500169705Skan
150190284Sobrien#undef TARGET_ASM_OPEN_PAREN
150290284Sobrien#define TARGET_ASM_OPEN_PAREN ""
150390284Sobrien#undef TARGET_ASM_CLOSE_PAREN
150490284Sobrien#define TARGET_ASM_CLOSE_PAREN ""
150590284Sobrien
150690284Sobrien#undef TARGET_ASM_ALIGNED_HI_OP
150790284Sobrien#define TARGET_ASM_ALIGNED_HI_OP ASM_SHORT
150890284Sobrien#undef TARGET_ASM_ALIGNED_SI_OP
150990284Sobrien#define TARGET_ASM_ALIGNED_SI_OP ASM_LONG
151090284Sobrien#ifdef ASM_QUAD
151190284Sobrien#undef TARGET_ASM_ALIGNED_DI_OP
151290284Sobrien#define TARGET_ASM_ALIGNED_DI_OP ASM_QUAD
151390284Sobrien#endif
151490284Sobrien
151590284Sobrien#undef TARGET_ASM_UNALIGNED_HI_OP
151690284Sobrien#define TARGET_ASM_UNALIGNED_HI_OP TARGET_ASM_ALIGNED_HI_OP
151790284Sobrien#undef TARGET_ASM_UNALIGNED_SI_OP
151890284Sobrien#define TARGET_ASM_UNALIGNED_SI_OP TARGET_ASM_ALIGNED_SI_OP
151990284Sobrien#undef TARGET_ASM_UNALIGNED_DI_OP
152090284Sobrien#define TARGET_ASM_UNALIGNED_DI_OP TARGET_ASM_ALIGNED_DI_OP
152190284Sobrien
152290284Sobrien#undef TARGET_SCHED_ADJUST_COST
152390284Sobrien#define TARGET_SCHED_ADJUST_COST ix86_adjust_cost
152490284Sobrien#undef TARGET_SCHED_ISSUE_RATE
152590284Sobrien#define TARGET_SCHED_ISSUE_RATE ix86_issue_rate
1526117408Skan#undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD
1527117408Skan#define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD \
1528117408Skan  ia32_multipass_dfa_lookahead
152990284Sobrien
1530132743Skan#undef TARGET_FUNCTION_OK_FOR_SIBCALL
1531132743Skan#define TARGET_FUNCTION_OK_FOR_SIBCALL ix86_function_ok_for_sibcall
1532132743Skan
1533117408Skan#ifdef HAVE_AS_TLS
1534117408Skan#undef TARGET_HAVE_TLS
1535117408Skan#define TARGET_HAVE_TLS true
1536117408Skan#endif
1537117408Skan#undef TARGET_CANNOT_FORCE_CONST_MEM
1538117408Skan#define TARGET_CANNOT_FORCE_CONST_MEM ix86_cannot_force_const_mem
1539169705Skan#undef TARGET_USE_BLOCKS_FOR_CONSTANT_P
1540169705Skan#define TARGET_USE_BLOCKS_FOR_CONSTANT_P hook_bool_mode_rtx_true
1541117408Skan
1542132743Skan#undef TARGET_DELEGITIMIZE_ADDRESS
1543132743Skan#define TARGET_DELEGITIMIZE_ADDRESS ix86_delegitimize_address
1544132743Skan
1545132743Skan#undef TARGET_MS_BITFIELD_LAYOUT_P
1546132743Skan#define TARGET_MS_BITFIELD_LAYOUT_P ix86_ms_bitfield_layout_p
1547132743Skan
1548169705Skan#if TARGET_MACHO
1549169705Skan#undef TARGET_BINDS_LOCAL_P
1550169705Skan#define TARGET_BINDS_LOCAL_P darwin_binds_local_p
1551169705Skan#endif
1552169705Skan
1553117408Skan#undef TARGET_ASM_OUTPUT_MI_THUNK
1554117408Skan#define TARGET_ASM_OUTPUT_MI_THUNK x86_output_mi_thunk
1555117408Skan#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
1556117408Skan#define TARGET_ASM_CAN_OUTPUT_MI_THUNK x86_can_output_mi_thunk
1557117408Skan
1558132743Skan#undef TARGET_ASM_FILE_START
1559132743Skan#define TARGET_ASM_FILE_START x86_file_start
1560132743Skan
1561169705Skan#undef TARGET_DEFAULT_TARGET_FLAGS
1562169705Skan#define TARGET_DEFAULT_TARGET_FLAGS	\
1563169705Skan  (TARGET_DEFAULT			\
1564169705Skan   | TARGET_64BIT_DEFAULT		\
1565169705Skan   | TARGET_SUBTARGET_DEFAULT		\
1566169705Skan   | TARGET_TLS_DIRECT_SEG_REFS_DEFAULT)
1567169705Skan
1568169705Skan#undef TARGET_HANDLE_OPTION
1569169705Skan#define TARGET_HANDLE_OPTION ix86_handle_option
1570169705Skan
1571132743Skan#undef TARGET_RTX_COSTS
1572132743Skan#define TARGET_RTX_COSTS ix86_rtx_costs
1573132743Skan#undef TARGET_ADDRESS_COST
1574132743Skan#define TARGET_ADDRESS_COST ix86_address_cost
1575132743Skan
1576132743Skan#undef TARGET_FIXED_CONDITION_CODE_REGS
1577132743Skan#define TARGET_FIXED_CONDITION_CODE_REGS ix86_fixed_condition_code_regs
1578132743Skan#undef TARGET_CC_MODES_COMPATIBLE
1579132743Skan#define TARGET_CC_MODES_COMPATIBLE ix86_cc_modes_compatible
1580132743Skan
1581132743Skan#undef TARGET_MACHINE_DEPENDENT_REORG
1582132743Skan#define TARGET_MACHINE_DEPENDENT_REORG ix86_reorg
1583132743Skan
1584132743Skan#undef TARGET_BUILD_BUILTIN_VA_LIST
1585132743Skan#define TARGET_BUILD_BUILTIN_VA_LIST ix86_build_builtin_va_list
1586132743Skan
1587169705Skan#undef TARGET_MD_ASM_CLOBBERS
1588169705Skan#define TARGET_MD_ASM_CLOBBERS ix86_md_asm_clobbers
1589169705Skan
1590169705Skan#undef TARGET_PROMOTE_PROTOTYPES
1591169705Skan#define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_true
1592169705Skan#undef TARGET_STRUCT_VALUE_RTX
1593169705Skan#define TARGET_STRUCT_VALUE_RTX ix86_struct_value_rtx
1594169705Skan#undef TARGET_SETUP_INCOMING_VARARGS
1595169705Skan#define TARGET_SETUP_INCOMING_VARARGS ix86_setup_incoming_varargs
1596169705Skan#undef TARGET_MUST_PASS_IN_STACK
1597169705Skan#define TARGET_MUST_PASS_IN_STACK ix86_must_pass_in_stack
1598169705Skan#undef TARGET_PASS_BY_REFERENCE
1599169705Skan#define TARGET_PASS_BY_REFERENCE ix86_pass_by_reference
1600169705Skan#undef TARGET_INTERNAL_ARG_POINTER
1601169705Skan#define TARGET_INTERNAL_ARG_POINTER ix86_internal_arg_pointer
1602169705Skan#undef TARGET_DWARF_HANDLE_FRAME_UNSPEC
1603169705Skan#define TARGET_DWARF_HANDLE_FRAME_UNSPEC ix86_dwarf_handle_frame_unspec
1604169705Skan
1605169705Skan#undef TARGET_GIMPLIFY_VA_ARG_EXPR
1606169705Skan#define TARGET_GIMPLIFY_VA_ARG_EXPR ix86_gimplify_va_arg
1607169705Skan
1608169705Skan#undef TARGET_SCALAR_MODE_SUPPORTED_P
1609169705Skan#define TARGET_SCALAR_MODE_SUPPORTED_P ix86_scalar_mode_supported_p
1610169705Skan
1611169705Skan#undef TARGET_VECTOR_MODE_SUPPORTED_P
1612169705Skan#define TARGET_VECTOR_MODE_SUPPORTED_P ix86_vector_mode_supported_p
1613169705Skan
1614169705Skan#ifdef HAVE_AS_TLS
1615169705Skan#undef TARGET_ASM_OUTPUT_DWARF_DTPREL
1616169705Skan#define TARGET_ASM_OUTPUT_DWARF_DTPREL i386_output_dwarf_dtprel
1617169705Skan#endif
1618169705Skan
1619169705Skan#ifdef SUBTARGET_INSERT_ATTRIBUTES
1620169705Skan#undef TARGET_INSERT_ATTRIBUTES
1621169705Skan#define TARGET_INSERT_ATTRIBUTES SUBTARGET_INSERT_ATTRIBUTES
1622169705Skan#endif
1623169705Skan
1624169705Skan#undef TARGET_MANGLE_FUNDAMENTAL_TYPE
1625169705Skan#define TARGET_MANGLE_FUNDAMENTAL_TYPE ix86_mangle_fundamental_type
1626169705Skan
1627169705Skan#undef TARGET_STACK_PROTECT_FAIL
1628169705Skan#define TARGET_STACK_PROTECT_FAIL ix86_stack_protect_fail
1629169705Skan
1630169705Skan#undef TARGET_FUNCTION_VALUE
1631169705Skan#define TARGET_FUNCTION_VALUE ix86_function_value
1632169705Skan
163390284Sobrienstruct gcc_target targetm = TARGET_INITIALIZER;
1634169705Skan
163590284Sobrien
1636117408Skan/* The svr4 ABI for the i386 says that records and unions are returned
1637117408Skan   in memory.  */
1638117408Skan#ifndef DEFAULT_PCC_STRUCT_RETURN
1639117408Skan#define DEFAULT_PCC_STRUCT_RETURN 1
1640117408Skan#endif
1641117408Skan
1642169705Skan/* Implement TARGET_HANDLE_OPTION.  */
1643169705Skan
1644169705Skanstatic bool
1645169705Skanix86_handle_option (size_t code, const char *arg ATTRIBUTE_UNUSED, int value)
1646169705Skan{
1647169705Skan  switch (code)
1648169705Skan    {
1649169705Skan    case OPT_m3dnow:
1650169705Skan      if (!value)
1651169705Skan	{
1652169705Skan	  target_flags &= ~MASK_3DNOW_A;
1653169705Skan	  target_flags_explicit |= MASK_3DNOW_A;
1654169705Skan	}
1655169705Skan      return true;
1656169705Skan
1657169705Skan    case OPT_mmmx:
1658169705Skan      if (!value)
1659169705Skan	{
1660169705Skan	  target_flags &= ~(MASK_3DNOW | MASK_3DNOW_A);
1661169705Skan	  target_flags_explicit |= MASK_3DNOW | MASK_3DNOW_A;
1662169705Skan	}
1663169705Skan      return true;
1664169705Skan
1665169705Skan    case OPT_msse:
1666169705Skan      if (!value)
1667169705Skan	{
1668251212Spfg	  target_flags &= ~(MASK_SSE2 | MASK_SSE3 | MASK_SSSE3 | MASK_SSE4A);
1669251212Spfg	  target_flags_explicit |= MASK_SSE2 | MASK_SSE3 | MASK_SSSE3 | MASK_SSE4A;
1670169705Skan	}
1671169705Skan      return true;
1672169705Skan
1673169705Skan    case OPT_msse2:
1674169705Skan      if (!value)
1675169705Skan	{
1676251212Spfg	  target_flags &= ~(MASK_SSE3 | MASK_SSSE3 | MASK_SSE4A);
1677251212Spfg	  target_flags_explicit |= MASK_SSE3 | MASK_SSSE3 | MASK_SSE4A;
1678169705Skan	}
1679169705Skan      return true;
1680169705Skan
1681219639Smm    case OPT_msse3:
1682219639Smm      if (!value)
1683219639Smm	{
1684251212Spfg	  target_flags &= ~(MASK_SSSE3 | MASK_SSE4A);
1685251212Spfg	  target_flags_explicit |= MASK_SSSE3 | MASK_SSE4A;
1686219639Smm	}
1687219639Smm      return true;
1688219639Smm
1689255185Sjmg    case OPT_maes:
1690255185Sjmg      if (!value)
1691255185Sjmg	{
1692255185Sjmg	  target_flags &= ~MASK_AES;
1693255185Sjmg	  target_flags_explicit |= MASK_AES;
1694255185Sjmg	}
1695255185Sjmg      return true;
1696255185Sjmg
1697169705Skan    default:
1698169705Skan      return true;
1699169705Skan    }
1700169705Skan}
1701169705Skan
170218334Speter/* Sometimes certain combinations of command options do not make
170318334Speter   sense on a particular target machine.  You can define a macro
170418334Speter   `OVERRIDE_OPTIONS' to take account of this.  This macro, if
170518334Speter   defined, is executed once just after all the command options have
170618334Speter   been parsed.
170718334Speter
170818334Speter   Don't use this macro to turn on various extra optimizations for
170918334Speter   `-O'.  That is what `OPTIMIZATION_OPTIONS' is for.  */
171018334Speter
171118334Spetervoid
1712132743Skanoverride_options (void)
171318334Speter{
171490284Sobrien  int i;
1715169705Skan  int ix86_tune_defaulted = 0;
1716169705Skan
171790284Sobrien  /* Comes from final.c -- no real reason to change it.  */
171890284Sobrien#define MAX_CODE_ALIGN 16
171918334Speter
172051411Sobrien  static struct ptt
172151411Sobrien    {
172290284Sobrien      const struct processor_costs *cost;	/* Processor costs */
172390284Sobrien      const int target_enable;			/* Target flags to enable.  */
172490284Sobrien      const int target_disable;			/* Target flags to disable.  */
172590284Sobrien      const int align_loop;			/* Default alignments.  */
172690284Sobrien      const int align_loop_max_skip;
172790284Sobrien      const int align_jump;
172890284Sobrien      const int align_jump_max_skip;
172990284Sobrien      const int align_func;
173090284Sobrien    }
173190284Sobrien  const processor_target_table[PROCESSOR_max] =
173290284Sobrien    {
1733132743Skan      {&i386_cost, 0, 0, 4, 3, 4, 3, 4},
1734132743Skan      {&i486_cost, 0, 0, 16, 15, 16, 15, 16},
1735132743Skan      {&pentium_cost, 0, 0, 16, 7, 16, 7, 16},
1736132743Skan      {&pentiumpro_cost, 0, 0, 16, 15, 16, 7, 16},
1737219374Smm      {&geode_cost, 0, 0, 0, 0, 0, 0, 0},
1738132743Skan      {&k6_cost, 0, 0, 32, 7, 32, 7, 32},
1739132743Skan      {&athlon_cost, 0, 0, 16, 7, 16, 7, 16},
1740132743Skan      {&pentium4_cost, 0, 0, 0, 0, 0, 0, 0},
1741169705Skan      {&k8_cost, 0, 0, 16, 7, 16, 7, 16},
1742169705Skan      {&nocona_cost, 0, 0, 0, 0, 0, 0, 0},
1743219374Smm      {&core2_cost, 0, 0, 16, 7, 16, 7, 16},
1744169705Skan      {&generic32_cost, 0, 0, 16, 7, 16, 7, 16},
1745251212Spfg      {&generic64_cost, 0, 0, 16, 7, 16, 7, 16},
1746251212Spfg      {&amdfam10_cost, 0, 0, 32, 24, 32, 7, 32}
174752294Sobrien    };
174851411Sobrien
174990284Sobrien  static const char * const cpu_names[] = TARGET_CPU_DEFAULT_NAMES;
175090284Sobrien  static struct pta
175190284Sobrien    {
175290284Sobrien      const char *const name;		/* processor name or nickname.  */
175390284Sobrien      const enum processor_type processor;
175490284Sobrien      const enum pta_flags
175590284Sobrien	{
175690284Sobrien	  PTA_SSE = 1,
175790284Sobrien	  PTA_SSE2 = 2,
1758132743Skan	  PTA_SSE3 = 4,
1759132743Skan	  PTA_MMX = 8,
1760132743Skan	  PTA_PREFETCH_SSE = 16,
1761132743Skan	  PTA_3DNOW = 32,
1762132743Skan	  PTA_3DNOW_A = 64,
1763219639Smm	  PTA_64BIT = 128,
1764251212Spfg	  PTA_SSSE3 = 256,
1765251212Spfg	  PTA_CX16 = 512,
1766251212Spfg	  PTA_POPCNT = 1024,
1767251212Spfg	  PTA_ABM = 2048,
1768251212Spfg 	  PTA_SSE4A = 4096
176990284Sobrien	} flags;
177090284Sobrien    }
177190284Sobrien  const processor_alias_table[] =
177290284Sobrien    {
177390284Sobrien      {"i386", PROCESSOR_I386, 0},
177490284Sobrien      {"i486", PROCESSOR_I486, 0},
177590284Sobrien      {"i586", PROCESSOR_PENTIUM, 0},
177690284Sobrien      {"pentium", PROCESSOR_PENTIUM, 0},
177790284Sobrien      {"pentium-mmx", PROCESSOR_PENTIUM, PTA_MMX},
1778117408Skan      {"winchip-c6", PROCESSOR_I486, PTA_MMX},
1779117408Skan      {"winchip2", PROCESSOR_I486, PTA_MMX | PTA_3DNOW},
1780117408Skan      {"c3", PROCESSOR_I486, PTA_MMX | PTA_3DNOW},
1781132743Skan      {"c3-2", PROCESSOR_PENTIUMPRO, PTA_MMX | PTA_PREFETCH_SSE | PTA_SSE},
178290284Sobrien      {"i686", PROCESSOR_PENTIUMPRO, 0},
178390284Sobrien      {"pentiumpro", PROCESSOR_PENTIUMPRO, 0},
178490284Sobrien      {"pentium2", PROCESSOR_PENTIUMPRO, PTA_MMX},
178590284Sobrien      {"pentium3", PROCESSOR_PENTIUMPRO, PTA_MMX | PTA_SSE | PTA_PREFETCH_SSE},
1786132743Skan      {"pentium3m", PROCESSOR_PENTIUMPRO, PTA_MMX | PTA_SSE | PTA_PREFETCH_SSE},
1787132743Skan      {"pentium-m", PROCESSOR_PENTIUMPRO, PTA_MMX | PTA_SSE | PTA_PREFETCH_SSE | PTA_SSE2},
1788132743Skan      {"pentium4", PROCESSOR_PENTIUM4, PTA_SSE | PTA_SSE2
1789132743Skan				       | PTA_MMX | PTA_PREFETCH_SSE},
1790132743Skan      {"pentium4m", PROCESSOR_PENTIUM4, PTA_SSE | PTA_SSE2
1791132743Skan				        | PTA_MMX | PTA_PREFETCH_SSE},
1792169705Skan      {"prescott", PROCESSOR_NOCONA, PTA_SSE | PTA_SSE2 | PTA_SSE3
1793132743Skan				        | PTA_MMX | PTA_PREFETCH_SSE},
1794169705Skan      {"nocona", PROCESSOR_NOCONA, PTA_SSE | PTA_SSE2 | PTA_SSE3 | PTA_64BIT
1795251212Spfg					| PTA_MMX | PTA_PREFETCH_SSE | PTA_CX16},
1796219639Smm      {"core2", PROCESSOR_CORE2, PTA_SSE | PTA_SSE2 | PTA_SSE3 | PTA_SSSE3
1797219374Smm                                        | PTA_64BIT | PTA_MMX
1798251212Spfg					| PTA_PREFETCH_SSE | PTA_CX16},
1799219374Smm      {"geode", PROCESSOR_GEODE, PTA_MMX | PTA_PREFETCH_SSE | PTA_3DNOW
1800219374Smm				   | PTA_3DNOW_A},
180190284Sobrien      {"k6", PROCESSOR_K6, PTA_MMX},
180290284Sobrien      {"k6-2", PROCESSOR_K6, PTA_MMX | PTA_3DNOW},
180390284Sobrien      {"k6-3", PROCESSOR_K6, PTA_MMX | PTA_3DNOW},
180490284Sobrien      {"athlon", PROCESSOR_ATHLON, PTA_MMX | PTA_PREFETCH_SSE | PTA_3DNOW
180590284Sobrien				   | PTA_3DNOW_A},
180690284Sobrien      {"athlon-tbird", PROCESSOR_ATHLON, PTA_MMX | PTA_PREFETCH_SSE
180790284Sobrien					 | PTA_3DNOW | PTA_3DNOW_A},
180890284Sobrien      {"athlon-4", PROCESSOR_ATHLON, PTA_MMX | PTA_PREFETCH_SSE | PTA_3DNOW
180990284Sobrien				    | PTA_3DNOW_A | PTA_SSE},
181090284Sobrien      {"athlon-xp", PROCESSOR_ATHLON, PTA_MMX | PTA_PREFETCH_SSE | PTA_3DNOW
181190284Sobrien				      | PTA_3DNOW_A | PTA_SSE},
181290284Sobrien      {"athlon-mp", PROCESSOR_ATHLON, PTA_MMX | PTA_PREFETCH_SSE | PTA_3DNOW
181390284Sobrien				      | PTA_3DNOW_A | PTA_SSE},
1814132743Skan      {"x86-64", PROCESSOR_K8, PTA_MMX | PTA_PREFETCH_SSE | PTA_64BIT
1815132743Skan			       | PTA_SSE | PTA_SSE2 },
1816132743Skan      {"k8", PROCESSOR_K8, PTA_MMX | PTA_PREFETCH_SSE | PTA_3DNOW | PTA_64BIT
1817132743Skan				      | PTA_3DNOW_A | PTA_SSE | PTA_SSE2},
1818218895Smm      {"k8-sse3", PROCESSOR_K8, PTA_MMX | PTA_PREFETCH_SSE | PTA_3DNOW | PTA_64BIT
1819218895Smm				      | PTA_3DNOW_A | PTA_SSE | PTA_SSE2
1820218895Smm				      | PTA_SSE3 },
1821132743Skan      {"opteron", PROCESSOR_K8, PTA_MMX | PTA_PREFETCH_SSE | PTA_3DNOW | PTA_64BIT
1822132743Skan				      | PTA_3DNOW_A | PTA_SSE | PTA_SSE2},
1823218895Smm      {"opteron-sse3", PROCESSOR_K8, PTA_MMX | PTA_PREFETCH_SSE | PTA_3DNOW | PTA_64BIT
1824218895Smm				      | PTA_3DNOW_A | PTA_SSE | PTA_SSE2
1825218895Smm				      | PTA_SSE3 },
1826132743Skan      {"athlon64", PROCESSOR_K8, PTA_MMX | PTA_PREFETCH_SSE | PTA_3DNOW | PTA_64BIT
1827132743Skan				      | PTA_3DNOW_A | PTA_SSE | PTA_SSE2},
1828218895Smm      {"athlon64-sse3", PROCESSOR_K8, PTA_MMX | PTA_PREFETCH_SSE | PTA_3DNOW | PTA_64BIT
1829218895Smm				      | PTA_3DNOW_A | PTA_SSE | PTA_SSE2
1830218895Smm				      | PTA_SSE3 },
1831132743Skan      {"athlon-fx", PROCESSOR_K8, PTA_MMX | PTA_PREFETCH_SSE | PTA_3DNOW | PTA_64BIT
1832132743Skan				      | PTA_3DNOW_A | PTA_SSE | PTA_SSE2},
1833251212Spfg      {"amdfam10", PROCESSOR_AMDFAM10, PTA_MMX | PTA_PREFETCH_SSE | PTA_3DNOW
1834251212Spfg                                       | PTA_64BIT | PTA_3DNOW_A | PTA_SSE
1835251212Spfg                                       | PTA_SSE2 | PTA_SSE3 | PTA_POPCNT
1836251212Spfg                                       | PTA_ABM | PTA_SSE4A | PTA_CX16},
1837251212Spfg      {"barcelona", PROCESSOR_AMDFAM10, PTA_MMX | PTA_PREFETCH_SSE | PTA_3DNOW
1838251212Spfg                                       | PTA_64BIT | PTA_3DNOW_A | PTA_SSE
1839251212Spfg                                       | PTA_SSE2 | PTA_SSE3 | PTA_POPCNT
1840251212Spfg                                       | PTA_ABM | PTA_SSE4A | PTA_CX16},
1841169705Skan      {"generic32", PROCESSOR_GENERIC32, 0 /* flags are only used for -march switch.  */ },
1842169705Skan      {"generic64", PROCESSOR_GENERIC64, PTA_64BIT /* flags are only used for -march switch.  */ },
184390284Sobrien    };
184451411Sobrien
1845117408Skan  int const pta_size = ARRAY_SIZE (processor_alias_table);
184690284Sobrien
1847169705Skan#ifdef SUBTARGET_OVERRIDE_OPTIONS
1848169705Skan  SUBTARGET_OVERRIDE_OPTIONS;
1849169705Skan#endif
1850169705Skan
1851169705Skan#ifdef SUBSUBTARGET_OVERRIDE_OPTIONS
1852169705Skan  SUBSUBTARGET_OVERRIDE_OPTIONS;
1853169705Skan#endif
1854169705Skan
1855169705Skan  /* -fPIC is the default for x86_64.  */
1856169705Skan  if (TARGET_MACHO && TARGET_64BIT)
1857169705Skan    flag_pic = 2;
1858169705Skan
1859107597Sobrien  /* Set the default values for switches whose default depends on TARGET_64BIT
1860132743Skan     in case they weren't overwritten by command line options.  */
1861107597Sobrien  if (TARGET_64BIT)
1862107597Sobrien    {
1863169705Skan      /* Mach-O doesn't support omitting the frame pointer for now.  */
1864107597Sobrien      if (flag_omit_frame_pointer == 2)
1865169705Skan	flag_omit_frame_pointer = (TARGET_MACHO ? 0 : 1);
1866107597Sobrien      if (flag_asynchronous_unwind_tables == 2)
1867107597Sobrien	flag_asynchronous_unwind_tables = 1;
1868107597Sobrien      if (flag_pcc_struct_return == 2)
1869107597Sobrien	flag_pcc_struct_return = 0;
1870107597Sobrien    }
1871107597Sobrien  else
1872107597Sobrien    {
1873107597Sobrien      if (flag_omit_frame_pointer == 2)
1874107597Sobrien	flag_omit_frame_pointer = 0;
1875107597Sobrien      if (flag_asynchronous_unwind_tables == 2)
1876107597Sobrien	flag_asynchronous_unwind_tables = 0;
1877107597Sobrien      if (flag_pcc_struct_return == 2)
1878110628Skan	flag_pcc_struct_return = DEFAULT_PCC_STRUCT_RETURN;
1879107597Sobrien    }
1880107597Sobrien
1881169705Skan  /* Need to check -mtune=generic first.  */
1882169705Skan  if (ix86_tune_string)
1883169705Skan    {
1884169705Skan      if (!strcmp (ix86_tune_string, "generic")
1885169705Skan	  || !strcmp (ix86_tune_string, "i686")
1886169705Skan	  /* As special support for cross compilers we read -mtune=native
1887169705Skan	     as -mtune=generic.  With native compilers we won't see the
1888169705Skan	     -mtune=native, as it was changed by the driver.  */
1889169705Skan	  || !strcmp (ix86_tune_string, "native"))
1890169705Skan	{
1891169705Skan	  if (TARGET_64BIT)
1892169705Skan	    ix86_tune_string = "generic64";
1893169705Skan	  else
1894169705Skan	    ix86_tune_string = "generic32";
1895169705Skan	}
1896169705Skan      else if (!strncmp (ix86_tune_string, "generic", 7))
1897169705Skan	error ("bad value (%s) for -mtune= switch", ix86_tune_string);
1898169705Skan    }
1899169705Skan  else
1900169705Skan    {
1901169705Skan      if (ix86_arch_string)
1902169705Skan	ix86_tune_string = ix86_arch_string;
1903169705Skan      if (!ix86_tune_string)
1904169705Skan	{
1905169705Skan	  ix86_tune_string = cpu_names [TARGET_CPU_DEFAULT];
1906169705Skan	  ix86_tune_defaulted = 1;
1907169705Skan	}
190818334Speter
1909169705Skan      /* ix86_tune_string is set to ix86_arch_string or defaulted.  We
1910169705Skan	 need to use a sensible tune option.  */
1911169705Skan      if (!strcmp (ix86_tune_string, "generic")
1912169705Skan	  || !strcmp (ix86_tune_string, "x86-64")
1913169705Skan	  || !strcmp (ix86_tune_string, "i686"))
1914169705Skan	{
1915169705Skan	  if (TARGET_64BIT)
1916169705Skan	    ix86_tune_string = "generic64";
1917169705Skan	  else
1918169705Skan	    ix86_tune_string = "generic32";
1919169705Skan	}
1920169705Skan    }
1921169705Skan  if (!strcmp (ix86_tune_string, "x86-64"))
1922169705Skan    warning (OPT_Wdeprecated, "-mtune=x86-64 is deprecated.  Use -mtune=k8 or "
1923169705Skan	     "-mtune=generic instead as appropriate.");
1924169705Skan
192590284Sobrien  if (!ix86_arch_string)
1926198344Sjhb    ix86_arch_string = TARGET_64BIT ? "x86-64" : "i486";
1927169705Skan  if (!strcmp (ix86_arch_string, "generic"))
1928169705Skan    error ("generic CPU can be used only for -mtune= switch");
1929169705Skan  if (!strncmp (ix86_arch_string, "generic", 7))
1930169705Skan    error ("bad value (%s) for -march= switch", ix86_arch_string);
193190284Sobrien
193290284Sobrien  if (ix86_cmodel_string != 0)
193318334Speter    {
193490284Sobrien      if (!strcmp (ix86_cmodel_string, "small"))
193590284Sobrien	ix86_cmodel = flag_pic ? CM_SMALL_PIC : CM_SMALL;
1936169705Skan      else if (!strcmp (ix86_cmodel_string, "medium"))
1937169705Skan	ix86_cmodel = flag_pic ? CM_MEDIUM_PIC : CM_MEDIUM;
193890284Sobrien      else if (flag_pic)
193990284Sobrien	sorry ("code model %s not supported in PIC mode", ix86_cmodel_string);
194090284Sobrien      else if (!strcmp (ix86_cmodel_string, "32"))
194190284Sobrien	ix86_cmodel = CM_32;
194290284Sobrien      else if (!strcmp (ix86_cmodel_string, "kernel") && !flag_pic)
194390284Sobrien	ix86_cmodel = CM_KERNEL;
194490284Sobrien      else if (!strcmp (ix86_cmodel_string, "large") && !flag_pic)
194590284Sobrien	ix86_cmodel = CM_LARGE;
194690284Sobrien      else
194790284Sobrien	error ("bad value (%s) for -mcmodel= switch", ix86_cmodel_string);
194818334Speter    }
194990284Sobrien  else
195051411Sobrien    {
195190284Sobrien      ix86_cmodel = CM_32;
195290284Sobrien      if (TARGET_64BIT)
195390284Sobrien	ix86_cmodel = flag_pic ? CM_SMALL_PIC : CM_SMALL;
195451411Sobrien    }
195590284Sobrien  if (ix86_asm_string != 0)
195690284Sobrien    {
1957169705Skan      if (! TARGET_MACHO
1958169705Skan	  && !strcmp (ix86_asm_string, "intel"))
195990284Sobrien	ix86_asm_dialect = ASM_INTEL;
196090284Sobrien      else if (!strcmp (ix86_asm_string, "att"))
196190284Sobrien	ix86_asm_dialect = ASM_ATT;
196290284Sobrien      else
196390284Sobrien	error ("bad value (%s) for -masm= switch", ix86_asm_string);
196490284Sobrien    }
196590284Sobrien  if ((TARGET_64BIT == 0) != (ix86_cmodel == CM_32))
1966169705Skan    error ("code model %qs not supported in the %s bit mode",
196790284Sobrien	   ix86_cmodel_string, TARGET_64BIT ? "64" : "32");
196890284Sobrien  if (ix86_cmodel == CM_LARGE)
1969169705Skan    sorry ("code model %<large%> not supported yet");
197090284Sobrien  if ((TARGET_64BIT != 0) != ((target_flags & MASK_64BIT) != 0))
197190284Sobrien    sorry ("%i-bit mode not compiled in",
197290284Sobrien	   (target_flags & MASK_64BIT) ? 64 : 32);
197351411Sobrien
197490284Sobrien  for (i = 0; i < pta_size; i++)
197590284Sobrien    if (! strcmp (ix86_arch_string, processor_alias_table[i].name))
197651411Sobrien      {
197790284Sobrien	ix86_arch = processor_alias_table[i].processor;
197890284Sobrien	/* Default cpu tuning to the architecture.  */
1979132743Skan	ix86_tune = ix86_arch;
198090284Sobrien	if (processor_alias_table[i].flags & PTA_MMX
1981117408Skan	    && !(target_flags_explicit & MASK_MMX))
198290284Sobrien	  target_flags |= MASK_MMX;
198390284Sobrien	if (processor_alias_table[i].flags & PTA_3DNOW
1984117408Skan	    && !(target_flags_explicit & MASK_3DNOW))
198590284Sobrien	  target_flags |= MASK_3DNOW;
198690284Sobrien	if (processor_alias_table[i].flags & PTA_3DNOW_A
1987117408Skan	    && !(target_flags_explicit & MASK_3DNOW_A))
198890284Sobrien	  target_flags |= MASK_3DNOW_A;
198990284Sobrien	if (processor_alias_table[i].flags & PTA_SSE
1990117408Skan	    && !(target_flags_explicit & MASK_SSE))
199190284Sobrien	  target_flags |= MASK_SSE;
199290284Sobrien	if (processor_alias_table[i].flags & PTA_SSE2
1993117408Skan	    && !(target_flags_explicit & MASK_SSE2))
199490284Sobrien	  target_flags |= MASK_SSE2;
1995132743Skan	if (processor_alias_table[i].flags & PTA_SSE3
1996132743Skan	    && !(target_flags_explicit & MASK_SSE3))
1997132743Skan	  target_flags |= MASK_SSE3;
1998219639Smm	if (processor_alias_table[i].flags & PTA_SSSE3
1999219639Smm	    && !(target_flags_explicit & MASK_SSSE3))
2000219639Smm	  target_flags |= MASK_SSSE3;
200190284Sobrien	if (processor_alias_table[i].flags & PTA_PREFETCH_SSE)
200290284Sobrien	  x86_prefetch_sse = true;
2003251212Spfg	if (processor_alias_table[i].flags & PTA_CX16)
2004251212Spfg	  x86_cmpxchg16b = true;
2005251212Spfg	if (processor_alias_table[i].flags & PTA_POPCNT
2006251212Spfg	    && !(target_flags_explicit & MASK_POPCNT))
2007251212Spfg	  target_flags |= MASK_POPCNT;
2008251212Spfg	if (processor_alias_table[i].flags & PTA_ABM
2009251212Spfg	    && !(target_flags_explicit & MASK_ABM))
2010251212Spfg	  target_flags |= MASK_ABM;
2011251212Spfg	if (processor_alias_table[i].flags & PTA_SSE4A
2012251212Spfg	    && !(target_flags_explicit & MASK_SSE4A))
2013251212Spfg	  target_flags |= MASK_SSE4A;
2014132743Skan	if (TARGET_64BIT && !(processor_alias_table[i].flags & PTA_64BIT))
2015169705Skan	  error ("CPU you selected does not support x86-64 "
2016169705Skan		 "instruction set");
201751411Sobrien	break;
201851411Sobrien      }
201951411Sobrien
202090284Sobrien  if (i == pta_size)
202190284Sobrien    error ("bad value (%s) for -march= switch", ix86_arch_string);
202251411Sobrien
202390284Sobrien  for (i = 0; i < pta_size; i++)
2024132743Skan    if (! strcmp (ix86_tune_string, processor_alias_table[i].name))
202551411Sobrien      {
2026132743Skan	ix86_tune = processor_alias_table[i].processor;
2027132743Skan	if (TARGET_64BIT && !(processor_alias_table[i].flags & PTA_64BIT))
2028169705Skan	  {
2029169705Skan	    if (ix86_tune_defaulted)
2030169705Skan	      {
2031169705Skan		ix86_tune_string = "x86-64";
2032169705Skan		for (i = 0; i < pta_size; i++)
2033169705Skan		  if (! strcmp (ix86_tune_string,
2034169705Skan				processor_alias_table[i].name))
2035169705Skan		    break;
2036169705Skan		ix86_tune = processor_alias_table[i].processor;
2037169705Skan	      }
2038169705Skan	    else
2039169705Skan	      error ("CPU you selected does not support x86-64 "
2040169705Skan		     "instruction set");
2041169705Skan	  }
2042169705Skan        /* Intel CPUs have always interpreted SSE prefetch instructions as
2043132743Skan	   NOPs; so, we can enable SSE prefetch instructions even when
2044132743Skan	   -mtune (rather than -march) points us to a processor that has them.
2045132743Skan	   However, the VIA C3 gives a SIGILL, so we only do that for i686 and
2046132743Skan	   higher processors.  */
2047132743Skan	if (TARGET_CMOVE && (processor_alias_table[i].flags & PTA_PREFETCH_SSE))
2048132743Skan	  x86_prefetch_sse = true;
204951411Sobrien	break;
205051411Sobrien      }
205190284Sobrien  if (i == pta_size)
2052132743Skan    error ("bad value (%s) for -mtune= switch", ix86_tune_string);
205351411Sobrien
205490284Sobrien  if (optimize_size)
205590284Sobrien    ix86_cost = &size_cost;
205690284Sobrien  else
2057132743Skan    ix86_cost = processor_target_table[ix86_tune].cost;
2058132743Skan  target_flags |= processor_target_table[ix86_tune].target_enable;
2059132743Skan  target_flags &= ~processor_target_table[ix86_tune].target_disable;
206090284Sobrien
206190284Sobrien  /* Arrange to set up i386_stack_locals for all functions.  */
206290284Sobrien  init_machine_status = ix86_init_machine_status;
206390284Sobrien
206490284Sobrien  /* Validate -mregparm= value.  */
206590284Sobrien  if (ix86_regparm_string)
206651411Sobrien    {
206790284Sobrien      i = atoi (ix86_regparm_string);
206890284Sobrien      if (i < 0 || i > REGPARM_MAX)
206990284Sobrien	error ("-mregparm=%d is not between 0 and %d", i, REGPARM_MAX);
207090284Sobrien      else
207190284Sobrien	ix86_regparm = i;
207251411Sobrien    }
207390284Sobrien  else
207490284Sobrien   if (TARGET_64BIT)
207590284Sobrien     ix86_regparm = REGPARM_MAX;
207651411Sobrien
207790284Sobrien  /* If the user has provided any of the -malign-* options,
207890284Sobrien     warn and use that value only if -falign-* is not set.
207990284Sobrien     Remove this code in GCC 3.2 or later.  */
208090284Sobrien  if (ix86_align_loops_string)
208118334Speter    {
2082169705Skan      warning (0, "-malign-loops is obsolete, use -falign-loops");
208390284Sobrien      if (align_loops == 0)
208490284Sobrien	{
208590284Sobrien	  i = atoi (ix86_align_loops_string);
208690284Sobrien	  if (i < 0 || i > MAX_CODE_ALIGN)
208790284Sobrien	    error ("-malign-loops=%d is not between 0 and %d", i, MAX_CODE_ALIGN);
208890284Sobrien	  else
208990284Sobrien	    align_loops = 1 << i;
209090284Sobrien	}
209118334Speter    }
209218334Speter
209390284Sobrien  if (ix86_align_jumps_string)
209418334Speter    {
2095169705Skan      warning (0, "-malign-jumps is obsolete, use -falign-jumps");
209690284Sobrien      if (align_jumps == 0)
209790284Sobrien	{
209890284Sobrien	  i = atoi (ix86_align_jumps_string);
209990284Sobrien	  if (i < 0 || i > MAX_CODE_ALIGN)
210090284Sobrien	    error ("-malign-loops=%d is not between 0 and %d", i, MAX_CODE_ALIGN);
210190284Sobrien	  else
210290284Sobrien	    align_jumps = 1 << i;
210390284Sobrien	}
210418334Speter    }
210552294Sobrien
210690284Sobrien  if (ix86_align_funcs_string)
210718334Speter    {
2108169705Skan      warning (0, "-malign-functions is obsolete, use -falign-functions");
210990284Sobrien      if (align_functions == 0)
211090284Sobrien	{
211190284Sobrien	  i = atoi (ix86_align_funcs_string);
211290284Sobrien	  if (i < 0 || i > MAX_CODE_ALIGN)
211390284Sobrien	    error ("-malign-loops=%d is not between 0 and %d", i, MAX_CODE_ALIGN);
211490284Sobrien	  else
211590284Sobrien	    align_functions = 1 << i;
211690284Sobrien	}
211718334Speter    }
211818334Speter
211990284Sobrien  /* Default align_* from the processor table.  */
212090284Sobrien  if (align_loops == 0)
212118334Speter    {
2122132743Skan      align_loops = processor_target_table[ix86_tune].align_loop;
2123132743Skan      align_loops_max_skip = processor_target_table[ix86_tune].align_loop_max_skip;
212418334Speter    }
212590284Sobrien  if (align_jumps == 0)
212690284Sobrien    {
2127132743Skan      align_jumps = processor_target_table[ix86_tune].align_jump;
2128132743Skan      align_jumps_max_skip = processor_target_table[ix86_tune].align_jump_max_skip;
212990284Sobrien    }
213090284Sobrien  if (align_functions == 0)
213190284Sobrien    {
2132132743Skan      align_functions = processor_target_table[ix86_tune].align_func;
213390284Sobrien    }
213451411Sobrien
213590284Sobrien  /* Validate -mbranch-cost= value, or provide default.  */
2136169705Skan  ix86_branch_cost = ix86_cost->branch_cost;
213790284Sobrien  if (ix86_branch_cost_string)
213851411Sobrien    {
213990284Sobrien      i = atoi (ix86_branch_cost_string);
214090284Sobrien      if (i < 0 || i > 5)
214190284Sobrien	error ("-mbranch-cost=%d is not between 0 and 5", i);
214290284Sobrien      else
214390284Sobrien	ix86_branch_cost = i;
214451411Sobrien    }
2145169705Skan  if (ix86_section_threshold_string)
2146169705Skan    {
2147169705Skan      i = atoi (ix86_section_threshold_string);
2148169705Skan      if (i < 0)
2149169705Skan	error ("-mlarge-data-threshold=%d is negative", i);
2150169705Skan      else
2151169705Skan	ix86_section_threshold = i;
2152169705Skan    }
215351411Sobrien
2154117408Skan  if (ix86_tls_dialect_string)
2155117408Skan    {
2156117408Skan      if (strcmp (ix86_tls_dialect_string, "gnu") == 0)
2157117408Skan	ix86_tls_dialect = TLS_DIALECT_GNU;
2158169705Skan      else if (strcmp (ix86_tls_dialect_string, "gnu2") == 0)
2159169705Skan	ix86_tls_dialect = TLS_DIALECT_GNU2;
2160117408Skan      else if (strcmp (ix86_tls_dialect_string, "sun") == 0)
2161117408Skan	ix86_tls_dialect = TLS_DIALECT_SUN;
2162117408Skan      else
2163117408Skan	error ("bad value (%s) for -mtls-dialect= switch",
2164117408Skan	       ix86_tls_dialect_string);
2165117408Skan    }
2166117408Skan
216751411Sobrien  /* Keep nonleaf frame pointers.  */
2168169705Skan  if (flag_omit_frame_pointer)
2169169705Skan    target_flags &= ~MASK_OMIT_LEAF_FRAME_POINTER;
2170169705Skan  else if (TARGET_OMIT_LEAF_FRAME_POINTER)
217151411Sobrien    flag_omit_frame_pointer = 1;
217218334Speter
217390284Sobrien  /* If we're doing fast math, we don't care about comparison order
217490284Sobrien     wrt NaNs.  This lets us use a shorter comparison sequence.  */
2175169705Skan  if (flag_finite_math_only)
217690284Sobrien    target_flags &= ~MASK_IEEE_FP;
217718334Speter
217896293Sobrien  /* If the architecture always has an FPU, turn off NO_FANCY_MATH_387,
217996293Sobrien     since the insns won't need emulation.  */
218096293Sobrien  if (x86_arch_always_fancy_math_387 & (1 << ix86_arch))
218196293Sobrien    target_flags &= ~MASK_NO_FANCY_MATH_387;
218296293Sobrien
2183169705Skan  /* Likewise, if the target doesn't have a 387, or we've specified
2184169705Skan     software floating point, don't use 387 inline intrinsics.  */
2185169705Skan  if (!TARGET_80387)
2186169705Skan    target_flags |= MASK_NO_FANCY_MATH_387;
2187169705Skan
2188219639Smm  /* Turn on SSE3 builtins for -mssse3.  */
2189219639Smm  if (TARGET_SSSE3)
2190219639Smm    target_flags |= MASK_SSE3;
2191219639Smm
2192251212Spfg  /* Turn on SSE3 builtins for -msse4a.  */
2193251212Spfg  if (TARGET_SSE4A)
2194251212Spfg    target_flags |= MASK_SSE3;
2195251212Spfg
2196132743Skan  /* Turn on SSE2 builtins for -msse3.  */
2197132743Skan  if (TARGET_SSE3)
2198122194Skan    target_flags |= MASK_SSE2;
2199122194Skan
2200255185Sjmg  /* Turn on SSE2 builtins for -maes.  */
2201255185Sjmg  if (TARGET_AES)
2202255185Sjmg    target_flags |= MASK_SSE2;
2203255185Sjmg
2204122194Skan  /* Turn on SSE builtins for -msse2.  */
2205122194Skan  if (TARGET_SSE2)
2206122194Skan    target_flags |= MASK_SSE;
2207122194Skan
2208169705Skan  /* Turn on MMX builtins for -msse.  */
2209169705Skan  if (TARGET_SSE)
2210169705Skan    {
2211169705Skan      target_flags |= MASK_MMX & ~target_flags_explicit;
2212169705Skan      x86_prefetch_sse = true;
2213169705Skan    }
2214169705Skan
2215169705Skan  /* Turn on MMX builtins for 3Dnow.  */
2216169705Skan  if (TARGET_3DNOW)
2217169705Skan    target_flags |= MASK_MMX;
2218169705Skan
2219251212Spfg  /* Turn on POPCNT builtins for -mabm.  */
2220251212Spfg  if (TARGET_ABM)
2221251212Spfg    target_flags |= MASK_POPCNT;
2222251212Spfg
222390284Sobrien  if (TARGET_64BIT)
222490284Sobrien    {
222590284Sobrien      if (TARGET_ALIGN_DOUBLE)
222690284Sobrien	error ("-malign-double makes no sense in the 64bit mode");
222790284Sobrien      if (TARGET_RTD)
222890284Sobrien	error ("-mrtd calling convention not supported in the 64bit mode");
2229169705Skan
2230169705Skan      /* Enable by default the SSE and MMX builtins.  Do allow the user to
2231169705Skan	 explicitly disable any of these.  In particular, disabling SSE and
2232169705Skan	 MMX for kernel code is extremely useful.  */
2233169705Skan      target_flags
2234169705Skan	|= ((MASK_SSE2 | MASK_SSE | MASK_MMX | MASK_128BIT_LONG_DOUBLE)
2235169705Skan	    & ~target_flags_explicit);
223690284Sobrien     }
223790284Sobrien  else
2238132743Skan    {
2239132743Skan      /* i386 ABI does not specify red zone.  It still makes sense to use it
2240132743Skan         when programmer takes care to stack from being destroyed.  */
2241132743Skan      if (!(target_flags_explicit & MASK_NO_RED_ZONE))
2242132743Skan        target_flags |= MASK_NO_RED_ZONE;
2243132743Skan    }
224418334Speter
2245169705Skan  /* Validate -mpreferred-stack-boundary= value, or provide default.
2246169705Skan     The default of 128 bits is for Pentium III's SSE __m128.  We can't
2247169705Skan     change it because of optimize_size.  Otherwise, we can't mix object
2248169705Skan     files compiled with -Os and -On.  */
2249169705Skan  ix86_preferred_stack_boundary = 128;
2250169705Skan  if (ix86_preferred_stack_boundary_string)
2251169705Skan    {
2252169705Skan      i = atoi (ix86_preferred_stack_boundary_string);
2253169705Skan      if (i < (TARGET_64BIT ? 4 : 2) || i > 12)
2254169705Skan	error ("-mpreferred-stack-boundary=%d is not between %d and 12", i,
2255169705Skan	       TARGET_64BIT ? 4 : 2);
2256169705Skan      else
2257169705Skan	ix86_preferred_stack_boundary = (1 << i) * BITS_PER_UNIT;
2258169705Skan    }
2259169705Skan
2260169705Skan  /* Accept -msseregparm only if at least SSE support is enabled.  */
2261169705Skan  if (TARGET_SSEREGPARM
2262169705Skan      && ! TARGET_SSE)
2263169705Skan    error ("-msseregparm used without SSE enabled");
2264169705Skan
2265169705Skan  ix86_fpmath = TARGET_FPMATH_DEFAULT;
2266169705Skan
226790284Sobrien  if (ix86_fpmath_string != 0)
226818334Speter    {
226990284Sobrien      if (! strcmp (ix86_fpmath_string, "387"))
227090284Sobrien	ix86_fpmath = FPMATH_387;
227190284Sobrien      else if (! strcmp (ix86_fpmath_string, "sse"))
227218334Speter	{
227390284Sobrien	  if (!TARGET_SSE)
227418334Speter	    {
2275169705Skan	      warning (0, "SSE instruction set disabled, using 387 arithmetics");
227690284Sobrien	      ix86_fpmath = FPMATH_387;
227718334Speter	    }
227890284Sobrien	  else
227990284Sobrien	    ix86_fpmath = FPMATH_SSE;
228018334Speter	}
228190284Sobrien      else if (! strcmp (ix86_fpmath_string, "387,sse")
228290284Sobrien	       || ! strcmp (ix86_fpmath_string, "sse,387"))
228318334Speter	{
228490284Sobrien	  if (!TARGET_SSE)
228590284Sobrien	    {
2286169705Skan	      warning (0, "SSE instruction set disabled, using 387 arithmetics");
228790284Sobrien	      ix86_fpmath = FPMATH_387;
228890284Sobrien	    }
228990284Sobrien	  else if (!TARGET_80387)
229090284Sobrien	    {
2291169705Skan	      warning (0, "387 instruction set disabled, using SSE arithmetics");
229290284Sobrien	      ix86_fpmath = FPMATH_SSE;
229390284Sobrien	    }
229490284Sobrien	  else
229590284Sobrien	    ix86_fpmath = FPMATH_SSE | FPMATH_387;
229618334Speter	}
2297117408Skan      else
229890284Sobrien	error ("bad value (%s) for -mfpmath= switch", ix86_fpmath_string);
229918334Speter    }
230018334Speter
2301169705Skan  /* If the i387 is disabled, then do not return values in it. */
2302169705Skan  if (!TARGET_80387)
2303169705Skan    target_flags &= ~MASK_FLOAT_RETURNS;
230490284Sobrien
2305132743Skan  if ((x86_accumulate_outgoing_args & TUNEMASK)
2306117408Skan      && !(target_flags_explicit & MASK_ACCUMULATE_OUTGOING_ARGS)
230790284Sobrien      && !optimize_size)
230890284Sobrien    target_flags |= MASK_ACCUMULATE_OUTGOING_ARGS;
230990284Sobrien
2310169705Skan  /* ??? Unwind info is not correct around the CFG unless either a frame
2311169705Skan     pointer is present or M_A_O_A is set.  Fixing this requires rewriting
2312169705Skan     unwind info generation to be aware of the CFG and propagating states
2313169705Skan     around edges.  */
2314169705Skan  if ((flag_unwind_tables || flag_asynchronous_unwind_tables
2315169705Skan       || flag_exceptions || flag_non_call_exceptions)
2316169705Skan      && flag_omit_frame_pointer
2317169705Skan      && !(target_flags & MASK_ACCUMULATE_OUTGOING_ARGS))
2318169705Skan    {
2319169705Skan      if (target_flags_explicit & MASK_ACCUMULATE_OUTGOING_ARGS)
2320169705Skan	warning (0, "unwind tables currently require either a frame pointer "
2321169705Skan		 "or -maccumulate-outgoing-args for correctness");
2322169705Skan      target_flags |= MASK_ACCUMULATE_OUTGOING_ARGS;
2323169705Skan    }
2324169705Skan
232590284Sobrien  /* Figure out what ASM_GENERATE_INTERNAL_LABEL builds as a prefix.  */
232690284Sobrien  {
232790284Sobrien    char *p;
232890284Sobrien    ASM_GENERATE_INTERNAL_LABEL (internal_label_prefix, "LX", 0);
232990284Sobrien    p = strchr (internal_label_prefix, 'X');
233090284Sobrien    internal_label_prefix_len = p - internal_label_prefix;
233190284Sobrien    *p = '\0';
233290284Sobrien  }
2333169705Skan
2334169705Skan  /* When scheduling description is not available, disable scheduler pass
2335169705Skan     so it won't slow down the compilation and make x87 code slower.  */
2336169705Skan  if (!TARGET_SCHEDULE)
2337169705Skan    flag_schedule_insns_after_reload = flag_schedule_insns = 0;
233851411Sobrien}
233951411Sobrien
2340169705Skan/* switch to the appropriate section for output of DECL.
2341169705Skan   DECL is either a `VAR_DECL' node or a constant of some sort.
2342169705Skan   RELOC indicates whether forming the initial value of DECL requires
2343169705Skan   link-time relocations.  */
2344169705Skan
2345169705Skanstatic section *
2346169705Skanx86_64_elf_select_section (tree decl, int reloc,
2347169705Skan			   unsigned HOST_WIDE_INT align)
2348169705Skan{
2349169705Skan  if ((ix86_cmodel == CM_MEDIUM || ix86_cmodel == CM_MEDIUM_PIC)
2350169705Skan      && ix86_in_large_data_p (decl))
2351169705Skan    {
2352169705Skan      const char *sname = NULL;
2353169705Skan      unsigned int flags = SECTION_WRITE;
2354169705Skan      switch (categorize_decl_for_section (decl, reloc))
2355169705Skan	{
2356169705Skan	case SECCAT_DATA:
2357169705Skan	  sname = ".ldata";
2358169705Skan	  break;
2359169705Skan	case SECCAT_DATA_REL:
2360169705Skan	  sname = ".ldata.rel";
2361169705Skan	  break;
2362169705Skan	case SECCAT_DATA_REL_LOCAL:
2363169705Skan	  sname = ".ldata.rel.local";
2364169705Skan	  break;
2365169705Skan	case SECCAT_DATA_REL_RO:
2366169705Skan	  sname = ".ldata.rel.ro";
2367169705Skan	  break;
2368169705Skan	case SECCAT_DATA_REL_RO_LOCAL:
2369169705Skan	  sname = ".ldata.rel.ro.local";
2370169705Skan	  break;
2371169705Skan	case SECCAT_BSS:
2372169705Skan	  sname = ".lbss";
2373169705Skan	  flags |= SECTION_BSS;
2374169705Skan	  break;
2375169705Skan	case SECCAT_RODATA:
2376169705Skan	case SECCAT_RODATA_MERGE_STR:
2377169705Skan	case SECCAT_RODATA_MERGE_STR_INIT:
2378169705Skan	case SECCAT_RODATA_MERGE_CONST:
2379169705Skan	  sname = ".lrodata";
2380169705Skan	  flags = 0;
2381169705Skan	  break;
2382169705Skan	case SECCAT_SRODATA:
2383169705Skan	case SECCAT_SDATA:
2384169705Skan	case SECCAT_SBSS:
2385169705Skan	  gcc_unreachable ();
2386169705Skan	case SECCAT_TEXT:
2387169705Skan	case SECCAT_TDATA:
2388169705Skan	case SECCAT_TBSS:
2389169705Skan	  /* We don't split these for medium model.  Place them into
2390169705Skan	     default sections and hope for best.  */
2391169705Skan	  break;
2392169705Skan	}
2393169705Skan      if (sname)
2394169705Skan	{
2395169705Skan	  /* We might get called with string constants, but get_named_section
2396169705Skan	     doesn't like them as they are not DECLs.  Also, we need to set
2397169705Skan	     flags in that case.  */
2398169705Skan	  if (!DECL_P (decl))
2399169705Skan	    return get_section (sname, flags, NULL);
2400169705Skan	  return get_named_section (decl, sname, reloc);
2401169705Skan	}
2402169705Skan    }
2403169705Skan  return default_elf_select_section (decl, reloc, align);
2404169705Skan}
2405169705Skan
2406169705Skan/* Build up a unique section name, expressed as a
2407169705Skan   STRING_CST node, and assign it to DECL_SECTION_NAME (decl).
2408169705Skan   RELOC indicates whether the initial value of EXP requires
2409169705Skan   link-time relocations.  */
2410169705Skan
2411169705Skanstatic void
2412169705Skanx86_64_elf_unique_section (tree decl, int reloc)
2413169705Skan{
2414169705Skan  if ((ix86_cmodel == CM_MEDIUM || ix86_cmodel == CM_MEDIUM_PIC)
2415169705Skan      && ix86_in_large_data_p (decl))
2416169705Skan    {
2417169705Skan      const char *prefix = NULL;
2418169705Skan      /* We only need to use .gnu.linkonce if we don't have COMDAT groups.  */
2419169705Skan      bool one_only = DECL_ONE_ONLY (decl) && !HAVE_COMDAT_GROUP;
2420169705Skan
2421169705Skan      switch (categorize_decl_for_section (decl, reloc))
2422169705Skan	{
2423169705Skan	case SECCAT_DATA:
2424169705Skan	case SECCAT_DATA_REL:
2425169705Skan	case SECCAT_DATA_REL_LOCAL:
2426169705Skan	case SECCAT_DATA_REL_RO:
2427169705Skan	case SECCAT_DATA_REL_RO_LOCAL:
2428169705Skan          prefix = one_only ? ".gnu.linkonce.ld." : ".ldata.";
2429169705Skan	  break;
2430169705Skan	case SECCAT_BSS:
2431169705Skan          prefix = one_only ? ".gnu.linkonce.lb." : ".lbss.";
2432169705Skan	  break;
2433169705Skan	case SECCAT_RODATA:
2434169705Skan	case SECCAT_RODATA_MERGE_STR:
2435169705Skan	case SECCAT_RODATA_MERGE_STR_INIT:
2436169705Skan	case SECCAT_RODATA_MERGE_CONST:
2437169705Skan          prefix = one_only ? ".gnu.linkonce.lr." : ".lrodata.";
2438169705Skan	  break;
2439169705Skan	case SECCAT_SRODATA:
2440169705Skan	case SECCAT_SDATA:
2441169705Skan	case SECCAT_SBSS:
2442169705Skan	  gcc_unreachable ();
2443169705Skan	case SECCAT_TEXT:
2444169705Skan	case SECCAT_TDATA:
2445169705Skan	case SECCAT_TBSS:
2446169705Skan	  /* We don't split these for medium model.  Place them into
2447169705Skan	     default sections and hope for best.  */
2448169705Skan	  break;
2449169705Skan	}
2450169705Skan      if (prefix)
2451169705Skan	{
2452169705Skan	  const char *name;
2453169705Skan	  size_t nlen, plen;
2454169705Skan	  char *string;
2455169705Skan	  plen = strlen (prefix);
2456169705Skan
2457169705Skan	  name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
2458169705Skan	  name = targetm.strip_name_encoding (name);
2459169705Skan	  nlen = strlen (name);
2460169705Skan
2461169705Skan	  string = alloca (nlen + plen + 1);
2462169705Skan	  memcpy (string, prefix, plen);
2463169705Skan	  memcpy (string + plen, name, nlen + 1);
2464169705Skan
2465169705Skan	  DECL_SECTION_NAME (decl) = build_string (nlen + plen, string);
2466169705Skan	  return;
2467169705Skan	}
2468169705Skan    }
2469169705Skan  default_unique_section (decl, reloc);
2470169705Skan}
2471169705Skan
2472169705Skan#ifdef COMMON_ASM_OP
2473169705Skan/* This says how to output assembler code to declare an
2474169705Skan   uninitialized external linkage data object.
2475169705Skan
2476169705Skan   For medium model x86-64 we need to use .largecomm opcode for
2477169705Skan   large objects.  */
247851411Sobrienvoid
2479169705Skanx86_elf_aligned_common (FILE *file,
2480169705Skan			const char *name, unsigned HOST_WIDE_INT size,
2481169705Skan			int align)
2482169705Skan{
2483169705Skan  if ((ix86_cmodel == CM_MEDIUM || ix86_cmodel == CM_MEDIUM_PIC)
2484169705Skan      && size > (unsigned int)ix86_section_threshold)
2485169705Skan    fprintf (file, ".largecomm\t");
2486169705Skan  else
2487169705Skan    fprintf (file, "%s", COMMON_ASM_OP);
2488169705Skan  assemble_name (file, name);
2489169705Skan  fprintf (file, ","HOST_WIDE_INT_PRINT_UNSIGNED",%u\n",
2490169705Skan	   size, align / BITS_PER_UNIT);
2491169705Skan}
2492169705Skan
2493169705Skan/* Utility function for targets to use in implementing
2494169705Skan   ASM_OUTPUT_ALIGNED_BSS.  */
2495169705Skan
2496169705Skanvoid
2497169705Skanx86_output_aligned_bss (FILE *file, tree decl ATTRIBUTE_UNUSED,
2498169705Skan			const char *name, unsigned HOST_WIDE_INT size,
2499169705Skan			int align)
2500169705Skan{
2501169705Skan  if ((ix86_cmodel == CM_MEDIUM || ix86_cmodel == CM_MEDIUM_PIC)
2502169705Skan      && size > (unsigned int)ix86_section_threshold)
2503169705Skan    switch_to_section (get_named_section (decl, ".lbss", 0));
2504169705Skan  else
2505169705Skan    switch_to_section (bss_section);
2506169705Skan  ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));
2507169705Skan#ifdef ASM_DECLARE_OBJECT_NAME
2508169705Skan  last_assemble_variable_decl = decl;
2509169705Skan  ASM_DECLARE_OBJECT_NAME (file, name, decl);
2510169705Skan#else
2511169705Skan  /* Standard thing is just output label for the object.  */
2512169705Skan  ASM_OUTPUT_LABEL (file, name);
2513169705Skan#endif /* ASM_DECLARE_OBJECT_NAME */
2514169705Skan  ASM_OUTPUT_SKIP (file, size ? size : 1);
2515169705Skan}
2516169705Skan#endif
2517169705Skan
2518169705Skanvoid
2519132743Skanoptimization_options (int level, int size ATTRIBUTE_UNUSED)
252051411Sobrien{
252151411Sobrien  /* For -O2 and beyond, turn off -fschedule-insns by default.  It tends to
252251411Sobrien     make the problem with not enough registers even worse.  */
252351411Sobrien#ifdef INSN_SCHEDULING
252451411Sobrien  if (level > 1)
252551411Sobrien    flag_schedule_insns = 0;
252651411Sobrien#endif
2527117408Skan
2528169705Skan  if (TARGET_MACHO)
2529169705Skan    /* The Darwin libraries never set errno, so we might as well
2530169705Skan       avoid calling them when that's the only reason we would.  */
2531169705Skan    flag_errno_math = 0;
2532169705Skan
2533107597Sobrien  /* The default values of these switches depend on the TARGET_64BIT
2534107597Sobrien     that is not known at this moment.  Mark these values with 2 and
2535107597Sobrien     let user the to override these.  In case there is no command line option
2536107597Sobrien     specifying them, we will set the defaults in override_options.  */
2537107597Sobrien  if (optimize >= 1)
2538107597Sobrien    flag_omit_frame_pointer = 2;
2539110628Skan  flag_pcc_struct_return = 2;
2540107597Sobrien  flag_asynchronous_unwind_tables = 2;
2541169705Skan#ifdef SUBTARGET_OPTIMIZATION_OPTIONS
2542169705Skan  SUBTARGET_OPTIMIZATION_OPTIONS;
2543169705Skan#endif
254451411Sobrien}
254551411Sobrien
254690284Sobrien/* Table of valid machine attributes.  */
254790284Sobrienconst struct attribute_spec ix86_attribute_table[] =
254890284Sobrien{
254990284Sobrien  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
255090284Sobrien  /* Stdcall attribute says callee is responsible for popping arguments
255190284Sobrien     if they are not variable.  */
2552169705Skan  { "stdcall",   0, 0, false, true,  true,  ix86_handle_cconv_attribute },
2553132743Skan  /* Fastcall attribute says callee is responsible for popping arguments
2554132743Skan     if they are not variable.  */
2555169705Skan  { "fastcall",  0, 0, false, true,  true,  ix86_handle_cconv_attribute },
255690284Sobrien  /* Cdecl attribute says the callee is a normal C declaration */
2557169705Skan  { "cdecl",     0, 0, false, true,  true,  ix86_handle_cconv_attribute },
255890284Sobrien  /* Regparm attribute specifies how many integer arguments are to be
255990284Sobrien     passed in registers.  */
2560169705Skan  { "regparm",   1, 1, false, true,  true,  ix86_handle_cconv_attribute },
2561169705Skan  /* Sseregparm attribute says we are using x86_64 calling conventions
2562169705Skan     for FP arguments.  */
2563169705Skan  { "sseregparm", 0, 0, false, true, true, ix86_handle_cconv_attribute },
2564169705Skan  /* force_align_arg_pointer says this function realigns the stack at entry.  */
2565169705Skan  { (const char *)&ix86_force_align_arg_pointer_string, 0, 0,
2566169705Skan    false, true,  true, ix86_handle_cconv_attribute },
2567169705Skan#if TARGET_DLLIMPORT_DECL_ATTRIBUTES
2568169705Skan  { "dllimport", 0, 0, false, false, false, handle_dll_attribute },
2569169705Skan  { "dllexport", 0, 0, false, false, false, handle_dll_attribute },
257090284Sobrien  { "shared",    0, 0, true,  false, false, ix86_handle_shared_attribute },
257190284Sobrien#endif
2572132743Skan  { "ms_struct", 0, 0, false, false,  false, ix86_handle_struct_attribute },
2573132743Skan  { "gcc_struct", 0, 0, false, false,  false, ix86_handle_struct_attribute },
2574169705Skan#ifdef SUBTARGET_ATTRIBUTE_TABLE
2575169705Skan  SUBTARGET_ATTRIBUTE_TABLE,
2576169705Skan#endif
257790284Sobrien  { NULL,        0, 0, false, false, false, NULL }
257890284Sobrien};
257918334Speter
2580132743Skan/* Decide whether we can make a sibling call to a function.  DECL is the
2581132743Skan   declaration of the function being targeted by the call and EXP is the
2582132743Skan   CALL_EXPR representing the call.  */
2583132743Skan
2584132743Skanstatic bool
2585132743Skanix86_function_ok_for_sibcall (tree decl, tree exp)
2586132743Skan{
2587169705Skan  tree func;
2588169705Skan  rtx a, b;
2589169705Skan
2590132743Skan  /* If we are generating position-independent code, we cannot sibcall
2591132743Skan     optimize any indirect call, or a direct call to a global function,
2592132743Skan     as the PLT requires %ebx be live.  */
2593169705Skan  if (!TARGET_64BIT && flag_pic && (!decl || !targetm.binds_local_p (decl)))
2594132743Skan    return false;
2595132743Skan
2596169705Skan  if (decl)
2597169705Skan    func = decl;
2598169705Skan  else
2599169705Skan    {
2600169705Skan      func = TREE_TYPE (TREE_OPERAND (exp, 0));
2601169705Skan      if (POINTER_TYPE_P (func))
2602169705Skan        func = TREE_TYPE (func);
2603169705Skan    }
2604169705Skan
2605169705Skan  /* Check that the return value locations are the same.  Like
2606169705Skan     if we are returning floats on the 80387 register stack, we cannot
2607132743Skan     make a sibcall from a function that doesn't return a float to a
2608132743Skan     function that does or, conversely, from a function that does return
2609132743Skan     a float to a function that doesn't; the necessary stack adjustment
2610169705Skan     would not be executed.  This is also the place we notice
2611169705Skan     differences in the return value ABI.  Note that it is ok for one
2612169705Skan     of the functions to have void return type as long as the return
2613169705Skan     value of the other is passed in a register.  */
2614169705Skan  a = ix86_function_value (TREE_TYPE (exp), func, false);
2615169705Skan  b = ix86_function_value (TREE_TYPE (DECL_RESULT (cfun->decl)),
2616169705Skan			   cfun->decl, false);
2617169705Skan  if (STACK_REG_P (a) || STACK_REG_P (b))
2618169705Skan    {
2619169705Skan      if (!rtx_equal_p (a, b))
2620169705Skan	return false;
2621169705Skan    }
2622169705Skan  else if (VOID_TYPE_P (TREE_TYPE (DECL_RESULT (cfun->decl))))
2623169705Skan    ;
2624169705Skan  else if (!rtx_equal_p (a, b))
2625132743Skan    return false;
2626132743Skan
2627132743Skan  /* If this call is indirect, we'll need to be able to use a call-clobbered
2628132743Skan     register for the address of the target function.  Make sure that all
2629132743Skan     such registers are not used for passing parameters.  */
2630132743Skan  if (!decl && !TARGET_64BIT)
2631132743Skan    {
2632132743Skan      tree type;
2633132743Skan
2634132743Skan      /* We're looking at the CALL_EXPR, we need the type of the function.  */
2635132743Skan      type = TREE_OPERAND (exp, 0);		/* pointer expression */
2636132743Skan      type = TREE_TYPE (type);			/* pointer type */
2637132743Skan      type = TREE_TYPE (type);			/* function type */
2638132743Skan
2639132743Skan      if (ix86_function_regparm (type, NULL) >= 3)
2640132743Skan	{
2641132743Skan	  /* ??? Need to count the actual number of registers to be used,
2642132743Skan	     not the possible number of registers.  Fix later.  */
2643132743Skan	  return false;
2644132743Skan	}
2645132743Skan    }
2646132743Skan
2647169705Skan#if TARGET_DLLIMPORT_DECL_ATTRIBUTES
2648169705Skan  /* Dllimport'd functions are also called indirectly.  */
2649169705Skan  if (decl && DECL_DLLIMPORT_P (decl)
2650169705Skan      && ix86_function_regparm (TREE_TYPE (decl), NULL) >= 3)
2651169705Skan    return false;
2652169705Skan#endif
2653169705Skan
2654169705Skan  /* If we forced aligned the stack, then sibcalling would unalign the
2655169705Skan     stack, which may break the called function.  */
2656169705Skan  if (cfun->machine->force_align_arg_pointer)
2657169705Skan    return false;
2658169705Skan
2659132743Skan  /* Otherwise okay.  That also includes certain types of indirect calls.  */
2660132743Skan  return true;
2661132743Skan}
2662132743Skan
2663169705Skan/* Handle "cdecl", "stdcall", "fastcall", "regparm" and "sseregparm"
2664169705Skan   calling convention attributes;
266590284Sobrien   arguments as in struct attribute_spec.handler.  */
2666169705Skan
266790284Sobrienstatic tree
2668169705Skanix86_handle_cconv_attribute (tree *node, tree name,
2669169705Skan				   tree args,
2670169705Skan				   int flags ATTRIBUTE_UNUSED,
2671169705Skan				   bool *no_add_attrs)
267251411Sobrien{
267390284Sobrien  if (TREE_CODE (*node) != FUNCTION_TYPE
267490284Sobrien      && TREE_CODE (*node) != METHOD_TYPE
267590284Sobrien      && TREE_CODE (*node) != FIELD_DECL
267690284Sobrien      && TREE_CODE (*node) != TYPE_DECL)
267751411Sobrien    {
2678169705Skan      warning (OPT_Wattributes, "%qs attribute only applies to functions",
267990284Sobrien	       IDENTIFIER_POINTER (name));
268090284Sobrien      *no_add_attrs = true;
2681169705Skan      return NULL_TREE;
268251411Sobrien    }
268318334Speter
2684169705Skan  /* Can combine regparm with all attributes but fastcall.  */
2685169705Skan  if (is_attribute_p ("regparm", name))
268690284Sobrien    {
2687169705Skan      tree cst;
268890284Sobrien
2689169705Skan      if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (*node)))
2690169705Skan        {
2691169705Skan	  error ("fastcall and regparm attributes are not compatible");
2692169705Skan	}
269318334Speter
269490284Sobrien      cst = TREE_VALUE (args);
269590284Sobrien      if (TREE_CODE (cst) != INTEGER_CST)
269690284Sobrien	{
2697169705Skan	  warning (OPT_Wattributes,
2698169705Skan		   "%qs attribute requires an integer constant argument",
269990284Sobrien		   IDENTIFIER_POINTER (name));
270090284Sobrien	  *no_add_attrs = true;
270190284Sobrien	}
270290284Sobrien      else if (compare_tree_int (cst, REGPARM_MAX) > 0)
270390284Sobrien	{
2704169705Skan	  warning (OPT_Wattributes, "argument to %qs attribute larger than %d",
270590284Sobrien		   IDENTIFIER_POINTER (name), REGPARM_MAX);
270690284Sobrien	  *no_add_attrs = true;
270790284Sobrien	}
2708132743Skan
2709169705Skan      if (!TARGET_64BIT
2710169705Skan	  && lookup_attribute (ix86_force_align_arg_pointer_string,
2711169705Skan			       TYPE_ATTRIBUTES (*node))
2712169705Skan	  && compare_tree_int (cst, REGPARM_MAX-1))
2713132743Skan	{
2714169705Skan	  error ("%s functions limited to %d register parameters",
2715169705Skan		 ix86_force_align_arg_pointer_string, REGPARM_MAX-1);
2716169705Skan	}
2717169705Skan
2718169705Skan      return NULL_TREE;
2719169705Skan    }
2720169705Skan
2721169705Skan  if (TARGET_64BIT)
2722169705Skan    {
2723169705Skan      warning (OPT_Wattributes, "%qs attribute ignored",
2724169705Skan	       IDENTIFIER_POINTER (name));
2725169705Skan      *no_add_attrs = true;
2726169705Skan      return NULL_TREE;
2727169705Skan    }
2728169705Skan
2729169705Skan  /* Can combine fastcall with stdcall (redundant) and sseregparm.  */
2730169705Skan  if (is_attribute_p ("fastcall", name))
2731169705Skan    {
2732169705Skan      if (lookup_attribute ("cdecl", TYPE_ATTRIBUTES (*node)))
2733169705Skan        {
2734169705Skan	  error ("fastcall and cdecl attributes are not compatible");
2735169705Skan	}
2736169705Skan      if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (*node)))
2737169705Skan        {
2738169705Skan	  error ("fastcall and stdcall attributes are not compatible");
2739169705Skan	}
2740169705Skan      if (lookup_attribute ("regparm", TYPE_ATTRIBUTES (*node)))
2741169705Skan        {
2742132743Skan	  error ("fastcall and regparm attributes are not compatible");
2743132743Skan	}
274490284Sobrien    }
274518334Speter
2746169705Skan  /* Can combine stdcall with fastcall (redundant), regparm and
2747169705Skan     sseregparm.  */
2748169705Skan  else if (is_attribute_p ("stdcall", name))
2749169705Skan    {
2750169705Skan      if (lookup_attribute ("cdecl", TYPE_ATTRIBUTES (*node)))
2751169705Skan        {
2752169705Skan	  error ("stdcall and cdecl attributes are not compatible");
2753169705Skan	}
2754169705Skan      if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (*node)))
2755169705Skan        {
2756169705Skan	  error ("stdcall and fastcall attributes are not compatible");
2757169705Skan	}
2758169705Skan    }
2759169705Skan
2760169705Skan  /* Can combine cdecl with regparm and sseregparm.  */
2761169705Skan  else if (is_attribute_p ("cdecl", name))
2762169705Skan    {
2763169705Skan      if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (*node)))
2764169705Skan        {
2765169705Skan	  error ("stdcall and cdecl attributes are not compatible");
2766169705Skan	}
2767169705Skan      if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (*node)))
2768169705Skan        {
2769169705Skan	  error ("fastcall and cdecl attributes are not compatible");
2770169705Skan	}
2771169705Skan    }
2772169705Skan
2773169705Skan  /* Can combine sseregparm with all attributes.  */
2774169705Skan
277590284Sobrien  return NULL_TREE;
277690284Sobrien}
277718334Speter
277818334Speter/* Return 0 if the attributes for two types are incompatible, 1 if they
277918334Speter   are compatible, and 2 if they are nearly compatible (which causes a
278018334Speter   warning to be generated).  */
278118334Speter
278290284Sobrienstatic int
2783132743Skanix86_comp_type_attributes (tree type1, tree type2)
278418334Speter{
278590284Sobrien  /* Check for mismatch of non-default calling convention.  */
278690284Sobrien  const char *const rtdstr = TARGET_RTD ? "cdecl" : "stdcall";
278752294Sobrien
278852294Sobrien  if (TREE_CODE (type1) != FUNCTION_TYPE)
278952294Sobrien    return 1;
279052294Sobrien
2791169705Skan  /* Check for mismatched fastcall/regparm types.  */
2792169705Skan  if ((!lookup_attribute ("fastcall", TYPE_ATTRIBUTES (type1))
2793169705Skan       != !lookup_attribute ("fastcall", TYPE_ATTRIBUTES (type2)))
2794169705Skan      || (ix86_function_regparm (type1, NULL)
2795169705Skan	  != ix86_function_regparm (type2, NULL)))
2796132743Skan    return 0;
2797132743Skan
2798169705Skan  /* Check for mismatched sseregparm types.  */
2799169705Skan  if (!lookup_attribute ("sseregparm", TYPE_ATTRIBUTES (type1))
2800169705Skan      != !lookup_attribute ("sseregparm", TYPE_ATTRIBUTES (type2)))
2801169705Skan    return 0;
2802169705Skan
280352294Sobrien  /* Check for mismatched return types (cdecl vs stdcall).  */
280452294Sobrien  if (!lookup_attribute (rtdstr, TYPE_ATTRIBUTES (type1))
280552294Sobrien      != !lookup_attribute (rtdstr, TYPE_ATTRIBUTES (type2)))
280652294Sobrien    return 0;
2807169705Skan
280818334Speter  return 1;
280918334Speter}
281018334Speter
2811169705Skan/* Return the regparm value for a function with the indicated TYPE and DECL.
2812132743Skan   DECL may be NULL when calling function indirectly
2813132743Skan   or considering a libcall.  */
2814117408Skan
2815117408Skanstatic int
2816132743Skanix86_function_regparm (tree type, tree decl)
2817117408Skan{
2818117408Skan  tree attr;
2819132743Skan  int regparm = ix86_regparm;
2820132743Skan  bool user_convention = false;
2821117408Skan
2822132743Skan  if (!TARGET_64BIT)
2823132743Skan    {
2824132743Skan      attr = lookup_attribute ("regparm", TYPE_ATTRIBUTES (type));
2825132743Skan      if (attr)
2826132743Skan	{
2827132743Skan	  regparm = TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (attr)));
2828132743Skan	  user_convention = true;
2829132743Skan	}
2830132743Skan
2831132743Skan      if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (type)))
2832132743Skan	{
2833132743Skan	  regparm = 2;
2834132743Skan	  user_convention = true;
2835132743Skan	}
2836132743Skan
2837132743Skan      /* Use register calling convention for local functions when possible.  */
2838132743Skan      if (!TARGET_64BIT && !user_convention && decl
2839132743Skan	  && flag_unit_at_a_time && !profile_flag)
2840132743Skan	{
2841132743Skan	  struct cgraph_local_info *i = cgraph_local_info (decl);
2842132743Skan	  if (i && i->local)
2843132743Skan	    {
2844169705Skan	      int local_regparm, globals = 0, regno;
2845169705Skan
2846169705Skan	      /* Make sure no regparm register is taken by a global register
2847169705Skan		 variable.  */
2848169705Skan	      for (local_regparm = 0; local_regparm < 3; local_regparm++)
2849169705Skan		if (global_regs[local_regparm])
2850169705Skan		  break;
2851132743Skan	      /* We can't use regparm(3) for nested functions as these use
2852132743Skan		 static chain pointer in third argument.  */
2853169705Skan	      if (local_regparm == 3
2854169705Skan		  && decl_function_context (decl)
2855169705Skan		  && !DECL_NO_STATIC_CHAIN (decl))
2856169705Skan		local_regparm = 2;
2857169705Skan	      /* If the function realigns its stackpointer, the
2858169705Skan		 prologue will clobber %ecx.  If we've already
2859169705Skan		 generated code for the callee, the callee
2860169705Skan		 DECL_STRUCT_FUNCTION is gone, so we fall back to
2861169705Skan		 scanning the attributes for the self-realigning
2862169705Skan		 property.  */
2863169705Skan	      if ((DECL_STRUCT_FUNCTION (decl)
2864169705Skan		   && DECL_STRUCT_FUNCTION (decl)->machine->force_align_arg_pointer)
2865169705Skan		  || (!DECL_STRUCT_FUNCTION (decl)
2866169705Skan		      && lookup_attribute (ix86_force_align_arg_pointer_string,
2867169705Skan					   TYPE_ATTRIBUTES (TREE_TYPE (decl)))))
2868169705Skan		local_regparm = 2;
2869169705Skan	      /* Each global register variable increases register preassure,
2870169705Skan		 so the more global reg vars there are, the smaller regparm
2871169705Skan		 optimization use, unless requested by the user explicitly.  */
2872169705Skan	      for (regno = 0; regno < 6; regno++)
2873169705Skan		if (global_regs[regno])
2874169705Skan		  globals++;
2875169705Skan	      local_regparm
2876169705Skan		= globals < local_regparm ? local_regparm - globals : 0;
2877169705Skan
2878169705Skan	      if (local_regparm > regparm)
2879169705Skan		regparm = local_regparm;
2880132743Skan	    }
2881132743Skan	}
2882132743Skan    }
2883132743Skan  return regparm;
2884117408Skan}
2885117408Skan
2886169705Skan/* Return 1 or 2, if we can pass up to SSE_REGPARM_MAX SFmode (1) and
2887169705Skan   DFmode (2) arguments in SSE registers for a function with the
2888169705Skan   indicated TYPE and DECL.  DECL may be NULL when calling function
2889169705Skan   indirectly or considering a libcall.  Otherwise return 0.  */
2890169705Skan
2891169705Skanstatic int
2892169705Skanix86_function_sseregparm (tree type, tree decl)
2893169705Skan{
2894169705Skan  /* Use SSE registers to pass SFmode and DFmode arguments if requested
2895169705Skan     by the sseregparm attribute.  */
2896169705Skan  if (TARGET_SSEREGPARM
2897169705Skan      || (type
2898169705Skan	  && lookup_attribute ("sseregparm", TYPE_ATTRIBUTES (type))))
2899169705Skan    {
2900169705Skan      if (!TARGET_SSE)
2901169705Skan	{
2902169705Skan	  if (decl)
2903169705Skan	    error ("Calling %qD with attribute sseregparm without "
2904169705Skan		   "SSE/SSE2 enabled", decl);
2905169705Skan	  else
2906169705Skan	    error ("Calling %qT with attribute sseregparm without "
2907169705Skan		   "SSE/SSE2 enabled", type);
2908169705Skan	  return 0;
2909169705Skan	}
2910169705Skan
2911169705Skan      return 2;
2912169705Skan    }
2913169705Skan
2914169705Skan  /* For local functions, pass up to SSE_REGPARM_MAX SFmode
2915169705Skan     (and DFmode for SSE2) arguments in SSE registers,
2916169705Skan     even for 32-bit targets.  */
2917169705Skan  if (!TARGET_64BIT && decl
2918169705Skan      && TARGET_SSE_MATH && flag_unit_at_a_time && !profile_flag)
2919169705Skan    {
2920169705Skan      struct cgraph_local_info *i = cgraph_local_info (decl);
2921169705Skan      if (i && i->local)
2922169705Skan	return TARGET_SSE2 ? 2 : 1;
2923169705Skan    }
2924169705Skan
2925169705Skan  return 0;
2926169705Skan}
2927169705Skan
2928169705Skan/* Return true if EAX is live at the start of the function.  Used by
2929132743Skan   ix86_expand_prologue to determine if we need special help before
2930132743Skan   calling allocate_stack_worker.  */
2931132743Skan
2932132743Skanstatic bool
2933132743Skanix86_eax_live_at_start_p (void)
2934132743Skan{
2935132743Skan  /* Cheat.  Don't bother working forward from ix86_function_regparm
2936132743Skan     to the function type to whether an actual argument is located in
2937132743Skan     eax.  Instead just look at cfg info, which is still close enough
2938132743Skan     to correct at this point.  This gives false positives for broken
2939132743Skan     functions that might use uninitialized data that happens to be
2940132743Skan     allocated in eax, but who cares?  */
2941169705Skan  return REGNO_REG_SET_P (ENTRY_BLOCK_PTR->il.rtl->global_live_at_end, 0);
2942132743Skan}
2943132743Skan
294418334Speter/* Value is the number of bytes of arguments automatically
294518334Speter   popped when returning from a subroutine call.
294618334Speter   FUNDECL is the declaration node of the function (as a tree),
294718334Speter   FUNTYPE is the data type of the function (as a tree),
294818334Speter   or for a library call it is an identifier node for the subroutine name.
294918334Speter   SIZE is the number of bytes of arguments passed on the stack.
295018334Speter
295118334Speter   On the 80386, the RTD insn may be used to pop them if the number
295218334Speter     of args is fixed, but if the number is variable then the caller
295318334Speter     must pop them all.  RTD can't be used for library calls now
295418334Speter     because the library is compiled with the Unix compiler.
295518334Speter   Use of RTD is a selectable option, since it is incompatible with
295618334Speter   standard Unix calling sequences.  If the option is not selected,
295718334Speter   the caller must always pop the args.
295818334Speter
295918334Speter   The attribute stdcall is equivalent to RTD on a per module basis.  */
296018334Speter
296118334Speterint
2962132743Skanix86_return_pops_args (tree fundecl, tree funtype, int size)
296318334Speter{
296451411Sobrien  int rtd = TARGET_RTD && (!fundecl || TREE_CODE (fundecl) != IDENTIFIER_NODE);
296518334Speter
2966132743Skan  /* Cdecl functions override -mrtd, and never pop the stack.  */
296751411Sobrien  if (! lookup_attribute ("cdecl", TYPE_ATTRIBUTES (funtype))) {
296818334Speter
2969132743Skan    /* Stdcall and fastcall functions will pop the stack if not
2970132743Skan       variable args.  */
2971132743Skan    if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (funtype))
2972132743Skan        || lookup_attribute ("fastcall", TYPE_ATTRIBUTES (funtype)))
297351411Sobrien      rtd = 1;
297418334Speter
297551411Sobrien    if (rtd
297651411Sobrien        && (TYPE_ARG_TYPES (funtype) == NULL_TREE
297751411Sobrien	    || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (funtype)))
297851411Sobrien		== void_type_node)))
297951411Sobrien      return size;
298051411Sobrien  }
298118334Speter
298296293Sobrien  /* Lose any fake structure return argument if it is passed on the stack.  */
2983132743Skan  if (aggregate_value_p (TREE_TYPE (funtype), fundecl)
2984169705Skan      && !TARGET_64BIT
2985169705Skan      && !KEEP_AGGREGATE_RETURN_POINTER)
298696293Sobrien    {
2987132743Skan      int nregs = ix86_function_regparm (funtype, fundecl);
298818334Speter
298996293Sobrien      if (!nregs)
299096293Sobrien	return GET_MODE_SIZE (Pmode);
299196293Sobrien    }
299296293Sobrien
299396293Sobrien  return 0;
299418334Speter}
299518334Speter
299618334Speter/* Argument support functions.  */
299718334Speter
299890284Sobrien/* Return true when register may be used to pass function parameters.  */
299990284Sobrienbool
3000132743Skanix86_function_arg_regno_p (int regno)
300190284Sobrien{
300290284Sobrien  int i;
300390284Sobrien  if (!TARGET_64BIT)
3004169705Skan    {
3005169705Skan      if (TARGET_MACHO)
3006169705Skan        return (regno < REGPARM_MAX
3007169705Skan                || (TARGET_SSE && SSE_REGNO_P (regno) && !fixed_regs[regno]));
3008169705Skan      else
3009169705Skan        return (regno < REGPARM_MAX
3010169705Skan	        || (TARGET_MMX && MMX_REGNO_P (regno)
3011169705Skan	  	    && (regno < FIRST_MMX_REG + MMX_REGPARM_MAX))
3012169705Skan	        || (TARGET_SSE && SSE_REGNO_P (regno)
3013169705Skan		    && (regno < FIRST_SSE_REG + SSE_REGPARM_MAX)));
3014169705Skan    }
3015169705Skan
3016169705Skan  if (TARGET_MACHO)
3017169705Skan    {
3018169705Skan      if (SSE_REGNO_P (regno) && TARGET_SSE)
3019169705Skan        return true;
3020169705Skan    }
3021169705Skan  else
3022169705Skan    {
3023169705Skan      if (TARGET_SSE && SSE_REGNO_P (regno)
3024169705Skan          && (regno < FIRST_SSE_REG + SSE_REGPARM_MAX))
3025169705Skan        return true;
3026169705Skan    }
302790284Sobrien  /* RAX is used as hidden argument to va_arg functions.  */
302890284Sobrien  if (!regno)
302990284Sobrien    return true;
303090284Sobrien  for (i = 0; i < REGPARM_MAX; i++)
303190284Sobrien    if (regno == x86_64_int_parameter_registers[i])
303290284Sobrien      return true;
303390284Sobrien  return false;
303490284Sobrien}
303590284Sobrien
3036169705Skan/* Return if we do not know how to pass TYPE solely in registers.  */
3037169705Skan
3038169705Skanstatic bool
3039169705Skanix86_must_pass_in_stack (enum machine_mode mode, tree type)
3040169705Skan{
3041169705Skan  if (must_pass_in_stack_var_size_or_pad (mode, type))
3042169705Skan    return true;
3043169705Skan
3044169705Skan  /* For 32-bit, we want TImode aggregates to go on the stack.  But watch out!
3045169705Skan     The layout_type routine is crafty and tries to trick us into passing
3046169705Skan     currently unsupported vector types on the stack by using TImode.  */
3047169705Skan  return (!TARGET_64BIT && mode == TImode
3048169705Skan	  && type && TREE_CODE (type) != VECTOR_TYPE);
3049169705Skan}
3050169705Skan
305118334Speter/* Initialize a variable CUM of type CUMULATIVE_ARGS
305218334Speter   for a call to a function whose data type is FNTYPE.
305318334Speter   For a library call, FNTYPE is 0.  */
305418334Speter
305518334Spetervoid
3056132743Skaninit_cumulative_args (CUMULATIVE_ARGS *cum,  /* Argument info to initialize */
3057132743Skan		      tree fntype,	/* tree ptr for function decl */
3058132743Skan		      rtx libname,	/* SYMBOL_REF of library name or 0 */
3059132743Skan		      tree fndecl)
306018334Speter{
306118334Speter  static CUMULATIVE_ARGS zero_cum;
306218334Speter  tree param, next_param;
306318334Speter
306418334Speter  if (TARGET_DEBUG_ARG)
306518334Speter    {
306618334Speter      fprintf (stderr, "\ninit_cumulative_args (");
306718334Speter      if (fntype)
306851411Sobrien	fprintf (stderr, "fntype code = %s, ret code = %s",
306951411Sobrien		 tree_code_name[(int) TREE_CODE (fntype)],
307051411Sobrien		 tree_code_name[(int) TREE_CODE (TREE_TYPE (fntype))]);
307118334Speter      else
307218334Speter	fprintf (stderr, "no fntype");
307318334Speter
307418334Speter      if (libname)
307518334Speter	fprintf (stderr, ", libname = %s", XSTR (libname, 0));
307618334Speter    }
307718334Speter
307818334Speter  *cum = zero_cum;
307918334Speter
308018334Speter  /* Set up the number of registers to use for passing arguments.  */
3081169705Skan  cum->nregs = ix86_regparm;
3082169705Skan  if (TARGET_SSE)
3083169705Skan    cum->sse_nregs = SSE_REGPARM_MAX;
3084169705Skan  if (TARGET_MMX)
3085169705Skan    cum->mmx_nregs = MMX_REGPARM_MAX;
3086132743Skan  cum->warn_sse = true;
3087132743Skan  cum->warn_mmx = true;
3088132743Skan  cum->maybe_vaarg = false;
3089132743Skan
3090169705Skan  /* Use ecx and edx registers if function has fastcall attribute,
3091169705Skan     else look for regparm information.  */
309290284Sobrien  if (fntype && !TARGET_64BIT)
309318334Speter    {
3094132743Skan      if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (fntype)))
3095132743Skan	{
3096132743Skan	  cum->nregs = 2;
3097132743Skan	  cum->fastcall = 1;
3098132743Skan	}
3099169705Skan      else
3100169705Skan	cum->nregs = ix86_function_regparm (fntype, fndecl);
310118334Speter    }
310218334Speter
3103169705Skan  /* Set up the number of SSE registers used for passing SFmode
3104169705Skan     and DFmode arguments.  Warn for mismatching ABI.  */
3105169705Skan  cum->float_in_sse = ix86_function_sseregparm (fntype, fndecl);
3106132743Skan
310718334Speter  /* Determine if this function has variable arguments.  This is
310818334Speter     indicated by the last argument being 'void_type_mode' if there
310918334Speter     are no variable arguments.  If there are variable arguments, then
3110169705Skan     we won't pass anything in registers in 32-bit mode. */
311118334Speter
3112169705Skan  if (cum->nregs || cum->mmx_nregs || cum->sse_nregs)
311318334Speter    {
311418334Speter      for (param = (fntype) ? TYPE_ARG_TYPES (fntype) : 0;
311551411Sobrien	   param != 0; param = next_param)
311618334Speter	{
311718334Speter	  next_param = TREE_CHAIN (param);
311851411Sobrien	  if (next_param == 0 && TREE_VALUE (param) != void_type_node)
311990284Sobrien	    {
312090284Sobrien	      if (!TARGET_64BIT)
3121132743Skan		{
3122132743Skan		  cum->nregs = 0;
3123132743Skan		  cum->sse_nregs = 0;
3124132743Skan		  cum->mmx_nregs = 0;
3125132743Skan		  cum->warn_sse = 0;
3126132743Skan		  cum->warn_mmx = 0;
3127132743Skan		  cum->fastcall = 0;
3128169705Skan		  cum->float_in_sse = 0;
3129132743Skan		}
313090284Sobrien	      cum->maybe_vaarg = true;
313190284Sobrien	    }
313218334Speter	}
313318334Speter    }
313490284Sobrien  if ((!fntype && !libname)
313590284Sobrien      || (fntype && !TYPE_ARG_TYPES (fntype)))
3136169705Skan    cum->maybe_vaarg = true;
313718334Speter
313818334Speter  if (TARGET_DEBUG_ARG)
313918334Speter    fprintf (stderr, ", nregs=%d )\n", cum->nregs);
314018334Speter
314118334Speter  return;
314218334Speter}
314318334Speter
3144169705Skan/* Return the "natural" mode for TYPE.  In most cases, this is just TYPE_MODE.
3145169705Skan   But in the case of vector types, it is some vector mode.
3146169705Skan
3147169705Skan   When we have only some of our vector isa extensions enabled, then there
3148169705Skan   are some modes for which vector_mode_supported_p is false.  For these
3149169705Skan   modes, the generic vector support in gcc will choose some non-vector mode
3150169705Skan   in order to implement the type.  By computing the natural mode, we'll
3151169705Skan   select the proper ABI location for the operand and not depend on whatever
3152169705Skan   the middle-end decides to do with these vector types.  */
3153169705Skan
3154169705Skanstatic enum machine_mode
3155169705Skantype_natural_mode (tree type)
3156169705Skan{
3157169705Skan  enum machine_mode mode = TYPE_MODE (type);
3158169705Skan
3159169705Skan  if (TREE_CODE (type) == VECTOR_TYPE && !VECTOR_MODE_P (mode))
3160169705Skan    {
3161169705Skan      HOST_WIDE_INT size = int_size_in_bytes (type);
3162169705Skan      if ((size == 8 || size == 16)
3163169705Skan	  /* ??? Generic code allows us to create width 1 vectors.  Ignore.  */
3164169705Skan	  && TYPE_VECTOR_SUBPARTS (type) > 1)
3165169705Skan	{
3166169705Skan	  enum machine_mode innermode = TYPE_MODE (TREE_TYPE (type));
3167169705Skan
3168169705Skan	  if (TREE_CODE (TREE_TYPE (type)) == REAL_TYPE)
3169169705Skan	    mode = MIN_MODE_VECTOR_FLOAT;
3170169705Skan	  else
3171169705Skan	    mode = MIN_MODE_VECTOR_INT;
3172169705Skan
3173169705Skan	  /* Get the mode which has this inner mode and number of units.  */
3174169705Skan	  for (; mode != VOIDmode; mode = GET_MODE_WIDER_MODE (mode))
3175169705Skan	    if (GET_MODE_NUNITS (mode) == TYPE_VECTOR_SUBPARTS (type)
3176169705Skan		&& GET_MODE_INNER (mode) == innermode)
3177169705Skan	      return mode;
3178169705Skan
3179169705Skan	  gcc_unreachable ();
3180169705Skan	}
3181169705Skan    }
3182169705Skan
3183169705Skan  return mode;
3184169705Skan}
3185169705Skan
3186169705Skan/* We want to pass a value in REGNO whose "natural" mode is MODE.  However,
3187169705Skan   this may not agree with the mode that the type system has chosen for the
3188169705Skan   register, which is ORIG_MODE.  If ORIG_MODE is not BLKmode, then we can
3189169705Skan   go ahead and use it.  Otherwise we have to build a PARALLEL instead.  */
3190169705Skan
3191169705Skanstatic rtx
3192169705Skangen_reg_or_parallel (enum machine_mode mode, enum machine_mode orig_mode,
3193169705Skan		     unsigned int regno)
3194169705Skan{
3195169705Skan  rtx tmp;
3196169705Skan
3197169705Skan  if (orig_mode != BLKmode)
3198169705Skan    tmp = gen_rtx_REG (orig_mode, regno);
3199169705Skan  else
3200169705Skan    {
3201169705Skan      tmp = gen_rtx_REG (mode, regno);
3202169705Skan      tmp = gen_rtx_EXPR_LIST (VOIDmode, tmp, const0_rtx);
3203169705Skan      tmp = gen_rtx_PARALLEL (orig_mode, gen_rtvec (1, tmp));
3204169705Skan    }
3205169705Skan
3206169705Skan  return tmp;
3207169705Skan}
3208169705Skan
3209132743Skan/* x86-64 register passing implementation.  See x86-64 ABI for details.  Goal
321090284Sobrien   of this code is to classify each 8bytes of incoming argument by the register
321190284Sobrien   class and assign registers accordingly.  */
321290284Sobrien
321390284Sobrien/* Return the union class of CLASS1 and CLASS2.
321490284Sobrien   See the x86-64 PS ABI for details.  */
321590284Sobrien
321690284Sobrienstatic enum x86_64_reg_class
3217132743Skanmerge_classes (enum x86_64_reg_class class1, enum x86_64_reg_class class2)
321890284Sobrien{
321990284Sobrien  /* Rule #1: If both classes are equal, this is the resulting class.  */
322090284Sobrien  if (class1 == class2)
322190284Sobrien    return class1;
322290284Sobrien
322390284Sobrien  /* Rule #2: If one of the classes is NO_CLASS, the resulting class is
322490284Sobrien     the other class.  */
322590284Sobrien  if (class1 == X86_64_NO_CLASS)
322690284Sobrien    return class2;
322790284Sobrien  if (class2 == X86_64_NO_CLASS)
322890284Sobrien    return class1;
322990284Sobrien
323090284Sobrien  /* Rule #3: If one of the classes is MEMORY, the result is MEMORY.  */
323190284Sobrien  if (class1 == X86_64_MEMORY_CLASS || class2 == X86_64_MEMORY_CLASS)
323290284Sobrien    return X86_64_MEMORY_CLASS;
323390284Sobrien
323490284Sobrien  /* Rule #4: If one of the classes is INTEGER, the result is INTEGER.  */
323590284Sobrien  if ((class1 == X86_64_INTEGERSI_CLASS && class2 == X86_64_SSESF_CLASS)
323690284Sobrien      || (class2 == X86_64_INTEGERSI_CLASS && class1 == X86_64_SSESF_CLASS))
323790284Sobrien    return X86_64_INTEGERSI_CLASS;
323890284Sobrien  if (class1 == X86_64_INTEGER_CLASS || class1 == X86_64_INTEGERSI_CLASS
323990284Sobrien      || class2 == X86_64_INTEGER_CLASS || class2 == X86_64_INTEGERSI_CLASS)
324090284Sobrien    return X86_64_INTEGER_CLASS;
324190284Sobrien
3242169705Skan  /* Rule #5: If one of the classes is X87, X87UP, or COMPLEX_X87 class,
3243169705Skan     MEMORY is used.  */
3244169705Skan  if (class1 == X86_64_X87_CLASS
3245169705Skan      || class1 == X86_64_X87UP_CLASS
3246169705Skan      || class1 == X86_64_COMPLEX_X87_CLASS
3247169705Skan      || class2 == X86_64_X87_CLASS
3248169705Skan      || class2 == X86_64_X87UP_CLASS
3249169705Skan      || class2 == X86_64_COMPLEX_X87_CLASS)
325090284Sobrien    return X86_64_MEMORY_CLASS;
325190284Sobrien
325290284Sobrien  /* Rule #6: Otherwise class SSE is used.  */
325390284Sobrien  return X86_64_SSE_CLASS;
325490284Sobrien}
325590284Sobrien
325690284Sobrien/* Classify the argument of type TYPE and mode MODE.
325790284Sobrien   CLASSES will be filled by the register class used to pass each word
325890284Sobrien   of the operand.  The number of words is returned.  In case the parameter
325990284Sobrien   should be passed in memory, 0 is returned. As a special case for zero
326090284Sobrien   sized containers, classes[0] will be NO_CLASS and 1 is returned.
326190284Sobrien
326290284Sobrien   BIT_OFFSET is used internally for handling records and specifies offset
326390284Sobrien   of the offset in bits modulo 256 to avoid overflow cases.
326490284Sobrien
326590284Sobrien   See the x86-64 PS ABI for details.
326690284Sobrien*/
326790284Sobrien
326890284Sobrienstatic int
3269132743Skanclassify_argument (enum machine_mode mode, tree type,
3270132743Skan		   enum x86_64_reg_class classes[MAX_CLASSES], int bit_offset)
327190284Sobrien{
3272132743Skan  HOST_WIDE_INT bytes =
327390284Sobrien    (mode == BLKmode) ? int_size_in_bytes (type) : (int) GET_MODE_SIZE (mode);
3274104767Skan  int words = (bytes + (bit_offset % 64) / 8 + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
327590284Sobrien
3276117408Skan  /* Variable sized entities are always passed/returned in memory.  */
3277117408Skan  if (bytes < 0)
3278104767Skan    return 0;
3279104767Skan
3280132743Skan  if (mode != VOIDmode
3281169705Skan      && targetm.calls.must_pass_in_stack (mode, type))
3282132743Skan    return 0;
3283132743Skan
328490284Sobrien  if (type && AGGREGATE_TYPE_P (type))
328590284Sobrien    {
328690284Sobrien      int i;
328790284Sobrien      tree field;
328890284Sobrien      enum x86_64_reg_class subclasses[MAX_CLASSES];
328990284Sobrien
329090284Sobrien      /* On x86-64 we pass structures larger than 16 bytes on the stack.  */
329190284Sobrien      if (bytes > 16)
329290284Sobrien	return 0;
329390284Sobrien
329490284Sobrien      for (i = 0; i < words; i++)
329590284Sobrien	classes[i] = X86_64_NO_CLASS;
329690284Sobrien
329790284Sobrien      /* Zero sized arrays or structures are NO_CLASS.  We return 0 to
329890284Sobrien	 signalize memory class, so handle it as special case.  */
329990284Sobrien      if (!words)
330090284Sobrien	{
330190284Sobrien	  classes[0] = X86_64_NO_CLASS;
330290284Sobrien	  return 1;
330390284Sobrien	}
330490284Sobrien
330590284Sobrien      /* Classify each field of record and merge classes.  */
3306169705Skan      switch (TREE_CODE (type))
330790284Sobrien	{
3308169705Skan	case RECORD_TYPE:
3309102800Skan	  /* For classes first merge in the field of the subclasses.  */
3310169705Skan	  if (TYPE_BINFO (type))
3311102800Skan	    {
3312169705Skan	      tree binfo, base_binfo;
3313169705Skan	      int basenum;
3314102800Skan
3315169705Skan	      for (binfo = TYPE_BINFO (type), basenum = 0;
3316169705Skan		   BINFO_BASE_ITERATE (binfo, basenum, base_binfo); basenum++)
3317102800Skan		{
3318102800Skan		   int num;
3319169705Skan		   int offset = tree_low_cst (BINFO_OFFSET (base_binfo), 0) * 8;
3320169705Skan		   tree type = BINFO_TYPE (base_binfo);
3321102800Skan
3322102800Skan		   num = classify_argument (TYPE_MODE (type),
3323102800Skan					    type, subclasses,
3324102800Skan					    (offset + bit_offset) % 256);
3325102800Skan		   if (!num)
3326102800Skan		     return 0;
3327102800Skan		   for (i = 0; i < num; i++)
3328102800Skan		     {
3329117408Skan		       int pos = (offset + (bit_offset % 64)) / 8 / 8;
3330102800Skan		       classes[i + pos] =
3331102800Skan			 merge_classes (subclasses[i], classes[i + pos]);
3332102800Skan		     }
3333102800Skan		}
3334102800Skan	    }
3335132743Skan	  /* And now merge the fields of structure.  */
333690284Sobrien	  for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
333790284Sobrien	    {
333890284Sobrien	      if (TREE_CODE (field) == FIELD_DECL)
333990284Sobrien		{
334090284Sobrien		  int num;
334190284Sobrien
3342169705Skan		  if (TREE_TYPE (field) == error_mark_node)
3343169705Skan		    continue;
3344169705Skan
334590284Sobrien		  /* Bitfields are always classified as integer.  Handle them
334690284Sobrien		     early, since later code would consider them to be
334790284Sobrien		     misaligned integers.  */
334890284Sobrien		  if (DECL_BIT_FIELD (field))
334990284Sobrien		    {
3350169705Skan		      for (i = (int_bit_position (field) + (bit_offset % 64)) / 8 / 8;
3351169705Skan			   i < ((int_bit_position (field) + (bit_offset % 64))
335290284Sobrien			        + tree_low_cst (DECL_SIZE (field), 0)
3353132743Skan				+ 63) / 8 / 8; i++)
335490284Sobrien			classes[i] =
335590284Sobrien			  merge_classes (X86_64_INTEGER_CLASS,
335690284Sobrien					 classes[i]);
335790284Sobrien		    }
335890284Sobrien		  else
335990284Sobrien		    {
336090284Sobrien		      num = classify_argument (TYPE_MODE (TREE_TYPE (field)),
336190284Sobrien					       TREE_TYPE (field), subclasses,
336290284Sobrien					       (int_bit_position (field)
336390284Sobrien						+ bit_offset) % 256);
336490284Sobrien		      if (!num)
336590284Sobrien			return 0;
336690284Sobrien		      for (i = 0; i < num; i++)
336790284Sobrien			{
336890284Sobrien			  int pos =
3369117408Skan			    (int_bit_position (field) + (bit_offset % 64)) / 8 / 8;
337090284Sobrien			  classes[i + pos] =
337190284Sobrien			    merge_classes (subclasses[i], classes[i + pos]);
337290284Sobrien			}
337390284Sobrien		    }
337490284Sobrien		}
337590284Sobrien	    }
3376169705Skan	  break;
337790284Sobrien
3378169705Skan	case ARRAY_TYPE:
3379169705Skan	  /* Arrays are handled as small records.  */
3380169705Skan	  {
3381169705Skan	    int num;
3382169705Skan	    num = classify_argument (TYPE_MODE (TREE_TYPE (type)),
3383169705Skan				     TREE_TYPE (type), subclasses, bit_offset);
3384169705Skan	    if (!num)
3385169705Skan	      return 0;
338690284Sobrien
3387169705Skan	    /* The partial classes are now full classes.  */
3388169705Skan	    if (subclasses[0] == X86_64_SSESF_CLASS && bytes != 4)
3389169705Skan	      subclasses[0] = X86_64_SSE_CLASS;
3390169705Skan	    if (subclasses[0] == X86_64_INTEGERSI_CLASS && bytes != 4)
3391169705Skan	      subclasses[0] = X86_64_INTEGER_CLASS;
3392102800Skan
3393169705Skan	    for (i = 0; i < words; i++)
3394169705Skan	      classes[i] = subclasses[i % num];
3395102800Skan
3396169705Skan	    break;
3397169705Skan	  }
3398169705Skan	case UNION_TYPE:
3399169705Skan	case QUAL_UNION_TYPE:
3400169705Skan	  /* Unions are similar to RECORD_TYPE but offset is always 0.
3401169705Skan	     */
3402169705Skan
3403169705Skan	  /* Unions are not derived.  */
3404169705Skan	  gcc_assert (!TYPE_BINFO (type)
3405169705Skan		      || !BINFO_N_BASE_BINFOS (TYPE_BINFO (type)));
340690284Sobrien	  for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
340790284Sobrien	    {
340890284Sobrien	      if (TREE_CODE (field) == FIELD_DECL)
340990284Sobrien		{
341090284Sobrien		  int num;
3411169705Skan
3412169705Skan		  if (TREE_TYPE (field) == error_mark_node)
3413169705Skan		    continue;
3414169705Skan
341590284Sobrien		  num = classify_argument (TYPE_MODE (TREE_TYPE (field)),
341690284Sobrien					   TREE_TYPE (field), subclasses,
341790284Sobrien					   bit_offset);
341890284Sobrien		  if (!num)
341990284Sobrien		    return 0;
342090284Sobrien		  for (i = 0; i < num; i++)
342190284Sobrien		    classes[i] = merge_classes (subclasses[i], classes[i]);
342290284Sobrien		}
342390284Sobrien	    }
3424169705Skan	  break;
3425169705Skan
3426169705Skan	default:
3427169705Skan	  gcc_unreachable ();
342890284Sobrien	}
342990284Sobrien
343090284Sobrien      /* Final merger cleanup.  */
343190284Sobrien      for (i = 0; i < words; i++)
343290284Sobrien	{
343390284Sobrien	  /* If one class is MEMORY, everything should be passed in
343490284Sobrien	     memory.  */
343590284Sobrien	  if (classes[i] == X86_64_MEMORY_CLASS)
343690284Sobrien	    return 0;
343790284Sobrien
343890284Sobrien	  /* The X86_64_SSEUP_CLASS should be always preceded by
343990284Sobrien	     X86_64_SSE_CLASS.  */
344090284Sobrien	  if (classes[i] == X86_64_SSEUP_CLASS
344190284Sobrien	      && (i == 0 || classes[i - 1] != X86_64_SSE_CLASS))
344290284Sobrien	    classes[i] = X86_64_SSE_CLASS;
344390284Sobrien
344490284Sobrien	  /*  X86_64_X87UP_CLASS should be preceded by X86_64_X87_CLASS.  */
344590284Sobrien	  if (classes[i] == X86_64_X87UP_CLASS
344690284Sobrien	      && (i == 0 || classes[i - 1] != X86_64_X87_CLASS))
344790284Sobrien	    classes[i] = X86_64_SSE_CLASS;
344890284Sobrien	}
344990284Sobrien      return words;
345090284Sobrien    }
345190284Sobrien
345290284Sobrien  /* Compute alignment needed.  We align all types to natural boundaries with
345390284Sobrien     exception of XFmode that is aligned to 64bits.  */
345490284Sobrien  if (mode != VOIDmode && mode != BLKmode)
345590284Sobrien    {
345690284Sobrien      int mode_alignment = GET_MODE_BITSIZE (mode);
345790284Sobrien
345890284Sobrien      if (mode == XFmode)
345990284Sobrien	mode_alignment = 128;
346090284Sobrien      else if (mode == XCmode)
346190284Sobrien	mode_alignment = 256;
3462132743Skan      if (COMPLEX_MODE_P (mode))
3463132743Skan	mode_alignment /= 2;
346490284Sobrien      /* Misaligned fields are always returned in memory.  */
346590284Sobrien      if (bit_offset % mode_alignment)
346690284Sobrien	return 0;
346790284Sobrien    }
346890284Sobrien
3469169705Skan  /* for V1xx modes, just use the base mode */
3470169705Skan  if (VECTOR_MODE_P (mode)
3471169705Skan      && GET_MODE_SIZE (GET_MODE_INNER (mode)) == bytes)
3472169705Skan    mode = GET_MODE_INNER (mode);
3473169705Skan
347490284Sobrien  /* Classification of atomic types.  */
347590284Sobrien  switch (mode)
347690284Sobrien    {
3477169705Skan    case SDmode:
3478169705Skan    case DDmode:
3479169705Skan      classes[0] = X86_64_SSE_CLASS;
3480169705Skan      return 1;
3481169705Skan    case TDmode:
3482169705Skan      classes[0] = X86_64_SSE_CLASS;
3483169705Skan      classes[1] = X86_64_SSEUP_CLASS;
3484169705Skan      return 2;
348590284Sobrien    case DImode:
348690284Sobrien    case SImode:
348790284Sobrien    case HImode:
348890284Sobrien    case QImode:
348990284Sobrien    case CSImode:
349090284Sobrien    case CHImode:
349190284Sobrien    case CQImode:
349290284Sobrien      if (bit_offset + GET_MODE_BITSIZE (mode) <= 32)
349390284Sobrien	classes[0] = X86_64_INTEGERSI_CLASS;
349490284Sobrien      else
349590284Sobrien	classes[0] = X86_64_INTEGER_CLASS;
349690284Sobrien      return 1;
349790284Sobrien    case CDImode:
349890284Sobrien    case TImode:
349990284Sobrien      classes[0] = classes[1] = X86_64_INTEGER_CLASS;
350090284Sobrien      return 2;
350190284Sobrien    case CTImode:
3502169705Skan      return 0;
350390284Sobrien    case SFmode:
350490284Sobrien      if (!(bit_offset % 64))
350590284Sobrien	classes[0] = X86_64_SSESF_CLASS;
350690284Sobrien      else
350790284Sobrien	classes[0] = X86_64_SSE_CLASS;
350890284Sobrien      return 1;
350990284Sobrien    case DFmode:
351090284Sobrien      classes[0] = X86_64_SSEDF_CLASS;
351190284Sobrien      return 1;
3512132743Skan    case XFmode:
351390284Sobrien      classes[0] = X86_64_X87_CLASS;
351490284Sobrien      classes[1] = X86_64_X87UP_CLASS;
351590284Sobrien      return 2;
3516132743Skan    case TFmode:
3517169705Skan      classes[0] = X86_64_SSE_CLASS;
3518169705Skan      classes[1] = X86_64_SSEUP_CLASS;
3519169705Skan      return 2;
3520169705Skan    case SCmode:
3521169705Skan      classes[0] = X86_64_SSE_CLASS;
3522169705Skan      return 1;
352390284Sobrien    case DCmode:
352490284Sobrien      classes[0] = X86_64_SSEDF_CLASS;
352590284Sobrien      classes[1] = X86_64_SSEDF_CLASS;
352690284Sobrien      return 2;
3527169705Skan    case XCmode:
3528169705Skan      classes[0] = X86_64_COMPLEX_X87_CLASS;
352990284Sobrien      return 1;
3530169705Skan    case TCmode:
3531169705Skan      /* This modes is larger than 16 bytes.  */
3532169705Skan      return 0;
353396293Sobrien    case V4SFmode:
353496293Sobrien    case V4SImode:
3535117408Skan    case V16QImode:
3536117408Skan    case V8HImode:
3537117408Skan    case V2DFmode:
3538117408Skan    case V2DImode:
353996293Sobrien      classes[0] = X86_64_SSE_CLASS;
354096293Sobrien      classes[1] = X86_64_SSEUP_CLASS;
354196293Sobrien      return 2;
354296293Sobrien    case V2SFmode:
354396293Sobrien    case V2SImode:
354496293Sobrien    case V4HImode:
354596293Sobrien    case V8QImode:
3546169705Skan      classes[0] = X86_64_SSE_CLASS;
3547169705Skan      return 1;
354890284Sobrien    case BLKmode:
354996293Sobrien    case VOIDmode:
355090284Sobrien      return 0;
355190284Sobrien    default:
3552169705Skan      gcc_assert (VECTOR_MODE_P (mode));
3553169705Skan
3554169705Skan      if (bytes > 16)
3555169705Skan	return 0;
3556169705Skan
3557169705Skan      gcc_assert (GET_MODE_CLASS (GET_MODE_INNER (mode)) == MODE_INT);
3558169705Skan
3559169705Skan      if (bit_offset + GET_MODE_BITSIZE (mode) <= 32)
3560169705Skan	classes[0] = X86_64_INTEGERSI_CLASS;
3561169705Skan      else
3562169705Skan	classes[0] = X86_64_INTEGER_CLASS;
3563169705Skan      classes[1] = X86_64_INTEGER_CLASS;
3564169705Skan      return 1 + (bytes > 8);
356590284Sobrien    }
356690284Sobrien}
356790284Sobrien
356890284Sobrien/* Examine the argument and return set number of register required in each
356990284Sobrien   class.  Return 0 iff parameter should be passed in memory.  */
357090284Sobrienstatic int
3571132743Skanexamine_argument (enum machine_mode mode, tree type, int in_return,
3572132743Skan		  int *int_nregs, int *sse_nregs)
357390284Sobrien{
357490284Sobrien  enum x86_64_reg_class class[MAX_CLASSES];
357590284Sobrien  int n = classify_argument (mode, type, class, 0);
357690284Sobrien
357790284Sobrien  *int_nregs = 0;
357890284Sobrien  *sse_nregs = 0;
357990284Sobrien  if (!n)
358090284Sobrien    return 0;
358190284Sobrien  for (n--; n >= 0; n--)
358290284Sobrien    switch (class[n])
358390284Sobrien      {
358490284Sobrien      case X86_64_INTEGER_CLASS:
358590284Sobrien      case X86_64_INTEGERSI_CLASS:
358690284Sobrien	(*int_nregs)++;
358790284Sobrien	break;
358890284Sobrien      case X86_64_SSE_CLASS:
358990284Sobrien      case X86_64_SSESF_CLASS:
359090284Sobrien      case X86_64_SSEDF_CLASS:
359190284Sobrien	(*sse_nregs)++;
359290284Sobrien	break;
359390284Sobrien      case X86_64_NO_CLASS:
359490284Sobrien      case X86_64_SSEUP_CLASS:
359590284Sobrien	break;
359690284Sobrien      case X86_64_X87_CLASS:
359790284Sobrien      case X86_64_X87UP_CLASS:
359890284Sobrien	if (!in_return)
359990284Sobrien	  return 0;
360090284Sobrien	break;
3601169705Skan      case X86_64_COMPLEX_X87_CLASS:
3602169705Skan	return in_return ? 2 : 0;
360390284Sobrien      case X86_64_MEMORY_CLASS:
3604169705Skan	gcc_unreachable ();
360590284Sobrien      }
360690284Sobrien  return 1;
360790284Sobrien}
3608169705Skan
360990284Sobrien/* Construct container for the argument used by GCC interface.  See
361090284Sobrien   FUNCTION_ARG for the detailed description.  */
3611169705Skan
361290284Sobrienstatic rtx
3613169705Skanconstruct_container (enum machine_mode mode, enum machine_mode orig_mode,
3614169705Skan		     tree type, int in_return, int nintregs, int nsseregs,
3615169705Skan		     const int *intreg, int sse_regno)
361690284Sobrien{
3617169705Skan  /* The following variables hold the static issued_error state.  */
3618169705Skan  static bool issued_sse_arg_error;
3619169705Skan  static bool issued_sse_ret_error;
3620169705Skan  static bool issued_x87_ret_error;
3621169705Skan
362290284Sobrien  enum machine_mode tmpmode;
362390284Sobrien  int bytes =
362490284Sobrien    (mode == BLKmode) ? int_size_in_bytes (type) : (int) GET_MODE_SIZE (mode);
362590284Sobrien  enum x86_64_reg_class class[MAX_CLASSES];
362690284Sobrien  int n;
362790284Sobrien  int i;
362890284Sobrien  int nexps = 0;
362990284Sobrien  int needed_sseregs, needed_intregs;
363090284Sobrien  rtx exp[MAX_CLASSES];
363190284Sobrien  rtx ret;
363290284Sobrien
363390284Sobrien  n = classify_argument (mode, type, class, 0);
363490284Sobrien  if (TARGET_DEBUG_ARG)
363590284Sobrien    {
363690284Sobrien      if (!n)
363790284Sobrien	fprintf (stderr, "Memory class\n");
363890284Sobrien      else
363990284Sobrien	{
364090284Sobrien	  fprintf (stderr, "Classes:");
364190284Sobrien	  for (i = 0; i < n; i++)
364290284Sobrien	    {
364390284Sobrien	      fprintf (stderr, " %s", x86_64_reg_class_name[class[i]]);
364490284Sobrien	    }
364590284Sobrien	   fprintf (stderr, "\n");
364690284Sobrien	}
364790284Sobrien    }
364890284Sobrien  if (!n)
364990284Sobrien    return NULL;
3650169705Skan  if (!examine_argument (mode, type, in_return, &needed_intregs,
3651169705Skan			 &needed_sseregs))
365290284Sobrien    return NULL;
365390284Sobrien  if (needed_intregs > nintregs || needed_sseregs > nsseregs)
365490284Sobrien    return NULL;
365590284Sobrien
3656169705Skan  /* We allowed the user to turn off SSE for kernel mode.  Don't crash if
3657169705Skan     some less clueful developer tries to use floating-point anyway.  */
3658169705Skan  if (needed_sseregs && !TARGET_SSE)
3659169705Skan    {
3660169705Skan      if (in_return)
3661169705Skan	{
3662169705Skan	  if (!issued_sse_ret_error)
3663169705Skan	    {
3664169705Skan	      error ("SSE register return with SSE disabled");
3665169705Skan	      issued_sse_ret_error = true;
3666169705Skan	    }
3667169705Skan	}
3668169705Skan      else if (!issued_sse_arg_error)
3669169705Skan	{
3670169705Skan	  error ("SSE register argument with SSE disabled");
3671169705Skan	  issued_sse_arg_error = true;
3672169705Skan	}
3673169705Skan      return NULL;
3674169705Skan    }
3675169705Skan
3676169705Skan  /* Likewise, error if the ABI requires us to return values in the
3677169705Skan     x87 registers and the user specified -mno-80387.  */
3678169705Skan  if (!TARGET_80387 && in_return)
3679169705Skan    for (i = 0; i < n; i++)
3680169705Skan      if (class[i] == X86_64_X87_CLASS
3681169705Skan	  || class[i] == X86_64_X87UP_CLASS
3682169705Skan	  || class[i] == X86_64_COMPLEX_X87_CLASS)
3683169705Skan	{
3684169705Skan	  if (!issued_x87_ret_error)
3685169705Skan	    {
3686169705Skan	      error ("x87 register return with x87 disabled");
3687169705Skan	      issued_x87_ret_error = true;
3688169705Skan	    }
3689169705Skan	  return NULL;
3690169705Skan	}
3691169705Skan
369290284Sobrien  /* First construct simple cases.  Avoid SCmode, since we want to use
369390284Sobrien     single register to pass this type.  */
369490284Sobrien  if (n == 1 && mode != SCmode)
369590284Sobrien    switch (class[0])
369690284Sobrien      {
369790284Sobrien      case X86_64_INTEGER_CLASS:
369890284Sobrien      case X86_64_INTEGERSI_CLASS:
369990284Sobrien	return gen_rtx_REG (mode, intreg[0]);
370090284Sobrien      case X86_64_SSE_CLASS:
370190284Sobrien      case X86_64_SSESF_CLASS:
370290284Sobrien      case X86_64_SSEDF_CLASS:
3703169705Skan	return gen_reg_or_parallel (mode, orig_mode, SSE_REGNO (sse_regno));
370490284Sobrien      case X86_64_X87_CLASS:
3705169705Skan      case X86_64_COMPLEX_X87_CLASS:
370690284Sobrien	return gen_rtx_REG (mode, FIRST_STACK_REG);
370790284Sobrien      case X86_64_NO_CLASS:
370890284Sobrien	/* Zero sized array, struct or class.  */
370990284Sobrien	return NULL;
371090284Sobrien      default:
3711169705Skan	gcc_unreachable ();
371290284Sobrien      }
3713132743Skan  if (n == 2 && class[0] == X86_64_SSE_CLASS && class[1] == X86_64_SSEUP_CLASS
3714132743Skan      && mode != BLKmode)
371596293Sobrien    return gen_rtx_REG (mode, SSE_REGNO (sse_regno));
371690284Sobrien  if (n == 2
371790284Sobrien      && class[0] == X86_64_X87_CLASS && class[1] == X86_64_X87UP_CLASS)
3718132743Skan    return gen_rtx_REG (XFmode, FIRST_STACK_REG);
371990284Sobrien  if (n == 2 && class[0] == X86_64_INTEGER_CLASS
372090284Sobrien      && class[1] == X86_64_INTEGER_CLASS
3721132743Skan      && (mode == CDImode || mode == TImode || mode == TFmode)
372290284Sobrien      && intreg[0] + 1 == intreg[1])
372390284Sobrien    return gen_rtx_REG (mode, intreg[0]);
372490284Sobrien
372590284Sobrien  /* Otherwise figure out the entries of the PARALLEL.  */
372690284Sobrien  for (i = 0; i < n; i++)
372790284Sobrien    {
372890284Sobrien      switch (class[i])
372990284Sobrien        {
373090284Sobrien	  case X86_64_NO_CLASS:
373190284Sobrien	    break;
373290284Sobrien	  case X86_64_INTEGER_CLASS:
373390284Sobrien	  case X86_64_INTEGERSI_CLASS:
3734132743Skan	    /* Merge TImodes on aligned occasions here too.  */
373590284Sobrien	    if (i * 8 + 8 > bytes)
373690284Sobrien	      tmpmode = mode_for_size ((bytes - i * 8) * BITS_PER_UNIT, MODE_INT, 0);
373790284Sobrien	    else if (class[i] == X86_64_INTEGERSI_CLASS)
373890284Sobrien	      tmpmode = SImode;
373990284Sobrien	    else
374090284Sobrien	      tmpmode = DImode;
374190284Sobrien	    /* We've requested 24 bytes we don't have mode for.  Use DImode.  */
374290284Sobrien	    if (tmpmode == BLKmode)
374390284Sobrien	      tmpmode = DImode;
374490284Sobrien	    exp [nexps++] = gen_rtx_EXPR_LIST (VOIDmode,
374590284Sobrien					       gen_rtx_REG (tmpmode, *intreg),
374690284Sobrien					       GEN_INT (i*8));
374790284Sobrien	    intreg++;
374890284Sobrien	    break;
374990284Sobrien	  case X86_64_SSESF_CLASS:
375090284Sobrien	    exp [nexps++] = gen_rtx_EXPR_LIST (VOIDmode,
375190284Sobrien					       gen_rtx_REG (SFmode,
375290284Sobrien							    SSE_REGNO (sse_regno)),
375390284Sobrien					       GEN_INT (i*8));
375490284Sobrien	    sse_regno++;
375590284Sobrien	    break;
375690284Sobrien	  case X86_64_SSEDF_CLASS:
375790284Sobrien	    exp [nexps++] = gen_rtx_EXPR_LIST (VOIDmode,
375890284Sobrien					       gen_rtx_REG (DFmode,
375990284Sobrien							    SSE_REGNO (sse_regno)),
376090284Sobrien					       GEN_INT (i*8));
376190284Sobrien	    sse_regno++;
376290284Sobrien	    break;
376390284Sobrien	  case X86_64_SSE_CLASS:
376496293Sobrien	    if (i < n - 1 && class[i + 1] == X86_64_SSEUP_CLASS)
3765117408Skan	      tmpmode = TImode;
376690284Sobrien	    else
376790284Sobrien	      tmpmode = DImode;
376890284Sobrien	    exp [nexps++] = gen_rtx_EXPR_LIST (VOIDmode,
376990284Sobrien					       gen_rtx_REG (tmpmode,
377090284Sobrien							    SSE_REGNO (sse_regno)),
377190284Sobrien					       GEN_INT (i*8));
3772117408Skan	    if (tmpmode == TImode)
3773117408Skan	      i++;
377490284Sobrien	    sse_regno++;
377590284Sobrien	    break;
377690284Sobrien	  default:
3777169705Skan	    gcc_unreachable ();
377890284Sobrien	}
377990284Sobrien    }
3780169705Skan
3781169705Skan  /* Empty aligned struct, union or class.  */
3782169705Skan  if (nexps == 0)
3783169705Skan    return NULL;
3784169705Skan
378590284Sobrien  ret =  gen_rtx_PARALLEL (mode, rtvec_alloc (nexps));
378690284Sobrien  for (i = 0; i < nexps; i++)
378790284Sobrien    XVECEXP (ret, 0, i) = exp [i];
378890284Sobrien  return ret;
378990284Sobrien}
379090284Sobrien
379118334Speter/* Update the data in CUM to advance over an argument
379218334Speter   of mode MODE and data type TYPE.
379318334Speter   (TYPE is null for libcalls where that information may not be available.)  */
379418334Speter
379518334Spetervoid
3796169705Skanfunction_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
3797169705Skan		      tree type, int named)
379818334Speter{
379990284Sobrien  int bytes =
380090284Sobrien    (mode == BLKmode) ? int_size_in_bytes (type) : (int) GET_MODE_SIZE (mode);
380118334Speter  int words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
380218334Speter
3803169705Skan  if (type)
3804169705Skan    mode = type_natural_mode (type);
3805169705Skan
380618334Speter  if (TARGET_DEBUG_ARG)
3807169705Skan    fprintf (stderr, "function_adv (sz=%d, wds=%2d, nregs=%d, ssenregs=%d, "
3808169705Skan	     "mode=%s, named=%d)\n\n",
3809169705Skan	     words, cum->words, cum->nregs, cum->sse_nregs,
3810169705Skan	     GET_MODE_NAME (mode), named);
3811169705Skan
381290284Sobrien  if (TARGET_64BIT)
381318334Speter    {
381490284Sobrien      int int_nregs, sse_nregs;
381590284Sobrien      if (!examine_argument (mode, type, 0, &int_nregs, &sse_nregs))
381690284Sobrien	cum->words += words;
381790284Sobrien      else if (sse_nregs <= cum->sse_nregs && int_nregs <= cum->nregs)
381890284Sobrien	{
381990284Sobrien	  cum->nregs -= int_nregs;
382090284Sobrien	  cum->sse_nregs -= sse_nregs;
382190284Sobrien	  cum->regno += int_nregs;
382290284Sobrien	  cum->sse_regno += sse_nregs;
382390284Sobrien	}
382490284Sobrien      else
382590284Sobrien	cum->words += words;
382618334Speter    }
382790284Sobrien  else
382890284Sobrien    {
3829169705Skan      switch (mode)
383090284Sobrien	{
3831169705Skan	default:
3832169705Skan	  break;
3833169705Skan
3834169705Skan	case BLKmode:
3835169705Skan	  if (bytes < 0)
3836169705Skan	    break;
3837169705Skan	  /* FALLTHRU */
3838169705Skan
3839169705Skan	case DImode:
3840169705Skan	case SImode:
3841169705Skan	case HImode:
3842169705Skan	case QImode:
384390284Sobrien	  cum->words += words;
384490284Sobrien	  cum->nregs -= words;
384590284Sobrien	  cum->regno += words;
384618334Speter
384790284Sobrien	  if (cum->nregs <= 0)
384890284Sobrien	    {
384990284Sobrien	      cum->nregs = 0;
385090284Sobrien	      cum->regno = 0;
385190284Sobrien	    }
3852169705Skan	  break;
385318334Speter
3854169705Skan	case DFmode:
3855169705Skan	  if (cum->float_in_sse < 2)
3856169705Skan	    break;
3857169705Skan	case SFmode:
3858169705Skan	  if (cum->float_in_sse < 1)
3859169705Skan	    break;
3860169705Skan	  /* FALLTHRU */
3861146908Skan
3862169705Skan	case TImode:
3863169705Skan	case V16QImode:
3864169705Skan	case V8HImode:
3865169705Skan	case V4SImode:
3866169705Skan	case V2DImode:
3867169705Skan	case V4SFmode:
3868169705Skan	case V2DFmode:
3869169705Skan	  if (!type || !AGGREGATE_TYPE_P (type))
3870169705Skan	    {
3871169705Skan	      cum->sse_words += words;
3872169705Skan	      cum->sse_nregs -= 1;
3873169705Skan	      cum->sse_regno += 1;
3874169705Skan	      if (cum->sse_nregs <= 0)
3875169705Skan		{
3876169705Skan		  cum->sse_nregs = 0;
3877169705Skan		  cum->sse_regno = 0;
3878169705Skan		}
3879169705Skan	    }
3880169705Skan	  break;
3881146908Skan
3882169705Skan	case V8QImode:
3883169705Skan	case V4HImode:
3884169705Skan	case V2SImode:
3885169705Skan	case V2SFmode:
3886169705Skan	  if (!type || !AGGREGATE_TYPE_P (type))
3887169705Skan	    {
3888169705Skan	      cum->mmx_words += words;
3889169705Skan	      cum->mmx_nregs -= 1;
3890169705Skan	      cum->mmx_regno += 1;
3891169705Skan	      if (cum->mmx_nregs <= 0)
3892169705Skan		{
3893169705Skan		  cum->mmx_nregs = 0;
3894169705Skan		  cum->mmx_regno = 0;
3895169705Skan		}
3896169705Skan	    }
3897169705Skan	  break;
3898169705Skan	}
3899146908Skan    }
3900146908Skan}
3901146908Skan
390218334Speter/* Define where to put the arguments to a function.
390318334Speter   Value is zero to push the argument on the stack,
390418334Speter   or a hard register in which to store the argument.
390518334Speter
390618334Speter   MODE is the argument's machine mode.
390718334Speter   TYPE is the data type of the argument (as a tree).
390818334Speter    This is null for libcalls where that information may
390918334Speter    not be available.
391018334Speter   CUM is a variable of type CUMULATIVE_ARGS which gives info about
391118334Speter    the preceding args and about the function being called.
391218334Speter   NAMED is nonzero if this argument is a named parameter
391318334Speter    (otherwise it is an extra parameter matching an ellipsis).  */
391418334Speter
391590284Sobrienrtx
3916146908Skanfunction_arg (CUMULATIVE_ARGS *cum, enum machine_mode orig_mode,
3917146908Skan	      tree type, int named)
391818334Speter{
3919146908Skan  enum machine_mode mode = orig_mode;
3920146908Skan  rtx ret = NULL_RTX;
392190284Sobrien  int bytes =
392290284Sobrien    (mode == BLKmode) ? int_size_in_bytes (type) : (int) GET_MODE_SIZE (mode);
392318334Speter  int words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
3924132743Skan  static bool warnedsse, warnedmmx;
392518334Speter
3926169705Skan  /* To simplify the code below, represent vector types with a vector mode
3927169705Skan     even if MMX/SSE are not active.  */
3928169705Skan  if (type && TREE_CODE (type) == VECTOR_TYPE)
3929169705Skan    mode = type_natural_mode (type);
3930169705Skan
3931132743Skan  /* Handle a hidden AL argument containing number of registers for varargs
393290284Sobrien     x86-64 functions.  For i386 ABI just return constm1_rtx to avoid
393390284Sobrien     any AL settings.  */
393490284Sobrien  if (mode == VOIDmode)
393518334Speter    {
393690284Sobrien      if (TARGET_64BIT)
393790284Sobrien	return GEN_INT (cum->maybe_vaarg
393890284Sobrien			? (cum->sse_nregs < 0
393990284Sobrien			   ? SSE_REGPARM_MAX
394090284Sobrien			   : cum->sse_regno)
394190284Sobrien			: -1);
394290284Sobrien      else
394390284Sobrien	return constm1_rtx;
394418334Speter    }
394590284Sobrien  if (TARGET_64BIT)
3946169705Skan    ret = construct_container (mode, orig_mode, type, 0, cum->nregs,
3947169705Skan			       cum->sse_nregs,
394890284Sobrien			       &x86_64_int_parameter_registers [cum->regno],
394990284Sobrien			       cum->sse_regno);
395090284Sobrien  else
395190284Sobrien    switch (mode)
395290284Sobrien      {
395390284Sobrien	/* For now, pass fp/complex values on the stack.  */
395490284Sobrien      default:
395590284Sobrien	break;
395618334Speter
395790284Sobrien      case BLKmode:
3958117408Skan	if (bytes < 0)
3959117408Skan	  break;
3960117408Skan	/* FALLTHRU */
396190284Sobrien      case DImode:
396290284Sobrien      case SImode:
396390284Sobrien      case HImode:
396490284Sobrien      case QImode:
396590284Sobrien	if (words <= cum->nregs)
3966132743Skan	  {
3967132743Skan	    int regno = cum->regno;
3968132743Skan
3969132743Skan	    /* Fastcall allocates the first two DWORD (SImode) or
3970132743Skan	       smaller arguments to ECX and EDX.  */
3971132743Skan	    if (cum->fastcall)
3972132743Skan	      {
3973132743Skan	        if (mode == BLKmode || mode == DImode)
3974132743Skan	          break;
3975132743Skan
3976132743Skan	        /* ECX not EAX is the first allocated register.  */
3977132743Skan	        if (regno == 0)
3978132743Skan		  regno = 2;
3979132743Skan	      }
3980132743Skan	    ret = gen_rtx_REG (mode, regno);
3981132743Skan	  }
398290284Sobrien	break;
3983169705Skan      case DFmode:
3984169705Skan	if (cum->float_in_sse < 2)
3985169705Skan	  break;
3986169705Skan      case SFmode:
3987169705Skan	if (cum->float_in_sse < 1)
3988169705Skan	  break;
3989169705Skan	/* FALLTHRU */
399090284Sobrien      case TImode:
3991132743Skan      case V16QImode:
3992132743Skan      case V8HImode:
3993132743Skan      case V4SImode:
3994132743Skan      case V2DImode:
3995132743Skan      case V4SFmode:
3996132743Skan      case V2DFmode:
3997132743Skan	if (!type || !AGGREGATE_TYPE_P (type))
3998132743Skan	  {
3999169705Skan	    if (!TARGET_SSE && !warnedsse && cum->warn_sse)
4000132743Skan	      {
4001132743Skan		warnedsse = true;
4002169705Skan		warning (0, "SSE vector argument without SSE enabled "
4003132743Skan			 "changes the ABI");
4004132743Skan	      }
4005132743Skan	    if (cum->sse_nregs)
4006169705Skan	      ret = gen_reg_or_parallel (mode, orig_mode,
4007146908Skan					 cum->sse_regno + FIRST_SSE_REG);
4008132743Skan	  }
400990284Sobrien	break;
4010132743Skan      case V8QImode:
4011132743Skan      case V4HImode:
4012132743Skan      case V2SImode:
4013132743Skan      case V2SFmode:
4014132743Skan	if (!type || !AGGREGATE_TYPE_P (type))
4015132743Skan	  {
4016132743Skan	    if (!TARGET_MMX && !warnedmmx && cum->warn_mmx)
4017132743Skan	      {
4018132743Skan		warnedmmx = true;
4019169705Skan		warning (0, "MMX vector argument without MMX enabled "
4020132743Skan			 "changes the ABI");
4021132743Skan	      }
4022132743Skan	    if (cum->mmx_nregs)
4023169705Skan	      ret = gen_reg_or_parallel (mode, orig_mode,
4024146908Skan					 cum->mmx_regno + FIRST_MMX_REG);
4025132743Skan	  }
4026132743Skan	break;
402790284Sobrien      }
402890284Sobrien
402918334Speter  if (TARGET_DEBUG_ARG)
403018334Speter    {
403118334Speter      fprintf (stderr,
4032117408Skan	       "function_arg (size=%d, wds=%2d, nregs=%d, mode=%4s, named=%d, ",
403318334Speter	       words, cum->words, cum->nregs, GET_MODE_NAME (mode), named);
403418334Speter
403518334Speter      if (ret)
4036117408Skan	print_simple_rtl (stderr, ret);
403718334Speter      else
403818334Speter	fprintf (stderr, ", stack");
403918334Speter
404018334Speter      fprintf (stderr, " )\n");
404118334Speter    }
404218334Speter
404318334Speter  return ret;
404418334Speter}
404518334Speter
4046132743Skan/* A C expression that indicates when an argument must be passed by
4047132743Skan   reference.  If nonzero for an argument, a copy of that argument is
4048132743Skan   made in memory and a pointer to the argument is passed instead of
4049132743Skan   the argument itself.  The pointer is passed in whatever way is
4050132743Skan   appropriate for passing a pointer to that type.  */
4051132743Skan
4052169705Skanstatic bool
4053169705Skanix86_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
4054169705Skan			enum machine_mode mode ATTRIBUTE_UNUSED,
4055169705Skan			tree type, bool named ATTRIBUTE_UNUSED)
4056132743Skan{
4057132743Skan  if (!TARGET_64BIT)
4058132743Skan    return 0;
4059132743Skan
4060132743Skan  if (type && int_size_in_bytes (type) == -1)
4061132743Skan    {
4062132743Skan      if (TARGET_DEBUG_ARG)
4063132743Skan	fprintf (stderr, "function_arg_pass_by_reference\n");
4064132743Skan      return 1;
4065132743Skan    }
4066132743Skan
4067132743Skan  return 0;
4068132743Skan}
4069132743Skan
4070117408Skan/* Return true when TYPE should be 128bit aligned for 32bit argument passing
4071169705Skan   ABI.  Only called if TARGET_SSE.  */
4072117408Skanstatic bool
4073132743Skancontains_128bit_aligned_vector_p (tree type)
4074117408Skan{
4075117408Skan  enum machine_mode mode = TYPE_MODE (type);
4076117408Skan  if (SSE_REG_MODE_P (mode)
4077117408Skan      && (!TYPE_USER_ALIGN (type) || TYPE_ALIGN (type) > 128))
4078117408Skan    return true;
4079117408Skan  if (TYPE_ALIGN (type) < 128)
4080117408Skan    return false;
4081117408Skan
4082117408Skan  if (AGGREGATE_TYPE_P (type))
4083117408Skan    {
4084132743Skan      /* Walk the aggregates recursively.  */
4085169705Skan      switch (TREE_CODE (type))
4086117408Skan	{
4087169705Skan	case RECORD_TYPE:
4088169705Skan	case UNION_TYPE:
4089169705Skan	case QUAL_UNION_TYPE:
4090169705Skan	  {
4091169705Skan	    tree field;
4092117408Skan
4093169705Skan	    if (TYPE_BINFO (type))
4094169705Skan	      {
4095169705Skan		tree binfo, base_binfo;
4096169705Skan		int i;
4097117408Skan
4098169705Skan		for (binfo = TYPE_BINFO (type), i = 0;
4099169705Skan		     BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
4100169705Skan		  if (contains_128bit_aligned_vector_p
4101169705Skan		      (BINFO_TYPE (base_binfo)))
4102169705Skan		    return true;
4103169705Skan	      }
4104169705Skan	    /* And now merge the fields of structure.  */
4105169705Skan	    for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
4106169705Skan	      {
4107169705Skan		if (TREE_CODE (field) == FIELD_DECL
4108169705Skan		    && contains_128bit_aligned_vector_p (TREE_TYPE (field)))
4109169705Skan		  return true;
4110169705Skan	      }
4111169705Skan	    break;
4112169705Skan	  }
4113117408Skan
4114169705Skan	case ARRAY_TYPE:
4115169705Skan	  /* Just for use if some languages passes arrays by value.  */
4116117408Skan	  if (contains_128bit_aligned_vector_p (TREE_TYPE (type)))
4117117408Skan	    return true;
4118169705Skan	  break;
4119169705Skan
4120169705Skan	default:
4121169705Skan	  gcc_unreachable ();
4122117408Skan	}
4123117408Skan    }
4124117408Skan  return false;
4125117408Skan}
4126117408Skan
4127132743Skan/* Gives the alignment boundary, in bits, of an argument with the
4128132743Skan   specified mode and type.  */
4129117408Skan
4130117408Skanint
4131132743Skanix86_function_arg_boundary (enum machine_mode mode, tree type)
4132117408Skan{
413390284Sobrien  int align;
413490284Sobrien  if (type)
413590284Sobrien    align = TYPE_ALIGN (type);
413690284Sobrien  else
413790284Sobrien    align = GET_MODE_ALIGNMENT (mode);
413890284Sobrien  if (align < PARM_BOUNDARY)
413990284Sobrien    align = PARM_BOUNDARY;
4140117408Skan  if (!TARGET_64BIT)
4141117408Skan    {
4142117408Skan      /* i386 ABI defines all arguments to be 4 byte aligned.  We have to
4143117408Skan	 make an exception for SSE modes since these require 128bit
4144132743Skan	 alignment.
4145117408Skan
4146117408Skan	 The handling here differs from field_alignment.  ICC aligns MMX
4147117408Skan	 arguments to 4 byte boundaries, while structure fields are aligned
4148117408Skan	 to 8 byte boundaries.  */
4149169705Skan      if (!TARGET_SSE)
4150169705Skan	align = PARM_BOUNDARY;
4151169705Skan      else if (!type)
4152117408Skan	{
4153117408Skan	  if (!SSE_REG_MODE_P (mode))
4154117408Skan	    align = PARM_BOUNDARY;
4155117408Skan	}
4156117408Skan      else
4157117408Skan	{
4158117408Skan	  if (!contains_128bit_aligned_vector_p (type))
4159117408Skan	    align = PARM_BOUNDARY;
4160117408Skan	}
4161117408Skan    }
416290284Sobrien  if (align > 128)
416390284Sobrien    align = 128;
416490284Sobrien  return align;
416518334Speter}
416690284Sobrien
416790284Sobrien/* Return true if N is a possible register number of function value.  */
416890284Sobrienbool
4169132743Skanix86_function_value_regno_p (int regno)
417018334Speter{
4171169705Skan  if (TARGET_MACHO)
417218334Speter    {
4173169705Skan      if (!TARGET_64BIT)
4174169705Skan        {
4175169705Skan          return ((regno) == 0
4176169705Skan                  || ((regno) == FIRST_FLOAT_REG && TARGET_FLOAT_RETURNS_IN_80387)
4177169705Skan                  || ((regno) == FIRST_SSE_REG && TARGET_SSE));
4178169705Skan        }
4179169705Skan      return ((regno) == 0 || (regno) == FIRST_FLOAT_REG
4180169705Skan              || ((regno) == FIRST_SSE_REG && TARGET_SSE)
4181169705Skan              || ((regno) == FIRST_FLOAT_REG && TARGET_FLOAT_RETURNS_IN_80387));
4182169705Skan      }
4183169705Skan  else
4184169705Skan    {
4185169705Skan      if (regno == 0
4186169705Skan          || (regno == FIRST_FLOAT_REG && TARGET_FLOAT_RETURNS_IN_80387)
4187169705Skan          || (regno == FIRST_SSE_REG && TARGET_SSE))
4188169705Skan        return true;
4189169705Skan
4190169705Skan      if (!TARGET_64BIT
4191169705Skan          && (regno == FIRST_MMX_REG && TARGET_MMX))
4192169705Skan	    return true;
4193169705Skan
4194169705Skan      return false;
419518334Speter    }
419690284Sobrien}
419790284Sobrien
419890284Sobrien/* Define how to find the value returned by a function.
419990284Sobrien   VALTYPE is the data type of the value (as a tree).
420090284Sobrien   If the precise function being called is known, FUNC is its FUNCTION_DECL;
420190284Sobrien   otherwise, FUNC is 0.  */
420290284Sobrienrtx
4203169705Skanix86_function_value (tree valtype, tree fntype_or_decl,
4204169705Skan		     bool outgoing ATTRIBUTE_UNUSED)
420590284Sobrien{
4206169705Skan  enum machine_mode natmode = type_natural_mode (valtype);
4207169705Skan
420890284Sobrien  if (TARGET_64BIT)
420918334Speter    {
4210169705Skan      rtx ret = construct_container (natmode, TYPE_MODE (valtype), valtype,
4211169705Skan				     1, REGPARM_MAX, SSE_REGPARM_MAX,
421290284Sobrien				     x86_64_int_return_registers, 0);
4213169705Skan      /* For zero sized structures, construct_container return NULL, but we
4214169705Skan	 need to keep rest of compiler happy by returning meaningful value.  */
421590284Sobrien      if (!ret)
421690284Sobrien	ret = gen_rtx_REG (TYPE_MODE (valtype), 0);
421790284Sobrien      return ret;
421818334Speter    }
421990284Sobrien  else
4220169705Skan    {
4221169705Skan      tree fn = NULL_TREE, fntype;
4222169705Skan      if (fntype_or_decl
4223169705Skan	  && DECL_P (fntype_or_decl))
4224169705Skan        fn = fntype_or_decl;
4225169705Skan      fntype = fn ? TREE_TYPE (fn) : fntype_or_decl;
4226169705Skan      return gen_rtx_REG (TYPE_MODE (valtype),
4227169705Skan			  ix86_value_regno (natmode, fn, fntype));
4228169705Skan    }
422918334Speter}
423018334Speter
4231169705Skan/* Return true iff type is returned in memory.  */
423290284Sobrienint
4233132743Skanix86_return_in_memory (tree type)
423418334Speter{
4235122194Skan  int needed_intregs, needed_sseregs, size;
4236169705Skan  enum machine_mode mode = type_natural_mode (type);
4237122194Skan
423890284Sobrien  if (TARGET_64BIT)
4239122194Skan    return !examine_argument (mode, type, 1, &needed_intregs, &needed_sseregs);
4240122194Skan
4241122194Skan  if (mode == BLKmode)
4242122194Skan    return 1;
4243122194Skan
4244122194Skan  size = int_size_in_bytes (type);
4245122194Skan
4246132743Skan  if (MS_AGGREGATE_RETURN && AGGREGATE_TYPE_P (type) && size <= 8)
4247132743Skan    return 0;
4248132743Skan
4249122194Skan  if (VECTOR_MODE_P (mode) || mode == TImode)
425018334Speter    {
4251122194Skan      /* User-created vectors small enough to fit in EAX.  */
4252122194Skan      if (size < 8)
4253122194Skan	return 0;
4254122194Skan
4255169705Skan      /* MMX/3dNow values are returned in MM0,
4256169705Skan	 except when it doesn't exits.  */
4257122194Skan      if (size == 8)
4258169705Skan	return (TARGET_MMX ? 0 : 1);
4259122194Skan
4260169705Skan      /* SSE values are returned in XMM0, except when it doesn't exist.  */
4261122194Skan      if (size == 16)
4262169705Skan	return (TARGET_SSE ? 0 : 1);
426318334Speter    }
4264122194Skan
4265132743Skan  if (mode == XFmode)
4266122194Skan    return 0;
4267132743Skan
4268169705Skan  if (mode == TDmode)
4269169705Skan    return 1;
4270169705Skan
4271122194Skan  if (size > 12)
4272122194Skan    return 1;
4273122194Skan  return 0;
427418334Speter}
427590284Sobrien
4276169705Skan/* When returning SSE vector types, we have a choice of either
4277169705Skan     (1) being abi incompatible with a -march switch, or
4278169705Skan     (2) generating an error.
4279169705Skan   Given no good solution, I think the safest thing is one warning.
4280169705Skan   The user won't be able to use -Werror, but....
4281169705Skan
4282169705Skan   Choose the STRUCT_VALUE_RTX hook because that's (at present) only
4283169705Skan   called in response to actually generating a caller or callee that
4284169705Skan   uses such a type.  As opposed to RETURN_IN_MEMORY, which is called
4285169705Skan   via aggregate_value_p for general type probing from tree-ssa.  */
4286169705Skan
4287169705Skanstatic rtx
4288169705Skanix86_struct_value_rtx (tree type, int incoming ATTRIBUTE_UNUSED)
4289169705Skan{
4290169705Skan  static bool warnedsse, warnedmmx;
4291169705Skan
4292169705Skan  if (type)
4293169705Skan    {
4294169705Skan      /* Look at the return type of the function, not the function type.  */
4295169705Skan      enum machine_mode mode = TYPE_MODE (TREE_TYPE (type));
4296169705Skan
4297169705Skan      if (!TARGET_SSE && !warnedsse)
4298169705Skan	{
4299169705Skan	  if (mode == TImode
4300169705Skan	      || (VECTOR_MODE_P (mode) && GET_MODE_SIZE (mode) == 16))
4301169705Skan	    {
4302169705Skan	      warnedsse = true;
4303169705Skan	      warning (0, "SSE vector return without SSE enabled "
4304169705Skan		       "changes the ABI");
4305169705Skan	    }
4306169705Skan	}
4307169705Skan
4308169705Skan      if (!TARGET_MMX && !warnedmmx)
4309169705Skan	{
4310169705Skan	  if (VECTOR_MODE_P (mode) && GET_MODE_SIZE (mode) == 8)
4311169705Skan	    {
4312169705Skan	      warnedmmx = true;
4313169705Skan	      warning (0, "MMX vector return without MMX enabled "
4314169705Skan		       "changes the ABI");
4315169705Skan	    }
4316169705Skan	}
4317169705Skan    }
4318169705Skan
4319169705Skan  return NULL;
4320169705Skan}
4321169705Skan
432290284Sobrien/* Define how to find the value returned by a library function
432390284Sobrien   assuming the value has mode MODE.  */
432490284Sobrienrtx
4325132743Skanix86_libcall_value (enum machine_mode mode)
432690284Sobrien{
432790284Sobrien  if (TARGET_64BIT)
432890284Sobrien    {
432990284Sobrien      switch (mode)
433090284Sobrien	{
4331132743Skan	case SFmode:
4332132743Skan	case SCmode:
4333132743Skan	case DFmode:
4334132743Skan	case DCmode:
4335169705Skan	case TFmode:
4336169705Skan	case SDmode:
4337169705Skan	case DDmode:
4338169705Skan	case TDmode:
4339132743Skan	  return gen_rtx_REG (mode, FIRST_SSE_REG);
4340132743Skan	case XFmode:
4341132743Skan	case XCmode:
4342132743Skan	  return gen_rtx_REG (mode, FIRST_FLOAT_REG);
4343132743Skan	case TCmode:
4344132743Skan	  return NULL;
4345132743Skan	default:
4346132743Skan	  return gen_rtx_REG (mode, 0);
434790284Sobrien	}
434890284Sobrien    }
434990284Sobrien  else
4350169705Skan    return gen_rtx_REG (mode, ix86_value_regno (mode, NULL, NULL));
435190284Sobrien}
4352117408Skan
4353117408Skan/* Given a mode, return the register to use for a return value.  */
4354117408Skan
4355117408Skanstatic int
4356169705Skanix86_value_regno (enum machine_mode mode, tree func, tree fntype)
4357117408Skan{
4358169705Skan  gcc_assert (!TARGET_64BIT);
4359169705Skan
4360169705Skan  /* 8-byte vector modes in %mm0. See ix86_return_in_memory for where
4361169705Skan     we normally prevent this case when mmx is not available.  However
4362169705Skan     some ABIs may require the result to be returned like DImode.  */
4363169705Skan  if (VECTOR_MODE_P (mode) && GET_MODE_SIZE (mode) == 8)
4364169705Skan    return TARGET_MMX ? FIRST_MMX_REG : 0;
4365169705Skan
4366122194Skan  /* 16-byte vector modes in %xmm0.  See ix86_return_in_memory for where
4367169705Skan     we prevent this case when sse is not available.  However some ABIs
4368169705Skan     may require the result to be returned like integer TImode.  */
4369122194Skan  if (mode == TImode || (VECTOR_MODE_P (mode) && GET_MODE_SIZE (mode) == 16))
4370169705Skan    return TARGET_SSE ? FIRST_SSE_REG : 0;
4371169705Skan
4372169705Skan  /* Decimal floating point values can go in %eax, unlike other float modes.  */
4373169705Skan  if (DECIMAL_FLOAT_MODE_P (mode))
4374169705Skan    return 0;
4375169705Skan
4376169705Skan  /* Most things go in %eax, except (unless -mno-fp-ret-in-387) fp values.  */
4377169705Skan  if (!SCALAR_FLOAT_MODE_P (mode) || !TARGET_FLOAT_RETURNS_IN_80387)
4378169705Skan    return 0;
4379169705Skan
4380169705Skan  /* Floating point return values in %st(0), except for local functions when
4381169705Skan     SSE math is enabled or for functions with sseregparm attribute.  */
4382169705Skan  if ((func || fntype)
4383169705Skan      && (mode == SFmode || mode == DFmode))
4384169705Skan    {
4385169705Skan      int sse_level = ix86_function_sseregparm (fntype, func);
4386169705Skan      if ((sse_level >= 1 && mode == SFmode)
4387169705Skan	  || (sse_level == 2 && mode == DFmode))
4388169705Skan        return FIRST_SSE_REG;
4389169705Skan    }
4390169705Skan
4391169705Skan  return FIRST_FLOAT_REG;
4392117408Skan}
439318334Speter
439490284Sobrien/* Create the va_list data type.  */
439518334Speter
4396132743Skanstatic tree
4397132743Skanix86_build_builtin_va_list (void)
439818334Speter{
439990284Sobrien  tree f_gpr, f_fpr, f_ovf, f_sav, record, type_decl;
440018334Speter
440190284Sobrien  /* For i386 we use plain pointer to argument area.  */
440290284Sobrien  if (!TARGET_64BIT)
440390284Sobrien    return build_pointer_type (char_type_node);
440418334Speter
4405117408Skan  record = (*lang_hooks.types.make_type) (RECORD_TYPE);
440690284Sobrien  type_decl = build_decl (TYPE_DECL, get_identifier ("__va_list_tag"), record);
440718334Speter
4408117408Skan  f_gpr = build_decl (FIELD_DECL, get_identifier ("gp_offset"),
440990284Sobrien		      unsigned_type_node);
4410117408Skan  f_fpr = build_decl (FIELD_DECL, get_identifier ("fp_offset"),
441190284Sobrien		      unsigned_type_node);
441290284Sobrien  f_ovf = build_decl (FIELD_DECL, get_identifier ("overflow_arg_area"),
441390284Sobrien		      ptr_type_node);
441490284Sobrien  f_sav = build_decl (FIELD_DECL, get_identifier ("reg_save_area"),
441590284Sobrien		      ptr_type_node);
441618334Speter
4417169705Skan  va_list_gpr_counter_field = f_gpr;
4418169705Skan  va_list_fpr_counter_field = f_fpr;
4419169705Skan
442090284Sobrien  DECL_FIELD_CONTEXT (f_gpr) = record;
442190284Sobrien  DECL_FIELD_CONTEXT (f_fpr) = record;
442290284Sobrien  DECL_FIELD_CONTEXT (f_ovf) = record;
442390284Sobrien  DECL_FIELD_CONTEXT (f_sav) = record;
442418334Speter
442590284Sobrien  TREE_CHAIN (record) = type_decl;
442690284Sobrien  TYPE_NAME (record) = type_decl;
442790284Sobrien  TYPE_FIELDS (record) = f_gpr;
442890284Sobrien  TREE_CHAIN (f_gpr) = f_fpr;
442990284Sobrien  TREE_CHAIN (f_fpr) = f_ovf;
443090284Sobrien  TREE_CHAIN (f_ovf) = f_sav;
443118334Speter
443290284Sobrien  layout_type (record);
443318334Speter
443490284Sobrien  /* The correct type is an array type of one element.  */
443590284Sobrien  return build_array_type (record, build_index_type (size_zero_node));
443690284Sobrien}
443718334Speter
4438169705Skan/* Worker function for TARGET_SETUP_INCOMING_VARARGS.  */
443990284Sobrien
4440169705Skanstatic void
4441132743Skanix86_setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
4442132743Skan			     tree type, int *pretend_size ATTRIBUTE_UNUSED,
4443132743Skan			     int no_rtl)
444490284Sobrien{
444590284Sobrien  CUMULATIVE_ARGS next_cum;
444690284Sobrien  rtx save_area = NULL_RTX, mem;
444790284Sobrien  rtx label;
444890284Sobrien  rtx label_ref;
444990284Sobrien  rtx tmp_reg;
445090284Sobrien  rtx nsse_reg;
445190284Sobrien  int set;
445290284Sobrien  tree fntype;
445390284Sobrien  int stdarg_p;
445490284Sobrien  int i;
445590284Sobrien
445690284Sobrien  if (!TARGET_64BIT)
445790284Sobrien    return;
445890284Sobrien
4459169705Skan  if (! cfun->va_list_gpr_size && ! cfun->va_list_fpr_size)
4460169705Skan    return;
4461169705Skan
446290284Sobrien  /* Indicate to allocate space on the stack for varargs save area.  */
446390284Sobrien  ix86_save_varrargs_registers = 1;
446490284Sobrien
4465117408Skan  cfun->stack_alignment_needed = 128;
4466117408Skan
446790284Sobrien  fntype = TREE_TYPE (current_function_decl);
446890284Sobrien  stdarg_p = (TYPE_ARG_TYPES (fntype) != 0
446990284Sobrien	      && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
447090284Sobrien		  != void_type_node));
447190284Sobrien
447290284Sobrien  /* For varargs, we do not want to skip the dummy va_dcl argument.
447390284Sobrien     For stdargs, we do want to skip the last named argument.  */
447490284Sobrien  next_cum = *cum;
447590284Sobrien  if (stdarg_p)
447690284Sobrien    function_arg_advance (&next_cum, mode, type, 1);
447790284Sobrien
447890284Sobrien  if (!no_rtl)
447990284Sobrien    save_area = frame_pointer_rtx;
448090284Sobrien
448190284Sobrien  set = get_varargs_alias_set ();
448290284Sobrien
4483169705Skan  for (i = next_cum.regno;
4484169705Skan       i < ix86_regparm
4485169705Skan       && i < next_cum.regno + cfun->va_list_gpr_size / UNITS_PER_WORD;
4486169705Skan       i++)
448718334Speter    {
448890284Sobrien      mem = gen_rtx_MEM (Pmode,
448990284Sobrien			 plus_constant (save_area, i * UNITS_PER_WORD));
4490169705Skan      MEM_NOTRAP_P (mem) = 1;
449190284Sobrien      set_mem_alias_set (mem, set);
449290284Sobrien      emit_move_insn (mem, gen_rtx_REG (Pmode,
449390284Sobrien					x86_64_int_parameter_registers[i]));
449418334Speter    }
449518334Speter
4496169705Skan  if (next_cum.sse_nregs && cfun->va_list_fpr_size)
449718334Speter    {
449890284Sobrien      /* Now emit code to save SSE registers.  The AX parameter contains number
4499132743Skan	 of SSE parameter registers used to call this function.  We use
450090284Sobrien	 sse_prologue_save insn template that produces computed jump across
450190284Sobrien	 SSE saves.  We need some preparation work to get this working.  */
450290284Sobrien
450390284Sobrien      label = gen_label_rtx ();
450490284Sobrien      label_ref = gen_rtx_LABEL_REF (Pmode, label);
450590284Sobrien
450690284Sobrien      /* Compute address to jump to :
450790284Sobrien         label - 5*eax + nnamed_sse_arguments*5  */
450890284Sobrien      tmp_reg = gen_reg_rtx (Pmode);
450990284Sobrien      nsse_reg = gen_reg_rtx (Pmode);
451090284Sobrien      emit_insn (gen_zero_extendqidi2 (nsse_reg, gen_rtx_REG (QImode, 0)));
451190284Sobrien      emit_insn (gen_rtx_SET (VOIDmode, tmp_reg,
451290284Sobrien			      gen_rtx_MULT (Pmode, nsse_reg,
451390284Sobrien					    GEN_INT (4))));
451490284Sobrien      if (next_cum.sse_regno)
451590284Sobrien	emit_move_insn
451690284Sobrien	  (nsse_reg,
451790284Sobrien	   gen_rtx_CONST (DImode,
451890284Sobrien			  gen_rtx_PLUS (DImode,
451990284Sobrien					label_ref,
452090284Sobrien					GEN_INT (next_cum.sse_regno * 4))));
452118334Speter      else
452290284Sobrien	emit_move_insn (nsse_reg, label_ref);
452390284Sobrien      emit_insn (gen_subdi3 (nsse_reg, nsse_reg, tmp_reg));
452490284Sobrien
452590284Sobrien      /* Compute address of memory block we save into.  We always use pointer
452690284Sobrien	 pointing 127 bytes after first byte to store - this is needed to keep
452790284Sobrien	 instruction size limited by 4 bytes.  */
452890284Sobrien      tmp_reg = gen_reg_rtx (Pmode);
452990284Sobrien      emit_insn (gen_rtx_SET (VOIDmode, tmp_reg,
453090284Sobrien			      plus_constant (save_area,
453190284Sobrien					     8 * REGPARM_MAX + 127)));
453290284Sobrien      mem = gen_rtx_MEM (BLKmode, plus_constant (tmp_reg, -127));
4533169705Skan      MEM_NOTRAP_P (mem) = 1;
453490284Sobrien      set_mem_alias_set (mem, set);
453590284Sobrien      set_mem_align (mem, BITS_PER_WORD);
453690284Sobrien
453790284Sobrien      /* And finally do the dirty job!  */
453890284Sobrien      emit_insn (gen_sse_prologue_save (mem, nsse_reg,
453990284Sobrien					GEN_INT (next_cum.sse_regno), label));
454018334Speter    }
454118334Speter
454290284Sobrien}
454318334Speter
454490284Sobrien/* Implement va_start.  */
454518334Speter
454690284Sobrienvoid
4547132743Skanix86_va_start (tree valist, rtx nextarg)
454890284Sobrien{
454990284Sobrien  HOST_WIDE_INT words, n_gpr, n_fpr;
455090284Sobrien  tree f_gpr, f_fpr, f_ovf, f_sav;
455190284Sobrien  tree gpr, fpr, ovf, sav, t;
4552169705Skan  tree type;
455390284Sobrien
455490284Sobrien  /* Only 64bit target needs something special.  */
455590284Sobrien  if (!TARGET_64BIT)
455618334Speter    {
4557117408Skan      std_expand_builtin_va_start (valist, nextarg);
455890284Sobrien      return;
455990284Sobrien    }
456090284Sobrien
456190284Sobrien  f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
456290284Sobrien  f_fpr = TREE_CHAIN (f_gpr);
456390284Sobrien  f_ovf = TREE_CHAIN (f_fpr);
456490284Sobrien  f_sav = TREE_CHAIN (f_ovf);
456590284Sobrien
456690284Sobrien  valist = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)), valist);
4567169705Skan  gpr = build3 (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr, NULL_TREE);
4568169705Skan  fpr = build3 (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr, NULL_TREE);
4569169705Skan  ovf = build3 (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf, NULL_TREE);
4570169705Skan  sav = build3 (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav, NULL_TREE);
457190284Sobrien
457290284Sobrien  /* Count number of gp and fp argument registers used.  */
457390284Sobrien  words = current_function_args_info.words;
457490284Sobrien  n_gpr = current_function_args_info.regno;
457590284Sobrien  n_fpr = current_function_args_info.sse_regno;
457690284Sobrien
457790284Sobrien  if (TARGET_DEBUG_ARG)
457890284Sobrien    fprintf (stderr, "va_start: words = %d, n_gpr = %d, n_fpr = %d\n",
457990284Sobrien	     (int) words, (int) n_gpr, (int) n_fpr);
458090284Sobrien
4581169705Skan  if (cfun->va_list_gpr_size)
4582169705Skan    {
4583169705Skan      type = TREE_TYPE (gpr);
4584169705Skan      t = build2 (MODIFY_EXPR, type, gpr,
4585169705Skan		  build_int_cst (type, n_gpr * 8));
4586169705Skan      TREE_SIDE_EFFECTS (t) = 1;
4587169705Skan      expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
4588169705Skan    }
458990284Sobrien
4590169705Skan  if (cfun->va_list_fpr_size)
4591169705Skan    {
4592169705Skan      type = TREE_TYPE (fpr);
4593169705Skan      t = build2 (MODIFY_EXPR, type, fpr,
4594169705Skan		  build_int_cst (type, n_fpr * 16 + 8*REGPARM_MAX));
4595169705Skan      TREE_SIDE_EFFECTS (t) = 1;
4596169705Skan      expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
4597169705Skan    }
459890284Sobrien
459990284Sobrien  /* Find the overflow area.  */
4600169705Skan  type = TREE_TYPE (ovf);
4601169705Skan  t = make_tree (type, virtual_incoming_args_rtx);
460290284Sobrien  if (words != 0)
4603169705Skan    t = build2 (PLUS_EXPR, type, t,
4604169705Skan	        build_int_cst (type, words * UNITS_PER_WORD));
4605169705Skan  t = build2 (MODIFY_EXPR, type, ovf, t);
460690284Sobrien  TREE_SIDE_EFFECTS (t) = 1;
460790284Sobrien  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
460890284Sobrien
4609169705Skan  if (cfun->va_list_gpr_size || cfun->va_list_fpr_size)
4610169705Skan    {
4611169705Skan      /* Find the register save area.
4612169705Skan	 Prologue of the function save it right above stack frame.  */
4613169705Skan      type = TREE_TYPE (sav);
4614169705Skan      t = make_tree (type, frame_pointer_rtx);
4615169705Skan      t = build2 (MODIFY_EXPR, type, sav, t);
4616169705Skan      TREE_SIDE_EFFECTS (t) = 1;
4617169705Skan      expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
4618169705Skan    }
461990284Sobrien}
462090284Sobrien
462190284Sobrien/* Implement va_arg.  */
4622169705Skan
4623169705Skantree
4624169705Skanix86_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
462590284Sobrien{
4626117408Skan  static const int intreg[6] = { 0, 1, 2, 3, 4, 5 };
462790284Sobrien  tree f_gpr, f_fpr, f_ovf, f_sav;
462890284Sobrien  tree gpr, fpr, ovf, sav, t;
462990284Sobrien  int size, rsize;
4630169705Skan  tree lab_false, lab_over = NULL_TREE;
4631169705Skan  tree addr, t2;
463290284Sobrien  rtx container;
4633117408Skan  int indirect_p = 0;
4634169705Skan  tree ptrtype;
4635169705Skan  enum machine_mode nat_mode;
463690284Sobrien
463790284Sobrien  /* Only 64bit target needs something special.  */
463890284Sobrien  if (!TARGET_64BIT)
4639169705Skan    return std_gimplify_va_arg_expr (valist, type, pre_p, post_p);
464090284Sobrien
464190284Sobrien  f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
464290284Sobrien  f_fpr = TREE_CHAIN (f_gpr);
464390284Sobrien  f_ovf = TREE_CHAIN (f_fpr);
464490284Sobrien  f_sav = TREE_CHAIN (f_ovf);
464590284Sobrien
4646169705Skan  valist = build_va_arg_indirect_ref (valist);
4647169705Skan  gpr = build3 (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr, NULL_TREE);
4648169705Skan  fpr = build3 (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr, NULL_TREE);
4649169705Skan  ovf = build3 (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf, NULL_TREE);
4650169705Skan  sav = build3 (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav, NULL_TREE);
465190284Sobrien
4652169705Skan  indirect_p = pass_by_reference (NULL, TYPE_MODE (type), type, false);
4653169705Skan  if (indirect_p)
4654169705Skan    type = build_pointer_type (type);
465590284Sobrien  size = int_size_in_bytes (type);
465690284Sobrien  rsize = (size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
465790284Sobrien
4658169705Skan  nat_mode = type_natural_mode (type);
4659169705Skan  container = construct_container (nat_mode, TYPE_MODE (type), type, 0,
466090284Sobrien				   REGPARM_MAX, SSE_REGPARM_MAX, intreg, 0);
466190284Sobrien
4662169705Skan  /* Pull the value out of the saved registers.  */
466390284Sobrien
4664169705Skan  addr = create_tmp_var (ptr_type_node, "addr");
4665169705Skan  DECL_POINTER_ALIAS_SET (addr) = get_varargs_alias_set ();
4666169705Skan
466790284Sobrien  if (container)
466890284Sobrien    {
466990284Sobrien      int needed_intregs, needed_sseregs;
4670169705Skan      bool need_temp;
4671169705Skan      tree int_addr, sse_addr;
467290284Sobrien
4673169705Skan      lab_false = create_artificial_label ();
4674169705Skan      lab_over = create_artificial_label ();
467590284Sobrien
4676169705Skan      examine_argument (nat_mode, type, 0, &needed_intregs, &needed_sseregs);
467790284Sobrien
4678169705Skan      need_temp = (!REG_P (container)
4679169705Skan		   && ((needed_intregs && TYPE_ALIGN (type) > 64)
4680169705Skan		       || TYPE_ALIGN (type) > 128));
468190284Sobrien
4682132743Skan      /* In case we are passing structure, verify that it is consecutive block
468390284Sobrien         on the register save area.  If not we need to do moves.  */
468490284Sobrien      if (!need_temp && !REG_P (container))
468518334Speter	{
4686132743Skan	  /* Verify that all registers are strictly consecutive  */
468790284Sobrien	  if (SSE_REGNO_P (REGNO (XEXP (XVECEXP (container, 0, 0), 0))))
468890284Sobrien	    {
468990284Sobrien	      int i;
469090284Sobrien
469190284Sobrien	      for (i = 0; i < XVECLEN (container, 0) && !need_temp; i++)
469290284Sobrien		{
469390284Sobrien		  rtx slot = XVECEXP (container, 0, i);
469490284Sobrien		  if (REGNO (XEXP (slot, 0)) != FIRST_SSE_REG + (unsigned int) i
469590284Sobrien		      || INTVAL (XEXP (slot, 1)) != i * 16)
469690284Sobrien		    need_temp = 1;
469790284Sobrien		}
469890284Sobrien	    }
469990284Sobrien	  else
470090284Sobrien	    {
470190284Sobrien	      int i;
470290284Sobrien
470390284Sobrien	      for (i = 0; i < XVECLEN (container, 0) && !need_temp; i++)
470490284Sobrien		{
470590284Sobrien		  rtx slot = XVECEXP (container, 0, i);
470690284Sobrien		  if (REGNO (XEXP (slot, 0)) != (unsigned int) i
470790284Sobrien		      || INTVAL (XEXP (slot, 1)) != i * 8)
470890284Sobrien		    need_temp = 1;
470990284Sobrien		}
471090284Sobrien	    }
471118334Speter	}
471290284Sobrien      if (!need_temp)
471318334Speter	{
4714169705Skan	  int_addr = addr;
4715169705Skan	  sse_addr = addr;
471618334Speter	}
471718334Speter      else
471818334Speter	{
4719169705Skan	  int_addr = create_tmp_var (ptr_type_node, "int_addr");
4720169705Skan	  DECL_POINTER_ALIAS_SET (int_addr) = get_varargs_alias_set ();
4721169705Skan	  sse_addr = create_tmp_var (ptr_type_node, "sse_addr");
4722169705Skan	  DECL_POINTER_ALIAS_SET (sse_addr) = get_varargs_alias_set ();
472318334Speter	}
4724169705Skan
472590284Sobrien      /* First ensure that we fit completely in registers.  */
472690284Sobrien      if (needed_intregs)
472790284Sobrien	{
4728169705Skan	  t = build_int_cst (TREE_TYPE (gpr),
4729169705Skan			     (REGPARM_MAX - needed_intregs + 1) * 8);
4730169705Skan	  t = build2 (GE_EXPR, boolean_type_node, gpr, t);
4731169705Skan	  t2 = build1 (GOTO_EXPR, void_type_node, lab_false);
4732169705Skan	  t = build3 (COND_EXPR, void_type_node, t, t2, NULL_TREE);
4733169705Skan	  gimplify_and_add (t, pre_p);
473490284Sobrien	}
473590284Sobrien      if (needed_sseregs)
473690284Sobrien	{
4737169705Skan	  t = build_int_cst (TREE_TYPE (fpr),
4738169705Skan			     (SSE_REGPARM_MAX - needed_sseregs + 1) * 16
4739169705Skan			     + REGPARM_MAX * 8);
4740169705Skan	  t = build2 (GE_EXPR, boolean_type_node, fpr, t);
4741169705Skan	  t2 = build1 (GOTO_EXPR, void_type_node, lab_false);
4742169705Skan	  t = build3 (COND_EXPR, void_type_node, t, t2, NULL_TREE);
4743169705Skan	  gimplify_and_add (t, pre_p);
474490284Sobrien	}
474551411Sobrien
474690284Sobrien      /* Compute index to start of area used for integer regs.  */
474790284Sobrien      if (needed_intregs)
474818334Speter	{
4749169705Skan	  /* int_addr = gpr + sav; */
4750169705Skan	  t = fold_convert (ptr_type_node, gpr);
4751169705Skan	  t = build2 (PLUS_EXPR, ptr_type_node, sav, t);
4752169705Skan	  t = build2 (MODIFY_EXPR, void_type_node, int_addr, t);
4753169705Skan	  gimplify_and_add (t, pre_p);
475418334Speter	}
475590284Sobrien      if (needed_sseregs)
475618334Speter	{
4757169705Skan	  /* sse_addr = fpr + sav; */
4758169705Skan	  t = fold_convert (ptr_type_node, fpr);
4759169705Skan	  t = build2 (PLUS_EXPR, ptr_type_node, sav, t);
4760169705Skan	  t = build2 (MODIFY_EXPR, void_type_node, sse_addr, t);
4761169705Skan	  gimplify_and_add (t, pre_p);
476218334Speter	}
476390284Sobrien      if (need_temp)
476418334Speter	{
476590284Sobrien	  int i;
4766169705Skan	  tree temp = create_tmp_var (type, "va_arg_tmp");
476790284Sobrien
4768169705Skan	  /* addr = &temp; */
4769169705Skan	  t = build1 (ADDR_EXPR, build_pointer_type (type), temp);
4770169705Skan	  t = build2 (MODIFY_EXPR, void_type_node, addr, t);
4771169705Skan	  gimplify_and_add (t, pre_p);
477290284Sobrien
477390284Sobrien	  for (i = 0; i < XVECLEN (container, 0); i++)
477418334Speter	    {
477590284Sobrien	      rtx slot = XVECEXP (container, 0, i);
477690284Sobrien	      rtx reg = XEXP (slot, 0);
477790284Sobrien	      enum machine_mode mode = GET_MODE (reg);
4778169705Skan	      tree piece_type = lang_hooks.types.type_for_mode (mode, 1);
4779169705Skan	      tree addr_type = build_pointer_type (piece_type);
4780169705Skan	      tree src_addr, src;
478190284Sobrien	      int src_offset;
4782169705Skan	      tree dest_addr, dest;
478318334Speter
478490284Sobrien	      if (SSE_REGNO_P (REGNO (reg)))
478590284Sobrien		{
4786169705Skan		  src_addr = sse_addr;
478790284Sobrien		  src_offset = (REGNO (reg) - FIRST_SSE_REG) * 16;
478890284Sobrien		}
478990284Sobrien	      else
479090284Sobrien		{
4791169705Skan		  src_addr = int_addr;
479290284Sobrien		  src_offset = REGNO (reg) * 8;
479390284Sobrien		}
4794169705Skan	      src_addr = fold_convert (addr_type, src_addr);
4795169705Skan	      src_addr = fold (build2 (PLUS_EXPR, addr_type, src_addr,
4796169705Skan				       size_int (src_offset)));
4797169705Skan	      src = build_va_arg_indirect_ref (src_addr);
4798169705Skan
4799169705Skan	      dest_addr = fold_convert (addr_type, addr);
4800169705Skan	      dest_addr = fold (build2 (PLUS_EXPR, addr_type, dest_addr,
4801169705Skan					size_int (INTVAL (XEXP (slot, 1)))));
4802169705Skan	      dest = build_va_arg_indirect_ref (dest_addr);
4803169705Skan
4804169705Skan	      t = build2 (MODIFY_EXPR, void_type_node, dest, src);
4805169705Skan	      gimplify_and_add (t, pre_p);
480618334Speter	    }
480790284Sobrien	}
480890284Sobrien
480990284Sobrien      if (needed_intregs)
481018334Speter	{
4811169705Skan	  t = build2 (PLUS_EXPR, TREE_TYPE (gpr), gpr,
4812169705Skan		      build_int_cst (TREE_TYPE (gpr), needed_intregs * 8));
4813169705Skan	  t = build2 (MODIFY_EXPR, TREE_TYPE (gpr), gpr, t);
4814169705Skan	  gimplify_and_add (t, pre_p);
481518334Speter	}
481690284Sobrien      if (needed_sseregs)
481790284Sobrien	{
4818169705Skan	  t = build2 (PLUS_EXPR, TREE_TYPE (fpr), fpr,
4819169705Skan		      build_int_cst (TREE_TYPE (fpr), needed_sseregs * 16));
4820169705Skan	  t = build2 (MODIFY_EXPR, TREE_TYPE (fpr), fpr, t);
4821169705Skan	  gimplify_and_add (t, pre_p);
482290284Sobrien	}
482390284Sobrien
4824169705Skan      t = build1 (GOTO_EXPR, void_type_node, lab_over);
4825169705Skan      gimplify_and_add (t, pre_p);
4826169705Skan
4827169705Skan      t = build1 (LABEL_EXPR, void_type_node, lab_false);
4828169705Skan      append_to_statement_list (t, pre_p);
482918334Speter    }
483051411Sobrien
483190284Sobrien  /* ... otherwise out of the overflow area.  */
483290284Sobrien
483390284Sobrien  /* Care for on-stack alignment if needed.  */
4834169705Skan  if (FUNCTION_ARG_BOUNDARY (VOIDmode, type) <= 64
4835169705Skan      || integer_zerop (TYPE_SIZE (type)))
483690284Sobrien    t = ovf;
483751411Sobrien  else
483818334Speter    {
483990284Sobrien      HOST_WIDE_INT align = FUNCTION_ARG_BOUNDARY (VOIDmode, type) / 8;
4840169705Skan      t = build2 (PLUS_EXPR, TREE_TYPE (ovf), ovf,
4841169705Skan		  build_int_cst (TREE_TYPE (ovf), align - 1));
4842169705Skan      t = build2 (BIT_AND_EXPR, TREE_TYPE (t), t,
4843169705Skan		  build_int_cst (TREE_TYPE (t), -align));
484490284Sobrien    }
4845169705Skan  gimplify_expr (&t, pre_p, NULL, is_gimple_val, fb_rvalue);
484651411Sobrien
4847169705Skan  t2 = build2 (MODIFY_EXPR, void_type_node, addr, t);
4848169705Skan  gimplify_and_add (t2, pre_p);
484918334Speter
4850169705Skan  t = build2 (PLUS_EXPR, TREE_TYPE (t), t,
4851169705Skan	      build_int_cst (TREE_TYPE (t), rsize * UNITS_PER_WORD));
4852169705Skan  t = build2 (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t);
4853169705Skan  gimplify_and_add (t, pre_p);
485418334Speter
485590284Sobrien  if (container)
4856117408Skan    {
4857169705Skan      t = build1 (LABEL_EXPR, void_type_node, lab_over);
4858169705Skan      append_to_statement_list (t, pre_p);
4859117408Skan    }
4860117408Skan
4861169705Skan  ptrtype = build_pointer_type (type);
4862169705Skan  addr = fold_convert (ptrtype, addr);
4863169705Skan
4864169705Skan  if (indirect_p)
4865169705Skan    addr = build_va_arg_indirect_ref (addr);
4866169705Skan  return build_va_arg_indirect_ref (addr);
486790284Sobrien}
486890284Sobrien
4869117408Skan/* Return nonzero if OPNUM's MEM should be matched
4870117408Skan   in movabs* patterns.  */
4871117408Skan
4872117408Skanint
4873132743Skanix86_check_movabs (rtx insn, int opnum)
4874117408Skan{
4875117408Skan  rtx set, mem;
4876117408Skan
4877117408Skan  set = PATTERN (insn);
4878117408Skan  if (GET_CODE (set) == PARALLEL)
4879117408Skan    set = XVECEXP (set, 0, 0);
4880169705Skan  gcc_assert (GET_CODE (set) == SET);
4881117408Skan  mem = XEXP (set, opnum);
4882117408Skan  while (GET_CODE (mem) == SUBREG)
4883117408Skan    mem = SUBREG_REG (mem);
4884169705Skan  gcc_assert (GET_CODE (mem) == MEM);
4885117408Skan  return (volatile_ok || !MEM_VOLATILE_P (mem));
4886117408Skan}
488790284Sobrien
4888132743Skan/* Initialize the table of extra 80387 mathematical constants.  */
4889132743Skan
4890132743Skanstatic void
4891132743Skaninit_ext_80387_constants (void)
4892132743Skan{
4893132743Skan  static const char * cst[5] =
4894132743Skan  {
4895132743Skan    "0.3010299956639811952256464283594894482",  /* 0: fldlg2  */
4896132743Skan    "0.6931471805599453094286904741849753009",  /* 1: fldln2  */
4897132743Skan    "1.4426950408889634073876517827983434472",  /* 2: fldl2e  */
4898132743Skan    "3.3219280948873623478083405569094566090",  /* 3: fldl2t  */
4899132743Skan    "3.1415926535897932385128089594061862044",  /* 4: fldpi   */
4900132743Skan  };
4901132743Skan  int i;
4902132743Skan
4903132743Skan  for (i = 0; i < 5; i++)
4904132743Skan    {
4905132743Skan      real_from_string (&ext_80387_constants_table[i], cst[i]);
4906132743Skan      /* Ensure each constant is rounded to XFmode precision.  */
4907132743Skan      real_convert (&ext_80387_constants_table[i],
4908132743Skan		    XFmode, &ext_80387_constants_table[i]);
4909132743Skan    }
4910132743Skan
4911132743Skan  ext_80387_constants_init = 1;
4912132743Skan}
4913132743Skan
491490284Sobrien/* Return true if the constant is something that can be loaded with
4915132743Skan   a special instruction.  */
491651411Sobrien
491751411Sobrienint
4918132743Skanstandard_80387_constant_p (rtx x)
491951411Sobrien{
492090284Sobrien  if (GET_CODE (x) != CONST_DOUBLE || !FLOAT_MODE_P (GET_MODE (x)))
492190284Sobrien    return -1;
4922132743Skan
492390284Sobrien  if (x == CONST0_RTX (GET_MODE (x)))
492490284Sobrien    return 1;
492590284Sobrien  if (x == CONST1_RTX (GET_MODE (x)))
492690284Sobrien    return 2;
4927132743Skan
4928169705Skan  /* For XFmode constants, try to find a special 80387 instruction when
4929169705Skan     optimizing for size or on those CPUs that benefit from them.  */
4930132743Skan  if (GET_MODE (x) == XFmode
4931169705Skan      && (optimize_size || x86_ext_80387_constants & TUNEMASK))
4932132743Skan    {
4933132743Skan      REAL_VALUE_TYPE r;
4934132743Skan      int i;
4935132743Skan
4936132743Skan      if (! ext_80387_constants_init)
4937132743Skan	init_ext_80387_constants ();
4938132743Skan
4939132743Skan      REAL_VALUE_FROM_CONST_DOUBLE (r, x);
4940132743Skan      for (i = 0; i < 5; i++)
4941132743Skan        if (real_identical (&r, &ext_80387_constants_table[i]))
4942132743Skan	  return i + 3;
4943132743Skan    }
4944132743Skan
494590284Sobrien  return 0;
494651411Sobrien}
494751411Sobrien
4948132743Skan/* Return the opcode of the special instruction to be used to load
4949132743Skan   the constant X.  */
4950132743Skan
4951132743Skanconst char *
4952132743Skanstandard_80387_constant_opcode (rtx x)
4953132743Skan{
4954132743Skan  switch (standard_80387_constant_p (x))
4955132743Skan    {
4956132743Skan    case 1:
4957132743Skan      return "fldz";
4958132743Skan    case 2:
4959132743Skan      return "fld1";
4960132743Skan    case 3:
4961132743Skan      return "fldlg2";
4962132743Skan    case 4:
4963132743Skan      return "fldln2";
4964132743Skan    case 5:
4965132743Skan      return "fldl2e";
4966132743Skan    case 6:
4967132743Skan      return "fldl2t";
4968132743Skan    case 7:
4969132743Skan      return "fldpi";
4970169705Skan    default:
4971169705Skan      gcc_unreachable ();
4972132743Skan    }
4973132743Skan}
4974132743Skan
4975132743Skan/* Return the CONST_DOUBLE representing the 80387 constant that is
4976132743Skan   loaded by the specified special instruction.  The argument IDX
4977132743Skan   matches the return value from standard_80387_constant_p.  */
4978132743Skan
4979132743Skanrtx
4980132743Skanstandard_80387_constant_rtx (int idx)
4981132743Skan{
4982132743Skan  int i;
4983132743Skan
4984132743Skan  if (! ext_80387_constants_init)
4985132743Skan    init_ext_80387_constants ();
4986132743Skan
4987132743Skan  switch (idx)
4988132743Skan    {
4989132743Skan    case 3:
4990132743Skan    case 4:
4991132743Skan    case 5:
4992132743Skan    case 6:
4993132743Skan    case 7:
4994132743Skan      i = idx - 3;
4995132743Skan      break;
4996132743Skan
4997132743Skan    default:
4998169705Skan      gcc_unreachable ();
4999132743Skan    }
5000132743Skan
5001132743Skan  return CONST_DOUBLE_FROM_REAL_VALUE (ext_80387_constants_table[i],
5002132743Skan				       XFmode);
5003132743Skan}
5004132743Skan
5005169705Skan/* Return 1 if mode is a valid mode for sse.  */
5006169705Skanstatic int
5007169705Skanstandard_sse_mode_p (enum machine_mode mode)
5008169705Skan{
5009169705Skan  switch (mode)
5010169705Skan    {
5011169705Skan    case V16QImode:
5012169705Skan    case V8HImode:
5013169705Skan    case V4SImode:
5014169705Skan    case V2DImode:
5015169705Skan    case V4SFmode:
5016169705Skan    case V2DFmode:
5017169705Skan      return 1;
5018169705Skan
5019169705Skan    default:
5020169705Skan      return 0;
5021169705Skan    }
5022169705Skan}
5023169705Skan
502490284Sobrien/* Return 1 if X is FP constant we can load to SSE register w/o using memory.
502590284Sobrien */
502690284Sobrienint
5027132743Skanstandard_sse_constant_p (rtx x)
502890284Sobrien{
5029169705Skan  enum machine_mode mode = GET_MODE (x);
5030169705Skan
5031169705Skan  if (x == const0_rtx || x == CONST0_RTX (GET_MODE (x)))
5032117408Skan    return 1;
5033169705Skan  if (vector_all_ones_operand (x, mode)
5034169705Skan      && standard_sse_mode_p (mode))
5035169705Skan    return TARGET_SSE2 ? 2 : -1;
5036169705Skan
5037169705Skan  return 0;
503890284Sobrien}
503990284Sobrien
5040169705Skan/* Return the opcode of the special instruction to be used to load
5041169705Skan   the constant X.  */
5042169705Skan
5043169705Skanconst char *
5044169705Skanstandard_sse_constant_opcode (rtx insn, rtx x)
5045169705Skan{
5046169705Skan  switch (standard_sse_constant_p (x))
5047169705Skan    {
5048169705Skan    case 1:
5049169705Skan      if (get_attr_mode (insn) == MODE_V4SF)
5050169705Skan        return "xorps\t%0, %0";
5051169705Skan      else if (get_attr_mode (insn) == MODE_V2DF)
5052169705Skan        return "xorpd\t%0, %0";
5053169705Skan      else
5054169705Skan        return "pxor\t%0, %0";
5055169705Skan    case 2:
5056169705Skan      return "pcmpeqd\t%0, %0";
5057169705Skan    }
5058169705Skan  gcc_unreachable ();
5059169705Skan}
5060169705Skan
506118334Speter/* Returns 1 if OP contains a symbol reference */
506218334Speter
506318334Speterint
5064132743Skansymbolic_reference_mentioned_p (rtx op)
506518334Speter{
5066132743Skan  const char *fmt;
5067132743Skan  int i;
506818334Speter
506918334Speter  if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)
507018334Speter    return 1;
507118334Speter
507218334Speter  fmt = GET_RTX_FORMAT (GET_CODE (op));
507318334Speter  for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
507418334Speter    {
507518334Speter      if (fmt[i] == 'E')
507618334Speter	{
5077132743Skan	  int j;
507818334Speter
507918334Speter	  for (j = XVECLEN (op, i) - 1; j >= 0; j--)
508018334Speter	    if (symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
508118334Speter	      return 1;
508218334Speter	}
508351411Sobrien
508418334Speter      else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i)))
508518334Speter	return 1;
508618334Speter    }
508718334Speter
508818334Speter  return 0;
508918334Speter}
509051411Sobrien
509190284Sobrien/* Return 1 if it is appropriate to emit `ret' instructions in the
509290284Sobrien   body of a function.  Do this only if the epilogue is simple, needing a
509390284Sobrien   couple of insns.  Prior to reloading, we can't tell how many registers
509490284Sobrien   must be saved, so return 0 then.  Return 0 if there is no frame
5095169705Skan   marker to de-allocate.  */
509690284Sobrien
509751411Sobrienint
5098132743Skanix86_can_use_return_insn_p (void)
509951411Sobrien{
510090284Sobrien  struct ix86_frame frame;
510151411Sobrien
510290284Sobrien  if (! reload_completed || frame_pointer_needed)
510390284Sobrien    return 0;
510490284Sobrien
510590284Sobrien  /* Don't allow more than 32 pop, since that's all we can do
510690284Sobrien     with one instruction.  */
510790284Sobrien  if (current_function_pops_args
510890284Sobrien      && current_function_args_size >= 32768)
510990284Sobrien    return 0;
511090284Sobrien
511190284Sobrien  ix86_compute_frame_layout (&frame);
511290284Sobrien  return frame.to_allocate == 0 && frame.nregs == 0;
511390284Sobrien}
511490284Sobrien
511590284Sobrien/* Value should be nonzero if functions must have frame pointers.
511690284Sobrien   Zero means the frame pointer need not be set up (and parms may
511790284Sobrien   be accessed via the stack pointer) in functions that seem suitable.  */
511851411Sobrien
511951411Sobrienint
5120132743Skanix86_frame_pointer_required (void)
512151411Sobrien{
512290284Sobrien  /* If we accessed previous frames, then the generated code expects
512390284Sobrien     to be able to access the saved ebp value in our frame.  */
512490284Sobrien  if (cfun->machine->accesses_prev_frame)
512590284Sobrien    return 1;
512651411Sobrien
512790284Sobrien  /* Several x86 os'es need a frame pointer for other reasons,
512890284Sobrien     usually pertaining to setjmp.  */
512990284Sobrien  if (SUBTARGET_FRAME_POINTER_REQUIRED)
513090284Sobrien    return 1;
513151411Sobrien
513290284Sobrien  /* In override_options, TARGET_OMIT_LEAF_FRAME_POINTER turns off
513390284Sobrien     the frame pointer by default.  Turn it back on now if we've not
513490284Sobrien     got a leaf function.  */
5135117408Skan  if (TARGET_OMIT_LEAF_FRAME_POINTER
5136169705Skan      && (!current_function_is_leaf
5137169705Skan	  || ix86_current_function_calls_tls_descriptor))
513890284Sobrien    return 1;
513990284Sobrien
5140117408Skan  if (current_function_profile)
5141117408Skan    return 1;
5142117408Skan
514390284Sobrien  return 0;
514451411Sobrien}
514551411Sobrien
514690284Sobrien/* Record that the current function accesses previous call frames.  */
514790284Sobrien
514890284Sobrienvoid
5149132743Skanix86_setup_frame_addresses (void)
515051411Sobrien{
515190284Sobrien  cfun->machine->accesses_prev_frame = 1;
515251411Sobrien}
515351411Sobrien
5154169705Skan#if (defined(HAVE_GAS_HIDDEN) && (SUPPORTS_ONE_ONLY - 0)) || TARGET_MACHO
5155117408Skan# define USE_HIDDEN_LINKONCE 1
5156117408Skan#else
5157117408Skan# define USE_HIDDEN_LINKONCE 0
5158117408Skan#endif
515951411Sobrien
5160117408Skanstatic int pic_labels_used;
5161117408Skan
5162117408Skan/* Fills in the label name that should be used for a pc thunk for
5163117408Skan   the given register.  */
5164117408Skan
5165117408Skanstatic void
5166132743Skanget_pc_thunk_name (char name[32], unsigned int regno)
5167117408Skan{
5168169705Skan  gcc_assert (!TARGET_64BIT);
5169169705Skan
5170117408Skan  if (USE_HIDDEN_LINKONCE)
5171117408Skan    sprintf (name, "__i686.get_pc_thunk.%s", reg_names[regno]);
5172117408Skan  else
5173117408Skan    ASM_GENERATE_INTERNAL_LABEL (name, "LPR", regno);
5174117408Skan}
5175117408Skan
5176117408Skan
517751411Sobrien/* This function generates code for -fpic that loads %ebx with
517851411Sobrien   the return address of the caller and then returns.  */
517951411Sobrien
518051411Sobrienvoid
5181132743Skanix86_file_end (void)
518251411Sobrien{
518351411Sobrien  rtx xops[2];
5184117408Skan  int regno;
518551411Sobrien
5186117408Skan  for (regno = 0; regno < 8; ++regno)
5187117408Skan    {
5188117408Skan      char name[32];
518951411Sobrien
5190117408Skan      if (! ((pic_labels_used >> regno) & 1))
5191117408Skan	continue;
519251411Sobrien
5193117408Skan      get_pc_thunk_name (name, regno);
519451411Sobrien
5195169705Skan#if TARGET_MACHO
5196169705Skan      if (TARGET_MACHO)
5197169705Skan	{
5198169705Skan	  switch_to_section (darwin_sections[text_coal_section]);
5199169705Skan	  fputs ("\t.weak_definition\t", asm_out_file);
5200169705Skan	  assemble_name (asm_out_file, name);
5201169705Skan	  fputs ("\n\t.private_extern\t", asm_out_file);
5202169705Skan	  assemble_name (asm_out_file, name);
5203169705Skan	  fputs ("\n", asm_out_file);
5204169705Skan	  ASM_OUTPUT_LABEL (asm_out_file, name);
5205169705Skan	}
5206169705Skan      else
5207169705Skan#endif
5208117408Skan      if (USE_HIDDEN_LINKONCE)
5209117408Skan	{
5210117408Skan	  tree decl;
521151411Sobrien
5212117408Skan	  decl = build_decl (FUNCTION_DECL, get_identifier (name),
5213117408Skan			     error_mark_node);
5214117408Skan	  TREE_PUBLIC (decl) = 1;
5215117408Skan	  TREE_STATIC (decl) = 1;
5216117408Skan	  DECL_ONE_ONLY (decl) = 1;
521751411Sobrien
5218117408Skan	  (*targetm.asm_out.unique_section) (decl, 0);
5219169705Skan	  switch_to_section (get_named_section (decl, NULL, 0));
5220117408Skan
5221132743Skan	  (*targetm.asm_out.globalize_label) (asm_out_file, name);
5222132743Skan	  fputs ("\t.hidden\t", asm_out_file);
5223132743Skan	  assemble_name (asm_out_file, name);
5224132743Skan	  fputc ('\n', asm_out_file);
5225132743Skan	  ASM_DECLARE_FUNCTION_NAME (asm_out_file, name, decl);
5226117408Skan	}
5227117408Skan      else
5228117408Skan	{
5229169705Skan	  switch_to_section (text_section);
5230132743Skan	  ASM_OUTPUT_LABEL (asm_out_file, name);
5231117408Skan	}
5232117408Skan
5233117408Skan      xops[0] = gen_rtx_REG (SImode, regno);
5234117408Skan      xops[1] = gen_rtx_MEM (SImode, stack_pointer_rtx);
5235117408Skan      output_asm_insn ("mov{l}\t{%1, %0|%0, %1}", xops);
5236117408Skan      output_asm_insn ("ret", xops);
5237117408Skan    }
5238132743Skan
5239132743Skan  if (NEED_INDICATE_EXEC_STACK)
5240132743Skan    file_end_indicate_exec_stack ();
524151411Sobrien}
524251411Sobrien
5243117408Skan/* Emit code for the SET_GOT patterns.  */
5244117408Skan
5245117408Skanconst char *
5246169705Skanoutput_set_got (rtx dest, rtx label ATTRIBUTE_UNUSED)
524718334Speter{
5248117408Skan  rtx xops[3];
524990284Sobrien
5250117408Skan  xops[0] = dest;
5251117408Skan  xops[1] = gen_rtx_SYMBOL_REF (Pmode, GOT_SYMBOL_NAME);
525290284Sobrien
5253117408Skan  if (! TARGET_DEEP_BRANCH_PREDICTION || !flag_pic)
5254117408Skan    {
5255169705Skan      xops[2] = gen_rtx_LABEL_REF (Pmode, label ? label : gen_label_rtx ());
525690284Sobrien
5257117408Skan      if (!flag_pic)
5258117408Skan	output_asm_insn ("mov{l}\t{%2, %0|%0, %2}", xops);
5259117408Skan      else
5260117408Skan	output_asm_insn ("call\t%a2", xops);
5261117408Skan
5262117408Skan#if TARGET_MACHO
5263169705Skan      /* Output the Mach-O "canonical" label name ("Lxx$pb") here too.  This
5264169705Skan         is what will be referenced by the Mach-O PIC subsystem.  */
5265169705Skan      if (!label)
5266169705Skan	ASM_OUTPUT_LABEL (asm_out_file, machopic_function_base_name ());
5267117408Skan#endif
5268169705Skan
5269132743Skan      (*targetm.asm_out.internal_label) (asm_out_file, "L",
5270117408Skan				 CODE_LABEL_NUMBER (XEXP (xops[2], 0)));
5271117408Skan
5272117408Skan      if (flag_pic)
5273117408Skan	output_asm_insn ("pop{l}\t%0", xops);
527451411Sobrien    }
527590284Sobrien  else
527690284Sobrien    {
5277117408Skan      char name[32];
5278117408Skan      get_pc_thunk_name (name, REGNO (dest));
5279117408Skan      pic_labels_used |= 1 << REGNO (dest);
5280117408Skan
5281117408Skan      xops[2] = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (name));
5282117408Skan      xops[2] = gen_rtx_MEM (QImode, xops[2]);
5283117408Skan      output_asm_insn ("call\t%X2", xops);
5284169705Skan      /* Output the Mach-O "canonical" label name ("Lxx$pb") here too.  This
5285169705Skan         is what will be referenced by the Mach-O PIC subsystem.  */
5286169705Skan#if TARGET_MACHO
5287169705Skan      if (!label)
5288169705Skan	ASM_OUTPUT_LABEL (asm_out_file, machopic_function_base_name ());
5289169705Skan      else
5290169705Skan        targetm.asm_out.internal_label (asm_out_file, "L",
5291169705Skan					   CODE_LABEL_NUMBER (label));
5292169705Skan#endif
529390284Sobrien    }
529451411Sobrien
5295169705Skan  if (TARGET_MACHO)
5296169705Skan    return "";
5297169705Skan
5298117408Skan  if (!flag_pic || TARGET_DEEP_BRANCH_PREDICTION)
5299117408Skan    output_asm_insn ("add{l}\t{%1, %0|%0, %1}", xops);
5300169705Skan  else
5301161660Skan    output_asm_insn ("add{l}\t{%1+[.-%a2], %0|%0, %1+(.-%a2)}", xops);
530290284Sobrien
5303117408Skan  return "";
530451411Sobrien}
530551411Sobrien
530690284Sobrien/* Generate an "push" pattern for input ARG.  */
530751411Sobrien
530890284Sobrienstatic rtx
5309132743Skangen_push (rtx arg)
531051411Sobrien{
531190284Sobrien  return gen_rtx_SET (VOIDmode,
531290284Sobrien		      gen_rtx_MEM (Pmode,
531390284Sobrien				   gen_rtx_PRE_DEC (Pmode,
531490284Sobrien						    stack_pointer_rtx)),
531590284Sobrien		      arg);
531651411Sobrien}
531751411Sobrien
5318117408Skan/* Return >= 0 if there is an unused call-clobbered register available
5319117408Skan   for the entire function.  */
5320117408Skan
5321117408Skanstatic unsigned int
5322132743Skanix86_select_alt_pic_regnum (void)
5323117408Skan{
5324169705Skan  if (current_function_is_leaf && !current_function_profile
5325169705Skan      && !ix86_current_function_calls_tls_descriptor)
5326117408Skan    {
5327117408Skan      int i;
5328117408Skan      for (i = 2; i >= 0; --i)
5329117408Skan        if (!regs_ever_live[i])
5330117408Skan	  return i;
5331117408Skan    }
5332117408Skan
5333117408Skan  return INVALID_REGNUM;
5334117408Skan}
5335117408Skan
533690284Sobrien/* Return 1 if we need to save REGNO.  */
533790284Sobrienstatic int
5338132743Skanix86_save_reg (unsigned int regno, int maybe_eh_return)
533951411Sobrien{
5340117408Skan  if (pic_offset_table_rtx
5341117408Skan      && regno == REAL_PIC_OFFSET_TABLE_REGNUM
5342117408Skan      && (regs_ever_live[REAL_PIC_OFFSET_TABLE_REGNUM]
5343117408Skan	  || current_function_profile
5344117408Skan	  || current_function_calls_eh_return
5345117408Skan	  || current_function_uses_const_pool))
5346117408Skan    {
5347117408Skan      if (ix86_select_alt_pic_regnum () != INVALID_REGNUM)
5348117408Skan	return 0;
5349117408Skan      return 1;
5350117408Skan    }
535151411Sobrien
535290284Sobrien  if (current_function_calls_eh_return && maybe_eh_return)
535351411Sobrien    {
535490284Sobrien      unsigned i;
535590284Sobrien      for (i = 0; ; i++)
535651411Sobrien	{
535790284Sobrien	  unsigned test = EH_RETURN_DATA_REGNO (i);
535890284Sobrien	  if (test == INVALID_REGNUM)
535990284Sobrien	    break;
5360117408Skan	  if (test == regno)
536190284Sobrien	    return 1;
536251411Sobrien	}
536390284Sobrien    }
536451411Sobrien
5365169705Skan  if (cfun->machine->force_align_arg_pointer
5366169705Skan      && regno == REGNO (cfun->machine->force_align_arg_pointer))
5367169705Skan    return 1;
5368169705Skan
536990284Sobrien  return (regs_ever_live[regno]
537090284Sobrien	  && !call_used_regs[regno]
537190284Sobrien	  && !fixed_regs[regno]
537290284Sobrien	  && (regno != HARD_FRAME_POINTER_REGNUM || !frame_pointer_needed));
537390284Sobrien}
537451411Sobrien
537590284Sobrien/* Return number of registers to be saved on the stack.  */
537651411Sobrien
537790284Sobrienstatic int
5378132743Skanix86_nsaved_regs (void)
537990284Sobrien{
538090284Sobrien  int nregs = 0;
538190284Sobrien  int regno;
538290284Sobrien
538390284Sobrien  for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno--)
538490284Sobrien    if (ix86_save_reg (regno, true))
538590284Sobrien      nregs++;
538690284Sobrien  return nregs;
538790284Sobrien}
538890284Sobrien
538990284Sobrien/* Return the offset between two registers, one to be eliminated, and the other
539090284Sobrien   its replacement, at the start of a routine.  */
539190284Sobrien
539290284SobrienHOST_WIDE_INT
5393132743Skanix86_initial_elimination_offset (int from, int to)
539490284Sobrien{
539590284Sobrien  struct ix86_frame frame;
539690284Sobrien  ix86_compute_frame_layout (&frame);
539790284Sobrien
539890284Sobrien  if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
539990284Sobrien    return frame.hard_frame_pointer_offset;
540090284Sobrien  else if (from == FRAME_POINTER_REGNUM
540190284Sobrien	   && to == HARD_FRAME_POINTER_REGNUM)
540290284Sobrien    return frame.hard_frame_pointer_offset - frame.frame_pointer_offset;
540351411Sobrien  else
540451411Sobrien    {
5405169705Skan      gcc_assert (to == STACK_POINTER_REGNUM);
5406169705Skan
5407169705Skan      if (from == ARG_POINTER_REGNUM)
540890284Sobrien	return frame.stack_pointer_offset;
5409169705Skan
5410169705Skan      gcc_assert (from == FRAME_POINTER_REGNUM);
5411169705Skan      return frame.stack_pointer_offset - frame.frame_pointer_offset;
541251411Sobrien    }
541351411Sobrien}
541451411Sobrien
541590284Sobrien/* Fill structure ix86_frame about frame of currently computed function.  */
541652294Sobrien
541790284Sobrienstatic void
5418132743Skanix86_compute_frame_layout (struct ix86_frame *frame)
541952294Sobrien{
542052294Sobrien  HOST_WIDE_INT total_size;
5421169705Skan  unsigned int stack_alignment_needed;
5422132743Skan  HOST_WIDE_INT offset;
5423169705Skan  unsigned int preferred_alignment;
542490284Sobrien  HOST_WIDE_INT size = get_frame_size ();
542552294Sobrien
542690284Sobrien  frame->nregs = ix86_nsaved_regs ();
542790284Sobrien  total_size = size;
542852294Sobrien
5429169705Skan  stack_alignment_needed = cfun->stack_alignment_needed / BITS_PER_UNIT;
5430169705Skan  preferred_alignment = cfun->preferred_stack_boundary / BITS_PER_UNIT;
5431169705Skan
5432132743Skan  /* During reload iteration the amount of registers saved can change.
5433132743Skan     Recompute the value as needed.  Do not recompute when amount of registers
5434169705Skan     didn't change as reload does multiple calls to the function and does not
5435132743Skan     expect the decision to change within single iteration.  */
5436132743Skan  if (!optimize_size
5437132743Skan      && cfun->machine->use_fast_prologue_epilogue_nregs != frame->nregs)
5438132743Skan    {
5439132743Skan      int count = frame->nregs;
5440132743Skan
5441132743Skan      cfun->machine->use_fast_prologue_epilogue_nregs = count;
5442132743Skan      /* The fast prologue uses move instead of push to save registers.  This
5443132743Skan         is significantly longer, but also executes faster as modern hardware
5444132743Skan         can execute the moves in parallel, but can't do that for push/pop.
5445132743Skan
5446132743Skan	 Be careful about choosing what prologue to emit:  When function takes
5447132743Skan	 many instructions to execute we may use slow version as well as in
5448132743Skan	 case function is known to be outside hot spot (this is known with
5449132743Skan	 feedback only).  Weight the size of function by number of registers
5450132743Skan	 to save as it is cheap to use one or two push instructions but very
5451132743Skan	 slow to use many of them.  */
5452132743Skan      if (count)
5453132743Skan	count = (count - 1) * FAST_PROLOGUE_INSN_COUNT;
5454132743Skan      if (cfun->function_frequency < FUNCTION_FREQUENCY_NORMAL
5455132743Skan	  || (flag_branch_probabilities
5456132743Skan	      && cfun->function_frequency < FUNCTION_FREQUENCY_HOT))
5457132743Skan        cfun->machine->use_fast_prologue_epilogue = false;
5458132743Skan      else
5459132743Skan        cfun->machine->use_fast_prologue_epilogue
5460132743Skan	   = !expensive_function_p (count);
5461132743Skan    }
5462132743Skan  if (TARGET_PROLOGUE_USING_MOVE
5463132743Skan      && cfun->machine->use_fast_prologue_epilogue)
5464132743Skan    frame->save_regs_using_mov = true;
5465132743Skan  else
5466132743Skan    frame->save_regs_using_mov = false;
5467132743Skan
5468132743Skan
5469117408Skan  /* Skip return address and saved base pointer.  */
547090284Sobrien  offset = frame_pointer_needed ? UNITS_PER_WORD * 2 : UNITS_PER_WORD;
547152294Sobrien
547290284Sobrien  frame->hard_frame_pointer_offset = offset;
547352294Sobrien
547490284Sobrien  /* Do some sanity checking of stack_alignment_needed and
547590284Sobrien     preferred_alignment, since i386 port is the only using those features
547690284Sobrien     that may break easily.  */
547752294Sobrien
5478169705Skan  gcc_assert (!size || stack_alignment_needed);
5479169705Skan  gcc_assert (preferred_alignment >= STACK_BOUNDARY / BITS_PER_UNIT);
5480169705Skan  gcc_assert (preferred_alignment <= PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT);
5481169705Skan  gcc_assert (stack_alignment_needed
5482169705Skan	      <= PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT);
548352294Sobrien
548490284Sobrien  if (stack_alignment_needed < STACK_BOUNDARY / BITS_PER_UNIT)
548590284Sobrien    stack_alignment_needed = STACK_BOUNDARY / BITS_PER_UNIT;
548652294Sobrien
548790284Sobrien  /* Register save area */
548890284Sobrien  offset += frame->nregs * UNITS_PER_WORD;
548952294Sobrien
549090284Sobrien  /* Va-arg area */
549190284Sobrien  if (ix86_save_varrargs_registers)
549290284Sobrien    {
549390284Sobrien      offset += X86_64_VARARGS_SIZE;
549490284Sobrien      frame->va_arg_size = X86_64_VARARGS_SIZE;
549590284Sobrien    }
549690284Sobrien  else
549790284Sobrien    frame->va_arg_size = 0;
549852294Sobrien
549990284Sobrien  /* Align start of frame for local function.  */
550090284Sobrien  frame->padding1 = ((offset + stack_alignment_needed - 1)
550190284Sobrien		     & -stack_alignment_needed) - offset;
550252294Sobrien
550390284Sobrien  offset += frame->padding1;
550452294Sobrien
550590284Sobrien  /* Frame pointer points here.  */
550690284Sobrien  frame->frame_pointer_offset = offset;
550790284Sobrien
550890284Sobrien  offset += size;
550990284Sobrien
5510102800Skan  /* Add outgoing arguments area.  Can be skipped if we eliminated
5511132743Skan     all the function calls as dead code.
5512132743Skan     Skipping is however impossible when function calls alloca.  Alloca
5513132743Skan     expander assumes that last current_function_outgoing_args_size
5514132743Skan     of stack frame are unused.  */
5515132743Skan  if (ACCUMULATE_OUTGOING_ARGS
5516169705Skan      && (!current_function_is_leaf || current_function_calls_alloca
5517169705Skan	  || ix86_current_function_calls_tls_descriptor))
551890284Sobrien    {
551990284Sobrien      offset += current_function_outgoing_args_size;
552090284Sobrien      frame->outgoing_arguments_size = current_function_outgoing_args_size;
552190284Sobrien    }
552290284Sobrien  else
552390284Sobrien    frame->outgoing_arguments_size = 0;
552490284Sobrien
5525102800Skan  /* Align stack boundary.  Only needed if we're calling another function
5526102800Skan     or using alloca.  */
5527169705Skan  if (!current_function_is_leaf || current_function_calls_alloca
5528169705Skan      || ix86_current_function_calls_tls_descriptor)
5529102800Skan    frame->padding2 = ((offset + preferred_alignment - 1)
5530102800Skan		       & -preferred_alignment) - offset;
5531102800Skan  else
5532102800Skan    frame->padding2 = 0;
553390284Sobrien
553490284Sobrien  offset += frame->padding2;
553590284Sobrien
553690284Sobrien  /* We've reached end of stack frame.  */
553790284Sobrien  frame->stack_pointer_offset = offset;
553890284Sobrien
553990284Sobrien  /* Size prologue needs to allocate.  */
554090284Sobrien  frame->to_allocate =
554190284Sobrien    (size + frame->padding1 + frame->padding2
554290284Sobrien     + frame->outgoing_arguments_size + frame->va_arg_size);
554390284Sobrien
5544132743Skan  if ((!frame->to_allocate && frame->nregs <= 1)
5545132743Skan      || (TARGET_64BIT && frame->to_allocate >= (HOST_WIDE_INT) 0x80000000))
5546132743Skan    frame->save_regs_using_mov = false;
5547132743Skan
5548132743Skan  if (TARGET_RED_ZONE && current_function_sp_is_unchanging
5549169705Skan      && current_function_is_leaf
5550169705Skan      && !ix86_current_function_calls_tls_descriptor)
555190284Sobrien    {
555290284Sobrien      frame->red_zone_size = frame->to_allocate;
5553132743Skan      if (frame->save_regs_using_mov)
5554132743Skan	frame->red_zone_size += frame->nregs * UNITS_PER_WORD;
555590284Sobrien      if (frame->red_zone_size > RED_ZONE_SIZE - RED_ZONE_RESERVE)
555690284Sobrien	frame->red_zone_size = RED_ZONE_SIZE - RED_ZONE_RESERVE;
555790284Sobrien    }
555890284Sobrien  else
555990284Sobrien    frame->red_zone_size = 0;
556090284Sobrien  frame->to_allocate -= frame->red_zone_size;
556190284Sobrien  frame->stack_pointer_offset -= frame->red_zone_size;
556290284Sobrien#if 0
5563237021Spfg  fprintf (stderr, "nregs: %i\n", frame->nregs);
5564237021Spfg  fprintf (stderr, "size: %i\n", size);
5565237021Spfg  fprintf (stderr, "alignment1: %i\n", stack_alignment_needed);
5566237021Spfg  fprintf (stderr, "padding1: %i\n", frame->padding1);
5567237021Spfg  fprintf (stderr, "va_arg: %i\n", frame->va_arg_size);
5568237021Spfg  fprintf (stderr, "padding2: %i\n", frame->padding2);
5569237021Spfg  fprintf (stderr, "to_allocate: %i\n", frame->to_allocate);
5570237021Spfg  fprintf (stderr, "red_zone_size: %i\n", frame->red_zone_size);
5571237021Spfg  fprintf (stderr, "frame_pointer_offset: %i\n", frame->frame_pointer_offset);
5572237021Spfg  fprintf (stderr, "hard_frame_pointer_offset: %i\n",
5573237021Spfg	   frame->hard_frame_pointer_offset);
5574237021Spfg  fprintf (stderr, "stack_pointer_offset: %i\n", frame->stack_pointer_offset);
557590284Sobrien#endif
557652294Sobrien}
557752294Sobrien
557890284Sobrien/* Emit code to save registers in the prologue.  */
557990284Sobrien
558051411Sobrienstatic void
5581132743Skanix86_emit_save_regs (void)
558251411Sobrien{
5583169705Skan  unsigned int regno;
558451411Sobrien  rtx insn;
558518334Speter
5586169705Skan  for (regno = FIRST_PSEUDO_REGISTER; regno-- > 0; )
558790284Sobrien    if (ix86_save_reg (regno, true))
558890284Sobrien      {
558990284Sobrien	insn = emit_insn (gen_push (gen_rtx_REG (Pmode, regno)));
559090284Sobrien	RTX_FRAME_RELATED_P (insn) = 1;
559190284Sobrien      }
559290284Sobrien}
559351411Sobrien
559490284Sobrien/* Emit code to save registers using MOV insns.  First register
559590284Sobrien   is restored from POINTER + OFFSET.  */
559690284Sobrienstatic void
5597132743Skanix86_emit_save_regs_using_mov (rtx pointer, HOST_WIDE_INT offset)
559890284Sobrien{
5599169705Skan  unsigned int regno;
560090284Sobrien  rtx insn;
560190284Sobrien
560290284Sobrien  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
560390284Sobrien    if (ix86_save_reg (regno, true))
560490284Sobrien      {
560590284Sobrien	insn = emit_move_insn (adjust_address (gen_rtx_MEM (Pmode, pointer),
560690284Sobrien					       Pmode, offset),
560790284Sobrien			       gen_rtx_REG (Pmode, regno));
560890284Sobrien	RTX_FRAME_RELATED_P (insn) = 1;
560990284Sobrien	offset += UNITS_PER_WORD;
561090284Sobrien      }
561190284Sobrien}
561290284Sobrien
5613132743Skan/* Expand prologue or epilogue stack adjustment.
5614132743Skan   The pattern exist to put a dependency on all ebp-based memory accesses.
5615132743Skan   STYLE should be negative if instructions should be marked as frame related,
5616132743Skan   zero if %r11 register is live and cannot be freely used and positive
5617132743Skan   otherwise.  */
5618132743Skan
5619132743Skanstatic void
5620132743Skanpro_epilogue_adjust_stack (rtx dest, rtx src, rtx offset, int style)
5621132743Skan{
5622132743Skan  rtx insn;
5623132743Skan
5624132743Skan  if (! TARGET_64BIT)
5625132743Skan    insn = emit_insn (gen_pro_epilogue_adjust_stack_1 (dest, src, offset));
5626132743Skan  else if (x86_64_immediate_operand (offset, DImode))
5627132743Skan    insn = emit_insn (gen_pro_epilogue_adjust_stack_rex64 (dest, src, offset));
5628132743Skan  else
5629132743Skan    {
5630132743Skan      rtx r11;
5631132743Skan      /* r11 is used by indirect sibcall return as well, set before the
5632132743Skan	 epilogue and used after the epilogue.  ATM indirect sibcall
5633132743Skan	 shouldn't be used together with huge frame sizes in one
5634132743Skan	 function because of the frame_size check in sibcall.c.  */
5635169705Skan      gcc_assert (style);
5636132743Skan      r11 = gen_rtx_REG (DImode, FIRST_REX_INT_REG + 3 /* R11 */);
5637132743Skan      insn = emit_insn (gen_rtx_SET (DImode, r11, offset));
5638132743Skan      if (style < 0)
5639132743Skan	RTX_FRAME_RELATED_P (insn) = 1;
5640132743Skan      insn = emit_insn (gen_pro_epilogue_adjust_stack_rex64_2 (dest, src, r11,
5641132743Skan							       offset));
5642132743Skan    }
5643132743Skan  if (style < 0)
5644132743Skan    RTX_FRAME_RELATED_P (insn) = 1;
5645132743Skan}
5646132743Skan
5647169705Skan/* Handle the TARGET_INTERNAL_ARG_POINTER hook.  */
5648169705Skan
5649169705Skanstatic rtx
5650169705Skanix86_internal_arg_pointer (void)
5651169705Skan{
5652169705Skan  bool has_force_align_arg_pointer =
5653169705Skan    (0 != lookup_attribute (ix86_force_align_arg_pointer_string,
5654169705Skan			    TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl))));
5655169705Skan  if ((FORCE_PREFERRED_STACK_BOUNDARY_IN_MAIN
5656169705Skan       && DECL_NAME (current_function_decl)
5657169705Skan       && MAIN_NAME_P (DECL_NAME (current_function_decl))
5658169705Skan       && DECL_FILE_SCOPE_P (current_function_decl))
5659169705Skan      || ix86_force_align_arg_pointer
5660169705Skan      || has_force_align_arg_pointer)
5661169705Skan    {
5662169705Skan      /* Nested functions can't realign the stack due to a register
5663169705Skan	 conflict.  */
5664169705Skan      if (DECL_CONTEXT (current_function_decl)
5665169705Skan	  && TREE_CODE (DECL_CONTEXT (current_function_decl)) == FUNCTION_DECL)
5666169705Skan	{
5667169705Skan	  if (ix86_force_align_arg_pointer)
5668169705Skan	    warning (0, "-mstackrealign ignored for nested functions");
5669169705Skan	  if (has_force_align_arg_pointer)
5670169705Skan	    error ("%s not supported for nested functions",
5671169705Skan		   ix86_force_align_arg_pointer_string);
5672169705Skan	  return virtual_incoming_args_rtx;
5673169705Skan	}
5674169705Skan      cfun->machine->force_align_arg_pointer = gen_rtx_REG (Pmode, 2);
5675169705Skan      return copy_to_reg (cfun->machine->force_align_arg_pointer);
5676169705Skan    }
5677169705Skan  else
5678169705Skan    return virtual_incoming_args_rtx;
5679169705Skan}
5680169705Skan
5681169705Skan/* Handle the TARGET_DWARF_HANDLE_FRAME_UNSPEC hook.
5682169705Skan   This is called from dwarf2out.c to emit call frame instructions
5683169705Skan   for frame-related insns containing UNSPECs and UNSPEC_VOLATILEs. */
5684169705Skanstatic void
5685169705Skanix86_dwarf_handle_frame_unspec (const char *label, rtx pattern, int index)
5686169705Skan{
5687169705Skan  rtx unspec = SET_SRC (pattern);
5688169705Skan  gcc_assert (GET_CODE (unspec) == UNSPEC);
5689169705Skan
5690169705Skan  switch (index)
5691169705Skan    {
5692169705Skan    case UNSPEC_REG_SAVE:
5693169705Skan      dwarf2out_reg_save_reg (label, XVECEXP (unspec, 0, 0),
5694169705Skan			      SET_DEST (pattern));
5695169705Skan      break;
5696169705Skan    case UNSPEC_DEF_CFA:
5697169705Skan      dwarf2out_def_cfa (label, REGNO (SET_DEST (pattern)),
5698169705Skan			 INTVAL (XVECEXP (unspec, 0, 0)));
5699169705Skan      break;
5700169705Skan    default:
5701169705Skan      gcc_unreachable ();
5702169705Skan    }
5703169705Skan}
5704169705Skan
570590284Sobrien/* Expand the prologue into a bunch of separate insns.  */
570690284Sobrien
570790284Sobrienvoid
5708132743Skanix86_expand_prologue (void)
570990284Sobrien{
571090284Sobrien  rtx insn;
5711117408Skan  bool pic_reg_used;
571290284Sobrien  struct ix86_frame frame;
571390284Sobrien  HOST_WIDE_INT allocate;
571490284Sobrien
571590284Sobrien  ix86_compute_frame_layout (&frame);
571690284Sobrien
5717169705Skan  if (cfun->machine->force_align_arg_pointer)
5718169705Skan    {
5719169705Skan      rtx x, y;
5720169705Skan
5721169705Skan      /* Grab the argument pointer.  */
5722169705Skan      x = plus_constant (stack_pointer_rtx, 4);
5723169705Skan      y = cfun->machine->force_align_arg_pointer;
5724169705Skan      insn = emit_insn (gen_rtx_SET (VOIDmode, y, x));
5725169705Skan      RTX_FRAME_RELATED_P (insn) = 1;
5726169705Skan
5727169705Skan      /* The unwind info consists of two parts: install the fafp as the cfa,
5728169705Skan	 and record the fafp as the "save register" of the stack pointer.
5729169705Skan	 The later is there in order that the unwinder can see where it
5730169705Skan	 should restore the stack pointer across the and insn.  */
5731169705Skan      x = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, const0_rtx), UNSPEC_DEF_CFA);
5732169705Skan      x = gen_rtx_SET (VOIDmode, y, x);
5733169705Skan      RTX_FRAME_RELATED_P (x) = 1;
5734169705Skan      y = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, stack_pointer_rtx),
5735169705Skan			  UNSPEC_REG_SAVE);
5736169705Skan      y = gen_rtx_SET (VOIDmode, cfun->machine->force_align_arg_pointer, y);
5737169705Skan      RTX_FRAME_RELATED_P (y) = 1;
5738169705Skan      x = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, x, y));
5739169705Skan      x = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, x, NULL);
5740169705Skan      REG_NOTES (insn) = x;
5741169705Skan
5742169705Skan      /* Align the stack.  */
5743169705Skan      emit_insn (gen_andsi3 (stack_pointer_rtx, stack_pointer_rtx,
5744169705Skan			     GEN_INT (-16)));
5745169705Skan
5746169705Skan      /* And here we cheat like madmen with the unwind info.  We force the
5747169705Skan	 cfa register back to sp+4, which is exactly what it was at the
5748169705Skan	 start of the function.  Re-pushing the return address results in
5749169705Skan	 the return at the same spot relative to the cfa, and thus is
5750169705Skan	 correct wrt the unwind info.  */
5751169705Skan      x = cfun->machine->force_align_arg_pointer;
5752169705Skan      x = gen_frame_mem (Pmode, plus_constant (x, -4));
5753169705Skan      insn = emit_insn (gen_push (x));
5754169705Skan      RTX_FRAME_RELATED_P (insn) = 1;
5755169705Skan
5756169705Skan      x = GEN_INT (4);
5757169705Skan      x = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, x), UNSPEC_DEF_CFA);
5758169705Skan      x = gen_rtx_SET (VOIDmode, stack_pointer_rtx, x);
5759169705Skan      x = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, x, NULL);
5760169705Skan      REG_NOTES (insn) = x;
5761169705Skan    }
5762169705Skan
576390284Sobrien  /* Note: AT&T enter does NOT have reversed args.  Enter is probably
576490284Sobrien     slower on all targets.  Also sdb doesn't like it.  */
576590284Sobrien
576618334Speter  if (frame_pointer_needed)
576718334Speter    {
576890284Sobrien      insn = emit_insn (gen_push (hard_frame_pointer_rtx));
576990284Sobrien      RTX_FRAME_RELATED_P (insn) = 1;
577051411Sobrien
577190284Sobrien      insn = emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
577290284Sobrien      RTX_FRAME_RELATED_P (insn) = 1;
577390284Sobrien    }
577451411Sobrien
577590284Sobrien  allocate = frame.to_allocate;
577651411Sobrien
5777132743Skan  if (!frame.save_regs_using_mov)
577890284Sobrien    ix86_emit_save_regs ();
577990284Sobrien  else
578090284Sobrien    allocate += frame.nregs * UNITS_PER_WORD;
578151411Sobrien
5782132743Skan  /* When using red zone we may start register saving before allocating
5783132743Skan     the stack frame saving one cycle of the prologue.  */
5784132743Skan  if (TARGET_RED_ZONE && frame.save_regs_using_mov)
5785132743Skan    ix86_emit_save_regs_using_mov (frame_pointer_needed ? hard_frame_pointer_rtx
5786132743Skan				   : stack_pointer_rtx,
5787132743Skan				   -frame.nregs * UNITS_PER_WORD);
5788132743Skan
578990284Sobrien  if (allocate == 0)
579051411Sobrien    ;
579190284Sobrien  else if (! TARGET_STACK_PROBE || allocate < CHECK_STACK_LIMIT)
5792132743Skan    pro_epilogue_adjust_stack (stack_pointer_rtx, stack_pointer_rtx,
5793132743Skan			       GEN_INT (-allocate), -1);
579451411Sobrien  else
579551411Sobrien    {
5796132743Skan      /* Only valid for Win32.  */
5797132743Skan      rtx eax = gen_rtx_REG (SImode, 0);
5798132743Skan      bool eax_live = ix86_eax_live_at_start_p ();
5799169705Skan      rtx t;
580018334Speter
5801169705Skan      gcc_assert (!TARGET_64BIT);
580251411Sobrien
5803132743Skan      if (eax_live)
5804132743Skan	{
5805132743Skan	  emit_insn (gen_push (eax));
5806132743Skan	  allocate -= 4;
5807132743Skan	}
580851411Sobrien
5809169705Skan      emit_move_insn (eax, GEN_INT (allocate));
581051411Sobrien
5811132743Skan      insn = emit_insn (gen_allocate_stack_worker (eax));
5812132743Skan      RTX_FRAME_RELATED_P (insn) = 1;
5813169705Skan      t = gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (-allocate));
5814169705Skan      t = gen_rtx_SET (VOIDmode, stack_pointer_rtx, t);
5815169705Skan      REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
5816169705Skan					    t, REG_NOTES (insn));
5817117408Skan
5818132743Skan      if (eax_live)
5819132743Skan	{
5820169705Skan	  if (frame_pointer_needed)
5821169705Skan	    t = plus_constant (hard_frame_pointer_rtx,
5822169705Skan			       allocate
5823169705Skan			       - frame.to_allocate
5824169705Skan			       - frame.nregs * UNITS_PER_WORD);
5825169705Skan	  else
5826169705Skan	    t = plus_constant (stack_pointer_rtx, allocate);
5827132743Skan	  emit_move_insn (eax, gen_rtx_MEM (SImode, t));
5828132743Skan	}
582990284Sobrien    }
5830132743Skan
5831132743Skan  if (frame.save_regs_using_mov && !TARGET_RED_ZONE)
583290284Sobrien    {
583390284Sobrien      if (!frame_pointer_needed || !frame.to_allocate)
583490284Sobrien        ix86_emit_save_regs_using_mov (stack_pointer_rtx, frame.to_allocate);
583590284Sobrien      else
583690284Sobrien        ix86_emit_save_regs_using_mov (hard_frame_pointer_rtx,
583790284Sobrien				       -frame.nregs * UNITS_PER_WORD);
583890284Sobrien    }
583951411Sobrien
5840117408Skan  pic_reg_used = false;
5841117408Skan  if (pic_offset_table_rtx
5842117408Skan      && (regs_ever_live[REAL_PIC_OFFSET_TABLE_REGNUM]
5843117408Skan	  || current_function_profile))
5844117408Skan    {
5845117408Skan      unsigned int alt_pic_reg_used = ix86_select_alt_pic_regnum ();
5846117408Skan
5847117408Skan      if (alt_pic_reg_used != INVALID_REGNUM)
5848117408Skan	REGNO (pic_offset_table_rtx) = alt_pic_reg_used;
5849117408Skan
5850117408Skan      pic_reg_used = true;
5851117408Skan    }
5852117408Skan
585318334Speter  if (pic_reg_used)
5854117408Skan    {
5855169705Skan      if (TARGET_64BIT)
5856169705Skan        insn = emit_insn (gen_set_got_rex64 (pic_offset_table_rtx));
5857169705Skan      else
5858169705Skan        insn = emit_insn (gen_set_got (pic_offset_table_rtx));
585918334Speter
5860117408Skan      /* Even with accurate pre-reload life analysis, we can wind up
5861117408Skan	 deleting all references to the pic register after reload.
5862117408Skan	 Consider if cross-jumping unifies two sides of a branch
5863132743Skan	 controlled by a comparison vs the only read from a global.
5864117408Skan	 In which case, allow the set_got to be deleted, though we're
5865117408Skan	 too late to do anything about the ebx save in the prologue.  */
5866117408Skan      REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx, NULL);
5867117408Skan    }
5868117408Skan
5869117408Skan  /* Prevent function calls from be scheduled before the call to mcount.
5870117408Skan     In the pic_reg_used case, make sure that the got load isn't deleted.  */
5871117408Skan  if (current_function_profile)
5872117408Skan    emit_insn (gen_blockage (pic_reg_used ? pic_offset_table_rtx : const0_rtx));
587318334Speter}
587418334Speter
587590284Sobrien/* Emit code to restore saved registers using MOV insns.  First register
587690284Sobrien   is restored from POINTER + OFFSET.  */
587790284Sobrienstatic void
5878132743Skanix86_emit_restore_regs_using_mov (rtx pointer, HOST_WIDE_INT offset,
5879132743Skan				  int maybe_eh_return)
588018334Speter{
588118334Speter  int regno;
5882132743Skan  rtx base_address = gen_rtx_MEM (Pmode, pointer);
588318334Speter
588490284Sobrien  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
588590284Sobrien    if (ix86_save_reg (regno, maybe_eh_return))
588690284Sobrien      {
5887132743Skan	/* Ensure that adjust_address won't be forced to produce pointer
5888132743Skan	   out of range allowed by x86-64 instruction set.  */
5889132743Skan	if (TARGET_64BIT && offset != trunc_int_for_mode (offset, SImode))
5890132743Skan	  {
5891132743Skan	    rtx r11;
5892132743Skan
5893132743Skan	    r11 = gen_rtx_REG (DImode, FIRST_REX_INT_REG + 3 /* R11 */);
5894132743Skan	    emit_move_insn (r11, GEN_INT (offset));
5895132743Skan	    emit_insn (gen_adddi3 (r11, r11, pointer));
5896132743Skan	    base_address = gen_rtx_MEM (Pmode, r11);
5897132743Skan	    offset = 0;
5898132743Skan	  }
589990284Sobrien	emit_move_insn (gen_rtx_REG (Pmode, regno),
5900132743Skan			adjust_address (base_address, Pmode, offset));
590190284Sobrien	offset += UNITS_PER_WORD;
590290284Sobrien      }
590318334Speter}
590418334Speter
590590284Sobrien/* Restore function stack, frame, and registers.  */
590618334Speter
590718334Spetervoid
5908132743Skanix86_expand_epilogue (int style)
590918334Speter{
591090284Sobrien  int regno;
591152294Sobrien  int sp_valid = !frame_pointer_needed || current_function_sp_is_unchanging;
591290284Sobrien  struct ix86_frame frame;
591352294Sobrien  HOST_WIDE_INT offset;
591418334Speter
591590284Sobrien  ix86_compute_frame_layout (&frame);
591618334Speter
591790284Sobrien  /* Calculate start of saved registers relative to ebp.  Special care
591890284Sobrien     must be taken for the normal return case of a function using
591990284Sobrien     eh_return: the eax and edx registers are marked as saved, but not
592090284Sobrien     restored along this path.  */
592190284Sobrien  offset = frame.nregs;
592290284Sobrien  if (current_function_calls_eh_return && style != 2)
592390284Sobrien    offset -= 2;
592490284Sobrien  offset *= -UNITS_PER_WORD;
592518334Speter
592690284Sobrien  /* If we're only restoring one register and sp is not valid then
592790284Sobrien     using a move instruction to restore the register since it's
592890284Sobrien     less work than reloading sp and popping the register.
592918334Speter
593090284Sobrien     The default code result in stack adjustment using add/lea instruction,
593190284Sobrien     while this code results in LEAVE instruction (or discrete equivalent),
593290284Sobrien     so it is profitable in some other cases as well.  Especially when there
593390284Sobrien     are no registers to restore.  We also use this code when TARGET_USE_LEAVE
5934132743Skan     and there is exactly one register to pop. This heuristic may need some
593590284Sobrien     tuning in future.  */
593690284Sobrien  if ((!sp_valid && frame.nregs <= 1)
593790284Sobrien      || (TARGET_EPILOGUE_USING_MOVE
5938132743Skan	  && cfun->machine->use_fast_prologue_epilogue
593990284Sobrien	  && (frame.nregs > 1 || frame.to_allocate))
594090284Sobrien      || (frame_pointer_needed && !frame.nregs && frame.to_allocate)
594190284Sobrien      || (frame_pointer_needed && TARGET_USE_LEAVE
5942132743Skan	  && cfun->machine->use_fast_prologue_epilogue
5943132743Skan	  && frame.nregs == 1)
594490284Sobrien      || current_function_calls_eh_return)
594590284Sobrien    {
594690284Sobrien      /* Restore registers.  We can use ebp or esp to address the memory
594790284Sobrien	 locations.  If both are available, default to ebp, since offsets
594890284Sobrien	 are known to be small.  Only exception is esp pointing directly to the
594990284Sobrien	 end of block of saved registers, where we may simplify addressing
595090284Sobrien	 mode.  */
595151411Sobrien
595290284Sobrien      if (!frame_pointer_needed || (sp_valid && !frame.to_allocate))
595390284Sobrien	ix86_emit_restore_regs_using_mov (stack_pointer_rtx,
595490284Sobrien					  frame.to_allocate, style == 2);
595590284Sobrien      else
595690284Sobrien	ix86_emit_restore_regs_using_mov (hard_frame_pointer_rtx,
595790284Sobrien					  offset, style == 2);
595851411Sobrien
595990284Sobrien      /* eh_return epilogues need %ecx added to the stack pointer.  */
596090284Sobrien      if (style == 2)
596190284Sobrien	{
596290284Sobrien	  rtx tmp, sa = EH_RETURN_STACKADJ_RTX;
596351411Sobrien
596490284Sobrien	  if (frame_pointer_needed)
596590284Sobrien	    {
596690284Sobrien	      tmp = gen_rtx_PLUS (Pmode, hard_frame_pointer_rtx, sa);
596790284Sobrien	      tmp = plus_constant (tmp, UNITS_PER_WORD);
596890284Sobrien	      emit_insn (gen_rtx_SET (VOIDmode, sa, tmp));
596956810Sobrien
597090284Sobrien	      tmp = gen_rtx_MEM (Pmode, hard_frame_pointer_rtx);
597190284Sobrien	      emit_move_insn (hard_frame_pointer_rtx, tmp);
597252294Sobrien
5973132743Skan	      pro_epilogue_adjust_stack (stack_pointer_rtx, sa,
5974132743Skan					 const0_rtx, style);
597590284Sobrien	    }
597690284Sobrien	  else
597790284Sobrien	    {
597890284Sobrien	      tmp = gen_rtx_PLUS (Pmode, stack_pointer_rtx, sa);
597990284Sobrien	      tmp = plus_constant (tmp, (frame.to_allocate
598090284Sobrien                                         + frame.nregs * UNITS_PER_WORD));
598190284Sobrien	      emit_insn (gen_rtx_SET (VOIDmode, stack_pointer_rtx, tmp));
598290284Sobrien	    }
598390284Sobrien	}
598490284Sobrien      else if (!frame_pointer_needed)
5985132743Skan	pro_epilogue_adjust_stack (stack_pointer_rtx, stack_pointer_rtx,
5986132743Skan				   GEN_INT (frame.to_allocate
5987132743Skan					    + frame.nregs * UNITS_PER_WORD),
5988132743Skan				   style);
598990284Sobrien      /* If not an i386, mov & pop is faster than "leave".  */
5990132743Skan      else if (TARGET_USE_LEAVE || optimize_size
5991132743Skan	       || !cfun->machine->use_fast_prologue_epilogue)
599290284Sobrien	emit_insn (TARGET_64BIT ? gen_leave_rex64 () : gen_leave ());
599390284Sobrien      else
599418334Speter	{
5995132743Skan	  pro_epilogue_adjust_stack (stack_pointer_rtx,
5996132743Skan				     hard_frame_pointer_rtx,
5997132743Skan				     const0_rtx, style);
599890284Sobrien	  if (TARGET_64BIT)
599990284Sobrien	    emit_insn (gen_popdi1 (hard_frame_pointer_rtx));
600051411Sobrien	  else
600190284Sobrien	    emit_insn (gen_popsi1 (hard_frame_pointer_rtx));
600218334Speter	}
600390284Sobrien    }
600490284Sobrien  else
600590284Sobrien    {
600690284Sobrien      /* First step is to deallocate the stack frame so that we can
600790284Sobrien	 pop the registers.  */
600890284Sobrien      if (!sp_valid)
600990284Sobrien	{
6010169705Skan	  gcc_assert (frame_pointer_needed);
6011132743Skan	  pro_epilogue_adjust_stack (stack_pointer_rtx,
6012132743Skan				     hard_frame_pointer_rtx,
6013132743Skan				     GEN_INT (offset), style);
601490284Sobrien	}
601590284Sobrien      else if (frame.to_allocate)
6016132743Skan	pro_epilogue_adjust_stack (stack_pointer_rtx, stack_pointer_rtx,
6017132743Skan				   GEN_INT (frame.to_allocate), style);
601818334Speter
601990284Sobrien      for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
602090284Sobrien	if (ix86_save_reg (regno, false))
602118334Speter	  {
602290284Sobrien	    if (TARGET_64BIT)
602390284Sobrien	      emit_insn (gen_popdi1 (gen_rtx_REG (Pmode, regno)));
602451411Sobrien	    else
602590284Sobrien	      emit_insn (gen_popsi1 (gen_rtx_REG (Pmode, regno)));
602618334Speter	  }
602790284Sobrien      if (frame_pointer_needed)
602890284Sobrien	{
602990284Sobrien	  /* Leave results in shorter dependency chains on CPUs that are
603090284Sobrien	     able to grok it fast.  */
603190284Sobrien	  if (TARGET_USE_LEAVE)
603290284Sobrien	    emit_insn (TARGET_64BIT ? gen_leave_rex64 () : gen_leave ());
603390284Sobrien	  else if (TARGET_64BIT)
603490284Sobrien	    emit_insn (gen_popdi1 (hard_frame_pointer_rtx));
603590284Sobrien	  else
603690284Sobrien	    emit_insn (gen_popsi1 (hard_frame_pointer_rtx));
603790284Sobrien	}
603818334Speter    }
603951411Sobrien
6040169705Skan  if (cfun->machine->force_align_arg_pointer)
6041169705Skan    {
6042169705Skan      emit_insn (gen_addsi3 (stack_pointer_rtx,
6043169705Skan			     cfun->machine->force_align_arg_pointer,
6044169705Skan			     GEN_INT (-4)));
6045169705Skan    }
6046169705Skan
604790284Sobrien  /* Sibcall epilogues don't want a return instruction.  */
604890284Sobrien  if (style == 0)
604990284Sobrien    return;
605090284Sobrien
605190284Sobrien  if (current_function_pops_args && current_function_args_size)
605290284Sobrien    {
605390284Sobrien      rtx popc = GEN_INT (current_function_pops_args);
605490284Sobrien
605590284Sobrien      /* i386 can only pop 64K bytes.  If asked to pop more, pop
605690284Sobrien	 return address, do explicit add, and jump indirectly to the
605790284Sobrien	 caller.  */
605890284Sobrien
605990284Sobrien      if (current_function_pops_args >= 65536)
606018334Speter	{
606190284Sobrien	  rtx ecx = gen_rtx_REG (SImode, 2);
606251411Sobrien
6063132743Skan	  /* There is no "pascal" calling convention in 64bit ABI.  */
6064169705Skan	  gcc_assert (!TARGET_64BIT);
606551411Sobrien
606690284Sobrien	  emit_insn (gen_popsi1 (ecx));
606790284Sobrien	  emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, popc));
606890284Sobrien	  emit_jump_insn (gen_return_indirect_internal (ecx));
606918334Speter	}
607090284Sobrien      else
607190284Sobrien	emit_jump_insn (gen_return_pop_internal (popc));
607290284Sobrien    }
607390284Sobrien  else
607490284Sobrien    emit_jump_insn (gen_return_internal ());
607590284Sobrien}
6076117408Skan
6077117408Skan/* Reset from the function's potential modifications.  */
6078117408Skan
6079117408Skanstatic void
6080132743Skanix86_output_function_epilogue (FILE *file ATTRIBUTE_UNUSED,
6081132743Skan			       HOST_WIDE_INT size ATTRIBUTE_UNUSED)
6082117408Skan{
6083117408Skan  if (pic_offset_table_rtx)
6084117408Skan    REGNO (pic_offset_table_rtx) = REAL_PIC_OFFSET_TABLE_REGNUM;
6085169705Skan#if TARGET_MACHO
6086169705Skan  /* Mach-O doesn't support labels at the end of objects, so if
6087169705Skan     it looks like we might want one, insert a NOP.  */
6088169705Skan  {
6089169705Skan    rtx insn = get_last_insn ();
6090169705Skan    while (insn
6091169705Skan	   && NOTE_P (insn)
6092169705Skan	   && NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED_LABEL)
6093169705Skan      insn = PREV_INSN (insn);
6094169705Skan    if (insn
6095169705Skan	&& (LABEL_P (insn)
6096169705Skan	    || (NOTE_P (insn)
6097169705Skan		&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED_LABEL)))
6098169705Skan      fputs ("\tnop\n", file);
6099169705Skan  }
6100169705Skan#endif
6101169705Skan
6102117408Skan}
610390284Sobrien
610490284Sobrien/* Extract the parts of an RTL expression that is a valid memory address
610590284Sobrien   for an instruction.  Return 0 if the structure of the address is
610690284Sobrien   grossly off.  Return -1 if the address contains ASHIFT, so it is not
6107132743Skan   strictly valid, but still used for computing length of lea instruction.  */
610818334Speter
6109169705Skanint
6110132743Skanix86_decompose_address (rtx addr, struct ix86_address *out)
611190284Sobrien{
6112169705Skan  rtx base = NULL_RTX, index = NULL_RTX, disp = NULL_RTX;
6113169705Skan  rtx base_reg, index_reg;
611490284Sobrien  HOST_WIDE_INT scale = 1;
611590284Sobrien  rtx scale_rtx = NULL_RTX;
611690284Sobrien  int retval = 1;
6117132743Skan  enum ix86_address_seg seg = SEG_DEFAULT;
611890284Sobrien
6119132743Skan  if (GET_CODE (addr) == REG || GET_CODE (addr) == SUBREG)
612090284Sobrien    base = addr;
612190284Sobrien  else if (GET_CODE (addr) == PLUS)
612218334Speter    {
6123132743Skan      rtx addends[4], op;
6124132743Skan      int n = 0, i;
612518334Speter
6126132743Skan      op = addr;
6127132743Skan      do
612818334Speter	{
6129132743Skan	  if (n >= 4)
6130132743Skan	    return 0;
6131132743Skan	  addends[n++] = XEXP (op, 1);
6132132743Skan	  op = XEXP (op, 0);
613351411Sobrien	}
6134132743Skan      while (GET_CODE (op) == PLUS);
6135132743Skan      if (n >= 4)
6136132743Skan	return 0;
6137132743Skan      addends[n] = op;
6138132743Skan
6139132743Skan      for (i = n; i >= 0; --i)
614051411Sobrien	{
6141132743Skan	  op = addends[i];
6142132743Skan	  switch (GET_CODE (op))
6143132743Skan	    {
6144132743Skan	    case MULT:
6145132743Skan	      if (index)
6146132743Skan		return 0;
6147132743Skan	      index = XEXP (op, 0);
6148132743Skan	      scale_rtx = XEXP (op, 1);
6149132743Skan	      break;
6150132743Skan
6151132743Skan	    case UNSPEC:
6152132743Skan	      if (XINT (op, 1) == UNSPEC_TP
6153132743Skan	          && TARGET_TLS_DIRECT_SEG_REFS
6154132743Skan	          && seg == SEG_DEFAULT)
6155132743Skan		seg = TARGET_64BIT ? SEG_FS : SEG_GS;
6156132743Skan	      else
6157132743Skan		return 0;
6158132743Skan	      break;
6159132743Skan
6160132743Skan	    case REG:
6161132743Skan	    case SUBREG:
6162132743Skan	      if (!base)
6163132743Skan		base = op;
6164132743Skan	      else if (!index)
6165132743Skan		index = op;
6166132743Skan	      else
6167132743Skan		return 0;
6168132743Skan	      break;
6169132743Skan
6170132743Skan	    case CONST:
6171132743Skan	    case CONST_INT:
6172132743Skan	    case SYMBOL_REF:
6173132743Skan	    case LABEL_REF:
6174132743Skan	      if (disp)
6175132743Skan		return 0;
6176132743Skan	      disp = op;
6177132743Skan	      break;
6178132743Skan
6179132743Skan	    default:
6180132743Skan	      return 0;
6181132743Skan	    }
618218334Speter	}
618390284Sobrien    }
618490284Sobrien  else if (GET_CODE (addr) == MULT)
618590284Sobrien    {
618690284Sobrien      index = XEXP (addr, 0);		/* index*scale */
618790284Sobrien      scale_rtx = XEXP (addr, 1);
618890284Sobrien    }
618990284Sobrien  else if (GET_CODE (addr) == ASHIFT)
619090284Sobrien    {
619190284Sobrien      rtx tmp;
619251411Sobrien
619390284Sobrien      /* We're called for lea too, which implements ashift on occasion.  */
619490284Sobrien      index = XEXP (addr, 0);
619590284Sobrien      tmp = XEXP (addr, 1);
619690284Sobrien      if (GET_CODE (tmp) != CONST_INT)
619790284Sobrien	return 0;
619890284Sobrien      scale = INTVAL (tmp);
619990284Sobrien      if ((unsigned HOST_WIDE_INT) scale > 3)
620090284Sobrien	return 0;
620190284Sobrien      scale = 1 << scale;
620290284Sobrien      retval = -1;
620318334Speter    }
620490284Sobrien  else
620590284Sobrien    disp = addr;			/* displacement */
620618334Speter
620790284Sobrien  /* Extract the integral value of scale.  */
620890284Sobrien  if (scale_rtx)
620951411Sobrien    {
621090284Sobrien      if (GET_CODE (scale_rtx) != CONST_INT)
621190284Sobrien	return 0;
621290284Sobrien      scale = INTVAL (scale_rtx);
621351411Sobrien    }
621451411Sobrien
6215169705Skan  base_reg = base && GET_CODE (base) == SUBREG ? SUBREG_REG (base) : base;
6216169705Skan  index_reg = index && GET_CODE (index) == SUBREG ? SUBREG_REG (index) : index;
6217169705Skan
6218132743Skan  /* Allow arg pointer and stack pointer as index if there is not scaling.  */
6219169705Skan  if (base_reg && index_reg && scale == 1
6220169705Skan      && (index_reg == arg_pointer_rtx
6221169705Skan	  || index_reg == frame_pointer_rtx
6222169705Skan	  || (REG_P (index_reg) && REGNO (index_reg) == STACK_POINTER_REGNUM)))
622318334Speter    {
6224169705Skan      rtx tmp;
6225169705Skan      tmp = base, base = index, index = tmp;
6226169705Skan      tmp = base_reg, base_reg = index_reg, index_reg = tmp;
622790284Sobrien    }
622818334Speter
622990284Sobrien  /* Special case: %ebp cannot be encoded as a base without a displacement.  */
6230169705Skan  if ((base_reg == hard_frame_pointer_rtx
6231169705Skan       || base_reg == frame_pointer_rtx
6232169705Skan       || base_reg == arg_pointer_rtx) && !disp)
623390284Sobrien    disp = const0_rtx;
623418334Speter
623590284Sobrien  /* Special case: on K6, [%esi] makes the instruction vector decoded.
623690284Sobrien     Avoid this by transforming to [%esi+0].  */
6237132743Skan  if (ix86_tune == PROCESSOR_K6 && !optimize_size
6238169705Skan      && base_reg && !index_reg && !disp
6239169705Skan      && REG_P (base_reg)
6240169705Skan      && REGNO_REG_CLASS (REGNO (base_reg)) == SIREG)
624190284Sobrien    disp = const0_rtx;
624251411Sobrien
624390284Sobrien  /* Special case: encode reg+reg instead of reg*2.  */
624490284Sobrien  if (!base && index && scale && scale == 2)
6245169705Skan    base = index, base_reg = index_reg, scale = 1;
624690284Sobrien
624790284Sobrien  /* Special case: scaling cannot be encoded without base or displacement.  */
624890284Sobrien  if (!base && !disp && index && scale != 1)
624990284Sobrien    disp = const0_rtx;
625090284Sobrien
625190284Sobrien  out->base = base;
625290284Sobrien  out->index = index;
625390284Sobrien  out->disp = disp;
625490284Sobrien  out->scale = scale;
6255132743Skan  out->seg = seg;
625690284Sobrien
625790284Sobrien  return retval;
625818334Speter}
625918334Speter
626090284Sobrien/* Return cost of the memory address x.
626190284Sobrien   For i386, it is better to use a complex address than let gcc copy
626290284Sobrien   the address into a reg and make a new pseudo.  But not if the address
626390284Sobrien   requires to two regs - that would mean more pseudos with longer
626490284Sobrien   lifetimes.  */
6265132743Skanstatic int
6266132743Skanix86_address_cost (rtx x)
626790284Sobrien{
626890284Sobrien  struct ix86_address parts;
626990284Sobrien  int cost = 1;
6270169705Skan  int ok = ix86_decompose_address (x, &parts);
627118334Speter
6272169705Skan  gcc_assert (ok);
627318334Speter
6274169705Skan  if (parts.base && GET_CODE (parts.base) == SUBREG)
6275169705Skan    parts.base = SUBREG_REG (parts.base);
6276169705Skan  if (parts.index && GET_CODE (parts.index) == SUBREG)
6277169705Skan    parts.index = SUBREG_REG (parts.index);
6278169705Skan
627990284Sobrien  /* More complex memory references are better.  */
628090284Sobrien  if (parts.disp && parts.disp != const0_rtx)
628190284Sobrien    cost--;
6282132743Skan  if (parts.seg != SEG_DEFAULT)
6283132743Skan    cost--;
628418334Speter
628590284Sobrien  /* Attempt to minimize number of registers in the address.  */
628690284Sobrien  if ((parts.base
628790284Sobrien       && (!REG_P (parts.base) || REGNO (parts.base) >= FIRST_PSEUDO_REGISTER))
628890284Sobrien      || (parts.index
628990284Sobrien	  && (!REG_P (parts.index)
629090284Sobrien	      || REGNO (parts.index) >= FIRST_PSEUDO_REGISTER)))
629190284Sobrien    cost++;
629218334Speter
629390284Sobrien  if (parts.base
629490284Sobrien      && (!REG_P (parts.base) || REGNO (parts.base) >= FIRST_PSEUDO_REGISTER)
629590284Sobrien      && parts.index
629690284Sobrien      && (!REG_P (parts.index) || REGNO (parts.index) >= FIRST_PSEUDO_REGISTER)
629790284Sobrien      && parts.base != parts.index)
629890284Sobrien    cost++;
629918334Speter
630090284Sobrien  /* AMD-K6 don't like addresses with ModR/M set to 00_xxx_100b,
630190284Sobrien     since it's predecode logic can't detect the length of instructions
630290284Sobrien     and it degenerates to vector decoded.  Increase cost of such
630390284Sobrien     addresses here.  The penalty is minimally 2 cycles.  It may be worthwhile
630490284Sobrien     to split such addresses or even refuse such addresses at all.
630518334Speter
630690284Sobrien     Following addressing modes are affected:
630790284Sobrien      [base+scale*index]
630890284Sobrien      [scale*index+disp]
630990284Sobrien      [base+index]
631090284Sobrien
631190284Sobrien     The first and last case  may be avoidable by explicitly coding the zero in
631290284Sobrien     memory address, but I don't have AMD-K6 machine handy to check this
631390284Sobrien     theory.  */
631490284Sobrien
631590284Sobrien  if (TARGET_K6
631690284Sobrien      && ((!parts.disp && parts.base && parts.index && parts.scale != 1)
631790284Sobrien	  || (parts.disp && !parts.base && parts.index && parts.scale != 1)
631890284Sobrien	  || (!parts.disp && parts.base && parts.index && parts.scale == 1)))
631990284Sobrien    cost += 10;
632090284Sobrien
632190284Sobrien  return cost;
632290284Sobrien}
632390284Sobrien
632490284Sobrien/* If X is a machine specific address (i.e. a symbol or label being
632590284Sobrien   referenced as a displacement from the GOT implemented using an
632690284Sobrien   UNSPEC), then return the base term.  Otherwise return X.  */
632790284Sobrien
632890284Sobrienrtx
6329132743Skanix86_find_base_term (rtx x)
633090284Sobrien{
633190284Sobrien  rtx term;
633290284Sobrien
633390284Sobrien  if (TARGET_64BIT)
633490284Sobrien    {
633590284Sobrien      if (GET_CODE (x) != CONST)
633690284Sobrien	return x;
633790284Sobrien      term = XEXP (x, 0);
633890284Sobrien      if (GET_CODE (term) == PLUS
633990284Sobrien	  && (GET_CODE (XEXP (term, 1)) == CONST_INT
634090284Sobrien	      || GET_CODE (XEXP (term, 1)) == CONST_DOUBLE))
634190284Sobrien	term = XEXP (term, 0);
634290284Sobrien      if (GET_CODE (term) != UNSPEC
6343117408Skan	  || XINT (term, 1) != UNSPEC_GOTPCREL)
634490284Sobrien	return x;
634590284Sobrien
634690284Sobrien      term = XVECEXP (term, 0, 0);
634790284Sobrien
634890284Sobrien      if (GET_CODE (term) != SYMBOL_REF
634990284Sobrien	  && GET_CODE (term) != LABEL_REF)
635090284Sobrien	return x;
635190284Sobrien
635290284Sobrien      return term;
635390284Sobrien    }
635490284Sobrien
6355132743Skan  term = ix86_delegitimize_address (x);
635690284Sobrien
635790284Sobrien  if (GET_CODE (term) != SYMBOL_REF
635890284Sobrien      && GET_CODE (term) != LABEL_REF)
635990284Sobrien    return x;
636090284Sobrien
636190284Sobrien  return term;
636290284Sobrien}
6363169705Skan
6364169705Skan/* Allow {LABEL | SYMBOL}_REF - SYMBOL_REF-FOR-PICBASE for Mach-O as
6365169705Skan   this is used for to form addresses to local data when -fPIC is in
6366169705Skan   use.  */
6367169705Skan
6368169705Skanstatic bool
6369169705Skandarwin_local_data_pic (rtx disp)
6370169705Skan{
6371169705Skan  if (GET_CODE (disp) == MINUS)
6372169705Skan    {
6373169705Skan      if (GET_CODE (XEXP (disp, 0)) == LABEL_REF
6374169705Skan          || GET_CODE (XEXP (disp, 0)) == SYMBOL_REF)
6375169705Skan        if (GET_CODE (XEXP (disp, 1)) == SYMBOL_REF)
6376169705Skan          {
6377169705Skan            const char *sym_name = XSTR (XEXP (disp, 1), 0);
6378169705Skan            if (! strcmp (sym_name, "<pic base>"))
6379169705Skan              return true;
6380169705Skan          }
6381169705Skan    }
6382169705Skan
6383169705Skan  return false;
6384169705Skan}
638590284Sobrien
6386117408Skan/* Determine if a given RTX is a valid constant.  We already know this
6387117408Skan   satisfies CONSTANT_P.  */
6388117408Skan
6389117408Skanbool
6390132743Skanlegitimate_constant_p (rtx x)
6391117408Skan{
6392117408Skan  switch (GET_CODE (x))
6393117408Skan    {
6394117408Skan    case CONST:
6395146908Skan      x = XEXP (x, 0);
6396117408Skan
6397146908Skan      if (GET_CODE (x) == PLUS)
6398132743Skan	{
6399146908Skan	  if (GET_CODE (XEXP (x, 1)) != CONST_INT)
6400132743Skan	    return false;
6401146908Skan	  x = XEXP (x, 0);
6402132743Skan	}
6403132743Skan
6404169705Skan      if (TARGET_MACHO && darwin_local_data_pic (x))
6405169705Skan	return true;
6406169705Skan
6407117408Skan      /* Only some unspecs are valid as "constants".  */
6408146908Skan      if (GET_CODE (x) == UNSPEC)
6409146908Skan	switch (XINT (x, 1))
6410117408Skan	  {
6411169705Skan	  case UNSPEC_GOTOFF:
6412169705Skan	    return TARGET_64BIT;
6413117408Skan	  case UNSPEC_TPOFF:
6414132743Skan	  case UNSPEC_NTPOFF:
6415169705Skan	    x = XVECEXP (x, 0, 0);
6416169705Skan	    return (GET_CODE (x) == SYMBOL_REF
6417169705Skan		    && SYMBOL_REF_TLS_MODEL (x) == TLS_MODEL_LOCAL_EXEC);
6418132743Skan	  case UNSPEC_DTPOFF:
6419169705Skan	    x = XVECEXP (x, 0, 0);
6420169705Skan	    return (GET_CODE (x) == SYMBOL_REF
6421169705Skan		    && SYMBOL_REF_TLS_MODEL (x) == TLS_MODEL_LOCAL_DYNAMIC);
6422117408Skan	  default:
6423117408Skan	    return false;
6424117408Skan	  }
6425146908Skan
6426146908Skan      /* We must have drilled down to a symbol.  */
6427169705Skan      if (GET_CODE (x) == LABEL_REF)
6428169705Skan	return true;
6429169705Skan      if (GET_CODE (x) != SYMBOL_REF)
6430146908Skan	return false;
6431146908Skan      /* FALLTHRU */
6432146908Skan
6433146908Skan    case SYMBOL_REF:
6434146908Skan      /* TLS symbols are never valid.  */
6435169705Skan      if (SYMBOL_REF_TLS_MODEL (x))
6436146908Skan	return false;
6437117408Skan      break;
6438117408Skan
6439169705Skan    case CONST_DOUBLE:
6440169705Skan      if (GET_MODE (x) == TImode
6441169705Skan	  && x != CONST0_RTX (TImode)
6442169705Skan          && !TARGET_64BIT)
6443169705Skan	return false;
6444169705Skan      break;
6445169705Skan
6446169705Skan    case CONST_VECTOR:
6447169705Skan      if (x == CONST0_RTX (GET_MODE (x)))
6448169705Skan	return true;
6449169705Skan      return false;
6450169705Skan
6451117408Skan    default:
6452117408Skan      break;
6453117408Skan    }
6454117408Skan
6455117408Skan  /* Otherwise we handle everything else in the move patterns.  */
6456117408Skan  return true;
6457117408Skan}
6458117408Skan
6459117408Skan/* Determine if it's legal to put X into the constant pool.  This
6460117408Skan   is not possible for the address of thread-local symbols, which
6461117408Skan   is checked above.  */
6462117408Skan
6463117408Skanstatic bool
6464132743Skanix86_cannot_force_const_mem (rtx x)
6465117408Skan{
6466169705Skan  /* We can always put integral constants and vectors in memory.  */
6467169705Skan  switch (GET_CODE (x))
6468169705Skan    {
6469169705Skan    case CONST_INT:
6470169705Skan    case CONST_DOUBLE:
6471169705Skan    case CONST_VECTOR:
6472169705Skan      return false;
6473169705Skan
6474169705Skan    default:
6475169705Skan      break;
6476169705Skan    }
6477117408Skan  return !legitimate_constant_p (x);
6478117408Skan}
6479117408Skan
6480117408Skan/* Determine if a given RTX is a valid constant address.  */
6481117408Skan
6482117408Skanbool
6483132743Skanconstant_address_p (rtx x)
6484117408Skan{
6485132743Skan  return CONSTANT_P (x) && legitimate_address_p (Pmode, x, 1);
6486117408Skan}
6487117408Skan
6488117408Skan/* Nonzero if the constant value X is a legitimate general operand
6489117408Skan   when generating PIC code.  It is given that flag_pic is on and
6490117408Skan   that X satisfies CONSTANT_P or is a CONST_DOUBLE.  */
6491117408Skan
6492117408Skanbool
6493132743Skanlegitimate_pic_operand_p (rtx x)
6494117408Skan{
6495117408Skan  rtx inner;
6496117408Skan
6497117408Skan  switch (GET_CODE (x))
6498117408Skan    {
6499117408Skan    case CONST:
6500117408Skan      inner = XEXP (x, 0);
6501169705Skan      if (GET_CODE (inner) == PLUS
6502169705Skan	  && GET_CODE (XEXP (inner, 1)) == CONST_INT)
6503169705Skan	inner = XEXP (inner, 0);
6504117408Skan
6505117408Skan      /* Only some unspecs are valid as "constants".  */
6506117408Skan      if (GET_CODE (inner) == UNSPEC)
6507117408Skan	switch (XINT (inner, 1))
6508117408Skan	  {
6509169705Skan	  case UNSPEC_GOTOFF:
6510169705Skan	    return TARGET_64BIT;
6511117408Skan	  case UNSPEC_TPOFF:
6512169705Skan	    x = XVECEXP (inner, 0, 0);
6513169705Skan	    return (GET_CODE (x) == SYMBOL_REF
6514169705Skan		    && SYMBOL_REF_TLS_MODEL (x) == TLS_MODEL_LOCAL_EXEC);
6515117408Skan	  default:
6516117408Skan	    return false;
6517117408Skan	  }
6518117408Skan      /* FALLTHRU */
6519117408Skan
6520117408Skan    case SYMBOL_REF:
6521117408Skan    case LABEL_REF:
6522117408Skan      return legitimate_pic_address_disp_p (x);
6523117408Skan
6524117408Skan    default:
6525117408Skan      return true;
6526117408Skan    }
6527117408Skan}
6528117408Skan
652990284Sobrien/* Determine if a given CONST RTX is a valid memory displacement
653090284Sobrien   in PIC mode.  */
653190284Sobrien
653218334Speterint
6533132743Skanlegitimate_pic_address_disp_p (rtx disp)
653452294Sobrien{
6535117408Skan  bool saw_plus;
6536117408Skan
653790284Sobrien  /* In 64bit mode we can allow direct addresses of symbols and labels
653890284Sobrien     when they are not dynamic symbols.  */
653990284Sobrien  if (TARGET_64BIT)
654090284Sobrien    {
6541169705Skan      rtx op0 = disp, op1;
6542169705Skan
6543169705Skan      switch (GET_CODE (disp))
6544132743Skan	{
6545169705Skan	case LABEL_REF:
6546169705Skan	  return true;
6547132743Skan
6548169705Skan	case CONST:
6549169705Skan	  if (GET_CODE (XEXP (disp, 0)) != PLUS)
6550169705Skan	    break;
6551169705Skan	  op0 = XEXP (XEXP (disp, 0), 0);
6552169705Skan	  op1 = XEXP (XEXP (disp, 0), 1);
6553169705Skan	  if (GET_CODE (op1) != CONST_INT
6554169705Skan	      || INTVAL (op1) >= 16*1024*1024
6555169705Skan	      || INTVAL (op1) < -16*1024*1024)
6556169705Skan            break;
6557169705Skan	  if (GET_CODE (op0) == LABEL_REF)
6558169705Skan	    return true;
6559169705Skan	  if (GET_CODE (op0) != SYMBOL_REF)
6560169705Skan	    break;
6561169705Skan	  /* FALLTHRU */
6562169705Skan
6563169705Skan	case SYMBOL_REF:
6564132743Skan	  /* TLS references should always be enclosed in UNSPEC.  */
6565169705Skan	  if (SYMBOL_REF_TLS_MODEL (op0))
6566169705Skan	    return false;
6567169705Skan	  if (!SYMBOL_REF_FAR_ADDR_P (op0) && SYMBOL_REF_LOCAL_P (op0))
6568169705Skan	    return true;
6569169705Skan	  break;
6570169705Skan
6571169705Skan	default:
6572169705Skan	  break;
6573132743Skan	}
657490284Sobrien    }
657552294Sobrien  if (GET_CODE (disp) != CONST)
657652294Sobrien    return 0;
657752294Sobrien  disp = XEXP (disp, 0);
657852294Sobrien
657990284Sobrien  if (TARGET_64BIT)
658090284Sobrien    {
658190284Sobrien      /* We are unsafe to allow PLUS expressions.  This limit allowed distance
658290284Sobrien         of GOT tables.  We should not need these anyway.  */
658390284Sobrien      if (GET_CODE (disp) != UNSPEC
6584169705Skan	  || (XINT (disp, 1) != UNSPEC_GOTPCREL
6585169705Skan	      && XINT (disp, 1) != UNSPEC_GOTOFF))
658690284Sobrien	return 0;
658790284Sobrien
658890284Sobrien      if (GET_CODE (XVECEXP (disp, 0, 0)) != SYMBOL_REF
658990284Sobrien	  && GET_CODE (XVECEXP (disp, 0, 0)) != LABEL_REF)
659090284Sobrien	return 0;
659190284Sobrien      return 1;
659290284Sobrien    }
659390284Sobrien
6594117408Skan  saw_plus = false;
659552294Sobrien  if (GET_CODE (disp) == PLUS)
659652294Sobrien    {
659752294Sobrien      if (GET_CODE (XEXP (disp, 1)) != CONST_INT)
659852294Sobrien	return 0;
659952294Sobrien      disp = XEXP (disp, 0);
6600117408Skan      saw_plus = true;
660152294Sobrien    }
660252294Sobrien
6603169705Skan  if (TARGET_MACHO && darwin_local_data_pic (disp))
6604169705Skan    return 1;
6605117408Skan
6606117408Skan  if (GET_CODE (disp) != UNSPEC)
660752294Sobrien    return 0;
660852294Sobrien
660990284Sobrien  switch (XINT (disp, 1))
661090284Sobrien    {
6611117408Skan    case UNSPEC_GOT:
6612117408Skan      if (saw_plus)
6613117408Skan	return false;
661490284Sobrien      return GET_CODE (XVECEXP (disp, 0, 0)) == SYMBOL_REF;
6615117408Skan    case UNSPEC_GOTOFF:
6616169705Skan      /* Refuse GOTOFF in 64bit mode since it is always 64bit when used.
6617169705Skan	 While ABI specify also 32bit relocation but we don't produce it in
6618169705Skan	 small PIC model at all.  */
6619169705Skan      if ((GET_CODE (XVECEXP (disp, 0, 0)) == SYMBOL_REF
6620169705Skan	   || GET_CODE (XVECEXP (disp, 0, 0)) == LABEL_REF)
6621169705Skan	  && !TARGET_64BIT)
6622132743Skan        return local_symbolic_operand (XVECEXP (disp, 0, 0), Pmode);
6623132743Skan      return false;
6624117408Skan    case UNSPEC_GOTTPOFF:
6625117408Skan    case UNSPEC_GOTNTPOFF:
6626117408Skan    case UNSPEC_INDNTPOFF:
6627117408Skan      if (saw_plus)
6628117408Skan	return false;
6629169705Skan      disp = XVECEXP (disp, 0, 0);
6630169705Skan      return (GET_CODE (disp) == SYMBOL_REF
6631169705Skan	      && SYMBOL_REF_TLS_MODEL (disp) == TLS_MODEL_INITIAL_EXEC);
6632117408Skan    case UNSPEC_NTPOFF:
6633169705Skan      disp = XVECEXP (disp, 0, 0);
6634169705Skan      return (GET_CODE (disp) == SYMBOL_REF
6635169705Skan	      && SYMBOL_REF_TLS_MODEL (disp) == TLS_MODEL_LOCAL_EXEC);
6636117408Skan    case UNSPEC_DTPOFF:
6637169705Skan      disp = XVECEXP (disp, 0, 0);
6638169705Skan      return (GET_CODE (disp) == SYMBOL_REF
6639169705Skan	      && SYMBOL_REF_TLS_MODEL (disp) == TLS_MODEL_LOCAL_DYNAMIC);
664090284Sobrien    }
6641117408Skan
664290284Sobrien  return 0;
664352294Sobrien}
664452294Sobrien
664590284Sobrien/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression that is a valid
664690284Sobrien   memory address for an instruction.  The MODE argument is the machine mode
664790284Sobrien   for the MEM expression that wants to use this address.
664890284Sobrien
664990284Sobrien   It only recognizes address in canonical form.  LEGITIMIZE_ADDRESS should
665090284Sobrien   convert common non-canonical forms to canonical form so that they will
665190284Sobrien   be recognized.  */
665290284Sobrien
665352294Sobrienint
6654132743Skanlegitimate_address_p (enum machine_mode mode, rtx addr, int strict)
665518334Speter{
665690284Sobrien  struct ix86_address parts;
665790284Sobrien  rtx base, index, disp;
665890284Sobrien  HOST_WIDE_INT scale;
665990284Sobrien  const char *reason = NULL;
666090284Sobrien  rtx reason_rtx = NULL_RTX;
666118334Speter
666218334Speter  if (TARGET_DEBUG_ADDR)
666318334Speter    {
666418334Speter      fprintf (stderr,
666551411Sobrien	       "\n======\nGO_IF_LEGITIMATE_ADDRESS, mode = %s, strict = %d\n",
666618334Speter	       GET_MODE_NAME (mode), strict);
666718334Speter      debug_rtx (addr);
666818334Speter    }
666918334Speter
667090284Sobrien  if (ix86_decompose_address (addr, &parts) <= 0)
667118334Speter    {
667290284Sobrien      reason = "decomposition failed";
667390284Sobrien      goto report_error;
667418334Speter    }
667518334Speter
667690284Sobrien  base = parts.base;
667790284Sobrien  index = parts.index;
667890284Sobrien  disp = parts.disp;
667990284Sobrien  scale = parts.scale;
668018334Speter
668190284Sobrien  /* Validate base register.
668218334Speter
6683169705Skan     Don't allow SUBREG's that span more than a word here.  It can lead to spill
6684169705Skan     failures when the base is one word out of a two word structure, which is
6685169705Skan     represented internally as a DImode int.  */
668651411Sobrien
668718334Speter  if (base)
668818334Speter    {
6689169705Skan      rtx reg;
669090284Sobrien      reason_rtx = base;
669190284Sobrien
6692169705Skan      if (REG_P (base))
6693169705Skan  	reg = base;
6694169705Skan      else if (GET_CODE (base) == SUBREG
6695169705Skan	       && REG_P (SUBREG_REG (base))
6696169705Skan	       && GET_MODE_SIZE (GET_MODE (SUBREG_REG (base)))
6697169705Skan		  <= UNITS_PER_WORD)
6698169705Skan  	reg = SUBREG_REG (base);
6699169705Skan      else
670018334Speter	{
670190284Sobrien	  reason = "base is not a register";
670290284Sobrien	  goto report_error;
670318334Speter	}
670418334Speter
670552294Sobrien      if (GET_MODE (base) != Pmode)
670652294Sobrien	{
670790284Sobrien	  reason = "base is not in Pmode";
670890284Sobrien	  goto report_error;
670952294Sobrien	}
671052294Sobrien
6711169705Skan      if ((strict && ! REG_OK_FOR_BASE_STRICT_P (reg))
6712169705Skan	  || (! strict && ! REG_OK_FOR_BASE_NONSTRICT_P (reg)))
671318334Speter	{
671490284Sobrien	  reason = "base is not valid";
671590284Sobrien	  goto report_error;
671618334Speter	}
671718334Speter    }
671818334Speter
671990284Sobrien  /* Validate index register.
672051411Sobrien
6721169705Skan     Don't allow SUBREG's that span more than a word here -- same as above.  */
672290284Sobrien
672390284Sobrien  if (index)
672418334Speter    {
6725169705Skan      rtx reg;
672690284Sobrien      reason_rtx = index;
672790284Sobrien
6728169705Skan      if (REG_P (index))
6729169705Skan  	reg = index;
6730169705Skan      else if (GET_CODE (index) == SUBREG
6731169705Skan	       && REG_P (SUBREG_REG (index))
6732169705Skan	       && GET_MODE_SIZE (GET_MODE (SUBREG_REG (index)))
6733169705Skan		  <= UNITS_PER_WORD)
6734169705Skan  	reg = SUBREG_REG (index);
6735169705Skan      else
673618334Speter	{
673790284Sobrien	  reason = "index is not a register";
673890284Sobrien	  goto report_error;
673918334Speter	}
674018334Speter
674190284Sobrien      if (GET_MODE (index) != Pmode)
674252294Sobrien	{
674390284Sobrien	  reason = "index is not in Pmode";
674490284Sobrien	  goto report_error;
674552294Sobrien	}
674652294Sobrien
6747169705Skan      if ((strict && ! REG_OK_FOR_INDEX_STRICT_P (reg))
6748169705Skan	  || (! strict && ! REG_OK_FOR_INDEX_NONSTRICT_P (reg)))
674918334Speter	{
675090284Sobrien	  reason = "index is not valid";
675190284Sobrien	  goto report_error;
675218334Speter	}
675318334Speter    }
675418334Speter
675590284Sobrien  /* Validate scale factor.  */
675690284Sobrien  if (scale != 1)
675718334Speter    {
675890284Sobrien      reason_rtx = GEN_INT (scale);
675990284Sobrien      if (!index)
676018334Speter	{
676190284Sobrien	  reason = "scale without index";
676290284Sobrien	  goto report_error;
676318334Speter	}
676418334Speter
676590284Sobrien      if (scale != 2 && scale != 4 && scale != 8)
676618334Speter	{
676790284Sobrien	  reason = "scale is not a valid multiplier";
676890284Sobrien	  goto report_error;
676918334Speter	}
677018334Speter    }
677118334Speter
677252294Sobrien  /* Validate displacement.  */
677318334Speter  if (disp)
677418334Speter    {
677590284Sobrien      reason_rtx = disp;
677690284Sobrien
6777117408Skan      if (GET_CODE (disp) == CONST
6778117408Skan	  && GET_CODE (XEXP (disp, 0)) == UNSPEC)
6779117408Skan	switch (XINT (XEXP (disp, 0), 1))
6780117408Skan	  {
6781169705Skan	  /* Refuse GOTOFF and GOT in 64bit mode since it is always 64bit when
6782169705Skan	     used.  While ABI specify also 32bit relocations, we don't produce
6783169705Skan	     them at all and use IP relative instead.  */
6784117408Skan	  case UNSPEC_GOT:
6785117408Skan	  case UNSPEC_GOTOFF:
6786169705Skan	    gcc_assert (flag_pic);
6787169705Skan	    if (!TARGET_64BIT)
6788169705Skan	      goto is_legitimate_pic;
6789169705Skan	    reason = "64bit address unspec";
6790169705Skan	    goto report_error;
6791169705Skan
6792117408Skan	  case UNSPEC_GOTPCREL:
6793169705Skan	    gcc_assert (flag_pic);
6794117408Skan	    goto is_legitimate_pic;
679518334Speter
6796117408Skan	  case UNSPEC_GOTTPOFF:
6797117408Skan	  case UNSPEC_GOTNTPOFF:
6798117408Skan	  case UNSPEC_INDNTPOFF:
6799117408Skan	  case UNSPEC_NTPOFF:
6800117408Skan	  case UNSPEC_DTPOFF:
6801117408Skan	    break;
680218334Speter
6803117408Skan	  default:
6804117408Skan	    reason = "invalid address unspec";
6805117408Skan	    goto report_error;
6806117408Skan	  }
6807117408Skan
6808169705Skan      else if (SYMBOLIC_CONST (disp)
6809169705Skan	       && (flag_pic
6810169705Skan		   || (TARGET_MACHO
6811117408Skan#if TARGET_MACHO
6812169705Skan		       && MACHOPIC_INDIRECT
6813169705Skan		       && !machopic_operand_p (disp)
6814117408Skan#endif
6815169705Skan	       )))
681618334Speter	{
6817169705Skan
6818117408Skan	is_legitimate_pic:
681990284Sobrien	  if (TARGET_64BIT && (index || base))
682090284Sobrien	    {
6821117408Skan	      /* foo@dtpoff(%rX) is ok.  */
6822117408Skan	      if (GET_CODE (disp) != CONST
6823117408Skan		  || GET_CODE (XEXP (disp, 0)) != PLUS
6824117408Skan		  || GET_CODE (XEXP (XEXP (disp, 0), 0)) != UNSPEC
6825117408Skan		  || GET_CODE (XEXP (XEXP (disp, 0), 1)) != CONST_INT
6826117408Skan		  || (XINT (XEXP (XEXP (disp, 0), 0), 1) != UNSPEC_DTPOFF
6827117408Skan		      && XINT (XEXP (XEXP (disp, 0), 0), 1) != UNSPEC_NTPOFF))
6828117408Skan		{
6829117408Skan		  reason = "non-constant pic memory reference";
6830117408Skan		  goto report_error;
6831117408Skan		}
683290284Sobrien	    }
6833117408Skan	  else if (! legitimate_pic_address_disp_p (disp))
683452294Sobrien	    {
683590284Sobrien	      reason = "displacement is an invalid pic construct";
683690284Sobrien	      goto report_error;
683752294Sobrien	    }
683852294Sobrien
683990284Sobrien          /* This code used to verify that a symbolic pic displacement
684090284Sobrien	     includes the pic_offset_table_rtx register.
684190284Sobrien
684290284Sobrien	     While this is good idea, unfortunately these constructs may
684390284Sobrien	     be created by "adds using lea" optimization for incorrect
684490284Sobrien	     code like:
684590284Sobrien
684690284Sobrien	     int a;
684790284Sobrien	     int foo(int i)
684890284Sobrien	       {
684990284Sobrien	         return *(&a+i);
685090284Sobrien	       }
685190284Sobrien
685290284Sobrien	     This code is nonsensical, but results in addressing
685390284Sobrien	     GOT table with pic_offset_table_rtx base.  We can't
685490284Sobrien	     just refuse it easily, since it gets matched by
685590284Sobrien	     "addsi3" pattern, that later gets split to lea in the
685690284Sobrien	     case output register differs from input.  While this
685790284Sobrien	     can be handled by separate addsi pattern for this case
685890284Sobrien	     that never results in lea, this seems to be easier and
685990284Sobrien	     correct fix for crash to disable this test.  */
686018334Speter	}
6861132743Skan      else if (GET_CODE (disp) != LABEL_REF
6862132743Skan	       && GET_CODE (disp) != CONST_INT
6863132743Skan	       && (GET_CODE (disp) != CONST
6864132743Skan		   || !legitimate_constant_p (disp))
6865132743Skan	       && (GET_CODE (disp) != SYMBOL_REF
6866132743Skan		   || !legitimate_constant_p (disp)))
686718334Speter	{
6868117408Skan	  reason = "displacement is not constant";
6869117408Skan	  goto report_error;
687018334Speter	}
6871169705Skan      else if (TARGET_64BIT
6872169705Skan	       && !x86_64_immediate_operand (disp, VOIDmode))
6873117408Skan	{
6874117408Skan	  reason = "displacement is out of range";
6875117408Skan	  goto report_error;
6876117408Skan	}
687718334Speter    }
687818334Speter
687990284Sobrien  /* Everything looks valid.  */
688018334Speter  if (TARGET_DEBUG_ADDR)
688190284Sobrien    fprintf (stderr, "Success.\n");
688290284Sobrien  return TRUE;
688318334Speter
6884117408Skan report_error:
688590284Sobrien  if (TARGET_DEBUG_ADDR)
688690284Sobrien    {
688790284Sobrien      fprintf (stderr, "Error: %s\n", reason);
688890284Sobrien      debug_rtx (reason_rtx);
688990284Sobrien    }
689090284Sobrien  return FALSE;
689118334Speter}
689218334Speter
6893169705Skan/* Return a unique alias set for the GOT.  */
689490284Sobrien
689590284Sobrienstatic HOST_WIDE_INT
6896132743Skanix86_GOT_alias_set (void)
689790284Sobrien{
6898117408Skan  static HOST_WIDE_INT set = -1;
6899117408Skan  if (set == -1)
6900117408Skan    set = new_alias_set ();
6901117408Skan  return set;
690290284Sobrien}
690390284Sobrien
690418334Speter/* Return a legitimate reference for ORIG (an address) using the
690518334Speter   register REG.  If REG is 0, a new pseudo is generated.
690618334Speter
690752294Sobrien   There are two types of references that must be handled:
690818334Speter
690918334Speter   1. Global data references must load the address from the GOT, via
691018334Speter      the PIC reg.  An insn is emitted to do this load, and the reg is
691118334Speter      returned.
691218334Speter
691352294Sobrien   2. Static data references, constant pool addresses, and code labels
691452294Sobrien      compute the address as an offset from the GOT, whose base is in
6915132743Skan      the PIC reg.  Static data objects have SYMBOL_FLAG_LOCAL set to
691652294Sobrien      differentiate them from global data objects.  The returned
691752294Sobrien      address is the PIC reg + an unspec constant.
691818334Speter
691918334Speter   GO_IF_LEGITIMATE_ADDRESS rejects symbolic references unless the PIC
692052294Sobrien   reg also appears in the address.  */
692118334Speter
6922169705Skanstatic rtx
6923132743Skanlegitimize_pic_address (rtx orig, rtx reg)
692418334Speter{
692518334Speter  rtx addr = orig;
692618334Speter  rtx new = orig;
692752294Sobrien  rtx base;
692818334Speter
6929117408Skan#if TARGET_MACHO
6930169705Skan  if (TARGET_MACHO && !TARGET_64BIT)
6931169705Skan    {
6932169705Skan      if (reg == 0)
6933169705Skan	reg = gen_reg_rtx (Pmode);
6934169705Skan      /* Use the generic Mach-O PIC machinery.  */
6935169705Skan      return machopic_legitimize_pic_address (orig, GET_MODE (orig), reg);
6936169705Skan    }
6937117408Skan#endif
6938117408Skan
6939117408Skan  if (TARGET_64BIT && legitimate_pic_address_disp_p (addr))
6940117408Skan    new = addr;
6941169705Skan  else if (TARGET_64BIT
6942169705Skan	   && ix86_cmodel != CM_SMALL_PIC
6943169705Skan	   && local_symbolic_operand (addr, Pmode))
6944169705Skan    {
6945169705Skan      rtx tmpreg;
6946169705Skan      /* This symbol may be referenced via a displacement from the PIC
6947169705Skan	 base address (@GOTOFF).  */
6948169705Skan
6949169705Skan      if (reload_in_progress)
6950169705Skan	regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1;
6951169705Skan      if (GET_CODE (addr) == CONST)
6952169705Skan	addr = XEXP (addr, 0);
6953169705Skan      if (GET_CODE (addr) == PLUS)
6954169705Skan	  {
6955169705Skan            new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, XEXP (addr, 0)), UNSPEC_GOTOFF);
6956169705Skan	    new = gen_rtx_PLUS (Pmode, new, XEXP (addr, 1));
6957169705Skan	  }
6958169705Skan	else
6959169705Skan          new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOTOFF);
6960169705Skan      new = gen_rtx_CONST (Pmode, new);
6961169705Skan      if (!reg)
6962169705Skan        tmpreg = gen_reg_rtx (Pmode);
6963169705Skan      else
6964169705Skan	tmpreg = reg;
6965169705Skan      emit_move_insn (tmpreg, new);
6966169705Skan
6967169705Skan      if (reg != 0)
6968169705Skan	{
6969169705Skan	  new = expand_simple_binop (Pmode, PLUS, reg, pic_offset_table_rtx,
6970169705Skan				     tmpreg, 1, OPTAB_DIRECT);
6971169705Skan	  new = reg;
6972169705Skan	}
6973169705Skan      else new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, tmpreg);
6974169705Skan    }
6975117408Skan  else if (!TARGET_64BIT && local_symbolic_operand (addr, Pmode))
697618334Speter    {
6977117408Skan      /* This symbol may be referenced via a displacement from the PIC
6978117408Skan	 base address (@GOTOFF).  */
697918334Speter
6980117408Skan      if (reload_in_progress)
6981117408Skan	regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1;
6982132743Skan      if (GET_CODE (addr) == CONST)
6983132743Skan	addr = XEXP (addr, 0);
6984132743Skan      if (GET_CODE (addr) == PLUS)
6985132743Skan	  {
6986132743Skan            new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, XEXP (addr, 0)), UNSPEC_GOTOFF);
6987132743Skan	    new = gen_rtx_PLUS (Pmode, new, XEXP (addr, 1));
6988132743Skan	  }
6989132743Skan	else
6990132743Skan          new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOTOFF);
6991117408Skan      new = gen_rtx_CONST (Pmode, new);
6992117408Skan      new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new);
699318334Speter
6994117408Skan      if (reg != 0)
6995117408Skan	{
6996117408Skan	  emit_move_insn (reg, new);
6997117408Skan	  new = reg;
6998117408Skan	}
699990284Sobrien    }
7000169705Skan  else if (GET_CODE (addr) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (addr) == 0)
700190284Sobrien    {
700290284Sobrien      if (TARGET_64BIT)
700352294Sobrien	{
7004117408Skan	  new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOTPCREL);
700590284Sobrien	  new = gen_rtx_CONST (Pmode, new);
7006169705Skan	  new = gen_const_mem (Pmode, new);
700790284Sobrien	  set_mem_alias_set (new, ix86_GOT_alias_set ());
700890284Sobrien
700990284Sobrien	  if (reg == 0)
701090284Sobrien	    reg = gen_reg_rtx (Pmode);
701190284Sobrien	  /* Use directly gen_movsi, otherwise the address is loaded
701290284Sobrien	     into register for CSE.  We don't want to CSE this addresses,
701390284Sobrien	     instead we CSE addresses from the GOT table, so skip this.  */
701490284Sobrien	  emit_insn (gen_movsi (reg, new));
701590284Sobrien	  new = reg;
701690284Sobrien	}
701790284Sobrien      else
701890284Sobrien	{
701990284Sobrien	  /* This symbol must be referenced via a load from the
702090284Sobrien	     Global Offset Table (@GOT).  */
702190284Sobrien
7022117408Skan	  if (reload_in_progress)
7023117408Skan	    regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1;
7024117408Skan	  new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOT);
702590284Sobrien	  new = gen_rtx_CONST (Pmode, new);
702690284Sobrien	  new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new);
7027169705Skan	  new = gen_const_mem (Pmode, new);
702890284Sobrien	  set_mem_alias_set (new, ix86_GOT_alias_set ());
702990284Sobrien
703090284Sobrien	  if (reg == 0)
703190284Sobrien	    reg = gen_reg_rtx (Pmode);
703218334Speter	  emit_move_insn (reg, new);
703352294Sobrien	  new = reg;
703418334Speter	}
703518334Speter    }
703652294Sobrien  else
703718334Speter    {
7038169705Skan      if (GET_CODE (addr) == CONST_INT
7039169705Skan	  && !x86_64_immediate_operand (addr, VOIDmode))
704018334Speter	{
7041169705Skan	  if (reg)
7042169705Skan	    {
7043169705Skan	      emit_move_insn (reg, addr);
7044169705Skan	      new = reg;
7045169705Skan	    }
7046169705Skan	  else
7047169705Skan	    new = force_reg (Pmode, addr);
7048169705Skan	}
7049169705Skan      else if (GET_CODE (addr) == CONST)
7050169705Skan	{
705118334Speter	  addr = XEXP (addr, 0);
705296293Sobrien
705396293Sobrien	  /* We must match stuff we generate before.  Assume the only
705496293Sobrien	     unspecs that can get here are ours.  Not that we could do
7055132743Skan	     anything with them anyway....  */
705696293Sobrien	  if (GET_CODE (addr) == UNSPEC
705796293Sobrien	      || (GET_CODE (addr) == PLUS
705896293Sobrien		  && GET_CODE (XEXP (addr, 0)) == UNSPEC))
705996293Sobrien	    return orig;
7060169705Skan	  gcc_assert (GET_CODE (addr) == PLUS);
706118334Speter	}
706252294Sobrien      if (GET_CODE (addr) == PLUS)
706352294Sobrien	{
706452294Sobrien	  rtx op0 = XEXP (addr, 0), op1 = XEXP (addr, 1);
706518334Speter
706652294Sobrien	  /* Check first to see if this is a constant offset from a @GOTOFF
706752294Sobrien	     symbol reference.  */
706890284Sobrien	  if (local_symbolic_operand (op0, Pmode)
706952294Sobrien	      && GET_CODE (op1) == CONST_INT)
707052294Sobrien	    {
707190284Sobrien	      if (!TARGET_64BIT)
707290284Sobrien		{
7073117408Skan		  if (reload_in_progress)
7074117408Skan		    regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1;
7075117408Skan		  new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op0),
7076117408Skan					UNSPEC_GOTOFF);
707790284Sobrien		  new = gen_rtx_PLUS (Pmode, new, op1);
707890284Sobrien		  new = gen_rtx_CONST (Pmode, new);
707990284Sobrien		  new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new);
708018334Speter
708190284Sobrien		  if (reg != 0)
708290284Sobrien		    {
708390284Sobrien		      emit_move_insn (reg, new);
708490284Sobrien		      new = reg;
708590284Sobrien		    }
708690284Sobrien		}
708790284Sobrien	      else
708852294Sobrien		{
7089117408Skan		  if (INTVAL (op1) < -16*1024*1024
7090117408Skan		      || INTVAL (op1) >= 16*1024*1024)
7091169705Skan		    {
7092169705Skan		      if (!x86_64_immediate_operand (op1, Pmode))
7093169705Skan			op1 = force_reg (Pmode, op1);
7094169705Skan		      new = gen_rtx_PLUS (Pmode, force_reg (Pmode, op0), op1);
7095169705Skan		    }
709652294Sobrien		}
709752294Sobrien	    }
709852294Sobrien	  else
709952294Sobrien	    {
710052294Sobrien	      base = legitimize_pic_address (XEXP (addr, 0), reg);
710152294Sobrien	      new  = legitimize_pic_address (XEXP (addr, 1),
710252294Sobrien					     base == reg ? NULL_RTX : reg);
710318334Speter
710452294Sobrien	      if (GET_CODE (new) == CONST_INT)
710552294Sobrien		new = plus_constant (base, INTVAL (new));
710652294Sobrien	      else
710752294Sobrien		{
710852294Sobrien		  if (GET_CODE (new) == PLUS && CONSTANT_P (XEXP (new, 1)))
710952294Sobrien		    {
711052294Sobrien		      base = gen_rtx_PLUS (Pmode, base, XEXP (new, 0));
711152294Sobrien		      new = XEXP (new, 1);
711252294Sobrien		    }
711352294Sobrien		  new = gen_rtx_PLUS (Pmode, base, new);
711452294Sobrien		}
711552294Sobrien	    }
711618334Speter	}
711718334Speter    }
711818334Speter  return new;
711918334Speter}
7120132743Skan
7121132743Skan/* Load the thread pointer.  If TO_REG is true, force it into a register.  */
7122117408Skan
7123132743Skanstatic rtx
7124132743Skanget_thread_pointer (int to_reg)
7125117408Skan{
7126132743Skan  rtx tp, reg, insn;
7127117408Skan
7128132743Skan  tp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx), UNSPEC_TP);
7129132743Skan  if (!to_reg)
7130132743Skan    return tp;
7131117408Skan
7132132743Skan  reg = gen_reg_rtx (Pmode);
7133132743Skan  insn = gen_rtx_SET (VOIDmode, reg, tp);
7134132743Skan  insn = emit_insn (insn);
7135117408Skan
7136132743Skan  return reg;
7137132743Skan}
7138117408Skan
7139132743Skan/* A subroutine of legitimize_address and ix86_expand_move.  FOR_MOV is
7140132743Skan   false if we expect this to be used for a memory address and true if
7141132743Skan   we expect to load the address into a register.  */
7142117408Skan
7143132743Skanstatic rtx
7144132743Skanlegitimize_tls_address (rtx x, enum tls_model model, int for_mov)
7145132743Skan{
7146169705Skan  rtx dest, base, off, pic, tp;
7147132743Skan  int type;
7148132743Skan
7149132743Skan  switch (model)
7150117408Skan    {
7151132743Skan    case TLS_MODEL_GLOBAL_DYNAMIC:
7152132743Skan      dest = gen_reg_rtx (Pmode);
7153169705Skan      tp = TARGET_GNU2_TLS ? get_thread_pointer (1) : 0;
7154169705Skan
7155169705Skan      if (TARGET_64BIT && ! TARGET_GNU2_TLS)
7156132743Skan	{
7157132743Skan	  rtx rax = gen_rtx_REG (Pmode, 0), insns;
7158117408Skan
7159132743Skan	  start_sequence ();
7160132743Skan	  emit_call_insn (gen_tls_global_dynamic_64 (rax, x));
7161132743Skan	  insns = get_insns ();
7162132743Skan	  end_sequence ();
7163132743Skan
7164132743Skan	  emit_libcall_block (insns, dest, rax, x);
7165132743Skan	}
7166169705Skan      else if (TARGET_64BIT && TARGET_GNU2_TLS)
7167169705Skan	emit_insn (gen_tls_global_dynamic_64 (dest, x));
7168132743Skan      else
7169132743Skan	emit_insn (gen_tls_global_dynamic_32 (dest, x));
7170169705Skan
7171169705Skan      if (TARGET_GNU2_TLS)
7172169705Skan	{
7173169705Skan	  dest = force_reg (Pmode, gen_rtx_PLUS (Pmode, tp, dest));
7174169705Skan
7175169705Skan	  set_unique_reg_note (get_last_insn (), REG_EQUIV, x);
7176169705Skan	}
7177132743Skan      break;
7178132743Skan
7179132743Skan    case TLS_MODEL_LOCAL_DYNAMIC:
7180132743Skan      base = gen_reg_rtx (Pmode);
7181169705Skan      tp = TARGET_GNU2_TLS ? get_thread_pointer (1) : 0;
7182169705Skan
7183169705Skan      if (TARGET_64BIT && ! TARGET_GNU2_TLS)
7184117408Skan	{
7185132743Skan	  rtx rax = gen_rtx_REG (Pmode, 0), insns, note;
7186132743Skan
7187132743Skan	  start_sequence ();
7188132743Skan	  emit_call_insn (gen_tls_local_dynamic_base_64 (rax));
7189132743Skan	  insns = get_insns ();
7190132743Skan	  end_sequence ();
7191132743Skan
7192132743Skan	  note = gen_rtx_EXPR_LIST (VOIDmode, const0_rtx, NULL);
7193132743Skan	  note = gen_rtx_EXPR_LIST (VOIDmode, ix86_tls_get_addr (), note);
7194132743Skan	  emit_libcall_block (insns, base, rax, note);
7195117408Skan	}
7196169705Skan      else if (TARGET_64BIT && TARGET_GNU2_TLS)
7197169705Skan	emit_insn (gen_tls_local_dynamic_base_64 (base));
7198132743Skan      else
7199132743Skan	emit_insn (gen_tls_local_dynamic_base_32 (base));
7200117408Skan
7201169705Skan      if (TARGET_GNU2_TLS)
7202169705Skan	{
7203169705Skan	  rtx x = ix86_tls_module_base ();
7204169705Skan
7205169705Skan	  set_unique_reg_note (get_last_insn (), REG_EQUIV,
7206169705Skan			       gen_rtx_MINUS (Pmode, x, tp));
7207169705Skan	}
7208169705Skan
7209132743Skan      off = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), UNSPEC_DTPOFF);
7210132743Skan      off = gen_rtx_CONST (Pmode, off);
7211117408Skan
7212169705Skan      dest = force_reg (Pmode, gen_rtx_PLUS (Pmode, base, off));
7213132743Skan
7214169705Skan      if (TARGET_GNU2_TLS)
7215169705Skan	{
7216169705Skan	  dest = force_reg (Pmode, gen_rtx_PLUS (Pmode, dest, tp));
7217169705Skan
7218169705Skan	  set_unique_reg_note (get_last_insn (), REG_EQUIV, x);
7219169705Skan	}
7220169705Skan
7221169705Skan      break;
7222169705Skan
7223132743Skan    case TLS_MODEL_INITIAL_EXEC:
7224132743Skan      if (TARGET_64BIT)
7225117408Skan	{
7226132743Skan	  pic = NULL;
7227132743Skan	  type = UNSPEC_GOTNTPOFF;
7228117408Skan	}
7229132743Skan      else if (flag_pic)
7230132743Skan	{
7231132743Skan	  if (reload_in_progress)
7232132743Skan	    regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1;
7233132743Skan	  pic = pic_offset_table_rtx;
7234169705Skan	  type = TARGET_ANY_GNU_TLS ? UNSPEC_GOTNTPOFF : UNSPEC_GOTTPOFF;
7235132743Skan	}
7236169705Skan      else if (!TARGET_ANY_GNU_TLS)
7237132743Skan	{
7238132743Skan	  pic = gen_reg_rtx (Pmode);
7239132743Skan	  emit_insn (gen_set_got (pic));
7240132743Skan	  type = UNSPEC_GOTTPOFF;
7241132743Skan	}
7242132743Skan      else
7243132743Skan	{
7244132743Skan	  pic = NULL;
7245132743Skan	  type = UNSPEC_INDNTPOFF;
7246132743Skan	}
7247117408Skan
7248132743Skan      off = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), type);
7249132743Skan      off = gen_rtx_CONST (Pmode, off);
7250132743Skan      if (pic)
7251132743Skan	off = gen_rtx_PLUS (Pmode, pic, off);
7252169705Skan      off = gen_const_mem (Pmode, off);
7253132743Skan      set_mem_alias_set (off, ix86_GOT_alias_set ());
7254117408Skan
7255169705Skan      if (TARGET_64BIT || TARGET_ANY_GNU_TLS)
7256132743Skan	{
7257132743Skan          base = get_thread_pointer (for_mov || !TARGET_TLS_DIRECT_SEG_REFS);
7258132743Skan	  off = force_reg (Pmode, off);
7259132743Skan	  return gen_rtx_PLUS (Pmode, base, off);
7260132743Skan	}
7261132743Skan      else
7262132743Skan	{
7263132743Skan	  base = get_thread_pointer (true);
7264132743Skan	  dest = gen_reg_rtx (Pmode);
7265132743Skan	  emit_insn (gen_subsi3 (dest, base, off));
7266132743Skan	}
7267132743Skan      break;
7268117408Skan
7269132743Skan    case TLS_MODEL_LOCAL_EXEC:
7270132743Skan      off = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x),
7271169705Skan			    (TARGET_64BIT || TARGET_ANY_GNU_TLS)
7272132743Skan			    ? UNSPEC_NTPOFF : UNSPEC_TPOFF);
7273132743Skan      off = gen_rtx_CONST (Pmode, off);
7274117408Skan
7275169705Skan      if (TARGET_64BIT || TARGET_ANY_GNU_TLS)
7276132743Skan	{
7277132743Skan	  base = get_thread_pointer (for_mov || !TARGET_TLS_DIRECT_SEG_REFS);
7278132743Skan	  return gen_rtx_PLUS (Pmode, base, off);
7279132743Skan	}
7280132743Skan      else
7281132743Skan	{
7282132743Skan	  base = get_thread_pointer (true);
7283132743Skan	  dest = gen_reg_rtx (Pmode);
7284132743Skan	  emit_insn (gen_subsi3 (dest, base, off));
7285132743Skan	}
7286132743Skan      break;
7287117408Skan
7288132743Skan    default:
7289169705Skan      gcc_unreachable ();
7290132743Skan    }
7291117408Skan
7292132743Skan  return dest;
7293117408Skan}
7294117408Skan
729518334Speter/* Try machine-dependent ways of modifying an illegitimate address
729618334Speter   to be legitimate.  If we find one, return the new, valid address.
729718334Speter   This macro is used in only one place: `memory_address' in explow.c.
729818334Speter
729918334Speter   OLDX is the address as it was before break_out_memory_refs was called.
730018334Speter   In some cases it is useful to look at this to decide what needs to be done.
730118334Speter
730218334Speter   MODE and WIN are passed so that this macro can use
730318334Speter   GO_IF_LEGITIMATE_ADDRESS.
730418334Speter
730518334Speter   It is always safe for this macro to do nothing.  It exists to recognize
730618334Speter   opportunities to optimize the output.
730718334Speter
730818334Speter   For the 80386, we handle X+REG by loading X into a register R and
730918334Speter   using R+REG.  R will go in a general reg and indexing will be used.
731018334Speter   However, if REG is a broken-out memory address or multiplication,
731118334Speter   nothing needs to be done because REG can certainly go in a general reg.
731218334Speter
731318334Speter   When -fpic is used, special handling is needed for symbolic references.
731418334Speter   See comments by legitimize_pic_address in i386.c for details.  */
731518334Speter
731618334Speterrtx
7317132743Skanlegitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, enum machine_mode mode)
731818334Speter{
731918334Speter  int changed = 0;
732018334Speter  unsigned log;
732118334Speter
732218334Speter  if (TARGET_DEBUG_ADDR)
732318334Speter    {
732451411Sobrien      fprintf (stderr, "\n==========\nLEGITIMIZE_ADDRESS, mode = %s\n",
732551411Sobrien	       GET_MODE_NAME (mode));
732618334Speter      debug_rtx (x);
732718334Speter    }
732818334Speter
7329169705Skan  log = GET_CODE (x) == SYMBOL_REF ? SYMBOL_REF_TLS_MODEL (x) : 0;
7330117408Skan  if (log)
7331132743Skan    return legitimize_tls_address (x, log, false);
7332169705Skan  if (GET_CODE (x) == CONST
7333169705Skan      && GET_CODE (XEXP (x, 0)) == PLUS
7334169705Skan      && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
7335169705Skan      && (log = SYMBOL_REF_TLS_MODEL (XEXP (XEXP (x, 0), 0))))
7336169705Skan    {
7337169705Skan      rtx t = legitimize_tls_address (XEXP (XEXP (x, 0), 0), log, false);
7338169705Skan      return gen_rtx_PLUS (Pmode, t, XEXP (XEXP (x, 0), 1));
7339169705Skan    }
7340117408Skan
734118334Speter  if (flag_pic && SYMBOLIC_CONST (x))
734218334Speter    return legitimize_pic_address (x, 0);
734318334Speter
734418334Speter  /* Canonicalize shifts by 0, 1, 2, 3 into multiply */
734518334Speter  if (GET_CODE (x) == ASHIFT
734618334Speter      && GET_CODE (XEXP (x, 1)) == CONST_INT
7347169705Skan      && (unsigned HOST_WIDE_INT) INTVAL (XEXP (x, 1)) < 4)
734818334Speter    {
734918334Speter      changed = 1;
7350169705Skan      log = INTVAL (XEXP (x, 1));
735152294Sobrien      x = gen_rtx_MULT (Pmode, force_reg (Pmode, XEXP (x, 0)),
735252294Sobrien			GEN_INT (1 << log));
735318334Speter    }
735418334Speter
735518334Speter  if (GET_CODE (x) == PLUS)
735618334Speter    {
735790284Sobrien      /* Canonicalize shifts by 0, 1, 2, 3 into multiply.  */
735851411Sobrien
735918334Speter      if (GET_CODE (XEXP (x, 0)) == ASHIFT
736018334Speter	  && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
7361169705Skan	  && (unsigned HOST_WIDE_INT) INTVAL (XEXP (XEXP (x, 0), 1)) < 4)
736218334Speter	{
736318334Speter	  changed = 1;
7364169705Skan	  log = INTVAL (XEXP (XEXP (x, 0), 1));
736590284Sobrien	  XEXP (x, 0) = gen_rtx_MULT (Pmode,
736690284Sobrien				      force_reg (Pmode, XEXP (XEXP (x, 0), 0)),
736790284Sobrien				      GEN_INT (1 << log));
736818334Speter	}
736918334Speter
737018334Speter      if (GET_CODE (XEXP (x, 1)) == ASHIFT
737118334Speter	  && GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT
7372169705Skan	  && (unsigned HOST_WIDE_INT) INTVAL (XEXP (XEXP (x, 1), 1)) < 4)
737318334Speter	{
737418334Speter	  changed = 1;
7375169705Skan	  log = INTVAL (XEXP (XEXP (x, 1), 1));
737690284Sobrien	  XEXP (x, 1) = gen_rtx_MULT (Pmode,
737790284Sobrien				      force_reg (Pmode, XEXP (XEXP (x, 1), 0)),
737890284Sobrien				      GEN_INT (1 << log));
737918334Speter	}
738018334Speter
738190284Sobrien      /* Put multiply first if it isn't already.  */
738218334Speter      if (GET_CODE (XEXP (x, 1)) == MULT)
738318334Speter	{
738418334Speter	  rtx tmp = XEXP (x, 0);
738518334Speter	  XEXP (x, 0) = XEXP (x, 1);
738618334Speter	  XEXP (x, 1) = tmp;
738718334Speter	  changed = 1;
738818334Speter	}
738918334Speter
739018334Speter      /* Canonicalize (plus (mult (reg) (const)) (plus (reg) (const)))
739118334Speter	 into (plus (plus (mult (reg) (const)) (reg)) (const)).  This can be
739218334Speter	 created by virtual register instantiation, register elimination, and
739318334Speter	 similar optimizations.  */
739418334Speter      if (GET_CODE (XEXP (x, 0)) == MULT && GET_CODE (XEXP (x, 1)) == PLUS)
739518334Speter	{
739618334Speter	  changed = 1;
739790284Sobrien	  x = gen_rtx_PLUS (Pmode,
739890284Sobrien			    gen_rtx_PLUS (Pmode, XEXP (x, 0),
739990284Sobrien					  XEXP (XEXP (x, 1), 0)),
740090284Sobrien			    XEXP (XEXP (x, 1), 1));
740118334Speter	}
740218334Speter
740351411Sobrien      /* Canonicalize
740451411Sobrien	 (plus (plus (mult (reg) (const)) (plus (reg) (const))) const)
740518334Speter	 into (plus (plus (mult (reg) (const)) (reg)) (const)).  */
740618334Speter      else if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 0)) == PLUS
740718334Speter	       && GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT
740818334Speter	       && GET_CODE (XEXP (XEXP (x, 0), 1)) == PLUS
740918334Speter	       && CONSTANT_P (XEXP (x, 1)))
741018334Speter	{
741151411Sobrien	  rtx constant;
741251411Sobrien	  rtx other = NULL_RTX;
741318334Speter
741418334Speter	  if (GET_CODE (XEXP (x, 1)) == CONST_INT)
741518334Speter	    {
741618334Speter	      constant = XEXP (x, 1);
741718334Speter	      other = XEXP (XEXP (XEXP (x, 0), 1), 1);
741818334Speter	    }
741918334Speter	  else if (GET_CODE (XEXP (XEXP (XEXP (x, 0), 1), 1)) == CONST_INT)
742018334Speter	    {
742118334Speter	      constant = XEXP (XEXP (XEXP (x, 0), 1), 1);
742218334Speter	      other = XEXP (x, 1);
742318334Speter	    }
742418334Speter	  else
742518334Speter	    constant = 0;
742618334Speter
742718334Speter	  if (constant)
742818334Speter	    {
742918334Speter	      changed = 1;
743090284Sobrien	      x = gen_rtx_PLUS (Pmode,
743190284Sobrien				gen_rtx_PLUS (Pmode, XEXP (XEXP (x, 0), 0),
743290284Sobrien					      XEXP (XEXP (XEXP (x, 0), 1), 0)),
743390284Sobrien				plus_constant (other, INTVAL (constant)));
743418334Speter	    }
743518334Speter	}
743618334Speter
743718334Speter      if (changed && legitimate_address_p (mode, x, FALSE))
743818334Speter	return x;
743918334Speter
744018334Speter      if (GET_CODE (XEXP (x, 0)) == MULT)
744118334Speter	{
744218334Speter	  changed = 1;
744318334Speter	  XEXP (x, 0) = force_operand (XEXP (x, 0), 0);
744418334Speter	}
744518334Speter
744618334Speter      if (GET_CODE (XEXP (x, 1)) == MULT)
744718334Speter	{
744818334Speter	  changed = 1;
744918334Speter	  XEXP (x, 1) = force_operand (XEXP (x, 1), 0);
745018334Speter	}
745118334Speter
745218334Speter      if (changed
745318334Speter	  && GET_CODE (XEXP (x, 1)) == REG
745418334Speter	  && GET_CODE (XEXP (x, 0)) == REG)
745518334Speter	return x;
745618334Speter
745718334Speter      if (flag_pic && SYMBOLIC_CONST (XEXP (x, 1)))
745818334Speter	{
745918334Speter	  changed = 1;
746018334Speter	  x = legitimize_pic_address (x, 0);
746118334Speter	}
746218334Speter
746318334Speter      if (changed && legitimate_address_p (mode, x, FALSE))
746418334Speter	return x;
746518334Speter
746618334Speter      if (GET_CODE (XEXP (x, 0)) == REG)
746718334Speter	{
7468132743Skan	  rtx temp = gen_reg_rtx (Pmode);
7469132743Skan	  rtx val  = force_operand (XEXP (x, 1), temp);
747018334Speter	  if (val != temp)
747118334Speter	    emit_move_insn (temp, val);
747218334Speter
747318334Speter	  XEXP (x, 1) = temp;
747418334Speter	  return x;
747518334Speter	}
747618334Speter
747718334Speter      else if (GET_CODE (XEXP (x, 1)) == REG)
747818334Speter	{
7479132743Skan	  rtx temp = gen_reg_rtx (Pmode);
7480132743Skan	  rtx val  = force_operand (XEXP (x, 0), temp);
748118334Speter	  if (val != temp)
748218334Speter	    emit_move_insn (temp, val);
748318334Speter
748418334Speter	  XEXP (x, 0) = temp;
748518334Speter	  return x;
748618334Speter	}
748718334Speter    }
748818334Speter
748918334Speter  return x;
749018334Speter}
749118334Speter
749218334Speter/* Print an integer constant expression in assembler syntax.  Addition
749318334Speter   and subtraction are the only arithmetic that may appear in these
749418334Speter   expressions.  FILE is the stdio stream to write to, X is the rtx, and
749518334Speter   CODE is the operand print code from the output string.  */
749618334Speter
749718334Speterstatic void
7498132743Skanoutput_pic_addr_const (FILE *file, rtx x, int code)
749918334Speter{
750018334Speter  char buf[256];
750118334Speter
750218334Speter  switch (GET_CODE (x))
750318334Speter    {
750418334Speter    case PC:
7505169705Skan      gcc_assert (flag_pic);
7506169705Skan      putc ('.', file);
750718334Speter      break;
750818334Speter
750918334Speter    case SYMBOL_REF:
7510169705Skan      if (! TARGET_MACHO || TARGET_64BIT)
7511169705Skan	output_addr_const (file, x);
7512169705Skan      else
7513169705Skan	{
7514169705Skan	  const char *name = XSTR (x, 0);
7515169705Skan
7516169705Skan	  /* Mark the decl as referenced so that cgraph will output the function.  */
7517169705Skan	  if (SYMBOL_REF_DECL (x))
7518169705Skan	    mark_decl_referenced (SYMBOL_REF_DECL (x));
7519169705Skan
7520169705Skan#if TARGET_MACHO
7521169705Skan	  if (MACHOPIC_INDIRECT
7522169705Skan	      && machopic_classify_symbol (x) == MACHOPIC_UNDEFINED_FUNCTION)
7523169705Skan	    name = machopic_indirection_name (x, /*stub_p=*/true);
7524169705Skan#endif
7525169705Skan	  assemble_name (file, name);
7526169705Skan	}
7527132743Skan      if (!TARGET_MACHO && code == 'P' && ! SYMBOL_REF_LOCAL_P (x))
752852294Sobrien	fputs ("@PLT", file);
752918334Speter      break;
753018334Speter
753152294Sobrien    case LABEL_REF:
753252294Sobrien      x = XEXP (x, 0);
753352294Sobrien      /* FALLTHRU */
753418334Speter    case CODE_LABEL:
753518334Speter      ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
753618334Speter      assemble_name (asm_out_file, buf);
753718334Speter      break;
753818334Speter
753918334Speter    case CONST_INT:
754051411Sobrien      fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x));
754118334Speter      break;
754218334Speter
754318334Speter    case CONST:
754418334Speter      /* This used to output parentheses around the expression,
754518334Speter	 but that does not work on the 386 (either ATT or BSD assembler).  */
754618334Speter      output_pic_addr_const (file, XEXP (x, 0), code);
754718334Speter      break;
754818334Speter
754918334Speter    case CONST_DOUBLE:
755018334Speter      if (GET_MODE (x) == VOIDmode)
755118334Speter	{
755218334Speter	  /* We can use %d if the number is <32 bits and positive.  */
755318334Speter	  if (CONST_DOUBLE_HIGH (x) || CONST_DOUBLE_LOW (x) < 0)
755451411Sobrien	    fprintf (file, "0x%lx%08lx",
755551411Sobrien		     (unsigned long) CONST_DOUBLE_HIGH (x),
755651411Sobrien		     (unsigned long) CONST_DOUBLE_LOW (x));
755718334Speter	  else
755851411Sobrien	    fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x));
755918334Speter	}
756018334Speter      else
756118334Speter	/* We can't handle floating point constants;
756218334Speter	   PRINT_OPERAND must handle them.  */
756318334Speter	output_operand_lossage ("floating constant misused");
756418334Speter      break;
756518334Speter
756618334Speter    case PLUS:
756751411Sobrien      /* Some assemblers need integer constants to appear first.  */
756818334Speter      if (GET_CODE (XEXP (x, 0)) == CONST_INT)
756918334Speter	{
757051411Sobrien	  output_pic_addr_const (file, XEXP (x, 0), code);
757190284Sobrien	  putc ('+', file);
757218334Speter	  output_pic_addr_const (file, XEXP (x, 1), code);
757318334Speter	}
7574169705Skan      else
757518334Speter	{
7576169705Skan	  gcc_assert (GET_CODE (XEXP (x, 1)) == CONST_INT);
757751411Sobrien	  output_pic_addr_const (file, XEXP (x, 1), code);
757890284Sobrien	  putc ('+', file);
757918334Speter	  output_pic_addr_const (file, XEXP (x, 0), code);
758018334Speter	}
758118334Speter      break;
758218334Speter
758318334Speter    case MINUS:
7584117408Skan      if (!TARGET_MACHO)
7585117408Skan	putc (ASSEMBLER_DIALECT == ASM_INTEL ? '(' : '[', file);
758618334Speter      output_pic_addr_const (file, XEXP (x, 0), code);
758790284Sobrien      putc ('-', file);
758818334Speter      output_pic_addr_const (file, XEXP (x, 1), code);
7589117408Skan      if (!TARGET_MACHO)
7590117408Skan	putc (ASSEMBLER_DIALECT == ASM_INTEL ? ')' : ']', file);
759118334Speter      break;
759218334Speter
759352294Sobrien     case UNSPEC:
7594169705Skan       gcc_assert (XVECLEN (x, 0) == 1);
759552294Sobrien       output_pic_addr_const (file, XVECEXP (x, 0, 0), code);
759652294Sobrien       switch (XINT (x, 1))
759790284Sobrien	{
7598117408Skan	case UNSPEC_GOT:
759990284Sobrien	  fputs ("@GOT", file);
760090284Sobrien	  break;
7601117408Skan	case UNSPEC_GOTOFF:
760290284Sobrien	  fputs ("@GOTOFF", file);
760390284Sobrien	  break;
7604117408Skan	case UNSPEC_GOTPCREL:
7605117408Skan	  fputs ("@GOTPCREL(%rip)", file);
760690284Sobrien	  break;
7607117408Skan	case UNSPEC_GOTTPOFF:
7608117408Skan	  /* FIXME: This might be @TPOFF in Sun ld too.  */
7609117408Skan	  fputs ("@GOTTPOFF", file);
761090284Sobrien	  break;
7611117408Skan	case UNSPEC_TPOFF:
7612117408Skan	  fputs ("@TPOFF", file);
7613117408Skan	  break;
7614117408Skan	case UNSPEC_NTPOFF:
7615117408Skan	  if (TARGET_64BIT)
7616117408Skan	    fputs ("@TPOFF", file);
7617117408Skan	  else
7618117408Skan	    fputs ("@NTPOFF", file);
7619117408Skan	  break;
7620117408Skan	case UNSPEC_DTPOFF:
7621117408Skan	  fputs ("@DTPOFF", file);
7622117408Skan	  break;
7623117408Skan	case UNSPEC_GOTNTPOFF:
7624117408Skan	  if (TARGET_64BIT)
7625117408Skan	    fputs ("@GOTTPOFF(%rip)", file);
7626117408Skan	  else
7627117408Skan	    fputs ("@GOTNTPOFF", file);
7628117408Skan	  break;
7629117408Skan	case UNSPEC_INDNTPOFF:
7630117408Skan	  fputs ("@INDNTPOFF", file);
7631117408Skan	  break;
763290284Sobrien	default:
763390284Sobrien	  output_operand_lossage ("invalid UNSPEC as operand");
763490284Sobrien	  break;
763590284Sobrien	}
763652294Sobrien       break;
763752294Sobrien
763818334Speter    default:
763918334Speter      output_operand_lossage ("invalid expression as operand");
764018334Speter    }
764118334Speter}
764290284Sobrien
7643169705Skan/* This is called from dwarf2out.c via TARGET_ASM_OUTPUT_DWARF_DTPREL.
7644117408Skan   We need to emit DTP-relative relocations.  */
7645117408Skan
7646169705Skanstatic void
7647132743Skani386_output_dwarf_dtprel (FILE *file, int size, rtx x)
7648117408Skan{
7649117408Skan  fputs (ASM_LONG, file);
7650117408Skan  output_addr_const (file, x);
7651117408Skan  fputs ("@DTPOFF", file);
7652117408Skan  switch (size)
7653117408Skan    {
7654117408Skan    case 4:
7655117408Skan      break;
7656117408Skan    case 8:
7657117408Skan      fputs (", 0", file);
7658117408Skan      break;
7659117408Skan    default:
7660169705Skan      gcc_unreachable ();
7661117408Skan   }
7662117408Skan}
7663117408Skan
766490284Sobrien/* In the name of slightly smaller debug output, and to cater to
7665169705Skan   general assembler lossage, recognize PIC+GOTOFF and turn it back
7666169705Skan   into a direct symbol reference.
766790284Sobrien
7668169705Skan   On Darwin, this is necessary to avoid a crash, because Darwin
7669169705Skan   has a different PIC label for each routine but the DWARF debugging
7670169705Skan   information is not associated with any particular routine, so it's
7671169705Skan   necessary to remove references to the PIC label from RTL stored by
7672169705Skan   the DWARF output code.  */
7673169705Skan
7674132743Skanstatic rtx
7675132743Skanix86_delegitimize_address (rtx orig_x)
767690284Sobrien{
7677169705Skan  rtx x = orig_x;
7678169705Skan  /* reg_addend is NULL or a multiple of some register.  */
7679169705Skan  rtx reg_addend = NULL_RTX;
7680169705Skan  /* const_addend is NULL or a const_int.  */
7681169705Skan  rtx const_addend = NULL_RTX;
7682169705Skan  /* This is the result, or NULL.  */
7683169705Skan  rtx result = NULL_RTX;
768490284Sobrien
768596293Sobrien  if (GET_CODE (x) == MEM)
768696293Sobrien    x = XEXP (x, 0);
768796293Sobrien
768890284Sobrien  if (TARGET_64BIT)
768990284Sobrien    {
769090284Sobrien      if (GET_CODE (x) != CONST
769190284Sobrien	  || GET_CODE (XEXP (x, 0)) != UNSPEC
7692117408Skan	  || XINT (XEXP (x, 0), 1) != UNSPEC_GOTPCREL
769396293Sobrien	  || GET_CODE (orig_x) != MEM)
769490284Sobrien	return orig_x;
769590284Sobrien      return XVECEXP (XEXP (x, 0), 0, 0);
769690284Sobrien    }
769790284Sobrien
769890284Sobrien  if (GET_CODE (x) != PLUS
769990284Sobrien      || GET_CODE (XEXP (x, 1)) != CONST)
770090284Sobrien    return orig_x;
770190284Sobrien
770296293Sobrien  if (GET_CODE (XEXP (x, 0)) == REG
770396293Sobrien      && REGNO (XEXP (x, 0)) == PIC_OFFSET_TABLE_REGNUM)
770496293Sobrien    /* %ebx + GOT/GOTOFF */
7705169705Skan    ;
770696293Sobrien  else if (GET_CODE (XEXP (x, 0)) == PLUS)
770796293Sobrien    {
770896293Sobrien      /* %ebx + %reg * scale + GOT/GOTOFF */
7709169705Skan      reg_addend = XEXP (x, 0);
7710169705Skan      if (GET_CODE (XEXP (reg_addend, 0)) == REG
7711169705Skan	  && REGNO (XEXP (reg_addend, 0)) == PIC_OFFSET_TABLE_REGNUM)
7712169705Skan	reg_addend = XEXP (reg_addend, 1);
7713169705Skan      else if (GET_CODE (XEXP (reg_addend, 1)) == REG
7714169705Skan	       && REGNO (XEXP (reg_addend, 1)) == PIC_OFFSET_TABLE_REGNUM)
7715169705Skan	reg_addend = XEXP (reg_addend, 0);
771696293Sobrien      else
771796293Sobrien	return orig_x;
7718169705Skan      if (GET_CODE (reg_addend) != REG
7719169705Skan	  && GET_CODE (reg_addend) != MULT
7720169705Skan	  && GET_CODE (reg_addend) != ASHIFT)
772196293Sobrien	return orig_x;
772296293Sobrien    }
772396293Sobrien  else
772496293Sobrien    return orig_x;
772596293Sobrien
772690284Sobrien  x = XEXP (XEXP (x, 1), 0);
7727169705Skan  if (GET_CODE (x) == PLUS
7728169705Skan      && GET_CODE (XEXP (x, 1)) == CONST_INT)
7729169705Skan    {
7730169705Skan      const_addend = XEXP (x, 1);
7731169705Skan      x = XEXP (x, 0);
7732169705Skan    }
7733169705Skan
773490284Sobrien  if (GET_CODE (x) == UNSPEC
7735117408Skan      && ((XINT (x, 1) == UNSPEC_GOT && GET_CODE (orig_x) == MEM)
7736117408Skan	  || (XINT (x, 1) == UNSPEC_GOTOFF && GET_CODE (orig_x) != MEM)))
7737169705Skan    result = XVECEXP (x, 0, 0);
773890284Sobrien
7739169705Skan  if (TARGET_MACHO && darwin_local_data_pic (x)
7740169705Skan      && GET_CODE (orig_x) != MEM)
7741169705Skan    result = XEXP (x, 0);
774290284Sobrien
7743169705Skan  if (! result)
7744169705Skan    return orig_x;
7745169705Skan
7746169705Skan  if (const_addend)
7747169705Skan    result = gen_rtx_PLUS (Pmode, result, const_addend);
7748169705Skan  if (reg_addend)
7749169705Skan    result = gen_rtx_PLUS (Pmode, reg_addend, result);
7750169705Skan  return result;
775190284Sobrien}
775218334Speter
775352294Sobrienstatic void
7754132743Skanput_condition_code (enum rtx_code code, enum machine_mode mode, int reverse,
7755132743Skan		    int fp, FILE *file)
775652294Sobrien{
775752294Sobrien  const char *suffix;
775852294Sobrien
775990284Sobrien  if (mode == CCFPmode || mode == CCFPUmode)
776090284Sobrien    {
776190284Sobrien      enum rtx_code second_code, bypass_code;
776290284Sobrien      ix86_fp_comparison_codes (code, &bypass_code, &code, &second_code);
7763169705Skan      gcc_assert (bypass_code == UNKNOWN && second_code == UNKNOWN);
776490284Sobrien      code = ix86_fp_compare_code_to_integer (code);
776590284Sobrien      mode = CCmode;
776652294Sobrien    }
776752294Sobrien  if (reverse)
776852294Sobrien    code = reverse_condition (code);
776990284Sobrien
777052294Sobrien  switch (code)
777152294Sobrien    {
777252294Sobrien    case EQ:
777352294Sobrien      suffix = "e";
777452294Sobrien      break;
777552294Sobrien    case NE:
777652294Sobrien      suffix = "ne";
777752294Sobrien      break;
777852294Sobrien    case GT:
7779169705Skan      gcc_assert (mode == CCmode || mode == CCNOmode || mode == CCGCmode);
778090284Sobrien      suffix = "g";
778152294Sobrien      break;
778252294Sobrien    case GTU:
7783169705Skan      /* ??? Use "nbe" instead of "a" for fcmov lossage on some assemblers.
7784169705Skan	 Those same assemblers have the same but opposite lossage on cmov.  */
7785169705Skan      gcc_assert (mode == CCmode);
778690284Sobrien      suffix = fp ? "nbe" : "a";
778752294Sobrien      break;
778852294Sobrien    case LT:
7789169705Skan      switch (mode)
7790169705Skan	{
7791169705Skan	case CCNOmode:
7792169705Skan	case CCGOCmode:
7793169705Skan	  suffix = "s";
7794169705Skan	  break;
7795169705Skan
7796169705Skan	case CCmode:
7797169705Skan	case CCGCmode:
7798169705Skan	  suffix = "l";
7799169705Skan	  break;
7800169705Skan
7801169705Skan	default:
7802169705Skan	  gcc_unreachable ();
7803169705Skan	}
780452294Sobrien      break;
780552294Sobrien    case LTU:
7806169705Skan      gcc_assert (mode == CCmode);
780752294Sobrien      suffix = "b";
780852294Sobrien      break;
780952294Sobrien    case GE:
7810169705Skan      switch (mode)
7811169705Skan	{
7812169705Skan	case CCNOmode:
7813169705Skan	case CCGOCmode:
7814169705Skan	  suffix = "ns";
7815169705Skan	  break;
7816169705Skan
7817169705Skan	case CCmode:
7818169705Skan	case CCGCmode:
7819169705Skan	  suffix = "ge";
7820169705Skan	  break;
7821169705Skan
7822169705Skan	default:
7823169705Skan	  gcc_unreachable ();
7824169705Skan	}
782552294Sobrien      break;
782652294Sobrien    case GEU:
782790284Sobrien      /* ??? As above.  */
7828169705Skan      gcc_assert (mode == CCmode);
782990284Sobrien      suffix = fp ? "nb" : "ae";
783052294Sobrien      break;
783152294Sobrien    case LE:
7832169705Skan      gcc_assert (mode == CCmode || mode == CCGCmode || mode == CCNOmode);
783390284Sobrien      suffix = "le";
783452294Sobrien      break;
783552294Sobrien    case LEU:
7836169705Skan      gcc_assert (mode == CCmode);
783752294Sobrien      suffix = "be";
783852294Sobrien      break;
783990284Sobrien    case UNORDERED:
784090284Sobrien      suffix = fp ? "u" : "p";
784190284Sobrien      break;
784290284Sobrien    case ORDERED:
784390284Sobrien      suffix = fp ? "nu" : "np";
784490284Sobrien      break;
784552294Sobrien    default:
7846169705Skan      gcc_unreachable ();
784752294Sobrien    }
784852294Sobrien  fputs (suffix, file);
784952294Sobrien}
785052294Sobrien
7851132743Skan/* Print the name of register X to FILE based on its machine mode and number.
7852132743Skan   If CODE is 'w', pretend the mode is HImode.
7853132743Skan   If CODE is 'b', pretend the mode is QImode.
7854132743Skan   If CODE is 'k', pretend the mode is SImode.
7855132743Skan   If CODE is 'q', pretend the mode is DImode.
7856169705Skan   If CODE is 'h', pretend the reg is the 'high' byte register.
7857132743Skan   If CODE is 'y', print "st(0)" instead of "st", if the reg is stack op.  */
7858132743Skan
785990284Sobrienvoid
7860132743Skanprint_reg (rtx x, int code, FILE *file)
786151411Sobrien{
7862169705Skan  gcc_assert (REGNO (x) != ARG_POINTER_REGNUM
7863169705Skan	      && REGNO (x) != FRAME_POINTER_REGNUM
7864169705Skan	      && REGNO (x) != FLAGS_REG
7865237021Spfg	      && REGNO (x) != FPSR_REG);
786651411Sobrien
7867117408Skan  if (ASSEMBLER_DIALECT == ASM_ATT || USER_LABEL_PREFIX[0] == 0)
786890284Sobrien    putc ('%', file);
786951411Sobrien
787090284Sobrien  if (code == 'w' || MMX_REG_P (x))
787190284Sobrien    code = 2;
787290284Sobrien  else if (code == 'b')
787390284Sobrien    code = 1;
787490284Sobrien  else if (code == 'k')
787590284Sobrien    code = 4;
787690284Sobrien  else if (code == 'q')
787790284Sobrien    code = 8;
787890284Sobrien  else if (code == 'y')
787990284Sobrien    code = 3;
788090284Sobrien  else if (code == 'h')
788190284Sobrien    code = 0;
788290284Sobrien  else
788390284Sobrien    code = GET_MODE_SIZE (GET_MODE (x));
788451411Sobrien
788590284Sobrien  /* Irritatingly, AMD extended registers use different naming convention
788690284Sobrien     from the normal registers.  */
788790284Sobrien  if (REX_INT_REG_P (x))
788890284Sobrien    {
7889169705Skan      gcc_assert (TARGET_64BIT);
789090284Sobrien      switch (code)
789190284Sobrien	{
789290284Sobrien	  case 0:
789390284Sobrien	    error ("extended registers have no high halves");
789490284Sobrien	    break;
789590284Sobrien	  case 1:
789690284Sobrien	    fprintf (file, "r%ib", REGNO (x) - FIRST_REX_INT_REG + 8);
789790284Sobrien	    break;
789890284Sobrien	  case 2:
789990284Sobrien	    fprintf (file, "r%iw", REGNO (x) - FIRST_REX_INT_REG + 8);
790090284Sobrien	    break;
790190284Sobrien	  case 4:
790290284Sobrien	    fprintf (file, "r%id", REGNO (x) - FIRST_REX_INT_REG + 8);
790390284Sobrien	    break;
790490284Sobrien	  case 8:
790590284Sobrien	    fprintf (file, "r%i", REGNO (x) - FIRST_REX_INT_REG + 8);
790690284Sobrien	    break;
790790284Sobrien	  default:
790890284Sobrien	    error ("unsupported operand size for extended register");
790990284Sobrien	    break;
791090284Sobrien	}
791190284Sobrien      return;
791251411Sobrien    }
791390284Sobrien  switch (code)
791490284Sobrien    {
791590284Sobrien    case 3:
791690284Sobrien      if (STACK_TOP_P (x))
791790284Sobrien	{
791890284Sobrien	  fputs ("st(0)", file);
791990284Sobrien	  break;
792090284Sobrien	}
792190284Sobrien      /* FALLTHRU */
792290284Sobrien    case 8:
792390284Sobrien    case 4:
792490284Sobrien    case 12:
792590284Sobrien      if (! ANY_FP_REG_P (x))
792690284Sobrien	putc (code == 8 && TARGET_64BIT ? 'r' : 'e', file);
792790284Sobrien      /* FALLTHRU */
792890284Sobrien    case 16:
792990284Sobrien    case 2:
7930132743Skan    normal:
793190284Sobrien      fputs (hi_reg_name[REGNO (x)], file);
793290284Sobrien      break;
793390284Sobrien    case 1:
7934132743Skan      if (REGNO (x) >= ARRAY_SIZE (qi_reg_name))
7935132743Skan	goto normal;
793690284Sobrien      fputs (qi_reg_name[REGNO (x)], file);
793790284Sobrien      break;
793890284Sobrien    case 0:
7939132743Skan      if (REGNO (x) >= ARRAY_SIZE (qi_high_reg_name))
7940132743Skan	goto normal;
794190284Sobrien      fputs (qi_high_reg_name[REGNO (x)], file);
794290284Sobrien      break;
794390284Sobrien    default:
7944169705Skan      gcc_unreachable ();
794590284Sobrien    }
794651411Sobrien}
794751411Sobrien
7948117408Skan/* Locate some local-dynamic symbol still in use by this function
7949117408Skan   so that we can print its name in some tls_local_dynamic_base
7950117408Skan   pattern.  */
7951117408Skan
7952117408Skanstatic const char *
7953132743Skanget_some_local_dynamic_name (void)
7954117408Skan{
7955117408Skan  rtx insn;
7956117408Skan
7957117408Skan  if (cfun->machine->some_ld_name)
7958117408Skan    return cfun->machine->some_ld_name;
7959117408Skan
7960117408Skan  for (insn = get_insns (); insn ; insn = NEXT_INSN (insn))
7961117408Skan    if (INSN_P (insn)
7962117408Skan	&& for_each_rtx (&PATTERN (insn), get_some_local_dynamic_name_1, 0))
7963117408Skan      return cfun->machine->some_ld_name;
7964117408Skan
7965169705Skan  gcc_unreachable ();
7966117408Skan}
7967117408Skan
7968117408Skanstatic int
7969132743Skanget_some_local_dynamic_name_1 (rtx *px, void *data ATTRIBUTE_UNUSED)
7970117408Skan{
7971117408Skan  rtx x = *px;
7972117408Skan
7973117408Skan  if (GET_CODE (x) == SYMBOL_REF
7974169705Skan      && SYMBOL_REF_TLS_MODEL (x) == TLS_MODEL_LOCAL_DYNAMIC)
7975117408Skan    {
7976117408Skan      cfun->machine->some_ld_name = XSTR (x, 0);
7977117408Skan      return 1;
7978117408Skan    }
7979117408Skan
7980117408Skan  return 0;
7981117408Skan}
7982117408Skan
798318334Speter/* Meaning of CODE:
798451411Sobrien   L,W,B,Q,S,T -- print the opcode suffix for specified size of operand.
798551411Sobrien   C -- print opcode suffix for set/cmov insn.
798651411Sobrien   c -- like C, but print reversed condition
798790284Sobrien   F,f -- likewise, but for floating-point.
7988122194Skan   O -- if HAVE_AS_IX86_CMOV_SUN_SYNTAX, expand to "w.", "l." or "q.",
7989122194Skan        otherwise nothing
799018334Speter   R -- print the prefix for register names.
799118334Speter   z -- print the opcode suffix for the size of the current operand.
799218334Speter   * -- print a star (in certain assembler syntax)
799390284Sobrien   A -- print an absolute memory reference.
799418334Speter   w -- print the operand as if it's a "word" (HImode) even if it isn't.
799551411Sobrien   s -- print a shift double count, followed by the assemblers argument
799651411Sobrien	delimiter.
799751411Sobrien   b -- print the QImode name of the register for the indicated operand.
799851411Sobrien	%b0 would print %al if operands[0] is reg 0.
799951411Sobrien   w --  likewise, print the HImode name of the register.
800051411Sobrien   k --  likewise, print the SImode name of the register.
800190284Sobrien   q --  likewise, print the DImode name of the register.
800290284Sobrien   h -- print the QImode name for a "high" register, either ah, bh, ch or dh.
800390284Sobrien   y -- print "st(0)" instead of "st" as a register.
800490284Sobrien   D -- print condition for SSE cmp instruction.
800590284Sobrien   P -- if PIC, print an @PLT suffix.
800690284Sobrien   X -- don't print any sort of PIC '@' suffix for a symbol.
8007117408Skan   & -- print some in-use local-dynamic symbol name.
8008169705Skan   H -- print a memory address offset by 8; used for sse high-parts
800990284Sobrien */
801018334Speter
801118334Spetervoid
8012132743Skanprint_operand (FILE *file, rtx x, int code)
801318334Speter{
801418334Speter  if (code)
801518334Speter    {
801618334Speter      switch (code)
801718334Speter	{
801818334Speter	case '*':
801990284Sobrien	  if (ASSEMBLER_DIALECT == ASM_ATT)
802018334Speter	    putc ('*', file);
802118334Speter	  return;
802218334Speter
8023117408Skan	case '&':
8024117408Skan	  assemble_name (file, get_some_local_dynamic_name ());
8025117408Skan	  return;
8026117408Skan
802790284Sobrien	case 'A':
8028169705Skan	  switch (ASSEMBLER_DIALECT)
802990284Sobrien	    {
8030169705Skan	    case ASM_ATT:
8031169705Skan	      putc ('*', file);
8032169705Skan	      break;
8033169705Skan
8034169705Skan	    case ASM_INTEL:
803590284Sobrien	      /* Intel syntax. For absolute addresses, registers should not
803690284Sobrien		 be surrounded by braces.  */
803790284Sobrien	      if (GET_CODE (x) != REG)
803890284Sobrien		{
803990284Sobrien		  putc ('[', file);
804090284Sobrien		  PRINT_OPERAND (file, x, 0);
804190284Sobrien		  putc (']', file);
804290284Sobrien		  return;
804390284Sobrien		}
8044169705Skan	      break;
8045169705Skan
8046169705Skan	    default:
8047169705Skan	      gcc_unreachable ();
804890284Sobrien	    }
804990284Sobrien
805090284Sobrien	  PRINT_OPERAND (file, x, 0);
805152294Sobrien	  return;
805252294Sobrien
805390284Sobrien
805418334Speter	case 'L':
805590284Sobrien	  if (ASSEMBLER_DIALECT == ASM_ATT)
805690284Sobrien	    putc ('l', file);
805718334Speter	  return;
805818334Speter
805918334Speter	case 'W':
806090284Sobrien	  if (ASSEMBLER_DIALECT == ASM_ATT)
806190284Sobrien	    putc ('w', file);
806218334Speter	  return;
806318334Speter
806418334Speter	case 'B':
806590284Sobrien	  if (ASSEMBLER_DIALECT == ASM_ATT)
806690284Sobrien	    putc ('b', file);
806718334Speter	  return;
806818334Speter
806918334Speter	case 'Q':
807090284Sobrien	  if (ASSEMBLER_DIALECT == ASM_ATT)
807190284Sobrien	    putc ('l', file);
807218334Speter	  return;
807318334Speter
807418334Speter	case 'S':
807590284Sobrien	  if (ASSEMBLER_DIALECT == ASM_ATT)
807690284Sobrien	    putc ('s', file);
807718334Speter	  return;
807818334Speter
807918334Speter	case 'T':
808090284Sobrien	  if (ASSEMBLER_DIALECT == ASM_ATT)
808190284Sobrien	    putc ('t', file);
808218334Speter	  return;
808318334Speter
808418334Speter	case 'z':
808518334Speter	  /* 387 opcodes don't get size suffixes if the operands are
808690284Sobrien	     registers.  */
808718334Speter	  if (STACK_REG_P (x))
808818334Speter	    return;
808918334Speter
809096293Sobrien	  /* Likewise if using Intel opcodes.  */
809196293Sobrien	  if (ASSEMBLER_DIALECT == ASM_INTEL)
809296293Sobrien	    return;
809396293Sobrien
809496293Sobrien	  /* This is the size of op from size of operand.  */
809518334Speter	  switch (GET_MODE_SIZE (GET_MODE (x)))
809618334Speter	    {
809718334Speter	    case 2:
809852294Sobrien#ifdef HAVE_GAS_FILDS_FISTS
809990284Sobrien	      putc ('s', file);
810052294Sobrien#endif
810118334Speter	      return;
810218334Speter
810318334Speter	    case 4:
810418334Speter	      if (GET_MODE (x) == SFmode)
810518334Speter		{
810690284Sobrien		  putc ('s', file);
810718334Speter		  return;
810818334Speter		}
810918334Speter	      else
811090284Sobrien		putc ('l', file);
811118334Speter	      return;
811218334Speter
811318334Speter	    case 12:
811490284Sobrien	    case 16:
811590284Sobrien	      putc ('t', file);
811690284Sobrien	      return;
811718334Speter
811818334Speter	    case 8:
811918334Speter	      if (GET_MODE_CLASS (GET_MODE (x)) == MODE_INT)
812018334Speter		{
812118334Speter#ifdef GAS_MNEMONICS
812290284Sobrien		  putc ('q', file);
812318334Speter#else
812490284Sobrien		  putc ('l', file);
812590284Sobrien		  putc ('l', file);
812618334Speter#endif
812718334Speter		}
812890284Sobrien	      else
812990284Sobrien	        putc ('l', file);
813018334Speter	      return;
813152294Sobrien
813252294Sobrien	    default:
8133169705Skan	      gcc_unreachable ();
813418334Speter	    }
813518334Speter
813618334Speter	case 'b':
813718334Speter	case 'w':
813818334Speter	case 'k':
813990284Sobrien	case 'q':
814018334Speter	case 'h':
814118334Speter	case 'y':
814290284Sobrien	case 'X':
814318334Speter	case 'P':
814418334Speter	  break;
814518334Speter
814651411Sobrien	case 's':
814751411Sobrien	  if (GET_CODE (x) == CONST_INT || ! SHIFT_DOUBLE_OMITS_COUNT)
814851411Sobrien	    {
814951411Sobrien	      PRINT_OPERAND (file, x, 0);
815090284Sobrien	      putc (',', file);
815151411Sobrien	    }
815251411Sobrien	  return;
815351411Sobrien
815452294Sobrien	case 'D':
815590284Sobrien	  /* Little bit of braindamage here.  The SSE compare instructions
815690284Sobrien	     does use completely different names for the comparisons that the
815790284Sobrien	     fp conditional moves.  */
815890284Sobrien	  switch (GET_CODE (x))
815990284Sobrien	    {
816090284Sobrien	    case EQ:
816190284Sobrien	    case UNEQ:
816290284Sobrien	      fputs ("eq", file);
816390284Sobrien	      break;
816490284Sobrien	    case LT:
816590284Sobrien	    case UNLT:
816690284Sobrien	      fputs ("lt", file);
816790284Sobrien	      break;
816890284Sobrien	    case LE:
816990284Sobrien	    case UNLE:
817090284Sobrien	      fputs ("le", file);
817190284Sobrien	      break;
817290284Sobrien	    case UNORDERED:
817390284Sobrien	      fputs ("unord", file);
817490284Sobrien	      break;
817590284Sobrien	    case NE:
817690284Sobrien	    case LTGT:
817790284Sobrien	      fputs ("neq", file);
817890284Sobrien	      break;
817990284Sobrien	    case UNGE:
818090284Sobrien	    case GE:
818190284Sobrien	      fputs ("nlt", file);
818290284Sobrien	      break;
818390284Sobrien	    case UNGT:
818490284Sobrien	    case GT:
818590284Sobrien	      fputs ("nle", file);
818690284Sobrien	      break;
818790284Sobrien	    case ORDERED:
818890284Sobrien	      fputs ("ord", file);
818990284Sobrien	      break;
819090284Sobrien	    default:
8191169705Skan	      gcc_unreachable ();
819290284Sobrien	    }
819352294Sobrien	  return;
819496293Sobrien	case 'O':
8195122194Skan#ifdef HAVE_AS_IX86_CMOV_SUN_SYNTAX
819696293Sobrien	  if (ASSEMBLER_DIALECT == ASM_ATT)
819796293Sobrien	    {
819896293Sobrien	      switch (GET_MODE (x))
819996293Sobrien		{
820096293Sobrien		case HImode: putc ('w', file); break;
820196293Sobrien		case SImode:
820296293Sobrien		case SFmode: putc ('l', file); break;
820396293Sobrien		case DImode:
820496293Sobrien		case DFmode: putc ('q', file); break;
8205169705Skan		default: gcc_unreachable ();
820696293Sobrien		}
820796293Sobrien	      putc ('.', file);
820896293Sobrien	    }
820996293Sobrien#endif
821096293Sobrien	  return;
821151411Sobrien	case 'C':
821290284Sobrien	  put_condition_code (GET_CODE (x), GET_MODE (XEXP (x, 0)), 0, 0, file);
821351411Sobrien	  return;
821490284Sobrien	case 'F':
8215122194Skan#ifdef HAVE_AS_IX86_CMOV_SUN_SYNTAX
821696293Sobrien	  if (ASSEMBLER_DIALECT == ASM_ATT)
821796293Sobrien	    putc ('.', file);
821896293Sobrien#endif
821990284Sobrien	  put_condition_code (GET_CODE (x), GET_MODE (XEXP (x, 0)), 0, 1, file);
822090284Sobrien	  return;
822151411Sobrien
822251411Sobrien	  /* Like above, but reverse condition */
822351411Sobrien	case 'c':
8224117408Skan	  /* Check to see if argument to %c is really a constant
822590284Sobrien	     and not a condition code which needs to be reversed.  */
8226169705Skan	  if (!COMPARISON_P (x))
822790284Sobrien	  {
822890284Sobrien	    output_operand_lossage ("operand is neither a constant nor a condition code, invalid operand code 'c'");
822990284Sobrien	     return;
823090284Sobrien	  }
823190284Sobrien	  put_condition_code (GET_CODE (x), GET_MODE (XEXP (x, 0)), 1, 0, file);
823251411Sobrien	  return;
823351411Sobrien	case 'f':
8234122194Skan#ifdef HAVE_AS_IX86_CMOV_SUN_SYNTAX
823596293Sobrien	  if (ASSEMBLER_DIALECT == ASM_ATT)
823696293Sobrien	    putc ('.', file);
823796293Sobrien#endif
823890284Sobrien	  put_condition_code (GET_CODE (x), GET_MODE (XEXP (x, 0)), 1, 1, file);
823951411Sobrien	  return;
8240169705Skan
8241169705Skan	case 'H':
8242169705Skan	  /* It doesn't actually matter what mode we use here, as we're
8243169705Skan	     only going to use this for printing.  */
8244169705Skan	  x = adjust_address_nv (x, DImode, 8);
8245169705Skan	  break;
8246169705Skan
824790284Sobrien	case '+':
824890284Sobrien	  {
824990284Sobrien	    rtx x;
825051411Sobrien
825190284Sobrien	    if (!optimize || optimize_size || !TARGET_BRANCH_PREDICTION_HINTS)
825290284Sobrien	      return;
825390284Sobrien
825490284Sobrien	    x = find_reg_note (current_output_insn, REG_BR_PROB, 0);
825590284Sobrien	    if (x)
825690284Sobrien	      {
825790284Sobrien		int pred_val = INTVAL (XEXP (x, 0));
825890284Sobrien
825990284Sobrien		if (pred_val < REG_BR_PROB_BASE * 45 / 100
826090284Sobrien		    || pred_val > REG_BR_PROB_BASE * 55 / 100)
826190284Sobrien		  {
826290284Sobrien		    int taken = pred_val > REG_BR_PROB_BASE / 2;
826390284Sobrien		    int cputaken = final_forward_branch_p (current_output_insn) == 0;
826490284Sobrien
826590284Sobrien		    /* Emit hints only in the case default branch prediction
8266132743Skan		       heuristics would fail.  */
826790284Sobrien		    if (taken != cputaken)
826890284Sobrien		      {
826990284Sobrien			/* We use 3e (DS) prefix for taken branches and
827090284Sobrien			   2e (CS) prefix for not taken branches.  */
827190284Sobrien			if (taken)
827290284Sobrien			  fputs ("ds ; ", file);
827390284Sobrien			else
827490284Sobrien			  fputs ("cs ; ", file);
827590284Sobrien		      }
827690284Sobrien		  }
827790284Sobrien	      }
827890284Sobrien	    return;
827990284Sobrien	  }
828018334Speter	default:
8281169705Skan	    output_operand_lossage ("invalid operand code '%c'", code);
828218334Speter	}
828318334Speter    }
828451411Sobrien
828518334Speter  if (GET_CODE (x) == REG)
8286132743Skan    print_reg (x, code, file);
828751411Sobrien
828818334Speter  else if (GET_CODE (x) == MEM)
828918334Speter    {
829090284Sobrien      /* No `byte ptr' prefix for call instructions.  */
829190284Sobrien      if (ASSEMBLER_DIALECT == ASM_INTEL && code != 'X' && code != 'P')
829218334Speter	{
829390284Sobrien	  const char * size;
829490284Sobrien	  switch (GET_MODE_SIZE (GET_MODE (x)))
829590284Sobrien	    {
829690284Sobrien	    case 1: size = "BYTE"; break;
829790284Sobrien	    case 2: size = "WORD"; break;
829890284Sobrien	    case 4: size = "DWORD"; break;
829990284Sobrien	    case 8: size = "QWORD"; break;
830090284Sobrien	    case 12: size = "XWORD"; break;
830190284Sobrien	    case 16: size = "XMMWORD"; break;
830290284Sobrien	    default:
8303169705Skan	      gcc_unreachable ();
830490284Sobrien	    }
830590284Sobrien
830690284Sobrien	  /* Check for explicit size override (codes 'b', 'w' and 'k')  */
830790284Sobrien	  if (code == 'b')
830890284Sobrien	    size = "BYTE";
830990284Sobrien	  else if (code == 'w')
831090284Sobrien	    size = "WORD";
831190284Sobrien	  else if (code == 'k')
831290284Sobrien	    size = "DWORD";
831390284Sobrien
831490284Sobrien	  fputs (size, file);
831590284Sobrien	  fputs (" PTR ", file);
831618334Speter	}
831790284Sobrien
831890284Sobrien      x = XEXP (x, 0);
831990284Sobrien      /* Avoid (%rip) for call operands.  */
8320132743Skan      if (CONSTANT_ADDRESS_P (x) && code == 'P'
832190284Sobrien	       && GET_CODE (x) != CONST_INT)
832290284Sobrien	output_addr_const (file, x);
8323117408Skan      else if (this_is_asm_operands && ! address_operand (x, VOIDmode))
8324117408Skan	output_operand_lossage ("invalid constraints for operand");
832518334Speter      else
832690284Sobrien	output_address (x);
832718334Speter    }
832851411Sobrien
832918334Speter  else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == SFmode)
833018334Speter    {
833151411Sobrien      REAL_VALUE_TYPE r;
833251411Sobrien      long l;
833351411Sobrien
833418334Speter      REAL_VALUE_FROM_CONST_DOUBLE (r, x);
833518334Speter      REAL_VALUE_TO_TARGET_SINGLE (r, l);
833690284Sobrien
833790284Sobrien      if (ASSEMBLER_DIALECT == ASM_ATT)
833890284Sobrien	putc ('$', file);
8339132743Skan      fprintf (file, "0x%08lx", l);
834018334Speter    }
834151411Sobrien
8342132743Skan  /* These float cases don't actually occur as immediate operands.  */
8343132743Skan  else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == DFmode)
834418334Speter    {
834551411Sobrien      char dstr[30];
834651411Sobrien
8347117408Skan      real_to_decimal (dstr, CONST_DOUBLE_REAL_VALUE (x), sizeof (dstr), 0, 1);
834818334Speter      fprintf (file, "%s", dstr);
834918334Speter    }
835051411Sobrien
835190284Sobrien  else if (GET_CODE (x) == CONST_DOUBLE
8352132743Skan	   && GET_MODE (x) == XFmode)
835318334Speter    {
835451411Sobrien      char dstr[30];
835551411Sobrien
8356117408Skan      real_to_decimal (dstr, CONST_DOUBLE_REAL_VALUE (x), sizeof (dstr), 0, 1);
835718334Speter      fprintf (file, "%s", dstr);
835818334Speter    }
8359117408Skan
836051411Sobrien  else
836118334Speter    {
8362169705Skan      /* We have patterns that allow zero sets of memory, for instance.
8363169705Skan	 In 64-bit mode, we should probably support all 8-byte vectors,
8364169705Skan	 since we can in fact encode that into an immediate.  */
8365169705Skan      if (GET_CODE (x) == CONST_VECTOR)
8366169705Skan	{
8367169705Skan	  gcc_assert (x == CONST0_RTX (GET_MODE (x)));
8368169705Skan	  x = const0_rtx;
8369169705Skan	}
8370169705Skan
837118334Speter      if (code != 'P')
837218334Speter	{
837318334Speter	  if (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE)
837490284Sobrien	    {
837590284Sobrien	      if (ASSEMBLER_DIALECT == ASM_ATT)
837690284Sobrien		putc ('$', file);
837790284Sobrien	    }
837818334Speter	  else if (GET_CODE (x) == CONST || GET_CODE (x) == SYMBOL_REF
837918334Speter		   || GET_CODE (x) == LABEL_REF)
838090284Sobrien	    {
838190284Sobrien	      if (ASSEMBLER_DIALECT == ASM_ATT)
838290284Sobrien		putc ('$', file);
838390284Sobrien	      else
838490284Sobrien		fputs ("OFFSET FLAT:", file);
838590284Sobrien	    }
838618334Speter	}
838790284Sobrien      if (GET_CODE (x) == CONST_INT)
838890284Sobrien	fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x));
838990284Sobrien      else if (flag_pic)
839018334Speter	output_pic_addr_const (file, x, code);
839118334Speter      else
839218334Speter	output_addr_const (file, x);
839318334Speter    }
839418334Speter}
839518334Speter
839618334Speter/* Print a memory operand whose address is ADDR.  */
839718334Speter
839818334Spetervoid
8399132743Skanprint_operand_address (FILE *file, rtx addr)
840018334Speter{
840190284Sobrien  struct ix86_address parts;
840290284Sobrien  rtx base, index, disp;
840390284Sobrien  int scale;
8404169705Skan  int ok = ix86_decompose_address (addr, &parts);
840518334Speter
8406169705Skan  gcc_assert (ok);
8407117408Skan
840890284Sobrien  base = parts.base;
840990284Sobrien  index = parts.index;
841090284Sobrien  disp = parts.disp;
841190284Sobrien  scale = parts.scale;
841251411Sobrien
8413132743Skan  switch (parts.seg)
8414132743Skan    {
8415132743Skan    case SEG_DEFAULT:
8416132743Skan      break;
8417132743Skan    case SEG_FS:
8418132743Skan    case SEG_GS:
8419132743Skan      if (USER_LABEL_PREFIX[0] == 0)
8420132743Skan	putc ('%', file);
8421132743Skan      fputs ((parts.seg == SEG_FS ? "fs:" : "gs:"), file);
8422132743Skan      break;
8423132743Skan    default:
8424169705Skan      gcc_unreachable ();
8425132743Skan    }
8426132743Skan
842790284Sobrien  if (!base && !index)
842890284Sobrien    {
842990284Sobrien      /* Displacement only requires special attention.  */
843051411Sobrien
843190284Sobrien      if (GET_CODE (disp) == CONST_INT)
843218334Speter	{
8433132743Skan	  if (ASSEMBLER_DIALECT == ASM_INTEL && parts.seg == SEG_DEFAULT)
843490284Sobrien	    {
843590284Sobrien	      if (USER_LABEL_PREFIX[0] == 0)
843690284Sobrien		putc ('%', file);
843790284Sobrien	      fputs ("ds:", file);
843890284Sobrien	    }
8439132743Skan	  fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (disp));
844018334Speter	}
844190284Sobrien      else if (flag_pic)
8442132743Skan	output_pic_addr_const (file, disp, 0);
844390284Sobrien      else
8444132743Skan	output_addr_const (file, disp);
844551411Sobrien
844690284Sobrien      /* Use one byte shorter RIP relative addressing for 64bit mode.  */
8447169705Skan      if (TARGET_64BIT)
8448169705Skan	{
8449169705Skan	  if (GET_CODE (disp) == CONST
8450169705Skan	      && GET_CODE (XEXP (disp, 0)) == PLUS
8451169705Skan	      && GET_CODE (XEXP (XEXP (disp, 0), 1)) == CONST_INT)
8452169705Skan	    disp = XEXP (XEXP (disp, 0), 0);
8453169705Skan	  if (GET_CODE (disp) == LABEL_REF
8454169705Skan	      || (GET_CODE (disp) == SYMBOL_REF
8455169705Skan		  && SYMBOL_REF_TLS_MODEL (disp) == 0))
8456169705Skan	    fputs ("(%rip)", file);
8457169705Skan	}
845890284Sobrien    }
845990284Sobrien  else
846090284Sobrien    {
846190284Sobrien      if (ASSEMBLER_DIALECT == ASM_ATT)
846218334Speter	{
846390284Sobrien	  if (disp)
846490284Sobrien	    {
846590284Sobrien	      if (flag_pic)
846690284Sobrien		output_pic_addr_const (file, disp, 0);
846790284Sobrien	      else if (GET_CODE (disp) == LABEL_REF)
846890284Sobrien		output_asm_label (disp);
846990284Sobrien	      else
847090284Sobrien		output_addr_const (file, disp);
847190284Sobrien	    }
847251411Sobrien
847390284Sobrien	  putc ('(', file);
847490284Sobrien	  if (base)
8475132743Skan	    print_reg (base, 0, file);
847690284Sobrien	  if (index)
847790284Sobrien	    {
847890284Sobrien	      putc (',', file);
8479132743Skan	      print_reg (index, 0, file);
848090284Sobrien	      if (scale != 1)
848190284Sobrien		fprintf (file, ",%d", scale);
848290284Sobrien	    }
848390284Sobrien	  putc (')', file);
848418334Speter	}
848590284Sobrien      else
848618334Speter	{
848790284Sobrien	  rtx offset = NULL_RTX;
848818334Speter
848990284Sobrien	  if (disp)
849090284Sobrien	    {
849190284Sobrien	      /* Pull out the offset of a symbol; print any symbol itself.  */
849290284Sobrien	      if (GET_CODE (disp) == CONST
849390284Sobrien		  && GET_CODE (XEXP (disp, 0)) == PLUS
849490284Sobrien		  && GET_CODE (XEXP (XEXP (disp, 0), 1)) == CONST_INT)
849590284Sobrien		{
849690284Sobrien		  offset = XEXP (XEXP (disp, 0), 1);
849790284Sobrien		  disp = gen_rtx_CONST (VOIDmode,
849890284Sobrien					XEXP (XEXP (disp, 0), 0));
849990284Sobrien		}
850018334Speter
850118334Speter	      if (flag_pic)
850290284Sobrien		output_pic_addr_const (file, disp, 0);
850390284Sobrien	      else if (GET_CODE (disp) == LABEL_REF)
850490284Sobrien		output_asm_label (disp);
850590284Sobrien	      else if (GET_CODE (disp) == CONST_INT)
850690284Sobrien		offset = disp;
850718334Speter	      else
850890284Sobrien		output_addr_const (file, disp);
850918334Speter	    }
851018334Speter
851190284Sobrien	  putc ('[', file);
851290284Sobrien	  if (base)
851318334Speter	    {
8514132743Skan	      print_reg (base, 0, file);
851590284Sobrien	      if (offset)
851690284Sobrien		{
851790284Sobrien		  if (INTVAL (offset) >= 0)
851890284Sobrien		    putc ('+', file);
851990284Sobrien		  fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (offset));
852090284Sobrien		}
852118334Speter	    }
852290284Sobrien	  else if (offset)
852390284Sobrien	    fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (offset));
852490284Sobrien	  else
852590284Sobrien	    putc ('0', file);
852618334Speter
852790284Sobrien	  if (index)
852818334Speter	    {
852990284Sobrien	      putc ('+', file);
8530132743Skan	      print_reg (index, 0, file);
853190284Sobrien	      if (scale != 1)
853290284Sobrien		fprintf (file, "*%d", scale);
853318334Speter	    }
853490284Sobrien	  putc (']', file);
853518334Speter	}
853618334Speter    }
853718334Speter}
8538117408Skan
8539117408Skanbool
8540132743Skanoutput_addr_const_extra (FILE *file, rtx x)
8541117408Skan{
8542117408Skan  rtx op;
8543117408Skan
8544117408Skan  if (GET_CODE (x) != UNSPEC)
8545117408Skan    return false;
8546117408Skan
8547117408Skan  op = XVECEXP (x, 0, 0);
8548117408Skan  switch (XINT (x, 1))
8549117408Skan    {
8550117408Skan    case UNSPEC_GOTTPOFF:
8551117408Skan      output_addr_const (file, op);
8552117408Skan      /* FIXME: This might be @TPOFF in Sun ld.  */
8553117408Skan      fputs ("@GOTTPOFF", file);
8554117408Skan      break;
8555117408Skan    case UNSPEC_TPOFF:
8556117408Skan      output_addr_const (file, op);
8557117408Skan      fputs ("@TPOFF", file);
8558117408Skan      break;
8559117408Skan    case UNSPEC_NTPOFF:
8560117408Skan      output_addr_const (file, op);
8561117408Skan      if (TARGET_64BIT)
8562117408Skan	fputs ("@TPOFF", file);
8563117408Skan      else
8564117408Skan	fputs ("@NTPOFF", file);
8565117408Skan      break;
8566117408Skan    case UNSPEC_DTPOFF:
8567117408Skan      output_addr_const (file, op);
8568117408Skan      fputs ("@DTPOFF", file);
8569117408Skan      break;
8570117408Skan    case UNSPEC_GOTNTPOFF:
8571117408Skan      output_addr_const (file, op);
8572117408Skan      if (TARGET_64BIT)
8573117408Skan	fputs ("@GOTTPOFF(%rip)", file);
8574117408Skan      else
8575117408Skan	fputs ("@GOTNTPOFF", file);
8576117408Skan      break;
8577117408Skan    case UNSPEC_INDNTPOFF:
8578117408Skan      output_addr_const (file, op);
8579117408Skan      fputs ("@INDNTPOFF", file);
8580117408Skan      break;
8581117408Skan
8582117408Skan    default:
8583117408Skan      return false;
8584117408Skan    }
8585117408Skan
8586117408Skan  return true;
8587117408Skan}
858818334Speter
858990284Sobrien/* Split one or more DImode RTL references into pairs of SImode
859090284Sobrien   references.  The RTL can be REG, offsettable MEM, integer constant, or
859190284Sobrien   CONST_DOUBLE.  "operands" is a pointer to an array of DImode RTL to
859290284Sobrien   split and "num" is its length.  lo_half and hi_half are output arrays
859390284Sobrien   that parallel "operands".  */
859418334Speter
859518334Spetervoid
8596132743Skansplit_di (rtx operands[], int num, rtx lo_half[], rtx hi_half[])
859718334Speter{
859890284Sobrien  while (num--)
859918334Speter    {
860090284Sobrien      rtx op = operands[num];
860151411Sobrien
860290284Sobrien      /* simplify_subreg refuse to split volatile memory addresses,
860390284Sobrien         but we still have to handle it.  */
860490284Sobrien      if (GET_CODE (op) == MEM)
860518334Speter	{
860690284Sobrien	  lo_half[num] = adjust_address (op, SImode, 0);
860790284Sobrien	  hi_half[num] = adjust_address (op, SImode, 4);
860818334Speter	}
860918334Speter      else
861018334Speter	{
861190284Sobrien	  lo_half[num] = simplify_gen_subreg (SImode, op,
861290284Sobrien					      GET_MODE (op) == VOIDmode
861390284Sobrien					      ? DImode : GET_MODE (op), 0);
861490284Sobrien	  hi_half[num] = simplify_gen_subreg (SImode, op,
861590284Sobrien					      GET_MODE (op) == VOIDmode
861690284Sobrien					      ? DImode : GET_MODE (op), 4);
861718334Speter	}
861818334Speter    }
861918334Speter}
8620169705Skan/* Split one or more TImode RTL references into pairs of DImode
862118334Speter   references.  The RTL can be REG, offsettable MEM, integer constant, or
862218334Speter   CONST_DOUBLE.  "operands" is a pointer to an array of DImode RTL to
862318334Speter   split and "num" is its length.  lo_half and hi_half are output arrays
862490284Sobrien   that parallel "operands".  */
862518334Speter
862618334Spetervoid
8627132743Skansplit_ti (rtx operands[], int num, rtx lo_half[], rtx hi_half[])
862818334Speter{
862918334Speter  while (num--)
863018334Speter    {
863151411Sobrien      rtx op = operands[num];
863290284Sobrien
863390284Sobrien      /* simplify_subreg refuse to split volatile memory addresses, but we
863490284Sobrien         still have to handle it.  */
863590284Sobrien      if (GET_CODE (op) == MEM)
863618334Speter	{
863790284Sobrien	  lo_half[num] = adjust_address (op, DImode, 0);
863890284Sobrien	  hi_half[num] = adjust_address (op, DImode, 8);
863952294Sobrien	}
864090284Sobrien      else
864152294Sobrien	{
864290284Sobrien	  lo_half[num] = simplify_gen_subreg (DImode, op, TImode, 0);
864390284Sobrien	  hi_half[num] = simplify_gen_subreg (DImode, op, TImode, 8);
864418334Speter	}
864518334Speter    }
864618334Speter}
864718334Speter
864818334Speter/* Output code to perform a 387 binary operation in INSN, one of PLUS,
864918334Speter   MINUS, MULT or DIV.  OPERANDS are the insn operands, where operands[3]
865018334Speter   is the expression of the binary operation.  The output may either be
865118334Speter   emitted here, or returned to the caller, like all output_* functions.
865218334Speter
865318334Speter   There is no guarantee that the operands are the same mode, as they
865490284Sobrien   might be within FLOAT or FLOAT_EXTEND expressions.  */
865518334Speter
865690284Sobrien#ifndef SYSV386_COMPAT
865790284Sobrien/* Set to 1 for compatibility with brain-damaged assemblers.  No-one
865890284Sobrien   wants to fix the assemblers because that causes incompatibility
865990284Sobrien   with gcc.  No-one wants to fix gcc because that causes
866090284Sobrien   incompatibility with assemblers...  You can use the option of
866190284Sobrien   -DSYSV386_COMPAT=0 if you recompile both gcc and gas this way.  */
866290284Sobrien#define SYSV386_COMPAT 1
866390284Sobrien#endif
866490284Sobrien
866590284Sobrienconst char *
8666132743Skanoutput_387_binary_op (rtx insn, rtx *operands)
866718334Speter{
866890284Sobrien  static char buf[30];
866990284Sobrien  const char *p;
867090284Sobrien  const char *ssep;
8671169705Skan  int is_sse = SSE_REG_P (operands[0]) || SSE_REG_P (operands[1]) || SSE_REG_P (operands[2]);
867218334Speter
867390284Sobrien#ifdef ENABLE_CHECKING
867490284Sobrien  /* Even if we do not want to check the inputs, this documents input
867590284Sobrien     constraints.  Which helps in understanding the following code.  */
867690284Sobrien  if (STACK_REG_P (operands[0])
867790284Sobrien      && ((REG_P (operands[1])
867890284Sobrien	   && REGNO (operands[0]) == REGNO (operands[1])
867990284Sobrien	   && (STACK_REG_P (operands[2]) || GET_CODE (operands[2]) == MEM))
868090284Sobrien	  || (REG_P (operands[2])
868190284Sobrien	      && REGNO (operands[0]) == REGNO (operands[2])
868290284Sobrien	      && (STACK_REG_P (operands[1]) || GET_CODE (operands[1]) == MEM)))
868390284Sobrien      && (STACK_TOP_P (operands[1]) || STACK_TOP_P (operands[2])))
868490284Sobrien    ; /* ok */
8685169705Skan  else
8686169705Skan    gcc_assert (is_sse);
868790284Sobrien#endif
868890284Sobrien
868918334Speter  switch (GET_CODE (operands[3]))
869018334Speter    {
869118334Speter    case PLUS:
869290284Sobrien      if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT
869390284Sobrien	  || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT)
869490284Sobrien	p = "fiadd";
869590284Sobrien      else
869690284Sobrien	p = "fadd";
869790284Sobrien      ssep = "add";
869818334Speter      break;
869918334Speter
870018334Speter    case MINUS:
870190284Sobrien      if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT
870290284Sobrien	  || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT)
870390284Sobrien	p = "fisub";
870490284Sobrien      else
870590284Sobrien	p = "fsub";
870690284Sobrien      ssep = "sub";
870718334Speter      break;
870818334Speter
870918334Speter    case MULT:
871090284Sobrien      if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT
871190284Sobrien	  || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT)
871290284Sobrien	p = "fimul";
871390284Sobrien      else
871490284Sobrien	p = "fmul";
871590284Sobrien      ssep = "mul";
871618334Speter      break;
871718334Speter
871818334Speter    case DIV:
871990284Sobrien      if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT
872090284Sobrien	  || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT)
872190284Sobrien	p = "fidiv";
872290284Sobrien      else
872390284Sobrien	p = "fdiv";
872490284Sobrien      ssep = "div";
872518334Speter      break;
872618334Speter
872718334Speter    default:
8728169705Skan      gcc_unreachable ();
872918334Speter    }
873018334Speter
873190284Sobrien  if (is_sse)
873290284Sobrien   {
873390284Sobrien      strcpy (buf, ssep);
873490284Sobrien      if (GET_MODE (operands[0]) == SFmode)
873590284Sobrien	strcat (buf, "ss\t{%2, %0|%0, %2}");
873690284Sobrien      else
873790284Sobrien	strcat (buf, "sd\t{%2, %0|%0, %2}");
873890284Sobrien      return buf;
873990284Sobrien   }
874090284Sobrien  strcpy (buf, p);
874118334Speter
874218334Speter  switch (GET_CODE (operands[3]))
874318334Speter    {
874418334Speter    case MULT:
874518334Speter    case PLUS:
874618334Speter      if (REG_P (operands[2]) && REGNO (operands[0]) == REGNO (operands[2]))
874718334Speter	{
874890284Sobrien	  rtx temp = operands[2];
874918334Speter	  operands[2] = operands[1];
875018334Speter	  operands[1] = temp;
875118334Speter	}
875218334Speter
875390284Sobrien      /* know operands[0] == operands[1].  */
875490284Sobrien
875518334Speter      if (GET_CODE (operands[2]) == MEM)
875690284Sobrien	{
875790284Sobrien	  p = "%z2\t%2";
875890284Sobrien	  break;
875990284Sobrien	}
876018334Speter
876118334Speter      if (find_regno_note (insn, REG_DEAD, REGNO (operands[2])))
876251411Sobrien	{
876351411Sobrien	  if (STACK_TOP_P (operands[0]))
876490284Sobrien	    /* How is it that we are storing to a dead operand[2]?
876590284Sobrien	       Well, presumably operands[1] is dead too.  We can't
876690284Sobrien	       store the result to st(0) as st(0) gets popped on this
876790284Sobrien	       instruction.  Instead store to operands[2] (which I
876890284Sobrien	       think has to be st(1)).  st(1) will be popped later.
876990284Sobrien	       gcc <= 2.8.1 didn't have this check and generated
877090284Sobrien	       assembly code that the Unixware assembler rejected.  */
877190284Sobrien	    p = "p\t{%0, %2|%2, %0}";	/* st(1) = st(0) op st(1); pop */
877251411Sobrien	  else
877390284Sobrien	    p = "p\t{%2, %0|%0, %2}";	/* st(r1) = st(r1) op st(0); pop */
877490284Sobrien	  break;
877551411Sobrien	}
877618334Speter
877718334Speter      if (STACK_TOP_P (operands[0]))
877890284Sobrien	p = "\t{%y2, %0|%0, %y2}";	/* st(0) = st(0) op st(r2) */
877918334Speter      else
878090284Sobrien	p = "\t{%2, %0|%0, %2}";	/* st(r1) = st(r1) op st(0) */
878190284Sobrien      break;
878218334Speter
878318334Speter    case MINUS:
878418334Speter    case DIV:
878518334Speter      if (GET_CODE (operands[1]) == MEM)
878690284Sobrien	{
878790284Sobrien	  p = "r%z1\t%1";
878890284Sobrien	  break;
878990284Sobrien	}
879018334Speter
879118334Speter      if (GET_CODE (operands[2]) == MEM)
879290284Sobrien	{
879390284Sobrien	  p = "%z2\t%2";
879490284Sobrien	  break;
879590284Sobrien	}
879618334Speter
879718334Speter      if (find_regno_note (insn, REG_DEAD, REGNO (operands[2])))
879851411Sobrien	{
879990284Sobrien#if SYSV386_COMPAT
880090284Sobrien	  /* The SystemV/386 SVR3.2 assembler, and probably all AT&T
880190284Sobrien	     derived assemblers, confusingly reverse the direction of
880290284Sobrien	     the operation for fsub{r} and fdiv{r} when the
880390284Sobrien	     destination register is not st(0).  The Intel assembler
880490284Sobrien	     doesn't have this brain damage.  Read !SYSV386_COMPAT to
880590284Sobrien	     figure out what the hardware really does.  */
880651411Sobrien	  if (STACK_TOP_P (operands[0]))
880790284Sobrien	    p = "{p\t%0, %2|rp\t%2, %0}";
880851411Sobrien	  else
880990284Sobrien	    p = "{rp\t%2, %0|p\t%0, %2}";
881090284Sobrien#else
881190284Sobrien	  if (STACK_TOP_P (operands[0]))
881290284Sobrien	    /* As above for fmul/fadd, we can't store to st(0).  */
881390284Sobrien	    p = "rp\t{%0, %2|%2, %0}";	/* st(1) = st(0) op st(1); pop */
881490284Sobrien	  else
881590284Sobrien	    p = "p\t{%2, %0|%0, %2}";	/* st(r1) = st(r1) op st(0); pop */
881690284Sobrien#endif
881790284Sobrien	  break;
881851411Sobrien	}
881918334Speter
882018334Speter      if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
882151411Sobrien	{
882290284Sobrien#if SYSV386_COMPAT
882351411Sobrien	  if (STACK_TOP_P (operands[0]))
882490284Sobrien	    p = "{rp\t%0, %1|p\t%1, %0}";
882551411Sobrien	  else
882690284Sobrien	    p = "{p\t%1, %0|rp\t%0, %1}";
882790284Sobrien#else
882890284Sobrien	  if (STACK_TOP_P (operands[0]))
882990284Sobrien	    p = "p\t{%0, %1|%1, %0}";	/* st(1) = st(1) op st(0); pop */
883090284Sobrien	  else
883190284Sobrien	    p = "rp\t{%1, %0|%0, %1}";	/* st(r2) = st(0) op st(r2); pop */
883290284Sobrien#endif
883390284Sobrien	  break;
883451411Sobrien	}
883518334Speter
883618334Speter      if (STACK_TOP_P (operands[0]))
883718334Speter	{
883818334Speter	  if (STACK_TOP_P (operands[1]))
883990284Sobrien	    p = "\t{%y2, %0|%0, %y2}";	/* st(0) = st(0) op st(r2) */
884018334Speter	  else
884190284Sobrien	    p = "r\t{%y1, %0|%0, %y1}";	/* st(0) = st(r1) op st(0) */
884290284Sobrien	  break;
884318334Speter	}
884418334Speter      else if (STACK_TOP_P (operands[1]))
884590284Sobrien	{
884690284Sobrien#if SYSV386_COMPAT
884790284Sobrien	  p = "{\t%1, %0|r\t%0, %1}";
884890284Sobrien#else
884990284Sobrien	  p = "r\t{%1, %0|%0, %1}";	/* st(r2) = st(0) op st(r2) */
885090284Sobrien#endif
885190284Sobrien	}
885218334Speter      else
885390284Sobrien	{
885490284Sobrien#if SYSV386_COMPAT
885590284Sobrien	  p = "{r\t%2, %0|\t%0, %2}";
885690284Sobrien#else
885790284Sobrien	  p = "\t{%2, %0|%0, %2}";	/* st(r1) = st(r1) op st(0) */
885890284Sobrien#endif
885990284Sobrien	}
886090284Sobrien      break;
886118334Speter
886218334Speter    default:
8863169705Skan      gcc_unreachable ();
886418334Speter    }
886590284Sobrien
886690284Sobrien  strcat (buf, p);
886790284Sobrien  return buf;
886818334Speter}
886990284Sobrien
8870169705Skan/* Return needed mode for entity in optimize_mode_switching pass.  */
8871169705Skan
8872169705Skanint
8873169705Skanix86_mode_needed (int entity, rtx insn)
8874169705Skan{
8875169705Skan  enum attr_i387_cw mode;
8876169705Skan
8877169705Skan  /* The mode UNINITIALIZED is used to store control word after a
8878169705Skan     function call or ASM pattern.  The mode ANY specify that function
8879169705Skan     has no requirements on the control word and make no changes in the
8880169705Skan     bits we are interested in.  */
8881169705Skan
8882169705Skan  if (CALL_P (insn)
8883169705Skan      || (NONJUMP_INSN_P (insn)
8884169705Skan	  && (asm_noperands (PATTERN (insn)) >= 0
8885169705Skan	      || GET_CODE (PATTERN (insn)) == ASM_INPUT)))
8886169705Skan    return I387_CW_UNINITIALIZED;
8887169705Skan
8888169705Skan  if (recog_memoized (insn) < 0)
8889169705Skan    return I387_CW_ANY;
8890169705Skan
8891169705Skan  mode = get_attr_i387_cw (insn);
8892169705Skan
8893169705Skan  switch (entity)
8894169705Skan    {
8895169705Skan    case I387_TRUNC:
8896169705Skan      if (mode == I387_CW_TRUNC)
8897169705Skan	return mode;
8898169705Skan      break;
8899169705Skan
8900169705Skan    case I387_FLOOR:
8901169705Skan      if (mode == I387_CW_FLOOR)
8902169705Skan	return mode;
8903169705Skan      break;
8904169705Skan
8905169705Skan    case I387_CEIL:
8906169705Skan      if (mode == I387_CW_CEIL)
8907169705Skan	return mode;
8908169705Skan      break;
8909169705Skan
8910169705Skan    case I387_MASK_PM:
8911169705Skan      if (mode == I387_CW_MASK_PM)
8912169705Skan	return mode;
8913169705Skan      break;
8914169705Skan
8915169705Skan    default:
8916169705Skan      gcc_unreachable ();
8917169705Skan    }
8918169705Skan
8919169705Skan  return I387_CW_ANY;
8920169705Skan}
8921169705Skan
8922169705Skan/* Output code to initialize control word copies used by trunc?f?i and
8923169705Skan   rounding patterns.  CURRENT_MODE is set to current control word,
8924169705Skan   while NEW_MODE is set to new control word.  */
8925169705Skan
892690284Sobrienvoid
8927169705Skanemit_i387_cw_initialization (int mode)
892890284Sobrien{
8929169705Skan  rtx stored_mode = assign_386_stack_local (HImode, SLOT_CW_STORED);
8930169705Skan  rtx new_mode;
8931169705Skan
8932169705Skan  int slot;
8933169705Skan
893490284Sobrien  rtx reg = gen_reg_rtx (HImode);
893590284Sobrien
8936169705Skan  emit_insn (gen_x86_fnstcw_1 (stored_mode));
8937169705Skan  emit_move_insn (reg, stored_mode);
8938169705Skan
8939169705Skan  if (TARGET_64BIT || TARGET_PARTIAL_REG_STALL || optimize_size)
8940169705Skan    {
8941169705Skan      switch (mode)
8942169705Skan	{
8943169705Skan	case I387_CW_TRUNC:
8944169705Skan	  /* round toward zero (truncate) */
8945169705Skan	  emit_insn (gen_iorhi3 (reg, reg, GEN_INT (0x0c00)));
8946169705Skan	  slot = SLOT_CW_TRUNC;
8947169705Skan	  break;
8948169705Skan
8949169705Skan	case I387_CW_FLOOR:
8950169705Skan	  /* round down toward -oo */
8951169705Skan	  emit_insn (gen_andhi3 (reg, reg, GEN_INT (~0x0c00)));
8952169705Skan	  emit_insn (gen_iorhi3 (reg, reg, GEN_INT (0x0400)));
8953169705Skan	  slot = SLOT_CW_FLOOR;
8954169705Skan	  break;
8955169705Skan
8956169705Skan	case I387_CW_CEIL:
8957169705Skan	  /* round up toward +oo */
8958169705Skan	  emit_insn (gen_andhi3 (reg, reg, GEN_INT (~0x0c00)));
8959169705Skan	  emit_insn (gen_iorhi3 (reg, reg, GEN_INT (0x0800)));
8960169705Skan	  slot = SLOT_CW_CEIL;
8961169705Skan	  break;
8962169705Skan
8963169705Skan	case I387_CW_MASK_PM:
8964169705Skan	  /* mask precision exception for nearbyint() */
8965169705Skan	  emit_insn (gen_iorhi3 (reg, reg, GEN_INT (0x0020)));
8966169705Skan	  slot = SLOT_CW_MASK_PM;
8967169705Skan	  break;
8968169705Skan
8969169705Skan	default:
8970169705Skan	  gcc_unreachable ();
8971169705Skan	}
8972169705Skan    }
897390284Sobrien  else
8974169705Skan    {
8975169705Skan      switch (mode)
8976169705Skan	{
8977169705Skan	case I387_CW_TRUNC:
8978169705Skan	  /* round toward zero (truncate) */
8979169705Skan	  emit_insn (gen_movsi_insv_1 (reg, GEN_INT (0xc)));
8980169705Skan	  slot = SLOT_CW_TRUNC;
8981169705Skan	  break;
8982169705Skan
8983169705Skan	case I387_CW_FLOOR:
8984169705Skan	  /* round down toward -oo */
8985169705Skan	  emit_insn (gen_movsi_insv_1 (reg, GEN_INT (0x4)));
8986169705Skan	  slot = SLOT_CW_FLOOR;
8987169705Skan	  break;
8988169705Skan
8989169705Skan	case I387_CW_CEIL:
8990169705Skan	  /* round up toward +oo */
8991169705Skan	  emit_insn (gen_movsi_insv_1 (reg, GEN_INT (0x8)));
8992169705Skan	  slot = SLOT_CW_CEIL;
8993169705Skan	  break;
8994169705Skan
8995169705Skan	case I387_CW_MASK_PM:
8996169705Skan	  /* mask precision exception for nearbyint() */
8997169705Skan	  emit_insn (gen_iorhi3 (reg, reg, GEN_INT (0x0020)));
8998169705Skan	  slot = SLOT_CW_MASK_PM;
8999169705Skan	  break;
9000169705Skan
9001169705Skan	default:
9002169705Skan	  gcc_unreachable ();
9003169705Skan	}
9004169705Skan    }
9005169705Skan
9006169705Skan  gcc_assert (slot < MAX_386_STACK_LOCALS);
9007169705Skan
9008169705Skan  new_mode = assign_386_stack_local (HImode, slot);
9009169705Skan  emit_move_insn (new_mode, reg);
901090284Sobrien}
901190284Sobrien
901218334Speter/* Output code for INSN to convert a float to a signed int.  OPERANDS
901390284Sobrien   are the insn operands.  The output may be [HSD]Imode and the input
901490284Sobrien   operand may be [SDX]Fmode.  */
901518334Speter
901690284Sobrienconst char *
9017169705Skanoutput_fix_trunc (rtx insn, rtx *operands, int fisttp)
901818334Speter{
901918334Speter  int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
902090284Sobrien  int dimode_p = GET_MODE (operands[0]) == DImode;
9021169705Skan  int round_mode = get_attr_i387_cw (insn);
902218334Speter
902390284Sobrien  /* Jump through a hoop or two for DImode, since the hardware has no
902490284Sobrien     non-popping instruction.  We used to do this a different way, but
902590284Sobrien     that was somewhat fragile and broke with post-reload splitters.  */
9026169705Skan  if ((dimode_p || fisttp) && !stack_top_dies)
902790284Sobrien    output_asm_insn ("fld\t%y1", operands);
902890284Sobrien
9029169705Skan  gcc_assert (STACK_TOP_P (operands[1]));
9030169705Skan  gcc_assert (GET_CODE (operands[0]) == MEM);
903118334Speter
9032169705Skan  if (fisttp)
9033169705Skan      output_asm_insn ("fisttp%z0\t%0", operands);
903490284Sobrien  else
9035169705Skan    {
9036169705Skan      if (round_mode != I387_CW_ANY)
9037169705Skan	output_asm_insn ("fldcw\t%3", operands);
9038169705Skan      if (stack_top_dies || dimode_p)
9039169705Skan	output_asm_insn ("fistp%z0\t%0", operands);
9040169705Skan      else
9041169705Skan	output_asm_insn ("fist%z0\t%0", operands);
9042169705Skan      if (round_mode != I387_CW_ANY)
9043169705Skan	output_asm_insn ("fldcw\t%2", operands);
9044169705Skan    }
904552294Sobrien
904690284Sobrien  return "";
904790284Sobrien}
904818334Speter
9049169705Skan/* Output code for x87 ffreep insn.  The OPNO argument, which may only
9050169705Skan   have the values zero or one, indicates the ffreep insn's operand
9051169705Skan   from the OPERANDS array.  */
9052169705Skan
9053169705Skanstatic const char *
9054169705Skanoutput_387_ffreep (rtx *operands ATTRIBUTE_UNUSED, int opno)
9055169705Skan{
9056169705Skan  if (TARGET_USE_FFREEP)
9057169705Skan#if HAVE_AS_IX86_FFREEP
9058169705Skan    return opno ? "ffreep\t%y1" : "ffreep\t%y0";
9059169705Skan#else
9060237021Spfg    switch (REGNO (operands[opno]))
9061237021Spfg      {
9062237021Spfg      case FIRST_STACK_REG + 0: return ".word\t0xc0df";
9063237021Spfg      case FIRST_STACK_REG + 1: return ".word\t0xc1df";
9064237021Spfg      case FIRST_STACK_REG + 2: return ".word\t0xc2df";
9065237021Spfg      case FIRST_STACK_REG + 3: return ".word\t0xc3df";
9066237021Spfg      case FIRST_STACK_REG + 4: return ".word\t0xc4df";
9067237021Spfg      case FIRST_STACK_REG + 5: return ".word\t0xc5df";
9068237021Spfg      case FIRST_STACK_REG + 6: return ".word\t0xc6df";
9069237021Spfg      case FIRST_STACK_REG + 7: return ".word\t0xc7df";
9070237021Spfg      }
9071169705Skan#endif
9072169705Skan
9073169705Skan  return opno ? "fstp\t%y1" : "fstp\t%y0";
9074169705Skan}
9075169705Skan
9076169705Skan
907790284Sobrien/* Output code for INSN to compare OPERANDS.  EFLAGS_P is 1 when fcomi
9078169705Skan   should be used.  UNORDERED_P is true when fucom should be used.  */
907952294Sobrien
908090284Sobrienconst char *
9081132743Skanoutput_fp_compare (rtx insn, rtx *operands, int eflags_p, int unordered_p)
908290284Sobrien{
908390284Sobrien  int stack_top_dies;
9084169705Skan  rtx cmp_op0, cmp_op1;
9085169705Skan  int is_sse = SSE_REG_P (operands[0]) || SSE_REG_P (operands[1]);
908652294Sobrien
9087169705Skan  if (eflags_p)
908852294Sobrien    {
9089169705Skan      cmp_op0 = operands[0];
9090169705Skan      cmp_op1 = operands[1];
9091169705Skan    }
9092169705Skan  else
9093169705Skan    {
9094169705Skan      cmp_op0 = operands[1];
909590284Sobrien      cmp_op1 = operands[2];
909690284Sobrien    }
9097169705Skan
909890284Sobrien  if (is_sse)
909990284Sobrien    {
910090284Sobrien      if (GET_MODE (operands[0]) == SFmode)
910190284Sobrien	if (unordered_p)
910290284Sobrien	  return "ucomiss\t{%1, %0|%0, %1}";
910390284Sobrien	else
9104117408Skan	  return "comiss\t{%1, %0|%0, %1}";
910552294Sobrien      else
910690284Sobrien	if (unordered_p)
910790284Sobrien	  return "ucomisd\t{%1, %0|%0, %1}";
910890284Sobrien	else
9109117408Skan	  return "comisd\t{%1, %0|%0, %1}";
911090284Sobrien    }
911190284Sobrien
9112169705Skan  gcc_assert (STACK_TOP_P (cmp_op0));
911390284Sobrien
911490284Sobrien  stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
911590284Sobrien
9116169705Skan  if (cmp_op1 == CONST0_RTX (GET_MODE (cmp_op1)))
9117169705Skan    {
9118169705Skan      if (stack_top_dies)
9119169705Skan	{
9120169705Skan	  output_asm_insn ("ftst\n\tfnstsw\t%0", operands);
9121169705Skan	  return output_387_ffreep (operands, 1);
9122169705Skan	}
9123169705Skan      else
9124169705Skan	return "ftst\n\tfnstsw\t%0";
9125169705Skan    }
9126169705Skan
912790284Sobrien  if (STACK_REG_P (cmp_op1)
912890284Sobrien      && stack_top_dies
912990284Sobrien      && find_regno_note (insn, REG_DEAD, REGNO (cmp_op1))
913090284Sobrien      && REGNO (cmp_op1) != FIRST_STACK_REG)
913190284Sobrien    {
913290284Sobrien      /* If both the top of the 387 stack dies, and the other operand
913390284Sobrien	 is also a stack register that dies, then this must be a
913490284Sobrien	 `fcompp' float compare */
913590284Sobrien
9136169705Skan      if (eflags_p)
913752294Sobrien	{
913890284Sobrien	  /* There is no double popping fcomi variant.  Fortunately,
913990284Sobrien	     eflags is immune from the fstp's cc clobbering.  */
914090284Sobrien	  if (unordered_p)
914190284Sobrien	    output_asm_insn ("fucomip\t{%y1, %0|%0, %y1}", operands);
914290284Sobrien	  else
914390284Sobrien	    output_asm_insn ("fcomip\t{%y1, %0|%0, %y1}", operands);
9144169705Skan	  return output_387_ffreep (operands, 0);
914552294Sobrien	}
914690284Sobrien      else
914790284Sobrien	{
9148169705Skan	  if (unordered_p)
9149169705Skan	    return "fucompp\n\tfnstsw\t%0";
915090284Sobrien	  else
9151169705Skan	    return "fcompp\n\tfnstsw\t%0";
915290284Sobrien	}
915352294Sobrien    }
915490284Sobrien  else
915590284Sobrien    {
915690284Sobrien      /* Encoded here as eflags_p | intmode | unordered_p | stack_top_dies.  */
915751411Sobrien
9158169705Skan      static const char * const alt[16] =
915990284Sobrien      {
9160169705Skan	"fcom%z2\t%y2\n\tfnstsw\t%0",
9161169705Skan	"fcomp%z2\t%y2\n\tfnstsw\t%0",
9162169705Skan	"fucom%z2\t%y2\n\tfnstsw\t%0",
9163169705Skan	"fucomp%z2\t%y2\n\tfnstsw\t%0",
916490284Sobrien
9165169705Skan	"ficom%z2\t%y2\n\tfnstsw\t%0",
9166169705Skan	"ficomp%z2\t%y2\n\tfnstsw\t%0",
916790284Sobrien	NULL,
916890284Sobrien	NULL,
916990284Sobrien
917090284Sobrien	"fcomi\t{%y1, %0|%0, %y1}",
917190284Sobrien	"fcomip\t{%y1, %0|%0, %y1}",
917290284Sobrien	"fucomi\t{%y1, %0|%0, %y1}",
917390284Sobrien	"fucomip\t{%y1, %0|%0, %y1}",
917490284Sobrien
917590284Sobrien	NULL,
917690284Sobrien	NULL,
917790284Sobrien	NULL,
917890284Sobrien	NULL
917990284Sobrien      };
918090284Sobrien
918190284Sobrien      int mask;
918290284Sobrien      const char *ret;
918390284Sobrien
918490284Sobrien      mask  = eflags_p << 3;
9185169705Skan      mask |= (GET_MODE_CLASS (GET_MODE (cmp_op1)) == MODE_INT) << 2;
918690284Sobrien      mask |= unordered_p << 1;
918790284Sobrien      mask |= stack_top_dies;
918890284Sobrien
9189169705Skan      gcc_assert (mask < 16);
919090284Sobrien      ret = alt[mask];
9191169705Skan      gcc_assert (ret);
919290284Sobrien
919390284Sobrien      return ret;
919490284Sobrien    }
919552294Sobrien}
919690284Sobrien
919790284Sobrienvoid
9198132743Skanix86_output_addr_vec_elt (FILE *file, int value)
919990284Sobrien{
920090284Sobrien  const char *directive = ASM_LONG;
920190284Sobrien
9202169705Skan#ifdef ASM_QUAD
920390284Sobrien  if (TARGET_64BIT)
9204169705Skan    directive = ASM_QUAD;
920590284Sobrien#else
9206169705Skan  gcc_assert (!TARGET_64BIT);
920790284Sobrien#endif
920890284Sobrien
920990284Sobrien  fprintf (file, "%s%s%d\n", directive, LPREFIX, value);
921090284Sobrien}
921190284Sobrien
921290284Sobrienvoid
9213132743Skanix86_output_addr_diff_elt (FILE *file, int value, int rel)
921490284Sobrien{
921590284Sobrien  if (TARGET_64BIT)
9216117408Skan    fprintf (file, "%s%s%d-%s%d\n",
921790284Sobrien	     ASM_LONG, LPREFIX, value, LPREFIX, rel);
921890284Sobrien  else if (HAVE_AS_GOTOFF_IN_DATA)
921990284Sobrien    fprintf (file, "%s%s%d@GOTOFF\n", ASM_LONG, LPREFIX, value);
9220117408Skan#if TARGET_MACHO
9221117408Skan  else if (TARGET_MACHO)
9222132743Skan    {
9223132743Skan      fprintf (file, "%s%s%d-", ASM_LONG, LPREFIX, value);
9224132743Skan      machopic_output_function_base_name (file);
9225132743Skan      fprintf(file, "\n");
9226132743Skan    }
9227117408Skan#endif
922890284Sobrien  else
9229117408Skan    asm_fprintf (file, "%s%U%s+[.-%s%d]\n",
9230117408Skan		 ASM_LONG, GOT_SYMBOL_NAME, LPREFIX, value);
923190284Sobrien}
923252294Sobrien
923390284Sobrien/* Generate either "mov $0, reg" or "xor reg, reg", as appropriate
923490284Sobrien   for the target.  */
923552294Sobrien
923652294Sobrienvoid
9237132743Skanix86_expand_clear (rtx dest)
923852294Sobrien{
923990284Sobrien  rtx tmp;
924052294Sobrien
924190284Sobrien  /* We play register width games, which are only valid after reload.  */
9242169705Skan  gcc_assert (reload_completed);
924352294Sobrien
924490284Sobrien  /* Avoid HImode and its attendant prefix byte.  */
924590284Sobrien  if (GET_MODE_SIZE (GET_MODE (dest)) < 4)
924690284Sobrien    dest = gen_rtx_REG (SImode, REGNO (dest));
924752294Sobrien
924890284Sobrien  tmp = gen_rtx_SET (VOIDmode, dest, const0_rtx);
924990284Sobrien
925090284Sobrien  /* This predicate should match that for movsi_xor and movdi_xor_rex64.  */
925190284Sobrien  if (reload_completed && (!TARGET_USE_MOV0 || optimize_size))
925218334Speter    {
925390284Sobrien      rtx clob = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, 17));
925490284Sobrien      tmp = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, tmp, clob));
925590284Sobrien    }
925690284Sobrien
925790284Sobrien  emit_insn (tmp);
925890284Sobrien}
925990284Sobrien
9260117408Skan/* X is an unchanging MEM.  If it is a constant pool reference, return
9261117408Skan   the constant pool rtx, else NULL.  */
9262117408Skan
9263169705Skanrtx
9264132743Skanmaybe_get_pool_constant (rtx x)
9265117408Skan{
9266132743Skan  x = ix86_delegitimize_address (XEXP (x, 0));
9267117408Skan
9268117408Skan  if (GET_CODE (x) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (x))
9269117408Skan    return get_pool_constant (x);
9270117408Skan
9271117408Skan  return NULL_RTX;
9272117408Skan}
9273117408Skan
927490284Sobrienvoid
9275132743Skanix86_expand_move (enum machine_mode mode, rtx operands[])
927690284Sobrien{
927790284Sobrien  int strict = (reload_in_progress || reload_completed);
9278132743Skan  rtx op0, op1;
9279132743Skan  enum tls_model model;
928090284Sobrien
9281117408Skan  op0 = operands[0];
9282117408Skan  op1 = operands[1];
9283117408Skan
9284169705Skan  if (GET_CODE (op1) == SYMBOL_REF)
928590284Sobrien    {
9286169705Skan      model = SYMBOL_REF_TLS_MODEL (op1);
9287169705Skan      if (model)
9288169705Skan	{
9289169705Skan	  op1 = legitimize_tls_address (op1, model, true);
9290169705Skan	  op1 = force_operand (op1, op0);
9291169705Skan	  if (op1 == op0)
9292169705Skan	    return;
9293169705Skan	}
9294117408Skan    }
9295169705Skan  else if (GET_CODE (op1) == CONST
9296169705Skan	   && GET_CODE (XEXP (op1, 0)) == PLUS
9297169705Skan	   && GET_CODE (XEXP (XEXP (op1, 0), 0)) == SYMBOL_REF)
9298169705Skan    {
9299169705Skan      model = SYMBOL_REF_TLS_MODEL (XEXP (XEXP (op1, 0), 0));
9300169705Skan      if (model)
9301169705Skan	{
9302169705Skan	  rtx addend = XEXP (XEXP (op1, 0), 1);
9303169705Skan	  op1 = legitimize_tls_address (XEXP (XEXP (op1, 0), 0), model, true);
9304169705Skan	  op1 = force_operand (op1, NULL);
9305169705Skan	  op1 = expand_simple_binop (Pmode, PLUS, op1, addend,
9306169705Skan				     op0, 1, OPTAB_DIRECT);
9307169705Skan	  if (op1 == op0)
9308169705Skan	    return;
9309169705Skan	}
9310169705Skan    }
9311132743Skan
9312132743Skan  if (flag_pic && mode == Pmode && symbolic_operand (op1, Pmode))
9313117408Skan    {
9314169705Skan      if (TARGET_MACHO && !TARGET_64BIT)
9315169705Skan	{
9316117408Skan#if TARGET_MACHO
9317169705Skan	  if (MACHOPIC_PURE)
9318169705Skan	    {
9319169705Skan	      rtx temp = ((reload_in_progress
9320169705Skan			   || ((op0 && GET_CODE (op0) == REG)
9321169705Skan			       && mode == Pmode))
9322169705Skan			  ? op0 : gen_reg_rtx (Pmode));
9323169705Skan	      op1 = machopic_indirect_data_reference (op1, temp);
9324169705Skan	      op1 = machopic_legitimize_pic_address (op1, mode,
9325169705Skan						     temp == op1 ? 0 : temp);
9326169705Skan	    }
9327169705Skan	  else if (MACHOPIC_INDIRECT)
9328169705Skan	    op1 = machopic_indirect_data_reference (op1, 0);
9329169705Skan	  if (op0 == op1)
9330169705Skan	    return;
9331169705Skan#endif
9332117408Skan	}
9333117408Skan      else
9334117408Skan	{
9335169705Skan	  if (GET_CODE (op0) == MEM)
9336169705Skan	    op1 = force_reg (Pmode, op1);
9337169705Skan	  else
9338169705Skan	    op1 = legitimize_address (op1, op1, Pmode);
933951411Sobrien	}
934018334Speter    }
934118334Speter  else
934252294Sobrien    {
9343117408Skan      if (GET_CODE (op0) == MEM
934490284Sobrien	  && (PUSH_ROUNDING (GET_MODE_SIZE (mode)) != GET_MODE_SIZE (mode)
9345117408Skan	      || !push_operand (op0, mode))
9346117408Skan	  && GET_CODE (op1) == MEM)
9347117408Skan	op1 = force_reg (mode, op1);
934818334Speter
9349117408Skan      if (push_operand (op0, mode)
9350117408Skan	  && ! general_no_elim_operand (op1, mode))
9351117408Skan	op1 = copy_to_mode_reg (mode, op1);
935290284Sobrien
935390284Sobrien      /* Force large constants in 64bit compilation into register
935490284Sobrien	 to get them CSEed.  */
935590284Sobrien      if (TARGET_64BIT && mode == DImode
9356117408Skan	  && immediate_operand (op1, mode)
9357169705Skan	  && !x86_64_zext_immediate_operand (op1, VOIDmode)
9358117408Skan	  && !register_operand (op0, mode)
935990284Sobrien	  && optimize && !reload_completed && !reload_in_progress)
9360117408Skan	op1 = copy_to_mode_reg (mode, op1);
936190284Sobrien
936290284Sobrien      if (FLOAT_MODE_P (mode))
936352294Sobrien	{
936490284Sobrien	  /* If we are loading a floating point constant to a register,
936590284Sobrien	     force the value to memory now, since we'll get better code
936690284Sobrien	     out the back end.  */
936752294Sobrien
936890284Sobrien	  if (strict)
936990284Sobrien	    ;
9370117408Skan	  else if (GET_CODE (op1) == CONST_DOUBLE)
9371117408Skan	    {
9372117408Skan	      op1 = validize_mem (force_const_mem (mode, op1));
9373117408Skan	      if (!register_operand (op0, mode))
9374117408Skan		{
9375117408Skan		  rtx temp = gen_reg_rtx (mode);
9376117408Skan		  emit_insn (gen_rtx_SET (VOIDmode, temp, op1));
9377117408Skan		  emit_move_insn (op0, temp);
9378117408Skan		  return;
9379117408Skan		}
9380117408Skan	    }
938152294Sobrien	}
938252294Sobrien    }
938390284Sobrien
9384132743Skan  emit_insn (gen_rtx_SET (VOIDmode, op0, op1));
938518334Speter}
938618334Speter
938790284Sobrienvoid
9388132743Skanix86_expand_vector_move (enum machine_mode mode, rtx operands[])
938918334Speter{
9390169705Skan  rtx op0 = operands[0], op1 = operands[1];
9391169705Skan
939290284Sobrien  /* Force constants other than zero into memory.  We do not know how
939390284Sobrien     the instructions used to build constants modify the upper 64 bits
939490284Sobrien     of the register, once we have that information we may be able
939590284Sobrien     to handle some of them more efficiently.  */
939690284Sobrien  if ((reload_in_progress | reload_completed) == 0
9397169705Skan      && register_operand (op0, mode)
9398169705Skan      && CONSTANT_P (op1)
9399169705Skan      && standard_sse_constant_p (op1) <= 0)
9400169705Skan    op1 = validize_mem (force_const_mem (mode, op1));
940151411Sobrien
940290284Sobrien  /* Make operand1 a register if it isn't already.  */
9403117408Skan  if (!no_new_pseudos
9404169705Skan      && !register_operand (op0, mode)
9405169705Skan      && !register_operand (op1, mode))
940651411Sobrien    {
9407169705Skan      emit_move_insn (op0, force_reg (GET_MODE (op0), op1));
940890284Sobrien      return;
940951411Sobrien    }
941051411Sobrien
9411169705Skan  emit_insn (gen_rtx_SET (VOIDmode, op0, op1));
9412117408Skan}
941318334Speter
9414169705Skan/* Implement the movmisalign patterns for SSE.  Non-SSE modes go
9415169705Skan   straight to ix86_expand_vector_move.  */
941618334Speter
941790284Sobrienvoid
9418169705Skanix86_expand_vector_move_misalign (enum machine_mode mode, rtx operands[])
941990284Sobrien{
9420169705Skan  rtx op0, op1, m;
9421169705Skan
9422169705Skan  op0 = operands[0];
9423169705Skan  op1 = operands[1];
9424169705Skan
9425169705Skan  if (MEM_P (op1))
9426169705Skan    {
9427169705Skan      /* If we're optimizing for size, movups is the smallest.  */
9428169705Skan      if (optimize_size)
9429169705Skan	{
9430169705Skan	  op0 = gen_lowpart (V4SFmode, op0);
9431169705Skan	  op1 = gen_lowpart (V4SFmode, op1);
9432169705Skan	  emit_insn (gen_sse_movups (op0, op1));
9433169705Skan	  return;
9434169705Skan	}
9435169705Skan
9436169705Skan      /* ??? If we have typed data, then it would appear that using
9437169705Skan	 movdqu is the only way to get unaligned data loaded with
9438169705Skan	 integer type.  */
9439169705Skan      if (TARGET_SSE2 && GET_MODE_CLASS (mode) == MODE_VECTOR_INT)
9440169705Skan	{
9441169705Skan	  op0 = gen_lowpart (V16QImode, op0);
9442169705Skan	  op1 = gen_lowpart (V16QImode, op1);
9443169705Skan	  emit_insn (gen_sse2_movdqu (op0, op1));
9444169705Skan	  return;
9445169705Skan	}
9446169705Skan
9447169705Skan      if (TARGET_SSE2 && mode == V2DFmode)
9448251212Spfg        {
9449251212Spfg          rtx zero;
9450169705Skan
9451251212Spfg          if (TARGET_SSE_UNALIGNED_MOVE_OPTIMAL)
9452251212Spfg            {
9453251212Spfg              op0 = gen_lowpart (V2DFmode, op0);
9454251212Spfg              op1 = gen_lowpart (V2DFmode, op1);
9455251212Spfg              emit_insn (gen_sse2_movupd (op0, op1));
9456251212Spfg              return;
9457251212Spfg            }
9458251212Spfg
9459169705Skan	  /* When SSE registers are split into halves, we can avoid
9460169705Skan	     writing to the top half twice.  */
9461169705Skan	  if (TARGET_SSE_SPLIT_REGS)
9462169705Skan	    {
9463169705Skan	      emit_insn (gen_rtx_CLOBBER (VOIDmode, op0));
9464169705Skan	      zero = op0;
9465169705Skan	    }
9466169705Skan	  else
9467169705Skan	    {
9468169705Skan	      /* ??? Not sure about the best option for the Intel chips.
9469169705Skan		 The following would seem to satisfy; the register is
9470169705Skan		 entirely cleared, breaking the dependency chain.  We
9471169705Skan		 then store to the upper half, with a dependency depth
9472169705Skan		 of one.  A rumor has it that Intel recommends two movsd
9473169705Skan		 followed by an unpacklpd, but this is unconfirmed.  And
9474169705Skan		 given that the dependency depth of the unpacklpd would
9475169705Skan		 still be one, I'm not sure why this would be better.  */
9476169705Skan	      zero = CONST0_RTX (V2DFmode);
9477169705Skan	    }
9478169705Skan
9479169705Skan	  m = adjust_address (op1, DFmode, 0);
9480169705Skan	  emit_insn (gen_sse2_loadlpd (op0, zero, m));
9481169705Skan	  m = adjust_address (op1, DFmode, 8);
9482169705Skan	  emit_insn (gen_sse2_loadhpd (op0, op0, m));
9483169705Skan	}
9484169705Skan      else
9485251212Spfg        {
9486251212Spfg          if (TARGET_SSE_UNALIGNED_MOVE_OPTIMAL)
9487251212Spfg            {
9488251212Spfg              op0 = gen_lowpart (V4SFmode, op0);
9489251212Spfg              op1 = gen_lowpart (V4SFmode, op1);
9490251212Spfg              emit_insn (gen_sse_movups (op0, op1));
9491251212Spfg              return;
9492251212Spfg            }
9493251212Spfg
9494169705Skan	  if (TARGET_SSE_PARTIAL_REG_DEPENDENCY)
9495169705Skan	    emit_move_insn (op0, CONST0_RTX (mode));
9496169705Skan	  else
9497169705Skan	    emit_insn (gen_rtx_CLOBBER (VOIDmode, op0));
9498169705Skan
9499169705Skan	  if (mode != V4SFmode)
9500169705Skan	    op0 = gen_lowpart (V4SFmode, op0);
9501169705Skan	  m = adjust_address (op1, V2SFmode, 0);
9502169705Skan	  emit_insn (gen_sse_loadlps (op0, op0, m));
9503169705Skan	  m = adjust_address (op1, V2SFmode, 8);
9504169705Skan	  emit_insn (gen_sse_loadhps (op0, op0, m));
9505169705Skan	}
9506169705Skan    }
9507169705Skan  else if (MEM_P (op0))
9508169705Skan    {
9509169705Skan      /* If we're optimizing for size, movups is the smallest.  */
9510169705Skan      if (optimize_size)
9511169705Skan	{
9512169705Skan	  op0 = gen_lowpart (V4SFmode, op0);
9513169705Skan	  op1 = gen_lowpart (V4SFmode, op1);
9514169705Skan	  emit_insn (gen_sse_movups (op0, op1));
9515169705Skan	  return;
9516169705Skan	}
9517169705Skan
9518169705Skan      /* ??? Similar to above, only less clear because of quote
9519169705Skan	 typeless stores unquote.  */
9520169705Skan      if (TARGET_SSE2 && !TARGET_SSE_TYPELESS_STORES
9521169705Skan	  && GET_MODE_CLASS (mode) == MODE_VECTOR_INT)
9522169705Skan        {
9523169705Skan	  op0 = gen_lowpart (V16QImode, op0);
9524169705Skan	  op1 = gen_lowpart (V16QImode, op1);
9525169705Skan	  emit_insn (gen_sse2_movdqu (op0, op1));
9526169705Skan	  return;
9527169705Skan	}
9528169705Skan
9529169705Skan      if (TARGET_SSE2 && mode == V2DFmode)
9530169705Skan	{
9531169705Skan	  m = adjust_address (op0, DFmode, 0);
9532169705Skan	  emit_insn (gen_sse2_storelpd (m, op1));
9533169705Skan	  m = adjust_address (op0, DFmode, 8);
9534169705Skan	  emit_insn (gen_sse2_storehpd (m, op1));
9535169705Skan	}
9536169705Skan      else
9537169705Skan	{
9538169705Skan	  if (mode != V4SFmode)
9539169705Skan	    op1 = gen_lowpart (V4SFmode, op1);
9540169705Skan	  m = adjust_address (op0, V2SFmode, 0);
9541169705Skan	  emit_insn (gen_sse_storelps (m, op1));
9542169705Skan	  m = adjust_address (op0, V2SFmode, 8);
9543169705Skan	  emit_insn (gen_sse_storehps (m, op1));
9544169705Skan	}
9545169705Skan    }
9546169705Skan  else
9547169705Skan    gcc_unreachable ();
9548169705Skan}
9549169705Skan
9550169705Skan/* Expand a push in MODE.  This is some mode for which we do not support
9551169705Skan   proper push instructions, at least from the registers that we expect
9552169705Skan   the value to live in.  */
9553169705Skan
9554169705Skanvoid
9555169705Skanix86_expand_push (enum machine_mode mode, rtx x)
9556169705Skan{
9557169705Skan  rtx tmp;
9558169705Skan
9559169705Skan  tmp = expand_simple_binop (Pmode, PLUS, stack_pointer_rtx,
9560169705Skan			     GEN_INT (-GET_MODE_SIZE (mode)),
9561169705Skan			     stack_pointer_rtx, 1, OPTAB_DIRECT);
9562169705Skan  if (tmp != stack_pointer_rtx)
9563169705Skan    emit_move_insn (stack_pointer_rtx, tmp);
9564169705Skan
9565169705Skan  tmp = gen_rtx_MEM (mode, stack_pointer_rtx);
9566169705Skan  emit_move_insn (tmp, x);
9567169705Skan}
9568169705Skan
9569169705Skan/* Fix up OPERANDS to satisfy ix86_binary_operator_ok.  Return the
9570169705Skan   destination to use for the operation.  If different from the true
9571169705Skan   destination in operands[0], a copy operation will be required.  */
9572169705Skan
9573169705Skanrtx
9574169705Skanix86_fixup_binary_operands (enum rtx_code code, enum machine_mode mode,
9575169705Skan			    rtx operands[])
9576169705Skan{
957790284Sobrien  int matching_memory;
9578169705Skan  rtx src1, src2, dst;
957990284Sobrien
958090284Sobrien  dst = operands[0];
958190284Sobrien  src1 = operands[1];
958290284Sobrien  src2 = operands[2];
958390284Sobrien
958490284Sobrien  /* Recognize <var1> = <value> <op> <var1> for commutative operators */
9585169705Skan  if (GET_RTX_CLASS (code) == RTX_COMM_ARITH
958690284Sobrien      && (rtx_equal_p (dst, src2)
958790284Sobrien	  || immediate_operand (src1, mode)))
958818334Speter    {
958990284Sobrien      rtx temp = src1;
959090284Sobrien      src1 = src2;
959190284Sobrien      src2 = temp;
959290284Sobrien    }
959318334Speter
959490284Sobrien  /* If the destination is memory, and we do not have matching source
959590284Sobrien     operands, do things in registers.  */
959690284Sobrien  matching_memory = 0;
959790284Sobrien  if (GET_CODE (dst) == MEM)
959890284Sobrien    {
959990284Sobrien      if (rtx_equal_p (dst, src1))
960090284Sobrien	matching_memory = 1;
9601169705Skan      else if (GET_RTX_CLASS (code) == RTX_COMM_ARITH
960290284Sobrien	       && rtx_equal_p (dst, src2))
960390284Sobrien	matching_memory = 2;
960418334Speter      else
960590284Sobrien	dst = gen_reg_rtx (mode);
960618334Speter    }
960790284Sobrien
960890284Sobrien  /* Both source operands cannot be in memory.  */
960990284Sobrien  if (GET_CODE (src1) == MEM && GET_CODE (src2) == MEM)
961090284Sobrien    {
961190284Sobrien      if (matching_memory != 2)
961290284Sobrien	src2 = force_reg (mode, src2);
961390284Sobrien      else
961490284Sobrien	src1 = force_reg (mode, src1);
961590284Sobrien    }
961690284Sobrien
961790284Sobrien  /* If the operation is not commutable, source 1 cannot be a constant
961890284Sobrien     or non-matching memory.  */
961990284Sobrien  if ((CONSTANT_P (src1)
962090284Sobrien       || (!matching_memory && GET_CODE (src1) == MEM))
9621169705Skan      && GET_RTX_CLASS (code) != RTX_COMM_ARITH)
962290284Sobrien    src1 = force_reg (mode, src1);
962390284Sobrien
9624169705Skan  src1 = operands[1] = src1;
9625169705Skan  src2 = operands[2] = src2;
9626169705Skan  return dst;
9627169705Skan}
962890284Sobrien
9629169705Skan/* Similarly, but assume that the destination has already been
9630169705Skan   set up properly.  */
963190284Sobrien
9632169705Skanvoid
9633169705Skanix86_fixup_binary_operands_no_copy (enum rtx_code code,
9634169705Skan				    enum machine_mode mode, rtx operands[])
9635169705Skan{
9636169705Skan  rtx dst = ix86_fixup_binary_operands (code, mode, operands);
9637169705Skan  gcc_assert (dst == operands[0]);
9638169705Skan}
9639169705Skan
9640169705Skan/* Attempt to expand a binary operator.  Make the expansion closer to the
9641169705Skan   actual machine, then just general_operand, which will allow 3 separate
9642169705Skan   memory references (one output, two input) in a single insn.  */
9643169705Skan
9644169705Skanvoid
9645169705Skanix86_expand_binary_operator (enum rtx_code code, enum machine_mode mode,
9646169705Skan			     rtx operands[])
9647169705Skan{
9648169705Skan  rtx src1, src2, dst, op, clob;
9649169705Skan
9650169705Skan  dst = ix86_fixup_binary_operands (code, mode, operands);
9651169705Skan  src1 = operands[1];
9652169705Skan  src2 = operands[2];
9653169705Skan
9654169705Skan /* Emit the instruction.  */
9655169705Skan
965690284Sobrien  op = gen_rtx_SET (VOIDmode, dst, gen_rtx_fmt_ee (code, mode, src1, src2));
965790284Sobrien  if (reload_in_progress)
965890284Sobrien    {
965990284Sobrien      /* Reload doesn't know about the flags register, and doesn't know that
966090284Sobrien         it doesn't want to clobber it.  We can only do this with PLUS.  */
9661169705Skan      gcc_assert (code == PLUS);
966290284Sobrien      emit_insn (op);
966390284Sobrien    }
966418334Speter  else
966518334Speter    {
966690284Sobrien      clob = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, FLAGS_REG));
966790284Sobrien      emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, op, clob)));
966890284Sobrien    }
966918334Speter
967090284Sobrien  /* Fix up the destination if needed.  */
967190284Sobrien  if (dst != operands[0])
967290284Sobrien    emit_move_insn (operands[0], dst);
967390284Sobrien}
967418334Speter
967590284Sobrien/* Return TRUE or FALSE depending on whether the binary operator meets the
967690284Sobrien   appropriate constraints.  */
967718334Speter
967890284Sobrienint
9679132743Skanix86_binary_operator_ok (enum rtx_code code,
9680132743Skan			 enum machine_mode mode ATTRIBUTE_UNUSED,
9681132743Skan			 rtx operands[3])
968290284Sobrien{
968390284Sobrien  /* Both source operands cannot be in memory.  */
968490284Sobrien  if (GET_CODE (operands[1]) == MEM && GET_CODE (operands[2]) == MEM)
968590284Sobrien    return 0;
968690284Sobrien  /* If the operation is not commutable, source 1 cannot be a constant.  */
9687169705Skan  if (CONSTANT_P (operands[1]) && GET_RTX_CLASS (code) != RTX_COMM_ARITH)
968890284Sobrien    return 0;
968990284Sobrien  /* If the destination is memory, we must have a matching source operand.  */
969090284Sobrien  if (GET_CODE (operands[0]) == MEM
969190284Sobrien      && ! (rtx_equal_p (operands[0], operands[1])
9692169705Skan	    || (GET_RTX_CLASS (code) == RTX_COMM_ARITH
969390284Sobrien		&& rtx_equal_p (operands[0], operands[2]))))
969490284Sobrien    return 0;
969590284Sobrien  /* If the operation is not commutable and the source 1 is memory, we must
969690284Sobrien     have a matching destination.  */
969790284Sobrien  if (GET_CODE (operands[1]) == MEM
9698169705Skan      && GET_RTX_CLASS (code) != RTX_COMM_ARITH
969990284Sobrien      && ! rtx_equal_p (operands[0], operands[1]))
970090284Sobrien    return 0;
970190284Sobrien  return 1;
970290284Sobrien}
970318334Speter
970490284Sobrien/* Attempt to expand a unary operator.  Make the expansion closer to the
970590284Sobrien   actual machine, then just general_operand, which will allow 2 separate
970690284Sobrien   memory references (one output, one input) in a single insn.  */
970718334Speter
970890284Sobrienvoid
9709132743Skanix86_expand_unary_operator (enum rtx_code code, enum machine_mode mode,
9710132743Skan			    rtx operands[])
971190284Sobrien{
971290284Sobrien  int matching_memory;
971390284Sobrien  rtx src, dst, op, clob;
971490284Sobrien
971590284Sobrien  dst = operands[0];
971690284Sobrien  src = operands[1];
971790284Sobrien
971890284Sobrien  /* If the destination is memory, and we do not have matching source
971990284Sobrien     operands, do things in registers.  */
972090284Sobrien  matching_memory = 0;
9721169705Skan  if (MEM_P (dst))
972290284Sobrien    {
972390284Sobrien      if (rtx_equal_p (dst, src))
972490284Sobrien	matching_memory = 1;
972518334Speter      else
972690284Sobrien	dst = gen_reg_rtx (mode);
972718334Speter    }
972818334Speter
972990284Sobrien  /* When source operand is memory, destination must match.  */
9730169705Skan  if (MEM_P (src) && !matching_memory)
973190284Sobrien    src = force_reg (mode, src);
973290284Sobrien
973390284Sobrien  /* Emit the instruction.  */
973452294Sobrien
973590284Sobrien  op = gen_rtx_SET (VOIDmode, dst, gen_rtx_fmt_e (code, mode, src));
973690284Sobrien  if (reload_in_progress || code == NOT)
973752294Sobrien    {
973890284Sobrien      /* Reload doesn't know about the flags register, and doesn't know that
973990284Sobrien         it doesn't want to clobber it.  */
9740169705Skan      gcc_assert (code == NOT);
974190284Sobrien      emit_insn (op);
974252294Sobrien    }
974390284Sobrien  else
974490284Sobrien    {
974590284Sobrien      clob = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, FLAGS_REG));
974690284Sobrien      emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, op, clob)));
974790284Sobrien    }
974852294Sobrien
974990284Sobrien  /* Fix up the destination if needed.  */
975090284Sobrien  if (dst != operands[0])
975190284Sobrien    emit_move_insn (operands[0], dst);
975290284Sobrien}
975352294Sobrien
975490284Sobrien/* Return TRUE or FALSE depending on whether the unary operator meets the
975590284Sobrien   appropriate constraints.  */
975652294Sobrien
975790284Sobrienint
9758132743Skanix86_unary_operator_ok (enum rtx_code code ATTRIBUTE_UNUSED,
9759132743Skan			enum machine_mode mode ATTRIBUTE_UNUSED,
9760132743Skan			rtx operands[2] ATTRIBUTE_UNUSED)
976190284Sobrien{
976290284Sobrien  /* If one of operands is memory, source and destination must match.  */
976390284Sobrien  if ((GET_CODE (operands[0]) == MEM
976490284Sobrien       || GET_CODE (operands[1]) == MEM)
976590284Sobrien      && ! rtx_equal_p (operands[0], operands[1]))
976690284Sobrien    return FALSE;
976790284Sobrien  return TRUE;
976818334Speter}
976918334Speter
9770169705Skan/* A subroutine of ix86_expand_fp_absneg_operator and copysign expanders.
9771169705Skan   Create a mask for the sign bit in MODE for an SSE register.  If VECT is
9772169705Skan   true, then replicate the mask for all elements of the vector register.
9773169705Skan   If INVERT is true, then create a mask excluding the sign bit.  */
9774169705Skan
9775169705Skanrtx
9776169705Skanix86_build_signbit_mask (enum machine_mode mode, bool vect, bool invert)
9777169705Skan{
9778169705Skan  enum machine_mode vec_mode;
9779169705Skan  HOST_WIDE_INT hi, lo;
9780169705Skan  int shift = 63;
9781169705Skan  rtvec v;
9782169705Skan  rtx mask;
9783169705Skan
9784169705Skan  /* Find the sign bit, sign extended to 2*HWI.  */
9785169705Skan  if (mode == SFmode)
9786169705Skan    lo = 0x80000000, hi = lo < 0;
9787169705Skan  else if (HOST_BITS_PER_WIDE_INT >= 64)
9788169705Skan    lo = (HOST_WIDE_INT)1 << shift, hi = -1;
9789169705Skan  else
9790169705Skan    lo = 0, hi = (HOST_WIDE_INT)1 << (shift - HOST_BITS_PER_WIDE_INT);
9791169705Skan
9792169705Skan  if (invert)
9793169705Skan    lo = ~lo, hi = ~hi;
9794169705Skan
9795169705Skan  /* Force this value into the low part of a fp vector constant.  */
9796169705Skan  mask = immed_double_const (lo, hi, mode == SFmode ? SImode : DImode);
9797169705Skan  mask = gen_lowpart (mode, mask);
9798169705Skan
9799169705Skan  if (mode == SFmode)
9800169705Skan    {
9801169705Skan      if (vect)
9802169705Skan	v = gen_rtvec (4, mask, mask, mask, mask);
9803169705Skan      else
9804169705Skan	v = gen_rtvec (4, mask, CONST0_RTX (SFmode),
9805169705Skan		       CONST0_RTX (SFmode), CONST0_RTX (SFmode));
9806169705Skan      vec_mode = V4SFmode;
9807169705Skan    }
9808169705Skan  else
9809169705Skan    {
9810169705Skan      if (vect)
9811169705Skan	v = gen_rtvec (2, mask, mask);
9812169705Skan      else
9813169705Skan	v = gen_rtvec (2, mask, CONST0_RTX (DFmode));
9814169705Skan      vec_mode = V2DFmode;
9815169705Skan    }
9816169705Skan
9817169705Skan  return force_reg (vec_mode, gen_rtx_CONST_VECTOR (vec_mode, v));
9818169705Skan}
9819169705Skan
9820169705Skan/* Generate code for floating point ABS or NEG.  */
9821169705Skan
9822169705Skanvoid
9823169705Skanix86_expand_fp_absneg_operator (enum rtx_code code, enum machine_mode mode,
9824169705Skan				rtx operands[])
9825169705Skan{
9826169705Skan  rtx mask, set, use, clob, dst, src;
9827169705Skan  bool matching_memory;
9828169705Skan  bool use_sse = false;
9829169705Skan  bool vector_mode = VECTOR_MODE_P (mode);
9830169705Skan  enum machine_mode elt_mode = mode;
9831169705Skan
9832169705Skan  if (vector_mode)
9833169705Skan    {
9834169705Skan      elt_mode = GET_MODE_INNER (mode);
9835169705Skan      use_sse = true;
9836169705Skan    }
9837169705Skan  else if (TARGET_SSE_MATH)
9838169705Skan    use_sse = SSE_FLOAT_MODE_P (mode);
9839169705Skan
9840169705Skan  /* NEG and ABS performed with SSE use bitwise mask operations.
9841169705Skan     Create the appropriate mask now.  */
9842169705Skan  if (use_sse)
9843169705Skan    mask = ix86_build_signbit_mask (elt_mode, vector_mode, code == ABS);
9844169705Skan  else
9845169705Skan    mask = NULL_RTX;
9846169705Skan
9847169705Skan  dst = operands[0];
9848169705Skan  src = operands[1];
9849169705Skan
9850169705Skan  /* If the destination is memory, and we don't have matching source
9851169705Skan     operands or we're using the x87, do things in registers.  */
9852169705Skan  matching_memory = false;
9853169705Skan  if (MEM_P (dst))
9854169705Skan    {
9855169705Skan      if (use_sse && rtx_equal_p (dst, src))
9856169705Skan	matching_memory = true;
9857169705Skan      else
9858169705Skan	dst = gen_reg_rtx (mode);
9859169705Skan    }
9860169705Skan  if (MEM_P (src) && !matching_memory)
9861169705Skan    src = force_reg (mode, src);
9862169705Skan
9863169705Skan  if (vector_mode)
9864169705Skan    {
9865169705Skan      set = gen_rtx_fmt_ee (code == NEG ? XOR : AND, mode, src, mask);
9866169705Skan      set = gen_rtx_SET (VOIDmode, dst, set);
9867169705Skan      emit_insn (set);
9868169705Skan    }
9869169705Skan  else
9870169705Skan    {
9871169705Skan      set = gen_rtx_fmt_e (code, mode, src);
9872169705Skan      set = gen_rtx_SET (VOIDmode, dst, set);
9873169705Skan      if (mask)
9874169705Skan        {
9875169705Skan          use = gen_rtx_USE (VOIDmode, mask);
9876169705Skan          clob = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, FLAGS_REG));
9877169705Skan          emit_insn (gen_rtx_PARALLEL (VOIDmode,
9878169705Skan				       gen_rtvec (3, set, use, clob)));
9879169705Skan        }
9880169705Skan      else
9881169705Skan	emit_insn (set);
9882169705Skan    }
9883169705Skan
9884169705Skan  if (dst != operands[0])
9885169705Skan    emit_move_insn (operands[0], dst);
9886169705Skan}
9887169705Skan
9888169705Skan/* Expand a copysign operation.  Special case operand 0 being a constant.  */
9889169705Skan
9890169705Skanvoid
9891169705Skanix86_expand_copysign (rtx operands[])
9892169705Skan{
9893169705Skan  enum machine_mode mode, vmode;
9894169705Skan  rtx dest, op0, op1, mask, nmask;
9895169705Skan
9896169705Skan  dest = operands[0];
9897169705Skan  op0 = operands[1];
9898169705Skan  op1 = operands[2];
9899169705Skan
9900169705Skan  mode = GET_MODE (dest);
9901169705Skan  vmode = mode == SFmode ? V4SFmode : V2DFmode;
9902169705Skan
9903169705Skan  if (GET_CODE (op0) == CONST_DOUBLE)
9904169705Skan    {
9905169705Skan      rtvec v;
9906169705Skan
9907169705Skan      if (real_isneg (CONST_DOUBLE_REAL_VALUE (op0)))
9908169705Skan	op0 = simplify_unary_operation (ABS, mode, op0, mode);
9909169705Skan
9910169705Skan      if (op0 == CONST0_RTX (mode))
9911169705Skan	op0 = CONST0_RTX (vmode);
9912169705Skan      else
9913169705Skan        {
9914169705Skan	  if (mode == SFmode)
9915169705Skan	    v = gen_rtvec (4, op0, CONST0_RTX (SFmode),
9916169705Skan                           CONST0_RTX (SFmode), CONST0_RTX (SFmode));
9917169705Skan	  else
9918169705Skan	    v = gen_rtvec (2, op0, CONST0_RTX (DFmode));
9919169705Skan          op0 = force_reg (vmode, gen_rtx_CONST_VECTOR (vmode, v));
9920169705Skan	}
9921169705Skan
9922169705Skan      mask = ix86_build_signbit_mask (mode, 0, 0);
9923169705Skan
9924169705Skan      if (mode == SFmode)
9925169705Skan	emit_insn (gen_copysignsf3_const (dest, op0, op1, mask));
9926169705Skan      else
9927169705Skan	emit_insn (gen_copysigndf3_const (dest, op0, op1, mask));
9928169705Skan    }
9929169705Skan  else
9930169705Skan    {
9931169705Skan      nmask = ix86_build_signbit_mask (mode, 0, 1);
9932169705Skan      mask = ix86_build_signbit_mask (mode, 0, 0);
9933169705Skan
9934169705Skan      if (mode == SFmode)
9935169705Skan	emit_insn (gen_copysignsf3_var (dest, NULL, op0, op1, nmask, mask));
9936169705Skan      else
9937169705Skan	emit_insn (gen_copysigndf3_var (dest, NULL, op0, op1, nmask, mask));
9938169705Skan    }
9939169705Skan}
9940169705Skan
9941169705Skan/* Deconstruct a copysign operation into bit masks.  Operand 0 is known to
9942169705Skan   be a constant, and so has already been expanded into a vector constant.  */
9943169705Skan
9944169705Skanvoid
9945169705Skanix86_split_copysign_const (rtx operands[])
9946169705Skan{
9947169705Skan  enum machine_mode mode, vmode;
9948169705Skan  rtx dest, op0, op1, mask, x;
9949169705Skan
9950169705Skan  dest = operands[0];
9951169705Skan  op0 = operands[1];
9952169705Skan  op1 = operands[2];
9953169705Skan  mask = operands[3];
9954169705Skan
9955169705Skan  mode = GET_MODE (dest);
9956169705Skan  vmode = GET_MODE (mask);
9957169705Skan
9958169705Skan  dest = simplify_gen_subreg (vmode, dest, mode, 0);
9959169705Skan  x = gen_rtx_AND (vmode, dest, mask);
9960169705Skan  emit_insn (gen_rtx_SET (VOIDmode, dest, x));
9961169705Skan
9962169705Skan  if (op0 != CONST0_RTX (vmode))
9963169705Skan    {
9964169705Skan      x = gen_rtx_IOR (vmode, dest, op0);
9965169705Skan      emit_insn (gen_rtx_SET (VOIDmode, dest, x));
9966169705Skan    }
9967169705Skan}
9968169705Skan
9969169705Skan/* Deconstruct a copysign operation into bit masks.  Operand 0 is variable,
9970169705Skan   so we have to do two masks.  */
9971169705Skan
9972169705Skanvoid
9973169705Skanix86_split_copysign_var (rtx operands[])
9974169705Skan{
9975169705Skan  enum machine_mode mode, vmode;
9976169705Skan  rtx dest, scratch, op0, op1, mask, nmask, x;
9977169705Skan
9978169705Skan  dest = operands[0];
9979169705Skan  scratch = operands[1];
9980169705Skan  op0 = operands[2];
9981169705Skan  op1 = operands[3];
9982169705Skan  nmask = operands[4];
9983169705Skan  mask = operands[5];
9984169705Skan
9985169705Skan  mode = GET_MODE (dest);
9986169705Skan  vmode = GET_MODE (mask);
9987169705Skan
9988169705Skan  if (rtx_equal_p (op0, op1))
9989169705Skan    {
9990169705Skan      /* Shouldn't happen often (it's useless, obviously), but when it does
9991169705Skan	 we'd generate incorrect code if we continue below.  */
9992169705Skan      emit_move_insn (dest, op0);
9993169705Skan      return;
9994169705Skan    }
9995169705Skan
9996169705Skan  if (REG_P (mask) && REGNO (dest) == REGNO (mask))	/* alternative 0 */
9997169705Skan    {
9998169705Skan      gcc_assert (REGNO (op1) == REGNO (scratch));
9999169705Skan
10000169705Skan      x = gen_rtx_AND (vmode, scratch, mask);
10001169705Skan      emit_insn (gen_rtx_SET (VOIDmode, scratch, x));
10002169705Skan
10003169705Skan      dest = mask;
10004169705Skan      op0 = simplify_gen_subreg (vmode, op0, mode, 0);
10005169705Skan      x = gen_rtx_NOT (vmode, dest);
10006169705Skan      x = gen_rtx_AND (vmode, x, op0);
10007169705Skan      emit_insn (gen_rtx_SET (VOIDmode, dest, x));
10008169705Skan    }
10009169705Skan  else
10010169705Skan    {
10011169705Skan      if (REGNO (op1) == REGNO (scratch))		/* alternative 1,3 */
10012169705Skan	{
10013169705Skan	  x = gen_rtx_AND (vmode, scratch, mask);
10014169705Skan	}
10015169705Skan      else						/* alternative 2,4 */
10016169705Skan	{
10017169705Skan          gcc_assert (REGNO (mask) == REGNO (scratch));
10018169705Skan          op1 = simplify_gen_subreg (vmode, op1, mode, 0);
10019169705Skan	  x = gen_rtx_AND (vmode, scratch, op1);
10020169705Skan	}
10021169705Skan      emit_insn (gen_rtx_SET (VOIDmode, scratch, x));
10022169705Skan
10023169705Skan      if (REGNO (op0) == REGNO (dest))			/* alternative 1,2 */
10024169705Skan	{
10025169705Skan	  dest = simplify_gen_subreg (vmode, op0, mode, 0);
10026169705Skan	  x = gen_rtx_AND (vmode, dest, nmask);
10027169705Skan	}
10028169705Skan      else						/* alternative 3,4 */
10029169705Skan	{
10030169705Skan          gcc_assert (REGNO (nmask) == REGNO (dest));
10031169705Skan	  dest = nmask;
10032169705Skan	  op0 = simplify_gen_subreg (vmode, op0, mode, 0);
10033169705Skan	  x = gen_rtx_AND (vmode, dest, op0);
10034169705Skan	}
10035169705Skan      emit_insn (gen_rtx_SET (VOIDmode, dest, x));
10036169705Skan    }
10037169705Skan
10038169705Skan  x = gen_rtx_IOR (vmode, dest, scratch);
10039169705Skan  emit_insn (gen_rtx_SET (VOIDmode, dest, x));
10040169705Skan}
10041169705Skan
1004290284Sobrien/* Return TRUE or FALSE depending on whether the first SET in INSN
1004390284Sobrien   has source and destination with matching CC modes, and that the
1004490284Sobrien   CC mode is at least as constrained as REQ_MODE.  */
1004590284Sobrien
1004690284Sobrienint
10047132743Skanix86_match_ccmode (rtx insn, enum machine_mode req_mode)
1004818334Speter{
1004990284Sobrien  rtx set;
1005090284Sobrien  enum machine_mode set_mode;
1005118334Speter
1005290284Sobrien  set = PATTERN (insn);
1005390284Sobrien  if (GET_CODE (set) == PARALLEL)
1005490284Sobrien    set = XVECEXP (set, 0, 0);
10055169705Skan  gcc_assert (GET_CODE (set) == SET);
10056169705Skan  gcc_assert (GET_CODE (SET_SRC (set)) == COMPARE);
1005790284Sobrien
1005890284Sobrien  set_mode = GET_MODE (SET_DEST (set));
1005990284Sobrien  switch (set_mode)
1006052294Sobrien    {
1006190284Sobrien    case CCNOmode:
1006290284Sobrien      if (req_mode != CCNOmode
1006390284Sobrien	  && (req_mode != CCmode
1006490284Sobrien	      || XEXP (SET_SRC (set), 1) != const0_rtx))
1006590284Sobrien	return 0;
1006690284Sobrien      break;
1006790284Sobrien    case CCmode:
1006890284Sobrien      if (req_mode == CCGCmode)
1006990284Sobrien	return 0;
1007090284Sobrien      /* FALLTHRU */
1007190284Sobrien    case CCGCmode:
1007290284Sobrien      if (req_mode == CCGOCmode || req_mode == CCNOmode)
1007390284Sobrien	return 0;
1007490284Sobrien      /* FALLTHRU */
1007590284Sobrien    case CCGOCmode:
1007690284Sobrien      if (req_mode == CCZmode)
1007790284Sobrien	return 0;
1007890284Sobrien      /* FALLTHRU */
1007990284Sobrien    case CCZmode:
1008090284Sobrien      break;
1008190284Sobrien
1008290284Sobrien    default:
10083169705Skan      gcc_unreachable ();
1008452294Sobrien    }
1008518334Speter
1008690284Sobrien  return (GET_MODE (SET_SRC (set)) == set_mode);
1008790284Sobrien}
1008851411Sobrien
1008990284Sobrien/* Generate insn patterns to do an integer compare of OPERANDS.  */
1009051411Sobrien
1009190284Sobrienstatic rtx
10092132743Skanix86_expand_int_compare (enum rtx_code code, rtx op0, rtx op1)
1009390284Sobrien{
1009490284Sobrien  enum machine_mode cmpmode;
1009590284Sobrien  rtx tmp, flags;
1009651411Sobrien
1009790284Sobrien  cmpmode = SELECT_CC_MODE (code, op0, op1);
1009890284Sobrien  flags = gen_rtx_REG (cmpmode, FLAGS_REG);
1009918334Speter
1010090284Sobrien  /* This is very simple, but making the interface the same as in the
1010190284Sobrien     FP case makes the rest of the code easier.  */
1010290284Sobrien  tmp = gen_rtx_COMPARE (cmpmode, op0, op1);
1010390284Sobrien  emit_insn (gen_rtx_SET (VOIDmode, flags, tmp));
1010490284Sobrien
1010590284Sobrien  /* Return the test that should be put into the flags user, i.e.
1010690284Sobrien     the bcc, scc, or cmov instruction.  */
1010790284Sobrien  return gen_rtx_fmt_ee (code, VOIDmode, flags, const0_rtx);
1010890284Sobrien}
1010990284Sobrien
1011090284Sobrien/* Figure out whether to use ordered or unordered fp comparisons.
1011190284Sobrien   Return the appropriate mode to use.  */
1011290284Sobrien
1011390284Sobrienenum machine_mode
10114132743Skanix86_fp_compare_mode (enum rtx_code code ATTRIBUTE_UNUSED)
1011590284Sobrien{
1011690284Sobrien  /* ??? In order to make all comparisons reversible, we do all comparisons
1011790284Sobrien     non-trapping when compiling for IEEE.  Once gcc is able to distinguish
1011890284Sobrien     all forms trapping and nontrapping comparisons, we can make inequality
1011990284Sobrien     comparisons trapping again, since it results in better code when using
1012090284Sobrien     FCOM based compares.  */
1012190284Sobrien  return TARGET_IEEE_FP ? CCFPUmode : CCFPmode;
1012290284Sobrien}
1012390284Sobrien
1012490284Sobrienenum machine_mode
10125132743Skanix86_cc_mode (enum rtx_code code, rtx op0, rtx op1)
1012690284Sobrien{
10127169705Skan  if (SCALAR_FLOAT_MODE_P (GET_MODE (op0)))
1012890284Sobrien    return ix86_fp_compare_mode (code);
1012990284Sobrien  switch (code)
1013018334Speter    {
1013190284Sobrien      /* Only zero flag is needed.  */
1013290284Sobrien    case EQ:			/* ZF=0 */
1013390284Sobrien    case NE:			/* ZF!=0 */
1013490284Sobrien      return CCZmode;
1013590284Sobrien      /* Codes needing carry flag.  */
1013690284Sobrien    case GEU:			/* CF=0 */
1013790284Sobrien    case GTU:			/* CF=0 & ZF=0 */
1013890284Sobrien    case LTU:			/* CF=1 */
1013990284Sobrien    case LEU:			/* CF=1 | ZF=1 */
1014090284Sobrien      return CCmode;
1014190284Sobrien      /* Codes possibly doable only with sign flag when
1014290284Sobrien         comparing against zero.  */
1014390284Sobrien    case GE:			/* SF=OF   or   SF=0 */
1014490284Sobrien    case LT:			/* SF<>OF  or   SF=1 */
1014590284Sobrien      if (op1 == const0_rtx)
1014690284Sobrien	return CCGOCmode;
1014751411Sobrien      else
1014890284Sobrien	/* For other cases Carry flag is not required.  */
1014990284Sobrien	return CCGCmode;
1015090284Sobrien      /* Codes doable only with sign flag when comparing
1015190284Sobrien         against zero, but we miss jump instruction for it
10152132743Skan         so we need to use relational tests against overflow
1015390284Sobrien         that thus needs to be zero.  */
1015490284Sobrien    case GT:			/* ZF=0 & SF=OF */
1015590284Sobrien    case LE:			/* ZF=1 | SF<>OF */
1015690284Sobrien      if (op1 == const0_rtx)
1015790284Sobrien	return CCNOmode;
1015890284Sobrien      else
1015990284Sobrien	return CCGCmode;
1016090284Sobrien      /* strcmp pattern do (use flags) and combine may ask us for proper
1016190284Sobrien	 mode.  */
1016290284Sobrien    case USE:
1016390284Sobrien      return CCmode;
1016490284Sobrien    default:
10165169705Skan      gcc_unreachable ();
1016618334Speter    }
1016790284Sobrien}
1016851411Sobrien
10169132743Skan/* Return the fixed registers used for condition codes.  */
10170132743Skan
10171132743Skanstatic bool
10172132743Skanix86_fixed_condition_code_regs (unsigned int *p1, unsigned int *p2)
10173132743Skan{
10174132743Skan  *p1 = FLAGS_REG;
10175132743Skan  *p2 = FPSR_REG;
10176132743Skan  return true;
10177132743Skan}
10178132743Skan
10179132743Skan/* If two condition code modes are compatible, return a condition code
10180132743Skan   mode which is compatible with both.  Otherwise, return
10181132743Skan   VOIDmode.  */
10182132743Skan
10183132743Skanstatic enum machine_mode
10184132743Skanix86_cc_modes_compatible (enum machine_mode m1, enum machine_mode m2)
10185132743Skan{
10186132743Skan  if (m1 == m2)
10187132743Skan    return m1;
10188132743Skan
10189132743Skan  if (GET_MODE_CLASS (m1) != MODE_CC || GET_MODE_CLASS (m2) != MODE_CC)
10190132743Skan    return VOIDmode;
10191132743Skan
10192132743Skan  if ((m1 == CCGCmode && m2 == CCGOCmode)
10193132743Skan      || (m1 == CCGOCmode && m2 == CCGCmode))
10194132743Skan    return CCGCmode;
10195132743Skan
10196132743Skan  switch (m1)
10197132743Skan    {
10198132743Skan    default:
10199169705Skan      gcc_unreachable ();
10200132743Skan
10201132743Skan    case CCmode:
10202132743Skan    case CCGCmode:
10203132743Skan    case CCGOCmode:
10204132743Skan    case CCNOmode:
10205132743Skan    case CCZmode:
10206132743Skan      switch (m2)
10207132743Skan	{
10208132743Skan	default:
10209132743Skan	  return VOIDmode;
10210132743Skan
10211132743Skan	case CCmode:
10212132743Skan	case CCGCmode:
10213132743Skan	case CCGOCmode:
10214132743Skan	case CCNOmode:
10215132743Skan	case CCZmode:
10216132743Skan	  return CCmode;
10217132743Skan	}
10218132743Skan
10219132743Skan    case CCFPmode:
10220132743Skan    case CCFPUmode:
10221132743Skan      /* These are only compatible with themselves, which we already
10222132743Skan	 checked above.  */
10223132743Skan      return VOIDmode;
10224132743Skan    }
10225132743Skan}
10226132743Skan
1022790284Sobrien/* Return true if we should use an FCOMI instruction for this fp comparison.  */
1022890284Sobrien
1022990284Sobrienint
10230132743Skanix86_use_fcomi_compare (enum rtx_code code ATTRIBUTE_UNUSED)
1023190284Sobrien{
1023290284Sobrien  enum rtx_code swapped_code = swap_condition (code);
1023390284Sobrien  return ((ix86_fp_comparison_cost (code) == ix86_fp_comparison_fcomi_cost (code))
1023490284Sobrien	  || (ix86_fp_comparison_cost (swapped_code)
1023590284Sobrien	      == ix86_fp_comparison_fcomi_cost (swapped_code)));
1023690284Sobrien}
1023790284Sobrien
1023890284Sobrien/* Swap, force into registers, or otherwise massage the two operands
1023990284Sobrien   to a fp comparison.  The operands are updated in place; the new
10240132743Skan   comparison code is returned.  */
1024190284Sobrien
1024290284Sobrienstatic enum rtx_code
10243132743Skanix86_prepare_fp_compare_args (enum rtx_code code, rtx *pop0, rtx *pop1)
1024490284Sobrien{
1024590284Sobrien  enum machine_mode fpcmp_mode = ix86_fp_compare_mode (code);
1024690284Sobrien  rtx op0 = *pop0, op1 = *pop1;
1024790284Sobrien  enum machine_mode op_mode = GET_MODE (op0);
10248169705Skan  int is_sse = TARGET_SSE_MATH && SSE_FLOAT_MODE_P (op_mode);
1024990284Sobrien
1025090284Sobrien  /* All of the unordered compare instructions only work on registers.
10251169705Skan     The same is true of the fcomi compare instructions.  The XFmode
10252169705Skan     compare instructions require registers except when comparing
10253169705Skan     against zero or when converting operand 1 from fixed point to
10254169705Skan     floating point.  */
1025590284Sobrien
1025690284Sobrien  if (!is_sse
1025790284Sobrien      && (fpcmp_mode == CCFPUmode
10258169705Skan	  || (op_mode == XFmode
10259169705Skan	      && ! (standard_80387_constant_p (op0) == 1
10260169705Skan		    || standard_80387_constant_p (op1) == 1)
10261169705Skan	      && GET_CODE (op1) != FLOAT)
1026290284Sobrien	  || ix86_use_fcomi_compare (code)))
1026318334Speter    {
1026490284Sobrien      op0 = force_reg (op_mode, op0);
1026590284Sobrien      op1 = force_reg (op_mode, op1);
1026618334Speter    }
1026718334Speter  else
1026852294Sobrien    {
1026990284Sobrien      /* %%% We only allow op1 in memory; op0 must be st(0).  So swap
1027090284Sobrien	 things around if they appear profitable, otherwise force op0
1027190284Sobrien	 into a register.  */
1027218334Speter
1027390284Sobrien      if (standard_80387_constant_p (op0) == 0
1027490284Sobrien	  || (GET_CODE (op0) == MEM
1027590284Sobrien	      && ! (standard_80387_constant_p (op1) == 0
1027690284Sobrien		    || GET_CODE (op1) == MEM)))
1027790284Sobrien	{
1027890284Sobrien	  rtx tmp;
1027990284Sobrien	  tmp = op0, op0 = op1, op1 = tmp;
1028090284Sobrien	  code = swap_condition (code);
1028190284Sobrien	}
1028252294Sobrien
1028390284Sobrien      if (GET_CODE (op0) != REG)
1028490284Sobrien	op0 = force_reg (op_mode, op0);
1028590284Sobrien
1028690284Sobrien      if (CONSTANT_P (op1))
1028752294Sobrien	{
10288169705Skan	  int tmp = standard_80387_constant_p (op1);
10289169705Skan	  if (tmp == 0)
10290169705Skan	    op1 = validize_mem (force_const_mem (op_mode, op1));
10291169705Skan	  else if (tmp == 1)
10292169705Skan	    {
10293169705Skan	      if (TARGET_CMOVE)
10294169705Skan		op1 = force_reg (op_mode, op1);
10295169705Skan	    }
10296169705Skan	  else
1029790284Sobrien	    op1 = force_reg (op_mode, op1);
1029890284Sobrien	}
1029990284Sobrien    }
1030052294Sobrien
1030190284Sobrien  /* Try to rearrange the comparison to make it cheaper.  */
1030290284Sobrien  if (ix86_fp_comparison_cost (code)
1030390284Sobrien      > ix86_fp_comparison_cost (swap_condition (code))
1030496293Sobrien      && (GET_CODE (op1) == REG || !no_new_pseudos))
1030590284Sobrien    {
1030690284Sobrien      rtx tmp;
1030790284Sobrien      tmp = op0, op0 = op1, op1 = tmp;
1030890284Sobrien      code = swap_condition (code);
1030990284Sobrien      if (GET_CODE (op0) != REG)
1031090284Sobrien	op0 = force_reg (op_mode, op0);
1031190284Sobrien    }
1031252294Sobrien
1031390284Sobrien  *pop0 = op0;
1031490284Sobrien  *pop1 = op1;
1031590284Sobrien  return code;
1031690284Sobrien}
1031752294Sobrien
1031890284Sobrien/* Convert comparison codes we use to represent FP comparison to integer
1031990284Sobrien   code that will result in proper branch.  Return UNKNOWN if no such code
1032090284Sobrien   is available.  */
10321169705Skan
10322169705Skanenum rtx_code
10323132743Skanix86_fp_compare_code_to_integer (enum rtx_code code)
1032490284Sobrien{
1032590284Sobrien  switch (code)
1032690284Sobrien    {
1032790284Sobrien    case GT:
1032890284Sobrien      return GTU;
1032990284Sobrien    case GE:
1033090284Sobrien      return GEU;
1033190284Sobrien    case ORDERED:
1033290284Sobrien    case UNORDERED:
1033390284Sobrien      return code;
1033490284Sobrien      break;
1033590284Sobrien    case UNEQ:
1033690284Sobrien      return EQ;
1033790284Sobrien      break;
1033890284Sobrien    case UNLT:
1033990284Sobrien      return LTU;
1034090284Sobrien      break;
1034190284Sobrien    case UNLE:
1034290284Sobrien      return LEU;
1034390284Sobrien      break;
1034490284Sobrien    case LTGT:
1034590284Sobrien      return NE;
1034690284Sobrien      break;
1034790284Sobrien    default:
1034890284Sobrien      return UNKNOWN;
1034990284Sobrien    }
1035090284Sobrien}
1035152294Sobrien
1035290284Sobrien/* Split comparison code CODE into comparisons we can do using branch
1035390284Sobrien   instructions.  BYPASS_CODE is comparison code for branch that will
1035490284Sobrien   branch around FIRST_CODE and SECOND_CODE.  If some of branches
10355169705Skan   is not required, set value to UNKNOWN.
1035690284Sobrien   We never require more than two branches.  */
10357169705Skan
10358169705Skanvoid
10359132743Skanix86_fp_comparison_codes (enum rtx_code code, enum rtx_code *bypass_code,
10360132743Skan			  enum rtx_code *first_code,
10361132743Skan			  enum rtx_code *second_code)
1036290284Sobrien{
1036390284Sobrien  *first_code = code;
10364169705Skan  *bypass_code = UNKNOWN;
10365169705Skan  *second_code = UNKNOWN;
1036690284Sobrien
1036790284Sobrien  /* The fcomi comparison sets flags as follows:
1036890284Sobrien
1036990284Sobrien     cmp    ZF PF CF
1037090284Sobrien     >      0  0  0
1037190284Sobrien     <      0  0  1
1037290284Sobrien     =      1  0  0
1037390284Sobrien     un     1  1  1 */
1037490284Sobrien
1037590284Sobrien  switch (code)
1037690284Sobrien    {
1037790284Sobrien    case GT:			/* GTU - CF=0 & ZF=0 */
1037890284Sobrien    case GE:			/* GEU - CF=0 */
1037990284Sobrien    case ORDERED:		/* PF=0 */
1038090284Sobrien    case UNORDERED:		/* PF=1 */
1038190284Sobrien    case UNEQ:			/* EQ - ZF=1 */
1038290284Sobrien    case UNLT:			/* LTU - CF=1 */
1038390284Sobrien    case UNLE:			/* LEU - CF=1 | ZF=1 */
1038490284Sobrien    case LTGT:			/* EQ - ZF=0 */
1038590284Sobrien      break;
1038690284Sobrien    case LT:			/* LTU - CF=1 - fails on unordered */
1038790284Sobrien      *first_code = UNLT;
1038890284Sobrien      *bypass_code = UNORDERED;
1038990284Sobrien      break;
1039090284Sobrien    case LE:			/* LEU - CF=1 | ZF=1 - fails on unordered */
1039190284Sobrien      *first_code = UNLE;
1039290284Sobrien      *bypass_code = UNORDERED;
1039390284Sobrien      break;
1039490284Sobrien    case EQ:			/* EQ - ZF=1 - fails on unordered */
1039590284Sobrien      *first_code = UNEQ;
1039690284Sobrien      *bypass_code = UNORDERED;
1039790284Sobrien      break;
1039890284Sobrien    case NE:			/* NE - ZF=0 - fails on unordered */
1039990284Sobrien      *first_code = LTGT;
1040090284Sobrien      *second_code = UNORDERED;
1040190284Sobrien      break;
1040290284Sobrien    case UNGE:			/* GEU - CF=0 - fails on unordered */
1040390284Sobrien      *first_code = GE;
1040490284Sobrien      *second_code = UNORDERED;
1040590284Sobrien      break;
1040690284Sobrien    case UNGT:			/* GTU - CF=0 & ZF=0 - fails on unordered */
1040790284Sobrien      *first_code = GT;
1040890284Sobrien      *second_code = UNORDERED;
1040990284Sobrien      break;
1041090284Sobrien    default:
10411169705Skan      gcc_unreachable ();
1041290284Sobrien    }
1041390284Sobrien  if (!TARGET_IEEE_FP)
1041490284Sobrien    {
10415169705Skan      *second_code = UNKNOWN;
10416169705Skan      *bypass_code = UNKNOWN;
1041790284Sobrien    }
1041890284Sobrien}
1041990284Sobrien
1042090284Sobrien/* Return cost of comparison done fcom + arithmetics operations on AX.
10421132743Skan   All following functions do use number of instructions as a cost metrics.
1042290284Sobrien   In future this should be tweaked to compute bytes for optimize_size and
1042390284Sobrien   take into account performance of various instructions on various CPUs.  */
1042490284Sobrienstatic int
10425132743Skanix86_fp_comparison_arithmetics_cost (enum rtx_code code)
1042690284Sobrien{
1042790284Sobrien  if (!TARGET_IEEE_FP)
1042890284Sobrien    return 4;
1042990284Sobrien  /* The cost of code output by ix86_expand_fp_compare.  */
1043090284Sobrien  switch (code)
1043190284Sobrien    {
1043290284Sobrien    case UNLE:
1043390284Sobrien    case UNLT:
1043490284Sobrien    case LTGT:
1043590284Sobrien    case GT:
1043690284Sobrien    case GE:
1043790284Sobrien    case UNORDERED:
1043890284Sobrien    case ORDERED:
1043990284Sobrien    case UNEQ:
1044090284Sobrien      return 4;
1044190284Sobrien      break;
1044290284Sobrien    case LT:
1044390284Sobrien    case NE:
1044490284Sobrien    case EQ:
1044590284Sobrien    case UNGE:
1044690284Sobrien      return 5;
1044790284Sobrien      break;
1044890284Sobrien    case LE:
1044990284Sobrien    case UNGT:
1045090284Sobrien      return 6;
1045190284Sobrien      break;
1045290284Sobrien    default:
10453169705Skan      gcc_unreachable ();
1045490284Sobrien    }
1045590284Sobrien}
1045690284Sobrien
1045790284Sobrien/* Return cost of comparison done using fcomi operation.
1045890284Sobrien   See ix86_fp_comparison_arithmetics_cost for the metrics.  */
1045990284Sobrienstatic int
10460132743Skanix86_fp_comparison_fcomi_cost (enum rtx_code code)
1046190284Sobrien{
1046290284Sobrien  enum rtx_code bypass_code, first_code, second_code;
10463132743Skan  /* Return arbitrarily high cost when instruction is not supported - this
1046490284Sobrien     prevents gcc from using it.  */
1046590284Sobrien  if (!TARGET_CMOVE)
1046690284Sobrien    return 1024;
1046790284Sobrien  ix86_fp_comparison_codes (code, &bypass_code, &first_code, &second_code);
10468169705Skan  return (bypass_code != UNKNOWN || second_code != UNKNOWN) + 2;
1046990284Sobrien}
1047090284Sobrien
1047190284Sobrien/* Return cost of comparison done using sahf operation.
1047290284Sobrien   See ix86_fp_comparison_arithmetics_cost for the metrics.  */
1047390284Sobrienstatic int
10474132743Skanix86_fp_comparison_sahf_cost (enum rtx_code code)
1047590284Sobrien{
1047690284Sobrien  enum rtx_code bypass_code, first_code, second_code;
10477132743Skan  /* Return arbitrarily high cost when instruction is not preferred - this
1047890284Sobrien     avoids gcc from using it.  */
1047990284Sobrien  if (!TARGET_USE_SAHF && !optimize_size)
1048090284Sobrien    return 1024;
1048190284Sobrien  ix86_fp_comparison_codes (code, &bypass_code, &first_code, &second_code);
10482169705Skan  return (bypass_code != UNKNOWN || second_code != UNKNOWN) + 3;
1048390284Sobrien}
1048490284Sobrien
1048590284Sobrien/* Compute cost of the comparison done using any method.
1048690284Sobrien   See ix86_fp_comparison_arithmetics_cost for the metrics.  */
1048790284Sobrienstatic int
10488132743Skanix86_fp_comparison_cost (enum rtx_code code)
1048990284Sobrien{
1049090284Sobrien  int fcomi_cost, sahf_cost, arithmetics_cost = 1024;
1049190284Sobrien  int min;
1049290284Sobrien
1049390284Sobrien  fcomi_cost = ix86_fp_comparison_fcomi_cost (code);
1049490284Sobrien  sahf_cost = ix86_fp_comparison_sahf_cost (code);
1049590284Sobrien
1049690284Sobrien  min = arithmetics_cost = ix86_fp_comparison_arithmetics_cost (code);
1049790284Sobrien  if (min > sahf_cost)
1049890284Sobrien    min = sahf_cost;
1049990284Sobrien  if (min > fcomi_cost)
1050090284Sobrien    min = fcomi_cost;
1050190284Sobrien  return min;
1050290284Sobrien}
1050390284Sobrien
1050490284Sobrien/* Generate insn patterns to do a floating point compare of OPERANDS.  */
1050590284Sobrien
1050690284Sobrienstatic rtx
10507132743Skanix86_expand_fp_compare (enum rtx_code code, rtx op0, rtx op1, rtx scratch,
10508132743Skan			rtx *second_test, rtx *bypass_test)
1050990284Sobrien{
1051090284Sobrien  enum machine_mode fpcmp_mode, intcmp_mode;
1051190284Sobrien  rtx tmp, tmp2;
1051290284Sobrien  int cost = ix86_fp_comparison_cost (code);
1051390284Sobrien  enum rtx_code bypass_code, first_code, second_code;
1051490284Sobrien
1051590284Sobrien  fpcmp_mode = ix86_fp_compare_mode (code);
1051690284Sobrien  code = ix86_prepare_fp_compare_args (code, &op0, &op1);
1051790284Sobrien
1051890284Sobrien  if (second_test)
1051990284Sobrien    *second_test = NULL_RTX;
1052090284Sobrien  if (bypass_test)
1052190284Sobrien    *bypass_test = NULL_RTX;
1052290284Sobrien
1052390284Sobrien  ix86_fp_comparison_codes (code, &bypass_code, &first_code, &second_code);
1052490284Sobrien
1052590284Sobrien  /* Do fcomi/sahf based test when profitable.  */
10526169705Skan  if ((bypass_code == UNKNOWN || bypass_test)
10527169705Skan      && (second_code == UNKNOWN || second_test)
1052890284Sobrien      && ix86_fp_comparison_arithmetics_cost (code) > cost)
1052990284Sobrien    {
1053090284Sobrien      if (TARGET_CMOVE)
1053190284Sobrien	{
1053290284Sobrien	  tmp = gen_rtx_COMPARE (fpcmp_mode, op0, op1);
1053390284Sobrien	  tmp = gen_rtx_SET (VOIDmode, gen_rtx_REG (fpcmp_mode, FLAGS_REG),
1053490284Sobrien			     tmp);
1053590284Sobrien	  emit_insn (tmp);
1053652294Sobrien	}
1053790284Sobrien      else
1053890284Sobrien	{
1053990284Sobrien	  tmp = gen_rtx_COMPARE (fpcmp_mode, op0, op1);
10540117408Skan	  tmp2 = gen_rtx_UNSPEC (HImode, gen_rtvec (1, tmp), UNSPEC_FNSTSW);
1054190284Sobrien	  if (!scratch)
1054290284Sobrien	    scratch = gen_reg_rtx (HImode);
1054390284Sobrien	  emit_insn (gen_rtx_SET (VOIDmode, scratch, tmp2));
1054490284Sobrien	  emit_insn (gen_x86_sahf_1 (scratch));
1054590284Sobrien	}
1054690284Sobrien
1054790284Sobrien      /* The FP codes work out to act like unsigned.  */
1054890284Sobrien      intcmp_mode = fpcmp_mode;
1054990284Sobrien      code = first_code;
10550169705Skan      if (bypass_code != UNKNOWN)
1055190284Sobrien	*bypass_test = gen_rtx_fmt_ee (bypass_code, VOIDmode,
1055290284Sobrien				       gen_rtx_REG (intcmp_mode, FLAGS_REG),
1055390284Sobrien				       const0_rtx);
10554169705Skan      if (second_code != UNKNOWN)
1055590284Sobrien	*second_test = gen_rtx_fmt_ee (second_code, VOIDmode,
1055690284Sobrien				       gen_rtx_REG (intcmp_mode, FLAGS_REG),
1055790284Sobrien				       const0_rtx);
1055852294Sobrien    }
1055952294Sobrien  else
1056018334Speter    {
1056190284Sobrien      /* Sadness wrt reg-stack pops killing fpsr -- gotta get fnstsw first.  */
1056290284Sobrien      tmp = gen_rtx_COMPARE (fpcmp_mode, op0, op1);
10563117408Skan      tmp2 = gen_rtx_UNSPEC (HImode, gen_rtvec (1, tmp), UNSPEC_FNSTSW);
1056490284Sobrien      if (!scratch)
1056590284Sobrien	scratch = gen_reg_rtx (HImode);
1056690284Sobrien      emit_insn (gen_rtx_SET (VOIDmode, scratch, tmp2));
1056718334Speter
1056890284Sobrien      /* In the unordered case, we have to check C2 for NaN's, which
1056990284Sobrien	 doesn't happen to work out to anything nice combination-wise.
1057090284Sobrien	 So do some bit twiddling on the value we've got in AH to come
1057190284Sobrien	 up with an appropriate set of condition codes.  */
1057290284Sobrien
1057390284Sobrien      intcmp_mode = CCNOmode;
1057452294Sobrien      switch (code)
1057552294Sobrien	{
1057652294Sobrien	case GT:
1057790284Sobrien	case UNGT:
1057890284Sobrien	  if (code == GT || !TARGET_IEEE_FP)
1057990284Sobrien	    {
1058090284Sobrien	      emit_insn (gen_testqi_ext_ccno_0 (scratch, GEN_INT (0x45)));
1058190284Sobrien	      code = EQ;
1058290284Sobrien	    }
1058390284Sobrien	  else
1058490284Sobrien	    {
1058590284Sobrien	      emit_insn (gen_andqi_ext_0 (scratch, scratch, GEN_INT (0x45)));
1058690284Sobrien	      emit_insn (gen_addqi_ext_1 (scratch, scratch, constm1_rtx));
1058790284Sobrien	      emit_insn (gen_cmpqi_ext_3 (scratch, GEN_INT (0x44)));
1058890284Sobrien	      intcmp_mode = CCmode;
1058990284Sobrien	      code = GEU;
1059090284Sobrien	    }
1059152294Sobrien	  break;
1059252294Sobrien	case LT:
1059390284Sobrien	case UNLT:
1059490284Sobrien	  if (code == LT && TARGET_IEEE_FP)
1059590284Sobrien	    {
1059690284Sobrien	      emit_insn (gen_andqi_ext_0 (scratch, scratch, GEN_INT (0x45)));
1059790284Sobrien	      emit_insn (gen_cmpqi_ext_3 (scratch, GEN_INT (0x01)));
1059890284Sobrien	      intcmp_mode = CCmode;
1059990284Sobrien	      code = EQ;
1060090284Sobrien	    }
1060190284Sobrien	  else
1060290284Sobrien	    {
1060390284Sobrien	      emit_insn (gen_testqi_ext_ccno_0 (scratch, GEN_INT (0x01)));
1060490284Sobrien	      code = NE;
1060590284Sobrien	    }
1060652294Sobrien	  break;
1060752294Sobrien	case GE:
1060890284Sobrien	case UNGE:
1060990284Sobrien	  if (code == GE || !TARGET_IEEE_FP)
1061090284Sobrien	    {
1061190284Sobrien	      emit_insn (gen_testqi_ext_ccno_0 (scratch, GEN_INT (0x05)));
1061290284Sobrien	      code = EQ;
1061390284Sobrien	    }
1061490284Sobrien	  else
1061590284Sobrien	    {
1061690284Sobrien	      emit_insn (gen_andqi_ext_0 (scratch, scratch, GEN_INT (0x45)));
1061790284Sobrien	      emit_insn (gen_xorqi_cc_ext_1 (scratch, scratch,
1061890284Sobrien					     GEN_INT (0x01)));
1061990284Sobrien	      code = NE;
1062090284Sobrien	    }
1062152294Sobrien	  break;
1062252294Sobrien	case LE:
1062390284Sobrien	case UNLE:
1062490284Sobrien	  if (code == LE && TARGET_IEEE_FP)
1062590284Sobrien	    {
1062690284Sobrien	      emit_insn (gen_andqi_ext_0 (scratch, scratch, GEN_INT (0x45)));
1062790284Sobrien	      emit_insn (gen_addqi_ext_1 (scratch, scratch, constm1_rtx));
1062890284Sobrien	      emit_insn (gen_cmpqi_ext_3 (scratch, GEN_INT (0x40)));
1062990284Sobrien	      intcmp_mode = CCmode;
1063090284Sobrien	      code = LTU;
1063190284Sobrien	    }
1063290284Sobrien	  else
1063390284Sobrien	    {
1063490284Sobrien	      emit_insn (gen_testqi_ext_ccno_0 (scratch, GEN_INT (0x45)));
1063590284Sobrien	      code = NE;
1063690284Sobrien	    }
1063752294Sobrien	  break;
1063852294Sobrien	case EQ:
1063990284Sobrien	case UNEQ:
1064090284Sobrien	  if (code == EQ && TARGET_IEEE_FP)
1064190284Sobrien	    {
1064290284Sobrien	      emit_insn (gen_andqi_ext_0 (scratch, scratch, GEN_INT (0x45)));
1064390284Sobrien	      emit_insn (gen_cmpqi_ext_3 (scratch, GEN_INT (0x40)));
1064490284Sobrien	      intcmp_mode = CCmode;
1064590284Sobrien	      code = EQ;
1064690284Sobrien	    }
1064790284Sobrien	  else
1064890284Sobrien	    {
1064990284Sobrien	      emit_insn (gen_testqi_ext_ccno_0 (scratch, GEN_INT (0x40)));
1065090284Sobrien	      code = NE;
1065190284Sobrien	      break;
1065290284Sobrien	    }
1065352294Sobrien	  break;
1065452294Sobrien	case NE:
1065590284Sobrien	case LTGT:
1065690284Sobrien	  if (code == NE && TARGET_IEEE_FP)
1065790284Sobrien	    {
1065890284Sobrien	      emit_insn (gen_andqi_ext_0 (scratch, scratch, GEN_INT (0x45)));
1065990284Sobrien	      emit_insn (gen_xorqi_cc_ext_1 (scratch, scratch,
1066090284Sobrien					     GEN_INT (0x40)));
1066190284Sobrien	      code = NE;
1066290284Sobrien	    }
1066390284Sobrien	  else
1066490284Sobrien	    {
1066590284Sobrien	      emit_insn (gen_testqi_ext_ccno_0 (scratch, GEN_INT (0x40)));
1066690284Sobrien	      code = EQ;
1066790284Sobrien	    }
1066852294Sobrien	  break;
1066952294Sobrien
1067090284Sobrien	case UNORDERED:
1067190284Sobrien	  emit_insn (gen_testqi_ext_ccno_0 (scratch, GEN_INT (0x04)));
1067290284Sobrien	  code = NE;
1067390284Sobrien	  break;
1067490284Sobrien	case ORDERED:
1067590284Sobrien	  emit_insn (gen_testqi_ext_ccno_0 (scratch, GEN_INT (0x04)));
1067690284Sobrien	  code = EQ;
1067790284Sobrien	  break;
1067890284Sobrien
1067952294Sobrien	default:
10680169705Skan	  gcc_unreachable ();
1068152294Sobrien	}
1068218334Speter    }
1068351411Sobrien
1068490284Sobrien  /* Return the test that should be put into the flags user, i.e.
1068590284Sobrien     the bcc, scc, or cmov instruction.  */
1068690284Sobrien  return gen_rtx_fmt_ee (code, VOIDmode,
1068790284Sobrien			 gen_rtx_REG (intcmp_mode, FLAGS_REG),
1068890284Sobrien			 const0_rtx);
1068918334Speter}
1069018334Speter
1069190284Sobrienrtx
10692132743Skanix86_expand_compare (enum rtx_code code, rtx *second_test, rtx *bypass_test)
1069318334Speter{
1069490284Sobrien  rtx op0, op1, ret;
1069590284Sobrien  op0 = ix86_compare_op0;
1069690284Sobrien  op1 = ix86_compare_op1;
1069718334Speter
1069890284Sobrien  if (second_test)
1069990284Sobrien    *second_test = NULL_RTX;
1070090284Sobrien  if (bypass_test)
1070190284Sobrien    *bypass_test = NULL_RTX;
1070218334Speter
10703169705Skan  if (ix86_compare_emitted)
10704169705Skan    {
10705169705Skan      ret = gen_rtx_fmt_ee (code, VOIDmode, ix86_compare_emitted, const0_rtx);
10706169705Skan      ix86_compare_emitted = NULL_RTX;
10707169705Skan    }
10708169705Skan  else if (SCALAR_FLOAT_MODE_P (GET_MODE (op0)))
1070990284Sobrien    ret = ix86_expand_fp_compare (code, op0, op1, NULL_RTX,
1071090284Sobrien				  second_test, bypass_test);
1071190284Sobrien  else
1071290284Sobrien    ret = ix86_expand_int_compare (code, op0, op1);
1071390284Sobrien
1071490284Sobrien  return ret;
1071518334Speter}
1071618334Speter
1071790284Sobrien/* Return true if the CODE will result in nontrivial jump sequence.  */
1071890284Sobrienbool
10719132743Skanix86_fp_jump_nontrivial_p (enum rtx_code code)
1072018334Speter{
1072190284Sobrien  enum rtx_code bypass_code, first_code, second_code;
1072290284Sobrien  if (!TARGET_CMOVE)
1072390284Sobrien    return true;
1072490284Sobrien  ix86_fp_comparison_codes (code, &bypass_code, &first_code, &second_code);
10725169705Skan  return bypass_code != UNKNOWN || second_code != UNKNOWN;
1072618334Speter}
1072718334Speter
1072818334Spetervoid
10729132743Skanix86_expand_branch (enum rtx_code code, rtx label)
1073018334Speter{
1073190284Sobrien  rtx tmp;
1073218334Speter
10733169705Skan  /* If we have emitted a compare insn, go straight to simple.
10734169705Skan     ix86_expand_compare won't emit anything if ix86_compare_emitted
10735169705Skan     is non NULL.  */
10736169705Skan  if (ix86_compare_emitted)
10737169705Skan    goto simple;
10738169705Skan
1073990284Sobrien  switch (GET_MODE (ix86_compare_op0))
1074090284Sobrien    {
1074190284Sobrien    case QImode:
1074290284Sobrien    case HImode:
1074390284Sobrien    case SImode:
1074490284Sobrien      simple:
1074590284Sobrien      tmp = ix86_expand_compare (code, NULL, NULL);
1074690284Sobrien      tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
1074790284Sobrien				  gen_rtx_LABEL_REF (VOIDmode, label),
1074890284Sobrien				  pc_rtx);
1074990284Sobrien      emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
1075090284Sobrien      return;
1075118334Speter
1075290284Sobrien    case SFmode:
1075390284Sobrien    case DFmode:
1075490284Sobrien    case XFmode:
1075590284Sobrien      {
1075690284Sobrien	rtvec vec;
1075790284Sobrien	int use_fcomi;
1075890284Sobrien	enum rtx_code bypass_code, first_code, second_code;
1075918334Speter
1076090284Sobrien	code = ix86_prepare_fp_compare_args (code, &ix86_compare_op0,
1076190284Sobrien					     &ix86_compare_op1);
10762117408Skan
1076390284Sobrien	ix86_fp_comparison_codes (code, &bypass_code, &first_code, &second_code);
1076418334Speter
1076590284Sobrien	/* Check whether we will use the natural sequence with one jump.  If
1076690284Sobrien	   so, we can expand jump early.  Otherwise delay expansion by
1076790284Sobrien	   creating compound insn to not confuse optimizers.  */
10768169705Skan	if (bypass_code == UNKNOWN && second_code == UNKNOWN
1076990284Sobrien	    && TARGET_CMOVE)
1077090284Sobrien	  {
1077190284Sobrien	    ix86_split_fp_branch (code, ix86_compare_op0, ix86_compare_op1,
1077290284Sobrien				  gen_rtx_LABEL_REF (VOIDmode, label),
10773169705Skan				  pc_rtx, NULL_RTX, NULL_RTX);
1077490284Sobrien	  }
1077590284Sobrien	else
1077690284Sobrien	  {
1077790284Sobrien	    tmp = gen_rtx_fmt_ee (code, VOIDmode,
1077890284Sobrien				  ix86_compare_op0, ix86_compare_op1);
1077990284Sobrien	    tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
1078090284Sobrien					gen_rtx_LABEL_REF (VOIDmode, label),
1078190284Sobrien					pc_rtx);
1078290284Sobrien	    tmp = gen_rtx_SET (VOIDmode, pc_rtx, tmp);
1078318334Speter
1078490284Sobrien	    use_fcomi = ix86_use_fcomi_compare (code);
1078590284Sobrien	    vec = rtvec_alloc (3 + !use_fcomi);
1078690284Sobrien	    RTVEC_ELT (vec, 0) = tmp;
1078790284Sobrien	    RTVEC_ELT (vec, 1)
1078890284Sobrien	      = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 18));
1078990284Sobrien	    RTVEC_ELT (vec, 2)
1079090284Sobrien	      = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 17));
1079190284Sobrien	    if (! use_fcomi)
1079290284Sobrien	      RTVEC_ELT (vec, 3)
1079390284Sobrien		= gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (HImode));
1079418334Speter
1079590284Sobrien	    emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, vec));
1079690284Sobrien	  }
1079790284Sobrien	return;
1079890284Sobrien      }
1079918334Speter
1080090284Sobrien    case DImode:
1080190284Sobrien      if (TARGET_64BIT)
1080290284Sobrien	goto simple;
10803169705Skan    case TImode:
1080490284Sobrien      /* Expand DImode branch into multiple compare+branch.  */
1080590284Sobrien      {
1080690284Sobrien	rtx lo[2], hi[2], label2;
1080790284Sobrien	enum rtx_code code1, code2, code3;
10808169705Skan	enum machine_mode submode;
1080951411Sobrien
1081090284Sobrien	if (CONSTANT_P (ix86_compare_op0) && ! CONSTANT_P (ix86_compare_op1))
1081190284Sobrien	  {
1081290284Sobrien	    tmp = ix86_compare_op0;
1081390284Sobrien	    ix86_compare_op0 = ix86_compare_op1;
1081490284Sobrien	    ix86_compare_op1 = tmp;
1081590284Sobrien	    code = swap_condition (code);
1081690284Sobrien	  }
10817169705Skan	if (GET_MODE (ix86_compare_op0) == DImode)
10818169705Skan	  {
10819169705Skan	    split_di (&ix86_compare_op0, 1, lo+0, hi+0);
10820169705Skan	    split_di (&ix86_compare_op1, 1, lo+1, hi+1);
10821169705Skan	    submode = SImode;
10822169705Skan	  }
10823169705Skan	else
10824169705Skan	  {
10825169705Skan	    split_ti (&ix86_compare_op0, 1, lo+0, hi+0);
10826169705Skan	    split_ti (&ix86_compare_op1, 1, lo+1, hi+1);
10827169705Skan	    submode = DImode;
10828169705Skan	  }
1082951411Sobrien
1083090284Sobrien	/* When comparing for equality, we can use (hi0^hi1)|(lo0^lo1) to
1083190284Sobrien	   avoid two branches.  This costs one extra insn, so disable when
1083290284Sobrien	   optimizing for size.  */
1083351411Sobrien
1083490284Sobrien	if ((code == EQ || code == NE)
1083590284Sobrien	    && (!optimize_size
1083690284Sobrien	        || hi[1] == const0_rtx || lo[1] == const0_rtx))
1083790284Sobrien	  {
1083890284Sobrien	    rtx xor0, xor1;
1083951411Sobrien
1084090284Sobrien	    xor1 = hi[0];
1084190284Sobrien	    if (hi[1] != const0_rtx)
10842169705Skan	      xor1 = expand_binop (submode, xor_optab, xor1, hi[1],
1084390284Sobrien				   NULL_RTX, 0, OPTAB_WIDEN);
1084451411Sobrien
1084590284Sobrien	    xor0 = lo[0];
1084690284Sobrien	    if (lo[1] != const0_rtx)
10847169705Skan	      xor0 = expand_binop (submode, xor_optab, xor0, lo[1],
1084890284Sobrien				   NULL_RTX, 0, OPTAB_WIDEN);
1084951411Sobrien
10850169705Skan	    tmp = expand_binop (submode, ior_optab, xor1, xor0,
1085190284Sobrien				NULL_RTX, 0, OPTAB_WIDEN);
1085251411Sobrien
1085390284Sobrien	    ix86_compare_op0 = tmp;
1085490284Sobrien	    ix86_compare_op1 = const0_rtx;
1085590284Sobrien	    ix86_expand_branch (code, label);
1085690284Sobrien	    return;
1085790284Sobrien	  }
1085851411Sobrien
1085990284Sobrien	/* Otherwise, if we are doing less-than or greater-or-equal-than,
1086090284Sobrien	   op1 is a constant and the low word is zero, then we can just
1086190284Sobrien	   examine the high word.  */
1086251411Sobrien
1086390284Sobrien	if (GET_CODE (hi[1]) == CONST_INT && lo[1] == const0_rtx)
1086490284Sobrien	  switch (code)
1086551411Sobrien	    {
1086690284Sobrien	    case LT: case LTU: case GE: case GEU:
1086790284Sobrien	      ix86_compare_op0 = hi[0];
1086890284Sobrien	      ix86_compare_op1 = hi[1];
1086990284Sobrien	      ix86_expand_branch (code, label);
1087090284Sobrien	      return;
1087190284Sobrien	    default:
1087290284Sobrien	      break;
1087351411Sobrien	    }
1087451411Sobrien
1087590284Sobrien	/* Otherwise, we need two or three jumps.  */
1087651411Sobrien
1087790284Sobrien	label2 = gen_label_rtx ();
1087851411Sobrien
1087990284Sobrien	code1 = code;
1088090284Sobrien	code2 = swap_condition (code);
1088190284Sobrien	code3 = unsigned_condition (code);
1088251411Sobrien
1088390284Sobrien	switch (code)
1088490284Sobrien	  {
1088590284Sobrien	  case LT: case GT: case LTU: case GTU:
1088690284Sobrien	    break;
1088790284Sobrien
1088890284Sobrien	  case LE:   code1 = LT;  code2 = GT;  break;
1088990284Sobrien	  case GE:   code1 = GT;  code2 = LT;  break;
1089090284Sobrien	  case LEU:  code1 = LTU; code2 = GTU; break;
1089190284Sobrien	  case GEU:  code1 = GTU; code2 = LTU; break;
1089290284Sobrien
10893169705Skan	  case EQ:   code1 = UNKNOWN; code2 = NE;  break;
10894169705Skan	  case NE:   code2 = UNKNOWN; break;
1089590284Sobrien
1089690284Sobrien	  default:
10897169705Skan	    gcc_unreachable ();
1089890284Sobrien	  }
1089990284Sobrien
1090090284Sobrien	/*
1090190284Sobrien	 * a < b =>
1090290284Sobrien	 *    if (hi(a) < hi(b)) goto true;
1090390284Sobrien	 *    if (hi(a) > hi(b)) goto false;
1090490284Sobrien	 *    if (lo(a) < lo(b)) goto true;
1090590284Sobrien	 *  false:
1090690284Sobrien	 */
1090790284Sobrien
1090890284Sobrien	ix86_compare_op0 = hi[0];
1090990284Sobrien	ix86_compare_op1 = hi[1];
1091090284Sobrien
10911169705Skan	if (code1 != UNKNOWN)
1091290284Sobrien	  ix86_expand_branch (code1, label);
10913169705Skan	if (code2 != UNKNOWN)
1091490284Sobrien	  ix86_expand_branch (code2, label2);
1091590284Sobrien
1091690284Sobrien	ix86_compare_op0 = lo[0];
1091790284Sobrien	ix86_compare_op1 = lo[1];
1091890284Sobrien	ix86_expand_branch (code3, label);
1091990284Sobrien
10920169705Skan	if (code2 != UNKNOWN)
1092190284Sobrien	  emit_label (label2);
1092290284Sobrien	return;
1092390284Sobrien      }
1092490284Sobrien
1092590284Sobrien    default:
10926169705Skan      gcc_unreachable ();
1092751411Sobrien    }
1092851411Sobrien}
1092951411Sobrien
1093090284Sobrien/* Split branch based on floating point condition.  */
1093151411Sobrienvoid
10932132743Skanix86_split_fp_branch (enum rtx_code code, rtx op1, rtx op2,
10933169705Skan		      rtx target1, rtx target2, rtx tmp, rtx pushed)
1093451411Sobrien{
1093590284Sobrien  rtx second, bypass;
1093690284Sobrien  rtx label = NULL_RTX;
1093790284Sobrien  rtx condition;
1093890284Sobrien  int bypass_probability = -1, second_probability = -1, probability = -1;
1093990284Sobrien  rtx i;
1094051411Sobrien
1094190284Sobrien  if (target2 != pc_rtx)
1094290284Sobrien    {
1094390284Sobrien      rtx tmp = target2;
1094490284Sobrien      code = reverse_condition_maybe_unordered (code);
1094590284Sobrien      target2 = target1;
1094690284Sobrien      target1 = tmp;
1094790284Sobrien    }
1094851411Sobrien
1094990284Sobrien  condition = ix86_expand_fp_compare (code, op1, op2,
1095090284Sobrien				      tmp, &second, &bypass);
1095190284Sobrien
10952169705Skan  /* Remove pushed operand from stack.  */
10953169705Skan  if (pushed)
10954169705Skan    ix86_free_from_memory (GET_MODE (pushed));
10955169705Skan
1095690284Sobrien  if (split_branch_probability >= 0)
1095751411Sobrien    {
1095890284Sobrien      /* Distribute the probabilities across the jumps.
1095990284Sobrien	 Assume the BYPASS and SECOND to be always test
1096090284Sobrien	 for UNORDERED.  */
1096190284Sobrien      probability = split_branch_probability;
1096251411Sobrien
1096390284Sobrien      /* Value of 1 is low enough to make no need for probability
1096490284Sobrien	 to be updated.  Later we may run some experiments and see
1096590284Sobrien	 if unordered values are more frequent in practice.  */
1096690284Sobrien      if (bypass)
1096790284Sobrien	bypass_probability = 1;
1096890284Sobrien      if (second)
1096990284Sobrien	second_probability = 1;
1097090284Sobrien    }
1097190284Sobrien  if (bypass != NULL_RTX)
1097290284Sobrien    {
1097390284Sobrien      label = gen_label_rtx ();
1097490284Sobrien      i = emit_jump_insn (gen_rtx_SET
1097590284Sobrien			  (VOIDmode, pc_rtx,
1097690284Sobrien			   gen_rtx_IF_THEN_ELSE (VOIDmode,
1097790284Sobrien						 bypass,
1097890284Sobrien						 gen_rtx_LABEL_REF (VOIDmode,
1097990284Sobrien								    label),
1098090284Sobrien						 pc_rtx)));
1098190284Sobrien      if (bypass_probability >= 0)
1098290284Sobrien	REG_NOTES (i)
1098390284Sobrien	  = gen_rtx_EXPR_LIST (REG_BR_PROB,
1098490284Sobrien			       GEN_INT (bypass_probability),
1098590284Sobrien			       REG_NOTES (i));
1098690284Sobrien    }
1098790284Sobrien  i = emit_jump_insn (gen_rtx_SET
1098890284Sobrien		      (VOIDmode, pc_rtx,
1098990284Sobrien		       gen_rtx_IF_THEN_ELSE (VOIDmode,
1099090284Sobrien					     condition, target1, target2)));
1099190284Sobrien  if (probability >= 0)
1099290284Sobrien    REG_NOTES (i)
1099390284Sobrien      = gen_rtx_EXPR_LIST (REG_BR_PROB,
1099490284Sobrien			   GEN_INT (probability),
1099590284Sobrien			   REG_NOTES (i));
1099690284Sobrien  if (second != NULL_RTX)
1099790284Sobrien    {
1099890284Sobrien      i = emit_jump_insn (gen_rtx_SET
1099990284Sobrien			  (VOIDmode, pc_rtx,
1100090284Sobrien			   gen_rtx_IF_THEN_ELSE (VOIDmode, second, target1,
1100190284Sobrien						 target2)));
1100290284Sobrien      if (second_probability >= 0)
1100390284Sobrien	REG_NOTES (i)
1100490284Sobrien	  = gen_rtx_EXPR_LIST (REG_BR_PROB,
1100590284Sobrien			       GEN_INT (second_probability),
1100690284Sobrien			       REG_NOTES (i));
1100790284Sobrien    }
1100890284Sobrien  if (label != NULL_RTX)
1100990284Sobrien    emit_label (label);
1101090284Sobrien}
1101190284Sobrien
1101290284Sobrienint
11013132743Skanix86_expand_setcc (enum rtx_code code, rtx dest)
1101490284Sobrien{
11015132743Skan  rtx ret, tmp, tmpreg, equiv;
1101690284Sobrien  rtx second_test, bypass_test;
1101790284Sobrien
11018169705Skan  if (GET_MODE (ix86_compare_op0) == (TARGET_64BIT ? TImode : DImode))
1101990284Sobrien    return 0; /* FAIL */
1102090284Sobrien
11021169705Skan  gcc_assert (GET_MODE (dest) == QImode);
1102290284Sobrien
1102390284Sobrien  ret = ix86_expand_compare (code, &second_test, &bypass_test);
1102490284Sobrien  PUT_MODE (ret, QImode);
1102590284Sobrien
1102690284Sobrien  tmp = dest;
1102790284Sobrien  tmpreg = dest;
1102890284Sobrien
1102990284Sobrien  emit_insn (gen_rtx_SET (VOIDmode, tmp, ret));
1103090284Sobrien  if (bypass_test || second_test)
1103190284Sobrien    {
1103290284Sobrien      rtx test = second_test;
1103390284Sobrien      int bypass = 0;
1103490284Sobrien      rtx tmp2 = gen_reg_rtx (QImode);
1103590284Sobrien      if (bypass_test)
1103651411Sobrien	{
11037169705Skan	  gcc_assert (!second_test);
1103890284Sobrien	  test = bypass_test;
1103990284Sobrien	  bypass = 1;
1104090284Sobrien	  PUT_CODE (test, reverse_condition_maybe_unordered (GET_CODE (test)));
1104151411Sobrien	}
1104290284Sobrien      PUT_MODE (test, QImode);
1104390284Sobrien      emit_insn (gen_rtx_SET (VOIDmode, tmp2, test));
1104451411Sobrien
1104590284Sobrien      if (bypass)
1104690284Sobrien	emit_insn (gen_andqi3 (tmp, tmpreg, tmp2));
1104790284Sobrien      else
1104890284Sobrien	emit_insn (gen_iorqi3 (tmp, tmpreg, tmp2));
1104951411Sobrien    }
1105051411Sobrien
11051132743Skan  /* Attach a REG_EQUAL note describing the comparison result.  */
11052169705Skan  if (ix86_compare_op0 && ix86_compare_op1)
11053169705Skan    {
11054169705Skan      equiv = simplify_gen_relational (code, QImode,
11055169705Skan				       GET_MODE (ix86_compare_op0),
11056169705Skan				       ix86_compare_op0, ix86_compare_op1);
11057169705Skan      set_unique_reg_note (get_last_insn (), REG_EQUAL, equiv);
11058169705Skan    }
11059132743Skan
1106090284Sobrien  return 1; /* DONE */
1106190284Sobrien}
1106251411Sobrien
11063132743Skan/* Expand comparison setting or clearing carry flag.  Return true when
11064132743Skan   successful and set pop for the operation.  */
11065132743Skanstatic bool
11066132743Skanix86_expand_carry_flag_compare (enum rtx_code code, rtx op0, rtx op1, rtx *pop)
11067132743Skan{
11068132743Skan  enum machine_mode mode =
11069132743Skan    GET_MODE (op0) != VOIDmode ? GET_MODE (op0) : GET_MODE (op1);
11070132743Skan
11071169705Skan  /* Do not handle DImode compares that go through special path.  Also we can't
11072132743Skan     deal with FP compares yet.  This is possible to add.  */
11073169705Skan  if (mode == (TARGET_64BIT ? TImode : DImode))
11074132743Skan    return false;
11075132743Skan  if (FLOAT_MODE_P (mode))
11076132743Skan    {
11077132743Skan      rtx second_test = NULL, bypass_test = NULL;
11078132743Skan      rtx compare_op, compare_seq;
11079132743Skan
11080132743Skan      /* Shortcut:  following common codes never translate into carry flag compares.  */
11081132743Skan      if (code == EQ || code == NE || code == UNEQ || code == LTGT
11082132743Skan	  || code == ORDERED || code == UNORDERED)
11083132743Skan	return false;
11084132743Skan
11085132743Skan      /* These comparisons require zero flag; swap operands so they won't.  */
11086132743Skan      if ((code == GT || code == UNLE || code == LE || code == UNGT)
11087132743Skan	  && !TARGET_IEEE_FP)
11088132743Skan	{
11089132743Skan	  rtx tmp = op0;
11090132743Skan	  op0 = op1;
11091132743Skan	  op1 = tmp;
11092132743Skan	  code = swap_condition (code);
11093132743Skan	}
11094132743Skan
11095132743Skan      /* Try to expand the comparison and verify that we end up with carry flag
11096132743Skan	 based comparison.  This is fails to be true only when we decide to expand
11097132743Skan	 comparison using arithmetic that is not too common scenario.  */
11098132743Skan      start_sequence ();
11099132743Skan      compare_op = ix86_expand_fp_compare (code, op0, op1, NULL_RTX,
11100132743Skan					   &second_test, &bypass_test);
11101132743Skan      compare_seq = get_insns ();
11102132743Skan      end_sequence ();
11103132743Skan
11104132743Skan      if (second_test || bypass_test)
11105132743Skan	return false;
11106132743Skan      if (GET_MODE (XEXP (compare_op, 0)) == CCFPmode
11107132743Skan	  || GET_MODE (XEXP (compare_op, 0)) == CCFPUmode)
11108132743Skan        code = ix86_fp_compare_code_to_integer (GET_CODE (compare_op));
11109132743Skan      else
11110132743Skan	code = GET_CODE (compare_op);
11111132743Skan      if (code != LTU && code != GEU)
11112132743Skan	return false;
11113132743Skan      emit_insn (compare_seq);
11114132743Skan      *pop = compare_op;
11115132743Skan      return true;
11116132743Skan    }
11117132743Skan  if (!INTEGRAL_MODE_P (mode))
11118132743Skan    return false;
11119132743Skan  switch (code)
11120132743Skan    {
11121132743Skan    case LTU:
11122132743Skan    case GEU:
11123132743Skan      break;
11124132743Skan
11125132743Skan    /* Convert a==0 into (unsigned)a<1.  */
11126132743Skan    case EQ:
11127132743Skan    case NE:
11128132743Skan      if (op1 != const0_rtx)
11129132743Skan	return false;
11130132743Skan      op1 = const1_rtx;
11131132743Skan      code = (code == EQ ? LTU : GEU);
11132132743Skan      break;
11133132743Skan
11134132743Skan    /* Convert a>b into b<a or a>=b-1.  */
11135132743Skan    case GTU:
11136132743Skan    case LEU:
11137132743Skan      if (GET_CODE (op1) == CONST_INT)
11138132743Skan	{
11139132743Skan	  op1 = gen_int_mode (INTVAL (op1) + 1, GET_MODE (op0));
11140132743Skan	  /* Bail out on overflow.  We still can swap operands but that
11141132743Skan	     would force loading of the constant into register.  */
11142132743Skan	  if (op1 == const0_rtx
11143132743Skan	      || !x86_64_immediate_operand (op1, GET_MODE (op1)))
11144132743Skan	    return false;
11145132743Skan	  code = (code == GTU ? GEU : LTU);
11146132743Skan	}
11147132743Skan      else
11148132743Skan	{
11149132743Skan	  rtx tmp = op1;
11150132743Skan	  op1 = op0;
11151132743Skan	  op0 = tmp;
11152132743Skan	  code = (code == GTU ? LTU : GEU);
11153132743Skan	}
11154132743Skan      break;
11155132743Skan
11156132743Skan    /* Convert a>=0 into (unsigned)a<0x80000000.  */
11157132743Skan    case LT:
11158132743Skan    case GE:
11159132743Skan      if (mode == DImode || op1 != const0_rtx)
11160132743Skan	return false;
11161132743Skan      op1 = gen_int_mode (1 << (GET_MODE_BITSIZE (mode) - 1), mode);
11162132743Skan      code = (code == LT ? GEU : LTU);
11163132743Skan      break;
11164132743Skan    case LE:
11165132743Skan    case GT:
11166132743Skan      if (mode == DImode || op1 != constm1_rtx)
11167132743Skan	return false;
11168132743Skan      op1 = gen_int_mode (1 << (GET_MODE_BITSIZE (mode) - 1), mode);
11169132743Skan      code = (code == LE ? GEU : LTU);
11170132743Skan      break;
11171132743Skan
11172132743Skan    default:
11173132743Skan      return false;
11174132743Skan    }
11175132743Skan  /* Swapping operands may cause constant to appear as first operand.  */
11176132743Skan  if (!nonimmediate_operand (op0, VOIDmode))
11177132743Skan    {
11178132743Skan      if (no_new_pseudos)
11179132743Skan	return false;
11180132743Skan      op0 = force_reg (mode, op0);
11181132743Skan    }
11182132743Skan  ix86_compare_op0 = op0;
11183132743Skan  ix86_compare_op1 = op1;
11184132743Skan  *pop = ix86_expand_compare (code, NULL, NULL);
11185169705Skan  gcc_assert (GET_CODE (*pop) == LTU || GET_CODE (*pop) == GEU);
11186132743Skan  return true;
11187132743Skan}
11188132743Skan
1118990284Sobrienint
11190132743Skanix86_expand_int_movcc (rtx operands[])
1119190284Sobrien{
1119290284Sobrien  enum rtx_code code = GET_CODE (operands[1]), compare_code;
1119390284Sobrien  rtx compare_seq, compare_op;
1119490284Sobrien  rtx second_test, bypass_test;
1119590284Sobrien  enum machine_mode mode = GET_MODE (operands[0]);
11196132743Skan  bool sign_bit_compare_p = false;;
1119790284Sobrien
1119890284Sobrien  start_sequence ();
1119990284Sobrien  compare_op = ix86_expand_compare (code, &second_test, &bypass_test);
11200117408Skan  compare_seq = get_insns ();
1120190284Sobrien  end_sequence ();
1120290284Sobrien
1120390284Sobrien  compare_code = GET_CODE (compare_op);
1120490284Sobrien
11205132743Skan  if ((ix86_compare_op1 == const0_rtx && (code == GE || code == LT))
11206132743Skan      || (ix86_compare_op1 == constm1_rtx && (code == GT || code == LE)))
11207132743Skan    sign_bit_compare_p = true;
11208132743Skan
1120990284Sobrien  /* Don't attempt mode expansion here -- if we had to expand 5 or 6
1121090284Sobrien     HImode insns, we'd be swallowed in word prefix ops.  */
1121190284Sobrien
11212132743Skan  if ((mode != HImode || TARGET_FAST_PREFIX)
11213169705Skan      && (mode != (TARGET_64BIT ? TImode : DImode))
1121490284Sobrien      && GET_CODE (operands[2]) == CONST_INT
1121590284Sobrien      && GET_CODE (operands[3]) == CONST_INT)
1121690284Sobrien    {
1121790284Sobrien      rtx out = operands[0];
1121890284Sobrien      HOST_WIDE_INT ct = INTVAL (operands[2]);
1121990284Sobrien      HOST_WIDE_INT cf = INTVAL (operands[3]);
1122090284Sobrien      HOST_WIDE_INT diff;
1122190284Sobrien
11222132743Skan      diff = ct - cf;
11223132743Skan      /*  Sign bit compares are better done using shifts than we do by using
11224132743Skan	  sbb.  */
11225132743Skan      if (sign_bit_compare_p
11226132743Skan	  || ix86_expand_carry_flag_compare (code, ix86_compare_op0,
11227132743Skan					     ix86_compare_op1, &compare_op))
1122851411Sobrien	{
1122990284Sobrien	  /* Detect overlap between destination and compare sources.  */
1123090284Sobrien	  rtx tmp = out;
1123190284Sobrien
11232132743Skan          if (!sign_bit_compare_p)
1123390284Sobrien	    {
11234132743Skan	      bool fpcmp = false;
1123590284Sobrien
11236132743Skan	      compare_code = GET_CODE (compare_op);
1123790284Sobrien
11238132743Skan	      if (GET_MODE (XEXP (compare_op, 0)) == CCFPmode
11239132743Skan		  || GET_MODE (XEXP (compare_op, 0)) == CCFPUmode)
11240132743Skan		{
11241132743Skan		  fpcmp = true;
11242132743Skan		  compare_code = ix86_fp_compare_code_to_integer (compare_code);
11243132743Skan		}
11244132743Skan
11245132743Skan	      /* To simplify rest of code, restrict to the GEU case.  */
11246132743Skan	      if (compare_code == LTU)
11247132743Skan		{
11248132743Skan		  HOST_WIDE_INT tmp = ct;
11249132743Skan		  ct = cf;
11250132743Skan		  cf = tmp;
11251132743Skan		  compare_code = reverse_condition (compare_code);
11252132743Skan		  code = reverse_condition (code);
11253132743Skan		}
11254132743Skan	      else
11255132743Skan		{
11256132743Skan		  if (fpcmp)
11257132743Skan		    PUT_CODE (compare_op,
11258132743Skan			      reverse_condition_maybe_unordered
11259132743Skan			        (GET_CODE (compare_op)));
11260132743Skan		  else
11261132743Skan		    PUT_CODE (compare_op, reverse_condition (GET_CODE (compare_op)));
11262132743Skan		}
11263132743Skan	      diff = ct - cf;
11264132743Skan
11265132743Skan	      if (reg_overlap_mentioned_p (out, ix86_compare_op0)
11266132743Skan		  || reg_overlap_mentioned_p (out, ix86_compare_op1))
11267132743Skan		tmp = gen_reg_rtx (mode);
11268132743Skan
11269132743Skan	      if (mode == DImode)
11270132743Skan		emit_insn (gen_x86_movdicc_0_m1_rex64 (tmp, compare_op));
11271132743Skan	      else
11272132743Skan		emit_insn (gen_x86_movsicc_0_m1 (gen_lowpart (SImode, tmp), compare_op));
11273132743Skan	    }
1127451411Sobrien	  else
11275132743Skan	    {
11276132743Skan	      if (code == GT || code == GE)
11277132743Skan		code = reverse_condition (code);
11278132743Skan	      else
11279132743Skan		{
11280132743Skan		  HOST_WIDE_INT tmp = ct;
11281132743Skan		  ct = cf;
11282132743Skan		  cf = tmp;
11283132743Skan		  diff = ct - cf;
11284132743Skan		}
11285132743Skan	      tmp = emit_store_flag (tmp, code, ix86_compare_op0,
11286132743Skan				     ix86_compare_op1, VOIDmode, 0, -1);
11287132743Skan	    }
1128851411Sobrien
1128990284Sobrien	  if (diff == 1)
1129090284Sobrien	    {
1129190284Sobrien	      /*
1129290284Sobrien	       * cmpl op0,op1
1129390284Sobrien	       * sbbl dest,dest
1129490284Sobrien	       * [addl dest, ct]
1129590284Sobrien	       *
1129690284Sobrien	       * Size 5 - 8.
1129790284Sobrien	       */
1129890284Sobrien	      if (ct)
11299132743Skan		tmp = expand_simple_binop (mode, PLUS,
1130090284Sobrien					   tmp, GEN_INT (ct),
11301132743Skan					   copy_rtx (tmp), 1, OPTAB_DIRECT);
1130290284Sobrien	    }
1130390284Sobrien	  else if (cf == -1)
1130490284Sobrien	    {
1130590284Sobrien	      /*
1130690284Sobrien	       * cmpl op0,op1
1130790284Sobrien	       * sbbl dest,dest
1130890284Sobrien	       * orl $ct, dest
1130990284Sobrien	       *
1131090284Sobrien	       * Size 8.
1131190284Sobrien	       */
1131290284Sobrien	      tmp = expand_simple_binop (mode, IOR,
1131390284Sobrien					 tmp, GEN_INT (ct),
11314132743Skan					 copy_rtx (tmp), 1, OPTAB_DIRECT);
1131590284Sobrien	    }
1131690284Sobrien	  else if (diff == -1 && ct)
1131790284Sobrien	    {
1131890284Sobrien	      /*
1131990284Sobrien	       * cmpl op0,op1
1132090284Sobrien	       * sbbl dest,dest
11321117408Skan	       * notl dest
1132290284Sobrien	       * [addl dest, cf]
1132390284Sobrien	       *
1132490284Sobrien	       * Size 8 - 11.
1132590284Sobrien	       */
11326132743Skan	      tmp = expand_simple_unop (mode, NOT, tmp, copy_rtx (tmp), 1);
1132790284Sobrien	      if (cf)
11328132743Skan		tmp = expand_simple_binop (mode, PLUS,
11329132743Skan					   copy_rtx (tmp), GEN_INT (cf),
11330132743Skan					   copy_rtx (tmp), 1, OPTAB_DIRECT);
1133190284Sobrien	    }
1133251411Sobrien	  else
1133390284Sobrien	    {
1133490284Sobrien	      /*
1133590284Sobrien	       * cmpl op0,op1
1133690284Sobrien	       * sbbl dest,dest
11337117408Skan	       * [notl dest]
1133890284Sobrien	       * andl cf - ct, dest
1133990284Sobrien	       * [addl dest, ct]
1134090284Sobrien	       *
1134190284Sobrien	       * Size 8 - 11.
1134290284Sobrien	       */
11343117408Skan
11344117408Skan	      if (cf == 0)
11345117408Skan		{
11346117408Skan		  cf = ct;
11347117408Skan		  ct = 0;
11348132743Skan		  tmp = expand_simple_unop (mode, NOT, tmp, copy_rtx (tmp), 1);
11349117408Skan		}
11350117408Skan
1135190284Sobrien	      tmp = expand_simple_binop (mode, AND,
11352132743Skan					 copy_rtx (tmp),
11353117408Skan					 gen_int_mode (cf - ct, mode),
11354132743Skan					 copy_rtx (tmp), 1, OPTAB_DIRECT);
1135590284Sobrien	      if (ct)
11356132743Skan		tmp = expand_simple_binop (mode, PLUS,
11357132743Skan					   copy_rtx (tmp), GEN_INT (ct),
11358132743Skan					   copy_rtx (tmp), 1, OPTAB_DIRECT);
1135990284Sobrien	    }
1136090284Sobrien
11361132743Skan	  if (!rtx_equal_p (tmp, out))
11362132743Skan	    emit_move_insn (copy_rtx (out), copy_rtx (tmp));
1136390284Sobrien
1136490284Sobrien	  return 1; /* DONE */
1136551411Sobrien	}
1136651411Sobrien
1136790284Sobrien      if (diff < 0)
1136851411Sobrien	{
1136990284Sobrien	  HOST_WIDE_INT tmp;
1137090284Sobrien	  tmp = ct, ct = cf, cf = tmp;
1137190284Sobrien	  diff = -diff;
1137290284Sobrien	  if (FLOAT_MODE_P (GET_MODE (ix86_compare_op0)))
1137351411Sobrien	    {
1137490284Sobrien	      /* We may be reversing unordered compare to normal compare, that
1137590284Sobrien		 is not valid in general (we may convert non-trapping condition
1137690284Sobrien		 to trapping one), however on i386 we currently emit all
1137790284Sobrien		 comparisons unordered.  */
1137890284Sobrien	      compare_code = reverse_condition_maybe_unordered (compare_code);
1137990284Sobrien	      code = reverse_condition_maybe_unordered (code);
1138051411Sobrien	    }
1138151411Sobrien	  else
1138251411Sobrien	    {
1138390284Sobrien	      compare_code = reverse_condition (compare_code);
1138490284Sobrien	      code = reverse_condition (code);
1138551411Sobrien	    }
1138651411Sobrien	}
11387117408Skan
11388169705Skan      compare_code = UNKNOWN;
11389117408Skan      if (GET_MODE_CLASS (GET_MODE (ix86_compare_op0)) == MODE_INT
11390117408Skan	  && GET_CODE (ix86_compare_op1) == CONST_INT)
11391117408Skan	{
11392117408Skan	  if (ix86_compare_op1 == const0_rtx
11393117408Skan	      && (code == LT || code == GE))
11394117408Skan	    compare_code = code;
11395117408Skan	  else if (ix86_compare_op1 == constm1_rtx)
11396117408Skan	    {
11397117408Skan	      if (code == LE)
11398117408Skan		compare_code = LT;
11399117408Skan	      else if (code == GT)
11400117408Skan		compare_code = GE;
11401117408Skan	    }
11402117408Skan	}
11403117408Skan
11404117408Skan      /* Optimize dest = (op0 < 0) ? -1 : cf.  */
11405169705Skan      if (compare_code != UNKNOWN
11406117408Skan	  && GET_MODE (ix86_compare_op0) == GET_MODE (out)
11407117408Skan	  && (cf == -1 || ct == -1))
11408117408Skan	{
11409117408Skan	  /* If lea code below could be used, only optimize
11410117408Skan	     if it results in a 2 insn sequence.  */
11411117408Skan
11412117408Skan	  if (! (diff == 1 || diff == 2 || diff == 4 || diff == 8
11413117408Skan		 || diff == 3 || diff == 5 || diff == 9)
11414117408Skan	      || (compare_code == LT && ct == -1)
11415117408Skan	      || (compare_code == GE && cf == -1))
11416117408Skan	    {
11417117408Skan	      /*
11418117408Skan	       * notl op1	(if necessary)
11419117408Skan	       * sarl $31, op1
11420117408Skan	       * orl cf, op1
11421117408Skan	       */
11422117408Skan	      if (ct != -1)
11423117408Skan		{
11424117408Skan		  cf = ct;
11425132743Skan		  ct = -1;
11426117408Skan		  code = reverse_condition (code);
11427117408Skan		}
11428117408Skan
11429117408Skan	      out = emit_store_flag (out, code, ix86_compare_op0,
11430117408Skan				     ix86_compare_op1, VOIDmode, 0, -1);
11431117408Skan
11432117408Skan	      out = expand_simple_binop (mode, IOR,
11433117408Skan					 out, GEN_INT (cf),
11434117408Skan					 out, 1, OPTAB_DIRECT);
11435117408Skan	      if (out != operands[0])
11436117408Skan		emit_move_insn (operands[0], out);
11437117408Skan
11438117408Skan	      return 1; /* DONE */
11439117408Skan	    }
11440117408Skan	}
11441117408Skan
11442132743Skan
1144390284Sobrien      if ((diff == 1 || diff == 2 || diff == 4 || diff == 8
1144490284Sobrien	   || diff == 3 || diff == 5 || diff == 9)
11445132743Skan	  && ((mode != QImode && mode != HImode) || !TARGET_PARTIAL_REG_STALL)
11446169705Skan	  && (mode != DImode
11447169705Skan	      || x86_64_immediate_operand (GEN_INT (cf), VOIDmode)))
1144890284Sobrien	{
1144990284Sobrien	  /*
1145090284Sobrien	   * xorl dest,dest
1145190284Sobrien	   * cmpl op1,op2
1145290284Sobrien	   * setcc dest
1145390284Sobrien	   * lea cf(dest*(ct-cf)),dest
1145490284Sobrien	   *
1145590284Sobrien	   * Size 14.
1145690284Sobrien	   *
1145790284Sobrien	   * This also catches the degenerate setcc-only case.
1145890284Sobrien	   */
1145951411Sobrien
1146090284Sobrien	  rtx tmp;
1146190284Sobrien	  int nops;
1146290284Sobrien
1146390284Sobrien	  out = emit_store_flag (out, code, ix86_compare_op0,
1146490284Sobrien				 ix86_compare_op1, VOIDmode, 0, 1);
1146590284Sobrien
1146690284Sobrien	  nops = 0;
11467117408Skan	  /* On x86_64 the lea instruction operates on Pmode, so we need
11468117408Skan	     to get arithmetics done in proper mode to match.  */
1146990284Sobrien	  if (diff == 1)
11470117408Skan	    tmp = copy_rtx (out);
1147190284Sobrien	  else
1147251411Sobrien	    {
1147390284Sobrien	      rtx out1;
11474117408Skan	      out1 = copy_rtx (out);
1147590284Sobrien	      tmp = gen_rtx_MULT (mode, out1, GEN_INT (diff & ~1));
1147690284Sobrien	      nops++;
1147790284Sobrien	      if (diff & 1)
1147890284Sobrien		{
1147990284Sobrien		  tmp = gen_rtx_PLUS (mode, tmp, out1);
1148090284Sobrien		  nops++;
1148190284Sobrien		}
1148251411Sobrien	    }
1148390284Sobrien	  if (cf != 0)
1148490284Sobrien	    {
1148590284Sobrien	      tmp = gen_rtx_PLUS (mode, tmp, GEN_INT (cf));
1148690284Sobrien	      nops++;
1148790284Sobrien	    }
11488132743Skan	  if (!rtx_equal_p (tmp, out))
1148990284Sobrien	    {
1149090284Sobrien	      if (nops == 1)
11491117408Skan		out = force_operand (tmp, copy_rtx (out));
1149290284Sobrien	      else
11493117408Skan		emit_insn (gen_rtx_SET (VOIDmode, copy_rtx (out), copy_rtx (tmp)));
1149490284Sobrien	    }
11495132743Skan	  if (!rtx_equal_p (out, operands[0]))
11496117408Skan	    emit_move_insn (operands[0], copy_rtx (out));
1149790284Sobrien
1149890284Sobrien	  return 1; /* DONE */
1149951411Sobrien	}
1150090284Sobrien
1150190284Sobrien      /*
1150290284Sobrien       * General case:			Jumpful:
1150390284Sobrien       *   xorl dest,dest		cmpl op1, op2
1150490284Sobrien       *   cmpl op1, op2		movl ct, dest
1150590284Sobrien       *   setcc dest			jcc 1f
1150690284Sobrien       *   decl dest			movl cf, dest
1150790284Sobrien       *   andl (cf-ct),dest		1:
1150890284Sobrien       *   addl ct,dest
1150990284Sobrien       *
1151090284Sobrien       * Size 20.			Size 14.
1151190284Sobrien       *
1151290284Sobrien       * This is reasonably steep, but branch mispredict costs are
1151390284Sobrien       * high on modern cpus, so consider failing only if optimizing
1151490284Sobrien       * for space.
1151590284Sobrien       */
1151690284Sobrien
11517132743Skan      if ((!TARGET_CMOVE || (mode == QImode && TARGET_PARTIAL_REG_STALL))
11518132743Skan	  && BRANCH_COST >= 2)
1151951411Sobrien	{
11520117408Skan	  if (cf == 0)
1152190284Sobrien	    {
11522117408Skan	      cf = ct;
11523117408Skan	      ct = 0;
1152490284Sobrien	      if (FLOAT_MODE_P (GET_MODE (ix86_compare_op0)))
11525117408Skan		/* We may be reversing unordered compare to normal compare,
11526117408Skan		   that is not valid in general (we may convert non-trapping
11527117408Skan		   condition to trapping one), however on i386 we currently
11528117408Skan		   emit all comparisons unordered.  */
11529117408Skan		code = reverse_condition_maybe_unordered (code);
11530117408Skan	      else
1153190284Sobrien		{
11532117408Skan		  code = reverse_condition (code);
11533169705Skan		  if (compare_code != UNKNOWN)
11534117408Skan		    compare_code = reverse_condition (compare_code);
1153590284Sobrien		}
11536117408Skan	    }
11537117408Skan
11538169705Skan	  if (compare_code != UNKNOWN)
11539117408Skan	    {
11540117408Skan	      /* notl op1	(if needed)
11541117408Skan		 sarl $31, op1
11542117408Skan		 andl (cf-ct), op1
11543132743Skan		 addl ct, op1
11544117408Skan
11545117408Skan		 For x < 0 (resp. x <= -1) there will be no notl,
11546117408Skan		 so if possible swap the constants to get rid of the
11547117408Skan		 complement.
11548117408Skan		 True/false will be -1/0 while code below (store flag
11549117408Skan		 followed by decrement) is 0/-1, so the constants need
11550117408Skan		 to be exchanged once more.  */
11551117408Skan
11552117408Skan	      if (compare_code == GE || !cf)
11553117408Skan		{
11554132743Skan		  code = reverse_condition (code);
11555117408Skan		  compare_code = LT;
11556117408Skan		}
1155790284Sobrien	      else
1155890284Sobrien		{
11559117408Skan		  HOST_WIDE_INT tmp = cf;
11560132743Skan		  cf = ct;
11561117408Skan		  ct = tmp;
1156290284Sobrien		}
11563117408Skan
11564117408Skan	      out = emit_store_flag (out, code, ix86_compare_op0,
11565117408Skan				     ix86_compare_op1, VOIDmode, 0, -1);
1156690284Sobrien	    }
11567117408Skan	  else
11568117408Skan	    {
11569117408Skan	      out = emit_store_flag (out, code, ix86_compare_op0,
11570117408Skan				     ix86_compare_op1, VOIDmode, 0, 1);
1157190284Sobrien
11572132743Skan	      out = expand_simple_binop (mode, PLUS, copy_rtx (out), constm1_rtx,
11573132743Skan					 copy_rtx (out), 1, OPTAB_DIRECT);
11574117408Skan	    }
1157590284Sobrien
11576132743Skan	  out = expand_simple_binop (mode, AND, copy_rtx (out),
11577117408Skan				     gen_int_mode (cf - ct, mode),
11578132743Skan				     copy_rtx (out), 1, OPTAB_DIRECT);
11579117408Skan	  if (ct)
11580132743Skan	    out = expand_simple_binop (mode, PLUS, copy_rtx (out), GEN_INT (ct),
11581132743Skan				       copy_rtx (out), 1, OPTAB_DIRECT);
11582132743Skan	  if (!rtx_equal_p (out, operands[0]))
11583132743Skan	    emit_move_insn (operands[0], copy_rtx (out));
1158490284Sobrien
1158590284Sobrien	  return 1; /* DONE */
1158651411Sobrien	}
1158751411Sobrien    }
1158890284Sobrien
11589132743Skan  if (!TARGET_CMOVE || (mode == QImode && TARGET_PARTIAL_REG_STALL))
1159051411Sobrien    {
1159190284Sobrien      /* Try a few things more with specific constants and a variable.  */
1159251411Sobrien
1159390284Sobrien      optab op;
1159490284Sobrien      rtx var, orig_out, out, tmp;
1159590284Sobrien
11596132743Skan      if (BRANCH_COST <= 2)
1159790284Sobrien	return 0; /* FAIL */
1159890284Sobrien
1159990284Sobrien      /* If one of the two operands is an interesting constant, load a
1160090284Sobrien	 constant with the above and mask it in with a logical operation.  */
1160190284Sobrien
1160290284Sobrien      if (GET_CODE (operands[2]) == CONST_INT)
1160351411Sobrien	{
1160490284Sobrien	  var = operands[3];
11605132743Skan	  if (INTVAL (operands[2]) == 0 && operands[3] != constm1_rtx)
1160690284Sobrien	    operands[3] = constm1_rtx, op = and_optab;
11607132743Skan	  else if (INTVAL (operands[2]) == -1 && operands[3] != const0_rtx)
1160890284Sobrien	    operands[3] = const0_rtx, op = ior_optab;
1160990284Sobrien	  else
1161090284Sobrien	    return 0; /* FAIL */
1161151411Sobrien	}
1161290284Sobrien      else if (GET_CODE (operands[3]) == CONST_INT)
1161390284Sobrien	{
1161490284Sobrien	  var = operands[2];
11615132743Skan	  if (INTVAL (operands[3]) == 0 && operands[2] != constm1_rtx)
1161690284Sobrien	    operands[2] = constm1_rtx, op = and_optab;
11617132743Skan	  else if (INTVAL (operands[3]) == -1 && operands[3] != const0_rtx)
1161890284Sobrien	    operands[2] = const0_rtx, op = ior_optab;
1161990284Sobrien	  else
1162090284Sobrien	    return 0; /* FAIL */
1162190284Sobrien	}
1162290284Sobrien      else
1162390284Sobrien        return 0; /* FAIL */
1162451411Sobrien
1162590284Sobrien      orig_out = operands[0];
1162690284Sobrien      tmp = gen_reg_rtx (mode);
1162790284Sobrien      operands[0] = tmp;
1162851411Sobrien
1162990284Sobrien      /* Recurse to get the constant loaded.  */
1163090284Sobrien      if (ix86_expand_int_movcc (operands) == 0)
1163190284Sobrien        return 0; /* FAIL */
1163251411Sobrien
1163390284Sobrien      /* Mask in the interesting variable.  */
1163490284Sobrien      out = expand_binop (mode, op, var, tmp, orig_out, 0,
1163590284Sobrien			  OPTAB_WIDEN);
11636132743Skan      if (!rtx_equal_p (out, orig_out))
11637132743Skan	emit_move_insn (copy_rtx (orig_out), copy_rtx (out));
1163851411Sobrien
1163990284Sobrien      return 1; /* DONE */
1164051411Sobrien    }
1164151411Sobrien
1164290284Sobrien  /*
1164390284Sobrien   * For comparison with above,
1164490284Sobrien   *
1164590284Sobrien   * movl cf,dest
1164690284Sobrien   * movl ct,tmp
1164790284Sobrien   * cmpl op1,op2
1164890284Sobrien   * cmovcc tmp,dest
1164990284Sobrien   *
1165090284Sobrien   * Size 15.
1165190284Sobrien   */
1165290284Sobrien
1165390284Sobrien  if (! nonimmediate_operand (operands[2], mode))
1165490284Sobrien    operands[2] = force_reg (mode, operands[2]);
1165590284Sobrien  if (! nonimmediate_operand (operands[3], mode))
1165690284Sobrien    operands[3] = force_reg (mode, operands[3]);
1165790284Sobrien
1165890284Sobrien  if (bypass_test && reg_overlap_mentioned_p (operands[0], operands[3]))
1165951411Sobrien    {
1166090284Sobrien      rtx tmp = gen_reg_rtx (mode);
1166190284Sobrien      emit_move_insn (tmp, operands[3]);
1166290284Sobrien      operands[3] = tmp;
1166351411Sobrien    }
1166490284Sobrien  if (second_test && reg_overlap_mentioned_p (operands[0], operands[2]))
1166551411Sobrien    {
1166690284Sobrien      rtx tmp = gen_reg_rtx (mode);
1166790284Sobrien      emit_move_insn (tmp, operands[2]);
1166890284Sobrien      operands[2] = tmp;
1166951411Sobrien    }
11670132743Skan
1167190284Sobrien  if (! register_operand (operands[2], VOIDmode)
11672132743Skan      && (mode == QImode
11673132743Skan          || ! register_operand (operands[3], VOIDmode)))
1167490284Sobrien    operands[2] = force_reg (mode, operands[2]);
1167551411Sobrien
11676132743Skan  if (mode == QImode
11677132743Skan      && ! register_operand (operands[3], VOIDmode))
11678132743Skan    operands[3] = force_reg (mode, operands[3]);
11679132743Skan
1168090284Sobrien  emit_insn (compare_seq);
1168190284Sobrien  emit_insn (gen_rtx_SET (VOIDmode, operands[0],
1168290284Sobrien			  gen_rtx_IF_THEN_ELSE (mode,
1168390284Sobrien						compare_op, operands[2],
1168490284Sobrien						operands[3])));
1168590284Sobrien  if (bypass_test)
11686132743Skan    emit_insn (gen_rtx_SET (VOIDmode, copy_rtx (operands[0]),
1168790284Sobrien			    gen_rtx_IF_THEN_ELSE (mode,
1168890284Sobrien				  bypass_test,
11689132743Skan				  copy_rtx (operands[3]),
11690132743Skan				  copy_rtx (operands[0]))));
1169190284Sobrien  if (second_test)
11692132743Skan    emit_insn (gen_rtx_SET (VOIDmode, copy_rtx (operands[0]),
1169390284Sobrien			    gen_rtx_IF_THEN_ELSE (mode,
1169490284Sobrien				  second_test,
11695132743Skan				  copy_rtx (operands[2]),
11696132743Skan				  copy_rtx (operands[0]))));
1169790284Sobrien
1169890284Sobrien  return 1; /* DONE */
1169990284Sobrien}
1170090284Sobrien
11701169705Skan/* Swap, force into registers, or otherwise massage the two operands
11702169705Skan   to an sse comparison with a mask result.  Thus we differ a bit from
11703169705Skan   ix86_prepare_fp_compare_args which expects to produce a flags result.
11704169705Skan
11705169705Skan   The DEST operand exists to help determine whether to commute commutative
11706169705Skan   operators.  The POP0/POP1 operands are updated in place.  The new
11707169705Skan   comparison code is returned, or UNKNOWN if not implementable.  */
11708169705Skan
11709169705Skanstatic enum rtx_code
11710169705Skanix86_prepare_sse_fp_compare_args (rtx dest, enum rtx_code code,
11711169705Skan				  rtx *pop0, rtx *pop1)
11712169705Skan{
11713169705Skan  rtx tmp;
11714169705Skan
11715169705Skan  switch (code)
11716169705Skan    {
11717169705Skan    case LTGT:
11718169705Skan    case UNEQ:
11719169705Skan      /* We have no LTGT as an operator.  We could implement it with
11720169705Skan	 NE & ORDERED, but this requires an extra temporary.  It's
11721169705Skan	 not clear that it's worth it.  */
11722169705Skan      return UNKNOWN;
11723169705Skan
11724169705Skan    case LT:
11725169705Skan    case LE:
11726169705Skan    case UNGT:
11727169705Skan    case UNGE:
11728169705Skan      /* These are supported directly.  */
11729169705Skan      break;
11730169705Skan
11731169705Skan    case EQ:
11732169705Skan    case NE:
11733169705Skan    case UNORDERED:
11734169705Skan    case ORDERED:
11735169705Skan      /* For commutative operators, try to canonicalize the destination
11736169705Skan	 operand to be first in the comparison - this helps reload to
11737169705Skan	 avoid extra moves.  */
11738169705Skan      if (!dest || !rtx_equal_p (dest, *pop1))
11739169705Skan	break;
11740169705Skan      /* FALLTHRU */
11741169705Skan
11742169705Skan    case GE:
11743169705Skan    case GT:
11744169705Skan    case UNLE:
11745169705Skan    case UNLT:
11746169705Skan      /* These are not supported directly.  Swap the comparison operands
11747169705Skan	 to transform into something that is supported.  */
11748169705Skan      tmp = *pop0;
11749169705Skan      *pop0 = *pop1;
11750169705Skan      *pop1 = tmp;
11751169705Skan      code = swap_condition (code);
11752169705Skan      break;
11753169705Skan
11754169705Skan    default:
11755169705Skan      gcc_unreachable ();
11756169705Skan    }
11757169705Skan
11758169705Skan  return code;
11759169705Skan}
11760169705Skan
11761169705Skan/* Detect conditional moves that exactly match min/max operational
11762169705Skan   semantics.  Note that this is IEEE safe, as long as we don't
11763169705Skan   interchange the operands.
11764169705Skan
11765169705Skan   Returns FALSE if this conditional move doesn't match a MIN/MAX,
11766169705Skan   and TRUE if the operation is successful and instructions are emitted.  */
11767169705Skan
11768169705Skanstatic bool
11769169705Skanix86_expand_sse_fp_minmax (rtx dest, enum rtx_code code, rtx cmp_op0,
11770169705Skan			   rtx cmp_op1, rtx if_true, rtx if_false)
11771169705Skan{
11772169705Skan  enum machine_mode mode;
11773169705Skan  bool is_min;
11774169705Skan  rtx tmp;
11775169705Skan
11776169705Skan  if (code == LT)
11777169705Skan    ;
11778169705Skan  else if (code == UNGE)
11779169705Skan    {
11780169705Skan      tmp = if_true;
11781169705Skan      if_true = if_false;
11782169705Skan      if_false = tmp;
11783169705Skan    }
11784169705Skan  else
11785169705Skan    return false;
11786169705Skan
11787169705Skan  if (rtx_equal_p (cmp_op0, if_true) && rtx_equal_p (cmp_op1, if_false))
11788169705Skan    is_min = true;
11789169705Skan  else if (rtx_equal_p (cmp_op1, if_true) && rtx_equal_p (cmp_op0, if_false))
11790169705Skan    is_min = false;
11791169705Skan  else
11792169705Skan    return false;
11793169705Skan
11794169705Skan  mode = GET_MODE (dest);
11795169705Skan
11796169705Skan  /* We want to check HONOR_NANS and HONOR_SIGNED_ZEROS here,
11797169705Skan     but MODE may be a vector mode and thus not appropriate.  */
11798169705Skan  if (!flag_finite_math_only || !flag_unsafe_math_optimizations)
11799169705Skan    {
11800169705Skan      int u = is_min ? UNSPEC_IEEE_MIN : UNSPEC_IEEE_MAX;
11801169705Skan      rtvec v;
11802169705Skan
11803169705Skan      if_true = force_reg (mode, if_true);
11804169705Skan      v = gen_rtvec (2, if_true, if_false);
11805169705Skan      tmp = gen_rtx_UNSPEC (mode, v, u);
11806169705Skan    }
11807169705Skan  else
11808169705Skan    {
11809169705Skan      code = is_min ? SMIN : SMAX;
11810169705Skan      tmp = gen_rtx_fmt_ee (code, mode, if_true, if_false);
11811169705Skan    }
11812169705Skan
11813169705Skan  emit_insn (gen_rtx_SET (VOIDmode, dest, tmp));
11814169705Skan  return true;
11815169705Skan}
11816169705Skan
11817169705Skan/* Expand an sse vector comparison.  Return the register with the result.  */
11818169705Skan
11819169705Skanstatic rtx
11820169705Skanix86_expand_sse_cmp (rtx dest, enum rtx_code code, rtx cmp_op0, rtx cmp_op1,
11821169705Skan		     rtx op_true, rtx op_false)
11822169705Skan{
11823169705Skan  enum machine_mode mode = GET_MODE (dest);
11824169705Skan  rtx x;
11825169705Skan
11826169705Skan  cmp_op0 = force_reg (mode, cmp_op0);
11827169705Skan  if (!nonimmediate_operand (cmp_op1, mode))
11828169705Skan    cmp_op1 = force_reg (mode, cmp_op1);
11829169705Skan
11830169705Skan  if (optimize
11831169705Skan      || reg_overlap_mentioned_p (dest, op_true)
11832169705Skan      || reg_overlap_mentioned_p (dest, op_false))
11833169705Skan    dest = gen_reg_rtx (mode);
11834169705Skan
11835169705Skan  x = gen_rtx_fmt_ee (code, mode, cmp_op0, cmp_op1);
11836169705Skan  emit_insn (gen_rtx_SET (VOIDmode, dest, x));
11837169705Skan
11838169705Skan  return dest;
11839169705Skan}
11840169705Skan
11841169705Skan/* Expand DEST = CMP ? OP_TRUE : OP_FALSE into a sequence of logical
11842169705Skan   operations.  This is used for both scalar and vector conditional moves.  */
11843169705Skan
11844169705Skanstatic void
11845169705Skanix86_expand_sse_movcc (rtx dest, rtx cmp, rtx op_true, rtx op_false)
11846169705Skan{
11847169705Skan  enum machine_mode mode = GET_MODE (dest);
11848169705Skan  rtx t2, t3, x;
11849169705Skan
11850169705Skan  if (op_false == CONST0_RTX (mode))
11851169705Skan    {
11852169705Skan      op_true = force_reg (mode, op_true);
11853169705Skan      x = gen_rtx_AND (mode, cmp, op_true);
11854169705Skan      emit_insn (gen_rtx_SET (VOIDmode, dest, x));
11855169705Skan    }
11856169705Skan  else if (op_true == CONST0_RTX (mode))
11857169705Skan    {
11858169705Skan      op_false = force_reg (mode, op_false);
11859169705Skan      x = gen_rtx_NOT (mode, cmp);
11860169705Skan      x = gen_rtx_AND (mode, x, op_false);
11861169705Skan      emit_insn (gen_rtx_SET (VOIDmode, dest, x));
11862169705Skan    }
11863169705Skan  else
11864169705Skan    {
11865169705Skan      op_true = force_reg (mode, op_true);
11866169705Skan      op_false = force_reg (mode, op_false);
11867169705Skan
11868169705Skan      t2 = gen_reg_rtx (mode);
11869169705Skan      if (optimize)
11870169705Skan	t3 = gen_reg_rtx (mode);
11871169705Skan      else
11872169705Skan	t3 = dest;
11873169705Skan
11874169705Skan      x = gen_rtx_AND (mode, op_true, cmp);
11875169705Skan      emit_insn (gen_rtx_SET (VOIDmode, t2, x));
11876169705Skan
11877169705Skan      x = gen_rtx_NOT (mode, cmp);
11878169705Skan      x = gen_rtx_AND (mode, x, op_false);
11879169705Skan      emit_insn (gen_rtx_SET (VOIDmode, t3, x));
11880169705Skan
11881169705Skan      x = gen_rtx_IOR (mode, t3, t2);
11882169705Skan      emit_insn (gen_rtx_SET (VOIDmode, dest, x));
11883169705Skan    }
11884169705Skan}
11885169705Skan
11886169705Skan/* Expand a floating-point conditional move.  Return true if successful.  */
11887169705Skan
1188890284Sobrienint
11889132743Skanix86_expand_fp_movcc (rtx operands[])
1189090284Sobrien{
11891169705Skan  enum machine_mode mode = GET_MODE (operands[0]);
11892169705Skan  enum rtx_code code = GET_CODE (operands[1]);
11893169705Skan  rtx tmp, compare_op, second_test, bypass_test;
1189490284Sobrien
11895169705Skan  if (TARGET_SSE_MATH && SSE_FLOAT_MODE_P (mode))
1189651411Sobrien    {
11897169705Skan      enum machine_mode cmode;
1189851411Sobrien
11899169705Skan      /* Since we've no cmove for sse registers, don't force bad register
11900169705Skan	 allocation just to gain access to it.  Deny movcc when the
11901169705Skan	 comparison mode doesn't match the move mode.  */
11902169705Skan      cmode = GET_MODE (ix86_compare_op0);
11903169705Skan      if (cmode == VOIDmode)
11904169705Skan	cmode = GET_MODE (ix86_compare_op1);
11905169705Skan      if (cmode != mode)
11906169705Skan	return 0;
11907169705Skan
11908169705Skan      code = ix86_prepare_sse_fp_compare_args (operands[0], code,
11909169705Skan					       &ix86_compare_op0,
11910169705Skan					       &ix86_compare_op1);
11911169705Skan      if (code == UNKNOWN)
11912169705Skan	return 0;
11913169705Skan
11914169705Skan      if (ix86_expand_sse_fp_minmax (operands[0], code, ix86_compare_op0,
11915169705Skan				     ix86_compare_op1, operands[2],
11916169705Skan				     operands[3]))
11917169705Skan	return 1;
11918169705Skan
11919169705Skan      tmp = ix86_expand_sse_cmp (operands[0], code, ix86_compare_op0,
11920169705Skan				 ix86_compare_op1, operands[2], operands[3]);
11921169705Skan      ix86_expand_sse_movcc (operands[0], tmp, operands[2], operands[3]);
1192290284Sobrien      return 1;
1192351411Sobrien    }
1192451411Sobrien
1192590284Sobrien  /* The floating point conditional move instructions don't directly
1192690284Sobrien     support conditions resulting from a signed integer comparison.  */
1192790284Sobrien
1192890284Sobrien  compare_op = ix86_expand_compare (code, &second_test, &bypass_test);
1192990284Sobrien
1193090284Sobrien  /* The floating point conditional move instructions don't directly
1193190284Sobrien     support signed integer comparisons.  */
1193290284Sobrien
1193390284Sobrien  if (!fcmov_comparison_operator (compare_op, VOIDmode))
1193451411Sobrien    {
11935169705Skan      gcc_assert (!second_test && !bypass_test);
1193690284Sobrien      tmp = gen_reg_rtx (QImode);
1193790284Sobrien      ix86_expand_setcc (code, tmp);
1193890284Sobrien      code = NE;
1193990284Sobrien      ix86_compare_op0 = tmp;
1194090284Sobrien      ix86_compare_op1 = const0_rtx;
1194190284Sobrien      compare_op = ix86_expand_compare (code,  &second_test, &bypass_test);
1194251411Sobrien    }
1194390284Sobrien  if (bypass_test && reg_overlap_mentioned_p (operands[0], operands[3]))
1194490284Sobrien    {
11945169705Skan      tmp = gen_reg_rtx (mode);
1194690284Sobrien      emit_move_insn (tmp, operands[3]);
1194790284Sobrien      operands[3] = tmp;
1194890284Sobrien    }
1194990284Sobrien  if (second_test && reg_overlap_mentioned_p (operands[0], operands[2]))
1195090284Sobrien    {
11951169705Skan      tmp = gen_reg_rtx (mode);
1195290284Sobrien      emit_move_insn (tmp, operands[2]);
1195390284Sobrien      operands[2] = tmp;
1195490284Sobrien    }
1195551411Sobrien
1195690284Sobrien  emit_insn (gen_rtx_SET (VOIDmode, operands[0],
11957169705Skan			  gen_rtx_IF_THEN_ELSE (mode, compare_op,
11958169705Skan						operands[2], operands[3])));
1195990284Sobrien  if (bypass_test)
1196090284Sobrien    emit_insn (gen_rtx_SET (VOIDmode, operands[0],
11961169705Skan			    gen_rtx_IF_THEN_ELSE (mode, bypass_test,
11962169705Skan						  operands[3], operands[0])));
1196390284Sobrien  if (second_test)
1196490284Sobrien    emit_insn (gen_rtx_SET (VOIDmode, operands[0],
11965169705Skan			    gen_rtx_IF_THEN_ELSE (mode, second_test,
11966169705Skan						  operands[2], operands[0])));
1196790284Sobrien
1196890284Sobrien  return 1;
1196990284Sobrien}
1197090284Sobrien
11971169705Skan/* Expand a floating-point vector conditional move; a vcond operation
11972169705Skan   rather than a movcc operation.  */
11973169705Skan
11974169705Skanbool
11975169705Skanix86_expand_fp_vcond (rtx operands[])
11976169705Skan{
11977169705Skan  enum rtx_code code = GET_CODE (operands[3]);
11978169705Skan  rtx cmp;
11979169705Skan
11980169705Skan  code = ix86_prepare_sse_fp_compare_args (operands[0], code,
11981169705Skan					   &operands[4], &operands[5]);
11982169705Skan  if (code == UNKNOWN)
11983169705Skan    return false;
11984169705Skan
11985169705Skan  if (ix86_expand_sse_fp_minmax (operands[0], code, operands[4],
11986169705Skan				 operands[5], operands[1], operands[2]))
11987169705Skan    return true;
11988169705Skan
11989169705Skan  cmp = ix86_expand_sse_cmp (operands[0], code, operands[4], operands[5],
11990169705Skan			     operands[1], operands[2]);
11991169705Skan  ix86_expand_sse_movcc (operands[0], cmp, operands[1], operands[2]);
11992169705Skan  return true;
11993169705Skan}
11994169705Skan
11995169705Skan/* Expand a signed integral vector conditional move.  */
11996169705Skan
11997169705Skanbool
11998169705Skanix86_expand_int_vcond (rtx operands[])
11999169705Skan{
12000169705Skan  enum machine_mode mode = GET_MODE (operands[0]);
12001169705Skan  enum rtx_code code = GET_CODE (operands[3]);
12002169705Skan  bool negate = false;
12003169705Skan  rtx x, cop0, cop1;
12004169705Skan
12005169705Skan  cop0 = operands[4];
12006169705Skan  cop1 = operands[5];
12007169705Skan
12008169705Skan  /* Canonicalize the comparison to EQ, GT, GTU.  */
12009169705Skan  switch (code)
12010169705Skan    {
12011169705Skan    case EQ:
12012169705Skan    case GT:
12013169705Skan    case GTU:
12014169705Skan      break;
12015169705Skan
12016169705Skan    case NE:
12017169705Skan    case LE:
12018169705Skan    case LEU:
12019169705Skan      code = reverse_condition (code);
12020169705Skan      negate = true;
12021169705Skan      break;
12022169705Skan
12023169705Skan    case GE:
12024169705Skan    case GEU:
12025169705Skan      code = reverse_condition (code);
12026169705Skan      negate = true;
12027169705Skan      /* FALLTHRU */
12028169705Skan
12029169705Skan    case LT:
12030169705Skan    case LTU:
12031169705Skan      code = swap_condition (code);
12032169705Skan      x = cop0, cop0 = cop1, cop1 = x;
12033169705Skan      break;
12034169705Skan
12035169705Skan    default:
12036169705Skan      gcc_unreachable ();
12037169705Skan    }
12038169705Skan
12039169705Skan  /* Unsigned parallel compare is not supported by the hardware.  Play some
12040169705Skan     tricks to turn this into a signed comparison against 0.  */
12041169705Skan  if (code == GTU)
12042169705Skan    {
12043169705Skan      cop0 = force_reg (mode, cop0);
12044169705Skan
12045169705Skan      switch (mode)
12046169705Skan	{
12047169705Skan	case V4SImode:
12048169705Skan	  {
12049169705Skan	    rtx t1, t2, mask;
12050169705Skan
12051169705Skan	    /* Perform a parallel modulo subtraction.  */
12052169705Skan	    t1 = gen_reg_rtx (mode);
12053169705Skan	    emit_insn (gen_subv4si3 (t1, cop0, cop1));
12054169705Skan
12055169705Skan	    /* Extract the original sign bit of op0.  */
12056169705Skan	    mask = GEN_INT (-0x80000000);
12057169705Skan	    mask = gen_rtx_CONST_VECTOR (mode,
12058169705Skan			gen_rtvec (4, mask, mask, mask, mask));
12059169705Skan	    mask = force_reg (mode, mask);
12060169705Skan	    t2 = gen_reg_rtx (mode);
12061169705Skan	    emit_insn (gen_andv4si3 (t2, cop0, mask));
12062169705Skan
12063169705Skan	    /* XOR it back into the result of the subtraction.  This results
12064169705Skan	       in the sign bit set iff we saw unsigned underflow.  */
12065169705Skan	    x = gen_reg_rtx (mode);
12066169705Skan	    emit_insn (gen_xorv4si3 (x, t1, t2));
12067169705Skan
12068169705Skan	    code = GT;
12069169705Skan	  }
12070169705Skan	  break;
12071169705Skan
12072169705Skan	case V16QImode:
12073169705Skan	case V8HImode:
12074169705Skan	  /* Perform a parallel unsigned saturating subtraction.  */
12075169705Skan	  x = gen_reg_rtx (mode);
12076169705Skan	  emit_insn (gen_rtx_SET (VOIDmode, x,
12077169705Skan				  gen_rtx_US_MINUS (mode, cop0, cop1)));
12078169705Skan
12079169705Skan	  code = EQ;
12080169705Skan	  negate = !negate;
12081169705Skan	  break;
12082169705Skan
12083169705Skan	default:
12084169705Skan	  gcc_unreachable ();
12085169705Skan	}
12086169705Skan
12087169705Skan      cop0 = x;
12088169705Skan      cop1 = CONST0_RTX (mode);
12089169705Skan    }
12090169705Skan
12091169705Skan  x = ix86_expand_sse_cmp (operands[0], code, cop0, cop1,
12092169705Skan			   operands[1+negate], operands[2-negate]);
12093169705Skan
12094169705Skan  ix86_expand_sse_movcc (operands[0], x, operands[1+negate],
12095169705Skan			 operands[2-negate]);
12096169705Skan  return true;
12097169705Skan}
12098169705Skan
12099132743Skan/* Expand conditional increment or decrement using adb/sbb instructions.
12100132743Skan   The default case using setcc followed by the conditional move can be
12101132743Skan   done by generic code.  */
12102132743Skanint
12103132743Skanix86_expand_int_addcc (rtx operands[])
12104132743Skan{
12105132743Skan  enum rtx_code code = GET_CODE (operands[1]);
12106132743Skan  rtx compare_op;
12107132743Skan  rtx val = const0_rtx;
12108132743Skan  bool fpcmp = false;
12109132743Skan  enum machine_mode mode = GET_MODE (operands[0]);
12110132743Skan
12111132743Skan  if (operands[3] != const1_rtx
12112132743Skan      && operands[3] != constm1_rtx)
12113132743Skan    return 0;
12114132743Skan  if (!ix86_expand_carry_flag_compare (code, ix86_compare_op0,
12115132743Skan				       ix86_compare_op1, &compare_op))
12116132743Skan     return 0;
12117132743Skan  code = GET_CODE (compare_op);
12118132743Skan
12119132743Skan  if (GET_MODE (XEXP (compare_op, 0)) == CCFPmode
12120132743Skan      || GET_MODE (XEXP (compare_op, 0)) == CCFPUmode)
12121132743Skan    {
12122132743Skan      fpcmp = true;
12123132743Skan      code = ix86_fp_compare_code_to_integer (code);
12124132743Skan    }
12125132743Skan
12126132743Skan  if (code != LTU)
12127132743Skan    {
12128132743Skan      val = constm1_rtx;
12129132743Skan      if (fpcmp)
12130132743Skan	PUT_CODE (compare_op,
12131132743Skan		  reverse_condition_maybe_unordered
12132132743Skan		    (GET_CODE (compare_op)));
12133132743Skan      else
12134132743Skan	PUT_CODE (compare_op, reverse_condition (GET_CODE (compare_op)));
12135132743Skan    }
12136132743Skan  PUT_MODE (compare_op, mode);
12137132743Skan
12138132743Skan  /* Construct either adc or sbb insn.  */
12139132743Skan  if ((code == LTU) == (operands[3] == constm1_rtx))
12140132743Skan    {
12141132743Skan      switch (GET_MODE (operands[0]))
12142132743Skan	{
12143132743Skan	  case QImode:
12144132743Skan            emit_insn (gen_subqi3_carry (operands[0], operands[2], val, compare_op));
12145132743Skan	    break;
12146132743Skan	  case HImode:
12147132743Skan            emit_insn (gen_subhi3_carry (operands[0], operands[2], val, compare_op));
12148132743Skan	    break;
12149132743Skan	  case SImode:
12150132743Skan            emit_insn (gen_subsi3_carry (operands[0], operands[2], val, compare_op));
12151132743Skan	    break;
12152132743Skan	  case DImode:
12153132743Skan            emit_insn (gen_subdi3_carry_rex64 (operands[0], operands[2], val, compare_op));
12154132743Skan	    break;
12155132743Skan	  default:
12156169705Skan	    gcc_unreachable ();
12157132743Skan	}
12158132743Skan    }
12159132743Skan  else
12160132743Skan    {
12161132743Skan      switch (GET_MODE (operands[0]))
12162132743Skan	{
12163132743Skan	  case QImode:
12164132743Skan            emit_insn (gen_addqi3_carry (operands[0], operands[2], val, compare_op));
12165132743Skan	    break;
12166132743Skan	  case HImode:
12167132743Skan            emit_insn (gen_addhi3_carry (operands[0], operands[2], val, compare_op));
12168132743Skan	    break;
12169132743Skan	  case SImode:
12170132743Skan            emit_insn (gen_addsi3_carry (operands[0], operands[2], val, compare_op));
12171132743Skan	    break;
12172132743Skan	  case DImode:
12173132743Skan            emit_insn (gen_adddi3_carry_rex64 (operands[0], operands[2], val, compare_op));
12174132743Skan	    break;
12175132743Skan	  default:
12176169705Skan	    gcc_unreachable ();
12177132743Skan	}
12178132743Skan    }
12179132743Skan  return 1; /* DONE */
12180132743Skan}
12181132743Skan
12182132743Skan
1218390284Sobrien/* Split operands 0 and 1 into SImode parts.  Similar to split_di, but
1218490284Sobrien   works for floating pointer parameters and nonoffsetable memories.
1218590284Sobrien   For pushes, it returns just stack offsets; the values will be saved
1218690284Sobrien   in the right order.  Maximally three parts are generated.  */
1218790284Sobrien
1218890284Sobrienstatic int
12189132743Skanix86_split_to_parts (rtx operand, rtx *parts, enum machine_mode mode)
1219090284Sobrien{
1219190284Sobrien  int size;
1219290284Sobrien
1219390284Sobrien  if (!TARGET_64BIT)
12194132743Skan    size = mode==XFmode ? 3 : GET_MODE_SIZE (mode) / 4;
1219590284Sobrien  else
1219690284Sobrien    size = (GET_MODE_SIZE (mode) + 4) / 8;
1219790284Sobrien
12198169705Skan  gcc_assert (GET_CODE (operand) != REG || !MMX_REGNO_P (REGNO (operand)));
12199169705Skan  gcc_assert (size >= 2 && size <= 3);
1220090284Sobrien
12201117408Skan  /* Optimize constant pool reference to immediates.  This is used by fp
12202117408Skan     moves, that force all constants to memory to allow combining.  */
12203169705Skan  if (GET_CODE (operand) == MEM && MEM_READONLY_P (operand))
12204117408Skan    {
12205117408Skan      rtx tmp = maybe_get_pool_constant (operand);
12206117408Skan      if (tmp)
12207117408Skan	operand = tmp;
12208117408Skan    }
1220990284Sobrien
1221090284Sobrien  if (GET_CODE (operand) == MEM && !offsettable_memref_p (operand))
1221151411Sobrien    {
1221290284Sobrien      /* The only non-offsetable memories we handle are pushes.  */
12213169705Skan      int ok = push_operand (operand, VOIDmode);
1221490284Sobrien
12215169705Skan      gcc_assert (ok);
12216169705Skan
1221790284Sobrien      operand = copy_rtx (operand);
1221890284Sobrien      PUT_MODE (operand, Pmode);
1221990284Sobrien      parts[0] = parts[1] = parts[2] = operand;
12220169705Skan      return size;
1222190284Sobrien    }
12222169705Skan
12223169705Skan  if (GET_CODE (operand) == CONST_VECTOR)
1222490284Sobrien    {
12225169705Skan      enum machine_mode imode = int_mode_for_mode (mode);
12226169705Skan      /* Caution: if we looked through a constant pool memory above,
12227169705Skan	 the operand may actually have a different mode now.  That's
12228169705Skan	 ok, since we want to pun this all the way back to an integer.  */
12229169705Skan      operand = simplify_subreg (imode, operand, GET_MODE (operand), 0);
12230169705Skan      gcc_assert (operand != NULL);
12231169705Skan      mode = imode;
12232169705Skan    }
12233169705Skan
12234169705Skan  if (!TARGET_64BIT)
12235169705Skan    {
1223690284Sobrien      if (mode == DImode)
1223790284Sobrien	split_di (&operand, 1, &parts[0], &parts[1]);
1223851411Sobrien      else
1223951411Sobrien	{
1224090284Sobrien	  if (REG_P (operand))
1224151411Sobrien	    {
12242169705Skan	      gcc_assert (reload_completed);
1224390284Sobrien	      parts[0] = gen_rtx_REG (SImode, REGNO (operand) + 0);
1224490284Sobrien	      parts[1] = gen_rtx_REG (SImode, REGNO (operand) + 1);
1224590284Sobrien	      if (size == 3)
1224690284Sobrien		parts[2] = gen_rtx_REG (SImode, REGNO (operand) + 2);
1224790284Sobrien	    }
1224890284Sobrien	  else if (offsettable_memref_p (operand))
1224990284Sobrien	    {
1225090284Sobrien	      operand = adjust_address (operand, SImode, 0);
1225190284Sobrien	      parts[0] = operand;
1225290284Sobrien	      parts[1] = adjust_address (operand, SImode, 4);
1225390284Sobrien	      if (size == 3)
1225490284Sobrien		parts[2] = adjust_address (operand, SImode, 8);
1225590284Sobrien	    }
1225690284Sobrien	  else if (GET_CODE (operand) == CONST_DOUBLE)
1225790284Sobrien	    {
1225890284Sobrien	      REAL_VALUE_TYPE r;
1225990284Sobrien	      long l[4];
1226051411Sobrien
1226190284Sobrien	      REAL_VALUE_FROM_CONST_DOUBLE (r, operand);
1226290284Sobrien	      switch (mode)
1226351411Sobrien		{
1226490284Sobrien		case XFmode:
1226590284Sobrien		  REAL_VALUE_TO_TARGET_LONG_DOUBLE (r, l);
12266117408Skan		  parts[2] = gen_int_mode (l[2], SImode);
1226790284Sobrien		  break;
1226890284Sobrien		case DFmode:
1226990284Sobrien		  REAL_VALUE_TO_TARGET_DOUBLE (r, l);
1227090284Sobrien		  break;
1227190284Sobrien		default:
12272169705Skan		  gcc_unreachable ();
1227351411Sobrien		}
12274117408Skan	      parts[1] = gen_int_mode (l[1], SImode);
12275117408Skan	      parts[0] = gen_int_mode (l[0], SImode);
1227651411Sobrien	    }
1227751411Sobrien	  else
12278169705Skan	    gcc_unreachable ();
1227990284Sobrien	}
1228090284Sobrien    }
1228190284Sobrien  else
1228290284Sobrien    {
1228390284Sobrien      if (mode == TImode)
1228490284Sobrien	split_ti (&operand, 1, &parts[0], &parts[1]);
1228590284Sobrien      if (mode == XFmode || mode == TFmode)
1228690284Sobrien	{
12287132743Skan	  enum machine_mode upper_mode = mode==XFmode ? SImode : DImode;
1228890284Sobrien	  if (REG_P (operand))
1228951411Sobrien	    {
12290169705Skan	      gcc_assert (reload_completed);
1229190284Sobrien	      parts[0] = gen_rtx_REG (DImode, REGNO (operand) + 0);
12292132743Skan	      parts[1] = gen_rtx_REG (upper_mode, REGNO (operand) + 1);
1229390284Sobrien	    }
1229490284Sobrien	  else if (offsettable_memref_p (operand))
1229590284Sobrien	    {
1229690284Sobrien	      operand = adjust_address (operand, DImode, 0);
1229790284Sobrien	      parts[0] = operand;
12298132743Skan	      parts[1] = adjust_address (operand, upper_mode, 8);
1229990284Sobrien	    }
1230090284Sobrien	  else if (GET_CODE (operand) == CONST_DOUBLE)
1230190284Sobrien	    {
1230290284Sobrien	      REAL_VALUE_TYPE r;
12303146908Skan	      long l[4];
1230451411Sobrien
1230590284Sobrien	      REAL_VALUE_FROM_CONST_DOUBLE (r, operand);
12306132743Skan	      real_to_target (l, &r, mode);
12307146908Skan
1230890284Sobrien	      /* Do not use shift by 32 to avoid warning on 32bit systems.  */
1230990284Sobrien	      if (HOST_BITS_PER_WIDE_INT >= 64)
1231090284Sobrien	        parts[0]
12311117408Skan		  = gen_int_mode
1231290284Sobrien		      ((l[0] & (((HOST_WIDE_INT) 2 << 31) - 1))
1231390284Sobrien		       + ((((HOST_WIDE_INT) l[1]) << 31) << 1),
12314117408Skan		       DImode);
1231551411Sobrien	      else
1231690284Sobrien	        parts[0] = immed_double_const (l[0], l[1], DImode);
12317146908Skan
12318132743Skan	      if (upper_mode == SImode)
12319132743Skan	        parts[1] = gen_int_mode (l[2], SImode);
12320132743Skan	      else if (HOST_BITS_PER_WIDE_INT >= 64)
12321132743Skan	        parts[1]
12322132743Skan		  = gen_int_mode
12323132743Skan		      ((l[2] & (((HOST_WIDE_INT) 2 << 31) - 1))
12324132743Skan		       + ((((HOST_WIDE_INT) l[3]) << 31) << 1),
12325132743Skan		       DImode);
12326132743Skan	      else
12327132743Skan	        parts[1] = immed_double_const (l[2], l[3], DImode);
1232851411Sobrien	    }
1232990284Sobrien	  else
12330169705Skan	    gcc_unreachable ();
1233151411Sobrien	}
1233290284Sobrien    }
1233390284Sobrien
1233490284Sobrien  return size;
1233590284Sobrien}
1233690284Sobrien
1233790284Sobrien/* Emit insns to perform a move or push of DI, DF, and XF values.
1233890284Sobrien   Return false when normal moves are needed; true when all required
1233990284Sobrien   insns have been emitted.  Operands 2-4 contain the input values
1234090284Sobrien   int the correct order; operands 5-7 contain the output values.  */
1234190284Sobrien
1234290284Sobrienvoid
12343132743Skanix86_split_long_move (rtx operands[])
1234490284Sobrien{
1234590284Sobrien  rtx part[2][3];
1234690284Sobrien  int nparts;
1234790284Sobrien  int push = 0;
1234890284Sobrien  int collisions = 0;
1234990284Sobrien  enum machine_mode mode = GET_MODE (operands[0]);
1235090284Sobrien
1235190284Sobrien  /* The DFmode expanders may ask us to move double.
1235290284Sobrien     For 64bit target this is single move.  By hiding the fact
1235390284Sobrien     here we simplify i386.md splitters.  */
1235490284Sobrien  if (GET_MODE_SIZE (GET_MODE (operands[0])) == 8 && TARGET_64BIT)
1235590284Sobrien    {
1235690284Sobrien      /* Optimize constant pool reference to immediates.  This is used by
1235790284Sobrien	 fp moves, that force all constants to memory to allow combining.  */
1235890284Sobrien
1235990284Sobrien      if (GET_CODE (operands[1]) == MEM
1236090284Sobrien	  && GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF
1236190284Sobrien	  && CONSTANT_POOL_ADDRESS_P (XEXP (operands[1], 0)))
1236290284Sobrien	operands[1] = get_pool_constant (XEXP (operands[1], 0));
1236390284Sobrien      if (push_operand (operands[0], VOIDmode))
1236490284Sobrien	{
1236590284Sobrien	  operands[0] = copy_rtx (operands[0]);
1236690284Sobrien	  PUT_MODE (operands[0], Pmode);
1236790284Sobrien	}
1236851411Sobrien      else
1236990284Sobrien        operands[0] = gen_lowpart (DImode, operands[0]);
1237090284Sobrien      operands[1] = gen_lowpart (DImode, operands[1]);
1237190284Sobrien      emit_move_insn (operands[0], operands[1]);
1237290284Sobrien      return;
1237390284Sobrien    }
1237490284Sobrien
1237590284Sobrien  /* The only non-offsettable memory we handle is push.  */
1237690284Sobrien  if (push_operand (operands[0], VOIDmode))
1237790284Sobrien    push = 1;
12378169705Skan  else
12379169705Skan    gcc_assert (GET_CODE (operands[0]) != MEM
12380169705Skan		|| offsettable_memref_p (operands[0]));
1238190284Sobrien
1238290284Sobrien  nparts = ix86_split_to_parts (operands[1], part[1], GET_MODE (operands[0]));
1238390284Sobrien  ix86_split_to_parts (operands[0], part[0], GET_MODE (operands[0]));
1238490284Sobrien
1238590284Sobrien  /* When emitting push, take care for source operands on the stack.  */
1238690284Sobrien  if (push && GET_CODE (operands[1]) == MEM
1238790284Sobrien      && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
1238890284Sobrien    {
1238990284Sobrien      if (nparts == 3)
1239090284Sobrien	part[1][1] = change_address (part[1][1], GET_MODE (part[1][1]),
1239190284Sobrien				     XEXP (part[1][2], 0));
1239290284Sobrien      part[1][0] = change_address (part[1][0], GET_MODE (part[1][0]),
1239390284Sobrien				   XEXP (part[1][1], 0));
1239490284Sobrien    }
1239590284Sobrien
1239690284Sobrien  /* We need to do copy in the right order in case an address register
1239790284Sobrien     of the source overlaps the destination.  */
1239890284Sobrien  if (REG_P (part[0][0]) && GET_CODE (part[1][0]) == MEM)
1239990284Sobrien    {
1240090284Sobrien      if (reg_overlap_mentioned_p (part[0][0], XEXP (part[1][0], 0)))
1240190284Sobrien	collisions++;
1240290284Sobrien      if (reg_overlap_mentioned_p (part[0][1], XEXP (part[1][0], 0)))
1240390284Sobrien	collisions++;
1240490284Sobrien      if (nparts == 3
1240590284Sobrien	  && reg_overlap_mentioned_p (part[0][2], XEXP (part[1][0], 0)))
1240690284Sobrien	collisions++;
1240790284Sobrien
1240890284Sobrien      /* Collision in the middle part can be handled by reordering.  */
1240990284Sobrien      if (collisions == 1 && nparts == 3
1241090284Sobrien	  && reg_overlap_mentioned_p (part[0][1], XEXP (part[1][0], 0)))
1241151411Sobrien	{
1241290284Sobrien	  rtx tmp;
1241390284Sobrien	  tmp = part[0][1]; part[0][1] = part[0][2]; part[0][2] = tmp;
1241490284Sobrien	  tmp = part[1][1]; part[1][1] = part[1][2]; part[1][2] = tmp;
1241590284Sobrien	}
1241690284Sobrien
1241790284Sobrien      /* If there are more collisions, we can't handle it by reordering.
1241890284Sobrien	 Do an lea to the last part and use only one colliding move.  */
1241990284Sobrien      else if (collisions > 1)
1242090284Sobrien	{
12421117408Skan	  rtx base;
12422117408Skan
1242390284Sobrien	  collisions = 1;
12424117408Skan
12425117408Skan	  base = part[0][nparts - 1];
12426117408Skan
12427117408Skan	  /* Handle the case when the last part isn't valid for lea.
12428117408Skan	     Happens in 64-bit mode storing the 12-byte XFmode.  */
12429117408Skan	  if (GET_MODE (base) != Pmode)
12430117408Skan	    base = gen_rtx_REG (Pmode, REGNO (base));
12431117408Skan
12432117408Skan	  emit_insn (gen_rtx_SET (VOIDmode, base, XEXP (part[1][0], 0)));
12433117408Skan	  part[1][0] = replace_equiv_address (part[1][0], base);
12434117408Skan	  part[1][1] = replace_equiv_address (part[1][1],
12435117408Skan				      plus_constant (base, UNITS_PER_WORD));
1243690284Sobrien	  if (nparts == 3)
12437117408Skan	    part[1][2] = replace_equiv_address (part[1][2],
12438117408Skan				      plus_constant (base, 8));
1243990284Sobrien	}
1244090284Sobrien    }
1244190284Sobrien
1244290284Sobrien  if (push)
1244390284Sobrien    {
1244490284Sobrien      if (!TARGET_64BIT)
1244590284Sobrien	{
1244690284Sobrien	  if (nparts == 3)
1244751411Sobrien	    {
12448132743Skan	      if (TARGET_128BIT_LONG_DOUBLE && mode == XFmode)
12449132743Skan                emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, GEN_INT (-4)));
1245090284Sobrien	      emit_move_insn (part[0][2], part[1][2]);
1245151411Sobrien	    }
1245290284Sobrien	}
1245390284Sobrien      else
1245490284Sobrien	{
1245590284Sobrien	  /* In 64bit mode we don't have 32bit push available.  In case this is
1245690284Sobrien	     register, it is OK - we will just use larger counterpart.  We also
1245790284Sobrien	     retype memory - these comes from attempt to avoid REX prefix on
1245890284Sobrien	     moving of second half of TFmode value.  */
1245990284Sobrien	  if (GET_MODE (part[1][1]) == SImode)
1246051411Sobrien	    {
12461169705Skan	      switch (GET_CODE (part[1][1]))
12462169705Skan		{
12463169705Skan		case MEM:
12464169705Skan		  part[1][1] = adjust_address (part[1][1], DImode, 0);
12465169705Skan		  break;
12466169705Skan
12467169705Skan		case REG:
12468169705Skan		  part[1][1] = gen_rtx_REG (DImode, REGNO (part[1][1]));
12469169705Skan		  break;
12470169705Skan
12471169705Skan		default:
12472169705Skan		  gcc_unreachable ();
12473169705Skan		}
12474169705Skan
1247590284Sobrien	      if (GET_MODE (part[1][0]) == SImode)
1247690284Sobrien		part[1][0] = part[1][1];
1247751411Sobrien	    }
1247851411Sobrien	}
1247990284Sobrien      emit_move_insn (part[0][1], part[1][1]);
1248090284Sobrien      emit_move_insn (part[0][0], part[1][0]);
1248151411Sobrien      return;
1248251411Sobrien    }
1248390284Sobrien
1248490284Sobrien  /* Choose correct order to not overwrite the source before it is copied.  */
1248590284Sobrien  if ((REG_P (part[0][0])
1248690284Sobrien       && REG_P (part[1][1])
1248790284Sobrien       && (REGNO (part[0][0]) == REGNO (part[1][1])
1248890284Sobrien	   || (nparts == 3
1248990284Sobrien	       && REGNO (part[0][0]) == REGNO (part[1][2]))))
1249090284Sobrien      || (collisions > 0
1249190284Sobrien	  && reg_overlap_mentioned_p (part[0][0], XEXP (part[1][0], 0))))
1249290284Sobrien    {
1249390284Sobrien      if (nparts == 3)
1249490284Sobrien	{
1249590284Sobrien	  operands[2] = part[0][2];
1249690284Sobrien	  operands[3] = part[0][1];
1249790284Sobrien	  operands[4] = part[0][0];
1249890284Sobrien	  operands[5] = part[1][2];
1249990284Sobrien	  operands[6] = part[1][1];
1250090284Sobrien	  operands[7] = part[1][0];
1250190284Sobrien	}
1250290284Sobrien      else
1250390284Sobrien	{
1250490284Sobrien	  operands[2] = part[0][1];
1250590284Sobrien	  operands[3] = part[0][0];
1250690284Sobrien	  operands[5] = part[1][1];
1250790284Sobrien	  operands[6] = part[1][0];
1250890284Sobrien	}
1250990284Sobrien    }
1251051411Sobrien  else
1251151411Sobrien    {
1251290284Sobrien      if (nparts == 3)
1251390284Sobrien	{
1251490284Sobrien	  operands[2] = part[0][0];
1251590284Sobrien	  operands[3] = part[0][1];
1251690284Sobrien	  operands[4] = part[0][2];
1251790284Sobrien	  operands[5] = part[1][0];
1251890284Sobrien	  operands[6] = part[1][1];
1251990284Sobrien	  operands[7] = part[1][2];
1252090284Sobrien	}
1252190284Sobrien      else
1252290284Sobrien	{
1252390284Sobrien	  operands[2] = part[0][0];
1252490284Sobrien	  operands[3] = part[0][1];
1252590284Sobrien	  operands[5] = part[1][0];
1252690284Sobrien	  operands[6] = part[1][1];
1252790284Sobrien	}
1252851411Sobrien    }
12529169705Skan
12530169705Skan  /* If optimizing for size, attempt to locally unCSE nonzero constants.  */
12531169705Skan  if (optimize_size)
12532169705Skan    {
12533169705Skan      if (GET_CODE (operands[5]) == CONST_INT
12534169705Skan	  && operands[5] != const0_rtx
12535169705Skan	  && REG_P (operands[2]))
12536169705Skan	{
12537169705Skan	  if (GET_CODE (operands[6]) == CONST_INT
12538169705Skan	      && INTVAL (operands[6]) == INTVAL (operands[5]))
12539169705Skan	    operands[6] = operands[2];
12540169705Skan
12541169705Skan	  if (nparts == 3
12542169705Skan	      && GET_CODE (operands[7]) == CONST_INT
12543169705Skan	      && INTVAL (operands[7]) == INTVAL (operands[5]))
12544169705Skan	    operands[7] = operands[2];
12545169705Skan	}
12546169705Skan
12547169705Skan      if (nparts == 3
12548169705Skan	  && GET_CODE (operands[6]) == CONST_INT
12549169705Skan	  && operands[6] != const0_rtx
12550169705Skan	  && REG_P (operands[3])
12551169705Skan	  && GET_CODE (operands[7]) == CONST_INT
12552169705Skan	  && INTVAL (operands[7]) == INTVAL (operands[6]))
12553169705Skan	operands[7] = operands[3];
12554169705Skan    }
12555169705Skan
1255690284Sobrien  emit_move_insn (operands[2], operands[5]);
1255790284Sobrien  emit_move_insn (operands[3], operands[6]);
1255890284Sobrien  if (nparts == 3)
1255990284Sobrien    emit_move_insn (operands[4], operands[7]);
1256090284Sobrien
1256190284Sobrien  return;
1256251411Sobrien}
1256390284Sobrien
12564169705Skan/* Helper function of ix86_split_ashl used to generate an SImode/DImode
12565169705Skan   left shift by a constant, either using a single shift or
12566169705Skan   a sequence of add instructions.  */
12567169705Skan
12568169705Skanstatic void
12569169705Skanix86_expand_ashl_const (rtx operand, int count, enum machine_mode mode)
12570169705Skan{
12571169705Skan  if (count == 1)
12572169705Skan    {
12573169705Skan      emit_insn ((mode == DImode
12574169705Skan		  ? gen_addsi3
12575169705Skan		  : gen_adddi3) (operand, operand, operand));
12576169705Skan    }
12577169705Skan  else if (!optimize_size
12578169705Skan	   && count * ix86_cost->add <= ix86_cost->shift_const)
12579169705Skan    {
12580169705Skan      int i;
12581169705Skan      for (i=0; i<count; i++)
12582169705Skan	{
12583169705Skan	  emit_insn ((mode == DImode
12584169705Skan		      ? gen_addsi3
12585169705Skan		      : gen_adddi3) (operand, operand, operand));
12586169705Skan	}
12587169705Skan    }
12588169705Skan  else
12589169705Skan    emit_insn ((mode == DImode
12590169705Skan		? gen_ashlsi3
12591169705Skan		: gen_ashldi3) (operand, operand, GEN_INT (count)));
12592169705Skan}
12593169705Skan
1259490284Sobrienvoid
12595169705Skanix86_split_ashl (rtx *operands, rtx scratch, enum machine_mode mode)
1259651411Sobrien{
1259790284Sobrien  rtx low[2], high[2];
1259890284Sobrien  int count;
12599169705Skan  const int single_width = mode == DImode ? 32 : 64;
1260051411Sobrien
1260190284Sobrien  if (GET_CODE (operands[2]) == CONST_INT)
1260251411Sobrien    {
12603169705Skan      (mode == DImode ? split_di : split_ti) (operands, 2, low, high);
12604169705Skan      count = INTVAL (operands[2]) & (single_width * 2 - 1);
1260551411Sobrien
12606169705Skan      if (count >= single_width)
1260751411Sobrien	{
1260890284Sobrien	  emit_move_insn (high[0], low[1]);
1260990284Sobrien	  emit_move_insn (low[0], const0_rtx);
1261051411Sobrien
12611169705Skan	  if (count > single_width)
12612169705Skan	    ix86_expand_ashl_const (high[0], count - single_width, mode);
1261390284Sobrien	}
1261490284Sobrien      else
1261590284Sobrien	{
1261690284Sobrien	  if (!rtx_equal_p (operands[0], operands[1]))
1261790284Sobrien	    emit_move_insn (operands[0], operands[1]);
12618169705Skan	  emit_insn ((mode == DImode
12619169705Skan		     ? gen_x86_shld_1
12620169705Skan		     : gen_x86_64_shld) (high[0], low[0], GEN_INT (count)));
12621169705Skan	  ix86_expand_ashl_const (low[0], count, mode);
1262290284Sobrien	}
12623169705Skan      return;
1262490284Sobrien    }
12625169705Skan
12626169705Skan  (mode == DImode ? split_di : split_ti) (operands, 1, low, high);
12627169705Skan
12628169705Skan  if (operands[1] == const1_rtx)
1262990284Sobrien    {
12630169705Skan      /* Assuming we've chosen a QImode capable registers, then 1 << N
12631169705Skan	 can be done with two 32/64-bit shifts, no branches, no cmoves.  */
12632169705Skan      if (ANY_QI_REG_P (low[0]) && ANY_QI_REG_P (high[0]))
12633169705Skan	{
12634169705Skan	  rtx s, d, flags = gen_rtx_REG (CCZmode, FLAGS_REG);
1263551411Sobrien
12636169705Skan	  ix86_expand_clear (low[0]);
12637169705Skan	  ix86_expand_clear (high[0]);
12638169705Skan	  emit_insn (gen_testqi_ccz_1 (operands[2], GEN_INT (single_width)));
1263951411Sobrien
12640169705Skan	  d = gen_lowpart (QImode, low[0]);
12641169705Skan	  d = gen_rtx_STRICT_LOW_PART (VOIDmode, d);
12642169705Skan	  s = gen_rtx_EQ (QImode, flags, const0_rtx);
12643169705Skan	  emit_insn (gen_rtx_SET (VOIDmode, d, s));
1264490284Sobrien
12645169705Skan	  d = gen_lowpart (QImode, high[0]);
12646169705Skan	  d = gen_rtx_STRICT_LOW_PART (VOIDmode, d);
12647169705Skan	  s = gen_rtx_NE (QImode, flags, const0_rtx);
12648169705Skan	  emit_insn (gen_rtx_SET (VOIDmode, d, s));
12649169705Skan	}
12650169705Skan
12651169705Skan      /* Otherwise, we can get the same results by manually performing
12652169705Skan	 a bit extract operation on bit 5/6, and then performing the two
12653169705Skan	 shifts.  The two methods of getting 0/1 into low/high are exactly
12654169705Skan	 the same size.  Avoiding the shift in the bit extract case helps
12655169705Skan	 pentium4 a bit; no one else seems to care much either way.  */
12656169705Skan      else
1265790284Sobrien	{
12658169705Skan	  rtx x;
12659169705Skan
12660169705Skan	  if (TARGET_PARTIAL_REG_STALL && !optimize_size)
12661169705Skan	    x = gen_rtx_ZERO_EXTEND (mode == DImode ? SImode : DImode, operands[2]);
1266290284Sobrien	  else
12663169705Skan	    x = gen_lowpart (mode == DImode ? SImode : DImode, operands[2]);
12664169705Skan	  emit_insn (gen_rtx_SET (VOIDmode, high[0], x));
1266590284Sobrien
12666169705Skan	  emit_insn ((mode == DImode
12667169705Skan		      ? gen_lshrsi3
12668169705Skan		      : gen_lshrdi3) (high[0], high[0], GEN_INT (mode == DImode ? 5 : 6)));
12669169705Skan	  emit_insn ((mode == DImode
12670169705Skan		      ? gen_andsi3
12671169705Skan		      : gen_anddi3) (high[0], high[0], GEN_INT (1)));
12672169705Skan	  emit_move_insn (low[0], high[0]);
12673169705Skan	  emit_insn ((mode == DImode
12674169705Skan		      ? gen_xorsi3
12675169705Skan		      : gen_xordi3) (low[0], low[0], GEN_INT (1)));
1267651411Sobrien	}
12677169705Skan
12678169705Skan      emit_insn ((mode == DImode
12679169705Skan		    ? gen_ashlsi3
12680169705Skan		    : gen_ashldi3) (low[0], low[0], operands[2]));
12681169705Skan      emit_insn ((mode == DImode
12682169705Skan		    ? gen_ashlsi3
12683169705Skan		    : gen_ashldi3) (high[0], high[0], operands[2]));
12684169705Skan      return;
12685169705Skan    }
12686169705Skan
12687169705Skan  if (operands[1] == constm1_rtx)
12688169705Skan    {
12689169705Skan      /* For -1 << N, we can avoid the shld instruction, because we
12690169705Skan	 know that we're shifting 0...31/63 ones into a -1.  */
12691169705Skan      emit_move_insn (low[0], constm1_rtx);
12692169705Skan      if (optimize_size)
12693169705Skan	emit_move_insn (high[0], low[0]);
1269451411Sobrien      else
12695169705Skan	emit_move_insn (high[0], constm1_rtx);
1269651411Sobrien    }
12697169705Skan  else
12698169705Skan    {
12699169705Skan      if (!rtx_equal_p (operands[0], operands[1]))
12700169705Skan	emit_move_insn (operands[0], operands[1]);
12701169705Skan
12702169705Skan      (mode == DImode ? split_di : split_ti) (operands, 1, low, high);
12703169705Skan      emit_insn ((mode == DImode
12704169705Skan		  ? gen_x86_shld_1
12705169705Skan		  : gen_x86_64_shld) (high[0], low[0], operands[2]));
12706169705Skan    }
12707169705Skan
12708169705Skan  emit_insn ((mode == DImode ? gen_ashlsi3 : gen_ashldi3) (low[0], low[0], operands[2]));
12709169705Skan
12710169705Skan  if (TARGET_CMOVE && scratch)
12711169705Skan    {
12712169705Skan      ix86_expand_clear (scratch);
12713169705Skan      emit_insn ((mode == DImode
12714169705Skan		  ? gen_x86_shift_adj_1
12715169705Skan		  : gen_x86_64_shift_adj) (high[0], low[0], operands[2], scratch));
12716169705Skan    }
12717169705Skan  else
12718169705Skan    emit_insn (gen_x86_shift_adj_2 (high[0], low[0], operands[2]));
1271990284Sobrien}
1272051411Sobrien
1272190284Sobrienvoid
12722169705Skanix86_split_ashr (rtx *operands, rtx scratch, enum machine_mode mode)
1272351411Sobrien{
1272490284Sobrien  rtx low[2], high[2];
1272590284Sobrien  int count;
12726169705Skan  const int single_width = mode == DImode ? 32 : 64;
1272790284Sobrien
1272890284Sobrien  if (GET_CODE (operands[2]) == CONST_INT)
1272951411Sobrien    {
12730169705Skan      (mode == DImode ? split_di : split_ti) (operands, 2, low, high);
12731169705Skan      count = INTVAL (operands[2]) & (single_width * 2 - 1);
1273251411Sobrien
12733169705Skan      if (count == single_width * 2 - 1)
1273490284Sobrien	{
12735169705Skan	  emit_move_insn (high[0], high[1]);
12736169705Skan	  emit_insn ((mode == DImode
12737169705Skan		      ? gen_ashrsi3
12738169705Skan		      : gen_ashrdi3) (high[0], high[0],
12739169705Skan				      GEN_INT (single_width - 1)));
12740169705Skan	  emit_move_insn (low[0], high[0]);
1274151411Sobrien
1274290284Sobrien	}
12743169705Skan      else if (count >= single_width)
12744169705Skan	{
12745169705Skan	  emit_move_insn (low[0], high[1]);
12746169705Skan	  emit_move_insn (high[0], low[0]);
12747169705Skan	  emit_insn ((mode == DImode
12748169705Skan		      ? gen_ashrsi3
12749169705Skan		      : gen_ashrdi3) (high[0], high[0],
12750169705Skan				      GEN_INT (single_width - 1)));
12751169705Skan	  if (count > single_width)
12752169705Skan	    emit_insn ((mode == DImode
12753169705Skan			? gen_ashrsi3
12754169705Skan			: gen_ashrdi3) (low[0], low[0],
12755169705Skan					GEN_INT (count - single_width)));
12756169705Skan	}
1275790284Sobrien      else
1275890284Sobrien	{
1275990284Sobrien	  if (!rtx_equal_p (operands[0], operands[1]))
1276090284Sobrien	    emit_move_insn (operands[0], operands[1]);
12761169705Skan	  emit_insn ((mode == DImode
12762169705Skan		      ? gen_x86_shrd_1
12763169705Skan		      : gen_x86_64_shrd) (low[0], high[0], GEN_INT (count)));
12764169705Skan	  emit_insn ((mode == DImode
12765169705Skan		      ? gen_ashrsi3
12766169705Skan		      : gen_ashrdi3) (high[0], high[0], GEN_INT (count)));
1276790284Sobrien	}
1276851411Sobrien    }
1276990284Sobrien  else
1277090284Sobrien    {
1277190284Sobrien      if (!rtx_equal_p (operands[0], operands[1]))
1277290284Sobrien	emit_move_insn (operands[0], operands[1]);
1277390284Sobrien
12774169705Skan      (mode == DImode ? split_di : split_ti) (operands, 1, low, high);
1277590284Sobrien
12776169705Skan      emit_insn ((mode == DImode
12777169705Skan		  ? gen_x86_shrd_1
12778169705Skan		  : gen_x86_64_shrd) (low[0], high[0], operands[2]));
12779169705Skan      emit_insn ((mode == DImode
12780169705Skan		  ? gen_ashrsi3
12781169705Skan		  : gen_ashrdi3)  (high[0], high[0], operands[2]));
1278290284Sobrien
12783169705Skan      if (TARGET_CMOVE && scratch)
1278490284Sobrien	{
1278590284Sobrien	  emit_move_insn (scratch, high[0]);
12786169705Skan	  emit_insn ((mode == DImode
12787169705Skan		      ? gen_ashrsi3
12788169705Skan		      : gen_ashrdi3) (scratch, scratch,
12789169705Skan				      GEN_INT (single_width - 1)));
12790169705Skan	  emit_insn ((mode == DImode
12791169705Skan		      ? gen_x86_shift_adj_1
12792169705Skan		      : gen_x86_64_shift_adj) (low[0], high[0], operands[2],
12793169705Skan					 scratch));
1279490284Sobrien	}
1279590284Sobrien      else
1279690284Sobrien	emit_insn (gen_x86_shift_adj_3 (low[0], high[0], operands[2]));
1279790284Sobrien    }
1279851411Sobrien}
1279990284Sobrien
1280090284Sobrienvoid
12801169705Skanix86_split_lshr (rtx *operands, rtx scratch, enum machine_mode mode)
1280251411Sobrien{
1280390284Sobrien  rtx low[2], high[2];
1280490284Sobrien  int count;
12805169705Skan  const int single_width = mode == DImode ? 32 : 64;
1280690284Sobrien
1280790284Sobrien  if (GET_CODE (operands[2]) == CONST_INT)
1280851411Sobrien    {
12809169705Skan      (mode == DImode ? split_di : split_ti) (operands, 2, low, high);
12810169705Skan      count = INTVAL (operands[2]) & (single_width * 2 - 1);
1281151411Sobrien
12812169705Skan      if (count >= single_width)
1281390284Sobrien	{
1281490284Sobrien	  emit_move_insn (low[0], high[1]);
12815169705Skan	  ix86_expand_clear (high[0]);
1281690284Sobrien
12817169705Skan	  if (count > single_width)
12818169705Skan	    emit_insn ((mode == DImode
12819169705Skan			? gen_lshrsi3
12820169705Skan			: gen_lshrdi3) (low[0], low[0],
12821169705Skan					GEN_INT (count - single_width)));
1282290284Sobrien	}
1282390284Sobrien      else
1282490284Sobrien	{
1282590284Sobrien	  if (!rtx_equal_p (operands[0], operands[1]))
1282690284Sobrien	    emit_move_insn (operands[0], operands[1]);
12827169705Skan	  emit_insn ((mode == DImode
12828169705Skan		      ? gen_x86_shrd_1
12829169705Skan		      : gen_x86_64_shrd) (low[0], high[0], GEN_INT (count)));
12830169705Skan	  emit_insn ((mode == DImode
12831169705Skan		      ? gen_lshrsi3
12832169705Skan		      : gen_lshrdi3) (high[0], high[0], GEN_INT (count)));
1283390284Sobrien	}
1283451411Sobrien    }
1283590284Sobrien  else
1283690284Sobrien    {
1283790284Sobrien      if (!rtx_equal_p (operands[0], operands[1]))
1283890284Sobrien	emit_move_insn (operands[0], operands[1]);
1283990284Sobrien
12840169705Skan      (mode == DImode ? split_di : split_ti) (operands, 1, low, high);
1284190284Sobrien
12842169705Skan      emit_insn ((mode == DImode
12843169705Skan		  ? gen_x86_shrd_1
12844169705Skan		  : gen_x86_64_shrd) (low[0], high[0], operands[2]));
12845169705Skan      emit_insn ((mode == DImode
12846169705Skan		  ? gen_lshrsi3
12847169705Skan		  : gen_lshrdi3) (high[0], high[0], operands[2]));
1284890284Sobrien
1284990284Sobrien      /* Heh.  By reversing the arguments, we can reuse this pattern.  */
12850169705Skan      if (TARGET_CMOVE && scratch)
1285190284Sobrien	{
12852169705Skan	  ix86_expand_clear (scratch);
12853169705Skan	  emit_insn ((mode == DImode
12854169705Skan		      ? gen_x86_shift_adj_1
12855169705Skan		      : gen_x86_64_shift_adj) (low[0], high[0], operands[2],
12856169705Skan					       scratch));
1285790284Sobrien	}
1285890284Sobrien      else
1285990284Sobrien	emit_insn (gen_x86_shift_adj_2 (low[0], high[0], operands[2]));
1286090284Sobrien    }
1286151411Sobrien}
1286290284Sobrien
1286390284Sobrien/* Helper function for the string operations below.  Dest VARIABLE whether
1286490284Sobrien   it is aligned to VALUE bytes.  If true, jump to the label.  */
1286590284Sobrienstatic rtx
12866132743Skanix86_expand_aligntest (rtx variable, int value)
1286751411Sobrien{
1286890284Sobrien  rtx label = gen_label_rtx ();
1286990284Sobrien  rtx tmpcount = gen_reg_rtx (GET_MODE (variable));
1287090284Sobrien  if (GET_MODE (variable) == DImode)
1287190284Sobrien    emit_insn (gen_anddi3 (tmpcount, variable, GEN_INT (value)));
1287290284Sobrien  else
1287390284Sobrien    emit_insn (gen_andsi3 (tmpcount, variable, GEN_INT (value)));
1287490284Sobrien  emit_cmp_and_jump_insns (tmpcount, const0_rtx, EQ, 0, GET_MODE (variable),
1287590284Sobrien			   1, label);
1287690284Sobrien  return label;
1287790284Sobrien}
1287851411Sobrien
1287990284Sobrien/* Adjust COUNTER by the VALUE.  */
1288090284Sobrienstatic void
12881132743Skanix86_adjust_counter (rtx countreg, HOST_WIDE_INT value)
1288290284Sobrien{
1288390284Sobrien  if (GET_MODE (countreg) == DImode)
1288490284Sobrien    emit_insn (gen_adddi3 (countreg, countreg, GEN_INT (-value)));
1288590284Sobrien  else
1288690284Sobrien    emit_insn (gen_addsi3 (countreg, countreg, GEN_INT (-value)));
1288751411Sobrien}
1288890284Sobrien
1288990284Sobrien/* Zero extend possibly SImode EXP to Pmode register.  */
1289090284Sobrienrtx
12891132743Skanix86_zero_extend_to_Pmode (rtx exp)
1289251411Sobrien{
1289390284Sobrien  rtx r;
1289490284Sobrien  if (GET_MODE (exp) == VOIDmode)
1289590284Sobrien    return force_reg (Pmode, exp);
1289690284Sobrien  if (GET_MODE (exp) == Pmode)
1289790284Sobrien    return copy_to_mode_reg (Pmode, exp);
1289890284Sobrien  r = gen_reg_rtx (Pmode);
1289990284Sobrien  emit_insn (gen_zero_extendsidi2 (r, exp));
1290090284Sobrien  return r;
1290151411Sobrien}
1290251411Sobrien
1290390284Sobrien/* Expand string move (memcpy) operation.  Use i386 string operations when
12904169705Skan   profitable.  expand_clrmem contains similar code.  */
1290551411Sobrienint
12906169705Skanix86_expand_movmem (rtx dst, rtx src, rtx count_exp, rtx align_exp)
1290751411Sobrien{
12908132743Skan  rtx srcreg, destreg, countreg, srcexp, destexp;
1290990284Sobrien  enum machine_mode counter_mode;
1291090284Sobrien  HOST_WIDE_INT align = 0;
1291190284Sobrien  unsigned HOST_WIDE_INT count = 0;
1291251411Sobrien
1291390284Sobrien  if (GET_CODE (align_exp) == CONST_INT)
1291490284Sobrien    align = INTVAL (align_exp);
1291551411Sobrien
12916132743Skan  /* Can't use any of this if the user has appropriated esi or edi.  */
12917132743Skan  if (global_regs[4] || global_regs[5])
12918132743Skan    return 0;
12919132743Skan
1292090284Sobrien  /* This simple hack avoids all inlining code and simplifies code below.  */
1292190284Sobrien  if (!TARGET_ALIGN_STRINGOPS)
1292290284Sobrien    align = 64;
1292351411Sobrien
1292490284Sobrien  if (GET_CODE (count_exp) == CONST_INT)
12925132743Skan    {
12926132743Skan      count = INTVAL (count_exp);
12927132743Skan      if (!TARGET_INLINE_ALL_STRINGOPS && count > 64)
12928132743Skan	return 0;
12929132743Skan    }
1293090284Sobrien
1293190284Sobrien  /* Figure out proper mode for counter.  For 32bits it is always SImode,
1293290284Sobrien     for 64bits use SImode when possible, otherwise DImode.
1293390284Sobrien     Set count to number of bytes copied when known at compile time.  */
12934169705Skan  if (!TARGET_64BIT
12935169705Skan      || GET_MODE (count_exp) == SImode
12936169705Skan      || x86_64_zext_immediate_operand (count_exp, VOIDmode))
1293790284Sobrien    counter_mode = SImode;
1293890284Sobrien  else
1293990284Sobrien    counter_mode = DImode;
1294090284Sobrien
12941169705Skan  gcc_assert (counter_mode == SImode || counter_mode == DImode);
1294290284Sobrien
1294390284Sobrien  destreg = copy_to_mode_reg (Pmode, XEXP (dst, 0));
12944132743Skan  if (destreg != XEXP (dst, 0))
12945132743Skan    dst = replace_equiv_address_nv (dst, destreg);
1294690284Sobrien  srcreg = copy_to_mode_reg (Pmode, XEXP (src, 0));
12947132743Skan  if (srcreg != XEXP (src, 0))
12948132743Skan    src = replace_equiv_address_nv (src, srcreg);
1294990284Sobrien
1295090284Sobrien  /* When optimizing for size emit simple rep ; movsb instruction for
12951169705Skan     counts not divisible by 4, except when (movsl;)*(movsw;)?(movsb;)?
12952169705Skan     sequence is shorter than mov{b,l} $count, %{ecx,cl}; rep; movsb.
12953169705Skan     Sice of (movsl;)*(movsw;)?(movsb;)? sequence is
12954169705Skan     count / 4 + (count & 3), the other sequence is either 4 or 7 bytes,
12955169705Skan     but we don't know whether upper 24 (resp. 56) bits of %ecx will be
12956169705Skan     known to be zero or not.  The rep; movsb sequence causes higher
12957169705Skan     register pressure though, so take that into account.  */
1295890284Sobrien
12959169705Skan  if ((!optimize || optimize_size)
12960169705Skan      && (count == 0
12961169705Skan	  || ((count & 0x03)
12962169705Skan	      && (!optimize_size
12963169705Skan		  || count > 5 * 4
12964169705Skan		  || (count & 3) + count / 4 > 6))))
1296590284Sobrien    {
12966132743Skan      emit_insn (gen_cld ());
1296790284Sobrien      countreg = ix86_zero_extend_to_Pmode (count_exp);
12968132743Skan      destexp = gen_rtx_PLUS (Pmode, destreg, countreg);
12969132743Skan      srcexp = gen_rtx_PLUS (Pmode, srcreg, countreg);
12970132743Skan      emit_insn (gen_rep_mov (destreg, dst, srcreg, src, countreg,
12971132743Skan			      destexp, srcexp));
1297290284Sobrien    }
1297390284Sobrien
1297490284Sobrien  /* For constant aligned (or small unaligned) copies use rep movsl
1297590284Sobrien     followed by code copying the rest.  For PentiumPro ensure 8 byte
1297690284Sobrien     alignment to allow rep movsl acceleration.  */
1297790284Sobrien
1297890284Sobrien  else if (count != 0
1297990284Sobrien	   && (align >= 8
1298090284Sobrien	       || (!TARGET_PENTIUMPRO && !TARGET_64BIT && align >= 4)
1298190284Sobrien	       || optimize_size || count < (unsigned int) 64))
1298290284Sobrien    {
12983132743Skan      unsigned HOST_WIDE_INT offset = 0;
1298490284Sobrien      int size = TARGET_64BIT && !optimize_size ? 8 : 4;
12985132743Skan      rtx srcmem, dstmem;
12986132743Skan
12987132743Skan      emit_insn (gen_cld ());
1298890284Sobrien      if (count & ~(size - 1))
1298990284Sobrien	{
12990169705Skan	  if ((TARGET_SINGLE_STRINGOP || optimize_size) && count < 5 * 4)
12991169705Skan	    {
12992169705Skan	      enum machine_mode movs_mode = size == 4 ? SImode : DImode;
12993132743Skan
12994169705Skan	      while (offset < (count & ~(size - 1)))
12995169705Skan		{
12996169705Skan		  srcmem = adjust_automodify_address_nv (src, movs_mode,
12997169705Skan							 srcreg, offset);
12998169705Skan		  dstmem = adjust_automodify_address_nv (dst, movs_mode,
12999169705Skan							 destreg, offset);
13000169705Skan		  emit_insn (gen_strmov (destreg, dstmem, srcreg, srcmem));
13001169705Skan		  offset += size;
13002169705Skan		}
13003169705Skan	    }
13004169705Skan	  else
13005169705Skan	    {
13006169705Skan	      countreg = GEN_INT ((count >> (size == 4 ? 2 : 3))
13007169705Skan				  & (TARGET_64BIT ? -1 : 0x3fffffff));
13008169705Skan	      countreg = copy_to_mode_reg (counter_mode, countreg);
13009169705Skan	      countreg = ix86_zero_extend_to_Pmode (countreg);
13010169705Skan
13011169705Skan	      destexp = gen_rtx_ASHIFT (Pmode, countreg,
13012169705Skan					GEN_INT (size == 4 ? 2 : 3));
13013169705Skan	      srcexp = gen_rtx_PLUS (Pmode, destexp, srcreg);
13014169705Skan	      destexp = gen_rtx_PLUS (Pmode, destexp, destreg);
13015169705Skan
13016169705Skan	      emit_insn (gen_rep_mov (destreg, dst, srcreg, src,
13017169705Skan				      countreg, destexp, srcexp));
13018169705Skan	      offset = count & ~(size - 1);
13019169705Skan	    }
1302090284Sobrien	}
1302190284Sobrien      if (size == 8 && (count & 0x04))
13022132743Skan	{
13023132743Skan	  srcmem = adjust_automodify_address_nv (src, SImode, srcreg,
13024132743Skan						 offset);
13025132743Skan	  dstmem = adjust_automodify_address_nv (dst, SImode, destreg,
13026132743Skan						 offset);
13027132743Skan	  emit_insn (gen_strmov (destreg, dstmem, srcreg, srcmem));
13028132743Skan	  offset += 4;
13029132743Skan	}
1303090284Sobrien      if (count & 0x02)
13031132743Skan	{
13032132743Skan	  srcmem = adjust_automodify_address_nv (src, HImode, srcreg,
13033132743Skan						 offset);
13034132743Skan	  dstmem = adjust_automodify_address_nv (dst, HImode, destreg,
13035132743Skan						 offset);
13036132743Skan	  emit_insn (gen_strmov (destreg, dstmem, srcreg, srcmem));
13037132743Skan	  offset += 2;
13038132743Skan	}
1303990284Sobrien      if (count & 0x01)
13040132743Skan	{
13041132743Skan	  srcmem = adjust_automodify_address_nv (src, QImode, srcreg,
13042132743Skan						 offset);
13043132743Skan	  dstmem = adjust_automodify_address_nv (dst, QImode, destreg,
13044132743Skan						 offset);
13045132743Skan	  emit_insn (gen_strmov (destreg, dstmem, srcreg, srcmem));
13046132743Skan	}
1304790284Sobrien    }
1304890284Sobrien  /* The generic code based on the glibc implementation:
1304990284Sobrien     - align destination to 4 bytes (8 byte alignment is used for PentiumPro
1305090284Sobrien     allowing accelerated copying there)
1305190284Sobrien     - copy the data using rep movsl
1305290284Sobrien     - copy the rest.  */
1305390284Sobrien  else
1305490284Sobrien    {
1305590284Sobrien      rtx countreg2;
1305690284Sobrien      rtx label = NULL;
13057132743Skan      rtx srcmem, dstmem;
13058102800Skan      int desired_alignment = (TARGET_PENTIUMPRO
13059102800Skan			       && (count == 0 || count >= (unsigned int) 260)
13060102800Skan			       ? 8 : UNITS_PER_WORD);
13061132743Skan      /* Get rid of MEM_OFFSETs, they won't be accurate.  */
13062132743Skan      dst = change_address (dst, BLKmode, destreg);
13063132743Skan      src = change_address (src, BLKmode, srcreg);
1306490284Sobrien
1306590284Sobrien      /* In case we don't know anything about the alignment, default to
1306690284Sobrien         library version, since it is usually equally fast and result in
13067132743Skan         shorter code.
1306890284Sobrien
13069132743Skan	 Also emit call when we know that the count is large and call overhead
13070132743Skan	 will not be important.  */
13071132743Skan      if (!TARGET_INLINE_ALL_STRINGOPS
13072132743Skan	  && (align < UNITS_PER_WORD || !TARGET_REP_MOVL_OPTIMAL))
13073132743Skan	return 0;
13074132743Skan
1307590284Sobrien      if (TARGET_SINGLE_STRINGOP)
1307690284Sobrien	emit_insn (gen_cld ());
1307790284Sobrien
1307890284Sobrien      countreg2 = gen_reg_rtx (Pmode);
1307990284Sobrien      countreg = copy_to_mode_reg (counter_mode, count_exp);
1308090284Sobrien
1308190284Sobrien      /* We don't use loops to align destination and to copy parts smaller
1308290284Sobrien         than 4 bytes, because gcc is able to optimize such code better (in
1308390284Sobrien         the case the destination or the count really is aligned, gcc is often
1308490284Sobrien         able to predict the branches) and also it is friendlier to the
1308590284Sobrien         hardware branch prediction.
1308690284Sobrien
13087132743Skan         Using loops is beneficial for generic case, because we can
1308890284Sobrien         handle small counts using the loops.  Many CPUs (such as Athlon)
1308990284Sobrien         have large REP prefix setup costs.
1309090284Sobrien
13091132743Skan         This is quite costly.  Maybe we can revisit this decision later or
1309290284Sobrien         add some customizability to this code.  */
1309390284Sobrien
13094102800Skan      if (count == 0 && align < desired_alignment)
1309590284Sobrien	{
1309690284Sobrien	  label = gen_label_rtx ();
13097102800Skan	  emit_cmp_and_jump_insns (countreg, GEN_INT (desired_alignment - 1),
1309890284Sobrien				   LEU, 0, counter_mode, 1, label);
1309990284Sobrien	}
1310090284Sobrien      if (align <= 1)
1310190284Sobrien	{
1310290284Sobrien	  rtx label = ix86_expand_aligntest (destreg, 1);
13103132743Skan	  srcmem = change_address (src, QImode, srcreg);
13104132743Skan	  dstmem = change_address (dst, QImode, destreg);
13105132743Skan	  emit_insn (gen_strmov (destreg, dstmem, srcreg, srcmem));
1310690284Sobrien	  ix86_adjust_counter (countreg, 1);
1310790284Sobrien	  emit_label (label);
1310890284Sobrien	  LABEL_NUSES (label) = 1;
1310990284Sobrien	}
1311090284Sobrien      if (align <= 2)
1311190284Sobrien	{
1311290284Sobrien	  rtx label = ix86_expand_aligntest (destreg, 2);
13113132743Skan	  srcmem = change_address (src, HImode, srcreg);
13114132743Skan	  dstmem = change_address (dst, HImode, destreg);
13115132743Skan	  emit_insn (gen_strmov (destreg, dstmem, srcreg, srcmem));
1311690284Sobrien	  ix86_adjust_counter (countreg, 2);
1311790284Sobrien	  emit_label (label);
1311890284Sobrien	  LABEL_NUSES (label) = 1;
1311990284Sobrien	}
13120102800Skan      if (align <= 4 && desired_alignment > 4)
1312190284Sobrien	{
1312290284Sobrien	  rtx label = ix86_expand_aligntest (destreg, 4);
13123132743Skan	  srcmem = change_address (src, SImode, srcreg);
13124132743Skan	  dstmem = change_address (dst, SImode, destreg);
13125132743Skan	  emit_insn (gen_strmov (destreg, dstmem, srcreg, srcmem));
1312690284Sobrien	  ix86_adjust_counter (countreg, 4);
1312790284Sobrien	  emit_label (label);
1312890284Sobrien	  LABEL_NUSES (label) = 1;
1312990284Sobrien	}
1313090284Sobrien
13131102800Skan      if (label && desired_alignment > 4 && !TARGET_64BIT)
13132102800Skan	{
13133102800Skan	  emit_label (label);
13134102800Skan	  LABEL_NUSES (label) = 1;
13135102800Skan	  label = NULL_RTX;
13136102800Skan	}
1313790284Sobrien      if (!TARGET_SINGLE_STRINGOP)
1313890284Sobrien	emit_insn (gen_cld ());
1313990284Sobrien      if (TARGET_64BIT)
1314090284Sobrien	{
1314190284Sobrien	  emit_insn (gen_lshrdi3 (countreg2, ix86_zero_extend_to_Pmode (countreg),
1314290284Sobrien				  GEN_INT (3)));
13143132743Skan	  destexp = gen_rtx_ASHIFT (Pmode, countreg2, GEN_INT (3));
1314490284Sobrien	}
1314590284Sobrien      else
1314690284Sobrien	{
13147132743Skan	  emit_insn (gen_lshrsi3 (countreg2, countreg, const2_rtx));
13148132743Skan	  destexp = gen_rtx_ASHIFT (Pmode, countreg2, const2_rtx);
1314990284Sobrien	}
13150132743Skan      srcexp = gen_rtx_PLUS (Pmode, destexp, srcreg);
13151132743Skan      destexp = gen_rtx_PLUS (Pmode, destexp, destreg);
13152132743Skan      emit_insn (gen_rep_mov (destreg, dst, srcreg, src,
13153132743Skan			      countreg2, destexp, srcexp));
1315490284Sobrien
1315590284Sobrien      if (label)
1315690284Sobrien	{
1315790284Sobrien	  emit_label (label);
1315890284Sobrien	  LABEL_NUSES (label) = 1;
1315990284Sobrien	}
1316090284Sobrien      if (TARGET_64BIT && align > 4 && count != 0 && (count & 4))
13161132743Skan	{
13162132743Skan	  srcmem = change_address (src, SImode, srcreg);
13163132743Skan	  dstmem = change_address (dst, SImode, destreg);
13164132743Skan	  emit_insn (gen_strmov (destreg, dstmem, srcreg, srcmem));
13165132743Skan	}
1316690284Sobrien      if ((align <= 4 || count == 0) && TARGET_64BIT)
1316790284Sobrien	{
1316890284Sobrien	  rtx label = ix86_expand_aligntest (countreg, 4);
13169132743Skan	  srcmem = change_address (src, SImode, srcreg);
13170132743Skan	  dstmem = change_address (dst, SImode, destreg);
13171132743Skan	  emit_insn (gen_strmov (destreg, dstmem, srcreg, srcmem));
1317290284Sobrien	  emit_label (label);
1317390284Sobrien	  LABEL_NUSES (label) = 1;
1317490284Sobrien	}
1317590284Sobrien      if (align > 2 && count != 0 && (count & 2))
13176132743Skan	{
13177132743Skan	  srcmem = change_address (src, HImode, srcreg);
13178132743Skan	  dstmem = change_address (dst, HImode, destreg);
13179132743Skan	  emit_insn (gen_strmov (destreg, dstmem, srcreg, srcmem));
13180132743Skan	}
1318190284Sobrien      if (align <= 2 || count == 0)
1318290284Sobrien	{
1318390284Sobrien	  rtx label = ix86_expand_aligntest (countreg, 2);
13184132743Skan	  srcmem = change_address (src, HImode, srcreg);
13185132743Skan	  dstmem = change_address (dst, HImode, destreg);
13186132743Skan	  emit_insn (gen_strmov (destreg, dstmem, srcreg, srcmem));
1318790284Sobrien	  emit_label (label);
1318890284Sobrien	  LABEL_NUSES (label) = 1;
1318990284Sobrien	}
1319090284Sobrien      if (align > 1 && count != 0 && (count & 1))
13191132743Skan	{
13192132743Skan	  srcmem = change_address (src, QImode, srcreg);
13193132743Skan	  dstmem = change_address (dst, QImode, destreg);
13194132743Skan	  emit_insn (gen_strmov (destreg, dstmem, srcreg, srcmem));
13195132743Skan	}
1319690284Sobrien      if (align <= 1 || count == 0)
1319790284Sobrien	{
1319890284Sobrien	  rtx label = ix86_expand_aligntest (countreg, 1);
13199132743Skan	  srcmem = change_address (src, QImode, srcreg);
13200132743Skan	  dstmem = change_address (dst, QImode, destreg);
13201132743Skan	  emit_insn (gen_strmov (destreg, dstmem, srcreg, srcmem));
1320290284Sobrien	  emit_label (label);
1320390284Sobrien	  LABEL_NUSES (label) = 1;
1320490284Sobrien	}
1320590284Sobrien    }
1320690284Sobrien
1320790284Sobrien  return 1;
1320851411Sobrien}
1320951411Sobrien
1321090284Sobrien/* Expand string clear operation (bzero).  Use i386 string operations when
13211169705Skan   profitable.  expand_movmem contains similar code.  */
1321251411Sobrienint
13213169705Skanix86_expand_clrmem (rtx dst, rtx count_exp, rtx align_exp)
1321451411Sobrien{
13215132743Skan  rtx destreg, zeroreg, countreg, destexp;
1321690284Sobrien  enum machine_mode counter_mode;
1321790284Sobrien  HOST_WIDE_INT align = 0;
1321890284Sobrien  unsigned HOST_WIDE_INT count = 0;
1321951411Sobrien
1322090284Sobrien  if (GET_CODE (align_exp) == CONST_INT)
1322190284Sobrien    align = INTVAL (align_exp);
1322252294Sobrien
13223132743Skan  /* Can't use any of this if the user has appropriated esi.  */
13224132743Skan  if (global_regs[4])
13225132743Skan    return 0;
13226132743Skan
1322790284Sobrien  /* This simple hack avoids all inlining code and simplifies code below.  */
1322890284Sobrien  if (!TARGET_ALIGN_STRINGOPS)
1322990284Sobrien    align = 32;
1323051411Sobrien
1323190284Sobrien  if (GET_CODE (count_exp) == CONST_INT)
13232132743Skan    {
13233132743Skan      count = INTVAL (count_exp);
13234132743Skan      if (!TARGET_INLINE_ALL_STRINGOPS && count > 64)
13235132743Skan	return 0;
13236132743Skan    }
1323790284Sobrien  /* Figure out proper mode for counter.  For 32bits it is always SImode,
1323890284Sobrien     for 64bits use SImode when possible, otherwise DImode.
1323990284Sobrien     Set count to number of bytes copied when known at compile time.  */
13240169705Skan  if (!TARGET_64BIT
13241169705Skan      || GET_MODE (count_exp) == SImode
13242169705Skan      || x86_64_zext_immediate_operand (count_exp, VOIDmode))
1324390284Sobrien    counter_mode = SImode;
1324490284Sobrien  else
1324590284Sobrien    counter_mode = DImode;
1324652294Sobrien
13247132743Skan  destreg = copy_to_mode_reg (Pmode, XEXP (dst, 0));
13248132743Skan  if (destreg != XEXP (dst, 0))
13249132743Skan    dst = replace_equiv_address_nv (dst, destreg);
1325052294Sobrien
1325152294Sobrien
1325290284Sobrien  /* When optimizing for size emit simple rep ; movsb instruction for
13253169705Skan     counts not divisible by 4.  The movl $N, %ecx; rep; stosb
13254169705Skan     sequence is 7 bytes long, so if optimizing for size and count is
13255169705Skan     small enough that some stosl, stosw and stosb instructions without
13256169705Skan     rep are shorter, fall back into the next if.  */
1325790284Sobrien
13258169705Skan  if ((!optimize || optimize_size)
13259169705Skan      && (count == 0
13260169705Skan	  || ((count & 0x03)
13261169705Skan	      && (!optimize_size || (count & 0x03) + (count >> 2) > 7))))
1326290284Sobrien    {
13263169705Skan      emit_insn (gen_cld ());
13264169705Skan
1326590284Sobrien      countreg = ix86_zero_extend_to_Pmode (count_exp);
1326690284Sobrien      zeroreg = copy_to_mode_reg (QImode, const0_rtx);
13267132743Skan      destexp = gen_rtx_PLUS (Pmode, destreg, countreg);
13268132743Skan      emit_insn (gen_rep_stos (destreg, countreg, dst, zeroreg, destexp));
1326990284Sobrien    }
1327090284Sobrien  else if (count != 0
1327190284Sobrien	   && (align >= 8
1327290284Sobrien	       || (!TARGET_PENTIUMPRO && !TARGET_64BIT && align >= 4)
1327390284Sobrien	       || optimize_size || count < (unsigned int) 64))
1327490284Sobrien    {
1327590284Sobrien      int size = TARGET_64BIT && !optimize_size ? 8 : 4;
13276132743Skan      unsigned HOST_WIDE_INT offset = 0;
13277132743Skan
13278169705Skan      emit_insn (gen_cld ());
13279169705Skan
1328090284Sobrien      zeroreg = copy_to_mode_reg (size == 4 ? SImode : DImode, const0_rtx);
1328190284Sobrien      if (count & ~(size - 1))
1328290284Sobrien	{
13283169705Skan	  unsigned HOST_WIDE_INT repcount;
13284169705Skan	  unsigned int max_nonrep;
13285169705Skan
13286169705Skan	  repcount = count >> (size == 4 ? 2 : 3);
13287169705Skan	  if (!TARGET_64BIT)
13288169705Skan	    repcount &= 0x3fffffff;
13289169705Skan
13290169705Skan	  /* movl $N, %ecx; rep; stosl is 7 bytes, while N x stosl is N bytes.
13291169705Skan	     movl $N, %ecx; rep; stosq is 8 bytes, while N x stosq is 2xN
13292169705Skan	     bytes.  In both cases the latter seems to be faster for small
13293169705Skan	     values of N.  */
13294169705Skan	  max_nonrep = size == 4 ? 7 : 4;
13295169705Skan	  if (!optimize_size)
13296169705Skan	    switch (ix86_tune)
13297169705Skan	      {
13298169705Skan	      case PROCESSOR_PENTIUM4:
13299169705Skan	      case PROCESSOR_NOCONA:
13300169705Skan	        max_nonrep = 3;
13301169705Skan	        break;
13302169705Skan	      default:
13303169705Skan	        break;
13304169705Skan	      }
13305169705Skan
13306169705Skan	  if (repcount <= max_nonrep)
13307169705Skan	    while (repcount-- > 0)
13308169705Skan	      {
13309169705Skan		rtx mem = adjust_automodify_address_nv (dst,
13310169705Skan							GET_MODE (zeroreg),
13311169705Skan							destreg, offset);
13312169705Skan		emit_insn (gen_strset (destreg, mem, zeroreg));
13313169705Skan		offset += size;
13314169705Skan	      }
13315169705Skan	  else
13316169705Skan	    {
13317169705Skan	      countreg = copy_to_mode_reg (counter_mode, GEN_INT (repcount));
13318169705Skan	      countreg = ix86_zero_extend_to_Pmode (countreg);
13319169705Skan	      destexp = gen_rtx_ASHIFT (Pmode, countreg,
13320169705Skan					GEN_INT (size == 4 ? 2 : 3));
13321169705Skan	      destexp = gen_rtx_PLUS (Pmode, destexp, destreg);
13322169705Skan	      emit_insn (gen_rep_stos (destreg, countreg, dst, zeroreg,
13323169705Skan				       destexp));
13324169705Skan	      offset = count & ~(size - 1);
13325169705Skan	    }
1332690284Sobrien	}
1332790284Sobrien      if (size == 8 && (count & 0x04))
13328132743Skan	{
13329132743Skan	  rtx mem = adjust_automodify_address_nv (dst, SImode, destreg,
13330132743Skan						  offset);
13331132743Skan	  emit_insn (gen_strset (destreg, mem,
1333290284Sobrien				 gen_rtx_SUBREG (SImode, zeroreg, 0)));
13333132743Skan	  offset += 4;
13334132743Skan	}
1333590284Sobrien      if (count & 0x02)
13336132743Skan	{
13337132743Skan	  rtx mem = adjust_automodify_address_nv (dst, HImode, destreg,
13338132743Skan						  offset);
13339132743Skan	  emit_insn (gen_strset (destreg, mem,
1334090284Sobrien				 gen_rtx_SUBREG (HImode, zeroreg, 0)));
13341132743Skan	  offset += 2;
13342132743Skan	}
1334390284Sobrien      if (count & 0x01)
13344132743Skan	{
13345132743Skan	  rtx mem = adjust_automodify_address_nv (dst, QImode, destreg,
13346132743Skan						  offset);
13347132743Skan	  emit_insn (gen_strset (destreg, mem,
1334890284Sobrien				 gen_rtx_SUBREG (QImode, zeroreg, 0)));
13349132743Skan	}
1335090284Sobrien    }
1335190284Sobrien  else
1335290284Sobrien    {
1335390284Sobrien      rtx countreg2;
1335490284Sobrien      rtx label = NULL;
13355102800Skan      /* Compute desired alignment of the string operation.  */
13356102800Skan      int desired_alignment = (TARGET_PENTIUMPRO
13357102800Skan			       && (count == 0 || count >= (unsigned int) 260)
13358102800Skan			       ? 8 : UNITS_PER_WORD);
1335990284Sobrien
1336090284Sobrien      /* In case we don't know anything about the alignment, default to
1336190284Sobrien         library version, since it is usually equally fast and result in
13362132743Skan         shorter code.
13363132743Skan
13364132743Skan	 Also emit call when we know that the count is large and call overhead
13365132743Skan	 will not be important.  */
13366132743Skan      if (!TARGET_INLINE_ALL_STRINGOPS
13367132743Skan	  && (align < UNITS_PER_WORD || !TARGET_REP_MOVL_OPTIMAL))
1336890284Sobrien	return 0;
1336990284Sobrien
1337090284Sobrien      if (TARGET_SINGLE_STRINGOP)
1337190284Sobrien	emit_insn (gen_cld ());
1337290284Sobrien
1337390284Sobrien      countreg2 = gen_reg_rtx (Pmode);
1337490284Sobrien      countreg = copy_to_mode_reg (counter_mode, count_exp);
1337590284Sobrien      zeroreg = copy_to_mode_reg (Pmode, const0_rtx);
13376132743Skan      /* Get rid of MEM_OFFSET, it won't be accurate.  */
13377132743Skan      dst = change_address (dst, BLKmode, destreg);
1337890284Sobrien
13379102800Skan      if (count == 0 && align < desired_alignment)
1338090284Sobrien	{
1338190284Sobrien	  label = gen_label_rtx ();
13382102800Skan	  emit_cmp_and_jump_insns (countreg, GEN_INT (desired_alignment - 1),
1338390284Sobrien				   LEU, 0, counter_mode, 1, label);
1338490284Sobrien	}
1338590284Sobrien      if (align <= 1)
1338690284Sobrien	{
1338790284Sobrien	  rtx label = ix86_expand_aligntest (destreg, 1);
13388132743Skan	  emit_insn (gen_strset (destreg, dst,
13389132743Skan				 gen_rtx_SUBREG (QImode, zeroreg, 0)));
1339090284Sobrien	  ix86_adjust_counter (countreg, 1);
1339190284Sobrien	  emit_label (label);
1339290284Sobrien	  LABEL_NUSES (label) = 1;
1339390284Sobrien	}
1339490284Sobrien      if (align <= 2)
1339590284Sobrien	{
1339690284Sobrien	  rtx label = ix86_expand_aligntest (destreg, 2);
13397132743Skan	  emit_insn (gen_strset (destreg, dst,
13398132743Skan				 gen_rtx_SUBREG (HImode, zeroreg, 0)));
1339990284Sobrien	  ix86_adjust_counter (countreg, 2);
1340090284Sobrien	  emit_label (label);
1340190284Sobrien	  LABEL_NUSES (label) = 1;
1340290284Sobrien	}
13403102800Skan      if (align <= 4 && desired_alignment > 4)
1340490284Sobrien	{
1340590284Sobrien	  rtx label = ix86_expand_aligntest (destreg, 4);
13406132743Skan	  emit_insn (gen_strset (destreg, dst,
13407132743Skan				 (TARGET_64BIT
13408132743Skan				  ? gen_rtx_SUBREG (SImode, zeroreg, 0)
13409132743Skan				  : zeroreg)));
1341090284Sobrien	  ix86_adjust_counter (countreg, 4);
1341190284Sobrien	  emit_label (label);
1341290284Sobrien	  LABEL_NUSES (label) = 1;
1341390284Sobrien	}
1341490284Sobrien
13415102800Skan      if (label && desired_alignment > 4 && !TARGET_64BIT)
13416102800Skan	{
13417102800Skan	  emit_label (label);
13418102800Skan	  LABEL_NUSES (label) = 1;
13419102800Skan	  label = NULL_RTX;
13420102800Skan	}
13421102800Skan
1342290284Sobrien      if (!TARGET_SINGLE_STRINGOP)
1342390284Sobrien	emit_insn (gen_cld ());
1342490284Sobrien      if (TARGET_64BIT)
1342590284Sobrien	{
1342690284Sobrien	  emit_insn (gen_lshrdi3 (countreg2, ix86_zero_extend_to_Pmode (countreg),
1342790284Sobrien				  GEN_INT (3)));
13428132743Skan	  destexp = gen_rtx_ASHIFT (Pmode, countreg2, GEN_INT (3));
1342990284Sobrien	}
1343090284Sobrien      else
1343190284Sobrien	{
13432132743Skan	  emit_insn (gen_lshrsi3 (countreg2, countreg, const2_rtx));
13433132743Skan	  destexp = gen_rtx_ASHIFT (Pmode, countreg2, const2_rtx);
1343490284Sobrien	}
13435132743Skan      destexp = gen_rtx_PLUS (Pmode, destexp, destreg);
13436132743Skan      emit_insn (gen_rep_stos (destreg, countreg2, dst, zeroreg, destexp));
13437132743Skan
1343890284Sobrien      if (label)
1343990284Sobrien	{
1344090284Sobrien	  emit_label (label);
1344190284Sobrien	  LABEL_NUSES (label) = 1;
1344290284Sobrien	}
13443102800Skan
1344490284Sobrien      if (TARGET_64BIT && align > 4 && count != 0 && (count & 4))
13445132743Skan	emit_insn (gen_strset (destreg, dst,
13446132743Skan			       gen_rtx_SUBREG (SImode, zeroreg, 0)));
1344790284Sobrien      if (TARGET_64BIT && (align <= 4 || count == 0))
1344890284Sobrien	{
1344997827Sobrien	  rtx label = ix86_expand_aligntest (countreg, 4);
13450132743Skan	  emit_insn (gen_strset (destreg, dst,
13451132743Skan				 gen_rtx_SUBREG (SImode, zeroreg, 0)));
1345290284Sobrien	  emit_label (label);
1345390284Sobrien	  LABEL_NUSES (label) = 1;
1345490284Sobrien	}
1345590284Sobrien      if (align > 2 && count != 0 && (count & 2))
13456132743Skan	emit_insn (gen_strset (destreg, dst,
13457132743Skan			       gen_rtx_SUBREG (HImode, zeroreg, 0)));
1345890284Sobrien      if (align <= 2 || count == 0)
1345990284Sobrien	{
1346097827Sobrien	  rtx label = ix86_expand_aligntest (countreg, 2);
13461132743Skan	  emit_insn (gen_strset (destreg, dst,
13462132743Skan				 gen_rtx_SUBREG (HImode, zeroreg, 0)));
1346390284Sobrien	  emit_label (label);
1346490284Sobrien	  LABEL_NUSES (label) = 1;
1346590284Sobrien	}
1346690284Sobrien      if (align > 1 && count != 0 && (count & 1))
13467132743Skan	emit_insn (gen_strset (destreg, dst,
13468132743Skan			       gen_rtx_SUBREG (QImode, zeroreg, 0)));
1346990284Sobrien      if (align <= 1 || count == 0)
1347090284Sobrien	{
1347197827Sobrien	  rtx label = ix86_expand_aligntest (countreg, 1);
13472132743Skan	  emit_insn (gen_strset (destreg, dst,
13473132743Skan				 gen_rtx_SUBREG (QImode, zeroreg, 0)));
1347490284Sobrien	  emit_label (label);
1347590284Sobrien	  LABEL_NUSES (label) = 1;
1347690284Sobrien	}
1347790284Sobrien    }
1347890284Sobrien  return 1;
1347951411Sobrien}
13480132743Skan
1348190284Sobrien/* Expand strlen.  */
1348251411Sobrienint
13483132743Skanix86_expand_strlen (rtx out, rtx src, rtx eoschar, rtx align)
1348451411Sobrien{
1348590284Sobrien  rtx addr, scratch1, scratch2, scratch3, scratch4;
1348651411Sobrien
1348790284Sobrien  /* The generic case of strlen expander is long.  Avoid it's
1348890284Sobrien     expanding unless TARGET_INLINE_ALL_STRINGOPS.  */
1348990284Sobrien
1349090284Sobrien  if (TARGET_UNROLL_STRLEN && eoschar == const0_rtx && optimize > 1
1349190284Sobrien      && !TARGET_INLINE_ALL_STRINGOPS
1349290284Sobrien      && !optimize_size
1349390284Sobrien      && (GET_CODE (align) != CONST_INT || INTVAL (align) < 4))
1349451411Sobrien    return 0;
1349551411Sobrien
1349690284Sobrien  addr = force_reg (Pmode, XEXP (src, 0));
1349790284Sobrien  scratch1 = gen_reg_rtx (Pmode);
1349851411Sobrien
1349990284Sobrien  if (TARGET_UNROLL_STRLEN && eoschar == const0_rtx && optimize > 1
1350090284Sobrien      && !optimize_size)
1350151411Sobrien    {
1350290284Sobrien      /* Well it seems that some optimizer does not combine a call like
1350390284Sobrien         foo(strlen(bar), strlen(bar));
1350490284Sobrien         when the move and the subtraction is done here.  It does calculate
1350590284Sobrien         the length just once when these instructions are done inside of
1350690284Sobrien         output_strlen_unroll().  But I think since &bar[strlen(bar)] is
1350790284Sobrien         often used and I use one fewer register for the lifetime of
1350890284Sobrien         output_strlen_unroll() this is better.  */
1350990284Sobrien
1351090284Sobrien      emit_move_insn (out, addr);
1351190284Sobrien
13512132743Skan      ix86_expand_strlensi_unroll_1 (out, src, align);
1351390284Sobrien
1351490284Sobrien      /* strlensi_unroll_1 returns the address of the zero at the end of
1351590284Sobrien         the string, like memchr(), so compute the length by subtracting
1351690284Sobrien         the start address.  */
1351790284Sobrien      if (TARGET_64BIT)
1351890284Sobrien	emit_insn (gen_subdi3 (out, out, addr));
1351990284Sobrien      else
1352090284Sobrien	emit_insn (gen_subsi3 (out, out, addr));
1352151411Sobrien    }
1352290284Sobrien  else
1352390284Sobrien    {
13524132743Skan      rtx unspec;
1352590284Sobrien      scratch2 = gen_reg_rtx (Pmode);
1352690284Sobrien      scratch3 = gen_reg_rtx (Pmode);
1352790284Sobrien      scratch4 = force_reg (Pmode, constm1_rtx);
1352851411Sobrien
1352990284Sobrien      emit_move_insn (scratch3, addr);
1353090284Sobrien      eoschar = force_reg (QImode, eoschar);
1353151411Sobrien
1353290284Sobrien      emit_insn (gen_cld ());
13533132743Skan      src = replace_equiv_address_nv (src, scratch3);
13534132743Skan
13535132743Skan      /* If .md starts supporting :P, this can be done in .md.  */
13536132743Skan      unspec = gen_rtx_UNSPEC (Pmode, gen_rtvec (4, src, eoschar, align,
13537132743Skan						 scratch4), UNSPEC_SCAS);
13538132743Skan      emit_insn (gen_strlenqi_1 (scratch1, scratch3, unspec));
1353990284Sobrien      if (TARGET_64BIT)
1354051411Sobrien	{
1354190284Sobrien	  emit_insn (gen_one_cmpldi2 (scratch2, scratch1));
1354290284Sobrien	  emit_insn (gen_adddi3 (out, scratch2, constm1_rtx));
1354351411Sobrien	}
1354490284Sobrien      else
1354590284Sobrien	{
1354690284Sobrien	  emit_insn (gen_one_cmplsi2 (scratch2, scratch1));
1354790284Sobrien	  emit_insn (gen_addsi3 (out, scratch2, constm1_rtx));
1354890284Sobrien	}
1354951411Sobrien    }
1355090284Sobrien  return 1;
1355151411Sobrien}
1355251411Sobrien
1355390284Sobrien/* Expand the appropriate insns for doing strlen if not just doing
1355490284Sobrien   repnz; scasb
1355551411Sobrien
1355690284Sobrien   out = result, initialized with the start address
1355790284Sobrien   align_rtx = alignment of the address.
1355890284Sobrien   scratch = scratch register, initialized with the startaddress when
1355990284Sobrien	not aligned, otherwise undefined
1356090284Sobrien
13561132743Skan   This is just the body. It needs the initializations mentioned above and
1356251411Sobrien   some address computing at the end.  These things are done in i386.md.  */
1356351411Sobrien
1356490284Sobrienstatic void
13565132743Skanix86_expand_strlensi_unroll_1 (rtx out, rtx src, rtx align_rtx)
1356651411Sobrien{
1356790284Sobrien  int align;
1356890284Sobrien  rtx tmp;
1356990284Sobrien  rtx align_2_label = NULL_RTX;
1357090284Sobrien  rtx align_3_label = NULL_RTX;
1357190284Sobrien  rtx align_4_label = gen_label_rtx ();
1357290284Sobrien  rtx end_0_label = gen_label_rtx ();
1357390284Sobrien  rtx mem;
1357490284Sobrien  rtx tmpreg = gen_reg_rtx (SImode);
1357590284Sobrien  rtx scratch = gen_reg_rtx (SImode);
13576132743Skan  rtx cmp;
1357751411Sobrien
1357890284Sobrien  align = 0;
1357990284Sobrien  if (GET_CODE (align_rtx) == CONST_INT)
1358090284Sobrien    align = INTVAL (align_rtx);
1358151411Sobrien
1358251411Sobrien  /* Loop to check 1..3 bytes for null to get an aligned pointer.  */
1358351411Sobrien
1358451411Sobrien  /* Is there a known alignment and is it less than 4?  */
1358590284Sobrien  if (align < 4)
1358651411Sobrien    {
1358790284Sobrien      rtx scratch1 = gen_reg_rtx (Pmode);
1358890284Sobrien      emit_move_insn (scratch1, out);
1358951411Sobrien      /* Is there a known alignment and is it not 2? */
1359090284Sobrien      if (align != 2)
1359151411Sobrien	{
1359290284Sobrien	  align_3_label = gen_label_rtx (); /* Label when aligned to 3-byte */
1359390284Sobrien	  align_2_label = gen_label_rtx (); /* Label when aligned to 2-byte */
1359451411Sobrien
1359590284Sobrien	  /* Leave just the 3 lower bits.  */
1359690284Sobrien	  align_rtx = expand_binop (Pmode, and_optab, scratch1, GEN_INT (3),
1359790284Sobrien				    NULL_RTX, 0, OPTAB_WIDEN);
1359851411Sobrien
1359990284Sobrien	  emit_cmp_and_jump_insns (align_rtx, const0_rtx, EQ, NULL,
1360090284Sobrien				   Pmode, 1, align_4_label);
13601169705Skan	  emit_cmp_and_jump_insns (align_rtx, const2_rtx, EQ, NULL,
1360290284Sobrien				   Pmode, 1, align_2_label);
13603169705Skan	  emit_cmp_and_jump_insns (align_rtx, const2_rtx, GTU, NULL,
1360490284Sobrien				   Pmode, 1, align_3_label);
1360551411Sobrien	}
1360651411Sobrien      else
1360751411Sobrien        {
1360851411Sobrien	  /* Since the alignment is 2, we have to check 2 or 0 bytes;
1360951411Sobrien	     check if is aligned to 4 - byte.  */
1361051411Sobrien
13611169705Skan	  align_rtx = expand_binop (Pmode, and_optab, scratch1, const2_rtx,
1361290284Sobrien				    NULL_RTX, 0, OPTAB_WIDEN);
1361390284Sobrien
1361490284Sobrien	  emit_cmp_and_jump_insns (align_rtx, const0_rtx, EQ, NULL,
1361590284Sobrien				   Pmode, 1, align_4_label);
1361651411Sobrien        }
1361751411Sobrien
13618132743Skan      mem = change_address (src, QImode, out);
1361951411Sobrien
1362090284Sobrien      /* Now compare the bytes.  */
1362151411Sobrien
1362290284Sobrien      /* Compare the first n unaligned byte on a byte per byte basis.  */
1362390284Sobrien      emit_cmp_and_jump_insns (mem, const0_rtx, EQ, NULL,
1362490284Sobrien			       QImode, 1, end_0_label);
1362551411Sobrien
1362690284Sobrien      /* Increment the address.  */
1362790284Sobrien      if (TARGET_64BIT)
1362890284Sobrien	emit_insn (gen_adddi3 (out, out, const1_rtx));
1362990284Sobrien      else
1363090284Sobrien	emit_insn (gen_addsi3 (out, out, const1_rtx));
1363151411Sobrien
1363290284Sobrien      /* Not needed with an alignment of 2 */
1363390284Sobrien      if (align != 2)
1363490284Sobrien	{
1363590284Sobrien	  emit_label (align_2_label);
1363651411Sobrien
1363790284Sobrien	  emit_cmp_and_jump_insns (mem, const0_rtx, EQ, NULL, QImode, 1,
1363890284Sobrien				   end_0_label);
1363951411Sobrien
1364090284Sobrien	  if (TARGET_64BIT)
1364190284Sobrien	    emit_insn (gen_adddi3 (out, out, const1_rtx));
1364290284Sobrien	  else
1364390284Sobrien	    emit_insn (gen_addsi3 (out, out, const1_rtx));
1364451411Sobrien
1364590284Sobrien	  emit_label (align_3_label);
1364690284Sobrien	}
1364751411Sobrien
1364890284Sobrien      emit_cmp_and_jump_insns (mem, const0_rtx, EQ, NULL, QImode, 1,
1364990284Sobrien			       end_0_label);
1365053177Sobrien
1365190284Sobrien      if (TARGET_64BIT)
1365290284Sobrien	emit_insn (gen_adddi3 (out, out, const1_rtx));
1365390284Sobrien      else
1365490284Sobrien	emit_insn (gen_addsi3 (out, out, const1_rtx));
1365551411Sobrien    }
1365651411Sobrien
1365790284Sobrien  /* Generate loop to check 4 bytes at a time.  It is not a good idea to
1365890284Sobrien     align this loop.  It gives only huge programs, but does not help to
1365990284Sobrien     speed up.  */
1366090284Sobrien  emit_label (align_4_label);
1366151411Sobrien
13662132743Skan  mem = change_address (src, SImode, out);
1366390284Sobrien  emit_move_insn (scratch, mem);
1366490284Sobrien  if (TARGET_64BIT)
1366590284Sobrien    emit_insn (gen_adddi3 (out, out, GEN_INT (4)));
1366690284Sobrien  else
1366790284Sobrien    emit_insn (gen_addsi3 (out, out, GEN_INT (4)));
1366851411Sobrien
1366990284Sobrien  /* This formula yields a nonzero result iff one of the bytes is zero.
1367090284Sobrien     This saves three branches inside loop and many cycles.  */
1367190284Sobrien
1367290284Sobrien  emit_insn (gen_addsi3 (tmpreg, scratch, GEN_INT (-0x01010101)));
1367390284Sobrien  emit_insn (gen_one_cmplsi2 (scratch, scratch));
1367490284Sobrien  emit_insn (gen_andsi3 (tmpreg, tmpreg, scratch));
1367590284Sobrien  emit_insn (gen_andsi3 (tmpreg, tmpreg,
13676117408Skan			 gen_int_mode (0x80808080, SImode)));
1367790284Sobrien  emit_cmp_and_jump_insns (tmpreg, const0_rtx, EQ, 0, SImode, 1,
1367890284Sobrien			   align_4_label);
1367990284Sobrien
1368090284Sobrien  if (TARGET_CMOVE)
1368151411Sobrien    {
1368290284Sobrien       rtx reg = gen_reg_rtx (SImode);
1368390284Sobrien       rtx reg2 = gen_reg_rtx (Pmode);
1368490284Sobrien       emit_move_insn (reg, tmpreg);
1368590284Sobrien       emit_insn (gen_lshrsi3 (reg, reg, GEN_INT (16)));
1368651411Sobrien
1368790284Sobrien       /* If zero is not in the first two bytes, move two bytes forward.  */
1368890284Sobrien       emit_insn (gen_testsi_ccno_1 (tmpreg, GEN_INT (0x8080)));
1368990284Sobrien       tmp = gen_rtx_REG (CCNOmode, FLAGS_REG);
1369090284Sobrien       tmp = gen_rtx_EQ (VOIDmode, tmp, const0_rtx);
1369190284Sobrien       emit_insn (gen_rtx_SET (VOIDmode, tmpreg,
1369290284Sobrien			       gen_rtx_IF_THEN_ELSE (SImode, tmp,
1369390284Sobrien						     reg,
1369490284Sobrien						     tmpreg)));
1369590284Sobrien       /* Emit lea manually to avoid clobbering of flags.  */
1369690284Sobrien       emit_insn (gen_rtx_SET (SImode, reg2,
13697169705Skan			       gen_rtx_PLUS (Pmode, out, const2_rtx)));
1369851411Sobrien
1369990284Sobrien       tmp = gen_rtx_REG (CCNOmode, FLAGS_REG);
1370090284Sobrien       tmp = gen_rtx_EQ (VOIDmode, tmp, const0_rtx);
1370190284Sobrien       emit_insn (gen_rtx_SET (VOIDmode, out,
1370290284Sobrien			       gen_rtx_IF_THEN_ELSE (Pmode, tmp,
1370390284Sobrien						     reg2,
1370490284Sobrien						     out)));
1370551411Sobrien
1370651411Sobrien    }
1370751411Sobrien  else
1370851411Sobrien    {
1370990284Sobrien       rtx end_2_label = gen_label_rtx ();
1371090284Sobrien       /* Is zero in the first two bytes? */
1371151411Sobrien
1371290284Sobrien       emit_insn (gen_testsi_ccno_1 (tmpreg, GEN_INT (0x8080)));
1371390284Sobrien       tmp = gen_rtx_REG (CCNOmode, FLAGS_REG);
1371490284Sobrien       tmp = gen_rtx_NE (VOIDmode, tmp, const0_rtx);
1371590284Sobrien       tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
1371690284Sobrien                            gen_rtx_LABEL_REF (VOIDmode, end_2_label),
1371790284Sobrien                            pc_rtx);
1371890284Sobrien       tmp = emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
1371990284Sobrien       JUMP_LABEL (tmp) = end_2_label;
1372090284Sobrien
1372190284Sobrien       /* Not in the first two.  Move two bytes forward.  */
1372290284Sobrien       emit_insn (gen_lshrsi3 (tmpreg, tmpreg, GEN_INT (16)));
1372390284Sobrien       if (TARGET_64BIT)
13724169705Skan	 emit_insn (gen_adddi3 (out, out, const2_rtx));
1372590284Sobrien       else
13726169705Skan	 emit_insn (gen_addsi3 (out, out, const2_rtx));
1372790284Sobrien
1372890284Sobrien       emit_label (end_2_label);
1372990284Sobrien
1373051411Sobrien    }
1373151411Sobrien
1373290284Sobrien  /* Avoid branch in fixing the byte.  */
1373390284Sobrien  tmpreg = gen_lowpart (QImode, tmpreg);
1373490284Sobrien  emit_insn (gen_addqi3_cc (tmpreg, tmpreg, tmpreg));
13735132743Skan  cmp = gen_rtx_LTU (Pmode, gen_rtx_REG (CCmode, 17), const0_rtx);
1373690284Sobrien  if (TARGET_64BIT)
13737132743Skan    emit_insn (gen_subdi3_carry_rex64 (out, out, GEN_INT (3), cmp));
1373890284Sobrien  else
13739132743Skan    emit_insn (gen_subsi3_carry (out, out, GEN_INT (3), cmp));
1374051411Sobrien
1374190284Sobrien  emit_label (end_0_label);
1374290284Sobrien}
1374351411Sobrien
13744117408Skanvoid
13745132743Skanix86_expand_call (rtx retval, rtx fnaddr, rtx callarg1,
13746132743Skan		  rtx callarg2 ATTRIBUTE_UNUSED,
13747132743Skan		  rtx pop, int sibcall)
1374890284Sobrien{
13749117408Skan  rtx use = NULL, call;
1375051411Sobrien
13751117408Skan  if (pop == const0_rtx)
13752117408Skan    pop = NULL;
13753169705Skan  gcc_assert (!TARGET_64BIT || !pop);
1375451411Sobrien
13755169705Skan  if (TARGET_MACHO && !TARGET_64BIT)
13756169705Skan    {
13757117408Skan#if TARGET_MACHO
13758169705Skan      if (flag_pic && GET_CODE (XEXP (fnaddr, 0)) == SYMBOL_REF)
13759169705Skan	fnaddr = machopic_indirect_call_target (fnaddr);
13760169705Skan#endif
13761169705Skan    }
13762169705Skan  else
13763169705Skan    {
13764169705Skan      /* Static functions and indirect calls don't need the pic register.  */
13765169705Skan      if (! TARGET_64BIT && flag_pic
13766169705Skan	  && GET_CODE (XEXP (fnaddr, 0)) == SYMBOL_REF
13767169705Skan	  && ! SYMBOL_REF_LOCAL_P (XEXP (fnaddr, 0)))
13768169705Skan	use_reg (&use, pic_offset_table_rtx);
13769169705Skan    }
1377051411Sobrien
13771117408Skan  if (TARGET_64BIT && INTVAL (callarg2) >= 0)
13772117408Skan    {
13773117408Skan      rtx al = gen_rtx_REG (QImode, 0);
13774117408Skan      emit_move_insn (al, callarg2);
13775117408Skan      use_reg (&use, al);
13776117408Skan    }
13777117408Skan
13778117408Skan  if (! call_insn_operand (XEXP (fnaddr, 0), Pmode))
13779117408Skan    {
13780117408Skan      fnaddr = copy_to_mode_reg (Pmode, XEXP (fnaddr, 0));
13781117408Skan      fnaddr = gen_rtx_MEM (QImode, fnaddr);
13782117408Skan    }
13783132743Skan  if (sibcall && TARGET_64BIT
13784132743Skan      && !constant_call_address_operand (XEXP (fnaddr, 0), Pmode))
13785132743Skan    {
13786132743Skan      rtx addr;
13787132743Skan      addr = copy_to_mode_reg (Pmode, XEXP (fnaddr, 0));
13788132743Skan      fnaddr = gen_rtx_REG (Pmode, FIRST_REX_INT_REG + 3 /* R11 */);
13789132743Skan      emit_move_insn (fnaddr, addr);
13790132743Skan      fnaddr = gen_rtx_MEM (QImode, fnaddr);
13791132743Skan    }
13792117408Skan
13793117408Skan  call = gen_rtx_CALL (VOIDmode, fnaddr, callarg1);
13794117408Skan  if (retval)
13795117408Skan    call = gen_rtx_SET (VOIDmode, retval, call);
13796117408Skan  if (pop)
13797117408Skan    {
13798117408Skan      pop = gen_rtx_PLUS (Pmode, stack_pointer_rtx, pop);
13799117408Skan      pop = gen_rtx_SET (VOIDmode, stack_pointer_rtx, pop);
13800117408Skan      call = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, call, pop));
13801117408Skan    }
13802117408Skan
13803117408Skan  call = emit_call_insn (call);
13804117408Skan  if (use)
13805117408Skan    CALL_INSN_FUNCTION_USAGE (call) = use;
1380690284Sobrien}
1380751411Sobrien
13808117408Skan
13809117408Skan/* Clear stack slot assignments remembered from previous functions.
13810117408Skan   This is called from INIT_EXPANDERS once before RTL is emitted for each
13811117408Skan   function.  */
13812117408Skan
13813117408Skanstatic struct machine_function *
13814132743Skanix86_init_machine_status (void)
1381590284Sobrien{
13816132743Skan  struct machine_function *f;
13817132743Skan
13818132743Skan  f = ggc_alloc_cleared (sizeof (struct machine_function));
13819132743Skan  f->use_fast_prologue_epilogue_nregs = -1;
13820169705Skan  f->tls_descriptor_call_expanded_p = 0;
13821132743Skan
13822132743Skan  return f;
1382351411Sobrien}
1382451411Sobrien
1382590284Sobrien/* Return a MEM corresponding to a stack slot with mode MODE.
1382690284Sobrien   Allocate a new slot if necessary.
1382790284Sobrien
1382890284Sobrien   The RTL for a function can have several slots available: N is
1382990284Sobrien   which slot to use.  */
1383090284Sobrien
1383190284Sobrienrtx
13832169705Skanassign_386_stack_local (enum machine_mode mode, enum ix86_stack_slot n)
1383351411Sobrien{
13834132743Skan  struct stack_local_entry *s;
13835132743Skan
13836169705Skan  gcc_assert (n < MAX_386_STACK_LOCALS);
1383752294Sobrien
13838171836Skan  /* Virtual slot is valid only before vregs are instantiated.  */
13839171836Skan  gcc_assert ((n == SLOT_VIRTUAL) == !virtuals_instantiated);
13840171836Skan
13841132743Skan  for (s = ix86_stack_locals; s; s = s->next)
13842132743Skan    if (s->mode == mode && s->n == n)
13843132743Skan      return s->rtl;
1384490284Sobrien
13845132743Skan  s = (struct stack_local_entry *)
13846132743Skan    ggc_alloc (sizeof (struct stack_local_entry));
13847132743Skan  s->n = n;
13848132743Skan  s->mode = mode;
13849132743Skan  s->rtl = assign_stack_local (mode, GET_MODE_SIZE (mode), 0);
13850132743Skan
13851132743Skan  s->next = ix86_stack_locals;
13852132743Skan  ix86_stack_locals = s;
13853132743Skan  return s->rtl;
1385490284Sobrien}
13855117408Skan
13856117408Skan/* Construct the SYMBOL_REF for the tls_get_addr function.  */
13857117408Skan
13858117408Skanstatic GTY(()) rtx ix86_tls_symbol;
13859117408Skanrtx
13860132743Skanix86_tls_get_addr (void)
13861117408Skan{
13862117408Skan
13863117408Skan  if (!ix86_tls_symbol)
13864117408Skan    {
13865117408Skan      ix86_tls_symbol = gen_rtx_SYMBOL_REF (Pmode,
13866169705Skan					    (TARGET_ANY_GNU_TLS
13867169705Skan					     && !TARGET_64BIT)
13868117408Skan					    ? "___tls_get_addr"
13869117408Skan					    : "__tls_get_addr");
13870117408Skan    }
13871117408Skan
13872117408Skan  return ix86_tls_symbol;
13873117408Skan}
13874169705Skan
13875169705Skan/* Construct the SYMBOL_REF for the _TLS_MODULE_BASE_ symbol.  */
13876169705Skan
13877169705Skanstatic GTY(()) rtx ix86_tls_module_base_symbol;
13878169705Skanrtx
13879169705Skanix86_tls_module_base (void)
13880169705Skan{
13881169705Skan
13882169705Skan  if (!ix86_tls_module_base_symbol)
13883169705Skan    {
13884169705Skan      ix86_tls_module_base_symbol = gen_rtx_SYMBOL_REF (Pmode,
13885169705Skan							"_TLS_MODULE_BASE_");
13886169705Skan      SYMBOL_REF_FLAGS (ix86_tls_module_base_symbol)
13887169705Skan	|= TLS_MODEL_GLOBAL_DYNAMIC << SYMBOL_FLAG_TLS_SHIFT;
13888169705Skan    }
13889169705Skan
13890169705Skan  return ix86_tls_module_base_symbol;
13891169705Skan}
1389290284Sobrien
1389390284Sobrien/* Calculate the length of the memory address in the instruction
1389490284Sobrien   encoding.  Does not include the one-byte modrm, opcode, or prefix.  */
1389590284Sobrien
13896169705Skanint
13897132743Skanmemory_address_length (rtx addr)
1389890284Sobrien{
1389990284Sobrien  struct ix86_address parts;
1390090284Sobrien  rtx base, index, disp;
1390190284Sobrien  int len;
13902169705Skan  int ok;
1390390284Sobrien
1390490284Sobrien  if (GET_CODE (addr) == PRE_DEC
1390590284Sobrien      || GET_CODE (addr) == POST_INC
1390690284Sobrien      || GET_CODE (addr) == PRE_MODIFY
1390790284Sobrien      || GET_CODE (addr) == POST_MODIFY)
1390890284Sobrien    return 0;
1390990284Sobrien
13910169705Skan  ok = ix86_decompose_address (addr, &parts);
13911169705Skan  gcc_assert (ok);
1391252294Sobrien
13913169705Skan  if (parts.base && GET_CODE (parts.base) == SUBREG)
13914169705Skan    parts.base = SUBREG_REG (parts.base);
13915169705Skan  if (parts.index && GET_CODE (parts.index) == SUBREG)
13916169705Skan    parts.index = SUBREG_REG (parts.index);
13917169705Skan
1391890284Sobrien  base = parts.base;
1391990284Sobrien  index = parts.index;
1392090284Sobrien  disp = parts.disp;
1392190284Sobrien  len = 0;
1392290284Sobrien
13923122194Skan  /* Rule of thumb:
13924122194Skan       - esp as the base always wants an index,
13925122194Skan       - ebp as the base always wants a displacement.  */
13926122194Skan
1392790284Sobrien  /* Register Indirect.  */
1392890284Sobrien  if (base && !index && !disp)
1392951411Sobrien    {
13930122194Skan      /* esp (for its index) and ebp (for its displacement) need
13931122194Skan	 the two-byte modrm form.  */
1393290284Sobrien      if (addr == stack_pointer_rtx
1393390284Sobrien	  || addr == arg_pointer_rtx
1393490284Sobrien	  || addr == frame_pointer_rtx
1393590284Sobrien	  || addr == hard_frame_pointer_rtx)
1393690284Sobrien	len = 1;
1393790284Sobrien    }
1393851411Sobrien
1393990284Sobrien  /* Direct Addressing.  */
1394090284Sobrien  else if (disp && !base && !index)
1394190284Sobrien    len = 4;
1394251411Sobrien
1394390284Sobrien  else
1394490284Sobrien    {
1394590284Sobrien      /* Find the length of the displacement constant.  */
1394690284Sobrien      if (disp)
1394790284Sobrien	{
13948169705Skan	  if (base && satisfies_constraint_K (disp))
1394990284Sobrien	    len = 1;
1395090284Sobrien	  else
1395190284Sobrien	    len = 4;
1395290284Sobrien	}
13953122194Skan      /* ebp always wants a displacement.  */
13954122194Skan      else if (base == hard_frame_pointer_rtx)
13955122194Skan        len = 1;
1395690284Sobrien
13957132743Skan      /* An index requires the two-byte modrm form....  */
13958122194Skan      if (index
13959122194Skan	  /* ...like esp, which always wants an index.  */
13960122194Skan	  || base == stack_pointer_rtx
13961122194Skan	  || base == arg_pointer_rtx
13962122194Skan	  || base == frame_pointer_rtx)
1396390284Sobrien	len += 1;
1396451411Sobrien    }
1396551411Sobrien
1396690284Sobrien  return len;
1396751411Sobrien}
1396851411Sobrien
13969117408Skan/* Compute default value for "length_immediate" attribute.  When SHORTFORM
13970117408Skan   is set, expect that insn have 8bit immediate alternative.  */
1397190284Sobrienint
13972132743Skanix86_attr_length_immediate_default (rtx insn, int shortform)
1397351411Sobrien{
1397490284Sobrien  int len = 0;
1397590284Sobrien  int i;
1397690284Sobrien  extract_insn_cached (insn);
1397790284Sobrien  for (i = recog_data.n_operands - 1; i >= 0; --i)
1397890284Sobrien    if (CONSTANT_P (recog_data.operand[i]))
1397990284Sobrien      {
13980169705Skan	gcc_assert (!len);
13981169705Skan	if (shortform && satisfies_constraint_K (recog_data.operand[i]))
1398290284Sobrien	  len = 1;
1398390284Sobrien	else
1398490284Sobrien	  {
1398590284Sobrien	    switch (get_attr_mode (insn))
1398690284Sobrien	      {
1398790284Sobrien		case MODE_QI:
1398890284Sobrien		  len+=1;
1398990284Sobrien		  break;
1399090284Sobrien		case MODE_HI:
1399190284Sobrien		  len+=2;
1399290284Sobrien		  break;
1399390284Sobrien		case MODE_SI:
1399490284Sobrien		  len+=4;
1399590284Sobrien		  break;
1399690284Sobrien		/* Immediates for DImode instructions are encoded as 32bit sign extended values.  */
1399790284Sobrien		case MODE_DI:
1399890284Sobrien		  len+=4;
1399990284Sobrien		  break;
1400090284Sobrien		default:
1400190284Sobrien		  fatal_insn ("unknown insn mode", insn);
1400290284Sobrien	      }
1400390284Sobrien	  }
1400490284Sobrien      }
1400590284Sobrien  return len;
1400690284Sobrien}
1400790284Sobrien/* Compute default value for "length_address" attribute.  */
1400890284Sobrienint
14009132743Skanix86_attr_length_address_default (rtx insn)
1401090284Sobrien{
1401190284Sobrien  int i;
14012117408Skan
14013117408Skan  if (get_attr_type (insn) == TYPE_LEA)
14014117408Skan    {
14015117408Skan      rtx set = PATTERN (insn);
14016169705Skan
14017169705Skan      if (GET_CODE (set) == PARALLEL)
14018117408Skan	set = XVECEXP (set, 0, 0);
14019117408Skan
14020169705Skan      gcc_assert (GET_CODE (set) == SET);
14021169705Skan
14022117408Skan      return memory_address_length (SET_SRC (set));
14023117408Skan    }
14024117408Skan
1402590284Sobrien  extract_insn_cached (insn);
1402690284Sobrien  for (i = recog_data.n_operands - 1; i >= 0; --i)
1402790284Sobrien    if (GET_CODE (recog_data.operand[i]) == MEM)
1402890284Sobrien      {
1402990284Sobrien	return memory_address_length (XEXP (recog_data.operand[i], 0));
1403090284Sobrien	break;
1403190284Sobrien      }
1403290284Sobrien  return 0;
1403390284Sobrien}
1403490284Sobrien
1403590284Sobrien/* Return the maximum number of instructions a cpu can issue.  */
1403651411Sobrien
1403790284Sobrienstatic int
14038132743Skanix86_issue_rate (void)
1403990284Sobrien{
14040132743Skan  switch (ix86_tune)
1404190284Sobrien    {
1404290284Sobrien    case PROCESSOR_PENTIUM:
1404390284Sobrien    case PROCESSOR_K6:
1404490284Sobrien      return 2;
1404551411Sobrien
1404690284Sobrien    case PROCESSOR_PENTIUMPRO:
1404790284Sobrien    case PROCESSOR_PENTIUM4:
1404890284Sobrien    case PROCESSOR_ATHLON:
14049132743Skan    case PROCESSOR_K8:
14050251212Spfg    case PROCESSOR_AMDFAM10:
14051169705Skan    case PROCESSOR_NOCONA:
14052169705Skan    case PROCESSOR_GENERIC32:
14053169705Skan    case PROCESSOR_GENERIC64:
1405490284Sobrien      return 3;
1405551411Sobrien
14056219374Smm    case PROCESSOR_CORE2:
14057219374Smm      return 4;
14058219374Smm
1405990284Sobrien    default:
1406090284Sobrien      return 1;
1406190284Sobrien    }
1406290284Sobrien}
1406351411Sobrien
1406490284Sobrien/* A subroutine of ix86_adjust_cost -- return true iff INSN reads flags set
1406590284Sobrien   by DEP_INSN and nothing set by DEP_INSN.  */
1406690284Sobrien
1406790284Sobrienstatic int
14068169705Skanix86_flags_dependent (rtx insn, rtx dep_insn, enum attr_type insn_type)
1406990284Sobrien{
1407090284Sobrien  rtx set, set2;
1407190284Sobrien
1407290284Sobrien  /* Simplify the test for uninteresting insns.  */
1407390284Sobrien  if (insn_type != TYPE_SETCC
1407490284Sobrien      && insn_type != TYPE_ICMOV
1407590284Sobrien      && insn_type != TYPE_FCMOV
1407690284Sobrien      && insn_type != TYPE_IBR)
1407790284Sobrien    return 0;
1407890284Sobrien
1407990284Sobrien  if ((set = single_set (dep_insn)) != 0)
1408051411Sobrien    {
1408190284Sobrien      set = SET_DEST (set);
1408290284Sobrien      set2 = NULL_RTX;
1408390284Sobrien    }
1408490284Sobrien  else if (GET_CODE (PATTERN (dep_insn)) == PARALLEL
1408590284Sobrien	   && XVECLEN (PATTERN (dep_insn), 0) == 2
1408690284Sobrien	   && GET_CODE (XVECEXP (PATTERN (dep_insn), 0, 0)) == SET
1408790284Sobrien	   && GET_CODE (XVECEXP (PATTERN (dep_insn), 0, 1)) == SET)
1408890284Sobrien    {
1408990284Sobrien      set = SET_DEST (XVECEXP (PATTERN (dep_insn), 0, 0));
1409090284Sobrien      set2 = SET_DEST (XVECEXP (PATTERN (dep_insn), 0, 0));
1409190284Sobrien    }
1409290284Sobrien  else
1409390284Sobrien    return 0;
1409451411Sobrien
1409590284Sobrien  if (GET_CODE (set) != REG || REGNO (set) != FLAGS_REG)
1409690284Sobrien    return 0;
1409751411Sobrien
1409890284Sobrien  /* This test is true if the dependent insn reads the flags but
1409990284Sobrien     not any other potentially set register.  */
1410090284Sobrien  if (!reg_overlap_mentioned_p (set, PATTERN (insn)))
1410190284Sobrien    return 0;
1410290284Sobrien
1410390284Sobrien  if (set2 && reg_overlap_mentioned_p (set2, PATTERN (insn)))
1410490284Sobrien    return 0;
1410590284Sobrien
1410690284Sobrien  return 1;
1410790284Sobrien}
1410890284Sobrien
1410990284Sobrien/* A subroutine of ix86_adjust_cost -- return true iff INSN has a memory
1411090284Sobrien   address with operands set by DEP_INSN.  */
1411190284Sobrien
1411290284Sobrienstatic int
14113169705Skanix86_agi_dependent (rtx insn, rtx dep_insn, enum attr_type insn_type)
1411490284Sobrien{
1411590284Sobrien  rtx addr;
1411690284Sobrien
1411790284Sobrien  if (insn_type == TYPE_LEA
1411890284Sobrien      && TARGET_PENTIUM)
1411990284Sobrien    {
1412090284Sobrien      addr = PATTERN (insn);
14121169705Skan
14122169705Skan      if (GET_CODE (addr) == PARALLEL)
1412390284Sobrien	addr = XVECEXP (addr, 0, 0);
14124169705Skan
14125169705Skan      gcc_assert (GET_CODE (addr) == SET);
14126169705Skan
1412790284Sobrien      addr = SET_SRC (addr);
1412851411Sobrien    }
1412990284Sobrien  else
1413090284Sobrien    {
1413190284Sobrien      int i;
1413290284Sobrien      extract_insn_cached (insn);
1413390284Sobrien      for (i = recog_data.n_operands - 1; i >= 0; --i)
1413490284Sobrien	if (GET_CODE (recog_data.operand[i]) == MEM)
1413590284Sobrien	  {
1413690284Sobrien	    addr = XEXP (recog_data.operand[i], 0);
1413790284Sobrien	    goto found;
1413890284Sobrien	  }
1413990284Sobrien      return 0;
1414090284Sobrien    found:;
1414190284Sobrien    }
1414251411Sobrien
1414390284Sobrien  return modified_in_p (addr, dep_insn);
1414451411Sobrien}
1414552294Sobrien
1414690284Sobrienstatic int
14147132743Skanix86_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
1414852294Sobrien{
1414990284Sobrien  enum attr_type insn_type, dep_insn_type;
14150169705Skan  enum attr_memory memory;
1415190284Sobrien  rtx set, set2;
1415290284Sobrien  int dep_insn_code_number;
1415352294Sobrien
14154132743Skan  /* Anti and output dependencies have zero cost on all CPUs.  */
1415590284Sobrien  if (REG_NOTE_KIND (link) != 0)
1415652294Sobrien    return 0;
1415752294Sobrien
1415890284Sobrien  dep_insn_code_number = recog_memoized (dep_insn);
1415952294Sobrien
1416090284Sobrien  /* If we can't recognize the insns, we can't really do anything.  */
1416190284Sobrien  if (dep_insn_code_number < 0 || recog_memoized (insn) < 0)
1416290284Sobrien    return cost;
1416352294Sobrien
1416490284Sobrien  insn_type = get_attr_type (insn);
1416590284Sobrien  dep_insn_type = get_attr_type (dep_insn);
1416690284Sobrien
14167132743Skan  switch (ix86_tune)
1416852294Sobrien    {
1416952294Sobrien    case PROCESSOR_PENTIUM:
1417090284Sobrien      /* Address Generation Interlock adds a cycle of latency.  */
14171169705Skan      if (ix86_agi_dependent (insn, dep_insn, insn_type))
1417290284Sobrien	cost += 1;
1417352294Sobrien
1417490284Sobrien      /* ??? Compares pair with jump/setcc.  */
14175169705Skan      if (ix86_flags_dependent (insn, dep_insn, insn_type))
1417690284Sobrien	cost = 0;
1417752294Sobrien
14178132743Skan      /* Floating point stores require value to be ready one cycle earlier.  */
1417990284Sobrien      if (insn_type == TYPE_FMOV
1418090284Sobrien	  && get_attr_memory (insn) == MEMORY_STORE
14181169705Skan	  && !ix86_agi_dependent (insn, dep_insn, insn_type))
1418290284Sobrien	cost += 1;
1418390284Sobrien      break;
1418452294Sobrien
1418590284Sobrien    case PROCESSOR_PENTIUMPRO:
1418690284Sobrien      memory = get_attr_memory (insn);
1418790284Sobrien
1418890284Sobrien      /* INT->FP conversion is expensive.  */
1418990284Sobrien      if (get_attr_fp_int_src (dep_insn))
1419090284Sobrien	cost += 5;
1419190284Sobrien
1419290284Sobrien      /* There is one cycle extra latency between an FP op and a store.  */
1419390284Sobrien      if (insn_type == TYPE_FMOV
1419490284Sobrien	  && (set = single_set (dep_insn)) != NULL_RTX
1419590284Sobrien	  && (set2 = single_set (insn)) != NULL_RTX
1419690284Sobrien	  && rtx_equal_p (SET_DEST (set), SET_SRC (set2))
1419790284Sobrien	  && GET_CODE (SET_DEST (set2)) == MEM)
1419890284Sobrien	cost += 1;
1419990284Sobrien
1420090284Sobrien      /* Show ability of reorder buffer to hide latency of load by executing
1420190284Sobrien	 in parallel with previous instruction in case
1420290284Sobrien	 previous instruction is not needed to compute the address.  */
1420390284Sobrien      if ((memory == MEMORY_LOAD || memory == MEMORY_BOTH)
14204169705Skan	  && !ix86_agi_dependent (insn, dep_insn, insn_type))
14205132743Skan	{
1420690284Sobrien	  /* Claim moves to take one cycle, as core can issue one load
1420790284Sobrien	     at time and the next load can start cycle later.  */
1420890284Sobrien	  if (dep_insn_type == TYPE_IMOV
1420990284Sobrien	      || dep_insn_type == TYPE_FMOV)
1421090284Sobrien	    cost = 1;
1421190284Sobrien	  else if (cost > 1)
1421290284Sobrien	    cost--;
1421390284Sobrien	}
1421452294Sobrien      break;
1421590284Sobrien
1421652294Sobrien    case PROCESSOR_K6:
1421790284Sobrien      memory = get_attr_memory (insn);
14218169705Skan
1421990284Sobrien      /* The esp dependency is resolved before the instruction is really
1422090284Sobrien         finished.  */
1422190284Sobrien      if ((insn_type == TYPE_PUSH || insn_type == TYPE_POP)
1422290284Sobrien	  && (dep_insn_type == TYPE_PUSH || dep_insn_type == TYPE_POP))
1422390284Sobrien	return 1;
1422490284Sobrien
1422590284Sobrien      /* INT->FP conversion is expensive.  */
1422690284Sobrien      if (get_attr_fp_int_src (dep_insn))
1422790284Sobrien	cost += 5;
1422890284Sobrien
1422990284Sobrien      /* Show ability of reorder buffer to hide latency of load by executing
1423090284Sobrien	 in parallel with previous instruction in case
1423190284Sobrien	 previous instruction is not needed to compute the address.  */
1423290284Sobrien      if ((memory == MEMORY_LOAD || memory == MEMORY_BOTH)
14233169705Skan	  && !ix86_agi_dependent (insn, dep_insn, insn_type))
14234132743Skan	{
1423590284Sobrien	  /* Claim moves to take one cycle, as core can issue one load
1423690284Sobrien	     at time and the next load can start cycle later.  */
1423790284Sobrien	  if (dep_insn_type == TYPE_IMOV
1423890284Sobrien	      || dep_insn_type == TYPE_FMOV)
1423990284Sobrien	    cost = 1;
1424090284Sobrien	  else if (cost > 2)
1424190284Sobrien	    cost -= 2;
1424290284Sobrien	  else
1424390284Sobrien	    cost = 1;
1424490284Sobrien	}
1424590284Sobrien      break;
1424690284Sobrien
1424790284Sobrien    case PROCESSOR_ATHLON:
14248132743Skan    case PROCESSOR_K8:
14249251212Spfg    case PROCESSOR_AMDFAM10:
14250169705Skan    case PROCESSOR_GENERIC32:
14251169705Skan    case PROCESSOR_GENERIC64:
1425290284Sobrien      memory = get_attr_memory (insn);
1425390284Sobrien
1425490284Sobrien      /* Show ability of reorder buffer to hide latency of load by executing
1425590284Sobrien	 in parallel with previous instruction in case
1425690284Sobrien	 previous instruction is not needed to compute the address.  */
1425790284Sobrien      if ((memory == MEMORY_LOAD || memory == MEMORY_BOTH)
14258169705Skan	  && !ix86_agi_dependent (insn, dep_insn, insn_type))
14259132743Skan	{
14260132743Skan	  enum attr_unit unit = get_attr_unit (insn);
14261132743Skan	  int loadcost = 3;
14262132743Skan
14263132743Skan	  /* Because of the difference between the length of integer and
14264132743Skan	     floating unit pipeline preparation stages, the memory operands
14265132743Skan	     for floating point are cheaper.
14266132743Skan
14267132743Skan	     ??? For Athlon it the difference is most probably 2.  */
14268132743Skan	  if (unit == UNIT_INTEGER || unit == UNIT_UNKNOWN)
14269132743Skan	    loadcost = 3;
1427090284Sobrien	  else
14271132743Skan	    loadcost = TARGET_ATHLON ? 2 : 0;
14272132743Skan
14273132743Skan	  if (cost >= loadcost)
14274132743Skan	    cost -= loadcost;
14275132743Skan	  else
1427690284Sobrien	    cost = 0;
1427752294Sobrien	}
1427890284Sobrien
1427990284Sobrien    default:
1428052294Sobrien      break;
1428152294Sobrien    }
1428252294Sobrien
1428352294Sobrien  return cost;
1428452294Sobrien}
1428552294Sobrien
14286117408Skan/* How many alternative schedules to try.  This should be as wide as the
14287117408Skan   scheduling freedom in the DFA, but no wider.  Making this value too
14288117408Skan   large results extra work for the scheduler.  */
14289117408Skan
14290117408Skanstatic int
14291132743Skania32_multipass_dfa_lookahead (void)
14292117408Skan{
14293132743Skan  if (ix86_tune == PROCESSOR_PENTIUM)
14294117408Skan    return 2;
14295169705Skan
14296169705Skan  if (ix86_tune == PROCESSOR_PENTIUMPRO
14297169705Skan      || ix86_tune == PROCESSOR_K6)
14298169705Skan    return 1;
14299169705Skan
14300117408Skan  else
14301169705Skan    return 0;
14302117408Skan}
14303117408Skan
1430490284Sobrien
1430590284Sobrien/* Compute the alignment given to a constant that is being placed in memory.
1430690284Sobrien   EXP is the constant and ALIGN is the alignment that the object would
1430790284Sobrien   ordinarily have.
1430890284Sobrien   The value of this function is used instead of that alignment to align
1430990284Sobrien   the object.  */
1431052294Sobrien
1431190284Sobrienint
14312132743Skanix86_constant_alignment (tree exp, int align)
1431390284Sobrien{
1431490284Sobrien  if (TREE_CODE (exp) == REAL_CST)
1431552294Sobrien    {
1431690284Sobrien      if (TYPE_MODE (TREE_TYPE (exp)) == DFmode && align < 64)
1431790284Sobrien	return 64;
1431890284Sobrien      else if (ALIGN_MODE_128 (TYPE_MODE (TREE_TYPE (exp))) && align < 128)
1431990284Sobrien	return 128;
1432090284Sobrien    }
14321132743Skan  else if (!optimize_size && TREE_CODE (exp) == STRING_CST
14322169705Skan      	   && !TARGET_NO_ALIGN_LONG_STRINGS
14323132743Skan	   && TREE_STRING_LENGTH (exp) >= 31 && align < BITS_PER_WORD)
14324132743Skan    return BITS_PER_WORD;
1432590284Sobrien
1432690284Sobrien  return align;
1432790284Sobrien}
1432890284Sobrien
1432990284Sobrien/* Compute the alignment for a static variable.
1433090284Sobrien   TYPE is the data type, and ALIGN is the alignment that
1433190284Sobrien   the object would ordinarily have.  The value of this function is used
1433290284Sobrien   instead of that alignment to align the object.  */
1433390284Sobrien
1433490284Sobrienint
14335132743Skanix86_data_alignment (tree type, int align)
1433690284Sobrien{
14337169705Skan  int max_align = optimize_size ? BITS_PER_WORD : 256;
14338169705Skan
1433990284Sobrien  if (AGGREGATE_TYPE_P (type)
14340169705Skan      && TYPE_SIZE (type)
14341169705Skan      && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
14342169705Skan      && (TREE_INT_CST_LOW (TYPE_SIZE (type)) >= (unsigned) max_align
14343169705Skan	  || TREE_INT_CST_HIGH (TYPE_SIZE (type)))
14344169705Skan      && align < max_align)
14345169705Skan    align = max_align;
1434690284Sobrien
1434790284Sobrien  /* x86-64 ABI requires arrays greater than 16 bytes to be aligned
1434890284Sobrien     to 16byte boundary.  */
1434990284Sobrien  if (TARGET_64BIT)
1435090284Sobrien    {
1435190284Sobrien      if (AGGREGATE_TYPE_P (type)
1435290284Sobrien	   && TYPE_SIZE (type)
1435390284Sobrien	   && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
1435490284Sobrien	   && (TREE_INT_CST_LOW (TYPE_SIZE (type)) >= 128
1435590284Sobrien	       || TREE_INT_CST_HIGH (TYPE_SIZE (type))) && align < 128)
1435690284Sobrien	return 128;
1435790284Sobrien    }
1435890284Sobrien
1435990284Sobrien  if (TREE_CODE (type) == ARRAY_TYPE)
1436090284Sobrien    {
1436190284Sobrien      if (TYPE_MODE (TREE_TYPE (type)) == DFmode && align < 64)
1436290284Sobrien	return 64;
1436390284Sobrien      if (ALIGN_MODE_128 (TYPE_MODE (TREE_TYPE (type))) && align < 128)
1436490284Sobrien	return 128;
1436590284Sobrien    }
1436690284Sobrien  else if (TREE_CODE (type) == COMPLEX_TYPE)
1436790284Sobrien    {
1436890284Sobrien
1436990284Sobrien      if (TYPE_MODE (type) == DCmode && align < 64)
1437090284Sobrien	return 64;
1437190284Sobrien      if (TYPE_MODE (type) == XCmode && align < 128)
1437290284Sobrien	return 128;
1437390284Sobrien    }
1437490284Sobrien  else if ((TREE_CODE (type) == RECORD_TYPE
1437590284Sobrien	    || TREE_CODE (type) == UNION_TYPE
1437690284Sobrien	    || TREE_CODE (type) == QUAL_UNION_TYPE)
1437790284Sobrien	   && TYPE_FIELDS (type))
1437890284Sobrien    {
1437990284Sobrien      if (DECL_MODE (TYPE_FIELDS (type)) == DFmode && align < 64)
1438090284Sobrien	return 64;
1438190284Sobrien      if (ALIGN_MODE_128 (DECL_MODE (TYPE_FIELDS (type))) && align < 128)
1438290284Sobrien	return 128;
1438390284Sobrien    }
1438490284Sobrien  else if (TREE_CODE (type) == REAL_TYPE || TREE_CODE (type) == VECTOR_TYPE
1438590284Sobrien	   || TREE_CODE (type) == INTEGER_TYPE)
1438690284Sobrien    {
1438790284Sobrien      if (TYPE_MODE (type) == DFmode && align < 64)
1438890284Sobrien	return 64;
1438990284Sobrien      if (ALIGN_MODE_128 (TYPE_MODE (type)) && align < 128)
1439090284Sobrien	return 128;
1439190284Sobrien    }
1439290284Sobrien
1439390284Sobrien  return align;
1439490284Sobrien}
1439590284Sobrien
1439690284Sobrien/* Compute the alignment for a local variable.
1439790284Sobrien   TYPE is the data type, and ALIGN is the alignment that
1439890284Sobrien   the object would ordinarily have.  The value of this macro is used
1439990284Sobrien   instead of that alignment to align the object.  */
1440090284Sobrien
1440190284Sobrienint
14402132743Skanix86_local_alignment (tree type, int align)
1440390284Sobrien{
1440490284Sobrien  /* x86-64 ABI requires arrays greater than 16 bytes to be aligned
1440590284Sobrien     to 16byte boundary.  */
1440690284Sobrien  if (TARGET_64BIT)
1440790284Sobrien    {
1440890284Sobrien      if (AGGREGATE_TYPE_P (type)
1440990284Sobrien	   && TYPE_SIZE (type)
1441090284Sobrien	   && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
14411265231Spfg	   && (TREE_INT_CST_LOW (TYPE_SIZE (type)) >= 128
1441290284Sobrien	       || TREE_INT_CST_HIGH (TYPE_SIZE (type))) && align < 128)
1441390284Sobrien	return 128;
1441490284Sobrien    }
1441590284Sobrien  if (TREE_CODE (type) == ARRAY_TYPE)
1441690284Sobrien    {
1441790284Sobrien      if (TYPE_MODE (TREE_TYPE (type)) == DFmode && align < 64)
1441890284Sobrien	return 64;
1441990284Sobrien      if (ALIGN_MODE_128 (TYPE_MODE (TREE_TYPE (type))) && align < 128)
1442090284Sobrien	return 128;
1442190284Sobrien    }
1442290284Sobrien  else if (TREE_CODE (type) == COMPLEX_TYPE)
1442390284Sobrien    {
1442490284Sobrien      if (TYPE_MODE (type) == DCmode && align < 64)
1442590284Sobrien	return 64;
1442690284Sobrien      if (TYPE_MODE (type) == XCmode && align < 128)
1442790284Sobrien	return 128;
1442890284Sobrien    }
1442990284Sobrien  else if ((TREE_CODE (type) == RECORD_TYPE
1443090284Sobrien	    || TREE_CODE (type) == UNION_TYPE
1443190284Sobrien	    || TREE_CODE (type) == QUAL_UNION_TYPE)
1443290284Sobrien	   && TYPE_FIELDS (type))
1443390284Sobrien    {
1443490284Sobrien      if (DECL_MODE (TYPE_FIELDS (type)) == DFmode && align < 64)
1443590284Sobrien	return 64;
1443690284Sobrien      if (ALIGN_MODE_128 (DECL_MODE (TYPE_FIELDS (type))) && align < 128)
1443790284Sobrien	return 128;
1443890284Sobrien    }
1443990284Sobrien  else if (TREE_CODE (type) == REAL_TYPE || TREE_CODE (type) == VECTOR_TYPE
1444090284Sobrien	   || TREE_CODE (type) == INTEGER_TYPE)
1444190284Sobrien    {
1444290284Sobrien
1444390284Sobrien      if (TYPE_MODE (type) == DFmode && align < 64)
1444490284Sobrien	return 64;
1444590284Sobrien      if (ALIGN_MODE_128 (TYPE_MODE (type)) && align < 128)
1444690284Sobrien	return 128;
1444790284Sobrien    }
1444890284Sobrien  return align;
1444990284Sobrien}
1445090284Sobrien
1445190284Sobrien/* Emit RTL insns to initialize the variable parts of a trampoline.
1445290284Sobrien   FNADDR is an RTX for the address of the function's pure code.
1445390284Sobrien   CXT is an RTX for the static chain value for the function.  */
1445490284Sobrienvoid
14455132743Skanx86_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
1445690284Sobrien{
1445790284Sobrien  if (!TARGET_64BIT)
1445890284Sobrien    {
1445990284Sobrien      /* Compute offset from the end of the jmp to the target function.  */
1446090284Sobrien      rtx disp = expand_binop (SImode, sub_optab, fnaddr,
1446190284Sobrien			       plus_constant (tramp, 10),
1446290284Sobrien			       NULL_RTX, 1, OPTAB_DIRECT);
1446390284Sobrien      emit_move_insn (gen_rtx_MEM (QImode, tramp),
14464117408Skan		      gen_int_mode (0xb9, QImode));
1446590284Sobrien      emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 1)), cxt);
1446690284Sobrien      emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 5)),
14467117408Skan		      gen_int_mode (0xe9, QImode));
1446890284Sobrien      emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 6)), disp);
1446990284Sobrien    }
1447090284Sobrien  else
1447190284Sobrien    {
1447290284Sobrien      int offset = 0;
1447390284Sobrien      /* Try to load address using shorter movl instead of movabs.
1447490284Sobrien         We may want to support movq for kernel mode, but kernel does not use
1447590284Sobrien         trampolines at the moment.  */
14476169705Skan      if (x86_64_zext_immediate_operand (fnaddr, VOIDmode))
1447752294Sobrien	{
1447890284Sobrien	  fnaddr = copy_to_mode_reg (DImode, fnaddr);
1447990284Sobrien	  emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, offset)),
14480117408Skan			  gen_int_mode (0xbb41, HImode));
1448190284Sobrien	  emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, offset + 2)),
1448290284Sobrien			  gen_lowpart (SImode, fnaddr));
1448390284Sobrien	  offset += 6;
1448452294Sobrien	}
1448552294Sobrien      else
1448690284Sobrien	{
1448790284Sobrien	  emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, offset)),
14488117408Skan			  gen_int_mode (0xbb49, HImode));
1448990284Sobrien	  emit_move_insn (gen_rtx_MEM (DImode, plus_constant (tramp, offset + 2)),
1449090284Sobrien			  fnaddr);
1449190284Sobrien	  offset += 10;
1449290284Sobrien	}
1449390284Sobrien      /* Load static chain using movabs to r10.  */
1449490284Sobrien      emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, offset)),
14495117408Skan		      gen_int_mode (0xba49, HImode));
1449690284Sobrien      emit_move_insn (gen_rtx_MEM (DImode, plus_constant (tramp, offset + 2)),
1449790284Sobrien		      cxt);
1449890284Sobrien      offset += 10;
1449990284Sobrien      /* Jump to the r11 */
1450090284Sobrien      emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, offset)),
14501117408Skan		      gen_int_mode (0xff49, HImode));
1450290284Sobrien      emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, offset+2)),
14503117408Skan		      gen_int_mode (0xe3, QImode));
1450490284Sobrien      offset += 3;
14505169705Skan      gcc_assert (offset <= TRAMPOLINE_SIZE);
1450652294Sobrien    }
14507117408Skan
14508132743Skan#ifdef ENABLE_EXECUTE_STACK
14509169705Skan  emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__enable_execute_stack"),
14510117408Skan		     LCT_NORMAL, VOIDmode, 1, tramp, Pmode);
14511117408Skan#endif
1451252294Sobrien}
1451390284Sobrien
14514169705Skan/* Codes for all the SSE/MMX builtins.  */
14515169705Skanenum ix86_builtins
14516169705Skan{
14517169705Skan  IX86_BUILTIN_ADDPS,
14518169705Skan  IX86_BUILTIN_ADDSS,
14519169705Skan  IX86_BUILTIN_DIVPS,
14520169705Skan  IX86_BUILTIN_DIVSS,
14521169705Skan  IX86_BUILTIN_MULPS,
14522169705Skan  IX86_BUILTIN_MULSS,
14523169705Skan  IX86_BUILTIN_SUBPS,
14524169705Skan  IX86_BUILTIN_SUBSS,
14525169705Skan
14526169705Skan  IX86_BUILTIN_CMPEQPS,
14527169705Skan  IX86_BUILTIN_CMPLTPS,
14528169705Skan  IX86_BUILTIN_CMPLEPS,
14529169705Skan  IX86_BUILTIN_CMPGTPS,
14530169705Skan  IX86_BUILTIN_CMPGEPS,
14531169705Skan  IX86_BUILTIN_CMPNEQPS,
14532169705Skan  IX86_BUILTIN_CMPNLTPS,
14533169705Skan  IX86_BUILTIN_CMPNLEPS,
14534169705Skan  IX86_BUILTIN_CMPNGTPS,
14535169705Skan  IX86_BUILTIN_CMPNGEPS,
14536169705Skan  IX86_BUILTIN_CMPORDPS,
14537169705Skan  IX86_BUILTIN_CMPUNORDPS,
14538169705Skan  IX86_BUILTIN_CMPEQSS,
14539169705Skan  IX86_BUILTIN_CMPLTSS,
14540169705Skan  IX86_BUILTIN_CMPLESS,
14541169705Skan  IX86_BUILTIN_CMPNEQSS,
14542169705Skan  IX86_BUILTIN_CMPNLTSS,
14543169705Skan  IX86_BUILTIN_CMPNLESS,
14544169705Skan  IX86_BUILTIN_CMPNGTSS,
14545169705Skan  IX86_BUILTIN_CMPNGESS,
14546169705Skan  IX86_BUILTIN_CMPORDSS,
14547169705Skan  IX86_BUILTIN_CMPUNORDSS,
14548169705Skan
14549169705Skan  IX86_BUILTIN_COMIEQSS,
14550169705Skan  IX86_BUILTIN_COMILTSS,
14551169705Skan  IX86_BUILTIN_COMILESS,
14552169705Skan  IX86_BUILTIN_COMIGTSS,
14553169705Skan  IX86_BUILTIN_COMIGESS,
14554169705Skan  IX86_BUILTIN_COMINEQSS,
14555169705Skan  IX86_BUILTIN_UCOMIEQSS,
14556169705Skan  IX86_BUILTIN_UCOMILTSS,
14557169705Skan  IX86_BUILTIN_UCOMILESS,
14558169705Skan  IX86_BUILTIN_UCOMIGTSS,
14559169705Skan  IX86_BUILTIN_UCOMIGESS,
14560169705Skan  IX86_BUILTIN_UCOMINEQSS,
14561169705Skan
14562169705Skan  IX86_BUILTIN_CVTPI2PS,
14563169705Skan  IX86_BUILTIN_CVTPS2PI,
14564169705Skan  IX86_BUILTIN_CVTSI2SS,
14565169705Skan  IX86_BUILTIN_CVTSI642SS,
14566169705Skan  IX86_BUILTIN_CVTSS2SI,
14567169705Skan  IX86_BUILTIN_CVTSS2SI64,
14568169705Skan  IX86_BUILTIN_CVTTPS2PI,
14569169705Skan  IX86_BUILTIN_CVTTSS2SI,
14570169705Skan  IX86_BUILTIN_CVTTSS2SI64,
14571169705Skan
14572169705Skan  IX86_BUILTIN_MAXPS,
14573169705Skan  IX86_BUILTIN_MAXSS,
14574169705Skan  IX86_BUILTIN_MINPS,
14575169705Skan  IX86_BUILTIN_MINSS,
14576169705Skan
14577169705Skan  IX86_BUILTIN_LOADUPS,
14578169705Skan  IX86_BUILTIN_STOREUPS,
14579169705Skan  IX86_BUILTIN_MOVSS,
14580169705Skan
14581169705Skan  IX86_BUILTIN_MOVHLPS,
14582169705Skan  IX86_BUILTIN_MOVLHPS,
14583169705Skan  IX86_BUILTIN_LOADHPS,
14584169705Skan  IX86_BUILTIN_LOADLPS,
14585169705Skan  IX86_BUILTIN_STOREHPS,
14586169705Skan  IX86_BUILTIN_STORELPS,
14587169705Skan
14588169705Skan  IX86_BUILTIN_MASKMOVQ,
14589169705Skan  IX86_BUILTIN_MOVMSKPS,
14590169705Skan  IX86_BUILTIN_PMOVMSKB,
14591169705Skan
14592169705Skan  IX86_BUILTIN_MOVNTPS,
14593169705Skan  IX86_BUILTIN_MOVNTQ,
14594169705Skan
14595169705Skan  IX86_BUILTIN_LOADDQU,
14596169705Skan  IX86_BUILTIN_STOREDQU,
14597169705Skan
14598169705Skan  IX86_BUILTIN_PACKSSWB,
14599169705Skan  IX86_BUILTIN_PACKSSDW,
14600169705Skan  IX86_BUILTIN_PACKUSWB,
14601169705Skan
14602169705Skan  IX86_BUILTIN_PADDB,
14603169705Skan  IX86_BUILTIN_PADDW,
14604169705Skan  IX86_BUILTIN_PADDD,
14605169705Skan  IX86_BUILTIN_PADDQ,
14606169705Skan  IX86_BUILTIN_PADDSB,
14607169705Skan  IX86_BUILTIN_PADDSW,
14608169705Skan  IX86_BUILTIN_PADDUSB,
14609169705Skan  IX86_BUILTIN_PADDUSW,
14610169705Skan  IX86_BUILTIN_PSUBB,
14611169705Skan  IX86_BUILTIN_PSUBW,
14612169705Skan  IX86_BUILTIN_PSUBD,
14613169705Skan  IX86_BUILTIN_PSUBQ,
14614169705Skan  IX86_BUILTIN_PSUBSB,
14615169705Skan  IX86_BUILTIN_PSUBSW,
14616169705Skan  IX86_BUILTIN_PSUBUSB,
14617169705Skan  IX86_BUILTIN_PSUBUSW,
14618169705Skan
14619169705Skan  IX86_BUILTIN_PAND,
14620169705Skan  IX86_BUILTIN_PANDN,
14621169705Skan  IX86_BUILTIN_POR,
14622169705Skan  IX86_BUILTIN_PXOR,
14623169705Skan
14624169705Skan  IX86_BUILTIN_PAVGB,
14625169705Skan  IX86_BUILTIN_PAVGW,
14626169705Skan
14627169705Skan  IX86_BUILTIN_PCMPEQB,
14628169705Skan  IX86_BUILTIN_PCMPEQW,
14629169705Skan  IX86_BUILTIN_PCMPEQD,
14630169705Skan  IX86_BUILTIN_PCMPGTB,
14631169705Skan  IX86_BUILTIN_PCMPGTW,
14632169705Skan  IX86_BUILTIN_PCMPGTD,
14633169705Skan
14634169705Skan  IX86_BUILTIN_PMADDWD,
14635169705Skan
14636169705Skan  IX86_BUILTIN_PMAXSW,
14637169705Skan  IX86_BUILTIN_PMAXUB,
14638169705Skan  IX86_BUILTIN_PMINSW,
14639169705Skan  IX86_BUILTIN_PMINUB,
14640169705Skan
14641169705Skan  IX86_BUILTIN_PMULHUW,
14642169705Skan  IX86_BUILTIN_PMULHW,
14643169705Skan  IX86_BUILTIN_PMULLW,
14644169705Skan
14645169705Skan  IX86_BUILTIN_PSADBW,
14646169705Skan  IX86_BUILTIN_PSHUFW,
14647169705Skan
14648169705Skan  IX86_BUILTIN_PSLLW,
14649169705Skan  IX86_BUILTIN_PSLLD,
14650169705Skan  IX86_BUILTIN_PSLLQ,
14651169705Skan  IX86_BUILTIN_PSRAW,
14652169705Skan  IX86_BUILTIN_PSRAD,
14653169705Skan  IX86_BUILTIN_PSRLW,
14654169705Skan  IX86_BUILTIN_PSRLD,
14655169705Skan  IX86_BUILTIN_PSRLQ,
14656169705Skan  IX86_BUILTIN_PSLLWI,
14657169705Skan  IX86_BUILTIN_PSLLDI,
14658169705Skan  IX86_BUILTIN_PSLLQI,
14659169705Skan  IX86_BUILTIN_PSRAWI,
14660169705Skan  IX86_BUILTIN_PSRADI,
14661169705Skan  IX86_BUILTIN_PSRLWI,
14662169705Skan  IX86_BUILTIN_PSRLDI,
14663169705Skan  IX86_BUILTIN_PSRLQI,
14664169705Skan
14665169705Skan  IX86_BUILTIN_PUNPCKHBW,
14666169705Skan  IX86_BUILTIN_PUNPCKHWD,
14667169705Skan  IX86_BUILTIN_PUNPCKHDQ,
14668169705Skan  IX86_BUILTIN_PUNPCKLBW,
14669169705Skan  IX86_BUILTIN_PUNPCKLWD,
14670169705Skan  IX86_BUILTIN_PUNPCKLDQ,
14671169705Skan
14672169705Skan  IX86_BUILTIN_SHUFPS,
14673169705Skan
14674169705Skan  IX86_BUILTIN_RCPPS,
14675169705Skan  IX86_BUILTIN_RCPSS,
14676169705Skan  IX86_BUILTIN_RSQRTPS,
14677169705Skan  IX86_BUILTIN_RSQRTSS,
14678169705Skan  IX86_BUILTIN_SQRTPS,
14679169705Skan  IX86_BUILTIN_SQRTSS,
14680169705Skan
14681169705Skan  IX86_BUILTIN_UNPCKHPS,
14682169705Skan  IX86_BUILTIN_UNPCKLPS,
14683169705Skan
14684169705Skan  IX86_BUILTIN_ANDPS,
14685169705Skan  IX86_BUILTIN_ANDNPS,
14686169705Skan  IX86_BUILTIN_ORPS,
14687169705Skan  IX86_BUILTIN_XORPS,
14688169705Skan
14689169705Skan  IX86_BUILTIN_EMMS,
14690169705Skan  IX86_BUILTIN_LDMXCSR,
14691169705Skan  IX86_BUILTIN_STMXCSR,
14692169705Skan  IX86_BUILTIN_SFENCE,
14693169705Skan
14694169705Skan  /* 3DNow! Original */
14695169705Skan  IX86_BUILTIN_FEMMS,
14696169705Skan  IX86_BUILTIN_PAVGUSB,
14697169705Skan  IX86_BUILTIN_PF2ID,
14698169705Skan  IX86_BUILTIN_PFACC,
14699169705Skan  IX86_BUILTIN_PFADD,
14700169705Skan  IX86_BUILTIN_PFCMPEQ,
14701169705Skan  IX86_BUILTIN_PFCMPGE,
14702169705Skan  IX86_BUILTIN_PFCMPGT,
14703169705Skan  IX86_BUILTIN_PFMAX,
14704169705Skan  IX86_BUILTIN_PFMIN,
14705169705Skan  IX86_BUILTIN_PFMUL,
14706169705Skan  IX86_BUILTIN_PFRCP,
14707169705Skan  IX86_BUILTIN_PFRCPIT1,
14708169705Skan  IX86_BUILTIN_PFRCPIT2,
14709169705Skan  IX86_BUILTIN_PFRSQIT1,
14710169705Skan  IX86_BUILTIN_PFRSQRT,
14711169705Skan  IX86_BUILTIN_PFSUB,
14712169705Skan  IX86_BUILTIN_PFSUBR,
14713169705Skan  IX86_BUILTIN_PI2FD,
14714169705Skan  IX86_BUILTIN_PMULHRW,
14715169705Skan
14716169705Skan  /* 3DNow! Athlon Extensions */
14717169705Skan  IX86_BUILTIN_PF2IW,
14718169705Skan  IX86_BUILTIN_PFNACC,
14719169705Skan  IX86_BUILTIN_PFPNACC,
14720169705Skan  IX86_BUILTIN_PI2FW,
14721169705Skan  IX86_BUILTIN_PSWAPDSI,
14722169705Skan  IX86_BUILTIN_PSWAPDSF,
14723169705Skan
14724169705Skan  /* SSE2 */
14725169705Skan  IX86_BUILTIN_ADDPD,
14726169705Skan  IX86_BUILTIN_ADDSD,
14727169705Skan  IX86_BUILTIN_DIVPD,
14728169705Skan  IX86_BUILTIN_DIVSD,
14729169705Skan  IX86_BUILTIN_MULPD,
14730169705Skan  IX86_BUILTIN_MULSD,
14731169705Skan  IX86_BUILTIN_SUBPD,
14732169705Skan  IX86_BUILTIN_SUBSD,
14733169705Skan
14734169705Skan  IX86_BUILTIN_CMPEQPD,
14735169705Skan  IX86_BUILTIN_CMPLTPD,
14736169705Skan  IX86_BUILTIN_CMPLEPD,
14737169705Skan  IX86_BUILTIN_CMPGTPD,
14738169705Skan  IX86_BUILTIN_CMPGEPD,
14739169705Skan  IX86_BUILTIN_CMPNEQPD,
14740169705Skan  IX86_BUILTIN_CMPNLTPD,
14741169705Skan  IX86_BUILTIN_CMPNLEPD,
14742169705Skan  IX86_BUILTIN_CMPNGTPD,
14743169705Skan  IX86_BUILTIN_CMPNGEPD,
14744169705Skan  IX86_BUILTIN_CMPORDPD,
14745169705Skan  IX86_BUILTIN_CMPUNORDPD,
14746169705Skan  IX86_BUILTIN_CMPNEPD,
14747169705Skan  IX86_BUILTIN_CMPEQSD,
14748169705Skan  IX86_BUILTIN_CMPLTSD,
14749169705Skan  IX86_BUILTIN_CMPLESD,
14750169705Skan  IX86_BUILTIN_CMPNEQSD,
14751169705Skan  IX86_BUILTIN_CMPNLTSD,
14752169705Skan  IX86_BUILTIN_CMPNLESD,
14753169705Skan  IX86_BUILTIN_CMPORDSD,
14754169705Skan  IX86_BUILTIN_CMPUNORDSD,
14755169705Skan  IX86_BUILTIN_CMPNESD,
14756169705Skan
14757169705Skan  IX86_BUILTIN_COMIEQSD,
14758169705Skan  IX86_BUILTIN_COMILTSD,
14759169705Skan  IX86_BUILTIN_COMILESD,
14760169705Skan  IX86_BUILTIN_COMIGTSD,
14761169705Skan  IX86_BUILTIN_COMIGESD,
14762169705Skan  IX86_BUILTIN_COMINEQSD,
14763169705Skan  IX86_BUILTIN_UCOMIEQSD,
14764169705Skan  IX86_BUILTIN_UCOMILTSD,
14765169705Skan  IX86_BUILTIN_UCOMILESD,
14766169705Skan  IX86_BUILTIN_UCOMIGTSD,
14767169705Skan  IX86_BUILTIN_UCOMIGESD,
14768169705Skan  IX86_BUILTIN_UCOMINEQSD,
14769169705Skan
14770169705Skan  IX86_BUILTIN_MAXPD,
14771169705Skan  IX86_BUILTIN_MAXSD,
14772169705Skan  IX86_BUILTIN_MINPD,
14773169705Skan  IX86_BUILTIN_MINSD,
14774169705Skan
14775169705Skan  IX86_BUILTIN_ANDPD,
14776169705Skan  IX86_BUILTIN_ANDNPD,
14777169705Skan  IX86_BUILTIN_ORPD,
14778169705Skan  IX86_BUILTIN_XORPD,
14779169705Skan
14780169705Skan  IX86_BUILTIN_SQRTPD,
14781169705Skan  IX86_BUILTIN_SQRTSD,
14782169705Skan
14783169705Skan  IX86_BUILTIN_UNPCKHPD,
14784169705Skan  IX86_BUILTIN_UNPCKLPD,
14785169705Skan
14786169705Skan  IX86_BUILTIN_SHUFPD,
14787169705Skan
14788169705Skan  IX86_BUILTIN_LOADUPD,
14789169705Skan  IX86_BUILTIN_STOREUPD,
14790169705Skan  IX86_BUILTIN_MOVSD,
14791169705Skan
14792169705Skan  IX86_BUILTIN_LOADHPD,
14793169705Skan  IX86_BUILTIN_LOADLPD,
14794169705Skan
14795169705Skan  IX86_BUILTIN_CVTDQ2PD,
14796169705Skan  IX86_BUILTIN_CVTDQ2PS,
14797169705Skan
14798169705Skan  IX86_BUILTIN_CVTPD2DQ,
14799169705Skan  IX86_BUILTIN_CVTPD2PI,
14800169705Skan  IX86_BUILTIN_CVTPD2PS,
14801169705Skan  IX86_BUILTIN_CVTTPD2DQ,
14802169705Skan  IX86_BUILTIN_CVTTPD2PI,
14803169705Skan
14804169705Skan  IX86_BUILTIN_CVTPI2PD,
14805169705Skan  IX86_BUILTIN_CVTSI2SD,
14806169705Skan  IX86_BUILTIN_CVTSI642SD,
14807169705Skan
14808169705Skan  IX86_BUILTIN_CVTSD2SI,
14809169705Skan  IX86_BUILTIN_CVTSD2SI64,
14810169705Skan  IX86_BUILTIN_CVTSD2SS,
14811169705Skan  IX86_BUILTIN_CVTSS2SD,
14812169705Skan  IX86_BUILTIN_CVTTSD2SI,
14813169705Skan  IX86_BUILTIN_CVTTSD2SI64,
14814169705Skan
14815169705Skan  IX86_BUILTIN_CVTPS2DQ,
14816169705Skan  IX86_BUILTIN_CVTPS2PD,
14817169705Skan  IX86_BUILTIN_CVTTPS2DQ,
14818169705Skan
14819169705Skan  IX86_BUILTIN_MOVNTI,
14820169705Skan  IX86_BUILTIN_MOVNTPD,
14821169705Skan  IX86_BUILTIN_MOVNTDQ,
14822169705Skan
14823169705Skan  /* SSE2 MMX */
14824169705Skan  IX86_BUILTIN_MASKMOVDQU,
14825169705Skan  IX86_BUILTIN_MOVMSKPD,
14826169705Skan  IX86_BUILTIN_PMOVMSKB128,
14827169705Skan
14828169705Skan  IX86_BUILTIN_PACKSSWB128,
14829169705Skan  IX86_BUILTIN_PACKSSDW128,
14830169705Skan  IX86_BUILTIN_PACKUSWB128,
14831169705Skan
14832169705Skan  IX86_BUILTIN_PADDB128,
14833169705Skan  IX86_BUILTIN_PADDW128,
14834169705Skan  IX86_BUILTIN_PADDD128,
14835169705Skan  IX86_BUILTIN_PADDQ128,
14836169705Skan  IX86_BUILTIN_PADDSB128,
14837169705Skan  IX86_BUILTIN_PADDSW128,
14838169705Skan  IX86_BUILTIN_PADDUSB128,
14839169705Skan  IX86_BUILTIN_PADDUSW128,
14840169705Skan  IX86_BUILTIN_PSUBB128,
14841169705Skan  IX86_BUILTIN_PSUBW128,
14842169705Skan  IX86_BUILTIN_PSUBD128,
14843169705Skan  IX86_BUILTIN_PSUBQ128,
14844169705Skan  IX86_BUILTIN_PSUBSB128,
14845169705Skan  IX86_BUILTIN_PSUBSW128,
14846169705Skan  IX86_BUILTIN_PSUBUSB128,
14847169705Skan  IX86_BUILTIN_PSUBUSW128,
14848169705Skan
14849169705Skan  IX86_BUILTIN_PAND128,
14850169705Skan  IX86_BUILTIN_PANDN128,
14851169705Skan  IX86_BUILTIN_POR128,
14852169705Skan  IX86_BUILTIN_PXOR128,
14853169705Skan
14854169705Skan  IX86_BUILTIN_PAVGB128,
14855169705Skan  IX86_BUILTIN_PAVGW128,
14856169705Skan
14857169705Skan  IX86_BUILTIN_PCMPEQB128,
14858169705Skan  IX86_BUILTIN_PCMPEQW128,
14859169705Skan  IX86_BUILTIN_PCMPEQD128,
14860169705Skan  IX86_BUILTIN_PCMPGTB128,
14861169705Skan  IX86_BUILTIN_PCMPGTW128,
14862169705Skan  IX86_BUILTIN_PCMPGTD128,
14863169705Skan
14864169705Skan  IX86_BUILTIN_PMADDWD128,
14865169705Skan
14866169705Skan  IX86_BUILTIN_PMAXSW128,
14867169705Skan  IX86_BUILTIN_PMAXUB128,
14868169705Skan  IX86_BUILTIN_PMINSW128,
14869169705Skan  IX86_BUILTIN_PMINUB128,
14870169705Skan
14871169705Skan  IX86_BUILTIN_PMULUDQ,
14872169705Skan  IX86_BUILTIN_PMULUDQ128,
14873169705Skan  IX86_BUILTIN_PMULHUW128,
14874169705Skan  IX86_BUILTIN_PMULHW128,
14875169705Skan  IX86_BUILTIN_PMULLW128,
14876169705Skan
14877169705Skan  IX86_BUILTIN_PSADBW128,
14878169705Skan  IX86_BUILTIN_PSHUFHW,
14879169705Skan  IX86_BUILTIN_PSHUFLW,
14880169705Skan  IX86_BUILTIN_PSHUFD,
14881169705Skan
14882169705Skan  IX86_BUILTIN_PSLLW128,
14883169705Skan  IX86_BUILTIN_PSLLD128,
14884169705Skan  IX86_BUILTIN_PSLLQ128,
14885169705Skan  IX86_BUILTIN_PSRAW128,
14886169705Skan  IX86_BUILTIN_PSRAD128,
14887169705Skan  IX86_BUILTIN_PSRLW128,
14888169705Skan  IX86_BUILTIN_PSRLD128,
14889169705Skan  IX86_BUILTIN_PSRLQ128,
14890169705Skan  IX86_BUILTIN_PSLLDQI128,
14891169705Skan  IX86_BUILTIN_PSLLWI128,
14892169705Skan  IX86_BUILTIN_PSLLDI128,
14893169705Skan  IX86_BUILTIN_PSLLQI128,
14894169705Skan  IX86_BUILTIN_PSRAWI128,
14895169705Skan  IX86_BUILTIN_PSRADI128,
14896169705Skan  IX86_BUILTIN_PSRLDQI128,
14897169705Skan  IX86_BUILTIN_PSRLWI128,
14898169705Skan  IX86_BUILTIN_PSRLDI128,
14899169705Skan  IX86_BUILTIN_PSRLQI128,
14900169705Skan
14901169705Skan  IX86_BUILTIN_PUNPCKHBW128,
14902169705Skan  IX86_BUILTIN_PUNPCKHWD128,
14903169705Skan  IX86_BUILTIN_PUNPCKHDQ128,
14904169705Skan  IX86_BUILTIN_PUNPCKHQDQ128,
14905169705Skan  IX86_BUILTIN_PUNPCKLBW128,
14906169705Skan  IX86_BUILTIN_PUNPCKLWD128,
14907169705Skan  IX86_BUILTIN_PUNPCKLDQ128,
14908169705Skan  IX86_BUILTIN_PUNPCKLQDQ128,
14909169705Skan
14910169705Skan  IX86_BUILTIN_CLFLUSH,
14911169705Skan  IX86_BUILTIN_MFENCE,
14912169705Skan  IX86_BUILTIN_LFENCE,
14913169705Skan
14914169705Skan  /* Prescott New Instructions.  */
14915169705Skan  IX86_BUILTIN_ADDSUBPS,
14916169705Skan  IX86_BUILTIN_HADDPS,
14917169705Skan  IX86_BUILTIN_HSUBPS,
14918169705Skan  IX86_BUILTIN_MOVSHDUP,
14919169705Skan  IX86_BUILTIN_MOVSLDUP,
14920169705Skan  IX86_BUILTIN_ADDSUBPD,
14921169705Skan  IX86_BUILTIN_HADDPD,
14922169705Skan  IX86_BUILTIN_HSUBPD,
14923169705Skan  IX86_BUILTIN_LDDQU,
14924169705Skan
14925169705Skan  IX86_BUILTIN_MONITOR,
14926169705Skan  IX86_BUILTIN_MWAIT,
14927169705Skan
14928219639Smm  /* SSSE3.  */
14929219639Smm  IX86_BUILTIN_PHADDW,
14930219639Smm  IX86_BUILTIN_PHADDD,
14931219639Smm  IX86_BUILTIN_PHADDSW,
14932219639Smm  IX86_BUILTIN_PHSUBW,
14933219639Smm  IX86_BUILTIN_PHSUBD,
14934219639Smm  IX86_BUILTIN_PHSUBSW,
14935219639Smm  IX86_BUILTIN_PMADDUBSW,
14936219639Smm  IX86_BUILTIN_PMULHRSW,
14937219639Smm  IX86_BUILTIN_PSHUFB,
14938219639Smm  IX86_BUILTIN_PSIGNB,
14939219639Smm  IX86_BUILTIN_PSIGNW,
14940219639Smm  IX86_BUILTIN_PSIGND,
14941219639Smm  IX86_BUILTIN_PALIGNR,
14942219639Smm  IX86_BUILTIN_PABSB,
14943219639Smm  IX86_BUILTIN_PABSW,
14944219639Smm  IX86_BUILTIN_PABSD,
14945219639Smm
14946219639Smm  IX86_BUILTIN_PHADDW128,
14947219639Smm  IX86_BUILTIN_PHADDD128,
14948219639Smm  IX86_BUILTIN_PHADDSW128,
14949219639Smm  IX86_BUILTIN_PHSUBW128,
14950219639Smm  IX86_BUILTIN_PHSUBD128,
14951219639Smm  IX86_BUILTIN_PHSUBSW128,
14952219639Smm  IX86_BUILTIN_PMADDUBSW128,
14953219639Smm  IX86_BUILTIN_PMULHRSW128,
14954219639Smm  IX86_BUILTIN_PSHUFB128,
14955219639Smm  IX86_BUILTIN_PSIGNB128,
14956219639Smm  IX86_BUILTIN_PSIGNW128,
14957219639Smm  IX86_BUILTIN_PSIGND128,
14958219639Smm  IX86_BUILTIN_PALIGNR128,
14959219639Smm  IX86_BUILTIN_PABSB128,
14960219639Smm  IX86_BUILTIN_PABSW128,
14961219639Smm  IX86_BUILTIN_PABSD128,
14962219639Smm
14963251212Spfg  /* AMDFAM10 - SSE4A New Instructions.  */
14964251212Spfg  IX86_BUILTIN_MOVNTSD,
14965251212Spfg  IX86_BUILTIN_MOVNTSS,
14966251212Spfg  IX86_BUILTIN_EXTRQI,
14967251212Spfg  IX86_BUILTIN_EXTRQ,
14968251212Spfg  IX86_BUILTIN_INSERTQI,
14969251212Spfg  IX86_BUILTIN_INSERTQ,
14970251212Spfg
14971169705Skan  IX86_BUILTIN_VEC_INIT_V2SI,
14972169705Skan  IX86_BUILTIN_VEC_INIT_V4HI,
14973169705Skan  IX86_BUILTIN_VEC_INIT_V8QI,
14974169705Skan  IX86_BUILTIN_VEC_EXT_V2DF,
14975169705Skan  IX86_BUILTIN_VEC_EXT_V2DI,
14976169705Skan  IX86_BUILTIN_VEC_EXT_V4SF,
14977169705Skan  IX86_BUILTIN_VEC_EXT_V4SI,
14978169705Skan  IX86_BUILTIN_VEC_EXT_V8HI,
14979171836Skan  IX86_BUILTIN_VEC_EXT_V16QI,
14980169705Skan  IX86_BUILTIN_VEC_EXT_V2SI,
14981169705Skan  IX86_BUILTIN_VEC_EXT_V4HI,
14982169705Skan  IX86_BUILTIN_VEC_SET_V8HI,
14983169705Skan  IX86_BUILTIN_VEC_SET_V4HI,
14984169705Skan
14985169705Skan  IX86_BUILTIN_MAX
14986169705Skan};
14987169705Skan
14988169705Skan#define def_builtin(MASK, NAME, TYPE, CODE)				\
14989169705Skando {									\
14990169705Skan  if ((MASK) & target_flags						\
14991169705Skan      && (!((MASK) & MASK_64BIT) || TARGET_64BIT))			\
14992169705Skan    lang_hooks.builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD,	\
14993169705Skan				 NULL, NULL_TREE);			\
1499490284Sobrien} while (0)
1499552294Sobrien
14996169705Skan/* Bits for builtin_description.flag.  */
14997169705Skan
14998169705Skan/* Set when we don't support the comparison natively, and should
14999169705Skan   swap_comparison in order to support it.  */
15000169705Skan#define BUILTIN_DESC_SWAP_OPERANDS	1
15001169705Skan
1500290284Sobrienstruct builtin_description
1500390284Sobrien{
1500490284Sobrien  const unsigned int mask;
1500590284Sobrien  const enum insn_code icode;
1500690284Sobrien  const char *const name;
1500790284Sobrien  const enum ix86_builtins code;
1500890284Sobrien  const enum rtx_code comparison;
1500990284Sobrien  const unsigned int flag;
1501090284Sobrien};
1501152294Sobrien
1501290284Sobrienstatic const struct builtin_description bdesc_comi[] =
1501352294Sobrien{
15014122194Skan  { MASK_SSE, CODE_FOR_sse_comi, "__builtin_ia32_comieq", IX86_BUILTIN_COMIEQSS, UNEQ, 0 },
15015122194Skan  { MASK_SSE, CODE_FOR_sse_comi, "__builtin_ia32_comilt", IX86_BUILTIN_COMILTSS, UNLT, 0 },
15016122194Skan  { MASK_SSE, CODE_FOR_sse_comi, "__builtin_ia32_comile", IX86_BUILTIN_COMILESS, UNLE, 0 },
15017122194Skan  { MASK_SSE, CODE_FOR_sse_comi, "__builtin_ia32_comigt", IX86_BUILTIN_COMIGTSS, GT, 0 },
15018122194Skan  { MASK_SSE, CODE_FOR_sse_comi, "__builtin_ia32_comige", IX86_BUILTIN_COMIGESS, GE, 0 },
15019122194Skan  { MASK_SSE, CODE_FOR_sse_comi, "__builtin_ia32_comineq", IX86_BUILTIN_COMINEQSS, LTGT, 0 },
15020122194Skan  { MASK_SSE, CODE_FOR_sse_ucomi, "__builtin_ia32_ucomieq", IX86_BUILTIN_UCOMIEQSS, UNEQ, 0 },
15021122194Skan  { MASK_SSE, CODE_FOR_sse_ucomi, "__builtin_ia32_ucomilt", IX86_BUILTIN_UCOMILTSS, UNLT, 0 },
15022122194Skan  { MASK_SSE, CODE_FOR_sse_ucomi, "__builtin_ia32_ucomile", IX86_BUILTIN_UCOMILESS, UNLE, 0 },
15023122194Skan  { MASK_SSE, CODE_FOR_sse_ucomi, "__builtin_ia32_ucomigt", IX86_BUILTIN_UCOMIGTSS, GT, 0 },
15024122194Skan  { MASK_SSE, CODE_FOR_sse_ucomi, "__builtin_ia32_ucomige", IX86_BUILTIN_UCOMIGESS, GE, 0 },
15025122194Skan  { MASK_SSE, CODE_FOR_sse_ucomi, "__builtin_ia32_ucomineq", IX86_BUILTIN_UCOMINEQSS, LTGT, 0 },
15026117408Skan  { MASK_SSE2, CODE_FOR_sse2_comi, "__builtin_ia32_comisdeq", IX86_BUILTIN_COMIEQSD, UNEQ, 0 },
15027117408Skan  { MASK_SSE2, CODE_FOR_sse2_comi, "__builtin_ia32_comisdlt", IX86_BUILTIN_COMILTSD, UNLT, 0 },
15028117408Skan  { MASK_SSE2, CODE_FOR_sse2_comi, "__builtin_ia32_comisdle", IX86_BUILTIN_COMILESD, UNLE, 0 },
15029117408Skan  { MASK_SSE2, CODE_FOR_sse2_comi, "__builtin_ia32_comisdgt", IX86_BUILTIN_COMIGTSD, GT, 0 },
15030117408Skan  { MASK_SSE2, CODE_FOR_sse2_comi, "__builtin_ia32_comisdge", IX86_BUILTIN_COMIGESD, GE, 0 },
15031117408Skan  { MASK_SSE2, CODE_FOR_sse2_comi, "__builtin_ia32_comisdneq", IX86_BUILTIN_COMINEQSD, LTGT, 0 },
15032117408Skan  { MASK_SSE2, CODE_FOR_sse2_ucomi, "__builtin_ia32_ucomisdeq", IX86_BUILTIN_UCOMIEQSD, UNEQ, 0 },
15033117408Skan  { MASK_SSE2, CODE_FOR_sse2_ucomi, "__builtin_ia32_ucomisdlt", IX86_BUILTIN_UCOMILTSD, UNLT, 0 },
15034117408Skan  { MASK_SSE2, CODE_FOR_sse2_ucomi, "__builtin_ia32_ucomisdle", IX86_BUILTIN_UCOMILESD, UNLE, 0 },
15035117408Skan  { MASK_SSE2, CODE_FOR_sse2_ucomi, "__builtin_ia32_ucomisdgt", IX86_BUILTIN_UCOMIGTSD, GT, 0 },
15036117408Skan  { MASK_SSE2, CODE_FOR_sse2_ucomi, "__builtin_ia32_ucomisdge", IX86_BUILTIN_UCOMIGESD, GE, 0 },
15037117408Skan  { MASK_SSE2, CODE_FOR_sse2_ucomi, "__builtin_ia32_ucomisdneq", IX86_BUILTIN_UCOMINEQSD, LTGT, 0 },
1503890284Sobrien};
1503952294Sobrien
1504090284Sobrienstatic const struct builtin_description bdesc_2arg[] =
1504190284Sobrien{
1504290284Sobrien  /* SSE */
15043122194Skan  { MASK_SSE, CODE_FOR_addv4sf3, "__builtin_ia32_addps", IX86_BUILTIN_ADDPS, 0, 0 },
15044122194Skan  { MASK_SSE, CODE_FOR_subv4sf3, "__builtin_ia32_subps", IX86_BUILTIN_SUBPS, 0, 0 },
15045122194Skan  { MASK_SSE, CODE_FOR_mulv4sf3, "__builtin_ia32_mulps", IX86_BUILTIN_MULPS, 0, 0 },
15046122194Skan  { MASK_SSE, CODE_FOR_divv4sf3, "__builtin_ia32_divps", IX86_BUILTIN_DIVPS, 0, 0 },
15047169705Skan  { MASK_SSE, CODE_FOR_sse_vmaddv4sf3,  "__builtin_ia32_addss", IX86_BUILTIN_ADDSS, 0, 0 },
15048169705Skan  { MASK_SSE, CODE_FOR_sse_vmsubv4sf3,  "__builtin_ia32_subss", IX86_BUILTIN_SUBSS, 0, 0 },
15049169705Skan  { MASK_SSE, CODE_FOR_sse_vmmulv4sf3,  "__builtin_ia32_mulss", IX86_BUILTIN_MULSS, 0, 0 },
15050169705Skan  { MASK_SSE, CODE_FOR_sse_vmdivv4sf3,  "__builtin_ia32_divss", IX86_BUILTIN_DIVSS, 0, 0 },
1505190284Sobrien
15052169705Skan  { MASK_SSE, CODE_FOR_sse_maskcmpv4sf3, "__builtin_ia32_cmpeqps", IX86_BUILTIN_CMPEQPS, EQ, 0 },
15053169705Skan  { MASK_SSE, CODE_FOR_sse_maskcmpv4sf3, "__builtin_ia32_cmpltps", IX86_BUILTIN_CMPLTPS, LT, 0 },
15054169705Skan  { MASK_SSE, CODE_FOR_sse_maskcmpv4sf3, "__builtin_ia32_cmpleps", IX86_BUILTIN_CMPLEPS, LE, 0 },
15055169705Skan  { MASK_SSE, CODE_FOR_sse_maskcmpv4sf3, "__builtin_ia32_cmpgtps", IX86_BUILTIN_CMPGTPS, LT,
15056169705Skan    BUILTIN_DESC_SWAP_OPERANDS },
15057169705Skan  { MASK_SSE, CODE_FOR_sse_maskcmpv4sf3, "__builtin_ia32_cmpgeps", IX86_BUILTIN_CMPGEPS, LE,
15058169705Skan    BUILTIN_DESC_SWAP_OPERANDS },
15059169705Skan  { MASK_SSE, CODE_FOR_sse_maskcmpv4sf3, "__builtin_ia32_cmpunordps", IX86_BUILTIN_CMPUNORDPS, UNORDERED, 0 },
15060169705Skan  { MASK_SSE, CODE_FOR_sse_maskcmpv4sf3, "__builtin_ia32_cmpneqps", IX86_BUILTIN_CMPNEQPS, NE, 0 },
15061169705Skan  { MASK_SSE, CODE_FOR_sse_maskcmpv4sf3, "__builtin_ia32_cmpnltps", IX86_BUILTIN_CMPNLTPS, UNGE, 0 },
15062169705Skan  { MASK_SSE, CODE_FOR_sse_maskcmpv4sf3, "__builtin_ia32_cmpnleps", IX86_BUILTIN_CMPNLEPS, UNGT, 0 },
15063169705Skan  { MASK_SSE, CODE_FOR_sse_maskcmpv4sf3, "__builtin_ia32_cmpngtps", IX86_BUILTIN_CMPNGTPS, UNGE,
15064169705Skan    BUILTIN_DESC_SWAP_OPERANDS },
15065169705Skan  { MASK_SSE, CODE_FOR_sse_maskcmpv4sf3, "__builtin_ia32_cmpngeps", IX86_BUILTIN_CMPNGEPS, UNGT,
15066169705Skan    BUILTIN_DESC_SWAP_OPERANDS },
15067169705Skan  { MASK_SSE, CODE_FOR_sse_maskcmpv4sf3, "__builtin_ia32_cmpordps", IX86_BUILTIN_CMPORDPS, ORDERED, 0 },
15068169705Skan  { MASK_SSE, CODE_FOR_sse_vmmaskcmpv4sf3, "__builtin_ia32_cmpeqss", IX86_BUILTIN_CMPEQSS, EQ, 0 },
15069169705Skan  { MASK_SSE, CODE_FOR_sse_vmmaskcmpv4sf3, "__builtin_ia32_cmpltss", IX86_BUILTIN_CMPLTSS, LT, 0 },
15070169705Skan  { MASK_SSE, CODE_FOR_sse_vmmaskcmpv4sf3, "__builtin_ia32_cmpless", IX86_BUILTIN_CMPLESS, LE, 0 },
15071169705Skan  { MASK_SSE, CODE_FOR_sse_vmmaskcmpv4sf3, "__builtin_ia32_cmpunordss", IX86_BUILTIN_CMPUNORDSS, UNORDERED, 0 },
15072169705Skan  { MASK_SSE, CODE_FOR_sse_vmmaskcmpv4sf3, "__builtin_ia32_cmpneqss", IX86_BUILTIN_CMPNEQSS, NE, 0 },
15073169705Skan  { MASK_SSE, CODE_FOR_sse_vmmaskcmpv4sf3, "__builtin_ia32_cmpnltss", IX86_BUILTIN_CMPNLTSS, UNGE, 0 },
15074169705Skan  { MASK_SSE, CODE_FOR_sse_vmmaskcmpv4sf3, "__builtin_ia32_cmpnless", IX86_BUILTIN_CMPNLESS, UNGT, 0 },
15075169705Skan  { MASK_SSE, CODE_FOR_sse_vmmaskcmpv4sf3, "__builtin_ia32_cmpngtss", IX86_BUILTIN_CMPNGTSS, UNGE,
15076169705Skan    BUILTIN_DESC_SWAP_OPERANDS },
15077169705Skan  { MASK_SSE, CODE_FOR_sse_vmmaskcmpv4sf3, "__builtin_ia32_cmpngess", IX86_BUILTIN_CMPNGESS, UNGT,
15078169705Skan    BUILTIN_DESC_SWAP_OPERANDS },
15079169705Skan  { MASK_SSE, CODE_FOR_sse_vmmaskcmpv4sf3, "__builtin_ia32_cmpordss", IX86_BUILTIN_CMPORDSS, ORDERED, 0 },
1508090284Sobrien
15081122194Skan  { MASK_SSE, CODE_FOR_sminv4sf3, "__builtin_ia32_minps", IX86_BUILTIN_MINPS, 0, 0 },
15082122194Skan  { MASK_SSE, CODE_FOR_smaxv4sf3, "__builtin_ia32_maxps", IX86_BUILTIN_MAXPS, 0, 0 },
15083169705Skan  { MASK_SSE, CODE_FOR_sse_vmsminv4sf3, "__builtin_ia32_minss", IX86_BUILTIN_MINSS, 0, 0 },
15084169705Skan  { MASK_SSE, CODE_FOR_sse_vmsmaxv4sf3, "__builtin_ia32_maxss", IX86_BUILTIN_MAXSS, 0, 0 },
1508590284Sobrien
15086169705Skan  { MASK_SSE, CODE_FOR_andv4sf3, "__builtin_ia32_andps", IX86_BUILTIN_ANDPS, 0, 0 },
15087122194Skan  { MASK_SSE, CODE_FOR_sse_nandv4sf3,  "__builtin_ia32_andnps", IX86_BUILTIN_ANDNPS, 0, 0 },
15088169705Skan  { MASK_SSE, CODE_FOR_iorv4sf3, "__builtin_ia32_orps", IX86_BUILTIN_ORPS, 0, 0 },
15089169705Skan  { MASK_SSE, CODE_FOR_xorv4sf3,  "__builtin_ia32_xorps", IX86_BUILTIN_XORPS, 0, 0 },
1509090284Sobrien
15091122194Skan  { MASK_SSE, CODE_FOR_sse_movss,  "__builtin_ia32_movss", IX86_BUILTIN_MOVSS, 0, 0 },
15092122194Skan  { MASK_SSE, CODE_FOR_sse_movhlps,  "__builtin_ia32_movhlps", IX86_BUILTIN_MOVHLPS, 0, 0 },
15093122194Skan  { MASK_SSE, CODE_FOR_sse_movlhps,  "__builtin_ia32_movlhps", IX86_BUILTIN_MOVLHPS, 0, 0 },
15094122194Skan  { MASK_SSE, CODE_FOR_sse_unpckhps, "__builtin_ia32_unpckhps", IX86_BUILTIN_UNPCKHPS, 0, 0 },
15095122194Skan  { MASK_SSE, CODE_FOR_sse_unpcklps, "__builtin_ia32_unpcklps", IX86_BUILTIN_UNPCKLPS, 0, 0 },
15096117408Skan
1509790284Sobrien  /* MMX */
15098169705Skan  { MASK_MMX, CODE_FOR_mmx_addv8qi3, "__builtin_ia32_paddb", IX86_BUILTIN_PADDB, 0, 0 },
15099169705Skan  { MASK_MMX, CODE_FOR_mmx_addv4hi3, "__builtin_ia32_paddw", IX86_BUILTIN_PADDW, 0, 0 },
15100169705Skan  { MASK_MMX, CODE_FOR_mmx_addv2si3, "__builtin_ia32_paddd", IX86_BUILTIN_PADDD, 0, 0 },
15101169705Skan  { MASK_SSE2, CODE_FOR_mmx_adddi3, "__builtin_ia32_paddq", IX86_BUILTIN_PADDQ, 0, 0 },
15102169705Skan  { MASK_MMX, CODE_FOR_mmx_subv8qi3, "__builtin_ia32_psubb", IX86_BUILTIN_PSUBB, 0, 0 },
15103169705Skan  { MASK_MMX, CODE_FOR_mmx_subv4hi3, "__builtin_ia32_psubw", IX86_BUILTIN_PSUBW, 0, 0 },
15104169705Skan  { MASK_MMX, CODE_FOR_mmx_subv2si3, "__builtin_ia32_psubd", IX86_BUILTIN_PSUBD, 0, 0 },
15105169705Skan  { MASK_SSE2, CODE_FOR_mmx_subdi3, "__builtin_ia32_psubq", IX86_BUILTIN_PSUBQ, 0, 0 },
1510690284Sobrien
15107169705Skan  { MASK_MMX, CODE_FOR_mmx_ssaddv8qi3, "__builtin_ia32_paddsb", IX86_BUILTIN_PADDSB, 0, 0 },
15108169705Skan  { MASK_MMX, CODE_FOR_mmx_ssaddv4hi3, "__builtin_ia32_paddsw", IX86_BUILTIN_PADDSW, 0, 0 },
15109169705Skan  { MASK_MMX, CODE_FOR_mmx_sssubv8qi3, "__builtin_ia32_psubsb", IX86_BUILTIN_PSUBSB, 0, 0 },
15110169705Skan  { MASK_MMX, CODE_FOR_mmx_sssubv4hi3, "__builtin_ia32_psubsw", IX86_BUILTIN_PSUBSW, 0, 0 },
15111169705Skan  { MASK_MMX, CODE_FOR_mmx_usaddv8qi3, "__builtin_ia32_paddusb", IX86_BUILTIN_PADDUSB, 0, 0 },
15112169705Skan  { MASK_MMX, CODE_FOR_mmx_usaddv4hi3, "__builtin_ia32_paddusw", IX86_BUILTIN_PADDUSW, 0, 0 },
15113169705Skan  { MASK_MMX, CODE_FOR_mmx_ussubv8qi3, "__builtin_ia32_psubusb", IX86_BUILTIN_PSUBUSB, 0, 0 },
15114169705Skan  { MASK_MMX, CODE_FOR_mmx_ussubv4hi3, "__builtin_ia32_psubusw", IX86_BUILTIN_PSUBUSW, 0, 0 },
1511590284Sobrien
15116169705Skan  { MASK_MMX, CODE_FOR_mmx_mulv4hi3, "__builtin_ia32_pmullw", IX86_BUILTIN_PMULLW, 0, 0 },
15117169705Skan  { MASK_MMX, CODE_FOR_mmx_smulv4hi3_highpart, "__builtin_ia32_pmulhw", IX86_BUILTIN_PMULHW, 0, 0 },
15118169705Skan  { MASK_SSE | MASK_3DNOW_A, CODE_FOR_mmx_umulv4hi3_highpart, "__builtin_ia32_pmulhuw", IX86_BUILTIN_PMULHUW, 0, 0 },
1511990284Sobrien
15120169705Skan  { MASK_MMX, CODE_FOR_mmx_andv2si3, "__builtin_ia32_pand", IX86_BUILTIN_PAND, 0, 0 },
15121169705Skan  { MASK_MMX, CODE_FOR_mmx_nandv2si3, "__builtin_ia32_pandn", IX86_BUILTIN_PANDN, 0, 0 },
15122169705Skan  { MASK_MMX, CODE_FOR_mmx_iorv2si3, "__builtin_ia32_por", IX86_BUILTIN_POR, 0, 0 },
15123169705Skan  { MASK_MMX, CODE_FOR_mmx_xorv2si3, "__builtin_ia32_pxor", IX86_BUILTIN_PXOR, 0, 0 },
1512490284Sobrien
15125122194Skan  { MASK_SSE | MASK_3DNOW_A, CODE_FOR_mmx_uavgv8qi3, "__builtin_ia32_pavgb", IX86_BUILTIN_PAVGB, 0, 0 },
15126122194Skan  { MASK_SSE | MASK_3DNOW_A, CODE_FOR_mmx_uavgv4hi3, "__builtin_ia32_pavgw", IX86_BUILTIN_PAVGW, 0, 0 },
1512790284Sobrien
15128169705Skan  { MASK_MMX, CODE_FOR_mmx_eqv8qi3, "__builtin_ia32_pcmpeqb", IX86_BUILTIN_PCMPEQB, 0, 0 },
15129169705Skan  { MASK_MMX, CODE_FOR_mmx_eqv4hi3, "__builtin_ia32_pcmpeqw", IX86_BUILTIN_PCMPEQW, 0, 0 },
15130169705Skan  { MASK_MMX, CODE_FOR_mmx_eqv2si3, "__builtin_ia32_pcmpeqd", IX86_BUILTIN_PCMPEQD, 0, 0 },
15131169705Skan  { MASK_MMX, CODE_FOR_mmx_gtv8qi3, "__builtin_ia32_pcmpgtb", IX86_BUILTIN_PCMPGTB, 0, 0 },
15132169705Skan  { MASK_MMX, CODE_FOR_mmx_gtv4hi3, "__builtin_ia32_pcmpgtw", IX86_BUILTIN_PCMPGTW, 0, 0 },
15133169705Skan  { MASK_MMX, CODE_FOR_mmx_gtv2si3, "__builtin_ia32_pcmpgtd", IX86_BUILTIN_PCMPGTD, 0, 0 },
1513490284Sobrien
15135169705Skan  { MASK_SSE | MASK_3DNOW_A, CODE_FOR_mmx_umaxv8qi3, "__builtin_ia32_pmaxub", IX86_BUILTIN_PMAXUB, 0, 0 },
15136169705Skan  { MASK_SSE | MASK_3DNOW_A, CODE_FOR_mmx_smaxv4hi3, "__builtin_ia32_pmaxsw", IX86_BUILTIN_PMAXSW, 0, 0 },
15137169705Skan  { MASK_SSE | MASK_3DNOW_A, CODE_FOR_mmx_uminv8qi3, "__builtin_ia32_pminub", IX86_BUILTIN_PMINUB, 0, 0 },
15138169705Skan  { MASK_SSE | MASK_3DNOW_A, CODE_FOR_mmx_sminv4hi3, "__builtin_ia32_pminsw", IX86_BUILTIN_PMINSW, 0, 0 },
1513990284Sobrien
1514090284Sobrien  { MASK_MMX, CODE_FOR_mmx_punpckhbw, "__builtin_ia32_punpckhbw", IX86_BUILTIN_PUNPCKHBW, 0, 0 },
1514190284Sobrien  { MASK_MMX, CODE_FOR_mmx_punpckhwd, "__builtin_ia32_punpckhwd", IX86_BUILTIN_PUNPCKHWD, 0, 0 },
1514290284Sobrien  { MASK_MMX, CODE_FOR_mmx_punpckhdq, "__builtin_ia32_punpckhdq", IX86_BUILTIN_PUNPCKHDQ, 0, 0 },
1514390284Sobrien  { MASK_MMX, CODE_FOR_mmx_punpcklbw, "__builtin_ia32_punpcklbw", IX86_BUILTIN_PUNPCKLBW, 0, 0 },
1514490284Sobrien  { MASK_MMX, CODE_FOR_mmx_punpcklwd, "__builtin_ia32_punpcklwd", IX86_BUILTIN_PUNPCKLWD, 0, 0 },
1514590284Sobrien  { MASK_MMX, CODE_FOR_mmx_punpckldq, "__builtin_ia32_punpckldq", IX86_BUILTIN_PUNPCKLDQ, 0, 0 },
1514690284Sobrien
1514790284Sobrien  /* Special.  */
1514890284Sobrien  { MASK_MMX, CODE_FOR_mmx_packsswb, 0, IX86_BUILTIN_PACKSSWB, 0, 0 },
1514990284Sobrien  { MASK_MMX, CODE_FOR_mmx_packssdw, 0, IX86_BUILTIN_PACKSSDW, 0, 0 },
1515090284Sobrien  { MASK_MMX, CODE_FOR_mmx_packuswb, 0, IX86_BUILTIN_PACKUSWB, 0, 0 },
1515190284Sobrien
15152169705Skan  { MASK_SSE, CODE_FOR_sse_cvtpi2ps, 0, IX86_BUILTIN_CVTPI2PS, 0, 0 },
15153169705Skan  { MASK_SSE, CODE_FOR_sse_cvtsi2ss, 0, IX86_BUILTIN_CVTSI2SS, 0, 0 },
15154169705Skan  { MASK_SSE | MASK_64BIT, CODE_FOR_sse_cvtsi2ssq, 0, IX86_BUILTIN_CVTSI642SS, 0, 0 },
1515590284Sobrien
15156169705Skan  { MASK_MMX, CODE_FOR_mmx_ashlv4hi3, 0, IX86_BUILTIN_PSLLW, 0, 0 },
15157169705Skan  { MASK_MMX, CODE_FOR_mmx_ashlv4hi3, 0, IX86_BUILTIN_PSLLWI, 0, 0 },
15158169705Skan  { MASK_MMX, CODE_FOR_mmx_ashlv2si3, 0, IX86_BUILTIN_PSLLD, 0, 0 },
15159169705Skan  { MASK_MMX, CODE_FOR_mmx_ashlv2si3, 0, IX86_BUILTIN_PSLLDI, 0, 0 },
1516090284Sobrien  { MASK_MMX, CODE_FOR_mmx_ashldi3, 0, IX86_BUILTIN_PSLLQ, 0, 0 },
1516190284Sobrien  { MASK_MMX, CODE_FOR_mmx_ashldi3, 0, IX86_BUILTIN_PSLLQI, 0, 0 },
1516290284Sobrien
15163169705Skan  { MASK_MMX, CODE_FOR_mmx_lshrv4hi3, 0, IX86_BUILTIN_PSRLW, 0, 0 },
15164169705Skan  { MASK_MMX, CODE_FOR_mmx_lshrv4hi3, 0, IX86_BUILTIN_PSRLWI, 0, 0 },
15165169705Skan  { MASK_MMX, CODE_FOR_mmx_lshrv2si3, 0, IX86_BUILTIN_PSRLD, 0, 0 },
15166169705Skan  { MASK_MMX, CODE_FOR_mmx_lshrv2si3, 0, IX86_BUILTIN_PSRLDI, 0, 0 },
1516790284Sobrien  { MASK_MMX, CODE_FOR_mmx_lshrdi3, 0, IX86_BUILTIN_PSRLQ, 0, 0 },
1516890284Sobrien  { MASK_MMX, CODE_FOR_mmx_lshrdi3, 0, IX86_BUILTIN_PSRLQI, 0, 0 },
1516990284Sobrien
15170169705Skan  { MASK_MMX, CODE_FOR_mmx_ashrv4hi3, 0, IX86_BUILTIN_PSRAW, 0, 0 },
15171169705Skan  { MASK_MMX, CODE_FOR_mmx_ashrv4hi3, 0, IX86_BUILTIN_PSRAWI, 0, 0 },
15172169705Skan  { MASK_MMX, CODE_FOR_mmx_ashrv2si3, 0, IX86_BUILTIN_PSRAD, 0, 0 },
15173169705Skan  { MASK_MMX, CODE_FOR_mmx_ashrv2si3, 0, IX86_BUILTIN_PSRADI, 0, 0 },
1517490284Sobrien
15175122194Skan  { MASK_SSE | MASK_3DNOW_A, CODE_FOR_mmx_psadbw, 0, IX86_BUILTIN_PSADBW, 0, 0 },
15176117408Skan  { MASK_MMX, CODE_FOR_mmx_pmaddwd, 0, IX86_BUILTIN_PMADDWD, 0, 0 },
1517790284Sobrien
15178117408Skan  /* SSE2 */
15179117408Skan  { MASK_SSE2, CODE_FOR_addv2df3, "__builtin_ia32_addpd", IX86_BUILTIN_ADDPD, 0, 0 },
15180117408Skan  { MASK_SSE2, CODE_FOR_subv2df3, "__builtin_ia32_subpd", IX86_BUILTIN_SUBPD, 0, 0 },
15181117408Skan  { MASK_SSE2, CODE_FOR_mulv2df3, "__builtin_ia32_mulpd", IX86_BUILTIN_MULPD, 0, 0 },
15182117408Skan  { MASK_SSE2, CODE_FOR_divv2df3, "__builtin_ia32_divpd", IX86_BUILTIN_DIVPD, 0, 0 },
15183169705Skan  { MASK_SSE2, CODE_FOR_sse2_vmaddv2df3,  "__builtin_ia32_addsd", IX86_BUILTIN_ADDSD, 0, 0 },
15184169705Skan  { MASK_SSE2, CODE_FOR_sse2_vmsubv2df3,  "__builtin_ia32_subsd", IX86_BUILTIN_SUBSD, 0, 0 },
15185169705Skan  { MASK_SSE2, CODE_FOR_sse2_vmmulv2df3,  "__builtin_ia32_mulsd", IX86_BUILTIN_MULSD, 0, 0 },
15186169705Skan  { MASK_SSE2, CODE_FOR_sse2_vmdivv2df3,  "__builtin_ia32_divsd", IX86_BUILTIN_DIVSD, 0, 0 },
15187117408Skan
15188169705Skan  { MASK_SSE2, CODE_FOR_sse2_maskcmpv2df3, "__builtin_ia32_cmpeqpd", IX86_BUILTIN_CMPEQPD, EQ, 0 },
15189169705Skan  { MASK_SSE2, CODE_FOR_sse2_maskcmpv2df3, "__builtin_ia32_cmpltpd", IX86_BUILTIN_CMPLTPD, LT, 0 },
15190169705Skan  { MASK_SSE2, CODE_FOR_sse2_maskcmpv2df3, "__builtin_ia32_cmplepd", IX86_BUILTIN_CMPLEPD, LE, 0 },
15191169705Skan  { MASK_SSE2, CODE_FOR_sse2_maskcmpv2df3, "__builtin_ia32_cmpgtpd", IX86_BUILTIN_CMPGTPD, LT,
15192169705Skan    BUILTIN_DESC_SWAP_OPERANDS },
15193169705Skan  { MASK_SSE2, CODE_FOR_sse2_maskcmpv2df3, "__builtin_ia32_cmpgepd", IX86_BUILTIN_CMPGEPD, LE,
15194169705Skan    BUILTIN_DESC_SWAP_OPERANDS },
15195169705Skan  { MASK_SSE2, CODE_FOR_sse2_maskcmpv2df3, "__builtin_ia32_cmpunordpd", IX86_BUILTIN_CMPUNORDPD, UNORDERED, 0 },
15196169705Skan  { MASK_SSE2, CODE_FOR_sse2_maskcmpv2df3, "__builtin_ia32_cmpneqpd", IX86_BUILTIN_CMPNEQPD, NE, 0 },
15197169705Skan  { MASK_SSE2, CODE_FOR_sse2_maskcmpv2df3, "__builtin_ia32_cmpnltpd", IX86_BUILTIN_CMPNLTPD, UNGE, 0 },
15198169705Skan  { MASK_SSE2, CODE_FOR_sse2_maskcmpv2df3, "__builtin_ia32_cmpnlepd", IX86_BUILTIN_CMPNLEPD, UNGT, 0 },
15199169705Skan  { MASK_SSE2, CODE_FOR_sse2_maskcmpv2df3, "__builtin_ia32_cmpngtpd", IX86_BUILTIN_CMPNGTPD, UNGE,
15200169705Skan    BUILTIN_DESC_SWAP_OPERANDS },
15201169705Skan  { MASK_SSE2, CODE_FOR_sse2_maskcmpv2df3, "__builtin_ia32_cmpngepd", IX86_BUILTIN_CMPNGEPD, UNGT,
15202169705Skan    BUILTIN_DESC_SWAP_OPERANDS },
15203169705Skan  { MASK_SSE2, CODE_FOR_sse2_maskcmpv2df3, "__builtin_ia32_cmpordpd", IX86_BUILTIN_CMPORDPD, ORDERED, 0 },
15204169705Skan  { MASK_SSE2, CODE_FOR_sse2_vmmaskcmpv2df3, "__builtin_ia32_cmpeqsd", IX86_BUILTIN_CMPEQSD, EQ, 0 },
15205169705Skan  { MASK_SSE2, CODE_FOR_sse2_vmmaskcmpv2df3, "__builtin_ia32_cmpltsd", IX86_BUILTIN_CMPLTSD, LT, 0 },
15206169705Skan  { MASK_SSE2, CODE_FOR_sse2_vmmaskcmpv2df3, "__builtin_ia32_cmplesd", IX86_BUILTIN_CMPLESD, LE, 0 },
15207169705Skan  { MASK_SSE2, CODE_FOR_sse2_vmmaskcmpv2df3, "__builtin_ia32_cmpunordsd", IX86_BUILTIN_CMPUNORDSD, UNORDERED, 0 },
15208169705Skan  { MASK_SSE2, CODE_FOR_sse2_vmmaskcmpv2df3, "__builtin_ia32_cmpneqsd", IX86_BUILTIN_CMPNEQSD, NE, 0 },
15209169705Skan  { MASK_SSE2, CODE_FOR_sse2_vmmaskcmpv2df3, "__builtin_ia32_cmpnltsd", IX86_BUILTIN_CMPNLTSD, UNGE, 0 },
15210169705Skan  { MASK_SSE2, CODE_FOR_sse2_vmmaskcmpv2df3, "__builtin_ia32_cmpnlesd", IX86_BUILTIN_CMPNLESD, UNGT, 0 },
15211169705Skan  { MASK_SSE2, CODE_FOR_sse2_vmmaskcmpv2df3, "__builtin_ia32_cmpordsd", IX86_BUILTIN_CMPORDSD, ORDERED, 0 },
15212117408Skan
15213117408Skan  { MASK_SSE2, CODE_FOR_sminv2df3, "__builtin_ia32_minpd", IX86_BUILTIN_MINPD, 0, 0 },
15214117408Skan  { MASK_SSE2, CODE_FOR_smaxv2df3, "__builtin_ia32_maxpd", IX86_BUILTIN_MAXPD, 0, 0 },
15215169705Skan  { MASK_SSE2, CODE_FOR_sse2_vmsminv2df3, "__builtin_ia32_minsd", IX86_BUILTIN_MINSD, 0, 0 },
15216169705Skan  { MASK_SSE2, CODE_FOR_sse2_vmsmaxv2df3, "__builtin_ia32_maxsd", IX86_BUILTIN_MAXSD, 0, 0 },
15217117408Skan
15218169705Skan  { MASK_SSE2, CODE_FOR_andv2df3, "__builtin_ia32_andpd", IX86_BUILTIN_ANDPD, 0, 0 },
15219117408Skan  { MASK_SSE2, CODE_FOR_sse2_nandv2df3,  "__builtin_ia32_andnpd", IX86_BUILTIN_ANDNPD, 0, 0 },
15220169705Skan  { MASK_SSE2, CODE_FOR_iorv2df3, "__builtin_ia32_orpd", IX86_BUILTIN_ORPD, 0, 0 },
15221169705Skan  { MASK_SSE2, CODE_FOR_xorv2df3,  "__builtin_ia32_xorpd", IX86_BUILTIN_XORPD, 0, 0 },
15222117408Skan
15223117408Skan  { MASK_SSE2, CODE_FOR_sse2_movsd,  "__builtin_ia32_movsd", IX86_BUILTIN_MOVSD, 0, 0 },
15224117408Skan  { MASK_SSE2, CODE_FOR_sse2_unpckhpd, "__builtin_ia32_unpckhpd", IX86_BUILTIN_UNPCKHPD, 0, 0 },
15225117408Skan  { MASK_SSE2, CODE_FOR_sse2_unpcklpd, "__builtin_ia32_unpcklpd", IX86_BUILTIN_UNPCKLPD, 0, 0 },
15226117408Skan
15227117408Skan  /* SSE2 MMX */
15228117408Skan  { MASK_SSE2, CODE_FOR_addv16qi3, "__builtin_ia32_paddb128", IX86_BUILTIN_PADDB128, 0, 0 },
15229117408Skan  { MASK_SSE2, CODE_FOR_addv8hi3, "__builtin_ia32_paddw128", IX86_BUILTIN_PADDW128, 0, 0 },
15230117408Skan  { MASK_SSE2, CODE_FOR_addv4si3, "__builtin_ia32_paddd128", IX86_BUILTIN_PADDD128, 0, 0 },
15231117408Skan  { MASK_SSE2, CODE_FOR_addv2di3, "__builtin_ia32_paddq128", IX86_BUILTIN_PADDQ128, 0, 0 },
15232117408Skan  { MASK_SSE2, CODE_FOR_subv16qi3, "__builtin_ia32_psubb128", IX86_BUILTIN_PSUBB128, 0, 0 },
15233117408Skan  { MASK_SSE2, CODE_FOR_subv8hi3, "__builtin_ia32_psubw128", IX86_BUILTIN_PSUBW128, 0, 0 },
15234117408Skan  { MASK_SSE2, CODE_FOR_subv4si3, "__builtin_ia32_psubd128", IX86_BUILTIN_PSUBD128, 0, 0 },
15235117408Skan  { MASK_SSE2, CODE_FOR_subv2di3, "__builtin_ia32_psubq128", IX86_BUILTIN_PSUBQ128, 0, 0 },
15236117408Skan
15237169705Skan  { MASK_MMX, CODE_FOR_sse2_ssaddv16qi3, "__builtin_ia32_paddsb128", IX86_BUILTIN_PADDSB128, 0, 0 },
15238169705Skan  { MASK_MMX, CODE_FOR_sse2_ssaddv8hi3, "__builtin_ia32_paddsw128", IX86_BUILTIN_PADDSW128, 0, 0 },
15239169705Skan  { MASK_MMX, CODE_FOR_sse2_sssubv16qi3, "__builtin_ia32_psubsb128", IX86_BUILTIN_PSUBSB128, 0, 0 },
15240169705Skan  { MASK_MMX, CODE_FOR_sse2_sssubv8hi3, "__builtin_ia32_psubsw128", IX86_BUILTIN_PSUBSW128, 0, 0 },
15241169705Skan  { MASK_MMX, CODE_FOR_sse2_usaddv16qi3, "__builtin_ia32_paddusb128", IX86_BUILTIN_PADDUSB128, 0, 0 },
15242169705Skan  { MASK_MMX, CODE_FOR_sse2_usaddv8hi3, "__builtin_ia32_paddusw128", IX86_BUILTIN_PADDUSW128, 0, 0 },
15243169705Skan  { MASK_MMX, CODE_FOR_sse2_ussubv16qi3, "__builtin_ia32_psubusb128", IX86_BUILTIN_PSUBUSB128, 0, 0 },
15244169705Skan  { MASK_MMX, CODE_FOR_sse2_ussubv8hi3, "__builtin_ia32_psubusw128", IX86_BUILTIN_PSUBUSW128, 0, 0 },
15245117408Skan
15246117408Skan  { MASK_SSE2, CODE_FOR_mulv8hi3, "__builtin_ia32_pmullw128", IX86_BUILTIN_PMULLW128, 0, 0 },
15247169705Skan  { MASK_SSE2, CODE_FOR_sse2_smulv8hi3_highpart, "__builtin_ia32_pmulhw128", IX86_BUILTIN_PMULHW128, 0, 0 },
15248117408Skan
15249169705Skan  { MASK_SSE2, CODE_FOR_andv2di3, "__builtin_ia32_pand128", IX86_BUILTIN_PAND128, 0, 0 },
15250117408Skan  { MASK_SSE2, CODE_FOR_sse2_nandv2di3, "__builtin_ia32_pandn128", IX86_BUILTIN_PANDN128, 0, 0 },
15251169705Skan  { MASK_SSE2, CODE_FOR_iorv2di3, "__builtin_ia32_por128", IX86_BUILTIN_POR128, 0, 0 },
15252169705Skan  { MASK_SSE2, CODE_FOR_xorv2di3, "__builtin_ia32_pxor128", IX86_BUILTIN_PXOR128, 0, 0 },
15253117408Skan
15254117408Skan  { MASK_SSE2, CODE_FOR_sse2_uavgv16qi3, "__builtin_ia32_pavgb128", IX86_BUILTIN_PAVGB128, 0, 0 },
15255117408Skan  { MASK_SSE2, CODE_FOR_sse2_uavgv8hi3, "__builtin_ia32_pavgw128", IX86_BUILTIN_PAVGW128, 0, 0 },
15256117408Skan
15257169705Skan  { MASK_SSE2, CODE_FOR_sse2_eqv16qi3, "__builtin_ia32_pcmpeqb128", IX86_BUILTIN_PCMPEQB128, 0, 0 },
15258169705Skan  { MASK_SSE2, CODE_FOR_sse2_eqv8hi3, "__builtin_ia32_pcmpeqw128", IX86_BUILTIN_PCMPEQW128, 0, 0 },
15259169705Skan  { MASK_SSE2, CODE_FOR_sse2_eqv4si3, "__builtin_ia32_pcmpeqd128", IX86_BUILTIN_PCMPEQD128, 0, 0 },
15260169705Skan  { MASK_SSE2, CODE_FOR_sse2_gtv16qi3, "__builtin_ia32_pcmpgtb128", IX86_BUILTIN_PCMPGTB128, 0, 0 },
15261169705Skan  { MASK_SSE2, CODE_FOR_sse2_gtv8hi3, "__builtin_ia32_pcmpgtw128", IX86_BUILTIN_PCMPGTW128, 0, 0 },
15262169705Skan  { MASK_SSE2, CODE_FOR_sse2_gtv4si3, "__builtin_ia32_pcmpgtd128", IX86_BUILTIN_PCMPGTD128, 0, 0 },
15263117408Skan
15264117408Skan  { MASK_SSE2, CODE_FOR_umaxv16qi3, "__builtin_ia32_pmaxub128", IX86_BUILTIN_PMAXUB128, 0, 0 },
15265117408Skan  { MASK_SSE2, CODE_FOR_smaxv8hi3, "__builtin_ia32_pmaxsw128", IX86_BUILTIN_PMAXSW128, 0, 0 },
15266117408Skan  { MASK_SSE2, CODE_FOR_uminv16qi3, "__builtin_ia32_pminub128", IX86_BUILTIN_PMINUB128, 0, 0 },
15267117408Skan  { MASK_SSE2, CODE_FOR_sminv8hi3, "__builtin_ia32_pminsw128", IX86_BUILTIN_PMINSW128, 0, 0 },
15268117408Skan
15269117408Skan  { MASK_SSE2, CODE_FOR_sse2_punpckhbw, "__builtin_ia32_punpckhbw128", IX86_BUILTIN_PUNPCKHBW128, 0, 0 },
15270117408Skan  { MASK_SSE2, CODE_FOR_sse2_punpckhwd, "__builtin_ia32_punpckhwd128", IX86_BUILTIN_PUNPCKHWD128, 0, 0 },
15271117408Skan  { MASK_SSE2, CODE_FOR_sse2_punpckhdq, "__builtin_ia32_punpckhdq128", IX86_BUILTIN_PUNPCKHDQ128, 0, 0 },
15272117408Skan  { MASK_SSE2, CODE_FOR_sse2_punpckhqdq, "__builtin_ia32_punpckhqdq128", IX86_BUILTIN_PUNPCKHQDQ128, 0, 0 },
15273117408Skan  { MASK_SSE2, CODE_FOR_sse2_punpcklbw, "__builtin_ia32_punpcklbw128", IX86_BUILTIN_PUNPCKLBW128, 0, 0 },
15274117408Skan  { MASK_SSE2, CODE_FOR_sse2_punpcklwd, "__builtin_ia32_punpcklwd128", IX86_BUILTIN_PUNPCKLWD128, 0, 0 },
15275117408Skan  { MASK_SSE2, CODE_FOR_sse2_punpckldq, "__builtin_ia32_punpckldq128", IX86_BUILTIN_PUNPCKLDQ128, 0, 0 },
15276117408Skan  { MASK_SSE2, CODE_FOR_sse2_punpcklqdq, "__builtin_ia32_punpcklqdq128", IX86_BUILTIN_PUNPCKLQDQ128, 0, 0 },
15277117408Skan
15278117408Skan  { MASK_SSE2, CODE_FOR_sse2_packsswb, "__builtin_ia32_packsswb128", IX86_BUILTIN_PACKSSWB128, 0, 0 },
15279117408Skan  { MASK_SSE2, CODE_FOR_sse2_packssdw, "__builtin_ia32_packssdw128", IX86_BUILTIN_PACKSSDW128, 0, 0 },
15280117408Skan  { MASK_SSE2, CODE_FOR_sse2_packuswb, "__builtin_ia32_packuswb128", IX86_BUILTIN_PACKUSWB128, 0, 0 },
15281117408Skan
15282169705Skan  { MASK_SSE2, CODE_FOR_sse2_umulv8hi3_highpart, "__builtin_ia32_pmulhuw128", IX86_BUILTIN_PMULHUW128, 0, 0 },
15283117408Skan  { MASK_SSE2, CODE_FOR_sse2_psadbw, 0, IX86_BUILTIN_PSADBW128, 0, 0 },
15284117408Skan
15285169705Skan  { MASK_SSE2, CODE_FOR_sse2_umulsidi3, 0, IX86_BUILTIN_PMULUDQ, 0, 0 },
15286169705Skan  { MASK_SSE2, CODE_FOR_sse2_umulv2siv2di3, 0, IX86_BUILTIN_PMULUDQ128, 0, 0 },
15287169705Skan
15288117408Skan  { MASK_SSE2, CODE_FOR_ashlv8hi3, 0, IX86_BUILTIN_PSLLWI128, 0, 0 },
15289117408Skan  { MASK_SSE2, CODE_FOR_ashlv4si3, 0, IX86_BUILTIN_PSLLDI128, 0, 0 },
15290117408Skan  { MASK_SSE2, CODE_FOR_ashlv2di3, 0, IX86_BUILTIN_PSLLQI128, 0, 0 },
15291117408Skan
15292117408Skan  { MASK_SSE2, CODE_FOR_lshrv8hi3, 0, IX86_BUILTIN_PSRLWI128, 0, 0 },
15293117408Skan  { MASK_SSE2, CODE_FOR_lshrv4si3, 0, IX86_BUILTIN_PSRLDI128, 0, 0 },
15294117408Skan  { MASK_SSE2, CODE_FOR_lshrv2di3, 0, IX86_BUILTIN_PSRLQI128, 0, 0 },
15295117408Skan
15296117408Skan  { MASK_SSE2, CODE_FOR_ashrv8hi3, 0, IX86_BUILTIN_PSRAWI128, 0, 0 },
15297117408Skan  { MASK_SSE2, CODE_FOR_ashrv4si3, 0, IX86_BUILTIN_PSRADI128, 0, 0 },
15298117408Skan
15299117408Skan  { MASK_SSE2, CODE_FOR_sse2_pmaddwd, 0, IX86_BUILTIN_PMADDWD128, 0, 0 },
15300117408Skan
15301169705Skan  { MASK_SSE2, CODE_FOR_sse2_cvtsi2sd, 0, IX86_BUILTIN_CVTSI2SD, 0, 0 },
15302169705Skan  { MASK_SSE2 | MASK_64BIT, CODE_FOR_sse2_cvtsi2sdq, 0, IX86_BUILTIN_CVTSI642SD, 0, 0 },
15303169705Skan  { MASK_SSE2, CODE_FOR_sse2_cvtsd2ss, 0, IX86_BUILTIN_CVTSD2SS, 0, 0 },
15304169705Skan  { MASK_SSE2, CODE_FOR_sse2_cvtss2sd, 0, IX86_BUILTIN_CVTSS2SD, 0, 0 },
15305122194Skan
15306132743Skan  /* SSE3 MMX */
15307169705Skan  { MASK_SSE3, CODE_FOR_sse3_addsubv4sf3, "__builtin_ia32_addsubps", IX86_BUILTIN_ADDSUBPS, 0, 0 },
15308169705Skan  { MASK_SSE3, CODE_FOR_sse3_addsubv2df3, "__builtin_ia32_addsubpd", IX86_BUILTIN_ADDSUBPD, 0, 0 },
15309169705Skan  { MASK_SSE3, CODE_FOR_sse3_haddv4sf3, "__builtin_ia32_haddps", IX86_BUILTIN_HADDPS, 0, 0 },
15310169705Skan  { MASK_SSE3, CODE_FOR_sse3_haddv2df3, "__builtin_ia32_haddpd", IX86_BUILTIN_HADDPD, 0, 0 },
15311169705Skan  { MASK_SSE3, CODE_FOR_sse3_hsubv4sf3, "__builtin_ia32_hsubps", IX86_BUILTIN_HSUBPS, 0, 0 },
15312219639Smm  { MASK_SSE3, CODE_FOR_sse3_hsubv2df3, "__builtin_ia32_hsubpd", IX86_BUILTIN_HSUBPD, 0, 0 },
15313219639Smm
15314219639Smm  /* SSSE3 */
15315219639Smm  { MASK_SSSE3, CODE_FOR_ssse3_phaddwv8hi3, "__builtin_ia32_phaddw128", IX86_BUILTIN_PHADDW128, 0, 0 },
15316219639Smm  { MASK_SSSE3, CODE_FOR_ssse3_phaddwv4hi3, "__builtin_ia32_phaddw", IX86_BUILTIN_PHADDW, 0, 0 },
15317219639Smm  { MASK_SSSE3, CODE_FOR_ssse3_phadddv4si3, "__builtin_ia32_phaddd128", IX86_BUILTIN_PHADDD128, 0, 0 },
15318219639Smm  { MASK_SSSE3, CODE_FOR_ssse3_phadddv2si3, "__builtin_ia32_phaddd", IX86_BUILTIN_PHADDD, 0, 0 },
15319219639Smm  { MASK_SSSE3, CODE_FOR_ssse3_phaddswv8hi3, "__builtin_ia32_phaddsw128", IX86_BUILTIN_PHADDSW128, 0, 0 },
15320219639Smm  { MASK_SSSE3, CODE_FOR_ssse3_phaddswv4hi3, "__builtin_ia32_phaddsw", IX86_BUILTIN_PHADDSW, 0, 0 },
15321219639Smm  { MASK_SSSE3, CODE_FOR_ssse3_phsubwv8hi3, "__builtin_ia32_phsubw128", IX86_BUILTIN_PHSUBW128, 0, 0 },
15322219639Smm  { MASK_SSSE3, CODE_FOR_ssse3_phsubwv4hi3, "__builtin_ia32_phsubw", IX86_BUILTIN_PHSUBW, 0, 0 },
15323219639Smm  { MASK_SSSE3, CODE_FOR_ssse3_phsubdv4si3, "__builtin_ia32_phsubd128", IX86_BUILTIN_PHSUBD128, 0, 0 },
15324219639Smm  { MASK_SSSE3, CODE_FOR_ssse3_phsubdv2si3, "__builtin_ia32_phsubd", IX86_BUILTIN_PHSUBD, 0, 0 },
15325219639Smm  { MASK_SSSE3, CODE_FOR_ssse3_phsubswv8hi3, "__builtin_ia32_phsubsw128", IX86_BUILTIN_PHSUBSW128, 0, 0 },
15326219639Smm  { MASK_SSSE3, CODE_FOR_ssse3_phsubswv4hi3, "__builtin_ia32_phsubsw", IX86_BUILTIN_PHSUBSW, 0, 0 },
15327219639Smm  { MASK_SSSE3, CODE_FOR_ssse3_pmaddubswv8hi3, "__builtin_ia32_pmaddubsw128", IX86_BUILTIN_PMADDUBSW128, 0, 0 },
15328219639Smm  { MASK_SSSE3, CODE_FOR_ssse3_pmaddubswv4hi3, "__builtin_ia32_pmaddubsw", IX86_BUILTIN_PMADDUBSW, 0, 0 },
15329219639Smm  { MASK_SSSE3, CODE_FOR_ssse3_pmulhrswv8hi3, "__builtin_ia32_pmulhrsw128", IX86_BUILTIN_PMULHRSW128, 0, 0 },
15330219639Smm  { MASK_SSSE3, CODE_FOR_ssse3_pmulhrswv4hi3, "__builtin_ia32_pmulhrsw", IX86_BUILTIN_PMULHRSW, 0, 0 },
15331219639Smm  { MASK_SSSE3, CODE_FOR_ssse3_pshufbv16qi3, "__builtin_ia32_pshufb128", IX86_BUILTIN_PSHUFB128, 0, 0 },
15332219639Smm  { MASK_SSSE3, CODE_FOR_ssse3_pshufbv8qi3, "__builtin_ia32_pshufb", IX86_BUILTIN_PSHUFB, 0, 0 },
15333219639Smm  { MASK_SSSE3, CODE_FOR_ssse3_psignv16qi3, "__builtin_ia32_psignb128", IX86_BUILTIN_PSIGNB128, 0, 0 },
15334219639Smm  { MASK_SSSE3, CODE_FOR_ssse3_psignv8qi3, "__builtin_ia32_psignb", IX86_BUILTIN_PSIGNB, 0, 0 },
15335219639Smm  { MASK_SSSE3, CODE_FOR_ssse3_psignv8hi3, "__builtin_ia32_psignw128", IX86_BUILTIN_PSIGNW128, 0, 0 },
15336219639Smm  { MASK_SSSE3, CODE_FOR_ssse3_psignv4hi3, "__builtin_ia32_psignw", IX86_BUILTIN_PSIGNW, 0, 0 },
15337219639Smm  { MASK_SSSE3, CODE_FOR_ssse3_psignv4si3, "__builtin_ia32_psignd128", IX86_BUILTIN_PSIGND128, 0, 0 },
15338219639Smm  { MASK_SSSE3, CODE_FOR_ssse3_psignv2si3, "__builtin_ia32_psignd", IX86_BUILTIN_PSIGND, 0, 0 }
1533990284Sobrien};
1534090284Sobrien
1534190284Sobrienstatic const struct builtin_description bdesc_1arg[] =
1534290284Sobrien{
15343122194Skan  { MASK_SSE | MASK_3DNOW_A, CODE_FOR_mmx_pmovmskb, 0, IX86_BUILTIN_PMOVMSKB, 0, 0 },
15344122194Skan  { MASK_SSE, CODE_FOR_sse_movmskps, 0, IX86_BUILTIN_MOVMSKPS, 0, 0 },
1534590284Sobrien
15346122194Skan  { MASK_SSE, CODE_FOR_sqrtv4sf2, 0, IX86_BUILTIN_SQRTPS, 0, 0 },
15347169705Skan  { MASK_SSE, CODE_FOR_sse_rsqrtv4sf2, 0, IX86_BUILTIN_RSQRTPS, 0, 0 },
15348169705Skan  { MASK_SSE, CODE_FOR_sse_rcpv4sf2, 0, IX86_BUILTIN_RCPPS, 0, 0 },
1534990284Sobrien
15350169705Skan  { MASK_SSE, CODE_FOR_sse_cvtps2pi, 0, IX86_BUILTIN_CVTPS2PI, 0, 0 },
15351169705Skan  { MASK_SSE, CODE_FOR_sse_cvtss2si, 0, IX86_BUILTIN_CVTSS2SI, 0, 0 },
15352169705Skan  { MASK_SSE | MASK_64BIT, CODE_FOR_sse_cvtss2siq, 0, IX86_BUILTIN_CVTSS2SI64, 0, 0 },
15353169705Skan  { MASK_SSE, CODE_FOR_sse_cvttps2pi, 0, IX86_BUILTIN_CVTTPS2PI, 0, 0 },
15354169705Skan  { MASK_SSE, CODE_FOR_sse_cvttss2si, 0, IX86_BUILTIN_CVTTSS2SI, 0, 0 },
15355169705Skan  { MASK_SSE | MASK_64BIT, CODE_FOR_sse_cvttss2siq, 0, IX86_BUILTIN_CVTTSS2SI64, 0, 0 },
1535690284Sobrien
15357117408Skan  { MASK_SSE2, CODE_FOR_sse2_pmovmskb, 0, IX86_BUILTIN_PMOVMSKB128, 0, 0 },
15358117408Skan  { MASK_SSE2, CODE_FOR_sse2_movmskpd, 0, IX86_BUILTIN_MOVMSKPD, 0, 0 },
15359117408Skan
15360117408Skan  { MASK_SSE2, CODE_FOR_sqrtv2df2, 0, IX86_BUILTIN_SQRTPD, 0, 0 },
15361117408Skan
15362169705Skan  { MASK_SSE2, CODE_FOR_sse2_cvtdq2pd, 0, IX86_BUILTIN_CVTDQ2PD, 0, 0 },
15363169705Skan  { MASK_SSE2, CODE_FOR_sse2_cvtdq2ps, 0, IX86_BUILTIN_CVTDQ2PS, 0, 0 },
15364117408Skan
15365169705Skan  { MASK_SSE2, CODE_FOR_sse2_cvtpd2dq, 0, IX86_BUILTIN_CVTPD2DQ, 0, 0 },
15366169705Skan  { MASK_SSE2, CODE_FOR_sse2_cvtpd2pi, 0, IX86_BUILTIN_CVTPD2PI, 0, 0 },
15367169705Skan  { MASK_SSE2, CODE_FOR_sse2_cvtpd2ps, 0, IX86_BUILTIN_CVTPD2PS, 0, 0 },
15368169705Skan  { MASK_SSE2, CODE_FOR_sse2_cvttpd2dq, 0, IX86_BUILTIN_CVTTPD2DQ, 0, 0 },
15369169705Skan  { MASK_SSE2, CODE_FOR_sse2_cvttpd2pi, 0, IX86_BUILTIN_CVTTPD2PI, 0, 0 },
15370117408Skan
15371169705Skan  { MASK_SSE2, CODE_FOR_sse2_cvtpi2pd, 0, IX86_BUILTIN_CVTPI2PD, 0, 0 },
15372117408Skan
15373169705Skan  { MASK_SSE2, CODE_FOR_sse2_cvtsd2si, 0, IX86_BUILTIN_CVTSD2SI, 0, 0 },
15374169705Skan  { MASK_SSE2, CODE_FOR_sse2_cvttsd2si, 0, IX86_BUILTIN_CVTTSD2SI, 0, 0 },
15375169705Skan  { MASK_SSE2 | MASK_64BIT, CODE_FOR_sse2_cvtsd2siq, 0, IX86_BUILTIN_CVTSD2SI64, 0, 0 },
15376169705Skan  { MASK_SSE2 | MASK_64BIT, CODE_FOR_sse2_cvttsd2siq, 0, IX86_BUILTIN_CVTTSD2SI64, 0, 0 },
15377117408Skan
15378169705Skan  { MASK_SSE2, CODE_FOR_sse2_cvtps2dq, 0, IX86_BUILTIN_CVTPS2DQ, 0, 0 },
15379169705Skan  { MASK_SSE2, CODE_FOR_sse2_cvtps2pd, 0, IX86_BUILTIN_CVTPS2PD, 0, 0 },
15380169705Skan  { MASK_SSE2, CODE_FOR_sse2_cvttps2dq, 0, IX86_BUILTIN_CVTTPS2DQ, 0, 0 },
15381117408Skan
15382132743Skan  /* SSE3 */
15383169705Skan  { MASK_SSE3, CODE_FOR_sse3_movshdup, 0, IX86_BUILTIN_MOVSHDUP, 0, 0 },
15384169705Skan  { MASK_SSE3, CODE_FOR_sse3_movsldup, 0, IX86_BUILTIN_MOVSLDUP, 0, 0 },
15385219639Smm
15386219639Smm  /* SSSE3 */
15387219639Smm  { MASK_SSSE3, CODE_FOR_absv16qi2, "__builtin_ia32_pabsb128", IX86_BUILTIN_PABSB128, 0, 0 },
15388219639Smm  { MASK_SSSE3, CODE_FOR_absv8qi2, "__builtin_ia32_pabsb", IX86_BUILTIN_PABSB, 0, 0 },
15389219639Smm  { MASK_SSSE3, CODE_FOR_absv8hi2, "__builtin_ia32_pabsw128", IX86_BUILTIN_PABSW128, 0, 0 },
15390219639Smm  { MASK_SSSE3, CODE_FOR_absv4hi2, "__builtin_ia32_pabsw", IX86_BUILTIN_PABSW, 0, 0 },
15391219639Smm  { MASK_SSSE3, CODE_FOR_absv4si2, "__builtin_ia32_pabsd128", IX86_BUILTIN_PABSD128, 0, 0 },
15392219639Smm  { MASK_SSSE3, CODE_FOR_absv2si2, "__builtin_ia32_pabsd", IX86_BUILTIN_PABSD, 0, 0 },
1539390284Sobrien};
1539490284Sobrien
15395169705Skanstatic void
15396132743Skanix86_init_builtins (void)
1539790284Sobrien{
1539890284Sobrien  if (TARGET_MMX)
1539990284Sobrien    ix86_init_mmx_sse_builtins ();
1540090284Sobrien}
1540190284Sobrien
1540290284Sobrien/* Set up all the MMX/SSE builtins.  This is not called if TARGET_MMX
1540390284Sobrien   is zero.  Otherwise, if TARGET_SSE is not set, only expand the MMX
1540490284Sobrien   builtins.  */
1540590284Sobrienstatic void
15406132743Skanix86_init_mmx_sse_builtins (void)
1540790284Sobrien{
1540890284Sobrien  const struct builtin_description * d;
1540990284Sobrien  size_t i;
1541090284Sobrien
15411259005Spfg  tree V16QI_type_node = build_vector_type_for_mode (char_type_node, V16QImode);
15412169705Skan  tree V2SI_type_node = build_vector_type_for_mode (intSI_type_node, V2SImode);
15413169705Skan  tree V2SF_type_node = build_vector_type_for_mode (float_type_node, V2SFmode);
15414169705Skan  tree V2DI_type_node
15415169705Skan    = build_vector_type_for_mode (long_long_integer_type_node, V2DImode);
15416169705Skan  tree V2DF_type_node = build_vector_type_for_mode (double_type_node, V2DFmode);
15417169705Skan  tree V4SF_type_node = build_vector_type_for_mode (float_type_node, V4SFmode);
15418169705Skan  tree V4SI_type_node = build_vector_type_for_mode (intSI_type_node, V4SImode);
15419169705Skan  tree V4HI_type_node = build_vector_type_for_mode (intHI_type_node, V4HImode);
15420259005Spfg  tree V8QI_type_node = build_vector_type_for_mode (char_type_node, V8QImode);
15421169705Skan  tree V8HI_type_node = build_vector_type_for_mode (intHI_type_node, V8HImode);
15422169705Skan
1542390284Sobrien  tree pchar_type_node = build_pointer_type (char_type_node);
15424117408Skan  tree pcchar_type_node = build_pointer_type (
15425117408Skan			     build_type_variant (char_type_node, 1, 0));
1542690284Sobrien  tree pfloat_type_node = build_pointer_type (float_type_node);
15427117408Skan  tree pcfloat_type_node = build_pointer_type (
15428117408Skan			     build_type_variant (float_type_node, 1, 0));
1542990284Sobrien  tree pv2si_type_node = build_pointer_type (V2SI_type_node);
15430117408Skan  tree pv2di_type_node = build_pointer_type (V2DI_type_node);
1543190284Sobrien  tree pdi_type_node = build_pointer_type (long_long_unsigned_type_node);
1543290284Sobrien
1543390284Sobrien  /* Comparisons.  */
1543490284Sobrien  tree int_ftype_v4sf_v4sf
15435117408Skan    = build_function_type_list (integer_type_node,
15436117408Skan				V4SF_type_node, V4SF_type_node, NULL_TREE);
1543790284Sobrien  tree v4si_ftype_v4sf_v4sf
15438117408Skan    = build_function_type_list (V4SI_type_node,
15439117408Skan				V4SF_type_node, V4SF_type_node, NULL_TREE);
1544090284Sobrien  /* MMX/SSE/integer conversions.  */
1544190284Sobrien  tree int_ftype_v4sf
15442117408Skan    = build_function_type_list (integer_type_node,
15443117408Skan				V4SF_type_node, NULL_TREE);
15444117408Skan  tree int64_ftype_v4sf
15445117408Skan    = build_function_type_list (long_long_integer_type_node,
15446117408Skan				V4SF_type_node, NULL_TREE);
1544790284Sobrien  tree int_ftype_v8qi
15448117408Skan    = build_function_type_list (integer_type_node, V8QI_type_node, NULL_TREE);
1544990284Sobrien  tree v4sf_ftype_v4sf_int
15450117408Skan    = build_function_type_list (V4SF_type_node,
15451117408Skan				V4SF_type_node, integer_type_node, NULL_TREE);
15452117408Skan  tree v4sf_ftype_v4sf_int64
15453117408Skan    = build_function_type_list (V4SF_type_node,
15454117408Skan				V4SF_type_node, long_long_integer_type_node,
15455117408Skan				NULL_TREE);
1545690284Sobrien  tree v4sf_ftype_v4sf_v2si
15457117408Skan    = build_function_type_list (V4SF_type_node,
15458117408Skan				V4SF_type_node, V2SI_type_node, NULL_TREE);
15459169705Skan
1546090284Sobrien  /* Miscellaneous.  */
1546190284Sobrien  tree v8qi_ftype_v4hi_v4hi
15462117408Skan    = build_function_type_list (V8QI_type_node,
15463117408Skan				V4HI_type_node, V4HI_type_node, NULL_TREE);
1546490284Sobrien  tree v4hi_ftype_v2si_v2si
15465117408Skan    = build_function_type_list (V4HI_type_node,
15466117408Skan				V2SI_type_node, V2SI_type_node, NULL_TREE);
1546790284Sobrien  tree v4sf_ftype_v4sf_v4sf_int
15468117408Skan    = build_function_type_list (V4SF_type_node,
15469117408Skan				V4SF_type_node, V4SF_type_node,
15470117408Skan				integer_type_node, NULL_TREE);
1547190284Sobrien  tree v2si_ftype_v4hi_v4hi
15472117408Skan    = build_function_type_list (V2SI_type_node,
15473117408Skan				V4HI_type_node, V4HI_type_node, NULL_TREE);
1547490284Sobrien  tree v4hi_ftype_v4hi_int
15475117408Skan    = build_function_type_list (V4HI_type_node,
15476117408Skan				V4HI_type_node, integer_type_node, NULL_TREE);
1547790284Sobrien  tree v4hi_ftype_v4hi_di
15478117408Skan    = build_function_type_list (V4HI_type_node,
15479117408Skan				V4HI_type_node, long_long_unsigned_type_node,
15480117408Skan				NULL_TREE);
1548190284Sobrien  tree v2si_ftype_v2si_di
15482117408Skan    = build_function_type_list (V2SI_type_node,
15483117408Skan				V2SI_type_node, long_long_unsigned_type_node,
15484117408Skan				NULL_TREE);
1548590284Sobrien  tree void_ftype_void
15486117408Skan    = build_function_type (void_type_node, void_list_node);
1548790284Sobrien  tree void_ftype_unsigned
15488117408Skan    = build_function_type_list (void_type_node, unsigned_type_node, NULL_TREE);
15489122194Skan  tree void_ftype_unsigned_unsigned
15490122194Skan    = build_function_type_list (void_type_node, unsigned_type_node,
15491122194Skan				unsigned_type_node, NULL_TREE);
15492122194Skan  tree void_ftype_pcvoid_unsigned_unsigned
15493122194Skan    = build_function_type_list (void_type_node, const_ptr_type_node,
15494122194Skan				unsigned_type_node, unsigned_type_node,
15495122194Skan				NULL_TREE);
1549690284Sobrien  tree unsigned_ftype_void
15497117408Skan    = build_function_type (unsigned_type_node, void_list_node);
1549890284Sobrien  tree v2si_ftype_v4sf
15499117408Skan    = build_function_type_list (V2SI_type_node, V4SF_type_node, NULL_TREE);
1550090284Sobrien  /* Loads/stores.  */
1550190284Sobrien  tree void_ftype_v8qi_v8qi_pchar
15502117408Skan    = build_function_type_list (void_type_node,
15503117408Skan				V8QI_type_node, V8QI_type_node,
15504117408Skan				pchar_type_node, NULL_TREE);
15505117408Skan  tree v4sf_ftype_pcfloat
15506117408Skan    = build_function_type_list (V4SF_type_node, pcfloat_type_node, NULL_TREE);
1550790284Sobrien  /* @@@ the type is bogus */
1550890284Sobrien  tree v4sf_ftype_v4sf_pv2si
15509117408Skan    = build_function_type_list (V4SF_type_node,
15510117408Skan				V4SF_type_node, pv2si_type_node, NULL_TREE);
1551190284Sobrien  tree void_ftype_pv2si_v4sf
15512117408Skan    = build_function_type_list (void_type_node,
15513117408Skan				pv2si_type_node, V4SF_type_node, NULL_TREE);
1551490284Sobrien  tree void_ftype_pfloat_v4sf
15515117408Skan    = build_function_type_list (void_type_node,
15516117408Skan				pfloat_type_node, V4SF_type_node, NULL_TREE);
1551790284Sobrien  tree void_ftype_pdi_di
15518117408Skan    = build_function_type_list (void_type_node,
15519117408Skan				pdi_type_node, long_long_unsigned_type_node,
15520117408Skan				NULL_TREE);
15521117408Skan  tree void_ftype_pv2di_v2di
15522117408Skan    = build_function_type_list (void_type_node,
15523117408Skan				pv2di_type_node, V2DI_type_node, NULL_TREE);
1552490284Sobrien  /* Normal vector unops.  */
1552590284Sobrien  tree v4sf_ftype_v4sf
15526117408Skan    = build_function_type_list (V4SF_type_node, V4SF_type_node, NULL_TREE);
15527219639Smm  tree v16qi_ftype_v16qi
15528219639Smm    = build_function_type_list (V16QI_type_node, V16QI_type_node, NULL_TREE);
15529219639Smm  tree v8hi_ftype_v8hi
15530219639Smm    = build_function_type_list (V8HI_type_node, V8HI_type_node, NULL_TREE);
15531219639Smm  tree v4si_ftype_v4si
15532219639Smm    = build_function_type_list (V4SI_type_node, V4SI_type_node, NULL_TREE);
15533219639Smm  tree v8qi_ftype_v8qi
15534219639Smm    = build_function_type_list (V8QI_type_node, V8QI_type_node, NULL_TREE);
15535219639Smm  tree v4hi_ftype_v4hi
15536219639Smm    = build_function_type_list (V4HI_type_node, V4HI_type_node, NULL_TREE);
1553790284Sobrien
1553890284Sobrien  /* Normal vector binops.  */
1553990284Sobrien  tree v4sf_ftype_v4sf_v4sf
15540117408Skan    = build_function_type_list (V4SF_type_node,
15541117408Skan				V4SF_type_node, V4SF_type_node, NULL_TREE);
1554290284Sobrien  tree v8qi_ftype_v8qi_v8qi
15543117408Skan    = build_function_type_list (V8QI_type_node,
15544117408Skan				V8QI_type_node, V8QI_type_node, NULL_TREE);
1554590284Sobrien  tree v4hi_ftype_v4hi_v4hi
15546117408Skan    = build_function_type_list (V4HI_type_node,
15547117408Skan				V4HI_type_node, V4HI_type_node, NULL_TREE);
1554890284Sobrien  tree v2si_ftype_v2si_v2si
15549117408Skan    = build_function_type_list (V2SI_type_node,
15550117408Skan				V2SI_type_node, V2SI_type_node, NULL_TREE);
1555190284Sobrien  tree di_ftype_di_di
15552117408Skan    = build_function_type_list (long_long_unsigned_type_node,
15553117408Skan				long_long_unsigned_type_node,
15554117408Skan				long_long_unsigned_type_node, NULL_TREE);
1555590284Sobrien
15556219639Smm  tree di_ftype_di_di_int
15557219639Smm    = build_function_type_list (long_long_unsigned_type_node,
15558219639Smm				long_long_unsigned_type_node,
15559219639Smm				long_long_unsigned_type_node,
15560219639Smm				integer_type_node, NULL_TREE);
15561219639Smm
1556290284Sobrien  tree v2si_ftype_v2sf
15563117408Skan    = build_function_type_list (V2SI_type_node, V2SF_type_node, NULL_TREE);
1556490284Sobrien  tree v2sf_ftype_v2si
15565117408Skan    = build_function_type_list (V2SF_type_node, V2SI_type_node, NULL_TREE);
1556690284Sobrien  tree v2si_ftype_v2si
15567117408Skan    = build_function_type_list (V2SI_type_node, V2SI_type_node, NULL_TREE);
1556890284Sobrien  tree v2sf_ftype_v2sf
15569117408Skan    = build_function_type_list (V2SF_type_node, V2SF_type_node, NULL_TREE);
1557090284Sobrien  tree v2sf_ftype_v2sf_v2sf
15571117408Skan    = build_function_type_list (V2SF_type_node,
15572117408Skan				V2SF_type_node, V2SF_type_node, NULL_TREE);
1557390284Sobrien  tree v2si_ftype_v2sf_v2sf
15574117408Skan    = build_function_type_list (V2SI_type_node,
15575117408Skan				V2SF_type_node, V2SF_type_node, NULL_TREE);
15576117408Skan  tree pint_type_node    = build_pointer_type (integer_type_node);
15577117408Skan  tree pdouble_type_node = build_pointer_type (double_type_node);
15578117408Skan  tree pcdouble_type_node = build_pointer_type (
15579117408Skan				build_type_variant (double_type_node, 1, 0));
15580117408Skan  tree int_ftype_v2df_v2df
15581117408Skan    = build_function_type_list (integer_type_node,
15582117408Skan				V2DF_type_node, V2DF_type_node, NULL_TREE);
1558390284Sobrien
15584117408Skan  tree void_ftype_pcvoid
15585117408Skan    = build_function_type_list (void_type_node, const_ptr_type_node, NULL_TREE);
15586117408Skan  tree v4sf_ftype_v4si
15587117408Skan    = build_function_type_list (V4SF_type_node, V4SI_type_node, NULL_TREE);
15588117408Skan  tree v4si_ftype_v4sf
15589117408Skan    = build_function_type_list (V4SI_type_node, V4SF_type_node, NULL_TREE);
15590117408Skan  tree v2df_ftype_v4si
15591117408Skan    = build_function_type_list (V2DF_type_node, V4SI_type_node, NULL_TREE);
15592117408Skan  tree v4si_ftype_v2df
15593117408Skan    = build_function_type_list (V4SI_type_node, V2DF_type_node, NULL_TREE);
15594117408Skan  tree v2si_ftype_v2df
15595117408Skan    = build_function_type_list (V2SI_type_node, V2DF_type_node, NULL_TREE);
15596117408Skan  tree v4sf_ftype_v2df
15597117408Skan    = build_function_type_list (V4SF_type_node, V2DF_type_node, NULL_TREE);
15598117408Skan  tree v2df_ftype_v2si
15599117408Skan    = build_function_type_list (V2DF_type_node, V2SI_type_node, NULL_TREE);
15600117408Skan  tree v2df_ftype_v4sf
15601117408Skan    = build_function_type_list (V2DF_type_node, V4SF_type_node, NULL_TREE);
15602117408Skan  tree int_ftype_v2df
15603117408Skan    = build_function_type_list (integer_type_node, V2DF_type_node, NULL_TREE);
15604117408Skan  tree int64_ftype_v2df
15605117408Skan    = build_function_type_list (long_long_integer_type_node,
15606132743Skan				V2DF_type_node, NULL_TREE);
15607117408Skan  tree v2df_ftype_v2df_int
15608117408Skan    = build_function_type_list (V2DF_type_node,
15609117408Skan				V2DF_type_node, integer_type_node, NULL_TREE);
15610117408Skan  tree v2df_ftype_v2df_int64
15611117408Skan    = build_function_type_list (V2DF_type_node,
15612117408Skan				V2DF_type_node, long_long_integer_type_node,
15613117408Skan				NULL_TREE);
15614117408Skan  tree v4sf_ftype_v4sf_v2df
15615117408Skan    = build_function_type_list (V4SF_type_node,
15616117408Skan				V4SF_type_node, V2DF_type_node, NULL_TREE);
15617117408Skan  tree v2df_ftype_v2df_v4sf
15618117408Skan    = build_function_type_list (V2DF_type_node,
15619117408Skan				V2DF_type_node, V4SF_type_node, NULL_TREE);
15620117408Skan  tree v2df_ftype_v2df_v2df_int
15621117408Skan    = build_function_type_list (V2DF_type_node,
15622117408Skan				V2DF_type_node, V2DF_type_node,
15623117408Skan				integer_type_node,
15624117408Skan				NULL_TREE);
15625169705Skan  tree v2df_ftype_v2df_pcdouble
15626117408Skan    = build_function_type_list (V2DF_type_node,
15627169705Skan				V2DF_type_node, pcdouble_type_node, NULL_TREE);
15628117408Skan  tree void_ftype_pdouble_v2df
15629117408Skan    = build_function_type_list (void_type_node,
15630117408Skan				pdouble_type_node, V2DF_type_node, NULL_TREE);
15631117408Skan  tree void_ftype_pint_int
15632117408Skan    = build_function_type_list (void_type_node,
15633117408Skan				pint_type_node, integer_type_node, NULL_TREE);
15634117408Skan  tree void_ftype_v16qi_v16qi_pchar
15635117408Skan    = build_function_type_list (void_type_node,
15636117408Skan				V16QI_type_node, V16QI_type_node,
15637117408Skan				pchar_type_node, NULL_TREE);
15638117408Skan  tree v2df_ftype_pcdouble
15639117408Skan    = build_function_type_list (V2DF_type_node, pcdouble_type_node, NULL_TREE);
15640117408Skan  tree v2df_ftype_v2df_v2df
15641117408Skan    = build_function_type_list (V2DF_type_node,
15642117408Skan				V2DF_type_node, V2DF_type_node, NULL_TREE);
15643117408Skan  tree v16qi_ftype_v16qi_v16qi
15644117408Skan    = build_function_type_list (V16QI_type_node,
15645117408Skan				V16QI_type_node, V16QI_type_node, NULL_TREE);
15646117408Skan  tree v8hi_ftype_v8hi_v8hi
15647117408Skan    = build_function_type_list (V8HI_type_node,
15648117408Skan				V8HI_type_node, V8HI_type_node, NULL_TREE);
15649117408Skan  tree v4si_ftype_v4si_v4si
15650117408Skan    = build_function_type_list (V4SI_type_node,
15651117408Skan				V4SI_type_node, V4SI_type_node, NULL_TREE);
15652117408Skan  tree v2di_ftype_v2di_v2di
15653117408Skan    = build_function_type_list (V2DI_type_node,
15654117408Skan				V2DI_type_node, V2DI_type_node, NULL_TREE);
15655117408Skan  tree v2di_ftype_v2df_v2df
15656117408Skan    = build_function_type_list (V2DI_type_node,
15657117408Skan				V2DF_type_node, V2DF_type_node, NULL_TREE);
15658117408Skan  tree v2df_ftype_v2df
15659117408Skan    = build_function_type_list (V2DF_type_node, V2DF_type_node, NULL_TREE);
15660117408Skan  tree v2di_ftype_v2di_int
15661117408Skan    = build_function_type_list (V2DI_type_node,
15662117408Skan				V2DI_type_node, integer_type_node, NULL_TREE);
15663219639Smm  tree v2di_ftype_v2di_v2di_int
15664219639Smm    = build_function_type_list (V2DI_type_node, V2DI_type_node,
15665219639Smm				V2DI_type_node, integer_type_node, NULL_TREE);
15666117408Skan  tree v4si_ftype_v4si_int
15667117408Skan    = build_function_type_list (V4SI_type_node,
15668117408Skan				V4SI_type_node, integer_type_node, NULL_TREE);
15669117408Skan  tree v8hi_ftype_v8hi_int
15670117408Skan    = build_function_type_list (V8HI_type_node,
15671117408Skan				V8HI_type_node, integer_type_node, NULL_TREE);
15672117408Skan  tree v4si_ftype_v8hi_v8hi
15673117408Skan    = build_function_type_list (V4SI_type_node,
15674117408Skan				V8HI_type_node, V8HI_type_node, NULL_TREE);
15675117408Skan  tree di_ftype_v8qi_v8qi
15676117408Skan    = build_function_type_list (long_long_unsigned_type_node,
15677117408Skan				V8QI_type_node, V8QI_type_node, NULL_TREE);
15678169705Skan  tree di_ftype_v2si_v2si
15679169705Skan    = build_function_type_list (long_long_unsigned_type_node,
15680169705Skan				V2SI_type_node, V2SI_type_node, NULL_TREE);
15681117408Skan  tree v2di_ftype_v16qi_v16qi
15682117408Skan    = build_function_type_list (V2DI_type_node,
15683117408Skan				V16QI_type_node, V16QI_type_node, NULL_TREE);
15684169705Skan  tree v2di_ftype_v4si_v4si
15685169705Skan    = build_function_type_list (V2DI_type_node,
15686169705Skan				V4SI_type_node, V4SI_type_node, NULL_TREE);
15687117408Skan  tree int_ftype_v16qi
15688117408Skan    = build_function_type_list (integer_type_node, V16QI_type_node, NULL_TREE);
15689117408Skan  tree v16qi_ftype_pcchar
15690117408Skan    = build_function_type_list (V16QI_type_node, pcchar_type_node, NULL_TREE);
15691117408Skan  tree void_ftype_pchar_v16qi
15692117408Skan    = build_function_type_list (void_type_node,
15693117408Skan			        pchar_type_node, V16QI_type_node, NULL_TREE);
15694117408Skan
15695251212Spfg  tree v2di_ftype_v2di_unsigned_unsigned
15696251212Spfg    = build_function_type_list (V2DI_type_node, V2DI_type_node,
15697251212Spfg                                unsigned_type_node, unsigned_type_node,
15698251212Spfg                                NULL_TREE);
15699251212Spfg  tree v2di_ftype_v2di_v2di_unsigned_unsigned
15700251212Spfg    = build_function_type_list (V2DI_type_node, V2DI_type_node, V2DI_type_node,
15701251212Spfg                                unsigned_type_node, unsigned_type_node,
15702251212Spfg                                NULL_TREE);
15703251212Spfg  tree v2di_ftype_v2di_v16qi
15704251212Spfg    = build_function_type_list (V2DI_type_node, V2DI_type_node, V16QI_type_node,
15705251212Spfg                                NULL_TREE);
15706251212Spfg
15707132743Skan  tree float80_type;
15708132743Skan  tree float128_type;
15709169705Skan  tree ftype;
15710132743Skan
15711132743Skan  /* The __float80 type.  */
15712132743Skan  if (TYPE_MODE (long_double_type_node) == XFmode)
15713132743Skan    (*lang_hooks.types.register_builtin_type) (long_double_type_node,
15714132743Skan					       "__float80");
15715132743Skan  else
15716132743Skan    {
15717132743Skan      /* The __float80 type.  */
15718132743Skan      float80_type = make_node (REAL_TYPE);
15719169705Skan      TYPE_PRECISION (float80_type) = 80;
15720132743Skan      layout_type (float80_type);
15721132743Skan      (*lang_hooks.types.register_builtin_type) (float80_type, "__float80");
15722132743Skan    }
15723132743Skan
15724169705Skan  if (TARGET_64BIT)
15725169705Skan    {
15726169705Skan      float128_type = make_node (REAL_TYPE);
15727169705Skan      TYPE_PRECISION (float128_type) = 128;
15728169705Skan      layout_type (float128_type);
15729169705Skan      (*lang_hooks.types.register_builtin_type) (float128_type, "__float128");
15730169705Skan    }
15731132743Skan
1573290284Sobrien  /* Add all builtins that are more or less simple operations on two
1573390284Sobrien     operands.  */
15734117408Skan  for (i = 0, d = bdesc_2arg; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
1573590284Sobrien    {
1573690284Sobrien      /* Use one of the operands; the target can have a different mode for
1573790284Sobrien	 mask-generating compares.  */
1573890284Sobrien      enum machine_mode mode;
1573990284Sobrien      tree type;
1574090284Sobrien
1574190284Sobrien      if (d->name == 0)
1574290284Sobrien	continue;
1574390284Sobrien      mode = insn_data[d->icode].operand[1].mode;
1574490284Sobrien
1574590284Sobrien      switch (mode)
1574690284Sobrien	{
15747117408Skan	case V16QImode:
15748117408Skan	  type = v16qi_ftype_v16qi_v16qi;
15749117408Skan	  break;
15750117408Skan	case V8HImode:
15751117408Skan	  type = v8hi_ftype_v8hi_v8hi;
15752117408Skan	  break;
15753117408Skan	case V4SImode:
15754117408Skan	  type = v4si_ftype_v4si_v4si;
15755117408Skan	  break;
15756117408Skan	case V2DImode:
15757117408Skan	  type = v2di_ftype_v2di_v2di;
15758117408Skan	  break;
15759117408Skan	case V2DFmode:
15760117408Skan	  type = v2df_ftype_v2df_v2df;
15761117408Skan	  break;
1576290284Sobrien	case V4SFmode:
1576390284Sobrien	  type = v4sf_ftype_v4sf_v4sf;
1576490284Sobrien	  break;
1576590284Sobrien	case V8QImode:
1576690284Sobrien	  type = v8qi_ftype_v8qi_v8qi;
1576790284Sobrien	  break;
1576890284Sobrien	case V4HImode:
1576990284Sobrien	  type = v4hi_ftype_v4hi_v4hi;
1577090284Sobrien	  break;
1577190284Sobrien	case V2SImode:
1577290284Sobrien	  type = v2si_ftype_v2si_v2si;
1577390284Sobrien	  break;
1577490284Sobrien	case DImode:
1577590284Sobrien	  type = di_ftype_di_di;
1577690284Sobrien	  break;
1577790284Sobrien
1577890284Sobrien	default:
15779169705Skan	  gcc_unreachable ();
1578090284Sobrien	}
1578190284Sobrien
1578290284Sobrien      /* Override for comparisons.  */
15783169705Skan      if (d->icode == CODE_FOR_sse_maskcmpv4sf3
15784169705Skan	  || d->icode == CODE_FOR_sse_vmmaskcmpv4sf3)
1578590284Sobrien	type = v4si_ftype_v4sf_v4sf;
1578690284Sobrien
15787169705Skan      if (d->icode == CODE_FOR_sse2_maskcmpv2df3
15788169705Skan	  || d->icode == CODE_FOR_sse2_vmmaskcmpv2df3)
15789117408Skan	type = v2di_ftype_v2df_v2df;
15790117408Skan
1579190284Sobrien      def_builtin (d->mask, d->name, type, d->code);
1579290284Sobrien    }
1579390284Sobrien
15794219639Smm  /* Add all builtins that are more or less simple operations on 1 operand.  */
15795219639Smm  for (i = 0, d = bdesc_1arg; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
15796219639Smm    {
15797219639Smm      enum machine_mode mode;
15798219639Smm      tree type;
15799219639Smm
15800219639Smm      if (d->name == 0)
15801219639Smm	continue;
15802219639Smm      mode = insn_data[d->icode].operand[1].mode;
15803219639Smm
15804219639Smm      switch (mode)
15805219639Smm	{
15806219639Smm	case V16QImode:
15807219639Smm	  type = v16qi_ftype_v16qi;
15808219639Smm	  break;
15809219639Smm	case V8HImode:
15810219639Smm	  type = v8hi_ftype_v8hi;
15811219639Smm	  break;
15812219639Smm	case V4SImode:
15813219639Smm	  type = v4si_ftype_v4si;
15814219639Smm	  break;
15815219639Smm	case V2DFmode:
15816219639Smm	  type = v2df_ftype_v2df;
15817219639Smm	  break;
15818219639Smm	case V4SFmode:
15819219639Smm	  type = v4sf_ftype_v4sf;
15820219639Smm	  break;
15821219639Smm	case V8QImode:
15822219639Smm	  type = v8qi_ftype_v8qi;
15823219639Smm	  break;
15824219639Smm	case V4HImode:
15825219639Smm	  type = v4hi_ftype_v4hi;
15826219639Smm	  break;
15827219639Smm	case V2SImode:
15828219639Smm	  type = v2si_ftype_v2si;
15829219639Smm	  break;
15830219639Smm
15831219639Smm	default:
15832219639Smm	  abort ();
15833219639Smm	}
15834219639Smm
15835219639Smm      def_builtin (d->mask, d->name, type, d->code);
15836219639Smm    }
15837219639Smm
1583890284Sobrien  /* Add the remaining MMX insns with somewhat more complicated types.  */
1583990284Sobrien  def_builtin (MASK_MMX, "__builtin_ia32_emms", void_ftype_void, IX86_BUILTIN_EMMS);
1584090284Sobrien  def_builtin (MASK_MMX, "__builtin_ia32_psllw", v4hi_ftype_v4hi_di, IX86_BUILTIN_PSLLW);
1584190284Sobrien  def_builtin (MASK_MMX, "__builtin_ia32_pslld", v2si_ftype_v2si_di, IX86_BUILTIN_PSLLD);
1584290284Sobrien  def_builtin (MASK_MMX, "__builtin_ia32_psllq", di_ftype_di_di, IX86_BUILTIN_PSLLQ);
1584390284Sobrien
1584490284Sobrien  def_builtin (MASK_MMX, "__builtin_ia32_psrlw", v4hi_ftype_v4hi_di, IX86_BUILTIN_PSRLW);
1584590284Sobrien  def_builtin (MASK_MMX, "__builtin_ia32_psrld", v2si_ftype_v2si_di, IX86_BUILTIN_PSRLD);
1584690284Sobrien  def_builtin (MASK_MMX, "__builtin_ia32_psrlq", di_ftype_di_di, IX86_BUILTIN_PSRLQ);
1584790284Sobrien
1584890284Sobrien  def_builtin (MASK_MMX, "__builtin_ia32_psraw", v4hi_ftype_v4hi_di, IX86_BUILTIN_PSRAW);
1584990284Sobrien  def_builtin (MASK_MMX, "__builtin_ia32_psrad", v2si_ftype_v2si_di, IX86_BUILTIN_PSRAD);
1585090284Sobrien
15851169705Skan  def_builtin (MASK_SSE | MASK_3DNOW_A, "__builtin_ia32_pshufw", v4hi_ftype_v4hi_int, IX86_BUILTIN_PSHUFW);
1585290284Sobrien  def_builtin (MASK_MMX, "__builtin_ia32_pmaddwd", v2si_ftype_v4hi_v4hi, IX86_BUILTIN_PMADDWD);
1585390284Sobrien
1585490284Sobrien  /* comi/ucomi insns.  */
15855117408Skan  for (i = 0, d = bdesc_comi; i < ARRAY_SIZE (bdesc_comi); i++, d++)
15856117408Skan    if (d->mask == MASK_SSE2)
15857117408Skan      def_builtin (d->mask, d->name, int_ftype_v2df_v2df, d->code);
15858117408Skan    else
15859117408Skan      def_builtin (d->mask, d->name, int_ftype_v4sf_v4sf, d->code);
1586090284Sobrien
1586190284Sobrien  def_builtin (MASK_MMX, "__builtin_ia32_packsswb", v8qi_ftype_v4hi_v4hi, IX86_BUILTIN_PACKSSWB);
1586290284Sobrien  def_builtin (MASK_MMX, "__builtin_ia32_packssdw", v4hi_ftype_v2si_v2si, IX86_BUILTIN_PACKSSDW);
1586390284Sobrien  def_builtin (MASK_MMX, "__builtin_ia32_packuswb", v8qi_ftype_v4hi_v4hi, IX86_BUILTIN_PACKUSWB);
1586490284Sobrien
15865122194Skan  def_builtin (MASK_SSE, "__builtin_ia32_ldmxcsr", void_ftype_unsigned, IX86_BUILTIN_LDMXCSR);
15866122194Skan  def_builtin (MASK_SSE, "__builtin_ia32_stmxcsr", unsigned_ftype_void, IX86_BUILTIN_STMXCSR);
15867122194Skan  def_builtin (MASK_SSE, "__builtin_ia32_cvtpi2ps", v4sf_ftype_v4sf_v2si, IX86_BUILTIN_CVTPI2PS);
15868122194Skan  def_builtin (MASK_SSE, "__builtin_ia32_cvtps2pi", v2si_ftype_v4sf, IX86_BUILTIN_CVTPS2PI);
15869122194Skan  def_builtin (MASK_SSE, "__builtin_ia32_cvtsi2ss", v4sf_ftype_v4sf_int, IX86_BUILTIN_CVTSI2SS);
15870122194Skan  def_builtin (MASK_SSE | MASK_64BIT, "__builtin_ia32_cvtsi642ss", v4sf_ftype_v4sf_int64, IX86_BUILTIN_CVTSI642SS);
15871122194Skan  def_builtin (MASK_SSE, "__builtin_ia32_cvtss2si", int_ftype_v4sf, IX86_BUILTIN_CVTSS2SI);
15872122194Skan  def_builtin (MASK_SSE | MASK_64BIT, "__builtin_ia32_cvtss2si64", int64_ftype_v4sf, IX86_BUILTIN_CVTSS2SI64);
15873122194Skan  def_builtin (MASK_SSE, "__builtin_ia32_cvttps2pi", v2si_ftype_v4sf, IX86_BUILTIN_CVTTPS2PI);
15874122194Skan  def_builtin (MASK_SSE, "__builtin_ia32_cvttss2si", int_ftype_v4sf, IX86_BUILTIN_CVTTSS2SI);
15875122194Skan  def_builtin (MASK_SSE | MASK_64BIT, "__builtin_ia32_cvttss2si64", int64_ftype_v4sf, IX86_BUILTIN_CVTTSS2SI64);
1587690284Sobrien
15877122194Skan  def_builtin (MASK_SSE | MASK_3DNOW_A, "__builtin_ia32_maskmovq", void_ftype_v8qi_v8qi_pchar, IX86_BUILTIN_MASKMOVQ);
1587890284Sobrien
15879122194Skan  def_builtin (MASK_SSE, "__builtin_ia32_loadups", v4sf_ftype_pcfloat, IX86_BUILTIN_LOADUPS);
15880122194Skan  def_builtin (MASK_SSE, "__builtin_ia32_storeups", void_ftype_pfloat_v4sf, IX86_BUILTIN_STOREUPS);
1588190284Sobrien
15882122194Skan  def_builtin (MASK_SSE, "__builtin_ia32_loadhps", v4sf_ftype_v4sf_pv2si, IX86_BUILTIN_LOADHPS);
15883122194Skan  def_builtin (MASK_SSE, "__builtin_ia32_loadlps", v4sf_ftype_v4sf_pv2si, IX86_BUILTIN_LOADLPS);
15884122194Skan  def_builtin (MASK_SSE, "__builtin_ia32_storehps", void_ftype_pv2si_v4sf, IX86_BUILTIN_STOREHPS);
15885122194Skan  def_builtin (MASK_SSE, "__builtin_ia32_storelps", void_ftype_pv2si_v4sf, IX86_BUILTIN_STORELPS);
1588690284Sobrien
15887122194Skan  def_builtin (MASK_SSE, "__builtin_ia32_movmskps", int_ftype_v4sf, IX86_BUILTIN_MOVMSKPS);
15888122194Skan  def_builtin (MASK_SSE | MASK_3DNOW_A, "__builtin_ia32_pmovmskb", int_ftype_v8qi, IX86_BUILTIN_PMOVMSKB);
15889122194Skan  def_builtin (MASK_SSE, "__builtin_ia32_movntps", void_ftype_pfloat_v4sf, IX86_BUILTIN_MOVNTPS);
15890122194Skan  def_builtin (MASK_SSE | MASK_3DNOW_A, "__builtin_ia32_movntq", void_ftype_pdi_di, IX86_BUILTIN_MOVNTQ);
1589190284Sobrien
15892122194Skan  def_builtin (MASK_SSE | MASK_3DNOW_A, "__builtin_ia32_sfence", void_ftype_void, IX86_BUILTIN_SFENCE);
1589390284Sobrien
15894122194Skan  def_builtin (MASK_SSE | MASK_3DNOW_A, "__builtin_ia32_psadbw", di_ftype_v8qi_v8qi, IX86_BUILTIN_PSADBW);
1589590284Sobrien
15896122194Skan  def_builtin (MASK_SSE, "__builtin_ia32_rcpps", v4sf_ftype_v4sf, IX86_BUILTIN_RCPPS);
15897122194Skan  def_builtin (MASK_SSE, "__builtin_ia32_rcpss", v4sf_ftype_v4sf, IX86_BUILTIN_RCPSS);
15898122194Skan  def_builtin (MASK_SSE, "__builtin_ia32_rsqrtps", v4sf_ftype_v4sf, IX86_BUILTIN_RSQRTPS);
15899122194Skan  def_builtin (MASK_SSE, "__builtin_ia32_rsqrtss", v4sf_ftype_v4sf, IX86_BUILTIN_RSQRTSS);
15900122194Skan  def_builtin (MASK_SSE, "__builtin_ia32_sqrtps", v4sf_ftype_v4sf, IX86_BUILTIN_SQRTPS);
15901122194Skan  def_builtin (MASK_SSE, "__builtin_ia32_sqrtss", v4sf_ftype_v4sf, IX86_BUILTIN_SQRTSS);
1590290284Sobrien
15903122194Skan  def_builtin (MASK_SSE, "__builtin_ia32_shufps", v4sf_ftype_v4sf_v4sf_int, IX86_BUILTIN_SHUFPS);
1590490284Sobrien
1590590284Sobrien  /* Original 3DNow!  */
1590690284Sobrien  def_builtin (MASK_3DNOW, "__builtin_ia32_femms", void_ftype_void, IX86_BUILTIN_FEMMS);
1590790284Sobrien  def_builtin (MASK_3DNOW, "__builtin_ia32_pavgusb", v8qi_ftype_v8qi_v8qi, IX86_BUILTIN_PAVGUSB);
1590890284Sobrien  def_builtin (MASK_3DNOW, "__builtin_ia32_pf2id", v2si_ftype_v2sf, IX86_BUILTIN_PF2ID);
1590990284Sobrien  def_builtin (MASK_3DNOW, "__builtin_ia32_pfacc", v2sf_ftype_v2sf_v2sf, IX86_BUILTIN_PFACC);
1591090284Sobrien  def_builtin (MASK_3DNOW, "__builtin_ia32_pfadd", v2sf_ftype_v2sf_v2sf, IX86_BUILTIN_PFADD);
1591190284Sobrien  def_builtin (MASK_3DNOW, "__builtin_ia32_pfcmpeq", v2si_ftype_v2sf_v2sf, IX86_BUILTIN_PFCMPEQ);
1591290284Sobrien  def_builtin (MASK_3DNOW, "__builtin_ia32_pfcmpge", v2si_ftype_v2sf_v2sf, IX86_BUILTIN_PFCMPGE);
1591390284Sobrien  def_builtin (MASK_3DNOW, "__builtin_ia32_pfcmpgt", v2si_ftype_v2sf_v2sf, IX86_BUILTIN_PFCMPGT);
1591490284Sobrien  def_builtin (MASK_3DNOW, "__builtin_ia32_pfmax", v2sf_ftype_v2sf_v2sf, IX86_BUILTIN_PFMAX);
1591590284Sobrien  def_builtin (MASK_3DNOW, "__builtin_ia32_pfmin", v2sf_ftype_v2sf_v2sf, IX86_BUILTIN_PFMIN);
1591690284Sobrien  def_builtin (MASK_3DNOW, "__builtin_ia32_pfmul", v2sf_ftype_v2sf_v2sf, IX86_BUILTIN_PFMUL);
1591790284Sobrien  def_builtin (MASK_3DNOW, "__builtin_ia32_pfrcp", v2sf_ftype_v2sf, IX86_BUILTIN_PFRCP);
1591890284Sobrien  def_builtin (MASK_3DNOW, "__builtin_ia32_pfrcpit1", v2sf_ftype_v2sf_v2sf, IX86_BUILTIN_PFRCPIT1);
1591990284Sobrien  def_builtin (MASK_3DNOW, "__builtin_ia32_pfrcpit2", v2sf_ftype_v2sf_v2sf, IX86_BUILTIN_PFRCPIT2);
1592090284Sobrien  def_builtin (MASK_3DNOW, "__builtin_ia32_pfrsqrt", v2sf_ftype_v2sf, IX86_BUILTIN_PFRSQRT);
1592190284Sobrien  def_builtin (MASK_3DNOW, "__builtin_ia32_pfrsqit1", v2sf_ftype_v2sf_v2sf, IX86_BUILTIN_PFRSQIT1);
1592290284Sobrien  def_builtin (MASK_3DNOW, "__builtin_ia32_pfsub", v2sf_ftype_v2sf_v2sf, IX86_BUILTIN_PFSUB);
1592390284Sobrien  def_builtin (MASK_3DNOW, "__builtin_ia32_pfsubr", v2sf_ftype_v2sf_v2sf, IX86_BUILTIN_PFSUBR);
1592490284Sobrien  def_builtin (MASK_3DNOW, "__builtin_ia32_pi2fd", v2sf_ftype_v2si, IX86_BUILTIN_PI2FD);
1592590284Sobrien  def_builtin (MASK_3DNOW, "__builtin_ia32_pmulhrw", v4hi_ftype_v4hi_v4hi, IX86_BUILTIN_PMULHRW);
1592690284Sobrien
1592790284Sobrien  /* 3DNow! extension as used in the Athlon CPU.  */
1592890284Sobrien  def_builtin (MASK_3DNOW_A, "__builtin_ia32_pf2iw", v2si_ftype_v2sf, IX86_BUILTIN_PF2IW);
1592990284Sobrien  def_builtin (MASK_3DNOW_A, "__builtin_ia32_pfnacc", v2sf_ftype_v2sf_v2sf, IX86_BUILTIN_PFNACC);
1593090284Sobrien  def_builtin (MASK_3DNOW_A, "__builtin_ia32_pfpnacc", v2sf_ftype_v2sf_v2sf, IX86_BUILTIN_PFPNACC);
1593190284Sobrien  def_builtin (MASK_3DNOW_A, "__builtin_ia32_pi2fw", v2sf_ftype_v2si, IX86_BUILTIN_PI2FW);
1593290284Sobrien  def_builtin (MASK_3DNOW_A, "__builtin_ia32_pswapdsf", v2sf_ftype_v2sf, IX86_BUILTIN_PSWAPDSF);
1593390284Sobrien  def_builtin (MASK_3DNOW_A, "__builtin_ia32_pswapdsi", v2si_ftype_v2si, IX86_BUILTIN_PSWAPDSI);
1593490284Sobrien
15935117408Skan  /* SSE2 */
15936117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_maskmovdqu", void_ftype_v16qi_v16qi_pchar, IX86_BUILTIN_MASKMOVDQU);
15937117408Skan
15938117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_loadupd", v2df_ftype_pcdouble, IX86_BUILTIN_LOADUPD);
15939117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_storeupd", void_ftype_pdouble_v2df, IX86_BUILTIN_STOREUPD);
15940117408Skan
15941169705Skan  def_builtin (MASK_SSE2, "__builtin_ia32_loadhpd", v2df_ftype_v2df_pcdouble, IX86_BUILTIN_LOADHPD);
15942169705Skan  def_builtin (MASK_SSE2, "__builtin_ia32_loadlpd", v2df_ftype_v2df_pcdouble, IX86_BUILTIN_LOADLPD);
15943117408Skan
15944117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_movmskpd", int_ftype_v2df, IX86_BUILTIN_MOVMSKPD);
15945117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_pmovmskb128", int_ftype_v16qi, IX86_BUILTIN_PMOVMSKB128);
15946117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_movnti", void_ftype_pint_int, IX86_BUILTIN_MOVNTI);
15947117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_movntpd", void_ftype_pdouble_v2df, IX86_BUILTIN_MOVNTPD);
15948117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_movntdq", void_ftype_pv2di_v2di, IX86_BUILTIN_MOVNTDQ);
15949117408Skan
15950117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_pshufd", v4si_ftype_v4si_int, IX86_BUILTIN_PSHUFD);
15951117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_pshuflw", v8hi_ftype_v8hi_int, IX86_BUILTIN_PSHUFLW);
15952117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_pshufhw", v8hi_ftype_v8hi_int, IX86_BUILTIN_PSHUFHW);
15953117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_psadbw128", v2di_ftype_v16qi_v16qi, IX86_BUILTIN_PSADBW128);
15954117408Skan
15955117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_sqrtpd", v2df_ftype_v2df, IX86_BUILTIN_SQRTPD);
15956117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_sqrtsd", v2df_ftype_v2df, IX86_BUILTIN_SQRTSD);
15957117408Skan
15958117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_shufpd", v2df_ftype_v2df_v2df_int, IX86_BUILTIN_SHUFPD);
15959117408Skan
15960117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_cvtdq2pd", v2df_ftype_v4si, IX86_BUILTIN_CVTDQ2PD);
15961117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_cvtdq2ps", v4sf_ftype_v4si, IX86_BUILTIN_CVTDQ2PS);
15962117408Skan
15963117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_cvtpd2dq", v4si_ftype_v2df, IX86_BUILTIN_CVTPD2DQ);
15964117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_cvtpd2pi", v2si_ftype_v2df, IX86_BUILTIN_CVTPD2PI);
15965117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_cvtpd2ps", v4sf_ftype_v2df, IX86_BUILTIN_CVTPD2PS);
15966117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_cvttpd2dq", v4si_ftype_v2df, IX86_BUILTIN_CVTTPD2DQ);
15967117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_cvttpd2pi", v2si_ftype_v2df, IX86_BUILTIN_CVTTPD2PI);
15968117408Skan
15969117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_cvtpi2pd", v2df_ftype_v2si, IX86_BUILTIN_CVTPI2PD);
15970117408Skan
15971117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_cvtsd2si", int_ftype_v2df, IX86_BUILTIN_CVTSD2SI);
15972117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_cvttsd2si", int_ftype_v2df, IX86_BUILTIN_CVTTSD2SI);
15973122194Skan  def_builtin (MASK_SSE2 | MASK_64BIT, "__builtin_ia32_cvtsd2si64", int64_ftype_v2df, IX86_BUILTIN_CVTSD2SI64);
15974122194Skan  def_builtin (MASK_SSE2 | MASK_64BIT, "__builtin_ia32_cvttsd2si64", int64_ftype_v2df, IX86_BUILTIN_CVTTSD2SI64);
15975117408Skan
15976117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_cvtps2dq", v4si_ftype_v4sf, IX86_BUILTIN_CVTPS2DQ);
15977117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_cvtps2pd", v2df_ftype_v4sf, IX86_BUILTIN_CVTPS2PD);
15978117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_cvttps2dq", v4si_ftype_v4sf, IX86_BUILTIN_CVTTPS2DQ);
15979117408Skan
15980117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_cvtsi2sd", v2df_ftype_v2df_int, IX86_BUILTIN_CVTSI2SD);
15981122194Skan  def_builtin (MASK_SSE2 | MASK_64BIT, "__builtin_ia32_cvtsi642sd", v2df_ftype_v2df_int64, IX86_BUILTIN_CVTSI642SD);
15982117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_cvtsd2ss", v4sf_ftype_v4sf_v2df, IX86_BUILTIN_CVTSD2SS);
15983117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_cvtss2sd", v2df_ftype_v2df_v4sf, IX86_BUILTIN_CVTSS2SD);
15984117408Skan
15985117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_clflush", void_ftype_pcvoid, IX86_BUILTIN_CLFLUSH);
15986117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_lfence", void_ftype_void, IX86_BUILTIN_LFENCE);
15987117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_mfence", void_ftype_void, IX86_BUILTIN_MFENCE);
15988117408Skan
15989117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_loaddqu", v16qi_ftype_pcchar, IX86_BUILTIN_LOADDQU);
15990117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_storedqu", void_ftype_pchar_v16qi, IX86_BUILTIN_STOREDQU);
15991117408Skan
15992169705Skan  def_builtin (MASK_SSE2, "__builtin_ia32_pmuludq", di_ftype_v2si_v2si, IX86_BUILTIN_PMULUDQ);
15993169705Skan  def_builtin (MASK_SSE2, "__builtin_ia32_pmuludq128", v2di_ftype_v4si_v4si, IX86_BUILTIN_PMULUDQ128);
15994117408Skan
15995169705Skan  def_builtin (MASK_SSE2, "__builtin_ia32_psllw128", v8hi_ftype_v8hi_v8hi, IX86_BUILTIN_PSLLW128);
15996169705Skan  def_builtin (MASK_SSE2, "__builtin_ia32_pslld128", v4si_ftype_v4si_v4si, IX86_BUILTIN_PSLLD128);
15997117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_psllq128", v2di_ftype_v2di_v2di, IX86_BUILTIN_PSLLQ128);
15998117408Skan
15999169705Skan  def_builtin (MASK_SSE2, "__builtin_ia32_psrlw128", v8hi_ftype_v8hi_v8hi, IX86_BUILTIN_PSRLW128);
16000169705Skan  def_builtin (MASK_SSE2, "__builtin_ia32_psrld128", v4si_ftype_v4si_v4si, IX86_BUILTIN_PSRLD128);
16001117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_psrlq128", v2di_ftype_v2di_v2di, IX86_BUILTIN_PSRLQ128);
16002117408Skan
16003169705Skan  def_builtin (MASK_SSE2, "__builtin_ia32_psraw128", v8hi_ftype_v8hi_v8hi, IX86_BUILTIN_PSRAW128);
16004169705Skan  def_builtin (MASK_SSE2, "__builtin_ia32_psrad128", v4si_ftype_v4si_v4si, IX86_BUILTIN_PSRAD128);
16005117408Skan
16006117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_pslldqi128", v2di_ftype_v2di_int, IX86_BUILTIN_PSLLDQI128);
16007117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_psllwi128", v8hi_ftype_v8hi_int, IX86_BUILTIN_PSLLWI128);
16008117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_pslldi128", v4si_ftype_v4si_int, IX86_BUILTIN_PSLLDI128);
16009117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_psllqi128", v2di_ftype_v2di_int, IX86_BUILTIN_PSLLQI128);
16010117408Skan
16011117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_psrldqi128", v2di_ftype_v2di_int, IX86_BUILTIN_PSRLDQI128);
16012117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_psrlwi128", v8hi_ftype_v8hi_int, IX86_BUILTIN_PSRLWI128);
16013117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_psrldi128", v4si_ftype_v4si_int, IX86_BUILTIN_PSRLDI128);
16014117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_psrlqi128", v2di_ftype_v2di_int, IX86_BUILTIN_PSRLQI128);
16015117408Skan
16016117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_psrawi128", v8hi_ftype_v8hi_int, IX86_BUILTIN_PSRAWI128);
16017117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_psradi128", v4si_ftype_v4si_int, IX86_BUILTIN_PSRADI128);
16018117408Skan
16019117408Skan  def_builtin (MASK_SSE2, "__builtin_ia32_pmaddwd128", v4si_ftype_v8hi_v8hi, IX86_BUILTIN_PMADDWD128);
16020122194Skan
16021122194Skan  /* Prescott New Instructions.  */
16022132743Skan  def_builtin (MASK_SSE3, "__builtin_ia32_monitor",
16023122194Skan	       void_ftype_pcvoid_unsigned_unsigned,
16024122194Skan	       IX86_BUILTIN_MONITOR);
16025132743Skan  def_builtin (MASK_SSE3, "__builtin_ia32_mwait",
16026122194Skan	       void_ftype_unsigned_unsigned,
16027122194Skan	       IX86_BUILTIN_MWAIT);
16028132743Skan  def_builtin (MASK_SSE3, "__builtin_ia32_movshdup",
16029122194Skan	       v4sf_ftype_v4sf,
16030122194Skan	       IX86_BUILTIN_MOVSHDUP);
16031132743Skan  def_builtin (MASK_SSE3, "__builtin_ia32_movsldup",
16032122194Skan	       v4sf_ftype_v4sf,
16033122194Skan	       IX86_BUILTIN_MOVSLDUP);
16034132743Skan  def_builtin (MASK_SSE3, "__builtin_ia32_lddqu",
16035122194Skan	       v16qi_ftype_pcchar, IX86_BUILTIN_LDDQU);
16036169705Skan
16037219639Smm  /* SSSE3.  */
16038219639Smm  def_builtin (MASK_SSSE3, "__builtin_ia32_palignr128",
16039219639Smm	       v2di_ftype_v2di_v2di_int, IX86_BUILTIN_PALIGNR128);
16040219639Smm  def_builtin (MASK_SSSE3, "__builtin_ia32_palignr", di_ftype_di_di_int,
16041219639Smm	       IX86_BUILTIN_PALIGNR);
16042219639Smm
16043251212Spfg  /* AMDFAM10 SSE4A New built-ins  */
16044251212Spfg  def_builtin (MASK_SSE4A, "__builtin_ia32_movntsd",
16045251212Spfg               void_ftype_pdouble_v2df, IX86_BUILTIN_MOVNTSD);
16046251212Spfg  def_builtin (MASK_SSE4A, "__builtin_ia32_movntss",
16047251212Spfg               void_ftype_pfloat_v4sf, IX86_BUILTIN_MOVNTSS);
16048251212Spfg  def_builtin (MASK_SSE4A, "__builtin_ia32_extrqi",
16049251212Spfg               v2di_ftype_v2di_unsigned_unsigned, IX86_BUILTIN_EXTRQI);
16050251212Spfg  def_builtin (MASK_SSE4A, "__builtin_ia32_extrq",
16051251212Spfg               v2di_ftype_v2di_v16qi,  IX86_BUILTIN_EXTRQ);
16052251212Spfg  def_builtin (MASK_SSE4A, "__builtin_ia32_insertqi",
16053251212Spfg               v2di_ftype_v2di_v2di_unsigned_unsigned, IX86_BUILTIN_INSERTQI);
16054251212Spfg  def_builtin (MASK_SSE4A, "__builtin_ia32_insertq",
16055251212Spfg               v2di_ftype_v2di_v2di, IX86_BUILTIN_INSERTQ);
16056251212Spfg
16057169705Skan  /* Access to the vec_init patterns.  */
16058169705Skan  ftype = build_function_type_list (V2SI_type_node, integer_type_node,
16059169705Skan				    integer_type_node, NULL_TREE);
16060169705Skan  def_builtin (MASK_MMX, "__builtin_ia32_vec_init_v2si",
16061169705Skan	       ftype, IX86_BUILTIN_VEC_INIT_V2SI);
16062169705Skan
16063169705Skan  ftype = build_function_type_list (V4HI_type_node, short_integer_type_node,
16064169705Skan				    short_integer_type_node,
16065169705Skan				    short_integer_type_node,
16066169705Skan				    short_integer_type_node, NULL_TREE);
16067169705Skan  def_builtin (MASK_MMX, "__builtin_ia32_vec_init_v4hi",
16068169705Skan	       ftype, IX86_BUILTIN_VEC_INIT_V4HI);
16069169705Skan
16070169705Skan  ftype = build_function_type_list (V8QI_type_node, char_type_node,
16071169705Skan				    char_type_node, char_type_node,
16072169705Skan				    char_type_node, char_type_node,
16073169705Skan				    char_type_node, char_type_node,
16074169705Skan				    char_type_node, NULL_TREE);
16075169705Skan  def_builtin (MASK_MMX, "__builtin_ia32_vec_init_v8qi",
16076169705Skan	       ftype, IX86_BUILTIN_VEC_INIT_V8QI);
16077169705Skan
16078169705Skan  /* Access to the vec_extract patterns.  */
16079169705Skan  ftype = build_function_type_list (double_type_node, V2DF_type_node,
16080169705Skan				    integer_type_node, NULL_TREE);
16081171836Skan  def_builtin (MASK_SSE2, "__builtin_ia32_vec_ext_v2df",
16082169705Skan	       ftype, IX86_BUILTIN_VEC_EXT_V2DF);
16083169705Skan
16084169705Skan  ftype = build_function_type_list (long_long_integer_type_node,
16085169705Skan				    V2DI_type_node, integer_type_node,
16086169705Skan				    NULL_TREE);
16087171836Skan  def_builtin (MASK_SSE2, "__builtin_ia32_vec_ext_v2di",
16088169705Skan	       ftype, IX86_BUILTIN_VEC_EXT_V2DI);
16089169705Skan
16090169705Skan  ftype = build_function_type_list (float_type_node, V4SF_type_node,
16091169705Skan				    integer_type_node, NULL_TREE);
16092169705Skan  def_builtin (MASK_SSE, "__builtin_ia32_vec_ext_v4sf",
16093169705Skan	       ftype, IX86_BUILTIN_VEC_EXT_V4SF);
16094169705Skan
16095169705Skan  ftype = build_function_type_list (intSI_type_node, V4SI_type_node,
16096169705Skan				    integer_type_node, NULL_TREE);
16097171836Skan  def_builtin (MASK_SSE2, "__builtin_ia32_vec_ext_v4si",
16098169705Skan	       ftype, IX86_BUILTIN_VEC_EXT_V4SI);
16099169705Skan
16100169705Skan  ftype = build_function_type_list (intHI_type_node, V8HI_type_node,
16101169705Skan				    integer_type_node, NULL_TREE);
16102171836Skan  def_builtin (MASK_SSE2, "__builtin_ia32_vec_ext_v8hi",
16103169705Skan	       ftype, IX86_BUILTIN_VEC_EXT_V8HI);
16104169705Skan
16105169705Skan  ftype = build_function_type_list (intHI_type_node, V4HI_type_node,
16106169705Skan				    integer_type_node, NULL_TREE);
16107169705Skan  def_builtin (MASK_SSE | MASK_3DNOW_A, "__builtin_ia32_vec_ext_v4hi",
16108169705Skan	       ftype, IX86_BUILTIN_VEC_EXT_V4HI);
16109169705Skan
16110169705Skan  ftype = build_function_type_list (intSI_type_node, V2SI_type_node,
16111169705Skan				    integer_type_node, NULL_TREE);
16112169705Skan  def_builtin (MASK_MMX, "__builtin_ia32_vec_ext_v2si",
16113169705Skan	       ftype, IX86_BUILTIN_VEC_EXT_V2SI);
16114169705Skan
16115171836Skan  ftype = build_function_type_list (intQI_type_node, V16QI_type_node,
16116171836Skan				    integer_type_node, NULL_TREE);
16117171836Skan  def_builtin (MASK_SSE2, "__builtin_ia32_vec_ext_v16qi", ftype, IX86_BUILTIN_VEC_EXT_V16QI);
16118171836Skan
16119169705Skan  /* Access to the vec_set patterns.  */
16120169705Skan  ftype = build_function_type_list (V8HI_type_node, V8HI_type_node,
16121169705Skan				    intHI_type_node,
16122169705Skan				    integer_type_node, NULL_TREE);
16123171836Skan  def_builtin (MASK_SSE2, "__builtin_ia32_vec_set_v8hi",
16124169705Skan	       ftype, IX86_BUILTIN_VEC_SET_V8HI);
16125169705Skan
16126169705Skan  ftype = build_function_type_list (V4HI_type_node, V4HI_type_node,
16127169705Skan				    intHI_type_node,
16128169705Skan				    integer_type_node, NULL_TREE);
16129169705Skan  def_builtin (MASK_SSE | MASK_3DNOW_A, "__builtin_ia32_vec_set_v4hi",
16130169705Skan	       ftype, IX86_BUILTIN_VEC_SET_V4HI);
1613190284Sobrien}
1613290284Sobrien
1613390284Sobrien/* Errors in the source file can cause expand_expr to return const0_rtx
1613490284Sobrien   where we expect a vector.  To avoid crashing, use one of the vector
1613590284Sobrien   clear instructions.  */
1613690284Sobrienstatic rtx
16137132743Skansafe_vector_operand (rtx x, enum machine_mode mode)
1613890284Sobrien{
16139169705Skan  if (x == const0_rtx)
16140169705Skan    x = CONST0_RTX (mode);
1614190284Sobrien  return x;
1614290284Sobrien}
1614390284Sobrien
1614490284Sobrien/* Subroutine of ix86_expand_builtin to take care of binop insns.  */
1614590284Sobrien
1614690284Sobrienstatic rtx
16147132743Skanix86_expand_binop_builtin (enum insn_code icode, tree arglist, rtx target)
1614890284Sobrien{
16149169705Skan  rtx pat, xops[3];
1615090284Sobrien  tree arg0 = TREE_VALUE (arglist);
1615190284Sobrien  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
16152169705Skan  rtx op0 = expand_normal (arg0);
16153169705Skan  rtx op1 = expand_normal (arg1);
1615490284Sobrien  enum machine_mode tmode = insn_data[icode].operand[0].mode;
1615590284Sobrien  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
1615690284Sobrien  enum machine_mode mode1 = insn_data[icode].operand[2].mode;
1615790284Sobrien
1615890284Sobrien  if (VECTOR_MODE_P (mode0))
1615990284Sobrien    op0 = safe_vector_operand (op0, mode0);
1616090284Sobrien  if (VECTOR_MODE_P (mode1))
1616190284Sobrien    op1 = safe_vector_operand (op1, mode1);
1616290284Sobrien
16163169705Skan  if (optimize || !target
1616490284Sobrien      || GET_MODE (target) != tmode
1616590284Sobrien      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
1616690284Sobrien    target = gen_reg_rtx (tmode);
1616790284Sobrien
16168117408Skan  if (GET_MODE (op1) == SImode && mode1 == TImode)
16169117408Skan    {
16170117408Skan      rtx x = gen_reg_rtx (V4SImode);
16171117408Skan      emit_insn (gen_sse2_loadd (x, op1));
16172117408Skan      op1 = gen_lowpart (TImode, x);
16173117408Skan    }
16174117408Skan
16175169705Skan  /* The insn must want input operands in the same modes as the
16176169705Skan     result.  */
16177169705Skan  gcc_assert ((GET_MODE (op0) == mode0 || GET_MODE (op0) == VOIDmode)
16178169705Skan	      && (GET_MODE (op1) == mode1 || GET_MODE (op1) == VOIDmode));
1617990284Sobrien
16180169705Skan  if (!(*insn_data[icode].operand[1].predicate) (op0, mode0))
1618190284Sobrien    op0 = copy_to_mode_reg (mode0, op0);
16182169705Skan  if (!(*insn_data[icode].operand[2].predicate) (op1, mode1))
1618390284Sobrien    op1 = copy_to_mode_reg (mode1, op1);
1618490284Sobrien
16185169705Skan  /* ??? Using ix86_fixup_binary_operands is problematic when
16186169705Skan     we've got mismatched modes.  Fake it.  */
1618796293Sobrien
16188169705Skan  xops[0] = target;
16189169705Skan  xops[1] = op0;
16190169705Skan  xops[2] = op1;
16191169705Skan
16192169705Skan  if (tmode == mode0 && tmode == mode1)
16193169705Skan    {
16194169705Skan      target = ix86_fixup_binary_operands (UNKNOWN, tmode, xops);
16195169705Skan      op0 = xops[1];
16196169705Skan      op1 = xops[2];
16197169705Skan    }
16198169705Skan  else if (optimize || !ix86_binary_operator_ok (UNKNOWN, tmode, xops))
16199169705Skan    {
16200169705Skan      op0 = force_reg (mode0, op0);
16201169705Skan      op1 = force_reg (mode1, op1);
16202169705Skan      target = gen_reg_rtx (tmode);
16203169705Skan    }
16204169705Skan
1620590284Sobrien  pat = GEN_FCN (icode) (target, op0, op1);
1620690284Sobrien  if (! pat)
1620752294Sobrien    return 0;
1620890284Sobrien  emit_insn (pat);
1620990284Sobrien  return target;
1621090284Sobrien}
1621152294Sobrien
1621290284Sobrien/* Subroutine of ix86_expand_builtin to take care of stores.  */
1621390284Sobrien
1621490284Sobrienstatic rtx
16215132743Skanix86_expand_store_builtin (enum insn_code icode, tree arglist)
1621690284Sobrien{
1621790284Sobrien  rtx pat;
1621890284Sobrien  tree arg0 = TREE_VALUE (arglist);
1621990284Sobrien  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
16220169705Skan  rtx op0 = expand_normal (arg0);
16221169705Skan  rtx op1 = expand_normal (arg1);
1622290284Sobrien  enum machine_mode mode0 = insn_data[icode].operand[0].mode;
1622390284Sobrien  enum machine_mode mode1 = insn_data[icode].operand[1].mode;
1622490284Sobrien
1622590284Sobrien  if (VECTOR_MODE_P (mode1))
1622690284Sobrien    op1 = safe_vector_operand (op1, mode1);
1622790284Sobrien
1622890284Sobrien  op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
16229117408Skan  op1 = copy_to_mode_reg (mode1, op1);
1623096293Sobrien
1623190284Sobrien  pat = GEN_FCN (icode) (op0, op1);
1623290284Sobrien  if (pat)
1623390284Sobrien    emit_insn (pat);
1623490284Sobrien  return 0;
1623590284Sobrien}
1623690284Sobrien
1623790284Sobrien/* Subroutine of ix86_expand_builtin to take care of unop insns.  */
1623890284Sobrien
1623990284Sobrienstatic rtx
16240132743Skanix86_expand_unop_builtin (enum insn_code icode, tree arglist,
16241132743Skan			  rtx target, int do_load)
1624290284Sobrien{
1624390284Sobrien  rtx pat;
1624490284Sobrien  tree arg0 = TREE_VALUE (arglist);
16245169705Skan  rtx op0 = expand_normal (arg0);
1624690284Sobrien  enum machine_mode tmode = insn_data[icode].operand[0].mode;
1624790284Sobrien  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
1624890284Sobrien
16249169705Skan  if (optimize || !target
1625090284Sobrien      || GET_MODE (target) != tmode
1625190284Sobrien      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
1625290284Sobrien    target = gen_reg_rtx (tmode);
1625390284Sobrien  if (do_load)
1625490284Sobrien    op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
1625590284Sobrien  else
1625652294Sobrien    {
1625790284Sobrien      if (VECTOR_MODE_P (mode0))
1625890284Sobrien	op0 = safe_vector_operand (op0, mode0);
1625952294Sobrien
16260169705Skan      if ((optimize && !register_operand (op0, mode0))
16261169705Skan	  || ! (*insn_data[icode].operand[1].predicate) (op0, mode0))
1626290284Sobrien	op0 = copy_to_mode_reg (mode0, op0);
1626352294Sobrien    }
1626452294Sobrien
1626590284Sobrien  pat = GEN_FCN (icode) (target, op0);
1626690284Sobrien  if (! pat)
1626790284Sobrien    return 0;
1626890284Sobrien  emit_insn (pat);
1626990284Sobrien  return target;
1627090284Sobrien}
1627152294Sobrien
1627290284Sobrien/* Subroutine of ix86_expand_builtin to take care of three special unop insns:
1627390284Sobrien   sqrtss, rsqrtss, rcpss.  */
1627452294Sobrien
1627590284Sobrienstatic rtx
16276132743Skanix86_expand_unop1_builtin (enum insn_code icode, tree arglist, rtx target)
1627790284Sobrien{
1627890284Sobrien  rtx pat;
1627990284Sobrien  tree arg0 = TREE_VALUE (arglist);
16280169705Skan  rtx op1, op0 = expand_normal (arg0);
1628190284Sobrien  enum machine_mode tmode = insn_data[icode].operand[0].mode;
1628290284Sobrien  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
1628390284Sobrien
16284169705Skan  if (optimize || !target
1628590284Sobrien      || GET_MODE (target) != tmode
1628690284Sobrien      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
1628790284Sobrien    target = gen_reg_rtx (tmode);
1628890284Sobrien
1628990284Sobrien  if (VECTOR_MODE_P (mode0))
1629090284Sobrien    op0 = safe_vector_operand (op0, mode0);
1629190284Sobrien
16292169705Skan  if ((optimize && !register_operand (op0, mode0))
16293169705Skan      || ! (*insn_data[icode].operand[1].predicate) (op0, mode0))
1629490284Sobrien    op0 = copy_to_mode_reg (mode0, op0);
16295117408Skan
1629696293Sobrien  op1 = op0;
1629796293Sobrien  if (! (*insn_data[icode].operand[2].predicate) (op1, mode0))
1629896293Sobrien    op1 = copy_to_mode_reg (mode0, op1);
16299117408Skan
1630096293Sobrien  pat = GEN_FCN (icode) (target, op0, op1);
1630190284Sobrien  if (! pat)
1630290284Sobrien    return 0;
1630390284Sobrien  emit_insn (pat);
1630490284Sobrien  return target;
1630590284Sobrien}
1630690284Sobrien
1630790284Sobrien/* Subroutine of ix86_expand_builtin to take care of comparison insns.  */
1630890284Sobrien
1630990284Sobrienstatic rtx
16310132743Skanix86_expand_sse_compare (const struct builtin_description *d, tree arglist,
16311132743Skan			 rtx target)
1631290284Sobrien{
1631390284Sobrien  rtx pat;
1631490284Sobrien  tree arg0 = TREE_VALUE (arglist);
1631590284Sobrien  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
16316169705Skan  rtx op0 = expand_normal (arg0);
16317169705Skan  rtx op1 = expand_normal (arg1);
1631890284Sobrien  rtx op2;
1631990284Sobrien  enum machine_mode tmode = insn_data[d->icode].operand[0].mode;
1632090284Sobrien  enum machine_mode mode0 = insn_data[d->icode].operand[1].mode;
1632190284Sobrien  enum machine_mode mode1 = insn_data[d->icode].operand[2].mode;
1632290284Sobrien  enum rtx_code comparison = d->comparison;
1632390284Sobrien
1632490284Sobrien  if (VECTOR_MODE_P (mode0))
1632590284Sobrien    op0 = safe_vector_operand (op0, mode0);
1632690284Sobrien  if (VECTOR_MODE_P (mode1))
1632790284Sobrien    op1 = safe_vector_operand (op1, mode1);
1632890284Sobrien
1632990284Sobrien  /* Swap operands if we have a comparison that isn't available in
1633090284Sobrien     hardware.  */
16331169705Skan  if (d->flag & BUILTIN_DESC_SWAP_OPERANDS)
1633252294Sobrien    {
1633390284Sobrien      rtx tmp = gen_reg_rtx (mode1);
1633490284Sobrien      emit_move_insn (tmp, op1);
1633590284Sobrien      op1 = op0;
1633690284Sobrien      op0 = tmp;
1633790284Sobrien    }
1633890284Sobrien
16339169705Skan  if (optimize || !target
1634090284Sobrien      || GET_MODE (target) != tmode
1634190284Sobrien      || ! (*insn_data[d->icode].operand[0].predicate) (target, tmode))
1634290284Sobrien    target = gen_reg_rtx (tmode);
1634390284Sobrien
16344169705Skan  if ((optimize && !register_operand (op0, mode0))
16345169705Skan      || ! (*insn_data[d->icode].operand[1].predicate) (op0, mode0))
1634690284Sobrien    op0 = copy_to_mode_reg (mode0, op0);
16347169705Skan  if ((optimize && !register_operand (op1, mode1))
16348169705Skan      || ! (*insn_data[d->icode].operand[2].predicate) (op1, mode1))
1634990284Sobrien    op1 = copy_to_mode_reg (mode1, op1);
1635090284Sobrien
1635190284Sobrien  op2 = gen_rtx_fmt_ee (comparison, mode0, op0, op1);
1635290284Sobrien  pat = GEN_FCN (d->icode) (target, op0, op1, op2);
1635390284Sobrien  if (! pat)
1635490284Sobrien    return 0;
1635590284Sobrien  emit_insn (pat);
1635690284Sobrien  return target;
1635790284Sobrien}
1635890284Sobrien
1635990284Sobrien/* Subroutine of ix86_expand_builtin to take care of comi insns.  */
1636090284Sobrien
1636190284Sobrienstatic rtx
16362132743Skanix86_expand_sse_comi (const struct builtin_description *d, tree arglist,
16363132743Skan		      rtx target)
1636490284Sobrien{
1636590284Sobrien  rtx pat;
1636690284Sobrien  tree arg0 = TREE_VALUE (arglist);
1636790284Sobrien  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
16368169705Skan  rtx op0 = expand_normal (arg0);
16369169705Skan  rtx op1 = expand_normal (arg1);
1637090284Sobrien  rtx op2;
1637190284Sobrien  enum machine_mode mode0 = insn_data[d->icode].operand[0].mode;
1637290284Sobrien  enum machine_mode mode1 = insn_data[d->icode].operand[1].mode;
1637390284Sobrien  enum rtx_code comparison = d->comparison;
1637490284Sobrien
1637590284Sobrien  if (VECTOR_MODE_P (mode0))
1637690284Sobrien    op0 = safe_vector_operand (op0, mode0);
1637790284Sobrien  if (VECTOR_MODE_P (mode1))
1637890284Sobrien    op1 = safe_vector_operand (op1, mode1);
1637990284Sobrien
1638090284Sobrien  /* Swap operands if we have a comparison that isn't available in
1638190284Sobrien     hardware.  */
16382169705Skan  if (d->flag & BUILTIN_DESC_SWAP_OPERANDS)
1638390284Sobrien    {
1638490284Sobrien      rtx tmp = op1;
1638590284Sobrien      op1 = op0;
1638690284Sobrien      op0 = tmp;
1638790284Sobrien    }
1638890284Sobrien
1638990284Sobrien  target = gen_reg_rtx (SImode);
1639090284Sobrien  emit_move_insn (target, const0_rtx);
1639190284Sobrien  target = gen_rtx_SUBREG (QImode, target, 0);
1639290284Sobrien
16393169705Skan  if ((optimize && !register_operand (op0, mode0))
16394169705Skan      || !(*insn_data[d->icode].operand[0].predicate) (op0, mode0))
1639590284Sobrien    op0 = copy_to_mode_reg (mode0, op0);
16396169705Skan  if ((optimize && !register_operand (op1, mode1))
16397169705Skan      || !(*insn_data[d->icode].operand[1].predicate) (op1, mode1))
1639890284Sobrien    op1 = copy_to_mode_reg (mode1, op1);
1639990284Sobrien
1640090284Sobrien  op2 = gen_rtx_fmt_ee (comparison, mode0, op0, op1);
16401117408Skan  pat = GEN_FCN (d->icode) (op0, op1);
1640290284Sobrien  if (! pat)
1640390284Sobrien    return 0;
1640490284Sobrien  emit_insn (pat);
1640590284Sobrien  emit_insn (gen_rtx_SET (VOIDmode,
1640690284Sobrien			  gen_rtx_STRICT_LOW_PART (VOIDmode, target),
1640790284Sobrien			  gen_rtx_fmt_ee (comparison, QImode,
16408117408Skan					  SET_DEST (pat),
1640990284Sobrien					  const0_rtx)));
1641090284Sobrien
1641190284Sobrien  return SUBREG_REG (target);
1641290284Sobrien}
1641390284Sobrien
16414169705Skan/* Return the integer constant in ARG.  Constrain it to be in the range
16415169705Skan   of the subparts of VEC_TYPE; issue an error if not.  */
16416169705Skan
16417169705Skanstatic int
16418169705Skanget_element_number (tree vec_type, tree arg)
16419169705Skan{
16420169705Skan  unsigned HOST_WIDE_INT elt, max = TYPE_VECTOR_SUBPARTS (vec_type) - 1;
16421169705Skan
16422169705Skan  if (!host_integerp (arg, 1)
16423169705Skan      || (elt = tree_low_cst (arg, 1), elt > max))
16424169705Skan    {
16425169705Skan      error ("selector must be an integer constant in the range 0..%wi", max);
16426169705Skan      return 0;
16427169705Skan    }
16428169705Skan
16429169705Skan  return elt;
16430169705Skan}
16431169705Skan
16432169705Skan/* A subroutine of ix86_expand_builtin.  These builtins are a wrapper around
16433169705Skan   ix86_expand_vector_init.  We DO have language-level syntax for this, in
16434169705Skan   the form of  (type){ init-list }.  Except that since we can't place emms
16435169705Skan   instructions from inside the compiler, we can't allow the use of MMX
16436169705Skan   registers unless the user explicitly asks for it.  So we do *not* define
16437169705Skan   vec_set/vec_extract/vec_init patterns for MMX modes in mmx.md.  Instead
16438169705Skan   we have builtins invoked by mmintrin.h that gives us license to emit
16439169705Skan   these sorts of instructions.  */
16440169705Skan
16441169705Skanstatic rtx
16442169705Skanix86_expand_vec_init_builtin (tree type, tree arglist, rtx target)
16443169705Skan{
16444169705Skan  enum machine_mode tmode = TYPE_MODE (type);
16445169705Skan  enum machine_mode inner_mode = GET_MODE_INNER (tmode);
16446169705Skan  int i, n_elt = GET_MODE_NUNITS (tmode);
16447169705Skan  rtvec v = rtvec_alloc (n_elt);
16448169705Skan
16449169705Skan  gcc_assert (VECTOR_MODE_P (tmode));
16450169705Skan
16451169705Skan  for (i = 0; i < n_elt; ++i, arglist = TREE_CHAIN (arglist))
16452169705Skan    {
16453169705Skan      rtx x = expand_normal (TREE_VALUE (arglist));
16454169705Skan      RTVEC_ELT (v, i) = gen_lowpart (inner_mode, x);
16455169705Skan    }
16456169705Skan
16457169705Skan  gcc_assert (arglist == NULL);
16458169705Skan
16459169705Skan  if (!target || !register_operand (target, tmode))
16460169705Skan    target = gen_reg_rtx (tmode);
16461169705Skan
16462169705Skan  ix86_expand_vector_init (true, target, gen_rtx_PARALLEL (tmode, v));
16463169705Skan  return target;
16464169705Skan}
16465169705Skan
16466169705Skan/* A subroutine of ix86_expand_builtin.  These builtins are a wrapper around
16467169705Skan   ix86_expand_vector_extract.  They would be redundant (for non-MMX) if we
16468169705Skan   had a language-level syntax for referencing vector elements.  */
16469169705Skan
16470169705Skanstatic rtx
16471169705Skanix86_expand_vec_ext_builtin (tree arglist, rtx target)
16472169705Skan{
16473169705Skan  enum machine_mode tmode, mode0;
16474169705Skan  tree arg0, arg1;
16475169705Skan  int elt;
16476169705Skan  rtx op0;
16477169705Skan
16478169705Skan  arg0 = TREE_VALUE (arglist);
16479169705Skan  arg1 = TREE_VALUE (TREE_CHAIN (arglist));
16480169705Skan
16481169705Skan  op0 = expand_normal (arg0);
16482169705Skan  elt = get_element_number (TREE_TYPE (arg0), arg1);
16483169705Skan
16484169705Skan  tmode = TYPE_MODE (TREE_TYPE (TREE_TYPE (arg0)));
16485169705Skan  mode0 = TYPE_MODE (TREE_TYPE (arg0));
16486169705Skan  gcc_assert (VECTOR_MODE_P (mode0));
16487169705Skan
16488169705Skan  op0 = force_reg (mode0, op0);
16489169705Skan
16490169705Skan  if (optimize || !target || !register_operand (target, tmode))
16491169705Skan    target = gen_reg_rtx (tmode);
16492169705Skan
16493169705Skan  ix86_expand_vector_extract (true, target, op0, elt);
16494169705Skan
16495169705Skan  return target;
16496169705Skan}
16497169705Skan
16498169705Skan/* A subroutine of ix86_expand_builtin.  These builtins are a wrapper around
16499169705Skan   ix86_expand_vector_set.  They would be redundant (for non-MMX) if we had
16500169705Skan   a language-level syntax for referencing vector elements.  */
16501169705Skan
16502169705Skanstatic rtx
16503169705Skanix86_expand_vec_set_builtin (tree arglist)
16504169705Skan{
16505169705Skan  enum machine_mode tmode, mode1;
16506169705Skan  tree arg0, arg1, arg2;
16507169705Skan  int elt;
16508169705Skan  rtx op0, op1, target;
16509169705Skan
16510169705Skan  arg0 = TREE_VALUE (arglist);
16511169705Skan  arg1 = TREE_VALUE (TREE_CHAIN (arglist));
16512169705Skan  arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
16513169705Skan
16514169705Skan  tmode = TYPE_MODE (TREE_TYPE (arg0));
16515169705Skan  mode1 = TYPE_MODE (TREE_TYPE (TREE_TYPE (arg0)));
16516169705Skan  gcc_assert (VECTOR_MODE_P (tmode));
16517169705Skan
16518169705Skan  op0 = expand_expr (arg0, NULL_RTX, tmode, 0);
16519169705Skan  op1 = expand_expr (arg1, NULL_RTX, mode1, 0);
16520169705Skan  elt = get_element_number (TREE_TYPE (arg0), arg2);
16521169705Skan
16522169705Skan  if (GET_MODE (op1) != mode1 && GET_MODE (op1) != VOIDmode)
16523169705Skan    op1 = convert_modes (mode1, GET_MODE (op1), op1, true);
16524169705Skan
16525169705Skan  op0 = force_reg (tmode, op0);
16526169705Skan  op1 = force_reg (mode1, op1);
16527169705Skan
16528169705Skan  /* OP0 is the source of these builtin functions and shouldn't be
16529169705Skan     modified.  Create a copy, use it and return it as target.  */
16530169705Skan  target = gen_reg_rtx (tmode);
16531169705Skan  emit_move_insn (target, op0);
16532169705Skan  ix86_expand_vector_set (true, target, op1, elt);
16533169705Skan
16534169705Skan  return target;
16535169705Skan}
16536169705Skan
1653790284Sobrien/* Expand an expression EXP that calls a built-in function,
1653890284Sobrien   with result going to TARGET if that's convenient
1653990284Sobrien   (and in mode MODE if that's convenient).
1654090284Sobrien   SUBTARGET may be used as the target for computing one of EXP's operands.
1654190284Sobrien   IGNORE is nonzero if the value is to be ignored.  */
1654290284Sobrien
16543169705Skanstatic rtx
16544132743Skanix86_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
16545132743Skan		     enum machine_mode mode ATTRIBUTE_UNUSED,
16546132743Skan		     int ignore ATTRIBUTE_UNUSED)
1654790284Sobrien{
1654890284Sobrien  const struct builtin_description *d;
1654990284Sobrien  size_t i;
1655090284Sobrien  enum insn_code icode;
1655190284Sobrien  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
1655290284Sobrien  tree arglist = TREE_OPERAND (exp, 1);
16553251212Spfg  tree arg0, arg1, arg2, arg3;
16554251212Spfg  rtx op0, op1, op2, op3, pat;
16555251212Spfg  enum machine_mode tmode, mode0, mode1, mode2, mode3, mode4;
1655690284Sobrien  unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
1655790284Sobrien
1655890284Sobrien  switch (fcode)
1655990284Sobrien    {
1656090284Sobrien    case IX86_BUILTIN_EMMS:
16561169705Skan      emit_insn (gen_mmx_emms ());
1656290284Sobrien      return 0;
1656390284Sobrien
1656490284Sobrien    case IX86_BUILTIN_SFENCE:
16565169705Skan      emit_insn (gen_sse_sfence ());
1656690284Sobrien      return 0;
1656790284Sobrien
1656890284Sobrien    case IX86_BUILTIN_MASKMOVQ:
16569117408Skan    case IX86_BUILTIN_MASKMOVDQU:
16570117408Skan      icode = (fcode == IX86_BUILTIN_MASKMOVQ
16571169705Skan	       ? CODE_FOR_mmx_maskmovq
16572169705Skan	       : CODE_FOR_sse2_maskmovdqu);
1657390284Sobrien      /* Note the arg order is different from the operand order.  */
1657490284Sobrien      arg1 = TREE_VALUE (arglist);
1657590284Sobrien      arg2 = TREE_VALUE (TREE_CHAIN (arglist));
1657690284Sobrien      arg0 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
16577169705Skan      op0 = expand_normal (arg0);
16578169705Skan      op1 = expand_normal (arg1);
16579169705Skan      op2 = expand_normal (arg2);
1658090284Sobrien      mode0 = insn_data[icode].operand[0].mode;
1658190284Sobrien      mode1 = insn_data[icode].operand[1].mode;
1658290284Sobrien      mode2 = insn_data[icode].operand[2].mode;
1658390284Sobrien
16584169705Skan      op0 = force_reg (Pmode, op0);
16585169705Skan      op0 = gen_rtx_MEM (mode1, op0);
16586169705Skan
1658796293Sobrien      if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
1658890284Sobrien	op0 = copy_to_mode_reg (mode0, op0);
1658990284Sobrien      if (! (*insn_data[icode].operand[1].predicate) (op1, mode1))
1659090284Sobrien	op1 = copy_to_mode_reg (mode1, op1);
1659190284Sobrien      if (! (*insn_data[icode].operand[2].predicate) (op2, mode2))
1659290284Sobrien	op2 = copy_to_mode_reg (mode2, op2);
1659390284Sobrien      pat = GEN_FCN (icode) (op0, op1, op2);
1659490284Sobrien      if (! pat)
1659590284Sobrien	return 0;
1659690284Sobrien      emit_insn (pat);
1659790284Sobrien      return 0;
1659890284Sobrien
1659990284Sobrien    case IX86_BUILTIN_SQRTSS:
16600169705Skan      return ix86_expand_unop1_builtin (CODE_FOR_sse_vmsqrtv4sf2, arglist, target);
1660190284Sobrien    case IX86_BUILTIN_RSQRTSS:
16602169705Skan      return ix86_expand_unop1_builtin (CODE_FOR_sse_vmrsqrtv4sf2, arglist, target);
1660390284Sobrien    case IX86_BUILTIN_RCPSS:
16604169705Skan      return ix86_expand_unop1_builtin (CODE_FOR_sse_vmrcpv4sf2, arglist, target);
1660590284Sobrien
1660690284Sobrien    case IX86_BUILTIN_LOADUPS:
1660790284Sobrien      return ix86_expand_unop_builtin (CODE_FOR_sse_movups, arglist, target, 1);
1660890284Sobrien
1660990284Sobrien    case IX86_BUILTIN_STOREUPS:
1661090284Sobrien      return ix86_expand_store_builtin (CODE_FOR_sse_movups, arglist);
1661190284Sobrien
1661290284Sobrien    case IX86_BUILTIN_LOADHPS:
1661390284Sobrien    case IX86_BUILTIN_LOADLPS:
16614117408Skan    case IX86_BUILTIN_LOADHPD:
16615117408Skan    case IX86_BUILTIN_LOADLPD:
16616169705Skan      icode = (fcode == IX86_BUILTIN_LOADHPS ? CODE_FOR_sse_loadhps
16617169705Skan	       : fcode == IX86_BUILTIN_LOADLPS ? CODE_FOR_sse_loadlps
16618169705Skan	       : fcode == IX86_BUILTIN_LOADHPD ? CODE_FOR_sse2_loadhpd
16619169705Skan	       : CODE_FOR_sse2_loadlpd);
1662090284Sobrien      arg0 = TREE_VALUE (arglist);
1662190284Sobrien      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
16622169705Skan      op0 = expand_normal (arg0);
16623169705Skan      op1 = expand_normal (arg1);
1662490284Sobrien      tmode = insn_data[icode].operand[0].mode;
1662590284Sobrien      mode0 = insn_data[icode].operand[1].mode;
1662690284Sobrien      mode1 = insn_data[icode].operand[2].mode;
1662790284Sobrien
16628169705Skan      op0 = force_reg (mode0, op0);
1662990284Sobrien      op1 = gen_rtx_MEM (mode1, copy_to_mode_reg (Pmode, op1));
16630169705Skan      if (optimize || target == 0
1663190284Sobrien	  || GET_MODE (target) != tmode
16632169705Skan	  || !register_operand (target, tmode))
1663390284Sobrien	target = gen_reg_rtx (tmode);
1663490284Sobrien      pat = GEN_FCN (icode) (target, op0, op1);
1663590284Sobrien      if (! pat)
1663690284Sobrien	return 0;
1663790284Sobrien      emit_insn (pat);
1663890284Sobrien      return target;
1663990284Sobrien
1664090284Sobrien    case IX86_BUILTIN_STOREHPS:
1664190284Sobrien    case IX86_BUILTIN_STORELPS:
16642169705Skan      icode = (fcode == IX86_BUILTIN_STOREHPS ? CODE_FOR_sse_storehps
16643169705Skan	       : CODE_FOR_sse_storelps);
1664490284Sobrien      arg0 = TREE_VALUE (arglist);
1664590284Sobrien      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
16646169705Skan      op0 = expand_normal (arg0);
16647169705Skan      op1 = expand_normal (arg1);
16648169705Skan      mode0 = insn_data[icode].operand[0].mode;
16649169705Skan      mode1 = insn_data[icode].operand[1].mode;
1665090284Sobrien
1665190284Sobrien      op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
16652169705Skan      op1 = force_reg (mode1, op1);
1665390284Sobrien
16654169705Skan      pat = GEN_FCN (icode) (op0, op1);
1665590284Sobrien      if (! pat)
1665690284Sobrien	return 0;
1665790284Sobrien      emit_insn (pat);
16658169705Skan      return const0_rtx;
1665990284Sobrien
1666090284Sobrien    case IX86_BUILTIN_MOVNTPS:
1666190284Sobrien      return ix86_expand_store_builtin (CODE_FOR_sse_movntv4sf, arglist);
1666290284Sobrien    case IX86_BUILTIN_MOVNTQ:
1666390284Sobrien      return ix86_expand_store_builtin (CODE_FOR_sse_movntdi, arglist);
1666490284Sobrien
1666590284Sobrien    case IX86_BUILTIN_LDMXCSR:
16666169705Skan      op0 = expand_normal (TREE_VALUE (arglist));
16667171836Skan      target = assign_386_stack_local (SImode, SLOT_VIRTUAL);
1666890284Sobrien      emit_move_insn (target, op0);
16669169705Skan      emit_insn (gen_sse_ldmxcsr (target));
1667090284Sobrien      return 0;
1667190284Sobrien
1667290284Sobrien    case IX86_BUILTIN_STMXCSR:
16673171836Skan      target = assign_386_stack_local (SImode, SLOT_VIRTUAL);
16674169705Skan      emit_insn (gen_sse_stmxcsr (target));
1667590284Sobrien      return copy_to_mode_reg (SImode, target);
1667690284Sobrien
1667790284Sobrien    case IX86_BUILTIN_SHUFPS:
16678117408Skan    case IX86_BUILTIN_SHUFPD:
16679117408Skan      icode = (fcode == IX86_BUILTIN_SHUFPS
16680117408Skan	       ? CODE_FOR_sse_shufps
16681117408Skan	       : CODE_FOR_sse2_shufpd);
1668290284Sobrien      arg0 = TREE_VALUE (arglist);
1668390284Sobrien      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
1668490284Sobrien      arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
16685169705Skan      op0 = expand_normal (arg0);
16686169705Skan      op1 = expand_normal (arg1);
16687169705Skan      op2 = expand_normal (arg2);
1668890284Sobrien      tmode = insn_data[icode].operand[0].mode;
1668990284Sobrien      mode0 = insn_data[icode].operand[1].mode;
1669090284Sobrien      mode1 = insn_data[icode].operand[2].mode;
1669190284Sobrien      mode2 = insn_data[icode].operand[3].mode;
1669290284Sobrien
1669390284Sobrien      if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
1669490284Sobrien	op0 = copy_to_mode_reg (mode0, op0);
16695169705Skan      if ((optimize && !register_operand (op1, mode1))
16696169705Skan	  || !(*insn_data[icode].operand[2].predicate) (op1, mode1))
1669790284Sobrien	op1 = copy_to_mode_reg (mode1, op1);
1669890284Sobrien      if (! (*insn_data[icode].operand[3].predicate) (op2, mode2))
1669952294Sobrien	{
1670090284Sobrien	  /* @@@ better error message */
1670190284Sobrien	  error ("mask must be an immediate");
1670290284Sobrien	  return gen_reg_rtx (tmode);
1670352294Sobrien	}
16704169705Skan      if (optimize || target == 0
1670590284Sobrien	  || GET_MODE (target) != tmode
1670690284Sobrien	  || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
1670790284Sobrien	target = gen_reg_rtx (tmode);
1670890284Sobrien      pat = GEN_FCN (icode) (target, op0, op1, op2);
1670990284Sobrien      if (! pat)
1671090284Sobrien	return 0;
1671190284Sobrien      emit_insn (pat);
1671290284Sobrien      return target;
1671390284Sobrien
1671490284Sobrien    case IX86_BUILTIN_PSHUFW:
16715117408Skan    case IX86_BUILTIN_PSHUFD:
16716117408Skan    case IX86_BUILTIN_PSHUFHW:
16717117408Skan    case IX86_BUILTIN_PSHUFLW:
16718117408Skan      icode = (  fcode == IX86_BUILTIN_PSHUFHW ? CODE_FOR_sse2_pshufhw
16719117408Skan	       : fcode == IX86_BUILTIN_PSHUFLW ? CODE_FOR_sse2_pshuflw
16720117408Skan	       : fcode == IX86_BUILTIN_PSHUFD ? CODE_FOR_sse2_pshufd
16721117408Skan	       : CODE_FOR_mmx_pshufw);
1672290284Sobrien      arg0 = TREE_VALUE (arglist);
1672390284Sobrien      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
16724169705Skan      op0 = expand_normal (arg0);
16725169705Skan      op1 = expand_normal (arg1);
1672690284Sobrien      tmode = insn_data[icode].operand[0].mode;
1672790284Sobrien      mode1 = insn_data[icode].operand[1].mode;
1672890284Sobrien      mode2 = insn_data[icode].operand[2].mode;
1672990284Sobrien
1673090284Sobrien      if (! (*insn_data[icode].operand[1].predicate) (op0, mode1))
1673190284Sobrien	op0 = copy_to_mode_reg (mode1, op0);
1673290284Sobrien      if (! (*insn_data[icode].operand[2].predicate) (op1, mode2))
1673352294Sobrien	{
1673490284Sobrien	  /* @@@ better error message */
1673590284Sobrien	  error ("mask must be an immediate");
1673690284Sobrien	  return const0_rtx;
1673752294Sobrien	}
1673890284Sobrien      if (target == 0
1673990284Sobrien	  || GET_MODE (target) != tmode
1674090284Sobrien	  || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
1674190284Sobrien	target = gen_reg_rtx (tmode);
1674290284Sobrien      pat = GEN_FCN (icode) (target, op0, op1);
1674390284Sobrien      if (! pat)
1674490284Sobrien	return 0;
1674590284Sobrien      emit_insn (pat);
1674690284Sobrien      return target;
1674790284Sobrien
16748169705Skan    case IX86_BUILTIN_PSLLWI128:
16749169705Skan      icode = CODE_FOR_ashlv8hi3;
16750169705Skan      goto do_pshifti;
16751169705Skan    case IX86_BUILTIN_PSLLDI128:
16752169705Skan      icode = CODE_FOR_ashlv4si3;
16753169705Skan      goto do_pshifti;
16754169705Skan    case IX86_BUILTIN_PSLLQI128:
16755169705Skan      icode = CODE_FOR_ashlv2di3;
16756169705Skan      goto do_pshifti;
16757169705Skan    case IX86_BUILTIN_PSRAWI128:
16758169705Skan      icode = CODE_FOR_ashrv8hi3;
16759169705Skan      goto do_pshifti;
16760169705Skan    case IX86_BUILTIN_PSRADI128:
16761169705Skan      icode = CODE_FOR_ashrv4si3;
16762169705Skan      goto do_pshifti;
16763169705Skan    case IX86_BUILTIN_PSRLWI128:
16764169705Skan      icode = CODE_FOR_lshrv8hi3;
16765169705Skan      goto do_pshifti;
16766169705Skan    case IX86_BUILTIN_PSRLDI128:
16767169705Skan      icode = CODE_FOR_lshrv4si3;
16768169705Skan      goto do_pshifti;
16769169705Skan    case IX86_BUILTIN_PSRLQI128:
16770169705Skan      icode = CODE_FOR_lshrv2di3;
16771169705Skan      goto do_pshifti;
16772169705Skan    do_pshifti:
16773169705Skan      arg0 = TREE_VALUE (arglist);
16774169705Skan      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
16775169705Skan      op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
16776169705Skan      op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
16777169705Skan
16778169705Skan      if (GET_CODE (op1) != CONST_INT)
16779169705Skan	{
16780169705Skan	  error ("shift must be an immediate");
16781169705Skan	  return const0_rtx;
16782169705Skan	}
16783169705Skan      if (INTVAL (op1) < 0 || INTVAL (op1) > 255)
16784169705Skan	op1 = GEN_INT (255);
16785169705Skan
16786169705Skan      tmode = insn_data[icode].operand[0].mode;
16787169705Skan      mode1 = insn_data[icode].operand[1].mode;
16788169705Skan      if (! (*insn_data[icode].operand[1].predicate) (op0, mode1))
16789169705Skan	op0 = copy_to_reg (op0);
16790169705Skan
16791169705Skan      target = gen_reg_rtx (tmode);
16792169705Skan      pat = GEN_FCN (icode) (target, op0, op1);
16793169705Skan      if (!pat)
16794169705Skan	return 0;
16795169705Skan      emit_insn (pat);
16796169705Skan      return target;
16797169705Skan
16798169705Skan    case IX86_BUILTIN_PSLLW128:
16799169705Skan      icode = CODE_FOR_ashlv8hi3;
16800169705Skan      goto do_pshift;
16801169705Skan    case IX86_BUILTIN_PSLLD128:
16802169705Skan      icode = CODE_FOR_ashlv4si3;
16803169705Skan      goto do_pshift;
16804169705Skan    case IX86_BUILTIN_PSLLQ128:
16805169705Skan      icode = CODE_FOR_ashlv2di3;
16806169705Skan      goto do_pshift;
16807169705Skan    case IX86_BUILTIN_PSRAW128:
16808169705Skan      icode = CODE_FOR_ashrv8hi3;
16809169705Skan      goto do_pshift;
16810169705Skan    case IX86_BUILTIN_PSRAD128:
16811169705Skan      icode = CODE_FOR_ashrv4si3;
16812169705Skan      goto do_pshift;
16813169705Skan    case IX86_BUILTIN_PSRLW128:
16814169705Skan      icode = CODE_FOR_lshrv8hi3;
16815169705Skan      goto do_pshift;
16816169705Skan    case IX86_BUILTIN_PSRLD128:
16817169705Skan      icode = CODE_FOR_lshrv4si3;
16818169705Skan      goto do_pshift;
16819169705Skan    case IX86_BUILTIN_PSRLQ128:
16820169705Skan      icode = CODE_FOR_lshrv2di3;
16821169705Skan      goto do_pshift;
16822169705Skan    do_pshift:
16823169705Skan      arg0 = TREE_VALUE (arglist);
16824169705Skan      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
16825169705Skan      op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
16826169705Skan      op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
16827169705Skan
16828169705Skan      tmode = insn_data[icode].operand[0].mode;
16829169705Skan      mode1 = insn_data[icode].operand[1].mode;
16830169705Skan
16831169705Skan      if (! (*insn_data[icode].operand[1].predicate) (op0, mode1))
16832169705Skan	op0 = copy_to_reg (op0);
16833169705Skan
16834169705Skan      op1 = simplify_gen_subreg (TImode, op1, GET_MODE (op1), 0);
16835169705Skan      if (! (*insn_data[icode].operand[2].predicate) (op1, TImode))
16836169705Skan	op1 = copy_to_reg (op1);
16837169705Skan
16838169705Skan      target = gen_reg_rtx (tmode);
16839169705Skan      pat = GEN_FCN (icode) (target, op0, op1);
16840169705Skan      if (!pat)
16841169705Skan	return 0;
16842169705Skan      emit_insn (pat);
16843169705Skan      return target;
16844169705Skan
16845117408Skan    case IX86_BUILTIN_PSLLDQI128:
16846117408Skan    case IX86_BUILTIN_PSRLDQI128:
16847169705Skan      icode = (fcode == IX86_BUILTIN_PSLLDQI128 ? CODE_FOR_sse2_ashlti3
16848117408Skan	       : CODE_FOR_sse2_lshrti3);
16849117408Skan      arg0 = TREE_VALUE (arglist);
16850117408Skan      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
16851169705Skan      op0 = expand_normal (arg0);
16852169705Skan      op1 = expand_normal (arg1);
16853117408Skan      tmode = insn_data[icode].operand[0].mode;
16854117408Skan      mode1 = insn_data[icode].operand[1].mode;
16855117408Skan      mode2 = insn_data[icode].operand[2].mode;
16856117408Skan
16857117408Skan      if (! (*insn_data[icode].operand[1].predicate) (op0, mode1))
16858117408Skan	{
16859117408Skan	  op0 = copy_to_reg (op0);
16860117408Skan	  op0 = simplify_gen_subreg (mode1, op0, GET_MODE (op0), 0);
16861117408Skan	}
16862117408Skan      if (! (*insn_data[icode].operand[2].predicate) (op1, mode2))
16863117408Skan	{
16864117408Skan	  error ("shift must be an immediate");
16865117408Skan	  return const0_rtx;
16866117408Skan	}
16867117408Skan      target = gen_reg_rtx (V2DImode);
16868169705Skan      pat = GEN_FCN (icode) (simplify_gen_subreg (tmode, target, V2DImode, 0),
16869169705Skan			     op0, op1);
16870117408Skan      if (! pat)
16871117408Skan	return 0;
16872117408Skan      emit_insn (pat);
16873117408Skan      return target;
16874117408Skan
1687590284Sobrien    case IX86_BUILTIN_FEMMS:
16876169705Skan      emit_insn (gen_mmx_femms ());
1687790284Sobrien      return NULL_RTX;
1687890284Sobrien
1687990284Sobrien    case IX86_BUILTIN_PAVGUSB:
16880169705Skan      return ix86_expand_binop_builtin (CODE_FOR_mmx_uavgv8qi3, arglist, target);
1688190284Sobrien
1688290284Sobrien    case IX86_BUILTIN_PF2ID:
16883169705Skan      return ix86_expand_unop_builtin (CODE_FOR_mmx_pf2id, arglist, target, 0);
1688490284Sobrien
1688590284Sobrien    case IX86_BUILTIN_PFACC:
16886169705Skan      return ix86_expand_binop_builtin (CODE_FOR_mmx_haddv2sf3, arglist, target);
1688790284Sobrien
1688890284Sobrien    case IX86_BUILTIN_PFADD:
16889169705Skan     return ix86_expand_binop_builtin (CODE_FOR_mmx_addv2sf3, arglist, target);
1689090284Sobrien
1689190284Sobrien    case IX86_BUILTIN_PFCMPEQ:
16892169705Skan      return ix86_expand_binop_builtin (CODE_FOR_mmx_eqv2sf3, arglist, target);
1689390284Sobrien
1689490284Sobrien    case IX86_BUILTIN_PFCMPGE:
16895169705Skan      return ix86_expand_binop_builtin (CODE_FOR_mmx_gev2sf3, arglist, target);
1689690284Sobrien
1689790284Sobrien    case IX86_BUILTIN_PFCMPGT:
16898169705Skan      return ix86_expand_binop_builtin (CODE_FOR_mmx_gtv2sf3, arglist, target);
1689990284Sobrien
1690090284Sobrien    case IX86_BUILTIN_PFMAX:
16901169705Skan      return ix86_expand_binop_builtin (CODE_FOR_mmx_smaxv2sf3, arglist, target);
1690290284Sobrien
1690390284Sobrien    case IX86_BUILTIN_PFMIN:
16904169705Skan      return ix86_expand_binop_builtin (CODE_FOR_mmx_sminv2sf3, arglist, target);
1690590284Sobrien
1690690284Sobrien    case IX86_BUILTIN_PFMUL:
16907169705Skan      return ix86_expand_binop_builtin (CODE_FOR_mmx_mulv2sf3, arglist, target);
1690890284Sobrien
1690990284Sobrien    case IX86_BUILTIN_PFRCP:
16910169705Skan      return ix86_expand_unop_builtin (CODE_FOR_mmx_rcpv2sf2, arglist, target, 0);
1691190284Sobrien
1691290284Sobrien    case IX86_BUILTIN_PFRCPIT1:
16913169705Skan      return ix86_expand_binop_builtin (CODE_FOR_mmx_rcpit1v2sf3, arglist, target);
1691490284Sobrien
1691590284Sobrien    case IX86_BUILTIN_PFRCPIT2:
16916169705Skan      return ix86_expand_binop_builtin (CODE_FOR_mmx_rcpit2v2sf3, arglist, target);
1691790284Sobrien
1691890284Sobrien    case IX86_BUILTIN_PFRSQIT1:
16919169705Skan      return ix86_expand_binop_builtin (CODE_FOR_mmx_rsqit1v2sf3, arglist, target);
1692090284Sobrien
1692190284Sobrien    case IX86_BUILTIN_PFRSQRT:
16922169705Skan      return ix86_expand_unop_builtin (CODE_FOR_mmx_rsqrtv2sf2, arglist, target, 0);
1692390284Sobrien
1692490284Sobrien    case IX86_BUILTIN_PFSUB:
16925169705Skan      return ix86_expand_binop_builtin (CODE_FOR_mmx_subv2sf3, arglist, target);
1692690284Sobrien
1692790284Sobrien    case IX86_BUILTIN_PFSUBR:
16928169705Skan      return ix86_expand_binop_builtin (CODE_FOR_mmx_subrv2sf3, arglist, target);
1692990284Sobrien
1693090284Sobrien    case IX86_BUILTIN_PI2FD:
16931169705Skan      return ix86_expand_unop_builtin (CODE_FOR_mmx_floatv2si2, arglist, target, 0);
1693290284Sobrien
1693390284Sobrien    case IX86_BUILTIN_PMULHRW:
16934169705Skan      return ix86_expand_binop_builtin (CODE_FOR_mmx_pmulhrwv4hi3, arglist, target);
1693590284Sobrien
1693690284Sobrien    case IX86_BUILTIN_PF2IW:
16937169705Skan      return ix86_expand_unop_builtin (CODE_FOR_mmx_pf2iw, arglist, target, 0);
1693890284Sobrien
1693990284Sobrien    case IX86_BUILTIN_PFNACC:
16940169705Skan      return ix86_expand_binop_builtin (CODE_FOR_mmx_hsubv2sf3, arglist, target);
1694190284Sobrien
1694290284Sobrien    case IX86_BUILTIN_PFPNACC:
16943169705Skan      return ix86_expand_binop_builtin (CODE_FOR_mmx_addsubv2sf3, arglist, target);
1694490284Sobrien
1694590284Sobrien    case IX86_BUILTIN_PI2FW:
16946169705Skan      return ix86_expand_unop_builtin (CODE_FOR_mmx_pi2fw, arglist, target, 0);
1694790284Sobrien
1694890284Sobrien    case IX86_BUILTIN_PSWAPDSI:
16949169705Skan      return ix86_expand_unop_builtin (CODE_FOR_mmx_pswapdv2si2, arglist, target, 0);
1695090284Sobrien
1695190284Sobrien    case IX86_BUILTIN_PSWAPDSF:
16952169705Skan      return ix86_expand_unop_builtin (CODE_FOR_mmx_pswapdv2sf2, arglist, target, 0);
1695390284Sobrien
16954117408Skan    case IX86_BUILTIN_SQRTSD:
16955169705Skan      return ix86_expand_unop1_builtin (CODE_FOR_sse2_vmsqrtv2df2, arglist, target);
16956117408Skan    case IX86_BUILTIN_LOADUPD:
16957117408Skan      return ix86_expand_unop_builtin (CODE_FOR_sse2_movupd, arglist, target, 1);
16958117408Skan    case IX86_BUILTIN_STOREUPD:
16959117408Skan      return ix86_expand_store_builtin (CODE_FOR_sse2_movupd, arglist);
16960117408Skan
16961117408Skan    case IX86_BUILTIN_MFENCE:
16962117408Skan	emit_insn (gen_sse2_mfence ());
16963117408Skan	return 0;
16964117408Skan    case IX86_BUILTIN_LFENCE:
16965117408Skan	emit_insn (gen_sse2_lfence ());
16966117408Skan	return 0;
16967117408Skan
16968117408Skan    case IX86_BUILTIN_CLFLUSH:
16969117408Skan	arg0 = TREE_VALUE (arglist);
16970169705Skan	op0 = expand_normal (arg0);
16971117408Skan	icode = CODE_FOR_sse2_clflush;
16972117408Skan	if (! (*insn_data[icode].operand[0].predicate) (op0, Pmode))
16973117408Skan	    op0 = copy_to_mode_reg (Pmode, op0);
16974117408Skan
16975117408Skan	emit_insn (gen_sse2_clflush (op0));
16976117408Skan	return 0;
16977117408Skan
16978117408Skan    case IX86_BUILTIN_MOVNTPD:
16979117408Skan      return ix86_expand_store_builtin (CODE_FOR_sse2_movntv2df, arglist);
16980117408Skan    case IX86_BUILTIN_MOVNTDQ:
16981117408Skan      return ix86_expand_store_builtin (CODE_FOR_sse2_movntv2di, arglist);
16982117408Skan    case IX86_BUILTIN_MOVNTI:
16983117408Skan      return ix86_expand_store_builtin (CODE_FOR_sse2_movntsi, arglist);
16984117408Skan
16985117408Skan    case IX86_BUILTIN_LOADDQU:
16986117408Skan      return ix86_expand_unop_builtin (CODE_FOR_sse2_movdqu, arglist, target, 1);
16987117408Skan    case IX86_BUILTIN_STOREDQU:
16988117408Skan      return ix86_expand_store_builtin (CODE_FOR_sse2_movdqu, arglist);
16989117408Skan
16990122194Skan    case IX86_BUILTIN_MONITOR:
16991122194Skan      arg0 = TREE_VALUE (arglist);
16992122194Skan      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
16993122194Skan      arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
16994169705Skan      op0 = expand_normal (arg0);
16995169705Skan      op1 = expand_normal (arg1);
16996169705Skan      op2 = expand_normal (arg2);
16997122194Skan      if (!REG_P (op0))
16998169705Skan	op0 = copy_to_mode_reg (Pmode, op0);
16999122194Skan      if (!REG_P (op1))
17000122194Skan	op1 = copy_to_mode_reg (SImode, op1);
17001122194Skan      if (!REG_P (op2))
17002122194Skan	op2 = copy_to_mode_reg (SImode, op2);
17003169705Skan      if (!TARGET_64BIT)
17004169705Skan	emit_insn (gen_sse3_monitor (op0, op1, op2));
17005169705Skan      else
17006169705Skan	emit_insn (gen_sse3_monitor64 (op0, op1, op2));
17007122194Skan      return 0;
17008122194Skan
17009122194Skan    case IX86_BUILTIN_MWAIT:
17010122194Skan      arg0 = TREE_VALUE (arglist);
17011122194Skan      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
17012169705Skan      op0 = expand_normal (arg0);
17013169705Skan      op1 = expand_normal (arg1);
17014122194Skan      if (!REG_P (op0))
17015122194Skan	op0 = copy_to_mode_reg (SImode, op0);
17016122194Skan      if (!REG_P (op1))
17017122194Skan	op1 = copy_to_mode_reg (SImode, op1);
17018169705Skan      emit_insn (gen_sse3_mwait (op0, op1));
17019122194Skan      return 0;
17020122194Skan
17021122194Skan    case IX86_BUILTIN_LDDQU:
17022169705Skan      return ix86_expand_unop_builtin (CODE_FOR_sse3_lddqu, arglist,
17023169705Skan				       target, 1);
17024122194Skan
17025219639Smm    case IX86_BUILTIN_PALIGNR:
17026219639Smm    case IX86_BUILTIN_PALIGNR128:
17027219639Smm      if (fcode == IX86_BUILTIN_PALIGNR)
17028219639Smm	{
17029219639Smm	  icode = CODE_FOR_ssse3_palignrdi;
17030219639Smm	  mode = DImode;
17031219639Smm	}
17032219639Smm      else
17033219639Smm	{
17034219639Smm	  icode = CODE_FOR_ssse3_palignrti;
17035219639Smm	  mode = V2DImode;
17036219639Smm	}
17037219639Smm      arg0 = TREE_VALUE (arglist);
17038219639Smm      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
17039219639Smm      arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
17040219639Smm      op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
17041219639Smm      op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
17042219639Smm      op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
17043219639Smm      tmode = insn_data[icode].operand[0].mode;
17044219639Smm      mode1 = insn_data[icode].operand[1].mode;
17045219639Smm      mode2 = insn_data[icode].operand[2].mode;
17046219639Smm      mode3 = insn_data[icode].operand[3].mode;
17047219639Smm
17048219639Smm      if (! (*insn_data[icode].operand[1].predicate) (op0, mode1))
17049219639Smm	{
17050219639Smm	  op0 = copy_to_reg (op0);
17051219639Smm	  op0 = simplify_gen_subreg (mode1, op0, GET_MODE (op0), 0);
17052219639Smm	}
17053219639Smm      if (! (*insn_data[icode].operand[2].predicate) (op1, mode2))
17054219639Smm	{
17055219639Smm	  op1 = copy_to_reg (op1);
17056219639Smm	  op1 = simplify_gen_subreg (mode2, op1, GET_MODE (op1), 0);
17057219639Smm	}
17058219639Smm      if (! (*insn_data[icode].operand[3].predicate) (op2, mode3))
17059219639Smm	{
17060219639Smm	  error ("shift must be an immediate");
17061219639Smm	  return const0_rtx;
17062219639Smm	}
17063219639Smm      target = gen_reg_rtx (mode);
17064219639Smm      pat = GEN_FCN (icode) (simplify_gen_subreg (tmode, target, mode, 0),
17065219639Smm			     op0, op1, op2);
17066219639Smm      if (! pat)
17067219639Smm	return 0;
17068219639Smm      emit_insn (pat);
17069219639Smm      return target;
17070219639Smm
17071251212Spfg    case IX86_BUILTIN_MOVNTSD:
17072251212Spfg      return ix86_expand_store_builtin (CODE_FOR_sse4a_vmmovntv2df, arglist);
17073251212Spfg
17074251212Spfg    case IX86_BUILTIN_MOVNTSS:
17075251212Spfg      return ix86_expand_store_builtin (CODE_FOR_sse4a_vmmovntv4sf, arglist);
17076251212Spfg
17077251212Spfg    case IX86_BUILTIN_INSERTQ:
17078251212Spfg    case IX86_BUILTIN_EXTRQ:
17079251212Spfg      icode = (fcode == IX86_BUILTIN_EXTRQ
17080251212Spfg               ? CODE_FOR_sse4a_extrq
17081251212Spfg               : CODE_FOR_sse4a_insertq);
17082251212Spfg      arg0 = TREE_VALUE (arglist);
17083251212Spfg      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
17084251212Spfg      op0 = expand_normal (arg0);
17085251212Spfg      op1 = expand_normal (arg1);
17086251212Spfg      tmode = insn_data[icode].operand[0].mode;
17087251212Spfg      mode1 = insn_data[icode].operand[1].mode;
17088251212Spfg      mode2 = insn_data[icode].operand[2].mode;
17089251212Spfg      if (! (*insn_data[icode].operand[1].predicate) (op0, mode1))
17090251212Spfg        op0 = copy_to_mode_reg (mode1, op0);
17091251212Spfg      if (! (*insn_data[icode].operand[2].predicate) (op1, mode2))
17092251212Spfg        op1 = copy_to_mode_reg (mode2, op1);
17093251212Spfg      if (optimize || target == 0
17094251212Spfg          || GET_MODE (target) != tmode
17095251212Spfg          || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
17096251212Spfg        target = gen_reg_rtx (tmode);
17097251212Spfg      pat = GEN_FCN (icode) (target, op0, op1);
17098251212Spfg      if (! pat)
17099251212Spfg        return NULL_RTX;
17100251212Spfg      emit_insn (pat);
17101251212Spfg      return target;
17102251212Spfg
17103251212Spfg    case IX86_BUILTIN_EXTRQI:
17104251212Spfg      icode = CODE_FOR_sse4a_extrqi;
17105251212Spfg      arg0 = TREE_VALUE (arglist);
17106251212Spfg      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
17107251212Spfg      arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
17108251212Spfg      op0 = expand_normal (arg0);
17109251212Spfg      op1 = expand_normal (arg1);
17110251212Spfg      op2 = expand_normal (arg2);
17111251212Spfg      tmode = insn_data[icode].operand[0].mode;
17112251212Spfg      mode1 = insn_data[icode].operand[1].mode;
17113251212Spfg      mode2 = insn_data[icode].operand[2].mode;
17114251212Spfg      mode3 = insn_data[icode].operand[3].mode;
17115251212Spfg      if (! (*insn_data[icode].operand[1].predicate) (op0, mode1))
17116251212Spfg        op0 = copy_to_mode_reg (mode1, op0);
17117251212Spfg      if (! (*insn_data[icode].operand[2].predicate) (op1, mode2))
17118251212Spfg        {
17119251212Spfg          error ("index mask must be an immediate");
17120251212Spfg          return gen_reg_rtx (tmode);
17121251212Spfg        }
17122251212Spfg      if (! (*insn_data[icode].operand[3].predicate) (op2, mode3))
17123251212Spfg        {
17124251212Spfg          error ("length mask must be an immediate");
17125251212Spfg          return gen_reg_rtx (tmode);
17126251212Spfg        }
17127251212Spfg      if (optimize || target == 0
17128251212Spfg          || GET_MODE (target) != tmode
17129251212Spfg          || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
17130251212Spfg        target = gen_reg_rtx (tmode);
17131251212Spfg      pat = GEN_FCN (icode) (target, op0, op1, op2);
17132251212Spfg      if (! pat)
17133251212Spfg        return NULL_RTX;
17134251212Spfg      emit_insn (pat);
17135251212Spfg      return target;
17136251212Spfg
17137251212Spfg    case IX86_BUILTIN_INSERTQI:
17138251212Spfg      icode = CODE_FOR_sse4a_insertqi;
17139251212Spfg      arg0 = TREE_VALUE (arglist);
17140251212Spfg      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
17141251212Spfg      arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
17142251212Spfg      arg3 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (arglist))));
17143251212Spfg      op0 = expand_normal (arg0);
17144251212Spfg      op1 = expand_normal (arg1);
17145251212Spfg      op2 = expand_normal (arg2);
17146251212Spfg      op3 = expand_normal (arg3);
17147251212Spfg      tmode = insn_data[icode].operand[0].mode;
17148251212Spfg      mode1 = insn_data[icode].operand[1].mode;
17149251212Spfg      mode2 = insn_data[icode].operand[2].mode;
17150251212Spfg      mode3 = insn_data[icode].operand[3].mode;
17151251212Spfg      mode4 = insn_data[icode].operand[4].mode;
17152251212Spfg
17153251212Spfg      if (! (*insn_data[icode].operand[1].predicate) (op0, mode1))
17154251212Spfg        op0 = copy_to_mode_reg (mode1, op0);
17155251212Spfg
17156251212Spfg      if (! (*insn_data[icode].operand[2].predicate) (op1, mode2))
17157251212Spfg        op1 = copy_to_mode_reg (mode2, op1);
17158251212Spfg
17159251212Spfg      if (! (*insn_data[icode].operand[3].predicate) (op2, mode3))
17160251212Spfg        {
17161251212Spfg          error ("index mask must be an immediate");
17162251212Spfg          return gen_reg_rtx (tmode);
17163251212Spfg        }
17164251212Spfg      if (! (*insn_data[icode].operand[4].predicate) (op3, mode4))
17165251212Spfg        {
17166251212Spfg          error ("length mask must be an immediate");
17167251212Spfg          return gen_reg_rtx (tmode);
17168251212Spfg        }
17169251212Spfg      if (optimize || target == 0
17170251212Spfg          || GET_MODE (target) != tmode
17171251212Spfg          || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
17172251212Spfg        target = gen_reg_rtx (tmode);
17173251212Spfg      pat = GEN_FCN (icode) (target, op0, op1, op2, op3);
17174251212Spfg      if (! pat)
17175251212Spfg        return NULL_RTX;
17176251212Spfg      emit_insn (pat);
17177251212Spfg      return target;
17178251212Spfg
17179169705Skan    case IX86_BUILTIN_VEC_INIT_V2SI:
17180169705Skan    case IX86_BUILTIN_VEC_INIT_V4HI:
17181169705Skan    case IX86_BUILTIN_VEC_INIT_V8QI:
17182169705Skan      return ix86_expand_vec_init_builtin (TREE_TYPE (exp), arglist, target);
17183169705Skan
17184169705Skan    case IX86_BUILTIN_VEC_EXT_V2DF:
17185169705Skan    case IX86_BUILTIN_VEC_EXT_V2DI:
17186169705Skan    case IX86_BUILTIN_VEC_EXT_V4SF:
17187169705Skan    case IX86_BUILTIN_VEC_EXT_V4SI:
17188169705Skan    case IX86_BUILTIN_VEC_EXT_V8HI:
17189171836Skan    case IX86_BUILTIN_VEC_EXT_V16QI:
17190169705Skan    case IX86_BUILTIN_VEC_EXT_V2SI:
17191169705Skan    case IX86_BUILTIN_VEC_EXT_V4HI:
17192169705Skan      return ix86_expand_vec_ext_builtin (arglist, target);
17193169705Skan
17194169705Skan    case IX86_BUILTIN_VEC_SET_V8HI:
17195169705Skan    case IX86_BUILTIN_VEC_SET_V4HI:
17196169705Skan      return ix86_expand_vec_set_builtin (arglist);
17197169705Skan
1719890284Sobrien    default:
1719990284Sobrien      break;
1720052294Sobrien    }
1720190284Sobrien
17202117408Skan  for (i = 0, d = bdesc_2arg; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
1720390284Sobrien    if (d->code == fcode)
1720490284Sobrien      {
1720590284Sobrien	/* Compares are treated specially.  */
17206169705Skan	if (d->icode == CODE_FOR_sse_maskcmpv4sf3
17207169705Skan	    || d->icode == CODE_FOR_sse_vmmaskcmpv4sf3
17208169705Skan	    || d->icode == CODE_FOR_sse2_maskcmpv2df3
17209169705Skan	    || d->icode == CODE_FOR_sse2_vmmaskcmpv2df3)
1721090284Sobrien	  return ix86_expand_sse_compare (d, arglist, target);
1721190284Sobrien
1721290284Sobrien	return ix86_expand_binop_builtin (d->icode, arglist, target);
1721390284Sobrien      }
1721490284Sobrien
17215117408Skan  for (i = 0, d = bdesc_1arg; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
1721690284Sobrien    if (d->code == fcode)
1721790284Sobrien      return ix86_expand_unop_builtin (d->icode, arglist, target, 0);
1721890284Sobrien
17219117408Skan  for (i = 0, d = bdesc_comi; i < ARRAY_SIZE (bdesc_comi); i++, d++)
1722090284Sobrien    if (d->code == fcode)
1722190284Sobrien      return ix86_expand_sse_comi (d, arglist, target);
1722290284Sobrien
17223169705Skan  gcc_unreachable ();
1722490284Sobrien}
1722590284Sobrien
1722690284Sobrien/* Store OPERAND to the memory after reload is completed.  This means
1722790284Sobrien   that we can't easily use assign_stack_local.  */
1722890284Sobrienrtx
17229132743Skanix86_force_to_memory (enum machine_mode mode, rtx operand)
1723090284Sobrien{
1723190284Sobrien  rtx result;
17232169705Skan
17233169705Skan  gcc_assert (reload_completed);
17234132743Skan  if (TARGET_RED_ZONE)
1723552294Sobrien    {
1723690284Sobrien      result = gen_rtx_MEM (mode,
1723790284Sobrien			    gen_rtx_PLUS (Pmode,
1723890284Sobrien					  stack_pointer_rtx,
1723990284Sobrien					  GEN_INT (-RED_ZONE_SIZE)));
1724090284Sobrien      emit_move_insn (result, operand);
1724152294Sobrien    }
17242132743Skan  else if (!TARGET_RED_ZONE && TARGET_64BIT)
1724390284Sobrien    {
1724490284Sobrien      switch (mode)
1724590284Sobrien	{
1724690284Sobrien	case HImode:
1724790284Sobrien	case SImode:
1724890284Sobrien	  operand = gen_lowpart (DImode, operand);
1724990284Sobrien	  /* FALLTHRU */
1725090284Sobrien	case DImode:
1725190284Sobrien	  emit_insn (
1725290284Sobrien		      gen_rtx_SET (VOIDmode,
1725390284Sobrien				   gen_rtx_MEM (DImode,
1725490284Sobrien						gen_rtx_PRE_DEC (DImode,
1725590284Sobrien							stack_pointer_rtx)),
1725690284Sobrien				   operand));
1725790284Sobrien	  break;
1725890284Sobrien	default:
17259169705Skan	  gcc_unreachable ();
1726090284Sobrien	}
1726190284Sobrien      result = gen_rtx_MEM (mode, stack_pointer_rtx);
1726290284Sobrien    }
1726352294Sobrien  else
1726452294Sobrien    {
1726590284Sobrien      switch (mode)
1726690284Sobrien	{
1726790284Sobrien	case DImode:
1726890284Sobrien	  {
1726990284Sobrien	    rtx operands[2];
1727090284Sobrien	    split_di (&operand, 1, operands, operands + 1);
1727190284Sobrien	    emit_insn (
1727290284Sobrien			gen_rtx_SET (VOIDmode,
1727390284Sobrien				     gen_rtx_MEM (SImode,
1727490284Sobrien						  gen_rtx_PRE_DEC (Pmode,
1727590284Sobrien							stack_pointer_rtx)),
1727690284Sobrien				     operands[1]));
1727790284Sobrien	    emit_insn (
1727890284Sobrien			gen_rtx_SET (VOIDmode,
1727990284Sobrien				     gen_rtx_MEM (SImode,
1728090284Sobrien						  gen_rtx_PRE_DEC (Pmode,
1728190284Sobrien							stack_pointer_rtx)),
1728290284Sobrien				     operands[0]));
1728390284Sobrien	  }
1728490284Sobrien	  break;
1728590284Sobrien	case HImode:
17286169705Skan	  /* Store HImodes as SImodes.  */
17287169705Skan	  operand = gen_lowpart (SImode, operand);
1728890284Sobrien	  /* FALLTHRU */
1728990284Sobrien	case SImode:
1729090284Sobrien	  emit_insn (
1729190284Sobrien		      gen_rtx_SET (VOIDmode,
1729290284Sobrien				   gen_rtx_MEM (GET_MODE (operand),
1729390284Sobrien						gen_rtx_PRE_DEC (SImode,
1729490284Sobrien							stack_pointer_rtx)),
1729590284Sobrien				   operand));
1729690284Sobrien	  break;
1729790284Sobrien	default:
17298169705Skan	  gcc_unreachable ();
1729990284Sobrien	}
1730090284Sobrien      result = gen_rtx_MEM (mode, stack_pointer_rtx);
1730152294Sobrien    }
1730290284Sobrien  return result;
1730390284Sobrien}
1730452294Sobrien
1730590284Sobrien/* Free operand from the memory.  */
1730690284Sobrienvoid
17307132743Skanix86_free_from_memory (enum machine_mode mode)
1730890284Sobrien{
17309132743Skan  if (!TARGET_RED_ZONE)
1731090284Sobrien    {
1731190284Sobrien      int size;
1731252294Sobrien
1731390284Sobrien      if (mode == DImode || TARGET_64BIT)
1731490284Sobrien	size = 8;
1731590284Sobrien      else
1731690284Sobrien	size = 4;
1731790284Sobrien      /* Use LEA to deallocate stack space.  In peephole2 it will be converted
1731890284Sobrien         to pop or add instruction if registers are available.  */
1731990284Sobrien      emit_insn (gen_rtx_SET (VOIDmode, stack_pointer_rtx,
1732090284Sobrien			      gen_rtx_PLUS (Pmode, stack_pointer_rtx,
1732190284Sobrien					    GEN_INT (size))));
1732290284Sobrien    }
1732390284Sobrien}
1732452294Sobrien
1732590284Sobrien/* Put float CONST_DOUBLE in the constant pool instead of fp regs.
1732690284Sobrien   QImode must go into class Q_REGS.
1732790284Sobrien   Narrow ALL_REGS to GENERAL_REGS.  This supports allowing movsf and
1732890284Sobrien   movdf to do mem-to-mem moves through integer regs.  */
1732990284Sobrienenum reg_class
17330132743Skanix86_preferred_reload_class (rtx x, enum reg_class class)
1733190284Sobrien{
17332169705Skan  enum machine_mode mode = GET_MODE (x);
17333169705Skan
17334169705Skan  /* We're only allowed to return a subclass of CLASS.  Many of the
17335169705Skan     following checks fail for NO_REGS, so eliminate that early.  */
17336169705Skan  if (class == NO_REGS)
17337117408Skan    return NO_REGS;
17338169705Skan
17339169705Skan  /* All classes can load zeros.  */
17340169705Skan  if (x == CONST0_RTX (mode))
17341169705Skan    return class;
17342169705Skan
17343169705Skan  /* Force constants into memory if we are loading a (nonzero) constant into
17344169705Skan     an MMX or SSE register.  This is because there are no MMX/SSE instructions
17345169705Skan     to load from a constant.  */
17346169705Skan  if (CONSTANT_P (x)
17347169705Skan      && (MAYBE_MMX_CLASS_P (class) || MAYBE_SSE_CLASS_P (class)))
17348169705Skan    return NO_REGS;
17349169705Skan
17350169705Skan  /* Prefer SSE regs only, if we can use them for math.  */
17351169705Skan  if (TARGET_SSE_MATH && !TARGET_MIX_SSE_I387 && SSE_FLOAT_MODE_P (mode))
17352169705Skan    return SSE_CLASS_P (class) ? class : NO_REGS;
17353169705Skan
17354169705Skan  /* Floating-point constants need more complex checks.  */
1735590284Sobrien  if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) != VOIDmode)
1735652294Sobrien    {
17357169705Skan      /* General regs can load everything.  */
17358169705Skan      if (reg_class_subset_p (class, GENERAL_REGS))
17359169705Skan        return class;
17360169705Skan
17361169705Skan      /* Floats can load 0 and 1 plus some others.  Note that we eliminated
17362169705Skan	 zero above.  We only want to wind up preferring 80387 registers if
17363169705Skan	 we plan on doing computation with them.  */
17364169705Skan      if (TARGET_80387
17365169705Skan	  && standard_80387_constant_p (x))
1736690284Sobrien	{
17367169705Skan	  /* Limit class to non-sse.  */
17368169705Skan	  if (class == FLOAT_SSE_REGS)
17369169705Skan	    return FLOAT_REGS;
17370169705Skan	  if (class == FP_TOP_SSE_REGS)
17371169705Skan	    return FP_TOP_REG;
17372169705Skan	  if (class == FP_SECOND_SSE_REGS)
17373169705Skan	    return FP_SECOND_REG;
17374169705Skan	  if (class == FLOAT_INT_REGS || class == FLOAT_REGS)
1737590284Sobrien	    return class;
1737690284Sobrien	}
17377169705Skan
17378169705Skan      return NO_REGS;
1737990284Sobrien    }
17380169705Skan
17381169705Skan  /* Generally when we see PLUS here, it's the function invariant
17382169705Skan     (plus soft-fp const_int).  Which can only be computed into general
17383169705Skan     regs.  */
17384169705Skan  if (GET_CODE (x) == PLUS)
17385169705Skan    return reg_class_subset_p (class, GENERAL_REGS) ? class : NO_REGS;
17386169705Skan
17387169705Skan  /* QImode constants are easy to load, but non-constant QImode data
17388169705Skan     must go into Q_REGS.  */
17389169705Skan  if (GET_MODE (x) == QImode && !CONSTANT_P (x))
17390169705Skan    {
17391169705Skan      if (reg_class_subset_p (class, Q_REGS))
17392169705Skan	return class;
17393169705Skan      if (reg_class_subset_p (Q_REGS, class))
17394169705Skan	return Q_REGS;
17395169705Skan      return NO_REGS;
17396169705Skan    }
17397169705Skan
1739890284Sobrien  return class;
1739990284Sobrien}
1740090284Sobrien
17401169705Skan/* Discourage putting floating-point values in SSE registers unless
17402169705Skan   SSE math is being used, and likewise for the 387 registers.  */
17403169705Skanenum reg_class
17404169705Skanix86_preferred_output_reload_class (rtx x, enum reg_class class)
17405169705Skan{
17406169705Skan  enum machine_mode mode = GET_MODE (x);
17407169705Skan
17408169705Skan  /* Restrict the output reload class to the register bank that we are doing
17409169705Skan     math on.  If we would like not to return a subset of CLASS, reject this
17410169705Skan     alternative: if reload cannot do this, it will still use its choice.  */
17411169705Skan  mode = GET_MODE (x);
17412169705Skan  if (TARGET_SSE_MATH && SSE_FLOAT_MODE_P (mode))
17413169705Skan    return MAYBE_SSE_CLASS_P (class) ? SSE_REGS : NO_REGS;
17414169705Skan
17415169705Skan  if (TARGET_80387 && SCALAR_FLOAT_MODE_P (mode))
17416169705Skan    {
17417169705Skan      if (class == FP_TOP_SSE_REGS)
17418169705Skan	return FP_TOP_REG;
17419169705Skan      else if (class == FP_SECOND_SSE_REGS)
17420169705Skan	return FP_SECOND_REG;
17421169705Skan      else
17422169705Skan	return FLOAT_CLASS_P (class) ? class : NO_REGS;
17423169705Skan    }
17424169705Skan
17425169705Skan  return class;
17426169705Skan}
17427169705Skan
1742890284Sobrien/* If we are copying between general and FP registers, we need a memory
1742990284Sobrien   location. The same is true for SSE and MMX registers.
1743090284Sobrien
1743190284Sobrien   The macro can't work reliably when one of the CLASSES is class containing
1743290284Sobrien   registers from multiple units (SSE, MMX, integer).  We avoid this by never
1743390284Sobrien   combining those units in single alternative in the machine description.
1743490284Sobrien   Ensure that this constraint holds to avoid unexpected surprises.
1743590284Sobrien
1743690284Sobrien   When STRICT is false, we are being called from REGISTER_MOVE_COST, so do not
1743790284Sobrien   enforce these sanity checks.  */
17438169705Skan
1743990284Sobrienint
17440132743Skanix86_secondary_memory_needed (enum reg_class class1, enum reg_class class2,
17441132743Skan			      enum machine_mode mode, int strict)
1744290284Sobrien{
1744390284Sobrien  if (MAYBE_FLOAT_CLASS_P (class1) != FLOAT_CLASS_P (class1)
1744490284Sobrien      || MAYBE_FLOAT_CLASS_P (class2) != FLOAT_CLASS_P (class2)
1744590284Sobrien      || MAYBE_SSE_CLASS_P (class1) != SSE_CLASS_P (class1)
1744690284Sobrien      || MAYBE_SSE_CLASS_P (class2) != SSE_CLASS_P (class2)
1744790284Sobrien      || MAYBE_MMX_CLASS_P (class1) != MMX_CLASS_P (class1)
1744890284Sobrien      || MAYBE_MMX_CLASS_P (class2) != MMX_CLASS_P (class2))
1744990284Sobrien    {
17450169705Skan      gcc_assert (!strict);
17451169705Skan      return true;
1745252294Sobrien    }
17453169705Skan
17454169705Skan  if (FLOAT_CLASS_P (class1) != FLOAT_CLASS_P (class2))
17455169705Skan    return true;
17456169705Skan
17457169705Skan  /* ??? This is a lie.  We do have moves between mmx/general, and for
17458169705Skan     mmx/sse2.  But by saying we need secondary memory we discourage the
17459169705Skan     register allocator from using the mmx registers unless needed.  */
17460169705Skan  if (MMX_CLASS_P (class1) != MMX_CLASS_P (class2))
17461169705Skan    return true;
17462169705Skan
17463169705Skan  if (SSE_CLASS_P (class1) != SSE_CLASS_P (class2))
17464169705Skan    {
17465169705Skan      /* SSE1 doesn't have any direct moves from other classes.  */
17466169705Skan      if (!TARGET_SSE2)
17467169705Skan	return true;
17468169705Skan
17469169705Skan      /* If the target says that inter-unit moves are more expensive
17470169705Skan	 than moving through memory, then don't generate them.  */
17471169705Skan      if (!TARGET_INTER_UNIT_MOVES && !optimize_size)
17472169705Skan	return true;
17473169705Skan
17474169705Skan      /* Between SSE and general, we have moves no larger than word size.  */
17475169705Skan      if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
17476169705Skan	return true;
17477169705Skan
17478169705Skan      /* ??? For the cost of one register reformat penalty, we could use
17479169705Skan	 the same instructions to move SFmode and DFmode data, but the
17480169705Skan	 relevant move patterns don't support those alternatives.  */
17481169705Skan      if (mode == SFmode || mode == DFmode)
17482169705Skan	return true;
17483169705Skan    }
17484169705Skan
17485169705Skan  return false;
1748690284Sobrien}
17487169705Skan
17488169705Skan/* Return true if the registers in CLASS cannot represent the change from
17489169705Skan   modes FROM to TO.  */
17490169705Skan
17491169705Skanbool
17492169705Skanix86_cannot_change_mode_class (enum machine_mode from, enum machine_mode to,
17493169705Skan			       enum reg_class class)
17494169705Skan{
17495169705Skan  if (from == to)
17496169705Skan    return false;
17497169705Skan
17498169705Skan  /* x87 registers can't do subreg at all, as all values are reformatted
17499169705Skan     to extended precision.  */
17500169705Skan  if (MAYBE_FLOAT_CLASS_P (class))
17501169705Skan    return true;
17502169705Skan
17503169705Skan  if (MAYBE_SSE_CLASS_P (class) || MAYBE_MMX_CLASS_P (class))
17504169705Skan    {
17505169705Skan      /* Vector registers do not support QI or HImode loads.  If we don't
17506169705Skan	 disallow a change to these modes, reload will assume it's ok to
17507169705Skan	 drop the subreg from (subreg:SI (reg:HI 100) 0).  This affects
17508169705Skan	 the vec_dupv4hi pattern.  */
17509169705Skan      if (GET_MODE_SIZE (from) < 4)
17510169705Skan	return true;
17511169705Skan
17512169705Skan      /* Vector registers do not support subreg with nonzero offsets, which
17513169705Skan	 are otherwise valid for integer registers.  Since we can't see
17514169705Skan	 whether we have a nonzero offset from here, prohibit all
17515169705Skan         nonparadoxical subregs changing size.  */
17516169705Skan      if (GET_MODE_SIZE (to) < GET_MODE_SIZE (from))
17517169705Skan	return true;
17518169705Skan    }
17519169705Skan
17520169705Skan  return false;
17521169705Skan}
17522169705Skan
1752390284Sobrien/* Return the cost of moving data from a register in class CLASS1 to
1752490284Sobrien   one in class CLASS2.
1752552294Sobrien
1752690284Sobrien   It is not required that the cost always equal 2 when FROM is the same as TO;
1752790284Sobrien   on some machines it is expensive to move between registers if they are not
1752890284Sobrien   general registers.  */
17529169705Skan
1753090284Sobrienint
17531132743Skanix86_register_move_cost (enum machine_mode mode, enum reg_class class1,
17532132743Skan			 enum reg_class class2)
1753390284Sobrien{
1753490284Sobrien  /* In case we require secondary memory, compute cost of the store followed
17535132743Skan     by load.  In order to avoid bad register allocation choices, we need
17536104767Skan     for this to be *at least* as high as the symmetric MEMORY_MOVE_COST.  */
17537104767Skan
1753890284Sobrien  if (ix86_secondary_memory_needed (class1, class2, mode, 0))
1753990284Sobrien    {
17540104767Skan      int cost = 1;
17541104767Skan
17542104767Skan      cost += MAX (MEMORY_MOVE_COST (mode, class1, 0),
17543104767Skan		   MEMORY_MOVE_COST (mode, class1, 1));
17544104767Skan      cost += MAX (MEMORY_MOVE_COST (mode, class2, 0),
17545104767Skan		   MEMORY_MOVE_COST (mode, class2, 1));
17546132743Skan
17547104767Skan      /* In case of copying from general_purpose_register we may emit multiple
17548104767Skan         stores followed by single load causing memory size mismatch stall.
17549132743Skan         Count this as arbitrarily high cost of 20.  */
1755090284Sobrien      if (CLASS_MAX_NREGS (class1, mode) > CLASS_MAX_NREGS (class2, mode))
17551104767Skan	cost += 20;
17552104767Skan
17553104767Skan      /* In the case of FP/MMX moves, the registers actually overlap, and we
17554104767Skan	 have to switch modes in order to treat them differently.  */
17555104767Skan      if ((MMX_CLASS_P (class1) && MAYBE_FLOAT_CLASS_P (class2))
17556104767Skan          || (MMX_CLASS_P (class2) && MAYBE_FLOAT_CLASS_P (class1)))
17557104767Skan	cost += 20;
17558104767Skan
17559104767Skan      return cost;
1756090284Sobrien    }
17561104767Skan
1756290284Sobrien  /* Moves between SSE/MMX and integer unit are expensive.  */
1756390284Sobrien  if (MMX_CLASS_P (class1) != MMX_CLASS_P (class2)
1756490284Sobrien      || SSE_CLASS_P (class1) != SSE_CLASS_P (class2))
1756590284Sobrien    return ix86_cost->mmxsse_to_integer;
1756690284Sobrien  if (MAYBE_FLOAT_CLASS_P (class1))
1756790284Sobrien    return ix86_cost->fp_move;
1756890284Sobrien  if (MAYBE_SSE_CLASS_P (class1))
1756990284Sobrien    return ix86_cost->sse_move;
1757090284Sobrien  if (MAYBE_MMX_CLASS_P (class1))
1757190284Sobrien    return ix86_cost->mmx_move;
1757290284Sobrien  return 2;
1757390284Sobrien}
1757452294Sobrien
1757590284Sobrien/* Return 1 if hard register REGNO can hold a value of machine-mode MODE.  */
17576169705Skan
17577169705Skanbool
17578132743Skanix86_hard_regno_mode_ok (int regno, enum machine_mode mode)
1757990284Sobrien{
1758090284Sobrien  /* Flags and only flags can only hold CCmode values.  */
1758190284Sobrien  if (CC_REGNO_P (regno))
1758290284Sobrien    return GET_MODE_CLASS (mode) == MODE_CC;
1758390284Sobrien  if (GET_MODE_CLASS (mode) == MODE_CC
1758490284Sobrien      || GET_MODE_CLASS (mode) == MODE_RANDOM
1758590284Sobrien      || GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)
1758690284Sobrien    return 0;
1758790284Sobrien  if (FP_REGNO_P (regno))
1758890284Sobrien    return VALID_FP_MODE_P (mode);
1758990284Sobrien  if (SSE_REGNO_P (regno))
17590146908Skan    {
17591146908Skan      /* We implement the move patterns for all vector modes into and
17592169705Skan	 out of SSE registers, even when no operation instructions
17593169705Skan	 are available.  */
17594146908Skan      return (VALID_SSE_REG_MODE (mode)
17595146908Skan	      || VALID_SSE2_REG_MODE (mode)
17596146908Skan	      || VALID_MMX_REG_MODE (mode)
17597146908Skan	      || VALID_MMX_REG_MODE_3DNOW (mode));
17598146908Skan    }
1759990284Sobrien  if (MMX_REGNO_P (regno))
17600146908Skan    {
17601146908Skan      /* We implement the move patterns for 3DNOW modes even in MMX mode,
17602169705Skan	 so if the register is available at all, then we can move data of
17603169705Skan	 the given mode into or out of it.  */
17604146908Skan      return (VALID_MMX_REG_MODE (mode)
17605146908Skan	      || VALID_MMX_REG_MODE_3DNOW (mode));
17606146908Skan    }
17607169705Skan
17608169705Skan  if (mode == QImode)
17609169705Skan    {
17610169705Skan      /* Take care for QImode values - they can be in non-QI regs,
17611169705Skan	 but then they do cause partial register stalls.  */
17612169705Skan      if (regno < 4 || TARGET_64BIT)
17613169705Skan	return 1;
17614169705Skan      if (!TARGET_PARTIAL_REG_STALL)
17615169705Skan	return 1;
17616169705Skan      return reload_in_progress || reload_completed;
17617169705Skan    }
17618169705Skan  /* We handle both integer and floats in the general purpose registers.  */
17619169705Skan  else if (VALID_INT_MODE_P (mode))
1762090284Sobrien    return 1;
17621169705Skan  else if (VALID_FP_MODE_P (mode))
17622169705Skan    return 1;
17623169705Skan  /* Lots of MMX code casts 8 byte vector modes to DImode.  If we then go
17624169705Skan     on to use that value in smaller contexts, this can easily force a
17625169705Skan     pseudo to be allocated to GENERAL_REGS.  Since this is no worse than
17626169705Skan     supporting DImode, allow it.  */
17627169705Skan  else if (VALID_MMX_REG_MODE_3DNOW (mode) || VALID_MMX_REG_MODE (mode))
17628169705Skan    return 1;
17629169705Skan
17630169705Skan  return 0;
1763152294Sobrien}
1763290284Sobrien
17633169705Skan/* A subroutine of ix86_modes_tieable_p.  Return true if MODE is a
17634169705Skan   tieable integer mode.  */
17635169705Skan
17636169705Skanstatic bool
17637169705Skanix86_tieable_integer_mode_p (enum machine_mode mode)
17638169705Skan{
17639169705Skan  switch (mode)
17640169705Skan    {
17641169705Skan    case HImode:
17642169705Skan    case SImode:
17643169705Skan      return true;
17644169705Skan
17645169705Skan    case QImode:
17646169705Skan      return TARGET_64BIT || !TARGET_PARTIAL_REG_STALL;
17647169705Skan
17648169705Skan    case DImode:
17649169705Skan      return TARGET_64BIT;
17650169705Skan
17651169705Skan    default:
17652169705Skan      return false;
17653169705Skan    }
17654169705Skan}
17655169705Skan
17656169705Skan/* Return true if MODE1 is accessible in a register that can hold MODE2
17657169705Skan   without copying.  That is, all register classes that can hold MODE2
17658169705Skan   can also hold MODE1.  */
17659169705Skan
17660169705Skanbool
17661169705Skanix86_modes_tieable_p (enum machine_mode mode1, enum machine_mode mode2)
17662169705Skan{
17663169705Skan  if (mode1 == mode2)
17664169705Skan    return true;
17665169705Skan
17666169705Skan  if (ix86_tieable_integer_mode_p (mode1)
17667169705Skan      && ix86_tieable_integer_mode_p (mode2))
17668169705Skan    return true;
17669169705Skan
17670169705Skan  /* MODE2 being XFmode implies fp stack or general regs, which means we
17671169705Skan     can tie any smaller floating point modes to it.  Note that we do not
17672169705Skan     tie this with TFmode.  */
17673169705Skan  if (mode2 == XFmode)
17674169705Skan    return mode1 == SFmode || mode1 == DFmode;
17675169705Skan
17676169705Skan  /* MODE2 being DFmode implies fp stack, general or sse regs, which means
17677169705Skan     that we can tie it with SFmode.  */
17678169705Skan  if (mode2 == DFmode)
17679169705Skan    return mode1 == SFmode;
17680169705Skan
17681169705Skan  /* If MODE2 is only appropriate for an SSE register, then tie with
17682169705Skan     any other mode acceptable to SSE registers.  */
17683169705Skan  if (GET_MODE_SIZE (mode2) >= 8
17684169705Skan      && ix86_hard_regno_mode_ok (FIRST_SSE_REG, mode2))
17685169705Skan    return ix86_hard_regno_mode_ok (FIRST_SSE_REG, mode1);
17686169705Skan
17687169705Skan  /* If MODE2 is appropriate for an MMX (or SSE) register, then tie
17688169705Skan     with any other mode acceptable to MMX registers.  */
17689169705Skan  if (GET_MODE_SIZE (mode2) == 8
17690169705Skan      && ix86_hard_regno_mode_ok (FIRST_MMX_REG, mode2))
17691169705Skan    return ix86_hard_regno_mode_ok (FIRST_MMX_REG, mode1);
17692169705Skan
17693169705Skan  return false;
17694169705Skan}
17695169705Skan
1769690284Sobrien/* Return the cost of moving data of mode M between a
1769790284Sobrien   register and memory.  A value of 2 is the default; this cost is
1769890284Sobrien   relative to those in `REGISTER_MOVE_COST'.
1769990284Sobrien
1770090284Sobrien   If moving between registers and memory is more expensive than
1770190284Sobrien   between two registers, you should define this macro to express the
1770290284Sobrien   relative cost.
1770390284Sobrien
1770490284Sobrien   Model also increased moving costs of QImode registers in non
1770590284Sobrien   Q_REGS classes.
1770690284Sobrien */
1770790284Sobrienint
17708132743Skanix86_memory_move_cost (enum machine_mode mode, enum reg_class class, int in)
1770990284Sobrien{
1771090284Sobrien  if (FLOAT_CLASS_P (class))
1771190284Sobrien    {
1771290284Sobrien      int index;
1771390284Sobrien      switch (mode)
1771490284Sobrien	{
1771590284Sobrien	  case SFmode:
1771690284Sobrien	    index = 0;
1771790284Sobrien	    break;
1771890284Sobrien	  case DFmode:
1771990284Sobrien	    index = 1;
1772090284Sobrien	    break;
1772190284Sobrien	  case XFmode:
1772290284Sobrien	    index = 2;
1772390284Sobrien	    break;
1772490284Sobrien	  default:
1772590284Sobrien	    return 100;
1772690284Sobrien	}
1772790284Sobrien      return in ? ix86_cost->fp_load [index] : ix86_cost->fp_store [index];
1772890284Sobrien    }
1772990284Sobrien  if (SSE_CLASS_P (class))
1773090284Sobrien    {
1773190284Sobrien      int index;
1773290284Sobrien      switch (GET_MODE_SIZE (mode))
1773390284Sobrien	{
1773490284Sobrien	  case 4:
1773590284Sobrien	    index = 0;
1773690284Sobrien	    break;
1773790284Sobrien	  case 8:
1773890284Sobrien	    index = 1;
1773990284Sobrien	    break;
1774090284Sobrien	  case 16:
1774190284Sobrien	    index = 2;
1774290284Sobrien	    break;
1774390284Sobrien	  default:
1774490284Sobrien	    return 100;
1774590284Sobrien	}
1774690284Sobrien      return in ? ix86_cost->sse_load [index] : ix86_cost->sse_store [index];
1774790284Sobrien    }
1774890284Sobrien  if (MMX_CLASS_P (class))
1774990284Sobrien    {
1775090284Sobrien      int index;
1775190284Sobrien      switch (GET_MODE_SIZE (mode))
1775290284Sobrien	{
1775390284Sobrien	  case 4:
1775490284Sobrien	    index = 0;
1775590284Sobrien	    break;
1775690284Sobrien	  case 8:
1775790284Sobrien	    index = 1;
1775890284Sobrien	    break;
1775990284Sobrien	  default:
1776090284Sobrien	    return 100;
1776190284Sobrien	}
1776290284Sobrien      return in ? ix86_cost->mmx_load [index] : ix86_cost->mmx_store [index];
1776390284Sobrien    }
1776490284Sobrien  switch (GET_MODE_SIZE (mode))
1776590284Sobrien    {
1776690284Sobrien      case 1:
1776790284Sobrien	if (in)
1776890284Sobrien	  return (Q_CLASS_P (class) ? ix86_cost->int_load[0]
1776990284Sobrien		  : ix86_cost->movzbl_load);
1777090284Sobrien	else
1777190284Sobrien	  return (Q_CLASS_P (class) ? ix86_cost->int_store[0]
1777290284Sobrien		  : ix86_cost->int_store[0] + 4);
1777390284Sobrien	break;
1777490284Sobrien      case 2:
1777590284Sobrien	return in ? ix86_cost->int_load[1] : ix86_cost->int_store[1];
1777690284Sobrien      default:
1777790284Sobrien	/* Compute number of 32bit moves needed.  TFmode is moved as XFmode.  */
1777890284Sobrien	if (mode == TFmode)
1777990284Sobrien	  mode = XFmode;
1778090284Sobrien	return ((in ? ix86_cost->int_load[2] : ix86_cost->int_store[2])
17781132743Skan		* (((int) GET_MODE_SIZE (mode)
17782132743Skan		    + UNITS_PER_WORD - 1) / UNITS_PER_WORD));
1778390284Sobrien    }
1778490284Sobrien}
1778590284Sobrien
17786132743Skan/* Compute a (partial) cost for rtx X.  Return true if the complete
17787132743Skan   cost has been computed, and false if subexpressions should be
17788132743Skan   scanned.  In either case, *TOTAL contains the cost result.  */
17789132743Skan
17790132743Skanstatic bool
17791132743Skanix86_rtx_costs (rtx x, int code, int outer_code, int *total)
17792132743Skan{
17793132743Skan  enum machine_mode mode = GET_MODE (x);
17794132743Skan
17795132743Skan  switch (code)
17796132743Skan    {
17797132743Skan    case CONST_INT:
17798132743Skan    case CONST:
17799132743Skan    case LABEL_REF:
17800132743Skan    case SYMBOL_REF:
17801169705Skan      if (TARGET_64BIT && !x86_64_immediate_operand (x, VOIDmode))
17802132743Skan	*total = 3;
17803169705Skan      else if (TARGET_64BIT && !x86_64_zext_immediate_operand (x, VOIDmode))
17804132743Skan	*total = 2;
17805132743Skan      else if (flag_pic && SYMBOLIC_CONST (x)
17806132743Skan	       && (!TARGET_64BIT
17807132743Skan		   || (!GET_CODE (x) != LABEL_REF
17808132743Skan		       && (GET_CODE (x) != SYMBOL_REF
17809132743Skan		           || !SYMBOL_REF_LOCAL_P (x)))))
17810132743Skan	*total = 1;
17811132743Skan      else
17812132743Skan	*total = 0;
17813132743Skan      return true;
17814132743Skan
17815132743Skan    case CONST_DOUBLE:
17816132743Skan      if (mode == VOIDmode)
17817132743Skan	*total = 0;
17818132743Skan      else
17819132743Skan	switch (standard_80387_constant_p (x))
17820132743Skan	  {
17821132743Skan	  case 1: /* 0.0 */
17822132743Skan	    *total = 1;
17823132743Skan	    break;
17824132743Skan	  default: /* Other constants */
17825132743Skan	    *total = 2;
17826132743Skan	    break;
17827132743Skan	  case 0:
17828132743Skan	  case -1:
17829132743Skan	    /* Start with (MEM (SYMBOL_REF)), since that's where
17830132743Skan	       it'll probably end up.  Add a penalty for size.  */
17831132743Skan	    *total = (COSTS_N_INSNS (1)
17832132743Skan		      + (flag_pic != 0 && !TARGET_64BIT)
17833132743Skan		      + (mode == SFmode ? 0 : mode == DFmode ? 1 : 2));
17834132743Skan	    break;
17835132743Skan	  }
17836132743Skan      return true;
17837132743Skan
17838132743Skan    case ZERO_EXTEND:
17839132743Skan      /* The zero extensions is often completely free on x86_64, so make
17840132743Skan	 it as cheap as possible.  */
17841132743Skan      if (TARGET_64BIT && mode == DImode
17842132743Skan	  && GET_MODE (XEXP (x, 0)) == SImode)
17843132743Skan	*total = 1;
17844132743Skan      else if (TARGET_ZERO_EXTEND_WITH_AND)
17845169705Skan	*total = ix86_cost->add;
17846132743Skan      else
17847169705Skan	*total = ix86_cost->movzx;
17848132743Skan      return false;
17849132743Skan
17850132743Skan    case SIGN_EXTEND:
17851169705Skan      *total = ix86_cost->movsx;
17852132743Skan      return false;
17853132743Skan
17854132743Skan    case ASHIFT:
17855132743Skan      if (GET_CODE (XEXP (x, 1)) == CONST_INT
17856132743Skan	  && (GET_MODE (XEXP (x, 0)) != DImode || TARGET_64BIT))
17857132743Skan	{
17858132743Skan	  HOST_WIDE_INT value = INTVAL (XEXP (x, 1));
17859132743Skan	  if (value == 1)
17860132743Skan	    {
17861169705Skan	      *total = ix86_cost->add;
17862132743Skan	      return false;
17863132743Skan	    }
17864132743Skan	  if ((value == 2 || value == 3)
17865132743Skan	      && ix86_cost->lea <= ix86_cost->shift_const)
17866132743Skan	    {
17867169705Skan	      *total = ix86_cost->lea;
17868132743Skan	      return false;
17869132743Skan	    }
17870132743Skan	}
17871132743Skan      /* FALLTHRU */
17872132743Skan
17873132743Skan    case ROTATE:
17874132743Skan    case ASHIFTRT:
17875132743Skan    case LSHIFTRT:
17876132743Skan    case ROTATERT:
17877132743Skan      if (!TARGET_64BIT && GET_MODE (XEXP (x, 0)) == DImode)
17878132743Skan	{
17879132743Skan	  if (GET_CODE (XEXP (x, 1)) == CONST_INT)
17880132743Skan	    {
17881132743Skan	      if (INTVAL (XEXP (x, 1)) > 32)
17882169705Skan		*total = ix86_cost->shift_const + COSTS_N_INSNS (2);
17883132743Skan	      else
17884169705Skan		*total = ix86_cost->shift_const * 2;
17885132743Skan	    }
17886132743Skan	  else
17887132743Skan	    {
17888132743Skan	      if (GET_CODE (XEXP (x, 1)) == AND)
17889169705Skan		*total = ix86_cost->shift_var * 2;
17890132743Skan	      else
17891169705Skan		*total = ix86_cost->shift_var * 6 + COSTS_N_INSNS (2);
17892132743Skan	    }
17893132743Skan	}
17894132743Skan      else
17895132743Skan	{
17896132743Skan	  if (GET_CODE (XEXP (x, 1)) == CONST_INT)
17897169705Skan	    *total = ix86_cost->shift_const;
17898132743Skan	  else
17899169705Skan	    *total = ix86_cost->shift_var;
17900132743Skan	}
17901132743Skan      return false;
17902132743Skan
17903132743Skan    case MULT:
17904132743Skan      if (FLOAT_MODE_P (mode))
17905132743Skan	{
17906169705Skan	  *total = ix86_cost->fmul;
17907169705Skan	  return false;
17908169705Skan	}
17909169705Skan      else
17910169705Skan	{
17911169705Skan	  rtx op0 = XEXP (x, 0);
17912169705Skan	  rtx op1 = XEXP (x, 1);
17913132743Skan	  int nbits;
17914169705Skan	  if (GET_CODE (XEXP (x, 1)) == CONST_INT)
17915169705Skan	    {
17916169705Skan	      unsigned HOST_WIDE_INT value = INTVAL (XEXP (x, 1));
17917169705Skan	      for (nbits = 0; value != 0; value &= value - 1)
17918169705Skan	        nbits++;
17919169705Skan	    }
17920169705Skan	  else
17921169705Skan	    /* This is arbitrary.  */
17922169705Skan	    nbits = 7;
17923132743Skan
17924169705Skan	  /* Compute costs correctly for widening multiplication.  */
17925169705Skan	  if ((GET_CODE (op0) == SIGN_EXTEND || GET_CODE (op1) == ZERO_EXTEND)
17926169705Skan	      && GET_MODE_SIZE (GET_MODE (XEXP (op0, 0))) * 2
17927169705Skan	         == GET_MODE_SIZE (mode))
17928169705Skan	    {
17929169705Skan	      int is_mulwiden = 0;
17930169705Skan	      enum machine_mode inner_mode = GET_MODE (op0);
17931132743Skan
17932169705Skan	      if (GET_CODE (op0) == GET_CODE (op1))
17933169705Skan		is_mulwiden = 1, op1 = XEXP (op1, 0);
17934169705Skan	      else if (GET_CODE (op1) == CONST_INT)
17935169705Skan		{
17936169705Skan		  if (GET_CODE (op0) == SIGN_EXTEND)
17937169705Skan		    is_mulwiden = trunc_int_for_mode (INTVAL (op1), inner_mode)
17938169705Skan			          == INTVAL (op1);
17939169705Skan		  else
17940169705Skan		    is_mulwiden = !(INTVAL (op1) & ~GET_MODE_MASK (inner_mode));
17941169705Skan	        }
17942169705Skan
17943169705Skan	      if (is_mulwiden)
17944169705Skan	        op0 = XEXP (op0, 0), mode = GET_MODE (op0);
17945169705Skan	    }
17946169705Skan
17947169705Skan  	  *total = (ix86_cost->mult_init[MODE_INDEX (mode)]
17948169705Skan		    + nbits * ix86_cost->mult_bit
17949169705Skan	            + rtx_cost (op0, outer_code) + rtx_cost (op1, outer_code));
17950169705Skan
17951169705Skan          return true;
17952132743Skan	}
17953132743Skan
17954132743Skan    case DIV:
17955132743Skan    case UDIV:
17956132743Skan    case MOD:
17957132743Skan    case UMOD:
17958132743Skan      if (FLOAT_MODE_P (mode))
17959169705Skan	*total = ix86_cost->fdiv;
17960132743Skan      else
17961169705Skan	*total = ix86_cost->divide[MODE_INDEX (mode)];
17962132743Skan      return false;
17963132743Skan
17964132743Skan    case PLUS:
17965132743Skan      if (FLOAT_MODE_P (mode))
17966169705Skan	*total = ix86_cost->fadd;
17967169705Skan      else if (GET_MODE_CLASS (mode) == MODE_INT
17968132743Skan	       && GET_MODE_BITSIZE (mode) <= GET_MODE_BITSIZE (Pmode))
17969132743Skan	{
17970132743Skan	  if (GET_CODE (XEXP (x, 0)) == PLUS
17971132743Skan	      && GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT
17972132743Skan	      && GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 1)) == CONST_INT
17973132743Skan	      && CONSTANT_P (XEXP (x, 1)))
17974132743Skan	    {
17975132743Skan	      HOST_WIDE_INT val = INTVAL (XEXP (XEXP (XEXP (x, 0), 0), 1));
17976132743Skan	      if (val == 2 || val == 4 || val == 8)
17977132743Skan		{
17978169705Skan		  *total = ix86_cost->lea;
17979132743Skan		  *total += rtx_cost (XEXP (XEXP (x, 0), 1), outer_code);
17980132743Skan		  *total += rtx_cost (XEXP (XEXP (XEXP (x, 0), 0), 0),
17981132743Skan				      outer_code);
17982132743Skan		  *total += rtx_cost (XEXP (x, 1), outer_code);
17983132743Skan		  return true;
17984132743Skan		}
17985132743Skan	    }
17986132743Skan	  else if (GET_CODE (XEXP (x, 0)) == MULT
17987132743Skan		   && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)
17988132743Skan	    {
17989132743Skan	      HOST_WIDE_INT val = INTVAL (XEXP (XEXP (x, 0), 1));
17990132743Skan	      if (val == 2 || val == 4 || val == 8)
17991132743Skan		{
17992169705Skan		  *total = ix86_cost->lea;
17993132743Skan		  *total += rtx_cost (XEXP (XEXP (x, 0), 0), outer_code);
17994132743Skan		  *total += rtx_cost (XEXP (x, 1), outer_code);
17995132743Skan		  return true;
17996132743Skan		}
17997132743Skan	    }
17998132743Skan	  else if (GET_CODE (XEXP (x, 0)) == PLUS)
17999132743Skan	    {
18000169705Skan	      *total = ix86_cost->lea;
18001132743Skan	      *total += rtx_cost (XEXP (XEXP (x, 0), 0), outer_code);
18002132743Skan	      *total += rtx_cost (XEXP (XEXP (x, 0), 1), outer_code);
18003132743Skan	      *total += rtx_cost (XEXP (x, 1), outer_code);
18004132743Skan	      return true;
18005132743Skan	    }
18006132743Skan	}
18007132743Skan      /* FALLTHRU */
18008132743Skan
18009132743Skan    case MINUS:
18010132743Skan      if (FLOAT_MODE_P (mode))
18011132743Skan	{
18012169705Skan	  *total = ix86_cost->fadd;
18013132743Skan	  return false;
18014132743Skan	}
18015132743Skan      /* FALLTHRU */
18016132743Skan
18017132743Skan    case AND:
18018132743Skan    case IOR:
18019132743Skan    case XOR:
18020132743Skan      if (!TARGET_64BIT && mode == DImode)
18021132743Skan	{
18022169705Skan	  *total = (ix86_cost->add * 2
18023132743Skan		    + (rtx_cost (XEXP (x, 0), outer_code)
18024132743Skan		       << (GET_MODE (XEXP (x, 0)) != DImode))
18025132743Skan		    + (rtx_cost (XEXP (x, 1), outer_code)
18026132743Skan	               << (GET_MODE (XEXP (x, 1)) != DImode)));
18027132743Skan	  return true;
18028132743Skan	}
18029132743Skan      /* FALLTHRU */
18030132743Skan
18031132743Skan    case NEG:
18032132743Skan      if (FLOAT_MODE_P (mode))
18033132743Skan	{
18034169705Skan	  *total = ix86_cost->fchs;
18035132743Skan	  return false;
18036132743Skan	}
18037132743Skan      /* FALLTHRU */
18038132743Skan
18039132743Skan    case NOT:
18040132743Skan      if (!TARGET_64BIT && mode == DImode)
18041169705Skan	*total = ix86_cost->add * 2;
18042132743Skan      else
18043169705Skan	*total = ix86_cost->add;
18044132743Skan      return false;
18045132743Skan
18046169705Skan    case COMPARE:
18047169705Skan      if (GET_CODE (XEXP (x, 0)) == ZERO_EXTRACT
18048169705Skan	  && XEXP (XEXP (x, 0), 1) == const1_rtx
18049169705Skan	  && GET_CODE (XEXP (XEXP (x, 0), 2)) == CONST_INT
18050169705Skan	  && XEXP (x, 1) == const0_rtx)
18051169705Skan	{
18052169705Skan	  /* This kind of construct is implemented using test[bwl].
18053169705Skan	     Treat it as if we had an AND.  */
18054169705Skan	  *total = (ix86_cost->add
18055169705Skan		    + rtx_cost (XEXP (XEXP (x, 0), 0), outer_code)
18056169705Skan		    + rtx_cost (const1_rtx, outer_code));
18057169705Skan	  return true;
18058169705Skan	}
18059169705Skan      return false;
18060169705Skan
18061132743Skan    case FLOAT_EXTEND:
18062146908Skan      if (!TARGET_SSE_MATH
18063146908Skan	  || mode == XFmode
18064146908Skan	  || (mode == DFmode && !TARGET_SSE2))
18065169705Skan	/* For standard 80387 constants, raise the cost to prevent
18066169705Skan	   compress_float_constant() to generate load from memory.  */
18067169705Skan	switch (standard_80387_constant_p (XEXP (x, 0)))
18068169705Skan	  {
18069169705Skan	  case -1:
18070169705Skan	  case 0:
18071169705Skan	    *total = 0;
18072169705Skan	    break;
18073169705Skan	  case 1: /* 0.0 */
18074169705Skan	    *total = 1;
18075169705Skan	    break;
18076169705Skan	  default:
18077169705Skan	    *total = (x86_ext_80387_constants & TUNEMASK
18078169705Skan		      || optimize_size
18079169705Skan		      ? 1 : 0);
18080169705Skan	  }
18081132743Skan      return false;
18082132743Skan
18083132743Skan    case ABS:
18084132743Skan      if (FLOAT_MODE_P (mode))
18085169705Skan	*total = ix86_cost->fabs;
18086132743Skan      return false;
18087132743Skan
18088132743Skan    case SQRT:
18089132743Skan      if (FLOAT_MODE_P (mode))
18090169705Skan	*total = ix86_cost->fsqrt;
18091132743Skan      return false;
18092132743Skan
18093132743Skan    case UNSPEC:
18094132743Skan      if (XINT (x, 1) == UNSPEC_TP)
18095132743Skan	*total = 0;
18096132743Skan      return false;
18097132743Skan
18098132743Skan    default:
18099132743Skan      return false;
18100132743Skan    }
18101132743Skan}
18102132743Skan
18103117408Skan#if TARGET_MACHO
18104117408Skan
18105117408Skanstatic int current_machopic_label_num;
18106117408Skan
18107117408Skan/* Given a symbol name and its associated stub, write out the
18108117408Skan   definition of the stub.  */
18109117408Skan
18110117408Skanvoid
18111132743Skanmachopic_output_stub (FILE *file, const char *symb, const char *stub)
18112117408Skan{
18113117408Skan  unsigned int length;
18114117408Skan  char *binder_name, *symbol_name, lazy_ptr_name[32];
18115117408Skan  int label = ++current_machopic_label_num;
18116117408Skan
18117169705Skan  /* For 64-bit we shouldn't get here.  */
18118169705Skan  gcc_assert (!TARGET_64BIT);
18119169705Skan
18120117408Skan  /* Lose our funky encoding stuff so it doesn't contaminate the stub.  */
18121117408Skan  symb = (*targetm.strip_name_encoding) (symb);
18122117408Skan
18123117408Skan  length = strlen (stub);
18124117408Skan  binder_name = alloca (length + 32);
18125117408Skan  GEN_BINDER_NAME_FOR_STUB (binder_name, stub, length);
18126117408Skan
18127117408Skan  length = strlen (symb);
18128117408Skan  symbol_name = alloca (length + 32);
18129117408Skan  GEN_SYMBOL_NAME_FOR_SYMBOL (symbol_name, symb, length);
18130117408Skan
18131117408Skan  sprintf (lazy_ptr_name, "L%d$lz", label);
18132117408Skan
18133117408Skan  if (MACHOPIC_PURE)
18134169705Skan    switch_to_section (darwin_sections[machopic_picsymbol_stub_section]);
18135117408Skan  else
18136169705Skan    switch_to_section (darwin_sections[machopic_symbol_stub_section]);
18137117408Skan
18138117408Skan  fprintf (file, "%s:\n", stub);
18139117408Skan  fprintf (file, "\t.indirect_symbol %s\n", symbol_name);
18140117408Skan
18141117408Skan  if (MACHOPIC_PURE)
18142117408Skan    {
18143169705Skan      fprintf (file, "\tcall\tLPC$%d\nLPC$%d:\tpopl\t%%eax\n", label, label);
18144169705Skan      fprintf (file, "\tmovl\t%s-LPC$%d(%%eax),%%edx\n", lazy_ptr_name, label);
18145169705Skan      fprintf (file, "\tjmp\t*%%edx\n");
18146117408Skan    }
18147117408Skan  else
18148169705Skan    fprintf (file, "\tjmp\t*%s\n", lazy_ptr_name);
18149132743Skan
18150117408Skan  fprintf (file, "%s:\n", binder_name);
18151132743Skan
18152117408Skan  if (MACHOPIC_PURE)
18153117408Skan    {
18154169705Skan      fprintf (file, "\tlea\t%s-LPC$%d(%%eax),%%eax\n", lazy_ptr_name, label);
18155169705Skan      fprintf (file, "\tpushl\t%%eax\n");
18156117408Skan    }
18157117408Skan  else
18158169705Skan    fprintf (file, "\tpushl\t$%s\n", lazy_ptr_name);
18159117408Skan
18160169705Skan  fprintf (file, "\tjmp\tdyld_stub_binding_helper\n");
18161117408Skan
18162169705Skan  switch_to_section (darwin_sections[machopic_lazy_symbol_ptr_section]);
18163117408Skan  fprintf (file, "%s:\n", lazy_ptr_name);
18164117408Skan  fprintf (file, "\t.indirect_symbol %s\n", symbol_name);
18165117408Skan  fprintf (file, "\t.long %s\n", binder_name);
18166117408Skan}
18167169705Skan
18168169705Skanvoid
18169169705Skandarwin_x86_file_end (void)
18170169705Skan{
18171169705Skan  darwin_file_end ();
18172169705Skan  ix86_file_end ();
18173169705Skan}
18174117408Skan#endif /* TARGET_MACHO */
18175117408Skan
1817696293Sobrien/* Order the registers for register allocator.  */
1817796293Sobrien
1817896293Sobrienvoid
18179132743Skanx86_order_regs_for_local_alloc (void)
1818096293Sobrien{
1818196293Sobrien   int pos = 0;
1818296293Sobrien   int i;
1818396293Sobrien
1818496293Sobrien   /* First allocate the local general purpose registers.  */
1818596293Sobrien   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
1818696293Sobrien     if (GENERAL_REGNO_P (i) && call_used_regs[i])
1818796293Sobrien	reg_alloc_order [pos++] = i;
1818896293Sobrien
1818996293Sobrien   /* Global general purpose registers.  */
1819096293Sobrien   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
1819196293Sobrien     if (GENERAL_REGNO_P (i) && !call_used_regs[i])
1819296293Sobrien	reg_alloc_order [pos++] = i;
1819396293Sobrien
1819496293Sobrien   /* x87 registers come first in case we are doing FP math
1819596293Sobrien      using them.  */
1819696293Sobrien   if (!TARGET_SSE_MATH)
1819796293Sobrien     for (i = FIRST_STACK_REG; i <= LAST_STACK_REG; i++)
1819896293Sobrien       reg_alloc_order [pos++] = i;
18199117408Skan
1820096293Sobrien   /* SSE registers.  */
1820196293Sobrien   for (i = FIRST_SSE_REG; i <= LAST_SSE_REG; i++)
1820296293Sobrien     reg_alloc_order [pos++] = i;
1820396293Sobrien   for (i = FIRST_REX_SSE_REG; i <= LAST_REX_SSE_REG; i++)
1820496293Sobrien     reg_alloc_order [pos++] = i;
1820596293Sobrien
18206132743Skan   /* x87 registers.  */
1820796293Sobrien   if (TARGET_SSE_MATH)
1820896293Sobrien     for (i = FIRST_STACK_REG; i <= LAST_STACK_REG; i++)
1820996293Sobrien       reg_alloc_order [pos++] = i;
1821096293Sobrien
1821196293Sobrien   for (i = FIRST_MMX_REG; i <= LAST_MMX_REG; i++)
1821296293Sobrien     reg_alloc_order [pos++] = i;
1821396293Sobrien
1821496293Sobrien   /* Initialize the rest of array as we do not allocate some registers
1821596293Sobrien      at all.  */
1821696293Sobrien   while (pos < FIRST_PSEUDO_REGISTER)
1821796293Sobrien     reg_alloc_order [pos++] = 0;
1821896293Sobrien}
18219102800Skan
18220132743Skan/* Handle a "ms_struct" or "gcc_struct" attribute; arguments as in
18221132743Skan   struct attribute_spec.handler.  */
18222132743Skanstatic tree
18223132743Skanix86_handle_struct_attribute (tree *node, tree name,
18224132743Skan			      tree args ATTRIBUTE_UNUSED,
18225132743Skan			      int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
18226132743Skan{
18227132743Skan  tree *type = NULL;
18228132743Skan  if (DECL_P (*node))
18229132743Skan    {
18230132743Skan      if (TREE_CODE (*node) == TYPE_DECL)
18231132743Skan	type = &TREE_TYPE (*node);
18232132743Skan    }
18233132743Skan  else
18234132743Skan    type = node;
18235132743Skan
18236132743Skan  if (!(type && (TREE_CODE (*type) == RECORD_TYPE
18237132743Skan		 || TREE_CODE (*type) == UNION_TYPE)))
18238132743Skan    {
18239169705Skan      warning (OPT_Wattributes, "%qs attribute ignored",
18240169705Skan	       IDENTIFIER_POINTER (name));
18241132743Skan      *no_add_attrs = true;
18242132743Skan    }
18243132743Skan
18244132743Skan  else if ((is_attribute_p ("ms_struct", name)
18245132743Skan	    && lookup_attribute ("gcc_struct", TYPE_ATTRIBUTES (*type)))
18246132743Skan	   || ((is_attribute_p ("gcc_struct", name)
18247132743Skan		&& lookup_attribute ("ms_struct", TYPE_ATTRIBUTES (*type)))))
18248132743Skan    {
18249169705Skan      warning (OPT_Wattributes, "%qs incompatible attribute ignored",
18250132743Skan               IDENTIFIER_POINTER (name));
18251132743Skan      *no_add_attrs = true;
18252132743Skan    }
18253132743Skan
18254132743Skan  return NULL_TREE;
18255132743Skan}
18256132743Skan
18257132743Skanstatic bool
18258132743Skanix86_ms_bitfield_layout_p (tree record_type)
18259132743Skan{
18260169705Skan  return (TARGET_MS_BITFIELD_LAYOUT &&
18261132743Skan	  !lookup_attribute ("gcc_struct", TYPE_ATTRIBUTES (record_type)))
18262132743Skan    || lookup_attribute ("ms_struct", TYPE_ATTRIBUTES (record_type));
18263132743Skan}
18264132743Skan
18265117408Skan/* Returns an expression indicating where the this parameter is
18266117408Skan   located on entry to the FUNCTION.  */
18267117408Skan
18268117408Skanstatic rtx
18269132743Skanx86_this_parameter (tree function)
18270102800Skan{
18271117408Skan  tree type = TREE_TYPE (function);
18272102800Skan
18273117408Skan  if (TARGET_64BIT)
18274117408Skan    {
18275132743Skan      int n = aggregate_value_p (TREE_TYPE (type), type) != 0;
18276117408Skan      return gen_rtx_REG (DImode, x86_64_int_parameter_registers[n]);
18277117408Skan    }
18278117408Skan
18279132743Skan  if (ix86_function_regparm (type, function) > 0)
18280117408Skan    {
18281117408Skan      tree parm;
18282117408Skan
18283117408Skan      parm = TYPE_ARG_TYPES (type);
18284117408Skan      /* Figure out whether or not the function has a variable number of
18285117408Skan	 arguments.  */
18286117408Skan      for (; parm; parm = TREE_CHAIN (parm))
18287117408Skan	if (TREE_VALUE (parm) == void_type_node)
18288117408Skan	  break;
18289132743Skan      /* If not, the this parameter is in the first argument.  */
18290117408Skan      if (parm)
18291132743Skan	{
18292132743Skan	  int regno = 0;
18293132743Skan	  if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (type)))
18294132743Skan	    regno = 2;
18295132743Skan	  return gen_rtx_REG (SImode, regno);
18296132743Skan	}
18297117408Skan    }
18298117408Skan
18299132743Skan  if (aggregate_value_p (TREE_TYPE (type), type))
18300117408Skan    return gen_rtx_MEM (SImode, plus_constant (stack_pointer_rtx, 8));
18301102800Skan  else
18302117408Skan    return gen_rtx_MEM (SImode, plus_constant (stack_pointer_rtx, 4));
18303117408Skan}
18304102800Skan
18305117408Skan/* Determine whether x86_output_mi_thunk can succeed.  */
18306117408Skan
18307117408Skanstatic bool
18308132743Skanx86_can_output_mi_thunk (tree thunk ATTRIBUTE_UNUSED,
18309132743Skan			 HOST_WIDE_INT delta ATTRIBUTE_UNUSED,
18310132743Skan			 HOST_WIDE_INT vcall_offset, tree function)
18311117408Skan{
18312117408Skan  /* 64-bit can handle anything.  */
18313102800Skan  if (TARGET_64BIT)
18314117408Skan    return true;
18315117408Skan
18316117408Skan  /* For 32-bit, everything's fine if we have one free register.  */
18317132743Skan  if (ix86_function_regparm (TREE_TYPE (function), function) < 3)
18318117408Skan    return true;
18319117408Skan
18320117408Skan  /* Need a free register for vcall_offset.  */
18321117408Skan  if (vcall_offset)
18322117408Skan    return false;
18323117408Skan
18324117408Skan  /* Need a free register for GOT references.  */
18325117408Skan  if (flag_pic && !(*targetm.binds_local_p) (function))
18326117408Skan    return false;
18327117408Skan
18328117408Skan  /* Otherwise ok.  */
18329117408Skan  return true;
18330117408Skan}
18331117408Skan
18332117408Skan/* Output the assembler code for a thunk function.  THUNK_DECL is the
18333117408Skan   declaration for the thunk function itself, FUNCTION is the decl for
18334117408Skan   the target function.  DELTA is an immediate constant offset to be
18335132743Skan   added to THIS.  If VCALL_OFFSET is nonzero, the word at
18336117408Skan   *(*this + vcall_offset) should be added to THIS.  */
18337117408Skan
18338117408Skanstatic void
18339132743Skanx86_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED,
18340132743Skan		     tree thunk ATTRIBUTE_UNUSED, HOST_WIDE_INT delta,
18341132743Skan		     HOST_WIDE_INT vcall_offset, tree function)
18342117408Skan{
18343117408Skan  rtx xops[3];
18344117408Skan  rtx this = x86_this_parameter (function);
18345117408Skan  rtx this_reg, tmp;
18346117408Skan
18347117408Skan  /* If VCALL_OFFSET, we'll need THIS in a register.  Might as well
18348117408Skan     pull it in now and let DELTA benefit.  */
18349117408Skan  if (REG_P (this))
18350117408Skan    this_reg = this;
18351117408Skan  else if (vcall_offset)
18352102800Skan    {
18353117408Skan      /* Put the this parameter into %eax.  */
18354117408Skan      xops[0] = this;
18355117408Skan      xops[1] = this_reg = gen_rtx_REG (Pmode, 0);
18356117408Skan      output_asm_insn ("mov{l}\t{%0, %1|%1, %0}", xops);
18357117408Skan    }
18358117408Skan  else
18359117408Skan    this_reg = NULL_RTX;
18360117408Skan
18361117408Skan  /* Adjust the this parameter by a fixed constant.  */
18362117408Skan  if (delta)
18363117408Skan    {
18364117408Skan      xops[0] = GEN_INT (delta);
18365117408Skan      xops[1] = this_reg ? this_reg : this;
18366117408Skan      if (TARGET_64BIT)
18367102800Skan	{
18368117408Skan	  if (!x86_64_general_operand (xops[0], DImode))
18369117408Skan	    {
18370117408Skan	      tmp = gen_rtx_REG (DImode, FIRST_REX_INT_REG + 2 /* R10 */);
18371117408Skan	      xops[1] = tmp;
18372117408Skan	      output_asm_insn ("mov{q}\t{%1, %0|%0, %1}", xops);
18373117408Skan	      xops[0] = tmp;
18374117408Skan	      xops[1] = this;
18375117408Skan	    }
18376117408Skan	  output_asm_insn ("add{q}\t{%0, %1|%1, %0}", xops);
18377102800Skan	}
18378102800Skan      else
18379117408Skan	output_asm_insn ("add{l}\t{%0, %1|%1, %0}", xops);
18380117408Skan    }
18381117408Skan
18382117408Skan  /* Adjust the this parameter by a value stored in the vtable.  */
18383117408Skan  if (vcall_offset)
18384117408Skan    {
18385117408Skan      if (TARGET_64BIT)
18386117408Skan	tmp = gen_rtx_REG (DImode, FIRST_REX_INT_REG + 2 /* R10 */);
18387117408Skan      else
18388132743Skan	{
18389132743Skan	  int tmp_regno = 2 /* ECX */;
18390132743Skan	  if (lookup_attribute ("fastcall",
18391132743Skan	      TYPE_ATTRIBUTES (TREE_TYPE (function))))
18392132743Skan	    tmp_regno = 0 /* EAX */;
18393132743Skan	  tmp = gen_rtx_REG (SImode, tmp_regno);
18394132743Skan	}
18395117408Skan
18396117408Skan      xops[0] = gen_rtx_MEM (Pmode, this_reg);
18397117408Skan      xops[1] = tmp;
18398117408Skan      if (TARGET_64BIT)
18399117408Skan	output_asm_insn ("mov{q}\t{%0, %1|%1, %0}", xops);
18400117408Skan      else
18401117408Skan	output_asm_insn ("mov{l}\t{%0, %1|%1, %0}", xops);
18402117408Skan
18403117408Skan      /* Adjust the this parameter.  */
18404117408Skan      xops[0] = gen_rtx_MEM (Pmode, plus_constant (tmp, vcall_offset));
18405117408Skan      if (TARGET_64BIT && !memory_operand (xops[0], Pmode))
18406102800Skan	{
18407117408Skan	  rtx tmp2 = gen_rtx_REG (DImode, FIRST_REX_INT_REG + 3 /* R11 */);
18408117408Skan	  xops[0] = GEN_INT (vcall_offset);
18409117408Skan	  xops[1] = tmp2;
18410117408Skan	  output_asm_insn ("mov{q}\t{%0, %1|%1, %0}", xops);
18411117408Skan	  xops[0] = gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, tmp, tmp2));
18412102800Skan	}
18413117408Skan      xops[1] = this_reg;
18414117408Skan      if (TARGET_64BIT)
18415117408Skan	output_asm_insn ("add{q}\t{%0, %1|%1, %0}", xops);
18416117408Skan      else
18417117408Skan	output_asm_insn ("add{l}\t{%0, %1|%1, %0}", xops);
18418102800Skan    }
18419117408Skan
18420117408Skan  /* If necessary, drop THIS back to its stack slot.  */
18421117408Skan  if (this_reg && this_reg != this)
18422102800Skan    {
18423117408Skan      xops[0] = this_reg;
18424117408Skan      xops[1] = this;
18425117408Skan      output_asm_insn ("mov{l}\t{%0, %1|%1, %0}", xops);
18426117408Skan    }
18427117408Skan
18428130711Sobrien  xops[0] = XEXP (DECL_RTL (function), 0);
18429117408Skan  if (TARGET_64BIT)
18430117408Skan    {
18431117408Skan      if (!flag_pic || (*targetm.binds_local_p) (function))
18432117408Skan	output_asm_insn ("jmp\t%P0", xops);
18433102800Skan      else
18434102800Skan	{
18435130711Sobrien	  tmp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xops[0]), UNSPEC_GOTPCREL);
18436117408Skan	  tmp = gen_rtx_CONST (Pmode, tmp);
18437117408Skan	  tmp = gen_rtx_MEM (QImode, tmp);
18438117408Skan	  xops[0] = tmp;
18439117408Skan	  output_asm_insn ("jmp\t%A0", xops);
18440102800Skan	}
18441117408Skan    }
18442117408Skan  else
18443117408Skan    {
18444117408Skan      if (!flag_pic || (*targetm.binds_local_p) (function))
18445117408Skan	output_asm_insn ("jmp\t%P0", xops);
18446102800Skan      else
18447132743Skan#if TARGET_MACHO
18448132743Skan	if (TARGET_MACHO)
18449132743Skan	  {
18450169705Skan	    rtx sym_ref = XEXP (DECL_RTL (function), 0);
18451169705Skan	    tmp = (gen_rtx_SYMBOL_REF
18452169705Skan		   (Pmode,
18453169705Skan		    machopic_indirection_name (sym_ref, /*stub_p=*/true)));
18454132743Skan	    tmp = gen_rtx_MEM (QImode, tmp);
18455132743Skan	    xops[0] = tmp;
18456132743Skan	    output_asm_insn ("jmp\t%0", xops);
18457132743Skan	  }
18458132743Skan	else
18459132743Skan#endif /* TARGET_MACHO */
18460102800Skan	{
18461117408Skan	  tmp = gen_rtx_REG (SImode, 2 /* ECX */);
18462169705Skan	  output_set_got (tmp, NULL_RTX);
18463117408Skan
18464117408Skan	  xops[1] = tmp;
18465117408Skan	  output_asm_insn ("mov{l}\t{%0@GOT(%1), %1|%1, %0@GOT[%1]}", xops);
18466117408Skan	  output_asm_insn ("jmp\t{*}%1", xops);
18467102800Skan	}
18468102800Skan    }
18469102800Skan}
18470102800Skan
18471132743Skanstatic void
18472132743Skanx86_file_start (void)
18473132743Skan{
18474132743Skan  default_file_start ();
18475169705Skan#if TARGET_MACHO
18476169705Skan  darwin_file_start ();
18477169705Skan#endif
18478132743Skan  if (X86_FILE_START_VERSION_DIRECTIVE)
18479132743Skan    fputs ("\t.version\t\"01.01\"\n", asm_out_file);
18480132743Skan  if (X86_FILE_START_FLTUSED)
18481132743Skan    fputs ("\t.global\t__fltused\n", asm_out_file);
18482132743Skan  if (ix86_asm_dialect == ASM_INTEL)
18483132743Skan    fputs ("\t.intel_syntax\n", asm_out_file);
18484132743Skan}
18485132743Skan
18486102800Skanint
18487132743Skanx86_field_alignment (tree field, int computed)
18488102800Skan{
18489102800Skan  enum machine_mode mode;
18490102800Skan  tree type = TREE_TYPE (field);
18491102800Skan
18492102800Skan  if (TARGET_64BIT || TARGET_ALIGN_DOUBLE)
18493102800Skan    return computed;
18494102800Skan  mode = TYPE_MODE (TREE_CODE (type) == ARRAY_TYPE
18495102800Skan		    ? get_inner_array_type (type) : type);
18496102800Skan  if (mode == DFmode || mode == DCmode
18497102800Skan      || GET_MODE_CLASS (mode) == MODE_INT
18498102800Skan      || GET_MODE_CLASS (mode) == MODE_COMPLEX_INT)
18499102800Skan    return MIN (32, computed);
18500102800Skan  return computed;
18501102800Skan}
18502117408Skan
18503117408Skan/* Output assembler code to FILE to increment profiler label # LABELNO
18504117408Skan   for profiling a function entry.  */
18505117408Skanvoid
18506132743Skanx86_function_profiler (FILE *file, int labelno ATTRIBUTE_UNUSED)
18507117408Skan{
18508117408Skan  if (TARGET_64BIT)
18509117408Skan    if (flag_pic)
18510117408Skan      {
18511117408Skan#ifndef NO_PROFILE_COUNTERS
18512117408Skan	fprintf (file, "\tleaq\t%sP%d@(%%rip),%%r11\n", LPREFIX, labelno);
18513117408Skan#endif
18514117408Skan	fprintf (file, "\tcall\t*%s@GOTPCREL(%%rip)\n", MCOUNT_NAME);
18515117408Skan      }
18516117408Skan    else
18517117408Skan      {
18518117408Skan#ifndef NO_PROFILE_COUNTERS
18519117408Skan	fprintf (file, "\tmovq\t$%sP%d,%%r11\n", LPREFIX, labelno);
18520117408Skan#endif
18521117408Skan	fprintf (file, "\tcall\t%s\n", MCOUNT_NAME);
18522117408Skan      }
18523117408Skan  else if (flag_pic)
18524117408Skan    {
18525117408Skan#ifndef NO_PROFILE_COUNTERS
18526117408Skan      fprintf (file, "\tleal\t%sP%d@GOTOFF(%%ebx),%%%s\n",
18527117408Skan	       LPREFIX, labelno, PROFILE_COUNT_REGISTER);
18528117408Skan#endif
18529117408Skan      fprintf (file, "\tcall\t*%s@GOT(%%ebx)\n", MCOUNT_NAME);
18530117408Skan    }
18531117408Skan  else
18532117408Skan    {
18533117408Skan#ifndef NO_PROFILE_COUNTERS
18534117408Skan      fprintf (file, "\tmovl\t$%sP%d,%%%s\n", LPREFIX, labelno,
18535117408Skan	       PROFILE_COUNT_REGISTER);
18536117408Skan#endif
18537117408Skan      fprintf (file, "\tcall\t%s\n", MCOUNT_NAME);
18538117408Skan    }
18539117408Skan}
18540117408Skan
18541132743Skan/* We don't have exact information about the insn sizes, but we may assume
18542132743Skan   quite safely that we are informed about all 1 byte insns and memory
18543132743Skan   address sizes.  This is enough to eliminate unnecessary padding in
18544132743Skan   99% of cases.  */
18545132743Skan
18546132743Skanstatic int
18547132743Skanmin_insn_size (rtx insn)
18548132743Skan{
18549132743Skan  int l = 0;
18550132743Skan
18551132743Skan  if (!INSN_P (insn) || !active_insn_p (insn))
18552132743Skan    return 0;
18553132743Skan
18554132743Skan  /* Discard alignments we've emit and jump instructions.  */
18555132743Skan  if (GET_CODE (PATTERN (insn)) == UNSPEC_VOLATILE
18556132743Skan      && XINT (PATTERN (insn), 1) == UNSPECV_ALIGN)
18557132743Skan    return 0;
18558132743Skan  if (GET_CODE (insn) == JUMP_INSN
18559132743Skan      && (GET_CODE (PATTERN (insn)) == ADDR_VEC
18560132743Skan	  || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC))
18561132743Skan    return 0;
18562132743Skan
18563132743Skan  /* Important case - calls are always 5 bytes.
18564132743Skan     It is common to have many calls in the row.  */
18565132743Skan  if (GET_CODE (insn) == CALL_INSN
18566132743Skan      && symbolic_reference_mentioned_p (PATTERN (insn))
18567132743Skan      && !SIBLING_CALL_P (insn))
18568132743Skan    return 5;
18569132743Skan  if (get_attr_length (insn) <= 1)
18570132743Skan    return 1;
18571132743Skan
18572132743Skan  /* For normal instructions we may rely on the sizes of addresses
18573132743Skan     and the presence of symbol to require 4 bytes of encoding.
18574132743Skan     This is not the case for jumps where references are PC relative.  */
18575132743Skan  if (GET_CODE (insn) != JUMP_INSN)
18576132743Skan    {
18577132743Skan      l = get_attr_length_address (insn);
18578132743Skan      if (l < 4 && symbolic_reference_mentioned_p (PATTERN (insn)))
18579132743Skan	l = 4;
18580132743Skan    }
18581132743Skan  if (l)
18582132743Skan    return 1+l;
18583132743Skan  else
18584132743Skan    return 2;
18585132743Skan}
18586132743Skan
18587132743Skan/* AMD K8 core mispredicts jumps when there are more than 3 jumps in 16 byte
18588132743Skan   window.  */
18589132743Skan
18590132743Skanstatic void
18591169705Skanix86_avoid_jump_misspredicts (void)
18592132743Skan{
18593132743Skan  rtx insn, start = get_insns ();
18594132743Skan  int nbytes = 0, njumps = 0;
18595132743Skan  int isjump = 0;
18596132743Skan
18597132743Skan  /* Look for all minimal intervals of instructions containing 4 jumps.
18598132743Skan     The intervals are bounded by START and INSN.  NBYTES is the total
18599132743Skan     size of instructions in the interval including INSN and not including
18600132743Skan     START.  When the NBYTES is smaller than 16 bytes, it is possible
18601132743Skan     that the end of START and INSN ends up in the same 16byte page.
18602132743Skan
18603132743Skan     The smallest offset in the page INSN can start is the case where START
18604132743Skan     ends on the offset 0.  Offset of INSN is then NBYTES - sizeof (INSN).
18605132743Skan     We add p2align to 16byte window with maxskip 17 - NBYTES + sizeof (INSN).
18606132743Skan     */
18607132743Skan  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
18608132743Skan    {
18609132743Skan
18610132743Skan      nbytes += min_insn_size (insn);
18611169705Skan      if (dump_file)
18612169705Skan        fprintf(dump_file, "Insn %i estimated to %i bytes\n",
18613132743Skan		INSN_UID (insn), min_insn_size (insn));
18614132743Skan      if ((GET_CODE (insn) == JUMP_INSN
18615132743Skan	   && GET_CODE (PATTERN (insn)) != ADDR_VEC
18616132743Skan	   && GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC)
18617132743Skan	  || GET_CODE (insn) == CALL_INSN)
18618132743Skan	njumps++;
18619132743Skan      else
18620132743Skan	continue;
18621132743Skan
18622132743Skan      while (njumps > 3)
18623132743Skan	{
18624132743Skan	  start = NEXT_INSN (start);
18625132743Skan	  if ((GET_CODE (start) == JUMP_INSN
18626132743Skan	       && GET_CODE (PATTERN (start)) != ADDR_VEC
18627132743Skan	       && GET_CODE (PATTERN (start)) != ADDR_DIFF_VEC)
18628132743Skan	      || GET_CODE (start) == CALL_INSN)
18629132743Skan	    njumps--, isjump = 1;
18630132743Skan	  else
18631132743Skan	    isjump = 0;
18632132743Skan	  nbytes -= min_insn_size (start);
18633132743Skan	}
18634169705Skan      gcc_assert (njumps >= 0);
18635169705Skan      if (dump_file)
18636169705Skan        fprintf (dump_file, "Interval %i to %i has %i bytes\n",
18637132743Skan		INSN_UID (start), INSN_UID (insn), nbytes);
18638132743Skan
18639132743Skan      if (njumps == 3 && isjump && nbytes < 16)
18640132743Skan	{
18641132743Skan	  int padsize = 15 - nbytes + min_insn_size (insn);
18642132743Skan
18643169705Skan	  if (dump_file)
18644169705Skan	    fprintf (dump_file, "Padding insn %i by %i bytes!\n",
18645169705Skan		     INSN_UID (insn), padsize);
18646132743Skan          emit_insn_before (gen_align (GEN_INT (padsize)), insn);
18647132743Skan	}
18648132743Skan    }
18649132743Skan}
18650132743Skan
18651169705Skan/* AMD Athlon works faster
18652132743Skan   when RET is not destination of conditional jump or directly preceded
18653117408Skan   by other jump instruction.  We avoid the penalty by inserting NOP just
18654117408Skan   before the RET instructions in such cases.  */
18655132743Skanstatic void
18656169705Skanix86_pad_returns (void)
18657117408Skan{
18658117408Skan  edge e;
18659169705Skan  edge_iterator ei;
18660117408Skan
18661169705Skan  FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds)
18662169705Skan    {
18663169705Skan      basic_block bb = e->src;
18664169705Skan      rtx ret = BB_END (bb);
18665169705Skan      rtx prev;
18666169705Skan      bool replace = false;
18667117408Skan
18668169705Skan      if (GET_CODE (ret) != JUMP_INSN || GET_CODE (PATTERN (ret)) != RETURN
18669169705Skan	  || !maybe_hot_bb_p (bb))
18670169705Skan	continue;
18671169705Skan      for (prev = PREV_INSN (ret); prev; prev = PREV_INSN (prev))
18672169705Skan	if (active_insn_p (prev) || GET_CODE (prev) == CODE_LABEL)
18673169705Skan	  break;
18674169705Skan      if (prev && GET_CODE (prev) == CODE_LABEL)
18675169705Skan	{
18676169705Skan	  edge e;
18677169705Skan	  edge_iterator ei;
18678169705Skan
18679169705Skan	  FOR_EACH_EDGE (e, ei, bb->preds)
18680169705Skan	    if (EDGE_FREQUENCY (e) && e->src->index >= 0
18681169705Skan		&& !(e->flags & EDGE_FALLTHRU))
18682169705Skan	      replace = true;
18683169705Skan	}
18684169705Skan      if (!replace)
18685169705Skan	{
18686169705Skan	  prev = prev_active_insn (ret);
18687169705Skan	  if (prev
18688169705Skan	      && ((GET_CODE (prev) == JUMP_INSN && any_condjump_p (prev))
18689169705Skan		  || GET_CODE (prev) == CALL_INSN))
18690132743Skan	    replace = true;
18691169705Skan	  /* Empty functions get branch mispredict even when the jump destination
18692169705Skan	     is not visible to us.  */
18693169705Skan	  if (!prev && cfun->function_frequency > FUNCTION_FREQUENCY_UNLIKELY_EXECUTED)
18694169705Skan	    replace = true;
18695169705Skan	}
18696169705Skan      if (replace)
18697169705Skan	{
18698169705Skan	  emit_insn_before (gen_return_internal_long (), ret);
18699169705Skan	  delete_insn (ret);
18700169705Skan	}
18701169705Skan    }
18702117408Skan}
18703117408Skan
18704169705Skan/* Implement machine specific optimizations.  We implement padding of returns
18705169705Skan   for K8 CPUs and pass to avoid 4 jumps in the single 16 byte window.  */
18706169705Skanstatic void
18707169705Skanix86_reorg (void)
18708169705Skan{
18709169705Skan  if (TARGET_PAD_RETURNS && optimize && !optimize_size)
18710169705Skan    ix86_pad_returns ();
18711169705Skan  if (TARGET_FOUR_JUMP_LIMIT && optimize && !optimize_size)
18712169705Skan    ix86_avoid_jump_misspredicts ();
18713169705Skan}
18714169705Skan
18715132743Skan/* Return nonzero when QImode register that must be represented via REX prefix
18716132743Skan   is used.  */
18717132743Skanbool
18718132743Skanx86_extended_QIreg_mentioned_p (rtx insn)
18719132743Skan{
18720132743Skan  int i;
18721132743Skan  extract_insn_cached (insn);
18722132743Skan  for (i = 0; i < recog_data.n_operands; i++)
18723132743Skan    if (REG_P (recog_data.operand[i])
18724132743Skan	&& REGNO (recog_data.operand[i]) >= 4)
18725132743Skan       return true;
18726132743Skan  return false;
18727132743Skan}
18728132743Skan
18729132743Skan/* Return nonzero when P points to register encoded via REX prefix.
18730132743Skan   Called via for_each_rtx.  */
18731132743Skanstatic int
18732132743Skanextended_reg_mentioned_1 (rtx *p, void *data ATTRIBUTE_UNUSED)
18733132743Skan{
18734132743Skan   unsigned int regno;
18735132743Skan   if (!REG_P (*p))
18736132743Skan     return 0;
18737132743Skan   regno = REGNO (*p);
18738132743Skan   return REX_INT_REGNO_P (regno) || REX_SSE_REGNO_P (regno);
18739132743Skan}
18740132743Skan
18741132743Skan/* Return true when INSN mentions register that must be encoded using REX
18742132743Skan   prefix.  */
18743132743Skanbool
18744132743Skanx86_extended_reg_mentioned_p (rtx insn)
18745132743Skan{
18746132743Skan  return for_each_rtx (&PATTERN (insn), extended_reg_mentioned_1, NULL);
18747132743Skan}
18748132743Skan
18749132743Skan/* Generate an unsigned DImode/SImode to FP conversion.  This is the same code
18750132743Skan   optabs would emit if we didn't have TFmode patterns.  */
18751132743Skan
18752132743Skanvoid
18753132743Skanx86_emit_floatuns (rtx operands[2])
18754132743Skan{
18755132743Skan  rtx neglab, donelab, i0, i1, f0, in, out;
18756132743Skan  enum machine_mode mode, inmode;
18757132743Skan
18758132743Skan  inmode = GET_MODE (operands[1]);
18759169705Skan  gcc_assert (inmode == SImode || inmode == DImode);
18760132743Skan
18761132743Skan  out = operands[0];
18762132743Skan  in = force_reg (inmode, operands[1]);
18763132743Skan  mode = GET_MODE (out);
18764132743Skan  neglab = gen_label_rtx ();
18765132743Skan  donelab = gen_label_rtx ();
18766132743Skan  i1 = gen_reg_rtx (Pmode);
18767132743Skan  f0 = gen_reg_rtx (mode);
18768132743Skan
18769132743Skan  emit_cmp_and_jump_insns (in, const0_rtx, LT, const0_rtx, Pmode, 0, neglab);
18770132743Skan
18771132743Skan  emit_insn (gen_rtx_SET (VOIDmode, out, gen_rtx_FLOAT (mode, in)));
18772132743Skan  emit_jump_insn (gen_jump (donelab));
18773132743Skan  emit_barrier ();
18774132743Skan
18775132743Skan  emit_label (neglab);
18776132743Skan
18777132743Skan  i0 = expand_simple_binop (Pmode, LSHIFTRT, in, const1_rtx, NULL, 1, OPTAB_DIRECT);
18778132743Skan  i1 = expand_simple_binop (Pmode, AND, in, const1_rtx, NULL, 1, OPTAB_DIRECT);
18779132743Skan  i0 = expand_simple_binop (Pmode, IOR, i0, i1, i0, 1, OPTAB_DIRECT);
18780132743Skan  expand_float (f0, i0, 0);
18781132743Skan  emit_insn (gen_rtx_SET (VOIDmode, out, gen_rtx_PLUS (mode, f0, f0)));
18782132743Skan
18783132743Skan  emit_label (donelab);
18784132743Skan}
18785169705Skan
18786169705Skan/* A subroutine of ix86_expand_vector_init.  Store into TARGET a vector
18787169705Skan   with all elements equal to VAR.  Return true if successful.  */
18788132743Skan
18789169705Skanstatic bool
18790169705Skanix86_expand_vector_init_duplicate (bool mmx_ok, enum machine_mode mode,
18791169705Skan				   rtx target, rtx val)
18792132743Skan{
18793169705Skan  enum machine_mode smode, wsmode, wvmode;
18794169705Skan  rtx x;
18795169705Skan
18796169705Skan  switch (mode)
18797169705Skan    {
18798169705Skan    case V2SImode:
18799169705Skan    case V2SFmode:
18800169705Skan      if (!mmx_ok)
18801169705Skan	return false;
18802169705Skan      /* FALLTHRU */
18803169705Skan
18804169705Skan    case V2DFmode:
18805169705Skan    case V2DImode:
18806169705Skan    case V4SFmode:
18807169705Skan    case V4SImode:
18808169705Skan      val = force_reg (GET_MODE_INNER (mode), val);
18809169705Skan      x = gen_rtx_VEC_DUPLICATE (mode, val);
18810169705Skan      emit_insn (gen_rtx_SET (VOIDmode, target, x));
18811169705Skan      return true;
18812169705Skan
18813169705Skan    case V4HImode:
18814169705Skan      if (!mmx_ok)
18815169705Skan	return false;
18816169705Skan      if (TARGET_SSE || TARGET_3DNOW_A)
18817169705Skan	{
18818169705Skan	  val = gen_lowpart (SImode, val);
18819169705Skan	  x = gen_rtx_TRUNCATE (HImode, val);
18820169705Skan	  x = gen_rtx_VEC_DUPLICATE (mode, x);
18821169705Skan	  emit_insn (gen_rtx_SET (VOIDmode, target, x));
18822169705Skan	  return true;
18823169705Skan	}
18824169705Skan      else
18825169705Skan	{
18826169705Skan	  smode = HImode;
18827169705Skan	  wsmode = SImode;
18828169705Skan	  wvmode = V2SImode;
18829169705Skan	  goto widen;
18830169705Skan	}
18831169705Skan
18832169705Skan    case V8QImode:
18833169705Skan      if (!mmx_ok)
18834169705Skan	return false;
18835169705Skan      smode = QImode;
18836169705Skan      wsmode = HImode;
18837169705Skan      wvmode = V4HImode;
18838169705Skan      goto widen;
18839169705Skan    case V8HImode:
18840169705Skan      if (TARGET_SSE2)
18841169705Skan	{
18842169705Skan	  rtx tmp1, tmp2;
18843169705Skan	  /* Extend HImode to SImode using a paradoxical SUBREG.  */
18844169705Skan	  tmp1 = gen_reg_rtx (SImode);
18845169705Skan	  emit_move_insn (tmp1, gen_lowpart (SImode, val));
18846169705Skan	  /* Insert the SImode value as low element of V4SImode vector. */
18847169705Skan	  tmp2 = gen_reg_rtx (V4SImode);
18848169705Skan	  tmp1 = gen_rtx_VEC_MERGE (V4SImode,
18849169705Skan				    gen_rtx_VEC_DUPLICATE (V4SImode, tmp1),
18850169705Skan				    CONST0_RTX (V4SImode),
18851169705Skan				    const1_rtx);
18852169705Skan	  emit_insn (gen_rtx_SET (VOIDmode, tmp2, tmp1));
18853169705Skan	  /* Cast the V4SImode vector back to a V8HImode vector.  */
18854169705Skan	  tmp1 = gen_reg_rtx (V8HImode);
18855169705Skan	  emit_move_insn (tmp1, gen_lowpart (V8HImode, tmp2));
18856169705Skan	  /* Duplicate the low short through the whole low SImode word.  */
18857169705Skan	  emit_insn (gen_sse2_punpcklwd (tmp1, tmp1, tmp1));
18858169705Skan	  /* Cast the V8HImode vector back to a V4SImode vector.  */
18859169705Skan	  tmp2 = gen_reg_rtx (V4SImode);
18860169705Skan	  emit_move_insn (tmp2, gen_lowpart (V4SImode, tmp1));
18861169705Skan	  /* Replicate the low element of the V4SImode vector.  */
18862169705Skan	  emit_insn (gen_sse2_pshufd (tmp2, tmp2, const0_rtx));
18863169705Skan	  /* Cast the V2SImode back to V8HImode, and store in target.  */
18864169705Skan	  emit_move_insn (target, gen_lowpart (V8HImode, tmp2));
18865169705Skan	  return true;
18866169705Skan	}
18867169705Skan      smode = HImode;
18868169705Skan      wsmode = SImode;
18869169705Skan      wvmode = V4SImode;
18870169705Skan      goto widen;
18871169705Skan    case V16QImode:
18872169705Skan      if (TARGET_SSE2)
18873169705Skan	{
18874169705Skan	  rtx tmp1, tmp2;
18875169705Skan	  /* Extend QImode to SImode using a paradoxical SUBREG.  */
18876169705Skan	  tmp1 = gen_reg_rtx (SImode);
18877169705Skan	  emit_move_insn (tmp1, gen_lowpart (SImode, val));
18878169705Skan	  /* Insert the SImode value as low element of V4SImode vector. */
18879169705Skan	  tmp2 = gen_reg_rtx (V4SImode);
18880169705Skan	  tmp1 = gen_rtx_VEC_MERGE (V4SImode,
18881169705Skan				    gen_rtx_VEC_DUPLICATE (V4SImode, tmp1),
18882169705Skan				    CONST0_RTX (V4SImode),
18883169705Skan				    const1_rtx);
18884169705Skan	  emit_insn (gen_rtx_SET (VOIDmode, tmp2, tmp1));
18885169705Skan	  /* Cast the V4SImode vector back to a V16QImode vector.  */
18886169705Skan	  tmp1 = gen_reg_rtx (V16QImode);
18887169705Skan	  emit_move_insn (tmp1, gen_lowpart (V16QImode, tmp2));
18888169705Skan	  /* Duplicate the low byte through the whole low SImode word.  */
18889169705Skan	  emit_insn (gen_sse2_punpcklbw (tmp1, tmp1, tmp1));
18890169705Skan	  emit_insn (gen_sse2_punpcklbw (tmp1, tmp1, tmp1));
18891169705Skan	  /* Cast the V16QImode vector back to a V4SImode vector.  */
18892169705Skan	  tmp2 = gen_reg_rtx (V4SImode);
18893169705Skan	  emit_move_insn (tmp2, gen_lowpart (V4SImode, tmp1));
18894169705Skan	  /* Replicate the low element of the V4SImode vector.  */
18895169705Skan	  emit_insn (gen_sse2_pshufd (tmp2, tmp2, const0_rtx));
18896169705Skan	  /* Cast the V2SImode back to V16QImode, and store in target.  */
18897169705Skan	  emit_move_insn (target, gen_lowpart (V16QImode, tmp2));
18898169705Skan	  return true;
18899169705Skan	}
18900169705Skan      smode = QImode;
18901169705Skan      wsmode = HImode;
18902169705Skan      wvmode = V8HImode;
18903169705Skan      goto widen;
18904169705Skan    widen:
18905169705Skan      /* Replicate the value once into the next wider mode and recurse.  */
18906169705Skan      val = convert_modes (wsmode, smode, val, true);
18907169705Skan      x = expand_simple_binop (wsmode, ASHIFT, val,
18908169705Skan			       GEN_INT (GET_MODE_BITSIZE (smode)),
18909169705Skan			       NULL_RTX, 1, OPTAB_LIB_WIDEN);
18910169705Skan      val = expand_simple_binop (wsmode, IOR, val, x, x, 1, OPTAB_LIB_WIDEN);
18911169705Skan
18912169705Skan      x = gen_reg_rtx (wvmode);
18913169705Skan      if (!ix86_expand_vector_init_duplicate (mmx_ok, wvmode, x, val))
18914169705Skan	gcc_unreachable ();
18915169705Skan      emit_move_insn (target, gen_lowpart (mode, x));
18916169705Skan      return true;
18917169705Skan
18918169705Skan    default:
18919169705Skan      return false;
18920169705Skan    }
18921132743Skan}
18922132743Skan
18923169705Skan/* A subroutine of ix86_expand_vector_init.  Store into TARGET a vector
18924169705Skan   whose ONE_VAR element is VAR, and other elements are zero.  Return true
18925169705Skan   if successful.  */
18926169705Skan
18927169705Skanstatic bool
18928169705Skanix86_expand_vector_init_one_nonzero (bool mmx_ok, enum machine_mode mode,
18929169705Skan				     rtx target, rtx var, int one_var)
18930169705Skan{
18931169705Skan  enum machine_mode vsimode;
18932169705Skan  rtx new_target;
18933169705Skan  rtx x, tmp;
18934169705Skan
18935169705Skan  switch (mode)
18936169705Skan    {
18937169705Skan    case V2SFmode:
18938169705Skan    case V2SImode:
18939169705Skan      if (!mmx_ok)
18940169705Skan	return false;
18941169705Skan      /* FALLTHRU */
18942169705Skan
18943169705Skan    case V2DFmode:
18944169705Skan    case V2DImode:
18945169705Skan      if (one_var != 0)
18946169705Skan	return false;
18947169705Skan      var = force_reg (GET_MODE_INNER (mode), var);
18948169705Skan      x = gen_rtx_VEC_CONCAT (mode, var, CONST0_RTX (GET_MODE_INNER (mode)));
18949169705Skan      emit_insn (gen_rtx_SET (VOIDmode, target, x));
18950169705Skan      return true;
18951169705Skan
18952169705Skan    case V4SFmode:
18953169705Skan    case V4SImode:
18954169705Skan      if (!REG_P (target) || REGNO (target) < FIRST_PSEUDO_REGISTER)
18955169705Skan	new_target = gen_reg_rtx (mode);
18956169705Skan      else
18957169705Skan	new_target = target;
18958169705Skan      var = force_reg (GET_MODE_INNER (mode), var);
18959169705Skan      x = gen_rtx_VEC_DUPLICATE (mode, var);
18960169705Skan      x = gen_rtx_VEC_MERGE (mode, x, CONST0_RTX (mode), const1_rtx);
18961169705Skan      emit_insn (gen_rtx_SET (VOIDmode, new_target, x));
18962169705Skan      if (one_var != 0)
18963169705Skan	{
18964169705Skan	  /* We need to shuffle the value to the correct position, so
18965169705Skan	     create a new pseudo to store the intermediate result.  */
18966169705Skan
18967169705Skan	  /* With SSE2, we can use the integer shuffle insns.  */
18968169705Skan	  if (mode != V4SFmode && TARGET_SSE2)
18969169705Skan	    {
18970169705Skan	      emit_insn (gen_sse2_pshufd_1 (new_target, new_target,
18971169705Skan					    GEN_INT (1),
18972169705Skan					    GEN_INT (one_var == 1 ? 0 : 1),
18973169705Skan					    GEN_INT (one_var == 2 ? 0 : 1),
18974169705Skan					    GEN_INT (one_var == 3 ? 0 : 1)));
18975169705Skan	      if (target != new_target)
18976169705Skan		emit_move_insn (target, new_target);
18977169705Skan	      return true;
18978169705Skan	    }
18979169705Skan
18980169705Skan	  /* Otherwise convert the intermediate result to V4SFmode and
18981169705Skan	     use the SSE1 shuffle instructions.  */
18982169705Skan	  if (mode != V4SFmode)
18983169705Skan	    {
18984169705Skan	      tmp = gen_reg_rtx (V4SFmode);
18985169705Skan	      emit_move_insn (tmp, gen_lowpart (V4SFmode, new_target));
18986169705Skan	    }
18987169705Skan	  else
18988169705Skan	    tmp = new_target;
18989169705Skan
18990169705Skan	  emit_insn (gen_sse_shufps_1 (tmp, tmp, tmp,
18991169705Skan				       GEN_INT (1),
18992169705Skan				       GEN_INT (one_var == 1 ? 0 : 1),
18993169705Skan				       GEN_INT (one_var == 2 ? 0+4 : 1+4),
18994169705Skan				       GEN_INT (one_var == 3 ? 0+4 : 1+4)));
18995169705Skan
18996169705Skan	  if (mode != V4SFmode)
18997169705Skan	    emit_move_insn (target, gen_lowpart (V4SImode, tmp));
18998169705Skan	  else if (tmp != target)
18999169705Skan	    emit_move_insn (target, tmp);
19000169705Skan	}
19001169705Skan      else if (target != new_target)
19002169705Skan	emit_move_insn (target, new_target);
19003169705Skan      return true;
19004169705Skan
19005169705Skan    case V8HImode:
19006169705Skan    case V16QImode:
19007169705Skan      vsimode = V4SImode;
19008169705Skan      goto widen;
19009169705Skan    case V4HImode:
19010169705Skan    case V8QImode:
19011169705Skan      if (!mmx_ok)
19012169705Skan	return false;
19013169705Skan      vsimode = V2SImode;
19014169705Skan      goto widen;
19015169705Skan    widen:
19016169705Skan      if (one_var != 0)
19017169705Skan	return false;
19018169705Skan
19019169705Skan      /* Zero extend the variable element to SImode and recurse.  */
19020169705Skan      var = convert_modes (SImode, GET_MODE_INNER (mode), var, true);
19021169705Skan
19022169705Skan      x = gen_reg_rtx (vsimode);
19023169705Skan      if (!ix86_expand_vector_init_one_nonzero (mmx_ok, vsimode, x,
19024169705Skan						var, one_var))
19025169705Skan	gcc_unreachable ();
19026169705Skan
19027169705Skan      emit_move_insn (target, gen_lowpart (mode, x));
19028169705Skan      return true;
19029169705Skan
19030169705Skan    default:
19031169705Skan      return false;
19032169705Skan    }
19033169705Skan}
19034169705Skan
19035169705Skan/* A subroutine of ix86_expand_vector_init.  Store into TARGET a vector
19036169705Skan   consisting of the values in VALS.  It is known that all elements
19037169705Skan   except ONE_VAR are constants.  Return true if successful.  */
19038169705Skan
19039169705Skanstatic bool
19040169705Skanix86_expand_vector_init_one_var (bool mmx_ok, enum machine_mode mode,
19041169705Skan				 rtx target, rtx vals, int one_var)
19042169705Skan{
19043169705Skan  rtx var = XVECEXP (vals, 0, one_var);
19044169705Skan  enum machine_mode wmode;
19045169705Skan  rtx const_vec, x;
19046169705Skan
19047169705Skan  const_vec = copy_rtx (vals);
19048169705Skan  XVECEXP (const_vec, 0, one_var) = CONST0_RTX (GET_MODE_INNER (mode));
19049169705Skan  const_vec = gen_rtx_CONST_VECTOR (mode, XVEC (const_vec, 0));
19050169705Skan
19051169705Skan  switch (mode)
19052169705Skan    {
19053169705Skan    case V2DFmode:
19054169705Skan    case V2DImode:
19055169705Skan    case V2SFmode:
19056169705Skan    case V2SImode:
19057169705Skan      /* For the two element vectors, it's just as easy to use
19058169705Skan	 the general case.  */
19059169705Skan      return false;
19060169705Skan
19061169705Skan    case V4SFmode:
19062169705Skan    case V4SImode:
19063169705Skan    case V8HImode:
19064169705Skan    case V4HImode:
19065169705Skan      break;
19066169705Skan
19067169705Skan    case V16QImode:
19068169705Skan      wmode = V8HImode;
19069169705Skan      goto widen;
19070169705Skan    case V8QImode:
19071169705Skan      wmode = V4HImode;
19072169705Skan      goto widen;
19073169705Skan    widen:
19074169705Skan      /* There's no way to set one QImode entry easily.  Combine
19075169705Skan	 the variable value with its adjacent constant value, and
19076169705Skan	 promote to an HImode set.  */
19077169705Skan      x = XVECEXP (vals, 0, one_var ^ 1);
19078169705Skan      if (one_var & 1)
19079169705Skan	{
19080169705Skan	  var = convert_modes (HImode, QImode, var, true);
19081169705Skan	  var = expand_simple_binop (HImode, ASHIFT, var, GEN_INT (8),
19082169705Skan				     NULL_RTX, 1, OPTAB_LIB_WIDEN);
19083169705Skan	  x = GEN_INT (INTVAL (x) & 0xff);
19084169705Skan	}
19085169705Skan      else
19086169705Skan	{
19087169705Skan	  var = convert_modes (HImode, QImode, var, true);
19088169705Skan	  x = gen_int_mode (INTVAL (x) << 8, HImode);
19089169705Skan	}
19090169705Skan      if (x != const0_rtx)
19091169705Skan	var = expand_simple_binop (HImode, IOR, var, x, var,
19092169705Skan				   1, OPTAB_LIB_WIDEN);
19093169705Skan
19094169705Skan      x = gen_reg_rtx (wmode);
19095169705Skan      emit_move_insn (x, gen_lowpart (wmode, const_vec));
19096169705Skan      ix86_expand_vector_set (mmx_ok, x, var, one_var >> 1);
19097169705Skan
19098169705Skan      emit_move_insn (target, gen_lowpart (mode, x));
19099169705Skan      return true;
19100169705Skan
19101169705Skan    default:
19102169705Skan      return false;
19103169705Skan    }
19104169705Skan
19105169705Skan  emit_move_insn (target, const_vec);
19106169705Skan  ix86_expand_vector_set (mmx_ok, target, var, one_var);
19107169705Skan  return true;
19108169705Skan}
19109169705Skan
19110169705Skan/* A subroutine of ix86_expand_vector_init.  Handle the most general case:
19111169705Skan   all values variable, and none identical.  */
19112169705Skan
19113169705Skanstatic void
19114169705Skanix86_expand_vector_init_general (bool mmx_ok, enum machine_mode mode,
19115169705Skan				 rtx target, rtx vals)
19116169705Skan{
19117169705Skan  enum machine_mode half_mode = GET_MODE_INNER (mode);
19118169705Skan  rtx op0 = NULL, op1 = NULL;
19119169705Skan  bool use_vec_concat = false;
19120169705Skan
19121169705Skan  switch (mode)
19122169705Skan    {
19123169705Skan    case V2SFmode:
19124169705Skan    case V2SImode:
19125169705Skan      if (!mmx_ok && !TARGET_SSE)
19126169705Skan	break;
19127169705Skan      /* FALLTHRU */
19128169705Skan
19129169705Skan    case V2DFmode:
19130169705Skan    case V2DImode:
19131169705Skan      /* For the two element vectors, we always implement VEC_CONCAT.  */
19132169705Skan      op0 = XVECEXP (vals, 0, 0);
19133169705Skan      op1 = XVECEXP (vals, 0, 1);
19134169705Skan      use_vec_concat = true;
19135169705Skan      break;
19136169705Skan
19137169705Skan    case V4SFmode:
19138169705Skan      half_mode = V2SFmode;
19139169705Skan      goto half;
19140169705Skan    case V4SImode:
19141169705Skan      half_mode = V2SImode;
19142169705Skan      goto half;
19143169705Skan    half:
19144169705Skan      {
19145169705Skan	rtvec v;
19146169705Skan
19147169705Skan	/* For V4SF and V4SI, we implement a concat of two V2 vectors.
19148169705Skan	   Recurse to load the two halves.  */
19149169705Skan
19150169705Skan	op0 = gen_reg_rtx (half_mode);
19151169705Skan	v = gen_rtvec (2, XVECEXP (vals, 0, 0), XVECEXP (vals, 0, 1));
19152169705Skan	ix86_expand_vector_init (false, op0, gen_rtx_PARALLEL (half_mode, v));
19153169705Skan
19154169705Skan	op1 = gen_reg_rtx (half_mode);
19155169705Skan	v = gen_rtvec (2, XVECEXP (vals, 0, 2), XVECEXP (vals, 0, 3));
19156169705Skan	ix86_expand_vector_init (false, op1, gen_rtx_PARALLEL (half_mode, v));
19157169705Skan
19158169705Skan	use_vec_concat = true;
19159169705Skan      }
19160169705Skan      break;
19161169705Skan
19162169705Skan    case V8HImode:
19163169705Skan    case V16QImode:
19164169705Skan    case V4HImode:
19165169705Skan    case V8QImode:
19166169705Skan      break;
19167169705Skan
19168169705Skan    default:
19169169705Skan      gcc_unreachable ();
19170169705Skan    }
19171169705Skan
19172169705Skan  if (use_vec_concat)
19173169705Skan    {
19174169705Skan      if (!register_operand (op0, half_mode))
19175169705Skan	op0 = force_reg (half_mode, op0);
19176169705Skan      if (!register_operand (op1, half_mode))
19177169705Skan	op1 = force_reg (half_mode, op1);
19178169705Skan
19179169705Skan      emit_insn (gen_rtx_SET (VOIDmode, target,
19180169705Skan			      gen_rtx_VEC_CONCAT (mode, op0, op1)));
19181169705Skan    }
19182169705Skan  else
19183169705Skan    {
19184169705Skan      int i, j, n_elts, n_words, n_elt_per_word;
19185169705Skan      enum machine_mode inner_mode;
19186169705Skan      rtx words[4], shift;
19187169705Skan
19188169705Skan      inner_mode = GET_MODE_INNER (mode);
19189169705Skan      n_elts = GET_MODE_NUNITS (mode);
19190169705Skan      n_words = GET_MODE_SIZE (mode) / UNITS_PER_WORD;
19191169705Skan      n_elt_per_word = n_elts / n_words;
19192169705Skan      shift = GEN_INT (GET_MODE_BITSIZE (inner_mode));
19193169705Skan
19194169705Skan      for (i = 0; i < n_words; ++i)
19195169705Skan	{
19196169705Skan	  rtx word = NULL_RTX;
19197169705Skan
19198169705Skan	  for (j = 0; j < n_elt_per_word; ++j)
19199169705Skan	    {
19200169705Skan	      rtx elt = XVECEXP (vals, 0, (i+1)*n_elt_per_word - j - 1);
19201169705Skan	      elt = convert_modes (word_mode, inner_mode, elt, true);
19202169705Skan
19203169705Skan	      if (j == 0)
19204169705Skan		word = elt;
19205169705Skan	      else
19206169705Skan		{
19207169705Skan		  word = expand_simple_binop (word_mode, ASHIFT, word, shift,
19208169705Skan					      word, 1, OPTAB_LIB_WIDEN);
19209169705Skan		  word = expand_simple_binop (word_mode, IOR, word, elt,
19210169705Skan					      word, 1, OPTAB_LIB_WIDEN);
19211169705Skan		}
19212169705Skan	    }
19213169705Skan
19214169705Skan	  words[i] = word;
19215169705Skan	}
19216169705Skan
19217169705Skan      if (n_words == 1)
19218169705Skan	emit_move_insn (target, gen_lowpart (mode, words[0]));
19219169705Skan      else if (n_words == 2)
19220169705Skan	{
19221169705Skan	  rtx tmp = gen_reg_rtx (mode);
19222169705Skan	  emit_insn (gen_rtx_CLOBBER (VOIDmode, tmp));
19223169705Skan	  emit_move_insn (gen_lowpart (word_mode, tmp), words[0]);
19224169705Skan	  emit_move_insn (gen_highpart (word_mode, tmp), words[1]);
19225169705Skan	  emit_move_insn (target, tmp);
19226169705Skan	}
19227169705Skan      else if (n_words == 4)
19228169705Skan	{
19229169705Skan	  rtx tmp = gen_reg_rtx (V4SImode);
19230169705Skan	  vals = gen_rtx_PARALLEL (V4SImode, gen_rtvec_v (4, words));
19231169705Skan	  ix86_expand_vector_init_general (false, V4SImode, tmp, vals);
19232169705Skan	  emit_move_insn (target, gen_lowpart (mode, tmp));
19233169705Skan	}
19234169705Skan      else
19235169705Skan	gcc_unreachable ();
19236169705Skan    }
19237169705Skan}
19238169705Skan
19239169705Skan/* Initialize vector TARGET via VALS.  Suppress the use of MMX
19240169705Skan   instructions unless MMX_OK is true.  */
19241169705Skan
19242132743Skanvoid
19243169705Skanix86_expand_vector_init (bool mmx_ok, rtx target, rtx vals)
19244132743Skan{
19245132743Skan  enum machine_mode mode = GET_MODE (target);
19246169705Skan  enum machine_mode inner_mode = GET_MODE_INNER (mode);
19247169705Skan  int n_elts = GET_MODE_NUNITS (mode);
19248169705Skan  int n_var = 0, one_var = -1;
19249169705Skan  bool all_same = true, all_const_zero = true;
19250132743Skan  int i;
19251169705Skan  rtx x;
19252132743Skan
19253169705Skan  for (i = 0; i < n_elts; ++i)
19254132743Skan    {
19255169705Skan      x = XVECEXP (vals, 0, i);
19256169705Skan      if (!CONSTANT_P (x))
19257169705Skan	n_var++, one_var = i;
19258169705Skan      else if (x != CONST0_RTX (inner_mode))
19259169705Skan	all_const_zero = false;
19260169705Skan      if (i > 0 && !rtx_equal_p (x, XVECEXP (vals, 0, 0)))
19261169705Skan	all_same = false;
19262169705Skan    }
19263169705Skan
19264169705Skan  /* Constants are best loaded from the constant pool.  */
19265169705Skan  if (n_var == 0)
19266169705Skan    {
19267132743Skan      emit_move_insn (target, gen_rtx_CONST_VECTOR (mode, XVEC (vals, 0)));
19268132743Skan      return;
19269132743Skan    }
19270132743Skan
19271169705Skan  /* If all values are identical, broadcast the value.  */
19272169705Skan  if (all_same
19273169705Skan      && ix86_expand_vector_init_duplicate (mmx_ok, mode, target,
19274169705Skan					    XVECEXP (vals, 0, 0)))
19275169705Skan    return;
19276169705Skan
19277169705Skan  /* Values where only one field is non-constant are best loaded from
19278169705Skan     the pool and overwritten via move later.  */
19279169705Skan  if (n_var == 1)
19280132743Skan    {
19281169705Skan      if (all_const_zero
19282169705Skan	  && ix86_expand_vector_init_one_nonzero (mmx_ok, mode, target,
19283169705Skan						  XVECEXP (vals, 0, one_var),
19284169705Skan						  one_var))
19285169705Skan	return;
19286132743Skan
19287169705Skan      if (ix86_expand_vector_init_one_var (mmx_ok, mode, target, vals, one_var))
19288169705Skan	return;
19289169705Skan    }
19290169705Skan
19291169705Skan  ix86_expand_vector_init_general (mmx_ok, mode, target, vals);
19292169705Skan}
19293169705Skan
19294169705Skanvoid
19295169705Skanix86_expand_vector_set (bool mmx_ok, rtx target, rtx val, int elt)
19296169705Skan{
19297169705Skan  enum machine_mode mode = GET_MODE (target);
19298169705Skan  enum machine_mode inner_mode = GET_MODE_INNER (mode);
19299169705Skan  bool use_vec_merge = false;
19300169705Skan  rtx tmp;
19301169705Skan
19302169705Skan  switch (mode)
19303169705Skan    {
19304169705Skan    case V2SFmode:
19305169705Skan    case V2SImode:
19306169705Skan      if (mmx_ok)
19307132743Skan	{
19308169705Skan	  tmp = gen_reg_rtx (GET_MODE_INNER (mode));
19309169705Skan	  ix86_expand_vector_extract (true, tmp, target, 1 - elt);
19310169705Skan	  if (elt == 0)
19311169705Skan	    tmp = gen_rtx_VEC_CONCAT (mode, tmp, val);
19312169705Skan	  else
19313169705Skan	    tmp = gen_rtx_VEC_CONCAT (mode, val, tmp);
19314169705Skan	  emit_insn (gen_rtx_SET (VOIDmode, target, tmp));
19315169705Skan	  return;
19316132743Skan	}
19317169705Skan      break;
19318169705Skan
19319169705Skan    case V2DFmode:
19320169705Skan    case V2DImode:
19321169705Skan      {
19322169705Skan	rtx op0, op1;
19323169705Skan
19324169705Skan	/* For the two element vectors, we implement a VEC_CONCAT with
19325169705Skan	   the extraction of the other element.  */
19326169705Skan
19327169705Skan	tmp = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (1, GEN_INT (1 - elt)));
19328169705Skan	tmp = gen_rtx_VEC_SELECT (inner_mode, target, tmp);
19329169705Skan
19330169705Skan	if (elt == 0)
19331169705Skan	  op0 = val, op1 = tmp;
19332169705Skan	else
19333169705Skan	  op0 = tmp, op1 = val;
19334169705Skan
19335169705Skan	tmp = gen_rtx_VEC_CONCAT (mode, op0, op1);
19336169705Skan	emit_insn (gen_rtx_SET (VOIDmode, target, tmp));
19337169705Skan      }
19338132743Skan      return;
19339169705Skan
19340169705Skan    case V4SFmode:
19341169705Skan      switch (elt)
19342169705Skan	{
19343169705Skan	case 0:
19344169705Skan	  use_vec_merge = true;
19345169705Skan	  break;
19346169705Skan
19347169705Skan	case 1:
19348169705Skan	  /* tmp = target = A B C D */
19349169705Skan	  tmp = copy_to_reg (target);
19350169705Skan	  /* target = A A B B */
19351169705Skan	  emit_insn (gen_sse_unpcklps (target, target, target));
19352169705Skan	  /* target = X A B B */
19353169705Skan	  ix86_expand_vector_set (false, target, val, 0);
19354169705Skan	  /* target = A X C D  */
19355169705Skan	  emit_insn (gen_sse_shufps_1 (target, target, tmp,
19356169705Skan				       GEN_INT (1), GEN_INT (0),
19357169705Skan				       GEN_INT (2+4), GEN_INT (3+4)));
19358169705Skan	  return;
19359169705Skan
19360169705Skan	case 2:
19361169705Skan	  /* tmp = target = A B C D */
19362169705Skan	  tmp = copy_to_reg (target);
19363169705Skan	  /* tmp = X B C D */
19364169705Skan	  ix86_expand_vector_set (false, tmp, val, 0);
19365169705Skan	  /* target = A B X D */
19366169705Skan	  emit_insn (gen_sse_shufps_1 (target, target, tmp,
19367169705Skan				       GEN_INT (0), GEN_INT (1),
19368169705Skan				       GEN_INT (0+4), GEN_INT (3+4)));
19369169705Skan	  return;
19370169705Skan
19371169705Skan	case 3:
19372169705Skan	  /* tmp = target = A B C D */
19373169705Skan	  tmp = copy_to_reg (target);
19374169705Skan	  /* tmp = X B C D */
19375169705Skan	  ix86_expand_vector_set (false, tmp, val, 0);
19376169705Skan	  /* target = A B X D */
19377169705Skan	  emit_insn (gen_sse_shufps_1 (target, target, tmp,
19378169705Skan				       GEN_INT (0), GEN_INT (1),
19379169705Skan				       GEN_INT (2+4), GEN_INT (0+4)));
19380169705Skan	  return;
19381169705Skan
19382169705Skan	default:
19383169705Skan	  gcc_unreachable ();
19384169705Skan	}
19385169705Skan      break;
19386169705Skan
19387169705Skan    case V4SImode:
19388169705Skan      /* Element 0 handled by vec_merge below.  */
19389169705Skan      if (elt == 0)
19390169705Skan	{
19391169705Skan	  use_vec_merge = true;
19392169705Skan	  break;
19393169705Skan	}
19394169705Skan
19395169705Skan      if (TARGET_SSE2)
19396169705Skan	{
19397169705Skan	  /* With SSE2, use integer shuffles to swap element 0 and ELT,
19398169705Skan	     store into element 0, then shuffle them back.  */
19399169705Skan
19400169705Skan	  rtx order[4];
19401169705Skan
19402169705Skan	  order[0] = GEN_INT (elt);
19403169705Skan	  order[1] = const1_rtx;
19404169705Skan	  order[2] = const2_rtx;
19405169705Skan	  order[3] = GEN_INT (3);
19406169705Skan	  order[elt] = const0_rtx;
19407169705Skan
19408169705Skan	  emit_insn (gen_sse2_pshufd_1 (target, target, order[0],
19409169705Skan					order[1], order[2], order[3]));
19410169705Skan
19411169705Skan	  ix86_expand_vector_set (false, target, val, 0);
19412169705Skan
19413169705Skan	  emit_insn (gen_sse2_pshufd_1 (target, target, order[0],
19414169705Skan					order[1], order[2], order[3]));
19415169705Skan	}
19416169705Skan      else
19417169705Skan	{
19418169705Skan	  /* For SSE1, we have to reuse the V4SF code.  */
19419169705Skan	  ix86_expand_vector_set (false, gen_lowpart (V4SFmode, target),
19420169705Skan				  gen_lowpart (SFmode, val), elt);
19421169705Skan	}
19422169705Skan      return;
19423169705Skan
19424169705Skan    case V8HImode:
19425169705Skan      use_vec_merge = TARGET_SSE2;
19426169705Skan      break;
19427169705Skan    case V4HImode:
19428169705Skan      use_vec_merge = mmx_ok && (TARGET_SSE || TARGET_3DNOW_A);
19429169705Skan      break;
19430169705Skan
19431169705Skan    case V16QImode:
19432169705Skan    case V8QImode:
19433169705Skan    default:
19434169705Skan      break;
19435132743Skan    }
19436132743Skan
19437169705Skan  if (use_vec_merge)
19438132743Skan    {
19439169705Skan      tmp = gen_rtx_VEC_DUPLICATE (mode, val);
19440169705Skan      tmp = gen_rtx_VEC_MERGE (mode, tmp, target, GEN_INT (1 << elt));
19441169705Skan      emit_insn (gen_rtx_SET (VOIDmode, target, tmp));
19442169705Skan    }
19443169705Skan  else
19444169705Skan    {
19445169705Skan      rtx mem = assign_stack_temp (mode, GET_MODE_SIZE (mode), false);
19446169705Skan
19447169705Skan      emit_move_insn (mem, target);
19448169705Skan
19449169705Skan      tmp = adjust_address (mem, inner_mode, elt*GET_MODE_SIZE (inner_mode));
19450169705Skan      emit_move_insn (tmp, val);
19451169705Skan
19452169705Skan      emit_move_insn (target, mem);
19453169705Skan    }
19454169705Skan}
19455169705Skan
19456169705Skanvoid
19457169705Skanix86_expand_vector_extract (bool mmx_ok, rtx target, rtx vec, int elt)
19458169705Skan{
19459169705Skan  enum machine_mode mode = GET_MODE (vec);
19460169705Skan  enum machine_mode inner_mode = GET_MODE_INNER (mode);
19461169705Skan  bool use_vec_extr = false;
19462169705Skan  rtx tmp;
19463169705Skan
19464169705Skan  switch (mode)
19465169705Skan    {
19466169705Skan    case V2SImode:
19467169705Skan    case V2SFmode:
19468169705Skan      if (!mmx_ok)
19469169705Skan	break;
19470169705Skan      /* FALLTHRU */
19471169705Skan
19472169705Skan    case V2DFmode:
19473169705Skan    case V2DImode:
19474169705Skan      use_vec_extr = true;
19475169705Skan      break;
19476169705Skan
19477169705Skan    case V4SFmode:
19478169705Skan      switch (elt)
19479132743Skan	{
19480169705Skan	case 0:
19481169705Skan	  tmp = vec;
19482169705Skan	  break;
19483132743Skan
19484169705Skan	case 1:
19485169705Skan	case 3:
19486169705Skan	  tmp = gen_reg_rtx (mode);
19487169705Skan	  emit_insn (gen_sse_shufps_1 (tmp, vec, vec,
19488169705Skan				       GEN_INT (elt), GEN_INT (elt),
19489169705Skan				       GEN_INT (elt+4), GEN_INT (elt+4)));
19490169705Skan	  break;
19491169705Skan
19492169705Skan	case 2:
19493169705Skan	  tmp = gen_reg_rtx (mode);
19494169705Skan	  emit_insn (gen_sse_unpckhps (tmp, vec, vec));
19495169705Skan	  break;
19496169705Skan
19497169705Skan	default:
19498169705Skan	  gcc_unreachable ();
19499132743Skan	}
19500169705Skan      vec = tmp;
19501169705Skan      use_vec_extr = true;
19502169705Skan      elt = 0;
19503169705Skan      break;
19504169705Skan
19505169705Skan    case V4SImode:
19506169705Skan      if (TARGET_SSE2)
19507132743Skan	{
19508169705Skan	  switch (elt)
19509169705Skan	    {
19510169705Skan	    case 0:
19511169705Skan	      tmp = vec;
19512169705Skan	      break;
19513132743Skan
19514169705Skan	    case 1:
19515169705Skan	    case 3:
19516169705Skan	      tmp = gen_reg_rtx (mode);
19517169705Skan	      emit_insn (gen_sse2_pshufd_1 (tmp, vec,
19518169705Skan					    GEN_INT (elt), GEN_INT (elt),
19519169705Skan					    GEN_INT (elt), GEN_INT (elt)));
19520169705Skan	      break;
19521169705Skan
19522169705Skan	    case 2:
19523169705Skan	      tmp = gen_reg_rtx (mode);
19524169705Skan	      emit_insn (gen_sse2_punpckhdq (tmp, vec, vec));
19525169705Skan	      break;
19526169705Skan
19527169705Skan	    default:
19528169705Skan	      gcc_unreachable ();
19529169705Skan	    }
19530169705Skan	  vec = tmp;
19531169705Skan	  use_vec_extr = true;
19532169705Skan	  elt = 0;
19533132743Skan	}
19534169705Skan      else
19535169705Skan	{
19536169705Skan	  /* For SSE1, we have to reuse the V4SF code.  */
19537169705Skan	  ix86_expand_vector_extract (false, gen_lowpart (SFmode, target),
19538169705Skan				      gen_lowpart (V4SFmode, vec), elt);
19539169705Skan	  return;
19540169705Skan	}
19541169705Skan      break;
19542169705Skan
19543169705Skan    case V8HImode:
19544169705Skan      use_vec_extr = TARGET_SSE2;
19545169705Skan      break;
19546169705Skan    case V4HImode:
19547169705Skan      use_vec_extr = mmx_ok && (TARGET_SSE || TARGET_3DNOW_A);
19548169705Skan      break;
19549169705Skan
19550169705Skan    case V16QImode:
19551169705Skan    case V8QImode:
19552169705Skan      /* ??? Could extract the appropriate HImode element and shift.  */
19553169705Skan    default:
19554169705Skan      break;
19555132743Skan    }
19556169705Skan
19557169705Skan  if (use_vec_extr)
19558169705Skan    {
19559169705Skan      tmp = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (1, GEN_INT (elt)));
19560169705Skan      tmp = gen_rtx_VEC_SELECT (inner_mode, vec, tmp);
19561169705Skan
19562169705Skan      /* Let the rtl optimizers know about the zero extension performed.  */
19563169705Skan      if (inner_mode == HImode)
19564169705Skan	{
19565169705Skan	  tmp = gen_rtx_ZERO_EXTEND (SImode, tmp);
19566169705Skan	  target = gen_lowpart (SImode, target);
19567169705Skan	}
19568169705Skan
19569169705Skan      emit_insn (gen_rtx_SET (VOIDmode, target, tmp));
19570169705Skan    }
19571169705Skan  else
19572169705Skan    {
19573169705Skan      rtx mem = assign_stack_temp (mode, GET_MODE_SIZE (mode), false);
19574169705Skan
19575169705Skan      emit_move_insn (mem, vec);
19576169705Skan
19577169705Skan      tmp = adjust_address (mem, inner_mode, elt*GET_MODE_SIZE (inner_mode));
19578169705Skan      emit_move_insn (target, tmp);
19579169705Skan    }
19580132743Skan}
19581132743Skan
19582169705Skan/* Expand a vector reduction on V4SFmode for SSE1.  FN is the binary
19583169705Skan   pattern to reduce; DEST is the destination; IN is the input vector.  */
19584169705Skan
19585169705Skanvoid
19586169705Skanix86_expand_reduc_v4sf (rtx (*fn) (rtx, rtx, rtx), rtx dest, rtx in)
19587169705Skan{
19588169705Skan  rtx tmp1, tmp2, tmp3;
19589169705Skan
19590169705Skan  tmp1 = gen_reg_rtx (V4SFmode);
19591169705Skan  tmp2 = gen_reg_rtx (V4SFmode);
19592169705Skan  tmp3 = gen_reg_rtx (V4SFmode);
19593169705Skan
19594169705Skan  emit_insn (gen_sse_movhlps (tmp1, in, in));
19595169705Skan  emit_insn (fn (tmp2, tmp1, in));
19596169705Skan
19597169705Skan  emit_insn (gen_sse_shufps_1 (tmp3, tmp2, tmp2,
19598169705Skan			       GEN_INT (1), GEN_INT (1),
19599169705Skan			       GEN_INT (1+4), GEN_INT (1+4)));
19600169705Skan  emit_insn (fn (dest, tmp2, tmp3));
19601169705Skan}
19602169705Skan
19603169705Skan/* Target hook for scalar_mode_supported_p.  */
19604169705Skanstatic bool
19605169705Skanix86_scalar_mode_supported_p (enum machine_mode mode)
19606169705Skan{
19607169705Skan  if (DECIMAL_FLOAT_MODE_P (mode))
19608169705Skan    return true;
19609169705Skan  else
19610169705Skan    return default_scalar_mode_supported_p (mode);
19611169705Skan}
19612169705Skan
19613169705Skan/* Implements target hook vector_mode_supported_p.  */
19614169705Skanstatic bool
19615169705Skanix86_vector_mode_supported_p (enum machine_mode mode)
19616169705Skan{
19617169705Skan  if (TARGET_SSE && VALID_SSE_REG_MODE (mode))
19618169705Skan    return true;
19619169705Skan  if (TARGET_SSE2 && VALID_SSE2_REG_MODE (mode))
19620169705Skan    return true;
19621169705Skan  if (TARGET_MMX && VALID_MMX_REG_MODE (mode))
19622169705Skan    return true;
19623169705Skan  if (TARGET_3DNOW && VALID_MMX_REG_MODE_3DNOW (mode))
19624169705Skan    return true;
19625169705Skan  return false;
19626169705Skan}
19627169705Skan
19628169705Skan/* Worker function for TARGET_MD_ASM_CLOBBERS.
19629169705Skan
19630169705Skan   We do this in the new i386 backend to maintain source compatibility
19631169705Skan   with the old cc0-based compiler.  */
19632169705Skan
19633169705Skanstatic tree
19634169705Skanix86_md_asm_clobbers (tree outputs ATTRIBUTE_UNUSED,
19635169705Skan		      tree inputs ATTRIBUTE_UNUSED,
19636169705Skan		      tree clobbers)
19637169705Skan{
19638169705Skan  clobbers = tree_cons (NULL_TREE, build_string (5, "flags"),
19639169705Skan			clobbers);
19640169705Skan  clobbers = tree_cons (NULL_TREE, build_string (4, "fpsr"),
19641169705Skan			clobbers);
19642169705Skan  clobbers = tree_cons (NULL_TREE, build_string (7, "dirflag"),
19643169705Skan			clobbers);
19644169705Skan  return clobbers;
19645169705Skan}
19646169705Skan
19647169705Skan/* Return true if this goes in small data/bss.  */
19648169705Skan
19649169705Skanstatic bool
19650169705Skanix86_in_large_data_p (tree exp)
19651169705Skan{
19652169705Skan  if (ix86_cmodel != CM_MEDIUM && ix86_cmodel != CM_MEDIUM_PIC)
19653169705Skan    return false;
19654169705Skan
19655169705Skan  /* Functions are never large data.  */
19656169705Skan  if (TREE_CODE (exp) == FUNCTION_DECL)
19657169705Skan    return false;
19658169705Skan
19659169705Skan  if (TREE_CODE (exp) == VAR_DECL && DECL_SECTION_NAME (exp))
19660169705Skan    {
19661169705Skan      const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (exp));
19662169705Skan      if (strcmp (section, ".ldata") == 0
19663169705Skan	  || strcmp (section, ".lbss") == 0)
19664169705Skan	return true;
19665169705Skan      return false;
19666169705Skan    }
19667169705Skan  else
19668169705Skan    {
19669169705Skan      HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp));
19670169705Skan
19671169705Skan      /* If this is an incomplete type with size 0, then we can't put it
19672169705Skan	 in data because it might be too big when completed.  */
19673169705Skan      if (!size || size > ix86_section_threshold)
19674169705Skan	return true;
19675169705Skan    }
19676169705Skan
19677169705Skan  return false;
19678169705Skan}
19679169705Skanstatic void
19680169705Skanix86_encode_section_info (tree decl, rtx rtl, int first)
19681169705Skan{
19682169705Skan  default_encode_section_info (decl, rtl, first);
19683169705Skan
19684169705Skan  if (TREE_CODE (decl) == VAR_DECL
19685169705Skan      && (TREE_STATIC (decl) || DECL_EXTERNAL (decl))
19686169705Skan      && ix86_in_large_data_p (decl))
19687169705Skan    SYMBOL_REF_FLAGS (XEXP (rtl, 0)) |= SYMBOL_FLAG_FAR_ADDR;
19688169705Skan}
19689169705Skan
19690169705Skan/* Worker function for REVERSE_CONDITION.  */
19691169705Skan
19692169705Skanenum rtx_code
19693169705Skanix86_reverse_condition (enum rtx_code code, enum machine_mode mode)
19694169705Skan{
19695169705Skan  return (mode != CCFPmode && mode != CCFPUmode
19696169705Skan	  ? reverse_condition (code)
19697169705Skan	  : reverse_condition_maybe_unordered (code));
19698169705Skan}
19699169705Skan
19700169705Skan/* Output code to perform an x87 FP register move, from OPERANDS[1]
19701169705Skan   to OPERANDS[0].  */
19702169705Skan
19703169705Skanconst char *
19704169705Skanoutput_387_reg_move (rtx insn, rtx *operands)
19705169705Skan{
19706169705Skan  if (REG_P (operands[1])
19707169705Skan      && find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
19708169705Skan    {
19709169705Skan      if (REGNO (operands[0]) == FIRST_STACK_REG)
19710169705Skan	return output_387_ffreep (operands, 0);
19711169705Skan      return "fstp\t%y0";
19712169705Skan    }
19713169705Skan  if (STACK_TOP_P (operands[0]))
19714169705Skan    return "fld%z1\t%y1";
19715169705Skan  return "fst\t%y0";
19716169705Skan}
19717169705Skan
19718169705Skan/* Output code to perform a conditional jump to LABEL, if C2 flag in
19719169705Skan   FP status register is set.  */
19720169705Skan
19721169705Skanvoid
19722169705Skanix86_emit_fp_unordered_jump (rtx label)
19723169705Skan{
19724169705Skan  rtx reg = gen_reg_rtx (HImode);
19725169705Skan  rtx temp;
19726169705Skan
19727169705Skan  emit_insn (gen_x86_fnstsw_1 (reg));
19728169705Skan
19729169705Skan  if (TARGET_USE_SAHF)
19730169705Skan    {
19731169705Skan      emit_insn (gen_x86_sahf_1 (reg));
19732169705Skan
19733169705Skan      temp = gen_rtx_REG (CCmode, FLAGS_REG);
19734169705Skan      temp = gen_rtx_UNORDERED (VOIDmode, temp, const0_rtx);
19735169705Skan    }
19736169705Skan  else
19737169705Skan    {
19738169705Skan      emit_insn (gen_testqi_ext_ccno_0 (reg, GEN_INT (0x04)));
19739169705Skan
19740169705Skan      temp = gen_rtx_REG (CCNOmode, FLAGS_REG);
19741169705Skan      temp = gen_rtx_NE (VOIDmode, temp, const0_rtx);
19742169705Skan    }
19743169705Skan
19744169705Skan  temp = gen_rtx_IF_THEN_ELSE (VOIDmode, temp,
19745169705Skan			      gen_rtx_LABEL_REF (VOIDmode, label),
19746169705Skan			      pc_rtx);
19747169705Skan  temp = gen_rtx_SET (VOIDmode, pc_rtx, temp);
19748169705Skan  emit_jump_insn (temp);
19749169705Skan}
19750169705Skan
19751169705Skan/* Output code to perform a log1p XFmode calculation.  */
19752169705Skan
19753169705Skanvoid ix86_emit_i387_log1p (rtx op0, rtx op1)
19754169705Skan{
19755169705Skan  rtx label1 = gen_label_rtx ();
19756169705Skan  rtx label2 = gen_label_rtx ();
19757169705Skan
19758169705Skan  rtx tmp = gen_reg_rtx (XFmode);
19759169705Skan  rtx tmp2 = gen_reg_rtx (XFmode);
19760169705Skan
19761169705Skan  emit_insn (gen_absxf2 (tmp, op1));
19762169705Skan  emit_insn (gen_cmpxf (tmp,
19763169705Skan    CONST_DOUBLE_FROM_REAL_VALUE (
19764169705Skan       REAL_VALUE_ATOF ("0.29289321881345247561810596348408353", XFmode),
19765169705Skan       XFmode)));
19766169705Skan  emit_jump_insn (gen_bge (label1));
19767169705Skan
19768169705Skan  emit_move_insn (tmp2, standard_80387_constant_rtx (4)); /* fldln2 */
19769169705Skan  emit_insn (gen_fyl2xp1_xf3 (op0, tmp2, op1));
19770169705Skan  emit_jump (label2);
19771169705Skan
19772169705Skan  emit_label (label1);
19773169705Skan  emit_move_insn (tmp, CONST1_RTX (XFmode));
19774169705Skan  emit_insn (gen_addxf3 (tmp, op1, tmp));
19775169705Skan  emit_move_insn (tmp2, standard_80387_constant_rtx (4)); /* fldln2 */
19776169705Skan  emit_insn (gen_fyl2x_xf3 (op0, tmp2, tmp));
19777169705Skan
19778169705Skan  emit_label (label2);
19779169705Skan}
19780169705Skan
19781169705Skan/* Solaris implementation of TARGET_ASM_NAMED_SECTION.  */
19782169705Skan
19783169705Skanstatic void
19784169705Skani386_solaris_elf_named_section (const char *name, unsigned int flags,
19785169705Skan				tree decl)
19786169705Skan{
19787169705Skan  /* With Binutils 2.15, the "@unwind" marker must be specified on
19788169705Skan     every occurrence of the ".eh_frame" section, not just the first
19789169705Skan     one.  */
19790169705Skan  if (TARGET_64BIT
19791169705Skan      && strcmp (name, ".eh_frame") == 0)
19792169705Skan    {
19793169705Skan      fprintf (asm_out_file, "\t.section\t%s,\"%s\",@unwind\n", name,
19794169705Skan	       flags & SECTION_WRITE ? "aw" : "a");
19795169705Skan      return;
19796169705Skan    }
19797169705Skan  default_elf_asm_named_section (name, flags, decl);
19798169705Skan}
19799169705Skan
19800169705Skan/* Return the mangling of TYPE if it is an extended fundamental type.  */
19801169705Skan
19802169705Skanstatic const char *
19803169705Skanix86_mangle_fundamental_type (tree type)
19804169705Skan{
19805169705Skan  switch (TYPE_MODE (type))
19806169705Skan    {
19807169705Skan    case TFmode:
19808169705Skan      /* __float128 is "g".  */
19809169705Skan      return "g";
19810169705Skan    case XFmode:
19811169705Skan      /* "long double" or __float80 is "e".  */
19812169705Skan      return "e";
19813169705Skan    default:
19814169705Skan      return NULL;
19815169705Skan    }
19816169705Skan}
19817169705Skan
19818169705Skan/* For 32-bit code we can save PIC register setup by using
19819169705Skan   __stack_chk_fail_local hidden function instead of calling
19820169705Skan   __stack_chk_fail directly.  64-bit code doesn't need to setup any PIC
19821169705Skan   register, so it is better to call __stack_chk_fail directly.  */
19822169705Skan
19823169705Skanstatic tree
19824169705Skanix86_stack_protect_fail (void)
19825169705Skan{
19826169705Skan  return TARGET_64BIT
19827169705Skan	 ? default_external_stack_protect_fail ()
19828169705Skan	 : default_hidden_stack_protect_fail ();
19829169705Skan}
19830169705Skan
19831169705Skan/* Select a format to encode pointers in exception handling data.  CODE
19832169705Skan   is 0 for data, 1 for code labels, 2 for function pointers.  GLOBAL is
19833169705Skan   true if the symbol may be affected by dynamic relocations.
19834169705Skan
19835169705Skan   ??? All x86 object file formats are capable of representing this.
19836169705Skan   After all, the relocation needed is the same as for the call insn.
19837169705Skan   Whether or not a particular assembler allows us to enter such, I
19838169705Skan   guess we'll have to see.  */
19839169705Skanint
19840169705Skanasm_preferred_eh_data_format (int code, int global)
19841169705Skan{
19842169705Skan  if (flag_pic)
19843169705Skan    {
19844169705Skan      int type = DW_EH_PE_sdata8;
19845169705Skan      if (!TARGET_64BIT
19846169705Skan	  || ix86_cmodel == CM_SMALL_PIC
19847169705Skan	  || (ix86_cmodel == CM_MEDIUM_PIC && (global || code)))
19848169705Skan	type = DW_EH_PE_sdata4;
19849169705Skan      return (global ? DW_EH_PE_indirect : 0) | DW_EH_PE_pcrel | type;
19850169705Skan    }
19851169705Skan  if (ix86_cmodel == CM_SMALL
19852169705Skan      || (ix86_cmodel == CM_MEDIUM && code))
19853169705Skan    return DW_EH_PE_udata4;
19854169705Skan  return DW_EH_PE_absptr;
19855169705Skan}
19856169705Skan
19857117408Skan#include "gt-i386.h"
19858