diff options
-rw-r--r-- | lib/Sema/SemaChecking.cpp | 57 | ||||
-rw-r--r-- | test/Sema/arm-neon-types.c | 8 | ||||
-rw-r--r-- | utils/TableGen/NeonEmitter.cpp | 28 |
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"; |