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