On Sun, Nov 10, 2024 at 8: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.
PING. > 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); > + > + 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); > + 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); > + } > + > + 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); > + } > + } > + > + 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); > + } > > /* 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.