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 <[email protected]>
---
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