On Wed, 9 Nov 2011, Richard Guenther wrote:

> 
> When we transform an indirect to a direct call or when, with LTO,
> two incompatible function declarations are merged, we can end up
> with call statements that use calling conventions according to
> a different function type than the type of the actual function
> being called.  Currently we try to make sure not to inline the
> call in such cases (because we'd ICE when trying to match up
> types for the GIMPLE checkers) - but given the recent amount of
> (ice-on-invalid) bugs I wonder whether this isn't too fragile
> (one original idea was of course that maybe details of the ABI
> make the code work in practice if not inlined, for example
> passing a double instead of a v2df in an xmm register on x86_64,
> but when inlined the program (with undefined behavior) would
> behave erratically).
> 
> Thus, the following patch simply makes sure to always create
> something that is valid GIMPLE.  For return type mismatches
> we can simply fallback to a ref-all memory read, for parameters
> (which are not always lvalues) we expand the existing handling
> to avoid generating invalid register VIEW_CONVERT_EXPRs by
> using a literal zero arg.
> 
> In both cases we apply promotion/demotion as we do not have
> properly matched up types between caller/callee in GIMPLE
> (ugh, yeah ...).
> 
> So, I'm going to bootstrap and test this, which will also
> fix PR51039 (but I have another fix for that in testing as well).
> 
> Any comments?  A final patch would remove all callers of
> the now pointless gimple_check_call_matching_types function
> and eventually remove gimple_call_cannot_inline_p and friends
> if it turns out to be unused.

I have bootstrapped and tested the patch successfully but will hold
the gimple_check_call_args change for now.  I have applied the
tree-inline.c changes as those will make sure we do not ICE when
we fail to properly not inline mismatching calls.

Richard.

> Thanks,
> Richard.
> 
> 2011-11-09  Richard Guenther  <rguent...@suse.de>
> 
>       PR tree-optimization/51039
>       * gimple-low.c (gimple_check_call_args): Remove.
>       (gimple_check_call_matching_types): Always return true.
>       * tree-inline.c (setup_one_parameter): Always perform a
>       valid gimple type change.
>       (declare_return_variable): Likewise.
> 
> Index: gcc/gimple-low.c
> ===================================================================
> *** gcc/gimple-low.c  (revision 181196)
> --- gcc/gimple-low.c  (working copy)
> *************** struct gimple_opt_pass pass_lower_cf =
> *** 208,298 ****
>   };
>   
>   
> - 
> - /* Verify if the type of the argument matches that of the function
> -    declaration.  If we cannot verify this or there is a mismatch,
> -    return false.  */
> - 
> - static bool
> - gimple_check_call_args (gimple stmt, tree fndecl)
> - {
> -   tree parms, p;
> -   unsigned int i, nargs;
> - 
> -   /* Calls to internal functions always match their signature.  */
> -   if (gimple_call_internal_p (stmt))
> -     return true;
> - 
> -   nargs = gimple_call_num_args (stmt);
> - 
> -   /* Get argument types for verification.  */
> -   if (fndecl)
> -     parms = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
> -   else
> -     parms = TYPE_ARG_TYPES (gimple_call_fntype (stmt));
> - 
> -   /* Verify if the type of the argument matches that of the function
> -      declaration.  If we cannot verify this or there is a mismatch,
> -      return false.  */
> -   if (fndecl && DECL_ARGUMENTS (fndecl))
> -     {
> -       for (i = 0, p = DECL_ARGUMENTS (fndecl);
> -        i < nargs;
> -        i++, p = DECL_CHAIN (p))
> -     {
> -       /* We cannot distinguish a varargs function from the case
> -          of excess parameters, still deferring the inlining decision
> -          to the callee is possible.  */
> -       if (!p)
> -         break;
> -       if (p == error_mark_node
> -           || gimple_call_arg (stmt, i) == error_mark_node
> -           || !fold_convertible_p (DECL_ARG_TYPE (p),
> -                                   gimple_call_arg (stmt, i)))
> -             return false;
> -     }
> -     }
> -   else if (parms)
> -     {
> -       for (i = 0, p = parms; i < nargs; i++, p = TREE_CHAIN (p))
> -     {
> -       /* If this is a varargs function defer inlining decision
> -          to callee.  */
> -       if (!p)
> -         break;
> -       if (TREE_VALUE (p) == error_mark_node
> -           || gimple_call_arg (stmt, i) == error_mark_node
> -           || TREE_CODE (TREE_VALUE (p)) == VOID_TYPE
> -           || !fold_convertible_p (TREE_VALUE (p),
> -                                   gimple_call_arg (stmt, i)))
> -             return false;
> -     }
> -     }
> -   else
> -     {
> -       if (nargs != 0)
> -         return false;
> -     }
> -   return true;
> - }
> - 
>   /* Verify if the type of the argument and lhs of CALL_STMT matches
>      that of the function declaration CALLEE.
>      If we cannot verify this or there is a mismatch, return false.  */
>   
>   bool
> ! gimple_check_call_matching_types (gimple call_stmt, tree callee)
>   {
> -   tree lhs;
> - 
> -   if ((DECL_RESULT (callee)
> -        && !DECL_BY_REFERENCE (DECL_RESULT (callee))
> -        && (lhs = gimple_call_lhs (call_stmt)) != NULL_TREE
> -        && !useless_type_conversion_p (TREE_TYPE (DECL_RESULT (callee)),
> -                                       TREE_TYPE (lhs))
> -        && !fold_convertible_p (TREE_TYPE (DECL_RESULT (callee)), lhs))
> -       || !gimple_check_call_args (call_stmt, callee))
> -     return false;
>     return true;
>   }
>   
> --- 208,221 ----
>   };
>   
>   
>   /* Verify if the type of the argument and lhs of CALL_STMT matches
>      that of the function declaration CALLEE.
>      If we cannot verify this or there is a mismatch, return false.  */
>   
>   bool
> ! gimple_check_call_matching_types (gimple call_stmt ATTRIBUTE_UNUSED,
> !                               tree callee ATTRIBUTE_UNUSED)
>   {
>     return true;
>   }
>   
> Index: gcc/tree-inline.c
> ===================================================================
> *** gcc/tree-inline.c (revision 181196)
> --- gcc/tree-inline.c (working copy)
> *************** setup_one_parameter (copy_body_data *id,
> *** 2574,2587 ****
>         && value != error_mark_node
>         && !useless_type_conversion_p (TREE_TYPE (p), TREE_TYPE (value)))
>       {
>         if (fold_convertible_p (TREE_TYPE (p), value))
> !     rhs = fold_build1 (NOP_EXPR, TREE_TYPE (p), value);
>         else
> !     /* ???  For valid (GIMPLE) programs we should not end up here.
> !        Still if something has gone wrong and we end up with truly
> !        mismatched types here, fall back to using a VIEW_CONVERT_EXPR
> !        to not leak invalid GIMPLE to the following passes.  */
> !     rhs = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (p), value);
>       }
>   
>     /* Make an equivalent VAR_DECL.  Note that we must NOT remap the type
> --- 2574,2594 ----
>         && value != error_mark_node
>         && !useless_type_conversion_p (TREE_TYPE (p), TREE_TYPE (value)))
>       {
> +       /* If we can match up types by promotion/demotion do so.  */
>         if (fold_convertible_p (TREE_TYPE (p), value))
> !     rhs = fold_convert (TREE_TYPE (p), value);
>         else
> !     {
> !       /* ???  For valid programs we should not end up here.
> !          Still if we end up with truly mismatched types here, fall back
> !          to using a VIEW_CONVERT_EXPR or a literal zero to not leak invalid
> !          GIMPLE to the following passes.  */
> !       if (!is_gimple_reg_type (TREE_TYPE (value))
> !           || TYPE_SIZE (TREE_TYPE (p)) == TYPE_SIZE (TREE_TYPE (value)))
> !         rhs = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (p), value);
> !       else
> !         rhs = build_zero_cst (TREE_TYPE (p));
> !     }
>       }
>   
>     /* Make an equivalent VAR_DECL.  Note that we must NOT remap the type
> *************** declare_return_variable (copy_body_data
> *** 2912,2918 ****
>        promoted, convert it back to the expected type.  */
>     use = var;
>     if (!useless_type_conversion_p (caller_type, TREE_TYPE (var)))
> !     use = fold_convert (caller_type, var);
>   
>     STRIP_USELESS_TYPE_CONVERSION (use);
>   
> --- 2919,2945 ----
>        promoted, convert it back to the expected type.  */
>     use = var;
>     if (!useless_type_conversion_p (caller_type, TREE_TYPE (var)))
> !     {
> !       /* If we can match up types by promotion/demotion do so.  */
> !       if (fold_convertible_p (caller_type, var))
> !     use = fold_convert (caller_type, var);
> !       else
> !     {
> !       /* ???  For valid programs we should not end up here.
> !          Still if we end up with truly mismatched types here, fall back
> !          to using a MEM_REF to not leak invalid GIMPLE to the following
> !          passes.  */
> !       /* Prevent var from being written into SSA form.  */
> !       if (TREE_CODE (TREE_TYPE (var)) == VECTOR_TYPE
> !           || TREE_CODE (TREE_TYPE (var)) == COMPLEX_TYPE)
> !         DECL_GIMPLE_REG_P (var) = false;
> !       else if (is_gimple_reg_type (TREE_TYPE (var)))
> !         TREE_ADDRESSABLE (var) = true;
> !       use = fold_build2 (MEM_REF, caller_type,
> !                          build_fold_addr_expr (var),
> !                          build_int_cst (ptr_type_node, 0));
> !     }
> !     }
>   
>     STRIP_USELESS_TYPE_CONVERSION (use);
>   
> 

-- 
Richard Guenther <rguent...@suse.de>
SUSE / SUSE Labs
SUSE LINUX Products GmbH - Nuernberg - AG Nuernberg - HRB 16746
GF: Jeff Hawn, Jennifer Guild, Felix Imendörffer

Reply via email to