On Mon, Aug 25, 2025 at 5:59 AM H.J. Lu <hjl.to...@gmail.com> wrote: > > On Fri, Jun 27, 2025 at 05:53:57AM +0800, H.J. Lu wrote: > > Here is the v3 patch. The difference from v2 is to use > > > > if (MEM_P (src) > > && MEM_EXPR (src) > > && (TREE_CODE (get_base_address (MEM_EXPR (src))) > > == PARM_DECL)) > > continue; > > > > to check incoming arguments on stack. > > > > OK for master? > > > > Thanks. > > > > I forgot to include the patch. Here it is. OK for master? > > Thanks. > > H.J. > --- > 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 are copied to outgoing arguments > directly. > > We can use the incoming argument value as the outgoing argument as if it > has been promoted if > > 1. Caller and callee are not nested functions. > 2. Caller and callee have the same incoming argument order. Add a new > target hook, TARGET_SAME_FUNCTION_ARGUMENT_ORDER_P, which returns true > if caller and callee have the same incoming argument order. If the > incoming argument order of the caller is different from the incoming > argument order of the callee since the same register may be used for > different incoming arguments in caller and callee. Copying from one > incoming argument register in the caller to an outgoing argument may > override another incoming argument register. > 3. The incoming argument is unchanged before call expansion. > > Otherwise, using the incoming argument as the outgoing argument may change > values of other incoming arguments or the wrong outgoing argument value > may be used. > > 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. > > Tested on x86-64, x32 and i686. > > NB: I tried to elide all incoming argument copying for all types, not > just integer arguments smaller than int. But GCC was miscompiled which > is related to function inlining. There is > > foo > call baz > > bar > call foo > > when foo is inlined > > bar > call baz > > the incoming arguments, which aren't integer arguments smaller than int, > for baz get the wrong values sometimes. > > gcc/ > > PR middle-end/14907 > * calls.cc (arg_data): Add incoming_argument_value. > (precompute_register_parameters): Set args[i].value to > args[i].incoming_argument_value if not nullptr. > (get_incoming_argument_value): New function. > (initialize_argument_information): Set > args[i].incoming_argument_value with get_incoming_argument_value. > (store_one_arg): Set arg->value to arg->incoming_argument_value > if not nullptr. > * function.h (function): Add before_first_expand_call and > no_incoming_argument_value. > * target.def (same_incoming_argument_order_p): New target hook > for calls. > * config/i386/i386.cc (ix86_same_incoming_argument_order_p): New. > (TARGET_SAME_FUNCTION_ARGUMENT_ORDER_P): Likewise. > * doc/tm.texi: Regenerated. > * doc/tm.texi.in (TARGET_SAME_FUNCTION_ARGUMENT_ORDER_P): New hook. > > gcc/testsuite/ > > PR middle-end/14907 > * gcc.dg/elide-1a.c: New test. > * gcc.dg/elide-1b.c: Likewise. > * gcc.dg/elide-2a.c: Likewise. > * gcc.dg/elide-2b.c: Likewise. > * gcc.target/i386/pr14907-1.c: Likewise. > * 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-7a.c: Likewise. > * gcc.target/i386/pr14907-7b.c: Likewise. > * gcc.target/i386/pr14907-8a.c: Likewise. > * gcc.target/i386/pr14907-8b.c: Likewise. > * gcc.target/i386/pr14907-9a.c: Likewise. > * gcc.target/i386/pr14907-9b.c: Likewise. > * gcc.target/i386/pr14907-10a.c: Likewise. > * gcc.target/i386/pr14907-10b.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. > * gcc.target/i386/pr14907-17.c: Likewise. > * gcc.target/i386/pr14907-18.c: Likewise. > * gcc.target/i386/pr14907-19.c: Likewise. > * gcc.target/i386/pr14907-20a.c: Likewise. > * gcc.target/i386/pr14907-20b.c: Likewise. > * gcc.target/i386/pr14907-21.c: Likewise. > * gcc.target/i386/pr14907-22.c: Likewise. > * gcc.target/i386/pr14907-23.c: Likewise. > > Signed-off-by: H.J. Lu <hjl.to...@gmail.com> > --- > gcc/calls.cc | 212 ++++++++++++++++++-- > gcc/config/i386/i386.cc | 16 ++ > gcc/doc/tm.texi | 6 + > gcc/doc/tm.texi.in | 2 + > gcc/function.h | 7 + > gcc/target.def | 8 + > gcc/testsuite/gcc.dg/elide-1a.c | 10 + > gcc/testsuite/gcc.dg/elide-1b.c | 26 +++ > gcc/testsuite/gcc.dg/elide-2a.c | 12 ++ > gcc/testsuite/gcc.dg/elide-2b.c | 30 +++ > gcc/testsuite/gcc.target/i386/pr14907-1.c | 21 ++ > gcc/testsuite/gcc.target/i386/pr14907-10a.c | 24 +++ > gcc/testsuite/gcc.target/i386/pr14907-10b.c | 20 ++ > 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-17.c | 28 +++ > gcc/testsuite/gcc.target/i386/pr14907-18.c | 24 +++ > gcc/testsuite/gcc.target/i386/pr14907-19.c | 26 +++ > gcc/testsuite/gcc.target/i386/pr14907-2.c | 21 ++ > gcc/testsuite/gcc.target/i386/pr14907-20a.c | 27 +++ > gcc/testsuite/gcc.target/i386/pr14907-20b.c | 23 +++ > gcc/testsuite/gcc.target/i386/pr14907-21.c | 28 +++ > gcc/testsuite/gcc.target/i386/pr14907-22.c | 28 +++ > gcc/testsuite/gcc.target/i386/pr14907-23.c | 11 + > 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-7a.c | 22 ++ > gcc/testsuite/gcc.target/i386/pr14907-7b.c | 17 ++ > gcc/testsuite/gcc.target/i386/pr14907-8a.c | 22 ++ > gcc/testsuite/gcc.target/i386/pr14907-8b.c | 17 ++ > gcc/testsuite/gcc.target/i386/pr14907-9a.c | 24 +++ > gcc/testsuite/gcc.target/i386/pr14907-9b.c | 19 ++ > 38 files changed, 906 insertions(+), 17 deletions(-) > create mode 100644 gcc/testsuite/gcc.dg/elide-1a.c > create mode 100644 gcc/testsuite/gcc.dg/elide-1b.c > create mode 100644 gcc/testsuite/gcc.dg/elide-2a.c > create mode 100644 gcc/testsuite/gcc.dg/elide-2b.c > create mode 100644 gcc/testsuite/gcc.target/i386/pr14907-1.c > create mode 100644 gcc/testsuite/gcc.target/i386/pr14907-10a.c > create mode 100644 gcc/testsuite/gcc.target/i386/pr14907-10b.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-17.c > create mode 100644 gcc/testsuite/gcc.target/i386/pr14907-18.c > create mode 100644 gcc/testsuite/gcc.target/i386/pr14907-19.c > create mode 100644 gcc/testsuite/gcc.target/i386/pr14907-2.c > create mode 100644 gcc/testsuite/gcc.target/i386/pr14907-20a.c > create mode 100644 gcc/testsuite/gcc.target/i386/pr14907-20b.c > create mode 100644 gcc/testsuite/gcc.target/i386/pr14907-21.c > create mode 100644 gcc/testsuite/gcc.target/i386/pr14907-22.c > create mode 100644 gcc/testsuite/gcc.target/i386/pr14907-23.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-7a.c > create mode 100644 gcc/testsuite/gcc.target/i386/pr14907-7b.c > create mode 100644 gcc/testsuite/gcc.target/i386/pr14907-8a.c > create mode 100644 gcc/testsuite/gcc.target/i386/pr14907-8b.c > create mode 100644 gcc/testsuite/gcc.target/i386/pr14907-9a.c > create mode 100644 gcc/testsuite/gcc.target/i386/pr14907-9b.c > > diff --git a/gcc/calls.cc b/gcc/calls.cc > index bb8a6d09f82..c78337cf4b0 100644 > --- a/gcc/calls.cc > +++ b/gcc/calls.cc > @@ -75,6 +75,8 @@ struct arg_data > machine_mode mode; > /* Current RTL value for argument, or 0 if it isn't precomputed. */ > rtx value; > + /* RTL value from the incoming argument, or 0 if it isn't available. */ > + rtx incoming_argument_value; > /* Initially-compute RTL value for argument; only for const functions. */ > rtx initial_value; > /* Register to pass this argument in, 0 if passed on stack, or an > @@ -1019,7 +1021,10 @@ precompute_register_parameters (int num_actuals, > struct arg_data *args, > if (args[i].value == 0) > { > push_temp_slots (); > - args[i].value = expand_normal (args[i].tree_value); > + if (args[i].incoming_argument_value) > + args[i].value = args[i].incoming_argument_value; > + else > + args[i].value = expand_normal (args[i].tree_value); > preserve_temp_slots (args[i].value); > pop_temp_slots (); > } > @@ -1288,6 +1293,152 @@ maybe_complain_about_tail_call (tree call_expr, const > char *reason) > } > } > > +/* Return the value of the incoming argument, INCOMING_ARG if ARG, which > + is an outgoing argument, is copied directly from the incoming argument. > + Otherwise return nullptr. */ > + > +static rtx > +get_incoming_argument_value (const_tree fndecl, tree incoming_arg, > + tree arg) > +{ > + if (cfun->no_incoming_argument_value) > + return nullptr; > + > + /* Skip nested callee and caller. */ > + if ((fndecl && DECL_STATIC_CHAIN (fndecl)) > + || DECL_STATIC_CHAIN (current_function_decl)) > + { > +no_incoming_argument_value: > + cfun->no_incoming_argument_value = 1; > + return nullptr; > + } > + > + /* Skip if the incoming argument order of the caller is different from > + the incoming argument order of the callee since the same register > + may be used for different incoming arguments in caller and callee. > + Copying from one incoming argument in the caller to an outgoing > + argument may override another incoming argument. */ > + if (!targetm.calls.same_incoming_argument_order_p (fndecl)) > + goto no_incoming_argument_value; > + > + rtx_insn *before_call_expand = get_last_insn (); > + if (cfun->before_first_expand_call == nullptr) > + { > + cfun->before_first_expand_call = before_call_expand; > + > + /* Scan from the function start. */ > + rtx_insn *insn, *start = get_insns (); > + for (insn = start; insn; insn = NEXT_INSN (insn)) > + { > + /* Skip argument assignments before NOTE_INSN_FUNCTION_BEG. */ > + if (NOTE_P (insn) > + && NOTE_KIND (insn) == NOTE_INSN_FUNCTION_BEG) > + { > + insn = NEXT_INSN (insn); > + break; > + } > + > + if (!NONDEBUG_INSN_P (insn)) > + continue; > + > + rtx set = single_set (insn); > + /* Don't know if the incoming arguments are changed. */ > + if (!set) > + goto no_incoming_argument_value; > + > + rtx dest = SET_DEST (set); > + /* Don't know if the incoming arguments are changed. */ > + if (!REG_P (dest)) > + goto no_incoming_argument_value; > + > + rtx src = SET_SRC (set); > + if (REG_P (src) > + && REG_ATTRS (dest) == REG_ATTRS (src)) > + continue; > + > + /* Function argument source is OK. */ > + if (MEM_P (src) > + && MEM_EXPR (src) > + && (TREE_CODE (get_base_address (MEM_EXPR (src))) > + == PARM_DECL)) > + continue; > + > + > + /* Don't know if the incoming arguments are changed. */ > + goto no_incoming_argument_value; > + } > + > + /* Check if the incoming argument may be changed after > + NOTE_INSN_FUNCTION_BEG. */ > + for (; insn; insn = NEXT_INSN (insn)) > + { > + if (!NONDEBUG_INSN_P (insn)) > + continue; > + > + rtx set = single_set (insn); > + if (set) > + { > + rtx dest = SET_DEST (set); > + if (REG_P (dest) && !HARD_REGISTER_P (dest)) > + { > + /* Skip assignment from the hidden argument of the > + return value. */ > + tree result = DECL_RESULT (current_function_decl); > + if (DECL_RTL_SET_P (result)) > + { > + rtx result_rtl = DECL_RTL (result); > + if (result_rtl && MEM_P (result_rtl)) > + { > + rtx src = SET_SRC (set); > + result_rtl = XEXP (result_rtl, 0); > + if (rtx_equal_p (src, result_rtl)) > + continue; > + } > + } > + } > + } > + > + /* Don't use the incoming argument if there are any > + instructions which may change incoming arguments. */ > + goto no_incoming_argument_value; > + } > + } > + /* Incoming arguments aren't preserved after the first call. */ > + else if (cfun->before_first_expand_call != before_call_expand) > + goto no_incoming_argument_value; > + > + if (TREE_CODE (arg) != SSA_NAME) > + return nullptr; > + > + if (!SSA_NAME_IS_DEFAULT_DEF (arg)) > + return nullptr; > + > + tree var = SSA_NAME_VAR (arg); > + if (TREE_CODE (var) != PARM_DECL) > + return nullptr; > + tree arg_type = TREE_TYPE (arg); > + if (TYPE_MODE (arg_type) != TYPE_MODE (DECL_ARG_TYPE (var))) > + return nullptr; > + > + /* Return nullptr if the outgoing argument isn't copied directly from > + the corresponding incoming argument. In the case, the incoming > + argument order of the caller is different from the incoming argument > + of the callee and the same argument slot maps to different arguments > + in caller and callee. */ > + if (var != incoming_arg) > + return nullptr; > + > + /* Return the small integer incoming argument as int for the outgoing > + argument without extension. 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. */ > + rtx incoming_rtl = shallow_copy_rtx (DECL_INCOMING_RTL (var)); > + PUT_MODE (incoming_rtl, SImode); > + return incoming_rtl; > +} > + > /* Fill in ARGS_SIZE and ARGS array based on the parameters found in > CALL_EXPR EXP. > > @@ -1349,6 +1500,7 @@ initialize_argument_information (int num_actuals > ATTRIBUTE_UNUSED, > /* In this loop, we consider args in the order they are written. > We fill up ARGS from the back. */ > > + int implicit_argument = 0; > i = num_actuals - 1; > { > int j = i; > @@ -1359,6 +1511,7 @@ initialize_argument_information (int num_actuals > ATTRIBUTE_UNUSED, > { > args[j].tree_value = struct_value_addr_value; > j--; > + implicit_argument++; > } > argpos = 0; > FOR_EACH_CALL_EXPR_ARG (arg, iter, exp) > @@ -1387,19 +1540,38 @@ initialize_argument_information (int num_actuals > ATTRIBUTE_UNUSED, > ? TREE_TYPE (fndecl) > : fntype); > > + tree incoming_arg = nullptr; > + > /* I counts args in order (to be) pushed; ARGPOS counts in order written. > */ > for (argpos = 0; argpos < num_actuals; i--, argpos++) > { > tree type = TREE_TYPE (args[i].tree_value); > int unsignedp; > > + if (argpos >= implicit_argument) > + { > + if (incoming_arg == nullptr) > + incoming_arg = DECL_ARGUMENTS (current_function_decl); > + else > + incoming_arg = DECL_CHAIN (incoming_arg); > + } > + > /* 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 > - && INTEGRAL_TYPE_P (type) > - && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)) > - type = integer_type_node; > + else > + { > + if (promote_p > + && INTEGRAL_TYPE_P (type) > + && (TYPE_PRECISION (type) > + < TYPE_PRECISION (integer_type_node))) > + { > + type = integer_type_node; > + args[i].incoming_argument_value > + = get_incoming_argument_value (fndecl, incoming_arg, > + 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 > @@ -5073,18 +5245,24 @@ store_one_arg (struct arg_data *arg, rtx argblock, > int flags, > if (arg->pass_on_stack) > stack_arg_under_construction++; > > - arg->value = expand_expr (pval, > - (partial > - || TYPE_MODE (TREE_TYPE (pval)) != arg->mode) > - ? NULL_RTX : arg->stack, > - VOIDmode, EXPAND_STACK_PARM); > - > - /* If we are promoting object (or for any other reason) the mode > - doesn't agree, convert the mode. */ > - > - if (arg->mode != TYPE_MODE (TREE_TYPE (pval))) > - arg->value = convert_modes (arg->mode, TYPE_MODE (TREE_TYPE (pval)), > - arg->value, arg->unsignedp); > + if (arg->incoming_argument_value) > + arg->value = arg->incoming_argument_value; > + else > + { > + arg->value = expand_expr (pval, > + (partial > + || TYPE_MODE (TREE_TYPE (pval)) != > arg->mode) > + ? NULL_RTX : arg->stack, > + VOIDmode, EXPAND_STACK_PARM); > + > + /* If we are promoting object (or for any other reason) the mode > + doesn't agree, convert the mode. */ > + > + if (arg->mode != TYPE_MODE (TREE_TYPE (pval))) > + arg->value = convert_modes (arg->mode, > + TYPE_MODE (TREE_TYPE (pval)), > + arg->value, arg->unsignedp); > + } > > if (arg->pass_on_stack) > stack_arg_under_construction--; > diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc > index 55c9b16dd38..d0f1a7ef80e 100644 > --- a/gcc/config/i386/i386.cc > +++ b/gcc/config/i386/i386.cc > @@ -4497,6 +4497,19 @@ ix86_return_in_memory (const_tree type, const_tree > fntype ATTRIBUTE_UNUSED) > } > } > > +/* Implement TARGET_SAME_INCOMING_ARGUMENT_ORDER_P. */ > + > +static bool > +ix86_same_incoming_argument_order_p (const_tree fndecl) > +{ > + /* 64-bit SYSV ABI and 64-bit MS ABI have different argument orders. > + Copying one incoming argument register to another outgoing argument > + register may override the other incoming argument register. */ > + return (!TARGET_64BIT > + || (ix86_function_abi (current_function_decl) > + == ix86_function_abi (fndecl))); > +} > + > /* Implement TARGET_PUSH_ARGUMENT. */ > > static bool > @@ -27819,6 +27832,9 @@ static const scoped_attribute_specs *const > ix86_attribute_table[] = > #define TARGET_CXX_ADJUST_CDTOR_CALLABI_FNTYPE > ix86_cxx_adjust_cdtor_callabi_fntype > #undef TARGET_PROMOTE_PROTOTYPES > #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true > +#undef TARGET_SAME_INCOMING_ARGUMENT_ORDER_P > +#define TARGET_SAME_INCOMING_ARGUMENT_ORDER_P \ > + ix86_same_incoming_argument_order_p > #undef TARGET_PUSH_ARGUMENT > #define TARGET_PUSH_ARGUMENT ix86_push_argument > #undef TARGET_SETUP_INCOMING_VARARGS > diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi > index 4c338c382ad..0038b718ab9 100644 > --- a/gcc/doc/tm.texi > +++ b/gcc/doc/tm.texi > @@ -4057,6 +4057,12 @@ cases of mismatch, it also makes for better code on > certain machines. > The default is to not promote prototypes. > @end deftypefn > > +@deftypefn {Target Hook} bool TARGET_SAME_INCOMING_ARGUMENT_ORDER_P > (const_tree @var{fndecl}) > +This target hook returns @code{true} if the incoming argument order of > +the caller is the same as the incoming argument order of the calee > +@var{fndecl}. The default is to return @code{true}. > +@end deftypefn > + > @deftypefn {Target Hook} bool TARGET_PUSH_ARGUMENT (unsigned int @var{npush}) > This target hook returns @code{true} if push instructions will be > used to pass outgoing arguments. When the push instruction usage is > diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in > index 12b8ed660a0..5f4e78ed177 100644 > --- a/gcc/doc/tm.texi.in > +++ b/gcc/doc/tm.texi.in > @@ -3210,6 +3210,8 @@ control passing certain arguments in registers. > > @hook TARGET_PROMOTE_PROTOTYPES > > +@hook TARGET_SAME_INCOMING_ARGUMENT_ORDER_P > + > @hook TARGET_PUSH_ARGUMENT > > @defmac PUSH_ARGS_REVERSED > diff --git a/gcc/function.h b/gcc/function.h > index 370629f4de2..c7e5c171f64 100644 > --- a/gcc/function.h > +++ b/gcc/function.h > @@ -346,6 +346,9 @@ struct GTY(()) function { > a string describing the reason for failure. */ > const char * GTY((skip)) cannot_be_copied_reason; > > + /* The instruction before the first call expansion. */ > + rtx_insn *before_first_expand_call; > + > /* Last assigned dependence info clique. */ > unsigned short last_clique; > > @@ -451,6 +454,10 @@ struct GTY(()) function { > > /* Nonzero if reload will have to split basic blocks. */ > unsigned int split_basic_blocks_after_reload : 1; > + > + /* Nonzero if the incoming argument can't be used as the outgoing > + argument. */ > + unsigned int no_incoming_argument_value : 1; > }; > > /* Add the decl D to the local_decls list of FUN. */ > diff --git a/gcc/target.def b/gcc/target.def > index 5dd8f253ef6..e0e87bed79e 100644 > --- a/gcc/target.def > +++ b/gcc/target.def > @@ -4857,6 +4857,14 @@ The default is to not promote prototypes.", > bool, (const_tree fntype), > hook_bool_const_tree_false) > > +DEFHOOK > +(same_incoming_argument_order_p, > + "This target hook returns @code{true} if the incoming argument order of\n\ > +the caller is the same as the incoming argument order of the calee\n\ > +@var{fndecl}. The default is to return @code{true}.", > + bool, (const_tree fndecl), > + hook_bool_const_tree_true) > + > DEFHOOK > (struct_value_rtx, > "This target hook should return the location of the structure value\n\ > diff --git a/gcc/testsuite/gcc.dg/elide-1a.c b/gcc/testsuite/gcc.dg/elide-1a.c > new file mode 100644 > index 00000000000..282ac98d956 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/elide-1a.c > @@ -0,0 +1,10 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O2" } */ > + > +extern int baz (char, char); > + > +int > +foo (char c1, char c2) > +{ > + return baz (c2, c1) + 1; > +} > diff --git a/gcc/testsuite/gcc.dg/elide-1b.c b/gcc/testsuite/gcc.dg/elide-1b.c > new file mode 100644 > index 00000000000..034071974d1 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/elide-1b.c > @@ -0,0 +1,26 @@ > +/* { dg-do run } */ > +/* { dg-options "-O2" } */ > +/* { dg-additional-sources elide-1a.c } */ > + > +extern int foo (int, int); > + > +/* Verify that arguments aren't elided. */ > + > +int > +baz (int c1, int c2) > +{ > + if (c1 != 3) > + __builtin_abort (); > + if (c2 != -1) > + __builtin_abort (); > + > + return c1 - c2; > +} > + > +int > +main (void) > +{ > + if (foo (-1, 3) != 5) > + __builtin_abort (); > + return 0; > +} > diff --git a/gcc/testsuite/gcc.dg/elide-2a.c b/gcc/testsuite/gcc.dg/elide-2a.c > new file mode 100644 > index 00000000000..b2b63d1199e > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/elide-2a.c > @@ -0,0 +1,12 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O2" } */ > + > +extern int baz1 (char, char); > +extern void baz2 (char, char); > + > +int > +foo (char c1, char c2) > +{ > + baz2 (c1, c2); > + return baz1 (c1, c2); > +} > diff --git a/gcc/testsuite/gcc.dg/elide-2b.c b/gcc/testsuite/gcc.dg/elide-2b.c > new file mode 100644 > index 00000000000..fc411863f30 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/elide-2b.c > @@ -0,0 +1,30 @@ > +/* { dg-do run } */ > +/* { dg-options "-O2" } */ > +/* { dg-additional-sources elide-2a.c } */ > + > +extern int foo (int, int); > + > +int > +baz1 (int c1, int c2) > +{ > + return c2 + c1; > +} > + > +/* Verify that arguments aren't elided. */ > + > +void > +baz2 (int c1, int c2) > +{ > + if (c1 != -1) > + __builtin_abort (); > + if (c2 != 3) > + __builtin_abort (); > +} > + > +int > +main (void) > +{ > + if (foo (-1, 3) != 2) > + __builtin_abort (); > + return 0; > +} > 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-10a.c > b/gcc/testsuite/gcc.target/i386/pr14907-10a.c > new file mode 100644 > index 00000000000..dfe401bf1ef > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/pr14907-10a.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*... > +x64* movsbl %dil, %eax > +x64*... > +x64* movsbl %sil, %edi > +x64* movl %eax, %esi > +x64* call baz > +x64*... > +*/ > + > +extern int baz (char, char); > + > +int > +foo (char c1, char c2) > +{ > + return baz (c2, c1) + 1; > +} > diff --git a/gcc/testsuite/gcc.target/i386/pr14907-10b.c > b/gcc/testsuite/gcc.target/i386/pr14907-10b.c > new file mode 100644 > index 00000000000..d2c5fbd7f19 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/pr14907-10b.c > @@ -0,0 +1,20 @@ > +/* { 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*... > +ia32* movsbl 24\(%esp\), %eax > +ia32* pushl %eax > +ia32*... > +ia32* movsbl 32\(%esp\), %eax > +ia32* pushl %eax > +ia32*... > +ia32* call baz > +ia32*... > +*/ > + > +#include "pr14907-10a.c" > 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-17.c > b/gcc/testsuite/gcc.target/i386/pr14907-17.c > new file mode 100644 > index 00000000000..079cb4475a2 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/pr14907-17.c > @@ -0,0 +1,28 @@ > +/* { 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* movl %edi, %eax > +x64* movl base\(%rip\), %edi > +x64* movsbl %sil, %esi > +x64* movsbl %al, %edi > +x64* jmp baz > +x64* .cfi_endproc > +x64*... > +*/ > + > +extern int baz (char, char); > + > +extern int base; > + > +int > +foo (char c1, char c2) > +{ > + asm volatile ("": : "D" (base)); > + return baz (c1, c2); > +} > diff --git a/gcc/testsuite/gcc.target/i386/pr14907-18.c > b/gcc/testsuite/gcc.target/i386/pr14907-18.c > new file mode 100644 > index 00000000000..5d8eadfce2c > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/pr14907-18.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 "x86*" "" "" { target { *-*-linux* > *-*-gnu* } } {^\t?\.} } } */ > + > +/* > +x86*foo: > +x86*.LFB0: > +x86*... > +x86* call baz2 > +x86*... > +x86* jmp baz1 > +x86*... > +*/ > + > +extern int baz1 (char, char); > +extern void baz2 (char, char); > + > +int > +foo (char c1, char c2) > +{ > + baz2 (c1, c2); > + return baz1 (c1, c2); > +} > diff --git a/gcc/testsuite/gcc.target/i386/pr14907-19.c > b/gcc/testsuite/gcc.target/i386/pr14907-19.c > new file mode 100644 > index 00000000000..07712e5da20 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/pr14907-19.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 "ia32*" "" "" { target { { *-*-linux* > *-*-gnu* } && { ia32 } } } {^\t?\.} } } */ > + > +/* > +ia32*foo: > +ia32*.LFB0: > +ia32* .cfi_startproc > +ia32* movl 8\(%esp\), %edx > +ia32* movl 4\(%esp\), %eax > +ia32* jmp baz > +ia32* .cfi_endproc > +ia32*... > +*/ > + > +__attribute__ ((regparm (2))) > +extern int baz (char, char); > + > +int > +foo (char c1, char c2) > +{ > + return baz (c1, c2); > +} > + > +/* { dg-final { scan-assembler-not "movsbl" } } */ > 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-20a.c > b/gcc/testsuite/gcc.target/i386/pr14907-20a.c > new file mode 100644 > index 00000000000..1d65185b021 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/pr14907-20a.c > @@ -0,0 +1,27 @@ > +/* { dg-do compile { target ia32 } } */ > +/* { 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*... > +ia32* pushl %edx > +ia32*... > +ia32* pushl %eax > +ia32*... > +ia32* call baz > +ia32*... > +*/ > + > +extern int baz (char, char); > + > +__attribute__ ((regparm (2))) > +int > +foo (char c1, char c2) > +{ > + return baz (c1, c2); > +} > + > +/* { dg-final { scan-assembler-not "movsbl" } } */ > diff --git a/gcc/testsuite/gcc.target/i386/pr14907-20b.c > b/gcc/testsuite/gcc.target/i386/pr14907-20b.c > new file mode 100644 > index 00000000000..2dcd8a94c81 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/pr14907-20b.c > @@ -0,0 +1,23 @@ > +/* { dg-do run { target ia32 } } */ > +/* { dg-options "-O2" } */ > +/* { dg-additional-sources pr14907-20a.c } */ > + > +extern int foo (int, int) __attribute__ ((regparm (2))); > + > +int > +baz (int c1, int c2) > +{ > + if (c1 != -1) > + __builtin_abort (); > + if (c2 != 3) > + __builtin_abort (); > + return c1 + c2; > +} > + > +int > +main (void) > +{ > + if (foo (-1, 3) != 2) > + __builtin_abort (); > + return 0; > +} > diff --git a/gcc/testsuite/gcc.target/i386/pr14907-21.c > b/gcc/testsuite/gcc.target/i386/pr14907-21.c > new file mode 100644 > index 00000000000..1e6cd18349c > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/pr14907-21.c > @@ -0,0 +1,28 @@ > +/* { dg-do run { target { ! x32 } } } */ > +/* { dg-options "-O2" } */ > + > +#include <stdint.h> > + > +__attribute__ ((sysv_abi, noipa)) > +uint8_t > +foo (uint8_t a, uint8_t b, uint8_t c, uint8_t d, > + uint8_t e, uint8_t f, uint8_t g) > +{ > + return a + b + c + d + e + f + g; > +} > + > +__attribute__((ms_abi, noipa)) > +uint8_t > +bar (uint8_t a, uint8_t b, uint8_t c, uint8_t d, > + uint8_t e, uint8_t f, uint8_t g) > +{ > + return foo (a, b, c, d, e, f, g); > +} > + > +int > +main (void) > +{ > + if (bar (0, 1, 2, 3, 4, 5, 6) != 21) > + __builtin_abort (); > + return 0; > +} > diff --git a/gcc/testsuite/gcc.target/i386/pr14907-22.c > b/gcc/testsuite/gcc.target/i386/pr14907-22.c > new file mode 100644 > index 00000000000..591c8efd438 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/pr14907-22.c > @@ -0,0 +1,28 @@ > +/* { dg-do run { target { ! x32 } } } */ > +/* { dg-options "-O2" } */ > + > +#include <stdint.h> > + > +__attribute__((ms_abi, noipa)) > +uint8_t > +foo (uint8_t a, uint8_t b, uint8_t c, uint8_t d, > + uint8_t e, uint8_t f, uint8_t g) > +{ > + return a + b + c + d + e + f + g; > +} > + > +__attribute__ ((sysv_abi, noipa)) > +uint8_t > +bar (uint8_t a, uint8_t b, uint8_t c, uint8_t d, > + uint8_t e, uint8_t f, uint8_t g) > +{ > + return foo (a, b, c, d, e, f, g); > +} > + > +int > +main (void) > +{ > + if (bar (0, 1, 2, 3, 4, 5, 6) != 21) > + __builtin_abort (); > + return 0; > +} > diff --git a/gcc/testsuite/gcc.target/i386/pr14907-23.c > b/gcc/testsuite/gcc.target/i386/pr14907-23.c > new file mode 100644 > index 00000000000..5082b4de589 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/pr14907-23.c > @@ -0,0 +1,11 @@ > +/* { dg-do compile { target maybe_x32 } } */ > +/* { dg-require-effective-target maybe_x32 } */ > +/* { dg-options "-mx32 -O2" } */ > + > +extern int baz (int a1, int a2, int a3, int a4, int a5, int a6, int *a7); > + > +int > +foo (int a1, int a2, int a3, int a4, int a5, int a6, int *a7) > +{ > + return baz (a1, a2, a3, a4, a5, a6, a7); > +} > 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-7a.c > b/gcc/testsuite/gcc.target/i386/pr14907-7a.c > new file mode 100644 > index 00000000000..fbf511f691e > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/pr14907-7a.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-7b.c > b/gcc/testsuite/gcc.target/i386/pr14907-7b.c > new file mode 100644 > index 00000000000..56596e080e2 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/pr14907-7b.c > @@ -0,0 +1,17 @@ > +/* { 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*... > +*/ > + > +#include "pr14907-7a.c" > diff --git a/gcc/testsuite/gcc.target/i386/pr14907-8a.c > b/gcc/testsuite/gcc.target/i386/pr14907-8a.c > new file mode 100644 > index 00000000000..a22383694bf > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/pr14907-8a.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/gcc.target/i386/pr14907-8b.c > b/gcc/testsuite/gcc.target/i386/pr14907-8b.c > new file mode 100644 > index 00000000000..4e30f323e04 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/pr14907-8b.c > @@ -0,0 +1,17 @@ > +/* { 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*... > +*/ > + > +#include "pr14907-8a.c" > diff --git a/gcc/testsuite/gcc.target/i386/pr14907-9a.c > b/gcc/testsuite/gcc.target/i386/pr14907-9a.c > new file mode 100644 > index 00000000000..ee8d0b0805f > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/pr14907-9a.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* movsbl %dil, %eax > +x64* movsbl %sil, %edi > +x64* movl %eax, %esi > +x64* jmp baz > +x64* .cfi_endproc > +x64*... > +*/ > + > +extern int baz (char, char); > + > +int > +foo (char c1, char c2) > +{ > + return baz (c2, c1); > +} > diff --git a/gcc/testsuite/gcc.target/i386/pr14907-9b.c > b/gcc/testsuite/gcc.target/i386/pr14907-9b.c > new file mode 100644 > index 00000000000..d094e2f4ce7 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/pr14907-9b.c > @@ -0,0 +1,19 @@ > +/* { 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 8\(%esp\), %eax > +ia32* movsbl 4\(%esp\), %edx > +ia32* movl %eax, 4\(%esp\) > +ia32* movl %edx, 8\(%esp\) > +ia32* jmp baz > +ia32* .cfi_endproc > +ia32*... > +*/ > + > +#include "pr14907-9a.c" > -- > 2.51.0 >
PING. -- H.J.