Use the function's abi instead of the target's abi when CUM is NULL and a
sysv_abi function is calling an ms_abi function or vice versa.

gcc/ChangeLog:

        * config/i386/i386.cc (ix86_pass_by_reference): Use the function's
        ABI instead of the target's ABI when CUM is NULL.

gcc/testsuite/ChangeLog:

        * gcc.target/i386/va-arg-abi-attribute.c: New test.

Signed-off-by: Oleg Tolmatcev <[email protected]>
---
 gcc/config/i386/i386.cc                       |  2 +-
 .../gcc.target/i386/va-arg-abi-attribute.c    | 39 +++++++++++++++++++
 2 files changed, 40 insertions(+), 1 deletion(-)
 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 b09a507782..2b1c3ae13d 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -3664,7 +3664,7 @@ ix86_pass_by_reference (cumulative_args_t cum_v, const 
function_arg_info &arg)
 
   if (TARGET_64BIT)
     {
-      enum calling_abi call_abi = cum ? cum->call_abi : ix86_abi;
+      enum calling_abi call_abi = cum ? cum->call_abi : ix86_cfun_abi ();
 
       /* See Windows x64 Software Convention.  */
       if (call_abi == MS_ABI)
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..e0bb01b6b1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/va-arg-abi-attribute.c
@@ -0,0 +1,39 @@
+/* va_arg must follow the convention of the function it is in: the MS one
+   passes a struct of more than eight bytes by reference, System V by
+   value.  */
+/* { dg-do run { target { lp64 || llp64 } } } */
+/* { dg-options "-std=gnu99" } */
+
+struct s { long long a, b; };
+
+static __attribute__((sysv_abi, noipa)) long long
+sysv (int n, ...)
+{
+  __builtin_sysv_va_list ap;
+  struct s x;
+  __builtin_sysv_va_start (ap, n);
+  x = __builtin_va_arg (ap, struct s);
+  __builtin_sysv_va_end (ap);
+  return x.a * 10 + x.b;
+}
+
+static __attribute__((ms_abi, noipa)) long long
+ms (int n, ...)
+{
+  __builtin_ms_va_list ap;
+  struct s x;
+  __builtin_ms_va_start (ap, n);
+  x = __builtin_va_arg (ap, struct s);
+  __builtin_ms_va_end (ap);
+  return x.a * 10 + x.b;
+}
+
+int
+main (void)
+{
+  struct s x = { 3, 4 };
+
+  if (sysv (1, x) != 34 || ms (1, x) != 34)
+    __builtin_abort ();
+  return 0;
+}
-- 
2.55.0.windows.5

Reply via email to