aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Sema/SemaChecking.cpp57
-rw-r--r--test/Sema/arm-neon-types.c8
-rw-r--r--utils/TableGen/NeonEmitter.cpp28
3 files changed, 80 insertions, 13 deletions
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 90b9738039..cd07358b15 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -268,11 +268,38 @@ static unsigned RFT(unsigned t, bool shift = false) {
return 0;
}
+/// getNeonEltType - Return the QualType corresponding to the elements of
+/// the vector type specified by the NeonTypeFlags. This is used to check
+/// the pointer arguments for Neon load/store intrinsics.
+static QualType getNeonEltType(NeonTypeFlags Flags, ASTContext &Context) {
+ switch (Flags.getEltType()) {
+ case NeonTypeFlags::Int8:
+ return Flags.isUnsigned() ? Context.UnsignedCharTy : Context.SignedCharTy;
+ case NeonTypeFlags::Int16:
+ return Flags.isUnsigned() ? Context.UnsignedShortTy : Context.ShortTy;
+ case NeonTypeFlags::Int32:
+ return Flags.isUnsigned() ? Context.UnsignedIntTy : Context.IntTy;
+ case NeonTypeFlags::Int64:
+ return Flags.isUnsigned() ? Context.UnsignedLongLongTy : Context.LongLongTy;
+ case NeonTypeFlags::Poly8:
+ return Context.SignedCharTy;
+ case NeonTypeFlags::Poly16:
+ return Context.ShortTy;
+ case NeonTypeFlags::Float16:
+ return Context.UnsignedShortTy;
+ case NeonTypeFlags::Float32:
+ return Context.FloatTy;
+ }
+ return QualType();
+}
+
bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
llvm::APSInt Result;
unsigned mask = 0;
unsigned TV = 0;
+ bool HasPtr = false;
+ bool HasConstPtr = false;
switch (BuiltinID) {
#define GET_NEON_OVERLOAD_CHECK
#include "clang/Basic/arm_neon.inc"
@@ -281,15 +308,39 @@ bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
// For NEON intrinsics which are overloaded on vector element type, validate
// the immediate which specifies which variant to emit.
+ unsigned ImmArg = TheCall->getNumArgs()-1;
if (mask) {
- unsigned ArgNo = TheCall->getNumArgs()-1;
- if (SemaBuiltinConstantArg(TheCall, ArgNo, Result))
+ if (SemaBuiltinConstantArg(TheCall, ImmArg, Result))
return true;
TV = Result.getLimitedValue(64);
if ((TV > 63) || (mask & (1 << TV)) == 0)
return Diag(TheCall->getLocStart(), diag::err_invalid_neon_type_code)
- << TheCall->getArg(ArgNo)->getSourceRange();
+ << TheCall->getArg(ImmArg)->getSourceRange();
+ }
+
+ if (HasPtr || HasConstPtr) {
+ // Check that pointer arguments have the specified type.
+ for (unsigned ArgNo = 0; ArgNo < ImmArg; ++ArgNo) {
+ Expr *Arg = TheCall->getArg(ArgNo);
+ if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg))
+ Arg = ICE->getSubExpr();
+ ExprResult RHS = DefaultFunctionArrayLvalueConversion(Arg);
+ QualType RHSTy = RHS.get()->getType();
+ if (!RHSTy->isPointerType())
+ continue;
+ QualType EltTy = getNeonEltType(NeonTypeFlags(TV), Context);
+ if (HasConstPtr)
+ EltTy = EltTy.withConst();
+ QualType LHSTy = Context.getPointerType(EltTy);
+ AssignConvertType ConvTy;
+ ConvTy = CheckSingleAssignmentConstraints(LHSTy, RHS);
+ if (RHS.isInvalid())
+ return true;
+ if (DiagnoseAssignmentResult(ConvTy, Arg->getLocStart(), LHSTy, RHSTy,
+ RHS.get(), AA_Assigning))
+ return true;
+ }
}
// For NEON intrinsics which take an immediate value as part of the
diff --git a/test/Sema/arm-neon-types.c b/test/Sema/arm-neon-types.c
index 4be83da970..7bb605d9b1 100644
--- a/test/Sema/arm-neon-types.c
+++ b/test/Sema/arm-neon-types.c
@@ -25,3 +25,11 @@ int32x4_t test4(int32x4_t a, vSInt32 b) {
b += a;
return b += a;
}
+
+// Warn for incompatible pointer types used with vld/vst intrinsics.
+int16x8_t test5(int *p) {
+ return vld1q_s16(p); // expected-warning {{incompatible pointer types}}
+}
+void test6(float *p, int32x2_t v) {
+ return vst1_s32(p, v); // expected-warning {{incompatible pointer types}}
+}
diff --git a/utils/TableGen/NeonEmitter.cpp b/utils/TableGen/NeonEmitter.cpp
index f393dff614..fec16b957e 100644
--- a/utils/TableGen/NeonEmitter.cpp
+++ b/utils/TableGen/NeonEmitter.cpp
@@ -526,12 +526,6 @@ static std::string GenMacroLocals(const std::string &proto, StringRef typestr) {
for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
// Do not create a temporary for an immediate argument.
// That would defeat the whole point of using a macro!
- // FIXME: For other (non-immediate) arguments that are used directly, a
- // local temporary (or some other method) is still needed to get the
- // correct type checking, even if that temporary is not used for anything.
- // This is omitted for now because it turns out the the use of
- // "__extension__" in the macro disables any warnings from the pointer
- // assignment.
if (MacroArgUsedDirectly(proto, i))
continue;
generatedLocal = true;
@@ -1342,14 +1336,28 @@ void NeonEmitter::runHeader(raw_ostream &OS) {
mask |= 1 << GetNeonEnum(Proto, TypeVec[ti]);
}
}
- if (mask)
+ bool HasPtr = (Proto.find('p') != std::string::npos);
+ bool HasConstPtr = (Proto.find('c') != std::string::npos);
+ if (mask) {
OS << "case ARM::BI__builtin_neon_"
<< MangleName(name, TypeVec[si], ClassB)
- << ": mask = " << "0x" << utohexstr(mask) << "; break;\n";
- if (qmask)
+ << ": mask = " << "0x" << utohexstr(mask);
+ if (HasPtr)
+ OS << "; HasPtr = true";
+ if (HasConstPtr)
+ OS << "; HasConstPtr = true";
+ OS << "; break;\n";
+ }
+ if (qmask) {
OS << "case ARM::BI__builtin_neon_"
<< MangleName(name, TypeVec[qi], ClassB)
- << ": mask = " << "0x" << utohexstr(qmask) << "; break;\n";
+ << ": mask = " << "0x" << utohexstr(qmask);
+ if (HasPtr)
+ OS << "; HasPtr = true";
+ if (HasConstPtr)
+ OS << "; HasConstPtr = true";
+ OS << "; break;\n";
+ }
}
OS << "#endif\n\n";