On Thu, Oct 1, 2026 at 12:46 AM Oleg Tolmatcev <[email protected]> wrote: > > For an MS ABI va_list, ix86_gimplify_va_arg calls > std_gimplify_va_arg_expr, which asks the pass_by_reference hook whether > the argument was passed by reference. Without cumulative args, the hook > assumes the default ABI, SysV on Linux, so va_arg reads an argument > passed by reference as if it were passed by value. > > Split the ABI-specific decision out of ix86_pass_by_reference. For an > indirect MS ABI argument, follow ia64_gimplify_va_arg: use the standard > va_arg helper to read its pointer and then dereference it. Use the > explicit SysV ABI for a SysV va_list so the opposite target-default > mismatch is handled as well. > > gcc/ChangeLog: > > * config/i386/i386.cc (ix86_pass_by_reference_abi): New function, > split out of ... > (ix86_pass_by_reference): ... this. > (ix86_gimplify_va_arg): Derive argument indirection from the ABI of > the va_list type. Read indirect MS ABI arguments as pointers. > > gcc/testsuite/ChangeLog: > > * gcc.target/i386/va-arg-abi-attribute.c: New test.
OK. For future contributions, please state how you tested the patch, see [1]. Also, if you don't have write access, please point out lack of write access in your initial submission, as also advised in [1]. [1] https://gcc.gnu.org/contribute.html#patches Thanks, Uros. > > Signed-off-by: Oleg Tolmatcev <[email protected]> > --- > gcc/config/i386/i386.cc | 37 +++++++--- > .../gcc.target/i386/va-arg-abi-attribute.c | 73 +++++++++++++++++++ > 2 files changed, 101 insertions(+), 9 deletions(-) > create mode 100644 gcc/testsuite/gcc.target/i386/va-arg-abi-attribute.c > > diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc > index e9015d2427..3b1f680b22 100644 > --- a/gcc/config/i386/i386.cc > +++ b/gcc/config/i386/i386.cc > @@ -3655,17 +3655,15 @@ ix86_function_arg (cumulative_args_t cum_v, const > function_arg_info &arg) > reference. If nonzero for an argument, a copy of that argument is > made in memory and a pointer to the argument is passed instead of > the argument itself. The pointer is passed in whatever way is > - appropriate for passing a pointer to that type. */ > + appropriate for passing a pointer to that type. CALL_ABI is the > + calling convention the argument is passed under. */ > > static bool > -ix86_pass_by_reference (cumulative_args_t cum_v, const function_arg_info > &arg) > +ix86_pass_by_reference_abi (enum calling_abi call_abi, > + const function_arg_info &arg) > { > - CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v); > - > if (TARGET_64BIT) > { > - enum calling_abi call_abi = cum ? cum->call_abi : ix86_abi; > - > /* See Windows x64 Software Convention. */ > if (call_abi == MS_ABI) > { > @@ -3695,6 +3693,16 @@ ix86_pass_by_reference (cumulative_args_t cum_v, const > function_arg_info &arg) > return false; > } > > +/* Implement TARGET_PASS_BY_REFERENCE. */ > + > +static bool > +ix86_pass_by_reference (cumulative_args_t cum_v, const function_arg_info > &arg) > +{ > + CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v); > + > + return ix86_pass_by_reference_abi (cum ? cum->call_abi : ix86_abi, arg); > +} > + > /* Return true when TYPE should be 128bit aligned for 32bit argument > passing ABI. XXX: This function is obsolete and is only used for > checking psABI compatibility with previous versions of GCC. */ > @@ -4988,7 +4996,7 @@ ix86_gimplify_va_arg (tree valist, tree type, > gimple_seq *pre_p, > tree lab_false, lab_over = NULL_TREE; > tree addr, t2; > rtx container; > - int indirect_p = 0; > + bool indirect_p; > tree ptrtype; > machine_mode nat_mode; > unsigned int arg_boundary; > @@ -4996,7 +5004,17 @@ ix86_gimplify_va_arg (tree valist, tree type, > gimple_seq *pre_p, > > /* Only 64bit target needs something special. */ > if (is_va_list_char_pointer (TREE_TYPE (valist))) > - return std_gimplify_va_arg_expr (valist, type, pre_p, post_p); > + { > + indirect_p > + = ix86_pass_by_reference_abi (MS_ABI, function_arg_info (type, > false)); > + if (indirect_p) > + { > + type = build_pointer_type (type); > + t = std_gimplify_va_arg_expr (valist, type, pre_p, post_p); > + return build_va_arg_indirect_ref (t); > + } > + return std_gimplify_va_arg_expr (valist, type, pre_p, post_p); > + } > > f_gpr = TYPE_FIELDS (TREE_TYPE (sysv_va_list_type_node)); > f_fpr = DECL_CHAIN (f_gpr); > @@ -5010,7 +5028,8 @@ ix86_gimplify_va_arg (tree valist, tree type, > gimple_seq *pre_p, > ovf = build3 (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf, NULL_TREE); > sav = build3 (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav, NULL_TREE); > > - indirect_p = pass_va_arg_by_reference (type); > + indirect_p > + = ix86_pass_by_reference_abi (SYSV_ABI, function_arg_info (type, false)); > if (indirect_p) > type = build_pointer_type (type); > size = arg_int_size_in_bytes (type); > diff --git a/gcc/testsuite/gcc.target/i386/va-arg-abi-attribute.c > b/gcc/testsuite/gcc.target/i386/va-arg-abi-attribute.c > new file mode 100644 > index 0000000000..48aed0c914 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/va-arg-abi-attribute.c > @@ -0,0 +1,73 @@ > +/* ix86_gimplify_va_arg must decide whether an argument is passed by > + reference from the va_list type, not from the ABI of the function > + containing the va_arg or from the target default. */ > +/* { dg-do run { target { lp64 || llp64 } } } */ > +/* { dg-options "-std=gnu99" } */ > + > +typedef int v4si __attribute__ ((vector_size (16))); > +struct s3 { char a, b, c; }; > +struct s8 { int a, b; }; > +struct s12 { int a, b, c; }; > +struct s16 { long long a, b; }; > + > +#define READER(name, abi, list) > \ > +static __attribute__ ((abi, noipa)) void \ > +name (list ap) \ > +{ \ > + struct s3 x3 = __builtin_va_arg (ap, struct s3); \ > + struct s8 x8 = __builtin_va_arg (ap, struct s8); \ > + struct s12 x12 = __builtin_va_arg (ap, struct s12); \ > + struct s16 x16 = __builtin_va_arg (ap, struct s16); \ > + v4si v = __builtin_va_arg (ap, v4si); > \ > + int i = __builtin_va_arg (ap, int); \ > + if (x3.a != 1 || x3.b != 2 || x3.c != 3 \ > + || x8.a != 4 || x8.b != 5 > \ > + || x12.a != 6 || x12.b != 7 || x12.c != 8 > \ > + || x16.a != 9 || x16.b != 10 \ > + || v[0] != 11 || v[1] != 12 || v[2] != 13 || v[3] != 14 \ > + || i != 15) \ > + __builtin_abort (); > \ > +} > + > +READER (sysv_reads_sysv, sysv_abi, __builtin_sysv_va_list) > +READER (ms_reads_sysv, ms_abi, __builtin_sysv_va_list) > +READER (sysv_reads_ms, sysv_abi, __builtin_ms_va_list) > +READER (ms_reads_ms, ms_abi, __builtin_ms_va_list) > + > +static __attribute__ ((sysv_abi, noipa)) void > +sysv_varargs (int n, ...) > +{ > + __builtin_sysv_va_list ap; > + __builtin_sysv_va_start (ap, n); > + sysv_reads_sysv (ap); > + __builtin_sysv_va_end (ap); > + __builtin_sysv_va_start (ap, n); > + ms_reads_sysv (ap); > + __builtin_sysv_va_end (ap); > +} > + > +static __attribute__ ((ms_abi, noipa)) void > +ms_varargs (int n, ...) > +{ > + __builtin_ms_va_list ap; > + __builtin_ms_va_start (ap, n); > + sysv_reads_ms (ap); > + __builtin_ms_va_end (ap); > + __builtin_ms_va_start (ap, n); > + ms_reads_ms (ap); > + __builtin_ms_va_end (ap); > +} > + > +int > +main (void) > +{ > + struct s3 x3 = { 1, 2, 3 }; > + struct s8 x8 = { 4, 5 }; > + struct s12 x12 = { 6, 7, 8 }; > + struct s16 x16 = { 9, 10 }; > + v4si v = { 11, 12, 13, 14 }; > + > + sysv_varargs (0, x3, x8, x12, x16, v, 15); > + ms_varargs (0, x3, x8, x12, x16, v, 15); > + return 0; > +} > -- > 2.56.0.windows.1 >
