]> granicus.if.org Git - clang/commitdiff
Check pointer types for arguments of Neon load/store macros. rdar://9958031
authorBob Wilson <bob.wilson@apple.com>
Tue, 8 Nov 2011 05:04:11 +0000 (05:04 +0000)
committerBob Wilson <bob.wilson@apple.com>
Tue, 8 Nov 2011 05:04:11 +0000 (05:04 +0000)
The Neon load/store intrinsics need to be implemented as macros to avoid
hiding alignment attributes on the pointer arguments, and the macros can
only evaluate those pointer arguments once (in case they have side effects),
so it has been hard to get the right type checking for those pointers.
I tried various alternatives in the arm_neon.h header, but it's much more
straightforward to just check directly in Sema.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@144075 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaChecking.cpp
test/Sema/arm-neon-types.c
utils/TableGen/NeonEmitter.cpp

index 90b9738039849bb556cb150947dd5f13e7c181f2..cd07358b159a00b97e543fda26d3008e3c290a49 100644 (file)
@@ -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 
index 4be83da970bd5c8cd585a6d4571cf37c38d73783..7bb605d9b14c993593b85e5aa2ca837c0864083e 100644 (file)
@@ -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}}
+}
index f393dff6147acc5928b979ab8287d65f1c74a399..fec16b957efc2830df078b53163c3888d288f855 100644 (file)
@@ -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";