On Thu, Sep 18, 2025 at 9:01 PM H.J. Lu <[email protected]> wrote:
>
> On Mon, Aug 25, 2025 at 5:59 AM H.J. Lu <[email protected]> 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 <[email protected]>
> > ---
> >  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.

PING^2.

-- 
H.J.

Reply via email to