On 8/31/25 9:58 PM, Trevor Gross wrote:
For MinGW on x86-64, GCC currently passes and returns `_Float16` in
GPRs. Microsoft does not specify an official ABI for this type, but the
Windows x86-64 calling convention [1] does state the following:

     Any floating-point and double-precision arguments in the first four
     parameters are passed in XMM0 - XMM3, depending on position.
     Floating-point values are only placed in the integer registers RCX,
     RDX, R8, and R9 when there are varargs arguments. For details, see
     Varargs. Similarly, the XMM0 - XMM3 registers are ignored when the
     corresponding argument is an integer or pointer type.

And

     A scalar return value that can fit into 64 bits, including the __m64
     type, is returned through RAX. Nonscalar types including floats,
     doubles, and vector types such as __m128, __m128i, __m128d are
     returned in XMM0. The state of unused bits in the value returned in
     RAX or XMM0 is undefined.

Some reading between the lines is necessary, but it seems reasonable to
expect that `_Float16` should be passed in xmm registers and returned in
xmm0. This is the same as `float` and `double` and matches the behavior
that Clang currently has for `_Float16` on its x64 MSVC and MinGW
targets. (SystemV does the same).

Thus, update the `HFmode` ABI to both pass and return in vector
registers.


LH, any feedback?

The results can be verified by evaluating the change in assembly output
with this source:

     void pass_f16(_Float16 x, _Float16 *dst) {
         *dst = x;
     }

     void callee_f16(_Float16);
     void call_f16() {
         callee_f16(1.0);
     }

     _Float16 ret_f16(_Float16 *x) {
         return *x;
     }

     /* Check libcall ABI */

     void extend_f16(_Float16 *x, _Float32 *dst) {
         *dst = (_Float32)*x;
     }

     void trunc_f16(_Float32 *x, _Float16 *dst) {
         *dst = (_Float16)*x;
     }

     /* Float varargs should be in vregs with a zeroed shadow GPR */

     void va(_Float16, ...);
     void va_f16() {
         va(1.0f16, 2.0f16, 3.0f16, 4.0f16, 5.0f16);
     }

2025-08-31  Trevor Gross  <[email protected]>

gcc/:
         PR target/115054
         * gcc/config/i386/i386.cc (function_arg_ms_64,
           function_value_ms_64): Pass and return _Float16 in vector
           registers on Windows.

[1]: 
https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170

Signed-off-by: Trevor Gross <[email protected]>
---

I have sample output with and without this patch at [1] for reference.
The ABI smoke test source is not yet in-tree, patch at [2].

If an asm ABI test is needed (checking the registers), I will need some
direction for what this should look like.

[1]: https://github.com/tgross35/gcc-build-output

  gcc/config/i386/i386.cc | 12 +++++++-----
  1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index 471be3e8615..1a71c01f081 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -3493,8 +3493,10 @@ function_arg_ms_64 (const CUMULATIVE_ARGS *cum, 
machine_mode mode,
regno = x86_64_ms_abi_int_parameter_registers[cum->regno]; - /* Only floating point modes are passed in anything but integer regs. */
-  if (TARGET_SSE && (mode == SFmode || mode == DFmode))
+  /* Only floating point modes less than 64 bits are passed in anything but
+     integer regs.  Larger floating point types are excluded as the Windows
+     ABI requires vreg args can be shawoed in GPRs (for red zone / varargs). */

Shadowed?

+  if (TARGET_SSE && (mode == HFmode || mode == SFmode || mode == DFmode))
      {
        if (named)
        {
@@ -4314,9 +4316,8 @@ function_value_ms_64 (machine_mode orig_mode, 
machine_mode mode,
      {
        switch (GET_MODE_SIZE (mode))
        {
-       case 16:
+       case 16:        
          if (valtype != NULL_TREE
-             && !VECTOR_INTEGER_TYPE_P (valtype)
              && !VECTOR_INTEGER_TYPE_P (valtype)
              && !INTEGRAL_TYPE_P (valtype)
              && !VECTOR_FLOAT_TYPE_P (valtype))
@@ -4327,9 +4328,10 @@ function_value_ms_64 (machine_mode orig_mode, 
machine_mode mode,
          break;
        case 8:
        case 4:
+       case 2:
          if (valtype != NULL_TREE && AGGREGATE_TYPE_P (valtype))
            break;
-         if (mode == SFmode || mode == DFmode)
+         if (mode == HFmode || mode == SFmode || mode == DFmode)
            regno = FIRST_SSE_REG;
          break;
        default:

Reply via email to