]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
rs6000: Don't fold stuff for C++ during targetm.resolve_overloaded_builtin [PR124133]
authorJakub Jelinek <jakub@redhat.com>
Fri, 24 Apr 2026 12:50:23 +0000 (14:50 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Fri, 24 Apr 2026 12:50:23 +0000 (14:50 +0200)
The following testcase ICEs starting with the removal of NON_DEPENDENT_EXPR
in GCC 14.  The problem is that while parsing templates if all the arguments
of the overloaded builtins are non-dependent types,
targetm.resolve_overloaded_builtin can be called on it.  And trying to
fold_convert or fold_build2 subexpressions of such arguments can ICE,
because they can contain various FE specific trees, or standard trees
with NULL_TREE types, or e.g. type mismatches in binary tree operands etc.
All that goes away later when the trees are instantiated and
targetm.resolve_overloaded_builtin is called again, but if it ICEs while
doing that, it won't reach that point.  And the reason to call that
hook in that case if none of the arguments are type dependent is to figure
out if the result type is also non-dependent.

Given the general desire to fold stuff in the FE during parsing as little
as possible and fold it only during cp_fold later on and because from the
target *-c.cc files it isn't easily possible to find out if it is
processing_template_decl or not, the following patch just stops folding
anything in the arguments, calls convert instead of fold_convert and
just build2 instead of fold_build2 etc. when in C++ (and keeps doing what
it did for C).

2026-04-24  Jakub Jelinek  <jakub@redhat.com>

PR target/124133
* config/rs6000/rs6000-c.cc (c_fold_convert): New function.
(c_fold_build2_loc): Likewise.
(fully_fold_convert): Use c_fold_convert instead of fold_convert.
(altivec_build_resolved_builtin): Likewise.  Use c_fold_build2_loc
instead of fold_build2.
(resolve_vec_mul, resolve_vec_adde_sube, resolve_vec_addec_subec):
Use c_fold_build2_loc instead of fold_build2_loc.
(resolve_vec_splats, resolve_vec_extract): Use c_fold_convert instead
of fold_convert.
(resolve_vec_insert): Use c_fold_build2_loc instead of fold_build2.
(altivec_resolve_overloaded_builtin): Use c_fold_convert instead
of fold_convert.

* g++.target/powerpc/pr124133-1.C: New test.
* g++.target/powerpc/pr124133-2.C: New test.

Reviewed-by: Michael Meissner <meissner@linux.ibm.com>
gcc/config/rs6000/rs6000-c.cc
gcc/testsuite/g++.target/powerpc/pr124133-1.C [new file with mode: 0644]
gcc/testsuite/g++.target/powerpc/pr124133-2.C [new file with mode: 0644]

index 8c221b71b8d39cce9a29e935278e3563c9910894..f6cc8923775824b0010b00f777026b03c8ee5d01 100644 (file)
@@ -835,14 +835,40 @@ rs6000_builtin_type_compatible (tree parmtype, tree argtype)
   return lang_hooks.types_compatible_p (parmtype, argtype);
 }
 
-/* In addition to calling fold_convert for EXPR of type TYPE, also
+/* Return fold_convert (TYPE, EXPR) for C and convert (TYPE, EXPR)
+   for C++.  The latter is needed because resolve_overloaded_builtin
+   can be called when parsing templates too if they don't have type
+   dependent operands, but the nested trees might not be usable in
+   GENERIC folding.  */
+
+static tree
+c_fold_convert (tree type, tree expr)
+{
+  return c_dialect_cxx () ? convert (type, expr) : fold_convert (type, expr);
+}
+
+/* Similar wrapper for fold_build2_loc.  For C++ just call build2_loc.  */
+
+static tree
+c_fold_build2_loc (location_t loc, enum tree_code code, tree type, tree arg0,
+                  tree arg1)
+{
+  if (!c_dialect_cxx ())
+    return fold_build2_loc (loc, code, type, arg0, arg1);
+  else if (loc != UNKNOWN_LOCATION)
+    return build2_loc (loc, code, type, arg0, arg1);
+  else
+    return build2 (code, type, arg0, arg1);
+}
+
+/* In addition to calling c_fold_convert for EXPR of type TYPE, also
    call c_fully_fold to remove any C_MAYBE_CONST_EXPRs that could be
    hiding there (PR47197).  */
 
 static tree
 fully_fold_convert (tree type, tree expr)
 {
-  tree result = fold_convert (type, expr);
+  tree result = c_fold_convert (type, expr);
   bool maybe_const = true;
 
   if (!c_dialect_cxx ())
@@ -855,7 +881,7 @@ fully_fold_convert (tree type, tree expr)
    The overloaded builtin that matched the types and args is described
    by DESC.  The N arguments are given in ARGS, respectively.
 
-   Actually the only thing it does is calling fold_convert on ARGS, with
+   Actually the only thing it does is calling c_fold_convert on ARGS, with
    a small exception for vec_{all,any}_{ge,le} predicates. */
 
 static tree
@@ -891,8 +917,9 @@ altivec_build_resolved_builtin (tree *args, int n, tree fntype, tree ret_type,
       std::swap (args[1], args[2]);
       std::swap (arg_type[1], arg_type[2]);
 
-      args[0] = fold_build2 (BIT_XOR_EXPR, TREE_TYPE (args[0]), args[0],
-                            build_int_cst (NULL_TREE, 2));
+      args[0] = c_fold_build2_loc (UNKNOWN_LOCATION, BIT_XOR_EXPR,
+                                  TREE_TYPE (args[0]), args[0],
+                                  build_int_cst (NULL_TREE, 2));
     }
 
   for (int j = 0; j < n; j++)
@@ -923,7 +950,7 @@ altivec_build_resolved_builtin (tree *args, int n, tree fntype, tree ret_type,
     default:
       gcc_unreachable ();
     }
-  return fold_convert (ret_type, call);
+  return c_fold_convert (ret_type, call);
 }
 
 /* Enumeration of possible results from attempted overload resolution.
@@ -964,8 +991,8 @@ resolve_vec_mul (resolution *res, tree *args, tree *types, location_t loc)
     case E_TImode:
       /* For scalar types just use a multiply expression.  */
       *res = resolved;
-      return fold_build2_loc (loc, MULT_EXPR, types[0], args[0],
-                             fold_convert (types[0], args[1]));
+      return c_fold_build2_loc (loc, MULT_EXPR, types[0], args[0],
+                               c_fold_convert (types[0], args[1]));
     case E_SFmode:
       {
        /* For floats use the xvmulsp instruction directly.  */
@@ -1108,8 +1135,8 @@ resolve_vec_adde_sube (resolution *res, rs6000_gen_builtins fcode,
                                                        params);
        tree const1 = build_int_cstu (TREE_TYPE (types[0]), 1);
        tree ones_vector = build_vector_from_val (types[0], const1);
-       tree and_expr = fold_build2_loc (loc, BIT_AND_EXPR, types[0],
-                                        args[2], ones_vector);
+       tree and_expr = c_fold_build2_loc (loc, BIT_AND_EXPR, types[0],
+                                          args[2], ones_vector);
        params = make_tree_vector ();
        vec_safe_push (params, call);
        vec_safe_push (params, and_expr);
@@ -1194,8 +1221,8 @@ resolve_vec_addec_subec (resolution *res, rs6000_gen_builtins fcode,
                                                         params);
        tree const1 = build_int_cstu (TREE_TYPE (types[0]), 1);
        tree ones_vector = build_vector_from_val (types[0], const1);
-       tree and_expr = fold_build2_loc (loc, BIT_AND_EXPR, types[0],
-                                        args[2], ones_vector);
+       tree and_expr = c_fold_build2_loc (loc, BIT_AND_EXPR, types[0],
+                                          args[2], ones_vector);
        params = make_tree_vector ();
        vec_safe_push (params, call2);
        vec_safe_push (params, and_expr);
@@ -1303,7 +1330,7 @@ resolve_vec_splats (resolution *res, rs6000_gen_builtins fcode,
       return error_mark_node;
     }
 
-  arg = save_expr (fold_convert (TREE_TYPE (type), arg));
+  arg = save_expr (c_fold_convert (TREE_TYPE (type), arg));
   vec<constructor_elt, va_gc> *vec;
   vec_alloc (vec, size);
 
@@ -1442,7 +1469,7 @@ resolve_vec_extract (resolution *res, vec<tree, va_gc> *arglist,
          tree result = build_call_expr (call, 2, arg1, arg2);
          /* Coerce the result to vector element type.  May be no-op.  */
          arg1_inner_type = TREE_TYPE (arg1_type);
-         result = fold_convert (arg1_inner_type, result);
+         result = c_fold_convert (arg1_inner_type, result);
          *res = resolved;
          return result;
        }
@@ -1566,8 +1593,9 @@ resolve_vec_insert (resolution *res, vec<tree, va_gc> *arglist,
   if (TARGET_VSX)
     {
       stmt = build_array_ref (loc, stmt, arg2);
-      stmt = fold_build2 (MODIFY_EXPR, TREE_TYPE (arg0), stmt,
-                         convert (TREE_TYPE (stmt), arg0));
+      stmt = c_fold_build2_loc (UNKNOWN_LOCATION, MODIFY_EXPR,
+                               TREE_TYPE (arg0), stmt,
+                               convert (TREE_TYPE (stmt), arg0));
       stmt = build2 (COMPOUND_EXPR, arg1_type, stmt, decl);
     }
   else
@@ -1791,7 +1819,7 @@ altivec_resolve_overloaded_builtin (location_t loc, tree fndecl,
                     "const");
          type = build_qualified_type (TREE_TYPE (type), 0);
          type = build_pointer_type (type);
-         arg = fold_convert (type, arg);
+         arg = c_fold_convert (type, arg);
        }
 
       /* For RS6000_OVLD_VEC_LXVL, convert any const * to its non constant
@@ -1802,7 +1830,7 @@ altivec_resolve_overloaded_builtin (location_t loc, tree fndecl,
        {
          type = build_qualified_type (TREE_TYPE (type), 0);
          type = build_pointer_type (type);
-         arg = fold_convert (type, arg);
+         arg = c_fold_convert (type, arg);
        }
 
       args[n] = arg;
diff --git a/gcc/testsuite/g++.target/powerpc/pr124133-1.C b/gcc/testsuite/g++.target/powerpc/pr124133-1.C
new file mode 100644 (file)
index 0000000..688f7fa
--- /dev/null
@@ -0,0 +1,12 @@
+// PR target/124133
+// { dg-options "-mdejagnu-cpu=power8 -mvsx" }
+// { dg-require-effective-target powerpc_vsx }
+
+typedef __INTPTR_TYPE__ intptr_t;
+
+template <int>
+void
+foo (int x, short *y, intptr_t z)
+{
+  __builtin_vec_vsx_ld ((x + z) * 2, y);
+}
diff --git a/gcc/testsuite/g++.target/powerpc/pr124133-2.C b/gcc/testsuite/g++.target/powerpc/pr124133-2.C
new file mode 100644 (file)
index 0000000..a0ae684
--- /dev/null
@@ -0,0 +1,14 @@
+// PR target/124133
+// { dg-options "-mdejagnu-cpu=power8 -mvsx -O2" }
+// { dg-require-effective-target powerpc_vsx }
+
+#include <altivec.h>                                                                                                                                                                  
+                                                                                                                                                                                      
+struct S { float d; unsigned char e[16]; };                                                                                                                                           
+                                                                                                                                                                                      
+template <typename T>                                                                                                                                                                 
+void                                                                                                                                                                                  
+foo (const S *s)                                                                                                                                                                      
+{                                                                                                                                                                                     
+  vector signed char a = (vector signed char) vec_xl (0, s->e);                                                                                                                       
+}