revised x86_64-pc-mingw32 patch

Richard Henderson rth@redhat.com
Thu Mar 22 00:33:00 GMT 2007


Try the following patch.  It fixes up the calling abi problems,
and gives a stab at fixing the flag_pic sorts of problems.

I do have one question: can I assume that given

  extern int i;
  int f(void) { return i; }

that "i" *cannot* be resolved from a dllimport?  If not,
what does VC++ do with the generated code?


r~
-------------- next part --------------
--- gcc/c-pragma.c	(revision 123123)
+++ gcc/c-pragma.c	(local)
@@ -53,6 +53,20 @@ typedef struct align_stack GTY(())
 
 static GTY(()) struct align_stack * alignment_stack;
 
+#ifdef HANDLE_PRAGMA_PUSH_POP_MACRO
+static void handle_pragma_push_macro (cpp_reader *);
+static void handle_pragma_pop_macro (cpp_reader *);
+#endif
+
+typedef struct sPragmaMacro GTY(())
+{
+	char *name;
+	char *value;
+	struct sPragmaMacro *prev;
+} sPragmaMacro;
+static GTY(()) struct sPragmaMacro *theMacroList = NULL;
+
+
 #ifdef HANDLE_PRAGMA_PACK
 static void handle_pragma_pack (cpp_reader *);
 
@@ -132,6 +146,133 @@ pop_alignment (tree id)
     GCC_BAD ("#pragma pack(pop[, id], <n>) is not supported on this target")
 #endif /* HANDLE_PRAGMA_PACK_PUSH_POP */
 
+#ifdef HANDLE_PRAGMA_PUSH_POP_MACRO
+
+/*
+  #pragma push_macro("MACRO_NAME")
+  #pragma pop_macro("MACRO_NAME")
+*/
+static void
+handle_pragma_push_macro (cpp_reader *ARG_UNUSED (dummy))
+{
+  tree x, id = 0;
+  enum cpp_ttype token;
+
+  if (pragma_lex (&x) != CPP_OPEN_PAREN)
+    GCC_BAD ("missing %<(%> after %<#pragma push_macro%> - ignored");
+  token = pragma_lex (&id);
+  if (token == CPP_CLOSE_PAREN)
+    {
+	  /* Silently ignore */
+	  id = 0;
+    }
+  else if (token != CPP_STRING)
+    {
+	  GCC_BAD ("invalid constant in %<#pragma push_macro%> - ignored");
+    }
+  else
+    {
+	  id = (TREE_STRING_LENGTH (id) > 1 ? id : NULL);
+	  token = pragma_lex (&x);
+	  if (token != CPP_CLOSE_PAREN)
+	    {
+		  GCC_BAD ("missing %<)%> after %<#pragma push_macro%> - ignored");
+	    }
+	  else if (pragma_lex (&x) != CPP_EOF)
+	    {
+		  warning (OPT_Wpragmas, "junk at end of %<#pragma push_macro%>");
+		  while(pragma_lex (&x) != CPP_EOF)
+		    ;
+	    }
+  }
+  if (id)
+    {
+	  sPragmaMacro *c;
+	  const char *macroname = TREE_STRING_POINTER (id);
+
+	  if (cpp_defined (dummy,(const unsigned char *) macroname, strlen (macroname)))
+	    {
+		  const char *val;
+
+		  val = cpp_macro_definition (dummy, cpp_lookup (dummy, (const unsigned char *)macroname, strlen (macroname)));
+		  c = (sPragmaMacro *) ggc_alloc (sizeof(sPragmaMacro) + strlen (macroname) + strlen (val) + 4);
+		  c->name = (char *)&c[1];
+		  c->value = &c->name[strlen (macroname) + 1];
+		  strcpy (c->name, macroname);
+		  strcpy (&c->value[0], val);
+		  if (c->value[strlen (c->value) - 1] == '\n')
+		  c->value[strlen (c->value) - 1] = 0;
+		  c->prev = theMacroList;
+		  theMacroList = c;
+	    }
+	  else
+	    {
+		  c = (sPragmaMacro *) ggc_alloc (sizeof(sPragmaMacro) + strlen (macroname) + 4);
+		  c->name = (char*)&c[1];
+		  c->value = NULL;
+		  strcpy (c->name, macroname);
+		  c->prev = theMacroList;
+		  theMacroList = c;
+	    }
+    }
+}
+
+static void handle_pragma_pop_macro(cpp_reader *ARG_UNUSED (dummy))
+{
+  tree x, id = 0;
+  enum cpp_ttype token;
+
+  if (pragma_lex (&x) != CPP_OPEN_PAREN)
+    GCC_BAD ("missing %<(%> after %<#pragma pop_macro%> - ignored");
+  token = pragma_lex (&id);
+  if (token == CPP_CLOSE_PAREN)
+    {
+	  /* Silently ignore */
+    }
+  else if(token != CPP_STRING)
+    {
+	  GCC_BAD ("invalid constant in %<#pragma pop_macro%> - ignored");
+    }
+  else
+    {
+	  id = (TREE_STRING_LENGTH (id) > 1 ? id : NULL);
+	  token = pragma_lex (&x);
+	  if (token != CPP_CLOSE_PAREN)
+	    {
+		  GCC_BAD ("missing %<)%> after %<#pragma pop_macro%> - ignored");
+	    }
+	  else if (pragma_lex (&x) != CPP_EOF)
+		  warning (OPT_Wpragmas, "junk at end of %<#pragma pop_macro%>");
+  }
+  if(id)
+    {
+	  sPragmaMacro *p = NULL, *c = theMacroList;
+	  const char *macroname = TREE_STRING_POINTER (id);
+
+	  while(c != NULL)
+	    {
+		  if(!strcmp (macroname, c->name))
+		    {
+			  char s[4096];
+			  sprintf (s, "\n\n#undef %s\n", c->name);
+			  if (c->value)
+			    {
+				  sprintf (s + strlen (s), "#define %s\n", c->value);
+				  cpp_push_buffer (dummy,s, strlen (s), true);
+				}
+			  else
+			  	  cpp_push_buffer(dummy, s, strlen(s), true);
+			  if(!p) theMacroList = c->prev;
+			  else p->prev = c->prev;
+			  break;
+			}
+		  c = (p = c)->prev;
+		}
+	}
+}
+
+#endif /* HANDLE_PRAGMA_PUSH_POP_MACRO */
+
 /* #pragma pack ()
    #pragma pack (N)
 
@@ -819,6 +960,10 @@ init_pragma (void)
   c_register_pragma (0, "pack", handle_pragma_pack);
 #endif
 #endif
+#ifdef HANDLE_PRAGMA_PUSH_POP_MACRO
+  c_register_pragma (0 ,"push_macro", handle_pragma_push_macro);
+  c_register_pragma (0 ,"pop_macro", handle_pragma_pop_macro);
+#endif
 #ifdef HANDLE_PRAGMA_WEAK
   c_register_pragma (0, "weak", handle_pragma_weak);
 #endif
--- gcc/calls.c	(revision 123123)
+++ gcc/calls.c	(local)
@@ -42,6 +42,11 @@ Software Foundation, 51 Franklin Street,
 #include "cgraph.h"
 #include "except.h"
 
+#ifndef OUTGOING_REG_PARM_STACK_SPACE
+#define OUTGOING_REG_PARM_STACK_SPACE 0
+#endif
+
+
 /* Like PREFERRED_STACK_BOUNDARY but in units of bytes, not bits.  */
 #define STACK_BYTES (PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT)
 
@@ -1222,13 +1227,12 @@ compute_argument_block_size (int reg_par
 	    = size_binop (MAX_EXPR, args_size->var,
 			  ssize_int (reg_parm_stack_space));
 
-#ifndef OUTGOING_REG_PARM_STACK_SPACE
 	  /* The area corresponding to register parameters is not to count in
 	     the size of the block we need.  So make the adjustment.  */
+	  if (!OUTGOING_REG_PARM_STACK_SPACE)
 	  args_size->var
 	    = size_binop (MINUS_EXPR, args_size->var,
 			  ssize_int (reg_parm_stack_space));
-#endif
 	}
     }
   else
@@ -1246,9 +1250,8 @@ compute_argument_block_size (int reg_par
       args_size->constant = MAX (args_size->constant,
 				 reg_parm_stack_space);
 
-#ifndef OUTGOING_REG_PARM_STACK_SPACE
+      if (!OUTGOING_REG_PARM_STACK_SPACE)
       args_size->constant -= reg_parm_stack_space;
-#endif
     }
   return unadjusted_args_size;
 }
@@ -2026,10 +2029,8 @@ expand_call (tree exp, rtx target, int i
   reg_parm_stack_space = REG_PARM_STACK_SPACE (fndecl);
 #endif
 
-#ifndef OUTGOING_REG_PARM_STACK_SPACE
-  if (reg_parm_stack_space > 0 && PUSH_ARGS)
+  if (!OUTGOING_REG_PARM_STACK_SPACE && reg_parm_stack_space > 0 && PUSH_ARGS)
     must_preallocate = 1;
-#endif
 
   /* Set up a place to return a structure.  */
 
@@ -2430,12 +2431,11 @@ expand_call (tree exp, rtx target, int i
 		     Another approach might be to try to reorder the argument
 		     evaluations to avoid this conflicting stack usage.  */
 
-#ifndef OUTGOING_REG_PARM_STACK_SPACE
 		  /* Since we will be writing into the entire argument area,
 		     the map must be allocated for its entire size, not just
 		     the part that is the responsibility of the caller.  */
+		  if (!OUTGOING_REG_PARM_STACK_SPACE)
 		  needed += reg_parm_stack_space;
-#endif
 
 #ifdef ARGS_GROW_DOWNWARD
 		  highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use,
@@ -2531,12 +2531,8 @@ expand_call (tree exp, rtx target, int i
 	     an argument.  */
 	  if (stack_arg_under_construction)
 	    {
-#ifndef OUTGOING_REG_PARM_STACK_SPACE
-	      rtx push_size = GEN_INT (reg_parm_stack_space
-				       + adjusted_args_size.constant);
-#else
-	      rtx push_size = GEN_INT (adjusted_args_size.constant);
-#endif
+	      rtx push_size = (!OUTGOING_REG_PARM_STACK_SPACE ? (GEN_INT (reg_parm_stack_space
+				       + adjusted_args_size.constant)) : (GEN_INT (adjusted_args_size.constant)));
 	      if (old_stack_level == 0)
 		{
 		  emit_stack_save (SAVE_BLOCK, &old_stack_level,
@@ -2706,11 +2702,9 @@ expand_call (tree exp, rtx target, int i
       /* If register arguments require space on the stack and stack space
 	 was not preallocated, allocate stack space here for arguments
 	 passed in registers.  */
-#ifdef OUTGOING_REG_PARM_STACK_SPACE
-      if (!ACCUMULATE_OUTGOING_ARGS
+      if (OUTGOING_REG_PARM_STACK_SPACE && !ACCUMULATE_OUTGOING_ARGS
 	  && must_preallocate == 0 && reg_parm_stack_space > 0)
 	anti_adjust_stack (GEN_INT (reg_parm_stack_space));
-#endif
 
       /* Pass the function the address in which to return a
 	 structure value.  */
@@ -3532,9 +3526,8 @@ emit_library_call_value_1 (int retval, r
   args_size.constant = MAX (args_size.constant,
 			    reg_parm_stack_space);
 
-#ifndef OUTGOING_REG_PARM_STACK_SPACE
+  if (!OUTGOING_REG_PARM_STACK_SPACE)
   args_size.constant -= reg_parm_stack_space;
-#endif
 
   if (args_size.constant > current_function_outgoing_args_size)
     current_function_outgoing_args_size = args_size.constant;
@@ -3555,12 +3548,11 @@ emit_library_call_value_1 (int retval, r
 
       needed = args_size.constant;
 
-#ifndef OUTGOING_REG_PARM_STACK_SPACE
       /* Since we will be writing into the entire argument area, the
 	 map must be allocated for its entire size, not just the part that
 	 is the responsibility of the caller.  */
+	  if (!OUTGOING_REG_PARM_STACK_SPACE)
       needed += reg_parm_stack_space;
-#endif
 
 #ifdef ARGS_GROW_DOWNWARD
       highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use,
--- gcc/config/i386/cygming.h	(revision 123123)
+++ gcc/config/i386/cygming.h	(local)
@@ -21,18 +21,35 @@ along with GCC; see the file COPYING.  I
 the Free Software Foundation, 51 Franklin Street, Fifth Floor,
 Boston, MA 02110-1301, USA.  */
 
+#if TARGET_64BIT_DEFAULT
+#ifndef DWARF2_DEBUGGING_INFO
+#define DWARF2_DEBUGGING_INFO 1
+#endif
+#ifndef DWARF2_UNWIND_INFO
+#define DWARF2_UNWIND_INFO 1
+#endif
+#endif
+
 #define DBX_DEBUGGING_INFO 1
 #define SDB_DEBUGGING_INFO 1
 #undef PREFERRED_DEBUGGING_TYPE
+#if TARGET_64BIT_DEFAULT
+#define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG
+#else
 #define PREFERRED_DEBUGGING_TYPE DBX_DEBUG
+#endif
+
+#undef TARGET_64BIT_MS_ABI
+#define TARGET_64BIT_MS_ABI TARGET_64BIT
 
 #ifdef HAVE_GAS_PE_SECREL32_RELOC
 #define DWARF2_DEBUGGING_INFO 1
 
 #undef DBX_REGISTER_NUMBER
-#define DBX_REGISTER_NUMBER(n) (write_symbols == DWARF2_DEBUG   \
-                                ? svr4_dbx_register_map[n]      \
-                                : dbx_register_map[n])
+#define DBX_REGISTER_NUMBER(n)				\
+  (TARGET_64BIT ? dbx64_register_map[n]			\
+   : (write_symbols == DWARF2_DEBUG			\
+      ? svr4_dbx_register_map[n] : dbx_register_map[n]))
 
 /* Use section relative relocations for debugging offsets.  Unlike
    other targets that fake this by putting the section VMA at 0, PE
@@ -97,14 +114,28 @@ Boston, MA 02110-1301, USA.  */
 #undef MATH_LIBRARY
 #define MATH_LIBRARY ""
 
-#define SIZE_TYPE "unsigned int"
-#define PTRDIFF_TYPE "int"
+#define SIZE_TYPE (TARGET_64BIT ? "long long unsigned int" : "unsigned int")
+#define PTRDIFF_TYPE (TARGET_64BIT ? "long long int" : "int")
 #define WCHAR_TYPE_SIZE 16
 #define WCHAR_TYPE "short unsigned int"
 
 
+#undef REG_PARM_STACK_SPACE
+#define REG_PARM_STACK_SPACE(FNDECL) (TARGET_64BIT_MS_ABI ? 32 : 0)
+
+#undef OUTGOING_REG_PARM_STACK_SPACE
+#define OUTGOING_REG_PARM_STACK_SPACE (TARGET_64BIT_MS_ABI ? 1 : 0)
+
+#undef REGPARM_MAX
+#define REGPARM_MAX (TARGET_64BIT_MS_ABI ? 4 : 3)
+
+#undef SSE_REGPARM_MAX
+#define SSE_REGPARM_MAX (TARGET_64BIT_MS_ABI ? 4 : TARGET_SSE ? 3 : 0)
+
 /* Enable parsing of #pragma pack(push,<n>) and #pragma pack(pop).  */
 #define HANDLE_PRAGMA_PACK_PUSH_POP 1
+/* Enable push_macro & pop_macro */
+#define HANDLE_PRAGMA_PUSH_POP_MACRO 1
 
 union tree_node;
 #define TREE union tree_node *
@@ -185,19 +216,26 @@ do {							\
 } while (0)
 
 
-/* Emit code to check the stack when allocating more that 4000
+/* Emit code to check the stack when allocating more than 4000
    bytes in one go.  */
-
 #define CHECK_STACK_LIMIT 4000
 
+#undef STACK_BOUNDARY
+#define STACK_BOUNDARY	(TARGET_64BIT_MS_ABI ? 128 : BITS_PER_WORD)
+
 /* By default, target has a 80387, uses IEEE compatible arithmetic,
    returns float values in the 387 and needs stack probes.
    We also align doubles to 64-bits for MSVC default compatibility.  */
 
 #undef TARGET_SUBTARGET_DEFAULT
+#if TARGET_64BIT_DEFAULT
+#define TARGET_SUBTARGET_DEFAULT \
+	(MASK_80387 | MASK_IEEE_FP | MASK_FLOAT_RETURNS)
+#else
 #define TARGET_SUBTARGET_DEFAULT \
-   (MASK_80387 | MASK_IEEE_FP | MASK_FLOAT_RETURNS | MASK_STACK_PROBE \
-    | MASK_ALIGN_DOUBLE)
+	(MASK_80387 | MASK_IEEE_FP | MASK_FLOAT_RETURNS \
+	 | MASK_STACK_PROBE | MASK_ALIGN_DOUBLE)
+#endif
 
 /* This is how to output an assembler line
    that says to advance the location counter
@@ -266,7 +304,9 @@ extern void i386_pe_unique_section (TREE
 /* DWARF2 Unwinding doesn't work with exception handling yet.  To make
    it work, we need to build a libgcc_s.dll, and dcrt0.o should be
    changed to call __register_frame_info/__deregister_frame_info.  */
+#ifndef DWARF2_UNWIND_INFO
 #define DWARF2_UNWIND_INFO 0
+#endif
 
 /* Don't assume anything about the header files.  */
 #define NO_IMPLICIT_EXTERN_C
@@ -375,8 +415,8 @@ extern int i386_pe_dllimport_name_p (con
 #define TARGET_USE_LOCAL_THUNK_ALIAS_P(DECL) (!DECL_ONE_ONLY (DECL))
 
 #define SUBTARGET_ATTRIBUTE_TABLE \
-  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ \
   { "selectany", 0, 0, true, false, false, ix86_handle_selectany_attribute }
+  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
 
 /*  mcount() does not need a counter variable.  */
 #undef NO_PROFILE_COUNTERS
--- gcc/config/i386/cygwin.asm	(revision 123123)
+++ gcc/config/i386/cygwin.asm	(local)
@@ -44,6 +44,7 @@
 	.global	__alloca
 ___chkstk:
 __alloca:
+#ifndef _WIN64
 	pushl  %ecx		/* save temp */
 	movl   %esp,%ecx	/* get sp */
 	addl   $0x8,%ecx	/* and point to return addr */
@@ -65,4 +66,27 @@ done: 	subl   %eax,%ecx	   
 	movl   (%eax),%ecx	/* recover saved temp */
 	movl   4(%eax),%eax	/* get return address */
 	jmp    *%eax	
+#else
+	pushq  %rdx		/* save temp */
+	movq   %rsp,%rdx	/* get sp */
+	addq   $0x10,%rdx	/* and point to return addr */
+
+probe: 	cmpq   $0x1000,%rcx	/* > 4k ?*/
+	jb    done		
+
+	subq   $0x1000,%rdx  		/* yes, move pointer down 4k*/
+	orq    $0x0,(%rdx)   		/* probe there */
+	subq   $0x1000,%rcx  	 	/* decrement count */
+	jmp    probe           	 	/* and do it again */
+
+done: 	subq   %rcx,%rdx	   
+	orq    $0x0,(%rdx)	/* less that 4k, just peek here */
+
+	movq   %rsp,%rax
+	movq   %rdx,%rsp	/* decrement stack */
+
+	movq   (%rax),%rdx	/* recover saved temp */
+	movq   8(%rax),%rax	/* get return address */
+	jmp    *%rax	
+#endif
 #endif
--- gcc/config/i386/i386-protos.h	(revision 123123)
+++ gcc/config/i386/i386-protos.h	(local)
@@ -179,7 +179,6 @@ extern void init_cumulative_args (CUMULA
 extern rtx function_arg (CUMULATIVE_ARGS *, enum machine_mode, tree, int);
 extern void function_arg_advance (CUMULATIVE_ARGS *, enum machine_mode,
 				  tree, int);
-extern rtx ix86_function_value (tree, tree, bool);
 #endif
 
 #endif
@@ -252,3 +251,4 @@ extern enum rtx_code ix86_fp_compare_cod
 extern rtx construct_plt_address (rtx);
 #endif
 extern int asm_preferred_eh_data_format (int, int);
+extern HOST_WIDE_INT ix86_GOT_alias_set (void);
--- gcc/config/i386/i386.c	(revision 123123)
+++ gcc/config/i386/i386.c	(local)
@@ -1304,9 +1304,15 @@ static int const x86_64_int_parameter_re
   FIRST_REX_INT_REG /*R8 */, FIRST_REX_INT_REG + 1 /*R9 */
 };
 
+static int const x86_64_ms_abi_int_parameter_registers[4] =
+{
+  2 /*RCX*/, 1 /*RDX*/,
+  FIRST_REX_INT_REG /*R8 */, FIRST_REX_INT_REG + 1 /*R9 */
+};
+
 static int const x86_64_int_return_registers[4] =
 {
-  0 /*RAX*/, 1 /*RDI*/, 5 /*RDI*/, 4 /*RSI*/
+  0 /*RAX*/, 1 /*RDX*/, 5 /*RDI*/, 4 /*RSI*/
 };
 
 /* The "default" register map used in 64bit mode.  */
@@ -1512,7 +1518,6 @@ static void ix86_emit_save_regs (void);
 static void ix86_emit_save_regs_using_mov (rtx, HOST_WIDE_INT);
 static void ix86_emit_restore_regs_using_mov (rtx, HOST_WIDE_INT, int);
 static void ix86_output_function_epilogue (FILE *, HOST_WIDE_INT);
-static HOST_WIDE_INT ix86_GOT_alias_set (void);
 static void ix86_adjust_counter (rtx, HOST_WIDE_INT);
 static void ix86_expand_strlensi_unroll_1 (rtx, rtx, rtx);
 static int ix86_issue_rate (void);
@@ -1562,7 +1567,6 @@ static int ix86_function_regparm (tree, 
 const struct attribute_spec ix86_attribute_table[];
 static bool ix86_function_ok_for_sibcall (tree, tree);
 static tree ix86_handle_cconv_attribute (tree *, tree, tree, int, bool *);
-static int ix86_value_regno (enum machine_mode, tree, tree);
 static bool contains_128bit_aligned_vector_p (tree);
 static rtx ix86_struct_value_rtx (tree, int);
 static bool ix86_ms_bitfield_layout_p (tree);
@@ -1584,6 +1588,7 @@ static rtx ix86_internal_arg_pointer (vo
 static void ix86_dwarf_handle_frame_unspec (const char *, rtx, int);
 static bool ix86_expand_vector_init_one_nonzero (bool, enum machine_mode,
 						 rtx, rtx, int);
+static rtx ix86_function_value (tree, tree, bool);
 
 /* This function is only used on Solaris.  */
 static void i386_solaris_elf_named_section (const char *, unsigned int, tree)
@@ -2115,9 +2120,15 @@ override_options (void)
     }
   else
     {
-      ix86_cmodel = CM_32;
-      if (TARGET_64BIT)
+      if (TARGET_64BIT_MS_ABI)
+	{
+	  ix86_cmodel = CM_SMALL_PIC;
+	  flag_pic = 1;
+	}
+      else if (TARGET_64BIT)
 	ix86_cmodel = flag_pic ? CM_SMALL_PIC : CM_SMALL;
+      else
+        ix86_cmodel = CM_32;
     }
   if (ix86_asm_string != 0)
     {
@@ -2239,15 +2250,16 @@ override_options (void)
   /* Validate -mregparm= value.  */
   if (ix86_regparm_string)
     {
+      if (TARGET_64BIT)
+	warning (0, "-mregparm is ignored in 64-bit mode");
       i = atoi (ix86_regparm_string);
       if (i < 0 || i > REGPARM_MAX)
 	error ("-mregparm=%d is not between 0 and %d", i, REGPARM_MAX);
       else
 	ix86_regparm = i;
     }
-  else
-   if (TARGET_64BIT)
-     ix86_regparm = REGPARM_MAX;
+  if (TARGET_64BIT)
+    ix86_regparm = REGPARM_MAX;
 
   /* If the user has provided any of the -malign-* options,
      warn and use that value only if -falign-* is not set.
@@ -2900,8 +2912,10 @@ ix86_handle_cconv_attribute (tree *node,
 
   if (TARGET_64BIT)
     {
-      warning (OPT_Wattributes, "%qs attribute ignored",
-	       IDENTIFIER_POINTER (name));
+      /* Do not warn when emulating the MS ABI.  */
+      if (!TARGET_64BIT_MS_ABI)
+	warning (OPT_Wattributes, "%qs attribute ignored",
+	         IDENTIFIER_POINTER (name));
       *no_add_attrs = true;
       return NULL_TREE;
     }
@@ -2997,69 +3011,64 @@ ix86_function_regparm (tree type, tree d
 {
   tree attr;
   int regparm = ix86_regparm;
-  bool user_convention = false;
 
-  if (!TARGET_64BIT)
-    {
-      attr = lookup_attribute ("regparm", TYPE_ATTRIBUTES (type));
-      if (attr)
-	{
-	  regparm = TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (attr)));
-	  user_convention = true;
-	}
+  if (TARGET_64BIT)
+    return regparm;
 
-      if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (type)))
-	{
-	  regparm = 2;
-	  user_convention = true;
-	}
+  attr = lookup_attribute ("regparm", TYPE_ATTRIBUTES (type));
+  if (attr)
+    return TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (attr)));
+
+  if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (type)))
+    return 2;
 
-      /* Use register calling convention for local functions when possible.  */
-      if (!TARGET_64BIT && !user_convention && decl
-	  && flag_unit_at_a_time && !profile_flag)
+  /* Use register calling convention for local functions when possible.  */
+  if (decl && flag_unit_at_a_time && !profile_flag)
+    {
+      struct cgraph_local_info *i = cgraph_local_info (decl);
+      if (i && i->local)
 	{
-	  struct cgraph_local_info *i = cgraph_local_info (decl);
-	  if (i && i->local)
-	    {
-	      int local_regparm, globals = 0, regno;
+	  int local_regparm, globals = 0, regno;
+	  struct function *f;
 
-	      /* Make sure no regparm register is taken by a global register
-		 variable.  */
-	      for (local_regparm = 0; local_regparm < 3; local_regparm++)
-		if (global_regs[local_regparm])
-		  break;
-	      /* We can't use regparm(3) for nested functions as these use
-		 static chain pointer in third argument.  */
-	      if (local_regparm == 3
-		  && decl_function_context (decl)
-		  && !DECL_NO_STATIC_CHAIN (decl))
-		local_regparm = 2;
-	      /* If the function realigns its stackpointer, the
-		 prologue will clobber %ecx.  If we've already
-		 generated code for the callee, the callee
-		 DECL_STRUCT_FUNCTION is gone, so we fall back to
-		 scanning the attributes for the self-realigning
-		 property.  */
-	      if ((DECL_STRUCT_FUNCTION (decl)
-		   && DECL_STRUCT_FUNCTION (decl)->machine->force_align_arg_pointer)
-		  || (!DECL_STRUCT_FUNCTION (decl)
-		      && lookup_attribute (ix86_force_align_arg_pointer_string,
-					   TYPE_ATTRIBUTES (TREE_TYPE (decl)))))
-		local_regparm = 2;
-	      /* Each global register variable increases register preassure,
-		 so the more global reg vars there are, the smaller regparm
-		 optimization use, unless requested by the user explicitly.  */
-	      for (regno = 0; regno < 6; regno++)
-		if (global_regs[regno])
-		  globals++;
-	      local_regparm
-		= globals < local_regparm ? local_regparm - globals : 0;
+	  /* Make sure no regparm register is taken by a
+	     global register variable.  */
+	  for (local_regparm = 0; local_regparm < 3; local_regparm++)
+	    if (global_regs[local_regparm])
+	      break;
 
-	      if (local_regparm > regparm)
-		regparm = local_regparm;
-	    }
+	  /* We can't use regparm(3) for nested functions as these use
+	     static chain pointer in third argument.  */
+	  if (local_regparm == 3
+	      && decl_function_context (decl)
+	      && !DECL_NO_STATIC_CHAIN (decl))
+	    local_regparm = 2;
+
+	  /* If the function realigns its stackpointer, the prologue will
+	     clobber %ecx.  If we've already generated code for the callee,
+	     the callee DECL_STRUCT_FUNCTION is gone, so we fall back to
+	     scanning the attributes for the self-realigning property.  */
+	  f = DECL_STRUCT_FUNCTION (decl);
+	  if (local_regparm == 3
+	      && (f ? !!f->machine->force_align_arg_pointer
+		  : !!lookup_attribute (ix86_force_align_arg_pointer_string,
+					TYPE_ATTRIBUTES (TREE_TYPE (decl)))))
+	    local_regparm = 2;
+
+	  /* Each global register variable increases register preassure,
+	     so the more global reg vars there are, the smaller regparm
+	     optimization use, unless requested by the user explicitly.  */
+	  for (regno = 0; regno < 6; regno++)
+	    if (global_regs[regno])
+	      globals++;
+	  local_regparm
+	    = globals < local_regparm ? local_regparm - globals : 0;
+
+	  if (local_regparm > regparm)
+	    regparm = local_regparm;
 	}
     }
+
   return regparm;
 }
 
@@ -3071,11 +3080,12 @@ ix86_function_regparm (tree type, tree d
 static int
 ix86_function_sseregparm (tree type, tree decl)
 {
+  gcc_assert (!TARGET_64BIT);
+
   /* Use SSE registers to pass SFmode and DFmode arguments if requested
      by the sseregparm attribute.  */
   if (TARGET_SSEREGPARM
-      || (type
-	  && lookup_attribute ("sseregparm", TYPE_ATTRIBUTES (type))))
+      || (type && lookup_attribute ("sseregparm", TYPE_ATTRIBUTES (type))))
     {
       if (!TARGET_SSE)
 	{
@@ -3092,10 +3102,8 @@ ix86_function_sseregparm (tree type, tre
     }
 
   /* For local functions, pass up to SSE_REGPARM_MAX SFmode
-     (and DFmode for SSE2) arguments in SSE registers,
-     even for 32-bit targets.  */
-  if (!TARGET_64BIT && decl
-      && TARGET_SSE_MATH && flag_unit_at_a_time && !profile_flag)
+     (and DFmode for SSE2) arguments in SSE registers.  */
+  if (decl && TARGET_SSE_MATH && flag_unit_at_a_time && !profile_flag)
     {
       struct cgraph_local_info *i = cgraph_local_info (decl);
       if (i && i->local)
@@ -3121,6 +3129,19 @@ ix86_eax_live_at_start_p (void)
   return REGNO_REG_SET_P (ENTRY_BLOCK_PTR->il.rtl->global_live_at_end, 0);
 }
 
+/* Return true if TYPE has a variable argument list.  */
+
+static bool
+type_has_variadic_args_p (tree type)
+{
+  tree t;
+
+  for (t = TYPE_ARG_TYPES (type); t; t = TREE_CHAIN (t))
+    if (t == void_list_node)
+      return false;
+  return true;
+}
+
 /* Value is the number of bytes of arguments automatically
    popped when returning from a subroutine call.
    FUNDECL is the declaration node of the function (as a tree),
@@ -3141,32 +3162,33 @@ ix86_eax_live_at_start_p (void)
 int
 ix86_return_pops_args (tree fundecl, tree funtype, int size)
 {
-  int rtd = TARGET_RTD && (!fundecl || TREE_CODE (fundecl) != IDENTIFIER_NODE);
+  int rtd;
+
+  /* None of the 64-bit ABIs pop arguments.  */
+  if (TARGET_64BIT)
+    return 0;
+
+  rtd = TARGET_RTD && (!fundecl || TREE_CODE (fundecl) != IDENTIFIER_NODE);
 
   /* Cdecl functions override -mrtd, and never pop the stack.  */
-  if (! lookup_attribute ("cdecl", TYPE_ATTRIBUTES (funtype))) {
+  if (! lookup_attribute ("cdecl", TYPE_ATTRIBUTES (funtype)))
+    {
+      /* Stdcall and fastcall functions will pop the stack if not
+         variable args.  */
+      if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (funtype))
+          || lookup_attribute ("fastcall", TYPE_ATTRIBUTES (funtype)))
+	rtd = 1;
 
-    /* Stdcall and fastcall functions will pop the stack if not
-       variable args.  */
-    if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (funtype))
-        || lookup_attribute ("fastcall", TYPE_ATTRIBUTES (funtype)))
-      rtd = 1;
-
-    if (rtd
-        && (TYPE_ARG_TYPES (funtype) == NULL_TREE
-	    || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (funtype)))
-		== void_type_node)))
-      return size;
-  }
+      if (rtd && ! type_has_variadic_args_p (funtype))
+	return size;
+    }
 
   /* Lose any fake structure return argument if it is passed on the stack.  */
   if (aggregate_value_p (TREE_TYPE (funtype), fundecl)
-      && !TARGET_64BIT
       && !KEEP_AGGREGATE_RETURN_POINTER)
     {
       int nregs = ix86_function_regparm (funtype, fundecl);
-
-      if (!nregs)
+      if (nregs == 0)
 	return GET_MODE_SIZE (Pmode);
     }
 
@@ -3180,6 +3202,8 @@ bool
 ix86_function_arg_regno_p (int regno)
 {
   int i;
+  const int *parm_regs;
+
   if (!TARGET_64BIT)
     {
       if (TARGET_MACHO)
@@ -3204,11 +3228,17 @@ ix86_function_arg_regno_p (int regno)
           && (regno < FIRST_SSE_REG + SSE_REGPARM_MAX))
         return true;
     }
+
   /* RAX is used as hidden argument to va_arg functions.  */
-  if (!regno)
+  if (!TARGET_64BIT_MS_ABI && regno == 0)
     return true;
+
+  if (TARGET_64BIT_MS_ABI)
+    parm_regs = x86_64_ms_abi_int_parameter_registers;
+  else
+    parm_regs = x86_64_int_parameter_registers;
   for (i = 0; i < REGPARM_MAX; i++)
-    if (regno == x86_64_int_parameter_registers[i])
+    if (regno == parm_regs[i])
       return true;
   return false;
 }
@@ -3238,24 +3268,7 @@ init_cumulative_args (CUMULATIVE_ARGS *c
 		      rtx libname,	/* SYMBOL_REF of library name or 0 */
 		      tree fndecl)
 {
-  static CUMULATIVE_ARGS zero_cum;
-  tree param, next_param;
-
-  if (TARGET_DEBUG_ARG)
-    {
-      fprintf (stderr, "\ninit_cumulative_args (");
-      if (fntype)
-	fprintf (stderr, "fntype code = %s, ret code = %s",
-		 tree_code_name[(int) TREE_CODE (fntype)],
-		 tree_code_name[(int) TREE_CODE (TREE_TYPE (fntype))]);
-      else
-	fprintf (stderr, "no fntype");
-
-      if (libname)
-	fprintf (stderr, ", libname = %s", XSTR (libname, 0));
-    }
-
-  *cum = zero_cum;
+  memset (cum, 0, sizeof (*cum));
 
   /* Set up the number of registers to use for passing arguments.  */
   cum->nregs = ix86_regparm;
@@ -3265,60 +3278,39 @@ init_cumulative_args (CUMULATIVE_ARGS *c
     cum->mmx_nregs = MMX_REGPARM_MAX;
   cum->warn_sse = true;
   cum->warn_mmx = true;
-  cum->maybe_vaarg = false;
+  cum->maybe_vaarg = (fntype ? type_has_variadic_args_p (fntype) : !libname);
 
-  /* Use ecx and edx registers if function has fastcall attribute,
-     else look for regparm information.  */
-  if (fntype && !TARGET_64BIT)
+  if (!TARGET_64BIT)
     {
-      if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (fntype)))
-	{
-	  cum->nregs = 2;
-	  cum->fastcall = 1;
+      /* If there are variable arguments, then we won't pass anything
+         in registers in 32-bit mode. */
+      if (cum->maybe_vaarg)
+	{
+	  cum->nregs = 0;
+	  cum->sse_nregs = 0;
+	  cum->mmx_nregs = 0;
+	  cum->warn_sse = 0;
+	  cum->warn_mmx = 0;
+	  return;
 	}
-      else
-	cum->nregs = ix86_function_regparm (fntype, fndecl);
-    }
-
-  /* Set up the number of SSE registers used for passing SFmode
-     and DFmode arguments.  Warn for mismatching ABI.  */
-  cum->float_in_sse = ix86_function_sseregparm (fntype, fndecl);
-
-  /* Determine if this function has variable arguments.  This is
-     indicated by the last argument being 'void_type_mode' if there
-     are no variable arguments.  If there are variable arguments, then
-     we won't pass anything in registers in 32-bit mode. */
 
-  if (cum->nregs || cum->mmx_nregs || cum->sse_nregs)
-    {
-      for (param = (fntype) ? TYPE_ARG_TYPES (fntype) : 0;
-	   param != 0; param = next_param)
+      /* Use ecx and edx registers if function has fastcall attribute,
+	 else look for regparm information.  */
+      if (fntype)
 	{
-	  next_param = TREE_CHAIN (param);
-	  if (next_param == 0 && TREE_VALUE (param) != void_type_node)
+	  if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (fntype)))
 	    {
-	      if (!TARGET_64BIT)
-		{
-		  cum->nregs = 0;
-		  cum->sse_nregs = 0;
-		  cum->mmx_nregs = 0;
-		  cum->warn_sse = 0;
-		  cum->warn_mmx = 0;
-		  cum->fastcall = 0;
-		  cum->float_in_sse = 0;
-		}
-	      cum->maybe_vaarg = true;
+	      cum->nregs = 2;
+	      cum->fastcall = 1;
 	    }
+	  else
+	    cum->nregs = ix86_function_regparm (fntype, fndecl);
 	}
-    }
-  if ((!fntype && !libname)
-      || (fntype && !TYPE_ARG_TYPES (fntype)))
-    cum->maybe_vaarg = true;
-
-  if (TARGET_DEBUG_ARG)
-    fprintf (stderr, ", nregs=%d )\n", cum->nregs);
 
-  return;
+      /* Set up the number of SSE registers used for passing SFmode
+	 and DFmode arguments.  Warn for mismatching ABI.  */
+      cum->float_in_sse = ix86_function_sseregparm (fntype, fndecl);
+    }
 }
 
 /* Return the "natural" mode for TYPE.  In most cases, this is just TYPE_MODE.
@@ -3781,20 +3773,6 @@ construct_container (enum machine_mode m
   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,
@@ -3863,6 +3841,7 @@ construct_container (enum machine_mode m
   if (n == 2 && class[0] == X86_64_SSE_CLASS && class[1] == X86_64_SSEUP_CLASS
       && mode != BLKmode)
     return gen_rtx_REG (mode, SSE_REGNO (sse_regno));
+
   if (n == 2
       && class[0] == X86_64_X87_CLASS && class[1] == X86_64_X87UP_CLASS)
     return gen_rtx_REG (XFmode, FIRST_STACK_REG);
@@ -3938,117 +3917,143 @@ construct_container (enum machine_mode m
   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.)  */
+/* 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 (CUMULATIVE_ARGS *cum, enum machine_mode mode,
-		      tree type, int named)
+static void
+function_arg_advance_32 (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+			 tree type, HOST_WIDE_INT bytes, HOST_WIDE_INT words)
 {
-  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 (type)
-    mode = type_natural_mode (type);
-
-  if (TARGET_DEBUG_ARG)
-    fprintf (stderr, "function_adv (sz=%d, wds=%2d, nregs=%d, ssenregs=%d, "
-	     "mode=%s, named=%d)\n\n",
-	     words, cum->words, cum->nregs, cum->sse_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
+  switch (mode)
     {
-      switch (mode)
-	{
-	default:
-	  break;
+    default:
+      break;
 
-	case BLKmode:
-	  if (bytes < 0)
-	    break;
-	  /* FALLTHRU */
+    case BLKmode:
+      if (bytes < 0)
+	break;
+      /* FALLTHRU */
 
-	case DImode:
-	case SImode:
-	case HImode:
-	case QImode:
-	  cum->words += words;
-	  cum->nregs -= words;
-	  cum->regno += words;
+    case DImode:
+    case SImode:
+    case HImode:
+    case QImode:
+      cum->words += words;
+      cum->nregs -= words;
+      cum->regno += words;
 
-	  if (cum->nregs <= 0)
-	    {
-	      cum->nregs = 0;
-	      cum->regno = 0;
-	    }
-	  break;
+      if (cum->nregs <= 0)
+	{
+	  cum->nregs = 0;
+	  cum->regno = 0;
+	}
+      break;
 
-	case DFmode:
-	  if (cum->float_in_sse < 2)
-	    break;
-	case SFmode:
-	  if (cum->float_in_sse < 1)
-	    break;
-	  /* FALLTHRU */
+    case DFmode:
+      if (cum->float_in_sse < 2)
+	break;
+    case SFmode:
+      if (cum->float_in_sse < 1)
+	break;
+      /* FALLTHRU */
 
-	case TImode:
-	case V16QImode:
-	case V8HImode:
-	case V4SImode:
-	case V2DImode:
-	case V4SFmode:
-	case V2DFmode:
-	  if (!type || !AGGREGATE_TYPE_P (type))
+    case TImode:
+    case V16QImode:
+    case V8HImode:
+    case V4SImode:
+    case V2DImode:
+    case V4SFmode:
+    case V2DFmode:
+      if (!type || !AGGREGATE_TYPE_P (type))
+	{
+	  cum->sse_words += words;
+	  cum->sse_nregs -= 1;
+	  cum->sse_regno += 1;
+	  if (cum->sse_nregs <= 0)
 	    {
-	      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;
-		}
+	      cum->sse_nregs = 0;
+	      cum->sse_regno = 0;
 	    }
-	  break;
+	}
+      break;
 
-	case V8QImode:
-	case V4HImode:
-	case V2SImode:
-	case V2SFmode:
-	  if (!type || !AGGREGATE_TYPE_P (type))
+    case V8QImode:
+    case V4HImode:
+    case V2SImode:
+    case V2SFmode:
+      if (!type || !AGGREGATE_TYPE_P (type))
+	{
+	  cum->mmx_words += words;
+	  cum->mmx_nregs -= 1;
+	  cum->mmx_regno += 1;
+	  if (cum->mmx_nregs <= 0)
 	    {
-	      cum->mmx_words += words;
-	      cum->mmx_nregs -= 1;
-	      cum->mmx_regno += 1;
-	      if (cum->mmx_nregs <= 0)
-		{
-		  cum->mmx_nregs = 0;
-		  cum->mmx_regno = 0;
-		}
+	      cum->mmx_nregs = 0;
+	      cum->mmx_regno = 0;
 	    }
-	  break;
 	}
+      break;
     }
 }
 
+static void
+function_arg_advance_64 (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+			 tree type, HOST_WIDE_INT words)
+{
+  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;
+}
+
+static void
+function_arg_advance_ms_64 (CUMULATIVE_ARGS *cum, HOST_WIDE_INT bytes,
+			    HOST_WIDE_INT words)
+{
+  /* Otherwise, this should be passed indirect.  */
+  gcc_assert (bytes == 1 || bytes == 2 || bytes == 4 || bytes == 8);
+
+  cum->words += words;
+  if (cum->nregs > 0)
+    {
+      cum->nregs -= 1;
+      cum->regno += 1;
+    }
+}
+
+void
+function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+		      tree type, int named ATTRIBUTE_UNUSED)
+{
+  HOST_WIDE_INT bytes, words;
+
+  if (mode == BLKmode)
+    bytes = int_size_in_bytes (type);
+  else
+    bytes = GET_MODE_SIZE (mode);
+  words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+
+  if (type)
+    mode = type_natural_mode (type);
+
+  if (TARGET_64BIT_MS_ABI)
+    function_arg_advance_ms_64 (cum, bytes, words);
+  else if (TARGET_64BIT)
+    function_arg_advance_64 (cum, mode, type, words);
+  else
+    function_arg_advance_32 (cum, mode, type, bytes, words);
+}
+
 /* 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.
@@ -4062,135 +4067,180 @@ function_arg_advance (CUMULATIVE_ARGS *c
    NAMED is nonzero if this argument is a named parameter
     (otherwise it is an extra parameter matching an ellipsis).  */
 
-rtx
-function_arg (CUMULATIVE_ARGS *cum, enum machine_mode orig_mode,
-	      tree type, int named)
+static rtx
+function_arg_32 (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+		 enum machine_mode orig_mode, tree type,
+		 HOST_WIDE_INT bytes, HOST_WIDE_INT words)
 {
-  enum machine_mode mode = orig_mode;
-  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;
   static bool warnedsse, warnedmmx;
 
-  /* To simplify the code below, represent vector types with a vector mode
-     even if MMX/SSE are not active.  */
-  if (type && TREE_CODE (type) == VECTOR_TYPE)
-    mode = type_natural_mode (type);
-
-  /* Handle a hidden AL argument containing number of registers for varargs
-     x86-64 functions.  For i386 ABI just return constm1_rtx to avoid
-     any AL settings.  */
+  /* Avoid the AL settings for the Unix64 ABI.  */
   if (mode == VOIDmode)
+    return constm1_rtx;
+
+  switch (mode)
     {
-      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, orig_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:
+    default:
+      break;
+
+    case BLKmode:
+      if (bytes < 0)
 	break;
+      /* FALLTHRU */
+    case DImode:
+    case SImode:
+    case HImode:
+    case QImode:
+      if (words <= cum->nregs)
+	{
+	  int regno = cum->regno;
 
-      case BLKmode:
-	if (bytes < 0)
-	  break;
-	/* FALLTHRU */
-      case DImode:
-      case SImode:
-      case HImode:
-      case QImode:
-	if (words <= cum->nregs)
-	  {
-	    int regno = cum->regno;
+	  /* Fastcall allocates the first two DWORD (SImode) or
+	     smaller arguments to ECX and EDX.  */
+	  if (cum->fastcall)
+	    {
+	      if (mode == BLKmode || mode == DImode)
+	        break;
 
-	    /* Fastcall allocates the first two DWORD (SImode) or
-	       smaller arguments to ECX and EDX.  */
-	    if (cum->fastcall)
-	      {
-	        if (mode == BLKmode || mode == DImode)
-	          break;
+	      /* ECX not EAX is the first allocated register.  */
+	      if (regno == 0)
+		regno = 2;
+	    }
+	  return gen_rtx_REG (mode, regno);
+	}
+      break;
 
-	        /* ECX not EAX is the first allocated register.  */
-	        if (regno == 0)
-		  regno = 2;
-	      }
-	    ret = gen_rtx_REG (mode, regno);
-	  }
-	break;
-      case DFmode:
-	if (cum->float_in_sse < 2)
-	  break;
-      case SFmode:
-	if (cum->float_in_sse < 1)
-	  break;
-	/* FALLTHRU */
-      case TImode:
-      case V16QImode:
-      case V8HImode:
-      case V4SImode:
-      case V2DImode:
-      case V4SFmode:
-      case V2DFmode:
-	if (!type || !AGGREGATE_TYPE_P (type))
-	  {
-	    if (!TARGET_SSE && !warnedsse && cum->warn_sse)
-	      {
-		warnedsse = true;
-		warning (0, "SSE vector argument without SSE enabled "
-			 "changes the ABI");
-	      }
-	    if (cum->sse_nregs)
-	      ret = gen_reg_or_parallel (mode, orig_mode,
-					 cum->sse_regno + FIRST_SSE_REG);
-	  }
+    case DFmode:
+      if (cum->float_in_sse < 2)
 	break;
-      case V8QImode:
-      case V4HImode:
-      case V2SImode:
-      case V2SFmode:
-	if (!type || !AGGREGATE_TYPE_P (type))
-	  {
-	    if (!TARGET_MMX && !warnedmmx && cum->warn_mmx)
-	      {
-		warnedmmx = true;
-		warning (0, "MMX vector argument without MMX enabled "
-			 "changes the ABI");
-	      }
-	    if (cum->mmx_nregs)
-	      ret = gen_reg_or_parallel (mode, orig_mode,
-					 cum->mmx_regno + FIRST_MMX_REG);
-	  }
+    case SFmode:
+      if (cum->float_in_sse < 1)
 	break;
-      }
+      /* FALLTHRU */
+    case TImode:
+    case V16QImode:
+    case V8HImode:
+    case V4SImode:
+    case V2DImode:
+    case V4SFmode:
+    case V2DFmode:
+      if (!type || !AGGREGATE_TYPE_P (type))
+	{
+	  if (!TARGET_SSE && !warnedsse && cum->warn_sse)
+	    {
+	      warnedsse = true;
+	      warning (0, "SSE vector argument without SSE enabled "
+		       "changes the ABI");
+	    }
+	  if (cum->sse_nregs)
+	    return gen_reg_or_parallel (mode, orig_mode,
+				        cum->sse_regno + FIRST_SSE_REG);
+	}
+      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);
+    case V8QImode:
+    case V4HImode:
+    case V2SImode:
+    case V2SFmode:
+      if (!type || !AGGREGATE_TYPE_P (type))
+	{
+	  if (!TARGET_MMX && !warnedmmx && cum->warn_mmx)
+	    {
+	      warnedmmx = true;
+	      warning (0, "MMX vector argument without MMX enabled "
+		       "changes the ABI");
+	    }
+	  if (cum->mmx_nregs)
+	    return gen_reg_or_parallel (mode, orig_mode,
+				        cum->mmx_regno + FIRST_MMX_REG);
+	}
+      break;
+    }
+
+  return NULL_RTX;
+}
+
+static rtx
+function_arg_64 (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+		 enum machine_mode orig_mode, tree type)
+{
+  /* Handle a hidden AL argument containing number of registers
+     for varargs x86-64 functions.  */
+  if (mode == VOIDmode)
+    return GEN_INT (cum->maybe_vaarg
+		    ? (cum->sse_nregs < 0
+		       ? SSE_REGPARM_MAX
+		       : cum->sse_regno)
+		    : -1);
+
+  return construct_container (mode, orig_mode, type, 0, cum->nregs,
+			      cum->sse_nregs,
+			      &x86_64_int_parameter_registers [cum->regno],
+			      cum->sse_regno);
+}
+
+static rtx
+function_arg_ms_64 (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+		    enum machine_mode orig_mode, int named)
+{
+  unsigned int regno;
 
-      if (ret)
-	print_simple_rtl (stderr, ret);
+  /* Avoid the AL settings for the Unix64 ABI.  */
+  if (mode == VOIDmode)
+    return constm1_rtx;
+
+  /* If we've run out of registers, it goes on the stack.  */
+  if (cum->nregs == 0)
+    return NULL_RTX;
+
+  regno = x86_64_ms_abi_int_parameter_registers[cum->regno];
+
+  /* Only floating point modes are passed in anything but integer regs.  */
+  if (mode == SFmode || mode == DFmode)
+    {
+      if (named)
+	regno = cum->regno + FIRST_SSE_REG;
       else
-	fprintf (stderr, ", stack");
+	{
+	  rtx t1, t2;
 
-      fprintf (stderr, " )\n");
+	  /* Unnamed floating parameters are passed in both the
+	     SSE and integer registers.  */
+	  t1 = gen_rtx_REG (mode, cum->regno + FIRST_SSE_REG);
+	  t2 = gen_rtx_REG (mode, regno);
+	  t1 = gen_rtx_EXPR_LIST (VOIDmode, t1, const0_rtx);
+	  t2 = gen_rtx_EXPR_LIST (VOIDmode, t2, const0_rtx);
+	  return gen_rtx_PARALLEL (mode, gen_rtvec (2, t1, t2));
+	}
     }
 
-  return ret;
+  return gen_reg_or_parallel (mode, orig_mode, regno);
+}
+
+rtx
+function_arg (CUMULATIVE_ARGS *cum, enum machine_mode omode,
+	      tree type, int named)
+{
+  enum machine_mode mode = omode;
+  HOST_WIDE_INT bytes, words;
+
+  if (mode == BLKmode)
+    bytes = int_size_in_bytes (type);
+  else
+    bytes = GET_MODE_SIZE (mode);
+  words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+
+  /* To simplify the code below, represent vector types with a vector mode
+     even if MMX/SSE are not active.  */
+  if (type && TREE_CODE (type) == VECTOR_TYPE)
+    mode = type_natural_mode (type);
+
+  if (TARGET_64BIT_MS_ABI)
+    return function_arg_ms_64 (cum, mode, omode, named);
+  else if (TARGET_64BIT)
+    return function_arg_64 (cum, mode, omode, type);
+  else
+    return function_arg_32 (cum, mode, omode, type, bytes, words);
 }
 
 /* A C expression that indicates when an argument must be passed by
@@ -4204,15 +4254,35 @@ ix86_pass_by_reference (CUMULATIVE_ARGS 
 			enum machine_mode mode ATTRIBUTE_UNUSED,
 			tree type, bool named ATTRIBUTE_UNUSED)
 {
-  if (!TARGET_64BIT)
-    return 0;
-
-  if (type && int_size_in_bytes (type) == -1)
+  if (TARGET_64BIT_MS_ABI)
     {
-      if (TARGET_DEBUG_ARG)
-	fprintf (stderr, "function_arg_pass_by_reference\n");
-      return 1;
+      if (type)
+	{
+	  /* Arrays are passed by reference.  */
+	  if (TREE_CODE (type) == ARRAY_TYPE)
+	    return true;
+
+	  if (AGGREGATE_TYPE_P (type))
+	    {
+	      /* Structs/unions of sizes other than 8, 16, 32, or 64 bits
+	         are passed by reference.  */
+	      int el2 = exact_log2 (int_size_in_bytes (type));
+	      return !(el2 >= 0 && el2 <= 3);
+	    }
+	}
+
+      /* ??? How to handle long double?  */
+      if (mode == XFmode)
+	return false;
+
+      /* __m128 is passed by reference.  */
+      /* ??? How to handle complex?  For now treat them as structs,
+	 and pass them by reference if they're too large.  */
+      if (GET_MODE_SIZE (mode) > 8)
+	return true;
     }
+  else if (TARGET_64BIT && type && int_size_in_bytes (type) == -1)
+    return 1;
 
   return 0;
 }
@@ -4278,104 +4348,206 @@ ix86_function_arg_boundary (enum machine
     align = PARM_BOUNDARY;
   if (!TARGET_64BIT)
     {
-      /* i386 ABI defines all arguments to be 4 byte aligned.  We have to
-	 make an exception for SSE modes since these require 128bit
-	 alignment.
+      /* i386 ABI defines all arguments to be 4 byte aligned.  We have to
+	 make an exception for SSE modes since these require 128bit
+	 alignment.
+
+	 The handling here differs from field_alignment.  ICC aligns MMX
+	 arguments to 4 byte boundaries, while structure fields are aligned
+	 to 8 byte boundaries.  */
+      if (!TARGET_SSE)
+	align = PARM_BOUNDARY;
+      else if (!type)
+	{
+	  if (!SSE_REG_MODE_P (mode))
+	    align = PARM_BOUNDARY;
+	}
+      else
+	{
+	  if (!contains_128bit_aligned_vector_p (type))
+	    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 (int regno)
+{
+  switch (regno)
+    {
+    case 0:
+      return true;
+
+    case FIRST_FLOAT_REG:
+      return TARGET_FLOAT_RETURNS_IN_80387;
+
+    case FIRST_SSE_REG:
+      return TARGET_SSE;
+
+    case FIRST_MMX_REG:
+      if (TARGET_MACHO || TARGET_64BIT)
+	return false;
+      return TARGET_MMX;
+    }
+
+  return false;
+}
+
+/* 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.  */
+
+static rtx
+function_value_32 (enum machine_mode orig_mode, enum machine_mode mode,
+		   tree fntype, tree fn)
+{
+  unsigned int regno;
+
+  /* 8-byte vector modes in %mm0. See ix86_return_in_memory for where
+     we normally prevent this case when mmx is not available.  However
+     some ABIs may require the result to be returned like DImode.  */
+  if (VECTOR_MODE_P (mode) && GET_MODE_SIZE (mode) == 8)
+    regno = TARGET_MMX ? FIRST_MMX_REG : 0;
+
+  /* 16-byte vector modes in %xmm0.  See ix86_return_in_memory for where
+     we prevent this case when sse is not available.  However some ABIs
+     may require the result to be returned like integer TImode.  */
+  else if (mode == TImode
+	   || (VECTOR_MODE_P (mode) && GET_MODE_SIZE (mode) == 16))
+    regno = TARGET_SSE ? FIRST_SSE_REG : 0;
+
+  /* Decimal floating point values can go in %eax, unlike other float modes.  */
+  else if (DECIMAL_FLOAT_MODE_P (mode))
+    regno = 0;
+
+  /* Most things go in %eax, except (unless -mno-fp-ret-in-387) fp values.  */
+  else if (!SCALAR_FLOAT_MODE_P (mode) || !TARGET_FLOAT_RETURNS_IN_80387)
+    regno = 0;
+
+  /* Floating point return values in %st(0), except for local functions when
+     SSE math is enabled or for functions with sseregparm attribute.  */
+  else
+    {
+      regno = FIRST_FLOAT_REG;
 
-	 The handling here differs from field_alignment.  ICC aligns MMX
-	 arguments to 4 byte boundaries, while structure fields are aligned
-	 to 8 byte boundaries.  */
-      if (!TARGET_SSE)
-	align = PARM_BOUNDARY;
-      else if (!type)
+      if ((fn || fntype) && (mode == SFmode || mode == DFmode))
 	{
-	  if (!SSE_REG_MODE_P (mode))
-	    align = PARM_BOUNDARY;
+	  int sse_level = ix86_function_sseregparm (fntype, fn);
+	  if ((sse_level >= 1 && mode == SFmode)
+	      || (sse_level == 2 && mode == DFmode))
+	    regno = FIRST_SSE_REG;
 	}
-      else
+    }
+
+  return gen_rtx_REG (orig_mode, regno);
+}
+
+static rtx
+function_value_64 (enum machine_mode orig_mode, enum machine_mode mode,
+		   tree valtype)
+{
+  rtx ret;
+
+  /* Handle libcalls, which don't provide a type node.  */
+  if (valtype == NULL)
+    {
+      switch (mode)
 	{
-	  if (!contains_128bit_aligned_vector_p (type))
-	    align = PARM_BOUNDARY;
+	case SFmode:
+	case SCmode:
+	case DFmode:
+	case DCmode:
+	case TFmode:
+	case SDmode:
+	case DDmode:
+	case TDmode:
+	  return gen_rtx_REG (mode, FIRST_SSE_REG);
+	case XFmode:
+	case XCmode:
+	  return gen_rtx_REG (mode, FIRST_FLOAT_REG);
+	case TCmode:
+	  return NULL;
+	default:
+	  return gen_rtx_REG (mode, 0);
 	}
     }
-  if (align > 128)
-    align = 128;
-  return align;
+
+  ret = construct_container (mode, orig_mode, valtype, 1,
+			     REGPARM_MAX, SSE_REGPARM_MAX,
+			     x86_64_int_return_registers, 0);
+
+  /* For zero sized structures, construct_container returns NULL, but we
+     need to keep rest of compiler happy by returning meaningful value.  */
+  if (!ret)
+    ret = gen_rtx_REG (orig_mode, 0);
+
+  return ret;
 }
 
-/* Return true if N is a possible register number of function value.  */
-bool
-ix86_function_value_regno_p (int regno)
+static rtx
+function_value_ms_64 (enum machine_mode orig_mode, enum machine_mode mode)
 {
-  if (TARGET_MACHO)
-    {
-      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));
-      }
-  else
-    {
-      if (regno == 0
-          || (regno == FIRST_FLOAT_REG && TARGET_FLOAT_RETURNS_IN_80387)
-          || (regno == FIRST_SSE_REG && TARGET_SSE))
-        return true;
+  unsigned int regno = 0;
 
-      if (!TARGET_64BIT
-          && (regno == FIRST_MMX_REG && TARGET_MMX))
-	    return true;
+  if (mode == SFmode || mode == DFmode)
+    regno = FIRST_SSE_REG;
+  else if (VECTOR_MODE_P (mode) || GET_MODE_SIZE (mode) == 16)
+    regno = FIRST_SSE_REG;
+  else if (mode == XFmode)
+    /* ??? How to handle long double?  */
+    regno = FIRST_FLOAT_REG;
+  
+  return gen_rtx_REG (orig_mode, regno);
+}
 
-      return false;
-    }
+static rtx
+ix86_function_value_1 (tree valtype, tree fntype_or_decl,
+		       enum machine_mode orig_mode, enum machine_mode mode)
+{
+  tree fn, fntype;
+
+  fn = NULL_TREE;
+  if (fntype_or_decl && DECL_P (fntype_or_decl))
+    fn = fntype_or_decl;
+  fntype = fn ? TREE_TYPE (fn) : fntype_or_decl;
+
+  if (TARGET_64BIT_MS_ABI)
+    return function_value_ms_64 (orig_mode, mode);
+  else if (TARGET_64BIT)
+    return function_value_64 (orig_mode, mode, valtype);
+  else
+    return function_value_32 (orig_mode, mode, fntype, fn);
 }
 
-/* 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
+static rtx
 ix86_function_value (tree valtype, tree fntype_or_decl,
 		     bool outgoing ATTRIBUTE_UNUSED)
 {
-  enum machine_mode natmode = type_natural_mode (valtype);
+  enum machine_mode mode, orig_mode;
 
-  if (TARGET_64BIT)
-    {
-      rtx ret = construct_container (natmode, TYPE_MODE (valtype), valtype,
-				     1, REGPARM_MAX, SSE_REGPARM_MAX,
-				     x86_64_int_return_registers, 0);
-      /* For zero sized structures, construct_container return NULL, but we
-	 need to keep rest of compiler happy by returning meaningful value.  */
-      if (!ret)
-	ret = gen_rtx_REG (TYPE_MODE (valtype), 0);
-      return ret;
-    }
-  else
-    {
-      tree fn = NULL_TREE, fntype;
-      if (fntype_or_decl
-	  && DECL_P (fntype_or_decl))
-        fn = fntype_or_decl;
-      fntype = fn ? TREE_TYPE (fn) : fntype_or_decl;
-      return gen_rtx_REG (TYPE_MODE (valtype),
-			  ix86_value_regno (natmode, fn, fntype));
-    }
+  orig_mode = TYPE_MODE (valtype);
+  mode = type_natural_mode (valtype);
+  return ix86_function_value_1 (valtype, fntype_or_decl, orig_mode, mode);
 }
 
-/* Return true iff type is returned in memory.  */
-int
-ix86_return_in_memory (tree type)
+rtx
+ix86_libcall_value (enum machine_mode mode)
 {
-  int needed_intregs, needed_sseregs, size;
-  enum machine_mode mode = type_natural_mode (type);
+  return ix86_function_value_1 (NULL, NULL, mode, mode);
+}
 
-  if (TARGET_64BIT)
-    return !examine_argument (mode, type, 1, &needed_intregs, &needed_sseregs);
+/* Return true iff type is returned in memory.  */
+
+static int
+return_in_memory_32 (tree type, enum machine_mode mode)
+{
+  HOST_WIDE_INT size;
 
   if (mode == BLKmode)
     return 1;
@@ -4412,6 +4584,43 @@ ix86_return_in_memory (tree type)
   return 0;
 }
 
+static int
+return_in_memory_64 (tree type, enum machine_mode mode)
+{
+  int needed_intregs, needed_sseregs;
+  return !examine_argument (mode, type, 1, &needed_intregs, &needed_sseregs);
+}
+
+static int
+return_in_memory_ms_64 (tree type, enum machine_mode mode)
+{
+  HOST_WIDE_INT size = int_size_in_bytes (type);
+
+  /* __m128 and friends are returned in xmm0.  */
+  if (size == 16 && VECTOR_MODE_P (mode))
+    return 0;
+
+  /* ??? How to handle long double?  */
+  if (mode == XFmode)
+    return 0;
+
+  /* Otherwise, the size must be exactly in [1248].  */
+  return (size != 1 || size != 2 || size != 4 || size != 8);
+}
+
+int
+ix86_return_in_memory (tree type)
+{
+  enum machine_mode mode = type_natural_mode (type);
+
+  if (TARGET_64BIT_MS_ABI)
+    return return_in_memory_ms_64 (type, mode);
+  else if (TARGET_64BIT)
+    return return_in_memory_64 (type, mode);
+  else
+    return return_in_memory_32 (type, mode);
+}
+
 /* When returning SSE vector types, we have a choice of either
      (1) being abi incompatible with a -march switch, or
      (2) generating an error.
@@ -4428,7 +4637,7 @@ ix86_struct_value_rtx (tree type, int in
 {
   static bool warnedsse, warnedmmx;
 
-  if (type)
+  if (!TARGET_64BIT && type)
     {
       /* Look at the return type of the function, not the function type.  */
       enum machine_mode mode = TYPE_MODE (TREE_TYPE (type));
@@ -4458,77 +4667,6 @@ ix86_struct_value_rtx (tree type, int in
   return NULL;
 }
 
-/* Define how to find the value returned by a library function
-   assuming the value has mode MODE.  */
-rtx
-ix86_libcall_value (enum machine_mode mode)
-{
-  if (TARGET_64BIT)
-    {
-      switch (mode)
-	{
-	case SFmode:
-	case SCmode:
-	case DFmode:
-	case DCmode:
-	case TFmode:
-	case SDmode:
-	case DDmode:
-	case TDmode:
-	  return gen_rtx_REG (mode, FIRST_SSE_REG);
-	case XFmode:
-	case XCmode:
-	  return gen_rtx_REG (mode, FIRST_FLOAT_REG);
-	case TCmode:
-	  return NULL;
-	default:
-	  return gen_rtx_REG (mode, 0);
-	}
-    }
-  else
-    return gen_rtx_REG (mode, ix86_value_regno (mode, NULL, NULL));
-}
-
-/* Given a mode, return the register to use for a return value.  */
-
-static int
-ix86_value_regno (enum machine_mode mode, tree func, tree fntype)
-{
-  gcc_assert (!TARGET_64BIT);
-
-  /* 8-byte vector modes in %mm0. See ix86_return_in_memory for where
-     we normally prevent this case when mmx is not available.  However
-     some ABIs may require the result to be returned like DImode.  */
-  if (VECTOR_MODE_P (mode) && GET_MODE_SIZE (mode) == 8)
-    return TARGET_MMX ? FIRST_MMX_REG : 0;
-
-  /* 16-byte vector modes in %xmm0.  See ix86_return_in_memory for where
-     we prevent this case when sse is not available.  However some ABIs
-     may require the result to be returned like integer TImode.  */
-  if (mode == TImode || (VECTOR_MODE_P (mode) && GET_MODE_SIZE (mode) == 16))
-    return TARGET_SSE ? FIRST_SSE_REG : 0;
-
-  /* Decimal floating point values can go in %eax, unlike other float modes.  */
-  if (DECIMAL_FLOAT_MODE_P (mode))
-    return 0;
-
-  /* Most things go in %eax, except (unless -mno-fp-ret-in-387) fp values.  */
-  if (!SCALAR_FLOAT_MODE_P (mode) || !TARGET_FLOAT_RETURNS_IN_80387)
-    return 0;
-
-  /* Floating point return values in %st(0), except for local functions when
-     SSE math is enabled or for functions with sseregparm attribute.  */
-  if ((func || fntype)
-      && (mode == SFmode || mode == DFmode))
-    {
-      int sse_level = ix86_function_sseregparm (fntype, func);
-      if ((sse_level >= 1 && mode == SFmode)
-	  || (sse_level == 2 && mode == DFmode))
-        return FIRST_SSE_REG;
-    }
-
-  return FIRST_FLOAT_REG;
-}
 
 /* Create the va_list data type.  */
 
@@ -4538,7 +4676,7 @@ ix86_build_builtin_va_list (void)
   tree f_gpr, f_fpr, f_ovf, f_sav, record, type_decl;
 
   /* For i386 we use plain pointer to argument area.  */
-  if (!TARGET_64BIT)
+  if (!TARGET_64BIT || TARGET_64BIT_MS_ABI)
     return build_pointer_type (char_type_node);
 
   record = (*lang_hooks.types.make_type) (RECORD_TYPE);
@@ -4577,51 +4715,29 @@ ix86_build_builtin_va_list (void)
 /* Worker function for TARGET_SETUP_INCOMING_VARARGS.  */
 
 static void
-ix86_setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
-			     tree type, int *pretend_size ATTRIBUTE_UNUSED,
-			     int no_rtl)
+setup_incoming_varargs_64 (CUMULATIVE_ARGS *cum)
 {
-  CUMULATIVE_ARGS next_cum;
-  rtx save_area = NULL_RTX, mem;
+  rtx save_area, 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;
-
   if (! cfun->va_list_gpr_size && ! cfun->va_list_fpr_size)
     return;
 
   /* Indicate to allocate space on the stack for varargs save area.  */
   ix86_save_varrargs_registers = 1;
-
   cfun->stack_alignment_needed = 128;
 
-  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;
-
+  save_area = frame_pointer_rtx;
   set = get_varargs_alias_set ();
 
-  for (i = next_cum.regno;
+  for (i = cum->regno;
        i < ix86_regparm
-       && i < next_cum.regno + cfun->va_list_gpr_size / UNITS_PER_WORD;
+       && i < cum->regno + cfun->va_list_gpr_size / UNITS_PER_WORD;
        i++)
     {
       mem = gen_rtx_MEM (Pmode,
@@ -4632,7 +4748,7 @@ ix86_setup_incoming_varargs (CUMULATIVE_
 					x86_64_int_parameter_registers[i]));
     }
 
-  if (next_cum.sse_nregs && cfun->va_list_fpr_size)
+  if (cum->sse_nregs && cfun->va_list_fpr_size)
     {
       /* Now emit code to save SSE registers.  The AX parameter contains number
 	 of SSE parameter registers used to call this function.  We use
@@ -4650,13 +4766,13 @@ ix86_setup_incoming_varargs (CUMULATIVE_
       emit_insn (gen_rtx_SET (VOIDmode, tmp_reg,
 			      gen_rtx_MULT (Pmode, nsse_reg,
 					    GEN_INT (4))));
-      if (next_cum.sse_regno)
+      if (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))));
+					GEN_INT (cum->sse_regno * 4))));
       else
 	emit_move_insn (nsse_reg, label_ref);
       emit_insn (gen_subdi3 (nsse_reg, nsse_reg, tmp_reg));
@@ -4675,9 +4791,62 @@ ix86_setup_incoming_varargs (CUMULATIVE_
 
       /* And finally do the dirty job!  */
       emit_insn (gen_sse_prologue_save (mem, nsse_reg,
-					GEN_INT (next_cum.sse_regno), label));
+					GEN_INT (cum->sse_regno), label));
+    }
+}
+
+static void
+setup_incoming_varargs_ms_64 (CUMULATIVE_ARGS *cum)
+{
+  int set = get_varargs_alias_set ();
+  int i;
+
+  for (i = cum->regno; i < REGPARM_MAX; i++)
+    {
+      rtx reg, mem;
+
+      mem = gen_rtx_MEM (Pmode,
+			 plus_constant (virtual_incoming_args_rtx,
+					i * UNITS_PER_WORD));
+      MEM_NOTRAP_P (mem) = 1;
+      set_mem_alias_set (mem, set);
+
+      reg = gen_rtx_REG (Pmode, x86_64_ms_abi_int_parameter_registers[i]);
+      emit_move_insn (mem, reg);
     }
+}
+
+static void
+ix86_setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+			     tree type, int *pretend_size ATTRIBUTE_UNUSED,
+			     int no_rtl)
+{
+  CUMULATIVE_ARGS next_cum;
+  tree fntype;
+  int stdarg_p;
+
+  /* This argument doesn't appear to be used anymore.  Which is good,
+     because the old code here didn't suppress rtl generation.  */
+  gcc_assert (!no_rtl);
+
+  if (!TARGET_64BIT)
+    return;
+
+  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 (TARGET_64BIT_MS_ABI)
+    setup_incoming_varargs_ms_64 (&next_cum);
+  else
+    setup_incoming_varargs_64 (&next_cum);
 }
 
 /* Implement va_start.  */
@@ -4691,7 +4860,7 @@ ix86_va_start (tree valist, rtx nextarg)
   tree type;
 
   /* Only 64bit target needs something special.  */
-  if (!TARGET_64BIT)
+  if (!TARGET_64BIT || TARGET_64BIT_MS_ABI)
     {
       std_expand_builtin_va_start (valist, nextarg);
       return;
@@ -4713,10 +4882,6 @@ ix86_va_start (tree valist, rtx nextarg)
   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);
-
   if (cfun->va_list_gpr_size)
     {
       type = TREE_TYPE (gpr);
@@ -4774,7 +4939,7 @@ ix86_gimplify_va_arg (tree valist, tree 
   enum machine_mode nat_mode;
 
   /* Only 64bit target needs something special.  */
-  if (!TARGET_64BIT)
+  if (!TARGET_64BIT || TARGET_64BIT_MS_ABI)
     return std_gimplify_va_arg_expr (valist, type, pre_p, post_p);
 
   f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
@@ -5966,16 +6131,21 @@ ix86_expand_prologue (void)
   else
     {
       /* Only valid for Win32.  */
-      rtx eax = gen_rtx_REG (SImode, 0);
-      bool eax_live = ix86_eax_live_at_start_p ();
+      rtx eax = gen_rtx_REG (Pmode, 0);
+      bool eax_live;
       rtx t;
 
-      gcc_assert (!TARGET_64BIT);
+      gcc_assert (!TARGET_64BIT || TARGET_64BIT_MS_ABI);
+
+      if (TARGET_64BIT_MS_ABI)
+	eax_live = false;
+      else
+	eax_live = ix86_eax_live_at_start_p ();
 
       if (eax_live)
 	{
 	  emit_insn (gen_push (eax));
-	  allocate -= 4;
+	  allocate -= UNITS_PER_WORD;
 	}
 
       emit_move_insn (eax, GEN_INT (allocate));
@@ -5996,7 +6166,7 @@ ix86_expand_prologue (void)
 			       - frame.nregs * UNITS_PER_WORD);
 	  else
 	    t = plus_constant (stack_pointer_rtx, allocate);
-	  emit_move_insn (eax, gen_rtx_MEM (SImode, t));
+	  emit_move_insn (eax, gen_rtx_MEM (Pmode, t));
 	}
     }
 
@@ -6250,7 +6420,7 @@ ix86_expand_epilogue (int style)
 	{
 	  rtx ecx = gen_rtx_REG (SImode, 2);
 
-	  /* There is no "pascal" calling convention in 64bit ABI.  */
+	  /* There is no "pascal" calling convention in any 64bit ABI.  */
 	  gcc_assert (!TARGET_64BIT);
 
 	  emit_insn (gen_popsi1 (ecx));
@@ -6713,6 +6883,10 @@ legitimate_pic_operand_p (rtx x)
 
     case SYMBOL_REF:
     case LABEL_REF:
+      /* ??? Hack.  See legitimize_pic_address re dllimports.  */
+      if (TARGET_64BIT_MS_ABI)
+	return true;
+
       return legitimate_pic_address_disp_p (x);
 
     default:
@@ -7092,7 +7266,7 @@ legitimate_address_p (enum machine_mode 
 
 /* Return a unique alias set for the GOT.  */
 
-static HOST_WIDE_INT
+HOST_WIDE_INT
 ix86_GOT_alias_set (void)
 {
   static HOST_WIDE_INT set = -1;
@@ -7138,6 +7312,13 @@ legitimize_pic_address (rtx orig, rtx re
 
   if (TARGET_64BIT && legitimate_pic_address_disp_p (addr))
     new = addr;
+
+  /* ??? What are we supposed to do with variables that are dllimported
+     but not properly marked as such?  For now, hard-code the full 
+     64-bit address and assume it'll be fixed up.  */
+  else if (TARGET_64BIT_MS_ABI)
+    new = force_reg (Pmode, addr);
+
   else if (TARGET_64BIT
 	   && ix86_cmodel != CM_SMALL_PIC
 	   && gotoff_operand (addr, Pmode))
@@ -7729,7 +7910,8 @@ output_pic_addr_const (FILE *file, rtx x
 #endif
 	  assemble_name (file, name);
 	}
-      if (!TARGET_MACHO && code == 'P' && ! SYMBOL_REF_LOCAL_P (x))
+      if (!TARGET_MACHO && !TARGET_64BIT_MS_ABI
+	  && code == 'P' && ! SYMBOL_REF_LOCAL_P (x))
 	fputs ("@PLT", file);
       break;
 
@@ -9464,7 +9646,6 @@ ix86_expand_clear (rtx dest)
   /* 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.  */
@@ -19577,37 +19758,29 @@ static rtx
 x86_this_parameter (tree function)
 {
   tree type = TREE_TYPE (function);
+  bool aggr = aggregate_value_p (TREE_TYPE (type), type) != 0;
 
   if (TARGET_64BIT)
     {
-      int n = aggregate_value_p (TREE_TYPE (type), type) != 0;
-      return gen_rtx_REG (DImode, x86_64_int_parameter_registers[n]);
+      const int *parm_regs;
+
+      if (TARGET_64BIT_MS_ABI)
+        parm_regs = x86_64_ms_abi_int_parameter_registers;
+      else
+        parm_regs = x86_64_int_parameter_registers;
+      return gen_rtx_REG (DImode, parm_regs[aggr]);
     }
 
-  if (ix86_function_regparm (type, function) > 0)
+  if (ix86_function_regparm (type, function) > 0
+      && !type_has_variadic_args_p (type))
     {
-      tree parm;
-
-      parm = TYPE_ARG_TYPES (type);
-      /* Figure out whether or not the function has a variable number of
-	 arguments.  */
-      for (; parm; parm = TREE_CHAIN (parm))
-	if (TREE_VALUE (parm) == void_type_node)
-	  break;
-      /* If not, the this parameter is in the first argument.  */
-      if (parm)
-	{
-	  int regno = 0;
-	  if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (type)))
-	    regno = 2;
-	  return gen_rtx_REG (SImode, regno);
-	}
+      int regno = 0;
+      if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (type)))
+	regno = 2;
+      return gen_rtx_REG (SImode, regno);
     }
 
-  if (aggregate_value_p (TREE_TYPE (type), type))
-    return gen_rtx_MEM (SImode, plus_constant (stack_pointer_rtx, 8));
-  else
-    return gen_rtx_MEM (SImode, plus_constant (stack_pointer_rtx, 4));
+  return gen_rtx_MEM (SImode, plus_constant (stack_pointer_rtx, aggr ? 8 : 4));
 }
 
 /* Determine whether x86_output_mi_thunk can succeed.  */
@@ -19696,7 +19869,7 @@ x86_output_mi_thunk (FILE *file ATTRIBUT
 	{
 	  int tmp_regno = 2 /* ECX */;
 	  if (lookup_attribute ("fastcall",
-	      TYPE_ATTRIBUTES (TREE_TYPE (function))))
+				TYPE_ATTRIBUTES (TREE_TYPE (function))))
 	    tmp_regno = 0 /* EAX */;
 	  tmp = gen_rtx_REG (SImode, tmp_regno);
 	}
--- gcc/config/i386/i386.h	(revision 123123)
+++ gcc/config/i386/i386.h	(local)
@@ -20,6 +20,21 @@ along with GCC; see the file COPYING.  I
 the Free Software Foundation, 51 Franklin Street, Fifth Floor,
 Boston, MA 02110-1301, USA.  */
 
+/* The purpose of this file is to define the characteristics of the i386,
+   independent of assembler syntax or operating system.
+
+   Three other files build on this one to describe a specific assembler syntax:
+   bsd386.h, att386.h, and sun386.h.
+
+   The actual tm.h file for a particular system should include
+   this file, and then the file for the appropriate assembler syntax.
+
+   Many macros that specify assembler syntax are omitted entirely from
+   this file because they really belong in the files for particular
+   assemblers.  These include RP, IP, LPREFIX, PUT_OP_SIZE, USE_STAR,
+   ADDR_BEG, ADDR_END, PRINT_IREG, PRINT_SCALE, PRINT_B_I_S, and many
+   that start with ASM_ or end in ASM_OP.  */
+
 #include "config/vxworks-dummy.h"
 
 /* Algorithm to expand string function with.  */
@@ -34,7 +49,9 @@ enum stringop_alg
    loop,
    unrolled_loop
 };
+
 #define NAX_STRINGOP_ALGS 4
+
 /* Specify what algorithm to use for stringops on known size.
    When size is unknown, the UNKNOWN_SIZE alg is used.  When size is
    known at compile time or estimated via feedback, the SIZE array
@@ -43,8 +60,7 @@ enum stringop_alg
    For example initializer:
     {{256, loop}, {-1, rep_prefix_4_byte}}		
    will use loop for blocks smaller or equal to 256 bytes, rep prefix will
-   be used otherwise.
-*/
+   be used otherwise.  */
 struct stringop_algs
 {
   const enum stringop_alg unknown_size;
@@ -54,21 +70,6 @@ struct stringop_algs
   } size [NAX_STRINGOP_ALGS];
 };
 
-/* The purpose of this file is to define the characteristics of the i386,
-   independent of assembler syntax or operating system.
-
-   Three other files build on this one to describe a specific assembler syntax:
-   bsd386.h, att386.h, and sun386.h.
-
-   The actual tm.h file for a particular system should include
-   this file, and then the file for the appropriate assembler syntax.
-
-   Many macros that specify assembler syntax are omitted entirely from
-   this file because they really belong in the files for particular
-   assemblers.  These include RP, IP, LPREFIX, PUT_OP_SIZE, USE_STAR,
-   ADDR_BEG, ADDR_END, PRINT_IREG, PRINT_SCALE, PRINT_B_I_S, and many
-   that start with ASM_ or end in ASM_OP.  */
-
 /* Define the specific costs for a given cpu */
 
 struct processor_costs {
@@ -374,6 +375,9 @@ extern int x86_prefetch_sse;
    redefines this to 1.  */
 #define TARGET_MACHO 0
 
+/* Likewise, for the Windows 64-bit ABI.  */
+#define TARGET_64BIT_MS_ABI 0
+
 /* Subtargets may reset this to 1 in order to enable 96-bit long double
    with the rounding mode forced to 53 bits.  */
 #define TARGET_96_ROUND_53_LONG_DOUBLE 0
@@ -995,6 +999,11 @@ do {									\
 	for (i = FIRST_REX_SSE_REG; i <= LAST_REX_SSE_REG; i++)		\
 	  reg_names[i] = "";						\
       }									\
+    if (TARGET_64BIT_MS_ABI)						\
+      {									\
+        call_used_regs[4 /*RSI*/] = 0;                                  \
+        call_used_regs[5 /*RDI*/] = 0;                                  \
+      }									\
   } while (0)
 
 /* Return number of consecutive hard regs needed starting at reg REGNO
--- gcc/config/i386/i386.md	(revision 123123)
+++ gcc/config/i386/i386.md	(local)
@@ -19636,7 +19636,7 @@
    (set_attr "mode" "DI")])
 
 (define_expand "allocate_stack_worker"
-  [(match_operand:SI 0 "register_operand" "")]
+  [(match_operand 0 "register_operand" "")]
   "TARGET_STACK_PROBE"
 {
   if (reload_completed)
@@ -19697,23 +19697,23 @@
   "")
 
 (define_expand "allocate_stack"
-  [(parallel [(set (match_operand:SI 0 "register_operand" "=r")
-		   (minus:SI (reg:SI SP_REG)
-			     (match_operand:SI 1 "general_operand" "")))
-	      (clobber (reg:CC FLAGS_REG))])
-   (parallel [(set (reg:SI SP_REG)
-		   (minus:SI (reg:SI SP_REG) (match_dup 1)))
-	      (clobber (reg:CC FLAGS_REG))])]
+  [(match_operand 0 "register_operand" "")
+   (match_operand 1 "general_operand" "")]
   "TARGET_STACK_PROBE"
 {
 #ifdef CHECK_STACK_LIMIT
   if (CONST_INT_P (operands[1])
       && INTVAL (operands[1]) < CHECK_STACK_LIMIT)
-    emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx,
-			   operands[1]));
+    {
+      rtx x = expand_simple_binop (Pmode, MINUS, stack_pointer_rtx,
+				   operands[1], stack_pointer_rtx,
+				   0, OPTAB_DIRECT);
+      if (x != stack_pointer_rtx)
+	emit_move_insn (stack_pointer_rtx, x);
+    }
   else
 #endif
-    emit_insn (gen_allocate_stack_worker (copy_to_mode_reg (SImode,
+    emit_insn (gen_allocate_stack_worker (copy_to_mode_reg (Pmode,
 							    operands[1])));
 
   emit_move_insn (operands[0], virtual_stack_dynamic_rtx);
--- gcc/config/i386/mingw32.h	(revision 123123)
+++ gcc/config/i386/mingw32.h	(local)
@@ -21,7 +21,11 @@ the Free Software Foundation, 51 Frankli
 Boston, MA 02110-1301, USA.  */
 
 #undef TARGET_VERSION
-#define TARGET_VERSION fprintf (stderr, " (x86 MinGW)"); 
+#if TARGET_64BIT_DEFAULT
+#define TARGET_VERSION fprintf (stderr,"(x86_64 MinGW");
+#else
+#define TARGET_VERSION fprintf (stderr," (x86 MinGW)");
+#endif
 
 /* See i386/crtdll.h for an alternative definition.  */
 #define EXTRA_OS_CPP_BUILTINS()					\
@@ -32,13 +36,25 @@ Boston, MA 02110-1301, USA.  */
       builtin_define ("_WIN32");				\
       builtin_define_std ("WIN32");				\
       builtin_define_std ("WINNT");				\
+	  if(TARGET_64BIT_MS_ABI) {					\
+	  builtin_define ("__MINGW64__");			\
+	  builtin_define_with_value("_INTEGRAL_MAX_BITS","64",0); \
+	  builtin_define_std ("WIN64");				\
+	  builtin_define_std ("_WIN64");			\
+	  } else {									\
+	  builtin_define_with_value("_INTEGRAL_MAX_BITS","32",0); \
+	  }	\
     }								\
   while (0)
 
 /* Override the standard choice of /usr/include as the default prefix
    to try when searching for header files.  */
 #undef STANDARD_INCLUDE_DIR
+#if TARGET_64BIT_DEFAULT
+#define STANDARD_INCLUDE_DIR "/mingw/include64"
+#else
 #define STANDARD_INCLUDE_DIR "/mingw/include"
+#endif
 #undef STANDARD_INCLUDE_COMPONENT
 #define STANDARD_INCLUDE_COMPONENT "MINGW"
 
@@ -71,8 +87,12 @@ Boston, MA 02110-1301, USA.  */
 
 /* Override startfile prefix defaults.  */
 #ifndef STANDARD_STARTFILE_PREFIX_1
+#if TARGET_64BIT_DEFAULT
+#define STANDARD_STARTFILE_PREFIX_1 "/mingw/lib64/"
+#else
 #define STANDARD_STARTFILE_PREFIX_1 "/mingw/lib/"
 #endif
+#endif
 #ifndef STANDARD_STARTFILE_PREFIX_2
 #define STANDARD_STARTFILE_PREFIX_2 ""
 #endif
--- gcc/config/i386/predicates.md	(revision 123123)
+++ gcc/config/i386/predicates.md	(local)
@@ -344,7 +344,7 @@
 
 ;; Return nonzero if OP is nonmemory operand acceptable by movabs patterns.
 (define_predicate "x86_64_movabs_operand"
-  (if_then_else (match_test "!TARGET_64BIT || !flag_pic")
+  (if_then_else (match_test "TARGET_64BIT_MS_ABI || !flag_pic")
     (match_operand 0 "nonmemory_operand")
     (ior (match_operand 0 "register_operand")
 	 (and (match_operand 0 "const_double_operand")
--- gcc/config/i386/winnt.c	(revision 123123)
+++ gcc/config/i386/winnt.c	(local)
@@ -277,8 +277,11 @@ i386_pe_mark_dllimport (tree decl)
   idp = get_identifier (newname);
 
   symref = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp));
-  SET_SYMBOL_REF_DECL (symref, decl);
-  newrtl = gen_rtx_MEM (Pmode,symref);
+  SYMBOL_REF_FLAGS (symref) = SYMBOL_FLAG_LOCAL;
+
+  newrtl = gen_const_mem (Pmode, symref);
+  set_mem_alias_set (newrtl, ix86_GOT_alias_set ());
+
   XEXP (DECL_RTL (decl), 0) = newrtl;
 
   DECL_DLLIMPORT_P (decl) = 1;
--- gcc/config/iq2000/iq2000.h	(revision 123123)
+++ gcc/config/iq2000/iq2000.h	(local)
@@ -375,7 +375,7 @@ enum reg_class
 
 #define REG_PARM_STACK_SPACE(FNDECL) 0
 
-#define OUTGOING_REG_PARM_STACK_SPACE
+#define OUTGOING_REG_PARM_STACK_SPACE 1
 
 #define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) 0
 
--- gcc/config/mips/mips.h	(revision 123123)
+++ gcc/config/mips/mips.h	(local)
@@ -1807,7 +1807,7 @@ extern const enum reg_class mips_regno_t
    If `ACCUMULATE_OUTGOING_ARGS' is also defined, the only effect
    of this macro is to determine whether the space is included in
    `current_function_outgoing_args_size'.  */
-#define OUTGOING_REG_PARM_STACK_SPACE
+#define OUTGOING_REG_PARM_STACK_SPACE 1
 
 #define STACK_BOUNDARY (TARGET_NEWABI ? 128 : 64)
 
--- gcc/config/mn10300/mn10300.h	(revision 123123)
+++ gcc/config/mn10300/mn10300.h	(local)
@@ -529,7 +529,7 @@ enum reg_class {
 /* We use d0/d1 for passing parameters, so allocate 8 bytes of space
    for a register flushback area.  */
 #define REG_PARM_STACK_SPACE(DECL) 8
-#define OUTGOING_REG_PARM_STACK_SPACE
+#define OUTGOING_REG_PARM_STACK_SPACE 1
 #define ACCUMULATE_OUTGOING_ARGS 1
 
 /* So we can allocate space for return pointers once for the function
--- gcc/config/mt/mt.h	(revision 123123)
+++ gcc/config/mt/mt.h	(local)
@@ -533,7 +533,7 @@ extern struct mt_frame_info current_fram
 
 /* Define this if it is the responsibility of the caller to
    allocate the area reserved for arguments passed in registers.  */
-#define OUTGOING_REG_PARM_STACK_SPACE
+#define OUTGOING_REG_PARM_STACK_SPACE 1
 
 /* The number of register assigned to holding function arguments.  */
 #define MT_NUM_ARG_REGS        4
--- gcc/config/pa/pa.h	(revision 123123)
+++ gcc/config/pa/pa.h	(local)
@@ -602,7 +602,7 @@ extern struct rtx_def *hppa_pic_save_rtx
 
 /* Define this if the above stack space is to be considered part of the
    space allocated by the caller.  */
-#define OUTGOING_REG_PARM_STACK_SPACE
+#define OUTGOING_REG_PARM_STACK_SPACE 1
 
 /* Keep the stack pointer constant throughout the function.
    This is both an optimization and a necessity: longjmp
--- gcc/config/rs6000/rs6000.h	(revision 123123)
+++ gcc/config/rs6000/rs6000.h	(local)
@@ -1277,7 +1277,7 @@ extern enum rs6000_abi rs6000_current_ab
 
 /* Define this if the above stack space is to be considered part of the
    space allocated by the caller.  */
-#define OUTGOING_REG_PARM_STACK_SPACE
+#define OUTGOING_REG_PARM_STACK_SPACE 1
 
 /* This is the difference between the logical top of stack and the actual sp.
 
--- gcc/config/score/score.h	(revision 123123)
+++ gcc/config/score/score.h	(local)
@@ -534,7 +534,7 @@ enum reg_class
    If `ACCUMULATE_OUTGOING_ARGS' is also defined, the only effect
    of this macro is to determine whether the space is included in
    `current_function_outgoing_args_size'.  */
-#define OUTGOING_REG_PARM_STACK_SPACE
+#define OUTGOING_REG_PARM_STACK_SPACE 1
 
 #define RETURN_POPS_ARGS(FUNDECL, FUNTYPE, STACK_SIZE) 0
 
--- gcc/config/spu/spu.h	(revision 123123)
+++ gcc/config/spu/spu.h	(local)
@@ -337,7 +337,7 @@ targetm.resolve_overloaded_builtin = spu
 
 #define REG_PARM_STACK_SPACE(FNDECL) 0
 
-#define OUTGOING_REG_PARM_STACK_SPACE 
+#define OUTGOING_REG_PARM_STACK_SPACE 1
 
 #define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) (0)
 
--- gcc/config/v850/v850.h	(revision 123123)
+++ gcc/config/v850/v850.h	(local)
@@ -626,7 +626,7 @@ struct cum_arg { int nbytes; int anonymo
 
 /* Define this if the above stack space is to be considered part of the
    space allocated by the caller.  */
-#define OUTGOING_REG_PARM_STACK_SPACE
+#define OUTGOING_REG_PARM_STACK_SPACE 1
 
 /* 1 if N is a possible register number for function argument passing.  */
 
--- gcc/config.build	(revision 123123)
+++ gcc/config.build	(local)
@@ -77,7 +77,7 @@ case $build in
     build_xm_file=i386/xm-cygwin.h
     build_exeext=.exe
     ;;
-  i[34567]86-*-mingw32*)
+  i[34567]86-*-mingw32* | x86_64-*-mingw32)
     build_xm_file=i386/xm-mingw32.h
     build_exeext=.exe
     ;;
--- gcc/config.gcc	(revision 123123)
+++ gcc/config.gcc	(local)
@@ -1343,7 +1343,7 @@ i[34567]86-*-pe | i[34567]86-*-cygwin*)
 		thread_file='posix'
 	fi
 	;;
-i[34567]86-*-mingw32*)
+i[34567]86-*-mingw32* | x86_64-*-mingw32*)
 	tm_file="${tm_file} i386/unix.h i386/bsd.h i386/gas.h dbxcoff.h i386/cygming.h i386/mingw32.h"
 	xm_file=i386/xm-mingw32.h
 	tmake_file="i386/t-cygming i386/t-mingw32"
--- gcc/config.host	(revision 123123)
+++ gcc/config.host	(local)
@@ -168,7 +168,7 @@ case ${host} in
     host_xmake_file="${host_xmake_file} i386/x-cygwin"
     host_exeext=.exe
     ;;
-  i[34567]86-*-mingw32*)
+  i[34567]86-*-mingw32* | x86_64-*-mingw32*)
     host_xm_file=i386/xm-mingw32.h
     host_xmake_file="${host_xmake_file} i386/x-mingw32"
     host_exeext=.exe
--- gcc/doc/tm.texi	(revision 123123)
+++ gcc/doc/tm.texi	(local)
@@ -3730,7 +3730,7 @@ which.
 @c something, not sure if it looks good.  --mew 10feb93
 
 @defmac OUTGOING_REG_PARM_STACK_SPACE
-Define this if it is the responsibility of the caller to allocate the area
+Define this to one if it is the responsibility of the caller to allocate the area
 reserved for arguments passed in registers.
 
 If @code{ACCUMULATE_OUTGOING_ARGS} is defined, this macro controls
@@ -9719,6 +9719,18 @@ This must be a value that would also be 
 @samp{#pragma pack()} (that is, a small power of two).
 @end defmac
 
+@findex #pragma
+@findex pragma
+@defmac HANDLE_PRAGMA_PUSH_POP_MACRO
+Define this macro if you want to support the Win32 style pragmas
+@samp{#pragma push_macro(macro-name-as-string)} and @samp{#pragma
+pop_macro(macro-name-as-string)}.  The @samp{#pragma push_macro(
+macro-name-as-string)} pragma saves the named macro and via
+@samp{#pragma pop_macro(macro-name-as-string)} it will return to the
+previous value.
+@end defmac
+
+
 @defmac DOLLARS_IN_IDENTIFIERS
 Define this macro to control use of the character @samp{$} in
 identifier names for the C family of languages.  0 means @samp{$} is
--- gcc/expr.c	(revision 123123)
+++ gcc/expr.c	(local)
@@ -54,6 +54,10 @@ Software Foundation, 51 Franklin Street,
 #include "target.h"
 #include "timevar.h"
 
+#ifndef OUTGOING_REG_PARM_STACK_SPACE
+#define OUTGOING_REG_PARM_STACK_SPACE 0
+#endif
+
 /* Decide whether a function's arguments should be processed
    from first to last or from last to first.
 
@@ -1237,8 +1241,8 @@ block_move_libcall_safe_for_call_parm (v
 
   /* If registers go on the stack anyway, any argument is sure to clobber
      an outgoing argument.  */
-#if defined (REG_PARM_STACK_SPACE) && defined (OUTGOING_REG_PARM_STACK_SPACE)
-  {
+#if defined (REG_PARM_STACK_SPACE)
+  if(OUTGOING_REG_PARM_STACK_SPACE) {
     tree fn = emit_block_move_libcall_fn (false);
     (void) fn;
     if (REG_PARM_STACK_SPACE (fn) != 0)
--- gcc/function.c	(revision 123123)
+++ gcc/function.c	(local)
@@ -65,6 +65,11 @@ Software Foundation, 51 Franklin Street,
 #include "predict.h"
 #include "vecprim.h"
 
+#ifndef OUTGOING_REG_PARM_STACK_SPACE
+#define OUTGOING_REG_PARM_STACK_SPACE 0
+#endif
+
+
 #ifndef LOCAL_ALIGNMENT
 #define LOCAL_ALIGNMENT(TYPE, ALIGNMENT) ALIGNMENT
 #endif
@@ -1211,12 +1216,12 @@ static int cfa_offset;
    `current_function_outgoing_args_size'.  Nevertheless, we must allow
    for it when allocating stack dynamic objects.  */
 
-#if defined(REG_PARM_STACK_SPACE) && ! defined(OUTGOING_REG_PARM_STACK_SPACE)
+#if defined(REG_PARM_STACK_SPACE)
 #define STACK_DYNAMIC_OFFSET(FNDECL)	\
 ((ACCUMULATE_OUTGOING_ARGS						      \
-  ? (current_function_outgoing_args_size + REG_PARM_STACK_SPACE (FNDECL)) : 0)\
- + (STACK_POINTER_OFFSET))						      \
-
+  ? (current_function_outgoing_args_size				      \
+     + (OUTGOING_REG_PARM_STACK_SPACE ? 0 : REG_PARM_STACK_SPACE (FNDECL)))   \
+  : 0) + (STACK_POINTER_OFFSET))
 #else
 #define STACK_DYNAMIC_OFFSET(FNDECL)	\
 ((ACCUMULATE_OUTGOING_ARGS ? current_function_outgoing_args_size : 0)	      \


More information about the Gcc-patches mailing list