OSDN Git Service

PR bootstrap/43511
[pf3gnuchains/gcc-fork.git] / gcc / config / i386 / i386.c
index 1926c50..35b4c49 100644 (file)
@@ -53,6 +53,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tm-constrs.h"
 #include "params.h"
 #include "cselib.h"
+#include "debug.h"
+#include "dwarf2out.h"
 
 static rtx legitimize_dllimport_symbol (rtx, bool);
 
@@ -1456,7 +1458,7 @@ static unsigned int initial_ix86_tune_features[X86_TUNE_LAST] = {
   m_AMD_MULTIPLE,
 
   /* X86_TUNE_INTER_UNIT_MOVES */
-  ~(m_AMD_MULTIPLE | m_ATOM | m_GENERIC),
+  ~(m_AMD_MULTIPLE | m_GENERIC),
 
   /* X86_TUNE_INTER_UNIT_CONVERSIONS */
   ~(m_AMDFAM10),
@@ -1910,6 +1912,10 @@ static unsigned int ix86_minimum_incoming_stack_boundary (bool);
 static enum calling_abi ix86_function_abi (const_tree);
 
 \f
+#ifndef SUBTARGET32_DEFAULT_CPU
+#define SUBTARGET32_DEFAULT_CPU "i386"
+#endif
+
 /* The svr4 ABI for the i386 says that records and unions are returned
    in memory.  */
 #ifndef DEFAULT_PCC_STRUCT_RETURN
@@ -2400,7 +2406,7 @@ ix86_handle_option (size_t code, const char *arg ATTRIBUTE_UNUSED, int value)
     }
 }
 \f
-/* Return a string the documents the current -m options.  The caller is
+/* Return a string that documents the current -m options.  The caller is
    responsible for freeing the string.  */
 
 static char *
@@ -2419,6 +2425,7 @@ ix86_target_string (int isa, int flags, const char *arch, const char *tune,
   {
     { "-m64",          OPTION_MASK_ISA_64BIT },
     { "-mfma4",                OPTION_MASK_ISA_FMA4 },
+    { "-mfma",         OPTION_MASK_ISA_FMA },
     { "-mxop",         OPTION_MASK_ISA_XOP },
     { "-mlwp",         OPTION_MASK_ISA_LWP },
     { "-msse4a",       OPTION_MASK_ISA_SSE4A },
@@ -2621,6 +2628,7 @@ override_options (bool main_args_p)
 {
   int i;
   unsigned int ix86_arch_mask, ix86_tune_mask;
+  const bool ix86_tune_specified = (ix86_tune_string != NULL); 
   const char *prefix;
   const char *suffix;
   const char *sw;
@@ -2821,8 +2829,12 @@ override_options (bool main_args_p)
                   || !strcmp (ix86_tune_string, "generic64")))
        ;
       else if (!strncmp (ix86_tune_string, "generic", 7))
-       error ("bad value (%s) for %stune=%s %s",
+        error ("bad value (%s) for %stune=%s %s",
               ix86_tune_string, prefix, suffix, sw);
+      else if (!strcmp (ix86_tune_string, "x86-64"))
+        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);
     }
   else
     {
@@ -2846,6 +2858,7 @@ override_options (bool main_args_p)
            ix86_tune_string = "generic32";
        }
     }
+
   if (ix86_stringop_string)
     {
       if (!strcmp (ix86_stringop_string, "rep_byte"))
@@ -2868,23 +2881,12 @@ override_options (bool main_args_p)
        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, "%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";
+    ix86_arch_string = TARGET_64BIT ? "x86-64" : SUBTARGET32_DEFAULT_CPU;
   else
     ix86_arch_specified = 1;
 
-  if (!strcmp (ix86_arch_string, "generic"))
-    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 %sarch=%s %s",
-          ix86_arch_string, prefix, suffix, sw);
-
   /* Validate -mabi= value.  */
   if (ix86_abi_string)
     {
@@ -3032,7 +3034,10 @@ override_options (bool main_args_p)
        break;
       }
 
-  if (i == pta_size)
+  if (!strcmp (ix86_arch_string, "generic"))
+    error ("generic CPU can be used only for %stune=%s %s",
+          prefix, suffix, sw);
+  else if (!strncmp (ix86_arch_string, "generic", 7) || i == pta_size)
     error ("bad value (%s) for %sarch=%s %s",
           ix86_arch_string, prefix, suffix, sw);
 
@@ -3071,7 +3076,8 @@ override_options (bool main_args_p)
          x86_prefetch_sse = true;
        break;
       }
-  if (i == pta_size)
+
+  if (ix86_tune_specified && i == pta_size)
     error ("bad value (%s) for %stune=%s %s",
           ix86_tune_string, prefix, suffix, sw);
 
@@ -3191,8 +3197,6 @@ override_options (bool main_args_p)
        ix86_tls_dialect = TLS_DIALECT_GNU;
       else if (strcmp (ix86_tls_dialect_string, "gnu2") == 0)
        ix86_tls_dialect = TLS_DIALECT_GNU2;
-      else if (strcmp (ix86_tls_dialect_string, "sun") == 0)
-       ix86_tls_dialect = TLS_DIALECT_SUN;
       else
        error ("bad value (%s) for %stls-dialect=%s %s",
               ix86_tls_dialect_string, prefix, suffix, sw);
@@ -7576,8 +7580,8 @@ get_pc_thunk_name (char name[32], unsigned int regno)
 /* This function generates code for -fpic that loads %ebx with
    the return address of the caller and then returns.  */
 
-void
-ix86_file_end (void)
+static void
+ix86_code_end (void)
 {
   rtx xops[2];
   int regno;
@@ -7585,12 +7589,21 @@ ix86_file_end (void)
   for (regno = 0; regno < 8; ++regno)
     {
       char name[32];
+      tree decl;
 
       if (! ((pic_labels_used >> regno) & 1))
        continue;
 
       get_pc_thunk_name (name, regno);
 
+      decl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL,
+                        get_identifier (name),
+                        build_function_type (void_type_node, void_list_node));
+      DECL_RESULT (decl) = build_decl (BUILTINS_LOCATION, RESULT_DECL,
+                                      NULL_TREE, void_type_node);
+      TREE_PUBLIC (decl) = 1;
+      TREE_STATIC (decl) = 1;
+
 #if TARGET_MACHO
       if (TARGET_MACHO)
        {
@@ -7601,18 +7614,12 @@ ix86_file_end (void)
          assemble_name (asm_out_file, name);
          fputs ("\n", asm_out_file);
          ASM_OUTPUT_LABEL (asm_out_file, name);
+         DECL_WEAK (decl) = 1;
        }
       else
 #endif
       if (USE_HIDDEN_LINKONCE)
        {
-         tree decl;
-
-         decl = build_decl (BUILTINS_LOCATION,
-                            FUNCTION_DECL, get_identifier (name),
-                            error_mark_node);
-         TREE_PUBLIC (decl) = 1;
-         TREE_STATIC (decl) = 1;
          DECL_COMDAT_GROUP (decl) = DECL_ASSEMBLER_NAME (decl);
 
          (*targetm.asm_out.unique_section) (decl, 0);
@@ -7630,14 +7637,23 @@ ix86_file_end (void)
          ASM_OUTPUT_LABEL (asm_out_file, name);
        }
 
+      DECL_INITIAL (decl) = make_node (BLOCK);
+      current_function_decl = decl;
+      init_function_start (decl);
+      first_function_block_is_cold = false;
+      /* Make sure unwind info is emitted for the thunk if needed.  */
+      final_start_function (emit_barrier (), asm_out_file, 1);
+
       xops[0] = gen_rtx_REG (Pmode, regno);
       xops[1] = gen_rtx_MEM (Pmode, stack_pointer_rtx);
       output_asm_insn ("mov%z0\t{%1, %0|%0, %1}", xops);
       output_asm_insn ("ret", xops);
+      final_end_function ();
+      init_insn_lengths ();
+      free_after_compilation (cfun);
+      set_cfun (NULL);
+      current_function_decl = NULL;
     }
-
-  if (NEED_INDICATE_EXEC_STACK)
-    file_end_indicate_exec_stack ();
 }
 
 /* Emit code for the SET_GOT patterns.  */
@@ -7674,7 +7690,24 @@ output_set_got (rtx dest, rtx label ATTRIBUTE_UNUSED)
       if (!flag_pic)
        output_asm_insn ("mov%z0\t{%2, %0|%0, %2}", xops);
       else
-       output_asm_insn ("call\t%a2", xops);
+       {
+         output_asm_insn ("call\t%a2", xops);
+#ifdef DWARF2_UNWIND_INFO
+         /* The call to next label acts as a push.  */
+         if (dwarf2out_do_frame ())
+           {
+             rtx insn;
+             start_sequence ();
+             insn = emit_insn (gen_rtx_SET (VOIDmode, stack_pointer_rtx,
+                                            gen_rtx_PLUS (Pmode,
+                                                          stack_pointer_rtx,
+                                                          GEN_INT (-4))));
+             RTX_FRAME_RELATED_P (insn) = 1;
+             dwarf2out_frame_debug (insn, true);
+             end_sequence ();
+           }
+#endif
+       }
 
 #if TARGET_MACHO
       /* Output the Mach-O "canonical" label name ("Lxx$pb") here too.  This
@@ -7687,7 +7720,27 @@ output_set_got (rtx dest, rtx label ATTRIBUTE_UNUSED)
                                 CODE_LABEL_NUMBER (XEXP (xops[2], 0)));
 
       if (flag_pic)
-       output_asm_insn ("pop%z0\t%0", xops);
+       {
+         output_asm_insn ("pop%z0\t%0", xops);
+#ifdef DWARF2_UNWIND_INFO
+         /* The pop is a pop and clobbers dest, but doesn't restore it
+            for unwind info purposes.  */
+         if (dwarf2out_do_frame ())
+           {
+             rtx insn;
+             start_sequence ();
+             insn = emit_insn (gen_rtx_SET (VOIDmode, dest, const0_rtx));
+             dwarf2out_frame_debug (insn, true);
+             insn = emit_insn (gen_rtx_SET (VOIDmode, stack_pointer_rtx,
+                                            gen_rtx_PLUS (Pmode,
+                                                          stack_pointer_rtx,
+                                                          GEN_INT (4))));
+             RTX_FRAME_RELATED_P (insn) = 1;
+             dwarf2out_frame_debug (insn, true);
+             end_sequence ();
+           }
+#endif
+       }
     }
   else
     {
@@ -7695,6 +7748,18 @@ output_set_got (rtx dest, rtx label ATTRIBUTE_UNUSED)
       get_pc_thunk_name (name, REGNO (dest));
       pic_labels_used |= 1 << REGNO (dest);
 
+#ifdef DWARF2_UNWIND_INFO
+      /* Ensure all queued register saves are flushed before the
+        call.  */
+      if (dwarf2out_do_frame ())
+       {
+         rtx insn;
+         start_sequence ();
+         insn = emit_barrier ();
+         end_sequence ();
+         dwarf2out_frame_debug (insn, false);
+       }
+#endif
       xops[2] = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (name));
       xops[2] = gen_rtx_MEM (QImode, xops[2]);
       output_asm_insn ("call\t%X2", xops);
@@ -8331,7 +8396,11 @@ ix86_get_drap_rtx (void)
       end_sequence ();
       
       insn = emit_insn_before (seq, NEXT_INSN (entry_of_function ()));
-      RTX_FRAME_RELATED_P (insn) = 1;
+      if (!optimize)
+       {
+         add_reg_note (insn, REG_CFA_SET_VDRAP, drap_vreg);
+         RTX_FRAME_RELATED_P (insn) = 1;
+       }
       return drap_vreg;
     }
   else
@@ -10794,29 +10863,29 @@ output_pic_addr_const (FILE *file, rtx x, int code)
          break;
        case UNSPEC_GOTTPOFF:
          /* FIXME: This might be @TPOFF in Sun ld too.  */
-         fputs ("@GOTTPOFF", file);
+         fputs ("@gottpoff", file);
          break;
        case UNSPEC_TPOFF:
-         fputs ("@TPOFF", file);
+         fputs ("@tpoff", file);
          break;
        case UNSPEC_NTPOFF:
          if (TARGET_64BIT)
-           fputs ("@TPOFF", file);
+           fputs ("@tpoff", file);
          else
-           fputs ("@NTPOFF", file);
+           fputs ("@ntpoff", file);
          break;
        case UNSPEC_DTPOFF:
-         fputs ("@DTPOFF", file);
+         fputs ("@dtpoff", file);
          break;
        case UNSPEC_GOTNTPOFF:
          if (TARGET_64BIT)
            fputs (ASSEMBLER_DIALECT == ASM_ATT ?
-                  "@GOTTPOFF(%rip)": "@GOTTPOFF[rip]", file);
+                  "@gottpoff(%rip)": "@gottpoff[rip]", file);
          else
-           fputs ("@GOTNTPOFF", file);
+           fputs ("@gotntpoff", file);
          break;
        case UNSPEC_INDNTPOFF:
-         fputs ("@INDNTPOFF", file);
+         fputs ("@indntpoff", file);
          break;
 #if TARGET_MACHO
        case UNSPEC_MACHOPIC_OFFSET:
@@ -10843,7 +10912,7 @@ i386_output_dwarf_dtprel (FILE *file, int size, rtx x)
 {
   fputs (ASM_LONG, file);
   output_addr_const (file, x);
-  fputs ("@DTPOFF", file);
+  fputs ("@dtpoff", file);
   switch (size)
     {
     case 4:
@@ -10884,6 +10953,9 @@ static rtx
 ix86_delegitimize_address (rtx x)
 {
   rtx orig_x = delegitimize_mem_from_attrs (x);
+  /* addend is NULL or some rtx if x is something+GOTOFF where
+     something doesn't include the PIC register.  */
+  rtx addend = NULL_RTX;
   /* reg_addend is NULL or a multiple of some register.  */
   rtx reg_addend = NULL_RTX;
   /* const_addend is NULL or a const_int.  */
@@ -10922,14 +10994,13 @@ ix86_delegitimize_address (rtx x)
       else if (ix86_pic_register_p (XEXP (reg_addend, 1)))
        reg_addend = XEXP (reg_addend, 0);
       else
-       return orig_x;
-      if (!REG_P (reg_addend)
-         && GET_CODE (reg_addend) != MULT
-         && GET_CODE (reg_addend) != ASHIFT)
-       return orig_x;
+       {
+         reg_addend = NULL_RTX;
+         addend = XEXP (x, 0);
+       }
     }
   else
-    return orig_x;
+    addend = XEXP (x, 0);
 
   x = XEXP (XEXP (x, 1), 0);
   if (GET_CODE (x) == PLUS
@@ -10940,7 +11011,7 @@ ix86_delegitimize_address (rtx x)
     }
 
   if (GET_CODE (x) == UNSPEC
-      && ((XINT (x, 1) == UNSPEC_GOT && MEM_P (orig_x))
+      && ((XINT (x, 1) == UNSPEC_GOT && MEM_P (orig_x) && !addend)
          || (XINT (x, 1) == UNSPEC_GOTOFF && !MEM_P (orig_x))))
     result = XVECEXP (x, 0, 0);
 
@@ -10955,6 +11026,22 @@ ix86_delegitimize_address (rtx x)
     result = gen_rtx_CONST (Pmode, gen_rtx_PLUS (Pmode, result, const_addend));
   if (reg_addend)
     result = gen_rtx_PLUS (Pmode, reg_addend, result);
+  if (addend)
+    {
+      /* If the rest of original X doesn't involve the PIC register, add
+        addend and subtract pic_offset_table_rtx.  This can happen e.g.
+        for code like:
+        leal (%ebx, %ecx, 4), %ecx
+        ...
+        movl foo@GOTOFF(%ecx), %edx
+        in which case we return (%ecx - %ebx) + foo.  */
+      if (pic_offset_table_rtx)
+        result = gen_rtx_PLUS (Pmode, gen_rtx_MINUS (Pmode, copy_rtx (addend),
+                                                    pic_offset_table_rtx),
+                              result);
+      else
+       return orig_x;
+    }
   return result;
 }
 
@@ -12102,34 +12189,34 @@ output_addr_const_extra (FILE *file, rtx x)
     case UNSPEC_GOTTPOFF:
       output_addr_const (file, op);
       /* FIXME: This might be @TPOFF in Sun ld.  */
-      fputs ("@GOTTPOFF", file);
+      fputs ("@gottpoff", file);
       break;
     case UNSPEC_TPOFF:
       output_addr_const (file, op);
-      fputs ("@TPOFF", file);
+      fputs ("@tpoff", file);
       break;
     case UNSPEC_NTPOFF:
       output_addr_const (file, op);
       if (TARGET_64BIT)
-       fputs ("@TPOFF", file);
+       fputs ("@tpoff", file);
       else
-       fputs ("@NTPOFF", file);
+       fputs ("@ntpoff", file);
       break;
     case UNSPEC_DTPOFF:
       output_addr_const (file, op);
-      fputs ("@DTPOFF", file);
+      fputs ("@dtpoff", file);
       break;
     case UNSPEC_GOTNTPOFF:
       output_addr_const (file, op);
       if (TARGET_64BIT)
        fputs (ASSEMBLER_DIALECT == ASM_ATT ?
-              "@GOTTPOFF(%rip)" : "@GOTTPOFF[rip]", file);
+              "@gottpoff(%rip)" : "@gottpoff[rip]", file);
       else
-       fputs ("@GOTNTPOFF", file);
+       fputs ("@gotntpoff", file);
       break;
     case UNSPEC_INDNTPOFF:
       output_addr_const (file, op);
-      fputs ("@INDNTPOFF", file);
+      fputs ("@indntpoff", file);
       break;
 #if TARGET_MACHO
     case UNSPEC_MACHOPIC_OFFSET:
@@ -13387,16 +13474,6 @@ ix86_fixup_binary_operands (enum rtx_code code, enum machine_mode mode,
   if (MEM_P (src1) && !rtx_equal_p (dst, src1))
     src1 = force_reg (mode, src1);
 
-  /* In order for the multiply-add patterns to get matched, we need
-     to aid combine by forcing all operands into registers to start.  */
-  if (optimize && TARGET_FMA4)
-    {
-      if (MEM_P (src2))
-       src2 = force_reg (GET_MODE (src2), src2);
-      else if (MEM_P (src1))
-       src1 = force_reg (GET_MODE (src1), src1);
-    }
-
   operands[1] = src1;
   operands[2] = src2;
   return dst;
@@ -15391,7 +15468,7 @@ ix86_expand_int_movcc (rtx operands[])
   enum rtx_code code = GET_CODE (operands[1]), compare_code;
   rtx compare_seq, compare_op;
   enum machine_mode mode = GET_MODE (operands[0]);
-  bool sign_bit_compare_p = false;;
+  bool sign_bit_compare_p = false;
 
   start_sequence ();
   ix86_compare_op0 = XEXP (operands[1], 0);
@@ -15432,7 +15509,6 @@ ix86_expand_int_movcc (rtx operands[])
           if (!sign_bit_compare_p)
            {
              rtx flags;
-             rtx (*insn)(rtx, rtx, rtx);
              bool fpcmp = false;
 
              compare_code = GET_CODE (compare_op);
@@ -15473,11 +15549,10 @@ ix86_expand_int_movcc (rtx operands[])
                tmp = gen_reg_rtx (mode);
 
              if (mode == DImode)
-               insn = gen_x86_movdicc_0_m1;
+               emit_insn (gen_x86_movdicc_0_m1 (tmp, flags, compare_op));
              else
-               insn = gen_x86_movsicc_0_m1;
-
-             emit_insn (insn (tmp, flags, compare_op));
+               emit_insn (gen_x86_movsicc_0_m1 (gen_lowpart (SImode, tmp),
+                                                flags, compare_op));
            }
          else
            {
@@ -20970,6 +21045,10 @@ enum ix86_builtins
   IX86_BUILTIN_VPERMILPS,
   IX86_BUILTIN_VPERMILPD256,
   IX86_BUILTIN_VPERMILPS256,
+  IX86_BUILTIN_VPERMIL2PD,
+  IX86_BUILTIN_VPERMIL2PS,
+  IX86_BUILTIN_VPERMIL2PD256,
+  IX86_BUILTIN_VPERMIL2PS256,
   IX86_BUILTIN_VPERM2F128PD256,
   IX86_BUILTIN_VPERM2F128PS256,
   IX86_BUILTIN_VPERM2F128SI256,
@@ -22159,6 +22238,10 @@ static const struct builtin_description bdesc_args[] =
 };
 
 /* FMA4 and XOP.  */
+#define MULTI_ARG_4_DF2_DI_I   V2DF_FTYPE_V2DF_V2DF_V2DI_INT
+#define MULTI_ARG_4_DF2_DI_I1  V4DF_FTYPE_V4DF_V4DF_V4DI_INT
+#define MULTI_ARG_4_SF2_SI_I   V4SF_FTYPE_V4SF_V4SF_V4SI_INT
+#define MULTI_ARG_4_SF2_SI_I1  V8SF_FTYPE_V8SF_V8SF_V8SI_INT
 #define MULTI_ARG_3_SF         V4SF_FTYPE_V4SF_V4SF_V4SF
 #define MULTI_ARG_3_DF         V2DF_FTYPE_V2DF_V2DF_V2DF
 #define MULTI_ARG_3_SF2                V8SF_FTYPE_V8SF_V8SF_V8SF
@@ -22401,6 +22484,11 @@ static const struct builtin_description bdesc_multi_arg[] =
   { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pcom_tfv4si3,      "__builtin_ia32_vpcomtrueud", IX86_BUILTIN_VPCOMTRUEUD, (enum rtx_code) PCOM_TRUE,    (int)MULTI_ARG_2_SI_TF },
   { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pcom_tfv2di3,      "__builtin_ia32_vpcomtrueuq", IX86_BUILTIN_VPCOMTRUEUQ, (enum rtx_code) PCOM_TRUE,    (int)MULTI_ARG_2_DI_TF },
 
+  { OPTION_MASK_ISA_AVX, CODE_FOR_xop_vpermil2v2df3,     "__builtin_ia32_vpermil2pd",  IX86_BUILTIN_VPERMIL2PD, UNKNOWN, (int)MULTI_ARG_4_DF2_DI_I },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_xop_vpermil2v4sf3,     "__builtin_ia32_vpermil2ps",  IX86_BUILTIN_VPERMIL2PS, UNKNOWN, (int)MULTI_ARG_4_SF2_SI_I },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_xop_vpermil2v4df3,     "__builtin_ia32_vpermil2pd256", IX86_BUILTIN_VPERMIL2PD256, UNKNOWN, (int)MULTI_ARG_4_DF2_DI_I1 },
+  { OPTION_MASK_ISA_AVX, CODE_FOR_xop_vpermil2v8sf3,     "__builtin_ia32_vpermil2ps256", IX86_BUILTIN_VPERMIL2PS256, UNKNOWN, (int)MULTI_ARG_4_SF2_SI_I1 },
+
 };
 
 /* Set up all the MMX/SSE builtins, even builtins for instructions that are not
@@ -22781,6 +22869,14 @@ ix86_expand_multi_arg_builtin (enum insn_code icode, tree exp, rtx target,
 
   switch (m_type)
     {
+    case MULTI_ARG_4_DF2_DI_I:
+    case MULTI_ARG_4_DF2_DI_I1:
+    case MULTI_ARG_4_SF2_SI_I:
+    case MULTI_ARG_4_SF2_SI_I1:
+      nargs = 4;
+      last_arg_constant = true;
+      break;
+
     case MULTI_ARG_3_SF:
     case MULTI_ARG_3_DF:
     case MULTI_ARG_3_SF2:
@@ -22924,6 +23020,10 @@ ix86_expand_multi_arg_builtin (enum insn_code icode, tree exp, rtx target,
       pat = GEN_FCN (icode) (target, args[0].op, args[1].op, args[2].op);
       break;
 
+    case 4:
+      pat = GEN_FCN (icode) (target, args[0].op, args[1].op, args[2].op, args[3].op);
+      break;
+
     default:
       gcc_unreachable ();
     }
@@ -23542,6 +23642,13 @@ ix86_expand_args_builtin (const struct builtin_description *d,
       nargs = 3;
       nargs_constant = 2;
       break;
+    case MULTI_ARG_4_DF2_DI_I:
+    case MULTI_ARG_4_DF2_DI_I1:
+    case MULTI_ARG_4_SF2_SI_I:
+    case MULTI_ARG_4_SF2_SI_I1:
+      nargs = 4;
+      nargs_constant = 1;
+      break;
     case V2DI_FTYPE_V2DI_V2DI_UINT_UINT:
       nargs = 4;
       nargs_constant = 2;
@@ -23611,6 +23718,10 @@ ix86_expand_args_builtin (const struct builtin_description *d,
 
              case CODE_FOR_sse4_1_blendpd:
              case CODE_FOR_avx_vpermilv2df:
+             case CODE_FOR_xop_vpermil2v2df3:
+             case CODE_FOR_xop_vpermil2v4sf3:
+             case CODE_FOR_xop_vpermil2v4df3:
+             case CODE_FOR_xop_vpermil2v8sf3:
                error ("the last argument must be a 2-bit immediate");
                return const0_rtx;
 
@@ -24632,7 +24743,7 @@ avx_vpermilp_parallel (rtx par, enum machine_mode mode)
       if (!CONST_INT_P (er))
        return 0;
       ei = INTVAL (er);
-      if (ei >= 2 * nelt)
+      if (ei >= nelt)
        return 0;
       ipar[i] = ei;
     }
@@ -25827,13 +25938,6 @@ machopic_output_stub (FILE *file, const char *symb, const char *stub)
   fprintf (file, "\t.indirect_symbol %s\n", symbol_name);
   fprintf (file, ASM_LONG "%s\n", binder_name);
 }
-
-void
-darwin_x86_file_end (void)
-{
-  darwin_file_end ();
-  ix86_file_end ();
-}
 #endif /* TARGET_MACHO */
 
 /* Order the registers for register allocator.  */
@@ -26080,7 +26184,7 @@ x86_can_output_mi_thunk (const_tree thunk ATTRIBUTE_UNUSED,
    *(*this + vcall_offset) should be added to THIS.  */
 
 static void
-x86_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED,
+x86_output_mi_thunk (FILE *file,
                     tree thunk ATTRIBUTE_UNUSED, HOST_WIDE_INT delta,
                     HOST_WIDE_INT vcall_offset, tree function)
 {
@@ -26088,6 +26192,9 @@ x86_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED,
   rtx this_param = x86_this_parameter (function);
   rtx this_reg, tmp;
 
+  /* Make sure unwind info is emitted for the thunk if needed.  */
+  final_start_function (emit_barrier (), file, 1);
+
   /* If VCALL_OFFSET, we'll need THIS in a register.  Might as well
      pull it in now and let DELTA benefit.  */
   if (REG_P (this_param))
@@ -26216,6 +26323,7 @@ x86_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED,
          output_asm_insn ("jmp\t{*}%1", xops);
        }
     }
+  final_end_function ();
 }
 
 static void
@@ -26257,7 +26365,7 @@ x86_function_profiler (FILE *file, int labelno ATTRIBUTE_UNUSED)
   if (TARGET_64BIT)
     {
 #ifndef NO_PROFILE_COUNTERS
-      fprintf (file, "\tleaq\t" LPREFIX "P%d@(%%rip),%%r11\n", labelno);
+      fprintf (file, "\tleaq\t" LPREFIX "P%d(%%rip),%%r11\n", labelno);
 #endif
 
       if (DEFAULT_ABI == SYSV_ABI && flag_pic)
@@ -26654,8 +26762,16 @@ ix86_expand_vector_init_duplicate (bool mmx_ok, enum machine_mode mode,
        insn = emit_insn (gen_rtx_SET (VOIDmode, target, dup));
        if (recog_memoized (insn) < 0)
          {
+           rtx seq;
            /* If that fails, force VAL into a register.  */
+
+           start_sequence ();
            XEXP (dup, 0) = force_reg (GET_MODE_INNER (mode), val);
+           seq = get_insns ();
+           end_sequence ();
+           if (seq)
+             emit_insn_before (seq, insn);
+
            ok = recog_memoized (insn) >= 0;
            gcc_assert (ok);
          }
@@ -29095,8 +29211,8 @@ expand_vec_perm_blend (struct expand_vec_perm_d *d)
     do_subreg:
       vmode = V8HImode;
       target = gen_lowpart (vmode, target);
-      op0 = gen_lowpart (vmode, target);
-      op1 = gen_lowpart (vmode, target);
+      op0 = gen_lowpart (vmode, op0);
+      op1 = gen_lowpart (vmode, op1);
       break;
 
     default:
@@ -29104,7 +29220,7 @@ expand_vec_perm_blend (struct expand_vec_perm_d *d)
     }
 
   /* This matches five different patterns with the different modes.  */
-  x = gen_rtx_VEC_MERGE (vmode, op0, op1, GEN_INT (mask));
+  x = gen_rtx_VEC_MERGE (vmode, op1, op0, GEN_INT (mask));
   x = gen_rtx_SET (VOIDmode, target, x);
   emit_insn (x);
 
@@ -29216,7 +29332,12 @@ expand_vec_perm_1 (struct expand_vec_perm_d *d)
      input where SEL+CONCAT may not.  */
   if (d->op0 == d->op1)
     {
-      if (expand_vselect (d->target, d->op0, d->perm, nelt))
+      int mask = nelt - 1;
+
+      for (i = 0; i < nelt; i++)
+       perm2[i] = d->perm[i] & mask;
+
+      if (expand_vselect (d->target, d->op0, perm2, nelt))
        return true;
 
       /* There are plenty of patterns in sse.md that are written for
@@ -29227,8 +29348,8 @@ expand_vec_perm_1 (struct expand_vec_perm_d *d)
         every other permutation operand.  */
       for (i = 0; i < nelt; i += 2)
        {
-         perm2[i] = d->perm[i];
-         perm2[i+1] = d->perm[i+1] + nelt;
+         perm2[i] = d->perm[i] & mask;
+         perm2[i + 1] = (d->perm[i + 1] & mask) + nelt;
        }
       if (expand_vselect_vconcat (d->target, d->op0, d->op0, perm2, nelt))
        return true;
@@ -29236,11 +29357,12 @@ expand_vec_perm_1 (struct expand_vec_perm_d *d)
       /* Recognize shufps, which means adding {0, 0, nelt, nelt}.  */
       if (nelt >= 4)
        {
-         memcpy (perm2, d->perm, nelt);
-         for (i = 2; i < nelt; i += 4)
+         for (i = 0; i < nelt; i += 4)
            {
-             perm2[i+0] += nelt;
-             perm2[i+1] += nelt;
+             perm2[i + 0] = d->perm[i + 0] & mask;
+             perm2[i + 1] = d->perm[i + 1] & mask;
+             perm2[i + 2] = (d->perm[i + 2] & mask) + nelt;
+             perm2[i + 3] = (d->perm[i + 3] & mask) + nelt;
            }
 
          if (expand_vselect_vconcat (d->target, d->op0, d->op0, perm2, nelt))
@@ -30421,6 +30543,9 @@ ix86_enum_va_list (int idx, const char **pname, tree *ptree)
 #undef TARGET_CAN_ELIMINATE
 #define TARGET_CAN_ELIMINATE ix86_can_eliminate
 
+#undef TARGET_ASM_CODE_END
+#define TARGET_ASM_CODE_END ix86_code_end
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 #include "gt-i386.h"