Hello All,

Changes from V1:
        - Dropped rs6000-c.cc change. Resolver needs no modification
          since v2 does not have opaque instance entries.
        - Dropped isopaque field on typeinfo and the corresponding
          complete_vector_type() change; opaque string is now built in
          a self-contained helper make_opaque_fndecl().
        - Dropped parse_first_ovld_entry() and
          maybe_generate_opaque_variant(). v2 does not insert synthetic
          ovlddata entries into the ovlds[] array.
        - Removed the _VOP / __VOP enum entries and the wrong bifids
          they introduced.

Thank You,
Kishan

Before r12-5752 (gd08236359eb229), the public overload declaration for
overloaded PowerPC built-in functions used opaque_V4SI_type_node for all
vector argument and return types.  The C front end's compatibility check
(vector_types_convertible_p in c-family/c-common.cc) has an early-exit
for TYPE_VECTOR_OPAQUE types, so mis-typed vector arguments were passed
silently at that stage and left for altivec_resolve_overloaded_builtin()
to diagnose properly.

r12-5752 switched the new built-in generator to register each overload's
public declaration using the concrete vector type of the first instance
prototype.  This reactivated the front end's early vector-type
check, causing a spurious "use -flax-vector-conversions to permit
conversions between vectors with differing element types"
note before the overload resolver ran, obscuring the real diagnostic
such as "too few arguments".

Fix this in rs6000-gen-builtins.cc by restoring the opaque prototype for
the public overload declaration whenever the overload has by-value
vector arguments or a by-value vector return type.  A new "vop4si"
entry is added to type_map[], mapping to opaque_V4SI_type_node, and a
new helper make_opaque_fndecl() builds the function-type identifier
string with every by-value vector position replaced by "vop4si".
Vector-pointer arguments (e.g. vsc *) remain as it was, because
front-end's pointer-type check does not emit the 
-flax-vector-conversions note anyway.

2026-09-30  Kishan Parmar  <[email protected]>

gcc/ChangeLog:
        * config/rs6000/rs6000-gen-builtins.cc (type_map): Add "vop4si"
        entry mapping to opaque_V4SI.
        (make_opaque_fndecl): New function.  Build a function-type
        identifier string like construct_fntype_id() but with every
        by-value vector position replaced by "vop4si".
        (proto_has_vector_arg): New function.  Return true if a
        prototype has at least one vector argument.
        (write_init_ovld_table): Introduce reg_fndecl. Use
        make_opaque_fndecl() for the public overload declaration when
        the stanza has vector arguments, otherwise use the first
        instance's concrete fndecl as before.  Update the generated
        comment in the output file.  Free reg_fndecl after use when
        it was malloc'd by make_opaque_fndecl().
        (write_init_file): Add pre-pass loop to call
        make_opaque_fndecl() for every stanza with vector arguments
        before the fntype_rbt inorder walk, so that the opaque type
        strings are declared before they are used.

gcc/testsuite/ChangeLog:
        * gcc.target/powerpc/pr104930.c: New test.
---
 gcc/config/rs6000/rs6000-gen-builtins.cc | 179 ++++++++++++++++++++++-
 1 file changed, 171 insertions(+), 8 deletions(-)

diff --git a/gcc/config/rs6000/rs6000-gen-builtins.cc 
b/gcc/config/rs6000/rs6000-gen-builtins.cc
index 08068ba78fd..76dd33bbb90 100644
--- a/gcc/config/rs6000/rs6000-gen-builtins.cc
+++ b/gcc/config/rs6000/rs6000-gen-builtins.cc
@@ -600,6 +600,7 @@ static typemap type_map[] =
     { "v4sf",          "V4SF" },
     { "v4si",          "V4SI" },
     { "v8hi",          "V8HI" },
+    { "vop4si",                "opaque_V4SI" },
     { "vp8hi",         "pixel_V8HI" },
   };
 
@@ -2772,15 +2773,145 @@ write_init_bif_table (void)
     }
 }
 
+/* Build a function-type identifier string like construct_fntype_id() does,
+   but replace every by-value vector position with "vop4si" (opaque_V4SI).
+   This string is used as the public overload declaration so the C front end
+   does not complain about vector type mismatches before the overload resolver
+   runs (PR target/104930).
+
+   Rules for each position:
+     - by-value vector (isvector=1, ispointer=0): use "vop4si".
+     - vector pointer (isvector=1, ispointer=1): As it was, e.g. "pv16qi".
+       Pointer arguments never trigger the -flax-vector-conversions note 
anyway.
+     - everything else: same as construct_fntype_id(), no change.  */
+
+static char *
+make_opaque_fndecl (prototype *protoptr)
+{
+  /* Use the same size estimate as construct_fntype_id.  "vop4si" is 6 chars,
+     same worst-case length as "bv16qi", within the 9-char per-type budget.  */
+  int len = protoptr->nargs ? (protoptr->nargs + 1) * 9 + 6 : 17;
+  char *buf = (char *) malloc (len);
+  int bufi = 0;
+
+  //  Return type
+  if (protoptr->rettype.ispointer)
+    buf[bufi++] = 'p';
+
+  if (protoptr->rettype.isvoid)
+    buf[bufi++] = 'v';
+  else if (protoptr->rettype.isvector && !protoptr->rettype.ispointer)
+    {
+      memcpy (&buf[bufi], "vop4si", 6);
+      bufi += 6;
+    }
+  else
+    {
+      /* Scalar return, or vector-pointer return (e.g. vsc *): emit
+        the concrete type, identical to construct_fntype_id().  */
+      if (protoptr->rettype.isunsigned)
+       buf[bufi++] = 'u';
+      if (protoptr->rettype.isvector)
+       complete_vector_type (&protoptr->rettype, buf, &bufi);
+      else
+       complete_base_type (&protoptr->rettype, buf, &bufi);
+    }
+
+  memcpy (&buf[bufi], "_ftype", 6);
+  bufi += 6;
+
+  // Argument types
+  if (!protoptr->nargs)
+    {
+      memcpy (&buf[bufi], "_v", 2);
+      bufi += 2;
+    }
+  else
+    {
+      typelist *argptr = protoptr->args;
+      for (int i = 0; i < protoptr->nargs; i++, argptr = argptr->next)
+       {
+         assert (argptr);
+         buf[bufi++] = '_';
+
+         if (argptr->info.isvector && !argptr->info.ispointer)
+           {
+             memcpy (&buf[bufi], "vop4si", 6);
+             bufi += 6;
+           }
+         else
+           {
+             /* Non-vector argument, or vector-pointer argument (e.g. vsc *,
+                const vbc *): emit the concrete type, identical to
+                construct_fntype_id().  */
+             if (argptr->info.isconst
+                 && argptr->info.base == BT_INT
+                 && !argptr->info.ispointer)
+               {
+                 buf[bufi++] = 'c';
+                 buf[bufi++] = 'i';
+                 continue;
+               }
+             if (argptr->info.ispointer)
+               {
+                 if (argptr->info.isvoid)
+                   {
+                     if (argptr->info.isconst)
+                       {
+                         memcpy (&buf[bufi], "pcvoid", 6);
+                         bufi += 6;
+                         continue;
+                       }
+                     else
+                       {
+                         buf[bufi++] = 'p';
+                         buf[bufi++] = 'v';
+                         continue;
+                       }
+                   }
+                 else
+                   buf[bufi++] = 'p';
+               }
+             if (argptr->info.isunsigned)
+               buf[bufi++] = 'u';
+             if (argptr->info.isvector)
+               complete_vector_type (&argptr->info, buf, &bufi);
+             else
+               complete_base_type (&argptr->info, buf, &bufi);
+           }
+       }
+      assert (!argptr);
+    }
+
+  buf[bufi] = '\0';
+
+  rbt_insert (&fntype_rbt, buf);
+
+  return buf;
+}
+
+/* Return true if PROTOPTR has at least one vector argument.  */
+static bool
+proto_has_vector_arg (prototype *protoptr)
+{
+  for (typelist *arg = protoptr->args; arg; arg = arg->next)
+    if (arg->info.isvector)
+      return true;
+  return false;
+}
+
 /* Write code to initialize the overload table.  */
 static void
 write_init_ovld_table (void)
 {
   fprintf (init_file, "  int base = RS6000_OVLD_NONE;\n\n");
   fprintf (init_file,
-          "  /* The fndecl for an overload is arbitrarily the first one\n"
-          "     for the overload.  We sort out the real types when\n"
-          "     processing the overload in the gcc front end.  */\n");
+          "  /* The fndecl for the public overload declaration is an opaque-\n"
+          "     typed prototype when the overload has vector arguments.  
This\n"
+          "     avoids a spurious -flax-vector-conversions note in the C/C++\n"
+          "     front end before altivec_resolve_overloaded_builtin() runs.\n"
+          "     See PR target/104930.  For overloads without vector 
arguments\n"
+          "     the first instance's concrete type is used, as before.  */\n");
 
   for (int i = 0; i <= curr_ovld; i++)
     {
@@ -2794,16 +2925,33 @@ write_init_ovld_table (void)
          ovld_stanza *stanza = &ovld_stanzas[ovlds[i].stanza];
          fprintf (init_file, "\n");
 
+         /* If this stanza has vector arguments, register its public
+            declaration with an opaque prototype so that the front end's
+            early argument-type check does not fire before the overload
+            resolver can inspect the actual argument types.  Otherwise
+            use the first instance's concrete fndecl, as before.
+            make_opaque_fndecl() returns a malloc'd buffer, on duplicate
+            the RBT did not take ownership so we must free it after use.  */
+         char *reg_fndecl;
+         bool free_reg_fndecl = false;
+         if (proto_has_vector_arg (&ovlds[i].proto))
+           {
+             reg_fndecl = make_opaque_fndecl (&ovlds[i].proto);
+             free_reg_fndecl = true;
+           }
+         else
+           reg_fndecl = ovlds[i].fndecl;
+
          /* Check whether we have a "tf" token in this string, representing
             a float128_type_node.  It's possible that float128_type_node is
             undefined (occurs for -maltivec -mno-vsx, for example), so we
             must guard against that.  */
-         int tf_found = strstr (ovlds[i].fndecl, "tf") != NULL;
+         int tf_found = strstr (reg_fndecl, "tf") != NULL;
 
          /* Similarly, look for decimal float tokens.  */
-         int dfp_found = (strstr (ovlds[i].fndecl, "sd") != NULL
-                          || strstr (ovlds[i].fndecl, "dd") != NULL
-                          || strstr (ovlds[i].fndecl, "td") != NULL);
+         int dfp_found = (strstr (reg_fndecl, "sd") != NULL
+                          || strstr (reg_fndecl, "dd") != NULL
+                          || strstr (reg_fndecl, "td") != NULL);
 
          if (tf_found)
            {
@@ -2824,7 +2972,7 @@ write_init_ovld_table (void)
                   stanza->intern_name);
          fprintf (init_file,
                   "                            %s,\n",
-                  ovlds[i].fndecl);
+                  reg_fndecl);
          fprintf (init_file,
                   "                            (int)RS6000_OVLD_%s,"
                   " BUILT_IN_MD,\n",
@@ -2844,6 +2992,9 @@ write_init_ovld_table (void)
          fprintf (init_file,
                   "    = RS6000_INST_%s;\n\n",
                   ovlds[i].ovld_id_name);
+
+         if (free_reg_fndecl)
+           free (reg_fndecl);
        }
     }
 }
@@ -2871,6 +3022,18 @@ write_init_file (void)
   write_bif_static_init ();
   write_ovld_static_init ();
 
+  /*   We call make_opaque_fndecl() here first (before the RBT walk below)
+     so that the opaque type strings land in fntype_rbt in time for
+     write_fntype_init() to emit their tree-variable declarations.
+     write_init_ovld_table() calls make_opaque_fndecl() a second time to
+     get the string for fprintf,that second rbt_insert() is a no-op
+     since the string is already in the tree.  Two calls, but the second
+     one is cheap and avoids storing extra pointers in ovld_stanzas.  */
+  for (int i = 0; i <= curr_ovld; i++)
+    if (i == 0 || ovlds[i].stanza != ovlds[i-1].stanza)
+      if (proto_has_vector_arg (&ovlds[i].proto))
+       make_opaque_fndecl (&ovlds[i].proto);
+
   /* The reason to pass pointers to the function instead of accessing
      the rs6000_{{builtin,instance}_info_fntype,overload_info,builtin_decls}
      arrays directly is to decrease size of the already large function and
-- 
2.52.0

Reply via email to