Hi! The C and C++ FE handle resolve_overloaded_builtin differently, the C FE calls it when e.g. array-to-pointer and function-to-pointer conversions are already done on the arguments, while C++ FE does that only much later. The c-common code e.g. for __sync/__atomic builtins deals with that e.g. by: if (TREE_CODE (type) == ARRAY_TYPE) { /* Force array-to-pointer decay for C++. */ gcc_assert (c_dialect_cxx()); (*params)[0] = default_conversion ((*params)[0]); type = TREE_TYPE ((*params)[0]); } while the rs6000 md hook uses default_conversion only in one spot (the generic handling), but for vec_ld and vec_st does something on its own. What is even worse is that for vec_ld, it does that too late, there is a fold_convert in between for the case where the element type is qualified, and that only works if the argument is pointer, not array (in which case it ICEs). So, the following patch moves the vec_ld conversion earlier and for both vec_ld and vec_st uses what c-common as well as later altivec_resolve_overloaded_builtin uses.
Bootstrapped/regtested on powerpc64-linux (regtest with {,-m32}), ok for trunk? 2017-09-07 Jakub Jelinek <ja...@redhat.com> PR target/82112 * config/rs6000/rs6000-c.c (altivec_resolve_overloaded_builtin): For ALTIVEC_BUILTIN_VEC_LD if arg1 has array type call default_conversion on it early, rather than manual conversion late. For ALTIVEC_BUILTIN_VEC_ST if arg2 has array type call default_conversion instead of performing manual conversion. * g++.dg/ext/altivec-18.C: New test. --- gcc/config/rs6000/rs6000-c.c.jj 2017-09-01 09:26:55.000000000 +0200 +++ gcc/config/rs6000/rs6000-c.c 2017-09-06 15:43:11.719590365 +0200 @@ -6478,7 +6478,14 @@ altivec_resolve_overloaded_builtin (loca /* Strip qualifiers like "const" from the pointer arg. */ tree arg1_type = TREE_TYPE (arg1); - if (!POINTER_TYPE_P (arg1_type) && TREE_CODE (arg1_type) != ARRAY_TYPE) + if (TREE_CODE (arg1_type) == ARRAY_TYPE) + { + /* Force array-to-pointer decay for C++. */ + gcc_assert (c_dialect_cxx ()); + arg1 = default_conversion (arg1); + arg1_type = TREE_TYPE (arg1); + } + if (!POINTER_TYPE_P (arg1_type)) goto bad; tree inner_type = TREE_TYPE (arg1_type); @@ -6498,15 +6505,6 @@ altivec_resolve_overloaded_builtin (loca if (!ptrofftype_p (TREE_TYPE (arg0))) arg0 = build1 (NOP_EXPR, sizetype, arg0); - tree arg1_type = TREE_TYPE (arg1); - if (TREE_CODE (arg1_type) == ARRAY_TYPE) - { - arg1_type = TYPE_POINTER_TO (TREE_TYPE (arg1_type)); - tree const0 = build_int_cstu (sizetype, 0); - tree arg1_elt0 = build_array_ref (loc, arg1, const0); - arg1 = build1 (ADDR_EXPR, arg1_type, arg1_elt0); - } - tree addr = fold_build2_loc (loc, POINTER_PLUS_EXPR, arg1_type, arg1, arg0); tree aligned = fold_build2_loc (loc, BIT_AND_EXPR, arg1_type, addr, @@ -6563,10 +6561,10 @@ altivec_resolve_overloaded_builtin (loca tree arg2_type = TREE_TYPE (arg2); if (TREE_CODE (arg2_type) == ARRAY_TYPE) { - arg2_type = TYPE_POINTER_TO (TREE_TYPE (arg2_type)); - tree const0 = build_int_cstu (sizetype, 0); - tree arg2_elt0 = build_array_ref (loc, arg2, const0); - arg2 = build1 (ADDR_EXPR, arg2_type, arg2_elt0); + /* Force array-to-pointer decay for C++. */ + gcc_assert (c_dialect_cxx ()); + arg2 = default_conversion (arg2); + arg2_type = TREE_TYPE (arg2); } /* Find the built-in to make sure a compatible one exists; if not --- gcc/testsuite/g++.dg/ext/altivec-18.C.jj 2017-09-06 15:45:00.673295858 +0200 +++ gcc/testsuite/g++.dg/ext/altivec-18.C 2017-09-06 15:45:36.274872713 +0200 @@ -0,0 +1,14 @@ +// PR target/82112 +// { dg-do compile { target powerpc*-*-* } } +// { dg-require-effective-target powerpc_altivec_ok } +// { dg-options "-save-temps -maltivec" } + +#include <altivec.h> + +__attribute__((aligned (16))) extern const unsigned char c[16]; + +void +foo (void) +{ + vec_ld (0, c); +} Jakub