On Wed, Nov 20, 2024 at 10:05 PM Richard Biener <richard.guent...@gmail.com> wrote:
> On Sun, Nov 10, 2024 at 1:55 PM H.J. Lu <hjl.to...@gmail.com> wrote: > > > > For targets, like x86, which define TARGET_PROMOTE_PROTOTYPES to return > > true, all integer arguments smaller than int are passed as int: > > > > [hjl@gnu-tgl-3 pr14907]$ cat x.c > > extern int baz (char c1); > > > > int > > foo (char c1) > > { > > return baz (c1); > > } > > [hjl@gnu-tgl-3 pr14907]$ gcc -S -O2 -m32 x.c > > [hjl@gnu-tgl-3 pr14907]$ cat x.s > > .file "x.c" > > .text > > .p2align 4 > > .globl foo > > .type foo, @function > > foo: > > .LFB0: > > .cfi_startproc > > movsbl 4(%esp), %eax > > movl %eax, 4(%esp) > > jmp baz > > .cfi_endproc > > .LFE0: > > .size foo, .-foo > > .ident "GCC: (GNU) 14.2.1 20240912 (Red Hat 14.2.1-3)" > > .section .note.GNU-stack,"",@progbits > > [hjl@gnu-tgl-3 pr14907]$ > > > > But integer promotion: > > > > movsbl 4(%esp), %eax > > movl %eax, 4(%esp) > > > > isn't necessary if incoming arguments and outgoing arguments are the > > same. Drop targetm.promote_prototypes from C, C++ and Ada frontends > > and apply targetm.promote_prototypes during RTL call expansion. > > I'm only commenting on the RTL expansion bit below (thanks for doing this > btw) > > > gcc/ > > > > PR middle-end/14907 > > * calls.cc: Include "ssa.h", "tree-ssa-live.h" and > > "tree-outof-ssa.h". > > (get_promoted_int_value_from_ssa_name): New function. > > (get_promoted_int_value): Likewise. > > (initialize_argument_information): Call get_promoted_int_value > > to promote integer function argument. > > * gimple.cc (gimple_builtin_call_types_compatible_p): Remove the > > targetm.calls.promote_prototypes call. > > * tree.cc (tree_builtin_call_types_compatible_p): Likewise. > > > > gcc/ada/ > > > > PR middle-end/14907 > > * gcc-interface/utils.cc (create_param_decl): Remove the > > targetm.calls.promote_prototypes call. > > > > gcc/c/ > > > > PR middle-end/14907 > > * c-decl.cc (start_decl): Remove the > > targetm.calls.promote_prototypes call. > > (store_parm_decls_oldstyle): Likewise. > > (finish_function): Likewise. > > * c-typeck.cc (convert_argument): Likewise. > > (c_safe_arg_type_equiv_p): Likewise. > > > > gcc/cp/ > > > > PR middle-end/14907 > > * call.cc (type_passed_as): Remove the > > targetm.calls.promote_prototypes call. > > (convert_for_arg_passing): Likewise. > > * typeck.cc (cxx_safe_arg_type_equiv_p): Likewise. > > > > gcc/testsuite/ > > > > PR middle-end/14907 > > * gcc.target/i386/pr14907-1.c: New test. > > * gcc.target/i386/pr14907-2.c: Likewise. > > * gcc.target/i386/pr14907-3.c: Likewise. > > * gcc.target/i386/pr14907-4.c: Likewise. > > * gcc.target/i386/pr14907-5.c: Likewise. > > * gcc.target/i386/pr14907-6.c: Likewise. > > * gcc.target/i386/pr14907-7.c: Likewise. > > * gcc.target/i386/pr14907-8.c: Likewise. > > * gcc.target/i386/pr14907-9.c: Likewise. > > * gcc.target/i386/pr14907-10.c: Likewise. > > * gcc.target/i386/pr14907-11.c: Likewise. > > * gcc.target/i386/pr14907-12.c: Likewise. > > * gcc.target/i386/pr14907-13.c: Likewise. > > * gcc.target/i386/pr14907-14.c: Likewise. > > * gcc.target/i386/pr14907-15.c: Likewise. > > * gcc.target/i386/pr14907-16.c: Likewise. > > * gfortran.dg/pr14907-1.f90: Likewise. > > > > Signed-off-by: H.J. Lu <hjl.to...@gmail.com> > > --- > > gcc/ada/gcc-interface/utils.cc | 24 ------- > > gcc/c/c-decl.cc | 40 ----------- > > gcc/c/c-typeck.cc | 19 ++--- > > gcc/calls.cc | 81 ++++++++++++++++++++++ > > gcc/cp/call.cc | 10 --- > > gcc/cp/typeck.cc | 13 ++-- > > gcc/gimple.cc | 10 +-- > > gcc/testsuite/gcc.target/i386/pr14907-1.c | 21 ++++++ > > gcc/testsuite/gcc.target/i386/pr14907-10.c | 23 ++++++ > > gcc/testsuite/gcc.target/i386/pr14907-11.c | 12 ++++ > > gcc/testsuite/gcc.target/i386/pr14907-12.c | 17 +++++ > > gcc/testsuite/gcc.target/i386/pr14907-13.c | 12 ++++ > > gcc/testsuite/gcc.target/i386/pr14907-14.c | 17 +++++ > > gcc/testsuite/gcc.target/i386/pr14907-15.c | 26 +++++++ > > gcc/testsuite/gcc.target/i386/pr14907-16.c | 24 +++++++ > > gcc/testsuite/gcc.target/i386/pr14907-2.c | 21 ++++++ > > gcc/testsuite/gcc.target/i386/pr14907-3.c | 21 ++++++ > > gcc/testsuite/gcc.target/i386/pr14907-4.c | 21 ++++++ > > gcc/testsuite/gcc.target/i386/pr14907-5.c | 21 ++++++ > > gcc/testsuite/gcc.target/i386/pr14907-6.c | 21 ++++++ > > gcc/testsuite/gcc.target/i386/pr14907-7.c | 22 ++++++ > > gcc/testsuite/gcc.target/i386/pr14907-8.c | 23 ++++++ > > gcc/testsuite/gcc.target/i386/pr14907-9.c | 22 ++++++ > > gcc/testsuite/gfortran.dg/pr14907-1.f90 | 17 +++++ > > gcc/tree.cc | 14 ---- > > 25 files changed, 431 insertions(+), 121 deletions(-) > > create mode 100644 gcc/testsuite/gcc.target/i386/pr14907-1.c > > create mode 100644 gcc/testsuite/gcc.target/i386/pr14907-10.c > > create mode 100644 gcc/testsuite/gcc.target/i386/pr14907-11.c > > create mode 100644 gcc/testsuite/gcc.target/i386/pr14907-12.c > > create mode 100644 gcc/testsuite/gcc.target/i386/pr14907-13.c > > create mode 100644 gcc/testsuite/gcc.target/i386/pr14907-14.c > > create mode 100644 gcc/testsuite/gcc.target/i386/pr14907-15.c > > create mode 100644 gcc/testsuite/gcc.target/i386/pr14907-16.c > > create mode 100644 gcc/testsuite/gcc.target/i386/pr14907-2.c > > create mode 100644 gcc/testsuite/gcc.target/i386/pr14907-3.c > > create mode 100644 gcc/testsuite/gcc.target/i386/pr14907-4.c > > create mode 100644 gcc/testsuite/gcc.target/i386/pr14907-5.c > > create mode 100644 gcc/testsuite/gcc.target/i386/pr14907-6.c > > create mode 100644 gcc/testsuite/gcc.target/i386/pr14907-7.c > > create mode 100644 gcc/testsuite/gcc.target/i386/pr14907-8.c > > create mode 100644 gcc/testsuite/gcc.target/i386/pr14907-9.c > > create mode 100644 gcc/testsuite/gfortran.dg/pr14907-1.f90 > > > > diff --git a/gcc/ada/gcc-interface/utils.cc > b/gcc/ada/gcc-interface/utils.cc > > index 3a571e0077b..127a83b13b6 100644 > > --- a/gcc/ada/gcc-interface/utils.cc > > +++ b/gcc/ada/gcc-interface/utils.cc > > @@ -3283,30 +3283,6 @@ tree > > create_param_decl (tree name, tree type) > > { > > tree param_decl = build_decl (input_location, PARM_DECL, name, type); > > - > > - /* Honor TARGET_PROMOTE_PROTOTYPES like the C compiler, as not doing > so > > - can lead to various ABI violations. */ > > - if (targetm.calls.promote_prototypes (NULL_TREE) > > - && INTEGRAL_TYPE_P (type) > > - && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)) > > - { > > - /* We have to be careful about biased types here. Make a subtype > > - of integer_type_node with the proper biasing. */ > > - if (TREE_CODE (type) == INTEGER_TYPE > > - && TYPE_BIASED_REPRESENTATION_P (type)) > > - { > > - tree subtype > > - = make_unsigned_type (TYPE_PRECISION (integer_type_node)); > > - TREE_TYPE (subtype) = integer_type_node; > > - TYPE_BIASED_REPRESENTATION_P (subtype) = 1; > > - SET_TYPE_RM_MIN_VALUE (subtype, TYPE_MIN_VALUE (type)); > > - SET_TYPE_RM_MAX_VALUE (subtype, TYPE_MAX_VALUE (type)); > > - type = subtype; > > - } > > - else > > - type = integer_type_node; > > - } > > - > > DECL_ARG_TYPE (param_decl) = type; > > return param_decl; > > } > > diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc > > index ac47ef24a3d..d4e87bcf420 100644 > > --- a/gcc/c/c-decl.cc > > +++ b/gcc/c/c-decl.cc > > @@ -5709,26 +5709,6 @@ start_decl (struct c_declarator *declarator, > struct c_declspecs *declspecs, > > DECL_EXTERNAL (decl) = !DECL_EXTERNAL (decl); > > } > > > > - if (TREE_CODE (decl) == FUNCTION_DECL > > - && targetm.calls.promote_prototypes (TREE_TYPE (decl))) > > - { > > - struct c_declarator *ce = declarator; > > - > > - if (ce->kind == cdk_pointer) > > - ce = declarator->declarator; > > - if (ce->kind == cdk_function) > > - { > > - tree args = ce->u.arg_info->parms; > > - for (; args; args = DECL_CHAIN (args)) > > - { > > - tree type = TREE_TYPE (args); > > - if (type && INTEGRAL_TYPE_P (type) > > - && TYPE_PRECISION (type) < TYPE_PRECISION > (integer_type_node)) > > - DECL_ARG_TYPE (args) = c_type_promotes_to (type); > > - } > > - } > > - } > > - > > if (TREE_CODE (decl) == FUNCTION_DECL > > && DECL_DECLARED_INLINE_P (decl) > > && DECL_UNINLINABLE (decl) > > @@ -11145,13 +11125,6 @@ store_parm_decls_oldstyle (tree fndecl, const > struct c_arg_info *arg_info) > > useful for argument types like uid_t. */ > > DECL_ARG_TYPE (parm) = TREE_TYPE (parm); > > > > - if (targetm.calls.promote_prototypes (TREE_TYPE > (current_function_decl)) > > - && INTEGRAL_TYPE_P (TREE_TYPE (parm)) > > - && (TYPE_PRECISION (TREE_TYPE (parm)) > > - < TYPE_PRECISION (integer_type_node))) > > - DECL_ARG_TYPE (parm) > > - = c_type_promotes_to (TREE_TYPE (parm)); > > - > > /* ??? Is it possible to get here with a > > built-in prototype or will it always have > > been diagnosed as conflicting with an > > @@ -11379,19 +11352,6 @@ finish_function (location_t end_loc) > > if (c_dialect_objc ()) > > objc_finish_function (); > > > > - if (TREE_CODE (fndecl) == FUNCTION_DECL > > - && targetm.calls.promote_prototypes (TREE_TYPE (fndecl))) > > - { > > - tree args = DECL_ARGUMENTS (fndecl); > > - for (; args; args = DECL_CHAIN (args)) > > - { > > - tree type = TREE_TYPE (args); > > - if (INTEGRAL_TYPE_P (type) > > - && TYPE_PRECISION (type) < TYPE_PRECISION > (integer_type_node)) > > - DECL_ARG_TYPE (args) = c_type_promotes_to (type); > > - } > > - } > > - > > if (DECL_INITIAL (fndecl) && DECL_INITIAL (fndecl) != error_mark_node) > > BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl; > > > > diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc > > index 201d75d2e9c..cc1ccda4424 100644 > > --- a/gcc/c/c-typeck.cc > > +++ b/gcc/c/c-typeck.cc > > @@ -4085,12 +4085,6 @@ convert_argument (location_t ploc, tree function, > tree fundecl, > > val, origtype, ic_argpass, > > npc, fundecl, function, > > parmnum + 1, warnopt); > > - > > - if (targetm.calls.promote_prototypes (fundecl ? TREE_TYPE (fundecl) : > 0) > > - && INTEGRAL_TYPE_P (type) > > - && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node))) > > - parmval = default_conversion (parmval); > > - > > return parmval; > > } > > > > @@ -6572,17 +6566,12 @@ c_safe_arg_type_equiv_p (tree t1, tree t2) > > && TREE_CODE (t2) == POINTER_TYPE) > > return true; > > > > - /* The signedness of the parameter matters only when an integral > > - type smaller than int is promoted to int, otherwise only the > > - precision of the parameter matters. > > - This check should make sure that the callee does not see > > - undefined values in argument registers. */ > > + /* Only the precision of the parameter matters. This check should > > + make sure that the callee does not see undefined values in argument > > + registers. */ > > if (INTEGRAL_TYPE_P (t1) > > && INTEGRAL_TYPE_P (t2) > > - && TYPE_PRECISION (t1) == TYPE_PRECISION (t2) > > - && (TYPE_UNSIGNED (t1) == TYPE_UNSIGNED (t2) > > - || !targetm.calls.promote_prototypes (NULL_TREE) > > - || TYPE_PRECISION (t1) >= TYPE_PRECISION (integer_type_node))) > > + && TYPE_PRECISION (t1) == TYPE_PRECISION (t2)) > > return true; > > > > return comptypes (t1, t2); > > diff --git a/gcc/calls.cc b/gcc/calls.cc > > index f67067acad4..246abe34243 100644 > > --- a/gcc/calls.cc > > +++ b/gcc/calls.cc > > @@ -62,6 +62,9 @@ along with GCC; see the file COPYING3. If not see > > #include "value-query.h" > > #include "tree-pretty-print.h" > > #include "tree-eh.h" > > +#include "ssa.h" > > +#include "tree-ssa-live.h" > > +#include "tree-outof-ssa.h" > > > > /* Like PREFERRED_STACK_BOUNDARY but in units of bytes, not bits. */ > > #define STACK_BYTES (PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT) > > @@ -1281,6 +1284,74 @@ maybe_complain_about_tail_call (tree call_expr, > const char *reason) > > CALL_EXPR_MUST_TAIL_CALL (call_expr) = 0; > > } > > > > +/* Return the integer argument promoted from TYPE to PROMOTED_TYPE if > ARG > > + isn't copied from the incoming argument. Otherwise return the > original > > + argument ORIGIN_ARG. */ > > + > > +static tree > > +get_promoted_int_value_from_ssa_name (tree type, tree promoted_type, > > + tree arg, tree orig_arg) > > +{ > > + tree var = SSA_NAME_VAR (arg); > > + if (TREE_CODE (var) != PARM_DECL > > + || TYPE_MODE (type) != TYPE_MODE (DECL_ARG_TYPE (var))) > > + return fold_convert (promoted_type, var); > > + return orig_arg; > > +} > > + > > +/* Return the promoted integer argument if ARG is smaller than int and > > + isn't copied from the incoming argument. Otherwise return the > original > > + argument. */ > > + > > +static tree > > +get_promoted_int_value (tree arg) > > +{ > > + tree type = TREE_TYPE (arg); > > + if (!INTEGRAL_TYPE_P (type) > > + || TYPE_PRECISION (type) >= TYPE_PRECISION (integer_type_node)) > > + return arg; > > + > > + tree promoted_type = (TYPE_UNSIGNED (type) > > + ? unsigned_type_node : integer_type_node); > > I think it's always integer_type_node. > Will fix it. > > > + > > + if (TREE_CODE (arg) != SSA_NAME) > > + return fold_convert (promoted_type, arg); > > + > > + if (SSA_NAME_IS_DEFAULT_DEF (arg)) > > + return get_promoted_int_value_from_ssa_name (type, promoted_type, > > + arg, arg); > > So apart from moving promotion to RTL this also seems to apply the > optimization assuming incoming arguments are promoted? But it doesn't > seem to check whether the current function is binding locally (since the > promotion isn't guaranteed by the ABI)? > We can use the incoming small integer argument type for the outgoing argument. If callee is a global function, we always properly extend the incoming small integer arguments in callee. If callee is a local function, since DECL_ARG_TYPE has the original small integer type, we will extend the incoming small integer arguments in callee if needed. > > + else > > + { > > + gimple *stmt = get_gimple_for_ssa_name (arg); > > + if (stmt == nullptr) > > + return fold_convert (promoted_type, arg); > > + > > + gassign *g = as_a<gassign *> (stmt); > > + tree_code rhs_code = gimple_assign_rhs_code (g); > > + gimple_rhs_class rhs_class = get_gimple_rhs_class (rhs_code); > > + > > + if (rhs_class == GIMPLE_SINGLE_RHS || gimple_assign_cast_p (g)) > > + { > > + tree rhs = gimple_assign_rhs1 (g); > > + if (gimple_assign_cast_p (g)) > > + { > > + tree lhs = gimple_assign_lhs (g); > > + if (!tree_nop_conversion_p (TREE_TYPE (lhs), > > + TREE_TYPE (rhs))) > > + return fold_convert (promoted_type, arg); > > Did you intend to convert 'rhs' here? Otherwise why bother with > casts at all? I think converting 'rhs' is wrong in case the conversion > was a truncation. > Will fix. > > > + } > > + > > + if (TREE_CODE (rhs) == SSA_NAME > > + && SSA_NAME_IS_DEFAULT_DEF (rhs)) > > + return get_promoted_int_value_from_ssa_name (type, > > + promoted_type, > > + rhs, arg); > > The function behaves as returning 'arg' if rhs isn't a PARM_DECL, > I think abstracting get_promoted_int_value_from_ssa_name makes > the code harder to follow than when simply inlining it twice. > > I'd have prefered to see a patch applying promote_prototypes without > optimizing more than we already do as first step. > Will fix. > > > + } > > + } > > + > > + return fold_convert (promoted_type, arg); > > +} > > + > > /* Fill in ARGS_SIZE and ARGS array based on the parameters found in > > CALL_EXPR EXP. > > > > @@ -1375,6 +1446,11 @@ initialize_argument_information (int num_actuals > ATTRIBUTE_UNUSED, > > } > > } > > > > + bool promote_p > > + = targetm.calls.promote_prototypes (fndecl > > + ? TREE_TYPE (fndecl) > > + : fntype); > > + > > /* I counts args in order (to be) pushed; ARGPOS counts in order > written. */ > > for (argpos = 0; argpos < num_actuals; i--, argpos++) > > { > > @@ -1384,6 +1460,11 @@ initialize_argument_information (int num_actuals > ATTRIBUTE_UNUSED, > > /* Replace erroneous argument with constant zero. */ > > if (type == error_mark_node || !COMPLETE_TYPE_P (type)) > > args[i].tree_value = integer_zero_node, type = integer_type_node; > > + else if (promote_p) > > + { > > + args[i].tree_value = get_promoted_int_value > (args[i].tree_value); > > + type = TREE_TYPE (args[i].tree_value); > > + } > > I would have expected to handle the promotion where we promote according > to targetm.calls.promote_function_mode, so sth as simple as > > diff --git a/gcc/calls.cc b/gcc/calls.cc > index f67067acad4..9fea9e287f3 100644 > --- a/gcc/calls.cc > +++ b/gcc/calls.cc > @@ -1524,6 +1524,11 @@ initialize_argument_information (int > num_actuals ATTRIBUTE_UNUSED, > arg.pass_by_reference = true; > } > > + if (promote_p > + && INTEGRAL_TYPE_P (type) > + && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)) > + type = integer_type_node; > + > unsignedp = TYPE_UNSIGNED (type); > arg.type = type; > arg.mode > > OTOH, this also shows that PROMOTE_PROTOTYPES might change the ABI > iff small integer types are passed differently from int. > > That said, expansion already deals with arg.type/mode being not equal to > the > actual argument. The optimization to elide a promotion would then happen > where we actually expand arg. > > I suggest you split the patch into three - honor promote_prototypes > during expand, > remove the handling from the frontends and adding the optimization to > elide the > promotion when not necessary. I do hope somebody who is more familiar with > Will do. Thanks. > calls.cc will chime in as well. > > Richard. > > > /* If TYPE is a transparent union or record, pass things the way > > we would pass the first field of the union or record. We have > > diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc > > index 220ac130b0b..8e9818538e1 100644 > > --- a/gcc/cp/call.cc > > +++ b/gcc/cp/call.cc > > @@ -9436,11 +9436,6 @@ type_passed_as (tree type) > > /* Pass classes with copy ctors by invisible reference. */ > > if (TREE_ADDRESSABLE (type)) > > type = build_reference_type (type); > > - else if (targetm.calls.promote_prototypes (NULL_TREE) > > - && INTEGRAL_TYPE_P (type) > > - && COMPLETE_TYPE_P (type) > > - && tree_int_cst_lt (TYPE_SIZE (type), TYPE_SIZE > (integer_type_node))) > > - type = integer_type_node; > > > > return type; > > } > > @@ -9476,11 +9471,6 @@ convert_for_arg_passing (tree type, tree val, > tsubst_flags_t complain) > > /* Pass classes with copy ctors by invisible reference. */ > > else if (TREE_ADDRESSABLE (type)) > > val = build1 (ADDR_EXPR, build_reference_type (type), val); > > - else if (targetm.calls.promote_prototypes (NULL_TREE) > > - && INTEGRAL_TYPE_P (type) > > - && COMPLETE_TYPE_P (type) > > - && tree_int_cst_lt (TYPE_SIZE (type), TYPE_SIZE > (integer_type_node))) > > - val = cp_perform_integral_promotions (val, complain); > > if (complain & tf_warning) > > { > > if (warn_suggest_attribute_format) > > diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc > > index 4c15e26f692..2aa5347ec1c 100644 > > --- a/gcc/cp/typeck.cc > > +++ b/gcc/cp/typeck.cc > > @@ -1373,17 +1373,12 @@ cxx_safe_arg_type_equiv_p (tree t1, tree t2) > > && TYPE_PTR_P (t2)) > > return true; > > > > - /* The signedness of the parameter matters only when an integral > > - type smaller than int is promoted to int, otherwise only the > > - precision of the parameter matters. > > - This check should make sure that the callee does not see > > - undefined values in argument registers. */ > > + /* Only the precision of the parameter matters. This check should > > + make sure that the callee does not see undefined values in argument > > + registers. */ > > if (INTEGRAL_TYPE_P (t1) > > && INTEGRAL_TYPE_P (t2) > > - && TYPE_PRECISION (t1) == TYPE_PRECISION (t2) > > - && (TYPE_UNSIGNED (t1) == TYPE_UNSIGNED (t2) > > - || !targetm.calls.promote_prototypes (NULL_TREE) > > - || TYPE_PRECISION (t1) >= TYPE_PRECISION (integer_type_node))) > > + && TYPE_PRECISION (t1) == TYPE_PRECISION (t2)) > > return true; > > > > return same_type_p (t1, t2); > > diff --git a/gcc/gimple.cc b/gcc/gimple.cc > > index f7b313be40e..9f77d77d56d 100644 > > --- a/gcc/gimple.cc > > +++ b/gcc/gimple.cc > > @@ -2843,15 +2843,7 @@ gimple_builtin_call_types_compatible_p (const > gimple *stmt, tree fndecl) > > return true; > > tree arg = gimple_call_arg (stmt, i); > > tree type = TREE_VALUE (targs); > > - if (!useless_type_conversion_p (type, TREE_TYPE (arg)) > > - /* char/short integral arguments are promoted to int > > - by several frontends if targetm.calls.promote_prototypes > > - is true. Allow such promotion too. */ > > - && !(INTEGRAL_TYPE_P (type) > > - && TYPE_PRECISION (type) < TYPE_PRECISION > (integer_type_node) > > - && targetm.calls.promote_prototypes (TREE_TYPE (fndecl)) > > - && useless_type_conversion_p (integer_type_node, > > - TREE_TYPE (arg)))) > > + if (!useless_type_conversion_p (type, TREE_TYPE (arg))) > > return false; > > targs = TREE_CHAIN (targs); > > } > > diff --git a/gcc/testsuite/gcc.target/i386/pr14907-1.c > b/gcc/testsuite/gcc.target/i386/pr14907-1.c > > new file mode 100644 > > index 00000000000..231819ed675 > > --- /dev/null > > +++ b/gcc/testsuite/gcc.target/i386/pr14907-1.c > > @@ -0,0 +1,21 @@ > > +/* { dg-do compile } */ > > +/* { dg-options "-O2 -g0" } */ > > +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ > > +/* { dg-final { check-function-bodies "x86*" "" "" { target *-*-linux* > *-*-gnu* } {^\t?\.} } } */ > > + > > +/* > > +x86*foo: > > +x86*.LFB0: > > +x86* .cfi_startproc > > +x86* jmp baz > > +x86* .cfi_endproc > > +x86*... > > +*/ > > + > > +extern int baz (char); > > + > > +int > > +foo (char c1) > > +{ > > + return baz (c1); > > +} > > diff --git a/gcc/testsuite/gcc.target/i386/pr14907-10.c > b/gcc/testsuite/gcc.target/i386/pr14907-10.c > > new file mode 100644 > > index 00000000000..099c4dc81d1 > > --- /dev/null > > +++ b/gcc/testsuite/gcc.target/i386/pr14907-10.c > > @@ -0,0 +1,23 @@ > > +/* { dg-do compile } */ > > +/* { dg-options "-O2 -g0" } */ > > +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ > > +/* { dg-final { check-function-bodies "ia32*" "" "" { target { { > *-*-linux* *-*-gnu* } && ia32 } } {^\t?\.} } } */ > > + > > +/* > > +ia32*foo: > > +ia32*.LFB0: > > +ia32* .cfi_startproc > > +ia32* movsbl 4\(%esp\), %eax > > +ia32* movl %eax, 4\(%esp\) > > +ia32* jmp baz > > +ia32* .cfi_endproc > > +ia32*... > > +*/ > > + > > +extern int baz (short); > > + > > +int > > +foo (char c1) > > +{ > > + return baz (c1); > > +} > > diff --git a/gcc/testsuite/gcc.target/i386/pr14907-11.c > b/gcc/testsuite/gcc.target/i386/pr14907-11.c > > new file mode 100644 > > index 00000000000..12ac165c298 > > --- /dev/null > > +++ b/gcc/testsuite/gcc.target/i386/pr14907-11.c > > @@ -0,0 +1,12 @@ > > +/* { dg-do compile } */ > > +/* { dg-options "-O2" } */ > > + > > +extern int baz (char, char); > > + > > +int > > +foo (char c1, char c2) > > +{ > > + return baz (c1, c2) + 1; > > +} > > + > > +/* { dg-final { scan-assembler-not "movsbl" } } */ > > diff --git a/gcc/testsuite/gcc.target/i386/pr14907-12.c > b/gcc/testsuite/gcc.target/i386/pr14907-12.c > > new file mode 100644 > > index 00000000000..6cda72ef3a2 > > --- /dev/null > > +++ b/gcc/testsuite/gcc.target/i386/pr14907-12.c > > @@ -0,0 +1,17 @@ > > +/* { dg-do compile } */ > > +/* { dg-options "-O2" } */ > > + > > +struct s > > +{ > > + char c[20]; > > +}; > > + > > +extern struct s baz (char, char); > > + > > +struct s > > +foo (char c1, char c2) > > +{ > > + return baz (c1, c2); > > +} > > + > > +/* { dg-final { scan-assembler-not "movsbl" } } */ > > diff --git a/gcc/testsuite/gcc.target/i386/pr14907-13.c > b/gcc/testsuite/gcc.target/i386/pr14907-13.c > > new file mode 100644 > > index 00000000000..b4130fdcb57 > > --- /dev/null > > +++ b/gcc/testsuite/gcc.target/i386/pr14907-13.c > > @@ -0,0 +1,12 @@ > > +/* { dg-do compile } */ > > +/* { dg-options "-O2" } */ > > + > > +extern int baz (char, char, ...); > > + > > +int > > +foo (char c1, char c2) > > +{ > > + return baz (c1, c2, 0, 0, 0, 1); > > +} > > + > > +/* { dg-final { scan-assembler-not "movsbl" } } */ > > diff --git a/gcc/testsuite/gcc.target/i386/pr14907-14.c > b/gcc/testsuite/gcc.target/i386/pr14907-14.c > > new file mode 100644 > > index 00000000000..9b8d7a7607d > > --- /dev/null > > +++ b/gcc/testsuite/gcc.target/i386/pr14907-14.c > > @@ -0,0 +1,17 @@ > > +/* { dg-do compile } */ > > +/* { dg-options "-O2" } */ > > + > > +struct s > > +{ > > + char c[20]; > > +}; > > + > > +extern struct s baz (char, char, ...); > > + > > +struct s > > +foo (char c1, char c2) > > +{ > > + return baz (c1, c2, 0, 1); > > +} > > + > > +/* { dg-final { scan-assembler-not "movsbl" } } */ > > diff --git a/gcc/testsuite/gcc.target/i386/pr14907-15.c > b/gcc/testsuite/gcc.target/i386/pr14907-15.c > > new file mode 100644 > > index 00000000000..08bc4ea9ac8 > > --- /dev/null > > +++ b/gcc/testsuite/gcc.target/i386/pr14907-15.c > > @@ -0,0 +1,26 @@ > > +/* { dg-do compile } */ > > +/* { dg-options "-O2 -g0" } */ > > +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ > > +/* { dg-final { check-function-bodies "x64*" "" "" { target { { > *-*-linux* *-*-gnu* } && { ! ia32 } } } {^\t?\.} } } */ > > + > > +/* > > +x64*foo: > > +x64*.LFB1: > > +x64* .cfi_startproc > > +x64* jmp baz > > +x64* .cfi_endproc > > +x64*... > > +*/ > > + > > + __attribute__ ((noinline)) > > +static int > > +baz (char c1) > > +{ > > + return c1; > > +} > > + > > +int > > +foo (char c1) > > +{ > > + return baz (c1); > > +} > > diff --git a/gcc/testsuite/gcc.target/i386/pr14907-16.c > b/gcc/testsuite/gcc.target/i386/pr14907-16.c > > new file mode 100644 > > index 00000000000..48c255ffb20 > > --- /dev/null > > +++ b/gcc/testsuite/gcc.target/i386/pr14907-16.c > > @@ -0,0 +1,24 @@ > > +/* { dg-do compile } */ > > +/* { dg-options "-O2 -g0" } */ > > +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ > > +/* { dg-final { check-function-bodies "x64*" "" "" { target { { > *-*-linux* *-*-gnu* } && { ! ia32 } } } {^\t?\.} } } */ > > + > > +/* > > +x64*foo: > > +x64*.LFB0: > > +x64* .cfi_startproc > > +x64* andl \$1, %edi > > +x64* jmp baz > > +x64* .cfi_endproc > > +x64*... > > +*/ > > + > > +#include <stdbool.h> > > + > > +extern int baz (bool); > > + > > +int > > +foo (int c1) > > +{ > > + return baz (c1 & 0x1); > > +} > > diff --git a/gcc/testsuite/gcc.target/i386/pr14907-2.c > b/gcc/testsuite/gcc.target/i386/pr14907-2.c > > new file mode 100644 > > index 00000000000..5da7b029279 > > --- /dev/null > > +++ b/gcc/testsuite/gcc.target/i386/pr14907-2.c > > @@ -0,0 +1,21 @@ > > +/* { dg-do compile } */ > > +/* { dg-options "-O2 -g0" } */ > > +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ > > +/* { dg-final { check-function-bodies "x86*" "" "" { target *-*-linux* > *-*-gnu* } {^\t?\.} } } */ > > + > > +/* > > +x86*foo: > > +x86*.LFB0: > > +x86* .cfi_startproc > > +x86* jmp baz > > +x86* .cfi_endproc > > +x86*... > > +*/ > > + > > +extern int baz (int, int, int, int, int, int, char, char); > > + > > +int > > +foo (int a1, int a2, int a3, int a4, int a5, int a6, char c1, char c2) > > +{ > > + return baz (a1, a2, a3, a4, a5, a6, c1, c2); > > +} > > diff --git a/gcc/testsuite/gcc.target/i386/pr14907-3.c > b/gcc/testsuite/gcc.target/i386/pr14907-3.c > > new file mode 100644 > > index 00000000000..a8fb13f28f8 > > --- /dev/null > > +++ b/gcc/testsuite/gcc.target/i386/pr14907-3.c > > @@ -0,0 +1,21 @@ > > +/* { dg-do compile } */ > > +/* { dg-options "-O2 -g0" } */ > > +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ > > +/* { dg-final { check-function-bodies "x86*" "" "" { target *-*-linux* > *-*-gnu* } {^\t?\.} } } */ > > + > > +/* > > +x86*c1: > > +x86*.LFB0: > > +x86* .cfi_startproc > > +x86* jmp c2 > > +x86* .cfi_endproc > > +x86*... > > +*/ > > + > > +extern char c2 (char); > > + > > +char > > +c1 (char c) > > +{ > > + return c2 (c); > > +} > > diff --git a/gcc/testsuite/gcc.target/i386/pr14907-4.c > b/gcc/testsuite/gcc.target/i386/pr14907-4.c > > new file mode 100644 > > index 00000000000..b5fb92fefcc > > --- /dev/null > > +++ b/gcc/testsuite/gcc.target/i386/pr14907-4.c > > @@ -0,0 +1,21 @@ > > +/* { dg-do compile } */ > > +/* { dg-options "-O2 -g0" } */ > > +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ > > +/* { dg-final { check-function-bodies "x86*" "" "" { target *-*-linux* > *-*-gnu* } {^\t?\.} } } */ > > + > > +/* > > +x86*foo: > > +x86*.LFB0: > > +x86* .cfi_startproc > > +x86* jmp baz > > +x86* .cfi_endproc > > +x86*... > > +*/ > > + > > +extern int baz (short); > > + > > +int > > +foo (short c1) > > +{ > > + return baz (c1); > > +} > > diff --git a/gcc/testsuite/gcc.target/i386/pr14907-5.c > b/gcc/testsuite/gcc.target/i386/pr14907-5.c > > new file mode 100644 > > index 00000000000..d9abb5c8cfb > > --- /dev/null > > +++ b/gcc/testsuite/gcc.target/i386/pr14907-5.c > > @@ -0,0 +1,21 @@ > > +/* { dg-do compile } */ > > +/* { dg-options "-O2 -g0" } */ > > +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ > > +/* { dg-final { check-function-bodies "x86*" "" "" { target *-*-linux* > *-*-gnu* } {^\t?\.} } } */ > > + > > +/* > > +x86*foo: > > +x86*.LFB0: > > +x86* .cfi_startproc > > +x86* jmp baz > > +x86* .cfi_endproc > > +x86*... > > +*/ > > + > > +extern int baz (int, int, int, int, int, int, short, short); > > + > > +int > > +foo (int a1, int a2, int a3, int a4, int a5, int a6, short c1, short c2) > > +{ > > + return baz (a1, a2, a3, a4, a5, a6, c1, c2); > > +} > > diff --git a/gcc/testsuite/gcc.target/i386/pr14907-6.c > b/gcc/testsuite/gcc.target/i386/pr14907-6.c > > new file mode 100644 > > index 00000000000..b6d0183656a > > --- /dev/null > > +++ b/gcc/testsuite/gcc.target/i386/pr14907-6.c > > @@ -0,0 +1,21 @@ > > +/* { dg-do compile } */ > > +/* { dg-options "-O2 -g0" } */ > > +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ > > +/* { dg-final { check-function-bodies "x86*" "" "" { target *-*-linux* > *-*-gnu* } {^\t?\.} } } */ > > + > > +/* > > +x86*c1: > > +x86*.LFB0: > > +x86* .cfi_startproc > > +x86* jmp c2 > > +x86* .cfi_endproc > > +x86*... > > +*/ > > + > > +extern short c2 (short); > > + > > +short > > +c1 (short c) > > +{ > > + return c2 (c); > > +} > > diff --git a/gcc/testsuite/gcc.target/i386/pr14907-7.c > b/gcc/testsuite/gcc.target/i386/pr14907-7.c > > new file mode 100644 > > index 00000000000..fbf511f691e > > --- /dev/null > > +++ b/gcc/testsuite/gcc.target/i386/pr14907-7.c > > @@ -0,0 +1,22 @@ > > +/* { dg-do compile } */ > > +/* { dg-options "-O2 -g0" } */ > > +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ > > +/* { dg-final { check-function-bodies "x64*" "" "" { target { { > *-*-linux* *-*-gnu* } && { ! ia32 } } } {^\t?\.} } } */ > > + > > +/* > > +x64*foo: > > +x64*.LFB0: > > +x64* .cfi_startproc > > +x64* movsbl %dil, %edi > > +x64* jmp baz > > +x64* .cfi_endproc > > +x64*... > > +*/ > > + > > +extern int baz (int); > > + > > +int > > +foo (char c1) > > +{ > > + return baz (c1); > > +} > > diff --git a/gcc/testsuite/gcc.target/i386/pr14907-8.c > b/gcc/testsuite/gcc.target/i386/pr14907-8.c > > new file mode 100644 > > index 00000000000..7d2611398c0 > > --- /dev/null > > +++ b/gcc/testsuite/gcc.target/i386/pr14907-8.c > > @@ -0,0 +1,23 @@ > > +/* { dg-do compile } */ > > +/* { dg-options "-O2 -g0" } */ > > +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ > > +/* { dg-final { check-function-bodies "ia32*" "" "" { target { { > *-*-linux* *-*-gnu* } && ia32 } } {^\t?\.} } } */ > > + > > +/* > > +ia32*foo: > > +ia32*.LFB0: > > +ia32* .cfi_startproc > > +ia32* movsbl 4\(%esp\), %eax > > +ia32* movl %eax, 4\(%esp\) > > +ia32* jmp baz > > +ia32* .cfi_endproc > > +ia32*... > > +*/ > > + > > +extern int baz (int); > > + > > +int > > +foo (char c1) > > +{ > > + return baz (c1); > > +} > > diff --git a/gcc/testsuite/gcc.target/i386/pr14907-9.c > b/gcc/testsuite/gcc.target/i386/pr14907-9.c > > new file mode 100644 > > index 00000000000..a22383694bf > > --- /dev/null > > +++ b/gcc/testsuite/gcc.target/i386/pr14907-9.c > > @@ -0,0 +1,22 @@ > > +/* { dg-do compile } */ > > +/* { dg-options "-O2 -g0" } */ > > +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ > > +/* { dg-final { check-function-bodies "x64*" "" "" { target { { > *-*-linux* *-*-gnu* } && { ! ia32 } } } {^\t?\.} } } */ > > + > > +/* > > +x64*foo: > > +x64*.LFB0: > > +x64* .cfi_startproc > > +x64* movsbl %dil, %edi > > +x64* jmp baz > > +x64* .cfi_endproc > > +x64*... > > +*/ > > + > > +extern int baz (short); > > + > > +int > > +foo (char c1) > > +{ > > + return baz (c1); > > +} > > diff --git a/gcc/testsuite/gfortran.dg/pr14907-1.f90 > b/gcc/testsuite/gfortran.dg/pr14907-1.f90 > > new file mode 100644 > > index 00000000000..5e41cd6f54f > > --- /dev/null > > +++ b/gcc/testsuite/gfortran.dg/pr14907-1.f90 > > @@ -0,0 +1,17 @@ > > +! { dg-do compile } > > +! { dg-options "-Os" } > > + > > +program test > > + use iso_c_binding, only: c_short > > + interface > > + subroutine foo(a) bind(c) > > + import c_short > > + integer(kind=c_short), intent(in), value :: a > > + end subroutine foo > > + end interface > > + integer(kind=c_short) a(5); > > + call foo (a(3)) > > +end > > + > > +! { dg-final { scan-assembler "movswl\t10\\(%rsp\\), %edi" { target { { > *-*-linux* *-*-gnu* } && { ! ia32 } } } } } > > +! { dg-final { scan-assembler "movswl\t-14\\(%ebp\\), %eax" { target { > { *-*-linux* *-*-gnu* } && { ia32 } } } } } > > diff --git a/gcc/tree.cc b/gcc/tree.cc > > index b4c059d3b0d..2c3bf27a678 100644 > > --- a/gcc/tree.cc > > +++ b/gcc/tree.cc > > @@ -8676,20 +8676,6 @@ tree_builtin_call_types_compatible_p (const_tree > call, tree fndecl) > > && POINTER_TYPE_P (TREE_TYPE (arg)) > > && tree_nop_conversion_p (type, TREE_TYPE (arg))) > > continue; > > - /* char/short integral arguments are promoted to int > > - by several frontends if targetm.calls.promote_prototypes > > - is true. Allow such promotion too. */ > > - if (INTEGRAL_TYPE_P (type) > > - && TYPE_PRECISION (type) < TYPE_PRECISION > (integer_type_node) > > - && INTEGRAL_TYPE_P (TREE_TYPE (arg)) > > - && !TYPE_UNSIGNED (TREE_TYPE (arg)) > > - && targetm.calls.promote_prototypes (TREE_TYPE (fndecl)) > > - && (gimple_form > > - ? useless_type_conversion_p (integer_type_node, > > - TREE_TYPE (arg)) > > - : tree_nop_conversion_p (integer_type_node, > > - TREE_TYPE (arg)))) > > - continue; > > return false; > > } > > } > > -- > > 2.47.0 > > > -- H.J.