From: James Molloy Date: Fri, 20 Jun 2014 14:35:13 +0000 (+0000) Subject: The ability to use vector initializer lists is a GNU vector extension X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=9eef2659bf60af09e06e4e65f97cd34fb207cae9;p=platform%2Fupstream%2Fllvm.git 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. llvm-svn: 211362 --- diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index e6c8b9a..f7f08fc 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/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>; +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/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 3dfeb8e..606108c 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/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(); + 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 index 0000000..ffe3109 --- /dev/null +++ b/clang/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 + +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};