Jason Merrill [Friday, 5 September 2025, 18:34:23 CEST]:
> On 9/5/25 1:03 PM, Matthias Kretz wrote:
> > Okay for trunk? What about backports?
> 
> Regarding backports, I'm generally reluctant to change mangling within a
> release unless the old behavior would always fail loudly.  This case
> looks borderline; it could have worked for a single overload.
> 
> So I'm inclined to say no backports, and control it with -fabi-version
> in 16.  But I'm open to argument.

In my case it was super strange because inlining made the problem go away most 
of the time. But when it happened it was very puzzling; with the assembler 
complaining about a symbol getting defined a second time. With a symbol that 
cannot be demangled by c++filt.

I would assume that float16_t template arguments are rather niche and barely 
useful. (I use it for test code for std::simd::vec<std::float16_t>.) Also 
float16_t + float template args are C++20 and up, which is still experimental, 
right?

The cases where it matters most for ABI would be library interfaces. And I 
can't think of a case where you'd have only a single float16_t constant baked 
into a library ABI. IOW, if you're using it know where it matters for ABI then 
it doesn't assemble/link without this change.

If you want me to adjust the patch for -fabi-version I'd need a pointer how to 
do it.

> > +  if (words == 0)
> > +    {
> > +      int bytes = GET_MODE_BITSIZE (SCALAR_FLOAT_TYPE_MODE (type)) / 8;
> > +      real_to_target (target_real, &TREE_REAL_CST (value),
> > +                 TYPE_MODE (type));
> 
> It seems we could share this call with the other case, since the
> arguments look the same?

Done.

> > +      sprintf (buffer, "%04lx", (unsigned long) target_real[0]);
> > +      if (bytes == 2)
> > +   write_chars (buffer, 4);
> > +      else
> > +   write_chars (buffer + 2, 2);
> > +      return;
> > +    }
> 
> How about an assert that if words > 0, bitsize % 32 == 0?

I actually thought about an assert that bytes == 2 when words == 0. I don't 
think there's a 1-Byte real type on any GCC target yet (though NVidia 
apparently has hardware even for 4-Bit floats).

Hmm, would this fail for x86 long double, which is 80 bits? OK, just checked. 
It's mangled as 12/16 bytes on i686/x86_64.

Personally, I find non-power-of-2 fundamental types very surprising.

New patch:

----------------------- 8< ----------------------

Signed-off-by: Matthias Kretz <[email protected]>

gcc/testsuite/ChangeLog:

        * g++.dg/pr121801_float16_cst_mangling.C: New test.

gcc/cp/ChangeLog:

        * mangle.cc (write_real_cst): Handle reals that are smaller than
        32 bits.
---
 gcc/cp/mangle.cc                                 | 16 +++++++++++++++-
 .../g++.dg/pr121801_float16_cst_mangling.C       | 12 ++++++++++++
 2 files changed, 27 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/pr121801_float16_cst_mangling.C

diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc
index 80be40d2dce..605768ddc85 100644
--- a/gcc/cp/mangle.cc
+++ b/gcc/cp/mangle.cc
@@ -2176,11 +2176,25 @@ write_real_cst (const tree value)
   int i, limit, dir;
 
   tree type = TREE_TYPE (value);
-  int words = GET_MODE_BITSIZE (SCALAR_FLOAT_TYPE_MODE (type)) / 32;
+  int bits = GET_MODE_BITSIZE (SCALAR_FLOAT_TYPE_MODE (type));
+  int words = bits / 32;
 
   real_to_target (target_real, &TREE_REAL_CST (value),
                  TYPE_MODE (type));
 
+  if (words == 0)
+    {
+      int bytes = bits / 8;
+      sprintf (buffer, "%04lx", (unsigned long) target_real[0]);
+      if (bytes == 2)
+       write_chars (buffer, 4);
+      else
+       write_chars (buffer + 2, 2);
+      return;
+    }
+
+  gcc_assert (bits % 32 == 0);
+
   /* The value in target_real is in the target word order,
      so we must write it out backward if that happens to be
      little-endian.  write_number cannot be used, it will
diff --git a/gcc/testsuite/g++.dg/pr121801_float16_cst_mangling.C b/gcc/
testsuite/g++.dg/pr121801_float16_cst_mangling.C
new file mode 100644
index 00000000000..030822ff1c8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pr121801_float16_cst_mangling.C
@@ -0,0 +1,12 @@
+// PR c++/121801
+// { dg-do compile { target c++20 } }
+
+template<_Float16 T> void f() {}
+
+void uses() {
+  f<_Float16(1)>();
+  f<_Float16(2)>();
+}
+
+// { dg-final { scan-assembler "_Z1fILDF16_3c00EEvv" } }
+// { dg-final { scan-assembler "_Z1fILDF16_4000EEvv" } }


Reply via email to