> 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; } -- Eric Botcazou