Message ID | 20241110125550.787007-2-hjl.tools@gmail.com |
---|---|
State | New |
Headers | show |
Series | Improve outgoing integer argument promotion | expand |
On Sun, Nov 10, 2024 at 8:55 PM H.J. Lu <hjl.tools@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.tools@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 >
On Sun, Nov 10, 2024 at 1:55 PM H.J. Lu <hjl.tools@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.tools@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. > + > + 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)? > + 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. > + } > + > + 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. > + } > + } > + > + 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 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 >
On Wed, Nov 20, 2024 at 10:05 PM Richard Biener <richard.guenther@gmail.com> wrote: > On Sun, Nov 10, 2024 at 1:55 PM H.J. Lu <hjl.tools@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.tools@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 > > >
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; } }
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. 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.tools@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