OSDN Git Service

2010-04-09 Kai Tietz <kai.tietz@onevision.com>
[pf3gnuchains/gcc-fork.git] / gcc / config / i386 / i386.c
index da2a981..f65220c 100644 (file)
@@ -4395,8 +4395,8 @@ ix86_function_ok_for_sibcall (tree decl, tree exp)
   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
@@ -4426,6 +4426,11 @@ ix86_handle_cconv_attribute (tree *node, tree name,
          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)
        {
@@ -4447,7 +4452,8 @@ ix86_handle_cconv_attribute (tree *node, tree name,
   if (TARGET_64BIT)
     {
       /* Do not warn when emulating the MS ABI.  */
-      if (TREE_CODE (*node) != FUNCTION_TYPE
+      if ((TREE_CODE (*node) != FUNCTION_TYPE
+          && TREE_CODE (*node) != METHOD_TYPE)
          || ix86_function_type_abi (*node) != MS_ABI)
        warning (OPT_Wattributes, "%qE attribute ignored",
                 name);
@@ -4470,6 +4476,10 @@ ix86_handle_cconv_attribute (tree *node, tree name,
         {
          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
@@ -4484,6 +4494,10 @@ ix86_handle_cconv_attribute (tree *node, tree name,
         {
          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.  */
@@ -4497,6 +4511,28 @@ ix86_handle_cconv_attribute (tree *node, tree name,
         {
          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.  */
@@ -4530,6 +4566,11 @@ ix86_comp_type_attributes (const_tree type1, const_tree type2)
       != !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)))
@@ -4563,6 +4604,9 @@ ix86_function_regparm (const_tree type, const_tree decl)
   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
@@ -4700,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))
-          || 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))
@@ -4963,7 +5008,12 @@ init_cumulative_args (CUMULATIVE_ARGS *cum,  /* Argument info to initialize */
         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;
@@ -7614,6 +7664,7 @@ ix86_code_end (void)
          assemble_name (asm_out_file, name);
          fputs ("\n", asm_out_file);
          ASM_OUTPUT_LABEL (asm_out_file, name);
+         DECL_WEAK (decl) = 1;
        }
       else
 #endif
@@ -7639,6 +7690,7 @@ ix86_code_end (void)
       DECL_INITIAL (decl) = make_node (BLOCK);
       current_function_decl = decl;
       init_function_start (decl);
+      first_function_block_is_cold = false;
       /* Make sure unwind info is emitted for the thunk if needed.  */
       final_start_function (emit_barrier (), asm_out_file, 1);
 
@@ -8300,6 +8352,8 @@ find_drap_reg (void)
          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
@@ -8626,13 +8680,10 @@ ix86_expand_prologue (void)
                               ix86_cfa_state->reg == stack_pointer_rtx);
   else
     {
-      /* Only valid for Win32.  */
       rtx eax = gen_rtx_REG (Pmode, AX_REG);
       bool eax_live;
       rtx t;
 
-      gcc_assert (!TARGET_64BIT || cfun->machine->call_abi == MS_ABI);
-
       if (cfun->machine->call_abi == MS_ABI)
        eax_live = false;
       else
@@ -11391,7 +11442,6 @@ get_some_local_dynamic_name (void)
    L,W,B,Q,S,T -- print the opcode suffix for specified size of operand.
    C -- print opcode suffix for set/cmov insn.
    c -- like C, but print reversed condition
-   E,e -- likewise, but for compare-and-branch fused insn.
    F,f -- likewise, but for floating-point.
    O -- if HAVE_AS_IX86_CMOV_SUN_SYNTAX, expand to "w.", "l." or "q.",
         otherwise nothing
@@ -11796,14 +11846,6 @@ print_operand (FILE *file, rtx x, int code)
          put_condition_code (GET_CODE (x), GET_MODE (XEXP (x, 0)), 1, 1, file);
          return;
 
-       case 'E':
-         put_condition_code (GET_CODE (x), CCmode, 0, 0, file);
-         return;
-
-       case 'e':
-         put_condition_code (GET_CODE (x), CCmode, 1, 0, file);
-         return;
-
        case 'H':
          /* It doesn't actually matter what mode we use here, as we're
             only going to use this for printing.  */
@@ -20166,6 +20208,12 @@ ix86_static_chain (const_tree fndecl, bool incoming_p)
             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
@@ -22482,10 +22530,10 @@ static const struct builtin_description bdesc_multi_arg[] =
   { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pcom_tfv4si3,      "__builtin_ia32_vpcomtrueud", IX86_BUILTIN_VPCOMTRUEUD, (enum rtx_code) PCOM_TRUE,    (int)MULTI_ARG_2_SI_TF },
   { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pcom_tfv2di3,      "__builtin_ia32_vpcomtrueuq", IX86_BUILTIN_VPCOMTRUEUQ, (enum rtx_code) PCOM_TRUE,    (int)MULTI_ARG_2_DI_TF },
 
-  { OPTION_MASK_ISA_AVX, CODE_FOR_xop_vpermil2v2df3,     "__builtin_ia32_vpermil2pd",  IX86_BUILTIN_VPERMIL2PD, UNKNOWN, (int)MULTI_ARG_4_DF2_DI_I },
-  { OPTION_MASK_ISA_AVX, CODE_FOR_xop_vpermil2v4sf3,     "__builtin_ia32_vpermil2ps",  IX86_BUILTIN_VPERMIL2PS, UNKNOWN, (int)MULTI_ARG_4_SF2_SI_I },
-  { OPTION_MASK_ISA_AVX, CODE_FOR_xop_vpermil2v4df3,     "__builtin_ia32_vpermil2pd256", IX86_BUILTIN_VPERMIL2PD256, UNKNOWN, (int)MULTI_ARG_4_DF2_DI_I1 },
-  { OPTION_MASK_ISA_AVX, CODE_FOR_xop_vpermil2v8sf3,     "__builtin_ia32_vpermil2ps256", IX86_BUILTIN_VPERMIL2PS256, UNKNOWN, (int)MULTI_ARG_4_SF2_SI_I1 },
+  { OPTION_MASK_ISA_XOP, CODE_FOR_xop_vpermil2v2df3,     "__builtin_ia32_vpermil2pd",  IX86_BUILTIN_VPERMIL2PD, UNKNOWN, (int)MULTI_ARG_4_DF2_DI_I },
+  { OPTION_MASK_ISA_XOP, CODE_FOR_xop_vpermil2v4sf3,     "__builtin_ia32_vpermil2ps",  IX86_BUILTIN_VPERMIL2PS, UNKNOWN, (int)MULTI_ARG_4_SF2_SI_I },
+  { OPTION_MASK_ISA_XOP, CODE_FOR_xop_vpermil2v4df3,     "__builtin_ia32_vpermil2pd256", IX86_BUILTIN_VPERMIL2PD256, UNKNOWN, (int)MULTI_ARG_4_DF2_DI_I1 },
+  { OPTION_MASK_ISA_XOP, CODE_FOR_xop_vpermil2v8sf3,     "__builtin_ia32_vpermil2ps256", IX86_BUILTIN_VPERMIL2PS256, UNKNOWN, (int)MULTI_ARG_4_SF2_SI_I1 },
 
 };
 
@@ -23640,10 +23688,10 @@ ix86_expand_args_builtin (const struct builtin_description *d,
       nargs = 3;
       nargs_constant = 2;
       break;
-    case MULTI_ARG_4_DF2_DI_I:
-    case MULTI_ARG_4_DF2_DI_I1:
-    case MULTI_ARG_4_SF2_SI_I:
-    case MULTI_ARG_4_SF2_SI_I1:
+    case V2DF_FTYPE_V2DF_V2DF_V2DI_INT:
+    case V4DF_FTYPE_V4DF_V4DF_V4DI_INT:
+    case V4SF_FTYPE_V4SF_V4SF_V4SI_INT:
+    case V8SF_FTYPE_V8SF_V8SF_V8SI_INT:
       nargs = 4;
       nargs_constant = 1;
       break;
@@ -24376,14 +24424,16 @@ ix86_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
    if it is not available.  */
 
 static tree
-ix86_builtin_vectorized_function (unsigned int fn, tree type_out,
+ix86_builtin_vectorized_function (tree fndecl, tree type_out,
                                  tree type_in)
 {
   enum machine_mode in_mode, out_mode;
   int in_n, out_n;
+  enum built_in_function fn = DECL_FUNCTION_CODE (fndecl);
 
   if (TREE_CODE (type_out) != VECTOR_TYPE
-      || TREE_CODE (type_in) != VECTOR_TYPE)
+      || TREE_CODE (type_in) != VECTOR_TYPE
+      || DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL)
     return NULL_TREE;
 
   out_mode = TYPE_MODE (TREE_TYPE (type_out));
@@ -26131,6 +26181,11 @@ x86_this_parameter (tree function)
 
       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;
@@ -26210,10 +26265,7 @@ x86_output_mi_thunk (FILE *file,
   /* Adjust the this parameter by a fixed constant.  */
   if (delta)
     {
-      /* Make things pretty and `subl $4,%eax' rather than `addl $-4,%eax'.
-         Exceptions: -128 encodes smaller than 128, so swap sign and op.  */
-      bool sub = delta < 0 || delta == 128;
-      xops[0] = GEN_INT (sub ? -delta : delta);
+      xops[0] = GEN_INT (delta);
       xops[1] = this_reg ? this_reg : this_param;
       if (TARGET_64BIT)
        {
@@ -26225,12 +26277,12 @@ x86_output_mi_thunk (FILE *file,
              xops[0] = tmp;
              xops[1] = this_param;
            }
-         if (sub)
+         if (x86_maybe_negate_const_int (&xops[0], DImode))
            output_asm_insn ("sub{q}\t{%0, %1|%1, %0}", xops);
          else
            output_asm_insn ("add{q}\t{%0, %1|%1, %0}", xops);
        }
-      else if (sub)
+      else if (x86_maybe_negate_const_int (&xops[0], SImode))
        output_asm_insn ("sub{l}\t{%0, %1|%1, %0}", xops);
       else
        output_asm_insn ("add{l}\t{%0, %1|%1, %0}", xops);
@@ -26245,7 +26297,9 @@ x86_output_mi_thunk (FILE *file,
        {
          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);
        }
@@ -26657,6 +26711,52 @@ x86_extended_reg_mentioned_p (rtx insn)
                       extended_reg_mentioned_1, NULL);
 }
 
+/* If profitable, negate (without causing overflow) integer constant
+   of mode MODE at location LOC.  Return true in this case.  */
+bool
+x86_maybe_negate_const_int (rtx *loc, enum machine_mode mode)
+{
+  HOST_WIDE_INT val;
+
+  if (!CONST_INT_P (*loc))
+    return false;
+
+  switch (mode)
+    {
+    case DImode:
+      /* DImode x86_64 constants must fit in 32 bits.  */
+      gcc_assert (x86_64_immediate_operand (*loc, mode));
+
+      mode = SImode;
+      break;
+
+    case SImode:
+    case HImode:
+    case QImode:
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  /* Avoid overflows.  */
+  if (mode_signbit_p (mode, *loc))
+    return false;
+
+  val = INTVAL (*loc);
+
+  /* Make things pretty and `subl $4,%eax' rather than `addl $-4,%eax'.
+     Exceptions: -128 encodes smaller than 128, so swap sign and op.  */
+  if ((val < 0 && val != -128)
+      || val == 128)
+    {
+      *loc = GEN_INT (-val);
+      return true;
+    }
+
+  return false;
+}
+
 /* Generate an unsigned DImode/SImode to FP conversion.  This is the same code
    optabs would emit if we didn't have TFmode patterns.  */
 
@@ -28939,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 },
+  /* 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