diff mbox

[x32] PATCH: PR middle-end/47725: [x32] error: unable to find a register to spill in class DIREG

Message ID AANLkTi=122nPerQ8L3yrqcOZp4wvMr-R=Y_OK5wVg922@mail.gmail.com
State New
Headers show

Commit Message

H.J. Lu March 29, 2011, 5:10 p.m. UTC
On Thu, Mar 24, 2011 at 8:51 AM, Eric Botcazou <ebotcazou@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.
diff mbox

Patch

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.lu@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.lu@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