Merge "Fix a bug with compat lib support. Add new namespace to sp<>."
diff --git a/slang_rs_backend.cpp b/slang_rs_backend.cpp
index 3fb9f1a..541efb5 100644
--- a/slang_rs_backend.cpp
+++ b/slang_rs_backend.cpp
@@ -187,321 +187,324 @@
 }
 
 ///////////////////////////////////////////////////////////////////////////////
+void RSBackend::dumpExportVarInfo(llvm::Module *M) {
+  int slotCount = 0;
+  if (mExportVarMetadata == NULL)
+    mExportVarMetadata = M->getOrInsertNamedMetadata(RS_EXPORT_VAR_MN);
+
+  llvm::SmallVector<llvm::Value*, 2> ExportVarInfo;
+
+  // We emit slot information (#rs_object_slots) for any reference counted
+  // RS type or pointer (which can also be bound).
+
+  for (RSContext::const_export_var_iterator I = mContext->export_vars_begin(),
+          E = mContext->export_vars_end();
+       I != E;
+       I++) {
+    const RSExportVar *EV = *I;
+    const RSExportType *ET = EV->getType();
+    bool countsAsRSObject = false;
+
+    // Variable name
+    ExportVarInfo.push_back(
+        llvm::MDString::get(mLLVMContext, EV->getName().c_str()));
+
+    // Type name
+    switch (ET->getClass()) {
+      case RSExportType::ExportClassPrimitive: {
+        const RSExportPrimitiveType *PT =
+            static_cast<const RSExportPrimitiveType*>(ET);
+        ExportVarInfo.push_back(
+            llvm::MDString::get(
+              mLLVMContext, llvm::utostr_32(PT->getType())));
+        if (PT->isRSObjectType()) {
+          countsAsRSObject = true;
+        }
+        break;
+      }
+      case RSExportType::ExportClassPointer: {
+        ExportVarInfo.push_back(
+            llvm::MDString::get(
+              mLLVMContext, ("*" + static_cast<const RSExportPointerType*>(ET)
+                ->getPointeeType()->getName()).c_str()));
+        break;
+      }
+      case RSExportType::ExportClassMatrix: {
+        ExportVarInfo.push_back(
+            llvm::MDString::get(
+              mLLVMContext, llvm::utostr_32(
+                RSExportPrimitiveType::DataTypeRSMatrix2x2 +
+                static_cast<const RSExportMatrixType*>(ET)->getDim() - 2)));
+        break;
+      }
+      case RSExportType::ExportClassVector:
+      case RSExportType::ExportClassConstantArray:
+      case RSExportType::ExportClassRecord: {
+        ExportVarInfo.push_back(
+            llvm::MDString::get(mLLVMContext,
+              EV->getType()->getName().c_str()));
+        break;
+      }
+    }
+
+    mExportVarMetadata->addOperand(
+        llvm::MDNode::get(mLLVMContext, ExportVarInfo));
+    ExportVarInfo.clear();
+
+    if (mRSObjectSlotsMetadata == NULL) {
+      mRSObjectSlotsMetadata =
+          M->getOrInsertNamedMetadata(RS_OBJECT_SLOTS_MN);
+    }
+
+    if (countsAsRSObject) {
+      mRSObjectSlotsMetadata->addOperand(llvm::MDNode::get(mLLVMContext,
+          llvm::MDString::get(mLLVMContext, llvm::utostr_32(slotCount))));
+    }
+
+    slotCount++;
+  }
+}
+
+void RSBackend::dumpExportFunctionInfo(llvm::Module *M) {
+  if (mExportFuncMetadata == NULL)
+    mExportFuncMetadata =
+        M->getOrInsertNamedMetadata(RS_EXPORT_FUNC_MN);
+
+  llvm::SmallVector<llvm::Value*, 1> ExportFuncInfo;
+
+  for (RSContext::const_export_func_iterator
+          I = mContext->export_funcs_begin(),
+          E = mContext->export_funcs_end();
+       I != E;
+       I++) {
+    const RSExportFunc *EF = *I;
+
+    // Function name
+    if (!EF->hasParam()) {
+      ExportFuncInfo.push_back(llvm::MDString::get(mLLVMContext,
+                                                   EF->getName().c_str()));
+    } else {
+      llvm::Function *F = M->getFunction(EF->getName());
+      llvm::Function *HelperFunction;
+      const std::string HelperFunctionName(".helper_" + EF->getName());
+
+      slangAssert(F && "Function marked as exported disappeared in Bitcode");
+
+      // Create helper function
+      {
+        llvm::StructType *HelperFunctionParameterTy = NULL;
+
+        if (!F->getArgumentList().empty()) {
+          std::vector<llvm::Type*> HelperFunctionParameterTys;
+          for (llvm::Function::arg_iterator AI = F->arg_begin(),
+               AE = F->arg_end(); AI != AE; AI++)
+            HelperFunctionParameterTys.push_back(AI->getType());
+
+          HelperFunctionParameterTy =
+              llvm::StructType::get(mLLVMContext, HelperFunctionParameterTys);
+        }
+
+        if (!EF->checkParameterPacketType(HelperFunctionParameterTy)) {
+          fprintf(stderr, "Failed to export function %s: parameter type "
+                          "mismatch during creation of helper function.\n",
+                  EF->getName().c_str());
+
+          const RSExportRecordType *Expected = EF->getParamPacketType();
+          if (Expected) {
+            fprintf(stderr, "Expected:\n");
+            Expected->getLLVMType()->dump();
+          }
+          if (HelperFunctionParameterTy) {
+            fprintf(stderr, "Got:\n");
+            HelperFunctionParameterTy->dump();
+          }
+        }
+
+        std::vector<llvm::Type*> Params;
+        if (HelperFunctionParameterTy) {
+          llvm::PointerType *HelperFunctionParameterTyP =
+              llvm::PointerType::getUnqual(HelperFunctionParameterTy);
+          Params.push_back(HelperFunctionParameterTyP);
+        }
+
+        llvm::FunctionType * HelperFunctionType =
+            llvm::FunctionType::get(F->getReturnType(),
+                                    Params,
+                                    /* IsVarArgs = */false);
+
+        HelperFunction =
+            llvm::Function::Create(HelperFunctionType,
+                                   llvm::GlobalValue::ExternalLinkage,
+                                   HelperFunctionName,
+                                   M);
+
+        HelperFunction->addFnAttr(llvm::Attribute::NoInline);
+        HelperFunction->setCallingConv(F->getCallingConv());
+
+        // Create helper function body
+        {
+          llvm::Argument *HelperFunctionParameter =
+              &(*HelperFunction->arg_begin());
+          llvm::BasicBlock *BB =
+              llvm::BasicBlock::Create(mLLVMContext, "entry", HelperFunction);
+          llvm::IRBuilder<> *IB = new llvm::IRBuilder<>(BB);
+          llvm::SmallVector<llvm::Value*, 6> Params;
+          llvm::Value *Idx[2];
+
+          Idx[0] =
+              llvm::ConstantInt::get(llvm::Type::getInt32Ty(mLLVMContext), 0);
+
+          // getelementptr and load instruction for all elements in
+          // parameter .p
+          for (size_t i = 0; i < EF->getNumParameters(); i++) {
+            // getelementptr
+            Idx[1] = llvm::ConstantInt::get(
+              llvm::Type::getInt32Ty(mLLVMContext), i);
+
+            llvm::Value *Ptr =
+              IB->CreateInBoundsGEP(HelperFunctionParameter, Idx);
+
+            // load
+            llvm::Value *V = IB->CreateLoad(Ptr);
+            Params.push_back(V);
+          }
+
+          // Call and pass the all elements as parameter to F
+          llvm::CallInst *CI = IB->CreateCall(F, Params);
+
+          CI->setCallingConv(F->getCallingConv());
+
+          if (F->getReturnType() == llvm::Type::getVoidTy(mLLVMContext))
+            IB->CreateRetVoid();
+          else
+            IB->CreateRet(CI);
+
+          delete IB;
+        }
+      }
+
+      ExportFuncInfo.push_back(
+          llvm::MDString::get(mLLVMContext, HelperFunctionName.c_str()));
+    }
+
+    mExportFuncMetadata->addOperand(
+        llvm::MDNode::get(mLLVMContext, ExportFuncInfo));
+    ExportFuncInfo.clear();
+  }
+}
+
+void RSBackend::dumpExportForEachInfo(llvm::Module *M) {
+  if (mExportForEachNameMetadata == NULL) {
+    mExportForEachNameMetadata =
+        M->getOrInsertNamedMetadata(RS_EXPORT_FOREACH_NAME_MN);
+  }
+  if (mExportForEachSignatureMetadata == NULL) {
+    mExportForEachSignatureMetadata =
+        M->getOrInsertNamedMetadata(RS_EXPORT_FOREACH_MN);
+  }
+
+  llvm::SmallVector<llvm::Value*, 1> ExportForEachName;
+  llvm::SmallVector<llvm::Value*, 1> ExportForEachInfo;
+
+  for (RSContext::const_export_foreach_iterator
+          I = mContext->export_foreach_begin(),
+          E = mContext->export_foreach_end();
+       I != E;
+       I++) {
+    const RSExportForEach *EFE = *I;
+
+    ExportForEachName.push_back(
+        llvm::MDString::get(mLLVMContext, EFE->getName().c_str()));
+
+    mExportForEachNameMetadata->addOperand(
+        llvm::MDNode::get(mLLVMContext, ExportForEachName));
+    ExportForEachName.clear();
+
+    ExportForEachInfo.push_back(
+        llvm::MDString::get(mLLVMContext,
+                            llvm::utostr_32(EFE->getSignatureMetadata())));
+
+    mExportForEachSignatureMetadata->addOperand(
+        llvm::MDNode::get(mLLVMContext, ExportForEachInfo));
+    ExportForEachInfo.clear();
+  }
+}
+
+void RSBackend::dumpExportTypeInfo(llvm::Module *M) {
+  llvm::SmallVector<llvm::Value*, 1> ExportTypeInfo;
+
+  for (RSContext::const_export_type_iterator
+          I = mContext->export_types_begin(),
+          E = mContext->export_types_end();
+       I != E;
+       I++) {
+    // First, dump type name list to export
+    const RSExportType *ET = I->getValue();
+
+    ExportTypeInfo.clear();
+    // Type name
+    ExportTypeInfo.push_back(
+        llvm::MDString::get(mLLVMContext, ET->getName().c_str()));
+
+    if (ET->getClass() == RSExportType::ExportClassRecord) {
+      const RSExportRecordType *ERT =
+          static_cast<const RSExportRecordType*>(ET);
+
+      if (mExportTypeMetadata == NULL)
+        mExportTypeMetadata =
+            M->getOrInsertNamedMetadata(RS_EXPORT_TYPE_MN);
+
+      mExportTypeMetadata->addOperand(
+          llvm::MDNode::get(mLLVMContext, ExportTypeInfo));
+
+      // Now, export struct field information to %[struct name]
+      std::string StructInfoMetadataName("%");
+      StructInfoMetadataName.append(ET->getName());
+      llvm::NamedMDNode *StructInfoMetadata =
+          M->getOrInsertNamedMetadata(StructInfoMetadataName);
+      llvm::SmallVector<llvm::Value*, 3> FieldInfo;
+
+      slangAssert(StructInfoMetadata->getNumOperands() == 0 &&
+                  "Metadata with same name was created before");
+      for (RSExportRecordType::const_field_iterator FI = ERT->fields_begin(),
+              FE = ERT->fields_end();
+           FI != FE;
+           FI++) {
+        const RSExportRecordType::Field *F = *FI;
+
+        // 1. field name
+        FieldInfo.push_back(llvm::MDString::get(mLLVMContext,
+                                                F->getName().c_str()));
+
+        // 2. field type name
+        FieldInfo.push_back(
+            llvm::MDString::get(mLLVMContext,
+                                F->getType()->getName().c_str()));
+
+        StructInfoMetadata->addOperand(
+            llvm::MDNode::get(mLLVMContext, FieldInfo));
+        FieldInfo.clear();
+      }
+    }   // ET->getClass() == RSExportType::ExportClassRecord
+  }
+}
+
 void RSBackend::HandleTranslationUnitPost(llvm::Module *M) {
   if (!mContext->processExport()) {
     return;
   }
 
-  // Write optimization level
-  llvm::SmallVector<llvm::Value*, 1> OptimizationOption;
-  OptimizationOption.push_back(llvm::ConstantInt::get(
-    mLLVMContext, llvm::APInt(32, mCodeGenOpts.OptimizationLevel)));
+  if (mContext->hasExportVar())
+    dumpExportVarInfo(M);
 
-  // Dump export variable info
-  if (mContext->hasExportVar()) {
-    int slotCount = 0;
-    if (mExportVarMetadata == NULL)
-      mExportVarMetadata = M->getOrInsertNamedMetadata(RS_EXPORT_VAR_MN);
+  if (mContext->hasExportFunc())
+    dumpExportFunctionInfo(M);
 
-    llvm::SmallVector<llvm::Value*, 2> ExportVarInfo;
+  if (mContext->hasExportForEach())
+    dumpExportForEachInfo(M);
 
-    // We emit slot information (#rs_object_slots) for any reference counted
-    // RS type or pointer (which can also be bound).
-
-    for (RSContext::const_export_var_iterator I = mContext->export_vars_begin(),
-            E = mContext->export_vars_end();
-         I != E;
-         I++) {
-      const RSExportVar *EV = *I;
-      const RSExportType *ET = EV->getType();
-      bool countsAsRSObject = false;
-
-      // Variable name
-      ExportVarInfo.push_back(
-          llvm::MDString::get(mLLVMContext, EV->getName().c_str()));
-
-      // Type name
-      switch (ET->getClass()) {
-        case RSExportType::ExportClassPrimitive: {
-          const RSExportPrimitiveType *PT =
-              static_cast<const RSExportPrimitiveType*>(ET);
-          ExportVarInfo.push_back(
-              llvm::MDString::get(
-                mLLVMContext, llvm::utostr_32(PT->getType())));
-          if (PT->isRSObjectType()) {
-            countsAsRSObject = true;
-          }
-          break;
-        }
-        case RSExportType::ExportClassPointer: {
-          ExportVarInfo.push_back(
-              llvm::MDString::get(
-                mLLVMContext, ("*" + static_cast<const RSExportPointerType*>(ET)
-                  ->getPointeeType()->getName()).c_str()));
-          break;
-        }
-        case RSExportType::ExportClassMatrix: {
-          ExportVarInfo.push_back(
-              llvm::MDString::get(
-                mLLVMContext, llvm::utostr_32(
-                  RSExportPrimitiveType::DataTypeRSMatrix2x2 +
-                  static_cast<const RSExportMatrixType*>(ET)->getDim() - 2)));
-          break;
-        }
-        case RSExportType::ExportClassVector:
-        case RSExportType::ExportClassConstantArray:
-        case RSExportType::ExportClassRecord: {
-          ExportVarInfo.push_back(
-              llvm::MDString::get(mLLVMContext,
-                EV->getType()->getName().c_str()));
-          break;
-        }
-      }
-
-      mExportVarMetadata->addOperand(
-          llvm::MDNode::get(mLLVMContext, ExportVarInfo));
-      ExportVarInfo.clear();
-
-      if (mRSObjectSlotsMetadata == NULL) {
-        mRSObjectSlotsMetadata =
-            M->getOrInsertNamedMetadata(RS_OBJECT_SLOTS_MN);
-      }
-
-      if (countsAsRSObject) {
-        mRSObjectSlotsMetadata->addOperand(llvm::MDNode::get(mLLVMContext,
-            llvm::MDString::get(mLLVMContext, llvm::utostr_32(slotCount))));
-      }
-
-      slotCount++;
-    }
-  }
-
-  // Dump export function info
-  if (mContext->hasExportFunc()) {
-    if (mExportFuncMetadata == NULL)
-      mExportFuncMetadata =
-          M->getOrInsertNamedMetadata(RS_EXPORT_FUNC_MN);
-
-    llvm::SmallVector<llvm::Value*, 1> ExportFuncInfo;
-
-    for (RSContext::const_export_func_iterator
-            I = mContext->export_funcs_begin(),
-            E = mContext->export_funcs_end();
-         I != E;
-         I++) {
-      const RSExportFunc *EF = *I;
-
-      // Function name
-      if (!EF->hasParam()) {
-        ExportFuncInfo.push_back(llvm::MDString::get(mLLVMContext,
-                                                     EF->getName().c_str()));
-      } else {
-        llvm::Function *F = M->getFunction(EF->getName());
-        llvm::Function *HelperFunction;
-        const std::string HelperFunctionName(".helper_" + EF->getName());
-
-        slangAssert(F && "Function marked as exported disappeared in Bitcode");
-
-        // Create helper function
-        {
-          llvm::StructType *HelperFunctionParameterTy = NULL;
-
-          if (!F->getArgumentList().empty()) {
-            std::vector<llvm::Type*> HelperFunctionParameterTys;
-            for (llvm::Function::arg_iterator AI = F->arg_begin(),
-                 AE = F->arg_end(); AI != AE; AI++)
-              HelperFunctionParameterTys.push_back(AI->getType());
-
-            HelperFunctionParameterTy =
-                llvm::StructType::get(mLLVMContext, HelperFunctionParameterTys);
-          }
-
-          if (!EF->checkParameterPacketType(HelperFunctionParameterTy)) {
-            fprintf(stderr, "Failed to export function %s: parameter type "
-                            "mismatch during creation of helper function.\n",
-                    EF->getName().c_str());
-
-            const RSExportRecordType *Expected = EF->getParamPacketType();
-            if (Expected) {
-              fprintf(stderr, "Expected:\n");
-              Expected->getLLVMType()->dump();
-            }
-            if (HelperFunctionParameterTy) {
-              fprintf(stderr, "Got:\n");
-              HelperFunctionParameterTy->dump();
-            }
-          }
-
-          std::vector<llvm::Type*> Params;
-          if (HelperFunctionParameterTy) {
-            llvm::PointerType *HelperFunctionParameterTyP =
-                llvm::PointerType::getUnqual(HelperFunctionParameterTy);
-            Params.push_back(HelperFunctionParameterTyP);
-          }
-
-          llvm::FunctionType * HelperFunctionType =
-              llvm::FunctionType::get(F->getReturnType(),
-                                      Params,
-                                      /* IsVarArgs = */false);
-
-          HelperFunction =
-              llvm::Function::Create(HelperFunctionType,
-                                     llvm::GlobalValue::ExternalLinkage,
-                                     HelperFunctionName,
-                                     M);
-
-          HelperFunction->addFnAttr(llvm::Attribute::NoInline);
-          HelperFunction->setCallingConv(F->getCallingConv());
-
-          // Create helper function body
-          {
-            llvm::Argument *HelperFunctionParameter =
-                &(*HelperFunction->arg_begin());
-            llvm::BasicBlock *BB =
-                llvm::BasicBlock::Create(mLLVMContext, "entry", HelperFunction);
-            llvm::IRBuilder<> *IB = new llvm::IRBuilder<>(BB);
-            llvm::SmallVector<llvm::Value*, 6> Params;
-            llvm::Value *Idx[2];
-
-            Idx[0] =
-                llvm::ConstantInt::get(llvm::Type::getInt32Ty(mLLVMContext), 0);
-
-            // getelementptr and load instruction for all elements in
-            // parameter .p
-            for (size_t i = 0; i < EF->getNumParameters(); i++) {
-              // getelementptr
-              Idx[1] = llvm::ConstantInt::get(
-                llvm::Type::getInt32Ty(mLLVMContext), i);
-
-              llvm::Value *Ptr =
-                IB->CreateInBoundsGEP(HelperFunctionParameter, Idx);
-
-              // load
-              llvm::Value *V = IB->CreateLoad(Ptr);
-              Params.push_back(V);
-            }
-
-            // Call and pass the all elements as parameter to F
-            llvm::CallInst *CI = IB->CreateCall(F, Params);
-
-            CI->setCallingConv(F->getCallingConv());
-
-            if (F->getReturnType() == llvm::Type::getVoidTy(mLLVMContext))
-              IB->CreateRetVoid();
-            else
-              IB->CreateRet(CI);
-
-            delete IB;
-          }
-        }
-
-        ExportFuncInfo.push_back(
-            llvm::MDString::get(mLLVMContext, HelperFunctionName.c_str()));
-      }
-
-      mExportFuncMetadata->addOperand(
-          llvm::MDNode::get(mLLVMContext, ExportFuncInfo));
-      ExportFuncInfo.clear();
-    }
-  }
-
-  // Dump export function info
-  if (mContext->hasExportForEach()) {
-    if (mExportForEachNameMetadata == NULL) {
-      mExportForEachNameMetadata =
-          M->getOrInsertNamedMetadata(RS_EXPORT_FOREACH_NAME_MN);
-    }
-    if (mExportForEachSignatureMetadata == NULL) {
-      mExportForEachSignatureMetadata =
-          M->getOrInsertNamedMetadata(RS_EXPORT_FOREACH_MN);
-    }
-
-    llvm::SmallVector<llvm::Value*, 1> ExportForEachName;
-    llvm::SmallVector<llvm::Value*, 1> ExportForEachInfo;
-
-    for (RSContext::const_export_foreach_iterator
-            I = mContext->export_foreach_begin(),
-            E = mContext->export_foreach_end();
-         I != E;
-         I++) {
-      const RSExportForEach *EFE = *I;
-
-      ExportForEachName.push_back(
-          llvm::MDString::get(mLLVMContext, EFE->getName().c_str()));
-
-      mExportForEachNameMetadata->addOperand(
-          llvm::MDNode::get(mLLVMContext, ExportForEachName));
-      ExportForEachName.clear();
-
-      ExportForEachInfo.push_back(
-          llvm::MDString::get(mLLVMContext,
-                              llvm::utostr_32(EFE->getSignatureMetadata())));
-
-      mExportForEachSignatureMetadata->addOperand(
-          llvm::MDNode::get(mLLVMContext, ExportForEachInfo));
-      ExportForEachInfo.clear();
-    }
-  }
-
-  // Dump export type info
-  if (mContext->hasExportType()) {
-    llvm::SmallVector<llvm::Value*, 1> ExportTypeInfo;
-
-    for (RSContext::const_export_type_iterator
-            I = mContext->export_types_begin(),
-            E = mContext->export_types_end();
-         I != E;
-         I++) {
-      // First, dump type name list to export
-      const RSExportType *ET = I->getValue();
-
-      ExportTypeInfo.clear();
-      // Type name
-      ExportTypeInfo.push_back(
-          llvm::MDString::get(mLLVMContext, ET->getName().c_str()));
-
-      if (ET->getClass() == RSExportType::ExportClassRecord) {
-        const RSExportRecordType *ERT =
-            static_cast<const RSExportRecordType*>(ET);
-
-        if (mExportTypeMetadata == NULL)
-          mExportTypeMetadata =
-              M->getOrInsertNamedMetadata(RS_EXPORT_TYPE_MN);
-
-        mExportTypeMetadata->addOperand(
-            llvm::MDNode::get(mLLVMContext, ExportTypeInfo));
-
-        // Now, export struct field information to %[struct name]
-        std::string StructInfoMetadataName("%");
-        StructInfoMetadataName.append(ET->getName());
-        llvm::NamedMDNode *StructInfoMetadata =
-            M->getOrInsertNamedMetadata(StructInfoMetadataName);
-        llvm::SmallVector<llvm::Value*, 3> FieldInfo;
-
-        slangAssert(StructInfoMetadata->getNumOperands() == 0 &&
-                    "Metadata with same name was created before");
-        for (RSExportRecordType::const_field_iterator FI = ERT->fields_begin(),
-                FE = ERT->fields_end();
-             FI != FE;
-             FI++) {
-          const RSExportRecordType::Field *F = *FI;
-
-          // 1. field name
-          FieldInfo.push_back(llvm::MDString::get(mLLVMContext,
-                                                  F->getName().c_str()));
-
-          // 2. field type name
-          FieldInfo.push_back(
-              llvm::MDString::get(mLLVMContext,
-                                  F->getType()->getName().c_str()));
-
-          StructInfoMetadata->addOperand(
-              llvm::MDNode::get(mLLVMContext, FieldInfo));
-          FieldInfo.clear();
-        }
-      }   // ET->getClass() == RSExportType::ExportClassRecord
-    }
-  }
+  if (mContext->hasExportType())
+    dumpExportTypeInfo(M);
 
   return;
 }
diff --git a/slang_rs_backend.h b/slang_rs_backend.h
index 80c643d..2d6ab72 100644
--- a/slang_rs_backend.h
+++ b/slang_rs_backend.h
@@ -64,6 +64,11 @@
 
   void AnnotateFunction(clang::FunctionDecl *FD);
 
+  void dumpExportVarInfo(llvm::Module *M);
+  void dumpExportFunctionInfo(llvm::Module *M);
+  void dumpExportForEachInfo(llvm::Module *M);
+  void dumpExportTypeInfo(llvm::Module *M);
+
  protected:
   virtual unsigned int getTargetAPI() const {
     return mContext->getTargetAPI();
diff --git a/slang_rs_check_ast.cpp b/slang_rs_check_ast.cpp
index 845db4c..14ee822 100644
--- a/slang_rs_check_ast.cpp
+++ b/slang_rs_check_ast.cpp
@@ -36,6 +36,117 @@
   }
 }
 
+void RSCheckAST::WarnOnSetElementAt(clang::CallExpr *E) {
+  clang::FunctionDecl *Decl;
+  clang::DiagnosticsEngine &DiagEngine = C.getDiagnostics();
+  Decl = clang::dyn_cast_or_null<clang::FunctionDecl>(E->getCalleeDecl());
+
+  if (!Decl || Decl->getNameAsString() != std::string("rsSetElementAt")) {
+    return;
+  }
+
+  clang::Expr *Expr;
+  clang::ImplicitCastExpr *ImplCast;
+  Expr = E->getArg(1);
+  ImplCast = clang::dyn_cast_or_null<clang::ImplicitCastExpr>(Expr);
+
+  if (!ImplCast) {
+    return;
+  }
+
+  const clang::Type *Ty;
+  const clang::VectorType *VectorTy;
+  const clang::BuiltinType *ElementTy;
+  Ty = ImplCast->getSubExpr()->getType()->getPointeeType()
+    ->getUnqualifiedDesugaredType();
+  VectorTy = clang::dyn_cast_or_null<clang::VectorType>(Ty);
+
+  if (VectorTy) {
+    ElementTy = clang::dyn_cast_or_null<clang::BuiltinType>(
+      VectorTy->getElementType()->getUnqualifiedDesugaredType());
+  } else {
+    ElementTy = clang::dyn_cast_or_null<clang::BuiltinType>(
+      Ty->getUnqualifiedDesugaredType());
+  }
+
+  if (!ElementTy) {
+    return;
+  }
+
+  // We only support vectors with 2, 3 or 4 elements.
+  if (VectorTy) {
+    switch (VectorTy->getNumElements()) {
+    default:
+      return;
+    case 2:
+    case 3:
+    case 4:
+      break;
+    }
+  }
+
+  const char *Name;
+
+  switch (ElementTy->getKind()) {
+    case clang::BuiltinType::Float:
+      Name = "float";
+      break;
+    case clang::BuiltinType::Double:
+      Name = "double";
+      break;
+    case clang::BuiltinType::Char_S:
+      Name = "char";
+      break;
+    case clang::BuiltinType::Short:
+      Name = "short";
+      break;
+    case clang::BuiltinType::Int:
+      Name = "int";
+      break;
+    case clang::BuiltinType::Long:
+      Name = "long";
+      break;
+    case clang::BuiltinType::UChar:
+      Name = "uchar";
+      break;
+    case clang::BuiltinType::UShort:
+      Name = "ushort";
+      break;
+    case clang::BuiltinType::UInt:
+      Name = "uint";
+      break;
+    case clang::BuiltinType::ULong:
+      Name = "ulong";
+      break;
+    default:
+      return;
+  }
+
+  clang::DiagnosticBuilder DiagBuilder =  DiagEngine.Report(
+    clang::FullSourceLoc(E->getLocStart(), mSM),
+    mDiagEngine.getCustomDiagID( clang::DiagnosticsEngine::Warning,
+    "untyped rsSetElementAt() can reduce performance. "
+    "Use rsSetElementAt_%0%1() instead."));
+  DiagBuilder << Name;
+
+  if (VectorTy) {
+    DiagBuilder << VectorTy->getNumElements();
+  } else {
+    DiagBuilder << "";
+  }
+
+  return;
+}
+
+void RSCheckAST::VisitCallExpr(clang::CallExpr *E) {
+  WarnOnSetElementAt(E);
+
+  for (clang::CallExpr::arg_iterator AI = E->arg_begin(), AE = E->arg_end();
+       AI != AE; ++AI) {
+    Visit(*AI);
+  }
+}
+
 void RSCheckAST::ValidateFunctionDecl(clang::FunctionDecl *FD) {
   if (!FD) {
     return;
diff --git a/slang_rs_check_ast.h b/slang_rs_check_ast.h
index 1700cb7..53be3cf 100644
--- a/slang_rs_check_ast.h
+++ b/slang_rs_check_ast.h
@@ -36,6 +36,14 @@
   bool mIsFilterscript;
   bool mInKernel;
 
+  /// @brief Emit warnings for inapproriate uses of rsSetElementAt
+  ///
+  /// We warn in case generic rsSetElementAt() is used even though the user
+  /// could have used a typed rsSetElementAt_<type>() call. Typed calls
+  /// allow more aggressive optimization (e.g. due to better alias analysis
+  /// results). Hence, we want to steer the users to use them.
+  void WarnOnSetElementAt(clang::CallExpr*);
+
  public:
   explicit RSCheckAST(clang::ASTContext &Con, unsigned int TargetAPI,
                       bool IsFilterscript)
@@ -47,6 +55,8 @@
 
   void VisitStmt(clang::Stmt *S);
 
+  void VisitCallExpr(clang::CallExpr *CE);
+
   void VisitCastExpr(clang::CastExpr *CE);
 
   void VisitExpr(clang::Expr *E);
diff --git a/tests/F_vector_cast/stderr.txt.expect b/tests/F_vector_cast/stderr.txt.expect
index 84dfc4d..b8fa5ea 100644
--- a/tests/F_vector_cast/stderr.txt.expect
+++ b/tests/F_vector_cast/stderr.txt.expect
@@ -3,3 +3,4 @@
 vector_cast.rs:7:9: error: invalid vector cast
 vector_cast.rs:14:9: error: invalid vector cast
 vector_cast.rs:21:9: error: invalid vector cast
+vector_cast.rs:31:13: error: invalid vector cast
diff --git a/tests/F_vector_cast/vector_cast.rs b/tests/F_vector_cast/vector_cast.rs
index b504103..bd49391 100644
--- a/tests/F_vector_cast/vector_cast.rs
+++ b/tests/F_vector_cast/vector_cast.rs
@@ -21,3 +21,13 @@
     u = (uchar4) c;
 }
 
+uchar4 bar(uchar4 u) {
+    return u;
+}
+
+void c2uc_bar() {
+    char4 c;
+    uchar4 u;
+    u = bar((uchar4) c);
+}
+
diff --git a/tests/P_warnings_rsSetElementAt/setelementat.rs b/tests/P_warnings_rsSetElementAt/setelementat.rs
new file mode 100644
index 0000000..032a456
--- /dev/null
+++ b/tests/P_warnings_rsSetElementAt/setelementat.rs
@@ -0,0 +1,52 @@
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+rs_allocation A;
+static void foo() {
+    // Basic scalar and floating point types.
+    float a = 4.0f;
+    double d = 4.0f;
+    float2 a2 = {4.0f, 4.0f};
+    float3 a3 = {4.0f, 4.0f, 4.0f};
+    float4 a4 = {4.0f, 4.0f, 4.0f, 4.0f};
+    char c = 4;
+    uchar uc = 4;
+    short s = 4;
+    ushort us = 4;
+    int i = 4;
+    uint ui = 4;
+    long l = 4;
+    ulong ul = 4;
+
+    rsSetElementAt(A, &a, 0, 0);
+    rsSetElementAt(A, &d, 0, 0);
+    rsSetElementAt(A, &a2, 0, 0);
+    rsSetElementAt(A, &a3, 0, 0);
+    rsSetElementAt(A, &a4, 0, 0);
+    rsSetElementAt(A, &c, 0, 0);
+    rsSetElementAt(A, &uc, 0, 0);
+    rsSetElementAt(A, &s, 0, 0);
+    rsSetElementAt(A, &us, 0, 0);
+    rsSetElementAt(A, &i, 0, 0);
+    rsSetElementAt(A, &ui, 0, 0);
+    rsSetElementAt(A, &l, 0, 0);
+    rsSetElementAt(A, &ul, 0, 0);
+
+    // No warnings for complex data types
+    struct {
+        int A;
+        int B;
+    } P;
+    rsSetElementAt(A, &P, 0, 0);
+
+    // No warning for 'long long'
+    long long LL = 4.0f;
+    rsSetElementAt(A, &LL, 0, 0);
+
+    // Unsupported vector width
+    typedef int int5 __attribute__((ext_vector_type(5)));
+    int5 i5 = {5, 5, 5, 5, 5};
+
+    rsSetElementAt(A, &i5, 0, 0);
+}
+
diff --git a/tests/P_warnings_rsSetElementAt/stderr.txt.expect b/tests/P_warnings_rsSetElementAt/stderr.txt.expect
new file mode 100644
index 0000000..71b7aab
--- /dev/null
+++ b/tests/P_warnings_rsSetElementAt/stderr.txt.expect
@@ -0,0 +1,12 @@
+setelementat.rs:21:5: warning: untyped rsSetElementAt() can reduce performance. Use rsSetElementAt_float() instead.
+setelementat.rs:22:5: warning: untyped rsSetElementAt() can reduce performance. Use rsSetElementAt_double() instead.
+setelementat.rs:23:5: warning: untyped rsSetElementAt() can reduce performance. Use rsSetElementAt_float2() instead.
+setelementat.rs:24:5: warning: untyped rsSetElementAt() can reduce performance. Use rsSetElementAt_float3() instead.
+setelementat.rs:25:5: warning: untyped rsSetElementAt() can reduce performance. Use rsSetElementAt_float4() instead.
+setelementat.rs:26:5: warning: untyped rsSetElementAt() can reduce performance. Use rsSetElementAt_char() instead.
+setelementat.rs:27:5: warning: untyped rsSetElementAt() can reduce performance. Use rsSetElementAt_uchar() instead.
+setelementat.rs:28:5: warning: untyped rsSetElementAt() can reduce performance. Use rsSetElementAt_short() instead.
+setelementat.rs:29:5: warning: untyped rsSetElementAt() can reduce performance. Use rsSetElementAt_ushort() instead.
+setelementat.rs:30:5: warning: untyped rsSetElementAt() can reduce performance. Use rsSetElementAt_int() instead.
+setelementat.rs:31:5: warning: untyped rsSetElementAt() can reduce performance. Use rsSetElementAt_uint() instead.
+setelementat.rs:32:5: warning: untyped rsSetElementAt() can reduce performance. Use rsSetElementAt_long() instead.
diff --git a/tests/P_warnings_rsSetElementAt/stdout.txt.expect b/tests/P_warnings_rsSetElementAt/stdout.txt.expect
new file mode 100644
index 0000000..b10911b
--- /dev/null
+++ b/tests/P_warnings_rsSetElementAt/stdout.txt.expect
@@ -0,0 +1 @@
+Generating ScriptC_setelementat.java ...