OSDN Git Service

* configure.ac: Add test for new section attribute
[pf3gnuchains/gcc-fork.git] / gcc / config / i386 / winnt.c
index ee3448d..af3f975 100644 (file)
@@ -1,24 +1,23 @@
 /* Subroutines for insn-output.c for Windows NT.
    Contributed by Douglas Rupp (drupp@cs.washington.edu)
-   Copyright (C) 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003
-   Free Software Foundation, Inc.
+   Copyright (C) 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+   2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
 
-This file is part of GNU CC.
+This file is part of GCC.
 
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
 
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
@@ -31,9 +30,13 @@ Boston, MA 02111-1307, USA.  */
 #include "tree.h"
 #include "flags.h"
 #include "tm_p.h"
-#include "toplev.h"
+#include "diagnostic-core.h"
 #include "hashtab.h"
+#include "langhooks.h"
 #include "ggc.h"
+#include "target.h"
+#include "except.h"
+#include "lto-streamer.h"
 
 /* i386/PE specific attribute support.
 
@@ -46,462 +49,337 @@ Boston, MA 02111-1307, USA.  */
    multiple times.
 */
 
-static tree associated_type PARAMS ((tree));
-const char * gen_stdcall_suffix PARAMS ((tree));
-const char * gen_fastcall_suffix PARAMS ((tree));
-int i386_pe_dllexport_p PARAMS ((tree));
-int i386_pe_dllimport_p PARAMS ((tree));
-void i386_pe_mark_dllexport PARAMS ((tree));
-void i386_pe_mark_dllimport PARAMS ((tree));
-
-/* This is we how mark internal identifiers with dllimport or dllexport
-   attributes.  */
-#ifndef DLL_IMPORT_PREFIX
-#define DLL_IMPORT_PREFIX "#i."
-#endif
-#ifndef DLL_EXPORT_PREFIX
-#define DLL_EXPORT_PREFIX "#e."
-#endif
-
-/* Handle a "dllimport" or "dllexport" attribute;
+/* Handle a "shared" attribute;
    arguments as in struct attribute_spec.handler.  */
 tree
-ix86_handle_dll_attribute (node, name, args, flags, no_add_attrs)
-     tree *node;
-     tree name;
-     tree args;
-     int flags;
-     bool *no_add_attrs;
-{
-  /* These attributes may apply to structure and union types being created,
-     but otherwise should pass to the declaration involved.  */
-  if (!DECL_P (*node))
-    {
-      if (flags & ((int) ATTR_FLAG_DECL_NEXT | (int) ATTR_FLAG_FUNCTION_NEXT
-                  | (int) ATTR_FLAG_ARRAY_NEXT))
-       {
-         *no_add_attrs = true;
-         return tree_cons (name, args, NULL_TREE);
-       }
-      if (TREE_CODE (*node) != RECORD_TYPE && TREE_CODE (*node) != UNION_TYPE)
-       {
-         warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
-         *no_add_attrs = true;
-       }
-    }
-
-  /* `extern' needn't be specified with dllimport.
-     Specify `extern' now and hope for the best.  Sigh.  */
-  else if (TREE_CODE (*node) == VAR_DECL
-          && is_attribute_p ("dllimport", name))
+ix86_handle_shared_attribute (tree *node, tree name,
+                             tree args ATTRIBUTE_UNUSED,
+                             int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+{
+  if (TREE_CODE (*node) != VAR_DECL)
     {
-      DECL_EXTERNAL (*node) = 1;
-      TREE_PUBLIC (*node) = 1;
+      warning (OPT_Wattributes, "%qE attribute only applies to variables",
+              name);
+      *no_add_attrs = true;
     }
 
   return NULL_TREE;
 }
 
-/* Handle a "shared" attribute;
+/* Handle a "selectany" attribute;
    arguments as in struct attribute_spec.handler.  */
 tree
-ix86_handle_shared_attribute (node, name, args, flags, no_add_attrs)
-     tree *node;
-     tree name;
-     tree args ATTRIBUTE_UNUSED;
-     int flags ATTRIBUTE_UNUSED;
-     bool *no_add_attrs;
+ix86_handle_selectany_attribute (tree *node, tree name,
+                                tree args ATTRIBUTE_UNUSED,
+                                int flags ATTRIBUTE_UNUSED,
+                                bool *no_add_attrs)
 {
-  if (TREE_CODE (*node) != VAR_DECL)
-    {
-      warning ("`%s' attribute only applies to variables",
-              IDENTIFIER_POINTER (name));
+  /* The attribute applies only to objects that are initialized and have
+     external linkage.  However, we may not know about initialization
+     until the language frontend has processed the decl. We'll check for
+     initialization later in encode_section_info.  */
+  if (TREE_CODE (*node) != VAR_DECL || !TREE_PUBLIC (*node))
+    {  
+      error ("%qE attribute applies only to initialized variables"
+                    " with external linkage", name);
       *no_add_attrs = true;
     }
 
   return NULL_TREE;
 }
+
 \f
 /* Return the type that we should use to determine if DECL is
    imported or exported.  */
 
 static tree
-associated_type (decl)
-     tree decl;
+associated_type (tree decl)
 {
-  tree t = NULL_TREE;
-
-  /* In the C++ frontend, DECL_CONTEXT for a method doesn't actually refer
-     to the containing class.  So we look at the 'this' arg.  */
-  if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
-    {
-      /* Artificial methods are not affected by the import/export status of
-        their class unless they are virtual.  */
-      if (! DECL_ARTIFICIAL (decl) || DECL_VINDEX (decl))
-       t = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (decl))));
-    }
-  else if (DECL_CONTEXT (decl)
-          && TREE_CODE_CLASS (TREE_CODE (DECL_CONTEXT (decl))) == 't')
-    t = DECL_CONTEXT (decl);
-
-  return t;
+  return (DECL_CONTEXT (decl) && TYPE_P (DECL_CONTEXT (decl))
+          ?  DECL_CONTEXT (decl) : NULL_TREE);
 }
 
-/* Return nonzero if DECL is a dllexport'd object.  */
+/* Return true if DECL should be a dllexport'd object.  */
 
-int
-i386_pe_dllexport_p (decl)
-     tree decl;
+static bool
+i386_pe_determine_dllexport_p (tree decl)
 {
-  tree exp;
+  if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != FUNCTION_DECL)
+    return false;
 
-  if (TREE_CODE (decl) != VAR_DECL
-      && TREE_CODE (decl) != FUNCTION_DECL)
-    return 0;
-  exp = lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl));
-  if (exp)
-    return 1;
+  /* Don't export local clones of dllexports.  */
+  if (!TREE_PUBLIC (decl))
+    return false;
 
-  /* Class members get the dllexport status of their class.  */
-  if (associated_type (decl))
-    {
-      exp = lookup_attribute ("dllexport",
-                             TYPE_ATTRIBUTES (associated_type (decl)));
-      if (exp)
-       return 1;
-    }
+  if (lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl)))
+    return true;
 
-  return 0;
+  return false;
 }
 
-/* Return nonzero if DECL is a dllimport'd object.  */
+/* Return true if DECL should be a dllimport'd object.  */
 
-int
-i386_pe_dllimport_p (decl)
-     tree decl;
+static bool
+i386_pe_determine_dllimport_p (tree decl)
 {
-  tree imp;
-
-  if (TREE_CODE (decl) == FUNCTION_DECL
-      && TARGET_NOP_FUN_DLLIMPORT)
-    return 0;
-
-  if (TREE_CODE (decl) != VAR_DECL
-      && TREE_CODE (decl) != FUNCTION_DECL)
-    return 0;
-  imp = lookup_attribute ("dllimport", DECL_ATTRIBUTES (decl));
-  if (imp)
-    return 1;
-
-  /* Class members get the dllimport status of their class.  */
-  if (associated_type (decl))
-    {
-      imp = lookup_attribute ("dllimport",
-                             TYPE_ATTRIBUTES (associated_type (decl)));
-      if (imp)
-       return 1;
-    }
-
-  return 0;
+  tree assoc;
+
+  if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != FUNCTION_DECL)
+    return false;
+
+  if (DECL_DLLIMPORT_P (decl))
+    return true;
+
+  /* The DECL_DLLIMPORT_P flag was set for decls in the class definition
+     by  targetm.cxx.adjust_class_at_definition.  Check again to emit
+     error message if the class attribute has been overridden by an
+     out-of-class definition of static data.  */
+  assoc = associated_type (decl);
+  if (assoc && lookup_attribute ("dllimport", TYPE_ATTRIBUTES (assoc))
+      && TREE_CODE (decl) == VAR_DECL
+      && TREE_STATIC (decl) && TREE_PUBLIC (decl)
+      && !DECL_EXTERNAL (decl)
+      /* vtable's are linkonce constants, so defining a vtable is not
+        an error as long as we don't try to import it too.  */
+      && !DECL_VIRTUAL_P (decl))
+       error ("definition of static data member %q+D of "
+              "dllimport%'d class", decl);
+
+  return false;
 }
 
-/* Return nonzero if SYMBOL is marked as being dllexport'd.  */
+/* Handle the -mno-fun-dllimport target switch.  */
 
-int
-i386_pe_dllexport_name_p (symbol)
-     const char *symbol;
+bool
+i386_pe_valid_dllimport_attribute_p (const_tree decl)
 {
-  return (strncmp (DLL_EXPORT_PREFIX, symbol,
-                  strlen (DLL_EXPORT_PREFIX)) == 0);
+   if (TARGET_NOP_FUN_DLLIMPORT && TREE_CODE (decl) == FUNCTION_DECL)
+     return false;
+   return true;
 }
 
-/* Return nonzero if SYMBOL is marked as being dllimport'd.  */
+/* Return string which is the function name, identified by ID, modified
+   with a suffix consisting of an atsign (@) followed by the number of
+   bytes of arguments.  If ID is NULL use the DECL_NAME as base. If
+   FASTCALL is true, also add the FASTCALL_PREFIX.
+   Return NULL if no change required.  */
 
-int
-i386_pe_dllimport_name_p (symbol)
-     const char *symbol;
+static tree
+gen_stdcall_or_fastcall_suffix (tree decl, tree id, bool fastcall)
 {
-  return (strncmp (DLL_IMPORT_PREFIX, symbol,
-                  strlen (DLL_IMPORT_PREFIX)) == 0);
-}
-
-/* Mark a DECL as being dllexport'd.
-   Note that we override the previous setting (eg: dllimport).  */
+  HOST_WIDE_INT total = 0;
+  const char *old_str = IDENTIFIER_POINTER (id != NULL_TREE ? id : DECL_NAME (decl));
+  char *new_str, *p;
+  tree type = TREE_TYPE (DECL_ORIGIN (decl));
+  tree arg;
+  function_args_iterator args_iter;
 
-void
-i386_pe_mark_dllexport (decl)
-     tree decl;
-{
-  const char *oldname;
-  char  *newname;
-  rtx rtlname;
-  tree idp;
-
-  rtlname = XEXP (DECL_RTL (decl), 0);
-  if (GET_CODE (rtlname) == SYMBOL_REF)
-    oldname = XSTR (rtlname, 0);
-  else if (GET_CODE (rtlname) == MEM
-          && GET_CODE (XEXP (rtlname, 0)) == SYMBOL_REF)
-    oldname = XSTR (XEXP (rtlname, 0), 0);
-  else
-    abort ();
-  if (i386_pe_dllimport_name_p (oldname))
-    /* Remove DLL_IMPORT_PREFIX.  */
-    oldname += strlen (DLL_IMPORT_PREFIX);
-  else if (i386_pe_dllexport_name_p (oldname))
-    return; /* already done */
+  gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);  
 
-  newname = alloca (strlen (DLL_EXPORT_PREFIX) + strlen (oldname) + 1);
-  sprintf (newname, "%s%s", DLL_EXPORT_PREFIX, oldname);
+  if (prototype_p (type))
+    {
+      /* This attribute is ignored for variadic functions.  */ 
+      if (stdarg_p (type))
+       return NULL_TREE;
 
-  /* We pass newname through get_identifier to ensure it has a unique
-     address.  RTL processing can sometimes peek inside the symbol ref
-     and compare the string's addresses to see if two symbols are
-     identical.  */
-  idp = get_identifier (newname);
+      /* Quit if we hit an incomplete type.  Error is reported
+        by convert_arguments in c-typeck.c or cp/typeck.c.  */
+      FOREACH_FUNCTION_ARGS(type, arg, args_iter)
+       {
+         HOST_WIDE_INT parm_size;
+         HOST_WIDE_INT parm_boundary_bytes = PARM_BOUNDARY / BITS_PER_UNIT;
 
-  XEXP (DECL_RTL (decl), 0) =
-    gen_rtx (SYMBOL_REF, Pmode, IDENTIFIER_POINTER (idp));
-}
+         if (! COMPLETE_TYPE_P (arg))
+           break;
 
-/* Mark a DECL as being dllimport'd.  */
+         parm_size = int_size_in_bytes (arg);
+         if (parm_size < 0)
+           break;
 
-void
-i386_pe_mark_dllimport (decl)
-     tree decl;
-{
-  const char *oldname;
-  char  *newname;
-  tree idp;
-  rtx rtlname;
-
-  rtlname = XEXP (DECL_RTL (decl), 0);
-  if (GET_CODE (rtlname) == SYMBOL_REF)
-    oldname = XSTR (rtlname, 0);
-  else if (GET_CODE (rtlname) == MEM
-          && GET_CODE (XEXP (rtlname, 0)) == SYMBOL_REF)
-    oldname = XSTR (XEXP (rtlname, 0), 0);
-  else
-    abort ();
-  if (i386_pe_dllexport_name_p (oldname))
-    {
-      error ("`%s' declared as both exported to and imported from a DLL",
-             IDENTIFIER_POINTER (DECL_NAME (decl)));
-      return;
-    }
-  else if (i386_pe_dllimport_name_p (oldname))
-    {
-      /* Already done, but force correct linkage since the redeclaration 
-         might have omitted explicit extern.  Sigh.  */
-      if (TREE_CODE (decl) == VAR_DECL
-         /* ??? Is this test for vtables needed?  */
-         && !DECL_VIRTUAL_P (decl))
-       {
-         DECL_EXTERNAL (decl) = 1;
-         TREE_PUBLIC (decl) = 1;
+         /* Must round up to include padding.  This is done the same
+            way as in store_one_arg.  */
+         parm_size = ((parm_size + parm_boundary_bytes - 1)
+                      / parm_boundary_bytes * parm_boundary_bytes);
+         total += parm_size;
        }
-      return;
-    }
-
-  /* ??? One can well ask why we're making these checks here,
-     and that would be a good question.  */
-
-  /* Imported variables can't be initialized. Note that C++ classes
-     are marked initial, so we need to check.  */
-  if (TREE_CODE (decl) == VAR_DECL
-      && !DECL_VIRTUAL_P (decl)
-      && (DECL_INITIAL (decl)
-          && ! TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))))
-    {
-      error_with_decl (decl, "initialized variable `%s' is marked dllimport");
-      return;
-    }
-  /* Nor can they be static.  */
-  if (TREE_CODE (decl) == VAR_DECL
-      /* ??? Is this test for vtables needed?  */
-      && !DECL_VIRTUAL_P (decl)
-      && 0 /*???*/)
-    {
-      error_with_decl (decl, "static variable `%s' is marked dllimport");
-      return;
     }
 
-  newname = alloca (strlen (DLL_IMPORT_PREFIX) + strlen (oldname) + 1);
-  sprintf (newname, "%s%s", DLL_IMPORT_PREFIX, oldname);
-
-  /* We pass newname through get_identifier to ensure it has a unique
-     address.  RTL processing can sometimes peek inside the symbol ref
-     and compare the string's addresses to see if two symbols are
-     identical.  */
-  idp = get_identifier (newname);
+  /* Assume max of 8 base 10 digits in the suffix.  */
+  p = new_str = XALLOCAVEC (char, 1 + strlen (old_str) + 1 + 8 + 1);
+  if (fastcall)
+    *p++ = FASTCALL_PREFIX;
+  sprintf (p, "%s@" HOST_WIDE_INT_PRINT_DEC, old_str, total);
 
-  XEXP (DECL_RTL (decl), 0) 
-    = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp));
-
-  /* Can't treat a pointer to this as a constant address */
-  DECL_NON_ADDR_CONST_P (decl) = 1;
+  return get_identifier (new_str);
 }
 
-/* Return string which is the former assembler name modified with a 
-   prefix consisting of FASTCALL_PREFIX and a suffix consisting of an
-   atsign (@) followed by the number of bytes of arguments.  */
+/* Maybe decorate and get a new identifier for the DECL of a stdcall or
+   fastcall function. The original identifier is supplied in ID. */
 
-const char *
-gen_fastcall_suffix (decl)
-  tree decl;
+static tree
+i386_pe_maybe_mangle_decl_assembler_name (tree decl, tree id)
 {
-  int total = 0;
+  tree new_id = NULL_TREE;
 
-  const char *asmname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
-  char *newsym;
+  if (TREE_CODE (decl) == FUNCTION_DECL)
+    { 
+      unsigned int ccvt = ix86_get_callcvt (TREE_TYPE (decl));
+      if ((ccvt & IX86_CALLCVT_STDCALL) != 0)
+        {
+         if (TARGET_RTD)
+           /* If we are using -mrtd emit undecorated symbol and let linker
+              do the proper resolving.  */
+           return NULL_TREE;
+         new_id = gen_stdcall_or_fastcall_suffix (decl, id, false);
+       }
+      else if ((ccvt & IX86_CALLCVT_FASTCALL) != 0)
+       new_id = gen_stdcall_or_fastcall_suffix (decl, id, true);
+    }
 
-  if (TYPE_ARG_TYPES (TREE_TYPE (decl)))
-    if (TREE_VALUE (tree_last (TYPE_ARG_TYPES (TREE_TYPE (decl))))
-        == void_type_node)
-      {
-       tree formal_type = TYPE_ARG_TYPES (TREE_TYPE (decl));
+  return new_id;
+}
 
-       while (TREE_VALUE (formal_type) != void_type_node)
-         {
-           int parm_size
-             = TREE_INT_CST_LOW (TYPE_SIZE (TREE_VALUE (formal_type)));
-           /* Must round up to include padding.  This is done the same
-              way as in store_one_arg.  */
-           parm_size = ((parm_size + PARM_BOUNDARY - 1)
-                        / PARM_BOUNDARY * PARM_BOUNDARY);
-           total += parm_size;
-           formal_type = TREE_CHAIN (formal_type);
-         }
-      }
+/* Emit an assembler directive to set symbol for DECL visibility to
+   the visibility type VIS, which must not be VISIBILITY_DEFAULT.
+   As for PE there is no hidden support in gas, we just warn for
+   user-specified visibility attributes.  */
 
-  /* Assume max of 8 base 10 digits in the suffix.  */ 
-  newsym = xmalloc (1 + strlen (asmname) + 1 + 8 + 1);
-  sprintf (newsym, "%c%s@%d", FASTCALL_PREFIX, asmname, total/BITS_PER_UNIT);
-  return IDENTIFIER_POINTER (get_identifier (newsym));
+void
+i386_pe_assemble_visibility (tree decl,
+                            int vis ATTRIBUTE_UNUSED)
+{
+  if (!decl
+      || !lookup_attribute ("visibility", DECL_ATTRIBUTES (decl)))
+    return;
+  warning (OPT_Wattributes, "visibility attribute not supported "
+          "in this configuration; ignored");
 }
 
-/* Return string which is the former assembler name modified with a 
-   suffix consisting of an atsign (@) followed by the number of bytes of 
-   arguments */
-
-const char *
-gen_stdcall_suffix (decl)
-  tree decl;
+/* This is used as a target hook to modify the DECL_ASSEMBLER_NAME
+   in the language-independent default hook
+   langhooks,c:lhd_set_decl_assembler_name ()
+   and in cp/mangle,c:mangle_decl ().  */
+tree
+i386_pe_mangle_decl_assembler_name (tree decl, tree id)
 {
-  int total = 0;
-  /* ??? This probably should use XSTR (XEXP (DECL_RTL (decl), 0), 0) instead
-     of DECL_ASSEMBLER_NAME.  */
-  const char *asmname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
-  char *newsym;
+  tree new_id = i386_pe_maybe_mangle_decl_assembler_name (decl, id);   
 
-  if (TYPE_ARG_TYPES (TREE_TYPE (decl)))
-    if (TREE_VALUE (tree_last (TYPE_ARG_TYPES (TREE_TYPE (decl)))) 
-        == void_type_node)
-      {
-       tree formal_type = TYPE_ARG_TYPES (TREE_TYPE (decl));
+  return (new_id ? new_id : id);
+}
 
-       while (TREE_VALUE (formal_type) != void_type_node)
-         {
-           int parm_size
-             = TREE_INT_CST_LOW (TYPE_SIZE (TREE_VALUE (formal_type)));
-           /* Must round up to include padding.  This is done the same
-              way as in store_one_arg.  */
-           parm_size = ((parm_size + PARM_BOUNDARY - 1)
-                        / PARM_BOUNDARY * PARM_BOUNDARY);
-           total += parm_size;
-           formal_type = TREE_CHAIN (formal_type);
-         }
-      }
+/* This hook behaves the same as varasm.c/assemble_name(), but
+   generates the name into memory rather than outputting it to
+   a file stream.  */
 
-  /* Assume max of 8 base 10 digits in the suffix.  */ 
-  newsym = xmalloc (strlen (asmname) + 1 + 8 + 1);
-  sprintf (newsym, "%s@%d", asmname, total/BITS_PER_UNIT);
-  return IDENTIFIER_POINTER (get_identifier (newsym));
+tree
+i386_pe_mangle_assembler_name (const char *name ATTRIBUTE_UNUSED)
+{
+  const char *skipped = name + (*name == '*' ? 1 : 0);
+  const char *stripped = targetm.strip_name_encoding (skipped);
+  if (*name != '*' && *user_label_prefix && *stripped != FASTCALL_PREFIX)
+    stripped = ACONCAT ((user_label_prefix, stripped, NULL));
+  return get_identifier (stripped);
 }
 
 void
-i386_pe_encode_section_info (decl, rtl, first)
-     tree decl;
-     rtx rtl;
-     int first;
+i386_pe_encode_section_info (tree decl, rtx rtl, int first)
 {
-  if (!first)
-    return;
+  rtx symbol;
+  int flags;
 
+  /* Do this last, due to our frobbing of DECL_DLLIMPORT_P above.  */
   default_encode_section_info (decl, rtl, first);
 
-  if (TREE_CODE (decl) == FUNCTION_DECL)
-    {
-      if (lookup_attribute ("stdcall",
-                           TYPE_ATTRIBUTES (TREE_TYPE (decl))))
-        XEXP (DECL_RTL (decl), 0) = 
-         gen_rtx (SYMBOL_REF, Pmode, gen_stdcall_suffix (decl));
-      else if (lookup_attribute ("fastcall",
-                                TYPE_ATTRIBUTES (TREE_TYPE (decl))))
-        XEXP (DECL_RTL (decl), 0) =
-         gen_rtx (SYMBOL_REF, Pmode, gen_fastcall_suffix (decl));
-    }
+  /* Careful not to prod global register variables.  */
+  if (!MEM_P (rtl))
+    return;
 
-  /* Mark the decl so we can tell from the rtl whether the object is
-     dllexport'd or dllimport'd.  */
-
-  if (i386_pe_dllexport_p (decl))
-    i386_pe_mark_dllexport (decl);
-  else if (i386_pe_dllimport_p (decl))
-    i386_pe_mark_dllimport (decl);
-  /* It might be that DECL has already been marked as dllimport, but a
-     subsequent definition nullified that.  The attribute is gone but
-     DECL_RTL still has (DLL_IMPORT_PREFIX) prefixed. We need to remove
-     that. Ditto for the DECL_NON_ADDR_CONST_P flag.  */
-  else if ((TREE_CODE (decl) == FUNCTION_DECL
-           || TREE_CODE (decl) == VAR_DECL)
-          && DECL_RTL (decl) != NULL_RTX
-          && GET_CODE (DECL_RTL (decl)) == MEM
-          && GET_CODE (XEXP (DECL_RTL (decl), 0)) == MEM
-          && GET_CODE (XEXP (XEXP (DECL_RTL (decl), 0), 0)) == SYMBOL_REF
-          && i386_pe_dllimport_name_p (XSTR (XEXP (XEXP (DECL_RTL (decl), 0), 0), 0)))
-    {
-      const char *oldname = XSTR (XEXP (XEXP (DECL_RTL (decl), 0), 0), 0);
-      /* Remove DLL_IMPORT_PREFIX.  */
-      tree idp = get_identifier (oldname + strlen (DLL_IMPORT_PREFIX));
-      rtx newrtl = gen_rtx (SYMBOL_REF, Pmode, IDENTIFIER_POINTER (idp));
+  symbol = XEXP (rtl, 0);
+  gcc_assert (GET_CODE (symbol) == SYMBOL_REF);
 
-      XEXP (DECL_RTL (decl), 0) = newrtl;
+  switch (TREE_CODE (decl))
+    {
+    case FUNCTION_DECL:
+      /* FIXME:  Imported stdcall names are not modified by the Ada frontend.
+        Check and decorate the RTL name now.  */
+      if  (strcmp (lang_hooks.name, "GNU Ada") == 0)
+       {
+         tree new_id;
+         tree old_id = DECL_ASSEMBLER_NAME (decl);
+         const char* asm_str = IDENTIFIER_POINTER (old_id);
+         /* Do not change the identifier if a verbatim asmspec
+            or if stdcall suffix already added. */
+         if (!(*asm_str == '*' || strchr (asm_str, '@'))
+             && (new_id = i386_pe_maybe_mangle_decl_assembler_name (decl,
+                                                                    old_id)))
+           XSTR (symbol, 0) = IDENTIFIER_POINTER (new_id);
+       }
+      break;
 
-      DECL_NON_ADDR_CONST_P (decl) = 0;
+    case VAR_DECL:
+      if (lookup_attribute ("selectany", DECL_ATTRIBUTES (decl)))
+       {
+         if (DECL_INITIAL (decl)
+             /* If an object is initialized with a ctor, the static
+                initialization and destruction code for it is present in
+                each unit defining the object.  The code that calls the
+                ctor is protected by a link-once guard variable, so that
+                the object still has link-once semantics,  */
+             || TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))
+           make_decl_one_only (decl, DECL_ASSEMBLER_NAME (decl));
+         else
+           error ("%q+D:'selectany' attribute applies only to "
+                  "initialized objects", decl);
+       }
+      break;
 
-      /* We previously set TREE_PUBLIC and DECL_EXTERNAL.
-        We leave these alone for now.  */
+    default:
+      return;
     }
-}
 
-/* Strip only the leading encoding, leaving the stdcall suffix and fastcall
-   prefix if it exists.  */
+  /* Mark the decl so we can tell from the rtl whether the object is
+     dllexport'd or dllimport'd.  tree.c: merge_dllimport_decl_attributes
+     handles dllexport/dllimport override semantics.  */
+  flags = (SYMBOL_REF_FLAGS (symbol) &
+          ~(SYMBOL_FLAG_DLLIMPORT | SYMBOL_FLAG_DLLEXPORT));
+  if (i386_pe_determine_dllexport_p (decl))
+    flags |= SYMBOL_FLAG_DLLEXPORT;
+  else if (i386_pe_determine_dllimport_p (decl))
+    flags |= SYMBOL_FLAG_DLLIMPORT;
+  SYMBOL_REF_FLAGS (symbol) = flags;
+}
 
-const char *
-i386_pe_strip_name_encoding (str)
-     const char *str;
+bool
+i386_pe_binds_local_p (const_tree exp)
 {
-  if (strncmp (str, DLL_IMPORT_PREFIX, strlen (DLL_IMPORT_PREFIX))
-      == 0)
-    str += strlen (DLL_IMPORT_PREFIX);
-  else if (strncmp (str, DLL_EXPORT_PREFIX, strlen (DLL_EXPORT_PREFIX))
-          == 0)
-    str += strlen (DLL_EXPORT_PREFIX);
-  if (*str == '*')
-    str += 1;
-  return str;
+  /* PE does not do dynamic binding.  Indeed, the only kind of
+     non-local reference comes from a dllimport'd symbol.  */
+  if ((TREE_CODE (exp) == VAR_DECL || TREE_CODE (exp) == FUNCTION_DECL)
+      && DECL_DLLIMPORT_P (exp))
+    return false;
+
+  /* Or a weak one, now that they are supported.  */
+  if ((TREE_CODE (exp) == VAR_DECL || TREE_CODE (exp) == FUNCTION_DECL)
+      && DECL_WEAK (exp))
+    return false;
+
+  return true;
 }
 
-/* Also strip the stdcall suffix.  */
+/* Also strip the fastcall prefix and stdcall suffix.  */
 
 const char *
-i386_pe_strip_name_encoding_full (str)
-     const char *str;
+i386_pe_strip_name_encoding_full (const char *str)
 {
   const char *p;
-  const char *name = i386_pe_strip_name_encoding (str);
+  const char *name = default_strip_name_encoding (str);
+
+  /* Strip leading '@' on fastcall symbols.  */
+  if (*name == '@')
+    name++;
+
+  /* Strip trailing "@n".  */
   p = strchr (name, '@');
   if (p)
     return ggc_alloc_string (name, p - name);
@@ -509,52 +387,8 @@ i386_pe_strip_name_encoding_full (str)
   return name;
 }
 
-/* Output a reference to a label. Fastcall symbols are prefixed with @,
-   whereas symbols for functions using other calling conventions don't
-   have a prefix (unless they are marked dllimport or dllexport).  */
-
-void i386_pe_output_labelref (stream, name)
-     FILE *stream;
-     const char *name;
-{
-  if (strncmp (name, DLL_IMPORT_PREFIX, strlen (DLL_IMPORT_PREFIX))
-      == 0)
-   /* A dll import */ 
-   {
-      if (name[strlen (DLL_IMPORT_PREFIX)] == FASTCALL_PREFIX)
-      /* A dllimport fastcall symbol.  */   
-        {
-          fprintf (stream, "__imp_%s",
-                   i386_pe_strip_name_encoding (name));
-        }
-      else
-      /* A dllimport non-fastcall symbol.  */ 
-        {
-          fprintf (stream, "__imp__%s",
-                   i386_pe_strip_name_encoding (name));
-        }
-    }
-  else if ((name[0] == FASTCALL_PREFIX)
-           || (strncmp (name, DLL_EXPORT_PREFIX, strlen (DLL_EXPORT_PREFIX)
-              == 0 
-              && name[strlen (DLL_EXPORT_PREFIX)] == FASTCALL_PREFIX)))
-    /* A fastcall symbol.  */
-    {
-      fprintf (stream, "%s",
-               i386_pe_strip_name_encoding (name));
-    }
-  else
-    /* Everything else.  */
-    {
-      fprintf (stream, "%s%s", USER_LABEL_PREFIX,
-               i386_pe_strip_name_encoding (name));
-    }
-}
-
 void
-i386_pe_unique_section (decl, reloc)
-     tree decl;
-     int reloc;
+i386_pe_unique_section (tree decl, int reloc)
 {
   int len;
   const char *name, *prefix;
@@ -566,7 +400,7 @@ i386_pe_unique_section (decl, reloc)
   /* The object is put in, for example, section .text$foo.
      The linker will then ultimately place them in .text
      (everything from the $ on is stripped). Don't put
-     read-only data in .rdata section to avoid a PE linker 
+     read-only data in .rdata section to avoid a PE linker
      bug when .rdata$* grouped sections are used in code
      without a .rdata section.  */
   if (TREE_CODE (decl) == FUNCTION_DECL)
@@ -576,7 +410,7 @@ i386_pe_unique_section (decl, reloc)
   else
     prefix = ".data$";
   len = strlen (name) + strlen (prefix);
-  string = alloca (len + 1);
+  string = XALLOCAVEC (char, len + 1);
   sprintf (string, "%s%s", prefix, name);
 
   DECL_SECTION_NAME (decl) = build_string (len, string);
@@ -600,17 +434,14 @@ i386_pe_unique_section (decl, reloc)
 #define SECTION_PE_SHARED      SECTION_MACH_DEP
 
 unsigned int
-i386_pe_section_type_flags (decl, name, reloc)
-     tree decl;
-     const char *name;
-     int reloc;
+i386_pe_section_type_flags (tree decl, const char *name, int reloc)
 {
   static htab_t htab;
   unsigned int flags;
   unsigned int **slot;
 
   /* The names we put in the hashtable will always be the unique
-     versions gived to us by the stringtable, so we can just use
+     versions given to us by the stringtable, so we can just use
      their addresses as the keys.  */
   if (!htab)
     htab = htab_create (31, htab_hash_pointer, htab_eq_pointer, NULL);
@@ -641,25 +472,51 @@ i386_pe_section_type_flags (decl, name, reloc)
   else
     {
       if (decl && **slot != flags)
-       error_with_decl (decl, "%s causes a section type conflict");
+       error ("%q+D causes a section type conflict", decl);
     }
 
   return flags;
 }
 
 void
-i386_pe_asm_named_section (name, flags)
-     const char *name;
-     unsigned int flags;
+i386_pe_asm_named_section (const char *name, unsigned int flags, 
+                          tree decl)
 {
   char flagchars[8], *f = flagchars;
 
-  if (flags & SECTION_CODE)
-    *f++ = 'x';
-  if (flags & SECTION_WRITE)
-    *f++ = 'w';
-  if (flags & SECTION_PE_SHARED)
-    *f++ = 's';
+#if defined (HAVE_GAS_SECTION_EXCLUDE) && HAVE_GAS_SECTION_EXCLUDE == 1
+  if ((flags & SECTION_EXCLUDE) != 0)
+    *f++ = 'e';
+#endif
+
+  if ((flags & (SECTION_CODE | SECTION_WRITE)) == 0)
+    /* readonly data */
+    {
+      *f++ ='d';  /* This is necessary for older versions of gas.  */
+      *f++ ='r';
+    }
+  else 
+    {
+      if (flags & SECTION_CODE)
+        *f++ = 'x';
+      if (flags & SECTION_WRITE)
+        *f++ = 'w';
+      if (flags & SECTION_PE_SHARED)
+        *f++ = 's';
+#if !defined (HAVE_GAS_SECTION_EXCLUDE) || HAVE_GAS_SECTION_EXCLUDE == 0
+      /* If attribute "e" isn't supported we mark this section as
+         never-load.  */
+      if ((flags & SECTION_EXCLUDE) != 0)
+       *f++ = 'n';
+#endif
+    }
+
+  /* LTO sections need 1-byte alignment to avoid confusing the
+     zlib decompression algorithm with trailing zero pad bytes.  */
+  if (strncmp (name, LTO_SECTION_NAME_PREFIX,
+                       strlen (LTO_SECTION_NAME_PREFIX)) == 0)
+    *f++ = '0';
+
   *f = '\0';
 
   fprintf (asm_out_file, "\t.section\t%s,\"%s\"\n", name, flagchars);
@@ -667,12 +524,50 @@ i386_pe_asm_named_section (name, flags)
   if (flags & SECTION_LINKONCE)
     {
       /* Functions may have been compiled at various levels of
-         optimization so we can't use `same_size' here.
-         Instead, have the linker pick one.  */
+        optimization so we can't use `same_size' here.
+        Instead, have the linker pick one, without warning.
+        If 'selectany' attribute has been specified,  MS compiler
+        sets 'discard' characteristic, rather than telling linker
+        to warn of size or content mismatch, so do the same.  */ 
+      bool discard = (flags & SECTION_CODE)
+                     || lookup_attribute ("selectany",
+                                          DECL_ATTRIBUTES (decl));      
       fprintf (asm_out_file, "\t.linkonce %s\n",
-              (flags & SECTION_CODE ? "discard" : "same_size"));
+              (discard  ? "discard" : "same_size"));
     }
 }
+
+/* Beware, DECL may be NULL if compile_file() is emitting the LTO marker.  */
+
+void
+i386_pe_asm_output_aligned_decl_common (FILE *stream, tree decl,
+                                       const char *name, HOST_WIDE_INT size,
+                                       HOST_WIDE_INT align ATTRIBUTE_UNUSED)
+{
+  HOST_WIDE_INT rounded;
+
+  /* Compute as in assemble_noswitch_variable, since we don't have
+     support for aligned common on older binutils.  We must also
+     avoid emitting a common symbol of size zero, as this is the
+     overloaded representation that indicates an undefined external
+     symbol in the PE object file format.  */
+  rounded = size ? size : 1;
+  rounded += (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1;
+  rounded = (rounded / (BIGGEST_ALIGNMENT / BITS_PER_UNIT)
+            * (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
+  
+  i386_pe_maybe_record_exported_symbol (decl, name, 1);
+
+  fprintf (stream, "\t.comm\t");
+  assemble_name (stream, name);
+  if (use_pe_aligned_common)
+    fprintf (stream, ", " HOST_WIDE_INT_PRINT_DEC ", %d\n",
+          size ? size : (HOST_WIDE_INT) 1,
+          exact_log2 (align) - exact_log2 (CHAR_BIT));
+  else
+    fprintf (stream, ", " HOST_WIDE_INT_PRINT_DEC "\t" ASM_COMMENT_START
+          " " HOST_WIDE_INT_PRINT_DEC "\n", rounded, size);
+}
 \f
 /* The Microsoft linker requires that every function be marked as
    DT_FCN.  When using gas on cygwin, we must emit appropriate .type
@@ -683,31 +578,29 @@ i386_pe_asm_named_section (name, flags)
 /* Mark a function appropriately.  This should only be called for
    functions for which we are not emitting COFF debugging information.
    FILE is the assembler output file, NAME is the name of the
-   function, and PUBLIC is nonzero if the function is globally
+   function, and PUB is nonzero if the function is globally
    visible.  */
 
 void
-i386_pe_declare_function_type (file, name, public)
-     FILE *file;
-     const char *name;
-     int public;
+i386_pe_declare_function_type (FILE *file, const char *name, int pub)
 {
   fprintf (file, "\t.def\t");
   assemble_name (file, name);
   fprintf (file, ";\t.scl\t%d;\t.type\t%d;\t.endef\n",
-          public ? (int) C_EXT : (int) C_STAT,
+          pub ? (int) C_EXT : (int) C_STAT,
           (int) DT_FCN << N_BTSHFT);
 }
 
 /* Keep a list of external functions.  */
 
-struct extern_list
+struct GTY(()) extern_list
 {
   struct extern_list *next;
+  tree decl;
   const char *name;
 };
 
-static struct extern_list *extern_head;
+static GTY(()) struct extern_list *extern_head;
 
 /* Assemble an external function reference.  We need to keep a list of
    these, so that we can output the function types at the end of the
@@ -716,71 +609,147 @@ static struct extern_list *extern_head;
    for it then.  */
 
 void
-i386_pe_record_external_function (name)
-     const char *name;
+i386_pe_record_external_function (tree decl, const char *name)
 {
   struct extern_list *p;
 
-  p = (struct extern_list *) xmalloc (sizeof *p);
+  p = ggc_alloc_extern_list ();
   p->next = extern_head;
+  p->decl = decl;
   p->name = name;
   extern_head = p;
 }
 
 /* Keep a list of exported symbols.  */
 
-struct export_list
+struct GTY(()) export_list
 {
   struct export_list *next;
   const char *name;
   int is_data;         /* used to type tag exported symbols.  */
 };
 
-static struct export_list *export_head;
+static GTY(()) struct export_list *export_head;
 
 /* Assemble an export symbol entry.  We need to keep a list of
    these, so that we can output the export list at the end of the
    assembly.  We used to output these export symbols in each function,
-   but that causes problems with GNU ld when the sections are 
-   linkonce.  */
+   but that causes problems with GNU ld when the sections are
+   linkonce.  Beware, DECL may be NULL if compile_file() is emitting
+   the LTO marker.  */
 
 void
-i386_pe_record_exported_symbol (name, is_data)
-     const char *name;
-     int is_data;
+i386_pe_maybe_record_exported_symbol (tree decl, const char *name, int is_data)
 {
+  rtx symbol;
   struct export_list *p;
 
-  p = (struct export_list *) xmalloc (sizeof *p);
+  if (!decl)
+    return;
+
+  symbol = XEXP (DECL_RTL (decl), 0);
+  gcc_assert (GET_CODE (symbol) == SYMBOL_REF);
+  if (!SYMBOL_REF_DLLEXPORT_P (symbol))
+    return;
+
+  gcc_assert (TREE_PUBLIC (decl));
+
+  p = ggc_alloc_export_list ();
   p->next = export_head;
   p->name = name;
   p->is_data = is_data;
   export_head = p;
 }
 
+#ifdef CXX_WRAP_SPEC_LIST
+
+/*  Hash table equality helper function.  */
+
+static int
+wrapper_strcmp (const void *x, const void *y)
+{
+  return !strcmp ((const char *) x, (const char *) y);
+}
+
+/* Search for a function named TARGET in the list of library wrappers
+   we are using, returning a pointer to it if found or NULL if not.
+   This function might be called on quite a few symbols, and we only
+   have the list of names of wrapped functions available to us as a
+   spec string, so first time round we lazily initialise a hash table
+   to make things quicker.  */
+
+static const char *
+i386_find_on_wrapper_list (const char *target)
+{
+  static char first_time = 1;
+  static htab_t wrappers;
+
+  if (first_time)
+    {
+      /* Beware that this is not a complicated parser, it assumes
+         that any sequence of non-whitespace beginning with an
+        underscore is one of the wrapped symbols.  For now that's
+        adequate to distinguish symbols from spec substitutions
+        and command-line options.  */
+      static char wrapper_list_buffer[] = CXX_WRAP_SPEC_LIST;
+      char *bufptr;
+      /* Breaks up the char array into separated strings
+         strings and enter them into the hash table.  */
+      wrappers = htab_create_alloc (8, htab_hash_string, wrapper_strcmp,
+       0, xcalloc, free);
+      for (bufptr = wrapper_list_buffer; *bufptr; ++bufptr)
+       {
+         char *found = NULL;
+         if (ISSPACE (*bufptr))
+           continue;
+         if (*bufptr == '_')
+           found = bufptr;
+         while (*bufptr && !ISSPACE (*bufptr))
+           ++bufptr;
+         if (*bufptr)
+           *bufptr = 0;
+         if (found)
+           *htab_find_slot (wrappers, found, INSERT) = found;
+       }
+      first_time = 0;
+    }
+
+  return (const char *) htab_find (wrappers, target);
+}
+
+#endif /* CXX_WRAP_SPEC_LIST */
+
 /* This is called at the end of assembly.  For each external function
    which has not been defined, we output a declaration now.  We also
    output the .drectve section.  */
 
 void
-i386_pe_asm_file_end (file)
-     FILE *file;
+i386_pe_file_end (void)
 {
   struct extern_list *p;
 
-  ix86_asm_file_end (file);
-
   for (p = extern_head; p != NULL; p = p->next)
     {
       tree decl;
 
-      decl = get_identifier (p->name);
+      decl = p->decl;
 
       /* Positively ensure only one declaration for any given symbol.  */
-      if (! TREE_ASM_WRITTEN (decl) && TREE_SYMBOL_REFERENCED (decl))
+      if (! TREE_ASM_WRITTEN (decl)
+         && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))
        {
+#ifdef CXX_WRAP_SPEC_LIST
+         /* To ensure the DLL that provides the corresponding real
+            functions is still loaded at runtime, we must reference
+            the real function so that an (unused) import is created.  */
+         const char *realsym = i386_find_on_wrapper_list (p->name);
+         if (realsym)
+           i386_pe_declare_function_type (asm_out_file,
+               concat ("__real_", realsym, NULL), TREE_PUBLIC (decl));
+#endif /* CXX_WRAP_SPEC_LIST */
          TREE_ASM_WRITTEN (decl) = 1;
-         i386_pe_declare_function_type (file, p->name, TREE_PUBLIC (decl));
+         i386_pe_declare_function_type (asm_out_file, p->name,
+                                        TREE_PUBLIC (decl));
        }
     }
 
@@ -790,10 +759,394 @@ i386_pe_asm_file_end (file)
       drectve_section ();
       for (q = export_head; q != NULL; q = q->next)
        {
-         fprintf (file, "\t.ascii \" -export:%s%s\"\n",
-                  i386_pe_strip_name_encoding (q->name),
-                  (q->is_data) ? ",data" : "");
+         fprintf (asm_out_file, "\t.ascii \" -export:\\\"%s\\\"%s\"\n",
+                  default_strip_name_encoding (q->name),
+                  (q->is_data ? ",data" : ""));
        }
     }
 }
 
+\f
+/* x64 Structured Exception Handling unwind info.  */
+
+struct seh_frame_state
+{
+  /* SEH records saves relative to the "current" stack pointer, whether
+     or not there's a frame pointer in place.  This tracks the current
+     stack pointer offset from the CFA.  */
+  HOST_WIDE_INT sp_offset;
+
+  /* The CFA is located at CFA_REG + CFA_OFFSET.  */
+  HOST_WIDE_INT cfa_offset;
+  rtx cfa_reg;
+};
+
+/* Set up data structures beginning output for SEH.  */
+
+void
+i386_pe_seh_init (FILE *f)
+{
+  struct seh_frame_state *seh;
+
+  if (!TARGET_SEH)
+    return;
+  if (cfun->is_thunk)
+    return;
+
+  /* We cannot support DRAP with SEH.  We turned off support for it by
+     re-defining MAX_STACK_ALIGNMENT when SEH is enabled.  */
+  gcc_assert (!stack_realign_drap);
+
+  seh = XCNEW (struct seh_frame_state);
+  cfun->machine->seh = seh;
+
+  seh->sp_offset = INCOMING_FRAME_SP_OFFSET;
+  seh->cfa_offset = INCOMING_FRAME_SP_OFFSET;
+  seh->cfa_reg = stack_pointer_rtx;
+
+  fputs ("\t.seh_proc\t", f);
+  assemble_name (f, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (cfun->decl)));
+  fputc ('\n', f);
+}
+
+void
+i386_pe_seh_end_prologue (FILE *f)
+{
+  struct seh_frame_state *seh;
+
+  if (!TARGET_SEH)
+    return;
+  if (cfun->is_thunk)
+    return;
+  seh = cfun->machine->seh;
+
+  /* Emit an assembler directive to set up the frame pointer.  Always do
+     this last.  The documentation talks about doing this "before" any
+     other code that uses offsets, but (experimentally) that's after we
+     emit the codes in reverse order (handled by the assembler).  */
+  if (seh->cfa_reg != stack_pointer_rtx)
+    {
+      HOST_WIDE_INT offset = seh->sp_offset - seh->cfa_offset;
+
+      gcc_assert ((offset & 15) == 0);
+      gcc_assert (IN_RANGE (offset, 0, 240));
+
+      fputs ("\t.seh_setframe\t", f);
+      print_reg (seh->cfa_reg, 0, f);
+      fprintf (f, ", " HOST_WIDE_INT_PRINT_DEC "\n", offset);
+    }
+
+  XDELETE (seh);
+  cfun->machine->seh = NULL;
+
+  fputs ("\t.seh_endprologue\n", f);
+}
+
+static void
+i386_pe_seh_fini (FILE *f)
+{
+  if (!TARGET_SEH)
+    return;
+  if (cfun->is_thunk)
+    return;
+  fputs ("\t.seh_endproc\n", f);
+}
+
+/* Emit an assembler directive to save REG via a PUSH.  */
+
+static void
+seh_emit_push (FILE *f, struct seh_frame_state *seh, rtx reg)
+{
+  unsigned int regno = REGNO (reg);
+
+  gcc_checking_assert (GENERAL_REGNO_P (regno));
+
+  seh->sp_offset += UNITS_PER_WORD;
+  if (seh->cfa_reg == stack_pointer_rtx)
+    seh->cfa_offset += UNITS_PER_WORD;
+
+  fputs ("\t.seh_pushreg\t", f);
+  print_reg (reg, 0, f);
+  fputc ('\n', f);
+}
+
+/* Emit an assembler directive to save REG at CFA - CFA_OFFSET.  */
+
+static void
+seh_emit_save (FILE *f, struct seh_frame_state *seh,
+              rtx reg, HOST_WIDE_INT cfa_offset)
+{
+  unsigned int regno = REGNO (reg);
+  HOST_WIDE_INT offset;
+
+  /* Negative save offsets are of course not supported, since that
+     would be a store below the stack pointer and thus clobberable.  */
+  gcc_assert (seh->sp_offset >= cfa_offset);
+  offset = seh->sp_offset - cfa_offset;
+
+  fputs ((SSE_REGNO_P (regno) ? "\t.seh_savexmm\t"
+        : GENERAL_REGNO_P (regno) ?  "\t.seh_savereg\t"
+        : (gcc_unreachable (), "")), f);
+  print_reg (reg, 0, f);
+  fprintf (f, ", " HOST_WIDE_INT_PRINT_DEC "\n", offset);
+}
+
+/* Emit an assembler directive to adjust RSP by OFFSET.  */
+
+static void
+seh_emit_stackalloc (FILE *f, struct seh_frame_state *seh,
+                    HOST_WIDE_INT offset)
+{
+  /* We're only concerned with prologue stack allocations, which all
+     are subtractions from the stack pointer.  */
+  gcc_assert (offset < 0);
+  offset = -offset;
+
+  if (seh->cfa_reg == stack_pointer_rtx)
+    seh->cfa_offset += offset;
+  seh->sp_offset += offset;
+
+  fprintf (f, "\t.seh_stackalloc\t" HOST_WIDE_INT_PRINT_DEC "\n", offset);
+}
+
+/* Process REG_CFA_ADJUST_CFA for SEH.  */
+
+static void
+seh_cfa_adjust_cfa (FILE *f, struct seh_frame_state *seh, rtx pat)
+{
+  rtx dest, src;
+  HOST_WIDE_INT reg_offset = 0;
+  unsigned int dest_regno;
+
+  dest = SET_DEST (pat);
+  src = SET_SRC (pat);
+
+  if (GET_CODE (src) == PLUS)
+    {
+      reg_offset = INTVAL (XEXP (src, 1));
+      src = XEXP (src, 0);
+    }
+  else if (GET_CODE (src) == MINUS)
+    {
+      reg_offset = -INTVAL (XEXP (src, 1));
+      src = XEXP (src, 0);
+    }
+  gcc_assert (src == stack_pointer_rtx);
+  gcc_assert (seh->cfa_reg == stack_pointer_rtx);
+  dest_regno = REGNO (dest);
+
+  if (dest_regno == STACK_POINTER_REGNUM)
+    seh_emit_stackalloc (f, seh, reg_offset);
+  else if (dest_regno == HARD_FRAME_POINTER_REGNUM)
+    {
+      seh->cfa_reg = dest;
+      seh->cfa_offset -= reg_offset;
+    }
+  else
+    gcc_unreachable ();
+}
+
+/* Process REG_CFA_OFFSET for SEH.  */
+
+static void
+seh_cfa_offset (FILE *f, struct seh_frame_state *seh, rtx pat)
+{
+  rtx dest, src;
+  HOST_WIDE_INT reg_offset;
+
+  dest = SET_DEST (pat);
+  src = SET_SRC (pat);
+
+  gcc_assert (MEM_P (dest));
+  dest = XEXP (dest, 0);
+  if (REG_P (dest))
+    reg_offset = 0;
+  else
+    {
+      gcc_assert (GET_CODE (dest) == PLUS);
+      reg_offset = INTVAL (XEXP (dest, 1));
+      dest = XEXP (dest, 0);
+    }
+  gcc_assert (dest == seh->cfa_reg);
+
+  seh_emit_save (f, seh, src, seh->cfa_offset - reg_offset);
+}
+
+/* Process a FRAME_RELATED_EXPR for SEH.  */
+
+static void
+seh_frame_related_expr (FILE *f, struct seh_frame_state *seh, rtx pat)
+{
+  rtx dest, src;
+  HOST_WIDE_INT addend;
+
+  /* See the full loop in dwarf2out_frame_debug_expr.  */
+  if (GET_CODE (pat) == PARALLEL || GET_CODE (pat) == SEQUENCE)
+    {
+      int i, n = XVECLEN (pat, 0), pass, npass;
+
+      npass = (GET_CODE (pat) == PARALLEL ? 2 : 1);
+      for (pass = 0; pass < npass; ++pass)
+       for (i = 0; i < n; ++i)
+         {
+           rtx ele = XVECEXP (pat, 0, i);
+
+           if (GET_CODE (ele) != SET)
+             continue;
+           dest = SET_DEST (ele);
+
+           /* Process each member of the PARALLEL independently.  The first
+              member is always processed; others only if they are marked.  */
+           if (i == 0 || RTX_FRAME_RELATED_P (ele))
+             {
+               /* Evaluate all register saves in the first pass and all
+                  register updates in the second pass.  */
+               if ((MEM_P (dest) ^ pass) || npass == 1)
+                 seh_frame_related_expr (f, seh, ele);
+             }
+         }
+      return;
+    }
+
+  dest = SET_DEST (pat);
+  src = SET_SRC (pat);
+
+  switch (GET_CODE (dest))
+    {
+    case REG:
+      switch (GET_CODE (src))
+       {
+       case REG:
+         /* REG = REG: This should be establishing a frame pointer.  */
+         gcc_assert (src == stack_pointer_rtx);
+         gcc_assert (dest == hard_frame_pointer_rtx);
+         seh_cfa_adjust_cfa (f, seh, pat);
+         break;
+
+       case PLUS:
+         addend = INTVAL (XEXP (src, 1));
+         src = XEXP (src, 0);
+         if (dest == hard_frame_pointer_rtx)
+           seh_cfa_adjust_cfa (f, seh, pat);
+         else if (dest == stack_pointer_rtx)
+           {
+             gcc_assert (src == stack_pointer_rtx);
+             seh_emit_stackalloc (f, seh, addend);
+           }
+         else
+           gcc_unreachable ();
+         break;
+
+       default:
+         gcc_unreachable ();
+       }
+      break;
+
+    case MEM:
+      /* A save of some kind.  */
+      dest = XEXP (dest, 0);
+      if (GET_CODE (dest) == PRE_DEC)
+       {
+         gcc_checking_assert (GET_MODE (src) == Pmode);
+         gcc_checking_assert (REG_P (src));
+         seh_emit_push (f, seh, src);
+       }
+      else
+       seh_cfa_offset (f, seh, pat);
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+}
+
+/* This function looks at a single insn and emits any SEH directives
+   required for unwind of this insn.  */
+
+void
+i386_pe_seh_unwind_emit (FILE *asm_out_file, rtx insn)
+{
+  rtx note, pat;
+  bool handled_one = false;
+  struct seh_frame_state *seh;
+
+  if (!TARGET_SEH)
+    return;
+
+  /* We free the SEH data once done with the prologue.  Ignore those
+     RTX_FRAME_RELATED_P insns that are associated with the epilogue.  */
+  seh = cfun->machine->seh;
+  if (seh == NULL)
+    return;
+
+  if (NOTE_P (insn) || !RTX_FRAME_RELATED_P (insn))
+    return;
+
+  for (note = REG_NOTES (insn); note ; note = XEXP (note, 1))
+    {
+      pat = XEXP (note, 0);
+      switch (REG_NOTE_KIND (note))
+       {
+       case REG_FRAME_RELATED_EXPR:
+         goto found;
+
+       case REG_CFA_DEF_CFA:
+       case REG_CFA_EXPRESSION:
+         /* Only emitted with DRAP, which we disable.  */
+         gcc_unreachable ();
+         break;
+
+       case REG_CFA_REGISTER:
+         /* Only emitted in epilogues, which we skip.  */
+         gcc_unreachable ();
+
+       case REG_CFA_ADJUST_CFA:
+         if (pat == NULL)
+           {
+             pat = PATTERN (insn);
+             if (GET_CODE (pat) == PARALLEL)
+               pat = XVECEXP (pat, 0, 0);
+           }
+         seh_cfa_adjust_cfa (asm_out_file, seh, pat);
+         handled_one = true;
+         break;
+
+       case REG_CFA_OFFSET:
+         if (pat == NULL)
+           pat = single_set (insn);
+         seh_cfa_offset (asm_out_file, seh, pat);
+         handled_one = true;
+         break;
+
+       default:
+         break;
+       }
+    }
+  if (handled_one)
+    return;
+  pat = PATTERN (insn);
+ found:
+  seh_frame_related_expr (asm_out_file, seh, pat);
+}
+\f
+void
+i386_pe_start_function (FILE *f, const char *name, tree decl)
+{
+  i386_pe_maybe_record_exported_symbol (decl, name, 0);
+  if (write_symbols != SDB_DEBUG)
+    i386_pe_declare_function_type (f, name, TREE_PUBLIC (decl));
+  /* In case section was altered by debugging output.  */
+  if (decl != NULL_TREE)
+    switch_to_section (function_section (decl));
+  ASM_OUTPUT_FUNCTION_LABEL (f, name, decl);
+}
+
+void
+i386_pe_end_function (FILE *f, const char *name ATTRIBUTE_UNUSED,
+                     tree decl ATTRIBUTE_UNUSED)
+{
+  i386_pe_seh_fini (f);
+}
+\f
+
+#include "gt-winnt.h"