The ability to use vector initializer lists is a GNU vector extension
authorJames Molloy <james.molloy@arm.com>
Fri, 20 Jun 2014 14:35:13 +0000 (14:35 +0000)
committerJames Molloy <james.molloy@arm.com>
Fri, 20 Jun 2014 14:35:13 +0000 (14:35 +0000)
and is unrelated to the NEON intrinsics in arm_neon.h. On little
endian machines it works fine, however on big endian machines it
exhibits surprising behaviour:

    uint32x2_t x = {42, 64};
    return vget_lane_u32(x, 0); // Will return 64.

Because of this, explicitly call out that it is unsupported on big
endian machines.

This patch will emit the following warning in big-endian mode:

    test.c:3:15: warning: vector initializers are a GNU extension and are not compatible with NEON intrinsics [-Wgnu]
    int32x4_t x = {0, 1, 2, 3};
                  ^
    test.c:3:15: note: consider using vld1q_s32() to initialize a vector from memory, or vcombine_s32(vcreate_s32(), vcreate_s32()) to initialize from integer constants
    1 warning generated.

llvm-svn: 211362

clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/lib/Sema/SemaInit.cpp
clang/test/Sema/big-endian-neon-initializers.c [new file with mode: 0644]

index e6c8b9a..f7f08fc 100644 (file)
@@ -6729,6 +6729,16 @@ def err_invalid_neon_type_code : Error<
   "incompatible constant for this __builtin_neon function">; 
 def err_argument_invalid_range : Error<
   "argument should be a value from %0 to %1">;
+def warn_neon_vector_initializer_non_portable : Warning<
+  "vector initializers are not compatible with NEON intrinsics in big endian "
+  "mode">, InGroup<DiagGroup<"nonportable-vector-initialization">>;
+def note_neon_vector_initializer_non_portable : Note<
+  "consider using vld1_%0%1() to initialize a vector from memory, or "
+  "vcreate_%0%1() to initialize from an integer constant">;
+def note_neon_vector_initializer_non_portable_q : Note<
+  "consider using vld1q_%0%1() to initialize a vector from memory, or "
+  "vcombine_%0%1(vcreate_%0%1(), vcreate_%0%1()) to initialize from integer "
+  "constants">;
 
 def err_builtin_longjmp_invalid_val : Error<
   "argument to __builtin_longjmp must be a constant 1">;
index 3dfeb8e..606108c 100644 (file)
@@ -17,6 +17,7 @@
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/ExprObjC.h"
 #include "clang/AST/TypeLoc.h"
+#include "clang/Basic/TargetInfo.h"
 #include "clang/Sema/Designator.h"
 #include "clang/Sema/Lookup.h"
 #include "clang/Sema/SemaInternal.h"
@@ -1204,6 +1205,46 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity,
       CheckSubElementType(ElementEntity, IList, elementType, Index,
                           StructuredList, StructuredIndex);
     }
+
+    if (VerifyOnly)
+      return;
+
+    bool isBigEndian = SemaRef.Context.getTargetInfo().isBigEndian();
+    const VectorType *T = Entity.getType()->getAs<VectorType>();
+    if (isBigEndian && (T->getVectorKind() == VectorType::NeonVector ||
+                        T->getVectorKind() == VectorType::NeonPolyVector)) {
+      // The ability to use vector initializer lists is a GNU vector extension
+      // and is unrelated to the NEON intrinsics in arm_neon.h. On little
+      // endian machines it works fine, however on big endian machines it 
+      // exhibits surprising behaviour:
+      //
+      //   uint32x2_t x = {42, 64};
+      //   return vget_lane_u32(x, 0); // Will return 64.
+      //
+      // Because of this, explicitly call out that it is non-portable.
+      //
+      SemaRef.Diag(IList->getLocStart(),
+                   diag::warn_neon_vector_initializer_non_portable);
+
+      const char *typeCode;
+      unsigned typeSize = SemaRef.Context.getTypeSize(elementType);
+
+      if (elementType->isFloatingType())
+        typeCode = "f";
+      else if (elementType->isSignedIntegerType())
+        typeCode = "s";
+      else if (elementType->isUnsignedIntegerType())
+        typeCode = "u";
+      else
+        llvm_unreachable("Invalid element type!");
+
+      SemaRef.Diag(IList->getLocStart(),
+                   SemaRef.Context.getTypeSize(VT) > 64 ?
+                   diag::note_neon_vector_initializer_non_portable_q :
+                   diag::note_neon_vector_initializer_non_portable)
+        << typeCode << typeSize;
+    }
+
     return;
   }
 
diff --git a/clang/test/Sema/big-endian-neon-initializers.c b/clang/test/Sema/big-endian-neon-initializers.c
new file mode 100644 (file)
index 0000000..ffe3109
--- /dev/null
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 %s -triple arm64_be -target-feature +neon -verify -fsyntax-only -ffreestanding
+// RUN: %clang_cc1 %s -triple armebv7 -target-cpu cortex-a8 -verify -fsyntax-only -ffreestanding
+
+#include <arm_neon.h>
+
+int32x4_t x = {1, 2, 3, 4}; // expected-warning{{vector initializers are not compatible with NEON intrinsics}} expected-note{{consider using vld1q_s32() to initialize a vector from memory, or vcombine_s32(vcreate_s32(), vcreate_s32()) to initialize from integer constants}}
+int16x4_t y = {1, 2, 3, 4}; // expected-warning{{vector initializers are not compatible with NEON intrinsics}} expected-note{{consider using vld1_s16() to initialize a vector from memory, or vcreate_s16() to initialize from an integer constant}}
+int64x2_t z = {1, 2}; // expected-warning{{vector initializers are not compatible with NEON intrinsics}} expected-note{{consider using vld1q_s64() to initialize a vector from memory, or vcombine_s64(vcreate_s64(), vcreate_s64()) to initialize from integer constants}}
+float32x2_t b = {1, 2}; // expected-warning{{vector initializers are not compatible with NEON intrinsics}} expected-note{{consider using vld1_f32() to initialize a vector from memory, or vcreate_f32() to initialize from an integer constant}}
+
+// No warning expected here.
+typedef int v4si __attribute__ ((vector_size (16)));
+v4si c = {1, 2, 3, 4};