OSDN Git Service

2010-04-09 Kai Tietz <kai.tietz@onevision.com>
[pf3gnuchains/gcc-fork.git] / gcc / config / i386 / i386.c
index 5387fae..f65220c 100644 (file)
@@ -4395,8 +4395,8 @@ ix86_function_ok_for_sibcall (tree decl, tree exp)
   return true;
 }
 
   return true;
 }
 
-/* Handle "cdecl", "stdcall", "fastcall", "regparm" and "sseregparm"
-   calling convention attributes;
+/* Handle "cdecl", "stdcall", "fastcall", "regparm", "thiscall",
+   and "sseregparm" calling convention attributes;
    arguments as in struct attribute_spec.handler.  */
 
 static tree
    arguments as in struct attribute_spec.handler.  */
 
 static tree
@@ -4426,6 +4426,11 @@ ix86_handle_cconv_attribute (tree *node, tree name,
          error ("fastcall and regparm attributes are not compatible");
        }
 
          error ("fastcall and regparm attributes are not compatible");
        }
 
+      if (lookup_attribute ("thiscall", TYPE_ATTRIBUTES (*node)))
+       {
+         error ("regparam and thiscall attributes are not compatible");
+       }
+
       cst = TREE_VALUE (args);
       if (TREE_CODE (cst) != INTEGER_CST)
        {
       cst = TREE_VALUE (args);
       if (TREE_CODE (cst) != INTEGER_CST)
        {
@@ -4471,6 +4476,10 @@ ix86_handle_cconv_attribute (tree *node, tree name,
         {
          error ("fastcall and regparm attributes are not compatible");
        }
         {
          error ("fastcall and regparm attributes are not compatible");
        }
+      if (lookup_attribute ("thiscall", TYPE_ATTRIBUTES (*node)))
+       {
+         error ("fastcall and thiscall attributes are not compatible");
+       }
     }
 
   /* Can combine stdcall with fastcall (redundant), regparm and
     }
 
   /* Can combine stdcall with fastcall (redundant), regparm and
@@ -4485,6 +4494,10 @@ ix86_handle_cconv_attribute (tree *node, tree name,
         {
          error ("stdcall and fastcall attributes are not compatible");
        }
         {
          error ("stdcall and fastcall attributes are not compatible");
        }
+      if (lookup_attribute ("thiscall", TYPE_ATTRIBUTES (*node)))
+       {
+         error ("stdcall and thiscall attributes are not compatible");
+       }
     }
 
   /* Can combine cdecl with regparm and sseregparm.  */
     }
 
   /* Can combine cdecl with regparm and sseregparm.  */
@@ -4498,6 +4511,28 @@ ix86_handle_cconv_attribute (tree *node, tree name,
         {
          error ("fastcall and cdecl attributes are not compatible");
        }
         {
          error ("fastcall and cdecl attributes are not compatible");
        }
+      if (lookup_attribute ("thiscall", TYPE_ATTRIBUTES (*node)))
+       {
+         error ("cdecl and thiscall attributes are not compatible");
+       }
+    }
+  else if (is_attribute_p ("thiscall", name))
+    {
+      if (TREE_CODE (*node) != METHOD_TYPE && pedantic)
+       warning (OPT_Wattributes, "%qE attribute is used for none class-method",
+                name);
+      if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (*node)))
+       {
+         error ("stdcall and thiscall attributes are not compatible");
+       }
+      if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (*node)))
+       {
+         error ("fastcall and thiscall attributes are not compatible");
+       }
+      if (lookup_attribute ("cdecl", TYPE_ATTRIBUTES (*node)))
+       {
+         error ("cdecl and thiscall attributes are not compatible");
+       }
     }
 
   /* Can combine sseregparm with all attributes.  */
     }
 
   /* Can combine sseregparm with all attributes.  */
@@ -4531,6 +4566,11 @@ ix86_comp_type_attributes (const_tree type1, const_tree type2)
       != !lookup_attribute ("sseregparm", TYPE_ATTRIBUTES (type2)))
     return 0;
 
       != !lookup_attribute ("sseregparm", TYPE_ATTRIBUTES (type2)))
     return 0;
 
+  /* Check for mismatched thiscall types.  */
+  if (!lookup_attribute ("thiscall", TYPE_ATTRIBUTES (type1))
+      != !lookup_attribute ("thiscall", TYPE_ATTRIBUTES (type2)))
+    return 0;
+
   /* Check for mismatched return types (cdecl vs stdcall).  */
   if (!lookup_attribute (rtdstr, TYPE_ATTRIBUTES (type1))
       != !lookup_attribute (rtdstr, TYPE_ATTRIBUTES (type2)))
   /* Check for mismatched return types (cdecl vs stdcall).  */
   if (!lookup_attribute (rtdstr, TYPE_ATTRIBUTES (type1))
       != !lookup_attribute (rtdstr, TYPE_ATTRIBUTES (type2)))
@@ -4564,6 +4604,9 @@ ix86_function_regparm (const_tree type, const_tree decl)
   if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (type)))
     return 2;
 
   if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (type)))
     return 2;
 
+  if (lookup_attribute ("thiscall", TYPE_ATTRIBUTES (type)))
+    return 1;
+
   /* Use register calling convention for local functions when possible.  */
   if (decl
       && TREE_CODE (decl) == FUNCTION_DECL
   /* Use register calling convention for local functions when possible.  */
   if (decl
       && TREE_CODE (decl) == FUNCTION_DECL
@@ -4701,7 +4744,8 @@ ix86_return_pops_args (tree fundecl, tree funtype, int size)
       /* Stdcall and fastcall functions will pop the stack if not
          variable args.  */
       if (lookup_attribute ("stdcall", 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)))
+         || lookup_attribute ("fastcall", TYPE_ATTRIBUTES (funtype))
+          || lookup_attribute ("thiscall", TYPE_ATTRIBUTES (funtype)))
        rtd = 1;
 
       if (rtd && ! stdarg_p (funtype))
        rtd = 1;
 
       if (rtd && ! stdarg_p (funtype))
@@ -4964,7 +5008,12 @@ init_cumulative_args (CUMULATIVE_ARGS *cum,  /* Argument info to initialize */
         else look for regparm information.  */
       if (fntype)
        {
         else look for regparm information.  */
       if (fntype)
        {
-         if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (fntype)))
+         if (lookup_attribute ("thiscall", TYPE_ATTRIBUTES (fntype)))
+           {
+             cum->nregs = 1;
+             cum->fastcall = 1; /* Same first register as in fastcall.  */
+           }
+         else if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (fntype)))
            {
              cum->nregs = 2;
              cum->fastcall = 1;
            {
              cum->nregs = 2;
              cum->fastcall = 1;
@@ -8303,6 +8352,8 @@ find_drap_reg (void)
          passing.  */
       if (ix86_function_regparm (TREE_TYPE (decl), decl) <= 2
          && !lookup_attribute ("fastcall",
          passing.  */
       if (ix86_function_regparm (TREE_TYPE (decl), decl) <= 2
          && !lookup_attribute ("fastcall",
+                               TYPE_ATTRIBUTES (TREE_TYPE (decl)))
+         && !lookup_attribute ("thiscall",
                                TYPE_ATTRIBUTES (TREE_TYPE (decl))))
        return CX_REG;
       else
                                TYPE_ATTRIBUTES (TREE_TYPE (decl))))
        return CX_REG;
       else
@@ -20157,6 +20208,12 @@ ix86_static_chain (const_tree fndecl, bool incoming_p)
             us with EAX for the static chain.  */
          regno = AX_REG;
        }
             us with EAX for the static chain.  */
          regno = AX_REG;
        }
+      else if (lookup_attribute ("thiscall", TYPE_ATTRIBUTES (fntype)))
+       {
+         /* Thiscall functions use ecx for arguments, which leaves
+            us with EAX for the static chain.  */
+         regno = AX_REG;
+       }
       else if (ix86_function_regparm (fntype, fndecl) == 3)
        {
          /* For regparm 3, we have no free call-clobbered registers in
       else if (ix86_function_regparm (fntype, fndecl) == 3)
        {
          /* For regparm 3, we have no free call-clobbered registers in
@@ -26124,6 +26181,11 @@ x86_this_parameter (tree function)
 
       if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (type)))
        regno = aggr ? DX_REG : CX_REG;
 
       if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (type)))
        regno = aggr ? DX_REG : CX_REG;
+      /* ???: To be verified. It is not absolutely clear how aggregates
+         have to be treated for thiscall.  We assume that they are
+        identical to fastcall.  */
+      else if (lookup_attribute ("thiscall", TYPE_ATTRIBUTES (type)))
+       regno = aggr ? DX_REG : CX_REG;
       else
         {
          regno = AX_REG;
       else
         {
          regno = AX_REG;
@@ -26235,7 +26297,9 @@ x86_output_mi_thunk (FILE *file,
        {
          int tmp_regno = CX_REG;
          if (lookup_attribute ("fastcall",
        {
          int tmp_regno = CX_REG;
          if (lookup_attribute ("fastcall",
-                               TYPE_ATTRIBUTES (TREE_TYPE (function))))
+                               TYPE_ATTRIBUTES (TREE_TYPE (function)))
+             || lookup_attribute ("thiscall",
+                                  TYPE_ATTRIBUTES (TREE_TYPE (function))))
            tmp_regno = AX_REG;
          tmp = gen_rtx_REG (SImode, tmp_regno);
        }
            tmp_regno = AX_REG;
          tmp = gen_rtx_REG (SImode, tmp_regno);
        }
@@ -28975,6 +29039,9 @@ static const struct attribute_spec ix86_attribute_table[] =
   /* Fastcall attribute says callee is responsible for popping arguments
      if they are not variable.  */
   { "fastcall",  0, 0, false, true,  true,  ix86_handle_cconv_attribute },
   /* Fastcall attribute says callee is responsible for popping arguments
      if they are not variable.  */
   { "fastcall",  0, 0, false, true,  true,  ix86_handle_cconv_attribute },
+  /* Thiscall attribute says callee is responsible for popping arguments
+     if they are not variable.  */
+  { "thiscall",  0, 0, false, true,  true,  ix86_handle_cconv_attribute },
   /* Cdecl attribute says the callee is a normal C declaration */
   { "cdecl",     0, 0, false, true,  true,  ix86_handle_cconv_attribute },
   /* Regparm attribute specifies how many integer arguments are to be
   /* Cdecl attribute says the callee is a normal C declaration */
   { "cdecl",     0, 0, false, true,  true,  ix86_handle_cconv_attribute },
   /* Regparm attribute specifies how many integer arguments are to be