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
This commit is contained in:
parent
454ac7c6f3
commit
9eef2659bf
@ -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">;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
13
clang/test/Sema/big-endian-neon-initializers.c
Normal file
13
clang/test/Sema/big-endian-neon-initializers.c
Normal file
@ -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};
|
||||
Loading…
x
Reference in New Issue
Block a user