https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67896

--- Comment #1 from Roger Ferrer Ibanez <roger.ferrer at bsc dot es> ---
Hi,

after some debugging I think I understand what happens but I'm not sure I can
provide an acceptable fix for that.

When comparing __Poly8x8_t and __Poly16x8_t types (these are the builtin types
for poly8x8_t and poly16x8_t respectively) in the C++ FE, the sequence involves
"comptypes" and then "structural_comptypes".

Since both types are vectors, the number of elements is the same (i.e.
TYPE_VECTOR_SUBPARTS is 8 for the two vector types), so it only remains to
check the element type (i.e. the TREE_TYPE) of the vector (these are __Poly8_t
and __Poly16_t). At this point "structural_comptypes" sees that both types are
INTEGER_TYPE and then proceeds to compare them using TYPE_CANONICAL but at this
point for both types the canonical type is NULL, so the structural comparison
trivially succeeds.

Types __Poly8x8_t and __Poly16x8_t are initialized in
"aarch64_init_simd_builtin_types" in "gcc/config/aarch64/aarch64-builtins.c".
There is an array of structs, called aarch64_simd_types, with two fields, among
others, eltype (element type) and itype (internal type).

At some point the code initializes the several __PolyS_t (where S = {8, 16, 64,
128}) with a distinct type of integer type {QI, HI, DI, TI} (note that itype is
also initialized)

  aarch64_simd_types[Poly8_t].eltype = aarch64_simd_types[Poly8_t].itype =
    build_distinct_type_copy (unsigned_intQI_type_node);
  aarch64_simd_types[Poly16_t].eltype = aarch64_simd_types[Poly16_t].itype =
    build_distinct_type_copy (unsigned_intHI_type_node);
  ...

and a bit later it makes sure __PolySxN_t have their element type to their
respective __PolyS_t.

  aarch64_simd_types[Poly8x8_t].eltype = aarch64_simd_types[Poly8_t].itype;
  ...
  aarch64_simd_types[Poly16x8_t].eltype = aarch64_simd_types[Poly16_t].itype;

And it finally proceeds to build the vector types except if the itype is not
null. Only the nonvector __PolyS_t types have a non-null itype (it was assigned
above) so they are not set a vector type.

  for (i = 0; i < nelts; i++)
    {
      tree eltype = aarch64_simd_types[i].eltype;
      enum machine_mode mode = aarch64_simd_types[i].mode;

      if (aarch64_simd_types[i].itype == NULL)
        aarch64_simd_types[i].itype =
          build_distinct_type_copy
            (build_vector_type (eltype, GET_MODE_NUNITS (mode)));

      tdecl = add_builtin_type (aarch64_simd_types[i].name,
                                aarch64_simd_types[i].itype);
      TYPE_NAME (aarch64_simd_types[i].itype) = tdecl;
      SET_TYPE_STRUCTURAL_EQUALITY (aarch64_simd_types[i].itype);
    }

The last statement in the loop ensures that the type is compared using
structural equality. This effectively sets the canonical type to zero,
according to the macro in tree.h

#define SET_TYPE_STRUCTURAL_EQUALITY(NODE) (TYPE_CANONICAL (NODE) = NULL_TREE)

My knowledge of the internals of GCC is too limited at this point to state
whether setting structural equality for all these types is OK. I think, though,
that setting structural equality for the non-vector types (thus nullifying
their canonical type) may be wrong: it makes two __PolyS_N_t types (where N is
the same) identical at the eyes of the C++ FE.

The following crude patch seems to let the C++ FE distinguish the two types.

--- /home/roger/soft/gcc/src/gcc-5.2.0/gcc/config/aarch64/aarch64-builtins.c   
2015-04-01 13:18:03.000000000 +0200
+++ config/aarch64/aarch64-builtins.c   2015-10-11 23:51:05.315828614 +0200
@@ -628,15 +628,20 @@
       tree eltype = aarch64_simd_types[i].eltype;
       enum machine_mode mode = aarch64_simd_types[i].mode;

+      bool is_vector = false;
       if (aarch64_simd_types[i].itype == NULL)
-       aarch64_simd_types[i].itype =
-         build_distinct_type_copy
+       {
+         aarch64_simd_types[i].itype =
+           build_distinct_type_copy
            (build_vector_type (eltype, GET_MODE_NUNITS (mode)));
+         is_vector = true;
+       }

       tdecl = add_builtin_type (aarch64_simd_types[i].name,
                                aarch64_simd_types[i].itype);
       TYPE_NAME (aarch64_simd_types[i].itype) = tdecl;
-      SET_TYPE_STRUCTURAL_EQUALITY (aarch64_simd_types[i].itype);
+      if (is_vector)
+         SET_TYPE_STRUCTURAL_EQUALITY (aarch64_simd_types[i].itype);
     }

 #define AARCH64_BUILD_SIGNED_TYPE(mode)  \


With this change, g++ is able to tell the two types apart.

$ cat test.cc
typedef __Poly8x8_t A;
typedef __Poly16x8_t A;

$ aarch64-linux-gnu-g++ -fsyntax-only test.cc -Wall

test.cc:2:22: error: conflicting declaration ‘typedef __vector(8) __Poly16_t A’
 typedef __Poly16x8_t A;
                      ^
test.cc:1:21: note: previous declaration as ‘typedef __vector(8) __Poly8_t A’
 typedef __Poly8x8_t A;

Caveat: I debugged this problem in a cross-compiler without real hardware so I
do not know if this is OK or not.

Hope this helps.

Kind regards,

Reply via email to