@@ -1280,6 +1280,33 @@ maybe_complain_about_tail_call (tree call_expr, const char *reason)
CALL_EXPR_MUST_TAIL_CALL (call_expr) = 0;
}
+/* Return the original integer type if ARG is copied from the incoming
+ argument. Otherwise return integer_type_node. */
+
+static tree
+get_small_int_arg_type (tree arg)
+{
+ if (TREE_CODE (arg) != SSA_NAME)
+ return integer_type_node;
+
+ if (!SSA_NAME_IS_DEFAULT_DEF (arg))
+ return integer_type_node;
+
+ tree var = SSA_NAME_VAR (arg);
+ if (TREE_CODE (var) != PARM_DECL)
+ return integer_type_node;
+ if (TYPE_MODE (TREE_TYPE (arg)) != TYPE_MODE (DECL_ARG_TYPE (var)))
+ return integer_type_node;
+
+ /* 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. */
+ return TREE_TYPE (arg);
+}
+
/* Fill in ARGS_SIZE and ARGS array based on the parameters found in
CALL_EXPR EXP.
@@ -1391,7 +1418,7 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
else if (promote_p
&& INTEGRAL_TYPE_P (type)
&& TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node))
- type = integer_type_node;
+ type = get_small_int_arg_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
new file mode 100644
@@ -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);
+}
new file mode 100644
@@ -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);
+}
new file mode 100644
@@ -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" } } */
new file mode 100644
@@ -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" } } */
new file mode 100644
@@ -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" } } */
new file mode 100644
@@ -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" } } */
new file mode 100644
@@ -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);
+}
new file mode 100644
@@ -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);
+}
new file mode 100644
@@ -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);
+}
new file mode 100644
@@ -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);
+}
new file mode 100644
@@ -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);
+}
new file mode 100644
@@ -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);
+}
new file mode 100644
@@ -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);
+}
new file mode 100644
@@ -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);
+}
new file mode 100644
@@ -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);
+}
new file mode 100644
@@ -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);
+}