[X86][windows] Return fp128 on the stack#194214
Conversation
For x86-64 Windows targets, LLVM currently returns `fp128` in xmm0. This does match `i128` (both Clang and GCC return `__int128` in xmm0) but disagrees with GCC's behavior of returning `__float128` on the stack. Microsoft does not specify a `__float128` ABI so any decision is purely an extension. The Windows x64 calling convention [1] does say that user- defined types that do not fit in a register should be returned indirectly, so the GCC behavior seems like a reasonable interpretation of this rule. Thus, change `fp128` to return on the stack for Windows targets. This is done for both MinGW and MSVC targets; if official guidelines are ever published, this can be revisited. Relates to the pass ABI change in 5ee1c0b ("[windows] Always pass fp128 arguments indirectly"). [1]: https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170#return-values
| @@ -130,54 +130,54 @@ def CC_#NAME : CallingConv<[ | |||
|
|
|||
| // __mmask64 (v64i1) --> GPR64 (for x64) or 2 x GPR32 (for IA32) | |||
| CCIfType<[v64i1], CCPromoteToType<i64>>, | |||
| CCIfSubtarget<"is64Bit()", CCIfType<[i64], | |||
| CCIfSubtarget<"is64Bit()", CCIfType<[i64], | |||
There was a problem hiding this comment.
There is some trailing whitespace in this file that I unintentionally trimmed, but I think that's fine. If you'd prefer to me to split it out though, I can do that too.
|
Since ABI doesn’t specify this, why choose the less efficient approach? Why can’t make gcc match clang’s behavior? |
|
@rnk @phoebewang I'd appreciate a review once ready since you handled #128848 and #115052, but I need some help here first. This is going to hit the assertion at . What is the correct way to turn a type into a sret? Nothing stood out to me in existing tablegen files. |
🐧 Linux x64 Test Results
Failed Tests(click on a test name to see its output) LLVMLLVM.CodeGen/X86/fp128-libcalls-strict.llLLVM.CodeGen/X86/fp128-libcalls.llLLVM.CodeGen/X86/i128-fp128-abi.llIf these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the |
🪟 Windows x64 Test Results
Failed Tests(click on a test name to see its output) LLVMLLVM.CodeGen/X86/fp128-libcalls-strict.llLLVM.CodeGen/X86/fp128-libcalls.llLLVM.CodeGen/X86/i128-fp128-abi.llIf these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the |
That was my initial plan for a long time, which I noted in the linked commit. But I talked with a handful of people and got the impression that the proposed behavior here (return on the stack) is likely a closer interpretation of the MSVC ABI's handling of fundamental types than returning in xmm0. This also applies to i128 but it is much more set in stone (based on some light GCC archaeology I got the feeling that returning __int128 in xmm0 is not really intentional, but rather a carryover of __m128). If that's the case then I don't think the performance difference is especially concerning. The type already needs to be passed in memory and even a simple f128 addition is ~300 instructions (~50 for the shortest nontrivial fast path), an extra |
|
I'm still a bit stuck here figuring out how to get the stack return working. @phoebewang or perhaps @nikic do you happen to have any ideas? |
Subsumes #194214 For x86-64 Windows targets, LLVM currently returns `fp128` in xmm0. This does match `i128` (both Clang and GCC return `__int128` in xmm0) but disagrees with GCC's behavior of returning `__float128` on the stack. https://gcc.godbolt.org/z/xnWeGqcbW Microsoft does not specify a `__float128` ABI so any decision is purely an extension. The Windows x64 calling convention [1] does say that user- defined types that do not fit in a register should be returned indirectly, so the GCC behavior seems like a reasonable interpretation of this rule. Thus, change `fp128` to return on the stack for Windows targets. This is done for both MinGW and MSVC targets; if official guidelines are ever published, this can be revisited. The change is made in LLVM (via sret demotion of f128), but also explicitly in `clang`. Frontends should emit the `sret` explicitly, if only for debug info, return value optimization, etc. Relates to the pass ABI change in 5ee1c0b ("[windows] Always pass fp128 arguments indirectly"). [1]: https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170#return-values
Subsumes llvm/llvm-project#194214 For x86-64 Windows targets, LLVM currently returns `fp128` in xmm0. This does match `i128` (both Clang and GCC return `__int128` in xmm0) but disagrees with GCC's behavior of returning `__float128` on the stack. https://gcc.godbolt.org/z/xnWeGqcbW Microsoft does not specify a `__float128` ABI so any decision is purely an extension. The Windows x64 calling convention [1] does say that user- defined types that do not fit in a register should be returned indirectly, so the GCC behavior seems like a reasonable interpretation of this rule. Thus, change `fp128` to return on the stack for Windows targets. This is done for both MinGW and MSVC targets; if official guidelines are ever published, this can be revisited. The change is made in LLVM (via sret demotion of f128), but also explicitly in `clang`. Frontends should emit the `sret` explicitly, if only for debug info, return value optimization, etc. Relates to the pass ABI change in 5ee1c0b ("[windows] Always pass fp128 arguments indirectly"). [1]: https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170#return-values
Subsumes llvm/llvm-project#194214 For x86-64 Windows targets, LLVM currently returns `fp128` in xmm0. This does match `i128` (both Clang and GCC return `__int128` in xmm0) but disagrees with GCC's behavior of returning `__float128` on the stack. https://gcc.godbolt.org/z/xnWeGqcbW Microsoft does not specify a `__float128` ABI so any decision is purely an extension. The Windows x64 calling convention [1] does say that user- defined types that do not fit in a register should be returned indirectly, so the GCC behavior seems like a reasonable interpretation of this rule. Thus, change `fp128` to return on the stack for Windows targets. This is done for both MinGW and MSVC targets; if official guidelines are ever published, this can be revisited. The change is made in LLVM (via sret demotion of f128), but also explicitly in `clang`. Frontends should emit the `sret` explicitly, if only for debug info, return value optimization, etc. Relates to the pass ABI change in 5ee1c0b ("[windows] Always pass fp128 arguments indirectly"). [1]: https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170#return-values
Subsumes llvm#194214 For x86-64 Windows targets, LLVM currently returns `fp128` in xmm0. This does match `i128` (both Clang and GCC return `__int128` in xmm0) but disagrees with GCC's behavior of returning `__float128` on the stack. https://gcc.godbolt.org/z/xnWeGqcbW Microsoft does not specify a `__float128` ABI so any decision is purely an extension. The Windows x64 calling convention [1] does say that user- defined types that do not fit in a register should be returned indirectly, so the GCC behavior seems like a reasonable interpretation of this rule. Thus, change `fp128` to return on the stack for Windows targets. This is done for both MinGW and MSVC targets; if official guidelines are ever published, this can be revisited. The change is made in LLVM (via sret demotion of f128), but also explicitly in `clang`. Frontends should emit the `sret` explicitly, if only for debug info, return value optimization, etc. Relates to the pass ABI change in 5ee1c0b ("[windows] Always pass fp128 arguments indirectly"). [1]: https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170#return-values
Subsumes llvm/llvm-project#194214 For x86-64 Windows targets, LLVM currently returns `fp128` in xmm0. This does match `i128` (both Clang and GCC return `__int128` in xmm0) but disagrees with GCC's behavior of returning `__float128` on the stack. https://gcc.godbolt.org/z/xnWeGqcbW Microsoft does not specify a `__float128` ABI so any decision is purely an extension. The Windows x64 calling convention [1] does say that user- defined types that do not fit in a register should be returned indirectly, so the GCC behavior seems like a reasonable interpretation of this rule. Thus, change `fp128` to return on the stack for Windows targets. This is done for both MinGW and MSVC targets; if official guidelines are ever published, this can be revisited. The change is made in LLVM (via sret demotion of f128), but also explicitly in `clang`. Frontends should emit the `sret` explicitly, if only for debug info, return value optimization, etc. Relates to the pass ABI change in 5ee1c0b ("[windows] Always pass fp128 arguments indirectly"). [1]: https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170#return-values
|
#204887 finished this up |
For x86-64 Windows targets, LLVM currently returns
fp128in xmm0. This does matchi128(both Clang and GCC return__int128in xmm0) but disagrees with GCC's behavior of returning__float128on the stack.Microsoft does not specify a
__float128ABI so any decision is purely an extension. The Windows x64 calling convention 1 does say that user- defined types that do not fit in a register should be returned indirectly, so the GCC behavior seems like a reasonable interpretation of this rule.Thus, change
fp128to return on the stack for Windows targets. This is done for both MinGW and MSVC targets; if official guidelines are ever published, this can be revisited.Relates to the pass ABI change in 5ee1c0b ("[windows] Always pass fp128 arguments indirectly").