OSDN Git Service

Some SSE fixes
[pf3gnuchains/gcc-fork.git] / gcc / config / i386 / i386.c
index 163b36e..caccc7e 100644 (file)
@@ -20,7 +20,6 @@ the Free Software Foundation, 59 Temple Place - Suite 330,
 Boston, MA 02111-1307, USA.  */
 
 #include "config.h"
-#include <setjmp.h>
 #include "system.h"
 #include "rtl.h"
 #include "tree.h"
@@ -37,15 +36,54 @@ Boston, MA 02111-1307, USA.  */
 #include "function.h"
 #include "recog.h"
 #include "expr.h"
+#include "optabs.h"
 #include "toplev.h"
 #include "basic-block.h"
 #include "ggc.h"
+#include "target.h"
+#include "target-def.h"
 
 #ifndef CHECK_STACK_LIMIT
 #define CHECK_STACK_LIMIT -1
 #endif
 
 /* Processor costs (relative to an add) */
+static const 
+struct processor_costs size_cost = {   /* costs for tunning for size */
+  2,                                   /* cost of an add instruction */
+  3,                                   /* cost of a lea instruction */
+  2,                                   /* variable shift costs */
+  3,                                   /* constant shift costs */
+  3,                                   /* cost of starting a multiply */
+  0,                                   /* cost of multiply per each bit set */
+  3,                                   /* cost of a divide/mod */
+  3,                                   /* cost of movsx */
+  3,                                   /* cost of movzx */
+  0,                                   /* "large" insn */
+  2,                                   /* MOVE_RATIO */
+  2,                                   /* cost for loading QImode using movzbl */
+  {2, 2, 2},                           /* cost of loading integer registers
+                                          in QImode, HImode and SImode.
+                                          Relative to reg-reg move (2).  */
+  {2, 2, 2},                           /* cost of storing integer registers */
+  2,                                   /* cost of reg,reg fld/fst */
+  {2, 2, 2},                           /* cost of loading fp registers
+                                          in SFmode, DFmode and XFmode */
+  {2, 2, 2},                           /* cost of loading integer registers */
+  3,                                   /* cost of moving MMX register */
+  {3, 3},                              /* cost of loading MMX registers
+                                          in SImode and DImode */
+  {3, 3},                              /* cost of storing MMX registers
+                                          in SImode and DImode */
+  3,                                   /* cost of moving SSE register */
+  {3, 3, 3},                           /* cost of loading SSE registers
+                                          in SImode, DImode and TImode */
+  {3, 3, 3},                           /* cost of storing SSE registers
+                                          in SImode, DImode and TImode */
+  3,                                   /* MMX or SSE register to integer */
+};
+/* Processor costs (relative to an add) */
+static const 
 struct processor_costs i386_cost = {   /* 386 specific costs */
   1,                                   /* cost of an add instruction */
   1,                                   /* cost of a lea instruction */
@@ -54,6 +92,8 @@ struct processor_costs i386_cost = {  /* 386 specific costs */
   6,                                   /* cost of starting a multiply */
   1,                                   /* cost of multiply per each bit set */
   23,                                  /* cost of a divide/mod */
+  3,                                   /* cost of movsx */
+  2,                                   /* cost of movzx */
   15,                                  /* "large" insn */
   3,                                   /* MOVE_RATIO */
   4,                                   /* cost for loading QImode using movzbl */
@@ -78,6 +118,7 @@ struct processor_costs i386_cost = { /* 386 specific costs */
   3,                                   /* MMX or SSE register to integer */
 };
 
+static const 
 struct processor_costs i486_cost = {   /* 486 specific costs */
   1,                                   /* cost of an add instruction */
   1,                                   /* cost of a lea instruction */
@@ -86,6 +127,8 @@ struct processor_costs i486_cost = { /* 486 specific costs */
   12,                                  /* cost of starting a multiply */
   1,                                   /* cost of multiply per each bit set */
   40,                                  /* cost of a divide/mod */
+  3,                                   /* cost of movsx */
+  2,                                   /* cost of movzx */
   15,                                  /* "large" insn */
   3,                                   /* MOVE_RATIO */
   4,                                   /* cost for loading QImode using movzbl */
@@ -110,6 +153,7 @@ struct processor_costs i486_cost = {        /* 486 specific costs */
   3                                    /* MMX or SSE register to integer */
 };
 
+static const 
 struct processor_costs pentium_cost = {
   1,                                   /* cost of an add instruction */
   1,                                   /* cost of a lea instruction */
@@ -118,6 +162,8 @@ struct processor_costs pentium_cost = {
   11,                                  /* cost of starting a multiply */
   0,                                   /* cost of multiply per each bit set */
   25,                                  /* cost of a divide/mod */
+  3,                                   /* cost of movsx */
+  2,                                   /* cost of movzx */
   8,                                   /* "large" insn */
   6,                                   /* MOVE_RATIO */
   6,                                   /* cost for loading QImode using movzbl */
@@ -142,6 +188,7 @@ struct processor_costs pentium_cost = {
   3                                    /* MMX or SSE register to integer */
 };
 
+static const 
 struct processor_costs pentiumpro_cost = {
   1,                                   /* cost of an add instruction */
   1,                                   /* cost of a lea instruction */
@@ -150,6 +197,8 @@ struct processor_costs pentiumpro_cost = {
   4,                                   /* cost of starting a multiply */
   0,                                   /* cost of multiply per each bit set */
   17,                                  /* cost of a divide/mod */
+  1,                                   /* cost of movsx */
+  1,                                   /* cost of movzx */
   8,                                   /* "large" insn */
   6,                                   /* MOVE_RATIO */
   2,                                   /* cost for loading QImode using movzbl */
@@ -174,6 +223,7 @@ struct processor_costs pentiumpro_cost = {
   3                                    /* MMX or SSE register to integer */
 };
 
+static const 
 struct processor_costs k6_cost = {
   1,                                   /* cost of an add instruction */
   2,                                   /* cost of a lea instruction */
@@ -182,6 +232,8 @@ struct processor_costs k6_cost = {
   3,                                   /* cost of starting a multiply */
   0,                                   /* cost of multiply per each bit set */
   18,                                  /* cost of a divide/mod */
+  2,                                   /* cost of movsx */
+  2,                                   /* cost of movzx */
   8,                                   /* "large" insn */
   4,                                   /* MOVE_RATIO */
   3,                                   /* cost for loading QImode using movzbl */
@@ -206,6 +258,7 @@ struct processor_costs k6_cost = {
   6                                    /* MMX or SSE register to integer */
 };
 
+static const 
 struct processor_costs athlon_cost = {
   1,                                   /* cost of an add instruction */
   2,                                   /* cost of a lea instruction */
@@ -214,6 +267,8 @@ struct processor_costs athlon_cost = {
   5,                                   /* cost of starting a multiply */
   0,                                   /* cost of multiply per each bit set */
   42,                                  /* cost of a divide/mod */
+  1,                                   /* cost of movsx */
+  1,                                   /* cost of movzx */
   8,                                   /* "large" insn */
   9,                                   /* MOVE_RATIO */
   4,                                   /* cost for loading QImode using movzbl */
@@ -238,6 +293,7 @@ struct processor_costs athlon_cost = {
   6                                    /* MMX or SSE register to integer */
 };
 
+static const 
 struct processor_costs pentium4_cost = {
   1,                                   /* cost of an add instruction */
   1,                                   /* cost of a lea instruction */
@@ -246,6 +302,8 @@ struct processor_costs pentium4_cost = {
   30,                                  /* cost of starting a multiply */
   0,                                   /* cost of multiply per each bit set */
   112,                                 /* cost of a divide/mod */
+  1,                                   /* cost of movsx */
+  1,                                   /* cost of movzx */
   16,                                  /* "large" insn */
   6,                                   /* MOVE_RATIO */
   2,                                   /* cost for loading QImode using movzbl */
@@ -270,7 +328,7 @@ struct processor_costs pentium4_cost = {
   10,                                  /* MMX or SSE register to integer */
 };
 
-struct processor_costs *ix86_cost = &pentium_cost;
+const struct processor_costs *ix86_cost = &pentium_cost;
 
 /* Processor feature/optimization bitmasks.  */
 #define m_386 (1<<PROCESSOR_I386)
@@ -289,7 +347,9 @@ const int x86_double_with_add = ~m_386;
 const int x86_use_bit_test = m_386;
 const int x86_unroll_strlen = m_486 | m_PENT | m_PPRO | m_ATHLON | m_K6;
 const int x86_cmove = m_PPRO | m_ATHLON | m_PENT4;
+const int x86_3dnow_a = m_ATHLON;
 const int x86_deep_branch = m_PPRO | m_K6 | m_ATHLON | m_PENT4;
+const int x86_branch_hints = m_PENT4;
 const int x86_use_sahf = m_PPRO | m_K6 | m_PENT4;
 const int x86_partial_reg_stall = m_PPRO;
 const int x86_use_loop = m_K6;
@@ -312,12 +372,24 @@ const int x86_add_esp_8 = m_ATHLON | m_PPRO | m_K6 | m_386 | m_486 | m_PENT4;
 const int x86_integer_DFmode_moves = ~(m_ATHLON | m_PENT4);
 const int x86_partial_reg_dependency = m_ATHLON | m_PENT4;
 const int x86_memory_mismatch_stall = m_ATHLON | m_PENT4;
+const int x86_accumulate_outgoing_args = m_ATHLON | m_PENT4 | m_PPRO;
+const int x86_prologue_using_move = m_ATHLON | m_PENT4 | m_PPRO;
+const int x86_epilogue_using_move = m_ATHLON | m_PENT4 | m_PPRO;
+const int x86_decompose_lea = m_PENT4;
+
+/* In case the avreage insn count for single function invocation is
+   lower than this constant, emit fast (but longer) prologue and
+   epilogue code.  */
+#define FAST_PROLOGUE_INSN_COUNT 30
+/* Set by prologue expander and used by epilogue expander to determine
+   the style used.  */
+static int use_fast_prologue_epilogue;
 
 #define AT_BP(mode) (gen_rtx_MEM ((mode), hard_frame_pointer_rtx))
 
-const char * const hi_reg_name[] = HI_REGISTER_NAMES;
-const char * const qi_reg_name[] = QI_REGISTER_NAMES;
-const char * const qi_high_reg_name[] = QI_HIGH_REGISTER_NAMES;
+static const char *const hi_reg_name[] = HI_REGISTER_NAMES; /* names for 16 bit regs */
+static const char *const qi_reg_name[] = QI_REGISTER_NAMES; /* names for 8 bit regs (low) */
+static const char *const qi_high_reg_name[] = QI_HIGH_REGISTER_NAMES; /* names for 8 bit regs (high) */
 
 /* Array of the smallest class containing reg number REGNO, indexed by
    REGNO.  Used by REGNO_REG_CLASS in i386.h.  */
@@ -358,6 +430,12 @@ int const dbx_register_map[FIRST_PSEUDO_REGISTER] =
   -1, -1, -1, -1, -1, -1, -1, -1,      /* extended SSE registers */
 };
 
+static int 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 x86_64_int_return_registers[4] = {0 /*RAX*/, 1 /*RDI*/, 5, 4};
+
 /* The "default" register map used in 64bit mode.  */
 int const dbx64_register_map[FIRST_PSEUDO_REGISTER] =
 {
@@ -441,7 +519,7 @@ int const svr4_dbx_register_map[FIRST_PSEUDO_REGISTER] =
 struct rtx_def *ix86_compare_op0 = NULL_RTX;
 struct rtx_def *ix86_compare_op1 = NULL_RTX;
 
-#define MAX_386_STACK_LOCALS 2
+#define MAX_386_STACK_LOCALS 3
 /* Size of the register save area.  */
 #define X86_64_VARARGS_SIZE (REGPARM_MAX * UNITS_PER_WORD + SSE_REGPARM_MAX * 16)
 
@@ -532,15 +610,13 @@ int ix86_branch_cost;
 const char *ix86_branch_cost_string;
 
 /* Power of two alignment for functions.  */
-int ix86_align_funcs;
 const char *ix86_align_funcs_string;
 
-/* Power of two alignment for loops.  */
-int ix86_align_loops;
-
-/* Power of two alignment for non-loop jumps.  */
-int ix86_align_jumps;
+/* Prefix built by ASM_GENERATE_INTERNAL_LABEL.  */
+static char internal_label_prefix[16];
+static int internal_label_prefix_len;
 \f
+static int local_symbolic_operand PARAMS ((rtx, enum machine_mode));
 static void output_pic_addr_const PARAMS ((FILE *, rtx, int));
 static void put_condition_code PARAMS ((enum rtx_code, enum machine_mode,
                                       int, int, FILE *));
@@ -566,16 +642,20 @@ static int ix86_split_to_parts PARAMS ((rtx, rtx *, enum machine_mode));
 static int ix86_safe_length_prefix PARAMS ((rtx));
 static int ix86_nsaved_regs PARAMS((void));
 static void ix86_emit_save_regs PARAMS((void));
-static void ix86_emit_restore_regs_using_mov PARAMS ((rtx, int, bool));
-static void ix86_emit_epilogue_esp_adjustment PARAMS((int));
+static void ix86_emit_save_regs_using_mov PARAMS ((rtx, HOST_WIDE_INT));
+static void ix86_emit_restore_regs_using_mov PARAMS ((rtx, int, int));
 static void ix86_set_move_mem_attrs_1 PARAMS ((rtx, rtx, rtx, rtx, rtx));
 static void ix86_sched_reorder_pentium PARAMS((rtx *, rtx *));
 static void ix86_sched_reorder_ppro PARAMS((rtx *, rtx *));
 static HOST_WIDE_INT ix86_GOT_alias_set PARAMS ((void));
 static void ix86_adjust_counter PARAMS ((rtx, HOST_WIDE_INT));
-static rtx ix86_zero_extend_to_Pmode PARAMS ((rtx));
 static rtx ix86_expand_aligntest PARAMS ((rtx, int));
 static void ix86_expand_strlensi_unroll_1 PARAMS ((rtx, rtx));
+static int ix86_issue_rate PARAMS ((void));
+static int ix86_adjust_cost PARAMS ((rtx, rtx, rtx, int));
+static void ix86_sched_init PARAMS ((FILE *, int, int));
+static int ix86_sched_reorder PARAMS ((FILE *, int, rtx *, int *, int));
+static int ix86_variable_issue PARAMS ((FILE *, int, rtx, int));
 
 struct ix86_address
 {
@@ -586,10 +666,10 @@ struct ix86_address
 static int ix86_decompose_address PARAMS ((rtx, struct ix86_address *));
 
 struct builtin_description;
-static rtx ix86_expand_sse_comi PARAMS ((struct builtin_description *, tree,
-                                        rtx));
-static rtx ix86_expand_sse_compare PARAMS ((struct builtin_description *, tree,
-                                           rtx));
+static rtx ix86_expand_sse_comi PARAMS ((const struct builtin_description *,
+                                        tree, rtx));
+static rtx ix86_expand_sse_compare PARAMS ((const struct builtin_description *,
+                                           tree, rtx));
 static rtx ix86_expand_unop1_builtin PARAMS ((enum insn_code, tree, rtx));
 static rtx ix86_expand_unop_builtin PARAMS ((enum insn_code, tree, rtx, int));
 static rtx ix86_expand_binop_builtin PARAMS ((enum insn_code, tree, rtx));
@@ -606,8 +686,93 @@ static int ix86_fp_comparison_arithmetics_cost PARAMS ((enum rtx_code code));
 static int ix86_fp_comparison_fcomi_cost PARAMS ((enum rtx_code code));
 static int ix86_fp_comparison_sahf_cost PARAMS ((enum rtx_code code));
 static int ix86_fp_comparison_cost PARAMS ((enum rtx_code code));
-static int ix86_save_reg PARAMS ((int, bool));
+static int ix86_save_reg PARAMS ((int, int));
 static void ix86_compute_frame_layout PARAMS ((struct ix86_frame *));
+static int ix86_comp_type_attributes PARAMS ((tree, tree));
+const struct attribute_spec ix86_attribute_table[];
+static tree ix86_handle_cdecl_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree ix86_handle_regparm_attribute PARAMS ((tree *, tree, tree, int, bool *));
+
+#ifdef DO_GLOBAL_CTORS_BODY
+static void ix86_svr3_asm_out_constructor PARAMS ((rtx, int));
+#endif
+
+/* Register class used for passing given 64bit part of the argument.
+   These represent classes as documented by the PS ABI, with the exception
+   of SSESF, SSEDF classes, that are basically SSE class, just gcc will
+   use SF or DFmode move instead of DImode to avoid reformating penalties.
+
+   Similary we play games with INTEGERSI_CLASS to use cheaper SImode moves
+   whenever possible (upper half does contain padding).
+ */
+enum x86_64_reg_class
+  {
+    X86_64_NO_CLASS,
+    X86_64_INTEGER_CLASS,
+    X86_64_INTEGERSI_CLASS,
+    X86_64_SSE_CLASS,
+    X86_64_SSESF_CLASS,
+    X86_64_SSEDF_CLASS,
+    X86_64_SSEUP_CLASS,
+    X86_64_X87_CLASS,
+    X86_64_X87UP_CLASS,
+    X86_64_MEMORY_CLASS
+  };
+const char * const x86_64_reg_class_name[] =
+   {"no", "integer", "integerSI", "sse", "sseSF", "sseDF", "sseup", "x87", "x87up", "no"};
+
+#define MAX_CLASSES 4
+static int classify_argument PARAMS ((enum machine_mode, tree,
+                                     enum x86_64_reg_class [MAX_CLASSES],
+                                     int));
+static int examine_argument PARAMS ((enum machine_mode, tree, int, int *,
+                                    int *));
+static rtx construct_container PARAMS ((enum machine_mode, tree, int, int, int,
+                                       int *, int));
+static enum x86_64_reg_class merge_classes PARAMS ((enum x86_64_reg_class,
+                                                   enum x86_64_reg_class));
+\f
+/* Initialize the GCC target structure.  */
+#undef TARGET_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE ix86_attribute_table
+#ifdef TARGET_DLLIMPORT_DECL_ATTRIBUTES
+#  undef TARGET_MERGE_DECL_ATTRIBUTES
+#  define TARGET_MERGE_DECL_ATTRIBUTES merge_dllimport_decl_attributes
+#endif
+
+#undef TARGET_COMP_TYPE_ATTRIBUTES
+#define TARGET_COMP_TYPE_ATTRIBUTES ix86_comp_type_attributes
+
+#undef TARGET_INIT_BUILTINS
+#define TARGET_INIT_BUILTINS ix86_init_builtins
+
+#undef TARGET_EXPAND_BUILTIN
+#define TARGET_EXPAND_BUILTIN ix86_expand_builtin
+
+#if defined (OSF_OS) || defined (TARGET_OSF1ELF)
+   static void ix86_osf_output_function_prologue PARAMS ((FILE *,
+                                                         HOST_WIDE_INT));
+#  undef TARGET_ASM_FUNCTION_PROLOGUE
+#  define TARGET_ASM_FUNCTION_PROLOGUE ix86_osf_output_function_prologue
+#endif
+
+#undef TARGET_ASM_OPEN_PAREN
+#define TARGET_ASM_OPEN_PAREN ""
+#undef TARGET_ASM_CLOSE_PAREN
+#define TARGET_ASM_CLOSE_PAREN ""
+
+#undef TARGET_SCHED_ADJUST_COST
+#define TARGET_SCHED_ADJUST_COST ix86_adjust_cost
+#undef TARGET_SCHED_ISSUE_RATE
+#define TARGET_SCHED_ISSUE_RATE ix86_issue_rate
+#undef TARGET_SCHED_VARIABLE_ISSUE
+#define TARGET_SCHED_VARIABLE_ISSUE ix86_variable_issue
+#undef TARGET_SCHED_INIT
+#define TARGET_SCHED_INIT ix86_sched_init
+#undef TARGET_SCHED_REORDER
+#define TARGET_SCHED_REORDER ix86_sched_reorder
+
+struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 /* Sometimes certain combinations of command options do not make
    sense on a particular target machine.  You can define a macro
@@ -627,29 +792,31 @@ override_options ()
 
   static struct ptt
     {
-      struct processor_costs *cost;    /* Processor costs */
-      int target_enable;               /* Target flags to enable.  */
-      int target_disable;              /* Target flags to disable.  */
-      int align_loop;                  /* Default alignments.  */
-      int align_jump;
-      int align_func;
-      int branch_cost;
+      const struct processor_costs *cost;      /* Processor costs */
+      const int target_enable;                 /* Target flags to enable.  */
+      const int target_disable;                        /* Target flags to disable.  */
+      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 int branch_cost;
     }
   const processor_target_table[PROCESSOR_max] =
     {
-      {&i386_cost, 0, 0, 2, 2, 2, 1},
-      {&i486_cost, 0, 0, 4, 4, 4, 1},
-      {&pentium_cost, 0, 0, -4, -4, -4, 1},
-      {&pentiumpro_cost, 0, 0, 4, -4, 4, 1},
-      {&k6_cost, 0, 0, -5, -5, 4, 1},
-      {&athlon_cost, 0, 0, 4, -4, 4, 1},
-      {&pentium4_cost, 0, 0, 2, 2, 2, 1}
+      {&i386_cost, 0, 0, 4, 3, 4, 3, 4, 1},
+      {&i486_cost, 0, 0, 16, 15, 16, 15, 16, 1},
+      {&pentium_cost, 0, 0, 16, 7, 16, 7, 16, 1},
+      {&pentiumpro_cost, 0, 0, 16, 15, 16, 7, 16, 1},
+      {&k6_cost, 0, 0, 32, 7, 32, 7, 32, 1},
+      {&athlon_cost, 0, 0, 16, 7, 64, 7, 16, 1},
+      {&pentium4_cost, 0, 0, 0, 0, 0, 0, 0, 1}
     };
 
   static struct pta
     {
-      const char *name;                /* processor name or nickname.  */
-      enum processor_type processor;
+      const char *const name;          /* processor name or nickname.  */
+      const enum processor_type processor;
     }
   const processor_alias_table[] =
     {
@@ -701,6 +868,9 @@ override_options ()
           ix86_cmodel_string, TARGET_64BIT ? "64" : "32");
   if (ix86_cmodel == CM_LARGE)
     sorry ("Code model `large' not supported yet.");
+  if ((TARGET_64BIT != 0) != ((target_flags & MASK_64BIT) != 0))
+    sorry ("%i-bit mode not compiled in.",
+          (target_flags & MASK_64BIT) ? 64 : 32);
 
   if (ix86_arch_string != 0)
     {
@@ -729,7 +899,10 @@ override_options ()
        error ("bad value (%s) for -mcpu= switch", ix86_cpu_string);
     }
 
-  ix86_cost = processor_target_table[ix86_cpu].cost;
+  if (optimize_size)
+    ix86_cost = &size_cost;
+  else
+    ix86_cost = processor_target_table[ix86_cpu].cost;
   target_flags |= processor_target_table[ix86_cpu].target_enable;
   target_flags &= ~processor_target_table[ix86_cpu].target_disable;
 
@@ -751,48 +924,77 @@ override_options ()
    if (TARGET_64BIT)
      ix86_regparm = REGPARM_MAX;
 
-  /* Validate -malign-loops= value, or provide default.  */
-  ix86_align_loops = processor_target_table[ix86_cpu].align_loop;
+  /* If the user has provided any of the -malign-* options,
+     warn and use that value only if -falign-* is not set.
+     Remove this code in GCC 3.2 or later.  */
   if (ix86_align_loops_string)
     {
-      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);
-      else
-       ix86_align_loops = i;
+      warning ("-malign-loops is obsolete, use -falign-loops");
+      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);
+         else
+           align_loops = 1 << i;
+       }
     }
 
-  /* Validate -malign-jumps= value, or provide default.  */
-  ix86_align_jumps = processor_target_table[ix86_cpu].align_jump;
   if (ix86_align_jumps_string)
     {
-      i = atoi (ix86_align_jumps_string);
-      if (i < 0 || i > MAX_CODE_ALIGN)
-       error ("-malign-jumps=%d is not between 0 and %d", i, MAX_CODE_ALIGN);
-      else
-       ix86_align_jumps = i;
+      warning ("-malign-jumps is obsolete, use -falign-jumps");
+      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);
+         else
+           align_jumps = 1 << i;
+       }
     }
 
-  /* Validate -malign-functions= value, or provide default.  */
-  ix86_align_funcs = processor_target_table[ix86_cpu].align_func;
   if (ix86_align_funcs_string)
     {
-      i = atoi (ix86_align_funcs_string);
-      if (i < 0 || i > MAX_CODE_ALIGN)
-       error ("-malign-functions=%d is not between 0 and %d",
-              i, MAX_CODE_ALIGN);
-      else
-       ix86_align_funcs = i;
+      warning ("-malign-functions is obsolete, use -falign-functions");
+      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);
+         else
+           align_functions = 1 << i;
+       }
+    }
+
+  /* Default align_* from the processor table.  */
+#define abs(n) (n < 0 ? -n : n)
+  if (align_loops == 0)
+    {
+      align_loops = processor_target_table[ix86_cpu].align_loop;
+      align_loops_max_skip = processor_target_table[ix86_cpu].align_loop_max_skip;
+    }
+  if (align_jumps == 0)
+    {
+      align_jumps = processor_target_table[ix86_cpu].align_jump;
+      align_jumps_max_skip = processor_target_table[ix86_cpu].align_jump_max_skip;
+    }
+  if (align_functions == 0)
+    {
+      align_functions = processor_target_table[ix86_cpu].align_func;
     }
 
   /* Validate -mpreferred-stack-boundary= value, or provide default.
-     The default of 128 bits is for Pentium III's SSE __m128.  */
-  ix86_preferred_stack_boundary = 128;
+     The default of 128 bits is for Pentium III's SSE __m128, but we
+     don't want additional code to keep the stack aligned when
+     optimizing for code size.  */
+  ix86_preferred_stack_boundary = (optimize_size
+                                  ? TARGET_64BIT ? 64 : 32
+                                  : 128);
   if (ix86_preferred_stack_boundary_string)
     {
       i = atoi (ix86_preferred_stack_boundary_string);
-      if (i < (TARGET_64BIT ? 3 : 2) || i > 31)
-       error ("-mpreferred-stack-boundary=%d is not between %d and 31", i,
+      if (i < (TARGET_64BIT ? 3 : 2) || i > 12)
+       error ("-mpreferred-stack-boundary=%d is not between %d and 12", i,
               TARGET_64BIT ? 3 : 2);
       else
        ix86_preferred_stack_boundary = (1 << i) * BITS_PER_UNIT;
@@ -818,10 +1020,43 @@ override_options ()
   if (flag_unsafe_math_optimizations)
     target_flags &= ~MASK_IEEE_FP;
 
+  if (TARGET_64BIT)
+    {
+      if (TARGET_ALIGN_DOUBLE)
+       error ("-malign-double makes no sense in the 64bit mode.");
+      if (TARGET_RTD)
+       error ("-mrtd calling convention not supported in the 64bit mode.");
+      /* Enable by default the SSE and MMX builtins.  */
+      target_flags |= MASK_SSE2 | MASK_SSE | MASK_MMX | MASK_128BIT_LONG_DOUBLE;
+     }
+
   /* It makes no sense to ask for just SSE builtins, so MMX is also turned
      on by -msse.  */
   if (TARGET_SSE)
     target_flags |= MASK_MMX;
+
+  /* If it has 3DNow! it also has MMX so MMX is also turned on by -m3dnow */
+  if (TARGET_3DNOW)
+    {
+      target_flags |= MASK_MMX;
+      /* If we are targetting the Athlon architecture, enable the 3Dnow/MMX
+        extensions it adds.  */
+      if (x86_3dnow_a & (1 << ix86_arch))
+       target_flags |= MASK_3DNOW_A;
+    }
+  if ((x86_accumulate_outgoing_args & CPUMASK)
+      && !(target_flags & MASK_NO_ACCUMULATE_OUTGOING_ARGS)
+      && !optimize_size)
+    target_flags |= MASK_ACCUMULATE_OUTGOING_ARGS;
+
+  /* Figure out what ASM_GENERATE_INTERNAL_LABEL builds as a prefix.  */
+  {
+    char *p;
+    ASM_GENERATE_INTERNAL_LABEL (internal_label_prefix, "LX", 0);
+    p = strchr (internal_label_prefix, 'X');
+    internal_label_prefix_len = p - internal_label_prefix;
+    *p = '\0';
+  }
 }
 \f
 void
@@ -835,85 +1070,215 @@ optimization_options (level, size)
   if (level > 1)
     flag_schedule_insns = 0;
 #endif
+  if (TARGET_64BIT && optimize >= 1)
+    flag_omit_frame_pointer = 1;
+  if (TARGET_64BIT)
+    {
+      flag_pcc_struct_return = 0;
+      flag_asynchronous_unwind_tables = 1;
+    }
 }
 \f
-/* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine specific
-   attribute for DECL.  The attributes in ATTRIBUTES have previously been
-   assigned to DECL.  */
+/* Table of valid machine attributes.  */
+const struct attribute_spec ix86_attribute_table[] =
+{
+  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+  /* Stdcall attribute says callee is responsible for popping arguments
+     if they are not variable.  */
+  { "stdcall",   0, 0, false, true,  true,  ix86_handle_cdecl_attribute },
+  /* Cdecl attribute says the callee is a normal C declaration */
+  { "cdecl",     0, 0, false, true,  true,  ix86_handle_cdecl_attribute },
+  /* Regparm attribute specifies how many integer arguments are to be
+     passed in registers.  */
+  { "regparm",   1, 1, false, true,  true,  ix86_handle_regparm_attribute },
+#ifdef TARGET_DLLIMPORT_DECL_ATTRIBUTES
+  { "dllimport", 0, 0, false, false, false, ix86_handle_dll_attribute },
+  { "dllexport", 0, 0, false, false, false, ix86_handle_dll_attribute },
+  { "shared",    0, 0, true,  false, false, ix86_handle_shared_attribute },
+#endif
+  { NULL,        0, 0, false, false, false, NULL }
+};
 
-int
-ix86_valid_decl_attribute_p (decl, attributes, identifier, args)
-     tree decl ATTRIBUTE_UNUSED;
-     tree attributes ATTRIBUTE_UNUSED;
-     tree identifier ATTRIBUTE_UNUSED;
+/* Handle a "cdecl" or "stdcall" attribute;
+   arguments as in struct attribute_spec.handler.  */
+static tree
+ix86_handle_cdecl_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
      tree args ATTRIBUTE_UNUSED;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
 {
-  return 0;
-}
+  if (TREE_CODE (*node) != FUNCTION_TYPE
+      && TREE_CODE (*node) != METHOD_TYPE
+      && TREE_CODE (*node) != FIELD_DECL
+      && TREE_CODE (*node) != TYPE_DECL)
+    {
+      warning ("`%s' attribute only applies to functions",
+              IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
 
-/* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine specific
-   attribute for TYPE.  The attributes in ATTRIBUTES have previously been
-   assigned to TYPE.  */
+  if (TARGET_64BIT)
+    {
+      warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
 
-int
-ix86_valid_type_attribute_p (type, attributes, identifier, args)
-     tree type;
-     tree attributes ATTRIBUTE_UNUSED;
-     tree identifier;
+  return NULL_TREE;
+}
+
+/* Handle a "regparm" attribute;
+   arguments as in struct attribute_spec.handler.  */
+static tree
+ix86_handle_regparm_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
      tree args;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
 {
-  if (TREE_CODE (type) != FUNCTION_TYPE
-      && TREE_CODE (type) != METHOD_TYPE
-      && TREE_CODE (type) != FIELD_DECL
-      && TREE_CODE (type) != TYPE_DECL)
-    return 0;
+  if (TREE_CODE (*node) != FUNCTION_TYPE
+      && TREE_CODE (*node) != METHOD_TYPE
+      && TREE_CODE (*node) != FIELD_DECL
+      && TREE_CODE (*node) != TYPE_DECL)
+    {
+      warning ("`%s' attribute only applies to functions",
+              IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
+  else
+    {
+      tree cst;
 
-  /* Stdcall attribute says callee is responsible for popping arguments
-     if they are not variable.  */
-  if (is_attribute_p ("stdcall", identifier)
-      && !TARGET_64BIT)
-    return (args == NULL_TREE);
+      cst = TREE_VALUE (args);
+      if (TREE_CODE (cst) != INTEGER_CST)
+       {
+         warning ("`%s' attribute requires an integer constant argument",
+                  IDENTIFIER_POINTER (name));
+         *no_add_attrs = true;
+       }
+      else if (compare_tree_int (cst, REGPARM_MAX) > 0)
+       {
+         warning ("argument to `%s' attribute larger than %d",
+                  IDENTIFIER_POINTER (name), REGPARM_MAX);
+         *no_add_attrs = true;
+       }
+    }
 
-  /* Cdecl attribute says the callee is a normal C declaration.  */
-  if (is_attribute_p ("cdecl", identifier)
-      && !TARGET_64BIT)
-    return (args == NULL_TREE);
+  return NULL_TREE;
+}
 
-  /* Regparm attribute specifies how many integer arguments are to be
-     passed in registers.  */
-  if (is_attribute_p ("regparm", identifier))
+#if defined (OSF_OS) || defined (TARGET_OSF1ELF)
+
+/* Generate the assembly code for function entry.  FILE is a stdio
+   stream to output the code to.  SIZE is an int: how many units of
+   temporary storage to allocate.
+
+   Refer to the array `regs_ever_live' to determine which registers to
+   save; `regs_ever_live[I]' is nonzero if register number I is ever
+   used in the function.  This function is responsible for knowing
+   which registers should not be saved even if used.
+
+   We override it here to allow for the new profiling code to go before
+   the prologue and the old mcount code to go after the prologue (and
+   after %ebx has been set up for ELF shared library support).  */
+
+static void
+ix86_osf_output_function_prologue (file, size)
+     FILE *file;
+     HOST_WIDE_INT size;
+{
+  const char *prefix = "";
+  const char *const lprefix = LPREFIX;
+  int labelno = profile_label_no;
+
+#ifdef OSF_OS
+
+  if (TARGET_UNDERSCORES)
+    prefix = "_";
+
+  if (profile_flag && OSF_PROFILE_BEFORE_PROLOGUE)
     {
-      tree cst;
+      if (!flag_pic && !HALF_PIC_P ())
+       {
+         fprintf (file, "\tmovl $%sP%d,%%edx\n", lprefix, labelno);
+         fprintf (file, "\tcall *%s_mcount_ptr\n", prefix);
+       }
 
-      if (! args || TREE_CODE (args) != TREE_LIST
-         || TREE_CHAIN (args) != NULL_TREE
-         || TREE_VALUE (args) == NULL_TREE)
-       return 0;
+      else if (HALF_PIC_P ())
+       {
+         rtx symref;
 
-      cst = TREE_VALUE (args);
-      if (TREE_CODE (cst) != INTEGER_CST)
-       return 0;
+         HALF_PIC_EXTERNAL ("_mcount_ptr");
+         symref = HALF_PIC_PTR (gen_rtx_SYMBOL_REF (Pmode,
+                                                    "_mcount_ptr"));
 
-      if (compare_tree_int (cst, REGPARM_MAX) > 0)
-       return 0;
+         fprintf (file, "\tmovl $%sP%d,%%edx\n", lprefix, labelno);
+         fprintf (file, "\tmovl %s%s,%%eax\n", prefix,
+                  XSTR (symref, 0));
+         fprintf (file, "\tcall *(%%eax)\n");
+       }
 
-      return 1;
+      else
+       {
+         static int call_no = 0;
+
+         fprintf (file, "\tcall %sPc%d\n", lprefix, call_no);
+         fprintf (file, "%sPc%d:\tpopl %%eax\n", lprefix, call_no);
+         fprintf (file, "\taddl $_GLOBAL_OFFSET_TABLE_+[.-%sPc%d],%%eax\n",
+                  lprefix, call_no++);
+         fprintf (file, "\tleal %sP%d@GOTOFF(%%eax),%%edx\n",
+                  lprefix, labelno);
+         fprintf (file, "\tmovl %s_mcount_ptr@GOT(%%eax),%%eax\n",
+                  prefix);
+         fprintf (file, "\tcall *(%%eax)\n");
+       }
     }
 
-  return 0;
+#else  /* !OSF_OS */
+
+  if (profile_flag && OSF_PROFILE_BEFORE_PROLOGUE)
+    {
+      if (!flag_pic)
+       {
+         fprintf (file, "\tmovl $%sP%d,%%edx\n", lprefix, labelno);
+         fprintf (file, "\tcall *%s_mcount_ptr\n", prefix);
+       }
+
+      else
+       {
+         static int call_no = 0;
+
+         fprintf (file, "\tcall %sPc%d\n", lprefix, call_no);
+         fprintf (file, "%sPc%d:\tpopl %%eax\n", lprefix, call_no);
+         fprintf (file, "\taddl $_GLOBAL_OFFSET_TABLE_+[.-%sPc%d],%%eax\n",
+                  lprefix, call_no++);
+         fprintf (file, "\tleal %sP%d@GOTOFF(%%eax),%%edx\n",
+                  lprefix, labelno);
+         fprintf (file, "\tmovl %s_mcount_ptr@GOT(%%eax),%%eax\n",
+                  prefix);
+         fprintf (file, "\tcall *(%%eax)\n");
+       }
+    }
+#endif /* !OSF_OS */
+
+  function_prologue (file, size);
 }
 
+#endif  /* OSF_OS || TARGET_OSF1ELF */
+
 /* Return 0 if the attributes for two types are incompatible, 1 if they
    are compatible, and 2 if they are nearly compatible (which causes a
    warning to be generated).  */
 
-int
+static int
 ix86_comp_type_attributes (type1, type2)
      tree type1;
      tree type2;
 {
   /* Check for mismatch of non-default calling convention.  */
-  const char *rtdstr = TARGET_RTD ? "cdecl" : "stdcall";
+  const char *const rtdstr = TARGET_RTD ? "cdecl" : "stdcall";
 
   if (TREE_CODE (type1) != FUNCTION_TYPE)
     return 1;
@@ -974,6 +1339,25 @@ ix86_return_pops_args (fundecl, funtype, size)
 \f
 /* Argument support functions.  */
 
+/* Return true when register may be used to pass function parameters.  */
+bool
+ix86_function_arg_regno_p (regno)
+     int regno;
+{
+  int i;
+  if (!TARGET_64BIT)
+    return regno < REGPARM_MAX || (TARGET_SSE && SSE_REGNO_P (regno));
+  if (SSE_REGNO_P (regno) && TARGET_SSE)
+    return true;
+  /* RAX is used as hidden argument to va_arg functions.  */
+  if (!regno)
+    return true;
+  for (i = 0; i < REGPARM_MAX; i++)
+    if (regno == x86_64_int_parameter_registers[i])
+      return true;
+  return false;
+}
+
 /* 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.  */
@@ -1005,13 +1389,15 @@ init_cumulative_args (cum, fntype, libname)
 
   /* Set up the number of registers to use for passing arguments.  */
   cum->nregs = ix86_regparm;
-  if (fntype)
+  cum->sse_nregs = SSE_REGPARM_MAX;
+  if (fntype && !TARGET_64BIT)
     {
       tree attr = lookup_attribute ("regparm", TYPE_ATTRIBUTES (fntype));
 
       if (attr)
        cum->nregs = TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (attr)));
     }
+  cum->maybe_vaarg = false;
 
   /* Determine if this function has variable arguments.  This is
      indicated by the last argument being 'void_type_mode' if there
@@ -1025,9 +1411,16 @@ init_cumulative_args (cum, fntype, libname)
        {
          next_param = TREE_CHAIN (param);
          if (next_param == 0 && TREE_VALUE (param) != void_type_node)
-           cum->nregs = 0;
+           {
+             if (!TARGET_64BIT)
+               cum->nregs = 0;
+             cum->maybe_vaarg = true;
+           }
        }
     }
+  if ((!fntype && !libname)
+      || (fntype && !TYPE_ARG_TYPES (fntype)))
+    cum->maybe_vaarg = 1;
 
   if (TARGET_DEBUG_ARG)
     fprintf (stderr, ", nregs=%d )\n", cum->nregs);
@@ -1035,117 +1428,1142 @@ init_cumulative_args (cum, fntype, libname)
   return;
 }
 
-/* Update the data in CUM to advance over an argument
-   of mode MODE and data type TYPE.
-   (TYPE is null for libcalls where that information may not be available.)  */
+/* x86-64 register passing impleemntation.  See x86-64 ABI for details.  Goal
+   of this code is to classify each 8bytes of incoming argument by the register
+   class and assign registers accordingly.  */
 
-void
-function_arg_advance (cum, mode, type, named)
-     CUMULATIVE_ARGS *cum;     /* current arg information */
-     enum machine_mode mode;   /* current arg mode */
-     tree type;                        /* type of the argument or 0 if lib support */
-     int named;                        /* whether or not the argument was named */
+/* Return the union class of CLASS1 and CLASS2.
+   See the x86-64 PS ABI for details.  */
+
+static enum x86_64_reg_class
+merge_classes (class1, class2)
+     enum x86_64_reg_class class1, class2;
+{
+  /* Rule #1: If both classes are equal, this is the resulting class.  */
+  if (class1 == class2)
+    return class1;
+
+  /* Rule #2: If one of the classes is NO_CLASS, the resulting class is
+     the other class.  */
+  if (class1 == X86_64_NO_CLASS)
+    return class2;
+  if (class2 == X86_64_NO_CLASS)
+    return class1;
+
+  /* Rule #3: If one of the classes is MEMORY, the result is MEMORY.  */
+  if (class1 == X86_64_MEMORY_CLASS || class2 == X86_64_MEMORY_CLASS)
+    return X86_64_MEMORY_CLASS;
+
+  /* Rule #4: If one of the classes is INTEGER, the result is INTEGER.  */
+  if ((class1 == X86_64_INTEGERSI_CLASS && class2 == X86_64_SSESF_CLASS)
+      || (class2 == X86_64_INTEGERSI_CLASS && class1 == X86_64_SSESF_CLASS))
+    return X86_64_INTEGERSI_CLASS;
+  if (class1 == X86_64_INTEGER_CLASS || class1 == X86_64_INTEGERSI_CLASS
+      || class2 == X86_64_INTEGER_CLASS || class2 == X86_64_INTEGERSI_CLASS)
+    return X86_64_INTEGER_CLASS;
+
+  /* Rule #5: If one of the classes is X87 or X87UP class, MEMORY is used.  */
+  if (class1 == X86_64_X87_CLASS || class1 == X86_64_X87UP_CLASS
+      || class2 == X86_64_X87_CLASS || class2 == X86_64_X87UP_CLASS)
+    return X86_64_MEMORY_CLASS;
+
+  /* Rule #6: Otherwise class SSE is used.  */
+  return X86_64_SSE_CLASS;
+}
+
+/* Classify the argument of type TYPE and mode MODE.
+   CLASSES will be filled by the register class used to pass each word
+   of the operand.  The number of words is returned.  In case the parameter
+   should be passed in memory, 0 is returned. As a special case for zero
+   sized containers, classes[0] will be NO_CLASS and 1 is returned.
+
+   BIT_OFFSET is used internally for handling records and specifies offset
+   of the offset in bits modulo 256 to avoid overflow cases.
+
+   See the x86-64 PS ABI for details.
+*/
+
+static int
+classify_argument (mode, type, classes, bit_offset)
+     enum machine_mode mode;
+     tree type;
+     enum x86_64_reg_class classes[MAX_CLASSES];
+     int bit_offset;
 {
   int bytes =
     (mode == BLKmode) ? int_size_in_bytes (type) : (int) GET_MODE_SIZE (mode);
   int words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
 
-  if (TARGET_DEBUG_ARG)
-    fprintf (stderr,
-            "function_adv (sz=%d, wds=%2d, nregs=%d, mode=%s, named=%d)\n\n",
-            words, cum->words, cum->nregs, GET_MODE_NAME (mode), named);
-  if (TARGET_SSE && mode == TImode)
-    {
-      cum->sse_words += words;
-      cum->sse_nregs -= 1;
-      cum->sse_regno += 1;
-      if (cum->sse_nregs <= 0)
+  if (type && AGGREGATE_TYPE_P (type))
+    {
+      int i;
+      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)
+       return 0;
+
+      for (i = 0; i < words; i++)
+       classes[i] = X86_64_NO_CLASS;
+
+      /* Zero sized arrays or structures are NO_CLASS.  We return 0 to
+        signalize memory class, so handle it as special case.  */
+      if (!words)
+       {
+         classes[0] = X86_64_NO_CLASS;
+         return 1;
+       }
+
+      /* Classify each field of record and merge classes.  */
+      if (TREE_CODE (type) == RECORD_TYPE)
+       {
+         for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+           {
+             if (TREE_CODE (field) == FIELD_DECL)
+               {
+                 int num;
+
+                 /* Bitfields are always classified as integer.  Handle them
+                    early, since later code would consider them to be
+                    misaligned integers.  */
+                 if (DECL_BIT_FIELD (field))
+                   {
+                     for (i = int_bit_position (field) / 8 / 8;
+                          i < (int_bit_position (field)
+                               + tree_low_cst (DECL_SIZE (field), 0)
+                               + 63) / 8 / 8; i++)
+                       classes[i] =
+                         merge_classes (X86_64_INTEGER_CLASS,
+                                        classes[i]);
+                   }
+                 else
+                   {
+                     num = classify_argument (TYPE_MODE (TREE_TYPE (field)),
+                                              TREE_TYPE (field), 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) / 8 / 8;
+                         classes[i + pos] =
+                           merge_classes (subclasses[i], classes[i + pos]);
+                       }
+                   }
+               }
+           }
+       }
+      /* Arrays are handled as small records.  */
+      else if (TREE_CODE (type) == ARRAY_TYPE)
+       {
+         int num;
+         num = classify_argument (TYPE_MODE (TREE_TYPE (type)),
+                                  TREE_TYPE (type), subclasses, bit_offset);
+         if (!num)
+           return 0;
+
+         /* 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)
+           subclasses[0] = X86_64_INTEGER_CLASS;
+
+         for (i = 0; i < words; i++)
+           classes[i] = subclasses[i % num];
+       }
+      /* Unions are similar to RECORD_TYPE but offset is always 0.  */
+      else if (TREE_CODE (type) == UNION_TYPE)
+       {
+         for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+           {
+             if (TREE_CODE (field) == FIELD_DECL)
+               {
+                 int num;
+                 num = classify_argument (TYPE_MODE (TREE_TYPE (field)),
+                                          TREE_TYPE (field), subclasses,
+                                          bit_offset);
+                 if (!num)
+                   return 0;
+                 for (i = 0; i < num; i++)
+                   classes[i] = merge_classes (subclasses[i], classes[i]);
+               }
+           }
+       }
+      else
+       abort ();
+
+      /* Final merger cleanup.  */
+      for (i = 0; i < words; i++)
+       {
+         /* If one class is MEMORY, everything should be passed in
+            memory.  */
+         if (classes[i] == X86_64_MEMORY_CLASS)
+           return 0;
+
+         /* The X86_64_SSEUP_CLASS should be always preceeded by
+            X86_64_SSE_CLASS.  */
+         if (classes[i] == X86_64_SSEUP_CLASS
+             && (i == 0 || classes[i - 1] != X86_64_SSE_CLASS))
+           classes[i] = X86_64_SSE_CLASS;
+
+         /*  X86_64_X87UP_CLASS should be preceeded by X86_64_X87_CLASS.  */
+         if (classes[i] == X86_64_X87UP_CLASS
+             && (i == 0 || classes[i - 1] != X86_64_X87_CLASS))
+           classes[i] = X86_64_SSE_CLASS;
+       }
+      return words;
+    }
+
+  /* Compute alignment needed.  We align all types to natural boundaries with
+     exception of XFmode that is aligned to 64bits.  */
+  if (mode != VOIDmode && mode != BLKmode)
+    {
+      int mode_alignment = GET_MODE_BITSIZE (mode);
+
+      if (mode == XFmode)
+       mode_alignment = 128;
+      else if (mode == XCmode)
+       mode_alignment = 256;
+      /* Misaligned fields are always returned in memory.  */
+      if (bit_offset % mode_alignment)
+       return 0;
+    }
+
+  /* Classification of atomic types.  */
+  switch (mode)
+    {
+    case DImode:
+    case SImode:
+    case HImode:
+    case QImode:
+    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;
+    case CDImode:
+    case TImode:
+      classes[0] = classes[1] = X86_64_INTEGER_CLASS;
+      return 2;
+    case CTImode:
+      classes[0] = classes[1] = X86_64_INTEGER_CLASS;
+      classes[2] = classes[3] = X86_64_INTEGER_CLASS;
+      return 4;
+    case SFmode:
+      if (!(bit_offset % 64))
+       classes[0] = X86_64_SSESF_CLASS;
+      else
+       classes[0] = X86_64_SSE_CLASS;
+      return 1;
+    case DFmode:
+      classes[0] = X86_64_SSEDF_CLASS;
+      return 1;
+    case TFmode:
+      classes[0] = X86_64_X87_CLASS;
+      classes[1] = X86_64_X87UP_CLASS;
+      return 2;
+    case TCmode:
+      classes[0] = X86_64_X87_CLASS;
+      classes[1] = X86_64_X87UP_CLASS;
+      classes[2] = X86_64_X87_CLASS;
+      classes[3] = X86_64_X87UP_CLASS;
+      return 4;
+    case DCmode:
+      classes[0] = X86_64_SSEDF_CLASS;
+      classes[1] = X86_64_SSEDF_CLASS;
+      return 2;
+    case SCmode:
+      classes[0] = X86_64_SSE_CLASS;
+      return 1;
+    case BLKmode:
+      return 0;
+    default:
+      abort ();
+    }
+}
+
+/* Examine the argument and return set number of register required in each
+   class.  Return 0 iff parameter should be passed in memory.  */
+static int
+examine_argument (mode, type, in_return, int_nregs, sse_nregs)
+     enum machine_mode mode;
+     tree type;
+     int *int_nregs, *sse_nregs;
+     int in_return;
+{
+  enum x86_64_reg_class class[MAX_CLASSES];
+  int n = classify_argument (mode, type, class, 0);
+
+  *int_nregs = 0;
+  *sse_nregs = 0;
+  if (!n)
+    return 0;
+  for (n--; n >= 0; n--)
+    switch (class[n])
+      {
+      case X86_64_INTEGER_CLASS:
+      case X86_64_INTEGERSI_CLASS:
+       (*int_nregs)++;
+       break;
+      case X86_64_SSE_CLASS:
+      case X86_64_SSESF_CLASS:
+      case X86_64_SSEDF_CLASS:
+       (*sse_nregs)++;
+       break;
+      case X86_64_NO_CLASS:
+      case X86_64_SSEUP_CLASS:
+       break;
+      case X86_64_X87_CLASS:
+      case X86_64_X87UP_CLASS:
+       if (!in_return)
+         return 0;
+       break;
+      case X86_64_MEMORY_CLASS:
+       abort ();
+      }
+  return 1;
+}
+/* Construct container for the argument used by GCC interface.  See
+   FUNCTION_ARG for the detailed description.  */
+static rtx
+construct_container (mode, type, in_return, nintregs, nsseregs, intreg, sse_regno)
+     enum machine_mode mode;
+     tree type;
+     int in_return;
+     int nintregs, nsseregs;
+     int *intreg, sse_regno;
+{
+  enum machine_mode tmpmode;
+  int bytes =
+    (mode == BLKmode) ? int_size_in_bytes (type) : (int) GET_MODE_SIZE (mode);
+  enum x86_64_reg_class class[MAX_CLASSES];
+  int n;
+  int i;
+  int nexps = 0;
+  int needed_sseregs, needed_intregs;
+  rtx exp[MAX_CLASSES];
+  rtx ret;
+
+  n = classify_argument (mode, type, class, 0);
+  if (TARGET_DEBUG_ARG)
+    {
+      if (!n)
+       fprintf (stderr, "Memory class\n");
+      else
+       {
+         fprintf (stderr, "Classes:");
+         for (i = 0; i < n; i++)
+           {
+             fprintf (stderr, " %s", x86_64_reg_class_name[class[i]]);
+           }
+          fprintf (stderr, "\n");
+       }
+    }
+  if (!n)
+    return NULL;
+  if (!examine_argument (mode, type, in_return, &needed_intregs, &needed_sseregs))
+    return NULL;
+  if (needed_intregs > nintregs || needed_sseregs > nsseregs)
+    return NULL;
+
+  /* First construct simple cases.  Avoid SCmode, since we want to use
+     single register to pass this type.  */
+  if (n == 1 && mode != SCmode)
+    switch (class[0])
+      {
+      case X86_64_INTEGER_CLASS:
+      case X86_64_INTEGERSI_CLASS:
+       return gen_rtx_REG (mode, intreg[0]);
+      case X86_64_SSE_CLASS:
+      case X86_64_SSESF_CLASS:
+      case X86_64_SSEDF_CLASS:
+       return gen_rtx_REG (mode, SSE_REGNO (sse_regno));
+      case X86_64_X87_CLASS:
+       return gen_rtx_REG (mode, FIRST_STACK_REG);
+      case X86_64_NO_CLASS:
+       /* Zero sized array, struct or class.  */
+       return NULL;
+      default:
+       abort ();
+      }
+  if (n == 2 && class[0] == X86_64_SSE_CLASS && class[1] == X86_64_SSEUP_CLASS)
+    return gen_rtx_REG (TImode, SSE_REGNO (sse_regno));
+  if (n == 2
+      && class[0] == X86_64_X87_CLASS && class[1] == X86_64_X87UP_CLASS)
+    return gen_rtx_REG (TFmode, FIRST_STACK_REG);
+  if (n == 2 && class[0] == X86_64_INTEGER_CLASS
+      && class[1] == X86_64_INTEGER_CLASS
+      && (mode == CDImode || mode == TImode)
+      && intreg[0] + 1 == intreg[1])
+    return gen_rtx_REG (mode, intreg[0]);
+  if (n == 4
+      && class[0] == X86_64_X87_CLASS && class[1] == X86_64_X87UP_CLASS
+      && class[2] == X86_64_X87_CLASS && class[3] == X86_64_X87UP_CLASS)
+    return gen_rtx_REG (TCmode, FIRST_STACK_REG);
+
+  /* Otherwise figure out the entries of the PARALLEL.  */
+  for (i = 0; i < n; i++)
+    {
+      switch (class[i])
+        {
+         case X86_64_NO_CLASS:
+           break;
+         case X86_64_INTEGER_CLASS:
+         case X86_64_INTEGERSI_CLASS:
+           /* Merge TImodes on aligned occassions here too.  */
+           if (i * 8 + 8 > bytes)
+             tmpmode = mode_for_size ((bytes - i * 8) * BITS_PER_UNIT, MODE_INT, 0);
+           else if (class[i] == X86_64_INTEGERSI_CLASS)
+             tmpmode = SImode;
+           else
+             tmpmode = DImode;
+           /* We've requested 24 bytes we don't have mode for.  Use DImode.  */
+           if (tmpmode == BLKmode)
+             tmpmode = DImode;
+           exp [nexps++] = gen_rtx_EXPR_LIST (VOIDmode,
+                                              gen_rtx_REG (tmpmode, *intreg),
+                                              GEN_INT (i*8));
+           intreg++;
+           break;
+         case X86_64_SSESF_CLASS:
+           exp [nexps++] = gen_rtx_EXPR_LIST (VOIDmode,
+                                              gen_rtx_REG (SFmode,
+                                                           SSE_REGNO (sse_regno)),
+                                              GEN_INT (i*8));
+           sse_regno++;
+           break;
+         case X86_64_SSEDF_CLASS:
+           exp [nexps++] = gen_rtx_EXPR_LIST (VOIDmode,
+                                              gen_rtx_REG (DFmode,
+                                                           SSE_REGNO (sse_regno)),
+                                              GEN_INT (i*8));
+           sse_regno++;
+           break;
+         case X86_64_SSE_CLASS:
+           if (i < n && class[i + 1] == X86_64_SSEUP_CLASS)
+             tmpmode = TImode, i++;
+           else
+             tmpmode = DImode;
+           exp [nexps++] = gen_rtx_EXPR_LIST (VOIDmode,
+                                              gen_rtx_REG (tmpmode,
+                                                           SSE_REGNO (sse_regno)),
+                                              GEN_INT (i*8));
+           sse_regno++;
+           break;
+         default:
+           abort ();
+       }
+    }
+  ret =  gen_rtx_PARALLEL (mode, rtvec_alloc (nexps));
+  for (i = 0; i < nexps; i++)
+    XVECEXP (ret, 0, i) = exp [i];
+  return ret;
+}
+
+/* Update the data in CUM to advance over an argument
+   of mode MODE and data type TYPE.
+   (TYPE is null for libcalls where that information may not be available.)  */
+
+void
+function_arg_advance (cum, mode, type, named)
+     CUMULATIVE_ARGS *cum;     /* current arg information */
+     enum machine_mode mode;   /* current arg mode */
+     tree type;                        /* type of the argument or 0 if lib support */
+     int named;                        /* whether or not the argument was named */
+{
+  int bytes =
+    (mode == BLKmode) ? int_size_in_bytes (type) : (int) GET_MODE_SIZE (mode);
+  int words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+
+  if (TARGET_DEBUG_ARG)
+    fprintf (stderr,
+            "function_adv (sz=%d, wds=%2d, nregs=%d, mode=%s, named=%d)\n\n",
+            words, cum->words, cum->nregs, GET_MODE_NAME (mode), named);
+  if (TARGET_64BIT)
+    {
+      int int_nregs, sse_nregs;
+      if (!examine_argument (mode, type, 0, &int_nregs, &sse_nregs))
+       cum->words += words;
+      else if (sse_nregs <= cum->sse_nregs && int_nregs <= cum->nregs)
+       {
+         cum->nregs -= int_nregs;
+         cum->sse_nregs -= sse_nregs;
+         cum->regno += int_nregs;
+         cum->sse_regno += sse_nregs;
+       }
+      else
+       cum->words += words;
+    }
+  else
+    {
+      if (TARGET_SSE && mode == TImode)
+       {
+         cum->sse_words += words;
+         cum->sse_nregs -= 1;
+         cum->sse_regno += 1;
+         if (cum->sse_nregs <= 0)
+           {
+             cum->sse_nregs = 0;
+             cum->sse_regno = 0;
+           }
+       }
+      else
+       {
+         cum->words += words;
+         cum->nregs -= words;
+         cum->regno += words;
+
+         if (cum->nregs <= 0)
+           {
+             cum->nregs = 0;
+             cum->regno = 0;
+           }
+       }
+    }
+  return;
+}
+
+/* Define where to put the arguments to a function.
+   Value is zero to push the argument on the stack,
+   or a hard register in which to store the argument.
+
+   MODE is the argument's machine mode.
+   TYPE is the data type of the argument (as a tree).
+    This is null for libcalls where that information may
+    not be available.
+   CUM is a variable of type CUMULATIVE_ARGS which gives info about
+    the preceding args and about the function being called.
+   NAMED is nonzero if this argument is a named parameter
+    (otherwise it is an extra parameter matching an ellipsis).  */
+
+struct rtx_def *
+function_arg (cum, mode, type, named)
+     CUMULATIVE_ARGS *cum;     /* current arg information */
+     enum machine_mode mode;   /* current arg mode */
+     tree type;                        /* type of the argument or 0 if lib support */
+     int named;                        /* != 0 for normal args, == 0 for ... args */
+{
+  rtx ret   = NULL_RTX;
+  int bytes =
+    (mode == BLKmode) ? int_size_in_bytes (type) : (int) GET_MODE_SIZE (mode);
+  int words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+
+  /* Handle an hidden AL argument containing number of registers for varargs
+     x86-64 functions.  For i386 ABI just return constm1_rtx to avoid
+     any AL settings.  */
+  if (mode == VOIDmode)
+    {
+      if (TARGET_64BIT)
+       return GEN_INT (cum->maybe_vaarg
+                       ? (cum->sse_nregs < 0
+                          ? SSE_REGPARM_MAX
+                          : cum->sse_regno)
+                       : -1);
+      else
+       return constm1_rtx;
+    }
+  if (TARGET_64BIT)
+    ret = construct_container (mode, type, 0, cum->nregs, cum->sse_nregs,
+                              &x86_64_int_parameter_registers [cum->regno],
+                              cum->sse_regno);
+  else
+    switch (mode)
+      {
+       /* For now, pass fp/complex values on the stack.  */
+      default:
+       break;
+
+      case BLKmode:
+      case DImode:
+      case SImode:
+      case HImode:
+      case QImode:
+       if (words <= cum->nregs)
+         ret = gen_rtx_REG (mode, cum->regno);
+       break;
+      case TImode:
+       if (cum->sse_nregs)
+         ret = gen_rtx_REG (mode, cum->sse_regno);
+       break;
+      }
+
+  if (TARGET_DEBUG_ARG)
+    {
+      fprintf (stderr,
+              "function_arg (size=%d, wds=%2d, nregs=%d, mode=%4s, named=%d",
+              words, cum->words, cum->nregs, GET_MODE_NAME (mode), named);
+
+      if (ret)
+       fprintf (stderr, ", reg=%%e%s", reg_names[ REGNO(ret) ]);
+      else
+       fprintf (stderr, ", stack");
+
+      fprintf (stderr, " )\n");
+    }
+
+  return ret;
+}
+
+/* Gives the alignment boundary, in bits, of an argument with the specified mode
+   and type.   */
+
+int
+ix86_function_arg_boundary (mode, type)
+     enum machine_mode mode;
+     tree type;
+{
+  int align;
+  if (!TARGET_64BIT)
+    return PARM_BOUNDARY;
+  if (type)
+    align = TYPE_ALIGN (type);
+  else
+    align = GET_MODE_ALIGNMENT (mode);
+  if (align < PARM_BOUNDARY)
+    align = PARM_BOUNDARY;
+  if (align > 128)
+    align = 128;
+  return align;
+}
+
+/* Return true if N is a possible register number of function value.  */
+bool
+ix86_function_value_regno_p (regno)
+     int regno;
+{
+  if (!TARGET_64BIT)
+    {
+      return ((regno) == 0
+             || ((regno) == FIRST_FLOAT_REG && TARGET_FLOAT_RETURNS_IN_80387)
+             || ((regno) == FIRST_SSE_REG && TARGET_SSE));
+    }
+  return ((regno) == 0 || (regno) == FIRST_FLOAT_REG
+         || ((regno) == FIRST_SSE_REG && TARGET_SSE)
+         || ((regno) == FIRST_FLOAT_REG && TARGET_FLOAT_RETURNS_IN_80387));
+}
+
+/* Define how to find the value returned by a function.
+   VALTYPE is the data type of the value (as a tree).
+   If the precise function being called is known, FUNC is its FUNCTION_DECL;
+   otherwise, FUNC is 0.  */
+rtx
+ix86_function_value (valtype)
+     tree valtype;
+{
+  if (TARGET_64BIT)
+    {
+      rtx ret = construct_container (TYPE_MODE (valtype), valtype, 1,
+                                    REGPARM_MAX, SSE_REGPARM_MAX,
+                                    x86_64_int_return_registers, 0);
+      /* For zero sized structures, construct_continer return NULL, but we need
+         to keep rest of compiler happy by returning meaningfull value.  */
+      if (!ret)
+       ret = gen_rtx_REG (TYPE_MODE (valtype), 0);
+      return ret;
+    }
+  else
+    return gen_rtx_REG (TYPE_MODE (valtype), VALUE_REGNO (TYPE_MODE (valtype)));
+}
+
+/* Return false iff type is returned in memory.  */
+int
+ix86_return_in_memory (type)
+     tree type;
+{
+  int needed_intregs, needed_sseregs;
+  if (TARGET_64BIT)
+    {
+      return !examine_argument (TYPE_MODE (type), type, 1,
+                               &needed_intregs, &needed_sseregs);
+    }
+  else
+    {
+      if (TYPE_MODE (type) == BLKmode
+         || (VECTOR_MODE_P (TYPE_MODE (type))
+             && int_size_in_bytes (type) == 8)
+         || (int_size_in_bytes (type) > 12 && TYPE_MODE (type) != TImode
+             && TYPE_MODE (type) != TFmode
+             && !VECTOR_MODE_P (TYPE_MODE (type))))
+       return 1;
+      return 0;
+    }
+}
+
+/* Define how to find the value returned by a library function
+   assuming the value has mode MODE.  */
+rtx
+ix86_libcall_value (mode)
+   enum machine_mode mode;
+{
+  if (TARGET_64BIT)
+    {
+      switch (mode)
+       {
+         case SFmode:
+         case SCmode:
+         case DFmode:
+         case DCmode:
+           return gen_rtx_REG (mode, FIRST_SSE_REG);
+         case TFmode:
+         case TCmode:
+           return gen_rtx_REG (mode, FIRST_FLOAT_REG);
+         default:
+           return gen_rtx_REG (mode, 0);
+       }
+    }
+  else
+   return gen_rtx_REG (mode, VALUE_REGNO (mode));
+}
+\f
+/* Create the va_list data type.  */
+
+tree
+ix86_build_va_list ()
+{
+  tree f_gpr, f_fpr, f_ovf, f_sav, record, type_decl;
+
+  /* For i386 we use plain pointer to argument area.  */
+  if (!TARGET_64BIT)
+    return build_pointer_type (char_type_node);
+
+  record = make_lang_type (RECORD_TYPE);
+  type_decl = build_decl (TYPE_DECL, get_identifier ("__va_list_tag"), record);
+
+  f_gpr = build_decl (FIELD_DECL, get_identifier ("gp_offset"), 
+                     unsigned_type_node);
+  f_fpr = build_decl (FIELD_DECL, get_identifier ("fp_offset"), 
+                     unsigned_type_node);
+  f_ovf = build_decl (FIELD_DECL, get_identifier ("overflow_arg_area"),
+                     ptr_type_node);
+  f_sav = build_decl (FIELD_DECL, get_identifier ("reg_save_area"),
+                     ptr_type_node);
+
+  DECL_FIELD_CONTEXT (f_gpr) = record;
+  DECL_FIELD_CONTEXT (f_fpr) = record;
+  DECL_FIELD_CONTEXT (f_ovf) = record;
+  DECL_FIELD_CONTEXT (f_sav) = record;
+
+  TREE_CHAIN (record) = type_decl;
+  TYPE_NAME (record) = type_decl;
+  TYPE_FIELDS (record) = f_gpr;
+  TREE_CHAIN (f_gpr) = f_fpr;
+  TREE_CHAIN (f_fpr) = f_ovf;
+  TREE_CHAIN (f_ovf) = f_sav;
+
+  layout_type (record);
+
+  /* The correct type is an array type of one element.  */
+  return build_array_type (record, build_index_type (size_zero_node));
+}
+
+/* Perform any needed actions needed for a function that is receiving a
+   variable number of arguments. 
+
+   CUM is as above.
+
+   MODE and TYPE are the mode and type of the current parameter.
+
+   PRETEND_SIZE is a variable that should be set to the amount of stack
+   that must be pushed by the prolog to pretend that our caller pushed
+   it.
+
+   Normally, this macro will push all remaining incoming registers on the
+   stack and set PRETEND_SIZE to the length of the registers pushed.  */
+
+void
+ix86_setup_incoming_varargs (cum, mode, type, pretend_size, no_rtl)
+     CUMULATIVE_ARGS *cum;
+     enum machine_mode mode;
+     tree type;
+     int *pretend_size ATTRIBUTE_UNUSED;
+     int no_rtl;
+
+{
+  CUMULATIVE_ARGS next_cum;
+  rtx save_area = NULL_RTX, mem;
+  rtx label;
+  rtx label_ref;
+  rtx tmp_reg;
+  rtx nsse_reg;
+  int set;
+  tree fntype;
+  int stdarg_p;
+  int i;
+
+  if (!TARGET_64BIT)
+    return;
+
+  /* Indicate to allocate space on the stack for varargs save area.  */
+  ix86_save_varrargs_registers = 1;
+
+  fntype = TREE_TYPE (current_function_decl);
+  stdarg_p = (TYPE_ARG_TYPES (fntype) != 0
+             && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
+                 != void_type_node));
+
+  /* For varargs, we do not want to skip the dummy va_dcl argument.
+     For stdargs, we do want to skip the last named argument.  */
+  next_cum = *cum;
+  if (stdarg_p)
+    function_arg_advance (&next_cum, mode, type, 1);
+
+  if (!no_rtl)
+    save_area = frame_pointer_rtx;
+
+  set = get_varargs_alias_set ();
+
+  for (i = next_cum.regno; i < ix86_regparm; i++)
+    {
+      mem = gen_rtx_MEM (Pmode,
+                        plus_constant (save_area, i * UNITS_PER_WORD));
+      set_mem_alias_set (mem, set);
+      emit_move_insn (mem, gen_rtx_REG (Pmode,
+                                       x86_64_int_parameter_registers[i]));
+    }
+
+  if (next_cum.sse_nregs)
+    {
+      /* Now emit code to save SSE registers.  The AX parameter contains number
+        of SSE parameter regsiters used to call this function.  We use
+        sse_prologue_save insn template that produces computed jump across
+        SSE saves.  We need some preparation work to get this working.  */
+
+      label = gen_label_rtx ();
+      label_ref = gen_rtx_LABEL_REF (Pmode, label);
+
+      /* Compute address to jump to :
+         label - 5*eax + nnamed_sse_arguments*5  */
+      tmp_reg = gen_reg_rtx (Pmode);
+      nsse_reg = gen_reg_rtx (Pmode);
+      emit_insn (gen_zero_extendqidi2 (nsse_reg, gen_rtx_REG (QImode, 0)));
+      emit_insn (gen_rtx_SET (VOIDmode, tmp_reg,
+                             gen_rtx_MULT (Pmode, nsse_reg,
+                                           GEN_INT (4))));
+      if (next_cum.sse_regno)
+       emit_move_insn
+         (nsse_reg,
+          gen_rtx_CONST (DImode,
+                         gen_rtx_PLUS (DImode,
+                                       label_ref,
+                                       GEN_INT (next_cum.sse_regno * 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.  */
+      tmp_reg = gen_reg_rtx (Pmode);
+      emit_insn (gen_rtx_SET (VOIDmode, tmp_reg,
+                             plus_constant (save_area,
+                                            8 * REGPARM_MAX + 127)));
+      mem = gen_rtx_MEM (BLKmode, plus_constant (tmp_reg, -127));
+      set_mem_alias_set (mem, set);
+      set_mem_align (mem, BITS_PER_WORD);
+
+      /* And finally do the dirty job!  */
+      emit_insn (gen_sse_prologue_save (mem, nsse_reg,
+                                       GEN_INT (next_cum.sse_regno), label));
+    }
+
+}
+
+/* Implement va_start.  */
+
+void
+ix86_va_start (stdarg_p, valist, nextarg)
+     int stdarg_p;
+     tree valist;
+     rtx nextarg;
+{
+  HOST_WIDE_INT words, n_gpr, n_fpr;
+  tree f_gpr, f_fpr, f_ovf, f_sav;
+  tree gpr, fpr, ovf, sav, t;
+
+  /* Only 64bit target needs something special.  */
+  if (!TARGET_64BIT)
+    {
+      std_expand_builtin_va_start (stdarg_p, valist, nextarg);
+      return;
+    }
+
+  f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
+  f_fpr = TREE_CHAIN (f_gpr);
+  f_ovf = TREE_CHAIN (f_fpr);
+  f_sav = TREE_CHAIN (f_ovf);
+
+  valist = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)), valist);
+  gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
+  fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
+  ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf);
+  sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav);
+
+  /* Count number of gp and fp argument registers used.  */
+  words = current_function_args_info.words;
+  n_gpr = current_function_args_info.regno;
+  n_fpr = current_function_args_info.sse_regno;
+
+  if (TARGET_DEBUG_ARG)
+    fprintf (stderr, "va_start: words = %d, n_gpr = %d, n_fpr = %d\n",
+            (int)words, (int)n_gpr, (int)n_fpr);
+
+  t = build (MODIFY_EXPR, TREE_TYPE (gpr), gpr,
+            build_int_2 (n_gpr * 8, 0));
+  TREE_SIDE_EFFECTS (t) = 1;
+  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+  t = build (MODIFY_EXPR, TREE_TYPE (fpr), fpr,
+            build_int_2 (n_fpr * 16 + 8*REGPARM_MAX, 0));
+  TREE_SIDE_EFFECTS (t) = 1;
+  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+  /* Find the overflow area.  */
+  t = make_tree (TREE_TYPE (ovf), virtual_incoming_args_rtx);
+  if (words != 0)
+    t = build (PLUS_EXPR, TREE_TYPE (ovf), t,
+              build_int_2 (words * UNITS_PER_WORD, 0));
+  t = build (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t);
+  TREE_SIDE_EFFECTS (t) = 1;
+  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+  /* Find the register save area.
+     Prologue of the function save it right above stack frame.  */
+  t = make_tree (TREE_TYPE (sav), frame_pointer_rtx);
+  t = build (MODIFY_EXPR, TREE_TYPE (sav), sav, t);
+  TREE_SIDE_EFFECTS (t) = 1;
+  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+}
+
+/* Implement va_arg.  */
+rtx
+ix86_va_arg (valist, type)
+     tree valist, type;
+{
+  static int intreg[6] = { 0, 1, 2, 3, 4, 5 };
+  tree f_gpr, f_fpr, f_ovf, f_sav;
+  tree gpr, fpr, ovf, sav, t;
+  int size, rsize;
+  rtx lab_false, lab_over = NULL_RTX;
+  rtx addr_rtx, r;
+  rtx container;
+
+  /* Only 64bit target needs something special.  */
+  if (!TARGET_64BIT)
+    {
+      return std_expand_builtin_va_arg (valist, type);
+    }
+
+  f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
+  f_fpr = TREE_CHAIN (f_gpr);
+  f_ovf = TREE_CHAIN (f_fpr);
+  f_sav = TREE_CHAIN (f_ovf);
+
+  valist = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)), valist);
+  gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
+  fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
+  ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf);
+  sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav);
+
+  size = int_size_in_bytes (type);
+  rsize = (size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+
+  container = construct_container (TYPE_MODE (type), type, 0,
+                                  REGPARM_MAX, SSE_REGPARM_MAX, intreg, 0);
+  /*
+   * Pull the value out of the saved registers ...
+   */
+
+  addr_rtx = gen_reg_rtx (Pmode);
+
+  if (container)
+    {
+      rtx int_addr_rtx, sse_addr_rtx;
+      int needed_intregs, needed_sseregs;
+      int need_temp;
+
+      lab_over = gen_label_rtx ();
+      lab_false = gen_label_rtx ();
+
+      examine_argument (TYPE_MODE (type), type, 0,
+                       &needed_intregs, &needed_sseregs);
+
+
+      need_temp = ((needed_intregs && TYPE_ALIGN (type) > 64)
+                  || TYPE_ALIGN (type) > 128);
+
+      /* In case we are passing structure, verify that it is consetuctive block
+         on the register save area.  If not we need to do moves.  */
+      if (!need_temp && !REG_P (container))
+       {
+         /* Verify that all registers are strictly consetuctive  */
+         if (SSE_REGNO_P (REGNO (XEXP (XVECEXP (container, 0, 0), 0))))
+           {
+             int i;
+
+             for (i = 0; i < XVECLEN (container, 0) && !need_temp; i++)
+               {
+                 rtx slot = XVECEXP (container, 0, i);
+                 if (REGNO (XEXP (slot, 0)) != FIRST_SSE_REG + (unsigned int)i
+                     || INTVAL (XEXP (slot, 1)) != i * 16)
+                   need_temp = 1;
+               }
+           }
+         else
+           {
+             int i;
+
+             for (i = 0; i < XVECLEN (container, 0) && !need_temp; i++)
+               {
+                 rtx slot = XVECEXP (container, 0, i);
+                 if (REGNO (XEXP (slot, 0)) != (unsigned int)i
+                     || INTVAL (XEXP (slot, 1)) != i * 8)
+                   need_temp = 1;
+               }
+           }
+       }
+      if (!need_temp)
        {
-         cum->sse_nregs = 0;
-         cum->sse_regno = 0;
+         int_addr_rtx = addr_rtx;
+         sse_addr_rtx = addr_rtx;
+       }
+      else
+       {
+         int_addr_rtx = gen_reg_rtx (Pmode);
+         sse_addr_rtx = gen_reg_rtx (Pmode);
+       }
+      /* First ensure that we fit completely in registers.  */
+      if (needed_intregs)
+       {
+         emit_cmp_and_jump_insns (expand_expr
+                                  (gpr, NULL_RTX, SImode, EXPAND_NORMAL),
+                                  GEN_INT ((REGPARM_MAX - needed_intregs +
+                                            1) * 8), GE, const1_rtx, SImode,
+                                  1, lab_false);
+       }
+      if (needed_sseregs)
+       {
+         emit_cmp_and_jump_insns (expand_expr
+                                  (fpr, NULL_RTX, SImode, EXPAND_NORMAL),
+                                  GEN_INT ((SSE_REGPARM_MAX -
+                                            needed_sseregs + 1) * 16 +
+                                           REGPARM_MAX * 8), GE, const1_rtx,
+                                  SImode, 1, lab_false);
        }
-    }
-  else         
-    {
-      cum->words += words;
-      cum->nregs -= words;
-      cum->regno += words;
 
-      if (cum->nregs <= 0)
+      /* Compute index to start of area used for integer regs.  */
+      if (needed_intregs)
        {
-         cum->nregs = 0;
-         cum->regno = 0;
+         t = build (PLUS_EXPR, ptr_type_node, sav, gpr);
+         r = expand_expr (t, int_addr_rtx, Pmode, EXPAND_NORMAL);
+         if (r != int_addr_rtx)
+           emit_move_insn (int_addr_rtx, r);
        }
-    }
-  return;
-}
+      if (needed_sseregs)
+       {
+         t = build (PLUS_EXPR, ptr_type_node, sav, fpr);
+         r = expand_expr (t, sse_addr_rtx, Pmode, EXPAND_NORMAL);
+         if (r != sse_addr_rtx)
+           emit_move_insn (sse_addr_rtx, r);
+       }
+      if (need_temp)
+       {
+         int i;
+         rtx mem;
 
-/* Define where to put the arguments to a function.
-   Value is zero to push the argument on the stack,
-   or a hard register in which to store the argument.
+         /* Never use the memory itself, as it has the alias set.  */
+         addr_rtx = XEXP (assign_temp (type, 0, 1, 0), 0);
+         mem = gen_rtx_MEM (BLKmode, addr_rtx);
+         set_mem_alias_set (mem, get_varargs_alias_set ());
+         set_mem_align (mem, BITS_PER_UNIT);
 
-   MODE is the argument's machine mode.
-   TYPE is the data type of the argument (as a tree).
-    This is null for libcalls where that information may
-    not be available.
-   CUM is a variable of type CUMULATIVE_ARGS which gives info about
-    the preceding args and about the function being called.
-   NAMED is nonzero if this argument is a named parameter
-    (otherwise it is an extra parameter matching an ellipsis).  */
+         for (i = 0; i < XVECLEN (container, 0); i++)
+           {
+             rtx slot = XVECEXP (container, 0, i);
+             rtx reg = XEXP (slot, 0);
+             enum machine_mode mode = GET_MODE (reg);
+             rtx src_addr;
+             rtx src_mem;
+             int src_offset;
+             rtx dest_mem;
+
+             if (SSE_REGNO_P (REGNO (reg)))
+               {
+                 src_addr = sse_addr_rtx;
+                 src_offset = (REGNO (reg) - FIRST_SSE_REG) * 16;
+               }
+             else
+               {
+                 src_addr = int_addr_rtx;
+                 src_offset = REGNO (reg) * 8;
+               }
+             src_mem = gen_rtx_MEM (mode, src_addr);
+             set_mem_alias_set (src_mem, get_varargs_alias_set ());
+             src_mem = adjust_address (src_mem, mode, src_offset);
+             dest_mem = adjust_address (mem, mode, INTVAL (XEXP (slot, 1)));
+             emit_move_insn (dest_mem, src_mem);
+           }
+       }
 
-struct rtx_def *
-function_arg (cum, mode, type, named)
-     CUMULATIVE_ARGS *cum;     /* current arg information */
-     enum machine_mode mode;   /* current arg mode */
-     tree type;                        /* type of the argument or 0 if lib support */
-     int named;                        /* != 0 for normal args, == 0 for ... args */
-{
-  rtx ret   = NULL_RTX;
-  int bytes =
-    (mode == BLKmode) ? int_size_in_bytes (type) : (int) GET_MODE_SIZE (mode);
-  int words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+      if (needed_intregs)
+       {
+         t =
+           build (PLUS_EXPR, TREE_TYPE (gpr), gpr,
+                  build_int_2 (needed_intregs * 8, 0));
+         t = build (MODIFY_EXPR, TREE_TYPE (gpr), gpr, t);
+         TREE_SIDE_EFFECTS (t) = 1;
+         expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+       }
+      if (needed_sseregs)
+       {
+         t =
+           build (PLUS_EXPR, TREE_TYPE (fpr), fpr,
+                  build_int_2 (needed_sseregs * 16, 0));
+         t = build (MODIFY_EXPR, TREE_TYPE (fpr), fpr, t);
+         TREE_SIDE_EFFECTS (t) = 1;
+         expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+       }
 
-  if (mode == VOIDmode)
-    return constm1_rtx;
+      emit_jump_insn (gen_jump (lab_over));
+      emit_barrier ();
+      emit_label (lab_false);
+    }
 
-  switch (mode)
-    {
-      /* For now, pass fp/complex values on the stack.  */
-    default:
-      break;
+  /* ... otherwise out of the overflow area.  */
 
-    case BLKmode:
-    case DImode:
-    case SImode:
-    case HImode:
-    case QImode:
-      if (words <= cum->nregs)
-       ret = gen_rtx_REG (mode, cum->regno);
-      break;
-    case TImode:
-      if (cum->sse_nregs)
-        ret = gen_rtx_REG (mode, cum->sse_regno);
-      break;    
+  /* Care for on-stack alignment if needed.  */
+  if (FUNCTION_ARG_BOUNDARY (VOIDmode, type) <= 64)
+    t = ovf;
+  else
+    {
+      HOST_WIDE_INT align = FUNCTION_ARG_BOUNDARY (VOIDmode, type) / 8;
+      t = build (PLUS_EXPR, TREE_TYPE (ovf), ovf, build_int_2 (align - 1, 0));
+      t = build (BIT_AND_EXPR, TREE_TYPE (t), t, build_int_2 (-align, -1));
     }
+  t = save_expr (t);
 
-  if (TARGET_DEBUG_ARG)
-    {
-      fprintf (stderr,
-              "function_arg (size=%d, wds=%2d, nregs=%d, mode=%4s, named=%d",
-              words, cum->words, cum->nregs, GET_MODE_NAME (mode), named);
+  r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
+  if (r != addr_rtx)
+    emit_move_insn (addr_rtx, r);
 
-      if (ret)
-       fprintf (stderr, ", reg=%%e%s", reg_names[ REGNO(ret) ]);
-      else
-       fprintf (stderr, ", stack");
+  t =
+    build (PLUS_EXPR, TREE_TYPE (t), t,
+          build_int_2 (rsize * UNITS_PER_WORD, 0));
+  t = build (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t);
+  TREE_SIDE_EFFECTS (t) = 1;
+  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
 
-      fprintf (stderr, " )\n");
-    }
+  if (container)
+    emit_label (lab_over);
 
-  return ret;
+  return addr_rtx;
 }
 \f
-
 /* Return nonzero if OP is general operand representable on x86_64.  */
 
 int
@@ -1270,8 +2688,9 @@ symbolic_operand (op, mode)
       if (GET_CODE (op) == SYMBOL_REF
          || GET_CODE (op) == LABEL_REF
          || (GET_CODE (op) == UNSPEC
-             && XINT (op, 1) >= 6
-             && XINT (op, 1) <= 7))
+             && (XINT (op, 1) == 6
+                 || XINT (op, 1) == 7
+                 || XINT (op, 1) == 15)))
        return 1;
       if (GET_CODE (op) != PLUS
          || GET_CODE (XEXP (op, 1)) != CONST_INT)
@@ -1304,9 +2723,16 @@ pic_symbolic_operand (op, mode)
      register rtx op;
      enum machine_mode mode ATTRIBUTE_UNUSED;
 {
-  if (GET_CODE (op) == CONST)
+  if (GET_CODE (op) != CONST)
+    return 0;
+  op = XEXP (op, 0);
+  if (TARGET_64BIT)
+    {
+      if (GET_CODE (XEXP (op, 0)) == UNSPEC)
+       return 1;
+    }
+  else 
     {
-      op = XEXP (op, 0);
       if (GET_CODE (op) == UNSPEC)
        return 1;
       if (GET_CODE (op) != PLUS
@@ -1319,6 +2745,41 @@ pic_symbolic_operand (op, mode)
   return 0;
 }
 
+/* Return true if OP is a symbolic operand that resolves locally.  */
+
+static int
+local_symbolic_operand (op, mode)
+     rtx op;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+  if (GET_CODE (op) == LABEL_REF)
+    return 1;
+
+  if (GET_CODE (op) == CONST
+      && GET_CODE (XEXP (op, 0)) == PLUS
+      && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT)
+    op = XEXP (XEXP (op, 0), 0);
+
+  if (GET_CODE (op) != SYMBOL_REF)
+    return 0;
+
+  /* These we've been told are local by varasm and encode_section_info
+     respectively.  */
+  if (CONSTANT_POOL_ADDRESS_P (op) || SYMBOL_REF_FLAG (op))
+    return 1;
+
+  /* There is, however, a not insubstantial body of code in the rest of
+     the compiler that assumes it can just stick the results of 
+     ASM_GENERATE_INTERNAL_LABEL in a symbol_ref and have done.  */
+  /* ??? This is a hack.  Should update the body of the compiler to
+     always create a DECL an invoke ENCODE_SECTION_INFO.  */
+  if (strncmp (XSTR (op, 0), internal_label_prefix,
+              internal_label_prefix_len) == 0)
+    return 1;
+
+  return 0;
+}
+
 /* Test for a valid operand for a call instruction.  Don't allow the
    arg pointer register or virtual regs since they may decay into
    reg + const, which the patterns can't handle.  */
@@ -1401,23 +2862,13 @@ const248_operand (op, mode)
 int
 incdec_operand (op, mode)
      register rtx op;
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
 {
-  /* On Pentium4, the inc and dec operations causes extra dependancy on flag
+  /* On Pentium4, the inc and dec operations causes extra dependency on flag
      registers, since carry flag is not set.  */
   if (TARGET_PENTIUM4 && !optimize_size)
     return 0;
-  if (op == const1_rtx || op == constm1_rtx)
-    return 1;
-  if (GET_CODE (op) != CONST_INT)
-    return 0;
-  if (mode == SImode && INTVAL (op) == (HOST_WIDE_INT) 0xffffffff)
-    return 1;
-  if (mode == HImode && INTVAL (op) == (HOST_WIDE_INT) 0xffff)
-    return 1;
-  if (mode == QImode && INTVAL (op) == (HOST_WIDE_INT) 0xff)
-    return 1;
-  return 0;
+  return op == const1_rtx || op == constm1_rtx;
 }
 
 /* Return nonzero if OP is acceptable as operand of DImode shift
@@ -1691,10 +3142,17 @@ ext_register_operand (op, mode)
      register rtx op;
      enum machine_mode mode ATTRIBUTE_UNUSED;
 {
+  int regno;
   if ((!TARGET_64BIT || GET_MODE (op) != DImode)
       && GET_MODE (op) != SImode && GET_MODE (op) != HImode)
     return 0;
-  return register_operand (op, VOIDmode);
+
+  if (!register_operand (op, VOIDmode))
+    return 0;
+
+  /* Be curefull to accept only registers having upper parts.  */
+  regno = REG_P (op) ? REGNO (op) : REGNO (SUBREG_REG (op));
+  return (regno > LAST_VIRTUAL_REGISTER || regno < 4);
 }
 
 /* Return 1 if this is a valid binary floating-point operation.
@@ -1776,7 +3234,7 @@ cmpsi_operand (op, mode)
       rtx op;
       enum machine_mode mode;
 {
-  if (general_operand (op, mode))
+  if (nonimmediate_operand (op, mode))
     return 1;
 
   if (GET_CODE (op) == AND
@@ -2137,7 +3595,7 @@ ix86_frame_pointer_required ()
      to be able to access the saved ebp value in our frame.  */
   if (cfun->machine->accesses_prev_frame)
     return 1;
-  
+
   /* Several x86 os'es need a frame pointer for other reasons,
      usually pertaining to setjmp.  */
   if (SUBTARGET_FRAME_POINTER_REQUIRED)
@@ -2177,7 +3635,7 @@ ix86_asm_file_end (file)
   /* ??? Binutils 2.10 and earlier has a linkonce elimination bug related
      to updating relocations to a section being discarded such that this
      doesn't work.  Ought to detect this at configure time.  */
-#if 0 && defined (ASM_OUTPUT_SECTION_NAME)
+#if 0
   /* The trick here is to create a linkonce section containing the
      pic label thunk, but to refer to it with an internal label.
      Because the label is internal, we don't have inter-dso name
@@ -2185,16 +3643,18 @@ ix86_asm_file_end (file)
 
      In order to use these macros, however, we must create a fake
      function decl.  */
-  {
-    tree decl = build_decl (FUNCTION_DECL,
-                           get_identifier ("i686.get_pc_thunk"),
-                           error_mark_node);
-    DECL_ONE_ONLY (decl) = 1;
-    UNIQUE_SECTION (decl, 0);
-    named_section (decl, NULL, 0);
-  }
+  if (targetm.have_named_sections)
+    {
+      tree decl = build_decl (FUNCTION_DECL,
+                             get_identifier ("i686.get_pc_thunk"),
+                             error_mark_node);
+      DECL_ONE_ONLY (decl) = 1;
+      UNIQUE_SECTION (decl, 0);
+      named_section (decl, NULL);
+    }
+  else
 #else
-  text_section ();
+    text_section ();
 #endif
 
   /* This used to call ASM_DECLARE_FUNCTION_NAME() but since it's an
@@ -2258,7 +3718,7 @@ gen_push (arg)
 static int
 ix86_save_reg (regno, maybe_eh_return)
      int regno;
-     bool maybe_eh_return;
+     int maybe_eh_return;
 {
   if (flag_pic
       && ! TARGET_64BIT
@@ -2352,7 +3812,7 @@ ix86_compute_frame_layout (frame)
 
   /* Do some sanity checking of stack_alignment_needed and
      preferred_alignment, since i386 port is the only using those features
-     that may break easilly.  */
+     that may break easily.  */
 
   if (size && !stack_alignment_needed)
     abort ();
@@ -2455,6 +3915,27 @@ ix86_emit_save_regs ()
       }
 }
 
+/* Emit code to save registers using MOV insns.  First register
+   is restored from POINTER + OFFSET.  */
+static void
+ix86_emit_save_regs_using_mov (pointer, offset)
+     rtx pointer;
+     HOST_WIDE_INT offset;
+{
+  int regno;
+  rtx insn;
+
+  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+    if (ix86_save_reg (regno, true))
+      {
+       insn = emit_move_insn (adjust_address (gen_rtx_MEM (Pmode, pointer),
+                                              Pmode, offset),
+                              gen_rtx_REG (Pmode, regno));
+       RTX_FRAME_RELATED_P (insn) = 1;
+       offset += UNITS_PER_WORD;
+      }
+}
+
 /* Expand the prologue into a bunch of separate insns.  */
 
 void
@@ -2465,7 +3946,16 @@ ix86_expand_prologue ()
                                  || current_function_uses_const_pool)
                      && !TARGET_64BIT);
   struct ix86_frame frame;
+  int use_mov = 0;
+  HOST_WIDE_INT allocate;
 
+  if (!optimize_size)
+    {
+      use_fast_prologue_epilogue
+        = !expensive_function_p (FAST_PROLOGUE_INSN_COUNT);
+      if (TARGET_PROLOGUE_USING_MOVE)
+        use_mov = use_fast_prologue_epilogue;
+    }
   ix86_compute_frame_layout (&frame);
 
   /* Note: AT&T enter does NOT have reversed args.  Enter is probably
@@ -2480,23 +3970,24 @@ ix86_expand_prologue ()
       RTX_FRAME_RELATED_P (insn) = 1;
     }
 
-  ix86_emit_save_regs ();
+  allocate = frame.to_allocate;
+  /* In case we are dealing only with single register and empty frame,
+     push is equivalent of the mov+add sequence.  */
+  if (allocate == 0 && frame.nregs <= 1)
+    use_mov = 0;
 
-  if (frame.to_allocate == 0)
+  if (!use_mov)
+    ix86_emit_save_regs ();
+  else
+    allocate += frame.nregs * UNITS_PER_WORD;
+
+  if (allocate == 0)
     ;
-  else if (! TARGET_STACK_PROBE || frame.to_allocate < CHECK_STACK_LIMIT)
+  else if (! TARGET_STACK_PROBE || allocate < CHECK_STACK_LIMIT)
     {
-      if (frame_pointer_needed)
-       insn = emit_insn (gen_pro_epilogue_adjust_stack
-                         (stack_pointer_rtx, stack_pointer_rtx,
-                          GEN_INT (-frame.to_allocate), hard_frame_pointer_rtx));
-      else
-       if (TARGET_64BIT)
-         insn = emit_insn (gen_adddi3 (stack_pointer_rtx, stack_pointer_rtx,
-                                       GEN_INT (-frame.to_allocate)));
-        else
-         insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
-                                       GEN_INT (-frame.to_allocate)));
+      insn = emit_insn (gen_pro_epilogue_adjust_stack
+                       (stack_pointer_rtx, stack_pointer_rtx,
+                        GEN_INT (-allocate)));
       RTX_FRAME_RELATED_P (insn) = 1;
     }
   else
@@ -2509,7 +4000,7 @@ ix86_expand_prologue ()
        abort();
 
       arg0 = gen_rtx_REG (SImode, 0);
-      emit_move_insn (arg0, GEN_INT (frame.to_allocate));
+      emit_move_insn (arg0, GEN_INT (allocate));
 
       sym = gen_rtx_MEM (FUNCTION_MODE,
                         gen_rtx_SYMBOL_REF (Pmode, "_alloca"));
@@ -2519,6 +4010,14 @@ ix86_expand_prologue ()
        = gen_rtx_EXPR_LIST (VOIDmode, gen_rtx_USE (VOIDmode, arg0),
                             CALL_INSN_FUNCTION_USAGE (insn));
     }
+  if (use_mov)
+    {
+      if (!frame_pointer_needed || !frame.to_allocate)
+        ix86_emit_save_regs_using_mov (stack_pointer_rtx, frame.to_allocate);
+      else
+        ix86_emit_save_regs_using_mov (hard_frame_pointer_rtx,
+                                      -frame.nregs * UNITS_PER_WORD);
+    }
 
 #ifdef SUBTARGET_PROLOGUE
   SUBTARGET_PROLOGUE;
@@ -2534,36 +4033,13 @@ ix86_expand_prologue ()
     emit_insn (gen_blockage ());
 }
 
-/* Emit code to add TSIZE to esp value.  Use POP instruction when
-   profitable.  */
-
-static void
-ix86_emit_epilogue_esp_adjustment (tsize)
-     int tsize;
-{
-  /* If a frame pointer is present, we must be sure to tie the sp
-     to the fp so that we don't mis-schedule.  */
-  if (frame_pointer_needed)
-    emit_insn (gen_pro_epilogue_adjust_stack (stack_pointer_rtx,
-                                             stack_pointer_rtx,
-                                             GEN_INT (tsize),
-                                             hard_frame_pointer_rtx));
-  else
-    if (TARGET_64BIT)
-      emit_insn (gen_adddi3 (stack_pointer_rtx, stack_pointer_rtx,
-                            GEN_INT (tsize)));
-    else
-      emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
-                            GEN_INT (tsize)));
-}
-
 /* Emit code to restore saved registers using MOV insns.  First register
    is restored from POINTER + OFFSET.  */
 static void
 ix86_emit_restore_regs_using_mov (pointer, offset, maybe_eh_return)
      rtx pointer;
      int offset;
-     bool maybe_eh_return;
+     int maybe_eh_return;
 {
   int regno;
 
@@ -2571,9 +4047,8 @@ ix86_emit_restore_regs_using_mov (pointer, offset, maybe_eh_return)
     if (ix86_save_reg (regno, maybe_eh_return))
       {
        emit_move_insn (gen_rtx_REG (Pmode, regno),
-                       adj_offsettable_operand (gen_rtx_MEM (Pmode,
-                                                             pointer),
-                                                offset));
+                       adjust_address (gen_rtx_MEM (Pmode, pointer),
+                                       Pmode, offset));
        offset += UNITS_PER_WORD;
       }
 }
@@ -2591,8 +4066,14 @@ ix86_expand_epilogue (style)
 
   ix86_compute_frame_layout (&frame);
 
-  /* Calculate start of saved registers relative to ebp.  */
-  offset = -frame.nregs * UNITS_PER_WORD;
+  /* 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
+     restored along this path.  */
+  offset = frame.nregs;
+  if (current_function_calls_eh_return && style != 2)
+    offset -= 2;
+  offset *= -UNITS_PER_WORD;
 
 #ifdef FUNCTION_BLOCK_PROFILER_EXIT
   if (profile_block_flag == 2)
@@ -2612,10 +4093,13 @@ ix86_expand_epilogue (style)
      and there is exactly one register to pop. This heruistic may need some
      tuning in future.  */
   if ((!sp_valid && frame.nregs <= 1)
+      || (TARGET_EPILOGUE_USING_MOVE
+         && use_fast_prologue_epilogue
+         && (frame.nregs > 1 || frame.to_allocate))
       || (frame_pointer_needed && !frame.nregs && frame.to_allocate)
-      || (frame_pointer_needed && TARGET_USE_LEAVE && !optimize_size
-         && frame.nregs == 1)
-      || style == 2)
+      || (frame_pointer_needed && TARGET_USE_LEAVE
+         && use_fast_prologue_epilogue && frame.nregs == 1)
+      || current_function_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
@@ -2645,8 +4129,7 @@ ix86_expand_epilogue (style)
              emit_move_insn (hard_frame_pointer_rtx, tmp);
 
              emit_insn (gen_pro_epilogue_adjust_stack
-                        (stack_pointer_rtx, sa, const0_rtx,
-                         hard_frame_pointer_rtx));
+                        (stack_pointer_rtx, sa, const0_rtx));
            }
          else
            {
@@ -2657,17 +4140,18 @@ ix86_expand_epilogue (style)
            }
        }
       else if (!frame_pointer_needed)
-       ix86_emit_epilogue_esp_adjustment (frame.to_allocate
-                                          + frame.nregs * UNITS_PER_WORD);
+       emit_insn (gen_pro_epilogue_adjust_stack
+                  (stack_pointer_rtx, stack_pointer_rtx,
+                   GEN_INT (frame.to_allocate
+                            + frame.nregs * UNITS_PER_WORD)));
       /* If not an i386, mov & pop is faster than "leave".  */
-      else if (TARGET_USE_LEAVE || optimize_size)
+      else if (TARGET_USE_LEAVE || optimize_size || !use_fast_prologue_epilogue)
        emit_insn (TARGET_64BIT ? gen_leave_rex64 () : gen_leave ());
       else
        {
          emit_insn (gen_pro_epilogue_adjust_stack (stack_pointer_rtx,
                                                    hard_frame_pointer_rtx,
-                                                   const0_rtx,
-                                                   hard_frame_pointer_rtx));
+                                                   const0_rtx));
          if (TARGET_64BIT)
            emit_insn (gen_popdi1 (hard_frame_pointer_rtx));
          else
@@ -2684,11 +4168,12 @@ ix86_expand_epilogue (style)
            abort ();
           emit_insn (gen_pro_epilogue_adjust_stack (stack_pointer_rtx,
                                                    hard_frame_pointer_rtx,
-                                                   GEN_INT (offset),
-                                                   hard_frame_pointer_rtx));
+                                                   GEN_INT (offset)));
        }
       else if (frame.to_allocate)
-       ix86_emit_epilogue_esp_adjustment (frame.to_allocate);
+       emit_insn (gen_pro_epilogue_adjust_stack
+                  (stack_pointer_rtx, stack_pointer_rtx,
+                   GEN_INT (frame.to_allocate)));
 
       for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
        if (ix86_save_reg (regno, false))
@@ -2700,7 +4185,11 @@ ix86_expand_epilogue (style)
          }
       if (frame_pointer_needed)
        {
-         if (TARGET_64BIT)
+         /* 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));
          else
            emit_insn (gen_popsi1 (hard_frame_pointer_rtx));
@@ -2932,6 +4421,29 @@ ix86_find_base_term (x)
 {
   rtx term;
 
+  if (TARGET_64BIT)
+    {
+      if (GET_CODE (x) != CONST)
+       return x;
+      term = XEXP (x, 0);
+      if (GET_CODE (term) == PLUS
+         && (GET_CODE (XEXP (term, 1)) == CONST_INT
+             || GET_CODE (XEXP (term, 1)) == CONST_DOUBLE))
+       term = XEXP (term, 0);
+      if (GET_CODE (term) != UNSPEC
+         || XVECLEN (term, 0) != 1
+         || XINT (term, 1) !=  15)
+       return x;
+
+      term = XVECEXP (term, 0, 0);
+
+      if (GET_CODE (term) != SYMBOL_REF
+         && GET_CODE (term) != LABEL_REF)
+       return x;
+
+      return term;
+    }
+
   if (GET_CODE (x) != PLUS
       || XEXP (x, 0) != pic_offset_table_rtx
       || GET_CODE (XEXP (x, 1)) != CONST)
@@ -2963,10 +4475,42 @@ int
 legitimate_pic_address_disp_p (disp)
      register rtx disp;
 {
+  /* In 64bit mode we can allow direct addresses of symbols and labels
+     when they are not dynamic symbols.  */
+  if (TARGET_64BIT)
+    {
+      rtx x = disp;
+      if (GET_CODE (disp) == CONST)
+       x = XEXP (disp, 0);
+      /* ??? Handle PIC code models */
+      if (GET_CODE (x) == PLUS
+         && (GET_CODE (XEXP (x, 1)) == CONST_INT
+             && ix86_cmodel == CM_SMALL_PIC
+             && INTVAL (XEXP (x, 1)) < 1024*1024*1024
+             && INTVAL (XEXP (x, 1)) > -1024*1024*1024))
+       x = XEXP (x, 0);
+      if (local_symbolic_operand (x, Pmode))
+       return 1;
+    }
   if (GET_CODE (disp) != CONST)
     return 0;
   disp = XEXP (disp, 0);
 
+  if (TARGET_64BIT)
+    {
+      /* We are unsafe to allow PLUS expressions.  This limit allowed distance
+         of GOT tables.  We should not need these anyway.  */
+      if (GET_CODE (disp) != UNSPEC
+         || XVECLEN (disp, 0) != 1
+         || XINT (disp, 1) != 15)
+       return 0;
+
+      if (GET_CODE (XVECEXP (disp, 0, 0)) != SYMBOL_REF
+         && GET_CODE (XVECEXP (disp, 0, 0)) != LABEL_REF)
+       return 0;
+      return 1;
+    }
+
   if (GET_CODE (disp) == PLUS)
     {
       if (GET_CODE (XEXP (disp, 1)) != CONST_INT)
@@ -2979,15 +4523,16 @@ legitimate_pic_address_disp_p (disp)
     return 0;
 
   /* Must be @GOT or @GOTOFF.  */
-  if (XINT (disp, 1) != 6
-      && XINT (disp, 1) != 7)
-    return 0;
-
-  if (GET_CODE (XVECEXP (disp, 0, 0)) != SYMBOL_REF
-      && GET_CODE (XVECEXP (disp, 0, 0)) != LABEL_REF)
-    return 0;
+  switch (XINT (disp, 1))
+    {
+    case 6: /* @GOT */
+      return GET_CODE (XVECEXP (disp, 0, 0)) == SYMBOL_REF;
 
-  return 1;
+    case 7: /* @GOTOFF */
+      return local_symbolic_operand (XVECEXP (disp, 0, 0), Pmode);
+    }
+    
+  return 0;
 }
 
 /* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression that is a valid
@@ -3162,7 +4707,7 @@ legitimate_address_p (mode, addr, strict)
 
             This code is nonsensical, but results in addressing
             GOT table with pic_offset_table_rtx base.  We can't
-            just refuse it easilly, since it gets matched by
+            just refuse it easily, since it gets matched by
             "addsi3" pattern, that later gets split to lea in the
             case output register differs from input.  While this
             can be handled by separate addsi pattern for this case
@@ -3232,42 +4777,65 @@ legitimize_pic_address (orig, reg)
   rtx new = orig;
   rtx base;
 
-  if (GET_CODE (addr) == LABEL_REF
-      || (GET_CODE (addr) == SYMBOL_REF
-         && (CONSTANT_POOL_ADDRESS_P (addr)
-             || SYMBOL_REF_FLAG (addr))))
+  if (local_symbolic_operand (addr, Pmode))
     {
-      /* This symbol may be referenced via a displacement from the PIC
-        base address (@GOTOFF).  */
+      /* In 64bit mode we can address such objects directly.  */
+      if (TARGET_64BIT)
+       new = addr;
+      else
+       {
+         /* This symbol may be referenced via a displacement from the PIC
+            base address (@GOTOFF).  */
 
-      current_function_uses_pic_offset_table = 1;
-      new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), 7);
-      new = gen_rtx_CONST (Pmode, new);
-      new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new);
+         current_function_uses_pic_offset_table = 1;
+         new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), 7);
+         new = gen_rtx_CONST (Pmode, new);
+         new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new);
 
-      if (reg != 0)
-       {
-         emit_move_insn (reg, new);
-         new = reg;
-       }
+         if (reg != 0)
+           {
+             emit_move_insn (reg, new);
+             new = reg;
+           }
+       }
     }
   else if (GET_CODE (addr) == SYMBOL_REF)
     {
-      /* This symbol must be referenced via a load from the
-        Global Offset Table (@GOT).  */
+      if (TARGET_64BIT)
+       {
+         current_function_uses_pic_offset_table = 1;
+         new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), 15);
+         new = gen_rtx_CONST (Pmode, new);
+         new = gen_rtx_MEM (Pmode, new);
+         RTX_UNCHANGING_P (new) = 1;
+         set_mem_alias_set (new, ix86_GOT_alias_set ());
+
+         if (reg == 0)
+           reg = gen_reg_rtx (Pmode);
+         /* Use directly gen_movsi, otherwise the address is loaded
+            into register for CSE.  We don't want to CSE this addresses,
+            instead we CSE addresses from the GOT table, so skip this.  */
+         emit_insn (gen_movsi (reg, new));
+         new = reg;
+       }
+      else
+       {
+         /* This symbol must be referenced via a load from the
+            Global Offset Table (@GOT).  */
 
-      current_function_uses_pic_offset_table = 1;
-      new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), 6);
-      new = gen_rtx_CONST (Pmode, new);
-      new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new);
-      new = gen_rtx_MEM (Pmode, new);
-      RTX_UNCHANGING_P (new) = 1;
-      MEM_ALIAS_SET (new) = ix86_GOT_alias_set ();
+         current_function_uses_pic_offset_table = 1;
+         new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), 6);
+         new = gen_rtx_CONST (Pmode, new);
+         new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new);
+         new = gen_rtx_MEM (Pmode, new);
+         RTX_UNCHANGING_P (new) = 1;
+         set_mem_alias_set (new, ix86_GOT_alias_set ());
 
-      if (reg == 0)
-       reg = gen_reg_rtx (Pmode);
-      emit_move_insn (reg, new);
-      new = reg;
+         if (reg == 0)
+           reg = gen_reg_rtx (Pmode);
+         emit_move_insn (reg, new);
+         new = reg;
+       }
     }
   else
     {
@@ -3287,22 +4855,26 @@ legitimize_pic_address (orig, reg)
 
          /* Check first to see if this is a constant offset from a @GOTOFF
             symbol reference.  */
-         if ((GET_CODE (op0) == LABEL_REF
-              || (GET_CODE (op0) == SYMBOL_REF
-                  && (CONSTANT_POOL_ADDRESS_P (op0)
-                      || SYMBOL_REF_FLAG (op0))))
+         if (local_symbolic_operand (op0, Pmode)
              && GET_CODE (op1) == CONST_INT)
            {
-             current_function_uses_pic_offset_table = 1;
-             new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op0), 7);
-             new = gen_rtx_PLUS (Pmode, new, op1);
-             new = gen_rtx_CONST (Pmode, new);
-             new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new);
+             if (!TARGET_64BIT)
+               {
+                 current_function_uses_pic_offset_table = 1;
+                 new = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op0), 7);
+                 new = gen_rtx_PLUS (Pmode, new, op1);
+                 new = gen_rtx_CONST (Pmode, new);
+                 new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new);
 
-             if (reg != 0)
+                 if (reg != 0)
+                   {
+                     emit_move_insn (reg, new);
+                     new = reg;
+                   }
+               }
+             else
                {
-                 emit_move_insn (reg, new);
-                 new = reg;
+                 /* ??? We need to limit offsets here.  */
                }
            }
          else
@@ -3617,6 +5189,9 @@ output_pic_addr_const (file, x, code)
        case 8:
          fputs ("@PLT", file);
          break;
+       case 15:
+         fputs ("@GOTPCREL(%RIP)", file);
+         break;
        default:
          output_operand_lossage ("invalid UNSPEC as operand");
          break;
@@ -3636,7 +5211,13 @@ i386_dwarf_output_addr_const (file, x)
      FILE *file;
      rtx x;
 {
-  fprintf (file, "%s", INT_ASM_OP);
+#ifdef ASM_QUAD
+  fprintf (file, "%s", TARGET_64BIT ? ASM_QUAD : ASM_LONG);
+#else
+  if (TARGET_64BIT)
+    abort ();
+  fprintf (file, "%s", ASM_LONG);
+#endif
   if (flag_pic)
     output_pic_addr_const (file, x, '\0');
   else
@@ -3654,6 +5235,15 @@ i386_simplify_dwarf_addr (orig_x)
 {
   rtx x = orig_x;
 
+  if (TARGET_64BIT)
+    {
+      if (GET_CODE (x) != CONST
+         || GET_CODE (XEXP (x, 0)) != UNSPEC
+         || XINT (XEXP (x, 0), 1) != 15)
+       return orig_x;
+      return XVECEXP (XEXP (x, 0), 0, 0);
+    }
+
   if (GET_CODE (x) != PLUS
       || GET_CODE (XEXP (x, 0)) != REG
       || GET_CODE (XEXP (x, 1)) != CONST)
@@ -3780,7 +5370,7 @@ print_reg (x, code, file)
   if (ASSEMBLER_DIALECT == 0 || USER_LABEL_PREFIX[0] == 0)
     putc ('%', file);
 
-  if (code == 'w')
+  if (code == 'w' || MMX_REG_P (x))
     code = 2;
   else if (code == 'b')
     code = 1;
@@ -3792,8 +5382,6 @@ print_reg (x, code, file)
     code = 3;
   else if (code == 'h')
     code = 0;
-  else if (code == 'm' || MMX_REG_P (x))
-    code = 5;
   else
     code = GET_MODE_SIZE (GET_MODE (x));
 
@@ -3805,7 +5393,7 @@ print_reg (x, code, file)
        abort ();
       switch (code)
        {
-         case 5:
+         case 0:
            error ("Extended registers have no high halves\n");
            break;
          case 1:
@@ -3828,9 +5416,6 @@ print_reg (x, code, file)
     }
   switch (code)
     {
-    case 5:
-      fputs (hi_reg_name[REGNO (x)], file);
-      break;
     case 3:
       if (STACK_TOP_P (x))
        {
@@ -3863,6 +5448,7 @@ print_reg (x, code, file)
    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
+   F,f -- likewise, but for floating-point.
    R -- print the prefix for register names.
    z -- print the opcode suffix for the size of the current operand.
    * -- print a star (in certain assembler syntax)
@@ -3875,10 +5461,11 @@ print_reg (x, code, file)
    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.
-   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.
-   m --  print "st(n)" as an mmx 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 condition for SSE cmp instruction.
+   P -- if PIC, print an @PLT suffix.
+   X -- don't print any sort of PIC '@' suffix for a symbol.
  */
 
 void
@@ -4001,7 +5588,6 @@ print_operand (file, x, code)
        case 'q':
        case 'h':
        case 'y':
-       case 'm':
        case 'X':
        case 'P':
          break;
@@ -4069,7 +5655,39 @@ print_operand (file, x, code)
        case 'f':
          put_condition_code (GET_CODE (x), GET_MODE (XEXP (x, 0)), 1, 1, file);
          return;
+       case '+':
+         {
+           rtx x;
+
+           if (!optimize || optimize_size || !TARGET_BRANCH_PREDICTION_HINTS)
+             return;
 
+           x = find_reg_note (current_output_insn, REG_BR_PROB, 0);
+           if (x)
+             {
+               int pred_val = INTVAL (XEXP (x, 0));
+
+               if (pred_val < REG_BR_PROB_BASE * 45 / 100
+                   || pred_val > REG_BR_PROB_BASE * 55 / 100)
+                 {
+                   int taken = pred_val > REG_BR_PROB_BASE / 2;
+                   int cputaken = final_forward_branch_p (current_output_insn) == 0;
+
+                   /* Emit hints only in the case default branch prediction
+                      heruistics would fail.  */
+                   if (taken != cputaken)
+                     {
+                       /* We use 3e (DS) prefix for taken branches and
+                          2e (CS) prefix for not taken branches.  */
+                       if (taken)
+                         fputs ("ds ; ", file);
+                       else
+                         fputs ("cs ; ", file);
+                     }
+                 }
+             }
+           return;
+         }
        default:
          {
            char str[50];
@@ -4307,15 +5925,49 @@ print_operand_address (file, addr)
        }
     }
 }
-\f
-/* Split one or more DImode RTL references into pairs of SImode
+\f
+/* Split one or more DImode RTL references into pairs of SImode
+   references.  The RTL can be REG, offsettable MEM, integer constant, or
+   CONST_DOUBLE.  "operands" is a pointer to an array of DImode RTL to
+   split and "num" is its length.  lo_half and hi_half are output arrays
+   that parallel "operands".  */
+
+void
+split_di (operands, num, lo_half, hi_half)
+     rtx operands[];
+     int num;
+     rtx lo_half[], hi_half[];
+{
+  while (num--)
+    {
+      rtx op = operands[num];
+
+      /* simplify_subreg refuse to split volatile memory addresses,
+         but we still have to handle it.  */
+      if (GET_CODE (op) == MEM)
+       {
+         lo_half[num] = adjust_address (op, SImode, 0);
+         hi_half[num] = adjust_address (op, SImode, 4);
+       }
+      else
+       {
+         lo_half[num] = simplify_gen_subreg (SImode, op,
+                                             GET_MODE (op) == VOIDmode
+                                             ? DImode : GET_MODE (op), 0);
+         hi_half[num] = simplify_gen_subreg (SImode, op,
+                                             GET_MODE (op) == VOIDmode
+                                             ? DImode : GET_MODE (op), 4);
+       }
+    }
+}
+/* Split one or more TImode RTL references into pairs of SImode
    references.  The RTL can be REG, offsettable MEM, integer constant, or
    CONST_DOUBLE.  "operands" is a pointer to an array of DImode RTL to
    split and "num" is its length.  lo_half and hi_half are output arrays
    that parallel "operands".  */
 
 void
-split_di (operands, num, lo_half, hi_half)
+split_ti (operands, num, lo_half, hi_half)
      rtx operands[];
      int num;
      rtx lo_half[], hi_half[];
@@ -4323,29 +5975,19 @@ split_di (operands, num, lo_half, hi_half)
   while (num--)
     {
       rtx op = operands[num];
-      if (CONSTANT_P (op))
-       split_double (op, &lo_half[num], &hi_half[num]);
-      else if (! reload_completed)
-       {
-         lo_half[num] = gen_lowpart (SImode, op);
-         hi_half[num] = gen_highpart (SImode, op);
-       }
-      else if (GET_CODE (op) == REG)
+
+      /* simplify_subreg refuse to split volatile memory addresses, but we
+         still have to handle it.  */
+      if (GET_CODE (op) == MEM)
        {
-         if (TARGET_64BIT)
-           abort();
-         lo_half[num] = gen_rtx_REG (SImode, REGNO (op));
-         hi_half[num] = gen_rtx_REG (SImode, REGNO (op) + 1);
+         lo_half[num] = adjust_address (op, DImode, 0);
+         hi_half[num] = adjust_address (op, DImode, 8);
        }
-      else if (offsettable_memref_p (op))
+      else
        {
-         rtx lo_addr = XEXP (op, 0);
-         rtx hi_addr = XEXP (adj_offsettable_operand (op, 4), 0);
-         lo_half[num] = change_address (op, SImode, lo_addr);
-         hi_half[num] = change_address (op, SImode, hi_addr);
+         lo_half[num] = simplify_gen_subreg (DImode, op, TImode, 0);
+         hi_half[num] = simplify_gen_subreg (DImode, op, TImode, 8);
        }
-      else
-       abort ();
     }
 }
 \f
@@ -4573,6 +6215,25 @@ output_387_binary_op (insn, operands)
   return buf;
 }
 
+/* Output code to initialize control word copies used by
+   trunc?f?i patterns.  NORMAL is set to current control word, while ROUND_DOWN
+   is set to control word rounding downwards.  */
+void
+emit_i387_cw_initialization (normal, round_down)
+     rtx normal, round_down;
+{
+  rtx reg = gen_reg_rtx (HImode);
+
+  emit_insn (gen_x86_fnstcw_1 (normal));
+  emit_move_insn (reg, normal);
+  if (!TARGET_PARTIAL_REG_STALL && !optimize_size
+      && !TARGET_64BIT)
+    emit_insn (gen_movsi_insv_1 (reg, GEN_INT (0xc)));
+  else
+    emit_insn (gen_iorhi3 (reg, reg, GEN_INT (0xc00)));
+  emit_move_insn (round_down, reg);
+}
+
 /* Output code for INSN to convert a float to a signed int.  OPERANDS
    are the insn operands.  The output may be [HSD]Imode and the input
    operand may be [SDX]Fmode.  */
@@ -4584,7 +6245,6 @@ output_fix_trunc (insn, operands)
 {
   int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
   int dimode_p = GET_MODE (operands[0]) == DImode;
-  rtx xops[4];
 
   /* Jump through a hoop or two for DImode, since the hardware has no
      non-popping instruction.  We used to do this a different way, but
@@ -4592,45 +6252,19 @@ output_fix_trunc (insn, operands)
   if (dimode_p && !stack_top_dies)
     output_asm_insn ("fld\t%y1", operands);
 
-  if (! STACK_TOP_P (operands[1]))
+  if (!STACK_TOP_P (operands[1]))
     abort ();
 
-  xops[0] = GEN_INT (12);
-  xops[1] = adj_offsettable_operand (operands[2], 1);
-  xops[1] = change_address (xops[1], QImode, NULL_RTX);
-
-  xops[2] = operands[0];
   if (GET_CODE (operands[0]) != MEM)
-    xops[2] = operands[3];
-
-  output_asm_insn ("fnstcw\t%2", operands);
-  output_asm_insn ("mov{l}\t{%2, %4|%4, %2}", operands);
-  output_asm_insn ("mov{b}\t{%0, %1|%1, %0}", xops);
-  output_asm_insn ("fldcw\t%2", operands);
-  output_asm_insn ("mov{l}\t{%4, %2|%2, %4}", operands);
+    abort ();
 
+  output_asm_insn ("fldcw\t%3", operands);
   if (stack_top_dies || dimode_p)
-    output_asm_insn ("fistp%z2\t%2", xops);
+    output_asm_insn ("fistp%z0\t%0", operands);
   else
-    output_asm_insn ("fist%z2\t%2", xops);
-
+    output_asm_insn ("fist%z0\t%0", operands);
   output_asm_insn ("fldcw\t%2", operands);
 
-  if (GET_CODE (operands[0]) != MEM)
-    {
-      if (dimode_p)
-       {
-         split_di (operands+0, 1, xops+0, xops+1);
-         split_di (operands+3, 1, xops+2, xops+3);
-         output_asm_insn ("mov{l}\t{%2, %0|%0, %2}", xops);
-         output_asm_insn ("mov{l}\t{%3, %1|%1, %3}", xops);
-       }
-      else if (GET_MODE (operands[0]) == SImode)
-       output_asm_insn ("mov{l}\t{%3, %0|%0, %3}", operands);
-      else
-       output_asm_insn ("mov{w}\t{%3, %0|%0, %3}", operands);
-    }
-
   return "";
 }
 
@@ -5010,7 +6644,70 @@ ix86_output_block_profiler (file, blockno)
       break;
     }
 }
+
+void
+ix86_output_addr_vec_elt (file, value)
+     FILE *file;
+     int value;
+{
+  const char *directive = ASM_LONG;
+
+  if (TARGET_64BIT)
+    {
+#ifdef ASM_QUAD
+      directive = ASM_QUAD;
+#else
+      abort ();
+#endif
+    }
+
+  fprintf (file, "%s%s%d\n", directive, LPREFIX, value);
+}
+
+void
+ix86_output_addr_diff_elt (file, value, rel)
+     FILE *file;
+     int value, rel;
+{
+  if (TARGET_64BIT)
+    fprintf (file, "%s%s%d-.+4+(.-%s%d)\n",
+            ASM_LONG, LPREFIX, value, LPREFIX, rel);
+  else if (HAVE_AS_GOTOFF_IN_DATA)
+    fprintf (file, "%s%s%d@GOTOFF\n", ASM_LONG, LPREFIX, value);
+  else
+    asm_fprintf (file, "%s%U_GLOBAL_OFFSET_TABLE_+[.-%s%d]\n",
+                ASM_LONG, LPREFIX, value);
+}
 \f
+/* Generate either "mov $0, reg" or "xor reg, reg", as appropriate
+   for the target.  */
+
+void
+ix86_expand_clear (dest)
+     rtx dest;
+{
+  rtx tmp;
+
+  /* We play register width games, which are only valid after reload.  */
+  if (!reload_completed)
+    abort ();
+
+  /* Avoid HImode and its attendant prefix byte.  */
+  if (GET_MODE_SIZE (GET_MODE (dest)) < 4)
+    dest = gen_rtx_REG (SImode, REGNO (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))
+    {
+      rtx clob = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, 17));
+      tmp = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, tmp, clob));
+    }
+
+  emit_insn (tmp);
+}
+
 void
 ix86_expand_move (mode, operands)
      enum machine_mode mode;
@@ -5039,7 +6736,7 @@ ix86_expand_move (mode, operands)
   else
     {
       if (GET_CODE (operands[0]) == MEM
-         && (GET_MODE (operands[0]) == QImode
+         && (PUSH_ROUNDING (GET_MODE_SIZE (mode)) != GET_MODE_SIZE (mode)
              || !push_operand (operands[0], mode))
          && GET_CODE (operands[1]) == MEM)
        operands[1] = force_reg (mode, operands[1]);
@@ -5048,6 +6745,15 @@ ix86_expand_move (mode, operands)
          && ! general_no_elim_operand (operands[1], mode))
        operands[1] = copy_to_mode_reg (mode, operands[1]);
 
+      /* Force large constants in 64bit compilation into register
+        to get them CSEed.  */
+      if (TARGET_64BIT && mode == DImode
+         && immediate_operand (operands[1], mode)
+         && !x86_64_zero_extended_value (operands[1])
+         && !register_operand (operands[0], mode)
+         && optimize && !reload_completed && !reload_in_progress)
+       operands[1] = copy_to_mode_reg (mode, operands[1]);
+
       if (FLOAT_MODE_P (mode))
        {
          /* If we are loading a floating point constant to a register,
@@ -5883,6 +7589,18 @@ ix86_expand_compare (code, second_test, bypass_test)
   return ret;
 }
 
+/* Return true if the CODE will result in nontrivial jump sequence.  */
+bool
+ix86_fp_jump_nontrivial_p (code)
+    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 != NIL || second_code != NIL;
+}
+
 void
 ix86_expand_branch (code, label)
      enum rtx_code code;
@@ -5907,34 +7625,48 @@ ix86_expand_branch (code, label)
     case DFmode:
     case XFmode:
     case TFmode:
-      /* Don't expand the comparison early, so that we get better code
-        when jump or whoever decides to reverse the comparison.  */
       {
        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);
-
-       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, 18));
-       RTVEC_ELT (vec, 2)
-         = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 17));
-       if (! use_fcomi)
-         RTVEC_ELT (vec, 3)
-           = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (HImode));
-
-        emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, vec));
+       
+       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 == NIL && second_code == NIL
+           && TARGET_CMOVE)
+         {
+           ix86_split_fp_branch (code, ix86_compare_op0, ix86_compare_op1,
+                                 gen_rtx_LABEL_REF (VOIDmode, label),
+                                 pc_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, 18));
+           RTVEC_ELT (vec, 2)
+             = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 17));
+           if (! use_fcomi)
+             RTVEC_ELT (vec, 3)
+               = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (HImode));
+
+           emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, vec));
+         }
        return;
       }
 
@@ -6058,12 +7790,15 @@ ix86_expand_branch (code, label)
 
 /* Split branch based on floating point condition.  */
 void
-ix86_split_fp_branch (condition, op1, op2, target1, target2, tmp)
-     rtx condition, op1, op2, target1, target2, tmp;
+ix86_split_fp_branch (code, op1, op2, target1, target2, tmp)
+     enum rtx_code code;
+     rtx op1, op2, target1, target2, tmp;
 {
   rtx second, bypass;
   rtx label = NULL_RTX;
-  enum rtx_code code = GET_CODE (condition);
+  rtx condition;
+  int bypass_probability = -1, second_probability = -1, probability = -1;
+  rtx i;
 
   if (target2 != pc_rtx)
     {
@@ -6075,35 +7810,59 @@ ix86_split_fp_branch (condition, op1, op2, target1, target2, tmp)
 
   condition = ix86_expand_fp_compare (code, op1, op2,
                                      tmp, &second, &bypass);
+
+  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 enought 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 ();
-      emit_jump_insn (gen_rtx_SET
+      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,
-                                            bypass,
-                                            gen_rtx_LABEL_REF (VOIDmode,
-                                                               label),
-                                            pc_rtx)));
-    }
-  /* AMD Athlon and probably other CPUs too have fast bypass path between the
-     comparison and first branch.  The second branch takes longer to execute
-     so place first branch the worse predicable one if possible.  */
-  if (second != NULL_RTX
-      && (GET_CODE (second) == UNORDERED || GET_CODE (second) == ORDERED))
-    {
-      rtx tmp = condition;
-      condition = second;
-      second = tmp;
-    }
-  emit_jump_insn (gen_rtx_SET
-                 (VOIDmode, pc_rtx,
-                  gen_rtx_IF_THEN_ELSE (VOIDmode,
-                                        condition, target1, target2)));
+                                            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)
-    emit_jump_insn (gen_rtx_SET
-                   (VOIDmode, pc_rtx,
-                    gen_rtx_IF_THEN_ELSE (VOIDmode, second, target1, target2)));
+    {
+      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);
 }
@@ -6115,51 +7874,19 @@ ix86_expand_setcc (code, dest)
 {
   rtx ret, tmp, tmpreg;
   rtx second_test, bypass_test;
-  int type;
 
   if (GET_MODE (ix86_compare_op0) == DImode
       && !TARGET_64BIT)
     return 0; /* FAIL */
 
-  /* Three modes of generation:
-     0 -- destination does not overlap compare sources:
-          clear dest first, emit strict_low_part setcc.
-     1 -- destination does overlap compare sources:
-          emit subreg setcc, zero extend.
-     2 -- destination is in QImode:
-          emit setcc only.
-  */
-
-  type = 0;
-
-  if (GET_MODE (dest) == QImode)
-    type = 2;
-  else if (reg_overlap_mentioned_p (dest, ix86_compare_op0)
-          || reg_overlap_mentioned_p (dest, ix86_compare_op1))
-    type = 1;
-
-  if (type == 0)
-    emit_move_insn (dest, const0_rtx);
+  if (GET_MODE (dest) != QImode)
+    abort ();
 
   ret = ix86_expand_compare (code, &second_test, &bypass_test);
   PUT_MODE (ret, QImode);
 
   tmp = dest;
   tmpreg = dest;
-  if (type == 0)
-    {
-      tmp = gen_lowpart (QImode, dest);
-      tmpreg = tmp;
-      tmp = gen_rtx_STRICT_LOW_PART (VOIDmode, tmp);
-    }
-  else if (type == 1)
-    {
-      if (!cse_not_expected)
-       tmp = gen_reg_rtx (QImode);
-      else
-        tmp = gen_lowpart (QImode, dest);
-      tmpreg = tmp;
-    }
 
   emit_insn (gen_rtx_SET (VOIDmode, tmp, ret));
   if (bypass_test || second_test)
@@ -6184,17 +7911,6 @@ ix86_expand_setcc (code, dest)
        emit_insn (gen_iorqi3 (tmp, tmpreg, tmp2));
     }
 
-  if (type == 1)
-    {
-      rtx clob;
-
-      tmp = gen_rtx_ZERO_EXTEND (GET_MODE (dest), tmp);
-      tmp = gen_rtx_SET (VOIDmode, dest, tmp);
-      clob = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, FLAGS_REG));
-      tmp = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, tmp, clob));
-      emit_insn (tmp);
-    }
-
   return 1; /* DONE */
 }
 
@@ -6205,6 +7921,7 @@ ix86_expand_int_movcc (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]);
 
   /* When the compare code is not LTU or GEU, we can not use sbbl case.
      In case comparsion is done with immediate, we can convert it to LTU or
@@ -6212,7 +7929,7 @@ ix86_expand_int_movcc (operands)
 
   if ((code == LEU || code == GTU)
       && GET_CODE (ix86_compare_op1) == CONST_INT
-      && GET_MODE (operands[0]) != HImode
+      && mode != HImode
       && (unsigned int)INTVAL (ix86_compare_op1) != 0xffffffff
       && GET_CODE (operands[2]) == CONST_INT
       && GET_CODE (operands[3]) == CONST_INT)
@@ -6234,8 +7951,8 @@ ix86_expand_int_movcc (operands)
   /* Don't attempt mode expansion here -- if we had to expand 5 or 6
      HImode insns, we'd be swallowed in word prefix ops.  */
 
-  if (GET_MODE (operands[0]) != HImode
-      && GET_MODE (operands[0]) != DImode
+  if (mode != HImode
+      && (mode != DImode || TARGET_64BIT)
       && GET_CODE (operands[2]) == CONST_INT
       && GET_CODE (operands[3]) == CONST_INT)
     {
@@ -6264,10 +7981,13 @@ ix86_expand_int_movcc (operands)
 
          if (reg_overlap_mentioned_p (out, ix86_compare_op0)
              || reg_overlap_mentioned_p (out, ix86_compare_op1))
-           tmp = gen_reg_rtx (SImode);
+           tmp = gen_reg_rtx (mode);
 
          emit_insn (compare_seq);
-         emit_insn (gen_x86_movsicc_0_m1 (tmp));
+         if (mode == DImode)
+           emit_insn (gen_x86_movdicc_0_m1_rex64 (tmp));
+         else
+           emit_insn (gen_x86_movsicc_0_m1 (tmp));
 
          if (diff == 1)
            {
@@ -6279,7 +7999,9 @@ ix86_expand_int_movcc (operands)
               * Size 5 - 8.
               */
              if (ct)
-               emit_insn (gen_addsi3 (out, out, GEN_INT (ct)));
+               tmp = expand_simple_binop (mode, PLUS,
+                                          tmp, GEN_INT (ct),
+                                          tmp, 1, OPTAB_DIRECT);
            }
          else if (cf == -1)
            {
@@ -6290,7 +8012,9 @@ ix86_expand_int_movcc (operands)
               *
               * Size 8.
               */
-             emit_insn (gen_iorsi3 (out, out, GEN_INT (ct)));
+             tmp = expand_simple_binop (mode, IOR,
+                                        tmp, GEN_INT (ct),
+                                        tmp, 1, OPTAB_DIRECT);
            }
          else if (diff == -1 && ct)
            {
@@ -6302,9 +8026,11 @@ ix86_expand_int_movcc (operands)
               *
               * Size 8 - 11.
               */
-             emit_insn (gen_one_cmplsi2 (tmp, tmp));
+             tmp = expand_simple_unop (mode, NOT, tmp, tmp, 1);
              if (cf)
-               emit_insn (gen_addsi3 (out, out, GEN_INT (cf)));
+               tmp = expand_simple_binop (mode, PLUS,
+                                          tmp, GEN_INT (cf),
+                                          tmp, 1, OPTAB_DIRECT);
            }
          else
            {
@@ -6316,10 +8042,15 @@ ix86_expand_int_movcc (operands)
               *
               * Size 8 - 11.
               */
-             emit_insn (gen_andsi3 (out, out, GEN_INT (trunc_int_for_mode
-                                                       (cf - ct, SImode))));
+             tmp = expand_simple_binop (mode, AND,
+                                        tmp,
+                                        GEN_INT (trunc_int_for_mode
+                                                 (cf - ct, mode)),
+                                        tmp, 1, OPTAB_DIRECT);
              if (ct)
-               emit_insn (gen_addsi3 (out, out, GEN_INT (ct)));
+               tmp = expand_simple_binop (mode, PLUS,
+                                          tmp, GEN_INT (ct),
+                                          tmp, 1, OPTAB_DIRECT);
            }
 
          if (tmp != out)
@@ -6349,8 +8080,9 @@ ix86_expand_int_movcc (operands)
              code = reverse_condition (code);
            }
        }
-      if (diff == 1 || diff == 2 || diff == 4 || diff == 8
-         || diff == 3 || diff == 5 || diff == 9)
+      if ((diff == 1 || diff == 2 || diff == 4 || diff == 8
+          || diff == 3 || diff == 5 || diff == 9)
+         && (mode != DImode || x86_64_sign_extended_value (GEN_INT (cf))))
        {
          /*
           * xorl dest,dest
@@ -6373,43 +8105,28 @@ ix86_expand_int_movcc (operands)
          /* On x86_64 the lea instruction operates on Pmode, so we need to get arithmetics
             done in proper mode to match.  */
          if (diff == 1)
-           {
-             if (Pmode != SImode)
-               tmp = gen_lowpart (Pmode, out);
-             else
-               tmp = out;
-           }
+           tmp = out;
          else
            {
              rtx out1;
-             if (Pmode != SImode)
-               out1 = gen_lowpart (Pmode, out);
-             else
-               out1 = out;
-             tmp = gen_rtx_MULT (Pmode, out1, GEN_INT (diff & ~1));
+             out1 = out;
+             tmp = gen_rtx_MULT (mode, out1, GEN_INT (diff & ~1));
              nops++;
              if (diff & 1)
                {
-                 tmp = gen_rtx_PLUS (Pmode, tmp, out1);
+                 tmp = gen_rtx_PLUS (mode, tmp, out1);
                  nops++;
                }
            }
          if (cf != 0)
            {
-             tmp = gen_rtx_PLUS (Pmode, tmp, GEN_INT (cf));
+             tmp = gen_rtx_PLUS (mode, tmp, GEN_INT (cf));
              nops++;
            }
          if (tmp != out
              && (GET_CODE (tmp) != SUBREG || SUBREG_REG (tmp) != out))
            {
-             if (Pmode != SImode)
-               tmp = gen_rtx_SUBREG (SImode, tmp, 0);
-
-             /* ??? We should to take care for outputing non-lea arithmetics
-                for Pmode != SImode case too, but it is quite tricky and not
-                too important, since all TARGET_64BIT machines support real
-                conditional moves.  */
-             if (nops == 1 && Pmode == SImode)
+             if (nops == 1)
                {
                  rtx clob;
 
@@ -6473,11 +8190,17 @@ ix86_expand_int_movcc (operands)
          out = emit_store_flag (out, code, ix86_compare_op0,
                                 ix86_compare_op1, VOIDmode, 0, 1);
 
-         emit_insn (gen_addsi3 (out, out, constm1_rtx));
-         emit_insn (gen_andsi3 (out, out, GEN_INT (trunc_int_for_mode
-                                                   (cf - ct, SImode))));
-         if (ct != 0)
-           emit_insn (gen_addsi3 (out, out, GEN_INT (ct)));
+         out = expand_simple_binop (mode, PLUS,
+                                    out, constm1_rtx,
+                                    out, 1, OPTAB_DIRECT);
+         out = expand_simple_binop (mode, AND,
+                                    out,
+                                    GEN_INT (trunc_int_for_mode
+                                             (cf - ct, mode)),
+                                    out, 1, OPTAB_DIRECT);
+         out = expand_simple_binop (mode, PLUS,
+                                    out, GEN_INT (ct),
+                                    out, 1, OPTAB_DIRECT);
          if (out != operands[0])
            emit_move_insn (operands[0], out);
 
@@ -6522,7 +8245,7 @@ ix86_expand_int_movcc (operands)
         return 0; /* FAIL */
 
       orig_out = operands[0];
-      tmp = gen_reg_rtx (GET_MODE (orig_out));
+      tmp = gen_reg_rtx (mode);
       operands[0] = tmp;
 
       /* Recurse to get the constant loaded.  */
@@ -6530,7 +8253,7 @@ ix86_expand_int_movcc (operands)
         return 0; /* FAIL */
 
       /* Mask in the interesting variable.  */
-      out = expand_binop (GET_MODE (orig_out), op, var, tmp, orig_out, 0,
+      out = expand_binop (mode, op, var, tmp, orig_out, 0,
                          OPTAB_WIDEN);
       if (out != orig_out)
        emit_move_insn (orig_out, out);
@@ -6549,38 +8272,41 @@ ix86_expand_int_movcc (operands)
    * Size 15.
    */
 
-  if (! nonimmediate_operand (operands[2], GET_MODE (operands[0])))
-    operands[2] = force_reg (GET_MODE (operands[0]), operands[2]);
-  if (! nonimmediate_operand (operands[3], GET_MODE (operands[0])))
-    operands[3] = force_reg (GET_MODE (operands[0]), operands[3]);
+  if (! nonimmediate_operand (operands[2], mode))
+    operands[2] = force_reg (mode, operands[2]);
+  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 (GET_MODE (operands[0]));
+      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 (GET_MODE (operands[0]));
+      rtx tmp = gen_reg_rtx (mode);
       emit_move_insn (tmp, operands[2]);
       operands[2] = tmp;
     }
+  if (! register_operand (operands[2], VOIDmode)
+      && ! register_operand (operands[3], VOIDmode))
+    operands[2] = force_reg (mode, operands[2]);
 
   emit_insn (compare_seq);
   emit_insn (gen_rtx_SET (VOIDmode, operands[0],
-                         gen_rtx_IF_THEN_ELSE (GET_MODE (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 (GET_MODE (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 (GET_MODE (operands[0]),
+                           gen_rtx_IF_THEN_ELSE (mode,
                                  second_test,
                                  operands[2],
                                  operands[0])));
@@ -6607,8 +8333,7 @@ ix86_expand_fp_movcc (operands)
       /* We may be called from the post-reload splitter.  */
       && (!REG_P (operands[0])
          || SSE_REG_P (operands[0])
-         || REGNO (operands[0]) >= FIRST_PSEUDO_REGISTER)
-      && 0)
+         || REGNO (operands[0]) >= FIRST_PSEUDO_REGISTER))
     {
       rtx op0 = ix86_compare_op0, op1 = ix86_compare_op1;
       code = GET_CODE (operands[1]);
@@ -6801,11 +8526,11 @@ ix86_split_to_parts (operand, parts, mode)
            }
          else if (offsettable_memref_p (operand))
            {
-             operand = change_address (operand, SImode, XEXP (operand, 0));
+             operand = adjust_address (operand, SImode, 0);
              parts[0] = operand;
-             parts[1] = adj_offsettable_operand (operand, 4);
+             parts[1] = adjust_address (operand, SImode, 4);
              if (size == 3)
-               parts[2] = adj_offsettable_operand (operand, 8);
+               parts[2] = adjust_address (operand, SImode, 8);
            }
          else if (GET_CODE (operand) == CONST_DOUBLE)
            {
@@ -6818,7 +8543,7 @@ ix86_split_to_parts (operand, parts, mode)
                case XFmode:
                case TFmode:
                  REAL_VALUE_TO_TARGET_LONG_DOUBLE (r, l);
-                 parts[2] = GEN_INT (l[2]);
+                 parts[2] = GEN_INT (trunc_int_for_mode (l[2], SImode));
                  break;
                case DFmode:
                  REAL_VALUE_TO_TARGET_DOUBLE (r, l);
@@ -6826,8 +8551,8 @@ ix86_split_to_parts (operand, parts, mode)
                default:
                  abort ();
                }
-             parts[1] = GEN_INT (l[1]);
-             parts[0] = GEN_INT (l[0]);
+             parts[1] = GEN_INT (trunc_int_for_mode (l[1], SImode));
+             parts[0] = GEN_INT (trunc_int_for_mode (l[0], SImode));
            }
          else
            abort ();
@@ -6835,6 +8560,8 @@ ix86_split_to_parts (operand, parts, mode)
     }
   else
     {
+      if (mode == TImode)
+       split_ti (&operand, 1, &parts[0], &parts[1]);
       if (mode == XFmode || mode == TFmode)
        {
          if (REG_P (operand))
@@ -6846,10 +8573,9 @@ ix86_split_to_parts (operand, parts, mode)
            }
          else if (offsettable_memref_p (operand))
            {
-             operand = change_address (operand, DImode, XEXP (operand, 0));
+             operand = adjust_address (operand, DImode, 0);
              parts[0] = operand;
-             parts[1] = adj_offsettable_operand (operand, 8);
-             parts[1] = change_address (parts[1], SImode, XEXP (parts[1], 0));
+             parts[1] = adjust_address (operand, SImode, 8);
            }
          else if (GET_CODE (operand) == CONST_DOUBLE)
            {
@@ -6860,10 +8586,14 @@ ix86_split_to_parts (operand, parts, mode)
              REAL_VALUE_TO_TARGET_LONG_DOUBLE (r, l);
              /* Do not use shift by 32 to avoid warning on 32bit systems.  */
              if (HOST_BITS_PER_WIDE_INT >= 64)
-               parts[0] = GEN_INT (l[0] + ((l[1] << 31) << 1));
+               parts[0]
+                 = GEN_INT (trunc_int_for_mode
+                     ((l[0] & (((HOST_WIDE_INT) 2 << 31) - 1))
+                      + ((((HOST_WIDE_INT)l[1]) << 31) << 1),
+                      DImode));
              else
                parts[0] = immed_double_const (l[0], l[1], DImode);
-             parts[1] = GEN_INT (l[2]);
+             parts[1] = GEN_INT (trunc_int_for_mode (l[2], SImode));
            }
          else
            abort ();
@@ -6964,12 +8694,9 @@ ix86_split_long_move (operands)
          part[1][0] = change_address (part[1][0],
                                       TARGET_64BIT ? DImode : SImode,
                                       part[0][nparts - 1]);
-         part[1][1] = adj_offsettable_operand (part[1][0],
-                                               UNITS_PER_WORD);
-         part[1][1] = change_address (part[1][1], GET_MODE (part[0][1]),
-                                      XEXP (part[1][1], 0));
+         part[1][1] = adjust_address (part[1][0], VOIDmode, UNITS_PER_WORD);
          if (nparts == 3)
-           part[1][2] = adj_offsettable_operand (part[1][0], 8);
+           part[1][2] = adjust_address (part[1][0], VOIDmode, 8);
        }
     }
 
@@ -6997,7 +8724,7 @@ ix86_split_long_move (operands)
          if (GET_MODE (part[1][1]) == SImode)
            {
              if (GET_CODE (part[1][1]) == MEM)
-               part[1][1] = change_address (part[1][1], DImode, XEXP (part[1][1], 0));
+               part[1][1] = adjust_address (part[1][1], DImode, 0);
              else if (REG_P (part[1][1]))
                part[1][1] = gen_rtx_REG (DImode, REGNO (part[1][1]));
              else
@@ -7230,7 +8957,7 @@ ix86_split_lshrdi (operands, scratch)
     }
 }
 
-/* Helper function for the string operations bellow.  Dest VARIABLE whether
+/* Helper function for the string operations below.  Dest VARIABLE whether
    it is aligned to VALUE bytes.  If true, jump to the label.  */
 static rtx
 ix86_expand_aligntest (variable, value)
@@ -7244,7 +8971,7 @@ ix86_expand_aligntest (variable, value)
   else
     emit_insn (gen_andsi3 (tmpcount, variable, GEN_INT (value)));
   emit_cmp_and_jump_insns (tmpcount, const0_rtx, EQ, 0, GET_MODE (variable),
-                          1, 0, label);
+                          1, label);
   return label;
 }
 
@@ -7261,7 +8988,7 @@ ix86_adjust_counter (countreg, value)
 }
 
 /* Zero extend possibly SImode EXP to Pmode register.  */
-static rtx
+rtx
 ix86_zero_extend_to_Pmode (exp)
    rtx exp;
 {
@@ -7292,7 +9019,7 @@ ix86_expand_movstr (dst, src, count_exp, align_exp)
   if (GET_CODE (align_exp) == CONST_INT)
     align = INTVAL (align_exp);
 
-  /* This simple hack avoids all inlining code and simplifies code bellow.  */
+  /* This simple hack avoids all inlining code and simplifies code below.  */
   if (!TARGET_ALIGN_STRINGOPS)
     align = 64;
 
@@ -7395,7 +9122,7 @@ ix86_expand_movstr (dst, src, count_exp, align_exp)
          than 4 bytes, because gcc is able to optimize such code better (in
          the case the destination or the count really is aligned, gcc is often
          able to predict the branches) and also it is friendlier to the
-         hardware branch prediction.  
+         hardware branch prediction.
 
          Using loops is benefical for generic case, because we can
          handle small counts using the loops.  Many CPUs (such as Athlon)
@@ -7411,7 +9138,7 @@ ix86_expand_movstr (dst, src, count_exp, align_exp)
        {
          label = gen_label_rtx ();
          emit_cmp_and_jump_insns (countreg, GEN_INT (UNITS_PER_WORD - 1),
-                                  LEU, 0, counter_mode, 1, 0, label);
+                                  LEU, 0, counter_mode, 1, label);
        }
       if (align <= 1)
        {
@@ -7513,7 +9240,7 @@ ix86_expand_clrstr (src, count_exp, align_exp)
   if (GET_CODE (align_exp) == CONST_INT)
     align = INTVAL (align_exp);
 
-  /* This simple hack avoids all inlining code and simplifies code bellow.  */
+  /* This simple hack avoids all inlining code and simplifies code below.  */
   if (!TARGET_ALIGN_STRINGOPS)
     align = 32;
 
@@ -7607,7 +9334,7 @@ ix86_expand_clrstr (src, count_exp, align_exp)
        {
          label = gen_label_rtx ();
          emit_cmp_and_jump_insns (countreg, GEN_INT (UNITS_PER_WORD - 1),
-                                  LEU, 0, counter_mode, 1, 0, label);
+                                  LEU, 0, counter_mode, 1, label);
        }
       if (align <= 1)
        {
@@ -7813,11 +9540,11 @@ ix86_expand_strlensi_unroll_1 (out, align_rtx)
                                    NULL_RTX, 0, OPTAB_WIDEN);
 
          emit_cmp_and_jump_insns (align_rtx, const0_rtx, EQ, NULL,
-                                  Pmode, 1, 0, align_4_label);
+                                  Pmode, 1, align_4_label);
          emit_cmp_and_jump_insns (align_rtx, GEN_INT (2), EQ, NULL,
-                                  Pmode, 1, 0, align_2_label);
+                                  Pmode, 1, align_2_label);
          emit_cmp_and_jump_insns (align_rtx, GEN_INT (2), GTU, NULL,
-                                  Pmode, 1, 0, align_3_label);
+                                  Pmode, 1, align_3_label);
        }
       else
         {
@@ -7828,7 +9555,7 @@ ix86_expand_strlensi_unroll_1 (out, align_rtx)
                                    NULL_RTX, 0, OPTAB_WIDEN);
 
          emit_cmp_and_jump_insns (align_rtx, const0_rtx, EQ, NULL,
-                                  Pmode, 1, 0, align_4_label);
+                                  Pmode, 1, align_4_label);
         }
 
       mem = gen_rtx_MEM (QImode, out);
@@ -7837,7 +9564,7 @@ ix86_expand_strlensi_unroll_1 (out, align_rtx)
 
       /* Compare the first n unaligned byte on a byte per byte basis.  */
       emit_cmp_and_jump_insns (mem, const0_rtx, EQ, NULL,
-                              QImode, 1, 0, end_0_label);
+                              QImode, 1, end_0_label);
 
       /* Increment the address.  */
       if (TARGET_64BIT)
@@ -7850,8 +9577,8 @@ ix86_expand_strlensi_unroll_1 (out, align_rtx)
        {
          emit_label (align_2_label);
 
-         emit_cmp_and_jump_insns (mem, const0_rtx, EQ, NULL,
-                                  QImode, 1, 0, end_0_label);
+         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));
@@ -7861,8 +9588,8 @@ ix86_expand_strlensi_unroll_1 (out, align_rtx)
          emit_label (align_3_label);
        }
 
-      emit_cmp_and_jump_insns (mem, const0_rtx, EQ, NULL,
-                              QImode, 1, 0, end_0_label);
+      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));
@@ -7891,8 +9618,8 @@ ix86_expand_strlensi_unroll_1 (out, align_rtx)
   emit_insn (gen_andsi3 (tmpreg, tmpreg,
                         GEN_INT (trunc_int_for_mode
                                  (0x80808080, SImode))));
-  emit_cmp_and_jump_insns (tmpreg, const0_rtx, EQ, 0,
-                          SImode, 1, 0, align_4_label);
+  emit_cmp_and_jump_insns (tmpreg, const0_rtx, EQ, 0, SImode, 1,
+                          align_4_label);
 
   if (TARGET_CMOVE)
     {
@@ -7917,8 +9644,8 @@ ix86_expand_strlensi_unroll_1 (out, align_rtx)
        tmp = gen_rtx_EQ (VOIDmode, tmp, const0_rtx);
        emit_insn (gen_rtx_SET (VOIDmode, out,
                               gen_rtx_IF_THEN_ELSE (Pmode, tmp,
-                                                    reg2,
-                                                    out)));
+                                                    reg2,
+                                                    out)));
 
     }
   else
@@ -8108,6 +9835,10 @@ ix86_attr_length_immediate_default (insn, shortform)
                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);
              }
@@ -8133,7 +9864,7 @@ ix86_attr_length_address_default (insn)
 \f
 /* Return the maximum number of instructions a cpu can issue.  */
 
-int
+static int
 ix86_issue_rate ()
 {
   switch (ix86_cpu)
@@ -8188,7 +9919,7 @@ ix86_flags_dependant (insn, dep_insn, insn_type)
   if (GET_CODE (set) != REG || REGNO (set) != FLAGS_REG)
     return 0;
 
-  /* This test is true if the dependant insn reads the flags but
+  /* This test is true if the dependent insn reads the flags but
      not any other potentially set register.  */
   if (!reg_overlap_mentioned_p (set, PATTERN (insn)))
     return 0;
@@ -8209,7 +9940,8 @@ ix86_agi_dependant (insn, dep_insn, insn_type)
 {
   rtx addr;
 
-  if (insn_type == TYPE_LEA)
+  if (insn_type == TYPE_LEA
+      && TARGET_PENTIUM)
     {
       addr = PATTERN (insn);
       if (GET_CODE (addr) == SET)
@@ -8238,13 +9970,13 @@ ix86_agi_dependant (insn, dep_insn, insn_type)
   return modified_in_p (addr, dep_insn);
 }
 
-int
+static int
 ix86_adjust_cost (insn, link, dep_insn, cost)
      rtx insn, link, dep_insn;
      int cost;
 {
   enum attr_type insn_type, dep_insn_type;
-  enum attr_memory memory;
+  enum attr_memory memory, dep_memory;
   rtx set, set2;
   int dep_insn_code_number;
 
@@ -8261,14 +9993,6 @@ ix86_adjust_cost (insn, link, dep_insn, cost)
   insn_type = get_attr_type (insn);
   dep_insn_type = get_attr_type (dep_insn);
 
-  /* Prologue and epilogue allocators can have a false dependency on ebp.
-     This results in one cycle extra stall on Pentium prologue scheduling,
-     so handle this important case manually.  */
-  if (dep_insn_code_number == CODE_FOR_pro_epilogue_adjust_stack
-      && dep_insn_type == TYPE_ALU
-      && !reg_mentioned_p (stack_pointer_rtx, insn))
-    return 0;
-
   switch (ix86_cpu)
     {
     case PROCESSOR_PENTIUM:
@@ -8288,12 +10012,14 @@ ix86_adjust_cost (insn, link, dep_insn, cost)
       break;
 
     case PROCESSOR_PENTIUMPRO:
+      memory = get_attr_memory (insn);
+      dep_memory = get_attr_memory (dep_insn);
+
       /* Since we can't represent delayed latencies of load+operation,
         increase the cost here for non-imov insns.  */
       if (dep_insn_type != TYPE_IMOV
-         && dep_insn_type != TYPE_FMOV
-         && ((memory = get_attr_memory (dep_insn) == MEMORY_LOAD)
-              || memory == MEMORY_BOTH))
+          && dep_insn_type != TYPE_FMOV
+          && (dep_memory == MEMORY_LOAD || dep_memory == MEMORY_BOTH))
        cost += 1;
 
       /* INT->FP conversion is expensive.  */
@@ -8307,9 +10033,26 @@ ix86_adjust_cost (insn, link, dep_insn, cost)
          && rtx_equal_p (SET_DEST (set), SET_SRC (set2))
          && GET_CODE (SET_DEST (set2)) == MEM)
        cost += 1;
+
+      /* Show ability of reorder buffer to hide latency of load by executing
+        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_dependant (insn, dep_insn, insn_type))
+       {
+         /* Claim moves to take one cycle, as core can issue one load
+            at time and the next load can start cycle later.  */
+         if (dep_insn_type == TYPE_IMOV
+             || dep_insn_type == TYPE_FMOV)
+           cost = 1;
+         else if (cost > 1)
+           cost--;
+       }
       break;
 
     case PROCESSOR_K6:
+      memory = get_attr_memory (insn);
+      dep_memory = get_attr_memory (dep_insn);
       /* The esp dependency is resolved before the instruction is really
          finished.  */
       if ((insn_type == TYPE_PUSH || insn_type == TYPE_POP)
@@ -8318,24 +10061,58 @@ ix86_adjust_cost (insn, link, dep_insn, cost)
 
       /* Since we can't represent delayed latencies of load+operation,
         increase the cost here for non-imov insns.  */
-      if ((memory = get_attr_memory (dep_insn) == MEMORY_LOAD)
-          || memory == MEMORY_BOTH)
+      if (dep_memory == MEMORY_LOAD || dep_memory == MEMORY_BOTH)
        cost += (dep_insn_type != TYPE_IMOV) ? 2 : 1;
 
       /* INT->FP conversion is expensive.  */
       if (get_attr_fp_int_src (dep_insn))
        cost += 5;
+
+      /* Show ability of reorder buffer to hide latency of load by executing
+        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_dependant (insn, dep_insn, insn_type))
+       {
+         /* Claim moves to take one cycle, as core can issue one load
+            at time and the next load can start cycle later.  */
+         if (dep_insn_type == TYPE_IMOV
+             || dep_insn_type == TYPE_FMOV)
+           cost = 1;
+         else if (cost > 2)
+           cost -= 2;
+         else
+           cost = 1;
+       }
       break;
 
     case PROCESSOR_ATHLON:
-      if ((memory = get_attr_memory (dep_insn)) == MEMORY_LOAD
-           || memory == MEMORY_BOTH)
+      memory = get_attr_memory (insn);
+      dep_memory = get_attr_memory (dep_insn);
+
+      if (dep_memory == MEMORY_LOAD || dep_memory == MEMORY_BOTH)
        {
          if (dep_insn_type == TYPE_IMOV || dep_insn_type == TYPE_FMOV)
            cost += 2;
          else
            cost += 3;
         }
+      /* Show ability of reorder buffer to hide latency of load by executing
+        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_dependant (insn, dep_insn, insn_type))
+       {
+         /* Claim moves to take one cycle, as core can issue one load
+            at time and the next load can start cycle later.  */
+         if (dep_insn_type == TYPE_IMOV
+             || dep_insn_type == TYPE_FMOV)
+           cost = 0;
+         else if (cost >= 3)
+           cost -= 3;
+         else
+           cost = 0;
+       }
 
     default:
       break;
@@ -8421,10 +10198,11 @@ ix86_dump_ppro_packet (dump)
 
 /* We're beginning a new block.  Initialize data structures as necessary.  */
 
-void
-ix86_sched_init (dump, sched_verbose)
+static void
+ix86_sched_init (dump, sched_verbose, veclen)
      FILE *dump ATTRIBUTE_UNUSED;
      int sched_verbose ATTRIBUTE_UNUSED;
+     int veclen ATTRIBUTE_UNUSED;
 {
   memset (&ix86_sched_data, 0, sizeof (ix86_sched_data));
 }
@@ -8655,14 +10433,15 @@ ix86_sched_reorder_ppro (ready, e_ready)
 
 /* We are about to being issuing insns for this clock cycle.
    Override the default sort algorithm to better slot instructions.  */
-int
-ix86_sched_reorder (dump, sched_verbose, ready, n_ready, clock_var)
+static int
+ix86_sched_reorder (dump, sched_verbose, ready, n_readyp, clock_var)
      FILE *dump ATTRIBUTE_UNUSED;
      int sched_verbose ATTRIBUTE_UNUSED;
      rtx *ready;
-     int n_ready;
+     int *n_readyp;
      int clock_var ATTRIBUTE_UNUSED;
 {
+  int n_ready = *n_readyp;
   rtx *e_ready = ready + n_ready - 1;
 
   if (n_ready < 2)
@@ -8689,7 +10468,7 @@ out:
 /* We are about to issue INSN.  Return the number of insns left on the
    ready queue that can be issued this cycle.  */
 
-int
+static int
 ix86_variable_issue (dump, sched_verbose, insn, can_issue_more)
      FILE *dump;
      int sched_verbose;
@@ -8996,196 +10775,208 @@ x86_initialize_trampoline (tramp, fnaddr, cxt)
       emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, offset)),
                      GEN_INT (trunc_int_for_mode (0xff49, HImode)));
       emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, offset+2)),
-                     GEN_INT (trunc_int_for_mode (0xe3, HImode)));
+                     GEN_INT (trunc_int_for_mode (0xe3, QImode)));
       offset += 3;
       if (offset > TRAMPOLINE_SIZE)
        abort();
     }
 }
+\f
+#define def_builtin(MASK, NAME, TYPE, CODE)                            \
+do {                                                                   \
+  if ((MASK) & target_flags)                                           \
+    builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, NULL);      \
+} while (0)
 
-#define def_builtin(NAME, TYPE, CODE) \
-  builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, NULL_PTR)
 struct builtin_description
 {
-  enum insn_code icode;
-  const char * name;
-  enum ix86_builtins code;
-  enum rtx_code comparison;
-  unsigned int flag;
+  const unsigned int mask;
+  const enum insn_code icode;
+  const char *const name;
+  const enum ix86_builtins code;
+  const enum rtx_code comparison;
+  const unsigned int flag;
 };
 
-static struct builtin_description bdesc_comi[] =
-{
-  { CODE_FOR_sse_comi, "__builtin_ia32_comieq", IX86_BUILTIN_COMIEQSS, EQ, 0 },
-  { CODE_FOR_sse_comi, "__builtin_ia32_comilt", IX86_BUILTIN_COMILTSS, LT, 0 },
-  { CODE_FOR_sse_comi, "__builtin_ia32_comile", IX86_BUILTIN_COMILESS, LE, 0 },
-  { CODE_FOR_sse_comi, "__builtin_ia32_comigt", IX86_BUILTIN_COMIGTSS, LT, 1 },
-  { CODE_FOR_sse_comi, "__builtin_ia32_comige", IX86_BUILTIN_COMIGESS, LE, 1 },
-  { CODE_FOR_sse_comi, "__builtin_ia32_comineq", IX86_BUILTIN_COMINEQSS, NE, 0 },
-  { CODE_FOR_sse_ucomi, "__builtin_ia32_ucomieq", IX86_BUILTIN_UCOMIEQSS, EQ, 0 },
-  { CODE_FOR_sse_ucomi, "__builtin_ia32_ucomilt", IX86_BUILTIN_UCOMILTSS, LT, 0 },
-  { CODE_FOR_sse_ucomi, "__builtin_ia32_ucomile", IX86_BUILTIN_UCOMILESS, LE, 0 },
-  { CODE_FOR_sse_ucomi, "__builtin_ia32_ucomigt", IX86_BUILTIN_UCOMIGTSS, LT, 1 },
-  { CODE_FOR_sse_ucomi, "__builtin_ia32_ucomige", IX86_BUILTIN_UCOMIGESS, LE, 1 },
-  { CODE_FOR_sse_ucomi, "__builtin_ia32_ucomineq", IX86_BUILTIN_UCOMINEQSS, NE, 0 }
+static const struct builtin_description bdesc_comi[] =
+{
+  { MASK_SSE, CODE_FOR_sse_comi, "__builtin_ia32_comieq", IX86_BUILTIN_COMIEQSS, EQ, 0 },
+  { MASK_SSE, CODE_FOR_sse_comi, "__builtin_ia32_comilt", IX86_BUILTIN_COMILTSS, LT, 0 },
+  { MASK_SSE, CODE_FOR_sse_comi, "__builtin_ia32_comile", IX86_BUILTIN_COMILESS, LE, 0 },
+  { MASK_SSE, CODE_FOR_sse_comi, "__builtin_ia32_comigt", IX86_BUILTIN_COMIGTSS, LT, 1 },
+  { MASK_SSE, CODE_FOR_sse_comi, "__builtin_ia32_comige", IX86_BUILTIN_COMIGESS, LE, 1 },
+  { MASK_SSE, CODE_FOR_sse_comi, "__builtin_ia32_comineq", IX86_BUILTIN_COMINEQSS, NE, 0 },
+  { MASK_SSE, CODE_FOR_sse_ucomi, "__builtin_ia32_ucomieq", IX86_BUILTIN_UCOMIEQSS, EQ, 0 },
+  { MASK_SSE, CODE_FOR_sse_ucomi, "__builtin_ia32_ucomilt", IX86_BUILTIN_UCOMILTSS, LT, 0 },
+  { MASK_SSE, CODE_FOR_sse_ucomi, "__builtin_ia32_ucomile", IX86_BUILTIN_UCOMILESS, LE, 0 },
+  { MASK_SSE, CODE_FOR_sse_ucomi, "__builtin_ia32_ucomigt", IX86_BUILTIN_UCOMIGTSS, LT, 1 },
+  { MASK_SSE, CODE_FOR_sse_ucomi, "__builtin_ia32_ucomige", IX86_BUILTIN_UCOMIGESS, LE, 1 },
+  { MASK_SSE, CODE_FOR_sse_ucomi, "__builtin_ia32_ucomineq", IX86_BUILTIN_UCOMINEQSS, NE, 0 }
 };
 
-static struct builtin_description bdesc_2arg[] =
+static const struct builtin_description bdesc_2arg[] =
 {
   /* SSE */
-  { CODE_FOR_addv4sf3, "__builtin_ia32_addps", IX86_BUILTIN_ADDPS, 0, 0 },
-  { CODE_FOR_subv4sf3, "__builtin_ia32_subps", IX86_BUILTIN_SUBPS, 0, 0 },
-  { CODE_FOR_mulv4sf3, "__builtin_ia32_mulps", IX86_BUILTIN_MULPS, 0, 0 },
-  { CODE_FOR_divv4sf3, "__builtin_ia32_divps", IX86_BUILTIN_DIVPS, 0, 0 },
-  { CODE_FOR_vmaddv4sf3,  "__builtin_ia32_addss", IX86_BUILTIN_ADDSS, 0, 0 },
-  { CODE_FOR_vmsubv4sf3,  "__builtin_ia32_subss", IX86_BUILTIN_SUBSS, 0, 0 },
-  { CODE_FOR_vmmulv4sf3,  "__builtin_ia32_mulss", IX86_BUILTIN_MULSS, 0, 0 },
-  { CODE_FOR_vmdivv4sf3,  "__builtin_ia32_divss", IX86_BUILTIN_DIVSS, 0, 0 },
-
-  { CODE_FOR_maskcmpv4sf3, "__builtin_ia32_cmpeqps", IX86_BUILTIN_CMPEQPS, EQ, 0 },
-  { CODE_FOR_maskcmpv4sf3, "__builtin_ia32_cmpltps", IX86_BUILTIN_CMPLTPS, LT, 0 },
-  { CODE_FOR_maskcmpv4sf3, "__builtin_ia32_cmpleps", IX86_BUILTIN_CMPLEPS, LE, 0 },
-  { CODE_FOR_maskcmpv4sf3, "__builtin_ia32_cmpgtps", IX86_BUILTIN_CMPGTPS, LT, 1 },
-  { CODE_FOR_maskcmpv4sf3, "__builtin_ia32_cmpgeps", IX86_BUILTIN_CMPGEPS, LE, 1 },
-  { CODE_FOR_maskcmpv4sf3, "__builtin_ia32_cmpunordps", IX86_BUILTIN_CMPUNORDPS, UNORDERED, 0 },
-  { CODE_FOR_maskncmpv4sf3, "__builtin_ia32_cmpneqps", IX86_BUILTIN_CMPNEQPS, EQ, 0 },
-  { CODE_FOR_maskncmpv4sf3, "__builtin_ia32_cmpnltps", IX86_BUILTIN_CMPNLTPS, LT, 0 },
-  { CODE_FOR_maskncmpv4sf3, "__builtin_ia32_cmpnleps", IX86_BUILTIN_CMPNLEPS, LE, 0 },
-  { CODE_FOR_maskncmpv4sf3, "__builtin_ia32_cmpngtps", IX86_BUILTIN_CMPNGTPS, LT, 1 },
-  { CODE_FOR_maskncmpv4sf3, "__builtin_ia32_cmpngeps", IX86_BUILTIN_CMPNGEPS, LE, 1 },
-  { CODE_FOR_maskncmpv4sf3, "__builtin_ia32_cmpordps", IX86_BUILTIN_CMPORDPS, UNORDERED, 0 },
-  { CODE_FOR_vmmaskcmpv4sf3, "__builtin_ia32_cmpeqss", IX86_BUILTIN_CMPEQSS, EQ, 0 },
-  { CODE_FOR_vmmaskcmpv4sf3, "__builtin_ia32_cmpltss", IX86_BUILTIN_CMPLTSS, LT, 0 },
-  { CODE_FOR_vmmaskcmpv4sf3, "__builtin_ia32_cmpless", IX86_BUILTIN_CMPLESS, LE, 0 },
-  { CODE_FOR_vmmaskcmpv4sf3, "__builtin_ia32_cmpgtss", IX86_BUILTIN_CMPGTSS, LT, 1 },
-  { CODE_FOR_vmmaskcmpv4sf3, "__builtin_ia32_cmpgess", IX86_BUILTIN_CMPGESS, LE, 1 },
-  { CODE_FOR_vmmaskcmpv4sf3, "__builtin_ia32_cmpunordss", IX86_BUILTIN_CMPUNORDSS, UNORDERED, 0 },
-  { CODE_FOR_vmmaskncmpv4sf3, "__builtin_ia32_cmpneqss", IX86_BUILTIN_CMPNEQSS, EQ, 0 },
-  { CODE_FOR_vmmaskncmpv4sf3, "__builtin_ia32_cmpnltss", IX86_BUILTIN_CMPNLTSS, LT, 0 },
-  { CODE_FOR_vmmaskncmpv4sf3, "__builtin_ia32_cmpnless", IX86_BUILTIN_CMPNLESS, LE, 0 },
-  { CODE_FOR_vmmaskncmpv4sf3, "__builtin_ia32_cmpngtss", IX86_BUILTIN_CMPNGTSS, LT, 1 },
-  { CODE_FOR_vmmaskncmpv4sf3, "__builtin_ia32_cmpngess", IX86_BUILTIN_CMPNGESS, LE, 1 },
-  { CODE_FOR_vmmaskncmpv4sf3, "__builtin_ia32_cmpordss", IX86_BUILTIN_CMPORDSS, UNORDERED, 0 },
-
-  { CODE_FOR_sminv4sf3, "__builtin_ia32_minps", IX86_BUILTIN_MINPS, 0, 0 },
-  { CODE_FOR_smaxv4sf3, "__builtin_ia32_maxps", IX86_BUILTIN_MAXPS, 0, 0 },
-  { CODE_FOR_vmsminv4sf3, "__builtin_ia32_minss", IX86_BUILTIN_MINSS, 0, 0 },
-  { CODE_FOR_vmsmaxv4sf3, "__builtin_ia32_maxss", IX86_BUILTIN_MAXSS, 0, 0 },
-
-  { CODE_FOR_sse_andti3, "__builtin_ia32_andps", IX86_BUILTIN_ANDPS, 0, 0 },
-  { CODE_FOR_sse_nandti3,  "__builtin_ia32_andnps", IX86_BUILTIN_ANDNPS, 0, 0 },
-  { CODE_FOR_sse_iorti3, "__builtin_ia32_orps", IX86_BUILTIN_ORPS, 0, 0 },
-  { CODE_FOR_sse_xorti3,  "__builtin_ia32_xorps", IX86_BUILTIN_XORPS, 0, 0 },
-
-  { CODE_FOR_sse_movss,  "__builtin_ia32_movss", IX86_BUILTIN_MOVSS, 0, 0 },
-  { CODE_FOR_sse_movhlps,  "__builtin_ia32_movhlps", IX86_BUILTIN_MOVHLPS, 0, 0 },
-  { CODE_FOR_sse_movlhps,  "__builtin_ia32_movlhps", IX86_BUILTIN_MOVLHPS, 0, 0 },
-  { CODE_FOR_sse_unpckhps, "__builtin_ia32_unpckhps", IX86_BUILTIN_UNPCKHPS, 0, 0 },
-  { CODE_FOR_sse_unpcklps, "__builtin_ia32_unpcklps", IX86_BUILTIN_UNPCKLPS, 0, 0 },
+  { MASK_SSE, CODE_FOR_addv4sf3, "__builtin_ia32_addps", IX86_BUILTIN_ADDPS, 0, 0 },
+  { MASK_SSE, CODE_FOR_subv4sf3, "__builtin_ia32_subps", IX86_BUILTIN_SUBPS, 0, 0 },
+  { MASK_SSE, CODE_FOR_mulv4sf3, "__builtin_ia32_mulps", IX86_BUILTIN_MULPS, 0, 0 },
+  { MASK_SSE, CODE_FOR_divv4sf3, "__builtin_ia32_divps", IX86_BUILTIN_DIVPS, 0, 0 },
+  { MASK_SSE, CODE_FOR_vmaddv4sf3,  "__builtin_ia32_addss", IX86_BUILTIN_ADDSS, 0, 0 },
+  { MASK_SSE, CODE_FOR_vmsubv4sf3,  "__builtin_ia32_subss", IX86_BUILTIN_SUBSS, 0, 0 },
+  { MASK_SSE, CODE_FOR_vmmulv4sf3,  "__builtin_ia32_mulss", IX86_BUILTIN_MULSS, 0, 0 },
+  { MASK_SSE, CODE_FOR_vmdivv4sf3,  "__builtin_ia32_divss", IX86_BUILTIN_DIVSS, 0, 0 },
+
+  { MASK_SSE, CODE_FOR_maskcmpv4sf3, "__builtin_ia32_cmpeqps", IX86_BUILTIN_CMPEQPS, EQ, 0 },
+  { MASK_SSE, CODE_FOR_maskcmpv4sf3, "__builtin_ia32_cmpltps", IX86_BUILTIN_CMPLTPS, LT, 0 },
+  { MASK_SSE, CODE_FOR_maskcmpv4sf3, "__builtin_ia32_cmpleps", IX86_BUILTIN_CMPLEPS, LE, 0 },
+  { MASK_SSE, CODE_FOR_maskcmpv4sf3, "__builtin_ia32_cmpgtps", IX86_BUILTIN_CMPGTPS, LT, 1 },
+  { MASK_SSE, CODE_FOR_maskcmpv4sf3, "__builtin_ia32_cmpgeps", IX86_BUILTIN_CMPGEPS, LE, 1 },
+  { MASK_SSE, CODE_FOR_maskcmpv4sf3, "__builtin_ia32_cmpunordps", IX86_BUILTIN_CMPUNORDPS, UNORDERED, 0 },
+  { MASK_SSE, CODE_FOR_maskncmpv4sf3, "__builtin_ia32_cmpneqps", IX86_BUILTIN_CMPNEQPS, EQ, 0 },
+  { MASK_SSE, CODE_FOR_maskncmpv4sf3, "__builtin_ia32_cmpnltps", IX86_BUILTIN_CMPNLTPS, LT, 0 },
+  { MASK_SSE, CODE_FOR_maskncmpv4sf3, "__builtin_ia32_cmpnleps", IX86_BUILTIN_CMPNLEPS, LE, 0 },
+  { MASK_SSE, CODE_FOR_maskncmpv4sf3, "__builtin_ia32_cmpngtps", IX86_BUILTIN_CMPNGTPS, LT, 1 },
+  { MASK_SSE, CODE_FOR_maskncmpv4sf3, "__builtin_ia32_cmpngeps", IX86_BUILTIN_CMPNGEPS, LE, 1 },
+  { MASK_SSE, CODE_FOR_maskncmpv4sf3, "__builtin_ia32_cmpordps", IX86_BUILTIN_CMPORDPS, UNORDERED, 0 },
+  { MASK_SSE, CODE_FOR_vmmaskcmpv4sf3, "__builtin_ia32_cmpeqss", IX86_BUILTIN_CMPEQSS, EQ, 0 },
+  { MASK_SSE, CODE_FOR_vmmaskcmpv4sf3, "__builtin_ia32_cmpltss", IX86_BUILTIN_CMPLTSS, LT, 0 },
+  { MASK_SSE, CODE_FOR_vmmaskcmpv4sf3, "__builtin_ia32_cmpless", IX86_BUILTIN_CMPLESS, LE, 0 },
+  { MASK_SSE, CODE_FOR_vmmaskcmpv4sf3, "__builtin_ia32_cmpgtss", IX86_BUILTIN_CMPGTSS, LT, 1 },
+  { MASK_SSE, CODE_FOR_vmmaskcmpv4sf3, "__builtin_ia32_cmpgess", IX86_BUILTIN_CMPGESS, LE, 1 },
+  { MASK_SSE, CODE_FOR_vmmaskcmpv4sf3, "__builtin_ia32_cmpunordss", IX86_BUILTIN_CMPUNORDSS, UNORDERED, 0 },
+  { MASK_SSE, CODE_FOR_vmmaskncmpv4sf3, "__builtin_ia32_cmpneqss", IX86_BUILTIN_CMPNEQSS, EQ, 0 },
+  { MASK_SSE, CODE_FOR_vmmaskncmpv4sf3, "__builtin_ia32_cmpnltss", IX86_BUILTIN_CMPNLTSS, LT, 0 },
+  { MASK_SSE, CODE_FOR_vmmaskncmpv4sf3, "__builtin_ia32_cmpnless", IX86_BUILTIN_CMPNLESS, LE, 0 },
+  { MASK_SSE, CODE_FOR_vmmaskncmpv4sf3, "__builtin_ia32_cmpngtss", IX86_BUILTIN_CMPNGTSS, LT, 1 },
+  { MASK_SSE, CODE_FOR_vmmaskncmpv4sf3, "__builtin_ia32_cmpngess", IX86_BUILTIN_CMPNGESS, LE, 1 },
+  { MASK_SSE, CODE_FOR_vmmaskncmpv4sf3, "__builtin_ia32_cmpordss", IX86_BUILTIN_CMPORDSS, UNORDERED, 0 },
+
+  { MASK_SSE, CODE_FOR_sminv4sf3, "__builtin_ia32_minps", IX86_BUILTIN_MINPS, 0, 0 },
+  { MASK_SSE, CODE_FOR_smaxv4sf3, "__builtin_ia32_maxps", IX86_BUILTIN_MAXPS, 0, 0 },
+  { MASK_SSE, CODE_FOR_vmsminv4sf3, "__builtin_ia32_minss", IX86_BUILTIN_MINSS, 0, 0 },
+  { MASK_SSE, CODE_FOR_vmsmaxv4sf3, "__builtin_ia32_maxss", IX86_BUILTIN_MAXSS, 0, 0 },
+
+  { MASK_SSE, CODE_FOR_sse_andti3, "__builtin_ia32_andps", IX86_BUILTIN_ANDPS, 0, 0 },
+  { MASK_SSE, CODE_FOR_sse_nandti3,  "__builtin_ia32_andnps", IX86_BUILTIN_ANDNPS, 0, 0 },
+  { MASK_SSE, CODE_FOR_sse_iorti3, "__builtin_ia32_orps", IX86_BUILTIN_ORPS, 0, 0 },
+  { MASK_SSE, CODE_FOR_sse_xorti3,  "__builtin_ia32_xorps", IX86_BUILTIN_XORPS, 0, 0 },
+
+  { MASK_SSE, CODE_FOR_sse_movss,  "__builtin_ia32_movss", IX86_BUILTIN_MOVSS, 0, 0 },
+  { MASK_SSE, CODE_FOR_sse_movhlps,  "__builtin_ia32_movhlps", IX86_BUILTIN_MOVHLPS, 0, 0 },
+  { MASK_SSE, CODE_FOR_sse_movlhps,  "__builtin_ia32_movlhps", IX86_BUILTIN_MOVLHPS, 0, 0 },
+  { MASK_SSE, CODE_FOR_sse_unpckhps, "__builtin_ia32_unpckhps", IX86_BUILTIN_UNPCKHPS, 0, 0 },
+  { MASK_SSE, CODE_FOR_sse_unpcklps, "__builtin_ia32_unpcklps", IX86_BUILTIN_UNPCKLPS, 0, 0 },
 
   /* MMX */
-  { CODE_FOR_addv8qi3, "__builtin_ia32_paddb", IX86_BUILTIN_PADDB, 0, 0 },
-  { CODE_FOR_addv4hi3, "__builtin_ia32_paddw", IX86_BUILTIN_PADDW, 0, 0 },
-  { CODE_FOR_addv2si3, "__builtin_ia32_paddd", IX86_BUILTIN_PADDD, 0, 0 },
-  { CODE_FOR_subv8qi3, "__builtin_ia32_psubb", IX86_BUILTIN_PSUBB, 0, 0 },
-  { CODE_FOR_subv4hi3, "__builtin_ia32_psubw", IX86_BUILTIN_PSUBW, 0, 0 },
-  { CODE_FOR_subv2si3, "__builtin_ia32_psubd", IX86_BUILTIN_PSUBD, 0, 0 },
-
-  { CODE_FOR_ssaddv8qi3, "__builtin_ia32_paddsb", IX86_BUILTIN_PADDSB, 0, 0 },
-  { CODE_FOR_ssaddv4hi3, "__builtin_ia32_paddsw", IX86_BUILTIN_PADDSW, 0, 0 },
-  { CODE_FOR_sssubv8qi3, "__builtin_ia32_psubsb", IX86_BUILTIN_PSUBSB, 0, 0 },
-  { CODE_FOR_sssubv4hi3, "__builtin_ia32_psubsw", IX86_BUILTIN_PSUBSW, 0, 0 },
-  { CODE_FOR_usaddv8qi3, "__builtin_ia32_paddusb", IX86_BUILTIN_PADDUSB, 0, 0 },
-  { CODE_FOR_usaddv4hi3, "__builtin_ia32_paddusw", IX86_BUILTIN_PADDUSW, 0, 0 },
-  { CODE_FOR_ussubv8qi3, "__builtin_ia32_psubusb", IX86_BUILTIN_PSUBUSB, 0, 0 },
-  { CODE_FOR_ussubv4hi3, "__builtin_ia32_psubusw", IX86_BUILTIN_PSUBUSW, 0, 0 },
-
-  { CODE_FOR_mulv4hi3, "__builtin_ia32_pmullw", IX86_BUILTIN_PMULLW, 0, 0 },
-  { CODE_FOR_smulv4hi3_highpart, "__builtin_ia32_pmulhw", IX86_BUILTIN_PMULHW, 0, 0 },
-  { CODE_FOR_umulv4hi3_highpart, "__builtin_ia32_pmulhuw", IX86_BUILTIN_PMULHUW, 0, 0 },
-
-  { CODE_FOR_mmx_anddi3, "__builtin_ia32_pand", IX86_BUILTIN_PAND, 0, 0 },
-  { CODE_FOR_mmx_nanddi3, "__builtin_ia32_pandn", IX86_BUILTIN_PANDN, 0, 0 },
-  { CODE_FOR_mmx_iordi3, "__builtin_ia32_por", IX86_BUILTIN_POR, 0, 0 },
-  { CODE_FOR_mmx_xordi3, "__builtin_ia32_pxor", IX86_BUILTIN_PXOR, 0, 0 },
-
-  { CODE_FOR_mmx_uavgv8qi3, "__builtin_ia32_pavgb", IX86_BUILTIN_PAVGB, 0, 0 },
-  { CODE_FOR_mmx_uavgv4hi3, "__builtin_ia32_pavgw", IX86_BUILTIN_PAVGW, 0, 0 },
-
-  { CODE_FOR_eqv8qi3, "__builtin_ia32_pcmpeqb", IX86_BUILTIN_PCMPEQB, 0, 0 },
-  { CODE_FOR_eqv4hi3, "__builtin_ia32_pcmpeqw", IX86_BUILTIN_PCMPEQW, 0, 0 },
-  { CODE_FOR_eqv2si3, "__builtin_ia32_pcmpeqd", IX86_BUILTIN_PCMPEQD, 0, 0 },
-  { CODE_FOR_gtv8qi3, "__builtin_ia32_pcmpgtb", IX86_BUILTIN_PCMPGTB, 0, 0 },
-  { CODE_FOR_gtv4hi3, "__builtin_ia32_pcmpgtw", IX86_BUILTIN_PCMPGTW, 0, 0 },
-  { CODE_FOR_gtv2si3, "__builtin_ia32_pcmpgtd", IX86_BUILTIN_PCMPGTD, 0, 0 },
-
-  { CODE_FOR_umaxv8qi3, "__builtin_ia32_pmaxub", IX86_BUILTIN_PMAXUB, 0, 0 },
-  { CODE_FOR_smaxv4hi3, "__builtin_ia32_pmaxsw", IX86_BUILTIN_PMAXSW, 0, 0 },
-  { CODE_FOR_uminv8qi3, "__builtin_ia32_pminub", IX86_BUILTIN_PMINUB, 0, 0 },
-  { CODE_FOR_sminv4hi3, "__builtin_ia32_pminsw", IX86_BUILTIN_PMINSW, 0, 0 },
-
-  { CODE_FOR_mmx_punpckhbw, "__builtin_ia32_punpckhbw", IX86_BUILTIN_PUNPCKHBW, 0, 0 },
-  { CODE_FOR_mmx_punpckhwd, "__builtin_ia32_punpckhwd", IX86_BUILTIN_PUNPCKHWD, 0, 0 },
-  { CODE_FOR_mmx_punpckhdq, "__builtin_ia32_punpckhdq", IX86_BUILTIN_PUNPCKHDQ, 0, 0 },
-  { CODE_FOR_mmx_punpcklbw, "__builtin_ia32_punpcklbw", IX86_BUILTIN_PUNPCKLBW, 0, 0 },
-  { CODE_FOR_mmx_punpcklwd, "__builtin_ia32_punpcklwd", IX86_BUILTIN_PUNPCKLWD, 0, 0 },
-  { CODE_FOR_mmx_punpckldq, "__builtin_ia32_punpckldq", IX86_BUILTIN_PUNPCKLDQ, 0, 0 },
+  { MASK_MMX, CODE_FOR_addv8qi3, "__builtin_ia32_paddb", IX86_BUILTIN_PADDB, 0, 0 },
+  { MASK_MMX, CODE_FOR_addv4hi3, "__builtin_ia32_paddw", IX86_BUILTIN_PADDW, 0, 0 },
+  { MASK_MMX, CODE_FOR_addv2si3, "__builtin_ia32_paddd", IX86_BUILTIN_PADDD, 0, 0 },
+  { MASK_MMX, CODE_FOR_subv8qi3, "__builtin_ia32_psubb", IX86_BUILTIN_PSUBB, 0, 0 },
+  { MASK_MMX, CODE_FOR_subv4hi3, "__builtin_ia32_psubw", IX86_BUILTIN_PSUBW, 0, 0 },
+  { MASK_MMX, CODE_FOR_subv2si3, "__builtin_ia32_psubd", IX86_BUILTIN_PSUBD, 0, 0 },
+
+  { MASK_MMX, CODE_FOR_ssaddv8qi3, "__builtin_ia32_paddsb", IX86_BUILTIN_PADDSB, 0, 0 },
+  { MASK_MMX, CODE_FOR_ssaddv4hi3, "__builtin_ia32_paddsw", IX86_BUILTIN_PADDSW, 0, 0 },
+  { MASK_MMX, CODE_FOR_sssubv8qi3, "__builtin_ia32_psubsb", IX86_BUILTIN_PSUBSB, 0, 0 },
+  { MASK_MMX, CODE_FOR_sssubv4hi3, "__builtin_ia32_psubsw", IX86_BUILTIN_PSUBSW, 0, 0 },
+  { MASK_MMX, CODE_FOR_usaddv8qi3, "__builtin_ia32_paddusb", IX86_BUILTIN_PADDUSB, 0, 0 },
+  { MASK_MMX, CODE_FOR_usaddv4hi3, "__builtin_ia32_paddusw", IX86_BUILTIN_PADDUSW, 0, 0 },
+  { MASK_MMX, CODE_FOR_ussubv8qi3, "__builtin_ia32_psubusb", IX86_BUILTIN_PSUBUSB, 0, 0 },
+  { MASK_MMX, CODE_FOR_ussubv4hi3, "__builtin_ia32_psubusw", IX86_BUILTIN_PSUBUSW, 0, 0 },
+
+  { MASK_MMX, CODE_FOR_mulv4hi3, "__builtin_ia32_pmullw", IX86_BUILTIN_PMULLW, 0, 0 },
+  { MASK_MMX, CODE_FOR_smulv4hi3_highpart, "__builtin_ia32_pmulhw", IX86_BUILTIN_PMULHW, 0, 0 },
+  { MASK_SSE | MASK_3DNOW_A, CODE_FOR_umulv4hi3_highpart, "__builtin_ia32_pmulhuw", IX86_BUILTIN_PMULHUW, 0, 0 },
+
+  { MASK_MMX, CODE_FOR_mmx_anddi3, "__builtin_ia32_pand", IX86_BUILTIN_PAND, 0, 0 },
+  { MASK_MMX, CODE_FOR_mmx_nanddi3, "__builtin_ia32_pandn", IX86_BUILTIN_PANDN, 0, 0 },
+  { MASK_MMX, CODE_FOR_mmx_iordi3, "__builtin_ia32_por", IX86_BUILTIN_POR, 0, 0 },
+  { MASK_MMX, CODE_FOR_mmx_xordi3, "__builtin_ia32_pxor", IX86_BUILTIN_PXOR, 0, 0 },
+
+  { MASK_SSE | MASK_3DNOW_A, CODE_FOR_mmx_uavgv8qi3, "__builtin_ia32_pavgb", IX86_BUILTIN_PAVGB, 0, 0 },
+  { MASK_SSE | MASK_3DNOW_A, CODE_FOR_mmx_uavgv4hi3, "__builtin_ia32_pavgw", IX86_BUILTIN_PAVGW, 0, 0 },
+
+  { MASK_MMX, CODE_FOR_eqv8qi3, "__builtin_ia32_pcmpeqb", IX86_BUILTIN_PCMPEQB, 0, 0 },
+  { MASK_MMX, CODE_FOR_eqv4hi3, "__builtin_ia32_pcmpeqw", IX86_BUILTIN_PCMPEQW, 0, 0 },
+  { MASK_MMX, CODE_FOR_eqv2si3, "__builtin_ia32_pcmpeqd", IX86_BUILTIN_PCMPEQD, 0, 0 },
+  { MASK_MMX, CODE_FOR_gtv8qi3, "__builtin_ia32_pcmpgtb", IX86_BUILTIN_PCMPGTB, 0, 0 },
+  { MASK_MMX, CODE_FOR_gtv4hi3, "__builtin_ia32_pcmpgtw", IX86_BUILTIN_PCMPGTW, 0, 0 },
+  { MASK_MMX, CODE_FOR_gtv2si3, "__builtin_ia32_pcmpgtd", IX86_BUILTIN_PCMPGTD, 0, 0 },
+
+  { MASK_SSE | MASK_3DNOW_A, CODE_FOR_umaxv8qi3, "__builtin_ia32_pmaxub", IX86_BUILTIN_PMAXUB, 0, 0 },
+  { MASK_SSE | MASK_3DNOW_A, CODE_FOR_smaxv4hi3, "__builtin_ia32_pmaxsw", IX86_BUILTIN_PMAXSW, 0, 0 },
+  { MASK_SSE | MASK_3DNOW_A, CODE_FOR_uminv8qi3, "__builtin_ia32_pminub", IX86_BUILTIN_PMINUB, 0, 0 },
+  { MASK_SSE | MASK_3DNOW_A, CODE_FOR_sminv4hi3, "__builtin_ia32_pminsw", IX86_BUILTIN_PMINSW, 0, 0 },
+
+  { MASK_MMX, CODE_FOR_mmx_punpckhbw, "__builtin_ia32_punpckhbw", IX86_BUILTIN_PUNPCKHBW, 0, 0 },
+  { MASK_MMX, CODE_FOR_mmx_punpckhwd, "__builtin_ia32_punpckhwd", IX86_BUILTIN_PUNPCKHWD, 0, 0 },
+  { MASK_MMX, CODE_FOR_mmx_punpckhdq, "__builtin_ia32_punpckhdq", IX86_BUILTIN_PUNPCKHDQ, 0, 0 },
+  { MASK_MMX, CODE_FOR_mmx_punpcklbw, "__builtin_ia32_punpcklbw", IX86_BUILTIN_PUNPCKLBW, 0, 0 },
+  { MASK_MMX, CODE_FOR_mmx_punpcklwd, "__builtin_ia32_punpcklwd", IX86_BUILTIN_PUNPCKLWD, 0, 0 },
+  { MASK_MMX, CODE_FOR_mmx_punpckldq, "__builtin_ia32_punpckldq", IX86_BUILTIN_PUNPCKLDQ, 0, 0 },
 
   /* Special.  */
-  { CODE_FOR_mmx_packsswb, 0, IX86_BUILTIN_PACKSSWB, 0, 0 },
-  { CODE_FOR_mmx_packssdw, 0, IX86_BUILTIN_PACKSSDW, 0, 0 },
-  { CODE_FOR_mmx_packuswb, 0, IX86_BUILTIN_PACKUSWB, 0, 0 },
-
-  { CODE_FOR_cvtpi2ps, 0, IX86_BUILTIN_CVTPI2PS, 0, 0 },
-  { CODE_FOR_cvtsi2ss, 0, IX86_BUILTIN_CVTSI2SS, 0, 0 },
-
-  { CODE_FOR_ashlv4hi3, 0, IX86_BUILTIN_PSLLW, 0, 0 },
-  { CODE_FOR_ashlv4hi3, 0, IX86_BUILTIN_PSLLWI, 0, 0 },
-  { CODE_FOR_ashlv2si3, 0, IX86_BUILTIN_PSLLD, 0, 0 },
-  { CODE_FOR_ashlv2si3, 0, IX86_BUILTIN_PSLLDI, 0, 0 },
-  { CODE_FOR_mmx_ashldi3, 0, IX86_BUILTIN_PSLLQ, 0, 0 },
-  { CODE_FOR_mmx_ashldi3, 0, IX86_BUILTIN_PSLLQI, 0, 0 },
-
-  { CODE_FOR_lshrv4hi3, 0, IX86_BUILTIN_PSRLW, 0, 0 },
-  { CODE_FOR_lshrv4hi3, 0, IX86_BUILTIN_PSRLWI, 0, 0 },
-  { CODE_FOR_lshrv2si3, 0, IX86_BUILTIN_PSRLD, 0, 0 },
-  { CODE_FOR_lshrv2si3, 0, IX86_BUILTIN_PSRLDI, 0, 0 },
-  { CODE_FOR_mmx_lshrdi3, 0, IX86_BUILTIN_PSRLQ, 0, 0 },
-  { CODE_FOR_mmx_lshrdi3, 0, IX86_BUILTIN_PSRLQI, 0, 0 },
-
-  { CODE_FOR_ashrv4hi3, 0, IX86_BUILTIN_PSRAW, 0, 0 },
-  { CODE_FOR_ashrv4hi3, 0, IX86_BUILTIN_PSRAWI, 0, 0 },
-  { CODE_FOR_ashrv2si3, 0, IX86_BUILTIN_PSRAD, 0, 0 },
-  { CODE_FOR_ashrv2si3, 0, IX86_BUILTIN_PSRADI, 0, 0 },
-
-  { CODE_FOR_mmx_psadbw, 0, IX86_BUILTIN_PSADBW, 0, 0 },
-  { CODE_FOR_mmx_pmaddwd, 0, IX86_BUILTIN_PMADDWD, 0, 0 }
+  { MASK_MMX, CODE_FOR_mmx_packsswb, 0, IX86_BUILTIN_PACKSSWB, 0, 0 },
+  { MASK_MMX, CODE_FOR_mmx_packssdw, 0, IX86_BUILTIN_PACKSSDW, 0, 0 },
+  { MASK_MMX, CODE_FOR_mmx_packuswb, 0, IX86_BUILTIN_PACKUSWB, 0, 0 },
+
+  { MASK_SSE, CODE_FOR_cvtpi2ps, 0, IX86_BUILTIN_CVTPI2PS, 0, 0 },
+  { MASK_SSE, CODE_FOR_cvtsi2ss, 0, IX86_BUILTIN_CVTSI2SS, 0, 0 },
+
+  { MASK_MMX, CODE_FOR_ashlv4hi3, 0, IX86_BUILTIN_PSLLW, 0, 0 },
+  { MASK_MMX, CODE_FOR_ashlv4hi3, 0, IX86_BUILTIN_PSLLWI, 0, 0 },
+  { MASK_MMX, CODE_FOR_ashlv2si3, 0, IX86_BUILTIN_PSLLD, 0, 0 },
+  { MASK_MMX, CODE_FOR_ashlv2si3, 0, IX86_BUILTIN_PSLLDI, 0, 0 },
+  { MASK_MMX, CODE_FOR_mmx_ashldi3, 0, IX86_BUILTIN_PSLLQ, 0, 0 },
+  { MASK_MMX, CODE_FOR_mmx_ashldi3, 0, IX86_BUILTIN_PSLLQI, 0, 0 },
+
+  { MASK_MMX, CODE_FOR_lshrv4hi3, 0, IX86_BUILTIN_PSRLW, 0, 0 },
+  { MASK_MMX, CODE_FOR_lshrv4hi3, 0, IX86_BUILTIN_PSRLWI, 0, 0 },
+  { MASK_MMX, CODE_FOR_lshrv2si3, 0, IX86_BUILTIN_PSRLD, 0, 0 },
+  { MASK_MMX, CODE_FOR_lshrv2si3, 0, IX86_BUILTIN_PSRLDI, 0, 0 },
+  { MASK_MMX, CODE_FOR_mmx_lshrdi3, 0, IX86_BUILTIN_PSRLQ, 0, 0 },
+  { MASK_MMX, CODE_FOR_mmx_lshrdi3, 0, IX86_BUILTIN_PSRLQI, 0, 0 },
+
+  { MASK_MMX, CODE_FOR_ashrv4hi3, 0, IX86_BUILTIN_PSRAW, 0, 0 },
+  { MASK_MMX, CODE_FOR_ashrv4hi3, 0, IX86_BUILTIN_PSRAWI, 0, 0 },
+  { MASK_MMX, CODE_FOR_ashrv2si3, 0, IX86_BUILTIN_PSRAD, 0, 0 },
+  { MASK_MMX, CODE_FOR_ashrv2si3, 0, IX86_BUILTIN_PSRADI, 0, 0 },
+
+  { MASK_SSE, CODE_FOR_mmx_psadbw, 0, IX86_BUILTIN_PSADBW, 0, 0 },
+  { MASK_MMX, CODE_FOR_mmx_pmaddwd, 0, IX86_BUILTIN_PMADDWD, 0, 0 }
 
 };
 
-static struct builtin_description bdesc_1arg[] =
+static const struct builtin_description bdesc_1arg[] =
 {
-  { CODE_FOR_mmx_pmovmskb, 0, IX86_BUILTIN_PMOVMSKB, 0, 0 },
-  { CODE_FOR_sse_movmskps, 0, IX86_BUILTIN_MOVMSKPS, 0, 0 },
+  { MASK_SSE | MASK_3DNOW_A, CODE_FOR_mmx_pmovmskb, 0, IX86_BUILTIN_PMOVMSKB, 0, 0 },
+  { MASK_SSE, CODE_FOR_sse_movmskps, 0, IX86_BUILTIN_MOVMSKPS, 0, 0 },
 
-  { CODE_FOR_sqrtv4sf2, 0, IX86_BUILTIN_SQRTPS, 0, 0 },
-  { CODE_FOR_rsqrtv4sf2, 0, IX86_BUILTIN_RSQRTPS, 0, 0 },
-  { CODE_FOR_rcpv4sf2, 0, IX86_BUILTIN_RCPPS, 0, 0 },
+  { MASK_SSE, CODE_FOR_sqrtv4sf2, 0, IX86_BUILTIN_SQRTPS, 0, 0 },
+  { MASK_SSE, CODE_FOR_rsqrtv4sf2, 0, IX86_BUILTIN_RSQRTPS, 0, 0 },
+  { MASK_SSE, CODE_FOR_rcpv4sf2, 0, IX86_BUILTIN_RCPPS, 0, 0 },
 
-  { CODE_FOR_cvtps2pi, 0, IX86_BUILTIN_CVTPS2PI, 0, 0 },
-  { CODE_FOR_cvtss2si, 0, IX86_BUILTIN_CVTSS2SI, 0, 0 },
-  { CODE_FOR_cvttps2pi, 0, IX86_BUILTIN_CVTTPS2PI, 0, 0 },
-  { CODE_FOR_cvttss2si, 0, IX86_BUILTIN_CVTTSS2SI, 0, 0 }
+  { MASK_SSE, CODE_FOR_cvtps2pi, 0, IX86_BUILTIN_CVTPS2PI, 0, 0 },
+  { MASK_SSE, CODE_FOR_cvtss2si, 0, IX86_BUILTIN_CVTSS2SI, 0, 0 },
+  { MASK_SSE, CODE_FOR_cvttps2pi, 0, IX86_BUILTIN_CVTTPS2PI, 0, 0 },
+  { MASK_SSE, CODE_FOR_cvttss2si, 0, IX86_BUILTIN_CVTTSS2SI, 0, 0 }
 
 };
 
-/* Expand all the target specific builtins.  This is not called if TARGET_MMX
+void
+ix86_init_builtins ()
+{
+  if (TARGET_MMX)
+    ix86_init_mmx_sse_builtins ();
+}
+
+/* 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.  */
 void
-ix86_init_builtins ()
+ix86_init_mmx_sse_builtins ()
 {
-  struct builtin_description * d;
+  const struct builtin_description * d;
   size_t i;
   tree endlink = void_list_node;
 
@@ -9208,12 +10999,6 @@ ix86_init_builtins ()
                                                 V4SF_type_node,
                                                 endlink)));
   /* MMX/SSE/integer conversions.  */
-  tree int_ftype_v4sf_int
-    = build_function_type (integer_type_node,
-                          tree_cons (NULL_TREE, V4SF_type_node,
-                                     tree_cons (NULL_TREE,
-                                                integer_type_node,
-                                                endlink)));
   tree int_ftype_v4sf
     = build_function_type (integer_type_node,
                           tree_cons (NULL_TREE, V4SF_type_node,
@@ -9231,7 +11016,7 @@ ix86_init_builtins ()
                           tree_cons (NULL_TREE, integer_type_node,
                                      endlink));
   tree v4sf_ftype_v4sf_int
-    = build_function_type (integer_type_node,
+    = build_function_type (V4SF_type_node,
                           tree_cons (NULL_TREE, V4SF_type_node,
                                      tree_cons (NULL_TREE, integer_type_node,
                                                 endlink)));
@@ -9285,17 +11070,6 @@ ix86_init_builtins ()
                           tree_cons (NULL_TREE, V4HI_type_node,
                                      tree_cons (NULL_TREE, integer_type_node,
                                                 endlink)));
-  tree di_ftype_di_int
-    = build_function_type (long_long_unsigned_type_node,
-                          tree_cons (NULL_TREE, long_long_unsigned_type_node,
-                                     tree_cons (NULL_TREE, integer_type_node,
-                                                endlink)));
-  tree v8qi_ftype_v8qi_di
-    = build_function_type (V8QI_type_node,
-                          tree_cons (NULL_TREE, V8QI_type_node,
-                                     tree_cons (NULL_TREE,
-                                                long_long_integer_type_node,
-                                                endlink)));
   tree v4hi_ftype_v4hi_di
     = build_function_type (V4HI_type_node,
                           tree_cons (NULL_TREE, V4HI_type_node,
@@ -9360,10 +11134,10 @@ ix86_init_builtins ()
                           tree_cons (NULL_TREE, V4SF_type_node,
                                      tree_cons (NULL_TREE, pv2si_type_node,
                                                 endlink)));
-  tree v4sf_ftype_pv2si_v4sf
-    = build_function_type (V4SF_type_node,
-                          tree_cons (NULL_TREE, V4SF_type_node,
-                                     tree_cons (NULL_TREE, pv2si_type_node,
+  tree void_ftype_pv2si_v4sf
+    = build_function_type (void_type_node,
+                          tree_cons (NULL_TREE, pv2si_type_node,
+                                     tree_cons (NULL_TREE, V4SF_type_node,
                                                 endlink)));
   tree void_ftype_pfloat_v4sf
     = build_function_type (void_type_node,
@@ -9415,6 +11189,40 @@ ix86_init_builtins ()
                                                 long_long_unsigned_type_node,
                                                 endlink)));
 
+  tree v2si_ftype_v2sf
+    = build_function_type (V2SI_type_node,
+                           tree_cons (NULL_TREE, V2SF_type_node,
+                                      endlink));
+  tree v2sf_ftype_v2si
+    = build_function_type (V2SF_type_node,
+                           tree_cons (NULL_TREE, V2SI_type_node,
+                                      endlink));
+  tree v2si_ftype_v2si
+    = build_function_type (V2SI_type_node,
+                           tree_cons (NULL_TREE, V2SI_type_node,
+                                      endlink));
+  tree v2sf_ftype_v2sf
+    = build_function_type (V2SF_type_node,
+                           tree_cons (NULL_TREE, V2SF_type_node,
+                                      endlink));
+  tree v2sf_ftype_v2sf_v2sf
+    = build_function_type (V2SF_type_node,
+                           tree_cons (NULL_TREE, V2SF_type_node,
+                                      tree_cons (NULL_TREE,
+                                                 V2SF_type_node,
+                                                 endlink)));
+  tree v2si_ftype_v2sf_v2sf
+    = build_function_type (V2SI_type_node,
+                           tree_cons (NULL_TREE, V2SF_type_node,
+                                      tree_cons (NULL_TREE,
+                                                 V2SF_type_node,
+                                                 endlink)));
+
+  tree void_ftype_pchar
+    = build_function_type (void_type_node,
+                           tree_cons (NULL_TREE, pchar_type_node,
+                                      endlink));
+
   /* Add all builtins that are more or less simple operations on two
      operands.  */
   for (i = 0, d = bdesc_2arg; i < sizeof (bdesc_2arg) / sizeof *d; i++, d++)
@@ -9428,9 +11236,6 @@ ix86_init_builtins ()
        continue;
       mode = insn_data[d->icode].operand[1].mode;
 
-      if (! TARGET_SSE && ! VALID_MMX_REG_MODE (mode))
-       continue;
-
       switch (mode)
        {
        case V4SFmode:
@@ -9463,93 +11268,121 @@ ix86_init_builtins ()
          || d->icode == CODE_FOR_vmmaskncmpv4sf3)
        type = v4si_ftype_v4sf_v4sf;
 
-      def_builtin (d->name, type, d->code);
+      def_builtin (d->mask, d->name, type, d->code);
     }
 
   /* Add the remaining MMX insns with somewhat more complicated types.  */
-  def_builtin ("__builtin_ia32_m_from_int", v2si_ftype_int, IX86_BUILTIN_M_FROM_INT);
-  def_builtin ("__builtin_ia32_m_to_int", int_ftype_v2si, IX86_BUILTIN_M_TO_INT);
-  def_builtin ("__builtin_ia32_mmx_zero", di_ftype_void, IX86_BUILTIN_MMX_ZERO);
-  def_builtin ("__builtin_ia32_emms", void_ftype_void, IX86_BUILTIN_EMMS);
-  def_builtin ("__builtin_ia32_ldmxcsr", void_ftype_unsigned, IX86_BUILTIN_LDMXCSR);
-  def_builtin ("__builtin_ia32_stmxcsr", unsigned_ftype_void, IX86_BUILTIN_STMXCSR);
-  def_builtin ("__builtin_ia32_psllw", v4hi_ftype_v4hi_di, IX86_BUILTIN_PSLLW);
-  def_builtin ("__builtin_ia32_pslld", v2si_ftype_v2si_di, IX86_BUILTIN_PSLLD);
-  def_builtin ("__builtin_ia32_psllq", di_ftype_di_di, IX86_BUILTIN_PSLLQ);
-
-  def_builtin ("__builtin_ia32_psrlw", v4hi_ftype_v4hi_di, IX86_BUILTIN_PSRLW);
-  def_builtin ("__builtin_ia32_psrld", v2si_ftype_v2si_di, IX86_BUILTIN_PSRLD);
-  def_builtin ("__builtin_ia32_psrlq", di_ftype_di_di, IX86_BUILTIN_PSRLQ);
-
-  def_builtin ("__builtin_ia32_psraw", v4hi_ftype_v4hi_di, IX86_BUILTIN_PSRAW);
-  def_builtin ("__builtin_ia32_psrad", v2si_ftype_v2si_di, IX86_BUILTIN_PSRAD);
-
-  def_builtin ("__builtin_ia32_pshufw", v4hi_ftype_v4hi_int, IX86_BUILTIN_PSHUFW);
-  def_builtin ("__builtin_ia32_pmaddwd", v2si_ftype_v4hi_v4hi, IX86_BUILTIN_PMADDWD);
-
-  /* Everything beyond this point is SSE only.  */
-  if (! TARGET_SSE)
-    return;
+  def_builtin (MASK_MMX, "__builtin_ia32_m_from_int", v2si_ftype_int, IX86_BUILTIN_M_FROM_INT);
+  def_builtin (MASK_MMX, "__builtin_ia32_m_to_int", int_ftype_v2si, IX86_BUILTIN_M_TO_INT);
+  def_builtin (MASK_MMX, "__builtin_ia32_mmx_zero", di_ftype_void, IX86_BUILTIN_MMX_ZERO);
+  def_builtin (MASK_MMX, "__builtin_ia32_emms", void_ftype_void, IX86_BUILTIN_EMMS);
+  def_builtin (MASK_MMX, "__builtin_ia32_ldmxcsr", void_ftype_unsigned, IX86_BUILTIN_LDMXCSR);
+  def_builtin (MASK_MMX, "__builtin_ia32_stmxcsr", unsigned_ftype_void, IX86_BUILTIN_STMXCSR);
+  def_builtin (MASK_MMX, "__builtin_ia32_psllw", v4hi_ftype_v4hi_di, IX86_BUILTIN_PSLLW);
+  def_builtin (MASK_MMX, "__builtin_ia32_pslld", v2si_ftype_v2si_di, IX86_BUILTIN_PSLLD);
+  def_builtin (MASK_MMX, "__builtin_ia32_psllq", di_ftype_di_di, IX86_BUILTIN_PSLLQ);
+
+  def_builtin (MASK_MMX, "__builtin_ia32_psrlw", v4hi_ftype_v4hi_di, IX86_BUILTIN_PSRLW);
+  def_builtin (MASK_MMX, "__builtin_ia32_psrld", v2si_ftype_v2si_di, IX86_BUILTIN_PSRLD);
+  def_builtin (MASK_MMX, "__builtin_ia32_psrlq", di_ftype_di_di, IX86_BUILTIN_PSRLQ);
+
+  def_builtin (MASK_MMX, "__builtin_ia32_psraw", v4hi_ftype_v4hi_di, IX86_BUILTIN_PSRAW);
+  def_builtin (MASK_MMX, "__builtin_ia32_psrad", v2si_ftype_v2si_di, IX86_BUILTIN_PSRAD);
+
+  def_builtin (MASK_MMX, "__builtin_ia32_pshufw", v4hi_ftype_v4hi_int, IX86_BUILTIN_PSHUFW);
+  def_builtin (MASK_MMX, "__builtin_ia32_pmaddwd", v2si_ftype_v4hi_v4hi, IX86_BUILTIN_PMADDWD);
 
   /* comi/ucomi insns.  */
   for (i = 0, d = bdesc_comi; i < sizeof (bdesc_comi) / sizeof *d; i++, d++)
-    def_builtin (d->name, int_ftype_v4sf_v4sf, d->code);
-
-  def_builtin ("__builtin_ia32_packsswb", v8qi_ftype_v4hi_v4hi, IX86_BUILTIN_PACKSSWB);
-  def_builtin ("__builtin_ia32_packssdw", v4hi_ftype_v2si_v2si, IX86_BUILTIN_PACKSSDW);
-  def_builtin ("__builtin_ia32_packuswb", v8qi_ftype_v4hi_v4hi, IX86_BUILTIN_PACKUSWB);
-
-  def_builtin ("__builtin_ia32_cvtpi2ps", v4sf_ftype_v4sf_v2si, IX86_BUILTIN_CVTPI2PS);
-  def_builtin ("__builtin_ia32_cvtps2pi", v2si_ftype_v4sf, IX86_BUILTIN_CVTPS2PI);
-  def_builtin ("__builtin_ia32_cvtsi2ss", v4sf_ftype_v4sf_int, IX86_BUILTIN_CVTSI2SS);
-  def_builtin ("__builtin_ia32_cvtss2si", int_ftype_v4sf, IX86_BUILTIN_CVTSS2SI);
-  def_builtin ("__builtin_ia32_cvttps2pi", v2si_ftype_v4sf, IX86_BUILTIN_CVTTPS2PI);
-  def_builtin ("__builtin_ia32_cvttss2si", int_ftype_v4sf, IX86_BUILTIN_CVTTSS2SI);
-
-  def_builtin ("__builtin_ia32_pextrw", int_ftype_v4hi_int, IX86_BUILTIN_PEXTRW);
-  def_builtin ("__builtin_ia32_pinsrw", v4hi_ftype_v4hi_int_int, IX86_BUILTIN_PINSRW);
-
-  def_builtin ("__builtin_ia32_maskmovq", void_ftype_v8qi_v8qi_pchar, IX86_BUILTIN_MASKMOVQ);
-
-  def_builtin ("__builtin_ia32_loadaps", v4sf_ftype_pfloat, IX86_BUILTIN_LOADAPS);
-  def_builtin ("__builtin_ia32_loadups", v4sf_ftype_pfloat, IX86_BUILTIN_LOADUPS);
-  def_builtin ("__builtin_ia32_loadss", v4sf_ftype_pfloat, IX86_BUILTIN_LOADSS);
-  def_builtin ("__builtin_ia32_storeaps", void_ftype_pfloat_v4sf, IX86_BUILTIN_STOREAPS);
-  def_builtin ("__builtin_ia32_storeups", void_ftype_pfloat_v4sf, IX86_BUILTIN_STOREUPS);
-  def_builtin ("__builtin_ia32_storess", void_ftype_pfloat_v4sf, IX86_BUILTIN_STORESS);
-
-  def_builtin ("__builtin_ia32_loadhps", v4sf_ftype_v4sf_pv2si, IX86_BUILTIN_LOADHPS);
-  def_builtin ("__builtin_ia32_loadlps", v4sf_ftype_v4sf_pv2si, IX86_BUILTIN_LOADLPS);
-  def_builtin ("__builtin_ia32_storehps", v4sf_ftype_pv2si_v4sf, IX86_BUILTIN_STOREHPS);
-  def_builtin ("__builtin_ia32_storelps", v4sf_ftype_pv2si_v4sf, IX86_BUILTIN_STORELPS);
-
-  def_builtin ("__builtin_ia32_movmskps", int_ftype_v4sf, IX86_BUILTIN_MOVMSKPS);
-  def_builtin ("__builtin_ia32_pmovmskb", int_ftype_v8qi, IX86_BUILTIN_PMOVMSKB);
-  def_builtin ("__builtin_ia32_movntps", void_ftype_pfloat_v4sf, IX86_BUILTIN_MOVNTPS);
-  def_builtin ("__builtin_ia32_movntq", void_ftype_pdi_di, IX86_BUILTIN_MOVNTQ);
-
-  def_builtin ("__builtin_ia32_sfence", void_ftype_void, IX86_BUILTIN_SFENCE);
-  def_builtin ("__builtin_ia32_prefetch", void_ftype_pchar_int, IX86_BUILTIN_PREFETCH);
-
-  def_builtin ("__builtin_ia32_psadbw", v4hi_ftype_v8qi_v8qi, IX86_BUILTIN_PSADBW);
-
-  def_builtin ("__builtin_ia32_rcpps", v4sf_ftype_v4sf, IX86_BUILTIN_RCPPS);
-  def_builtin ("__builtin_ia32_rcpss", v4sf_ftype_v4sf, IX86_BUILTIN_RCPSS);
-  def_builtin ("__builtin_ia32_rsqrtps", v4sf_ftype_v4sf, IX86_BUILTIN_RSQRTPS);
-  def_builtin ("__builtin_ia32_rsqrtss", v4sf_ftype_v4sf, IX86_BUILTIN_RSQRTSS);
-  def_builtin ("__builtin_ia32_sqrtps", v4sf_ftype_v4sf, IX86_BUILTIN_SQRTPS);
-  def_builtin ("__builtin_ia32_sqrtss", v4sf_ftype_v4sf, IX86_BUILTIN_SQRTSS);
-
-  def_builtin ("__builtin_ia32_shufps", v4sf_ftype_v4sf_v4sf_int, IX86_BUILTIN_SHUFPS);
+    def_builtin (d->mask, d->name, int_ftype_v4sf_v4sf, d->code);
+
+  def_builtin (MASK_MMX, "__builtin_ia32_packsswb", v8qi_ftype_v4hi_v4hi, IX86_BUILTIN_PACKSSWB);
+  def_builtin (MASK_MMX, "__builtin_ia32_packssdw", v4hi_ftype_v2si_v2si, IX86_BUILTIN_PACKSSDW);
+  def_builtin (MASK_MMX, "__builtin_ia32_packuswb", v8qi_ftype_v4hi_v4hi, IX86_BUILTIN_PACKUSWB);
+
+  def_builtin (MASK_SSE, "__builtin_ia32_cvtpi2ps", v4sf_ftype_v4sf_v2si, IX86_BUILTIN_CVTPI2PS);
+  def_builtin (MASK_SSE, "__builtin_ia32_cvtps2pi", v2si_ftype_v4sf, IX86_BUILTIN_CVTPS2PI);
+  def_builtin (MASK_SSE, "__builtin_ia32_cvtsi2ss", v4sf_ftype_v4sf_int, IX86_BUILTIN_CVTSI2SS);
+  def_builtin (MASK_SSE, "__builtin_ia32_cvtss2si", int_ftype_v4sf, IX86_BUILTIN_CVTSS2SI);
+  def_builtin (MASK_SSE, "__builtin_ia32_cvttps2pi", v2si_ftype_v4sf, IX86_BUILTIN_CVTTPS2PI);
+  def_builtin (MASK_SSE, "__builtin_ia32_cvttss2si", int_ftype_v4sf, IX86_BUILTIN_CVTTSS2SI);
+
+  def_builtin (MASK_SSE | MASK_3DNOW_A, "__builtin_ia32_pextrw", int_ftype_v4hi_int, IX86_BUILTIN_PEXTRW);
+  def_builtin (MASK_SSE | MASK_3DNOW_A, "__builtin_ia32_pinsrw", v4hi_ftype_v4hi_int_int, IX86_BUILTIN_PINSRW);
+
+  def_builtin (MASK_SSE | MASK_3DNOW_A, "__builtin_ia32_maskmovq", void_ftype_v8qi_v8qi_pchar, IX86_BUILTIN_MASKMOVQ);
+
+  def_builtin (MASK_SSE, "__builtin_ia32_loadaps", v4sf_ftype_pfloat, IX86_BUILTIN_LOADAPS);
+  def_builtin (MASK_SSE, "__builtin_ia32_loadups", v4sf_ftype_pfloat, IX86_BUILTIN_LOADUPS);
+  def_builtin (MASK_SSE, "__builtin_ia32_loadss", v4sf_ftype_pfloat, IX86_BUILTIN_LOADSS);
+  def_builtin (MASK_SSE, "__builtin_ia32_storeaps", void_ftype_pfloat_v4sf, IX86_BUILTIN_STOREAPS);
+  def_builtin (MASK_SSE, "__builtin_ia32_storeups", void_ftype_pfloat_v4sf, IX86_BUILTIN_STOREUPS);
+  def_builtin (MASK_SSE, "__builtin_ia32_storess", void_ftype_pfloat_v4sf, IX86_BUILTIN_STORESS);
+
+  def_builtin (MASK_SSE, "__builtin_ia32_loadhps", v4sf_ftype_v4sf_pv2si, IX86_BUILTIN_LOADHPS);
+  def_builtin (MASK_SSE, "__builtin_ia32_loadlps", v4sf_ftype_v4sf_pv2si, IX86_BUILTIN_LOADLPS);
+  def_builtin (MASK_SSE, "__builtin_ia32_storehps", void_ftype_pv2si_v4sf, IX86_BUILTIN_STOREHPS);
+  def_builtin (MASK_SSE, "__builtin_ia32_storelps", void_ftype_pv2si_v4sf, IX86_BUILTIN_STORELPS);
+
+  def_builtin (MASK_SSE, "__builtin_ia32_movmskps", int_ftype_v4sf, IX86_BUILTIN_MOVMSKPS);
+  def_builtin (MASK_SSE | MASK_3DNOW_A, "__builtin_ia32_pmovmskb", int_ftype_v8qi, IX86_BUILTIN_PMOVMSKB);
+  def_builtin (MASK_SSE, "__builtin_ia32_movntps", void_ftype_pfloat_v4sf, IX86_BUILTIN_MOVNTPS);
+  def_builtin (MASK_SSE | MASK_3DNOW_A, "__builtin_ia32_movntq", void_ftype_pdi_di, IX86_BUILTIN_MOVNTQ);
+
+  def_builtin (MASK_SSE | MASK_3DNOW_A, "__builtin_ia32_sfence", void_ftype_void, IX86_BUILTIN_SFENCE);
+  def_builtin (MASK_SSE | MASK_3DNOW_A, "__builtin_ia32_prefetch", void_ftype_pchar_int, IX86_BUILTIN_PREFETCH);
+
+  def_builtin (MASK_SSE | MASK_3DNOW_A, "__builtin_ia32_psadbw", v4hi_ftype_v8qi_v8qi, IX86_BUILTIN_PSADBW);
+
+  def_builtin (MASK_SSE, "__builtin_ia32_rcpps", v4sf_ftype_v4sf, IX86_BUILTIN_RCPPS);
+  def_builtin (MASK_SSE, "__builtin_ia32_rcpss", v4sf_ftype_v4sf, IX86_BUILTIN_RCPSS);
+  def_builtin (MASK_SSE, "__builtin_ia32_rsqrtps", v4sf_ftype_v4sf, IX86_BUILTIN_RSQRTPS);
+  def_builtin (MASK_SSE, "__builtin_ia32_rsqrtss", v4sf_ftype_v4sf, IX86_BUILTIN_RSQRTSS);
+  def_builtin (MASK_SSE, "__builtin_ia32_sqrtps", v4sf_ftype_v4sf, IX86_BUILTIN_SQRTPS);
+  def_builtin (MASK_SSE, "__builtin_ia32_sqrtss", v4sf_ftype_v4sf, IX86_BUILTIN_SQRTSS);
+
+  def_builtin (MASK_SSE, "__builtin_ia32_shufps", v4sf_ftype_v4sf_v4sf_int, IX86_BUILTIN_SHUFPS);
+
+  /* Original 3DNow!  */
+  def_builtin (MASK_3DNOW, "__builtin_ia32_femms", void_ftype_void, IX86_BUILTIN_FEMMS);
+  def_builtin (MASK_3DNOW, "__builtin_ia32_pavgusb", v8qi_ftype_v8qi_v8qi, IX86_BUILTIN_PAVGUSB);
+  def_builtin (MASK_3DNOW, "__builtin_ia32_pf2id", v2si_ftype_v2sf, IX86_BUILTIN_PF2ID);
+  def_builtin (MASK_3DNOW, "__builtin_ia32_pfacc", v2sf_ftype_v2sf_v2sf, IX86_BUILTIN_PFACC);
+  def_builtin (MASK_3DNOW, "__builtin_ia32_pfadd", v2sf_ftype_v2sf_v2sf, IX86_BUILTIN_PFADD);
+  def_builtin (MASK_3DNOW, "__builtin_ia32_pfcmpeq", v2si_ftype_v2sf_v2sf, IX86_BUILTIN_PFCMPEQ);
+  def_builtin (MASK_3DNOW, "__builtin_ia32_pfcmpge", v2si_ftype_v2sf_v2sf, IX86_BUILTIN_PFCMPGE);
+  def_builtin (MASK_3DNOW, "__builtin_ia32_pfcmpgt", v2si_ftype_v2sf_v2sf, IX86_BUILTIN_PFCMPGT);
+  def_builtin (MASK_3DNOW, "__builtin_ia32_pfmax", v2sf_ftype_v2sf_v2sf, IX86_BUILTIN_PFMAX);
+  def_builtin (MASK_3DNOW, "__builtin_ia32_pfmin", v2sf_ftype_v2sf_v2sf, IX86_BUILTIN_PFMIN);
+  def_builtin (MASK_3DNOW, "__builtin_ia32_pfmul", v2sf_ftype_v2sf_v2sf, IX86_BUILTIN_PFMUL);
+  def_builtin (MASK_3DNOW, "__builtin_ia32_pfrcp", v2sf_ftype_v2sf, IX86_BUILTIN_PFRCP);
+  def_builtin (MASK_3DNOW, "__builtin_ia32_pfrcpit1", v2sf_ftype_v2sf_v2sf, IX86_BUILTIN_PFRCPIT1);
+  def_builtin (MASK_3DNOW, "__builtin_ia32_pfrcpit2", v2sf_ftype_v2sf_v2sf, IX86_BUILTIN_PFRCPIT2);
+  def_builtin (MASK_3DNOW, "__builtin_ia32_pfrsqrt", v2sf_ftype_v2sf, IX86_BUILTIN_PFRSQRT);
+  def_builtin (MASK_3DNOW, "__builtin_ia32_pfrsqit1", v2sf_ftype_v2sf_v2sf, IX86_BUILTIN_PFRSQIT1);
+  def_builtin (MASK_3DNOW, "__builtin_ia32_pfsub", v2sf_ftype_v2sf_v2sf, IX86_BUILTIN_PFSUB);
+  def_builtin (MASK_3DNOW, "__builtin_ia32_pfsubr", v2sf_ftype_v2sf_v2sf, IX86_BUILTIN_PFSUBR);
+  def_builtin (MASK_3DNOW, "__builtin_ia32_pi2fd", v2sf_ftype_v2si, IX86_BUILTIN_PI2FD);
+  def_builtin (MASK_3DNOW, "__builtin_ia32_pmulhrw", v4hi_ftype_v4hi_v4hi, IX86_BUILTIN_PMULHRW);
+  def_builtin (MASK_3DNOW, "__builtin_ia32_prefetch_3dnow", void_ftype_pchar, IX86_BUILTIN_PREFETCH_3DNOW);
+  def_builtin (MASK_3DNOW, "__builtin_ia32_prefetchw", void_ftype_pchar, IX86_BUILTIN_PREFETCHW);
+
+  /* 3DNow! extension as used in the Athlon CPU.  */
+  def_builtin (MASK_3DNOW_A, "__builtin_ia32_pf2iw", v2si_ftype_v2sf, IX86_BUILTIN_PF2IW);
+  def_builtin (MASK_3DNOW_A, "__builtin_ia32_pfnacc", v2sf_ftype_v2sf_v2sf, IX86_BUILTIN_PFNACC);
+  def_builtin (MASK_3DNOW_A, "__builtin_ia32_pfpnacc", v2sf_ftype_v2sf_v2sf, IX86_BUILTIN_PFPNACC);
+  def_builtin (MASK_3DNOW_A, "__builtin_ia32_pi2fw", v2sf_ftype_v2si, IX86_BUILTIN_PI2FW);
+  def_builtin (MASK_3DNOW_A, "__builtin_ia32_pswapdsf", v2sf_ftype_v2sf, IX86_BUILTIN_PSWAPDSF);
+  def_builtin (MASK_3DNOW_A, "__builtin_ia32_pswapdsi", v2si_ftype_v2si, IX86_BUILTIN_PSWAPDSI);
 
   /* Composite intrinsics.  */
-  def_builtin ("__builtin_ia32_setps1", v4sf_ftype_float, IX86_BUILTIN_SETPS1);
-  def_builtin ("__builtin_ia32_setps", v4sf_ftype_float_float_float_float, IX86_BUILTIN_SETPS);
-  def_builtin ("__builtin_ia32_setzerops", ti_ftype_void, IX86_BUILTIN_CLRPS);
-  def_builtin ("__builtin_ia32_loadps1", v4sf_ftype_pfloat, IX86_BUILTIN_LOADPS1);
-  def_builtin ("__builtin_ia32_loadrps", v4sf_ftype_pfloat, IX86_BUILTIN_LOADRPS);
-  def_builtin ("__builtin_ia32_storeps1", void_ftype_pfloat_v4sf, IX86_BUILTIN_STOREPS1);
-  def_builtin ("__builtin_ia32_storerps", void_ftype_pfloat_v4sf, IX86_BUILTIN_STORERPS);
+  def_builtin (MASK_SSE, "__builtin_ia32_setps1", v4sf_ftype_float, IX86_BUILTIN_SETPS1);
+  def_builtin (MASK_SSE, "__builtin_ia32_setps", v4sf_ftype_float_float_float_float, IX86_BUILTIN_SETPS);
+  def_builtin (MASK_SSE, "__builtin_ia32_setzerops", ti_ftype_void, IX86_BUILTIN_CLRPS);
+  def_builtin (MASK_SSE, "__builtin_ia32_loadps1", v4sf_ftype_pfloat, IX86_BUILTIN_LOADPS1);
+  def_builtin (MASK_SSE, "__builtin_ia32_loadrps", v4sf_ftype_pfloat, IX86_BUILTIN_LOADRPS);
+  def_builtin (MASK_SSE, "__builtin_ia32_storeps1", void_ftype_pfloat_v4sf, IX86_BUILTIN_STOREPS1);
+  def_builtin (MASK_SSE, "__builtin_ia32_storerps", void_ftype_pfloat_v4sf, IX86_BUILTIN_STORERPS);
 }
 
 /* Errors in the source file can cause expand_expr to return const0_rtx
@@ -9564,7 +11397,7 @@ safe_vector_operand (x, mode)
     return x;
   x = gen_reg_rtx (mode);
 
-  if (VALID_MMX_REG_MODE (mode))
+  if (VALID_MMX_REG_MODE (mode) || VALID_MMX_REG_MODE_3DNOW (mode))
     emit_insn (gen_mmx_clrdi (mode == DImode ? x
                              : gen_rtx_SUBREG (DImode, x, 0)));
   else
@@ -9721,7 +11554,7 @@ ix86_expand_unop1_builtin (icode, arglist, target)
 
 static rtx
 ix86_expand_sse_compare (d, arglist, target)
-     struct builtin_description *d;
+     const struct builtin_description *d;
      tree arglist;
      rtx target;
 {
@@ -9745,15 +11578,15 @@ ix86_expand_sse_compare (d, arglist, target)
      hardware.  */
   if (d->flag)
     {
-      target = gen_reg_rtx (tmode);
-      emit_move_insn (target, op1);
+      rtx tmp = gen_reg_rtx (mode1);
+      emit_move_insn (tmp, op1);
       op1 = op0;
-      op0 = target;
-      comparison = swap_condition (comparison);
+      op0 = tmp;
     }
-  else if (! target
-          || GET_MODE (target) != tmode
-          || ! (*insn_data[d->icode].operand[0].predicate) (target, tmode))
+
+  if (! target
+      || GET_MODE (target) != tmode
+      || ! (*insn_data[d->icode].operand[0].predicate) (target, tmode))
     target = gen_reg_rtx (tmode);
 
   if (! (*insn_data[d->icode].operand[1].predicate) (op0, mode0))
@@ -9773,7 +11606,7 @@ ix86_expand_sse_compare (d, arglist, target)
 
 static rtx
 ix86_expand_sse_comi (d, arglist, target)
-     struct builtin_description *d;
+     const struct builtin_description *d;
      tree arglist;
      rtx target;
 {
@@ -9799,7 +11632,6 @@ ix86_expand_sse_comi (d, arglist, target)
       rtx tmp = op1;
       op1 = op0;
       op0 = tmp;
-      comparison = swap_condition (comparison);
     }
 
   target = gen_reg_rtx (SImode);
@@ -9816,7 +11648,11 @@ ix86_expand_sse_comi (d, arglist, target)
   if (! pat)
     return 0;
   emit_insn (pat);
-  emit_insn (gen_setcc_2 (target, op2));
+  emit_insn (gen_rtx_SET (VOIDmode,
+                         gen_rtx_STRICT_LOW_PART (VOIDmode, target),
+                         gen_rtx_fmt_ee (comparison, QImode,
+                                         gen_rtx_REG (CCmode, FLAGS_REG),
+                                         const0_rtx)));
 
   return target;
 }
@@ -9835,7 +11671,7 @@ ix86_expand_builtin (exp, target, subtarget, mode, ignore)
      enum machine_mode mode ATTRIBUTE_UNUSED;
      int ignore ATTRIBUTE_UNUSED;
 {
-  struct builtin_description *d;
+  const struct builtin_description *d;
   size_t i;
   enum insn_code icode;
   tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
@@ -10104,12 +11940,12 @@ ix86_expand_builtin (exp, target, subtarget, mode, ignore)
       op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
       op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
       tmode = insn_data[icode].operand[0].mode;
-      mode0 = insn_data[icode].operand[2].mode;
-      mode1 = insn_data[icode].operand[3].mode;
+      mode1 = insn_data[icode].operand[1].mode;
+      mode2 = insn_data[icode].operand[2].mode;
 
-      if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
-       op0 = copy_to_mode_reg (mode0, op0);
-      if (! (*insn_data[icode].operand[3].predicate) (op1, mode1))
+      if (! (*insn_data[icode].operand[1].predicate) (op0, mode1))
+       op0 = copy_to_mode_reg (mode1, op0);
+      if (! (*insn_data[icode].operand[2].predicate) (op1, mode2))
        {
          /* @@@ better error message */
          error ("mask must be an immediate");
@@ -10119,38 +11955,137 @@ ix86_expand_builtin (exp, target, subtarget, mode, ignore)
          || GET_MODE (target) != tmode
          || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
        target = gen_reg_rtx (tmode);
-      pat = GEN_FCN (icode) (target, target, op0, op1);
+      pat = GEN_FCN (icode) (target, op0, op1);
       if (! pat)
        return 0;
       emit_insn (pat);
       return target;
 
+    case IX86_BUILTIN_FEMMS:
+      emit_insn (gen_femms ());
+      return NULL_RTX;
+
+    case IX86_BUILTIN_PAVGUSB:
+      return ix86_expand_binop_builtin (CODE_FOR_pavgusb, arglist, target);
+
+    case IX86_BUILTIN_PF2ID:
+      return ix86_expand_unop_builtin (CODE_FOR_pf2id, arglist, target, 0);
+
+    case IX86_BUILTIN_PFACC:
+      return ix86_expand_binop_builtin (CODE_FOR_pfacc, arglist, target);
+
+    case IX86_BUILTIN_PFADD:
+     return ix86_expand_binop_builtin (CODE_FOR_addv2sf3, arglist, target);
+
+    case IX86_BUILTIN_PFCMPEQ:
+      return ix86_expand_binop_builtin (CODE_FOR_eqv2sf3, arglist, target);
+
+    case IX86_BUILTIN_PFCMPGE:
+      return ix86_expand_binop_builtin (CODE_FOR_gev2sf3, arglist, target);
+
+    case IX86_BUILTIN_PFCMPGT:
+      return ix86_expand_binop_builtin (CODE_FOR_gtv2sf3, arglist, target);
+
+    case IX86_BUILTIN_PFMAX:
+      return ix86_expand_binop_builtin (CODE_FOR_pfmaxv2sf3, arglist, target);
+
+    case IX86_BUILTIN_PFMIN:
+      return ix86_expand_binop_builtin (CODE_FOR_pfminv2sf3, arglist, target);
+
+    case IX86_BUILTIN_PFMUL:
+      return ix86_expand_binop_builtin (CODE_FOR_mulv2sf3, arglist, target);
+
+    case IX86_BUILTIN_PFRCP:
+      return ix86_expand_unop_builtin (CODE_FOR_pfrcpv2sf2, arglist, target, 0);
+
+    case IX86_BUILTIN_PFRCPIT1:
+      return ix86_expand_binop_builtin (CODE_FOR_pfrcpit1v2sf3, arglist, target);
+
+    case IX86_BUILTIN_PFRCPIT2:
+      return ix86_expand_binop_builtin (CODE_FOR_pfrcpit2v2sf3, arglist, target);
+
+    case IX86_BUILTIN_PFRSQIT1:
+      return ix86_expand_binop_builtin (CODE_FOR_pfrsqit1v2sf3, arglist, target);
+
+    case IX86_BUILTIN_PFRSQRT:
+      return ix86_expand_unop_builtin (CODE_FOR_pfrsqrtv2sf2, arglist, target, 0);
+
+    case IX86_BUILTIN_PFSUB:
+      return ix86_expand_binop_builtin (CODE_FOR_subv2sf3, arglist, target);
+
+    case IX86_BUILTIN_PFSUBR:
+      return ix86_expand_binop_builtin (CODE_FOR_subrv2sf3, arglist, target);
+
+    case IX86_BUILTIN_PI2FD:
+      return ix86_expand_unop_builtin (CODE_FOR_floatv2si2, arglist, target, 0);
+
+    case IX86_BUILTIN_PMULHRW:
+      return ix86_expand_binop_builtin (CODE_FOR_pmulhrwv4hi3, arglist, target);
+
+    case IX86_BUILTIN_PREFETCH_3DNOW:
+      icode = CODE_FOR_prefetch_3dnow;
+      arg0 = TREE_VALUE (arglist);
+      op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
+      mode0 = insn_data[icode].operand[0].mode;
+      pat = GEN_FCN (icode) (copy_to_mode_reg (Pmode, op0));
+      if (! pat)
+        return NULL_RTX;
+      emit_insn (pat);
+      return NULL_RTX;
+
+    case IX86_BUILTIN_PREFETCHW:
+      icode = CODE_FOR_prefetchw;
+      arg0 = TREE_VALUE (arglist);
+      op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
+      mode0 = insn_data[icode].operand[0].mode;
+      pat = GEN_FCN (icode) (copy_to_mode_reg (Pmode, op0));
+      if (! pat)
+        return NULL_RTX;
+      emit_insn (pat);
+      return NULL_RTX;
+
+    case IX86_BUILTIN_PF2IW:
+      return ix86_expand_unop_builtin (CODE_FOR_pf2iw, arglist, target, 0);
+
+    case IX86_BUILTIN_PFNACC:
+      return ix86_expand_binop_builtin (CODE_FOR_pfnacc, arglist, target);
+
+    case IX86_BUILTIN_PFPNACC:
+      return ix86_expand_binop_builtin (CODE_FOR_pfpnacc, arglist, target);
+
+    case IX86_BUILTIN_PI2FW:
+      return ix86_expand_unop_builtin (CODE_FOR_pi2fw, arglist, target, 0);
+
+    case IX86_BUILTIN_PSWAPDSI:
+      return ix86_expand_unop_builtin (CODE_FOR_pswapdv2si2, arglist, target, 0);
+
+    case IX86_BUILTIN_PSWAPDSF:
+      return ix86_expand_unop_builtin (CODE_FOR_pswapdv2sf2, arglist, target, 0);
+
       /* Composite intrinsics.  */
     case IX86_BUILTIN_SETPS1:
       target = assign_386_stack_local (SFmode, 0);
       arg0 = TREE_VALUE (arglist);
-      emit_move_insn (change_address (target, SFmode, XEXP (target, 0)),
+      emit_move_insn (adjust_address (target, SFmode, 0),
                      expand_expr (arg0, NULL_RTX, VOIDmode, 0));
       op0 = gen_reg_rtx (V4SFmode);
-      emit_insn (gen_sse_loadss (op0, change_address (target, V4SFmode,
-                                                     XEXP (target, 0))));
+      emit_insn (gen_sse_loadss (op0, adjust_address (target, V4SFmode, 0)));
       emit_insn (gen_sse_shufps (op0, op0, op0, GEN_INT (0)));
       return op0;
 
     case IX86_BUILTIN_SETPS:
       target = assign_386_stack_local (V4SFmode, 0);
-      op0 = change_address (target, SFmode, XEXP (target, 0));
       arg0 = TREE_VALUE (arglist);
       arg1 = TREE_VALUE (TREE_CHAIN (arglist));
       arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
       arg3 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (arglist))));
-      emit_move_insn (op0,
+      emit_move_insn (adjust_address (target, SFmode, 0),
                      expand_expr (arg0, NULL_RTX, VOIDmode, 0));
-      emit_move_insn (adj_offsettable_operand (op0, 4),
+      emit_move_insn (adjust_address (target, SFmode, 4),
                      expand_expr (arg1, NULL_RTX, VOIDmode, 0));
-      emit_move_insn (adj_offsettable_operand (op0, 8),
+      emit_move_insn (adjust_address (target, SFmode, 8),
                      expand_expr (arg2, NULL_RTX, VOIDmode, 0));
-      emit_move_insn (adj_offsettable_operand (op0, 12),
+      emit_move_insn (adjust_address (target, SFmode, 12),
                      expand_expr (arg3, NULL_RTX, VOIDmode, 0));
       op0 = gen_reg_rtx (V4SFmode);
       emit_insn (gen_sse_movaps (op0, target));
@@ -10213,7 +12148,7 @@ ix86_expand_builtin (exp, target, subtarget, mode, ignore)
 }
 
 /* Store OPERAND to the memory after reload is completed.  This means
-   that we can't easilly use assign_stack_local.  */
+   that we can't easily use assign_stack_local.  */
 rtx
 ix86_force_to_memory (mode, operand)
      enum machine_mode mode;
@@ -10320,7 +12255,7 @@ ix86_free_from_memory (mode)
 /* 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
-   movdf to do mem-to-mem moves through integer regs. */
+   movdf to do mem-to-mem moves through integer regs.  */
 enum reg_class
 ix86_preferred_reload_class (x, class)
      rtx x;
@@ -10390,7 +12325,7 @@ ix86_secondary_memory_needed (class1, class2, mode, strict)
              && (mode) != SImode));
 }
 /* Return the cost of moving data from a register in class CLASS1 to
-   one in class CLASS2. 
+   one in class CLASS2.
 
    It is not required that the cost always equal 2 when FROM is the same as TO;
    on some machines it is expensive to move between registers if they are not
@@ -10443,7 +12378,7 @@ ix86_hard_regno_mode_ok (regno, mode)
   if (SSE_REGNO_P (regno))
     return VALID_SSE_REG_MODE (mode);
   if (MMX_REGNO_P (regno))
-    return VALID_MMX_REG_MODE (mode);
+    return VALID_MMX_REG_MODE (mode) || VALID_MMX_REG_MODE_3DNOW (mode);
   /* We handle both integer and floats in the general purpose registers.
      In future we should be able to handle vector modes as well.  */
   if (!VALID_INT_MODE_P (mode) && !VALID_FP_MODE_P (mode))
@@ -10461,8 +12396,8 @@ ix86_hard_regno_mode_ok (regno, mode)
 
    If moving between registers and memory is more expensive than
    between two registers, you should define this macro to express the
-   relative cost.  
+   relative cost.
+
    Model also increased moving costs of QImode registers in non
    Q_REGS classes.
  */
@@ -10547,3 +12482,16 @@ ix86_memory_move_cost (mode, class, in)
                * (int) GET_MODE_SIZE (mode) / 4);
     }
 }
+
+#ifdef DO_GLOBAL_CTORS_BODY
+static void
+ix86_svr3_asm_out_constructor (symbol, priority)
+     rtx symbol;
+     int priority ATTRIBUTE_UNUSED;
+{
+  init_section ();
+  fputs ("\tpushl $", asm_out_file);
+  assemble_name (asm_out_file, XSTR (symbol, 0));
+  fputc ('\n', asm_out_file);
+}
+#endif