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