Libgcc helper libcalls such as __udivti3 still use the historical
TImode direct-return convention. Preserve that convention when
TARGET_RETURN_IN_MEMORY is queried for a libcall so the caller's
expectation continues to match libgcc on x86_64-w64-mingw32.

gcc/ChangeLog:

        PR target/78799
        * config/i386/i386.cc (ix86_return_in_memory): Keep TImode
        libcalls on the direct-return convention.
        * testsuite/gcc.target/i386/pr78799-2.c: New test.

Signed-off-by: Oleg Tolmatcev <[email protected]>
---
 gcc/config/i386/i386.cc                   |  8 ++++++-
 gcc/testsuite/gcc.target/i386/pr78799-2.c | 28 +++++++++++++++++++++++
 2 files changed, 35 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/gcc.target/i386/pr78799-2.c

diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index e83402f2c4..2156e50e49 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -4446,13 +4446,19 @@ ix86_libcall_value (machine_mode mode)
 /* Return true iff type is returned in memory.  */
 
 static bool
-ix86_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
+ix86_return_in_memory (const_tree type, const_tree fntype)
 {
   const machine_mode mode = type_natural_mode (type, NULL, true);
   HOST_WIDE_INT size;
 
   if (TARGET_64BIT)
     {
+      /* Libcalls use TARGET_LIBCALL_VALUE for their return ABI.  Keep
+        TImode helpers such as __udivti3 on the historical direct-return
+        convention so they continue to match libgcc.  */
+      if (fntype == NULL_TREE && mode == TImode)
+       return false;
+
       if (ix86_function_type_abi (fntype) == MS_ABI)
        {
          size = int_size_in_bytes (type);
diff --git a/gcc/testsuite/gcc.target/i386/pr78799-2.c 
b/gcc/testsuite/gcc.target/i386/pr78799-2.c
new file mode 100644
index 0000000000..f223f6de94
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr78799-2.c
@@ -0,0 +1,28 @@
+/* { dg-do run { target { int128 && x86_64-*-mingw* } } } */
+/* { dg-options "-O2" } */
+
+typedef unsigned long long u64;
+typedef unsigned __int128 u128;
+
+__attribute__((noinline, noclone))
+static u64
+div128_high_by (u64 high, u64 divisor)
+{
+  u128 n = (u128) high << 64;
+  return (u64) (n / (u128) divisor);
+}
+
+int
+main (void)
+{
+  if (div128_high_by (1ull, 3ull) != 0x5555555555555555ull)
+    __builtin_abort ();
+
+  if (div128_high_by (1ull << 62, 1ull << 63) != (1ull << 63))
+    __builtin_abort ();
+
+  if (div128_high_by (1ull, ~0ull) != 1ull)
+    __builtin_abort ();
+
+  return 0;
+}
-- 
2.55.0.windows.3

Reply via email to