From 8d4b65e9e44d0653255bbd66b3691bf54c4e4fac Mon Sep 17 00:00:00 2001 From: James Molloy <james.molloy@arm.com> Date: Fri, 20 Jun 2014 14:35:13 +0000 Subject: [PATCH] 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 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@211362 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 10 ++++++ lib/Sema/SemaInit.cpp | 41 ++++++++++++++++++++++ test/Sema/big-endian-neon-initializers.c | 13 +++++++ 3 files changed, 64 insertions(+) create mode 100644 test/Sema/big-endian-neon-initializers.c diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index e6c8b9a34bd..f7f08fc4cbb 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -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">; diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 3dfeb8ecd30..606108c127e 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -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/test/Sema/big-endian-neon-initializers.c b/test/Sema/big-endian-neon-initializers.c new file mode 100644 index 00000000000..ffe310903bc --- /dev/null +++ b/test/Sema/big-endian-neon-initializers.c @@ -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}; -- GitLab