On Thu, Mar 24, 2011 at 8:51 AM, Eric Botcazou <ebotca...@adacore.com> wrote:
>> Pointer is promoted to Pmode from ptr_mode.
>
> Indeed.  However the problem is the 2 in assign_parm_setup_reg:
>
>  /* Store the parm in a pseudoregister during the function, but we may
>     need to do it in a wider mode.  Using 2 here makes the result
>     consistent with promote_decl_mode and thus expand_expr_real_1.  */
>  promoted_nominal_mode
>   = promote_function_mode (data->nominal_type, data->nominal_mode, &unsignedp,
>                             TREE_TYPE (current_function_decl), 2);
>
> which is supposed to match the 2 in promote_decl_mode:
>
>  if (TREE_CODE (decl) == RESULT_DECL
>      || TREE_CODE (decl) == PARM_DECL)
>    pmode = promote_function_mode (type, mode, &unsignedp,
>                                   TREE_TYPE (current_function_decl), 2);
>  else
>    pmode = promote_mode (type, mode, &unsignedp);
>
> but doesn't match the 0 in assign_parm_find_data_types:
>
>  promoted_mode = promote_function_mode (passed_type, passed_mode, &unsignedp,
>                                         TREE_TYPE (current_function_decl), 0);
>
> so you get the redundant extension in the callee.  The solution is to define
> the promote_function_mode hook for x86 to something like:
>
> static enum machine_mode
> ix86_promote_function_mode (const_tree type,
>                            enum machine_mode mode,
>                            int *punsignedp,
>                            const_tree fntype ATTRIBUTE_UNUSED,
>                            int for_return ATTRIBUTE_UNUSED)
> {
>  if (POINTER_TYPE_P (type))
>    {
>      *punsignedp = POINTERS_EXTEND_UNSIGNED;
>      return Pmode;
>    }
>
>  return mode;
> }
>

Here is the patch.  precompute_register_parameters change is needed for

---
extern __thread int ttt;
extern void bar (void *);
void
foo1 ()
{
  bar (&ttt);
}
---

I used

/* Pointer function arguments and return values are promoted to
   Pmode.  */

static enum machine_mode
ix86_promote_function_mode (const_tree type, enum machine_mode mode,
                            int *punsignedp, const_tree fntype,
                            int for_return)
{
  if (for_return != 1 && POINTER_TYPE_P (type))
    {
      *punsignedp = POINTERS_EXTEND_UNSIGNED;
      return Pmode;
    }
  return default_promote_function_mode (type, mode, punsignedp, fntype,
                                        for_return);
}

since for_return == 1 has to match function_value, which I want to keep
as is.  default_promote_function_mode handles i386 PROMOTE_MODE.
Tested it on Linux/ia32 and Linux/x86-64.  OK for trunk?

Thanks.

-- 
H.J.
--
2011-03-29  H.J. Lu  <hongjiu...@intel.com>

        PR middle-end/47725
        PR target/48085
        * calls.c (precompute_register_parameters): Convert pointer to
        TLS symbol if needed.

        * config/i386/i386.c (ix86_promote_function_mode): New.
        (TARGET_PROMOTE_FUNCTION_MODE): Likewise.
diff --git a/gcc/ChangeLog.x32 b/gcc/ChangeLog.x32
index 303acd8..a7ff7e3 100644
--- a/gcc/ChangeLog.x32
+++ b/gcc/ChangeLog.x32
@@ -1,6 +1,16 @@
 2011-03-29  H.J. Lu  <hongjiu...@intel.com>
 
        PR middle-end/47725
+       PR target/48085
+       * calls.c (precompute_register_parameters): Convert pointer to
+       TLS symbol if needed.
+
+       * config/i386/i386.c (ix86_promote_function_mode): New.
+       (TARGET_PROMOTE_FUNCTION_MODE): Likewise.
+
+2011-03-29  H.J. Lu  <hongjiu...@intel.com>
+
+       PR middle-end/47725
        * combine.c (cant_combine_insn_p): Don't check zero/sign extended
        hard registers.
 
diff --git a/gcc/calls.c b/gcc/calls.c
index 2e79777..7357241 100644
--- a/gcc/calls.c
+++ b/gcc/calls.c
@@ -691,7 +691,13 @@ precompute_register_parameters (int num_actuals, struct 
arg_data *args,
           pseudo now.  TLS symbols sometimes need a call to resolve.  */
        if (CONSTANT_P (args[i].value)
            && !LEGITIMATE_CONSTANT_P (args[i].value))
-         args[i].value = force_reg (args[i].mode, args[i].value);
+         {
+           if (GET_MODE (args[i].value) != args[i].mode)
+             args[i].value = convert_to_mode (args[i].mode,
+                                              args[i].value,
+                                              args[i].unsignedp);
+           args[i].value = force_reg (args[i].mode, args[i].value);
+         }
 
        /* If we are to promote the function arg to a wider mode,
           do it now.  */
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index d7a5c02..6cffab2 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -7636,6 +7636,23 @@ ix86_function_value (const_tree valtype, const_tree 
fntype_or_decl,
   return ix86_function_value_1 (valtype, fntype_or_decl, orig_mode, mode);
 }
 
+/* Pointer function arguments and return values are promoted to
+   Pmode.  */
+
+static enum machine_mode
+ix86_promote_function_mode (const_tree type, enum machine_mode mode,
+                           int *punsignedp, const_tree fntype,
+                           int for_return)
+{
+  if (for_return != 1 && POINTER_TYPE_P (type))
+    {
+      *punsignedp = POINTERS_EXTEND_UNSIGNED;
+      return Pmode;
+    }
+  return default_promote_function_mode (type, mode, punsignedp, fntype,
+                                       for_return);
+}
+
 rtx
 ix86_libcall_value (enum machine_mode mode)
 {
@@ -35577,6 +35594,9 @@ ix86_autovectorize_vector_sizes (void)
 #undef TARGET_FUNCTION_VALUE_REGNO_P
 #define TARGET_FUNCTION_VALUE_REGNO_P ix86_function_value_regno_p
 
+#undef TARGET_PROMOTE_FUNCTION_MODE
+#define TARGET_PROMOTE_FUNCTION_MODE ix86_promote_function_mode
+
 #undef TARGET_SECONDARY_RELOAD
 #define TARGET_SECONDARY_RELOAD ix86_secondary_reload
 

Reply via email to