https://gcc.gnu.org/g:17b02d8f2b385cbe0f72a5ed0acf34818934b79e

commit r17-3969-g17b02d8f2b385cbe0f72a5ed0acf34818934b79e
Author: Jakub Jelinek <[email protected]>
Date:   Mon Sep 7 08:46:52 2026 +0200

    Use optabs-libfuncs.cc infrastructure for __floatbitint<mode> and 
__fix<mode>bitint calls
    
    rs6000.cc likes to rename some of the libfuncs for certain names and uses
    set_conv_libfunc/set_optab_libfunc overrides for that.
    
    Unfortunately the large/huge _BitInt <-> binary/decimal floating point
    ifns build the libcall names by hand and so it isn't possible to override
    them (and for pru/c6x which don't support _BitInt yet doesn't add the __gnu
    prefix either).
    
    The following patch adds libcall only optabs for this so that they can
    be overridden and also can be cached, if one has more than one conversion
    from/to _BitInt to certain floating point mode, the name/rtx won't be
    constructed each time again.
    
    Tested additionally on
    _Float128 a;
    long double b;
    _BitInt(176) c;
    _Decimal128 d;
    
    void foo () { a = c; }
    void bar () { b = c; }
    void baz () { c = a; }
    void qux () { c = b; }
    void corge () { d = c; }
    void garply () { c = d; }
    on x86_64-linux (I've verified it emits exactly the same names as before)
    and with an incremental patch on powerpc64le-linux (where it fixed problems
    on that testcase).
    
    2026-09-07  Jakub Jelinek  <[email protected]>
    
            * optabs.def (bitinttofp_optab, bitintfromfp_optab): New optabs.
            * optabs-libfuncs.h (gen_bitint_fp_libfunc): Declare.
            * optabs-libfuncs.cc (gen_interclass_conv_libfunc): Move most of
            the function into ...
            (gen_interclass_conv_libfunc_name_name): New helper function.
            (gen_bitint_fp_libfunc): New function.
            * internal-fn.cc (expand_FLOATTOBITINT): Use
            optab_libfunc (bitintfromfp_optab, mode) instead of constructing
            libcall name manually.
            (expand_BITINTTOFLOAT): Similarly with
            optab_libfunc (bitinttofp_optab, mode).
    
    Reviewed-by: Richard Biener <[email protected]>

Diff:
---
 gcc/internal-fn.cc     | 54 ++------------------------------------
 gcc/optabs-libfuncs.cc | 70 +++++++++++++++++++++++++++++++++++++-------------
 gcc/optabs-libfuncs.h  |  1 +
 gcc/optabs.def         |  3 +++
 4 files changed, 58 insertions(+), 70 deletions(-)

diff --git a/gcc/internal-fn.cc b/gcc/internal-fn.cc
index 0138c6f7ef01..c57b594ac591 100644
--- a/gcc/internal-fn.cc
+++ b/gcc/internal-fn.cc
@@ -5722,32 +5722,7 @@ expand_FLOATTOBITINT (internal_fn, gcall *stmt)
   rtx arg0 = expand_normal (gimple_call_arg (stmt, 0));
   rtx arg1 = expand_normal (gimple_call_arg (stmt, 1));
   rtx arg2 = expand_normal (gimple_call_arg (stmt, 2));
-  const char *mname = GET_MODE_NAME (mode);
-  unsigned mname_len = strlen (mname);
-  int len = 12 + mname_len;
-  if (DECIMAL_FLOAT_MODE_P (mode))
-    len += 4;
-  char *libfunc_name = XALLOCAVEC (char, len);
-  char *p = libfunc_name;
-  const char *q;
-  if (DECIMAL_FLOAT_MODE_P (mode))
-    {
-#if ENABLE_DECIMAL_BID_FORMAT
-      memcpy (p, "__bid_fix", 9);
-#else
-      memcpy (p, "__dpd_fix", 9);
-#endif
-      p += 9;
-    }
-  else
-    {
-      memcpy (p, "__fix", 5);
-      p += 5;
-    }
-  for (q = mname; *q; q++)
-    *p++ = TOLOWER (*q);
-  memcpy (p, "bitint", 7);
-  rtx fun = init_one_libfunc (libfunc_name);
+  rtx fun = optab_libfunc (bitintfromfp_optab, mode);
   emit_library_call (fun, LCT_NORMAL, VOIDmode, arg0, ptr_mode, arg1,
                     SImode, arg2, mode);
 }
@@ -5761,32 +5736,7 @@ expand_BITINTTOFLOAT (internal_fn, gcall *stmt)
   machine_mode mode = TYPE_MODE (TREE_TYPE (lhs));
   rtx arg0 = expand_normal (gimple_call_arg (stmt, 0));
   rtx arg1 = expand_normal (gimple_call_arg (stmt, 1));
-  const char *mname = GET_MODE_NAME (mode);
-  unsigned mname_len = strlen (mname);
-  int len = 14 + mname_len;
-  if (DECIMAL_FLOAT_MODE_P (mode))
-    len += 4;
-  char *libfunc_name = XALLOCAVEC (char, len);
-  char *p = libfunc_name;
-  const char *q;
-  if (DECIMAL_FLOAT_MODE_P (mode))
-    {
-#if ENABLE_DECIMAL_BID_FORMAT
-      memcpy (p, "__bid_floatbitint", 17);
-#else
-      memcpy (p, "__dpd_floatbitint", 17);
-#endif
-      p += 17;
-    }
-  else
-    {
-      memcpy (p, "__floatbitint", 13);
-      p += 13;
-    }
-  for (q = mname; *q; q++)
-    *p++ = TOLOWER (*q);
-  *p = '\0';
-  rtx fun = init_one_libfunc (libfunc_name);
+  rtx fun = optab_libfunc (bitinttofp_optab, mode);
   rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
   rtx val = emit_library_call_value (fun, target, LCT_PURE, mode,
                                     arg0, ptr_mode, arg1, SImode);
diff --git a/gcc/optabs-libfuncs.cc b/gcc/optabs-libfuncs.cc
index 1b201e915afa..1866b7f3acf2 100644
--- a/gcc/optabs-libfuncs.cc
+++ b/gcc/optabs-libfuncs.cc
@@ -362,22 +362,16 @@ gen_int_unsigned_fixed_libfunc (optab optable, const char 
*name, char suffix,
     gen_unsigned_fixed_libfunc (optable, name, suffix, mode);
 }
 
-/* Initialize the libfunc fields of an entire group of entries of an
-   inter-mode-class conversion optab.  The string formation rules are
-   similar to the ones for init_libfuncs, above, but instead of having
-   a mode name and an operand count these functions have two mode names
-   and no operand count.  */
+/* Helper function for gen_interclass_conv_libfunc and gen_bitint_fp_libfunc.
+   Return name for interclass conversion function.  */
 
-void
-gen_interclass_conv_libfunc (convert_optab tab,
-                            const char *opname,
-                            machine_mode tmode,
-                            machine_mode fmode)
+static const char *
+gen_interclass_conv_libfunc_name (const char *opname, bool decimal_p,
+                                 const char *tname, const char *fname)
 {
   size_t opname_len = strlen (opname);
   size_t mname_len = 0;
 
-  const char *fname, *tname;
   const char *q;
   int prefix_len = targetm.libfunc_gnu_prefix ? 6 : 2;
   char *libfunc_name, *suffix;
@@ -388,7 +382,7 @@ gen_interclass_conv_libfunc (convert_optab tab,
      depends on which underlying decimal floating point format is used.  */
   const size_t dec_len = sizeof (DECIMAL_PREFIX) - 1;
 
-  mname_len = strlen (GET_MODE_NAME (tmode)) + strlen (GET_MODE_NAME (fmode));
+  mname_len = strlen (tname) + strlen (fname);
 
   nondec_name = XALLOCAVEC (char, prefix_len + opname_len + mname_len + 1 + 1);
   nondec_name[0] = '_';
@@ -411,10 +405,7 @@ gen_interclass_conv_libfunc (convert_optab tab,
   memcpy (&dec_name[2+dec_len], opname, opname_len);
   dec_suffix = dec_name + dec_len + opname_len + 2;
 
-  fname = GET_MODE_NAME (fmode);
-  tname = GET_MODE_NAME (tmode);
-
-  if (DECIMAL_FLOAT_MODE_P (fmode) || DECIMAL_FLOAT_MODE_P (tmode))
+  if (decimal_p)
     {
       libfunc_name = dec_name;
       suffix = dec_suffix;
@@ -433,8 +424,28 @@ gen_interclass_conv_libfunc (convert_optab tab,
 
   *p = '\0';
 
-  set_conv_libfunc (tab, tmode, fmode,
-                   ggc_alloc_string (libfunc_name, p - libfunc_name));
+  return ggc_alloc_string (libfunc_name, p - libfunc_name);
+}
+
+/* Initialize the libfunc fields of an entire group of entries of an
+   inter-mode-class conversion optab.  The string formation rules are
+   similar to the ones for init_libfuncs, above, but instead of having
+   a mode name and an operand count these functions have two mode names
+   and no operand count.  */
+
+void
+gen_interclass_conv_libfunc (convert_optab tab,
+                            const char *opname,
+                            machine_mode tmode,
+                            machine_mode fmode)
+{
+  const char *name
+    = gen_interclass_conv_libfunc_name (opname,
+                                       DECIMAL_FLOAT_MODE_P (fmode)
+                                       || DECIMAL_FLOAT_MODE_P (tmode),
+                                       GET_MODE_NAME (tmode),
+                                       GET_MODE_NAME (fmode));
+  set_conv_libfunc (tab, tmode, fmode, name);
 }
 
 /* Same as gen_interclass_conv_libfunc but verify that we are producing
@@ -703,6 +714,29 @@ gen_satfractuns_conv_libfunc (convert_optab tab,
   gen_interclass_conv_libfunc (tab, opname, tmode, fmode);
 }
 
+/* Pick proper libcall for bitinttofp_optab and bitintfromfp_optab.  */
+
+void
+gen_bitint_fp_libfunc (optab optable, const char *opname, char suffix,
+                      machine_mode mode)
+{
+  if (DECIMAL_FLOAT_MODE_P (mode) || GET_MODE_CLASS (mode) == MODE_FLOAT)
+    {
+      const char *name;
+      if (suffix == '0')
+       name = gen_interclass_conv_libfunc_name (opname,
+                                                DECIMAL_FLOAT_MODE_P (mode),
+                                                GET_MODE_NAME (mode),
+                                                "bitint");
+      else
+       name = gen_interclass_conv_libfunc_name (opname,
+                                                DECIMAL_FLOAT_MODE_P (mode),
+                                                "bitint",
+                                                GET_MODE_NAME (mode));
+      set_optab_libfunc (optable, mode, name);
+    }
+}
+
 /* Hashtable callbacks for libfunc_decls.  */
 
 struct libfunc_decl_hasher : ggc_ptr_hash<tree_node>
diff --git a/gcc/optabs-libfuncs.h b/gcc/optabs-libfuncs.h
index 8ce6fdcad13a..3fd5244a89a1 100644
--- a/gcc/optabs-libfuncs.h
+++ b/gcc/optabs-libfuncs.h
@@ -37,6 +37,7 @@ void gen_int_fp_signed_fixed_libfunc (optab, const char *, 
char, machine_mode);
 void gen_int_fixed_libfunc (optab, const char *, char, machine_mode);
 void gen_int_signed_fixed_libfunc (optab, const char *, char, machine_mode);
 void gen_int_unsigned_fixed_libfunc (optab, const char *, char, machine_mode);
+void gen_bitint_fp_libfunc (optab, const char *, char, machine_mode);
 
 void gen_interclass_conv_libfunc (convert_optab, const char *,
                                  machine_mode, machine_mode);
diff --git a/gcc/optabs.def b/gcc/optabs.def
index 327e3efaf8a9..37738f396ddf 100644
--- a/gcc/optabs.def
+++ b/gcc/optabs.def
@@ -207,6 +207,9 @@ OPTAB_NL(unord_optab, NULL, UNORDERED, "unord", '2', 
gen_fp_libfunc)
 
 OPTAB_NL(powi_optab, NULL, UNKNOWN, "powi", '2', gen_fp_libfunc)
 
+OPTAB_NL(bitinttofp_optab, NULL, UNKNOWN, "float", '0', gen_bitint_fp_libfunc)
+OPTAB_NL(bitintfromfp_optab, NULL, UNKNOWN, "fix", '1', gen_bitint_fp_libfunc)
+
 /* These are all initialized individually, on a per-host basis.  */
 OPTAB_NC(sqrt_optab, "sqrt$a2", SQRT)
 OPTAB_NC(sync_old_add_optab, "sync_old_add$I$a", UNKNOWN)

Reply via email to