OSDN Git Service

* config/i386/i386.c: Use ASM_LONG instead of .long. Concatenate
[pf3gnuchains/gcc-fork.git] / gcc / config / i386 / i386.c
index 776d07a..35c169a 100644 (file)
@@ -1,6 +1,6 @@
 /* Subroutines used for code generation on IA-32.
    Copyright (C) 1988, 1992, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
-   2002, 2003, 2004, 2005, 2006, 2007, 2008
+   2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -35,7 +35,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "insn-codes.h"
 #include "insn-attr.h"
 #include "flags.h"
-#include "c-common.h"
 #include "except.h"
 #include "function.h"
 #include "recog.h"
@@ -48,11 +47,12 @@ along with GCC; see the file COPYING3.  If not see
 #include "target-def.h"
 #include "langhooks.h"
 #include "cgraph.h"
-#include "tree-gimple.h"
+#include "gimple.h"
 #include "dwarf2.h"
 #include "df.h"
 #include "tm-constrs.h"
 #include "params.h"
+#include "cselib.h"
 
 static int x86_builtin_vectorization_cost (bool);
 static rtx legitimize_dllimport_symbol (rtx, bool);
@@ -75,8 +75,8 @@ static rtx legitimize_dllimport_symbol (rtx, bool);
 
 #define DUMMY_STRINGOP_ALGS {libcall, {{-1, libcall}}}
 
-static const
-struct processor_costs size_cost = {   /* costs for tuning for size */
+const
+struct processor_costs ix86_size_cost = {/* costs for tuning for size */
   COSTS_N_BYTES (2),                   /* cost of an add instruction */
   COSTS_N_BYTES (3),                   /* cost of a lea instruction */
   COSTS_N_BYTES (2),                   /* variable shift costs */
@@ -991,7 +991,8 @@ struct processor_costs core2_cost = {
   2,                                   /* cost of reg,reg fld/fst */
   {6, 6, 6},                           /* cost of loading fp registers
                                           in SFmode, DFmode and XFmode */
-  {4, 4, 4},                           /* cost of loading integer registers */
+  {4, 4, 4},                           /* cost of storing fp registers
+                                          in SFmode, DFmode and XFmode */
   2,                                   /* cost of moving MMX register */
   {6, 6},                              /* cost of loading MMX registers
                                           in SImode and DImode */
@@ -1034,6 +1035,79 @@ struct processor_costs core2_cost = {
   1,                                    /* cond_not_taken_branch_cost.  */
 };
 
+static const
+struct processor_costs atom_cost = {
+  COSTS_N_INSNS (1),                   /* cost of an add instruction */
+  COSTS_N_INSNS (1) + 1,               /* cost of a lea instruction */
+  COSTS_N_INSNS (1),                   /* variable shift costs */
+  COSTS_N_INSNS (1),                   /* constant shift costs */
+  {COSTS_N_INSNS (3),                  /* cost of starting multiply for QI */
+   COSTS_N_INSNS (4),                  /*                               HI */
+   COSTS_N_INSNS (3),                  /*                               SI */
+   COSTS_N_INSNS (4),                  /*                               DI */
+   COSTS_N_INSNS (2)},                 /*                               other */
+  0,                                   /* cost of multiply per each bit set */
+  {COSTS_N_INSNS (18),                 /* cost of a divide/mod for QI */
+   COSTS_N_INSNS (26),                 /*                          HI */
+   COSTS_N_INSNS (42),                 /*                          SI */
+   COSTS_N_INSNS (74),                 /*                          DI */
+   COSTS_N_INSNS (74)},                        /*                          other */
+  COSTS_N_INSNS (1),                   /* cost of movsx */
+  COSTS_N_INSNS (1),                   /* cost of movzx */
+  8,                                   /* "large" insn */
+  17,                                  /* MOVE_RATIO */
+  2,                                   /* cost for loading QImode using movzbl */
+  {4, 4, 4},                           /* cost of loading integer registers
+                                          in QImode, HImode and SImode.
+                                          Relative to reg-reg move (2).  */
+  {4, 4, 4},                           /* cost of storing integer registers */
+  4,                                   /* cost of reg,reg fld/fst */
+  {12, 12, 12},                                /* cost of loading fp registers
+                                          in SFmode, DFmode and XFmode */
+  {6, 6, 8},                           /* cost of storing fp registers
+                                          in SFmode, DFmode and XFmode */
+  2,                                   /* cost of moving MMX register */
+  {8, 8},                              /* cost of loading MMX registers
+                                          in SImode and DImode */
+  {8, 8},                              /* cost of storing MMX registers
+                                          in SImode and DImode */
+  2,                                   /* cost of moving SSE register */
+  {8, 8, 8},                           /* cost of loading SSE registers
+                                          in SImode, DImode and TImode */
+  {8, 8, 8},                           /* cost of storing SSE registers
+                                          in SImode, DImode and TImode */
+  5,                                   /* MMX or SSE register to integer */
+  32,                                  /* size of l1 cache.  */
+  256,                                 /* size of l2 cache.  */
+  64,                                  /* size of prefetch block */
+  6,                                   /* number of parallel prefetches */
+  3,                                   /* Branch cost */
+  COSTS_N_INSNS (8),                   /* cost of FADD and FSUB insns.  */
+  COSTS_N_INSNS (8),                   /* cost of FMUL instruction.  */
+  COSTS_N_INSNS (20),                  /* cost of FDIV instruction.  */
+  COSTS_N_INSNS (8),                   /* cost of FABS instruction.  */
+  COSTS_N_INSNS (8),                   /* cost of FCHS instruction.  */
+  COSTS_N_INSNS (40),                  /* cost of FSQRT instruction.  */
+  {{libcall, {{11, loop}, {-1, rep_prefix_4_byte}}},
+   {libcall, {{32, loop}, {64, rep_prefix_4_byte},
+          {8192, rep_prefix_8_byte}, {-1, libcall}}}},
+  {{libcall, {{8, loop}, {15, unrolled_loop},
+          {2048, rep_prefix_4_byte}, {-1, libcall}}},
+   {libcall, {{24, loop}, {32, unrolled_loop},
+          {8192, rep_prefix_8_byte}, {-1, libcall}}}},
+  1,                                    /* scalar_stmt_cost.  */
+  1,                                    /* scalar load_cost.  */
+  1,                                    /* scalar_store_cost.  */
+  1,                                    /* vec_stmt_cost.  */
+  1,                                    /* vec_to_scalar_cost.  */
+  1,                                    /* scalar_to_vec_cost.  */
+  1,                                    /* vec_align_load_cost.  */
+  2,                                    /* vec_unalign_load_cost.  */
+  1,                                    /* vec_store_cost.  */
+  3,                                    /* cond_taken_branch_cost.  */
+  1,                                    /* cond_not_taken_branch_cost.  */
+};
+
 /* Generic64 should produce code tuned for Nocona and K8.  */
 static const
 struct processor_costs generic64_cost = {
@@ -1192,6 +1266,7 @@ const struct processor_costs *ix86_cost = &pentium_cost;
 #define m_PENT4  (1<<PROCESSOR_PENTIUM4)
 #define m_NOCONA  (1<<PROCESSOR_NOCONA)
 #define m_CORE2  (1<<PROCESSOR_CORE2)
+#define m_ATOM  (1<<PROCESSOR_ATOM)
 
 #define m_GEODE  (1<<PROCESSOR_GEODE)
 #define m_K6  (1<<PROCESSOR_K6)
@@ -1210,7 +1285,11 @@ const struct processor_costs *ix86_cost = &pentium_cost;
 #define m_GENERIC (m_GENERIC32 | m_GENERIC64)
 
 /* Feature tests against the various tunings.  */
-unsigned int ix86_tune_features[X86_TUNE_LAST] = {
+unsigned char ix86_tune_features[X86_TUNE_LAST];
+
+/* Feature tests against the various tunings used to create ix86_tune_features
+   based on the processor mask.  */
+static unsigned int initial_ix86_tune_features[X86_TUNE_LAST] = {
   /* X86_TUNE_USE_LEAVE: Leave does not affect Nocona SPEC2000 results
      negatively, so enabling for Generic64 seems like good code size
      tradeoff.  We can't enable it for 32bit generic because it does not
@@ -1224,14 +1303,12 @@ unsigned int ix86_tune_features[X86_TUNE_LAST] = {
   /* X86_TUNE_ZERO_EXTEND_WITH_AND */
   m_486 | m_PENT,
 
-  /* X86_TUNE_USE_BIT_TEST */
-  m_386,
-
   /* X86_TUNE_UNROLL_STRLEN */
-  m_486 | m_PENT | m_PPRO | m_AMD_MULTIPLE | m_K6 | m_CORE2 | m_GENERIC,
+  m_486 | m_PENT | m_ATOM | m_PPRO | m_AMD_MULTIPLE | m_K6
+  | m_CORE2 | m_GENERIC,
 
   /* X86_TUNE_DEEP_BRANCH_PREDICTION */
-  m_PPRO | m_K6_GEODE | m_AMD_MULTIPLE | m_PENT4 | m_GENERIC,
+  m_ATOM | m_PPRO | m_K6_GEODE | m_AMD_MULTIPLE | m_PENT4 | m_GENERIC,
 
   /* X86_TUNE_BRANCH_PREDICTION_HINTS: Branch hints were put in P4 based
      on simulation result. But after P4 was made, no performance benefit
@@ -1243,12 +1320,12 @@ unsigned int ix86_tune_features[X86_TUNE_LAST] = {
   ~m_386,
 
   /* X86_TUNE_USE_SAHF */
-  m_PPRO | m_K6_GEODE | m_K8 | m_AMDFAM10 | m_PENT4
+  m_ATOM | m_PPRO | m_K6_GEODE | m_K8 | m_AMDFAM10 | m_PENT4
   | m_NOCONA | m_CORE2 | m_GENERIC,
 
   /* X86_TUNE_MOVX: Enable to zero extend integer registers to avoid
      partial dependencies.  */
-  m_AMD_MULTIPLE | m_PPRO | m_PENT4 | m_NOCONA
+  m_AMD_MULTIPLE | m_ATOM | m_PPRO | m_PENT4 | m_NOCONA
   | m_CORE2 | m_GENERIC | m_GEODE /* m_386 | m_K6 */,
 
   /* X86_TUNE_PARTIAL_REG_STALL: We probably ought to watch for partial
@@ -1268,13 +1345,13 @@ unsigned int ix86_tune_features[X86_TUNE_LAST] = {
   m_386 | m_486 | m_K6_GEODE,
 
   /* X86_TUNE_USE_SIMODE_FIOP */
-  ~(m_PPRO | m_AMD_MULTIPLE | m_PENT | m_CORE2 | m_GENERIC),
+  ~(m_PPRO | m_AMD_MULTIPLE | m_PENT | m_ATOM | m_CORE2 | m_GENERIC),
 
   /* X86_TUNE_USE_MOV0 */
   m_K6,
 
   /* X86_TUNE_USE_CLTD */
-  ~(m_PENT | m_K6 | m_CORE2 | m_GENERIC),
+  ~(m_PENT | m_ATOM | m_K6 | m_CORE2 | m_GENERIC),
 
   /* X86_TUNE_USE_XCHGB: Use xchgb %rh,%rl instead of rolw/rorw $8,rx.  */
   m_PENT4,
@@ -1289,8 +1366,8 @@ unsigned int ix86_tune_features[X86_TUNE_LAST] = {
   ~(m_PENT | m_PPRO),
 
   /* X86_TUNE_PROMOTE_QIMODE */
-  m_K6_GEODE | m_PENT | m_386 | m_486 | m_AMD_MULTIPLE | m_CORE2
-  | m_GENERIC /* | m_PENT4 ? */,
+  m_K6_GEODE | m_PENT | m_ATOM | m_386 | m_486 | m_AMD_MULTIPLE
+  | m_CORE2 | m_GENERIC /* | m_PENT4 ? */,
 
   /* X86_TUNE_FAST_PREFIX */
   ~(m_PENT | m_486 | m_386),
@@ -1314,26 +1391,28 @@ unsigned int ix86_tune_features[X86_TUNE_LAST] = {
   m_PPRO,
 
   /* X86_TUNE_ADD_ESP_4: Enable if add/sub is preferred over 1/2 push/pop.  */
-  m_AMD_MULTIPLE | m_K6_GEODE | m_PENT4 | m_NOCONA | m_CORE2 | m_GENERIC,
+  m_ATOM | m_AMD_MULTIPLE | m_K6_GEODE | m_PENT4 | m_NOCONA
+  | m_CORE2 | m_GENERIC,
 
   /* X86_TUNE_ADD_ESP_8 */
-  m_AMD_MULTIPLE | m_PPRO | m_K6_GEODE | m_386
+  m_AMD_MULTIPLE | m_ATOM | m_PPRO | m_K6_GEODE | m_386
   | m_486 | m_PENT4 | m_NOCONA | m_CORE2 | m_GENERIC,
 
   /* X86_TUNE_SUB_ESP_4 */
-  m_AMD_MULTIPLE | m_PPRO | m_PENT4 | m_NOCONA | m_CORE2 | m_GENERIC,
+  m_AMD_MULTIPLE | m_ATOM | m_PPRO | m_PENT4 | m_NOCONA | m_CORE2
+  | m_GENERIC,
 
   /* X86_TUNE_SUB_ESP_8 */
-  m_AMD_MULTIPLE | m_PPRO | m_386 | m_486
+  m_AMD_MULTIPLE | m_ATOM | m_PPRO | m_386 | m_486
   | m_PENT4 | m_NOCONA | m_CORE2 | m_GENERIC,
 
   /* X86_TUNE_INTEGER_DFMODE_MOVES: Enable if integer moves are preferred
      for DFmode copies */
-  ~(m_AMD_MULTIPLE | m_PENT4 | m_NOCONA | m_PPRO | m_CORE2
+  ~(m_AMD_MULTIPLE | m_ATOM | m_PENT4 | m_NOCONA | m_PPRO | m_CORE2
     | m_GENERIC | m_GEODE),
 
   /* X86_TUNE_PARTIAL_REG_DEPENDENCY */
-  m_AMD_MULTIPLE | m_PENT4 | m_NOCONA | m_CORE2 | m_GENERIC,
+  m_AMD_MULTIPLE | m_ATOM | m_PENT4 | m_NOCONA | m_CORE2 | m_GENERIC,
 
   /* X86_TUNE_SSE_PARTIAL_REG_DEPENDENCY: In the Generic model we have a
      conflict here in between PPro/Pentium4 based chips that thread 128bit
@@ -1344,7 +1423,8 @@ unsigned int ix86_tune_features[X86_TUNE_LAST] = {
      shows that disabling this option on P4 brings over 20% SPECfp regression,
      while enabling it on K8 brings roughly 2.4% regression that can be partly
      masked by careful scheduling of moves.  */
-  m_PENT4 | m_NOCONA | m_PPRO | m_CORE2 | m_GENERIC | m_AMDFAM10,
+  m_ATOM | m_PENT4 | m_NOCONA | m_PPRO | m_CORE2 | m_GENERIC
+  | m_AMDFAM10,
 
   /* X86_TUNE_SSE_UNALIGNED_MOVE_OPTIMAL */
   m_AMDFAM10,
@@ -1362,13 +1442,13 @@ unsigned int ix86_tune_features[X86_TUNE_LAST] = {
   m_PPRO | m_PENT4 | m_NOCONA,
 
   /* X86_TUNE_MEMORY_MISMATCH_STALL */
-  m_AMD_MULTIPLE | m_PENT4 | m_NOCONA | m_CORE2 | m_GENERIC,
+  m_AMD_MULTIPLE | m_ATOM | m_PENT4 | m_NOCONA | m_CORE2 | m_GENERIC,
 
   /* X86_TUNE_PROLOGUE_USING_MOVE */
-  m_ATHLON_K8 | m_PPRO | m_CORE2 | m_GENERIC,
+  m_ATHLON_K8 | m_ATOM | m_PPRO | m_CORE2 | m_GENERIC,
 
   /* X86_TUNE_EPILOGUE_USING_MOVE */
-  m_ATHLON_K8 | m_PPRO | m_CORE2 | m_GENERIC,
+  m_ATHLON_K8 | m_ATOM | m_PPRO | m_CORE2 | m_GENERIC,
 
   /* X86_TUNE_SHIFT1 */
   ~m_486,
@@ -1377,29 +1457,32 @@ unsigned int ix86_tune_features[X86_TUNE_LAST] = {
   m_AMD_MULTIPLE,
 
   /* X86_TUNE_INTER_UNIT_MOVES */
-  ~(m_AMD_MULTIPLE | m_GENERIC),
+  ~(m_AMD_MULTIPLE | m_ATOM | m_GENERIC),
 
   /* X86_TUNE_INTER_UNIT_CONVERSIONS */
   ~(m_AMDFAM10),
 
   /* X86_TUNE_FOUR_JUMP_LIMIT: Some CPU cores are not able to predict more
      than 4 branch instructions in the 16 byte window.  */
-  m_PPRO | m_AMD_MULTIPLE | m_PENT4 | m_NOCONA | m_CORE2 | m_GENERIC,
+  m_ATOM | m_PPRO | m_AMD_MULTIPLE | m_PENT4 | m_NOCONA | m_CORE2
+  | m_GENERIC,
 
   /* X86_TUNE_SCHEDULE */
-  m_PPRO | m_AMD_MULTIPLE | m_K6_GEODE | m_PENT | m_CORE2 | m_GENERIC,
+  m_PPRO | m_AMD_MULTIPLE | m_K6_GEODE | m_PENT | m_ATOM | m_CORE2
+  | m_GENERIC,
 
   /* X86_TUNE_USE_BT */
-  m_AMD_MULTIPLE,
+  m_AMD_MULTIPLE | m_ATOM | m_CORE2 | m_GENERIC,
 
   /* X86_TUNE_USE_INCDEC */
-  ~(m_PENT4 | m_NOCONA | m_GENERIC),
+  ~(m_PENT4 | m_NOCONA | m_GENERIC | m_ATOM),
 
   /* X86_TUNE_PAD_RETURNS */
   m_AMD_MULTIPLE | m_CORE2 | m_GENERIC,
 
   /* X86_TUNE_EXT_80387_CONSTANTS */
-  m_K6_GEODE | m_ATHLON_K8 | m_PENT4 | m_NOCONA | m_PPRO | m_CORE2 | m_GENERIC,
+  m_K6_GEODE | m_ATHLON_K8 | m_ATOM | m_PENT4 | m_NOCONA | m_PPRO
+  | m_CORE2 | m_GENERIC,
 
   /* X86_TUNE_SHORTEN_X87_SSE */
   ~m_K8,
@@ -1432,13 +1515,30 @@ unsigned int ix86_tune_features[X86_TUNE_LAST] = {
      replacement is long decoded, so this split helps here as well.  */
   m_K6,
 
+  /* X86_TUNE_USE_VECTOR_FP_CONVERTS: Prefer vector packed SSE conversion
+     from FP to FP. */
+  m_AMDFAM10 | m_GENERIC,
+
   /* X86_TUNE_USE_VECTOR_CONVERTS: Prefer vector packed SSE conversion
      from integer to FP. */
   m_AMDFAM10,
+
+  /* X86_TUNE_FUSE_CMP_AND_BRANCH: Fuse a compare or test instruction
+     with a subsequent conditional jump instruction into a single
+     compare-and-branch uop.  */
+  m_CORE2,
+
+  /* X86_TUNE_OPT_AGU: Optimize for Address Generation Unit. This flag
+     will impact LEA instruction selection. */
+  m_ATOM,
 };
 
 /* Feature tests against the various architecture variations.  */
-unsigned int ix86_arch_features[X86_ARCH_LAST] = {
+unsigned char ix86_arch_features[X86_ARCH_LAST];
+
+/* Feature tests against the various architecture variations, used to create
+   ix86_arch_features based on the processor mask.  */
+static unsigned int initial_ix86_arch_features[X86_ARCH_LAST] = {
   /* X86_ARCH_CMOVE: Conditional move was added for pentiumpro.  */
   ~(m_386 | m_486 | m_PENT | m_K6),
 
@@ -1456,10 +1556,11 @@ unsigned int ix86_arch_features[X86_ARCH_LAST] = {
 };
 
 static const unsigned int x86_accumulate_outgoing_args
-  = m_AMD_MULTIPLE | m_PENT4 | m_NOCONA | m_PPRO | m_CORE2 | m_GENERIC;
+  = m_AMD_MULTIPLE | m_ATOM | m_PENT4 | m_NOCONA | m_PPRO | m_CORE2
+    | m_GENERIC;
 
 static const unsigned int x86_arch_always_fancy_math_387
-  = m_PENT | m_PPRO | m_AMD_MULTIPLE | m_PENT4
+  = m_PENT | m_ATOM | m_PPRO | m_AMD_MULTIPLE | m_PENT4
     | m_NOCONA | m_CORE2 | m_GENERIC;
 
 static enum stringop_alg stringop_alg = no_stringop;
@@ -1517,24 +1618,8 @@ int const dbx_register_map[FIRST_PSEUDO_REGISTER] =
   -1, -1, -1, -1, -1, -1, -1, -1,      /* extended SSE registers */
 };
 
-static int const x86_64_int_parameter_registers[6] =
-{
-  5 /*RDI*/, 4 /*RSI*/, 1 /*RDX*/, 2 /*RCX*/,
-  FIRST_REX_INT_REG /*R8 */, FIRST_REX_INT_REG + 1 /*R9 */
-};
-
-static int const x86_64_ms_abi_int_parameter_registers[4] =
-{
-  2 /*RCX*/, 1 /*RDX*/,
-  FIRST_REX_INT_REG /*R8 */, FIRST_REX_INT_REG + 1 /*R9 */
-};
-
-static int const x86_64_int_return_registers[4] =
-{
-  0 /*RAX*/, 1 /*RDX*/, 5 /*RDI*/, 4 /*RSI*/
-};
-
 /* The "default" register map used in 64bit mode.  */
+
 int const dbx64_register_map[FIRST_PSEUDO_REGISTER] =
 {
   0, 1, 2, 3, 4, 5, 6, 7,              /* general regs */
@@ -1616,15 +1701,27 @@ int const svr4_dbx_register_map[FIRST_PSEUDO_REGISTER] =
 
 rtx ix86_compare_op0 = NULL_RTX;
 rtx ix86_compare_op1 = NULL_RTX;
-rtx ix86_compare_emitted = NULL_RTX;
 
-/* Size of the register save area.  */
-#define X86_64_VARARGS_SIZE (REGPARM_MAX * UNITS_PER_WORD + SSE_REGPARM_MAX * 16)
+/* Define parameter passing and return registers.  */
 
-/* Define the structure for the machine field in struct function.  */
+static int const x86_64_int_parameter_registers[6] =
+{
+  DI_REG, SI_REG, DX_REG, CX_REG, R8_REG, R9_REG
+};
 
-struct stack_local_entry GTY(())
+static int const x86_64_ms_abi_int_parameter_registers[4] =
+{
+  CX_REG, DX_REG, R8_REG, R9_REG
+};
+
+static int const x86_64_int_return_registers[4] =
 {
+  AX_REG, DX_REG, DI_REG, SI_REG
+};
+
+/* Define the structure for the machine field in struct function.  */
+
+struct GTY(()) stack_local_entry {
   unsigned short mode;
   unsigned short n;
   rtx rtl;
@@ -1642,6 +1739,10 @@ struct stack_local_entry GTY(())
                                              <- HARD_FRAME_POINTER
    [saved regs]
 
+   [padding0]
+
+   [saved SSE regs]
+
    [padding1]          \
                        )
    [va_arg registers]  (
@@ -1652,6 +1753,8 @@ struct stack_local_entry GTY(())
   */
 struct ix86_frame
 {
+  int padding0;
+  int nsseregs;
   int nregs;
   int padding1;
   int va_arg_size;
@@ -1682,6 +1785,9 @@ enum tls_dialect ix86_tls_dialect = TLS_DIALECT_GNU;
 enum fpmath_unit ix86_fpmath;
 
 /* Which cpu are we scheduling for.  */
+enum attr_cpu ix86_schedule;
+
+/* Which cpu are we optimizing for.  */
 enum processor_type ix86_tune;
 
 /* Which instruction set architecture to use.  */
@@ -1695,14 +1801,41 @@ static int ix86_regparm;
 
 /* -mstackrealign option */
 extern int ix86_force_align_arg_pointer;
-static const char ix86_force_align_arg_pointer_string[] = "force_align_arg_pointer";
+static const char ix86_force_align_arg_pointer_string[]
+  = "force_align_arg_pointer";
+
+static rtx (*ix86_gen_leave) (void);
+static rtx (*ix86_gen_pop1) (rtx);
+static rtx (*ix86_gen_add3) (rtx, rtx, rtx);
+static rtx (*ix86_gen_sub3) (rtx, rtx, rtx);
+static rtx (*ix86_gen_sub3_carry) (rtx, rtx, rtx, rtx);
+static rtx (*ix86_gen_one_cmpl2) (rtx, rtx);
+static rtx (*ix86_gen_monitor) (rtx, rtx, rtx);
+static rtx (*ix86_gen_andsp) (rtx, rtx, rtx);
 
 /* Preferred alignment for stack boundary in bits.  */
 unsigned int ix86_preferred_stack_boundary;
 
+/* Alignment for incoming stack boundary in bits specified at
+   command line.  */
+static unsigned int ix86_user_incoming_stack_boundary;
+
+/* Default alignment for incoming stack boundary in bits.  */
+static unsigned int ix86_default_incoming_stack_boundary;
+
+/* Alignment for incoming stack boundary in bits.  */
+unsigned int ix86_incoming_stack_boundary;
+
+/* The abi used by target.  */
+enum calling_abi ix86_abi;
+
 /* Values 1-5: see jump.c */
 int ix86_branch_cost;
 
+/* Calling abi specific va_list type nodes.  */
+static GTY(()) tree sysv_va_list_type_node;
+static GTY(()) tree ms_va_list_type_node;
+
 /* Variables which are this size or smaller are put in the data/bss
    or ldata/lbss sections.  */
 
@@ -1736,11 +1869,6 @@ enum x86_64_reg_class
     X86_64_COMPLEX_X87_CLASS,
     X86_64_MEMORY_CLASS
   };
-static const char * const x86_64_reg_class_name[] =
-{
-  "no", "integer", "integerSI", "sse", "sseSF", "sseDF",
-  "sseup", "x87", "x87up", "cplx87", "no"
-};
 
 #define MAX_CLASSES 4
 
@@ -1755,6 +1883,29 @@ static int ix86_function_regparm (const_tree, const_tree);
 static void ix86_compute_frame_layout (struct ix86_frame *);
 static bool ix86_expand_vector_init_one_nonzero (bool, enum machine_mode,
                                                 rtx, rtx, int);
+static void ix86_add_new_builtins (int);
+
+enum ix86_function_specific_strings
+{
+  IX86_FUNCTION_SPECIFIC_ARCH,
+  IX86_FUNCTION_SPECIFIC_TUNE,
+  IX86_FUNCTION_SPECIFIC_FPMATH,
+  IX86_FUNCTION_SPECIFIC_MAX
+};
+
+static char *ix86_target_string (int, int, const char *, const char *,
+                                const char *, bool);
+static void ix86_debug_options (void) ATTRIBUTE_UNUSED;
+static void ix86_function_specific_save (struct cl_target_option *);
+static void ix86_function_specific_restore (struct cl_target_option *);
+static void ix86_function_specific_print (FILE *, int,
+                                         struct cl_target_option *);
+static bool ix86_valid_target_attribute_p (tree, tree, tree, int);
+static bool ix86_valid_target_attribute_inner_p (tree, char *[]);
+static bool ix86_can_inline_p (tree, tree);
+static void ix86_set_current_function (tree);
+
+static enum calling_abi ix86_function_abi (const_tree);
 
 \f
 /* The svr4 ABI for the i386 says that records and unions are returned
@@ -1763,6 +1914,10 @@ static bool ix86_expand_vector_init_one_nonzero (bool, enum machine_mode,
 #define DEFAULT_PCC_STRUCT_RETURN 1
 #endif
 
+/* Whether -mtune= or -march= were specified */
+static int ix86_tune_defaulted;
+static int ix86_arch_specified;
+
 /* Bit flags that specify the ISA we are compiling for.  */
 int ix86_isa_flags = TARGET_64BIT_DEFAULT | TARGET_SUBTARGET_ISA_DEFAULT;
 
@@ -1788,6 +1943,10 @@ static int ix86_isa_flags_explicit;
   (OPTION_MASK_ISA_SSE4_1 | OPTION_MASK_ISA_SSSE3_SET)
 #define OPTION_MASK_ISA_SSE4_2_SET \
   (OPTION_MASK_ISA_SSE4_2 | OPTION_MASK_ISA_SSE4_1_SET)
+#define OPTION_MASK_ISA_AVX_SET \
+  (OPTION_MASK_ISA_AVX | OPTION_MASK_ISA_SSE4_2_SET)
+#define OPTION_MASK_ISA_FMA_SET \
+  (OPTION_MASK_ISA_FMA | OPTION_MASK_ISA_AVX_SET)
 
 /* SSE4 includes both SSE4.1 and SSE4.2. -msse4 should be the same
    as -msse4.2.  */
@@ -1798,6 +1957,21 @@ static int ix86_isa_flags_explicit;
 #define OPTION_MASK_ISA_SSE5_SET \
   (OPTION_MASK_ISA_SSE5 | OPTION_MASK_ISA_SSE4A_SET)
 
+/* AES and PCLMUL need SSE2 because they use xmm registers */
+#define OPTION_MASK_ISA_AES_SET \
+  (OPTION_MASK_ISA_AES | OPTION_MASK_ISA_SSE2_SET)
+#define OPTION_MASK_ISA_PCLMUL_SET \
+  (OPTION_MASK_ISA_PCLMUL | OPTION_MASK_ISA_SSE2_SET)
+
+#define OPTION_MASK_ISA_ABM_SET \
+  (OPTION_MASK_ISA_ABM | OPTION_MASK_ISA_POPCNT)
+
+#define OPTION_MASK_ISA_POPCNT_SET OPTION_MASK_ISA_POPCNT
+#define OPTION_MASK_ISA_CX16_SET OPTION_MASK_ISA_CX16
+#define OPTION_MASK_ISA_SAHF_SET OPTION_MASK_ISA_SAHF
+#define OPTION_MASK_ISA_MOVBE_SET OPTION_MASK_ISA_MOVBE
+#define OPTION_MASK_ISA_CRC32_SET OPTION_MASK_ISA_CRC32
+
 /* Define a set of ISAs which aren't available when a given ISA is
    disabled.  MMX and SSE ISAs are handled separately.  */
 
@@ -1819,7 +1993,11 @@ static int ix86_isa_flags_explicit;
   (OPTION_MASK_ISA_SSSE3 | OPTION_MASK_ISA_SSE4_1_UNSET)
 #define OPTION_MASK_ISA_SSE4_1_UNSET \
   (OPTION_MASK_ISA_SSE4_1 | OPTION_MASK_ISA_SSE4_2_UNSET)
-#define OPTION_MASK_ISA_SSE4_2_UNSET OPTION_MASK_ISA_SSE4_2
+#define OPTION_MASK_ISA_SSE4_2_UNSET \
+  (OPTION_MASK_ISA_SSE4_2 | OPTION_MASK_ISA_AVX_UNSET )
+#define OPTION_MASK_ISA_AVX_UNSET \
+  (OPTION_MASK_ISA_AVX | OPTION_MASK_ISA_FMA_UNSET)
+#define OPTION_MASK_ISA_FMA_UNSET OPTION_MASK_ISA_FMA
 
 /* SSE4 includes both SSE4.1 and SSE4.2.  -mno-sse4 should the same
    as -mno-sse4.1. */
@@ -1827,14 +2005,77 @@ static int ix86_isa_flags_explicit;
 
 #define OPTION_MASK_ISA_SSE4A_UNSET \
   (OPTION_MASK_ISA_SSE4A | OPTION_MASK_ISA_SSE5_UNSET)
-
 #define OPTION_MASK_ISA_SSE5_UNSET OPTION_MASK_ISA_SSE5
+#define OPTION_MASK_ISA_AES_UNSET OPTION_MASK_ISA_AES
+#define OPTION_MASK_ISA_PCLMUL_UNSET OPTION_MASK_ISA_PCLMUL
+#define OPTION_MASK_ISA_ABM_UNSET OPTION_MASK_ISA_ABM
+#define OPTION_MASK_ISA_POPCNT_UNSET OPTION_MASK_ISA_POPCNT
+#define OPTION_MASK_ISA_CX16_UNSET OPTION_MASK_ISA_CX16
+#define OPTION_MASK_ISA_SAHF_UNSET OPTION_MASK_ISA_SAHF
+#define OPTION_MASK_ISA_MOVBE_UNSET OPTION_MASK_ISA_MOVBE
+#define OPTION_MASK_ISA_CRC32_UNSET OPTION_MASK_ISA_CRC32
 
 /* Vectorization library interface and handlers.  */
 tree (*ix86_veclib_handler)(enum built_in_function, tree, tree) = NULL;
 static tree ix86_veclibabi_svml (enum built_in_function, tree, tree);
 static tree ix86_veclibabi_acml (enum built_in_function, tree, tree);
 
+/* Processor target table, indexed by processor number */
+struct ptt
+{
+  const struct processor_costs *cost;          /* Processor costs */
+  const int align_loop;                                /* Default alignments.  */
+  const int align_loop_max_skip;
+  const int align_jump;
+  const int align_jump_max_skip;
+  const int align_func;
+};
+
+static const struct ptt processor_target_table[PROCESSOR_max] =
+{
+  {&i386_cost, 4, 3, 4, 3, 4},
+  {&i486_cost, 16, 15, 16, 15, 16},
+  {&pentium_cost, 16, 7, 16, 7, 16},
+  {&pentiumpro_cost, 16, 15, 16, 10, 16},
+  {&geode_cost, 0, 0, 0, 0, 0},
+  {&k6_cost, 32, 7, 32, 7, 32},
+  {&athlon_cost, 16, 7, 16, 7, 16},
+  {&pentium4_cost, 0, 0, 0, 0, 0},
+  {&k8_cost, 16, 7, 16, 7, 16},
+  {&nocona_cost, 0, 0, 0, 0, 0},
+  {&core2_cost, 16, 10, 16, 10, 16},
+  {&generic32_cost, 16, 7, 16, 7, 16},
+  {&generic64_cost, 16, 10, 16, 10, 16},
+  {&amdfam10_cost, 32, 24, 32, 7, 32},
+  {&atom_cost, 16, 7, 16, 7, 16}
+};
+
+static const char *const cpu_names[TARGET_CPU_DEFAULT_max] =
+{
+  "generic",
+  "i386",
+  "i486",
+  "pentium",
+  "pentium-mmx",
+  "pentiumpro",
+  "pentium2",
+  "pentium3",
+  "pentium4",
+  "pentium-m",
+  "prescott",
+  "nocona",
+  "core2",
+  "atom",
+  "geode",
+  "k6",
+  "k6-2",
+  "k6-3",
+  "athlon",
+  "athlon-4",
+  "k8",
+  "amdfam10"
+};
+\f
 /* Implement TARGET_HANDLE_OPTION.  */
 
 static bool
@@ -1949,6 +2190,32 @@ ix86_handle_option (size_t code, const char *arg ATTRIBUTE_UNUSED, int value)
        }
       return true;
 
+    case OPT_mavx:
+      if (value)
+       {
+         ix86_isa_flags |= OPTION_MASK_ISA_AVX_SET;
+         ix86_isa_flags_explicit |= OPTION_MASK_ISA_AVX_SET;
+       }
+      else
+       {
+         ix86_isa_flags &= ~OPTION_MASK_ISA_AVX_UNSET;
+         ix86_isa_flags_explicit |= OPTION_MASK_ISA_AVX_UNSET;
+       }
+      return true;
+
+    case OPT_mfma:
+      if (value)
+       {
+         ix86_isa_flags |= OPTION_MASK_ISA_FMA_SET;
+         ix86_isa_flags_explicit |= OPTION_MASK_ISA_FMA_SET;
+       }
+      else
+       {
+         ix86_isa_flags &= ~OPTION_MASK_ISA_FMA_UNSET;
+         ix86_isa_flags_explicit |= OPTION_MASK_ISA_FMA_UNSET;
+       }
+      return true;
+
     case OPT_msse4:
       ix86_isa_flags |= OPTION_MASK_ISA_SSE4_SET;
       ix86_isa_flags_explicit |= OPTION_MASK_ISA_SSE4_SET;
@@ -1985,201 +2252,477 @@ ix86_handle_option (size_t code, const char *arg ATTRIBUTE_UNUSED, int value)
        }
       return true;
 
+    case OPT_mabm:
+      if (value)
+       {
+         ix86_isa_flags |= OPTION_MASK_ISA_ABM_SET;
+         ix86_isa_flags_explicit |= OPTION_MASK_ISA_ABM_SET;
+       }
+      else
+       {
+         ix86_isa_flags &= ~OPTION_MASK_ISA_ABM_UNSET;
+         ix86_isa_flags_explicit |= OPTION_MASK_ISA_ABM_UNSET;
+       }
+      return true;
+
+    case OPT_mpopcnt:
+      if (value)
+       {
+         ix86_isa_flags |= OPTION_MASK_ISA_POPCNT_SET;
+         ix86_isa_flags_explicit |= OPTION_MASK_ISA_POPCNT_SET;
+       }
+      else
+       {
+         ix86_isa_flags &= ~OPTION_MASK_ISA_POPCNT_UNSET;
+         ix86_isa_flags_explicit |= OPTION_MASK_ISA_POPCNT_UNSET;
+       }
+      return true;
+
+    case OPT_msahf:
+      if (value)
+       {
+         ix86_isa_flags |= OPTION_MASK_ISA_SAHF_SET;
+         ix86_isa_flags_explicit |= OPTION_MASK_ISA_SAHF_SET;
+       }
+      else
+       {
+         ix86_isa_flags &= ~OPTION_MASK_ISA_SAHF_UNSET;
+         ix86_isa_flags_explicit |= OPTION_MASK_ISA_SAHF_UNSET;
+       }
+      return true;
+
+    case OPT_mcx16:
+      if (value)
+       {
+         ix86_isa_flags |= OPTION_MASK_ISA_CX16_SET;
+         ix86_isa_flags_explicit |= OPTION_MASK_ISA_CX16_SET;
+       }
+      else
+       {
+         ix86_isa_flags &= ~OPTION_MASK_ISA_CX16_UNSET;
+         ix86_isa_flags_explicit |= OPTION_MASK_ISA_CX16_UNSET;
+       }
+      return true;
+
+    case OPT_mmovbe:
+      if (value)
+       {
+         ix86_isa_flags |= OPTION_MASK_ISA_MOVBE_SET;
+         ix86_isa_flags_explicit |= OPTION_MASK_ISA_MOVBE_SET;
+       }
+      else
+       {
+         ix86_isa_flags &= ~OPTION_MASK_ISA_MOVBE_UNSET;
+         ix86_isa_flags_explicit |= OPTION_MASK_ISA_MOVBE_UNSET;
+       }
+      return true;
+
+    case OPT_mcrc32:
+      if (value)
+       {
+         ix86_isa_flags |= OPTION_MASK_ISA_CRC32_SET;
+         ix86_isa_flags_explicit |= OPTION_MASK_ISA_CRC32_SET;
+       }
+      else
+       {
+         ix86_isa_flags &= ~OPTION_MASK_ISA_CRC32_UNSET;
+         ix86_isa_flags_explicit |= OPTION_MASK_ISA_CRC32_UNSET;
+       }
+      return true;
+
+    case OPT_maes:
+      if (value)
+       {
+         ix86_isa_flags |= OPTION_MASK_ISA_AES_SET;
+         ix86_isa_flags_explicit |= OPTION_MASK_ISA_AES_SET;
+       }
+      else
+       {
+         ix86_isa_flags &= ~OPTION_MASK_ISA_AES_UNSET;
+         ix86_isa_flags_explicit |= OPTION_MASK_ISA_AES_UNSET;
+       }
+      return true;
+
+    case OPT_mpclmul:
+      if (value)
+       {
+         ix86_isa_flags |= OPTION_MASK_ISA_PCLMUL_SET;
+         ix86_isa_flags_explicit |= OPTION_MASK_ISA_PCLMUL_SET;
+       }
+      else
+       {
+         ix86_isa_flags &= ~OPTION_MASK_ISA_PCLMUL_UNSET;
+         ix86_isa_flags_explicit |= OPTION_MASK_ISA_PCLMUL_UNSET;
+       }
+      return true;
+
     default:
       return true;
     }
 }
+\f
+/* Return a string the documents the current -m options.  The caller is
+   responsible for freeing the string.  */
 
-/* Sometimes certain combinations of command options do not make
-   sense on a particular target machine.  You can define a macro
-   `OVERRIDE_OPTIONS' to take account of this.  This macro, if
-   defined, is executed once just after all the command options have
-   been parsed.
+static char *
+ix86_target_string (int isa, int flags, const char *arch, const char *tune,
+                   const char *fpmath, bool add_nl_p)
+{
+  struct ix86_target_opts
+  {
+    const char *option;                /* option string */
+    int mask;                  /* isa mask options */
+  };
 
-   Don't use this macro to turn on various extra optimizations for
-   `-O'.  That is what `OPTIMIZATION_OPTIONS' is for.  */
+  /* This table is ordered so that options like -msse5 or -msse4.2 that imply
+     preceding options while match those first.  */
+  static struct ix86_target_opts isa_opts[] =
+  {
+    { "-m64",          OPTION_MASK_ISA_64BIT },
+    { "-msse5",                OPTION_MASK_ISA_SSE5 },
+    { "-msse4a",       OPTION_MASK_ISA_SSE4A },
+    { "-msse4.2",      OPTION_MASK_ISA_SSE4_2 },
+    { "-msse4.1",      OPTION_MASK_ISA_SSE4_1 },
+    { "-mssse3",       OPTION_MASK_ISA_SSSE3 },
+    { "-msse3",                OPTION_MASK_ISA_SSE3 },
+    { "-msse2",                OPTION_MASK_ISA_SSE2 },
+    { "-msse",         OPTION_MASK_ISA_SSE },
+    { "-m3dnow",       OPTION_MASK_ISA_3DNOW },
+    { "-m3dnowa",      OPTION_MASK_ISA_3DNOW_A },
+    { "-mmmx",         OPTION_MASK_ISA_MMX },
+    { "-mabm",         OPTION_MASK_ISA_ABM },
+    { "-mpopcnt",      OPTION_MASK_ISA_POPCNT },
+    { "-mmovbe",       OPTION_MASK_ISA_MOVBE },
+    { "-mcrc32",       OPTION_MASK_ISA_CRC32 },
+    { "-maes",         OPTION_MASK_ISA_AES },
+    { "-mpclmul",      OPTION_MASK_ISA_PCLMUL },
+  };
 
-void
-override_options (void)
-{
-  int i;
-  int ix86_tune_defaulted = 0;
-  int ix86_arch_specified = 0;
-  unsigned int ix86_arch_mask, ix86_tune_mask;
+  /* Flag options.  */
+  static struct ix86_target_opts flag_opts[] =
+  {
+    { "-m128bit-long-double",          MASK_128BIT_LONG_DOUBLE },
+    { "-m80387",                       MASK_80387 },
+    { "-maccumulate-outgoing-args",    MASK_ACCUMULATE_OUTGOING_ARGS },
+    { "-malign-double",                        MASK_ALIGN_DOUBLE },
+    { "-mcld",                         MASK_CLD },
+    { "-mfp-ret-in-387",               MASK_FLOAT_RETURNS },
+    { "-mieee-fp",                     MASK_IEEE_FP },
+    { "-minline-all-stringops",                MASK_INLINE_ALL_STRINGOPS },
+    { "-minline-stringops-dynamically",        MASK_INLINE_STRINGOPS_DYNAMICALLY },
+    { "-mms-bitfields",                        MASK_MS_BITFIELD_LAYOUT },
+    { "-mno-align-stringops",          MASK_NO_ALIGN_STRINGOPS },
+    { "-mno-fancy-math-387",           MASK_NO_FANCY_MATH_387 },
+    { "-mno-fused-madd",               MASK_NO_FUSED_MADD },
+    { "-mno-push-args",                        MASK_NO_PUSH_ARGS },
+    { "-mno-red-zone",                 MASK_NO_RED_ZONE },
+    { "-momit-leaf-frame-pointer",     MASK_OMIT_LEAF_FRAME_POINTER },
+    { "-mrecip",                       MASK_RECIP },
+    { "-mrtd",                         MASK_RTD },
+    { "-msseregparm",                  MASK_SSEREGPARM },
+    { "-mstack-arg-probe",             MASK_STACK_PROBE },
+    { "-mtls-direct-seg-refs",         MASK_TLS_DIRECT_SEG_REFS },
+  };
 
-  /* Comes from final.c -- no real reason to change it.  */
-#define MAX_CODE_ALIGN 16
+  const char *opts[ARRAY_SIZE (isa_opts) + ARRAY_SIZE (flag_opts) + 6][2];
 
-  static struct ptt
-    {
-      const struct processor_costs *cost;      /* Processor costs */
-      const int align_loop;                    /* Default alignments.  */
-      const int align_loop_max_skip;
-      const int align_jump;
-      const int align_jump_max_skip;
-      const int align_func;
-    }
-  const processor_target_table[PROCESSOR_max] =
-    {
-      {&i386_cost, 4, 3, 4, 3, 4},
-      {&i486_cost, 16, 15, 16, 15, 16},
-      {&pentium_cost, 16, 7, 16, 7, 16},
-      {&pentiumpro_cost, 16, 15, 16, 10, 16},
-      {&geode_cost, 0, 0, 0, 0, 0},
-      {&k6_cost, 32, 7, 32, 7, 32},
-      {&athlon_cost, 16, 7, 16, 7, 16},
-      {&pentium4_cost, 0, 0, 0, 0, 0},
-      {&k8_cost, 16, 7, 16, 7, 16},
-      {&nocona_cost, 0, 0, 0, 0, 0},
-      {&core2_cost, 16, 10, 16, 10, 16},
-      {&generic32_cost, 16, 7, 16, 7, 16},
-      {&generic64_cost, 16, 10, 16, 10, 16},
-      {&amdfam10_cost, 32, 24, 32, 7, 32}
-    };
+  char isa_other[40];
+  char target_other[40];
+  unsigned num = 0;
+  unsigned i, j;
+  char *ret;
+  char *ptr;
+  size_t len;
+  size_t line_len;
+  size_t sep_len;
 
-  static const char *const cpu_names[TARGET_CPU_DEFAULT_max] =
-    {
-      "generic",
-      "i386",
-      "i486",
-      "pentium",
-      "pentium-mmx",
-      "pentiumpro",
-      "pentium2",
-      "pentium3",
-      "pentium4",
-      "pentium-m",
-      "prescott",
-      "nocona",
-      "core2",
-      "geode",
-      "k6",
-      "k6-2",
-      "k6-3",
-      "athlon",
-      "athlon-4",
-      "k8",
-      "amdfam10"
-    };
+  memset (opts, '\0', sizeof (opts));
 
-  enum pta_flags
+  /* Add -march= option.  */
+  if (arch)
     {
-      PTA_SSE = 1 << 0,
-      PTA_SSE2 = 1 << 1,
-      PTA_SSE3 = 1 << 2,
-      PTA_MMX = 1 << 3,
-      PTA_PREFETCH_SSE = 1 << 4,
-      PTA_3DNOW = 1 << 5,
-      PTA_3DNOW_A = 1 << 6,
-      PTA_64BIT = 1 << 7,
-      PTA_SSSE3 = 1 << 8,
-      PTA_CX16 = 1 << 9,
-      PTA_POPCNT = 1 << 10,
-      PTA_ABM = 1 << 11,
-      PTA_SSE4A = 1 << 12,
-      PTA_NO_SAHF = 1 << 13,
-      PTA_SSE4_1 = 1 << 14,
-      PTA_SSE4_2 = 1 << 15,
-      PTA_SSE5 = 1 << 16,
-      PTA_AES = 1 << 17,
-      PTA_PCLMUL = 1 << 18
-    };
+      opts[num][0] = "-march=";
+      opts[num++][1] = arch;
+    }
+
+  /* Add -mtune= option.  */
+  if (tune)
+    {
+      opts[num][0] = "-mtune=";
+      opts[num++][1] = tune;
+    }
+
+  /* Pick out the options in isa options.  */
+  for (i = 0; i < ARRAY_SIZE (isa_opts); i++)
+    {
+      if ((isa & isa_opts[i].mask) != 0)
+       {
+         opts[num++][0] = isa_opts[i].option;
+         isa &= ~ isa_opts[i].mask;
+       }
+    }
+
+  if (isa && add_nl_p)
+    {
+      opts[num++][0] = isa_other;
+      sprintf (isa_other, "(other isa: 0x%x)", isa);
+    }
+
+  /* Add flag options.  */
+  for (i = 0; i < ARRAY_SIZE (flag_opts); i++)
+    {
+      if ((flags & flag_opts[i].mask) != 0)
+       {
+         opts[num++][0] = flag_opts[i].option;
+         flags &= ~ flag_opts[i].mask;
+       }
+    }
+
+  if (flags && add_nl_p)
+    {
+      opts[num++][0] = target_other;
+      sprintf (target_other, "(other flags: 0x%x)", isa);
+    }
+
+  /* Add -fpmath= option.  */
+  if (fpmath)
+    {
+      opts[num][0] = "-mfpmath=";
+      opts[num++][1] = fpmath;
+    }
+
+  /* Any options?  */
+  if (num == 0)
+    return NULL;
+
+  gcc_assert (num < ARRAY_SIZE (opts));
+
+  /* Size the string.  */
+  len = 0;
+  sep_len = (add_nl_p) ? 3 : 1;
+  for (i = 0; i < num; i++)
+    {
+      len += sep_len;
+      for (j = 0; j < 2; j++)
+       if (opts[i][j])
+         len += strlen (opts[i][j]);
+    }
+
+  /* Build the string.  */
+  ret = ptr = (char *) xmalloc (len);
+  line_len = 0;
+
+  for (i = 0; i < num; i++)
+    {
+      size_t len2[2];
+
+      for (j = 0; j < 2; j++)
+       len2[j] = (opts[i][j]) ? strlen (opts[i][j]) : 0;
+
+      if (i != 0)
+       {
+         *ptr++ = ' ';
+         line_len++;
+
+         if (add_nl_p && line_len + len2[0] + len2[1] > 70)
+           {
+             *ptr++ = '\\';
+             *ptr++ = '\n';
+             line_len = 0;
+           }
+       }
+
+      for (j = 0; j < 2; j++)
+       if (opts[i][j])
+         {
+           memcpy (ptr, opts[i][j], len2[j]);
+           ptr += len2[j];
+           line_len += len2[j];
+         }
+    }
+
+  *ptr = '\0';
+  gcc_assert (ret + len >= ptr);
+
+  return ret;
+}
+
+/* Function that is callable from the debugger to print the current
+   options.  */
+void
+ix86_debug_options (void)
+{
+  char *opts = ix86_target_string (ix86_isa_flags, target_flags,
+                                  ix86_arch_string, ix86_tune_string,
+                                  ix86_fpmath_string, true);
+
+  if (opts)
+    {
+      fprintf (stderr, "%s\n\n", opts);
+      free (opts);
+    }
+  else
+    fputs ("<no options>\n\n", stderr);
+
+  return;
+}
+\f
+/* Sometimes certain combinations of command options do not make
+   sense on a particular target machine.  You can define a macro
+   `OVERRIDE_OPTIONS' to take account of this.  This macro, if
+   defined, is executed once just after all the command options have
+   been parsed.
+
+   Don't use this macro to turn on various extra optimizations for
+   `-O'.  That is what `OPTIMIZATION_OPTIONS' is for.  */
+
+void
+override_options (bool main_args_p)
+{
+  int i;
+  unsigned int ix86_arch_mask, ix86_tune_mask;
+  const char *prefix;
+  const char *suffix;
+  const char *sw;
+
+  /* Comes from final.c -- no real reason to change it.  */
+#define MAX_CODE_ALIGN 16
+
+  enum pta_flags
+    {
+      PTA_SSE = 1 << 0,
+      PTA_SSE2 = 1 << 1,
+      PTA_SSE3 = 1 << 2,
+      PTA_MMX = 1 << 3,
+      PTA_PREFETCH_SSE = 1 << 4,
+      PTA_3DNOW = 1 << 5,
+      PTA_3DNOW_A = 1 << 6,
+      PTA_64BIT = 1 << 7,
+      PTA_SSSE3 = 1 << 8,
+      PTA_CX16 = 1 << 9,
+      PTA_POPCNT = 1 << 10,
+      PTA_ABM = 1 << 11,
+      PTA_SSE4A = 1 << 12,
+      PTA_NO_SAHF = 1 << 13,
+      PTA_SSE4_1 = 1 << 14,
+      PTA_SSE4_2 = 1 << 15,
+      PTA_SSE5 = 1 << 16,
+      PTA_AES = 1 << 17,
+      PTA_PCLMUL = 1 << 18,
+      PTA_AVX = 1 << 19,
+      PTA_FMA = 1 << 20,
+      PTA_MOVBE = 1 << 21
+    };
 
   static struct pta
     {
       const char *const name;          /* processor name or nickname.  */
       const enum processor_type processor;
+      const enum attr_cpu schedule;
       const unsigned /*enum pta_flags*/ flags;
     }
   const processor_alias_table[] =
     {
-      {"i386", PROCESSOR_I386, 0},
-      {"i486", PROCESSOR_I486, 0},
-      {"i586", PROCESSOR_PENTIUM, 0},
-      {"pentium", PROCESSOR_PENTIUM, 0},
-      {"pentium-mmx", PROCESSOR_PENTIUM, PTA_MMX},
-      {"winchip-c6", PROCESSOR_I486, PTA_MMX},
-      {"winchip2", PROCESSOR_I486, PTA_MMX | PTA_3DNOW},
-      {"c3", PROCESSOR_I486, PTA_MMX | PTA_3DNOW},
-      {"c3-2", PROCESSOR_PENTIUMPRO, PTA_MMX | PTA_SSE},
-      {"i686", PROCESSOR_PENTIUMPRO, 0},
-      {"pentiumpro", PROCESSOR_PENTIUMPRO, 0},
-      {"pentium2", PROCESSOR_PENTIUMPRO, PTA_MMX},
-      {"pentium3", PROCESSOR_PENTIUMPRO, PTA_MMX | PTA_SSE},
-      {"pentium3m", PROCESSOR_PENTIUMPRO, PTA_MMX | PTA_SSE},
-      {"pentium-m", PROCESSOR_PENTIUMPRO, PTA_MMX | PTA_SSE | PTA_SSE2},
-      {"pentium4", PROCESSOR_PENTIUM4, PTA_MMX |PTA_SSE | PTA_SSE2},
-      {"pentium4m", PROCESSOR_PENTIUM4, PTA_MMX | PTA_SSE | PTA_SSE2},
-      {"prescott", PROCESSOR_NOCONA, PTA_MMX | PTA_SSE | PTA_SSE2 | PTA_SSE3},
-      {"nocona", PROCESSOR_NOCONA, (PTA_64BIT
-                                   | PTA_MMX | PTA_SSE | PTA_SSE2 | PTA_SSE3
-                                   | PTA_CX16 | PTA_NO_SAHF)},
-      {"core2", PROCESSOR_CORE2, (PTA_64BIT
-                                 | PTA_MMX | PTA_SSE | PTA_SSE2 | PTA_SSE3
-                                 | PTA_SSSE3
-                                 | PTA_CX16)},
-      {"geode", PROCESSOR_GEODE, (PTA_MMX | PTA_3DNOW | PTA_3DNOW_A
-                                 |PTA_PREFETCH_SSE)},
-      {"k6", PROCESSOR_K6, PTA_MMX},
-      {"k6-2", PROCESSOR_K6, PTA_MMX | PTA_3DNOW},
-      {"k6-3", PROCESSOR_K6, PTA_MMX | PTA_3DNOW},
-      {"athlon", PROCESSOR_ATHLON, (PTA_MMX | PTA_3DNOW | PTA_3DNOW_A
-                                   | PTA_PREFETCH_SSE)},
-      {"athlon-tbird", PROCESSOR_ATHLON, (PTA_MMX | PTA_3DNOW | PTA_3DNOW_A
-                                         | PTA_PREFETCH_SSE)},
-      {"athlon-4", PROCESSOR_ATHLON, (PTA_MMX | PTA_3DNOW | PTA_3DNOW_A
-                                     | PTA_SSE)},
-      {"athlon-xp", PROCESSOR_ATHLON, (PTA_MMX | PTA_3DNOW | PTA_3DNOW_A
-                                      | PTA_SSE)},
-      {"athlon-mp", PROCESSOR_ATHLON, (PTA_MMX | PTA_3DNOW | PTA_3DNOW_A
-                                      | PTA_SSE)},
-      {"x86-64", PROCESSOR_K8, (PTA_64BIT
-                               | PTA_MMX | PTA_SSE | PTA_SSE2
-                               | PTA_NO_SAHF)},
-      {"k8", PROCESSOR_K8, (PTA_64BIT
-                           | PTA_MMX | PTA_3DNOW | PTA_3DNOW_A
-                           | PTA_SSE | PTA_SSE2
-                           | PTA_NO_SAHF)},
-      {"k8-sse3", PROCESSOR_K8, (PTA_64BIT
-                                | PTA_MMX | PTA_3DNOW | PTA_3DNOW_A
-                                | PTA_SSE | PTA_SSE2 | PTA_SSE3
-                                | PTA_NO_SAHF)},
-      {"opteron", PROCESSOR_K8, (PTA_64BIT
-                                | PTA_MMX | PTA_3DNOW | PTA_3DNOW_A
-                                | PTA_SSE | PTA_SSE2
-                                | PTA_NO_SAHF)},
-      {"opteron-sse3", PROCESSOR_K8, (PTA_64BIT
-                                     | PTA_MMX | PTA_3DNOW | PTA_3DNOW_A
-                                     | PTA_SSE | PTA_SSE2 | PTA_SSE3
-                                     | PTA_NO_SAHF)},
-      {"athlon64", PROCESSOR_K8, (PTA_64BIT
-                                 | PTA_MMX | PTA_3DNOW | PTA_3DNOW_A
-                                 | PTA_SSE | PTA_SSE2
-                                 | PTA_NO_SAHF)},
-      {"athlon64-sse3", PROCESSOR_K8, (PTA_64BIT
-                                      | PTA_MMX | PTA_3DNOW | PTA_3DNOW_A
-                                      | PTA_SSE | PTA_SSE2 | PTA_SSE3
-                                      | PTA_NO_SAHF)},
-      {"athlon-fx", PROCESSOR_K8, (PTA_64BIT
-                                  | PTA_MMX | PTA_3DNOW | PTA_3DNOW_A
-                                  | PTA_SSE | PTA_SSE2
-                                  | PTA_NO_SAHF)},
-      {"amdfam10", PROCESSOR_AMDFAM10, (PTA_64BIT
-                                       | PTA_MMX | PTA_3DNOW | PTA_3DNOW_A
-                                       | PTA_SSE | PTA_SSE2 | PTA_SSE3
-                                       | PTA_SSE4A
-                                       | PTA_CX16 | PTA_ABM)},
-      {"barcelona", PROCESSOR_AMDFAM10, (PTA_64BIT
-                                        | PTA_MMX | PTA_3DNOW | PTA_3DNOW_A
-                                        | PTA_SSE | PTA_SSE2 | PTA_SSE3
-                                        | PTA_SSE4A
-                                        | PTA_CX16 | PTA_ABM)},
-      {"generic32", PROCESSOR_GENERIC32, 0 /* flags are only used for -march switch.  */ },
-      {"generic64", PROCESSOR_GENERIC64, PTA_64BIT /* flags are only used for -march switch.  */ },
+      {"i386", PROCESSOR_I386, CPU_NONE, 0},
+      {"i486", PROCESSOR_I486, CPU_NONE, 0},
+      {"i586", PROCESSOR_PENTIUM, CPU_PENTIUM, 0},
+      {"pentium", PROCESSOR_PENTIUM, CPU_PENTIUM, 0},
+      {"pentium-mmx", PROCESSOR_PENTIUM, CPU_PENTIUM, PTA_MMX},
+      {"winchip-c6", PROCESSOR_I486, CPU_NONE, PTA_MMX},
+      {"winchip2", PROCESSOR_I486, CPU_NONE, PTA_MMX | PTA_3DNOW},
+      {"c3", PROCESSOR_I486, CPU_NONE, PTA_MMX | PTA_3DNOW},
+      {"c3-2", PROCESSOR_PENTIUMPRO, CPU_PENTIUMPRO, PTA_MMX | PTA_SSE},
+      {"i686", PROCESSOR_PENTIUMPRO, CPU_PENTIUMPRO, 0},
+      {"pentiumpro", PROCESSOR_PENTIUMPRO, CPU_PENTIUMPRO, 0},
+      {"pentium2", PROCESSOR_PENTIUMPRO, CPU_PENTIUMPRO, PTA_MMX},
+      {"pentium3", PROCESSOR_PENTIUMPRO, CPU_PENTIUMPRO,
+       PTA_MMX | PTA_SSE},
+      {"pentium3m", PROCESSOR_PENTIUMPRO, CPU_PENTIUMPRO,
+       PTA_MMX | PTA_SSE},
+      {"pentium-m", PROCESSOR_PENTIUMPRO, CPU_PENTIUMPRO,
+       PTA_MMX | PTA_SSE | PTA_SSE2},
+      {"pentium4", PROCESSOR_PENTIUM4, CPU_NONE,
+       PTA_MMX |PTA_SSE | PTA_SSE2},
+      {"pentium4m", PROCESSOR_PENTIUM4, CPU_NONE,
+       PTA_MMX | PTA_SSE | PTA_SSE2},
+      {"prescott", PROCESSOR_NOCONA, CPU_NONE,
+       PTA_MMX | PTA_SSE | PTA_SSE2 | PTA_SSE3},
+      {"nocona", PROCESSOR_NOCONA, CPU_NONE,
+       PTA_64BIT | PTA_MMX | PTA_SSE | PTA_SSE2 | PTA_SSE3
+       | PTA_CX16 | PTA_NO_SAHF},
+      {"core2", PROCESSOR_CORE2, CPU_CORE2,
+       PTA_64BIT | PTA_MMX | PTA_SSE | PTA_SSE2 | PTA_SSE3
+       | PTA_SSSE3 | PTA_CX16},
+      {"atom", PROCESSOR_ATOM, CPU_ATOM,
+       PTA_64BIT | PTA_MMX | PTA_SSE | PTA_SSE2 | PTA_SSE3
+       | PTA_SSSE3 | PTA_CX16 | PTA_MOVBE},
+      {"geode", PROCESSOR_GEODE, CPU_GEODE,
+       PTA_MMX | PTA_3DNOW | PTA_3DNOW_A |PTA_PREFETCH_SSE},
+      {"k6", PROCESSOR_K6, CPU_K6, PTA_MMX},
+      {"k6-2", PROCESSOR_K6, CPU_K6, PTA_MMX | PTA_3DNOW},
+      {"k6-3", PROCESSOR_K6, CPU_K6, PTA_MMX | PTA_3DNOW},
+      {"athlon", PROCESSOR_ATHLON, CPU_ATHLON,
+       PTA_MMX | PTA_3DNOW | PTA_3DNOW_A | PTA_PREFETCH_SSE},
+      {"athlon-tbird", PROCESSOR_ATHLON, CPU_ATHLON,
+       PTA_MMX | PTA_3DNOW | PTA_3DNOW_A | PTA_PREFETCH_SSE},
+      {"athlon-4", PROCESSOR_ATHLON, CPU_ATHLON,
+       PTA_MMX | PTA_3DNOW | PTA_3DNOW_A | PTA_SSE},
+      {"athlon-xp", PROCESSOR_ATHLON, CPU_ATHLON,
+       PTA_MMX | PTA_3DNOW | PTA_3DNOW_A | PTA_SSE},
+      {"athlon-mp", PROCESSOR_ATHLON, CPU_ATHLON,
+       PTA_MMX | PTA_3DNOW | PTA_3DNOW_A | PTA_SSE},
+      {"x86-64", PROCESSOR_K8, CPU_K8,
+       PTA_64BIT | PTA_MMX | PTA_SSE | PTA_SSE2 | PTA_NO_SAHF},
+      {"k8", PROCESSOR_K8, CPU_K8,
+       PTA_64BIT | PTA_MMX | PTA_3DNOW | PTA_3DNOW_A | PTA_SSE
+       | PTA_SSE2 | PTA_NO_SAHF},
+      {"k8-sse3", PROCESSOR_K8, CPU_K8,
+       PTA_64BIT | PTA_MMX | PTA_3DNOW | PTA_3DNOW_A | PTA_SSE
+       | PTA_SSE2 | PTA_SSE3 | PTA_NO_SAHF},
+      {"opteron", PROCESSOR_K8, CPU_K8,
+       PTA_64BIT | PTA_MMX | PTA_3DNOW | PTA_3DNOW_A | PTA_SSE
+       | PTA_SSE2 | PTA_NO_SAHF},
+      {"opteron-sse3", PROCESSOR_K8, CPU_K8,
+        PTA_64BIT | PTA_MMX | PTA_3DNOW | PTA_3DNOW_A | PTA_SSE
+       | PTA_SSE2 | PTA_SSE3 | PTA_NO_SAHF},
+      {"athlon64", PROCESSOR_K8, CPU_K8,
+       PTA_64BIT | PTA_MMX | PTA_3DNOW | PTA_3DNOW_A | PTA_SSE
+       | PTA_SSE2 | PTA_NO_SAHF},
+      {"athlon64-sse3", PROCESSOR_K8, CPU_K8,
+       PTA_64BIT | PTA_MMX | PTA_3DNOW | PTA_3DNOW_A | PTA_SSE
+       | PTA_SSE2 | PTA_SSE3 | PTA_NO_SAHF},
+      {"athlon-fx", PROCESSOR_K8, CPU_K8,
+       PTA_64BIT | PTA_MMX | PTA_3DNOW | PTA_3DNOW_A | PTA_SSE
+       | PTA_SSE2 | PTA_NO_SAHF},
+      {"amdfam10", PROCESSOR_AMDFAM10, CPU_AMDFAM10,
+       PTA_64BIT | PTA_MMX | PTA_3DNOW | PTA_3DNOW_A | PTA_SSE
+       | PTA_SSE2 | PTA_SSE3 | PTA_SSE4A | PTA_CX16 | PTA_ABM},
+      {"barcelona", PROCESSOR_AMDFAM10, CPU_AMDFAM10,
+       PTA_64BIT | PTA_MMX | PTA_3DNOW | PTA_3DNOW_A | PTA_SSE
+       | PTA_SSE2 | PTA_SSE3 | PTA_SSE4A | PTA_CX16 | PTA_ABM},
+      {"generic32", PROCESSOR_GENERIC32, CPU_PENTIUMPRO,
+       0 /* flags are only used for -march switch.  */ },
+      {"generic64", PROCESSOR_GENERIC64, CPU_GENERIC64,
+       PTA_64BIT /* flags are only used for -march switch.  */ },
     };
 
   int const pta_size = ARRAY_SIZE (processor_alias_table);
 
+  /* Set up prefix/suffix so the error messages refer to either the command
+     line argument, or the attribute(target).  */
+  if (main_args_p)
+    {
+      prefix = "-m";
+      suffix = "";
+      sw = "switch";
+    }
+  else
+    {
+      prefix = "option(\"";
+      suffix = "\")";
+      sw = "attribute";
+    }
+
 #ifdef SUBTARGET_OVERRIDE_OPTIONS
   SUBTARGET_OVERRIDE_OPTIONS;
 #endif
@@ -2229,8 +2772,15 @@ override_options (void)
          else
            ix86_tune_string = "generic32";
        }
+      /* If this call is for setting the option attribute, allow the
+        generic32/generic64 that was previously set.  */
+      else if (!main_args_p
+              && (!strcmp (ix86_tune_string, "generic32")
+                  || !strcmp (ix86_tune_string, "generic64")))
+       ;
       else if (!strncmp (ix86_tune_string, "generic", 7))
-       error ("bad value (%s) for -mtune= switch", ix86_tune_string);
+       error ("bad value (%s) for %stune=%s %s",
+              ix86_tune_string, prefix, suffix, sw);
     }
   else
     {
@@ -2262,7 +2812,9 @@ override_options (void)
        stringop_alg = libcall;
       else if (!strcmp (ix86_stringop_string, "rep_4byte"))
        stringop_alg = rep_prefix_4_byte;
-      else if (!strcmp (ix86_stringop_string, "rep_8byte"))
+      else if (!strcmp (ix86_stringop_string, "rep_8byte")
+              && TARGET_64BIT)
+       /* rep; movq isn't available in 32-bit code.  */
        stringop_alg = rep_prefix_8_byte;
       else if (!strcmp (ix86_stringop_string, "byte_loop"))
        stringop_alg = loop_1_byte;
@@ -2271,11 +2823,13 @@ override_options (void)
       else if (!strcmp (ix86_stringop_string, "unrolled_loop"))
        stringop_alg = unrolled_loop;
       else
-       error ("bad value (%s) for -mstringop-strategy= switch", ix86_stringop_string);
+       error ("bad value (%s) for %sstringop-strategy=%s %s",
+              ix86_stringop_string, prefix, suffix, sw);
     }
   if (!strcmp (ix86_tune_string, "x86-64"))
-    warning (OPT_Wdeprecated, "-mtune=x86-64 is deprecated.  Use -mtune=k8 or "
-            "-mtune=generic instead as appropriate.");
+    warning (OPT_Wdeprecated, "%stune=x86-64%s is deprecated.  Use "
+            "%stune=k8%s or %stune=generic%s instead as appropriate.",
+            prefix, suffix, prefix, suffix, prefix, suffix);
 
   if (!ix86_arch_string)
     ix86_arch_string = TARGET_64BIT ? "x86-64" : "i386";
@@ -2283,9 +2837,25 @@ override_options (void)
     ix86_arch_specified = 1;
 
   if (!strcmp (ix86_arch_string, "generic"))
-    error ("generic CPU can be used only for -mtune= switch");
+    error ("generic CPU can be used only for %stune=%s %s",
+          prefix, suffix, sw);
   if (!strncmp (ix86_arch_string, "generic", 7))
-    error ("bad value (%s) for -march= switch", ix86_arch_string);
+    error ("bad value (%s) for %sarch=%s %s",
+          ix86_arch_string, prefix, suffix, sw);
+
+  /* Validate -mabi= value.  */
+  if (ix86_abi_string)
+    {
+      if (strcmp (ix86_abi_string, "sysv") == 0)
+       ix86_abi = SYSV_ABI;
+      else if (strcmp (ix86_abi_string, "ms") == 0)
+       ix86_abi = MS_ABI;
+      else
+       error ("unknown ABI (%s) for %sabi=%s %s",
+              ix86_abi_string, prefix, suffix, sw);
+    }
+  else
+    ix86_abi = DEFAULT_ABI;
 
   if (ix86_cmodel_string != 0)
     {
@@ -2302,15 +2872,16 @@ override_options (void)
       else if (!strcmp (ix86_cmodel_string, "kernel") && !flag_pic)
        ix86_cmodel = CM_KERNEL;
       else
-       error ("bad value (%s) for -mcmodel= switch", ix86_cmodel_string);
+       error ("bad value (%s) for %scmodel=%s %s",
+              ix86_cmodel_string, prefix, suffix, sw);
     }
   else
     {
-      /* For TARGET_64BIT_MS_ABI, force pic on, in order to enable the
+      /* For TARGET_64BIT and MS_ABI, force pic on, in order to enable the
         use of rip-relative addressing.  This eliminates fixups that
         would otherwise be needed if this object is to be placed in a
         DLL, and is essentially just as efficient as direct addressing.  */
-      if (TARGET_64BIT_MS_ABI)
+      if (TARGET_64BIT && DEFAULT_ABI == MS_ABI)
        ix86_cmodel = CM_SMALL_PIC, flag_pic = 1;
       else if (TARGET_64BIT)
        ix86_cmodel = flag_pic ? CM_SMALL_PIC : CM_SMALL;
@@ -2325,7 +2896,8 @@ override_options (void)
       else if (!strcmp (ix86_asm_string, "att"))
        ix86_asm_dialect = ASM_ATT;
       else
-       error ("bad value (%s) for -masm= switch", ix86_asm_string);
+       error ("bad value (%s) for %sasm=%s %s",
+              ix86_asm_string, prefix, suffix, sw);
     }
   if ((TARGET_64BIT == 0) != (ix86_cmodel == CM_32))
     error ("code model %qs not supported in the %s bit mode",
@@ -2337,6 +2909,7 @@ override_options (void)
   for (i = 0; i < pta_size; i++)
     if (! strcmp (ix86_arch_string, processor_alias_table[i].name))
       {
+       ix86_schedule = processor_alias_table[i].schedule;
        ix86_arch = processor_alias_table[i].processor;
        /* Default cpu tuning to the architecture.  */
        ix86_tune = ix86_arch;
@@ -2372,41 +2945,57 @@ override_options (void)
        if (processor_alias_table[i].flags & PTA_SSE4_2
            && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_SSE4_2))
          ix86_isa_flags |= OPTION_MASK_ISA_SSE4_2;
+       if (processor_alias_table[i].flags & PTA_AVX
+           && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_AVX))
+         ix86_isa_flags |= OPTION_MASK_ISA_AVX;
+       if (processor_alias_table[i].flags & PTA_FMA
+           && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_FMA))
+         ix86_isa_flags |= OPTION_MASK_ISA_FMA;
        if (processor_alias_table[i].flags & PTA_SSE4A
            && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_SSE4A))
          ix86_isa_flags |= OPTION_MASK_ISA_SSE4A;
        if (processor_alias_table[i].flags & PTA_SSE5
            && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_SSE5))
          ix86_isa_flags |= OPTION_MASK_ISA_SSE5;
-
-       if (processor_alias_table[i].flags & PTA_ABM)
-         x86_abm = true;
-       if (processor_alias_table[i].flags & PTA_CX16)
-         x86_cmpxchg16b = true;
-       if (processor_alias_table[i].flags & (PTA_POPCNT | PTA_ABM))
-         x86_popcnt = true;
+       if (processor_alias_table[i].flags & PTA_ABM
+           && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_ABM))
+         ix86_isa_flags |= OPTION_MASK_ISA_ABM;
+       if (processor_alias_table[i].flags & PTA_CX16
+           && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_CX16))
+         ix86_isa_flags |= OPTION_MASK_ISA_CX16;
+       if (processor_alias_table[i].flags & (PTA_POPCNT | PTA_ABM)
+           && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_POPCNT))
+         ix86_isa_flags |= OPTION_MASK_ISA_POPCNT;
+       if (!(TARGET_64BIT && (processor_alias_table[i].flags & PTA_NO_SAHF))
+           && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_SAHF))
+         ix86_isa_flags |= OPTION_MASK_ISA_SAHF;
+       if (processor_alias_table[i].flags & PTA_MOVBE
+           && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_MOVBE))
+         ix86_isa_flags |= OPTION_MASK_ISA_MOVBE;
+       if (processor_alias_table[i].flags & PTA_AES
+           && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_AES))
+         ix86_isa_flags |= OPTION_MASK_ISA_AES;
+       if (processor_alias_table[i].flags & PTA_PCLMUL
+           && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_PCLMUL))
+         ix86_isa_flags |= OPTION_MASK_ISA_PCLMUL;
        if (processor_alias_table[i].flags & (PTA_PREFETCH_SSE | PTA_SSE))
          x86_prefetch_sse = true;
-       if (!(TARGET_64BIT && (processor_alias_table[i].flags & PTA_NO_SAHF)))
-         x86_sahf = true;
-       if (processor_alias_table[i].flags & PTA_AES)
-         x86_aes = true;
-       if (processor_alias_table[i].flags & PTA_PCLMUL)
-         x86_pclmul = true;
 
        break;
       }
 
   if (i == pta_size)
-    error ("bad value (%s) for -march= switch", ix86_arch_string);
+    error ("bad value (%s) for %sarch=%s %s",
+          ix86_arch_string, prefix, suffix, sw);
 
   ix86_arch_mask = 1u << ix86_arch;
   for (i = 0; i < X86_ARCH_LAST; ++i)
-    ix86_arch_features[i] &= ix86_arch_mask;
+    ix86_arch_features[i] = !!(initial_ix86_arch_features[i] & ix86_arch_mask);
 
   for (i = 0; i < pta_size; i++)
     if (! strcmp (ix86_tune_string, processor_alias_table[i].name))
       {
+       ix86_schedule = processor_alias_table[i].schedule;
        ix86_tune = processor_alias_table[i].processor;
        if (TARGET_64BIT && !(processor_alias_table[i].flags & PTA_64BIT))
          {
@@ -2417,6 +3006,7 @@ override_options (void)
                  if (! strcmp (ix86_tune_string,
                                processor_alias_table[i].name))
                    break;
+               ix86_schedule = processor_alias_table[i].schedule;
                ix86_tune = processor_alias_table[i].processor;
              }
            else
@@ -2434,22 +3024,15 @@ override_options (void)
        break;
       }
   if (i == pta_size)
-    error ("bad value (%s) for -mtune= switch", ix86_tune_string);
-
-  /* Enable SSE2 if AES or PCLMUL is enabled.  */
-  if ((x86_aes || x86_pclmul)
-      && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_SSE2))
-    {
-      ix86_isa_flags |= OPTION_MASK_ISA_SSE2_SET;
-      ix86_isa_flags_explicit |= OPTION_MASK_ISA_SSE2_SET;
-    }
+    error ("bad value (%s) for %stune=%s %s",
+          ix86_tune_string, prefix, suffix, sw);
 
   ix86_tune_mask = 1u << ix86_tune;
   for (i = 0; i < X86_TUNE_LAST; ++i)
-    ix86_tune_features[i] &= ix86_tune_mask;
+    ix86_tune_features[i] = !!(initial_ix86_tune_features[i] & ix86_tune_mask);
 
   if (optimize_size)
-    ix86_cost = &size_cost;
+    ix86_cost = &ix86_size_cost;
   else
     ix86_cost = processor_target_table[ix86_tune].cost;
 
@@ -2460,10 +3043,11 @@ override_options (void)
   if (ix86_regparm_string)
     {
       if (TARGET_64BIT)
-       warning (0, "-mregparm is ignored in 64-bit mode");
+       warning (0, "%sregparm%s is ignored in 64-bit mode", prefix, suffix);
       i = atoi (ix86_regparm_string);
       if (i < 0 || i > REGPARM_MAX)
-       error ("-mregparm=%d is not between 0 and %d", i, REGPARM_MAX);
+       error ("%sregparm=%d%s is not between 0 and %d",
+              prefix, i, suffix, REGPARM_MAX);
       else
        ix86_regparm = i;
     }
@@ -2475,12 +3059,14 @@ override_options (void)
      Remove this code in GCC 3.2 or later.  */
   if (ix86_align_loops_string)
     {
-      warning (0, "-malign-loops is obsolete, use -falign-loops");
+      warning (0, "%salign-loops%s is obsolete, use -falign-loops%s",
+              prefix, suffix, suffix);
       if (align_loops == 0)
        {
          i = atoi (ix86_align_loops_string);
          if (i < 0 || i > MAX_CODE_ALIGN)
-           error ("-malign-loops=%d is not between 0 and %d", i, MAX_CODE_ALIGN);
+           error ("%salign-loops=%d%s is not between 0 and %d",
+                  prefix, i, suffix, MAX_CODE_ALIGN);
          else
            align_loops = 1 << i;
        }
@@ -2488,12 +3074,14 @@ override_options (void)
 
   if (ix86_align_jumps_string)
     {
-      warning (0, "-malign-jumps is obsolete, use -falign-jumps");
+      warning (0, "%salign-jumps%s is obsolete, use -falign-jumps%s",
+              prefix, suffix, suffix);
       if (align_jumps == 0)
        {
          i = atoi (ix86_align_jumps_string);
          if (i < 0 || i > MAX_CODE_ALIGN)
-           error ("-malign-loops=%d is not between 0 and %d", i, MAX_CODE_ALIGN);
+           error ("%salign-loops=%d%s is not between 0 and %d",
+                  prefix, i, suffix, MAX_CODE_ALIGN);
          else
            align_jumps = 1 << i;
        }
@@ -2501,12 +3089,14 @@ override_options (void)
 
   if (ix86_align_funcs_string)
     {
-      warning (0, "-malign-functions is obsolete, use -falign-functions");
+      warning (0, "%salign-functions%s is obsolete, use -falign-functions%s",
+              prefix, suffix, suffix);
       if (align_functions == 0)
        {
          i = atoi (ix86_align_funcs_string);
          if (i < 0 || i > MAX_CODE_ALIGN)
-           error ("-malign-loops=%d is not between 0 and %d", i, MAX_CODE_ALIGN);
+           error ("%salign-loops=%d%s is not between 0 and %d",
+                  prefix, i, suffix, MAX_CODE_ALIGN);
          else
            align_functions = 1 << i;
        }
@@ -2534,7 +3124,7 @@ override_options (void)
     {
       i = atoi (ix86_branch_cost_string);
       if (i < 0 || i > 5)
-       error ("-mbranch-cost=%d is not between 0 and 5", i);
+       error ("%sbranch-cost=%d%s is not between 0 and 5", prefix, i, suffix);
       else
        ix86_branch_cost = i;
     }
@@ -2542,7 +3132,7 @@ override_options (void)
     {
       i = atoi (ix86_section_threshold_string);
       if (i < 0)
-       error ("-mlarge-data-threshold=%d is negative", i);
+       error ("%slarge-data-threshold=%d%s is negative", prefix, i, suffix);
       else
        ix86_section_threshold = i;
     }
@@ -2556,8 +3146,8 @@ override_options (void)
       else if (strcmp (ix86_tls_dialect_string, "sun") == 0)
        ix86_tls_dialect = TLS_DIALECT_SUN;
       else
-       error ("bad value (%s) for -mtls-dialect= switch",
-              ix86_tls_dialect_string);
+       error ("bad value (%s) for %stls-dialect=%s %s",
+              ix86_tls_dialect_string, prefix, suffix, sw);
     }
 
   if (ix87_precision_string)
@@ -2580,7 +3170,7 @@ override_options (void)
             | TARGET_SUBTARGET64_ISA_DEFAULT) & ~ix86_isa_flags_explicit);
 
       if (TARGET_RTD)
-       warning (0, "-mrtd is ignored in 64bit mode");
+       warning (0, "%srtd%s is ignored in 64bit mode", prefix, suffix);
     }
   else
     {
@@ -2626,27 +3216,50 @@ override_options (void)
 
   /* Turn on popcnt instruction for -msse4.2 or -mabm.  */
   if (TARGET_SSE4_2 || TARGET_ABM)
-    x86_popcnt = true;
+    ix86_isa_flags |= OPTION_MASK_ISA_POPCNT & ~ix86_isa_flags_explicit;
 
-  /* Validate -mpreferred-stack-boundary= value, or provide default.
-     The default of 128 bits is for Pentium III's SSE __m128.  We can't
-     change it because of optimize_size.  Otherwise, we can't mix object
-     files compiled with -Os and -On.  */
-  ix86_preferred_stack_boundary = 128;
+  /* Validate -mpreferred-stack-boundary= value or default it to
+     PREFERRED_STACK_BOUNDARY_DEFAULT.  */
+  ix86_preferred_stack_boundary = PREFERRED_STACK_BOUNDARY_DEFAULT;
   if (ix86_preferred_stack_boundary_string)
     {
       i = atoi (ix86_preferred_stack_boundary_string);
       if (i < (TARGET_64BIT ? 4 : 2) || i > 12)
-       error ("-mpreferred-stack-boundary=%d is not between %d and 12", i,
-              TARGET_64BIT ? 4 : 2);
+       error ("%spreferred-stack-boundary=%d%s is not between %d and 12",
+              prefix, i, suffix, TARGET_64BIT ? 4 : 2);
       else
        ix86_preferred_stack_boundary = (1 << i) * BITS_PER_UNIT;
     }
 
+  /* Set the default value for -mstackrealign.  */
+  if (ix86_force_align_arg_pointer == -1)
+    ix86_force_align_arg_pointer = STACK_REALIGN_DEFAULT;
+
+  /* Validate -mincoming-stack-boundary= value or default it to
+     MIN_STACK_BOUNDARY/PREFERRED_STACK_BOUNDARY.  */
+  if (ix86_force_align_arg_pointer)
+    ix86_default_incoming_stack_boundary = MIN_STACK_BOUNDARY;
+  else
+    ix86_default_incoming_stack_boundary = PREFERRED_STACK_BOUNDARY;
+  ix86_incoming_stack_boundary = ix86_default_incoming_stack_boundary;
+  if (ix86_incoming_stack_boundary_string)
+    {
+      i = atoi (ix86_incoming_stack_boundary_string);
+      if (i < (TARGET_64BIT ? 4 : 2) || i > 12)
+       error ("-mincoming-stack-boundary=%d is not between %d and 12",
+              i, TARGET_64BIT ? 4 : 2);
+      else
+       {
+         ix86_user_incoming_stack_boundary = (1 << i) * BITS_PER_UNIT;
+         ix86_incoming_stack_boundary
+           = ix86_user_incoming_stack_boundary;
+       }
+    }
+
   /* Accept -msseregparm only if at least SSE support is enabled.  */
   if (TARGET_SSEREGPARM
       && ! TARGET_SSE)
-    error ("-msseregparm used without SSE enabled");
+    error ("%ssseregparm%s used without SSE enabled", prefix, suffix);
 
   ix86_fpmath = TARGET_FPMATH_DEFAULT;
   if (ix86_fpmath_string != 0)
@@ -2664,7 +3277,10 @@ override_options (void)
            ix86_fpmath = FPMATH_SSE;
        }
       else if (! strcmp (ix86_fpmath_string, "387,sse")
-              || ! strcmp (ix86_fpmath_string, "sse,387"))
+              || ! strcmp (ix86_fpmath_string, "387+sse")
+              || ! strcmp (ix86_fpmath_string, "sse,387")
+              || ! strcmp (ix86_fpmath_string, "sse+387")
+              || ! strcmp (ix86_fpmath_string, "both"))
        {
          if (!TARGET_SSE)
            {
@@ -2680,7 +3296,8 @@ override_options (void)
            ix86_fpmath = (enum fpmath_unit) (FPMATH_SSE | FPMATH_387);
        }
       else
-       error ("bad value (%s) for -mfpmath= switch", ix86_fpmath_string);
+       error ("bad value (%s) for %sfpmath=%s %s",
+              ix86_fpmath_string, prefix, suffix, sw);
     }
 
   /* If the i387 is disabled, then do not return values in it. */
@@ -2696,7 +3313,8 @@ override_options (void)
        ix86_veclib_handler = ix86_veclibabi_acml;
       else
        error ("unknown vectorization library ABI type (%s) for "
-              "-mveclibabi= switch", ix86_veclibabi_string);
+              "%sveclibabi=%s %s", ix86_veclibabi_string,
+              prefix, suffix, sw);
     }
 
   if ((x86_accumulate_outgoing_args & ix86_tune_mask)
@@ -2715,7 +3333,8 @@ override_options (void)
     {
       if (target_flags_explicit & MASK_ACCUMULATE_OUTGOING_ARGS)
        warning (0, "unwind tables currently require either a frame pointer "
-                "or -maccumulate-outgoing-args for correctness");
+                "or %saccumulate-outgoing-args%s for correctness",
+                prefix, suffix);
       target_flags |= MASK_ACCUMULATE_OUTGOING_ARGS;
     }
 
@@ -2726,8 +3345,8 @@ override_options (void)
       && !(target_flags & MASK_ACCUMULATE_OUTGOING_ARGS))
     {
       if (target_flags_explicit & MASK_ACCUMULATE_OUTGOING_ARGS)
-       warning (0, "stack probing requires -maccumulate-outgoing-args "
-                "for correctness");
+       warning (0, "stack probing requires %saccumulate-outgoing-args%s "
+                "for correctness", prefix, suffix);
       target_flags |= MASK_ACCUMULATE_OUTGOING_ARGS;
     }
 
@@ -2750,21 +3369,644 @@ override_options (void)
   if (!TARGET_SCHEDULE)
     flag_schedule_insns_after_reload = flag_schedule_insns = 0;
 
-  if (!PARAM_SET_P (PARAM_SIMULTANEOUS_PREFETCHES))
-    set_param_value ("simultaneous-prefetches",
-                    ix86_cost->simultaneous_prefetches);
-  if (!PARAM_SET_P (PARAM_L1_CACHE_LINE_SIZE))
-    set_param_value ("l1-cache-line-size", ix86_cost->prefetch_block);
-  if (!PARAM_SET_P (PARAM_L1_CACHE_SIZE))
-    set_param_value ("l1-cache-size", ix86_cost->l1_cache_size);
-  if (!PARAM_SET_P (PARAM_L2_CACHE_SIZE))
-    set_param_value ("l2-cache-size", ix86_cost->l2_cache_size);
+  if (!PARAM_SET_P (PARAM_SIMULTANEOUS_PREFETCHES))
+    set_param_value ("simultaneous-prefetches",
+                    ix86_cost->simultaneous_prefetches);
+  if (!PARAM_SET_P (PARAM_L1_CACHE_LINE_SIZE))
+    set_param_value ("l1-cache-line-size", ix86_cost->prefetch_block);
+  if (!PARAM_SET_P (PARAM_L1_CACHE_SIZE))
+    set_param_value ("l1-cache-size", ix86_cost->l1_cache_size);
+  if (!PARAM_SET_P (PARAM_L2_CACHE_SIZE))
+    set_param_value ("l2-cache-size", ix86_cost->l2_cache_size);
+
+  /* If using typedef char *va_list, signal that __builtin_va_start (&ap, 0)
+     can be optimized to ap = __builtin_next_arg (0).  */
+  if (!TARGET_64BIT)
+    targetm.expand_builtin_va_start = NULL;
+
+  if (TARGET_64BIT)
+    {
+      ix86_gen_leave = gen_leave_rex64;
+      ix86_gen_pop1 = gen_popdi1;
+      ix86_gen_add3 = gen_adddi3;
+      ix86_gen_sub3 = gen_subdi3;
+      ix86_gen_sub3_carry = gen_subdi3_carry_rex64;
+      ix86_gen_one_cmpl2 = gen_one_cmpldi2;
+      ix86_gen_monitor = gen_sse3_monitor64;
+      ix86_gen_andsp = gen_anddi3;
+    }
+  else
+    {
+      ix86_gen_leave = gen_leave;
+      ix86_gen_pop1 = gen_popsi1;
+      ix86_gen_add3 = gen_addsi3;
+      ix86_gen_sub3 = gen_subsi3;
+      ix86_gen_sub3_carry = gen_subsi3_carry;
+      ix86_gen_one_cmpl2 = gen_one_cmplsi2;
+      ix86_gen_monitor = gen_sse3_monitor;
+      ix86_gen_andsp = gen_andsi3;
+    }
+
+#ifdef USE_IX86_CLD
+  /* Use -mcld by default for 32-bit code if configured with --enable-cld.  */
+  if (!TARGET_64BIT)
+    target_flags |= MASK_CLD & ~target_flags_explicit;
+#endif
+
+  /* Save the initial options in case the user does function specific options */
+  if (main_args_p)
+    target_option_default_node = target_option_current_node
+      = build_target_option_node ();
+}
+
+/* Update register usage after having seen the compiler flags.  */
+
+void
+ix86_conditional_register_usage (void)
+{
+  int i;
+  unsigned int j;
+
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    {
+      if (fixed_regs[i] > 1)
+       fixed_regs[i] = (fixed_regs[i] == (TARGET_64BIT ? 3 : 2));
+      if (call_used_regs[i] > 1)
+       call_used_regs[i] = (call_used_regs[i] == (TARGET_64BIT ? 3 : 2));
+    }
+
+  /* The PIC register, if it exists, is fixed.  */
+  j = PIC_OFFSET_TABLE_REGNUM;
+  if (j != INVALID_REGNUM)
+    fixed_regs[j] = call_used_regs[j] = 1;
+
+  /* The MS_ABI changes the set of call-used registers.  */
+  if (TARGET_64BIT && ix86_cfun_abi () == MS_ABI)
+    {
+      call_used_regs[SI_REG] = 0;
+      call_used_regs[DI_REG] = 0;
+      call_used_regs[XMM6_REG] = 0;
+      call_used_regs[XMM7_REG] = 0;
+      for (i = FIRST_REX_SSE_REG; i <= LAST_REX_SSE_REG; i++)
+       call_used_regs[i] = 0;
+    }
+
+  /* The default setting of CLOBBERED_REGS is for 32-bit; add in the
+     other call-clobbered regs for 64-bit.  */
+  if (TARGET_64BIT)
+    {
+      CLEAR_HARD_REG_SET (reg_class_contents[(int)CLOBBERED_REGS]);
+
+      for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+       if (TEST_HARD_REG_BIT (reg_class_contents[(int)GENERAL_REGS], i)
+           && call_used_regs[i])
+         SET_HARD_REG_BIT (reg_class_contents[(int)CLOBBERED_REGS], i);
+    }
+
+  /* If MMX is disabled, squash the registers.  */
+  if (! TARGET_MMX)
+    for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+      if (TEST_HARD_REG_BIT (reg_class_contents[(int)MMX_REGS], i))
+       fixed_regs[i] = call_used_regs[i] = 1, reg_names[i] = "";
+
+  /* If SSE is disabled, squash the registers.  */
+  if (! TARGET_SSE)
+    for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+      if (TEST_HARD_REG_BIT (reg_class_contents[(int)SSE_REGS], i))
+       fixed_regs[i] = call_used_regs[i] = 1, reg_names[i] = "";
+
+  /* If the FPU is disabled, squash the registers.  */
+  if (! (TARGET_80387 || TARGET_FLOAT_RETURNS_IN_80387))
+    for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+      if (TEST_HARD_REG_BIT (reg_class_contents[(int)FLOAT_REGS], i))
+       fixed_regs[i] = call_used_regs[i] = 1, reg_names[i] = "";
+
+  /* If 32-bit, squash the 64-bit registers.  */
+  if (! TARGET_64BIT)
+    {
+      for (i = FIRST_REX_INT_REG; i <= LAST_REX_INT_REG; i++)
+       reg_names[i] = "";
+      for (i = FIRST_REX_SSE_REG; i <= LAST_REX_SSE_REG; i++)
+       reg_names[i] = "";
+    }
+}
+
+\f
+/* Save the current options */
+
+static void
+ix86_function_specific_save (struct cl_target_option *ptr)
+{
+  ptr->arch = ix86_arch;
+  ptr->schedule = ix86_schedule;
+  ptr->tune = ix86_tune;
+  ptr->fpmath = ix86_fpmath;
+  ptr->branch_cost = ix86_branch_cost;
+  ptr->tune_defaulted = ix86_tune_defaulted;
+  ptr->arch_specified = ix86_arch_specified;
+  ptr->ix86_isa_flags_explicit = ix86_isa_flags_explicit;
+  ptr->target_flags_explicit = target_flags_explicit;
+
+  /* The fields are char but the variables are not; make sure the
+     values fit in the fields.  */
+  gcc_assert (ptr->arch == ix86_arch);
+  gcc_assert (ptr->schedule == ix86_schedule);
+  gcc_assert (ptr->tune == ix86_tune);
+  gcc_assert (ptr->fpmath == ix86_fpmath);
+  gcc_assert (ptr->branch_cost == ix86_branch_cost);
+}
+
+/* Restore the current options */
+
+static void
+ix86_function_specific_restore (struct cl_target_option *ptr)
+{
+  enum processor_type old_tune = ix86_tune;
+  enum processor_type old_arch = ix86_arch;
+  unsigned int ix86_arch_mask, ix86_tune_mask;
+  int i;
+
+  ix86_arch = (enum processor_type) ptr->arch;
+  ix86_schedule = (enum attr_cpu) ptr->schedule;
+  ix86_tune = (enum processor_type) ptr->tune;
+  ix86_fpmath = (enum fpmath_unit) ptr->fpmath;
+  ix86_branch_cost = ptr->branch_cost;
+  ix86_tune_defaulted = ptr->tune_defaulted;
+  ix86_arch_specified = ptr->arch_specified;
+  ix86_isa_flags_explicit = ptr->ix86_isa_flags_explicit;
+  target_flags_explicit = ptr->target_flags_explicit;
+
+  /* Recreate the arch feature tests if the arch changed */
+  if (old_arch != ix86_arch)
+    {
+      ix86_arch_mask = 1u << ix86_arch;
+      for (i = 0; i < X86_ARCH_LAST; ++i)
+       ix86_arch_features[i]
+         = !!(initial_ix86_arch_features[i] & ix86_arch_mask);
+    }
+
+  /* Recreate the tune optimization tests */
+  if (old_tune != ix86_tune)
+    {
+      ix86_tune_mask = 1u << ix86_tune;
+      for (i = 0; i < X86_TUNE_LAST; ++i)
+       ix86_tune_features[i]
+         = !!(initial_ix86_tune_features[i] & ix86_tune_mask);
+    }
+}
+
+/* Print the current options */
+
+static void
+ix86_function_specific_print (FILE *file, int indent,
+                             struct cl_target_option *ptr)
+{
+  char *target_string
+    = ix86_target_string (ptr->ix86_isa_flags, ptr->target_flags,
+                         NULL, NULL, NULL, false);
+
+  fprintf (file, "%*sarch = %d (%s)\n",
+          indent, "",
+          ptr->arch,
+          ((ptr->arch < TARGET_CPU_DEFAULT_max)
+           ? cpu_names[ptr->arch]
+           : "<unknown>"));
+
+  fprintf (file, "%*stune = %d (%s)\n",
+          indent, "",
+          ptr->tune,
+          ((ptr->tune < TARGET_CPU_DEFAULT_max)
+           ? cpu_names[ptr->tune]
+           : "<unknown>"));
+
+  fprintf (file, "%*sfpmath = %d%s%s\n", indent, "", ptr->fpmath,
+          (ptr->fpmath & FPMATH_387) ? ", 387" : "",
+          (ptr->fpmath & FPMATH_SSE) ? ", sse" : "");
+  fprintf (file, "%*sbranch_cost = %d\n", indent, "", ptr->branch_cost);
+
+  if (target_string)
+    {
+      fprintf (file, "%*s%s\n", indent, "", target_string);
+      free (target_string);
+    }
+}
+
+\f
+/* Inner function to process the attribute((target(...))), take an argument and
+   set the current options from the argument. If we have a list, recursively go
+   over the list.  */
+
+static bool
+ix86_valid_target_attribute_inner_p (tree args, char *p_strings[])
+{
+  char *next_optstr;
+  bool ret = true;
+
+#define IX86_ATTR_ISA(S,O)   { S, sizeof (S)-1, ix86_opt_isa, O, 0 }
+#define IX86_ATTR_STR(S,O)   { S, sizeof (S)-1, ix86_opt_str, O, 0 }
+#define IX86_ATTR_YES(S,O,M) { S, sizeof (S)-1, ix86_opt_yes, O, M }
+#define IX86_ATTR_NO(S,O,M)  { S, sizeof (S)-1, ix86_opt_no,  O, M }
+
+  enum ix86_opt_type
+  {
+    ix86_opt_unknown,
+    ix86_opt_yes,
+    ix86_opt_no,
+    ix86_opt_str,
+    ix86_opt_isa
+  };
+
+  static const struct
+  {
+    const char *string;
+    size_t len;
+    enum ix86_opt_type type;
+    int opt;
+    int mask;
+  } attrs[] = {
+    /* isa options */
+    IX86_ATTR_ISA ("3dnow",    OPT_m3dnow),
+    IX86_ATTR_ISA ("abm",      OPT_mabm),
+    IX86_ATTR_ISA ("aes",      OPT_maes),
+    IX86_ATTR_ISA ("avx",      OPT_mavx),
+    IX86_ATTR_ISA ("mmx",      OPT_mmmx),
+    IX86_ATTR_ISA ("pclmul",   OPT_mpclmul),
+    IX86_ATTR_ISA ("popcnt",   OPT_mpopcnt),
+    IX86_ATTR_ISA ("sse",      OPT_msse),
+    IX86_ATTR_ISA ("sse2",     OPT_msse2),
+    IX86_ATTR_ISA ("sse3",     OPT_msse3),
+    IX86_ATTR_ISA ("sse4",     OPT_msse4),
+    IX86_ATTR_ISA ("sse4.1",   OPT_msse4_1),
+    IX86_ATTR_ISA ("sse4.2",   OPT_msse4_2),
+    IX86_ATTR_ISA ("sse4a",    OPT_msse4a),
+    IX86_ATTR_ISA ("sse5",     OPT_msse5),
+    IX86_ATTR_ISA ("ssse3",    OPT_mssse3),
+
+    /* string options */
+    IX86_ATTR_STR ("arch=",    IX86_FUNCTION_SPECIFIC_ARCH),
+    IX86_ATTR_STR ("fpmath=",  IX86_FUNCTION_SPECIFIC_FPMATH),
+    IX86_ATTR_STR ("tune=",    IX86_FUNCTION_SPECIFIC_TUNE),
+
+    /* flag options */
+    IX86_ATTR_YES ("cld",
+                  OPT_mcld,
+                  MASK_CLD),
+
+    IX86_ATTR_NO ("fancy-math-387",
+                 OPT_mfancy_math_387,
+                 MASK_NO_FANCY_MATH_387),
+
+    IX86_ATTR_NO ("fused-madd",
+                 OPT_mfused_madd,
+                 MASK_NO_FUSED_MADD),
+
+    IX86_ATTR_YES ("ieee-fp",
+                  OPT_mieee_fp,
+                  MASK_IEEE_FP),
+
+    IX86_ATTR_YES ("inline-all-stringops",
+                  OPT_minline_all_stringops,
+                  MASK_INLINE_ALL_STRINGOPS),
+
+    IX86_ATTR_YES ("inline-stringops-dynamically",
+                  OPT_minline_stringops_dynamically,
+                  MASK_INLINE_STRINGOPS_DYNAMICALLY),
+
+    IX86_ATTR_NO ("align-stringops",
+                 OPT_mno_align_stringops,
+                 MASK_NO_ALIGN_STRINGOPS),
+
+    IX86_ATTR_YES ("recip",
+                  OPT_mrecip,
+                  MASK_RECIP),
+
+  };
+
+  /* If this is a list, recurse to get the options.  */
+  if (TREE_CODE (args) == TREE_LIST)
+    {
+      bool ret = true;
+
+      for (; args; args = TREE_CHAIN (args))
+       if (TREE_VALUE (args)
+           && !ix86_valid_target_attribute_inner_p (TREE_VALUE (args), p_strings))
+         ret = false;
+
+      return ret;
+    }
+
+  else if (TREE_CODE (args) != STRING_CST)
+    gcc_unreachable ();
+
+  /* Handle multiple arguments separated by commas.  */
+  next_optstr = ASTRDUP (TREE_STRING_POINTER (args));
+
+  while (next_optstr && *next_optstr != '\0')
+    {
+      char *p = next_optstr;
+      char *orig_p = p;
+      char *comma = strchr (next_optstr, ',');
+      const char *opt_string;
+      size_t len, opt_len;
+      int opt;
+      bool opt_set_p;
+      char ch;
+      unsigned i;
+      enum ix86_opt_type type = ix86_opt_unknown;
+      int mask = 0;
+
+      if (comma)
+       {
+         *comma = '\0';
+         len = comma - next_optstr;
+         next_optstr = comma + 1;
+       }
+      else
+       {
+         len = strlen (p);
+         next_optstr = NULL;
+       }
+
+      /* Recognize no-xxx.  */
+      if (len > 3 && p[0] == 'n' && p[1] == 'o' && p[2] == '-')
+       {
+         opt_set_p = false;
+         p += 3;
+         len -= 3;
+       }
+      else
+       opt_set_p = true;
+
+      /* Find the option.  */
+      ch = *p;
+      opt = N_OPTS;
+      for (i = 0; i < ARRAY_SIZE (attrs); i++)
+       {
+         type = attrs[i].type;
+         opt_len = attrs[i].len;
+         if (ch == attrs[i].string[0]
+             && ((type != ix86_opt_str) ? len == opt_len : len > opt_len)
+             && memcmp (p, attrs[i].string, opt_len) == 0)
+           {
+             opt = attrs[i].opt;
+             mask = attrs[i].mask;
+             opt_string = attrs[i].string;
+             break;
+           }
+       }
+
+      /* Process the option.  */
+      if (opt == N_OPTS)
+       {
+         error ("attribute(target(\"%s\")) is unknown", orig_p);
+         ret = false;
+       }
+
+      else if (type == ix86_opt_isa)
+       ix86_handle_option (opt, p, opt_set_p);
+
+      else if (type == ix86_opt_yes || type == ix86_opt_no)
+       {
+         if (type == ix86_opt_no)
+           opt_set_p = !opt_set_p;
+
+         if (opt_set_p)
+           target_flags |= mask;
+         else
+           target_flags &= ~mask;
+       }
+
+      else if (type == ix86_opt_str)
+       {
+         if (p_strings[opt])
+           {
+             error ("option(\"%s\") was already specified", opt_string);
+             ret = false;
+           }
+         else
+           p_strings[opt] = xstrdup (p + opt_len);
+       }
+
+      else
+       gcc_unreachable ();
+    }
+
+  return ret;
+}
+
+/* Return a TARGET_OPTION_NODE tree of the target options listed or NULL.  */
+
+tree
+ix86_valid_target_attribute_tree (tree args)
+{
+  const char *orig_arch_string = ix86_arch_string;
+  const char *orig_tune_string = ix86_tune_string;
+  const char *orig_fpmath_string = ix86_fpmath_string;
+  int orig_tune_defaulted = ix86_tune_defaulted;
+  int orig_arch_specified = ix86_arch_specified;
+  char *option_strings[IX86_FUNCTION_SPECIFIC_MAX] = { NULL, NULL, NULL };
+  tree t = NULL_TREE;
+  int i;
+  struct cl_target_option *def
+    = TREE_TARGET_OPTION (target_option_default_node);
+
+  /* Process each of the options on the chain.  */
+  if (! ix86_valid_target_attribute_inner_p (args, option_strings))
+    return NULL_TREE;
+
+  /* If the changed options are different from the default, rerun override_options,
+     and then save the options away.  The string options are are attribute options,
+     and will be undone when we copy the save structure.  */
+  if (ix86_isa_flags != def->ix86_isa_flags
+      || target_flags != def->target_flags
+      || option_strings[IX86_FUNCTION_SPECIFIC_ARCH]
+      || option_strings[IX86_FUNCTION_SPECIFIC_TUNE]
+      || option_strings[IX86_FUNCTION_SPECIFIC_FPMATH])
+    {
+      /* If we are using the default tune= or arch=, undo the string assigned,
+        and use the default.  */
+      if (option_strings[IX86_FUNCTION_SPECIFIC_ARCH])
+       ix86_arch_string = option_strings[IX86_FUNCTION_SPECIFIC_ARCH];
+      else if (!orig_arch_specified)
+       ix86_arch_string = NULL;
+
+      if (option_strings[IX86_FUNCTION_SPECIFIC_TUNE])
+       ix86_tune_string = option_strings[IX86_FUNCTION_SPECIFIC_TUNE];
+      else if (orig_tune_defaulted)
+       ix86_tune_string = NULL;
+
+      /* If fpmath= is not set, and we now have sse2 on 32-bit, use it.  */
+      if (option_strings[IX86_FUNCTION_SPECIFIC_FPMATH])
+       ix86_fpmath_string = option_strings[IX86_FUNCTION_SPECIFIC_FPMATH];
+      else if (!TARGET_64BIT && TARGET_SSE)
+       ix86_fpmath_string = "sse,387";
+
+      /* Do any overrides, such as arch=xxx, or tune=xxx support.  */
+      override_options (false);
+
+      /* Add any builtin functions with the new isa if any.  */
+      ix86_add_new_builtins (ix86_isa_flags);
+
+      /* Save the current options unless we are validating options for
+        #pragma.  */
+      t = build_target_option_node ();
+
+      ix86_arch_string = orig_arch_string;
+      ix86_tune_string = orig_tune_string;
+      ix86_fpmath_string = orig_fpmath_string;
+
+      /* Free up memory allocated to hold the strings */
+      for (i = 0; i < IX86_FUNCTION_SPECIFIC_MAX; i++)
+       if (option_strings[i])
+         free (option_strings[i]);
+    }
+
+  return t;
+}
+
+/* Hook to validate attribute((target("string"))).  */
+
+static bool
+ix86_valid_target_attribute_p (tree fndecl,
+                              tree ARG_UNUSED (name),
+                              tree args,
+                              int ARG_UNUSED (flags))
+{
+  struct cl_target_option cur_target;
+  bool ret = true;
+  tree old_optimize = build_optimization_node ();
+  tree new_target, new_optimize;
+  tree func_optimize = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl);
+
+  /* If the function changed the optimization levels as well as setting target
+     options, start with the optimizations specified.  */
+  if (func_optimize && func_optimize != old_optimize)
+    cl_optimization_restore (TREE_OPTIMIZATION (func_optimize));
+
+  /* The target attributes may also change some optimization flags, so update
+     the optimization options if necessary.  */
+  cl_target_option_save (&cur_target);
+  new_target = ix86_valid_target_attribute_tree (args);
+  new_optimize = build_optimization_node ();
+
+  if (!new_target)
+    ret = false;
+
+  else if (fndecl)
+    {
+      DECL_FUNCTION_SPECIFIC_TARGET (fndecl) = new_target;
+
+      if (old_optimize != new_optimize)
+       DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl) = new_optimize;
+    }
+
+  cl_target_option_restore (&cur_target);
+
+  if (old_optimize != new_optimize)
+    cl_optimization_restore (TREE_OPTIMIZATION (old_optimize));
+
+  return ret;
+}
+
+\f
+/* Hook to determine if one function can safely inline another.  */
+
+static bool
+ix86_can_inline_p (tree caller, tree callee)
+{
+  bool ret = false;
+  tree caller_tree = DECL_FUNCTION_SPECIFIC_TARGET (caller);
+  tree callee_tree = DECL_FUNCTION_SPECIFIC_TARGET (callee);
+
+  /* If callee has no option attributes, then it is ok to inline.  */
+  if (!callee_tree)
+    ret = true;
+
+  /* If caller has no option attributes, but callee does then it is not ok to
+     inline.  */
+  else if (!caller_tree)
+    ret = false;
+
+  else
+    {
+      struct cl_target_option *caller_opts = TREE_TARGET_OPTION (caller_tree);
+      struct cl_target_option *callee_opts = TREE_TARGET_OPTION (callee_tree);
+
+      /* Callee's isa options should a subset of the caller's, i.e. a SSE5 function
+        can inline a SSE2 function but a SSE2 function can't inline a SSE5
+        function.  */
+      if ((caller_opts->ix86_isa_flags & callee_opts->ix86_isa_flags)
+         != callee_opts->ix86_isa_flags)
+       ret = false;
+
+      /* See if we have the same non-isa options.  */
+      else if (caller_opts->target_flags != callee_opts->target_flags)
+       ret = false;
+
+      /* See if arch, tune, etc. are the same.  */
+      else if (caller_opts->arch != callee_opts->arch)
+       ret = false;
+
+      else if (caller_opts->tune != callee_opts->tune)
+       ret = false;
+
+      else if (caller_opts->fpmath != callee_opts->fpmath)
+       ret = false;
+
+      else if (caller_opts->branch_cost != callee_opts->branch_cost)
+       ret = false;
+
+      else
+       ret = true;
+    }
+
+  return ret;
+}
+
+\f
+/* Remember the last target of ix86_set_current_function.  */
+static GTY(()) tree ix86_previous_fndecl;
+
+/* Establish appropriate back-end context for processing the function
+   FNDECL.  The argument might be NULL to indicate processing at top
+   level, outside of any function scope.  */
+static void
+ix86_set_current_function (tree fndecl)
+{
+  /* Only change the context if the function changes.  This hook is called
+     several times in the course of compiling a function, and we don't want to
+     slow things down too much or call target_reinit when it isn't safe.  */
+  if (fndecl && fndecl != ix86_previous_fndecl)
+    {
+      tree old_tree = (ix86_previous_fndecl
+                      ? DECL_FUNCTION_SPECIFIC_TARGET (ix86_previous_fndecl)
+                      : NULL_TREE);
+
+      tree new_tree = (fndecl
+                      ? DECL_FUNCTION_SPECIFIC_TARGET (fndecl)
+                      : NULL_TREE);
+
+      ix86_previous_fndecl = fndecl;
+      if (old_tree == new_tree)
+       ;
+
+      else if (new_tree)
+       {
+         cl_target_option_restore (TREE_TARGET_OPTION (new_tree));
+         target_reinit ();
+       }
 
-  /* If using typedef char *va_list, signal that __builtin_va_start (&ap, 0)
-     can be optimized to ap = __builtin_next_arg (0).  */
-  if (!TARGET_64BIT || TARGET_64BIT_MS_ABI)
-    targetm.expand_builtin_va_start = NULL;
+      else if (old_tree)
+       {
+         struct cl_target_option *def
+           = TREE_TARGET_OPTION (target_option_current_node);
+
+         cl_target_option_restore (def);
+         target_reinit ();
+       }
+    }
 }
+
 \f
 /* Return true if this goes in large data/bss.  */
 
@@ -2955,9 +4197,9 @@ x86_elf_aligned_common (FILE *file,
 {
   if ((ix86_cmodel == CM_MEDIUM || ix86_cmodel == CM_MEDIUM_PIC)
       && size > (unsigned int)ix86_section_threshold)
-    fprintf (file, ".largecomm\t");
+    fputs (".largecomm\t", file);
   else
-    fprintf (file, "%s", COMMON_ASM_OP);
+    fputs (COMMON_ASM_OP, file);
   assemble_name (file, name);
   fprintf (file, ","HOST_WIDE_INT_PRINT_UNSIGNED",%u\n",
           size, align / BITS_PER_UNIT);
@@ -3024,7 +4266,7 @@ optimization_options (int level, int size ATTRIBUTE_UNUSED)
 static bool
 ix86_function_ok_for_sibcall (tree decl, tree exp)
 {
-  tree func;
+  tree type, decl_or_type;
   rtx a, b;
 
   /* If we are generating position-independent code, we cannot sibcall
@@ -3033,13 +4275,23 @@ ix86_function_ok_for_sibcall (tree decl, tree exp)
   if (!TARGET_64BIT && flag_pic && (!decl || !targetm.binds_local_p (decl)))
     return false;
 
+  /* If we need to align the outgoing stack, then sibcalling would
+     unalign the stack, which may break the called function.  */
+  if (ix86_incoming_stack_boundary < PREFERRED_STACK_BOUNDARY)
+    return false;
+
   if (decl)
-    func = decl;
+    {
+      decl_or_type = decl;
+      type = TREE_TYPE (decl);
+    }
   else
     {
-      func = TREE_TYPE (CALL_EXPR_FN (exp));
-      if (POINTER_TYPE_P (func))
-        func = TREE_TYPE (func);
+      /* We're looking at the CALL_EXPR, we need the type of the function.  */
+      type = CALL_EXPR_FN (exp);               /* pointer expression */
+      type = TREE_TYPE (type);                 /* pointer type */
+      type = TREE_TYPE (type);                 /* function type */
+      decl_or_type = type;
     }
 
   /* Check that the return value locations are the same.  Like
@@ -3051,7 +4303,7 @@ ix86_function_ok_for_sibcall (tree decl, tree exp)
      differences in the return value ABI.  Note that it is ok for one
      of the functions to have void return type as long as the return
      value of the other is passed in a register.  */
-  a = ix86_function_value (TREE_TYPE (exp), func, false);
+  a = ix86_function_value (TREE_TYPE (exp), decl_or_type, false);
   b = ix86_function_value (TREE_TYPE (DECL_RESULT (cfun->decl)),
                           cfun->decl, false);
   if (STACK_REG_P (a) || STACK_REG_P (b))
@@ -3064,37 +4316,32 @@ ix86_function_ok_for_sibcall (tree decl, tree exp)
   else if (!rtx_equal_p (a, b))
     return false;
 
-  /* If this call is indirect, we'll need to be able to use a call-clobbered
-     register for the address of the target function.  Make sure that all
-     such registers are not used for passing parameters.  */
-  if (!decl && !TARGET_64BIT)
+  if (TARGET_64BIT)
     {
-      tree type;
-
-      /* We're looking at the CALL_EXPR, we need the type of the function.  */
-      type = CALL_EXPR_FN (exp);               /* pointer expression */
-      type = TREE_TYPE (type);                 /* pointer type */
-      type = TREE_TYPE (type);                 /* function type */
-
-      if (ix86_function_regparm (type, NULL) >= 3)
+      /* The SYSV ABI has more call-clobbered registers;
+        disallow sibcalls from MS to SYSV.  */
+      if (cfun->machine->call_abi == MS_ABI
+         && ix86_function_type_abi (type) == SYSV_ABI)
+       return false;
+    }
+  else
+    {
+      /* If this call is indirect, we'll need to be able to use a
+        call-clobbered register for the address of the target function.
+        Make sure that all such registers are not used for passing
+        parameters.  Note that DLLIMPORT functions are indirect.  */
+      if (!decl
+         || (TARGET_DLLIMPORT_DECL_ATTRIBUTES && DECL_DLLIMPORT_P (decl)))
        {
-         /* ??? Need to count the actual number of registers to be used,
-            not the possible number of registers.  Fix later.  */
-         return false;
+         if (ix86_function_regparm (type, NULL) >= 3)
+           {
+             /* ??? Need to count the actual number of registers to be used,
+                not the possible number of registers.  Fix later.  */
+             return false;
+           }
        }
     }
 
-  /* Dllimport'd functions are also called indirectly.  */
-  if (TARGET_DLLIMPORT_DECL_ATTRIBUTES
-      && decl && DECL_DLLIMPORT_P (decl)
-      && ix86_function_regparm (TREE_TYPE (decl), NULL) >= 3)
-    return false;
-
-  /* If we forced aligned the stack, then sibcalling would unalign the
-     stack, which may break the called function.  */
-  if (cfun->machine->force_align_arg_pointer)
-    return false;
-
   /* Otherwise okay.  That also includes certain types of indirect calls.  */
   return true;
 }
@@ -3114,8 +4361,8 @@ ix86_handle_cconv_attribute (tree *node, tree name,
       && TREE_CODE (*node) != FIELD_DECL
       && TREE_CODE (*node) != TYPE_DECL)
     {
-      warning (OPT_Wattributes, "%qs attribute only applies to functions",
-              IDENTIFIER_POINTER (name));
+      warning (OPT_Wattributes, "%qE attribute only applies to functions",
+              name);
       *no_add_attrs = true;
       return NULL_TREE;
     }
@@ -3134,35 +4381,27 @@ ix86_handle_cconv_attribute (tree *node, tree name,
       if (TREE_CODE (cst) != INTEGER_CST)
        {
          warning (OPT_Wattributes,
-                  "%qs attribute requires an integer constant argument",
-                  IDENTIFIER_POINTER (name));
+                  "%qE attribute requires an integer constant argument",
+                  name);
          *no_add_attrs = true;
        }
       else if (compare_tree_int (cst, REGPARM_MAX) > 0)
        {
-         warning (OPT_Wattributes, "argument to %qs attribute larger than %d",
-                  IDENTIFIER_POINTER (name), REGPARM_MAX);
+         warning (OPT_Wattributes, "argument to %qE attribute larger than %d",
+                  name, REGPARM_MAX);
          *no_add_attrs = true;
        }
 
-      if (!TARGET_64BIT
-         && lookup_attribute (ix86_force_align_arg_pointer_string,
-                              TYPE_ATTRIBUTES (*node))
-         && compare_tree_int (cst, REGPARM_MAX-1))
-       {
-         error ("%s functions limited to %d register parameters",
-                ix86_force_align_arg_pointer_string, REGPARM_MAX-1);
-       }
-
       return NULL_TREE;
     }
 
   if (TARGET_64BIT)
     {
       /* Do not warn when emulating the MS ABI.  */
-      if (!TARGET_64BIT_MS_ABI)
-       warning (OPT_Wattributes, "%qs attribute ignored",
-                IDENTIFIER_POINTER (name));
+      if (TREE_CODE (*node) != FUNCTION_TYPE
+         || ix86_function_type_abi (*node) != MS_ABI)
+       warning (OPT_Wattributes, "%qE attribute ignored",
+                name);
       *no_add_attrs = true;
       return NULL_TREE;
     }
@@ -3258,13 +4497,15 @@ static int
 ix86_function_regparm (const_tree type, const_tree decl)
 {
   tree attr;
-  int regparm = ix86_regparm;
+  int regparm;
 
   static bool error_issued;
 
   if (TARGET_64BIT)
-    return regparm;
+    return (ix86_function_type_abi (type) == SYSV_ABI
+           ? X86_64_REGPARM_MAX : X86_64_MS_REGPARM_MAX);
 
+  regparm = ix86_regparm;
   attr = lookup_attribute ("regparm", TYPE_ATTRIBUTES (type));
   if (attr)
     {
@@ -3292,8 +4533,10 @@ ix86_function_regparm (const_tree type, const_tree decl)
     return 2;
 
   /* Use register calling convention for local functions when possible.  */
-  if (decl && TREE_CODE (decl) == FUNCTION_DECL
-      && flag_unit_at_a_time && !profile_flag)
+  if (decl
+      && TREE_CODE (decl) == FUNCTION_DECL
+      && optimize
+      && !profile_flag)
     {
       /* FIXME: remove this CONST_CAST when cgraph.[ch] is constified.  */
       struct cgraph_local_info *i = cgraph_local_info (CONST_CAST_TREE(decl));
@@ -3311,8 +4554,7 @@ ix86_function_regparm (const_tree type, const_tree decl)
          /* We can't use regparm(3) for nested functions as these use
             static chain pointer in third argument.  */
          if (local_regparm == 3
-             && (decl_function_context (decl)
-                  || ix86_force_align_arg_pointer)
+             && decl_function_context (decl)
              && !DECL_NO_STATIC_CHAIN (decl))
            local_regparm = 2;
 
@@ -3321,13 +4563,11 @@ ix86_function_regparm (const_tree type, const_tree decl)
             the callee DECL_STRUCT_FUNCTION is gone, so we fall back to
             scanning the attributes for the self-realigning property.  */
          f = DECL_STRUCT_FUNCTION (decl);
-         if (local_regparm == 3
-             && (f ? !!f->machine->force_align_arg_pointer
-                 : !!lookup_attribute (ix86_force_align_arg_pointer_string,
-                                       TYPE_ATTRIBUTES (TREE_TYPE (decl)))))
-           local_regparm = 2;
+          /* Since current internal arg pointer won't conflict with
+            parameter passing regs, so no need to change stack
+            realignment and adjust regparm number.
 
-         /* Each fixed register usage increases register pressure,
+            Each fixed register usage increases register pressure,
             so less registers should be used for argument passing.
             This functionality can be overriden by an explicit
             regparm value.  */
@@ -3380,7 +4620,7 @@ ix86_function_sseregparm (const_tree type, const_tree decl, bool warn)
 
   /* For local functions, pass up to SSE_REGPARM_MAX SFmode
      (and DFmode for SSE2) arguments in SSE registers.  */
-  if (decl && TARGET_SSE_MATH && flag_unit_at_a_time && !profile_flag)
+  if (decl && TARGET_SSE_MATH && optimize && !profile_flag)
     {
       /* FIXME: remove this CONST_CAST when cgraph.[ch] is constified.  */
       struct cgraph_local_info *i = cgraph_local_info (CONST_CAST_TREE(decl));
@@ -3494,15 +4734,20 @@ ix86_function_arg_regno_p (int regno)
         return true;
     }
 
+  /* TODO: The function should depend on current function ABI but
+     builtins.c would need updating then. Therefore we use the
+     default ABI.  */
+
   /* RAX is used as hidden argument to va_arg functions.  */
-  if (!TARGET_64BIT_MS_ABI && regno == AX_REG)
+  if (ix86_abi == SYSV_ABI && regno == AX_REG)
     return true;
 
-  if (TARGET_64BIT_MS_ABI)
+  if (ix86_abi == MS_ABI)
     parm_regs = x86_64_ms_abi_int_parameter_registers;
   else
     parm_regs = x86_64_int_parameter_registers;
-  for (i = 0; i < REGPARM_MAX; i++)
+  for (i = 0; i < (ix86_abi == MS_ABI
+                  ? X86_64_MS_REGPARM_MAX : X86_64_REGPARM_MAX); i++)
     if (regno == parm_regs[i])
       return true;
   return false;
@@ -3523,6 +4768,86 @@ ix86_must_pass_in_stack (enum machine_mode mode, const_tree type)
          && type && TREE_CODE (type) != VECTOR_TYPE);
 }
 
+/* It returns the size, in bytes, of the area reserved for arguments passed
+   in registers for the function represented by fndecl dependent to the used
+   abi format.  */
+int
+ix86_reg_parm_stack_space (const_tree fndecl)
+{
+  enum calling_abi call_abi = SYSV_ABI;
+  if (fndecl != NULL_TREE && TREE_CODE (fndecl) == FUNCTION_DECL)
+    call_abi = ix86_function_abi (fndecl);
+  else
+    call_abi = ix86_function_type_abi (fndecl);
+  if (call_abi == MS_ABI)
+    return 32;
+  return 0;
+}
+
+/* Returns value SYSV_ABI, MS_ABI dependent on fntype, specifying the
+   call abi used.  */
+enum calling_abi
+ix86_function_type_abi (const_tree fntype)
+{
+  if (TARGET_64BIT && fntype != NULL)
+    {
+      enum calling_abi abi = ix86_abi;
+      if (abi == SYSV_ABI)
+       {
+         if (lookup_attribute ("ms_abi", TYPE_ATTRIBUTES (fntype)))
+           abi = MS_ABI;
+       }
+      else if (lookup_attribute ("sysv_abi", TYPE_ATTRIBUTES (fntype)))
+       abi = SYSV_ABI;
+      return abi;
+    }
+  return ix86_abi;
+}
+
+static enum calling_abi
+ix86_function_abi (const_tree fndecl)
+{
+  if (! fndecl)
+    return ix86_abi;
+  return ix86_function_type_abi (TREE_TYPE (fndecl));
+}
+
+/* Returns value SYSV_ABI, MS_ABI dependent on cfun, specifying the
+   call abi used.  */
+enum calling_abi
+ix86_cfun_abi (void)
+{
+  if (! cfun || ! TARGET_64BIT)
+    return ix86_abi;
+  return cfun->machine->call_abi;
+}
+
+/* regclass.c  */
+extern void init_regs (void);
+
+/* Implementation of call abi switching target hook. Specific to FNDECL
+   the specific call register sets are set. See also CONDITIONAL_REGISTER_USAGE
+   for more details.  */
+void
+ix86_call_abi_override (const_tree fndecl)
+{
+  if (fndecl == NULL_TREE)
+    cfun->machine->call_abi = ix86_abi;
+  else
+    cfun->machine->call_abi = ix86_function_type_abi (TREE_TYPE (fndecl));
+}
+
+/* MS and SYSV ABI have different set of call used registers.  Avoid expensive
+   re-initialization of init_regs each time we switch function context since
+   this is needed only during RTL expansion.  */
+static void
+ix86_maybe_switch_abi (void)
+{
+  if (TARGET_64BIT &&
+      call_used_regs[SI_REG] == (cfun->machine->call_abi == MS_ABI))
+    reinit_regs ();
+}
+
 /* Initialize a variable CUM of type CUMULATIVE_ARGS
    for a call to a function whose data type is FNTYPE.
    For a library call, FNTYPE is 0.  */
@@ -3536,12 +4861,36 @@ init_cumulative_args (CUMULATIVE_ARGS *cum,  /* Argument info to initialize */
   struct cgraph_local_info *i = fndecl ? cgraph_local_info (fndecl) : NULL;
   memset (cum, 0, sizeof (*cum));
 
+  if (fndecl)
+   cum->call_abi = ix86_function_abi (fndecl);
+  else
+   cum->call_abi = ix86_function_type_abi (fntype);
   /* Set up the number of registers to use for passing arguments.  */
+
+  if (cum->call_abi == MS_ABI && !ACCUMULATE_OUTGOING_ARGS)
+    sorry ("ms_abi attribute requires -maccumulate-outgoing-args "
+          "or subtarget optimization implying it");
   cum->nregs = ix86_regparm;
+  if (TARGET_64BIT)
+    {
+      if (cum->call_abi != ix86_abi)
+        cum->nregs = (ix86_abi != SYSV_ABI
+                     ? X86_64_REGPARM_MAX : X86_64_MS_REGPARM_MAX);
+    }
   if (TARGET_SSE)
-    cum->sse_nregs = SSE_REGPARM_MAX;
+    {
+      cum->sse_nregs = SSE_REGPARM_MAX;
+      if (TARGET_64BIT)
+        {
+          if (cum->call_abi != ix86_abi)
+            cum->sse_nregs = (ix86_abi != SYSV_ABI
+                             ? X86_64_SSE_REGPARM_MAX
+                             : X86_64_MS_SSE_REGPARM_MAX);
+        }
+    }
   if (TARGET_MMX)
     cum->mmx_nregs = MMX_REGPARM_MAX;
+  cum->warn_avx = true;
   cum->warn_sse = true;
   cum->warn_mmx = true;
 
@@ -3566,6 +4915,7 @@ init_cumulative_args (CUMULATIVE_ARGS *cum,  /* Argument info to initialize */
          cum->nregs = 0;
          cum->sse_nregs = 0;
          cum->mmx_nregs = 0;
+         cum->warn_avx = 0;
          cum->warn_sse = 0;
          cum->warn_mmx = 0;
          return;
@@ -3598,17 +4948,21 @@ init_cumulative_args (CUMULATIVE_ARGS *cum,  /* Argument info to initialize */
    modes, the generic vector support in gcc will choose some non-vector mode
    in order to implement the type.  By computing the natural mode, we'll
    select the proper ABI location for the operand and not depend on whatever
-   the middle-end decides to do with these vector types.  */
+   the middle-end decides to do with these vector types.
+
+   The midde-end can't deal with the vector types > 16 bytes.  In this
+   case, we return the original mode and warn ABI change if CUM isn't
+   NULL.  */
 
 static enum machine_mode
-type_natural_mode (const_tree type)
+type_natural_mode (const_tree type, CUMULATIVE_ARGS *cum)
 {
   enum machine_mode mode = TYPE_MODE (type);
 
   if (TREE_CODE (type) == VECTOR_TYPE && !VECTOR_MODE_P (mode))
     {
       HOST_WIDE_INT size = int_size_in_bytes (type);
-      if ((size == 8 || size == 16)
+      if ((size == 8 || size == 16 || size == 32)
          /* ??? Generic code allows us to create width 1 vectors.  Ignore.  */
          && TYPE_VECTOR_SUBPARTS (type) > 1)
        {
@@ -3623,7 +4977,24 @@ type_natural_mode (const_tree type)
          for (; mode != VOIDmode; mode = GET_MODE_WIDER_MODE (mode))
            if (GET_MODE_NUNITS (mode) == TYPE_VECTOR_SUBPARTS (type)
                && GET_MODE_INNER (mode) == innermode)
-             return mode;
+             {
+               if (size == 32 && !TARGET_AVX)
+                 {
+                   static bool warnedavx;
+
+                   if (cum
+                       && !warnedavx 
+                       && cum->warn_avx)
+                     {
+                       warnedavx = true;
+                       warning (0, "AVX vector argument without AVX "
+                                "enabled changes the ABI");
+                     }
+                   return TYPE_MODE (type);
+                 }
+               else
+                 return mode;
+             }
 
          gcc_unreachable ();
        }
@@ -3736,8 +5107,8 @@ classify_argument (enum machine_mode mode, const_tree type,
       tree field;
       enum x86_64_reg_class subclasses[MAX_CLASSES];
 
-      /* On x86-64 we pass structures larger than 16 bytes on the stack.  */
-      if (bytes > 16)
+      /* On x86-64 we pass structures larger than 32 bytes on the stack.  */
+      if (bytes > 32)
        return 0;
 
       for (i = 0; i < words; i++)
@@ -3780,19 +5151,40 @@ classify_argument (enum machine_mode mode, const_tree type,
                    }
                  else
                    {
-                     num = classify_argument (TYPE_MODE (TREE_TYPE (field)),
-                                              TREE_TYPE (field), subclasses,
+                     int pos;
+
+                     type = TREE_TYPE (field);
+
+                     /* Flexible array member is ignored.  */
+                     if (TYPE_MODE (type) == BLKmode
+                         && TREE_CODE (type) == ARRAY_TYPE
+                         && TYPE_SIZE (type) == NULL_TREE
+                         && TYPE_DOMAIN (type) != NULL_TREE
+                         && (TYPE_MAX_VALUE (TYPE_DOMAIN (type))
+                             == NULL_TREE))
+                       {
+                         static bool warned;
+                         
+                         if (!warned && warn_psabi)
+                           {
+                             warned = true;
+                             inform (input_location,
+                                     "The ABI of passing struct with"
+                                     " a flexible array member has"
+                                     " changed in GCC 4.4");
+                           }
+                         continue;
+                       }
+                     num = classify_argument (TYPE_MODE (type), type,
+                                              subclasses,
                                               (int_bit_position (field)
                                                + bit_offset) % 256);
                      if (!num)
                        return 0;
-                     for (i = 0; i < num; i++)
-                       {
-                         int pos =
-                           (int_bit_position (field) + (bit_offset % 64)) / 8 / 8;
-                         classes[i + pos] =
-                           merge_classes (subclasses[i], classes[i + pos]);
-                       }
+                     pos = (int_bit_position (field) + (bit_offset % 64)) / 8 / 8;
+                     for (i = 0; i < num && (i + pos) < words; i++)
+                       classes[i + pos] =
+                         merge_classes (subclasses[i], classes[i + pos]);
                    }
                }
            }
@@ -3810,7 +5202,8 @@ classify_argument (enum machine_mode mode, const_tree type,
            /* The partial classes are now full classes.  */
            if (subclasses[0] == X86_64_SSESF_CLASS && bytes != 4)
              subclasses[0] = X86_64_SSE_CLASS;
-           if (subclasses[0] == X86_64_INTEGERSI_CLASS && bytes != 4)
+           if (subclasses[0] == X86_64_INTEGERSI_CLASS
+               && !((bit_offset % 64) == 0 && bytes == 4))
              subclasses[0] = X86_64_INTEGER_CLASS;
 
            for (i = 0; i < words; i++)
@@ -3846,6 +5239,20 @@ classify_argument (enum machine_mode mode, const_tree type,
          gcc_unreachable ();
        }
 
+      if (words > 2)
+       {
+         /* When size > 16 bytes, if the first one isn't
+            X86_64_SSE_CLASS or any other ones aren't
+            X86_64_SSEUP_CLASS, everything should be passed in
+            memory.  */
+         if (classes[0] != X86_64_SSE_CLASS)
+             return 0;
+
+         for (i = 1; i < words; i++)
+           if (classes[i] != X86_64_SSEUP_CLASS)
+             return 0;
+       }
+
       /* Final merger cleanup.  */
       for (i = 0; i < words; i++)
        {
@@ -3855,15 +5262,34 @@ classify_argument (enum machine_mode mode, const_tree type,
            return 0;
 
          /* The X86_64_SSEUP_CLASS should be always preceded by
-            X86_64_SSE_CLASS.  */
+            X86_64_SSE_CLASS or X86_64_SSEUP_CLASS.  */
          if (classes[i] == X86_64_SSEUP_CLASS
-             && (i == 0 || classes[i - 1] != X86_64_SSE_CLASS))
-           classes[i] = X86_64_SSE_CLASS;
+             && classes[i - 1] != X86_64_SSE_CLASS
+             && classes[i - 1] != X86_64_SSEUP_CLASS)
+           {
+             /* The first one should never be X86_64_SSEUP_CLASS.  */
+             gcc_assert (i != 0);
+             classes[i] = X86_64_SSE_CLASS;
+           }
 
-         /*  X86_64_X87UP_CLASS should be preceded by X86_64_X87_CLASS.  */
+         /*  If X86_64_X87UP_CLASS isn't preceded by X86_64_X87_CLASS,
+              everything should be passed in memory.  */
          if (classes[i] == X86_64_X87UP_CLASS
-             && (i == 0 || classes[i - 1] != X86_64_X87_CLASS))
-           classes[i] = X86_64_SSE_CLASS;
+             && (classes[i - 1] != X86_64_X87_CLASS))
+           {
+             static bool warned;
+
+             /* The first one should never be X86_64_X87UP_CLASS.  */
+             gcc_assert (i != 0);
+             if (!warned && warn_psabi)
+               {
+                 warned = true;
+                 inform (input_location,
+                         "The ABI of passing union with long double"
+                         " has changed in GCC 4.4");
+               }
+             return 0;
+           }
        }
       return words;
     }
@@ -3908,15 +5334,41 @@ classify_argument (enum machine_mode mode, const_tree type,
     case CSImode:
     case CHImode:
     case CQImode:
-      if (bit_offset + GET_MODE_BITSIZE (mode) <= 32)
-       classes[0] = X86_64_INTEGERSI_CLASS;
-      else
-       classes[0] = X86_64_INTEGER_CLASS;
-      return 1;
+      {
+       int size = (bit_offset % 64)+ (int) GET_MODE_BITSIZE (mode);
+
+       if (size <= 32)
+         {
+           classes[0] = X86_64_INTEGERSI_CLASS;
+           return 1;
+         }
+       else if (size <= 64)
+         {
+           classes[0] = X86_64_INTEGER_CLASS;
+           return 1;
+         }
+       else if (size <= 64+32)
+         {
+           classes[0] = X86_64_INTEGER_CLASS;
+           classes[1] = X86_64_INTEGERSI_CLASS;
+           return 2;
+         }
+       else if (size <= 64+64)
+         {
+           classes[0] = classes[1] = X86_64_INTEGER_CLASS;
+           return 2;
+         }
+       else
+         gcc_unreachable ();
+      }
     case CDImode:
     case TImode:
       classes[0] = classes[1] = X86_64_INTEGER_CLASS;
       return 2;
+    case COImode:
+    case OImode:
+      /* OImode shouldn't be used directly.  */
+      gcc_unreachable ();
     case CTImode:
       return 0;
     case SFmode:
@@ -3938,7 +5390,22 @@ classify_argument (enum machine_mode mode, const_tree type,
       return 2;
     case SCmode:
       classes[0] = X86_64_SSE_CLASS;
-      return 1;
+      if (!(bit_offset % 64))
+       return 1;
+      else
+       {
+         static bool warned;
+
+         if (!warned && warn_psabi)
+           {
+             warned = true;
+             inform (input_location,
+                     "The ABI of passing structure with complex float"
+                     " member has changed in GCC 4.4");
+           }
+         classes[1] = X86_64_SSESF_CLASS;
+         return 2;
+       }
     case DCmode:
       classes[0] = X86_64_SSEDF_CLASS;
       classes[1] = X86_64_SSEDF_CLASS;
@@ -3949,6 +5416,17 @@ classify_argument (enum machine_mode mode, const_tree type,
     case TCmode:
       /* This modes is larger than 16 bytes.  */
       return 0;
+    case V8SFmode:
+    case V8SImode:
+    case V32QImode:
+    case V16HImode:
+    case V4DFmode:
+    case V4DImode:
+      classes[0] = X86_64_SSE_CLASS;
+      classes[1] = X86_64_SSEUP_CLASS;
+      classes[2] = X86_64_SSEUP_CLASS;
+      classes[3] = X86_64_SSEUP_CLASS;
+      return 4;
     case V4SFmode:
     case V4SImode:
     case V16QImode:
@@ -4106,7 +5584,10 @@ construct_container (enum machine_mode mode, enum machine_mode orig_mode,
       case X86_64_SSE_CLASS:
       case X86_64_SSESF_CLASS:
       case X86_64_SSEDF_CLASS:
-       return gen_reg_or_parallel (mode, orig_mode, SSE_REGNO (sse_regno));
+       if (mode != BLKmode)
+         return gen_reg_or_parallel (mode, orig_mode, 
+                                     SSE_REGNO (sse_regno));
+       break;
       case X86_64_X87_CLASS:
       case X86_64_COMPLEX_X87_CLASS:
        return gen_rtx_REG (mode, FIRST_STACK_REG);
@@ -4119,6 +5600,13 @@ construct_container (enum machine_mode mode, enum machine_mode orig_mode,
   if (n == 2 && regclass[0] == X86_64_SSE_CLASS
       && regclass[1] == X86_64_SSEUP_CLASS && mode != BLKmode)
     return gen_rtx_REG (mode, SSE_REGNO (sse_regno));
+  if (n == 4
+      && regclass[0] == X86_64_SSE_CLASS
+      && regclass[1] == X86_64_SSEUP_CLASS
+      && regclass[2] == X86_64_SSEUP_CLASS
+      && regclass[3] == X86_64_SSEUP_CLASS
+      && mode != BLKmode)
+    return gen_rtx_REG (mode, SSE_REGNO (sse_regno));
 
   if (n == 2
       && regclass[0] == X86_64_X87_CLASS && regclass[1] == X86_64_X87UP_CLASS)
@@ -4132,6 +5620,8 @@ construct_container (enum machine_mode mode, enum machine_mode orig_mode,
   /* Otherwise figure out the entries of the PARALLEL.  */
   for (i = 0; i < n; i++)
     {
+      int pos;
+
       switch (regclass[i])
         {
          case X86_64_NO_CLASS:
@@ -4168,16 +5658,36 @@ construct_container (enum machine_mode mode, enum machine_mode orig_mode,
            sse_regno++;
            break;
          case X86_64_SSE_CLASS:
-           if (i < n - 1 && regclass[i + 1] == X86_64_SSEUP_CLASS)
-             tmpmode = TImode;
-           else
-             tmpmode = DImode;
+           pos = i;
+           switch (n)
+             {
+             case 1:
+               tmpmode = DImode;
+               break;
+             case 2:
+               if (i == 0 && regclass[1] == X86_64_SSEUP_CLASS)
+                 {
+                   tmpmode = TImode;
+                   i++;
+                 }
+               else
+                 tmpmode = DImode;
+               break;
+             case 4:
+               gcc_assert (i == 0
+                           && regclass[1] == X86_64_SSEUP_CLASS
+                           && regclass[2] == X86_64_SSEUP_CLASS
+                           && regclass[3] == X86_64_SSEUP_CLASS);
+               tmpmode = OImode;
+               i += 3;
+               break;
+             default:
+               gcc_unreachable ();
+             }
            exp [nexps++] = gen_rtx_EXPR_LIST (VOIDmode,
                                               gen_rtx_REG (tmpmode,
                                                            SSE_REGNO (sse_regno)),
-                                              GEN_INT (i*8));
-           if (tmpmode == TImode)
-             i++;
+                                              GEN_INT (pos*8));
            sse_regno++;
            break;
          default:
@@ -4228,6 +5738,10 @@ function_arg_advance_32 (CUMULATIVE_ARGS *cum, enum machine_mode mode,
        }
       break;
 
+    case OImode:
+      /* OImode shouldn't be used directly.  */
+      gcc_unreachable ();
+
     case DFmode:
       if (cum->float_in_sse < 2)
        break;
@@ -4236,6 +5750,12 @@ function_arg_advance_32 (CUMULATIVE_ARGS *cum, enum machine_mode mode,
        break;
       /* FALLTHRU */
 
+    case V8SFmode:
+    case V8SImode:
+    case V32QImode:
+    case V16HImode:
+    case V4DFmode:
+    case V4DImode:
     case TImode:
     case V16QImode:
     case V8HImode:
@@ -4278,10 +5798,14 @@ function_arg_advance_32 (CUMULATIVE_ARGS *cum, enum machine_mode mode,
 
 static void
 function_arg_advance_64 (CUMULATIVE_ARGS *cum, enum machine_mode mode,
-                        tree type, HOST_WIDE_INT words)
+                        tree type, HOST_WIDE_INT words, int named)
 {
   int int_nregs, sse_nregs;
 
+  /* Unnamed 256bit vector mode parameters are passed on stack.  */
+  if (!named && VALID_AVX256_REG_MODE (mode))
+    return;
+
   if (!examine_argument (mode, type, 0, &int_nregs, &sse_nregs))
     cum->words += words;
   else if (sse_nregs <= cum->sse_nregs && int_nregs <= cum->nregs)
@@ -4312,7 +5836,7 @@ function_arg_advance_ms_64 (CUMULATIVE_ARGS *cum, HOST_WIDE_INT bytes,
 
 void
 function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
-                     tree type, int named ATTRIBUTE_UNUSED)
+                     tree type, int named)
 {
   HOST_WIDE_INT bytes, words;
 
@@ -4323,12 +5847,12 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
   words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
 
   if (type)
-    mode = type_natural_mode (type);
+    mode = type_natural_mode (type, NULL);
 
-  if (TARGET_64BIT_MS_ABI)
+  if (TARGET_64BIT && (cum ? cum->call_abi : ix86_abi) == MS_ABI)
     function_arg_advance_ms_64 (cum, bytes, words);
   else if (TARGET_64BIT)
-    function_arg_advance_64 (cum, mode, type, words);
+    function_arg_advance_64 (cum, mode, type, words, named);
   else
     function_arg_advance_32 (cum, mode, type, bytes, words);
 }
@@ -4400,6 +5924,7 @@ function_arg_32 (CUMULATIVE_ARGS *cum, enum machine_mode mode,
        break;
       /* FALLTHRU */
     case TImode:
+      /* In 32bit, we pass TImode in xmm registers.  */
     case V16QImode:
     case V8HImode:
     case V4SImode:
@@ -4420,6 +5945,24 @@ function_arg_32 (CUMULATIVE_ARGS *cum, enum machine_mode mode,
        }
       break;
 
+    case OImode:
+      /* OImode shouldn't be used directly.  */
+      gcc_unreachable ();
+
+    case V8SFmode:
+    case V8SImode:
+    case V32QImode:
+    case V16HImode:
+    case V4DFmode:
+    case V4DImode:
+      if (!type || !AGGREGATE_TYPE_P (type))
+       {
+         if (cum->sse_nregs)
+           return gen_reg_or_parallel (mode, orig_mode,
+                                       cum->sse_regno + FIRST_SSE_REG);
+       }
+      break;
+
     case V8QImode:
     case V4HImode:
     case V2SImode:
@@ -4445,17 +5988,38 @@ function_arg_32 (CUMULATIVE_ARGS *cum, enum machine_mode mode,
 
 static rtx
 function_arg_64 (CUMULATIVE_ARGS *cum, enum machine_mode mode,
-                enum machine_mode orig_mode, tree type)
+                enum machine_mode orig_mode, tree type, int named)
 {
   /* Handle a hidden AL argument containing number of registers
      for varargs x86-64 functions.  */
   if (mode == VOIDmode)
     return GEN_INT (cum->maybe_vaarg
                    ? (cum->sse_nregs < 0
-                      ? SSE_REGPARM_MAX
+                      ? (cum->call_abi == ix86_abi
+                         ? SSE_REGPARM_MAX
+                         : (ix86_abi != SYSV_ABI
+                            ? X86_64_SSE_REGPARM_MAX
+                            : X86_64_MS_SSE_REGPARM_MAX))
                       : cum->sse_regno)
                    : -1);
 
+  switch (mode)
+    {
+    default:
+      break;
+
+    case V8SFmode:
+    case V8SImode:
+    case V32QImode:
+    case V16HImode:
+    case V4DFmode:
+    case V4DImode:
+      /* Unnamed 256bit vector mode parameters are passed on stack.  */
+      if (!named)
+       return NULL;
+      break;
+    }
+
   return construct_container (mode, orig_mode, type, 0, cum->nregs,
                              cum->sse_nregs,
                              &x86_64_int_parameter_registers [cum->regno],
@@ -4469,9 +6033,10 @@ function_arg_ms_64 (CUMULATIVE_ARGS *cum, enum machine_mode mode,
 {
   unsigned int regno;
 
-  /* Avoid the AL settings for the Unix64 ABI.  */
+  /* We need to add clobber for MS_ABI->SYSV ABI calls in expand_call.
+     We use value of -2 to specify that current function call is MSABI.  */
   if (mode == VOIDmode)
-    return constm1_rtx;
+    return GEN_INT (-2);
 
   /* If we've run out of registers, it goes on the stack.  */
   if (cum->nregs == 0)
@@ -4525,12 +6090,12 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode omode,
   /* To simplify the code below, represent vector types with a vector mode
      even if MMX/SSE are not active.  */
   if (type && TREE_CODE (type) == VECTOR_TYPE)
-    mode = type_natural_mode (type);
+    mode = type_natural_mode (type, cum);
 
-  if (TARGET_64BIT_MS_ABI)
+  if (TARGET_64BIT && (cum ? cum->call_abi : ix86_abi) == MS_ABI)
     return function_arg_ms_64 (cum, mode, omode, named, bytes);
   else if (TARGET_64BIT)
-    return function_arg_64 (cum, mode, omode, type);
+    return function_arg_64 (cum, mode, omode, type, named);
   else
     return function_arg_32 (cum, mode, omode, type, bytes, words);
 }
@@ -4547,7 +6112,7 @@ ix86_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
                        const_tree type, bool named ATTRIBUTE_UNUSED)
 {
   /* See Windows x64 Software Convention.  */
-  if (TARGET_64BIT_MS_ABI)
+  if (TARGET_64BIT && (cum ? cum->call_abi : ix86_abi) == MS_ABI)
     {
       int msize = (int) GET_MODE_SIZE (mode);
       if (type)
@@ -4584,7 +6149,10 @@ static bool
 contains_aligned_value_p (tree type)
 {
   enum machine_mode mode = TYPE_MODE (type);
-  if (((TARGET_SSE && SSE_REG_MODE_P (mode)) || mode == TDmode)
+  if (((TARGET_SSE && SSE_REG_MODE_P (mode))
+       || mode == TDmode
+       || mode == TFmode
+       || mode == TCmode)
       && (!TYPE_USER_ALIGN (type) || TYPE_ALIGN (type) > 128))
     return true;
   if (TYPE_ALIGN (type) < 128)
@@ -4632,13 +6200,20 @@ ix86_function_arg_boundary (enum machine_mode mode, tree type)
 {
   int align;
   if (type)
-    align = TYPE_ALIGN (type);
+    {
+      /* Since canonical type is used for call, we convert it to
+        canonical type if needed.  */
+      if (!TYPE_STRUCTURAL_EQUALITY_P (type))
+       type = TYPE_CANONICAL (type);
+      align = TYPE_ALIGN (type);
+    }
   else
     align = GET_MODE_ALIGNMENT (mode);
   if (align < PARM_BOUNDARY)
     align = PARM_BOUNDARY;
-  /* In 32bit, only _Decimal128 is aligned to its natural boundary.  */
-  if (!TARGET_64BIT && mode != TDmode)
+  /* In 32bit, only _Decimal128 and __float128 are aligned to their
+     natural boundaries.  */
+  if (!TARGET_64BIT && mode != TDmode && mode != TFmode)
     {
       /* i386 ABI defines all arguments to be 4 byte aligned.  We have to
         make an exception for SSE modes since these require 128bit
@@ -4649,7 +6224,7 @@ ix86_function_arg_boundary (enum machine_mode mode, tree type)
         to 8 byte boundaries.  */
       if (!type)
        {
-         if (!(TARGET_SSE && SSE_REG_MODE_P (mode)) && mode != TDmode)
+         if (!(TARGET_SSE && SSE_REG_MODE_P (mode)))
            align = PARM_BOUNDARY;
        }
       else
@@ -4674,7 +6249,10 @@ ix86_function_value_regno_p (int regno)
       return true;
 
     case FIRST_FLOAT_REG:
-      if (TARGET_64BIT_MS_ABI)
+      /* TODO: The function should depend on current function ABI but
+       builtins.c would need updating then. Therefore we use the
+       default ABI.  */
+      if (TARGET_64BIT && ix86_abi == MS_ABI)
        return false;
       return TARGET_FLOAT_RETURNS_IN_80387;
 
@@ -4714,6 +6292,10 @@ function_value_32 (enum machine_mode orig_mode, enum machine_mode mode,
           || (VECTOR_MODE_P (mode) && GET_MODE_SIZE (mode) == 16))
     regno = TARGET_SSE ? FIRST_SSE_REG : 0;
 
+  /* 32-byte vector modes in %ymm0.   */
+  else if (VECTOR_MODE_P (mode) && GET_MODE_SIZE (mode) == 32)
+    regno = TARGET_AVX ? FIRST_SSE_REG : 0;
+
   /* Floating point return values in %st(0) (unless -mno-fp-ret-in-387).  */
   else if (X87_FLOAT_MODE_P (mode) && TARGET_FLOAT_RETURNS_IN_80387)
     regno = FIRST_FLOAT_REG;
@@ -4731,6 +6313,9 @@ function_value_32 (enum machine_mode orig_mode, enum machine_mode mode,
        regno = FIRST_SSE_REG;
     }
 
+  /* OImode shouldn't be used directly.  */
+  gcc_assert (mode != OImode);
+
   return gen_rtx_REG (orig_mode, regno);
 }
 
@@ -4765,7 +6350,7 @@ function_value_64 (enum machine_mode orig_mode, enum machine_mode mode,
     }
 
   ret = construct_container (mode, orig_mode, valtype, 1,
-                            REGPARM_MAX, SSE_REGPARM_MAX,
+                            X86_64_REGPARM_MAX, X86_64_SSE_REGPARM_MAX,
                             x86_64_int_return_registers, 0);
 
   /* For zero sized structures, construct_container returns NULL, but we
@@ -4813,7 +6398,7 @@ ix86_function_value_1 (const_tree valtype, const_tree fntype_or_decl,
     fn = fntype_or_decl;
   fntype = fn ? TREE_TYPE (fn) : fntype_or_decl;
 
-  if (TARGET_64BIT_MS_ABI)
+  if (TARGET_64BIT && ix86_function_type_abi (fntype) == MS_ABI)
     return function_value_ms_64 (orig_mode, mode);
   else if (TARGET_64BIT)
     return function_value_64 (orig_mode, mode, valtype);
@@ -4828,7 +6413,7 @@ ix86_function_value (const_tree valtype, const_tree fntype_or_decl,
   enum machine_mode mode, orig_mode;
 
   orig_mode = TYPE_MODE (valtype);
-  mode = type_natural_mode (valtype);
+  mode = type_natural_mode (valtype, NULL);
   return ix86_function_value_1 (valtype, fntype_or_decl, orig_mode, mode);
 }
 
@@ -4840,7 +6425,7 @@ ix86_libcall_value (enum machine_mode mode)
 
 /* Return true iff type is returned in memory.  */
 
-static int
+static int ATTRIBUTE_UNUSED
 return_in_memory_32 (const_tree type, enum machine_mode mode)
 {
   HOST_WIDE_INT size;
@@ -4867,27 +6452,32 @@ return_in_memory_32 (const_tree type, enum machine_mode mode)
       /* SSE values are returned in XMM0, except when it doesn't exist.  */
       if (size == 16)
        return (TARGET_SSE ? 0 : 1);
+
+      /* AVX values are returned in YMM0, except when it doesn't exist.  */
+      if (size == 32)
+       return TARGET_AVX ? 0 : 1;
     }
 
   if (mode == XFmode)
     return 0;
 
-  if (mode == TDmode)
-    return 1;
-
   if (size > 12)
     return 1;
+
+  /* OImode shouldn't be used directly.  */
+  gcc_assert (mode != OImode);
+
   return 0;
 }
 
-static int
+static int ATTRIBUTE_UNUSED
 return_in_memory_64 (const_tree type, enum machine_mode mode)
 {
   int needed_intregs, needed_sseregs;
   return !examine_argument (mode, type, 1, &needed_intregs, &needed_sseregs);
 }
 
-static int
+static int ATTRIBUTE_UNUSED
 return_in_memory_ms_64 (const_tree type, enum machine_mode mode)
 {
   HOST_WIDE_INT size = int_size_in_bytes (type);
@@ -4901,17 +6491,24 @@ return_in_memory_ms_64 (const_tree type, enum machine_mode mode)
   return (size != 1 && size != 2 && size != 4 && size != 8);
 }
 
-bool
+static bool
 ix86_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
 {
-  const enum machine_mode mode = type_natural_mode (type);
-
-  if (TARGET_64BIT_MS_ABI)
-    return return_in_memory_ms_64 (type, mode);
-  else if (TARGET_64BIT)
-    return return_in_memory_64 (type, mode);
+#ifdef SUBTARGET_RETURN_IN_MEMORY
+  return SUBTARGET_RETURN_IN_MEMORY (type, fntype);
+#else
+  const enum machine_mode mode = type_natural_mode (type, NULL);
+  if (TARGET_64BIT)
+    {
+      if (ix86_function_type_abi (fntype) == MS_ABI)
+       return return_in_memory_ms_64 (type, mode);
+      else
+       return return_in_memory_64 (type, mode);
+    }
   else
     return return_in_memory_32 (type, mode);
+#endif
 }
 
 /* Return false iff TYPE is returned in memory.  This version is used
@@ -4923,7 +6520,7 @@ bool
 ix86_sol10_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
 {
   int size;
-  enum machine_mode mode = type_natural_mode (type);
+  enum machine_mode mode = type_natural_mode (type, NULL);
 
   if (TARGET_64BIT)
     return return_in_memory_64 (type, mode);
@@ -4951,20 +6548,6 @@ ix86_sol10_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED
   return size > 12;
 }
 
-bool
-ix86_i386elf_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
-{
-  return (TYPE_MODE (type) == BLKmode
-         || (VECTOR_MODE_P (TYPE_MODE (type)) && int_size_in_bytes (type) == 8));
-}
-
-bool
-ix86_i386interix_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
-{
-  return (TYPE_MODE (type) == BLKmode
-          || (AGGREGATE_TYPE_P (type) && int_size_in_bytes(type) > 8 ));
-}
-
 /* When returning SSE vector types, we have a choice of either
      (1) being abi incompatible with a -march switch, or
      (2) generating an error.
@@ -5014,25 +6597,33 @@ ix86_struct_value_rtx (tree type, int incoming ATTRIBUTE_UNUSED)
 \f
 /* Create the va_list data type.  */
 
+/* Returns the calling convention specific va_list date type.
+   The argument ABI can be DEFAULT_ABI, MS_ABI, or SYSV_ABI.  */
+
 static tree
-ix86_build_builtin_va_list (void)
+ix86_build_builtin_va_list_abi (enum calling_abi abi)
 {
   tree f_gpr, f_fpr, f_ovf, f_sav, record, type_decl;
 
   /* For i386 we use plain pointer to argument area.  */
-  if (!TARGET_64BIT || TARGET_64BIT_MS_ABI)
+  if (!TARGET_64BIT || abi == MS_ABI)
     return build_pointer_type (char_type_node);
 
   record = (*lang_hooks.types.make_type) (RECORD_TYPE);
-  type_decl = build_decl (TYPE_DECL, get_identifier ("__va_list_tag"), record);
+  type_decl = build_decl (BUILTINS_LOCATION,
+                         TYPE_DECL, get_identifier ("__va_list_tag"), record);
 
-  f_gpr = build_decl (FIELD_DECL, get_identifier ("gp_offset"),
+  f_gpr = build_decl (BUILTINS_LOCATION,
+                     FIELD_DECL, get_identifier ("gp_offset"),
                      unsigned_type_node);
-  f_fpr = build_decl (FIELD_DECL, get_identifier ("fp_offset"),
+  f_fpr = build_decl (BUILTINS_LOCATION,
+                     FIELD_DECL, get_identifier ("fp_offset"),
                      unsigned_type_node);
-  f_ovf = build_decl (FIELD_DECL, get_identifier ("overflow_arg_area"),
+  f_ovf = build_decl (BUILTINS_LOCATION,
+                     FIELD_DECL, get_identifier ("overflow_arg_area"),
                      ptr_type_node);
-  f_sav = build_decl (FIELD_DECL, get_identifier ("reg_save_area"),
+  f_sav = build_decl (BUILTINS_LOCATION,
+                     FIELD_DECL, get_identifier ("reg_save_area"),
                      ptr_type_node);
 
   va_list_gpr_counter_field = f_gpr;
@@ -5056,6 +6647,51 @@ ix86_build_builtin_va_list (void)
   return build_array_type (record, build_index_type (size_zero_node));
 }
 
+/* Setup the builtin va_list data type and for 64-bit the additional
+   calling convention specific va_list data types.  */
+
+static tree
+ix86_build_builtin_va_list (void)
+{
+  tree ret = ix86_build_builtin_va_list_abi (ix86_abi);
+
+  /* Initialize abi specific va_list builtin types.  */
+  if (TARGET_64BIT)
+    {
+      tree t;
+      if (ix86_abi == MS_ABI)
+        {
+          t = ix86_build_builtin_va_list_abi (SYSV_ABI);
+          if (TREE_CODE (t) != RECORD_TYPE)
+            t = build_variant_type_copy (t);
+          sysv_va_list_type_node = t;
+        }
+      else
+        {
+          t = ret;
+          if (TREE_CODE (t) != RECORD_TYPE)
+            t = build_variant_type_copy (t);
+          sysv_va_list_type_node = t;
+        }
+      if (ix86_abi != MS_ABI)
+        {
+          t = ix86_build_builtin_va_list_abi (MS_ABI);
+          if (TREE_CODE (t) != RECORD_TYPE)
+            t = build_variant_type_copy (t);
+          ms_va_list_type_node = t;
+        }
+      else
+        {
+          t = ret;
+          if (TREE_CODE (t) != RECORD_TYPE)
+            t = build_variant_type_copy (t);
+          ms_va_list_type_node = t;
+        }
+    }
+
+  return ret;
+}
+
 /* Worker function for TARGET_SETUP_INCOMING_VARARGS.  */
 
 static void
@@ -5068,26 +6704,33 @@ setup_incoming_varargs_64 (CUMULATIVE_ARGS *cum)
   rtx nsse_reg;
   alias_set_type set;
   int i;
+  int regparm = ix86_regparm;
 
-  if (! cfun->va_list_gpr_size && ! cfun->va_list_fpr_size)
-    return;
+  if (cum->call_abi != ix86_abi)
+    regparm = (ix86_abi != SYSV_ABI
+              ? X86_64_REGPARM_MAX : X86_64_MS_REGPARM_MAX);
+
+  /* GPR size of varargs save area.  */
+  if (cfun->va_list_gpr_size)
+    ix86_varargs_gpr_size = X86_64_REGPARM_MAX * UNITS_PER_WORD;
+  else
+    ix86_varargs_gpr_size = 0;
 
-  /* Indicate to allocate space on the stack for varargs save area.  */
-  ix86_save_varrargs_registers = 1;
-  /* We need 16-byte stack alignment to save SSE registers.  If user
-     asked for lower preferred_stack_boundary, lets just hope that he knows
-     what he is doing and won't varargs SSE values.
+  /* FPR size of varargs save area.  We don't need it if we don't pass
+     anything in SSE registers.  */
+  if (cum->sse_nregs && cfun->va_list_fpr_size)
+    ix86_varargs_fpr_size = X86_64_SSE_REGPARM_MAX * 16;
+  else
+    ix86_varargs_fpr_size = 0;
 
-     We also may end up assuming that only 64bit values are stored in SSE
-     register let some floating point program work.  */
-  if (ix86_preferred_stack_boundary >= BIGGEST_ALIGNMENT)
-    crtl->stack_alignment_needed = BIGGEST_ALIGNMENT;
+  if (! ix86_varargs_gpr_size && ! ix86_varargs_fpr_size)
+    return;
 
   save_area = frame_pointer_rtx;
   set = get_varargs_alias_set ();
 
   for (i = cum->regno;
-       i < ix86_regparm
+       i < regparm
        && i < cum->regno + cfun->va_list_gpr_size / UNITS_PER_WORD;
        i++)
     {
@@ -5099,7 +6742,7 @@ setup_incoming_varargs_64 (CUMULATIVE_ARGS *cum)
                                        x86_64_int_parameter_registers[i]));
     }
 
-  if (cum->sse_nregs && cfun->va_list_fpr_size)
+  if (ix86_varargs_fpr_size)
     {
       /* Now emit code to save SSE registers.  The AX parameter contains number
         of SSE parameter registers used to call this function.  We use
@@ -5110,31 +6753,41 @@ setup_incoming_varargs_64 (CUMULATIVE_ARGS *cum)
       label_ref = gen_rtx_LABEL_REF (Pmode, label);
 
       /* Compute address to jump to :
-         label - 5*eax + nnamed_sse_arguments*5  */
+         label - eax*4 + nnamed_sse_arguments*4 Or
+         label - eax*5 + nnamed_sse_arguments*5 for AVX.  */
       tmp_reg = gen_reg_rtx (Pmode);
       nsse_reg = gen_reg_rtx (Pmode);
       emit_insn (gen_zero_extendqidi2 (nsse_reg, gen_rtx_REG (QImode, AX_REG)));
       emit_insn (gen_rtx_SET (VOIDmode, tmp_reg,
                              gen_rtx_MULT (Pmode, nsse_reg,
                                            GEN_INT (4))));
+
+      /* vmovaps is one byte longer than movaps.  */
+      if (TARGET_AVX)
+       emit_insn (gen_rtx_SET (VOIDmode, tmp_reg,
+                               gen_rtx_PLUS (Pmode, tmp_reg,
+                                             nsse_reg)));
+
       if (cum->sse_regno)
        emit_move_insn
          (nsse_reg,
           gen_rtx_CONST (DImode,
                          gen_rtx_PLUS (DImode,
                                        label_ref,
-                                       GEN_INT (cum->sse_regno * 4))));
+                                       GEN_INT (cum->sse_regno
+                                                * (TARGET_AVX ? 5 : 4)))));
       else
        emit_move_insn (nsse_reg, label_ref);
       emit_insn (gen_subdi3 (nsse_reg, nsse_reg, tmp_reg));
 
       /* Compute address of memory block we save into.  We always use pointer
         pointing 127 bytes after first byte to store - this is needed to keep
-        instruction size limited by 4 bytes.  */
+        instruction size limited by 4 bytes (5 bytes for AVX) with one
+        byte displacement.  */
       tmp_reg = gen_reg_rtx (Pmode);
       emit_insn (gen_rtx_SET (VOIDmode, tmp_reg,
                              plus_constant (save_area,
-                                            8 * REGPARM_MAX + 127)));
+                                            ix86_varargs_gpr_size + 127)));
       mem = gen_rtx_MEM (BLKmode, plus_constant (tmp_reg, -127));
       MEM_NOTRAP_P (mem) = 1;
       set_mem_alias_set (mem, set);
@@ -5152,7 +6805,7 @@ setup_incoming_varargs_ms_64 (CUMULATIVE_ARGS *cum)
   alias_set_type set = get_varargs_alias_set ();
   int i;
 
-  for (i = cum->regno; i < REGPARM_MAX; i++)
+  for (i = cum->regno; i < X86_64_MS_REGPARM_MAX; i++)
     {
       rtx reg, mem;
 
@@ -5190,12 +6843,27 @@ ix86_setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
   if (stdarg_p (fntype))
     function_arg_advance (&next_cum, mode, type, 1);
 
-  if (TARGET_64BIT_MS_ABI)
+  if (cum->call_abi == MS_ABI)
     setup_incoming_varargs_ms_64 (&next_cum);
   else
     setup_incoming_varargs_64 (&next_cum);
 }
 
+/* Checks if TYPE is of kind va_list char *.  */
+
+static bool
+is_va_list_char_pointer (tree type)
+{
+  tree canonic;
+
+  /* For 32-bit it is always true.  */
+  if (!TARGET_64BIT)
+    return true;
+  canonic = ix86_canonical_va_list_type (type);
+  return (canonic == ms_va_list_type_node
+          || (ix86_abi == MS_ABI && canonic == va_list_type_node));
+}
+
 /* Implement va_start.  */
 
 static void
@@ -5207,13 +6875,13 @@ ix86_va_start (tree valist, rtx nextarg)
   tree type;
 
   /* Only 64bit target needs something special.  */
-  if (!TARGET_64BIT || TARGET_64BIT_MS_ABI)
+  if (!TARGET_64BIT || is_va_list_char_pointer (TREE_TYPE (valist)))
     {
       std_expand_builtin_va_start (valist, nextarg);
       return;
     }
 
-  f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
+  f_gpr = TYPE_FIELDS (TREE_TYPE (sysv_va_list_type_node));
   f_fpr = TREE_CHAIN (f_gpr);
   f_ovf = TREE_CHAIN (f_fpr);
   f_sav = TREE_CHAIN (f_ovf);
@@ -5232,38 +6900,41 @@ ix86_va_start (tree valist, rtx nextarg)
   if (cfun->va_list_gpr_size)
     {
       type = TREE_TYPE (gpr);
-      t = build2 (GIMPLE_MODIFY_STMT, type, gpr,
-                 build_int_cst (type, n_gpr * 8));
+      t = build2 (MODIFY_EXPR, type,
+                 gpr, build_int_cst (type, n_gpr * 8));
       TREE_SIDE_EFFECTS (t) = 1;
       expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
     }
 
-  if (cfun->va_list_fpr_size)
+  if (TARGET_SSE && cfun->va_list_fpr_size)
     {
       type = TREE_TYPE (fpr);
-      t = build2 (GIMPLE_MODIFY_STMT, type, fpr,
-                 build_int_cst (type, n_fpr * 16 + 8*REGPARM_MAX));
+      t = build2 (MODIFY_EXPR, type, fpr,
+                 build_int_cst (type, n_fpr * 16 + 8*X86_64_REGPARM_MAX));
       TREE_SIDE_EFFECTS (t) = 1;
       expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
     }
 
   /* Find the overflow area.  */
   type = TREE_TYPE (ovf);
-  t = make_tree (type, virtual_incoming_args_rtx);
+  t = make_tree (type, crtl->args.internal_arg_pointer);
   if (words != 0)
     t = build2 (POINTER_PLUS_EXPR, type, t,
                size_int (words * UNITS_PER_WORD));
-  t = build2 (GIMPLE_MODIFY_STMT, type, ovf, t);
+  t = build2 (MODIFY_EXPR, type, ovf, t);
   TREE_SIDE_EFFECTS (t) = 1;
   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
 
-  if (cfun->va_list_gpr_size || cfun->va_list_fpr_size)
+  if (ix86_varargs_gpr_size || ix86_varargs_fpr_size)
     {
       /* Find the register save area.
         Prologue of the function save it right above stack frame.  */
       type = TREE_TYPE (sav);
       t = make_tree (type, frame_pointer_rtx);
-      t = build2 (GIMPLE_MODIFY_STMT, type, sav, t);
+      if (!ix86_varargs_gpr_size)
+       t = build2 (POINTER_PLUS_EXPR, type, t,
+                   size_int (-8 * X86_64_REGPARM_MAX));
+      t = build2 (MODIFY_EXPR, type, sav, t);
       TREE_SIDE_EFFECTS (t) = 1;
       expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
     }
@@ -5272,7 +6943,8 @@ ix86_va_start (tree valist, rtx nextarg)
 /* Implement va_arg.  */
 
 static tree
-ix86_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
+ix86_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p,
+                     gimple_seq *post_p)
 {
   static const int intreg[6] = { 0, 1, 2, 3, 4, 5 };
   tree f_gpr, f_fpr, f_ovf, f_sav;
@@ -5284,18 +6956,20 @@ ix86_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
   int indirect_p = 0;
   tree ptrtype;
   enum machine_mode nat_mode;
+  int arg_boundary;
 
   /* Only 64bit target needs something special.  */
-  if (!TARGET_64BIT || TARGET_64BIT_MS_ABI)
+  if (!TARGET_64BIT || is_va_list_char_pointer (TREE_TYPE (valist)))
     return std_gimplify_va_arg_expr (valist, type, pre_p, post_p);
 
-  f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
+  f_gpr = TYPE_FIELDS (TREE_TYPE (sysv_va_list_type_node));
   f_fpr = TREE_CHAIN (f_gpr);
   f_ovf = TREE_CHAIN (f_fpr);
   f_sav = TREE_CHAIN (f_ovf);
 
+  gpr = build3 (COMPONENT_REF, TREE_TYPE (f_gpr),
+               build_va_arg_indirect_ref (valist), f_gpr, NULL_TREE);
   valist = build_va_arg_indirect_ref (valist);
-  gpr = build3 (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr, NULL_TREE);
   fpr = build3 (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr, NULL_TREE);
   ovf = build3 (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf, NULL_TREE);
   sav = build3 (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav, NULL_TREE);
@@ -5306,14 +6980,33 @@ ix86_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
   size = int_size_in_bytes (type);
   rsize = (size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
 
-  nat_mode = type_natural_mode (type);
-  container = construct_container (nat_mode, TYPE_MODE (type), type, 0,
-                                  REGPARM_MAX, SSE_REGPARM_MAX, intreg, 0);
+  nat_mode = type_natural_mode (type, NULL);
+  switch (nat_mode)
+    {
+    case V8SFmode:
+    case V8SImode:
+    case V32QImode:
+    case V16HImode:
+    case V4DFmode:
+    case V4DImode:
+      /* Unnamed 256bit vector mode parameters are passed on stack.  */
+      if (ix86_cfun_abi () == SYSV_ABI)
+       {
+         container = NULL;
+         break;
+       }
+
+    default:
+      container = construct_container (nat_mode, TYPE_MODE (type),
+                                      type, 0, X86_64_REGPARM_MAX,
+                                      X86_64_SSE_REGPARM_MAX, intreg,
+                                      0);
+      break;
+    }
 
   /* Pull the value out of the saved registers.  */
 
   addr = create_tmp_var (ptr_type_node, "addr");
-  DECL_POINTER_ALIAS_SET (addr) = get_varargs_alias_set ();
 
   if (container)
     {
@@ -5321,8 +7014,8 @@ ix86_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
       bool need_temp;
       tree int_addr, sse_addr;
 
-      lab_false = create_artificial_label ();
-      lab_over = create_artificial_label ();
+      lab_false = create_artificial_label (UNKNOWN_LOCATION);
+      lab_over = create_artificial_label (UNKNOWN_LOCATION);
 
       examine_argument (nat_mode, type, 0, &needed_intregs, &needed_sseregs);
 
@@ -5368,16 +7061,14 @@ ix86_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
       else
        {
          int_addr = create_tmp_var (ptr_type_node, "int_addr");
-         DECL_POINTER_ALIAS_SET (int_addr) = get_varargs_alias_set ();
          sse_addr = create_tmp_var (ptr_type_node, "sse_addr");
-         DECL_POINTER_ALIAS_SET (sse_addr) = get_varargs_alias_set ();
        }
 
       /* First ensure that we fit completely in registers.  */
       if (needed_intregs)
        {
          t = build_int_cst (TREE_TYPE (gpr),
-                            (REGPARM_MAX - needed_intregs + 1) * 8);
+                            (X86_64_REGPARM_MAX - needed_intregs + 1) * 8);
          t = build2 (GE_EXPR, boolean_type_node, gpr, t);
          t2 = build1 (GOTO_EXPR, void_type_node, lab_false);
          t = build3 (COND_EXPR, void_type_node, t, t2, NULL_TREE);
@@ -5386,8 +7077,8 @@ ix86_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
       if (needed_sseregs)
        {
          t = build_int_cst (TREE_TYPE (fpr),
-                            (SSE_REGPARM_MAX - needed_sseregs + 1) * 16
-                            + REGPARM_MAX * 8);
+                            (X86_64_SSE_REGPARM_MAX - needed_sseregs + 1) * 16
+                            + X86_64_REGPARM_MAX * 8);
          t = build2 (GE_EXPR, boolean_type_node, fpr, t);
          t2 = build1 (GOTO_EXPR, void_type_node, lab_false);
          t = build3 (COND_EXPR, void_type_node, t, t2, NULL_TREE);
@@ -5400,16 +7091,14 @@ ix86_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
          /* int_addr = gpr + sav; */
          t = fold_convert (sizetype, gpr);
          t = build2 (POINTER_PLUS_EXPR, ptr_type_node, sav, t);
-         t = build2 (GIMPLE_MODIFY_STMT, void_type_node, int_addr, t);
-         gimplify_and_add (t, pre_p);
+         gimplify_assign (int_addr, t, pre_p);
        }
       if (needed_sseregs)
        {
          /* sse_addr = fpr + sav; */
          t = fold_convert (sizetype, fpr);
          t = build2 (POINTER_PLUS_EXPR, ptr_type_node, sav, t);
-         t = build2 (GIMPLE_MODIFY_STMT, void_type_node, sse_addr, t);
-         gimplify_and_add (t, pre_p);
+         gimplify_assign (sse_addr, t, pre_p);
        }
       if (need_temp)
        {
@@ -5418,8 +7107,7 @@ ix86_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
 
          /* addr = &temp; */
          t = build1 (ADDR_EXPR, build_pointer_type (type), temp);
-         t = build2 (GIMPLE_MODIFY_STMT, void_type_node, addr, t);
-         gimplify_and_add (t, pre_p);
+         gimplify_assign (addr, t, pre_p);
 
          for (i = 0; i < XVECLEN (container, 0); i++)
            {
@@ -5428,6 +7116,8 @@ ix86_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
              enum machine_mode mode = GET_MODE (reg);
              tree piece_type = lang_hooks.types.type_for_mode (mode, 1);
              tree addr_type = build_pointer_type (piece_type);
+             tree daddr_type = build_pointer_type_for_mode (piece_type,
+                                                            ptr_mode, true);
              tree src_addr, src;
              int src_offset;
              tree dest_addr, dest;
@@ -5447,13 +7137,12 @@ ix86_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
                                      size_int (src_offset));
              src = build_va_arg_indirect_ref (src_addr);
 
-             dest_addr = fold_convert (addr_type, addr);
-             dest_addr = fold_build2 (POINTER_PLUS_EXPR, addr_type, dest_addr,
+             dest_addr = fold_convert (daddr_type, addr);
+             dest_addr = fold_build2 (POINTER_PLUS_EXPR, daddr_type, dest_addr,
                                       size_int (INTVAL (XEXP (slot, 1))));
              dest = build_va_arg_indirect_ref (dest_addr);
 
-             t = build2 (GIMPLE_MODIFY_STMT, void_type_node, dest, src);
-             gimplify_and_add (t, pre_p);
+             gimplify_assign (dest, src, pre_p);
            }
        }
 
@@ -5461,33 +7150,38 @@ ix86_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
        {
          t = build2 (PLUS_EXPR, TREE_TYPE (gpr), gpr,
                      build_int_cst (TREE_TYPE (gpr), needed_intregs * 8));
-         t = build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (gpr), gpr, t);
-         gimplify_and_add (t, pre_p);
+         gimplify_assign (gpr, t, pre_p);
        }
+
       if (needed_sseregs)
        {
          t = build2 (PLUS_EXPR, TREE_TYPE (fpr), fpr,
                      build_int_cst (TREE_TYPE (fpr), needed_sseregs * 16));
-         t = build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (fpr), fpr, t);
-         gimplify_and_add (t, pre_p);
+         gimplify_assign (fpr, t, pre_p);
        }
 
-      t = build1 (GOTO_EXPR, void_type_node, lab_over);
-      gimplify_and_add (t, pre_p);
+      gimple_seq_add_stmt (pre_p, gimple_build_goto (lab_over));
 
-      t = build1 (LABEL_EXPR, void_type_node, lab_false);
-      append_to_statement_list (t, pre_p);
+      gimple_seq_add_stmt (pre_p, gimple_build_label (lab_false));
     }
 
   /* ... otherwise out of the overflow area.  */
 
+  /* When we align parameter on stack for caller, if the parameter
+     alignment is beyond MAX_SUPPORTED_STACK_ALIGNMENT, it will be
+     aligned at MAX_SUPPORTED_STACK_ALIGNMENT.  We will match callee
+     here with caller.  */
+  arg_boundary = FUNCTION_ARG_BOUNDARY (VOIDmode, type);
+  if ((unsigned int) arg_boundary > MAX_SUPPORTED_STACK_ALIGNMENT)
+    arg_boundary = MAX_SUPPORTED_STACK_ALIGNMENT;
+
   /* Care for on-stack alignment if needed.  */
-  if (FUNCTION_ARG_BOUNDARY (VOIDmode, type) <= 64
+  if (arg_boundary <= 64
       || integer_zerop (TYPE_SIZE (type)))
     t = ovf;
  else
     {
-      HOST_WIDE_INT align = FUNCTION_ARG_BOUNDARY (VOIDmode, type) / 8;
+      HOST_WIDE_INT align = arg_boundary / 8;
       t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (ovf), ovf,
                  size_int (align - 1));
       t = fold_convert (sizetype, t);
@@ -5496,22 +7190,16 @@ ix86_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
       t = fold_convert (TREE_TYPE (ovf), t);
     }
   gimplify_expr (&t, pre_p, NULL, is_gimple_val, fb_rvalue);
-
-  t2 = build2 (GIMPLE_MODIFY_STMT, void_type_node, addr, t);
-  gimplify_and_add (t2, pre_p);
+  gimplify_assign (addr, t, pre_p);
 
   t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (t), t,
              size_int (rsize * UNITS_PER_WORD));
-  t = build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (ovf), ovf, t);
-  gimplify_and_add (t, pre_p);
+  gimplify_assign (unshare_expr (ovf), t, pre_p);
 
   if (container)
-    {
-      t = build1 (LABEL_EXPR, void_type_node, lab_over);
-      append_to_statement_list (t, pre_p);
-    }
+    gimple_seq_add_stmt (pre_p, gimple_build_label (lab_over));
 
-  ptrtype = build_pointer_type (type);
+  ptrtype = build_pointer_type_for_mode (type, ptr_mode, true);
   addr = fold_convert (ptrtype, addr);
 
   if (indirect_p)
@@ -5587,7 +7275,7 @@ standard_80387_constant_p (rtx x)
   /* For XFmode constants, try to find a special 80387 instruction when
      optimizing for size or on those CPUs that benefit from them.  */
   if (mode == XFmode
-      && (optimize_size || TARGET_EXT_80387_CONSTANTS))
+      && (optimize_function_for_size_p (cfun) || TARGET_EXT_80387_CONSTANTS))
     {
       int i;
 
@@ -5688,8 +7376,10 @@ standard_sse_mode_p (enum machine_mode mode)
     }
 }
 
-/* Return 1 if X is FP constant we can load to SSE register w/o using memory.
- */
+/* Return 1 if X is all 0s.  For all 1s, return 2 if X is in 128bit
+   SSE modes and SSE2 is enabled,  return 3 if X is in 256bit AVX
+   modes and AVX is enabled.  */
+
 int
 standard_sse_constant_p (rtx x)
 {
@@ -5697,9 +7387,13 @@ standard_sse_constant_p (rtx x)
 
   if (x == const0_rtx || x == CONST0_RTX (GET_MODE (x)))
     return 1;
-  if (vector_all_ones_operand (x, mode)
-      && standard_sse_mode_p (mode))
-    return TARGET_SSE2 ? 2 : -1;
+  if (vector_all_ones_operand (x, mode))
+    {
+      if (standard_sse_mode_p (mode))
+       return TARGET_SSE2 ? 2 : -2;
+      else if (VALID_AVX256_REG_MODE (mode))
+       return TARGET_AVX ? 3 : -3;
+    }
 
   return 0;
 }
@@ -5713,14 +7407,37 @@ standard_sse_constant_opcode (rtx insn, rtx x)
   switch (standard_sse_constant_p (x))
     {
     case 1:
-      if (get_attr_mode (insn) == MODE_V4SF)
-        return "xorps\t%0, %0";
-      else if (get_attr_mode (insn) == MODE_V2DF)
-        return "xorpd\t%0, %0";
-      else
-        return "pxor\t%0, %0";
+      switch (get_attr_mode (insn))
+       {
+       case MODE_V4SF:
+         return TARGET_AVX ? "vxorps\t%0, %0, %0" : "xorps\t%0, %0";
+       case MODE_V2DF:
+         return TARGET_AVX ? "vxorpd\t%0, %0, %0" : "xorpd\t%0, %0";
+       case MODE_TI:
+         return TARGET_AVX ? "vpxor\t%0, %0, %0" : "pxor\t%0, %0";
+       case MODE_V8SF:
+         return "vxorps\t%x0, %x0, %x0";
+       case MODE_V4DF:
+         return "vxorpd\t%x0, %x0, %x0";
+       case MODE_OI:
+         return "vpxor\t%x0, %x0, %x0";
+       default:
+         gcc_unreachable ();
+       }
     case 2:
-      return "pcmpeqd\t%0, %0";
+      if (TARGET_AVX)
+       switch (get_attr_mode (insn))
+         {
+         case MODE_V4SF:
+         case MODE_V2DF:
+         case MODE_TI:
+           return "vpcmpeqd\t%0, %0, %0";
+           break;
+         default:
+           gcc_unreachable ();
+       }
+      else
+       return "pcmpeqd\t%0, %0";
     }
   gcc_unreachable ();
 }
@@ -5776,25 +7493,25 @@ ix86_can_use_return_insn_p (void)
     return 0;
 
   ix86_compute_frame_layout (&frame);
-  return frame.to_allocate == 0 && frame.nregs == 0;
+  return frame.to_allocate == 0 && (frame.nregs + frame.nsseregs) == 0;
 }
 \f
 /* Value should be nonzero if functions must have frame pointers.
    Zero means the frame pointer need not be set up (and parms may
    be accessed via the stack pointer) in functions that seem suitable.  */
 
-int
+static bool
 ix86_frame_pointer_required (void)
 {
   /* If we accessed previous frames, then the generated code expects
      to be able to access the saved ebp value in our frame.  */
   if (cfun->machine->accesses_prev_frame)
-    return 1;
+    return true;
 
   /* Several x86 os'es need a frame pointer for other reasons,
      usually pertaining to setjmp.  */
   if (SUBTARGET_FRAME_POINTER_REQUIRED)
-    return 1;
+    return true;
 
   /* In override_options, TARGET_OMIT_LEAF_FRAME_POINTER turns off
      the frame pointer by default.  Turn it back on now if we've not
@@ -5802,12 +7519,12 @@ ix86_frame_pointer_required (void)
   if (TARGET_OMIT_LEAF_FRAME_POINTER
       && (!current_function_is_leaf
          || ix86_current_function_calls_tls_descriptor))
-    return 1;
+    return true;
 
   if (crtl->profile)
-    return 1;
+    return true;
 
-  return 0;
+  return false;
 }
 
 /* Record that the current function accesses previous call frames.  */
@@ -5818,10 +7535,12 @@ ix86_setup_frame_addresses (void)
   cfun->machine->accesses_prev_frame = 1;
 }
 \f
-#if (defined(HAVE_GAS_HIDDEN) && (SUPPORTS_ONE_ONLY - 0)) || TARGET_MACHO
-# define USE_HIDDEN_LINKONCE 1
-#else
-# define USE_HIDDEN_LINKONCE 0
+#ifndef USE_HIDDEN_LINKONCE
+# if (defined(HAVE_GAS_HIDDEN) && (SUPPORTS_ONE_ONLY - 0)) || TARGET_MACHO
+#  define USE_HIDDEN_LINKONCE 1
+# else
+#  define USE_HIDDEN_LINKONCE 0
+# endif
 #endif
 
 static int pic_labels_used;
@@ -5876,11 +7595,12 @@ ix86_file_end (void)
        {
          tree decl;
 
-         decl = build_decl (FUNCTION_DECL, get_identifier (name),
+         decl = build_decl (BUILTINS_LOCATION,
+                            FUNCTION_DECL, get_identifier (name),
                             error_mark_node);
          TREE_PUBLIC (decl) = 1;
          TREE_STATIC (decl) = 1;
-         DECL_ONE_ONLY (decl) = 1;
+         DECL_COMDAT_GROUP (decl) = DECL_ASSEMBLER_NAME (decl);
 
          (*targetm.asm_out.unique_section) (decl, 0);
          switch_to_section (get_named_section (decl, NULL, 0));
@@ -5888,7 +7608,7 @@ ix86_file_end (void)
          (*targetm.asm_out.globalize_label) (asm_out_file, name);
          fputs ("\t.hidden\t", asm_out_file);
          assemble_name (asm_out_file, name);
-         fputc ('\n', asm_out_file);
+         putc ('\n', asm_out_file);
          ASM_DECLARE_FUNCTION_NAME (asm_out_file, name, decl);
        }
       else
@@ -5899,10 +7619,7 @@ ix86_file_end (void)
 
       xops[0] = gen_rtx_REG (Pmode, regno);
       xops[1] = gen_rtx_MEM (Pmode, stack_pointer_rtx);
-      if (TARGET_64BIT)
-       output_asm_insn ("mov{q}\t{%1, %0|%0, %1}", xops);
-      else
-       output_asm_insn ("mov{l}\t{%1, %0|%0, %1}", xops);
+      output_asm_insn ("mov%z0\t{%1, %0|%0, %1}", xops);
       output_asm_insn ("ret", xops);
     }
 
@@ -5942,12 +7659,7 @@ output_set_got (rtx dest, rtx label ATTRIBUTE_UNUSED)
       xops[2] = gen_rtx_LABEL_REF (Pmode, label ? label : gen_label_rtx ());
 
       if (!flag_pic)
-        {
-          if (TARGET_64BIT)
-           output_asm_insn ("mov{q}\t{%2, %0|%0, %2}", xops);
-         else
-           output_asm_insn ("mov{l}\t{%2, %0|%0, %2}", xops);
-       }
+       output_asm_insn ("mov%z0\t{%2, %0|%0, %2}", xops);
       else
        output_asm_insn ("call\t%a2", xops);
 
@@ -5955,19 +7667,14 @@ output_set_got (rtx dest, rtx label ATTRIBUTE_UNUSED)
       /* Output the Mach-O "canonical" label name ("Lxx$pb") here too.  This
          is what will be referenced by the Mach-O PIC subsystem.  */
       if (!label)
-       ASM_OUTPUT_LABEL (asm_out_file, machopic_function_base_name ());
+       ASM_OUTPUT_LABEL (asm_out_file, MACHOPIC_FUNCTION_BASE_NAME);
 #endif
 
       (*targetm.asm_out.internal_label) (asm_out_file, "L",
                                 CODE_LABEL_NUMBER (XEXP (xops[2], 0)));
 
       if (flag_pic)
-        {
-          if (TARGET_64BIT)
-           output_asm_insn ("pop{q}\t%0", xops);
-         else
-           output_asm_insn ("pop{l}\t%0", xops);
-       }
+       output_asm_insn ("pop%z0\t%0", xops);
     }
   else
     {
@@ -5982,7 +7689,7 @@ output_set_got (rtx dest, rtx label ATTRIBUTE_UNUSED)
          is what will be referenced by the Mach-O PIC subsystem.  */
 #if TARGET_MACHO
       if (!label)
-       ASM_OUTPUT_LABEL (asm_out_file, machopic_function_base_name ());
+       ASM_OUTPUT_LABEL (asm_out_file, MACHOPIC_FUNCTION_BASE_NAME);
       else
         targetm.asm_out.internal_label (asm_out_file, "L",
                                           CODE_LABEL_NUMBER (label));
@@ -5993,19 +7700,9 @@ output_set_got (rtx dest, rtx label ATTRIBUTE_UNUSED)
     return "";
 
   if (!flag_pic || TARGET_DEEP_BRANCH_PREDICTION)
-    {
-      if (TARGET_64BIT)
-        output_asm_insn ("add{q}\t{%1, %0|%0, %1}", xops);
-      else
-        output_asm_insn ("add{l}\t{%1, %0|%0, %1}", xops);
-    }
+    output_asm_insn ("add%z0\t{%1, %0|%0, %1}", xops);
   else
-    {
-      if (TARGET_64BIT)
-        output_asm_insn ("add{q}\t{%1+[.-%a2], %0|%0, %1+(.-%a2)}", xops);
-      else
-        output_asm_insn ("add{l}\t{%1+[.-%a2], %0|%0, %1+(.-%a2)}", xops);
-    }
+    output_asm_insn ("add%z0\t{%1+[.-%a2], %0|%0, %1+(.-%a2)}", xops);
 
   return "";
 }
@@ -6015,6 +7712,9 @@ output_set_got (rtx dest, rtx label ATTRIBUTE_UNUSED)
 static rtx
 gen_push (rtx arg)
 {
+  if (ix86_cfa_state->reg == stack_pointer_rtx)
+    ix86_cfa_state->offset += UNITS_PER_WORD;
+
   return gen_rtx_SET (VOIDmode,
                      gen_rtx_MEM (Pmode,
                                   gen_rtx_PRE_DEC (Pmode,
@@ -6031,9 +7731,14 @@ ix86_select_alt_pic_regnum (void)
   if (current_function_is_leaf && !crtl->profile
       && !ix86_current_function_calls_tls_descriptor)
     {
-      int i;
+      int i, drap;
+      /* Can't use the same register for both PIC and DRAP.  */
+      if (crtl->drap_reg)
+       drap = REGNO (crtl->drap_reg);
+      else
+       drap = -1;
       for (i = 2; i >= 0; --i)
-        if (!df_regs_ever_live_p (i))
+        if (i != drap && !df_regs_ever_live_p (i))
          return i;
     }
 
@@ -6069,8 +7774,7 @@ ix86_save_reg (unsigned int regno, int maybe_eh_return)
        }
     }
 
-  if (cfun->machine->force_align_arg_pointer
-      && regno == REGNO (cfun->machine->force_align_arg_pointer))
+  if (crtl->drap_reg && regno == REGNO (crtl->drap_reg))
     return 1;
 
   return (df_regs_ever_live_p (regno)
@@ -6079,7 +7783,7 @@ ix86_save_reg (unsigned int regno, int maybe_eh_return)
          && (regno != HARD_FRAME_POINTER_REGNUM || !frame_pointer_needed));
 }
 
-/* Return number of registers to be saved on the stack.  */
+/* Return number of saved general prupose registers.  */
 
 static int
 ix86_nsaved_regs (void)
@@ -6087,12 +7791,46 @@ ix86_nsaved_regs (void)
   int nregs = 0;
   int regno;
 
-  for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno--)
-    if (ix86_save_reg (regno, true))
-      nregs++;
+  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+    if (!SSE_REGNO_P (regno) && ix86_save_reg (regno, true))
+      nregs ++;
+  return nregs;
+}
+
+/* Return number of saved SSE registrers.  */
+
+static int
+ix86_nsaved_sseregs (void)
+{
+  int nregs = 0;
+  int regno;
+
+  if (ix86_cfun_abi () != MS_ABI)
+    return 0;
+  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+    if (SSE_REGNO_P (regno) && ix86_save_reg (regno, true))
+      nregs ++;
   return nregs;
 }
 
+/* Given FROM and TO register numbers, say whether this elimination is
+   allowed.  If stack alignment is needed, we can only replace argument
+   pointer with hard frame pointer, or replace frame pointer with stack
+   pointer.  Otherwise, frame pointer elimination is automatically
+   handled and all other eliminations are valid.  */
+
+int
+ix86_can_eliminate (int from, int to)
+{
+  if (stack_realign_fp)
+    return ((from == ARG_POINTER_REGNUM
+            && to == HARD_FRAME_POINTER_REGNUM)
+           || (from == FRAME_POINTER_REGNUM
+               && to == STACK_POINTER_REGNUM));
+  else
+    return to == STACK_POINTER_REGNUM ? !frame_pointer_needed : 1;
+}
+
 /* Return the offset between two registers, one to be eliminated, and the other
    its replacement, at the start of a routine.  */
 
@@ -6119,6 +7857,17 @@ ix86_initial_elimination_offset (int from, int to)
     }
 }
 
+/* In a dynamically-aligned function, we can't know the offset from
+   stack pointer to frame pointer, so we must ensure that setjmp
+   eliminates fp against the hard fp (%ebp) rather than trying to
+   index from %esp up to the top of the frame across a gap that is
+   of unknown (at compile-time) size.  */
+static rtx
+ix86_builtin_setjmp_frame_value (void)
+{
+  return stack_realign_fp ? hard_frame_pointer_rtx : virtual_stack_vars_rtx;
+}
+
 /* Fill structure ix86_frame about frame of currently computed function.  */
 
 static void
@@ -6131,16 +7880,31 @@ ix86_compute_frame_layout (struct ix86_frame *frame)
   HOST_WIDE_INT size = get_frame_size ();
 
   frame->nregs = ix86_nsaved_regs ();
+  frame->nsseregs = ix86_nsaved_sseregs ();
   total_size = size;
 
   stack_alignment_needed = crtl->stack_alignment_needed / BITS_PER_UNIT;
   preferred_alignment = crtl->preferred_stack_boundary / BITS_PER_UNIT;
 
+  /* MS ABI seem to require stack alignment to be always 16 except for function
+     prologues.  */
+  if (ix86_cfun_abi () == MS_ABI && preferred_alignment < 16)
+    {
+      preferred_alignment = 16;
+      stack_alignment_needed = 16;
+      crtl->preferred_stack_boundary = 128;
+      crtl->stack_alignment_needed = 128;
+    }
+
+  gcc_assert (!size || stack_alignment_needed);
+  gcc_assert (preferred_alignment >= STACK_BOUNDARY / BITS_PER_UNIT);
+  gcc_assert (preferred_alignment <= stack_alignment_needed);
+
   /* During reload iteration the amount of registers saved can change.
      Recompute the value as needed.  Do not recompute when amount of registers
      didn't change as reload does multiple calls to the function and does not
      expect the decision to change within single iteration.  */
-  if (!optimize_size
+  if (!optimize_function_for_size_p (cfun)
       && cfun->machine->use_fast_prologue_epilogue_nregs != frame->nregs)
     {
       int count = frame->nregs;
@@ -6178,30 +7942,26 @@ ix86_compute_frame_layout (struct ix86_frame *frame)
 
   frame->hard_frame_pointer_offset = offset;
 
-  /* Do some sanity checking of stack_alignment_needed and
-     preferred_alignment, since i386 port is the only using those features
-     that may break easily.  */
-
-  gcc_assert (!size || stack_alignment_needed);
-  gcc_assert (preferred_alignment >= STACK_BOUNDARY / BITS_PER_UNIT);
-  gcc_assert (preferred_alignment <= PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT);
-  gcc_assert (stack_alignment_needed
-             <= PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT);
-
-  if (stack_alignment_needed < STACK_BOUNDARY / BITS_PER_UNIT)
-    stack_alignment_needed = STACK_BOUNDARY / BITS_PER_UNIT;
+  /* Set offset to aligned because the realigned frame starts from
+     here.  */
+  if (stack_realign_fp)
+    offset = (offset + stack_alignment_needed -1) & -stack_alignment_needed;
 
   /* Register save area */
   offset += frame->nregs * UNITS_PER_WORD;
 
-  /* Va-arg area */
-  if (ix86_save_varrargs_registers)
-    {
-      offset += X86_64_VARARGS_SIZE;
-      frame->va_arg_size = X86_64_VARARGS_SIZE;
-    }
+  /* Align SSE reg save area.  */
+  if (frame->nsseregs)
+    frame->padding0 = ((offset + 16 - 1) & -16) - offset;
   else
-    frame->va_arg_size = 0;
+    frame->padding0 = 0;
+  
+  /* SSE register save area.  */
+  offset += frame->padding0 + frame->nsseregs * 16;
+
+  /* Va-arg area */
+  frame->va_arg_size = ix86_varargs_gpr_size + ix86_varargs_fpr_size;
+  offset += frame->va_arg_size;
 
   /* Align start of frame for local function.  */
   frame->padding1 = ((offset + stack_alignment_needed - 1)
@@ -6252,7 +8012,8 @@ ix86_compute_frame_layout (struct ix86_frame *frame)
       || (TARGET_64BIT && frame->to_allocate >= (HOST_WIDE_INT) 0x80000000))
     frame->save_regs_using_mov = false;
 
-  if (TARGET_RED_ZONE && current_function_sp_is_unchanging
+  if (!TARGET_64BIT_MS_ABI && TARGET_RED_ZONE
+      && current_function_sp_is_unchanging
       && current_function_is_leaf
       && !ix86_current_function_calls_tls_descriptor)
     {
@@ -6268,8 +8029,10 @@ ix86_compute_frame_layout (struct ix86_frame *frame)
   frame->stack_pointer_offset -= frame->red_zone_size;
 #if 0
   fprintf (stderr, "\n");
-  fprintf (stderr, "nregs: %ld\n", (long)frame->nregs);
   fprintf (stderr, "size: %ld\n", (long)size);
+  fprintf (stderr, "nregs: %ld\n", (long)frame->nregs);
+  fprintf (stderr, "nsseregs: %ld\n", (long)frame->nsseregs);
+  fprintf (stderr, "padding0: %ld\n", (long)frame->padding0);
   fprintf (stderr, "alignment1: %ld\n", (long)stack_alignment_needed);
   fprintf (stderr, "padding1: %ld\n", (long)frame->padding1);
   fprintf (stderr, "va_arg: %ld\n", (long)frame->va_arg_size);
@@ -6294,8 +8057,8 @@ ix86_emit_save_regs (void)
   unsigned int regno;
   rtx insn;
 
-  for (regno = FIRST_PSEUDO_REGISTER; regno-- > 0; )
-    if (ix86_save_reg (regno, true))
+  for (regno = FIRST_PSEUDO_REGISTER - 1; regno-- > 0; )
+    if (!SSE_REGNO_P (regno) && ix86_save_reg (regno, true))
       {
        insn = emit_insn (gen_push (gen_rtx_REG (Pmode, regno)));
        RTX_FRAME_RELATED_P (insn) = 1;
@@ -6311,7 +8074,7 @@ ix86_emit_save_regs_using_mov (rtx pointer, HOST_WIDE_INT offset)
   rtx insn;
 
   for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
-    if (ix86_save_reg (regno, true))
+    if (!SSE_REGNO_P (regno) && ix86_save_reg (regno, true))
       {
        insn = emit_move_insn (adjust_address (gen_rtx_MEM (Pmode, pointer),
                                               Pmode, offset),
@@ -6321,6 +8084,69 @@ ix86_emit_save_regs_using_mov (rtx pointer, HOST_WIDE_INT offset)
       }
 }
 
+/* Emit code to save registers using MOV insns.  First register
+   is restored from POINTER + OFFSET.  */
+static void
+ix86_emit_save_sse_regs_using_mov (rtx pointer, HOST_WIDE_INT offset)
+{
+  unsigned int regno;
+  rtx insn;
+  rtx mem;
+
+  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+    if (SSE_REGNO_P (regno) && ix86_save_reg (regno, true))
+      {
+       mem = adjust_address (gen_rtx_MEM (TImode, pointer), TImode, offset);
+       set_mem_align (mem, 128);
+       insn = emit_move_insn (mem, gen_rtx_REG (TImode, regno));
+       RTX_FRAME_RELATED_P (insn) = 1;
+       offset += 16;
+      }
+}
+
+static GTY(()) rtx queued_cfa_restores;
+
+/* Add a REG_CFA_RESTORE REG note to INSN or queue them until next stack
+   manipulation insn.  Don't add it if the previously
+   saved value will be left untouched within stack red-zone till return,
+   as unwinders can find the same value in the register and
+   on the stack.  */
+
+static void
+ix86_add_cfa_restore_note (rtx insn, rtx reg, HOST_WIDE_INT red_offset)
+{
+  if (TARGET_RED_ZONE
+      && !TARGET_64BIT_MS_ABI
+      && red_offset + RED_ZONE_SIZE >= 0
+      && crtl->args.pops_args < 65536)
+    return;
+
+  if (insn)
+    {
+      add_reg_note (insn, REG_CFA_RESTORE, reg);
+      RTX_FRAME_RELATED_P (insn) = 1;
+    }
+  else
+    queued_cfa_restores
+      = alloc_reg_note (REG_CFA_RESTORE, reg, queued_cfa_restores);
+}
+
+/* Add queued REG_CFA_RESTORE notes if any to INSN.  */
+
+static void
+ix86_add_queued_cfa_restore_notes (rtx insn)
+{
+  rtx last;
+  if (!queued_cfa_restores)
+    return;
+  for (last = queued_cfa_restores; XEXP (last, 1); last = XEXP (last, 1))
+    ;
+  XEXP (last, 1) = REG_NOTES (insn);
+  REG_NOTES (insn) = queued_cfa_restores;
+  queued_cfa_restores = NULL_RTX;
+  RTX_FRAME_RELATED_P (insn) = 1;
+}
+
 /* Expand prologue or epilogue stack adjustment.
    The pattern exist to put a dependency on all ebp-based memory accesses.
    STYLE should be negative if instructions should be marked as frame related,
@@ -6328,7 +8154,8 @@ ix86_emit_save_regs_using_mov (rtx pointer, HOST_WIDE_INT offset)
    otherwise.  */
 
 static void
-pro_epilogue_adjust_stack (rtx dest, rtx src, rtx offset, int style)
+pro_epilogue_adjust_stack (rtx dest, rtx src, rtx offset,
+                          int style, bool set_cfa)
 {
   rtx insn;
 
@@ -6351,65 +8178,184 @@ pro_epilogue_adjust_stack (rtx dest, rtx src, rtx offset, int style)
       insn = emit_insn (gen_pro_epilogue_adjust_stack_rex64_2 (dest, src, r11,
                                                               offset));
     }
-  if (style < 0)
+
+  if (style >= 0)
+    ix86_add_queued_cfa_restore_notes (insn);
+
+  if (set_cfa)
+    {
+      rtx r;
+
+      gcc_assert (ix86_cfa_state->reg == src);
+      ix86_cfa_state->offset += INTVAL (offset);
+      ix86_cfa_state->reg = dest;
+    
+      r = gen_rtx_PLUS (Pmode, src, offset);
+      r = gen_rtx_SET (VOIDmode, dest, r);
+      add_reg_note (insn, REG_CFA_ADJUST_CFA, r);
+      RTX_FRAME_RELATED_P (insn) = 1;
+    }
+  else if (style < 0)
     RTX_FRAME_RELATED_P (insn) = 1;
 }
 
-/* Handle the TARGET_INTERNAL_ARG_POINTER hook.  */
+/* Find an available register to be used as dynamic realign argument
+   pointer regsiter.  Such a register will be written in prologue and
+   used in begin of body, so it must not be
+       1. parameter passing register.
+       2. GOT pointer.
+   We reuse static-chain register if it is available.  Otherwise, we
+   use DI for i386 and R13 for x86-64.  We chose R13 since it has
+   shorter encoding.
 
-static rtx
-ix86_internal_arg_pointer (void)
+   Return: the regno of chosen register.  */
+
+static unsigned int 
+find_drap_reg (void)
 {
-  bool has_force_align_arg_pointer =
-    (0 != lookup_attribute (ix86_force_align_arg_pointer_string,
-                           TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl))));
-  if ((FORCE_PREFERRED_STACK_BOUNDARY_IN_MAIN
-       && DECL_NAME (current_function_decl)
-       && MAIN_NAME_P (DECL_NAME (current_function_decl))
-       && DECL_FILE_SCOPE_P (current_function_decl))
-      || ix86_force_align_arg_pointer
-      || has_force_align_arg_pointer)
-    {
-      /* Nested functions can't realign the stack due to a register
-        conflict.  */
-      if (DECL_CONTEXT (current_function_decl)
-         && TREE_CODE (DECL_CONTEXT (current_function_decl)) == FUNCTION_DECL)
-       {
-         if (ix86_force_align_arg_pointer)
-           warning (0, "-mstackrealign ignored for nested functions");
-         if (has_force_align_arg_pointer)
-           error ("%s not supported for nested functions",
-                  ix86_force_align_arg_pointer_string);
-         return virtual_incoming_args_rtx;
-       }
-      cfun->machine->force_align_arg_pointer = gen_rtx_REG (Pmode, CX_REG);
-      return copy_to_reg (cfun->machine->force_align_arg_pointer);
+  tree decl = cfun->decl;
+
+  if (TARGET_64BIT)
+    {
+      /* Use R13 for nested function or function need static chain.
+        Since function with tail call may use any caller-saved
+        registers in epilogue, DRAP must not use caller-saved
+        register in such case.  */
+      if ((decl_function_context (decl)
+          && !DECL_NO_STATIC_CHAIN (decl))
+         || crtl->tail_call_emit)
+       return R13_REG;
+
+      return R10_REG;
     }
   else
-    return virtual_incoming_args_rtx;
+    {
+      /* Use DI for nested function or function need static chain.
+        Since function with tail call may use any caller-saved
+        registers in epilogue, DRAP must not use caller-saved
+        register in such case.  */
+      if ((decl_function_context (decl)
+          && !DECL_NO_STATIC_CHAIN (decl))
+         || crtl->tail_call_emit)
+       return DI_REG;
+    
+      /* Reuse static chain register if it isn't used for parameter
+         passing.  */
+      if (ix86_function_regparm (TREE_TYPE (decl), decl) <= 2
+         && !lookup_attribute ("fastcall",
+                               TYPE_ATTRIBUTES (TREE_TYPE (decl))))
+       return CX_REG;
+      else
+       return DI_REG;
+    }
 }
 
-/* Handle the TARGET_DWARF_HANDLE_FRAME_UNSPEC hook.
-   This is called from dwarf2out.c to emit call frame instructions
-   for frame-related insns containing UNSPECs and UNSPEC_VOLATILEs. */
+/* Update incoming stack boundary and estimated stack alignment.  */
+
 static void
-ix86_dwarf_handle_frame_unspec (const char *label, rtx pattern, int index)
+ix86_update_stack_boundary (void)
+{
+  /* Prefer the one specified at command line. */
+  ix86_incoming_stack_boundary 
+    = (ix86_user_incoming_stack_boundary
+       ? ix86_user_incoming_stack_boundary
+       : ix86_default_incoming_stack_boundary);
+
+  /* Incoming stack alignment can be changed on individual functions
+     via force_align_arg_pointer attribute.  We use the smallest
+     incoming stack boundary.  */
+  if (ix86_incoming_stack_boundary > MIN_STACK_BOUNDARY
+      && lookup_attribute (ix86_force_align_arg_pointer_string,
+                          TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl))))
+    ix86_incoming_stack_boundary = MIN_STACK_BOUNDARY;
+
+  /* The incoming stack frame has to be aligned at least at
+     parm_stack_boundary.  */
+  if (ix86_incoming_stack_boundary < crtl->parm_stack_boundary)
+    ix86_incoming_stack_boundary = crtl->parm_stack_boundary;
+
+  /* Stack at entrance of main is aligned by runtime.  We use the
+     smallest incoming stack boundary. */
+  if (ix86_incoming_stack_boundary > MAIN_STACK_BOUNDARY
+      && DECL_NAME (current_function_decl)
+      && MAIN_NAME_P (DECL_NAME (current_function_decl))
+      && DECL_FILE_SCOPE_P (current_function_decl))
+    ix86_incoming_stack_boundary = MAIN_STACK_BOUNDARY;
+
+  /* x86_64 vararg needs 16byte stack alignment for register save
+     area.  */
+  if (TARGET_64BIT
+      && cfun->stdarg
+      && crtl->stack_alignment_estimated < 128)
+    crtl->stack_alignment_estimated = 128;
+}
+
+/* Handle the TARGET_GET_DRAP_RTX hook.  Return NULL if no DRAP is
+   needed or an rtx for DRAP otherwise.  */
+
+static rtx
+ix86_get_drap_rtx (void)
 {
-  rtx unspec = SET_SRC (pattern);
-  gcc_assert (GET_CODE (unspec) == UNSPEC);
+  if (ix86_force_drap || !ACCUMULATE_OUTGOING_ARGS)
+    crtl->need_drap = true;
 
-  switch (index)
+  if (stack_realign_drap)
     {
-    case UNSPEC_REG_SAVE:
-      dwarf2out_reg_save_reg (label, XVECEXP (unspec, 0, 0),
-                             SET_DEST (pattern));
-      break;
-    case UNSPEC_DEF_CFA:
-      dwarf2out_def_cfa (label, REGNO (SET_DEST (pattern)),
-                        INTVAL (XVECEXP (unspec, 0, 0)));
-      break;
-    default:
-      gcc_unreachable ();
+      /* Assign DRAP to vDRAP and returns vDRAP */
+      unsigned int regno = find_drap_reg ();
+      rtx drap_vreg;
+      rtx arg_ptr;
+      rtx seq, insn;
+
+      arg_ptr = gen_rtx_REG (Pmode, regno);
+      crtl->drap_reg = arg_ptr;
+
+      start_sequence ();
+      drap_vreg = copy_to_reg (arg_ptr);
+      seq = get_insns ();
+      end_sequence ();
+      
+      insn = emit_insn_before (seq, NEXT_INSN (entry_of_function ()));
+      RTX_FRAME_RELATED_P (insn) = 1;
+      return drap_vreg;
+    }
+  else
+    return NULL;
+}
+
+/* Handle the TARGET_INTERNAL_ARG_POINTER hook.  */
+
+static rtx
+ix86_internal_arg_pointer (void)
+{
+  return virtual_incoming_args_rtx;
+}
+
+/* Finalize stack_realign_needed flag, which will guide prologue/epilogue
+   to be generated in correct form.  */
+static void 
+ix86_finalize_stack_realign_flags (void)
+{
+  /* Check if stack realign is really needed after reload, and 
+     stores result in cfun */
+  unsigned int incoming_stack_boundary
+    = (crtl->parm_stack_boundary > ix86_incoming_stack_boundary
+       ? crtl->parm_stack_boundary : ix86_incoming_stack_boundary);
+  unsigned int stack_realign = (incoming_stack_boundary
+                               < (current_function_is_leaf
+                                  ? crtl->max_used_stack_slot_alignment
+                                  : crtl->stack_alignment_needed));
+
+  if (crtl->stack_realign_finalized)
+    {
+      /* After stack_realign_needed is finalized, we can't no longer
+        change it.  */
+      gcc_assert (crtl->stack_realign_needed == stack_realign);
+    }
+  else
+    {
+      crtl->stack_realign_needed = stack_realign;
+      crtl->stack_realign_finalized = true;
     }
 }
 
@@ -6423,52 +8369,61 @@ ix86_expand_prologue (void)
   struct ix86_frame frame;
   HOST_WIDE_INT allocate;
 
+  ix86_finalize_stack_realign_flags ();
+
+  /* DRAP should not coexist with stack_realign_fp */
+  gcc_assert (!(crtl->drap_reg && stack_realign_fp));
+
+  /* Initialize CFA state for before the prologue.  */
+  ix86_cfa_state->reg = stack_pointer_rtx;
+  ix86_cfa_state->offset = INCOMING_FRAME_SP_OFFSET;
+
   ix86_compute_frame_layout (&frame);
 
-  if (cfun->machine->force_align_arg_pointer)
+  /* Emit prologue code to adjust stack alignment and setup DRAP, in case
+     of DRAP is needed and stack realignment is really needed after reload */
+  if (crtl->drap_reg && crtl->stack_realign_needed)
     {
       rtx x, y;
+      int align_bytes = crtl->stack_alignment_needed / BITS_PER_UNIT;
+      int param_ptr_offset = (call_used_regs[REGNO (crtl->drap_reg)]
+                             ? 0 : UNITS_PER_WORD);
+
+      gcc_assert (stack_realign_drap);
 
       /* Grab the argument pointer.  */
-      x = plus_constant (stack_pointer_rtx, 4);
-      y = cfun->machine->force_align_arg_pointer;
-      insn = emit_insn (gen_rtx_SET (VOIDmode, y, x));
-      RTX_FRAME_RELATED_P (insn) = 1;
+      x = plus_constant (stack_pointer_rtx, 
+                         (UNITS_PER_WORD + param_ptr_offset));
+      y = crtl->drap_reg;
+
+      /* Only need to push parameter pointer reg if it is caller
+        saved reg */
+      if (!call_used_regs[REGNO (crtl->drap_reg)])
+       {
+         /* Push arg pointer reg */
+         insn = emit_insn (gen_push (y));
+         RTX_FRAME_RELATED_P (insn) = 1;
+       }
 
-      /* The unwind info consists of two parts: install the fafp as the cfa,
-        and record the fafp as the "save register" of the stack pointer.
-        The later is there in order that the unwinder can see where it
-        should restore the stack pointer across the and insn.  */
-      x = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, const0_rtx), UNSPEC_DEF_CFA);
-      x = gen_rtx_SET (VOIDmode, y, x);
-      RTX_FRAME_RELATED_P (x) = 1;
-      y = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, stack_pointer_rtx),
-                         UNSPEC_REG_SAVE);
-      y = gen_rtx_SET (VOIDmode, cfun->machine->force_align_arg_pointer, y);
-      RTX_FRAME_RELATED_P (y) = 1;
-      x = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, x, y));
-      x = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, x, NULL);
-      REG_NOTES (insn) = x;
+      insn = emit_insn (gen_rtx_SET (VOIDmode, y, x));
+      RTX_FRAME_RELATED_P (insn) = 1; 
+      ix86_cfa_state->reg = crtl->drap_reg;
 
       /* Align the stack.  */
-      emit_insn (gen_andsi3 (stack_pointer_rtx, stack_pointer_rtx,
-                            GEN_INT (-16)));
-
-      /* And here we cheat like madmen with the unwind info.  We force the
-        cfa register back to sp+4, which is exactly what it was at the
-        start of the function.  Re-pushing the return address results in
-        the return at the same spot relative to the cfa, and thus is
-        correct wrt the unwind info.  */
-      x = cfun->machine->force_align_arg_pointer;
-      x = gen_frame_mem (Pmode, plus_constant (x, -4));
-      insn = emit_insn (gen_push (x));
+      insn = emit_insn ((*ix86_gen_andsp) (stack_pointer_rtx,
+                                          stack_pointer_rtx,
+                                          GEN_INT (-align_bytes)));
       RTX_FRAME_RELATED_P (insn) = 1;
 
-      x = GEN_INT (4);
-      x = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, x), UNSPEC_DEF_CFA);
-      x = gen_rtx_SET (VOIDmode, stack_pointer_rtx, x);
-      x = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, x, NULL);
-      REG_NOTES (insn) = x;
+      /* Replicate the return address on the stack so that return
+        address can be reached via (argp - 1) slot.  This is needed
+        to implement macro RETURN_ADDR_RTX and intrinsic function
+        expand_builtin_return_addr etc.  */
+      x = crtl->drap_reg;
+      x = gen_frame_mem (Pmode,
+                         plus_constant (x, -UNITS_PER_WORD));
+      insn = emit_insn (gen_push (x));
+      RTX_FRAME_RELATED_P (insn) = 1;
     }
 
   /* Note: AT&T enter does NOT have reversed args.  Enter is probably
@@ -6481,9 +8436,24 @@ ix86_expand_prologue (void)
 
       insn = emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
       RTX_FRAME_RELATED_P (insn) = 1;
+
+      if (ix86_cfa_state->reg == stack_pointer_rtx)
+        ix86_cfa_state->reg = hard_frame_pointer_rtx;
+    }
+
+  if (stack_realign_fp)
+    {
+      int align_bytes = crtl->stack_alignment_needed / BITS_PER_UNIT;
+      gcc_assert (align_bytes > MIN_STACK_BOUNDARY / BITS_PER_UNIT);
+
+      /* Align the stack.  */
+      insn = emit_insn ((*ix86_gen_andsp) (stack_pointer_rtx,
+                                          stack_pointer_rtx,
+                                          GEN_INT (-align_bytes)));
+      RTX_FRAME_RELATED_P (insn) = 1;
     }
 
-  allocate = frame.to_allocate;
+  allocate = frame.to_allocate + frame.nsseregs * 16 + frame.padding0;
 
   if (!frame.save_regs_using_mov)
     ix86_emit_save_regs ();
@@ -6495,9 +8465,11 @@ ix86_expand_prologue (void)
      avoid doing this if I am going to have to probe the stack since
      at least on x86_64 the stack probe can turn into a call that clobbers
      a red zone location */
-  if (TARGET_RED_ZONE && frame.save_regs_using_mov
+  if (!TARGET_64BIT_MS_ABI && TARGET_RED_ZONE && frame.save_regs_using_mov
       && (! TARGET_STACK_PROBE || allocate < CHECK_STACK_LIMIT))
-    ix86_emit_save_regs_using_mov (frame_pointer_needed ? hard_frame_pointer_rtx
+    ix86_emit_save_regs_using_mov ((frame_pointer_needed
+                                    && !crtl->stack_realign_needed) 
+                                   ? hard_frame_pointer_rtx
                                   : stack_pointer_rtx,
                                   -frame.nregs * UNITS_PER_WORD);
 
@@ -6505,7 +8477,8 @@ ix86_expand_prologue (void)
     ;
   else if (! TARGET_STACK_PROBE || allocate < CHECK_STACK_LIMIT)
     pro_epilogue_adjust_stack (stack_pointer_rtx, stack_pointer_rtx,
-                              GEN_INT (-allocate), -1);
+                              GEN_INT (-allocate), -1,
+                              ix86_cfa_state->reg == stack_pointer_rtx);
   else
     {
       /* Only valid for Win32.  */
@@ -6513,9 +8486,9 @@ ix86_expand_prologue (void)
       bool eax_live;
       rtx t;
 
-      gcc_assert (!TARGET_64BIT || TARGET_64BIT_MS_ABI);
+      gcc_assert (!TARGET_64BIT || cfun->machine->call_abi == MS_ABI);
 
-      if (TARGET_64BIT_MS_ABI)
+      if (cfun->machine->call_abi == MS_ABI)
        eax_live = false;
       else
        eax_live = ix86_eax_live_at_start_p ();
@@ -6529,15 +8502,19 @@ ix86_expand_prologue (void)
       emit_move_insn (eax, GEN_INT (allocate));
 
       if (TARGET_64BIT)
-       insn = gen_allocate_stack_worker_64 (eax);
+       insn = gen_allocate_stack_worker_64 (eax, eax);
       else
-       insn = gen_allocate_stack_worker_32 (eax);
+       insn = gen_allocate_stack_worker_32 (eax, eax);
       insn = emit_insn (insn);
-      RTX_FRAME_RELATED_P (insn) = 1;
-      t = gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (-allocate));
-      t = gen_rtx_SET (VOIDmode, stack_pointer_rtx, t);
-      REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
-                                           t, REG_NOTES (insn));
+
+      if (ix86_cfa_state->reg == stack_pointer_rtx)
+       {
+         ix86_cfa_state->offset += allocate;
+         t = gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (-allocate));
+         t = gen_rtx_SET (VOIDmode, stack_pointer_rtx, t);
+         add_reg_note (insn, REG_CFA_ADJUST_CFA, t);
+         RTX_FRAME_RELATED_P (insn) = 1;
+       }
 
       if (eax_live)
        {
@@ -6553,15 +8530,29 @@ ix86_expand_prologue (void)
     }
 
   if (frame.save_regs_using_mov
-      && !(TARGET_RED_ZONE
+      && !(!TARGET_64BIT_MS_ABI && TARGET_RED_ZONE
          && (! TARGET_STACK_PROBE || allocate < CHECK_STACK_LIMIT)))
     {
-      if (!frame_pointer_needed || !frame.to_allocate)
-        ix86_emit_save_regs_using_mov (stack_pointer_rtx, frame.to_allocate);
+      if (!frame_pointer_needed
+         || !frame.to_allocate
+         || crtl->stack_realign_needed)
+        ix86_emit_save_regs_using_mov (stack_pointer_rtx,
+                                      frame.to_allocate
+                                      + frame.nsseregs * 16 + frame.padding0);
       else
         ix86_emit_save_regs_using_mov (hard_frame_pointer_rtx,
                                       -frame.nregs * UNITS_PER_WORD);
     }
+  if (!frame_pointer_needed
+      || !frame.to_allocate
+      || crtl->stack_realign_needed)
+    ix86_emit_save_sse_regs_using_mov (stack_pointer_rtx,
+                                      frame.to_allocate);
+  else
+    ix86_emit_save_sse_regs_using_mov (hard_frame_pointer_rtx,
+                                      - frame.nregs * UNITS_PER_WORD
+                                      - frame.nsseregs * 16
+                                      - frame.padding0);
 
   pic_reg_used = false;
   if (pic_offset_table_rtx
@@ -6599,13 +8590,116 @@ ix86_expand_prologue (void)
         insn = emit_insn (gen_set_got (pic_offset_table_rtx));
     }
 
-  /* Prevent function calls from being scheduled before the call to mcount.
-     In the pic_reg_used case, make sure that the got load isn't deleted.  */
-  if (crtl->profile)
+  /* In the pic_reg_used case, make sure that the got load isn't deleted
+     when mcount needs it.  Blockage to avoid call movement across mcount
+     call is emitted in generic code after the NOTE_INSN_PROLOGUE_END
+     note.  */
+  if (crtl->profile && pic_reg_used)
+    emit_insn (gen_prologue_use (pic_offset_table_rtx));
+
+  if (crtl->drap_reg && !crtl->stack_realign_needed)
+    {
+      /* vDRAP is setup but after reload it turns out stack realign
+         isn't necessary, here we will emit prologue to setup DRAP
+         without stack realign adjustment */
+      int drap_bp_offset = UNITS_PER_WORD * 2;
+      rtx x = plus_constant (hard_frame_pointer_rtx, drap_bp_offset);
+      insn = emit_insn (gen_rtx_SET (VOIDmode, crtl->drap_reg, x));
+    }
+
+  /* Prevent instructions from being scheduled into register save push
+     sequence when access to the redzone area is done through frame pointer.
+     The offset betweeh the frame pointer and the stack pointer is calculated
+     relative to the value of the stack pointer at the end of the function
+     prologue, and moving instructions that access redzone area via frame
+     pointer inside push sequence violates this assumption.  */
+  if (frame_pointer_needed && frame.red_zone_size)
+    emit_insn (gen_memory_blockage ());
+
+  /* Emit cld instruction if stringops are used in the function.  */
+  if (TARGET_CLD && ix86_current_function_needs_cld)
+    emit_insn (gen_cld ());
+}
+
+/* Emit code to restore REG using a POP insn.  */
+
+static void
+ix86_emit_restore_reg_using_pop (rtx reg, HOST_WIDE_INT red_offset)
+{
+  rtx insn = emit_insn (ix86_gen_pop1 (reg));
+
+  if (ix86_cfa_state->reg == crtl->drap_reg
+      && REGNO (reg) == REGNO (crtl->drap_reg))
+    {
+      /* Previously we'd represented the CFA as an expression
+        like *(%ebp - 8).  We've just popped that value from
+        the stack, which means we need to reset the CFA to
+        the drap register.  This will remain until we restore
+        the stack pointer.  */
+      add_reg_note (insn, REG_CFA_DEF_CFA, reg);
+      RTX_FRAME_RELATED_P (insn) = 1;
+      return;
+    }
+
+  if (ix86_cfa_state->reg == stack_pointer_rtx)
+    {
+      ix86_cfa_state->offset -= UNITS_PER_WORD;
+      add_reg_note (insn, REG_CFA_ADJUST_CFA,
+                   copy_rtx (XVECEXP (PATTERN (insn), 0, 1)));
+      RTX_FRAME_RELATED_P (insn) = 1;
+    }
+
+  /* When the frame pointer is the CFA, and we pop it, we are
+     swapping back to the stack pointer as the CFA.  This happens
+     for stack frames that don't allocate other data, so we assume
+     the stack pointer is now pointing at the return address, i.e.
+     the function entry state, which makes the offset be 1 word.  */
+  else if (ix86_cfa_state->reg == hard_frame_pointer_rtx
+          && reg == hard_frame_pointer_rtx)
+    {
+      ix86_cfa_state->reg = stack_pointer_rtx;
+      ix86_cfa_state->offset = UNITS_PER_WORD;
+
+      add_reg_note (insn, REG_CFA_DEF_CFA,
+                   gen_rtx_PLUS (Pmode, stack_pointer_rtx,
+                                 GEN_INT (UNITS_PER_WORD)));
+      RTX_FRAME_RELATED_P (insn) = 1;
+    }
+
+  ix86_add_cfa_restore_note (insn, reg, red_offset);
+}
+
+/* Emit code to restore saved registers using POP insns.  */
+
+static void
+ix86_emit_restore_regs_using_pop (HOST_WIDE_INT red_offset)
+{
+  int regno;
+
+  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+    if (!SSE_REGNO_P (regno) && ix86_save_reg (regno, false))
+      {
+       ix86_emit_restore_reg_using_pop (gen_rtx_REG (Pmode, regno),
+                                        red_offset);
+       red_offset += UNITS_PER_WORD;
+      }
+}
+
+/* Emit code and notes for the LEAVE instruction.  */
+
+static void
+ix86_emit_leave (HOST_WIDE_INT red_offset)
+{
+  rtx insn = emit_insn (ix86_gen_leave ());
+
+  ix86_add_queued_cfa_restore_notes (insn);
+
+  if (ix86_cfa_state->reg == hard_frame_pointer_rtx)
     {
-      if (pic_reg_used)
-       emit_insn (gen_prologue_use (pic_offset_table_rtx));
-      emit_insn (gen_blockage ());
+      add_reg_note (insn, REG_CFA_ADJUST_CFA, 
+                   copy_rtx (XVECEXP (PATTERN (insn), 0, 0)));
+      RTX_FRAME_RELATED_P (insn) = 1;
+      ix86_add_cfa_restore_note (insn, hard_frame_pointer_rtx, red_offset);
     }
 }
 
@@ -6613,14 +8707,18 @@ ix86_expand_prologue (void)
    is restored from POINTER + OFFSET.  */
 static void
 ix86_emit_restore_regs_using_mov (rtx pointer, HOST_WIDE_INT offset,
+                                 HOST_WIDE_INT red_offset,
                                  int maybe_eh_return)
 {
-  int regno;
+  unsigned int regno;
   rtx base_address = gen_rtx_MEM (Pmode, pointer);
+  rtx insn;
 
   for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
-    if (ix86_save_reg (regno, maybe_eh_return))
+    if (!SSE_REGNO_P (regno) && ix86_save_reg (regno, maybe_eh_return))
       {
+       rtx reg = gen_rtx_REG (Pmode, regno);
+
        /* Ensure that adjust_address won't be forced to produce pointer
           out of range allowed by x86-64 instruction set.  */
        if (TARGET_64BIT && offset != trunc_int_for_mode (offset, SImode))
@@ -6633,9 +8731,64 @@ ix86_emit_restore_regs_using_mov (rtx pointer, HOST_WIDE_INT offset,
            base_address = gen_rtx_MEM (Pmode, r11);
            offset = 0;
          }
-       emit_move_insn (gen_rtx_REG (Pmode, regno),
-                       adjust_address (base_address, Pmode, offset));
+       insn = emit_move_insn (reg,
+                              adjust_address (base_address, Pmode, offset));
        offset += UNITS_PER_WORD;
+
+        if (ix86_cfa_state->reg == crtl->drap_reg
+           && regno == REGNO (crtl->drap_reg))
+         {
+           /* Previously we'd represented the CFA as an expression
+              like *(%ebp - 8).  We've just popped that value from
+              the stack, which means we need to reset the CFA to
+              the drap register.  This will remain until we restore
+              the stack pointer.  */
+           add_reg_note (insn, REG_CFA_DEF_CFA, reg);
+           RTX_FRAME_RELATED_P (insn) = 1;
+         }
+       else
+         ix86_add_cfa_restore_note (NULL_RTX, reg, red_offset);
+
+       red_offset += UNITS_PER_WORD;
+      }
+}
+
+/* Emit code to restore saved registers using MOV insns.  First register
+   is restored from POINTER + OFFSET.  */
+static void
+ix86_emit_restore_sse_regs_using_mov (rtx pointer, HOST_WIDE_INT offset,
+                                     HOST_WIDE_INT red_offset,
+                                     int maybe_eh_return)
+{
+  int regno;
+  rtx base_address = gen_rtx_MEM (TImode, pointer);
+  rtx mem, insn;
+
+  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+    if (SSE_REGNO_P (regno) && ix86_save_reg (regno, maybe_eh_return))
+      {
+       rtx reg = gen_rtx_REG (TImode, regno);
+
+       /* Ensure that adjust_address won't be forced to produce pointer
+          out of range allowed by x86-64 instruction set.  */
+       if (TARGET_64BIT && offset != trunc_int_for_mode (offset, SImode))
+         {
+           rtx r11;
+
+           r11 = gen_rtx_REG (DImode, R11_REG);
+           emit_move_insn (r11, GEN_INT (offset));
+           emit_insn (gen_adddi3 (r11, r11, pointer));
+           base_address = gen_rtx_MEM (TImode, r11);
+           offset = 0;
+         }
+       mem = adjust_address (base_address, TImode, offset);
+       set_mem_align (mem, 128);
+       insn = emit_move_insn (reg, mem);
+       offset += 16;
+
+       ix86_add_cfa_restore_note (NULL_RTX, reg, red_offset);
+
+       red_offset += 16;
       }
 }
 
@@ -6644,13 +8797,29 @@ ix86_emit_restore_regs_using_mov (rtx pointer, HOST_WIDE_INT offset,
 void
 ix86_expand_epilogue (int style)
 {
-  int regno;
-  int sp_valid = !frame_pointer_needed || current_function_sp_is_unchanging;
+  int sp_valid;
   struct ix86_frame frame;
-  HOST_WIDE_INT offset;
+  HOST_WIDE_INT offset, red_offset;
+  struct machine_cfa_state cfa_state_save = *ix86_cfa_state;
+  bool using_drap;
+
+  ix86_finalize_stack_realign_flags ();
+
+ /* When stack is realigned, SP must be valid.  */
+  sp_valid = (!frame_pointer_needed
+             || current_function_sp_is_unchanging
+             || stack_realign_fp);
 
   ix86_compute_frame_layout (&frame);
 
+  /* See the comment about red zone and frame
+     pointer usage in ix86_expand_prologue.  */
+  if (frame_pointer_needed && frame.red_zone_size)
+    emit_insn (gen_memory_blockage ()); 
+
+  using_drap = crtl->drap_reg && crtl->stack_realign_needed;
+  gcc_assert (!using_drap || ix86_cfa_state->reg == crtl->drap_reg);
+
   /* Calculate start of saved registers relative to ebp.  Special care
      must be taken for the normal return case of a function using
      eh_return: the eax and edx registers are marked as saved, but not
@@ -6659,6 +8828,20 @@ ix86_expand_epilogue (int style)
   if (crtl->calls_eh_return && style != 2)
     offset -= 2;
   offset *= -UNITS_PER_WORD;
+  offset -= frame.nsseregs * 16 + frame.padding0;
+
+  /* Calculate start of saved registers relative to esp on entry of the
+     function.  When realigning stack, this needs to be the most negative
+     value possible at runtime.  */
+  red_offset = offset;
+  if (using_drap)
+    red_offset -= crtl->stack_alignment_needed / BITS_PER_UNIT
+                 + UNITS_PER_WORD;
+  else if (stack_realign_fp)
+    red_offset -= crtl->stack_alignment_needed / BITS_PER_UNIT
+                 - UNITS_PER_WORD;
+  if (frame_pointer_needed)
+    red_offset -= UNITS_PER_WORD;
 
   /* If we're only restoring one register and sp is not valid then
      using a move instruction to restore the register since it's
@@ -6670,138 +8853,252 @@ ix86_expand_epilogue (int style)
      are no registers to restore.  We also use this code when TARGET_USE_LEAVE
      and there is exactly one register to pop. This heuristic may need some
      tuning in future.  */
-  if ((!sp_valid && frame.nregs <= 1)
+  if ((!sp_valid && (frame.nregs + frame.nsseregs) <= 1)
       || (TARGET_EPILOGUE_USING_MOVE
          && cfun->machine->use_fast_prologue_epilogue
-         && (frame.nregs > 1 || frame.to_allocate))
-      || (frame_pointer_needed && !frame.nregs && frame.to_allocate)
+         && ((frame.nregs + frame.nsseregs) > 1 || frame.to_allocate))
+      || (frame_pointer_needed && !(frame.nregs + frame.nsseregs)
+         && frame.to_allocate)
       || (frame_pointer_needed && TARGET_USE_LEAVE
          && cfun->machine->use_fast_prologue_epilogue
-         && frame.nregs == 1)
+         && (frame.nregs + frame.nsseregs) == 1)
       || crtl->calls_eh_return)
     {
       /* Restore registers.  We can use ebp or esp to address the memory
         locations.  If both are available, default to ebp, since offsets
-        are known to be small.  Only exception is esp pointing directly to the
-        end of block of saved registers, where we may simplify addressing
-        mode.  */
-
-      if (!frame_pointer_needed || (sp_valid && !frame.to_allocate))
-       ix86_emit_restore_regs_using_mov (stack_pointer_rtx,
-                                         frame.to_allocate, style == 2);
+        are known to be small.  Only exception is esp pointing directly
+        to the end of block of saved registers, where we may simplify
+        addressing mode.  
+
+        If we are realigning stack with bp and sp, regs restore can't
+        be addressed by bp. sp must be used instead.  */
+
+      if (!frame_pointer_needed
+         || (sp_valid && !frame.to_allocate) 
+         || stack_realign_fp)
+       {
+         ix86_emit_restore_sse_regs_using_mov (stack_pointer_rtx,
+                                               frame.to_allocate, red_offset,
+                                               style == 2);
+         ix86_emit_restore_regs_using_mov (stack_pointer_rtx,
+                                           frame.to_allocate
+                                           + frame.nsseregs * 16
+                                           + frame.padding0,
+                                           red_offset
+                                           + frame.nsseregs * 16
+                                           + frame.padding0, style == 2);
+       }
       else
-       ix86_emit_restore_regs_using_mov (hard_frame_pointer_rtx,
-                                         offset, style == 2);
+        {
+         ix86_emit_restore_sse_regs_using_mov (hard_frame_pointer_rtx,
+                                               offset, red_offset,
+                                               style == 2);
+         ix86_emit_restore_regs_using_mov (hard_frame_pointer_rtx,
+                                           offset
+                                           + frame.nsseregs * 16
+                                           + frame.padding0,
+                                           red_offset
+                                           + frame.nsseregs * 16
+                                           + frame.padding0, style == 2);
+        }
+
+      red_offset -= offset;
 
       /* eh_return epilogues need %ecx added to the stack pointer.  */
       if (style == 2)
        {
          rtx tmp, sa = EH_RETURN_STACKADJ_RTX;
 
+         /* Stack align doesn't work with eh_return.  */
+         gcc_assert (!crtl->stack_realign_needed);
+
          if (frame_pointer_needed)
            {
              tmp = gen_rtx_PLUS (Pmode, hard_frame_pointer_rtx, sa);
              tmp = plus_constant (tmp, UNITS_PER_WORD);
-             emit_insn (gen_rtx_SET (VOIDmode, sa, tmp));
+             tmp = emit_insn (gen_rtx_SET (VOIDmode, sa, tmp));
 
              tmp = gen_rtx_MEM (Pmode, hard_frame_pointer_rtx);
-             emit_move_insn (hard_frame_pointer_rtx, tmp);
+             tmp = emit_move_insn (hard_frame_pointer_rtx, tmp);
+
+             /* Note that we use SA as a temporary CFA, as the return
+                address is at the proper place relative to it.  We
+                pretend this happens at the FP restore insn because
+                prior to this insn the FP would be stored at the wrong
+                offset relative to SA, and after this insn we have no
+                other reasonable register to use for the CFA.  We don't
+                bother resetting the CFA to the SP for the duration of
+                the return insn.  */
+             add_reg_note (tmp, REG_CFA_DEF_CFA,
+                           plus_constant (sa, UNITS_PER_WORD));
+             ix86_add_queued_cfa_restore_notes (tmp);
+             add_reg_note (tmp, REG_CFA_RESTORE, hard_frame_pointer_rtx);
+             RTX_FRAME_RELATED_P (tmp) = 1;
+             ix86_cfa_state->reg = sa;
+             ix86_cfa_state->offset = UNITS_PER_WORD;
 
              pro_epilogue_adjust_stack (stack_pointer_rtx, sa,
-                                        const0_rtx, style);
+                                        const0_rtx, style, false);
            }
          else
            {
              tmp = gen_rtx_PLUS (Pmode, stack_pointer_rtx, sa);
              tmp = plus_constant (tmp, (frame.to_allocate
-                                         + frame.nregs * UNITS_PER_WORD));
-             emit_insn (gen_rtx_SET (VOIDmode, stack_pointer_rtx, tmp));
+                                         + frame.nregs * UNITS_PER_WORD
+                                        + frame.nsseregs * 16
+                                        + frame.padding0));
+             tmp = emit_insn (gen_rtx_SET (VOIDmode, stack_pointer_rtx, tmp));
+             ix86_add_queued_cfa_restore_notes (tmp);
+
+             gcc_assert (ix86_cfa_state->reg == stack_pointer_rtx);
+             if (ix86_cfa_state->offset != UNITS_PER_WORD)
+               {
+                 ix86_cfa_state->offset = UNITS_PER_WORD;
+                 add_reg_note (tmp, REG_CFA_DEF_CFA,
+                               plus_constant (stack_pointer_rtx,
+                                              UNITS_PER_WORD));
+                 RTX_FRAME_RELATED_P (tmp) = 1;
+               }
            }
        }
       else if (!frame_pointer_needed)
        pro_epilogue_adjust_stack (stack_pointer_rtx, stack_pointer_rtx,
                                   GEN_INT (frame.to_allocate
-                                           + frame.nregs * UNITS_PER_WORD),
-                                  style);
+                                           + frame.nregs * UNITS_PER_WORD
+                                           + frame.nsseregs * 16
+                                           + frame.padding0),
+                                  style, !using_drap);
       /* If not an i386, mov & pop is faster than "leave".  */
-      else if (TARGET_USE_LEAVE || optimize_size
+      else if (TARGET_USE_LEAVE || optimize_function_for_size_p (cfun)
               || !cfun->machine->use_fast_prologue_epilogue)
-       emit_insn (TARGET_64BIT ? gen_leave_rex64 () : gen_leave ());
+       ix86_emit_leave (red_offset);
       else
        {
          pro_epilogue_adjust_stack (stack_pointer_rtx,
                                     hard_frame_pointer_rtx,
-                                    const0_rtx, style);
-         if (TARGET_64BIT)
-           emit_insn (gen_popdi1 (hard_frame_pointer_rtx));
-         else
-           emit_insn (gen_popsi1 (hard_frame_pointer_rtx));
+                                    const0_rtx, style, !using_drap);
+
+         ix86_emit_restore_reg_using_pop (hard_frame_pointer_rtx, red_offset);
        }
     }
   else
     {
       /* First step is to deallocate the stack frame so that we can
-        pop the registers.  */
+        pop the registers.
+
+        If we realign stack with frame pointer, then stack pointer
+         won't be able to recover via lea $offset(%bp), %sp, because
+         there is a padding area between bp and sp for realign. 
+         "add $to_allocate, %sp" must be used instead.  */
       if (!sp_valid)
        {
          gcc_assert (frame_pointer_needed);
+          gcc_assert (!stack_realign_fp);
          pro_epilogue_adjust_stack (stack_pointer_rtx,
                                     hard_frame_pointer_rtx,
-                                    GEN_INT (offset), style);
-       }
-      else if (frame.to_allocate)
-       pro_epilogue_adjust_stack (stack_pointer_rtx, stack_pointer_rtx,
-                                  GEN_INT (frame.to_allocate), style);
+                                    GEN_INT (offset), style, false);
+          ix86_emit_restore_sse_regs_using_mov (stack_pointer_rtx,
+                                               frame.to_allocate, red_offset,
+                                               style == 2);
+         pro_epilogue_adjust_stack (stack_pointer_rtx, stack_pointer_rtx,
+                                    GEN_INT (frame.nsseregs * 16),
+                                    style, false);
+       }
+      else if (frame.to_allocate || frame.nsseregs)
+       {
+          ix86_emit_restore_sse_regs_using_mov (stack_pointer_rtx,
+                                               frame.to_allocate, red_offset,
+                                               style == 2);
+         pro_epilogue_adjust_stack (stack_pointer_rtx, stack_pointer_rtx,
+                                    GEN_INT (frame.to_allocate
+                                             + frame.nsseregs * 16
+                                             + frame.padding0), style,
+                                    !using_drap && !frame_pointer_needed);
+       }
+
+      ix86_emit_restore_regs_using_pop (red_offset + frame.nsseregs * 16
+                                       + frame.padding0);
+      red_offset -= offset;
 
-      for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
-       if (ix86_save_reg (regno, false))
-         {
-           if (TARGET_64BIT)
-             emit_insn (gen_popdi1 (gen_rtx_REG (Pmode, regno)));
-           else
-             emit_insn (gen_popsi1 (gen_rtx_REG (Pmode, regno)));
-         }
       if (frame_pointer_needed)
        {
          /* Leave results in shorter dependency chains on CPUs that are
             able to grok it fast.  */
          if (TARGET_USE_LEAVE)
-           emit_insn (TARGET_64BIT ? gen_leave_rex64 () : gen_leave ());
-         else if (TARGET_64BIT)
-           emit_insn (gen_popdi1 (hard_frame_pointer_rtx));
+           ix86_emit_leave (red_offset);
          else
-           emit_insn (gen_popsi1 (hard_frame_pointer_rtx));
+            {
+              /* For stack realigned really happens, recover stack 
+                 pointer to hard frame pointer is a must, if not using 
+                 leave.  */
+              if (stack_realign_fp)
+               pro_epilogue_adjust_stack (stack_pointer_rtx,
+                                          hard_frame_pointer_rtx,
+                                          const0_rtx, style, !using_drap);
+             ix86_emit_restore_reg_using_pop (hard_frame_pointer_rtx,
+                                              red_offset);
+            }
        }
     }
 
-  if (cfun->machine->force_align_arg_pointer)
+  if (using_drap)
     {
-      emit_insn (gen_addsi3 (stack_pointer_rtx,
-                            cfun->machine->force_align_arg_pointer,
-                            GEN_INT (-4)));
+      int param_ptr_offset = (call_used_regs[REGNO (crtl->drap_reg)]
+                             ? 0 : UNITS_PER_WORD);
+      rtx insn;
+
+      gcc_assert (stack_realign_drap);
+
+      insn = emit_insn ((*ix86_gen_add3) (stack_pointer_rtx,
+                                         crtl->drap_reg,
+                                         GEN_INT (-(UNITS_PER_WORD
+                                                    + param_ptr_offset))));
+
+      ix86_cfa_state->reg = stack_pointer_rtx;
+      ix86_cfa_state->offset = UNITS_PER_WORD + param_ptr_offset;
+
+      add_reg_note (insn, REG_CFA_DEF_CFA,
+                   gen_rtx_PLUS (Pmode, ix86_cfa_state->reg,
+                                 GEN_INT (ix86_cfa_state->offset)));
+      RTX_FRAME_RELATED_P (insn) = 1;
+
+      if (param_ptr_offset)
+       ix86_emit_restore_reg_using_pop (crtl->drap_reg, -UNITS_PER_WORD);
     }
 
   /* Sibcall epilogues don't want a return instruction.  */
   if (style == 0)
-    return;
+    {
+      *ix86_cfa_state = cfa_state_save;
+      return;
+    }
 
   if (crtl->args.pops_args && crtl->args.size)
     {
       rtx popc = GEN_INT (crtl->args.pops_args);
 
-      /* i386 can only pop 64K bytes.  If asked to pop more, pop
-        return address, do explicit add, and jump indirectly to the
-        caller.  */
+      /* i386 can only pop 64K bytes.  If asked to pop more, pop return
+        address, do explicit add, and jump indirectly to the caller.  */
 
       if (crtl->args.pops_args >= 65536)
        {
          rtx ecx = gen_rtx_REG (SImode, CX_REG);
+         rtx insn;
 
          /* There is no "pascal" calling convention in any 64bit ABI.  */
          gcc_assert (!TARGET_64BIT);
 
-         emit_insn (gen_popsi1 (ecx));
-         emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, popc));
+         insn = emit_insn (gen_popsi1 (ecx));
+         ix86_cfa_state->offset -= UNITS_PER_WORD;
+
+         add_reg_note (insn, REG_CFA_ADJUST_CFA,
+                       copy_rtx (XVECEXP (PATTERN (insn), 0, 1)));
+         add_reg_note (insn, REG_CFA_REGISTER,
+                       gen_rtx_SET (VOIDmode, ecx, pc_rtx));
+         RTX_FRAME_RELATED_P (insn) = 1;
+
+         pro_epilogue_adjust_stack (stack_pointer_rtx, stack_pointer_rtx,
+                                    popc, -1, true);
          emit_jump_insn (gen_return_indirect_internal (ecx));
        }
       else
@@ -6809,6 +9106,10 @@ ix86_expand_epilogue (int style)
     }
   else
     emit_jump_insn (gen_return_internal ());
+
+  /* Restore the state back to the state from the prologue,
+     so that it's correct for the next epilogue.  */
+  *ix86_cfa_state = cfa_state_save;
 }
 
 /* Reset from the function's potential modifications.  */
@@ -6952,6 +9253,10 @@ ix86_decompose_address (rtx addr, struct ix86_address *out)
   base_reg = base && GET_CODE (base) == SUBREG ? SUBREG_REG (base) : base;
   index_reg = index && GET_CODE (index) == SUBREG ? SUBREG_REG (index) : index;
 
+  /* Avoid useless 0 displacement.  */
+  if (disp == const0_rtx && (base || index))
+    disp = NULL_RTX;
+
   /* Allow arg pointer and stack pointer as index if there is not scaling.  */
   if (base_reg && index_reg && scale == 1
       && (index_reg == arg_pointer_rtx
@@ -6963,22 +9268,30 @@ ix86_decompose_address (rtx addr, struct ix86_address *out)
       tmp = base_reg, base_reg = index_reg, index_reg = tmp;
     }
 
-  /* Special case: %ebp cannot be encoded as a base without a displacement.  */
-  if ((base_reg == hard_frame_pointer_rtx
-       || base_reg == frame_pointer_rtx
-       || base_reg == arg_pointer_rtx) && !disp)
+  /* Special case: %ebp cannot be encoded as a base without a displacement.
+     Similarly %r13.  */
+  if (!disp
+      && base_reg
+      && (base_reg == hard_frame_pointer_rtx
+         || base_reg == frame_pointer_rtx
+         || base_reg == arg_pointer_rtx
+         || (REG_P (base_reg)
+             && (REGNO (base_reg) == HARD_FRAME_POINTER_REGNUM
+                 || REGNO (base_reg) == R13_REG))))
     disp = const0_rtx;
 
   /* Special case: on K6, [%esi] makes the instruction vector decoded.
-     Avoid this by transforming to [%esi+0].  */
-  if (TARGET_K6 && !optimize_size
+     Avoid this by transforming to [%esi+0].
+     Reload calls address legitimization without cfun defined, so we need
+     to test cfun for being non-NULL. */
+  if (TARGET_K6 && cfun && optimize_function_for_speed_p (cfun)
       && base_reg && !index_reg && !disp
       && REG_P (base_reg)
       && REGNO_REG_CLASS (REGNO (base_reg)) == SIREG)
     disp = const0_rtx;
 
   /* Special case: encode reg+reg instead of reg*2.  */
-  if (!base && index && scale && scale == 2)
+  if (!base && index && scale == 2)
     base = index, base_reg = index_reg, scale = 1;
 
   /* Special case: scaling cannot be encoded without base or displacement.  */
@@ -7000,7 +9313,7 @@ ix86_decompose_address (rtx addr, struct ix86_address *out)
    requires to two regs - that would mean more pseudos with longer
    lifetimes.  */
 static int
-ix86_address_cost (rtx x)
+ix86_address_cost (rtx x, bool speed ATTRIBUTE_UNUSED)
 {
   struct ix86_address parts;
   int cost = 1;
@@ -7059,19 +9372,8 @@ ix86_address_cost (rtx x)
 static bool
 darwin_local_data_pic (rtx disp)
 {
-  if (GET_CODE (disp) == MINUS)
-    {
-      if (GET_CODE (XEXP (disp, 0)) == LABEL_REF
-          || GET_CODE (XEXP (disp, 0)) == SYMBOL_REF)
-        if (GET_CODE (XEXP (disp, 1)) == SYMBOL_REF)
-          {
-            const char *sym_name = XSTR (XEXP (disp, 1), 0);
-            if (! strcmp (sym_name, "<pic base>"))
-              return true;
-          }
-    }
-
-  return false;
+  return (GET_CODE (disp) == UNSPEC
+         && XINT (disp, 1) == UNSPEC_MACHOPIC_OFFSET);
 }
 
 /* Determine if a given RTX is a valid constant.  We already know this
@@ -7142,9 +9444,8 @@ legitimate_constant_p (rtx x)
       break;
 
     case CONST_VECTOR:
-      if (x == CONST0_RTX (GET_MODE (x)))
-       return true;
-      return false;
+      if (!standard_sse_constant_p (x))
+       return false;
 
     default:
       break;
@@ -7175,13 +9476,6 @@ ix86_cannot_force_const_mem (rtx x)
   return !legitimate_constant_p (x);
 }
 
-/* Determine if a given RTX is a valid constant address.  */
-
-bool
-constant_address_p (rtx x)
-{
-  return CONSTANT_P (x) && legitimate_address_p (Pmode, x, 1);
-}
 
 /* Nonzero if the constant value X is a legitimate general operand
    when generating PIC code.  It is given that flag_pic is on and
@@ -7212,6 +9506,8 @@ legitimate_pic_operand_p (rtx x)
            x = XVECEXP (inner, 0, 0);
            return (GET_CODE (x) == SYMBOL_REF
                    && SYMBOL_REF_TLS_MODEL (x) == TLS_MODEL_LOCAL_EXEC);
+         case UNSPEC_MACHOPIC_OFFSET:
+           return legitimate_pic_address_disp_p (x);
          default:
            return false;
          }
@@ -7348,17 +9644,17 @@ legitimate_pic_address_disp_p (rtx disp)
   return 0;
 }
 
-/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression that is a valid
-   memory address for an instruction.  The MODE argument is the machine mode
-   for the MEM expression that wants to use this address.
+/* Recognizes RTL expressions that are valid memory addresses for an
+   instruction.  The MODE argument is the machine mode for the MEM
+   expression that wants to use this address.
 
    It only recognizes address in canonical form.  LEGITIMIZE_ADDRESS should
    convert common non-canonical forms to canonical form so that they will
    be recognized.  */
 
-int
-legitimate_address_p (enum machine_mode mode ATTRIBUTE_UNUSED,
-                     rtx addr, int strict)
+static bool
+ix86_legitimate_address_p (enum machine_mode mode ATTRIBUTE_UNUSED,
+                          rtx addr, bool strict)
 {
   struct ix86_address parts;
   rtx base, index, disp;
@@ -7474,7 +9770,8 @@ legitimate_address_p (enum machine_mode mode ATTRIBUTE_UNUSED,
       reason_rtx = disp;
 
       if (GET_CODE (disp) == CONST
-         && GET_CODE (XEXP (disp, 0)) == UNSPEC)
+         && GET_CODE (XEXP (disp, 0)) == UNSPEC
+         && XINT (XEXP (disp, 0), 1) != UNSPEC_MACHOPIC_OFFSET)
        switch (XINT (XEXP (disp, 0), 1))
          {
          /* Refuse GOTOFF and GOT in 64bit mode since it is always 64bit when
@@ -7581,6 +9878,14 @@ legitimate_address_p (enum machine_mode mode ATTRIBUTE_UNUSED,
  report_error:
   return FALSE;
 }
+
+/* Determine if a given RTX is a valid constant address.  */
+
+bool
+constant_address_p (rtx x)
+{
+  return CONSTANT_P (x) && ix86_legitimate_address_p (Pmode, x, 1);
+}
 \f
 /* Return a unique alias set for the GOT.  */
 
@@ -7608,7 +9913,7 @@ ix86_GOT_alias_set (void)
       differentiate them from global data objects.  The returned
       address is the PIC reg + an unspec constant.
 
-   GO_IF_LEGITIMATE_ADDRESS rejects symbolic references unless the PIC
+   TARGET_LEGITIMATE_ADDRESS_P rejects symbolic references unless the PIC
    reg also appears in the address.  */
 
 static rtx
@@ -7848,7 +10153,7 @@ get_thread_pointer (int to_reg)
   return reg;
 }
 
-/* A subroutine of legitimize_address and ix86_expand_move.  FOR_MOV is
+/* A subroutine of ix86_legitimize_address and ix86_expand_move.  FOR_MOV is
    false if we expect this to be used for a memory address and true if
    we expect to load the address into a register.  */
 
@@ -8037,7 +10342,8 @@ get_dllimport_decl (tree decl)
   *loc = h = GGC_NEW (struct tree_map);
   h->hash = in.hash;
   h->base.from = decl;
-  h->to = to = build_decl (VAR_DECL, NULL, ptr_type_node);
+  h->to = to = build_decl (DECL_SOURCE_LOCATION (decl),
+                          VAR_DECL, NULL, ptr_type_node);
   DECL_ARTIFICIAL (to) = 1;
   DECL_IGNORED_P (to) = 1;
   DECL_EXTERNAL (to) = 1;
@@ -8045,7 +10351,8 @@ get_dllimport_decl (tree decl)
 
   name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
   name = targetm.strip_name_encoding (name);
-  prefix = name[0] == FASTCALL_PREFIX  ?  "*__imp_": "*__imp__";
+  prefix = name[0] == FASTCALL_PREFIX || user_label_prefix[0] == 0
+    ? "*__imp_" : "*__imp__";
   namelen = strlen (name);
   prefixlen = strlen (prefix);
   imp_name = (char *) alloca (namelen + prefixlen + 1);
@@ -8091,9 +10398,6 @@ legitimize_dllimport_symbol (rtx symbol, bool want_reg)
    OLDX is the address as it was before break_out_memory_refs was called.
    In some cases it is useful to look at this to decide what needs to be done.
 
-   MODE and WIN are passed so that this macro can use
-   GO_IF_LEGITIMATE_ADDRESS.
-
    It is always safe for this macro to do nothing.  It exists to recognize
    opportunities to optimize the output.
 
@@ -8105,8 +10409,9 @@ legitimize_dllimport_symbol (rtx symbol, bool want_reg)
    When -fpic is used, special handling is needed for symbolic references.
    See comments by legitimize_pic_address in i386.c for details.  */
 
-rtx
-legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, enum machine_mode mode)
+static rtx
+ix86_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
+                        enum machine_mode mode)
 {
   int changed = 0;
   unsigned log;
@@ -8234,7 +10539,7 @@ legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, enum machine_mode mode)
            }
        }
 
-      if (changed && legitimate_address_p (mode, x, FALSE))
+      if (changed && ix86_legitimate_address_p (mode, x, FALSE))
        return x;
 
       if (GET_CODE (XEXP (x, 0)) == MULT)
@@ -8260,7 +10565,7 @@ legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, enum machine_mode mode)
          x = legitimize_pic_address (x, 0);
        }
 
-      if (changed && legitimate_address_p (mode, x, FALSE))
+      if (changed && ix86_legitimate_address_p (mode, x, FALSE))
        return x;
 
       if (REG_P (XEXP (x, 0)))
@@ -8325,7 +10630,7 @@ output_pic_addr_const (FILE *file, rtx x, int code)
 #endif
          assemble_name (file, name);
        }
-      if (!TARGET_MACHO && !TARGET_64BIT_MS_ABI
+      if (!TARGET_MACHO && !(TARGET_64BIT && DEFAULT_ABI == MS_ABI)
          && code == 'P' && ! SYMBOL_REF_LOCAL_P (x))
        fputs ("@PLT", file);
       break;
@@ -8436,6 +10741,12 @@ output_pic_addr_const (FILE *file, rtx x, int code)
        case UNSPEC_INDNTPOFF:
          fputs ("@INDNTPOFF", file);
          break;
+#if TARGET_MACHO
+       case UNSPEC_MACHOPIC_OFFSET:
+         putc ('-', file);
+         machopic_output_function_base_name (file);
+         break;
+#endif
        default:
          output_operand_lossage ("invalid UNSPEC as operand");
          break;
@@ -8468,6 +10779,20 @@ i386_output_dwarf_dtprel (FILE *file, int size, rtx x)
    }
 }
 
+/* Return true if X is a representation of the PIC register.  This copes
+   with calls from ix86_find_base_term, where the register might have
+   been replaced by a cselib value.  */
+
+static bool
+ix86_pic_register_p (rtx x)
+{
+  if (GET_CODE (x) == VALUE)
+    return (pic_offset_table_rtx
+           && rtx_equal_for_cselib_p (x, pic_offset_table_rtx));
+  else
+    return REG_P (x) && REGNO (x) == PIC_OFFSET_TABLE_REGNUM;
+}
+
 /* In the name of slightly smaller debug output, and to cater to
    general assembler lossage, recognize PIC+GOTOFF and turn it back
    into a direct symbol reference.
@@ -8506,19 +10831,16 @@ ix86_delegitimize_address (rtx orig_x)
       || GET_CODE (XEXP (x, 1)) != CONST)
     return orig_x;
 
-  if (REG_P (XEXP (x, 0))
-      && REGNO (XEXP (x, 0)) == PIC_OFFSET_TABLE_REGNUM)
+  if (ix86_pic_register_p (XEXP (x, 0)))
     /* %ebx + GOT/GOTOFF */
     ;
   else if (GET_CODE (XEXP (x, 0)) == PLUS)
     {
       /* %ebx + %reg * scale + GOT/GOTOFF */
       reg_addend = XEXP (x, 0);
-      if (REG_P (XEXP (reg_addend, 0))
-         && REGNO (XEXP (reg_addend, 0)) == PIC_OFFSET_TABLE_REGNUM)
+      if (ix86_pic_register_p (XEXP (reg_addend, 0)))
        reg_addend = XEXP (reg_addend, 1);
-      else if (REG_P (XEXP (reg_addend, 1))
-              && REGNO (XEXP (reg_addend, 1)) == PIC_OFFSET_TABLE_REGNUM)
+      else if (ix86_pic_register_p (XEXP (reg_addend, 1)))
        reg_addend = XEXP (reg_addend, 0);
       else
        return orig_x;
@@ -8545,13 +10867,13 @@ ix86_delegitimize_address (rtx orig_x)
 
   if (TARGET_MACHO && darwin_local_data_pic (x)
       && !MEM_P (orig_x))
-    result = XEXP (x, 0);
+    result = XVECEXP (x, 0, 0);
 
   if (! result)
     return orig_x;
 
   if (const_addend)
-    result = gen_rtx_PLUS (Pmode, result, const_addend);
+    result = gen_rtx_CONST (Pmode, gen_rtx_PLUS (Pmode, result, const_addend));
   if (reg_addend)
     result = gen_rtx_PLUS (Pmode, reg_addend, result);
   return result;
@@ -8579,22 +10901,10 @@ ix86_find_base_term (rtx x)
          || XINT (term, 1) != UNSPEC_GOTPCREL)
        return x;
 
-      term = XVECEXP (term, 0, 0);
-
-      if (GET_CODE (term) != SYMBOL_REF
-         && GET_CODE (term) != LABEL_REF)
-       return x;
-
-      return term;
+      return XVECEXP (term, 0, 0);
     }
 
-  term = ix86_delegitimize_address (x);
-
-  if (GET_CODE (term) != SYMBOL_REF
-      && GET_CODE (term) != LABEL_REF)
-    return x;
-
-  return term;
+  return ix86_delegitimize_address (x);
 }
 \f
 static void
@@ -8605,9 +10915,6 @@ put_condition_code (enum rtx_code code, enum machine_mode mode, int reverse,
 
   if (mode == CCFPmode || mode == CCFPUmode)
     {
-      enum rtx_code second_code, bypass_code;
-      ix86_fp_comparison_codes (code, &bypass_code, &code, &second_code);
-      gcc_assert (bypass_code == UNKNOWN && second_code == UNKNOWN);
       code = ix86_fp_compare_code_to_integer (code);
       mode = CCmode;
     }
@@ -8749,12 +11056,19 @@ put_condition_code (enum rtx_code code, enum machine_mode mode, int reverse,
    If CODE is 'b', pretend the mode is QImode.
    If CODE is 'k', pretend the mode is SImode.
    If CODE is 'q', pretend the mode is DImode.
+   If CODE is 'x', pretend the mode is V4SFmode.
+   If CODE is 't', pretend the mode is V8SFmode.
    If CODE is 'h', pretend the reg is the 'high' byte register.
-   If CODE is 'y', print "st(0)" instead of "st", if the reg is stack op.  */
+   If CODE is 'y', print "st(0)" instead of "st", if the reg is stack op.
+   If CODE is 'd', duplicate the operand for AVX instruction.
+ */
 
 void
 print_reg (rtx x, int code, FILE *file)
 {
+  const char *reg;
+  bool duplicated = code == 'd' && TARGET_AVX;
+
   gcc_assert (x == pc_rtx
              || (REGNO (x) != ARG_POINTER_REGNUM
                  && REGNO (x) != FRAME_POINTER_REGNUM
@@ -8784,6 +11098,10 @@ print_reg (rtx x, int code, FILE *file)
     code = 3;
   else if (code == 'h')
     code = 0;
+  else if (code == 'x')
+    code = 16;
+  else if (code == 't')
+    code = 32;
   else
     code = GET_MODE_SIZE (GET_MODE (x));
 
@@ -8815,12 +11133,14 @@ print_reg (rtx x, int code, FILE *file)
        }
       return;
     }
+
+  reg = NULL;
   switch (code)
     {
     case 3:
       if (STACK_TOP_P (x))
        {
-         fputs ("st(0)", file);
+         reg = "st(0)";
          break;
        }
       /* FALLTHRU */
@@ -8833,21 +11153,39 @@ print_reg (rtx x, int code, FILE *file)
     case 16:
     case 2:
     normal:
-      fputs (hi_reg_name[REGNO (x)], file);
+      reg = hi_reg_name[REGNO (x)];
       break;
     case 1:
       if (REGNO (x) >= ARRAY_SIZE (qi_reg_name))
        goto normal;
-      fputs (qi_reg_name[REGNO (x)], file);
+      reg = qi_reg_name[REGNO (x)];
       break;
     case 0:
       if (REGNO (x) >= ARRAY_SIZE (qi_high_reg_name))
        goto normal;
-      fputs (qi_high_reg_name[REGNO (x)], file);
+      reg = qi_high_reg_name[REGNO (x)];
+      break;
+    case 32:
+      if (SSE_REG_P (x))
+       {
+         gcc_assert (!duplicated);
+         putc ('y', file);
+         fputs (hi_reg_name[REGNO (x)] + 1, file);
+         return;
+       }
       break;
     default:
       gcc_unreachable ();
     }
+
+  fputs (reg, file);
+  if (duplicated)
+    {
+      if (ASSEMBLER_DIALECT == ASM_ATT)
+       fprintf (file, ", %%%s", reg);
+      else
+       fprintf (file, ", %s", reg);
+    }
 }
 
 /* Locate some local-dynamic symbol still in use by this function
@@ -8889,11 +11227,13 @@ get_some_local_dynamic_name (void)
    L,W,B,Q,S,T -- print the opcode suffix for specified size of operand.
    C -- print opcode suffix for set/cmov insn.
    c -- like C, but print reversed condition
+   E,e -- likewise, but for compare-and-branch fused insn.
    F,f -- likewise, but for floating-point.
    O -- if HAVE_AS_IX86_CMOV_SUN_SYNTAX, expand to "w.", "l." or "q.",
         otherwise nothing
    R -- print the prefix for register names.
    z -- print the opcode suffix for the size of the current operand.
+   Z -- likewise, with special suffixes for x87 instructions.
    * -- print a star (in certain assembler syntax)
    A -- print an absolute memory reference.
    w -- print the operand as if it's a "word" (HImode) even if it isn't.
@@ -8904,8 +11244,11 @@ get_some_local_dynamic_name (void)
    w --  likewise, print the HImode name of the register.
    k --  likewise, print the SImode name of the register.
    q --  likewise, print the DImode name of the register.
+   x --  likewise, print the V4SFmode name of the register.
+   t --  likewise, print the V8SFmode name of the register.
    h -- print the QImode name for a "high" register, either ah, bh, ch or dh.
    y -- print "st(0)" instead of "st" as a register.
+   d -- print duplicated register operand for AVX instruction.
    D -- print condition for SSE cmp instruction.
    P -- if PIC, print an @PLT suffix.
    X -- don't print any sort of PIC '@' suffix for a symbol.
@@ -8990,73 +11333,119 @@ print_operand (FILE *file, rtx x, int code)
          return;
 
        case 'z':
-         /* 387 opcodes don't get size suffixes if the operands are
-            registers.  */
-         if (STACK_REG_P (x))
-           return;
+         if (GET_MODE_CLASS (GET_MODE (x)) == MODE_INT)
+           {
+             /* Opcodes don't get size suffixes if using Intel opcodes.  */
+             if (ASSEMBLER_DIALECT == ASM_INTEL)
+               return;
+
+             switch (GET_MODE_SIZE (GET_MODE (x)))
+               {
+               case 1:
+                 putc ('b', file);
+                 return;
+
+               case 2:
+                 putc ('w', file);
+                 return;
+
+               case 4:
+                 putc ('l', file);
+                 return;
+
+               case 8:
+                 putc ('q', file);
+                 return;
+
+               default:
+                 output_operand_lossage
+                   ("invalid operand size for operand code '%c'", code);
+                 return;
+               }
+           }
+
+         if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
+           warning
+             (0, "non-integer operand used with operand code '%c'", code);
+         /* FALLTHRU */
 
-         /* Likewise if using Intel opcodes.  */
+       case 'Z':
+         /* 387 opcodes don't get size suffixes if using Intel opcodes.  */
          if (ASSEMBLER_DIALECT == ASM_INTEL)
            return;
 
-         /* This is the size of op from size of operand.  */
-         switch (GET_MODE_SIZE (GET_MODE (x)))
+         if (GET_MODE_CLASS (GET_MODE (x)) == MODE_INT)
            {
-           case 1:
-             putc ('b', file);
-             return;
-
-           case 2:
-             if (MEM_P (x))
+             switch (GET_MODE_SIZE (GET_MODE (x)))
                {
-#ifdef HAVE_GAS_FILDS_FISTS
+               case 2:
+#ifdef HAVE_AS_IX86_FILDS
                  putc ('s', file);
 #endif
                  return;
+
+               case 4:
+                 putc ('l', file);
+                 return;
+
+               case 8:
+#ifdef HAVE_AS_IX86_FILDQ
+                 putc ('q', file);
+#else
+                 fputs ("ll", file);
+#endif
+                 return;
+
+               default:
+                 break;
                }
-             else
-               putc ('w', file);
-             return;
+           }
+         else if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
+           {
+             /* 387 opcodes don't get size suffixes
+                if the operands are registers.  */
+             if (STACK_REG_P (x))
+               return;
 
-           case 4:
-             if (GET_MODE (x) == SFmode)
+             switch (GET_MODE_SIZE (GET_MODE (x)))
                {
+               case 4:
                  putc ('s', file);
                  return;
-               }
-             else
-               putc ('l', file);
-             return;
 
-           case 12:
-           case 16:
-             putc ('t', file);
-             return;
-
-           case 8:
-             if (GET_MODE_CLASS (GET_MODE (x)) == MODE_INT)
-               {
-#ifdef GAS_MNEMONICS
-                 putc ('q', file);
-#else
+               case 8:
                  putc ('l', file);
-                 putc ('l', file);
-#endif
+                 return;
+
+               case 12:
+               case 16:
+                 putc ('t', file);
+                 return;
+
+               default:
+                 break;
                }
-             else
-               putc ('l', file);
+           }
+         else
+           {
+             output_operand_lossage
+               ("invalid operand type used with operand code '%c'", code);
              return;
-
-           default:
-             gcc_unreachable ();
            }
 
+         output_operand_lossage
+           ("invalid operand size for operand code '%c'", code);
+         return;
+           
+       case 'd':
        case 'b':
        case 'w':
        case 'k':
        case 'q':
        case 'h':
+       case 't':
        case 'y':
+       case 'x':
        case 'X':
        case 'P':
          break;
@@ -9065,7 +11454,7 @@ print_operand (FILE *file, rtx x, int code)
          if (CONST_INT_P (x) || ! SHIFT_DOUBLE_OMITS_COUNT)
            {
              PRINT_OPERAND (file, x, 0);
-             putc (',', file);
+             fputs (", ", file);
            }
          return;
 
@@ -9073,40 +11462,95 @@ print_operand (FILE *file, rtx x, int code)
          /* Little bit of braindamage here.  The SSE compare instructions
             does use completely different names for the comparisons that the
             fp conditional moves.  */
-         switch (GET_CODE (x))
+         if (TARGET_AVX)
            {
-           case EQ:
-           case UNEQ:
-             fputs ("eq", file);
-             break;
-           case LT:
-           case UNLT:
-             fputs ("lt", file);
-             break;
-           case LE:
-           case UNLE:
-             fputs ("le", file);
-             break;
-           case UNORDERED:
-             fputs ("unord", file);
-             break;
-           case NE:
-           case LTGT:
-             fputs ("neq", file);
-             break;
-           case UNGE:
-           case GE:
-             fputs ("nlt", file);
-             break;
-           case UNGT:
-           case GT:
-             fputs ("nle", file);
-             break;
-           case ORDERED:
-             fputs ("ord", file);
-             break;
-           default:
-             gcc_unreachable ();
+             switch (GET_CODE (x))
+               {
+               case EQ:
+                 fputs ("eq", file);
+                 break;
+               case UNEQ:
+                 fputs ("eq_us", file);
+                 break;
+               case LT:
+                 fputs ("lt", file);
+                 break;
+               case UNLT:
+                 fputs ("nge", file);
+                 break;
+               case LE:
+                 fputs ("le", file);
+                 break;
+               case UNLE:
+                 fputs ("ngt", file);
+                 break;
+               case UNORDERED:
+                 fputs ("unord", file);
+                 break;
+               case NE:
+                 fputs ("neq", file);
+                 break;
+               case LTGT:
+                 fputs ("neq_oq", file);
+                 break;
+               case GE:
+                 fputs ("ge", file);
+                 break;
+               case UNGE:
+                 fputs ("nlt", file);
+                 break;
+               case GT:
+                 fputs ("gt", file);
+                 break;
+               case UNGT:
+                 fputs ("nle", file);
+                 break;
+               case ORDERED:
+                 fputs ("ord", file);
+                 break;
+               default:
+                 output_operand_lossage ("operand is not a condition code, invalid operand code 'D'");
+                 return;
+               }
+           }
+         else
+           {
+             switch (GET_CODE (x))
+               {
+               case EQ:
+               case UNEQ:
+                 fputs ("eq", file);
+                 break;
+               case LT:
+               case UNLT:
+                 fputs ("lt", file);
+                 break;
+               case LE:
+               case UNLE:
+                 fputs ("le", file);
+                 break;
+               case UNORDERED:
+                 fputs ("unord", file);
+                 break;
+               case NE:
+               case LTGT:
+                 fputs ("neq", file);
+                 break;
+               case UNGE:
+               case GE:
+                 fputs ("nlt", file);
+                 break;
+               case UNGT:
+               case GT:
+                 fputs ("nle", file);
+                 break;
+               case ORDERED:
+                 fputs ("ord", file);
+                 break;
+               default:
+                 output_operand_lossage ("operand is not a condition code, invalid operand code 'D'");
+                 return;
+               }
            }
          return;
        case 'O':
@@ -9127,9 +11571,23 @@ print_operand (FILE *file, rtx x, int code)
 #endif
          return;
        case 'C':
+         if (!COMPARISON_P (x))
+           {
+             output_operand_lossage ("operand is neither a constant nor a "
+                                     "condition code, invalid operand code "
+                                     "'C'");
+             return;
+           }
          put_condition_code (GET_CODE (x), GET_MODE (XEXP (x, 0)), 0, 0, file);
          return;
        case 'F':
+         if (!COMPARISON_P (x))
+           {
+             output_operand_lossage ("operand is neither a constant nor a "
+                                     "condition code, invalid operand code "
+                                     "'F'");
+             return;
+           }
 #ifdef HAVE_AS_IX86_CMOV_SUN_SYNTAX
          if (ASSEMBLER_DIALECT == ASM_ATT)
            putc ('.', file);
@@ -9142,13 +11600,22 @@ print_operand (FILE *file, rtx x, int code)
          /* Check to see if argument to %c is really a constant
             and not a condition code which needs to be reversed.  */
          if (!COMPARISON_P (x))
-         {
-           output_operand_lossage ("operand is neither a constant nor a condition code, invalid operand code 'c'");
-            return;
-         }
+           {
+             output_operand_lossage ("operand is neither a constant nor a "
+                                     "condition code, invalid operand "
+                                     "code 'c'");
+             return;
+           }
          put_condition_code (GET_CODE (x), GET_MODE (XEXP (x, 0)), 1, 0, file);
          return;
        case 'f':
+         if (!COMPARISON_P (x))
+           {
+             output_operand_lossage ("operand is neither a constant nor a "
+                                     "condition code, invalid operand "
+                                     "code 'f'");
+             return;
+           }
 #ifdef HAVE_AS_IX86_CMOV_SUN_SYNTAX
          if (ASSEMBLER_DIALECT == ASM_ATT)
            putc ('.', file);
@@ -9156,6 +11623,14 @@ print_operand (FILE *file, rtx x, int code)
          put_condition_code (GET_CODE (x), GET_MODE (XEXP (x, 0)), 1, 1, file);
          return;
 
+       case 'E':
+         put_condition_code (GET_CODE (x), CCmode, 0, 0, file);
+         return;
+
+       case 'e':
+         put_condition_code (GET_CODE (x), CCmode, 1, 0, file);
+         return;
+
        case 'H':
          /* It doesn't actually matter what mode we use here, as we're
             only going to use this for printing.  */
@@ -9166,7 +11641,8 @@ print_operand (FILE *file, rtx x, int code)
          {
            rtx x;
 
-           if (!optimize || optimize_size || !TARGET_BRANCH_PREDICTION_HINTS)
+           if (!optimize
+               || optimize_function_for_size_p (cfun) || !TARGET_BRANCH_PREDICTION_HINTS)
              return;
 
            x = find_reg_note (current_output_insn, REG_BR_PROB, 0);
@@ -9246,7 +11722,8 @@ print_operand (FILE *file, rtx x, int code)
              fputs ("une", file);
              break;
            default:
-             gcc_unreachable ();
+             output_operand_lossage ("operand is not a condition code, invalid operand code 'D'");
+             return;
            }
          return;
 
@@ -9254,7 +11731,7 @@ print_operand (FILE *file, rtx x, int code)
 #if TARGET_MACHO
          fputs (" ; ", file);
 #else
-         fputc (' ', file);
+         putc (' ', file);
 #endif
          return;
 
@@ -9332,7 +11809,7 @@ print_operand (FILE *file, rtx x, int code)
       char dstr[30];
 
       real_to_decimal (dstr, CONST_DOUBLE_REAL_VALUE (x), sizeof (dstr), 0, 1);
-      fprintf (file, "%s", dstr);
+      fputs (dstr, file);
     }
 
   else if (GET_CODE (x) == CONST_DOUBLE
@@ -9564,6 +12041,13 @@ output_addr_const_extra (FILE *file, rtx x)
       output_addr_const (file, op);
       fputs ("@INDNTPOFF", file);
       break;
+#if TARGET_MACHO
+    case UNSPEC_MACHOPIC_OFFSET:
+      output_addr_const (file, op);
+      putc ('-', file);
+      machopic_output_function_base_name (file);
+      break;
+#endif
 
     default:
       return false;
@@ -9651,7 +12135,7 @@ split_ti (rtx operands[], int num, rtx lo_half[], rtx hi_half[])
 const char *
 output_387_binary_op (rtx insn, rtx *operands)
 {
-  static char buf[30];
+  static char buf[40];
   const char *p;
   const char *ssep;
   int is_sse = SSE_REG_P (operands[0]) || SSE_REG_P (operands[1]) || SSE_REG_P (operands[2]);
@@ -9680,7 +12164,7 @@ output_387_binary_op (rtx insn, rtx *operands)
        p = "fiadd";
       else
        p = "fadd";
-      ssep = "add";
+      ssep = "vadd";
       break;
 
     case MINUS:
@@ -9689,7 +12173,7 @@ output_387_binary_op (rtx insn, rtx *operands)
        p = "fisub";
       else
        p = "fsub";
-      ssep = "sub";
+      ssep = "vsub";
       break;
 
     case MULT:
@@ -9698,7 +12182,7 @@ output_387_binary_op (rtx insn, rtx *operands)
        p = "fimul";
       else
        p = "fmul";
-      ssep = "mul";
+      ssep = "vmul";
       break;
 
     case DIV:
@@ -9707,7 +12191,7 @@ output_387_binary_op (rtx insn, rtx *operands)
        p = "fidiv";
       else
        p = "fdiv";
-      ssep = "div";
+      ssep = "vdiv";
       break;
 
     default:
@@ -9716,11 +12200,22 @@ output_387_binary_op (rtx insn, rtx *operands)
 
   if (is_sse)
    {
-      strcpy (buf, ssep);
-      if (GET_MODE (operands[0]) == SFmode)
-       strcat (buf, "ss\t{%2, %0|%0, %2}");
-      else
-       strcat (buf, "sd\t{%2, %0|%0, %2}");
+     if (TARGET_AVX)
+       {
+        strcpy (buf, ssep);
+        if (GET_MODE (operands[0]) == SFmode)
+          strcat (buf, "ss\t{%2, %1, %0|%0, %1, %2}");
+        else
+          strcat (buf, "sd\t{%2, %1, %0|%0, %1, %2}");
+       }
+     else
+       {
+        strcpy (buf, ssep + 1);
+        if (GET_MODE (operands[0]) == SFmode)
+          strcat (buf, "ss\t{%2, %0|%0, %2}");
+        else
+          strcat (buf, "sd\t{%2, %0|%0, %2}");
+       }
       return buf;
    }
   strcpy (buf, p);
@@ -9740,7 +12235,7 @@ output_387_binary_op (rtx insn, rtx *operands)
 
       if (MEM_P (operands[2]))
        {
-         p = "%z2\t%2";
+         p = "%Z2\t%2";
          break;
        }
 
@@ -9770,13 +12265,13 @@ output_387_binary_op (rtx insn, rtx *operands)
     case DIV:
       if (MEM_P (operands[1]))
        {
-         p = "r%z1\t%1";
+         p = "r%Z1\t%1";
          break;
        }
 
       if (MEM_P (operands[2]))
        {
-         p = "%z2\t%2";
+         p = "%Z2\t%2";
          break;
        }
 
@@ -9922,7 +12417,8 @@ emit_i387_cw_initialization (int mode)
   emit_insn (gen_x86_fnstcw_1 (stored_mode));
   emit_move_insn (reg, copy_rtx (stored_mode));
 
-  if (TARGET_64BIT || TARGET_PARTIAL_REG_STALL || optimize_size)
+  if (TARGET_64BIT || TARGET_PARTIAL_REG_STALL
+      || optimize_function_for_size_p (cfun))
     {
       switch (mode)
        {
@@ -10017,15 +12513,15 @@ output_fix_trunc (rtx insn, rtx *operands, int fisttp)
   gcc_assert (GET_MODE (operands[1]) != TFmode);
 
   if (fisttp)
-      output_asm_insn ("fisttp%z0\t%0", operands);
+      output_asm_insn ("fisttp%Z0\t%0", operands);
   else
     {
       if (round_mode != I387_CW_ANY)
        output_asm_insn ("fldcw\t%3", operands);
       if (stack_top_dies || dimode_p)
-       output_asm_insn ("fistp%z0\t%0", operands);
+       output_asm_insn ("fistp%Z0\t%0", operands);
       else
-       output_asm_insn ("fist%z0\t%0", operands);
+       output_asm_insn ("fist%Z0\t%0", operands);
       if (round_mode != I387_CW_ANY)
        output_asm_insn ("fldcw\t%2", operands);
     }
@@ -10041,16 +12537,18 @@ static const char *
 output_387_ffreep (rtx *operands ATTRIBUTE_UNUSED, int opno)
 {
   if (TARGET_USE_FFREEP)
-#if HAVE_AS_IX86_FFREEP
+#ifdef HAVE_AS_IX86_FFREEP
     return opno ? "ffreep\t%y1" : "ffreep\t%y0";
 #else
     {
-      static char retval[] = ".word\t0xc_df";
+      static char retval[32];
       int regno = REGNO (operands[opno]);
 
       gcc_assert (FP_REGNO_P (regno));
 
-      retval[9] = '0' + (regno - FIRST_STACK_REG);
+      regno -= FIRST_STACK_REG;
+
+      snprintf (retval, sizeof (retval), ASM_SHORT "0xc%ddf", regno);
       return retval;
     }
 #endif
@@ -10082,16 +12580,21 @@ output_fp_compare (rtx insn, rtx *operands, int eflags_p, int unordered_p)
 
   if (is_sse)
     {
+      static const char ucomiss[] = "vucomiss\t{%1, %0|%0, %1}";
+      static const char ucomisd[] = "vucomisd\t{%1, %0|%0, %1}";
+      static const char comiss[] = "vcomiss\t{%1, %0|%0, %1}";
+      static const char comisd[] = "vcomisd\t{%1, %0|%0, %1}";
+
       if (GET_MODE (operands[0]) == SFmode)
        if (unordered_p)
-         return "ucomiss\t{%1, %0|%0, %1}";
+         return &ucomiss[TARGET_AVX ? 0 : 1];
        else
-         return "comiss\t{%1, %0|%0, %1}";
+         return &comiss[TARGET_AVX ? 0 : 1];
       else
        if (unordered_p)
-         return "ucomisd\t{%1, %0|%0, %1}";
+         return &ucomisd[TARGET_AVX ? 0 : 1];
        else
-         return "comisd\t{%1, %0|%0, %1}";
+         return &comisd[TARGET_AVX ? 0 : 1];
     }
 
   gcc_assert (STACK_TOP_P (cmp_op0));
@@ -10142,13 +12645,13 @@ output_fp_compare (rtx insn, rtx *operands, int eflags_p, int unordered_p)
 
       static const char * const alt[16] =
       {
-       "fcom%z2\t%y2\n\tfnstsw\t%0",
-       "fcomp%z2\t%y2\n\tfnstsw\t%0",
-       "fucom%z2\t%y2\n\tfnstsw\t%0",
-       "fucomp%z2\t%y2\n\tfnstsw\t%0",
+       "fcom%Z2\t%y2\n\tfnstsw\t%0",
+       "fcomp%Z2\t%y2\n\tfnstsw\t%0",
+       "fucom%Z2\t%y2\n\tfnstsw\t%0",
+       "fucomp%Z2\t%y2\n\tfnstsw\t%0",
 
-       "ficom%z2\t%y2\n\tfnstsw\t%0",
-       "ficomp%z2\t%y2\n\tfnstsw\t%0",
+       "ficom%Z2\t%y2\n\tfnstsw\t%0",
+       "ficomp%Z2\t%y2\n\tfnstsw\t%0",
        NULL,
        NULL,
 
@@ -10191,7 +12694,7 @@ ix86_output_addr_vec_elt (FILE *file, int value)
   gcc_assert (!TARGET_64BIT);
 #endif
 
-  fprintf (file, "%s%s%d\n", directive, LPREFIX, value);
+  fprintf (file, "%s" LPREFIX "%d\n", directive, value);
 }
 
 void
@@ -10207,21 +12710,21 @@ ix86_output_addr_diff_elt (FILE *file, int value, int rel)
 #endif
   /* We can't use @GOTOFF for text labels on VxWorks; see gotoff_operand.  */
   if (TARGET_64BIT || TARGET_VXWORKS_RTP)
-    fprintf (file, "%s%s%d-%s%d\n",
-            directive, LPREFIX, value, LPREFIX, rel);
+    fprintf (file, "%s" LPREFIX "%d-" LPREFIX "%d\n",
+            directive, value, rel);
   else if (HAVE_AS_GOTOFF_IN_DATA)
-    fprintf (file, "%s%s%d@GOTOFF\n", ASM_LONG, LPREFIX, value);
+    fprintf (file, ASM_LONG LPREFIX "%d@GOTOFF\n", value);
 #if TARGET_MACHO
   else if (TARGET_MACHO)
     {
-      fprintf (file, "%s%s%d-", ASM_LONG, LPREFIX, value);
+      fprintf (file, ASM_LONG LPREFIX "%d-", value);
       machopic_output_function_base_name (file);
-      fprintf(file, "\n");
+      putc ('\n', file);
     }
 #endif
   else
-    asm_fprintf (file, "%s%U%s+[.-%s%d]\n",
-                ASM_LONG, GOT_SYMBOL_NAME, LPREFIX, value);
+    asm_fprintf (file, ASM_LONG "%U%s+[.-" LPREFIX "%d]\n",
+                GOT_SYMBOL_NAME, value);
 }
 \f
 /* Generate either "mov $0, reg" or "xor reg, reg", as appropriate
@@ -10241,7 +12744,7 @@ ix86_expand_clear (rtx dest)
   tmp = gen_rtx_SET (VOIDmode, dest, const0_rtx);
 
   /* This predicate should match that for movsi_xor and movdi_xor_rex64.  */
-  if (reload_completed && (!TARGET_USE_MOV0 || optimize_size))
+  if (reload_completed && (!TARGET_USE_MOV0 || optimize_insn_for_speed_p ()))
     {
       rtx clob = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, FLAGS_REG));
       tmp = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, tmp, clob));
@@ -10339,7 +12842,7 @@ ix86_expand_move (enum machine_mode mode, rtx operands[])
            op1 = force_reg (Pmode, op1);
          else if (!TARGET_64BIT || !x86_64_movabs_operand (op1, Pmode))
            {
-             rtx reg = !can_create_pseudo_p () ? op0 : NULL_RTX;
+             rtx reg = can_create_pseudo_p () ? NULL_RTX : op0;
              op1 = legitimize_pic_address (op1, reg);
              if (op0 == op1)
                return;
@@ -10408,12 +12911,10 @@ ix86_expand_vector_move (enum machine_mode mode, rtx operands[])
       && standard_sse_constant_p (op1) <= 0)
     op1 = validize_mem (force_const_mem (mode, op1));
 
-  /* TDmode values are passed as TImode on the stack.  TImode values
-     are moved via xmm registers, and moving them to stack can result in
-     unaligned memory access.  Use ix86_expand_vector_move_misalign()
-     if memory operand is not aligned correctly.  */
+  /* We need to check memory alignment for SSE mode since attribute
+     can make operands unaligned.  */
   if (can_create_pseudo_p ()
-      && (mode == TImode) && !TARGET_64BIT
+      && SSE_REG_MODE_P (mode)
       && ((MEM_P (op0) && (MEM_ALIGN (op0) < align))
          || (MEM_P (op1) && (MEM_ALIGN (op1) < align))))
     {
@@ -10507,10 +13008,62 @@ ix86_expand_vector_move_misalign (enum machine_mode mode, rtx operands[])
   op0 = operands[0];
   op1 = operands[1];
 
+  if (TARGET_AVX)
+    {
+      switch (GET_MODE_CLASS (mode))
+       {
+       case MODE_VECTOR_INT:
+       case MODE_INT:
+         switch (GET_MODE_SIZE (mode))
+           {
+           case 16:
+             op0 = gen_lowpart (V16QImode, op0);
+             op1 = gen_lowpart (V16QImode, op1);
+             emit_insn (gen_avx_movdqu (op0, op1));
+             break;
+           case 32:
+             op0 = gen_lowpart (V32QImode, op0);
+             op1 = gen_lowpart (V32QImode, op1);
+             emit_insn (gen_avx_movdqu256 (op0, op1));
+             break;
+           default:
+             gcc_unreachable ();
+           }
+         break;
+       case MODE_VECTOR_FLOAT:
+         op0 = gen_lowpart (mode, op0);
+         op1 = gen_lowpart (mode, op1);
+
+         switch (mode)
+           { 
+           case V4SFmode:
+             emit_insn (gen_avx_movups (op0, op1));
+             break;
+           case V8SFmode:
+             emit_insn (gen_avx_movups256 (op0, op1));
+             break;
+           case V2DFmode:
+             emit_insn (gen_avx_movupd (op0, op1));
+             break;
+           case V4DFmode:
+             emit_insn (gen_avx_movupd256 (op0, op1));
+             break;
+           default:
+             gcc_unreachable ();
+           }
+         break;
+
+       default:
+         gcc_unreachable ();
+       }
+
+      return;
+    }
+
   if (MEM_P (op1))
     {
       /* If we're optimizing for size, movups is the smallest.  */
-      if (optimize_size)
+      if (optimize_insn_for_size_p ())
        {
          op0 = gen_lowpart (V4SFmode, op0);
          op1 = gen_lowpart (V4SFmode, op1);
@@ -10545,7 +13098,7 @@ ix86_expand_vector_move_misalign (enum machine_mode mode, rtx operands[])
             writing to the top half twice.  */
          if (TARGET_SSE_SPLIT_REGS)
            {
-             emit_insn (gen_rtx_CLOBBER (VOIDmode, op0));
+             emit_clobber (op0);
              zero = op0;
            }
          else
@@ -10579,7 +13132,7 @@ ix86_expand_vector_move_misalign (enum machine_mode mode, rtx operands[])
          if (TARGET_SSE_PARTIAL_REG_DEPENDENCY)
            emit_move_insn (op0, CONST0_RTX (mode));
          else
-           emit_insn (gen_rtx_CLOBBER (VOIDmode, op0));
+           emit_clobber (op0);
 
          if (mode != V4SFmode)
            op0 = gen_lowpart (V4SFmode, op0);
@@ -10592,7 +13145,7 @@ ix86_expand_vector_move_misalign (enum machine_mode mode, rtx operands[])
   else if (MEM_P (op0))
     {
       /* If we're optimizing for size, movups is the smallest.  */
-      if (optimize_size)
+      if (optimize_insn_for_size_p ())
        {
          op0 = gen_lowpart (V4SFmode, op0);
          op1 = gen_lowpart (V4SFmode, op1);
@@ -10648,6 +13201,11 @@ ix86_expand_push (enum machine_mode mode, rtx x)
     emit_move_insn (stack_pointer_rtx, tmp);
 
   tmp = gen_rtx_MEM (mode, stack_pointer_rtx);
+
+  /* When we push an operand onto stack, it has to be aligned at least
+     at the function argument boundary.  However since we don't have
+     the argument type, we can't determine the actual argument
+     boundary.  */
   emit_move_insn (tmp, x);
 }
 
@@ -10878,6 +13436,316 @@ ix86_expand_unary_operator (enum rtx_code code, enum machine_mode mode,
     emit_move_insn (operands[0], dst);
 }
 
+#define LEA_SEARCH_THRESHOLD 12
+
+/* Search backward for non-agu definition of register number REGNO1
+   or register number REGNO2 in INSN's basic block until 
+   1. Pass LEA_SEARCH_THRESHOLD instructions, or
+   2. Reach BB boundary, or
+   3. Reach agu definition.
+   Returns the distance between the non-agu definition point and INSN.
+   If no definition point, returns -1.  */
+
+static int
+distance_non_agu_define (unsigned int regno1, unsigned int regno2,
+                        rtx insn)
+{
+  basic_block bb = BLOCK_FOR_INSN (insn);
+  int distance = 0;
+  df_ref *def_rec;
+  enum attr_type insn_type;
+
+  if (insn != BB_HEAD (bb))
+    {
+      rtx prev = PREV_INSN (insn);
+      while (prev && distance < LEA_SEARCH_THRESHOLD)
+       {
+         if (INSN_P (prev))
+           {
+             distance++;
+              for (def_rec = DF_INSN_DEFS (prev); *def_rec; def_rec++)
+                if (DF_REF_TYPE (*def_rec) == DF_REF_REG_DEF
+                    && !DF_REF_IS_ARTIFICIAL (*def_rec)
+                    && (regno1 == DF_REF_REGNO (*def_rec)
+                       || regno2 == DF_REF_REGNO (*def_rec)))
+                 {
+                   insn_type = get_attr_type (prev);
+                   if (insn_type != TYPE_LEA)
+                     goto done;
+                 }
+           }
+         if (prev == BB_HEAD (bb))
+           break;
+         prev = PREV_INSN (prev);
+       }
+    }
+  
+  if (distance < LEA_SEARCH_THRESHOLD)
+    {
+      edge e;
+      edge_iterator ei;
+      bool simple_loop = false;
+  
+      FOR_EACH_EDGE (e, ei, bb->preds)
+       if (e->src == bb)
+         {
+           simple_loop = true;
+           break;
+         }
+  
+      if (simple_loop)
+       {
+         rtx prev = BB_END (bb);
+         while (prev
+                && prev != insn
+                && distance < LEA_SEARCH_THRESHOLD)
+           {
+             if (INSN_P (prev))
+               {
+                 distance++;
+                 for (def_rec = DF_INSN_DEFS (prev); *def_rec; def_rec++)
+                   if (DF_REF_TYPE (*def_rec) == DF_REF_REG_DEF
+                       && !DF_REF_IS_ARTIFICIAL (*def_rec)
+                       && (regno1 == DF_REF_REGNO (*def_rec)
+                           || regno2 == DF_REF_REGNO (*def_rec)))
+                     {
+                       insn_type = get_attr_type (prev);
+                       if (insn_type != TYPE_LEA)
+                         goto done;
+                     }
+               }
+             prev = PREV_INSN (prev);
+           }
+       }
+    }
+
+  distance = -1;
+
+done:
+  /* get_attr_type may modify recog data.  We want to make sure
+     that recog data is valid for instruction INSN, on which
+     distance_non_agu_define is called.  INSN is unchanged here.  */
+  extract_insn_cached (insn);
+  return distance;
+}
+
+/* Return the distance between INSN and the next insn that uses 
+   register number REGNO0 in memory address.  Return -1 if no such
+   a use is found within LEA_SEARCH_THRESHOLD or REGNO0 is set.  */
+
+static int
+distance_agu_use (unsigned int regno0, rtx insn)
+{
+  basic_block bb = BLOCK_FOR_INSN (insn);
+  int distance = 0;
+  df_ref *def_rec;
+  df_ref *use_rec;
+
+  if (insn != BB_END (bb))
+    {
+      rtx next = NEXT_INSN (insn);
+      while (next && distance < LEA_SEARCH_THRESHOLD)
+       {
+         if (INSN_P (next))
+           {
+             distance++;
+
+             for (use_rec = DF_INSN_USES (next); *use_rec; use_rec++)
+               if ((DF_REF_TYPE (*use_rec) == DF_REF_REG_MEM_LOAD
+                    || DF_REF_TYPE (*use_rec) == DF_REF_REG_MEM_STORE)
+                   && regno0 == DF_REF_REGNO (*use_rec))
+                 {
+                   /* Return DISTANCE if OP0 is used in memory
+                      address in NEXT.  */
+                   return distance;
+                 }
+
+             for (def_rec = DF_INSN_DEFS (next); *def_rec; def_rec++)
+               if (DF_REF_TYPE (*def_rec) == DF_REF_REG_DEF
+                   && !DF_REF_IS_ARTIFICIAL (*def_rec)
+                   && regno0 == DF_REF_REGNO (*def_rec))
+                 {
+                   /* Return -1 if OP0 is set in NEXT.  */
+                   return -1;
+                 }
+           }
+         if (next == BB_END (bb))
+           break;
+         next = NEXT_INSN (next);
+       }
+    }
+
+  if (distance < LEA_SEARCH_THRESHOLD)
+    {
+      edge e;
+      edge_iterator ei;
+      bool simple_loop = false;
+  
+      FOR_EACH_EDGE (e, ei, bb->succs)
+        if (e->dest == bb)
+         {
+           simple_loop = true;
+           break;
+         }
+  
+      if (simple_loop)
+       {
+         rtx next = BB_HEAD (bb);
+         while (next
+                && next != insn
+                && distance < LEA_SEARCH_THRESHOLD)
+           {
+             if (INSN_P (next))
+               {
+                 distance++;
+
+                 for (use_rec = DF_INSN_USES (next); *use_rec; use_rec++)
+                   if ((DF_REF_TYPE (*use_rec) == DF_REF_REG_MEM_LOAD
+                        || DF_REF_TYPE (*use_rec) == DF_REF_REG_MEM_STORE)
+                       && regno0 == DF_REF_REGNO (*use_rec))
+                     {
+                       /* Return DISTANCE if OP0 is used in memory
+                          address in NEXT.  */
+                       return distance;
+                     }
+
+                 for (def_rec = DF_INSN_DEFS (next); *def_rec; def_rec++)
+                   if (DF_REF_TYPE (*def_rec) == DF_REF_REG_DEF
+                       && !DF_REF_IS_ARTIFICIAL (*def_rec)
+                       && regno0 == DF_REF_REGNO (*def_rec))
+                     {
+                       /* Return -1 if OP0 is set in NEXT.  */
+                       return -1;
+                     }
+
+               }
+             next = NEXT_INSN (next);
+           }
+       }
+    }  
+
+  return -1;
+}
+
+/* Define this macro to tune LEA priority vs ADD, it take effect when
+   there is a dilemma of choicing LEA or ADD
+   Negative value: ADD is more preferred than LEA
+   Zero: Netrual
+   Positive value: LEA is more preferred than ADD*/
+#define IX86_LEA_PRIORITY 2
+
+/* Return true if it is ok to optimize an ADD operation to LEA
+   operation to avoid flag register consumation.  For the processors
+   like ATOM, if the destination register of LEA holds an actual
+   address which will be used soon, LEA is better and otherwise ADD
+   is better.  */
+
+bool
+ix86_lea_for_add_ok (enum rtx_code code ATTRIBUTE_UNUSED,
+                     rtx insn, rtx operands[])
+{
+  unsigned int regno0 = true_regnum (operands[0]);
+  unsigned int regno1 = true_regnum (operands[1]);
+  unsigned int regno2;
+
+  if (!TARGET_OPT_AGU || optimize_function_for_size_p (cfun))
+    return regno0 != regno1;
+
+  regno2 = true_regnum (operands[2]);
+
+  /* If a = b + c, (a!=b && a!=c), must use lea form. */
+  if (regno0 != regno1 && regno0 != regno2)
+    return true;
+  else    
+    {
+      int dist_define, dist_use;
+      dist_define = distance_non_agu_define (regno1, regno2, insn);
+      if (dist_define <= 0)
+        return true;
+
+      /* If this insn has both backward non-agu dependence and forward
+         agu dependence, the one with short distance take effect. */
+      dist_use = distance_agu_use (regno0, insn);
+      if (dist_use <= 0
+         || (dist_define + IX86_LEA_PRIORITY) < dist_use)
+        return false;
+
+      return true;
+    }
+}
+
+/* Return true if destination reg of SET_BODY is shift count of
+   USE_BODY.  */
+
+static bool
+ix86_dep_by_shift_count_body (const_rtx set_body, const_rtx use_body)
+{
+  rtx set_dest;
+  rtx shift_rtx;
+  int i;
+
+  /* Retrieve destination of SET_BODY.  */
+  switch (GET_CODE (set_body))
+    {
+    case SET:
+      set_dest = SET_DEST (set_body);
+      if (!set_dest || !REG_P (set_dest))
+       return false;
+      break;
+    case PARALLEL:
+      for (i = XVECLEN (set_body, 0) - 1; i >= 0; i--)
+       if (ix86_dep_by_shift_count_body (XVECEXP (set_body, 0, i),
+                                         use_body))
+         return true;
+    default:
+      return false;
+      break;
+    }
+
+  /* Retrieve shift count of USE_BODY.  */
+  switch (GET_CODE (use_body))
+    {
+    case SET:
+      shift_rtx = XEXP (use_body, 1);
+      break;
+    case PARALLEL:
+      for (i = XVECLEN (use_body, 0) - 1; i >= 0; i--)
+       if (ix86_dep_by_shift_count_body (set_body,
+                                         XVECEXP (use_body, 0, i)))
+         return true;
+    default:
+      return false;
+      break;
+    }
+
+  if (shift_rtx 
+      && (GET_CODE (shift_rtx) == ASHIFT
+         || GET_CODE (shift_rtx) == LSHIFTRT
+         || GET_CODE (shift_rtx) == ASHIFTRT
+         || GET_CODE (shift_rtx) == ROTATE
+         || GET_CODE (shift_rtx) == ROTATERT))
+    {
+      rtx shift_count = XEXP (shift_rtx, 1);
+
+      /* Return true if shift count is dest of SET_BODY.  */
+      if (REG_P (shift_count)
+         && true_regnum (set_dest) == true_regnum (shift_count))
+       return true;
+    }
+
+  return false;
+}
+
+/* Return true if destination reg of SET_INSN is shift count of
+   USE_INSN.  */
+
+bool
+ix86_dep_by_shift_count (const_rtx set_insn, const_rtx use_insn)
+{
+  return ix86_dep_by_shift_count_body (PATTERN (set_insn),
+                                      PATTERN (use_insn));
+}
+
 /* Return TRUE or FALSE depending on whether the unary operator meets the
    appropriate constraints.  */
 
@@ -10972,7 +13840,7 @@ ix86_expand_convert_uns_didf_sse (rtx target, rtx input)
     emit_insn (gen_movdi_to_sse (int_xmm, input));
   else if (TARGET_SSE_SPLIT_REGS)
     {
-      emit_insn (gen_rtx_CLOBBER (VOIDmode, int_xmm));
+      emit_clobber (int_xmm);
       emit_move_insn (gen_lowpart (DImode, int_xmm), input);
     }
   else
@@ -11105,7 +13973,7 @@ ix86_expand_convert_uns_sisf_sse (rtx target, rtx input)
     emit_move_insn (target, fp_hi);
 }
 
-/* A subroutine of ix86_build_signbit_mask_vector.  If VECT is true,
+/* A subroutine of ix86_build_signbit_mask.  If VECT is true,
    then replicate the value for all elements of the vector
    register.  */
 
@@ -11182,10 +14050,35 @@ ix86_build_signbit_mask (enum machine_mode mode, bool vect, bool invert)
 
     case TImode:
     case TFmode:
-      imode = TImode;
       vec_mode = VOIDmode;
-      gcc_assert (HOST_BITS_PER_WIDE_INT >= 64);
-      lo = 0, hi = (HOST_WIDE_INT)1 << shift;
+      if (HOST_BITS_PER_WIDE_INT >= 64)
+       {
+         imode = TImode;
+         lo = 0, hi = (HOST_WIDE_INT)1 << shift;
+       }
+      else
+       {
+         rtvec vec;
+
+         imode = DImode;
+         lo = 0, hi = (HOST_WIDE_INT)1 << (shift - HOST_BITS_PER_WIDE_INT);
+
+         if (invert)
+           {
+             lo = ~lo, hi = ~hi;
+             v = constm1_rtx;
+           }
+         else
+           v = const0_rtx;
+
+         mask = immed_double_const (lo, hi, imode);
+
+         vec = gen_rtvec (2, v, mask);
+         v = gen_rtx_CONST_VECTOR (V2DImode, vec);
+         v = copy_to_mode_reg (mode, gen_lowpart (mode, v));
+
+         return v;
+       }
      break;
 
     default:
@@ -11290,15 +14183,9 @@ ix86_expand_copysign (rtx operands[])
            op0 = CONST0_RTX (vmode);
          else
            {
-             rtvec v;
-
-             if (mode == SFmode)
-               v = gen_rtvec (4, op0, CONST0_RTX (SFmode),
-                              CONST0_RTX (SFmode), CONST0_RTX (SFmode));
-             else
-               v = gen_rtvec (2, op0, CONST0_RTX (DFmode));
+             rtx v = ix86_build_const_vector (mode, false, op0);
 
-             op0 = force_reg (vmode, gen_rtx_CONST_VECTOR (vmode, v));
+             op0 = force_reg (vmode, v);
            }
        }
       else if (op0 != CONST0_RTX (mode))
@@ -11471,6 +14358,10 @@ ix86_match_ccmode (rtx insn, enum machine_mode req_mode)
       if (req_mode == CCZmode)
        return 0;
       /* FALLTHRU */
+    case CCAmode:
+    case CCCmode:
+    case CCOmode:
+    case CCSmode:
     case CCZmode:
       break;
 
@@ -11644,84 +14535,41 @@ ix86_cc_modes_compatible (enum machine_mode m1, enum machine_mode m2)
     }
 }
 
-/* Split comparison code CODE into comparisons we can do using branch
-   instructions.  BYPASS_CODE is comparison code for branch that will
-   branch around FIRST_CODE and SECOND_CODE.  If some of branches
-   is not required, set value to UNKNOWN.
-   We never require more than two branches.  */
 
-void
-ix86_fp_comparison_codes (enum rtx_code code, enum rtx_code *bypass_code,
-                         enum rtx_code *first_code,
-                         enum rtx_code *second_code)
-{
-  *first_code = code;
-  *bypass_code = UNKNOWN;
-  *second_code = UNKNOWN;
-
-  /* The fcomi comparison sets flags as follows:
-
-     cmp    ZF PF CF
-     >      0  0  0
-     <      0  0  1
-     =      1  0  0
-     un     1  1  1 */
+/* Return a comparison we can do and that it is equivalent to 
+   swap_condition (code) apart possibly from orderedness.
+   But, never change orderedness if TARGET_IEEE_FP, returning
+   UNKNOWN in that case if necessary.  */
 
+static enum rtx_code
+ix86_fp_swap_condition (enum rtx_code code)
+{
   switch (code)
     {
-    case GT:                   /* GTU - CF=0 & ZF=0 */
-    case GE:                   /* GEU - CF=0 */
-    case ORDERED:              /* PF=0 */
-    case UNORDERED:            /* PF=1 */
-    case UNEQ:                 /* EQ - ZF=1 */
-    case UNLT:                 /* LTU - CF=1 */
-    case UNLE:                 /* LEU - CF=1 | ZF=1 */
-    case LTGT:                 /* EQ - ZF=0 */
-      break;
-    case LT:                   /* LTU - CF=1 - fails on unordered */
-      *first_code = UNLT;
-      *bypass_code = UNORDERED;
-      break;
-    case LE:                   /* LEU - CF=1 | ZF=1 - fails on unordered */
-      *first_code = UNLE;
-      *bypass_code = UNORDERED;
-      break;
-    case EQ:                   /* EQ - ZF=1 - fails on unordered */
-      *first_code = UNEQ;
-      *bypass_code = UNORDERED;
-      break;
-    case NE:                   /* NE - ZF=0 - fails on unordered */
-      *first_code = LTGT;
-      *second_code = UNORDERED;
-      break;
-    case UNGE:                 /* GEU - CF=0 - fails on unordered */
-      *first_code = GE;
-      *second_code = UNORDERED;
-      break;
-    case UNGT:                 /* GTU - CF=0 & ZF=0 - fails on unordered */
-      *first_code = GT;
-      *second_code = UNORDERED;
-      break;
+    case GT:                   /* GTU - CF=0 & ZF=0 */
+      return TARGET_IEEE_FP ? UNKNOWN : UNLT;
+    case GE:                   /* GEU - CF=0 */
+      return TARGET_IEEE_FP ? UNKNOWN : UNLE;
+    case UNLT:                 /* LTU - CF=1 */
+      return TARGET_IEEE_FP ? UNKNOWN : GT;
+    case UNLE:                 /* LEU - CF=1 | ZF=1 */
+      return TARGET_IEEE_FP ? UNKNOWN : GE;
     default:
-      gcc_unreachable ();
-    }
-  if (!TARGET_IEEE_FP)
-    {
-      *second_code = UNKNOWN;
-      *bypass_code = UNKNOWN;
+      return swap_condition (code);
     }
 }
 
-/* Return cost of comparison done fcom + arithmetics operations on AX.
+/* Return cost of comparison CODE using the best strategy for performance.
    All following functions do use number of instructions as a cost metrics.
    In future this should be tweaked to compute bytes for optimize_size and
    take into account performance of various instructions on various CPUs.  */
+
 static int
-ix86_fp_comparison_arithmetics_cost (enum rtx_code code)
+ix86_fp_comparison_cost (enum rtx_code code)
 {
-  if (!TARGET_IEEE_FP)
-    return 4;
-  /* The cost of code output by ix86_expand_fp_compare.  */
+  int arith_cost;
+
+  /* The cost of code using bit-twiddling on %ah.  */
   switch (code)
     {
     case UNLE:
@@ -11732,82 +14580,49 @@ ix86_fp_comparison_arithmetics_cost (enum rtx_code code)
     case UNORDERED:
     case ORDERED:
     case UNEQ:
-      return 4;
+      arith_cost = 4;
       break;
     case LT:
     case NE:
     case EQ:
     case UNGE:
-      return 5;
+      arith_cost = TARGET_IEEE_FP ? 5 : 4;
       break;
     case LE:
     case UNGT:
-      return 6;
+      arith_cost = TARGET_IEEE_FP ? 6 : 4;
       break;
     default:
       gcc_unreachable ();
     }
-}
 
-/* Return cost of comparison done using fcomi operation.
-   See ix86_fp_comparison_arithmetics_cost for the metrics.  */
-static int
-ix86_fp_comparison_fcomi_cost (enum rtx_code code)
-{
-  enum rtx_code bypass_code, first_code, second_code;
-  /* Return arbitrarily high cost when instruction is not supported - this
-     prevents gcc from using it.  */
-  if (!TARGET_CMOVE)
-    return 1024;
-  ix86_fp_comparison_codes (code, &bypass_code, &first_code, &second_code);
-  return (bypass_code != UNKNOWN || second_code != UNKNOWN) + 2;
+  switch (ix86_fp_comparison_strategy (code))
+    {
+    case IX86_FPCMP_COMI:
+      return arith_cost > 4 ? 3 : 2;
+    case IX86_FPCMP_SAHF:
+      return arith_cost > 4 ? 4 : 3;
+    default:
+      return arith_cost;
+    }
 }
 
-/* Return cost of comparison done using sahf operation.
-   See ix86_fp_comparison_arithmetics_cost for the metrics.  */
-static int
-ix86_fp_comparison_sahf_cost (enum rtx_code code)
-{
-  enum rtx_code bypass_code, first_code, second_code;
-  /* Return arbitrarily high cost when instruction is not preferred - this
-     avoids gcc from using it.  */
-  if (!(TARGET_SAHF && (TARGET_USE_SAHF || optimize_size)))
-    return 1024;
-  ix86_fp_comparison_codes (code, &bypass_code, &first_code, &second_code);
-  return (bypass_code != UNKNOWN || second_code != UNKNOWN) + 3;
-}
+/* Return strategy to use for floating-point.  We assume that fcomi is always
+   preferrable where available, since that is also true when looking at size
+   (2 bytes, vs. 3 for fnstsw+sahf and at least 5 for fnstsw+test).  */
 
-/* Compute cost of the comparison done using any method.
-   See ix86_fp_comparison_arithmetics_cost for the metrics.  */
-static int
-ix86_fp_comparison_cost (enum rtx_code code)
+enum ix86_fpcmp_strategy
+ix86_fp_comparison_strategy (enum rtx_code code ATTRIBUTE_UNUSED)
 {
-  int fcomi_cost, sahf_cost, arithmetics_cost = 1024;
-  int min;
-
-  fcomi_cost = ix86_fp_comparison_fcomi_cost (code);
-  sahf_cost = ix86_fp_comparison_sahf_cost (code);
-
-  min = arithmetics_cost = ix86_fp_comparison_arithmetics_cost (code);
-  if (min > sahf_cost)
-    min = sahf_cost;
-  if (min > fcomi_cost)
-    min = fcomi_cost;
-  return min;
-}
+  /* Do fcomi/sahf based test when profitable.  */
 
-/* Return true if we should use an FCOMI instruction for this
-   fp comparison.  */
+  if (TARGET_CMOVE)
+    return IX86_FPCMP_COMI;
 
-int
-ix86_use_fcomi_compare (enum rtx_code code ATTRIBUTE_UNUSED)
-{
-  enum rtx_code swapped_code = swap_condition (code);
+  if (TARGET_SAHF && (TARGET_USE_SAHF || optimize_insn_for_size_p ()))
+    return IX86_FPCMP_SAHF;
 
-  return ((ix86_fp_comparison_cost (code)
-          == ix86_fp_comparison_fcomi_cost (code))
-         || (ix86_fp_comparison_cost (swapped_code)
-             == ix86_fp_comparison_fcomi_cost (swapped_code)));
+  return IX86_FPCMP_ARITH;
 }
 
 /* Swap, force into registers, or otherwise massage the two operands
@@ -11834,7 +14649,7 @@ ix86_prepare_fp_compare_args (enum rtx_code code, rtx *pop0, rtx *pop1)
              && ! (standard_80387_constant_p (op0) == 1
                    || standard_80387_constant_p (op1) == 1)
              && GET_CODE (op1) != FLOAT)
-         || ix86_use_fcomi_compare (code)))
+         || ix86_fp_comparison_strategy (code) == IX86_FPCMP_COMI))
     {
       op0 = force_reg (op_mode, op0);
       op1 = force_reg (op_mode, op1);
@@ -11850,9 +14665,13 @@ ix86_prepare_fp_compare_args (enum rtx_code code, rtx *pop0, rtx *pop1)
              && ! (standard_80387_constant_p (op1) == 0
                    || MEM_P (op1))))
        {
-         rtx tmp;
-         tmp = op0, op0 = op1, op1 = tmp;
-         code = swap_condition (code);
+         enum rtx_code new_code = ix86_fp_swap_condition (code);
+         if (new_code != UNKNOWN)
+           {
+             rtx tmp;
+             tmp = op0, op0 = op1, op1 = tmp;
+             code = new_code;
+           }
        }
 
       if (!REG_P (op0))
@@ -11927,59 +14746,38 @@ ix86_fp_compare_code_to_integer (enum rtx_code code)
 /* Generate insn patterns to do a floating point compare of OPERANDS.  */
 
 static rtx
-ix86_expand_fp_compare (enum rtx_code code, rtx op0, rtx op1, rtx scratch,
-                       rtx *second_test, rtx *bypass_test)
+ix86_expand_fp_compare (enum rtx_code code, rtx op0, rtx op1, rtx scratch)
 {
   enum machine_mode fpcmp_mode, intcmp_mode;
   rtx tmp, tmp2;
-  int cost = ix86_fp_comparison_cost (code);
-  enum rtx_code bypass_code, first_code, second_code;
 
   fpcmp_mode = ix86_fp_compare_mode (code);
   code = ix86_prepare_fp_compare_args (code, &op0, &op1);
 
-  if (second_test)
-    *second_test = NULL_RTX;
-  if (bypass_test)
-    *bypass_test = NULL_RTX;
-
-  ix86_fp_comparison_codes (code, &bypass_code, &first_code, &second_code);
-
   /* Do fcomi/sahf based test when profitable.  */
-  if (ix86_fp_comparison_arithmetics_cost (code) > cost
-      && (bypass_code == UNKNOWN || bypass_test)
-      && (second_code == UNKNOWN || second_test))
+  switch (ix86_fp_comparison_strategy (code))
     {
+    case IX86_FPCMP_COMI:
+      intcmp_mode = fpcmp_mode;
       tmp = gen_rtx_COMPARE (fpcmp_mode, op0, op1);
       tmp = gen_rtx_SET (VOIDmode, gen_rtx_REG (fpcmp_mode, FLAGS_REG),
                         tmp);
-      if (TARGET_CMOVE)
-       emit_insn (tmp);
-      else
-       {
-         gcc_assert (TARGET_SAHF);
+      emit_insn (tmp);
+      break;
 
-         if (!scratch)
-           scratch = gen_reg_rtx (HImode);
-         tmp2 = gen_rtx_CLOBBER (VOIDmode, scratch);
+    case IX86_FPCMP_SAHF:
+      intcmp_mode = fpcmp_mode;
+      tmp = gen_rtx_COMPARE (fpcmp_mode, op0, op1);
+      tmp = gen_rtx_SET (VOIDmode, gen_rtx_REG (fpcmp_mode, FLAGS_REG),
+                        tmp);
 
-         emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, tmp, tmp2)));
-       }
+      if (!scratch)
+       scratch = gen_reg_rtx (HImode);
+      tmp2 = gen_rtx_CLOBBER (VOIDmode, scratch);
+      emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, tmp, tmp2)));
+      break;
 
-      /* The FP codes work out to act like unsigned.  */
-      intcmp_mode = fpcmp_mode;
-      code = first_code;
-      if (bypass_code != UNKNOWN)
-       *bypass_test = gen_rtx_fmt_ee (bypass_code, VOIDmode,
-                                      gen_rtx_REG (intcmp_mode, FLAGS_REG),
-                                      const0_rtx);
-      if (second_code != UNKNOWN)
-       *second_test = gen_rtx_fmt_ee (second_code, VOIDmode,
-                                      gen_rtx_REG (intcmp_mode, FLAGS_REG),
-                                      const0_rtx);
-    }
-  else
-    {
+    case IX86_FPCMP_ARITH:
       /* Sadness wrt reg-stack pops killing fpsr -- gotta get fnstsw first.  */
       tmp = gen_rtx_COMPARE (fpcmp_mode, op0, op1);
       tmp2 = gen_rtx_UNSPEC (HImode, gen_rtvec (1, tmp), UNSPEC_FNSTSW);
@@ -12101,6 +14899,10 @@ ix86_expand_fp_compare (enum rtx_code code, rtx op0, rtx op1, rtx scratch,
        default:
          gcc_unreachable ();
        }
+       break;
+
+    default:
+      gcc_unreachable();
     }
 
   /* Return the test that should be put into the flags user, i.e.
@@ -12111,27 +14913,19 @@ ix86_expand_fp_compare (enum rtx_code code, rtx op0, rtx op1, rtx scratch,
 }
 
 rtx
-ix86_expand_compare (enum rtx_code code, rtx *second_test, rtx *bypass_test)
+ix86_expand_compare (enum rtx_code code)
 {
   rtx op0, op1, ret;
   op0 = ix86_compare_op0;
   op1 = ix86_compare_op1;
 
-  if (second_test)
-    *second_test = NULL_RTX;
-  if (bypass_test)
-    *bypass_test = NULL_RTX;
+  if (GET_MODE_CLASS (GET_MODE (ix86_compare_op0)) == MODE_CC)
+    ret = gen_rtx_fmt_ee (code, VOIDmode, ix86_compare_op0, ix86_compare_op1);
 
-  if (ix86_compare_emitted)
-    {
-      ret = gen_rtx_fmt_ee (code, VOIDmode, ix86_compare_emitted, const0_rtx);
-      ix86_compare_emitted = NULL_RTX;
-    }
   else if (SCALAR_FLOAT_MODE_P (GET_MODE (op0)))
     {
       gcc_assert (!DECIMAL_FLOAT_MODE_P (GET_MODE (op0)));
-      ret = ix86_expand_fp_compare (code, op0, op1, NULL_RTX,
-                                   second_test, bypass_test);
+      ret = ix86_expand_fp_compare (code, op0, op1, NULL_RTX);
     }
   else
     ret = ix86_expand_int_compare (code, op0, op1);
@@ -12139,88 +14933,27 @@ ix86_expand_compare (enum rtx_code code, rtx *second_test, rtx *bypass_test)
   return ret;
 }
 
-/* Return true if the CODE will result in nontrivial jump sequence.  */
-bool
-ix86_fp_jump_nontrivial_p (enum rtx_code code)
-{
-  enum rtx_code bypass_code, first_code, second_code;
-  if (!TARGET_CMOVE)
-    return true;
-  ix86_fp_comparison_codes (code, &bypass_code, &first_code, &second_code);
-  return bypass_code != UNKNOWN || second_code != UNKNOWN;
-}
-
 void
 ix86_expand_branch (enum rtx_code code, rtx label)
 {
   rtx tmp;
 
-  /* If we have emitted a compare insn, go straight to simple.
-     ix86_expand_compare won't emit anything if ix86_compare_emitted
-     is non NULL.  */
-  if (ix86_compare_emitted)
-    goto simple;
-
   switch (GET_MODE (ix86_compare_op0))
     {
+    case SFmode:
+    case DFmode:
+    case XFmode:
     case QImode:
     case HImode:
     case SImode:
       simple:
-      tmp = ix86_expand_compare (code, NULL, NULL);
+      tmp = ix86_expand_compare (code);
       tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
                                  gen_rtx_LABEL_REF (VOIDmode, label),
                                  pc_rtx);
       emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
       return;
 
-    case SFmode:
-    case DFmode:
-    case XFmode:
-      {
-       rtvec vec;
-       int use_fcomi;
-       enum rtx_code bypass_code, first_code, second_code;
-
-       code = ix86_prepare_fp_compare_args (code, &ix86_compare_op0,
-                                            &ix86_compare_op1);
-
-       ix86_fp_comparison_codes (code, &bypass_code, &first_code, &second_code);
-
-       /* Check whether we will use the natural sequence with one jump.  If
-          so, we can expand jump early.  Otherwise delay expansion by
-          creating compound insn to not confuse optimizers.  */
-       if (bypass_code == UNKNOWN && second_code == UNKNOWN)
-         {
-           ix86_split_fp_branch (code, ix86_compare_op0, ix86_compare_op1,
-                                 gen_rtx_LABEL_REF (VOIDmode, label),
-                                 pc_rtx, NULL_RTX, NULL_RTX);
-         }
-       else
-         {
-           tmp = gen_rtx_fmt_ee (code, VOIDmode,
-                                 ix86_compare_op0, ix86_compare_op1);
-           tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
-                                       gen_rtx_LABEL_REF (VOIDmode, label),
-                                       pc_rtx);
-           tmp = gen_rtx_SET (VOIDmode, pc_rtx, tmp);
-
-           use_fcomi = ix86_use_fcomi_compare (code);
-           vec = rtvec_alloc (3 + !use_fcomi);
-           RTVEC_ELT (vec, 0) = tmp;
-           RTVEC_ELT (vec, 1)
-             = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, FPSR_REG));
-           RTVEC_ELT (vec, 2)
-             = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, FLAGS_REG));
-           if (! use_fcomi)
-             RTVEC_ELT (vec, 3)
-               = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (HImode));
-
-           emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, vec));
-         }
-       return;
-      }
-
     case DImode:
       if (TARGET_64BIT)
        goto simple;
@@ -12256,7 +14989,7 @@ ix86_expand_branch (enum rtx_code code, rtx label)
           optimizing for size.  */
 
        if ((code == EQ || code == NE)
-           && (!optimize_size
+           && (!optimize_insn_for_size_p ()
                || hi[1] == const0_rtx || lo[1] == const0_rtx))
          {
            rtx xor0, xor1;
@@ -12361,7 +15094,11 @@ ix86_expand_branch (enum rtx_code code, rtx label)
       }
 
     default:
-      gcc_unreachable ();
+      /* If we have already emitted a compare insn, go straight to simple.
+         ix86_expand_compare won't emit anything if ix86_compare_emitted
+         is non NULL.  */
+      gcc_assert (GET_MODE_CLASS (GET_MODE (ix86_compare_op0)) == MODE_CC);
+      goto simple;
     }
 }
 
@@ -12370,10 +15107,7 @@ void
 ix86_split_fp_branch (enum rtx_code code, rtx op1, rtx op2,
                      rtx target1, rtx target2, rtx tmp, rtx pushed)
 {
-  rtx second, bypass;
-  rtx label = NULL_RTX;
   rtx condition;
-  int bypass_probability = -1, second_probability = -1, probability = -1;
   rtx i;
 
   if (target2 != pc_rtx)
@@ -12385,117 +15119,30 @@ ix86_split_fp_branch (enum rtx_code code, rtx op1, rtx op2,
     }
 
   condition = ix86_expand_fp_compare (code, op1, op2,
-                                     tmp, &second, &bypass);
+                                     tmp);
 
   /* Remove pushed operand from stack.  */
   if (pushed)
     ix86_free_from_memory (GET_MODE (pushed));
 
-  if (split_branch_probability >= 0)
-    {
-      /* Distribute the probabilities across the jumps.
-        Assume the BYPASS and SECOND to be always test
-        for UNORDERED.  */
-      probability = split_branch_probability;
-
-      /* Value of 1 is low enough to make no need for probability
-        to be updated.  Later we may run some experiments and see
-        if unordered values are more frequent in practice.  */
-      if (bypass)
-       bypass_probability = 1;
-      if (second)
-       second_probability = 1;
-    }
-  if (bypass != NULL_RTX)
-    {
-      label = gen_label_rtx ();
-      i = emit_jump_insn (gen_rtx_SET
-                         (VOIDmode, pc_rtx,
-                          gen_rtx_IF_THEN_ELSE (VOIDmode,
-                                                bypass,
-                                                gen_rtx_LABEL_REF (VOIDmode,
-                                                                   label),
-                                                pc_rtx)));
-      if (bypass_probability >= 0)
-       REG_NOTES (i)
-         = gen_rtx_EXPR_LIST (REG_BR_PROB,
-                              GEN_INT (bypass_probability),
-                              REG_NOTES (i));
-    }
   i = emit_jump_insn (gen_rtx_SET
                      (VOIDmode, pc_rtx,
                       gen_rtx_IF_THEN_ELSE (VOIDmode,
                                             condition, target1, target2)));
-  if (probability >= 0)
-    REG_NOTES (i)
-      = gen_rtx_EXPR_LIST (REG_BR_PROB,
-                          GEN_INT (probability),
-                          REG_NOTES (i));
-  if (second != NULL_RTX)
-    {
-      i = emit_jump_insn (gen_rtx_SET
-                         (VOIDmode, pc_rtx,
-                          gen_rtx_IF_THEN_ELSE (VOIDmode, second, target1,
-                                                target2)));
-      if (second_probability >= 0)
-       REG_NOTES (i)
-         = gen_rtx_EXPR_LIST (REG_BR_PROB,
-                              GEN_INT (second_probability),
-                              REG_NOTES (i));
-    }
-  if (label != NULL_RTX)
-    emit_label (label);
+  if (split_branch_probability >= 0)
+    add_reg_note (i, REG_BR_PROB, GEN_INT (split_branch_probability));
 }
 
-int
+void
 ix86_expand_setcc (enum rtx_code code, rtx dest)
 {
-  rtx ret, tmp, tmpreg, equiv;
-  rtx second_test, bypass_test;
-
-  if (GET_MODE (ix86_compare_op0) == (TARGET_64BIT ? TImode : DImode))
-    return 0; /* FAIL */
+  rtx ret;
 
   gcc_assert (GET_MODE (dest) == QImode);
 
-  ret = ix86_expand_compare (code, &second_test, &bypass_test);
+  ret = ix86_expand_compare (code);
   PUT_MODE (ret, QImode);
-
-  tmp = dest;
-  tmpreg = dest;
-
-  emit_insn (gen_rtx_SET (VOIDmode, tmp, ret));
-  if (bypass_test || second_test)
-    {
-      rtx test = second_test;
-      int bypass = 0;
-      rtx tmp2 = gen_reg_rtx (QImode);
-      if (bypass_test)
-       {
-         gcc_assert (!second_test);
-         test = bypass_test;
-         bypass = 1;
-         PUT_CODE (test, reverse_condition_maybe_unordered (GET_CODE (test)));
-       }
-      PUT_MODE (test, QImode);
-      emit_insn (gen_rtx_SET (VOIDmode, tmp2, test));
-
-      if (bypass)
-       emit_insn (gen_andqi3 (tmp, tmpreg, tmp2));
-      else
-       emit_insn (gen_iorqi3 (tmp, tmpreg, tmp2));
-    }
-
-  /* Attach a REG_EQUAL note describing the comparison result.  */
-  if (ix86_compare_op0 && ix86_compare_op1)
-    {
-      equiv = simplify_gen_relational (code, QImode,
-                                      GET_MODE (ix86_compare_op0),
-                                      ix86_compare_op0, ix86_compare_op1);
-      set_unique_reg_note (get_last_insn (), REG_EQUAL, equiv);
-    }
-
-  return 1; /* DONE */
+  emit_insn (gen_rtx_SET (VOIDmode, dest, ret));
 }
 
 /* Expand comparison setting or clearing carry flag.  Return true when
@@ -12512,7 +15159,6 @@ ix86_expand_carry_flag_compare (enum rtx_code code, rtx op0, rtx op1, rtx *pop)
 
   if (SCALAR_FLOAT_MODE_P (mode))
     {
-      rtx second_test = NULL, bypass_test = NULL;
       rtx compare_op, compare_seq;
 
       gcc_assert (!DECIMAL_FLOAT_MODE_P (mode));
@@ -12538,14 +15184,10 @@ ix86_expand_carry_flag_compare (enum rtx_code code, rtx op0, rtx op1, rtx *pop)
         we decide to expand comparison using arithmetic that is not
         too common scenario.  */
       start_sequence ();
-      compare_op = ix86_expand_fp_compare (code, op0, op1, NULL_RTX,
-                                          &second_test, &bypass_test);
+      compare_op = ix86_expand_fp_compare (code, op0, op1, NULL_RTX);
       compare_seq = get_insns ();
       end_sequence ();
 
-      if (second_test || bypass_test)
-       return false;
-
       if (GET_MODE (XEXP (compare_op, 0)) == CCFPmode
          || GET_MODE (XEXP (compare_op, 0)) == CCFPUmode)
         code = ix86_fp_compare_code_to_integer (GET_CODE (compare_op));
@@ -12628,7 +15270,7 @@ ix86_expand_carry_flag_compare (enum rtx_code code, rtx op0, rtx op1, rtx *pop)
     }
   ix86_compare_op0 = op0;
   ix86_compare_op1 = op1;
-  *pop = ix86_expand_compare (code, NULL, NULL);
+  *pop = ix86_expand_compare (code);
   gcc_assert (GET_CODE (*pop) == LTU || GET_CODE (*pop) == GEU);
   return true;
 }
@@ -12638,12 +15280,13 @@ ix86_expand_int_movcc (rtx operands[])
 {
   enum rtx_code code = GET_CODE (operands[1]), compare_code;
   rtx compare_seq, compare_op;
-  rtx second_test, bypass_test;
   enum machine_mode mode = GET_MODE (operands[0]);
   bool sign_bit_compare_p = false;;
 
   start_sequence ();
-  compare_op = ix86_expand_compare (code, &second_test, &bypass_test);
+  ix86_compare_op0 = XEXP (operands[1], 0);
+  ix86_compare_op1 = XEXP (operands[1], 1);
+  compare_op = ix86_expand_compare (code);
   compare_seq = get_insns ();
   end_sequence ();
 
@@ -12967,7 +15610,8 @@ ix86_expand_int_movcc (rtx operands[])
        */
 
       if ((!TARGET_CMOVE || (mode == QImode && TARGET_PARTIAL_REG_STALL))
-         && BRANCH_COST >= 2)
+         && BRANCH_COST (optimize_insn_for_speed_p (),
+                         false) >= 2)
        {
          if (cf == 0)
            {
@@ -13052,7 +15696,7 @@ ix86_expand_int_movcc (rtx operands[])
       optab op;
       rtx var, orig_out, out, tmp;
 
-      if (BRANCH_COST <= 2)
+      if (BRANCH_COST (optimize_insn_for_speed_p (), false) <= 2)
        return 0; /* FAIL */
 
       /* If one of the two operands is an interesting constant, load a
@@ -13114,19 +15758,6 @@ ix86_expand_int_movcc (rtx operands[])
   if (! nonimmediate_operand (operands[3], mode))
     operands[3] = force_reg (mode, operands[3]);
 
-  if (bypass_test && reg_overlap_mentioned_p (operands[0], operands[3]))
-    {
-      rtx tmp = gen_reg_rtx (mode);
-      emit_move_insn (tmp, operands[3]);
-      operands[3] = tmp;
-    }
-  if (second_test && reg_overlap_mentioned_p (operands[0], operands[2]))
-    {
-      rtx tmp = gen_reg_rtx (mode);
-      emit_move_insn (tmp, operands[2]);
-      operands[2] = tmp;
-    }
-
   if (! register_operand (operands[2], VOIDmode)
       && (mode == QImode
           || ! register_operand (operands[3], VOIDmode)))
@@ -13141,18 +15772,6 @@ ix86_expand_int_movcc (rtx operands[])
                          gen_rtx_IF_THEN_ELSE (mode,
                                                compare_op, operands[2],
                                                operands[3])));
-  if (bypass_test)
-    emit_insn (gen_rtx_SET (VOIDmode, copy_rtx (operands[0]),
-                           gen_rtx_IF_THEN_ELSE (mode,
-                                 bypass_test,
-                                 copy_rtx (operands[3]),
-                                 copy_rtx (operands[0]))));
-  if (second_test)
-    emit_insn (gen_rtx_SET (VOIDmode, copy_rtx (operands[0]),
-                           gen_rtx_IF_THEN_ELSE (mode,
-                                 second_test,
-                                 copy_rtx (operands[2]),
-                                 copy_rtx (operands[0]))));
 
   return 1; /* DONE */
 }
@@ -13357,8 +15976,10 @@ ix86_expand_fp_movcc (rtx operands[])
 {
   enum machine_mode mode = GET_MODE (operands[0]);
   enum rtx_code code = GET_CODE (operands[1]);
-  rtx tmp, compare_op, second_test, bypass_test;
+  rtx tmp, compare_op;
 
+  ix86_compare_op0 = XEXP (operands[1], 0);
+  ix86_compare_op1 = XEXP (operands[1], 1);
   if (TARGET_SSE_MATH && SSE_FLOAT_MODE_P (mode))
     {
       enum machine_mode cmode;
@@ -13392,45 +16013,20 @@ ix86_expand_fp_movcc (rtx operands[])
   /* The floating point conditional move instructions don't directly
      support conditions resulting from a signed integer comparison.  */
 
-  compare_op = ix86_expand_compare (code, &second_test, &bypass_test);
-
-  /* The floating point conditional move instructions don't directly
-     support signed integer comparisons.  */
-
+  compare_op = ix86_expand_compare (code);
   if (!fcmov_comparison_operator (compare_op, VOIDmode))
     {
-      gcc_assert (!second_test && !bypass_test);
       tmp = gen_reg_rtx (QImode);
       ix86_expand_setcc (code, tmp);
       code = NE;
       ix86_compare_op0 = tmp;
       ix86_compare_op1 = const0_rtx;
-      compare_op = ix86_expand_compare (code,  &second_test, &bypass_test);
-    }
-  if (bypass_test && reg_overlap_mentioned_p (operands[0], operands[3]))
-    {
-      tmp = gen_reg_rtx (mode);
-      emit_move_insn (tmp, operands[3]);
-      operands[3] = tmp;
-    }
-  if (second_test && reg_overlap_mentioned_p (operands[0], operands[2]))
-    {
-      tmp = gen_reg_rtx (mode);
-      emit_move_insn (tmp, operands[2]);
-      operands[2] = tmp;
+      compare_op = ix86_expand_compare (code);
     }
 
   emit_insn (gen_rtx_SET (VOIDmode, operands[0],
                          gen_rtx_IF_THEN_ELSE (mode, compare_op,
                                                operands[2], operands[3])));
-  if (bypass_test)
-    emit_insn (gen_rtx_SET (VOIDmode, operands[0],
-                           gen_rtx_IF_THEN_ELSE (mode, bypass_test,
-                                                 operands[3], operands[0])));
-  if (second_test)
-    emit_insn (gen_rtx_SET (VOIDmode, operands[0],
-                           gen_rtx_IF_THEN_ELSE (mode, second_test,
-                                                 operands[2], operands[0])));
 
   return 1;
 }
@@ -13886,6 +16482,8 @@ ix86_expand_int_addcc (rtx operands[])
   bool fpcmp = false;
   enum machine_mode mode = GET_MODE (operands[0]);
 
+  ix86_compare_op0 = XEXP (operands[1], 0);
+  ix86_compare_op1 = XEXP (operands[1], 1);
   if (operands[3] != const1_rtx
       && operands[3] != constm1_rtx)
     return 0;
@@ -13974,7 +16572,7 @@ ix86_split_to_parts (rtx operand, rtx *parts, enum machine_mode mode)
     size = (GET_MODE_SIZE (mode) + 4) / 8;
 
   gcc_assert (!REG_P (operand) || !MMX_REGNO_P (REGNO (operand)));
-  gcc_assert (size >= 2 && size <= 3);
+  gcc_assert (size >= 2 && size <= 4);
 
   /* Optimize constant pool reference to immediates.  This is used by fp
      moves, that force all constants to memory to allow combining.  */
@@ -13994,7 +16592,7 @@ ix86_split_to_parts (rtx operand, rtx *parts, enum machine_mode mode)
 
       operand = copy_rtx (operand);
       PUT_MODE (operand, Pmode);
-      parts[0] = parts[1] = parts[2] = operand;
+      parts[0] = parts[1] = parts[2] = parts[3] = operand;
       return size;
     }
 
@@ -14015,21 +16613,20 @@ ix86_split_to_parts (rtx operand, rtx *parts, enum machine_mode mode)
        split_di (&operand, 1, &parts[0], &parts[1]);
       else
        {
+         int i;
+
          if (REG_P (operand))
            {
              gcc_assert (reload_completed);
-             parts[0] = gen_rtx_REG (SImode, REGNO (operand) + 0);
-             parts[1] = gen_rtx_REG (SImode, REGNO (operand) + 1);
-             if (size == 3)
-               parts[2] = gen_rtx_REG (SImode, REGNO (operand) + 2);
+             for (i = 0; i < size; i++)
+               parts[i] = gen_rtx_REG (SImode, REGNO (operand) + i);
            }
          else if (offsettable_memref_p (operand))
            {
              operand = adjust_address (operand, SImode, 0);
              parts[0] = operand;
-             parts[1] = adjust_address (operand, SImode, 4);
-             if (size == 3)
-               parts[2] = adjust_address (operand, SImode, 8);
+             for (i = 1; i < size; i++)
+               parts[i] = adjust_address (operand, SImode, 4 * i);
            }
          else if (GET_CODE (operand) == CONST_DOUBLE)
            {
@@ -14039,6 +16636,11 @@ ix86_split_to_parts (rtx operand, rtx *parts, enum machine_mode mode)
              REAL_VALUE_FROM_CONST_DOUBLE (r, operand);
              switch (mode)
                {
+               case TFmode:
+                 real_to_target (l, &r, mode);
+                 parts[3] = gen_int_mode (l[3], SImode);
+                 parts[2] = gen_int_mode (l[2], SImode);
+                 break;
                case XFmode:
                  REAL_VALUE_TO_TARGET_LONG_DOUBLE (r, l);
                  parts[2] = gen_int_mode (l[2], SImode);
@@ -14112,7 +16714,7 @@ ix86_split_to_parts (rtx operand, rtx *parts, enum machine_mode mode)
   return size;
 }
 
-/* Emit insns to perform a move or push of DI, DF, and XF values.
+/* Emit insns to perform a move or push of DI, DF, XF, and TF values.
    Return false when normal moves are needed; true when all required
    insns have been emitted.  Operands 2-4 contain the input values
    int the correct order; operands 5-7 contain the output values.  */
@@ -14120,11 +16722,12 @@ ix86_split_to_parts (rtx operand, rtx *parts, enum machine_mode mode)
 void
 ix86_split_long_move (rtx operands[])
 {
-  rtx part[2][3];
-  int nparts;
+  rtx part[2][4];
+  int nparts, i, j;
   int push = 0;
   int collisions = 0;
   enum machine_mode mode = GET_MODE (operands[0]);
+  bool collisionparts[4];
 
   /* The DFmode expanders may ask us to move double.
      For 64bit target this is single move.  By hiding the fact
@@ -14163,34 +16766,46 @@ ix86_split_long_move (rtx operands[])
   /* When emitting push, take care for source operands on the stack.  */
   if (push && MEM_P (operands[1])
       && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
-    {
-      if (nparts == 3)
-       part[1][1] = change_address (part[1][1], GET_MODE (part[1][1]),
-                                    XEXP (part[1][2], 0));
-      part[1][0] = change_address (part[1][0], GET_MODE (part[1][0]),
-                                  XEXP (part[1][1], 0));
-    }
+    for (i = 0; i < nparts - 1; i++)
+      part[1][i] = change_address (part[1][i],
+                                  GET_MODE (part[1][i]),
+                                  XEXP (part[1][i + 1], 0));
 
   /* We need to do copy in the right order in case an address register
      of the source overlaps the destination.  */
   if (REG_P (part[0][0]) && MEM_P (part[1][0]))
     {
-      if (reg_overlap_mentioned_p (part[0][0], XEXP (part[1][0], 0)))
-       collisions++;
-      if (reg_overlap_mentioned_p (part[0][1], XEXP (part[1][0], 0)))
-       collisions++;
-      if (nparts == 3
-         && reg_overlap_mentioned_p (part[0][2], XEXP (part[1][0], 0)))
-       collisions++;
+      rtx tmp;
+
+      for (i = 0; i < nparts; i++)
+       {
+         collisionparts[i]
+           = reg_overlap_mentioned_p (part[0][i], XEXP (part[1][0], 0));
+         if (collisionparts[i])
+           collisions++;
+       }
 
       /* Collision in the middle part can be handled by reordering.  */
-      if (collisions == 1 && nparts == 3
-         && reg_overlap_mentioned_p (part[0][1], XEXP (part[1][0], 0)))
+      if (collisions == 1 && nparts == 3 && collisionparts [1])
        {
-         rtx tmp;
          tmp = part[0][1]; part[0][1] = part[0][2]; part[0][2] = tmp;
          tmp = part[1][1]; part[1][1] = part[1][2]; part[1][2] = tmp;
        }
+      else if (collisions == 1
+              && nparts == 4
+              && (collisionparts [1] || collisionparts [2]))
+       {
+         if (collisionparts [1])
+           {
+             tmp = part[0][1]; part[0][1] = part[0][2]; part[0][2] = tmp;
+             tmp = part[1][1]; part[1][1] = part[1][2]; part[1][2] = tmp;
+           }
+         else
+           {
+             tmp = part[0][2]; part[0][2] = part[0][3]; part[0][3] = tmp;
+             tmp = part[1][2]; part[1][2] = part[1][3]; part[1][3] = tmp;
+           }
+       }
 
       /* If there are more collisions, we can't handle it by reordering.
         Do an lea to the last part and use only one colliding move.  */
@@ -14209,11 +16824,11 @@ ix86_split_long_move (rtx operands[])
 
          emit_insn (gen_rtx_SET (VOIDmode, base, XEXP (part[1][0], 0)));
          part[1][0] = replace_equiv_address (part[1][0], base);
-         part[1][1] = replace_equiv_address (part[1][1],
-                                     plus_constant (base, UNITS_PER_WORD));
-         if (nparts == 3)
-           part[1][2] = replace_equiv_address (part[1][2],
-                                     plus_constant (base, 8));
+         for (i = 1; i < nparts; i++)
+           {
+             tmp = plus_constant (base, UNITS_PER_WORD * i);
+             part[1][i] = replace_equiv_address (part[1][i], tmp);
+           }
        }
     }
 
@@ -14227,6 +16842,11 @@ ix86_split_long_move (rtx operands[])
                 emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, GEN_INT (-4)));
              emit_move_insn (part[0][2], part[1][2]);
            }
+         else if (nparts == 4)
+           {
+             emit_move_insn (part[0][3], part[1][3]);
+             emit_move_insn (part[0][2], part[1][2]);
+           }
        }
       else
        {
@@ -14264,77 +16884,42 @@ ix86_split_long_move (rtx operands[])
        && REG_P (part[1][1])
        && (REGNO (part[0][0]) == REGNO (part[1][1])
           || (nparts == 3
-              && REGNO (part[0][0]) == REGNO (part[1][2]))))
+              && REGNO (part[0][0]) == REGNO (part[1][2]))
+          || (nparts == 4
+              && REGNO (part[0][0]) == REGNO (part[1][3]))))
       || (collisions > 0
          && reg_overlap_mentioned_p (part[0][0], XEXP (part[1][0], 0))))
     {
-      if (nparts == 3)
+      for (i = 0, j = nparts - 1; i < nparts; i++, j--)
        {
-         operands[2] = part[0][2];
-         operands[3] = part[0][1];
-         operands[4] = part[0][0];
-         operands[5] = part[1][2];
-         operands[6] = part[1][1];
-         operands[7] = part[1][0];
-       }
-      else
-       {
-         operands[2] = part[0][1];
-         operands[3] = part[0][0];
-         operands[5] = part[1][1];
-         operands[6] = part[1][0];
+         operands[2 + i] = part[0][j];
+         operands[6 + i] = part[1][j];
        }
     }
   else
     {
-      if (nparts == 3)
-       {
-         operands[2] = part[0][0];
-         operands[3] = part[0][1];
-         operands[4] = part[0][2];
-         operands[5] = part[1][0];
-         operands[6] = part[1][1];
-         operands[7] = part[1][2];
-       }
-      else
+      for (i = 0; i < nparts; i++)
        {
-         operands[2] = part[0][0];
-         operands[3] = part[0][1];
-         operands[5] = part[1][0];
-         operands[6] = part[1][1];
+         operands[2 + i] = part[0][i];
+         operands[6 + i] = part[1][i];
        }
     }
 
   /* If optimizing for size, attempt to locally unCSE nonzero constants.  */
-  if (optimize_size)
+  if (optimize_insn_for_size_p ())
     {
-      if (CONST_INT_P (operands[5])
-         && operands[5] != const0_rtx
-         && REG_P (operands[2]))
-       {
-         if (CONST_INT_P (operands[6])
-             && INTVAL (operands[6]) == INTVAL (operands[5]))
-           operands[6] = operands[2];
-
-         if (nparts == 3
-             && CONST_INT_P (operands[7])
-             && INTVAL (operands[7]) == INTVAL (operands[5]))
-           operands[7] = operands[2];
-       }
-
-      if (nparts == 3
-         && CONST_INT_P (operands[6])
-         && operands[6] != const0_rtx
-         && REG_P (operands[3])
-         && CONST_INT_P (operands[7])
-         && INTVAL (operands[7]) == INTVAL (operands[6]))
-       operands[7] = operands[3];
+      for (j = 0; j < nparts - 1; j++)
+       if (CONST_INT_P (operands[6 + j])
+           && operands[6 + j] != const0_rtx
+           && REG_P (operands[2 + j]))
+         for (i = j; i < nparts - 1; i++)
+           if (CONST_INT_P (operands[7 + i])
+               && INTVAL (operands[7 + i]) == INTVAL (operands[6 + j]))
+             operands[7 + i] = operands[2 + j];
     }
 
-  emit_move_insn (operands[2], operands[5]);
-  emit_move_insn (operands[3], operands[6]);
-  if (nparts == 3)
-    emit_move_insn (operands[4], operands[7]);
+  for (i = 0; i < nparts; i++)
+    emit_move_insn (operands[2 + i], operands[6 + i]);
 
   return;
 }
@@ -14352,7 +16937,7 @@ ix86_expand_ashl_const (rtx operand, int count, enum machine_mode mode)
                  ? gen_addsi3
                  : gen_adddi3) (operand, operand, operand));
     }
-  else if (!optimize_size
+  else if (!optimize_insn_for_size_p ()
           && count * ix86_cost->add <= ix86_cost->shift_const)
     {
       int i;
@@ -14394,7 +16979,7 @@ ix86_split_ashl (rtx *operands, rtx scratch, enum machine_mode mode)
          if (!rtx_equal_p (operands[0], operands[1]))
            emit_move_insn (operands[0], operands[1]);
          emit_insn ((mode == DImode
-                    ? gen_x86_shld_1
+                    ? gen_x86_shld
                     : gen_x86_64_shld) (high[0], low[0], GEN_INT (count)));
          ix86_expand_ashl_const (low[0], count, mode);
        }
@@ -14435,7 +17020,7 @@ ix86_split_ashl (rtx *operands, rtx scratch, enum machine_mode mode)
        {
          rtx x;
 
-         if (TARGET_PARTIAL_REG_STALL && !optimize_size)
+         if (TARGET_PARTIAL_REG_STALL && !optimize_insn_for_size_p ())
            x = gen_rtx_ZERO_EXTEND (mode == DImode ? SImode : DImode, operands[2]);
          else
            x = gen_lowpart (mode == DImode ? SImode : DImode, operands[2]);
@@ -14467,7 +17052,7 @@ ix86_split_ashl (rtx *operands, rtx scratch, enum machine_mode mode)
       /* For -1 << N, we can avoid the shld instruction, because we
         know that we're shifting 0...31/63 ones into a -1.  */
       emit_move_insn (low[0], constm1_rtx);
-      if (optimize_size)
+      if (optimize_insn_for_size_p ())
        emit_move_insn (high[0], low[0]);
       else
        emit_move_insn (high[0], constm1_rtx);
@@ -14479,7 +17064,7 @@ ix86_split_ashl (rtx *operands, rtx scratch, enum machine_mode mode)
 
       (mode == DImode ? split_di : split_ti) (operands, 1, low, high);
       emit_insn ((mode == DImode
-                 ? gen_x86_shld_1
+                 ? gen_x86_shld
                  : gen_x86_64_shld) (high[0], low[0], operands[2]));
     }
 
@@ -14490,10 +17075,13 @@ ix86_split_ashl (rtx *operands, rtx scratch, enum machine_mode mode)
       ix86_expand_clear (scratch);
       emit_insn ((mode == DImode
                  ? gen_x86_shift_adj_1
-                 : gen_x86_64_shift_adj) (high[0], low[0], operands[2], scratch));
+                 : gen_x86_64_shift_adj_1) (high[0], low[0], operands[2],
+                                            scratch));
     }
   else
-    emit_insn (gen_x86_shift_adj_2 (high[0], low[0], operands[2]));
+    emit_insn ((mode == DImode
+               ? gen_x86_shift_adj_2
+               : gen_x86_64_shift_adj_2) (high[0], low[0], operands[2]));
 }
 
 void
@@ -14537,7 +17125,7 @@ ix86_split_ashr (rtx *operands, rtx scratch, enum machine_mode mode)
          if (!rtx_equal_p (operands[0], operands[1]))
            emit_move_insn (operands[0], operands[1]);
          emit_insn ((mode == DImode
-                     ? gen_x86_shrd_1
+                     ? gen_x86_shrd
                      : gen_x86_64_shrd) (low[0], high[0], GEN_INT (count)));
          emit_insn ((mode == DImode
                      ? gen_ashrsi3
@@ -14552,7 +17140,7 @@ ix86_split_ashr (rtx *operands, rtx scratch, enum machine_mode mode)
       (mode == DImode ? split_di : split_ti) (operands, 1, low, high);
 
       emit_insn ((mode == DImode
-                 ? gen_x86_shrd_1
+                 ? gen_x86_shrd
                  : gen_x86_64_shrd) (low[0], high[0], operands[2]));
       emit_insn ((mode == DImode
                  ? gen_ashrsi3
@@ -14567,11 +17155,13 @@ ix86_split_ashr (rtx *operands, rtx scratch, enum machine_mode mode)
                                      GEN_INT (single_width - 1)));
          emit_insn ((mode == DImode
                      ? gen_x86_shift_adj_1
-                     : gen_x86_64_shift_adj) (low[0], high[0], operands[2],
-                                        scratch));
+                     : gen_x86_64_shift_adj_1) (low[0], high[0], operands[2],
+                                                scratch));
        }
       else
-       emit_insn (gen_x86_shift_adj_3 (low[0], high[0], operands[2]));
+       emit_insn ((mode == DImode
+                   ? gen_x86_shift_adj_3
+                   : gen_x86_64_shift_adj_3) (low[0], high[0], operands[2]));
     }
 }
 
@@ -14603,7 +17193,7 @@ ix86_split_lshr (rtx *operands, rtx scratch, enum machine_mode mode)
          if (!rtx_equal_p (operands[0], operands[1]))
            emit_move_insn (operands[0], operands[1]);
          emit_insn ((mode == DImode
-                     ? gen_x86_shrd_1
+                     ? gen_x86_shrd
                      : gen_x86_64_shrd) (low[0], high[0], GEN_INT (count)));
          emit_insn ((mode == DImode
                      ? gen_lshrsi3
@@ -14618,7 +17208,7 @@ ix86_split_lshr (rtx *operands, rtx scratch, enum machine_mode mode)
       (mode == DImode ? split_di : split_ti) (operands, 1, low, high);
 
       emit_insn ((mode == DImode
-                 ? gen_x86_shrd_1
+                 ? gen_x86_shrd
                  : gen_x86_64_shrd) (low[0], high[0], operands[2]));
       emit_insn ((mode == DImode
                  ? gen_lshrsi3
@@ -14630,11 +17220,13 @@ ix86_split_lshr (rtx *operands, rtx scratch, enum machine_mode mode)
          ix86_expand_clear (scratch);
          emit_insn ((mode == DImode
                      ? gen_x86_shift_adj_1
-                     : gen_x86_64_shift_adj) (low[0], high[0], operands[2],
-                                              scratch));
+                     : gen_x86_64_shift_adj_1) (low[0], high[0], operands[2],
+                                                scratch));
        }
       else
-       emit_insn (gen_x86_shift_adj_2 (low[0], high[0], operands[2]));
+       emit_insn ((mode == DImode
+                   ? gen_x86_shift_adj_2
+                   : gen_x86_64_shift_adj_2) (low[0], high[0], operands[2]));
     }
 }
 
@@ -14644,10 +17236,7 @@ predict_jump (int prob)
 {
   rtx insn = get_last_insn ();
   gcc_assert (JUMP_P (insn));
-  REG_NOTES (insn)
-    = gen_rtx_EXPR_LIST (REG_BR_PROB,
-                        GEN_INT (prob),
-                        REG_NOTES (insn));
+  add_reg_note (insn, REG_BR_PROB, GEN_INT (prob));
 }
 
 /* Helper function for the string operations below.  Dest VARIABLE whether
@@ -14722,7 +17311,7 @@ counter_mode (rtx count_exp)
 {
   if (GET_MODE (count_exp) != VOIDmode)
     return GET_MODE (count_exp);
-  if (GET_CODE (count_exp) != CONST_INT)
+  if (!CONST_INT_P (count_exp))
     return Pmode;
   if (TARGET_64BIT && (INTVAL (count_exp) & ~0xffffffff))
     return DImode;
@@ -14900,6 +17489,22 @@ expand_movmem_via_rep_mov (rtx destmem, rtx srcmem,
       destexp = gen_rtx_PLUS (Pmode, destptr, countreg);
       srcexp = gen_rtx_PLUS (Pmode, srcptr, countreg);
     }
+  if (CONST_INT_P (count))
+    {
+      count = GEN_INT (INTVAL (count)
+                      & ~((HOST_WIDE_INT) GET_MODE_SIZE (mode) - 1));
+      destmem = shallow_copy_rtx (destmem);
+      srcmem = shallow_copy_rtx (srcmem);
+      set_mem_size (destmem, count);
+      set_mem_size (srcmem, count);
+    }
+  else
+    {
+      if (MEM_SIZE (destmem))
+       set_mem_size (destmem, NULL_RTX);
+      if (MEM_SIZE (srcmem))
+       set_mem_size (srcmem, NULL_RTX);
+    }
   emit_insn (gen_rep_mov (destptr, destmem, srcptr, srcmem, countreg,
                          destexp, srcexp));
 }
@@ -14908,8 +17513,8 @@ expand_movmem_via_rep_mov (rtx destmem, rtx srcmem,
    Arguments have same meaning as for previous function */
 static void
 expand_setmem_via_rep_stos (rtx destmem, rtx destptr, rtx value,
-                           rtx count,
-                           enum machine_mode mode)
+                           rtx count, enum machine_mode mode,
+                           rtx orig_value)
 {
   rtx destexp;
   rtx countreg;
@@ -14926,6 +17531,15 @@ expand_setmem_via_rep_stos (rtx destmem, rtx destptr, rtx value,
     }
   else
     destexp = gen_rtx_PLUS (Pmode, destptr, countreg);
+  if (orig_value == const0_rtx && CONST_INT_P (count))
+    {
+      count = GEN_INT (INTVAL (count)
+                      & ~((HOST_WIDE_INT) GET_MODE_SIZE (mode) - 1));
+      destmem = shallow_copy_rtx (destmem);
+      set_mem_size (destmem, count);
+    }
+  else if (MEM_SIZE (destmem))
+    set_mem_size (destmem, NULL_RTX);
   emit_insn (gen_rep_stos (destptr, countreg, destmem, value, destexp));
 }
 
@@ -15259,6 +17873,85 @@ expand_movmem_prologue (rtx destmem, rtx srcmem,
   gcc_assert (desired_alignment <= 8);
 }
 
+/* Copy enough from DST to SRC to align DST known to DESIRED_ALIGN.
+   ALIGN_BYTES is how many bytes need to be copied.  */
+static rtx
+expand_constant_movmem_prologue (rtx dst, rtx *srcp, rtx destreg, rtx srcreg,
+                                int desired_align, int align_bytes)
+{
+  rtx src = *srcp;
+  rtx src_size, dst_size;
+  int off = 0;
+  int src_align_bytes = get_mem_align_offset (src, desired_align * BITS_PER_UNIT);
+  if (src_align_bytes >= 0)
+    src_align_bytes = desired_align - src_align_bytes;
+  src_size = MEM_SIZE (src);
+  dst_size = MEM_SIZE (dst);
+  if (align_bytes & 1)
+    {
+      dst = adjust_automodify_address_nv (dst, QImode, destreg, 0);
+      src = adjust_automodify_address_nv (src, QImode, srcreg, 0);
+      off = 1;
+      emit_insn (gen_strmov (destreg, dst, srcreg, src));
+    }
+  if (align_bytes & 2)
+    {
+      dst = adjust_automodify_address_nv (dst, HImode, destreg, off);
+      src = adjust_automodify_address_nv (src, HImode, srcreg, off);
+      if (MEM_ALIGN (dst) < 2 * BITS_PER_UNIT)
+       set_mem_align (dst, 2 * BITS_PER_UNIT);
+      if (src_align_bytes >= 0
+         && (src_align_bytes & 1) == (align_bytes & 1)
+         && MEM_ALIGN (src) < 2 * BITS_PER_UNIT)
+       set_mem_align (src, 2 * BITS_PER_UNIT);
+      off = 2;
+      emit_insn (gen_strmov (destreg, dst, srcreg, src));
+    }
+  if (align_bytes & 4)
+    {
+      dst = adjust_automodify_address_nv (dst, SImode, destreg, off);
+      src = adjust_automodify_address_nv (src, SImode, srcreg, off);
+      if (MEM_ALIGN (dst) < 4 * BITS_PER_UNIT)
+       set_mem_align (dst, 4 * BITS_PER_UNIT);
+      if (src_align_bytes >= 0)
+       {
+         unsigned int src_align = 0;
+         if ((src_align_bytes & 3) == (align_bytes & 3))
+           src_align = 4;
+         else if ((src_align_bytes & 1) == (align_bytes & 1))
+           src_align = 2;
+         if (MEM_ALIGN (src) < src_align * BITS_PER_UNIT)
+           set_mem_align (src, src_align * BITS_PER_UNIT);
+       }
+      off = 4;
+      emit_insn (gen_strmov (destreg, dst, srcreg, src));
+    }
+  dst = adjust_automodify_address_nv (dst, BLKmode, destreg, off);
+  src = adjust_automodify_address_nv (src, BLKmode, srcreg, off);
+  if (MEM_ALIGN (dst) < (unsigned int) desired_align * BITS_PER_UNIT)
+    set_mem_align (dst, desired_align * BITS_PER_UNIT);
+  if (src_align_bytes >= 0)
+    {
+      unsigned int src_align = 0;
+      if ((src_align_bytes & 7) == (align_bytes & 7))
+       src_align = 8;
+      else if ((src_align_bytes & 3) == (align_bytes & 3))
+       src_align = 4;
+      else if ((src_align_bytes & 1) == (align_bytes & 1))
+       src_align = 2;
+      if (src_align > (unsigned int) desired_align)
+       src_align = desired_align;
+      if (MEM_ALIGN (src) < src_align * BITS_PER_UNIT)
+       set_mem_align (src, src_align * BITS_PER_UNIT);
+    }
+  if (dst_size)
+    set_mem_size (dst, GEN_INT (INTVAL (dst_size) - align_bytes));
+  if (src_size)
+    set_mem_size (dst, GEN_INT (INTVAL (src_size) - align_bytes));
+  *srcp = src;
+  return dst;
+}
+
 /* Set enough from DEST to align DEST known to by aligned by ALIGN to
    DESIRED_ALIGNMENT.  */
 static void
@@ -15295,12 +17988,54 @@ expand_setmem_prologue (rtx destmem, rtx destptr, rtx value, rtx count,
   gcc_assert (desired_alignment <= 8);
 }
 
+/* Set enough from DST to align DST known to by aligned by ALIGN to
+   DESIRED_ALIGN.  ALIGN_BYTES is how many bytes need to be stored.  */
+static rtx
+expand_constant_setmem_prologue (rtx dst, rtx destreg, rtx value,
+                                int desired_align, int align_bytes)
+{
+  int off = 0;
+  rtx dst_size = MEM_SIZE (dst);
+  if (align_bytes & 1)
+    {
+      dst = adjust_automodify_address_nv (dst, QImode, destreg, 0);
+      off = 1;
+      emit_insn (gen_strset (destreg, dst,
+                            gen_lowpart (QImode, value)));
+    }
+  if (align_bytes & 2)
+    {
+      dst = adjust_automodify_address_nv (dst, HImode, destreg, off);
+      if (MEM_ALIGN (dst) < 2 * BITS_PER_UNIT)
+       set_mem_align (dst, 2 * BITS_PER_UNIT);
+      off = 2;
+      emit_insn (gen_strset (destreg, dst,
+                            gen_lowpart (HImode, value)));
+    }
+  if (align_bytes & 4)
+    {
+      dst = adjust_automodify_address_nv (dst, SImode, destreg, off);
+      if (MEM_ALIGN (dst) < 4 * BITS_PER_UNIT)
+       set_mem_align (dst, 4 * BITS_PER_UNIT);
+      off = 4;
+      emit_insn (gen_strset (destreg, dst,
+                            gen_lowpart (SImode, value)));
+    }
+  dst = adjust_automodify_address_nv (dst, BLKmode, destreg, off);
+  if (MEM_ALIGN (dst) < (unsigned int) desired_align * BITS_PER_UNIT)
+    set_mem_align (dst, desired_align * BITS_PER_UNIT);
+  if (dst_size)
+    set_mem_size (dst, GEN_INT (INTVAL (dst_size) - align_bytes));
+  return dst;
+}
+
 /* Given COUNT and EXPECTED_SIZE, decide on codegen of string operation.  */
 static enum stringop_alg
 decide_alg (HOST_WIDE_INT count, HOST_WIDE_INT expected_size, bool memset,
            int *dynamic_check)
 {
   const struct stringop_algs * algs;
+  bool optimize_for_speed;
   /* Algorithms using the rep prefix want at least edi and ecx;
      additionally, memset wants eax and memcpy wants esi.  Don't
      consider such algorithms if the user has appropriated those
@@ -15313,16 +18048,28 @@ decide_alg (HOST_WIDE_INT count, HOST_WIDE_INT expected_size, bool memset,
                           || (alg != rep_prefix_1_byte         \
                               && alg != rep_prefix_4_byte      \
                               && alg != rep_prefix_8_byte))
+  const struct processor_costs *cost;
+  
+  /* Even if the string operation call is cold, we still might spend a lot
+     of time processing large blocks.  */
+  if (optimize_function_for_size_p (cfun)
+      || (optimize_insn_for_size_p ()
+          && expected_size != -1 && expected_size < 256))
+    optimize_for_speed = false;
+  else
+    optimize_for_speed = true;
+
+  cost = optimize_for_speed ? ix86_cost : &ix86_size_cost;
 
   *dynamic_check = -1;
   if (memset)
-    algs = &ix86_cost->memset[TARGET_64BIT != 0];
+    algs = &cost->memset[TARGET_64BIT != 0];
   else
-    algs = &ix86_cost->memcpy[TARGET_64BIT != 0];
+    algs = &cost->memcpy[TARGET_64BIT != 0];
   if (stringop_alg != no_stringop && ALG_USABLE_P (stringop_alg))
     return stringop_alg;
   /* rep; movq or rep; movl is the smallest variant.  */
-  else if (optimize_size)
+  else if (!optimize_for_speed)
     {
       if (!count || (count & 3))
        return rep_prefix_usable ? rep_prefix_1_byte : loop_1_byte;
@@ -15513,9 +18260,10 @@ ix86_expand_movmem (rtx dst, rtx src, rtx count_exp, rtx align_exp,
   unsigned HOST_WIDE_INT count = 0;
   HOST_WIDE_INT expected_size = -1;
   int size_needed = 0, epilogue_size_needed;
-  int desired_align = 0;
+  int desired_align = 0, align_bytes = 0;
   enum stringop_alg alg;
   int dynamic_check;
+  bool need_zero_guard = false;
 
   if (CONST_INT_P (align_exp))
     align = INTVAL (align_exp);
@@ -15523,6 +18271,11 @@ ix86_expand_movmem (rtx dst, rtx src, rtx count_exp, rtx align_exp,
   if (CONST_INT_P (expected_align_exp)
       && INTVAL (expected_align_exp) > align)
     align = INTVAL (expected_align_exp);
+  /* ALIGN is the minimum of destination and source alignment, but we care here
+     just about destination alignment.  */
+  else if (MEM_ALIGN (dst) > (unsigned HOST_WIDE_INT) align * BITS_PER_UNIT)
+    align = MEM_ALIGN (dst) / BITS_PER_UNIT;
+
   if (CONST_INT_P (count_exp))
     count = expected_size = INTVAL (count_exp);
   if (CONST_INT_P (expected_size_exp) && count == 0)
@@ -15554,9 +18307,11 @@ ix86_expand_movmem (rtx dst, rtx src, rtx count_exp, rtx align_exp,
     case no_stringop:
       gcc_unreachable ();
     case loop:
+      need_zero_guard = true;
       size_needed = GET_MODE_SIZE (Pmode);
       break;
     case unrolled_loop:
+      need_zero_guard = true;
       size_needed = GET_MODE_SIZE (Pmode) * (TARGET_64BIT ? 4 : 2);
       break;
     case rep_prefix_8_byte:
@@ -15566,7 +18321,10 @@ ix86_expand_movmem (rtx dst, rtx src, rtx count_exp, rtx align_exp,
       size_needed = 4;
       break;
     case rep_prefix_1_byte:
+      size_needed = 1;
+      break;
     case loop_1_byte:
+      need_zero_guard = true;
       size_needed = 1;
       break;
     }
@@ -15577,7 +18335,20 @@ ix86_expand_movmem (rtx dst, rtx src, rtx count_exp, rtx align_exp,
 
   /* Alignment code needs count to be in register.  */
   if (CONST_INT_P (count_exp) && desired_align > align)
-    count_exp = force_reg (counter_mode (count_exp), count_exp);
+    {
+      if (INTVAL (count_exp) > desired_align
+         && INTVAL (count_exp) > size_needed)
+       {
+         align_bytes
+           = get_mem_align_offset (dst, desired_align * BITS_PER_UNIT);
+         if (align_bytes <= 0)
+           align_bytes = 0;
+         else
+           align_bytes = desired_align - align_bytes;
+       }
+      if (align_bytes == 0)
+       count_exp = force_reg (counter_mode (count_exp), count_exp);
+    }
   gcc_assert (desired_align >= 1 && align >= 1);
 
   /* Ensure that alignment prologue won't copy past end of block.  */
@@ -15588,10 +18359,17 @@ ix86_expand_movmem (rtx dst, rtx src, rtx count_exp, rtx align_exp,
         Make sure it is power of 2.  */
       epilogue_size_needed = smallest_pow2_greater_than (epilogue_size_needed);
 
-      if (CONST_INT_P (count_exp))
+      if (count)
        {
-         if (UINTVAL (count_exp) < (unsigned HOST_WIDE_INT)epilogue_size_needed)
-           goto epilogue;
+         if (count < (unsigned HOST_WIDE_INT)epilogue_size_needed)
+           {
+             /* If main algorithm works on QImode, no epilogue is needed.
+                For small sizes just don't align anything.  */
+             if (size_needed == 1)
+               desired_align = align;
+             else
+               goto epilogue;
+           }
        }
       else
        {
@@ -15636,21 +18414,56 @@ ix86_expand_movmem (rtx dst, rtx src, rtx count_exp, rtx align_exp,
 
   if (desired_align > align)
     {
-      /* Except for the first move in epilogue, we no longer know
-         constant offset in aliasing info.  It don't seems to worth
-        the pain to maintain it for the first move, so throw away
-        the info early.  */
-      src = change_address (src, BLKmode, srcreg);
-      dst = change_address (dst, BLKmode, destreg);
-      expand_movmem_prologue (dst, src, destreg, srcreg, count_exp, align,
-                             desired_align);
+      if (align_bytes == 0)
+       {
+         /* Except for the first move in epilogue, we no longer know
+            constant offset in aliasing info.  It don't seems to worth
+            the pain to maintain it for the first move, so throw away
+            the info early.  */
+         src = change_address (src, BLKmode, srcreg);
+         dst = change_address (dst, BLKmode, destreg);
+         expand_movmem_prologue (dst, src, destreg, srcreg, count_exp, align,
+                                 desired_align);
+       }
+      else
+       {
+         /* If we know how many bytes need to be stored before dst is
+            sufficiently aligned, maintain aliasing info accurately.  */
+         dst = expand_constant_movmem_prologue (dst, &src, destreg, srcreg,
+                                                desired_align, align_bytes);
+         count_exp = plus_constant (count_exp, -align_bytes);
+         count -= align_bytes;
+       }
+      if (need_zero_guard
+         && (count < (unsigned HOST_WIDE_INT) size_needed
+             || (align_bytes == 0
+                 && count < ((unsigned HOST_WIDE_INT) size_needed
+                             + desired_align - align))))
+       {
+         /* It is possible that we copied enough so the main loop will not
+            execute.  */
+         gcc_assert (size_needed > 1);
+         if (label == NULL_RTX)
+           label = gen_label_rtx ();
+         emit_cmp_and_jump_insns (count_exp,
+                                  GEN_INT (size_needed),
+                                  LTU, 0, counter_mode (count_exp), 1, label);
+         if (expected_size == -1
+             || expected_size < (desired_align - align) / 2 + size_needed)
+           predict_jump (REG_BR_PROB_BASE * 20 / 100);
+         else
+           predict_jump (REG_BR_PROB_BASE * 60 / 100);
+       }
     }
   if (label && size_needed == 1)
     {
       emit_label (label);
       LABEL_NUSES (label) = 1;
       label = NULL;
+      epilogue_size_needed = 1;
     }
+  else if (label == NULL_RTX)
+    epilogue_size_needed = size_needed;
 
   /* Step 3: Main loop.  */
 
@@ -15839,11 +18652,12 @@ ix86_expand_setmem (rtx dst, rtx count_exp, rtx val_exp, rtx align_exp,
   unsigned HOST_WIDE_INT count = 0;
   HOST_WIDE_INT expected_size = -1;
   int size_needed = 0, epilogue_size_needed;
-  int desired_align = 0;
+  int desired_align = 0, align_bytes = 0;
   enum stringop_alg alg;
   rtx promoted_val = NULL;
   bool force_loopy_epilogue = false;
   int dynamic_check;
+  bool need_zero_guard = false;
 
   if (CONST_INT_P (align_exp))
     align = INTVAL (align_exp);
@@ -15881,9 +18695,11 @@ ix86_expand_setmem (rtx dst, rtx count_exp, rtx val_exp, rtx align_exp,
     case no_stringop:
       gcc_unreachable ();
     case loop:
+      need_zero_guard = true;
       size_needed = GET_MODE_SIZE (Pmode);
       break;
     case unrolled_loop:
+      need_zero_guard = true;
       size_needed = GET_MODE_SIZE (Pmode) * 4;
       break;
     case rep_prefix_8_byte:
@@ -15893,7 +18709,10 @@ ix86_expand_setmem (rtx dst, rtx count_exp, rtx val_exp, rtx align_exp,
       size_needed = 4;
       break;
     case rep_prefix_1_byte:
+      size_needed = 1;
+      break;
     case loop_1_byte:
+      need_zero_guard = true;
       size_needed = 1;
       break;
     }
@@ -15904,10 +18723,23 @@ ix86_expand_setmem (rtx dst, rtx count_exp, rtx val_exp, rtx align_exp,
   /* Alignment code needs count to be in register.  */
   if (CONST_INT_P (count_exp) && desired_align > align)
     {
-      enum machine_mode mode = SImode;
-      if (TARGET_64BIT && (count & ~0xffffffff))
-       mode = DImode;
-      count_exp = force_reg (mode, count_exp);
+      if (INTVAL (count_exp) > desired_align
+         && INTVAL (count_exp) > size_needed)
+       {
+         align_bytes
+           = get_mem_align_offset (dst, desired_align * BITS_PER_UNIT);
+         if (align_bytes <= 0)
+           align_bytes = 0;
+         else
+           align_bytes = desired_align - align_bytes;
+       }
+      if (align_bytes == 0)
+       {
+         enum machine_mode mode = SImode;
+         if (TARGET_64BIT && (count & ~0xffffffff))
+           mode = DImode;
+         count_exp = force_reg (mode, count_exp);
+       }
     }
   /* Do the cheap promotion to allow better CSE across the
      main loop and epilogue (ie one load of the big constant in the
@@ -15919,7 +18751,7 @@ ix86_expand_setmem (rtx dst, rtx count_exp, rtx val_exp, rtx align_exp,
   if (size_needed > 1 || (desired_align > 1 && desired_align > align))
     {
       epilogue_size_needed = MAX (size_needed - 1, desired_align - align);
-      /* Epilogue always copies COUNT_EXP & EPILOGUE_SIZE_NEEDED bytes.
+      /* Epilogue always copies COUNT_EXP & (EPILOGUE_SIZE_NEEDED - 1) bytes.
         Make sure it is power of 2.  */
       epilogue_size_needed = smallest_pow2_greater_than (epilogue_size_needed);
 
@@ -15929,16 +18761,29 @@ ix86_expand_setmem (rtx dst, rtx count_exp, rtx val_exp, rtx align_exp,
         loop variant.  */
       if (epilogue_size_needed > 2 && !promoted_val)
         force_loopy_epilogue = true;
-      label = gen_label_rtx ();
-      emit_cmp_and_jump_insns (count_exp,
-                              GEN_INT (epilogue_size_needed),
-                              LTU, 0, counter_mode (count_exp), 1, label);
-      if (GET_CODE (count_exp) == CONST_INT)
-       ;
-      else if (expected_size == -1 || expected_size <= epilogue_size_needed)
-       predict_jump (REG_BR_PROB_BASE * 60 / 100);
+      if (count)
+       {
+         if (count < (unsigned HOST_WIDE_INT)epilogue_size_needed)
+           {
+             /* If main algorithm works on QImode, no epilogue is needed.
+                For small sizes just don't align anything.  */
+             if (size_needed == 1)
+               desired_align = align;
+             else
+               goto epilogue;
+           }
+       }
       else
-       predict_jump (REG_BR_PROB_BASE * 20 / 100);
+       {
+         label = gen_label_rtx ();
+         emit_cmp_and_jump_insns (count_exp,
+                                  GEN_INT (epilogue_size_needed),
+                                  LTU, 0, counter_mode (count_exp), 1, label);
+         if (expected_size == -1 || expected_size <= epilogue_size_needed)
+           predict_jump (REG_BR_PROB_BASE * 60 / 100);
+         else
+           predict_jump (REG_BR_PROB_BASE * 20 / 100);
+       }
     }
   if (dynamic_check != -1)
     {
@@ -15962,20 +18807,56 @@ ix86_expand_setmem (rtx dst, rtx count_exp, rtx val_exp, rtx align_exp,
 
   if (desired_align > align)
     {
-      /* Except for the first move in epilogue, we no longer know
-         constant offset in aliasing info.  It don't seems to worth
-        the pain to maintain it for the first move, so throw away
-        the info early.  */
-      dst = change_address (dst, BLKmode, destreg);
-      expand_setmem_prologue (dst, destreg, promoted_val, count_exp, align,
-                             desired_align);
+      if (align_bytes == 0)
+       {
+         /* Except for the first move in epilogue, we no longer know
+            constant offset in aliasing info.  It don't seems to worth
+            the pain to maintain it for the first move, so throw away
+            the info early.  */
+         dst = change_address (dst, BLKmode, destreg);
+         expand_setmem_prologue (dst, destreg, promoted_val, count_exp, align,
+                                 desired_align);
+       }
+      else
+       {
+         /* If we know how many bytes need to be stored before dst is
+            sufficiently aligned, maintain aliasing info accurately.  */
+         dst = expand_constant_setmem_prologue (dst, destreg, promoted_val,
+                                                desired_align, align_bytes);
+         count_exp = plus_constant (count_exp, -align_bytes);
+         count -= align_bytes;
+       }
+      if (need_zero_guard
+         && (count < (unsigned HOST_WIDE_INT) size_needed
+             || (align_bytes == 0
+                 && count < ((unsigned HOST_WIDE_INT) size_needed
+                             + desired_align - align))))
+       {
+         /* It is possible that we copied enough so the main loop will not
+            execute.  */
+         gcc_assert (size_needed > 1);
+         if (label == NULL_RTX)
+           label = gen_label_rtx ();
+         emit_cmp_and_jump_insns (count_exp,
+                                  GEN_INT (size_needed),
+                                  LTU, 0, counter_mode (count_exp), 1, label);
+         if (expected_size == -1
+             || expected_size < (desired_align - align) / 2 + size_needed)
+           predict_jump (REG_BR_PROB_BASE * 20 / 100);
+         else
+           predict_jump (REG_BR_PROB_BASE * 60 / 100);
+       }
     }
   if (label && size_needed == 1)
     {
       emit_label (label);
       LABEL_NUSES (label) = 1;
       label = NULL;
+      promoted_val = val_exp;
+      epilogue_size_needed = 1;
     }
+  else if (label == NULL_RTX)
+    epilogue_size_needed = size_needed;
 
   /* Step 3: Main loop.  */
 
@@ -15998,15 +18879,15 @@ ix86_expand_setmem (rtx dst, rtx count_exp, rtx val_exp, rtx align_exp,
       break;
     case rep_prefix_8_byte:
       expand_setmem_via_rep_stos (dst, destreg, promoted_val, count_exp,
-                                 DImode);
+                                 DImode, val_exp);
       break;
     case rep_prefix_4_byte:
       expand_setmem_via_rep_stos (dst, destreg, promoted_val, count_exp,
-                                 SImode);
+                                 SImode, val_exp);
       break;
     case rep_prefix_1_byte:
       expand_setmem_via_rep_stos (dst, destreg, promoted_val, count_exp,
-                                 QImode);
+                                 QImode, val_exp);
       break;
     }
   /* Adjust properly the offset of src and dest memory for aliasing.  */
@@ -16025,27 +18906,27 @@ ix86_expand_setmem (rtx dst, rtx count_exp, rtx val_exp, rtx align_exp,
         Epilogue code will actually copy COUNT_EXP & EPILOGUE_SIZE_NEEDED
         bytes. Compensate if needed.  */
 
-      if (size_needed < desired_align - align)
+      if (size_needed < epilogue_size_needed)
        {
          tmp =
            expand_simple_binop (counter_mode (count_exp), AND, count_exp,
                                 GEN_INT (size_needed - 1), count_exp, 1,
                                 OPTAB_DIRECT);
-         size_needed = desired_align - align + 1;
          if (tmp != count_exp)
            emit_move_insn (count_exp, tmp);
        }
       emit_label (label);
       LABEL_NUSES (label) = 1;
     }
+ epilogue:
   if (count_exp != const0_rtx && epilogue_size_needed > 1)
     {
       if (force_loopy_epilogue)
        expand_setmem_epilogue_via_loop (dst, destreg, val_exp, count_exp,
-                                        size_needed);
+                                        epilogue_size_needed);
       else
        expand_setmem_epilogue (dst, destreg, promoted_val, count_exp,
-                               size_needed);
+                               epilogue_size_needed);
     }
   if (jump_around_label)
     emit_label (jump_around_label);
@@ -16126,10 +19007,7 @@ ix86_expand_strlensi_unroll_1 (rtx out, rtx src, rtx align_rtx)
                               QImode, 1, end_0_label);
 
       /* Increment the address.  */
-      if (TARGET_64BIT)
-       emit_insn (gen_adddi3 (out, out, const1_rtx));
-      else
-       emit_insn (gen_addsi3 (out, out, const1_rtx));
+      emit_insn ((*ix86_gen_add3) (out, out, const1_rtx));
 
       /* Not needed with an alignment of 2 */
       if (align != 2)
@@ -16139,10 +19017,7 @@ ix86_expand_strlensi_unroll_1 (rtx out, rtx src, rtx align_rtx)
          emit_cmp_and_jump_insns (mem, const0_rtx, EQ, NULL, QImode, 1,
                                   end_0_label);
 
-         if (TARGET_64BIT)
-           emit_insn (gen_adddi3 (out, out, const1_rtx));
-         else
-           emit_insn (gen_addsi3 (out, out, const1_rtx));
+         emit_insn ((*ix86_gen_add3) (out, out, const1_rtx));
 
          emit_label (align_3_label);
        }
@@ -16150,10 +19025,7 @@ ix86_expand_strlensi_unroll_1 (rtx out, rtx src, rtx align_rtx)
       emit_cmp_and_jump_insns (mem, const0_rtx, EQ, NULL, QImode, 1,
                               end_0_label);
 
-      if (TARGET_64BIT)
-       emit_insn (gen_adddi3 (out, out, const1_rtx));
-      else
-       emit_insn (gen_addsi3 (out, out, const1_rtx));
+      emit_insn ((*ix86_gen_add3) (out, out, const1_rtx));
     }
 
   /* Generate loop to check 4 bytes at a time.  It is not a good idea to
@@ -16163,10 +19035,7 @@ ix86_expand_strlensi_unroll_1 (rtx out, rtx src, rtx align_rtx)
 
   mem = change_address (src, SImode, out);
   emit_move_insn (scratch, mem);
-  if (TARGET_64BIT)
-    emit_insn (gen_adddi3 (out, out, GEN_INT (4)));
-  else
-    emit_insn (gen_addsi3 (out, out, GEN_INT (4)));
+  emit_insn ((*ix86_gen_add3) (out, out, GEN_INT (4)));
 
   /* This formula yields a nonzero result iff one of the bytes is zero.
      This saves three branches inside loop and many cycles.  */
@@ -16222,10 +19091,7 @@ ix86_expand_strlensi_unroll_1 (rtx out, rtx src, rtx align_rtx)
 
        /* Not in the first two.  Move two bytes forward.  */
        emit_insn (gen_lshrsi3 (tmpreg, tmpreg, GEN_INT (16)));
-       if (TARGET_64BIT)
-        emit_insn (gen_adddi3 (out, out, const2_rtx));
-       else
-        emit_insn (gen_addsi3 (out, out, const2_rtx));
+       emit_insn ((*ix86_gen_add3) (out, out, const2_rtx));
 
        emit_label (end_2_label);
 
@@ -16235,10 +19101,7 @@ ix86_expand_strlensi_unroll_1 (rtx out, rtx src, rtx align_rtx)
   tmpreg = gen_lowpart (QImode, tmpreg);
   emit_insn (gen_addqi3_cc (tmpreg, tmpreg, tmpreg));
   cmp = gen_rtx_LTU (Pmode, gen_rtx_REG (CCmode, FLAGS_REG), const0_rtx);
-  if (TARGET_64BIT)
-    emit_insn (gen_subdi3_carry_rex64 (out, out, GEN_INT (3), cmp));
-  else
-    emit_insn (gen_subsi3_carry (out, out, GEN_INT (3), cmp));
+  emit_insn ((*ix86_gen_sub3_carry) (out, out, GEN_INT (3), cmp));
 
   emit_label (end_0_label);
 }
@@ -16255,7 +19118,7 @@ ix86_expand_strlen (rtx out, rtx src, rtx eoschar, rtx align)
 
   if (TARGET_UNROLL_STRLEN && eoschar == const0_rtx && optimize > 1
       && !TARGET_INLINE_ALL_STRINGOPS
-      && !optimize_size
+      && !optimize_insn_for_size_p ()
       && (!CONST_INT_P (align) || INTVAL (align) < 4))
     return 0;
 
@@ -16263,7 +19126,7 @@ ix86_expand_strlen (rtx out, rtx src, rtx eoschar, rtx align)
   scratch1 = gen_reg_rtx (Pmode);
 
   if (TARGET_UNROLL_STRLEN && eoschar == const0_rtx && optimize > 1
-      && !optimize_size)
+      && !optimize_insn_for_size_p ())
     {
       /* Well it seems that some optimizer does not combine a call like
          foo(strlen(bar), strlen(bar));
@@ -16280,10 +19143,7 @@ ix86_expand_strlen (rtx out, rtx src, rtx eoschar, rtx align)
       /* strlensi_unroll_1 returns the address of the zero at the end of
          the string, like memchr(), so compute the length by subtracting
          the start address.  */
-      if (TARGET_64BIT)
-       emit_insn (gen_subdi3 (out, out, addr));
-      else
-       emit_insn (gen_subsi3 (out, out, addr));
+      emit_insn ((*ix86_gen_sub3) (out, out, addr));
     }
   else
     {
@@ -16306,16 +19166,8 @@ ix86_expand_strlen (rtx out, rtx src, rtx eoschar, rtx align)
       unspec = gen_rtx_UNSPEC (Pmode, gen_rtvec (4, src, eoschar, align,
                                                 scratch4), UNSPEC_SCAS);
       emit_insn (gen_strlenqi_1 (scratch1, scratch3, unspec));
-      if (TARGET_64BIT)
-       {
-         emit_insn (gen_one_cmpldi2 (scratch2, scratch1));
-         emit_insn (gen_adddi3 (out, scratch2, constm1_rtx));
-       }
-      else
-       {
-         emit_insn (gen_one_cmplsi2 (scratch2, scratch1));
-         emit_insn (gen_addsi3 (out, scratch2, constm1_rtx));
-       }
+      emit_insn ((*ix86_gen_one_cmpl2) (scratch2, scratch1));
+      emit_insn ((*ix86_gen_add3) (out, scratch2, constm1_rtx));
     }
   return 1;
 }
@@ -16338,7 +19190,7 @@ construct_plt_address (rtx symbol)
 
 void
 ix86_expand_call (rtx retval, rtx fnaddr, rtx callarg1,
-                 rtx callarg2 ATTRIBUTE_UNUSED,
+                 rtx callarg2,
                  rtx pop, int sibcall)
 {
   rtx use = NULL, call;
@@ -16371,24 +19223,17 @@ ix86_expand_call (rtx retval, rtx fnaddr, rtx callarg1,
     }
 
   if (ix86_cmodel == CM_LARGE_PIC
-      && GET_CODE (fnaddr) == MEM
+      && MEM_P (fnaddr) 
       && GET_CODE (XEXP (fnaddr, 0)) == SYMBOL_REF
       && !local_symbolic_operand (XEXP (fnaddr, 0), VOIDmode))
     fnaddr = gen_rtx_MEM (QImode, construct_plt_address (XEXP (fnaddr, 0)));
-  else if (! call_insn_operand (XEXP (fnaddr, 0), Pmode))
+  else if (sibcall
+          ? !sibcall_insn_operand (XEXP (fnaddr, 0), Pmode)
+          : !call_insn_operand (XEXP (fnaddr, 0), Pmode))
     {
       fnaddr = copy_to_mode_reg (Pmode, XEXP (fnaddr, 0));
       fnaddr = gen_rtx_MEM (QImode, fnaddr);
     }
-  if (sibcall && TARGET_64BIT
-      && !constant_call_address_operand (XEXP (fnaddr, 0), Pmode))
-    {
-      rtx addr;
-      addr = copy_to_mode_reg (Pmode, XEXP (fnaddr, 0));
-      fnaddr = gen_rtx_REG (Pmode, R11_REG);
-      emit_move_insn (fnaddr, addr);
-      fnaddr = gen_rtx_MEM (QImode, fnaddr);
-    }
 
   call = gen_rtx_CALL (VOIDmode, fnaddr, callarg1);
   if (retval)
@@ -16399,6 +19244,37 @@ ix86_expand_call (rtx retval, rtx fnaddr, rtx callarg1,
       pop = gen_rtx_SET (VOIDmode, stack_pointer_rtx, pop);
       call = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, call, pop));
     }
+  if (TARGET_64BIT
+      && ix86_cfun_abi () == MS_ABI
+      && (!callarg2 || INTVAL (callarg2) != -2))
+    {
+      /* We need to represent that SI and DI registers are clobbered
+        by SYSV calls.  */
+      static int clobbered_registers[] = {
+       XMM6_REG, XMM7_REG, XMM8_REG,
+       XMM9_REG, XMM10_REG, XMM11_REG,
+       XMM12_REG, XMM13_REG, XMM14_REG,
+       XMM15_REG, SI_REG, DI_REG
+      };
+      unsigned int i;
+      rtx vec[ARRAY_SIZE (clobbered_registers) + 2];
+      rtx unspec = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, const0_rtx),
+                                  UNSPEC_MS_TO_SYSV_CALL);
+
+      vec[0] = call;
+      vec[1] = unspec;
+      for (i = 0; i < ARRAY_SIZE (clobbered_registers); i++)
+        vec[i + 2] = gen_rtx_CLOBBER (SSE_REGNO_P (clobbered_registers[i])
+                                     ? TImode : DImode,
+                                     gen_rtx_REG
+                                       (SSE_REGNO_P (clobbered_registers[i])
+                                                     ? TImode : DImode,
+                                        clobbered_registers[i]));
+
+      call = gen_rtx_PARALLEL (VOIDmode,
+                              gen_rtvec_v (ARRAY_SIZE (clobbered_registers)
+                              + 2, vec));
+    }
 
   call = emit_call_insn (call);
   if (use)
@@ -16418,6 +19294,7 @@ ix86_init_machine_status (void)
   f = GGC_CNEW (struct machine_function);
   f->use_fast_prologue_epilogue_nregs = -1;
   f->tls_descriptor_call_expanded_p = 0;
+  f->call_abi = ix86_abi;
 
   return f;
 }
@@ -16522,23 +19399,53 @@ memory_address_length (rtx addr)
 
   /* Rule of thumb:
        - esp as the base always wants an index,
-       - ebp as the base always wants a displacement.  */
+       - ebp as the base always wants a displacement,
+       - r12 as the base always wants an index,
+       - r13 as the base always wants a displacement.  */
 
   /* Register Indirect.  */
   if (base && !index && !disp)
     {
       /* esp (for its index) and ebp (for its displacement) need
-        the two-byte modrm form.  */
-      if (addr == stack_pointer_rtx
-         || addr == arg_pointer_rtx
-         || addr == frame_pointer_rtx
-         || addr == hard_frame_pointer_rtx)
+        the two-byte modrm form.  Similarly for r12 and r13 in 64-bit
+        code.  */
+      if (REG_P (addr)
+         && (addr == arg_pointer_rtx
+             || addr == frame_pointer_rtx
+             || REGNO (addr) == SP_REG
+             || REGNO (addr) == BP_REG
+             || REGNO (addr) == R12_REG
+             || REGNO (addr) == R13_REG))
        len = 1;
     }
 
-  /* Direct Addressing.  */
+  /* Direct Addressing.  In 64-bit mode mod 00 r/m 5
+     is not disp32, but disp32(%rip), so for disp32
+     SIB byte is needed, unless print_operand_address
+     optimizes it into disp32(%rip) or (%rip) is implied
+     by UNSPEC.  */
   else if (disp && !base && !index)
-    len = 4;
+    {
+      len = 4;
+      if (TARGET_64BIT)
+       {
+         rtx symbol = disp;
+
+         if (GET_CODE (disp) == CONST)
+           symbol = XEXP (disp, 0);
+         if (GET_CODE (symbol) == PLUS
+             && CONST_INT_P (XEXP (symbol, 1)))
+           symbol = XEXP (symbol, 0);
+
+         if (GET_CODE (symbol) != LABEL_REF
+             && (GET_CODE (symbol) != SYMBOL_REF
+                 || SYMBOL_REF_TLS_MODEL (symbol) != 0)
+             && (GET_CODE (symbol) != UNSPEC
+                 || (XINT (symbol, 1) != UNSPEC_GOTPCREL
+                     && XINT (symbol, 1) != UNSPEC_GOTNTPOFF)))
+           len += 1;
+       }
+    }
 
   else
     {
@@ -16550,19 +19457,31 @@ memory_address_length (rtx addr)
          else
            len = 4;
        }
-      /* ebp always wants a displacement.  */
-      else if (base == hard_frame_pointer_rtx)
-        len = 1;
+      /* ebp always wants a displacement.  Similarly r13.  */
+      else if (base && REG_P (base)
+              && (REGNO (base) == BP_REG || REGNO (base) == R13_REG))
+       len = 1;
 
       /* An index requires the two-byte modrm form....  */
       if (index
-         /* ...like esp, which always wants an index.  */
-         || base == stack_pointer_rtx
+         /* ...like esp (or r12), which always wants an index.  */
          || base == arg_pointer_rtx
-         || base == frame_pointer_rtx)
+         || base == frame_pointer_rtx
+         || (base && REG_P (base)
+             && (REGNO (base) == SP_REG || REGNO (base) == R12_REG)))
        len += 1;
     }
 
+  switch (parts.seg)
+    {
+    case SEG_FS:
+    case SEG_GS:
+      len += 1;
+      break;
+    default:
+      break;
+    }
+
   return len;
 }
 
@@ -16577,30 +19496,50 @@ ix86_attr_length_immediate_default (rtx insn, int shortform)
   for (i = recog_data.n_operands - 1; i >= 0; --i)
     if (CONSTANT_P (recog_data.operand[i]))
       {
+        enum attr_mode mode = get_attr_mode (insn);
+
        gcc_assert (!len);
-       if (shortform && satisfies_constraint_K (recog_data.operand[i]))
-         len = 1;
-       else
+       if (shortform && CONST_INT_P (recog_data.operand[i]))
          {
-           switch (get_attr_mode (insn))
+           HOST_WIDE_INT ival = INTVAL (recog_data.operand[i]);
+           switch (mode)
              {
-               case MODE_QI:
-                 len+=1;
-                 break;
-               case MODE_HI:
-                 len+=2;
-                 break;
-               case MODE_SI:
-                 len+=4;
-                 break;
-               /* Immediates for DImode instructions are encoded as 32bit sign extended values.  */
-               case MODE_DI:
-                 len+=4;
-                 break;
-               default:
-                 fatal_insn ("unknown insn mode", insn);
+             case MODE_QI:
+               len = 1;
+               continue;
+             case MODE_HI:
+               ival = trunc_int_for_mode (ival, HImode);
+               break;
+             case MODE_SI:
+               ival = trunc_int_for_mode (ival, SImode);
+               break;
+             default:
+               break;
+             }
+           if (IN_RANGE (ival, -128, 127))
+             {
+               len = 1;
+               continue;
              }
          }
+       switch (mode)
+         {
+         case MODE_QI:
+           len = 1;
+           break;
+         case MODE_HI:
+           len = 2;
+           break;
+         case MODE_SI:
+           len = 4;
+           break;
+         /* Immediates for DImode instructions are encoded as 32bit sign extended values.  */
+         case MODE_DI:
+           len = 4;
+           break;
+         default:
+           fatal_insn ("unknown insn mode", insn);
+       }
       }
   return len;
 }
@@ -16612,25 +19551,87 @@ ix86_attr_length_address_default (rtx insn)
 
   if (get_attr_type (insn) == TYPE_LEA)
     {
-      rtx set = PATTERN (insn);
+      rtx set = PATTERN (insn), addr;
 
       if (GET_CODE (set) == PARALLEL)
        set = XVECEXP (set, 0, 0);
 
       gcc_assert (GET_CODE (set) == SET);
 
-      return memory_address_length (SET_SRC (set));
+      addr = SET_SRC (set);
+      if (TARGET_64BIT && get_attr_mode (insn) == MODE_SI)
+       {
+         if (GET_CODE (addr) == ZERO_EXTEND)
+           addr = XEXP (addr, 0);
+         if (GET_CODE (addr) == SUBREG)
+           addr = SUBREG_REG (addr);
+       }
+
+      return memory_address_length (addr);
     }
 
   extract_insn_cached (insn);
   for (i = recog_data.n_operands - 1; i >= 0; --i)
     if (MEM_P (recog_data.operand[i]))
       {
+        constrain_operands_cached (reload_completed);
+        if (which_alternative != -1)
+         {
+           const char *constraints = recog_data.constraints[i];
+           int alt = which_alternative;
+
+           while (*constraints == '=' || *constraints == '+')
+             constraints++;
+           while (alt-- > 0)
+             while (*constraints++ != ',')
+               ;
+           /* Skip ignored operands.  */
+           if (*constraints == 'X')
+             continue;
+         }
        return memory_address_length (XEXP (recog_data.operand[i], 0));
-       break;
       }
   return 0;
 }
+
+/* Compute default value for "length_vex" attribute. It includes
+   2 or 3 byte VEX prefix and 1 opcode byte.  */
+
+int
+ix86_attr_length_vex_default (rtx insn, int has_0f_opcode,
+                             int has_vex_w)
+{
+  int i;
+
+  /* Only 0f opcode can use 2 byte VEX prefix and  VEX W bit uses 3
+     byte VEX prefix.  */
+  if (!has_0f_opcode || has_vex_w)
+    return 3 + 1;
+
+ /* We can always use 2 byte VEX prefix in 32bit.  */
+  if (!TARGET_64BIT)
+    return 2 + 1;
+
+  extract_insn_cached (insn);
+
+  for (i = recog_data.n_operands - 1; i >= 0; --i)
+    if (REG_P (recog_data.operand[i]))
+      {
+       /* REX.W bit uses 3 byte VEX prefix.  */
+       if (GET_MODE (recog_data.operand[i]) == DImode
+           && GENERAL_REG_P (recog_data.operand[i]))
+         return 3 + 1;
+      }
+    else
+      {
+       /* REX.X or REX.B bits use 3 byte VEX prefix.  */
+       if (MEM_P (recog_data.operand[i])
+           && x86_extended_reg_mentioned_p (recog_data.operand[i]))
+         return 3 + 1;
+      }
+
+  return 2 + 1;
+}
 \f
 /* Return the maximum number of instructions a cpu can issue.  */
 
@@ -16640,6 +19641,7 @@ ix86_issue_rate (void)
   switch (ix86_tune)
     {
     case PROCESSOR_PENTIUM:
+    case PROCESSOR_ATOM:
     case PROCESSOR_K6:
       return 2;
 
@@ -16706,41 +19708,21 @@ ix86_flags_dependent (rtx insn, rtx dep_insn, enum attr_type insn_type)
   return 1;
 }
 
-/* A subroutine of ix86_adjust_cost -- return true iff INSN has a memory
-   address with operands set by DEP_INSN.  */
+/* Return true iff USE_INSN has a memory address with operands set by
+   SET_INSN.  */
 
-static int
-ix86_agi_dependent (rtx insn, rtx dep_insn, enum attr_type insn_type)
+bool
+ix86_agi_dependent (rtx set_insn, rtx use_insn)
 {
-  rtx addr;
-
-  if (insn_type == TYPE_LEA
-      && TARGET_PENTIUM)
-    {
-      addr = PATTERN (insn);
-
-      if (GET_CODE (addr) == PARALLEL)
-       addr = XVECEXP (addr, 0, 0);
-
-      gcc_assert (GET_CODE (addr) == SET);
-
-      addr = SET_SRC (addr);
-    }
-  else
-    {
-      int i;
-      extract_insn_cached (insn);
-      for (i = recog_data.n_operands - 1; i >= 0; --i)
-       if (MEM_P (recog_data.operand[i]))
-         {
-           addr = XEXP (recog_data.operand[i], 0);
-           goto found;
-         }
-      return 0;
-    found:;
-    }
-
-  return modified_in_p (addr, dep_insn);
+  int i;
+  extract_insn_cached (use_insn);
+  for (i = recog_data.n_operands - 1; i >= 0; --i)
+    if (MEM_P (recog_data.operand[i]))
+      {
+       rtx addr = XEXP (recog_data.operand[i], 0);
+       return modified_in_p (addr, set_insn) != 0;
+      }
+  return false;
 }
 
 static int
@@ -16768,7 +19750,20 @@ ix86_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
     {
     case PROCESSOR_PENTIUM:
       /* Address Generation Interlock adds a cycle of latency.  */
-      if (ix86_agi_dependent (insn, dep_insn, insn_type))
+      if (insn_type == TYPE_LEA)
+       {
+         rtx addr = PATTERN (insn);
+
+         if (GET_CODE (addr) == PARALLEL)
+           addr = XVECEXP (addr, 0, 0);
+
+         gcc_assert (GET_CODE (addr) == SET);
+
+         addr = SET_SRC (addr);
+         if (modified_in_p (addr, dep_insn))
+           cost += 1;
+       }
+      else if (ix86_agi_dependent (dep_insn, insn))
        cost += 1;
 
       /* ??? Compares pair with jump/setcc.  */
@@ -16778,7 +19773,7 @@ ix86_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
       /* Floating point stores require value to be ready one cycle earlier.  */
       if (insn_type == TYPE_FMOV
          && get_attr_memory (insn) == MEMORY_STORE
-         && !ix86_agi_dependent (insn, dep_insn, insn_type))
+         && !ix86_agi_dependent (dep_insn, insn))
        cost += 1;
       break;
 
@@ -16801,7 +19796,7 @@ ix86_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
         in parallel with previous instruction in case
         previous instruction is not needed to compute the address.  */
       if ((memory == MEMORY_LOAD || memory == MEMORY_BOTH)
-         && !ix86_agi_dependent (insn, dep_insn, insn_type))
+         && !ix86_agi_dependent (dep_insn, insn))
        {
          /* Claim moves to take one cycle, as core can issue one load
             at time and the next load can start cycle later.  */
@@ -16830,7 +19825,7 @@ ix86_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
         in parallel with previous instruction in case
         previous instruction is not needed to compute the address.  */
       if ((memory == MEMORY_LOAD || memory == MEMORY_BOTH)
-         && !ix86_agi_dependent (insn, dep_insn, insn_type))
+         && !ix86_agi_dependent (dep_insn, insn))
        {
          /* Claim moves to take one cycle, as core can issue one load
             at time and the next load can start cycle later.  */
@@ -16847,6 +19842,7 @@ ix86_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
     case PROCESSOR_ATHLON:
     case PROCESSOR_K8:
     case PROCESSOR_AMDFAM10:
+    case PROCESSOR_ATOM:
     case PROCESSOR_GENERIC32:
     case PROCESSOR_GENERIC64:
       memory = get_attr_memory (insn);
@@ -16855,7 +19851,7 @@ ix86_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
         in parallel with previous instruction in case
         previous instruction is not needed to compute the address.  */
       if ((memory == MEMORY_LOAD || memory == MEMORY_BOTH)
-         && !ix86_agi_dependent (insn, dep_insn, insn_type))
+         && !ix86_agi_dependent (dep_insn, insn))
        {
          enum attr_unit unit = get_attr_unit (insn);
          int loadcost = 3;
@@ -16971,7 +19967,8 @@ ix86_data_alignment (tree type, int align)
 
       if (TYPE_MODE (type) == DCmode && align < 64)
        return 64;
-      if (TYPE_MODE (type) == XCmode && align < 128)
+      if ((TYPE_MODE (type) == XCmode
+          || TYPE_MODE (type) == TCmode) && align < 128)
        return 128;
     }
   else if ((TREE_CODE (type) == RECORD_TYPE
@@ -16996,14 +19993,49 @@ ix86_data_alignment (tree type, int align)
   return align;
 }
 
-/* Compute the alignment for a local variable.
-   TYPE is the data type, and ALIGN is the alignment that
-   the object would ordinarily have.  The value of this macro is used
-   instead of that alignment to align the object.  */
+/* Compute the alignment for a local variable or a stack slot.  EXP is
+   the data type or decl itself, MODE is the widest mode available and
+   ALIGN is the alignment that the object would ordinarily have.  The
+   value of this macro is used instead of that alignment to align the
+   object.  */
 
-int
-ix86_local_alignment (tree type, int align)
+unsigned int
+ix86_local_alignment (tree exp, enum machine_mode mode,
+                     unsigned int align)
 {
+  tree type, decl;
+
+  if (exp && DECL_P (exp))
+    {
+      type = TREE_TYPE (exp);
+      decl = exp;
+    }
+  else
+    {
+      type = exp;
+      decl = NULL;
+    }
+
+  /* Don't do dynamic stack realignment for long long objects with
+     -mpreferred-stack-boundary=2.  */
+  if (!TARGET_64BIT
+      && align == 64
+      && ix86_preferred_stack_boundary < 64
+      && (mode == DImode || (type && TYPE_MODE (type) == DImode))
+      && (!type || !TYPE_USER_ALIGN (type))
+      && (!decl || !DECL_USER_ALIGN (decl)))
+    align = 32;
+
+  /* If TYPE is NULL, we are allocating a stack slot for caller-save
+     register in MODE.  We will return the largest alignment of XF
+     and DF.  */
+  if (!type)
+    {
+      if (mode == XFmode && align < GET_MODE_ALIGNMENT (DFmode))
+       align = GET_MODE_ALIGNMENT (DFmode);
+      return align;
+    }
+
   /* x86-64 ABI requires arrays greater than 16 bytes to be aligned
      to 16byte boundary.  */
   if (TARGET_64BIT)
@@ -17026,7 +20058,8 @@ ix86_local_alignment (tree type, int align)
     {
       if (TYPE_MODE (type) == DCmode && align < 64)
        return 64;
-      if (TYPE_MODE (type) == XCmode && align < 128)
+      if ((TYPE_MODE (type) == XCmode
+          || TYPE_MODE (type) == TCmode) && align < 128)
        return 128;
     }
   else if ((TREE_CODE (type) == RECORD_TYPE
@@ -17050,6 +20083,41 @@ ix86_local_alignment (tree type, int align)
     }
   return align;
 }
+
+/* Compute the minimum required alignment for dynamic stack realignment
+   purposes for a local variable, parameter or a stack slot.  EXP is
+   the data type or decl itself, MODE is its mode and ALIGN is the
+   alignment that the object would ordinarily have.  */
+
+unsigned int
+ix86_minimum_alignment (tree exp, enum machine_mode mode,
+                       unsigned int align)
+{
+  tree type, decl;
+
+  if (TARGET_64BIT || align != 64 || ix86_preferred_stack_boundary >= 64)
+    return align;
+
+  if (exp && DECL_P (exp))
+    {
+      type = TREE_TYPE (exp);
+      decl = exp;
+    }
+  else
+    {
+      type = exp;
+      decl = NULL;
+    }
+
+  /* Don't do dynamic stack realignment for long long objects with
+     -mpreferred-stack-boundary=2.  */
+  if ((mode == DImode || (type && TYPE_MODE (type) == DImode))
+      && (!type || !TYPE_USER_ALIGN (type))
+      && (!decl || !DECL_USER_ALIGN (decl)))
+    return 32;
+
+  return align;
+}
 \f
 /* Emit RTL insns to initialize the variable parts of a trampoline.
    FNADDR is an RTX for the address of the function's pure code.
@@ -17424,6 +20492,8 @@ enum ix86_builtins
   IX86_BUILTIN_MOVNTPD,
   IX86_BUILTIN_MOVNTDQ,
 
+  IX86_BUILTIN_MOVQ128,
+
   /* SSE2 MMX */
   IX86_BUILTIN_MASKMOVDQU,
   IX86_BUILTIN_MOVMSKPD,
@@ -17517,6 +20587,16 @@ enum ix86_builtins
   IX86_BUILTIN_MFENCE,
   IX86_BUILTIN_LFENCE,
 
+  IX86_BUILTIN_BSRSI,
+  IX86_BUILTIN_BSRDI,
+  IX86_BUILTIN_RDPMC,
+  IX86_BUILTIN_RDTSC,
+  IX86_BUILTIN_RDTSCP,
+  IX86_BUILTIN_ROLQI,
+  IX86_BUILTIN_ROLHI,
+  IX86_BUILTIN_RORQI,
+  IX86_BUILTIN_RORHI,
+
   /* SSE3.  */
   IX86_BUILTIN_ADDSUBPS,
   IX86_BUILTIN_HADDPS,
@@ -17683,11 +20763,155 @@ enum ix86_builtins
   /* PCLMUL instruction */
   IX86_BUILTIN_PCLMULQDQ128,
 
+  /* AVX */
+  IX86_BUILTIN_ADDPD256,
+  IX86_BUILTIN_ADDPS256,
+  IX86_BUILTIN_ADDSUBPD256,
+  IX86_BUILTIN_ADDSUBPS256,
+  IX86_BUILTIN_ANDPD256,
+  IX86_BUILTIN_ANDPS256,
+  IX86_BUILTIN_ANDNPD256,
+  IX86_BUILTIN_ANDNPS256,
+  IX86_BUILTIN_BLENDPD256,
+  IX86_BUILTIN_BLENDPS256,
+  IX86_BUILTIN_BLENDVPD256,
+  IX86_BUILTIN_BLENDVPS256,
+  IX86_BUILTIN_DIVPD256,
+  IX86_BUILTIN_DIVPS256,
+  IX86_BUILTIN_DPPS256,
+  IX86_BUILTIN_HADDPD256,
+  IX86_BUILTIN_HADDPS256,
+  IX86_BUILTIN_HSUBPD256,
+  IX86_BUILTIN_HSUBPS256,
+  IX86_BUILTIN_MAXPD256,
+  IX86_BUILTIN_MAXPS256,
+  IX86_BUILTIN_MINPD256,
+  IX86_BUILTIN_MINPS256,
+  IX86_BUILTIN_MULPD256,
+  IX86_BUILTIN_MULPS256,
+  IX86_BUILTIN_ORPD256,
+  IX86_BUILTIN_ORPS256,
+  IX86_BUILTIN_SHUFPD256,
+  IX86_BUILTIN_SHUFPS256,
+  IX86_BUILTIN_SUBPD256,
+  IX86_BUILTIN_SUBPS256,
+  IX86_BUILTIN_XORPD256,
+  IX86_BUILTIN_XORPS256,
+  IX86_BUILTIN_CMPSD,
+  IX86_BUILTIN_CMPSS,
+  IX86_BUILTIN_CMPPD,
+  IX86_BUILTIN_CMPPS,
+  IX86_BUILTIN_CMPPD256,
+  IX86_BUILTIN_CMPPS256,
+  IX86_BUILTIN_CVTDQ2PD256,
+  IX86_BUILTIN_CVTDQ2PS256,
+  IX86_BUILTIN_CVTPD2PS256,
+  IX86_BUILTIN_CVTPS2DQ256,
+  IX86_BUILTIN_CVTPS2PD256,
+  IX86_BUILTIN_CVTTPD2DQ256,
+  IX86_BUILTIN_CVTPD2DQ256,
+  IX86_BUILTIN_CVTTPS2DQ256,
+  IX86_BUILTIN_EXTRACTF128PD256,
+  IX86_BUILTIN_EXTRACTF128PS256,
+  IX86_BUILTIN_EXTRACTF128SI256,
+  IX86_BUILTIN_VZEROALL,
+  IX86_BUILTIN_VZEROUPPER,
+  IX86_BUILTIN_VZEROUPPER_REX64,
+  IX86_BUILTIN_VPERMILVARPD,
+  IX86_BUILTIN_VPERMILVARPS,
+  IX86_BUILTIN_VPERMILVARPD256,
+  IX86_BUILTIN_VPERMILVARPS256,
+  IX86_BUILTIN_VPERMILPD,
+  IX86_BUILTIN_VPERMILPS,
+  IX86_BUILTIN_VPERMILPD256,
+  IX86_BUILTIN_VPERMILPS256,
+  IX86_BUILTIN_VPERM2F128PD256,
+  IX86_BUILTIN_VPERM2F128PS256,
+  IX86_BUILTIN_VPERM2F128SI256,
+  IX86_BUILTIN_VBROADCASTSS,
+  IX86_BUILTIN_VBROADCASTSD256,
+  IX86_BUILTIN_VBROADCASTSS256,
+  IX86_BUILTIN_VBROADCASTPD256,
+  IX86_BUILTIN_VBROADCASTPS256,
+  IX86_BUILTIN_VINSERTF128PD256,
+  IX86_BUILTIN_VINSERTF128PS256,
+  IX86_BUILTIN_VINSERTF128SI256,
+  IX86_BUILTIN_LOADUPD256,
+  IX86_BUILTIN_LOADUPS256,
+  IX86_BUILTIN_STOREUPD256,
+  IX86_BUILTIN_STOREUPS256,
+  IX86_BUILTIN_LDDQU256,
+  IX86_BUILTIN_MOVNTDQ256,
+  IX86_BUILTIN_MOVNTPD256,
+  IX86_BUILTIN_MOVNTPS256,
+  IX86_BUILTIN_LOADDQU256,
+  IX86_BUILTIN_STOREDQU256,
+  IX86_BUILTIN_MASKLOADPD,
+  IX86_BUILTIN_MASKLOADPS,
+  IX86_BUILTIN_MASKSTOREPD,
+  IX86_BUILTIN_MASKSTOREPS,
+  IX86_BUILTIN_MASKLOADPD256,
+  IX86_BUILTIN_MASKLOADPS256,
+  IX86_BUILTIN_MASKSTOREPD256,
+  IX86_BUILTIN_MASKSTOREPS256,
+  IX86_BUILTIN_MOVSHDUP256,
+  IX86_BUILTIN_MOVSLDUP256,
+  IX86_BUILTIN_MOVDDUP256,
+
+  IX86_BUILTIN_SQRTPD256,
+  IX86_BUILTIN_SQRTPS256,
+  IX86_BUILTIN_SQRTPS_NR256,
+  IX86_BUILTIN_RSQRTPS256,
+  IX86_BUILTIN_RSQRTPS_NR256,
+
+  IX86_BUILTIN_RCPPS256,
+
+  IX86_BUILTIN_ROUNDPD256,
+  IX86_BUILTIN_ROUNDPS256,
+
+  IX86_BUILTIN_UNPCKHPD256,
+  IX86_BUILTIN_UNPCKLPD256,
+  IX86_BUILTIN_UNPCKHPS256,
+  IX86_BUILTIN_UNPCKLPS256,
+
+  IX86_BUILTIN_SI256_SI,
+  IX86_BUILTIN_PS256_PS,
+  IX86_BUILTIN_PD256_PD,
+  IX86_BUILTIN_SI_SI256,
+  IX86_BUILTIN_PS_PS256,
+  IX86_BUILTIN_PD_PD256,
+
+  IX86_BUILTIN_VTESTZPD,
+  IX86_BUILTIN_VTESTCPD,
+  IX86_BUILTIN_VTESTNZCPD,
+  IX86_BUILTIN_VTESTZPS,
+  IX86_BUILTIN_VTESTCPS,
+  IX86_BUILTIN_VTESTNZCPS,
+  IX86_BUILTIN_VTESTZPD256,
+  IX86_BUILTIN_VTESTCPD256,
+  IX86_BUILTIN_VTESTNZCPD256,
+  IX86_BUILTIN_VTESTZPS256,
+  IX86_BUILTIN_VTESTCPS256,
+  IX86_BUILTIN_VTESTNZCPS256,
+  IX86_BUILTIN_PTESTZ256,
+  IX86_BUILTIN_PTESTC256,
+  IX86_BUILTIN_PTESTNZC256,
+
+  IX86_BUILTIN_MOVMSKPD256,
+  IX86_BUILTIN_MOVMSKPS256,
+
   /* TFmode support builtins.  */
   IX86_BUILTIN_INFQ,
+  IX86_BUILTIN_HUGE_VALQ,
   IX86_BUILTIN_FABSQ,
   IX86_BUILTIN_COPYSIGNQ,
 
+  /* Vectorizer support builtins.  */
+  IX86_BUILTIN_CPYSGNPS,
+  IX86_BUILTIN_CPYSGNPD,
+
+  IX86_BUILTIN_CVTUDQ2PS,
+
   /* SSE5 instructions */
   IX86_BUILTIN_FMADDSS,
   IX86_BUILTIN_FMADDSD,
@@ -17705,6 +20929,7 @@ enum ix86_builtins
   IX86_BUILTIN_FNMSUBSD,
   IX86_BUILTIN_FNMSUBPS,
   IX86_BUILTIN_FNMSUBPD,
+  IX86_BUILTIN_PCMOV,
   IX86_BUILTIN_PCMOV_V2DI,
   IX86_BUILTIN_PCMOV_V4SI,
   IX86_BUILTIN_PCMOV_V8HI,
@@ -17904,22 +21129,61 @@ enum ix86_builtins
 /* Table for the ix86 builtin decls.  */
 static GTY(()) tree ix86_builtins[(int) IX86_BUILTIN_MAX];
 
-/* Add an ix86 target builtin function with CODE, NAME and TYPE.  Do so,
- * if the target_flags include one of MASK.  Stores the function decl
- * in the ix86_builtins array.
- * Returns the function decl or NULL_TREE, if the builtin was not added.  */
+/* Table of all of the builtin functions that are possible with different ISA's
+   but are waiting to be built until a function is declared to use that
+   ISA.  */
+struct GTY(()) builtin_isa {
+  tree type;                   /* builtin type to use in the declaration */
+  const char *name;            /* function name */
+  int isa;                     /* isa_flags this builtin is defined for */
+  bool const_p;                        /* true if the declaration is constant */
+};
+
+static GTY(()) struct builtin_isa ix86_builtins_isa[(int) IX86_BUILTIN_MAX];
+
+
+/* Add an ix86 target builtin function with CODE, NAME and TYPE.  Save the MASK
+ * of which isa_flags to use in the ix86_builtins_isa array.  Stores the
+ * function decl in the ix86_builtins array.  Returns the function decl or
+ * NULL_TREE, if the builtin was not added.
+ *
+ * If the front end has a special hook for builtin functions, delay adding
+ * builtin functions that aren't in the current ISA until the ISA is changed
+ * with function specific optimization.  Doing so, can save about 300K for the
+ * default compiler.  When the builtin is expanded, check at that time whether
+ * it is valid.
+ *
+ * If the front end doesn't have a special hook, record all builtins, even if
+ * it isn't an instruction set in the current ISA in case the user uses
+ * function specific options for a different ISA, so that we don't get scope
+ * errors if a builtin is added in the middle of a function scope.  */
 
 static inline tree
 def_builtin (int mask, const char *name, tree type, enum ix86_builtins code)
 {
   tree decl = NULL_TREE;
 
-  if (mask & ix86_isa_flags
-      && (!(mask & OPTION_MASK_ISA_64BIT) || TARGET_64BIT))
+  if (!(mask & OPTION_MASK_ISA_64BIT) || TARGET_64BIT)
     {
-      decl = add_builtin_function (name, type, code, BUILT_IN_MD,
-                                  NULL, NULL_TREE);
-      ix86_builtins[(int) code] = decl;
+      ix86_builtins_isa[(int) code].isa = mask;
+
+      if ((mask & ix86_isa_flags) != 0
+         || (lang_hooks.builtin_function
+             == lang_hooks.builtin_function_ext_scope))
+
+       {
+         decl = add_builtin_function (name, type, code, BUILT_IN_MD, NULL,
+                                      NULL_TREE);
+         ix86_builtins[(int) code] = decl;
+         ix86_builtins_isa[(int) code].type = NULL_TREE;
+       }
+      else
+       {
+         ix86_builtins[(int) code] = NULL_TREE;
+         ix86_builtins_isa[(int) code].const_p = false;
+         ix86_builtins_isa[(int) code].type = type;
+         ix86_builtins_isa[(int) code].name = name;
+       }
     }
 
   return decl;
@@ -17934,9 +21198,40 @@ def_builtin_const (int mask, const char *name, tree type,
   tree decl = def_builtin (mask, name, type, code);
   if (decl)
     TREE_READONLY (decl) = 1;
+  else
+    ix86_builtins_isa[(int) code].const_p = true;
+
   return decl;
 }
 
+/* Add any new builtin functions for a given ISA that may not have been
+   declared.  This saves a bit of space compared to adding all of the
+   declarations to the tree, even if we didn't use them.  */
+
+static void
+ix86_add_new_builtins (int isa)
+{
+  int i;
+  tree decl;
+
+  for (i = 0; i < (int)IX86_BUILTIN_MAX; i++)
+    {
+      if ((ix86_builtins_isa[i].isa & isa) != 0
+         && ix86_builtins_isa[i].type != NULL_TREE)
+       {
+         decl = add_builtin_function_ext_scope (ix86_builtins_isa[i].name,
+                                                ix86_builtins_isa[i].type,
+                                                i, BUILT_IN_MD, NULL,
+                                                NULL_TREE);
+
+         ix86_builtins[i] = decl;
+         ix86_builtins_isa[i].type = NULL_TREE;
+         if (ix86_builtins_isa[i].const_p)
+           TREE_READONLY (decl) = 1;
+       }
+    }
+}
+
 /* Bits for builtin_description.flag.  */
 
 /* Set when we don't support the comparison natively, and should
@@ -18010,19 +21305,38 @@ enum ix86_special_builtin_type
 {
   SPECIAL_FTYPE_UNKNOWN,
   VOID_FTYPE_VOID,
+  UINT64_FTYPE_VOID,
+  UINT64_FTYPE_PUNSIGNED,
+  V32QI_FTYPE_PCCHAR,
   V16QI_FTYPE_PCCHAR,
+  V8SF_FTYPE_PCV4SF,
+  V8SF_FTYPE_PCFLOAT,
+  V4DF_FTYPE_PCV2DF,
+  V4DF_FTYPE_PCDOUBLE,
   V4SF_FTYPE_PCFLOAT,
   V2DF_FTYPE_PCDOUBLE,
+  V8SF_FTYPE_PCV8SF_V8SF,
+  V4DF_FTYPE_PCV4DF_V4DF,
   V4SF_FTYPE_V4SF_PCV2SF,
+  V4SF_FTYPE_PCV4SF_V4SF,
   V2DF_FTYPE_V2DF_PCDOUBLE,
+  V2DF_FTYPE_PCV2DF_V2DF,
   V2DI_FTYPE_PV2DI,
   VOID_FTYPE_PV2SF_V4SF,
+  VOID_FTYPE_PV4DI_V4DI,
   VOID_FTYPE_PV2DI_V2DI,
+  VOID_FTYPE_PCHAR_V32QI,
   VOID_FTYPE_PCHAR_V16QI,
+  VOID_FTYPE_PFLOAT_V8SF,
   VOID_FTYPE_PFLOAT_V4SF,
+  VOID_FTYPE_PDOUBLE_V4DF,
   VOID_FTYPE_PDOUBLE_V2DF,
   VOID_FTYPE_PDI_DI,
-  VOID_FTYPE_PINT_INT
+  VOID_FTYPE_PINT_INT,
+  VOID_FTYPE_PV8SF_V8SF_V8SF,
+  VOID_FTYPE_PV4DF_V4DF_V4DF,
+  VOID_FTYPE_PV4SF_V4SF_V4SF,
+  VOID_FTYPE_PV2DF_V2DF_V2DF
 };
 
 /* Builtin types */
@@ -18032,25 +21346,48 @@ enum ix86_builtin_type
   FLOAT128_FTYPE_FLOAT128,
   FLOAT_FTYPE_FLOAT,
   FLOAT128_FTYPE_FLOAT128_FLOAT128,
+  INT_FTYPE_V8SF_V8SF_PTEST,
+  INT_FTYPE_V4DI_V4DI_PTEST,
+  INT_FTYPE_V4DF_V4DF_PTEST,
+  INT_FTYPE_V4SF_V4SF_PTEST,
   INT_FTYPE_V2DI_V2DI_PTEST,
+  INT_FTYPE_V2DF_V2DF_PTEST,
+  INT_FTYPE_INT,
+  UINT64_FTYPE_INT,
+  INT64_FTYPE_INT64,
   INT64_FTYPE_V4SF,
   INT64_FTYPE_V2DF,
   INT_FTYPE_V16QI,
   INT_FTYPE_V8QI,
+  INT_FTYPE_V8SF,
+  INT_FTYPE_V4DF,
   INT_FTYPE_V4SF,
   INT_FTYPE_V2DF,
   V16QI_FTYPE_V16QI,
+  V8SI_FTYPE_V8SF,
+  V8SI_FTYPE_V4SI,
   V8HI_FTYPE_V8HI,
   V8HI_FTYPE_V16QI,
   V8QI_FTYPE_V8QI,
+  V8SF_FTYPE_V8SF,
+  V8SF_FTYPE_V8SI,
+  V8SF_FTYPE_V4SF,
   V4SI_FTYPE_V4SI,
   V4SI_FTYPE_V16QI,
+  V4SI_FTYPE_V8SI,
   V4SI_FTYPE_V8HI,
+  V4SI_FTYPE_V4DF,
   V4SI_FTYPE_V4SF,
   V4SI_FTYPE_V2DF,
   V4HI_FTYPE_V4HI,
+  V4DF_FTYPE_V4DF,
+  V4DF_FTYPE_V4SI,
+  V4DF_FTYPE_V4SF,
+  V4DF_FTYPE_V2DF,
+  V4SF_FTYPE_V4DF,
   V4SF_FTYPE_V4SF,
   V4SF_FTYPE_V4SF_VEC_MERGE,
+  V4SF_FTYPE_V8SF,
   V4SF_FTYPE_V4SI,
   V4SF_FTYPE_V2DF,
   V2DI_FTYPE_V2DI,
@@ -18060,6 +21397,7 @@ enum ix86_builtin_type
   V2DF_FTYPE_V2DF,
   V2DF_FTYPE_V2DF_VEC_MERGE,
   V2DF_FTYPE_V4SI,
+  V2DF_FTYPE_V4DF,
   V2DF_FTYPE_V4SF,
   V2DF_FTYPE_V2SI,
   V2SI_FTYPE_V2SI,
@@ -18077,6 +21415,8 @@ enum ix86_builtin_type
   V8HI_FTYPE_V16QI_V16QI,
   V8HI_FTYPE_V4SI_V4SI,
   V8HI_FTYPE_V8HI_SI_COUNT,
+  V8SF_FTYPE_V8SF_V8SF,
+  V8SF_FTYPE_V8SF_V8SI,
   V4SI_FTYPE_V4SI_V4SI,
   V4SI_FTYPE_V4SI_V4SI_COUNT,
   V4SI_FTYPE_V8HI_V8HI,
@@ -18088,8 +21428,11 @@ enum ix86_builtin_type
   V4HI_FTYPE_V8QI_V8QI,
   V4HI_FTYPE_V2SI_V2SI,
   V4HI_FTYPE_V4HI_SI_COUNT,
+  V4DF_FTYPE_V4DF_V4DF,
+  V4DF_FTYPE_V4DF_V4DI,
   V4SF_FTYPE_V4SF_V4SF,
   V4SF_FTYPE_V4SF_V4SF_SWAP,
+  V4SF_FTYPE_V4SF_V4SI,
   V4SF_FTYPE_V4SF_V2SI,
   V4SF_FTYPE_V4SF_V2DF,
   V4SF_FTYPE_V4SF_DI,
@@ -18109,6 +21452,7 @@ enum ix86_builtin_type
   V2DF_FTYPE_V2DF_V2DF,
   V2DF_FTYPE_V2DF_V2DF_SWAP,
   V2DF_FTYPE_V2DF_V4SF,
+  V2DF_FTYPE_V2DF_V2DI,
   V2DF_FTYPE_V2DF_DI,
   V2DF_FTYPE_V2DF_SI,
   V2SF_FTYPE_V2SF_V2SF,
@@ -18121,19 +21465,34 @@ enum ix86_builtin_type
   UINT_FTYPE_UINT_UINT,
   UINT_FTYPE_UINT_USHORT,
   UINT_FTYPE_UINT_UCHAR,
+  UINT16_FTYPE_UINT16_INT,
+  UINT8_FTYPE_UINT8_INT,
   V8HI_FTYPE_V8HI_INT,
   V4SI_FTYPE_V4SI_INT,
   V4HI_FTYPE_V4HI_INT,
+  V8SF_FTYPE_V8SF_INT,
+  V4SI_FTYPE_V8SI_INT,
+  V4SF_FTYPE_V8SF_INT,
+  V2DF_FTYPE_V4DF_INT,
+  V4DF_FTYPE_V4DF_INT,
   V4SF_FTYPE_V4SF_INT,
   V2DI_FTYPE_V2DI_INT,
   V2DI2TI_FTYPE_V2DI_INT,
   V2DF_FTYPE_V2DF_INT,
   V16QI_FTYPE_V16QI_V16QI_V16QI,
+  V8SF_FTYPE_V8SF_V8SF_V8SF,
+  V4DF_FTYPE_V4DF_V4DF_V4DF,
   V4SF_FTYPE_V4SF_V4SF_V4SF,
   V2DF_FTYPE_V2DF_V2DF_V2DF,
   V16QI_FTYPE_V16QI_V16QI_INT,
+  V8SI_FTYPE_V8SI_V8SI_INT,
+  V8SI_FTYPE_V8SI_V4SI_INT,
   V8HI_FTYPE_V8HI_V8HI_INT,
+  V8SF_FTYPE_V8SF_V8SF_INT,
+  V8SF_FTYPE_V8SF_V4SF_INT,
   V4SI_FTYPE_V4SI_V4SI_INT,
+  V4DF_FTYPE_V4DF_V4DF_INT,
+  V4DF_FTYPE_V4DF_V2DF_INT,
   V4SF_FTYPE_V4SF_V4SF_INT,
   V2DI_FTYPE_V2DI_V2DI_INT,
   V2DI2TI_FTYPE_V2DI_V2DI_INT,
@@ -18146,6 +21505,9 @@ enum ix86_builtin_type
 /* Special builtins with variable number of arguments.  */
 static const struct builtin_description bdesc_special_args[] =
 {
+  { ~OPTION_MASK_ISA_64BIT, CODE_FOR_rdtsc, "__builtin_ia32_rdtsc", IX86_BUILTIN_RDTSC, UNKNOWN, (int) UINT64_FTYPE_VOID },
+  { ~OPTION_MASK_ISA_64BIT, CODE_FOR_rdtscp, "__builtin_ia32_rdtscp", IX86_BUILTIN_RDTSCP, UNKNOWN, (int) UINT64_FTYPE_PUNSIGNED },
+
   /* MMX */
   { OPTION_MASK_ISA_MMX, CODE_FOR_mmx_emms, "__builtin_ia32_emms", IX86_BUILTIN_EMMS, UNKNOWN, (int) VOID_FTYPE_VOID },
 
@@ -18189,11 +21551,51 @@ static const struct builtin_description bdesc_special_args[] =
   /* SSE4A */
   { OPTION_MASK_ISA_SSE4A, CODE_FOR_sse4a_vmmovntv2df, "__builtin_ia32_movntsd", IX86_BUILTIN_MOVNTSD, UNKNOWN, (int) VOID_FTYPE_PDOUBLE_V2DF },
   { OPTION_MASK_ISA_SSE4A, CODE_FOR_sse4a_vmmovntv4sf, "__builtin_ia32_movntss", IX86_BUILTIN_MOVNTSS, UNKNOWN, (int) VOID_FTYPE_PFLOAT_V4SF },
+
+  /* AVX */
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_vzeroall, "__builtin_ia32_vzeroall", IX86_BUILTIN_VZEROALL, UNKNOWN, (int) VOID_FTYPE_VOID },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_vzeroupper, 0, IX86_BUILTIN_VZEROUPPER, UNKNOWN, (int) VOID_FTYPE_VOID },
+  { OPTION_MASK_ISA_AVX | OPTION_MASK_ISA_64BIT, CODE_FOR_avx_vzeroupper_rex64, 0, IX86_BUILTIN_VZEROUPPER_REX64, UNKNOWN, (int) VOID_FTYPE_VOID },
+
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_vbroadcastss, "__builtin_ia32_vbroadcastss", IX86_BUILTIN_VBROADCASTSS, UNKNOWN, (int) V4SF_FTYPE_PCFLOAT },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_vbroadcastsd256, "__builtin_ia32_vbroadcastsd256", IX86_BUILTIN_VBROADCASTSD256, UNKNOWN, (int) V4DF_FTYPE_PCDOUBLE },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_vbroadcastss256, "__builtin_ia32_vbroadcastss256", IX86_BUILTIN_VBROADCASTSS256, UNKNOWN, (int) V8SF_FTYPE_PCFLOAT },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_vbroadcastf128_pd256, "__builtin_ia32_vbroadcastf128_pd256", IX86_BUILTIN_VBROADCASTPD256, UNKNOWN, (int) V4DF_FTYPE_PCV2DF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_vbroadcastf128_ps256, "__builtin_ia32_vbroadcastf128_ps256", IX86_BUILTIN_VBROADCASTPS256, UNKNOWN, (int) V8SF_FTYPE_PCV4SF },
+
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_movupd256, "__builtin_ia32_loadupd256", IX86_BUILTIN_LOADUPD256, UNKNOWN, (int) V4DF_FTYPE_PCDOUBLE },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_movups256, "__builtin_ia32_loadups256", IX86_BUILTIN_LOADUPS256, UNKNOWN, (int) V8SF_FTYPE_PCFLOAT },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_movupd256, "__builtin_ia32_storeupd256", IX86_BUILTIN_STOREUPD256, UNKNOWN, (int) VOID_FTYPE_PDOUBLE_V4DF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_movups256, "__builtin_ia32_storeups256", IX86_BUILTIN_STOREUPS256, UNKNOWN, (int) VOID_FTYPE_PFLOAT_V8SF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_movdqu256, "__builtin_ia32_loaddqu256", IX86_BUILTIN_LOADDQU256, UNKNOWN, (int) V32QI_FTYPE_PCCHAR },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_movdqu256, "__builtin_ia32_storedqu256", IX86_BUILTIN_STOREDQU256, UNKNOWN, (int) VOID_FTYPE_PCHAR_V32QI },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_lddqu256, "__builtin_ia32_lddqu256", IX86_BUILTIN_LDDQU256, UNKNOWN, (int) V32QI_FTYPE_PCCHAR },
+
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_movntv4di, "__builtin_ia32_movntdq256", IX86_BUILTIN_MOVNTDQ256, UNKNOWN, (int) VOID_FTYPE_PV4DI_V4DI },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_movntv4df, "__builtin_ia32_movntpd256", IX86_BUILTIN_MOVNTPD256, UNKNOWN, (int) VOID_FTYPE_PDOUBLE_V4DF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_movntv8sf, "__builtin_ia32_movntps256", IX86_BUILTIN_MOVNTPS256, UNKNOWN, (int) VOID_FTYPE_PFLOAT_V8SF },
+
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_maskloadpd, "__builtin_ia32_maskloadpd", IX86_BUILTIN_MASKLOADPD, UNKNOWN, (int) V2DF_FTYPE_PCV2DF_V2DF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_maskloadps, "__builtin_ia32_maskloadps", IX86_BUILTIN_MASKLOADPS, UNKNOWN, (int) V4SF_FTYPE_PCV4SF_V4SF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_maskloadpd256, "__builtin_ia32_maskloadpd256", IX86_BUILTIN_MASKLOADPD256, UNKNOWN, (int) V4DF_FTYPE_PCV4DF_V4DF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_maskloadps256, "__builtin_ia32_maskloadps256", IX86_BUILTIN_MASKLOADPS256, UNKNOWN, (int) V8SF_FTYPE_PCV8SF_V8SF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_maskstorepd, "__builtin_ia32_maskstorepd", IX86_BUILTIN_MASKSTOREPD, UNKNOWN, (int) VOID_FTYPE_PV2DF_V2DF_V2DF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_maskstoreps, "__builtin_ia32_maskstoreps", IX86_BUILTIN_MASKSTOREPS, UNKNOWN, (int) VOID_FTYPE_PV4SF_V4SF_V4SF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_maskstorepd256, "__builtin_ia32_maskstorepd256", IX86_BUILTIN_MASKSTOREPD256, UNKNOWN, (int) VOID_FTYPE_PV4DF_V4DF_V4DF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_maskstoreps256, "__builtin_ia32_maskstoreps256", IX86_BUILTIN_MASKSTOREPS256, UNKNOWN, (int) VOID_FTYPE_PV8SF_V8SF_V8SF },
 };
 
 /* Builtins with variable number of arguments.  */
 static const struct builtin_description bdesc_args[] =
 {
+  { ~OPTION_MASK_ISA_64BIT, CODE_FOR_bsr, "__builtin_ia32_bsrsi", IX86_BUILTIN_BSRSI, UNKNOWN, (int) INT_FTYPE_INT },
+  { OPTION_MASK_ISA_64BIT, CODE_FOR_bsr_rex64, "__builtin_ia32_bsrdi", IX86_BUILTIN_BSRDI, UNKNOWN, (int) INT64_FTYPE_INT64 },
+  { ~OPTION_MASK_ISA_64BIT, CODE_FOR_rdpmc, "__builtin_ia32_rdpmc", IX86_BUILTIN_RDPMC, UNKNOWN, (int) UINT64_FTYPE_INT },
+  { ~OPTION_MASK_ISA_64BIT, CODE_FOR_rotlqi3, "__builtin_ia32_rolqi", IX86_BUILTIN_ROLQI, UNKNOWN, (int) UINT8_FTYPE_UINT8_INT },
+  { ~OPTION_MASK_ISA_64BIT, CODE_FOR_rotlhi3, "__builtin_ia32_rolhi", IX86_BUILTIN_ROLHI, UNKNOWN, (int) UINT16_FTYPE_UINT16_INT },
+  { ~OPTION_MASK_ISA_64BIT, CODE_FOR_rotrqi3, "__builtin_ia32_rorqi", IX86_BUILTIN_RORQI, UNKNOWN, (int) UINT8_FTYPE_UINT8_INT },
+  { ~OPTION_MASK_ISA_64BIT, CODE_FOR_rotrhi3, "__builtin_ia32_rorhi", IX86_BUILTIN_RORHI, UNKNOWN, (int) UINT16_FTYPE_UINT16_INT },
+
   /* MMX */
   { OPTION_MASK_ISA_MMX, CODE_FOR_mmx_addv8qi3, "__builtin_ia32_paddb", IX86_BUILTIN_PADDB, UNKNOWN, (int) V8QI_FTYPE_V8QI_V8QI },
   { OPTION_MASK_ISA_MMX, CODE_FOR_mmx_addv4hi3, "__builtin_ia32_paddw", IX86_BUILTIN_PADDW, UNKNOWN, (int) V4HI_FTYPE_V4HI_V4HI },
@@ -18215,7 +21617,7 @@ static const struct builtin_description bdesc_args[] =
   { OPTION_MASK_ISA_MMX, CODE_FOR_mmx_smulv4hi3_highpart, "__builtin_ia32_pmulhw", IX86_BUILTIN_PMULHW, UNKNOWN, (int) V4HI_FTYPE_V4HI_V4HI },
 
   { OPTION_MASK_ISA_MMX, CODE_FOR_mmx_andv2si3, "__builtin_ia32_pand", IX86_BUILTIN_PAND, UNKNOWN, (int) V2SI_FTYPE_V2SI_V2SI },
-  { OPTION_MASK_ISA_MMX, CODE_FOR_mmx_nandv2si3, "__builtin_ia32_pandn", IX86_BUILTIN_PANDN, UNKNOWN, (int) V2SI_FTYPE_V2SI_V2SI },
+  { OPTION_MASK_ISA_MMX, CODE_FOR_mmx_andnotv2si3, "__builtin_ia32_pandn", IX86_BUILTIN_PANDN, UNKNOWN, (int) V2SI_FTYPE_V2SI_V2SI },
   { OPTION_MASK_ISA_MMX, CODE_FOR_mmx_iorv2si3, "__builtin_ia32_por", IX86_BUILTIN_POR, UNKNOWN, (int) V2SI_FTYPE_V2SI_V2SI },
   { OPTION_MASK_ISA_MMX, CODE_FOR_mmx_xorv2si3, "__builtin_ia32_pxor", IX86_BUILTIN_PXOR, UNKNOWN, (int) V2SI_FTYPE_V2SI_V2SI },
 
@@ -18342,10 +21744,12 @@ static const struct builtin_description bdesc_args[] =
   { OPTION_MASK_ISA_SSE, CODE_FOR_sse_vmsmaxv4sf3, "__builtin_ia32_maxss", IX86_BUILTIN_MAXSS, UNKNOWN, (int) V4SF_FTYPE_V4SF_V4SF },
 
   { OPTION_MASK_ISA_SSE, CODE_FOR_andv4sf3, "__builtin_ia32_andps", IX86_BUILTIN_ANDPS, UNKNOWN, (int) V4SF_FTYPE_V4SF_V4SF },
-  { OPTION_MASK_ISA_SSE, CODE_FOR_sse_nandv4sf3,  "__builtin_ia32_andnps", IX86_BUILTIN_ANDNPS, UNKNOWN, (int) V4SF_FTYPE_V4SF_V4SF },
+  { OPTION_MASK_ISA_SSE, CODE_FOR_sse_andnotv4sf3,  "__builtin_ia32_andnps", IX86_BUILTIN_ANDNPS, UNKNOWN, (int) V4SF_FTYPE_V4SF_V4SF },
   { OPTION_MASK_ISA_SSE, CODE_FOR_iorv4sf3, "__builtin_ia32_orps", IX86_BUILTIN_ORPS, UNKNOWN, (int) V4SF_FTYPE_V4SF_V4SF },
   { OPTION_MASK_ISA_SSE, CODE_FOR_xorv4sf3,  "__builtin_ia32_xorps", IX86_BUILTIN_XORPS, UNKNOWN, (int) V4SF_FTYPE_V4SF_V4SF },
 
+  { OPTION_MASK_ISA_SSE, CODE_FOR_copysignv4sf3,  "__builtin_ia32_copysignps", IX86_BUILTIN_CPYSGNPS, UNKNOWN, (int) V4SF_FTYPE_V4SF_V4SF },
+
   { OPTION_MASK_ISA_SSE, CODE_FOR_sse_movss,  "__builtin_ia32_movss", IX86_BUILTIN_MOVSS, UNKNOWN, (int) V4SF_FTYPE_V4SF_V4SF },
   { OPTION_MASK_ISA_SSE, CODE_FOR_sse_movhlps_exp,  "__builtin_ia32_movhlps", IX86_BUILTIN_MOVHLPS, UNKNOWN, (int) V4SF_FTYPE_V4SF_V4SF },
   { OPTION_MASK_ISA_SSE, CODE_FOR_sse_movlhps_exp,  "__builtin_ia32_movlhps", IX86_BUILTIN_MOVLHPS, UNKNOWN, (int) V4SF_FTYPE_V4SF_V4SF },
@@ -18385,6 +21789,7 @@ static const struct builtin_description bdesc_args[] =
   { OPTION_MASK_ISA_SSE2, CODE_FOR_sqrtv2df2, "__builtin_ia32_sqrtpd", IX86_BUILTIN_SQRTPD, UNKNOWN, (int) V2DF_FTYPE_V2DF },
   { OPTION_MASK_ISA_SSE2, CODE_FOR_sse2_cvtdq2pd, "__builtin_ia32_cvtdq2pd", IX86_BUILTIN_CVTDQ2PD, UNKNOWN, (int) V2DF_FTYPE_V4SI },
   { OPTION_MASK_ISA_SSE2, CODE_FOR_sse2_cvtdq2ps, "__builtin_ia32_cvtdq2ps", IX86_BUILTIN_CVTDQ2PS, UNKNOWN, (int) V4SF_FTYPE_V4SI },
+  { OPTION_MASK_ISA_SSE2, CODE_FOR_sse2_cvtudq2ps, "__builtin_ia32_cvtudq2ps", IX86_BUILTIN_CVTUDQ2PS, UNKNOWN, (int) V4SF_FTYPE_V4SI },
 
   { OPTION_MASK_ISA_SSE2, CODE_FOR_sse2_cvtpd2dq, "__builtin_ia32_cvtpd2dq", IX86_BUILTIN_CVTPD2DQ, UNKNOWN, (int) V4SI_FTYPE_V2DF },
   { OPTION_MASK_ISA_SSE2, CODE_FOR_sse2_cvtpd2pi, "__builtin_ia32_cvtpd2pi", IX86_BUILTIN_CVTPD2PI, UNKNOWN, (int) V2SI_FTYPE_V2DF },
@@ -18439,10 +21844,12 @@ static const struct builtin_description bdesc_args[] =
   { OPTION_MASK_ISA_SSE2, CODE_FOR_sse2_vmsmaxv2df3, "__builtin_ia32_maxsd", IX86_BUILTIN_MAXSD, UNKNOWN, (int) V2DF_FTYPE_V2DF_V2DF },
 
   { OPTION_MASK_ISA_SSE2, CODE_FOR_andv2df3, "__builtin_ia32_andpd", IX86_BUILTIN_ANDPD, UNKNOWN, (int) V2DF_FTYPE_V2DF_V2DF },
-  { OPTION_MASK_ISA_SSE2, CODE_FOR_sse2_nandv2df3,  "__builtin_ia32_andnpd", IX86_BUILTIN_ANDNPD, UNKNOWN, (int) V2DF_FTYPE_V2DF_V2DF },
+  { OPTION_MASK_ISA_SSE2, CODE_FOR_sse2_andnotv2df3,  "__builtin_ia32_andnpd", IX86_BUILTIN_ANDNPD, UNKNOWN, (int) V2DF_FTYPE_V2DF_V2DF },
   { OPTION_MASK_ISA_SSE2, CODE_FOR_iorv2df3, "__builtin_ia32_orpd", IX86_BUILTIN_ORPD, UNKNOWN, (int) V2DF_FTYPE_V2DF_V2DF },
   { OPTION_MASK_ISA_SSE2, CODE_FOR_xorv2df3,  "__builtin_ia32_xorpd", IX86_BUILTIN_XORPD, UNKNOWN, (int) V2DF_FTYPE_V2DF_V2DF },
 
+  { OPTION_MASK_ISA_SSE2, CODE_FOR_copysignv2df3,  "__builtin_ia32_copysignpd", IX86_BUILTIN_CPYSGNPD, UNKNOWN, (int) V2DF_FTYPE_V2DF_V2DF },
+
   { OPTION_MASK_ISA_SSE2, CODE_FOR_sse2_movsd,  "__builtin_ia32_movsd", IX86_BUILTIN_MOVSD, UNKNOWN, (int) V2DF_FTYPE_V2DF_V2DF },
   { OPTION_MASK_ISA_SSE2, CODE_FOR_sse2_unpckhpd_exp, "__builtin_ia32_unpckhpd", IX86_BUILTIN_UNPCKHPD, UNKNOWN, (int) V2DF_FTYPE_V2DF_V2DF },
   { OPTION_MASK_ISA_SSE2, CODE_FOR_sse2_unpcklpd_exp, "__builtin_ia32_unpcklpd", IX86_BUILTIN_UNPCKLPD, UNKNOWN, (int) V2DF_FTYPE_V2DF_V2DF },
@@ -18471,7 +21878,7 @@ static const struct builtin_description bdesc_args[] =
   { OPTION_MASK_ISA_SSE2, CODE_FOR_smulv8hi3_highpart, "__builtin_ia32_pmulhw128", IX86_BUILTIN_PMULHW128, UNKNOWN,(int) V8HI_FTYPE_V8HI_V8HI },
 
   { OPTION_MASK_ISA_SSE2, CODE_FOR_andv2di3, "__builtin_ia32_pand128", IX86_BUILTIN_PAND128, UNKNOWN, (int) V2DI_FTYPE_V2DI_V2DI },
-  { OPTION_MASK_ISA_SSE2, CODE_FOR_sse2_nandv2di3, "__builtin_ia32_pandn128", IX86_BUILTIN_PANDN128, UNKNOWN, (int) V2DI_FTYPE_V2DI_V2DI },
+  { OPTION_MASK_ISA_SSE2, CODE_FOR_sse2_andnotv2di3, "__builtin_ia32_pandn128", IX86_BUILTIN_PANDN128, UNKNOWN, (int) V2DI_FTYPE_V2DI_V2DI },
   { OPTION_MASK_ISA_SSE2, CODE_FOR_iorv2di3, "__builtin_ia32_por128", IX86_BUILTIN_POR128, UNKNOWN, (int) V2DI_FTYPE_V2DI_V2DI },
   { OPTION_MASK_ISA_SSE2, CODE_FOR_xorv2di3, "__builtin_ia32_pxor128", IX86_BUILTIN_PXOR128, UNKNOWN, (int) V2DI_FTYPE_V2DI_V2DI },
 
@@ -18543,6 +21950,11 @@ static const struct builtin_description bdesc_args[] =
 
   { OPTION_MASK_ISA_SSE2, CODE_FOR_sse2_vmsqrtv2df2, "__builtin_ia32_sqrtsd", IX86_BUILTIN_SQRTSD, UNKNOWN, (int) V2DF_FTYPE_V2DF_VEC_MERGE },
 
+  { OPTION_MASK_ISA_SSE2, CODE_FOR_abstf2, 0, IX86_BUILTIN_FABSQ, UNKNOWN, (int) FLOAT128_FTYPE_FLOAT128 },
+  { OPTION_MASK_ISA_SSE2, CODE_FOR_copysigntf3, 0, IX86_BUILTIN_COPYSIGNQ, UNKNOWN, (int) FLOAT128_FTYPE_FLOAT128_FLOAT128 },
+
+  { OPTION_MASK_ISA_SSE, CODE_FOR_sse2_movq128, "__builtin_ia32_movq128", IX86_BUILTIN_MOVQ128, UNKNOWN, (int) V2DI_FTYPE_V2DI },
+
   /* SSE2 MMX */
   { OPTION_MASK_ISA_SSE2, CODE_FOR_mmx_addv1di3, "__builtin_ia32_paddq", IX86_BUILTIN_PADDQ, UNKNOWN, (int) V1DI_FTYPE_V1DI_V1DI },
   { OPTION_MASK_ISA_SSE2, CODE_FOR_mmx_subv1di3, "__builtin_ia32_psubq", IX86_BUILTIN_PSUBQ, UNKNOWN, (int) V1DI_FTYPE_V1DI_V1DI },
@@ -18646,10 +22058,10 @@ static const struct builtin_description bdesc_args[] =
 
   /* SSE4.2 */
   { OPTION_MASK_ISA_SSE4_2, CODE_FOR_sse4_2_gtv2di3, "__builtin_ia32_pcmpgtq", IX86_BUILTIN_PCMPGTQ, UNKNOWN, (int) V2DI_FTYPE_V2DI_V2DI },
-  { OPTION_MASK_ISA_SSE4_2, CODE_FOR_sse4_2_crc32qi, "__builtin_ia32_crc32qi", IX86_BUILTIN_CRC32QI, UNKNOWN, (int) UINT_FTYPE_UINT_UCHAR },
-  { OPTION_MASK_ISA_SSE4_2, CODE_FOR_sse4_2_crc32hi, "__builtin_ia32_crc32hi", IX86_BUILTIN_CRC32HI, UNKNOWN, (int) UINT_FTYPE_UINT_USHORT },
-  { OPTION_MASK_ISA_SSE4_2, CODE_FOR_sse4_2_crc32si, "__builtin_ia32_crc32si", IX86_BUILTIN_CRC32SI, UNKNOWN, (int) UINT_FTYPE_UINT_UINT },
-  { OPTION_MASK_ISA_SSE4_2 | OPTION_MASK_ISA_64BIT, CODE_FOR_sse4_2_crc32di, "__builtin_ia32_crc32di", IX86_BUILTIN_CRC32DI, UNKNOWN, (int) UINT64_FTYPE_UINT64_UINT64 },
+  { OPTION_MASK_ISA_SSE4_2 | OPTION_MASK_ISA_CRC32, CODE_FOR_sse4_2_crc32qi, "__builtin_ia32_crc32qi", IX86_BUILTIN_CRC32QI, UNKNOWN, (int) UINT_FTYPE_UINT_UCHAR },
+  { OPTION_MASK_ISA_SSE4_2 | OPTION_MASK_ISA_CRC32, CODE_FOR_sse4_2_crc32hi, "__builtin_ia32_crc32hi", IX86_BUILTIN_CRC32HI, UNKNOWN, (int) UINT_FTYPE_UINT_USHORT },
+  { OPTION_MASK_ISA_SSE4_2 | OPTION_MASK_ISA_CRC32, CODE_FOR_sse4_2_crc32si, "__builtin_ia32_crc32si", IX86_BUILTIN_CRC32SI, UNKNOWN, (int) UINT_FTYPE_UINT_UINT },
+  { OPTION_MASK_ISA_SSE4_2 | OPTION_MASK_ISA_CRC32 | OPTION_MASK_ISA_64BIT, CODE_FOR_sse4_2_crc32di, "__builtin_ia32_crc32di", IX86_BUILTIN_CRC32DI, UNKNOWN, (int) UINT64_FTYPE_UINT64_UINT64 },
 
   /* SSE4A */
   { OPTION_MASK_ISA_SSE4A, CODE_FOR_sse4a_extrqi, "__builtin_ia32_extrqi", IX86_BUILTIN_EXTRQI, UNKNOWN, (int) V2DI_FTYPE_V2DI_UINT_UINT },
@@ -18669,9 +22081,119 @@ static const struct builtin_description bdesc_args[] =
   /* PCLMUL */
   { OPTION_MASK_ISA_SSE2, CODE_FOR_pclmulqdq, 0, IX86_BUILTIN_PCLMULQDQ128, UNKNOWN, (int) V2DI_FTYPE_V2DI_V2DI_INT },
 
-   /* 64bit */
-  { OPTION_MASK_ISA_64BIT, CODE_FOR_abstf2, 0, IX86_BUILTIN_FABSQ, UNKNOWN, (int) FLOAT128_FTYPE_FLOAT128 },
-  { OPTION_MASK_ISA_64BIT, CODE_FOR_copysigntf3, 0, IX86_BUILTIN_COPYSIGNQ, UNKNOWN, (int) FLOAT128_FTYPE_FLOAT128_FLOAT128 },
+  /* AVX */
+  { OPTION_MASK_ISA_AVX, CODE_FOR_addv4df3, "__builtin_ia32_addpd256", IX86_BUILTIN_ADDPD256, UNKNOWN, (int) V4DF_FTYPE_V4DF_V4DF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_addv8sf3, "__builtin_ia32_addps256", IX86_BUILTIN_ADDPS256, UNKNOWN, (int) V8SF_FTYPE_V8SF_V8SF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_addsubv4df3, "__builtin_ia32_addsubpd256", IX86_BUILTIN_ADDSUBPD256, UNKNOWN, (int) V4DF_FTYPE_V4DF_V4DF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_addsubv8sf3, "__builtin_ia32_addsubps256", IX86_BUILTIN_ADDSUBPS256, UNKNOWN, (int) V8SF_FTYPE_V8SF_V8SF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_andv4df3, "__builtin_ia32_andpd256", IX86_BUILTIN_ANDPD256, UNKNOWN, (int) V4DF_FTYPE_V4DF_V4DF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_andv8sf3, "__builtin_ia32_andps256", IX86_BUILTIN_ANDPS256, UNKNOWN, (int) V8SF_FTYPE_V8SF_V8SF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_andnotv4df3, "__builtin_ia32_andnpd256", IX86_BUILTIN_ANDNPD256, UNKNOWN, (int) V4DF_FTYPE_V4DF_V4DF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_andnotv8sf3, "__builtin_ia32_andnps256", IX86_BUILTIN_ANDNPS256, UNKNOWN, (int) V8SF_FTYPE_V8SF_V8SF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_divv4df3, "__builtin_ia32_divpd256", IX86_BUILTIN_DIVPD256, UNKNOWN, (int) V4DF_FTYPE_V4DF_V4DF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_divv8sf3, "__builtin_ia32_divps256", IX86_BUILTIN_DIVPS256, UNKNOWN, (int) V8SF_FTYPE_V8SF_V8SF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_haddv4df3, "__builtin_ia32_haddpd256", IX86_BUILTIN_HADDPD256, UNKNOWN, (int) V4DF_FTYPE_V4DF_V4DF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_hsubv8sf3, "__builtin_ia32_hsubps256", IX86_BUILTIN_HSUBPS256, UNKNOWN, (int) V8SF_FTYPE_V8SF_V8SF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_hsubv4df3, "__builtin_ia32_hsubpd256", IX86_BUILTIN_HSUBPD256, UNKNOWN, (int) V4DF_FTYPE_V4DF_V4DF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_haddv8sf3, "__builtin_ia32_haddps256", IX86_BUILTIN_HADDPS256, UNKNOWN, (int) V8SF_FTYPE_V8SF_V8SF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_smaxv4df3, "__builtin_ia32_maxpd256", IX86_BUILTIN_MAXPD256, UNKNOWN, (int) V4DF_FTYPE_V4DF_V4DF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_smaxv8sf3, "__builtin_ia32_maxps256", IX86_BUILTIN_MAXPS256, UNKNOWN, (int) V8SF_FTYPE_V8SF_V8SF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_sminv4df3, "__builtin_ia32_minpd256", IX86_BUILTIN_MINPD256, UNKNOWN, (int) V4DF_FTYPE_V4DF_V4DF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_sminv8sf3, "__builtin_ia32_minps256", IX86_BUILTIN_MINPS256, UNKNOWN, (int) V8SF_FTYPE_V8SF_V8SF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_mulv4df3, "__builtin_ia32_mulpd256", IX86_BUILTIN_MULPD256, UNKNOWN, (int) V4DF_FTYPE_V4DF_V4DF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_mulv8sf3, "__builtin_ia32_mulps256", IX86_BUILTIN_MULPS256, UNKNOWN, (int) V8SF_FTYPE_V8SF_V8SF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_iorv4df3, "__builtin_ia32_orpd256", IX86_BUILTIN_ORPD256, UNKNOWN, (int) V4DF_FTYPE_V4DF_V4DF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_iorv8sf3, "__builtin_ia32_orps256", IX86_BUILTIN_ORPS256, UNKNOWN, (int) V8SF_FTYPE_V8SF_V8SF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_subv4df3, "__builtin_ia32_subpd256", IX86_BUILTIN_SUBPD256, UNKNOWN, (int) V4DF_FTYPE_V4DF_V4DF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_subv8sf3, "__builtin_ia32_subps256", IX86_BUILTIN_SUBPS256, UNKNOWN, (int) V8SF_FTYPE_V8SF_V8SF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_xorv4df3, "__builtin_ia32_xorpd256", IX86_BUILTIN_XORPD256, UNKNOWN, (int) V4DF_FTYPE_V4DF_V4DF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_xorv8sf3, "__builtin_ia32_xorps256", IX86_BUILTIN_XORPS256, UNKNOWN, (int) V8SF_FTYPE_V8SF_V8SF },
+
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_vpermilvarv2df3, "__builtin_ia32_vpermilvarpd", IX86_BUILTIN_VPERMILVARPD, UNKNOWN, (int) V2DF_FTYPE_V2DF_V2DI },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_vpermilvarv4sf3, "__builtin_ia32_vpermilvarps", IX86_BUILTIN_VPERMILVARPS, UNKNOWN, (int) V4SF_FTYPE_V4SF_V4SI },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_vpermilvarv4df3, "__builtin_ia32_vpermilvarpd256", IX86_BUILTIN_VPERMILVARPD256, UNKNOWN, (int) V4DF_FTYPE_V4DF_V4DI },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_vpermilvarv8sf3, "__builtin_ia32_vpermilvarps256", IX86_BUILTIN_VPERMILVARPS256, UNKNOWN, (int) V8SF_FTYPE_V8SF_V8SI },
+
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_blendpd256, "__builtin_ia32_blendpd256", IX86_BUILTIN_BLENDPD256, UNKNOWN, (int) V4DF_FTYPE_V4DF_V4DF_INT },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_blendps256, "__builtin_ia32_blendps256", IX86_BUILTIN_BLENDPS256, UNKNOWN, (int) V8SF_FTYPE_V8SF_V8SF_INT },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_blendvpd256, "__builtin_ia32_blendvpd256", IX86_BUILTIN_BLENDVPD256, UNKNOWN, (int) V4DF_FTYPE_V4DF_V4DF_V4DF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_blendvps256, "__builtin_ia32_blendvps256", IX86_BUILTIN_BLENDVPS256, UNKNOWN, (int) V8SF_FTYPE_V8SF_V8SF_V8SF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_dpps256, "__builtin_ia32_dpps256", IX86_BUILTIN_DPPS256, UNKNOWN, (int) V8SF_FTYPE_V8SF_V8SF_INT },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_shufpd256, "__builtin_ia32_shufpd256", IX86_BUILTIN_SHUFPD256, UNKNOWN, (int) V4DF_FTYPE_V4DF_V4DF_INT },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_shufps256, "__builtin_ia32_shufps256", IX86_BUILTIN_SHUFPS256, UNKNOWN, (int) V8SF_FTYPE_V8SF_V8SF_INT },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_cmpsdv2df3, "__builtin_ia32_cmpsd", IX86_BUILTIN_CMPSD, UNKNOWN, (int) V2DF_FTYPE_V2DF_V2DF_INT },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_cmpssv4sf3, "__builtin_ia32_cmpss", IX86_BUILTIN_CMPSS, UNKNOWN, (int) V4SF_FTYPE_V4SF_V4SF_INT },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_cmppdv2df3, "__builtin_ia32_cmppd", IX86_BUILTIN_CMPPD, UNKNOWN, (int) V2DF_FTYPE_V2DF_V2DF_INT },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_cmppsv4sf3, "__builtin_ia32_cmpps", IX86_BUILTIN_CMPPS, UNKNOWN, (int) V4SF_FTYPE_V4SF_V4SF_INT },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_cmppdv4df3, "__builtin_ia32_cmppd256", IX86_BUILTIN_CMPPD256, UNKNOWN, (int) V4DF_FTYPE_V4DF_V4DF_INT },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_cmppsv8sf3, "__builtin_ia32_cmpps256", IX86_BUILTIN_CMPPS256, UNKNOWN, (int) V8SF_FTYPE_V8SF_V8SF_INT },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_vextractf128v4df, "__builtin_ia32_vextractf128_pd256", IX86_BUILTIN_EXTRACTF128PD256, UNKNOWN, (int) V2DF_FTYPE_V4DF_INT },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_vextractf128v8sf, "__builtin_ia32_vextractf128_ps256", IX86_BUILTIN_EXTRACTF128PS256, UNKNOWN, (int) V4SF_FTYPE_V8SF_INT },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_vextractf128v8si, "__builtin_ia32_vextractf128_si256", IX86_BUILTIN_EXTRACTF128SI256, UNKNOWN, (int) V4SI_FTYPE_V8SI_INT },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_cvtdq2pd256, "__builtin_ia32_cvtdq2pd256", IX86_BUILTIN_CVTDQ2PD256, UNKNOWN, (int) V4DF_FTYPE_V4SI },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_cvtdq2ps256, "__builtin_ia32_cvtdq2ps256", IX86_BUILTIN_CVTDQ2PS256, UNKNOWN, (int) V8SF_FTYPE_V8SI },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_cvtpd2ps256, "__builtin_ia32_cvtpd2ps256", IX86_BUILTIN_CVTPD2PS256, UNKNOWN, (int) V4SF_FTYPE_V4DF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_cvtps2dq256, "__builtin_ia32_cvtps2dq256", IX86_BUILTIN_CVTPS2DQ256, UNKNOWN, (int) V8SI_FTYPE_V8SF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_cvtps2pd256, "__builtin_ia32_cvtps2pd256", IX86_BUILTIN_CVTPS2PD256, UNKNOWN, (int) V4DF_FTYPE_V4SF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_cvttpd2dq256, "__builtin_ia32_cvttpd2dq256", IX86_BUILTIN_CVTTPD2DQ256, UNKNOWN, (int) V4SI_FTYPE_V4DF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_cvtpd2dq256, "__builtin_ia32_cvtpd2dq256", IX86_BUILTIN_CVTPD2DQ256, UNKNOWN, (int) V4SI_FTYPE_V4DF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_cvttps2dq256, "__builtin_ia32_cvttps2dq256", IX86_BUILTIN_CVTTPS2DQ256, UNKNOWN, (int) V8SI_FTYPE_V8SF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_vperm2f128v4df3, "__builtin_ia32_vperm2f128_pd256", IX86_BUILTIN_VPERM2F128PD256, UNKNOWN, (int) V4DF_FTYPE_V4DF_V4DF_INT },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_vperm2f128v8sf3, "__builtin_ia32_vperm2f128_ps256", IX86_BUILTIN_VPERM2F128PS256, UNKNOWN, (int) V8SF_FTYPE_V8SF_V8SF_INT },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_vperm2f128v8si3, "__builtin_ia32_vperm2f128_si256", IX86_BUILTIN_VPERM2F128SI256, UNKNOWN, (int) V8SI_FTYPE_V8SI_V8SI_INT },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_vpermilv2df, "__builtin_ia32_vpermilpd", IX86_BUILTIN_VPERMILPD, UNKNOWN, (int) V2DF_FTYPE_V2DF_INT },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_vpermilv4sf, "__builtin_ia32_vpermilps", IX86_BUILTIN_VPERMILPS, UNKNOWN, (int) V4SF_FTYPE_V4SF_INT },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_vpermilv4df, "__builtin_ia32_vpermilpd256", IX86_BUILTIN_VPERMILPD256, UNKNOWN, (int) V4DF_FTYPE_V4DF_INT },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_vpermilv8sf, "__builtin_ia32_vpermilps256", IX86_BUILTIN_VPERMILPS256, UNKNOWN, (int) V8SF_FTYPE_V8SF_INT },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_vinsertf128v4df, "__builtin_ia32_vinsertf128_pd256", IX86_BUILTIN_VINSERTF128PD256, UNKNOWN, (int) V4DF_FTYPE_V4DF_V2DF_INT },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_vinsertf128v8sf, "__builtin_ia32_vinsertf128_ps256", IX86_BUILTIN_VINSERTF128PS256, UNKNOWN, (int) V8SF_FTYPE_V8SF_V4SF_INT },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_vinsertf128v8si, "__builtin_ia32_vinsertf128_si256", IX86_BUILTIN_VINSERTF128SI256, UNKNOWN, (int) V8SI_FTYPE_V8SI_V4SI_INT },
+
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_movshdup256, "__builtin_ia32_movshdup256", IX86_BUILTIN_MOVSHDUP256, UNKNOWN, (int) V8SF_FTYPE_V8SF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_movsldup256, "__builtin_ia32_movsldup256", IX86_BUILTIN_MOVSLDUP256, UNKNOWN, (int) V8SF_FTYPE_V8SF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_movddup256, "__builtin_ia32_movddup256", IX86_BUILTIN_MOVDDUP256, UNKNOWN, (int) V4DF_FTYPE_V4DF },
+
+  { OPTION_MASK_ISA_AVX, CODE_FOR_sqrtv4df2, "__builtin_ia32_sqrtpd256", IX86_BUILTIN_SQRTPD256, UNKNOWN, (int) V4DF_FTYPE_V4DF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_sqrtv8sf2, "__builtin_ia32_sqrtps256", IX86_BUILTIN_SQRTPS256, UNKNOWN, (int) V8SF_FTYPE_V8SF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_sqrtv8sf2, "__builtin_ia32_sqrtps_nr256", IX86_BUILTIN_SQRTPS_NR256, UNKNOWN, (int) V8SF_FTYPE_V8SF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_rsqrtv8sf2, "__builtin_ia32_rsqrtps256", IX86_BUILTIN_RSQRTPS256, UNKNOWN, (int) V8SF_FTYPE_V8SF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_rsqrtv8sf2, "__builtin_ia32_rsqrtps_nr256", IX86_BUILTIN_RSQRTPS_NR256, UNKNOWN, (int) V8SF_FTYPE_V8SF },
+
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_rcpv8sf2, "__builtin_ia32_rcpps256", IX86_BUILTIN_RCPPS256, UNKNOWN, (int) V8SF_FTYPE_V8SF },
+
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_roundpd256, "__builtin_ia32_roundpd256", IX86_BUILTIN_ROUNDPD256, UNKNOWN, (int) V4DF_FTYPE_V4DF_INT },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_roundps256, "__builtin_ia32_roundps256", IX86_BUILTIN_ROUNDPS256, UNKNOWN, (int) V8SF_FTYPE_V8SF_INT },
+
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_unpckhpd256,  "__builtin_ia32_unpckhpd256", IX86_BUILTIN_UNPCKHPD256, UNKNOWN, (int) V4DF_FTYPE_V4DF_V4DF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_unpcklpd256,  "__builtin_ia32_unpcklpd256", IX86_BUILTIN_UNPCKLPD256, UNKNOWN, (int) V4DF_FTYPE_V4DF_V4DF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_unpckhps256,  "__builtin_ia32_unpckhps256", IX86_BUILTIN_UNPCKHPS256, UNKNOWN, (int) V8SF_FTYPE_V8SF_V8SF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_unpcklps256,  "__builtin_ia32_unpcklps256", IX86_BUILTIN_UNPCKLPS256, UNKNOWN, (int) V8SF_FTYPE_V8SF_V8SF },
+
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_si256_si, "__builtin_ia32_si256_si", IX86_BUILTIN_SI256_SI, UNKNOWN, (int) V8SI_FTYPE_V4SI },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_ps256_ps, "__builtin_ia32_ps256_ps", IX86_BUILTIN_PS256_PS, UNKNOWN, (int) V8SF_FTYPE_V4SF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_pd256_pd, "__builtin_ia32_pd256_pd", IX86_BUILTIN_PD256_PD, UNKNOWN, (int) V4DF_FTYPE_V2DF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_si_si256, "__builtin_ia32_si_si256", IX86_BUILTIN_SI_SI256, UNKNOWN, (int) V4SI_FTYPE_V8SI },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_ps_ps256, "__builtin_ia32_ps_ps256", IX86_BUILTIN_PS_PS256, UNKNOWN, (int) V4SF_FTYPE_V8SF },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_pd_pd256, "__builtin_ia32_pd_pd256", IX86_BUILTIN_PD_PD256, UNKNOWN, (int) V2DF_FTYPE_V4DF },
+
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_vtestpd, "__builtin_ia32_vtestzpd", IX86_BUILTIN_VTESTZPD, EQ, (int) INT_FTYPE_V2DF_V2DF_PTEST },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_vtestpd, "__builtin_ia32_vtestcpd", IX86_BUILTIN_VTESTCPD, LTU, (int) INT_FTYPE_V2DF_V2DF_PTEST },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_vtestpd, "__builtin_ia32_vtestnzcpd", IX86_BUILTIN_VTESTNZCPD, GTU, (int) INT_FTYPE_V2DF_V2DF_PTEST },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_vtestps, "__builtin_ia32_vtestzps", IX86_BUILTIN_VTESTZPS, EQ, (int) INT_FTYPE_V4SF_V4SF_PTEST },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_vtestps, "__builtin_ia32_vtestcps", IX86_BUILTIN_VTESTCPS, LTU, (int) INT_FTYPE_V4SF_V4SF_PTEST },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_vtestps, "__builtin_ia32_vtestnzcps", IX86_BUILTIN_VTESTNZCPS, GTU, (int) INT_FTYPE_V4SF_V4SF_PTEST },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_vtestpd256, "__builtin_ia32_vtestzpd256", IX86_BUILTIN_VTESTZPD256, EQ, (int) INT_FTYPE_V4DF_V4DF_PTEST },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_vtestpd256, "__builtin_ia32_vtestcpd256", IX86_BUILTIN_VTESTCPD256, LTU, (int) INT_FTYPE_V4DF_V4DF_PTEST },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_vtestpd256, "__builtin_ia32_vtestnzcpd256", IX86_BUILTIN_VTESTNZCPD256, GTU, (int) INT_FTYPE_V4DF_V4DF_PTEST },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_vtestps256, "__builtin_ia32_vtestzps256", IX86_BUILTIN_VTESTZPS256, EQ, (int) INT_FTYPE_V8SF_V8SF_PTEST },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_vtestps256, "__builtin_ia32_vtestcps256", IX86_BUILTIN_VTESTCPS256, LTU, (int) INT_FTYPE_V8SF_V8SF_PTEST },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_vtestps256, "__builtin_ia32_vtestnzcps256", IX86_BUILTIN_VTESTNZCPS256, GTU, (int) INT_FTYPE_V8SF_V8SF_PTEST },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_ptest256, "__builtin_ia32_ptestz256", IX86_BUILTIN_PTESTZ256, EQ, (int) INT_FTYPE_V4DI_V4DI_PTEST },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_ptest256, "__builtin_ia32_ptestc256", IX86_BUILTIN_PTESTC256, LTU, (int) INT_FTYPE_V4DI_V4DI_PTEST },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_ptest256, "__builtin_ia32_ptestnzc256", IX86_BUILTIN_PTESTNZC256, GTU, (int) INT_FTYPE_V4DI_V4DI_PTEST },
+
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_movmskpd256, "__builtin_ia32_movmskpd256", IX86_BUILTIN_MOVMSKPD256, UNKNOWN, (int) INT_FTYPE_V4DF  },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_avx_movmskps256, "__builtin_ia32_movmskps256", IX86_BUILTIN_MOVMSKPS256, UNKNOWN, (int) INT_FTYPE_V8SF },
 };
 
 /* SSE5 */
@@ -18727,81 +22249,81 @@ enum multi_arg_type {
 
 static const struct builtin_description bdesc_multi_arg[] =
 {
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5i_vmfmaddv4sf4,     "__builtin_ia32_fmaddss",    IX86_BUILTIN_FMADDSS,    0,            (int)MULTI_ARG_3_SF },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5i_vmfmaddv2df4,     "__builtin_ia32_fmaddsd",    IX86_BUILTIN_FMADDSD,    0,            (int)MULTI_ARG_3_DF },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5i_fmaddv4sf4,       "__builtin_ia32_fmaddps",    IX86_BUILTIN_FMADDPS,    0,            (int)MULTI_ARG_3_SF },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5i_fmaddv2df4,       "__builtin_ia32_fmaddpd",    IX86_BUILTIN_FMADDPD,    0,            (int)MULTI_ARG_3_DF },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5i_vmfmsubv4sf4,     "__builtin_ia32_fmsubss",    IX86_BUILTIN_FMSUBSS,    0,            (int)MULTI_ARG_3_SF },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5i_vmfmsubv2df4,     "__builtin_ia32_fmsubsd",    IX86_BUILTIN_FMSUBSD,    0,            (int)MULTI_ARG_3_DF },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5i_fmsubv4sf4,       "__builtin_ia32_fmsubps",    IX86_BUILTIN_FMSUBPS,    0,            (int)MULTI_ARG_3_SF },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5i_fmsubv2df4,       "__builtin_ia32_fmsubpd",    IX86_BUILTIN_FMSUBPD,    0,            (int)MULTI_ARG_3_DF },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5i_vmfnmaddv4sf4,    "__builtin_ia32_fnmaddss",   IX86_BUILTIN_FNMADDSS,   0,            (int)MULTI_ARG_3_SF },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5i_vmfnmaddv2df4,    "__builtin_ia32_fnmaddsd",   IX86_BUILTIN_FNMADDSD,   0,            (int)MULTI_ARG_3_DF },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5i_fnmaddv4sf4,      "__builtin_ia32_fnmaddps",   IX86_BUILTIN_FNMADDPS,   0,            (int)MULTI_ARG_3_SF },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5i_fnmaddv2df4,      "__builtin_ia32_fnmaddpd",   IX86_BUILTIN_FNMADDPD,   0,            (int)MULTI_ARG_3_DF },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5i_vmfnmsubv4sf4,    "__builtin_ia32_fnmsubss",   IX86_BUILTIN_FNMSUBSS,   0,            (int)MULTI_ARG_3_SF },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5i_vmfnmsubv2df4,    "__builtin_ia32_fnmsubsd",   IX86_BUILTIN_FNMSUBSD,   0,            (int)MULTI_ARG_3_DF },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5i_fnmsubv4sf4,      "__builtin_ia32_fnmsubps",   IX86_BUILTIN_FNMSUBPS,   0,            (int)MULTI_ARG_3_SF },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5i_fnmsubv2df4,      "__builtin_ia32_fnmsubpd",   IX86_BUILTIN_FNMSUBPD,   0,            (int)MULTI_ARG_3_DF },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcmov_v2di,        "__builtin_ia32_pcmov",      IX86_BUILTIN_PCMOV_V2DI, 0,            (int)MULTI_ARG_3_DI },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcmov_v2di,        "__builtin_ia32_pcmov_v2di", IX86_BUILTIN_PCMOV_V2DI, 0,            (int)MULTI_ARG_3_DI },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcmov_v4si,        "__builtin_ia32_pcmov_v4si", IX86_BUILTIN_PCMOV_V4SI, 0,            (int)MULTI_ARG_3_SI },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcmov_v8hi,        "__builtin_ia32_pcmov_v8hi", IX86_BUILTIN_PCMOV_V8HI, 0,            (int)MULTI_ARG_3_HI },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcmov_v16qi,       "__builtin_ia32_pcmov_v16qi",IX86_BUILTIN_PCMOV_V16QI,0,            (int)MULTI_ARG_3_QI },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcmov_v2df,        "__builtin_ia32_pcmov_v2df", IX86_BUILTIN_PCMOV_V2DF, 0,            (int)MULTI_ARG_3_DF },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcmov_v4sf,        "__builtin_ia32_pcmov_v4sf", IX86_BUILTIN_PCMOV_V4SF, 0,            (int)MULTI_ARG_3_SF },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pperm,             "__builtin_ia32_pperm",      IX86_BUILTIN_PPERM,      0,            (int)MULTI_ARG_3_QI },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_permv4sf,          "__builtin_ia32_permps",     IX86_BUILTIN_PERMPS,     0,            (int)MULTI_ARG_3_PERMPS },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_permv2df,          "__builtin_ia32_permpd",     IX86_BUILTIN_PERMPD,     0,            (int)MULTI_ARG_3_PERMPD },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pmacssww,          "__builtin_ia32_pmacssww",   IX86_BUILTIN_PMACSSWW,   0,            (int)MULTI_ARG_3_HI },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pmacsww,           "__builtin_ia32_pmacsww",    IX86_BUILTIN_PMACSWW,    0,            (int)MULTI_ARG_3_HI },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pmacsswd,          "__builtin_ia32_pmacsswd",   IX86_BUILTIN_PMACSSWD,   0,            (int)MULTI_ARG_3_HI_SI },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pmacswd,           "__builtin_ia32_pmacswd",    IX86_BUILTIN_PMACSWD,    0,            (int)MULTI_ARG_3_HI_SI },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pmacssdd,          "__builtin_ia32_pmacssdd",   IX86_BUILTIN_PMACSSDD,   0,            (int)MULTI_ARG_3_SI },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pmacsdd,           "__builtin_ia32_pmacsdd",    IX86_BUILTIN_PMACSDD,    0,            (int)MULTI_ARG_3_SI },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pmacssdql,         "__builtin_ia32_pmacssdql",  IX86_BUILTIN_PMACSSDQL,  0,            (int)MULTI_ARG_3_SI_DI },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pmacssdqh,         "__builtin_ia32_pmacssdqh",  IX86_BUILTIN_PMACSSDQH,  0,            (int)MULTI_ARG_3_SI_DI },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pmacsdql,          "__builtin_ia32_pmacsdql",   IX86_BUILTIN_PMACSDQL,   0,            (int)MULTI_ARG_3_SI_DI },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pmacsdqh,          "__builtin_ia32_pmacsdqh",   IX86_BUILTIN_PMACSDQH,   0,            (int)MULTI_ARG_3_SI_DI },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pmadcsswd,         "__builtin_ia32_pmadcsswd",  IX86_BUILTIN_PMADCSSWD,  0,            (int)MULTI_ARG_3_HI_SI },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pmadcswd,          "__builtin_ia32_pmadcswd",   IX86_BUILTIN_PMADCSWD,   0,            (int)MULTI_ARG_3_HI_SI },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_vrotlv2di3,        "__builtin_ia32_protq",      IX86_BUILTIN_PROTQ,      0,            (int)MULTI_ARG_2_DI },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_vrotlv4si3,        "__builtin_ia32_protd",      IX86_BUILTIN_PROTD,      0,            (int)MULTI_ARG_2_SI },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_vrotlv8hi3,        "__builtin_ia32_protw",      IX86_BUILTIN_PROTW,      0,            (int)MULTI_ARG_2_HI },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_vrotlv16qi3,       "__builtin_ia32_protb",      IX86_BUILTIN_PROTB,      0,            (int)MULTI_ARG_2_QI },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_rotlv2di3,         "__builtin_ia32_protqi",     IX86_BUILTIN_PROTQ_IMM,  0,            (int)MULTI_ARG_2_DI_IMM },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_rotlv4si3,         "__builtin_ia32_protdi",     IX86_BUILTIN_PROTD_IMM,  0,            (int)MULTI_ARG_2_SI_IMM },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_rotlv8hi3,         "__builtin_ia32_protwi",     IX86_BUILTIN_PROTW_IMM,  0,            (int)MULTI_ARG_2_HI_IMM },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_rotlv16qi3,        "__builtin_ia32_protbi",     IX86_BUILTIN_PROTB_IMM,  0,            (int)MULTI_ARG_2_QI_IMM },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_ashlv2di3,         "__builtin_ia32_pshaq",      IX86_BUILTIN_PSHAQ,      0,            (int)MULTI_ARG_2_DI },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_ashlv4si3,         "__builtin_ia32_pshad",      IX86_BUILTIN_PSHAD,      0,            (int)MULTI_ARG_2_SI },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_ashlv8hi3,         "__builtin_ia32_pshaw",      IX86_BUILTIN_PSHAW,      0,            (int)MULTI_ARG_2_HI },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_ashlv16qi3,        "__builtin_ia32_pshab",      IX86_BUILTIN_PSHAB,      0,            (int)MULTI_ARG_2_QI },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_lshlv2di3,         "__builtin_ia32_pshlq",      IX86_BUILTIN_PSHLQ,      0,            (int)MULTI_ARG_2_DI },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_lshlv4si3,         "__builtin_ia32_pshld",      IX86_BUILTIN_PSHLD,      0,            (int)MULTI_ARG_2_SI },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_lshlv8hi3,         "__builtin_ia32_pshlw",      IX86_BUILTIN_PSHLW,      0,            (int)MULTI_ARG_2_HI },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_lshlv16qi3,        "__builtin_ia32_pshlb",      IX86_BUILTIN_PSHLB,      0,            (int)MULTI_ARG_2_QI },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_vmfrczv4sf2,       "__builtin_ia32_frczss",     IX86_BUILTIN_FRCZSS,     0,            (int)MULTI_ARG_2_SF },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_vmfrczv2df2,       "__builtin_ia32_frczsd",     IX86_BUILTIN_FRCZSD,     0,            (int)MULTI_ARG_2_DF },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_frczv4sf2,         "__builtin_ia32_frczps",     IX86_BUILTIN_FRCZPS,     0,            (int)MULTI_ARG_1_SF },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_frczv2df2,         "__builtin_ia32_frczpd",     IX86_BUILTIN_FRCZPD,     0,            (int)MULTI_ARG_1_DF },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_cvtph2ps,          "__builtin_ia32_cvtph2ps",   IX86_BUILTIN_CVTPH2PS,   0,            (int)MULTI_ARG_1_PH2PS },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_cvtps2ph,          "__builtin_ia32_cvtps2ph",   IX86_BUILTIN_CVTPS2PH,   0,            (int)MULTI_ARG_1_PS2PH },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_phaddbw,           "__builtin_ia32_phaddbw",    IX86_BUILTIN_PHADDBW,    0,            (int)MULTI_ARG_1_QI_HI },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_phaddbd,           "__builtin_ia32_phaddbd",    IX86_BUILTIN_PHADDBD,    0,            (int)MULTI_ARG_1_QI_SI },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_phaddbq,           "__builtin_ia32_phaddbq",    IX86_BUILTIN_PHADDBQ,    0,            (int)MULTI_ARG_1_QI_DI },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_phaddwd,           "__builtin_ia32_phaddwd",    IX86_BUILTIN_PHADDWD,    0,            (int)MULTI_ARG_1_HI_SI },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_phaddwq,           "__builtin_ia32_phaddwq",    IX86_BUILTIN_PHADDWQ,    0,            (int)MULTI_ARG_1_HI_DI },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_phadddq,           "__builtin_ia32_phadddq",    IX86_BUILTIN_PHADDDQ,    0,            (int)MULTI_ARG_1_SI_DI },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_phaddubw,          "__builtin_ia32_phaddubw",   IX86_BUILTIN_PHADDUBW,   0,            (int)MULTI_ARG_1_QI_HI },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_phaddubd,          "__builtin_ia32_phaddubd",   IX86_BUILTIN_PHADDUBD,   0,            (int)MULTI_ARG_1_QI_SI },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_phaddubq,          "__builtin_ia32_phaddubq",   IX86_BUILTIN_PHADDUBQ,   0,            (int)MULTI_ARG_1_QI_DI },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_phadduwd,          "__builtin_ia32_phadduwd",   IX86_BUILTIN_PHADDUWD,   0,            (int)MULTI_ARG_1_HI_SI },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_phadduwq,          "__builtin_ia32_phadduwq",   IX86_BUILTIN_PHADDUWQ,   0,            (int)MULTI_ARG_1_HI_DI },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_phaddudq,          "__builtin_ia32_phaddudq",   IX86_BUILTIN_PHADDUDQ,   0,            (int)MULTI_ARG_1_SI_DI },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_phsubbw,           "__builtin_ia32_phsubbw",    IX86_BUILTIN_PHSUBBW,    0,            (int)MULTI_ARG_1_QI_HI },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_phsubwd,           "__builtin_ia32_phsubwd",    IX86_BUILTIN_PHSUBWD,    0,            (int)MULTI_ARG_1_HI_SI },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_phsubdq,           "__builtin_ia32_phsubdq",    IX86_BUILTIN_PHSUBDQ,    0,            (int)MULTI_ARG_1_SI_DI },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5i_vmfmaddv4sf4,     "__builtin_ia32_fmaddss",    IX86_BUILTIN_FMADDSS,    UNKNOWN,      (int)MULTI_ARG_3_SF },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5i_vmfmaddv2df4,     "__builtin_ia32_fmaddsd",    IX86_BUILTIN_FMADDSD,    UNKNOWN,      (int)MULTI_ARG_3_DF },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5i_fmaddv4sf4,       "__builtin_ia32_fmaddps",    IX86_BUILTIN_FMADDPS,    UNKNOWN,      (int)MULTI_ARG_3_SF },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5i_fmaddv2df4,       "__builtin_ia32_fmaddpd",    IX86_BUILTIN_FMADDPD,    UNKNOWN,      (int)MULTI_ARG_3_DF },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5i_vmfmsubv4sf4,     "__builtin_ia32_fmsubss",    IX86_BUILTIN_FMSUBSS,    UNKNOWN,      (int)MULTI_ARG_3_SF },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5i_vmfmsubv2df4,     "__builtin_ia32_fmsubsd",    IX86_BUILTIN_FMSUBSD,    UNKNOWN,      (int)MULTI_ARG_3_DF },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5i_fmsubv4sf4,       "__builtin_ia32_fmsubps",    IX86_BUILTIN_FMSUBPS,    UNKNOWN,      (int)MULTI_ARG_3_SF },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5i_fmsubv2df4,       "__builtin_ia32_fmsubpd",    IX86_BUILTIN_FMSUBPD,    UNKNOWN,      (int)MULTI_ARG_3_DF },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5i_vmfnmaddv4sf4,    "__builtin_ia32_fnmaddss",   IX86_BUILTIN_FNMADDSS,   UNKNOWN,      (int)MULTI_ARG_3_SF },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5i_vmfnmaddv2df4,    "__builtin_ia32_fnmaddsd",   IX86_BUILTIN_FNMADDSD,   UNKNOWN,      (int)MULTI_ARG_3_DF },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5i_fnmaddv4sf4,      "__builtin_ia32_fnmaddps",   IX86_BUILTIN_FNMADDPS,   UNKNOWN,      (int)MULTI_ARG_3_SF },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5i_fnmaddv2df4,      "__builtin_ia32_fnmaddpd",   IX86_BUILTIN_FNMADDPD,   UNKNOWN,      (int)MULTI_ARG_3_DF },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5i_vmfnmsubv4sf4,    "__builtin_ia32_fnmsubss",   IX86_BUILTIN_FNMSUBSS,   UNKNOWN,      (int)MULTI_ARG_3_SF },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5i_vmfnmsubv2df4,    "__builtin_ia32_fnmsubsd",   IX86_BUILTIN_FNMSUBSD,   UNKNOWN,      (int)MULTI_ARG_3_DF },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5i_fnmsubv4sf4,      "__builtin_ia32_fnmsubps",   IX86_BUILTIN_FNMSUBPS,   UNKNOWN,      (int)MULTI_ARG_3_SF },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5i_fnmsubv2df4,      "__builtin_ia32_fnmsubpd",   IX86_BUILTIN_FNMSUBPD,   UNKNOWN,      (int)MULTI_ARG_3_DF },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcmov_v2di,        "__builtin_ia32_pcmov",      IX86_BUILTIN_PCMOV,     UNKNOWN,      (int)MULTI_ARG_3_DI },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcmov_v2di,        "__builtin_ia32_pcmov_v2di", IX86_BUILTIN_PCMOV_V2DI, UNKNOWN,      (int)MULTI_ARG_3_DI },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcmov_v4si,        "__builtin_ia32_pcmov_v4si", IX86_BUILTIN_PCMOV_V4SI, UNKNOWN,      (int)MULTI_ARG_3_SI },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcmov_v8hi,        "__builtin_ia32_pcmov_v8hi", IX86_BUILTIN_PCMOV_V8HI, UNKNOWN,      (int)MULTI_ARG_3_HI },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcmov_v16qi,       "__builtin_ia32_pcmov_v16qi",IX86_BUILTIN_PCMOV_V16QI,UNKNOWN,      (int)MULTI_ARG_3_QI },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcmov_v2df,        "__builtin_ia32_pcmov_v2df", IX86_BUILTIN_PCMOV_V2DF, UNKNOWN,      (int)MULTI_ARG_3_DF },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcmov_v4sf,        "__builtin_ia32_pcmov_v4sf", IX86_BUILTIN_PCMOV_V4SF, UNKNOWN,      (int)MULTI_ARG_3_SF },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pperm,             "__builtin_ia32_pperm",      IX86_BUILTIN_PPERM,      UNKNOWN,      (int)MULTI_ARG_3_QI },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_permv4sf,          "__builtin_ia32_permps",     IX86_BUILTIN_PERMPS,     UNKNOWN,      (int)MULTI_ARG_3_PERMPS },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_permv2df,          "__builtin_ia32_permpd",     IX86_BUILTIN_PERMPD,     UNKNOWN,      (int)MULTI_ARG_3_PERMPD },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pmacssww,          "__builtin_ia32_pmacssww",   IX86_BUILTIN_PMACSSWW,   UNKNOWN,      (int)MULTI_ARG_3_HI },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pmacsww,           "__builtin_ia32_pmacsww",    IX86_BUILTIN_PMACSWW,    UNKNOWN,      (int)MULTI_ARG_3_HI },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pmacsswd,          "__builtin_ia32_pmacsswd",   IX86_BUILTIN_PMACSSWD,   UNKNOWN,      (int)MULTI_ARG_3_HI_SI },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pmacswd,           "__builtin_ia32_pmacswd",    IX86_BUILTIN_PMACSWD,    UNKNOWN,      (int)MULTI_ARG_3_HI_SI },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pmacssdd,          "__builtin_ia32_pmacssdd",   IX86_BUILTIN_PMACSSDD,   UNKNOWN,      (int)MULTI_ARG_3_SI },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pmacsdd,           "__builtin_ia32_pmacsdd",    IX86_BUILTIN_PMACSDD,    UNKNOWN,      (int)MULTI_ARG_3_SI },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pmacssdql,         "__builtin_ia32_pmacssdql",  IX86_BUILTIN_PMACSSDQL,  UNKNOWN,      (int)MULTI_ARG_3_SI_DI },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pmacssdqh,         "__builtin_ia32_pmacssdqh",  IX86_BUILTIN_PMACSSDQH,  UNKNOWN,      (int)MULTI_ARG_3_SI_DI },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pmacsdql,          "__builtin_ia32_pmacsdql",   IX86_BUILTIN_PMACSDQL,   UNKNOWN,      (int)MULTI_ARG_3_SI_DI },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pmacsdqh,          "__builtin_ia32_pmacsdqh",   IX86_BUILTIN_PMACSDQH,   UNKNOWN,      (int)MULTI_ARG_3_SI_DI },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pmadcsswd,         "__builtin_ia32_pmadcsswd",  IX86_BUILTIN_PMADCSSWD,  UNKNOWN,      (int)MULTI_ARG_3_HI_SI },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pmadcswd,          "__builtin_ia32_pmadcswd",   IX86_BUILTIN_PMADCSWD,   UNKNOWN,      (int)MULTI_ARG_3_HI_SI },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_vrotlv2di3,        "__builtin_ia32_protq",      IX86_BUILTIN_PROTQ,      UNKNOWN,      (int)MULTI_ARG_2_DI },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_vrotlv4si3,        "__builtin_ia32_protd",      IX86_BUILTIN_PROTD,      UNKNOWN,      (int)MULTI_ARG_2_SI },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_vrotlv8hi3,        "__builtin_ia32_protw",      IX86_BUILTIN_PROTW,      UNKNOWN,      (int)MULTI_ARG_2_HI },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_vrotlv16qi3,       "__builtin_ia32_protb",      IX86_BUILTIN_PROTB,      UNKNOWN,      (int)MULTI_ARG_2_QI },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_rotlv2di3,         "__builtin_ia32_protqi",     IX86_BUILTIN_PROTQ_IMM,  UNKNOWN,      (int)MULTI_ARG_2_DI_IMM },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_rotlv4si3,         "__builtin_ia32_protdi",     IX86_BUILTIN_PROTD_IMM,  UNKNOWN,      (int)MULTI_ARG_2_SI_IMM },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_rotlv8hi3,         "__builtin_ia32_protwi",     IX86_BUILTIN_PROTW_IMM,  UNKNOWN,      (int)MULTI_ARG_2_HI_IMM },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_rotlv16qi3,        "__builtin_ia32_protbi",     IX86_BUILTIN_PROTB_IMM,  UNKNOWN,      (int)MULTI_ARG_2_QI_IMM },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_ashlv2di3,         "__builtin_ia32_pshaq",      IX86_BUILTIN_PSHAQ,      UNKNOWN,      (int)MULTI_ARG_2_DI },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_ashlv4si3,         "__builtin_ia32_pshad",      IX86_BUILTIN_PSHAD,      UNKNOWN,      (int)MULTI_ARG_2_SI },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_ashlv8hi3,         "__builtin_ia32_pshaw",      IX86_BUILTIN_PSHAW,      UNKNOWN,      (int)MULTI_ARG_2_HI },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_ashlv16qi3,        "__builtin_ia32_pshab",      IX86_BUILTIN_PSHAB,      UNKNOWN,      (int)MULTI_ARG_2_QI },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_lshlv2di3,         "__builtin_ia32_pshlq",      IX86_BUILTIN_PSHLQ,      UNKNOWN,      (int)MULTI_ARG_2_DI },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_lshlv4si3,         "__builtin_ia32_pshld",      IX86_BUILTIN_PSHLD,      UNKNOWN,      (int)MULTI_ARG_2_SI },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_lshlv8hi3,         "__builtin_ia32_pshlw",      IX86_BUILTIN_PSHLW,      UNKNOWN,      (int)MULTI_ARG_2_HI },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_lshlv16qi3,        "__builtin_ia32_pshlb",      IX86_BUILTIN_PSHLB,      UNKNOWN,      (int)MULTI_ARG_2_QI },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_vmfrczv4sf2,       "__builtin_ia32_frczss",     IX86_BUILTIN_FRCZSS,     UNKNOWN,      (int)MULTI_ARG_2_SF },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_vmfrczv2df2,       "__builtin_ia32_frczsd",     IX86_BUILTIN_FRCZSD,     UNKNOWN,      (int)MULTI_ARG_2_DF },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_frczv4sf2,         "__builtin_ia32_frczps",     IX86_BUILTIN_FRCZPS,     UNKNOWN,      (int)MULTI_ARG_1_SF },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_frczv2df2,         "__builtin_ia32_frczpd",     IX86_BUILTIN_FRCZPD,     UNKNOWN,      (int)MULTI_ARG_1_DF },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_cvtph2ps,          "__builtin_ia32_cvtph2ps",   IX86_BUILTIN_CVTPH2PS,   UNKNOWN,      (int)MULTI_ARG_1_PH2PS },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_cvtps2ph,          "__builtin_ia32_cvtps2ph",   IX86_BUILTIN_CVTPS2PH,   UNKNOWN,      (int)MULTI_ARG_1_PS2PH },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_phaddbw,           "__builtin_ia32_phaddbw",    IX86_BUILTIN_PHADDBW,    UNKNOWN,      (int)MULTI_ARG_1_QI_HI },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_phaddbd,           "__builtin_ia32_phaddbd",    IX86_BUILTIN_PHADDBD,    UNKNOWN,      (int)MULTI_ARG_1_QI_SI },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_phaddbq,           "__builtin_ia32_phaddbq",    IX86_BUILTIN_PHADDBQ,    UNKNOWN,      (int)MULTI_ARG_1_QI_DI },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_phaddwd,           "__builtin_ia32_phaddwd",    IX86_BUILTIN_PHADDWD,    UNKNOWN,      (int)MULTI_ARG_1_HI_SI },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_phaddwq,           "__builtin_ia32_phaddwq",    IX86_BUILTIN_PHADDWQ,    UNKNOWN,      (int)MULTI_ARG_1_HI_DI },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_phadddq,           "__builtin_ia32_phadddq",    IX86_BUILTIN_PHADDDQ,    UNKNOWN,      (int)MULTI_ARG_1_SI_DI },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_phaddubw,          "__builtin_ia32_phaddubw",   IX86_BUILTIN_PHADDUBW,   UNKNOWN,      (int)MULTI_ARG_1_QI_HI },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_phaddubd,          "__builtin_ia32_phaddubd",   IX86_BUILTIN_PHADDUBD,   UNKNOWN,      (int)MULTI_ARG_1_QI_SI },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_phaddubq,          "__builtin_ia32_phaddubq",   IX86_BUILTIN_PHADDUBQ,   UNKNOWN,      (int)MULTI_ARG_1_QI_DI },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_phadduwd,          "__builtin_ia32_phadduwd",   IX86_BUILTIN_PHADDUWD,   UNKNOWN,      (int)MULTI_ARG_1_HI_SI },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_phadduwq,          "__builtin_ia32_phadduwq",   IX86_BUILTIN_PHADDUWQ,   UNKNOWN,      (int)MULTI_ARG_1_HI_DI },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_phaddudq,          "__builtin_ia32_phaddudq",   IX86_BUILTIN_PHADDUDQ,   UNKNOWN,      (int)MULTI_ARG_1_SI_DI },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_phsubbw,           "__builtin_ia32_phsubbw",    IX86_BUILTIN_PHSUBBW,    UNKNOWN,      (int)MULTI_ARG_1_QI_HI },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_phsubwd,           "__builtin_ia32_phsubwd",    IX86_BUILTIN_PHSUBWD,    UNKNOWN,      (int)MULTI_ARG_1_HI_SI },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_phsubdq,           "__builtin_ia32_phsubdq",    IX86_BUILTIN_PHSUBDQ,    UNKNOWN,      (int)MULTI_ARG_1_SI_DI },
 
   { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_vmmaskcmpv4sf3,    "__builtin_ia32_comeqss",    IX86_BUILTIN_COMEQSS,    EQ,           (int)MULTI_ARG_2_SF_CMP },
   { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_vmmaskcmpv4sf3,    "__builtin_ia32_comness",    IX86_BUILTIN_COMNESS,    NE,           (int)MULTI_ARG_2_SF_CMP },
@@ -18935,37 +22457,38 @@ static const struct builtin_description bdesc_multi_arg[] =
   { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_maskcmp_unsv2di3,  "__builtin_ia32_pcomgtuq",   IX86_BUILTIN_PCOMGTUQ,   GTU,          (int)MULTI_ARG_2_DI_CMP },
   { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_maskcmp_unsv2di3,  "__builtin_ia32_pcomgeuq",   IX86_BUILTIN_PCOMGEUQ,   GEU,          (int)MULTI_ARG_2_DI_CMP },
 
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_com_tfv4sf3,       "__builtin_ia32_comfalsess", IX86_BUILTIN_COMFALSESS, COM_FALSE_S,  (int)MULTI_ARG_2_SF_TF },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_com_tfv4sf3,       "__builtin_ia32_comtruess",  IX86_BUILTIN_COMTRUESS,  COM_TRUE_S,   (int)MULTI_ARG_2_SF_TF },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_com_tfv4sf3,       "__builtin_ia32_comfalseps", IX86_BUILTIN_COMFALSEPS, COM_FALSE_P,  (int)MULTI_ARG_2_SF_TF },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_com_tfv4sf3,       "__builtin_ia32_comtrueps",  IX86_BUILTIN_COMTRUEPS,  COM_TRUE_P,   (int)MULTI_ARG_2_SF_TF },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_com_tfv2df3,       "__builtin_ia32_comfalsesd", IX86_BUILTIN_COMFALSESD, COM_FALSE_S,  (int)MULTI_ARG_2_DF_TF },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_com_tfv2df3,       "__builtin_ia32_comtruesd",  IX86_BUILTIN_COMTRUESD,  COM_TRUE_S,   (int)MULTI_ARG_2_DF_TF },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_com_tfv2df3,       "__builtin_ia32_comfalsepd", IX86_BUILTIN_COMFALSEPD, COM_FALSE_P,  (int)MULTI_ARG_2_DF_TF },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_com_tfv2df3,       "__builtin_ia32_comtruepd",  IX86_BUILTIN_COMTRUEPD,  COM_TRUE_P,   (int)MULTI_ARG_2_DF_TF },
-
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcom_tfv16qi3,     "__builtin_ia32_pcomfalseb", IX86_BUILTIN_PCOMFALSEB, PCOM_FALSE,   (int)MULTI_ARG_2_QI_TF },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcom_tfv8hi3,      "__builtin_ia32_pcomfalsew", IX86_BUILTIN_PCOMFALSEW, PCOM_FALSE,   (int)MULTI_ARG_2_HI_TF },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcom_tfv4si3,      "__builtin_ia32_pcomfalsed", IX86_BUILTIN_PCOMFALSED, PCOM_FALSE,   (int)MULTI_ARG_2_SI_TF },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcom_tfv2di3,      "__builtin_ia32_pcomfalseq", IX86_BUILTIN_PCOMFALSEQ, PCOM_FALSE,   (int)MULTI_ARG_2_DI_TF },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcom_tfv16qi3,     "__builtin_ia32_pcomfalseub",IX86_BUILTIN_PCOMFALSEUB,PCOM_FALSE,   (int)MULTI_ARG_2_QI_TF },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcom_tfv8hi3,      "__builtin_ia32_pcomfalseuw",IX86_BUILTIN_PCOMFALSEUW,PCOM_FALSE,   (int)MULTI_ARG_2_HI_TF },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcom_tfv4si3,      "__builtin_ia32_pcomfalseud",IX86_BUILTIN_PCOMFALSEUD,PCOM_FALSE,   (int)MULTI_ARG_2_SI_TF },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcom_tfv2di3,      "__builtin_ia32_pcomfalseuq",IX86_BUILTIN_PCOMFALSEUQ,PCOM_FALSE,   (int)MULTI_ARG_2_DI_TF },
-
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcom_tfv16qi3,     "__builtin_ia32_pcomtrueb",  IX86_BUILTIN_PCOMTRUEB,  PCOM_TRUE,    (int)MULTI_ARG_2_QI_TF },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcom_tfv8hi3,      "__builtin_ia32_pcomtruew",  IX86_BUILTIN_PCOMTRUEW,  PCOM_TRUE,    (int)MULTI_ARG_2_HI_TF },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcom_tfv4si3,      "__builtin_ia32_pcomtrued",  IX86_BUILTIN_PCOMTRUED,  PCOM_TRUE,    (int)MULTI_ARG_2_SI_TF },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcom_tfv2di3,      "__builtin_ia32_pcomtrueq",  IX86_BUILTIN_PCOMTRUEQ,  PCOM_TRUE,    (int)MULTI_ARG_2_DI_TF },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcom_tfv16qi3,     "__builtin_ia32_pcomtrueub", IX86_BUILTIN_PCOMTRUEUB, PCOM_TRUE,    (int)MULTI_ARG_2_QI_TF },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcom_tfv8hi3,      "__builtin_ia32_pcomtrueuw", IX86_BUILTIN_PCOMTRUEUW, PCOM_TRUE,    (int)MULTI_ARG_2_HI_TF },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcom_tfv4si3,      "__builtin_ia32_pcomtrueud", IX86_BUILTIN_PCOMTRUEUD, PCOM_TRUE,    (int)MULTI_ARG_2_SI_TF },
-  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcom_tfv2di3,      "__builtin_ia32_pcomtrueuq", IX86_BUILTIN_PCOMTRUEUQ, PCOM_TRUE,    (int)MULTI_ARG_2_DI_TF },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_com_tfv4sf3,       "__builtin_ia32_comfalsess", IX86_BUILTIN_COMFALSESS, (enum rtx_code) COM_FALSE_S,  (int)MULTI_ARG_2_SF_TF },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_com_tfv4sf3,       "__builtin_ia32_comtruess",  IX86_BUILTIN_COMTRUESS,  (enum rtx_code) COM_TRUE_S,   (int)MULTI_ARG_2_SF_TF },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_com_tfv4sf3,       "__builtin_ia32_comfalseps", IX86_BUILTIN_COMFALSEPS, (enum rtx_code) COM_FALSE_P,  (int)MULTI_ARG_2_SF_TF },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_com_tfv4sf3,       "__builtin_ia32_comtrueps",  IX86_BUILTIN_COMTRUEPS,  (enum rtx_code) COM_TRUE_P,   (int)MULTI_ARG_2_SF_TF },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_com_tfv2df3,       "__builtin_ia32_comfalsesd", IX86_BUILTIN_COMFALSESD, (enum rtx_code) COM_FALSE_S,  (int)MULTI_ARG_2_DF_TF },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_com_tfv2df3,       "__builtin_ia32_comtruesd",  IX86_BUILTIN_COMTRUESD,  (enum rtx_code) COM_TRUE_S,   (int)MULTI_ARG_2_DF_TF },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_com_tfv2df3,       "__builtin_ia32_comfalsepd", IX86_BUILTIN_COMFALSEPD, (enum rtx_code) COM_FALSE_P,  (int)MULTI_ARG_2_DF_TF },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_com_tfv2df3,       "__builtin_ia32_comtruepd",  IX86_BUILTIN_COMTRUEPD,  (enum rtx_code) COM_TRUE_P,   (int)MULTI_ARG_2_DF_TF },
+
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcom_tfv16qi3,     "__builtin_ia32_pcomfalseb", IX86_BUILTIN_PCOMFALSEB, (enum rtx_code) PCOM_FALSE,   (int)MULTI_ARG_2_QI_TF },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcom_tfv8hi3,      "__builtin_ia32_pcomfalsew", IX86_BUILTIN_PCOMFALSEW, (enum rtx_code) PCOM_FALSE,   (int)MULTI_ARG_2_HI_TF },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcom_tfv4si3,      "__builtin_ia32_pcomfalsed", IX86_BUILTIN_PCOMFALSED, (enum rtx_code) PCOM_FALSE,   (int)MULTI_ARG_2_SI_TF },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcom_tfv2di3,      "__builtin_ia32_pcomfalseq", IX86_BUILTIN_PCOMFALSEQ, (enum rtx_code) PCOM_FALSE,   (int)MULTI_ARG_2_DI_TF },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcom_tfv16qi3,     "__builtin_ia32_pcomfalseub",IX86_BUILTIN_PCOMFALSEUB,(enum rtx_code) PCOM_FALSE,   (int)MULTI_ARG_2_QI_TF },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcom_tfv8hi3,      "__builtin_ia32_pcomfalseuw",IX86_BUILTIN_PCOMFALSEUW,(enum rtx_code) PCOM_FALSE,   (int)MULTI_ARG_2_HI_TF },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcom_tfv4si3,      "__builtin_ia32_pcomfalseud",IX86_BUILTIN_PCOMFALSEUD,(enum rtx_code) PCOM_FALSE,   (int)MULTI_ARG_2_SI_TF },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcom_tfv2di3,      "__builtin_ia32_pcomfalseuq",IX86_BUILTIN_PCOMFALSEUQ,(enum rtx_code) PCOM_FALSE,   (int)MULTI_ARG_2_DI_TF },
+
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcom_tfv16qi3,     "__builtin_ia32_pcomtrueb",  IX86_BUILTIN_PCOMTRUEB,  (enum rtx_code) PCOM_TRUE,    (int)MULTI_ARG_2_QI_TF },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcom_tfv8hi3,      "__builtin_ia32_pcomtruew",  IX86_BUILTIN_PCOMTRUEW,  (enum rtx_code) PCOM_TRUE,    (int)MULTI_ARG_2_HI_TF },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcom_tfv4si3,      "__builtin_ia32_pcomtrued",  IX86_BUILTIN_PCOMTRUED,  (enum rtx_code) PCOM_TRUE,    (int)MULTI_ARG_2_SI_TF },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcom_tfv2di3,      "__builtin_ia32_pcomtrueq",  IX86_BUILTIN_PCOMTRUEQ,  (enum rtx_code) PCOM_TRUE,    (int)MULTI_ARG_2_DI_TF },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcom_tfv16qi3,     "__builtin_ia32_pcomtrueub", IX86_BUILTIN_PCOMTRUEUB, (enum rtx_code) PCOM_TRUE,    (int)MULTI_ARG_2_QI_TF },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcom_tfv8hi3,      "__builtin_ia32_pcomtrueuw", IX86_BUILTIN_PCOMTRUEUW, (enum rtx_code) PCOM_TRUE,    (int)MULTI_ARG_2_HI_TF },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcom_tfv4si3,      "__builtin_ia32_pcomtrueud", IX86_BUILTIN_PCOMTRUEUD, (enum rtx_code) PCOM_TRUE,    (int)MULTI_ARG_2_SI_TF },
+  { OPTION_MASK_ISA_SSE5, CODE_FOR_sse5_pcom_tfv2di3,      "__builtin_ia32_pcomtrueuq", IX86_BUILTIN_PCOMTRUEUQ, (enum rtx_code) PCOM_TRUE,    (int)MULTI_ARG_2_DI_TF },
 };
 
-/* Set up all the MMX/SSE builtins.  This is not called if TARGET_MMX
-   is zero.  Otherwise, if TARGET_SSE is not set, only expand the MMX
-   builtins.  */
+/* Set up all the MMX/SSE builtins, even builtins for instructions that are not
+   in the current target ISA to allow the user to compile particular modules
+   with different target specific options that differ from the command line
+   options.  */
 static void
 ix86_init_mmx_sse_builtins (void)
 {
@@ -19452,64 +22975,307 @@ ix86_init_mmx_sse_builtins (void)
                                unsigned_type_node,
                                short_unsigned_type_node,
                                NULL_TREE);
-  tree unsigned_ftype_unsigned_unsigned
-    = build_function_type_list (unsigned_type_node,
-                               unsigned_type_node,
-                               unsigned_type_node,
+  tree unsigned_ftype_unsigned_unsigned
+    = build_function_type_list (unsigned_type_node,
+                               unsigned_type_node,
+                               unsigned_type_node,
+                               NULL_TREE);
+  tree uint64_ftype_uint64_uint64
+    = build_function_type_list (long_long_unsigned_type_node,
+                               long_long_unsigned_type_node,
+                               long_long_unsigned_type_node,
+                               NULL_TREE);
+  tree float_ftype_float
+    = build_function_type_list (float_type_node,
+                               float_type_node,
+                               NULL_TREE);
+
+  /* AVX builtins  */
+  tree V32QI_type_node = build_vector_type_for_mode (char_type_node,
+                                                    V32QImode);
+  tree V8SI_type_node = build_vector_type_for_mode (intSI_type_node,
+                                                   V8SImode);
+  tree V8SF_type_node = build_vector_type_for_mode (float_type_node,
+                                                   V8SFmode);
+  tree V4DI_type_node = build_vector_type_for_mode (long_long_integer_type_node,
+                                                   V4DImode);
+  tree V4DF_type_node = build_vector_type_for_mode (double_type_node,
+                                                   V4DFmode);
+  tree v8sf_ftype_v8sf
+    = build_function_type_list (V8SF_type_node,
+                               V8SF_type_node,
+                               NULL_TREE);
+  tree v8si_ftype_v8sf
+    = build_function_type_list (V8SI_type_node,
+                               V8SF_type_node,
+                               NULL_TREE);
+  tree v8sf_ftype_v8si
+    = build_function_type_list (V8SF_type_node,
+                               V8SI_type_node,
+                               NULL_TREE);
+  tree v4si_ftype_v4df
+    = build_function_type_list (V4SI_type_node,
+                               V4DF_type_node,
+                               NULL_TREE);
+  tree v4df_ftype_v4df
+    = build_function_type_list (V4DF_type_node,
+                               V4DF_type_node,
+                               NULL_TREE);
+  tree v4df_ftype_v4si
+    = build_function_type_list (V4DF_type_node,
+                               V4SI_type_node,
+                               NULL_TREE);
+  tree v4df_ftype_v4sf
+    = build_function_type_list (V4DF_type_node,
+                               V4SF_type_node,
+                               NULL_TREE);
+  tree v4sf_ftype_v4df
+    = build_function_type_list (V4SF_type_node,
+                               V4DF_type_node,
+                               NULL_TREE);
+  tree v8sf_ftype_v8sf_v8sf
+    = build_function_type_list (V8SF_type_node,
+                               V8SF_type_node, V8SF_type_node,
+                               NULL_TREE);
+  tree v4df_ftype_v4df_v4df
+    = build_function_type_list (V4DF_type_node,
+                               V4DF_type_node, V4DF_type_node,
+                               NULL_TREE);
+  tree v8sf_ftype_v8sf_int
+    = build_function_type_list (V8SF_type_node,
+                               V8SF_type_node, integer_type_node,
+                               NULL_TREE);
+  tree v4si_ftype_v8si_int
+    = build_function_type_list (V4SI_type_node,
+                               V8SI_type_node, integer_type_node,
+                               NULL_TREE);
+  tree v4df_ftype_v4df_int
+    = build_function_type_list (V4DF_type_node,
+                               V4DF_type_node, integer_type_node,
+                               NULL_TREE);
+  tree v4sf_ftype_v8sf_int
+    = build_function_type_list (V4SF_type_node,
+                               V8SF_type_node, integer_type_node,
+                               NULL_TREE);
+  tree v2df_ftype_v4df_int
+    = build_function_type_list (V2DF_type_node,
+                               V4DF_type_node, integer_type_node,
+                               NULL_TREE);
+  tree v8sf_ftype_v8sf_v8sf_int
+    = build_function_type_list (V8SF_type_node,
+                               V8SF_type_node, V8SF_type_node,
+                               integer_type_node,
+                               NULL_TREE);
+  tree v8sf_ftype_v8sf_v8sf_v8sf
+    = build_function_type_list (V8SF_type_node,
+                               V8SF_type_node, V8SF_type_node,
+                               V8SF_type_node,
+                               NULL_TREE);
+  tree v4df_ftype_v4df_v4df_v4df
+    = build_function_type_list (V4DF_type_node,
+                               V4DF_type_node, V4DF_type_node,
+                               V4DF_type_node,
+                               NULL_TREE);
+  tree v8si_ftype_v8si_v8si_int
+    = build_function_type_list (V8SI_type_node,
+                               V8SI_type_node, V8SI_type_node,
+                               integer_type_node,
+                               NULL_TREE);
+  tree v4df_ftype_v4df_v4df_int
+    = build_function_type_list (V4DF_type_node,
+                               V4DF_type_node, V4DF_type_node,
+                               integer_type_node,
+                               NULL_TREE);
+  tree v8sf_ftype_pcfloat
+    = build_function_type_list (V8SF_type_node,
+                               pcfloat_type_node,
+                               NULL_TREE);
+  tree v4df_ftype_pcdouble
+    = build_function_type_list (V4DF_type_node,
+                               pcdouble_type_node,
+                               NULL_TREE);
+  tree pcv4sf_type_node
+    = build_pointer_type (build_type_variant (V4SF_type_node, 1, 0));
+  tree pcv2df_type_node
+    = build_pointer_type (build_type_variant (V2DF_type_node, 1, 0));
+  tree v8sf_ftype_pcv4sf
+    = build_function_type_list (V8SF_type_node,
+                               pcv4sf_type_node,
+                               NULL_TREE);
+  tree v4df_ftype_pcv2df
+    = build_function_type_list (V4DF_type_node,
+                               pcv2df_type_node,
+                               NULL_TREE);
+  tree v32qi_ftype_pcchar
+    = build_function_type_list (V32QI_type_node,
+                               pcchar_type_node,
+                               NULL_TREE);
+  tree void_ftype_pchar_v32qi
+    = build_function_type_list (void_type_node,
+                               pchar_type_node, V32QI_type_node,
+                               NULL_TREE);
+  tree v8si_ftype_v8si_v4si_int
+    = build_function_type_list (V8SI_type_node,
+                               V8SI_type_node, V4SI_type_node,
+                               integer_type_node,
+                               NULL_TREE);
+  tree pv4di_type_node = build_pointer_type (V4DI_type_node);
+  tree void_ftype_pv4di_v4di
+    = build_function_type_list (void_type_node,
+                               pv4di_type_node, V4DI_type_node,
+                               NULL_TREE);
+  tree v8sf_ftype_v8sf_v4sf_int
+    = build_function_type_list (V8SF_type_node,
+                               V8SF_type_node, V4SF_type_node,
+                               integer_type_node,
+                               NULL_TREE);
+  tree v4df_ftype_v4df_v2df_int
+    = build_function_type_list (V4DF_type_node,
+                               V4DF_type_node, V2DF_type_node,
+                               integer_type_node,
+                               NULL_TREE);
+  tree void_ftype_pfloat_v8sf
+    = build_function_type_list (void_type_node,
+                               pfloat_type_node, V8SF_type_node,
+                               NULL_TREE);
+  tree void_ftype_pdouble_v4df
+    = build_function_type_list (void_type_node,
+                               pdouble_type_node, V4DF_type_node,
+                               NULL_TREE);
+  tree pv8sf_type_node = build_pointer_type (V8SF_type_node);
+  tree pv4sf_type_node = build_pointer_type (V4SF_type_node);
+  tree pv4df_type_node = build_pointer_type (V4DF_type_node);
+  tree pv2df_type_node = build_pointer_type (V2DF_type_node);
+  tree pcv8sf_type_node
+    = build_pointer_type (build_type_variant (V8SF_type_node, 1, 0));
+  tree pcv4df_type_node
+    = build_pointer_type (build_type_variant (V4DF_type_node, 1, 0));
+  tree v8sf_ftype_pcv8sf_v8sf
+    = build_function_type_list (V8SF_type_node,
+                               pcv8sf_type_node, V8SF_type_node,
+                               NULL_TREE);
+  tree v4df_ftype_pcv4df_v4df
+    = build_function_type_list (V4DF_type_node,
+                               pcv4df_type_node, V4DF_type_node,
+                               NULL_TREE);
+  tree v4sf_ftype_pcv4sf_v4sf
+    = build_function_type_list (V4SF_type_node,
+                               pcv4sf_type_node, V4SF_type_node,
+                               NULL_TREE);
+  tree v2df_ftype_pcv2df_v2df
+    = build_function_type_list (V2DF_type_node,
+                               pcv2df_type_node, V2DF_type_node,
+                               NULL_TREE);
+  tree void_ftype_pv8sf_v8sf_v8sf
+    = build_function_type_list (void_type_node,
+                               pv8sf_type_node, V8SF_type_node,
+                               V8SF_type_node,
+                               NULL_TREE);
+  tree void_ftype_pv4df_v4df_v4df
+    = build_function_type_list (void_type_node,
+                               pv4df_type_node, V4DF_type_node,
+                               V4DF_type_node,
+                               NULL_TREE);
+  tree void_ftype_pv4sf_v4sf_v4sf
+    = build_function_type_list (void_type_node,
+                               pv4sf_type_node, V4SF_type_node,
+                               V4SF_type_node,
+                               NULL_TREE);
+  tree void_ftype_pv2df_v2df_v2df
+    = build_function_type_list (void_type_node,
+                               pv2df_type_node, V2DF_type_node,
+                               V2DF_type_node,
+                               NULL_TREE);
+  tree v4df_ftype_v2df
+    = build_function_type_list (V4DF_type_node,
+                               V2DF_type_node,
+                               NULL_TREE);
+  tree v8sf_ftype_v4sf
+    = build_function_type_list (V8SF_type_node,
+                               V4SF_type_node,
+                               NULL_TREE);
+  tree v8si_ftype_v4si
+    = build_function_type_list (V8SI_type_node,
+                               V4SI_type_node,
+                               NULL_TREE);
+  tree v2df_ftype_v4df
+    = build_function_type_list (V2DF_type_node,
+                               V4DF_type_node,
+                               NULL_TREE);
+  tree v4sf_ftype_v8sf
+    = build_function_type_list (V4SF_type_node,
+                               V8SF_type_node,
+                               NULL_TREE);
+  tree v4si_ftype_v8si
+    = build_function_type_list (V4SI_type_node,
+                               V8SI_type_node,
+                               NULL_TREE);
+  tree int_ftype_v4df
+    = build_function_type_list (integer_type_node,
+                               V4DF_type_node,
+                               NULL_TREE);
+  tree int_ftype_v8sf
+    = build_function_type_list (integer_type_node,
+                               V8SF_type_node,
+                               NULL_TREE);
+  tree int_ftype_v8sf_v8sf
+    = build_function_type_list (integer_type_node,
+                               V8SF_type_node, V8SF_type_node,
+                               NULL_TREE);
+  tree int_ftype_v4di_v4di
+    = build_function_type_list (integer_type_node,
+                               V4DI_type_node, V4DI_type_node,
+                               NULL_TREE);
+  tree int_ftype_v4df_v4df
+    = build_function_type_list (integer_type_node,
+                               V4DF_type_node, V4DF_type_node,
+                               NULL_TREE);
+  tree v8sf_ftype_v8sf_v8si
+    = build_function_type_list (V8SF_type_node,
+                               V8SF_type_node, V8SI_type_node,
+                               NULL_TREE);
+  tree v4df_ftype_v4df_v4di
+    = build_function_type_list (V4DF_type_node,
+                               V4DF_type_node, V4DI_type_node,
+                               NULL_TREE);
+  tree v4sf_ftype_v4sf_v4si
+    = build_function_type_list (V4SF_type_node,
+                               V4SF_type_node, V4SI_type_node, NULL_TREE);
+  tree v2df_ftype_v2df_v2di
+    = build_function_type_list (V2DF_type_node,
+                               V2DF_type_node, V2DI_type_node, NULL_TREE);
+
+  /* Integer intrinsics.  */
+  tree uint64_ftype_void
+    = build_function_type (long_long_unsigned_type_node,
+                          void_list_node);
+  tree int_ftype_int
+    = build_function_type_list (integer_type_node,
+                               integer_type_node, NULL_TREE);
+  tree int64_ftype_int64
+    = build_function_type_list (long_long_integer_type_node,
+                               long_long_integer_type_node,
                                NULL_TREE);
-  tree uint64_ftype_uint64_uint64
+  tree uint64_ftype_int
     = build_function_type_list (long_long_unsigned_type_node,
-                               long_long_unsigned_type_node,
-                               long_long_unsigned_type_node,
+                               integer_type_node, NULL_TREE);
+  tree punsigned_type_node = build_pointer_type (unsigned_type_node);
+  tree uint64_ftype_punsigned
+    = build_function_type_list (long_long_unsigned_type_node,
+                               punsigned_type_node, NULL_TREE);
+  tree ushort_ftype_ushort_int
+    = build_function_type_list (short_unsigned_type_node,
+                               short_unsigned_type_node,
+                               integer_type_node,
                                NULL_TREE);
-  tree float_ftype_float
-    = build_function_type_list (float_type_node,
-                               float_type_node,
+  tree uchar_ftype_uchar_int
+    = build_function_type_list (unsigned_char_type_node,
+                               unsigned_char_type_node,
+                               integer_type_node,
                                NULL_TREE);
 
   tree ftype;
 
-  /* The __float80 type.  */
-  if (TYPE_MODE (long_double_type_node) == XFmode)
-    (*lang_hooks.types.register_builtin_type) (long_double_type_node,
-                                              "__float80");
-  else
-    {
-      /* The __float80 type.  */
-      tree float80_type_node = make_node (REAL_TYPE);
-
-      TYPE_PRECISION (float80_type_node) = 80;
-      layout_type (float80_type_node);
-      (*lang_hooks.types.register_builtin_type) (float80_type_node,
-                                                "__float80");
-    }
-
-  if (TARGET_64BIT)
-    {
-      tree float128_type_node = make_node (REAL_TYPE);
-
-      TYPE_PRECISION (float128_type_node) = 128;
-      layout_type (float128_type_node);
-      (*lang_hooks.types.register_builtin_type) (float128_type_node,
-                                                "__float128");
-
-      /* TFmode support builtins.  */
-      ftype = build_function_type (float128_type_node,
-                                  void_list_node);
-      def_builtin (OPTION_MASK_ISA_64BIT, "__builtin_infq", ftype, IX86_BUILTIN_INFQ);
-
-      ftype = build_function_type_list (float128_type_node,
-                                       float128_type_node,
-                                       NULL_TREE);
-      def_builtin_const (OPTION_MASK_ISA_64BIT, "__builtin_fabsq", ftype, IX86_BUILTIN_FABSQ);
-
-      ftype = build_function_type_list (float128_type_node,
-                                       float128_type_node,
-                                       float128_type_node,
-                                       NULL_TREE);
-      def_builtin_const (OPTION_MASK_ISA_64BIT, "__builtin_copysignq", ftype, IX86_BUILTIN_COPYSIGNQ);
-    }
-
   /* Add all special builtins with variable number of operands.  */
   for (i = 0, d = bdesc_special_args;
        i < ARRAY_SIZE (bdesc_special_args);
@@ -19525,9 +23291,30 @@ ix86_init_mmx_sse_builtins (void)
        case VOID_FTYPE_VOID:
          type = void_ftype_void;
          break;
+       case UINT64_FTYPE_VOID:
+         type = uint64_ftype_void;
+         break;
+       case UINT64_FTYPE_PUNSIGNED:
+         type = uint64_ftype_punsigned;
+         break;
+       case V32QI_FTYPE_PCCHAR:
+         type = v32qi_ftype_pcchar;
+         break;
        case V16QI_FTYPE_PCCHAR:
          type = v16qi_ftype_pcchar;
          break;
+       case V8SF_FTYPE_PCV4SF:
+         type = v8sf_ftype_pcv4sf;
+         break;
+       case V8SF_FTYPE_PCFLOAT:
+         type = v8sf_ftype_pcfloat;
+         break;
+       case V4DF_FTYPE_PCV2DF:
+         type = v4df_ftype_pcv2df;
+         break;
+       case V4DF_FTYPE_PCDOUBLE:
+         type = v4df_ftype_pcdouble;
+         break;
        case V4SF_FTYPE_PCFLOAT:
          type = v4sf_ftype_pcfloat;
          break;
@@ -19537,24 +23324,48 @@ ix86_init_mmx_sse_builtins (void)
        case V2DF_FTYPE_PCDOUBLE:
          type = v2df_ftype_pcdouble;
          break;
+       case V8SF_FTYPE_PCV8SF_V8SF:
+         type = v8sf_ftype_pcv8sf_v8sf;
+         break;
+       case V4DF_FTYPE_PCV4DF_V4DF:
+         type = v4df_ftype_pcv4df_v4df;
+         break;
        case V4SF_FTYPE_V4SF_PCV2SF:
          type = v4sf_ftype_v4sf_pcv2sf;
          break;
+       case V4SF_FTYPE_PCV4SF_V4SF:
+         type = v4sf_ftype_pcv4sf_v4sf;
+         break;
        case V2DF_FTYPE_V2DF_PCDOUBLE:
          type = v2df_ftype_v2df_pcdouble;
          break;
+       case V2DF_FTYPE_PCV2DF_V2DF:
+         type = v2df_ftype_pcv2df_v2df;
+         break;
        case VOID_FTYPE_PV2SF_V4SF:
          type = void_ftype_pv2sf_v4sf;
          break;
+       case VOID_FTYPE_PV4DI_V4DI:
+         type = void_ftype_pv4di_v4di;
+         break;
        case VOID_FTYPE_PV2DI_V2DI:
          type = void_ftype_pv2di_v2di;
          break;
+       case VOID_FTYPE_PCHAR_V32QI:
+         type = void_ftype_pchar_v32qi;
+         break;
        case VOID_FTYPE_PCHAR_V16QI:
          type = void_ftype_pchar_v16qi;
          break;
+       case VOID_FTYPE_PFLOAT_V8SF:
+         type = void_ftype_pfloat_v8sf;
+         break;
        case VOID_FTYPE_PFLOAT_V4SF:
          type = void_ftype_pfloat_v4sf;
          break;
+       case VOID_FTYPE_PDOUBLE_V4DF:
+         type = void_ftype_pdouble_v4df;
+         break;
        case VOID_FTYPE_PDOUBLE_V2DF:
          type = void_ftype_pdouble_v2df;
          break;
@@ -19564,6 +23375,18 @@ ix86_init_mmx_sse_builtins (void)
        case VOID_FTYPE_PINT_INT:
          type = void_ftype_pint_int;
          break;
+       case VOID_FTYPE_PV8SF_V8SF_V8SF:
+         type = void_ftype_pv8sf_v8sf_v8sf;
+         break;
+       case VOID_FTYPE_PV4DF_V4DF_V4DF:
+         type = void_ftype_pv4df_v4df_v4df;
+         break;
+       case VOID_FTYPE_PV4SF_V4SF_V4SF:
+         type = void_ftype_pv4sf_v4sf_v4sf;
+         break;
+       case VOID_FTYPE_PV2DF_V2DF_V2DF:
+         type = void_ftype_pv2df_v2df_v2df;
+         break;
        default:
          gcc_unreachable ();
        }
@@ -19586,9 +23409,33 @@ ix86_init_mmx_sse_builtins (void)
        case FLOAT_FTYPE_FLOAT:
          type = float_ftype_float;
          break;
+       case INT_FTYPE_V8SF_V8SF_PTEST:
+         type = int_ftype_v8sf_v8sf;
+         break;
+       case INT_FTYPE_V4DI_V4DI_PTEST:
+         type = int_ftype_v4di_v4di;
+         break;
+       case INT_FTYPE_V4DF_V4DF_PTEST:
+         type = int_ftype_v4df_v4df;
+         break;
+       case INT_FTYPE_V4SF_V4SF_PTEST:
+         type = int_ftype_v4sf_v4sf;
+         break;
        case INT_FTYPE_V2DI_V2DI_PTEST:
          type = int_ftype_v2di_v2di;
          break;
+       case INT_FTYPE_V2DF_V2DF_PTEST:
+         type = int_ftype_v2df_v2df;
+         break;
+       case INT_FTYPE_INT:
+         type = int_ftype_int;
+         break;
+       case UINT64_FTYPE_INT:
+         type = uint64_ftype_int;
+         break;
+       case INT64_FTYPE_INT64:
+         type = int64_ftype_int64;
+         break;
        case INT64_FTYPE_V4SF:
          type = int64_ftype_v4sf;
          break;
@@ -19601,6 +23448,12 @@ ix86_init_mmx_sse_builtins (void)
        case INT_FTYPE_V8QI:
          type = int_ftype_v8qi;
          break;
+       case INT_FTYPE_V8SF:
+         type = int_ftype_v8sf;
+         break;
+       case INT_FTYPE_V4DF:
+         type = int_ftype_v4df;
+         break;
        case INT_FTYPE_V4SF:
          type = int_ftype_v4sf;
          break;
@@ -19610,6 +23463,12 @@ ix86_init_mmx_sse_builtins (void)
        case V16QI_FTYPE_V16QI:
          type = v16qi_ftype_v16qi;
          break;
+       case V8SI_FTYPE_V8SF:
+         type = v8si_ftype_v8sf;
+         break;
+       case V8SI_FTYPE_V4SI:
+         type = v8si_ftype_v4si;
+         break;
        case V8HI_FTYPE_V8HI:
          type = v8hi_ftype_v8hi;
          break;
@@ -19619,12 +23478,27 @@ ix86_init_mmx_sse_builtins (void)
        case V8QI_FTYPE_V8QI:
          type = v8qi_ftype_v8qi;
          break;
+       case V8SF_FTYPE_V8SF:
+         type = v8sf_ftype_v8sf;
+         break;
+       case V8SF_FTYPE_V8SI:
+         type = v8sf_ftype_v8si;
+         break;
+       case V8SF_FTYPE_V4SF:
+         type = v8sf_ftype_v4sf;
+         break;
+       case V4SI_FTYPE_V4DF:
+         type = v4si_ftype_v4df;
+         break;
        case V4SI_FTYPE_V4SI:
          type = v4si_ftype_v4si;
          break;
        case V4SI_FTYPE_V16QI:
          type = v4si_ftype_v16qi;
          break;
+       case V4SI_FTYPE_V8SI:
+         type = v4si_ftype_v8si;
+         break;
        case V4SI_FTYPE_V8HI:
          type = v4si_ftype_v8hi;
          break;
@@ -19637,13 +23511,31 @@ ix86_init_mmx_sse_builtins (void)
        case V4HI_FTYPE_V4HI:
          type = v4hi_ftype_v4hi;
          break;
+       case V4DF_FTYPE_V4DF:
+         type = v4df_ftype_v4df;
+         break;
+       case V4DF_FTYPE_V4SI:
+         type = v4df_ftype_v4si;
+         break;
+       case V4DF_FTYPE_V4SF:
+         type = v4df_ftype_v4sf;
+         break;
+       case V4DF_FTYPE_V2DF:
+         type = v4df_ftype_v2df;
+         break;
        case V4SF_FTYPE_V4SF:
        case V4SF_FTYPE_V4SF_VEC_MERGE:
          type = v4sf_ftype_v4sf;
          break;
+       case V4SF_FTYPE_V8SF:
+         type = v4sf_ftype_v8sf;
+         break;
        case V4SF_FTYPE_V4SI:
          type = v4sf_ftype_v4si;
          break;
+       case V4SF_FTYPE_V4DF:
+         type = v4sf_ftype_v4df;
+         break;
        case V4SF_FTYPE_V2DF:
          type = v4sf_ftype_v2df;
          break;
@@ -19671,6 +23563,9 @@ ix86_init_mmx_sse_builtins (void)
        case V2SI_FTYPE_V2SF:
          type = v2si_ftype_v2sf;
          break;
+       case V2DF_FTYPE_V4DF:
+         type = v2df_ftype_v4df;
+         break;
        case V2DF_FTYPE_V4SF:
          type = v2df_ftype_v4sf;
          break;
@@ -19715,6 +23610,12 @@ ix86_init_mmx_sse_builtins (void)
        case V8HI_FTYPE_V8HI_SI_COUNT:
          type = v8hi_ftype_v8hi_int;
          break;
+       case V8SF_FTYPE_V8SF_V8SF:
+         type = v8sf_ftype_v8sf_v8sf;
+         break;
+       case V8SF_FTYPE_V8SF_V8SI:
+         type = v8sf_ftype_v8sf_v8si;
+         break;
        case V4SI_FTYPE_V4SI_V4SI:
        case V4SI_FTYPE_V4SI_V4SI_COUNT:
          type = v4si_ftype_v4si_v4si;
@@ -19744,10 +23645,19 @@ ix86_init_mmx_sse_builtins (void)
        case V4HI_FTYPE_V4HI_SI_COUNT:
          type = v4hi_ftype_v4hi_int;
          break;
+       case V4DF_FTYPE_V4DF_V4DF:
+         type = v4df_ftype_v4df_v4df;
+         break;
+       case V4DF_FTYPE_V4DF_V4DI:
+         type = v4df_ftype_v4df_v4di;
+         break;
        case V4SF_FTYPE_V4SF_V4SF:
        case V4SF_FTYPE_V4SF_V4SF_SWAP:
          type = v4sf_ftype_v4sf_v4sf;
          break;
+       case V4SF_FTYPE_V4SF_V4SI:
+         type = v4sf_ftype_v4sf_v4si;
+         break;
        case V4SF_FTYPE_V4SF_V2SI:
          type = v4sf_ftype_v4sf_v2si;
          break;
@@ -19799,6 +23709,9 @@ ix86_init_mmx_sse_builtins (void)
        case V2DF_FTYPE_V2DF_V4SF:
          type = v2df_ftype_v2df_v4sf;
          break;
+       case V2DF_FTYPE_V2DF_V2DI:
+         type = v2df_ftype_v2df_v2di;
+         break;
        case V2DF_FTYPE_V2DF_DI:
          type = v2df_ftype_v2df_int64;
          break;
@@ -19833,18 +23746,36 @@ ix86_init_mmx_sse_builtins (void)
        case UINT_FTYPE_UINT_UCHAR:
          type = unsigned_ftype_unsigned_uchar;
          break;
+       case UINT16_FTYPE_UINT16_INT:
+         type = ushort_ftype_ushort_int;
+         break;
+       case UINT8_FTYPE_UINT8_INT:
+         type = uchar_ftype_uchar_int;
+         break;
        case V8HI_FTYPE_V8HI_INT:
          type = v8hi_ftype_v8hi_int;
          break;
+       case V8SF_FTYPE_V8SF_INT:
+         type = v8sf_ftype_v8sf_int;
+         break;
        case V4SI_FTYPE_V4SI_INT:
          type = v4si_ftype_v4si_int;
          break;
+       case V4SI_FTYPE_V8SI_INT:
+         type = v4si_ftype_v8si_int;
+         break;
        case V4HI_FTYPE_V4HI_INT:
          type = v4hi_ftype_v4hi_int;
          break;
+       case V4DF_FTYPE_V4DF_INT:
+         type = v4df_ftype_v4df_int;
+         break;
        case V4SF_FTYPE_V4SF_INT:
          type = v4sf_ftype_v4sf_int;
          break;
+       case V4SF_FTYPE_V8SF_INT:
+         type = v4sf_ftype_v8sf_int;
+         break;
        case V2DI_FTYPE_V2DI_INT:
        case V2DI2TI_FTYPE_V2DI_INT:
          type = v2di_ftype_v2di_int;
@@ -19852,9 +23783,18 @@ ix86_init_mmx_sse_builtins (void)
        case V2DF_FTYPE_V2DF_INT:
          type = v2df_ftype_v2df_int;
          break;
+       case V2DF_FTYPE_V4DF_INT:
+         type = v2df_ftype_v4df_int;
+         break;
        case V16QI_FTYPE_V16QI_V16QI_V16QI:
          type = v16qi_ftype_v16qi_v16qi_v16qi;
          break;
+       case V8SF_FTYPE_V8SF_V8SF_V8SF:
+         type = v8sf_ftype_v8sf_v8sf_v8sf;
+         break;
+       case V4DF_FTYPE_V4DF_V4DF_V4DF:
+         type = v4df_ftype_v4df_v4df_v4df;
+         break;
        case V4SF_FTYPE_V4SF_V4SF_V4SF:
          type = v4sf_ftype_v4sf_v4sf_v4sf;
          break;
@@ -19864,12 +23804,30 @@ ix86_init_mmx_sse_builtins (void)
        case V16QI_FTYPE_V16QI_V16QI_INT:
          type = v16qi_ftype_v16qi_v16qi_int;
          break;
+       case V8SI_FTYPE_V8SI_V8SI_INT:
+         type = v8si_ftype_v8si_v8si_int;
+         break;
+       case V8SI_FTYPE_V8SI_V4SI_INT:
+         type = v8si_ftype_v8si_v4si_int;
+         break;
        case V8HI_FTYPE_V8HI_V8HI_INT:
          type = v8hi_ftype_v8hi_v8hi_int;
          break;
+       case V8SF_FTYPE_V8SF_V8SF_INT:
+         type = v8sf_ftype_v8sf_v8sf_int;
+         break;
+       case V8SF_FTYPE_V8SF_V4SF_INT:
+         type = v8sf_ftype_v8sf_v4sf_int;
+         break;
        case V4SI_FTYPE_V4SI_V4SI_INT:
          type = v4si_ftype_v4si_v4si_int;
          break;
+       case V4DF_FTYPE_V4DF_V4DF_INT:
+         type = v4df_ftype_v4df_v4df_int;
+         break;
+       case V4DF_FTYPE_V4DF_V2DF_INT:
+         type = v4df_ftype_v4df_v2df_int;
+         break;
        case V4SF_FTYPE_V4SF_V4SF_INT:
          type = v4sf_ftype_v4sf_v4sf_int;
          break;
@@ -19945,23 +23903,19 @@ ix86_init_mmx_sse_builtins (void)
   def_builtin (OPTION_MASK_ISA_SSE3, "__builtin_ia32_mwait", void_ftype_unsigned_unsigned, IX86_BUILTIN_MWAIT);
 
   /* AES */
-  if (TARGET_AES)
-    {
-      /* Define AES built-in functions only if AES is enabled.  */
-      def_builtin_const (OPTION_MASK_ISA_SSE2, "__builtin_ia32_aesenc128", v2di_ftype_v2di_v2di, IX86_BUILTIN_AESENC128);
-      def_builtin_const (OPTION_MASK_ISA_SSE2, "__builtin_ia32_aesenclast128", v2di_ftype_v2di_v2di, IX86_BUILTIN_AESENCLAST128);
-      def_builtin_const (OPTION_MASK_ISA_SSE2, "__builtin_ia32_aesdec128", v2di_ftype_v2di_v2di, IX86_BUILTIN_AESDEC128);
-      def_builtin_const (OPTION_MASK_ISA_SSE2, "__builtin_ia32_aesdeclast128", v2di_ftype_v2di_v2di, IX86_BUILTIN_AESDECLAST128);
-      def_builtin_const (OPTION_MASK_ISA_SSE2, "__builtin_ia32_aesimc128", v2di_ftype_v2di, IX86_BUILTIN_AESIMC128);
-      def_builtin_const (OPTION_MASK_ISA_SSE2, "__builtin_ia32_aeskeygenassist128", v2di_ftype_v2di_int, IX86_BUILTIN_AESKEYGENASSIST128);
-    }
+  def_builtin_const (OPTION_MASK_ISA_AES, "__builtin_ia32_aesenc128", v2di_ftype_v2di_v2di, IX86_BUILTIN_AESENC128);
+  def_builtin_const (OPTION_MASK_ISA_AES, "__builtin_ia32_aesenclast128", v2di_ftype_v2di_v2di, IX86_BUILTIN_AESENCLAST128);
+  def_builtin_const (OPTION_MASK_ISA_AES, "__builtin_ia32_aesdec128", v2di_ftype_v2di_v2di, IX86_BUILTIN_AESDEC128);
+  def_builtin_const (OPTION_MASK_ISA_AES, "__builtin_ia32_aesdeclast128", v2di_ftype_v2di_v2di, IX86_BUILTIN_AESDECLAST128);
+  def_builtin_const (OPTION_MASK_ISA_AES, "__builtin_ia32_aesimc128", v2di_ftype_v2di, IX86_BUILTIN_AESIMC128);
+  def_builtin_const (OPTION_MASK_ISA_AES, "__builtin_ia32_aeskeygenassist128", v2di_ftype_v2di_int, IX86_BUILTIN_AESKEYGENASSIST128);
 
   /* PCLMUL */
-  if (TARGET_PCLMUL)
-    {
-      /* Define PCLMUL built-in function only if PCLMUL is enabled.  */
-      def_builtin_const (OPTION_MASK_ISA_SSE2, "__builtin_ia32_pclmulqdq128", v2di_ftype_v2di_v2di_int, IX86_BUILTIN_PCLMULQDQ128);
-    }
+  def_builtin_const (OPTION_MASK_ISA_PCLMUL, "__builtin_ia32_pclmulqdq128", v2di_ftype_v2di_v2di_int, IX86_BUILTIN_PCLMULQDQ128);
+
+  /* AVX */
+  def_builtin (OPTION_MASK_ISA_AVX, "__builtin_ia32_vzeroupper", void_ftype_void,
+              TARGET_64BIT ? IX86_BUILTIN_VZEROUPPER_REX64 : IX86_BUILTIN_VZEROUPPER);
 
   /* Access to the vec_init patterns.  */
   ftype = build_function_type_list (V2SI_type_node, integer_type_node,
@@ -20112,11 +24066,118 @@ ix86_init_mmx_sse_builtins (void)
     }
 }
 
+/* Internal method for ix86_init_builtins.  */
+
+static void
+ix86_init_builtins_va_builtins_abi (void)
+{
+  tree ms_va_ref, sysv_va_ref;
+  tree fnvoid_va_end_ms, fnvoid_va_end_sysv;
+  tree fnvoid_va_start_ms, fnvoid_va_start_sysv;
+  tree fnvoid_va_copy_ms, fnvoid_va_copy_sysv;
+  tree fnattr_ms = NULL_TREE, fnattr_sysv = NULL_TREE;
+
+  if (!TARGET_64BIT)
+    return;
+  fnattr_ms = build_tree_list (get_identifier ("ms_abi"), NULL_TREE);
+  fnattr_sysv = build_tree_list (get_identifier ("sysv_abi"), NULL_TREE);
+  ms_va_ref = build_reference_type (ms_va_list_type_node);
+  sysv_va_ref =
+    build_pointer_type (TREE_TYPE (sysv_va_list_type_node));
+
+  fnvoid_va_end_ms =
+    build_function_type_list (void_type_node, ms_va_ref, NULL_TREE);
+  fnvoid_va_start_ms =
+    build_varargs_function_type_list (void_type_node, ms_va_ref, NULL_TREE);
+  fnvoid_va_end_sysv =
+    build_function_type_list (void_type_node, sysv_va_ref, NULL_TREE);
+  fnvoid_va_start_sysv =
+    build_varargs_function_type_list (void_type_node, sysv_va_ref,
+                                      NULL_TREE);
+  fnvoid_va_copy_ms =
+    build_function_type_list (void_type_node, ms_va_ref, ms_va_list_type_node,
+                             NULL_TREE);
+  fnvoid_va_copy_sysv =
+    build_function_type_list (void_type_node, sysv_va_ref,
+                             sysv_va_ref, NULL_TREE);
+
+  add_builtin_function ("__builtin_ms_va_start", fnvoid_va_start_ms,
+                       BUILT_IN_VA_START, BUILT_IN_NORMAL, NULL, fnattr_ms);
+  add_builtin_function ("__builtin_ms_va_end", fnvoid_va_end_ms,
+                       BUILT_IN_VA_END, BUILT_IN_NORMAL, NULL, fnattr_ms);
+  add_builtin_function ("__builtin_ms_va_copy", fnvoid_va_copy_ms,
+                       BUILT_IN_VA_COPY, BUILT_IN_NORMAL, NULL, fnattr_ms);
+  add_builtin_function ("__builtin_sysv_va_start", fnvoid_va_start_sysv,
+                       BUILT_IN_VA_START, BUILT_IN_NORMAL, NULL, fnattr_sysv);
+  add_builtin_function ("__builtin_sysv_va_end", fnvoid_va_end_sysv,
+                       BUILT_IN_VA_END, BUILT_IN_NORMAL, NULL, fnattr_sysv);
+  add_builtin_function ("__builtin_sysv_va_copy", fnvoid_va_copy_sysv,
+                       BUILT_IN_VA_COPY, BUILT_IN_NORMAL, NULL, fnattr_sysv);
+}
+
 static void
 ix86_init_builtins (void)
 {
-  if (TARGET_MMX)
-    ix86_init_mmx_sse_builtins ();
+  tree float128_type_node = make_node (REAL_TYPE);
+  tree ftype, decl;
+
+  /* The __float80 type.  */
+  if (TYPE_MODE (long_double_type_node) == XFmode)
+    (*lang_hooks.types.register_builtin_type) (long_double_type_node,
+                                              "__float80");
+  else
+    {
+      /* The __float80 type.  */
+      tree float80_type_node = make_node (REAL_TYPE);
+
+      TYPE_PRECISION (float80_type_node) = 80;
+      layout_type (float80_type_node);
+      (*lang_hooks.types.register_builtin_type) (float80_type_node,
+                                                "__float80");
+    }
+
+  /* The __float128 type.  */
+  TYPE_PRECISION (float128_type_node) = 128;
+  layout_type (float128_type_node);
+  (*lang_hooks.types.register_builtin_type) (float128_type_node,
+                                            "__float128");
+
+  /* TFmode support builtins.  */
+  ftype = build_function_type (float128_type_node, void_list_node);
+  decl = add_builtin_function ("__builtin_infq", ftype,
+                              IX86_BUILTIN_INFQ, BUILT_IN_MD,
+                              NULL, NULL_TREE);
+  ix86_builtins[(int) IX86_BUILTIN_INFQ] = decl;
+
+  decl = add_builtin_function ("__builtin_huge_valq", ftype,
+                              IX86_BUILTIN_HUGE_VALQ, BUILT_IN_MD,
+                              NULL, NULL_TREE);
+  ix86_builtins[(int) IX86_BUILTIN_HUGE_VALQ] = decl;
+
+  /* We will expand them to normal call if SSE2 isn't available since
+     they are used by libgcc. */
+  ftype = build_function_type_list (float128_type_node,
+                                   float128_type_node,
+                                   NULL_TREE);
+  decl = add_builtin_function ("__builtin_fabsq", ftype,
+                              IX86_BUILTIN_FABSQ, BUILT_IN_MD,
+                              "__fabstf2", NULL_TREE);
+  ix86_builtins[(int) IX86_BUILTIN_FABSQ] = decl;
+  TREE_READONLY (decl) = 1;
+
+  ftype = build_function_type_list (float128_type_node,
+                                   float128_type_node,
+                                   float128_type_node,
+                                   NULL_TREE);
+  decl = add_builtin_function ("__builtin_copysignq", ftype,
+                              IX86_BUILTIN_COPYSIGNQ, BUILT_IN_MD,
+                              "__copysigntf3", NULL_TREE);
+  ix86_builtins[(int) IX86_BUILTIN_COPYSIGNQ] = decl;
+  TREE_READONLY (decl) = 1;
+
+  ix86_init_mmx_sse_builtins ();
+  if (TARGET_64BIT)
+    ix86_init_builtins_va_builtins_abi ();
 }
 
 /* Errors in the source file can cause expand_expr to return const0_rtx
@@ -20180,7 +24241,7 @@ ix86_expand_binop_builtin (enum insn_code icode, tree exp, rtx target)
 static rtx
 ix86_expand_multi_arg_builtin (enum insn_code icode, tree exp, rtx target,
                               enum multi_arg_type m_type,
-                              enum insn_code sub_code)
+                              enum rtx_code sub_code)
 {
   rtx pat;
   int i;
@@ -20286,7 +24347,7 @@ ix86_expand_multi_arg_builtin (enum insn_code icode, tree exp, rtx target,
 
       if (last_arg_constant && i == nargs-1)
        {
-         if (GET_CODE (op) != CONST_INT)
+         if (!CONST_INT_P (op))
            {
              error ("last argument must be an immediate");
              return gen_reg_rtx (tmode);
@@ -20761,28 +24822,51 @@ ix86_expand_args_builtin (const struct builtin_description *d,
 
   switch ((enum ix86_builtin_type) d->flag)
     {
+    case INT_FTYPE_V8SF_V8SF_PTEST:
+    case INT_FTYPE_V4DI_V4DI_PTEST:
+    case INT_FTYPE_V4DF_V4DF_PTEST:
+    case INT_FTYPE_V4SF_V4SF_PTEST:
     case INT_FTYPE_V2DI_V2DI_PTEST:
+    case INT_FTYPE_V2DF_V2DF_PTEST:
       return ix86_expand_sse_ptest (d, exp, target);
     case FLOAT128_FTYPE_FLOAT128:
     case FLOAT_FTYPE_FLOAT:
+    case INT_FTYPE_INT:
+    case UINT64_FTYPE_INT:
+    case INT64_FTYPE_INT64:
     case INT64_FTYPE_V4SF:
     case INT64_FTYPE_V2DF:
     case INT_FTYPE_V16QI:
     case INT_FTYPE_V8QI:
+    case INT_FTYPE_V8SF:
+    case INT_FTYPE_V4DF:
     case INT_FTYPE_V4SF:
     case INT_FTYPE_V2DF:
     case V16QI_FTYPE_V16QI:
+    case V8SI_FTYPE_V8SF:
+    case V8SI_FTYPE_V4SI:
     case V8HI_FTYPE_V8HI:
     case V8HI_FTYPE_V16QI:
     case V8QI_FTYPE_V8QI:
+    case V8SF_FTYPE_V8SF:
+    case V8SF_FTYPE_V8SI:
+    case V8SF_FTYPE_V4SF:
     case V4SI_FTYPE_V4SI:
     case V4SI_FTYPE_V16QI:
     case V4SI_FTYPE_V4SF:
+    case V4SI_FTYPE_V8SI:
     case V4SI_FTYPE_V8HI:
+    case V4SI_FTYPE_V4DF:
     case V4SI_FTYPE_V2DF:
     case V4HI_FTYPE_V4HI:
+    case V4DF_FTYPE_V4DF:
+    case V4DF_FTYPE_V4SI:
+    case V4DF_FTYPE_V4SF:
+    case V4DF_FTYPE_V2DF:
     case V4SF_FTYPE_V4SF:
     case V4SF_FTYPE_V4SI:
+    case V4SF_FTYPE_V8SF:
+    case V4SF_FTYPE_V4DF:
     case V4SF_FTYPE_V2DF:
     case V2DI_FTYPE_V2DI:
     case V2DI_FTYPE_V16QI:
@@ -20790,6 +24874,7 @@ ix86_expand_args_builtin (const struct builtin_description *d,
     case V2DI_FTYPE_V4SI:
     case V2DF_FTYPE_V2DF:
     case V2DF_FTYPE_V4SI:
+    case V2DF_FTYPE_V4DF:
     case V2DF_FTYPE_V4SF:
     case V2DF_FTYPE_V2SI:
     case V2SI_FTYPE_V2SI:
@@ -20811,6 +24896,8 @@ ix86_expand_args_builtin (const struct builtin_description *d,
     case V8HI_FTYPE_V8HI_V8HI:
     case V8HI_FTYPE_V16QI_V16QI:
     case V8HI_FTYPE_V4SI_V4SI:
+    case V8SF_FTYPE_V8SF_V8SF:
+    case V8SF_FTYPE_V8SF_V8SI:
     case V4SI_FTYPE_V4SI_V4SI:
     case V4SI_FTYPE_V8HI_V8HI:
     case V4SI_FTYPE_V4SF_V4SF:
@@ -20818,7 +24905,10 @@ ix86_expand_args_builtin (const struct builtin_description *d,
     case V4HI_FTYPE_V4HI_V4HI:
     case V4HI_FTYPE_V8QI_V8QI:
     case V4HI_FTYPE_V2SI_V2SI:
+    case V4DF_FTYPE_V4DF_V4DF:
+    case V4DF_FTYPE_V4DF_V4DI:
     case V4SF_FTYPE_V4SF_V4SF:
+    case V4SF_FTYPE_V4SF_V4SI:
     case V4SF_FTYPE_V4SF_V2SI:
     case V4SF_FTYPE_V4SF_V2DF:
     case V4SF_FTYPE_V4SF_DI:
@@ -20833,6 +24923,7 @@ ix86_expand_args_builtin (const struct builtin_description *d,
     case V2SI_FTYPE_V2SF_V2SF:
     case V2DF_FTYPE_V2DF_V2DF:
     case V2DF_FTYPE_V2DF_V4SF:
+    case V2DF_FTYPE_V2DF_V2DI:
     case V2DF_FTYPE_V2DF_DI:
     case V2DF_FTYPE_V2DF_SI:
     case V2SF_FTYPE_V2SF_V2SF:
@@ -20868,6 +24959,8 @@ ix86_expand_args_builtin (const struct builtin_description *d,
     case UINT_FTYPE_UINT_UINT:
     case UINT_FTYPE_UINT_USHORT:
     case UINT_FTYPE_UINT_UCHAR:
+    case UINT16_FTYPE_UINT16_INT:
+    case UINT8_FTYPE_UINT8_INT:
       nargs = 2;
       break;
     case V2DI2TI_FTYPE_V2DI_INT:
@@ -20876,22 +24969,35 @@ ix86_expand_args_builtin (const struct builtin_description *d,
       nargs_constant = 1;
       break;
     case V8HI_FTYPE_V8HI_INT:
+    case V8SF_FTYPE_V8SF_INT:
     case V4SI_FTYPE_V4SI_INT:
+    case V4SI_FTYPE_V8SI_INT:
     case V4HI_FTYPE_V4HI_INT:
+    case V4DF_FTYPE_V4DF_INT:
     case V4SF_FTYPE_V4SF_INT:
+    case V4SF_FTYPE_V8SF_INT:
     case V2DI_FTYPE_V2DI_INT:
     case V2DF_FTYPE_V2DF_INT:
+    case V2DF_FTYPE_V4DF_INT:
       nargs = 2;
       nargs_constant = 1;
       break;
     case V16QI_FTYPE_V16QI_V16QI_V16QI:
+    case V8SF_FTYPE_V8SF_V8SF_V8SF:
+    case V4DF_FTYPE_V4DF_V4DF_V4DF:
     case V4SF_FTYPE_V4SF_V4SF_V4SF:
     case V2DF_FTYPE_V2DF_V2DF_V2DF:
       nargs = 3;
       break;
     case V16QI_FTYPE_V16QI_V16QI_INT:
     case V8HI_FTYPE_V8HI_V8HI_INT:
+    case V8SI_FTYPE_V8SI_V8SI_INT:
+    case V8SI_FTYPE_V8SI_V4SI_INT:
+    case V8SF_FTYPE_V8SF_V8SF_INT: 
+    case V8SF_FTYPE_V8SF_V4SF_INT: 
     case V4SI_FTYPE_V4SI_V4SI_INT:
+    case V4DF_FTYPE_V4DF_V4DF_INT:
+    case V4DF_FTYPE_V4DF_V2DF_INT:
     case V4SF_FTYPE_V4SF_V4SF_INT:
     case V2DI_FTYPE_V2DI_V2DI_INT:
     case V2DF_FTYPE_V2DF_V2DF_INT:
@@ -20972,13 +25078,36 @@ ix86_expand_args_builtin (const struct builtin_description *d,
              case CODE_FOR_sse4_1_roundsd:
              case CODE_FOR_sse4_1_roundss:
              case CODE_FOR_sse4_1_blendps:
+             case CODE_FOR_avx_blendpd256:
+             case CODE_FOR_avx_vpermilv4df:
+             case CODE_FOR_avx_roundpd256:
+             case CODE_FOR_avx_roundps256:
                error ("the last argument must be a 4-bit immediate");
                return const0_rtx;
 
              case CODE_FOR_sse4_1_blendpd:
+             case CODE_FOR_avx_vpermilv2df:
                error ("the last argument must be a 2-bit immediate");
                return const0_rtx;
 
+             case CODE_FOR_avx_vextractf128v4df:
+             case CODE_FOR_avx_vextractf128v8sf:
+             case CODE_FOR_avx_vextractf128v8si:
+             case CODE_FOR_avx_vinsertf128v4df:
+             case CODE_FOR_avx_vinsertf128v8sf:
+             case CODE_FOR_avx_vinsertf128v8si:
+               error ("the last argument must be a 1-bit immediate");
+               return const0_rtx;
+
+             case CODE_FOR_avx_cmpsdv2df3:
+             case CODE_FOR_avx_cmpssv4sf3:
+             case CODE_FOR_avx_cmppdv2df3:
+             case CODE_FOR_avx_cmppsv4sf3:
+             case CODE_FOR_avx_cmppdv4df3:
+             case CODE_FOR_avx_cmppsv8sf3:
+               error ("the last argument must be a 5-bit immediate");
+               return const0_rtx;
+
             default:
                switch (nargs_constant)
                  {
@@ -21069,46 +25198,78 @@ ix86_expand_special_args_builtin (const struct builtin_description *d,
   bool last_arg_constant = false;
   const struct insn_data *insn_p = &insn_data[icode];
   enum machine_mode tmode = insn_p->operand[0].mode;
-  enum { load, store } class;
+  enum { load, store } klass;
 
   switch ((enum ix86_special_builtin_type) d->flag)
     {
     case VOID_FTYPE_VOID:
       emit_insn (GEN_FCN (icode) (target));
       return 0;
+    case UINT64_FTYPE_VOID:
+      nargs = 0;
+      klass = load;
+      memory = 0;
+      break;
+    case UINT64_FTYPE_PUNSIGNED:
     case V2DI_FTYPE_PV2DI:
+    case V32QI_FTYPE_PCCHAR:
     case V16QI_FTYPE_PCCHAR:
+    case V8SF_FTYPE_PCV4SF:
+    case V8SF_FTYPE_PCFLOAT:
     case V4SF_FTYPE_PCFLOAT:
+    case V4DF_FTYPE_PCV2DF:
+    case V4DF_FTYPE_PCDOUBLE:
     case V2DF_FTYPE_PCDOUBLE:
       nargs = 1;
-      class = load;
+      klass = load;
       memory = 0;
       break;
     case VOID_FTYPE_PV2SF_V4SF:
+    case VOID_FTYPE_PV4DI_V4DI:
     case VOID_FTYPE_PV2DI_V2DI:
+    case VOID_FTYPE_PCHAR_V32QI:
     case VOID_FTYPE_PCHAR_V16QI:
+    case VOID_FTYPE_PFLOAT_V8SF:
     case VOID_FTYPE_PFLOAT_V4SF:
+    case VOID_FTYPE_PDOUBLE_V4DF:
     case VOID_FTYPE_PDOUBLE_V2DF:
     case VOID_FTYPE_PDI_DI:
     case VOID_FTYPE_PINT_INT:
       nargs = 1;
-      class = store;
+      klass = store;
       /* Reserve memory operand for target.  */
       memory = ARRAY_SIZE (args);
       break;
     case V4SF_FTYPE_V4SF_PCV2SF:
     case V2DF_FTYPE_V2DF_PCDOUBLE:
       nargs = 2;
-      class = load;
+      klass = load;
       memory = 1;
       break;
+    case V8SF_FTYPE_PCV8SF_V8SF:
+    case V4DF_FTYPE_PCV4DF_V4DF:
+    case V4SF_FTYPE_PCV4SF_V4SF:
+    case V2DF_FTYPE_PCV2DF_V2DF:
+      nargs = 2;
+      klass = load;
+      memory = 0;
+      break;
+    case VOID_FTYPE_PV8SF_V8SF_V8SF:
+    case VOID_FTYPE_PV4DF_V4DF_V4DF:
+    case VOID_FTYPE_PV4SF_V4SF_V4SF:
+    case VOID_FTYPE_PV2DF_V2DF_V2DF:
+      nargs = 2;
+      klass = store;
+      /* Reserve memory operand for target.  */
+      memory = ARRAY_SIZE (args);
+      break;
     default:
       gcc_unreachable ();
     }
 
   gcc_assert (nargs <= ARRAY_SIZE (args));
 
-  if (class == store)
+  if (klass == store)
     {
       arg = CALL_EXPR_ARG (exp, 0);
       op = expand_normal (arg);
@@ -21172,6 +25333,9 @@ ix86_expand_special_args_builtin (const struct builtin_description *d,
 
   switch (nargs)
     {
+    case 0:
+      pat = GEN_FCN (icode) (target);
+      break;
     case 1:
       pat = GEN_FCN (icode) (target, args[0].op);
       break;
@@ -21185,7 +25349,7 @@ ix86_expand_special_args_builtin (const struct builtin_description *d,
   if (! pat)
     return 0;
   emit_insn (pat);
-  return class == store ? 0 : target;
+  return klass == store ? 0 : target;
 }
 
 /* Return the integer constant in ARG.  Constrain it to be in the range
@@ -21330,6 +25494,28 @@ ix86_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
   enum machine_mode mode0, mode1, mode2;
   unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
 
+  /* Determine whether the builtin function is available under the current ISA.
+     Originally the builtin was not created if it wasn't applicable to the
+     current ISA based on the command line switches.  With function specific
+     options, we need to check in the context of the function making the call
+     whether it is supported.  */
+  if (ix86_builtins_isa[fcode].isa
+      && !(ix86_builtins_isa[fcode].isa & ix86_isa_flags))
+    {
+      char *opts = ix86_target_string (ix86_builtins_isa[fcode].isa, 0, NULL,
+                                      NULL, NULL, false);
+
+      if (!opts)
+       error ("%qE needs unknown isa option", fndecl);
+      else
+       {
+         gcc_assert (opts != NULL);
+         error ("%qE needs isa option %s", fndecl, opts);
+         free (opts);
+       }
+      return const0_rtx;
+    }
+
   switch (fcode)
     {
     case IX86_BUILTIN_MASKMOVQ:
@@ -21398,10 +25584,7 @@ ix86_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
        op1 = copy_to_mode_reg (SImode, op1);
       if (!REG_P (op2))
        op2 = copy_to_mode_reg (SImode, op2);
-      if (!TARGET_64BIT)
-       emit_insn (gen_sse3_monitor (op0, op1, op2));
-      else
-       emit_insn (gen_sse3_monitor64 (op0, op1, op2));
+      emit_insn ((*ix86_gen_monitor) (op0, op1, op2));
       return 0;
 
     case IX86_BUILTIN_MWAIT:
@@ -21440,6 +25623,7 @@ ix86_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
       return ix86_expand_vec_set_builtin (exp);
 
     case IX86_BUILTIN_INFQ:
+    case IX86_BUILTIN_HUGE_VALQ:
       {
        REAL_VALUE_TYPE inf;
        rtx tmp;
@@ -21470,7 +25654,16 @@ ix86_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
        i < ARRAY_SIZE (bdesc_args);
        i++, d++)
     if (d->code == fcode)
-      return ix86_expand_args_builtin (d, exp, target);
+      switch (fcode)
+       {
+       case IX86_BUILTIN_FABSQ:
+       case IX86_BUILTIN_COPYSIGNQ:
+         if (!TARGET_SSE2)
+           /* Emit a normal call if SSE2 isn't available.  */
+           return expand_call (exp, target, ignore);
+       default:
+         return ix86_expand_args_builtin (d, exp, target);
+       }
 
   for (i = 0, d = bdesc_comi; i < ARRAY_SIZE (bdesc_comi); i++, d++)
     if (d->code == fcode)
@@ -21543,13 +25736,26 @@ ix86_builtin_vectorized_function (unsigned int fn, tree type_out,
        return ix86_builtins[IX86_BUILTIN_CVTPS2DQ];
       break;
 
+    case BUILT_IN_COPYSIGN:
+      if (out_mode == DFmode && out_n == 2
+         && in_mode == DFmode && in_n == 2)
+       return ix86_builtins[IX86_BUILTIN_CPYSGNPD];
+      break;
+
+    case BUILT_IN_COPYSIGNF:
+      if (out_mode == SFmode && out_n == 4
+         && in_mode == SFmode && in_n == 4)
+       return ix86_builtins[IX86_BUILTIN_CPYSGNPS];
+      break;
+
     default:
       ;
     }
 
   /* Dispatch to a handler for a vectorization library.  */
   if (ix86_veclib_handler)
-    return (*ix86_veclib_handler)(fn, type_out, type_in);
+    return (*ix86_veclib_handler) ((enum built_in_function) fn, type_out,
+                                  type_in);
 
   return NULL_TREE;
 }
@@ -21657,7 +25863,8 @@ ix86_veclibabi_svml (enum built_in_function fn, tree type_out, tree type_in)
     fntype = build_function_type_list (type_out, type_in, type_in, NULL);
 
   /* Build a function declaration for the vectorized function.  */
-  new_fndecl = build_decl (FUNCTION_DECL, get_identifier (name), fntype);
+  new_fndecl = build_decl (BUILTINS_LOCATION,
+                          FUNCTION_DECL, get_identifier (name), fntype);
   TREE_PUBLIC (new_fndecl) = 1;
   DECL_EXTERNAL (new_fndecl) = 1;
   DECL_IS_NOVOPS (new_fndecl) = 1;
@@ -21741,7 +25948,8 @@ ix86_veclibabi_acml (enum built_in_function fn, tree type_out, tree type_in)
     fntype = build_function_type_list (type_out, type_in, type_in, NULL);
 
   /* Build a function declaration for the vectorized function.  */
-  new_fndecl = build_decl (FUNCTION_DECL, get_identifier (name), fntype);
+  new_fndecl = build_decl (BUILTINS_LOCATION,
+                          FUNCTION_DECL, get_identifier (name), fntype);
   TREE_PUBLIC (new_fndecl) = 1;
   DECL_EXTERNAL (new_fndecl) = 1;
   DECL_IS_NOVOPS (new_fndecl) = 1;
@@ -21751,8 +25959,10 @@ ix86_veclibabi_acml (enum built_in_function fn, tree type_out, tree type_in)
 }
 
 
-/* Returns a decl of a function that implements conversion of the
-   input vector of type TYPE, or NULL_TREE if it is not available.  */
+/* Returns a decl of a function that implements conversion of an integer vector
+   into a floating-point vector, or vice-versa. TYPE is the type of the integer
+   side of the conversion.
+   Return NULL_TREE if it is not available.  */
 
 static tree
 ix86_vectorize_builtin_conversion (unsigned int code, tree type)
@@ -21766,7 +25976,9 @@ ix86_vectorize_builtin_conversion (unsigned int code, tree type)
       switch (TYPE_MODE (type))
        {
        case V4SImode:
-         return ix86_builtins[IX86_BUILTIN_CVTDQ2PS];
+         return TYPE_UNSIGNED (type)
+           ? ix86_builtins[IX86_BUILTIN_CVTUDQ2PS]
+           : ix86_builtins[IX86_BUILTIN_CVTDQ2PS];
        default:
          return NULL_TREE;
        }
@@ -21774,8 +25986,10 @@ ix86_vectorize_builtin_conversion (unsigned int code, tree type)
     case FIX_TRUNC_EXPR:
       switch (TYPE_MODE (type))
        {
-       case V4SFmode:
-         return ix86_builtins[IX86_BUILTIN_CVTTPS2DQ];
+       case V4SImode:
+         return TYPE_UNSIGNED (type)
+           ? NULL_TREE
+           : ix86_builtins[IX86_BUILTIN_CVTTPS2DQ];
        default:
          return NULL_TREE;
        }
@@ -21792,7 +26006,7 @@ static tree
 ix86_builtin_reciprocal (unsigned int fn, bool md_fn,
                         bool sqrt ATTRIBUTE_UNUSED)
 {
-  if (! (TARGET_SSE_MATH && TARGET_RECIP && !optimize_size
+  if (! (TARGET_SSE_MATH && TARGET_RECIP && !optimize_insn_for_size_p ()
         && flag_finite_math_only && !flag_trapping_math
         && flag_unsafe_math_optimizations))
     return NULL_TREE;
@@ -21829,7 +26043,7 @@ ix86_force_to_memory (enum machine_mode mode, rtx operand)
   rtx result;
 
   gcc_assert (reload_completed);
-  if (TARGET_RED_ZONE)
+  if (!TARGET_64BIT_MS_ABI && TARGET_RED_ZONE)
     {
       result = gen_rtx_MEM (mode,
                            gen_rtx_PLUS (Pmode,
@@ -21837,7 +26051,7 @@ ix86_force_to_memory (enum machine_mode mode, rtx operand)
                                          GEN_INT (-RED_ZONE_SIZE)));
       emit_move_insn (result, operand);
     }
-  else if (!TARGET_RED_ZONE && TARGET_64BIT)
+  else if ((TARGET_64BIT_MS_ABI || !TARGET_RED_ZONE) && TARGET_64BIT)
     {
       switch (mode)
        {
@@ -21904,7 +26118,7 @@ ix86_force_to_memory (enum machine_mode mode, rtx operand)
 void
 ix86_free_from_memory (enum machine_mode mode)
 {
-  if (!TARGET_RED_ZONE)
+  if (!TARGET_RED_ZONE || TARGET_64BIT_MS_ABI)
     {
       int size;
 
@@ -21920,6 +26134,22 @@ ix86_free_from_memory (enum machine_mode mode)
     }
 }
 
+/* Implement TARGET_IRA_COVER_CLASSES.  If -mfpmath=sse, we prefer
+   SSE_REGS to FLOAT_REGS if their costs for a pseudo are the
+   same.  */
+static const enum reg_class *
+i386_ira_cover_classes (void)
+{
+  static const enum reg_class sse_fpmath_classes[] = {
+    GENERAL_REGS, SSE_REGS, MMX_REGS, FLOAT_REGS, LIM_REG_CLASSES
+  };
+  static const enum reg_class no_sse_fpmath_classes[] = {
+    GENERAL_REGS, FLOAT_REGS, MMX_REGS, SSE_REGS, LIM_REG_CLASSES
+  };
+
+ return TARGET_SSE_MATH ? sse_fpmath_classes : no_sse_fpmath_classes;
+}
+
 /* Put float CONST_DOUBLE in the constant pool instead of fp regs.
    QImode must go into class Q_REGS.
    Narrow ALL_REGS to GENERAL_REGS.  This supports allowing movsf and
@@ -22024,14 +26254,16 @@ ix86_preferred_output_reload_class (rtx x, enum reg_class regclass)
 }
 
 static enum reg_class
-ix86_secondary_reload (bool in_p, rtx x, enum reg_class class,
+ix86_secondary_reload (bool in_p, rtx x, enum reg_class rclass,
                       enum machine_mode mode,
                       secondary_reload_info *sri ATTRIBUTE_UNUSED)
 {
   /* QImode spills from non-QI registers require
      intermediate register on 32bit targets.  */
-  if (!in_p && mode == QImode && class == NON_Q_REGS
-      && !TARGET_64BIT)
+  if (!in_p && mode == QImode && !TARGET_64BIT
+      && (rclass == GENERAL_REGS
+         || rclass == LEGACY_REGS
+         || rclass == INDEX_REGS))
     {
       int regno;
 
@@ -22236,7 +26468,8 @@ inline_memory_move_cost (enum machine_mode mode, enum reg_class regclass,
          {
            if (!in)
              return ix86_cost->int_store[0];
-           if (TARGET_PARTIAL_REG_DEPENDENCY && !optimize_size)
+           if (TARGET_PARTIAL_REG_DEPENDENCY
+               && optimize_function_for_speed_p (cfun))
              cost = ix86_cost->movzbl_load;
            else
              cost = ix86_cost->int_load[0];
@@ -22356,8 +26589,11 @@ ix86_hard_regno_mode_ok (int regno, enum machine_mode mode)
     {
       /* We implement the move patterns for all vector modes into and
         out of SSE registers, even when no operation instructions
-        are available.  */
-      return (VALID_SSE_REG_MODE (mode)
+        are available.  OImode move is available only when AVX is
+        enabled.  */
+      return ((TARGET_AVX && mode == OImode)
+             || VALID_AVX256_REG_MODE (mode)
+             || VALID_SSE_REG_MODE (mode)
              || VALID_SSE2_REG_MODE (mode)
              || VALID_MMX_REG_MODE (mode)
              || VALID_MMX_REG_MODE_3DNOW (mode));
@@ -22375,7 +26611,7 @@ ix86_hard_regno_mode_ok (int regno, enum machine_mode mode)
     {
       /* Take care for QImode values - they can be in non-QI regs,
         but then they do cause partial register stalls.  */
-      if (regno < 4 || TARGET_64BIT)
+      if (regno <= BX_REG || TARGET_64BIT)
        return 1;
       if (!TARGET_PARTIAL_REG_STALL)
        return 1;
@@ -22468,10 +26704,11 @@ ix86_modes_tieable_p (enum machine_mode mode1, enum machine_mode mode2)
    scanned.  In either case, *TOTAL contains the cost result.  */
 
 static bool
-ix86_rtx_costs (rtx x, int code, int outer_code_i, int *total)
+ix86_rtx_costs (rtx x, int code, int outer_code_i, int *total, bool speed)
 {
   enum rtx_code outer_code = (enum rtx_code) outer_code_i;
   enum machine_mode mode = GET_MODE (x);
+  const struct processor_costs *cost = speed ? ix86_cost : &ix86_size_cost;
 
   switch (code)
     {
@@ -22523,13 +26760,13 @@ ix86_rtx_costs (rtx x, int code, int outer_code_i, int *total)
          && GET_MODE (XEXP (x, 0)) == SImode)
        *total = 1;
       else if (TARGET_ZERO_EXTEND_WITH_AND)
-       *total = ix86_cost->add;
+       *total = cost->add;
       else
-       *total = ix86_cost->movzx;
+       *total = cost->movzx;
       return false;
 
     case SIGN_EXTEND:
-      *total = ix86_cost->movsx;
+      *total = cost->movsx;
       return false;
 
     case ASHIFT:
@@ -22539,13 +26776,13 @@ ix86_rtx_costs (rtx x, int code, int outer_code_i, int *total)
          HOST_WIDE_INT value = INTVAL (XEXP (x, 1));
          if (value == 1)
            {
-             *total = ix86_cost->add;
+             *total = cost->add;
              return false;
            }
          if ((value == 2 || value == 3)
-             && ix86_cost->lea <= ix86_cost->shift_const)
+             && cost->lea <= cost->shift_const)
            {
-             *total = ix86_cost->lea;
+             *total = cost->lea;
              return false;
            }
        }
@@ -22560,24 +26797,24 @@ ix86_rtx_costs (rtx x, int code, int outer_code_i, int *total)
          if (CONST_INT_P (XEXP (x, 1)))
            {
              if (INTVAL (XEXP (x, 1)) > 32)
-               *total = ix86_cost->shift_const + COSTS_N_INSNS (2);
+               *total = cost->shift_const + COSTS_N_INSNS (2);
              else
-               *total = ix86_cost->shift_const * 2;
+               *total = cost->shift_const * 2;
            }
          else
            {
              if (GET_CODE (XEXP (x, 1)) == AND)
-               *total = ix86_cost->shift_var * 2;
+               *total = cost->shift_var * 2;
              else
-               *total = ix86_cost->shift_var * 6 + COSTS_N_INSNS (2);
+               *total = cost->shift_var * 6 + COSTS_N_INSNS (2);
            }
        }
       else
        {
          if (CONST_INT_P (XEXP (x, 1)))
-           *total = ix86_cost->shift_const;
+           *total = cost->shift_const;
          else
-           *total = ix86_cost->shift_var;
+           *total = cost->shift_var;
        }
       return false;
 
@@ -22585,18 +26822,18 @@ ix86_rtx_costs (rtx x, int code, int outer_code_i, int *total)
       if (SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH)
        {
          /* ??? SSE scalar cost should be used here.  */
-         *total = ix86_cost->fmul;
+         *total = cost->fmul;
          return false;
        }
       else if (X87_FLOAT_MODE_P (mode))
        {
-         *total = ix86_cost->fmul;
+         *total = cost->fmul;
          return false;
        }
       else if (FLOAT_MODE_P (mode))
        {
          /* ??? SSE vector cost should be used here.  */
-         *total = ix86_cost->fmul;
+         *total = cost->fmul;
          return false;
        }
       else
@@ -22637,9 +26874,9 @@ ix86_rtx_costs (rtx x, int code, int outer_code_i, int *total)
                op0 = XEXP (op0, 0), mode = GET_MODE (op0);
            }
 
-         *total = (ix86_cost->mult_init[MODE_INDEX (mode)]
-                   + nbits * ix86_cost->mult_bit
-                   + rtx_cost (op0, outer_code) + rtx_cost (op1, outer_code));
+         *total = (cost->mult_init[MODE_INDEX (mode)]
+                   + nbits * cost->mult_bit
+                   + rtx_cost (op0, outer_code, speed) + rtx_cost (op1, outer_code, speed));
 
           return true;
        }
@@ -22650,14 +26887,14 @@ ix86_rtx_costs (rtx x, int code, int outer_code_i, int *total)
     case UMOD:
       if (SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH)
        /* ??? SSE cost should be used here.  */
-       *total = ix86_cost->fdiv;
+       *total = cost->fdiv;
       else if (X87_FLOAT_MODE_P (mode))
-       *total = ix86_cost->fdiv;
+       *total = cost->fdiv;
       else if (FLOAT_MODE_P (mode))
        /* ??? SSE vector cost should be used here.  */
-       *total = ix86_cost->fdiv;
+       *total = cost->fdiv;
       else
-       *total = ix86_cost->divide[MODE_INDEX (mode)];
+       *total = cost->divide[MODE_INDEX (mode)];
       return false;
 
     case PLUS:
@@ -22672,11 +26909,11 @@ ix86_rtx_costs (rtx x, int code, int outer_code_i, int *total)
              HOST_WIDE_INT val = INTVAL (XEXP (XEXP (XEXP (x, 0), 0), 1));
              if (val == 2 || val == 4 || val == 8)
                {
-                 *total = ix86_cost->lea;
-                 *total += rtx_cost (XEXP (XEXP (x, 0), 1), outer_code);
+                 *total = cost->lea;
+                 *total += rtx_cost (XEXP (XEXP (x, 0), 1), outer_code, speed);
                  *total += rtx_cost (XEXP (XEXP (XEXP (x, 0), 0), 0),
-                                     outer_code);
-                 *total += rtx_cost (XEXP (x, 1), outer_code);
+                                     outer_code, speed);
+                 *total += rtx_cost (XEXP (x, 1), outer_code, speed);
                  return true;
                }
            }
@@ -22686,18 +26923,18 @@ ix86_rtx_costs (rtx x, int code, int outer_code_i, int *total)
              HOST_WIDE_INT val = INTVAL (XEXP (XEXP (x, 0), 1));
              if (val == 2 || val == 4 || val == 8)
                {
-                 *total = ix86_cost->lea;
-                 *total += rtx_cost (XEXP (XEXP (x, 0), 0), outer_code);
-                 *total += rtx_cost (XEXP (x, 1), outer_code);
+                 *total = cost->lea;
+                 *total += rtx_cost (XEXP (XEXP (x, 0), 0), outer_code, speed);
+                 *total += rtx_cost (XEXP (x, 1), outer_code, speed);
                  return true;
                }
            }
          else if (GET_CODE (XEXP (x, 0)) == PLUS)
            {
-             *total = ix86_cost->lea;
-             *total += rtx_cost (XEXP (XEXP (x, 0), 0), outer_code);
-             *total += rtx_cost (XEXP (XEXP (x, 0), 1), outer_code);
-             *total += rtx_cost (XEXP (x, 1), outer_code);
+             *total = cost->lea;
+             *total += rtx_cost (XEXP (XEXP (x, 0), 0), outer_code, speed);
+             *total += rtx_cost (XEXP (XEXP (x, 0), 1), outer_code, speed);
+             *total += rtx_cost (XEXP (x, 1), outer_code, speed);
              return true;
            }
        }
@@ -22707,18 +26944,18 @@ ix86_rtx_costs (rtx x, int code, int outer_code_i, int *total)
       if (SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH)
        {
          /* ??? SSE cost should be used here.  */
-         *total = ix86_cost->fadd;
+         *total = cost->fadd;
          return false;
        }
       else if (X87_FLOAT_MODE_P (mode))
        {
-         *total = ix86_cost->fadd;
+         *total = cost->fadd;
          return false;
        }
       else if (FLOAT_MODE_P (mode))
        {
          /* ??? SSE vector cost should be used here.  */
-         *total = ix86_cost->fadd;
+         *total = cost->fadd;
          return false;
        }
       /* FALLTHRU */
@@ -22728,10 +26965,10 @@ ix86_rtx_costs (rtx x, int code, int outer_code_i, int *total)
     case XOR:
       if (!TARGET_64BIT && mode == DImode)
        {
-         *total = (ix86_cost->add * 2
-                   + (rtx_cost (XEXP (x, 0), outer_code)
+         *total = (cost->add * 2
+                   + (rtx_cost (XEXP (x, 0), outer_code, speed)
                       << (GET_MODE (XEXP (x, 0)) != DImode))
-                   + (rtx_cost (XEXP (x, 1), outer_code)
+                   + (rtx_cost (XEXP (x, 1), outer_code, speed)
                       << (GET_MODE (XEXP (x, 1)) != DImode)));
          return true;
        }
@@ -22741,27 +26978,27 @@ ix86_rtx_costs (rtx x, int code, int outer_code_i, int *total)
       if (SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH)
        {
          /* ??? SSE cost should be used here.  */
-         *total = ix86_cost->fchs;
+         *total = cost->fchs;
          return false;
        }
       else if (X87_FLOAT_MODE_P (mode))
        {
-         *total = ix86_cost->fchs;
+         *total = cost->fchs;
          return false;
        }
       else if (FLOAT_MODE_P (mode))
        {
          /* ??? SSE vector cost should be used here.  */
-         *total = ix86_cost->fchs;
+         *total = cost->fchs;
          return false;
        }
       /* FALLTHRU */
 
     case NOT:
       if (!TARGET_64BIT && mode == DImode)
-       *total = ix86_cost->add * 2;
+       *total = cost->add * 2;
       else
-       *total = ix86_cost->add;
+       *total = cost->add;
       return false;
 
     case COMPARE:
@@ -22772,9 +27009,9 @@ ix86_rtx_costs (rtx x, int code, int outer_code_i, int *total)
        {
          /* This kind of construct is implemented using test[bwl].
             Treat it as if we had an AND.  */
-         *total = (ix86_cost->add
-                   + rtx_cost (XEXP (XEXP (x, 0), 0), outer_code)
-                   + rtx_cost (const1_rtx, outer_code));
+         *total = (cost->add
+                   + rtx_cost (XEXP (XEXP (x, 0), 0), outer_code, speed)
+                   + rtx_cost (const1_rtx, outer_code, speed));
          return true;
        }
       return false;
@@ -22787,23 +27024,23 @@ ix86_rtx_costs (rtx x, int code, int outer_code_i, int *total)
     case ABS:
       if (SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH)
        /* ??? SSE cost should be used here.  */
-       *total = ix86_cost->fabs;
+       *total = cost->fabs;
       else if (X87_FLOAT_MODE_P (mode))
-       *total = ix86_cost->fabs;
+       *total = cost->fabs;
       else if (FLOAT_MODE_P (mode))
        /* ??? SSE vector cost should be used here.  */
-       *total = ix86_cost->fabs;
+       *total = cost->fabs;
       return false;
 
     case SQRT:
       if (SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH)
        /* ??? SSE cost should be used here.  */
-       *total = ix86_cost->fsqrt;
+       *total = cost->fsqrt;
       else if (X87_FLOAT_MODE_P (mode))
-       *total = ix86_cost->fsqrt;
+       *total = cost->fsqrt;
       else if (FLOAT_MODE_P (mode))
        /* ??? SSE vector cost should be used here.  */
-       *total = ix86_cost->fsqrt;
+       *total = cost->fsqrt;
       return false;
 
     case UNSPEC:
@@ -22837,11 +27074,11 @@ machopic_output_stub (FILE *file, const char *symb, const char *stub)
   symb = (*targetm.strip_name_encoding) (symb);
 
   length = strlen (stub);
-  binder_name = alloca (length + 32);
+  binder_name = XALLOCAVEC (char, length + 32);
   GEN_BINDER_NAME_FOR_STUB (binder_name, stub, length);
 
   length = strlen (symb);
-  symbol_name = alloca (length + 32);
+  symbol_name = XALLOCAVEC (char, length + 32);
   GEN_SYMBOL_NAME_FOR_SYMBOL (symbol_name, symb, length);
 
   sprintf (lazy_ptr_name, "L%d$lz", label);
@@ -22868,17 +27105,17 @@ machopic_output_stub (FILE *file, const char *symb, const char *stub)
   if (MACHOPIC_PURE)
     {
       fprintf (file, "\tlea\t%s-LPC$%d(%%eax),%%eax\n", lazy_ptr_name, label);
-      fprintf (file, "\tpushl\t%%eax\n");
+      fputs ("\tpushl\t%eax\n", file);
     }
   else
     fprintf (file, "\tpushl\t$%s\n", lazy_ptr_name);
 
-  fprintf (file, "\tjmp\tdyld_stub_binding_helper\n");
+  fputs ("\tjmp\tdyld_stub_binding_helper\n", file);
 
   switch_to_section (darwin_sections[machopic_lazy_symbol_ptr_section]);
   fprintf (file, "%s:\n", lazy_ptr_name);
   fprintf (file, "\t.indirect_symbol %s\n", symbol_name);
-  fprintf (file, "\t.long %s\n", binder_name);
+  fprintf (file, ASM_LONG "%s\n", binder_name);
 }
 
 void
@@ -22933,6 +27170,54 @@ x86_order_regs_for_local_alloc (void)
      reg_alloc_order [pos++] = 0;
 }
 
+/* Handle a "ms_abi" or "sysv" attribute; arguments as in
+   struct attribute_spec.handler.  */
+static tree
+ix86_handle_abi_attribute (tree *node, tree name,
+                             tree args ATTRIBUTE_UNUSED,
+                             int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+{
+  if (TREE_CODE (*node) != FUNCTION_TYPE
+      && TREE_CODE (*node) != METHOD_TYPE
+      && TREE_CODE (*node) != FIELD_DECL
+      && TREE_CODE (*node) != TYPE_DECL)
+    {
+      warning (OPT_Wattributes, "%qE attribute only applies to functions",
+              name);
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+  if (!TARGET_64BIT)
+    {
+      warning (OPT_Wattributes, "%qE attribute only available for 64-bit",
+              name);
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+
+  /* Can combine regparm with all attributes but fastcall.  */
+  if (is_attribute_p ("ms_abi", name))
+    {
+      if (lookup_attribute ("sysv_abi", TYPE_ATTRIBUTES (*node)))
+        {
+         error ("ms_abi and sysv_abi attributes are not compatible");
+       }
+
+      return NULL_TREE;
+    }
+  else if (is_attribute_p ("sysv_abi", name))
+    {
+      if (lookup_attribute ("ms_abi", TYPE_ATTRIBUTES (*node)))
+        {
+         error ("ms_abi and sysv_abi attributes are not compatible");
+       }
+
+      return NULL_TREE;
+    }
+
+  return NULL_TREE;
+}
+
 /* Handle a "ms_struct" or "gcc_struct" attribute; arguments as in
    struct attribute_spec.handler.  */
 static tree
@@ -22952,8 +27237,8 @@ ix86_handle_struct_attribute (tree *node, tree name,
   if (!(type && (TREE_CODE (*type) == RECORD_TYPE
                 || TREE_CODE (*type) == UNION_TYPE)))
     {
-      warning (OPT_Wattributes, "%qs attribute ignored",
-              IDENTIFIER_POINTER (name));
+      warning (OPT_Wattributes, "%qE attribute ignored",
+              name);
       *no_add_attrs = true;
     }
 
@@ -22962,8 +27247,8 @@ ix86_handle_struct_attribute (tree *node, tree name,
           || ((is_attribute_p ("gcc_struct", name)
                && lookup_attribute ("ms_struct", TYPE_ATTRIBUTES (*type)))))
     {
-      warning (OPT_Wattributes, "%qs incompatible attribute ignored",
-               IDENTIFIER_POINTER (name));
+      warning (OPT_Wattributes, "%qE incompatible attribute ignored",
+               name);
       *no_add_attrs = true;
     }
 
@@ -22992,7 +27277,7 @@ x86_this_parameter (tree function)
     {
       const int *parm_regs;
 
-      if (TARGET_64BIT_MS_ABI)
+      if (ix86_function_type_abi (type) == MS_ABI)
         parm_regs = x86_64_ms_abi_int_parameter_registers;
       else
         parm_regs = x86_64_int_parameter_registers;
@@ -23075,10 +27360,7 @@ x86_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED,
       /* Put the this parameter into %eax.  */
       xops[0] = this_param;
       xops[1] = this_reg = gen_rtx_REG (Pmode, AX_REG);
-      if (TARGET_64BIT)
-        output_asm_insn ("mov{q}\t{%0, %1|%1, %0}", xops);
-      else
-        output_asm_insn ("mov{l}\t{%0, %1|%1, %0}", xops);
+      output_asm_insn ("mov%z1\t{%0, %1|%1, %0}", xops);
     }
   else
     this_reg = NULL_RTX;
@@ -23120,10 +27402,7 @@ x86_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED,
 
       xops[0] = gen_rtx_MEM (Pmode, this_reg);
       xops[1] = tmp;
-      if (TARGET_64BIT)
-       output_asm_insn ("mov{q}\t{%0, %1|%1, %0}", xops);
-      else
-       output_asm_insn ("mov{l}\t{%0, %1|%1, %0}", xops);
+      output_asm_insn ("mov%z1\t{%0, %1|%1, %0}", xops);
 
       /* Adjust the this parameter.  */
       xops[0] = gen_rtx_MEM (Pmode, plus_constant (tmp, vcall_offset));
@@ -23136,10 +27415,7 @@ x86_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED,
          xops[0] = gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, tmp, tmp2));
        }
       xops[1] = this_reg;
-      if (TARGET_64BIT)
-       output_asm_insn ("add{q}\t{%0, %1|%1, %0}", xops);
-      else
-       output_asm_insn ("add{l}\t{%0, %1|%1, %0}", xops);
+      output_asm_insn ("add%z1\t{%0, %1|%1, %0}", xops);
     }
 
   /* If necessary, drop THIS back to its stack slot.  */
@@ -23147,10 +27423,7 @@ x86_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED,
     {
       xops[0] = this_reg;
       xops[1] = this_param;
-      if (TARGET_64BIT)
-        output_asm_insn ("mov{q}\t{%0, %1|%1, %0}", xops);
-      else
-        output_asm_insn ("mov{l}\t{%0, %1|%1, %0}", xops);
+      output_asm_insn ("mov%z1\t{%0, %1|%1, %0}", xops);
     }
 
   xops[0] = XEXP (DECL_RTL (function), 0);
@@ -23160,7 +27433,7 @@ x86_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED,
        output_asm_insn ("jmp\t%P0", xops);
       /* All thunks should be in the same object as their target,
         and thus binds_local_p should be true.  */
-      else if (TARGET_64BIT_MS_ABI)
+      else if (TARGET_64BIT && cfun->machine->call_abi == MS_ABI)
        gcc_unreachable ();
       else
        {
@@ -23223,8 +27496,7 @@ x86_field_alignment (tree field, int computed)
 
   if (TARGET_64BIT || TARGET_ALIGN_DOUBLE)
     return computed;
-  mode = TYPE_MODE (TREE_CODE (type) == ARRAY_TYPE
-                   ? get_inner_array_type (type) : type);
+  mode = TYPE_MODE (strip_array_types (type));
   if (mode == DFmode || mode == DCmode
       || GET_MODE_CLASS (mode) == MODE_INT
       || GET_MODE_CLASS (mode) == MODE_COMPLEX_INT)
@@ -23240,32 +27512,33 @@ x86_function_profiler (FILE *file, int labelno ATTRIBUTE_UNUSED)
   if (TARGET_64BIT)
     {
 #ifndef NO_PROFILE_COUNTERS
-      fprintf (file, "\tleaq\t%sP%d@(%%rip),%%r11\n", LPREFIX, labelno);
+      fprintf (file, "\tleaq\t" LPREFIX "P%d@(%%rip),%%r11\n", labelno);
 #endif
 
-      if (!TARGET_64BIT_MS_ABI && flag_pic)
-       fprintf (file, "\tcall\t*%s@GOTPCREL(%%rip)\n", MCOUNT_NAME);
+      if (DEFAULT_ABI == SYSV_ABI && flag_pic)
+       fputs ("\tcall\t*" MCOUNT_NAME "@GOTPCREL(%rip)\n", file);
       else
-       fprintf (file, "\tcall\t%s\n", MCOUNT_NAME);
+       fputs ("\tcall\t" MCOUNT_NAME "\n", file);
     }
   else if (flag_pic)
     {
 #ifndef NO_PROFILE_COUNTERS
-      fprintf (file, "\tleal\t%sP%d@GOTOFF(%%ebx),%%%s\n",
-              LPREFIX, labelno, PROFILE_COUNT_REGISTER);
+      fprintf (file, "\tleal\t" LPREFIX "P%d@GOTOFF(%%ebx),%%" PROFILE_COUNT_REGISTER "\n",
+              labelno);
 #endif
-      fprintf (file, "\tcall\t*%s@GOT(%%ebx)\n", MCOUNT_NAME);
+      fputs ("\tcall\t*" MCOUNT_NAME "@GOT(%ebx)\n", file);
     }
   else
     {
 #ifndef NO_PROFILE_COUNTERS
-      fprintf (file, "\tmovl\t$%sP%d,%%%s\n", LPREFIX, labelno,
-              PROFILE_COUNT_REGISTER);
+      fprintf (file, "\tmovl\t$" LPREFIX "P%d,%%" PROFILE_COUNT_REGISTER "\n",
+              labelno);
 #endif
-      fprintf (file, "\tcall\t%s\n", MCOUNT_NAME);
+      fputs ("\tcall\t" MCOUNT_NAME "\n", file);
     }
 }
 
+#ifdef ASM_OUTPUT_MAX_SKIP_PAD
 /* We don't have exact information about the insn sizes, but we may assume
    quite safely that we are informed about all 1 byte insns and memory
    address sizes.  This is enough to eliminate unnecessary padding in
@@ -23274,7 +27547,7 @@ x86_function_profiler (FILE *file, int labelno ATTRIBUTE_UNUSED)
 static int
 min_insn_size (rtx insn)
 {
-  int l = 0;
+  int l = 0, len;
 
   if (!INSN_P (insn) || !active_insn_p (insn))
     return 0;
@@ -23283,9 +27556,7 @@ min_insn_size (rtx insn)
   if (GET_CODE (PATTERN (insn)) == UNSPEC_VOLATILE
       && XINT (PATTERN (insn), 1) == UNSPECV_ALIGN)
     return 0;
-  if (JUMP_P (insn)
-      && (GET_CODE (PATTERN (insn)) == ADDR_VEC
-         || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC))
+  if (JUMP_TABLE_DATA_P (insn))
     return 0;
 
   /* Important case - calls are always 5 bytes.
@@ -23294,14 +27565,31 @@ min_insn_size (rtx insn)
       && symbolic_reference_mentioned_p (PATTERN (insn))
       && !SIBLING_CALL_P (insn))
     return 5;
-  if (get_attr_length (insn) <= 1)
+  len = get_attr_length (insn);
+  if (len <= 1)
     return 1;
 
-  /* For normal instructions we may rely on the sizes of addresses
-     and the presence of symbol to require 4 bytes of encoding.
-     This is not the case for jumps where references are PC relative.  */
+  /* For normal instructions we rely on get_attr_length being exact,
+     with a few exceptions.  */
   if (!JUMP_P (insn))
     {
+      enum attr_type type = get_attr_type (insn);
+
+      switch (type)
+       {
+       case TYPE_MULTI:
+         if (GET_CODE (PATTERN (insn)) == ASM_INPUT
+             || asm_noperands (PATTERN (insn)) >= 0)
+           return 0;
+         break;
+       case TYPE_OTHER:
+       case TYPE_FCMP:
+         break;
+       default:
+         /* Otherwise trust get_attr_length.  */
+         return len;
+       }
+
       l = get_attr_length_address (insn);
       if (l < 4 && symbolic_reference_mentioned_p (PATTERN (insn)))
        l = 4;
@@ -23316,7 +27604,7 @@ min_insn_size (rtx insn)
    window.  */
 
 static void
-ix86_avoid_jump_misspredicts (void)
+ix86_avoid_jump_mispredicts (void)
 {
   rtx insn, start = get_insns ();
   int nbytes = 0, njumps = 0;
@@ -23330,15 +27618,52 @@ ix86_avoid_jump_misspredicts (void)
 
      The smallest offset in the page INSN can start is the case where START
      ends on the offset 0.  Offset of INSN is then NBYTES - sizeof (INSN).
-     We add p2align to 16byte window with maxskip 17 - NBYTES + sizeof (INSN).
+     We add p2align to 16byte window with maxskip 15 - NBYTES + sizeof (INSN).
      */
-  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+  for (insn = start; insn; insn = NEXT_INSN (insn))
     {
+      int min_size;
+
+      if (LABEL_P (insn))
+       {
+         int align = label_to_alignment (insn);
+         int max_skip = label_to_max_skip (insn);
+
+         if (max_skip > 15)
+           max_skip = 15;
+         /* If align > 3, only up to 16 - max_skip - 1 bytes can be
+            already in the current 16 byte page, because otherwise
+            ASM_OUTPUT_MAX_SKIP_ALIGN could skip max_skip or fewer
+            bytes to reach 16 byte boundary.  */
+         if (align <= 0
+             || (align <= 3 && max_skip != (1 << align) - 1))
+           max_skip = 0;
+         if (dump_file)
+           fprintf (dump_file, "Label %i with max_skip %i\n",
+                    INSN_UID (insn), max_skip);
+         if (max_skip)
+           {
+             while (nbytes + max_skip >= 16)
+               {
+                 start = NEXT_INSN (start);
+                 if ((JUMP_P (start)
+                      && GET_CODE (PATTERN (start)) != ADDR_VEC
+                      && GET_CODE (PATTERN (start)) != ADDR_DIFF_VEC)
+                     || CALL_P (start))
+                   njumps--, isjump = 1;
+                 else
+                   isjump = 0;
+                 nbytes -= min_insn_size (start);
+               }
+           }
+         continue;
+       }
 
-      nbytes += min_insn_size (insn);
+      min_size = min_insn_size (insn);
+      nbytes += min_size;
       if (dump_file)
-        fprintf(dump_file, "Insn %i estimated to %i bytes\n",
-               INSN_UID (insn), min_insn_size (insn));
+       fprintf (dump_file, "Insn %i estimated to %i bytes\n",
+                INSN_UID (insn), min_size);
       if ((JUMP_P (insn)
           && GET_CODE (PATTERN (insn)) != ADDR_VEC
           && GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC)
@@ -23362,7 +27687,7 @@ ix86_avoid_jump_misspredicts (void)
       gcc_assert (njumps >= 0);
       if (dump_file)
         fprintf (dump_file, "Interval %i to %i has %i bytes\n",
-               INSN_UID (start), INSN_UID (insn), nbytes);
+                INSN_UID (start), INSN_UID (insn), nbytes);
 
       if (njumps == 3 && isjump && nbytes < 16)
        {
@@ -23371,10 +27696,11 @@ ix86_avoid_jump_misspredicts (void)
          if (dump_file)
            fprintf (dump_file, "Padding insn %i by %i bytes!\n",
                     INSN_UID (insn), padsize);
-          emit_insn_before (gen_align (GEN_INT (padsize)), insn);
+          emit_insn_before (gen_pad (GEN_INT (padsize)), insn);
        }
     }
 }
+#endif
 
 /* AMD Athlon works faster
    when RET is not destination of conditional jump or directly preceded
@@ -23394,7 +27720,7 @@ ix86_pad_returns (void)
       bool replace = false;
 
       if (!JUMP_P (ret) || GET_CODE (PATTERN (ret)) != RETURN
-         || !maybe_hot_bb_p (bb))
+         || optimize_bb_for_size_p (bb))
        continue;
       for (prev = PREV_INSN (ret); prev; prev = PREV_INSN (prev))
        if (active_insn_p (prev) || LABEL_P (prev))
@@ -23423,7 +27749,7 @@ ix86_pad_returns (void)
        }
       if (replace)
        {
-         emit_insn_before (gen_return_internal_long (), ret);
+         emit_jump_insn_before (gen_return_internal_long (), ret);
          delete_insn (ret);
        }
     }
@@ -23434,10 +27760,15 @@ ix86_pad_returns (void)
 static void
 ix86_reorg (void)
 {
-  if (TARGET_PAD_RETURNS && optimize && !optimize_size)
-    ix86_pad_returns ();
-  if (TARGET_FOUR_JUMP_LIMIT && optimize && !optimize_size)
-    ix86_avoid_jump_misspredicts ();
+  if (optimize && optimize_function_for_speed_p (cfun))
+    {
+      if (TARGET_PAD_RETURNS)
+       ix86_pad_returns ();
+#ifdef ASM_OUTPUT_MAX_SKIP_PAD
+      if (TARGET_FOUR_JUMP_LIMIT)
+       ix86_avoid_jump_mispredicts ();
+#endif
+    }
 }
 
 /* Return nonzero when QImode register that must be represented via REX prefix
@@ -23449,7 +27780,7 @@ x86_extended_QIreg_mentioned_p (rtx insn)
   extract_insn_cached (insn);
   for (i = 0; i < recog_data.n_operands; i++)
     if (REG_P (recog_data.operand[i])
-       && REGNO (recog_data.operand[i]) >= 4)
+       && REGNO (recog_data.operand[i]) > BX_REG)
        return true;
   return false;
 }
@@ -23471,7 +27802,8 @@ extended_reg_mentioned_1 (rtx *p, void *data ATTRIBUTE_UNUSED)
 bool
 x86_extended_reg_mentioned_p (rtx insn)
 {
-  return for_each_rtx (&PATTERN (insn), extended_reg_mentioned_1, NULL);
+  return for_each_rtx (INSN_P (insn) ? &PATTERN (insn) : &insn,
+                      extended_reg_mentioned_1, NULL);
 }
 
 /* Generate an unsigned DImode/SImode to FP conversion.  This is the same code
@@ -23522,7 +27854,7 @@ static bool
 ix86_expand_vector_init_duplicate (bool mmx_ok, enum machine_mode mode,
                                   rtx target, rtx val)
 {
-  enum machine_mode smode, wsmode, wvmode;
+  enum machine_mode hmode, smode, wsmode, wvmode;
   rtx x;
 
   switch (mode)
@@ -23647,6 +27979,33 @@ ix86_expand_vector_init_duplicate (bool mmx_ok, enum machine_mode mode,
       emit_move_insn (target, gen_lowpart (mode, x));
       return true;
 
+    case V4DFmode:
+      hmode = V2DFmode;
+      goto half;
+    case V4DImode:
+      hmode = V2DImode;
+      goto half;
+    case V8SFmode:
+      hmode = V4SFmode;
+      goto half;
+    case V8SImode:
+      hmode = V4SImode;
+      goto half;
+    case V16HImode:
+      hmode = V8HImode;
+      goto half;
+    case V32QImode:
+      hmode = V16QImode;
+      goto half;
+half:
+      {
+       rtx tmp = gen_reg_rtx (hmode);
+       ix86_expand_vector_init_duplicate (mmx_ok, hmode, tmp, val);
+       emit_insn (gen_rtx_SET (VOIDmode, target,
+                               gen_rtx_VEC_CONCAT (mode, tmp, tmp)));
+      }
+      return true;
+
     default:
       return false;
     }
@@ -23668,7 +28027,13 @@ ix86_expand_vector_init_one_nonzero (bool mmx_ok, enum machine_mode mode,
   switch (mode)
     {
     case V2DImode:
-      use_vector_set = TARGET_64BIT && TARGET_SSE4_1;
+      /* For SSE4.1, we normally use vector set.  But if the second
+        element is zero and inter-unit moves are OK, we use movq
+        instead.  */
+      use_vector_set = (TARGET_64BIT
+                       && TARGET_SSE4_1
+                       && !(TARGET_INTER_UNIT_MOVES
+                            && one_var == 0));
       break;
     case V16QImode:
     case V4SImode:
@@ -23680,6 +28045,18 @@ ix86_expand_vector_init_one_nonzero (bool mmx_ok, enum machine_mode mode,
       break;
     case V4HImode:
       use_vector_set = TARGET_SSE || TARGET_3DNOW_A;
+      break;
+    case V32QImode:
+    case V16HImode:
+    case V8SImode:
+    case V8SFmode:
+    case V4DFmode:
+      use_vector_set = TARGET_AVX;
+      break;
+    case V4DImode:
+      /* Use ix86_expand_vector_set in 64bit mode only.  */
+      use_vector_set = TARGET_AVX && TARGET_64BIT;
+      break;
     default:
       break;
     }
@@ -23747,7 +28124,7 @@ ix86_expand_vector_init_one_nonzero (bool mmx_ok, enum machine_mode mode,
          else
            tmp = new_target;
 
-         emit_insn (gen_sse_shufps_1 (tmp, tmp, tmp,
+         emit_insn (gen_sse_shufps_v4sf (tmp, tmp, tmp,
                                       GEN_INT (1),
                                       GEN_INT (one_var == 1 ? 0 : 1),
                                       GEN_INT (one_var == 2 ? 0+4 : 1+4),
@@ -23818,6 +28195,15 @@ ix86_expand_vector_init_one_var (bool mmx_ok, enum machine_mode mode,
         the general case.  */
       return false;
 
+    case V4DImode:
+      /* Use ix86_expand_vector_set in 64bit mode only.  */
+      if (!TARGET_64BIT)
+       return false;
+    case V4DFmode:
+    case V8SFmode:
+    case V8SImode:
+    case V16HImode:
+    case V32QImode:
     case V4SFmode:
     case V4SImode:
     case V8HImode:
@@ -23825,6 +28211,8 @@ ix86_expand_vector_init_one_var (bool mmx_ok, enum machine_mode mode,
       break;
 
     case V16QImode:
+      if (TARGET_SSE4_1)
+       break;
       wmode = V8HImode;
       goto widen;
     case V8QImode:
@@ -23867,214 +28255,335 @@ ix86_expand_vector_init_one_var (bool mmx_ok, enum machine_mode mode,
   return true;
 }
 
-/* A subroutine of ix86_expand_vector_init.  Handle the most general case:
-   all values variable, and none identical.  */
+/* A subroutine of ix86_expand_vector_init_general.  Use vector
+   concatenate to handle the most general case: all values variable,
+   and none identical.  */
 
 static void
-ix86_expand_vector_init_general (bool mmx_ok, enum machine_mode mode,
-                                rtx target, rtx vals)
+ix86_expand_vector_init_concat (enum machine_mode mode,
+                               rtx target, rtx *ops, int n)
 {
-  enum machine_mode half_mode = GET_MODE_INNER (mode);
-  rtx op0 = NULL, op1 = NULL;
-  bool use_vec_concat = false;
+  enum machine_mode cmode, hmode = VOIDmode;
+  rtx first[8], second[4];
+  rtvec v;
+  int i, j;
 
-  switch (mode)
+  switch (n)
     {
-    case V2SFmode:
-    case V2SImode:
-      if (!mmx_ok && !TARGET_SSE)
-       break;
-      /* FALLTHRU */
+    case 2:
+      switch (mode)
+       {
+       case V8SImode:
+         cmode = V4SImode;
+         break;
+       case V8SFmode:
+         cmode = V4SFmode;
+         break;
+       case V4DImode:
+         cmode = V2DImode;
+         break;
+       case V4DFmode:
+         cmode = V2DFmode;
+         break;
+       case V4SImode:
+         cmode = V2SImode;
+         break;
+       case V4SFmode:
+         cmode = V2SFmode;
+         break;
+       case V2DImode:
+         cmode = DImode;
+         break;
+       case V2SImode:
+         cmode = SImode;
+         break;
+       case V2DFmode:
+         cmode = DFmode;
+         break;
+       case V2SFmode:
+         cmode = SFmode;
+         break;
+       default:
+         gcc_unreachable ();
+       }
 
-    case V2DFmode:
-    case V2DImode:
-      /* For the two element vectors, we always implement VEC_CONCAT.  */
-      op0 = XVECEXP (vals, 0, 0);
-      op1 = XVECEXP (vals, 0, 1);
-      use_vec_concat = true;
+      if (!register_operand (ops[1], cmode))
+       ops[1] = force_reg (cmode, ops[1]);
+      if (!register_operand (ops[0], cmode))
+       ops[0] = force_reg (cmode, ops[0]);
+      emit_insn (gen_rtx_SET (VOIDmode, target,
+                             gen_rtx_VEC_CONCAT (mode, ops[0],
+                                                 ops[1])));
       break;
 
-    case V4SFmode:
-      half_mode = V2SFmode;
-      goto half;
-    case V4SImode:
-      half_mode = V2SImode;
+    case 4:
+      switch (mode)
+       {
+       case V4DImode:
+         cmode = V2DImode;
+         break;
+       case V4DFmode:
+         cmode = V2DFmode;
+         break;
+       case V4SImode:
+         cmode = V2SImode;
+         break;
+       case V4SFmode:
+         cmode = V2SFmode;
+         break;
+       default:
+         gcc_unreachable ();
+       }
       goto half;
-    half:
-      {
-       rtvec v;
-
-       /* For V4SF and V4SI, we implement a concat of two V2 vectors.
-          Recurse to load the two halves.  */
-
-       op1 = gen_reg_rtx (half_mode);
-       v = gen_rtvec (2, XVECEXP (vals, 0, 2), XVECEXP (vals, 0, 3));
-       ix86_expand_vector_init (false, op1, gen_rtx_PARALLEL (half_mode, v));
-
-       op0 = gen_reg_rtx (half_mode);
-       v = gen_rtvec (2, XVECEXP (vals, 0, 0), XVECEXP (vals, 0, 1));
-       ix86_expand_vector_init (false, op0, gen_rtx_PARALLEL (half_mode, v));
 
-       use_vec_concat = true;
-      }
-      break;
-
-    case V8HImode:
-      if (TARGET_SSE2)
+    case 8:
+      switch (mode)
        {
-         rtx ops[4];
-         unsigned int i, j;
+       case V8SImode:
+         cmode = V2SImode;
+         hmode = V4SImode;
+         break;
+       case V8SFmode:
+         cmode = V2SFmode;
+         hmode = V4SFmode;
+         break;
+       default:
+         gcc_unreachable ();
+       }
+      goto half;
 
-         for (i = 0; i < ARRAY_SIZE (ops); i++)
-           {
-             /* Extend the odd elment from HImode to SImode using
-                a paradoxical SUBREG.  */
-             op0 = gen_reg_rtx (SImode);
-             emit_move_insn (op0, gen_lowpart (SImode,
-                                               XVECEXP (vals, 0,
-                                                        i + i)));
-
-             /* Insert the SImode value as low element of V4SImode
-                vector. */
-             op1 = gen_reg_rtx (V4SImode);
-             op0 = gen_rtx_VEC_MERGE (V4SImode,
-                                      gen_rtx_VEC_DUPLICATE (V4SImode,
-                                                             op0),
-                                      CONST0_RTX (V4SImode),
-                                      const1_rtx);
-             emit_insn (gen_rtx_SET (VOIDmode, op1, op0));
-
-             /* Cast the V4SImode vector back to a V8HImode vector.  */
-             op0 = gen_reg_rtx (mode);
-             emit_move_insn (op0, gen_lowpart (mode, op1));
-
-             /* Load even HI elements into the second positon.  */
-             emit_insn (gen_vec_setv8hi (op0, XVECEXP (vals, 0,
-                                                       i + i + 1),
-                                         const1_rtx));
-
-             /* Cast V8HImode vector to V4SImode vector.  */
-             ops[i] = gen_reg_rtx (V4SImode);
-             emit_move_insn (ops[i], gen_lowpart (V4SImode, op0));
-           }
+half:
+      /* FIXME: We process inputs backward to help RA.  PR 36222.  */
+      i = n - 1;
+      j = (n >> 1) - 1;
+      for (; i > 0; i -= 2, j--)
+       {
+         first[j] = gen_reg_rtx (cmode);
+         v = gen_rtvec (2, ops[i - 1], ops[i]);
+         ix86_expand_vector_init (false, first[j],
+                                  gen_rtx_PARALLEL (cmode, v));
+       }
 
-         /* Interleave low V4SIs.  */
-         for (i = j = 0; i < ARRAY_SIZE (ops); i += 2, j++)
+      n >>= 1;
+      if (n > 2)
+       {
+         gcc_assert (hmode != VOIDmode);
+         for (i = j = 0; i < n; i += 2, j++)
            {
-             op0 = gen_reg_rtx (V4SImode);
-             emit_insn (gen_vec_interleave_lowv4si (op0, ops[i],
-                                                    ops[i + 1]));
-
-             /* Cast V4SImode vectors to V2DImode vectors.  */
-             op1 = gen_reg_rtx (V2DImode);
-             emit_move_insn (op1, gen_lowpart (V2DImode, op0));
-             ops[j] = op1;
+             second[j] = gen_reg_rtx (hmode);
+             ix86_expand_vector_init_concat (hmode, second [j],
+                                             &first [i], 2);
            }
+         n >>= 1;
+         ix86_expand_vector_init_concat (mode, target, second, n);
+       }
+      else
+       ix86_expand_vector_init_concat (mode, target, first, n);
+      break;
 
-         /* Interleave low V2DIs.  */
-         op0 = gen_reg_rtx (V2DImode);
-         emit_insn (gen_vec_interleave_lowv2di (op0, ops[0], ops[1]));
+    default:
+      gcc_unreachable ();
+    }
+}
 
-         /* Cast the V2DImode vector back to a V8HImode vector.  */
-         emit_insn (gen_rtx_SET (VOIDmode, target,
-                                 gen_lowpart (mode, op0)));
-         return;
-       }
+/* A subroutine of ix86_expand_vector_init_general.  Use vector
+   interleave to handle the most general case: all values variable,
+   and none identical.  */
 
+static void
+ix86_expand_vector_init_interleave (enum machine_mode mode,
+                                   rtx target, rtx *ops, int n)
+{
+  enum machine_mode first_imode, second_imode, third_imode, inner_mode;
+  int i, j;
+  rtx op0, op1;
+  rtx (*gen_load_even) (rtx, rtx, rtx);
+  rtx (*gen_interleave_first_low) (rtx, rtx, rtx);
+  rtx (*gen_interleave_second_low) (rtx, rtx, rtx);
+  
+  switch (mode)
+    {
+    case V8HImode:
+      gen_load_even = gen_vec_setv8hi;
+      gen_interleave_first_low = gen_vec_interleave_lowv4si;
+      gen_interleave_second_low = gen_vec_interleave_lowv2di;
+      inner_mode = HImode;
+      first_imode = V4SImode;
+      second_imode = V2DImode;
+      third_imode = VOIDmode;
+      break;
     case V16QImode:
-      if (TARGET_SSE4_1)
-       {
-         rtx ops[8];
-         unsigned int i, j;
+      gen_load_even = gen_vec_setv16qi;
+      gen_interleave_first_low = gen_vec_interleave_lowv8hi;
+      gen_interleave_second_low = gen_vec_interleave_lowv4si;
+      inner_mode = QImode;
+      first_imode = V8HImode;
+      second_imode = V4SImode;
+      third_imode = V2DImode;
+      break;
+    default:
+      gcc_unreachable ();
+    }
+     
+  for (i = 0; i < n; i++)
+    {
+      /* Extend the odd elment to SImode using a paradoxical SUBREG.  */
+      op0 = gen_reg_rtx (SImode);
+      emit_move_insn (op0, gen_lowpart (SImode, ops [i + i]));
 
-         for (i = 0; i < ARRAY_SIZE (ops); i++)
-           {
-             /* Extend the odd elment from QImode to SImode using
-                a paradoxical SUBREG.  */
-             op0 = gen_reg_rtx (SImode);
-             emit_move_insn (op0, gen_lowpart (SImode,
-                                               XVECEXP (vals, 0,
-                                                        i + i)));
-
-             /* Insert the SImode value as low element of V4SImode
-                vector. */
-             op1 = gen_reg_rtx (V4SImode);
-             op0 = gen_rtx_VEC_MERGE (V4SImode,
-                                      gen_rtx_VEC_DUPLICATE (V4SImode,
-                                                             op0),
-                                      CONST0_RTX (V4SImode),
-                                      const1_rtx);
-             emit_insn (gen_rtx_SET (VOIDmode, op1, op0));
-
-             /* Cast the V4SImode vector back to a V16QImode vector.  */
-             op0 = gen_reg_rtx (mode);
-             emit_move_insn (op0, gen_lowpart (mode, op1));
-
-             /* Load even QI elements into the second positon.  */
-             emit_insn (gen_vec_setv16qi (op0, XVECEXP (vals, 0,
-                                                        i + i + 1),
-                                          const1_rtx));
-
-             /* Cast V16QImode vector to V8HImode vector.  */
-             ops[i] = gen_reg_rtx (V8HImode);
-             emit_move_insn (ops[i], gen_lowpart (V8HImode, op0));
-           }
+      /* Insert the SImode value as low element of V4SImode vector. */
+      op1 = gen_reg_rtx (V4SImode);
+      op0 = gen_rtx_VEC_MERGE (V4SImode,
+                              gen_rtx_VEC_DUPLICATE (V4SImode,
+                                                     op0),
+                              CONST0_RTX (V4SImode),
+                              const1_rtx);
+      emit_insn (gen_rtx_SET (VOIDmode, op1, op0));
 
-         /* Interleave low V8HIs.  */
-         for (i = j = 0; i < ARRAY_SIZE (ops); i += 2, j++)
-           {
-             op0 = gen_reg_rtx (V8HImode);
-             emit_insn (gen_vec_interleave_lowv8hi (op0, ops[i],
-                                                    ops[i + 1]));
-
-             /* Cast V8HImode vector to V4SImode vector.  */
-             op1 = gen_reg_rtx (V4SImode);
-             emit_move_insn (op1, gen_lowpart (V4SImode, op0));
-             ops[j] = op1;
-           }
+      /* Cast the V4SImode vector back to a vector in orignal mode.  */
+      op0 = gen_reg_rtx (mode);
+      emit_move_insn (op0, gen_lowpart (mode, op1));
+      
+      /* Load even elements into the second positon.  */
+      emit_insn ((*gen_load_even) (op0,
+                                  force_reg (inner_mode,
+                                             ops [i + i + 1]),
+                                  const1_rtx));
 
-         /* Interleave low V4SIs.  */
-         for (i = j = 0; i < ARRAY_SIZE (ops) / 2; i += 2, j++)
-           {
-             op0 = gen_reg_rtx (V4SImode);
-             emit_insn (gen_vec_interleave_lowv4si (op0, ops[i],
-                                                    ops[i + 1]));
-
-             /* Cast V4SImode vectors to V2DImode vectors.  */
-             op1 = gen_reg_rtx (V2DImode);
-             emit_move_insn (op1, gen_lowpart (V2DImode, op0));
-             ops[j] = op1;
-           }
+      /* Cast vector to FIRST_IMODE vector.  */
+      ops[i] = gen_reg_rtx (first_imode);
+      emit_move_insn (ops[i], gen_lowpart (first_imode, op0));
+    }
 
-         /* Interleave low V2DIs.  */
-         op0 = gen_reg_rtx (V2DImode);
-         emit_insn (gen_vec_interleave_lowv2di (op0, ops[0], ops[1]));
+  /* Interleave low FIRST_IMODE vectors.  */
+  for (i = j = 0; i < n; i += 2, j++)
+    {
+      op0 = gen_reg_rtx (first_imode);
+      emit_insn ((*gen_interleave_first_low) (op0, ops[i], ops[i + 1]));
 
-         /* Cast the V2DImode vector back to a V8HImode vector.  */
-         emit_insn (gen_rtx_SET (VOIDmode, target,
-                                 gen_lowpart (mode, op0)));
-         return;
+      /* Cast FIRST_IMODE vector to SECOND_IMODE vector.  */
+      ops[j] = gen_reg_rtx (second_imode);
+      emit_move_insn (ops[j], gen_lowpart (second_imode, op0));
+    }
+
+  /* Interleave low SECOND_IMODE vectors.  */
+  switch (second_imode)
+    {
+    case V4SImode:
+      for (i = j = 0; i < n / 2; i += 2, j++)
+       {
+         op0 = gen_reg_rtx (second_imode);
+         emit_insn ((*gen_interleave_second_low) (op0, ops[i],
+                                                  ops[i + 1]));
+
+         /* Cast the SECOND_IMODE vector to the THIRD_IMODE
+            vector.  */
+         ops[j] = gen_reg_rtx (third_imode);
+         emit_move_insn (ops[j], gen_lowpart (third_imode, op0));
        }
+      second_imode = V2DImode;
+      gen_interleave_second_low = gen_vec_interleave_lowv2di;
+      /* FALLTHRU */
 
-    case V4HImode:
-    case V8QImode:
+    case V2DImode:
+      op0 = gen_reg_rtx (second_imode);
+      emit_insn ((*gen_interleave_second_low) (op0, ops[0],
+                                              ops[1]));
+
+      /* Cast the SECOND_IMODE vector back to a vector on original
+        mode.  */
+      emit_insn (gen_rtx_SET (VOIDmode, target,
+                             gen_lowpart (mode, op0)));
       break;
 
     default:
       gcc_unreachable ();
     }
+}
+
+/* A subroutine of ix86_expand_vector_init.  Handle the most general case:
+   all values variable, and none identical.  */
+
+static void
+ix86_expand_vector_init_general (bool mmx_ok, enum machine_mode mode,
+                                rtx target, rtx vals)
+{
+  rtx ops[32], op0, op1;
+  enum machine_mode half_mode = VOIDmode;
+  int n, i;
 
-  if (use_vec_concat)
+  switch (mode)
     {
-      if (!register_operand (op1, half_mode))
-       op1 = force_reg (half_mode, op1);
-      if (!register_operand (op0, half_mode))
-       op0 = force_reg (half_mode, op0);
+    case V2SFmode:
+    case V2SImode:
+      if (!mmx_ok && !TARGET_SSE)
+       break;
+      /* FALLTHRU */
+
+    case V8SFmode:
+    case V8SImode:
+    case V4DFmode:
+    case V4DImode:
+    case V4SFmode:
+    case V4SImode:
+    case V2DFmode:
+    case V2DImode:
+      n = GET_MODE_NUNITS (mode);
+      for (i = 0; i < n; i++)
+       ops[i] = XVECEXP (vals, 0, i);
+      ix86_expand_vector_init_concat (mode, target, ops, n);
+      return;
+
+    case V32QImode:
+      half_mode = V16QImode;
+      goto half;
 
+    case V16HImode:
+      half_mode = V8HImode;
+      goto half;
+
+half:
+      n = GET_MODE_NUNITS (mode);
+      for (i = 0; i < n; i++)
+       ops[i] = XVECEXP (vals, 0, i);
+      op0 = gen_reg_rtx (half_mode);
+      op1 = gen_reg_rtx (half_mode);
+      ix86_expand_vector_init_interleave (half_mode, op0, ops,
+                                         n >> 2);
+      ix86_expand_vector_init_interleave (half_mode, op1,
+                                         &ops [n >> 1], n >> 2);
       emit_insn (gen_rtx_SET (VOIDmode, target,
                              gen_rtx_VEC_CONCAT (mode, op0, op1)));
+      return;
+
+    case V16QImode:
+      if (!TARGET_SSE4_1)
+       break;
+      /* FALLTHRU */
+
+    case V8HImode:
+      if (!TARGET_SSE2)
+       break;
+
+      /* Don't use ix86_expand_vector_init_interleave if we can't
+        move from GPR to SSE register directly.  */ 
+      if (!TARGET_INTER_UNIT_MOVES)
+       break;
+
+      n = GET_MODE_NUNITS (mode);
+      for (i = 0; i < n; i++)
+       ops[i] = XVECEXP (vals, 0, i);
+      ix86_expand_vector_init_interleave (mode, target, ops, n >> 1);
+      return;
+
+    case V4HImode:
+    case V8QImode:
+      break;
+
+    default:
+      gcc_unreachable ();
     }
-  else
+
     {
       int i, j, n_elts, n_words, n_elt_per_word;
       enum machine_mode inner_mode;
@@ -24114,7 +28623,7 @@ ix86_expand_vector_init_general (bool mmx_ok, enum machine_mode mode,
       else if (n_words == 2)
        {
          rtx tmp = gen_reg_rtx (mode);
-         emit_insn (gen_rtx_CLOBBER (VOIDmode, tmp));
+         emit_clobber (tmp);
          emit_move_insn (gen_lowpart (word_mode, tmp), words[0]);
          emit_move_insn (gen_highpart (word_mode, tmp), words[1]);
          emit_move_insn (target, tmp);
@@ -24122,6 +28631,7 @@ ix86_expand_vector_init_general (bool mmx_ok, enum machine_mode mode,
       else if (n_words == 4)
        {
          rtx tmp = gen_reg_rtx (V4SImode);
+         gcc_assert (word_mode == SImode);
          vals = gen_rtx_PARALLEL (V4SImode, gen_rtvec_v (4, words));
          ix86_expand_vector_init_general (false, V4SImode, tmp, vals);
          emit_move_insn (target, gen_lowpart (mode, tmp));
@@ -24193,8 +28703,28 @@ ix86_expand_vector_set (bool mmx_ok, rtx target, rtx val, int elt)
 {
   enum machine_mode mode = GET_MODE (target);
   enum machine_mode inner_mode = GET_MODE_INNER (mode);
+  enum machine_mode half_mode;
   bool use_vec_merge = false;
   rtx tmp;
+  static rtx (*gen_extract[6][2]) (rtx, rtx)
+    = {
+       { gen_vec_extract_lo_v32qi, gen_vec_extract_hi_v32qi },
+       { gen_vec_extract_lo_v16hi, gen_vec_extract_hi_v16hi },
+       { gen_vec_extract_lo_v8si, gen_vec_extract_hi_v8si },
+       { gen_vec_extract_lo_v4di, gen_vec_extract_hi_v4di },
+       { gen_vec_extract_lo_v8sf, gen_vec_extract_hi_v8sf },
+       { gen_vec_extract_lo_v4df, gen_vec_extract_hi_v4df }
+      };
+  static rtx (*gen_insert[6][2]) (rtx, rtx, rtx)
+    = {
+       { gen_vec_set_lo_v32qi, gen_vec_set_hi_v32qi },
+       { gen_vec_set_lo_v16hi, gen_vec_set_hi_v16hi },
+       { gen_vec_set_lo_v8si, gen_vec_set_hi_v8si },
+       { gen_vec_set_lo_v4di, gen_vec_set_hi_v4di },
+       { gen_vec_set_lo_v8sf, gen_vec_set_hi_v8sf },
+       { gen_vec_set_lo_v4df, gen_vec_set_hi_v4df }
+      };
+  int i, j, n;
 
   switch (mode)
     {
@@ -24257,7 +28787,7 @@ ix86_expand_vector_set (bool mmx_ok, rtx target, rtx val, int elt)
          /* target = X A B B */
          ix86_expand_vector_set (false, target, val, 0);
          /* target = A X C D  */
-         emit_insn (gen_sse_shufps_1 (target, target, tmp,
+         emit_insn (gen_sse_shufps_v4sf (target, target, tmp,
                                       GEN_INT (1), GEN_INT (0),
                                       GEN_INT (2+4), GEN_INT (3+4)));
          return;
@@ -24268,7 +28798,7 @@ ix86_expand_vector_set (bool mmx_ok, rtx target, rtx val, int elt)
          /* tmp = X B C D */
          ix86_expand_vector_set (false, tmp, val, 0);
          /* target = A B X D */
-         emit_insn (gen_sse_shufps_1 (target, target, tmp,
+         emit_insn (gen_sse_shufps_v4sf (target, target, tmp,
                                       GEN_INT (0), GEN_INT (1),
                                       GEN_INT (0+4), GEN_INT (3+4)));
          return;
@@ -24279,7 +28809,7 @@ ix86_expand_vector_set (bool mmx_ok, rtx target, rtx val, int elt)
          /* tmp = X B C D */
          ix86_expand_vector_set (false, tmp, val, 0);
          /* target = A B X D */
-         emit_insn (gen_sse_shufps_1 (target, target, tmp,
+         emit_insn (gen_sse_shufps_v4sf (target, target, tmp,
                                       GEN_INT (0), GEN_INT (1),
                                       GEN_INT (2+4), GEN_INT (0+4)));
          return;
@@ -24342,6 +28872,62 @@ ix86_expand_vector_set (bool mmx_ok, rtx target, rtx val, int elt)
       break;
 
     case V8QImode:
+      break;
+
+    case V32QImode:
+      half_mode = V16QImode;
+      j = 0;
+      n = 16;
+      goto half;
+
+    case V16HImode:
+      half_mode = V8HImode;
+      j = 1;
+      n = 8;
+      goto half;
+
+    case V8SImode:
+      half_mode = V4SImode;
+      j = 2;
+      n = 4;
+      goto half;
+
+    case V4DImode:
+      half_mode = V2DImode;
+      j = 3;
+      n = 2;
+      goto half;
+
+    case V8SFmode:
+      half_mode = V4SFmode;
+      j = 4;
+      n = 4;
+      goto half;
+
+    case V4DFmode:
+      half_mode = V2DFmode;
+      j = 5;
+      n = 2;
+      goto half;
+
+half:
+      /* Compute offset.  */
+      i = elt / n;
+      elt %= n;
+
+      gcc_assert (i <= 1);
+
+      /* Extract the half.  */
+      tmp = gen_reg_rtx (half_mode);
+      emit_insn ((*gen_extract[j][i]) (tmp, target));
+
+      /* Put val in tmp at elt.  */
+      ix86_expand_vector_set (false, tmp, val, elt);
+
+      /* Put it back.  */
+      emit_insn ((*gen_insert[j][i]) (target, target, tmp));
+      return;
+
     default:
       break;
     }
@@ -24400,7 +28986,7 @@ ix86_expand_vector_extract (bool mmx_ok, rtx target, rtx vec, int elt)
        case 1:
        case 3:
          tmp = gen_reg_rtx (mode);
-         emit_insn (gen_sse_shufps_1 (tmp, vec, vec,
+         emit_insn (gen_sse_shufps_v4sf (tmp, vec, vec,
                                       GEN_INT (elt), GEN_INT (elt),
                                       GEN_INT (elt+4), GEN_INT (elt+4)));
          break;
@@ -24517,7 +29103,7 @@ ix86_expand_reduc_v4sf (rtx (*fn) (rtx, rtx, rtx), rtx dest, rtx in)
   emit_insn (gen_sse_movhlps (tmp1, in, in));
   emit_insn (fn (tmp2, tmp1, in));
 
-  emit_insn (gen_sse_shufps_1 (tmp3, tmp2, tmp2,
+  emit_insn (gen_sse_shufps_v4sf (tmp3, tmp2, tmp2,
                               GEN_INT (1), GEN_INT (1),
                               GEN_INT (1+4), GEN_INT (1+4)));
   emit_insn (fn (dest, tmp2, tmp3));
@@ -24530,7 +29116,7 @@ ix86_scalar_mode_supported_p (enum machine_mode mode)
   if (DECIMAL_FLOAT_MODE_P (mode))
     return true;
   else if (mode == TFmode)
-    return TARGET_64BIT;
+    return true;
   else
     return default_scalar_mode_supported_p (mode);
 }
@@ -24543,6 +29129,8 @@ ix86_vector_mode_supported_p (enum machine_mode mode)
     return true;
   if (TARGET_SSE2 && VALID_SSE2_REG_MODE (mode))
     return true;
+  if (TARGET_AVX && VALID_AVX256_REG_MODE (mode))
+    return true;
   if (TARGET_MMX && VALID_MMX_REG_MODE (mode))
     return true;
   if (TARGET_3DNOW && VALID_MMX_REG_MODE_3DNOW (mode))
@@ -24554,9 +29142,9 @@ ix86_vector_mode_supported_p (enum machine_mode mode)
 static enum machine_mode
 ix86_c_mode_for_suffix (char suffix)
 {
-  if (TARGET_64BIT && suffix == 'q')
+  if (suffix == 'q')
     return TFmode;
-  if (TARGET_MMX && suffix == 'w')
+  if (suffix == 'w')
     return XFmode;
 
   return VOIDmode;
@@ -24619,22 +29207,22 @@ output_387_reg_move (rtx insn, rtx *operands)
          return "fstp\t%y0";
        }
       if (STACK_TOP_P (operands[0]))
-       return "fld%z1\t%y1";
+       return "fld%Z1\t%y1";
       return "fst\t%y0";
     }
   else if (MEM_P (operands[0]))
     {
       gcc_assert (REG_P (operands[1]));
       if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
-       return "fstp%z0\t%y0";
+       return "fstp%Z0\t%y0";
       else
        {
          /* There is no non-popping store to memory for XFmode.
             So if we need one, follow the store with a load.  */
          if (GET_MODE (operands[0]) == XFmode)
-           return "fstp%z0\t%y0\n\tfld%z0\t%y0";
+           return "fstp%Z0\t%y0\n\tfld%Z0\t%y0";
          else
-           return "fst%z0\t%y0";
+           return "fst%Z0\t%y0";
        }
     }
   else
@@ -24652,7 +29240,7 @@ ix86_emit_fp_unordered_jump (rtx label)
 
   emit_insn (gen_x86_fnstsw_1 (reg));
 
-  if (TARGET_SAHF && (TARGET_USE_SAHF || optimize_size))
+  if (TARGET_SAHF && (TARGET_USE_SAHF || optimize_insn_for_size_p ()))
     {
       emit_insn (gen_x86_sahf_1 (reg));
 
@@ -24685,13 +29273,14 @@ void ix86_emit_i387_log1p (rtx op0, rtx op1)
 
   rtx tmp = gen_reg_rtx (XFmode);
   rtx tmp2 = gen_reg_rtx (XFmode);
+  rtx test;
 
   emit_insn (gen_absxf2 (tmp, op1));
-  emit_insn (gen_cmpxf (tmp,
+  test = gen_rtx_GE (VOIDmode, tmp,
     CONST_DOUBLE_FROM_REAL_VALUE (
        REAL_VALUE_ATOF ("0.29289321881345247561810596348408353", XFmode),
-       XFmode)));
-  emit_jump_insn (gen_bge (label1));
+       XFmode));
+  emit_jump_insn (gen_cbranchxf4 (test, XEXP (test, 0), XEXP (test, 1), label1));
 
   emit_move_insn (tmp2, standard_80387_constant_rtx (4)); /* fldln2 */
   emit_insn (gen_fyl2xp1xf3_i387 (op0, op1, tmp2));
@@ -25485,11 +30074,12 @@ ix86_expand_round (rtx operand0, rtx operand1)
    OPERANDS is the array of operands.
    NUM is the number of operands.
    USES_OC0 is true if the instruction uses OC0 and provides 4 variants.
-   NUM_MEMORY is the maximum number of memory operands to accept.  */
+   NUM_MEMORY is the maximum number of memory operands to accept.  
+   when COMMUTATIVE is set, operand 1 and 2 can be swapped.  */
 
 bool
 ix86_sse5_valid_op_p (rtx operands[], rtx insn ATTRIBUTE_UNUSED, int num,
-                     bool uses_oc0, int num_memory)
+                     bool uses_oc0, int num_memory, bool commutative)
 {
   int mem_mask;
   int mem_count;
@@ -25573,6 +30163,8 @@ ix86_sse5_valid_op_p (rtx operands[], rtx insn ATTRIBUTE_UNUSED, int num,
 
       /* format, example pmacsdd:
         xmm1, xmm2, xmm3/mem, xmm1 */
+      if (commutative)
+       return (mem_mask == (1 << 2) || mem_mask == (1 << 1));
       else
        return (mem_mask == (1 << 2));
     }
@@ -25607,6 +30199,8 @@ ix86_sse5_valid_op_p (rtx operands[], rtx insn ATTRIBUTE_UNUSED, int num,
 
          For the integer multiply/add instructions be more restrictive and
          require operands[2] and operands[3] to be the memory operands.  */
+      if (commutative)
+       return (mem_mask == ((1 << 1) | (1 << 3)) || ((1 << 2) | (1 << 3)));
       else
        return (mem_mask == ((1 << 2) | (1 << 3)));
     }
@@ -25700,6 +30294,10 @@ static const struct attribute_spec ix86_attribute_table[] =
 #ifdef SUBTARGET_ATTRIBUTE_TABLE
   SUBTARGET_ATTRIBUTE_TABLE,
 #endif
+  /* ms_abi and sysv_abi calling convention function attributes.  */
+  { "ms_abi", 0, 0, false, true, true, ix86_handle_abi_attribute },
+  { "sysv_abi", 0, 0, false, true, true, ix86_handle_abi_attribute },
+  /* End element.  */
   { NULL,        0, 0, false, false, false, NULL }
 };
 
@@ -25727,7 +30325,132 @@ x86_builtin_vectorization_cost (bool runtime_test)
     return 0;
 }
 
+/* This function returns the calling abi specific va_list type node.
+   It returns  the FNDECL specific va_list type.  */
+
+tree
+ix86_fn_abi_va_list (tree fndecl)
+{
+  if (!TARGET_64BIT)
+    return va_list_type_node;
+  gcc_assert (fndecl != NULL_TREE);
+
+  if (ix86_function_abi ((const_tree) fndecl) == MS_ABI)
+    return ms_va_list_type_node;
+  else
+    return sysv_va_list_type_node;
+}
+
+/* Returns the canonical va_list type specified by TYPE. If there
+   is no valid TYPE provided, it return NULL_TREE.  */
+
+tree
+ix86_canonical_va_list_type (tree type)
+{
+  tree wtype, htype;
+
+  /* Resolve references and pointers to va_list type.  */
+  if (INDIRECT_REF_P (type))
+    type = TREE_TYPE (type);
+  else if (POINTER_TYPE_P (type) && POINTER_TYPE_P (TREE_TYPE(type)))
+    type = TREE_TYPE (type);
+
+  if (TARGET_64BIT)
+    {
+      wtype = va_list_type_node;
+         gcc_assert (wtype != NULL_TREE);
+      htype = type;
+      if (TREE_CODE (wtype) == ARRAY_TYPE)
+       {
+         /* If va_list is an array type, the argument may have decayed
+            to a pointer type, e.g. by being passed to another function.
+            In that case, unwrap both types so that we can compare the
+            underlying records.  */
+         if (TREE_CODE (htype) == ARRAY_TYPE
+             || POINTER_TYPE_P (htype))
+           {
+             wtype = TREE_TYPE (wtype);
+             htype = TREE_TYPE (htype);
+           }
+       }
+      if (TYPE_MAIN_VARIANT (wtype) == TYPE_MAIN_VARIANT (htype))
+       return va_list_type_node;
+      wtype = sysv_va_list_type_node;
+         gcc_assert (wtype != NULL_TREE);
+      htype = type;
+      if (TREE_CODE (wtype) == ARRAY_TYPE)
+       {
+         /* If va_list is an array type, the argument may have decayed
+            to a pointer type, e.g. by being passed to another function.
+            In that case, unwrap both types so that we can compare the
+            underlying records.  */
+         if (TREE_CODE (htype) == ARRAY_TYPE
+             || POINTER_TYPE_P (htype))
+           {
+             wtype = TREE_TYPE (wtype);
+             htype = TREE_TYPE (htype);
+           }
+       }
+      if (TYPE_MAIN_VARIANT (wtype) == TYPE_MAIN_VARIANT (htype))
+       return sysv_va_list_type_node;
+      wtype = ms_va_list_type_node;
+         gcc_assert (wtype != NULL_TREE);
+      htype = type;
+      if (TREE_CODE (wtype) == ARRAY_TYPE)
+       {
+         /* If va_list is an array type, the argument may have decayed
+            to a pointer type, e.g. by being passed to another function.
+            In that case, unwrap both types so that we can compare the
+            underlying records.  */
+         if (TREE_CODE (htype) == ARRAY_TYPE
+             || POINTER_TYPE_P (htype))
+           {
+             wtype = TREE_TYPE (wtype);
+             htype = TREE_TYPE (htype);
+           }
+       }
+      if (TYPE_MAIN_VARIANT (wtype) == TYPE_MAIN_VARIANT (htype))
+       return ms_va_list_type_node;
+      return NULL_TREE;
+    }
+  return std_canonical_va_list_type (type);
+}
+
+/* Iterate through the target-specific builtin types for va_list.
+    IDX denotes the iterator, *PTREE is set to the result type of
+    the va_list builtin, and *PNAME to its internal type.
+    Returns zero if there is no element for this index, otherwise
+    IDX should be increased upon the next call.
+    Note, do not iterate a base builtin's name like __builtin_va_list.
+    Used from c_common_nodes_and_builtins.  */
+
+int
+ix86_enum_va_list (int idx, const char **pname, tree *ptree)
+{
+  if (!TARGET_64BIT)
+    return 0;
+  switch (idx) {
+  case 0:
+    *ptree = ms_va_list_type_node;
+    *pname = "__builtin_ms_va_list";
+    break;
+  case 1:
+    *ptree = sysv_va_list_type_node;
+    *pname = "__builtin_sysv_va_list";
+    break;
+  default:
+    return 0;
+  }
+  return 1;
+}
+
 /* Initialize the GCC target structure.  */
+#undef TARGET_RETURN_IN_MEMORY
+#define TARGET_RETURN_IN_MEMORY ix86_return_in_memory
+
+#undef TARGET_LEGITIMIZE_ADDRESS
+#define TARGET_LEGITIMIZE_ADDRESS ix86_legitimize_address
+
 #undef TARGET_ATTRIBUTE_TABLE
 #define TARGET_ATTRIBUTE_TABLE ix86_attribute_table
 #if TARGET_DLLIMPORT_DECL_ATTRIBUTES
@@ -25849,9 +30572,18 @@ x86_builtin_vectorization_cost (bool runtime_test)
 #undef TARGET_MACHINE_DEPENDENT_REORG
 #define TARGET_MACHINE_DEPENDENT_REORG ix86_reorg
 
+#undef TARGET_BUILTIN_SETJMP_FRAME_VALUE
+#define TARGET_BUILTIN_SETJMP_FRAME_VALUE ix86_builtin_setjmp_frame_value
+
 #undef TARGET_BUILD_BUILTIN_VA_LIST
 #define TARGET_BUILD_BUILTIN_VA_LIST ix86_build_builtin_va_list
 
+#undef TARGET_FN_ABI_VA_LIST
+#define TARGET_FN_ABI_VA_LIST ix86_fn_abi_va_list
+
+#undef TARGET_CANONICAL_VA_LIST_TYPE
+#define TARGET_CANONICAL_VA_LIST_TYPE ix86_canonical_va_list_type
+
 #undef TARGET_EXPAND_BUILTIN_VA_START
 #define TARGET_EXPAND_BUILTIN_VA_START ix86_va_start
 
@@ -25870,8 +30602,10 @@ x86_builtin_vectorization_cost (bool runtime_test)
 #define TARGET_PASS_BY_REFERENCE ix86_pass_by_reference
 #undef TARGET_INTERNAL_ARG_POINTER
 #define TARGET_INTERNAL_ARG_POINTER ix86_internal_arg_pointer
-#undef TARGET_DWARF_HANDLE_FRAME_UNSPEC
-#define TARGET_DWARF_HANDLE_FRAME_UNSPEC ix86_dwarf_handle_frame_unspec
+#undef TARGET_UPDATE_STACK_BOUNDARY
+#define TARGET_UPDATE_STACK_BOUNDARY ix86_update_stack_boundary
+#undef TARGET_GET_DRAP_RTX
+#define TARGET_GET_DRAP_RTX ix86_get_drap_rtx
 #undef TARGET_STRICT_ARGUMENT_NAMING
 #define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true
 
@@ -25912,6 +30646,36 @@ x86_builtin_vectorization_cost (bool runtime_test)
 #undef TARGET_VECTORIZE_BUILTIN_VECTORIZATION_COST
 #define TARGET_VECTORIZE_BUILTIN_VECTORIZATION_COST x86_builtin_vectorization_cost
 
+#undef TARGET_SET_CURRENT_FUNCTION
+#define TARGET_SET_CURRENT_FUNCTION ix86_set_current_function
+
+#undef TARGET_OPTION_VALID_ATTRIBUTE_P
+#define TARGET_OPTION_VALID_ATTRIBUTE_P ix86_valid_target_attribute_p
+
+#undef TARGET_OPTION_SAVE
+#define TARGET_OPTION_SAVE ix86_function_specific_save
+
+#undef TARGET_OPTION_RESTORE
+#define TARGET_OPTION_RESTORE ix86_function_specific_restore
+
+#undef TARGET_OPTION_PRINT
+#define TARGET_OPTION_PRINT ix86_function_specific_print
+
+#undef TARGET_CAN_INLINE_P
+#define TARGET_CAN_INLINE_P ix86_can_inline_p
+
+#undef TARGET_EXPAND_TO_RTL_HOOK
+#define TARGET_EXPAND_TO_RTL_HOOK ix86_maybe_switch_abi
+
+#undef TARGET_LEGITIMATE_ADDRESS_P
+#define TARGET_LEGITIMATE_ADDRESS_P ix86_legitimate_address_p
+
+#undef TARGET_IRA_COVER_CLASSES
+#define TARGET_IRA_COVER_CLASSES i386_ira_cover_classes
+
+#undef TARGET_FRAME_POINTER_REQUIRED
+#define TARGET_FRAME_POINTER_REQUIRED ix86_frame_pointer_required
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 #include "gt-i386.h"